diff --git a/Cargo.lock b/Cargo.lock index d5466d57e7..ecd42d6d4a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -183,7 +183,16 @@ dependencies = [ "block-padding", "byte-tools", "byteorder", - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array 0.14.4", ] [[package]] @@ -207,6 +216,7 @@ dependencies = [ "ignore", "lazy_static", "libc", + "merge", "num_cpus", "opener", "pretty_assertions", @@ -230,8 +240,15 @@ dependencies = [ name = "build-manifest" version = "0.1.0" dependencies = [ + "anyhow", + "flate2", + "hex 0.4.2", + "num_cpus", + "rayon", "serde", "serde_json", + "sha2", + "tar", "toml", ] @@ -278,7 +295,7 @@ checksum = "81a18687293a1546b67c246452202bbbf143d239cb43494cc163da14979082da" [[package]] name = "cargo" -version = "0.48.0" +version = "0.49.0" dependencies = [ "anyhow", "atty", @@ -342,7 +359,6 @@ dependencies = [ name = "cargo-miri" version = "0.1.0" dependencies = [ - "cargo_metadata 0.9.1", "directories", "rustc-workspace-hack", "rustc_version", @@ -391,18 +407,6 @@ dependencies = [ "serde_json", ] -[[package]] -name = "cargo_metadata" -version = "0.9.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "46e3374c604fb39d1a2f35ed5e4a4e30e60d01fab49446e08f1b3e9a90aef202" -dependencies = [ - "semver 0.9.0", - "serde", - "serde_derive", - "serde_json", -] - [[package]] name = "cargo_metadata" version = "0.11.1" @@ -420,9 +424,9 @@ version = "0.1.0" [[package]] name = "cc" -version = "1.0.58" +version = "1.0.60" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9a06fb2e53271d7c279ec1efea6ab691c35a2ae67ec0d91d7acec0caf13b518" +checksum = "ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c" dependencies = [ "jobserver", ] @@ -439,9 +443,9 @@ dependencies = [ [[package]] name = "chalk-derive" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d" +checksum = "3a7f257e3bcdc56d8877ae31c012bd69fba0be66929d588e603905f2632c0c59" dependencies = [ "proc-macro2", "quote", @@ -451,21 +455,22 @@ dependencies = [ [[package]] name = "chalk-engine" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000" +checksum = "c43fcc7edf4d51b42f44ed50e2337bd90ddc8e088d0cd78a71db92a6f780f782" dependencies = [ "chalk-derive", "chalk-ir", + "chalk-solve", "rustc-hash", "tracing", ] [[package]] name = "chalk-ir" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe" +checksum = "03a4050029ecb2b5a1ff3bfc64c39279179b294821ec2e8891a4a5c6e3a08db0" dependencies = [ "chalk-derive", "lazy_static", @@ -473,18 +478,19 @@ dependencies = [ [[package]] name = "chalk-solve" -version = "0.14.0" +version = "0.29.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29" +checksum = "828c1f80d4eaf681027cce02050c54a3c97370f81988d31bf2a56df54048746c" dependencies = [ "chalk-derive", - "chalk-engine", "chalk-ir", "ena", "itertools 0.9.0", "petgraph", "rustc-hash", "tracing", + "tracing-subscriber", + "tracing-tree", ] [[package]] @@ -518,7 +524,7 @@ dependencies = [ name = "clippy" version = "0.0.212" dependencies = [ - "cargo_metadata 0.9.1", + "cargo_metadata 0.11.1", "clippy-mini-macro-test", "clippy_lints", "compiletest_rs", @@ -526,7 +532,7 @@ dependencies = [ "lazy_static", "rustc-workspace-hack", "rustc_tools_util 0.2.0", - "semver 0.9.0", + "semver 0.10.0", "serde", "tempfile", "tester", @@ -540,15 +546,15 @@ version = "0.2.0" name = "clippy_lints" version = "0.0.212" dependencies = [ - "cargo_metadata 0.9.1", + "cargo_metadata 0.11.1", "if_chain", "itertools 0.9.0", "lazy_static", - "pulldown-cmark", + "pulldown-cmark 0.8.0", "quine-mc_cluskey", "quote", "regex-syntax", - "semver 0.9.0", + "semver 0.10.0", "serde", "smallvec 1.4.2", "syn", @@ -586,9 +592,9 @@ dependencies = [ [[package]] name = "colored" -version = "1.9.3" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f4ffc801dacf156c5854b9df4f425a626539c3a6ef7893cc0c5084a23f0b6c59" +checksum = "b3616f750b84d8f0de8a58bda93e08e2a81ad3f523089b05f1dffecab48c6cbd" dependencies = [ "atty", "lazy_static", @@ -615,9 +621,9 @@ dependencies = [ [[package]] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.35" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c" +checksum = "e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455" dependencies = [ "cc", "rustc-std-workspace-core", @@ -694,6 +700,12 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9a21fa21941700a3cd8fcb4091f361a6a712fac632f85d9f487cc892045d55c6" +[[package]] +name = "cpuid-bool" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634" + [[package]] name = "crates-io" version = "0.31.1" @@ -717,12 +729,12 @@ dependencies = [ [[package]] name = "crossbeam-channel" -version = "0.4.3" +version = "0.4.4" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" +checksum = "b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87" dependencies = [ - "cfg-if", "crossbeam-utils 0.7.2", + "maybe-uninit", ] [[package]] @@ -891,16 +903,24 @@ version = "0.8.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" dependencies = [ - "generic-array", + "generic-array 0.12.3", +] + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "generic-array 0.14.4", ] [[package]] name = "directories" -version = "2.0.2" +version = "3.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "551a778172a450d7fc12e629ca3b0428d00f6afa9a43da1b630d54604e97371c" +checksum = "f8fed639d60b58d0f53498ab13d26f621fd77569cc6edb031f4cc36a2ad9da0f" dependencies = [ - "cfg-if", "dirs-sys", ] @@ -1010,9 +1030,9 @@ dependencies = [ [[package]] name = "expect-test" -version = "0.1.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a3e383741ea1982866572109d1a8c807bd36aad91fca701489fdca56ef92b3b8" +checksum = "ceb96f3eaa0d4e8769c52dacfd4eb60183b817ed2f176171b3c691d5022b0f2e" dependencies = [ "difference", "once_cell", @@ -1174,6 +1194,16 @@ dependencies = [ "typenum", ] +[[package]] +name = "generic-array" +version = "0.14.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817" +dependencies = [ + "typenum", + "version_check", +] + [[package]] name = "getopts" version = "0.2.21" @@ -1196,6 +1226,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "getrandom" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee8025cf36f917e6a52cce185b7c7177689b838b7ec138364e50cc2277a56cf4" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "gimli" version = "0.22.0" @@ -1209,9 +1250,9 @@ dependencies = [ [[package]] name = "git2" -version = "0.13.8" +version = "0.13.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e6ac22e49b7d886b6802c66662b12609452248b1bc9e87d6d83ecea3db96f557" +checksum = "ca6f1a0238d7f8f8fd5ee642f4ebac4dbc03e03d1f78fbe7a3ede35dcf7e2224" dependencies = [ "bitflags", "libc", @@ -1269,11 +1310,10 @@ dependencies = [ [[package]] name = "hashbrown" -version = "0.8.2" +version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25" +checksum = "00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7" dependencies = [ - "autocfg", "compiler_builtins", "rustc-std-workspace-alloc", "rustc-std-workspace-core", @@ -1411,9 +1451,9 @@ dependencies = [ [[package]] name = "indexmap" -version = "1.5.1" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ "autocfg", "hashbrown", @@ -1621,18 +1661,18 @@ checksum = "830d08ce1d1d941e6b30645f1a0eb5643013d835ce3779a5fc208261dbe10f55" [[package]] name = "libc" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" dependencies = [ "rustc-std-workspace-core", ] [[package]] name = "libgit2-sys" -version = "0.12.9+1.0.1" +version = "0.12.14+1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9b33bf3d9d4c45b48ae1ea7c334be69994624dc0a69f833d5d9f7605f24b552b" +checksum = "8f25af58e6495f7caf2919d08f212de550cfa3ed2f5e744988938ea292b9f549" dependencies = [ "cc", "libc", @@ -1654,9 +1694,9 @@ dependencies = [ [[package]] name = "libssh2-sys" -version = "0.2.18" +version = "0.2.19" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "eafa907407504b0e683786d4aba47acf250f114d37357d56608333fd167dd0fc" +checksum = "ca46220853ba1c512fc82826d0834d87b06bcd3c2a42241b7de72f3d2fe17056" dependencies = [ "cc", "libc", @@ -1668,9 +1708,9 @@ dependencies = [ [[package]] name = "libz-sys" -version = "1.0.27" +version = "1.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "6ca8894883d250240341478bf987467332fbdd5da5c42426c69a8f93dbc302f2" +checksum = "602113192b08db8f38796c4e85c39e960c145965140e918018bcde1952429655" dependencies = [ "cc", "libc", @@ -1688,6 +1728,15 @@ version = "0.5.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8dd5a6d5999d9907cda8ed67bbd137d3af8085216c2ac62de5be860bd41f304a" +[[package]] +name = "lint-docs" +version = "0.1.0" +dependencies = [ + "serde_json", + "tempfile", + "walkdir", +] + [[package]] name = "lock_api" version = "0.3.4" @@ -1833,16 +1882,16 @@ version = "0.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a18af3dcaf2b0219366cdb4e2af65a6101457b415c3d1a5c71dd9c2b7c77b9c8" dependencies = [ - "block-buffer", - "digest", - "opaque-debug", + "block-buffer 0.7.3", + "digest 0.8.1", + "opaque-debug 0.2.3", ] [[package]] name = "mdbook" -version = "0.4.2" +version = "0.4.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b75e31ae4eaa0e45e17ee2b6b9e3ed969c3c6ff12bb4c2e352c42493f4ebb706" +checksum = "29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff" dependencies = [ "ammonia", "anyhow", @@ -1855,7 +1904,7 @@ dependencies = [ "log", "memchr", "open", - "pulldown-cmark", + "pulldown-cmark 0.7.2", "regex", "serde", "serde_derive", @@ -1902,6 +1951,28 @@ dependencies = [ "autocfg", ] +[[package]] +name = "merge" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9" +dependencies = [ + "merge_derive", + "num-traits", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +dependencies = [ + "proc-macro-error", + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "minifier" version = "0.0.33" @@ -1991,11 +2062,10 @@ dependencies = [ name = "miri" version = "0.1.0" dependencies = [ - "byteorder", "colored", "compiletest_rs", "env_logger 0.7.1", - "getrandom", + "getrandom 0.2.0", "hex 0.4.2", "libc", "log", @@ -2067,9 +2137,6 @@ name = "once_cell" version = "1.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "260e51e7efe62b592207e9e13a68e43692a7a279171d6ba57abd208bf23645ad" -dependencies = [ - "parking_lot 0.11.0", -] [[package]] name = "opaque-debug" @@ -2077,6 +2144,12 @@ version = "0.2.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + [[package]] name = "open" version = "1.4.0" @@ -2517,6 +2590,17 @@ dependencies = [ "unicase", ] +[[package]] +name = "pulldown-cmark" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8" +dependencies = [ + "bitflags", + "memchr", + "unicase", +] + [[package]] name = "punycode" version = "0.4.1" @@ -2552,9 +2636,9 @@ dependencies = [ [[package]] name = "racer" -version = "2.1.37" +version = "2.1.39" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db975752fc2c2430b4159d262585f7e45eb9aa43d733bf02c5f2fde512b00bfb" +checksum = "b9424b4650b9c1134d0a1b34dab82319691e1c95fa8af1658fc640deb1b6823c" dependencies = [ "bitflags", "clap", @@ -2579,7 +2663,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" dependencies = [ - "getrandom", + "getrandom 0.1.14", "libc", "rand_chacha", "rand_core", @@ -2603,7 +2687,7 @@ version = "0.5.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" dependencies = [ - "getrandom", + "getrandom 0.1.14", ] [[package]] @@ -2679,7 +2763,7 @@ version = "0.3.4" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "09b23093265f8d200fa7b4c2c76297f47e681c655f6f1285a8780d6a022f7431" dependencies = [ - "getrandom", + "getrandom 0.1.14", "redox_syscall", "rust-argon2", ] @@ -2879,9 +2963,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_arena" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4a3941333c39ffa778611a34692244052fc9ba0f6b02dcf019c8d24925707dd6" +checksum = "e8e941a8fc3878a111d2bbfe78e39522d884136f0b412b12592195f26f653476" dependencies = [ "rustc-ap-rustc_data_structures", "smallvec 1.4.2", @@ -2889,30 +2973,28 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_ast" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "27c579f7d89e6fc971b433e92bb2b8c65b716d7c797b21de8685945be9455610" +checksum = "3b58b6b035710df7f339a2bf86f6dafa876efd95439540970e24609e33598ca6" dependencies = [ "bitflags", - "log", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_lexer", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", - "scoped-tls", "smallvec 1.4.2", + "tracing", ] [[package]] name = "rustc-ap-rustc_ast_passes" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f9914fadee461568d19ca2ebaec8699ff898f8ffec9928154659a57ee018e5fd" +checksum = "3d379a900d6a1f098490d92ab83e87487dcee2e4ec3f04c3ac4512b5117b64e2" dependencies = [ - "itertools 0.8.2", - "log", + "itertools 0.9.0", "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", "rustc-ap-rustc_attr", @@ -2922,31 +3004,33 @@ dependencies = [ "rustc-ap-rustc_parse", "rustc-ap-rustc_session", "rustc-ap-rustc_span", + "tracing", ] [[package]] name = "rustc-ap-rustc_ast_pretty" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2a78c5cc50a2f294d3c4e9131a15676724c9f136d3ed54e9ba419850b6025cb3" +checksum = "658d925c0da9e3c5cddc5e54f4fa8c03b41aff1fc6dc5e41837c1118ad010ac0" dependencies = [ - "log", "rustc-ap-rustc_ast", "rustc-ap-rustc_span", "rustc-ap-rustc_target", + "tracing", ] [[package]] name = "rustc-ap-rustc_attr" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a78ce08227d146949755175c0cf710280a4b5bf6ee504c0e3f7ccc30d66fbfd9" +checksum = "3f387037534f34c148aed753622677500e42d190a095670e7ac3fffc09811a59" dependencies = [ "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", + "rustc-ap-rustc_lexer", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_session", @@ -2956,9 +3040,9 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_data_structures" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9d5ac3735c38d2d0e95991ebcd7eb1618b60e784194a738e0ce2e8d39c39b809" +checksum = "14ffd17a37e00d77926a0713f191c59ff3aeb2b551a024c7cfffce14bab79be8" dependencies = [ "bitflags", "cfg-if", @@ -2966,14 +3050,12 @@ dependencies = [ "ena", "indexmap", "jobserver", - "lazy_static", "libc", - "log", "measureme", - "once_cell", - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-ap-rustc_graphviz", "rustc-ap-rustc_index", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-hash", "rustc-rayon", @@ -2981,34 +3063,36 @@ dependencies = [ "smallvec 1.4.2", "stable_deref_trait", "stacker", + "tempfile", + "tracing", "winapi 0.3.9", ] [[package]] name = "rustc-ap-rustc_errors" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5166a95afa6e3b78ccbece4c2f1e163634854297f1147c6fd90e2712ed3fede5" +checksum = "2b3263ddcfa9eb911e54a4e8088878dd9fd10e00d8b99b01033ba4a2733fe91d" dependencies = [ "annotate-snippets 0.8.0", "atty", - "log", "rustc-ap-rustc_data_structures", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", "termcolor", "termize", + "tracing", "unicode-width", "winapi 0.3.9", ] [[package]] name = "rustc-ap-rustc_expand" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1a0586e83bdfe70eda8393429a8a38ecb529525dd252d787e479af075d3cab08" +checksum = "e1ab7e68cede8a2273fd8b8623002ce9dc832e061dfc3330e9bcc1fc2a722d73" dependencies = [ - "log", "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_passes", "rustc-ap-rustc_ast_pretty", @@ -3017,60 +3101,62 @@ dependencies = [ "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_lexer", + "rustc-ap-rustc_macros", "rustc-ap-rustc_parse", "rustc-ap-rustc_serialize", "rustc-ap-rustc_session", "rustc-ap-rustc_span", "smallvec 1.4.2", + "tracing", ] [[package]] name = "rustc-ap-rustc_feature" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "48fc3aa8de0737a8c5a4353e6948548f469150d2b5d3eac391843de32c6c6ca2" +checksum = "eea2dc95421bc19bbd4d939399833a882c46b684283b4267ad1fcf982fc043d9" dependencies = [ - "lazy_static", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_span", ] [[package]] name = "rustc-ap-rustc_fs_util" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "59fd3380f4029020b693bbfd5a14ec8c893ec33c5c0063ad2e68e46d3fbd6a1f" +checksum = "1e44c1804f09635f83f6cf1e04c2e92f8aeb7b4e850ac6c53d373dab02c13053" [[package]] name = "rustc-ap-rustc_graphviz" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b54bd98f70e04291bf611151d1fcd4d7770b35f7ec603d301c4aee0d1979cca4" +checksum = "dc491f2b9be6e928f6df6b287549b8d50c48e8eff8638345155f40fa2cfb785d" [[package]] name = "rustc-ap-rustc_index" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "335bfb187a2489a59ee8c67fcf5d1760e9dcdbe0f02025c199a74caa05096b15" +checksum = "fa73f3fed413cdb6290738a10267da17b9ae8e02087334778b9a8c9491c5efc0" dependencies = [ "arrayvec", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", ] [[package]] name = "rustc-ap-rustc_lexer" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "22e1221f3bfa2943c942cf8da319ab2346887f8757778c29c7f1822cd27b521f" +checksum = "e993881244a92f3b44cf43c8f22ae2ca5cefe4f55a34e2b65b72ee66fe5ad077" dependencies = [ "unicode-xid", ] [[package]] name = "rustc-ap-rustc_macros" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "8b774df26c4ef513555b3a303cb209f44cf68a9e6a5481b41ac832301c6487cb" +checksum = "4effe366556e1d75344764adf4d54cba7c2fad33dbd07588e96d0853831ddc7c" dependencies = [ "proc-macro2", "quote", @@ -3080,12 +3166,11 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_parse" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "065e632101bdd57a271f38ee7a4d72b5a3d0467ec845104346c284b2c6c69960" +checksum = "0342675835251571471d3dca9ea1576a853a8dfa1f4b0084db283c861223cb60" dependencies = [ "bitflags", - "log", "rustc-ap-rustc_ast", "rustc-ap-rustc_ast_pretty", "rustc-ap-rustc_data_structures", @@ -3094,14 +3179,16 @@ dependencies = [ "rustc-ap-rustc_lexer", "rustc-ap-rustc_session", "rustc-ap-rustc_span", + "smallvec 1.4.2", + "tracing", "unicode-normalization", ] [[package]] name = "rustc-ap-rustc_serialize" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0e8c0b704e3dedb97cbb1ac566bbc0ab397ec4a4743098326a8f2230463fd9f9" +checksum = "438255ed968d73bf6573aa18d3b8d33c0a85ecdfd14160ef09ff813938e0606c" dependencies = [ "indexmap", "smallvec 1.4.2", @@ -3109,32 +3196,32 @@ dependencies = [ [[package]] name = "rustc-ap-rustc_session" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "dda99ede4e6e260712754f8548b0a175b615686ad393653a3bd11f6c5e41a04e" +checksum = "7d61ff76dede8eb827f6805754900d1097a7046f938f950231b62b448f55bf78" dependencies = [ "bitflags", "getopts", - "log", "num_cpus", "rustc-ap-rustc_ast", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_errors", "rustc-ap-rustc_feature", "rustc-ap-rustc_fs_util", + "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", "rustc-ap-rustc_target", + "tracing", ] [[package]] name = "rustc-ap-rustc_span" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "53453791c2c0b501a921927ce8e305a801eef130920873f8da92d83dad595236" +checksum = "1c267f15c3cfc82a8a441d2bf86bcccf299d1eb625822468e3d8ee6f7c5a1c89" dependencies = [ "cfg-if", - "log", "md-5", "rustc-ap-rustc_arena", "rustc-ap-rustc_data_structures", @@ -3143,22 +3230,23 @@ dependencies = [ "rustc-ap-rustc_serialize", "scoped-tls", "sha-1", + "tracing", "unicode-width", ] [[package]] name = "rustc-ap-rustc_target" -version = "671.0.0" +version = "679.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ac82006fdb31ef44e24e1623f8b72ac2b404ef15ba20b7ebec0df35e5d20bbef" +checksum = "8b1b4b266c4d44aac0f7f83b6741d8f0545b03d1ce32f3b5254f2014225cb96c" dependencies = [ "bitflags", - "log", "rustc-ap-rustc_data_structures", "rustc-ap-rustc_index", "rustc-ap-rustc_macros", "rustc-ap-rustc_serialize", "rustc-ap-rustc_span", + "tracing", ] [[package]] @@ -3300,7 +3388,7 @@ dependencies = [ name = "rustc_ast_passes" version = "0.0.0" dependencies = [ - "itertools 0.8.2", + "itertools 0.9.0", "rustc_ast", "rustc_ast_pretty", "rustc_attr", @@ -3365,7 +3453,6 @@ name = "rustc_codegen_llvm" version = "0.0.0" dependencies = [ "bitflags", - "flate2", "libc", "measureme", "rustc-demangle", @@ -3386,6 +3473,7 @@ dependencies = [ "rustc_span", "rustc_target", "smallvec 1.4.2", + "snap", "tracing", ] @@ -3431,11 +3519,9 @@ dependencies = [ "ena", "indexmap", "jobserver", - "lazy_static", "libc", "measureme", - "once_cell", - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-hash", "rustc-rayon", "rustc-rayon-core", @@ -3455,7 +3541,6 @@ dependencies = [ name = "rustc_driver" version = "0.0.0" dependencies = [ - "lazy_static", "libc", "rustc_ast", "rustc_ast_pretty", @@ -3529,7 +3614,6 @@ dependencies = [ name = "rustc_feature" version = "0.0.0" dependencies = [ - "lazy_static", "rustc_data_structures", "rustc_span", ] @@ -3546,7 +3630,6 @@ version = "0.0.0" name = "rustc_hir" version = "0.0.0" dependencies = [ - "lazy_static", "rustc_ast", "rustc_data_structures", "rustc_index", @@ -3600,7 +3683,6 @@ dependencies = [ name = "rustc_infer" version = "0.0.0" dependencies = [ - "arrayvec", "rustc_ast", "rustc_data_structures", "rustc_errors", @@ -3622,7 +3704,6 @@ name = "rustc_interface" version = "0.0.0" dependencies = [ "libc", - "once_cell", "rustc-rayon", "rustc_ast", "rustc_ast_lowering", @@ -3713,7 +3794,6 @@ dependencies = [ name = "rustc_metadata" version = "0.0.0" dependencies = [ - "flate2", "libc", "memmap", "rustc_ast", @@ -3721,6 +3801,7 @@ dependencies = [ "rustc_data_structures", "rustc_errors", "rustc_expand", + "rustc_feature", "rustc_hir", "rustc_hir_pretty", "rustc_index", @@ -3731,6 +3812,7 @@ dependencies = [ "rustc_span", "rustc_target", "smallvec 1.4.2", + "snap", "stable_deref_trait", "tracing", "winapi 0.3.9", @@ -3740,9 +3822,7 @@ dependencies = [ name = "rustc_middle" version = "0.0.0" dependencies = [ - "arrayvec", "bitflags", - "byteorder", "chalk-ir", "measureme", "polonius-engine", @@ -3771,9 +3851,10 @@ name = "rustc_mir" version = "0.0.0" dependencies = [ "either", - "itertools 0.8.2", + "itertools 0.9.0", "log_settings", "polonius-engine", + "regex", "rustc_apfloat", "rustc_ast", "rustc_attr", @@ -3855,6 +3936,7 @@ dependencies = [ "rustc_hir", "rustc_index", "rustc_middle", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_target", @@ -3895,7 +3977,7 @@ dependencies = [ name = "rustc_query_system" version = "0.0.0" dependencies = [ - "parking_lot 0.10.2", + "parking_lot 0.11.0", "rustc-rayon-core", "rustc_arena", "rustc_data_structures", @@ -3943,8 +4025,8 @@ dependencies = [ "rustc_data_structures", "rustc_hir", "rustc_hir_pretty", + "rustc_lexer", "rustc_middle", - "rustc_parse", "rustc_session", "rustc_span", "serde_json", @@ -4060,6 +4142,7 @@ dependencies = [ name = "rustc_traits" version = "0.0.0" dependencies = [ + "chalk-engine", "chalk-ir", "chalk-solve", "rustc_ast", @@ -4103,6 +4186,7 @@ dependencies = [ "rustc_hir_pretty", "rustc_index", "rustc_infer", + "rustc_macros", "rustc_middle", "rustc_session", "rustc_span", @@ -4125,9 +4209,10 @@ dependencies = [ name = "rustdoc" version = "0.0.0" dependencies = [ - "itertools 0.8.2", + "expect-test", + "itertools 0.9.0", "minifier", - "pulldown-cmark", + "pulldown-cmark 0.8.0", "rustc-rayon", "serde", "serde_json", @@ -4170,7 +4255,7 @@ dependencies = [ [[package]] name = "rustfmt-nightly" -version = "1.4.20" +version = "1.4.22" dependencies = [ "annotate-snippets 0.6.1", "anyhow", @@ -4328,10 +4413,23 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" dependencies = [ - "block-buffer", - "digest", + "block-buffer 0.7.3", + "digest 0.8.1", "fake-simd", - "opaque-debug", + "opaque-debug 0.2.3", +] + +[[package]] +name = "sha2" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1" +dependencies = [ + "block-buffer 0.9.0", + "cfg-if", + "cpuid-bool", + "digest 0.9.0", + "opaque-debug 0.3.0", ] [[package]] @@ -4402,6 +4500,12 @@ version = "1.4.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fbee7696b84bbf3d89a1c2eccff0850e3047ed46bfcd2e92c29a2d074d57e252" +[[package]] +name = "snap" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e" + [[package]] name = "socket2" version = "0.3.12" @@ -4422,9 +4526,9 @@ checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" [[package]] name = "stacker" -version = "0.1.11" +version = "0.1.12" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a92bc346006ae78c539d6ab2cf1a1532bc657b8339c464877a990ec82073c66f" +checksum = "21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786" dependencies = [ "cc", "cfg-if", @@ -4973,9 +5077,9 @@ dependencies = [ [[package]] name = "toml" -version = "0.5.6" +version = "0.5.7" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +checksum = "75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645" dependencies = [ "serde", ] @@ -4993,9 +5097,9 @@ dependencies = [ [[package]] name = "tracing-attributes" -version = "0.1.10" +version = "0.1.11" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "1fe233f4227389ab7df5b32649239da7ebe0b281824b4e84b342d04d3fd8c25e" +checksum = "80e0ccfc3378da0cce270c946b676a376943f5cd16aeba64568e7939806f4ada" dependencies = [ "proc-macro2", "quote", @@ -5004,13 +5108,34 @@ dependencies = [ [[package]] name = "tracing-core" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "db63662723c316b43ca36d833707cc93dff82a02ba3d7e354f342682cc8b3545" +checksum = "4f0e00789804e99b20f12bc7003ca416309d28a6f495d6af58d1e2c2842461b5" dependencies = [ "lazy_static", ] +[[package]] +name = "tracing-log" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e0f8c7178e13481ff6765bd169b33e8d554c5d2bbede5e32c356194be02b9b9" +dependencies = [ + "lazy_static", + "log", + "tracing-core", +] + +[[package]] +name = "tracing-serde" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b6ccba2f8f16e0ed268fc765d9b7ff22e965e7185d32f8f1ec8294fe17d86e79" +dependencies = [ + "serde", + "tracing-core", +] + [[package]] name = "tracing-subscriber" version = "0.2.11" @@ -5018,14 +5143,33 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "abd165311cc4d7a555ad11cc77a37756df836182db0d81aac908c8184c584f40" dependencies = [ "ansi_term 0.12.1", + "chrono", "lazy_static", "matchers", "parking_lot 0.11.0", "regex", + "serde", + "serde_json", "sharded-slab", "smallvec 1.4.2", "thread_local", "tracing-core", + "tracing-log", + "tracing-serde", +] + +[[package]] +name = "tracing-tree" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e1a3dc4774db3a6b2d66a4f8d8de670e874ec3ed55615860c994927419b32c5f" +dependencies = [ + "ansi_term 0.12.1", + "atty", + "chrono", + "termcolor", + "tracing", + "tracing-subscriber", ] [[package]] diff --git a/Cargo.toml b/Cargo.toml index d8d9cc399c..02794d1028 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,7 @@ [workspace] members = [ "src/bootstrap", - "src/rustc", - "src/librustc_codegen_llvm", + "compiler/rustc", "library/std", "library/test", "src/tools/cargotest", @@ -10,6 +9,7 @@ members = [ "src/tools/compiletest", "src/tools/error_index_generator", "src/tools/linkchecker", + "src/tools/lint-docs", "src/tools/rustbook", "src/tools/unstable-book-gen", "src/tools/tidy", diff --git a/README.md b/README.md index 3399f7fe6c..d445bbdf6e 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,10 @@ standard library, and documentation. [Rust]: https://www.rust-lang.org -**Note: this README is for _users_ rather than _contributors_.** +**Note: this README is for _users_ rather than _contributors_. +If you wish to _contribute_ to the compiler, you should read the +[Getting Started][gettingstarted] of the rustc-dev-guide instead of this +section.** ## Quick Start @@ -18,10 +21,6 @@ Read ["Installation"] from [The Book]. ## Installing from Source -**Note: If you wish to _contribute_ to the compiler, you should read the -[Getting Started][gettingstarted] of the rustc-dev-guide instead of this -section.** - The Rust build system uses a Python script called `x.py` to build the compiler, which manages the bootstrapping process. More information about it can be found by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. @@ -36,6 +35,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. * `python` 3 or 2.7 * GNU `make` 3.81 or later * `cmake` 3.4.3 or later + * `ninja` * `curl` * `git` * `ssl` which comes in `libssl-dev` or `openssl-devel` @@ -44,8 +44,8 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. 2. Clone the [source] with `git`: ```sh - $ git clone https://github.com/rust-lang/rust.git - $ cd rust + git clone https://github.com/rust-lang/rust.git + cd rust ``` [source]: https://github.com/rust-lang/rust @@ -57,7 +57,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. Copy the default `config.toml.example` to `config.toml` to get started. ```sh - $ cp config.toml.example config.toml + cp config.toml.example config.toml ``` If you plan to use `x.py install` to create an installation, it is recommended @@ -68,7 +68,7 @@ by running `./x.py --help` or reading the [rustc dev guide][rustcguidebuild]. 4. Build and install: ```sh - $ ./x.py build && ./x.py install + ./x.py build && ./x.py install ``` When complete, `./x.py install` will place several programs into @@ -106,27 +106,28 @@ build. ```sh # Update package mirrors (may be needed if you have a fresh install of MSYS2) - $ pacman -Sy pacman-mirrors + pacman -Sy pacman-mirrors # Install build tools needed for Rust. If you're building a 32-bit compiler, # then replace "x86_64" below with "i686". If you've already got git, python, # or CMake installed and in PATH you can remove them from this list. Note - # that it is important that you do **not** use the 'python2' and 'cmake' + # that it is important that you do **not** use the 'python2', 'cmake' and 'ninja' # packages from the 'msys2' subsystem. The build has historically been known # to fail with these packages. - $ pacman -S git \ + pacman -S git \ make \ diffutils \ tar \ mingw-w64-x86_64-python \ mingw-w64-x86_64-cmake \ - mingw-w64-x86_64-gcc + mingw-w64-x86_64-gcc \ + mingw-w64-x86_64-ninja ``` 4. Navigate to Rust's source code (or clone it), then build it: ```sh - $ ./x.py build && ./x.py install + ./x.py build && ./x.py install ``` #### MSVC @@ -144,7 +145,7 @@ With these dependencies installed, you can build the compiler in a `cmd.exe` shell with: ```sh -> python x.py build +python x.py build ``` Currently, building Rust only works with some known versions of Visual Studio. If @@ -153,8 +154,8 @@ you may need to force rustbuild to use an older version. This can be done by manually calling the appropriate vcvars file before running the bootstrap. ```batch -> CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" -> python x.py build +CALL "C:\Program Files (x86)\Microsoft Visual Studio\2019\Community\VC\Auxiliary\Build\vcvars64.bat" +python x.py build ``` #### Specifying an ABI @@ -180,8 +181,8 @@ While it's not the recommended build system, this project also provides a configure script and makefile (the latter of which just invokes `x.py`). ```sh -$ ./configure -$ make && sudo make install +./configure +make && sudo make install ``` When using the configure script, the generated `config.mk` file may override the @@ -193,7 +194,7 @@ When using the configure script, the generated `config.mk` file may override the If you’d like to build the documentation, it’s almost the same: ```sh -$ ./x.py doc +./x.py doc ``` The generated documentation will appear under `doc` in the `build` directory for @@ -209,11 +210,17 @@ fetch snapshots, and an OS that can execute the available snapshot binaries. Snapshot binaries are currently built and tested on several platforms: -| Platform / Architecture | x86 | x86_64 | -|----------------------------|-----|--------| -| Windows (7, 8, 10, ...) | ✓ | ✓ | -| Linux (2.6.18 or later) | ✓ | ✓ | -| macOS (10.7 Lion or later) | ✓ | ✓ | +| Platform / Architecture | x86 | x86_64 | +|---------------------------------------------|-----|--------| +| Windows (7, 8, 10, ...) | ✓ | ✓ | +| Linux (kernel 2.6.32, glibc 2.11 or later) | ✓ | ✓ | +| macOS (10.7 Lion or later) | (\*) | ✓ | + +(\*): Apple dropped support for running 32-bit binaries starting from macOS 10.15 and iOS 11. +Due to this decision from Apple, the targets are no longer useful to our users. +Please read [our blog post][macx32] for more info. + +[macx32]: https://blog.rust-lang.org/2020/01/03/reducing-support-for-32-bit-apple-targets.html You may find that other platforms work, but these are our officially supported build environments that are most likely to work. @@ -235,6 +242,8 @@ The Rust community congregates in a few places: If you are interested in contributing to the Rust project, please take a look at the [Getting Started][gettingstarted] guide in the [rustc-dev-guide]. +[rustc-dev-guide]: https://rustc-dev-guide.rust-lang.org + ## License Rust is primarily distributed under the terms of both the MIT license diff --git a/RELEASES.md b/RELEASES.md index 10c4994f2d..62d30842b2 100644 --- a/RELEASES.md +++ b/RELEASES.md @@ -84,16 +84,15 @@ Compatibility Notes `Delimiter::None`. - [Moved support for the CloudABI target to tier 3.][75568] - [`linux-gnu` targets now require minimum kernel 2.6.32 and glibc 2.11.][74163] - -Internal Only --------- -- [Improved default settings for bootstrapping in `x.py`.][73964] You can read details about this change in the ["Changes to `x.py` defaults"](https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html) post on the Inside Rust blog. - [Added the `rustc-docs` component.][75560] This allows you to install and read the documentation for the compiler internal APIs. (Currently only available for `x86_64-unknown-linux-gnu`.) +Internal Only +-------- +- [Improved default settings for bootstrapping in `x.py`.][73964] You can read details about this change in the ["Changes To `x.py` Defaults"](https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html) post on the Inside Rust blog. + [1.47.0-cfg]: https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard -[76980]: https://github.com/rust-lang/rust/issues/76980 [75048]: https://github.com/rust-lang/rust/pull/75048/ [74163]: https://github.com/rust-lang/rust/pull/74163/ [71237]: https://github.com/rust-lang/rust/pull/71237/ diff --git a/src/rustc/Cargo.toml b/compiler/rustc/Cargo.toml similarity index 74% rename from src/rustc/Cargo.toml rename to compiler/rustc/Cargo.toml index 5e0f167bb3..6e6c0c71a1 100644 --- a/src/rustc/Cargo.toml +++ b/compiler/rustc/Cargo.toml @@ -4,16 +4,12 @@ name = "rustc-main" version = "0.0.0" edition = '2018' -[[bin]] -name = "rustc_binary" -path = "rustc.rs" - [dependencies] -rustc_driver = { path = "../librustc_driver" } +rustc_driver = { path = "../rustc_driver" } # Make sure rustc_codegen_ssa ends up in the sysroot, because this # crate is intended to be used by codegen backends, which may not be in-tree. -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } [dependencies.jemalloc-sys] version = '0.3.0' @@ -23,3 +19,4 @@ features = ['unprefixed_malloc_on_supported_platforms'] [features] jemalloc = ['jemalloc-sys'] llvm = ['rustc_driver/llvm'] +max_level_info = ['rustc_driver/max_level_info'] diff --git a/src/rustc/rustc.rs b/compiler/rustc/src/main.rs similarity index 100% rename from src/rustc/rustc.rs rename to compiler/rustc/src/main.rs diff --git a/src/librustc_apfloat/Cargo.toml b/compiler/rustc_apfloat/Cargo.toml similarity index 82% rename from src/librustc_apfloat/Cargo.toml rename to compiler/rustc_apfloat/Cargo.toml index 726965e1e7..306513f1a7 100644 --- a/src/librustc_apfloat/Cargo.toml +++ b/compiler/rustc_apfloat/Cargo.toml @@ -4,10 +4,6 @@ name = "rustc_apfloat" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_apfloat" -path = "lib.rs" - [dependencies] bitflags = "1.2.1" smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_apfloat/ieee.rs b/compiler/rustc_apfloat/src/ieee.rs similarity index 100% rename from src/librustc_apfloat/ieee.rs rename to compiler/rustc_apfloat/src/ieee.rs diff --git a/src/librustc_apfloat/lib.rs b/compiler/rustc_apfloat/src/lib.rs similarity index 99% rename from src/librustc_apfloat/lib.rs rename to compiler/rustc_apfloat/src/lib.rs index ba3adc4a13..4a845fcb69 100644 --- a/src/librustc_apfloat/lib.rs +++ b/compiler/rustc_apfloat/src/lib.rs @@ -30,7 +30,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![no_std] #![forbid(unsafe_code)] #![feature(nll)] diff --git a/src/librustc_apfloat/ppc.rs b/compiler/rustc_apfloat/src/ppc.rs similarity index 100% rename from src/librustc_apfloat/ppc.rs rename to compiler/rustc_apfloat/src/ppc.rs diff --git a/src/librustc_apfloat/tests/ieee.rs b/compiler/rustc_apfloat/tests/ieee.rs similarity index 100% rename from src/librustc_apfloat/tests/ieee.rs rename to compiler/rustc_apfloat/tests/ieee.rs diff --git a/src/librustc_apfloat/tests/ppc.rs b/compiler/rustc_apfloat/tests/ppc.rs similarity index 100% rename from src/librustc_apfloat/tests/ppc.rs rename to compiler/rustc_apfloat/tests/ppc.rs diff --git a/src/librustc_arena/Cargo.toml b/compiler/rustc_arena/Cargo.toml similarity index 63% rename from src/librustc_arena/Cargo.toml rename to compiler/rustc_arena/Cargo.toml index dfae956e2b..41701f3255 100644 --- a/src/librustc_arena/Cargo.toml +++ b/compiler/rustc_arena/Cargo.toml @@ -4,10 +4,6 @@ name = "rustc_arena" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_arena" -path = "lib.rs" - [dependencies] -rustc_data_structures = { path = "../librustc_data_structures" } +rustc_data_structures = { path = "../rustc_data_structures" } smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_arena/lib.rs b/compiler/rustc_arena/src/lib.rs similarity index 90% rename from src/librustc_arena/lib.rs rename to compiler/rustc_arena/src/lib.rs index 5e6a0340d1..166f7f53c4 100644 --- a/src/librustc_arena/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -8,16 +8,13 @@ //! This crate implements several kinds of arena. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", test(no_crate_inject, attr(deny(warnings))) )] -#![feature(core_intrinsics)] #![feature(dropck_eyepatch)] -#![feature(raw_vec_internals)] +#![feature(new_uninit)] +#![feature(maybe_uninit_slice)] #![cfg_attr(test, feature(test))] -#![allow(deprecated)] - -extern crate alloc; use rustc_data_structures::cold_path; use smallvec::SmallVec; @@ -25,14 +22,11 @@ use smallvec::SmallVec; use std::alloc::Layout; use std::cell::{Cell, RefCell}; use std::cmp; -use std::intrinsics; use std::marker::{PhantomData, Send}; -use std::mem; +use std::mem::{self, MaybeUninit}; use std::ptr; use std::slice; -use alloc::raw_vec::RawVec; - /// An arena that can hold objects of only one type. pub struct TypedArena { /// A pointer to the next object to be allocated. @@ -52,7 +46,7 @@ pub struct TypedArena { struct TypedArenaChunk { /// The raw storage for the arena chunk. - storage: RawVec, + storage: Box<[MaybeUninit]>, /// The number of valid entries in the chunk. entries: usize, } @@ -60,7 +54,7 @@ struct TypedArenaChunk { impl TypedArenaChunk { #[inline] unsafe fn new(capacity: usize) -> TypedArenaChunk { - TypedArenaChunk { storage: RawVec::with_capacity(capacity), entries: 0 } + TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } } /// Destroys this arena chunk. @@ -69,30 +63,25 @@ impl TypedArenaChunk { // The branch on needs_drop() is an -O1 performance optimization. // Without the branch, dropping TypedArena takes linear time. if mem::needs_drop::() { - let mut start = self.start(); - // Destroy all allocated objects. - for _ in 0..len { - ptr::drop_in_place(start); - start = start.offset(1); - } + ptr::drop_in_place(MaybeUninit::slice_assume_init_mut(&mut self.storage[..len])); } } // Returns a pointer to the first allocated object. #[inline] - fn start(&self) -> *mut T { - self.storage.ptr() + fn start(&mut self) -> *mut T { + MaybeUninit::slice_as_mut_ptr(&mut self.storage) } // Returns a pointer to the end of the allocated space. #[inline] - fn end(&self) -> *mut T { + fn end(&mut self) -> *mut T { unsafe { if mem::size_of::() == 0 { // A pointer as large as possible for zero-sized elements. !0 as *mut T } else { - self.start().add(self.storage.capacity()) + self.start().add(self.storage.len()) } } } @@ -130,7 +119,7 @@ impl TypedArena { unsafe { if mem::size_of::() == 0 { - self.ptr.set(intrinsics::arith_offset(self.ptr.get() as *mut u8, 1) as *mut T); + self.ptr.set((self.ptr.get() as *mut u8).wrapping_offset(1) as *mut T); let ptr = mem::align_of::() as *mut T; // Don't drop the object. This `write` is equivalent to `forget`. ptr::write(ptr, object); @@ -226,10 +215,10 @@ impl TypedArena { let used_bytes = self.ptr.get() as usize - last_chunk.start() as usize; last_chunk.entries = used_bytes / mem::size_of::(); - // If the previous chunk's capacity is less than HUGE_PAGE + // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.capacity(); + new_cap = last_chunk.storage.len(); if new_cap < HUGE_PAGE / elem_size { new_cap = new_cap.checked_mul(2).unwrap(); } @@ -239,7 +228,7 @@ impl TypedArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let chunk = TypedArenaChunk::::new(new_cap); + let mut chunk = TypedArenaChunk::::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -301,7 +290,7 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { chunk.destroy(chunk.entries); } } - // RawVec handles deallocation of `last_chunk` and `self.chunks`. + // Box handles deallocation of `last_chunk` and `self.chunks`. } } } @@ -309,11 +298,13 @@ unsafe impl<#[may_dangle] T> Drop for TypedArena { unsafe impl Send for TypedArena {} pub struct DroplessArena { - /// A pointer to the next object to be allocated. - ptr: Cell<*mut u8>, + /// A pointer to the start of the free space. + start: Cell<*mut u8>, - /// A pointer to the end of the allocated area. When this pointer is - /// reached, a new chunk is allocated. + /// A pointer to the end of free space. + /// + /// The allocation proceeds from the end of the chunk towards the start. + /// When this pointer crosses the start pointer, a new chunk is allocated. end: Cell<*mut u8>, /// A vector of arena chunks. @@ -326,7 +317,7 @@ impl Default for DroplessArena { #[inline] fn default() -> DroplessArena { DroplessArena { - ptr: Cell::new(ptr::null_mut()), + start: Cell::new(ptr::null_mut()), end: Cell::new(ptr::null_mut()), chunks: Default::default(), } @@ -344,10 +335,10 @@ impl DroplessArena { // There is no need to update `last_chunk.entries` because that // field isn't used by `DroplessArena`. - // If the previous chunk's capacity is less than HUGE_PAGE + // If the previous chunk's len is less than HUGE_PAGE // bytes, then this chunk will be least double the previous // chunk's size. - new_cap = last_chunk.storage.capacity(); + new_cap = last_chunk.storage.len(); if new_cap < HUGE_PAGE { new_cap = new_cap.checked_mul(2).unwrap(); } @@ -357,8 +348,8 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let chunk = TypedArenaChunk::::new(new_cap); - self.ptr.set(chunk.start()); + let mut chunk = TypedArenaChunk::::new(new_cap); + self.start.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); } @@ -369,24 +360,17 @@ impl DroplessArena { /// request. #[inline] fn alloc_raw_without_grow(&self, layout: Layout) -> Option<*mut u8> { - let ptr = self.ptr.get() as usize; + let start = self.start.get() as usize; let end = self.end.get() as usize; + let align = layout.align(); let bytes = layout.size(); - // The allocation request fits into the current chunk iff: - // - // let aligned = align_to(ptr, align); - // ptr <= aligned && aligned + bytes <= end - // - // Except that we work with fixed width integers and need to be careful - // about potential overflow in the calcuation. If the overflow does - // happen, then we definitely don't have enough free and need to grow - // the arena. - let aligned = ptr.checked_add(align - 1)? & !(align - 1); - let new_ptr = aligned.checked_add(bytes)?; - if new_ptr <= end { - self.ptr.set(new_ptr as *mut u8); - Some(aligned as *mut u8) + + let new_end = end.checked_sub(bytes)? & !(align - 1); + if start <= new_end { + let new_end = new_end as *mut u8; + self.end.set(new_end); + Some(new_end) } else { None } diff --git a/src/librustc_arena/tests.rs b/compiler/rustc_arena/src/tests.rs similarity index 94% rename from src/librustc_arena/tests.rs rename to compiler/rustc_arena/src/tests.rs index 8e63bdf545..e8a1f2db1a 100644 --- a/src/librustc_arena/tests.rs +++ b/compiler/rustc_arena/src/tests.rs @@ -121,6 +121,17 @@ pub fn bench_typed_arena_clear(b: &mut Bencher) { }) } +#[bench] +pub fn bench_typed_arena_clear_100(b: &mut Bencher) { + let mut arena = TypedArena::default(); + b.iter(|| { + for _ in 0..100 { + arena.alloc(Point { x: 1, y: 2, z: 3 }); + } + arena.clear(); + }) +} + // Drop tests struct DropCounter<'a> { diff --git a/compiler/rustc_ast/Cargo.toml b/compiler/rustc_ast/Cargo.toml new file mode 100644 index 0000000000..13e17a807c --- /dev/null +++ b/compiler/rustc_ast/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_serialize = { path = "../rustc_serialize" } +tracing = "0.1" +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +bitflags = "1.2.1" diff --git a/src/librustc_ast/README.md b/compiler/rustc_ast/README.md similarity index 100% rename from src/librustc_ast/README.md rename to compiler/rustc_ast/README.md diff --git a/src/librustc_ast/ast.rs b/compiler/rustc_ast/src/ast.rs similarity index 98% rename from src/librustc_ast/ast.rs rename to compiler/rustc_ast/src/ast.rs index 127a53cad2..95abf55291 100644 --- a/src/librustc_ast/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -96,6 +96,7 @@ pub struct Path { /// The segments in the path: the things separated by `::`. /// Global paths begin with `kw::PathRoot`. pub segments: Vec, + pub tokens: Option, } impl PartialEq for Path { @@ -117,7 +118,7 @@ impl Path { // Convert a span and an identifier to the corresponding // one-segment path. pub fn from_ident(ident: Ident) -> Path { - Path { segments: vec![PathSegment::from_ident(ident)], span: ident.span } + Path { segments: vec![PathSegment::from_ident(ident)], span: ident.span, tokens: None } } pub fn is_global(&self) -> bool { @@ -540,6 +541,7 @@ pub struct Block { /// Distinguishes between `unsafe { ... }` and `{ ... }`. pub rules: BlockCheckMode, pub span: Span, + pub tokens: Option, } /// A match pattern. @@ -586,7 +588,7 @@ impl Pat { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span })) + Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) } /// Walk top-down and call `it` in each place where a pattern occurs @@ -916,15 +918,20 @@ pub struct Stmt { pub id: NodeId, pub kind: StmtKind, pub span: Span, + pub tokens: Option, } impl Stmt { pub fn add_trailing_semicolon(mut self) -> Self { self.kind = match self.kind { StmtKind::Expr(expr) => StmtKind::Semi(expr), - StmtKind::MacCall(mac) => StmtKind::MacCall( - mac.map(|(mac, _style, attrs)| (mac, MacStmtStyle::Semicolon, attrs)), - ), + StmtKind::MacCall(mac) => { + StmtKind::MacCall(mac.map(|MacCallStmt { mac, style: _, attrs }| MacCallStmt { + mac, + style: MacStmtStyle::Semicolon, + attrs, + })) + } kind => kind, }; self @@ -958,7 +965,14 @@ pub enum StmtKind { /// Just a trailing semi-colon. Empty, /// Macro. - MacCall(P<(MacCall, MacStmtStyle, AttrVec)>), + MacCall(P), +} + +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct MacCallStmt { + pub mac: MacCall, + pub style: MacStmtStyle, + pub attrs: AttrVec, } #[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug)] @@ -1057,7 +1071,7 @@ pub struct Expr { // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Expr, 104); +rustc_data_structures::static_assert_size!(Expr, 112); impl Expr { /// Returns `true` if this expression would be valid somewhere that expects a value; @@ -1157,7 +1171,7 @@ impl Expr { _ => return None, }; - Some(P(Ty { kind, id: self.id, span: self.span })) + Some(P(Ty { kind, id: self.id, span: self.span, tokens: None })) } pub fn precedence(&self) -> ExprPrecedence { @@ -1855,6 +1869,7 @@ pub struct Ty { pub id: NodeId, pub kind: TyKind, pub span: Span, + pub tokens: Option, } #[derive(Clone, Encodable, Decodable, Debug)] @@ -1916,7 +1931,7 @@ pub enum TyKind { impl TyKind { pub fn is_implicit_self(&self) -> bool { - if let TyKind::ImplicitSelf = *self { true } else { false } + matches!(self, TyKind::ImplicitSelf) } pub fn is_unit(&self) -> bool { @@ -2133,7 +2148,7 @@ impl Param { /// Builds a `Param` object from `ExplicitSelf`. pub fn from_self(attrs: AttrVec, eself: ExplicitSelf, eself_ident: Ident) -> Param { let span = eself.span.to(eself_ident.span); - let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span }); + let infer_ty = P(Ty { id: DUMMY_NODE_ID, kind: TyKind::ImplicitSelf, span, tokens: None }); let param = |mutbl, ty| Param { attrs, pat: P(Pat { @@ -2156,6 +2171,7 @@ impl Param { id: DUMMY_NODE_ID, kind: TyKind::Rptr(lt, MutTy { ty: infer_ty, mutbl }), span, + tokens: None, }), ), } @@ -2211,7 +2227,7 @@ pub enum Async { impl Async { pub fn is_async(self) -> bool { - if let Async::Yes { .. } = self { true } else { false } + matches!(self, Async::Yes { .. }) } /// In this case this is an `async` return, the `NodeId` for the generated `impl Trait` item. @@ -2278,12 +2294,15 @@ impl FnRetTy { /// Module declaration. /// /// E.g., `mod foo;` or `mod foo { .. }`. -#[derive(Clone, Encodable, Decodable, Debug, Default)] +#[derive(Clone, Encodable, Decodable, Debug)] pub struct Mod { /// A span from the first token past `{` to the last token until `}`. /// For `mod foo;`, the inner span ranges from the first token /// to the last token in the external file. pub inner: Span, + /// `unsafe` keyword accepted syntactically for macro DSLs, but not + /// semantically by Rust. + pub unsafety: Unsafe, pub items: Vec>, /// `true` for `mod foo { .. }`; `false` for `mod foo;`. pub inline: bool, @@ -2291,9 +2310,12 @@ pub struct Mod { /// Foreign module declaration. /// -/// E.g., `extern { .. }` or `extern C { .. }`. +/// E.g., `extern { .. }` or `extern "C" { .. }`. #[derive(Clone, Encodable, Decodable, Debug)] pub struct ForeignMod { + /// `unsafe` keyword accepted syntactically for macro DSLs, but not + /// semantically by Rust. + pub unsafety: Unsafe, pub abi: Option, pub items: Vec>, } @@ -2399,6 +2421,7 @@ impl rustc_serialize::Decodable for AttrId { pub struct AttrItem { pub path: Path, pub args: MacArgs, + pub tokens: Option, } /// A list of attributes. @@ -2468,7 +2491,12 @@ pub enum CrateSugar { JustCrate, } -pub type Visibility = Spanned; +#[derive(Clone, Encodable, Decodable, Debug)] +pub struct Visibility { + pub kind: VisibilityKind, + pub span: Span, + pub tokens: Option, +} #[derive(Clone, Encodable, Decodable, Debug)] pub enum VisibilityKind { @@ -2480,7 +2508,7 @@ pub enum VisibilityKind { impl VisibilityKind { pub fn is_pub(&self) -> bool { - if let VisibilityKind::Public = *self { true } else { false } + matches!(self, VisibilityKind::Public) } } diff --git a/src/librustc_ast/ast/tests.rs b/compiler/rustc_ast/src/ast/tests.rs similarity index 100% rename from src/librustc_ast/ast/tests.rs rename to compiler/rustc_ast/src/ast/tests.rs diff --git a/src/librustc_ast/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs similarity index 96% rename from src/librustc_ast/attr/mod.rs rename to compiler/rustc_ast/src/attr/mod.rs index edcbce3e2c..2782869fb8 100644 --- a/src/librustc_ast/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -8,7 +8,7 @@ use crate::ast::{Path, PathSegment}; use crate::mut_visit::visit_clobber; use crate::ptr::P; use crate::token::{self, CommentKind, Token}; -use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use crate::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_index::bit_set::GrowableBitSet; use rustc_span::source_map::{BytePos, Spanned}; @@ -16,7 +16,6 @@ use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; use std::iter; -use std::ops::DerefMut; pub struct MarkedAttrs(GrowableBitSet); @@ -331,7 +330,7 @@ crate fn mk_attr_id() -> AttrId { } pub fn mk_attr(style: AttrStyle, path: Path, args: MacArgs, span: Span) -> Attribute { - mk_attr_from_item(style, AttrItem { path, args }, span) + mk_attr_from_item(style, AttrItem { path, args, tokens: None }, span) } pub fn mk_attr_from_item(style: AttrStyle, item: AttrItem, span: Span) -> Attribute { @@ -362,7 +361,7 @@ pub fn list_contains_name(items: &[NestedMetaItem], name: Symbol) -> bool { } impl MetaItem { - fn token_trees_and_joints(&self) -> Vec { + fn token_trees_and_spacings(&self) -> Vec { let mut idents = vec![]; let mut last_pos = BytePos(0 as u32); for (i, segment) in self.path.segments.iter().enumerate() { @@ -375,7 +374,7 @@ impl MetaItem { idents.push(TokenTree::Token(Token::from_ast_ident(segment.ident)).into()); last_pos = segment.ident.span.hi(); } - idents.extend(self.kind.token_trees_and_joints(self.span)); + idents.extend(self.kind.token_trees_and_spacings(self.span)); idents } @@ -416,7 +415,7 @@ impl MetaItem { } } let span = span.with_hi(segments.last().unwrap().ident.span.hi()); - Path { span, segments } + Path { span, segments, tokens: None } } Some(TokenTree::Token(Token { kind: token::Interpolated(nt), .. })) => match *nt { token::Nonterminal::NtMeta(ref item) => return item.meta(item.path.span), @@ -448,7 +447,7 @@ impl MetaItemKind { if i > 0 { tts.push(TokenTree::token(token::Comma, span).into()); } - tts.extend(item.token_trees_and_joints()) + tts.extend(item.token_trees_and_spacings()) } MacArgs::Delimited( DelimSpan::from_single(span), @@ -459,7 +458,7 @@ impl MetaItemKind { } } - fn token_trees_and_joints(&self, span: Span) -> Vec { + fn token_trees_and_spacings(&self, span: Span) -> Vec { match *self { MetaItemKind::Word => vec![], MetaItemKind::NameValue(ref lit) => { @@ -471,7 +470,7 @@ impl MetaItemKind { if i > 0 { tokens.push(TokenTree::token(token::Comma, span).into()); } - tokens.extend(item.token_trees_and_joints()) + tokens.extend(item.token_trees_and_spacings()) } vec![ TokenTree::Delimited( @@ -554,9 +553,9 @@ impl NestedMetaItem { } } - fn token_trees_and_joints(&self) -> Vec { + fn token_trees_and_spacings(&self) -> Vec { match *self { - NestedMetaItem::MetaItem(ref item) => item.token_trees_and_joints(), + NestedMetaItem::MetaItem(ref item) => item.token_trees_and_spacings(), NestedMetaItem::Literal(ref lit) => vec![lit.token_tree().into()], } } @@ -634,10 +633,7 @@ impl HasAttrs for StmtKind { StmtKind::Local(ref local) => local.attrs(), StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => expr.attrs(), StmtKind::Empty | StmtKind::Item(..) => &[], - StmtKind::MacCall(ref mac) => { - let (_, _, ref attrs) = **mac; - attrs.attrs() - } + StmtKind::MacCall(ref mac) => mac.attrs.attrs(), } } @@ -647,8 +643,7 @@ impl HasAttrs for StmtKind { StmtKind::Expr(expr) | StmtKind::Semi(expr) => expr.visit_attrs(f), StmtKind::Empty | StmtKind::Item(..) => {} StmtKind::MacCall(mac) => { - let (_mac, _style, attrs) = mac.deref_mut(); - attrs.visit_attrs(f); + mac.attrs.visit_attrs(f); } } } diff --git a/src/librustc_ast/crate_disambiguator.rs b/compiler/rustc_ast/src/crate_disambiguator.rs similarity index 100% rename from src/librustc_ast/crate_disambiguator.rs rename to compiler/rustc_ast/src/crate_disambiguator.rs diff --git a/src/librustc_ast/entry.rs b/compiler/rustc_ast/src/entry.rs similarity index 100% rename from src/librustc_ast/entry.rs rename to compiler/rustc_ast/src/entry.rs diff --git a/src/librustc_ast/expand/allocator.rs b/compiler/rustc_ast/src/expand/allocator.rs similarity index 100% rename from src/librustc_ast/expand/allocator.rs rename to compiler/rustc_ast/src/expand/allocator.rs diff --git a/src/librustc_ast/expand/mod.rs b/compiler/rustc_ast/src/expand/mod.rs similarity index 100% rename from src/librustc_ast/expand/mod.rs rename to compiler/rustc_ast/src/expand/mod.rs diff --git a/src/librustc_ast/lib.rs b/compiler/rustc_ast/src/lib.rs similarity index 90% rename from src/librustc_ast/lib.rs rename to compiler/rustc_ast/src/lib.rs index b556c1a446..6e47ff7d74 100644 --- a/src/librustc_ast/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -4,18 +4,18 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/", test(attr(deny(warnings))))] -#![feature(bool_to_option)] +#![doc( + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", + test(attr(deny(warnings))) +)] #![feature(box_syntax)] #![feature(const_fn)] // For the `transmute` in `P::new` -#![feature(const_panic)] #![feature(const_fn_transmute)] +#![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(label_break_value)] #![feature(nll)] #![feature(or_patterns)] -#![feature(try_trait)] -#![feature(unicode_internals)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustc_ast/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs similarity index 97% rename from src/librustc_ast/mut_visit.rs rename to compiler/rustc_ast/src/mut_visit.rs index 965571aaa5..425ef83b57 100644 --- a/src/librustc_ast/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -14,7 +14,7 @@ use crate::tokenstream::*; use rustc_data_structures::map_in_place::MapInPlace; use rustc_data_structures::sync::Lrc; -use rustc_span::source_map::{respan, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; use rustc_span::Span; @@ -451,7 +451,7 @@ pub fn noop_visit_ty_constraint( } pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { - let Ty { id, kind, span } = ty.deref_mut(); + let Ty { id, kind, span, tokens: _ } = ty.deref_mut(); vis.visit_id(id); match kind { TyKind::Infer | TyKind::ImplicitSelf | TyKind::Err | TyKind::Never | TyKind::CVarArgs => {} @@ -490,7 +490,7 @@ pub fn noop_visit_ty(ty: &mut P, vis: &mut T) { } pub fn noop_visit_foreign_mod(foreign_mod: &mut ForeignMod, vis: &mut T) { - let ForeignMod { abi: _, items } = foreign_mod; + let ForeignMod { unsafety: _, abi: _, items } = foreign_mod; items.flat_map_in_place(|item| vis.flat_map_foreign_item(item)); } @@ -513,7 +513,7 @@ pub fn noop_visit_ident(Ident { name: _, span }: &mut Ident, vis: vis.visit_span(span); } -pub fn noop_visit_path(Path { segments, span }: &mut Path, vis: &mut T) { +pub fn noop_visit_path(Path { segments, span, tokens: _ }: &mut Path, vis: &mut T) { vis.visit_span(span); for PathSegment { ident, id, args } in segments { vis.visit_ident(ident); @@ -579,7 +579,7 @@ pub fn noop_visit_local(local: &mut P, vis: &mut T) { pub fn noop_visit_attribute(attr: &mut Attribute, vis: &mut T) { let Attribute { kind, id: _, style: _, span } = attr; match kind { - AttrKind::Normal(AttrItem { path, args }) => { + AttrKind::Normal(AttrItem { path, args, tokens: _ }) => { vis.visit_path(path); visit_mac_args(args, vis); } @@ -709,7 +709,7 @@ pub fn noop_visit_interpolated(nt: &mut token::Nonterminal, vis: token::NtLifetime(ident) => vis.visit_ident(ident), token::NtLiteral(expr) => vis.visit_expr(expr), token::NtMeta(item) => { - let AttrItem { path, args } = item.deref_mut(); + let AttrItem { path, args, tokens: _ } = item.deref_mut(); vis.visit_path(path); visit_mac_args(args, vis); } @@ -871,7 +871,7 @@ pub fn noop_visit_mt(MutTy { ty, mutbl: _ }: &mut MutTy, vis: &mu } pub fn noop_visit_block(block: &mut P, vis: &mut T) { - let Block { id, stmts, rules: _, span } = block.deref_mut(); + let Block { id, stmts, rules: _, span, tokens: _ } = block.deref_mut(); vis.visit_id(id); stmts.flat_map_in_place(|stmt| vis.flat_map_stmt(stmt)); vis.visit_span(span); @@ -970,18 +970,21 @@ pub fn noop_visit_fn_header(header: &mut FnHeader, vis: &mut T) { vis.visit_asyncness(asyncness); } -pub fn noop_visit_mod(Mod { inner, items, inline: _ }: &mut Mod, vis: &mut T) { +pub fn noop_visit_mod(module: &mut Mod, vis: &mut T) { + let Mod { inner, unsafety: _, items, inline: _ } = module; vis.visit_span(inner); items.flat_map_in_place(|item| vis.flat_map_item(item)); } pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { visit_clobber(krate, |Crate { module, attrs, span, proc_macros }| { + let item_vis = + Visibility { kind: VisibilityKind::Public, span: span.shrink_to_lo(), tokens: None }; let item = P(Item { ident: Ident::invalid(), attrs, id: DUMMY_NODE_ID, - vis: respan(span.shrink_to_lo(), VisibilityKind::Public), + vis: item_vis, span, kind: ItemKind::Mod(module), tokens: None, @@ -990,7 +993,7 @@ pub fn noop_visit_crate(krate: &mut Crate, vis: &mut T) { let len = items.len(); if len == 0 { - let module = Mod { inner: span, items: vec![], inline: true }; + let module = Mod { inner: span, unsafety: Unsafe::No, items: vec![], inline: true }; Crate { module, attrs: vec![], span, proc_macros } } else if len == 1 { let Item { attrs, span, kind, .. } = items.into_iter().next().unwrap().into_inner(); @@ -1283,12 +1286,15 @@ pub fn noop_filter_map_expr(mut e: P, vis: &mut T) -> Optio } pub fn noop_flat_map_stmt( - Stmt { kind, mut span, mut id }: Stmt, + Stmt { kind, mut span, mut id, tokens }: Stmt, vis: &mut T, ) -> SmallVec<[Stmt; 1]> { vis.visit_id(&mut id); vis.visit_span(&mut span); - noop_flat_map_stmt_kind(kind, vis).into_iter().map(|kind| Stmt { id, kind, span }).collect() + noop_flat_map_stmt_kind(kind, vis) + .into_iter() + .map(|kind| Stmt { id, kind, span, tokens: tokens.clone() }) + .collect() } pub fn noop_flat_map_stmt_kind( @@ -1305,7 +1311,7 @@ pub fn noop_flat_map_stmt_kind( StmtKind::Semi(expr) => vis.filter_map_expr(expr).into_iter().map(StmtKind::Semi).collect(), StmtKind::Empty => smallvec![StmtKind::Empty], StmtKind::MacCall(mut mac) => { - let (mac_, _semi, attrs) = mac.deref_mut(); + let MacCallStmt { mac: mac_, style: _, attrs } = mac.deref_mut(); vis.visit_mac(mac_); visit_thin_attrs(attrs, vis); smallvec![StmtKind::MacCall(mac)] @@ -1313,13 +1319,13 @@ pub fn noop_flat_map_stmt_kind( } } -pub fn noop_visit_vis(Spanned { node, span }: &mut Visibility, vis: &mut T) { - match node { +pub fn noop_visit_vis(visibility: &mut Visibility, vis: &mut T) { + match &mut visibility.kind { VisibilityKind::Public | VisibilityKind::Crate(_) | VisibilityKind::Inherited => {} VisibilityKind::Restricted { path, id } => { vis.visit_path(path); vis.visit_id(id); } } - vis.visit_span(span); + vis.visit_span(&mut visibility.span); } diff --git a/src/librustc_ast/node_id.rs b/compiler/rustc_ast/src/node_id.rs similarity index 100% rename from src/librustc_ast/node_id.rs rename to compiler/rustc_ast/src/node_id.rs diff --git a/src/librustc_ast/ptr.rs b/compiler/rustc_ast/src/ptr.rs similarity index 100% rename from src/librustc_ast/ptr.rs rename to compiler/rustc_ast/src/ptr.rs diff --git a/src/librustc_ast/token.rs b/compiler/rustc_ast/src/token.rs similarity index 97% rename from src/librustc_ast/token.rs rename to compiler/rustc_ast/src/token.rs index 7e58aab5a7..d5b3e87adc 100644 --- a/src/librustc_ast/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -173,6 +173,7 @@ pub fn ident_can_begin_expr(name: Symbol, span: Span, is_raw: bool) -> bool { kw::Move, kw::Return, kw::True, + kw::Try, kw::Unsafe, kw::While, kw::Yield, @@ -251,17 +252,6 @@ pub enum TokenKind { /// similarly to symbols in string literal tokens. DocComment(CommentKind, ast::AttrStyle, Symbol), - // Junk. These carry no data because we don't really care about the data - // they *would* carry, and don't really want to allocate a new ident for - // them. Instead, users could extract that from the associated span. - /// Whitespace. - Whitespace, - /// A comment. - Comment, - Shebang(Symbol), - /// A completely invalid token which should be skipped. - Unknown(Symbol), - Eof, } @@ -331,7 +321,7 @@ impl Token { /// Some token that will be thrown away later. pub fn dummy() -> Self { - Token::new(TokenKind::Whitespace, DUMMY_SP) + Token::new(TokenKind::Question, DUMMY_SP) } /// Recovers a `Token` from an `Ident`. This creates a raw identifier if necessary. @@ -360,7 +350,7 @@ impl Token { pub fn is_op(&self) -> bool { match self.kind { OpenDelim(..) | CloseDelim(..) | Literal(..) | DocComment(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | Whitespace | Comment | Shebang(..) | Eof => false, + | Lifetime(..) | Interpolated(..) | Eof => false, _ => true, } } @@ -676,8 +666,7 @@ impl Token { Le | EqEq | Ne | Ge | AndAnd | OrOr | Tilde | BinOpEq(..) | At | DotDotDot | DotDotEq | Comma | Semi | ModSep | RArrow | LArrow | FatArrow | Pound | Dollar | Question | OpenDelim(..) | CloseDelim(..) | Literal(..) | Ident(..) - | Lifetime(..) | Interpolated(..) | DocComment(..) | Whitespace | Comment - | Shebang(..) | Unknown(..) | Eof => return None, + | Lifetime(..) | Interpolated(..) | DocComment(..) | Eof => return None, }; Some(Token::new(kind, self.span.to(joint.span))) @@ -711,7 +700,7 @@ pub enum Nonterminal { // `Nonterminal` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -rustc_data_structures::static_assert_size!(Nonterminal, 40); +rustc_data_structures::static_assert_size!(Nonterminal, 48); #[derive(Debug, Copy, Clone, PartialEq, Encodable, Decodable)] pub enum NonterminalKind { diff --git a/src/librustc_ast/tokenstream.rs b/compiler/rustc_ast/src/tokenstream.rs similarity index 93% rename from src/librustc_ast/tokenstream.rs rename to compiler/rustc_ast/src/tokenstream.rs index 151acddae8..f201f0b5c6 100644 --- a/src/librustc_ast/tokenstream.rs +++ b/compiler/rustc_ast/src/tokenstream.rs @@ -83,7 +83,7 @@ impl TokenTree { } pub fn joint(self) -> TokenStream { - TokenStream::new(vec![(self, Joint)]) + TokenStream::new(vec![(self, Spacing::Joint)]) } pub fn token(kind: TokenKind, span: Span) -> TokenTree { @@ -125,22 +125,20 @@ where /// instead of a representation of the abstract syntax tree. /// Today's `TokenTree`s can still contain AST via `token::Interpolated` for back-compat. #[derive(Clone, Debug, Default, Encodable, Decodable)] -pub struct TokenStream(pub Lrc>); +pub struct TokenStream(pub Lrc>); -pub type TreeAndJoint = (TokenTree, IsJoint); +pub type TreeAndSpacing = (TokenTree, Spacing); // `TokenStream` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] rustc_data_structures::static_assert_size!(TokenStream, 8); #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable)] -pub enum IsJoint { +pub enum Spacing { + Alone, Joint, - NonJoint, } -use IsJoint::*; - impl TokenStream { /// Given a `TokenStream` with a `Stream` of only two arguments, return a new `TokenStream` /// separating the two arguments with a comma for diagnostic suggestions. @@ -153,7 +151,7 @@ impl TokenStream { let sp = match (&ts, &next) { (_, (TokenTree::Token(Token { kind: token::Comma, .. }), _)) => continue, ( - (TokenTree::Token(token_left), NonJoint), + (TokenTree::Token(token_left), Spacing::Alone), (TokenTree::Token(token_right), _), ) if ((token_left.is_ident() && !token_left.is_reserved_ident()) || token_left.is_lit()) @@ -162,11 +160,11 @@ impl TokenStream { { token_left.span } - ((TokenTree::Delimited(sp, ..), NonJoint), _) => sp.entire(), + ((TokenTree::Delimited(sp, ..), Spacing::Alone), _) => sp.entire(), _ => continue, }; let sp = sp.shrink_to_hi(); - let comma = (TokenTree::token(token::Comma, sp), NonJoint); + let comma = (TokenTree::token(token::Comma, sp), Spacing::Alone); suggestion = Some((pos, comma, sp)); } } @@ -184,19 +182,19 @@ impl TokenStream { impl From for TokenStream { fn from(tree: TokenTree) -> TokenStream { - TokenStream::new(vec![(tree, NonJoint)]) + TokenStream::new(vec![(tree, Spacing::Alone)]) } } -impl From for TreeAndJoint { - fn from(tree: TokenTree) -> TreeAndJoint { - (tree, NonJoint) +impl From for TreeAndSpacing { + fn from(tree: TokenTree) -> TreeAndSpacing { + (tree, Spacing::Alone) } } impl iter::FromIterator for TokenStream { fn from_iter>(iter: I) -> Self { - TokenStream::new(iter.into_iter().map(Into::into).collect::>()) + TokenStream::new(iter.into_iter().map(Into::into).collect::>()) } } @@ -209,7 +207,7 @@ impl PartialEq for TokenStream { } impl TokenStream { - pub fn new(streams: Vec) -> TokenStream { + pub fn new(streams: Vec) -> TokenStream { TokenStream(Lrc::new(streams)) } @@ -320,11 +318,11 @@ impl TokenStreamBuilder { // If `self` is not empty and the last tree within the last stream is a // token tree marked with `Joint`... if let Some(TokenStream(ref mut last_stream_lrc)) = self.0.last_mut() { - if let Some((TokenTree::Token(last_token), Joint)) = last_stream_lrc.last() { + if let Some((TokenTree::Token(last_token), Spacing::Joint)) = last_stream_lrc.last() { // ...and `stream` is not empty and the first tree within it is // a token tree... let TokenStream(ref mut stream_lrc) = stream; - if let Some((TokenTree::Token(token), is_joint)) = stream_lrc.first() { + if let Some((TokenTree::Token(token), spacing)) = stream_lrc.first() { // ...and the two tokens can be glued together... if let Some(glued_tok) = last_token.glue(&token) { // ...then do so, by overwriting the last token @@ -337,8 +335,7 @@ impl TokenStreamBuilder { // Overwrite the last token tree with the merged // token. let last_vec_mut = Lrc::make_mut(last_stream_lrc); - *last_vec_mut.last_mut().unwrap() = - (TokenTree::Token(glued_tok), *is_joint); + *last_vec_mut.last_mut().unwrap() = (TokenTree::Token(glued_tok), *spacing); // Remove the first token tree from `stream`. (This // is almost always the only tree in `stream`.) @@ -375,7 +372,7 @@ impl Iterator for Cursor { type Item = TokenTree; fn next(&mut self) -> Option { - self.next_with_joint().map(|(tree, _)| tree) + self.next_with_spacing().map(|(tree, _)| tree) } } @@ -384,7 +381,7 @@ impl Cursor { Cursor { stream, index: 0 } } - pub fn next_with_joint(&mut self) -> Option { + pub fn next_with_spacing(&mut self) -> Option { if self.index < self.stream.len() { self.index += 1; Some(self.stream.0[self.index - 1].clone()) diff --git a/src/librustc_ast/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs similarity index 100% rename from src/librustc_ast/util/classify.rs rename to compiler/rustc_ast/src/util/classify.rs diff --git a/src/librustc_ast/util/comments.rs b/compiler/rustc_ast/src/util/comments.rs similarity index 100% rename from src/librustc_ast/util/comments.rs rename to compiler/rustc_ast/src/util/comments.rs diff --git a/src/librustc_ast/util/comments/tests.rs b/compiler/rustc_ast/src/util/comments/tests.rs similarity index 100% rename from src/librustc_ast/util/comments/tests.rs rename to compiler/rustc_ast/src/util/comments/tests.rs diff --git a/src/librustc_ast/util/lev_distance.rs b/compiler/rustc_ast/src/util/lev_distance.rs similarity index 97% rename from src/librustc_ast/util/lev_distance.rs rename to compiler/rustc_ast/src/util/lev_distance.rs index d4e0e3ba05..754b1f1338 100644 --- a/src/librustc_ast/util/lev_distance.rs +++ b/compiler/rustc_ast/src/util/lev_distance.rs @@ -103,6 +103,7 @@ fn find_match_by_sorted_words<'a>(iter_names: Vec<&'a Symbol>, lookup: &str) -> fn sort_by_words(name: &str) -> String { let mut split_words: Vec<&str> = name.split('_').collect(); - split_words.sort(); + // We are sorting primitive &strs and can use unstable sort here + split_words.sort_unstable(); split_words.join("_") } diff --git a/src/librustc_ast/util/lev_distance/tests.rs b/compiler/rustc_ast/src/util/lev_distance/tests.rs similarity index 100% rename from src/librustc_ast/util/lev_distance/tests.rs rename to compiler/rustc_ast/src/util/lev_distance/tests.rs diff --git a/src/librustc_ast/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs similarity index 100% rename from src/librustc_ast/util/literal.rs rename to compiler/rustc_ast/src/util/literal.rs diff --git a/src/librustc_ast/util/parser.rs b/compiler/rustc_ast/src/util/parser.rs similarity index 100% rename from src/librustc_ast/util/parser.rs rename to compiler/rustc_ast/src/util/parser.rs diff --git a/src/librustc_ast/visit.rs b/compiler/rustc_ast/src/visit.rs similarity index 99% rename from src/librustc_ast/visit.rs rename to compiler/rustc_ast/src/visit.rs index b65a88cb90..86fd87f6c4 100644 --- a/src/librustc_ast/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -692,7 +692,7 @@ pub fn walk_stmt<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Stmt) { StmtKind::Expr(ref expr) | StmtKind::Semi(ref expr) => visitor.visit_expr(expr), StmtKind::Empty => {} StmtKind::MacCall(ref mac) => { - let (ref mac, _, ref attrs) = **mac; + let MacCallStmt { ref mac, style: _, ref attrs } = **mac; visitor.visit_mac(mac); for attr in attrs.iter() { visitor.visit_attribute(attr); @@ -879,7 +879,7 @@ pub fn walk_arm<'a, V: Visitor<'a>>(visitor: &mut V, arm: &'a Arm) { } pub fn walk_vis<'a, V: Visitor<'a>>(visitor: &mut V, vis: &'a Visibility) { - if let VisibilityKind::Restricted { ref path, id } = vis.node { + if let VisibilityKind::Restricted { ref path, id } = vis.kind { visitor.visit_path(path, id); } } diff --git a/compiler/rustc_ast_lowering/Cargo.toml b/compiler/rustc_ast_lowering/Cargo.toml new file mode 100644 index 0000000000..177a9066ed --- /dev/null +++ b/compiler/rustc_ast_lowering/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast_lowering" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_span = { path = "../rustc_span" } +rustc_errors = { path = "../rustc_errors" } +rustc_session = { path = "../rustc_session" } +rustc_ast = { path = "../rustc_ast" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_ast_lowering/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs similarity index 99% rename from src/librustc_ast_lowering/expr.rs rename to compiler/rustc_ast_lowering/src/expr.rs index df452825bb..c97f80cf09 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -1121,7 +1121,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // features. We check that at least one type is available for // the current target. let reg_class = reg.reg_class(); - let mut required_features = vec![]; + let mut required_features: Vec<&str> = vec![]; for &(_, feature) in reg_class.supported_types(asm_arch) { if let Some(feature) = feature { if self.sess.target_features.contains(&Symbol::intern(feature)) { @@ -1135,7 +1135,8 @@ impl<'hir> LoweringContext<'_, 'hir> { break; } } - required_features.sort(); + // We are sorting primitive strs here and can use unstable sort here + required_features.sort_unstable(); required_features.dedup(); match &required_features[..] { [] => {} diff --git a/src/librustc_ast_lowering/item.rs b/compiler/rustc_ast_lowering/src/item.rs similarity index 99% rename from src/librustc_ast_lowering/item.rs rename to compiler/rustc_ast_lowering/src/item.rs index f3309afec7..617cacee0e 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/compiler/rustc_ast_lowering/src/item.rs @@ -27,7 +27,7 @@ pub(super) struct ItemLowerer<'a, 'lowering, 'hir> { impl ItemLowerer<'_, '_, '_> { fn with_trait_impl_ref(&mut self, impl_ref: &Option, f: impl FnOnce(&mut Self)) { let old = self.lctx.is_in_trait_impl; - self.lctx.is_in_trait_impl = if let &None = impl_ref { false } else { true }; + self.lctx.is_in_trait_impl = impl_ref.is_some(); f(self); self.lctx.is_in_trait_impl = old; } @@ -251,7 +251,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ItemKind::ExternCrate(orig_name) => hir::ItemKind::ExternCrate(orig_name), ItemKind::Use(ref use_tree) => { // Start with an empty prefix. - let prefix = Path { segments: vec![], span: use_tree.span }; + let prefix = Path { segments: vec![], span: use_tree.span, tokens: None }; self.lower_use_tree(use_tree, &prefix, id, vis, ident, attrs) } @@ -488,7 +488,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *ident = tree.ident(); // First, apply the prefix to the path. - let mut path = Path { segments, span: path.span }; + let mut path = Path { segments, span: path.span, tokens: None }; // Correctly resolve `self` imports. if path.segments.len() > 1 @@ -540,8 +540,11 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ItemKind::Use(path, hir::UseKind::Single) } UseTreeKind::Glob => { - let path = - self.lower_path(id, &Path { segments, span: path.span }, ParamMode::Explicit); + let path = self.lower_path( + id, + &Path { segments, span: path.span, tokens: None }, + ParamMode::Explicit, + ); hir::ItemKind::Use(path, hir::UseKind::Glob) } UseTreeKind::Nested(ref trees) => { @@ -569,7 +572,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // for that we return the `{}` import (called the // `ListStem`). - let prefix = Path { segments, span: prefix.span.to(path.span) }; + let prefix = Path { segments, span: prefix.span.to(path.span), tokens: None }; // Add all the nested `PathListItem`s to the HIR. for &(ref use_tree, id) in trees { @@ -927,7 +930,7 @@ impl<'hir> LoweringContext<'_, 'hir> { v: &Visibility, explicit_owner: Option, ) -> hir::Visibility<'hir> { - let node = match v.node { + let node = match v.kind { VisibilityKind::Public => hir::VisibilityKind::Public, VisibilityKind::Crate(sugar) => hir::VisibilityKind::Crate(sugar), VisibilityKind::Restricted { ref path, id } => { diff --git a/src/librustc_ast_lowering/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs similarity index 99% rename from src/librustc_ast_lowering/lib.rs rename to compiler/rustc_ast_lowering/src/lib.rs index 586355fe61..a28d022c66 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -967,6 +967,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { AttrKind::Normal(ref item) => AttrKind::Normal(AttrItem { path: item.path.clone(), args: self.lower_mac_args(&item.args), + tokens: None, }), AttrKind::DocComment(comment_kind, data) => AttrKind::DocComment(comment_kind, data), }; @@ -1106,6 +1107,7 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { id: node_id, kind: TyKind::ImplTrait(impl_trait_node_id, bounds.clone()), span: constraint.span, + tokens: None, }, itctx, ); diff --git a/src/librustc_ast_lowering/pat.rs b/compiler/rustc_ast_lowering/src/pat.rs similarity index 100% rename from src/librustc_ast_lowering/pat.rs rename to compiler/rustc_ast_lowering/src/pat.rs diff --git a/src/librustc_ast_lowering/path.rs b/compiler/rustc_ast_lowering/src/path.rs similarity index 100% rename from src/librustc_ast_lowering/path.rs rename to compiler/rustc_ast_lowering/src/path.rs diff --git a/compiler/rustc_ast_passes/Cargo.toml b/compiler/rustc_ast_passes/Cargo.toml new file mode 100644 index 0000000000..9ed6bdc3d6 --- /dev/null +++ b/compiler/rustc_ast_passes/Cargo.toml @@ -0,0 +1,18 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast_passes" +version = "0.0.0" +edition = "2018" + +[dependencies] +itertools = "0.9" +tracing = "0.1" +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_parse = { path = "../rustc_parse" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_ast_passes/ast_validation.rs b/compiler/rustc_ast_passes/src/ast_validation.rs similarity index 98% rename from src/librustc_ast_passes/ast_validation.rs rename to compiler/rustc_ast_passes/src/ast_validation.rs index a01dd8c939..232ee35c4f 100644 --- a/src/librustc_ast_passes/ast_validation.rs +++ b/compiler/rustc_ast_passes/src/ast_validation.rs @@ -198,13 +198,13 @@ impl<'a> AstValidator<'a> { } fn invalid_visibility(&self, vis: &Visibility, note: Option<&str>) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } let mut err = struct_span_err!(self.session, vis.span, E0449, "unnecessary visibility qualifier"); - if vis.node.is_pub() { + if vis.kind.is_pub() { err.span_label(vis.span, "`pub` not permitted here because it's implied"); } if let Some(note) = note { @@ -868,10 +868,7 @@ impl<'a> Visitor<'a> for AstValidator<'a> { .emit(); } - if !bounds - .iter() - .any(|b| if let GenericBound::Trait(..) = *b { true } else { false }) - { + if !bounds.iter().any(|b| matches!(b, GenericBound::Trait(..))) { self.err_handler().span_err(ty.span, "at least one trait must be specified"); } @@ -990,12 +987,15 @@ impl<'a> Visitor<'a> for AstValidator<'a> { self.error_item_without_body(item.span, "function", msg, " { }"); } } - ItemKind::ForeignMod(_) => { + ItemKind::ForeignMod(ForeignMod { unsafety, .. }) => { let old_item = mem::replace(&mut self.extern_mod, Some(item)); self.invalid_visibility( &item.vis, Some("place qualifiers on individual foreign items instead"), ); + if let Unsafe::Yes(span) = unsafety { + self.err_handler().span_err(span, "extern block cannot be declared unsafe"); + } visit::walk_item(self, item); self.extern_mod = old_item; return; // Avoid visiting again. @@ -1029,7 +1029,10 @@ impl<'a> Visitor<'a> for AstValidator<'a> { walk_list!(self, visit_attribute, &item.attrs); return; } - ItemKind::Mod(Mod { inline, .. }) => { + ItemKind::Mod(Mod { inline, unsafety, .. }) => { + if let Unsafe::Yes(span) = unsafety { + self.err_handler().span_err(span, "module cannot be declared unsafe"); + } // Ensure that `path` attributes on modules are recorded as used (cf. issue #35584). if !inline && !self.session.contains_name(&item.attrs, sym::path) { self.check_mod_file_item_asciionly(item.ident); diff --git a/src/librustc_ast_passes/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs similarity index 95% rename from src/librustc_ast_passes/feature_gate.rs rename to compiler/rustc_ast_passes/src/feature_gate.rs index 0ee8ef55e6..00d3db7376 100644 --- a/src/librustc_ast_passes/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -260,7 +260,6 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { cfg => doc_cfg masked => doc_masked spotlight => doc_spotlight - alias => doc_alias keyword => doc_keyword ); } @@ -594,7 +593,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { } fn visit_vis(&mut self, vis: &'a ast::Visibility) { - if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.node { + if let ast::VisibilityKind::Crate(ast::CrateSugar::JustCrate) = vis.kind { gate_feature_post!( &self, crate_visibility_modifier, @@ -608,6 +607,7 @@ impl<'a> Visitor<'a> for PostExpansionVisitor<'a> { pub fn check_crate(krate: &ast::Crate, sess: &Session) { maybe_stage_features(sess, krate); + check_incompatible_features(sess); let mut visitor = PostExpansionVisitor { sess, features: &sess.features_untracked() }; let spans = sess.parse_sess.gated_spans.spans.borrow(); @@ -677,3 +677,36 @@ fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { } } } + +fn check_incompatible_features(sess: &Session) { + let features = sess.features_untracked(); + + let declared_features = features + .declared_lang_features + .iter() + .copied() + .map(|(name, span, _)| (name, span)) + .chain(features.declared_lib_features.iter().copied()); + + for (f1, f2) in rustc_feature::INCOMPATIBLE_FEATURES + .iter() + .filter(|&&(f1, f2)| features.enabled(f1) && features.enabled(f2)) + { + if let Some((f1_name, f1_span)) = declared_features.clone().find(|(name, _)| name == f1) { + if let Some((f2_name, f2_span)) = declared_features.clone().find(|(name, _)| name == f2) + { + let spans = vec![f1_span, f2_span]; + sess.struct_span_err( + spans.clone(), + &format!( + "features `{}` and `{}` are incompatible, using them at the same time \ + is not allowed", + f1_name, f2_name + ), + ) + .help("remove one of these features") + .emit(); + } + } + } +} diff --git a/src/librustc_ast_passes/lib.rs b/compiler/rustc_ast_passes/src/lib.rs similarity index 100% rename from src/librustc_ast_passes/lib.rs rename to compiler/rustc_ast_passes/src/lib.rs diff --git a/src/librustc_ast_passes/node_count.rs b/compiler/rustc_ast_passes/src/node_count.rs similarity index 100% rename from src/librustc_ast_passes/node_count.rs rename to compiler/rustc_ast_passes/src/node_count.rs diff --git a/src/librustc_ast_passes/show_span.rs b/compiler/rustc_ast_passes/src/show_span.rs similarity index 100% rename from src/librustc_ast_passes/show_span.rs rename to compiler/rustc_ast_passes/src/show_span.rs diff --git a/compiler/rustc_ast_pretty/Cargo.toml b/compiler/rustc_ast_pretty/Cargo.toml new file mode 100644 index 0000000000..f447bc7f4e --- /dev/null +++ b/compiler/rustc_ast_pretty/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ast_pretty" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +tracing = "0.1" +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } +rustc_target = { path = "../rustc_target" } diff --git a/src/librustc_ast_pretty/helpers.rs b/compiler/rustc_ast_pretty/src/helpers.rs similarity index 100% rename from src/librustc_ast_pretty/helpers.rs rename to compiler/rustc_ast_pretty/src/helpers.rs diff --git a/src/librustc_ast_pretty/lib.rs b/compiler/rustc_ast_pretty/src/lib.rs similarity index 100% rename from src/librustc_ast_pretty/lib.rs rename to compiler/rustc_ast_pretty/src/lib.rs diff --git a/src/librustc_ast_pretty/pp.rs b/compiler/rustc_ast_pretty/src/pp.rs similarity index 100% rename from src/librustc_ast_pretty/pp.rs rename to compiler/rustc_ast_pretty/src/pp.rs diff --git a/src/librustc_ast_pretty/pprust.rs b/compiler/rustc_ast_pretty/src/pprust.rs similarity index 99% rename from src/librustc_ast_pretty/pprust.rs rename to compiler/rustc_ast_pretty/src/pprust.rs index cb48deb588..d16b541c69 100644 --- a/src/librustc_ast_pretty/pprust.rs +++ b/compiler/rustc_ast_pretty/src/pprust.rs @@ -289,10 +289,6 @@ fn token_kind_to_string_ext(tok: &TokenKind, convert_dollar_crate: Option) doc_comment_to_string(comment_kind, attr_style, data) } token::Eof => "".to_string(), - token::Whitespace => " ".to_string(), - token::Comment => "/* */".to_string(), - token::Shebang(s) => format!("/* shebang: {}*/", s), - token::Unknown(s) => s.to_string(), token::Interpolated(ref nt) => nonterminal_to_string(nt), } @@ -1143,7 +1139,11 @@ impl<'a> State<'a> { self.print_fn_full(sig, item.ident, gen, &item.vis, def, body, &item.attrs); } ast::ItemKind::Mod(ref _mod) => { - self.head(visibility_qualified(&item.vis, "mod")); + self.head(to_string(|s| { + s.print_visibility(&item.vis); + s.print_unsafety(_mod.unsafety); + s.word("mod"); + })); self.print_ident(item.ident); if _mod.inline || self.is_expanded { @@ -1158,7 +1158,10 @@ impl<'a> State<'a> { } } ast::ItemKind::ForeignMod(ref nmod) => { - self.head("extern"); + self.head(to_string(|s| { + s.print_unsafety(nmod.unsafety); + s.word("extern"); + })); if let Some(abi) = nmod.abi { self.print_literal(&abi.as_lit()); self.nbsp(); @@ -1356,7 +1359,7 @@ impl<'a> State<'a> { } crate fn print_visibility(&mut self, vis: &ast::Visibility) { - match vis.node { + match vis.kind { ast::VisibilityKind::Public => self.word_nbsp("pub"), ast::VisibilityKind::Crate(sugar) => match sugar { ast::CrateSugar::PubCrate => self.word_nbsp("pub(crate)"), @@ -1507,11 +1510,10 @@ impl<'a> State<'a> { self.s.word(";"); } ast::StmtKind::MacCall(ref mac) => { - let (ref mac, style, ref attrs) = **mac; self.space_if_not_bol(); - self.print_outer_attributes(attrs); - self.print_mac(mac); - if style == ast::MacStmtStyle::Semicolon { + self.print_outer_attributes(&mac.attrs); + self.print_mac(&mac.mac); + if mac.style == ast::MacStmtStyle::Semicolon { self.s.word(";"); } } diff --git a/src/librustc_ast_pretty/pprust/tests.rs b/compiler/rustc_ast_pretty/src/pprust/tests.rs similarity index 89% rename from src/librustc_ast_pretty/pprust/tests.rs rename to compiler/rustc_ast_pretty/src/pprust/tests.rs index fdbf3feb90..b1a73a0bf0 100644 --- a/src/librustc_ast_pretty/pprust/tests.rs +++ b/compiler/rustc_ast_pretty/src/pprust/tests.rs @@ -1,7 +1,6 @@ use super::*; use rustc_ast as ast; -use rustc_span::source_map::respan; use rustc_span::symbol::Ident; use rustc_span::with_default_session_globals; @@ -45,7 +44,11 @@ fn test_variant_to_string() { let var = ast::Variant { ident, - vis: respan(rustc_span::DUMMY_SP, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: rustc_span::DUMMY_SP, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, data: ast::VariantData::Unit(ast::DUMMY_NODE_ID), diff --git a/compiler/rustc_attr/Cargo.toml b/compiler/rustc_attr/Cargo.toml new file mode 100644 index 0000000000..5f941a0a65 --- /dev/null +++ b/compiler/rustc_attr/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_attr" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_errors = { path = "../rustc_errors" } +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_feature = { path = "../rustc_feature" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_macros = { path = "../rustc_macros" } +rustc_session = { path = "../rustc_session" } +rustc_ast = { path = "../rustc_ast" } +version_check = "0.9" diff --git a/src/librustc_attr/builtin.rs b/compiler/rustc_attr/src/builtin.rs similarity index 95% rename from src/librustc_attr/builtin.rs rename to compiler/rustc_attr/src/builtin.rs index b8929fe088..94e2a40e1f 100644 --- a/src/librustc_attr/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -145,8 +145,6 @@ pub struct ConstStability { pub feature: Symbol, /// whether the function has a `#[rustc_promotable]` attribute pub promotable: bool, - /// whether the function has a `#[rustc_allow_const_fn_ptr]` attribute - pub allow_const_fn_ptr: bool, } /// The available stability levels. @@ -160,10 +158,10 @@ pub enum StabilityLevel { impl StabilityLevel { pub fn is_unstable(&self) -> bool { - if let StabilityLevel::Unstable { .. } = *self { true } else { false } + matches!(self, StabilityLevel::Unstable { .. }) } pub fn is_stable(&self) -> bool { - if let StabilityLevel::Stable { .. } = *self { true } else { false } + matches!(self, StabilityLevel::Stable { .. }) } } @@ -190,7 +188,6 @@ where let mut stab: Option = None; let mut const_stab: Option = None; let mut promotable = false; - let mut allow_const_fn_ptr = false; let diagnostic = &sess.parse_sess.span_diagnostic; 'outer: for attr in attrs_iter { @@ -200,7 +197,6 @@ where sym::unstable, sym::stable, sym::rustc_promotable, - sym::rustc_allow_const_fn_ptr, ] .iter() .any(|&s| attr.has_name(s)) @@ -215,9 +211,6 @@ where if attr.has_name(sym::rustc_promotable) { promotable = true; } - if attr.has_name(sym::rustc_allow_const_fn_ptr) { - allow_const_fn_ptr = true; - } // attributes with data else if let Some(MetaItem { kind: MetaItemKind::List(ref metas), .. }) = meta { let meta = meta.as_ref().unwrap(); @@ -301,7 +294,7 @@ where .emit(); }; match issue.parse() { - Ok(num) if num == 0 => { + Ok(0) => { emit_diag( "`issue` must not be \"0\", \ use \"none\" instead", @@ -360,12 +353,8 @@ where if sym::unstable == meta_name { stab = Some(Stability { level, feature }); } else { - const_stab = Some(ConstStability { - level, - feature, - promotable: false, - allow_const_fn_ptr: false, - }); + const_stab = + Some(ConstStability { level, feature, promotable: false }); } } (None, _, _) => { @@ -440,12 +429,8 @@ where if sym::stable == meta_name { stab = Some(Stability { level, feature }); } else { - const_stab = Some(ConstStability { - level, - feature, - promotable: false, - allow_const_fn_ptr: false, - }); + const_stab = + Some(ConstStability { level, feature, promotable: false }); } } (None, _) => { @@ -464,18 +449,16 @@ where } // Merge the const-unstable info into the stability info - if promotable || allow_const_fn_ptr { + if promotable { if let Some(ref mut stab) = const_stab { stab.promotable = promotable; - stab.allow_const_fn_ptr = allow_const_fn_ptr; } else { struct_span_err!( diagnostic, item_sp, E0717, - "rustc_promotable and rustc_allow_const_fn_ptr attributes \ - must be paired with either a rustc_const_unstable or a rustc_const_stable \ - attribute" + "`rustc_promotable` attribute must be paired with either a `rustc_const_unstable` \ + or a `rustc_const_stable` attribute" ) .emit(); } @@ -1022,14 +1005,21 @@ pub fn find_transparency( pub fn allow_internal_unstable<'a>( sess: &'a Session, - attrs: &[Attribute], + attrs: &'a [Attribute], ) -> Option + 'a> { - let attr = sess.find_by_name(attrs, sym::allow_internal_unstable)?; - let list = attr.meta_item_list().or_else(|| { - sess.diagnostic() - .span_err(attr.span, "allow_internal_unstable expects list of feature names"); - None - })?; + let attrs = sess.filter_by_name(attrs, sym::allow_internal_unstable); + let list = attrs + .filter_map(move |attr| { + attr.meta_item_list().or_else(|| { + sess.diagnostic().span_err( + attr.span, + "`allow_internal_unstable` expects a list of feature names", + ); + None + }) + }) + .flatten(); + Some(list.into_iter().filter_map(move |it| { let name = it.ident().map(|ident| ident.name); if name.is_none() { diff --git a/src/librustc_attr/lib.rs b/compiler/rustc_attr/src/lib.rs similarity index 100% rename from src/librustc_attr/lib.rs rename to compiler/rustc_attr/src/lib.rs diff --git a/compiler/rustc_builtin_macros/Cargo.toml b/compiler/rustc_builtin_macros/Cargo.toml new file mode 100644 index 0000000000..c397a85412 --- /dev/null +++ b/compiler/rustc_builtin_macros/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_builtin_macros" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_parse_format = { path = "../rustc_parse_format" } +tracing = "0.1" +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_parse = { path = "../rustc_parse" } +rustc_target = { path = "../rustc_target" } +rustc_session = { path = "../rustc_session" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_expand = { path = "../rustc_expand" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_builtin_macros/asm.rs b/compiler/rustc_builtin_macros/src/asm.rs similarity index 99% rename from src/librustc_builtin_macros/asm.rs rename to compiler/rustc_builtin_macros/src/asm.rs index 5dafd6b77a..09985959b6 100644 --- a/src/librustc_builtin_macros/asm.rs +++ b/compiler/rustc_builtin_macros/src/asm.rs @@ -368,7 +368,7 @@ fn parse_reg<'a>( explicit_reg: &mut bool, ) -> Result> { p.expect(&token::OpenDelim(token::DelimToken::Paren))?; - let result = match p.token.kind { + let result = match p.token.uninterpolate().kind { token::Ident(name, false) => ast::InlineAsmRegOrRegClass::RegClass(name), token::Literal(token::Lit { kind: token::LitKind::Str, symbol, suffix: _ }) => { *explicit_reg = true; diff --git a/src/librustc_builtin_macros/assert.rs b/compiler/rustc_builtin_macros/src/assert.rs similarity index 100% rename from src/librustc_builtin_macros/assert.rs rename to compiler/rustc_builtin_macros/src/assert.rs diff --git a/src/librustc_builtin_macros/cfg.rs b/compiler/rustc_builtin_macros/src/cfg.rs similarity index 100% rename from src/librustc_builtin_macros/cfg.rs rename to compiler/rustc_builtin_macros/src/cfg.rs diff --git a/src/librustc_builtin_macros/cfg_accessible.rs b/compiler/rustc_builtin_macros/src/cfg_accessible.rs similarity index 100% rename from src/librustc_builtin_macros/cfg_accessible.rs rename to compiler/rustc_builtin_macros/src/cfg_accessible.rs diff --git a/src/librustc_builtin_macros/cmdline_attrs.rs b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs similarity index 92% rename from src/librustc_builtin_macros/cmdline_attrs.rs rename to compiler/rustc_builtin_macros/src/cmdline_attrs.rs index 34e2accc61..5ed8b69d92 100644 --- a/src/librustc_builtin_macros/cmdline_attrs.rs +++ b/compiler/rustc_builtin_macros/src/cmdline_attrs.rs @@ -15,7 +15,7 @@ pub fn inject(mut krate: ast::Crate, parse_sess: &ParseSess, attrs: &[String]) - ); let start_span = parser.token.span; - let AttrItem { path, args } = match parser.parse_attr_item() { + let AttrItem { path, args, tokens: _ } = match parser.parse_attr_item() { Ok(ai) => ai, Err(mut err) => { err.emit(); diff --git a/src/librustc_builtin_macros/compile_error.rs b/compiler/rustc_builtin_macros/src/compile_error.rs similarity index 100% rename from src/librustc_builtin_macros/compile_error.rs rename to compiler/rustc_builtin_macros/src/compile_error.rs diff --git a/src/librustc_builtin_macros/concat.rs b/compiler/rustc_builtin_macros/src/concat.rs similarity index 100% rename from src/librustc_builtin_macros/concat.rs rename to compiler/rustc_builtin_macros/src/concat.rs diff --git a/src/librustc_builtin_macros/concat_idents.rs b/compiler/rustc_builtin_macros/src/concat_idents.rs similarity index 84% rename from src/librustc_builtin_macros/concat_idents.rs rename to compiler/rustc_builtin_macros/src/concat_idents.rs index 8223cdda07..209158ce39 100644 --- a/src/librustc_builtin_macros/concat_idents.rs +++ b/compiler/rustc_builtin_macros/src/concat_idents.rs @@ -27,15 +27,15 @@ pub fn expand_concat_idents<'cx>( } } } else { - match e { - TokenTree::Token(Token { kind: token::Ident(name, _), .. }) => { - res_str.push_str(&name.as_str()) - } - _ => { - cx.span_err(sp, "concat_idents! requires ident args."); - return DummyResult::any(sp); + if let TokenTree::Token(token) = e { + if let Some((ident, _)) = token.ident() { + res_str.push_str(&ident.name.as_str()); + continue; } } + + cx.span_err(sp, "concat_idents! requires ident args."); + return DummyResult::any(sp); } } @@ -61,6 +61,7 @@ pub fn expand_concat_idents<'cx>( id: ast::DUMMY_NODE_ID, kind: ast::TyKind::Path(None, ast::Path::from_ident(self.ident)), span: self.ident.span, + tokens: None, })) } } diff --git a/src/librustc_builtin_macros/deriving/bounds.rs b/compiler/rustc_builtin_macros/src/deriving/bounds.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/bounds.rs rename to compiler/rustc_builtin_macros/src/deriving/bounds.rs diff --git a/src/librustc_builtin_macros/deriving/clone.rs b/compiler/rustc_builtin_macros/src/deriving/clone.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/clone.rs rename to compiler/rustc_builtin_macros/src/deriving/clone.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/eq.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/eq.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/ord.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/ord.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_eq.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/partial_eq.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/partial_eq.rs diff --git a/src/librustc_builtin_macros/deriving/cmp/partial_ord.rs b/compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/cmp/partial_ord.rs rename to compiler/rustc_builtin_macros/src/deriving/cmp/partial_ord.rs diff --git a/src/librustc_builtin_macros/deriving/debug.rs b/compiler/rustc_builtin_macros/src/deriving/debug.rs similarity index 99% rename from src/librustc_builtin_macros/deriving/debug.rs rename to compiler/rustc_builtin_macros/src/deriving/debug.rs index 120e859f2b..d84b395647 100644 --- a/src/librustc_builtin_macros/deriving/debug.rs +++ b/compiler/rustc_builtin_macros/src/deriving/debug.rs @@ -133,5 +133,5 @@ fn stmt_let_underscore(cx: &mut ExtCtxt<'_>, sp: Span, expr: P) -> as span: sp, attrs: ast::AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp, tokens: None } } diff --git a/src/librustc_builtin_macros/deriving/decodable.rs b/compiler/rustc_builtin_macros/src/deriving/decodable.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/decodable.rs rename to compiler/rustc_builtin_macros/src/deriving/decodable.rs diff --git a/src/librustc_builtin_macros/deriving/default.rs b/compiler/rustc_builtin_macros/src/deriving/default.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/default.rs rename to compiler/rustc_builtin_macros/src/deriving/default.rs diff --git a/src/librustc_builtin_macros/deriving/encodable.rs b/compiler/rustc_builtin_macros/src/deriving/encodable.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/encodable.rs rename to compiler/rustc_builtin_macros/src/deriving/encodable.rs diff --git a/src/librustc_builtin_macros/deriving/generic/mod.rs b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs similarity index 99% rename from src/librustc_builtin_macros/deriving/generic/mod.rs rename to compiler/rustc_builtin_macros/src/deriving/generic/mod.rs index 849e8b136e..f4924997d1 100644 --- a/src/librustc_builtin_macros/deriving/generic/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/generic/mod.rs @@ -187,7 +187,6 @@ use rustc_ast::{GenericArg, GenericParamKind, VariantData}; use rustc_attr as attr; use rustc_data_structures::map_in_place::MapInPlace; use rustc_expand::base::{Annotatable, ExtCtxt}; -use rustc_span::source_map::respan; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -532,7 +531,11 @@ impl<'a> TraitDef<'a> { id: ast::DUMMY_NODE_ID, span: self.span, ident, - vis: respan(self.span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: self.span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), kind: ast::AssocItemKind::TyAlias( ast::Defaultness::Final, @@ -933,7 +936,11 @@ impl<'a> MethodDef<'a> { id: ast::DUMMY_NODE_ID, attrs: self.attributes.clone(), span: trait_.span, - vis: respan(trait_lo_sp, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: trait_lo_sp, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, ident: method_ident, kind: ast::AssocItemKind::Fn(def, sig, fn_generics, Some(body_block)), tokens: None, @@ -1522,7 +1529,7 @@ impl<'a> TraitDef<'a> { } } - let is_tuple = if let ast::VariantData::Tuple(..) = struct_def { true } else { false }; + let is_tuple = matches!(struct_def, ast::VariantData::Tuple(..)); match (just_spans.is_empty(), named_idents.is_empty()) { (false, false) => cx.span_bug( self.span, diff --git a/src/librustc_builtin_macros/deriving/generic/ty.rs b/compiler/rustc_builtin_macros/src/deriving/generic/ty.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/generic/ty.rs rename to compiler/rustc_builtin_macros/src/deriving/generic/ty.rs diff --git a/src/librustc_builtin_macros/deriving/hash.rs b/compiler/rustc_builtin_macros/src/deriving/hash.rs similarity index 100% rename from src/librustc_builtin_macros/deriving/hash.rs rename to compiler/rustc_builtin_macros/src/deriving/hash.rs diff --git a/src/librustc_builtin_macros/deriving/mod.rs b/compiler/rustc_builtin_macros/src/deriving/mod.rs similarity index 99% rename from src/librustc_builtin_macros/deriving/mod.rs rename to compiler/rustc_builtin_macros/src/deriving/mod.rs index 7e3fd131d4..9c8e0fc2f0 100644 --- a/src/librustc_builtin_macros/deriving/mod.rs +++ b/compiler/rustc_builtin_macros/src/deriving/mod.rs @@ -75,6 +75,7 @@ fn call_intrinsic( id: ast::DUMMY_NODE_ID, rules: ast::BlockCheckMode::Unsafe(ast::CompilerGenerated), span, + tokens: None, })) } diff --git a/src/librustc_builtin_macros/env.rs b/compiler/rustc_builtin_macros/src/env.rs similarity index 100% rename from src/librustc_builtin_macros/env.rs rename to compiler/rustc_builtin_macros/src/env.rs diff --git a/src/librustc_builtin_macros/format.rs b/compiler/rustc_builtin_macros/src/format.rs similarity index 95% rename from src/librustc_builtin_macros/format.rs rename to compiler/rustc_builtin_macros/src/format.rs index 373277f525..550524e652 100644 --- a/src/librustc_builtin_macros/format.rs +++ b/compiler/rustc_builtin_macros/src/format.rs @@ -135,21 +135,52 @@ fn parse_args<'a>( return Err(ecx.struct_span_err(sp, "requires at least a format string argument")); } - let fmtstr = p.parse_expr()?; + let first_token = &p.token; + let fmtstr = match first_token.kind { + token::TokenKind::Literal(token::Lit { + kind: token::LitKind::Str | token::LitKind::StrRaw(_), + .. + }) => { + // If the first token is a string literal, then a format expression + // is constructed from it. + // + // This allows us to properly handle cases when the first comma + // after the format string is mistakenly replaced with any operator, + // which cause the expression parser to eat too much tokens. + p.parse_literal_maybe_minus()? + } + _ => { + // Otherwise, we fall back to the expression parser. + p.parse_expr()? + } + }; + let mut first = true; let mut named = false; while p.token != token::Eof { if !p.eat(&token::Comma) { if first { - // After `format!(""` we always expect *only* a comma... - let mut err = ecx.struct_span_err(p.token.span, "expected token: `,`"); - err.span_label(p.token.span, "expected `,`"); - p.maybe_annotate_with_ascription(&mut err, false); - return Err(err); - } else { - // ...after that delegate to `expect` to also include the other expected tokens. - let _ = p.expect(&token::Comma)?; + 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(); + } + // Otherwise stop the parsing and return the error. + _ => return Err(err), } } first = false; @@ -512,9 +543,12 @@ impl<'a, 'b> Context<'a, 'b> { let idx = self.args.len(); self.arg_types.push(Vec::new()); self.arg_unique_types.push(Vec::new()); - self.args.push( - self.ecx.expr_ident(self.fmtsp, Ident::new(name, self.fmtsp)), - ); + let span = if self.is_literal { + *self.arg_spans.get(self.curpiece).unwrap_or(&self.fmtsp) + } else { + self.fmtsp + }; + self.args.push(self.ecx.expr_ident(span, Ident::new(name, span))); self.names.insert(name, idx); self.verify_arg_type(Exact(idx), ty) } else { diff --git a/src/librustc_builtin_macros/format_foreign.rs b/compiler/rustc_builtin_macros/src/format_foreign.rs similarity index 98% rename from src/librustc_builtin_macros/format_foreign.rs rename to compiler/rustc_builtin_macros/src/format_foreign.rs index 85cf4c42e9..ff81b5eca1 100644 --- a/src/librustc_builtin_macros/format_foreign.rs +++ b/compiler/rustc_builtin_macros/src/format_foreign.rs @@ -166,14 +166,14 @@ pub mod printf { let cap = self.span.len() + if has_options { 2 } else { 0 }; let mut s = String::with_capacity(cap); - s.push_str("{"); + s.push('{'); if let Some(arg) = self.parameter { write!(s, "{}", arg.checked_sub(1)?).ok()?; } if has_options { - s.push_str(":"); + s.push(':'); let align = if let Some(fill) = fill { s.push_str(fill); @@ -191,11 +191,11 @@ pub mod printf { } if alt { - s.push_str("#"); + s.push('#'); } if zero_fill { - s.push_str("0"); + s.push('0'); } if let Some(width) = width { @@ -203,7 +203,7 @@ pub mod printf { } if let Some(precision) = precision { - s.push_str("."); + s.push('.'); precision.translate(&mut s).ok()?; } @@ -212,7 +212,7 @@ pub mod printf { } } - s.push_str("}"); + s.push('}'); Some(s) } } @@ -518,8 +518,7 @@ pub mod printf { .and_then(|end| end.at_next_cp()) .map(|end| (next.slice_between(end).unwrap(), end)); let end = match end { - Some(("32", end)) => end, - Some(("64", end)) => end, + Some(("32" | "64", end)) => end, _ => next, }; state = Type; diff --git a/src/librustc_builtin_macros/format_foreign/printf/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs similarity index 100% rename from src/librustc_builtin_macros/format_foreign/printf/tests.rs rename to compiler/rustc_builtin_macros/src/format_foreign/printf/tests.rs diff --git a/src/librustc_builtin_macros/format_foreign/shell/tests.rs b/compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs similarity index 100% rename from src/librustc_builtin_macros/format_foreign/shell/tests.rs rename to compiler/rustc_builtin_macros/src/format_foreign/shell/tests.rs diff --git a/src/librustc_builtin_macros/global_allocator.rs b/compiler/rustc_builtin_macros/src/global_allocator.rs similarity index 100% rename from src/librustc_builtin_macros/global_allocator.rs rename to compiler/rustc_builtin_macros/src/global_allocator.rs diff --git a/src/librustc_builtin_macros/global_asm.rs b/compiler/rustc_builtin_macros/src/global_asm.rs similarity index 91% rename from src/librustc_builtin_macros/global_asm.rs rename to compiler/rustc_builtin_macros/src/global_asm.rs index 2465f33622..3689e33be6 100644 --- a/src/librustc_builtin_macros/global_asm.rs +++ b/compiler/rustc_builtin_macros/src/global_asm.rs @@ -14,7 +14,6 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_errors::DiagnosticBuilder; use rustc_expand::base::{self, *}; -use rustc_span::source_map::respan; use rustc_span::symbol::Ident; use rustc_span::Span; use smallvec::smallvec; @@ -30,7 +29,11 @@ pub fn expand_global_asm<'cx>( attrs: Vec::new(), id: ast::DUMMY_NODE_ID, kind: ast::ItemKind::GlobalAsm(P(global_asm)), - vis: respan(sp.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: sp.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span: cx.with_def_site_ctxt(sp), tokens: None, })]), diff --git a/src/librustc_builtin_macros/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs similarity index 98% rename from src/librustc_builtin_macros/lib.rs rename to compiler/rustc_builtin_macros/src/lib.rs index 87be6d1743..97cadb913c 100644 --- a/src/librustc_builtin_macros/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -1,7 +1,7 @@ //! This crate contains implementations of built-in macros and other code generating facilities //! injecting code into the crate before it is lowered to HIR. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] diff --git a/src/librustc_builtin_macros/llvm_asm.rs b/compiler/rustc_builtin_macros/src/llvm_asm.rs similarity index 100% rename from src/librustc_builtin_macros/llvm_asm.rs rename to compiler/rustc_builtin_macros/src/llvm_asm.rs diff --git a/src/librustc_builtin_macros/log_syntax.rs b/compiler/rustc_builtin_macros/src/log_syntax.rs similarity index 100% rename from src/librustc_builtin_macros/log_syntax.rs rename to compiler/rustc_builtin_macros/src/log_syntax.rs diff --git a/src/librustc_builtin_macros/proc_macro_harness.rs b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs similarity index 98% rename from src/librustc_builtin_macros/proc_macro_harness.rs rename to compiler/rustc_builtin_macros/src/proc_macro_harness.rs index 0c6769906f..c6ab3faf56 100644 --- a/src/librustc_builtin_macros/proc_macro_harness.rs +++ b/compiler/rustc_builtin_macros/src/proc_macro_harness.rs @@ -98,7 +98,7 @@ pub fn inject( impl<'a> CollectProcMacros<'a> { fn check_not_pub_in_root(&self, vis: &ast::Visibility, sp: Span) { - if self.is_proc_macro_crate && self.in_root && vis.node.is_pub() { + if self.is_proc_macro_crate && self.in_root && vis.kind.is_pub() { self.handler.span_err( sp, "`proc-macro` crate types currently cannot export any items other \ @@ -184,7 +184,7 @@ impl<'a> CollectProcMacros<'a> { Vec::new() }; - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Derive(ProcMacroDerive { id: item.id, span: item.span, @@ -204,7 +204,7 @@ impl<'a> CollectProcMacros<'a> { } fn collect_attr_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { id: item.id, span: item.span, @@ -223,7 +223,7 @@ impl<'a> CollectProcMacros<'a> { } fn collect_bang_proc_macro(&mut self, item: &'a ast::Item) { - if self.in_root && item.vis.node.is_pub() { + if self.in_root && item.vis.kind.is_pub() { self.macros.push(ProcMacro::Def(ProcMacroDef { id: item.id, span: item.span, diff --git a/src/librustc_builtin_macros/source_util.rs b/compiler/rustc_builtin_macros/src/source_util.rs similarity index 100% rename from src/librustc_builtin_macros/source_util.rs rename to compiler/rustc_builtin_macros/src/source_util.rs diff --git a/src/librustc_builtin_macros/standard_library_imports.rs b/compiler/rustc_builtin_macros/src/standard_library_imports.rs similarity index 100% rename from src/librustc_builtin_macros/standard_library_imports.rs rename to compiler/rustc_builtin_macros/src/standard_library_imports.rs diff --git a/src/librustc_builtin_macros/test.rs b/compiler/rustc_builtin_macros/src/test.rs similarity index 98% rename from src/librustc_builtin_macros/test.rs rename to compiler/rustc_builtin_macros/src/test.rs index 8e56e80bba..1de0b32f51 100644 --- a/src/librustc_builtin_macros/test.rs +++ b/compiler/rustc_builtin_macros/src/test.rs @@ -7,7 +7,6 @@ use rustc_ast::attr; use rustc_ast_pretty::pprust; use rustc_expand::base::*; use rustc_session::Session; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::Span; @@ -35,7 +34,11 @@ pub fn expand_test_case( let sp = ecx.with_def_site_ctxt(attr_sp); let mut item = anno_item.expect_item(); item = item.map(|mut item| { - item.vis = respan(item.vis.span, ast::VisibilityKind::Public); + item.vis = ast::Visibility { + span: item.vis.span, + kind: ast::VisibilityKind::Public, + tokens: None, + }; item.ident.span = item.ident.span.with_ctxt(sp.ctxt()); item.attrs.push(ecx.attribute(ecx.meta_word(sp, sym::rustc_test_marker))); item @@ -292,7 +295,7 @@ pub fn expand_test_or_bench( ), ); test_const = test_const.map(|mut tc| { - tc.vis.node = ast::VisibilityKind::Public; + tc.vis.kind = ast::VisibilityKind::Public; tc }); diff --git a/src/librustc_builtin_macros/test_harness.rs b/compiler/rustc_builtin_macros/src/test_harness.rs similarity index 99% rename from src/librustc_builtin_macros/test_harness.rs rename to compiler/rustc_builtin_macros/src/test_harness.rs index 0ea60665d6..0a60ca8faa 100644 --- a/src/librustc_builtin_macros/test_harness.rs +++ b/compiler/rustc_builtin_macros/src/test_harness.rs @@ -10,7 +10,6 @@ use rustc_expand::expand::{AstFragment, ExpansionConfig}; use rustc_feature::Features; use rustc_session::Session; use rustc_span::hygiene::{AstPass, SyntaxContext, Transparency}; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::PanicStrategy; @@ -333,7 +332,7 @@ fn mk_main(cx: &mut TestCtxt<'_>) -> P { attrs: vec![main_attr], id: ast::DUMMY_NODE_ID, kind: main, - vis: respan(sp, ast::VisibilityKind::Public), + vis: ast::Visibility { span: sp, kind: ast::VisibilityKind::Public, tokens: None }, span: sp, tokens: None, }); diff --git a/src/librustc_builtin_macros/trace_macros.rs b/compiler/rustc_builtin_macros/src/trace_macros.rs similarity index 100% rename from src/librustc_builtin_macros/trace_macros.rs rename to compiler/rustc_builtin_macros/src/trace_macros.rs diff --git a/src/librustc_builtin_macros/util.rs b/compiler/rustc_builtin_macros/src/util.rs similarity index 100% rename from src/librustc_builtin_macros/util.rs rename to compiler/rustc_builtin_macros/src/util.rs diff --git a/compiler/rustc_codegen_llvm/Cargo.toml b/compiler/rustc_codegen_llvm/Cargo.toml new file mode 100644 index 0000000000..04792b334d --- /dev/null +++ b/compiler/rustc_codegen_llvm/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_llvm" +version = "0.0.0" +edition = "2018" + +[lib] +test = false +doctest = false + +[dependencies] +bitflags = "1.0" +libc = "0.2" +measureme = "0.7.1" +snap = "1" +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc-demangle = "0.1" +rustc_attr = { path = "../rustc_attr" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_fs_util = { path = "../rustc_fs_util" } +rustc_hir = { path = "../rustc_hir" } +rustc_incremental = { path = "../rustc_incremental" } +rustc_index = { path = "../rustc_index" } +rustc_llvm = { path = "../rustc_llvm" } +rustc_session = { path = "../rustc_session" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_codegen_llvm/README.md b/compiler/rustc_codegen_llvm/README.md similarity index 100% rename from src/librustc_codegen_llvm/README.md rename to compiler/rustc_codegen_llvm/README.md diff --git a/src/librustc_codegen_llvm/abi.rs b/compiler/rustc_codegen_llvm/src/abi.rs similarity index 100% rename from src/librustc_codegen_llvm/abi.rs rename to compiler/rustc_codegen_llvm/src/abi.rs diff --git a/src/librustc_codegen_llvm/allocator.rs b/compiler/rustc_codegen_llvm/src/allocator.rs similarity index 100% rename from src/librustc_codegen_llvm/allocator.rs rename to compiler/rustc_codegen_llvm/src/allocator.rs diff --git a/src/librustc_codegen_llvm/asm.rs b/compiler/rustc_codegen_llvm/src/asm.rs similarity index 95% rename from src/librustc_codegen_llvm/asm.rs rename to compiler/rustc_codegen_llvm/src/asm.rs index 4fef94dde5..f801f845ac 100644 --- a/src/librustc_codegen_llvm/asm.rs +++ b/compiler/rustc_codegen_llvm/src/asm.rs @@ -259,6 +259,7 @@ impl AsmBuilderMethods<'tcx> for Builder<'a, 'll, 'tcx> { InlineAsmArch::RiscV32 | InlineAsmArch::RiscV64 => {} InlineAsmArch::Nvptx64 => {} InlineAsmArch::Hexagon => {} + InlineAsmArch::Mips => {} } } if !options.contains(InlineAsmOptions::NOMEM) { @@ -485,7 +486,7 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) format!("{{{}{}}}", class, idx) } else if reg == InlineAsmReg::AArch64(AArch64InlineAsmReg::x30) { // LLVM doesn't recognize x30 - "lr".to_string() + "{lr}".to_string() } else { format!("{{{}}}", reg.name()) } @@ -505,6 +506,8 @@ fn reg_to_llvm(reg: InlineAsmRegOrRegClass, layout: Option<&TyAndLayout<'tcx>>) InlineAsmRegClass::Arm(ArmInlineAsmRegClass::dreg) | InlineAsmRegClass::Arm(ArmInlineAsmRegClass::qreg) => "w", InlineAsmRegClass::Hexagon(HexagonInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg) => "r", + InlineAsmRegClass::Mips(MipsInlineAsmRegClass::freg) => "f", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg16) => "h", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg32) => "r", InlineAsmRegClass::Nvptx(NvptxInlineAsmRegClass::reg64) => "l", @@ -551,6 +554,7 @@ fn modifier_to_llvm( } } InlineAsmRegClass::Hexagon(_) => None, + InlineAsmRegClass::Mips(_) => None, InlineAsmRegClass::Nvptx(_) => None, InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::reg) | InlineAsmRegClass::RiscV(RiscVInlineAsmRegClass::freg) => None, @@ -603,6 +607,8 @@ fn dummy_output_type(cx: &CodegenCx<'ll, 'tcx>, reg: InlineAsmRegClass) -> &'ll cx.type_vector(cx.type_i64(), 2) } 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(), @@ -700,6 +706,12 @@ fn llvm_fixup_input( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => bx.zext(value, bx.cx.type_i32()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_i32()), + _ => value, + }, _ => value, } } @@ -768,6 +780,13 @@ fn llvm_fixup_output( value } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8, _) => bx.trunc(value, bx.cx.type_i8()), + Primitive::Int(Integer::I16, _) => bx.trunc(value, bx.cx.type_i16()), + Primitive::F32 => bx.bitcast(value, bx.cx.type_f32()), + _ => value, + }, _ => value, } } @@ -831,6 +850,12 @@ fn llvm_fixup_output_type( layout.llvm_type(cx) } } + (InlineAsmRegClass::Mips(MipsInlineAsmRegClass::reg), Abi::Scalar(s)) => match s.value { + // MIPS only supports register-length arithmetics. + Primitive::Int(Integer::I8 | Integer::I16, _) => cx.type_i32(), + Primitive::F32 => cx.type_i32(), + _ => layout.llvm_type(cx), + }, _ => layout.llvm_type(cx), } } diff --git a/src/librustc_codegen_llvm/attributes.rs b/compiler/rustc_codegen_llvm/src/attributes.rs similarity index 98% rename from src/librustc_codegen_llvm/attributes.rs rename to compiler/rustc_codegen_llvm/src/attributes.rs index 227a87ff81..73c3481844 100644 --- a/src/librustc_codegen_llvm/attributes.rs +++ b/compiler/rustc_codegen_llvm/src/attributes.rs @@ -294,6 +294,9 @@ pub fn from_fn_attrs(cx: &CodegenCx<'ll, 'tcx>, llfn: &'ll Value, instance: ty:: if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::ALLOCATOR) { Attribute::NoAlias.apply_llfn(llvm::AttributePlace::ReturnValue, llfn); } + if codegen_fn_attrs.flags.contains(CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY) { + llvm::AddFunctionAttrString(llfn, Function, const_cstr!("cmse_nonsecure_entry")); + } sanitize(cx, codegen_fn_attrs.no_sanitize, llfn); // Always annotate functions with the target-cpu they are compiled for. diff --git a/src/librustc_codegen_llvm/back/archive.rs b/compiler/rustc_codegen_llvm/src/back/archive.rs similarity index 100% rename from src/librustc_codegen_llvm/back/archive.rs rename to compiler/rustc_codegen_llvm/src/back/archive.rs diff --git a/src/librustc_codegen_llvm/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs similarity index 99% rename from src/librustc_codegen_llvm/back/lto.rs rename to compiler/rustc_codegen_llvm/src/back/lto.rs index 7c710a1cb3..4b2d5907a0 100644 --- a/src/librustc_codegen_llvm/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -346,14 +346,14 @@ fn fat_lto( Ok(LtoModuleCodegen::Fat { module: Some(module), _serialized_bitcode: serialized_bitcode }) } -struct Linker<'a>(&'a mut llvm::Linker<'a>); +crate struct Linker<'a>(&'a mut llvm::Linker<'a>); impl Linker<'a> { - fn new(llmod: &'a llvm::Module) -> Self { + crate fn new(llmod: &'a llvm::Module) -> Self { unsafe { Linker(llvm::LLVMRustLinkerNew(llmod)) } } - fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { + crate fn add(&mut self, bytecode: &[u8]) -> Result<(), ()> { unsafe { if llvm::LLVMRustLinkerAdd( self.0, diff --git a/src/librustc_codegen_llvm/back/profiling.rs b/compiler/rustc_codegen_llvm/src/back/profiling.rs similarity index 100% rename from src/librustc_codegen_llvm/back/profiling.rs rename to compiler/rustc_codegen_llvm/src/back/profiling.rs diff --git a/src/librustc_codegen_llvm/back/write.rs b/compiler/rustc_codegen_llvm/src/back/write.rs similarity index 96% rename from src/librustc_codegen_llvm/back/write.rs rename to compiler/rustc_codegen_llvm/src/back/write.rs index 6f386c1287..f35c1016f8 100644 --- a/src/librustc_codegen_llvm/back/write.rs +++ b/compiler/rustc_codegen_llvm/src/back/write.rs @@ -344,6 +344,13 @@ unsafe extern "C" fn diagnostic_handler(info: &DiagnosticInfo, user: *mut c_void .expect("non-UTF8 diagnostic"); diag_handler.warn(&msg); } + llvm::diagnostic::Unsupported(diagnostic_ref) => { + let msg = llvm::build_string(|s| { + llvm::LLVMRustWriteDiagnosticInfoToString(diagnostic_ref, s) + }) + .expect("non-UTF8 diagnostic"); + diag_handler.err(&msg); + } llvm::diagnostic::UnknownDiagnostic(..) => {} } } @@ -617,6 +624,31 @@ unsafe fn add_sanitizer_passes(config: &ModuleConfig, passes: &mut Vec<&'static } } +pub(crate) fn link( + cgcx: &CodegenContext, + diag_handler: &Handler, + mut modules: Vec>, +) -> Result, FatalError> { + use super::lto::{Linker, ModuleBuffer}; + // Sort the modules by name to ensure to ensure deterministic behavior. + modules.sort_by(|a, b| a.name.cmp(&b.name)); + let (first, elements) = + modules.split_first().expect("Bug! modules must contain at least one module."); + + let mut linker = Linker::new(first.module_llvm.llmod()); + for module in elements { + 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(|()| { + let msg = format!("failed to serialize module {:?}", module.name); + llvm_err(&diag_handler, &msg) + })?; + } + drop(linker); + Ok(modules.remove(0)) +} + pub(crate) unsafe fn codegen( cgcx: &CodegenContext, diag_handler: &Handler, diff --git a/src/librustc_codegen_llvm/base.rs b/compiler/rustc_codegen_llvm/src/base.rs similarity index 96% rename from src/librustc_codegen_llvm/base.rs rename to compiler/rustc_codegen_llvm/src/base.rs index b19199b9cf..f35708b1d0 100644 --- a/src/librustc_codegen_llvm/base.rs +++ b/compiler/rustc_codegen_llvm/src/base.rs @@ -45,15 +45,12 @@ pub fn write_compressed_metadata<'tcx>( metadata: &EncodedMetadata, llvm_module: &mut ModuleLlvm, ) { - use flate2::write::DeflateEncoder; - use flate2::Compression; + use snap::write::FrameEncoder; use std::io::Write; let (metadata_llcx, metadata_llmod) = (&*llvm_module.llcx, llvm_module.llmod()); let mut compressed = tcx.metadata_encoding_version(); - DeflateEncoder::new(&mut compressed, Compression::fast()) - .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); @@ -111,7 +108,7 @@ pub fn compile_codegen_unit( // We assume that the cost to run LLVM 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; + let cost = time_to_codegen.as_nanos() as u64; fn module_codegen(tcx: TyCtxt<'_>, cgu_name: Symbol) -> ModuleCodegen { let cgu = tcx.codegen_unit(cgu_name); diff --git a/src/librustc_codegen_llvm/builder.rs b/compiler/rustc_codegen_llvm/src/builder.rs similarity index 98% rename from src/librustc_codegen_llvm/builder.rs rename to compiler/rustc_codegen_llvm/src/builder.rs index 4ece08f629..0c172dc33b 100644 --- a/src/librustc_codegen_llvm/builder.rs +++ b/compiler/rustc_codegen_llvm/src/builder.rs @@ -6,7 +6,6 @@ use crate::type_::Type; use crate::type_of::LayoutLlvmExt; use crate::value::Value; use libc::{c_char, c_uint}; -use rustc_codegen_ssa::base::to_immediate; use rustc_codegen_ssa::common::{IntPredicate, RealPredicate, TypeKind}; use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; use rustc_codegen_ssa::mir::place::PlaceRef; @@ -22,7 +21,6 @@ use rustc_target::abi::{self, Align, Size}; use rustc_target::spec::{HasTargetSpec, Target}; use std::borrow::Cow; use std::ffi::CStr; -use std::iter::TrustedLen; use std::ops::{Deref, Range}; use std::ptr; use tracing::debug; @@ -180,7 +178,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { &mut self, v: &'ll Value, else_llbb: &'ll BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ) { let switch = unsafe { llvm::LLVMBuildSwitch(self.llbuilder, v, else_llbb, cases.len() as c_uint) }; @@ -307,10 +305,10 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { use rustc_ast::UintTy::*; use rustc_middle::ty::{Int, Uint}; - let new_kind = match ty.kind { + let new_kind = match ty.kind() { Int(t @ Isize) => Int(t.normalize(self.tcx.sess.target.ptr_width)), Uint(t @ Usize) => Uint(t.normalize(self.tcx.sess.target.ptr_width)), - ref t @ (Uint(_) | Int(_)) => t.clone(), + t @ (Uint(_) | Int(_)) => t.clone(), _ => panic!("tried to get overflow intrinsic for op applied to non-int type"), }; @@ -367,6 +365,20 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { (self.extract_value(res, 0), self.extract_value(res, 1)) } + 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 alloca(&mut self, ty: &'ll Type, align: Align) -> &'ll Value { let mut bx = Builder::with_cx(self.cx); bx.position_at_start(unsafe { llvm::LLVMGetFirstBasicBlock(self.llfn()) }); @@ -471,7 +483,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { } load }); - OperandValue::Immediate(to_immediate(self, llval, place.layout)) + OperandValue::Immediate(self.to_immediate(llval, 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); @@ -479,7 +491,7 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { let llptr = self.struct_gep(place.llval, i as u64); let load = self.load(llptr, align); scalar_load_metadata(self, load, scalar); - if scalar.is_bool() { self.trunc(load, self.type_i1()) } else { load } + self.to_immediate_scalar(load, scalar) }; OperandValue::Pair( @@ -918,7 +930,6 @@ impl BuilderMethods<'a, 'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMBuildSelect(self.llbuilder, cond, then_val, else_val, UNNAMED) } } - #[allow(dead_code)] fn va_arg(&mut self, list: &'ll Value, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMBuildVAArg(self.llbuilder, list, ty, UNNAMED) } } diff --git a/src/librustc_codegen_llvm/callee.rs b/compiler/rustc_codegen_llvm/src/callee.rs similarity index 100% rename from src/librustc_codegen_llvm/callee.rs rename to compiler/rustc_codegen_llvm/src/callee.rs diff --git a/src/librustc_codegen_llvm/common.rs b/compiler/rustc_codegen_llvm/src/common.rs similarity index 99% rename from src/librustc_codegen_llvm/common.rs rename to compiler/rustc_codegen_llvm/src/common.rs index 0b1cf03fa7..0992410a72 100644 --- a/src/librustc_codegen_llvm/common.rs +++ b/compiler/rustc_codegen_llvm/src/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types, non_snake_case)] - //! Code that is useful in various codegen modules. use crate::consts::{self, const_alloc_to_llvm}; diff --git a/src/librustc_codegen_llvm/consts.rs b/compiler/rustc_codegen_llvm/src/consts.rs similarity index 97% rename from src/librustc_codegen_llvm/consts.rs rename to compiler/rustc_codegen_llvm/src/consts.rs index 86a5ec5925..6d3582d302 100644 --- a/src/librustc_codegen_llvm/consts.rs +++ b/compiler/rustc_codegen_llvm/src/consts.rs @@ -7,12 +7,13 @@ use crate::type_of::LayoutLlvmExt; use crate::value::Value; use libc::c_uint; use rustc_codegen_ssa::traits::*; +use rustc_data_structures::const_cstr; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::Node; use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::interpret::{ - read_target_uint, Allocation, ConstValue, ErrorHandled, GlobalAlloc, Pointer, + read_target_uint, Allocation, ErrorHandled, GlobalAlloc, Pointer, }; use rustc_middle::mir::mono::MonoItem; use rustc_middle::ty::{self, Instance, Ty}; @@ -22,8 +23,6 @@ use rustc_span::Span; use rustc_target::abi::{AddressSpace, Align, HasDataLayout, LayoutOf, Primitive, Scalar, Size}; use tracing::debug; -use std::ffi::CStr; - pub fn const_alloc_to_llvm(cx: &CodegenCx<'ll, '_>, alloc: &Allocation) -> &'ll Value { let mut llvals = Vec::with_capacity(alloc.relocations().len() + 1); let dl = cx.data_layout(); @@ -85,10 +84,7 @@ pub fn codegen_static_initializer( cx: &CodegenCx<'ll, 'tcx>, def_id: DefId, ) -> Result<(&'ll Value, &'tcx Allocation), ErrorHandled> { - let alloc = match cx.tcx.const_eval_poly(def_id)? { - ConstValue::ByRef { alloc, offset } if offset.bytes() == 0 => alloc, - val => bug!("static const eval returned {:#?}", val), - }; + let alloc = cx.tcx.eval_static_initializer(def_id)?; Ok((const_alloc_to_llvm(cx, alloc), alloc)) } @@ -125,7 +121,7 @@ fn check_and_apply_linkage( // 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 { + let llty2 = if let ty::RawPtr(ref mt) = ty.kind() { cx.layout_of(mt.ty).llvm_type(cx) } else { cx.sess().span_fatal( @@ -457,9 +453,9 @@ impl StaticMethods for CodegenCx<'ll, 'tcx> { .all(|&byte| byte == 0); let sect_name = if all_bytes_are_zero { - CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_bss\0") + const_cstr!("__DATA,__thread_bss") } else { - CStr::from_bytes_with_nul_unchecked(b"__DATA,__thread_data\0") + const_cstr!("__DATA,__thread_data") }; llvm::LLVMSetSection(g, sect_name.as_ptr()); } diff --git a/src/librustc_codegen_llvm/context.rs b/compiler/rustc_codegen_llvm/src/context.rs similarity index 96% rename from src/librustc_codegen_llvm/context.rs rename to compiler/rustc_codegen_llvm/src/context.rs index 26707fdf83..1696f35563 100644 --- a/src/librustc_codegen_llvm/context.rs +++ b/compiler/rustc_codegen_llvm/src/context.rs @@ -82,6 +82,7 @@ pub struct CodegenCx<'ll, 'tcx> { pub dbg_cx: Option>, eh_personality: Cell>, + eh_catch_typeinfo: Cell>, pub rust_try_fn: Cell>, intrinsics: RefCell>, @@ -311,6 +312,7 @@ impl<'ll, 'tcx> CodegenCx<'ll, 'tcx> { coverage_cx, dbg_cx, eh_personality: Cell::new(None), + eh_catch_typeinfo: Cell::new(None), rust_try_fn: Cell::new(None), intrinsics: Default::default(), local_gen_sym_counter: Cell::new(0), @@ -431,6 +433,17 @@ impl MiscMethods<'tcx> for CodegenCx<'ll, 'tcx> { llvm::LLVMSetSection(g, section.as_ptr()); } } + + 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 + } + } } impl CodegenCx<'b, 'tcx> { @@ -819,6 +832,25 @@ impl CodegenCx<'b, 'tcx> { } None } + + crate fn eh_catch_typeinfo(&self) -> &'b Value { + if let Some(eh_catch_typeinfo) = self.eh_catch_typeinfo.get() { + return eh_catch_typeinfo; + } + let tcx = self.tcx; + assert!(self.sess().target.target.options.is_like_emscripten); + let eh_catch_typeinfo = match tcx.lang_items().eh_catch_typeinfo() { + Some(def_id) => self.get_static(def_id), + _ => { + let ty = self + .type_struct(&[self.type_ptr_to(self.type_isize()), self.type_i8p()], false); + self.declare_global("rust_eh_catch_typeinfo", ty) + } + }; + let eh_catch_typeinfo = self.const_bitcast(eh_catch_typeinfo, self.type_i8p()); + self.eh_catch_typeinfo.set(Some(eh_catch_typeinfo)); + eh_catch_typeinfo + } } impl<'b, 'tcx> CodegenCx<'b, 'tcx> { diff --git a/src/librustc_codegen_llvm/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs similarity index 100% rename from src/librustc_codegen_llvm/coverageinfo/mapgen.rs rename to compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs diff --git a/src/librustc_codegen_llvm/coverageinfo/mod.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs similarity index 100% rename from src/librustc_codegen_llvm/coverageinfo/mod.rs rename to compiler/rustc_codegen_llvm/src/coverageinfo/mod.rs diff --git a/src/librustc_codegen_llvm/debuginfo/create_scope_map.rs b/compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/create_scope_map.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/create_scope_map.rs diff --git a/src/librustc_codegen_llvm/debuginfo/doc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/doc.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/doc.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/doc.rs diff --git a/src/librustc_codegen_llvm/debuginfo/gdb.rs b/compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/gdb.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/gdb.rs diff --git a/src/librustc_codegen_llvm/debuginfo/metadata.rs b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs similarity index 98% rename from src/librustc_codegen_llvm/debuginfo/metadata.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs index 9d92d53775..987149cb4c 100644 --- a/src/librustc_codegen_llvm/debuginfo/metadata.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/metadata.rs @@ -343,7 +343,7 @@ fn fixed_vec_metadata( let (size, align) = cx.size_and_align_of(array_or_slice_type); - let upper_bound = match array_or_slice_type.kind { + let upper_bound = match array_or_slice_type.kind() { ty::Array(_, len) => len.eval_usize(cx.tcx, ty::ParamEnv::reveal_all()) as c_longlong, _ => -1, }; @@ -432,7 +432,7 @@ fn subroutine_type_metadata( let signature_metadata: Vec<_> = iter::once( // return type - match signature.output().kind { + match signature.output().kind() { ty::Tuple(ref tys) if tys.is_empty() => None, _ => Some(type_metadata(cx, signature.output(), span)), }, @@ -472,7 +472,7 @@ fn trait_pointer_metadata( // type is assigned the correct name, size, namespace, and source location. // However, it does not describe the trait's methods. - let containing_scope = match trait_type.kind { + let containing_scope = match trait_type.kind() { ty::Dynamic(ref data, ..) => { data.principal_def_id().map(|did| get_namespace_for_item(cx, did)) } @@ -572,7 +572,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp debug!("type_metadata: {:?}", t); - let ptr_metadata = |ty: Ty<'tcx>| match ty.kind { + let ptr_metadata = |ty: Ty<'tcx>| match *ty.kind() { ty::Slice(typ) => Ok(vec_slice_metadata(cx, t, typ, unique_type_id, usage_site_span)), ty::Str => Ok(vec_slice_metadata(cx, t, cx.tcx.types.u8, unique_type_id, usage_site_span)), ty::Dynamic(..) => Ok(MetadataCreationResult::new( @@ -592,7 +592,7 @@ pub fn type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>, usage_site_span: Sp } }; - let MetadataCreationResult { metadata, already_stored_in_typemap } = match t.kind { + let MetadataCreationResult { metadata, already_stored_in_typemap } = match *t.kind() { ty::Never | ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) => { MetadataCreationResult::new(basic_type_metadata(cx, t), false) } @@ -876,7 +876,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { // .natvis visualizers (and perhaps other existing native debuggers?) let msvc_like_names = cx.tcx.sess.target.target.options.is_like_msvc; - let (name, encoding) = match t.kind { + let (name, encoding) = match t.kind() { ty::Never => ("!", DW_ATE_unsigned), ty::Tuple(ref elements) if elements.is_empty() => ("()", DW_ATE_unsigned), ty::Bool => ("bool", DW_ATE_boolean), @@ -904,7 +904,7 @@ fn basic_type_metadata(cx: &CodegenCx<'ll, 'tcx>, t: Ty<'tcx>) -> &'ll DIType { return ty_metadata; } - let typedef_name = match t.kind { + let typedef_name = match t.kind() { ty::Int(int_ty) => int_ty.name_str(), ty::Uint(uint_ty) => uint_ty.name_str(), ty::Float(float_ty) => float_ty.name_str(), @@ -1239,7 +1239,7 @@ fn prepare_struct_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let struct_name = compute_debuginfo_type_name(cx.tcx, struct_type, false); - let (struct_def_id, variant) = match struct_type.kind { + let (struct_def_id, variant) = match struct_type.kind() { ty::Adt(def, _) => (def.did, def.non_enum_variant()), _ => bug!("prepare_struct_metadata on a non-ADT"), }; @@ -1373,7 +1373,7 @@ fn prepare_union_metadata( ) -> RecursiveTypeDescription<'ll, 'tcx> { let union_name = compute_debuginfo_type_name(cx.tcx, union_type, false); - let (union_def_id, variant) = match union_type.kind { + let (union_def_id, variant) = match union_type.kind() { ty::Adt(def, _) => (def.did, def.non_enum_variant()), _ => bug!("prepare_union_metadata on a non-ADT"), }; @@ -1457,14 +1457,14 @@ struct EnumMemberDescriptionFactory<'ll, 'tcx> { impl EnumMemberDescriptionFactory<'ll, 'tcx> { fn create_member_descriptions(&self, cx: &CodegenCx<'ll, 'tcx>) -> Vec> { - let generator_variant_info_data = match self.enum_type.kind { + let generator_variant_info_data = match *self.enum_type.kind() { ty::Generator(def_id, ..) => { Some(generator_layout_and_saved_local_names(cx.tcx, def_id)) } _ => None, }; - let variant_info_for = |index: VariantIdx| match self.enum_type.kind { + let variant_info_for = |index: VariantIdx| match *self.enum_type.kind() { ty::Adt(adt, _) => VariantInfo::Adt(&adt.variants[index]), ty::Generator(def_id, _, _) => { let (generator_layout, generator_saved_local_names) = @@ -1486,14 +1486,14 @@ impl EnumMemberDescriptionFactory<'ll, 'tcx> { } else { type_metadata(cx, self.enum_type, self.span) }; - let flags = match self.enum_type.kind { + let flags = match self.enum_type.kind() { ty::Generator(..) => DIFlags::FlagArtificial, _ => DIFlags::FlagZero, }; match self.layout.variants { Variants::Single { index } => { - if let ty::Adt(adt, _) = &self.enum_type.kind { + if let ty::Adt(adt, _) = self.enum_type.kind() { if adt.variants.is_empty() { return vec![]; } @@ -1845,7 +1845,6 @@ impl<'tcx> VariantInfo<'_, 'tcx> { None } - #[allow(dead_code)] fn is_artificial(&self) -> bool { match self { VariantInfo::Generator { .. } => true, @@ -1942,7 +1941,7 @@ fn prepare_enum_metadata( let tcx = cx.tcx; let enum_name = compute_debuginfo_type_name(tcx, enum_type, false); // FIXME(tmandry): This doesn't seem to have any effect. - let enum_flags = match enum_type.kind { + let enum_flags = match enum_type.kind() { ty::Generator(..) => DIFlags::FlagArtificial, _ => DIFlags::FlagZero, }; @@ -1957,13 +1956,13 @@ fn prepare_enum_metadata( let file_metadata = unknown_file_metadata(cx); let discriminant_type_metadata = |discr: Primitive| { - let enumerators_metadata: Vec<_> = match enum_type.kind { + let enumerators_metadata: Vec<_> = match enum_type.kind() { ty::Adt(def, _) => def .discriminants(tcx) .zip(&def.variants) .map(|((_, discr), v)| { let name = v.ident.as_str(); - let is_unsigned = match discr.ty.kind { + let is_unsigned = match discr.ty.kind() { ty::Int(_) => false, ty::Uint(_) => true, _ => bug!("non integer discriminant"), @@ -2012,7 +2011,7 @@ fn prepare_enum_metadata( type_metadata(cx, discr.to_ty(tcx), rustc_span::DUMMY_SP); let item_name; - let discriminant_name = match enum_type.kind { + let discriminant_name = match enum_type.kind() { ty::Adt(..) => { item_name = tcx.item_name(enum_def_id).as_str(); &*item_name @@ -2105,7 +2104,7 @@ fn prepare_enum_metadata( ); } - let discriminator_name = match &enum_type.kind { + let discriminator_name = match enum_type.kind() { ty::Generator(..) => "__state", _ => "", }; @@ -2328,7 +2327,7 @@ fn set_members_of_composite_type( /// Computes the type parameters for a type, if any, for the given metadata. fn compute_type_parameters(cx: &CodegenCx<'ll, 'tcx>, ty: Ty<'tcx>) -> Option<&'ll DIArray> { - if let ty::Adt(def, substs) = ty.kind { + if let ty::Adt(def, substs) = *ty.kind() { if substs.types().next().is_some() { let generics = cx.tcx.generics_of(def.did); let names = get_parameter_names(cx, generics); diff --git a/src/librustc_codegen_llvm/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs similarity index 99% rename from src/librustc_codegen_llvm/debuginfo/mod.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index b414426af8..7cdd366175 100644 --- a/src/librustc_codegen_llvm/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -361,9 +361,9 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // already inaccurate due to ABI adjustments (see #42800). signature.extend(fn_abi.args.iter().map(|arg| { let t = arg.layout.ty; - let t = match t.kind { + let t = match t.kind() { ty::Array(ct, _) - if (ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => + if (*ct == cx.tcx.types.u8) || cx.layout_of(ct).is_zst() => { cx.tcx.mk_imm_ptr(ct) } @@ -467,7 +467,7 @@ impl DebugInfoMethods<'tcx> for CodegenCx<'ll, 'tcx> { // Only "class" methods are generally understood by LLVM, // so avoid methods on other types (e.g., `<*mut T>::null`). - match impl_self_ty.kind { + match impl_self_ty.kind() { ty::Adt(def, ..) if !def.is_box() => { // Again, only create type information if full debuginfo is enabled if cx.sess().opts.debuginfo == DebugInfo::Full diff --git a/src/librustc_codegen_llvm/debuginfo/namespace.rs b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs similarity index 80% rename from src/librustc_codegen_llvm/debuginfo/namespace.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs index d1a55335c4..9945d4f428 100644 --- a/src/librustc_codegen_llvm/debuginfo/namespace.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/namespace.rs @@ -27,11 +27,18 @@ pub fn item_namespace(cx: &CodegenCx<'ll, '_>, def_id: DefId) -> &'ll DIScope { .parent .map(|parent| item_namespace(cx, DefId { krate: def_id.krate, index: parent })); + let crate_name_as_str; + let name_to_string; let namespace_name = match def_key.disambiguated_data.data { - DefPathData::CrateRoot => cx.tcx.crate_name(def_id.krate), - data => data.as_symbol(), + DefPathData::CrateRoot => { + crate_name_as_str = cx.tcx.crate_name(def_id.krate).as_str(); + &*crate_name_as_str + } + data => { + name_to_string = data.to_string(); + &*name_to_string + } }; - let namespace_name = namespace_name.as_str(); let scope = unsafe { llvm::LLVMRustDIBuilderCreateNameSpace( diff --git a/src/librustc_codegen_llvm/debuginfo/source_loc.rs b/compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/source_loc.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/source_loc.rs diff --git a/src/librustc_codegen_llvm/debuginfo/utils.rs b/compiler/rustc_codegen_llvm/src/debuginfo/utils.rs similarity index 100% rename from src/librustc_codegen_llvm/debuginfo/utils.rs rename to compiler/rustc_codegen_llvm/src/debuginfo/utils.rs diff --git a/src/librustc_codegen_llvm/declare.rs b/compiler/rustc_codegen_llvm/src/declare.rs similarity index 59% rename from src/librustc_codegen_llvm/declare.rs rename to compiler/rustc_codegen_llvm/src/declare.rs index ec42bd4a03..a3d6882940 100644 --- a/src/librustc_codegen_llvm/declare.rs +++ b/compiler/rustc_codegen_llvm/src/declare.rs @@ -51,17 +51,32 @@ fn declare_raw_fn( llfn } -impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { - fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { +impl CodegenCx<'ll, 'tcx> { + /// Declare a global value. + /// + /// If there’s a value with the same name already declared, the function will + /// return its Value instead. + pub fn declare_global(&self, name: &str, ty: &'ll Type) -> &'ll Value { debug!("declare_global(name={:?})", name); unsafe { llvm::LLVMRustGetOrInsertGlobal(self.llmod, name.as_ptr().cast(), name.len(), ty) } } - fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value { + /// Declare a C ABI function. + /// + /// Only use this for foreign function ABIs and glue. For Rust functions use + /// `declare_fn` instead. + /// + /// If there’s a value with the same name already declared, the function will + /// update the declaration and return existing Value instead. + pub fn declare_cfn(&self, name: &str, fn_type: &'ll Type) -> &'ll Value { declare_raw_fn(self, name, llvm::CCallConv, fn_type) } - fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value { + /// Declare a Rust function. + /// + /// If there’s a value with the same name already declared, the function will + /// update the declaration and return existing Value instead. + pub fn declare_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> &'ll Value { debug!("declare_rust_fn(name={:?}, fn_abi={:?})", name, fn_abi); let llfn = declare_raw_fn(self, name, fn_abi.llvm_cconv(), fn_abi.llvm_type(self)); @@ -69,7 +84,13 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { llfn } - fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> { + /// Declare a global with an intention to define it. + /// + /// Use this function when you intend to define a global. This function will + /// return `None` if the name already has a definition associated with it. In that + /// case an error should be reported to the user, because it usually happens due + /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes). + pub fn define_global(&self, name: &str, ty: &'ll Type) -> Option<&'ll Value> { if self.get_defined_value(name).is_some() { None } else { @@ -77,16 +98,22 @@ impl DeclareMethods<'tcx> for CodegenCx<'ll, 'tcx> { } } - fn define_private_global(&self, ty: &'ll Type) -> &'ll Value { + /// Declare a private global + /// + /// Use this function when you intend to define a global without a name. + pub fn define_private_global(&self, ty: &'ll Type) -> &'ll Value { unsafe { llvm::LLVMRustInsertPrivateGlobal(self.llmod, ty) } } - fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { + /// Gets declared value by name. + pub fn get_declared_value(&self, name: &str) -> Option<&'ll Value> { debug!("get_declared_value(name={:?})", name); unsafe { llvm::LLVMRustGetNamedValue(self.llmod, name.as_ptr().cast(), name.len()) } } - fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { + /// Gets defined or externally defined (AvailableExternally linkage) value by + /// name. + pub fn get_defined_value(&self, name: &str) -> Option<&'ll Value> { self.get_declared_value(name).and_then(|val| { let declaration = unsafe { llvm::LLVMIsDeclaration(val) != 0 }; if !declaration { Some(val) } else { None } diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/compiler/rustc_codegen_llvm/src/intrinsic.rs similarity index 71% rename from src/librustc_codegen_llvm/intrinsic.rs rename to compiler/rustc_codegen_llvm/src/intrinsic.rs index bb79a52dcf..7f5b09eac4 100644 --- a/src/librustc_codegen_llvm/intrinsic.rs +++ b/compiler/rustc_codegen_llvm/src/intrinsic.rs @@ -7,15 +7,12 @@ use crate::type_of::LayoutLlvmExt; use crate::va_arg::emit_va_arg; use crate::value::Value; -use rustc_ast as ast; -use rustc_codegen_ssa::base::{compare_simd_types, to_immediate, wants_msvc_seh}; +use rustc_codegen_ssa::base::{compare_simd_types, wants_msvc_seh}; use rustc_codegen_ssa::common::span_invalid_monomorphization_error; use rustc_codegen_ssa::common::{IntPredicate, TypeKind}; -use rustc_codegen_ssa::glue; -use rustc_codegen_ssa::mir::operand::{OperandRef, OperandValue}; +use rustc_codegen_ssa::mir::operand::OperandRef; use rustc_codegen_ssa::mir::place::PlaceRef; use rustc_codegen_ssa::traits::*; -use rustc_codegen_ssa::MemFlags; use rustc_hir as hir; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; use rustc_middle::ty::{self, Ty}; @@ -71,8 +68,6 @@ fn get_simple_intrinsic(cx: &CodegenCx<'ll, '_>, name: Symbol) -> Option<&'ll Va sym::nearbyintf64 => "llvm.nearbyint.f64", sym::roundf32 => "llvm.round.f32", sym::roundf64 => "llvm.round.f64", - sym::assume => "llvm.assume", - sym::abort => "llvm.trap", _ => return None, }; Some(cx.get_intrinsic(&llvm_name)) @@ -90,7 +85,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let tcx = self.tcx; let callee_ty = instance.ty(tcx, ty::ParamEnv::reveal_all()); - let (def_id, substs) = match callee_ty.kind { + let (def_id, substs) = match *callee_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), _ => bug!("expected fn item type, found {}", callee_ty), }; @@ -112,9 +107,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &args.iter().map(|arg| arg.immediate()).collect::>(), None, ), - sym::unreachable => { - return; - } sym::likely => { let expect = self.get_intrinsic(&("llvm.expect.i1")); self.call(expect, &[args[0].immediate(), self.const_bool(true)], None) @@ -137,8 +129,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { let llfn = self.get_intrinsic(&("llvm.debugtrap")); self.call(llfn, &[], None) } - sym::va_start => self.va_start(args[0].immediate()), - sym::va_end => self.va_end(args[0].immediate()), sym::va_copy => { let intrinsic = self.cx().get_intrinsic(&("llvm.va_copy")); self.call(intrinsic, &[args[0].immediate(), args[1].immediate()], None) @@ -169,123 +159,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { _ => bug!("the va_arg intrinsic does not work with non-scalar types"), } } - sym::size_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (llsize, _) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llsize - } else { - self.const_usize(self.size_of(tp_ty).bytes()) - } - } - sym::min_align_of_val => { - let tp_ty = substs.type_at(0); - if let OperandValue::Pair(_, meta) = args[0].val { - let (_, llalign) = glue::size_and_align_of_dst(self, tp_ty, Some(meta)); - llalign - } else { - self.const_usize(self.align_of(tp_ty).bytes()) - } - } - sym::size_of - | sym::pref_align_of - | sym::min_align_of - | sym::needs_drop - | sym::type_id - | sym::type_name - | sym::variant_count => { - let value = self - .tcx - .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) - .unwrap(); - OperandRef::from_const(self, value, ret_ty).immediate_or_packed_pair(self) - } - // Effectively no-op - sym::forget => { - return; - } - sym::offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.inbounds_gep(ptr, &[offset]) - } - sym::arith_offset => { - let ptr = args[0].immediate(); - let offset = args[1].immediate(); - self.gep(ptr, &[offset]) - } - sym::copy_nonoverlapping => { - copy_intrinsic( - self, - false, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::copy => { - copy_intrinsic( - self, - true, - false, - substs.type_at(0), - args[1].immediate(), - args[0].immediate(), - args[2].immediate(), - ); - return; - } - sym::write_bytes => { - memset_intrinsic( - self, - false, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - - sym::volatile_copy_nonoverlapping_memory => { - copy_intrinsic( - self, - false, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_copy_memory => { - copy_intrinsic( - self, - true, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } - sym::volatile_set_memory => { - memset_intrinsic( - self, - true, - substs.type_at(0), - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - ); - return; - } sym::volatile_load | sym::unaligned_volatile_load => { let tp_ty = substs.type_at(0); let mut ptr = args[0].immediate(); @@ -301,7 +175,7 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { unsafe { llvm::LLVMSetAlignment(load, align); } - to_immediate(self, load, self.layout_of(tp_ty)) + self.to_immediate(load, self.layout_of(tp_ty)) } sym::volatile_store => { let dst = args[0].deref(self.cx()); @@ -343,20 +217,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { | sym::ctpop | sym::bswap | sym::bitreverse - | sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow - | sym::wrapping_add - | sym::wrapping_sub - | sym::wrapping_mul - | sym::unchecked_div - | sym::unchecked_rem - | sym::unchecked_shl - | sym::unchecked_shr - | sym::unchecked_add - | sym::unchecked_sub - | sym::unchecked_mul - | sym::exact_div | sym::rotate_left | sym::rotate_right | sym::saturating_add @@ -396,84 +256,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { &[args[0].immediate()], None, ), - sym::add_with_overflow - | sym::sub_with_overflow - | sym::mul_with_overflow => { - let intrinsic = format!( - "llvm.{}{}.with.overflow.i{}", - if signed { 's' } else { 'u' }, - &name_str[..3], - width - ); - let llfn = self.get_intrinsic(&intrinsic); - - // Convert `i1` to a `bool`, and write it to the out parameter - let pair = - self.call(llfn, &[args[0].immediate(), args[1].immediate()], None); - let val = self.extract_value(pair, 0); - let overflow = self.extract_value(pair, 1); - let overflow = self.zext(overflow, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(overflow, dest.llval, dest.align); - - return; - } - sym::wrapping_add => self.add(args[0].immediate(), args[1].immediate()), - sym::wrapping_sub => self.sub(args[0].immediate(), args[1].immediate()), - sym::wrapping_mul => self.mul(args[0].immediate(), args[1].immediate()), - sym::exact_div => { - if signed { - self.exactsdiv(args[0].immediate(), args[1].immediate()) - } else { - self.exactudiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_div => { - if signed { - self.sdiv(args[0].immediate(), args[1].immediate()) - } else { - self.udiv(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_rem => { - if signed { - self.srem(args[0].immediate(), args[1].immediate()) - } else { - self.urem(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_shl => self.shl(args[0].immediate(), args[1].immediate()), - sym::unchecked_shr => { - if signed { - self.ashr(args[0].immediate(), args[1].immediate()) - } else { - self.lshr(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_add => { - if signed { - self.unchecked_sadd(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_uadd(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_sub => { - if signed { - self.unchecked_ssub(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_usub(args[0].immediate(), args[1].immediate()) - } - } - sym::unchecked_mul => { - if signed { - self.unchecked_smul(args[0].immediate(), args[1].immediate()) - } else { - self.unchecked_umul(args[0].immediate(), args[1].immediate()) - } - } sym::rotate_left | sym::rotate_right => { let is_left = name == sym::rotate_left; let val = args[0].immediate(); @@ -513,75 +295,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } } - sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { - match float_type_width(arg_tys[0]) { - Some(_width) => match name { - sym::fadd_fast => self.fadd_fast(args[0].immediate(), args[1].immediate()), - sym::fsub_fast => self.fsub_fast(args[0].immediate(), args[1].immediate()), - sym::fmul_fast => self.fmul_fast(args[0].immediate(), args[1].immediate()), - sym::fdiv_fast => self.fdiv_fast(args[0].immediate(), args[1].immediate()), - sym::frem_fast => self.frem_fast(args[0].immediate(), args[1].immediate()), - _ => bug!(), - }, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic float type, found `{}`", - name, arg_tys[0] - ), - ); - return; - } - } - } - - sym::float_to_int_unchecked => { - if float_type_width(arg_tys[0]).is_none() { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic float type, \ - found `{}`", - arg_tys[0] - ), - ); - return; - } - let (width, signed) = match int_type_width_signed(ret_ty, self.cx) { - Some(pair) => pair, - None => { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `float_to_int_unchecked` \ - intrinsic: expected basic integer type, \ - found `{}`", - ret_ty - ), - ); - return; - } - }; - if signed { - self.fptosi(args[0].immediate(), self.cx.type_ix(width)) - } else { - self.fptoui(args[0].immediate(), self.cx.type_ix(width)) - } - } - - sym::discriminant_value => { - if ret_ty.is_integral() { - args[0].deref(self.cx()).codegen_get_discr(self, ret_ty) - } else { - span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) - } - } _ if name_str.starts_with("simd_") => { match generic_simd_intrinsic(self, name, callee_ty, args, ret_ty, llret_ty, span) { @@ -589,174 +302,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { Err(()) => return, } } - // This requires that atomic intrinsics follow a specific naming pattern: - // "atomic_[_]", and no ordering means SeqCst - name if name_str.starts_with("atomic_") => { - use rustc_codegen_ssa::common::AtomicOrdering::*; - use rustc_codegen_ssa::common::{AtomicRmwBinOp, SynchronizationScope}; - - let split: Vec<&str> = name_str.split('_').collect(); - - let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; - let (order, failorder) = match split.len() { - 2 => (SequentiallyConsistent, SequentiallyConsistent), - 3 => match split[2] { - "unordered" => (Unordered, Unordered), - "relaxed" => (Monotonic, Monotonic), - "acq" => (Acquire, Acquire), - "rel" => (Release, Monotonic), - "acqrel" => (AcquireRelease, Acquire), - "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), - "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - 4 => match (split[2], split[3]) { - ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), - ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), - _ => self.sess().fatal("unknown ordering in atomic intrinsic"), - }, - _ => self.sess().fatal("Atomic intrinsic not in correct format"), - }; - - let invalid_monomorphization = |ty| { - span_invalid_monomorphization_error( - tcx.sess, - span, - &format!( - "invalid monomorphization of `{}` intrinsic: \ - expected basic integer type, found `{}`", - name, ty - ), - ); - }; - - match split[1] { - "cxchg" | "cxchgweak" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let weak = split[1] == "cxchgweak"; - let pair = self.atomic_cmpxchg( - args[0].immediate(), - args[1].immediate(), - args[2].immediate(), - order, - failorder, - weak, - ); - let val = self.extract_value(pair, 0); - let success = self.extract_value(pair, 1); - let success = self.zext(success, self.type_bool()); - - let dest = result.project_field(self, 0); - self.store(val, dest.llval, dest.align); - let dest = result.project_field(self, 1); - self.store(success, dest.llval, dest.align); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "load" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_load(args[0].immediate(), order, size) - } else { - return invalid_monomorphization(ty); - } - } - - "store" => { - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - let size = self.size_of(ty); - self.atomic_store( - args[1].immediate(), - args[0].immediate(), - order, - size, - ); - return; - } else { - return invalid_monomorphization(ty); - } - } - - "fence" => { - self.atomic_fence(order, SynchronizationScope::CrossThread); - return; - } - - "singlethreadfence" => { - self.atomic_fence(order, SynchronizationScope::SingleThread); - return; - } - - // These are all AtomicRMW ops - op => { - let atom_op = match op { - "xchg" => AtomicRmwBinOp::AtomicXchg, - "xadd" => AtomicRmwBinOp::AtomicAdd, - "xsub" => AtomicRmwBinOp::AtomicSub, - "and" => AtomicRmwBinOp::AtomicAnd, - "nand" => AtomicRmwBinOp::AtomicNand, - "or" => AtomicRmwBinOp::AtomicOr, - "xor" => AtomicRmwBinOp::AtomicXor, - "max" => AtomicRmwBinOp::AtomicMax, - "min" => AtomicRmwBinOp::AtomicMin, - "umax" => AtomicRmwBinOp::AtomicUMax, - "umin" => AtomicRmwBinOp::AtomicUMin, - _ => self.sess().fatal("unknown atomic operation"), - }; - - let ty = substs.type_at(0); - if int_type_width_signed(ty, self).is_some() { - self.atomic_rmw( - atom_op, - args[0].immediate(), - args[1].immediate(), - order, - ) - } else { - return invalid_monomorphization(ty); - } - } - } - } - - sym::nontemporal_store => { - let dst = args[0].deref(self.cx()); - args[1].val.nontemporal_store(self, dst); - return; - } - - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = args[0].immediate(); - let b = args[1].immediate(); - if name == sym::ptr_guaranteed_eq { - self.icmp(IntPredicate::IntEQ, a, b) - } else { - self.icmp(IntPredicate::IntNE, a, b) - } - } - - sym::ptr_offset_from => { - let ty = substs.type_at(0); - let pointee_size = self.size_of(ty); - - // This is the same sequence that Clang emits for pointer subtraction. - // It can be neither `nsw` nor `nuw` because the input is treated as - // unsigned but then the output is treated as signed, so neither works. - let a = args[0].immediate(); - let b = args[1].immediate(); - let a = self.ptrtoint(a, self.type_isize()); - let b = self.ptrtoint(b, self.type_isize()); - let d = self.sub(a, b); - let pointee_size = self.const_usize(pointee_size.bytes()); - // this is where the signed magic happens (notice the `s` in `exactsdiv`) - self.exactsdiv(d, pointee_size) - } _ => bug!("unknown intrinsic '{}'", name), }; @@ -807,39 +352,6 @@ impl IntrinsicCallMethods<'tcx> for Builder<'a, 'll, 'tcx> { } } -fn copy_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - allow_overlap: bool, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - src: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - if allow_overlap { - bx.memmove(dst, align, src, align, size, flags); - } else { - bx.memcpy(dst, align, src, align, size, flags); - } -} - -fn memset_intrinsic( - bx: &mut Builder<'a, 'll, 'tcx>, - volatile: bool, - ty: Ty<'tcx>, - dst: &'ll Value, - val: &'ll Value, - count: &'ll Value, -) { - let (size, align) = bx.size_and_align_of(ty); - let size = bx.mul(bx.const_usize(size.bytes()), count); - let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; - bx.memset(dst, val, size, align, flags); -} - fn try_intrinsic( bx: &mut Builder<'a, 'll, 'tcx>, try_func: &'ll Value, @@ -855,6 +367,8 @@ fn try_intrinsic( bx.store(bx.const_i32(0), dest, ret_align); } else if wants_msvc_seh(bx.sess()) { codegen_msvc_try(bx, try_func, data, catch_func, dest); + } else if bx.sess().target.target.options.is_like_emscripten { + codegen_emcc_try(bx, try_func, data, catch_func, dest); } else { codegen_gnu_try(bx, try_func, data, catch_func, dest); } @@ -880,7 +394,8 @@ fn codegen_msvc_try( let mut normal = bx.build_sibling_block("normal"); let mut catchswitch = bx.build_sibling_block("catchswitch"); - let mut catchpad = bx.build_sibling_block("catchpad"); + let mut catchpad_rust = bx.build_sibling_block("catchpad_rust"); + let mut catchpad_foreign = bx.build_sibling_block("catchpad_foreign"); let mut caught = bx.build_sibling_block("caught"); let try_func = llvm::get_param(bx.llfn(), 0); @@ -890,21 +405,26 @@ fn codegen_msvc_try( // We're generating an IR snippet that looks like: // // declare i32 @rust_try(%try_func, %data, %catch_func) { - // %slot = alloca u8* + // %slot = alloca i8* // invoke %try_func(%data) to label %normal unwind label %catchswitch // // normal: // ret i32 0 // // catchswitch: - // %cs = catchswitch within none [%catchpad] unwind to caller + // %cs = catchswitch within none [%catchpad_rust, %catchpad_foreign] unwind to caller // - // catchpad: - // %tok = catchpad within %cs [%type_descriptor, 0, %slot] + // catchpad_rust: + // %tok = catchpad within %cs [%type_descriptor, 8, %slot] // %ptr = load %slot // call %catch_func(%data, %ptr) // catchret from %tok to label %caught // + // catchpad_foreign: + // %tok = catchpad within %cs [null, 64, null] + // call %catch_func(%data, null) + // catchret from %tok to label %caught + // // caught: // ret i32 1 // } @@ -912,13 +432,11 @@ fn codegen_msvc_try( // This structure follows the basic usage of throw/try/catch in LLVM. // For example, compile this C++ snippet to see what LLVM generates: // - // #include - // // struct rust_panic { // rust_panic(const rust_panic&); // ~rust_panic(); // - // uint64_t x[2]; + // void* x[2]; // }; // // int __rust_try( @@ -932,6 +450,9 @@ fn codegen_msvc_try( // } catch(rust_panic& a) { // catch_func(data, &a); // return 1; + // } catch(...) { + // catch_func(data, NULL); + // return 1; // } // } // @@ -942,8 +463,9 @@ fn codegen_msvc_try( normal.ret(bx.const_i32(0)); - let cs = catchswitch.catch_switch(None, None, 1); - catchswitch.add_handler(cs, catchpad.llbb()); + let cs = catchswitch.catch_switch(None, None, 2); + catchswitch.add_handler(cs, catchpad_rust.llbb()); + catchswitch.add_handler(cs, catchpad_foreign.llbb()); // We can't use the TypeDescriptor defined in libpanic_unwind because it // might be in another DLL and the SEH encoding only supports specifying @@ -977,11 +499,17 @@ fn codegen_msvc_try( // // Source: MicrosoftCXXABI::getAddrOfCXXCatchHandlerType in clang let flags = bx.const_i32(8); - let funclet = catchpad.catch_pad(cs, &[tydesc, flags, slot]); - let ptr = catchpad.load(slot, ptr_align); - catchpad.call(catch_func, &[data, ptr], Some(&funclet)); + let funclet = catchpad_rust.catch_pad(cs, &[tydesc, flags, slot]); + let ptr = catchpad_rust.load(slot, ptr_align); + catchpad_rust.call(catch_func, &[data, ptr], Some(&funclet)); + catchpad_rust.catch_ret(&funclet, caught.llbb()); - catchpad.catch_ret(&funclet, caught.llbb()); + // The flag value of 64 indicates a "catch-all". + let flags = bx.const_i32(64); + let null = bx.const_null(bx.type_i8p()); + let funclet = catchpad_foreign.catch_pad(cs, &[null, flags, null]); + catchpad_foreign.call(catch_func, &[data, null], Some(&funclet)); + catchpad_foreign.catch_ret(&funclet, caught.llbb()); caught.ret(bx.const_i32(1)); }); @@ -1044,13 +572,7 @@ fn codegen_gnu_try( // rust_try ignores the selector. let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false); let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 1); - let tydesc = match bx.tcx().lang_items().eh_catch_typeinfo() { - Some(tydesc) => { - let tydesc = bx.get_static(tydesc); - bx.bitcast(tydesc, bx.type_i8p()) - } - None => bx.const_null(bx.type_i8p()), - }; + let tydesc = bx.const_null(bx.type_i8p()); catch.add_clause(vals, tydesc); let ptr = catch.extract_value(vals, 0); catch.call(catch_func, &[data, ptr], None); @@ -1064,6 +586,88 @@ fn codegen_gnu_try( bx.store(ret, dest, i32_align); } +// Variant of codegen_gnu_try used for emscripten where Rust panics are +// implemented using C++ exceptions. Here we use exceptions of a specific type +// (`struct rust_panic`) to represent Rust panics. +fn codegen_emcc_try( + bx: &mut Builder<'a, 'll, 'tcx>, + try_func: &'ll Value, + data: &'ll Value, + catch_func: &'ll Value, + dest: &'ll Value, +) { + let llfn = get_rust_try_fn(bx, &mut |mut bx| { + // Codegens the shims described above: + // + // bx: + // invoke %try_func(%data) normal %normal unwind %catch + // + // normal: + // ret 0 + // + // catch: + // (%ptr, %selector) = landingpad + // %rust_typeid = @llvm.eh.typeid.for(@_ZTI10rust_panic) + // %is_rust_panic = %selector == %rust_typeid + // %catch_data = alloca { i8*, i8 } + // %catch_data[0] = %ptr + // %catch_data[1] = %is_rust_panic + // call %catch_func(%data, %catch_data) + // ret 1 + + bx.sideeffect(); + + let mut then = bx.build_sibling_block("then"); + let mut catch = bx.build_sibling_block("catch"); + + let try_func = llvm::get_param(bx.llfn(), 0); + let data = llvm::get_param(bx.llfn(), 1); + let catch_func = llvm::get_param(bx.llfn(), 2); + bx.invoke(try_func, &[data], then.llbb(), catch.llbb(), None); + then.ret(bx.const_i32(0)); + + // Type indicator for the exception being thrown. + // + // The first value in this tuple is a pointer to the exception object + // being thrown. The second value is a "selector" indicating which of + // the landing pad clauses the exception's type had been matched to. + let tydesc = bx.eh_catch_typeinfo(); + let lpad_ty = bx.type_struct(&[bx.type_i8p(), bx.type_i32()], false); + let vals = catch.landing_pad(lpad_ty, bx.eh_personality(), 2); + catch.add_clause(vals, tydesc); + catch.add_clause(vals, bx.const_null(bx.type_i8p())); + let ptr = catch.extract_value(vals, 0); + let selector = catch.extract_value(vals, 1); + + // Check if the typeid we got is the one for a Rust panic. + let llvm_eh_typeid_for = bx.get_intrinsic("llvm.eh.typeid.for"); + let rust_typeid = catch.call(llvm_eh_typeid_for, &[tydesc], None); + let is_rust_panic = catch.icmp(IntPredicate::IntEQ, selector, rust_typeid); + let is_rust_panic = catch.zext(is_rust_panic, bx.type_bool()); + + // We need to pass two values to catch_func (ptr and is_rust_panic), so + // create an alloca and pass a pointer to that. + let ptr_align = bx.tcx().data_layout.pointer_align.abi; + let i8_align = bx.tcx().data_layout.i8_align.abi; + let catch_data = + catch.alloca(bx.type_struct(&[bx.type_i8p(), bx.type_bool()], false), ptr_align); + let catch_data_0 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(0)]); + catch.store(ptr, catch_data_0, ptr_align); + let catch_data_1 = catch.inbounds_gep(catch_data, &[bx.const_usize(0), bx.const_usize(1)]); + catch.store(is_rust_panic, catch_data_1, i8_align); + let catch_data = catch.bitcast(catch_data, bx.type_i8p()); + + catch.call(catch_func, &[data, catch_data], None); + catch.ret(bx.const_i32(1)); + }); + + // Note that no invoke is used here because by definition this function + // can't panic (that's what it's catching). + let ret = bx.call(llfn, &[try_func, data, catch_func], None); + let i32_align = bx.tcx().data_layout.i32_align.abi; + bx.store(ret, dest, i32_align); +} + // Helper function to give a Block to a closure to codegen a shim function. // This is currently primarily used for the `try` intrinsic functions above. fn gen_fn<'ll, 'tcx>( @@ -1179,7 +783,7 @@ fn generic_simd_intrinsic( if name == sym::simd_select_bitmask { let in_ty = arg_tys[0]; - let m_len = match in_ty.kind { + let m_len = match in_ty.kind() { // Note that this `.unwrap()` crashes for isize/usize, that's sort // of intentional as there's not currently a use case for that. ty::Int(i) => i.bit_width().unwrap(), @@ -1344,7 +948,7 @@ fn generic_simd_intrinsic( m_len, v_len ); - match m_elem_ty.kind { + match m_elem_ty.kind() { ty::Int(_) => {} _ => return_error!("mask element type is `{}`, expected `i_`", m_elem_ty), } @@ -1363,13 +967,13 @@ fn generic_simd_intrinsic( // If the vector has less than 8 lanes, an u8 is returned with zeroed // trailing bits. let expected_int_bits = in_len.max(8); - match ret_ty.kind { + match ret_ty.kind() { ty::Uint(i) if i.bit_width() == Some(expected_int_bits) => (), _ => return_error!("bitmask `{}`, expected `u{}`", ret_ty, expected_int_bits), } // Integer vector : - let (i_xn, in_elem_bitwidth) = match in_elem.kind { + let (i_xn, in_elem_bitwidth) = match in_elem.kind() { ty::Int(i) => { (args[0].immediate(), i.bit_width().unwrap_or(bx.data_layout().pointer_size.bits())) } @@ -1426,7 +1030,7 @@ fn generic_simd_intrinsic( } } } - let ety = match in_elem.kind { + let ety = match in_elem.kind() { ty::Float(f) if f.bit_width() == 32 => { if in_len < 2 || in_len > 16 { return_error!( @@ -1520,7 +1124,7 @@ fn generic_simd_intrinsic( // 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 { let p0s: String = "p0".repeat(no_pointers); - match elem_ty.kind { + 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::Float(v) => format!("v{}{}f{}", vec_len, p0s, v.bit_width()), @@ -1535,7 +1139,7 @@ fn generic_simd_intrinsic( mut no_pointers: usize, ) -> &'ll Type { // FIXME: use cx.layout_of(ty).llvm_type() ? - let mut elem_ty = match elem_ty.kind { + let mut elem_ty = match *elem_ty.kind() { ty::Int(v) => cx.type_int_from_ty(v), ty::Uint(v) => cx.type_uint_from_ty(v), ty::Float(v) => cx.type_float_from_ty(v), @@ -1588,7 +1192,7 @@ fn generic_simd_intrinsic( // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { - match t.kind { + match t.kind() { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, } @@ -1596,7 +1200,7 @@ fn generic_simd_intrinsic( // Non-ptr type fn non_ptr(t: Ty<'_>) -> Ty<'_> { - match t.kind { + match t.kind() { ty::RawPtr(p) => non_ptr(p.ty), _ => t, } @@ -1604,7 +1208,7 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind { + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { ty::RawPtr(p) if p.ty == in_elem => { (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) } @@ -1629,7 +1233,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind { + match arg_tys[2].simd_type(tcx).kind() { ty::Int(_) => (), _ => { require!( @@ -1711,7 +1315,7 @@ fn generic_simd_intrinsic( // This counts how many pointers fn ptr_count(t: Ty<'_>) -> usize { - match t.kind { + match t.kind() { ty::RawPtr(p) => 1 + ptr_count(p.ty), _ => 0, } @@ -1719,7 +1323,7 @@ fn generic_simd_intrinsic( // Non-ptr type fn non_ptr(t: Ty<'_>) -> Ty<'_> { - match t.kind { + match t.kind() { ty::RawPtr(p) => non_ptr(p.ty), _ => t, } @@ -1727,7 +1331,7 @@ fn generic_simd_intrinsic( // The second argument must be a simd vector with an element type that's a pointer // to the element type of the first argument - let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind { + let (pointer_count, underlying_ty) = match arg_tys[1].simd_type(tcx).kind() { ty::RawPtr(p) if p.ty == in_elem && p.mutbl == hir::Mutability::Mut => { (ptr_count(arg_tys[1].simd_type(tcx)), non_ptr(arg_tys[1].simd_type(tcx))) } @@ -1752,7 +1356,7 @@ fn generic_simd_intrinsic( assert_eq!(underlying_ty, non_ptr(arg_tys[0].simd_type(tcx))); // The element type of the third argument must be a signed integer type of any width: - match arg_tys[2].simd_type(tcx).kind { + match arg_tys[2].simd_type(tcx).kind() { ty::Int(_) => (), _ => { require!( @@ -1808,7 +1412,7 @@ fn generic_simd_intrinsic( in_ty, ret_ty ); - return match in_elem.kind { + return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.$integer_reduce(args[0].immediate()); if $ordered { @@ -1880,7 +1484,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, in_ty, ret_ty ); - return match in_elem.kind { + return match in_elem.kind() { ty::Int(_i) => Ok(bx.$int_red(args[0].immediate(), true)), ty::Uint(_u) => Ok(bx.$int_red(args[0].immediate(), false)), ty::Float(_f) => Ok(bx.$float_red(args[0].immediate())), @@ -1915,7 +1519,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ); args[0].immediate() } else { - match in_elem.kind { + match in_elem.kind() { ty::Int(_) | ty::Uint(_) => {} _ => return_error!( "unsupported {} from `{}` with element `{}` to `{}`", @@ -1931,7 +1535,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, let i1xn = bx.type_vector(i1, in_len as u64); bx.trunc(args[0].immediate(), i1xn) }; - return match in_elem.kind { + return match in_elem.kind() { ty::Int(_) | ty::Uint(_) => { let r = bx.$red(input); Ok(if !$boolean { r } else { bx.zext(r, bx.type_bool()) }) @@ -1979,7 +1583,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, Unsupported, } - let (in_style, in_width) = match in_elem.kind { + let (in_style, in_width) = match in_elem.kind() { // vectors of pointer-sized integers should've been // disallowed before here, so this unwrap is safe. ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()), @@ -1987,7 +1591,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, ty::Float(f) => (Style::Float, f.bit_width()), _ => (Style::Unsupported, 0), }; - let (out_style, out_width) = match out_elem.kind { + let (out_style, out_width) = match out_elem.kind() { ty::Int(i) => (Style::Int(true), i.bit_width().unwrap()), ty::Uint(u) => (Style::Int(false), u.bit_width().unwrap()), ty::Float(f) => (Style::Float, f.bit_width()), @@ -2043,7 +1647,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, macro_rules! arith { ($($name: ident: $($($p: ident),* => $call: ident),*;)*) => { $(if name == sym::$name { - match in_elem.kind { + match in_elem.kind() { $($(ty::$p(_))|* => { return Ok(bx.$call(args[0].immediate(), args[1].immediate())) })* @@ -2077,7 +1681,7 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, let rhs = args[1].immediate(); let is_add = name == sym::simd_saturating_add; let ptr_bits = bx.tcx().data_layout.pointer_size.bits() as _; - let (signed, elem_width, elem_ty) = match in_elem.kind { + let (signed, elem_width, elem_ty) = match *in_elem.kind() { ty::Int(i) => (true, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_int_from_ty(i)), ty::Uint(i) => (false, i.bit_width().unwrap_or(ptr_bits), bx.cx.type_uint_from_ty(i)), _ => { @@ -2112,38 +1716,13 @@ unsupported {} from `{}` with element `{}` of size `{}` to `{}`"#, // FIXME: there’s multiple of this functions, investigate using some of the already existing // stuffs. fn int_type_width_signed(ty: Ty<'_>, cx: &CodegenCx<'_, '_>) -> Option<(u64, bool)> { - match ty.kind { - ty::Int(t) => Some(( - match t { - ast::IntTy::Isize => u64::from(cx.tcx.sess.target.ptr_width), - ast::IntTy::I8 => 8, - ast::IntTy::I16 => 16, - ast::IntTy::I32 => 32, - ast::IntTy::I64 => 64, - ast::IntTy::I128 => 128, - }, - true, - )), - ty::Uint(t) => Some(( - match t { - ast::UintTy::Usize => u64::from(cx.tcx.sess.target.ptr_width), - ast::UintTy::U8 => 8, - ast::UintTy::U16 => 16, - ast::UintTy::U32 => 32, - ast::UintTy::U64 => 64, - ast::UintTy::U128 => 128, - }, - false, - )), - _ => None, - } -} - -// Returns the width of a float Ty -// Returns None if the type is not a float -fn float_type_width(ty: Ty<'_>) -> Option { - match ty.kind { - ty::Float(t) => Some(t.bit_width()), + match ty.kind() { + ty::Int(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), true)) + } + ty::Uint(t) => { + Some((t.bit_width().unwrap_or(u64::from(cx.tcx.sess.target.ptr_width)), false)) + } _ => None, } } diff --git a/src/librustc_codegen_llvm/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs similarity index 97% rename from src/librustc_codegen_llvm/lib.rs rename to compiler/rustc_codegen_llvm/src/lib.rs index 67d4b2642c..f14493e604 100644 --- a/src/librustc_codegen_llvm/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -4,7 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_cstr_unchecked)] #![feature(crate_visibility_modifier)] @@ -12,7 +12,6 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![recursion_limit = "256"] use back::write::{create_informational_target_machine, create_target_machine}; @@ -130,6 +129,13 @@ impl WriteBackendMethods for LlvmCodegenBackend { llvm::LLVMRustPrintPassTimings(); } } + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError> { + back::write::link(cgcx, diag_handler, modules) + } fn run_fat_lto( cgcx: &CodegenContext, modules: Vec>, diff --git a/src/librustc_codegen_llvm/llvm/archive_ro.rs b/compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs similarity index 100% rename from src/librustc_codegen_llvm/llvm/archive_ro.rs rename to compiler/rustc_codegen_llvm/src/llvm/archive_ro.rs diff --git a/src/librustc_codegen_llvm/llvm/diagnostic.rs b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs similarity index 98% rename from src/librustc_codegen_llvm/llvm/diagnostic.rs rename to compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs index 47f5c94e70..ccd3e42e45 100644 --- a/src/librustc_codegen_llvm/llvm/diagnostic.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/diagnostic.rs @@ -118,6 +118,7 @@ pub enum Diagnostic<'ll> { InlineAsm(InlineAsmDiagnostic<'ll>), PGO(&'ll DiagnosticInfo), Linker(&'ll DiagnosticInfo), + Unsupported(&'ll DiagnosticInfo), /// LLVM has other types that we do not wrap here. UnknownDiagnostic(&'ll DiagnosticInfo), @@ -159,6 +160,7 @@ impl Diagnostic<'ll> { Dk::PGOProfile => PGO(di), Dk::Linker => Linker(di), + Dk::Unsupported => Unsupported(di), _ => UnknownDiagnostic(di), } diff --git a/src/librustc_codegen_llvm/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs similarity index 99% rename from src/librustc_codegen_llvm/llvm/ffi.rs rename to compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 32822eba93..af3f3e7aa0 100644 --- a/src/librustc_codegen_llvm/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -96,7 +96,7 @@ pub enum DLLStorageClass { DllExport = 2, // Function to be accessible from DLL. } -/// Matches LLVMRustAttribute in rustllvm.h +/// Matches LLVMRustAttribute in LLVMWrapper.h /// Semantically a subset of the C++ enum llvm::Attribute::AttrKind, /// though it is not ABI compatible (since it's a C++ enum) #[repr(C)] @@ -483,6 +483,7 @@ pub enum DiagnosticKind { OptimizationFailure, PGOProfile, Linker, + Unsupported, } /// LLVMRustDiagnosticLevel @@ -948,7 +949,6 @@ extern "C" { // Operations on other types pub fn LLVMVoidTypeInContext(C: &Context) -> &Type; - pub fn LLVMX86MMXTypeInContext(C: &Context) -> &Type; pub fn LLVMRustMetadataTypeInContext(C: &Context) -> &Type; // Operations on all values @@ -1705,7 +1705,7 @@ extern "C" { PM: &PassManager<'_>, ); - // Stuff that's in rustllvm/ because it's not upstream yet. + // Stuff that's in llvm-wrapper/ because it's not upstream yet. /// Opens an object file. pub fn LLVMCreateObjectFile( diff --git a/src/librustc_codegen_llvm/llvm/mod.rs b/compiler/rustc_codegen_llvm/src/llvm/mod.rs similarity index 97% rename from src/librustc_codegen_llvm/llvm/mod.rs rename to compiler/rustc_codegen_llvm/src/llvm/mod.rs index c09e3659f8..ed9b99188b 100644 --- a/src/librustc_codegen_llvm/llvm/mod.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/mod.rs @@ -37,6 +37,12 @@ pub fn AddFunctionAttrStringValue(llfn: &'a Value, idx: AttributePlace, attr: &C } } +pub fn AddFunctionAttrString(llfn: &'a Value, idx: AttributePlace, attr: &CStr) { + unsafe { + LLVMRustAddFunctionAttrStringValue(llfn, idx.as_uint(), attr.as_ptr(), std::ptr::null()) + } +} + #[derive(Copy, Clone)] pub enum AttributePlace { ReturnValue, diff --git a/src/librustc_codegen_llvm/llvm_util.rs b/compiler/rustc_codegen_llvm/src/llvm_util.rs similarity index 99% rename from src/librustc_codegen_llvm/llvm_util.rs rename to compiler/rustc_codegen_llvm/src/llvm_util.rs index f0b5045983..900f2df383 100644 --- a/src/librustc_codegen_llvm/llvm_util.rs +++ b/compiler/rustc_codegen_llvm/src/llvm_util.rs @@ -203,7 +203,6 @@ const X86_ALLOWED_FEATURES: &[(&str, Option)] = &[ ("fma", None), ("fxsr", None), ("lzcnt", None), - ("mmx", Some(sym::mmx_target_feature)), ("movbe", Some(sym::movbe_target_feature)), ("pclmulqdq", None), ("popcnt", None), diff --git a/src/librustc_codegen_llvm/metadata.rs b/compiler/rustc_codegen_llvm/src/metadata.rs similarity index 100% rename from src/librustc_codegen_llvm/metadata.rs rename to compiler/rustc_codegen_llvm/src/metadata.rs diff --git a/src/librustc_codegen_llvm/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs similarity index 100% rename from src/librustc_codegen_llvm/mono_item.rs rename to compiler/rustc_codegen_llvm/src/mono_item.rs diff --git a/src/librustc_codegen_llvm/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs similarity index 98% rename from src/librustc_codegen_llvm/type_.rs rename to compiler/rustc_codegen_llvm/src/type_.rs index 3b53b4fe77..a43724fd49 100644 --- a/src/librustc_codegen_llvm/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -62,10 +62,6 @@ impl CodegenCx<'ll, 'tcx> { unsafe { llvm::LLVMIntTypeInContext(self.llcx, num_bits as c_uint) } } - crate fn type_x86_mmx(&self) -> &'ll Type { - unsafe { llvm::LLVMX86MMXTypeInContext(self.llcx) } - } - crate fn type_vector(&self, ty: &'ll Type, len: u64) -> &'ll Type { unsafe { llvm::LLVMVectorType(ty, len as c_uint) } } diff --git a/src/librustc_codegen_llvm/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs similarity index 89% rename from src/librustc_codegen_llvm/type_of.rs rename to compiler/rustc_codegen_llvm/src/type_of.rs index 40870c6647..e0754d21df 100644 --- a/src/librustc_codegen_llvm/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -4,7 +4,7 @@ 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::obsolete::DefPathBasedNames; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Ty, TypeFoldable}; use rustc_target::abi::{Abi, AddressSpace, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; @@ -21,23 +21,8 @@ fn uncached_llvm_type<'a, 'tcx>( match layout.abi { Abi::Scalar(_) => bug!("handled elsewhere"), Abi::Vector { ref element, count } => { - // LLVM has a separate type for 64-bit SIMD vectors on X86 called - // `x86_mmx` which is needed for some SIMD operations. As a bit of a - // hack (all SIMD definitions are super unstable anyway) we - // recognize any one-element SIMD vector as "this should be an - // x86_mmx" type. In general there shouldn't be a need for other - // one-element SIMD vectors, so it's assumed this won't clash with - // much else. - let use_x86_mmx = count == 1 - && layout.size.bits() == 64 - && (cx.sess().target.target.arch == "x86" - || cx.sess().target.target.arch == "x86_64"); - if use_x86_mmx { - return cx.type_x86_mmx(); - } else { - let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); - return cx.type_vector(element, count); - } + let element = layout.scalar_llvm_type_at(cx, element, Size::ZERO); + return cx.type_vector(element, count); } Abi::ScalarPair(..) => { return cx.type_struct( @@ -51,33 +36,35 @@ fn uncached_llvm_type<'a, 'tcx>( Abi::Uninhabited | Abi::Aggregate { .. } => {} } - let name = match layout.ty.kind { - ty::Closure(..) | - ty::Generator(..) | - ty::Adt(..) | + 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::Foreign(..) | - ty::Str => { - let mut name = String::with_capacity(32); - let printer = DefPathBasedNames::new(cx.tcx, true, true); - printer.push_type_name(layout.ty, &mut name, false); - if let (&ty::Adt(def, _), &Variants::Single { index }) - = (&layout.ty.kind, &layout.variants) + 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) + if let (&ty::Generator(_, _, _), &Variants::Single { index }) = + (layout.ty.kind(), &layout.variants) { write!(&mut name, "::{}", ty::GeneratorSubsts::variant_name(index)).unwrap(); } Some(name) } - _ => None + 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. + Some(String::new()) + } + _ => None, }; match layout.fields { @@ -236,7 +223,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { if let Some(&llty) = cx.scalar_lltypes.borrow().get(&self.ty) { return llty; } - let llty = match self.ty.kind { + let llty = match *self.ty.kind() { ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { cx.type_ptr_to(cx.layout_of(ty).llvm_type(cx)) } @@ -329,7 +316,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { ) -> &'a Type { // HACK(eddyb) special-case fat pointers until LLVM removes // pointee types, to avoid bitcasting every `OperandRef::deref`. - match self.ty.kind { + match self.ty.kind() { ty::Ref(..) | ty::RawPtr(_) => { return self.field(cx, index).llvm_type(cx); } diff --git a/src/librustc_codegen_llvm/va_arg.rs b/compiler/rustc_codegen_llvm/src/va_arg.rs similarity index 99% rename from src/librustc_codegen_llvm/va_arg.rs rename to compiler/rustc_codegen_llvm/src/va_arg.rs index 54efa05aee..22ed4dd757 100644 --- a/src/librustc_codegen_llvm/va_arg.rs +++ b/compiler/rustc_codegen_llvm/src/va_arg.rs @@ -11,7 +11,6 @@ use rustc_middle::ty::layout::HasTyCtxt; use rustc_middle::ty::Ty; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size}; -#[allow(dead_code)] fn round_pointer_up_to_alignment( bx: &mut Builder<'a, 'll, 'tcx>, addr: &'ll Value, diff --git a/src/librustc_codegen_llvm/value.rs b/compiler/rustc_codegen_llvm/src/value.rs similarity index 100% rename from src/librustc_codegen_llvm/value.rs rename to compiler/rustc_codegen_llvm/src/value.rs diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml new file mode 100644 index 0000000000..e5df0f6094 --- /dev/null +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -0,0 +1,36 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_codegen_ssa" +version = "0.0.0" +edition = "2018" + +[lib] +test = false + +[dependencies] +bitflags = "1.2.1" +cc = "1.0.1" +num_cpus = "1.0" +memmap = "0.7" +tracing = "0.1" +libc = "0.2.50" +jobserver = "0.1.11" +tempfile = "3.1" +pathdiff = "0.2.0" + +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_middle = { path = "../rustc_middle" } +rustc_apfloat = { path = "../rustc_apfloat" } +rustc_attr = { path = "../rustc_attr" } +rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } +rustc_data_structures = { path = "../rustc_data_structures"} +rustc_errors = { path = "../rustc_errors" } +rustc_fs_util = { path = "../rustc_fs_util" } +rustc_hir = { path = "../rustc_hir" } +rustc_incremental = { path = "../rustc_incremental" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } +rustc_target = { path = "../rustc_target" } +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_codegen_ssa/README.md b/compiler/rustc_codegen_ssa/README.md similarity index 100% rename from src/librustc_codegen_ssa/README.md rename to compiler/rustc_codegen_ssa/README.md diff --git a/src/librustc_codegen_ssa/back/archive.rs b/compiler/rustc_codegen_ssa/src/back/archive.rs similarity index 100% rename from src/librustc_codegen_ssa/back/archive.rs rename to compiler/rustc_codegen_ssa/src/back/archive.rs diff --git a/src/librustc_codegen_ssa/back/command.rs b/compiler/rustc_codegen_ssa/src/back/command.rs similarity index 100% rename from src/librustc_codegen_ssa/back/command.rs rename to compiler/rustc_codegen_ssa/src/back/command.rs diff --git a/src/librustc_codegen_ssa/back/link.rs b/compiler/rustc_codegen_ssa/src/back/link.rs similarity index 94% rename from src/librustc_codegen_ssa/back/link.rs rename to compiler/rustc_codegen_ssa/src/back/link.rs index bfcf979d12..010fd4e9c5 100644 --- a/src/librustc_codegen_ssa/back/link.rs +++ b/compiler/rustc_codegen_ssa/src/back/link.rs @@ -1014,86 +1014,7 @@ fn print_native_static_libs(sess: &Session, all_native_libs: &[NativeLib]) { } } -// Because windows-gnu target is meant to be self-contained for pure Rust code it bundles -// own mingw-w64 libraries. These libraries are usually not compatible with mingw-w64 -// installed in the system. This breaks many cases where Rust is mixed with other languages -// (e.g. *-sys crates). -// We prefer system mingw-w64 libraries if they are available to avoid this issue. -fn get_crt_libs_path(sess: &Session) -> Option { - fn find_exe_in_path

(exe_name: P) -> Option - where - P: AsRef, - { - for dir in env::split_paths(&env::var_os("PATH")?) { - let full_path = dir.join(&exe_name); - if full_path.is_file() { - return Some(fix_windows_verbatim_for_gcc(&full_path)); - } - } - None - } - - fn probe(sess: &Session) -> Option { - if let (linker, LinkerFlavor::Gcc) = linker_and_flavor(&sess) { - let linker_path = if cfg!(windows) && linker.extension().is_none() { - linker.with_extension("exe") - } else { - linker - }; - if let Some(linker_path) = find_exe_in_path(linker_path) { - let mingw_arch = match &sess.target.target.arch { - x if x == "x86" => "i686", - x => x, - }; - let mingw_bits = &sess.target.target.target_pointer_width; - let mingw_dir = format!("{}-w64-mingw32", mingw_arch); - // Here we have path/bin/gcc but we need path/ - let mut path = linker_path; - path.pop(); - path.pop(); - // Loosely based on Clang MinGW driver - let probe_paths = vec![ - path.join(&mingw_dir).join("lib"), // Typical path - path.join(&mingw_dir).join("sys-root/mingw/lib"), // Rare path - path.join(format!( - "lib/mingw/tools/install/mingw{}/{}/lib", - &mingw_bits, &mingw_dir - )), // Chocolatey is creative - ]; - for probe_path in probe_paths { - if probe_path.join("crt2.o").exists() { - return Some(probe_path); - }; - } - }; - }; - None - } - - let mut system_library_path = sess.system_library_path.borrow_mut(); - match &*system_library_path { - Some(Some(compiler_libs_path)) => Some(compiler_libs_path.clone()), - Some(None) => None, - None => { - let path = probe(sess); - *system_library_path = Some(path.clone()); - path - } - } -} - fn get_object_file_path(sess: &Session, name: &str, self_contained: bool) -> PathBuf { - // prefer system {,dll}crt2.o libs, see get_crt_libs_path comment for more details - if sess.opts.debugging_opts.link_self_contained.is_none() - && sess.target.target.llvm_target.contains("windows-gnu") - { - if let Some(compiler_libs_path) = get_crt_libs_path(sess) { - let file_path = compiler_libs_path.join(name); - if file_path.exists() { - return file_path; - } - } - } let fs = sess.target_filesearch(PathKind::Native); let file_path = fs.get_lib_path().join(name); if file_path.exists() { @@ -1155,7 +1076,7 @@ fn exec_linker( } .to_string(), ); - args.push_str("\n"); + args.push('\n'); } let file = tmpdir.join("linker-arguments"); let bytes = if sess.target.target.options.is_like_msvc { @@ -1286,10 +1207,32 @@ fn link_output_kind(sess: &Session, crate_type: CrateType) -> LinkOutputKind { } } +// Returns true if linker is located within sysroot +fn detect_self_contained_mingw(sess: &Session) -> bool { + let (linker, _) = linker_and_flavor(&sess); + // Assume `-C linker=rust-lld` as self-contained mode + if linker == Path::new("rust-lld") { + return true; + } + let linker_with_extension = if cfg!(windows) && linker.extension().is_none() { + linker.with_extension("exe") + } else { + linker + }; + for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { + let full_path = dir.join(&linker_with_extension); + // If linker comes from sysroot assume self-contained mode + if full_path.is_file() && !full_path.starts_with(&sess.sysroot) { + return false; + } + } + true +} + /// Whether we link to our own CRT objects instead of relying on gcc to pull them. /// We only provide such support for a very limited number of targets. fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { - if let Some(self_contained) = sess.opts.debugging_opts.link_self_contained { + if let Some(self_contained) = sess.opts.cg.link_self_contained { return self_contained; } @@ -1298,10 +1241,10 @@ fn crt_objects_fallback(sess: &Session, crate_type: CrateType) -> bool { // based on host and linker path, for example. // (https://github.com/rust-lang/rust/pull/71769#issuecomment-626330237). Some(CrtObjectsFallback::Musl) => sess.crt_static(Some(crate_type)), - // FIXME: Find some heuristic for "native mingw toolchain is available", - // likely based on `get_crt_libs_path` (https://github.com/rust-lang/rust/pull/67429). Some(CrtObjectsFallback::Mingw) => { - sess.host == sess.target.target && sess.target.target.target_vendor != "uwp" + sess.host == sess.target.target + && sess.target.target.target_vendor != "uwp" + && detect_self_contained_mingw(&sess) } // FIXME: Figure out cases in which WASM needs to link with a native toolchain. Some(CrtObjectsFallback::Wasm) => true, @@ -1390,9 +1333,6 @@ fn add_late_link_args( crate_type: CrateType, codegen_results: &CodegenResults, ) { - if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { - cmd.args(args); - } let any_dynamic_crate = crate_type == CrateType::Dylib || codegen_results.crate_info.dependency_formats.iter().any(|(ty, list)| { *ty == crate_type && list.iter().any(|&linkage| linkage == Linkage::Dynamic) @@ -1406,6 +1346,9 @@ fn add_late_link_args( cmd.args(args); } } + if let Some(args) = sess.target.target.options.late_link_args.get(&flavor) { + cmd.args(args); + } } /// Add arbitrary "post-link" args defined by the target spec. @@ -1498,16 +1441,6 @@ fn link_local_crate_native_libs_and_dependent_crate_libs<'a, B: ArchiveBuilder<' /// Add sysroot and other globally set directories to the directory search list. fn add_library_search_dirs(cmd: &mut dyn Linker, sess: &Session, self_contained: bool) { - // Prefer system mingw-w64 libs, see get_crt_libs_path comment for more details. - if sess.opts.debugging_opts.link_self_contained.is_none() - && cfg!(windows) - && sess.target.target.llvm_target.contains("windows-gnu") - { - if let Some(compiler_libs_path) = get_crt_libs_path(sess) { - cmd.include_path(&compiler_libs_path); - } - } - // The default library location, we need this to find the runtime. // The location of crates will be determined as needed. let lib_path = sess.target_filesearch(PathKind::All).get_lib_path(); @@ -1591,6 +1524,9 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // NO-OPT-OUT, OBJECT-FILES-MAYBE, CUSTOMIZATION-POINT add_pre_link_args(cmd, sess, flavor); + // NO-OPT-OUT, OBJECT-FILES-NO + add_apple_sdk(cmd, sess, flavor); + // NO-OPT-OUT add_link_script(cmd, sess, tmpdir, crate_type); @@ -1668,7 +1604,7 @@ fn linker_with_args<'a, B: ArchiveBuilder<'a>>( // FIXME: Order dependent, applies to the following objects. Where should it be placed? // Try to strip as much out of the generated object by removing unused // sections if possible. See more comments in linker.rs - if sess.opts.cg.link_dead_code != Some(true) { + if !sess.link_dead_code() { let keep_metadata = crate_type == CrateType::Dylib; cmd.gc_sections(keep_metadata); } @@ -2150,3 +2086,86 @@ fn are_upstream_rust_objects_already_included(sess: &Session) -> bool { config::Lto::No | config::Lto::ThinLocal => false, } } + +fn add_apple_sdk(cmd: &mut dyn Linker, sess: &Session, flavor: LinkerFlavor) { + let arch = &sess.target.target.arch; + let os = &sess.target.target.target_os; + let llvm_target = &sess.target.target.llvm_target; + if sess.target.target.target_vendor != "apple" + || !matches!(os.as_str(), "ios" | "tvos") + || flavor != LinkerFlavor::Gcc + { + return; + } + let sdk_name = match (arch.as_str(), os.as_str()) { + ("aarch64", "tvos") => "appletvos", + ("x86_64", "tvos") => "appletvsimulator", + ("arm", "ios") => "iphoneos", + ("aarch64", "ios") => "iphoneos", + ("x86", "ios") => "iphonesimulator", + ("x86_64", "ios") if llvm_target.contains("macabi") => "macosx10.15", + ("x86_64", "ios") => "iphonesimulator", + _ => { + sess.err(&format!("unsupported arch `{}` for os `{}`", arch, os)); + return; + } + }; + let sdk_root = match get_apple_sdk_root(sdk_name) { + Ok(s) => s, + Err(e) => { + sess.err(&e); + return; + } + }; + let arch_name = llvm_target.split('-').next().expect("LLVM target must have a hyphen"); + cmd.args(&["-arch", arch_name, "-isysroot", &sdk_root, "-Wl,-syslibroot", &sdk_root]); +} + +fn get_apple_sdk_root(sdk_name: &str) -> Result { + // Following what clang does + // (https://github.com/llvm/llvm-project/blob/ + // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678) + // to allow the SDK path to be set. (For clang, xcrun sets + // SDKROOT; for rustc, the user or build system can set it, or we + // can fall back to checking for xcrun on PATH.) + if let Ok(sdkroot) = env::var("SDKROOT") { + let p = Path::new(&sdkroot); + match sdk_name { + // Ignore `SDKROOT` if it's clearly set for the wrong platform. + "appletvos" + if sdkroot.contains("TVSimulator.platform") + || sdkroot.contains("MacOSX.platform") => {} + "appletvsimulator" + if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {} + "iphoneos" + if sdkroot.contains("iPhoneSimulator.platform") + || sdkroot.contains("MacOSX.platform") => {} + "iphonesimulator" + if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => { + } + "macosx10.15" + if sdkroot.contains("iPhoneOS.platform") + || sdkroot.contains("iPhoneSimulator.platform") => {} + // Ignore `SDKROOT` if it's not a valid path. + _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} + _ => return Ok(sdkroot), + } + } + let res = + Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then( + |output| { + if output.status.success() { + Ok(String::from_utf8(output.stdout).unwrap()) + } else { + let error = String::from_utf8(output.stderr); + let error = format!("process exit with error: {}", error.unwrap()); + Err(io::Error::new(io::ErrorKind::Other, &error[..])) + } + }, + ); + + match res { + Ok(output) => Ok(output.trim().to_string()), + Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)), + } +} diff --git a/src/librustc_codegen_ssa/back/linker.rs b/compiler/rustc_codegen_ssa/src/back/linker.rs similarity index 100% rename from src/librustc_codegen_ssa/back/linker.rs rename to compiler/rustc_codegen_ssa/src/back/linker.rs diff --git a/src/librustc_codegen_ssa/back/lto.rs b/compiler/rustc_codegen_ssa/src/back/lto.rs similarity index 100% rename from src/librustc_codegen_ssa/back/lto.rs rename to compiler/rustc_codegen_ssa/src/back/lto.rs diff --git a/src/librustc_codegen_ssa/back/mod.rs b/compiler/rustc_codegen_ssa/src/back/mod.rs similarity index 100% rename from src/librustc_codegen_ssa/back/mod.rs rename to compiler/rustc_codegen_ssa/src/back/mod.rs diff --git a/src/librustc_codegen_ssa/back/rpath.rs b/compiler/rustc_codegen_ssa/src/back/rpath.rs similarity index 100% rename from src/librustc_codegen_ssa/back/rpath.rs rename to compiler/rustc_codegen_ssa/src/back/rpath.rs diff --git a/src/librustc_codegen_ssa/back/rpath/tests.rs b/compiler/rustc_codegen_ssa/src/back/rpath/tests.rs similarity index 100% rename from src/librustc_codegen_ssa/back/rpath/tests.rs rename to compiler/rustc_codegen_ssa/src/back/rpath/tests.rs diff --git a/src/librustc_codegen_ssa/back/symbol_export.rs b/compiler/rustc_codegen_ssa/src/back/symbol_export.rs similarity index 100% rename from src/librustc_codegen_ssa/back/symbol_export.rs rename to compiler/rustc_codegen_ssa/src/back/symbol_export.rs diff --git a/src/librustc_codegen_ssa/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs similarity index 97% rename from src/librustc_codegen_ssa/back/write.rs rename to compiler/rustc_codegen_ssa/src/back/write.rs index 7d69bb983d..0edf0fcd1a 100644 --- a/src/librustc_codegen_ssa/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -702,6 +702,7 @@ impl WorkItem { enum WorkItemResult { Compiled(CompiledModule), + NeedsLink(ModuleCodegen), NeedsFatLTO(FatLTOInput), NeedsThinLTO(String, B::ThinBuffer), } @@ -801,11 +802,8 @@ fn execute_optimize_work_item( None }; - Ok(match lto_type { - ComputedLtoType::No => { - let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; - WorkItemResult::Compiled(module) - } + match lto_type { + ComputedLtoType::No => finish_intra_module_work(cgcx, module, module_config), ComputedLtoType::Thin => { let (name, thin_buffer) = B::prepare_thin(module); if let Some(path) = bitcode { @@ -813,7 +811,7 @@ fn execute_optimize_work_item( panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); } - WorkItemResult::NeedsThinLTO(name, thin_buffer) + Ok(WorkItemResult::NeedsThinLTO(name, thin_buffer)) } ComputedLtoType::Fat => match bitcode { Some(path) => { @@ -821,11 +819,11 @@ fn execute_optimize_work_item( fs::write(&path, buffer.data()).unwrap_or_else(|e| { panic!("Error writing pre-lto-bitcode file `{}`: {}", path.display(), e); }); - WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer }) + Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::Serialized { name, buffer })) } - None => WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module)), + None => Ok(WorkItemResult::NeedsFatLTO(FatLTOInput::InMemory(module))), }, - }) + } } fn execute_copy_from_cache_work_item( @@ -870,13 +868,26 @@ fn execute_lto_work_item( cgcx: &CodegenContext, mut module: lto::LtoModuleCodegen, module_config: &ModuleConfig, +) -> Result, FatalError> { + let module = unsafe { module.optimize(cgcx)? }; + finish_intra_module_work(cgcx, module, module_config) +} + +fn finish_intra_module_work( + cgcx: &CodegenContext, + module: ModuleCodegen, + module_config: &ModuleConfig, ) -> Result, FatalError> { let diag_handler = cgcx.create_diag_handler(); - unsafe { - let module = module.optimize(cgcx)?; - let module = B::codegen(cgcx, &diag_handler, module, module_config)?; + if !cgcx.opts.debugging_opts.combine_cgu + || module.kind == ModuleKind::Metadata + || module.kind == ModuleKind::Allocator + { + let module = unsafe { B::codegen(cgcx, &diag_handler, module, module_config)? }; Ok(WorkItemResult::Compiled(module)) + } else { + Ok(WorkItemResult::NeedsLink(module)) } } @@ -891,6 +902,10 @@ pub enum Message { thin_buffer: B::ThinBuffer, worker_id: usize, }, + NeedsLink { + module: ModuleCodegen, + worker_id: usize, + }, Done { result: Result>, worker_id: usize, @@ -1178,6 +1193,7 @@ fn start_executing_work( let mut compiled_modules = vec![]; let mut compiled_metadata_module = None; let mut compiled_allocator_module = None; + let mut needs_link = Vec::new(); let mut needs_fat_lto = Vec::new(); let mut needs_thin_lto = Vec::new(); let mut lto_import_only_modules = Vec::new(); @@ -1434,6 +1450,10 @@ fn start_executing_work( } } } + Message::NeedsLink { module, worker_id } => { + free_worker(worker_id); + needs_link.push(module); + } Message::NeedsFatLTO { result, worker_id } => { assert!(!started_lto); free_worker(worker_id); @@ -1462,6 +1482,18 @@ fn start_executing_work( } } + let needs_link = mem::take(&mut needs_link); + if !needs_link.is_empty() { + assert!(compiled_modules.is_empty()); + let diag_handler = cgcx.create_diag_handler(); + let module = B::run_link(&cgcx, &diag_handler, needs_link).map_err(|_| ())?; + let module = unsafe { + B::codegen(&cgcx, &diag_handler, module, cgcx.config(ModuleKind::Regular)) + .map_err(|_| ())? + }; + compiled_modules.push(module); + } + // Drop to print timings drop(llvm_start_time); @@ -1521,6 +1553,9 @@ fn spawn_work(cgcx: CodegenContext, work: WorkItem Some(Ok(WorkItemResult::Compiled(m))) => { Message::Done:: { result: Ok(m), worker_id } } + Some(Ok(WorkItemResult::NeedsLink(m))) => { + Message::NeedsLink:: { module: m, worker_id } + } Some(Ok(WorkItemResult::NeedsFatLTO(m))) => { Message::NeedsFatLTO:: { result: m, worker_id } } diff --git a/src/librustc_codegen_ssa/base.rs b/compiler/rustc_codegen_ssa/src/base.rs similarity index 95% rename from src/librustc_codegen_ssa/base.rs rename to compiler/rustc_codegen_ssa/src/base.rs index 77c12c410d..d82fc2c9f6 100644 --- a/src/librustc_codegen_ssa/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -38,7 +38,7 @@ use rustc_middle::middle::cstore::EncodedMetadata; use rustc_middle::middle::cstore::{self, LinkagePreference}; use rustc_middle::middle::lang_items; use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; -use rustc_middle::ty::layout::{self, HasTyCtxt, TyAndLayout}; +use rustc_middle::ty::layout::{HasTyCtxt, TyAndLayout}; use rustc_middle::ty::layout::{FAT_PTR_ADDR, FAT_PTR_EXTRA}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; @@ -48,7 +48,7 @@ use rustc_session::utils::NativeLibKind; use rustc_session::Session; use rustc_span::Span; use rustc_symbol_mangling::test as symbol_names_test; -use rustc_target::abi::{Abi, Align, LayoutOf, Scalar, VariantIdx}; +use rustc_target::abi::{Align, LayoutOf, VariantIdx}; use std::cmp; use std::ops::{Deref, DerefMut}; @@ -120,7 +120,7 @@ pub fn compare_simd_types<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ret_ty: Bx::Type, op: hir::BinOpKind, ) -> Bx::Value { - let signed = match t.kind { + let signed = match t.kind() { ty::Float(_) => { let cmp = bin_op_to_fcmp_predicate(op); let cmp = bx.fcmp(cmp, lhs, rhs); @@ -153,7 +153,7 @@ pub fn unsized_info<'tcx, Cx: CodegenMethods<'tcx>>( ) -> Cx::Value { let (source, target) = cx.tcx().struct_lockstep_tails_erasing_lifetimes(source, target, cx.param_env()); - match (&source.kind, &target.kind) { + match (source.kind(), target.kind()) { (&ty::Array(_, len), &ty::Slice(_)) => { cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all())) } @@ -182,7 +182,7 @@ pub fn unsize_thin_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( dst_ty: Ty<'tcx>, ) -> (Bx::Value, Bx::Value) { debug!("unsize_thin_ptr: {:?} => {:?}", src_ty, dst_ty); - match (&src_ty.kind, &dst_ty.kind) { + match (src_ty.kind(), dst_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, .. })) => { assert!(bx.cx().type_is_sized(a)); @@ -231,7 +231,7 @@ pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( ) { let src_ty = src.layout.ty; let dst_ty = dst.layout.ty; - match (&src_ty.kind, &dst_ty.kind) { + match (src_ty.kind(), dst_ty.kind()) { (&ty::Ref(..), &ty::Ref(..) | &ty::RawPtr(..)) | (&ty::RawPtr(..), &ty::RawPtr(..)) => { let (base, info) = match bx.load_operand(src).val { OperandValue::Pair(base, info) => { @@ -330,35 +330,6 @@ pub fn wants_msvc_seh(sess: &Session) -> bool { sess.target.target.options.is_like_msvc } -pub fn from_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - val: Bx::Value, -) -> Bx::Value { - if bx.cx().val_ty(val) == bx.cx().type_i1() { bx.zext(val, bx.cx().type_i8()) } else { val } -} - -pub fn to_immediate<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - val: Bx::Value, - layout: layout::TyAndLayout<'_>, -) -> Bx::Value { - if let Abi::Scalar(ref scalar) = layout.abi { - return to_immediate_scalar(bx, val, scalar); - } - val -} - -pub fn to_immediate_scalar<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( - bx: &mut Bx, - val: Bx::Value, - scalar: &Scalar, -) -> Bx::Value { - if scalar.is_bool() { - return bx.trunc(val, bx.cx().type_i1()); - } - val -} - pub fn memcpy_ty<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, dst: Bx::Value, @@ -436,16 +407,18 @@ pub fn maybe_create_entry_wrapper<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // listing. let main_ret_ty = cx.tcx().erase_regions(&main_ret_ty.no_bound_vars().unwrap()); - if cx.get_declared_value("main").is_some() { - // FIXME: We should be smart and show a better diagnostic here. - cx.sess() - .struct_span_err(sp, "entry symbol `main` declared multiple times") - .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") - .emit(); - cx.sess().abort_if_errors(); - bug!(); - } - let llfn = cx.declare_cfn("main", llfty); + let llfn = match cx.declare_c_main(llfty) { + Some(llfn) => llfn, + None => { + // FIXME: We should be smart and show a better diagnostic here. + cx.sess() + .struct_span_err(sp, "entry symbol `main` declared multiple times") + .help("did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead") + .emit(); + cx.sess().abort_if_errors(); + bug!(); + } + }; // `main` should respect same config for frame pointer elimination as rest of code cx.set_frame_pointer_elimination(llfn); diff --git a/src/librustc_codegen_ssa/common.rs b/compiler/rustc_codegen_ssa/src/common.rs similarity index 98% rename from src/librustc_codegen_ssa/common.rs rename to compiler/rustc_codegen_ssa/src/common.rs index e04ed531bb..780b1d2cd9 100644 --- a/src/librustc_codegen_ssa/common.rs +++ b/compiler/rustc_codegen_ssa/src/common.rs @@ -1,4 +1,4 @@ -#![allow(non_camel_case_types, non_snake_case)] +#![allow(non_camel_case_types)] use rustc_errors::struct_span_err; use rustc_hir as hir; @@ -25,7 +25,6 @@ pub enum IntPredicate { IntSLE, } -#[allow(dead_code)] pub enum RealPredicate { RealPredicateFalse, RealOEQ, @@ -60,7 +59,6 @@ pub enum AtomicRmwBinOp { } pub enum AtomicOrdering { - #[allow(dead_code)] NotAtomic, Unordered, Monotonic, diff --git a/src/librustc_codegen_ssa/coverageinfo/ffi.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs similarity index 100% rename from src/librustc_codegen_ssa/coverageinfo/ffi.rs rename to compiler/rustc_codegen_ssa/src/coverageinfo/ffi.rs diff --git a/src/librustc_codegen_ssa/coverageinfo/map.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/map.rs similarity index 100% rename from src/librustc_codegen_ssa/coverageinfo/map.rs rename to compiler/rustc_codegen_ssa/src/coverageinfo/map.rs diff --git a/src/librustc_codegen_ssa/coverageinfo/mod.rs b/compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs similarity index 100% rename from src/librustc_codegen_ssa/coverageinfo/mod.rs rename to compiler/rustc_codegen_ssa/src/coverageinfo/mod.rs diff --git a/src/librustc_codegen_ssa/debuginfo/mod.rs b/compiler/rustc_codegen_ssa/src/debuginfo/mod.rs similarity index 100% rename from src/librustc_codegen_ssa/debuginfo/mod.rs rename to compiler/rustc_codegen_ssa/src/debuginfo/mod.rs diff --git a/src/librustc_codegen_ssa/debuginfo/type_names.rs b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs similarity index 98% rename from src/librustc_codegen_ssa/debuginfo/type_names.rs rename to compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs index fb8f5a6298..45ecb79338 100644 --- a/src/librustc_codegen_ssa/debuginfo/type_names.rs +++ b/compiler/rustc_codegen_ssa/src/debuginfo/type_names.rs @@ -5,6 +5,8 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::ty::{self, subst::SubstsRef, Ty, TyCtxt}; +use std::fmt::Write; + // Compute the name of the type as it should be stored in debuginfo. Does not do // any caching, i.e., calling the function twice with the same type will also do // the work twice. The `qualified` parameter only affects the first level of the @@ -33,11 +35,11 @@ pub fn push_debuginfo_type_name<'tcx>( // .natvis visualizers (and perhaps other existing native debuggers?) let cpp_like_names = tcx.sess.target.target.options.is_like_msvc; - match t.kind { + match *t.kind() { ty::Bool => output.push_str("bool"), ty::Char => output.push_str("char"), ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), + ty::Never => output.push('!'), ty::Int(int_ty) => output.push_str(int_ty.name_str()), ty::Uint(uint_ty) => output.push_str(uint_ty.name_str()), ty::Float(float_ty) => output.push_str(float_ty.name_str()), @@ -228,8 +230,7 @@ pub fn push_debuginfo_type_name<'tcx>( if qualified { output.push_str(&tcx.crate_name(def_id.krate).as_str()); for path_element in tcx.def_path(def_id).data { - output.push_str("::"); - output.push_str(&path_element.data.as_symbol().as_str()); + write!(output, "::{}", path_element.data).unwrap(); } } else { output.push_str(&tcx.item_name(def_id).as_str()); diff --git a/src/librustc_codegen_ssa/glue.rs b/compiler/rustc_codegen_ssa/src/glue.rs similarity index 98% rename from src/librustc_codegen_ssa/glue.rs rename to compiler/rustc_codegen_ssa/src/glue.rs index 5b086bc43f..b88de0b241 100644 --- a/src/librustc_codegen_ssa/glue.rs +++ b/compiler/rustc_codegen_ssa/src/glue.rs @@ -19,7 +19,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let align = bx.const_usize(layout.align.abi.bytes()); return (size, align); } - match t.kind { + match t.kind() { ty::Dynamic(..) => { // load size/align from vtable let vtable = info.unwrap(); @@ -64,7 +64,7 @@ pub fn size_and_align_of_dst<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( let size = bx.add(sized_size, unsized_size); // Packed types ignore the alignment of their fields. - if let ty::Adt(def, _) = t.kind { + if let ty::Adt(def, _) = t.kind() { if def.repr.packed() { unsized_align = sized_align; } diff --git a/src/librustc_codegen_ssa/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs similarity index 96% rename from src/librustc_codegen_ssa/lib.rs rename to compiler/rustc_codegen_ssa/src/lib.rs index 73e3336917..d4f3bf3779 100644 --- a/src/librustc_codegen_ssa/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(option_expect_none)] #![feature(box_patterns)] @@ -6,10 +6,7 @@ #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] -#![feature(trusted_len)] #![feature(associated_type_bounds)] -#![feature(const_fn)] // for rustc_index::newtype_index -#![feature(const_panic)] // for rustc_index::newtype_index #![recursion_limit = "256"] //! This crate contains codegen code that is used by all codegen backends (LLVM and others). diff --git a/src/librustc_codegen_ssa/meth.rs b/compiler/rustc_codegen_ssa/src/meth.rs similarity index 100% rename from src/librustc_codegen_ssa/meth.rs rename to compiler/rustc_codegen_ssa/src/meth.rs diff --git a/src/librustc_codegen_ssa/mir/analyze.rs b/compiler/rustc_codegen_ssa/src/mir/analyze.rs similarity index 99% rename from src/librustc_codegen_ssa/mir/analyze.rs rename to compiler/rustc_codegen_ssa/src/mir/analyze.rs index 2e386c1e59..bdde07d3fa 100644 --- a/src/librustc_codegen_ssa/mir/analyze.rs +++ b/compiler/rustc_codegen_ssa/src/mir/analyze.rs @@ -236,7 +236,7 @@ impl<'mir, 'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> Visitor<'tcx> fn visit_terminator(&mut self, terminator: &mir::Terminator<'tcx>, location: Location) { let check = match terminator.kind { mir::TerminatorKind::Call { func: mir::Operand::Constant(ref c), ref args, .. } => { - match c.literal.ty.kind { + match *c.literal.ty.kind() { ty::FnDef(did, _) => Some((did, args)), _ => None, } diff --git a/src/librustc_codegen_ssa/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs similarity index 96% rename from src/librustc_codegen_ssa/mir/block.rs rename to compiler/rustc_codegen_ssa/src/mir/block.rs index 8048a569f7..703a17b200 100644 --- a/src/librustc_codegen_ssa/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -13,9 +13,10 @@ use rustc_ast as ast; use rustc_hir::lang_items::LangItem; use rustc_index::vec::Idx; use rustc_middle::mir; -use rustc_middle::mir::interpret::{AllocId, ConstValue, Pointer, Scalar}; +use rustc_middle::mir::interpret::ConstValue; use rustc_middle::mir::AssertKind; use rustc_middle::ty::layout::{FnAbiExt, HasTyCtxt}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, Instance, Ty, TypeFoldable}; use rustc_span::source_map::Span; use rustc_span::{sym, Symbol}; @@ -331,7 +332,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { args1 = [place.llval]; &args1[..] }; - let (drop_fn, fn_abi) = match ty.kind { + let (drop_fn, fn_abi) = match ty.kind() { // FIXME(eddyb) perhaps move some of this logic into // `Instance::resolve_drop_in_place`? ty::Dynamic(..) => { @@ -479,14 +480,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { UninitValid => !layout.might_permit_raw_init(bx, /*zero:*/ false).unwrap(), }; if do_panic { - let msg_str = 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_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, span).immediate(); @@ -537,7 +540,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // Create the callee. This is a fn ptr or zero-sized and hence a kind of scalar. let callee = self.codegen_operand(&mut bx, func); - let (instance, mut llfn) = match callee.layout.ty.kind { + let (instance, mut llfn) = match *callee.layout.ty.kind() { ty::FnDef(def_id, substs) => ( Some( ty::Instance::resolve(bx.tcx(), ty::ParamEnv::reveal_all(), def_id, substs) @@ -684,7 +687,8 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { }) .collect(); - bx.codegen_intrinsic_call( + Self::codegen_intrinsic_call( + &mut bx, *instance.as_ref().unwrap(), &fn_abi, &args, @@ -864,27 +868,15 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let ty = constant.literal.ty; let size = bx.layout_of(ty).size; let scalar = match const_value { - // Promoted constants are evaluated into a ByRef instead of a Scalar, - // but we want the scalar value here. - ConstValue::ByRef { alloc, offset } => { - let ptr = Pointer::new(AllocId(0), offset); - alloc - .read_scalar(&bx, ptr, size) - .and_then(|s| s.check_init()) - .unwrap_or_else(|e| { - bx.tcx().sess.span_err( - span, - &format!("Could not evaluate asm const: {}", e), - ); - - // We are erroring out, just emit a dummy constant. - Scalar::from_u64(0) - }) - } - _ => span_bug!(span, "expected ByRef for promoted asm const"), + ConstValue::Scalar(s) => s, + _ => span_bug!( + span, + "expected Scalar for promoted asm const, but got {:#?}", + const_value + ), }; let value = scalar.assert_bits(size); - let string = match ty.kind { + let string = match ty.kind() { ty::Uint(_) => value.to_string(), ty::Int(int_ty) => { match int_ty.normalize(bx.tcx().sess.target.ptr_width) { @@ -911,7 +903,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } mir::InlineAsmOperand::SymFn { ref value } => { let literal = self.monomorphize(&value.literal); - if let ty::FnDef(def_id, substs) = literal.ty.kind { + if let ty::FnDef(def_id, substs) = *literal.ty.kind() { let instance = ty::Instance::resolve_for_fn_ptr( bx.tcx(), ty::ParamEnv::reveal_all(), @@ -1143,7 +1135,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } // We store bools as `i8` so we need to truncate to `i1`. - llval = base::to_immediate(bx, llval, arg.layout); + llval = bx.to_immediate(llval, arg.layout); } } diff --git a/src/librustc_codegen_ssa/mir/constant.rs b/compiler/rustc_codegen_ssa/src/mir/constant.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/constant.rs rename to compiler/rustc_codegen_ssa/src/mir/constant.rs diff --git a/src/librustc_codegen_ssa/mir/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/coverageinfo.rs rename to compiler/rustc_codegen_ssa/src/mir/coverageinfo.rs diff --git a/src/librustc_codegen_ssa/mir/debuginfo.rs b/compiler/rustc_codegen_ssa/src/mir/debuginfo.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/debuginfo.rs rename to compiler/rustc_codegen_ssa/src/mir/debuginfo.rs diff --git a/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs new file mode 100644 index 0000000000..14f1ed59a6 --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/mir/intrinsic.rs @@ -0,0 +1,596 @@ +use super::operand::{OperandRef, OperandValue}; +use super::place::PlaceRef; +use super::FunctionCx; +use crate::common::{span_invalid_monomorphization_error, IntPredicate}; +use crate::glue; +use crate::traits::*; +use crate::MemFlags; + +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{sym, Span}; +use rustc_target::abi::call::{FnAbi, PassMode}; + +fn copy_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + allow_overlap: bool, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + src: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + if allow_overlap { + bx.memmove(dst, align, src, align, size, flags); + } else { + bx.memcpy(dst, align, src, align, size, flags); + } +} + +fn memset_intrinsic<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + volatile: bool, + ty: Ty<'tcx>, + dst: Bx::Value, + val: Bx::Value, + count: Bx::Value, +) { + let layout = bx.layout_of(ty); + let size = layout.size; + let align = layout.align.abi; + let size = bx.mul(bx.const_usize(size.bytes()), count); + let flags = if volatile { MemFlags::VOLATILE } else { MemFlags::empty() }; + bx.memset(dst, val, size, align, flags); +} + +impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { + pub fn codegen_intrinsic_call( + bx: &mut Bx, + instance: ty::Instance<'tcx>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + args: &[OperandRef<'tcx, Bx::Value>], + llresult: Bx::Value, + span: Span, + ) { + let callee_ty = instance.ty(bx.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(bx.tcx()); + let sig = bx.tcx().normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); + let arg_tys = sig.inputs(); + let ret_ty = sig.output(); + let name = bx.tcx().item_name(def_id); + let name_str = &*name.as_str(); + + let llret_ty = bx.backend_type(bx.layout_of(ret_ty)); + let result = PlaceRef::new_sized(llresult, fn_abi.ret.layout); + + let llval = match name { + sym::assume => { + bx.assume(args[0].immediate()); + return; + } + sym::abort => { + bx.abort(); + return; + } + + sym::unreachable => { + return; + } + sym::va_start => bx.va_start(args[0].immediate()), + sym::va_end => bx.va_end(args[0].immediate()), + sym::size_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (llsize, _) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llsize + } else { + bx.const_usize(bx.layout_of(tp_ty).size.bytes()) + } + } + sym::min_align_of_val => { + let tp_ty = substs.type_at(0); + if let OperandValue::Pair(_, meta) = args[0].val { + let (_, llalign) = glue::size_and_align_of_dst(bx, tp_ty, Some(meta)); + llalign + } else { + bx.const_usize(bx.layout_of(tp_ty).align.abi.bytes()) + } + } + sym::size_of + | sym::pref_align_of + | sym::min_align_of + | sym::needs_drop + | sym::type_id + | sym::type_name + | sym::variant_count => { + let value = bx + .tcx() + .const_eval_instance(ty::ParamEnv::reveal_all(), instance, None) + .unwrap(); + OperandRef::from_const(bx, value, ret_ty).immediate_or_packed_pair(bx) + } + // Effectively no-op + sym::forget => { + return; + } + sym::offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.inbounds_gep(ptr, &[offset]) + } + sym::arith_offset => { + let ptr = args[0].immediate(); + let offset = args[1].immediate(); + bx.gep(ptr, &[offset]) + } + + sym::copy_nonoverlapping => { + copy_intrinsic( + bx, + false, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::copy => { + copy_intrinsic( + bx, + true, + false, + substs.type_at(0), + args[1].immediate(), + args[0].immediate(), + args[2].immediate(), + ); + return; + } + sym::write_bytes => { + memset_intrinsic( + bx, + false, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + + sym::volatile_copy_nonoverlapping_memory => { + copy_intrinsic( + bx, + false, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_copy_memory => { + copy_intrinsic( + bx, + true, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_set_memory => { + memset_intrinsic( + bx, + true, + substs.type_at(0), + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + ); + return; + } + sym::volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.volatile_store(bx, dst); + return; + } + sym::unaligned_volatile_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.unaligned_volatile_store(bx, dst); + return; + } + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow + | sym::wrapping_add + | sym::wrapping_sub + | sym::wrapping_mul + | sym::unchecked_div + | sym::unchecked_rem + | sym::unchecked_shl + | sym::unchecked_shr + | sym::unchecked_add + | sym::unchecked_sub + | sym::unchecked_mul + | sym::exact_div => { + let ty = arg_tys[0]; + match int_type_width_signed(ty, bx.tcx()) { + Some((_width, signed)) => match name { + sym::add_with_overflow + | sym::sub_with_overflow + | sym::mul_with_overflow => { + let op = match name { + sym::add_with_overflow => OverflowOp::Add, + sym::sub_with_overflow => OverflowOp::Sub, + sym::mul_with_overflow => OverflowOp::Mul, + _ => bug!(), + }; + let (val, overflow) = + bx.checked_binop(op, ty, args[0].immediate(), args[1].immediate()); + // Convert `i1` to a `bool`, and write it to the out parameter + let val = bx.from_immediate(val); + let overflow = bx.from_immediate(overflow); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(overflow, dest.llval, dest.align); + + return; + } + sym::wrapping_add => bx.add(args[0].immediate(), args[1].immediate()), + sym::wrapping_sub => bx.sub(args[0].immediate(), args[1].immediate()), + sym::wrapping_mul => bx.mul(args[0].immediate(), args[1].immediate()), + sym::exact_div => { + if signed { + bx.exactsdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.exactudiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_div => { + if signed { + bx.sdiv(args[0].immediate(), args[1].immediate()) + } else { + bx.udiv(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_rem => { + if signed { + bx.srem(args[0].immediate(), args[1].immediate()) + } else { + bx.urem(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_shl => bx.shl(args[0].immediate(), args[1].immediate()), + sym::unchecked_shr => { + if signed { + bx.ashr(args[0].immediate(), args[1].immediate()) + } else { + bx.lshr(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_add => { + if signed { + bx.unchecked_sadd(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_uadd(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_sub => { + if signed { + bx.unchecked_ssub(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_usub(args[0].immediate(), args[1].immediate()) + } + } + sym::unchecked_mul => { + if signed { + bx.unchecked_smul(args[0].immediate(), args[1].immediate()) + } else { + bx.unchecked_umul(args[0].immediate(), args[1].immediate()) + } + } + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + return; + } + } + } + sym::fadd_fast | sym::fsub_fast | sym::fmul_fast | sym::fdiv_fast | sym::frem_fast => { + match float_type_width(arg_tys[0]) { + Some(_width) => match name { + sym::fadd_fast => bx.fadd_fast(args[0].immediate(), args[1].immediate()), + sym::fsub_fast => bx.fsub_fast(args[0].immediate(), args[1].immediate()), + sym::fmul_fast => bx.fmul_fast(args[0].immediate(), args[1].immediate()), + sym::fdiv_fast => bx.fdiv_fast(args[0].immediate(), args[1].immediate()), + sym::frem_fast => bx.frem_fast(args[0].immediate(), args[1].immediate()), + _ => bug!(), + }, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic float type, found `{}`", + name, arg_tys[0] + ), + ); + return; + } + } + } + + sym::float_to_int_unchecked => { + if float_type_width(arg_tys[0]).is_none() { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic float type, \ + found `{}`", + arg_tys[0] + ), + ); + return; + } + let (_width, signed) = match int_type_width_signed(ret_ty, bx.tcx()) { + Some(pair) => pair, + None => { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `float_to_int_unchecked` \ + intrinsic: expected basic integer type, \ + found `{}`", + ret_ty + ), + ); + return; + } + }; + if signed { + bx.fptosi(args[0].immediate(), llret_ty) + } else { + bx.fptoui(args[0].immediate(), llret_ty) + } + } + + sym::discriminant_value => { + if ret_ty.is_integral() { + args[0].deref(bx.cx()).codegen_get_discr(bx, ret_ty) + } else { + span_bug!(span, "Invalid discriminant type for `{:?}`", arg_tys[0]) + } + } + + // This requires that atomic intrinsics follow a specific naming pattern: + // "atomic_[_]", and no ordering means SeqCst + name if name_str.starts_with("atomic_") => { + use crate::common::AtomicOrdering::*; + use crate::common::{AtomicRmwBinOp, SynchronizationScope}; + + let split: Vec<&str> = name_str.split('_').collect(); + + let is_cxchg = split[1] == "cxchg" || split[1] == "cxchgweak"; + let (order, failorder) = match split.len() { + 2 => (SequentiallyConsistent, SequentiallyConsistent), + 3 => match split[2] { + "unordered" => (Unordered, Unordered), + "relaxed" => (Monotonic, Monotonic), + "acq" => (Acquire, Acquire), + "rel" => (Release, Monotonic), + "acqrel" => (AcquireRelease, Acquire), + "failrelaxed" if is_cxchg => (SequentiallyConsistent, Monotonic), + "failacq" if is_cxchg => (SequentiallyConsistent, Acquire), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + 4 => match (split[2], split[3]) { + ("acq", "failrelaxed") if is_cxchg => (Acquire, Monotonic), + ("acqrel", "failrelaxed") if is_cxchg => (AcquireRelease, Monotonic), + _ => bx.sess().fatal("unknown ordering in atomic intrinsic"), + }, + _ => bx.sess().fatal("Atomic intrinsic not in correct format"), + }; + + let invalid_monomorphization = |ty| { + span_invalid_monomorphization_error( + bx.tcx().sess, + span, + &format!( + "invalid monomorphization of `{}` intrinsic: \ + expected basic integer type, found `{}`", + name, ty + ), + ); + }; + + match split[1] { + "cxchg" | "cxchgweak" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let weak = split[1] == "cxchgweak"; + let pair = bx.atomic_cmpxchg( + args[0].immediate(), + args[1].immediate(), + args[2].immediate(), + order, + failorder, + weak, + ); + let val = bx.extract_value(pair, 0); + let success = bx.extract_value(pair, 1); + let val = bx.from_immediate(val); + let success = bx.from_immediate(success); + + let dest = result.project_field(bx, 0); + bx.store(val, dest.llval, dest.align); + let dest = result.project_field(bx, 1); + bx.store(success, dest.llval, dest.align); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "load" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_load(args[0].immediate(), order, size) + } else { + return invalid_monomorphization(ty); + } + } + + "store" => { + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + let size = bx.layout_of(ty).size; + bx.atomic_store(args[1].immediate(), args[0].immediate(), order, size); + return; + } else { + return invalid_monomorphization(ty); + } + } + + "fence" => { + bx.atomic_fence(order, SynchronizationScope::CrossThread); + return; + } + + "singlethreadfence" => { + bx.atomic_fence(order, SynchronizationScope::SingleThread); + return; + } + + // These are all AtomicRMW ops + op => { + let atom_op = match op { + "xchg" => AtomicRmwBinOp::AtomicXchg, + "xadd" => AtomicRmwBinOp::AtomicAdd, + "xsub" => AtomicRmwBinOp::AtomicSub, + "and" => AtomicRmwBinOp::AtomicAnd, + "nand" => AtomicRmwBinOp::AtomicNand, + "or" => AtomicRmwBinOp::AtomicOr, + "xor" => AtomicRmwBinOp::AtomicXor, + "max" => AtomicRmwBinOp::AtomicMax, + "min" => AtomicRmwBinOp::AtomicMin, + "umax" => AtomicRmwBinOp::AtomicUMax, + "umin" => AtomicRmwBinOp::AtomicUMin, + _ => bx.sess().fatal("unknown atomic operation"), + }; + + let ty = substs.type_at(0); + if int_type_width_signed(ty, bx.tcx()).is_some() { + bx.atomic_rmw(atom_op, args[0].immediate(), args[1].immediate(), order) + } else { + return invalid_monomorphization(ty); + } + } + } + } + + sym::nontemporal_store => { + let dst = args[0].deref(bx.cx()); + args[1].val.nontemporal_store(bx, dst); + return; + } + + sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { + let a = args[0].immediate(); + let b = args[1].immediate(); + if name == sym::ptr_guaranteed_eq { + bx.icmp(IntPredicate::IntEQ, a, b) + } else { + bx.icmp(IntPredicate::IntNE, a, b) + } + } + + sym::ptr_offset_from => { + let ty = substs.type_at(0); + let pointee_size = bx.layout_of(ty).size; + + // This is the same sequence that Clang emits for pointer subtraction. + // It can be neither `nsw` nor `nuw` because the input is treated as + // unsigned but then the output is treated as signed, so neither works. + let a = args[0].immediate(); + let b = args[1].immediate(); + let a = bx.ptrtoint(a, bx.type_isize()); + let b = bx.ptrtoint(b, bx.type_isize()); + let d = bx.sub(a, b); + let pointee_size = bx.const_usize(pointee_size.bytes()); + // this is where the signed magic happens (notice the `s` in `exactsdiv`) + bx.exactsdiv(d, pointee_size) + } + + _ => { + // Need to use backend-specific things in the implementation. + bx.codegen_intrinsic_call(instance, fn_abi, args, llresult, span); + return; + } + }; + + if !fn_abi.ret.is_ignore() { + if let PassMode::Cast(ty) = fn_abi.ret.mode { + let ptr_llty = bx.type_ptr_to(bx.cast_backend_type(&ty)); + let ptr = bx.pointercast(result.llval, ptr_llty); + bx.store(llval, ptr, result.align); + } else { + OperandRef::from_immediate_or_packed_pair(bx, llval, result.layout) + .val + .store(bx, result); + } + } + } +} + +// Returns the width of an int Ty, and if it's signed or not +// Returns None if the type is not an integer +// FIXME: there’s multiple of this functions, investigate using some of the already existing +// stuffs. +fn int_type_width_signed(ty: Ty<'_>, tcx: TyCtxt<'_>) -> Option<(u64, bool)> { + match ty.kind() { + ty::Int(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), true)), + ty::Uint(t) => Some((t.bit_width().unwrap_or(u64::from(tcx.sess.target.ptr_width)), false)), + _ => None, + } +} + +// Returns the width of a float Ty +// Returns None if the type is not a float +fn float_type_width(ty: Ty<'_>) -> Option { + match ty.kind() { + ty::Float(t) => Some(t.bit_width()), + _ => None, + } +} diff --git a/src/librustc_codegen_ssa/mir/mod.rs b/compiler/rustc_codegen_ssa/src/mir/mod.rs similarity index 99% rename from src/librustc_codegen_ssa/mir/mod.rs rename to compiler/rustc_codegen_ssa/src/mir/mod.rs index 26e6c35470..64d456fb7a 100644 --- a/src/librustc_codegen_ssa/mir/mod.rs +++ b/compiler/rustc_codegen_ssa/src/mir/mod.rs @@ -369,8 +369,8 @@ fn arg_local_refs<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( // individual LLVM function arguments. let arg_ty = fx.monomorphize(&arg_decl.ty); - let tupled_arg_tys = match arg_ty.kind { - ty::Tuple(ref tys) => tys, + let tupled_arg_tys = match arg_ty.kind() { + ty::Tuple(tys) => tys, _ => bug!("spread argument isn't a tuple?!"), }; @@ -486,6 +486,7 @@ mod block; pub mod constant; pub mod coverageinfo; pub mod debuginfo; +mod intrinsic; pub mod operand; pub mod place; mod rvalue; diff --git a/src/librustc_codegen_ssa/mir/operand.rs b/compiler/rustc_codegen_ssa/src/mir/operand.rs similarity index 92% rename from src/librustc_codegen_ssa/mir/operand.rs rename to compiler/rustc_codegen_ssa/src/mir/operand.rs index 937c7457c6..bbd004be87 100644 --- a/src/librustc_codegen_ssa/mir/operand.rs +++ b/compiler/rustc_codegen_ssa/src/mir/operand.rs @@ -147,8 +147,8 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { debug!("Operand::immediate_or_packed_pair: packing {:?} into {:?}", self, llty); // Reconstruct the immediate aggregate. let mut llpair = bx.cx().const_undef(llty); - let imm_a = base::from_immediate(bx, a); - let imm_b = base::from_immediate(bx, b); + let imm_a = bx.from_immediate(a); + let imm_b = bx.from_immediate(b); llpair = bx.insert_value(llpair, imm_a, 0); llpair = bx.insert_value(llpair, imm_b, 1); llpair @@ -168,9 +168,9 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { // Deconstruct the immediate aggregate. let a_llval = bx.extract_value(llval, 0); - let a_llval = base::to_immediate_scalar(bx, a_llval, a); + let a_llval = bx.to_immediate_scalar(a_llval, a); let b_llval = bx.extract_value(llval, 1); - let b_llval = base::to_immediate_scalar(bx, b_llval, b); + let b_llval = bx.to_immediate_scalar(b_llval, b); OperandValue::Pair(a_llval, b_llval) } else { OperandValue::Immediate(llval) @@ -220,29 +220,23 @@ impl<'a, 'tcx, V: CodegenObject> OperandRef<'tcx, V> { _ => bug!("OperandRef::extract_field({:?}): not applicable", self), }; - // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. - // Bools in union fields needs to be truncated. - let to_immediate_or_cast = |bx: &mut Bx, val, ty| { - if ty == bx.cx().type_i1() { bx.trunc(val, ty) } else { bx.bitcast(val, ty) } - }; - - match val { - OperandValue::Immediate(ref mut llval) => { - *llval = to_immediate_or_cast(bx, *llval, bx.cx().immediate_backend_type(field)); + match (&mut val, &field.abi) { + (OperandValue::Immediate(llval), _) => { + // Bools in union fields needs to be truncated. + *llval = bx.to_immediate(*llval, field); + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + *llval = bx.bitcast(*llval, bx.cx().immediate_backend_type(field)); } - OperandValue::Pair(ref mut a, ref mut b) => { - *a = to_immediate_or_cast( - bx, - *a, - bx.cx().scalar_pair_element_backend_type(field, 0, true), - ); - *b = to_immediate_or_cast( - bx, - *b, - bx.cx().scalar_pair_element_backend_type(field, 1, true), - ); + (OperandValue::Pair(a, b), Abi::ScalarPair(a_abi, b_abi)) => { + // Bools in union fields needs to be truncated. + *a = bx.to_immediate_scalar(*a, a_abi); + *b = bx.to_immediate_scalar(*b, b_abi); + // HACK(eddyb) have to bitcast pointers until LLVM removes pointee types. + *a = bx.bitcast(*a, bx.cx().scalar_pair_element_backend_type(field, 0, true)); + *b = bx.bitcast(*b, bx.cx().scalar_pair_element_backend_type(field, 1, true)); } - OperandValue::Ref(..) => bug!(), + (OperandValue::Pair(..), _) => bug!(), + (OperandValue::Ref(..), _) => bug!(), } OperandRef { val, layout: field } @@ -302,7 +296,7 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { bug!("cannot directly store unsized values"); } OperandValue::Immediate(s) => { - let val = base::from_immediate(bx, s); + let val = bx.from_immediate(s); bx.store_with_flags(val, dest.llval, dest.align, flags); } OperandValue::Pair(a, b) => { @@ -313,12 +307,12 @@ impl<'a, 'tcx, V: CodegenObject> OperandValue { let b_offset = a_scalar.value.size(bx).align_to(b_scalar.value.align(bx).abi); let llptr = bx.struct_gep(dest.llval, 0); - let val = base::from_immediate(bx, a); + let val = bx.from_immediate(a); let align = dest.align; bx.store_with_flags(val, llptr, align, flags); let llptr = bx.struct_gep(dest.llval, 1); - let val = base::from_immediate(bx, b); + let val = bx.from_immediate(b); let align = dest.align.restrict_for_offset(b_offset); bx.store_with_flags(val, llptr, align, flags); } diff --git a/src/librustc_codegen_ssa/mir/place.rs b/compiler/rustc_codegen_ssa/src/mir/place.rs similarity index 92% rename from src/librustc_codegen_ssa/mir/place.rs rename to compiler/rustc_codegen_ssa/src/mir/place.rs index 05656774f0..91609b2261 100644 --- a/src/librustc_codegen_ssa/mir/place.rs +++ b/compiler/rustc_codegen_ssa/src/mir/place.rs @@ -93,15 +93,33 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { let effective_field_align = self.align.restrict_for_offset(offset); let mut simple = || { - // Unions and newtypes only use an offset of 0. - let llval = if offset.bytes() == 0 { - self.llval - } else if let Abi::ScalarPair(ref a, ref b) = self.layout.abi { - // Offsets have to match either first or second field. - assert_eq!(offset, a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi)); - bx.struct_gep(self.llval, 1) - } else { - bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)) + let llval = match self.layout.abi { + _ if offset.bytes() == 0 => { + // Unions and newtypes only use an offset of 0. + // Also handles the first field of Scalar, ScalarPair, and Vector layouts. + self.llval + } + Abi::ScalarPair(ref a, ref b) + if offset == a.value.size(bx.cx()).align_to(b.value.align(bx.cx()).abi) => + { + // Offset matches second field. + bx.struct_gep(self.llval, 1) + } + Abi::Scalar(_) | Abi::ScalarPair(..) | Abi::Vector { .. } if field.is_zst() => { + // ZST fields are not included in Scalar, ScalarPair, and Vector layouts, so manually offset the pointer. + let byte_ptr = bx.pointercast(self.llval, bx.cx().type_i8p()); + bx.gep(byte_ptr, &[bx.const_usize(offset.bytes())]) + } + Abi::Scalar(_) | Abi::ScalarPair(..) => { + // All fields of Scalar and ScalarPair layouts must have been handled by this point. + // Vector layouts have additional fields for each element of the vector, so don't panic in that case. + bug!( + "offset of non-ZST field `{:?}` does not match layout `{:#?}`", + field, + self.layout + ); + } + _ => bx.struct_gep(self.llval, bx.cx().backend_field_index(self.layout, ix)), }; PlaceRef { // HACK(eddyb): have to bitcast pointers until LLVM removes pointee types. @@ -116,7 +134,7 @@ impl<'a, 'tcx, V: CodegenObject> PlaceRef<'tcx, V> { // * no metadata available - just log the case // * known alignment - sized types, `[T]`, `str` or a foreign type // * packed struct - there is no alignment padding - match field.ty.kind { + match field.ty.kind() { _ if self.llextra.is_none() => { debug!( "unsized field `{}`, of `{:?}` has no metadata for adjustment", diff --git a/src/librustc_codegen_ssa/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs similarity index 97% rename from src/librustc_codegen_ssa/mir/rvalue.rs rename to compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 71f924df11..7ce110dcbf 100644 --- a/src/librustc_codegen_ssa/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -98,7 +98,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } // Use llvm.memset.p0i8.* to initialize byte arrays - let v = base::from_immediate(&mut bx, v); + let v = bx.from_immediate(v); if bx.cx().val_ty(v) == bx.cx().type_i8() { bx.memset(start, v, size, dest.align, MemFlags::empty()); return bx; @@ -185,7 +185,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { let val = match *kind { mir::CastKind::Pointer(PointerCast::ReifyFnPointer) => { - match operand.layout.ty.kind { + match *operand.layout.ty.kind() { ty::FnDef(def_id, substs) => { if bx.cx().tcx().has_attr(def_id, sym::rustc_args_required_const) { bug!("reifying a fn ptr that requires const arguments"); @@ -204,7 +204,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::CastKind::Pointer(PointerCast::ClosureFnPointer(_)) => { - match operand.layout.ty.kind { + match *operand.layout.ty.kind() { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( bx.cx().tcx(), @@ -327,13 +327,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { if er.end != er.start && scalar.valid_range.end() > scalar.valid_range.start() { - // We want `table[e as usize]` to not + // We want `table[e as usize ± k]` to not // have bound checks, and this is the most - // convenient place to put the `assume`. - let ll_t_in_const = + // convenient place to put the `assume`s. + if *scalar.valid_range.start() > 0 { + let enum_value_lower_bound = bx + .cx() + .const_uint_big(ll_t_in, *scalar.valid_range.start()); + let cmp_start = bx.icmp( + IntPredicate::IntUGE, + llval, + enum_value_lower_bound, + ); + bx.assume(cmp_start); + } + + let enum_value_upper_bound = bx.cx().const_uint_big(ll_t_in, *scalar.valid_range.end()); - let cmp = bx.icmp(IntPredicate::IntULE, llval, ll_t_in_const); - bx.assume(cmp); + let cmp_end = bx.icmp( + IntPredicate::IntULE, + llval, + enum_value_upper_bound, + ); + bx.assume(cmp_end); } } } @@ -548,7 +564,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { // because codegen_place() panics if Local is operand. if let Some(index) = place.as_local() { if let LocalRef::Operand(Some(op)) = self.locals[index] { - if let ty::Array(_, n) = op.layout.ty.kind { + if let ty::Array(_, n) = op.layout.ty.kind() { let n = n.eval_usize(bx.cx().tcx(), ty::ParamEnv::reveal_all()); return bx.cx().const_usize(n); } diff --git a/src/librustc_codegen_ssa/mir/statement.rs b/compiler/rustc_codegen_ssa/src/mir/statement.rs similarity index 100% rename from src/librustc_codegen_ssa/mir/statement.rs rename to compiler/rustc_codegen_ssa/src/mir/statement.rs diff --git a/src/librustc_codegen_ssa/mono_item.rs b/compiler/rustc_codegen_ssa/src/mono_item.rs similarity index 94% rename from src/librustc_codegen_ssa/mono_item.rs rename to compiler/rustc_codegen_ssa/src/mono_item.rs index fc65149937..607b545967 100644 --- a/src/librustc_codegen_ssa/mono_item.rs +++ b/compiler/rustc_codegen_ssa/src/mono_item.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { fn define>(&self, cx: &'a Bx::CodegenCx) { debug!( "BEGIN IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); @@ -45,7 +45,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { debug!( "END IMPLEMENTING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); @@ -59,7 +59,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { ) { debug!( "BEGIN PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); @@ -80,7 +80,7 @@ impl<'a, 'tcx: 'a> MonoItemExt<'a, 'tcx> for MonoItem<'tcx> { debug!( "END PREDEFINING '{} ({})' in cgu {}", - self.to_string(cx.tcx(), true), + self, self.to_raw_string(), cx.codegen_unit().name() ); diff --git a/src/librustc_codegen_ssa/traits/abi.rs b/compiler/rustc_codegen_ssa/src/traits/abi.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/abi.rs rename to compiler/rustc_codegen_ssa/src/traits/abi.rs diff --git a/src/librustc_codegen_ssa/traits/asm.rs b/compiler/rustc_codegen_ssa/src/traits/asm.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/asm.rs rename to compiler/rustc_codegen_ssa/src/traits/asm.rs diff --git a/src/librustc_codegen_ssa/traits/backend.rs b/compiler/rustc_codegen_ssa/src/traits/backend.rs similarity index 92% rename from src/librustc_codegen_ssa/traits/backend.rs rename to compiler/rustc_codegen_ssa/src/traits/backend.rs index 3522ea0115..90520f77e3 100644 --- a/src/librustc_codegen_ssa/traits/backend.rs +++ b/compiler/rustc_codegen_ssa/src/traits/backend.rs @@ -15,6 +15,7 @@ use rustc_session::{ }; use rustc_span::symbol::Symbol; use rustc_target::abi::LayoutOf; +use rustc_target::spec::Target; pub use rustc_data_structures::sync::MetadataRef; @@ -54,6 +55,12 @@ pub trait CodegenBackend { fn print_passes(&self) {} fn print_version(&self) {} + /// If this plugin provides additional builtin targets, provide the one enabled by the options here. + /// Be careful: this is called *before* init() is called. + fn target_override(&self, _opts: &config::Options) -> Option { + None + } + fn metadata_loader(&self) -> Box; fn provide(&self, _providers: &mut Providers); fn provide_extern(&self, _providers: &mut Providers); diff --git a/src/librustc_codegen_ssa/traits/builder.rs b/compiler/rustc_codegen_ssa/src/traits/builder.rs similarity index 95% rename from src/librustc_codegen_ssa/traits/builder.rs rename to compiler/rustc_codegen_ssa/src/traits/builder.rs index 5ffc83c5f9..b35b0f2420 100644 --- a/src/librustc_codegen_ssa/traits/builder.rs +++ b/compiler/rustc_codegen_ssa/src/traits/builder.rs @@ -13,12 +13,11 @@ use crate::mir::operand::OperandRef; use crate::mir::place::PlaceRef; use crate::MemFlags; -use rustc_middle::ty::layout::HasParamEnv; +use rustc_middle::ty::layout::{HasParamEnv, TyAndLayout}; use rustc_middle::ty::Ty; -use rustc_target::abi::{Align, Size}; +use rustc_target::abi::{Abi, Align, Scalar, Size}; use rustc_target::spec::HasTargetSpec; -use std::iter::TrustedLen; use std::ops::Range; #[derive(Copy, Clone)] @@ -60,7 +59,7 @@ pub trait BuilderMethods<'a, 'tcx>: &mut self, v: Self::Value, else_llbb: Self::BasicBlock, - cases: impl ExactSizeIterator + TrustedLen, + cases: impl ExactSizeIterator, ); fn invoke( &mut self, @@ -115,6 +114,16 @@ pub trait BuilderMethods<'a, 'tcx>: rhs: Self::Value, ) -> (Self::Value, Self::Value); + 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 { + self.to_immediate_scalar(val, scalar) + } else { + val + } + } + 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; fn array_alloca(&mut self, ty: Self::Type, len: Self::Value, align: Align) -> Self::Value; diff --git a/src/librustc_codegen_ssa/traits/consts.rs b/compiler/rustc_codegen_ssa/src/traits/consts.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/consts.rs rename to compiler/rustc_codegen_ssa/src/traits/consts.rs diff --git a/src/librustc_codegen_ssa/traits/coverageinfo.rs b/compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/coverageinfo.rs rename to compiler/rustc_codegen_ssa/src/traits/coverageinfo.rs diff --git a/src/librustc_codegen_ssa/traits/debuginfo.rs b/compiler/rustc_codegen_ssa/src/traits/debuginfo.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/debuginfo.rs rename to compiler/rustc_codegen_ssa/src/traits/debuginfo.rs diff --git a/compiler/rustc_codegen_ssa/src/traits/declare.rs b/compiler/rustc_codegen_ssa/src/traits/declare.rs new file mode 100644 index 0000000000..655afcd17f --- /dev/null +++ b/compiler/rustc_codegen_ssa/src/traits/declare.rs @@ -0,0 +1,21 @@ +use super::BackendTypes; +use rustc_hir::def_id::DefId; +use rustc_middle::mir::mono::{Linkage, Visibility}; +use rustc_middle::ty::Instance; + +pub trait PreDefineMethods<'tcx>: BackendTypes { + fn predefine_static( + &self, + def_id: DefId, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ); + fn predefine_fn( + &self, + instance: Instance<'tcx>, + linkage: Linkage, + visibility: Visibility, + symbol_name: &str, + ); +} diff --git a/src/librustc_codegen_ssa/traits/intrinsic.rs b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs similarity index 80% rename from src/librustc_codegen_ssa/traits/intrinsic.rs rename to compiler/rustc_codegen_ssa/src/traits/intrinsic.rs index 9d48e233de..ccd294d92b 100644 --- a/src/librustc_codegen_ssa/traits/intrinsic.rs +++ b/compiler/rustc_codegen_ssa/src/traits/intrinsic.rs @@ -5,9 +5,9 @@ use rustc_span::Span; use rustc_target::abi::call::FnAbi; pub trait IntrinsicCallMethods<'tcx>: BackendTypes { - /// Remember to add all intrinsics here, in librustc_typeck/check/mod.rs, - /// and in libcore/intrinsics.rs; if you need access to any llvm intrinsics, - /// add them to librustc_codegen_llvm/context.rs + /// Remember to add all intrinsics here, in `compiler/rustc_typeck/src/check/mod.rs`, + /// and in `library/core/src/intrinsics.rs`; if you need access to any LLVM intrinsics, + /// add them to `compiler/rustc_codegen_llvm/src/context.rs`. fn codegen_intrinsic_call( &mut self, instance: ty::Instance<'tcx>, diff --git a/src/librustc_codegen_ssa/traits/misc.rs b/compiler/rustc_codegen_ssa/src/traits/misc.rs similarity index 82% rename from src/librustc_codegen_ssa/traits/misc.rs rename to compiler/rustc_codegen_ssa/src/traits/misc.rs index fc57a9a80b..6fff64bfcb 100644 --- a/src/librustc_codegen_ssa/traits/misc.rs +++ b/compiler/rustc_codegen_ssa/src/traits/misc.rs @@ -19,4 +19,6 @@ pub trait MiscMethods<'tcx>: BackendTypes { fn set_frame_pointer_elimination(&self, llfn: Self::Function); fn apply_target_cpu_attr(&self, llfn: Self::Function); fn create_used_variable(&self); + /// Declares the extern "C" main function for the entry point. Returns None if the symbol already exists. + fn declare_c_main(&self, fn_type: Self::Type) -> Option; } diff --git a/src/librustc_codegen_ssa/traits/mod.rs b/compiler/rustc_codegen_ssa/src/traits/mod.rs similarity index 96% rename from src/librustc_codegen_ssa/traits/mod.rs rename to compiler/rustc_codegen_ssa/src/traits/mod.rs index 0ac519dd0b..698ef6083e 100644 --- a/src/librustc_codegen_ssa/traits/mod.rs +++ b/compiler/rustc_codegen_ssa/src/traits/mod.rs @@ -35,7 +35,7 @@ pub use self::builder::{BuilderMethods, OverflowOp}; pub use self::consts::ConstMethods; pub use self::coverageinfo::{CoverageInfoBuilderMethods, CoverageInfoMethods}; pub use self::debuginfo::{DebugInfoBuilderMethods, DebugInfoMethods}; -pub use self::declare::{DeclareMethods, PreDefineMethods}; +pub use self::declare::PreDefineMethods; pub use self::intrinsic::IntrinsicCallMethods; pub use self::misc::MiscMethods; pub use self::statics::{StaticBuilderMethods, StaticMethods}; @@ -60,7 +60,6 @@ pub trait CodegenMethods<'tcx>: + StaticMethods + CoverageInfoMethods + DebugInfoMethods<'tcx> - + DeclareMethods<'tcx> + AsmMethods + PreDefineMethods<'tcx> + HasParamEnv<'tcx> @@ -77,7 +76,6 @@ impl<'tcx, T> CodegenMethods<'tcx> for T where + StaticMethods + CoverageInfoMethods + DebugInfoMethods<'tcx> - + DeclareMethods<'tcx> + AsmMethods + PreDefineMethods<'tcx> + HasParamEnv<'tcx> diff --git a/src/librustc_codegen_ssa/traits/statics.rs b/compiler/rustc_codegen_ssa/src/traits/statics.rs similarity index 100% rename from src/librustc_codegen_ssa/traits/statics.rs rename to compiler/rustc_codegen_ssa/src/traits/statics.rs diff --git a/src/librustc_codegen_ssa/traits/type_.rs b/compiler/rustc_codegen_ssa/src/traits/type_.rs similarity index 99% rename from src/librustc_codegen_ssa/traits/type_.rs rename to compiler/rustc_codegen_ssa/src/traits/type_.rs index 726d948cfd..cec07b977e 100644 --- a/src/librustc_codegen_ssa/traits/type_.rs +++ b/compiler/rustc_codegen_ssa/src/traits/type_.rs @@ -89,7 +89,7 @@ pub trait DerivedTypeMethods<'tcx>: BaseTypeMethods<'tcx> + MiscMethods<'tcx> { } let tail = self.tcx().struct_tail_erasing_lifetimes(ty, param_env); - match tail.kind { + match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, _ => bug!("unexpected unsized tail: {:?}", tail), diff --git a/src/librustc_codegen_ssa/traits/write.rs b/compiler/rustc_codegen_ssa/src/traits/write.rs similarity index 90% rename from src/librustc_codegen_ssa/traits/write.rs rename to compiler/rustc_codegen_ssa/src/traits/write.rs index 27d52e9b9c..264e7c2aa9 100644 --- a/src/librustc_codegen_ssa/traits/write.rs +++ b/compiler/rustc_codegen_ssa/src/traits/write.rs @@ -13,6 +13,12 @@ pub trait WriteBackendMethods: 'static + Sized + Clone { type ThinData: Send + Sync; type ThinBuffer: ThinBufferMethods; + /// Merge all modules into main_module and returning it + fn run_link( + cgcx: &CodegenContext, + diag_handler: &Handler, + modules: Vec>, + ) -> Result, FatalError>; /// Performs fat LTO by merging all modules into a single one and returning it /// for further optimization. fn run_fat_lto( diff --git a/src/librustc_data_structures/Cargo.toml b/compiler/rustc_data_structures/Cargo.toml similarity index 69% rename from src/librustc_data_structures/Cargo.toml rename to compiler/rustc_data_structures/Cargo.toml index 5905065120..caaf7c0c3c 100644 --- a/src/librustc_data_structures/Cargo.toml +++ b/compiler/rustc_data_structures/Cargo.toml @@ -5,8 +5,6 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustc_data_structures" -path = "lib.rs" doctest = false [dependencies] @@ -15,11 +13,9 @@ ena = "0.14" indexmap = "1.5.1" tracing = "0.1" jobserver_crate = { version = "0.1.13", package = "jobserver" } -lazy_static = "1" -once_cell = { version = "1", features = ["parking_lot"] } -rustc_serialize = { path = "../librustc_serialize" } -rustc_macros = { path = "../librustc_macros" } -rustc_graphviz = { path = "../librustc_graphviz" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_macros = { path = "../rustc_macros" } +rustc_graphviz = { path = "../rustc_graphviz" } cfg-if = "0.1.2" crossbeam-utils = { version = "0.7", features = ["nightly"] } stable_deref_trait = "1.0.0" @@ -27,15 +23,15 @@ rayon = { version = "0.3.0", package = "rustc-rayon" } rayon-core = { version = "0.3.0", package = "rustc-rayon-core" } rustc-hash = "1.1.0" smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_index = { path = "../librustc_index", package = "rustc_index" } +rustc_index = { path = "../rustc_index", package = "rustc_index" } bitflags = "1.2.1" measureme = "0.7.1" libc = "0.2" -stacker = "0.1.11" +stacker = "0.1.12" tempfile = "3.0.5" [dependencies.parking_lot] -version = "0.10" +version = "0.11" features = ["nightly"] [target.'cfg(windows)'.dependencies] diff --git a/src/librustc_data_structures/atomic_ref.rs b/compiler/rustc_data_structures/src/atomic_ref.rs similarity index 100% rename from src/librustc_data_structures/atomic_ref.rs rename to compiler/rustc_data_structures/src/atomic_ref.rs diff --git a/src/librustc_data_structures/base_n.rs b/compiler/rustc_data_structures/src/base_n.rs similarity index 100% rename from src/librustc_data_structures/base_n.rs rename to compiler/rustc_data_structures/src/base_n.rs diff --git a/src/librustc_data_structures/base_n/tests.rs b/compiler/rustc_data_structures/src/base_n/tests.rs similarity index 100% rename from src/librustc_data_structures/base_n/tests.rs rename to compiler/rustc_data_structures/src/base_n/tests.rs diff --git a/src/librustc_data_structures/binary_search_util/mod.rs b/compiler/rustc_data_structures/src/binary_search_util/mod.rs similarity index 100% rename from src/librustc_data_structures/binary_search_util/mod.rs rename to compiler/rustc_data_structures/src/binary_search_util/mod.rs diff --git a/src/librustc_data_structures/binary_search_util/tests.rs b/compiler/rustc_data_structures/src/binary_search_util/tests.rs similarity index 100% rename from src/librustc_data_structures/binary_search_util/tests.rs rename to compiler/rustc_data_structures/src/binary_search_util/tests.rs diff --git a/src/librustc_data_structures/box_region.rs b/compiler/rustc_data_structures/src/box_region.rs similarity index 100% rename from src/librustc_data_structures/box_region.rs rename to compiler/rustc_data_structures/src/box_region.rs diff --git a/src/librustc_data_structures/captures.rs b/compiler/rustc_data_structures/src/captures.rs similarity index 100% rename from src/librustc_data_structures/captures.rs rename to compiler/rustc_data_structures/src/captures.rs diff --git a/src/librustc_data_structures/const_cstr.rs b/compiler/rustc_data_structures/src/const_cstr.rs similarity index 100% rename from src/librustc_data_structures/const_cstr.rs rename to compiler/rustc_data_structures/src/const_cstr.rs diff --git a/src/librustc_data_structures/fingerprint.rs b/compiler/rustc_data_structures/src/fingerprint.rs similarity index 82% rename from src/librustc_data_structures/fingerprint.rs rename to compiler/rustc_data_structures/src/fingerprint.rs index f8d631ce01..aba0bbbac8 100644 --- a/src/librustc_data_structures/fingerprint.rs +++ b/compiler/rustc_data_structures/src/fingerprint.rs @@ -3,9 +3,10 @@ use rustc_serialize::{ opaque::{self, EncodeResult}, Decodable, Encodable, }; +use std::hash::{Hash, Hasher}; use std::mem; -#[derive(Eq, PartialEq, Ord, PartialOrd, Hash, Debug, Clone, Copy)] +#[derive(Eq, PartialEq, Ord, PartialOrd, Debug, Clone, Copy)] pub struct Fingerprint(u64, u64); impl Fingerprint { @@ -76,6 +77,33 @@ impl ::std::fmt::Display for Fingerprint { } } +impl Hash for Fingerprint { + #[inline] + fn hash(&self, state: &mut H) { + state.write_fingerprint(self); + } +} + +trait FingerprintHasher { + fn write_fingerprint(&mut self, fingerprint: &Fingerprint); +} + +impl FingerprintHasher for H { + #[inline] + default fn write_fingerprint(&mut self, fingerprint: &Fingerprint) { + self.write_u64(fingerprint.0); + self.write_u64(fingerprint.1); + } +} + +impl FingerprintHasher for crate::unhash::Unhasher { + #[inline] + fn write_fingerprint(&mut self, fingerprint: &Fingerprint) { + // `Unhasher` only wants a single `u64` + self.write_u64(fingerprint.0); + } +} + impl stable_hasher::StableHasherResult for Fingerprint { #[inline] fn finish(hasher: stable_hasher::StableHasher) -> Self { diff --git a/src/librustc_data_structures/flock.rs b/compiler/rustc_data_structures/src/flock.rs similarity index 100% rename from src/librustc_data_structures/flock.rs rename to compiler/rustc_data_structures/src/flock.rs diff --git a/src/librustc_data_structures/frozen.rs b/compiler/rustc_data_structures/src/frozen.rs similarity index 100% rename from src/librustc_data_structures/frozen.rs rename to compiler/rustc_data_structures/src/frozen.rs diff --git a/src/librustc_data_structures/fx.rs b/compiler/rustc_data_structures/src/fx.rs similarity index 100% rename from src/librustc_data_structures/fx.rs rename to compiler/rustc_data_structures/src/fx.rs diff --git a/src/librustc_data_structures/graph/dominators/mod.rs b/compiler/rustc_data_structures/src/graph/dominators/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/dominators/mod.rs rename to compiler/rustc_data_structures/src/graph/dominators/mod.rs diff --git a/src/librustc_data_structures/graph/dominators/tests.rs b/compiler/rustc_data_structures/src/graph/dominators/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/dominators/tests.rs rename to compiler/rustc_data_structures/src/graph/dominators/tests.rs diff --git a/src/librustc_data_structures/graph/implementation/mod.rs b/compiler/rustc_data_structures/src/graph/implementation/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/implementation/mod.rs rename to compiler/rustc_data_structures/src/graph/implementation/mod.rs diff --git a/src/librustc_data_structures/graph/implementation/tests.rs b/compiler/rustc_data_structures/src/graph/implementation/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/implementation/tests.rs rename to compiler/rustc_data_structures/src/graph/implementation/tests.rs diff --git a/src/librustc_data_structures/graph/iterate/mod.rs b/compiler/rustc_data_structures/src/graph/iterate/mod.rs similarity index 97% rename from src/librustc_data_structures/graph/iterate/mod.rs rename to compiler/rustc_data_structures/src/graph/iterate/mod.rs index 64ff6130dd..bc3d1ce53b 100644 --- a/src/librustc_data_structures/graph/iterate/mod.rs +++ b/compiler/rustc_data_structures/src/graph/iterate/mod.rs @@ -87,11 +87,8 @@ where } /// Allows searches to terminate early with a value. -#[derive(Clone, Copy, Debug)] -pub enum ControlFlow { - Break(T), - Continue, -} +// FIXME (#75744): remove the alias once the generics are in a better order and `C=()`. +pub type ControlFlow = std::ops::ControlFlow<(), T>; /// The status of a node in the depth-first search. /// @@ -260,12 +257,12 @@ where _node: G::Node, _prior_status: Option, ) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Called after all nodes reachable from this one have been examined. fn node_settled(&mut self, _node: G::Node) -> ControlFlow { - ControlFlow::Continue + ControlFlow::CONTINUE } /// Behave as if no edges exist from `source` to `target`. @@ -289,8 +286,8 @@ where prior_status: Option, ) -> ControlFlow { match prior_status { - Some(NodeStatus::Visited) => ControlFlow::Break(()), - _ => ControlFlow::Continue, + Some(NodeStatus::Visited) => ControlFlow::BREAK, + _ => ControlFlow::CONTINUE, } } } diff --git a/src/librustc_data_structures/graph/iterate/tests.rs b/compiler/rustc_data_structures/src/graph/iterate/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/iterate/tests.rs rename to compiler/rustc_data_structures/src/graph/iterate/tests.rs diff --git a/src/librustc_data_structures/graph/mod.rs b/compiler/rustc_data_structures/src/graph/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/mod.rs rename to compiler/rustc_data_structures/src/graph/mod.rs diff --git a/src/librustc_data_structures/graph/reference.rs b/compiler/rustc_data_structures/src/graph/reference.rs similarity index 100% rename from src/librustc_data_structures/graph/reference.rs rename to compiler/rustc_data_structures/src/graph/reference.rs diff --git a/src/librustc_data_structures/graph/scc/mod.rs b/compiler/rustc_data_structures/src/graph/scc/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/scc/mod.rs rename to compiler/rustc_data_structures/src/graph/scc/mod.rs diff --git a/src/librustc_data_structures/graph/scc/tests.rs b/compiler/rustc_data_structures/src/graph/scc/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/scc/tests.rs rename to compiler/rustc_data_structures/src/graph/scc/tests.rs diff --git a/src/librustc_data_structures/graph/tests.rs b/compiler/rustc_data_structures/src/graph/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/tests.rs rename to compiler/rustc_data_structures/src/graph/tests.rs diff --git a/src/librustc_data_structures/graph/vec_graph/mod.rs b/compiler/rustc_data_structures/src/graph/vec_graph/mod.rs similarity index 100% rename from src/librustc_data_structures/graph/vec_graph/mod.rs rename to compiler/rustc_data_structures/src/graph/vec_graph/mod.rs diff --git a/src/librustc_data_structures/graph/vec_graph/tests.rs b/compiler/rustc_data_structures/src/graph/vec_graph/tests.rs similarity index 100% rename from src/librustc_data_structures/graph/vec_graph/tests.rs rename to compiler/rustc_data_structures/src/graph/vec_graph/tests.rs diff --git a/compiler/rustc_data_structures/src/jobserver.rs b/compiler/rustc_data_structures/src/jobserver.rs new file mode 100644 index 0000000000..41605afb44 --- /dev/null +++ b/compiler/rustc_data_structures/src/jobserver.rs @@ -0,0 +1,40 @@ +pub use jobserver_crate::Client; +use std::lazy::SyncLazy; + +// We can only call `from_env` once per process + +// Note that this is unsafe because it may misinterpret file descriptors +// on Unix as jobserver file descriptors. We hopefully execute this near +// the beginning of the process though to ensure we don't get false +// positives, or in other words we try to execute this before we open +// any file descriptors ourselves. +// +// Pick a "reasonable maximum" if we don't otherwise have +// a jobserver in our environment, capping out at 32 so we +// don't take everything down by hogging the process run queue. +// The fixed number is used to have deterministic compilation +// across machines. +// +// Also note that we stick this in a global because there could be +// multiple rustc instances in this process, and the jobserver is +// per-process. +static GLOBAL_CLIENT: SyncLazy = SyncLazy::new(|| unsafe { + Client::from_env().unwrap_or_else(|| { + let client = Client::new(32).expect("failed to create jobserver"); + // Acquire a token for the main thread which we can release later + client.acquire_raw().ok(); + client + }) +}); + +pub fn client() -> Client { + GLOBAL_CLIENT.clone() +} + +pub fn acquire_thread() { + GLOBAL_CLIENT.acquire_raw().ok(); +} + +pub fn release_thread() { + GLOBAL_CLIENT.release_raw().ok(); +} diff --git a/src/librustc_data_structures/lib.rs b/compiler/rustc_data_structures/src/lib.rs similarity index 91% rename from src/librustc_data_structures/lib.rs rename to compiler/rustc_data_structures/src/lib.rs index cd25ba2ac6..90b0f25475 100644 --- a/src/librustc_data_structures/lib.rs +++ b/compiler/rustc_data_structures/src/lib.rs @@ -6,13 +6,14 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![allow(incomplete_features)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] +#![feature(control_flow_enum)] #![feature(in_band_lifetimes)] #![feature(unboxed_closures)] -#![feature(generators)] #![feature(generator_trait)] #![feature(fn_traits)] +#![feature(int_bits_const)] #![feature(min_specialization)] #![feature(optin_builtin_traits)] #![feature(nll)] @@ -25,7 +26,8 @@ #![feature(thread_id_value)] #![feature(extend_one)] #![feature(const_panic)] -#![feature(const_generics)] +#![feature(min_const_generics)] +#![feature(once_cell)] #![allow(rustc::default_hash_types)] #[macro_use] @@ -99,8 +101,10 @@ pub mod work_queue; pub use atomic_ref::AtomicRef; pub mod frozen; pub mod mini_map; +pub mod mini_set; pub mod tagged_ptr; pub mod temp_dir; +pub mod unhash; pub use ena::undo_log; pub use ena::unify; diff --git a/src/librustc_data_structures/macros.rs b/compiler/rustc_data_structures/src/macros.rs similarity index 76% rename from src/librustc_data_structures/macros.rs rename to compiler/rustc_data_structures/src/macros.rs index 67fbe3058c..b918ed9458 100644 --- a/src/librustc_data_structures/macros.rs +++ b/compiler/rustc_data_structures/src/macros.rs @@ -1,15 +1,3 @@ -/// A simple static assertion macro. -#[macro_export] -#[allow_internal_unstable(type_ascription)] -macro_rules! static_assert { - ($test:expr) => { - // Use the bool to access an array such that if the bool is false, the access - // is out-of-bounds. - #[allow(dead_code)] - const _: () = [()][!($test: bool) as usize]; - }; -} - /// Type size assertion. The first argument is a type and the second argument is its expected size. #[macro_export] macro_rules! static_assert_size { diff --git a/src/librustc_data_structures/map_in_place.rs b/compiler/rustc_data_structures/src/map_in_place.rs similarity index 100% rename from src/librustc_data_structures/map_in_place.rs rename to compiler/rustc_data_structures/src/map_in_place.rs diff --git a/src/librustc_data_structures/mini_map.rs b/compiler/rustc_data_structures/src/mini_map.rs similarity index 100% rename from src/librustc_data_structures/mini_map.rs rename to compiler/rustc_data_structures/src/mini_map.rs diff --git a/compiler/rustc_data_structures/src/mini_set.rs b/compiler/rustc_data_structures/src/mini_set.rs new file mode 100644 index 0000000000..9d45af723d --- /dev/null +++ b/compiler/rustc_data_structures/src/mini_set.rs @@ -0,0 +1,41 @@ +use crate::fx::FxHashSet; +use arrayvec::ArrayVec; +use std::hash::Hash; +/// Small-storage-optimized implementation of a set. +/// +/// Stores elements in a small array up to a certain length +/// and switches to `HashSet` when that length is exceeded. +pub enum MiniSet { + Array(ArrayVec<[T; 8]>), + Set(FxHashSet), +} + +impl MiniSet { + /// Creates an empty `MiniSet`. + pub fn new() -> Self { + MiniSet::Array(ArrayVec::new()) + } + + /// Adds a value to the set. + /// + /// If the set did not have this value present, true is returned. + /// + /// If the set did have this value present, false is returned. + pub fn insert(&mut self, elem: T) -> bool { + match self { + MiniSet::Array(array) => { + if array.iter().any(|e| *e == elem) { + false + } else { + if let Err(error) = array.try_push(elem) { + let mut set: FxHashSet = array.drain(..).collect(); + set.insert(error.element()); + *self = MiniSet::Set(set); + } + true + } + } + MiniSet::Set(set) => set.insert(elem), + } + } +} diff --git a/src/librustc_data_structures/obligation_forest/graphviz.rs b/compiler/rustc_data_structures/src/obligation_forest/graphviz.rs similarity index 100% rename from src/librustc_data_structures/obligation_forest/graphviz.rs rename to compiler/rustc_data_structures/src/obligation_forest/graphviz.rs diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/compiler/rustc_data_structures/src/obligation_forest/mod.rs similarity index 100% rename from src/librustc_data_structures/obligation_forest/mod.rs rename to compiler/rustc_data_structures/src/obligation_forest/mod.rs diff --git a/src/librustc_data_structures/obligation_forest/tests.rs b/compiler/rustc_data_structures/src/obligation_forest/tests.rs similarity index 100% rename from src/librustc_data_structures/obligation_forest/tests.rs rename to compiler/rustc_data_structures/src/obligation_forest/tests.rs diff --git a/src/librustc_data_structures/owning_ref/LICENSE b/compiler/rustc_data_structures/src/owning_ref/LICENSE similarity index 100% rename from src/librustc_data_structures/owning_ref/LICENSE rename to compiler/rustc_data_structures/src/owning_ref/LICENSE diff --git a/src/librustc_data_structures/owning_ref/mod.rs b/compiler/rustc_data_structures/src/owning_ref/mod.rs similarity index 100% rename from src/librustc_data_structures/owning_ref/mod.rs rename to compiler/rustc_data_structures/src/owning_ref/mod.rs diff --git a/src/librustc_data_structures/owning_ref/tests.rs b/compiler/rustc_data_structures/src/owning_ref/tests.rs similarity index 100% rename from src/librustc_data_structures/owning_ref/tests.rs rename to compiler/rustc_data_structures/src/owning_ref/tests.rs diff --git a/src/librustc_data_structures/profiling.rs b/compiler/rustc_data_structures/src/profiling.rs similarity index 99% rename from src/librustc_data_structures/profiling.rs rename to compiler/rustc_data_structures/src/profiling.rs index 07d16c6483..363879cbb1 100644 --- a/src/librustc_data_structures/profiling.rs +++ b/compiler/rustc_data_structures/src/profiling.rs @@ -600,10 +600,7 @@ pub fn print_time_passes_entry(do_it: bool, what: &str, dur: Duration) { // Hack up our own formatting for the duration to make it easier for scripts // to parse (always use the same number of decimal places and the same unit). pub fn duration_to_secs_str(dur: std::time::Duration) -> String { - const NANOS_PER_SEC: f64 = 1_000_000_000.0; - let secs = dur.as_secs() as f64 + dur.subsec_nanos() as f64 / NANOS_PER_SEC; - - format!("{:.3}", secs) + format!("{:.3}", dur.as_secs_f64()) } // Memory reporting diff --git a/src/librustc_data_structures/ptr_key.rs b/compiler/rustc_data_structures/src/ptr_key.rs similarity index 100% rename from src/librustc_data_structures/ptr_key.rs rename to compiler/rustc_data_structures/src/ptr_key.rs diff --git a/src/librustc_data_structures/sharded.rs b/compiler/rustc_data_structures/src/sharded.rs similarity index 100% rename from src/librustc_data_structures/sharded.rs rename to compiler/rustc_data_structures/src/sharded.rs diff --git a/src/librustc_data_structures/sip128.rs b/compiler/rustc_data_structures/src/sip128.rs similarity index 89% rename from src/librustc_data_structures/sip128.rs rename to compiler/rustc_data_structures/src/sip128.rs index beb28dd072..2c4eff618c 100644 --- a/src/librustc_data_structures/sip128.rs +++ b/compiler/rustc_data_structures/src/sip128.rs @@ -125,15 +125,28 @@ impl SipHasher128 { // A specialized write function for values with size <= 8. // - // The hashing of multi-byte integers depends on endianness. E.g.: + // The input must be zero-extended to 64-bits by the caller. This extension + // isn't hashed, but the implementation requires it for correctness. + // + // This function, given the same integer size and value, has the same effect + // on both little- and big-endian hardware. It operates on values without + // depending on their sequence in memory, so is independent of endianness. + // + // However, we want SipHasher128 to be platform-dependent, in order to be + // consistent with the platform-dependent SipHasher in libstd. In other + // words, we want: + // // - little-endian: `write_u32(0xDDCCBBAA)` == `write([0xAA, 0xBB, 0xCC, 0xDD])` // - big-endian: `write_u32(0xDDCCBBAA)` == `write([0xDD, 0xCC, 0xBB, 0xAA])` // - // This function does the right thing for little-endian hardware. On - // big-endian hardware `x` must be byte-swapped first to give the right - // behaviour. After any byte-swapping, the input must be zero-extended to - // 64-bits. The caller is responsible for the byte-swapping and - // zero-extension. + // Therefore, in order to produce endian-dependent results, SipHasher128's + // `write_xxx` Hasher trait methods byte-swap `x` prior to zero-extending. + // + // If clients of SipHasher128 itself want platform-independent results, they + // *also* must byte-swap integer inputs before invoking the `write_xxx` + // methods on big-endian hardware (that is, two byte-swaps must occur--one + // in the client, and one in SipHasher128). Additionally, they must extend + // `usize` and `isize` types to 64 bits on 32-bit systems. #[inline] fn short_write(&mut self, _x: T, x: u64) { let size = mem::size_of::(); diff --git a/src/librustc_data_structures/sip128/tests.rs b/compiler/rustc_data_structures/src/sip128/tests.rs similarity index 90% rename from src/librustc_data_structures/sip128/tests.rs rename to compiler/rustc_data_structures/src/sip128/tests.rs index 80b7fc7475..2e2274a7b7 100644 --- a/src/librustc_data_structures/sip128/tests.rs +++ b/compiler/rustc_data_structures/src/sip128/tests.rs @@ -1,7 +1,6 @@ use super::*; use std::hash::{Hash, Hasher}; -use std::{mem, slice}; // Hash just the bytes of the slice, without length prefix struct Bytes<'a>(&'a [u8]); @@ -399,20 +398,55 @@ fn test_hash_no_concat_alias() { } #[test] -fn test_write_short_works() { - let test_usize = 0xd0c0b0a0usize; +fn test_short_write_works() { + let test_u8 = 0xFF_u8; + let test_u16 = 0x1122_u16; + let test_u32 = 0x22334455_u32; + let test_u64 = 0x33445566_778899AA_u64; + let test_u128 = 0x11223344_55667788_99AABBCC_DDEEFF77_u128; + let test_usize = 0xD0C0B0A0_usize; + + let test_i8 = -1_i8; + let test_i16 = -2_i16; + let test_i32 = -3_i32; + let test_i64 = -4_i64; + let test_i128 = -5_i128; + let test_isize = -6_isize; + let mut h1 = SipHasher128::new_with_keys(0, 0); - h1.write_usize(test_usize); h1.write(b"bytes"); h1.write(b"string"); - h1.write_u8(0xFFu8); - h1.write_u8(0x01u8); + h1.write_u8(test_u8); + h1.write_u16(test_u16); + h1.write_u32(test_u32); + h1.write_u64(test_u64); + h1.write_u128(test_u128); + h1.write_usize(test_usize); + h1.write_i8(test_i8); + h1.write_i16(test_i16); + h1.write_i32(test_i32); + h1.write_i64(test_i64); + h1.write_i128(test_i128); + h1.write_isize(test_isize); + let mut h2 = SipHasher128::new_with_keys(0, 0); - h2.write(unsafe { - slice::from_raw_parts(&test_usize as *const _ as *const u8, mem::size_of::()) - }); h2.write(b"bytes"); h2.write(b"string"); - h2.write(&[0xFFu8, 0x01u8]); - assert_eq!(h1.finish128(), h2.finish128()); + h2.write(&test_u8.to_ne_bytes()); + h2.write(&test_u16.to_ne_bytes()); + h2.write(&test_u32.to_ne_bytes()); + h2.write(&test_u64.to_ne_bytes()); + h2.write(&test_u128.to_ne_bytes()); + h2.write(&test_usize.to_ne_bytes()); + h2.write(&test_i8.to_ne_bytes()); + h2.write(&test_i16.to_ne_bytes()); + h2.write(&test_i32.to_ne_bytes()); + h2.write(&test_i64.to_ne_bytes()); + h2.write(&test_i128.to_ne_bytes()); + h2.write(&test_isize.to_ne_bytes()); + + let h1_hash = h1.finish128(); + let h2_hash = h2.finish128(); + + assert_eq!(h1_hash, h2_hash); } diff --git a/src/librustc_data_structures/small_c_str.rs b/compiler/rustc_data_structures/src/small_c_str.rs similarity index 100% rename from src/librustc_data_structures/small_c_str.rs rename to compiler/rustc_data_structures/src/small_c_str.rs diff --git a/src/librustc_data_structures/small_c_str/tests.rs b/compiler/rustc_data_structures/src/small_c_str/tests.rs similarity index 100% rename from src/librustc_data_structures/small_c_str/tests.rs rename to compiler/rustc_data_structures/src/small_c_str/tests.rs diff --git a/src/librustc_data_structures/snapshot_map/mod.rs b/compiler/rustc_data_structures/src/snapshot_map/mod.rs similarity index 100% rename from src/librustc_data_structures/snapshot_map/mod.rs rename to compiler/rustc_data_structures/src/snapshot_map/mod.rs diff --git a/src/librustc_data_structures/snapshot_map/tests.rs b/compiler/rustc_data_structures/src/snapshot_map/tests.rs similarity index 100% rename from src/librustc_data_structures/snapshot_map/tests.rs rename to compiler/rustc_data_structures/src/snapshot_map/tests.rs diff --git a/src/librustc_data_structures/sorted_map.rs b/compiler/rustc_data_structures/src/sorted_map.rs similarity index 98% rename from src/librustc_data_structures/sorted_map.rs rename to compiler/rustc_data_structures/src/sorted_map.rs index 856eb73e62..4807380595 100644 --- a/src/librustc_data_structures/sorted_map.rs +++ b/compiler/rustc_data_structures/src/sorted_map.rs @@ -34,7 +34,7 @@ impl SortedMap { /// and that there are no duplicates. #[inline] pub fn from_presorted_elements(elements: Vec<(K, V)>) -> SortedMap { - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); SortedMap { data: elements } } @@ -159,7 +159,7 @@ impl SortedMap { return; } - debug_assert!(elements.windows(2).all(|w| w[0].0 < w[1].0)); + debug_assert!(elements.array_windows().all(|[fst, snd]| fst.0 < snd.0)); let start_index = self.lookup_index_for(&elements[0].0); diff --git a/src/librustc_data_structures/sorted_map/index_map.rs b/compiler/rustc_data_structures/src/sorted_map/index_map.rs similarity index 100% rename from src/librustc_data_structures/sorted_map/index_map.rs rename to compiler/rustc_data_structures/src/sorted_map/index_map.rs diff --git a/src/librustc_data_structures/sorted_map/tests.rs b/compiler/rustc_data_structures/src/sorted_map/tests.rs similarity index 100% rename from src/librustc_data_structures/sorted_map/tests.rs rename to compiler/rustc_data_structures/src/sorted_map/tests.rs diff --git a/src/librustc_data_structures/stable_hasher.rs b/compiler/rustc_data_structures/src/stable_hasher.rs similarity index 98% rename from src/librustc_data_structures/stable_hasher.rs rename to compiler/rustc_data_structures/src/stable_hasher.rs index c1c79b174f..68875b3fbd 100644 --- a/src/librustc_data_structures/stable_hasher.rs +++ b/compiler/rustc_data_structures/src/stable_hasher.rs @@ -5,6 +5,9 @@ use smallvec::SmallVec; use std::hash::{BuildHasher, Hash, Hasher}; use std::mem; +#[cfg(test)] +mod tests; + /// When hashing something that ends up affecting properties like symbol names, /// we want these symbol names to be calculated independently of other factors /// like what architecture you're compiling *from*. @@ -129,7 +132,8 @@ impl Hasher for StableHasher { fn write_isize(&mut self, i: isize) { // Always treat isize as i64 so we get the same results on 32 and 64 bit // platforms. This is important for symbol hashes when cross compiling, - // for example. + // for example. Sign extending here is preferable as it means that the + // same negative number hashes the same on both 32 and 64 bit platforms. self.state.write_i64((i as i64).to_le()); } } diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs new file mode 100644 index 0000000000..cd6ff96a55 --- /dev/null +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -0,0 +1,73 @@ +use super::*; + +// The tests below compare the computed hashes to particular expected values +// in order to test that we produce the same results on different platforms, +// regardless of endianness and `usize` and `isize` size differences (this +// of course assumes we run these tests on platforms that differ in those +// ways). The expected values depend on the hashing algorithm used, so they +// need to be updated whenever StableHasher changes its hashing algorithm. + +#[test] +fn test_hash_integers() { + // Test that integers are handled consistently across platforms. + let test_u8 = 0xAB_u8; + let test_u16 = 0xFFEE_u16; + let test_u32 = 0x445577AA_u32; + let test_u64 = 0x01234567_13243546_u64; + let test_u128 = 0x22114433_66557788_99AACCBB_EEDDFF77_u128; + let test_usize = 0xD0C0B0A0_usize; + + let test_i8 = -100_i8; + let test_i16 = -200_i16; + let test_i32 = -300_i32; + let test_i64 = -400_i64; + let test_i128 = -500_i128; + let test_isize = -600_isize; + + let mut h = StableHasher::new(); + test_u8.hash(&mut h); + test_u16.hash(&mut h); + test_u32.hash(&mut h); + test_u64.hash(&mut h); + test_u128.hash(&mut h); + test_usize.hash(&mut h); + test_i8.hash(&mut h); + test_i16.hash(&mut h); + test_i32.hash(&mut h); + test_i64.hash(&mut h); + test_i128.hash(&mut h); + test_isize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (2736651863462566372, 8121090595289675650); + + assert_eq!(h.finalize(), expected); +} + +#[test] +fn test_hash_usize() { + // Test that usize specifically is handled consistently across platforms. + let test_usize = 0xABCDEF01_usize; + + let mut h = StableHasher::new(); + test_usize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (5798740672699530587, 11186240177685111648); + + assert_eq!(h.finalize(), expected); +} + +#[test] +fn test_hash_isize() { + // Test that isize specifically is handled consistently across platforms. + let test_isize = -7_isize; + + let mut h = StableHasher::new(); + test_isize.hash(&mut h); + + // This depends on the hashing algorithm. See note at top of file. + let expected = (14721296605626097289, 11385941877786388409); + + assert_eq!(h.finalize(), expected); +} diff --git a/src/librustc_data_structures/stable_map.rs b/compiler/rustc_data_structures/src/stable_map.rs similarity index 100% rename from src/librustc_data_structures/stable_map.rs rename to compiler/rustc_data_structures/src/stable_map.rs diff --git a/src/librustc_data_structures/stable_set.rs b/compiler/rustc_data_structures/src/stable_set.rs similarity index 100% rename from src/librustc_data_structures/stable_set.rs rename to compiler/rustc_data_structures/src/stable_set.rs diff --git a/src/librustc_data_structures/stack.rs b/compiler/rustc_data_structures/src/stack.rs similarity index 100% rename from src/librustc_data_structures/stack.rs rename to compiler/rustc_data_structures/src/stack.rs diff --git a/src/librustc_data_structures/svh.rs b/compiler/rustc_data_structures/src/svh.rs similarity index 100% rename from src/librustc_data_structures/svh.rs rename to compiler/rustc_data_structures/src/svh.rs diff --git a/src/librustc_data_structures/sync.rs b/compiler/rustc_data_structures/src/sync.rs similarity index 99% rename from src/librustc_data_structures/sync.rs rename to compiler/rustc_data_structures/src/sync.rs index 53d831749c..d22f3adfb0 100644 --- a/src/librustc_data_structures/sync.rs +++ b/compiler/rustc_data_structures/src/sync.rs @@ -229,7 +229,7 @@ cfg_if! { pub use std::cell::RefMut as LockGuard; pub use std::cell::RefMut as MappedLockGuard; - pub use once_cell::unsync::OnceCell; + pub use std::lazy::OnceCell; use std::cell::RefCell as InnerRwLock; use std::cell::RefCell as InnerLock; @@ -314,7 +314,7 @@ cfg_if! { pub use parking_lot::MutexGuard as LockGuard; pub use parking_lot::MappedMutexGuard as MappedLockGuard; - pub use once_cell::sync::OnceCell; + pub use std::lazy::SyncOnceCell as OnceCell; pub use std::sync::atomic::{AtomicBool, AtomicUsize, AtomicU32, AtomicU64}; diff --git a/src/librustc_data_structures/tagged_ptr.rs b/compiler/rustc_data_structures/src/tagged_ptr.rs similarity index 100% rename from src/librustc_data_structures/tagged_ptr.rs rename to compiler/rustc_data_structures/src/tagged_ptr.rs diff --git a/src/librustc_data_structures/tagged_ptr/copy.rs b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs similarity index 98% rename from src/librustc_data_structures/tagged_ptr/copy.rs rename to compiler/rustc_data_structures/src/tagged_ptr/copy.rs index d39d146db3..d63bcdb3c2 100644 --- a/src/librustc_data_structures/tagged_ptr/copy.rs +++ b/compiler/rustc_data_structures/src/tagged_ptr/copy.rs @@ -48,7 +48,7 @@ where P: Pointer, T: Tag, { - const TAG_BIT_SHIFT: usize = (8 * std::mem::size_of::()) - T::BITS; + const TAG_BIT_SHIFT: usize = usize::BITS as usize - T::BITS; const ASSERTION: () = { assert!(T::BITS <= P::BITS); // Used for the transmute_copy's below diff --git a/src/librustc_data_structures/tagged_ptr/drop.rs b/compiler/rustc_data_structures/src/tagged_ptr/drop.rs similarity index 100% rename from src/librustc_data_structures/tagged_ptr/drop.rs rename to compiler/rustc_data_structures/src/tagged_ptr/drop.rs diff --git a/src/librustc_data_structures/temp_dir.rs b/compiler/rustc_data_structures/src/temp_dir.rs similarity index 92% rename from src/librustc_data_structures/temp_dir.rs rename to compiler/rustc_data_structures/src/temp_dir.rs index 0d9b3e3ca2..a780d2386a 100644 --- a/src/librustc_data_structures/temp_dir.rs +++ b/compiler/rustc_data_structures/src/temp_dir.rs @@ -12,7 +12,7 @@ pub struct MaybeTempDir { impl Drop for MaybeTempDir { fn drop(&mut self) { - // Safety: We are in the destructor, and no further access will + // SAFETY: We are in the destructor, and no further access will // occur. let dir = unsafe { ManuallyDrop::take(&mut self.dir) }; if self.keep { diff --git a/src/librustc_data_structures/thin_vec.rs b/compiler/rustc_data_structures/src/thin_vec.rs similarity index 100% rename from src/librustc_data_structures/thin_vec.rs rename to compiler/rustc_data_structures/src/thin_vec.rs diff --git a/src/librustc_data_structures/tiny_list.rs b/compiler/rustc_data_structures/src/tiny_list.rs similarity index 100% rename from src/librustc_data_structures/tiny_list.rs rename to compiler/rustc_data_structures/src/tiny_list.rs diff --git a/src/librustc_data_structures/tiny_list/tests.rs b/compiler/rustc_data_structures/src/tiny_list/tests.rs similarity index 100% rename from src/librustc_data_structures/tiny_list/tests.rs rename to compiler/rustc_data_structures/src/tiny_list/tests.rs diff --git a/src/librustc_data_structures/transitive_relation.rs b/compiler/rustc_data_structures/src/transitive_relation.rs similarity index 100% rename from src/librustc_data_structures/transitive_relation.rs rename to compiler/rustc_data_structures/src/transitive_relation.rs diff --git a/src/librustc_data_structures/transitive_relation/tests.rs b/compiler/rustc_data_structures/src/transitive_relation/tests.rs similarity index 100% rename from src/librustc_data_structures/transitive_relation/tests.rs rename to compiler/rustc_data_structures/src/transitive_relation/tests.rs diff --git a/compiler/rustc_data_structures/src/unhash.rs b/compiler/rustc_data_structures/src/unhash.rs new file mode 100644 index 0000000000..48e21a9dab --- /dev/null +++ b/compiler/rustc_data_structures/src/unhash.rs @@ -0,0 +1,29 @@ +use std::collections::{HashMap, HashSet}; +use std::hash::{BuildHasherDefault, Hasher}; + +pub type UnhashMap = HashMap>; +pub type UnhashSet = HashSet>; + +/// This no-op hasher expects only a single `write_u64` call. It's intended for +/// map keys that already have hash-like quality, like `Fingerprint`. +#[derive(Default)] +pub struct Unhasher { + value: u64, +} + +impl Hasher for Unhasher { + #[inline] + fn finish(&self) -> u64 { + self.value + } + + fn write(&mut self, _bytes: &[u8]) { + unimplemented!("use write_u64"); + } + + #[inline] + fn write_u64(&mut self, value: u64) { + debug_assert_eq!(0, self.value, "Unhasher doesn't mix values!"); + self.value = value; + } +} diff --git a/src/librustc_data_structures/vec_linked_list.rs b/compiler/rustc_data_structures/src/vec_linked_list.rs similarity index 100% rename from src/librustc_data_structures/vec_linked_list.rs rename to compiler/rustc_data_structures/src/vec_linked_list.rs diff --git a/src/librustc_data_structures/work_queue.rs b/compiler/rustc_data_structures/src/work_queue.rs similarity index 100% rename from src/librustc_data_structures/work_queue.rs rename to compiler/rustc_data_structures/src/work_queue.rs diff --git a/compiler/rustc_driver/Cargo.toml b/compiler/rustc_driver/Cargo.toml new file mode 100644 index 0000000000..adfce1008e --- /dev/null +++ b/compiler/rustc_driver/Cargo.toml @@ -0,0 +1,41 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_driver" +version = "0.0.0" +edition = "2018" + +[lib] +crate-type = ["dylib"] + +[dependencies] +libc = "0.2" +tracing = { version = "0.1.18" } +tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } +rustc_middle = { path = "../rustc_middle" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_target = { path = "../rustc_target" } +rustc_lint = { path = "../rustc_lint" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_mir = { path = "../rustc_mir" } +rustc_parse = { path = "../rustc_parse" } +rustc_plugin_impl = { path = "../rustc_plugin_impl" } +rustc_save_analysis = { path = "../rustc_save_analysis" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_session = { path = "../rustc_session" } +rustc_error_codes = { path = "../rustc_error_codes" } +rustc_interface = { path = "../rustc_interface" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] } + +[features] +llvm = ['rustc_interface/llvm'] +max_level_info = ['tracing/max_level_info'] diff --git a/src/librustc_driver/README.md b/compiler/rustc_driver/README.md similarity index 100% rename from src/librustc_driver/README.md rename to compiler/rustc_driver/README.md diff --git a/src/librustc_driver/args.rs b/compiler/rustc_driver/src/args.rs similarity index 94% rename from src/librustc_driver/args.rs rename to compiler/rustc_driver/src/args.rs index 5686819c61..4f2febf04b 100644 --- a/src/librustc_driver/args.rs +++ b/compiler/rustc_driver/src/args.rs @@ -4,8 +4,7 @@ use std::fs; use std::io; pub fn arg_expand(arg: String) -> Result, Error> { - if arg.starts_with('@') { - let path = &arg[1..]; + if let Some(path) = arg.strip_prefix('@') { let file = match fs::read_to_string(path) { Ok(file) => file, Err(ref err) if err.kind() == io::ErrorKind::InvalidData => { diff --git a/src/librustc_driver/lib.rs b/compiler/rustc_driver/src/lib.rs similarity index 97% rename from src/librustc_driver/lib.rs rename to compiler/rustc_driver/src/lib.rs index 09f5b22cc6..544efc124e 100644 --- a/src/librustc_driver/lib.rs +++ b/compiler/rustc_driver/src/lib.rs @@ -4,14 +4,13 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] +#![feature(once_cell)] #![recursion_limit = "256"] #[macro_use] extern crate tracing; -#[macro_use] -extern crate lazy_static; pub extern crate rustc_plugin_impl as plugin; @@ -33,7 +32,7 @@ use rustc_save_analysis as save; use rustc_save_analysis::DumpHandler; use rustc_serialize::json::{self, ToJson}; use rustc_session::config::nightly_options; -use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest}; +use rustc_session::config::{ErrorOutputType, Input, OutputType, PrintRequest, TrimmedDefPaths}; use rustc_session::getopts; use rustc_session::lint::{Lint, LintId}; use rustc_session::{config, DiagnosticOutput, Session}; @@ -48,6 +47,7 @@ use std::env; use std::ffi::OsString; use std::fs; use std::io::{self, Read, Write}; +use std::lazy::SyncLazy; use std::mem; use std::panic::{self, catch_unwind}; use std::path::PathBuf; @@ -126,6 +126,7 @@ impl Callbacks for TimePassesCallbacks { // time because it will mess up the --prints output. See #64339. self.time_passes = config.opts.prints.is_empty() && (config.opts.debugging_opts.time_passes || config.opts.debugging_opts.time); + config.opts.trimmed_def_paths = TrimmedDefPaths::GoodPath; } } @@ -140,6 +141,9 @@ pub fn run_compiler( callbacks: &mut (dyn Callbacks + Send), file_loader: Option>, emitter: Option>, + make_codegen_backend: Option< + Box Box + Send>, + >, ) -> interface::Result<()> { let mut args = Vec::new(); for arg in at_args { @@ -161,6 +165,11 @@ pub fn run_compiler( let sopts = config::build_session_options(&matches); let cfg = interface::parse_cfgspecs(matches.opt_strs("cfg")); + // We wrap `make_codegen_backend` in another `Option` such that `dummy_config` can take + // ownership of it when necessary, while also allowing the non-dummy config to take ownership + // when `dummy_config` is not used. + let mut make_codegen_backend = Some(make_codegen_backend); + let mut dummy_config = |sopts, cfg, diagnostic_output| { let mut config = interface::Config { opts: sopts, @@ -176,6 +185,7 @@ pub fn run_compiler( lint_caps: Default::default(), register_lints: None, override_queries: None, + make_codegen_backend: make_codegen_backend.take().unwrap(), registry: diagnostics_registry(), }; callbacks.config(&mut config); @@ -252,6 +262,7 @@ pub fn run_compiler( lint_caps: Default::default(), register_lints: None, override_queries: None, + make_codegen_backend: make_codegen_backend.unwrap(), registry: diagnostics_registry(), }; @@ -1141,13 +1152,12 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { } } -lazy_static! { - static ref DEFAULT_HOOK: Box) + Sync + Send + 'static> = { +static DEFAULT_HOOK: SyncLazy) + Sync + Send + 'static>> = + SyncLazy::new(|| { let hook = panic::take_hook(); panic::set_hook(Box::new(|info| report_ice(info, BUG_REPORT_URL))); hook - }; -} + }); /// Prints the ICE message, including backtrace and query stack. /// @@ -1222,7 +1232,7 @@ pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str) { /// /// A custom rustc driver can skip calling this to set up a custom ICE hook. pub fn install_ice_hook() { - lazy_static::initialize(&DEFAULT_HOOK); + SyncLazy::force(&DEFAULT_HOOK); } /// This allows tools to enable rust logging without having to magically match rustc's @@ -1265,7 +1275,7 @@ pub fn main() -> ! { }) }) .collect::>(); - run_compiler(&args, &mut callbacks, None, None) + run_compiler(&args, &mut callbacks, None, None, None) }); // The extra `\t` is necessary to align this label with the others. print_time_passes_entry(callbacks.time_passes, "\ttotal", start.elapsed()); diff --git a/src/librustc_driver/pretty.rs b/compiler/rustc_driver/src/pretty.rs similarity index 100% rename from src/librustc_driver/pretty.rs rename to compiler/rustc_driver/src/pretty.rs diff --git a/src/librustc_error_codes/Cargo.toml b/compiler/rustc_error_codes/Cargo.toml similarity index 69% rename from src/librustc_error_codes/Cargo.toml rename to compiler/rustc_error_codes/Cargo.toml index 5def867ff1..b4c9cd9456 100644 --- a/src/librustc_error_codes/Cargo.toml +++ b/compiler/rustc_error_codes/Cargo.toml @@ -3,7 +3,3 @@ authors = ["The Rust Project Developers"] name = "rustc_error_codes" version = "0.0.0" edition = "2018" - -[lib] -name = "rustc_error_codes" -path = "lib.rs" diff --git a/src/librustc_error_codes/error_codes.rs b/compiler/rustc_error_codes/src/error_codes.rs similarity index 98% rename from src/librustc_error_codes/error_codes.rs rename to compiler/rustc_error_codes/src/error_codes.rs index 4e5e77f80c..81f65ac869 100644 --- a/src/librustc_error_codes/error_codes.rs +++ b/compiler/rustc_error_codes/src/error_codes.rs @@ -18,7 +18,6 @@ E0010: include_str!("./error_codes/E0010.md"), E0013: include_str!("./error_codes/E0013.md"), E0014: include_str!("./error_codes/E0014.md"), E0015: include_str!("./error_codes/E0015.md"), -E0019: include_str!("./error_codes/E0019.md"), E0023: include_str!("./error_codes/E0023.md"), E0025: include_str!("./error_codes/E0025.md"), E0026: include_str!("./error_codes/E0026.md"), @@ -440,6 +439,8 @@ E0751: include_str!("./error_codes/E0751.md"), E0752: include_str!("./error_codes/E0752.md"), E0753: include_str!("./error_codes/E0753.md"), E0754: include_str!("./error_codes/E0754.md"), +E0755: include_str!("./error_codes/E0755.md"), +E0756: include_str!("./error_codes/E0756.md"), E0758: include_str!("./error_codes/E0758.md"), E0759: include_str!("./error_codes/E0759.md"), E0760: include_str!("./error_codes/E0760.md"), @@ -454,9 +455,14 @@ E0768: include_str!("./error_codes/E0768.md"), E0769: include_str!("./error_codes/E0769.md"), E0770: include_str!("./error_codes/E0770.md"), E0771: include_str!("./error_codes/E0771.md"), +E0773: include_str!("./error_codes/E0773.md"), +E0774: include_str!("./error_codes/E0774.md"), +E0775: include_str!("./error_codes/E0775.md"), +E0776: include_str!("./error_codes/E0776.md"), ; // E0006, // merged with E0005 // E0008, // cannot bind by-move into a pattern guard +// E0019, merged into E0015 // E0035, merged into E0087/E0089 // E0036, merged into E0087/E0089 // E0068, @@ -630,8 +636,6 @@ E0771: include_str!("./error_codes/E0771.md"), E0722, // Malformed `#[optimize]` attribute E0726, // non-explicit (not `'_`) elided lifetime in unsupported position // E0738, // Removed; errored on `#[track_caller] fn`s in `extern "Rust" { ... }`. - E0755, // `#[ffi_pure]` is only allowed on foreign functions - E0756, // `#[ffi_const]` is only allowed on foreign functions E0757, // `#[ffi_const]` functions cannot be `#[ffi_pure]` E0772, // `'static' obligation coming from `impl dyn Trait {}` or `impl Foo for dyn Bar {}`. } diff --git a/src/librustc_error_codes/error_codes/E0001.md b/compiler/rustc_error_codes/src/error_codes/E0001.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0001.md rename to compiler/rustc_error_codes/src/error_codes/E0001.md diff --git a/src/librustc_error_codes/error_codes/E0002.md b/compiler/rustc_error_codes/src/error_codes/E0002.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0002.md rename to compiler/rustc_error_codes/src/error_codes/E0002.md diff --git a/src/librustc_error_codes/error_codes/E0004.md b/compiler/rustc_error_codes/src/error_codes/E0004.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0004.md rename to compiler/rustc_error_codes/src/error_codes/E0004.md diff --git a/src/librustc_error_codes/error_codes/E0005.md b/compiler/rustc_error_codes/src/error_codes/E0005.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0005.md rename to compiler/rustc_error_codes/src/error_codes/E0005.md diff --git a/src/librustc_error_codes/error_codes/E0007.md b/compiler/rustc_error_codes/src/error_codes/E0007.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0007.md rename to compiler/rustc_error_codes/src/error_codes/E0007.md diff --git a/src/librustc_error_codes/error_codes/E0009.md b/compiler/rustc_error_codes/src/error_codes/E0009.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0009.md rename to compiler/rustc_error_codes/src/error_codes/E0009.md diff --git a/src/librustc_error_codes/error_codes/E0010.md b/compiler/rustc_error_codes/src/error_codes/E0010.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0010.md rename to compiler/rustc_error_codes/src/error_codes/E0010.md diff --git a/src/librustc_error_codes/error_codes/E0013.md b/compiler/rustc_error_codes/src/error_codes/E0013.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0013.md rename to compiler/rustc_error_codes/src/error_codes/E0013.md diff --git a/src/librustc_error_codes/error_codes/E0014.md b/compiler/rustc_error_codes/src/error_codes/E0014.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0014.md rename to compiler/rustc_error_codes/src/error_codes/E0014.md diff --git a/src/librustc_error_codes/error_codes/E0015.md b/compiler/rustc_error_codes/src/error_codes/E0015.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0015.md rename to compiler/rustc_error_codes/src/error_codes/E0015.md diff --git a/src/librustc_error_codes/error_codes/E0023.md b/compiler/rustc_error_codes/src/error_codes/E0023.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0023.md rename to compiler/rustc_error_codes/src/error_codes/E0023.md diff --git a/src/librustc_error_codes/error_codes/E0025.md b/compiler/rustc_error_codes/src/error_codes/E0025.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0025.md rename to compiler/rustc_error_codes/src/error_codes/E0025.md diff --git a/src/librustc_error_codes/error_codes/E0026.md b/compiler/rustc_error_codes/src/error_codes/E0026.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0026.md rename to compiler/rustc_error_codes/src/error_codes/E0026.md diff --git a/src/librustc_error_codes/error_codes/E0027.md b/compiler/rustc_error_codes/src/error_codes/E0027.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0027.md rename to compiler/rustc_error_codes/src/error_codes/E0027.md diff --git a/src/librustc_error_codes/error_codes/E0029.md b/compiler/rustc_error_codes/src/error_codes/E0029.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0029.md rename to compiler/rustc_error_codes/src/error_codes/E0029.md diff --git a/src/librustc_error_codes/error_codes/E0030.md b/compiler/rustc_error_codes/src/error_codes/E0030.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0030.md rename to compiler/rustc_error_codes/src/error_codes/E0030.md diff --git a/src/librustc_error_codes/error_codes/E0033.md b/compiler/rustc_error_codes/src/error_codes/E0033.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0033.md rename to compiler/rustc_error_codes/src/error_codes/E0033.md diff --git a/src/librustc_error_codes/error_codes/E0034.md b/compiler/rustc_error_codes/src/error_codes/E0034.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0034.md rename to compiler/rustc_error_codes/src/error_codes/E0034.md diff --git a/src/librustc_error_codes/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0038.md rename to compiler/rustc_error_codes/src/error_codes/E0038.md diff --git a/src/librustc_error_codes/error_codes/E0040.md b/compiler/rustc_error_codes/src/error_codes/E0040.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0040.md rename to compiler/rustc_error_codes/src/error_codes/E0040.md diff --git a/src/librustc_error_codes/error_codes/E0044.md b/compiler/rustc_error_codes/src/error_codes/E0044.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0044.md rename to compiler/rustc_error_codes/src/error_codes/E0044.md diff --git a/src/librustc_error_codes/error_codes/E0045.md b/compiler/rustc_error_codes/src/error_codes/E0045.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0045.md rename to compiler/rustc_error_codes/src/error_codes/E0045.md diff --git a/src/librustc_error_codes/error_codes/E0046.md b/compiler/rustc_error_codes/src/error_codes/E0046.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0046.md rename to compiler/rustc_error_codes/src/error_codes/E0046.md diff --git a/src/librustc_error_codes/error_codes/E0049.md b/compiler/rustc_error_codes/src/error_codes/E0049.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0049.md rename to compiler/rustc_error_codes/src/error_codes/E0049.md diff --git a/src/librustc_error_codes/error_codes/E0050.md b/compiler/rustc_error_codes/src/error_codes/E0050.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0050.md rename to compiler/rustc_error_codes/src/error_codes/E0050.md diff --git a/src/librustc_error_codes/error_codes/E0053.md b/compiler/rustc_error_codes/src/error_codes/E0053.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0053.md rename to compiler/rustc_error_codes/src/error_codes/E0053.md diff --git a/src/librustc_error_codes/error_codes/E0054.md b/compiler/rustc_error_codes/src/error_codes/E0054.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0054.md rename to compiler/rustc_error_codes/src/error_codes/E0054.md diff --git a/src/librustc_error_codes/error_codes/E0055.md b/compiler/rustc_error_codes/src/error_codes/E0055.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0055.md rename to compiler/rustc_error_codes/src/error_codes/E0055.md diff --git a/src/librustc_error_codes/error_codes/E0057.md b/compiler/rustc_error_codes/src/error_codes/E0057.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0057.md rename to compiler/rustc_error_codes/src/error_codes/E0057.md diff --git a/src/librustc_error_codes/error_codes/E0059.md b/compiler/rustc_error_codes/src/error_codes/E0059.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0059.md rename to compiler/rustc_error_codes/src/error_codes/E0059.md diff --git a/src/librustc_error_codes/error_codes/E0060.md b/compiler/rustc_error_codes/src/error_codes/E0060.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0060.md rename to compiler/rustc_error_codes/src/error_codes/E0060.md diff --git a/src/librustc_error_codes/error_codes/E0061.md b/compiler/rustc_error_codes/src/error_codes/E0061.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0061.md rename to compiler/rustc_error_codes/src/error_codes/E0061.md diff --git a/src/librustc_error_codes/error_codes/E0062.md b/compiler/rustc_error_codes/src/error_codes/E0062.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0062.md rename to compiler/rustc_error_codes/src/error_codes/E0062.md diff --git a/src/librustc_error_codes/error_codes/E0063.md b/compiler/rustc_error_codes/src/error_codes/E0063.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0063.md rename to compiler/rustc_error_codes/src/error_codes/E0063.md diff --git a/src/librustc_error_codes/error_codes/E0067.md b/compiler/rustc_error_codes/src/error_codes/E0067.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0067.md rename to compiler/rustc_error_codes/src/error_codes/E0067.md diff --git a/src/librustc_error_codes/error_codes/E0069.md b/compiler/rustc_error_codes/src/error_codes/E0069.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0069.md rename to compiler/rustc_error_codes/src/error_codes/E0069.md diff --git a/src/librustc_error_codes/error_codes/E0070.md b/compiler/rustc_error_codes/src/error_codes/E0070.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0070.md rename to compiler/rustc_error_codes/src/error_codes/E0070.md diff --git a/src/librustc_error_codes/error_codes/E0071.md b/compiler/rustc_error_codes/src/error_codes/E0071.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0071.md rename to compiler/rustc_error_codes/src/error_codes/E0071.md diff --git a/src/librustc_error_codes/error_codes/E0072.md b/compiler/rustc_error_codes/src/error_codes/E0072.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0072.md rename to compiler/rustc_error_codes/src/error_codes/E0072.md diff --git a/src/librustc_error_codes/error_codes/E0073.md b/compiler/rustc_error_codes/src/error_codes/E0073.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0073.md rename to compiler/rustc_error_codes/src/error_codes/E0073.md diff --git a/src/librustc_error_codes/error_codes/E0074.md b/compiler/rustc_error_codes/src/error_codes/E0074.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0074.md rename to compiler/rustc_error_codes/src/error_codes/E0074.md diff --git a/src/librustc_error_codes/error_codes/E0075.md b/compiler/rustc_error_codes/src/error_codes/E0075.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0075.md rename to compiler/rustc_error_codes/src/error_codes/E0075.md diff --git a/src/librustc_error_codes/error_codes/E0076.md b/compiler/rustc_error_codes/src/error_codes/E0076.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0076.md rename to compiler/rustc_error_codes/src/error_codes/E0076.md diff --git a/src/librustc_error_codes/error_codes/E0077.md b/compiler/rustc_error_codes/src/error_codes/E0077.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0077.md rename to compiler/rustc_error_codes/src/error_codes/E0077.md diff --git a/src/librustc_error_codes/error_codes/E0080.md b/compiler/rustc_error_codes/src/error_codes/E0080.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0080.md rename to compiler/rustc_error_codes/src/error_codes/E0080.md diff --git a/src/librustc_error_codes/error_codes/E0081.md b/compiler/rustc_error_codes/src/error_codes/E0081.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0081.md rename to compiler/rustc_error_codes/src/error_codes/E0081.md diff --git a/src/librustc_error_codes/error_codes/E0084.md b/compiler/rustc_error_codes/src/error_codes/E0084.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0084.md rename to compiler/rustc_error_codes/src/error_codes/E0084.md diff --git a/src/librustc_error_codes/error_codes/E0087.md b/compiler/rustc_error_codes/src/error_codes/E0087.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0087.md rename to compiler/rustc_error_codes/src/error_codes/E0087.md diff --git a/src/librustc_error_codes/error_codes/E0088.md b/compiler/rustc_error_codes/src/error_codes/E0088.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0088.md rename to compiler/rustc_error_codes/src/error_codes/E0088.md diff --git a/src/librustc_error_codes/error_codes/E0089.md b/compiler/rustc_error_codes/src/error_codes/E0089.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0089.md rename to compiler/rustc_error_codes/src/error_codes/E0089.md diff --git a/src/librustc_error_codes/error_codes/E0090.md b/compiler/rustc_error_codes/src/error_codes/E0090.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0090.md rename to compiler/rustc_error_codes/src/error_codes/E0090.md diff --git a/src/librustc_error_codes/error_codes/E0091.md b/compiler/rustc_error_codes/src/error_codes/E0091.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0091.md rename to compiler/rustc_error_codes/src/error_codes/E0091.md diff --git a/src/librustc_error_codes/error_codes/E0092.md b/compiler/rustc_error_codes/src/error_codes/E0092.md similarity index 74% rename from src/librustc_error_codes/error_codes/E0092.md rename to compiler/rustc_error_codes/src/error_codes/E0092.md index e289534bf7..496174b28e 100644 --- a/src/librustc_error_codes/error_codes/E0092.md +++ b/compiler/rustc_error_codes/src/error_codes/E0092.md @@ -12,8 +12,8 @@ extern "rust-intrinsic" { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in -`libcore/intrinsics.rs` in the Rust source code. Example: +functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in +`library/core/src/intrinsics.rs` in the Rust source code. Example: ``` #![feature(intrinsics)] diff --git a/src/librustc_error_codes/error_codes/E0093.md b/compiler/rustc_error_codes/src/error_codes/E0093.md similarity index 77% rename from src/librustc_error_codes/error_codes/E0093.md rename to compiler/rustc_error_codes/src/error_codes/E0093.md index 8e7de1a9d3..6d58e50ec8 100644 --- a/src/librustc_error_codes/error_codes/E0093.md +++ b/compiler/rustc_error_codes/src/error_codes/E0093.md @@ -17,8 +17,8 @@ fn main() { ``` Please check you didn't make a mistake in the function's name. All intrinsic -functions are defined in `librustc_codegen_llvm/intrinsic.rs` and in -`libcore/intrinsics.rs` in the Rust source code. Example: +functions are defined in `compiler/rustc_codegen_llvm/src/intrinsic.rs` and in +`library/core/src/intrinsics.rs` in the Rust source code. Example: ``` #![feature(intrinsics)] diff --git a/src/librustc_error_codes/error_codes/E0094.md b/compiler/rustc_error_codes/src/error_codes/E0094.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0094.md rename to compiler/rustc_error_codes/src/error_codes/E0094.md diff --git a/src/librustc_error_codes/error_codes/E0106.md b/compiler/rustc_error_codes/src/error_codes/E0106.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0106.md rename to compiler/rustc_error_codes/src/error_codes/E0106.md diff --git a/src/librustc_error_codes/error_codes/E0107.md b/compiler/rustc_error_codes/src/error_codes/E0107.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0107.md rename to compiler/rustc_error_codes/src/error_codes/E0107.md diff --git a/src/librustc_error_codes/error_codes/E0109.md b/compiler/rustc_error_codes/src/error_codes/E0109.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0109.md rename to compiler/rustc_error_codes/src/error_codes/E0109.md diff --git a/src/librustc_error_codes/error_codes/E0110.md b/compiler/rustc_error_codes/src/error_codes/E0110.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0110.md rename to compiler/rustc_error_codes/src/error_codes/E0110.md diff --git a/src/librustc_error_codes/error_codes/E0116.md b/compiler/rustc_error_codes/src/error_codes/E0116.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0116.md rename to compiler/rustc_error_codes/src/error_codes/E0116.md diff --git a/src/librustc_error_codes/error_codes/E0117.md b/compiler/rustc_error_codes/src/error_codes/E0117.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0117.md rename to compiler/rustc_error_codes/src/error_codes/E0117.md diff --git a/src/librustc_error_codes/error_codes/E0118.md b/compiler/rustc_error_codes/src/error_codes/E0118.md similarity index 63% rename from src/librustc_error_codes/error_codes/E0118.md rename to compiler/rustc_error_codes/src/error_codes/E0118.md index 5cb5f506e0..345ec341c3 100644 --- a/src/librustc_error_codes/error_codes/E0118.md +++ b/compiler/rustc_error_codes/src/error_codes/E0118.md @@ -1,10 +1,10 @@ -An inherent implementation was defined for something which isn't a struct nor -an enum. +An inherent implementation was defined for something which isn't a struct, +enum, union, or trait object. Erroneous code example: ```compile_fail,E0118 -impl (u8, u8) { // error: no base type found for inherent implementation +impl (u8, u8) { // error: no nominal type found for inherent implementation fn get_state(&self) -> String { // ... } @@ -41,3 +41,24 @@ impl TypeWrapper { } } ``` + +Instead of defining an inherent implementation on a reference, you could also +move the reference inside the implementation: + +```compile_fail,E0118 +struct Foo; + +impl &Foo { // error: no nominal type found for inherent implementation + fn bar(self, other: Self) {} +} +``` + +becomes + +``` +struct Foo; + +impl Foo { + fn bar(&self, other: &Self) {} +} +``` diff --git a/src/librustc_error_codes/error_codes/E0119.md b/compiler/rustc_error_codes/src/error_codes/E0119.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0119.md rename to compiler/rustc_error_codes/src/error_codes/E0119.md diff --git a/src/librustc_error_codes/error_codes/E0120.md b/compiler/rustc_error_codes/src/error_codes/E0120.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0120.md rename to compiler/rustc_error_codes/src/error_codes/E0120.md diff --git a/src/librustc_error_codes/error_codes/E0121.md b/compiler/rustc_error_codes/src/error_codes/E0121.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0121.md rename to compiler/rustc_error_codes/src/error_codes/E0121.md diff --git a/src/librustc_error_codes/error_codes/E0124.md b/compiler/rustc_error_codes/src/error_codes/E0124.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0124.md rename to compiler/rustc_error_codes/src/error_codes/E0124.md diff --git a/src/librustc_error_codes/error_codes/E0128.md b/compiler/rustc_error_codes/src/error_codes/E0128.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0128.md rename to compiler/rustc_error_codes/src/error_codes/E0128.md diff --git a/src/librustc_error_codes/error_codes/E0130.md b/compiler/rustc_error_codes/src/error_codes/E0130.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0130.md rename to compiler/rustc_error_codes/src/error_codes/E0130.md diff --git a/src/librustc_error_codes/error_codes/E0131.md b/compiler/rustc_error_codes/src/error_codes/E0131.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0131.md rename to compiler/rustc_error_codes/src/error_codes/E0131.md diff --git a/src/librustc_error_codes/error_codes/E0132.md b/compiler/rustc_error_codes/src/error_codes/E0132.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0132.md rename to compiler/rustc_error_codes/src/error_codes/E0132.md diff --git a/src/librustc_error_codes/error_codes/E0133.md b/compiler/rustc_error_codes/src/error_codes/E0133.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0133.md rename to compiler/rustc_error_codes/src/error_codes/E0133.md diff --git a/src/librustc_error_codes/error_codes/E0136.md b/compiler/rustc_error_codes/src/error_codes/E0136.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0136.md rename to compiler/rustc_error_codes/src/error_codes/E0136.md diff --git a/src/librustc_error_codes/error_codes/E0137.md b/compiler/rustc_error_codes/src/error_codes/E0137.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0137.md rename to compiler/rustc_error_codes/src/error_codes/E0137.md diff --git a/src/librustc_error_codes/error_codes/E0138.md b/compiler/rustc_error_codes/src/error_codes/E0138.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0138.md rename to compiler/rustc_error_codes/src/error_codes/E0138.md diff --git a/src/librustc_error_codes/error_codes/E0139.md b/compiler/rustc_error_codes/src/error_codes/E0139.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0139.md rename to compiler/rustc_error_codes/src/error_codes/E0139.md diff --git a/src/librustc_error_codes/error_codes/E0152.md b/compiler/rustc_error_codes/src/error_codes/E0152.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0152.md rename to compiler/rustc_error_codes/src/error_codes/E0152.md diff --git a/src/librustc_error_codes/error_codes/E0154.md b/compiler/rustc_error_codes/src/error_codes/E0154.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0154.md rename to compiler/rustc_error_codes/src/error_codes/E0154.md diff --git a/src/librustc_error_codes/error_codes/E0158.md b/compiler/rustc_error_codes/src/error_codes/E0158.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0158.md rename to compiler/rustc_error_codes/src/error_codes/E0158.md diff --git a/src/librustc_error_codes/error_codes/E0161.md b/compiler/rustc_error_codes/src/error_codes/E0161.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0161.md rename to compiler/rustc_error_codes/src/error_codes/E0161.md diff --git a/src/librustc_error_codes/error_codes/E0162.md b/compiler/rustc_error_codes/src/error_codes/E0162.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0162.md rename to compiler/rustc_error_codes/src/error_codes/E0162.md diff --git a/src/librustc_error_codes/error_codes/E0164.md b/compiler/rustc_error_codes/src/error_codes/E0164.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0164.md rename to compiler/rustc_error_codes/src/error_codes/E0164.md diff --git a/src/librustc_error_codes/error_codes/E0165.md b/compiler/rustc_error_codes/src/error_codes/E0165.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0165.md rename to compiler/rustc_error_codes/src/error_codes/E0165.md diff --git a/src/librustc_error_codes/error_codes/E0170.md b/compiler/rustc_error_codes/src/error_codes/E0170.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0170.md rename to compiler/rustc_error_codes/src/error_codes/E0170.md diff --git a/src/librustc_error_codes/error_codes/E0178.md b/compiler/rustc_error_codes/src/error_codes/E0178.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0178.md rename to compiler/rustc_error_codes/src/error_codes/E0178.md diff --git a/src/librustc_error_codes/error_codes/E0184.md b/compiler/rustc_error_codes/src/error_codes/E0184.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0184.md rename to compiler/rustc_error_codes/src/error_codes/E0184.md diff --git a/src/librustc_error_codes/error_codes/E0185.md b/compiler/rustc_error_codes/src/error_codes/E0185.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0185.md rename to compiler/rustc_error_codes/src/error_codes/E0185.md diff --git a/src/librustc_error_codes/error_codes/E0186.md b/compiler/rustc_error_codes/src/error_codes/E0186.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0186.md rename to compiler/rustc_error_codes/src/error_codes/E0186.md diff --git a/src/librustc_error_codes/error_codes/E0191.md b/compiler/rustc_error_codes/src/error_codes/E0191.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0191.md rename to compiler/rustc_error_codes/src/error_codes/E0191.md diff --git a/src/librustc_error_codes/error_codes/E0192.md b/compiler/rustc_error_codes/src/error_codes/E0192.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0192.md rename to compiler/rustc_error_codes/src/error_codes/E0192.md diff --git a/src/librustc_error_codes/error_codes/E0193.md b/compiler/rustc_error_codes/src/error_codes/E0193.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0193.md rename to compiler/rustc_error_codes/src/error_codes/E0193.md diff --git a/src/librustc_error_codes/error_codes/E0195.md b/compiler/rustc_error_codes/src/error_codes/E0195.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0195.md rename to compiler/rustc_error_codes/src/error_codes/E0195.md diff --git a/src/librustc_error_codes/error_codes/E0197.md b/compiler/rustc_error_codes/src/error_codes/E0197.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0197.md rename to compiler/rustc_error_codes/src/error_codes/E0197.md diff --git a/src/librustc_error_codes/error_codes/E0198.md b/compiler/rustc_error_codes/src/error_codes/E0198.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0198.md rename to compiler/rustc_error_codes/src/error_codes/E0198.md diff --git a/src/librustc_error_codes/error_codes/E0199.md b/compiler/rustc_error_codes/src/error_codes/E0199.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0199.md rename to compiler/rustc_error_codes/src/error_codes/E0199.md diff --git a/src/librustc_error_codes/error_codes/E0200.md b/compiler/rustc_error_codes/src/error_codes/E0200.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0200.md rename to compiler/rustc_error_codes/src/error_codes/E0200.md diff --git a/src/librustc_error_codes/error_codes/E0201.md b/compiler/rustc_error_codes/src/error_codes/E0201.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0201.md rename to compiler/rustc_error_codes/src/error_codes/E0201.md diff --git a/src/librustc_error_codes/error_codes/E0202.md b/compiler/rustc_error_codes/src/error_codes/E0202.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0202.md rename to compiler/rustc_error_codes/src/error_codes/E0202.md diff --git a/src/librustc_error_codes/error_codes/E0203.md b/compiler/rustc_error_codes/src/error_codes/E0203.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0203.md rename to compiler/rustc_error_codes/src/error_codes/E0203.md diff --git a/src/librustc_error_codes/error_codes/E0204.md b/compiler/rustc_error_codes/src/error_codes/E0204.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0204.md rename to compiler/rustc_error_codes/src/error_codes/E0204.md diff --git a/src/librustc_error_codes/error_codes/E0205.md b/compiler/rustc_error_codes/src/error_codes/E0205.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0205.md rename to compiler/rustc_error_codes/src/error_codes/E0205.md diff --git a/src/librustc_error_codes/error_codes/E0206.md b/compiler/rustc_error_codes/src/error_codes/E0206.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0206.md rename to compiler/rustc_error_codes/src/error_codes/E0206.md diff --git a/src/librustc_error_codes/error_codes/E0207.md b/compiler/rustc_error_codes/src/error_codes/E0207.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0207.md rename to compiler/rustc_error_codes/src/error_codes/E0207.md diff --git a/src/librustc_error_codes/error_codes/E0210.md b/compiler/rustc_error_codes/src/error_codes/E0210.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0210.md rename to compiler/rustc_error_codes/src/error_codes/E0210.md diff --git a/src/librustc_error_codes/error_codes/E0211.md b/compiler/rustc_error_codes/src/error_codes/E0211.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0211.md rename to compiler/rustc_error_codes/src/error_codes/E0211.md diff --git a/src/librustc_error_codes/error_codes/E0214.md b/compiler/rustc_error_codes/src/error_codes/E0214.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0214.md rename to compiler/rustc_error_codes/src/error_codes/E0214.md diff --git a/src/librustc_error_codes/error_codes/E0220.md b/compiler/rustc_error_codes/src/error_codes/E0220.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0220.md rename to compiler/rustc_error_codes/src/error_codes/E0220.md diff --git a/src/librustc_error_codes/error_codes/E0221.md b/compiler/rustc_error_codes/src/error_codes/E0221.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0221.md rename to compiler/rustc_error_codes/src/error_codes/E0221.md diff --git a/src/librustc_error_codes/error_codes/E0222.md b/compiler/rustc_error_codes/src/error_codes/E0222.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0222.md rename to compiler/rustc_error_codes/src/error_codes/E0222.md diff --git a/src/librustc_error_codes/error_codes/E0223.md b/compiler/rustc_error_codes/src/error_codes/E0223.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0223.md rename to compiler/rustc_error_codes/src/error_codes/E0223.md diff --git a/src/librustc_error_codes/error_codes/E0224.md b/compiler/rustc_error_codes/src/error_codes/E0224.md similarity index 59% rename from src/librustc_error_codes/error_codes/E0224.md rename to compiler/rustc_error_codes/src/error_codes/E0224.md index fd89c1d525..628488575b 100644 --- a/src/librustc_error_codes/error_codes/E0224.md +++ b/compiler/rustc_error_codes/src/error_codes/E0224.md @@ -1,4 +1,4 @@ -A trait object was declaired with no traits. +A trait object was declared with no traits. Erroneous code example: @@ -8,7 +8,7 @@ type Foo = dyn 'static +; Rust does not currently support this. -To solve ensure the the trait object has at least one trait: +To solve, ensure that the trait object has at least one trait: ``` type Foo = dyn 'static + Copy; diff --git a/src/librustc_error_codes/error_codes/E0225.md b/compiler/rustc_error_codes/src/error_codes/E0225.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0225.md rename to compiler/rustc_error_codes/src/error_codes/E0225.md diff --git a/src/librustc_error_codes/error_codes/E0226.md b/compiler/rustc_error_codes/src/error_codes/E0226.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0226.md rename to compiler/rustc_error_codes/src/error_codes/E0226.md diff --git a/src/librustc_error_codes/error_codes/E0228.md b/compiler/rustc_error_codes/src/error_codes/E0228.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0228.md rename to compiler/rustc_error_codes/src/error_codes/E0228.md diff --git a/src/librustc_error_codes/error_codes/E0229.md b/compiler/rustc_error_codes/src/error_codes/E0229.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0229.md rename to compiler/rustc_error_codes/src/error_codes/E0229.md diff --git a/src/librustc_error_codes/error_codes/E0230.md b/compiler/rustc_error_codes/src/error_codes/E0230.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0230.md rename to compiler/rustc_error_codes/src/error_codes/E0230.md diff --git a/src/librustc_error_codes/error_codes/E0231.md b/compiler/rustc_error_codes/src/error_codes/E0231.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0231.md rename to compiler/rustc_error_codes/src/error_codes/E0231.md diff --git a/src/librustc_error_codes/error_codes/E0232.md b/compiler/rustc_error_codes/src/error_codes/E0232.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0232.md rename to compiler/rustc_error_codes/src/error_codes/E0232.md diff --git a/src/librustc_error_codes/error_codes/E0243.md b/compiler/rustc_error_codes/src/error_codes/E0243.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0243.md rename to compiler/rustc_error_codes/src/error_codes/E0243.md diff --git a/src/librustc_error_codes/error_codes/E0244.md b/compiler/rustc_error_codes/src/error_codes/E0244.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0244.md rename to compiler/rustc_error_codes/src/error_codes/E0244.md diff --git a/src/librustc_error_codes/error_codes/E0251.md b/compiler/rustc_error_codes/src/error_codes/E0251.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0251.md rename to compiler/rustc_error_codes/src/error_codes/E0251.md diff --git a/src/librustc_error_codes/error_codes/E0252.md b/compiler/rustc_error_codes/src/error_codes/E0252.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0252.md rename to compiler/rustc_error_codes/src/error_codes/E0252.md diff --git a/src/librustc_error_codes/error_codes/E0253.md b/compiler/rustc_error_codes/src/error_codes/E0253.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0253.md rename to compiler/rustc_error_codes/src/error_codes/E0253.md diff --git a/src/librustc_error_codes/error_codes/E0254.md b/compiler/rustc_error_codes/src/error_codes/E0254.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0254.md rename to compiler/rustc_error_codes/src/error_codes/E0254.md diff --git a/src/librustc_error_codes/error_codes/E0255.md b/compiler/rustc_error_codes/src/error_codes/E0255.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0255.md rename to compiler/rustc_error_codes/src/error_codes/E0255.md diff --git a/src/librustc_error_codes/error_codes/E0256.md b/compiler/rustc_error_codes/src/error_codes/E0256.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0256.md rename to compiler/rustc_error_codes/src/error_codes/E0256.md diff --git a/src/librustc_error_codes/error_codes/E0259.md b/compiler/rustc_error_codes/src/error_codes/E0259.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0259.md rename to compiler/rustc_error_codes/src/error_codes/E0259.md diff --git a/src/librustc_error_codes/error_codes/E0260.md b/compiler/rustc_error_codes/src/error_codes/E0260.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0260.md rename to compiler/rustc_error_codes/src/error_codes/E0260.md diff --git a/src/librustc_error_codes/error_codes/E0261.md b/compiler/rustc_error_codes/src/error_codes/E0261.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0261.md rename to compiler/rustc_error_codes/src/error_codes/E0261.md diff --git a/src/librustc_error_codes/error_codes/E0262.md b/compiler/rustc_error_codes/src/error_codes/E0262.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0262.md rename to compiler/rustc_error_codes/src/error_codes/E0262.md diff --git a/src/librustc_error_codes/error_codes/E0263.md b/compiler/rustc_error_codes/src/error_codes/E0263.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0263.md rename to compiler/rustc_error_codes/src/error_codes/E0263.md diff --git a/src/librustc_error_codes/error_codes/E0264.md b/compiler/rustc_error_codes/src/error_codes/E0264.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0264.md rename to compiler/rustc_error_codes/src/error_codes/E0264.md diff --git a/src/librustc_error_codes/error_codes/E0267.md b/compiler/rustc_error_codes/src/error_codes/E0267.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0267.md rename to compiler/rustc_error_codes/src/error_codes/E0267.md diff --git a/src/librustc_error_codes/error_codes/E0268.md b/compiler/rustc_error_codes/src/error_codes/E0268.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0268.md rename to compiler/rustc_error_codes/src/error_codes/E0268.md diff --git a/src/librustc_error_codes/error_codes/E0271.md b/compiler/rustc_error_codes/src/error_codes/E0271.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0271.md rename to compiler/rustc_error_codes/src/error_codes/E0271.md diff --git a/src/librustc_error_codes/error_codes/E0275.md b/compiler/rustc_error_codes/src/error_codes/E0275.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0275.md rename to compiler/rustc_error_codes/src/error_codes/E0275.md diff --git a/src/librustc_error_codes/error_codes/E0276.md b/compiler/rustc_error_codes/src/error_codes/E0276.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0276.md rename to compiler/rustc_error_codes/src/error_codes/E0276.md diff --git a/src/librustc_error_codes/error_codes/E0277.md b/compiler/rustc_error_codes/src/error_codes/E0277.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0277.md rename to compiler/rustc_error_codes/src/error_codes/E0277.md diff --git a/src/librustc_error_codes/error_codes/E0281.md b/compiler/rustc_error_codes/src/error_codes/E0281.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0281.md rename to compiler/rustc_error_codes/src/error_codes/E0281.md diff --git a/src/librustc_error_codes/error_codes/E0282.md b/compiler/rustc_error_codes/src/error_codes/E0282.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0282.md rename to compiler/rustc_error_codes/src/error_codes/E0282.md diff --git a/src/librustc_error_codes/error_codes/E0283.md b/compiler/rustc_error_codes/src/error_codes/E0283.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0283.md rename to compiler/rustc_error_codes/src/error_codes/E0283.md diff --git a/src/librustc_error_codes/error_codes/E0284.md b/compiler/rustc_error_codes/src/error_codes/E0284.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0284.md rename to compiler/rustc_error_codes/src/error_codes/E0284.md diff --git a/src/librustc_error_codes/error_codes/E0297.md b/compiler/rustc_error_codes/src/error_codes/E0297.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0297.md rename to compiler/rustc_error_codes/src/error_codes/E0297.md diff --git a/src/librustc_error_codes/error_codes/E0301.md b/compiler/rustc_error_codes/src/error_codes/E0301.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0301.md rename to compiler/rustc_error_codes/src/error_codes/E0301.md diff --git a/src/librustc_error_codes/error_codes/E0302.md b/compiler/rustc_error_codes/src/error_codes/E0302.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0302.md rename to compiler/rustc_error_codes/src/error_codes/E0302.md diff --git a/src/librustc_error_codes/error_codes/E0303.md b/compiler/rustc_error_codes/src/error_codes/E0303.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0303.md rename to compiler/rustc_error_codes/src/error_codes/E0303.md diff --git a/src/librustc_error_codes/error_codes/E0307.md b/compiler/rustc_error_codes/src/error_codes/E0307.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0307.md rename to compiler/rustc_error_codes/src/error_codes/E0307.md diff --git a/src/librustc_error_codes/error_codes/E0308.md b/compiler/rustc_error_codes/src/error_codes/E0308.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0308.md rename to compiler/rustc_error_codes/src/error_codes/E0308.md diff --git a/src/librustc_error_codes/error_codes/E0309.md b/compiler/rustc_error_codes/src/error_codes/E0309.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0309.md rename to compiler/rustc_error_codes/src/error_codes/E0309.md diff --git a/src/librustc_error_codes/error_codes/E0310.md b/compiler/rustc_error_codes/src/error_codes/E0310.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0310.md rename to compiler/rustc_error_codes/src/error_codes/E0310.md diff --git a/src/librustc_error_codes/error_codes/E0312.md b/compiler/rustc_error_codes/src/error_codes/E0312.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0312.md rename to compiler/rustc_error_codes/src/error_codes/E0312.md diff --git a/src/librustc_error_codes/error_codes/E0317.md b/compiler/rustc_error_codes/src/error_codes/E0317.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0317.md rename to compiler/rustc_error_codes/src/error_codes/E0317.md diff --git a/src/librustc_error_codes/error_codes/E0321.md b/compiler/rustc_error_codes/src/error_codes/E0321.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0321.md rename to compiler/rustc_error_codes/src/error_codes/E0321.md diff --git a/src/librustc_error_codes/error_codes/E0322.md b/compiler/rustc_error_codes/src/error_codes/E0322.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0322.md rename to compiler/rustc_error_codes/src/error_codes/E0322.md diff --git a/src/librustc_error_codes/error_codes/E0323.md b/compiler/rustc_error_codes/src/error_codes/E0323.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0323.md rename to compiler/rustc_error_codes/src/error_codes/E0323.md diff --git a/src/librustc_error_codes/error_codes/E0324.md b/compiler/rustc_error_codes/src/error_codes/E0324.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0324.md rename to compiler/rustc_error_codes/src/error_codes/E0324.md diff --git a/src/librustc_error_codes/error_codes/E0325.md b/compiler/rustc_error_codes/src/error_codes/E0325.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0325.md rename to compiler/rustc_error_codes/src/error_codes/E0325.md diff --git a/src/librustc_error_codes/error_codes/E0326.md b/compiler/rustc_error_codes/src/error_codes/E0326.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0326.md rename to compiler/rustc_error_codes/src/error_codes/E0326.md diff --git a/src/librustc_error_codes/error_codes/E0328.md b/compiler/rustc_error_codes/src/error_codes/E0328.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0328.md rename to compiler/rustc_error_codes/src/error_codes/E0328.md diff --git a/src/librustc_error_codes/error_codes/E0329.md b/compiler/rustc_error_codes/src/error_codes/E0329.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0329.md rename to compiler/rustc_error_codes/src/error_codes/E0329.md diff --git a/src/librustc_error_codes/error_codes/E0364.md b/compiler/rustc_error_codes/src/error_codes/E0364.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0364.md rename to compiler/rustc_error_codes/src/error_codes/E0364.md diff --git a/src/librustc_error_codes/error_codes/E0365.md b/compiler/rustc_error_codes/src/error_codes/E0365.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0365.md rename to compiler/rustc_error_codes/src/error_codes/E0365.md diff --git a/src/librustc_error_codes/error_codes/E0366.md b/compiler/rustc_error_codes/src/error_codes/E0366.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0366.md rename to compiler/rustc_error_codes/src/error_codes/E0366.md diff --git a/src/librustc_error_codes/error_codes/E0367.md b/compiler/rustc_error_codes/src/error_codes/E0367.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0367.md rename to compiler/rustc_error_codes/src/error_codes/E0367.md diff --git a/src/librustc_error_codes/error_codes/E0368.md b/compiler/rustc_error_codes/src/error_codes/E0368.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0368.md rename to compiler/rustc_error_codes/src/error_codes/E0368.md diff --git a/src/librustc_error_codes/error_codes/E0369.md b/compiler/rustc_error_codes/src/error_codes/E0369.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0369.md rename to compiler/rustc_error_codes/src/error_codes/E0369.md diff --git a/src/librustc_error_codes/error_codes/E0370.md b/compiler/rustc_error_codes/src/error_codes/E0370.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0370.md rename to compiler/rustc_error_codes/src/error_codes/E0370.md diff --git a/src/librustc_error_codes/error_codes/E0371.md b/compiler/rustc_error_codes/src/error_codes/E0371.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0371.md rename to compiler/rustc_error_codes/src/error_codes/E0371.md diff --git a/src/librustc_error_codes/error_codes/E0373.md b/compiler/rustc_error_codes/src/error_codes/E0373.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0373.md rename to compiler/rustc_error_codes/src/error_codes/E0373.md diff --git a/src/librustc_error_codes/error_codes/E0374.md b/compiler/rustc_error_codes/src/error_codes/E0374.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0374.md rename to compiler/rustc_error_codes/src/error_codes/E0374.md diff --git a/src/librustc_error_codes/error_codes/E0375.md b/compiler/rustc_error_codes/src/error_codes/E0375.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0375.md rename to compiler/rustc_error_codes/src/error_codes/E0375.md diff --git a/src/librustc_error_codes/error_codes/E0376.md b/compiler/rustc_error_codes/src/error_codes/E0376.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0376.md rename to compiler/rustc_error_codes/src/error_codes/E0376.md diff --git a/src/librustc_error_codes/error_codes/E0378.md b/compiler/rustc_error_codes/src/error_codes/E0378.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0378.md rename to compiler/rustc_error_codes/src/error_codes/E0378.md diff --git a/src/librustc_error_codes/error_codes/E0379.md b/compiler/rustc_error_codes/src/error_codes/E0379.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0379.md rename to compiler/rustc_error_codes/src/error_codes/E0379.md diff --git a/src/librustc_error_codes/error_codes/E0380.md b/compiler/rustc_error_codes/src/error_codes/E0380.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0380.md rename to compiler/rustc_error_codes/src/error_codes/E0380.md diff --git a/src/librustc_error_codes/error_codes/E0381.md b/compiler/rustc_error_codes/src/error_codes/E0381.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0381.md rename to compiler/rustc_error_codes/src/error_codes/E0381.md diff --git a/src/librustc_error_codes/error_codes/E0382.md b/compiler/rustc_error_codes/src/error_codes/E0382.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0382.md rename to compiler/rustc_error_codes/src/error_codes/E0382.md diff --git a/src/librustc_error_codes/error_codes/E0383.md b/compiler/rustc_error_codes/src/error_codes/E0383.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0383.md rename to compiler/rustc_error_codes/src/error_codes/E0383.md diff --git a/src/librustc_error_codes/error_codes/E0384.md b/compiler/rustc_error_codes/src/error_codes/E0384.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0384.md rename to compiler/rustc_error_codes/src/error_codes/E0384.md diff --git a/src/librustc_error_codes/error_codes/E0386.md b/compiler/rustc_error_codes/src/error_codes/E0386.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0386.md rename to compiler/rustc_error_codes/src/error_codes/E0386.md diff --git a/src/librustc_error_codes/error_codes/E0387.md b/compiler/rustc_error_codes/src/error_codes/E0387.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0387.md rename to compiler/rustc_error_codes/src/error_codes/E0387.md diff --git a/src/librustc_error_codes/error_codes/E0388.md b/compiler/rustc_error_codes/src/error_codes/E0388.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0388.md rename to compiler/rustc_error_codes/src/error_codes/E0388.md diff --git a/src/librustc_error_codes/error_codes/E0389.md b/compiler/rustc_error_codes/src/error_codes/E0389.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0389.md rename to compiler/rustc_error_codes/src/error_codes/E0389.md diff --git a/src/librustc_error_codes/error_codes/E0390.md b/compiler/rustc_error_codes/src/error_codes/E0390.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0390.md rename to compiler/rustc_error_codes/src/error_codes/E0390.md diff --git a/src/librustc_error_codes/error_codes/E0391.md b/compiler/rustc_error_codes/src/error_codes/E0391.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0391.md rename to compiler/rustc_error_codes/src/error_codes/E0391.md diff --git a/src/librustc_error_codes/error_codes/E0392.md b/compiler/rustc_error_codes/src/error_codes/E0392.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0392.md rename to compiler/rustc_error_codes/src/error_codes/E0392.md diff --git a/src/librustc_error_codes/error_codes/E0393.md b/compiler/rustc_error_codes/src/error_codes/E0393.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0393.md rename to compiler/rustc_error_codes/src/error_codes/E0393.md diff --git a/src/librustc_error_codes/error_codes/E0398.md b/compiler/rustc_error_codes/src/error_codes/E0398.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0398.md rename to compiler/rustc_error_codes/src/error_codes/E0398.md diff --git a/src/librustc_error_codes/error_codes/E0399.md b/compiler/rustc_error_codes/src/error_codes/E0399.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0399.md rename to compiler/rustc_error_codes/src/error_codes/E0399.md diff --git a/src/librustc_error_codes/error_codes/E0401.md b/compiler/rustc_error_codes/src/error_codes/E0401.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0401.md rename to compiler/rustc_error_codes/src/error_codes/E0401.md diff --git a/src/librustc_error_codes/error_codes/E0403.md b/compiler/rustc_error_codes/src/error_codes/E0403.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0403.md rename to compiler/rustc_error_codes/src/error_codes/E0403.md diff --git a/src/librustc_error_codes/error_codes/E0404.md b/compiler/rustc_error_codes/src/error_codes/E0404.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0404.md rename to compiler/rustc_error_codes/src/error_codes/E0404.md diff --git a/src/librustc_error_codes/error_codes/E0405.md b/compiler/rustc_error_codes/src/error_codes/E0405.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0405.md rename to compiler/rustc_error_codes/src/error_codes/E0405.md diff --git a/src/librustc_error_codes/error_codes/E0407.md b/compiler/rustc_error_codes/src/error_codes/E0407.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0407.md rename to compiler/rustc_error_codes/src/error_codes/E0407.md diff --git a/src/librustc_error_codes/error_codes/E0408.md b/compiler/rustc_error_codes/src/error_codes/E0408.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0408.md rename to compiler/rustc_error_codes/src/error_codes/E0408.md diff --git a/src/librustc_error_codes/error_codes/E0409.md b/compiler/rustc_error_codes/src/error_codes/E0409.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0409.md rename to compiler/rustc_error_codes/src/error_codes/E0409.md diff --git a/src/librustc_error_codes/error_codes/E0411.md b/compiler/rustc_error_codes/src/error_codes/E0411.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0411.md rename to compiler/rustc_error_codes/src/error_codes/E0411.md diff --git a/src/librustc_error_codes/error_codes/E0412.md b/compiler/rustc_error_codes/src/error_codes/E0412.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0412.md rename to compiler/rustc_error_codes/src/error_codes/E0412.md diff --git a/src/librustc_error_codes/error_codes/E0415.md b/compiler/rustc_error_codes/src/error_codes/E0415.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0415.md rename to compiler/rustc_error_codes/src/error_codes/E0415.md diff --git a/src/librustc_error_codes/error_codes/E0416.md b/compiler/rustc_error_codes/src/error_codes/E0416.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0416.md rename to compiler/rustc_error_codes/src/error_codes/E0416.md diff --git a/src/librustc_error_codes/error_codes/E0422.md b/compiler/rustc_error_codes/src/error_codes/E0422.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0422.md rename to compiler/rustc_error_codes/src/error_codes/E0422.md diff --git a/src/librustc_error_codes/error_codes/E0423.md b/compiler/rustc_error_codes/src/error_codes/E0423.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0423.md rename to compiler/rustc_error_codes/src/error_codes/E0423.md diff --git a/src/librustc_error_codes/error_codes/E0424.md b/compiler/rustc_error_codes/src/error_codes/E0424.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0424.md rename to compiler/rustc_error_codes/src/error_codes/E0424.md diff --git a/src/librustc_error_codes/error_codes/E0425.md b/compiler/rustc_error_codes/src/error_codes/E0425.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0425.md rename to compiler/rustc_error_codes/src/error_codes/E0425.md diff --git a/src/librustc_error_codes/error_codes/E0426.md b/compiler/rustc_error_codes/src/error_codes/E0426.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0426.md rename to compiler/rustc_error_codes/src/error_codes/E0426.md diff --git a/src/librustc_error_codes/error_codes/E0428.md b/compiler/rustc_error_codes/src/error_codes/E0428.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0428.md rename to compiler/rustc_error_codes/src/error_codes/E0428.md diff --git a/src/librustc_error_codes/error_codes/E0429.md b/compiler/rustc_error_codes/src/error_codes/E0429.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0429.md rename to compiler/rustc_error_codes/src/error_codes/E0429.md diff --git a/src/librustc_error_codes/error_codes/E0430.md b/compiler/rustc_error_codes/src/error_codes/E0430.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0430.md rename to compiler/rustc_error_codes/src/error_codes/E0430.md diff --git a/src/librustc_error_codes/error_codes/E0431.md b/compiler/rustc_error_codes/src/error_codes/E0431.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0431.md rename to compiler/rustc_error_codes/src/error_codes/E0431.md diff --git a/src/librustc_error_codes/error_codes/E0432.md b/compiler/rustc_error_codes/src/error_codes/E0432.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0432.md rename to compiler/rustc_error_codes/src/error_codes/E0432.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0433.md b/compiler/rustc_error_codes/src/error_codes/E0433.md new file mode 100644 index 0000000000..5a64c13c9a --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0433.md @@ -0,0 +1,27 @@ +An undeclared crate, module, or type was used. + +Erroneous code example: + +```compile_fail,E0433 +let map = HashMap::new(); +// error: failed to resolve: use of undeclared type `HashMap` +``` + +Please verify you didn't misspell the type/module's name or that you didn't +forget to import it: + +``` +use std::collections::HashMap; // HashMap has been imported. +let map: HashMap = HashMap::new(); // So it can be used! +``` + +If you've expected to use a crate name: + +```compile_fail +use ferris_wheel::BigO; +// error: failed to resolve: use of undeclared crate or module `ferris_wheel` +``` + +Make sure the crate has been added as a dependency in `Cargo.toml`. + +To use a module from your current crate, add the `crate::` prefix to the path. diff --git a/src/librustc_error_codes/error_codes/E0434.md b/compiler/rustc_error_codes/src/error_codes/E0434.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0434.md rename to compiler/rustc_error_codes/src/error_codes/E0434.md diff --git a/src/librustc_error_codes/error_codes/E0435.md b/compiler/rustc_error_codes/src/error_codes/E0435.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0435.md rename to compiler/rustc_error_codes/src/error_codes/E0435.md diff --git a/src/librustc_error_codes/error_codes/E0436.md b/compiler/rustc_error_codes/src/error_codes/E0436.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0436.md rename to compiler/rustc_error_codes/src/error_codes/E0436.md diff --git a/src/librustc_error_codes/error_codes/E0437.md b/compiler/rustc_error_codes/src/error_codes/E0437.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0437.md rename to compiler/rustc_error_codes/src/error_codes/E0437.md diff --git a/src/librustc_error_codes/error_codes/E0438.md b/compiler/rustc_error_codes/src/error_codes/E0438.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0438.md rename to compiler/rustc_error_codes/src/error_codes/E0438.md diff --git a/src/librustc_error_codes/error_codes/E0439.md b/compiler/rustc_error_codes/src/error_codes/E0439.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0439.md rename to compiler/rustc_error_codes/src/error_codes/E0439.md diff --git a/src/librustc_error_codes/error_codes/E0445.md b/compiler/rustc_error_codes/src/error_codes/E0445.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0445.md rename to compiler/rustc_error_codes/src/error_codes/E0445.md diff --git a/src/librustc_error_codes/error_codes/E0446.md b/compiler/rustc_error_codes/src/error_codes/E0446.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0446.md rename to compiler/rustc_error_codes/src/error_codes/E0446.md diff --git a/src/librustc_error_codes/error_codes/E0447.md b/compiler/rustc_error_codes/src/error_codes/E0447.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0447.md rename to compiler/rustc_error_codes/src/error_codes/E0447.md diff --git a/src/librustc_error_codes/error_codes/E0448.md b/compiler/rustc_error_codes/src/error_codes/E0448.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0448.md rename to compiler/rustc_error_codes/src/error_codes/E0448.md diff --git a/src/librustc_error_codes/error_codes/E0449.md b/compiler/rustc_error_codes/src/error_codes/E0449.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0449.md rename to compiler/rustc_error_codes/src/error_codes/E0449.md diff --git a/src/librustc_error_codes/error_codes/E0451.md b/compiler/rustc_error_codes/src/error_codes/E0451.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0451.md rename to compiler/rustc_error_codes/src/error_codes/E0451.md diff --git a/src/librustc_error_codes/error_codes/E0452.md b/compiler/rustc_error_codes/src/error_codes/E0452.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0452.md rename to compiler/rustc_error_codes/src/error_codes/E0452.md diff --git a/src/librustc_error_codes/error_codes/E0453.md b/compiler/rustc_error_codes/src/error_codes/E0453.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0453.md rename to compiler/rustc_error_codes/src/error_codes/E0453.md diff --git a/src/librustc_error_codes/error_codes/E0454.md b/compiler/rustc_error_codes/src/error_codes/E0454.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0454.md rename to compiler/rustc_error_codes/src/error_codes/E0454.md diff --git a/src/librustc_error_codes/error_codes/E0455.md b/compiler/rustc_error_codes/src/error_codes/E0455.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0455.md rename to compiler/rustc_error_codes/src/error_codes/E0455.md diff --git a/src/librustc_error_codes/error_codes/E0458.md b/compiler/rustc_error_codes/src/error_codes/E0458.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0458.md rename to compiler/rustc_error_codes/src/error_codes/E0458.md diff --git a/src/librustc_error_codes/error_codes/E0459.md b/compiler/rustc_error_codes/src/error_codes/E0459.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0459.md rename to compiler/rustc_error_codes/src/error_codes/E0459.md diff --git a/src/librustc_error_codes/error_codes/E0463.md b/compiler/rustc_error_codes/src/error_codes/E0463.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0463.md rename to compiler/rustc_error_codes/src/error_codes/E0463.md diff --git a/src/librustc_error_codes/error_codes/E0466.md b/compiler/rustc_error_codes/src/error_codes/E0466.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0466.md rename to compiler/rustc_error_codes/src/error_codes/E0466.md diff --git a/src/librustc_error_codes/error_codes/E0468.md b/compiler/rustc_error_codes/src/error_codes/E0468.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0468.md rename to compiler/rustc_error_codes/src/error_codes/E0468.md diff --git a/src/librustc_error_codes/error_codes/E0469.md b/compiler/rustc_error_codes/src/error_codes/E0469.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0469.md rename to compiler/rustc_error_codes/src/error_codes/E0469.md diff --git a/src/librustc_error_codes/error_codes/E0477.md b/compiler/rustc_error_codes/src/error_codes/E0477.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0477.md rename to compiler/rustc_error_codes/src/error_codes/E0477.md diff --git a/src/librustc_error_codes/error_codes/E0478.md b/compiler/rustc_error_codes/src/error_codes/E0478.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0478.md rename to compiler/rustc_error_codes/src/error_codes/E0478.md diff --git a/src/librustc_error_codes/error_codes/E0491.md b/compiler/rustc_error_codes/src/error_codes/E0491.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0491.md rename to compiler/rustc_error_codes/src/error_codes/E0491.md diff --git a/src/librustc_error_codes/error_codes/E0492.md b/compiler/rustc_error_codes/src/error_codes/E0492.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0492.md rename to compiler/rustc_error_codes/src/error_codes/E0492.md diff --git a/src/librustc_error_codes/error_codes/E0493.md b/compiler/rustc_error_codes/src/error_codes/E0493.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0493.md rename to compiler/rustc_error_codes/src/error_codes/E0493.md diff --git a/src/librustc_error_codes/error_codes/E0495.md b/compiler/rustc_error_codes/src/error_codes/E0495.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0495.md rename to compiler/rustc_error_codes/src/error_codes/E0495.md diff --git a/src/librustc_error_codes/error_codes/E0496.md b/compiler/rustc_error_codes/src/error_codes/E0496.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0496.md rename to compiler/rustc_error_codes/src/error_codes/E0496.md diff --git a/src/librustc_error_codes/error_codes/E0497.md b/compiler/rustc_error_codes/src/error_codes/E0497.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0497.md rename to compiler/rustc_error_codes/src/error_codes/E0497.md diff --git a/src/librustc_error_codes/error_codes/E0499.md b/compiler/rustc_error_codes/src/error_codes/E0499.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0499.md rename to compiler/rustc_error_codes/src/error_codes/E0499.md diff --git a/src/librustc_error_codes/error_codes/E0500.md b/compiler/rustc_error_codes/src/error_codes/E0500.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0500.md rename to compiler/rustc_error_codes/src/error_codes/E0500.md diff --git a/src/librustc_error_codes/error_codes/E0501.md b/compiler/rustc_error_codes/src/error_codes/E0501.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0501.md rename to compiler/rustc_error_codes/src/error_codes/E0501.md diff --git a/src/librustc_error_codes/error_codes/E0502.md b/compiler/rustc_error_codes/src/error_codes/E0502.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0502.md rename to compiler/rustc_error_codes/src/error_codes/E0502.md diff --git a/src/librustc_error_codes/error_codes/E0503.md b/compiler/rustc_error_codes/src/error_codes/E0503.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0503.md rename to compiler/rustc_error_codes/src/error_codes/E0503.md diff --git a/src/librustc_error_codes/error_codes/E0504.md b/compiler/rustc_error_codes/src/error_codes/E0504.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0504.md rename to compiler/rustc_error_codes/src/error_codes/E0504.md diff --git a/src/librustc_error_codes/error_codes/E0505.md b/compiler/rustc_error_codes/src/error_codes/E0505.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0505.md rename to compiler/rustc_error_codes/src/error_codes/E0505.md diff --git a/src/librustc_error_codes/error_codes/E0506.md b/compiler/rustc_error_codes/src/error_codes/E0506.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0506.md rename to compiler/rustc_error_codes/src/error_codes/E0506.md diff --git a/src/librustc_error_codes/error_codes/E0507.md b/compiler/rustc_error_codes/src/error_codes/E0507.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0507.md rename to compiler/rustc_error_codes/src/error_codes/E0507.md diff --git a/src/librustc_error_codes/error_codes/E0508.md b/compiler/rustc_error_codes/src/error_codes/E0508.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0508.md rename to compiler/rustc_error_codes/src/error_codes/E0508.md diff --git a/src/librustc_error_codes/error_codes/E0509.md b/compiler/rustc_error_codes/src/error_codes/E0509.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0509.md rename to compiler/rustc_error_codes/src/error_codes/E0509.md diff --git a/src/librustc_error_codes/error_codes/E0510.md b/compiler/rustc_error_codes/src/error_codes/E0510.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0510.md rename to compiler/rustc_error_codes/src/error_codes/E0510.md diff --git a/src/librustc_error_codes/error_codes/E0511.md b/compiler/rustc_error_codes/src/error_codes/E0511.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0511.md rename to compiler/rustc_error_codes/src/error_codes/E0511.md diff --git a/src/librustc_error_codes/error_codes/E0512.md b/compiler/rustc_error_codes/src/error_codes/E0512.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0512.md rename to compiler/rustc_error_codes/src/error_codes/E0512.md diff --git a/src/librustc_error_codes/error_codes/E0515.md b/compiler/rustc_error_codes/src/error_codes/E0515.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0515.md rename to compiler/rustc_error_codes/src/error_codes/E0515.md diff --git a/src/librustc_error_codes/error_codes/E0516.md b/compiler/rustc_error_codes/src/error_codes/E0516.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0516.md rename to compiler/rustc_error_codes/src/error_codes/E0516.md diff --git a/src/librustc_error_codes/error_codes/E0517.md b/compiler/rustc_error_codes/src/error_codes/E0517.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0517.md rename to compiler/rustc_error_codes/src/error_codes/E0517.md diff --git a/src/librustc_error_codes/error_codes/E0518.md b/compiler/rustc_error_codes/src/error_codes/E0518.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0518.md rename to compiler/rustc_error_codes/src/error_codes/E0518.md diff --git a/src/librustc_error_codes/error_codes/E0520.md b/compiler/rustc_error_codes/src/error_codes/E0520.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0520.md rename to compiler/rustc_error_codes/src/error_codes/E0520.md diff --git a/src/librustc_error_codes/error_codes/E0522.md b/compiler/rustc_error_codes/src/error_codes/E0522.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0522.md rename to compiler/rustc_error_codes/src/error_codes/E0522.md diff --git a/src/librustc_error_codes/error_codes/E0524.md b/compiler/rustc_error_codes/src/error_codes/E0524.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0524.md rename to compiler/rustc_error_codes/src/error_codes/E0524.md diff --git a/src/librustc_error_codes/error_codes/E0525.md b/compiler/rustc_error_codes/src/error_codes/E0525.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0525.md rename to compiler/rustc_error_codes/src/error_codes/E0525.md diff --git a/src/librustc_error_codes/error_codes/E0527.md b/compiler/rustc_error_codes/src/error_codes/E0527.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0527.md rename to compiler/rustc_error_codes/src/error_codes/E0527.md diff --git a/src/librustc_error_codes/error_codes/E0528.md b/compiler/rustc_error_codes/src/error_codes/E0528.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0528.md rename to compiler/rustc_error_codes/src/error_codes/E0528.md diff --git a/src/librustc_error_codes/error_codes/E0529.md b/compiler/rustc_error_codes/src/error_codes/E0529.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0529.md rename to compiler/rustc_error_codes/src/error_codes/E0529.md diff --git a/src/librustc_error_codes/error_codes/E0530.md b/compiler/rustc_error_codes/src/error_codes/E0530.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0530.md rename to compiler/rustc_error_codes/src/error_codes/E0530.md diff --git a/src/librustc_error_codes/error_codes/E0531.md b/compiler/rustc_error_codes/src/error_codes/E0531.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0531.md rename to compiler/rustc_error_codes/src/error_codes/E0531.md diff --git a/src/librustc_error_codes/error_codes/E0532.md b/compiler/rustc_error_codes/src/error_codes/E0532.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0532.md rename to compiler/rustc_error_codes/src/error_codes/E0532.md diff --git a/src/librustc_error_codes/error_codes/E0533.md b/compiler/rustc_error_codes/src/error_codes/E0533.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0533.md rename to compiler/rustc_error_codes/src/error_codes/E0533.md diff --git a/src/librustc_error_codes/error_codes/E0534.md b/compiler/rustc_error_codes/src/error_codes/E0534.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0534.md rename to compiler/rustc_error_codes/src/error_codes/E0534.md diff --git a/src/librustc_error_codes/error_codes/E0535.md b/compiler/rustc_error_codes/src/error_codes/E0535.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0535.md rename to compiler/rustc_error_codes/src/error_codes/E0535.md diff --git a/src/librustc_error_codes/error_codes/E0536.md b/compiler/rustc_error_codes/src/error_codes/E0536.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0536.md rename to compiler/rustc_error_codes/src/error_codes/E0536.md diff --git a/src/librustc_error_codes/error_codes/E0537.md b/compiler/rustc_error_codes/src/error_codes/E0537.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0537.md rename to compiler/rustc_error_codes/src/error_codes/E0537.md diff --git a/src/librustc_error_codes/error_codes/E0538.md b/compiler/rustc_error_codes/src/error_codes/E0538.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0538.md rename to compiler/rustc_error_codes/src/error_codes/E0538.md diff --git a/src/librustc_error_codes/error_codes/E0539.md b/compiler/rustc_error_codes/src/error_codes/E0539.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0539.md rename to compiler/rustc_error_codes/src/error_codes/E0539.md diff --git a/src/librustc_error_codes/error_codes/E0541.md b/compiler/rustc_error_codes/src/error_codes/E0541.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0541.md rename to compiler/rustc_error_codes/src/error_codes/E0541.md diff --git a/src/librustc_error_codes/error_codes/E0550.md b/compiler/rustc_error_codes/src/error_codes/E0550.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0550.md rename to compiler/rustc_error_codes/src/error_codes/E0550.md diff --git a/src/librustc_error_codes/error_codes/E0551.md b/compiler/rustc_error_codes/src/error_codes/E0551.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0551.md rename to compiler/rustc_error_codes/src/error_codes/E0551.md diff --git a/src/librustc_error_codes/error_codes/E0552.md b/compiler/rustc_error_codes/src/error_codes/E0552.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0552.md rename to compiler/rustc_error_codes/src/error_codes/E0552.md diff --git a/src/librustc_error_codes/error_codes/E0554.md b/compiler/rustc_error_codes/src/error_codes/E0554.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0554.md rename to compiler/rustc_error_codes/src/error_codes/E0554.md diff --git a/src/librustc_error_codes/error_codes/E0556.md b/compiler/rustc_error_codes/src/error_codes/E0556.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0556.md rename to compiler/rustc_error_codes/src/error_codes/E0556.md diff --git a/src/librustc_error_codes/error_codes/E0557.md b/compiler/rustc_error_codes/src/error_codes/E0557.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0557.md rename to compiler/rustc_error_codes/src/error_codes/E0557.md diff --git a/src/librustc_error_codes/error_codes/E0559.md b/compiler/rustc_error_codes/src/error_codes/E0559.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0559.md rename to compiler/rustc_error_codes/src/error_codes/E0559.md diff --git a/src/librustc_error_codes/error_codes/E0560.md b/compiler/rustc_error_codes/src/error_codes/E0560.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0560.md rename to compiler/rustc_error_codes/src/error_codes/E0560.md diff --git a/src/librustc_error_codes/error_codes/E0561.md b/compiler/rustc_error_codes/src/error_codes/E0561.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0561.md rename to compiler/rustc_error_codes/src/error_codes/E0561.md diff --git a/src/librustc_error_codes/error_codes/E0562.md b/compiler/rustc_error_codes/src/error_codes/E0562.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0562.md rename to compiler/rustc_error_codes/src/error_codes/E0562.md diff --git a/src/librustc_error_codes/error_codes/E0565.md b/compiler/rustc_error_codes/src/error_codes/E0565.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0565.md rename to compiler/rustc_error_codes/src/error_codes/E0565.md diff --git a/src/librustc_error_codes/error_codes/E0566.md b/compiler/rustc_error_codes/src/error_codes/E0566.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0566.md rename to compiler/rustc_error_codes/src/error_codes/E0566.md diff --git a/src/librustc_error_codes/error_codes/E0567.md b/compiler/rustc_error_codes/src/error_codes/E0567.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0567.md rename to compiler/rustc_error_codes/src/error_codes/E0567.md diff --git a/src/librustc_error_codes/error_codes/E0568.md b/compiler/rustc_error_codes/src/error_codes/E0568.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0568.md rename to compiler/rustc_error_codes/src/error_codes/E0568.md diff --git a/src/librustc_error_codes/error_codes/E0569.md b/compiler/rustc_error_codes/src/error_codes/E0569.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0569.md rename to compiler/rustc_error_codes/src/error_codes/E0569.md diff --git a/src/librustc_error_codes/error_codes/E0570.md b/compiler/rustc_error_codes/src/error_codes/E0570.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0570.md rename to compiler/rustc_error_codes/src/error_codes/E0570.md diff --git a/src/librustc_error_codes/error_codes/E0571.md b/compiler/rustc_error_codes/src/error_codes/E0571.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0571.md rename to compiler/rustc_error_codes/src/error_codes/E0571.md diff --git a/src/librustc_error_codes/error_codes/E0572.md b/compiler/rustc_error_codes/src/error_codes/E0572.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0572.md rename to compiler/rustc_error_codes/src/error_codes/E0572.md diff --git a/src/librustc_error_codes/error_codes/E0573.md b/compiler/rustc_error_codes/src/error_codes/E0573.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0573.md rename to compiler/rustc_error_codes/src/error_codes/E0573.md diff --git a/src/librustc_error_codes/error_codes/E0574.md b/compiler/rustc_error_codes/src/error_codes/E0574.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0574.md rename to compiler/rustc_error_codes/src/error_codes/E0574.md diff --git a/src/librustc_error_codes/error_codes/E0575.md b/compiler/rustc_error_codes/src/error_codes/E0575.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0575.md rename to compiler/rustc_error_codes/src/error_codes/E0575.md diff --git a/src/librustc_error_codes/error_codes/E0576.md b/compiler/rustc_error_codes/src/error_codes/E0576.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0576.md rename to compiler/rustc_error_codes/src/error_codes/E0576.md diff --git a/src/librustc_error_codes/error_codes/E0577.md b/compiler/rustc_error_codes/src/error_codes/E0577.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0577.md rename to compiler/rustc_error_codes/src/error_codes/E0577.md diff --git a/src/librustc_error_codes/error_codes/E0578.md b/compiler/rustc_error_codes/src/error_codes/E0578.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0578.md rename to compiler/rustc_error_codes/src/error_codes/E0578.md diff --git a/src/librustc_error_codes/error_codes/E0579.md b/compiler/rustc_error_codes/src/error_codes/E0579.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0579.md rename to compiler/rustc_error_codes/src/error_codes/E0579.md diff --git a/src/librustc_error_codes/error_codes/E0580.md b/compiler/rustc_error_codes/src/error_codes/E0580.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0580.md rename to compiler/rustc_error_codes/src/error_codes/E0580.md diff --git a/src/librustc_error_codes/error_codes/E0581.md b/compiler/rustc_error_codes/src/error_codes/E0581.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0581.md rename to compiler/rustc_error_codes/src/error_codes/E0581.md diff --git a/src/librustc_error_codes/error_codes/E0582.md b/compiler/rustc_error_codes/src/error_codes/E0582.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0582.md rename to compiler/rustc_error_codes/src/error_codes/E0582.md diff --git a/src/librustc_error_codes/error_codes/E0583.md b/compiler/rustc_error_codes/src/error_codes/E0583.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0583.md rename to compiler/rustc_error_codes/src/error_codes/E0583.md diff --git a/src/librustc_error_codes/error_codes/E0584.md b/compiler/rustc_error_codes/src/error_codes/E0584.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0584.md rename to compiler/rustc_error_codes/src/error_codes/E0584.md diff --git a/src/librustc_error_codes/error_codes/E0585.md b/compiler/rustc_error_codes/src/error_codes/E0585.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0585.md rename to compiler/rustc_error_codes/src/error_codes/E0585.md diff --git a/src/librustc_error_codes/error_codes/E0586.md b/compiler/rustc_error_codes/src/error_codes/E0586.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0586.md rename to compiler/rustc_error_codes/src/error_codes/E0586.md diff --git a/src/librustc_error_codes/error_codes/E0587.md b/compiler/rustc_error_codes/src/error_codes/E0587.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0587.md rename to compiler/rustc_error_codes/src/error_codes/E0587.md diff --git a/src/librustc_error_codes/error_codes/E0588.md b/compiler/rustc_error_codes/src/error_codes/E0588.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0588.md rename to compiler/rustc_error_codes/src/error_codes/E0588.md diff --git a/src/librustc_error_codes/error_codes/E0589.md b/compiler/rustc_error_codes/src/error_codes/E0589.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0589.md rename to compiler/rustc_error_codes/src/error_codes/E0589.md diff --git a/src/librustc_error_codes/error_codes/E0590.md b/compiler/rustc_error_codes/src/error_codes/E0590.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0590.md rename to compiler/rustc_error_codes/src/error_codes/E0590.md diff --git a/src/librustc_error_codes/error_codes/E0591.md b/compiler/rustc_error_codes/src/error_codes/E0591.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0591.md rename to compiler/rustc_error_codes/src/error_codes/E0591.md diff --git a/src/librustc_error_codes/error_codes/E0592.md b/compiler/rustc_error_codes/src/error_codes/E0592.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0592.md rename to compiler/rustc_error_codes/src/error_codes/E0592.md diff --git a/src/librustc_error_codes/error_codes/E0593.md b/compiler/rustc_error_codes/src/error_codes/E0593.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0593.md rename to compiler/rustc_error_codes/src/error_codes/E0593.md diff --git a/src/librustc_error_codes/error_codes/E0594.md b/compiler/rustc_error_codes/src/error_codes/E0594.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0594.md rename to compiler/rustc_error_codes/src/error_codes/E0594.md diff --git a/src/librustc_error_codes/error_codes/E0595.md b/compiler/rustc_error_codes/src/error_codes/E0595.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0595.md rename to compiler/rustc_error_codes/src/error_codes/E0595.md diff --git a/src/librustc_error_codes/error_codes/E0596.md b/compiler/rustc_error_codes/src/error_codes/E0596.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0596.md rename to compiler/rustc_error_codes/src/error_codes/E0596.md diff --git a/src/librustc_error_codes/error_codes/E0597.md b/compiler/rustc_error_codes/src/error_codes/E0597.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0597.md rename to compiler/rustc_error_codes/src/error_codes/E0597.md diff --git a/src/librustc_error_codes/error_codes/E0599.md b/compiler/rustc_error_codes/src/error_codes/E0599.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0599.md rename to compiler/rustc_error_codes/src/error_codes/E0599.md diff --git a/src/librustc_error_codes/error_codes/E0600.md b/compiler/rustc_error_codes/src/error_codes/E0600.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0600.md rename to compiler/rustc_error_codes/src/error_codes/E0600.md diff --git a/src/librustc_error_codes/error_codes/E0601.md b/compiler/rustc_error_codes/src/error_codes/E0601.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0601.md rename to compiler/rustc_error_codes/src/error_codes/E0601.md diff --git a/src/librustc_error_codes/error_codes/E0602.md b/compiler/rustc_error_codes/src/error_codes/E0602.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0602.md rename to compiler/rustc_error_codes/src/error_codes/E0602.md diff --git a/src/librustc_error_codes/error_codes/E0603.md b/compiler/rustc_error_codes/src/error_codes/E0603.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0603.md rename to compiler/rustc_error_codes/src/error_codes/E0603.md diff --git a/src/librustc_error_codes/error_codes/E0604.md b/compiler/rustc_error_codes/src/error_codes/E0604.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0604.md rename to compiler/rustc_error_codes/src/error_codes/E0604.md diff --git a/src/librustc_error_codes/error_codes/E0605.md b/compiler/rustc_error_codes/src/error_codes/E0605.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0605.md rename to compiler/rustc_error_codes/src/error_codes/E0605.md diff --git a/src/librustc_error_codes/error_codes/E0606.md b/compiler/rustc_error_codes/src/error_codes/E0606.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0606.md rename to compiler/rustc_error_codes/src/error_codes/E0606.md diff --git a/src/librustc_error_codes/error_codes/E0607.md b/compiler/rustc_error_codes/src/error_codes/E0607.md similarity index 55% rename from src/librustc_error_codes/error_codes/E0607.md rename to compiler/rustc_error_codes/src/error_codes/E0607.md index ea6e10105b..0545246929 100644 --- a/src/librustc_error_codes/error_codes/E0607.md +++ b/compiler/rustc_error_codes/src/error_codes/E0607.md @@ -12,15 +12,15 @@ First: what are thin and fat pointers? Thin pointers are "simple" pointers: they are purely a reference to a memory address. -Fat pointers are pointers referencing Dynamically Sized Types (also called DST). -DST don't have a statically known size, therefore they can only exist behind -some kind of pointers that contain additional information. Slices and trait -objects are DSTs. In the case of slices, the additional information the fat -pointer holds is their size. +Fat pointers are pointers referencing Dynamically Sized Types (also called +DSTs). DSTs don't have a statically known size, therefore they can only exist +behind some kind of pointer that contains additional information. For example, +slices and trait objects are DSTs. In the case of slices, the additional +information the fat pointer holds is their size. To fix this error, don't try to cast directly between thin and fat pointers. -For more information about casts, take a look at the Type cast section in -[The Reference Book][1]. +For more information about type casts, take a look at the section of the +[The Rust Reference][1] on type cast expressions. [1]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#type-cast-expressions diff --git a/src/librustc_error_codes/error_codes/E0608.md b/compiler/rustc_error_codes/src/error_codes/E0608.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0608.md rename to compiler/rustc_error_codes/src/error_codes/E0608.md diff --git a/src/librustc_error_codes/error_codes/E0609.md b/compiler/rustc_error_codes/src/error_codes/E0609.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0609.md rename to compiler/rustc_error_codes/src/error_codes/E0609.md diff --git a/src/librustc_error_codes/error_codes/E0610.md b/compiler/rustc_error_codes/src/error_codes/E0610.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0610.md rename to compiler/rustc_error_codes/src/error_codes/E0610.md diff --git a/src/librustc_error_codes/error_codes/E0614.md b/compiler/rustc_error_codes/src/error_codes/E0614.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0614.md rename to compiler/rustc_error_codes/src/error_codes/E0614.md diff --git a/src/librustc_error_codes/error_codes/E0615.md b/compiler/rustc_error_codes/src/error_codes/E0615.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0615.md rename to compiler/rustc_error_codes/src/error_codes/E0615.md diff --git a/src/librustc_error_codes/error_codes/E0616.md b/compiler/rustc_error_codes/src/error_codes/E0616.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0616.md rename to compiler/rustc_error_codes/src/error_codes/E0616.md diff --git a/src/librustc_error_codes/error_codes/E0617.md b/compiler/rustc_error_codes/src/error_codes/E0617.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0617.md rename to compiler/rustc_error_codes/src/error_codes/E0617.md diff --git a/src/librustc_error_codes/error_codes/E0618.md b/compiler/rustc_error_codes/src/error_codes/E0618.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0618.md rename to compiler/rustc_error_codes/src/error_codes/E0618.md diff --git a/src/librustc_error_codes/error_codes/E0619.md b/compiler/rustc_error_codes/src/error_codes/E0619.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0619.md rename to compiler/rustc_error_codes/src/error_codes/E0619.md diff --git a/src/librustc_error_codes/error_codes/E0620.md b/compiler/rustc_error_codes/src/error_codes/E0620.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0620.md rename to compiler/rustc_error_codes/src/error_codes/E0620.md diff --git a/src/librustc_error_codes/error_codes/E0621.md b/compiler/rustc_error_codes/src/error_codes/E0621.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0621.md rename to compiler/rustc_error_codes/src/error_codes/E0621.md diff --git a/src/librustc_error_codes/error_codes/E0622.md b/compiler/rustc_error_codes/src/error_codes/E0622.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0622.md rename to compiler/rustc_error_codes/src/error_codes/E0622.md diff --git a/src/librustc_error_codes/error_codes/E0623.md b/compiler/rustc_error_codes/src/error_codes/E0623.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0623.md rename to compiler/rustc_error_codes/src/error_codes/E0623.md diff --git a/src/librustc_error_codes/error_codes/E0624.md b/compiler/rustc_error_codes/src/error_codes/E0624.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0624.md rename to compiler/rustc_error_codes/src/error_codes/E0624.md diff --git a/src/librustc_error_codes/error_codes/E0626.md b/compiler/rustc_error_codes/src/error_codes/E0626.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0626.md rename to compiler/rustc_error_codes/src/error_codes/E0626.md diff --git a/src/librustc_error_codes/error_codes/E0627.md b/compiler/rustc_error_codes/src/error_codes/E0627.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0627.md rename to compiler/rustc_error_codes/src/error_codes/E0627.md diff --git a/src/librustc_error_codes/error_codes/E0628.md b/compiler/rustc_error_codes/src/error_codes/E0628.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0628.md rename to compiler/rustc_error_codes/src/error_codes/E0628.md diff --git a/src/librustc_error_codes/error_codes/E0631.md b/compiler/rustc_error_codes/src/error_codes/E0631.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0631.md rename to compiler/rustc_error_codes/src/error_codes/E0631.md diff --git a/src/librustc_error_codes/error_codes/E0633.md b/compiler/rustc_error_codes/src/error_codes/E0633.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0633.md rename to compiler/rustc_error_codes/src/error_codes/E0633.md diff --git a/src/librustc_error_codes/error_codes/E0634.md b/compiler/rustc_error_codes/src/error_codes/E0634.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0634.md rename to compiler/rustc_error_codes/src/error_codes/E0634.md diff --git a/src/librustc_error_codes/error_codes/E0635.md b/compiler/rustc_error_codes/src/error_codes/E0635.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0635.md rename to compiler/rustc_error_codes/src/error_codes/E0635.md diff --git a/src/librustc_error_codes/error_codes/E0636.md b/compiler/rustc_error_codes/src/error_codes/E0636.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0636.md rename to compiler/rustc_error_codes/src/error_codes/E0636.md diff --git a/src/librustc_error_codes/error_codes/E0637.md b/compiler/rustc_error_codes/src/error_codes/E0637.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0637.md rename to compiler/rustc_error_codes/src/error_codes/E0637.md diff --git a/src/librustc_error_codes/error_codes/E0638.md b/compiler/rustc_error_codes/src/error_codes/E0638.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0638.md rename to compiler/rustc_error_codes/src/error_codes/E0638.md diff --git a/src/librustc_error_codes/error_codes/E0639.md b/compiler/rustc_error_codes/src/error_codes/E0639.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0639.md rename to compiler/rustc_error_codes/src/error_codes/E0639.md diff --git a/src/librustc_error_codes/error_codes/E0641.md b/compiler/rustc_error_codes/src/error_codes/E0641.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0641.md rename to compiler/rustc_error_codes/src/error_codes/E0641.md diff --git a/src/librustc_error_codes/error_codes/E0642.md b/compiler/rustc_error_codes/src/error_codes/E0642.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0642.md rename to compiler/rustc_error_codes/src/error_codes/E0642.md diff --git a/src/librustc_error_codes/error_codes/E0643.md b/compiler/rustc_error_codes/src/error_codes/E0643.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0643.md rename to compiler/rustc_error_codes/src/error_codes/E0643.md diff --git a/src/librustc_error_codes/error_codes/E0644.md b/compiler/rustc_error_codes/src/error_codes/E0644.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0644.md rename to compiler/rustc_error_codes/src/error_codes/E0644.md diff --git a/src/librustc_error_codes/error_codes/E0646.md b/compiler/rustc_error_codes/src/error_codes/E0646.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0646.md rename to compiler/rustc_error_codes/src/error_codes/E0646.md diff --git a/src/librustc_error_codes/error_codes/E0647.md b/compiler/rustc_error_codes/src/error_codes/E0647.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0647.md rename to compiler/rustc_error_codes/src/error_codes/E0647.md diff --git a/src/librustc_error_codes/error_codes/E0648.md b/compiler/rustc_error_codes/src/error_codes/E0648.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0648.md rename to compiler/rustc_error_codes/src/error_codes/E0648.md diff --git a/src/librustc_error_codes/error_codes/E0657.md b/compiler/rustc_error_codes/src/error_codes/E0657.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0657.md rename to compiler/rustc_error_codes/src/error_codes/E0657.md diff --git a/src/librustc_error_codes/error_codes/E0658.md b/compiler/rustc_error_codes/src/error_codes/E0658.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0658.md rename to compiler/rustc_error_codes/src/error_codes/E0658.md diff --git a/src/librustc_error_codes/error_codes/E0659.md b/compiler/rustc_error_codes/src/error_codes/E0659.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0659.md rename to compiler/rustc_error_codes/src/error_codes/E0659.md diff --git a/src/librustc_error_codes/error_codes/E0660.md b/compiler/rustc_error_codes/src/error_codes/E0660.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0660.md rename to compiler/rustc_error_codes/src/error_codes/E0660.md diff --git a/src/librustc_error_codes/error_codes/E0661.md b/compiler/rustc_error_codes/src/error_codes/E0661.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0661.md rename to compiler/rustc_error_codes/src/error_codes/E0661.md diff --git a/src/librustc_error_codes/error_codes/E0662.md b/compiler/rustc_error_codes/src/error_codes/E0662.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0662.md rename to compiler/rustc_error_codes/src/error_codes/E0662.md diff --git a/src/librustc_error_codes/error_codes/E0663.md b/compiler/rustc_error_codes/src/error_codes/E0663.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0663.md rename to compiler/rustc_error_codes/src/error_codes/E0663.md diff --git a/src/librustc_error_codes/error_codes/E0664.md b/compiler/rustc_error_codes/src/error_codes/E0664.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0664.md rename to compiler/rustc_error_codes/src/error_codes/E0664.md diff --git a/src/librustc_error_codes/error_codes/E0665.md b/compiler/rustc_error_codes/src/error_codes/E0665.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0665.md rename to compiler/rustc_error_codes/src/error_codes/E0665.md diff --git a/src/librustc_error_codes/error_codes/E0666.md b/compiler/rustc_error_codes/src/error_codes/E0666.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0666.md rename to compiler/rustc_error_codes/src/error_codes/E0666.md diff --git a/src/librustc_error_codes/error_codes/E0668.md b/compiler/rustc_error_codes/src/error_codes/E0668.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0668.md rename to compiler/rustc_error_codes/src/error_codes/E0668.md diff --git a/src/librustc_error_codes/error_codes/E0669.md b/compiler/rustc_error_codes/src/error_codes/E0669.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0669.md rename to compiler/rustc_error_codes/src/error_codes/E0669.md diff --git a/src/librustc_error_codes/error_codes/E0670.md b/compiler/rustc_error_codes/src/error_codes/E0670.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0670.md rename to compiler/rustc_error_codes/src/error_codes/E0670.md diff --git a/src/librustc_error_codes/error_codes/E0671.md b/compiler/rustc_error_codes/src/error_codes/E0671.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0671.md rename to compiler/rustc_error_codes/src/error_codes/E0671.md diff --git a/src/librustc_error_codes/error_codes/E0687.md b/compiler/rustc_error_codes/src/error_codes/E0687.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0687.md rename to compiler/rustc_error_codes/src/error_codes/E0687.md diff --git a/src/librustc_error_codes/error_codes/E0688.md b/compiler/rustc_error_codes/src/error_codes/E0688.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0688.md rename to compiler/rustc_error_codes/src/error_codes/E0688.md diff --git a/src/librustc_error_codes/error_codes/E0689.md b/compiler/rustc_error_codes/src/error_codes/E0689.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0689.md rename to compiler/rustc_error_codes/src/error_codes/E0689.md diff --git a/src/librustc_error_codes/error_codes/E0690.md b/compiler/rustc_error_codes/src/error_codes/E0690.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0690.md rename to compiler/rustc_error_codes/src/error_codes/E0690.md diff --git a/src/librustc_error_codes/error_codes/E0691.md b/compiler/rustc_error_codes/src/error_codes/E0691.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0691.md rename to compiler/rustc_error_codes/src/error_codes/E0691.md diff --git a/src/librustc_error_codes/error_codes/E0692.md b/compiler/rustc_error_codes/src/error_codes/E0692.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0692.md rename to compiler/rustc_error_codes/src/error_codes/E0692.md diff --git a/src/librustc_error_codes/error_codes/E0693.md b/compiler/rustc_error_codes/src/error_codes/E0693.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0693.md rename to compiler/rustc_error_codes/src/error_codes/E0693.md diff --git a/src/librustc_error_codes/error_codes/E0695.md b/compiler/rustc_error_codes/src/error_codes/E0695.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0695.md rename to compiler/rustc_error_codes/src/error_codes/E0695.md diff --git a/src/librustc_error_codes/error_codes/E0696.md b/compiler/rustc_error_codes/src/error_codes/E0696.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0696.md rename to compiler/rustc_error_codes/src/error_codes/E0696.md diff --git a/src/librustc_error_codes/error_codes/E0697.md b/compiler/rustc_error_codes/src/error_codes/E0697.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0697.md rename to compiler/rustc_error_codes/src/error_codes/E0697.md diff --git a/src/librustc_error_codes/error_codes/E0698.md b/compiler/rustc_error_codes/src/error_codes/E0698.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0698.md rename to compiler/rustc_error_codes/src/error_codes/E0698.md diff --git a/src/librustc_error_codes/error_codes/E0699.md b/compiler/rustc_error_codes/src/error_codes/E0699.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0699.md rename to compiler/rustc_error_codes/src/error_codes/E0699.md diff --git a/src/librustc_error_codes/error_codes/E0700.md b/compiler/rustc_error_codes/src/error_codes/E0700.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0700.md rename to compiler/rustc_error_codes/src/error_codes/E0700.md diff --git a/src/librustc_error_codes/error_codes/E0701.md b/compiler/rustc_error_codes/src/error_codes/E0701.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0701.md rename to compiler/rustc_error_codes/src/error_codes/E0701.md diff --git a/src/librustc_error_codes/error_codes/E0703.md b/compiler/rustc_error_codes/src/error_codes/E0703.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0703.md rename to compiler/rustc_error_codes/src/error_codes/E0703.md diff --git a/src/librustc_error_codes/error_codes/E0704.md b/compiler/rustc_error_codes/src/error_codes/E0704.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0704.md rename to compiler/rustc_error_codes/src/error_codes/E0704.md diff --git a/src/librustc_error_codes/error_codes/E0705.md b/compiler/rustc_error_codes/src/error_codes/E0705.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0705.md rename to compiler/rustc_error_codes/src/error_codes/E0705.md diff --git a/src/librustc_error_codes/error_codes/E0706.md b/compiler/rustc_error_codes/src/error_codes/E0706.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0706.md rename to compiler/rustc_error_codes/src/error_codes/E0706.md diff --git a/src/librustc_error_codes/error_codes/E0708.md b/compiler/rustc_error_codes/src/error_codes/E0708.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0708.md rename to compiler/rustc_error_codes/src/error_codes/E0708.md diff --git a/src/librustc_error_codes/error_codes/E0710.md b/compiler/rustc_error_codes/src/error_codes/E0710.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0710.md rename to compiler/rustc_error_codes/src/error_codes/E0710.md diff --git a/src/librustc_error_codes/error_codes/E0712.md b/compiler/rustc_error_codes/src/error_codes/E0712.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0712.md rename to compiler/rustc_error_codes/src/error_codes/E0712.md diff --git a/src/librustc_error_codes/error_codes/E0713.md b/compiler/rustc_error_codes/src/error_codes/E0713.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0713.md rename to compiler/rustc_error_codes/src/error_codes/E0713.md diff --git a/src/librustc_error_codes/error_codes/E0714.md b/compiler/rustc_error_codes/src/error_codes/E0714.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0714.md rename to compiler/rustc_error_codes/src/error_codes/E0714.md diff --git a/src/librustc_error_codes/error_codes/E0715.md b/compiler/rustc_error_codes/src/error_codes/E0715.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0715.md rename to compiler/rustc_error_codes/src/error_codes/E0715.md diff --git a/src/librustc_error_codes/error_codes/E0716.md b/compiler/rustc_error_codes/src/error_codes/E0716.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0716.md rename to compiler/rustc_error_codes/src/error_codes/E0716.md diff --git a/src/librustc_error_codes/error_codes/E0718.md b/compiler/rustc_error_codes/src/error_codes/E0718.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0718.md rename to compiler/rustc_error_codes/src/error_codes/E0718.md diff --git a/src/librustc_error_codes/error_codes/E0719.md b/compiler/rustc_error_codes/src/error_codes/E0719.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0719.md rename to compiler/rustc_error_codes/src/error_codes/E0719.md diff --git a/src/librustc_error_codes/error_codes/E0720.md b/compiler/rustc_error_codes/src/error_codes/E0720.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0720.md rename to compiler/rustc_error_codes/src/error_codes/E0720.md diff --git a/src/librustc_error_codes/error_codes/E0723.md b/compiler/rustc_error_codes/src/error_codes/E0723.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0723.md rename to compiler/rustc_error_codes/src/error_codes/E0723.md diff --git a/src/librustc_error_codes/error_codes/E0724.md b/compiler/rustc_error_codes/src/error_codes/E0724.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0724.md rename to compiler/rustc_error_codes/src/error_codes/E0724.md diff --git a/src/librustc_error_codes/error_codes/E0725.md b/compiler/rustc_error_codes/src/error_codes/E0725.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0725.md rename to compiler/rustc_error_codes/src/error_codes/E0725.md diff --git a/src/librustc_error_codes/error_codes/E0727.md b/compiler/rustc_error_codes/src/error_codes/E0727.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0727.md rename to compiler/rustc_error_codes/src/error_codes/E0727.md diff --git a/src/librustc_error_codes/error_codes/E0728.md b/compiler/rustc_error_codes/src/error_codes/E0728.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0728.md rename to compiler/rustc_error_codes/src/error_codes/E0728.md diff --git a/src/librustc_error_codes/error_codes/E0729.md b/compiler/rustc_error_codes/src/error_codes/E0729.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0729.md rename to compiler/rustc_error_codes/src/error_codes/E0729.md diff --git a/src/librustc_error_codes/error_codes/E0730.md b/compiler/rustc_error_codes/src/error_codes/E0730.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0730.md rename to compiler/rustc_error_codes/src/error_codes/E0730.md diff --git a/src/librustc_error_codes/error_codes/E0731.md b/compiler/rustc_error_codes/src/error_codes/E0731.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0731.md rename to compiler/rustc_error_codes/src/error_codes/E0731.md diff --git a/src/librustc_error_codes/error_codes/E0732.md b/compiler/rustc_error_codes/src/error_codes/E0732.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0732.md rename to compiler/rustc_error_codes/src/error_codes/E0732.md diff --git a/src/librustc_error_codes/error_codes/E0733.md b/compiler/rustc_error_codes/src/error_codes/E0733.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0733.md rename to compiler/rustc_error_codes/src/error_codes/E0733.md diff --git a/src/librustc_error_codes/error_codes/E0734.md b/compiler/rustc_error_codes/src/error_codes/E0734.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0734.md rename to compiler/rustc_error_codes/src/error_codes/E0734.md diff --git a/src/librustc_error_codes/error_codes/E0735.md b/compiler/rustc_error_codes/src/error_codes/E0735.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0735.md rename to compiler/rustc_error_codes/src/error_codes/E0735.md diff --git a/src/librustc_error_codes/error_codes/E0736.md b/compiler/rustc_error_codes/src/error_codes/E0736.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0736.md rename to compiler/rustc_error_codes/src/error_codes/E0736.md diff --git a/src/librustc_error_codes/error_codes/E0737.md b/compiler/rustc_error_codes/src/error_codes/E0737.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0737.md rename to compiler/rustc_error_codes/src/error_codes/E0737.md diff --git a/src/librustc_error_codes/error_codes/E0739.md b/compiler/rustc_error_codes/src/error_codes/E0739.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0739.md rename to compiler/rustc_error_codes/src/error_codes/E0739.md diff --git a/src/librustc_error_codes/error_codes/E0740.md b/compiler/rustc_error_codes/src/error_codes/E0740.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0740.md rename to compiler/rustc_error_codes/src/error_codes/E0740.md diff --git a/src/librustc_error_codes/error_codes/E0741.md b/compiler/rustc_error_codes/src/error_codes/E0741.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0741.md rename to compiler/rustc_error_codes/src/error_codes/E0741.md diff --git a/src/librustc_error_codes/error_codes/E0742.md b/compiler/rustc_error_codes/src/error_codes/E0742.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0742.md rename to compiler/rustc_error_codes/src/error_codes/E0742.md diff --git a/src/librustc_error_codes/error_codes/E0743.md b/compiler/rustc_error_codes/src/error_codes/E0743.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0743.md rename to compiler/rustc_error_codes/src/error_codes/E0743.md diff --git a/src/librustc_error_codes/error_codes/E0744.md b/compiler/rustc_error_codes/src/error_codes/E0744.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0744.md rename to compiler/rustc_error_codes/src/error_codes/E0744.md diff --git a/src/librustc_error_codes/error_codes/E0745.md b/compiler/rustc_error_codes/src/error_codes/E0745.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0745.md rename to compiler/rustc_error_codes/src/error_codes/E0745.md diff --git a/src/librustc_error_codes/error_codes/E0746.md b/compiler/rustc_error_codes/src/error_codes/E0746.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0746.md rename to compiler/rustc_error_codes/src/error_codes/E0746.md diff --git a/src/librustc_error_codes/error_codes/E0747.md b/compiler/rustc_error_codes/src/error_codes/E0747.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0747.md rename to compiler/rustc_error_codes/src/error_codes/E0747.md diff --git a/src/librustc_error_codes/error_codes/E0748.md b/compiler/rustc_error_codes/src/error_codes/E0748.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0748.md rename to compiler/rustc_error_codes/src/error_codes/E0748.md diff --git a/src/librustc_error_codes/error_codes/E0749.md b/compiler/rustc_error_codes/src/error_codes/E0749.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0749.md rename to compiler/rustc_error_codes/src/error_codes/E0749.md diff --git a/src/librustc_error_codes/error_codes/E0750.md b/compiler/rustc_error_codes/src/error_codes/E0750.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0750.md rename to compiler/rustc_error_codes/src/error_codes/E0750.md diff --git a/src/librustc_error_codes/error_codes/E0751.md b/compiler/rustc_error_codes/src/error_codes/E0751.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0751.md rename to compiler/rustc_error_codes/src/error_codes/E0751.md diff --git a/src/librustc_error_codes/error_codes/E0752.md b/compiler/rustc_error_codes/src/error_codes/E0752.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0752.md rename to compiler/rustc_error_codes/src/error_codes/E0752.md diff --git a/src/librustc_error_codes/error_codes/E0753.md b/compiler/rustc_error_codes/src/error_codes/E0753.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0753.md rename to compiler/rustc_error_codes/src/error_codes/E0753.md diff --git a/src/librustc_error_codes/error_codes/E0754.md b/compiler/rustc_error_codes/src/error_codes/E0754.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0754.md rename to compiler/rustc_error_codes/src/error_codes/E0754.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0755.md b/compiler/rustc_error_codes/src/error_codes/E0755.md new file mode 100644 index 0000000000..88b7f48496 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0755.md @@ -0,0 +1,28 @@ +The `ffi_pure` attribute was used on a non-foreign function. + +Erroneous code example: + +```compile_fail,E0755 +#![feature(ffi_pure)] + +#[ffi_pure] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_pure` attribute can only be used on foreign functions which do not have +side effects or infinite loops: + +``` +#![feature(ffi_pure)] + +extern "C" { + #[ffi_pure] // ok! + pub fn strlen(s: *const i8) -> isize; +} +# fn main() {} +``` + +You can find more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/unstable-book/language-features/ffi-pure.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0756.md b/compiler/rustc_error_codes/src/error_codes/E0756.md new file mode 100644 index 0000000000..ffdc421aab --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0756.md @@ -0,0 +1,29 @@ +The `ffi_const` attribute was used on something other than a foreign function +declaration. + +Erroneous code example: + +```compile_fail,E0756 +#![feature(ffi_const)] + +#[ffi_const] // error! +pub fn foo() {} +# fn main() {} +``` + +The `ffi_const` attribute can only be used on foreign function declarations +which have no side effects except for their return value: + +``` +#![feature(ffi_const)] + +extern "C" { + #[ffi_const] // ok! + pub fn strlen(s: *const i8) -> i32; +} +# fn main() {} +``` + +You can get more information about it in the [unstable Rust Book]. + +[unstable Rust Book]: https://doc.rust-lang.org/nightly/unstable-book/language-features/ffi-const.html diff --git a/src/librustc_error_codes/error_codes/E0758.md b/compiler/rustc_error_codes/src/error_codes/E0758.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0758.md rename to compiler/rustc_error_codes/src/error_codes/E0758.md diff --git a/src/librustc_error_codes/error_codes/E0759.md b/compiler/rustc_error_codes/src/error_codes/E0759.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0759.md rename to compiler/rustc_error_codes/src/error_codes/E0759.md diff --git a/src/librustc_error_codes/error_codes/E0760.md b/compiler/rustc_error_codes/src/error_codes/E0760.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0760.md rename to compiler/rustc_error_codes/src/error_codes/E0760.md diff --git a/src/librustc_error_codes/error_codes/E0761.md b/compiler/rustc_error_codes/src/error_codes/E0761.md similarity index 93% rename from src/librustc_error_codes/error_codes/E0761.md rename to compiler/rustc_error_codes/src/error_codes/E0761.md index c01574e413..e112674fbc 100644 --- a/src/librustc_error_codes/error_codes/E0761.md +++ b/compiler/rustc_error_codes/src/error_codes/E0761.md @@ -2,24 +2,20 @@ Multiple candidate files were found for an out-of-line module. Erroneous code example: -```rust +```ignore (multiple source files required for compile_fail) // file: ambiguous_module/mod.rs fn foo() {} -``` -```rust // file: ambiguous_module.rs fn foo() {} -``` -```ignore (multiple source files required for compile_fail) +// file: lib.rs + mod ambiguous_module; // error: file for module `ambiguous_module` // found at both ambiguous_module.rs and // ambiguous_module.rs/mod.rs - -fn main() {} ``` Please remove this ambiguity by deleting/renaming one of the candidate files. diff --git a/src/librustc_error_codes/error_codes/E0762.md b/compiler/rustc_error_codes/src/error_codes/E0762.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0762.md rename to compiler/rustc_error_codes/src/error_codes/E0762.md diff --git a/src/librustc_error_codes/error_codes/E0763.md b/compiler/rustc_error_codes/src/error_codes/E0763.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0763.md rename to compiler/rustc_error_codes/src/error_codes/E0763.md diff --git a/src/librustc_error_codes/error_codes/E0764.md b/compiler/rustc_error_codes/src/error_codes/E0764.md similarity index 60% rename from src/librustc_error_codes/error_codes/E0764.md rename to compiler/rustc_error_codes/src/error_codes/E0764.md index e9061f988a..0a2e2290e7 100644 --- a/src/librustc_error_codes/error_codes/E0764.md +++ b/compiler/rustc_error_codes/src/error_codes/E0764.md @@ -1,12 +1,4 @@ -Mutable references (`&mut`) can only be used in constant functions, not statics -or constants. This limitation exists to prevent the creation of constants that -have a mutable reference in their final value. If you had a constant of `&mut -i32` type, you could modify the value through that reference, making the -constant essentially mutable. While there could be a more fine-grained scheme -in the future that allows mutable references if they are not "leaked" to the -final value, a more conservative approach was chosen for now. `const fn` do not -have this problem, as the borrow checker will prevent the `const fn` from -returning new mutable references. +A mutable reference was used in a constant. Erroneous code example: @@ -19,6 +11,18 @@ fn main() { } ``` +Mutable references (`&mut`) can only be used in constant functions, not statics +or constants. This limitation exists to prevent the creation of constants that +have a mutable reference in their final value. If you had a constant of +`&mut i32` type, you could modify the value through that reference, making the +constant essentially mutable. + +While there could be a more fine-grained scheme in the future that allows +mutable references if they are not "leaked" to the final value, a more +conservative approach was chosen for now. `const fn` do not have this problem, +as the borrow checker will prevent the `const fn` from returning new mutable +references. + Remember: you cannot use a function call inside a constant or static. However, you can totally use it in constant functions: diff --git a/src/librustc_error_codes/error_codes/E0765.md b/compiler/rustc_error_codes/src/error_codes/E0765.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0765.md rename to compiler/rustc_error_codes/src/error_codes/E0765.md diff --git a/src/librustc_error_codes/error_codes/E0766.md b/compiler/rustc_error_codes/src/error_codes/E0766.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0766.md rename to compiler/rustc_error_codes/src/error_codes/E0766.md diff --git a/src/librustc_error_codes/error_codes/E0767.md b/compiler/rustc_error_codes/src/error_codes/E0767.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0767.md rename to compiler/rustc_error_codes/src/error_codes/E0767.md diff --git a/src/librustc_error_codes/error_codes/E0768.md b/compiler/rustc_error_codes/src/error_codes/E0768.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0768.md rename to compiler/rustc_error_codes/src/error_codes/E0768.md diff --git a/src/librustc_error_codes/error_codes/E0769.md b/compiler/rustc_error_codes/src/error_codes/E0769.md similarity index 58% rename from src/librustc_error_codes/error_codes/E0769.md rename to compiler/rustc_error_codes/src/error_codes/E0769.md index d1995be989..4a3b674b05 100644 --- a/src/librustc_error_codes/error_codes/E0769.md +++ b/compiler/rustc_error_codes/src/error_codes/E0769.md @@ -1,5 +1,5 @@ -A tuple struct or tuple variant was used in a pattern as if it were a -struct or struct variant. +A tuple struct or tuple variant was used in a pattern as if it were a struct or +struct variant. Erroneous code example: @@ -7,9 +7,13 @@ Erroneous code example: enum E { A(i32), } + let e = E::A(42); + match e { - E::A { number } => println!("{}", x), + E::A { number } => { // error! + println!("{}", number); + } } ``` @@ -21,12 +25,14 @@ To fix this error, you can use the tuple pattern: # } # let e = E::A(42); match e { - E::A(number) => println!("{}", number), + E::A(number) => { // ok! + println!("{}", number); + } } ``` -Alternatively, you can also use the struct pattern by using the correct -field names and binding them to new identifiers: +Alternatively, you can also use the struct pattern by using the correct field +names and binding them to new identifiers: ``` # enum E { @@ -34,6 +40,8 @@ field names and binding them to new identifiers: # } # let e = E::A(42); match e { - E::A { 0: number } => println!("{}", number), + E::A { 0: number } => { // ok! + println!("{}", number); + } } ``` diff --git a/src/librustc_error_codes/error_codes/E0770.md b/compiler/rustc_error_codes/src/error_codes/E0770.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0770.md rename to compiler/rustc_error_codes/src/error_codes/E0770.md diff --git a/src/librustc_error_codes/error_codes/E0771.md b/compiler/rustc_error_codes/src/error_codes/E0771.md similarity index 100% rename from src/librustc_error_codes/error_codes/E0771.md rename to compiler/rustc_error_codes/src/error_codes/E0771.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0773.md b/compiler/rustc_error_codes/src/error_codes/E0773.md new file mode 100644 index 0000000000..b19a58bf33 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0773.md @@ -0,0 +1,38 @@ +A builtin-macro was defined more than once. + +Erroneous code example: + +```compile_fail,E0773 +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + /* compiler built-in */ + } +} +``` + +To fix the issue, remove the duplicate declaration: + +``` +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { + /* compiler built-in */ +} +``` + +In very rare edge cases, this may happen when loading `core` or `std` twice, +once with `check` metadata and once with `build` metadata. +For more information, see [#75176]. + +[#75176]: https://github.com/rust-lang/rust/pull/75176#issuecomment-683234468 diff --git a/compiler/rustc_error_codes/src/error_codes/E0774.md b/compiler/rustc_error_codes/src/error_codes/E0774.md new file mode 100644 index 0000000000..79793ba9d7 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0774.md @@ -0,0 +1,24 @@ +`derive` was applied on something which is not a struct, a union or an enum. + +Erroneous code example: + +```compile_fail,E0774 +trait Foo { + #[derive(Clone)] // error! + type Bar; +} +``` + +As said above, the `derive` attribute is only allowed on structs, unions or +enums: + +``` +#[derive(Clone)] // ok! +struct Bar { + field: u32, +} +``` + +You can find more information about `derive` in the [Rust Book]. + +[Rust Book]: https://doc.rust-lang.org/book/appendix-03-derivable-traits.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0775.md b/compiler/rustc_error_codes/src/error_codes/E0775.md new file mode 100644 index 0000000000..9bafd52f75 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0775.md @@ -0,0 +1,17 @@ +`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M +extension. + +Erroneous code example: + +```compile_fail,E0775 +#![feature(cmse_nonsecure_entry)] + +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function() {} +``` + +To fix this error, compile your code for a Rust target that supports the +TrustZone-M extension. The current possible targets are: +* `thumbv8m.main-none-eabi` +* `thumbv8m.main-none-eabihf` +* `thumbv8m.base-none-eabi` diff --git a/compiler/rustc_error_codes/src/error_codes/E0776.md b/compiler/rustc_error_codes/src/error_codes/E0776.md new file mode 100644 index 0000000000..d65beebe07 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0776.md @@ -0,0 +1,13 @@ +`#[cmse_nonsecure_entry]` functions require a C ABI + +Erroneous code example: + +```compile_fail,E0776 +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub fn entry_function(input: Vec) {} +``` + +To fix this error, declare your entry function with a C ABI, using `extern "C"`. diff --git a/src/librustc_error_codes/lib.rs b/compiler/rustc_error_codes/src/lib.rs similarity index 100% rename from src/librustc_error_codes/lib.rs rename to compiler/rustc_error_codes/src/lib.rs diff --git a/src/librustc_errors/Cargo.toml b/compiler/rustc_errors/Cargo.toml similarity index 60% rename from src/librustc_errors/Cargo.toml rename to compiler/rustc_errors/Cargo.toml index 7c794bcd98..e4dbb8db38 100644 --- a/src/librustc_errors/Cargo.toml +++ b/compiler/rustc_errors/Cargo.toml @@ -5,16 +5,14 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustc_errors" -path = "lib.rs" doctest = false [dependencies] tracing = "0.1" -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_macros = { path = "../rustc_macros" } +rustc_data_structures = { path = "../rustc_data_structures" } unicode-width = "0.1.4" atty = "0.2" termcolor = "1.0" diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs similarity index 100% rename from src/librustc_errors/annotate_snippet_emitter_writer.rs rename to compiler/rustc_errors/src/annotate_snippet_emitter_writer.rs diff --git a/src/librustc_errors/diagnostic.rs b/compiler/rustc_errors/src/diagnostic.rs similarity index 100% rename from src/librustc_errors/diagnostic.rs rename to compiler/rustc_errors/src/diagnostic.rs diff --git a/src/librustc_errors/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs similarity index 100% rename from src/librustc_errors/diagnostic_builder.rs rename to compiler/rustc_errors/src/diagnostic_builder.rs diff --git a/src/librustc_errors/emitter.rs b/compiler/rustc_errors/src/emitter.rs similarity index 99% rename from src/librustc_errors/emitter.rs rename to compiler/rustc_errors/src/emitter.rs index 4555168af0..98cbf98df9 100644 --- a/src/librustc_errors/emitter.rs +++ b/compiler/rustc_errors/src/emitter.rs @@ -1227,18 +1227,14 @@ impl EmitterWriter { } draw_note_separator(&mut buffer, 0, max_line_num_len + 1); if *level != Level::FailureNote { - let level_str = level.to_string(); - if !level_str.is_empty() { - buffer.append(0, &level_str, Style::MainHeaderMsg); - buffer.append(0, ": ", Style::NoStyle); - } + buffer.append(0, level.to_str(), Style::MainHeaderMsg); + buffer.append(0, ": ", Style::NoStyle); } self.msg_to_buffer(&mut buffer, msg, max_line_num_len, "note", None); } else { - let level_str = level.to_string(); // The failure note level itself does not provide any useful diagnostic information - if *level != Level::FailureNote && !level_str.is_empty() { - buffer.append(0, &level_str, Style::Level(*level)); + if *level != Level::FailureNote { + buffer.append(0, level.to_str(), Style::Level(*level)); } // only render error codes, not lint codes if let Some(DiagnosticId::Error(ref code)) = *code { @@ -1246,7 +1242,7 @@ impl EmitterWriter { buffer.append(0, &code, Style::Level(*level)); buffer.append(0, "]", Style::Level(*level)); } - if *level != Level::FailureNote && !level_str.is_empty() { + if *level != Level::FailureNote { buffer.append(0, ": ", header_style); } for &(ref text, _) in msg.iter() { @@ -1548,11 +1544,9 @@ impl EmitterWriter { let mut buffer = StyledBuffer::new(); // Render the suggestion message - let level_str = level.to_string(); - if !level_str.is_empty() { - buffer.append(0, &level_str, Style::Level(*level)); - buffer.append(0, ": ", Style::HeaderMsg); - } + buffer.append(0, level.to_str(), Style::Level(*level)); + buffer.append(0, ": ", Style::HeaderMsg); + self.msg_to_buffer( &mut buffer, &[(suggestion.msg.to_owned(), Style::NoStyle)], diff --git a/src/librustc_errors/json.rs b/compiler/rustc_errors/src/json.rs similarity index 100% rename from src/librustc_errors/json.rs rename to compiler/rustc_errors/src/json.rs diff --git a/src/librustc_errors/json/tests.rs b/compiler/rustc_errors/src/json/tests.rs similarity index 100% rename from src/librustc_errors/json/tests.rs rename to compiler/rustc_errors/src/json/tests.rs diff --git a/src/librustc_errors/lib.rs b/compiler/rustc_errors/src/lib.rs similarity index 94% rename from src/librustc_errors/lib.rs rename to compiler/rustc_errors/src/lib.rs index d4f0a9d83e..2e8a4ef327 100644 --- a/src/librustc_errors/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -2,8 +2,9 @@ //! //! This module contains the code for creating and emitting diagnostics. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(crate_visibility_modifier)] +#![feature(backtrace)] #![feature(nll)] #[macro_use] @@ -296,9 +297,11 @@ struct HandlerInner { /// This is not necessarily the count that's reported to the user once /// compilation ends. err_count: usize, + warn_count: usize, deduplicated_err_count: usize, emitter: Box, delayed_span_bugs: Vec, + delayed_good_path_bugs: Vec, /// This set contains the `DiagnosticId` of all emitted diagnostics to avoid /// emitting the same diagnostic with extended help (`--teach`) twice, which @@ -361,13 +364,15 @@ impl Drop for HandlerInner { if !self.has_errors() { let bugs = std::mem::replace(&mut self.delayed_span_bugs, Vec::new()); - let has_bugs = !bugs.is_empty(); - for bug in bugs { - self.emit_diagnostic(&bug); - } - if has_bugs { - panic!("no errors encountered even though `delay_span_bug` issued"); - } + self.flush_delayed(bugs, "no errors encountered even though `delay_span_bug` issued"); + } + + if !self.has_any_message() { + let bugs = std::mem::replace(&mut self.delayed_good_path_bugs, Vec::new()); + self.flush_delayed( + bugs, + "no warnings or errors encountered even though `delayed_good_path_bugs` issued", + ); } } } @@ -422,10 +427,12 @@ impl Handler { inner: Lock::new(HandlerInner { flags, err_count: 0, + warn_count: 0, deduplicated_err_count: 0, deduplicated_warn_count: 0, emitter, delayed_span_bugs: Vec::new(), + delayed_good_path_bugs: Vec::new(), taught_diagnostics: Default::default(), emitted_diagnostic_codes: Default::default(), emitted_diagnostics: Default::default(), @@ -448,11 +455,13 @@ impl Handler { pub fn reset_err_count(&self) { let mut inner = self.inner.borrow_mut(); inner.err_count = 0; + inner.warn_count = 0; inner.deduplicated_err_count = 0; inner.deduplicated_warn_count = 0; // actually free the underlying memory (which `clear` would not do) inner.delayed_span_bugs = Default::default(); + inner.delayed_good_path_bugs = Default::default(); inner.taught_diagnostics = Default::default(); inner.emitted_diagnostic_codes = Default::default(); inner.emitted_diagnostics = Default::default(); @@ -629,6 +638,10 @@ impl Handler { self.inner.borrow_mut().delay_span_bug(span, msg) } + pub fn delay_good_path_bug(&self, msg: &str) { + self.inner.borrow_mut().delay_good_path_bug(msg) + } + pub fn span_bug_no_panic(&self, span: impl Into, msg: &str) { self.emit_diag_at_span(Diagnostic::new(Bug, msg), span); } @@ -768,6 +781,8 @@ impl HandlerInner { } if diagnostic.is_error() { self.bump_err_count(); + } else { + self.bump_warn_count(); } } @@ -859,6 +874,9 @@ impl HandlerInner { fn has_errors_or_delayed_span_bugs(&self) -> bool { self.has_errors() || !self.delayed_span_bugs.is_empty() } + fn has_any_message(&self) -> bool { + self.err_count() > 0 || self.warn_count > 0 + } fn abort_if_errors(&mut self) { self.emit_stashed_diagnostics(); @@ -892,6 +910,15 @@ impl HandlerInner { self.delay_as_bug(diagnostic) } + fn delay_good_path_bug(&mut self, msg: &str) { + let mut diagnostic = Diagnostic::new(Level::Bug, msg); + if self.flags.report_delayed_bugs { + self.emit_diagnostic(&diagnostic); + } + diagnostic.note(&format!("delayed at {}", std::backtrace::Backtrace::force_capture())); + self.delayed_good_path_bugs.push(diagnostic); + } + fn failure(&mut self, msg: &str) { self.emit_diagnostic(&Diagnostic::new(FailureNote, msg)); } @@ -925,23 +952,35 @@ impl HandlerInner { self.delayed_span_bugs.push(diagnostic); } + fn flush_delayed(&mut self, bugs: Vec, explanation: &str) { + let has_bugs = !bugs.is_empty(); + for bug in bugs { + self.emit_diagnostic(&bug); + } + if has_bugs { + panic!("{}", explanation); + } + } + fn bump_err_count(&mut self) { self.err_count += 1; self.panic_if_treat_err_as_bug(); } + fn bump_warn_count(&mut self) { + self.warn_count += 1; + } + fn panic_if_treat_err_as_bug(&self) { if self.treat_err_as_bug() { - let s = match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { - (0, _) => return, - (1, 1) => "aborting due to `-Z treat-err-as-bug=1`".to_string(), - (1, _) => return, - (count, as_bug) => format!( + match (self.err_count(), self.flags.treat_err_as_bug.unwrap_or(0)) { + (1, 1) => panic!("aborting due to `-Z treat-err-as-bug=1`"), + (0, _) | (1, _) => {} + (count, as_bug) => panic!( "aborting after {} errors due to `-Z treat-err-as-bug={}`", count, as_bug, ), - }; - panic!(s); + } } } } diff --git a/src/librustc_errors/lock.rs b/compiler/rustc_errors/src/lock.rs similarity index 100% rename from src/librustc_errors/lock.rs rename to compiler/rustc_errors/src/lock.rs diff --git a/src/librustc_errors/registry.rs b/compiler/rustc_errors/src/registry.rs similarity index 100% rename from src/librustc_errors/registry.rs rename to compiler/rustc_errors/src/registry.rs diff --git a/src/librustc_errors/snippet.rs b/compiler/rustc_errors/src/snippet.rs similarity index 96% rename from src/librustc_errors/snippet.rs rename to compiler/rustc_errors/src/snippet.rs index 160bf57779..fae5b94b3a 100644 --- a/src/librustc_errors/snippet.rs +++ b/compiler/rustc_errors/src/snippet.rs @@ -118,17 +118,15 @@ pub struct Annotation { impl Annotation { /// Whether this annotation is a vertical line placeholder. pub fn is_line(&self) -> bool { - if let AnnotationType::MultilineLine(_) = self.annotation_type { true } else { false } + matches!(self.annotation_type, AnnotationType::MultilineLine(_)) } pub fn is_multiline(&self) -> bool { - match self.annotation_type { + matches!(self.annotation_type, AnnotationType::Multiline(_) | AnnotationType::MultilineStart(_) | AnnotationType::MultilineLine(_) - | AnnotationType::MultilineEnd(_) => true, - _ => false, - } + | AnnotationType::MultilineEnd(_)) } pub fn len(&self) -> usize { diff --git a/src/librustc_errors/styled_buffer.rs b/compiler/rustc_errors/src/styled_buffer.rs similarity index 100% rename from src/librustc_errors/styled_buffer.rs rename to compiler/rustc_errors/src/styled_buffer.rs diff --git a/compiler/rustc_expand/Cargo.toml b/compiler/rustc_expand/Cargo.toml new file mode 100644 index 0000000000..25c2851f6d --- /dev/null +++ b/compiler/rustc_expand/Cargo.toml @@ -0,0 +1,26 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_expand" +version = "0.0.0" +edition = "2018" +build = false + +[lib] +doctest = false + +[dependencies] +rustc_serialize = { path = "../rustc_serialize" } +tracing = "0.1" +rustc_span = { path = "../rustc_span" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_ast_passes = { path = "../rustc_ast_passes" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_macros = { path = "../rustc_macros" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_parse = { path = "../rustc_parse" } +rustc_session = { path = "../rustc_session" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_expand/base.rs b/compiler/rustc_expand/src/base.rs similarity index 97% rename from src/librustc_expand/base.rs rename to compiler/rustc_expand/src/base.rs index 4c01cb8159..f7651ca0ba 100644 --- a/src/librustc_expand/base.rs +++ b/compiler/rustc_expand/src/base.rs @@ -1,10 +1,9 @@ use crate::expand::{self, AstFragment, Invocation}; use crate::module::DirectoryOwnership; -use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::ptr::P; use rustc_ast::token; -use rustc_ast::tokenstream::{self, TokenStream}; +use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{AssocCtxt, Visitor}; use rustc_ast::{self as ast, Attribute, NodeId, PatKind}; use rustc_attr::{self as attr, Deprecation, HasAttrs, Stability}; @@ -313,7 +312,7 @@ where ts: TokenStream, ) -> Result { // FIXME setup implicit context in TLS before calling self. - Ok((*self)(ts)) + Ok(self(ts)) } } @@ -339,7 +338,7 @@ where annotated: TokenStream, ) -> Result { // FIXME setup implicit context in TLS before calling self. - Ok((*self)(annotation, annotated)) + Ok(self(annotation, annotated)) } } @@ -364,31 +363,9 @@ where &self, ecx: &'cx mut ExtCtxt<'_>, span: Span, - mut input: TokenStream, + input: TokenStream, ) -> Box { - struct AvoidInterpolatedIdents; - - impl MutVisitor for AvoidInterpolatedIdents { - fn visit_tt(&mut self, tt: &mut tokenstream::TokenTree) { - if let tokenstream::TokenTree::Token(token) = tt { - if let token::Interpolated(nt) = &token.kind { - if let token::NtIdent(ident, is_raw) = **nt { - *tt = tokenstream::TokenTree::token( - token::Ident(ident.name, is_raw), - ident.span, - ); - } - } - } - mut_visit::noop_visit_tt(tt, self) - } - - fn visit_mac(&mut self, mac: &mut ast::MacCall) { - mut_visit::noop_visit_mac(mac, self) - } - } - AvoidInterpolatedIdents.visit_tts(&mut input); - (*self)(ecx, span, input) + self(ecx, span, input) } } @@ -400,6 +377,7 @@ macro_rules! make_stmts_default { id: ast::DUMMY_NODE_ID, span: e.span, kind: ast::StmtKind::Expr(e), + tokens: None }] }) }; @@ -607,6 +585,7 @@ impl DummyResult { id: ast::DUMMY_NODE_ID, kind: if is_error { ast::TyKind::Err } else { ast::TyKind::Tup(Vec::new()) }, span: sp, + tokens: None, }) } } @@ -641,6 +620,7 @@ impl MacResult for DummyResult { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Expr(DummyResult::raw_expr(self.span, self.is_error)), span: self.span, + tokens: None }]) } diff --git a/src/librustc_expand/build.rs b/compiler/rustc_expand/src/build.rs similarity index 93% rename from src/librustc_expand/build.rs rename to compiler/rustc_expand/src/build.rs index 9490b62aa1..a5a7ee6c9a 100644 --- a/src/librustc_expand/build.rs +++ b/compiler/rustc_expand/src/build.rs @@ -3,7 +3,7 @@ use crate::base::ExtCtxt; use rustc_ast::attr; use rustc_ast::ptr::P; use rustc_ast::{self as ast, AttrVec, BlockCheckMode, Expr, PatKind, UnOp}; -use rustc_span::source_map::{respan, Spanned}; +use rustc_span::source_map::Spanned; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::Span; @@ -46,7 +46,7 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, args, }); - ast::Path { span, segments } + ast::Path { span, segments, tokens: None } } pub fn ty_mt(&self, ty: P, mutbl: ast::Mutability) -> ast::MutTy { @@ -54,7 +54,7 @@ impl<'a> ExtCtxt<'a> { } pub fn ty(&self, span: Span, kind: ast::TyKind) -> P { - P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind }) + P(ast::Ty { id: ast::DUMMY_NODE_ID, span, kind, tokens: None }) } pub fn ty_path(&self, path: ast::Path) -> P { @@ -158,7 +158,12 @@ impl<'a> ExtCtxt<'a> { } pub fn stmt_expr(&self, expr: P) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr) } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + span: expr.span, + kind: ast::StmtKind::Expr(expr), + tokens: None, + } } pub fn stmt_let(&self, sp: Span, mutbl: bool, ident: Ident, ex: P) -> ast::Stmt { @@ -176,7 +181,12 @@ impl<'a> ExtCtxt<'a> { span: sp, attrs: AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span: sp } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Local(local), + span: sp, + tokens: None, + } } // Generates `let _: Type;`, which is usually used for type assertions. @@ -189,11 +199,16 @@ impl<'a> ExtCtxt<'a> { span, attrs: AttrVec::new(), }); - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span } + ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Local(local), span, tokens: None } } pub fn stmt_item(&self, sp: Span, item: P) -> ast::Stmt { - ast::Stmt { id: ast::DUMMY_NODE_ID, kind: ast::StmtKind::Item(item), span: sp } + ast::Stmt { + id: ast::DUMMY_NODE_ID, + kind: ast::StmtKind::Item(item), + span: sp, + tokens: None, + } } pub fn block_expr(&self, expr: P) -> P { @@ -203,11 +218,18 @@ impl<'a> ExtCtxt<'a> { id: ast::DUMMY_NODE_ID, span: expr.span, kind: ast::StmtKind::Expr(expr), + tokens: None, }], ) } pub fn block(&self, span: Span, stmts: Vec) -> P { - P(ast::Block { stmts, id: ast::DUMMY_NODE_ID, rules: BlockCheckMode::Default, span }) + P(ast::Block { + stmts, + id: ast::DUMMY_NODE_ID, + rules: BlockCheckMode::Default, + span, + tokens: None, + }) } pub fn expr(&self, span: Span, kind: ast::ExprKind) -> P { @@ -578,7 +600,11 @@ impl<'a> ExtCtxt<'a> { attrs, id: ast::DUMMY_NODE_ID, kind, - vis: respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span, tokens: None, }) @@ -592,7 +618,11 @@ impl<'a> ExtCtxt<'a> { span: ty.span, ty, ident: None, - vis: respan(vis_span, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: vis_span, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, attrs: Vec::new(), id: ast::DUMMY_NODE_ID, is_placeholder: false, @@ -611,7 +641,11 @@ impl<'a> ExtCtxt<'a> { disr_expr: None, id: ast::DUMMY_NODE_ID, ident, - vis: respan(vis_span, ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: vis_span, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, span, is_placeholder: false, } diff --git a/src/librustc_expand/config.rs b/compiler/rustc_expand/src/config.rs similarity index 98% rename from src/librustc_expand/config.rs rename to compiler/rustc_expand/src/config.rs index afd1e60640..dd087ab915 100644 --- a/src/librustc_expand/config.rs +++ b/compiler/rustc_expand/src/config.rs @@ -399,14 +399,10 @@ impl<'a> StripUnconfigured<'a> { } pub fn configure_foreign_mod(&mut self, foreign_mod: &mut ast::ForeignMod) { - let ast::ForeignMod { abi: _, items } = foreign_mod; + let ast::ForeignMod { unsafety: _, abi: _, items } = foreign_mod; items.flat_map_in_place(|item| self.configure(item)); } - pub fn configure_generic_params(&mut self, params: &mut Vec) { - params.flat_map_in_place(|param| self.configure(param)); - } - fn configure_variant_data(&mut self, vdata: &mut ast::VariantData) { match vdata { ast::VariantData::Struct(fields, ..) | ast::VariantData::Tuple(fields, _) => { @@ -496,6 +492,13 @@ impl<'a> MutVisitor for StripUnconfigured<'a> { Some(expr) } + fn flat_map_generic_param( + &mut self, + param: ast::GenericParam, + ) -> SmallVec<[ast::GenericParam; 1]> { + noop_flat_map_generic_param(configure!(self, param), self) + } + fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { noop_flat_map_stmt(configure!(self, stmt), self) } diff --git a/src/librustc_expand/expand.rs b/compiler/rustc_expand/src/expand.rs similarity index 97% rename from src/librustc_expand/expand.rs rename to compiler/rustc_expand/src/expand.rs index 7a21caf255..e5cfb86693 100644 --- a/src/librustc_expand/expand.rs +++ b/compiler/rustc_expand/src/expand.rs @@ -13,7 +13,7 @@ use rustc_ast::token; use rustc_ast::tokenstream::TokenStream; use rustc_ast::visit::{self, AssocCtxt, Visitor}; use rustc_ast::{self as ast, AttrItem, Block, LitKind, NodeId, PatKind, Path}; -use rustc_ast::{ItemKind, MacArgs, MacStmtStyle, StmtKind}; +use rustc_ast::{ItemKind, MacArgs, MacCallStmt, MacStmtStyle, StmtKind, Unsafe}; use rustc_ast_pretty::pprust; use rustc_attr::{self as attr, is_builtin_attr, HasAttrs}; use rustc_data_structures::map_in_place::MapInPlace; @@ -26,7 +26,6 @@ use rustc_session::lint::builtin::UNUSED_DOC_COMMENTS; use rustc_session::lint::BuiltinLintDiagnostics; use rustc_session::parse::{feature_err, ParseSess}; use rustc_session::Limit; -use rustc_span::source_map::respan; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{ExpnId, FileName, Span, DUMMY_SP}; @@ -358,7 +357,11 @@ impl<'a, 'b> MacroExpander<'a, 'b> { kind: ast::ItemKind::Mod(krate.module), ident: Ident::invalid(), id: ast::DUMMY_NODE_ID, - vis: respan(krate.span.shrink_to_lo(), ast::VisibilityKind::Public), + vis: ast::Visibility { + span: krate.span.shrink_to_lo(), + kind: ast::VisibilityKind::Public, + tokens: None, + }, tokens: None, })]); @@ -370,11 +373,21 @@ impl<'a, 'b> MacroExpander<'a, 'b> { None => { // Resolution failed so we return an empty expansion krate.attrs = vec![]; - krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + krate.module = ast::Mod { + inner: orig_mod_span, + unsafety: Unsafe::No, + items: vec![], + inline: true, + }; } Some(ast::Item { span, kind, .. }) => { krate.attrs = vec![]; - krate.module = ast::Mod { inner: orig_mod_span, items: vec![], inline: true }; + krate.module = ast::Mod { + inner: orig_mod_span, + unsafety: Unsafe::No, + items: vec![], + inline: true, + }; self.cx.span_err( span, &format!( @@ -529,9 +542,12 @@ impl<'a, 'b> MacroExpander<'a, 'b> { fn error_derive_forbidden_on_non_adt(&self, derives: &[Path], item: &Annotatable) { let attr = self.cx.sess.find_by_name(item.attrs(), sym::derive); let span = attr.map_or(item.span(), |attr| attr.span); - let mut err = self - .cx - .struct_span_err(span, "`derive` may only be applied to structs, enums and unions"); + let mut err = rustc_errors::struct_span_err!( + self.cx.sess, + span, + E0774, + "`derive` may only be applied to structs, enums and unions", + ); if let Some(ast::Attribute { style: ast::AttrStyle::Inner, .. }) = attr { let trait_list = derives.iter().map(|t| pprust::path_to_string(t)).collect::>(); let suggestion = format!("#[derive({})]", trait_list.join(", ")); @@ -1363,7 +1379,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } if let StmtKind::MacCall(mac) = stmt.kind { - let (mac, style, attrs) = mac.into_inner(); + let MacCallStmt { mac, style, attrs } = mac.into_inner(); self.check_attributes(&attrs); let mut placeholder = self.collect_bang(mac, stmt.span, AstFragmentKind::Stmts).make_stmts(); @@ -1380,10 +1396,10 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { } // The placeholder expander gives ids to statements, so we avoid folding the id here. - let ast::Stmt { id, kind, span } = stmt; + let ast::Stmt { id, kind, span, tokens } = stmt; noop_flat_map_stmt_kind(kind, self) .into_iter() - .map(|kind| ast::Stmt { id, kind, span }) + .map(|kind| ast::Stmt { id, kind, span, tokens: tokens.clone() }) .collect() } @@ -1438,8 +1454,15 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { push_directory(&self.cx.sess, ident, &item.attrs, dir) } else { // We have an outline `mod foo;` so we need to parse the file. - let (new_mod, dir) = - parse_external_mod(&self.cx.sess, ident, span, dir, &mut attrs, pushed); + let (new_mod, dir) = parse_external_mod( + &self.cx.sess, + ident, + span, + old_mod.unsafety, + dir, + &mut attrs, + pushed, + ); let krate = ast::Crate { span: new_mod.inner, @@ -1757,6 +1780,7 @@ impl<'a, 'b> MutVisitor for InvocationCollector<'a, 'b> { kind: ast::AttrKind::Normal(AttrItem { path: meta.path, args: meta.kind.mac_args(meta.span), + tokens: None, }), span: at.span, id: at.id, @@ -1788,6 +1812,7 @@ pub struct ExpansionConfig<'feat> { pub should_test: bool, // If false, strip `#[test]` nodes pub keep_macs: bool, pub span_debug: bool, // If true, use verbose debugging for `proc_macro::Span` + pub proc_macro_backtrace: bool, // If true, show backtraces for proc-macro panics } impl<'feat> ExpansionConfig<'feat> { @@ -1800,6 +1825,7 @@ impl<'feat> ExpansionConfig<'feat> { should_test: false, keep_macs: false, span_debug: false, + proc_macro_backtrace: false, } } diff --git a/src/librustc_expand/lib.rs b/compiler/rustc_expand/src/lib.rs similarity index 90% rename from src/librustc_expand/lib.rs rename to compiler/rustc_expand/src/lib.rs index 7f631cb71a..47247294f5 100644 --- a/src/librustc_expand/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -1,5 +1,4 @@ #![feature(bool_to_option)] -#![feature(cow_is_borrowed)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] #![feature(or_patterns)] @@ -39,11 +38,6 @@ mod tests; mod parse { #[cfg(test)] mod tests; - #[cfg(test)] - mod lexer { - #[cfg(test)] - mod tests; - } } #[cfg(test)] mod tokenstream { diff --git a/src/librustc_expand/mbe.rs b/compiler/rustc_expand/src/mbe.rs similarity index 100% rename from src/librustc_expand/mbe.rs rename to compiler/rustc_expand/src/mbe.rs diff --git a/src/librustc_expand/mbe/macro_check.rs b/compiler/rustc_expand/src/mbe/macro_check.rs similarity index 100% rename from src/librustc_expand/mbe/macro_check.rs rename to compiler/rustc_expand/src/mbe/macro_check.rs diff --git a/src/librustc_expand/mbe/macro_parser.rs b/compiler/rustc_expand/src/mbe/macro_parser.rs similarity index 100% rename from src/librustc_expand/mbe/macro_parser.rs rename to compiler/rustc_expand/src/mbe/macro_parser.rs diff --git a/src/librustc_expand/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs similarity index 100% rename from src/librustc_expand/mbe/macro_rules.rs rename to compiler/rustc_expand/src/mbe/macro_rules.rs diff --git a/src/librustc_expand/mbe/quoted.rs b/compiler/rustc_expand/src/mbe/quoted.rs similarity index 100% rename from src/librustc_expand/mbe/quoted.rs rename to compiler/rustc_expand/src/mbe/quoted.rs diff --git a/src/librustc_expand/mbe/transcribe.rs b/compiler/rustc_expand/src/mbe/transcribe.rs similarity index 99% rename from src/librustc_expand/mbe/transcribe.rs rename to compiler/rustc_expand/src/mbe/transcribe.rs index b908a12c1f..0e5c5fe4d4 100644 --- a/src/librustc_expand/mbe/transcribe.rs +++ b/compiler/rustc_expand/src/mbe/transcribe.rs @@ -4,7 +4,7 @@ use crate::mbe::macro_parser::{MatchedNonterminal, MatchedSeq, NamedMatch}; use rustc_ast::mut_visit::{self, MutVisitor}; use rustc_ast::token::{self, NtTT, Token}; -use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::MacCall; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::Lrc; @@ -111,7 +111,7 @@ pub(super) fn transcribe<'a>( // // Thus, if we try to pop the `result_stack` and it is empty, we have reached the top-level // again, and we are done transcribing. - let mut result: Vec = Vec::new(); + let mut result: Vec = Vec::new(); let mut result_stack = Vec::new(); let mut marker = Marker(cx.current_expansion.id, transparency); diff --git a/src/librustc_expand/module.rs b/compiler/rustc_expand/src/module.rs similarity index 96% rename from src/librustc_expand/module.rs rename to compiler/rustc_expand/src/module.rs index 1e123a2e14..171cb3fa8e 100644 --- a/src/librustc_expand/module.rs +++ b/compiler/rustc_expand/src/module.rs @@ -1,4 +1,4 @@ -use rustc_ast::{token, Attribute, Mod}; +use rustc_ast::{token, Attribute, Mod, Unsafe}; use rustc_errors::{struct_span_err, PResult}; use rustc_parse::new_parser_from_file; use rustc_session::parse::ParseSess; @@ -42,6 +42,7 @@ crate fn parse_external_mod( sess: &Session, id: Ident, span: Span, // The span to blame on errors. + unsafety: Unsafe, Directory { mut ownership, path }: Directory, attrs: &mut Vec, pop_mod_stack: &mut bool, @@ -60,13 +61,16 @@ crate fn parse_external_mod( drop(included_mod_stack); // Actually parse the external file as a module. - let mut module = - new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)).parse_mod(&token::Eof)?; + let mut parser = new_parser_from_file(&sess.parse_sess, &mp.path, Some(span)); + let mut module = parser.parse_mod(&token::Eof, unsafety)?; module.0.inline = false; module }; // (1) ...instead, we return a dummy module. - let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_default(); + let (module, mut new_attrs) = result.map_err(|mut err| err.emit()).unwrap_or_else(|_| { + let module = Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }; + (module, Vec::new()) + }); attrs.append(&mut new_attrs); // Extract the directory path for submodules of `module`. @@ -219,8 +223,7 @@ fn error_cannot_declare_mod_here<'a, T>( /// Derive a submodule path from the first found `#[path = "path_string"]`. /// The provided `dir_path` is joined with the `path_string`. -// Public for rustfmt usage. -pub fn submod_path_from_attr( +pub(super) fn submod_path_from_attr( sess: &Session, attrs: &[Attribute], dir_path: &Path, diff --git a/src/librustc_expand/mut_visit/tests.rs b/compiler/rustc_expand/src/mut_visit/tests.rs similarity index 100% rename from src/librustc_expand/mut_visit/tests.rs rename to compiler/rustc_expand/src/mut_visit/tests.rs diff --git a/src/librustc_expand/parse/tests.rs b/compiler/rustc_expand/src/parse/tests.rs similarity index 100% rename from src/librustc_expand/parse/tests.rs rename to compiler/rustc_expand/src/parse/tests.rs diff --git a/src/librustc_expand/placeholders.rs b/compiler/rustc_expand/src/placeholders.rs similarity index 92% rename from src/librustc_expand/placeholders.rs rename to compiler/rustc_expand/src/placeholders.rs index 29fb4c95ec..4c9271a58d 100644 --- a/src/librustc_expand/placeholders.rs +++ b/compiler/rustc_expand/src/placeholders.rs @@ -4,7 +4,7 @@ use crate::expand::{AstFragment, AstFragmentKind}; use rustc_ast as ast; use rustc_ast::mut_visit::*; use rustc_ast::ptr::P; -use rustc_span::source_map::{dummy_spanned, DUMMY_SP}; +use rustc_span::source_map::DUMMY_SP; use rustc_span::symbol::Ident; use smallvec::{smallvec, SmallVec}; @@ -18,7 +18,7 @@ pub fn placeholder( ) -> AstFragment { fn mac_placeholder() -> ast::MacCall { ast::MacCall { - path: ast::Path { span: DUMMY_SP, segments: Vec::new() }, + path: ast::Path { span: DUMMY_SP, segments: Vec::new(), tokens: None }, args: P(ast::MacArgs::Empty), prior_type_ascription: None, } @@ -26,7 +26,11 @@ pub fn placeholder( let ident = Ident::invalid(); let attrs = Vec::new(); - let vis = vis.unwrap_or_else(|| dummy_spanned(ast::VisibilityKind::Inherited)); + let vis = vis.unwrap_or(ast::Visibility { + span: DUMMY_SP, + kind: ast::VisibilityKind::Inherited, + tokens: None, + }); let span = DUMMY_SP; let expr_placeholder = || { P(ast::Expr { @@ -37,7 +41,8 @@ pub fn placeholder( tokens: None, }) }; - let ty = || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span }); + let ty = + || P(ast::Ty { id, kind: ast::TyKind::MacCall(mac_placeholder()), span, tokens: None }); let pat = || P(ast::Pat { id, kind: ast::PatKind::MacCall(mac_placeholder()), span, tokens: None }); @@ -88,12 +93,19 @@ pub fn placeholder( kind: ast::PatKind::MacCall(mac_placeholder()), tokens: None, })), - AstFragmentKind::Ty => { - AstFragment::Ty(P(ast::Ty { id, span, kind: ast::TyKind::MacCall(mac_placeholder()) })) - } + AstFragmentKind::Ty => AstFragment::Ty(P(ast::Ty { + id, + span, + kind: ast::TyKind::MacCall(mac_placeholder()), + tokens: None, + })), AstFragmentKind::Stmts => AstFragment::Stmts(smallvec![{ - let mac = P((mac_placeholder(), ast::MacStmtStyle::Braces, ast::AttrVec::new())); - ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac) } + let mac = P(ast::MacCallStmt { + mac: mac_placeholder(), + style: ast::MacStmtStyle::Braces, + attrs: ast::AttrVec::new(), + }); + ast::Stmt { id, span, kind: ast::StmtKind::MacCall(mac), tokens: None } }]), AstFragmentKind::Arms => AstFragment::Arms(smallvec![ast::Arm { attrs: Default::default(), @@ -293,7 +305,7 @@ impl<'a, 'b> MutVisitor for PlaceholderExpander<'a, 'b> { fn flat_map_stmt(&mut self, stmt: ast::Stmt) -> SmallVec<[ast::Stmt; 1]> { let (style, mut stmts) = match stmt.kind { - ast::StmtKind::MacCall(mac) => (mac.1, self.remove(stmt.id).make_stmts()), + ast::StmtKind::MacCall(mac) => (mac.style, self.remove(stmt.id).make_stmts()), _ => return noop_flat_map_stmt(stmt, self), }; diff --git a/src/librustc_expand/proc_macro.rs b/compiler/rustc_expand/src/proc_macro.rs similarity index 89% rename from src/librustc_expand/proc_macro.rs rename to compiler/rustc_expand/src/proc_macro.rs index 4e865c20d6..94b3fcf285 100644 --- a/src/librustc_expand/proc_macro.rs +++ b/compiler/rustc_expand/src/proc_macro.rs @@ -24,7 +24,7 @@ impl base::ProcMacro for BangProcMacro { input: TokenStream, ) -> Result { let server = proc_macro_server::Rustc::new(ecx); - self.client.run(&EXEC_STRATEGY, server, input).map_err(|e| { + self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace).map_err(|e| { let mut err = ecx.struct_span_err(span, "proc macro panicked"); if let Some(s) = e.as_str() { err.help(&format!("message: {}", s)); @@ -48,14 +48,16 @@ impl base::AttrProcMacro for AttrProcMacro { annotated: TokenStream, ) -> Result { let server = proc_macro_server::Rustc::new(ecx); - self.client.run(&EXEC_STRATEGY, server, annotation, annotated).map_err(|e| { - let mut err = ecx.struct_span_err(span, "custom attribute panicked"); - if let Some(s) = e.as_str() { - err.help(&format!("message: {}", s)); - } - err.emit(); - ErrorReported - }) + self.client + .run(&EXEC_STRATEGY, server, annotation, annotated, ecx.ecfg.proc_macro_backtrace) + .map_err(|e| { + let mut err = ecx.struct_span_err(span, "custom attribute panicked"); + if let Some(s) = e.as_str() { + err.help(&format!("message: {}", s)); + } + err.emit(); + ErrorReported + }) } } @@ -111,17 +113,18 @@ impl MultiItemModifier for ProcMacroDerive { }; let server = proc_macro_server::Rustc::new(ecx); - let stream = match self.client.run(&EXEC_STRATEGY, server, input) { - Ok(stream) => stream, - Err(e) => { - let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); - if let Some(s) = e.as_str() { - err.help(&format!("message: {}", s)); + let stream = + match self.client.run(&EXEC_STRATEGY, server, input, ecx.ecfg.proc_macro_backtrace) { + Ok(stream) => stream, + Err(e) => { + let mut err = ecx.struct_span_err(span, "proc-macro derive panicked"); + if let Some(s) = e.as_str() { + err.help(&format!("message: {}", s)); + } + err.emit(); + return ExpandResult::Ready(vec![]); } - err.emit(); - return ExpandResult::Ready(vec![]); - } - }; + }; let error_count_before = ecx.sess.parse_sess.span_diagnostic.err_count(); let mut parser = diff --git a/src/librustc_expand/proc_macro_server.rs b/compiler/rustc_expand/src/proc_macro_server.rs similarity index 97% rename from src/librustc_expand/proc_macro_server.rs rename to compiler/rustc_expand/src/proc_macro_server.rs index 409784812f..4cfb188783 100644 --- a/src/librustc_expand/proc_macro_server.rs +++ b/compiler/rustc_expand/src/proc_macro_server.rs @@ -2,7 +2,7 @@ use crate::base::ExtCtxt; use rustc_ast as ast; use rustc_ast::token; -use rustc_ast::tokenstream::{self, DelimSpan, IsJoint::*, TokenStream, TreeAndJoint}; +use rustc_ast::tokenstream::{self, DelimSpan, Spacing::*, TokenStream, TreeAndSpacing}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::Diagnostic; @@ -47,15 +47,15 @@ impl ToInternal for Delimiter { } } -impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> +impl FromInternal<(TreeAndSpacing, &'_ ParseSess, &'_ mut Vec)> for TokenTree { fn from_internal( - ((tree, is_joint), sess, stack): (TreeAndJoint, &ParseSess, &mut Vec), + ((tree, spacing), sess, stack): (TreeAndSpacing, &ParseSess, &mut Vec), ) -> Self { use rustc_ast::token::*; - let joint = is_joint == Joint; + let joint = spacing == Joint; let Token { kind, span } = match tree { tokenstream::TokenTree::Delimited(span, delim, tts) => { let delimiter = Delimiter::from_internal(delim); @@ -189,7 +189,7 @@ impl FromInternal<(TreeAndJoint, &'_ ParseSess, &'_ mut Vec)> } OpenDelim(..) | CloseDelim(..) => unreachable!(), - Whitespace | Comment | Shebang(..) | Unknown(..) | Eof => unreachable!(), + Eof => unreachable!(), } } } @@ -261,7 +261,7 @@ impl ToInternal for TokenTree { }; let tree = tokenstream::TokenTree::token(kind, span); - TokenStream::new(vec![(tree, if joint { Joint } else { NonJoint })]) + TokenStream::new(vec![(tree, if joint { Joint } else { Alone })]) } } @@ -444,7 +444,7 @@ impl server::TokenStreamIter for Rustc<'_> { ) -> Option> { loop { let tree = iter.stack.pop().or_else(|| { - let next = iter.cursor.next_with_joint()?; + let next = iter.cursor.next_with_spacing()?; Some(TokenTree::from_internal((next, self.sess, &mut iter.stack))) })?; // A hack used to pass AST fragments to attribute and derive macros @@ -584,12 +584,12 @@ impl server::Literal for Rustc<'_> { let start = match start { Bound::Included(lo) => lo, - Bound::Excluded(lo) => lo + 1, + Bound::Excluded(lo) => lo.checked_add(1)?, Bound::Unbounded => 0, }; let end = match end { - Bound::Included(hi) => hi + 1, + Bound::Included(hi) => hi.checked_add(1)?, Bound::Excluded(hi) => hi, Bound::Unbounded => length, }; diff --git a/src/librustc_expand/tests.rs b/compiler/rustc_expand/src/tests.rs similarity index 100% rename from src/librustc_expand/tests.rs rename to compiler/rustc_expand/src/tests.rs diff --git a/src/librustc_expand/tokenstream/tests.rs b/compiler/rustc_expand/src/tokenstream/tests.rs similarity index 100% rename from src/librustc_expand/tokenstream/tests.rs rename to compiler/rustc_expand/src/tokenstream/tests.rs diff --git a/compiler/rustc_feature/Cargo.toml b/compiler/rustc_feature/Cargo.toml new file mode 100644 index 0000000000..7a06bce13c --- /dev/null +++ b/compiler/rustc_feature/Cargo.toml @@ -0,0 +1,12 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_feature" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_feature/accepted.rs b/compiler/rustc_feature/src/accepted.rs similarity index 98% rename from src/librustc_feature/accepted.rs rename to compiler/rustc_feature/src/accepted.rs index d16f023c00..e2492efb9d 100644 --- a/src/librustc_feature/accepted.rs +++ b/compiler/rustc_feature/src/accepted.rs @@ -1,6 +1,6 @@ //! List of the accepted feature gates. -use super::{Feature, State}; +use super::{to_nonzero, Feature, State}; use rustc_span::symbol::sym; macro_rules! declare_features { @@ -14,7 +14,7 @@ macro_rules! declare_features { state: State::Accepted, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: None, description: concat!($($doc,)*), } @@ -268,6 +268,8 @@ declare_features! ( /// Allows `#[track_caller]` to be used which provides /// accurate caller location reporting during panic (RFC 2091). (accepted, track_caller, "1.46.0", Some(47809), None), + /// Allows `#[doc(alias = "...")]`. + (accepted, doc_alias, "1.48.0", Some(50146), None), // ------------------------------------------------------------------------- // feature-group-end: accepted features diff --git a/src/librustc_feature/active.rs b/compiler/rustc_feature/src/active.rs similarity index 96% rename from src/librustc_feature/active.rs rename to compiler/rustc_feature/src/active.rs index e858980738..060efd270d 100644 --- a/src/librustc_feature/active.rs +++ b/compiler/rustc_feature/src/active.rs @@ -1,6 +1,6 @@ //! List of the active feature gates. -use super::{Feature, State}; +use super::{to_nonzero, Feature, State}; use rustc_span::edition::Edition; use rustc_span::symbol::{sym, Symbol}; @@ -29,7 +29,7 @@ macro_rules! declare_features { state: State::Active { set: set!($feature) }, name: sym::$feature, since: $ver, - issue: $issue, + issue: to_nonzero($issue), edition: $edition, description: concat!($($doc,)*), } @@ -229,7 +229,6 @@ declare_features! ( (active, powerpc_target_feature, "1.27.0", Some(44839), None), (active, mips_target_feature, "1.27.0", Some(44839), None), (active, avx512_target_feature, "1.27.0", Some(44839), None), - (active, mmx_target_feature, "1.27.0", Some(44839), None), (active, sse4a_target_feature, "1.27.0", Some(44839), None), (active, tbm_target_feature, "1.27.0", Some(44839), None), (active, wasm_target_feature, "1.30.0", Some(44839), None), @@ -404,9 +403,6 @@ declare_features! ( /// Allows dereferencing raw pointers during const eval. (active, const_raw_ptr_deref, "1.27.0", Some(51911), None), - /// Allows `#[doc(alias = "...")]`. - (active, doc_alias, "1.27.0", Some(50146), None), - /// Allows inconsistent bounds in where clauses. (active, trivial_bounds, "1.28.0", Some(48214), None), @@ -585,6 +581,18 @@ declare_features! ( /// Allows `if let` guard in match arms. (active, if_let_guard, "1.47.0", Some(51114), None), + /// Allows non trivial generic constants which have to be manually propageted upwards. + (active, const_evaluatable_checked, "1.48.0", Some(76560), None), + + /// Allows basic arithmetic on floating point types in a `const fn`. + (active, const_fn_floating_point_arithmetic, "1.48.0", Some(57241), None), + + /// Allows using and casting function pointers in a `const fn`. + (active, const_fn_fn_ptr_basics, "1.48.0", Some(57563), None), + + /// Allows to use the `#[cmse_nonsecure_entry]` attribute. + (active, cmse_nonsecure_entry, "1.48.0", Some(75835), None), + // ------------------------------------------------------------------------- // feature-group-end: actual feature gates // ------------------------------------------------------------------------- @@ -600,8 +608,14 @@ pub const INCOMPLETE_FEATURES: &[Symbol] = &[ sym::const_generics, sym::let_chains, sym::raw_dylib, + sym::const_evaluatable_checked, sym::const_trait_impl, sym::const_trait_bound_opt_out, sym::lazy_normalization_consts, sym::specialization, ]; + +/// Some features are not allowed to be used together at the same time, if +/// the two are present, produce an error. +pub const INCOMPATIBLE_FEATURES: &[(Symbol, Symbol)] = + &[(sym::const_generics, sym::min_const_generics)]; diff --git a/src/librustc_feature/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs similarity index 98% rename from src/librustc_feature/builtin_attrs.rs rename to compiler/rustc_feature/src/builtin_attrs.rs index 879f06f89a..b7e113e601 100644 --- a/src/librustc_feature/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -5,10 +5,11 @@ use AttributeType::*; use crate::{Features, Stability}; -use lazy_static::lazy_static; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{sym, Symbol}; +use std::lazy::SyncLazy; + type GateFn = fn(&Features) -> bool; macro_rules! cfg_fn { @@ -25,6 +26,11 @@ const GATED_CFGS: &[GatedCfg] = &[ (sym::target_thread_local, sym::cfg_target_thread_local, cfg_fn!(cfg_target_thread_local)), (sym::target_has_atomic, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), (sym::target_has_atomic_load_store, sym::cfg_target_has_atomic, cfg_fn!(cfg_target_has_atomic)), + ( + sym::target_has_atomic_equal_alignment, + sym::cfg_target_has_atomic, + cfg_fn!(cfg_target_has_atomic), + ), (sym::sanitize, sym::cfg_sanitize, cfg_fn!(cfg_sanitize)), (sym::version, sym::cfg_version, cfg_fn!(cfg_version)), ]; @@ -343,6 +349,8 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ experimental!(register_tool), ), + gated!(cmse_nonsecure_entry, AssumedUsed, template!(Word), experimental!(cmse_nonsecure_entry)), + // ========================================================================== // Internal attributes: Stability, deprecation, and unsafe: // ========================================================================== @@ -458,7 +466,6 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ // ========================================================================== rustc_attr!(rustc_promotable, AssumedUsed, template!(Word), IMPL_DETAIL), - rustc_attr!(rustc_allow_const_fn_ptr, AssumedUsed, template!(Word), IMPL_DETAIL), rustc_attr!(rustc_args_required_const, AssumedUsed, template!(List: "N"), INTERNAL_UNSTABLE), // ========================================================================== @@ -589,8 +596,8 @@ pub fn is_builtin_attr_name(name: Symbol) -> bool { BUILTIN_ATTRIBUTE_MAP.get(&name).is_some() } -lazy_static! { - pub static ref BUILTIN_ATTRIBUTE_MAP: FxHashMap = { +pub static BUILTIN_ATTRIBUTE_MAP: SyncLazy> = + SyncLazy::new(|| { let mut map = FxHashMap::default(); for attr in BUILTIN_ATTRIBUTES.iter() { if map.insert(attr.0, attr).is_some() { @@ -598,5 +605,4 @@ lazy_static! { } } map - }; -} + }); diff --git a/src/librustc_feature/lib.rs b/compiler/rustc_feature/src/lib.rs similarity index 88% rename from src/librustc_feature/lib.rs rename to compiler/rustc_feature/src/lib.rs index f8bf0315d0..68ac2841fe 100644 --- a/src/librustc_feature/lib.rs +++ b/compiler/rustc_feature/src/lib.rs @@ -11,6 +11,8 @@ //! even if it is stabilized or removed, *do not remove it*. Instead, move the //! symbol to the `accepted` or `removed` modules respectively. +#![feature(once_cell)] + mod accepted; mod active; mod builtin_attrs; @@ -44,17 +46,11 @@ pub struct Feature { pub state: State, pub name: Symbol, pub since: &'static str, - issue: Option, // FIXME: once #58732 is done make this an Option + issue: Option, pub edition: Option, description: &'static str, } -impl Feature { - fn issue(&self) -> Option { - self.issue.and_then(NonZeroU32::new) - } -} - #[derive(Copy, Clone, Debug)] pub enum Stability { Unstable, @@ -100,8 +96,8 @@ impl UnstableFeatures { fn find_lang_feature_issue(feature: Symbol) -> Option { if let Some(info) = ACTIVE_FEATURES.iter().find(|t| t.name == feature) { // FIXME (#28244): enforce that active features have issue numbers - // assert!(info.issue().is_some()) - info.issue() + // assert!(info.issue.is_some()) + info.issue } else { // search in Accepted, Removed, or Stable Removed features let found = ACCEPTED_FEATURES @@ -110,12 +106,21 @@ fn find_lang_feature_issue(feature: Symbol) -> Option { .chain(STABLE_REMOVED_FEATURES) .find(|t| t.name == feature); match found { - Some(found) => found.issue(), + Some(found) => found.issue, None => panic!("feature `{}` is not declared anywhere", feature), } } } +const fn to_nonzero(n: Option) -> Option { + // Can be replaced with `n.and_then(NonZeroU32::new)` if that is ever usable + // in const context. Requires https://github.com/rust-lang/rfcs/pull/2632. + match n { + None => None, + Some(n) => NonZeroU32::new(n), + } +} + pub enum GateIssue { Language, Library(Option), @@ -129,7 +134,7 @@ pub fn find_feature_issue(feature: Symbol, issue: GateIssue) -> Option { fn target(&'a self, edge: &Self::Edge) -> Self::Node; } -#[derive(Copy, Clone, PartialEq, Eq, Debug)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum RenderOption { NoEdgeLabels, NoNodeLabels, NoEdgeStyles, NoNodeStyles, - Monospace, + Fontname(String), + DarkTheme, } /// Returns vec holding all the default render options. @@ -630,10 +631,26 @@ where writeln!(w, "digraph {} {{", g.graph_id().as_slice())?; // Global graph properties - if options.contains(&RenderOption::Monospace) { - writeln!(w, r#" graph[fontname="monospace"];"#)?; - writeln!(w, r#" node[fontname="monospace"];"#)?; - writeln!(w, r#" edge[fontname="monospace"];"#)?; + let mut graph_attrs = Vec::new(); + let mut content_attrs = Vec::new(); + let font; + if let Some(fontname) = options.iter().find_map(|option| { + if let RenderOption::Fontname(fontname) = option { Some(fontname) } else { None } + }) { + font = format!(r#"fontname="{}""#, fontname); + graph_attrs.push(&font[..]); + content_attrs.push(&font[..]); + } + if options.contains(&RenderOption::DarkTheme) { + graph_attrs.push(r#"bgcolor="black""#); + content_attrs.push(r#"color="white""#); + content_attrs.push(r#"fontcolor="white""#); + } + if !(graph_attrs.is_empty() && content_attrs.is_empty()) { + 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)?; } for n in g.nodes().iter() { diff --git a/src/librustc_graphviz/tests.rs b/compiler/rustc_graphviz/src/tests.rs similarity index 100% rename from src/librustc_graphviz/tests.rs rename to compiler/rustc_graphviz/src/tests.rs diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml new file mode 100644 index 0000000000..b24c208c76 --- /dev/null +++ b/compiler/rustc_hir/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_hir" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_target = { path = "../rustc_target" } +rustc_macros = { path = "../rustc_macros" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_span = { path = "../rustc_span" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +tracing = "0.1" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_hir/arena.rs b/compiler/rustc_hir/src/arena.rs similarity index 100% rename from src/librustc_hir/arena.rs rename to compiler/rustc_hir/src/arena.rs diff --git a/src/librustc_hir/def.rs b/compiler/rustc_hir/src/def.rs similarity index 91% rename from src/librustc_hir/def.rs rename to compiler/rustc_hir/src/def.rs index fb7fced27c..96fde48d96 100644 --- a/src/librustc_hir/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -6,6 +6,7 @@ use rustc_ast::NodeId; use rustc_macros::HashStable_Generic; use rustc_span::hygiene::MacroKind; +use std::array::IntoIter; use std::fmt::Debug; /// Encodes if a `DefKind::Ctor` is the constructor of an enum variant or a struct. @@ -198,7 +199,16 @@ pub enum Res { // Type namespace PrimTy(hir::PrimTy), - SelfTy(Option /* trait */, Option /* impl */), + /// `Self`, with both an optional trait and impl `DefId`. + /// + /// HACK(min_const_generics): impl self types also have an optional requirement to not mention + /// any generic parameters to allow the following with `min_const_generics`: + /// ```rust + /// impl Foo { fn test() -> [u8; std::mem::size_of::()] {} } + /// ``` + /// + /// FIXME(lazy_normalization_consts): Remove this bodge once this feature is stable. + SelfTy(Option /* trait */, Option<(DefId, bool)> /* impl */), ToolMod, // e.g., `rustfmt` in `#[rustfmt::skip]` // Value namespace @@ -291,6 +301,14 @@ impl PerNS { pub fn map U>(self, mut f: F) -> PerNS { PerNS { value_ns: f(self.value_ns), type_ns: f(self.type_ns), macro_ns: f(self.macro_ns) } } + + pub fn into_iter(self) -> IntoIter { + IntoIter::new([self.value_ns, self.type_ns, self.macro_ns]) + } + + pub fn iter(&self) -> IntoIter<&T, 3> { + IntoIter::new([&self.value_ns, &self.type_ns, &self.macro_ns]) + } } impl ::std::ops::Index for PerNS { @@ -451,13 +469,19 @@ impl Res { } } - pub fn matches_ns(&self, ns: Namespace) -> bool { + /// Returns `None` if this is `Res::Err` + pub fn ns(&self) -> Option { match self { - Res::Def(kind, ..) => kind.ns() == Some(ns), - Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => ns == Namespace::TypeNS, - Res::SelfCtor(..) | Res::Local(..) => ns == Namespace::ValueNS, - Res::NonMacroAttr(..) => ns == Namespace::MacroNS, - Res::Err => true, + Res::Def(kind, ..) => kind.ns(), + Res::PrimTy(..) | Res::SelfTy(..) | Res::ToolMod => Some(Namespace::TypeNS), + Res::SelfCtor(..) | Res::Local(..) => Some(Namespace::ValueNS), + Res::NonMacroAttr(..) => Some(Namespace::MacroNS), + Res::Err => None, } } + + /// Always returns `true` if `self` is `Res::Err` + pub fn matches_ns(&self, ns: Namespace) -> bool { + self.ns().map_or(true, |actual_ns| actual_ns == ns) + } } diff --git a/src/librustc_hir/definitions.rs b/compiler/rustc_hir/src/definitions.rs similarity index 87% rename from src/librustc_hir/definitions.rs rename to compiler/rustc_hir/src/definitions.rs index 45735ead25..afefde07f9 100644 --- a/src/librustc_hir/definitions.rs +++ b/compiler/rustc_hir/src/definitions.rs @@ -13,9 +13,9 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::stable_hasher::StableHasher; use rustc_index::vec::IndexVec; use rustc_span::hygiene::ExpnId; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; -use std::fmt::Write; +use std::fmt::{self, Write}; use std::hash::Hash; use tracing::debug; @@ -155,6 +155,29 @@ pub struct DisambiguatedDefPathData { pub disambiguator: u32, } +impl DisambiguatedDefPathData { + pub fn fmt_maybe_verbose(&self, writer: &mut impl Write, verbose: bool) -> fmt::Result { + match self.data.name() { + DefPathDataName::Named(name) => { + if verbose && self.disambiguator != 0 { + write!(writer, "{}#{}", name, self.disambiguator) + } else { + writer.write_str(&name.as_str()) + } + } + DefPathDataName::Anon { namespace } => { + write!(writer, "{{{}#{}}}", namespace, self.disambiguator) + } + } + } +} + +impl fmt::Display for DisambiguatedDefPathData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.fmt_maybe_verbose(f, true) + } +} + #[derive(Clone, Debug, Encodable, Decodable)] pub struct DefPath { /// The path leading from the crate root to the item. @@ -198,33 +221,11 @@ impl DefPath { /// Returns a string representation of the `DefPath` without /// the crate-prefix. This method is useful if you don't have /// a `TyCtxt` available. - pub fn to_string_no_crate(&self) -> String { + pub fn to_string_no_crate_verbose(&self) -> String { let mut s = String::with_capacity(self.data.len() * 16); for component in &self.data { - write!(s, "::{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); - } - - s - } - - /// Returns a filename-friendly string for the `DefPath`, with the - /// crate-prefix. - pub fn to_string_friendly(&self, crate_imported_name: F) -> String - where - F: FnOnce(CrateNum) -> Symbol, - { - let crate_name_str = crate_imported_name(self.krate).as_str(); - let mut s = String::with_capacity(crate_name_str.len() + self.data.len() * 16); - - write!(s, "::{}", crate_name_str).unwrap(); - - for component in &self.data { - if component.disambiguator == 0 { - write!(s, "::{}", component.data.as_symbol()).unwrap(); - } else { - write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); - } + write!(s, "::{}", component).unwrap(); } s @@ -240,12 +241,9 @@ impl DefPath { for component in &self.data { s.extend(opt_delimiter); opt_delimiter = Some('-'); - if component.disambiguator == 0 { - write!(s, "{}", component.data.as_symbol()).unwrap(); - } else { - write!(s, "{}[{}]", component.data.as_symbol(), component.disambiguator).unwrap(); - } + write!(s, "{}", component).unwrap(); } + s } } @@ -313,6 +311,7 @@ impl Definitions { } #[inline] + #[track_caller] pub fn local_def_id_to_hir_id(&self, id: LocalDefId) -> hir::HirId { self.def_id_to_hir_id[id].unwrap() } @@ -426,6 +425,12 @@ impl Definitions { } } +#[derive(Copy, Clone, PartialEq, Debug)] +pub enum DefPathDataName { + Named(Symbol), + Anon { namespace: Symbol }, +} + impl DefPathData { pub fn get_opt_name(&self) -> Option { use self::DefPathData::*; @@ -436,22 +441,30 @@ impl DefPathData { } } - pub fn as_symbol(&self) -> Symbol { + pub fn name(&self) -> DefPathDataName { use self::DefPathData::*; match *self { - TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => name, + TypeNs(name) | ValueNs(name) | MacroNs(name) | LifetimeNs(name) => { + DefPathDataName::Named(name) + } // Note that this does not show up in user print-outs. - CrateRoot => sym::double_braced_crate, - Impl => sym::double_braced_impl, - Misc => sym::double_braced_misc, - ClosureExpr => sym::double_braced_closure, - Ctor => sym::double_braced_constructor, - AnonConst => sym::double_braced_constant, - ImplTrait => sym::double_braced_opaque, + CrateRoot => DefPathDataName::Anon { namespace: kw::Crate }, + Impl => DefPathDataName::Anon { namespace: kw::Impl }, + Misc => DefPathDataName::Anon { namespace: sym::misc }, + ClosureExpr => DefPathDataName::Anon { namespace: sym::closure }, + Ctor => DefPathDataName::Anon { namespace: sym::constructor }, + AnonConst => DefPathDataName::Anon { namespace: sym::constant }, + ImplTrait => DefPathDataName::Anon { namespace: sym::opaque }, } } +} - pub fn to_string(&self) -> String { - self.as_symbol().to_string() +impl fmt::Display for DefPathData { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match self.name() { + DefPathDataName::Named(name) => f.write_str(&name.as_str()), + // FIXME(#70334): this will generate legacy {{closure}}, {{impl}}, etc + DefPathDataName::Anon { namespace } => write!(f, "{{{{{}}}}}", namespace), + } } } diff --git a/src/librustc_hir/hir.rs b/compiler/rustc_hir/src/hir.rs similarity index 99% rename from src/librustc_hir/hir.rs rename to compiler/rustc_hir/src/hir.rs index cd4185226d..636f67a77c 100644 --- a/src/librustc_hir/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2004,6 +2004,30 @@ pub enum PrimTy { Char, } +impl PrimTy { + pub fn name_str(self) -> &'static str { + match self { + PrimTy::Int(i) => i.name_str(), + PrimTy::Uint(u) => u.name_str(), + PrimTy::Float(f) => f.name_str(), + PrimTy::Str => "str", + PrimTy::Bool => "bool", + PrimTy::Char => "char", + } + } + + pub fn name(self) -> Symbol { + match self { + PrimTy::Int(i) => i.name(), + PrimTy::Uint(u) => u.name(), + PrimTy::Float(f) => f.name(), + PrimTy::Str => sym::str, + PrimTy::Bool => sym::bool, + PrimTy::Char => sym::char, + } + } +} + #[derive(Debug, HashStable_Generic)] pub struct BareFnTy<'hir> { pub unsafety: Unsafety, diff --git a/src/librustc_hir/hir_id.rs b/compiler/rustc_hir/src/hir_id.rs similarity index 100% rename from src/librustc_hir/hir_id.rs rename to compiler/rustc_hir/src/hir_id.rs diff --git a/src/librustc_hir/intravisit.rs b/compiler/rustc_hir/src/intravisit.rs similarity index 99% rename from src/librustc_hir/intravisit.rs rename to compiler/rustc_hir/src/intravisit.rs index 76cf6bd477..820d664c07 100644 --- a/src/librustc_hir/intravisit.rs +++ b/compiler/rustc_hir/src/intravisit.rs @@ -256,7 +256,6 @@ pub trait Visitor<'v>: Sized { /// patterns described on `itemlikevisit::ItemLikeVisitor`. The only /// reason to override this method is if you want a nested pattern /// but cannot supply a `Map`; see `nested_visit_map` for advice. - #[allow(unused_variables)] fn visit_nested_item(&mut self, id: ItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.item(id.id)); walk_list!(self, visit_item, opt_item); @@ -265,7 +264,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for trait items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_trait_item(&mut self, id: TraitItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.trait_item(id)); walk_list!(self, visit_trait_item, opt_item); @@ -274,7 +272,6 @@ pub trait Visitor<'v>: Sized { /// Like `visit_nested_item()`, but for impl items. See /// `visit_nested_item()` for advice on when to override this /// method. - #[allow(unused_variables)] fn visit_nested_impl_item(&mut self, id: ImplItemId) { let opt_item = self.nested_visit_map().inter().map(|map| map.impl_item(id)); walk_list!(self, visit_impl_item, opt_item); diff --git a/src/librustc_hir/itemlikevisit.rs b/compiler/rustc_hir/src/itemlikevisit.rs similarity index 100% rename from src/librustc_hir/itemlikevisit.rs rename to compiler/rustc_hir/src/itemlikevisit.rs diff --git a/src/librustc_hir/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs similarity index 97% rename from src/librustc_hir/lang_items.rs rename to compiler/rustc_hir/src/lang_items.rs index acf6847c01..5e4c03bec8 100644 --- a/src/librustc_hir/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -17,7 +17,7 @@ use rustc_macros::HashStable_Generic; use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; -use lazy_static::lazy_static; +use std::lazy::SyncLazy; pub enum LangItemGroup { Op, @@ -117,14 +117,12 @@ macro_rules! language_item_table { )* } - lazy_static! { - /// A mapping from the name of the lang item to its order and the form it must be of. - pub static ref ITEM_REFS: FxHashMap = { - let mut item_refs = FxHashMap::default(); - $( item_refs.insert($name, (LangItem::$variant as usize, $target)); )* - item_refs - }; - } + /// A mapping from the name of the lang item to its order and the form it must be of. + pub static ITEM_REFS: SyncLazy> = SyncLazy::new(|| { + let mut item_refs = FxHashMap::default(); + $( item_refs.insert($name, (LangItem::$variant as usize, $target)); )* + item_refs + }); // End of the macro } diff --git a/src/librustc_hir/lib.rs b/compiler/rustc_hir/src/lib.rs similarity index 94% rename from src/librustc_hir/lib.rs rename to compiler/rustc_hir/src/lib.rs index 19ea1de568..9d931b3a9e 100644 --- a/src/librustc_hir/lib.rs +++ b/compiler/rustc_hir/src/lib.rs @@ -2,10 +2,12 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/hir.html +#![feature(array_value_iter)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] // For the unsizing cast on `&[]` #![feature(const_panic)] #![feature(in_band_lifetimes)] +#![feature(once_cell)] #![feature(or_patterns)] #![recursion_limit = "256"] diff --git a/src/librustc_hir/pat_util.rs b/compiler/rustc_hir/src/pat_util.rs similarity index 100% rename from src/librustc_hir/pat_util.rs rename to compiler/rustc_hir/src/pat_util.rs diff --git a/src/librustc_hir/stable_hash_impls.rs b/compiler/rustc_hir/src/stable_hash_impls.rs similarity index 100% rename from src/librustc_hir/stable_hash_impls.rs rename to compiler/rustc_hir/src/stable_hash_impls.rs diff --git a/src/librustc_hir/target.rs b/compiler/rustc_hir/src/target.rs similarity index 100% rename from src/librustc_hir/target.rs rename to compiler/rustc_hir/src/target.rs diff --git a/src/librustc_hir/weak_lang_items.rs b/compiler/rustc_hir/src/weak_lang_items.rs similarity index 79% rename from src/librustc_hir/weak_lang_items.rs rename to compiler/rustc_hir/src/weak_lang_items.rs index 74e2a90262..52f28bf8f4 100644 --- a/src/librustc_hir/weak_lang_items.rs +++ b/compiler/rustc_hir/src/weak_lang_items.rs @@ -7,18 +7,16 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::{sym, Symbol}; -use lazy_static::lazy_static; +use std::lazy::SyncLazy; macro_rules! weak_lang_items { ($($name:ident, $item:ident, $sym:ident;)*) => ( -lazy_static! { - pub static ref WEAK_ITEMS_REFS: FxHashMap = { - let mut map = FxHashMap::default(); - $(map.insert(sym::$name, LangItem::$item);)* - map - }; -} +pub static WEAK_ITEMS_REFS: SyncLazy> = SyncLazy::new(|| { + let mut map = FxHashMap::default(); + $(map.insert(sym::$name, LangItem::$item);)* + map +}); /// The `check_name` argument avoids the need for `librustc_hir` to depend on /// `librustc_session`. @@ -48,5 +46,6 @@ impl LanguageItems { weak_lang_items! { panic_impl, PanicImpl, rust_begin_unwind; eh_personality, EhPersonality, rust_eh_personality; + eh_catch_typeinfo, EhCatchTypeinfo, rust_eh_catch_typeinfo; oom, Oom, rust_oom; } diff --git a/compiler/rustc_hir_pretty/Cargo.toml b/compiler/rustc_hir_pretty/Cargo.toml new file mode 100644 index 0000000000..1f7643e9fb --- /dev/null +++ b/compiler/rustc_hir_pretty/Cargo.toml @@ -0,0 +1,15 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_hir_pretty" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_hir_pretty/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs similarity index 100% rename from src/librustc_hir_pretty/lib.rs rename to compiler/rustc_hir_pretty/src/lib.rs diff --git a/compiler/rustc_incremental/Cargo.toml b/compiler/rustc_incremental/Cargo.toml new file mode 100644 index 0000000000..049e5b8b72 --- /dev/null +++ b/compiler/rustc_incremental/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_incremental" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_graphviz = { path = "../rustc_graphviz" } +tracing = "0.1" +rand = "0.7" +rustc_middle = { path = "../rustc_middle" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +rustc_macros = { path = "../rustc_macros" } +rustc_span = { path = "../rustc_span" } +rustc_fs_util = { path = "../rustc_fs_util" } +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_incremental/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs similarity index 100% rename from src/librustc_incremental/assert_dep_graph.rs rename to compiler/rustc_incremental/src/assert_dep_graph.rs diff --git a/src/librustc_incremental/assert_module_sources.rs b/compiler/rustc_incremental/src/assert_module_sources.rs similarity index 100% rename from src/librustc_incremental/assert_module_sources.rs rename to compiler/rustc_incremental/src/assert_module_sources.rs diff --git a/src/librustc_incremental/lib.rs b/compiler/rustc_incremental/src/lib.rs similarity index 92% rename from src/librustc_incremental/lib.rs rename to compiler/rustc_incremental/src/lib.rs index ad18913805..a80c4be3e9 100644 --- a/src/librustc_incremental/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -1,6 +1,6 @@ //! Support for serializing the dep-graph and reloading it. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] #![recursion_limit = "256"] diff --git a/src/librustc_incremental/persist/README.md b/compiler/rustc_incremental/src/persist/README.md similarity index 100% rename from src/librustc_incremental/persist/README.md rename to compiler/rustc_incremental/src/persist/README.md diff --git a/src/librustc_incremental/persist/data.rs b/compiler/rustc_incremental/src/persist/data.rs similarity index 100% rename from src/librustc_incremental/persist/data.rs rename to compiler/rustc_incremental/src/persist/data.rs diff --git a/src/librustc_incremental/persist/dirty_clean.rs b/compiler/rustc_incremental/src/persist/dirty_clean.rs similarity index 100% rename from src/librustc_incremental/persist/dirty_clean.rs rename to compiler/rustc_incremental/src/persist/dirty_clean.rs diff --git a/src/librustc_incremental/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs similarity index 100% rename from src/librustc_incremental/persist/file_format.rs rename to compiler/rustc_incremental/src/persist/file_format.rs diff --git a/src/librustc_incremental/persist/fs.rs b/compiler/rustc_incremental/src/persist/fs.rs similarity index 100% rename from src/librustc_incremental/persist/fs.rs rename to compiler/rustc_incremental/src/persist/fs.rs diff --git a/src/librustc_incremental/persist/fs/tests.rs b/compiler/rustc_incremental/src/persist/fs/tests.rs similarity index 100% rename from src/librustc_incremental/persist/fs/tests.rs rename to compiler/rustc_incremental/src/persist/fs/tests.rs diff --git a/src/librustc_incremental/persist/load.rs b/compiler/rustc_incremental/src/persist/load.rs similarity index 100% rename from src/librustc_incremental/persist/load.rs rename to compiler/rustc_incremental/src/persist/load.rs diff --git a/src/librustc_incremental/persist/mod.rs b/compiler/rustc_incremental/src/persist/mod.rs similarity index 100% rename from src/librustc_incremental/persist/mod.rs rename to compiler/rustc_incremental/src/persist/mod.rs diff --git a/src/librustc_incremental/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs similarity index 100% rename from src/librustc_incremental/persist/save.rs rename to compiler/rustc_incremental/src/persist/save.rs diff --git a/src/librustc_incremental/persist/work_product.rs b/compiler/rustc_incremental/src/persist/work_product.rs similarity index 100% rename from src/librustc_incremental/persist/work_product.rs rename to compiler/rustc_incremental/src/persist/work_product.rs diff --git a/src/librustc_index/Cargo.toml b/compiler/rustc_index/Cargo.toml similarity index 60% rename from src/librustc_index/Cargo.toml rename to compiler/rustc_index/Cargo.toml index 061f440ef1..6e1471df19 100644 --- a/src/librustc_index/Cargo.toml +++ b/compiler/rustc_index/Cargo.toml @@ -5,11 +5,9 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustc_index" -path = "lib.rs" doctest = false [dependencies] arrayvec = { version = "0.5.1", default-features = false } -rustc_serialize = { path = "../librustc_serialize" } -rustc_macros = { path = "../librustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_macros = { path = "../rustc_macros" } diff --git a/src/librustc_index/bit_set.rs b/compiler/rustc_index/src/bit_set.rs similarity index 97% rename from src/librustc_index/bit_set.rs rename to compiler/rustc_index/src/bit_set.rs index c43d1a6830..8e00e54650 100644 --- a/src/librustc_index/bit_set.rs +++ b/compiler/rustc_index/src/bit_set.rs @@ -28,13 +28,20 @@ pub const WORD_BITS: usize = WORD_BYTES * 8; /// will panic if the bitsets have differing domain sizes. /// /// [`GrowableBitSet`]: struct.GrowableBitSet.html -#[derive(Clone, Eq, PartialEq, Decodable, Encodable)] -pub struct BitSet { +#[derive(Eq, PartialEq, Decodable, Encodable)] +pub struct BitSet { domain_size: usize, words: Vec, marker: PhantomData, } +impl BitSet { + /// Gets the domain size. + pub fn domain_size(&self) -> usize { + self.domain_size + } +} + impl BitSet { /// Creates a new, empty bitset with a given `domain_size`. #[inline] @@ -52,11 +59,6 @@ impl BitSet { result } - /// Gets the domain size. - pub fn domain_size(&self) -> usize { - self.domain_size - } - /// Clear all elements. #[inline] pub fn clear(&mut self) { @@ -75,12 +77,6 @@ impl BitSet { } } - /// Efficiently overwrite `self` with `other`. - pub fn overwrite(&mut self, other: &BitSet) { - assert!(self.domain_size == other.domain_size); - self.words.clone_from_slice(&other.words); - } - /// Count the number of set bits in the set. pub fn count(&self) -> usize { self.words.iter().map(|e| e.count_ones() as usize).sum() @@ -243,6 +239,21 @@ impl SubtractFromBitSet for BitSet { } } +impl Clone for BitSet { + fn clone(&self) -> Self { + BitSet { domain_size: self.domain_size, words: self.words.clone(), marker: PhantomData } + } + + fn clone_from(&mut self, from: &Self) { + if self.domain_size != from.domain_size { + self.words.resize(from.domain_size, 0); + self.domain_size = from.domain_size; + } + + self.words.copy_from_slice(&from.words); + } +} + impl fmt::Debug for BitSet { fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { w.debug_list().entries(self.iter()).finish() @@ -363,7 +374,7 @@ const SPARSE_MAX: usize = 8; /// /// This type is used by `HybridBitSet`; do not use directly. #[derive(Clone, Debug)] -pub struct SparseBitSet { +pub struct SparseBitSet { domain_size: usize, elems: ArrayVec<[T; SPARSE_MAX]>, } @@ -464,18 +475,27 @@ impl SubtractFromBitSet for SparseBitSet { /// All operations that involve an element will panic if the element is equal /// to or greater than the domain size. All operations that involve two bitsets /// will panic if the bitsets have differing domain sizes. -#[derive(Clone, Debug)] -pub enum HybridBitSet { +#[derive(Clone)] +pub enum HybridBitSet { Sparse(SparseBitSet), Dense(BitSet), } +impl fmt::Debug for HybridBitSet { + fn fmt(&self, w: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + Self::Sparse(b) => b.fmt(w), + Self::Dense(b) => b.fmt(w), + } + } +} + impl HybridBitSet { pub fn new_empty(domain_size: usize) -> Self { HybridBitSet::Sparse(SparseBitSet::new_empty(domain_size)) } - fn domain_size(&self) -> usize { + pub fn domain_size(&self) -> usize { match self { HybridBitSet::Sparse(sparse) => sparse.domain_size, HybridBitSet::Dense(dense) => dense.domain_size, diff --git a/src/librustc_index/bit_set/tests.rs b/compiler/rustc_index/src/bit_set/tests.rs similarity index 100% rename from src/librustc_index/bit_set/tests.rs rename to compiler/rustc_index/src/bit_set/tests.rs diff --git a/src/librustc_index/lib.rs b/compiler/rustc_index/src/lib.rs similarity index 100% rename from src/librustc_index/lib.rs rename to compiler/rustc_index/src/lib.rs diff --git a/src/librustc_index/vec.rs b/compiler/rustc_index/src/vec.rs similarity index 100% rename from src/librustc_index/vec.rs rename to compiler/rustc_index/src/vec.rs diff --git a/src/librustc_index/vec/tests.rs b/compiler/rustc_index/src/vec/tests.rs similarity index 100% rename from src/librustc_index/vec/tests.rs rename to compiler/rustc_index/src/vec/tests.rs diff --git a/compiler/rustc_infer/Cargo.toml b/compiler/rustc_infer/Cargo.toml new file mode 100644 index 0000000000..5dba4106c9 --- /dev/null +++ b/compiler/rustc_infer/Cargo.toml @@ -0,0 +1,24 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_infer" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_graphviz = { path = "../rustc_graphviz" } +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } +rustc_session = { path = "../rustc_session" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_infer/infer/at.rs b/compiler/rustc_infer/src/infer/at.rs similarity index 100% rename from src/librustc_infer/infer/at.rs rename to compiler/rustc_infer/src/infer/at.rs diff --git a/src/librustc_infer/infer/canonical/canonicalizer.rs b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs similarity index 99% rename from src/librustc_infer/infer/canonical/canonicalizer.rs rename to compiler/rustc_infer/src/infer/canonical/canonicalizer.rs index ea32a1ae5a..871fc4fafe 100644 --- a/src/librustc_infer/infer/canonical/canonicalizer.rs +++ b/compiler/rustc_infer/src/infer/canonical/canonicalizer.rs @@ -340,7 +340,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(vid)) => { debug!("canonical: type var found with vid {:?}", vid); match self.infcx.unwrap().probe_ty_var(vid) { @@ -418,7 +418,7 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for Canonicalizer<'cx, 'tcx> { | ty::Foreign(..) | ty::Param(..) | ty::Opaque(..) => { - if t.flags.intersects(self.needs_canonical_flags) { + if t.flags().intersects(self.needs_canonical_flags) { t.super_fold_with(self) } else { t diff --git a/src/librustc_infer/infer/canonical/mod.rs b/compiler/rustc_infer/src/infer/canonical/mod.rs similarity index 100% rename from src/librustc_infer/infer/canonical/mod.rs rename to compiler/rustc_infer/src/infer/canonical/mod.rs diff --git a/src/librustc_infer/infer/canonical/query_response.rs b/compiler/rustc_infer/src/infer/canonical/query_response.rs similarity index 99% rename from src/librustc_infer/infer/canonical/query_response.rs rename to compiler/rustc_infer/src/infer/canonical/query_response.rs index 0dbebac7e3..93e1952189 100644 --- a/src/librustc_infer/infer/canonical/query_response.rs +++ b/compiler/rustc_infer/src/infer/canonical/query_response.rs @@ -422,7 +422,7 @@ impl<'cx, 'tcx> InferCtxt<'cx, 'tcx> { match result_value.unpack() { GenericArgKind::Type(result_value) => { // e.g., here `result_value` might be `?0` in the example above... - if let ty::Bound(debruijn, b) = result_value.kind { + if let ty::Bound(debruijn, b) = *result_value.kind() { // ...in which case we would set `canonical_vars[0]` to `Some(?U)`. // We only allow a `ty::INNERMOST` index in substitutions. diff --git a/src/librustc_infer/infer/canonical/substitute.rs b/compiler/rustc_infer/src/infer/canonical/substitute.rs similarity index 100% rename from src/librustc_infer/infer/canonical/substitute.rs rename to compiler/rustc_infer/src/infer/canonical/substitute.rs diff --git a/src/librustc_infer/infer/combine.rs b/compiler/rustc_infer/src/infer/combine.rs similarity index 76% rename from src/librustc_infer/infer/combine.rs rename to compiler/rustc_infer/src/infer/combine.rs index c89d8ced50..a540face4f 100644 --- a/src/librustc_infer/infer/combine.rs +++ b/compiler/rustc_infer/src/infer/combine.rs @@ -43,7 +43,7 @@ use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation}; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, InferConst, ToPredicate, Ty, TyCtxt, TypeFoldable}; use rustc_middle::ty::{IntType, UintType}; -use rustc_span::DUMMY_SP; +use rustc_span::{Span, DUMMY_SP}; #[derive(Clone)] pub struct CombineFields<'infcx, 'tcx> { @@ -73,7 +73,7 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { { let a_is_expected = relation.a_is_expected(); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { // Relate integral variables to other types (&ty::Infer(ty::IntVar(a_id)), &ty::Infer(ty::IntVar(b_id))) => { self.inner @@ -160,11 +160,11 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { } (ty::ConstKind::Infer(InferConst::Var(vid)), _) => { - return self.unify_const_variable(a_is_expected, vid, b); + return self.unify_const_variable(relation.param_env(), vid, b, a_is_expected); } (_, ty::ConstKind::Infer(InferConst::Var(vid))) => { - return self.unify_const_variable(!a_is_expected, vid, a); + return self.unify_const_variable(relation.param_env(), vid, a, !a_is_expected); } (ty::ConstKind::Unevaluated(..), _) if self.tcx.lazy_normalization() => { // FIXME(#59490): Need to remove the leak check to accommodate @@ -188,17 +188,66 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { ty::relate::super_relate_consts(relation, a, b) } - pub fn unify_const_variable( + /// Unifies the const variable `target_vid` with the given constant. + /// + /// This also tests if the given const `ct` contains an inference variable which was previously + /// unioned with `target_vid`. If this is the case, inferring `target_vid` to `ct` + /// would result in an infinite type as we continously replace an inference variable + /// in `ct` with `ct` itself. + /// + /// This is especially important as unevaluated consts use their parents generics. + /// They therefore often contain unused substs, making these errors far more likely. + /// + /// A good example of this is the following: + /// + /// ```rust + /// #![feature(const_generics)] + /// + /// fn bind(value: [u8; N]) -> [u8; 3 + 4] { + /// todo!() + /// } + /// + /// fn main() { + /// let mut arr = Default::default(); + /// arr = bind(arr); + /// } + /// ``` + /// + /// Here `3 + 4` ends up as `ConstKind::Unevaluated` which uses the generics + /// of `fn bind` (meaning that its substs contain `N`). + /// + /// `bind(arr)` now infers that the type of `arr` must be `[u8; N]`. + /// The assignment `arr = bind(arr)` now tries to equate `N` with `3 + 4`. + /// + /// As `3 + 4` contains `N` in its substs, this must not succeed. + /// + /// See `src/test/ui/const-generics/occurs-check/` for more examples where this is relevant. + fn unify_const_variable( &self, + param_env: ty::ParamEnv<'tcx>, + target_vid: ty::ConstVid<'tcx>, + ct: &'tcx ty::Const<'tcx>, vid_is_expected: bool, - vid: ty::ConstVid<'tcx>, - value: &'tcx ty::Const<'tcx>, ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + let (for_universe, span) = { + let mut inner = self.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + let var_value = variable_table.probe_value(target_vid); + match var_value.val { + ConstVariableValue::Known { value } => { + bug!("instantiating {:?} which has a known value {:?}", target_vid, value) + } + ConstVariableValue::Unknown { universe } => (universe, var_value.origin.span), + } + }; + let value = ConstInferUnifier { infcx: self, span, param_env, for_universe, target_vid } + .relate(ct, ct)?; + self.inner .borrow_mut() .const_unification_table() .unify_var_value( - vid, + target_vid, ConstVarValue { origin: ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, @@ -207,8 +256,8 @@ impl<'infcx, 'tcx> InferCtxt<'infcx, 'tcx> { val: ConstVariableValue::Known { value }, }, ) - .map_err(|e| const_unification_error(vid_is_expected, e))?; - Ok(value) + .map(|()| value) + .map_err(|e| const_unification_error(vid_is_expected, e)) } fn unify_integral_variable( @@ -363,7 +412,7 @@ impl<'infcx, 'tcx> CombineFields<'infcx, 'tcx> { let for_universe = match self.infcx.inner.borrow_mut().type_variables().probe(for_vid) { v @ TypeVariableValue::Known { .. } => { - panic!("instantiating {:?} which has a known value {:?}", for_vid, v,) + bug!("instantiating {:?} which has a known value {:?}", for_vid, v,) } TypeVariableValue::Unknown { universe } => universe, }; @@ -548,7 +597,7 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { // any other type variable related to `vid` via // subtyping. This is basically our "occurs check", preventing // us from creating infinitely sized types. - let result = match t.kind { + let result = match *t.kind() { ty::Infer(ty::TyVar(vid)) => { let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); let sub_vid = self.infcx.inner.borrow_mut().type_variables().sub_root_var(vid); @@ -681,7 +730,6 @@ impl TypeRelation<'tcx> for Generalizer<'_, 'tcx> { } } } - ty::ConstKind::Unevaluated(..) if self.tcx().lazy_normalization() => Ok(c), _ => relate::super_relate_consts(self, c, c), } } @@ -731,3 +779,175 @@ fn float_unification_error<'tcx>( let (ty::FloatVarValue(a), ty::FloatVarValue(b)) = v; TypeError::FloatMismatch(ty::relate::expected_found_bool(a_is_expected, a, b)) } + +struct ConstInferUnifier<'cx, 'tcx> { + infcx: &'cx InferCtxt<'cx, 'tcx>, + + span: Span, + + param_env: ty::ParamEnv<'tcx>, + + for_universe: ty::UniverseIndex, + + /// The vid of the const variable that is in the process of being + /// instantiated; if we find this within the const we are folding, + /// that means we would have created a cyclic const. + target_vid: ty::ConstVid<'tcx>, +} + +// We use `TypeRelation` here to propagate `RelateResult` upwards. +// +// Both inputs are expected to be the same. +impl TypeRelation<'tcx> for ConstInferUnifier<'_, 'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn param_env(&self) -> ty::ParamEnv<'tcx> { + self.param_env + } + + fn tag(&self) -> &'static str { + "ConstInferUnifier" + } + + fn a_is_expected(&self) -> bool { + true + } + + fn relate_with_variance>( + &mut self, + _variance: ty::Variance, + a: T, + b: T, + ) -> RelateResult<'tcx, T> { + // We don't care about variance here. + self.relate(a, b) + } + + fn binders( + &mut self, + a: ty::Binder, + b: ty::Binder, + ) -> RelateResult<'tcx, ty::Binder> + where + T: Relate<'tcx>, + { + Ok(ty::Binder::bind(self.relate(a.skip_binder(), b.skip_binder())?)) + } + + fn tys(&mut self, t: Ty<'tcx>, _t: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { + debug_assert_eq!(t, _t); + debug!("ConstInferUnifier: t={:?}", t); + + match t.kind() { + &ty::Infer(ty::TyVar(vid)) => { + let vid = self.infcx.inner.borrow_mut().type_variables().root_var(vid); + let probe = self.infcx.inner.borrow_mut().type_variables().probe(vid); + match probe { + TypeVariableValue::Known { value: u } => { + debug!("ConstOccursChecker: known value {:?}", u); + self.tys(u, u) + } + TypeVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + return Ok(t); + } + + 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, + false, + origin, + ); + let u = self.tcx().mk_ty_var(new_var_id); + debug!( + "ConstInferUnifier: replacing original vid={:?} with new={:?}", + vid, u + ); + Ok(u) + } + } + } + _ => relate::super_relate_tys(self, t, t), + } + } + + fn regions( + &mut self, + r: ty::Region<'tcx>, + _r: ty::Region<'tcx>, + ) -> RelateResult<'tcx, ty::Region<'tcx>> { + debug_assert_eq!(r, _r); + debug!("ConstInferUnifier: r={:?}", r); + + match r { + // Never make variables for regions bound within the type itself, + // nor for erased regions. + ty::ReLateBound(..) | ty::ReErased => { + return Ok(r); + } + + ty::RePlaceholder(..) + | ty::ReVar(..) + | ty::ReEmpty(_) + | ty::ReStatic + | ty::ReEarlyBound(..) + | ty::ReFree(..) => { + // see common code below + } + } + + let r_universe = self.infcx.universe_of_region(r); + if self.for_universe.can_name(r_universe) { + return Ok(r); + } else { + // FIXME: This is non-ideal because we don't give a + // very descriptive origin for this region variable. + Ok(self.infcx.next_region_var_in_universe(MiscVariable(self.span), self.for_universe)) + } + } + + fn consts( + &mut self, + c: &'tcx ty::Const<'tcx>, + _c: &'tcx ty::Const<'tcx>, + ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { + debug_assert_eq!(c, _c); + debug!("ConstInferUnifier: c={:?}", c); + + match c.val { + ty::ConstKind::Infer(InferConst::Var(vid)) => { + let mut inner = self.infcx.inner.borrow_mut(); + let variable_table = &mut inner.const_unification_table(); + + // Check if the current unification would end up + // unifying `target_vid` with a const which contains + // an inference variable which is unioned with `target_vid`. + // + // Not doing so can easily result in stack overflows. + if variable_table.unioned(self.target_vid, vid) { + return Err(TypeError::CyclicConst(c)); + } + + let var_value = variable_table.probe_value(vid); + match var_value.val { + ConstVariableValue::Known { value: u } => self.consts(u, u), + ConstVariableValue::Unknown { universe } => { + if self.for_universe.can_name(universe) { + Ok(c) + } else { + let new_var_id = variable_table.new_key(ConstVarValue { + origin: var_value.origin, + val: ConstVariableValue::Unknown { universe: self.for_universe }, + }); + Ok(self.tcx().mk_const_var(new_var_id, c.ty)) + } + } + } + } + _ => relate::super_relate_consts(self, c, c), + } + } +} diff --git a/src/librustc_infer/infer/equate.rs b/compiler/rustc_infer/src/infer/equate.rs similarity index 99% rename from src/librustc_infer/infer/equate.rs rename to compiler/rustc_infer/src/infer/equate.rs index 7de752d1de..7c388b5503 100644 --- a/src/librustc_infer/infer/equate.rs +++ b/compiler/rustc_infer/src/infer/equate.rs @@ -77,7 +77,7 @@ impl TypeRelation<'tcx> for Equate<'combine, 'infcx, 'tcx> { debug!("{}.tys: replacements ({:?}, {:?})", self.tag(), a, b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_id)), &ty::Infer(TyVar(b_id))) => { infcx.inner.borrow_mut().type_variables().equate(a_id, b_id); } diff --git a/src/librustc_infer/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs similarity index 94% rename from src/librustc_infer/infer/error_reporting/mod.rs rename to compiler/rustc_infer/src/infer/error_reporting/mod.rs index 8212958510..795c5a64d2 100644 --- a/src/librustc_infer/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -50,6 +50,7 @@ use super::region_constraints::GenericKind; use super::{InferCtxt, RegionVariableOrigin, SubregionOrigin, TypeTrace, ValuePairs}; use crate::infer; +use crate::infer::OriginalQueryValues; use crate::traits::error_reporting::report_object_safety_error; use crate::traits::{ IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, @@ -60,14 +61,16 @@ use rustc_errors::{pluralize, struct_span_err}; use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticStyledString}; use rustc_hir as hir; use rustc_hir::def_id::DefId; +use rustc_hir::lang_items::LangItem; use rustc_hir::{Item, ItemKind, Node}; use rustc_middle::ty::error::TypeError; +use rustc_middle::ty::ParamEnvAnd; use rustc_middle::ty::{ self, subst::{Subst, SubstsRef}, Region, Ty, TyCtxt, TypeFoldable, }; -use rustc_span::{DesugaringKind, Pos, Span}; +use rustc_span::{BytePos, DesugaringKind, Pos, Span}; use rustc_target::spec::abi; use std::{cmp, fmt}; @@ -528,7 +531,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { disambiguated_data: &DisambiguatedDefPathData, ) -> Result { let mut path = print_prefix(self)?; - path.push(disambiguated_data.data.as_symbol().to_string()); + path.push(disambiguated_data.to_string()); Ok(path) } fn path_generic_args( @@ -567,7 +570,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // if they are both "path types", there's a chance of ambiguity // due to different versions of the same crate if let (&ty::Adt(exp_adt, _), &ty::Adt(found_adt, _)) = - (&exp_found.expected.kind, &exp_found.found.kind) + (exp_found.expected.kind(), exp_found.found.kind()) { report_path_match(err, exp_adt.did, found_adt.did); } @@ -614,11 +617,20 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ref prior_arms, last_ty, scrut_hir_id, + opt_suggest_box_span, + arm_span, .. }) => match source { hir::MatchSource::IfLetDesugar { .. } => { let msg = "`if let` arms have incompatible types"; err.span_label(cause.span, msg); + if let Some(ret_sp) = opt_suggest_box_span { + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s), + ); + } } hir::MatchSource::TryDesugar => { if let Some(ty::error::ExpectedFound { expected, .. }) = exp_found { @@ -672,9 +684,23 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } + if let Some(ret_sp) = opt_suggest_box_span { + // Get return type span and point to it. + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + prior_arms.iter().chain(std::iter::once(&arm_span)).map(|s| *s), + ); + } } }, - ObligationCauseCode::IfExpression(box IfExpressionCause { then, outer, semicolon }) => { + ObligationCauseCode::IfExpression(box IfExpressionCause { + then, + else_sp, + outer, + semicolon, + opt_suggest_box_span, + }) => { err.span_label(then, "expected because of this"); if let Some(sp) = outer { err.span_label(sp, "`if` and `else` have incompatible types"); @@ -687,11 +713,48 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { Applicability::MachineApplicable, ); } + if let Some(ret_sp) = opt_suggest_box_span { + self.suggest_boxing_for_return_impl_trait( + err, + ret_sp, + vec![then, else_sp].into_iter(), + ); + } } _ => (), } } + fn suggest_boxing_for_return_impl_trait( + &self, + err: &mut DiagnosticBuilder<'tcx>, + return_sp: Span, + arm_spans: impl Iterator, + ) { + err.multipart_suggestion( + "you could change the return type to be a boxed trait object", + vec![ + (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box".to_string()), + ], + Applicability::MaybeIncorrect, + ); + let sugg = arm_spans + .flat_map(|sp| { + vec![ + (sp.shrink_to_lo(), "Box::new(".to_string()), + (sp.shrink_to_hi(), ")".to_string()), + ] + .into_iter() + }) + .collect::>(); + err.multipart_suggestion( + "if you change the return type to expect trait objects, box the returned expressions", + sugg, + Applicability::MaybeIncorrect, + ); + } + /// Given that `other_ty` is the same as a type argument for `name` in `sub`, populate `value` /// highlighting `name` and every type argument that isn't at `pos` (which is `other_ty`), and /// populate `other_value` with `other_ty`. @@ -793,7 +856,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); return Some(()); } - if let &ty::Adt(def, _) = &ta.kind { + if let &ty::Adt(def, _) = ta.kind() { let path_ = self.tcx.def_path_str(def.did); if path_ == other_path { self.highlight_outer(&mut t1_out, &mut t2_out, path, sub, i, &other_ty); @@ -974,11 +1037,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// Compares two given types, eliding parts that are the same between them and highlighting /// relevant differences, and return two representation of those types for highlighted printing. fn cmp(&self, t1: Ty<'tcx>, t2: Ty<'tcx>) -> (DiagnosticStyledString, DiagnosticStyledString) { - debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind, t2, t2.kind); + debug!("cmp(t1={}, t1.kind={:?}, t2={}, t2.kind={:?})", t1, t1.kind(), t2, t2.kind()); // helper functions fn equals<'tcx>(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (a, b) if *a == *b => true, (&ty::Int(_), &ty::Infer(ty::InferTy::IntVar(_))) | ( @@ -1011,7 +1074,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } // process starts here - match (&t1.kind, &t2.kind) { + match (t1.kind(), t2.kind()) { (&ty::Adt(def1, sub1), &ty::Adt(def2, sub2)) => { let sub_no_defaults_1 = self.strip_generic_default_params(def1.did, sub1); let sub_no_defaults_2 = self.strip_generic_default_params(def2.did, sub2); @@ -1473,7 +1536,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; match (&terr, expected == found) { (TypeError::Sorts(values), extra) => { - let sort_string = |ty: Ty<'tcx>| match (extra, &ty.kind) { + let sort_string = |ty: Ty<'tcx>| match (extra, ty.kind()) { (true, ty::Opaque(def_id, _)) => format!( " (opaque type at {})", self.tcx @@ -1529,6 +1592,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { }; if let Some(exp_found) = exp_found { self.suggest_as_ref_where_appropriate(span, &exp_found, diag); + self.suggest_await_on_expect_found(cause, span, &exp_found, diag); } // In some (most?) cases cause.body_id points to actual body, but in some cases @@ -1547,6 +1611,62 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { self.note_error_origin(diag, cause, exp_found); } + fn suggest_await_on_expect_found( + &self, + cause: &ObligationCause<'tcx>, + exp_span: Span, + exp_found: &ty::error::ExpectedFound>, + diag: &mut DiagnosticBuilder<'tcx>, + ) { + debug!( + "suggest_await_on_expect_found: exp_span={:?}, expected_ty={:?}, found_ty={:?}", + exp_span, exp_found.expected, exp_found.found + ); + + if let ty::Opaque(def_id, _) = *exp_found.expected.kind() { + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + // Future::Output + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + + let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); + if let Some(projection_ty) = projection_ty { + let projection_query = self.canonicalize_query( + &ParamEnvAnd { param_env: self.tcx.param_env(def_id), value: projection_ty }, + &mut OriginalQueryValues::default(), + ); + if let Ok(resp) = self.tcx.normalize_projection_ty(projection_query) { + let normalized_ty = resp.value.value.normalized_ty; + debug!("suggest_await_on_expect_found: normalized={:?}", normalized_ty); + if ty::TyS::same_type(normalized_ty, exp_found.found) { + let span = if let ObligationCauseCode::Pattern { + span, + origin_expr: _, + root_ty: _, + } = cause.code + { + // scrutinee's span + span.unwrap_or(exp_span) + } else { + exp_span + }; + diag.span_suggestion_verbose( + span.shrink_to_hi(), + "consider awaiting on the future", + ".await".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + /// When encountering a case where `.as_ref()` on a `Result` or `Option` would be appropriate, /// suggests it. fn suggest_as_ref_where_appropriate( @@ -1556,9 +1676,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { diag: &mut DiagnosticBuilder<'tcx>, ) { if let (ty::Adt(exp_def, exp_substs), ty::Ref(_, found_ty, _)) = - (&exp_found.expected.kind, &exp_found.found.kind) + (exp_found.expected.kind(), exp_found.found.kind()) { - if let ty::Adt(found_def, found_substs) = found_ty.kind { + if let ty::Adt(found_def, found_substs) = *found_ty.kind() { let path_str = format!("{:?}", exp_def); if exp_def == &found_def { let opt_msg = "you can convert from `&Option` to `Option<&T>` using \ @@ -1577,9 +1697,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { { let mut show_suggestion = true; for (exp_ty, found_ty) in exp_substs.types().zip(found_substs.types()) { - match exp_ty.kind { + match *exp_ty.kind() { ty::Ref(_, exp_ty, _) => { - match (&exp_ty.kind, &found_ty.kind) { + match (exp_ty.kind(), found_ty.kind()) { (_, ty::Param(_)) | (_, ty::Infer(_)) | (ty::Param(_), _) @@ -1929,7 +2049,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); if let Some(infer::RelateParamBound(_, t)) = origin { let t = self.resolve_vars_if_possible(&t); - match t.kind { + match t.kind() { // We've got: // fn get_later(g: G, dest: &mut T) -> impl FnOnce() + '_ // suggest: @@ -2033,7 +2153,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => String::new(), }; if !s.is_empty() { - s.push_str(" "); + s.push(' '); } s }; @@ -2171,7 +2291,7 @@ impl TyCategory { } pub fn from_ty(ty: Ty<'_>) -> Option<(Self, DefId)> { - match ty.kind { + match *ty.kind() { ty::Closure(def_id, _) => Some((Self::Closure, def_id)), ty::Opaque(def_id, _) => Some((Self::Opaque, def_id)), ty::Generator(def_id, ..) => Some((Self::Generator, def_id)), diff --git a/src/librustc_infer/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs similarity index 72% rename from src/librustc_infer/infer/error_reporting/need_type_info.rs rename to compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index bf087dfacf..2f3089f1a9 100644 --- a/src/librustc_infer/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -6,9 +6,10 @@ use rustc_hir::def::{DefKind, Namespace}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; use rustc_hir::{Body, Expr, ExprKind, FnRetTy, HirId, Local, Pat}; use rustc_middle::hir::map::Map; +use rustc_middle::infer::unify_key::ConstVariableOriginKind; use rustc_middle::ty::print::Print; use rustc_middle::ty::subst::{GenericArg, GenericArgKind}; -use rustc_middle::ty::{self, DefIdTree, Ty}; +use rustc_middle::ty::{self, DefIdTree, InferConst, Ty}; use rustc_span::source_map::DesugaringKind; use rustc_span::symbol::kw; use rustc_span::Span; @@ -53,7 +54,7 @@ impl<'a, 'tcx> FindHirNodeVisitor<'a, 'tcx> { inner == self.target || match (inner.unpack(), self.target.unpack()) { (GenericArgKind::Type(inner_ty), GenericArgKind::Type(target_ty)) => { - match (&inner_ty.kind, &target_ty.kind) { + match (inner_ty.kind(), target_ty.kind()) { ( &ty::Infer(ty::TyVar(a_vid)), &ty::Infer(ty::TyVar(b_vid)), @@ -175,7 +176,10 @@ fn closure_return_type_suggestion( suggestion, Applicability::HasPlaceholders, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label( + span, + InferCtxt::cannot_infer_msg("type", &name, &descr, parent_name, parent_descr), + ); } /// Given a closure signature, return a `String` containing a list of all its argument types. @@ -216,65 +220,151 @@ impl Into for TypeAnnotationNeeded { } } +/// Information about a constant or a type containing inference variables. +pub struct InferenceDiagnosticsData { + pub name: String, + pub span: Option, + pub description: Cow<'static, str>, + pub parent_name: Option, + pub parent_description: Option<&'static str>, +} + impl<'a, 'tcx> InferCtxt<'a, 'tcx> { - pub fn extract_type_name( + /// Extracts data used by diagnostic for either types or constants + /// which were stuck during inference. + pub fn extract_inference_diagnostics_data( &self, - ty: Ty<'tcx>, + arg: GenericArg<'tcx>, highlight: Option, - ) -> (String, Option, Cow<'static, str>, Option, Option<&'static str>) { - if let ty::Infer(ty::TyVar(ty_vid)) = ty.kind { - let mut inner = self.inner.borrow_mut(); - let ty_vars = &inner.type_variables(); - let var_origin = ty_vars.var_origin(ty_vid); - if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = var_origin.kind { - let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); - let (parent_name, parent_desc) = if let Some(parent_def_id) = parent_def_id { - let parent_name = self - .tcx - .def_key(parent_def_id) - .disambiguated_data - .data - .get_opt_name() - .map(|parent_symbol| parent_symbol.to_string()); + ) -> InferenceDiagnosticsData { + match arg.unpack() { + GenericArgKind::Type(ty) => { + if let ty::Infer(ty::TyVar(ty_vid)) = *ty.kind() { + let mut inner = self.inner.borrow_mut(); + let ty_vars = &inner.type_variables(); + let var_origin = ty_vars.var_origin(ty_vid); + if let TypeVariableOriginKind::TypeParameterDefinition(name, def_id) = + var_origin.kind + { + let parent_def_id = def_id.and_then(|def_id| self.tcx.parent(def_id)); + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); - (parent_name, Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id))) - } else { - (None, None) - }; + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; - if name != kw::SelfUpper { - return ( - name.to_string(), - Some(var_origin.span), - "type parameter".into(), - parent_name, - parent_desc, - ); + if name != kw::SelfUpper { + return InferenceDiagnosticsData { + name: name.to_string(), + span: Some(var_origin.span), + description: "type parameter".into(), + parent_name, + parent_description, + }; + } + } + } + + let mut s = String::new(); + let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; + } + let _ = ty.print(printer); + InferenceDiagnosticsData { + name: s, + span: None, + description: ty.prefix_string(), + parent_name: None, + parent_description: None, } } - } + GenericArgKind::Const(ct) => { + if let ty::ConstKind::Infer(InferConst::Var(vid)) = ct.val { + let origin = + self.inner.borrow_mut().const_unification_table().probe_value(vid).origin; + if let ConstVariableOriginKind::ConstParameterDefinition(name, def_id) = + origin.kind + { + let parent_def_id = self.tcx.parent(def_id); + let (parent_name, parent_description) = + if let Some(parent_def_id) = parent_def_id { + let parent_name = self + .tcx + .def_key(parent_def_id) + .disambiguated_data + .data + .get_opt_name() + .map(|parent_symbol| parent_symbol.to_string()); - let mut s = String::new(); - let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); - if let Some(highlight) = highlight { - printer.region_highlight_mode = highlight; + ( + parent_name, + Some(self.tcx.def_kind(parent_def_id).descr(parent_def_id)), + ) + } else { + (None, None) + }; + + return InferenceDiagnosticsData { + name: name.to_string(), + span: Some(origin.span), + description: "const parameter".into(), + parent_name, + parent_description, + }; + } + + debug_assert!(!origin.span.is_dummy()); + let mut s = String::new(); + let mut printer = + ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::ValueNS); + if let Some(highlight) = highlight { + printer.region_highlight_mode = highlight; + } + let _ = ct.print(printer); + InferenceDiagnosticsData { + name: s, + span: Some(origin.span), + description: "the constant".into(), + parent_name: None, + parent_description: None, + } + } else { + bug!("unexpect const: {:?}", ct); + } + } + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), } - let _ = ty.print(printer); - (s, None, ty.prefix_string(), None, None) } - // FIXME(eddyb) generalize all of this to handle `ty::Const` inference variables as well. - pub fn need_type_info_err( + pub fn emit_inference_failure_err( &self, body_id: Option, span: Span, - ty: Ty<'tcx>, + arg: GenericArg<'tcx>, error_code: TypeAnnotationNeeded, ) -> DiagnosticBuilder<'tcx> { - let ty = self.resolve_vars_if_possible(&ty); - let (name, name_sp, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let arg = self.resolve_vars_if_possible(&arg); + let arg_data = self.extract_inference_diagnostics_data(arg, None); + let kind_str = match arg.unpack() { + GenericArgKind::Type(_) => "type", + GenericArgKind::Const(_) => "the value", + GenericArgKind::Lifetime(_) => bug!("unexpected lifetime"), + }; - let mut local_visitor = FindHirNodeVisitor::new(&self, ty.into(), span); + let mut local_visitor = FindHirNodeVisitor::new(&self, arg, span); let ty_to_string = |ty: Ty<'tcx>| -> String { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.tcx, &mut s, Namespace::TypeNS); @@ -288,7 +378,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { None }; printer.name_resolver = Some(Box::new(&getter)); - let _ = if let ty::FnDef(..) = ty.kind { + let _ = if let ty::FnDef(..) = ty.kind() { // We don't want the regular output for `fn`s because it includes its path in // invalid pseudo-syntax, we want the `fn`-pointer output instead. ty.fn_sig(self.tcx).print(printer) @@ -304,7 +394,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } let err_span = if let Some(pattern) = local_visitor.found_arg_pattern { pattern.span - } else if let Some(span) = name_sp { + } else if let Some(span) = arg_data.span { // `span` here lets us point at `sum` instead of the entire right hand side expr: // error[E0282]: type annotations needed // --> file2.rs:3:15 @@ -336,7 +426,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let ty_msg = match (local_visitor.found_node_ty, local_visitor.found_exact_method_call) { (_, Some(_)) => String::new(), - (Some(ty::TyS { kind: ty::Closure(_, substs), .. }), _) => { + (Some(ty), _) if ty.is_closure() => { + let substs = + if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() }; let fn_sig = substs.as_closure().sig(); let args = closure_args(&fn_sig); let ret = fn_sig.output().skip_binder().to_string(); @@ -349,7 +441,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { _ => String::new(), }; - // When `name` corresponds to a type argument, show the path of the full type we're + // When `arg_data.name` corresponds to a type argument, show the path of the full type we're // trying to infer. In the following example, `ty_msg` contains // " in `std::result::Result`": // ``` @@ -370,7 +462,9 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ); let suffix = match local_visitor.found_node_ty { - Some(ty::TyS { kind: ty::Closure(_, substs), .. }) => { + Some(ty) if ty.is_closure() => { + let substs = + if let ty::Closure(_, substs) = *ty.kind() { substs } else { unreachable!() }; let fn_sig = substs.as_closure().sig(); let ret = fn_sig.output().skip_binder().to_string(); @@ -386,11 +480,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { &mut err, &decl.output, self.tcx.hir().body(body_id), - &descr, - &name, + &arg_data.description, + &arg_data.name, &ret, - parent_name, - parent_descr, + arg_data.parent_name, + arg_data.parent_description, ); // We don't want to give the other suggestions when the problem is the // closure return type. @@ -404,15 +498,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // nudge them in the right direction. format!("a boxed closure type like `Box {}>`", args, ret) } - Some(ty) if is_named_and_not_impl_trait(ty) && name == "_" => { + Some(ty) if is_named_and_not_impl_trait(ty) && arg_data.name == "_" => { let ty = ty_to_string(ty); format!("the explicit type `{}`, with the type parameters specified", ty) } - Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != name => { + Some(ty) if is_named_and_not_impl_trait(ty) && ty.to_string() != arg_data.name => { let ty = ty_to_string(ty); format!( "the explicit type `{}`, where the type parameter `{}` is specified", - ty, name, + ty, arg_data.name, ) } _ => "a type".to_string(), @@ -529,7 +623,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // | ^^^ cannot infer type for `S` // | // = note: type must be known at this point - let span = name_sp.unwrap_or(err_span); + let span = arg_data.span.unwrap_or(err_span); if !err .span .span_labels() @@ -540,43 +634,19 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { // Avoid multiple labels pointing at `span`. err.span_label( span, - InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr), + InferCtxt::cannot_infer_msg( + kind_str, + &arg_data.name, + &arg_data.description, + arg_data.parent_name, + arg_data.parent_description, + ), ); } err } - // FIXME(const_generics): We should either try and merge this with `need_type_info_err` - // or improve the errors created here. - // - // Unlike for type inference variables, we don't yet store the origin of const inference variables. - // This is needed for to get a more relevant error span. - pub fn need_type_info_err_const( - &self, - body_id: Option, - span: Span, - ct: &'tcx ty::Const<'tcx>, - error_code: TypeAnnotationNeeded, - ) -> DiagnosticBuilder<'tcx> { - let mut local_visitor = FindHirNodeVisitor::new(&self, ct.into(), span); - if let Some(body_id) = body_id { - let expr = self.tcx.hir().expect_expr(body_id.hir_id); - local_visitor.visit_expr(expr); - } - - let error_code = error_code.into(); - let mut err = self.tcx.sess.struct_span_err_with_code( - local_visitor.target_span, - "type annotations needed", - error_code, - ); - - err.note("unable to infer the value of a const parameter"); - - err - } - /// If the `FnSig` for the method call can be found and type arguments are identified as /// needed, suggest annotating the call, otherwise point out the resulting type of the call. fn annotate_method_call( @@ -611,11 +681,11 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { let sig = self.tcx.fn_sig(did); let bound_output = sig.output(); let output = bound_output.skip_binder(); - err.span_label(e.span, &format!("this method call resolves to `{:?}`", output)); - let kind = &output.kind; + err.span_label(e.span, &format!("this method call resolves to `{}`", output)); + let kind = output.kind(); if let ty::Projection(proj) = kind { if let Some(span) = self.tcx.hir().span_if_local(proj.item_def_id) { - err.span_label(span, &format!("`{:?}` defined here", output)); + err.span_label(span, &format!("`{}` defined here", output)); } } } @@ -630,7 +700,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { ty: Ty<'tcx>, ) -> DiagnosticBuilder<'tcx> { let ty = self.resolve_vars_if_possible(&ty); - let (name, _, descr, parent_name, parent_descr) = self.extract_type_name(&ty, None); + let data = self.extract_inference_diagnostics_data(ty.into(), None); let mut err = struct_span_err!( self.tcx.sess, @@ -639,18 +709,28 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "type inside {} must be known in this context", kind, ); - err.span_label(span, InferCtxt::missing_type_msg(&name, &descr, parent_name, parent_descr)); + err.span_label( + span, + InferCtxt::cannot_infer_msg( + "type", + &data.name, + &data.description, + data.parent_name, + data.parent_description, + ), + ); err } - fn missing_type_msg( + fn cannot_infer_msg( + kind_str: &str, type_name: &str, descr: &str, parent_name: Option, parent_descr: Option<&str>, - ) -> Cow<'static, str> { + ) -> String { if type_name == "_" { - "cannot infer type".into() + format!("cannot infer {}", kind_str) } else { let parent_desc = if let Some(parent_name) = parent_name { let parent_type_descr = if let Some(parent_descr) = parent_descr { @@ -664,7 +744,15 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { "".to_string() }; - format!("cannot infer type for {} `{}`{}", descr, type_name, parent_desc).into() + // FIXME: We really shouldn't be dealing with strings here + // but instead use a sensible enum for cases like this. + let preposition = if "the value" == kind_str { "of" } else { "for" }; + // For example: "cannot infer type for type parameter `T`" + format!( + "cannot infer {} {} {} `{}`{}", + kind_str, preposition, descr, type_name, parent_desc + ) + .into() } } } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/different_lifetimes.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/different_lifetimes.rs diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/find_anon_type.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/mod.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/mod.rs diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs similarity index 98% rename from src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs index 89142edb2d..e3c613b1d6 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/named_anon_conflict.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/named_anon_conflict.rs @@ -85,7 +85,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { debug!("try_report_named_anon_conflict: ret ty {:?}", ty); if sub == &ty::ReStatic - && v.0.into_iter().find(|t| t.span.desugaring_kind().is_none()).is_some() + && v.0.into_iter().any(|t| t.span.desugaring_kind().is_none()) { // If the failure is due to a `'static` requirement coming from a `dyn` or // `impl` Trait that *isn't* caused by `async fn` desugaring, handle this case diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/nice_region_error/placeholder_error.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/placeholder_error.rs diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs similarity index 96% rename from src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs index 7493b8b0a9..e9d5ebad7d 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/static_impl_trait.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/static_impl_trait.rs @@ -39,6 +39,14 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ) if **sub_r == RegionKind::ReStatic => { // This is for an implicit `'static` requirement coming from `impl dyn Trait {}`. if let ObligationCauseCode::UnifyReceiver(ctxt) = &cause.code { + // This may have a closure and it would cause ICE + // through `find_param_with_region` (#78262). + let anon_reg_sup = tcx.is_suitable_region(sup_r)?; + let fn_returns = tcx.return_type_impl_or_dyn_traits(anon_reg_sup.def_id); + if fn_returns.is_empty() { + return None; + } + let param = self.find_param_with_region(sup_r, sub_r)?; let lifetime = if sup_r.has_name() { format!("lifetime `{}`", sup_r) @@ -465,7 +473,7 @@ struct TraitObjectVisitor(Vec); impl TypeVisitor<'_> for TraitObjectVisitor { fn visit_ty(&mut self, t: Ty<'_>) -> bool { - match t.kind { + match t.kind() { ty::Dynamic(preds, RegionKind::ReStatic) => { if let Some(def_id) = preds.principal_def_id() { self.0.push(def_id); @@ -488,18 +496,16 @@ impl<'tcx> Visitor<'tcx> for HirTraitObjectVisitor { } fn visit_ty(&mut self, t: &'tcx hir::Ty<'tcx>) { - match t.kind { - TyKind::TraitObject( - poly_trait_refs, - Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, - ) => { - for ptr in poly_trait_refs { - if Some(self.1) == ptr.trait_ref.trait_def_id() { - self.0.push(ptr.span); - } + if let TyKind::TraitObject( + poly_trait_refs, + Lifetime { name: LifetimeName::ImplicitObjectLifetimeDefault, .. }, + ) = t.kind + { + for ptr in poly_trait_refs { + if Some(self.1) == ptr.trait_ref.trait_def_id() { + self.0.push(ptr.span); } } - _ => {} } walk_ty(self, t); } diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs similarity index 96% rename from src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index 788eabf296..c061f485c1 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -58,8 +58,8 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { .tcx() .sess .struct_span_err(sp, "`impl` item signature doesn't match `trait` item signature"); - err.span_label(sp, &format!("found `{:?}`", found)); - err.span_label(trait_sp, &format!("expected `{:?}`", expected)); + err.span_label(sp, &format!("found `{}`", found)); + err.span_label(trait_sp, &format!("expected `{}`", expected)); // Get the span of all the used type parameters in the method. let assoc_item = self.tcx().associated_item(trait_def_id); @@ -92,7 +92,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { err.note_expected_found(&"", expected, &"", found); } else { // This fallback shouldn't be necessary, but let's keep it in just in case. - err.note(&format!("expected `{:?}`\n found `{:?}`", expected, found)); + err.note(&format!("expected `{}`\n found `{}`", expected, found)); } err.span_help( type_param_span, diff --git a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs similarity index 99% rename from src/librustc_infer/infer/error_reporting/nice_region_error/util.rs rename to compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index 6e2d49f1ad..c055fed43f 100644 --- a/src/librustc_infer/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -95,7 +95,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { decl: &hir::FnDecl<'_>, ) -> Option { let ret_ty = self.tcx().type_of(scope_def_id); - if let ty::FnDef(_, _) = ret_ty.kind { + if let ty::FnDef(_, _) = ret_ty.kind() { let sig = ret_ty.fn_sig(self.tcx()); let late_bound_regions = self.tcx().collect_referenced_late_bound_regions(&sig.output()); diff --git a/src/librustc_infer/infer/error_reporting/note.rs b/compiler/rustc_infer/src/infer/error_reporting/note.rs similarity index 100% rename from src/librustc_infer/infer/error_reporting/note.rs rename to compiler/rustc_infer/src/infer/error_reporting/note.rs diff --git a/src/librustc_infer/infer/free_regions.rs b/compiler/rustc_infer/src/infer/free_regions.rs similarity index 100% rename from src/librustc_infer/infer/free_regions.rs rename to compiler/rustc_infer/src/infer/free_regions.rs diff --git a/src/librustc_infer/infer/freshen.rs b/compiler/rustc_infer/src/infer/freshen.rs similarity index 99% rename from src/librustc_infer/infer/freshen.rs rename to compiler/rustc_infer/src/infer/freshen.rs index 02bebe10ed..b3d7876c6e 100644 --- a/src/librustc_infer/infer/freshen.rs +++ b/compiler/rustc_infer/src/infer/freshen.rs @@ -144,7 +144,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for TypeFreshener<'a, 'tcx> { let tcx = self.infcx.tcx; - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(v)) => { let opt_ty = self.infcx.inner.borrow_mut().type_variables().probe(v).known(); self.freshen_ty(opt_ty, ty::TyVar(v), ty::FreshTy) diff --git a/src/librustc_infer/infer/fudge.rs b/compiler/rustc_infer/src/infer/fudge.rs similarity index 99% rename from src/librustc_infer/infer/fudge.rs rename to compiler/rustc_infer/src/infer/fudge.rs index c6651108df..d7bc636db8 100644 --- a/src/librustc_infer/infer/fudge.rs +++ b/compiler/rustc_infer/src/infer/fudge.rs @@ -182,7 +182,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for InferenceFudger<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match *ty.kind() { ty::Infer(ty::InferTy::TyVar(vid)) => { if self.type_vars.0.contains(&vid) { // This variable was created during the fudging. diff --git a/src/librustc_infer/infer/glb.rs b/compiler/rustc_infer/src/infer/glb.rs similarity index 100% rename from src/librustc_infer/infer/glb.rs rename to compiler/rustc_infer/src/infer/glb.rs diff --git a/src/librustc_infer/infer/higher_ranked/README.md b/compiler/rustc_infer/src/infer/higher_ranked/README.md similarity index 100% rename from src/librustc_infer/infer/higher_ranked/README.md rename to compiler/rustc_infer/src/infer/higher_ranked/README.md diff --git a/src/librustc_infer/infer/higher_ranked/mod.rs b/compiler/rustc_infer/src/infer/higher_ranked/mod.rs similarity index 100% rename from src/librustc_infer/infer/higher_ranked/mod.rs rename to compiler/rustc_infer/src/infer/higher_ranked/mod.rs diff --git a/src/librustc_infer/infer/lattice.rs b/compiler/rustc_infer/src/infer/lattice.rs similarity index 99% rename from src/librustc_infer/infer/lattice.rs rename to compiler/rustc_infer/src/infer/lattice.rs index 1bf43e74dc..c47d476963 100644 --- a/src/librustc_infer/infer/lattice.rs +++ b/compiler/rustc_infer/src/infer/lattice.rs @@ -58,7 +58,7 @@ where let infcx = this.infcx(); let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { // If one side is known to be a variable and one is not, // create a variable (`v`) to represent the LUB. Make sure to // relate `v` to the non-type-variable first (by passing it diff --git a/src/librustc_infer/infer/lexical_region_resolve/README.md b/compiler/rustc_infer/src/infer/lexical_region_resolve/README.md similarity index 100% rename from src/librustc_infer/infer/lexical_region_resolve/README.md rename to compiler/rustc_infer/src/infer/lexical_region_resolve/README.md diff --git a/src/librustc_infer/infer/lexical_region_resolve/mod.rs b/compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs similarity index 100% rename from src/librustc_infer/infer/lexical_region_resolve/mod.rs rename to compiler/rustc_infer/src/infer/lexical_region_resolve/mod.rs diff --git a/src/librustc_infer/infer/lub.rs b/compiler/rustc_infer/src/infer/lub.rs similarity index 98% rename from src/librustc_infer/infer/lub.rs rename to compiler/rustc_infer/src/infer/lub.rs index 3e2ea3d0f8..9f43fac091 100644 --- a/src/librustc_infer/infer/lub.rs +++ b/compiler/rustc_infer/src/infer/lub.rs @@ -50,7 +50,7 @@ impl TypeRelation<'tcx> for Lub<'combine, 'infcx, 'tcx> { ty::Invariant => self.fields.equate(self.a_is_expected).relate(a, b), ty::Covariant => self.relate(a, b), // FIXME(#41044) -- not correct, need test - ty::Bivariant => Ok(a.clone()), + ty::Bivariant => Ok(a), ty::Contravariant => self.fields.glb(self.a_is_expected).relate(a, b), } } diff --git a/src/librustc_infer/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs similarity index 99% rename from src/librustc_infer/infer/mod.rs rename to compiler/rustc_infer/src/infer/mod.rs index 3744ad5d03..07a55c7f85 100644 --- a/src/librustc_infer/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -21,7 +21,7 @@ use rustc_middle::infer::canonical::{Canonical, CanonicalVarValues}; use rustc_middle::infer::unify_key::{ConstVarValue, ConstVariableValue}; use rustc_middle::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind, ToType}; use rustc_middle::mir; -use rustc_middle::mir::interpret::ConstEvalResult; +use rustc_middle::mir::interpret::EvalToConstValueResult; use rustc_middle::traits::select; use rustc_middle::ty::error::{ExpectedFound, TypeError, UnconstrainedNumeric}; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; @@ -680,7 +680,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } pub fn type_var_diverges(&'a self, ty: Ty<'_>) -> bool { - match ty.kind { + match *ty.kind() { ty::Infer(ty::TyVar(vid)) => self.inner.borrow_mut().type_variables().var_diverges(vid), _ => false, } @@ -693,7 +693,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { pub fn type_is_unconstrained_numeric(&'a self, ty: Ty<'_>) -> UnconstrainedNumeric { use rustc_middle::ty::error::UnconstrainedNumeric::Neither; use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; - match ty.kind { + match *ty.kind() { ty::Infer(ty::IntVar(vid)) => { if self.inner.borrow_mut().int_unification_table().probe_value(vid).is_some() { Neither @@ -1163,7 +1163,10 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } GenericParamDefKind::Const { .. } => { let origin = ConstVariableOrigin { - kind: ConstVariableOriginKind::ConstParameterDefinition(param.name), + kind: ConstVariableOriginKind::ConstParameterDefinition( + param.name, + param.def_id, + ), span, }; let const_var_id = @@ -1275,7 +1278,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { } /// Gives temporary access to the region constraint data. - #[allow(non_camel_case_types)] // bug with impl trait pub fn with_region_constraints( &self, op: impl FnOnce(&RegionConstraintData<'tcx>) -> R, @@ -1542,7 +1544,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { substs: SubstsRef<'tcx>, promoted: Option, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { let mut original_values = OriginalQueryValues::default(); let canonical = self.canonicalize_query(&(param_env, substs), &mut original_values); @@ -1557,7 +1559,7 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> { /// not a type variable, just return it unmodified. // FIXME(eddyb) inline into `ShallowResolver::visit_ty`. fn shallow_resolve_ty(&self, typ: Ty<'tcx>) -> Ty<'tcx> { - match typ.kind { + match *typ.kind() { ty::Infer(ty::TyVar(v)) => { // Not entirely obvious: if `typ` is a type variable, // it can be resolved to an int/float variable, which @@ -1677,7 +1679,7 @@ impl TyOrConstInferVar<'tcx> { /// Tries to extract an inference variable from a type, returns `None` /// for types other than `ty::Infer(_)` (or `InferTy::Fresh*`). pub fn maybe_from_ty(ty: Ty<'tcx>) -> Option { - match ty.kind { + match *ty.kind() { ty::Infer(ty::TyVar(v)) => Some(TyOrConstInferVar::Ty(v)), ty::Infer(ty::IntVar(v)) => Some(TyOrConstInferVar::TyInt(v)), ty::Infer(ty::FloatVar(v)) => Some(TyOrConstInferVar::TyFloat(v)), diff --git a/src/librustc_infer/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs similarity index 99% rename from src/librustc_infer/infer/nll_relate/mod.rs rename to compiler/rustc_infer/src/infer/nll_relate/mod.rs index 3f5ed36035..839891f322 100644 --- a/src/librustc_infer/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -265,7 +265,7 @@ where use crate::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_span::DUMMY_SP; - match value_ty.kind { + match *value_ty.kind() { ty::Projection(other_projection_ty) => { let var = self.infcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, @@ -311,7 +311,7 @@ where // This only presently applies to chalk integration, as NLL // doesn't permit type variables to appear on both sides (and // doesn't use lazy norm). - match value_ty.kind { + match *value_ty.kind() { ty::Infer(ty::TyVar(value_vid)) => { // Two type variables: just equate them. self.infcx.inner.borrow_mut().type_variables().equate(vid, value_vid); @@ -531,7 +531,7 @@ where } } - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (_, &ty::Infer(ty::TyVar(vid))) => { if D::forbid_inference_vars() { // Forbid inference variables in the RHS. @@ -868,7 +868,7 @@ where debug!("TypeGeneralizer::tys(a={:?})", a); - match a.kind { + match *a.kind() { ty::Infer(ty::TyVar(_)) | ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) if D::forbid_inference_vars() => { diff --git a/src/librustc_infer/infer/outlives/env.rs b/compiler/rustc_infer/src/infer/outlives/env.rs similarity index 100% rename from src/librustc_infer/infer/outlives/env.rs rename to compiler/rustc_infer/src/infer/outlives/env.rs diff --git a/src/librustc_infer/infer/outlives/mod.rs b/compiler/rustc_infer/src/infer/outlives/mod.rs similarity index 90% rename from src/librustc_infer/infer/outlives/mod.rs rename to compiler/rustc_infer/src/infer/outlives/mod.rs index a1e7f1fa3e..de98cccf25 100644 --- a/src/librustc_infer/infer/outlives/mod.rs +++ b/compiler/rustc_infer/src/infer/outlives/mod.rs @@ -26,7 +26,8 @@ pub fn explicit_outlives_bounds<'tcx>( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, ty::PredicateAtom::RegionOutlives(ty::OutlivesPredicate(r_a, r_b)) => { Some(OutlivesBound::RegionSubRegion(r_b, r_a)) } diff --git a/src/librustc_infer/infer/outlives/obligations.rs b/compiler/rustc_infer/src/infer/outlives/obligations.rs similarity index 99% rename from src/librustc_infer/infer/outlives/obligations.rs rename to compiler/rustc_infer/src/infer/outlives/obligations.rs index 48f6d937f2..2851da89ab 100644 --- a/src/librustc_infer/infer/outlives/obligations.rs +++ b/compiler/rustc_infer/src/infer/outlives/obligations.rs @@ -383,7 +383,7 @@ where // #55756) in cases where you have e.g., `>::Item: // 'a` in the environment but `trait Foo<'b> { type Item: 'b // }` in the trait definition. - approx_env_bounds.retain(|bound| match bound.0.kind { + approx_env_bounds.retain(|bound| match *bound.0.kind() { ty::Projection(projection_ty) => self .verify_bound .projection_declared_bounds_from_trait(projection_ty) diff --git a/src/librustc_infer/infer/outlives/verify.rs b/compiler/rustc_infer/src/infer/outlives/verify.rs similarity index 99% rename from src/librustc_infer/infer/outlives/verify.rs rename to compiler/rustc_infer/src/infer/outlives/verify.rs index 5a8368700b..21b0836563 100644 --- a/src/librustc_infer/infer/outlives/verify.rs +++ b/compiler/rustc_infer/src/infer/outlives/verify.rs @@ -1,9 +1,9 @@ use crate::infer::outlives::env::RegionBoundPairs; use crate::infer::{GenericKind, VerifyBound}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::DefId; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, Subst}; -use rustc_middle::ty::walk::MiniSet; use rustc_middle::ty::{self, Ty, TyCtxt}; /// The `TypeOutlives` struct has the job of "lowering" a `T: 'a` @@ -46,7 +46,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { ty: Ty<'tcx>, visited: &mut MiniSet>, ) -> VerifyBound<'tcx> { - match ty.kind { + match *ty.kind() { ty::Param(p) => self.param_bound(p), ty::Projection(data) => self.projection_bound(data, visited), ty::FnDef(_, substs) => { @@ -126,7 +126,7 @@ impl<'cx, 'tcx> VerifyBoundCx<'cx, 'tcx> { let projection_ty = GenericKind::Projection(projection_ty).to_ty(self.tcx); let erased_projection_ty = self.tcx.erase_regions(&projection_ty); self.declared_generic_bounds_from_env_with_compare_fn(|ty| { - if let ty::Projection(..) = ty.kind { + if let ty::Projection(..) = ty.kind() { let erased_ty = self.tcx.erase_regions(&ty); erased_ty == erased_projection_ty } else { diff --git a/src/librustc_infer/infer/region_constraints/README.md b/compiler/rustc_infer/src/infer/region_constraints/README.md similarity index 100% rename from src/librustc_infer/infer/region_constraints/README.md rename to compiler/rustc_infer/src/infer/region_constraints/README.md diff --git a/src/librustc_infer/infer/region_constraints/leak_check.rs b/compiler/rustc_infer/src/infer/region_constraints/leak_check.rs similarity index 100% rename from src/librustc_infer/infer/region_constraints/leak_check.rs rename to compiler/rustc_infer/src/infer/region_constraints/leak_check.rs diff --git a/src/librustc_infer/infer/region_constraints/mod.rs b/compiler/rustc_infer/src/infer/region_constraints/mod.rs similarity index 100% rename from src/librustc_infer/infer/region_constraints/mod.rs rename to compiler/rustc_infer/src/infer/region_constraints/mod.rs diff --git a/src/librustc_infer/infer/resolve.rs b/compiler/rustc_infer/src/infer/resolve.rs similarity index 99% rename from src/librustc_infer/infer/resolve.rs rename to compiler/rustc_infer/src/infer/resolve.rs index 74f365ced2..337772d70b 100644 --- a/src/librustc_infer/infer/resolve.rs +++ b/compiler/rustc_infer/src/infer/resolve.rs @@ -124,7 +124,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for UnresolvedTypeFinder<'a, 'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { let t = self.infcx.shallow_resolve(t); if t.has_infer_types() { - if let ty::Infer(infer_ty) = t.kind { + if let ty::Infer(infer_ty) = *t.kind() { // Since we called `shallow_resolve` above, this must // be an (as yet...) unresolved inference variable. let ty_var_span = if let ty::TyVar(ty_vid) = infer_ty { @@ -191,7 +191,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for FullTypeResolver<'a, 'tcx> { t // micro-optimize -- if there is nothing in this type that this fold affects... } else { let t = self.infcx.shallow_resolve(t); - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(vid)) => { self.err = Some(FixupError::UnresolvedTy(vid)); self.tcx().ty_error() diff --git a/src/librustc_infer/infer/sub.rs b/compiler/rustc_infer/src/infer/sub.rs similarity index 99% rename from src/librustc_infer/infer/sub.rs rename to compiler/rustc_infer/src/infer/sub.rs index 308f884f9a..a676c5e65a 100644 --- a/src/librustc_infer/infer/sub.rs +++ b/compiler/rustc_infer/src/infer/sub.rs @@ -83,7 +83,7 @@ impl TypeRelation<'tcx> for Sub<'combine, 'infcx, 'tcx> { let infcx = self.fields.infcx; let a = infcx.inner.borrow_mut().type_variables().replace_if_possible(a); let b = infcx.inner.borrow_mut().type_variables().replace_if_possible(b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (&ty::Infer(TyVar(a_vid)), &ty::Infer(TyVar(b_vid))) => { // Shouldn't have any LBR here, so we can safely put // this under a binder below without fear of accidental diff --git a/src/librustc_infer/infer/type_variable.rs b/compiler/rustc_infer/src/infer/type_variable.rs similarity index 99% rename from src/librustc_infer/infer/type_variable.rs rename to compiler/rustc_infer/src/infer/type_variable.rs index 53c7dcc637..35b97fff3d 100644 --- a/src/librustc_infer/infer/type_variable.rs +++ b/compiler/rustc_infer/src/infer/type_variable.rs @@ -306,7 +306,7 @@ impl<'tcx> TypeVariableTable<'_, 'tcx> { /// instantiated, then return the with which it was /// instantiated. Otherwise, returns `t`. pub fn replace_if_possible(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { ty::Infer(ty::TyVar(v)) => match self.probe(v) { TypeVariableValue::Unknown { .. } => t, TypeVariableValue::Known { value } => value, diff --git a/src/librustc_infer/infer/undo_log.rs b/compiler/rustc_infer/src/infer/undo_log.rs similarity index 100% rename from src/librustc_infer/infer/undo_log.rs rename to compiler/rustc_infer/src/infer/undo_log.rs diff --git a/src/librustc_infer/lib.rs b/compiler/rustc_infer/src/lib.rs similarity index 88% rename from src/librustc_infer/lib.rs rename to compiler/rustc_infer/src/lib.rs index e05041d884..ea9a466134 100644 --- a/src/librustc_infer/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -12,8 +12,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bindings_after_at)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -23,7 +22,6 @@ #![feature(never_type)] #![feature(or_patterns)] #![feature(in_band_lifetimes)] -#![feature(crate_visibility_modifier)] #![recursion_limit = "512"] // For rustdoc #[macro_use] diff --git a/src/librustc_infer/traits/engine.rs b/compiler/rustc_infer/src/traits/engine.rs similarity index 100% rename from src/librustc_infer/traits/engine.rs rename to compiler/rustc_infer/src/traits/engine.rs diff --git a/src/librustc_infer/traits/error_reporting/mod.rs b/compiler/rustc_infer/src/traits/error_reporting/mod.rs similarity index 100% rename from src/librustc_infer/traits/error_reporting/mod.rs rename to compiler/rustc_infer/src/traits/error_reporting/mod.rs diff --git a/src/librustc_infer/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs similarity index 98% rename from src/librustc_infer/traits/mod.rs rename to compiler/rustc_infer/src/traits/mod.rs index 7e7c8588ff..a3c4920fa8 100644 --- a/src/librustc_infer/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -57,7 +57,7 @@ pub type TraitObligation<'tcx> = Obligation<'tcx, ty::PolyTraitPredicate<'tcx>>; // `PredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PredicateObligation<'_>, 40); +static_assert_size!(PredicateObligation<'_>, 32); pub type Obligations<'tcx, O> = Vec>; pub type PredicateObligations<'tcx> = Vec>; diff --git a/src/librustc_infer/traits/project.rs b/compiler/rustc_infer/src/traits/project.rs similarity index 100% rename from src/librustc_infer/traits/project.rs rename to compiler/rustc_infer/src/traits/project.rs diff --git a/src/librustc_infer/traits/structural_impls.rs b/compiler/rustc_infer/src/traits/structural_impls.rs similarity index 100% rename from src/librustc_infer/traits/structural_impls.rs rename to compiler/rustc_infer/src/traits/structural_impls.rs diff --git a/src/librustc_infer/traits/util.rs b/compiler/rustc_infer/src/traits/util.rs similarity index 98% rename from src/librustc_infer/traits/util.rs rename to compiler/rustc_infer/src/traits/util.rs index 93fc7f1f3b..9c0d934a03 100644 --- a/src/librustc_infer/traits/util.rs +++ b/compiler/rustc_infer/src/traits/util.rs @@ -236,6 +236,9 @@ impl Elaborator<'tcx> { .map(|predicate| predicate_obligation(predicate, None)), ); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + // Nothing to elaborate + } } } } diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml new file mode 100644 index 0000000000..e214493a56 --- /dev/null +++ b/compiler/rustc_interface/Cargo.toml @@ -0,0 +1,54 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_interface" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +libc = "0.2" +tracing = "0.1" +rayon = { version = "0.3.0", package = "rustc-rayon" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_attr = { path = "../rustc_attr" } +rustc_builtin_macros = { path = "../rustc_builtin_macros" } +rustc_expand = { path = "../rustc_expand" } +rustc_parse = { path = "../rustc_parse" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_middle = { path = "../rustc_middle" } +rustc_ast_lowering = { path = "../rustc_ast_lowering" } +rustc_ast_passes = { path = "../rustc_ast_passes" } +rustc_incremental = { path = "../rustc_incremental" } +rustc_traits = { path = "../rustc_traits" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } +rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } +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_mir_build = { path = "../rustc_mir_build" } +rustc_passes = { path = "../rustc_passes" } +rustc_typeck = { path = "../rustc_typeck" } +rustc_lint = { path = "../rustc_lint" } +rustc_errors = { path = "../rustc_errors" } +rustc_plugin_impl = { path = "../rustc_plugin_impl" } +rustc_privacy = { path = "../rustc_privacy" } +rustc_resolve = { path = "../rustc_resolve" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_ty = { path = "../rustc_ty" } +tempfile = "3.0.5" + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["libloaderapi"] } + +[dev-dependencies] +rustc_target = { path = "../rustc_target" } + +[features] +llvm = ['rustc_codegen_llvm'] diff --git a/src/librustc_interface/callbacks.rs b/compiler/rustc_interface/src/callbacks.rs similarity index 100% rename from src/librustc_interface/callbacks.rs rename to compiler/rustc_interface/src/callbacks.rs diff --git a/src/librustc_interface/interface.rs b/compiler/rustc_interface/src/interface.rs similarity index 96% rename from src/librustc_interface/interface.rs rename to compiler/rustc_interface/src/interface.rs index 4d84462c42..73a51ad477 100644 --- a/src/librustc_interface/interface.rs +++ b/compiler/rustc_interface/src/interface.rs @@ -154,6 +154,10 @@ pub struct Config { pub override_queries: Option, + /// This is a callback from the driver that is called to create a codegen backend. + pub make_codegen_backend: + Option Box + Send>>, + /// Registry of diagnostics codes. pub registry: Registry, } @@ -167,6 +171,7 @@ pub fn create_compiler_and_run(config: Config, f: impl FnOnce(&Compiler) -> R config.file_loader, config.input_path.clone(), config.lint_caps, + config.make_codegen_backend, registry.clone(), ); diff --git a/src/librustc_interface/lib.rs b/compiler/rustc_interface/src/lib.rs similarity index 95% rename from src/librustc_interface/lib.rs rename to compiler/rustc_interface/src/lib.rs index fe40c615f7..88d2efe96d 100644 --- a/src/librustc_interface/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -4,6 +4,7 @@ #![feature(nll)] #![feature(generator_trait)] #![feature(generators)] +#![feature(once_cell)] #![recursion_limit = "256"] mod callbacks; diff --git a/src/librustc_interface/passes.rs b/compiler/rustc_interface/src/passes.rs similarity index 99% rename from src/librustc_interface/passes.rs rename to compiler/rustc_interface/src/passes.rs index 007dbfb9fd..77d80bb542 100644 --- a/src/librustc_interface/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -2,7 +2,6 @@ use crate::interface::{Compiler, Result}; use crate::proc_macro_decls; use crate::util; -use once_cell::sync::Lazy; use rustc_ast::mut_visit::MutVisitor; use rustc_ast::{self as ast, visit}; use rustc_codegen_ssa::back::link::emit_metadata; @@ -47,6 +46,7 @@ use std::any::Any; use std::cell::RefCell; use std::ffi::OsString; use std::io::{self, BufWriter, Write}; +use std::lazy::SyncLazy; use std::path::PathBuf; use std::rc::Rc; use std::{env, fs, iter, mem}; @@ -292,6 +292,7 @@ fn configure_and_expand_inner<'a>( trace_mac: sess.opts.debugging_opts.trace_macros, should_test: sess.opts.test, span_debug: sess.opts.debugging_opts.span_debug, + proc_macro_backtrace: sess.opts.debugging_opts.proc_macro_backtrace, ..rustc_expand::expand::ExpansionConfig::default(crate_name.to_string()) }; @@ -697,7 +698,7 @@ pub fn prepare_outputs( Ok(outputs) } -pub static DEFAULT_QUERY_PROVIDERS: Lazy = Lazy::new(|| { +pub static DEFAULT_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { let providers = &mut Providers::default(); providers.analysis = analysis; proc_macro_decls::provide(providers); @@ -720,7 +721,7 @@ pub static DEFAULT_QUERY_PROVIDERS: Lazy = Lazy::new(|| { *providers }); -pub static DEFAULT_EXTERN_QUERY_PROVIDERS: Lazy = Lazy::new(|| { +pub static DEFAULT_EXTERN_QUERY_PROVIDERS: SyncLazy = SyncLazy::new(|| { let mut extern_providers = *DEFAULT_QUERY_PROVIDERS; rustc_metadata::provide_extern(&mut extern_providers); rustc_codegen_ssa::provide_extern(&mut extern_providers); diff --git a/src/librustc_interface/proc_macro_decls.rs b/compiler/rustc_interface/src/proc_macro_decls.rs similarity index 100% rename from src/librustc_interface/proc_macro_decls.rs rename to compiler/rustc_interface/src/proc_macro_decls.rs diff --git a/src/librustc_interface/queries.rs b/compiler/rustc_interface/src/queries.rs similarity index 100% rename from src/librustc_interface/queries.rs rename to compiler/rustc_interface/src/queries.rs diff --git a/src/librustc_interface/tests.rs b/compiler/rustc_interface/src/tests.rs similarity index 99% rename from src/librustc_interface/tests.rs rename to compiler/rustc_interface/src/tests.rs index e94745519a..07ce9d0cd9 100644 --- a/src/librustc_interface/tests.rs +++ b/compiler/rustc_interface/src/tests.rs @@ -40,6 +40,7 @@ fn mk_session(matches: getopts::Matches) -> (Session, CfgSpecs) { DiagnosticOutput::Default, Default::default(), None, + None, ); (sess, cfg) } @@ -402,6 +403,7 @@ fn test_codegen_options_tracking_hash() { // `link_arg` is omitted because it just forwards to `link_args`. untracked!(link_args, vec![String::from("abc"), String::from("def")]); untracked!(link_dead_code, Some(true)); + untracked!(link_self_contained, Some(true)); untracked!(linker, Some(PathBuf::from("linker"))); untracked!(linker_flavor, Some(LinkerFlavor::Gcc)); untracked!(no_stack_check, true); @@ -502,6 +504,7 @@ fn test_debugging_options_tracking_hash() { untracked!(print_llvm_passes, true); untracked!(print_mono_items, Some(String::from("abc"))); untracked!(print_type_sizes, true); + untracked!(proc_macro_backtrace, true); untracked!(query_dep_graph, true); untracked!(query_stats, true); untracked!(save_analysis, true); @@ -516,6 +519,7 @@ fn test_debugging_options_tracking_hash() { untracked!(time_llvm_passes, true); untracked!(time_passes, true); untracked!(trace_macros, true); + untracked!(trim_diagnostic_paths, false); untracked!(ui_testing, true); untracked!(unpretty, Some("expanded".to_string())); untracked!(unstable_options, true); @@ -564,6 +568,7 @@ fn test_debugging_options_tracking_hash() { tracked!(osx_rpath_install_name, true); tracked!(panic_abort_tests, true); tracked!(plt, Some(true)); + tracked!(precise_enum_drop_elaboration, false); tracked!(print_fuel, Some("abc".to_string())); tracked!(profile, true); tracked!(profile_emit, Some(PathBuf::from("abc"))); diff --git a/src/librustc_interface/util.rs b/compiler/rustc_interface/src/util.rs similarity index 96% rename from src/librustc_interface/util.rs rename to compiler/rustc_interface/src/util.rs index 8816ba198c..7ace707cc8 100644 --- a/src/librustc_interface/util.rs +++ b/compiler/rustc_interface/src/util.rs @@ -25,6 +25,7 @@ use rustc_span::symbol::{sym, Symbol}; use smallvec::SmallVec; use std::env; use std::io::{self, Write}; +use std::lazy::SyncOnceCell; use std::mem; use std::ops::DerefMut; use std::path::{Path, PathBuf}; @@ -62,8 +63,20 @@ pub fn create_session( file_loader: Option>, input_path: Option, lint_caps: FxHashMap, + make_codegen_backend: Option< + Box Box + Send>, + >, descriptions: Registry, ) -> (Lrc, Lrc>) { + let codegen_backend = if let Some(make_codegen_backend) = make_codegen_backend { + make_codegen_backend(&sopts) + } else { + get_codegen_backend(&sopts) + }; + + // target_override is documented to be called before init(), so this is okay + let target_override = codegen_backend.target_override(&sopts); + let mut sess = session::build_session( sopts, input_path, @@ -71,9 +84,10 @@ pub fn create_session( diagnostic_output, lint_caps, file_loader, + target_override, ); - let codegen_backend = get_codegen_backend(&sess); + codegen_backend.init(&sess); let mut cfg = config::build_configuration(&sess, config::to_crate_config(cfg)); add_configuration(&mut cfg, &mut sess, &*codegen_backend); @@ -218,13 +232,13 @@ fn load_backend_from_dylib(path: &Path) -> fn() -> Box { } } -pub fn get_codegen_backend(sess: &Session) -> Box { +pub fn get_codegen_backend(sopts: &config::Options) -> Box { static INIT: Once = Once::new(); static mut LOAD: fn() -> Box = || unreachable!(); INIT.call_once(|| { - let codegen_name = sess.opts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); + let codegen_name = sopts.debugging_opts.codegen_backend.as_deref().unwrap_or("llvm"); let backend = match codegen_name { filename if filename.contains('.') => load_backend_from_dylib(filename.as_ref()), codegen_name => get_builtin_codegen_backend(codegen_name), @@ -234,17 +248,14 @@ pub fn get_codegen_backend(sess: &Session) -> Box { LOAD = backend; } }); - let backend = unsafe { LOAD() }; - backend.init(sess); - backend + unsafe { LOAD() } } // This is used for rustdoc, but it uses similar machinery to codegen backend // loading, so we leave the code here. It is potentially useful for other tools // that want to invoke the rustc binary while linking to rustc as well. pub fn rustc_path<'a>() -> Option<&'a Path> { - static RUSTC_PATH: once_cell::sync::OnceCell> = - once_cell::sync::OnceCell::new(); + static RUSTC_PATH: SyncOnceCell> = SyncOnceCell::new(); const BIN_PATH: &str = env!("RUSTC_INSTALL_BINDIR"); @@ -693,6 +704,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { rules, id: resolver.next_node_id(), span: rustc_span::DUMMY_SP, + tokens: None, } } @@ -709,6 +721,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: resolver.next_node_id(), kind: ast::StmtKind::Expr(expr), span: rustc_span::DUMMY_SP, + tokens: None, } } @@ -725,6 +738,7 @@ impl<'a> MutVisitor for ReplaceBodyWithLoop<'a, '_> { id: self.resolver.next_node_id(), span: rustc_span::DUMMY_SP, kind: ast::StmtKind::Expr(loop_expr), + tokens: None, }; if self.within_static_or_const { diff --git a/src/librustc_lexer/Cargo.toml b/compiler/rustc_lexer/Cargo.toml similarity index 93% rename from src/librustc_lexer/Cargo.toml rename to compiler/rustc_lexer/Cargo.toml index 28b56f6fef..12101776de 100644 --- a/src/librustc_lexer/Cargo.toml +++ b/compiler/rustc_lexer/Cargo.toml @@ -14,11 +14,10 @@ Rust lexer used by rustc. No stability guarantees are provided. # This will be used when publishing this crate as `rustc-ap-rustc_lexer`. [lib] doctest = false -name = "rustc_lexer" # Note that this crate purposefully does not depend on other rustc crates [dependencies] unicode-xid = "0.2.0" [dev-dependencies] -expect-test = "0.1" +expect-test = "1.0" diff --git a/src/librustc_lexer/src/cursor.rs b/compiler/rustc_lexer/src/cursor.rs similarity index 100% rename from src/librustc_lexer/src/cursor.rs rename to compiler/rustc_lexer/src/cursor.rs diff --git a/src/librustc_lexer/src/lib.rs b/compiler/rustc_lexer/src/lib.rs similarity index 98% rename from src/librustc_lexer/src/lib.rs rename to compiler/rustc_lexer/src/lib.rs index b7d6194cd7..d784a86f14 100644 --- a/src/librustc_lexer/src/lib.rs +++ b/compiler/rustc_lexer/src/lib.rs @@ -2,7 +2,7 @@ //! //! The idea with `librustc_lexer` is to make a reusable library, //! by separating out pure lexing and rustc-specific concerns, like spans, -//! error reporting an interning. So, rustc_lexer operates directly on `&str`, +//! error reporting, and interning. So, rustc_lexer operates directly on `&str`, //! produces simple tokens which are a pair of type-tag and a bit of original text, //! and does not report errors, instead storing them as flags on the token. //! @@ -191,12 +191,16 @@ pub fn strip_shebang(input: &str) -> Option { // For simplicity we consider any line starting with `#!` a shebang, // regardless of restrictions put on shebangs by specific platforms. if let Some(input_tail) = input.strip_prefix("#!") { - // Ok, this is a shebang but if the next non-whitespace token is `[` or maybe - // a doc comment (due to `TokenKind::(Line,Block)Comment` ambiguity at lexer level), + // Ok, this is a shebang but if the next non-whitespace token is `[`, // then it may be valid Rust code, so consider it Rust code. - let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| - !matches!(tok, TokenKind::Whitespace | TokenKind::LineComment { .. } | TokenKind::BlockComment { .. }) - ); + let next_non_whitespace_token = tokenize(input_tail).map(|tok| tok.kind).find(|tok| { + !matches!( + tok, + TokenKind::Whitespace + | TokenKind::LineComment { doc_style: None } + | TokenKind::BlockComment { doc_style: None, .. } + ) + }); if next_non_whitespace_token != Some(TokenKind::OpenBracket) { // No other choice than to consider this a shebang. return Some(2 + input_tail.lines().next().unwrap_or_default().len()); diff --git a/compiler/rustc_lexer/src/tests.rs b/compiler/rustc_lexer/src/tests.rs new file mode 100644 index 0000000000..94017b7b28 --- /dev/null +++ b/compiler/rustc_lexer/src/tests.rs @@ -0,0 +1,287 @@ +use super::*; + +use expect_test::{expect, Expect}; + +fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { + let s = &format!("r{}", s); + let mut cursor = Cursor::new(s); + cursor.bump(); + let (n_hashes, err) = cursor.raw_double_quoted_string(0); + assert_eq!(n_hashes, expected_hashes); + assert_eq!(err, expected_err); +} + +#[test] +fn test_naked_raw_str() { + check_raw_str(r#""abc""#, 0, None); +} + +#[test] +fn test_raw_no_start() { + check_raw_str(r##""abc"#"##, 0, None); +} + +#[test] +fn test_too_many_terminators() { + // this error is handled in the parser later + check_raw_str(r###"#"abc"##"###, 1, None); +} + +#[test] +fn test_unterminated() { + check_raw_str( + r#"#"abc"#, + 1, + Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }), + ); + check_raw_str( + r###"##"abc"#"###, + 2, + Some(RawStrError::NoTerminator { + expected: 2, + found: 1, + possible_terminator_offset: Some(7), + }), + ); + // We're looking for "# not just any # + check_raw_str( + r###"##"abc#"###, + 2, + Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }), + ) +} + +#[test] +fn test_invalid_start() { + check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); +} + +#[test] +fn test_unterminated_no_pound() { + // https://github.com/rust-lang/rust/issues/70677 + check_raw_str( + r#"""#, + 0, + Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }), + ); +} + +#[test] +fn test_valid_shebang() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#!/usr/bin/rustrun\nlet x = 5;"; + assert_eq!(strip_shebang(input), Some(18)); +} + +#[test] +fn test_invalid_shebang_valid_rust_syntax() { + // https://github.com/rust-lang/rust/issues/70528 + let input = "#! [bad_attribute]"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_shebang_second_line() { + // Because shebangs are interpreted by the kernel, they must be on the first line + let input = "\n#!/bin/bash"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_shebang_space() { + let input = "#! /bin/bash"; + assert_eq!(strip_shebang(input), Some(input.len())); +} + +#[test] +fn test_shebang_empty_shebang() { + let input = "#! \n[attribute(foo)]"; + assert_eq!(strip_shebang(input), None); +} + +#[test] +fn test_invalid_shebang_comment() { + let input = "#!//bin/ami/a/comment\n["; + assert_eq!(strip_shebang(input), None) +} + +#[test] +fn test_invalid_shebang_another_comment() { + let input = "#!/*bin/ami/a/comment*/\n[attribute"; + assert_eq!(strip_shebang(input), None) +} + +#[test] +fn test_shebang_valid_rust_after() { + let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; + assert_eq!(strip_shebang(input), Some(23)) +} + +#[test] +fn test_shebang_followed_by_attrib() { + let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; + assert_eq!(strip_shebang(input), Some(19)); +} + +fn check_lexing(src: &str, expect: Expect) { + let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); + expect.assert_eq(&actual) +} + +#[test] +fn smoke_test() { + check_lexing( + "/* my source file */ fn main() { println!(\"zebra\"); }\n", + expect![[r#" + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 20 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 2 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 4 } + Token { kind: OpenParen, len: 1 } + Token { kind: CloseParen, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: OpenBrace, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: Ident, len: 7 } + Token { kind: Bang, len: 1 } + Token { kind: OpenParen, len: 1 } + Token { kind: Literal { kind: Str { terminated: true }, suffix_start: 7 }, len: 7 } + Token { kind: CloseParen, len: 1 } + Token { kind: Semi, len: 1 } + Token { kind: Whitespace, len: 1 } + Token { kind: CloseBrace, len: 1 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} + +#[test] +fn comment_flavors() { + check_lexing( + r" +// line +//// line as well +/// outer doc line +//! inner doc line +/* block */ +/**/ +/*** also block */ +/** outer doc block */ +/*! inner doc block */ +", + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: None }, len: 7 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: None }, len: 17 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: Some(Outer) }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: LineComment { doc_style: Some(Inner) }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: Some(Outer), terminated: true }, len: 22 } + Token { kind: Whitespace, len: 1 } + Token { kind: BlockComment { doc_style: Some(Inner), terminated: true }, len: 22 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} + +#[test] +fn nested_block_comments() { + check_lexing( + "/* /* */ */'a'", + expect![[r#" + Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + "#]], + ) +} + +#[test] +fn characters() { + check_lexing( + "'a' ' ' '\\n'", + expect![[r#" + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 4 }, len: 4 } + "#]], + ); +} + +#[test] +fn lifetime() { + check_lexing( + "'abc", + expect![[r#" + Token { kind: Lifetime { starts_with_number: false }, len: 4 } + "#]], + ); +} + +#[test] +fn raw_string() { + check_lexing( + "r###\"\"#a\\b\x00c\"\"###", + expect![[r#" + Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 17 }, len: 17 } + "#]], + ) +} + +#[test] +fn literal_suffixes() { + check_lexing( + r####" +'a' +b'a' +"a" +b"a" +1234 +0b101 +0xABC +1.0 +1.0e10 +2us +r###"raw"###suffix +br###"raw"###suffix +"####, + expect![[r#" + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Char { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Byte { terminated: true }, suffix_start: 4 }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Str { terminated: true }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: ByteStr { terminated: true }, suffix_start: 4 }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 4 }, len: 4 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Binary, empty_int: false }, suffix_start: 5 }, len: 5 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Hexadecimal, empty_int: false }, suffix_start: 5 }, len: 5 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Float { base: Decimal, empty_exponent: false }, suffix_start: 3 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Float { base: Decimal, empty_exponent: false }, suffix_start: 6 }, len: 6 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: Int { base: Decimal, empty_int: false }, suffix_start: 1 }, len: 3 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: RawStr { n_hashes: 3, err: None }, suffix_start: 12 }, len: 18 } + Token { kind: Whitespace, len: 1 } + Token { kind: Literal { kind: RawByteStr { n_hashes: 3, err: None }, suffix_start: 13 }, len: 19 } + Token { kind: Whitespace, len: 1 } + "#]], + ) +} diff --git a/src/librustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs similarity index 100% rename from src/librustc_lexer/src/unescape.rs rename to compiler/rustc_lexer/src/unescape.rs diff --git a/src/librustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs similarity index 100% rename from src/librustc_lexer/src/unescape/tests.rs rename to compiler/rustc_lexer/src/unescape/tests.rs diff --git a/compiler/rustc_lint/Cargo.toml b/compiler/rustc_lint/Cargo.toml new file mode 100644 index 0000000000..760a8e385d --- /dev/null +++ b/compiler/rustc_lint/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_lint" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +unicode-security = "0.0.5" +rustc_middle = { path = "../rustc_middle" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr = { path = "../rustc_attr" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_feature = { path = "../rustc_feature" } +rustc_index = { path = "../rustc_index" } +rustc_session = { path = "../rustc_session" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_lint/array_into_iter.rs b/compiler/rustc_lint/src/array_into_iter.rs similarity index 73% rename from src/librustc_lint/array_into_iter.rs rename to compiler/rustc_lint/src/array_into_iter.rs index 9d74ad3b2f..e6be082da0 100644 --- a/src/librustc_lint/array_into_iter.rs +++ b/compiler/rustc_lint/src/array_into_iter.rs @@ -7,6 +7,31 @@ use rustc_session::lint::FutureIncompatibleInfo; use rustc_span::symbol::sym; declare_lint! { + /// The `array_into_iter` lint detects calling `into_iter` on arrays. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// [1, 2, 3].into_iter().for_each(|n| { *n; }); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the future, it is planned to add an `IntoIter` implementation for + /// arrays such that it will iterate over *values* of the array instead of + /// references. Due to how method resolution works, this will change + /// existing code that uses `into_iter` on arrays. The solution to avoid + /// this warning is to use `iter()` instead of `into_iter()`. + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #66145] for more details and a more thorough + /// description of the lint. + /// + /// [issue #66145]: https://github.com/rust-lang/rust/issues/66145 + /// [future-incompatible]: ../index.md#future-incompatible-lints pub ARRAY_INTO_ITER, Warn, "detects calling `into_iter` on arrays", @@ -53,7 +78,7 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { } // Make sure we found an array after peeling the boxes. - if !matches!(recv_ty.kind, ty::Array(..)) { + if !matches!(recv_ty.kind(), ty::Array(..)) { return; } @@ -66,9 +91,9 @@ impl<'tcx> LateLintPass<'tcx> for ArrayIntoIter { } // Emit lint diagnostic. - let target = match cx.typeck_results().expr_ty_adjusted(receiver_arg).kind { - ty::Ref(_, ty::TyS { kind: ty::Array(..), .. }, _) => "[T; N]", - ty::Ref(_, ty::TyS { kind: ty::Slice(..), .. }, _) => "[T]", + let target = match *cx.typeck_results().expr_ty_adjusted(receiver_arg).kind() { + ty::Ref(_, inner_ty, _) if inner_ty.is_array() => "[T; N]", + ty::Ref(_, inner_ty, _) if matches!(inner_ty.kind(), ty::Slice(..)) => "[T]", // We know the original first argument type is an array type, // we know that the first adjustment was an autoref coercion diff --git a/src/librustc_lint/builtin.rs b/compiler/rustc_lint/src/builtin.rs similarity index 80% rename from src/librustc_lint/builtin.rs rename to compiler/rustc_lint/src/builtin.rs index b337bf0a3f..abd899e8db 100644 --- a/src/librustc_lint/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -21,7 +21,8 @@ //! `late_lint_methods!` invocation in `lib.rs`. use crate::{ - types::CItemKind, EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, + types::{transparent_newtype_field, CItemKind}, + EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext, }; use rustc_ast::attr::{self, HasAttrs}; use rustc_ast::tokenstream::{TokenStream, TokenTree}; @@ -38,9 +39,11 @@ use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::DefId; use rustc_hir::{ForeignItemKind, GenericParamKind, PatKind}; use rustc_hir::{HirId, HirIdSet, Node}; +use rustc_index::vec::Idx; use rustc_middle::lint::LintDiagnosticBuilder; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::subst::{GenericArgKind, Subst}; -use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_middle::ty::{self, layout::LayoutError, Ty, TyCtxt}; use rustc_session::lint::FutureIncompatibleInfo; use rustc_session::Session; use rustc_span::edition::Edition; @@ -59,6 +62,23 @@ use tracing::{debug, trace}; pub use rustc_session::lint::builtin::*; declare_lint! { + /// The `while_true` lint detects `while true { }`. + /// + /// ### Example + /// + /// ```rust,no_run + /// while true { + /// + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `while true` should be replaced with `loop`. A `loop` expression is + /// the preferred way to write an infinite loop because it more directly + /// expresses the intent of the loop. WHILE_TRUE, Warn, "suggest using `loop { }` instead of `while true { }`" @@ -100,6 +120,24 @@ impl EarlyLintPass for WhileTrue { } declare_lint! { + /// The `box_pointers` lints use of the Box type. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(box_pointers)] + /// struct Foo { + /// x: Box, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is mostly historical, and not particularly useful. `Box` + /// used to be built into the language, and the only way to do heap + /// allocation. Today's Rust can call into other allocators, etc. BOX_POINTERS, Allow, "use of owned (Box type) heap memory" @@ -154,6 +192,36 @@ impl<'tcx> LateLintPass<'tcx> for BoxPointers { } declare_lint! { + /// The `non_shorthand_field_patterns` lint detects using `Struct { x: x }` + /// instead of `Struct { x }` in a pattern. + /// + /// ### Example + /// + /// ```rust + /// struct Point { + /// x: i32, + /// y: i32, + /// } + /// + /// + /// fn main() { + /// let p = Point { + /// x: 5, + /// y: 5, + /// }; + /// + /// match p { + /// Point { x: x, y: y } => (), + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is to avoid the repetition of specifying both the + /// field name and the binding name if both identifiers are the same. NON_SHORTHAND_FIELD_PATTERNS, Warn, "using `Struct { x: x }` instead of `Struct { x }` in a pattern" @@ -214,6 +282,25 @@ impl<'tcx> LateLintPass<'tcx> for NonShorthandFieldPatterns { } declare_lint! { + /// The `unsafe_code` lint catches usage of `unsafe` code. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unsafe_code)] + /// fn main() { + /// unsafe { + /// + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is intended to restrict the usage of `unsafe`, which can be + /// difficult to use correctly. UNSAFE_CODE, Allow, "usage of `unsafe` code" @@ -301,6 +388,25 @@ impl EarlyLintPass for UnsafeCode { } declare_lint! { + /// The `missing_docs` lint detects missing documentation for public items. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_docs)] + /// pub fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint is intended to ensure that a library is well-documented. + /// Items without documentation can be difficult for users to understand + /// how to use properly. + /// + /// This lint is "allow" by default because it can be noisy, and not all + /// projects may want to enforce everything to be documented. pub MISSING_DOCS, Allow, "detects missing documentation for public members", @@ -507,6 +613,19 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { ); } + fn check_foreign_item(&mut self, cx: &LateContext<'_>, foreign_item: &hir::ForeignItem<'_>) { + let def_id = cx.tcx.hir().local_def_id(foreign_item.hir_id); + let (article, desc) = cx.tcx.article_and_description(def_id.to_def_id()); + self.check_missing_docs_attrs( + cx, + Some(foreign_item.hir_id), + &foreign_item.attrs, + foreign_item.span, + article, + desc, + ); + } + fn check_struct_field(&mut self, cx: &LateContext<'_>, sf: &hir::StructField<'_>) { if !sf.is_positional() { self.check_missing_docs_attrs( @@ -526,6 +645,34 @@ impl<'tcx> LateLintPass<'tcx> for MissingDoc { } declare_lint! { + /// The `missing_copy_implementations` lint detects potentially-forgotten + /// implementations of [`Copy`]. + /// + /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_copy_implementations)] + /// pub struct Foo { + /// pub field: i32 + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Historically (before 1.0), types were automatically marked as `Copy` + /// if possible. This was changed so that it required an explicit opt-in + /// by implementing the `Copy` trait. As part of this change, a lint was + /// added to alert if a copyable type was not marked `Copy`. + /// + /// This lint is "allow" by default because this code isn't bad; it is + /// common to write newtypes like this specifically so that a `Copy` type + /// is no longer `Copy`. `Copy` types can result in unintended copies of + /// large data which can impact performance. pub MISSING_COPY_IMPLEMENTATIONS, Allow, "detects potentially-forgotten implementations of `Copy`" @@ -582,6 +729,32 @@ impl<'tcx> LateLintPass<'tcx> for MissingCopyImplementations { } declare_lint! { + /// The `missing_debug_implementations` lint detects missing + /// implementations of [`fmt::Debug`]. + /// + /// [`fmt::Debug`]: https://doc.rust-lang.org/std/fmt/trait.Debug.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(missing_debug_implementations)] + /// pub struct Foo; + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Having a `Debug` implementation on all types can assist with + /// debugging, as it provides a convenient way to format and display a + /// value. Using the `#[derive(Debug)]` attribute will automatically + /// generate a typical implementation, or a custom implementation can be + /// added by manually implementing the `Debug` trait. + /// + /// This lint is "allow" by default because adding `Debug` to all types can + /// have a negative impact on compile time and code size. It also requires + /// boilerplate to be added to every type, which can be an impediment. MISSING_DEBUG_IMPLEMENTATIONS, Allow, "detects missing implementations of Debug" @@ -638,6 +811,45 @@ impl<'tcx> LateLintPass<'tcx> for MissingDebugImplementations { } declare_lint! { + /// The `anonymous_parameters` lint detects anonymous parameters in trait + /// definitions. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(anonymous_parameters)] + /// // edition 2015 + /// pub trait Foo { + /// fn foo(usize); + /// } + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This syntax is mostly a historical accident, and can be worked around + /// quite easily by adding an `_` pattern or a descriptive identifier: + /// + /// ```rust + /// trait Foo { + /// fn foo(_: usize); + /// } + /// ``` + /// + /// This syntax is now a hard error in the 2018 edition. In the 2015 + /// edition, this lint is "allow" by default, because the old code is + /// still valid, and warning for all old code can be noisy. This lint + /// enables the [`cargo fix`] tool with the `--edition` flag to + /// automatically transition old code from the 2015 edition to 2018. The + /// tool will switch this lint to "warn" and will automatically apply the + /// suggested fix from the compiler (which is to add `_` to each + /// parameter). This provides a completely automated way to update old + /// code for a new edition. See [issue #41686] for more details. + /// + /// [issue #41686]: https://github.com/rust-lang/rust/issues/41686 + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html pub ANONYMOUS_PARAMETERS, Allow, "detects anonymous parameters", @@ -763,7 +975,7 @@ fn warn_if_doc(cx: &EarlyContext<'_>, node_span: Span, node_kind: &str, attrs: & continue; } - let span = sugared_span.take().unwrap_or_else(|| attr.span); + let span = sugared_span.take().unwrap_or(attr.span); if attr.is_doc_comment() || cx.sess().check_name(attr, sym::doc) { cx.struct_span_lint(UNUSED_DOC_COMMENTS, span, |lint| { @@ -804,12 +1016,54 @@ impl EarlyLintPass for UnusedDocComment { } declare_lint! { + /// The `no_mangle_const_items` lint detects any `const` items with the + /// [`no_mangle` attribute]. + /// + /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[no_mangle] + /// const FOO: i32 = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Constants do not have their symbols exported, and therefore, this + /// probably means you meant to use a [`static`], not a [`const`]. + /// + /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html + /// [`const`]: https://doc.rust-lang.org/reference/items/constant-items.html NO_MANGLE_CONST_ITEMS, Deny, "const items will not have their symbols exported" } declare_lint! { + /// The `no_mangle_generic_items` lint detects generic items that must be + /// mangled. + /// + /// ### Example + /// + /// ```rust + /// #[no_mangle] + /// fn foo(t: T) { + /// + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An function with generics must have its symbol mangled to accommodate + /// the generic parameter. The [`no_mangle` attribute] has no effect in + /// this situation, and should be removed. + /// + /// [`no_mangle` attribute]: https://doc.rust-lang.org/reference/abi.html#the-no_mangle-attribute NO_MANGLE_GENERIC_ITEMS, Warn, "generic items must be mangled" @@ -880,6 +1134,27 @@ impl<'tcx> LateLintPass<'tcx> for InvalidNoMangleItems { } declare_lint! { + /// The `mutable_transmutes` lint catches transmuting from `&T` to `&mut + /// T` because it is [undefined behavior]. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// unsafe { + /// let y = std::mem::transmute::<&i32, &mut i32>(&5); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Certain assumptions are made about aliasing of data, and this transmute + /// violates those assumptions. Consider using [`UnsafeCell`] instead. + /// + /// [`UnsafeCell`]: https://doc.rust-lang.org/std/cell/struct.UnsafeCell.html MUTABLE_TRANSMUTES, Deny, "mutating transmuted &mut T from &T may cause undefined behavior" @@ -891,7 +1166,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) { use rustc_target::spec::abi::Abi::RustIntrinsic; if let Some((&ty::Ref(_, _, from_mt), &ty::Ref(_, _, to_mt))) = - get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (&ty1.kind, &ty2.kind)) + get_transmute_from_to(cx, expr).map(|(ty1, ty2)| (ty1.kind(), ty2.kind())) { if to_mt == hir::Mutability::Mut && from_mt == hir::Mutability::Not { let msg = "mutating transmuted &mut T from &T may cause undefined behavior, \ @@ -929,6 +1204,7 @@ impl<'tcx> LateLintPass<'tcx> for MutableTransmutes { } declare_lint! { + /// The `unstable_features` is deprecated and should no longer be used. UNSTABLE_FEATURES, Allow, "enabling unstable features (deprecated. do not use)" @@ -954,6 +1230,32 @@ impl<'tcx> LateLintPass<'tcx> for UnstableFeatures { } declare_lint! { + /// The `unreachable_pub` lint triggers for `pub` items not reachable from + /// the crate root. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unreachable_pub)] + /// mod foo { + /// pub mod bar { + /// + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A bare `pub` visibility may be misleading if the item is not actually + /// publicly exported from the crate. The `pub(crate)` visibility is + /// recommended to be used instead, which more clearly expresses the intent + /// that the item is only visible within its own crate. + /// + /// This lint is "allow" by default because it will trigger for a large + /// amount existing Rust code, and has some false-positives. Eventually it + /// is desired for this to become warn-by-default. pub UNREACHABLE_PUB, Allow, "`pub` items not reachable from crate root" @@ -1033,6 +1335,21 @@ impl<'tcx> LateLintPass<'tcx> for UnreachablePub { } declare_lint! { + /// The `type_alias_bounds` lint detects bounds in type aliases. + /// + /// ### Example + /// + /// ```rust + /// type SendVec = Vec; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The trait bounds in a type alias are currently ignored, and should not + /// be included to avoid confusion. This was previously allowed + /// unintentionally; this may become a hard error in the future. TYPE_ALIAS_BOUNDS, Warn, "bounds in type aliases are not enforced" @@ -1170,21 +1487,19 @@ declare_lint_pass!( UnusedBrokenConst => [] ); -fn check_const(cx: &LateContext<'_>, body_id: hir::BodyId) { - let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); - // trigger the query once for all constants since that will already report the errors - // FIXME: Use ensure here - let _ = cx.tcx.const_eval_poly(def_id); -} - impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { fn check_item(&mut self, cx: &LateContext<'_>, it: &hir::Item<'_>) { match it.kind { hir::ItemKind::Const(_, body_id) => { - check_const(cx, body_id); + let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); + // trigger the query once for all constants since that will already report the errors + // FIXME: Use ensure here + let _ = cx.tcx.const_eval_poly(def_id); } hir::ItemKind::Static(_, _, body_id) => { - check_const(cx, body_id); + let def_id = cx.tcx.hir().body_owner_def_id(body_id).to_def_id(); + // FIXME: Use ensure here + let _ = cx.tcx.eval_static_initializer(def_id); } _ => {} } @@ -1192,6 +1507,35 @@ impl<'tcx> LateLintPass<'tcx> for UnusedBrokenConst { } declare_lint! { + /// The `trivial_bounds` lint detects trait bounds that don't depend on + /// any type parameters. + /// + /// ### Example + /// + /// ```rust + /// #![feature(trivial_bounds)] + /// pub struct A where i32: Copy; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Usually you would not write a trait bound that you know is always + /// true, or never true. However, when using macros, the macro may not + /// know whether or not the constraint would hold or not at the time when + /// generating the code. Currently, the compiler does not alert you if the + /// constraint is always true, and generates an error if it is never true. + /// The `trivial_bounds` feature changes this to be a warning in both + /// cases, giving macros more freedom and flexibility to generate code, + /// while still providing a signal when writing non-macro code that + /// something is amiss. + /// + /// See [RFC 2056] for more details. This feature is currently only + /// available on the nightly channel, see [tracking issue #48214]. + /// + /// [RFC 2056]: https://github.com/rust-lang/rfcs/blob/master/text/2056-allow-trivial-where-clause-constraints.md + /// [tracking issue #48214]: https://github.com/rust-lang/rust/issues/48214 TRIVIAL_BOUNDS, Warn, "these bounds don't depend on an type parameters" @@ -1226,7 +1570,8 @@ impl<'tcx> LateLintPass<'tcx> for TrivialConstraints { ClosureKind(..) | Subtype(..) | ConstEvaluatable(..) | - ConstEquate(..) => continue, + ConstEquate(..) | + TypeWellFormedFromEnv(..) => continue, }; if predicate.is_global() { cx.struct_span_lint(TRIVIAL_BOUNDS, span, |lint| { @@ -1267,6 +1612,29 @@ declare_lint_pass!( ); declare_lint! { + /// The `ellipsis_inclusive_range_patterns` lint detects the [`...` range + /// pattern], which is deprecated. + /// + /// [`...` range pattern]: https://doc.rust-lang.org/reference/patterns.html#range-patterns + /// + /// ### Example + /// + /// ```rust + /// let x = 123; + /// match x { + /// 0...100 => {} + /// _ => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `...` range pattern syntax was changed to `..=` to avoid potential + /// confusion with the [`..` range expression]. Use the new form instead. + /// + /// [`..` range expression]: https://doc.rust-lang.org/reference/expressions/range-expr.html pub ELLIPSIS_INCLUSIVE_RANGE_PATTERNS, Warn, "`...` range patterns are deprecated" @@ -1353,6 +1721,38 @@ impl EarlyLintPass for EllipsisInclusiveRangePatterns { } declare_lint! { + /// The `unnameable_test_items` lint detects [`#[test]`][test] functions + /// that are not able to be run by the test harness because they are in a + /// position where they are not nameable. + /// + /// [test]: https://doc.rust-lang.org/reference/attributes/testing.html#the-test-attribute + /// + /// ### Example + /// + /// ```rust,test + /// fn main() { + /// #[test] + /// fn foo() { + /// // This test will not fail because it does not run. + /// assert_eq!(1, 2); + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In order for the test harness to run a test, the test function must be + /// located in a position where it can be accessed from the crate root. + /// This generally means it must be defined in a module, and not anywhere + /// else such as inside another function. The compiler previously allowed + /// this without an error, so a lint was added as an alert that a test is + /// not being used. Whether or not this should be allowed has not yet been + /// decided, see [RFC 2471] and [issue #36629]. + /// + /// [RFC 2471]: https://github.com/rust-lang/rfcs/pull/2471#issuecomment-397414443 + /// [issue #36629]: https://github.com/rust-lang/rust/issues/36629 UNNAMEABLE_TEST_ITEMS, Warn, "detects an item that cannot be named being marked as `#[test_case]`", @@ -1398,6 +1798,41 @@ impl<'tcx> LateLintPass<'tcx> for UnnameableTestItems { } declare_lint! { + /// The `keyword_idents` lint detects edition keywords being used as an + /// identifier. + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(keyword_idents)] + /// // edition 2015 + /// fn dyn() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses new keywords + /// that are added to the language that are used as identifiers (such as a + /// variable name, function name, etc.). If you switch the compiler to a + /// new edition without updating the code, then it will fail to compile if + /// you are using a new keyword as an identifier. + /// + /// You can manually change the identifiers to a non-keyword, or use a + /// [raw identifier], for example `r#dyn`, to transition to a new edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in older editions. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler (which is + /// to use a raw identifier). This provides a completely automated way to + /// update old code for a new edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [raw identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html pub KEYWORD_IDENTS, Allow, "detects edition keywords being used as an identifier", @@ -1562,9 +1997,9 @@ impl ExplicitOutlivesRequirements { .filter_map(|(i, bound)| { if let hir::GenericBound::Outlives(lifetime) = bound { let is_inferred = match tcx.named_region(lifetime.hir_id) { - Some(Region::Static) if infer_static => inferred_outlives - .iter() - .any(|r| if let ty::ReStatic = r { true } else { false }), + Some(Region::Static) if infer_static => { + inferred_outlives.iter().any(|r| matches!(r, ty::ReStatic)) + } Some(Region::EarlyBound(index, ..)) => inferred_outlives.iter().any(|r| { if let ty::ReEarlyBound(ebr) = r { ebr.index == index } else { false } }), @@ -1656,9 +2091,10 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { let mut lint_spans = Vec::new(); for param in hir_generics.params { - let has_lifetime_bounds = param.bounds.iter().any(|bound| { - if let hir::GenericBound::Outlives(_) = bound { true } else { false } - }); + let has_lifetime_bounds = param + .bounds + .iter() + .any(|bound| matches!(bound, hir::GenericBound::Outlives(_))); if !has_lifetime_bounds { continue; } @@ -1799,6 +2235,26 @@ impl<'tcx> LateLintPass<'tcx> for ExplicitOutlivesRequirements { } declare_lint! { + /// The `incomplete_features` lint detects unstable features enabled with + /// the [`feature` attribute] that may function improperly in some or all + /// cases. + /// + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust + /// #![feature(generic_associated_types)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Although it is encouraged for people to experiment with unstable + /// features, some of them are known to be incomplete or faulty. This lint + /// is a signal that the feature has not yet been finished, and you may + /// experience problems with it. pub INCOMPLETE_FEATURES, Warn, "incomplete features that may function improperly in some or all cases" @@ -1839,6 +2295,36 @@ impl EarlyLintPass for IncompleteFeatures { } declare_lint! { + /// The `invalid_value` lint detects creating a value that is not valid, + /// such as a NULL reference. + /// + /// ### Example + /// + /// ```rust,no_run + /// # #![allow(unused)] + /// unsafe { + /// let x: &'static i32 = std::mem::zeroed(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In some situations the compiler can detect that the code is creating + /// an invalid value, which should be avoided. + /// + /// In particular, this lint will check for improper use of + /// [`mem::zeroed`], [`mem::uninitialized`], [`mem::transmute`], and + /// [`MaybeUninit::assume_init`] that can cause [undefined behavior]. The + /// lint should provide extra information to indicate what the problem is + /// and a possible solution. + /// + /// [`mem::zeroed`]: https://doc.rust-lang.org/std/mem/fn.zeroed.html + /// [`mem::uninitialized`]: https://doc.rust-lang.org/std/mem/fn.uninitialized.html + /// [`mem::transmute`]: https://doc.rust-lang.org/std/mem/fn.transmute.html + /// [`MaybeUninit::assume_init`]: https://doc.rust-lang.org/std/mem/union.MaybeUninit.html#method.assume_init + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html pub INVALID_VALUE, Warn, "an invalid value is being created (such as a NULL reference)" @@ -1877,13 +2363,6 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { /// Determine if this expression is a "dangerous initialization". fn is_dangerous_init(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> Option { - // `transmute` is inside an anonymous module (the `extern` block?); - // `Invalid` represents the empty string and matches that. - // FIXME(#66075): use diagnostic items. Somehow, that does not seem to work - // on intrinsics right now. - const TRANSMUTE_PATH: &[Symbol] = - &[sym::core, sym::intrinsics, kw::Invalid, sym::transmute]; - if let hir::ExprKind::Call(ref path_expr, ref args) = expr.kind { // Find calls to `mem::{uninitialized,zeroed}` methods. if let hir::ExprKind::Path(ref qpath) = path_expr.kind { @@ -1893,7 +2372,7 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { return Some(InitKind::Zeroed); } else if cx.tcx.is_diagnostic_item(sym::mem_uninitialized, def_id) { return Some(InitKind::Uninit); - } else if cx.match_def_path(def_id, TRANSMUTE_PATH) { + } else if cx.tcx.is_diagnostic_item(sym::transmute, def_id) { if is_zero(&args[0]) { return Some(InitKind::Zeroed); } @@ -1938,13 +2417,13 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { init: InitKind, ) -> Option { use rustc_middle::ty::TyKind::*; - match ty.kind { + match ty.kind() { // Primitive types that don't like 0 as a value. Ref(..) => Some(("references must be non-null".to_string(), None)), Adt(..) if ty.is_box() => Some(("`Box` must be non-null".to_string(), None)), FnPtr(..) => Some(("function pointers must be non-null".to_string(), None)), Never => Some(("the `!` type has no valid value".to_string(), None)), - RawPtr(tm) if matches!(tm.ty.kind, Dynamic(..)) => + RawPtr(tm) if matches!(tm.ty.kind(), Dynamic(..)) => // raw ptr to dyn Trait { Some(("the vtable of a wide raw pointer must be non-null".to_string(), None)) @@ -2039,7 +2518,9 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { // using zeroed or uninitialized memory. // We are extremely conservative with what we warn about. let conjured_ty = cx.typeck_results().expr_ty(expr); - if let Some((msg, span)) = ty_find_init_error(cx.tcx, conjured_ty, init) { + if let Some((msg, span)) = + with_no_trimmed_paths(|| ty_find_init_error(cx.tcx, conjured_ty, init)) + { cx.struct_span_lint(INVALID_VALUE, expr.span, |lint| { let mut err = lint.build(&format!( "the type `{}` does not permit {}", @@ -2068,6 +2549,40 @@ impl<'tcx> LateLintPass<'tcx> for InvalidValue { } declare_lint! { + /// The `clashing_extern_declarations` lint detects when an `extern fn` + /// has been declared with the same name but different types. + /// + /// ### Example + /// + /// ```rust + /// mod m { + /// extern "C" { + /// fn foo(); + /// } + /// } + /// + /// extern "C" { + /// fn foo(_: u32); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Because two symbols of the same name cannot be resolved to two + /// different functions at link time, and one function cannot possibly + /// have two types, a clashing extern declaration is almost certainly a + /// mistake. Check to make sure that the `extern` definitions are correct + /// and equivalent, and possibly consider unifying them in one location. + /// + /// This lint does not run between crates because a project may have + /// dependencies which both rely on the same extern function, but declare + /// it in a different (but valid) way. For example, they may both declare + /// an opaque type for one or more of the arguments (which would end up + /// distinct types), or use types that are valid conversions in the + /// language the `extern fn` is defined in. In these cases, the compiler + /// can't say that the clashing declaration is incorrect. pub CLASHING_EXTERN_DECLARATIONS, Warn, "detects when an extern fn has been declared with the same name but different types" @@ -2162,6 +2677,39 @@ impl ClashingExternDeclarations { ckind: CItemKind, ) -> bool { debug!("structurally_same_type_impl(cx, a = {:?}, b = {:?})", a, b); + let tcx = cx.tcx; + + // Given a transparent newtype, reach through and grab the inner + // type unless the newtype makes the type non-null. + let non_transparent_ty = |ty: Ty<'tcx>| -> Ty<'tcx> { + let mut ty = ty; + loop { + if let ty::Adt(def, substs) = *ty.kind() { + let is_transparent = def.subst(tcx, substs).repr.transparent(); + let is_non_null = crate::types::nonnull_optimization_guaranteed(tcx, &def); + debug!( + "non_transparent_ty({:?}) -- type is transparent? {}, type is non-null? {}", + ty, is_transparent, is_non_null + ); + if is_transparent && !is_non_null { + debug_assert!(def.variants.len() == 1); + let v = &def.variants[VariantIdx::new(0)]; + ty = transparent_newtype_field(tcx, v) + .expect( + "single-variant transparent structure with zero-sized field", + ) + .ty(tcx, substs); + continue; + } + } + debug!("non_transparent_ty -> {:?}", ty); + return ty; + } + }; + + let a = non_transparent_ty(a); + let b = non_transparent_ty(b); + if !seen_types.insert((a, b)) { // We've encountered a cycle. There's no point going any further -- the types are // structurally the same. @@ -2174,14 +2722,20 @@ impl ClashingExternDeclarations { } else { // Do a full, depth-first comparison between the two. use rustc_middle::ty::TyKind::*; - let a_kind = &a.kind; - let b_kind = &b.kind; + let a_kind = a.kind(); + let b_kind = b.kind(); - let compare_layouts = |a, b| -> bool { - let a_layout = &cx.layout_of(a).unwrap().layout.abi; - let b_layout = &cx.layout_of(b).unwrap().layout.abi; - debug!("{:?} == {:?} = {}", a_layout, b_layout, a_layout == b_layout); - a_layout == b_layout + let compare_layouts = |a, b| -> Result> { + debug!("compare_layouts({:?}, {:?})", a, b); + let a_layout = &cx.layout_of(a)?.layout.abi; + let b_layout = &cx.layout_of(b)?.layout.abi; + debug!( + "comparing layouts: {:?} == {:?} = {}", + a_layout, + b_layout, + a_layout == b_layout + ); + Ok(a_layout == b_layout) }; #[allow(rustc::usage_of_ty_tykind)] @@ -2196,11 +2750,19 @@ impl ClashingExternDeclarations { let b = b.subst(cx.tcx, b_substs); debug!("Comparing {:?} and {:?}", a, b); + // We can immediately rule out these types as structurally same if + // their layouts differ. + match compare_layouts(a, b) { + Ok(false) => return false, + _ => (), // otherwise, continue onto the full, fields comparison + } + // Grab a flattened representation of all fields. let a_fields = a_def.variants.iter().flat_map(|v| v.fields.iter()); let b_fields = b_def.variants.iter().flat_map(|v| v.fields.iter()); - compare_layouts(a, b) - && a_fields.eq_by( + + // Perform a structural comparison for each field. + a_fields.eq_by( b_fields, |&ty::FieldDef { did: a_did, .. }, &ty::FieldDef { did: b_did, .. }| { @@ -2283,17 +2845,17 @@ impl ClashingExternDeclarations { if is_primitive_or_pointer(other_kind) => { let (primitive, adt) = - if is_primitive_or_pointer(&a.kind) { (a, b) } else { (b, a) }; + if is_primitive_or_pointer(a.kind()) { (a, b) } else { (b, a) }; if let Some(ty) = crate::types::repr_nullable_ptr(cx, adt, ckind) { ty == primitive } else { - compare_layouts(a, b) + compare_layouts(a, b).unwrap_or(false) } } // Otherwise, just compare the layouts. This may fail to lint for some // incompatible types, but at the very least, will stop reads into // uninitialised memory. - _ => compare_layouts(a, b), + _ => compare_layouts(a, b).unwrap_or(false), } }) } diff --git a/src/librustc_lint/context.rs b/compiler/rustc_lint/src/context.rs similarity index 96% rename from src/librustc_lint/context.rs rename to compiler/rustc_lint/src/context.rs index a6784ffffc..7a3035e5b4 100644 --- a/src/librustc_lint/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -31,6 +31,7 @@ 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::print::with_no_trimmed_paths; use rustc_middle::ty::{self, print::Printer, subst::GenericArg, Ty, TyCtxt}; use rustc_session::lint::{add_elided_lifetime_in_path_suggestion, BuiltinLintDiagnostics}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; @@ -719,6 +720,10 @@ impl<'tcx> LateContext<'tcx> { /// Anonymous scopes such as `extern` imports are matched with `kw::Invalid`; /// inherent `impl` blocks are matched with the name of the type. /// + /// Instead of using this method, it is often preferable to instead use + /// `rustc_diagnostic_item` or a `lang_item`. This is less prone to errors + /// as paths get invalidated if the target definition moves. + /// /// # Examples /// /// ```rust,ignore (no context or def id available) @@ -789,16 +794,18 @@ impl<'tcx> LateContext<'tcx> { trait_ref: Option>, ) -> Result { if trait_ref.is_none() { - if let ty::Adt(def, substs) = self_ty.kind { + if let ty::Adt(def, substs) = self_ty.kind() { return self.print_def_path(def.did, substs); } } // This shouldn't ever be needed, but just in case: - Ok(vec![match trait_ref { - Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)), - None => Symbol::intern(&format!("<{}>", self_ty)), - }]) + with_no_trimmed_paths(|| { + Ok(vec![match trait_ref { + Some(trait_ref) => Symbol::intern(&format!("{:?}", trait_ref)), + None => Symbol::intern(&format!("<{}>", self_ty)), + }]) + }) } fn path_append_impl( @@ -812,12 +819,16 @@ impl<'tcx> LateContext<'tcx> { // This shouldn't ever be needed, but just in case: path.push(match trait_ref { - Some(trait_ref) => Symbol::intern(&format!( - "", - trait_ref.print_only_trait_path(), - self_ty - )), - None => Symbol::intern(&format!("", self_ty)), + Some(trait_ref) => with_no_trimmed_paths(|| { + Symbol::intern(&format!( + "", + trait_ref.print_only_trait_path(), + self_ty + )) + }), + None => { + with_no_trimmed_paths(|| Symbol::intern(&format!("", self_ty))) + } }); Ok(path) @@ -835,7 +846,7 @@ impl<'tcx> LateContext<'tcx> { return Ok(path); } - path.push(disambiguated_data.data.as_symbol()); + path.push(Symbol::intern(&disambiguated_data.data.to_string())); Ok(path) } diff --git a/src/librustc_lint/early.rs b/compiler/rustc_lint/src/early.rs similarity index 100% rename from src/librustc_lint/early.rs rename to compiler/rustc_lint/src/early.rs diff --git a/src/librustc_lint/internal.rs b/compiler/rustc_lint/src/internal.rs similarity index 85% rename from src/librustc_lint/internal.rs rename to compiler/rustc_lint/src/internal.rs index 100e555f29..c2d98b8e4a 100644 --- a/src/librustc_lint/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -5,7 +5,9 @@ use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext} use rustc_ast::{Item, ItemKind}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::Applicability; +use rustc_hir::def::Res; use rustc_hir::{GenericArg, HirId, MutTy, Mutability, Path, PathSegment, QPath, Ty, TyKind}; +use rustc_middle::ty; use rustc_session::{declare_lint_pass, declare_tool_lint, impl_lint_pass}; use rustc_span::hygiene::{ExpnKind, MacroKind}; use rustc_span::symbol::{sym, Ident, Symbol}; @@ -177,11 +179,31 @@ fn lint_ty_kind_usage(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> bool { fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, ty: &Ty<'_>) -> Option { if let TyKind::Path(qpath) = &ty.kind { if let QPath::Resolved(_, path) = qpath { - let did = path.res.opt_def_id()?; - 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()))); + 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()))); + } + } + // 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) { + // 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])); + } + } + } + _ => (), } } } diff --git a/src/librustc_lint/late.rs b/compiler/rustc_lint/src/late.rs similarity index 100% rename from src/librustc_lint/late.rs rename to compiler/rustc_lint/src/late.rs diff --git a/src/librustc_lint/levels.rs b/compiler/rustc_lint/src/levels.rs similarity index 100% rename from src/librustc_lint/levels.rs rename to compiler/rustc_lint/src/levels.rs diff --git a/src/librustc_lint/lib.rs b/compiler/rustc_lint/src/lib.rs similarity index 99% rename from src/librustc_lint/lib.rs rename to compiler/rustc_lint/src/lib.rs index 0a14b16e27..33caedfc19 100644 --- a/src/librustc_lint/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -25,8 +25,9 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![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_syntax)] #![feature(crate_visibility_modifier)] @@ -304,6 +305,7 @@ fn register_builtins(store: &mut LintStore, no_interleave_lints: bool) { add_lint_group!( "rustdoc", BROKEN_INTRA_DOC_LINKS, + PRIVATE_INTRA_DOC_LINKS, INVALID_CODEBLOCK_ATTRIBUTES, MISSING_DOC_CODE_EXAMPLES, PRIVATE_DOC_TESTS diff --git a/src/librustc_lint/non_ascii_idents.rs b/compiler/rustc_lint/src/non_ascii_idents.rs similarity index 64% rename from src/librustc_lint/non_ascii_idents.rs rename to compiler/rustc_lint/src/non_ascii_idents.rs index 2f0b2a8d68..a1c7e47e74 100644 --- a/src/librustc_lint/non_ascii_idents.rs +++ b/compiler/rustc_lint/src/non_ascii_idents.rs @@ -4,6 +4,32 @@ use rustc_data_structures::fx::FxHashMap; use rustc_span::symbol::Symbol; declare_lint! { + /// The `non_ascii_idents` lint detects non-ASCII identifiers. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// #![feature(non_ascii_idents)] + /// #![deny(non_ascii_idents)] + /// fn main() { + /// let föö = 1; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Currently on stable Rust, identifiers must contain ASCII characters. + /// The [`non_ascii_idents`] nightly-only feature allows identifiers to + /// contain non-ASCII characters. This lint allows projects that wish to + /// retain the limit of only using ASCII characters to switch this lint to + /// "forbid" (for example to ease collaboration or for security reasons). + /// See [RFC 2457] for more details. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [RFC 2457]: https://github.com/rust-lang/rfcs/blob/master/text/2457-non-ascii-idents.md pub NON_ASCII_IDENTS, Allow, "detects non-ASCII identifiers", @@ -11,6 +37,37 @@ declare_lint! { } declare_lint! { + /// The `uncommon_codepoints` lint detects uncommon Unicode codepoints in + /// identifiers. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// #![feature(non_ascii_idents)] + /// const µ: f64 = 0.000001; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// about using characters which are not commonly used, and may cause + /// visual confusion. + /// + /// This lint is triggered by identifiers that contain a codepoint that is + /// not part of the set of "Allowed" codepoints as described by [Unicode® + /// Technical Standard #39 Unicode Security Mechanisms Section 3.1 General + /// Security Profile for Identifiers][TR39Allowed]. + /// + /// Note that the set of uncommon codepoints may change over time. Beware + /// that if you "forbid" this lint that existing code may fail in the + /// future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [TR39Allowed]: https://www.unicode.org/reports/tr39/#General_Security_Profile pub UNCOMMON_CODEPOINTS, Warn, "detects uncommon Unicode codepoints in identifiers", @@ -18,6 +75,43 @@ declare_lint! { } declare_lint! { + /// The `confusable_idents` lint detects visually confusable pairs between + /// identifiers. + /// + /// ### Example + /// + /// ```rust + /// #![feature(non_ascii_idents)] + /// + /// // Latin Capital Letter E With Caron + /// pub const Ě: i32 = 1; + /// // Latin Capital Letter E With Breve + /// pub const Ĕ: i32 = 2; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// when different identifiers may appear visually similar, which can + /// cause confusion. + /// + /// The confusable detection algorithm is based on [Unicode® Technical + /// Standard #39 Unicode Security Mechanisms Section 4 Confusable + /// Detection][TR39Confusable]. For every distinct identifier X execute + /// the function `skeleton(X)`. If there exist two distinct identifiers X + /// and Y in the same crate where `skeleton(X) = skeleton(Y)` report it. + /// The compiler uses the same mechanism to check if an identifier is too + /// similar to a keyword. + /// + /// Note that the set of confusable characters may change over time. + /// Beware that if you "forbid" this lint that existing code may fail in + /// the future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html + /// [TR39Confusable]: https://www.unicode.org/reports/tr39/#Confusable_Detection pub CONFUSABLE_IDENTS, Warn, "detects visually confusable pairs between identifiers", @@ -25,6 +119,41 @@ declare_lint! { } declare_lint! { + /// The `mixed_script_confusables` lint detects visually confusable + /// characters in identifiers between different [scripts]. + /// + /// [scripts]: https://en.wikipedia.org/wiki/Script_(Unicode) + /// + /// ### Example + /// + /// ```rust + /// #![feature(non_ascii_idents)] + /// + /// // The Japanese katakana character エ can be confused with the Han character 工. + /// const エ: &'static str = "アイウ"; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// With the [`non_ascii_idents`] nightly-only feature enabled, + /// identifiers are allowed to use non-ASCII characters. This lint warns + /// when characters between different scripts may appear visually similar, + /// which can cause confusion. + /// + /// If the crate contains other identifiers in the same script that have + /// non-confusable characters, then this lint will *not* be issued. For + /// example, if the example given above has another identifier with + /// katakana characters (such as `let カタカナ = 123;`), then this indicates + /// that you are intentionally using katakana, and it will not warn about + /// it. + /// + /// Note that the set of confusable characters may change over time. + /// Beware that if you "forbid" this lint that existing code may fail in + /// the future. + /// + /// [`non_ascii_idents`]: https://doc.rust-lang.org/nightly/unstable-book/language-features/non-ascii-idents.html pub MIXED_SCRIPT_CONFUSABLES, Warn, "detects Unicode scripts whose mixed script confusables codepoints are solely used", @@ -212,7 +341,8 @@ impl EarlyLintPass for NonAsciiIdents { } } - ch_list.sort(); + // We sort primitive chars here and can use unstable sort + ch_list.sort_unstable(); ch_list.dedup(); lint_reports.insert((sp, ch_list), augment_script_set); } diff --git a/src/librustc_lint/nonstandard_style.rs b/compiler/rustc_lint/src/nonstandard_style.rs similarity index 90% rename from src/librustc_lint/nonstandard_style.rs rename to compiler/rustc_lint/src/nonstandard_style.rs index f23e8c5e20..b3125f55d4 100644 --- a/src/librustc_lint/nonstandard_style.rs +++ b/compiler/rustc_lint/src/nonstandard_style.rs @@ -31,6 +31,24 @@ pub fn method_context(cx: &LateContext<'_>, id: hir::HirId) -> MethodLateContext } declare_lint! { + /// The `non_camel_case_types` lint detects types, variants, traits and + /// type parameters that don't have camel case names. + /// + /// ### Example + /// + /// ```rust + /// struct my_struct; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style for these identifiers is to use "camel case", such + /// as `MyStruct`, where the first letter should not be lowercase, and + /// should not use underscores between letters. Underscores are allowed at + /// the beginning and end of the identifier, as well as between + /// non-letters (such as `X86_64`). pub NON_CAMEL_CASE_TYPES, Warn, "types, variants, traits and type parameters should have camel case names" @@ -52,9 +70,9 @@ fn is_camel_case(name: &str) -> bool { // ones (some scripts don't have a concept of upper/lowercase) !name.chars().next().unwrap().is_lowercase() && !name.contains("__") - && !name.chars().collect::>().windows(2).any(|pair| { + && !name.chars().collect::>().array_windows().any(|&[fst, snd]| { // contains a capitalisable character followed by, or preceded by, an underscore - char_has_case(pair[0]) && pair[1] == '_' || char_has_case(pair[1]) && pair[0] == '_' + char_has_case(fst) && snd == '_' || char_has_case(snd) && fst == '_' }) } @@ -161,6 +179,22 @@ impl EarlyLintPass for NonCamelCaseTypes { } declare_lint! { + /// The `non_snake_case` lint detects variables, methods, functions, + /// lifetime parameters and modules that don't have snake case names. + /// + /// ### Example + /// + /// ```rust + /// let MY_VALUE = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style for these identifiers is to use "snake case", + /// where all the characters are in lowercase, with words separated with a + /// single underscore, such as `my_value`. pub NON_SNAKE_CASE, Warn, "variables, methods, functions, lifetime parameters and modules should have snake case names" @@ -379,6 +413,21 @@ impl<'tcx> LateLintPass<'tcx> for NonSnakeCase { } declare_lint! { + /// The `non_upper_case_globals` lint detects static items that don't have + /// uppercase identifiers. + /// + /// ### Example + /// + /// ```rust + /// static max_points: i32 = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is for static item names to use all uppercase + /// letters such as `MAX_POINTS`. pub NON_UPPER_CASE_GLOBALS, Warn, "static constants should have uppercase identifiers" diff --git a/src/librustc_lint/nonstandard_style/tests.rs b/compiler/rustc_lint/src/nonstandard_style/tests.rs similarity index 100% rename from src/librustc_lint/nonstandard_style/tests.rs rename to compiler/rustc_lint/src/nonstandard_style/tests.rs diff --git a/src/librustc_lint/passes.rs b/compiler/rustc_lint/src/passes.rs similarity index 100% rename from src/librustc_lint/passes.rs rename to compiler/rustc_lint/src/passes.rs diff --git a/src/librustc_lint/redundant_semicolon.rs b/compiler/rustc_lint/src/redundant_semicolon.rs similarity index 80% rename from src/librustc_lint/redundant_semicolon.rs rename to compiler/rustc_lint/src/redundant_semicolon.rs index d4aa4968f2..a31deb87ff 100644 --- a/src/librustc_lint/redundant_semicolon.rs +++ b/compiler/rustc_lint/src/redundant_semicolon.rs @@ -4,6 +4,21 @@ use rustc_errors::Applicability; use rustc_span::Span; declare_lint! { + /// The `redundant_semicolons` lint detects unnecessary trailing + /// semicolons. + /// + /// ### Example + /// + /// ```rust + /// let _ = 123;; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Extra semicolons are not needed, and may be removed to avoid confusion + /// and visual clutter. pub REDUNDANT_SEMICOLONS, Warn, "detects unnecessary trailing semicolons" diff --git a/src/librustc_lint/types.rs b/compiler/rustc_lint/src/types.rs similarity index 89% rename from src/librustc_lint/types.rs rename to compiler/rustc_lint/src/types.rs index 4ca5f23ebf..9925444b86 100644 --- a/src/librustc_lint/types.rs +++ b/compiler/rustc_lint/src/types.rs @@ -1,5 +1,3 @@ -#![allow(non_snake_case)] - use crate::{LateContext, LateLintPass, LintContext}; use rustc_ast as ast; use rustc_attr as attr; @@ -11,7 +9,7 @@ use rustc_index::vec::Idx; use rustc_middle::mir::interpret::{sign_extend, truncate}; use rustc_middle::ty::layout::{IntegerExt, SizeSkeleton}; use rustc_middle::ty::subst::SubstsRef; -use rustc_middle::ty::{self, AdtKind, Ty, TypeFoldable}; +use rustc_middle::ty::{self, AdtKind, Ty, TyCtxt, TypeFoldable}; use rustc_span::source_map; use rustc_span::symbol::sym; use rustc_span::{Span, DUMMY_SP}; @@ -23,18 +21,82 @@ use std::cmp; use tracing::debug; declare_lint! { + /// The `unused_comparisons` lint detects comparisons made useless by + /// limits of the types involved. + /// + /// ### Example + /// + /// ```rust + /// fn foo(x: u8) { + /// x >= 0; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A useless comparison may indicate a mistake, and should be fixed or + /// removed. UNUSED_COMPARISONS, Warn, "comparisons made useless by limits of the types involved" } declare_lint! { + /// The `overflowing_literals` lint detects literal out of range for its + /// type. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// let x: u8 = 1000; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to use a literal that overflows the type where + /// it is used. Either use a literal that is within range, or change the + /// type to be within the range of the literal. OVERFLOWING_LITERALS, Deny, "literal out of range for its type" } declare_lint! { + /// The `variant_size_differences` lint detects enums with widely varying + /// variant sizes. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(variant_size_differences)] + /// enum En { + /// V0(u8), + /// VBig([u8; 1024]), + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It can be a mistake to add a variant to an enum that is much larger + /// than the other variants, bloating the overall size required for all + /// variants. This can impact performance and memory usage. This is + /// triggered if one variant is more than 3 times larger than the + /// second-largest variant. + /// + /// Consider placing the large variant's contents on the heap (for example + /// via [`Box`]) to keep the overall size of the enum itself down. + /// + /// This lint is "allow" by default because it can be noisy, and may not be + /// an actual problem. Decisions about this should be guided with + /// profiling and benchmarking. + /// + /// [`Box`]: https://doc.rust-lang.org/std/boxed/index.html VARIANT_SIZE_DIFFERENCES, Allow, "detects enums with widely varying variant sizes" @@ -217,7 +279,7 @@ fn get_type_suggestion(t: Ty<'_>, val: u128, negative: bool) -> Option<&'static } } } - match t.kind { + match t.kind() { ty::Int(i) => find_fit!(i, val, negative, I8 => [U8] => [I16, I32, I64, I128], I16 => [U16] => [I32, I64, I128], @@ -303,7 +365,7 @@ fn lint_uint_literal<'tcx>( if let Node::Expr(par_e) = cx.tcx.hir().get(parent_id) { match par_e.kind { hir::ExprKind::Cast(..) => { - if let ty::Char = cx.typeck_results().expr_ty(par_e).kind { + if let ty::Char = cx.typeck_results().expr_ty(par_e).kind() { cx.struct_span_lint(OVERFLOWING_LITERALS, par_e.span, |lint| { lint.build("only `u8` can be cast into `char`") .span_suggestion( @@ -354,7 +416,7 @@ fn lint_literal<'tcx>( e: &'tcx hir::Expr<'tcx>, lit: &hir::Lit, ) { - match cx.typeck_results().node_type(e.hir_id).kind { + match *cx.typeck_results().node_type(e.hir_id).kind() { ty::Int(t) => { match lit.node { ast::LitKind::Int(v, ast::LitIntType::Signed(_) | ast::LitIntType::Unsuffixed) => { @@ -450,7 +512,7 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { // Normalize the binop so that the literal is always on the RHS in // the comparison let norm_binop = if swap { rev_binop(binop) } else { binop }; - match cx.typeck_results().node_type(expr.hir_id).kind { + match *cx.typeck_results().node_type(expr.hir_id).kind() { ty::Int(int_ty) => { let (min, max) = int_ty_range(int_ty); let lit_val: i128 = match lit.kind { @@ -495,6 +557,27 @@ impl<'tcx> LateLintPass<'tcx> for TypeLimits { } declare_lint! { + /// The `improper_ctypes` lint detects incorrect use of types in foreign + /// modules. + /// + /// ### Example + /// + /// ```rust + /// extern "C" { + /// static STATIC: String; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler has several checks to verify that types used in `extern` + /// blocks are safe and follow certain rules to ensure proper + /// compatibility with the foreign interfaces. This lint is issued when it + /// detects a probable mistake in a definition. The lint usually should + /// provide a description of the issue, along with possibly a hint on how + /// to resolve it. IMPROPER_CTYPES, Warn, "proper use of libc types in foreign modules" @@ -503,6 +586,27 @@ declare_lint! { declare_lint_pass!(ImproperCTypesDeclarations => [IMPROPER_CTYPES]); declare_lint! { + /// The `improper_ctypes_definitions` lint detects incorrect use of + /// [`extern` function] definitions. + /// + /// [`extern` function]: https://doc.rust-lang.org/reference/items/functions.html#extern-function-qualifier + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// pub extern "C" fn str_type(p: &str) { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There are many parameter and return types that may be specified in an + /// `extern` function that are not compatible with the given ABI. This + /// lint is an alert that these types should not be used. The lint usually + /// should provide a description of the issue, along with possibly a hint + /// on how to resolve it. IMPROPER_CTYPES_DEFINITIONS, Warn, "proper use of libc types in foreign item definitions" @@ -527,24 +631,48 @@ enum FfiResult<'tcx> { FfiUnsafe { ty: Ty<'tcx>, reason: String, help: Option }, } +crate fn nonnull_optimization_guaranteed<'tcx>(tcx: TyCtxt<'tcx>, def: &ty::AdtDef) -> bool { + tcx.get_attrs(def.did) + .iter() + .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed)) +} + +/// `repr(transparent)` structs can have a single non-ZST field, this function returns that +/// field. +pub fn transparent_newtype_field<'a, 'tcx>( + tcx: TyCtxt<'tcx>, + variant: &'a ty::VariantDef, +) -> Option<&'a ty::FieldDef> { + let param_env = tcx.param_env(variant.def_id); + for field in &variant.fields { + let field_ty = tcx.type_of(field.did); + let is_zst = + tcx.layout_of(param_env.and(field_ty)).map(|layout| layout.is_zst()).unwrap_or(false); + + if !is_zst { + return Some(field); + } + } + + None +} + /// Is type known to be non-null? -fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { +crate fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKind) -> bool { let tcx = cx.tcx; - match ty.kind { + match ty.kind() { ty::FnPtr(_) => true, ty::Ref(..) => true, ty::Adt(def, _) if def.is_box() && matches!(mode, CItemKind::Definition) => true, ty::Adt(def, substs) if def.repr.transparent() && !def.is_union() => { - let guaranteed_nonnull_optimization = tcx - .get_attrs(def.did) - .iter() - .any(|a| tcx.sess.check_name(a, sym::rustc_nonnull_optimization_guaranteed)); + let marked_non_null = nonnull_optimization_guaranteed(tcx, &def); - if guaranteed_nonnull_optimization { + if marked_non_null { return true; } + for variant in &def.variants { - if let Some(field) = variant.transparent_newtype_field(tcx) { + if let Some(field) = transparent_newtype_field(cx.tcx, variant) { if ty_is_known_nonnull(cx, field.ty(tcx, substs), mode) { return true; } @@ -561,11 +689,11 @@ fn ty_is_known_nonnull<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>, mode: CItemKi /// If the type passed in was not scalar, returns None. fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option> { let tcx = cx.tcx; - Some(match ty.kind { + Some(match *ty.kind() { ty::Adt(field_def, field_substs) => { let inner_field_ty = { let first_non_zst_ty = - field_def.variants.iter().filter_map(|v| v.transparent_newtype_field(tcx)); + field_def.variants.iter().filter_map(|v| transparent_newtype_field(cx.tcx, v)); debug_assert_eq!( first_non_zst_ty.clone().count(), 1, @@ -603,7 +731,7 @@ fn get_nullable_type<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option( ckind: CItemKind, ) -> Option> { debug!("is_repr_nullable_ptr(cx, ty = {:?})", ty); - if let ty::Adt(ty_def, substs) = ty.kind { + if let ty::Adt(ty_def, substs) = ty.kind() { if ty_def.variants.len() != 2 { return None; } @@ -663,7 +791,7 @@ crate fn repr_nullable_ptr<'tcx>( impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { /// Check if the type is array and emit an unsafe type lint. fn check_for_array_ty(&mut self, sp: Span, ty: Ty<'tcx>) -> bool { - if let ty::Array(..) = ty.kind { + if let ty::Array(..) = ty.kind() { self.emit_ffi_unsafe_type_lint( ty, sp, @@ -706,7 +834,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { if def.repr.transparent() { // Can assume that only one field is not a ZST, so only check // that field's type for FFI-safety. - if let Some(field) = variant.transparent_newtype_field(self.cx.tcx) { + 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"); @@ -751,7 +879,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { return FfiSafe; } - match ty.kind { + match ty.kind() { ty::Adt(def, _) if def.is_box() && matches!(self.mode, CItemKind::Definition) => { FfiSafe } @@ -990,7 +1118,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { diag.help(help); } diag.note(note); - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if let Some(sp) = self.cx.tcx.hir().span_if_local(def.did) { diag.span_note(sp, "the type is defined here"); } @@ -1007,7 +1135,7 @@ impl<'a, 'tcx> ImproperCTypesVisitor<'a, 'tcx> { impl<'a, 'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueTypes<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { ty::Opaque(..) => { self.ty = Some(ty); true diff --git a/src/librustc_lint/unused.rs b/compiler/rustc_lint/src/unused.rs similarity index 90% rename from src/librustc_lint/unused.rs rename to compiler/rustc_lint/src/unused.rs index c793e81ebe..1e8c30071e 100644 --- a/src/librustc_lint/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -20,6 +20,29 @@ use rustc_span::{BytePos, Span, DUMMY_SP}; use tracing::debug; declare_lint! { + /// The `unused_must_use` lint detects unused result of a type flagged as + /// `#[must_use]`. + /// + /// ### Example + /// + /// ```rust + /// fn returns_result() -> Result<(), ()> { + /// Ok(()) + /// } + /// + /// fn main() { + /// returns_result(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `#[must_use]` attribute is an indicator that it is a mistake to + /// ignore the value. See [the reference] for more details. + /// + /// [the reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute pub UNUSED_MUST_USE, Warn, "unused result of a type flagged as `#[must_use]`", @@ -27,6 +50,39 @@ declare_lint! { } declare_lint! { + /// The `unused_results` lint checks for the unused result of an + /// expression in a statement. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_results)] + /// fn foo() -> T { panic!() } + /// + /// fn main() { + /// foo::(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Ignoring the return value of a function may indicate a mistake. In + /// cases were it is almost certain that the result should be used, it is + /// recommended to annotate the function with the [`must_use` attribute]. + /// Failure to use such a return value will trigger the [`unused_must_use` + /// lint] which is warn-by-default. The `unused_results` lint is + /// essentially the same, but triggers for *all* return values. + /// + /// This lint is "allow" by default because it can be noisy, and may not be + /// an actual problem. For example, calling the `remove` method of a `Vec` + /// or `HashMap` returns the previous value, which you may not care about. + /// Using this lint would require explicitly ignoring or discarding such + /// values. + /// + /// [`must_use` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-must_use-attribute + /// [`unused_must_use` lint]: warn-by-default.html#unused-must-use pub UNUSED_RESULTS, Allow, "unused result of an expression in a statement" @@ -135,7 +191,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { let plural_suffix = pluralize!(plural_len); - match ty.kind { + match *ty.kind() { ty::Adt(..) if ty.is_box() => { let boxed_ty = ty.boxed_ty(); let descr_pre = &format!("{}boxed ", descr_pre); @@ -265,6 +321,21 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { } declare_lint! { + /// The `path_statements` lint detects path statements with no effect. + /// + /// ### Example + /// + /// ```rust + /// let x = 42; + /// + /// x; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to have a statement that has no effect. pub PATH_STATEMENTS, Warn, "path statements with no effect" @@ -635,6 +706,21 @@ trait UnusedDelimLint { } declare_lint! { + /// The `unused_parens` lint detects `if`, `match`, `while` and `return` + /// with parentheses; they do not need them. + /// + /// ### Examples + /// + /// ```rust + /// if(true) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The parenthesis are not needed, and should be removed. This is the + /// preferred style for writing these expressions. pub(super) UNUSED_PARENS, Warn, "`if`, `match`, `while` and `return` do not need parentheses" @@ -808,6 +894,23 @@ impl EarlyLintPass for UnusedParens { } declare_lint! { + /// The `unused_braces` lint detects unnecessary braces around an + /// expression. + /// + /// ### Example + /// + /// ```rust + /// if { true } { + /// // ... + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The braces are not needed, and should be removed. This is the + /// preferred style for writing these expressions. pub(super) UNUSED_BRACES, Warn, "unnecessary braces around an expression" @@ -929,6 +1032,30 @@ impl EarlyLintPass for UnusedBraces { } declare_lint! { + /// The `unused_import_braces` lint catches unnecessary braces around an + /// imported item. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_import_braces)] + /// use test::{A}; + /// + /// pub mod test { + /// pub struct A; + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If there is only a single item, then remove the braces (`use test::A;` + /// for example). + /// + /// This lint is "allow" by default because it is only enforcing a + /// stylistic choice. UNUSED_IMPORT_BRACES, Allow, "unnecessary braces around an imported item" @@ -978,6 +1105,25 @@ impl EarlyLintPass for UnusedImportBraces { } declare_lint! { + /// The `unused_allocation` lint detects unnecessary allocations that can + /// be eliminated. + /// + /// ### Example + /// + /// ```rust + /// #![feature(box_syntax)] + /// fn main() { + /// let a = (box [1,2,3]).len(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When a `box` expression is immediately coerced to a reference, then + /// the allocation is unnecessary, and a reference (using `&` or `&mut`) + /// should be used instead to avoid the allocation. pub(super) UNUSED_ALLOCATION, Warn, "detects unnecessary allocations that can be eliminated" diff --git a/src/librustc_llvm/Cargo.toml b/compiler/rustc_llvm/Cargo.toml similarity index 67% rename from src/librustc_llvm/Cargo.toml rename to compiler/rustc_llvm/Cargo.toml index 9f2711eec1..e29af05328 100644 --- a/src/librustc_llvm/Cargo.toml +++ b/compiler/rustc_llvm/Cargo.toml @@ -4,10 +4,6 @@ name = "rustc_llvm" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_llvm" -path = "lib.rs" - [features] static-libstdcpp = [] emscripten = [] @@ -16,5 +12,5 @@ emscripten = [] libc = "0.2.73" [build-dependencies] -build_helper = { path = "../build_helper" } -cc = "1.0.58" +build_helper = { path = "../../src/build_helper" } +cc = "1.0.60" diff --git a/src/librustc_llvm/build.rs b/compiler/rustc_llvm/build.rs similarity index 95% rename from src/librustc_llvm/build.rs rename to compiler/rustc_llvm/build.rs index 25c0b40c49..7f1e5cf336 100644 --- a/src/librustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -175,15 +175,15 @@ fn main() { cfg.debug(false); } - build_helper::rerun_if_changed_anything_in_dir(Path::new("../rustllvm")); - cfg.file("../rustllvm/PassWrapper.cpp") - .file("../rustllvm/RustWrapper.cpp") - .file("../rustllvm/ArchiveWrapper.cpp") - .file("../rustllvm/CoverageMappingWrapper.cpp") - .file("../rustllvm/Linker.cpp") + build_helper::rerun_if_changed_anything_in_dir(Path::new("llvm-wrapper")); + cfg.file("llvm-wrapper/PassWrapper.cpp") + .file("llvm-wrapper/RustWrapper.cpp") + .file("llvm-wrapper/ArchiveWrapper.cpp") + .file("llvm-wrapper/CoverageMappingWrapper.cpp") + .file("llvm-wrapper/Linker.cpp") .cpp(true) .cpp_link_stdlib(None) // we handle this below - .compile("rustllvm"); + .compile("llvm-wrapper"); let (llvm_kind, llvm_link_arg) = detect_llvm_link(); @@ -198,6 +198,8 @@ fn main() { } else if target.contains("windows-gnu") { println!("cargo:rustc-link-lib=shell32"); println!("cargo:rustc-link-lib=uuid"); + } else if target.contains("netbsd") || target.contains("haiku") { + println!("cargo:rustc-link-lib=z"); } cmd.args(&components); @@ -257,7 +259,7 @@ fn main() { } // Some LLVM linker flags (-L and -l) may be needed even when linking - // librustc_llvm, for example when using static libc++, we may need to + // rustc_llvm, for example when using static libc++, we may need to // manually specify the library search path and -ldl -lpthread as link // dependencies. let llvm_linker_flags = tracked_env_var_os("LLVM_LINKER_FLAGS"); diff --git a/src/rustllvm/.editorconfig b/compiler/rustc_llvm/llvm-wrapper/.editorconfig similarity index 100% rename from src/rustllvm/.editorconfig rename to compiler/rustc_llvm/llvm-wrapper/.editorconfig diff --git a/src/rustllvm/ArchiveWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp similarity index 99% rename from src/rustllvm/ArchiveWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp index 9ce614fda5..2797fe8df4 100644 --- a/src/rustllvm/ArchiveWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/ArchiveWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/Object/Archive.h" #include "llvm/Object/ArchiveWriter.h" diff --git a/src/rustllvm/CoverageMappingWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp similarity index 98% rename from src/rustllvm/CoverageMappingWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp index 81aba0cbf7..2b1143a4ec 100644 --- a/src/rustllvm/CoverageMappingWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/CoverageMappingWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/ProfileData/Coverage/CoverageMapping.h" #include "llvm/ProfileData/Coverage/CoverageMappingWriter.h" #include "llvm/ProfileData/InstrProf.h" diff --git a/src/rustllvm/rustllvm.h b/compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h similarity index 100% rename from src/rustllvm/rustllvm.h rename to compiler/rustc_llvm/llvm-wrapper/LLVMWrapper.h diff --git a/src/rustllvm/Linker.cpp b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp similarity index 97% rename from src/rustllvm/Linker.cpp rename to compiler/rustc_llvm/llvm-wrapper/Linker.cpp index 69176f9cb1..8766e96f08 100644 --- a/src/rustllvm/Linker.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/Linker.cpp @@ -1,6 +1,6 @@ #include "llvm/Linker/Linker.h" -#include "rustllvm.h" +#include "LLVMWrapper.h" using namespace llvm; diff --git a/src/rustllvm/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp similarity index 99% rename from src/rustllvm/PassWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index 76fe5e7f76..7b1c3f9ba2 100644 --- a/src/rustllvm/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -3,7 +3,7 @@ #include #include -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/Analysis/TargetLibraryInfo.h" #include "llvm/Analysis/TargetTransformInfo.h" diff --git a/src/rustllvm/README b/compiler/rustc_llvm/llvm-wrapper/README similarity index 100% rename from src/rustllvm/README rename to compiler/rustc_llvm/llvm-wrapper/README diff --git a/src/rustllvm/RustWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp similarity index 99% rename from src/rustllvm/RustWrapper.cpp rename to compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp index 9d90b0dfe0..9f8ea7f43d 100644 --- a/src/rustllvm/RustWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/RustWrapper.cpp @@ -1,4 +1,4 @@ -#include "rustllvm.h" +#include "LLVMWrapper.h" #include "llvm/IR/DebugInfoMetadata.h" #include "llvm/IR/DiagnosticInfo.h" #include "llvm/IR/DiagnosticPrinter.h" @@ -1171,6 +1171,7 @@ enum class LLVMRustDiagnosticKind { OptimizationFailure, PGOProfile, Linker, + Unsupported, }; static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { @@ -1197,6 +1198,8 @@ static LLVMRustDiagnosticKind toRust(DiagnosticKind Kind) { return LLVMRustDiagnosticKind::PGOProfile; case DK_Linker: return LLVMRustDiagnosticKind::Linker; + case DK_Unsupported: + return LLVMRustDiagnosticKind::Unsupported; default: return (Kind >= DK_FirstRemark && Kind <= DK_LastRemark) ? LLVMRustDiagnosticKind::OptimizationRemarkOther diff --git a/src/librustc_llvm/lib.rs b/compiler/rustc_llvm/src/lib.rs similarity index 98% rename from src/librustc_llvm/lib.rs rename to compiler/rustc_llvm/src/lib.rs index 9d23397ade..a381290d46 100644 --- a/src/librustc_llvm/lib.rs +++ b/compiler/rustc_llvm/src/lib.rs @@ -1,6 +1,6 @@ #![feature(nll)] #![feature(static_nobundle)] -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] // NOTE: This crate only exists to allow linking on mingw targets. @@ -21,7 +21,6 @@ impl RustString { /// Appending to a Rust string -- used by RawRustStringOstream. #[no_mangle] -#[allow(improper_ctypes_definitions)] pub unsafe extern "C" fn LLVMRustStringWriteImpl( sr: &RustString, ptr: *const c_char, diff --git a/src/librustc_macros/Cargo.toml b/compiler/rustc_macros/Cargo.toml similarity index 100% rename from src/librustc_macros/Cargo.toml rename to compiler/rustc_macros/Cargo.toml diff --git a/src/librustc_macros/src/hash_stable.rs b/compiler/rustc_macros/src/hash_stable.rs similarity index 100% rename from src/librustc_macros/src/hash_stable.rs rename to compiler/rustc_macros/src/hash_stable.rs diff --git a/src/librustc_macros/src/lib.rs b/compiler/rustc_macros/src/lib.rs similarity index 78% rename from src/librustc_macros/src/lib.rs rename to compiler/rustc_macros/src/lib.rs index 7fb3b0e7ea..5c28839c9b 100644 --- a/src/librustc_macros/src/lib.rs +++ b/compiler/rustc_macros/src/lib.rs @@ -1,3 +1,4 @@ +#![feature(proc_macro_diagnostic)] #![allow(rustc::default_hash_types)] #![recursion_limit = "128"] @@ -9,6 +10,7 @@ mod hash_stable; mod lift; mod query; mod serialize; +mod session_diagnostic; mod symbols; mod type_foldable; @@ -36,3 +38,14 @@ decl_derive!([MetadataDecodable] => serialize::meta_decodable_derive); decl_derive!([MetadataEncodable] => serialize::meta_encodable_derive); decl_derive!([TypeFoldable, attributes(type_foldable)] => type_foldable::type_foldable_derive); decl_derive!([Lift, attributes(lift)] => lift::lift_derive); +decl_derive!( + [SessionDiagnostic, attributes( + message, + lint, + error, + label, + suggestion, + suggestion_short, + suggestion_hidden, + suggestion_verbose)] => session_diagnostic::session_diagnostic_derive +); diff --git a/src/librustc_macros/src/lift.rs b/compiler/rustc_macros/src/lift.rs similarity index 100% rename from src/librustc_macros/src/lift.rs rename to compiler/rustc_macros/src/lift.rs diff --git a/src/librustc_macros/src/query.rs b/compiler/rustc_macros/src/query.rs similarity index 94% rename from src/librustc_macros/src/query.rs rename to compiler/rustc_macros/src/query.rs index c17d5311e8..e7c054653a 100644 --- a/src/librustc_macros/src/query.rs +++ b/compiler/rustc_macros/src/query.rs @@ -5,11 +5,10 @@ use syn::parse::{Parse, ParseStream, Result}; use syn::punctuated::Punctuated; use syn::spanned::Spanned; use syn::{ - braced, parenthesized, parse_macro_input, Attribute, Block, Error, Expr, Ident, ReturnType, - Token, Type, + braced, parenthesized, parse_macro_input, AttrStyle, Attribute, Block, Error, Expr, Ident, + ReturnType, Token, Type, }; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(query); } @@ -128,17 +127,25 @@ impl Parse for QueryModifier { } /// Ensures only doc comment attributes are used -fn check_attributes(attrs: Vec) -> Result<()> { - for attr in attrs { +fn check_attributes(attrs: Vec) -> Result> { + let inner = |attr: Attribute| { if !attr.path.is_ident("doc") { - return Err(Error::new(attr.span(), "attributes not supported on queries")); + Err(Error::new(attr.span(), "attributes not supported on queries")) + } else if attr.style != AttrStyle::Outer { + Err(Error::new( + attr.span(), + "attributes must be outer attributes (`///`), not inner attributes", + )) + } else { + Ok(attr) } - } - Ok(()) + }; + attrs.into_iter().map(inner).collect() } /// A compiler query. `query ... { ... }` struct Query { + doc_comments: Vec, modifiers: List, name: Ident, key: IdentOrWild, @@ -148,7 +155,7 @@ struct Query { impl Parse for Query { fn parse(input: ParseStream<'_>) -> Result { - check_attributes(input.call(Attribute::parse_outer)?)?; + let doc_comments = check_attributes(input.call(Attribute::parse_outer)?)?; // Parse the query declaration. Like `query type_of(key: DefId) -> Ty<'tcx>` input.parse::()?; @@ -165,7 +172,7 @@ impl Parse for Query { braced!(content in input); let modifiers = content.parse()?; - Ok(Query { modifiers, name, key, arg, result }) + Ok(Query { doc_comments, modifiers, name, key, arg, result }) } } @@ -392,7 +399,7 @@ fn add_query_description_impl( #tcx: TyCtxt<'tcx>, #key: #arg, ) -> Cow<'static, str> { - format!(#desc).into() + ::rustc_middle::ty::print::with_no_trimmed_paths(|| format!(#desc).into()) } }; @@ -476,9 +483,10 @@ pub fn rustc_queries(input: TokenStream) -> TokenStream { }; let attribute_stream = quote! {#(#attributes),*}; - + let doc_comments = query.doc_comments.iter(); // Add the query to the group group_stream.extend(quote! { + #(#doc_comments)* [#attribute_stream] fn #name: #name(#arg) #result, }); diff --git a/src/librustc_macros/src/serialize.rs b/compiler/rustc_macros/src/serialize.rs similarity index 100% rename from src/librustc_macros/src/serialize.rs rename to compiler/rustc_macros/src/serialize.rs diff --git a/compiler/rustc_macros/src/session_diagnostic.rs b/compiler/rustc_macros/src/session_diagnostic.rs new file mode 100644 index 0000000000..610b9155cf --- /dev/null +++ b/compiler/rustc_macros/src/session_diagnostic.rs @@ -0,0 +1,666 @@ +#![deny(unused_must_use)] +use proc_macro::Diagnostic; +use quote::{format_ident, quote}; +use syn::spanned::Spanned; + +use std::collections::{BTreeSet, HashMap}; + +/// Implements #[derive(SessionDiagnostic)], which allows for errors to be specified as a struct, independent +/// from the actual diagnostics emitting code. +/// ```ignore (pseudo-rust) +/// # extern crate rustc_errors; +/// # use rustc_errors::Applicability; +/// # extern crate rustc_span; +/// # use rustc_span::{symbol::Ident, Span}; +/// # extern crate rust_middle; +/// # use rustc_middle::ty::Ty; +/// #[derive(SessionDiagnostic)] +/// #[code = "E0505"] +/// #[error = "cannot move out of {name} because it is borrowed"] +/// pub struct MoveOutOfBorrowError<'tcx> { +/// pub name: Ident, +/// pub ty: Ty<'tcx>, +/// #[label = "cannot move out of borrow"] +/// pub span: Span, +/// #[label = "`{ty}` first borrowed here"] +/// pub other_span: Span, +/// #[suggestion(message = "consider cloning here", code = "{name}.clone()")] +/// pub opt_sugg: Option<(Span, Applicability)> +/// } +/// ``` +/// Then, later, to emit the error: +/// +/// ```ignore (pseudo-rust) +/// sess.emit_err(MoveOutOfBorrowError { +/// expected, +/// actual, +/// span, +/// other_span, +/// opt_sugg: Some(suggestion, Applicability::MachineApplicable), +/// }); +/// ``` +pub fn session_diagnostic_derive(s: synstructure::Structure<'_>) -> proc_macro2::TokenStream { + // Names for the diagnostic we build and the session we build it from. + let diag = format_ident!("diag"); + let sess = format_ident!("sess"); + + SessionDiagnosticDerive::new(diag, sess, s).into_tokens() +} + +// Checks whether the type name of `ty` matches `name`. +// +// Given some struct at a::b::c::Foo, this will return true for c::Foo, b::c::Foo, or +// a::b::c::Foo. This reasonably allows qualified names to be used in the macro. +fn type_matches_path(ty: &syn::Type, name: &[&str]) -> bool { + if let syn::Type::Path(ty) = ty { + ty.path + .segments + .iter() + .map(|s| s.ident.to_string()) + .rev() + .zip(name.iter().rev()) + .all(|(x, y)| &x.as_str() == y) + } else { + false + } +} + +/// The central struct for constructing the as_error method from an annotated struct. +struct SessionDiagnosticDerive<'a> { + structure: synstructure::Structure<'a>, + builder: SessionDiagnosticDeriveBuilder<'a>, +} + +impl std::convert::From for SessionDiagnosticDeriveError { + fn from(e: syn::Error) -> Self { + SessionDiagnosticDeriveError::SynError(e) + } +} + +/// Equivalent to rustc:errors::diagnostic::DiagnosticId, except stores the quoted expression to +/// initialise the code with. +enum DiagnosticId { + Error(proc_macro2::TokenStream), + Lint(proc_macro2::TokenStream), +} + +#[derive(Debug)] +enum SessionDiagnosticDeriveError { + SynError(syn::Error), + ErrorHandled, +} + +impl SessionDiagnosticDeriveError { + fn to_compile_error(self) -> proc_macro2::TokenStream { + match self { + SessionDiagnosticDeriveError::SynError(e) => e.to_compile_error(), + SessionDiagnosticDeriveError::ErrorHandled => { + // Return ! to avoid having to create a blank DiagnosticBuilder to return when an + // error has already been emitted to the compiler. + quote! { + unreachable!() + } + } + } + } +} + +fn span_err(span: impl proc_macro::MultiSpan, msg: &str) -> proc_macro::Diagnostic { + Diagnostic::spanned(span, proc_macro::Level::Error, msg) +} + +/// For methods that return a Result<_, SessionDiagnosticDeriveError>: emit a diagnostic on +/// span $span with msg $msg (and, optionally, perform additional decoration using the FnOnce +/// passed in `diag`). Then, return Err(ErrorHandled). +macro_rules! throw_span_err { + ($span:expr, $msg:expr) => {{ throw_span_err!($span, $msg, |diag| diag) }}; + ($span:expr, $msg:expr, $f:expr) => {{ + return Err(_throw_span_err($span, $msg, $f)); + }}; +} + +/// When possible, prefer using throw_span_err! over using this function directly. This only exists +/// as a function to constrain `f` to an impl FnOnce. +fn _throw_span_err( + span: impl proc_macro::MultiSpan, + msg: &str, + f: impl FnOnce(proc_macro::Diagnostic) -> proc_macro::Diagnostic, +) -> SessionDiagnosticDeriveError { + let diag = span_err(span, msg); + f(diag).emit(); + SessionDiagnosticDeriveError::ErrorHandled +} + +impl<'a> SessionDiagnosticDerive<'a> { + fn new(diag: syn::Ident, sess: syn::Ident, structure: synstructure::Structure<'a>) -> Self { + // Build the mapping of field names to fields. This allows attributes to peek values from + // other fields. + let mut fields_map = HashMap::new(); + + // Convenience bindings. + let ast = structure.ast(); + + if let syn::Data::Struct(syn::DataStruct { fields, .. }) = &ast.data { + for field in fields.iter() { + if let Some(ident) = &field.ident { + fields_map.insert(ident.to_string(), field); + } + } + } + + Self { + builder: SessionDiagnosticDeriveBuilder { diag, sess, fields: fields_map, kind: None }, + structure, + } + } + fn into_tokens(self) -> proc_macro2::TokenStream { + let SessionDiagnosticDerive { structure, mut builder } = self; + + let ast = structure.ast(); + let attrs = &ast.attrs; + + let implementation = { + if let syn::Data::Struct(..) = ast.data { + let preamble = { + let preamble = attrs.iter().map(|attr| { + builder + .generate_structure_code(attr) + .unwrap_or_else(|v| v.to_compile_error()) + }); + quote! { + #(#preamble)*; + } + }; + + let body = structure.each(|field_binding| { + let field = field_binding.ast(); + let result = field.attrs.iter().map(|attr| { + builder + .generate_field_code( + attr, + FieldInfo { + vis: &field.vis, + binding: field_binding, + ty: &field.ty, + span: &field.span(), + }, + ) + .unwrap_or_else(|v| v.to_compile_error()) + }); + return quote! { + #(#result);* + }; + }); + // Finally, putting it altogether. + match builder.kind { + None => { + span_err(ast.span().unwrap(), "`code` not specified") + .help("use the [code = \"...\"] attribute to set this diagnostic's error code ") + .emit(); + SessionDiagnosticDeriveError::ErrorHandled.to_compile_error() + } + Some((kind, _)) => match kind { + DiagnosticId::Lint(_lint) => todo!(), + DiagnosticId::Error(code) => { + let (diag, sess) = (&builder.diag, &builder.sess); + quote! { + let mut #diag = #sess.struct_err_with_code("", rustc_errors::DiagnosticId::Error(#code)); + #preamble + match self { + #body + } + #diag + } + } + }, + } + } else { + span_err( + ast.span().unwrap(), + "`#[derive(SessionDiagnostic)]` can only be used on structs", + ) + .emit(); + SessionDiagnosticDeriveError::ErrorHandled.to_compile_error() + } + }; + + let sess = &builder.sess; + structure.gen_impl(quote! { + gen impl<'__session_diagnostic_sess> rustc_session::SessionDiagnostic<'__session_diagnostic_sess> + for @Self + { + fn into_diagnostic( + self, + #sess: &'__session_diagnostic_sess rustc_session::Session + ) -> rustc_errors::DiagnosticBuilder<'__session_diagnostic_sess> { + #implementation + } + } + }) + } +} + +/// Field information passed to the builder. Deliberately omits attrs to discourage the generate_* +/// methods from walking the attributes themselves. +struct FieldInfo<'a> { + vis: &'a syn::Visibility, + binding: &'a synstructure::BindingInfo<'a>, + ty: &'a syn::Type, + span: &'a proc_macro2::Span, +} + +/// Tracks persistent information required for building up the individual calls to diagnostic +/// methods for the final generated method. This is a separate struct to SessionDerive only to be +/// able to destructure and split self.builder and the self.structure up to avoid a double mut +/// borrow later on. +struct SessionDiagnosticDeriveBuilder<'a> { + /// Name of the session parameter that's passed in to the as_error method. + sess: syn::Ident, + + /// Store a map of field name to its corresponding field. This is built on construction of the + /// derive builder. + fields: HashMap, + + /// The identifier to use for the generated DiagnosticBuilder instance. + diag: syn::Ident, + + /// Whether this is a lint or an error. This dictates how the diag will be initialised. Span + /// stores at what Span the kind was first set at (for error reporting purposes, if the kind + /// was multiply specified). + kind: Option<(DiagnosticId, proc_macro2::Span)>, +} + +impl<'a> SessionDiagnosticDeriveBuilder<'a> { + fn generate_structure_code( + &mut self, + attr: &syn::Attribute, + ) -> Result { + Ok(match attr.parse_meta()? { + syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + let formatted_str = self.build_format(&s.value(), attr.span()); + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + match name { + "message" => { + let diag = &self.diag; + quote! { + #diag.set_primary_message(#formatted_str); + } + } + attr @ "error" | attr @ "lint" => { + self.set_kind_once( + if attr == "error" { + DiagnosticId::Error(formatted_str) + } else if attr == "lint" { + DiagnosticId::Lint(formatted_str) + } else { + unreachable!() + }, + s.span(), + )?; + // This attribute is only allowed to be applied once, and the attribute + // will be set in the initialisation code. + quote! {} + } + other => throw_span_err!( + attr.span().unwrap(), + &format!( + "`#[{} = ...]` is not a valid SessionDiagnostic struct attribute", + other + ) + ), + } + } + _ => todo!("unhandled meta kind"), + }) + } + + #[must_use] + fn set_kind_once( + &mut self, + kind: DiagnosticId, + span: proc_macro2::Span, + ) -> Result<(), SessionDiagnosticDeriveError> { + if self.kind.is_none() { + self.kind = Some((kind, span)); + Ok(()) + } else { + let kind_str = |kind: &DiagnosticId| match kind { + DiagnosticId::Lint(..) => "lint", + DiagnosticId::Error(..) => "error", + }; + + let existing_kind = kind_str(&self.kind.as_ref().unwrap().0); + let this_kind = kind_str(&kind); + + let msg = if this_kind == existing_kind { + format!("`{}` specified multiple times", existing_kind) + } else { + format!("`{}` specified when `{}` was already specified", this_kind, existing_kind) + }; + throw_span_err!(span.unwrap(), &msg); + } + } + + fn generate_field_code( + &mut self, + attr: &syn::Attribute, + info: FieldInfo<'_>, + ) -> Result { + let field_binding = &info.binding.binding; + + 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), + span: info.span, + }, + )?; + Ok(if option_ty.is_none() { + quote! { #generated_code } + } else { + quote! { + if let Some(#field_binding) = #field_binding { + #generated_code + } + } + }) + } + + fn generate_non_option_field_code( + &mut self, + attr: &syn::Attribute, + info: FieldInfo<'_>, + ) -> Result { + let diag = &self.diag; + let field_binding = &info.binding.binding; + let name = attr.path.segments.last().unwrap().ident.to_string(); + let name = name.as_str(); + // At this point, we need to dispatch based on the attribute key + the + // type. + let meta = attr.parse_meta()?; + Ok(match meta { + syn::Meta::NameValue(syn::MetaNameValue { lit: syn::Lit::Str(s), .. }) => { + let formatted_str = self.build_format(&s.value(), attr.span()); + match name { + "message" => { + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + quote! { + #diag.set_span(*#field_binding); + #diag.set_primary_message(#formatted_str); + } + } else { + throw_span_err!( + attr.span().unwrap(), + "the `#[message = \"...\"]` attribute can only be applied to fields of type Span" + ); + } + } + "label" => { + if type_matches_path(&info.ty, &["rustc_span", "Span"]) { + quote! { + #diag.span_label(*#field_binding, #formatted_str); + } + } else { + throw_span_err!( + attr.span().unwrap(), + "The `#[label = ...]` attribute can only be applied to fields of type Span" + ); + } + } + other => throw_span_err!( + attr.span().unwrap(), + &format!( + "`#[{} = ...]` is not a valid SessionDiagnostic field attribute", + other + ) + ), + } + } + syn::Meta::List(list) => { + match list.path.segments.iter().last().unwrap().ident.to_string().as_str() { + suggestion_kind @ "suggestion" + | suggestion_kind @ "suggestion_short" + | suggestion_kind @ "suggestion_hidden" + | suggestion_kind @ "suggestion_verbose" => { + // For suggest, we need to ensure we are running on a (Span, + // Applicability) pair. + let (span, applicability) = (|| match &info.ty { + ty @ syn::Type::Path(..) + if type_matches_path(ty, &["rustc_span", "Span"]) => + { + let binding = &info.binding.binding; + Ok(( + quote!(*#binding), + quote!(rustc_errors::Applicability::Unspecified), + )) + } + syn::Type::Tuple(tup) => { + let mut span_idx = None; + let mut applicability_idx = None; + for (idx, elem) in tup.elems.iter().enumerate() { + if type_matches_path(elem, &["rustc_span", "Span"]) { + if span_idx.is_none() { + span_idx = Some(syn::Index::from(idx)); + } else { + throw_span_err!( + info.span.clone().unwrap(), + "type of field annotated with `#[suggestion(...)]` contains more than one Span" + ); + } + } else if type_matches_path( + elem, + &["rustc_errors", "Applicability"], + ) { + if applicability_idx.is_none() { + applicability_idx = Some(syn::Index::from(idx)); + } else { + throw_span_err!( + info.span.clone().unwrap(), + "type of field annotated with `#[suggestion(...)]` contains more than one Applicability" + ); + } + } + } + if let Some(span_idx) = span_idx { + let binding = &info.binding.binding; + let span = quote!(#binding.#span_idx); + let applicability = applicability_idx + .map( + |applicability_idx| quote!(#binding.#applicability_idx), + ) + .unwrap_or(quote!( + rustc_errors::Applicability::Unspecified + )); + return Ok((span, applicability)); + } + throw_span_err!( + info.span.clone().unwrap(), + "wrong types for suggestion", + |diag| { + diag.help("#[suggestion(...)] on a tuple field must be applied to fields of type (Span, Applicability)") + } + ); + } + _ => throw_span_err!( + info.span.clone().unwrap(), + "wrong field type for suggestion", + |diag| { + diag.help("#[suggestion(...)] should be applied to fields of type Span or (Span, Applicability)") + } + ), + })()?; + // Now read the key-value pairs. + let mut msg = None; + let mut code = None; + + for arg in list.nested.iter() { + if let syn::NestedMeta::Meta(syn::Meta::NameValue(arg_name_value)) = arg + { + if let syn::MetaNameValue { lit: syn::Lit::Str(s), .. } = + arg_name_value + { + let name = arg_name_value + .path + .segments + .last() + .unwrap() + .ident + .to_string(); + let name = name.as_str(); + let formatted_str = self.build_format(&s.value(), arg.span()); + match name { + "message" => { + msg = Some(formatted_str); + } + "code" => { + code = Some(formatted_str); + } + other => throw_span_err!( + arg.span().unwrap(), + &format!( + "`{}` is not a valid key for `#[suggestion(...)]`", + other + ) + ), + } + } + } + } + let msg = if let Some(msg) = msg { + quote!(#msg.as_str()) + } else { + throw_span_err!( + list.span().unwrap(), + "missing suggestion message", + |diag| { + diag.help("provide a suggestion message using #[suggestion(message = \"...\")]") + } + ); + }; + let code = code.unwrap_or_else(|| quote! { String::new() }); + // Now build it out: + let suggestion_method = format_ident!("span_{}", suggestion_kind); + quote! { + #diag.#suggestion_method(#span, #msg, #code, #applicability); + } + } + other => throw_span_err!( + list.span().unwrap(), + &format!("invalid annotation list `#[{}(...)]`", other) + ), + } + } + _ => panic!("unhandled meta kind"), + }) + } + + /// In the strings in the attributes supplied to this macro, we want callers to be able to + /// reference fields in the format string. Take this, for example: + /// ```ignore (not-usage-example) + /// struct Point { + /// #[error = "Expected a point greater than ({x}, {y})"] + /// x: i32, + /// y: i32, + /// } + /// ``` + /// We want to automatically pick up that {x} refers `self.x` and {y} refers to `self.y`, then + /// generate this call to format!: + /// ```ignore (not-usage-example) + /// format!("Expected a point greater than ({x}, {y})", x = self.x, y = self.y) + /// ``` + /// This function builds the entire call to format!. + fn build_format(&self, input: &String, span: proc_macro2::Span) -> proc_macro2::TokenStream { + // This set is used later to generate the final format string. To keep builds reproducible, + // the iteration order needs to be deterministic, hence why we use a BTreeSet here instead + // of a HashSet. + let mut referenced_fields: BTreeSet = BTreeSet::new(); + + // At this point, we can start parsing the format string. + let mut it = input.chars().peekable(); + // Once the start of a format string has been found, process the format string and spit out + // the referenced fields. Leaves `it` sitting on the closing brace of the format string, so the + // next call to `it.next()` retrieves the next character. + while let Some(c) = it.next() { + if c == '{' && *it.peek().unwrap_or(&'\0') != '{' { + #[must_use] + let mut eat_argument = || -> Option { + let mut result = String::new(); + // Format specifiers look like + // format := '{' [ argument ] [ ':' format_spec ] '}' . + // Therefore, we only need to eat until ':' or '}' to find the argument. + while let Some(c) = it.next() { + result.push(c); + let next = *it.peek().unwrap_or(&'\0'); + if next == '}' { + break; + } else if next == ':' { + // Eat the ':' character. + assert_eq!(it.next().unwrap(), ':'); + break; + } + } + // Eat until (and including) the matching '}' + while it.next()? != '}' { + continue; + } + Some(result) + }; + + if let Some(referenced_field) = eat_argument() { + referenced_fields.insert(referenced_field); + } + } + } + // At this point, `referenced_fields` contains a set of the unique fields that were + // referenced in the format string. Generate the corresponding "x = self.x" format + // string parameters: + let args = referenced_fields.into_iter().map(|field: String| { + let field_ident = format_ident!("{}", field); + let value = if self.fields.contains_key(&field) { + quote! { + &self.#field_ident + } + } else { + // This field doesn't exist. Emit a diagnostic. + Diagnostic::spanned( + span.unwrap(), + proc_macro::Level::Error, + format!("`{}` doesn't refer to a field on this type", field), + ) + .emit(); + quote! { + "{#field}" + } + }; + quote! { + #field_ident = #value + } + }); + quote! { + format!(#input #(,#args)*) + } + } +} + +/// If `ty` is an Option, returns Some(inner type). Else, returns None. +fn option_inner_ty(ty: &syn::Type) -> Option<&syn::Type> { + if type_matches_path(ty, &["std", "option", "Option"]) { + if let syn::Type::Path(ty_path) = ty { + let path = &ty_path.path; + let ty = path.segments.iter().last().unwrap(); + if let syn::PathArguments::AngleBracketed(bracketed) = &ty.arguments { + if bracketed.args.len() == 1 { + if let syn::GenericArgument::Type(ty) = &bracketed.args[0] { + return Some(ty); + } + } + } + } + } + None +} diff --git a/src/librustc_macros/src/symbols.rs b/compiler/rustc_macros/src/symbols.rs similarity index 99% rename from src/librustc_macros/src/symbols.rs rename to compiler/rustc_macros/src/symbols.rs index 352665f0ab..94d4ad78e8 100644 --- a/src/librustc_macros/src/symbols.rs +++ b/compiler/rustc_macros/src/symbols.rs @@ -4,7 +4,6 @@ use std::collections::HashSet; use syn::parse::{Parse, ParseStream, Result}; use syn::{braced, parse_macro_input, Ident, LitStr, Token}; -#[allow(non_camel_case_types)] mod kw { syn::custom_keyword!(Keywords); syn::custom_keyword!(Symbols); diff --git a/src/librustc_macros/src/type_foldable.rs b/compiler/rustc_macros/src/type_foldable.rs similarity index 100% rename from src/librustc_macros/src/type_foldable.rs rename to compiler/rustc_macros/src/type_foldable.rs diff --git a/compiler/rustc_metadata/Cargo.toml b/compiler/rustc_metadata/Cargo.toml new file mode 100644 index 0000000000..f1975e7880 --- /dev/null +++ b/compiler/rustc_metadata/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_metadata" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +libc = "0.2" +snap = "1" +tracing = "0.1" +memmap = "0.7" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_middle = { path = "../rustc_middle" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_target = { path = "../rustc_target" } +rustc_index = { path = "../rustc_index" } +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +stable_deref_trait = "1.0.0" +rustc_ast = { path = "../rustc_ast" } +rustc_expand = { path = "../rustc_expand" } +rustc_span = { path = "../rustc_span" } +rustc_session = { path = "../rustc_session" } + +[target.'cfg(windows)'.dependencies] +winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] } diff --git a/src/librustc_metadata/creader.rs b/compiler/rustc_metadata/src/creader.rs similarity index 98% rename from src/librustc_metadata/creader.rs rename to compiler/rustc_metadata/src/creader.rs index f8446d83d2..7562da6d78 100644 --- a/src/librustc_metadata/creader.rs +++ b/compiler/rustc_metadata/src/creader.rs @@ -222,6 +222,7 @@ impl<'a> CrateLoader<'a> { let mut ret = None; self.cstore.iter_crate_data(|cnum, data| { if data.name() != name { + tracing::trace!("{} did not match {}", data.name(), name); return; } @@ -230,7 +231,10 @@ impl<'a> CrateLoader<'a> { ret = Some(cnum); return; } - Some(..) => return, + Some(hash) => { + debug!("actual hash {} did not match expected {}", hash, data.hash()); + return; + } None => {} } @@ -273,6 +277,11 @@ impl<'a> CrateLoader<'a> { .1; if kind.matches(prev_kind) { ret = Some(cnum); + } else { + debug!( + "failed to load existing crate {}; kind {:?} did not match prev_kind {:?}", + name, kind, prev_kind + ); } }); ret diff --git a/src/librustc_metadata/dependency_format.rs b/compiler/rustc_metadata/src/dependency_format.rs similarity index 100% rename from src/librustc_metadata/dependency_format.rs rename to compiler/rustc_metadata/src/dependency_format.rs diff --git a/src/librustc_metadata/dynamic_lib.rs b/compiler/rustc_metadata/src/dynamic_lib.rs similarity index 51% rename from src/librustc_metadata/dynamic_lib.rs rename to compiler/rustc_metadata/src/dynamic_lib.rs index ce19240a00..bdb53e3f75 100644 --- a/src/librustc_metadata/dynamic_lib.rs +++ b/compiler/rustc_metadata/src/dynamic_lib.rs @@ -51,51 +51,90 @@ mod tests; #[cfg(unix)] mod dl { - use std::ffi::{CStr, CString, OsStr}; + use std::ffi::{CString, OsStr}; use std::os::unix::prelude::*; - use std::ptr; - use std::str; - pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> { - check_for_errors_in(|| unsafe { - let s = CString::new(filename.as_bytes()).unwrap(); - libc::dlopen(s.as_ptr(), libc::RTLD_LAZY) as *mut u8 - }) - } + // As of the 2017 revision of the POSIX standard (IEEE 1003.1-2017), it is + // implementation-defined whether `dlerror` is thread-safe (in which case it returns the most + // recent error in the calling thread) or not thread-safe (in which case it returns the most + // recent error in *any* thread). + // + // There's no easy way to tell what strategy is used by a given POSIX implementation, so we + // lock around all calls that can modify `dlerror` in this module lest we accidentally read an + // error from a different thread. This is bulletproof when we are the *only* code using the + // dynamic library APIs at a given point in time. However, it's still possible for us to race + // with other code (see #74469) on platforms where `dlerror` is not thread-safe. + mod error { + use std::ffi::CStr; + use std::lazy::SyncLazy; + use std::sync::{Mutex, MutexGuard}; - fn check_for_errors_in(f: F) -> Result - where - F: FnOnce() -> T, - { - use std::sync::{Mutex, Once}; - static INIT: Once = Once::new(); - static mut LOCK: *mut Mutex<()> = ptr::null_mut(); - unsafe { - INIT.call_once(|| { - LOCK = Box::into_raw(Box::new(Mutex::new(()))); - }); - // dlerror isn't thread safe, so we need to lock around this entire - // sequence - let _guard = (*LOCK).lock(); - let _old_error = libc::dlerror(); + pub fn lock() -> MutexGuard<'static, Guard> { + static LOCK: SyncLazy> = SyncLazy::new(|| Mutex::new(Guard { _priv: () })); + LOCK.lock().unwrap() + } - let result = f(); + pub struct Guard { + _priv: (), + } - let last_error = libc::dlerror() as *const _; - if ptr::null() == last_error { - Ok(result) - } else { - let s = CStr::from_ptr(last_error).to_bytes(); - Err(str::from_utf8(s).unwrap().to_owned()) + impl Guard { + pub fn get(&mut self) -> Result<(), String> { + let msg = unsafe { libc::dlerror() }; + if msg.is_null() { + Ok(()) + } else { + let msg = unsafe { CStr::from_ptr(msg as *const _) }; + Err(msg.to_string_lossy().into_owned()) + } + } + + pub fn clear(&mut self) { + let _ = unsafe { libc::dlerror() }; } } } + pub(super) fn open(filename: &OsStr) -> Result<*mut u8, String> { + let s = CString::new(filename.as_bytes()).unwrap(); + + let mut dlerror = error::lock(); + let ret = unsafe { libc::dlopen(s.as_ptr(), libc::RTLD_LAZY | libc::RTLD_LOCAL) }; + + if !ret.is_null() { + return Ok(ret.cast()); + } + + // A NULL return from `dlopen` indicates that an error has definitely occurred, so if + // nothing is in `dlerror`, we are racing with another thread that has stolen our error + // message. See the explanation on the `dl::error` module for more information. + dlerror.get().and_then(|()| Err("Unknown error".to_string())) + } + pub(super) unsafe fn symbol( handle: *mut u8, symbol: *const libc::c_char, ) -> Result<*mut u8, String> { - check_for_errors_in(|| libc::dlsym(handle as *mut libc::c_void, symbol) as *mut u8) + let mut dlerror = error::lock(); + + // Unlike `dlopen`, it's possible for `dlsym` to return NULL without overwriting `dlerror`. + // Because of this, we clear `dlerror` before calling `dlsym` to avoid picking up a stale + // error message by accident. + dlerror.clear(); + + let ret = libc::dlsym(handle as *mut libc::c_void, symbol); + + if !ret.is_null() { + return Ok(ret.cast()); + } + + // If `dlsym` returns NULL but there is nothing in `dlerror` it means one of two things: + // - We tried to load a symbol mapped to address 0. This is not technically an error but is + // unlikely to occur in practice and equally unlikely to be handled correctly by calling + // code. Therefore we treat it as an error anyway. + // - An error has occurred, but we are racing with another thread that has stolen our error + // message. See the explanation on the `dl::error` module for more information. + dlerror.get().and_then(|()| Err("Tried to load symbol mapped to address 0".to_string())) } pub(super) unsafe fn close(handle: *mut u8) { diff --git a/src/librustc_metadata/dynamic_lib/tests.rs b/compiler/rustc_metadata/src/dynamic_lib/tests.rs similarity index 100% rename from src/librustc_metadata/dynamic_lib/tests.rs rename to compiler/rustc_metadata/src/dynamic_lib/tests.rs diff --git a/src/librustc_metadata/foreign_modules.rs b/compiler/rustc_metadata/src/foreign_modules.rs similarity index 100% rename from src/librustc_metadata/foreign_modules.rs rename to compiler/rustc_metadata/src/foreign_modules.rs diff --git a/src/librustc_metadata/lib.rs b/compiler/rustc_metadata/src/lib.rs similarity index 87% rename from src/librustc_metadata/lib.rs rename to compiler/rustc_metadata/src/lib.rs index e50fa34554..77766be739 100644 --- a/src/librustc_metadata/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -1,10 +1,11 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(core_intrinsics)] #![feature(crate_visibility_modifier)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] #![feature(nll)] +#![feature(once_cell)] #![feature(or_patterns)] #![feature(proc_macro_internals)] #![feature(min_specialization)] diff --git a/src/librustc_metadata/link_args.rs b/compiler/rustc_metadata/src/link_args.rs similarity index 100% rename from src/librustc_metadata/link_args.rs rename to compiler/rustc_metadata/src/link_args.rs diff --git a/src/librustc_metadata/locator.rs b/compiler/rustc_metadata/src/locator.rs similarity index 99% rename from src/librustc_metadata/locator.rs rename to compiler/rustc_metadata/src/locator.rs index 8fa14a44f5..0869ec2836 100644 --- a/src/librustc_metadata/locator.rs +++ b/compiler/rustc_metadata/src/locator.rs @@ -229,7 +229,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::Span; use rustc_target::spec::{Target, TargetTriple}; -use flate2::read::DeflateDecoder; +use snap::read::FrameDecoder; use std::io::{Read, Result as IoResult, Write}; use std::ops::Deref; use std::path::{Path, PathBuf}; @@ -766,7 +766,7 @@ fn get_metadata_section( let compressed_bytes = &buf[header_len..]; debug!("inflating {} bytes of compressed metadata", compressed_bytes.len()); let mut inflated = Vec::new(); - match DeflateDecoder::new(compressed_bytes).read_to_end(&mut inflated) { + match FrameDecoder::new(compressed_bytes).read_to_end(&mut inflated) { Ok(_) => rustc_erase_owner!(OwningRef::new(inflated).map_owner_box()), Err(_) => { return Err(format!("failed to decompress metadata: {}", filename.display())); diff --git a/src/librustc_metadata/native_libs.rs b/compiler/rustc_metadata/src/native_libs.rs similarity index 98% rename from src/librustc_metadata/native_libs.rs rename to compiler/rustc_metadata/src/native_libs.rs index 3976475cb0..e76c2cb356 100644 --- a/src/librustc_metadata/native_libs.rs +++ b/compiler/rustc_metadata/src/native_libs.rs @@ -170,7 +170,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::static_nobundle, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"static-nobundle\" is unstable", ) .emit(); @@ -179,7 +179,7 @@ impl Collector<'tcx> { feature_err( &self.tcx.sess.parse_sess, sym::raw_dylib, - span.unwrap_or_else(|| rustc_span::DUMMY_SP), + span.unwrap_or(rustc_span::DUMMY_SP), "kind=\"raw-dylib\" is unstable", ) .emit(); diff --git a/src/librustc_metadata/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs similarity index 97% rename from src/librustc_metadata/rmeta/decoder.rs rename to compiler/rustc_metadata/src/rmeta/decoder.rs index 43d76e9fdb..c31e941b3f 100644 --- a/src/librustc_metadata/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -11,6 +11,7 @@ use rustc_data_structures::fingerprint::{Fingerprint, FingerprintDecoder}; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::svh::Svh; use rustc_data_structures::sync::{AtomicCell, Lock, LockGuard, Lrc, OnceCell}; +use rustc_errors::ErrorReported; use rustc_expand::base::{SyntaxExtension, SyntaxExtensionKind}; use rustc_expand::proc_macro::{AttrProcMacro, BangProcMacro, ProcMacroDerive}; use rustc_hir as hir; @@ -562,6 +563,12 @@ impl<'a, 'tcx> Decodable> for Span { } } +impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { + ty::codec::RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn decode(d: &mut DecodeContext<'a, 'tcx>) -> Result { ty::codec::RefDecodable::decode(d) @@ -700,7 +707,11 @@ impl CrateRoot<'_> { impl<'a, 'tcx> CrateMetadataRef<'a> { fn is_proc_macro(&self, id: DefIndex) -> bool { - self.root.proc_macro_data.and_then(|data| data.decode(self).find(|x| *x == id)).is_some() + self.root + .proc_macro_data + .as_ref() + .and_then(|data| data.macros.decode(self).find(|x| *x == id)) + .is_some() } fn maybe_kind(&self, item_id: DefIndex) -> Option { @@ -722,7 +733,15 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn raw_proc_macro(&self, id: DefIndex) -> &ProcMacro { // DefIndex's in root.proc_macro_data have a one-to-one correspondence // with items in 'raw_proc_macros'. - let pos = self.root.proc_macro_data.unwrap().decode(self).position(|i| i == id).unwrap(); + let pos = self + .root + .proc_macro_data + .as_ref() + .unwrap() + .macros + .decode(self) + .position(|i| i == id) + .unwrap(); &self.raw_proc_macros.unwrap()[pos] } @@ -759,7 +778,12 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn get_span(&self, index: DefIndex, sess: &Session) -> Span { - self.root.tables.span.get(self, index).unwrap().decode((self, sess)) + self.root + .tables + .span + .get(self, index) + .unwrap_or_else(|| panic!("Missing span for {:?}", index)) + .decode((self, sess)) } fn load_proc_macro(&self, id: DefIndex, sess: &Session) -> SyntaxExtension { @@ -935,7 +959,7 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn get_stability(&self, id: DefIndex) -> Option { match self.is_proc_macro(id) { - true => self.root.proc_macro_stability, + true => self.root.proc_macro_data.as_ref().unwrap().stability, false => self.root.tables.stability.get(self, id).map(|stab| stab.decode(self)), } } @@ -1028,24 +1052,20 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { where F: FnMut(Export), { - if let Some(proc_macros_ids) = self.root.proc_macro_data.map(|d| d.decode(self)) { + 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. */ if id == CRATE_DEF_INDEX { - for def_index in proc_macros_ids { + let macros = data.macros.decode(self); + for def_index in macros { let raw_macro = self.raw_proc_macro(def_index); let res = Res::Def( DefKind::Macro(macro_kind(raw_macro)), self.local_def_id(def_index), ); let ident = self.item_ident(def_index, sess); - callback(Export { - ident, - res, - vis: ty::Visibility::Public, - span: self.get_span(def_index, sess), - }); + callback(Export { ident, res, vis: ty::Visibility::Public, span: ident.span }); } } return; @@ -1191,6 +1211,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { .decode((self, tcx)) } + fn get_mir_abstract_const( + &self, + tcx: TyCtxt<'tcx>, + id: DefIndex, + ) -> Result]>, ErrorReported> { + self.root + .tables + .mir_abstract_consts + .get(self, id) + .filter(|_| !self.is_proc_macro(id)) + .map_or(Ok(None), |v| Ok(Some(v.decode((self, tcx))))) + } + fn get_unused_generic_params(&self, id: DefIndex) -> FiniteBitSet { self.root .tables @@ -1539,12 +1572,19 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { fn all_def_path_hashes_and_def_ids(&self) -> Vec<(DefPathHash, DefId)> { let mut def_path_hashes = self.def_path_hash_cache.lock(); - (0..self.num_def_ids()) - .map(|index| { - let index = DefIndex::from_usize(index); - (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) - }) - .collect() + let mut def_index_to_data = |index| { + (self.def_path_hash_unlocked(index, &mut def_path_hashes), self.local_def_id(index)) + }; + if let Some(data) = &self.root.proc_macro_data { + std::iter::once(CRATE_DEF_INDEX) + .chain(data.macros.decode(self)) + .map(def_index_to_data) + .collect() + } else { + (0..self.num_def_ids()) + .map(|index| def_index_to_data(DefIndex::from_usize(index))) + .collect() + } } /// Get the `DepNodeIndex` corresponding this crate. The result of this diff --git a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs similarity index 97% rename from src/librustc_metadata/rmeta/decoder/cstore_impl.rs rename to compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 36ff65fc5e..4102cf84a6 100644 --- a/src/librustc_metadata/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::query::Providers; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::utils::NativeLibKind; use rustc_session::{CrateDisambiguator, Session}; -use rustc_span::source_map::{self, Span, Spanned}; +use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Symbol; use rustc_data_structures::sync::Lrc; @@ -112,6 +112,7 @@ provide! { <'tcx> tcx, def_id, other, cdata, } optimized_mir => { tcx.arena.alloc(cdata.get_optimized_mir(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) } unused_generic_params => { cdata.get_unused_generic_params(def_id.index) } mir_const_qualif => { cdata.mir_const_qualif(def_id.index) } fn_sig => { cdata.fn_sig(def_id.index, tcx) } @@ -178,8 +179,11 @@ provide! { <'tcx> tcx, def_id, other, cdata, }) } proc_macro_decls_static => { - cdata.root.proc_macro_decls_static.map(|index| { - DefId { krate: def_id.krate, index } + cdata.root.proc_macro_data.as_ref().map(|data| { + DefId { + krate: def_id.krate, + index: data.proc_macro_decls_static, + } }) } crate_disambiguator => { cdata.root.disambiguator } @@ -421,7 +425,11 @@ impl CStore { span, attrs: attrs.to_vec(), kind: ast::ItemKind::MacroDef(data.get_macro(id.index, sess)), - vis: source_map::respan(span.shrink_to_lo(), ast::VisibilityKind::Inherited), + vis: ast::Visibility { + span: span.shrink_to_lo(), + kind: ast::VisibilityKind::Inherited, + tokens: None, + }, tokens: None, }, data.root.edition, diff --git a/src/librustc_metadata/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs similarity index 93% rename from src/librustc_metadata/rmeta/encoder.rs rename to compiler/rustc_metadata/src/rmeta/encoder.rs index 509ef1caf1..f58a792ef5 100644 --- a/src/librustc_metadata/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -40,6 +40,7 @@ use tracing::{debug, trace}; pub(super) struct EncodeContext<'a, 'tcx> { opaque: opaque::Encoder, tcx: TyCtxt<'tcx>, + feat: &'tcx rustc_feature::Features, tables: TableBuilders<'tcx>, @@ -67,6 +68,17 @@ pub(super) struct EncodeContext<'a, 'tcx> { hygiene_ctxt: &'a HygieneEncodeContext, } +/// If the current crate is a proc-macro, returns early with `Lazy:empty()`. +/// This is useful for skipping the encoding of things that aren't needed +/// for proc-macro crates. +macro_rules! empty_proc_macro { + ($self:ident) => { + if $self.is_proc_macro { + return Lazy::empty(); + } + }; +} + macro_rules! encoder_methods { ($($name:ident($ty:ty);)*) => { $(fn $name(&mut self, value: $ty) -> Result<(), Self::Error> { @@ -137,6 +149,15 @@ where } } +impl<'a, 'tcx> Encodable> for CrateNum { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + if *self != LOCAL_CRATE && s.is_proc_macro { + panic!("Attempted to encode non-local CrateNum {:?} for proc-macro crate", self); + } + s.emit_u32(self.as_u32()) + } +} + impl<'a, 'tcx> Encodable> for DefIndex { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { s.emit_u32(self.as_u32()) @@ -162,7 +183,7 @@ impl<'a, 'tcx> Encodable> for ExpnId { impl<'a, 'tcx> Encodable> for Span { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { - if self.is_dummy() { + if *self == rustc_span::DUMMY_SP { return TAG_INVALID_SPAN.encode(s); } @@ -320,6 +341,12 @@ impl<'a, 'tcx> TyEncoder<'tcx> for EncodeContext<'a, 'tcx> { } } +impl<'a, 'tcx> Encodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { + (**self).encode(s) + } +} + impl<'a, 'tcx> Encodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn encode(&self, s: &mut EncodeContext<'a, 'tcx>) -> opaque::EncodeResult { (**self).encode(s) @@ -411,6 +438,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { let krate = self.tcx.hir().krate(); let vis = Spanned { span: rustc_span::DUMMY_SP, node: hir::VisibilityKind::Public }; self.encode_info_for_mod(hir::CRATE_HIR_ID, &krate.item.module, &krate.item.attrs, &vis); + + // Proc-macro crates only export proc-macro items, which are looked + // up using `proc_macro_data` + if self.is_proc_macro { + return; + } + krate.visit_all_item_likes(&mut self.as_deep_visitor()); for macro_def in krate.exported_macros { self.visit_macro_def(macro_def); @@ -419,11 +453,22 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { fn encode_def_path_table(&mut self) { let table = self.tcx.hir().definitions().def_path_table(); - for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { - let def_key = self.lazy(def_key); - let def_path_hash = self.lazy(def_path_hash); - self.tables.def_keys.set(def_index, def_key); - self.tables.def_path_hashes.set(def_index, def_path_hash); + if self.is_proc_macro { + for def_index in std::iter::once(CRATE_DEF_INDEX) + .chain(self.tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index)) + { + let def_key = self.lazy(table.def_key(def_index)); + let def_path_hash = self.lazy(table.def_path_hash(def_index)); + self.tables.def_keys.set(def_index, def_key); + self.tables.def_path_hashes.set(def_index, def_path_hash); + } + } else { + for (def_index, def_key, def_path_hash) in table.enumerated_keys_and_path_hashes() { + let def_key = self.lazy(def_key); + let def_path_hash = self.lazy(def_path_hash); + self.tables.def_keys.set(def_index, def_key); + self.tables.def_path_hashes.set(def_index, def_path_hash); + } } } @@ -490,13 +535,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(adapted.iter().map(|rc| &**rc)) } - fn is_proc_macro(&self) -> bool { - self.tcx.sess.crate_types().contains(&CrateType::ProcMacro) - } - fn encode_crate_root(&mut self) -> Lazy> { - let is_proc_macro = self.is_proc_macro(); - let mut i = self.position(); // Encode the crate deps @@ -568,15 +607,16 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.lazy(interpret_alloc_index) }; - i = self.position(); - let tables = self.tables.encode(&mut self.opaque); - let tables_bytes = self.position() - i; - - // Encode the proc macro data + // Encode the proc macro data. This affects 'tables', + // so we need to do this before we encode the tables i = self.position(); let proc_macro_data = self.encode_proc_macros(); let proc_macro_data_bytes = self.position() - i; + i = self.position(); + let tables = self.tables.encode(&mut self.opaque); + let tables_bytes = self.position() - i; + // Encode exported symbols info. This is prefetched in `encode_metadata` so we encode // this as late as possible to give the prefetching as much time as possible to complete. i = self.position(); @@ -617,18 +657,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { has_panic_handler: tcx.has_panic_handler(LOCAL_CRATE), has_default_lib_allocator, plugin_registrar_fn: tcx.plugin_registrar_fn(LOCAL_CRATE).map(|id| id.index), - proc_macro_decls_static: if is_proc_macro { - let id = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap(); - Some(id.index) - } else { - None - }, proc_macro_data, - proc_macro_stability: if is_proc_macro { - tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied() - } else { - None - }, compiler_builtins: tcx.sess.contains_name(&attrs, sym::compiler_builtins), needs_allocator: tcx.sess.contains_name(&attrs, sym::needs_allocator), needs_panic_runtime: tcx.sess.contains_name(&attrs, sym::needs_panic_runtime), @@ -793,8 +822,13 @@ impl EncodeContext<'a, 'tcx> { let def_id = local_def_id.to_def_id(); debug!("EncodeContext::encode_info_for_mod({:?})", def_id); - let data = ModData { - reexports: match tcx.module_exports(local_def_id) { + // If we are encoding a proc-macro crates, `encode_info_for_mod` will + // only ever get called for the crate root. We still want to encode + // the crate root for consistency with other crates (some of the resolver + // code uses it). However, we skip encoding anything relating to child + // 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( @@ -804,7 +838,13 @@ impl EncodeContext<'a, 'tcx> { ) } _ => Lazy::empty(), - }, + } + } else { + Lazy::empty() + }; + + let data = ModData { + reexports, expansion: tcx.hir().definitions().expansion_that_defined(local_def_id), }; @@ -812,9 +852,13 @@ impl EncodeContext<'a, 'tcx> { record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(vis, id, self.tcx)); record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id] <- attrs); - record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| { - tcx.hir().local_def_id(item_id.id).local_def_index - })); + if self.is_proc_macro { + record!(self.tables.children[def_id] <- &[]); + } else { + record!(self.tables.children[def_id] <- md.item_ids.iter().map(|item_id| { + tcx.hir().local_def_id(item_id.id).local_def_index + })); + } self.encode_stability(def_id); self.encode_deprecation(def_id); } @@ -1108,6 +1152,11 @@ impl EncodeContext<'a, 'tcx> { if !unused.is_empty() { record!(self.tables.unused_generic_params[def_id.to_def_id()] <- unused); } + + let abstract_const = self.tcx.mir_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); + } } } @@ -1132,15 +1181,25 @@ impl EncodeContext<'a, 'tcx> { fn encode_stability(&mut self, def_id: DefId) { debug!("EncodeContext::encode_stability({:?})", def_id); - if let Some(stab) = self.tcx.lookup_stability(def_id) { - record!(self.tables.stability[def_id] <- stab) + + // The query lookup can take a measurable amount of time in crates with many items. Check if + // the stability attributes are even enabled before using their queries. + if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_stability(def_id) { + record!(self.tables.stability[def_id] <- stab) + } } } fn encode_const_stability(&mut self, def_id: DefId) { debug!("EncodeContext::encode_const_stability({:?})", def_id); - if let Some(stab) = self.tcx.lookup_const_stability(def_id) { - record!(self.tables.const_stability[def_id] <- stab) + + // The query lookup can take a measurable amount of time in crates with many items. Check if + // the stability attributes are even enabled before using their queries. + if self.feat.staged_api || self.tcx.sess.opts.debugging_opts.force_unstable_if_unmarked { + if let Some(stab) = self.tcx.lookup_const_stability(def_id) { + record!(self.tables.const_stability[def_id] <- stab) + } } } @@ -1278,7 +1337,7 @@ impl EncodeContext<'a, 'tcx> { }); record!(self.tables.visibility[def_id] <- ty::Visibility::from_hir(&item.vis, item.hir_id, tcx)); - record!(self.tables.span[def_id] <- item.span); + record!(self.tables.span[def_id] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id] <- item.attrs); // FIXME(eddyb) there should be a nicer way to do this. match item.kind { @@ -1418,7 +1477,7 @@ impl EncodeContext<'a, 'tcx> { let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); let ty = self.tcx.typeck(def_id).node_type(hir_id); - record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind { + record!(self.tables.kind[def_id.to_def_id()] <- match ty.kind() { ty::Generator(..) => { let data = self.tcx.generator_kind(def_id).unwrap(); EntryKind::Generator(data) @@ -1432,7 +1491,7 @@ impl EncodeContext<'a, 'tcx> { record!(self.tables.span[def_id.to_def_id()] <- self.tcx.def_span(def_id)); record!(self.tables.attributes[def_id.to_def_id()] <- &self.tcx.get_attrs(def_id.to_def_id())[..]); self.encode_item_type(def_id.to_def_id()); - if let ty::Closure(def_id, substs) = ty.kind { + if let ty::Closure(def_id, substs) = *ty.kind() { record!(self.tables.fn_sig[def_id] <- substs.as_closure().sig()); } self.encode_generics(def_id.to_def_id()); @@ -1459,11 +1518,13 @@ impl EncodeContext<'a, 'tcx> { } fn encode_native_libraries(&mut self) -> Lazy<[NativeLib]> { + empty_proc_macro!(self); let used_libraries = self.tcx.native_libraries(LOCAL_CRATE); self.lazy(used_libraries.iter().cloned()) } fn encode_foreign_modules(&mut self) -> Lazy<[ForeignModule]> { + empty_proc_macro!(self); let foreign_modules = self.tcx.foreign_modules(LOCAL_CRATE); self.lazy(foreign_modules.iter().cloned()) } @@ -1487,17 +1548,37 @@ impl EncodeContext<'a, 'tcx> { (syntax_contexts.encode(&mut self.opaque), expn_data_table.encode(&mut self.opaque)) } - fn encode_proc_macros(&mut self) -> Option> { + fn encode_proc_macros(&mut self) -> Option { let is_proc_macro = self.tcx.sess.crate_types().contains(&CrateType::ProcMacro); if is_proc_macro { let tcx = self.tcx; - Some(self.lazy(tcx.hir().krate().proc_macros.iter().map(|p| p.owner.local_def_index))) + let hir = tcx.hir(); + + let proc_macro_decls_static = tcx.proc_macro_decls_static(LOCAL_CRATE).unwrap().index; + let stability = tcx.lookup_stability(DefId::local(CRATE_DEF_INDEX)).copied(); + let macros = self.lazy(hir.krate().proc_macros.iter().map(|p| p.owner.local_def_index)); + + // Normally, this information is encoded when we walk the items + // defined in this crate. However, we skip doing that for proc-macro crates, + // so we manually encode just the information that we need + for proc_macro in &hir.krate().proc_macros { + let id = proc_macro.owner.local_def_index; + let span = self.lazy(hir.span(*proc_macro)); + // Proc-macros may have attributes like `#[allow_internal_unstable]`, + // so downstream crates need access to them. + let attrs = self.lazy(hir.attrs(*proc_macro)); + self.tables.span.set(id, span); + self.tables.attributes.set(id, attrs); + } + + Some(ProcMacroData { proc_macro_decls_static, stability, macros }) } else { None } } fn encode_crate_deps(&mut self) -> Lazy<[CrateDep]> { + empty_proc_macro!(self); let crates = self.tcx.crates(); let mut deps = crates @@ -1533,18 +1614,21 @@ impl EncodeContext<'a, 'tcx> { } fn encode_lib_features(&mut self) -> Lazy<[(Symbol, Option)]> { + empty_proc_macro!(self); let tcx = self.tcx; let lib_features = tcx.lib_features(); self.lazy(lib_features.to_vec()) } 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); self.lazy(diagnostic_items.iter().map(|(&name, def_id)| (name, def_id.index))) } fn encode_lang_items(&mut self) -> Lazy<[(DefIndex, usize)]> { + empty_proc_macro!(self); let tcx = self.tcx; let lang_items = tcx.lang_items(); let lang_items = lang_items.items().iter(); @@ -1559,12 +1643,14 @@ impl EncodeContext<'a, 'tcx> { } fn encode_lang_items_missing(&mut self) -> Lazy<[lang_items::LangItem]> { + empty_proc_macro!(self); let tcx = self.tcx; self.lazy(&tcx.lang_items().missing) } /// Encodes an index, mapping each trait to its (local) implementations. fn encode_impls(&mut self) -> Lazy<[TraitImpls]> { + empty_proc_macro!(self); debug!("EncodeContext::encode_impls()"); let tcx = self.tcx; let mut visitor = ImplVisitor { tcx, impls: FxHashMap::default() }; @@ -1603,6 +1689,7 @@ impl EncodeContext<'a, 'tcx> { &mut self, exported_symbols: &[(ExportedSymbol<'tcx>, SymbolExportLevel)], ) -> Lazy<[(ExportedSymbol<'tcx>, SymbolExportLevel)]> { + empty_proc_macro!(self); // The metadata symbol name is special. It should not show up in // downstream crates. let metadata_symbol_name = SymbolName::new(self.tcx, &metadata_symbol_name(self.tcx)); @@ -1619,6 +1706,7 @@ impl EncodeContext<'a, 'tcx> { } fn encode_dylib_dependency_formats(&mut self) -> Lazy<[Option]> { + empty_proc_macro!(self); let formats = self.tcx.dependency_formats(LOCAL_CRATE); for (ty, arr) in formats.iter() { if *ty != CrateType::Dylib { @@ -1665,6 +1753,7 @@ impl EncodeContext<'a, 'tcx> { self.encode_const_stability(def_id); self.encode_deprecation(def_id); self.encode_item_type(def_id); + self.encode_inherent_implementations(def_id); if let hir::ForeignItemKind::Fn(..) = nitem.kind { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); self.encode_variances_of(def_id); @@ -1734,6 +1823,9 @@ impl EncodeContext<'a, 'tcx> { EntryKind::TypeParam, default.is_some(), ); + if default.is_some() { + self.encode_stability(def_id.to_def_id()); + } } GenericParamKind::Const { .. } => { self.encode_info_for_generic_param( @@ -1741,6 +1833,7 @@ impl EncodeContext<'a, 'tcx> { EntryKind::ConstParam, true, ); + // FIXME(const_generics:defaults) } } } @@ -1979,6 +2072,7 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>) -> EncodedMetadata { let mut ecx = EncodeContext { opaque: encoder, tcx, + feat: tcx.features(), tables: Default::default(), lazy_state: LazyState::NoNode, type_shorthands: Default::default(), diff --git a/src/librustc_metadata/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs similarity index 91% rename from src/librustc_metadata/rmeta/mod.rs rename to compiler/rustc_metadata/src/rmeta/mod.rs index 1ba5962d11..1a127035d4 100644 --- a/src/librustc_metadata/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -172,6 +172,29 @@ macro_rules! Lazy { type SyntaxContextTable = Lazy>>; type ExpnDataTable = Lazy>>; +#[derive(MetadataEncodable, MetadataDecodable)] +crate struct ProcMacroData { + proc_macro_decls_static: DefIndex, + stability: Option, + macros: Lazy<[DefIndex]>, +} + +/// Serialized metadata for a crate. +/// When compiling a proc-macro crate, we encode many of +/// the `Lazy<[T]>` fields as `Lazy::empty()`. This serves two purposes: +/// +/// 1. We avoid performing unnecessary work. Proc-macro crates can only +/// export proc-macros functions, which are compiled into a shared library. +/// As a result, a large amount of the information we normally store +/// (e.g. optimized MIR) is unneeded by downstream crates. +/// 2. We avoid serializing invalid `CrateNum`s. When we deserialize +/// a proc-macro crate, we don't load any of its dependencies (since we +/// just need to invoke a native function from the shared library). +/// This means that any foreign `CrateNum`s that we serialize cannot be +/// deserialized, since we will not know how to map them into the current +/// compilation session. If we were to serialize a proc-macro crate like +/// a normal crate, much of what we serialized would be unusable in addition +/// to being unused. #[derive(MetadataEncodable, MetadataDecodable)] crate struct CrateRoot<'tcx> { name: Symbol, @@ -185,8 +208,6 @@ crate struct CrateRoot<'tcx> { has_panic_handler: bool, has_default_lib_allocator: bool, plugin_registrar_fn: Option, - proc_macro_decls_static: Option, - proc_macro_stability: Option, crate_deps: Lazy<[CrateDep]>, dylib_dependency_formats: Lazy<[Option]>, @@ -198,12 +219,10 @@ crate struct CrateRoot<'tcx> { foreign_modules: Lazy<[ForeignModule]>, impls: Lazy<[TraitImpls]>, interpret_alloc_index: Lazy<[u32]>, + proc_macro_data: Option, tables: LazyTables<'tcx>, - /// The DefIndex's of any proc macros declared by this crate. - proc_macro_data: Option>, - exported_symbols: Lazy!([(ExportedSymbol<'tcx>, SymbolExportLevel)]), syntax_contexts: SyntaxContextTable, @@ -284,6 +303,7 @@ define_tables! { super_predicates: Table)>, mir: Table)>, promoted_mir: Table>)>, + mir_abstract_consts: Table])>, unused_generic_params: Table>>, // `def_keys` and `def_path_hashes` represent a lazy version of a // `DefPathTable`. This allows us to avoid deserializing an entire diff --git a/src/librustc_metadata/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs similarity index 100% rename from src/librustc_metadata/rmeta/table.rs rename to compiler/rustc_metadata/src/rmeta/table.rs diff --git a/compiler/rustc_middle/Cargo.toml b/compiler/rustc_middle/Cargo.toml new file mode 100644 index 0000000000..e8ace361b2 --- /dev/null +++ b/compiler/rustc_middle/Cargo.toml @@ -0,0 +1,32 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_middle" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +bitflags = "1.2.1" +tracing = "0.1" +rustc-rayon-core = "0.3.0" +polonius-engine = "0.12.0" +rustc_apfloat = { path = "../rustc_apfloat" } +rustc_attr = { path = "../rustc_attr" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_macros = { path = "../rustc_macros" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_query_system = { path = "../rustc_query_system" } +rustc_errors = { path = "../rustc_errors" } +rustc_index = { path = "../rustc_index" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +chalk-ir = "0.29.0" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +measureme = "0.7.1" +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_middle/README.md b/compiler/rustc_middle/README.md similarity index 100% rename from src/librustc_middle/README.md rename to compiler/rustc_middle/README.md diff --git a/src/librustc_middle/benches/lib.rs b/compiler/rustc_middle/benches/lib.rs similarity index 100% rename from src/librustc_middle/benches/lib.rs rename to compiler/rustc_middle/benches/lib.rs diff --git a/src/librustc_middle/arena.rs b/compiler/rustc_middle/src/arena.rs similarity index 100% rename from src/librustc_middle/arena.rs rename to compiler/rustc_middle/src/arena.rs diff --git a/src/librustc_middle/dep_graph/dep_node.rs b/compiler/rustc_middle/src/dep_graph/dep_node.rs similarity index 100% rename from src/librustc_middle/dep_graph/dep_node.rs rename to compiler/rustc_middle/src/dep_graph/dep_node.rs diff --git a/src/librustc_middle/dep_graph/mod.rs b/compiler/rustc_middle/src/dep_graph/mod.rs similarity index 100% rename from src/librustc_middle/dep_graph/mod.rs rename to compiler/rustc_middle/src/dep_graph/mod.rs diff --git a/src/librustc_middle/hir/exports.rs b/compiler/rustc_middle/src/hir/exports.rs similarity index 100% rename from src/librustc_middle/hir/exports.rs rename to compiler/rustc_middle/src/hir/exports.rs diff --git a/src/librustc_middle/hir/map/blocks.rs b/compiler/rustc_middle/src/hir/map/blocks.rs similarity index 100% rename from src/librustc_middle/hir/map/blocks.rs rename to compiler/rustc_middle/src/hir/map/blocks.rs diff --git a/src/librustc_middle/hir/map/collector.rs b/compiler/rustc_middle/src/hir/map/collector.rs similarity index 98% rename from src/librustc_middle/hir/map/collector.rs rename to compiler/rustc_middle/src/hir/map/collector.rs index dce06a5f7e..d6869ab887 100644 --- a/src/librustc_middle/hir/map/collector.rs +++ b/compiler/rustc_middle/src/hir/map/collector.rs @@ -244,7 +244,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { if cfg!(debug_assertions) { if hir_id.owner != self.current_dep_node_owner { let node_str = match self.definitions.opt_hir_id_to_local_def_id(hir_id) { - Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate(), + Some(def_id) => self.definitions.def_path(def_id).to_string_no_crate_verbose(), None => format!("{:?}", node), }; @@ -254,9 +254,11 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { current_dep_node_owner={} ({:?}), hir_id.owner={} ({:?})", self.source_map.span_to_string(span), node_str, - self.definitions.def_path(self.current_dep_node_owner).to_string_no_crate(), + self.definitions + .def_path(self.current_dep_node_owner) + .to_string_no_crate_verbose(), self.current_dep_node_owner, - self.definitions.def_path(hir_id.owner).to_string_no_crate(), + self.definitions.def_path(hir_id.owner).to_string_no_crate_verbose(), hir_id.owner, ) } diff --git a/src/librustc_middle/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs similarity index 99% rename from src/librustc_middle/hir/map/mod.rs rename to compiler/rustc_middle/src/hir/map/mod.rs index 1e57411f9c..ceb873adf5 100644 --- a/src/librustc_middle/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -1002,11 +1002,7 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId) -> String { let def_id = map.local_def_id(id); tcx.def_path_str(def_id.to_def_id()) } else if let Some(path) = map.def_path_from_hir_id(id) { - path.data - .into_iter() - .map(|elem| elem.data.to_string()) - .collect::>() - .join("::") + path.data.into_iter().map(|elem| elem.to_string()).collect::>().join("::") } else { String::from("") } diff --git a/src/librustc_middle/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs similarity index 100% rename from src/librustc_middle/hir/mod.rs rename to compiler/rustc_middle/src/hir/mod.rs diff --git a/src/librustc_middle/hir/place.rs b/compiler/rustc_middle/src/hir/place.rs similarity index 100% rename from src/librustc_middle/hir/place.rs rename to compiler/rustc_middle/src/hir/place.rs diff --git a/src/librustc_middle/ich/hcx.rs b/compiler/rustc_middle/src/ich/hcx.rs similarity index 100% rename from src/librustc_middle/ich/hcx.rs rename to compiler/rustc_middle/src/ich/hcx.rs diff --git a/src/librustc_middle/ich/impls_hir.rs b/compiler/rustc_middle/src/ich/impls_hir.rs similarity index 100% rename from src/librustc_middle/ich/impls_hir.rs rename to compiler/rustc_middle/src/ich/impls_hir.rs diff --git a/src/librustc_middle/ich/impls_syntax.rs b/compiler/rustc_middle/src/ich/impls_syntax.rs similarity index 100% rename from src/librustc_middle/ich/impls_syntax.rs rename to compiler/rustc_middle/src/ich/impls_syntax.rs diff --git a/src/librustc_middle/ich/impls_ty.rs b/compiler/rustc_middle/src/ich/impls_ty.rs similarity index 100% rename from src/librustc_middle/ich/impls_ty.rs rename to compiler/rustc_middle/src/ich/impls_ty.rs diff --git a/src/librustc_middle/ich/mod.rs b/compiler/rustc_middle/src/ich/mod.rs similarity index 100% rename from src/librustc_middle/ich/mod.rs rename to compiler/rustc_middle/src/ich/mod.rs diff --git a/src/librustc_middle/infer/canonical.rs b/compiler/rustc_middle/src/infer/canonical.rs similarity index 100% rename from src/librustc_middle/infer/canonical.rs rename to compiler/rustc_middle/src/infer/canonical.rs diff --git a/src/librustc_middle/infer/mod.rs b/compiler/rustc_middle/src/infer/mod.rs similarity index 100% rename from src/librustc_middle/infer/mod.rs rename to compiler/rustc_middle/src/infer/mod.rs diff --git a/src/librustc_middle/infer/unify_key.rs b/compiler/rustc_middle/src/infer/unify_key.rs similarity index 94% rename from src/librustc_middle/infer/unify_key.rs rename to compiler/rustc_middle/src/infer/unify_key.rs index 2580ac6beb..4d884dde39 100644 --- a/src/librustc_middle/infer/unify_key.rs +++ b/compiler/rustc_middle/src/infer/unify_key.rs @@ -4,8 +4,9 @@ use rustc_data_structures::undo_log::UndoLogs; use rustc_data_structures::unify::{ self, EqUnifyValue, InPlace, NoError, UnificationTable, UnifyKey, UnifyValue, }; +use rustc_span::def_id::DefId; use rustc_span::symbol::Symbol; -use rustc_span::{Span, DUMMY_SP}; +use rustc_span::Span; use std::cmp; use std::marker::PhantomData; @@ -124,7 +125,7 @@ pub struct ConstVariableOrigin { pub enum ConstVariableOriginKind { MiscVariable, ConstInference, - ConstParameterDefinition(Symbol), + ConstParameterDefinition(Symbol, DefId), SubstitutionPlaceholder, } @@ -175,17 +176,17 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { type Error = (&'tcx ty::Const<'tcx>, &'tcx ty::Const<'tcx>); fn unify_values(value1: &Self, value2: &Self) -> Result { - let val = match (value1.val, value2.val) { + let (val, span) = match (value1.val, value2.val) { (ConstVariableValue::Known { .. }, ConstVariableValue::Known { .. }) => { bug!("equating two const variables, both of which have known values") } // If one side is known, prefer that one. (ConstVariableValue::Known { .. }, ConstVariableValue::Unknown { .. }) => { - Ok(value1.val) + (value1.val, value1.origin.span) } (ConstVariableValue::Unknown { .. }, ConstVariableValue::Known { .. }) => { - Ok(value2.val) + (value2.val, value2.origin.span) } // If both sides are *unknown*, it hardly matters, does it? @@ -199,14 +200,14 @@ impl<'tcx> UnifyValue for ConstVarValue<'tcx> { // universe is the minimum of the two universes, because that is // the one which contains the fewest names in scope. let universe = cmp::min(universe1, universe2); - Ok(ConstVariableValue::Unknown { universe }) + (ConstVariableValue::Unknown { universe }, value1.origin.span) } - }?; + }; Ok(ConstVarValue { origin: ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, - span: DUMMY_SP, + span: span, }, val, }) diff --git a/src/librustc_middle/lib.rs b/compiler/rustc_middle/src/lib.rs similarity index 91% rename from src/librustc_middle/lib.rs rename to compiler/rustc_middle/src/lib.rs index 1b2dea8a37..fa885ce2e7 100644 --- a/src/librustc_middle/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -22,7 +22,8 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] #![feature(backtrace)] #![feature(bool_to_option)] #![feature(box_patterns)] @@ -30,25 +31,21 @@ #![feature(cmp_min_max_by)] #![feature(const_fn)] #![feature(const_panic)] -#![feature(const_fn_transmute)] #![feature(core_intrinsics)] #![feature(discriminant_kind)] -#![feature(drain_filter)] #![feature(never_type)] -#![feature(exhaustive_patterns)] #![feature(extern_types)] #![feature(nll)] +#![feature(once_cell)] #![feature(option_expect_none)] #![feature(or_patterns)] #![feature(min_specialization)] #![feature(trusted_len)] -#![feature(stmt_expr_attributes)] #![feature(test)] #![feature(in_band_lifetimes)] #![feature(crate_visibility_modifier)] #![feature(associated_type_bounds)] #![feature(rustc_attrs)] -#![feature(hash_raw_entry)] #![feature(int_error_matching)] #![recursion_limit = "512"] diff --git a/src/librustc_middle/lint.rs b/compiler/rustc_middle/src/lint.rs similarity index 100% rename from src/librustc_middle/lint.rs rename to compiler/rustc_middle/src/lint.rs diff --git a/src/librustc_middle/macros.rs b/compiler/rustc_middle/src/macros.rs similarity index 100% rename from src/librustc_middle/macros.rs rename to compiler/rustc_middle/src/macros.rs diff --git a/src/librustc_middle/middle/codegen_fn_attrs.rs b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs similarity index 96% rename from src/librustc_middle/middle/codegen_fn_attrs.rs rename to compiler/rustc_middle/src/middle/codegen_fn_attrs.rs index 62a6198b9b..d71cdc4e67 100644 --- a/src/librustc_middle/middle/codegen_fn_attrs.rs +++ b/compiler/rustc_middle/src/middle/codegen_fn_attrs.rs @@ -79,6 +79,9 @@ bitflags! { /// #[ffi_const]: applies clang's `const` attribute to a foreign function /// declaration. const FFI_CONST = 1 << 13; + /// #[cmse_nonsecure_entry]: with a TrustZone-M extension, declare a + /// function as an entry function from Non-Secure code. + const CMSE_NONSECURE_ENTRY = 1 << 14; } } diff --git a/src/librustc_middle/middle/cstore.rs b/compiler/rustc_middle/src/middle/cstore.rs similarity index 99% rename from src/librustc_middle/middle/cstore.rs rename to compiler/rustc_middle/src/middle/cstore.rs index 1af1d58181..f3d7c8506a 100644 --- a/src/librustc_middle/middle/cstore.rs +++ b/compiler/rustc_middle/src/middle/cstore.rs @@ -69,7 +69,7 @@ pub enum LibSource { impl LibSource { pub fn is_some(&self) -> bool { - if let LibSource::Some(_) = *self { true } else { false } + matches!(self, LibSource::Some(_)) } pub fn option(&self) -> Option { diff --git a/src/librustc_middle/middle/dependency_format.rs b/compiler/rustc_middle/src/middle/dependency_format.rs similarity index 100% rename from src/librustc_middle/middle/dependency_format.rs rename to compiler/rustc_middle/src/middle/dependency_format.rs diff --git a/src/librustc_middle/middle/exported_symbols.rs b/compiler/rustc_middle/src/middle/exported_symbols.rs similarity index 100% rename from src/librustc_middle/middle/exported_symbols.rs rename to compiler/rustc_middle/src/middle/exported_symbols.rs diff --git a/src/librustc_middle/middle/lang_items.rs b/compiler/rustc_middle/src/middle/lang_items.rs similarity index 83% rename from src/librustc_middle/middle/lang_items.rs rename to compiler/rustc_middle/src/middle/lang_items.rs index 3e1caa3b54..cc9706f2d8 100644 --- a/src/librustc_middle/middle/lang_items.rs +++ b/compiler/rustc_middle/src/middle/lang_items.rs @@ -17,7 +17,7 @@ use rustc_target::spec::PanicStrategy; impl<'tcx> TyCtxt<'tcx> { /// Returns the `DefId` for a given `LangItem`. /// If not found, fatally aborts compilation. - pub fn require_lang_item(&self, lang_item: LangItem, span: Option) -> DefId { + pub fn require_lang_item(self, lang_item: LangItem, span: Option) -> DefId { self.lang_items().require(lang_item).unwrap_or_else(|msg| { if let Some(span) = span { self.sess.span_fatal(span, &msg) @@ -27,7 +27,7 @@ impl<'tcx> TyCtxt<'tcx> { }) } - pub fn fn_trait_kind_from_lang_item(&self, id: DefId) -> Option { + pub fn fn_trait_kind_from_lang_item(self, id: DefId) -> Option { let items = self.lang_items(); match Some(id) { x if x == items.fn_trait() => Some(ty::ClosureKind::Fn), @@ -37,7 +37,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - pub fn is_weak_lang_item(&self, item_def_id: DefId) -> bool { + pub fn is_weak_lang_item(self, item_def_id: DefId) -> bool { self.lang_items().is_weak_lang_item(item_def_id) } } @@ -53,7 +53,9 @@ pub fn required(tcx: TyCtxt<'_>, lang_item: LangItem) -> bool { // symbols. Other panic runtimes ensure that the relevant symbols are // available to link things together, but they're never exercised. match tcx.sess.panic_strategy() { - PanicStrategy::Abort => lang_item != LangItem::EhPersonality, + PanicStrategy::Abort => { + lang_item != LangItem::EhPersonality && lang_item != LangItem::EhCatchTypeinfo + } PanicStrategy::Unwind => true, } } diff --git a/src/librustc_middle/middle/limits.rs b/compiler/rustc_middle/src/middle/limits.rs similarity index 100% rename from src/librustc_middle/middle/limits.rs rename to compiler/rustc_middle/src/middle/limits.rs diff --git a/src/librustc_middle/middle/mod.rs b/compiler/rustc_middle/src/middle/mod.rs similarity index 100% rename from src/librustc_middle/middle/mod.rs rename to compiler/rustc_middle/src/middle/mod.rs diff --git a/src/librustc_middle/middle/privacy.rs b/compiler/rustc_middle/src/middle/privacy.rs similarity index 100% rename from src/librustc_middle/middle/privacy.rs rename to compiler/rustc_middle/src/middle/privacy.rs diff --git a/src/librustc_middle/middle/region.rs b/compiler/rustc_middle/src/middle/region.rs similarity index 100% rename from src/librustc_middle/middle/region.rs rename to compiler/rustc_middle/src/middle/region.rs diff --git a/src/librustc_middle/middle/resolve_lifetime.rs b/compiler/rustc_middle/src/middle/resolve_lifetime.rs similarity index 100% rename from src/librustc_middle/middle/resolve_lifetime.rs rename to compiler/rustc_middle/src/middle/resolve_lifetime.rs diff --git a/src/librustc_middle/middle/stability.rs b/compiler/rustc_middle/src/middle/stability.rs similarity index 92% rename from src/librustc_middle/middle/stability.rs rename to compiler/rustc_middle/src/middle/stability.rs index b32eebbb11..7e2415fd54 100644 --- a/src/librustc_middle/middle/stability.rs +++ b/compiler/rustc_middle/src/middle/stability.rs @@ -13,6 +13,7 @@ use rustc_hir as hir; use rustc_hir::def::DefKind; use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX}; 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::parse::feature_err_issue; @@ -308,7 +309,7 @@ impl<'tcx> TyCtxt<'tcx> { // #[rustc_deprecated] however wants to emit down the whole // hierarchy. if !skip || depr_entry.attr.is_since_rustc_version { - let path = &self.def_path_str(def_id); + 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( @@ -391,9 +392,27 @@ impl<'tcx> TyCtxt<'tcx> { /// If the item defined by `def_id` is unstable and the corresponding `#![feature]` does not /// exist, emits an error. /// - /// Additionally, this function will also check if the item is deprecated. If so, and `id` is - /// not `None`, a deprecated lint attached to `id` will be emitted. + /// This function will also check if the item is deprecated. + /// If so, and `id` is not `None`, a deprecated lint attached to `id` will be emitted. pub fn check_stability(self, def_id: DefId, id: Option, span: Span) { + self.check_optional_stability(def_id, id, span, |span, def_id| { + // The API could be uncallable for other reasons, for example when a private module + // was referenced. + self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); + }) + } + + /// Like `check_stability`, except that we permit items to have custom behaviour for + /// missing stability attributes (not necessarily just emit a `bug!`). This is necessary + /// for default generic parameters, which only have stability attributes if they were + /// added after the type on which they're defined. + pub fn check_optional_stability( + self, + def_id: DefId, + id: Option, + span: Span, + unmarked: impl FnOnce(Span, DefId) -> (), + ) { let soft_handler = |lint, span, msg: &_| { self.struct_span_lint_hir(lint, id.unwrap_or(hir::CRATE_HIR_ID), span, |lint| { lint.build(msg).emit() @@ -404,11 +423,7 @@ impl<'tcx> TyCtxt<'tcx> { EvalResult::Deny { feature, reason, issue, is_soft } => { report_unstable(self.sess, feature, reason, issue, is_soft, span, soft_handler) } - EvalResult::Unmarked => { - // The API could be uncallable for other reasons, for example when a private module - // was referenced. - self.sess.delay_span_bug(span, &format!("encountered unmarked API: {:?}", def_id)); - } + EvalResult::Unmarked => unmarked(span, def_id), } } diff --git a/compiler/rustc_middle/src/mir/abstract_const.rs b/compiler/rustc_middle/src/mir/abstract_const.rs new file mode 100644 index 0000000000..b85f1e6e5d --- /dev/null +++ b/compiler/rustc_middle/src/mir/abstract_const.rs @@ -0,0 +1,20 @@ +//! A subset of a mir body used for const evaluatability checking. +use crate::mir; +use crate::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]), +} diff --git a/src/librustc_middle/mir/coverage/mod.rs b/compiler/rustc_middle/src/mir/coverage/mod.rs similarity index 100% rename from src/librustc_middle/mir/coverage/mod.rs rename to compiler/rustc_middle/src/mir/coverage/mod.rs diff --git a/src/librustc_middle/mir/interpret/allocation.rs b/compiler/rustc_middle/src/mir/interpret/allocation.rs similarity index 98% rename from src/librustc_middle/mir/interpret/allocation.rs rename to compiler/rustc_middle/src/mir/interpret/allocation.rs index 505939d56e..ee1ea816e0 100644 --- a/src/librustc_middle/mir/interpret/allocation.rs +++ b/compiler/rustc_middle/src/mir/interpret/allocation.rs @@ -345,10 +345,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// Reads a *non-ZST* scalar. /// - /// ZSTs can't be read for two reasons: - /// * byte-order cannot work with zero-element buffers; - /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer - /// pointers being valid for ZSTs. + /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check + /// for ZSTness anyway due to integer pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. /// Most likely, you want to call `InterpCx::read_scalar` instead of this method. @@ -397,10 +395,8 @@ impl<'tcx, Tag: Copy, Extra: AllocationExtra> Allocation { /// Writes a *non-ZST* scalar. /// - /// ZSTs can't be read for two reasons: - /// * byte-order cannot work with zero-element buffers; - /// * in order to obtain a `Pointer`, we need to check for ZSTness anyway due to integer - /// pointers being valid for ZSTs. + /// ZSTs can't be read because in order to obtain a `Pointer`, we need to check + /// for ZSTness anyway due to integer pointers being valid for ZSTs. /// /// It is the caller's responsibility to check bounds and alignment beforehand. /// Most likely, you want to call `InterpCx::write_scalar` instead of this method. diff --git a/src/librustc_middle/mir/interpret/error.rs b/compiler/rustc_middle/src/mir/interpret/error.rs similarity index 98% rename from src/librustc_middle/mir/interpret/error.rs rename to compiler/rustc_middle/src/mir/interpret/error.rs index 059925088c..d41e568060 100644 --- a/src/librustc_middle/mir/interpret/error.rs +++ b/compiler/rustc_middle/src/mir/interpret/error.rs @@ -1,4 +1,4 @@ -use super::{AllocId, Pointer, RawConst, Scalar}; +use super::{AllocId, ConstAlloc, Pointer, Scalar}; use crate::mir::interpret::ConstValue; use crate::ty::{layout, query::TyCtxtAt, tls, FnSig, Ty}; @@ -23,12 +23,18 @@ pub enum ErrorHandled { TooGeneric, } +impl From for ErrorHandled { + fn from(err: ErrorReported) -> ErrorHandled { + ErrorHandled::Reported(err) + } +} + CloneTypeFoldableAndLiftImpls! { ErrorHandled, } -pub type ConstEvalRawResult<'tcx> = Result, ErrorHandled>; -pub type ConstEvalResult<'tcx> = Result, ErrorHandled>; +pub type EvalToAllocationRawResult<'tcx> = Result, ErrorHandled>; +pub type EvalToConstValueResult<'tcx> = Result, ErrorHandled>; pub fn struct_error<'tcx>(tcx: TyCtxtAt<'tcx>, msg: &str) -> DiagnosticBuilder<'tcx> { struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) diff --git a/src/librustc_middle/mir/interpret/mod.rs b/compiler/rustc_middle/src/mir/interpret/mod.rs similarity index 90% rename from src/librustc_middle/mir/interpret/mod.rs rename to compiler/rustc_middle/src/mir/interpret/mod.rs index 0dc3d6e344..20363625e4 100644 --- a/src/librustc_middle/mir/interpret/mod.rs +++ b/compiler/rustc_middle/src/mir/interpret/mod.rs @@ -98,16 +98,17 @@ mod value; use std::convert::TryFrom; use std::fmt; use std::io; +use std::io::{Read, Write}; use std::num::NonZeroU32; use std::sync::atomic::{AtomicU32, Ordering}; -use byteorder::{BigEndian, LittleEndian, ReadBytesExt, WriteBytesExt}; use rustc_ast::LitKind; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::{HashMapExt, Lock}; use rustc_data_structures::tiny_list::TinyList; use rustc_hir::def_id::DefId; use rustc_macros::HashStable; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_serialize::{Decodable, Encodable}; use rustc_target::abi::{Endian, Size}; @@ -117,12 +118,12 @@ use crate::ty::subst::GenericArgKind; use crate::ty::{self, Instance, Ty, TyCtxt}; pub use self::error::{ - struct_error, CheckInAllocMsg, ConstEvalRawResult, ConstEvalResult, ErrorHandled, InterpError, - InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, ResourceExhaustionInfo, - UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, + struct_error, CheckInAllocMsg, ErrorHandled, EvalToAllocationRawResult, EvalToConstValueResult, + InterpError, InterpErrorInfo, InterpResult, InvalidProgramInfo, MachineStopType, + ResourceExhaustionInfo, UndefinedBehaviorInfo, UninitBytesAccess, UnsupportedOpInfo, }; -pub use self::value::{get_slice_bytes, ConstValue, RawConst, Scalar, ScalarMaybeUninit}; +pub use self::value::{get_slice_bytes, ConstAlloc, ConstValue, Scalar, ScalarMaybeUninit}; pub use self::allocation::{Allocation, AllocationExtra, InitMask, Relocations}; @@ -145,7 +146,7 @@ pub struct GlobalId<'tcx> { impl GlobalId<'tcx> { pub fn display(self, tcx: TyCtxt<'tcx>) -> String { - let instance_name = tcx.def_path_str(self.instance.def.def_id()); + let instance_name = with_no_trimmed_paths(|| tcx.def_path_str(self.instance.def.def_id())); if let Some(promoted) = self.promoted { format!("{}::{:?}", instance_name, promoted) } else { @@ -446,14 +447,14 @@ impl<'tcx> TyCtxt<'tcx> { /// /// Make sure to call `set_alloc_id_memory` or `set_alloc_id_same_memory` before returning such /// an `AllocId` from a query. - pub fn reserve_alloc_id(&self) -> AllocId { + pub fn reserve_alloc_id(self) -> AllocId { self.alloc_map.lock().reserve() } /// Reserves a new ID *if* this allocation has not been dedup-reserved before. /// Should only be used for function pointers and statics, we don't want /// to dedup IDs for "real" memory! - fn reserve_and_set_dedup(&self, alloc: GlobalAlloc<'tcx>) -> AllocId { + fn reserve_and_set_dedup(self, alloc: GlobalAlloc<'tcx>) -> AllocId { let mut alloc_map = self.alloc_map.lock(); match alloc { GlobalAlloc::Function(..) | GlobalAlloc::Static(..) => {} @@ -471,13 +472,13 @@ impl<'tcx> TyCtxt<'tcx> { /// Generates an `AllocId` for a static or return a cached one in case this function has been /// called on the same static before. - pub fn create_static_alloc(&self, static_id: DefId) -> AllocId { + pub fn create_static_alloc(self, static_id: DefId) -> AllocId { self.reserve_and_set_dedup(GlobalAlloc::Static(static_id)) } /// Generates an `AllocId` for a function. Depending on the function type, /// this might get deduplicated or assigned a new ID each time. - pub fn create_fn_alloc(&self, instance: Instance<'tcx>) -> AllocId { + pub fn create_fn_alloc(self, instance: Instance<'tcx>) -> AllocId { // Functions cannot be identified by pointers, as asm-equal functions can get deduplicated // by the linker (we set the "unnamed_addr" attribute for LLVM) and functions can be // duplicated across crates. @@ -506,7 +507,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Statics with identical content will still point to the same `Allocation`, i.e., /// their data will be deduplicated through `Allocation` interning -- but they /// are different places in memory and as such need different IDs. - pub fn create_memory_alloc(&self, mem: &'tcx Allocation) -> AllocId { + pub fn create_memory_alloc(self, mem: &'tcx Allocation) -> AllocId { let id = self.reserve_alloc_id(); self.set_alloc_id_memory(id, mem); id @@ -518,7 +519,7 @@ impl<'tcx> TyCtxt<'tcx> { /// This function exists to allow const eval to detect the difference between evaluation- /// local dangling pointers and allocations in constants/statics. #[inline] - pub fn get_global_alloc(&self, id: AllocId) -> Option> { + pub fn get_global_alloc(self, id: AllocId) -> Option> { self.alloc_map.lock().alloc_map.get(&id).cloned() } @@ -528,7 +529,7 @@ impl<'tcx> TyCtxt<'tcx> { /// constants (as all constants must pass interning and validation that check for dangling /// ids), this function is frequently used throughout rustc, but should not be used within /// the miri engine. - pub fn global_alloc(&self, id: AllocId) -> GlobalAlloc<'tcx> { + pub fn global_alloc(self, id: AllocId) -> GlobalAlloc<'tcx> { match self.get_global_alloc(id) { Some(alloc) => alloc, None => bug!("could not find allocation for {}", id), @@ -537,7 +538,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. Trying to /// call this function twice, even with the same `Allocation` will ICE the compiler. - pub fn set_alloc_id_memory(&self, id: AllocId, mem: &'tcx Allocation) { + pub fn set_alloc_id_memory(self, id: AllocId, mem: &'tcx Allocation) { if let Some(old) = self.alloc_map.lock().alloc_map.insert(id, GlobalAlloc::Memory(mem)) { bug!("tried to set allocation ID {}, but it was already existing as {:#?}", id, old); } @@ -545,7 +546,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Freezes an `AllocId` created with `reserve` by pointing it at an `Allocation`. May be called /// twice for the same `(AllocId, Allocation)` pair. - fn set_alloc_id_same_memory(&self, id: AllocId, mem: &'tcx Allocation) { + fn set_alloc_id_same_memory(self, id: AllocId, mem: &'tcx Allocation) { self.alloc_map.lock().alloc_map.insert_same(id, GlobalAlloc::Memory(mem)); } } @@ -560,19 +561,33 @@ pub fn write_target_uint( mut target: &mut [u8], data: u128, ) -> Result<(), io::Error> { - let len = target.len(); + // This u128 holds an "any-size uint" (since smaller uints can fits in it) + // So we do not write all bytes of the u128, just the "payload". match endianness { - Endian::Little => target.write_uint128::(data, len), - Endian::Big => target.write_uint128::(data, len), - } + Endian::Little => target.write(&data.to_le_bytes())?, + Endian::Big => target.write(&data.to_be_bytes()[16 - target.len()..])?, + }; + debug_assert!(target.len() == 0); // We should have filled the target buffer. + Ok(()) } #[inline] pub fn read_target_uint(endianness: Endian, mut source: &[u8]) -> Result { - match endianness { - Endian::Little => source.read_uint128::(source.len()), - Endian::Big => source.read_uint128::(source.len()), - } + // This u128 holds an "any-size uint" (since smaller uints can fits in it) + let mut buf = [0u8; std::mem::size_of::()]; + // So we do not read exactly 16 bytes into the u128, just the "payload". + let uint = match endianness { + Endian::Little => { + source.read(&mut buf)?; + Ok(u128::from_le_bytes(buf)) + } + Endian::Big => { + source.read(&mut buf[16 - source.len()..])?; + Ok(u128::from_be_bytes(buf)) + } + }; + debug_assert!(source.len() == 0); // We should have consumed the source buffer. + uint } //////////////////////////////////////////////////////////////////////////////// diff --git a/src/librustc_middle/mir/interpret/pointer.rs b/compiler/rustc_middle/src/mir/interpret/pointer.rs similarity index 100% rename from src/librustc_middle/mir/interpret/pointer.rs rename to compiler/rustc_middle/src/mir/interpret/pointer.rs diff --git a/src/librustc_middle/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs similarity index 90% rename from src/librustc_middle/mir/interpret/queries.rs rename to compiler/rustc_middle/src/mir/interpret/queries.rs index dcc1f8b1a4..f366681bc7 100644 --- a/src/librustc_middle/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -1,4 +1,4 @@ -use super::{ConstEvalResult, ErrorHandled, GlobalId}; +use super::{ErrorHandled, EvalToConstValueResult, GlobalId}; use crate::mir; use crate::ty::subst::{InternalSubsts, SubstsRef}; @@ -10,7 +10,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Evaluates a constant without providing any substitutions. This is useful to evaluate consts /// that can't take any generic arguments like statics, const items or enum discriminants. If a /// generic parameter is used within the constant `ErrorHandled::ToGeneric` will be returned. - pub fn const_eval_poly(self, def_id: DefId) -> ConstEvalResult<'tcx> { + pub fn const_eval_poly(self, def_id: DefId) -> EvalToConstValueResult<'tcx> { // In some situations def_id will have substitutions within scope, but they aren't allowed // to be used. So we can't use `Instance::mono`, instead we feed unresolved substitutions // into `const_eval` which will return `ErrorHandled::ToGeneric` if any of them are @@ -38,7 +38,7 @@ impl<'tcx> TyCtxt<'tcx> { substs: SubstsRef<'tcx>, promoted: Option, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { match ty::Instance::resolve_opt_const_arg(self, param_env, def, substs) { Ok(Some(instance)) => { let cid = GlobalId { instance, promoted }; @@ -54,7 +54,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, instance: ty::Instance<'tcx>, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { self.const_eval_global_id(param_env, GlobalId { instance, promoted: None }, span) } @@ -64,14 +64,14 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, cid: GlobalId<'tcx>, span: Option, - ) -> ConstEvalResult<'tcx> { + ) -> EvalToConstValueResult<'tcx> { // Const-eval shouldn't depend on lifetimes at all, so we can erase them, which should // improve caching of queries. let inputs = self.erase_regions(¶m_env.and(cid)); if let Some(span) = span { - self.at(span).const_eval_validated(inputs) + self.at(span).eval_to_const_value_raw(inputs) } else { - self.const_eval_validated(inputs) + self.eval_to_const_value_raw(inputs) } } @@ -94,7 +94,7 @@ impl<'tcx> TyCtxt<'tcx> { param_env: ty::ParamEnv<'tcx>, ) -> Result<&'tcx mir::Allocation, ErrorHandled> { trace!("eval_to_allocation: Need to compute {:?}", gid); - let raw_const = self.const_eval_raw(param_env.and(gid))?; + let raw_const = self.eval_to_allocation_raw(param_env.and(gid))?; Ok(self.global_alloc(raw_const.alloc_id).unwrap_memory()) } } diff --git a/src/librustc_middle/mir/interpret/value.rs b/compiler/rustc_middle/src/mir/interpret/value.rs similarity index 97% rename from src/librustc_middle/mir/interpret/value.rs rename to compiler/rustc_middle/src/mir/interpret/value.rs index 4c47f25105..206f01c249 100644 --- a/src/librustc_middle/mir/interpret/value.rs +++ b/compiler/rustc_middle/src/mir/interpret/value.rs @@ -12,9 +12,9 @@ use crate::ty::{ParamEnv, Ty, TyCtxt}; use super::{sign_extend, truncate, AllocId, Allocation, InterpResult, Pointer, PointerArithmetic}; -/// Represents the result of a raw const operation, pre-validation. -#[derive(Clone, HashStable)] -pub struct RawConst<'tcx> { +/// Represents the result of const evaluation via the `eval_to_allocation` query. +#[derive(Clone, HashStable, TyEncodable, TyDecodable)] +pub struct ConstAlloc<'tcx> { // the value lives here, at offset 0, and that allocation definitely is a `AllocKind::Memory` // (so you can use `AllocMap::unwrap_memory`). pub alloc_id: AllocId, @@ -503,6 +503,11 @@ impl<'tcx, Tag> Scalar { self.to_unsigned_with_bit_width(64).map(|v| u64::try_from(v).unwrap()) } + /// Converts the scalar to produce an `u128`. Fails if the scalar is a pointer. + pub fn to_u128(self) -> InterpResult<'static, u128> { + self.to_unsigned_with_bit_width(128) + } + pub fn to_machine_usize(self, cx: &impl HasDataLayout) -> InterpResult<'static, u64> { let b = self.to_bits(cx.data_layout().pointer_size)?; Ok(u64::try_from(b).unwrap()) @@ -535,6 +540,11 @@ impl<'tcx, Tag> Scalar { self.to_signed_with_bit_width(64).map(|v| i64::try_from(v).unwrap()) } + /// Converts the scalar to produce an `i128`. Fails if the scalar is a pointer. + pub fn to_i128(self) -> InterpResult<'static, i128> { + self.to_signed_with_bit_width(128) + } + pub fn to_machine_isize(self, cx: &impl HasDataLayout) -> InterpResult<'static, i64> { let sz = cx.data_layout().pointer_size; let b = self.to_bits(sz)?; @@ -568,6 +578,9 @@ pub enum ScalarMaybeUninit { Uninit, } +#[cfg(target_arch = "x86_64")] +static_assert_size!(ScalarMaybeUninit, 24); + impl From> for ScalarMaybeUninit { #[inline(always)] fn from(s: Scalar) -> Self { diff --git a/src/librustc_middle/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs similarity index 93% rename from src/librustc_middle/mir/mod.rs rename to compiler/rustc_middle/src/mir/mod.rs index ad40cf221b..fee24f0bae 100644 --- a/src/librustc_middle/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -40,6 +40,7 @@ use std::{iter, mem, option}; use self::predecessors::{PredecessorCache, Predecessors}; pub use self::query::*; +pub mod abstract_const; pub mod coverage; pub mod interpret; pub mod mono; @@ -186,6 +187,23 @@ pub struct Body<'tcx> { /// FIXME(oli-obk): rewrite the promoted during promotion to eliminate the cell components. pub ignore_interior_mut_in_const_validation: bool, + /// Does this body use generic parameters. This is used for the `ConstEvaluatable` check. + /// + /// Note that this does not actually mean that this body is not computable right now. + /// The repeat count in the following example is polymorphic, but can still be evaluated + /// without knowing anything about the type parameter `T`. + /// + /// ```rust + /// fn test() { + /// let _ = [0; std::mem::size_of::<*mut T>()]; + /// } + /// ``` + /// + /// **WARNING**: Do not change this flags after the MIR was originally created, even if an optimization + /// removed the last mention of all generic params. We do not want to rely on optimizations and + /// potentially allow things like `[u8; std::mem::size_of::() * 0]` due to this. + pub is_polymorphic: bool, + predecessor_cache: PredecessorCache, } @@ -208,7 +226,7 @@ impl<'tcx> Body<'tcx> { local_decls.len() ); - Body { + let mut body = Body { phase: MirPhase::Build, basic_blocks, source_scopes, @@ -224,8 +242,11 @@ impl<'tcx> Body<'tcx> { span, required_consts: Vec::new(), ignore_interior_mut_in_const_validation: false, + is_polymorphic: false, predecessor_cache: PredecessorCache::new(), - } + }; + body.is_polymorphic = body.has_param_types_or_consts(); + body } /// Returns a partially initialized MIR body containing only a list of basic blocks. @@ -234,7 +255,7 @@ impl<'tcx> Body<'tcx> { /// is only useful for testing but cannot be `#[cfg(test)]` because it is used in a different /// crate. pub fn new_cfg_only(basic_blocks: IndexVec>) -> Self { - Body { + let mut body = Body { phase: MirPhase::Build, basic_blocks, source_scopes: IndexVec::new(), @@ -250,8 +271,11 @@ impl<'tcx> Body<'tcx> { generator_kind: None, var_debug_info: Vec::new(), ignore_interior_mut_in_const_validation: false, + is_polymorphic: false, predecessor_cache: PredecessorCache::new(), - } + }; + body.is_polymorphic = body.has_param_types_or_consts(); + body } #[inline] @@ -646,7 +670,7 @@ impl Atom for Local { } /// Classifies locals into categories. See `Body::local_kind`. -#[derive(PartialEq, Eq, Debug, HashStable)] +#[derive(Clone, Copy, PartialEq, Eq, Debug, HashStable)] pub enum LocalKind { /// User-declared variable binding. Var, @@ -899,6 +923,8 @@ pub enum LocalInfo<'tcx> { User(ClearCrossCrate>), /// A temporary created that references the static with the given `DefId`. StaticRef { def_id: DefId, is_thread_local: bool }, + /// A temporary created that references the const with the given `DefId` + ConstRef { def_id: DefId }, } impl<'tcx> LocalDecl<'tcx> { @@ -1051,6 +1077,25 @@ pub struct VarDebugInfo<'tcx> { // BasicBlock rustc_index::newtype_index! { + /// A node in the MIR [control-flow graph][CFG]. + /// + /// There are no branches (e.g., `if`s, function calls, etc.) within a basic block, which makes + /// it easier to do [data-flow analyses] and optimizations. Instead, branches are represented + /// as an edge in a graph between basic blocks. + /// + /// Basic blocks consist of a series of [statements][Statement], ending with a + /// [terminator][Terminator]. Basic blocks can have multiple predecessors and successors, + /// however there is a MIR pass ([`CriticalCallEdges`]) that removes *critical edges*, which + /// are edges that go from a multi-successor node to a multi-predecessor node. This pass is + /// needed because some analyses require that there are no critical edges in the CFG. + /// + /// Read more about basic blocks in the [rustc-dev-guide][guide-mir]. + /// + /// [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 + /// [guide-mir]: https://rustc-dev-guide.rust-lang.org/mir/ pub struct BasicBlock { derive [HashStable] DEBUG_FORMAT = "bb{}", @@ -1067,6 +1112,7 @@ impl BasicBlock { /////////////////////////////////////////////////////////////////////////// // BasicBlockData and Terminator +/// See [`BasicBlock`] for documentation on what basic blocks are at a high level. #[derive(Clone, Debug, TyEncodable, TyDecodable, HashStable, TypeFoldable)] pub struct BasicBlockData<'tcx> { /// List of statements in this block. @@ -1254,49 +1300,49 @@ impl AssertKind { match self { BoundsCheck { ref len, ref index } => write!( f, - "\"index out of bounds: the len is {{}} but the index is {{}}\", {:?}, {:?}", + "\"index out of bounds: the length is {{}} but the index is {{}}\", {:?}, {:?}", len, index ), OverflowNeg(op) => { - write!(f, "\"attempt to negate {{}} which would overflow\", {:?}", op) + write!(f, "\"attempt to negate `{{}}`, which would overflow\", {:?}", op) } - DivisionByZero(op) => write!(f, "\"attempt to divide {{}} by zero\", {:?}", op), + DivisionByZero(op) => write!(f, "\"attempt to divide `{{}}` by zero\", {:?}", op), RemainderByZero(op) => write!( f, - "\"attempt to calculate the remainder of {{}} with a divisor of zero\", {:?}", + "\"attempt to calculate the remainder of `{{}}` with a divisor of zero\", {:?}", op ), Overflow(BinOp::Add, l, r) => write!( f, - "\"attempt to compute `{{}} + {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} + {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Sub, l, r) => write!( f, - "\"attempt to compute `{{}} - {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} - {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Mul, l, r) => write!( f, - "\"attempt to compute `{{}} * {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} * {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Div, l, r) => write!( f, - "\"attempt to compute `{{}} / {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute `{{}} / {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Rem, l, r) => write!( f, - "\"attempt to compute the remainder of `{{}} % {{}}` which would overflow\", {:?}, {:?}", + "\"attempt to compute the remainder of `{{}} % {{}}`, which would overflow\", {:?}, {:?}", l, r ), Overflow(BinOp::Shr, _, r) => { - write!(f, "\"attempt to shift right by {{}} which would overflow\", {:?}", r) + write!(f, "\"attempt to shift right by `{{}}`, which would overflow\", {:?}", r) } Overflow(BinOp::Shl, _, r) => { - write!(f, "\"attempt to shift left by {{}} which would overflow\", {:?}", r) + write!(f, "\"attempt to shift left by `{{}}`, which would overflow\", {:?}", r) } _ => write!(f, "\"{}\"", self.description()), } @@ -1307,36 +1353,40 @@ impl fmt::Debug for AssertKind { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { use AssertKind::*; match self { - BoundsCheck { ref len, ref index } => { - write!(f, "index out of bounds: the len is {:?} but the index is {:?}", len, index) - } - OverflowNeg(op) => write!(f, "attempt to negate {:#?} which would overflow", op), - DivisionByZero(op) => write!(f, "attempt to divide {:#?} by zero", op), - RemainderByZero(op) => { - write!(f, "attempt to calculate the remainder of {:#?} with a divisor of zero", op) - } + BoundsCheck { ref len, ref index } => write!( + f, + "index out of bounds: the length is {:?} but the index is {:?}", + len, index + ), + OverflowNeg(op) => write!(f, "attempt to negate `{:#?}`, which would overflow", op), + DivisionByZero(op) => write!(f, "attempt to divide `{:#?}` by zero", op), + RemainderByZero(op) => write!( + f, + "attempt to calculate the remainder of `{:#?}` with a divisor of zero", + op + ), Overflow(BinOp::Add, l, r) => { - write!(f, "attempt to compute `{:#?} + {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} + {:#?}`, which would overflow", l, r) } Overflow(BinOp::Sub, l, r) => { - write!(f, "attempt to compute `{:#?} - {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} - {:#?}`, which would overflow", l, r) } Overflow(BinOp::Mul, l, r) => { - write!(f, "attempt to compute `{:#?} * {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} * {:#?}`, which would overflow", l, r) } Overflow(BinOp::Div, l, r) => { - write!(f, "attempt to compute `{:#?} / {:#?}` which would overflow", l, r) + write!(f, "attempt to compute `{:#?} / {:#?}`, which would overflow", l, r) } Overflow(BinOp::Rem, l, r) => write!( f, - "attempt to compute the remainder of `{:#?} % {:#?}` which would overflow", + "attempt to compute the remainder of `{:#?} % {:#?}`, which would overflow", l, r ), Overflow(BinOp::Shr, _, r) => { - write!(f, "attempt to shift right by {:#?} which would overflow", r) + write!(f, "attempt to shift right by `{:#?}`, which would overflow", r) } Overflow(BinOp::Shl, _, r) => { - write!(f, "attempt to shift left by {:#?} which would overflow", r) + write!(f, "attempt to shift left by `{:#?}`, which would overflow", r) } _ => write!(f, "{}", self.description()), } @@ -1430,6 +1480,15 @@ pub enum StatementKind<'tcx> { Nop, } +impl<'tcx> StatementKind<'tcx> { + pub fn as_assign_mut(&mut self) -> Option<&mut Box<(Place<'tcx>, Rvalue<'tcx>)>> { + match self { + StatementKind::Assign(x) => Some(x), + _ => None, + } + } +} + /// Describes what kind of retag is to be performed. #[derive(Copy, Clone, TyEncodable, TyDecodable, Debug, PartialEq, Eq, HashStable)] pub enum RetagKind { @@ -1521,7 +1580,24 @@ impl Debug for Statement<'_> { AscribeUserType(box (ref place, ref c_ty), ref variance) => { write!(fmt, "AscribeUserType({:?}, {:?}, {:?})", place, variance, c_ty) } - Coverage(box ref coverage) => write!(fmt, "{:?}", coverage), + Coverage(box ref coverage) => { + let rgn = &coverage.code_region; + match coverage.kind { + CoverageKind::Counter { id, .. } => { + write!(fmt, "Coverage::Counter({:?}) for {:?}", id.index(), rgn) + } + CoverageKind::Expression { id, lhs, op, rhs } => write!( + fmt, + "Coverage::Expression({:?}) = {} {} {} for {:?}", + id.index(), + lhs.index(), + if op == coverage::Op::Add { "+" } else { "-" }, + rhs.index(), + rgn + ), + CoverageKind::Unreachable => write!(fmt, "Coverage::Unreachable for {:?}", rgn), + } + } Nop => write!(fmt, "nop"), } } @@ -1564,10 +1640,10 @@ pub enum ProjectionElem { /// ``` ConstantIndex { /// index or -index (in Python terms), depending on from_end - offset: u32, + offset: u64, /// The thing being indexed must be at least this long. For arrays this /// is always the exact length. - min_length: u32, + min_length: u64, /// Counting backwards from end? This is always false when indexing an /// array. from_end: bool, @@ -1578,8 +1654,8 @@ pub enum ProjectionElem { /// If `from_end` is true `slice[from..slice.len() - to]`. /// Otherwise `array[from..to]`. Subslice { - from: u32, - to: u32, + from: u64, + to: u64, /// Whether `to` counts from the start or end of the array/slice. /// For `PlaceElem`s this is `true` if and only if the base is a slice. /// For `ProjectionKind`, this can also be `true` for arrays. @@ -1616,7 +1692,7 @@ pub type PlaceElem<'tcx> = ProjectionElem>; // At least on 64 bit systems, `PlaceElem` should not be larger than two pointers. #[cfg(target_arch = "x86_64")] -static_assert_size!(PlaceElem<'_>, 16); +static_assert_size!(PlaceElem<'_>, 24); /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. @@ -1843,6 +1919,10 @@ impl<'tcx> Operand<'tcx> { }) } + pub fn is_move(&self) -> bool { + matches!(self, Operand::Move(..)) + } + /// Convenience helper to make a literal-like constant from a given scalar value. /// Since this is used to synthesize MIR, assumes `user_ty` is None. pub fn const_from_scalar( @@ -1924,6 +2004,15 @@ impl<'tcx> Operand<'tcx> { Operand::Constant(_) => None, } } + + /// Returns the `Constant` that is the target of this `Operand`, or `None` if this `Operand` is a + /// place. + pub fn constant(&self) -> Option<&Constant<'tcx>> { + match self { + Operand::Constant(x) => Some(&**x), + Operand::Copy(_) | Operand::Move(_) => None, + } + } } /////////////////////////////////////////////////////////////////////////// @@ -2221,8 +2310,8 @@ impl<'tcx> Debug for Rvalue<'tcx> { /// Constants /// /// Two constants are equal if they are the same constant. Note that -/// this does not necessarily mean that they are "==" in Rust -- in -/// particular one must be wary of `NaN`! +/// this does not necessarily mean that they are `==` in Rust. In +/// particular, one must be wary of `NaN`! #[derive(Clone, Copy, PartialEq, TyEncodable, TyDecodable, HashStable)] pub struct Constant<'tcx> { @@ -2330,7 +2419,7 @@ impl<'tcx> UserTypeProjections { self.map_projections(|pat_ty_proj| pat_ty_proj.index()) } - pub fn subslice(self, from: u32, to: u32) -> Self { + pub fn subslice(self, from: u64, to: u64) -> Self { self.map_projections(|pat_ty_proj| pat_ty_proj.subslice(from, to)) } @@ -2376,7 +2465,7 @@ impl UserTypeProjection { self } - pub(crate) fn subslice(mut self, from: u32, to: u32) -> Self { + pub(crate) fn subslice(mut self, from: u64, to: u64) -> Self { self.projs.push(ProjectionElem::Subslice { from, to, from_end: true }); self } @@ -2452,7 +2541,7 @@ impl<'tcx> Debug for Constant<'tcx> { impl<'tcx> Display for Constant<'tcx> { fn fmt(&self, fmt: &mut Formatter<'_>) -> fmt::Result { - match self.literal.ty.kind { + match self.literal.ty.kind() { ty::FnDef(..) => {} _ => write!(fmt, "const ")?, } diff --git a/src/librustc_middle/mir/mono.rs b/compiler/rustc_middle/src/mir/mono.rs similarity index 95% rename from src/librustc_middle/mir/mono.rs rename to compiler/rustc_middle/src/mir/mono.rs index 0d5f6619df..79e2c5aac2 100644 --- a/src/librustc_middle/mir/mono.rs +++ b/compiler/rustc_middle/src/mir/mono.rs @@ -1,6 +1,5 @@ use crate::dep_graph::{DepConstructor, DepNode, WorkProduct, WorkProductId}; use crate::ich::{NodeIdHashingMode, StableHashingContext}; -use crate::ty::print::obsolete::DefPathBasedNames; use crate::ty::{subst::InternalSubsts, Instance, InstanceDef, SymbolName, TyCtxt}; use rustc_attr::InlineAttr; use rustc_data_structures::base_n; @@ -86,7 +85,7 @@ impl<'tcx> MonoItem<'tcx> { .debugging_opts .inline_in_all_cgus .unwrap_or_else(|| tcx.sess.opts.optimize != OptLevel::No) - && tcx.sess.opts.cg.link_dead_code != Some(true); + && !tcx.sess.link_dead_code(); match *self { MonoItem::Fn(ref instance) => { @@ -171,30 +170,6 @@ impl<'tcx> MonoItem<'tcx> { !tcx.subst_and_check_impossible_predicates((def_id, &substs)) } - pub fn to_string(&self, tcx: TyCtxt<'tcx>, debug: bool) -> String { - return match *self { - MonoItem::Fn(instance) => to_string_internal(tcx, "fn ", instance, debug), - MonoItem::Static(def_id) => { - let instance = Instance::new(def_id, tcx.intern_substs(&[])); - to_string_internal(tcx, "static ", instance, debug) - } - MonoItem::GlobalAsm(..) => "global_asm".to_string(), - }; - - fn to_string_internal<'tcx>( - tcx: TyCtxt<'tcx>, - prefix: &str, - instance: Instance<'tcx>, - debug: bool, - ) -> String { - let mut result = String::with_capacity(32); - result.push_str(prefix); - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_instance_as_string(instance, &mut result, debug); - result - } - } - pub fn local_span(&self, tcx: TyCtxt<'tcx>) -> Option { match *self { MonoItem::Fn(Instance { def, .. }) => { @@ -229,6 +204,18 @@ impl<'a, 'tcx> HashStable> for MonoItem<'tcx> { } } +impl<'tcx> fmt::Display for MonoItem<'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + MonoItem::Fn(instance) => write!(f, "fn {}", instance), + MonoItem::Static(def_id) => { + write!(f, "static {}", Instance::new(def_id, InternalSubsts::empty())) + } + MonoItem::GlobalAsm(..) => write!(f, "global_asm"), + } + } +} + pub struct CodegenUnit<'tcx> { /// A name for this CGU. Incremental compilation requires that /// name be unique amongst **all** crates. Therefore, it should diff --git a/src/librustc_middle/mir/predecessors.rs b/compiler/rustc_middle/src/mir/predecessors.rs similarity index 97% rename from src/librustc_middle/mir/predecessors.rs rename to compiler/rustc_middle/src/mir/predecessors.rs index b16a1d53ff..a8b7488335 100644 --- a/src/librustc_middle/mir/predecessors.rs +++ b/compiler/rustc_middle/src/mir/predecessors.rs @@ -33,7 +33,7 @@ impl PredecessorCache { self.cache = OnceCell::new(); } - /// Returns the the predecessor graph for this MIR. + /// Returns the predecessor graph for this MIR. #[inline] pub(super) fn compute( &self, diff --git a/src/librustc_middle/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs similarity index 100% rename from src/librustc_middle/mir/query.rs rename to compiler/rustc_middle/src/mir/query.rs diff --git a/src/librustc_middle/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs similarity index 99% rename from src/librustc_middle/mir/tcx.rs rename to compiler/rustc_middle/src/mir/tcx.rs index efcd41e5c1..b9e4f6fb12 100644 --- a/src/librustc_middle/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -33,7 +33,7 @@ impl<'tcx> PlaceTy<'tcx> { /// /// Note that the resulting type has not been normalized. pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: &Field) -> Ty<'tcx> { - let answer = match self.ty.kind { + let answer = match self.ty.kind() { ty::Adt(adt_def, substs) => { let variant_def = match self.variant_index { None => adt_def.non_enum_variant(), @@ -90,7 +90,7 @@ impl<'tcx> PlaceTy<'tcx> { PlaceTy::from_ty(self.ty.builtin_index().unwrap()) } ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match self.ty.kind { + PlaceTy::from_ty(match self.ty.kind() { ty::Slice(..) => self.ty, ty::Array(inner, _) if !from_end => tcx.mk_array(inner, (to - from) as u64), ty::Array(inner, size) if from_end => { diff --git a/src/librustc_middle/mir/terminator/mod.rs b/compiler/rustc_middle/src/mir/terminator/mod.rs similarity index 99% rename from src/librustc_middle/mir/terminator/mod.rs rename to compiler/rustc_middle/src/mir/terminator/mod.rs index fcfd648c2b..8909f02270 100644 --- a/src/librustc_middle/mir/terminator/mod.rs +++ b/compiler/rustc_middle/src/mir/terminator/mod.rs @@ -96,6 +96,8 @@ pub enum TerminatorKind<'tcx> { /// P <- V /// } /// ``` + /// + /// Note that DropAndReplace is eliminated as part of the `ElaborateDrops` pass. DropAndReplace { place: Place<'tcx>, value: Operand<'tcx>, diff --git a/src/librustc_middle/mir/traversal.rs b/compiler/rustc_middle/src/mir/traversal.rs similarity index 100% rename from src/librustc_middle/mir/traversal.rs rename to compiler/rustc_middle/src/mir/traversal.rs diff --git a/src/librustc_middle/mir/type_foldable.rs b/compiler/rustc_middle/src/mir/type_foldable.rs similarity index 99% rename from src/librustc_middle/mir/type_foldable.rs rename to compiler/rustc_middle/src/mir/type_foldable.rs index 6bb6abe028..ad2eae0298 100644 --- a/src/librustc_middle/mir/type_foldable.rs +++ b/compiler/rustc_middle/src/mir/type_foldable.rs @@ -175,7 +175,7 @@ impl<'tcx> TypeFoldable<'tcx> for Rvalue<'tcx> { use crate::mir::Rvalue::*; match *self { Use(ref op) => Use(op.fold_with(folder)), - Repeat(ref op, len) => Repeat(op.fold_with(folder), len), + Repeat(ref op, len) => Repeat(op.fold_with(folder), len.fold_with(folder)), ThreadLocalRef(did) => ThreadLocalRef(did.fold_with(folder)), Ref(region, bk, ref place) => { Ref(region.fold_with(folder), bk, place.fold_with(folder)) diff --git a/src/librustc_middle/mir/visit.rs b/compiler/rustc_middle/src/mir/visit.rs similarity index 99% rename from src/librustc_middle/mir/visit.rs rename to compiler/rustc_middle/src/mir/visit.rs index 6515ae31b4..a008bd5f75 100644 --- a/src/librustc_middle/mir/visit.rs +++ b/compiler/rustc_middle/src/mir/visit.rs @@ -1150,8 +1150,6 @@ pub enum NonUseContext { StorageDead, /// User type annotation assertions for NLL. AscribeUserTy, - /// Coverage code region and counter metadata. - Coverage, /// The data of an user variable, for debug info. VarDebugInfo, } diff --git a/src/librustc_middle/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs similarity index 93% rename from src/librustc_middle/query/mod.rs rename to compiler/rustc_middle/src/query/mod.rs index d6836d2ee3..d5b99ea4d2 100644 --- a/src/librustc_middle/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -42,48 +42,48 @@ rustc_queries! { } Other { - // 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. - // This is because the `hir_crate` query gives you access to all other items. - // To avoid this fate, do not call `tcx.hir().krate()`; instead, - // prefer wrappers like `tcx.visit_all_items_in_krate()`. + /// 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. + /// This is because the `hir_crate` query gives you access to all other items. + /// To avoid this fate, do not call `tcx.hir().krate()`; instead, + /// prefer wrappers like `tcx.visit_all_items_in_krate()`. query hir_crate(key: CrateNum) -> &'tcx Crate<'tcx> { eval_always no_hash desc { "get the crate HIR" } } - // The indexed HIR. This can be conveniently accessed by `tcx.hir()`. - // Avoid calling this query directly. + /// The indexed HIR. This can be conveniently accessed by `tcx.hir()`. + /// Avoid calling this query directly. query index_hir(_: CrateNum) -> &'tcx map::IndexedHir<'tcx> { eval_always no_hash desc { "index HIR" } } - // The items in a module. - // - // This can be conveniently accessed by `tcx.hir().visit_item_likes_in_module`. - // Avoid calling this query directly. + /// The items in a module. + /// + /// 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 desc { |tcx| "HIR module items in `{}`", tcx.def_path_str(key.to_def_id()) } } - // Gives access to the HIR node for the HIR owner `key`. - // - // This can be conveniently accessed by methods on `tcx.hir()`. - // Avoid calling this query directly. + /// Gives access to the HIR node for the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. query hir_owner(key: LocalDefId) -> Option<&'tcx crate::hir::Owner<'tcx>> { eval_always desc { |tcx| "HIR owner of `{}`", tcx.def_path_str(key.to_def_id()) } } - // Gives access to the HIR nodes and bodies inside the HIR owner `key`. - // - // This can be conveniently accessed by methods on `tcx.hir()`. - // Avoid calling this query directly. + /// Gives access to the HIR nodes and bodies inside the HIR owner `key`. + /// + /// This can be conveniently accessed by methods on `tcx.hir()`. + /// Avoid calling this query directly. query hir_owner_nodes(key: LocalDefId) -> Option<&'tcx crate::hir::OwnerNodes<'tcx>> { eval_always desc { |tcx| "HIR owner items in `{}`", tcx.def_path_str(key.to_def_id()) } @@ -173,6 +173,10 @@ rustc_queries! { desc { |tcx| "finding projection predicates for `{}`", tcx.def_path_str(key) } } + query projection_ty_from_predicates(key: (DefId, DefId)) -> Option> { + desc { |tcx| "finding projection type inside predicates of `{}`", tcx.def_path_str(key.0) } + } + query native_libraries(_: CrateNum) -> Lrc> { desc { "looking up the native libraries of a linked crate" } } @@ -240,6 +244,35 @@ rustc_queries! { no_hash } + /// Try to build an abstract representation of the given constant. + query mir_abstract_const( + key: DefId + ) -> 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( + key: (LocalDefId, DefId) + ) -> Result]>, ErrorReported> { + desc { + |tcx| + "building an abstract representation for the const argument {}", + tcx.def_path_str(key.0.to_def_id()), + } + } + + query try_unify_abstract_consts(key: ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>) + )) -> bool { + desc { + |tcx| "trying to unify the generic constants {} and {}", + tcx.def_path_str(key.0.0.did), tcx.def_path_str(key.1.0.did) + } + } + query mir_drops_elaborated_and_const_checked( key: ty::WithOptConstParam ) -> &'tcx Steal> { @@ -301,9 +334,9 @@ rustc_queries! { } TypeChecking { - // Erases regions from `ty` to yield a new type. - // Normally you would just use `tcx.erase_regions(&value)`, - // however, which uses this query as a kind of cache. + /// Erases regions from `ty` to yield a new type. + /// Normally you would just use `tcx.erase_regions(&value)`, + /// however, which uses this query as a kind of cache. query erase_regions_ty(ty: Ty<'tcx>) -> Ty<'tcx> { // This query is not expected to have input -- as a result, it // is not a good candidates for "replay" because it is essentially a @@ -424,10 +457,6 @@ rustc_queries! { desc { |tcx| "checking if item is promotable: `{}`", tcx.def_path_str(key) } } - query const_fn_is_allowed_fn_ptr(key: DefId) -> bool { - desc { |tcx| "checking if const fn allows `fn()` types: `{}`", tcx.def_path_str(key) } - } - /// Returns `true` if this is a foreign item (i.e., linked via `extern { ... }`). query is_foreign_item(key: DefId) -> bool { desc { |tcx| "checking if `{}` is a foreign item", tcx.def_path_str(key) } @@ -674,38 +703,31 @@ rustc_queries! { } Other { - /// Evaluates a constant without running sanity checks. + /// Evaluates a constant and returns the computed allocation. /// - /// **Do not use this** outside const eval. Const eval uses this to break query cycles - /// during validation. Please add a comment to every use site explaining why using - /// `const_eval_validated` isn't sufficient. The returned constant also isn't in a suitable - /// form to be used outside of const eval. - query const_eval_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalRawResult<'tcx> { - desc { |tcx| - "const-evaluating `{}`", - key.value.display(tcx) - } - } - - /// Results of evaluating const items or constants embedded in - /// other items (such as enum variant explicit discriminants). - /// - /// In contrast to `const_eval_raw` this performs some validation on the constant, and - /// returns a proper constant that is usable by the rest of the compiler. - /// - /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, - /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. - query const_eval_validated(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) - -> ConstEvalResult<'tcx> { + /// **Do not use this** directly, use the `tcx.eval_static_initializer` wrapper. + query eval_to_allocation_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToAllocationRawResult<'tcx> { desc { |tcx| "const-evaluating + checking `{}`", key.value.display(tcx) } - cache_on_disk_if(_, opt_result) { - // Only store results without errors - opt_result.map_or(true, |r| r.is_ok()) + cache_on_disk_if { true } + } + + /// Evaluates const items or anonymous constants + /// (such as enum variant explicit discriminants or array lengths) + /// into a representation suitable for the type system and const generics. + /// + /// **Do not use this** directly, use one of the following wrappers: `tcx.const_eval_poly`, + /// `tcx.const_eval_resolve`, `tcx.const_eval_instance`, or `tcx.const_eval_global_id`. + query eval_to_const_value_raw(key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>) + -> EvalToConstValueResult<'tcx> { + desc { |tcx| + "simplifying constant for the type system `{}`", + key.value.display(tcx) } + cache_on_disk_if { true } } /// Destructure a constant ADT or array into its variant index and its @@ -716,6 +738,14 @@ rustc_queries! { desc { "destructure constant" } } + /// Dereference a constant reference or raw pointer and turn the result into a constant + /// again. + query deref_const( + key: ty::ParamEnvAnd<'tcx, &'tcx ty::Const<'tcx>> + ) -> &'tcx ty::Const<'tcx> { + desc { "deref constant" } + } + query const_caller_location(key: (rustc_span::Symbol, u32, u32)) -> ConstValue<'tcx> { desc { "get a &core::panic::Location referring to a span" } } @@ -1251,6 +1281,11 @@ rustc_queries! { storage(ArenaCacheSelector<'tcx>) desc { "calculating the visible parent map" } } + query trimmed_def_paths(_: CrateNum) + -> FxHashMap { + storage(ArenaCacheSelector<'tcx>) + desc { "calculating trimmed def paths" } + } query missing_extern_crate_item(_: CrateNum) -> bool { eval_always desc { "seeing if we're missing an `extern crate` item for this crate" } @@ -1390,7 +1425,7 @@ rustc_queries! { } query evaluate_goal( - goal: traits::ChalkCanonicalGoal<'tcx> + goal: traits::CanonicalChalkEnvironmentAndGoal<'tcx> ) -> Result< &'tcx Canonical<'tcx, canonical::QueryResponse<'tcx, ()>>, NoSolution @@ -1505,7 +1540,7 @@ rustc_queries! { desc { "looking up supported target features" } } - // Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. + /// Get an estimate of the size of an InstanceDef based on its MIR for CGU partitioning. query instance_def_size_estimate(def: ty::InstanceDef<'tcx>) -> usize { desc { |tcx| "estimating size for `{}`", tcx.def_path_str(def.def_id()) } diff --git a/src/librustc_middle/tests.rs b/compiler/rustc_middle/src/tests.rs similarity index 100% rename from src/librustc_middle/tests.rs rename to compiler/rustc_middle/src/tests.rs diff --git a/src/librustc_middle/traits/chalk.rs b/compiler/rustc_middle/src/traits/chalk.rs similarity index 81% rename from src/librustc_middle/traits/chalk.rs rename to compiler/rustc_middle/src/traits/chalk.rs index 405af8cb24..d8507d08c1 100644 --- a/src/librustc_middle/traits/chalk.rs +++ b/compiler/rustc_middle/src/traits/chalk.rs @@ -6,14 +6,11 @@ //! interned Chalk types. use rustc_middle::mir::interpret::ConstValue; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_middle::ty::{self, AdtDef, TyCtxt}; use rustc_hir::def_id::DefId; use rustc_target::spec::abi::Abi; -use smallvec::SmallVec; - use std::cmp::Ordering; use std::fmt; use std::hash::{Hash, Hasher}; @@ -75,6 +72,7 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { type InternedQuantifiedWhereClauses = Vec>; type InternedVariableKinds = Vec>; type InternedCanonicalVarKinds = Vec>; + type InternedConstraints = Vec>>; type DefId = DefId; type InternedAdtId = &'tcx AdtDef; type Identifier = (); @@ -108,8 +106,42 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { application_ty: &chalk_ir::ApplicationTy, fmt: &mut fmt::Formatter<'_>, ) -> Option { - let chalk_ir::ApplicationTy { name, substitution } = application_ty; - Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned()))) + match application_ty.name { + chalk_ir::TypeName::Ref(mutbl) => { + let data = application_ty.substitution.interned(); + match (&**data[0].interned(), &**data[1].interned()) { + ( + chalk_ir::GenericArgData::Lifetime(lifetime), + chalk_ir::GenericArgData::Ty(ty), + ) => Some(match mutbl { + chalk_ir::Mutability::Not => write!(fmt, "(&{:?} {:?})", lifetime, ty), + chalk_ir::Mutability::Mut => write!(fmt, "(&{:?} mut {:?})", lifetime, ty), + }), + _ => unreachable!(), + } + } + chalk_ir::TypeName::Array => { + let data = application_ty.substitution.interned(); + match (&**data[0].interned(), &**data[1].interned()) { + (chalk_ir::GenericArgData::Ty(ty), chalk_ir::GenericArgData::Const(len)) => { + Some(write!(fmt, "[{:?}; {:?}]", ty, len)) + } + _ => unreachable!(), + } + } + chalk_ir::TypeName::Slice => { + let data = application_ty.substitution.interned(); + let ty = match &**data[0].interned() { + chalk_ir::GenericArgData::Ty(t) => t, + _ => unreachable!(), + }; + Some(write!(fmt, "[{:?}]", ty)) + } + _ => { + let chalk_ir::ApplicationTy { name, substitution } = application_ty; + Some(write!(fmt, "{:?}{:?}", name, chalk_ir::debug::Angle(substitution.interned()))) + } + } } fn debug_substitution( @@ -321,37 +353,30 @@ impl<'tcx> chalk_ir::interner::Interner for RustInterner<'tcx> { ) -> &'a [chalk_ir::CanonicalVarKind] { canonical_var_kinds } + + fn intern_constraints( + &self, + data: impl IntoIterator>, E>>, + ) -> Result { + data.into_iter().collect::, _>>() + } + + fn constraints_data<'a>( + &self, + constraints: &'a Self::InternedConstraints, + ) -> &'a [chalk_ir::InEnvironment>] { + constraints + } } impl<'tcx> chalk_ir::interner::HasInterner for RustInterner<'tcx> { type Interner = Self; } -#[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] -pub enum ChalkEnvironmentClause<'tcx> { - /// A normal rust `ty::Predicate` in the environment. - Predicate(ty::Predicate<'tcx>), - /// A special clause in the environment that gets lowered to - /// `chalk_ir::FromEnv::Ty`. - TypeFromEnv(Ty<'tcx>), -} - -impl<'tcx> TypeFoldable<'tcx> for &'tcx ty::List> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let v = self.iter().map(|t| t.fold_with(folder)).collect::>(); - folder.tcx().intern_chalk_environment_clause_list(&v) - } - - fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.iter().any(|t| t.visit_with(visitor)) - } -} -/// We have to elaborate the environment of a chalk goal *before* -/// canonicalization. This type wraps the predicate and the elaborated -/// environment. +/// A chalk environment and goal. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, HashStable, TypeFoldable)] pub struct ChalkEnvironmentAndGoal<'tcx> { - pub environment: &'tcx ty::List>, + pub environment: &'tcx ty::List>, pub goal: ty::Predicate<'tcx>, } diff --git a/src/librustc_middle/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs similarity index 89% rename from src/librustc_middle/traits/mod.rs rename to compiler/rustc_middle/src/traits/mod.rs index f86403fa50..1dd6d590d9 100644 --- a/src/librustc_middle/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -26,14 +26,11 @@ use std::rc::Rc; pub use self::select::{EvaluationCache, EvaluationResult, OverflowError, SelectionCache}; -pub type ChalkCanonicalGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; +pub type CanonicalChalkEnvironmentAndGoal<'tcx> = Canonical<'tcx, ChalkEnvironmentAndGoal<'tcx>>; -pub use self::ImplSource::*; pub use self::ObligationCauseCode::*; -pub use self::chalk::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, RustInterner as ChalkRustInterner, -}; +pub use self::chalk::{ChalkEnvironmentAndGoal, RustInterner as ChalkRustInterner}; /// Depending on the stage of compilation, we want projection to be /// more or less conservative. @@ -350,13 +347,16 @@ pub struct MatchExpressionArmCause<'tcx> { pub prior_arms: Vec, pub last_ty: Ty<'tcx>, pub scrut_hir_id: hir::HirId, + pub opt_suggest_box_span: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct IfExpressionCause { pub then: Span, + pub else_sp: Span, pub outer: Option, pub semicolon: Option, + pub opt_suggest_box_span: Option, } #[derive(Clone, Debug, PartialEq, Eq, Hash, Lift)] @@ -417,10 +417,10 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; /// /// // Case B: ImplSource must be provided by caller. This applies when /// // type is a type parameter. -/// param.clone(); // ImplSourceParam +/// param.clone(); // ImplSource::Param /// /// // Case C: A mix of cases A and B. -/// mixed.clone(); // ImplSource(Impl_1, [ImplSourceParam]) +/// mixed.clone(); // ImplSource(Impl_1, [ImplSource::Param]) /// } /// ``` /// @@ -430,72 +430,72 @@ pub type SelectionResult<'tcx, T> = Result, SelectionError<'tcx>>; #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, TypeFoldable, Lift)] pub enum ImplSource<'tcx, N> { /// ImplSource identifying a particular impl. - ImplSourceUserDefined(ImplSourceUserDefinedData<'tcx, N>), + UserDefined(ImplSourceUserDefinedData<'tcx, N>), /// ImplSource for auto trait implementations. /// This carries the information and nested obligations with regards /// to an auto implementation for a trait `Trait`. The nested obligations /// ensure the trait implementation holds for all the constituent types. - ImplSourceAutoImpl(ImplSourceAutoImplData), + AutoImpl(ImplSourceAutoImplData), /// Successful resolution to an obligation provided by the caller /// for some type parameter. The `Vec` represents the /// obligations incurred from normalizing the where-clause (if /// any). - ImplSourceParam(Vec), + Param(Vec), /// Virtual calls through an object. - ImplSourceObject(ImplSourceObjectData<'tcx, N>), + Object(ImplSourceObjectData<'tcx, N>), /// Successful resolution for a builtin trait. - ImplSourceBuiltin(ImplSourceBuiltinData), + Builtin(ImplSourceBuiltinData), /// ImplSource automatically generated for a closure. The `DefId` is the ID - /// of the closure expression. This is a `ImplSourceUserDefined` in spirit, but the + /// of the closure expression. This is a `ImplSource::UserDefined` in spirit, but the /// impl is generated by the compiler and does not appear in the source. - ImplSourceClosure(ImplSourceClosureData<'tcx, N>), + Closure(ImplSourceClosureData<'tcx, N>), /// Same as above, but for a function pointer type with the given signature. - ImplSourceFnPointer(ImplSourceFnPointerData<'tcx, N>), + FnPointer(ImplSourceFnPointerData<'tcx, N>), /// ImplSource for a builtin `DeterminantKind` trait implementation. - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData), + DiscriminantKind(ImplSourceDiscriminantKindData), /// ImplSource automatically generated for a generator. - ImplSourceGenerator(ImplSourceGeneratorData<'tcx, N>), + Generator(ImplSourceGeneratorData<'tcx, N>), /// ImplSource for a trait alias. - ImplSourceTraitAlias(ImplSourceTraitAliasData<'tcx, N>), + TraitAlias(ImplSourceTraitAliasData<'tcx, N>), } impl<'tcx, N> ImplSource<'tcx, N> { pub fn nested_obligations(self) -> Vec { match self { - ImplSourceUserDefined(i) => i.nested, - ImplSourceParam(n) => n, - ImplSourceBuiltin(i) => i.nested, - ImplSourceAutoImpl(d) => d.nested, - ImplSourceClosure(c) => c.nested, - ImplSourceGenerator(c) => c.nested, - ImplSourceObject(d) => d.nested, - ImplSourceFnPointer(d) => d.nested, - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(), - ImplSourceTraitAlias(d) => d.nested, + ImplSource::UserDefined(i) => i.nested, + ImplSource::Param(n) => n, + ImplSource::Builtin(i) => i.nested, + ImplSource::AutoImpl(d) => d.nested, + ImplSource::Closure(c) => c.nested, + ImplSource::Generator(c) => c.nested, + ImplSource::Object(d) => d.nested, + ImplSource::FnPointer(d) => d.nested, + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => Vec::new(), + ImplSource::TraitAlias(d) => d.nested, } } pub fn borrow_nested_obligations(&self) -> &[N] { match &self { - ImplSourceUserDefined(i) => &i.nested[..], - ImplSourceParam(n) => &n[..], - ImplSourceBuiltin(i) => &i.nested[..], - ImplSourceAutoImpl(d) => &d.nested[..], - ImplSourceClosure(c) => &c.nested[..], - ImplSourceGenerator(c) => &c.nested[..], - ImplSourceObject(d) => &d.nested[..], - ImplSourceFnPointer(d) => &d.nested[..], - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => &[], - ImplSourceTraitAlias(d) => &d.nested[..], + ImplSource::UserDefined(i) => &i.nested[..], + ImplSource::Param(n) => &n[..], + ImplSource::Builtin(i) => &i.nested[..], + ImplSource::AutoImpl(d) => &d.nested[..], + ImplSource::Closure(c) => &c.nested[..], + ImplSource::Generator(c) => &c.nested[..], + ImplSource::Object(d) => &d.nested[..], + ImplSource::FnPointer(d) => &d.nested[..], + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => &[], + ImplSource::TraitAlias(d) => &d.nested[..], } } @@ -504,42 +504,42 @@ impl<'tcx, N> ImplSource<'tcx, N> { F: FnMut(N) -> M, { match self { - ImplSourceUserDefined(i) => ImplSourceUserDefined(ImplSourceUserDefinedData { + ImplSource::UserDefined(i) => ImplSource::UserDefined(ImplSourceUserDefinedData { impl_def_id: i.impl_def_id, substs: i.substs, nested: i.nested.into_iter().map(f).collect(), }), - ImplSourceParam(n) => ImplSourceParam(n.into_iter().map(f).collect()), - ImplSourceBuiltin(i) => ImplSourceBuiltin(ImplSourceBuiltinData { + ImplSource::Param(n) => ImplSource::Param(n.into_iter().map(f).collect()), + ImplSource::Builtin(i) => ImplSource::Builtin(ImplSourceBuiltinData { nested: i.nested.into_iter().map(f).collect(), }), - ImplSourceObject(o) => ImplSourceObject(ImplSourceObjectData { + ImplSource::Object(o) => ImplSource::Object(ImplSourceObjectData { upcast_trait_ref: o.upcast_trait_ref, vtable_base: o.vtable_base, nested: o.nested.into_iter().map(f).collect(), }), - ImplSourceAutoImpl(d) => ImplSourceAutoImpl(ImplSourceAutoImplData { + ImplSource::AutoImpl(d) => ImplSource::AutoImpl(ImplSourceAutoImplData { trait_def_id: d.trait_def_id, nested: d.nested.into_iter().map(f).collect(), }), - ImplSourceClosure(c) => ImplSourceClosure(ImplSourceClosureData { + ImplSource::Closure(c) => ImplSource::Closure(ImplSourceClosureData { closure_def_id: c.closure_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - ImplSourceGenerator(c) => ImplSourceGenerator(ImplSourceGeneratorData { + ImplSource::Generator(c) => ImplSource::Generator(ImplSourceGeneratorData { generator_def_id: c.generator_def_id, substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), - ImplSourceFnPointer(p) => ImplSourceFnPointer(ImplSourceFnPointerData { + ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData { fn_ty: p.fn_ty, nested: p.nested.into_iter().map(f).collect(), }), - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) => { - ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData) + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) => { + ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) } - ImplSourceTraitAlias(d) => ImplSourceTraitAlias(ImplSourceTraitAliasData { + ImplSource::TraitAlias(d) => ImplSource::TraitAlias(ImplSourceTraitAliasData { alias_def_id: d.alias_def_id, substs: d.substs, nested: d.nested.into_iter().map(f).collect(), diff --git a/src/librustc_middle/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs similarity index 77% rename from src/librustc_middle/traits/query.rs rename to compiler/rustc_middle/src/traits/query.rs index 4b7663e9ad..f9cadb3bb2 100644 --- a/src/librustc_middle/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -190,74 +190,6 @@ impl<'tcx> FromIterator> for DtorckConstraint<'tcx> { } } -/// This returns true if the type `ty` is "trivial" for -/// dropck-outlives -- that is, if it doesn't require any types to -/// outlive. This is similar but not *quite* the same as the -/// `needs_drop` test in the compiler already -- that is, for every -/// type T for which this function return true, needs-drop would -/// return `false`. But the reverse does not hold: in particular, -/// `needs_drop` returns false for `PhantomData`, but it is not -/// trivial for dropck-outlives. -/// -/// Note also that `needs_drop` requires a "global" type (i.e., one -/// with erased regions), but this function does not. -pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { - // None of these types have a destructor and hence they do not - // require anything in particular to outlive the dtor's - // execution. - ty::Infer(ty::FreshIntTy(_)) - | ty::Infer(ty::FreshFloatTy(_)) - | ty::Bool - | ty::Int(_) - | ty::Uint(_) - | ty::Float(_) - | ty::Never - | ty::FnDef(..) - | ty::FnPtr(_) - | ty::Char - | ty::GeneratorWitness(..) - | ty::RawPtr(_) - | ty::Ref(..) - | ty::Str - | ty::Foreign(..) - | ty::Error(_) => true, - - // [T; N] and [T] have same properties as T. - ty::Array(ty, _) | ty::Slice(ty) => trivial_dropck_outlives(tcx, ty), - - // (T1..Tn) and closures have same properties as T1..Tn -- - // check if *any* of those are trivial. - ty::Tuple(ref tys) => tys.iter().all(|t| trivial_dropck_outlives(tcx, t.expect_ty())), - ty::Closure(_, ref substs) => { - substs.as_closure().upvar_tys().all(|t| trivial_dropck_outlives(tcx, t)) - } - - ty::Adt(def, _) => { - if Some(def.did) == tcx.lang_items().manually_drop() { - // `ManuallyDrop` never has a dtor. - true - } else { - // Other types might. Moreover, PhantomData doesn't - // have a dtor, but it is considered to own its - // content, so it is non-trivial. Unions can have `impl Drop`, - // and hence are non-trivial as well. - false - } - } - - // The following *might* require a destructor: needs deeper inspection. - ty::Dynamic(..) - | ty::Projection(..) - | ty::Param(_) - | ty::Opaque(..) - | ty::Placeholder(..) - | ty::Infer(_) - | ty::Bound(..) - | ty::Generator(..) => false, - } -} - #[derive(Debug, HashStable)] pub struct CandidateStep<'tcx> { pub self_ty: Canonical<'tcx, QueryResponse<'tcx, Ty<'tcx>>>, diff --git a/src/librustc_middle/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs similarity index 100% rename from src/librustc_middle/traits/select.rs rename to compiler/rustc_middle/src/traits/select.rs diff --git a/src/librustc_middle/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs similarity index 100% rename from src/librustc_middle/traits/specialization_graph.rs rename to compiler/rustc_middle/src/traits/specialization_graph.rs diff --git a/src/librustc_middle/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs similarity index 77% rename from src/librustc_middle/traits/structural_impls.rs rename to compiler/rustc_middle/src/traits/structural_impls.rs index d73fc628ce..b8f6675b8e 100644 --- a/src/librustc_middle/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -7,25 +7,25 @@ use std::fmt; impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - super::ImplSourceUserDefined(ref v) => write!(f, "{:?}", v), + super::ImplSource::UserDefined(ref v) => write!(f, "{:?}", v), - super::ImplSourceAutoImpl(ref t) => write!(f, "{:?}", t), + super::ImplSource::AutoImpl(ref t) => write!(f, "{:?}", t), - super::ImplSourceClosure(ref d) => write!(f, "{:?}", d), + super::ImplSource::Closure(ref d) => write!(f, "{:?}", d), - super::ImplSourceGenerator(ref d) => write!(f, "{:?}", d), + super::ImplSource::Generator(ref d) => write!(f, "{:?}", d), - super::ImplSourceFnPointer(ref d) => write!(f, "ImplSourceFnPointer({:?})", d), + super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d), - super::ImplSourceDiscriminantKind(ref d) => write!(f, "{:?}", d), + super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d), - super::ImplSourceObject(ref d) => write!(f, "{:?}", d), + super::ImplSource::Object(ref d) => write!(f, "{:?}", d), - super::ImplSourceParam(ref n) => write!(f, "ImplSourceParam({:?})", n), + super::ImplSource::Param(ref n) => write!(f, "ImplSourceParamData({:?})", n), - super::ImplSourceBuiltin(ref d) => write!(f, "{:?}", d), + super::ImplSource::Builtin(ref d) => write!(f, "{:?}", d), - super::ImplSourceTraitAlias(ref d) => write!(f, "{:?}", d), + super::ImplSource::TraitAlias(ref d) => write!(f, "{:?}", d), } } } @@ -96,7 +96,7 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceTraitAliasData<'tcx, fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, - "ImplSourceTraitAlias(alias_def_id={:?}, substs={:?}, nested={:?})", + "ImplSourceTraitAliasData(alias_def_id={:?}, substs={:?}, nested={:?})", self.alias_def_id, self.substs, self.nested ) } diff --git a/src/librustc_middle/ty/_match.rs b/compiler/rustc_middle/src/ty/_match.rs similarity index 98% rename from src/librustc_middle/ty/_match.rs rename to compiler/rustc_middle/src/ty/_match.rs index 4693a2f66f..27bccc0bca 100644 --- a/src/librustc_middle/ty/_match.rs +++ b/compiler/rustc_middle/src/ty/_match.rs @@ -67,7 +67,7 @@ impl TypeRelation<'tcx> for Match<'tcx> { return Ok(a); } - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { ( _, &ty::Infer(ty::FreshTy(_)) diff --git a/src/librustc_middle/ty/adjustment.rs b/compiler/rustc_middle/src/ty/adjustment.rs similarity index 98% rename from src/librustc_middle/ty/adjustment.rs rename to compiler/rustc_middle/src/ty/adjustment.rs index 6a9bb8d6c2..46ef5ff7dd 100644 --- a/src/librustc_middle/ty/adjustment.rs +++ b/compiler/rustc_middle/src/ty/adjustment.rs @@ -4,6 +4,7 @@ use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; use rustc_macros::HashStable; +use rustc_span::Span; #[derive(Clone, Copy, Debug, PartialEq, Eq, TyEncodable, TyDecodable, HashStable)] pub enum PointerCast { @@ -113,6 +114,9 @@ pub enum Adjust<'tcx> { pub struct OverloadedDeref<'tcx> { pub region: ty::Region<'tcx>, pub mutbl: hir::Mutability, + /// The `Span` associated with the field access or method call + /// that triggered this overloaded deref. + pub span: Span, } impl<'tcx> OverloadedDeref<'tcx> { diff --git a/src/librustc_middle/ty/binding.rs b/compiler/rustc_middle/src/ty/binding.rs similarity index 100% rename from src/librustc_middle/ty/binding.rs rename to compiler/rustc_middle/src/ty/binding.rs diff --git a/src/librustc_middle/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs similarity index 98% rename from src/librustc_middle/ty/cast.rs rename to compiler/rustc_middle/src/ty/cast.rs index 79a3008c36..b47d9c50e1 100644 --- a/src/librustc_middle/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -50,7 +50,7 @@ impl<'tcx> CastTy<'tcx> { /// Returns `Some` for integral/pointer casts. /// casts like unsizing casts will return `None` pub fn from_ty(t: Ty<'tcx>) -> Option> { - match t.kind { + match *t.kind() { ty::Bool => Some(CastTy::Int(IntTy::Bool)), ty::Char => Some(CastTy::Int(IntTy::Char)), ty::Int(_) => Some(CastTy::Int(IntTy::I)), diff --git a/src/librustc_middle/ty/codec.rs b/compiler/rustc_middle/src/ty/codec.rs similarity index 95% rename from src/librustc_middle/ty/codec.rs rename to compiler/rustc_middle/src/ty/codec.rs index 291648869f..8ea34f9161 100644 --- a/src/librustc_middle/ty/codec.rs +++ b/compiler/rustc_middle/src/ty/codec.rs @@ -36,8 +36,10 @@ pub trait EncodableWithShorthand<'tcx, E: TyEncoder<'tcx>>: Copy + Eq + Hash { #[allow(rustc::usage_of_ty_tykind)] impl<'tcx, E: TyEncoder<'tcx>> EncodableWithShorthand<'tcx, E> for Ty<'tcx> { type Variant = ty::TyKind<'tcx>; + + #[inline] fn variant(&self) -> &Self::Variant { - &self.kind + self.kind() } } @@ -355,6 +357,26 @@ impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [(ty::Predicate<'tcx>, } } +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::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()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + +impl<'tcx, D: TyDecoder<'tcx>> RefDecodable<'tcx, D> for [mir::abstract_const::NodeId] { + fn decode(decoder: &mut D) -> Result<&'tcx Self, D::Error> { + Ok(decoder.tcx().arena.alloc_from_iter( + (0..decoder.read_usize()?) + .map(|_| Decodable::decode(decoder)) + .collect::, _>>()?, + )) + } +} + impl_decodable_via_ref! { &'tcx ty::TypeckResults<'tcx>, &'tcx ty::List>, diff --git a/src/librustc_middle/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs similarity index 100% rename from src/librustc_middle/ty/consts.rs rename to compiler/rustc_middle/src/ty/consts.rs diff --git a/src/librustc_middle/ty/consts/int.rs b/compiler/rustc_middle/src/ty/consts/int.rs similarity index 100% rename from src/librustc_middle/ty/consts/int.rs rename to compiler/rustc_middle/src/ty/consts/int.rs diff --git a/src/librustc_middle/ty/consts/kind.rs b/compiler/rustc_middle/src/ty/consts/kind.rs similarity index 100% rename from src/librustc_middle/ty/consts/kind.rs rename to compiler/rustc_middle/src/ty/consts/kind.rs diff --git a/src/librustc_middle/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs similarity index 97% rename from src/librustc_middle/ty/context.rs rename to compiler/rustc_middle/src/ty/context.rs index 18ae744cb1..22c3fd37be 100644 --- a/src/librustc_middle/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -34,6 +34,7 @@ use rustc_data_structures::stable_hasher::{ hash_stable_hashmap, HashStable, StableHasher, StableVec, }; use rustc_data_structures::sync::{self, Lock, Lrc, WorkerLocal}; +use rustc_data_structures::unhash::UnhashMap; use rustc_errors::ErrorReported; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -65,8 +66,8 @@ use std::mem; use std::ops::{Bound, Deref}; use std::sync::Arc; -/// A type that is not publicly constructable. This prevents people from making `TyKind::Error` -/// except through `tcx.err*()`, which are in this module. +/// A type that is not publicly constructable. This prevents people from making [`TyKind::Error`]s +/// except through the error-reporting functions on a [`tcx`][TyCtxt]. #[derive(Copy, Clone, Debug, Eq, Hash, PartialEq, PartialOrd, Ord)] #[derive(TyEncodable, TyDecodable, HashStable)] pub struct DelaySpanBugEmitted(()); @@ -90,8 +91,6 @@ pub struct CtxtInterners<'tcx> { projs: InternedSet<'tcx, List>, place_elems: InternedSet<'tcx, List>>, const_: InternedSet<'tcx, Const<'tcx>>, - - chalk_environment_clause_list: InternedSet<'tcx, List>>, } impl<'tcx> CtxtInterners<'tcx> { @@ -109,7 +108,6 @@ impl<'tcx> CtxtInterners<'tcx> { projs: Default::default(), place_elems: Default::default(), const_: Default::default(), - chalk_environment_clause_list: Default::default(), } } @@ -758,10 +756,10 @@ impl CanonicalUserType<'tcx> { user_substs.substs.iter().zip(BoundVar::new(0)..).all(|(kind, cvar)| { match kind.unpack() { - GenericArgKind::Type(ty) => match ty.kind { + GenericArgKind::Type(ty) => match ty.kind() { ty::Bound(debruijn, b) => { // We only allow a `ty::INNERMOST` index in substitutions. - assert_eq!(debruijn, ty::INNERMOST); + assert_eq!(*debruijn, ty::INNERMOST); cvar == b.var } _ => false, @@ -935,7 +933,7 @@ pub struct GlobalCtxt<'tcx> { /// A map from `DefPathHash` -> `DefId`. Includes `DefId`s from the local crate /// as well as all upstream crates. Only populated in incremental mode. - pub def_path_hash_to_def_id: Option>, + pub def_path_hash_to_def_id: Option>, pub queries: query::Queries<'tcx>, @@ -943,7 +941,7 @@ pub struct GlobalCtxt<'tcx> { maybe_unused_extern_crates: Vec<(LocalDefId, Span)>, /// A map of glob use to a set of names it actually imports. Currently only /// used in save-analysis. - glob_map: FxHashMap>, + pub(crate) 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. pub extern_prelude: FxHashMap, @@ -1104,7 +1102,7 @@ impl<'tcx> TyCtxt<'tcx> { let def_path_hash_to_def_id = if s.opts.build_dep_graph() { let capacity = definitions.def_path_table().num_def_ids() + crates.iter().map(|cnum| cstore.num_def_ids(*cnum)).sum::(); - let mut map = FxHashMap::with_capacity_and_hasher(capacity, Default::default()); + let mut map = UnhashMap::with_capacity_and_hasher(capacity, Default::default()); map.extend(definitions.def_path_table().all_def_path_hashes_and_def_ids(LOCAL_CRATE)); for cnum in &crates { @@ -1181,7 +1179,7 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_const(ty::Const { val: ty::ConstKind::Error(DelaySpanBugEmitted(())), ty }) } - pub fn consider_optimizing String>(&self, msg: T) -> bool { + pub fn consider_optimizing String>(self, msg: T) -> bool { let cname = self.crate_name(LOCAL_CRATE).as_str(); self.sess.consider_optimizing(&cname, msg) } @@ -1274,7 +1272,7 @@ impl<'tcx> TyCtxt<'tcx> { // Don't print the whole crate disambiguator. That's just // annoying in debug output. &(crate_disambiguator.to_fingerprint().to_hex())[..4], - self.def_path(def_id).to_string_no_crate() + self.def_path(def_id).to_string_no_crate_verbose() ) } @@ -1405,7 +1403,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Returns the `DefId` and the `BoundRegion` corresponding to the given region. - pub fn is_suitable_region(&self, region: Region<'tcx>) -> Option { + pub fn is_suitable_region(self, region: Region<'tcx>) -> Option { let (suitable_region_binding_scope, bound_region) = match *region { ty::ReFree(ref free_region) => { (free_region.scope.expect_local(), free_region.bound_region) @@ -1435,7 +1433,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Given a `DefId` for an `fn`, return all the `dyn` and `impl` traits in its return type. pub fn return_type_impl_or_dyn_traits( - &self, + self, scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); @@ -1481,7 +1479,7 @@ impl<'tcx> TyCtxt<'tcx> { v.0 } - pub fn return_type_impl_trait(&self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { + pub fn return_type_impl_trait(self, scope_def_id: LocalDefId) -> Option<(Ty<'tcx>, Span)> { // HACK: `type_of_def_id()` will fail on these (#55796), so return `None`. let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); match self.hir().get(hir_id) { @@ -1497,9 +1495,9 @@ impl<'tcx> TyCtxt<'tcx> { } let ret_ty = self.type_of(scope_def_id); - match ret_ty.kind { + match ret_ty.kind() { ty::FnDef(_, _) => { - let sig = ret_ty.fn_sig(*self); + let sig = ret_ty.fn_sig(self); let output = self.erase_late_bound_regions(&sig.output()); if output.is_impl_trait() { let fn_decl = self.hir().fn_decl_by_hir_id(hir_id).unwrap(); @@ -1513,7 +1511,7 @@ impl<'tcx> TyCtxt<'tcx> { } // Checks if the bound region is in Impl Item. - pub fn is_bound_region_in_impl_item(&self, suitable_region_binding_scope: LocalDefId) -> bool { + pub fn is_bound_region_in_impl_item(self, suitable_region_binding_scope: LocalDefId) -> bool { let container_id = self.associated_item(suitable_region_binding_scope.to_def_id()).container.id(); if self.impl_trait_ref(container_id).is_some() { @@ -1530,21 +1528,21 @@ impl<'tcx> TyCtxt<'tcx> { /// Determines whether identifiers in the assembly have strict naming rules. /// Currently, only NVPTX* targets need it. - pub fn has_strict_asm_symbol_naming(&self) -> bool { + pub fn has_strict_asm_symbol_naming(self) -> bool { self.sess.target.target.arch.contains("nvptx") } /// Returns `&'static core::panic::Location<'static>`. - pub fn caller_location_ty(&self) -> Ty<'tcx> { + pub fn caller_location_ty(self) -> Ty<'tcx> { self.mk_imm_ref( self.lifetimes.re_static, self.type_of(self.require_lang_item(LangItem::PanicLocation, None)) - .subst(*self, self.mk_substs([self.lifetimes.re_static.into()].iter())), + .subst(self, self.mk_substs([self.lifetimes.re_static.into()].iter())), ) } /// Returns a displayable description and article for the given `def_id` (e.g. `("a", "struct")`). - pub fn article_and_description(&self, def_id: DefId) -> (&'static str, &'static str) { + pub fn article_and_description(self, def_id: DefId) -> (&'static str, &'static str) { match self.def_kind(def_id) { DefKind::Generator => match self.generator_kind(def_id).unwrap() { rustc_hir::GeneratorKind::Async(..) => ("an", "async closure"), @@ -1821,15 +1819,15 @@ macro_rules! sty_debug_print { let shards = tcx.interners.type_.lock_shards(); let types = shards.iter().flat_map(|shard| shard.keys()); for &Interned(t) in types { - let variant = match t.kind { + let variant = match t.kind() { ty::Bool | ty::Char | ty::Int(..) | ty::Uint(..) | ty::Float(..) | ty::Str | ty::Never => continue, ty::Error(_) => /* unimportant */ continue, $(ty::$variant(..) => &mut $variant,)* }; - let lt = t.flags.intersects(ty::TypeFlags::HAS_RE_INFER); - let ty = t.flags.intersects(ty::TypeFlags::HAS_TY_INFER); - let ct = t.flags.intersects(ty::TypeFlags::HAS_CT_INFER); + let lt = t.flags().intersects(ty::TypeFlags::HAS_RE_INFER); + let ty = t.flags().intersects(ty::TypeFlags::HAS_TY_INFER); + let ct = t.flags().intersects(ty::TypeFlags::HAS_CT_INFER); variant.total += 1; total.total += 1; @@ -1930,7 +1928,7 @@ impl<'tcx, T: 'tcx + ?Sized> IntoPointer for Interned<'tcx, T> { // N.B., an `Interned` compares and hashes as a `TyKind`. impl<'tcx> PartialEq for Interned<'tcx, TyS<'tcx>> { fn eq(&self, other: &Interned<'tcx, TyS<'tcx>>) -> bool { - self.0.kind == other.0.kind + self.0.kind() == other.0.kind() } } @@ -1938,14 +1936,14 @@ impl<'tcx> Eq for Interned<'tcx, TyS<'tcx>> {} impl<'tcx> Hash for Interned<'tcx, TyS<'tcx>> { fn hash(&self, s: &mut H) { - self.0.kind.hash(s) + self.0.kind().hash(s) } } #[allow(rustc::usage_of_ty_tykind)] impl<'tcx> Borrow> for Interned<'tcx, TyS<'tcx>> { fn borrow<'a>(&'a self) -> &'a TyKind<'tcx> { - &self.0.kind + &self.0.kind() } } // N.B., an `Interned` compares and hashes as a `PredicateKind`. @@ -2040,7 +2038,7 @@ direct_interners! { } macro_rules! slice_interners { - ($($field:ident: $method:ident($ty:ty)),+) => ( + ($($field:ident: $method:ident($ty:ty)),+ $(,)?) => ( $(impl<'tcx> TyCtxt<'tcx> { pub fn $method(self, v: &[$ty]) -> &'tcx List<$ty> { self.interners.$field.intern_ref(v, || { @@ -2059,8 +2057,6 @@ slice_interners!( predicates: _intern_predicates(Predicate<'tcx>), projs: _intern_projs(ProjectionKind), place_elems: _intern_place_elems(PlaceElem<'tcx>), - chalk_environment_clause_list: - _intern_chalk_environment_clause_list(traits::ChalkEnvironmentClause<'tcx>) ); impl<'tcx> TyCtxt<'tcx> { @@ -2085,7 +2081,7 @@ impl<'tcx> TyCtxt<'tcx> { unsafety: hir::Unsafety, ) -> PolyFnSig<'tcx> { sig.map_bound(|s| { - let params_iter = match s.inputs()[0].kind { + let params_iter = match s.inputs()[0].kind() { ty::Tuple(params) => params.into_iter().map(|k| k.expect_ty()), _ => bug!(), }; @@ -2423,7 +2419,7 @@ impl<'tcx> TyCtxt<'tcx> { eps: &[ExistentialPredicate<'tcx>], ) -> &'tcx List> { assert!(!eps.is_empty()); - assert!(eps.windows(2).all(|w| w[0].stable_cmp(self, &w[1]) != Ordering::Greater)); + assert!(eps.array_windows().all(|[a, b]| a.stable_cmp(self, b) != Ordering::Greater)); self._intern_existential_predicates(eps) } @@ -2459,13 +2455,6 @@ impl<'tcx> TyCtxt<'tcx> { if ts.is_empty() { List::empty() } else { self._intern_canonical_var_infos(ts) } } - pub fn intern_chalk_environment_clause_list( - self, - ts: &[traits::ChalkEnvironmentClause<'tcx>], - ) -> &'tcx List> { - if ts.is_empty() { List::empty() } else { self._intern_chalk_environment_clause_list(ts) } - } - pub fn mk_fn_sig( self, inputs: I, @@ -2523,18 +2512,6 @@ impl<'tcx> TyCtxt<'tcx> { self.mk_substs(iter::once(self_ty.into()).chain(rest.iter().cloned())) } - pub fn mk_chalk_environment_clause_list< - I: InternAs< - [traits::ChalkEnvironmentClause<'tcx>], - &'tcx List>, - >, - >( - self, - iter: I, - ) -> I::Output { - iter.intern_with(|xs| self.intern_chalk_environment_clause_list(xs)) - } - /// Walks upwards from `id` to find a node which might change lint levels with attributes. /// It stops at `bound` and just returns it if reached. pub fn maybe_lint_level_root_bounded(self, mut id: HirId, bound: HirId) -> HirId { diff --git a/src/librustc_middle/ty/diagnostics.rs b/compiler/rustc_middle/src/ty/diagnostics.rs similarity index 78% rename from src/librustc_middle/ty/diagnostics.rs rename to compiler/rustc_middle/src/ty/diagnostics.rs index b22727bdd7..715319747e 100644 --- a/src/librustc_middle/ty/diagnostics.rs +++ b/compiler/rustc_middle/src/ty/diagnostics.rs @@ -11,7 +11,7 @@ use rustc_hir::{QPath, TyKind, WhereBoundPredicate, WherePredicate}; impl<'tcx> TyS<'tcx> { /// Similar to `TyS::is_primitive`, but also considers inferred numeric values to be primitive. pub fn is_primitive_ty(&self) -> bool { - match self.kind { + match self.kind() { Bool | Char | Str @@ -31,7 +31,7 @@ impl<'tcx> TyS<'tcx> { /// Whether the type is succinctly representable as a type instead of just referred to with a /// description in error messages. This is used in the main error message. pub fn is_simple_ty(&self) -> bool { - match self.kind { + match self.kind() { Bool | Char | Str @@ -55,7 +55,7 @@ impl<'tcx> TyS<'tcx> { /// `is_simple_ty` includes, it also accepts ADTs with no type arguments and references to /// ADTs with no type arguments. pub fn is_simple_text(&self) -> bool { - match self.kind { + match self.kind() { Adt(_, substs) => substs.types().next().is_none(), Ref(_, ty, _) => ty.is_simple_text(), _ => self.is_simple_ty(), @@ -64,7 +64,7 @@ impl<'tcx> TyS<'tcx> { /// Whether the type can be safely suggested during error recovery. pub fn is_suggestable(&self) -> bool { - match self.kind { + match self.kind() { Opaque(..) | FnDef(..) | FnPtr(..) | Dynamic(..) | Closure(..) | Infer(..) | Projection(..) => false, _ => true, @@ -202,33 +202,59 @@ pub fn suggest_constraining_type_param( // Suggestion: // fn foo(t: T) where T: Foo, T: Bar {... } // - insert: `, T: Zar` + // + // Additionally, there may be no `where` clause whatsoever in the case that this was + // reached because the generic parameter has a default: + // + // Message: + // trait Foo {... } + // - help: consider further restricting this type parameter with `where T: Zar` + // + // Suggestion: + // trait Foo where T: Zar {... } + // - insert: `where T: Zar` - let mut param_spans = Vec::new(); + if matches!(param.kind, hir::GenericParamKind::Type { default: Some(_), .. }) + && generics.where_clause.predicates.len() == 0 + { + // Suggest a bound, but there is no existing `where` clause *and* the type param has a + // default (``), so we suggest adding `where T: Bar`. + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(" where {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } else { + let mut param_spans = Vec::new(); - for predicate in generics.where_clause.predicates { - if let WherePredicate::BoundPredicate(WhereBoundPredicate { - span, bounded_ty, .. - }) = predicate - { - if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { - if let Some(segment) = path.segments.first() { - if segment.ident.to_string() == param_name { - param_spans.push(span); + for predicate in generics.where_clause.predicates { + if let WherePredicate::BoundPredicate(WhereBoundPredicate { + span, + bounded_ty, + .. + }) = predicate + { + if let TyKind::Path(QPath::Resolved(_, path)) = &bounded_ty.kind { + if let Some(segment) = path.segments.first() { + if segment.ident.to_string() == param_name { + param_spans.push(span); + } } } } } - } - match ¶m_spans[..] { - &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), - _ => { - err.span_suggestion_verbose( - generics.where_clause.tail_span_for_suggestion(), - &msg_restrict_type_further, - format!(", {}: {}", param_name, constraint), - Applicability::MachineApplicable, - ); + match ¶m_spans[..] { + &[¶m_span] => suggest_restrict(param_span.shrink_to_hi()), + _ => { + err.span_suggestion_verbose( + generics.where_clause.tail_span_for_suggestion(), + &msg_restrict_type_further, + format!(", {}: {}", param_name, constraint), + Applicability::MachineApplicable, + ); + } } } diff --git a/src/librustc_middle/ty/erase_regions.rs b/compiler/rustc_middle/src/ty/erase_regions.rs similarity index 100% rename from src/librustc_middle/ty/erase_regions.rs rename to compiler/rustc_middle/src/ty/erase_regions.rs diff --git a/src/librustc_middle/ty/error.rs b/compiler/rustc_middle/src/ty/error.rs similarity index 94% rename from src/librustc_middle/ty/error.rs rename to compiler/rustc_middle/src/ty/error.rs index 1963881626..82d698b37a 100644 --- a/src/librustc_middle/ty/error.rs +++ b/compiler/rustc_middle/src/ty/error.rs @@ -56,6 +56,7 @@ pub enum TypeError<'tcx> { /// created a cycle (because it appears somewhere within that /// type). CyclicTy(Ty<'tcx>), + CyclicConst(&'tcx ty::Const<'tcx>), ProjectionMismatched(ExpectedFound), ExistentialMismatch(ExpectedFound<&'tcx ty::List>>), ObjectUnsafeCoercion(DefId), @@ -100,6 +101,7 @@ impl<'tcx> fmt::Display for TypeError<'tcx> { match *self { CyclicTy(_) => write!(f, "cyclic type of infinite size"), + CyclicConst(_) => write!(f, "encountered a self-referencing constant"), Mismatch => write!(f, "types differ"), UnsafetyMismatch(values) => { write!(f, "expected {} fn, found {} fn", values.expected, values.found) @@ -195,9 +197,9 @@ impl<'tcx> TypeError<'tcx> { pub fn must_include_note(&self) -> bool { use self::TypeError::*; match self { - CyclicTy(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) | FixedArraySize(_) - | Sorts(_) | IntMismatch(_) | FloatMismatch(_) | VariadicMismatch(_) - | TargetFeatureCast(_) => false, + CyclicTy(_) | CyclicConst(_) | UnsafetyMismatch(_) | Mismatch | AbiMismatch(_) + | FixedArraySize(_) | Sorts(_) | IntMismatch(_) | FloatMismatch(_) + | VariadicMismatch(_) | TargetFeatureCast(_) => false, Mutability | TupleSize(_) @@ -218,7 +220,7 @@ impl<'tcx> TypeError<'tcx> { impl<'tcx> ty::TyS<'tcx> { pub fn sort_string(&self, tcx: TyCtxt<'_>) -> Cow<'static, str> { - match self.kind { + match *self.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Str | ty::Never => { format!("`{}`", self).into() } @@ -230,7 +232,7 @@ impl<'tcx> ty::TyS<'tcx> { let n = tcx.lift(&n).unwrap(); match n.try_eval_usize(tcx, ty::ParamEnv::empty()) { _ if t.is_simple_ty() => format!("array `{}`", self).into(), - Some(n) => format!("array of {} element{} ", n, pluralize!(n)).into(), + Some(n) => format!("array of {} element{}", n, pluralize!(n)).into(), None => "array".into(), } } @@ -282,7 +284,7 @@ impl<'tcx> ty::TyS<'tcx> { } pub fn prefix_string(&self) -> Cow<'static, str> { - match self.kind { + match *self.kind() { ty::Infer(_) | ty::Error(_) | ty::Bool @@ -351,7 +353,7 @@ impl<'tcx> TyCtxt<'tcx> { ); } } - match (&values.expected.kind, &values.found.kind) { + match (values.expected.kind(), values.found.kind()) { (ty::Float(_), ty::Infer(ty::IntVar(_))) => { if let Ok( // Issue #53280 @@ -473,6 +475,18 @@ impl Trait for X { #traits-as-parameters", ); } + (ty::Param(p), ty::Closure(..) | ty::Generator(..)) => { + let generics = self.generics_of(body_owner_def_id); + let p_span = self.def_span(generics.type_param(p, self).def_id); + if !sp.contains(p_span) { + db.span_label(p_span, "this type parameter"); + } + db.help(&format!( + "every closure has a distinct type and so could not always match the \ + caller-chosen type of parameter `{}`", + p + )); + } (ty::Param(p), _) | (_, ty::Param(p)) => { let generics = self.generics_of(body_owner_def_id); let p_span = self.def_span(generics.type_param(p, self).def_id); @@ -512,7 +526,10 @@ impl Trait for X { } debug!( "note_and_explain_type_err expected={:?} ({:?}) found={:?} ({:?})", - values.expected, values.expected.kind, values.found, values.found.kind, + values.expected, + values.expected.kind(), + values.found, + values.found.kind(), ); } CyclicTy(ty) => { @@ -543,7 +560,7 @@ impl Trait for X { } fn suggest_constraint( - &self, + self, db: &mut DiagnosticBuilder<'_>, msg: &str, body_owner_def_id: DefId, @@ -551,14 +568,14 @@ impl Trait for X { ty: Ty<'tcx>, ) -> bool { let assoc = self.associated_item(proj_ty.item_def_id); - let trait_ref = proj_ty.trait_ref(*self); + let trait_ref = proj_ty.trait_ref(self); if let Some(item) = self.hir().get_if_local(body_owner_def_id) { if let Some(hir_generics) = item.generics() { // Get the `DefId` for the type parameter corresponding to `A` in `::Foo`. // This will also work for `impl Trait`. - let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind { + let def_id = if let ty::Param(param_ty) = proj_ty.self_ty().kind() { let generics = self.generics_of(body_owner_def_id); - generics.type_param(¶m_ty, *self).def_id + generics.type_param(param_ty, self).def_id } else { return false; }; @@ -626,7 +643,7 @@ impl Trait for X { /// and the `impl`, we provide a generic `help` to constrain the assoc type or call an assoc /// fn that returns the type. fn expected_projection( - &self, + self, db: &mut DiagnosticBuilder<'_>, proj_ty: &ty::ProjectionTy<'tcx>, values: &ExpectedFound>, @@ -680,7 +697,7 @@ impl Trait for X { } } - if let ty::Opaque(def_id, _) = proj_ty.self_ty().kind { + if let ty::Opaque(def_id, _) = *proj_ty.self_ty().kind() { // When the expected `impl Trait` is not defined in the current item, it will come from // a return type. This can occur when dealing with `TryStream` (#71035). if self.constrain_associated_type_structured_suggestion( @@ -731,7 +748,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_methods_that_satisfy_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, assoc_container_id: DefId, current_method_ident: Option, @@ -750,7 +767,7 @@ fn foo(&self) -> Self::T { String::new() } }) .filter_map(|(_, item)| { let method = self.fn_sig(item.def_id); - match method.output().skip_binder().kind { + match *method.output().skip_binder().kind() { ty::Projection(ty::ProjectionTy { item_def_id, .. }) if item_def_id == proj_ty_item_def_id => { @@ -786,7 +803,7 @@ fn foo(&self) -> Self::T { String::new() } } fn point_at_associated_type( - &self, + self, db: &mut DiagnosticBuilder<'_>, body_owner_def_id: DefId, found: Ty<'tcx>, @@ -829,14 +846,11 @@ fn foo(&self) -> Self::T { String::new() } kind: hir::ItemKind::Impl { items, .. }, .. })) => { for item in &items[..] { - match item.kind { - hir::AssocItemKind::Type => { - if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { - db.span_label(item.span, "expected this associated type"); - return true; - } + if let hir::AssocItemKind::Type = item.kind { + if self.type_of(self.hir().local_def_id(item.id.hir_id)) == found { + db.span_label(item.span, "expected this associated type"); + return true; } - _ => {} } } } @@ -848,7 +862,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a slice of `hir::GenericBound`s, if any of them corresponds to the `trait_ref` /// requirement, provide a strucuted suggestion to constrain it to a given type `ty`. fn constrain_generic_bound_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, trait_ref: &ty::TraitRef<'tcx>, bounds: hir::GenericBounds<'_>, @@ -872,7 +886,7 @@ fn foo(&self) -> Self::T { String::new() } /// Given a span corresponding to a bound, provide a structured suggestion to set an /// associated type to a given type `ty`. fn constrain_associated_type_structured_suggestion( - &self, + self, db: &mut DiagnosticBuilder<'_>, span: Span, assoc: &ty::AssocItem, diff --git a/src/librustc_middle/ty/fast_reject.rs b/compiler/rustc_middle/src/ty/fast_reject.rs similarity index 99% rename from src/librustc_middle/ty/fast_reject.rs rename to compiler/rustc_middle/src/ty/fast_reject.rs index 1bee2d60f7..860f91db2b 100644 --- a/src/librustc_middle/ty/fast_reject.rs +++ b/compiler/rustc_middle/src/ty/fast_reject.rs @@ -60,7 +60,7 @@ pub fn simplify_type( ty: Ty<'_>, can_simplify_params: bool, ) -> Option { - match ty.kind { + match *ty.kind() { ty::Bool => Some(BoolSimplifiedType), ty::Char => Some(CharSimplifiedType), ty::Int(int_type) => Some(IntSimplifiedType(int_type)), diff --git a/src/librustc_middle/ty/flags.rs b/compiler/rustc_middle/src/ty/flags.rs similarity index 98% rename from src/librustc_middle/ty/flags.rs rename to compiler/rustc_middle/src/ty/flags.rs index 27f50c240d..c9a4022330 100644 --- a/src/librustc_middle/ty/flags.rs +++ b/compiler/rustc_middle/src/ty/flags.rs @@ -249,11 +249,14 @@ impl FlagComputation { self.add_const(expected); self.add_const(found); } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + self.add_ty(ty); + } } } fn add_ty(&mut self, ty: Ty<'_>) { - self.add_flags(ty.flags); + self.add_flags(ty.flags()); self.add_exclusive_binder(ty.outer_exclusive_binder); } diff --git a/src/librustc_middle/ty/fold.rs b/compiler/rustc_middle/src/ty/fold.rs similarity index 98% rename from src/librustc_middle/ty/fold.rs rename to compiler/rustc_middle/src/ty/fold.rs index 492f8ce9ef..84134bedef 100644 --- a/src/librustc_middle/ty/fold.rs +++ b/compiler/rustc_middle/src/ty/fold.rs @@ -352,7 +352,7 @@ impl<'tcx> TyCtxt<'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // We're only interested in types involving regions - if ty.flags.intersects(TypeFlags::HAS_FREE_REGIONS) { + if ty.flags().intersects(TypeFlags::HAS_FREE_REGIONS) { ty.super_visit_with(self) } else { false // keep visiting @@ -471,7 +471,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for BoundVarReplacer<'a, 'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { ty::Bound(debruijn, bound_ty) => { if debruijn == self.current_index { let fld_t = &mut self.fld_t; @@ -623,7 +623,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Replaces any late-bound regions bound in `value` with /// free variants attached to `all_outlive_scope`. pub fn liberate_late_bound_regions( - &self, + self, all_outlive_scope: DefId, value: &ty::Binder, ) -> T @@ -644,7 +644,7 @@ impl<'tcx> TyCtxt<'tcx> { /// variables and equate `value` with something else, those /// variables will also be equated. pub fn collect_constrained_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -655,7 +655,7 @@ impl<'tcx> TyCtxt<'tcx> { /// Returns a set of all late-bound regions that appear in `value` anywhere. pub fn collect_referenced_late_bound_regions( - &self, + self, value: &Binder, ) -> FxHashSet where @@ -665,7 +665,7 @@ impl<'tcx> TyCtxt<'tcx> { } fn collect_late_bound_regions( - &self, + self, value: &Binder, just_constraint: bool, ) -> FxHashSet @@ -771,7 +771,7 @@ impl TypeFolder<'tcx> for Shifter<'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match *ty.kind() { ty::Bound(debruijn, bound_ty) => { if self.amount == 0 || debruijn < self.current_index { ty @@ -922,8 +922,13 @@ struct HasTypeFlagsVisitor { impl<'tcx> TypeVisitor<'tcx> for HasTypeFlagsVisitor { fn visit_ty(&mut self, t: Ty<'_>) -> bool { - debug!("HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", t, t.flags, self.flags); - t.flags.intersects(self.flags) + debug!( + "HasTypeFlagsVisitor: t={:?} t.flags={:?} self.flags={:?}", + t, + t.flags(), + self.flags + ); + t.flags().intersects(self.flags) } fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { @@ -987,7 +992,7 @@ impl<'tcx> TypeVisitor<'tcx> for LateBoundRegionsCollector { // ignore the inputs to a projection, as they may not appear // in the normalized form if self.just_constrained { - if let ty::Projection(..) | ty::Opaque(..) = t.kind { + if let ty::Projection(..) | ty::Opaque(..) = t.kind() { return false; } } diff --git a/src/librustc_middle/ty/inhabitedness/def_id_forest.rs b/compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs similarity index 100% rename from src/librustc_middle/ty/inhabitedness/def_id_forest.rs rename to compiler/rustc_middle/src/ty/inhabitedness/def_id_forest.rs diff --git a/src/librustc_middle/ty/inhabitedness/mod.rs b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs similarity index 99% rename from src/librustc_middle/ty/inhabitedness/mod.rs rename to compiler/rustc_middle/src/ty/inhabitedness/mod.rs index d1b5eed921..2c1179c21f 100644 --- a/src/librustc_middle/ty/inhabitedness/mod.rs +++ b/compiler/rustc_middle/src/ty/inhabitedness/mod.rs @@ -196,7 +196,7 @@ impl<'tcx> FieldDef { impl<'tcx> TyS<'tcx> { /// Calculates the forest of `DefId`s from which this type is visibly uninhabited. fn uninhabited_from(&self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> DefIdForest { - match self.kind { + match *self.kind() { Adt(def, substs) => { ensure_sufficient_stack(|| def.uninhabited_from(tcx, substs, param_env)) } diff --git a/src/librustc_middle/ty/instance.rs b/compiler/rustc_middle/src/ty/instance.rs similarity index 95% rename from src/librustc_middle/ty/instance.rs rename to compiler/rustc_middle/src/ty/instance.rs index 8e08fe4b87..a6b62097d5 100644 --- a/src/librustc_middle/ty/instance.rs +++ b/compiler/rustc_middle/src/ty/instance.rs @@ -62,10 +62,6 @@ pub enum InstanceDef<'tcx> { /// `::call_*` (generated `FnTrait` implementation for `fn()` pointers). /// /// `DefId` is `FnTrait::call_*`. - /// - /// NB: the (`fn` pointer) type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. FnPtrShim(DefId, Ty<'tcx>), /// Dynamic dispatch to `::fn`. @@ -87,10 +83,6 @@ pub enum InstanceDef<'tcx> { /// The `DefId` is for `core::ptr::drop_in_place`. /// The `Option>` is either `Some(T)`, or `None` for empty drop /// glue. - /// - /// NB: the type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. DropGlue(DefId, Option>), /// Compiler-generated `::clone` implementation. @@ -99,10 +91,6 @@ pub enum InstanceDef<'tcx> { /// Additionally, arrays, tuples, and closures get a `Clone` shim even if they aren't `Copy`. /// /// The `DefId` is for `Clone::clone`, the `Ty` is the type `T` with the builtin `Clone` impl. - /// - /// NB: the type must currently be monomorphic to avoid double substitution - /// problems with the MIR shim bodies. `Instance::resolve` enforces this. - // FIXME(#69925) support polymorphic MIR shim bodies properly instead. CloneShim(DefId, Ty<'tcx>), } @@ -243,6 +231,27 @@ impl<'tcx> InstanceDef<'tcx> { _ => false, } } + + /// Returns `true` when the MIR body associated with this instance should be monomorphized + /// by its users (e.g. codegen or miri) by substituting the `substs` from `Instance` (see + /// `Instance::substs_for_mir_body`). + /// + /// Otherwise, returns `false` only for some kinds of shims where the construction of the MIR + /// body should perform necessary substitutions. + pub fn has_polymorphic_mir_body(&self) -> bool { + match *self { + InstanceDef::CloneShim(..) + | InstanceDef::FnPtrShim(..) + | InstanceDef::DropGlue(_, Some(_)) => false, + InstanceDef::ClosureOnceShim { .. } + | InstanceDef::DropGlue(..) + | InstanceDef::Item(_) + | InstanceDef::Intrinsic(..) + | InstanceDef::ReifyShim(..) + | InstanceDef::Virtual(..) + | InstanceDef::VtableShim(..) => true, + } + } } impl<'tcx> fmt::Display for Instance<'tcx> { @@ -260,10 +269,11 @@ impl<'tcx> fmt::Display for Instance<'tcx> { InstanceDef::ReifyShim(_) => write!(f, " - shim(reify)"), InstanceDef::Intrinsic(_) => write!(f, " - intrinsic"), InstanceDef::Virtual(_, num) => write!(f, " - virtual#{}", num), - InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({:?})", ty), + InstanceDef::FnPtrShim(_, ty) => write!(f, " - shim({})", ty), InstanceDef::ClosureOnceShim { .. } => write!(f, " - shim"), - InstanceDef::DropGlue(_, ty) => write!(f, " - shim({:?})", ty), - InstanceDef::CloneShim(_, ty) => write!(f, " - shim({:?})", ty), + InstanceDef::DropGlue(_, None) => write!(f, " - shim(None)"), + InstanceDef::DropGlue(_, Some(ty)) => write!(f, " - shim(Some({}))", ty), + InstanceDef::CloneShim(_, ty) => write!(f, " - shim({})", ty), } } } @@ -439,30 +449,18 @@ impl<'tcx> Instance<'tcx> { Instance { def, substs } } - /// FIXME(#69925) Depending on the kind of `InstanceDef`, the MIR body associated with an + /// Depending on the kind of `InstanceDef`, the MIR body associated with an /// instance is expressed in terms of the generic parameters of `self.def_id()`, and in other /// cases the MIR body is expressed in terms of the types found in the substitution array. /// In the former case, we want to substitute those generic types and replace them with the /// values from the substs when monomorphizing the function body. But in the latter case, we /// don't want to do that substitution, since it has already been done effectively. /// - /// This function returns `Some(substs)` in the former case and None otherwise -- i.e., if + /// This function returns `Some(substs)` in the former case and `None` otherwise -- i.e., if /// this function returns `None`, then the MIR body does not require substitution during - /// monomorphization. + /// codegen. pub fn substs_for_mir_body(&self) -> Option> { - match self.def { - InstanceDef::CloneShim(..) - | InstanceDef::DropGlue(_, Some(_)) => None, - InstanceDef::ClosureOnceShim { .. } - | InstanceDef::DropGlue(..) - // FIXME(#69925): `FnPtrShim` should be in the other branch. - | InstanceDef::FnPtrShim(..) - | InstanceDef::Item(_) - | InstanceDef::Intrinsic(..) - | InstanceDef::ReifyShim(..) - | InstanceDef::Virtual(..) - | InstanceDef::VtableShim(..) => Some(self.substs), - } + if self.def.has_polymorphic_mir_body() { Some(self.substs) } else { None } } /// Returns a new `Instance` where generic parameters in `instance.substs` are replaced by diff --git a/src/librustc_middle/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs similarity index 96% rename from src/librustc_middle/ty/layout.rs rename to compiler/rustc_middle/src/ty/layout.rs index 08bd131565..ee669ed228 100644 --- a/src/librustc_middle/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -174,9 +174,9 @@ pub enum LayoutError<'tcx> { impl<'tcx> fmt::Display for LayoutError<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { match *self { - LayoutError::Unknown(ty) => write!(f, "the type `{:?}` has an unknown layout", ty), + LayoutError::Unknown(ty) => write!(f, "the type `{}` has an unknown layout", ty), LayoutError::SizeOverflow(ty) => { - write!(f, "the type `{:?}` is too big for the current architecture", ty) + write!(f, "the type `{}` is too big for the current architecture", ty) } } } @@ -390,78 +390,60 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { // Unpack newtype ABIs and find scalar pairs. if sized && size.bytes() > 0 { - // All other fields must be ZSTs, and we need them to all start at 0. - let mut zst_offsets = offsets.iter().enumerate().filter(|&(i, _)| fields[i].is_zst()); - if zst_offsets.all(|(_, o)| o.bytes() == 0) { - let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); + // All other fields must be ZSTs. + let mut non_zst_fields = fields.iter().enumerate().filter(|&(_, f)| !f.is_zst()); - match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { - // We have exactly one non-ZST field. - (Some((i, field)), None, None) => { - // Field fills the struct and it has a scalar or scalar pair ABI. - if offsets[i].bytes() == 0 - && align.abi == field.align.abi - && size == field.size - { - match field.abi { - // 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(); - } - // But scalar pairs are Rust-specific and get - // treated as aggregates by C ABIs anyway. - Abi::ScalarPair(..) => { - abi = field.abi.clone(); - } - _ => {} + match (non_zst_fields.next(), non_zst_fields.next(), non_zst_fields.next()) { + // We have exactly one non-ZST field. + (Some((i, field)), None, None) => { + // Field fills the struct and it has a scalar or scalar pair ABI. + if offsets[i].bytes() == 0 && align.abi == field.align.abi && size == field.size + { + match field.abi { + // 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(); } + // But scalar pairs are Rust-specific and get + // treated as aggregates by C ABIs anyway. + Abi::ScalarPair(..) => { + abi = field.abi.clone(); + } + _ => {} } } - - // 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), .. }, .. - }, - )), - 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_offsets = match pair.fields { - FieldsShape::Arbitrary { ref offsets, ref memory_index } => { - assert_eq!(memory_index, &[0, 1]); - offsets - } - _ => bug!(), - }; - if offsets[i] == pair_offsets[0] - && offsets[j] == pair_offsets[1] - && align == pair.align - && size == pair.size - { - // We can use `ScalarPair` only when it matches our - // already computed layout (including `#[repr(C)]`). - abi = pair.abi; - } - } - - _ => {} } + + // 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), .. }, .. })), + 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_offsets = match pair.fields { + FieldsShape::Arbitrary { ref offsets, ref memory_index } => { + assert_eq!(memory_index, &[0, 1]); + offsets + } + _ => bug!(), + }; + if offsets[i] == pair_offsets[0] + && offsets[j] == pair_offsets[1] + && align == pair.align + && size == pair.size + { + // We can use `ScalarPair` only when it matches our + // already computed layout (including `#[repr(C)]`). + abi = pair.abi; + } + } + + _ => {} } } @@ -495,7 +477,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { }; debug_assert!(!ty.has_infer_types_or_consts()); - Ok(match ty.kind { + Ok(match *ty.kind() { // Basic scalars. ty::Bool => tcx.intern_layout(Layout::scalar( self, @@ -540,7 +522,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { } let unsized_part = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - let metadata = match unsized_part.kind { + let metadata = match unsized_part.kind() { ty::Foreign(..) => { return Ok(tcx.intern_layout(Layout::scalar(self, data_ptr))); } @@ -1259,11 +1241,11 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { tcx.layout_raw(param_env.and(normalized))? } - ty::Bound(..) | ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { + ty::Placeholder(..) | ty::GeneratorWitness(..) | ty::Infer(_) => { bug!("Layout::compute: unexpected type `{}`", ty) } - ty::Param(_) | ty::Error(_) => { + ty::Bound(..) | ty::Param(_) | ty::Error(_) => { return Err(LayoutError::Unknown(ty)); } }) @@ -1624,7 +1606,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> { ); }; - let adt_def = match layout.ty.kind { + let adt_def = match *layout.ty.kind() { ty::Adt(ref adt_def, _) => { debug!("print-type-size t: `{:?}` process adt", layout.ty); adt_def @@ -1767,11 +1749,11 @@ impl<'tcx> SizeSkeleton<'tcx> { Err(err) => err, }; - match ty.kind { + match *ty.kind() { ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { let non_zero = !ty.is_unsafe_ptr(); let tail = tcx.struct_tail_erasing_lifetimes(pointee, param_env); - match tail.kind { + match tail.kind() { ty::Param(_) | ty::Projection(_) => { debug_assert!(tail.has_param_types_or_consts()); Ok(SizeSkeleton::Pointer { non_zero, tail: tcx.erase_regions(&tail) }) @@ -2018,7 +2000,7 @@ where assert_eq!(original_layout.variants, Variants::Single { index }); } - let fields = match this.ty.kind { + let fields = match this.ty.kind() { ty::Adt(def, _) if def.variants.is_empty() => bug!("for_variant called on zero-variant enum"), ty::Adt(def, _) => def.variants[variant_index].fields.len(), @@ -2056,7 +2038,7 @@ where })) }; - cx.layout_of(match this.ty.kind { + cx.layout_of(match *this.ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -2092,7 +2074,7 @@ where )); } - match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind { + match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { ty::Slice(_) | ty::Str => tcx.types.usize, ty::Dynamic(_, _) => { tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) @@ -2170,7 +2152,7 @@ where if ty.is_fn() { cx.data_layout().instruction_address_space } else { AddressSpace::DATA } }; - let pointee_info = match this.ty.kind { + let pointee_info = match *this.ty.kind() { ty::RawPtr(mt) if offset.bytes() == 0 => { cx.layout_of(mt.ty).to_result().ok().map(|layout| PointeeInfo { size: layout.size, @@ -2286,7 +2268,7 @@ where // FIXME(eddyb) This should be for `ptr::Unique`, not `Box`. if let Some(ref mut pointee) = result { - if let ty::Adt(def, _) = this.ty.kind { + if let ty::Adt(def, _) = this.ty.kind() { if def.is_box() && offset.bytes() == 0 { pointee.safe = Some(PointerKind::UniqueOwned); } @@ -2299,7 +2281,9 @@ where debug!( "pointee_info_at (offset={:?}, type kind: {:?}) => {:?}", - offset, this.ty.kind, pointee_info + offset, + this.ty.kind(), + pointee_info ); pointee_info @@ -2326,14 +2310,14 @@ impl<'tcx> ty::Instance<'tcx> { 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()); - match ty.kind { + match *ty.kind() { ty::FnDef(..) => { // HACK(davidtwco,eddyb): This is a workaround for polymorphization considering // parameters unused if they show up in the signature, but not in the `mir::Body` // (i.e. due to being inside a projection that got normalized, see // `src/test/ui/polymorphization/normalized_sig_types.rs`), and codegen not keeping // track of a polymorphization `ParamEnv` to allow normalizing later. - let mut sig = match ty.kind { + let mut sig = match *ty.kind() { ty::FnDef(def_id, substs) => tcx .normalize_erasing_regions(tcx.param_env(def_id), tcx.fn_sig(def_id)) .subst(tcx, substs), @@ -2596,7 +2580,7 @@ where assert!(!sig.c_variadic && extra_args.is_empty()); if let Some(input) = sig.inputs().last() { - if let ty::Tuple(tupled_arguments) = input.kind { + if let ty::Tuple(tupled_arguments) = input.kind() { inputs = &sig.inputs()[0..sig.inputs().len() - 1]; tupled_arguments.iter().map(|k| k.expect_ty()).collect() } else { @@ -2751,6 +2735,7 @@ where can_unwind: fn_can_unwind(cx.tcx().sess.panic_strategy(), codegen_fn_attr_flags, conv), }; fn_abi.adjust_for_abi(cx, sig.abi); + debug!("FnAbi::new_internal = {:?}", fn_abi); fn_abi } @@ -2764,7 +2749,7 @@ where || abi == SpecAbi::RustIntrinsic || abi == SpecAbi::PlatformIntrinsic { - let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>| { + let fixup = |arg: &mut ArgAbi<'tcx, Ty<'tcx>>, is_ret: bool| { if arg.is_ignore() { return; } @@ -2802,8 +2787,11 @@ where _ => return, } + let max_by_val_size = + if is_ret { call::max_ret_by_val(cx) } else { Pointer.size(cx) }; let size = arg.layout.size; - if arg.layout.is_unsized() || size > Pointer.size(cx) { + + if arg.layout.is_unsized() || size > max_by_val_size { arg.make_indirect(); } else { // We want to pass small aggregates as immediates, but using @@ -2812,9 +2800,9 @@ where arg.cast_to(Reg { kind: RegKind::Integer, size }); } }; - fixup(&mut self.ret); + fixup(&mut self.ret, true); for arg in &mut self.args { - fixup(arg); + fixup(arg, false); } if let PassMode::Indirect(ref mut attrs, _) = self.ret.mode { attrs.set(ArgAttribute::StructRet); diff --git a/src/librustc_middle/ty/list.rs b/compiler/rustc_middle/src/ty/list.rs similarity index 100% rename from src/librustc_middle/ty/list.rs rename to compiler/rustc_middle/src/ty/list.rs diff --git a/src/librustc_middle/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs similarity index 97% rename from src/librustc_middle/ty/mod.rs rename to compiler/rustc_middle/src/ty/mod.rs index a961d02f7a..b7530c077c 100644 --- a/src/librustc_middle/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -580,8 +580,12 @@ bitflags! { #[allow(rustc::usage_of_ty_tykind)] pub struct TyS<'tcx> { - pub kind: TyKind<'tcx>, - pub flags: TypeFlags, + /// This field shouldn't be used directly and may be removed in the future. + /// Use `TyS::kind()` instead. + kind: TyKind<'tcx>, + /// This field shouldn't be used directly and may be removed in the future. + /// Use `TyS::flags()` instead. + flags: TypeFlags, /// This is a kind of confusing thing: it stores the smallest /// binder such that @@ -609,13 +613,13 @@ static_assert_size!(TyS<'_>, 32); impl<'tcx> Ord for TyS<'tcx> { fn cmp(&self, other: &TyS<'tcx>) -> Ordering { - self.kind.cmp(&other.kind) + self.kind().cmp(other.kind()) } } impl<'tcx> PartialOrd for TyS<'tcx> { fn partial_cmp(&self, other: &TyS<'tcx>) -> Option { - Some(self.kind.cmp(&other.kind)) + Some(self.kind().cmp(other.kind())) } } @@ -678,25 +682,31 @@ pub enum BorrowKind { /// implicit closure bindings. It is needed when the closure /// is borrowing or mutating a mutable referent, e.g.: /// - /// let x: &mut isize = ...; - /// let y = || *x += 5; + /// ``` + /// let x: &mut isize = ...; + /// let y = || *x += 5; + /// ``` /// /// If we were to try to translate this closure into a more explicit /// form, we'd encounter an error with the code as written: /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &x }, fn_ptr); // Closure is pair of env and fn + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` /// /// This is then illegal because you cannot mutate a `&mut` found /// in an aliasable location. To solve, you'd have to translate with /// an `&mut` borrow: /// - /// struct Env { x: & &mut isize } - /// let x: &mut isize = ...; - /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x - /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` + /// struct Env { x: & &mut isize } + /// let x: &mut isize = ...; + /// let y = (&mut Env { &mut x }, fn_ptr); // changed from &x to &mut x + /// fn fn_ptr(env: &mut Env) { **env.x += 5; } + /// ``` /// /// Now the assignment to `**env.x` is legal, but creating a /// mutable pointer to `x` is not because `x` is not mutable. We @@ -721,7 +731,13 @@ pub enum UpvarCapture<'tcx> { /// Upvar is captured by value. This is always true when the /// closure is labeled `move`, but can also be true in other cases /// depending on inference. - ByValue, + /// + /// If the upvar was inferred to be captured by value (e.g. `move` + /// was not used), then the `Span` points to a usage that + /// required it. There may be more than one such usage + /// (e.g. `|| { a; a; }`), in which case we pick an + /// arbitrary one. + ByValue(Option), /// Upvar is captured by reference. ByRef(UpvarBorrow<'tcx>), @@ -1145,6 +1161,11 @@ pub enum PredicateAtom<'tcx> { /// Constants must be equal. The first component is the const that is expected. ConstEquate(&'tcx Const<'tcx>, &'tcx Const<'tcx>), + + /// Represents a type found in the environment that we can use for implied bounds. + /// + /// Only used for Chalk. + TypeWellFormedFromEnv(Ty<'tcx>), } impl<'tcx> PredicateAtom<'tcx> { @@ -1440,7 +1461,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateAtom::ClosureKind(..) | PredicateAtom::TypeOutlives(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } @@ -1455,7 +1477,8 @@ impl<'tcx> Predicate<'tcx> { | PredicateAtom::ObjectSafe(..) | PredicateAtom::ClosureKind(..) | PredicateAtom::ConstEvaluatable(..) - | PredicateAtom::ConstEquate(..) => None, + | PredicateAtom::ConstEquate(..) + | PredicateAtom::TypeWellFormedFromEnv(..) => None, } } } @@ -1728,11 +1751,6 @@ pub struct ParamEnv<'tcx> { /// /// Note: This is packed, use the reveal() method to access it. packed: CopyTaggedPtr<&'tcx List>, traits::Reveal, true>, - - /// If this `ParamEnv` comes from a call to `tcx.param_env(def_id)`, - /// register that `def_id` (useful for transitioning to the chalk trait - /// solver). - pub def_id: Option, } unsafe impl rustc_data_structures::tagged_ptr::Tag for traits::Reveal { @@ -1757,7 +1775,6 @@ impl<'tcx> fmt::Debug for ParamEnv<'tcx> { f.debug_struct("ParamEnv") .field("caller_bounds", &self.caller_bounds()) .field("reveal", &self.reveal()) - .field("def_id", &self.def_id) .finish() } } @@ -1766,23 +1783,16 @@ impl<'a, 'tcx> HashStable> for ParamEnv<'tcx> { fn hash_stable(&self, hcx: &mut StableHashingContext<'a>, hasher: &mut StableHasher) { self.caller_bounds().hash_stable(hcx, hasher); self.reveal().hash_stable(hcx, hasher); - self.def_id.hash_stable(hcx, hasher); } } impl<'tcx> TypeFoldable<'tcx> for ParamEnv<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - ParamEnv::new( - self.caller_bounds().fold_with(folder), - self.reveal().fold_with(folder), - self.def_id.fold_with(folder), - ) + ParamEnv::new(self.caller_bounds().fold_with(folder), self.reveal().fold_with(folder)) } fn super_visit_with>(&self, visitor: &mut V) -> bool { - self.caller_bounds().visit_with(visitor) - || self.reveal().visit_with(visitor) - || self.def_id.visit_with(visitor) + self.caller_bounds().visit_with(visitor) || self.reveal().visit_with(visitor) } } @@ -1793,7 +1803,7 @@ impl<'tcx> ParamEnv<'tcx> { /// type-checking. #[inline] pub fn empty() -> Self { - Self::new(List::empty(), Reveal::UserFacing, None) + Self::new(List::empty(), Reveal::UserFacing) } #[inline] @@ -1815,17 +1825,13 @@ impl<'tcx> ParamEnv<'tcx> { /// or invoke `param_env.with_reveal_all()`. #[inline] pub fn reveal_all() -> Self { - Self::new(List::empty(), Reveal::All, None) + Self::new(List::empty(), Reveal::All) } /// Construct a trait environment with the given set of predicates. #[inline] - pub fn new( - caller_bounds: &'tcx List>, - reveal: Reveal, - def_id: Option, - ) -> Self { - ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal), def_id } + pub fn new(caller_bounds: &'tcx List>, reveal: Reveal) -> Self { + ty::ParamEnv { packed: CopyTaggedPtr::new(caller_bounds, reveal) } } pub fn with_user_facing(mut self) -> Self { @@ -1847,12 +1853,12 @@ impl<'tcx> ParamEnv<'tcx> { return self; } - ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All, self.def_id) + ParamEnv::new(tcx.normalize_opaque_types(self.caller_bounds()), Reveal::All) } /// Returns this same environment but with no caller bounds. pub fn without_caller_bounds(self) -> Self { - Self::new(List::empty(), self.reveal(), self.def_id) + Self::new(List::empty(), self.reveal()) } /// Creates a suitable environment in which to perform trait @@ -1971,6 +1977,9 @@ bitflags! { const NO_VARIANT_FLAGS = 0; /// Indicates whether the field list of this variant is `#[non_exhaustive]`. const IS_FIELD_LIST_NON_EXHAUSTIVE = 1 << 0; + /// Indicates whether this variant was obtained as part of recovering from + /// a syntactic error. May be incomplete or bogus. + const IS_RECOVERED = 1 << 1; } } @@ -1994,12 +2003,9 @@ pub struct VariantDef { pub ctor_kind: CtorKind, /// Flags of the variant (e.g. is field list non-exhaustive)? flags: VariantFlags, - /// Variant is obtained as part of recovering from a syntactic error. - /// May be incomplete or bogus. - pub recovered: bool, } -impl<'tcx> VariantDef { +impl VariantDef { /// Creates a new `VariantDef`. /// /// `variant_did` is the `DefId` that identifies the enum variant (if this `VariantDef` @@ -2039,6 +2045,10 @@ impl<'tcx> VariantDef { flags |= VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE; } + if recovered { + flags |= VariantFlags::IS_RECOVERED; + } + VariantDef { def_id: variant_did.unwrap_or(parent_did), ctor_def_id, @@ -2047,7 +2057,6 @@ impl<'tcx> VariantDef { fields, ctor_kind, flags, - recovered, } } @@ -2057,17 +2066,10 @@ impl<'tcx> VariantDef { self.flags.intersects(VariantFlags::IS_FIELD_LIST_NON_EXHAUSTIVE) } - /// `repr(transparent)` structs can have a single non-ZST field, this function returns that - /// field. - pub fn transparent_newtype_field(&self, tcx: TyCtxt<'tcx>) -> Option<&FieldDef> { - for field in &self.fields { - let field_ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, self.def_id)); - if !field_ty.is_zst(tcx, self.def_id) { - return Some(field); - } - } - - None + /// Was this variant obtained as part of recovering from a syntactic error? + #[inline] + pub fn is_recovered(&self) -> bool { + self.flags.intersects(VariantFlags::IS_RECOVERED) } } @@ -2676,7 +2678,7 @@ impl<'tcx> ClosureKind { } } - /// Returns `true` if this a type that impls this closure kind + /// Returns `true` if a type that impls this closure kind /// must also implement `other`. pub fn extends(self, other: ty::ClosureKind) -> bool { match (self, other) { @@ -3086,6 +3088,7 @@ pub fn provide(providers: &mut ty::query::Providers) { erase_regions::provide(providers); layout::provide(providers); util::provide(providers); + print::provide(providers); super::util::bug::provide(providers); *providers = ty::query::Providers { trait_impls_of: trait_def::trait_impls_of_provider, diff --git a/src/librustc_middle/ty/normalize_erasing_regions.rs b/compiler/rustc_middle/src/ty/normalize_erasing_regions.rs similarity index 100% rename from src/librustc_middle/ty/normalize_erasing_regions.rs rename to compiler/rustc_middle/src/ty/normalize_erasing_regions.rs diff --git a/src/librustc_middle/ty/outlives.rs b/compiler/rustc_middle/src/ty/outlives.rs similarity index 99% rename from src/librustc_middle/ty/outlives.rs rename to compiler/rustc_middle/src/ty/outlives.rs index 07a0bcc0c4..ca992d36e9 100644 --- a/src/librustc_middle/ty/outlives.rs +++ b/compiler/rustc_middle/src/ty/outlives.rs @@ -3,8 +3,8 @@ // RFC for reference. use crate::ty::subst::{GenericArg, GenericArgKind}; -use crate::ty::walk::MiniSet; use crate::ty::{self, Ty, TyCtxt, TypeFoldable}; +use rustc_data_structures::mini_set::MiniSet; use smallvec::SmallVec; #[derive(Debug)] @@ -68,7 +68,7 @@ fn compute_components( // with `collect()` because of the need to sometimes skip subtrees // in the `subtys` iterator (e.g., when encountering a // projection). - match ty.kind { + match *ty.kind() { ty::FnDef(_, substs) => { // HACK(eddyb) ignore lifetimes found shallowly in `substs`. // This is inconsistent with `ty::Adt` (including all substs) diff --git a/src/librustc_middle/ty/print/mod.rs b/compiler/rustc_middle/src/ty/print/mod.rs similarity index 99% rename from src/librustc_middle/ty/print/mod.rs rename to compiler/rustc_middle/src/ty/print/mod.rs index 981e013683..225ea2399f 100644 --- a/src/librustc_middle/ty/print/mod.rs +++ b/compiler/rustc_middle/src/ty/print/mod.rs @@ -2,16 +2,14 @@ use crate::ty::subst::{GenericArg, Subst}; use crate::ty::{self, DefIdTree, Ty, TyCtxt}; use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use rustc_hir::def_id::{CrateNum, DefId}; use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; -use rustc_middle::ty::walk::MiniSet; // `pretty` is a separate module only for organization. mod pretty; pub use self::pretty::*; -pub mod obsolete; - // FIXME(eddyb) false positive, the lifetime parameters are used with `P: Printer<...>`. #[allow(unused_lifetimes)] pub trait Print<'tcx, P> { @@ -273,7 +271,7 @@ fn characteristic_def_id_of_type_cached<'a>( ty: Ty<'a>, visited: &mut MiniSet>, ) -> Option { - match ty.kind { + match *ty.kind() { ty::Adt(adt_def, _) => Some(adt_def.did), ty::Dynamic(data, ..) => data.principal_def_id(), diff --git a/src/librustc_middle/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs similarity index 87% rename from src/librustc_middle/ty/print/pretty.rs rename to compiler/rustc_middle/src/ty/print/pretty.rs index a29e0b0000..7b5cf681f3 100644 --- a/src/librustc_middle/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -7,10 +7,13 @@ use rustc_apfloat::ieee::{Double, Single}; use rustc_apfloat::Float; use rustc_ast as ast; use rustc_attr::{SignedInt, UnsignedInt}; +use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::def::{CtorKind, DefKind, Namespace}; -use rustc_hir::def_id::{CrateNum, DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; -use rustc_hir::definitions::{DefPathData, DisambiguatedDefPathData}; +use rustc_hir::def::{self, CtorKind, DefKind, Namespace}; +use rustc_hir::def_id::{CrateNum, DefId, DefIdSet, CRATE_DEF_INDEX, LOCAL_CRATE}; +use rustc_hir::definitions::{DefPathData, DefPathDataName, DisambiguatedDefPathData}; +use rustc_hir::ItemKind; +use rustc_session::config::TrimmedDefPaths; use rustc_span::symbol::{kw, Ident, Symbol}; use rustc_target::abi::{Integer, Size}; use rustc_target::spec::abi::Abi; @@ -52,6 +55,7 @@ macro_rules! define_scoped_cx { thread_local! { static FORCE_IMPL_FILENAME_LINE: Cell = Cell::new(false); static SHOULD_PREFIX_WITH_CRATE: Cell = Cell::new(false); + static NO_TRIMMED_PATH: Cell = Cell::new(false); static NO_QUERIES: Cell = Cell::new(false); } @@ -94,6 +98,18 @@ pub fn with_crate_prefix R, R>(f: F) -> R { }) } +/// Prevent path trimming if it is turned on. Path trimming affects `Display` impl +/// of various rustc types, for example `std::vec::Vec` would be trimmed to `Vec`, +/// if no other `Vec` is found. +pub fn with_no_trimmed_paths R, R>(f: F) -> R { + NO_TRIMMED_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 @@ -243,6 +259,28 @@ pub trait PrettyPrinter<'tcx>: self.try_print_visible_def_path_recur(def_id, &mut callers) } + /// Try to see if this path can be trimmed to a unique symbol name. + fn try_print_trimmed_def_path( + mut self, + def_id: DefId, + ) -> Result<(Self::Path, bool), Self::Error> { + if !self.tcx().sess.opts.debugging_opts.trim_diagnostic_paths + || matches!(self.tcx().sess.opts.trimmed_def_paths, TrimmedDefPaths::Never) + || NO_TRIMMED_PATH.with(|flag| flag.get()) + || SHOULD_PREFIX_WITH_CRATE.with(|flag| flag.get()) + { + return Ok((self, false)); + } + + match self.tcx().trimmed_def_paths(LOCAL_CRATE).get(&def_id) { + None => Ok((self, false)), + Some(symbol) => { + self.write_str(&symbol.as_str())?; + Ok((self, true)) + } + } + } + /// Does the work of `try_print_visible_def_path`, building the /// full definition path recursively before attempting to /// post-process it into the valid and visible version that @@ -419,7 +457,7 @@ pub trait PrettyPrinter<'tcx>: // Inherent impls. Try to print `Foo::bar` for an inherent // impl on `Foo`, but fallback to `::bar` if self-type is // anything other than a simple path. - match self_ty.kind { + match self_ty.kind() { ty::Adt(..) | ty::Foreign(_) | ty::Bool @@ -470,7 +508,7 @@ pub trait PrettyPrinter<'tcx>: fn pretty_print_type(mut self, ty: Ty<'tcx>) -> Result { define_scoped_cx!(self); - match ty.kind { + match *ty.kind() { ty::Bool => p!(write("bool")), ty::Char => p!(write("char")), ty::Int(t) => p!(write("{}", t.name_str())), @@ -603,42 +641,35 @@ pub trait PrettyPrinter<'tcx>: } ty::Str => p!(write("str")), ty::Generator(did, substs, movability) => { + p!(write("[")); match movability { - hir::Movability::Movable => p!(write("[generator")), - hir::Movability::Static => p!(write("[static generator")), + hir::Movability::Movable => {} + hir::Movability::Static => p!(write("static ")), } - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); - let span = self.tcx().hir().span(hir_id); - p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); - - if substs.as_generator().is_valid() { - let upvar_tys = substs.as_generator().upvar_tys(); - let mut sep = " "; - for (&var_id, upvar_ty) in self - .tcx() - .upvars_mentioned(did) - .as_ref() - .iter() - .flat_map(|v| v.keys()) - .zip(upvar_tys) - { - p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty)); - sep = ", "; - } + if !self.tcx().sess.verbose() { + p!(write("generator")); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); + let span = self.tcx().hir().span(hir_id); + p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); + } else { + p!(write("@{}", self.tcx().def_path_str(did))); } } else { - p!(write("@{}", self.tcx().def_path_str(did))); - + p!(print_def_path(did, substs)); if substs.as_generator().is_valid() { - let upvar_tys = substs.as_generator().upvar_tys(); - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - p!(write("{}{}:", sep, index), print(upvar_ty)); - sep = ", "; + // Search for the first inference variable + p!(write(" upvar_tys=(")); + let mut uninferred_ty = + substs.as_generator().upvar_tys().filter(|ty| ty.is_ty_infer()); + if uninferred_ty.next().is_some() { + p!(write("unavailable")); + } else { + self = self.comma_sep(substs.as_generator().upvar_tys())?; } + p!(write(")")); } } @@ -646,61 +677,50 @@ pub trait PrettyPrinter<'tcx>: p!(write(" "), print(substs.as_generator().witness())); } - p!(write("]")) + p!(write("]")); } ty::GeneratorWitness(types) => { p!(in_binder(&types)); } ty::Closure(did, substs) => { - p!(write("[closure")); - - // FIXME(eddyb) should use `def_span`. - if let Some(did) = did.as_local() { - let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); - if self.tcx().sess.opts.debugging_opts.span_free_formats { - p!(write("@"), print_def_path(did.to_def_id(), substs)); - } else { - let span = self.tcx().hir().span(hir_id); - p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); - } - - if substs.as_closure().is_valid() { - let upvar_tys = substs.as_closure().upvar_tys(); - let mut sep = " "; - for (&var_id, upvar_ty) in self - .tcx() - .upvars_mentioned(did) - .as_ref() - .iter() - .flat_map(|v| v.keys()) - .zip(upvar_tys) - { - p!(write("{}{}:", sep, self.tcx().hir().name(var_id)), print(upvar_ty)); - sep = ", "; + p!(write("[")); + if !self.tcx().sess.verbose() { + p!(write("closure")); + // FIXME(eddyb) should use `def_span`. + if let Some(did) = did.as_local() { + let hir_id = self.tcx().hir().local_def_id_to_hir_id(did); + if self.tcx().sess.opts.debugging_opts.span_free_formats { + p!(write("@"), print_def_path(did.to_def_id(), substs)); + } else { + let span = self.tcx().hir().span(hir_id); + p!(write("@{}", self.tcx().sess.source_map().span_to_string(span))); } + } else { + p!(write("@{}", self.tcx().def_path_str(did))); } } else { - p!(write("@{}", self.tcx().def_path_str(did))); - + p!(print_def_path(did, substs)); if substs.as_closure().is_valid() { - let upvar_tys = substs.as_closure().upvar_tys(); - let mut sep = " "; - for (index, upvar_ty) in upvar_tys.enumerate() { - p!(write("{}{}:", sep, index), print(upvar_ty)); - sep = ", "; + // Search for the first inference variable + let mut uninferred_ty = + substs.as_closure().upvar_tys().filter(|ty| ty.is_ty_infer()); + if uninferred_ty.next().is_some() { + // If the upvar substs contain an inference variable we haven't + // finished capture analysis. + p!(write(" closure_substs=(unavailable)")); + } else { + p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty())); + p!( + write(" closure_sig_as_fn_ptr_ty="), + print(substs.as_closure().sig_as_fn_ptr_ty()) + ); + p!(write(" upvar_tys=(")); + self = self.comma_sep(substs.as_closure().upvar_tys())?; + p!(write(")")); } } } - - if self.tcx().sess.verbose() && substs.as_closure().is_valid() { - p!(write(" closure_kind_ty="), print(substs.as_closure().kind_ty())); - p!( - write(" closure_sig_as_fn_ptr_ty="), - print(substs.as_closure().sig_as_fn_ptr_ty()) - ); - } - - p!(write("]")) + p!(write("]")); } ty::Array(ty, sz) => { p!(write("["), print(ty), write("; ")); @@ -759,7 +779,7 @@ pub trait PrettyPrinter<'tcx>: // Special-case `Fn(...) -> ...` and resugar it. let fn_trait_kind = self.tcx().fn_trait_kind_from_lang_item(principal.def_id); if !self.tcx().sess.verbose() && fn_trait_kind.is_some() { - if let ty::Tuple(ref args) = principal.substs.type_at(0).kind { + if let ty::Tuple(ref args) = principal.substs.type_at(0).kind() { let mut projections = predicates.projection_bounds(); if let (Some(proj), None) = (projections.next(), projections.next()) { let tys: Vec<_> = args.iter().map(|k| k.expect_ty()).collect(); @@ -938,7 +958,7 @@ pub trait PrettyPrinter<'tcx>: ) -> Result { define_scoped_cx!(self); - match (scalar, &ty.kind) { + match (scalar, &ty.kind()) { // Byte strings (&[u8; N]) ( Scalar::Ptr(ptr), @@ -1098,7 +1118,7 @@ pub trait PrettyPrinter<'tcx>: let u8_type = self.tcx().types.u8; - match (ct, &ty.kind) { + match (ct, ty.kind()) { // Byte/string slices, printed as (byte) string literals. ( ConstValue::Slice { data, start, end }, @@ -1151,7 +1171,7 @@ pub trait PrettyPrinter<'tcx>: ); let fields = contents.fields.iter().copied(); - match ty.kind { + match *ty.kind() { ty::Array(..) => { p!(write("["), comma_sep(fields), write("]")); } @@ -1326,6 +1346,11 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { define_scoped_cx!(self); if substs.is_empty() { + match self.try_print_trimmed_def_path(def_id)? { + (cx, true) => return Ok(cx), + (cx, false) => self = cx, + } + match self.try_print_visible_def_path(def_id)? { (cx, true) => return Ok(cx), (cx, false) => self = cx, @@ -1455,25 +1480,21 @@ impl Printer<'tcx> for FmtPrinter<'_, 'tcx, F> { // FIXME(eddyb) `name` should never be empty, but it // currently is for `extern { ... }` "foreign modules". - let name = disambiguated_data.data.as_symbol(); - if name != kw::Invalid { + let name = disambiguated_data.data.name(); + if name != DefPathDataName::Named(kw::Invalid) { if !self.empty_path { write!(self, "::")?; } - if Ident::with_dummy_span(name).is_raw_guess() { - write!(self, "r#")?; - } - write!(self, "{}", name)?; - // FIXME(eddyb) this will print e.g. `{{closure}}#3`, but it - // might be nicer to use something else, e.g. `{closure#3}`. - let dis = disambiguated_data.disambiguator; - let print_dis = disambiguated_data.data.get_opt_name().is_none() - || dis != 0 && self.tcx.sess.verbose(); - if print_dis { - write!(self, "#{}", dis)?; + if let DefPathDataName::Named(name) = name { + if Ident::with_dummy_span(name).is_raw_guess() { + write!(self, "r#")?; + } } + let verbose = self.tcx.sess.verbose(); + disambiguated_data.fmt_maybe_verbose(&mut self, verbose)?; + self.empty_path = false; } @@ -2061,6 +2082,11 @@ define_print_and_forward_display! { print(c2), write("`")) } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + p!(write("the type `"), + print(ty), + write("` is found in the environment")) + } } } @@ -2072,3 +2098,127 @@ define_print_and_forward_display! { } } } + +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.values() { + if item.ident.name.as_str().is_empty() || matches!(item.kind, ItemKind::Use(_, _)) { + continue; + } + + if let Some(local_def_id) = hir.definitions().opt_hir_id_to_local_def_id(item.hir_id) { + let def_id = local_def_id.to_def_id(); + let ns = tcx.def_kind(def_id).ns().unwrap_or(Namespace::TypeNS); + collect_fn(&item.ident, ns, def_id); + } + } + + // Now take care of extern crate items. + let queue = &mut Vec::new(); + let mut seen_defs: DefIdSet = Default::default(); + + for &cnum in tcx.crates().iter() { + let def_id = DefId { krate: cnum, index: CRATE_DEF_INDEX }; + + // Ignore crates that are not direct dependencies. + match tcx.extern_crate(def_id) { + None => continue, + Some(extern_crate) => { + if !extern_crate.is_direct() { + continue; + } + } + } + + queue.push(def_id); + } + + // Iterate external crate defs but be mindful about visibility + while let Some(def) = queue.pop() { + for child in tcx.item_children(def).iter() { + if child.vis != ty::Visibility::Public { + continue; + } + + match child.res { + def::Res::Def(DefKind::AssocTy, _) => {} + def::Res::Def(defkind, def_id) => { + if let Some(ns) = defkind.ns() { + collect_fn(&child.ident, ns, def_id); + } + + if seen_defs.insert(def_id) { + queue.push(def_id); + } + } + _ => {} + } + } + } +} + +/// The purpose of this function is to collect public symbols names that are unique across all +/// crates in the build. Later, when printing about types we can use those names instead of the +/// full exported path to them. +/// +/// So essentially, if a symbol name can only be imported from one place for a type, and as +/// long as it was not glob-imported anywhere in the current crate, we can trim its printed +/// path and print only the name. +/// +/// This has wide implications on error messages with types, for example, shortening +/// `std::vec::Vec` to just `Vec`, as long as there is no other `Vec` importable anywhere. +/// +/// The implementation uses similar import discovery logic to that of 'use' suggestions. +fn trimmed_def_paths(tcx: TyCtxt<'_>, crate_num: CrateNum) -> FxHashMap { + assert_eq!(crate_num, LOCAL_CRATE); + + let mut map = 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` + // wrapper can be used to suppress this query, in exchange for full paths being formatted. + tcx.sess.delay_good_path_bug("trimmed_def_paths constructed"); + } + + let unique_symbols_rev: &mut FxHashMap<(Namespace, Symbol), Option> = + &mut FxHashMap::default(); + + for symbol_set in tcx.glob_map.values() { + for symbol in symbol_set { + unique_symbols_rev.insert((Namespace::TypeNS, *symbol), None); + unique_symbols_rev.insert((Namespace::ValueNS, *symbol), None); + unique_symbols_rev.insert((Namespace::MacroNS, *symbol), None); + } + } + + for_each_def(tcx, |ident, ns, def_id| { + use std::collections::hash_map::Entry::{Occupied, Vacant}; + + match unique_symbols_rev.entry((ns, ident.name)) { + Occupied(mut v) => match v.get() { + None => {} + Some(existing) => { + if *existing != def_id { + v.insert(None); + } + } + }, + Vacant(v) => { + v.insert(Some(def_id)); + } + } + }); + + for ((_, symbol), opt_def_id) in unique_symbols_rev.drain() { + if let Some(def_id) = opt_def_id { + map.insert(def_id, symbol); + } + } + + map +} + +pub fn provide(providers: &mut ty::query::Providers) { + *providers = ty::query::Providers { trimmed_def_paths, ..*providers }; +} diff --git a/src/librustc_middle/ty/query/README.md b/compiler/rustc_middle/src/ty/query/README.md similarity index 100% rename from src/librustc_middle/ty/query/README.md rename to compiler/rustc_middle/src/ty/query/README.md diff --git a/src/librustc_middle/ty/query/job.rs b/compiler/rustc_middle/src/ty/query/job.rs similarity index 100% rename from src/librustc_middle/ty/query/job.rs rename to compiler/rustc_middle/src/ty/query/job.rs diff --git a/src/librustc_middle/ty/query/keys.rs b/compiler/rustc_middle/src/ty/query/keys.rs similarity index 95% rename from src/librustc_middle/ty/query/keys.rs rename to compiler/rustc_middle/src/ty/query/keys.rs index 3f7a20bba2..a005990264 100644 --- a/src/librustc_middle/ty/query/keys.rs +++ b/compiler/rustc_middle/src/ty/query/keys.rs @@ -193,6 +193,22 @@ impl<'tcx> Key for (DefId, SubstsRef<'tcx>) { } } +impl<'tcx> Key + for ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ) +{ + type CacheSelector = DefaultCacheSelector; + + fn query_crate(&self) -> CrateNum { + (self.0).0.did.krate + } + fn default_span(&self, tcx: TyCtxt<'_>) -> Span { + (self.0).0.did.default_span(tcx) + } +} + impl<'tcx> Key for (LocalDefId, DefId, SubstsRef<'tcx>) { type CacheSelector = DefaultCacheSelector; diff --git a/src/librustc_middle/ty/query/mod.rs b/compiler/rustc_middle/src/ty/query/mod.rs similarity index 99% rename from src/librustc_middle/ty/query/mod.rs rename to compiler/rustc_middle/src/ty/query/mod.rs index ee9b203b15..d3a7412ef1 100644 --- a/src/librustc_middle/ty/query/mod.rs +++ b/compiler/rustc_middle/src/ty/query/mod.rs @@ -14,7 +14,7 @@ use crate::middle::resolve_lifetime::{ObjectLifetimeDefault, Region, ResolveLife use crate::middle::stability::{self, DeprecationEntry}; use crate::mir; use crate::mir::interpret::GlobalId; -use crate::mir::interpret::{ConstEvalRawResult, ConstEvalResult, ConstValue}; +use crate::mir::interpret::{ConstValue, EvalToAllocationRawResult, EvalToConstValueResult}; use crate::mir::interpret::{LitToConstError, LitToConstInput}; use crate::mir::mono::CodegenUnit; use crate::traits::query::{ diff --git a/src/librustc_middle/ty/query/on_disk_cache.rs b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs similarity index 99% rename from src/librustc_middle/ty/query/on_disk_cache.rs rename to compiler/rustc_middle/src/ty/query/on_disk_cache.rs index dcfb8d3143..b0c48a860e 100644 --- a/src/librustc_middle/ty/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/ty/query/on_disk_cache.rs @@ -760,6 +760,12 @@ impl<'a, 'tcx> Decodable> } } +impl<'a, 'tcx> Decodable> for &'tcx [mir::abstract_const::Node<'tcx>] { + fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { + RefDecodable::decode(d) + } +} + impl<'a, 'tcx> Decodable> for &'tcx [(ty::Predicate<'tcx>, Span)] { fn decode(d: &mut CacheDecoder<'a, 'tcx>) -> Result { RefDecodable::decode(d) diff --git a/src/librustc_middle/ty/query/plumbing.rs b/compiler/rustc_middle/src/ty/query/plumbing.rs similarity index 100% rename from src/librustc_middle/ty/query/plumbing.rs rename to compiler/rustc_middle/src/ty/query/plumbing.rs diff --git a/src/librustc_middle/ty/query/profiling_support.rs b/compiler/rustc_middle/src/ty/query/profiling_support.rs similarity index 97% rename from src/librustc_middle/ty/query/profiling_support.rs rename to compiler/rustc_middle/src/ty/query/profiling_support.rs index 9b1837356e..4e8db3194b 100644 --- a/src/librustc_middle/ty/query/profiling_support.rs +++ b/compiler/rustc_middle/src/ty/query/profiling_support.rs @@ -55,18 +55,22 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { }; let dis_buffer = &mut [0u8; 16]; + let crate_name; + let other_name; let name; let dis; let end_index; match def_key.disambiguated_data.data { DefPathData::CrateRoot => { - name = self.tcx.original_crate_name(def_id.krate); + crate_name = self.tcx.original_crate_name(def_id.krate).as_str(); + name = &*crate_name; dis = ""; end_index = 3; } other => { - name = other.as_symbol(); + other_name = other.to_string(); + name = other_name.as_str(); if def_key.disambiguated_data.disambiguator == 0 { dis = ""; end_index = 3; @@ -80,7 +84,6 @@ impl<'p, 'c, 'tcx> QueryKeyStringBuilder<'p, 'c, 'tcx> { } } - let name = &*name.as_str(); let components = [ StringComponent::Ref(parent_string_id), StringComponent::Value("::"), diff --git a/src/librustc_middle/ty/query/stats.rs b/compiler/rustc_middle/src/ty/query/stats.rs similarity index 100% rename from src/librustc_middle/ty/query/stats.rs rename to compiler/rustc_middle/src/ty/query/stats.rs diff --git a/src/librustc_middle/ty/query/values.rs b/compiler/rustc_middle/src/ty/query/values.rs similarity index 100% rename from src/librustc_middle/ty/query/values.rs rename to compiler/rustc_middle/src/ty/query/values.rs diff --git a/src/librustc_middle/ty/relate.rs b/compiler/rustc_middle/src/ty/relate.rs similarity index 97% rename from src/librustc_middle/ty/relate.rs rename to compiler/rustc_middle/src/ty/relate.rs index ae2820b460..c4df0bba72 100644 --- a/src/librustc_middle/ty/relate.rs +++ b/compiler/rustc_middle/src/ty/relate.rs @@ -325,7 +325,7 @@ pub fn super_relate_tys>( ) -> RelateResult<'tcx, Ty<'tcx>> { let tcx = relation.tcx(); debug!("super_relate_tys: a={:?} b={:?}", a, b); - match (&a.kind, &b.kind) { + match (a.kind(), b.kind()) { (&ty::Infer(_), _) | (_, &ty::Infer(_)) => { // The caller should handle these cases! bug!("var types encountered in super_relate_tys") @@ -516,7 +516,7 @@ pub fn super_relate_consts>( (ConstValue::Scalar(a_val), ConstValue::Scalar(b_val)) if a.ty == b.ty => { if a_val == b_val { Ok(ConstValue::Scalar(a_val)) - } else if let ty::FnPtr(_) = a.ty.kind { + } else if let ty::FnPtr(_) = a.ty.kind() { let a_instance = tcx.global_alloc(a_val.assert_ptr().alloc_id).unwrap_fn(); let b_instance = tcx.global_alloc(b_val.assert_ptr().alloc_id).unwrap_fn(); if a_instance == b_instance { @@ -540,7 +540,7 @@ pub fn super_relate_consts>( } (ConstValue::ByRef { .. }, ConstValue::ByRef { .. }) => { - match a.ty.kind { + match a.ty.kind() { ty::Array(..) | ty::Adt(..) | ty::Tuple(..) => { let a_destructured = tcx.destructure_const(relation.param_env().and(a)); let b_destructured = tcx.destructure_const(relation.param_env().and(b)); @@ -576,7 +576,20 @@ pub fn super_relate_consts>( new_val.map(ty::ConstKind::Value) } - // FIXME(const_generics): this is wrong, as it is a projection + ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) if tcx.features().const_evaluatable_checked => { + if tcx.try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) { + Ok(a.val) + } else { + Err(TypeError::ConstMismatch(expected_found(relation, a, b))) + } + } + + // While this is slightly incorrect, it shouldn't matter for `min_const_generics` + // and is the better alternative to waiting until `const_evaluatable_checked` can + // be stabilized. ( ty::ConstKind::Unevaluated(a_def, a_substs, a_promoted), ty::ConstKind::Unevaluated(b_def, b_substs, b_promoted), diff --git a/src/librustc_middle/ty/steal.rs b/compiler/rustc_middle/src/ty/steal.rs similarity index 100% rename from src/librustc_middle/ty/steal.rs rename to compiler/rustc_middle/src/ty/steal.rs diff --git a/src/librustc_middle/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs similarity index 96% rename from src/librustc_middle/ty/structural_impls.rs rename to compiler/rustc_middle/src/ty/structural_impls.rs index 605e3545de..597ceac938 100644 --- a/src/librustc_middle/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -5,7 +5,7 @@ use crate::mir::interpret; use crate::mir::ProjectionKind; use crate::ty::fold::{TypeFoldable, TypeFolder, TypeVisitor}; -use crate::ty::print::{FmtPrinter, Printer}; +use crate::ty::print::{with_no_trimmed_paths, FmtPrinter, Printer}; use crate::ty::{self, InferConst, Lift, Ty, TyCtxt}; use rustc_hir as hir; use rustc_hir::def::Namespace; @@ -20,7 +20,9 @@ use std::sync::Arc; impl fmt::Debug for ty::TraitDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { - FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.def_id, &[])?; + with_no_trimmed_paths(|| { + FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.def_id, &[]) + })?; Ok(()) }) } @@ -29,7 +31,9 @@ impl fmt::Debug for ty::TraitDef { impl fmt::Debug for ty::AdtDef { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { ty::tls::with(|tcx| { - FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.did, &[])?; + with_no_trimmed_paths(|| { + FmtPrinter::new(tcx, f, Namespace::TypeNS).print_def_path(self.did, &[]) + })?; Ok(()) }) } @@ -50,7 +54,7 @@ impl fmt::Debug for ty::UpvarBorrow<'tcx> { impl fmt::Debug for ty::ExistentialTraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + with_no_trimmed_paths(|| fmt::Display::fmt(self, f)) } } @@ -183,13 +187,13 @@ impl fmt::Debug for ty::FloatVarValue { impl fmt::Debug for ty::TraitRef<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + with_no_trimmed_paths(|| fmt::Display::fmt(self, f)) } } impl fmt::Debug for Ty<'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - fmt::Display::fmt(self, f) + with_no_trimmed_paths(|| fmt::Display::fmt(self, f)) } } @@ -256,6 +260,9 @@ impl fmt::Debug for ty::PredicateAtom<'tcx> { write!(f, "ConstEvaluatable({:?}, {:?})", def_id, substs) } ty::PredicateAtom::ConstEquate(c1, c2) => write!(f, "ConstEquate({:?}, {:?})", c1, c2), + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + write!(f, "TypeWellFormedFromEnv({:?})", ty) + } } } } @@ -532,6 +539,9 @@ impl<'a, 'tcx> Lift<'tcx> for ty::PredicateAtom<'a> { ty::PredicateAtom::ConstEquate(c1, c2) => { tcx.lift(&(c1, c2)).map(|(c1, c2)| ty::PredicateAtom::ConstEquate(c1, c2)) } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + tcx.lift(&ty).map(ty::PredicateAtom::TypeWellFormedFromEnv) + } } } } @@ -547,7 +557,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::ParamEnv<'a> { type Lifted = ty::ParamEnv<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { tcx.lift(&self.caller_bounds()) - .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal(), self.def_id)) + .map(|caller_bounds| ty::ParamEnv::new(caller_bounds, self.reveal())) } } @@ -602,8 +612,11 @@ impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::Adjust<'a> { impl<'a, 'tcx> Lift<'tcx> for ty::adjustment::OverloadedDeref<'a> { type Lifted = ty::adjustment::OverloadedDeref<'tcx>; fn lift_to_tcx(&self, tcx: TyCtxt<'tcx>) -> Option { - tcx.lift(&self.region) - .map(|region| ty::adjustment::OverloadedDeref { region, mutbl: self.mutbl }) + tcx.lift(&self.region).map(|region| ty::adjustment::OverloadedDeref { + region, + mutbl: self.mutbl, + span: self.span, + }) } } @@ -676,6 +689,7 @@ impl<'a, 'tcx> Lift<'tcx> for ty::error::TypeError<'a> { Traits(x) => Traits(x), VariadicMismatch(x) => VariadicMismatch(x), CyclicTy(t) => return tcx.lift(&t).map(|t| CyclicTy(t)), + CyclicConst(ct) => return tcx.lift(&ct).map(|ct| CyclicConst(ct)), ProjectionMismatched(x) => ProjectionMismatched(x), Sorts(ref x) => return tcx.lift(x).map(Sorts), ExistentialMismatch(ref x) => return tcx.lift(x).map(ExistentialMismatch), @@ -919,25 +933,25 @@ impl<'tcx> TypeFoldable<'tcx> for interpret::GlobalId<'tcx> { impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { fn super_fold_with>(&self, folder: &mut F) -> Self { - let kind = match self.kind { + let kind = match self.kind() { ty::RawPtr(tm) => ty::RawPtr(tm.fold_with(folder)), ty::Array(typ, sz) => ty::Array(typ.fold_with(folder), sz.fold_with(folder)), ty::Slice(typ) => ty::Slice(typ.fold_with(folder)), - ty::Adt(tid, substs) => ty::Adt(tid, substs.fold_with(folder)), + ty::Adt(tid, substs) => ty::Adt(*tid, substs.fold_with(folder)), ty::Dynamic(ref trait_ty, ref region) => { ty::Dynamic(trait_ty.fold_with(folder), region.fold_with(folder)) } ty::Tuple(ts) => ty::Tuple(ts.fold_with(folder)), - ty::FnDef(def_id, substs) => ty::FnDef(def_id, substs.fold_with(folder)), + ty::FnDef(def_id, substs) => ty::FnDef(*def_id, substs.fold_with(folder)), ty::FnPtr(f) => ty::FnPtr(f.fold_with(folder)), - ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), mutbl), + ty::Ref(ref r, ty, mutbl) => ty::Ref(r.fold_with(folder), ty.fold_with(folder), *mutbl), ty::Generator(did, substs, movability) => { - ty::Generator(did, substs.fold_with(folder), movability) + ty::Generator(*did, substs.fold_with(folder), *movability) } ty::GeneratorWitness(types) => ty::GeneratorWitness(types.fold_with(folder)), - ty::Closure(did, substs) => ty::Closure(did, substs.fold_with(folder)), + ty::Closure(did, substs) => ty::Closure(*did, substs.fold_with(folder)), ty::Projection(ref data) => ty::Projection(data.fold_with(folder)), - ty::Opaque(did, substs) => ty::Opaque(did, substs.fold_with(folder)), + ty::Opaque(did, substs) => ty::Opaque(*did, substs.fold_with(folder)), ty::Bool | ty::Char @@ -954,7 +968,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { | ty::Foreign(..) => return self, }; - if self.kind == kind { self } else { folder.tcx().mk_ty(kind) } + if *self.kind() == kind { self } else { folder.tcx().mk_ty(kind) } } fn fold_with>(&self, folder: &mut F) -> Self { @@ -962,7 +976,7 @@ impl<'tcx> TypeFoldable<'tcx> for Ty<'tcx> { } fn super_visit_with>(&self, visitor: &mut V) -> bool { - match self.kind { + match self.kind() { ty::RawPtr(ref tm) => tm.visit_with(visitor), ty::Array(typ, sz) => typ.visit_with(visitor) || sz.visit_with(visitor), ty::Slice(typ) => typ.visit_with(visitor), diff --git a/src/librustc_middle/ty/sty.rs b/compiler/rustc_middle/src/ty/sty.rs similarity index 95% rename from src/librustc_middle/ty/sty.rs rename to compiler/rustc_middle/src/ty/sty.rs index c1f354c7a1..724ec101b2 100644 --- a/src/librustc_middle/ty/sty.rs +++ b/compiler/rustc_middle/src/ty/sty.rs @@ -367,7 +367,8 @@ impl<'tcx> ClosureSubsts<'tcx> { /// Used primarily by `ty::print::pretty` to be able to handle closure /// types that haven't had their synthetic types substituted in. pub fn is_valid(self) -> bool { - self.substs.len() >= 3 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_)) + self.substs.len() >= 3 + && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_)) } /// Returns the substitutions of the closure's parent. @@ -414,9 +415,9 @@ impl<'tcx> ClosureSubsts<'tcx> { /// Extracts the signature from the closure. pub fn sig(self) -> ty::PolyFnSig<'tcx> { let ty = self.sig_as_fn_ptr_ty(); - match ty.kind { - ty::FnPtr(sig) => sig, - _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind), + match ty.kind() { + ty::FnPtr(sig) => *sig, + _ => bug!("closure_sig_as_fn_ptr_ty is not a fn-ptr: {:?}", ty.kind()), } } } @@ -484,7 +485,8 @@ impl<'tcx> GeneratorSubsts<'tcx> { /// Used primarily by `ty::print::pretty` to be able to handle generator /// types that haven't had their synthetic types substituted in. pub fn is_valid(self) -> bool { - self.substs.len() >= 5 && matches!(self.split().tupled_upvars_ty.expect_ty().kind, Tuple(_)) + self.substs.len() >= 5 + && matches!(self.split().tupled_upvars_ty.expect_ty().kind(), Tuple(_)) } /// Returns the substitutions of the generator's parent. @@ -1231,13 +1233,13 @@ rustc_index::newtype_index! { /// particular, imagine a type like this: /// /// for<'a> fn(for<'b> fn(&'b isize, &'a isize), &'a char) - /// ^ ^ | | | - /// | | | | | - /// | +------------+ 0 | | - /// | | | - /// +--------------------------------+ 1 | - /// | | - /// +------------------------------------------+ 0 + /// ^ ^ | | | + /// | | | | | + /// | +------------+ 0 | | + /// | | | + /// +----------------------------------+ 1 | + /// | | + /// +----------------------------------------------+ 0 /// /// In this type, there are two binders (the outer fn and the inner /// fn). We need to be able to determine, for any given region, which @@ -1741,9 +1743,19 @@ impl RegionKind { /// Type utilities impl<'tcx> TyS<'tcx> { + #[inline(always)] + pub fn kind(&self) -> &TyKind<'tcx> { + &self.kind + } + + #[inline(always)] + pub fn flags(&self) -> TypeFlags { + self.flags + } + #[inline] pub fn is_unit(&self) -> bool { - match self.kind { + match self.kind() { Tuple(ref tys) => tys.is_empty(), _ => false, } @@ -1751,7 +1763,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_never(&self) -> bool { - match self.kind { + match self.kind() { Never => true, _ => false, } @@ -1766,7 +1778,7 @@ impl<'tcx> TyS<'tcx> { pub fn conservative_is_privately_uninhabited(&self, tcx: TyCtxt<'tcx>) -> bool { // FIXME(varkor): we can make this less conversative by substituting concrete // type arguments. - match self.kind { + match self.kind() { ty::Never => true, ty::Adt(def, _) if def.is_union() => { // For now, `union`s are never considered uninhabited. @@ -1806,12 +1818,28 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_primitive(&self) -> bool { - self.kind.is_primitive() + self.kind().is_primitive() + } + + #[inline] + pub fn is_adt(&self) -> bool { + match self.kind() { + Adt(..) => true, + _ => false, + } + } + + #[inline] + pub fn is_ref(&self) -> bool { + match self.kind() { + Ref(..) => true, + _ => false, + } } #[inline] pub fn is_ty_var(&self) -> bool { - match self.kind { + match self.kind() { Infer(TyVar(_)) => true, _ => false, } @@ -1819,7 +1847,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_ty_infer(&self) -> bool { - match self.kind { + match self.kind() { Infer(_) => true, _ => false, } @@ -1827,23 +1855,23 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_phantom_data(&self) -> bool { - if let Adt(def, _) = self.kind { def.is_phantom_data() } else { false } + if let Adt(def, _) = self.kind() { def.is_phantom_data() } else { false } } #[inline] pub fn is_bool(&self) -> bool { - self.kind == Bool + *self.kind() == Bool } /// Returns `true` if this type is a `str`. #[inline] pub fn is_str(&self) -> bool { - self.kind == Str + *self.kind() == Str } #[inline] pub fn is_param(&self, index: u32) -> bool { - match self.kind { + match self.kind() { ty::Param(ref data) => data.index == index, _ => false, } @@ -1851,8 +1879,8 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_slice(&self) -> bool { - match self.kind { - RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind { + match self.kind() { + RawPtr(TypeAndMut { ty, .. }) | Ref(_, ty, _) => match ty.kind() { Slice(_) | Str => true, _ => false, }, @@ -1860,16 +1888,24 @@ impl<'tcx> TyS<'tcx> { } } + #[inline] + pub fn is_array(&self) -> bool { + match self.kind() { + Array(..) => true, + _ => false, + } + } + #[inline] pub fn is_simd(&self) -> bool { - match self.kind { + match self.kind() { Adt(def, _) => def.repr.simd(), _ => false, } } pub fn sequence_element_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { + match self.kind() { Array(ty, _) | Slice(ty) => ty, Str => tcx.mk_mach_uint(ast::UintTy::U8), _ => bug!("`sequence_element_type` called on non-sequence value: {}", self), @@ -1877,7 +1913,7 @@ impl<'tcx> TyS<'tcx> { } pub fn simd_type(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { + match self.kind() { Adt(def, substs) => def.non_enum_variant().fields[0].ty(tcx, substs), _ => bug!("`simd_type` called on invalid type"), } @@ -1886,14 +1922,14 @@ impl<'tcx> TyS<'tcx> { pub fn simd_size(&self, _tcx: TyCtxt<'tcx>) -> u64 { // Parameter currently unused, but probably needed in the future to // allow `#[repr(simd)] struct Simd([T; N]);`. - match self.kind { + match self.kind() { Adt(def, _) => def.non_enum_variant().fields.len() as u64, _ => bug!("`simd_size` called on invalid type"), } } pub fn simd_size_and_type(&self, tcx: TyCtxt<'tcx>) -> (u64, Ty<'tcx>) { - match self.kind { + match self.kind() { Adt(def, substs) => { let variant = def.non_enum_variant(); (variant.fields.len() as u64, variant.fields[0].ty(tcx, substs)) @@ -1904,7 +1940,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_region_ptr(&self) -> bool { - match self.kind { + match self.kind() { Ref(..) => true, _ => false, } @@ -1912,7 +1948,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_mutable_ptr(&self) -> bool { - match self.kind { + match self.kind() { RawPtr(TypeAndMut { mutbl: hir::Mutability::Mut, .. }) | Ref(_, _, hir::Mutability::Mut) => true, _ => false, @@ -1921,7 +1957,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_unsafe_ptr(&self) -> bool { - match self.kind { + match self.kind() { RawPtr(_) => true, _ => false, } @@ -1935,7 +1971,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_box(&self) -> bool { - match self.kind { + match self.kind() { Adt(def, _) => def.is_box(), _ => false, } @@ -1943,7 +1979,7 @@ impl<'tcx> TyS<'tcx> { /// Panics if called on any type other than `Box`. pub fn boxed_ty(&self) -> Ty<'tcx> { - match self.kind { + match self.kind() { Adt(def, substs) if def.is_box() => substs.type_at(0), _ => bug!("`boxed_ty` is called on non-box type {:?}", self), } @@ -1954,7 +1990,7 @@ impl<'tcx> TyS<'tcx> { /// contents are abstract to rustc.) #[inline] pub fn is_scalar(&self) -> bool { - match self.kind { + match self.kind() { Bool | Char | Int(_) @@ -1971,7 +2007,7 @@ impl<'tcx> TyS<'tcx> { /// Returns `true` if this type is a floating point type. #[inline] pub fn is_floating_point(&self) -> bool { - match self.kind { + match self.kind() { Float(_) | Infer(FloatVar(_)) => true, _ => false, } @@ -1979,7 +2015,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_trait(&self) -> bool { - match self.kind { + match self.kind() { Dynamic(..) => true, _ => false, } @@ -1987,7 +2023,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_enum(&self) -> bool { - match self.kind { + match self.kind() { Adt(adt_def, _) => adt_def.is_enum(), _ => false, } @@ -1995,7 +2031,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_closure(&self) -> bool { - match self.kind { + match self.kind() { Closure(..) => true, _ => false, } @@ -2003,7 +2039,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_generator(&self) -> bool { - match self.kind { + match self.kind() { Generator(..) => true, _ => false, } @@ -2011,7 +2047,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_integral(&self) -> bool { - match self.kind { + match self.kind() { Infer(IntVar(_)) | Int(_) | Uint(_) => true, _ => false, } @@ -2019,7 +2055,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fresh_ty(&self) -> bool { - match self.kind { + match self.kind() { Infer(FreshTy(_)) => true, _ => false, } @@ -2027,7 +2063,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fresh(&self) -> bool { - match self.kind { + match self.kind() { Infer(FreshTy(_)) => true, Infer(FreshIntTy(_)) => true, Infer(FreshFloatTy(_)) => true, @@ -2037,7 +2073,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_char(&self) -> bool { - match self.kind { + match self.kind() { Char => true, _ => false, } @@ -2050,7 +2086,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_signed(&self) -> bool { - match self.kind { + match self.kind() { Int(_) => true, _ => false, } @@ -2058,7 +2094,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_ptr_sized_integral(&self) -> bool { - match self.kind { + match self.kind() { Int(ast::IntTy::Isize) | Uint(ast::UintTy::Usize) => true, _ => false, } @@ -2066,7 +2102,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_machine(&self) -> bool { - match self.kind { + match self.kind() { Int(..) | Uint(..) | Float(..) => true, _ => false, } @@ -2074,7 +2110,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn has_concrete_skeleton(&self) -> bool { - match self.kind { + match self.kind() { Param(_) | Infer(_) | Error(_) => false, _ => true, } @@ -2085,28 +2121,28 @@ impl<'tcx> TyS<'tcx> { /// The parameter `explicit` indicates if this is an *explicit* dereference. /// Some types -- notably unsafe ptrs -- can only be dereferenced explicitly. pub fn builtin_deref(&self, explicit: bool) -> Option> { - match self.kind { + match self.kind() { Adt(def, _) if def.is_box() => { Some(TypeAndMut { ty: self.boxed_ty(), mutbl: hir::Mutability::Not }) } - Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl }), - RawPtr(mt) if explicit => Some(mt), + Ref(_, ty, mutbl) => Some(TypeAndMut { ty, mutbl: *mutbl }), + RawPtr(mt) if explicit => Some(*mt), _ => None, } } /// Returns the type of `ty[i]`. pub fn builtin_index(&self) -> Option> { - match self.kind { + match self.kind() { Array(ty, _) | Slice(ty) => Some(ty), _ => None, } } pub fn fn_sig(&self, tcx: TyCtxt<'tcx>) -> PolyFnSig<'tcx> { - match self.kind { - FnDef(def_id, substs) => tcx.fn_sig(def_id).subst(tcx, substs), - FnPtr(f) => f, + match self.kind() { + FnDef(def_id, substs) => tcx.fn_sig(*def_id).subst(tcx, substs), + FnPtr(f) => *f, Error(_) => { // ignore errors (#54954) ty::Binder::dummy(FnSig::fake()) @@ -2120,7 +2156,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fn(&self) -> bool { - match self.kind { + match self.kind() { FnDef(..) | FnPtr(_) => true, _ => false, } @@ -2128,7 +2164,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_fn_ptr(&self) -> bool { - match self.kind { + match self.kind() { FnPtr(_) => true, _ => false, } @@ -2136,7 +2172,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn is_impl_trait(&self) -> bool { - match self.kind { + match self.kind() { Opaque(..) => true, _ => false, } @@ -2144,7 +2180,7 @@ impl<'tcx> TyS<'tcx> { #[inline] pub fn ty_adt_def(&self) -> Option<&'tcx AdtDef> { - match self.kind { + match self.kind() { Adt(adt, _) => Some(adt), _ => None, } @@ -2153,7 +2189,7 @@ impl<'tcx> TyS<'tcx> { /// Iterates over tuple fields. /// Panics when called on anything but a tuple. pub fn tuple_fields(&self) -> impl DoubleEndedIterator> { - match self.kind { + match self.kind() { Tuple(substs) => substs.iter().map(|field| field.expect_ty()), _ => bug!("tuple_fields called on non-tuple"), } @@ -2164,10 +2200,10 @@ impl<'tcx> TyS<'tcx> { // FIXME: This requires the optimized MIR in the case of generators. #[inline] pub fn variant_range(&self, tcx: TyCtxt<'tcx>) -> Option> { - match self.kind { + match self.kind() { TyKind::Adt(adt, _) => Some(adt.variant_range()), TyKind::Generator(def_id, substs, _) => { - Some(substs.as_generator().variant_range(def_id, tcx)) + Some(substs.as_generator().variant_range(*def_id, tcx)) } _ => None, } @@ -2183,7 +2219,7 @@ impl<'tcx> TyS<'tcx> { tcx: TyCtxt<'tcx>, variant_index: VariantIdx, ) -> Option> { - match self.kind { + match self.kind() { TyKind::Adt(adt, _) if adt.variants.is_empty() => { bug!("discriminant_for_variant called on zero variant enum"); } @@ -2191,7 +2227,7 @@ impl<'tcx> TyS<'tcx> { Some(adt.discriminant_for_variant(tcx, variant_index)) } TyKind::Generator(def_id, substs, _) => { - Some(substs.as_generator().discriminant_for_variant(def_id, tcx, variant_index)) + Some(substs.as_generator().discriminant_for_variant(*def_id, tcx, variant_index)) } _ => None, } @@ -2199,7 +2235,7 @@ impl<'tcx> TyS<'tcx> { /// Returns the type of the discriminant of this type. pub fn discriminant_ty(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx> { - match self.kind { + match self.kind() { ty::Adt(adt, _) if adt.is_enum() => adt.repr.discr_type().to_ty(tcx), ty::Generator(_, substs, _) => substs.as_generator().discr_ty(tcx), _ => { @@ -2222,7 +2258,7 @@ impl<'tcx> TyS<'tcx> { /// inferred. Once upvar inference (in `src/librustc_typeck/check/upvar.rs`) /// is complete, that type variable will be unified. pub fn to_opt_closure_kind(&self) -> Option { - match self.kind { + match self.kind() { Int(int_ty) => match int_ty { ast::IntTy::I8 => Some(ty::ClosureKind::Fn), ast::IntTy::I16 => Some(ty::ClosureKind::FnMut), @@ -2244,8 +2280,14 @@ impl<'tcx> TyS<'tcx> { /// /// Returning true means the type is known to be sized. Returning /// `false` means nothing -- could be sized, might not be. + /// + /// Note that we could never rely on the fact that a type such as `[_]` is + /// trivially `!Sized` because we could be in a type environment with a + /// bound such as `[_]: Copy`. A function with such a bound obviously never + /// can be called, but that doesn't mean it shouldn't typecheck. This is why + /// this method doesn't return `Option`. pub fn is_trivially_sized(&self, tcx: TyCtxt<'tcx>) -> bool { - match self.kind { + match self.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) | ty::Int(_) @@ -2280,9 +2322,4 @@ impl<'tcx> TyS<'tcx> { } } } - - /// Is this a zero-sized type? - pub fn is_zst(&'tcx self, tcx: TyCtxt<'tcx>, did: DefId) -> bool { - tcx.layout_of(tcx.param_env(did).and(self)).map(|layout| layout.is_zst()).unwrap_or(false) - } } diff --git a/src/librustc_middle/ty/subst.rs b/compiler/rustc_middle/src/ty/subst.rs similarity index 99% rename from src/librustc_middle/ty/subst.rs rename to compiler/rustc_middle/src/ty/subst.rs index acd58ab7f9..1bd3bcb6a4 100644 --- a/src/librustc_middle/ty/subst.rs +++ b/compiler/rustc_middle/src/ty/subst.rs @@ -486,7 +486,7 @@ impl<'a, 'tcx> TypeFolder<'tcx> for SubstFolder<'a, 'tcx> { return t; } - match t.kind { + match *t.kind() { ty::Param(p) => self.ty_for_param(p, t), _ => t.super_fold_with(self), } diff --git a/src/librustc_middle/ty/trait_def.rs b/compiler/rustc_middle/src/ty/trait_def.rs similarity index 99% rename from src/librustc_middle/ty/trait_def.rs rename to compiler/rustc_middle/src/ty/trait_def.rs index 86fe3ac375..9d5b558234 100644 --- a/src/librustc_middle/ty/trait_def.rs +++ b/compiler/rustc_middle/src/ty/trait_def.rs @@ -167,7 +167,7 @@ impl<'tcx> TyCtxt<'tcx> { } } - /// Returns a vector containing all impls + /// Returns an iterator containing all impls pub fn all_impls(self, def_id: DefId) -> impl Iterator + 'tcx { let TraitImpls { blanket_impls, non_blanket_impls } = self.trait_impls_of(def_id); diff --git a/src/librustc_middle/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs similarity index 97% rename from src/librustc_middle/ty/util.rs rename to compiler/rustc_middle/src/ty/util.rs index 63d4dcca08..4127b6535b 100644 --- a/src/librustc_middle/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -33,7 +33,7 @@ pub struct Discr<'tcx> { impl<'tcx> fmt::Display for Discr<'tcx> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.ty.kind { + match *self.ty.kind() { ty::Int(ity) => { let size = ty::tls::with(|tcx| Integer::from_attr(&tcx, SignedInt(ity)).size()); let x = self.val; @@ -59,7 +59,7 @@ fn unsigned_max(size: Size) -> u128 { } fn int_size_and_signed<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> (Size, bool) { - let (int, signed) = match ty.kind { + let (int, signed) = match *ty.kind() { Int(ity) => (Integer::from_attr(&tcx, SignedInt(ity)), true), Uint(uty) => (Integer::from_attr(&tcx, UnsignedInt(uty)), false), _ => bug!("non integer discriminant"), @@ -170,14 +170,12 @@ impl<'tcx> TyCtxt<'tcx> { }); hasher.finish() } -} -impl<'tcx> TyCtxt<'tcx> { pub fn has_error_field(self, ty: Ty<'tcx>) -> bool { - if let ty::Adt(def, substs) = ty.kind { + if let ty::Adt(def, substs) = *ty.kind() { for field in def.all_fields() { let field_ty = field.ty(self, substs); - if let Error(_) = field_ty.kind { + if let Error(_) = field_ty.kind() { return true; } } @@ -225,7 +223,7 @@ impl<'tcx> TyCtxt<'tcx> { normalize: impl Fn(Ty<'tcx>) -> Ty<'tcx>, ) -> Ty<'tcx> { loop { - match ty.kind { + match *ty.kind() { ty::Adt(def, substs) => { if !def.is_struct() { break; @@ -298,7 +296,7 @@ impl<'tcx> TyCtxt<'tcx> { ) -> (Ty<'tcx>, Ty<'tcx>) { let (mut a, mut b) = (source, target); loop { - match (&a.kind, &b.kind) { + match (&a.kind(), &b.kind()) { (&Adt(a_def, a_substs), &Adt(b_def, b_substs)) if a_def == b_def && a_def.is_struct() => { @@ -401,12 +399,12 @@ impl<'tcx> TyCtxt<'tcx> { // , and then look up which of the impl substs refer to // parameters marked as pure. - let impl_substs = match self.type_of(impl_def_id).kind { + let impl_substs = match *self.type_of(impl_def_id).kind() { ty::Adt(def_, substs) if def_ == def => substs, _ => bug!(), }; - let item_substs = match self.type_of(def.did).kind { + let item_substs = match *self.type_of(def.did).kind() { ty::Adt(def_, substs) if def_ == def => substs, _ => bug!(), }; @@ -526,22 +524,22 @@ impl<'tcx> TyCtxt<'tcx> { } /// Returns `true` if the node pointed to by `def_id` is a `static` item. - pub fn is_static(&self, def_id: DefId) -> bool { + pub fn is_static(self, def_id: DefId) -> bool { self.static_mutability(def_id).is_some() } /// Returns `true` if this is a `static` item with the `#[thread_local]` attribute. - pub fn is_thread_local_static(&self, def_id: DefId) -> bool { + pub fn is_thread_local_static(self, def_id: DefId) -> bool { self.codegen_fn_attrs(def_id).flags.contains(CodegenFnAttrFlags::THREAD_LOCAL) } /// Returns `true` if the node pointed to by `def_id` is a mutable `static` item. - pub fn is_mutable_static(&self, def_id: DefId) -> bool { + pub fn is_mutable_static(self, def_id: DefId) -> bool { self.static_mutability(def_id) == Some(hir::Mutability::Mut) } /// Get the type of the pointer to the static that we use in MIR. - pub fn static_ptr_ty(&self, def_id: DefId) -> Ty<'tcx> { + pub fn static_ptr_ty(self, def_id: DefId) -> Ty<'tcx> { // Make sure that any constants in the static's type are evaluated. let static_ty = self.normalize_erasing_regions(ty::ParamEnv::empty(), self.type_of(def_id)); @@ -640,7 +638,7 @@ impl<'tcx> ty::TyS<'tcx> { /// Returns the maximum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. pub fn numeric_max_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind { + 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) }; @@ -659,7 +657,7 @@ impl<'tcx> ty::TyS<'tcx> { /// Returns the minimum value for the given numeric type (including `char`s) /// or returns `None` if the type is not numeric. pub fn numeric_min_val(&'tcx self, tcx: TyCtxt<'tcx>) -> Option<&'tcx ty::Const<'tcx>> { - let val = match self.kind { + let val = match self.kind() { ty::Int(_) | ty::Uint(_) => { let (size, signed) = int_size_and_signed(tcx, self); let val = if signed { truncate(signed_min(size) as u128, size) } else { 0 }; @@ -717,7 +715,7 @@ impl<'tcx> ty::TyS<'tcx> { /// Returning true means the type is known to be `Freeze`. Returning /// `false` means nothing -- could be `Freeze`, might not be. fn is_trivially_freeze(&self) -> bool { - match self.kind { + match self.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) @@ -793,7 +791,7 @@ impl<'tcx> ty::TyS<'tcx> { /// down, you will need to use a type visitor. #[inline] pub fn is_structural_eq_shallow(&'tcx self, tcx: TyCtxt<'tcx>) -> bool { - match self.kind { + match self.kind() { // Look for an impl of both `PartialStructuralEq` and `StructuralEq`. Adt(..) => tcx.has_structural_eq_impls(self), @@ -828,7 +826,7 @@ impl<'tcx> ty::TyS<'tcx> { } pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool { - match (&a.kind, &b.kind) { + match (&a.kind(), &b.kind()) { (&Adt(did_a, substs_a), &Adt(did_b, substs_b)) => { if did_a != did_b { return false; @@ -860,7 +858,7 @@ impl<'tcx> ty::TyS<'tcx> { representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, ) -> Representability { - match ty.kind { + match ty.kind() { Tuple(..) => { // Find non representable fold_repr(ty.tuple_fields().map(|ty| { @@ -909,7 +907,7 @@ impl<'tcx> ty::TyS<'tcx> { } fn same_struct_or_enum<'tcx>(ty: Ty<'tcx>, def: &'tcx ty::AdtDef) -> bool { - match ty.kind { + match *ty.kind() { Adt(ty_def, _) => ty_def == def, _ => false, } @@ -947,7 +945,7 @@ impl<'tcx> ty::TyS<'tcx> { representable_cache: &mut FxHashMap, Representability>, ty: Ty<'tcx>, ) -> Representability { - match ty.kind { + match ty.kind() { Adt(def, _) => { { // Iterate through stack of previously seen types. @@ -962,7 +960,7 @@ impl<'tcx> ty::TyS<'tcx> { // struct Bar { x: Bar } if let Some(&seen_type) = iter.next() { - if same_struct_or_enum(seen_type, def) { + if same_struct_or_enum(seen_type, *def) { debug!("SelfRecursive: {:?} contains {:?}", seen_type, ty); return Representability::SelfRecursive(vec![sp]); } @@ -1024,7 +1022,7 @@ impl<'tcx> ty::TyS<'tcx> { /// - `&'a *const &'b u8 -> *const &'b u8` pub fn peel_refs(&'tcx self) -> Ty<'tcx> { let mut ty = self; - while let Ref(_, inner_ty, _) = ty.kind { + while let Ref(_, inner_ty, _) = ty.kind() { ty = inner_ty; } ty @@ -1070,7 +1068,7 @@ impl<'tcx> ExplicitSelf<'tcx> { { use self::ExplicitSelf::*; - match self_arg_ty.kind { + match *self_arg_ty.kind() { _ if is_self_ty(self_arg_ty) => ByValue, ty::Ref(region, ty, mutbl) if is_self_ty(ty) => ByReference(region, mutbl), ty::RawPtr(ty::TypeAndMut { ty, mutbl }) if is_self_ty(ty) => ByRawPointer(mutbl), @@ -1087,7 +1085,7 @@ pub fn needs_drop_components( ty: Ty<'tcx>, target_layout: &TargetDataLayout, ) -> Result; 2]>, AlwaysRequiresDrop> { - match ty.kind { + match ty.kind() { ty::Infer(ty::FreshIntTy(_)) | ty::Infer(ty::FreshFloatTy(_)) | ty::Bool diff --git a/src/librustc_middle/ty/walk.rs b/compiler/rustc_middle/src/ty/walk.rs similarity index 83% rename from src/librustc_middle/ty/walk.rs rename to compiler/rustc_middle/src/ty/walk.rs index 024f655eb6..80ade7dda4 100644 --- a/src/librustc_middle/ty/walk.rs +++ b/compiler/rustc_middle/src/ty/walk.rs @@ -3,50 +3,8 @@ use crate::ty; use crate::ty::subst::{GenericArg, GenericArgKind}; -use arrayvec::ArrayVec; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::mini_set::MiniSet; use smallvec::{self, SmallVec}; -use std::hash::Hash; - -/// Small-storage-optimized implementation of a set -/// made specifically for walking type tree. -/// -/// Stores elements in a small array up to a certain length -/// and switches to `HashSet` when that length is exceeded. -pub enum MiniSet { - Array(ArrayVec<[T; 8]>), - Set(FxHashSet), -} - -impl MiniSet { - /// Creates an empty `MiniSet`. - pub fn new() -> Self { - MiniSet::Array(ArrayVec::new()) - } - - /// Adds a value to the set. - /// - /// If the set did not have this value present, true is returned. - /// - /// If the set did have this value present, false is returned. - pub fn insert(&mut self, elem: T) -> bool { - match self { - MiniSet::Array(array) => { - if array.iter().any(|e| *e == elem) { - false - } else { - if array.try_push(elem).is_err() { - let mut set: FxHashSet = array.iter().copied().collect(); - set.insert(elem); - *self = MiniSet::Set(set); - } - true - } - } - MiniSet::Set(set) => set.insert(elem), - } - } -} // The TypeWalker's stack is hot enough that it's worth going to some effort to // avoid heap allocations. @@ -111,7 +69,7 @@ impl GenericArg<'tcx> { /// that appear in `self`, it does not descend into the fields of /// structs or variants. For example: /// - /// ```notrust + /// ```text /// isize => { isize } /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } @@ -144,7 +102,7 @@ impl<'tcx> super::TyS<'tcx> { /// that appear in `self`, it does not descend into the fields of /// structs or variants. For example: /// - /// ```notrust + /// ```text /// isize => { isize } /// Foo> => { Foo>, Bar, isize } /// [isize] => { [isize], isize } @@ -162,7 +120,7 @@ impl<'tcx> super::TyS<'tcx> { // types as they are written). fn push_inner<'tcx>(stack: &mut TypeWalkerStack<'tcx>, parent: GenericArg<'tcx>) { match parent.unpack() { - GenericArgKind::Type(parent_ty) => match parent_ty.kind { + GenericArgKind::Type(parent_ty) => match *parent_ty.kind() { ty::Bool | ty::Char | ty::Int(_) diff --git a/src/librustc_middle/util/bug.rs b/compiler/rustc_middle/src/util/bug.rs similarity index 100% rename from src/librustc_middle/util/bug.rs rename to compiler/rustc_middle/src/util/bug.rs diff --git a/src/librustc_middle/util/common.rs b/compiler/rustc_middle/src/util/common.rs similarity index 97% rename from src/librustc_middle/util/common.rs rename to compiler/rustc_middle/src/util/common.rs index 1e09702bf2..da857b0a40 100644 --- a/src/librustc_middle/util/common.rs +++ b/compiler/rustc_middle/src/util/common.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - use rustc_data_structures::sync::Lock; use std::fmt::Debug; diff --git a/src/librustc_middle/util/common/tests.rs b/compiler/rustc_middle/src/util/common/tests.rs similarity index 100% rename from src/librustc_middle/util/common/tests.rs rename to compiler/rustc_middle/src/util/common/tests.rs diff --git a/compiler/rustc_mir/Cargo.toml b/compiler/rustc_mir/Cargo.toml new file mode 100644 index 0000000000..a6d22243d6 --- /dev/null +++ b/compiler/rustc_mir/Cargo.toml @@ -0,0 +1,34 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_mir" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +either = "1.5.0" +rustc_graphviz = { path = "../rustc_graphviz" } +itertools = "0.9" +tracing = "0.1" +log_settings = "0.1.1" +polonius-engine = "0.12.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_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_apfloat = { path = "../rustc_apfloat" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir/borrow_check/borrow_set.rs b/compiler/rustc_mir/src/borrow_check/borrow_set.rs similarity index 100% rename from src/librustc_mir/borrow_check/borrow_set.rs rename to compiler/rustc_mir/src/borrow_check/borrow_set.rs diff --git a/src/librustc_mir/borrow_check/constraint_generation.rs b/compiler/rustc_mir/src/borrow_check/constraint_generation.rs similarity index 100% rename from src/librustc_mir/borrow_check/constraint_generation.rs rename to compiler/rustc_mir/src/borrow_check/constraint_generation.rs diff --git a/src/librustc_mir/borrow_check/constraints/graph.rs b/compiler/rustc_mir/src/borrow_check/constraints/graph.rs similarity index 100% rename from src/librustc_mir/borrow_check/constraints/graph.rs rename to compiler/rustc_mir/src/borrow_check/constraints/graph.rs diff --git a/src/librustc_mir/borrow_check/constraints/mod.rs b/compiler/rustc_mir/src/borrow_check/constraints/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/constraints/mod.rs rename to compiler/rustc_mir/src/borrow_check/constraints/mod.rs diff --git a/src/librustc_mir/borrow_check/def_use.rs b/compiler/rustc_mir/src/borrow_check/def_use.rs similarity index 96% rename from src/librustc_mir/borrow_check/def_use.rs rename to compiler/rustc_mir/src/borrow_check/def_use.rs index 6574e58440..689ec249a2 100644 --- a/src/librustc_mir/borrow_check/def_use.rs +++ b/compiler/rustc_mir/src/borrow_check/def_use.rs @@ -72,8 +72,7 @@ pub fn categorize(context: PlaceContext) -> Option { PlaceContext::MutatingUse(MutatingUseContext::Drop) => Some(DefUse::Drop), - // Coverage and debug info are neither def nor use. - PlaceContext::NonUse(NonUseContext::Coverage) | + // Debug info is neither def nor use. PlaceContext::NonUse(NonUseContext::VarDebugInfo) => None, } } diff --git a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs similarity index 95% rename from src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs index 7a50bdfeef..11122b195c 100644 --- a/src/librustc_mir/borrow_check/diagnostics/conflict_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/conflict_errors.rs @@ -66,7 +66,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let span = use_spans.args_or_use(); let move_site_vec = self.get_moved_indexes(location, mpi); - debug!("report_use_of_moved_or_uninitialized: move_site_vec={:?}", move_site_vec); + 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(); @@ -113,23 +116,32 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } } - let msg = ""; //FIXME: add "partially " or "collaterally " + 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(), - msg, + partially_str, self.describe_place_with_options(moved_place, IncludingDowncast(true)), ); self.add_moved_or_invoked_closure_note(location, used_place, &mut err); let mut is_loop_move = false; - 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; - used_place != moved_place.as_ref() && used_place.is_prefix_of(moved_place.as_ref()) - }); + 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; @@ -142,13 +154,19 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if location == move_out.source { err.span_label( span, - format!("value moved{} here, in previous iteration of loop", move_msg), + format!( + "value {}moved{} here, in previous iteration of loop", + partially_str, move_msg + ), ); is_loop_move = true; } else if move_site.traversed_back_edge { err.span_label( move_span, - format!("value moved{} here, in previous iteration of loop", move_msg), + format!( + "value {}moved{} here, in previous iteration of loop", + partially_str, move_msg + ), ); } else { if let UseSpans::FnSelfUse { var_span, fn_call_span, fn_span, kind } = @@ -162,7 +180,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { FnSelfUseKind::FnOnceCall => { err.span_label( fn_call_span, - &format!("{} moved due to this call", place_name), + &format!( + "{} {}moved due to this call", + place_name, partially_str + ), ); err.span_note( var_span, @@ -172,7 +193,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { FnSelfUseKind::Operator { self_arg } => { err.span_label( fn_call_span, - &format!("{} moved due to usage in operator", place_name), + &format!( + "{} {}moved due to usage in operator", + place_name, partially_str + ), ); if self.fn_self_span_reported.insert(fn_span) { err.span_note( @@ -186,14 +210,17 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( fn_call_span, &format!( - "{} moved due to this implicit call to `.into_iter()`", - place_name + "{} {}moved due to this implicit call to `.into_iter()`", + place_name, partially_str ), ); } else { err.span_label( fn_call_span, - &format!("{} moved due to this method call", place_name), + &format!( + "{} {}moved due to this method call", + place_name, partially_str + ), ); } // Avoid pointing to the same function in multiple different @@ -205,12 +232,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ); } } + // Deref::deref takes &self, which cannot cause a move + FnSelfUseKind::DerefCoercion { .. } => unreachable!(), } } else { - err.span_label(move_span, format!("value moved{} here", move_msg)); + err.span_label( + move_span, + format!("value {}moved{} here", partially_str, move_msg), + ); move_spans.var_span_label( &mut err, - format!("variable moved due to use{}", move_spans.describe()), + format!( + "variable {}moved due to use{}", + partially_str, + move_spans.describe() + ), ); } } @@ -250,9 +286,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { err.span_label( span, format!( - "value {} here {}", + "value {} here after {}move", desired_action.as_verb_in_past_tense(), - if is_partial_move { "after partial move" } else { "after move" }, + partial_str ), ); } @@ -260,7 +296,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = Place::ty_from(used_place.local, used_place.projection, self.body, self.infcx.tcx) .ty; - let needs_note = match ty.kind { + 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()); @@ -275,7 +311,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let ty = place.ty(self.body, self.infcx.tcx).ty; if is_loop_move { - if let ty::Ref(_, _, hir::Mutability::Mut) = ty.kind { + 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(), @@ -298,7 +334,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(ref name) => format!("`{}`", name), None => "value".to_owned(), }; - if let ty::Param(param_ty) = ty.kind { + 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); @@ -321,7 +357,21 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { } else { None }; - self.note_type_does_not_implement_copy(&mut err, ¬e_msg, ty, span); + 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)) = @@ -914,7 +964,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { name: &str, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { debug!( @@ -966,7 +1016,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .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 + match &self + .infcx + .tcx + .typeck(self.mir_def_id) + .node_type(fn_hir_id) + .kind() { ty::Closure(..) => "enclosing closure", ty::Generator(..) => "enclosing generator", @@ -1110,7 +1165,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { location: Location, borrow: &BorrowData<'tcx>, drop_span: Span, - borrow_spans: UseSpans, + borrow_spans: UseSpans<'tcx>, proper_span: Span, explanation: BorrowExplanation, ) -> DiagnosticBuilder<'cx> { @@ -1238,7 +1293,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn report_escaping_closure_capture( &mut self, - use_span: UseSpans, + use_span: UseSpans<'tcx>, var_span: Span, fr_name: &RegionName, category: ConstraintCategory, @@ -1398,8 +1453,12 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { for moi in &self.move_data.loc_map[location] { debug!("report_use_of_moved_or_uninitialized: moi={:?}", moi); - if mpis.contains(&self.move_data.moves[*moi].path) { - debug!("report_use_of_moved_or_uninitialized: found"); + 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 }); // Strictly speaking, we could continue our DFS here. There may be @@ -1590,7 +1649,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { }, ProjectionElem::Field(..) | ProjectionElem::Downcast(..) => { let base_ty = Place::ty_from(place.local, proj_base, self.body, tcx).ty; - match base_ty.kind { + match base_ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { // Report the outermost adt with a destructor match base_access { @@ -1654,7 +1713,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { None } else { let ty = self.infcx.tcx.type_of(self.mir_def_id); - match ty.kind { + 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), @@ -1889,13 +1948,13 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 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 { + 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 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 @@ -1941,9 +2000,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // Closure arguments are wrapped in a tuple, so we need to get the first // from that. - if let ty::Tuple(elems) = argument_ty.kind { + if let ty::Tuple(elems) = argument_ty.kind() { let argument_ty = elems.first()?.expect_ty(); - if let ty::Ref(_, _, _) = argument_ty.kind { + if let ty::Ref(_, _, _) = argument_ty.kind() { return Some(AnnotatedBorrowFnSignature::Closure { argument_ty, argument_span, @@ -1963,7 +2022,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let return_ty = sig.output().skip_binder(); // We expect the first argument to be a reference. - match argument_ty.kind { + match argument_ty.kind() { ty::Ref(_, _, _) => {} _ => return None, } diff --git a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs similarity index 99% rename from src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs index b591b938b5..eccb616822 100644 --- a/src/librustc_mir/borrow_check/diagnostics/explain_borrow.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/explain_borrow.rs @@ -102,7 +102,7 @@ impl BorrowExplanation { should_note_order, } => { let local_decl = &body.local_decls[dropped_local]; - let (dtor_desc, type_desc) = match local_decl.ty.kind { + 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() => { @@ -501,7 +501,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { fn later_use_kind( &self, borrow: &BorrowData<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, location: Location, ) -> (LaterUseKind, Span) { match use_spans { @@ -626,7 +626,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if from == target { debug!("was_captured_by_trait_object: ty={:?}", ty); // Check the type for a trait object. - return match ty.kind { + return match ty.kind() { // `&dyn Trait` ty::Ref(_, ty, _) if ty.is_trait() => true, // `Box` diff --git a/src/librustc_mir/borrow_check/diagnostics/find_use.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs similarity index 100% rename from src/librustc_mir/borrow_check/diagnostics/find_use.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/find_use.rs diff --git a/src/librustc_mir/borrow_check/diagnostics/mod.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs similarity index 81% rename from src/librustc_mir/borrow_check/diagnostics/mod.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs index daffdec2a8..4256f6e39d 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mod.rs @@ -11,7 +11,7 @@ use rustc_middle::mir::{ PlaceRef, ProjectionElem, Rvalue, Statement, StatementKind, Terminator, TerminatorKind, }; use rustc_middle::ty::print::Print; -use rustc_middle::ty::{self, DefIdTree, Ty, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, Instance, Ty, TyCtxt}; use rustc_span::{ hygiene::{DesugaringKind, ForLoopLoc}, symbol::sym, @@ -81,43 +81,41 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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: ty::Const { ty: &ty::TyS { kind: ty::FnDef(id, _), .. }, .. }, - .. - }), + func: Operand::Constant(box Constant { literal: ty::Const { ty: const_ty, .. }, .. }), args, .. } = &terminator.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, - }; + if let ty::FnDef(id, _) = *const_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); + 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, name)) = - 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", - name, - ), - ); - return; + if let Some((span, name)) = + 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", + name, + ), + ); + return; + } } } } @@ -125,7 +123,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 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 { + 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); @@ -152,8 +150,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Some(mut descr) => { // Surround descr with `backticks`. descr.reserve(2); - descr.insert_str(0, "`"); - descr.push_str("`"); + descr.insert(0, '`'); + descr.push('`'); descr } None => "value".to_string(), @@ -224,7 +222,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { if self.upvars[var_index].by_ref { buf.push_str(&name); } else { - buf.push_str(&format!("*{}", &name)); + buf.push('*'); + buf.push_str(&name); } } else { if autoderef { @@ -236,7 +235,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &including_downcast, )?; } else { - buf.push_str(&"*"); + buf.push('*'); self.append_place_to_string( PlaceRef { local, projection: proj_base }, buf, @@ -274,7 +273,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str(&format!(".{}", field_name)); + buf.push('.'); + buf.push_str(&field_name); } } ProjectionElem::Index(index) => { @@ -286,11 +286,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str("["); + buf.push('['); if self.append_local_to_string(*index, buf).is_err() { - buf.push_str("_"); + buf.push('_'); } - buf.push_str("]"); + buf.push(']'); } ProjectionElem::ConstantIndex { .. } | ProjectionElem::Subslice { .. } => { autoderef = true; @@ -303,7 +303,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { autoderef, &including_downcast, )?; - buf.push_str(&"[..]"); + buf.push_str("[..]"); } }; } @@ -365,7 +365,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 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 { + match *ty.kind() { ty::Adt(def, _) => { let variant = if let Some(idx) = variant_index { assert!(def.is_enum()); @@ -412,10 +412,11 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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", - place_desc, ty, + "{}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); @@ -495,7 +496,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // 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 { + match ty.kind() { ty::Ref( ty::RegionKind::ReLateBound(_, br) | ty::RegionKind::RePlaceholder(ty::PlaceholderRegion { name: br, .. }), @@ -515,7 +516,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { let mut s = String::new(); let mut printer = ty::print::FmtPrinter::new(self.infcx.tcx, &mut s, Namespace::TypeNS); - let region = match ty.kind { + let region = match ty.kind() { ty::Ref(region, _, _) => { match region { ty::RegionKind::ReLateBound(_, br) @@ -537,7 +538,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// The span(s) associated to a use of a place. #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum UseSpans { +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. @@ -557,7 +558,7 @@ pub(super) enum UseSpans { fn_call_span: Span, /// The definition span of the method being called fn_span: Span, - kind: FnSelfUseKind, + kind: FnSelfUseKind<'tcx>, }, /// This access is caused by a `match` or `if let` pattern. PatUse(Span), @@ -566,22 +567,32 @@ pub(super) enum UseSpans { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub(super) enum FnSelfUseKind { +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 }, /// 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 { +impl UseSpans<'_> { pub(super) fn args_or_use(self) -> Span { match self { UseSpans::ClosureUse { args_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -589,8 +600,11 @@ impl UseSpans { match self { UseSpans::ClosureUse { var_span: span, .. } | UseSpans::PatUse(span) - | UseSpans::FnSelfUse { var_span: span, .. } | UseSpans::OtherUse(span) => span, + UseSpans::FnSelfUse { + fn_call_span, kind: FnSelfUseKind::DerefCoercion { .. }, .. + } => fn_call_span, + UseSpans::FnSelfUse { var_span, .. } => var_span, } } @@ -649,7 +663,7 @@ impl UseSpans { " in closure".to_string() } } - _ => "".to_string(), + _ => String::new(), } } @@ -679,7 +693,7 @@ impl BorrowedContentSource<'tcx> { 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 { + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { "an `Rc`".to_string() } @@ -711,7 +725,7 @@ impl BorrowedContentSource<'tcx> { BorrowedContentSource::DerefMutableRef => { bug!("describe_for_immutable_place: DerefMutableRef isn't immutable") } - BorrowedContentSource::OverloadedDeref(ty) => match ty.kind { + BorrowedContentSource::OverloadedDeref(ty) => match ty.kind() { ty::Adt(def, _) if tcx.is_diagnostic_item(sym::Rc, def.did) => { "an `Rc`".to_string() } @@ -725,7 +739,7 @@ impl BorrowedContentSource<'tcx> { } fn from_call(func: Ty<'tcx>, tcx: TyCtxt<'tcx>) -> Option { - match func.kind { + match *func.kind() { ty::FnDef(def_id, substs) => { let trait_id = tcx.trait_of_item(def_id)?; @@ -753,7 +767,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { &self, moved_place: PlaceRef<'tcx>, // Could also be an upvar. location: Location, - ) -> UseSpans { + ) -> UseSpans<'tcx> { use self::UseSpans::*; let stmt = match self.body[location.block].statements.get(location.statement_index) { @@ -805,68 +819,79 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { debug!("move_spans: target_temp = {:?}", target_temp); if let Some(Terminator { - kind: TerminatorKind::Call { func, args, fn_span, from_hir_call, .. }, - .. + kind: TerminatorKind::Call { fn_span, from_hir_call, .. }, .. }) = &self.body[location.block].terminator { - let mut method_did = None; - if let Operand::Constant(box Constant { literal: ty::Const { ty, .. }, .. }) = func { - if let ty::FnDef(def_id, _) = ty.kind { - debug!("move_spans: fn = {:?}", def_id); - if let Some(ty::AssocItem { fn_has_self_parameter, .. }) = - self.infcx.tcx.opt_associated_item(def_id) - { - if *fn_has_self_parameter { - method_did = Some(def_id); - } - } - } - } + 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 method_did = if let Some(did) = method_did { did } else { return normal_ret }; + 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; - if let [Operand::Move(self_place), ..] = **args { - if self_place.as_local() == Some(target_temp) { - 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 fn_call_span = *fn_span; + let self_arg = tcx.fn_arg_names(method_did)[0]; - let self_arg = tcx.fn_arg_names(method_did)[0]; + debug!( + "terminator = {:?} from_hir_call={:?}", + self.body[location.block].terminator, from_hir_call + ); - let kind = if is_fn_once { - FnSelfUseKind::FnOnceCall - } else if is_operator { - FnSelfUseKind::Operator { self_arg } - } else { - 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)) - ); - FnSelfUseKind::Normal { self_arg, implicit_into_iter } - }; - - 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, - }; + // 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)) + ); + FnSelfUseKind::Normal { self_arg, implicit_into_iter } + }); + + 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 } @@ -875,7 +900,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// 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 { + 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); @@ -937,11 +962,14 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places ); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(def_id.as_local()?); + 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 (upvar, place) in self.infcx.tcx.upvars_mentioned(def_id)?.values().zip(places) { + for ((upvar_hir_id, upvar), place) in + self.infcx.tcx.upvars_mentioned(def_id)?.iter().zip(places) + { match place { Operand::Copy(place) | Operand::Move(place) if target_place == place.as_ref() => @@ -949,7 +977,23 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { 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, upvar.span)); + let upvar_id = ty::UpvarId { + var_path: ty::UpvarPath { hir_id: *upvar_hir_id }, + closure_expr_id: local_did, + }; + + // If we have a more specific span available, point to that. + // We do this even though this span might be part of a borrow error + // message rather than a move error message. Our goal is to point + // to a span that shows why the upvar is used in the closure, + // so a move-related span is as good as any (and potentially better, + // if the overall error is due to a move of the upvar). + let usage_span = + match self.infcx.tcx.typeck(local_did).upvar_capture(upvar_id) { + ty::UpvarCapture::ByValue(Some(span)) => span, + _ => upvar.span, + }; + return Some((*args_span, generator_kind, usage_span)); } _ => {} } @@ -960,7 +1004,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { /// Helper to retrieve span(s) of given borrow from the current MIR /// representation - pub(super) fn retrieve_borrow_spans(&self, borrow: &BorrowData<'_>) -> UseSpans { + 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 --git a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs similarity index 96% rename from src/librustc_mir/borrow_check/diagnostics/move_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index bd3e20458b..629e9be9dd 100644 --- a/src/librustc_mir/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -47,7 +47,7 @@ enum GroupedMoveError<'tcx> { // Everything that isn't from pattern matching. OtherIllegalMove { original_path: Place<'tcx>, - use_spans: UseSpans, + use_spans: UseSpans<'tcx>, kind: IllegalMoveOriginKind<'tcx>, }, } @@ -222,7 +222,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { let (mut err, err_span) = { let (span, use_spans, original_path, kind): ( Span, - Option, + Option>, Place<'tcx>, &IllegalMoveOriginKind<'_>, ) = match error { @@ -291,7 +291,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { move_place: Place<'tcx>, deref_target_place: Place<'tcx>, span: Span, - use_spans: Option, + use_spans: Option>, ) -> DiagnosticBuilder<'a> { // Inspect the type of the content behind the // borrow to provide feedback about why this @@ -326,7 +326,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } debug!("report: ty={:?}", ty); - let mut err = match ty.kind { + let mut err = match ty.kind() { ty::Array(..) | ty::Slice(..) => { self.cannot_move_out_of_interior_noncopy(span, ty, None) } @@ -385,7 +385,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } }; if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - let def_id = match move_place.ty(self.body, self.infcx.tcx).ty.kind { + let def_id = match *move_place.ty(self.body, self.infcx.tcx).ty.kind() { ty::Adt(self_def, _) => self_def.did, ty::Foreign(def_id) | ty::FnDef(def_id, _) @@ -445,7 +445,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { None => "value".to_string(), }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); + self.note_type_does_not_implement_copy( + err, + &place_desc, + place_ty, + Some(span), + "", + ); } else { binds_to.sort(); binds_to.dedup(); @@ -467,7 +473,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Some(desc) => format!("`{}`", desc), None => "value".to_string(), }; - self.note_type_does_not_implement_copy(err, &place_desc, place_ty, Some(span)); + 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 @@ -486,8 +492,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { { if let Ok(pat_snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(pat_span) { - if pat_snippet.starts_with('&') { - let pat_snippet = pat_snippet[1..].trim_start(); + 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) { @@ -529,6 +535,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { &format!("`{}`", self.local_names[*local].unwrap()), bind_to.ty, Some(binding_span), + "", ); } } diff --git a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs similarity index 99% rename from src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs index d26436ff1d..d4cdf02104 100644 --- a/src/librustc_mir/borrow_check/diagnostics/mutability_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/mutability_errors.rs @@ -230,7 +230,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // Otherwise, check if the name is the self kewyord - 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`. - if let ty::Ref(_, _, hir::Mutability::Mut) = local_decl.ty.kind { + if let ty::Ref(_, _, hir::Mutability::Mut) = local_decl.ty.kind() { true } else { false @@ -509,7 +509,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { 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) + tables.node_type_opt(func.hir_id).as_ref().map(|ty| ty.kind()) { let arg = match hir.get_if_local(*def_id) { Some( @@ -631,9 +631,8 @@ fn suggest_ampmut<'tcx>( let lt_name = &src[1..ws_pos]; let ty = &src[ws_pos..]; return (assignment_rhs_span, format!("&{} mut {}", lt_name, ty)); - } else if src.starts_with('&') { - let borrowed_expr = &src[1..]; - return (assignment_rhs_span, format!("&mut {}", borrowed_expr)); + } else if let Some(stripped) = src.strip_prefix('&') { + return (assignment_rhs_span, format!("&mut {}", stripped)); } } } @@ -687,8 +686,8 @@ fn annotate_struct_field( 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 { + 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()?); diff --git a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs similarity index 98% rename from src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs index a775fa59c1..7505e6e2dd 100644 --- a/src/librustc_mir/borrow_check/diagnostics/outlives_suggestion.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/outlives_suggestion.rs @@ -115,9 +115,10 @@ impl OutlivesSuggestionBuilder { // 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)| { - if let RegionNameSource::Static = outlived_name.source { true } else { false } - }) { + 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 diff --git a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs similarity index 98% rename from src/librustc_mir/borrow_check/diagnostics/region_errors.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs index a0d99ac33c..eb1f70099f 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_errors.rs @@ -364,13 +364,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .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 { + 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 { + 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" @@ -387,7 +387,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { 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), + ty => bug!("unexpected DefiningTy {:?}", ty), }; let upvar_def_span = self.infcx.tcx.hir().span(upvar); @@ -571,13 +571,13 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if let (Some(f), Some(ty::RegionKind::ReStatic)) = (self.to_error_region(fr), self.to_error_region(outlived_fr)) { - if let Some((&ty::TyS { kind: ty::Opaque(did, substs), .. }, _)) = self + if let Some(&ty::Opaque(did, substs)) = self .infcx .tcx .is_suitable_region(f) .map(|r| r.def_id) - .map(|id| self.infcx.tcx.return_type_impl_trait(id)) - .unwrap_or(None) + .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. diff --git a/src/librustc_mir/borrow_check/diagnostics/region_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs similarity index 98% rename from src/librustc_mir/borrow_check/diagnostics/region_name.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs index 2603b1e048..5f64eb3dba 100644 --- a/src/librustc_mir/borrow_check/diagnostics/region_name.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/region_name.rs @@ -396,7 +396,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ) -> Option { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(needle_fr, counter); - let type_name = self.infcx.extract_type_name(&ty, Some(highlight)).0; + 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={:?}", @@ -404,7 +405,6 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { ); if type_name.find(&format!("'{}", counter)).is_some() { // Only add a label if we can confirm that a region was labelled. - Some(RegionNameHighlight::CannotMatchHirTy(span, type_name)) } else { None @@ -441,7 +441,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { 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) { + 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: @@ -646,7 +646,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(&return_ty, Some(highlight)).0; + let type_name = + self.infcx.extract_inference_diagnostics_data(return_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); @@ -698,7 +699,8 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { let mut highlight = RegionHighlightMode::default(); highlight.highlighting_region_vid(fr, *self.next_region_name.try_borrow().unwrap()); - let type_name = self.infcx.extract_type_name(&yield_ty, Some(highlight)).0; + let type_name = + self.infcx.extract_inference_diagnostics_data(yield_ty.into(), Some(highlight)).name; let mir_hir_id = tcx.hir().local_def_id_to_hir_id(self.mir_def_id); diff --git a/src/librustc_mir/borrow_check/diagnostics/var_name.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs similarity index 100% rename from src/librustc_mir/borrow_check/diagnostics/var_name.rs rename to compiler/rustc_mir/src/borrow_check/diagnostics/var_name.rs diff --git a/src/librustc_mir/borrow_check/facts.rs b/compiler/rustc_mir/src/borrow_check/facts.rs similarity index 100% rename from src/librustc_mir/borrow_check/facts.rs rename to compiler/rustc_mir/src/borrow_check/facts.rs diff --git a/src/librustc_mir/borrow_check/invalidation.rs b/compiler/rustc_mir/src/borrow_check/invalidation.rs similarity index 100% rename from src/librustc_mir/borrow_check/invalidation.rs rename to compiler/rustc_mir/src/borrow_check/invalidation.rs diff --git a/src/librustc_mir/borrow_check/location.rs b/compiler/rustc_mir/src/borrow_check/location.rs similarity index 100% rename from src/librustc_mir/borrow_check/location.rs rename to compiler/rustc_mir/src/borrow_check/location.rs diff --git a/src/librustc_mir/borrow_check/member_constraints.rs b/compiler/rustc_mir/src/borrow_check/member_constraints.rs similarity index 99% rename from src/librustc_mir/borrow_check/member_constraints.rs rename to compiler/rustc_mir/src/borrow_check/member_constraints.rs index d4baa5d809..baaf6f27ee 100644 --- a/src/librustc_mir/borrow_check/member_constraints.rs +++ b/compiler/rustc_mir/src/borrow_check/member_constraints.rs @@ -71,7 +71,7 @@ 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 the `rustc_middle::infer` code. + /// 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 diff --git a/src/librustc_mir/borrow_check/mod.rs b/compiler/rustc_mir/src/borrow_check/mod.rs similarity index 99% rename from src/librustc_mir/borrow_check/mod.rs rename to compiler/rustc_mir/src/borrow_check/mod.rs index a61af5c3f0..e4237482f4 100644 --- a/src/librustc_mir/borrow_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/mod.rs @@ -17,7 +17,7 @@ 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, InstanceDef, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, InstanceDef, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::{MUTABLE_BORROW_RESERVATION_CONFLICT, UNUSED_MUT}; use rustc_span::{Span, Symbol, DUMMY_SP}; @@ -163,7 +163,7 @@ fn do_mir_borrowck<'a, 'tcx>( let var_hir_id = upvar_id.var_path.hir_id; let capture = tables.upvar_capture(*upvar_id); let by_ref = match capture { - ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByValue(_) => false, ty::UpvarCapture::ByRef(..) => true, }; let mut upvar = Upvar { @@ -205,6 +205,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut flow_inits = MaybeInitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint() .into_results_cursor(&body); @@ -264,12 +265,15 @@ fn do_mir_borrowck<'a, 'tcx>( let flow_borrows = Borrows::new(tcx, &body, regioncx.clone(), &borrow_set) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let flow_uninits = MaybeUninitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let flow_ever_inits = EverInitializedPlaces::new(tcx, &body, &mdpe) .into_engine(tcx, &body, def.did.to_def_id()) + .pass_name("borrowck") .iterate_to_fixpoint(); let movable_generator = match tcx.hir().get(id) { @@ -287,6 +291,7 @@ fn do_mir_borrowck<'a, 'tcx>( if let Err((move_data, move_errors)) = move_data_results { let mut promoted_mbcx = MirBorrowckCtxt { infcx, + param_env, body: promoted_body, mir_def_id: def.did, move_data: &move_data, @@ -320,6 +325,7 @@ fn do_mir_borrowck<'a, 'tcx>( let mut mbcx = MirBorrowckCtxt { infcx, + param_env, body, mir_def_id: def.did, move_data: &mdpe.move_data, @@ -473,6 +479,7 @@ fn do_mir_borrowck<'a, 'tcx>( crate struct MirBorrowckCtxt<'cx, 'tcx> { crate infcx: &'cx InferCtxt<'cx, 'tcx>, + param_env: ParamEnv<'tcx>, body: &'cx Body<'tcx>, mir_def_id: LocalDefId, move_data: &'cx MoveData<'tcx>, @@ -1694,8 +1701,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { desired_action: InitializationRequiringAction, place_span: (PlaceRef<'tcx>, Span), maybe_uninits: &BitSet, - from: u32, - to: u32, + from: u64, + to: u64, ) { if let Some(mpi) = self.move_path_for_place(place_span.0) { let move_paths = &self.move_data.move_paths; @@ -1758,7 +1765,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { { let place_ty = Place::ty_from(place_span.0.local, base_proj, self.body(), self.infcx.tcx); - if let ty::Array(..) = place_ty.ty.kind { + if let ty::Array(..) = place_ty.ty.kind() { let array_place = PlaceRef { local: place_span.0.local, projection: base_proj }; self.check_if_subslice_element_is_moved( location, @@ -1876,7 +1883,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // be already initialized let tcx = self.infcx.tcx; let base_ty = Place::ty_from(place.local, proj_base, self.body(), tcx).ty; - match base_ty.kind { + match base_ty.kind() { ty::Adt(def, _) if def.has_dtor(tcx) => { self.check_if_path_or_subpath_is_moved( location, InitializationRequiringAction::Assignment, @@ -1979,7 +1986,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // of the union - we should error in that case. let tcx = this.infcx.tcx; if let ty::Adt(def, _) = - Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind + Place::ty_from(base.local, base.projection, this.body(), tcx).ty.kind() { if def.is_union() { if this.move_data.path_map[mpi].iter().any(|moi| { @@ -2206,7 +2213,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { Place::ty_from(place.local, proj_base, self.body(), self.infcx.tcx).ty; // Check the kind of deref to decide - match base_ty.kind { + match base_ty.kind() { ty::Ref(_, _, mutbl) => { match mutbl { // Shared borrowed data is never mutable diff --git a/src/librustc_mir/borrow_check/nll.rs b/compiler/rustc_mir/src/borrow_check/nll.rs similarity index 100% rename from src/librustc_mir/borrow_check/nll.rs rename to compiler/rustc_mir/src/borrow_check/nll.rs diff --git a/src/librustc_mir/borrow_check/path_utils.rs b/compiler/rustc_mir/src/borrow_check/path_utils.rs similarity index 100% rename from src/librustc_mir/borrow_check/path_utils.rs rename to compiler/rustc_mir/src/borrow_check/path_utils.rs diff --git a/src/librustc_mir/borrow_check/place_ext.rs b/compiler/rustc_mir/src/borrow_check/place_ext.rs similarity index 99% rename from src/librustc_mir/borrow_check/place_ext.rs rename to compiler/rustc_mir/src/borrow_check/place_ext.rs index cadf1ebf1b..52fac3e53e 100644 --- a/src/librustc_mir/borrow_check/place_ext.rs +++ b/compiler/rustc_mir/src/borrow_check/place_ext.rs @@ -49,7 +49,7 @@ impl<'tcx> PlaceExt<'tcx> for Place<'tcx> { if elem == ProjectionElem::Deref { let ty = Place::ty_from(self.local, proj_base, body, tcx).ty; - match ty.kind { + match ty.kind() { ty::Ref(_, _, hir::Mutability::Not) if i == 0 => { // For references to thread-local statics, we do need // to track the borrow. diff --git a/src/librustc_mir/borrow_check/places_conflict.rs b/compiler/rustc_mir/src/borrow_check/places_conflict.rs similarity index 99% rename from src/librustc_mir/borrow_check/places_conflict.rs rename to compiler/rustc_mir/src/borrow_check/places_conflict.rs index 246e4826e0..02c7b7dc20 100644 --- a/src/librustc_mir/borrow_check/places_conflict.rs +++ b/compiler/rustc_mir/src/borrow_check/places_conflict.rs @@ -210,7 +210,7 @@ fn place_components_conflict<'tcx>( 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) { + match (elem, &base_ty.kind(), access) { (_, _, Shallow(Some(ArtificialField::ArrayLength))) | (_, _, Shallow(Some(ArtificialField::ShallowBorrow))) => { // The array length is like additional fields on the @@ -330,7 +330,7 @@ fn place_projection_conflict<'tcx>( Overlap::EqualOrDisjoint } else { let ty = Place::ty_from(pi1_local, pi1_proj_base, body, tcx).ty; - match ty.kind { + match ty.kind() { ty::Adt(def, _) if def.is_union() => { // Different fields of a union, we are basically stuck. debug!("place_element_conflict: STUCK-UNION"); diff --git a/src/librustc_mir/borrow_check/prefixes.rs b/compiler/rustc_mir/src/borrow_check/prefixes.rs similarity index 99% rename from src/librustc_mir/borrow_check/prefixes.rs rename to compiler/rustc_mir/src/borrow_check/prefixes.rs index a2475e0ff2..6c5d42296f 100644 --- a/src/librustc_mir/borrow_check/prefixes.rs +++ b/compiler/rustc_mir/src/borrow_check/prefixes.rs @@ -33,7 +33,6 @@ pub(super) struct Prefixes<'cx, 'tcx> { } #[derive(Copy, Clone, PartialEq, Eq, Debug)] -#[allow(dead_code)] pub(super) enum PrefixSet { /// Doesn't stop until it returns the base case (a Local or /// Static prefix). @@ -121,7 +120,7 @@ impl<'cx, 'tcx> Iterator for Prefixes<'cx, 'tcx> { // reference. let ty = Place::ty_from(cursor.local, proj_base, self.body, self.tcx).ty; - match ty.kind { + match ty.kind() { ty::RawPtr(_) | ty::Ref(_ /*rgn*/, _ /*ty*/, hir::Mutability::Not) => { // don't continue traversing over derefs of raw pointers or shared // borrows. diff --git a/src/librustc_mir/borrow_check/region_infer/dump_mir.rs b/compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/dump_mir.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/dump_mir.rs diff --git a/src/librustc_mir/borrow_check/region_infer/graphviz.rs b/compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/graphviz.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/graphviz.rs diff --git a/src/librustc_mir/borrow_check/region_infer/mod.rs b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs similarity index 99% rename from src/librustc_mir/borrow_check/region_infer/mod.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/mod.rs index 081125cb62..3dc082a441 100644 --- a/src/librustc_mir/borrow_check/region_infer/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/mod.rs @@ -551,7 +551,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { mir_def_id: DefId, polonius_output: Option>, ) -> (Option>, RegionErrors<'tcx>) { - self.propagate_constraints(body); + self.propagate_constraints(body, infcx.tcx); let mut errors_buffer = RegionErrors::new(); @@ -599,7 +599,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// 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>) { + fn propagate_constraints(&mut self, _body: &Body<'tcx>, tcx: TyCtxt<'tcx>) { debug!("propagate_constraints()"); debug!("propagate_constraints: constraints={:#?}", { @@ -617,7 +617,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { // own. let constraint_sccs = self.constraint_sccs.clone(); for scc in constraint_sccs.all_sccs() { - self.compute_value_for_scc(scc); + self.compute_value_for_scc(scc, tcx); } // Sort the applied member constraints so we can binary search @@ -629,7 +629,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// 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) { + fn compute_value_for_scc(&mut self, scc_a: ConstraintSccIndex, tcx: TyCtxt<'tcx>) { let constraint_sccs = self.constraint_sccs.clone(); // Walk each SCC `B` such that `A: B`... @@ -652,7 +652,12 @@ impl<'tcx> RegionInferenceContext<'tcx> { // 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)); + self.apply_member_constraint( + tcx, + scc_a, + m_c_i, + member_constraints.choice_regions(m_c_i), + ); } debug!( @@ -675,6 +680,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { /// If we make any changes, returns true, else false. fn apply_member_constraint( &mut self, + tcx: TyCtxt<'tcx>, scc: ConstraintSccIndex, member_constraint_index: NllMemberConstraintIndex, choice_regions: &[ty::RegionVid], @@ -688,12 +694,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { // `impl_trait_in_bindings`, I believe, and we are just // opting not to handle it for now. See #61773 for // details. - bug!( - "member constraint for `{:?}` has an option region `{:?}` \ - that is not a universal region", - self.member_constraints[member_constraint_index].opaque_type_def_id, - uh_oh, + tcx.sess.delay_span_bug( + self.member_constraints[member_constraint_index].definition_span, + &format!( + "member constraint for `{:?}` has an option region `{:?}` \ + that is not a universal region", + self.member_constraints[member_constraint_index].opaque_type_def_id, uh_oh, + ), ); + return false; } // Create a mutable vector of the options. We'll try to winnow diff --git a/src/librustc_mir/borrow_check/region_infer/opaque_types.rs b/compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/opaque_types.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/opaque_types.rs diff --git a/src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs b/compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs similarity index 100% rename from src/librustc_mir/borrow_check/region_infer/reverse_sccs.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/reverse_sccs.rs diff --git a/src/librustc_mir/borrow_check/region_infer/values.rs b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs similarity index 99% rename from src/librustc_mir/borrow_check/region_infer/values.rs rename to compiler/rustc_mir/src/borrow_check/region_infer/values.rs index 8a5a600cfd..f247d07e1f 100644 --- a/src/librustc_mir/borrow_check/region_infer/values.rs +++ b/compiler/rustc_mir/src/borrow_check/region_infer/values.rs @@ -417,7 +417,7 @@ crate fn location_set_str( fn region_value_str(elements: impl IntoIterator) -> String { let mut result = String::new(); - result.push_str("{"); + result.push('{'); // Set to Some(l1, l2) when we have observed all the locations // from l1..=l2 (inclusive) but not yet printed them. This @@ -478,7 +478,7 @@ fn region_value_str(elements: impl IntoIterator) -> String push_location_range(&mut result, location1, location2); } - result.push_str("}"); + result.push('}'); return result; diff --git a/src/librustc_mir/borrow_check/renumber.rs b/compiler/rustc_mir/src/borrow_check/renumber.rs similarity index 100% rename from src/librustc_mir/borrow_check/renumber.rs rename to compiler/rustc_mir/src/borrow_check/renumber.rs diff --git a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs similarity index 98% rename from src/librustc_mir/borrow_check/type_check/constraint_conversion.rs rename to compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs index 711271a63f..8513e5e531 100644 --- a/src/librustc_mir/borrow_check/type_check/constraint_conversion.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/constraint_conversion.rs @@ -62,8 +62,7 @@ impl<'a, 'tcx> ConstraintConversion<'a, 'tcx> { // `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::replace(&mut self.constraints.member_constraints, Default::default()); + 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)); } diff --git a/src/librustc_mir/borrow_check/type_check/free_region_relations.rs b/compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/free_region_relations.rs rename to compiler/rustc_mir/src/borrow_check/type_check/free_region_relations.rs diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/compiler/rustc_mir/src/borrow_check/type_check/input_output.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/input_output.rs rename to compiler/rustc_mir/src/borrow_check/type_check/input_output.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/local_use_map.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/local_use_map.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/mod.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/mod.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/polonius.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/polonius.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/polonius.rs diff --git a/src/librustc_mir/borrow_check/type_check/liveness/trace.rs b/compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/liveness/trace.rs rename to compiler/rustc_mir/src/borrow_check/type_check/liveness/trace.rs diff --git a/src/librustc_mir/borrow_check/type_check/mod.rs b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs similarity index 99% rename from src/librustc_mir/borrow_check/type_check/mod.rs rename to compiler/rustc_mir/src/borrow_check/type_check/mod.rs index b95d963759..3ace14610e 100644 --- a/src/librustc_mir/borrow_check/type_check/mod.rs +++ b/compiler/rustc_mir/src/borrow_check/type_check/mod.rs @@ -386,7 +386,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { } } - if let ty::FnDef(def_id, substs) = constant.literal.ty.kind { + 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, @@ -412,7 +412,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { // 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 { + if let ty::Ref(_, rty, _) = local_decl.ty.kind() { rty } else { bug!("{:?} with ref binding has wrong type {}", local, local_decl.ty); @@ -646,10 +646,10 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { })) } ProjectionElem::Subslice { from, to, from_end } => { - PlaceTy::from_ty(match base_ty.kind { + 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) as u64) + tcx.mk_array(inner, to - from) } ty::Slice(..) => { assert!(from_end, "slice subslices should use from_end"); @@ -658,7 +658,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { _ => span_mirbug_and_err!(self, place, "slice of non-array {:?}", base_ty), }) } - ProjectionElem::Downcast(maybe_name, index) => match base_ty.kind { + 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!( @@ -738,7 +738,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { let tcx = self.tcx(); let (variant, substs) = match base_ty { - PlaceTy { ty, variant_index: Some(variant_index) } => match ty.kind { + 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); @@ -757,7 +757,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } _ => bug!("can't have downcast of non-adt non-generator type"), }, - PlaceTy { ty, variant_index: None } => match ty.kind { + 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) } @@ -1140,7 +1140,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { category: ConstraintCategory, ) -> Fallible<()> { if let Err(terr) = self.sub_types(sub, sup, locations, category) { - if let ty::Opaque(..) = sup.kind { + if let ty::Opaque(..) = sup.kind() { // When you have `let x: impl Foo = ...` in a closure, // the resulting inferend values are stored with the // def-id of the base function. @@ -1283,8 +1283,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { for (&opaque_def_id, opaque_decl) in &opaque_type_map { let resolved_ty = infcx.resolve_vars_if_possible(&opaque_decl.concrete_ty); - let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind { - def_id == opaque_def_id + let concrete_is_opaque = if let ty::Opaque(def_id, _) = resolved_ty.kind() { + *def_id == opaque_def_id } else { false }; @@ -1486,7 +1486,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } StatementKind::SetDiscriminant { ref place, variant_index } => { let place_type = place.ty(body, tcx).ty; - let adt = match place_type.kind { + let adt = match place_type.kind() { ty::Adt(adt, _) if adt.is_enum() => adt, _ => { span_bug!( @@ -1602,7 +1602,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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 { + 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); @@ -2093,7 +2093,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::Pointer(PointerCast::ClosureFnPointer(unsafety)) => { - let sig = match op.ty(body, tcx).kind { + let sig = match op.ty(body, tcx).kind() { ty::Closure(_, substs) => substs.as_closure().sig(), _ => bug!(), }; @@ -2161,7 +2161,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } CastKind::Pointer(PointerCast::MutToConstPointer) => { - let ty_from = match op.ty(body, tcx).kind { + let ty_from = match op.ty(body, tcx).kind() { ty::RawPtr(ty::TypeAndMut { ty: ty_from, mutbl: hir::Mutability::Mut, @@ -2176,7 +2176,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { return; } }; - let ty_to = match ty.kind { + let ty_to = match ty.kind() { ty::RawPtr(ty::TypeAndMut { ty: ty_to, mutbl: hir::Mutability::Not, @@ -2211,11 +2211,11 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { CastKind::Pointer(PointerCast::ArrayToPointer) => { let ty_from = op.ty(body, tcx); - let opt_ty_elem = match ty_from.kind { + let opt_ty_elem = match ty_from.kind() { ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: array_ty, - }) => match array_ty.kind { + }) => match array_ty.kind() { ty::Array(ty_elem, _) => Some(ty_elem), _ => None, }, @@ -2235,7 +2235,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; - let ty_to = match ty.kind { + let ty_to = match ty.kind() { ty::RawPtr(ty::TypeAndMut { mutbl: hir::Mutability::Not, ty: ty_to, @@ -2301,7 +2301,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { right, ) => { let ty_left = left.ty(body, tcx); - match ty_left.kind { + 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); @@ -2512,7 +2512,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { 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 { + match base_ty.kind() { ty::Ref(ref_region, _, mutbl) => { constraints.outlives_constraints.push(OutlivesConstraint { sup: ref_region.to_region_vid(), diff --git a/src/librustc_mir/borrow_check/type_check/relate_tys.rs b/compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs similarity index 100% rename from src/librustc_mir/borrow_check/type_check/relate_tys.rs rename to compiler/rustc_mir/src/borrow_check/type_check/relate_tys.rs diff --git a/src/librustc_mir/borrow_check/universal_regions.rs b/compiler/rustc_mir/src/borrow_check/universal_regions.rs similarity index 99% rename from src/librustc_mir/borrow_check/universal_regions.rs rename to compiler/rustc_mir/src/borrow_check/universal_regions.rs index 9dfc67bcf6..4742113b1a 100644 --- a/src/librustc_mir/borrow_check/universal_regions.rs +++ b/compiler/rustc_mir/src/borrow_check/universal_regions.rs @@ -524,7 +524,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { let defining_ty = self.infcx.replace_free_regions_with_nll_infer_vars(FR, &defining_ty); - match defining_ty.kind { + 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) @@ -603,7 +603,7 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> { // flattens this tuple. let (&output, tuplized_inputs) = inputs_and_output.split_last().unwrap(); assert_eq!(tuplized_inputs.len(), 1, "multiple closure inputs"); - let inputs = match tuplized_inputs[0].kind { + let inputs = match tuplized_inputs[0].kind() { ty::Tuple(inputs) => inputs, _ => bug!("closure inputs not a tuple: {:?}", tuplized_inputs[0]), }; diff --git a/src/librustc_mir/borrow_check/used_muts.rs b/compiler/rustc_mir/src/borrow_check/used_muts.rs similarity index 100% rename from src/librustc_mir/borrow_check/used_muts.rs rename to compiler/rustc_mir/src/borrow_check/used_muts.rs diff --git a/src/librustc_mir/const_eval/error.rs b/compiler/rustc_mir/src/const_eval/error.rs similarity index 100% rename from src/librustc_mir/const_eval/error.rs rename to compiler/rustc_mir/src/const_eval/error.rs diff --git a/src/librustc_mir/const_eval/eval_queries.rs b/compiler/rustc_mir/src/const_eval/eval_queries.rs similarity index 78% rename from src/librustc_mir/const_eval/eval_queries.rs rename to compiler/rustc_mir/src/const_eval/eval_queries.rs index 291b42c12d..57aa216850 100644 --- a/src/librustc_mir/const_eval/eval_queries.rs +++ b/compiler/rustc_mir/src/const_eval/eval_queries.rs @@ -1,8 +1,8 @@ use super::{CompileTimeEvalContext, CompileTimeInterpreter, ConstEvalErr, MemoryExtra}; use crate::interpret::eval_nullary_intrinsic; use crate::interpret::{ - intern_const_alloc_recursive, Allocation, ConstValue, GlobalId, Immediate, InternKind, - InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RawConst, RefTracking, Scalar, + intern_const_alloc_recursive, Allocation, ConstAlloc, ConstValue, GlobalId, Immediate, + InternKind, InterpCx, InterpResult, MPlaceTy, MemoryKind, OpTy, RefTracking, Scalar, ScalarMaybeUninit, StackPopCleanup, }; @@ -10,10 +10,11 @@ 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::convert::TryInto; +use std::convert::{TryFrom, TryInto}; pub fn note_on_undefined_behavior_error() -> &'static str { "The rules on what exactly is undefined behavior aren't clear, \ @@ -33,7 +34,8 @@ fn eval_body_using_ecx<'mir, 'tcx>( assert!(!layout.is_unsized()); let ret = ecx.allocate(layout, MemoryKind::Stack); - let name = ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id())); + let name = + with_no_trimmed_paths(|| ty::tls::with(|tcx| tcx.def_path_str(cid.instance.def_id()))); let prom = cid.promoted.map_or(String::new(), |p| format!("::promoted[{:?}]", p)); trace!("eval_body_using_ecx: pushing stack frame for global: {}{}", name, prom); @@ -102,6 +104,8 @@ pub(super) fn mk_eval_cx<'mir, 'tcx>( ) } +/// 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>, @@ -115,8 +119,8 @@ pub(super) fn op_to_const<'tcx>( // `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 { + 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, @@ -144,10 +148,10 @@ pub(super) fn op_to_const<'tcx>( Scalar::Raw { data, .. } => { assert!(mplace.layout.is_zst()); assert_eq!( - data, - mplace.layout.align.abi.bytes().into(), - "this MPlaceTy must come from `try_as_mplace` being used on a zst, so we know what - value this integer address must have", + u64::try_from(data).unwrap() % 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()) } @@ -180,63 +184,37 @@ pub(super) fn op_to_const<'tcx>( } } -fn validate_and_turn_into_const<'tcx>( +fn turn_into_const_value<'tcx>( tcx: TyCtxt<'tcx>, - constant: RawConst<'tcx>, + constant: ConstAlloc<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalResult<'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 val = (|| { - let mplace = ecx.raw_const_to_mplace(constant)?; - // FIXME do not validate promoteds until a decision on - // https://github.com/rust-lang/rust/issues/67465 is made - if cid.promoted.is_none() { - let mut ref_tracking = RefTracking::new(mplace); - while let Some((mplace, path)) = ref_tracking.todo.pop() { - ecx.const_validate_operand( - mplace.into(), - path, - &mut ref_tracking, - /*may_ref_to_static*/ ecx.memory.extra.can_access_statics, - )?; - } - } - // Now that we validated, turn this into a proper constant. - // Statics/promoteds are always `ByRef`, for the rest `op_to_const` decides - // whether they become immediates. - if is_static || cid.promoted.is_some() { - let ptr = mplace.ptr.assert_ptr(); - Ok(ConstValue::ByRef { - alloc: ecx.tcx.global_alloc(ptr.alloc_id).unwrap_memory(), - offset: ptr.offset, - }) - } else { - Ok(op_to_const(&ecx, mplace.into())) - } - })(); - - val.map_err(|error| { - let err = ConstEvalErr::new(&ecx, error, None); - err.struct_error(ecx.tcx, "it is undefined behavior to use this value", |mut diag| { - diag.note(note_on_undefined_behavior_error()); - diag.emit(); - }) - }) + 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 const_eval_validated_provider<'tcx>( +pub fn eval_to_const_value_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalResult<'tcx> { +) -> ::rustc_middle::mir::interpret::EvalToConstValueResult<'tcx> { // see comment in const_eval_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.const_eval_validated(key) { + match tcx.eval_to_const_value_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls @@ -248,7 +226,7 @@ pub fn const_eval_validated_provider<'tcx>( // 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 { + let substs = match ty.kind() { ty::FnDef(_, substs) => substs, _ => bug!("intrinsic with type {:?}", ty), }; @@ -259,13 +237,13 @@ pub fn const_eval_validated_provider<'tcx>( }); } - tcx.const_eval_raw(key).and_then(|val| validate_and_turn_into_const(tcx, val, key)) + tcx.eval_to_allocation_raw(key).map(|val| turn_into_const_value(tcx, val, key)) } -pub fn const_eval_raw_provider<'tcx>( +pub fn eval_to_allocation_raw_provider<'tcx>( tcx: TyCtxt<'tcx>, key: ty::ParamEnvAnd<'tcx, GlobalId<'tcx>>, -) -> ::rustc_middle::mir::interpret::ConstEvalRawResult<'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 @@ -277,7 +255,7 @@ pub fn const_eval_raw_provider<'tcx>( if key.param_env.reveal() == Reveal::All { let mut key = key; key.param_env = key.param_env.with_user_facing(); - match tcx.const_eval_raw(key) { + match tcx.eval_to_allocation_raw(key) { // try again with reveal all as requested Err(ErrorHandled::TooGeneric) => {} // deduplicate calls @@ -290,7 +268,7 @@ pub fn const_eval_raw_provider<'tcx>( // 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 = key.value.instance.to_string(); + let instance = with_no_trimmed_paths(|| key.value.instance.to_string()); trace!("const eval: {:?} ({})", key, instance); } @@ -316,9 +294,8 @@ pub fn const_eval_raw_provider<'tcx>( ); let res = ecx.load_mir(cid.instance.def, cid.promoted); - res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) - .map(|place| RawConst { alloc_id: place.ptr.assert_ptr().alloc_id, ty: place.layout.ty }) - .map_err(|error| { + match res.and_then(|body| eval_body_using_ecx(&mut ecx, cid, &body)) { + Err(error) => { let err = ConstEvalErr::new(&ecx, error, None); // errors in statics are always emitted as fatal errors if is_static { @@ -340,7 +317,7 @@ pub fn const_eval_raw_provider<'tcx>( ); } - v + Err(v) } else if let Some(def) = def.as_local() { // constant defined in this crate, we can figure out a lint level! match tcx.def_kind(def.did.to_def_id()) { @@ -354,12 +331,12 @@ pub fn const_eval_raw_provider<'tcx>( // compatibility hazard DefKind::Const | DefKind::AssocConst => { let hir_id = tcx.hir().local_def_id_to_hir_id(def.did); - err.report_as_lint( + 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), - ) + )) } // promoting runtime code is only allowed to error if it references broken // constants any other kind of error will be reported to the user as a @@ -368,31 +345,65 @@ pub fn const_eval_raw_provider<'tcx>( if let Some(p) = cid.promoted { let span = tcx.promoted_mir_of_opt_const_arg(def.to_global())[p].span; if let err_inval!(ReferencedConstant) = err.error { - err.report_as_error( + Err(err.report_as_error( tcx.at(span), "evaluation of constant expression failed", - ) + )) } else { - err.report_as_lint( + Err(err.report_as_lint( tcx.at(span), "reaching this expression at runtime will panic or abort", tcx.hir().local_def_id_to_hir_id(def.did), Some(err.span), - ) + )) } // anything else (array lengths, enum initializers, constant patterns) are // reported as hard errors } else { - err.report_as_error( + Err(err.report_as_error( ecx.tcx.at(ecx.cur_span()), "evaluation of constant value failed", - ) + )) } } } } else { // use of broken constant from other crate - err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant") + Err(err.report_as_error(ecx.tcx.at(ecx.cur_span()), "could not evaluate constant")) } - }) + } + Ok(mplace) => { + // Since evaluation had no errors, valiate the resulting constant: + let validation = try { + // FIXME do not validate promoteds until a decision on + // https://github.com/rust-lang/rust/issues/67465 is made + if cid.promoted.is_none() { + let mut ref_tracking = RefTracking::new(mplace); + while let Some((mplace, path)) = ref_tracking.todo.pop() { + ecx.const_validate_operand( + mplace.into(), + path, + &mut ref_tracking, + /*may_ref_to_static*/ ecx.memory.extra.can_access_statics, + )?; + } + } + }; + if let Err(error) = validation { + // Validation failed, report an 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.emit(); + }, + )) + } else { + // Convert to raw constant + Ok(ConstAlloc { alloc_id: mplace.ptr.assert_ptr().alloc_id, ty: mplace.layout.ty }) + } + } + } } diff --git a/src/librustc_mir/const_eval/fn_queries.rs b/compiler/rustc_mir/src/const_eval/fn_queries.rs similarity index 95% rename from src/librustc_mir/const_eval/fn_queries.rs rename to compiler/rustc_mir/src/const_eval/fn_queries.rs index 9ef63b3322..aca822a05b 100644 --- a/src/librustc_mir/const_eval/fn_queries.rs +++ b/compiler/rustc_mir/src/const_eval/fn_queries.rs @@ -50,7 +50,7 @@ pub fn is_min_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { None => { if let Some(stab) = tcx.lookup_stability(def_id) { if stab.level.is_stable() { - tcx.sess.span_err( + tcx.sess.delay_span_bug( tcx.def_span(def_id), "stable const functions must have either `rustc_const_stable` or \ `rustc_const_unstable` attribute", @@ -151,17 +151,11 @@ fn is_promotable_const_fn(tcx: TyCtxt<'_>, def_id: DefId) -> bool { } } -fn const_fn_is_allowed_fn_ptr(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - is_const_fn(tcx, def_id) - && tcx.lookup_const_stability(def_id).map(|stab| stab.allow_const_fn_ptr).unwrap_or(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, - const_fn_is_allowed_fn_ptr, ..*providers }; } diff --git a/src/librustc_mir/const_eval/machine.rs b/compiler/rustc_mir/src/const_eval/machine.rs similarity index 81% rename from src/librustc_mir/const_eval/machine.rs rename to compiler/rustc_mir/src/const_eval/machine.rs index b0357c508a..73ca7e0d47 100644 --- a/src/librustc_mir/const_eval/machine.rs +++ b/compiler/rustc_mir/src/const_eval/machine.rs @@ -11,7 +11,7 @@ use rustc_ast::Mutability; use rustc_hir::def_id::DefId; use rustc_middle::mir::AssertMessage; use rustc_session::Limit; -use rustc_span::symbol::Symbol; +use rustc_span::symbol::{sym, Symbol}; use crate::interpret::{ self, compile_time_machine, AllocId, Allocation, Frame, GlobalId, ImmTy, InterpCx, @@ -51,7 +51,7 @@ impl<'mir, 'tcx> InterpCx<'mir, 'tcx, CompileTimeInterpreter<'mir, 'tcx>> { let gid = GlobalId { instance, promoted: None }; - let place = self.const_eval_raw(gid)?; + let place = self.eval_to_allocation(gid)?; self.copy_op(place.into(), dest)?; @@ -176,6 +176,38 @@ impl interpret::MayLeak for ! { } } +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::Raw { .. }, Scalar::Raw { .. }) => a == b, + // Equality with integers can never be known for sure. + (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => 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::Raw { .. }, Scalar::Raw { .. }) => 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. + (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr)) + | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr), + // Inequality with integers other than null can never be known for sure. + (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, + // 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>); @@ -234,12 +266,45 @@ impl<'mir, 'tcx> interpret::Machine<'mir, 'tcx> for CompileTimeInterpreter<'mir, ret: Option<(PlaceTy<'tcx>, mir::BasicBlock)>, _unwind: Option, ) -> InterpResult<'tcx> { + // Shared intrinsics. if ecx.emulate_intrinsic(instance, args, ret)? { return Ok(()); } - // An intrinsic that we do not support let intrinsic_name = ecx.tcx.item_name(instance.def_id()); - Err(ConstEvalErrKind::NeedsRfc(format!("calling intrinsic `{}`", intrinsic_name)).into()) + + // 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)?; + } + _ => { + return Err(ConstEvalErrKind::NeedsRfc(format!( + "calling intrinsic `{}`", + intrinsic_name + )) + .into()); + } + } + + ecx.go_to_block(ret); + Ok(()) } fn assert_panic( diff --git a/src/librustc_mir/const_eval/mod.rs b/compiler/rustc_mir/src/const_eval/mod.rs similarity index 60% rename from src/librustc_mir/const_eval/mod.rs rename to compiler/rustc_mir/src/const_eval/mod.rs index e7eeb4b4de..978d2fe000 100644 --- a/src/librustc_mir/const_eval/mod.rs +++ b/compiler/rustc_mir/src/const_eval/mod.rs @@ -2,11 +2,14 @@ use std::convert::TryFrom; +use rustc_hir::Mutability; use rustc_middle::mir; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::{source_map::DUMMY_SP, symbol::Symbol}; -use crate::interpret::{intern_const_alloc_recursive, ConstValue, InternKind, InterpCx}; +use crate::interpret::{ + intern_const_alloc_recursive, ConstValue, InternKind, InterpCx, MemPlaceMeta, Scalar, +}; mod error; mod eval_queries; @@ -44,7 +47,7 @@ pub(crate) fn destructure_const<'tcx>( 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 { + 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: tcx.arena.alloc_slice(&[]) }; @@ -67,3 +70,39 @@ pub(crate) fn destructure_const<'tcx>( 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 Scalar::Ptr(ptr) = mplace.ptr { + assert_eq!( + ecx.memory.get_raw(ptr.alloc_id).unwrap().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 --git a/src/librustc_mir/dataflow/drop_flag_effects.rs b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs similarity index 99% rename from src/librustc_mir/dataflow/drop_flag_effects.rs rename to compiler/rustc_mir/src/dataflow/drop_flag_effects.rs index 707e136678..d1d507e54e 100644 --- a/src/librustc_mir/dataflow/drop_flag_effects.rs +++ b/compiler/rustc_mir/src/dataflow/drop_flag_effects.rs @@ -53,7 +53,7 @@ fn place_contents_drop_state_cannot_differ<'tcx>( place: mir::Place<'tcx>, ) -> bool { let ty = place.ty(body, tcx).ty; - match ty.kind { + match ty.kind() { ty::Array(..) => { debug!( "place_contents_drop_state_cannot_differ place: {:?} ty: {:?} => false", diff --git a/src/librustc_mir/dataflow/framework/cursor.rs b/compiler/rustc_mir/src/dataflow/framework/cursor.rs similarity index 90% rename from src/librustc_mir/dataflow/framework/cursor.rs rename to compiler/rustc_mir/src/dataflow/framework/cursor.rs index 4f5930dc3f..4942bed656 100644 --- a/src/librustc_mir/dataflow/framework/cursor.rs +++ b/compiler/rustc_mir/src/dataflow/framework/cursor.rs @@ -4,6 +4,7 @@ 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}; @@ -26,7 +27,7 @@ where { body: &'mir mir::Body<'tcx>, results: R, - state: BitSet, + state: A::Domain, pos: CursorPosition, @@ -46,17 +47,16 @@ where { /// Returns a new cursor that can inspect `results`. pub fn new(body: &'mir mir::Body<'tcx>, results: R) -> Self { - let bits_per_block = results.borrow().entry_set_for_block(mir::START_BLOCK).domain_size(); - + let bottom_value = results.borrow().analysis.bottom_value(body); ResultsCursor { body, results, - // Initialize to an empty `BitSet` and set `state_needs_reset` to tell the cursor that + // 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: BitSet::new_empty(bits_per_block), + state: bottom_value, pos: CursorPosition::block_entry(mir::START_BLOCK), #[cfg(debug_assertions)] @@ -68,23 +68,21 @@ where self.body } - /// Returns the `Analysis` used to generate the underlying results. + /// 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) -> &BitSet { + pub fn get(&self) -> &A::Domain { &self.state } - /// Returns `true` if the dataflow state at the current location contains the given element. - /// - /// Shorthand for `self.get().contains(elem)` - pub fn contains(&self, elem: A::Idx) -> bool { - self.state.contains(elem) - } - /// 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. @@ -94,7 +92,7 @@ where #[cfg(debug_assertions)] assert!(self.reachable_blocks.contains(block)); - self.state.overwrite(&self.results.borrow().entry_set_for_block(block)); + self.state.clone_from(&self.results.borrow().entry_set_for_block(block)); self.pos = CursorPosition::block_entry(block); self.state_needs_reset = false; } @@ -202,12 +200,23 @@ where /// /// 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 BitSet)) { + 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, diff --git a/src/librustc_mir/dataflow/framework/direction.rs b/compiler/rustc_mir/src/dataflow/framework/direction.rs similarity index 80% rename from src/librustc_mir/dataflow/framework/direction.rs rename to compiler/rustc_mir/src/dataflow/framework/direction.rs index 4512ae96c0..ca2bb6e0bf 100644 --- a/src/librustc_mir/dataflow/framework/direction.rs +++ b/compiler/rustc_mir/src/dataflow/framework/direction.rs @@ -1,10 +1,10 @@ use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::TyCtxt; use std::ops::RangeInclusive; use super::visitor::{ResultsVisitable, ResultsVisitor}; -use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet}; +use super::{Analysis, Effect, EffectIndex, GenKillAnalysis, GenKillSet, SwitchIntTarget}; pub trait Direction { fn is_forward() -> bool; @@ -18,7 +18,7 @@ pub trait Direction { /// `effects.start()` must precede or equal `effects.end()` in this direction. fn apply_effects_in_range( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, effects: RangeInclusive, @@ -27,7 +27,7 @@ pub trait Direction { fn apply_effects_in_block( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, ) where @@ -55,9 +55,9 @@ pub trait Direction { tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, dead_unwinds: Option<&BitSet>, - exit_state: &mut BitSet, + exit_state: &mut A::Domain, block: (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - propagate: impl FnMut(BasicBlock, &BitSet), + propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>; } @@ -72,7 +72,7 @@ impl Direction for Backward { fn apply_effects_in_block( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, ) where @@ -112,7 +112,7 @@ impl Direction for Backward { fn apply_effects_in_range( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, effects: RangeInclusive, @@ -224,9 +224,9 @@ impl Direction for Backward { _tcx: TyCtxt<'tcx>, body: &mir::Body<'tcx>, dead_unwinds: Option<&BitSet>, - exit_state: &mut BitSet, + exit_state: &mut A::Domain, (bb, _bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - mut propagate: impl FnMut(BasicBlock, &BitSet), + mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, { @@ -281,7 +281,7 @@ impl Direction for Forward { fn apply_effects_in_block( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, ) where @@ -321,7 +321,7 @@ impl Direction for Forward { fn apply_effects_in_range( analysis: &A, - state: &mut BitSet, + state: &mut A::Domain, block: BasicBlock, block_data: &mir::BasicBlockData<'tcx>, effects: RangeInclusive, @@ -425,12 +425,12 @@ impl Direction for Forward { fn join_state_into_successors_of( analysis: &A, - tcx: TyCtxt<'tcx>, - body: &mir::Body<'tcx>, + _tcx: TyCtxt<'tcx>, + _body: &mir::Body<'tcx>, dead_unwinds: Option<&BitSet>, - exit_state: &mut BitSet, + exit_state: &mut A::Domain, (bb, bb_data): (BasicBlock, &'_ mir::BasicBlockData<'tcx>), - mut propagate: impl FnMut(BasicBlock, &BitSet), + mut propagate: impl FnMut(BasicBlock, &A::Domain), ) where A: Analysis<'tcx>, { @@ -489,50 +489,23 @@ impl Direction for Forward { } SwitchInt { ref targets, ref values, ref discr, switch_ty: _ } => { - let enum_ = discr - .place() - .and_then(|discr| switch_on_enum_discriminant(tcx, &body, bb_data, discr)); - match enum_ { - // If this is a switch on an enum discriminant, a custom effect may be applied - // along each outgoing edge. - Some((enum_place, enum_def)) => { - // 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 mut tmp = BitSet::new_empty(exit_state.domain_size()); - let mut discriminants = enum_def.discriminants(tcx); - for (value, target) in values.iter().zip(targets.iter().copied()) { - let (variant_idx, _) = - discriminants.find(|&(_, discr)| discr.val == *value).expect( - "Order of `AdtDef::discriminants` differed \ - from that of `SwitchInt::values`", - ); + let mut applier = SwitchIntEdgeEffectApplier { + exit_state, + targets: targets.as_ref(), + values: values.as_ref(), + propagate, + effects_applied: false, + }; - tmp.overwrite(exit_state); - analysis.apply_discriminant_switch_effect( - &mut tmp, - bb, - enum_place, - enum_def, - variant_idx, - ); - propagate(target, &tmp); - } + analysis.apply_switch_int_edge_effects(bb, discr, &mut applier); - // Move out of `tmp` so we don't accidentally use it below. - std::mem::drop(tmp); + let SwitchIntEdgeEffectApplier { + exit_state, mut propagate, effects_applied, .. + } = applier; - // Propagate dataflow state along the "otherwise" edge. - let otherwise = targets.last().copied().unwrap(); - propagate(otherwise, exit_state) - } - - // Otherwise, it's just a normal `SwitchInt`, and every successor sees the same - // exit state. - None => { - for target in targets.iter().copied() { - propagate(target, exit_state); - } + if !effects_applied { + for &target in targets.iter() { + propagate(target, exit_state); } } } @@ -540,37 +513,54 @@ impl Direction for Forward { } } -/// 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: -/// _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)), +struct SwitchIntEdgeEffectApplier<'a, D, F> { + exit_state: &'a mut D, + values: &'a [u128], + targets: &'a [BasicBlock], + propagate: F, - // `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, + effects_applied: bool, +} - t => bug!("`discriminant` called on unexpected type {:?}", t), - } +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.values.iter().zip(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); } - _ => None, + // 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.last().copied().unwrap(); + 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 --git a/src/librustc_mir/dataflow/framework/engine.rs b/compiler/rustc_mir/src/dataflow/framework/engine.rs similarity index 73% rename from src/librustc_mir/dataflow/framework/engine.rs rename to compiler/rustc_mir/src/dataflow/framework/engine.rs index b703852b1d..f39c78f503 100644 --- a/src/librustc_mir/dataflow/framework/engine.rs +++ b/compiler/rustc_mir/src/dataflow/framework/engine.rs @@ -1,5 +1,6 @@ //! A solver for dataflow problems. +use std::borrow::BorrowMut; use std::ffi::OsString; use std::fs; use std::path::PathBuf; @@ -9,14 +10,16 @@ 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::IndexVec; +use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, traversal, BasicBlock}; use rustc_middle::ty::{self, TyCtxt}; use rustc_span::symbol::{sym, Symbol}; +use super::fmt::DebugWithContext; use super::graphviz; use super::{ - visit_results, Analysis, Direction, GenKillAnalysis, GenKillSet, ResultsCursor, ResultsVisitor, + visit_results, Analysis, Direction, GenKill, GenKillAnalysis, GenKillSet, JoinSemiLattice, + ResultsCursor, ResultsVisitor, }; use crate::util::pretty::dump_enabled; @@ -26,7 +29,7 @@ where A: Analysis<'tcx>, { pub analysis: A, - pub(super) entry_sets: IndexVec>, + pub(super) entry_sets: IndexVec, } impl Results<'tcx, A> @@ -39,7 +42,7 @@ where } /// Gets the dataflow state for the given block. - pub fn entry_set_for_block(&self, block: BasicBlock) -> &BitSet { + pub fn entry_set_for_block(&self, block: BasicBlock) -> &A::Domain { &self.entry_sets[block] } @@ -47,7 +50,7 @@ where &self, body: &'mir mir::Body<'tcx>, blocks: impl IntoIterator, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, ) { visit_results(body, blocks, self, vis) } @@ -55,7 +58,7 @@ where pub fn visit_reachable_with( &self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, ) { let blocks = mir::traversal::reachable(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) @@ -64,7 +67,7 @@ where pub fn visit_in_rpo_with( &self, body: &'mir mir::Body<'tcx>, - vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = BitSet>, + vis: &mut impl ResultsVisitor<'mir, 'tcx, FlowState = A::Domain>, ) { let blocks = mir::traversal::reverse_postorder(body); visit_results(body, blocks.map(|(bb, _)| bb), self, vis) @@ -76,21 +79,28 @@ pub struct Engine<'a, 'tcx, A> where A: Analysis<'tcx>, { - bits_per_block: usize, tcx: TyCtxt<'tcx>, body: &'a mir::Body<'tcx>, def_id: DefId, dead_unwinds: Option<&'a BitSet>, - entry_sets: IndexVec>, + entry_sets: IndexVec, + pass_name: Option<&'static str>, analysis: A, /// Cached, cumulative transfer functions for each block. - trans_for_block: Option>>, + // + // 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> +impl Engine<'a, 'tcx, A> where - A: GenKillAnalysis<'tcx>, + 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( @@ -109,22 +119,26 @@ where // Otherwise, compute and store the cumulative transfer function for each block. - let bits_per_block = analysis.bits_per_block(body); - let mut trans_for_block = - IndexVec::from_elem(GenKillSet::identity(bits_per_block), body.basic_blocks()); + 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); } - Self::new(tcx, body, def_id, analysis, Some(trans_for_block)) + let apply_trans = Box::new(move |bb: BasicBlock, state: &mut A::Domain| { + trans_for_block[bb].apply(state.borrow_mut()); + }); + + Self::new(tcx, body, def_id, analysis, Some(apply_trans as Box<_>)) } } -impl Engine<'a, 'tcx, A> +impl Engine<'a, 'tcx, A> where - A: Analysis<'tcx>, + A: Analysis<'tcx, Domain = D>, + D: Clone + JoinSemiLattice, { /// Creates a new `Engine` to solve a dataflow problem with an arbitrary transfer /// function. @@ -145,32 +159,25 @@ where body: &'a mir::Body<'tcx>, def_id: DefId, analysis: A, - trans_for_block: Option>>, + apply_trans_for_block: Option>, ) -> Self { - let bits_per_block = analysis.bits_per_block(body); - - let bottom_value_set = if A::BOTTOM_VALUE { - BitSet::new_filled(bits_per_block) - } else { - BitSet::new_empty(bits_per_block) - }; - - let mut entry_sets = IndexVec::from_elem(bottom_value_set.clone(), body.basic_blocks()); + 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_set { + 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, - bits_per_block, tcx, body, def_id, dead_unwinds: None, + pass_name: None, entry_sets, - trans_for_block, + apply_trans_for_block, } } @@ -184,17 +191,29 @@ where 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> { + pub fn iterate_to_fixpoint(self) -> Results<'tcx, A> + where + A::Domain: DebugWithContext, + { let Engine { analysis, - bits_per_block, body, dead_unwinds, def_id, mut entry_sets, tcx, - trans_for_block, + apply_trans_for_block, + pass_name, .. } = self; @@ -213,14 +232,14 @@ where } } - let mut state = BitSet::new_empty(bits_per_block); + let mut state = analysis.bottom_value(body); while let Some(bb) = dirty_queue.pop() { let bb_data = &body[bb]; // Apply the block transfer function, using the cached one if it exists. - state.overwrite(&entry_sets[bb]); - match &trans_for_block { - Some(trans_for_block) => trans_for_block[bb].apply(&mut state), + state.clone_from(&entry_sets[bb]); + match &apply_trans_for_block { + Some(apply) => apply(bb, &mut state), None => A::Direction::apply_effects_in_block(&analysis, &mut state, bb, bb_data), } @@ -231,8 +250,8 @@ where dead_unwinds, &mut state, (bb, bb_data), - |target: BasicBlock, state: &BitSet| { - let set_changed = analysis.join(&mut entry_sets[target], state); + |target: BasicBlock, state: &A::Domain| { + let set_changed = entry_sets[target].join(state); if set_changed { dirty_queue.insert(target); } @@ -242,7 +261,7 @@ where let results = Results { analysis, entry_sets }; - let res = write_graphviz_results(tcx, def_id, &body, &results, trans_for_block); + let res = write_graphviz_results(tcx, def_id, &body, &results, pass_name); if let Err(e) = res { warn!("Failed to write graphviz dataflow results: {}", e); } @@ -260,10 +279,11 @@ fn write_graphviz_results( def_id: DefId, body: &mir::Body<'tcx>, results: &Results<'tcx, A>, - block_transfer_functions: Option>>, + pass_name: Option<&'static str>, ) -> std::io::Result<()> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { let attrs = match RustcMirAttrs::parse(tcx, def_id) { Ok(attrs) => attrs, @@ -278,39 +298,38 @@ where None if tcx.sess.opts.debugging_opts.dump_mir_dataflow && dump_enabled(tcx, A::NAME, def_id) => { + // FIXME: Use some variant of `pretty::dump_path` for this let mut path = PathBuf::from(&tcx.sess.opts.debugging_opts.dump_mir_dir); + let crate_name = tcx.crate_name(def_id.krate); let item_name = ty::print::with_forced_impl_filename_line(|| { tcx.def_path(def_id).to_filename_friendly_no_crate() }); - path.push(format!("rustc.{}.{}.dot", item_name, A::NAME)); + + let pass_name = pass_name.map(|s| format!(".{}", s)).unwrap_or_default(); + + path.push(format!("{}.{}.{}{}.dot", crate_name, item_name, A::NAME, pass_name)); path } None => return Ok(()), }; - let bits_per_block = results.analysis.bits_per_block(body); - - let mut formatter: Box> = match attrs.formatter { - Some(sym::two_phase) => Box::new(graphviz::TwoPhaseDiff::new(bits_per_block)), - Some(sym::gen_kill) => { - if let Some(trans_for_block) = block_transfer_functions { - Box::new(graphviz::BlockTransferFunc::new(body, trans_for_block)) - } else { - Box::new(graphviz::SimpleDiff::new(body, &results)) - } - } - - // Default to the `SimpleDiff` output style. - _ => Box::new(graphviz::SimpleDiff::new(body, &results)), + let style = match attrs.formatter { + Some(sym::two_phase) => graphviz::OutputStyle::BeforeAndAfter, + _ => graphviz::OutputStyle::AfterOnly, }; debug!("printing dataflow results for {:?} to {}", def_id, path.display()); let mut buf = Vec::new(); - let graphviz = graphviz::Formatter::new(body, def_id, results, &mut *formatter); - dot::render_opts(&graphviz, &mut buf, &[dot::RenderOption::Monospace])?; + let graphviz = graphviz::Formatter::new(body, def_id, 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)?; if let Some(parent) = path.parent() { fs::create_dir_all(parent)?; diff --git a/compiler/rustc_mir/src/dataflow/framework/fmt.rs b/compiler/rustc_mir/src/dataflow/framework/fmt.rs new file mode 100644 index 0000000000..0140a75054 --- /dev/null +++ b/compiler/rustc_mir/src/dataflow/framework/fmt.rs @@ -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}-")?; + self.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 --git a/src/librustc_mir/dataflow/framework/graphviz.rs b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs similarity index 53% rename from src/librustc_mir/dataflow/framework/graphviz.rs rename to compiler/rustc_mir/src/dataflow/framework/graphviz.rs index 896616a217..5d4c425196 100644 --- a/src/librustc_mir/dataflow/framework/graphviz.rs +++ b/compiler/rustc_mir/src/dataflow/framework/graphviz.rs @@ -1,26 +1,41 @@ //! A helpful diagram for debugging dataflow problems. -use std::cell::RefCell; +use std::borrow::Cow; +use std::lazy::SyncOnceCell; use std::{io, ops, str}; +use regex::Regex; use rustc_graphviz as dot; use rustc_hir::def_id::DefId; -use rustc_index::bit_set::{BitSet, HybridBitSet}; -use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::{self, BasicBlock, Body, Location}; -use super::{Analysis, Direction, GenKillSet, Results, ResultsRefCursor}; +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>, def_id: DefId, - - // This must be behind a `RefCell` because `dot::Labeller` takes `&self`. - block_formatter: RefCell>, + results: &'a Results<'tcx, A>, + style: OutputStyle, } impl Formatter<'a, 'tcx, A> @@ -31,15 +46,9 @@ where body: &'a Body<'tcx>, def_id: DefId, results: &'a Results<'tcx, A>, - state_formatter: &'a mut dyn StateFormatter<'tcx, A>, + style: OutputStyle, ) -> Self { - let block_formatter = BlockFormatter { - bg: Background::Light, - results: ResultsRefCursor::new(body, results), - state_formatter, - }; - - Formatter { body, def_id, block_formatter: RefCell::new(block_formatter) } + Formatter { body, def_id, results, style } } } @@ -62,6 +71,7 @@ fn dataflow_successors(body: &Body<'tcx>, bb: BasicBlock) -> Vec { impl dot::Labeller<'_> for Formatter<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { type Node = BasicBlock; type Edge = CfgEdge; @@ -77,7 +87,13 @@ where fn node_label(&self, block: &Self::Node) -> dot::LabelText<'_> { let mut label = Vec::new(); - self.block_formatter.borrow_mut().write_node_label(&mut label, self.body, *block).unwrap(); + 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()) } @@ -126,19 +142,16 @@ where { results: ResultsRefCursor<'a, 'a, 'tcx, A>, bg: Background, - state_formatter: &'a mut dyn StateFormatter<'tcx, A>, + style: OutputStyle, } impl BlockFormatter<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { const HEADER_COLOR: &'static str = "#a0a0a0"; - fn num_state_columns(&self) -> usize { - std::cmp::max(1, self.state_formatter.column_names().len()) - } - fn toggle_background(&mut self) -> Background { let bg = self.bg; self.bg = !bg; @@ -187,40 +200,30 @@ where write!(w, r#""#, fmt = table_fmt)?; // A + B: Block header - if self.state_formatter.column_names().is_empty() { - self.write_block_header_simple(w, block)?; - } else { - self.write_block_header_with_state_columns(w, block)?; + 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_entry_state = self.results.get().clone(); - + let block_start_state = self.results.get().clone(); self.write_row_with_full_state(w, "", "(on start)")?; - // D: Statement transfer functions - for (i, statement) in body[block].statements.iter().enumerate() { - let location = Location { block, statement_index: i }; - let statement_str = format!("{:?}", statement); - self.write_row_for_location(w, &i.to_string(), &statement_str, location)?; - } - - // E: Terminator transfer function - let terminator = body[block].terminator(); - let terminator_loc = body.terminator_loc(block); - let mut terminator_str = String::new(); - terminator.kind.fmt_head(&mut terminator_str).unwrap(); - - self.write_row_for_location(w, "T", &terminator_str, terminator_loc)?; + // 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_entry_state || A::Direction::is_backward() { + 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)", @@ -229,8 +232,11 @@ where self.write_row_with_full_state(w, "", after_terminator_name)?; } - // Write any changes caused by terminator-specific effects - let num_state_columns = self.num_state_columns(); + // 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, _)), @@ -239,44 +245,43 @@ where .. } => { self.write_row(w, "", "(on successful return)", |this, w, fmt| { - write!( - w, - r#""#, - colspan = num_state_columns, - fmt = 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_diff(w, this.results.analysis(), &state_on_unwind, this.results.get())?; - write!(w, "") + write!( + w, + r#"{diff}"#, + 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| { - write!( - w, - r#""#, - colspan = num_state_columns, - fmt = 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_diff( + write!( w, - this.results.analysis(), - &state_on_generator_drop, - this.results.get(), - )?; - write!(w, "") + r#"{diff}"#, + colspan = this.style.num_state_columns(), + fmt = fmt, + diff = diff_pretty( + this.results.get(), + &state_on_generator_drop, + this.results.analysis() + ), + ) })?; } @@ -322,6 +327,7 @@ where &mut self, w: &mut impl io::Write, block: BasicBlock, + state_column_names: &[&str], ) -> io::Result<()> { // +------------------------------------+-------------+ // A | bb4 | STATE | @@ -330,8 +336,6 @@ where // +-+----------------------------------+------+------+ // | | ... | | | - let state_column_names = self.state_formatter.column_names(); - // A write!( w, @@ -357,6 +361,56 @@ where 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( @@ -397,319 +451,176 @@ where 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#"{{"#, - colspan = this.num_state_columns(), + r#"{state}"#, + colspan = this.style.num_state_columns(), fmt = fmt, - )?; - pretty_print_state_elems(w, analysis, state.iter(), ", ", LIMIT_30_ALIGN_1)?; - write!(w, "}}") - }) - } - - fn write_row_for_location( - &mut self, - w: &mut impl io::Write, - i: &str, - mir: &str, - location: Location, - ) -> io::Result<()> { - self.write_row(w, i, mir, |this, w, fmt| { - this.state_formatter.write_state_for_location(w, fmt, &mut this.results, location) + state = format!("{:?}", DebugWithAdapter { this: state, ctxt: analysis }), + ) }) } } -/// Controls what gets printed under the `STATE` header. -pub trait StateFormatter<'tcx, A> +struct StateDiffCollector<'a, 'tcx, A> where A: Analysis<'tcx>, { - /// The columns that will get printed under `STATE`. - fn column_names(&self) -> &[&str]; - - fn write_state_for_location( - &mut self, - w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()>; + analysis: &'a A, + prev_state: A::Domain, + before: Option>, + after: Vec, } -/// Prints a single column containing the state vector immediately *after* each statement. -pub struct SimpleDiff<'a, 'tcx, A> +impl StateDiffCollector<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { - prev_state: ResultsRefCursor<'a, 'a, 'tcx, A>, -} - -impl SimpleDiff<'a, 'tcx, A> -where - A: Analysis<'tcx>, -{ - pub fn new(body: &'a Body<'tcx>, results: &'a Results<'tcx, A>) -> Self { - SimpleDiff { prev_state: ResultsRefCursor::new(body, results) } - } -} - -impl StateFormatter<'tcx, A> for SimpleDiff<'_, 'tcx, A> -where - A: Analysis<'tcx>, -{ - fn column_names(&self) -> &[&str] { - &[] - } - - fn write_state_for_location( - &mut self, - mut w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()> { - if A::Direction::is_forward() { - if location.statement_index == 0 { - self.prev_state.seek_to_block_start(location.block); - } else { - self.prev_state.seek_after_primary_effect(Location { - statement_index: location.statement_index - 1, - ..location - }); - } - } else { - if location == results.body().terminator_loc(location.block) { - self.prev_state.seek_to_block_end(location.block); - } else { - self.prev_state.seek_after_primary_effect(location.successor_within_block()); - } - } - - write!(w, r#""#, fmt = fmt)?; - results.seek_after_primary_effect(location); - let curr_state = results.get(); - write_diff(&mut w, results.analysis(), self.prev_state.get(), curr_state)?; - write!(w, "") - } -} - -/// Prints two state columns, one containing only the "before" effect of each statement and one -/// containing the full effect. -pub struct TwoPhaseDiff { - prev_state: BitSet, - prev_loc: Location, -} - -impl TwoPhaseDiff { - pub fn new(bits_per_block: usize) -> Self { - TwoPhaseDiff { prev_state: BitSet::new_empty(bits_per_block), prev_loc: Location::START } - } -} - -impl StateFormatter<'tcx, A> for TwoPhaseDiff -where - A: Analysis<'tcx>, -{ - fn column_names(&self) -> &[&str] { - &["BEFORE", " AFTER"] - } - - fn write_state_for_location( - &mut self, - mut w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()> { - if location.statement_index == 0 { - results.seek_to_block_entry(location.block); - self.prev_state.overwrite(results.get()); - } else { - // Ensure that we are visiting statements in order, so `prev_state` is correct. - assert_eq!(self.prev_loc.successor_within_block(), location); - } - - self.prev_loc = location; - - // Before - - write!(w, r#""#, fmt = fmt)?; - results.seek_before_primary_effect(location); - let curr_state = results.get(); - write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?; - self.prev_state.overwrite(curr_state); - write!(w, "")?; - - // After - - write!(w, r#""#, fmt = fmt)?; - results.seek_after_primary_effect(location); - let curr_state = results.get(); - write_diff(&mut w, results.analysis(), &self.prev_state, curr_state)?; - self.prev_state.overwrite(curr_state); - write!(w, "") - } -} - -/// Prints the gen/kill set for the entire block. -pub struct BlockTransferFunc<'a, 'tcx, T: Idx> { - body: &'a mir::Body<'tcx>, - trans_for_block: IndexVec>, -} - -impl BlockTransferFunc<'mir, 'tcx, T> { - pub fn new( - body: &'mir mir::Body<'tcx>, - trans_for_block: IndexVec>, + fn run( + body: &'a mir::Body<'tcx>, + block: BasicBlock, + results: &'a Results<'tcx, A>, + style: OutputStyle, ) -> Self { - BlockTransferFunc { body, trans_for_block } - } -} - -impl StateFormatter<'tcx, A> for BlockTransferFunc<'mir, 'tcx, A::Idx> -where - A: Analysis<'tcx>, -{ - fn column_names(&self) -> &[&str] { - &["GEN", "KILL"] - } - - fn write_state_for_location( - &mut self, - mut w: &mut dyn io::Write, - fmt: &str, - results: &mut ResultsRefCursor<'_, '_, 'tcx, A>, - location: Location, - ) -> io::Result<()> { - // Only print a single row. - if location.statement_index != 0 { - return Ok(()); - } - - let block_trans = &self.trans_for_block[location.block]; - let rowspan = self.body.basic_blocks()[location.block].statements.len(); - - for set in &[&block_trans.gen, &block_trans.kill] { - write!( - w, - r#""#, - fmt = fmt, - rowspan = rowspan - )?; - - pretty_print_state_elems(&mut w, results.analysis(), set.iter(), BR_LEFT, None)?; - write!(w, "")?; - } - - Ok(()) - } -} - -/// Writes two lines, one containing the added bits and one the removed bits. -fn write_diff>( - w: &mut impl io::Write, - analysis: &A, - from: &BitSet, - to: &BitSet, -) -> io::Result<()> { - assert_eq!(from.domain_size(), to.domain_size()); - let len = from.domain_size(); - - let mut set = HybridBitSet::new_empty(len); - let mut clear = HybridBitSet::new_empty(len); - - // FIXME: Implement a lazy iterator over the symmetric difference of two bitsets. - for i in (0..len).map(A::Idx::new) { - match (from.contains(i), to.contains(i)) { - (false, true) => set.insert(i), - (true, false) => clear.insert(i), - _ => continue, + let mut collector = StateDiffCollector { + analysis: &results.analysis, + prev_state: results.analysis.bottom_value(body), + after: vec![], + before: (style == OutputStyle::BeforeAndAfter).then_some(vec![]), }; - } - if !set.is_empty() { - write!(w, r#"+"#)?; - pretty_print_state_elems(w, analysis, set.iter(), ", ", LIMIT_30_ALIGN_1)?; - write!(w, r#""#)?; + results.visit_with(body, std::iter::once(block), &mut collector); + collector } - - if !set.is_empty() && !clear.is_empty() { - write!(w, "{}", BR_LEFT)?; - } - - if !clear.is_empty() { - write!(w, r#"-"#)?; - pretty_print_state_elems(w, analysis, clear.iter(), ", ", LIMIT_30_ALIGN_1)?; - write!(w, r#""#)?; - } - - Ok(()) } -const BR_LEFT: &str = r#"
"#; -const BR_LEFT_SPACE: &str = r#"
"#; - -/// Line break policy that breaks at 40 characters and starts the next line with a single space. -const LIMIT_30_ALIGN_1: Option = Some(LineBreak { sequence: BR_LEFT_SPACE, limit: 30 }); - -struct LineBreak { - sequence: &'static str, - limit: usize, -} - -/// Formats each `elem` using the pretty printer provided by `analysis` into a list with the given -/// separator (`sep`). -/// -/// Optionally, it will break lines using the given character sequence (usually `
`) and -/// character limit. -fn pretty_print_state_elems
( - w: &mut impl io::Write, - analysis: &A, - elems: impl Iterator, - sep: &str, - line_break: Option, -) -> io::Result +impl ResultsVisitor<'a, 'tcx> for StateDiffCollector<'a, 'tcx, A> where A: Analysis<'tcx>, + A::Domain: DebugWithContext, { - let sep_width = sep.chars().count(); + type FlowState = A::Domain; - let mut buf = Vec::new(); - - let mut first = true; - let mut curr_line_width = 0; - let mut line_break_inserted = false; - - for idx in elems { - buf.clear(); - analysis.pretty_print_idx(&mut buf, idx)?; - let idx_str = - str::from_utf8(&buf).expect("Output of `pretty_print_idx` must be valid UTF-8"); - let escaped = dot::escape_html(idx_str); - let escaped_width = escaped.chars().count(); - - if first { - first = false; - } else { - write!(w, "{}", sep)?; - curr_line_width += sep_width; - - if let Some(line_break) = &line_break { - if curr_line_width + sep_width + escaped_width > line_break.limit { - write!(w, "{}", line_break.sequence)?; - line_break_inserted = true; - curr_line_width = 0; - } - } + 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); } - - write!(w, "{}", escaped)?; - curr_line_width += escaped_width; } - Ok(line_break_inserted) + 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. diff --git a/compiler/rustc_mir/src/dataflow/framework/lattice.rs b/compiler/rustc_mir/src/dataflow/framework/lattice.rs new file mode 100644 index 0000000000..e7ef9267db --- /dev/null +++ b/compiler/rustc_mir/src/dataflow/framework/lattice.rs @@ -0,0 +1,230 @@ +//! 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}; + +/// 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 self.iter_mut().zip(other.iter()) { + 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 self.iter_mut().zip(other.iter()) { + 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 --git a/src/librustc_mir/dataflow/framework/mod.rs b/compiler/rustc_mir/src/dataflow/framework/mod.rs similarity index 76% rename from src/librustc_mir/dataflow/framework/mod.rs rename to compiler/rustc_mir/src/dataflow/framework/mod.rs index a21bbacb46..65c159e6a7 100644 --- a/src/librustc_mir/dataflow/framework/mod.rs +++ b/compiler/rustc_mir/src/dataflow/framework/mod.rs @@ -30,82 +30,39 @@ //! //! [gen-kill]: https://en.wikipedia.org/wiki/Data-flow_analysis#Bit_vector_problems +use std::borrow::BorrowMut; use std::cmp::Ordering; -use std::io; use rustc_hir::def_id::DefId; use rustc_index::bit_set::{BitSet, HybridBitSet}; use rustc_index::vec::Idx; use rustc_middle::mir::{self, BasicBlock, Location}; -use rustc_middle::ty::{self, TyCtxt}; -use rustc_target::abi::VariantIdx; +use rustc_middle::ty::TyCtxt; mod cursor; mod direction; mod engine; +pub mod fmt; 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}; -/// Parameterization for the precise form of data flow that is used. -/// -/// `BottomValue` determines whether the initial entry set for each basic block is empty or full. -/// This also determines the semantics of the lattice `join` operator used to merge dataflow -/// results, since dataflow works by starting at the bottom and moving monotonically to a fixed -/// point. -/// -/// This means, for propagation across the graph, that you either want to start at all-zeroes and -/// then use Union as your merge when propagating, or you start at all-ones and then use Intersect -/// as your merge when propagating. -pub trait BottomValue { - /// Specifies the initial value for each bit in the entry set for each basic block. - const BOTTOM_VALUE: bool; - - /// Merges `in_set` into `inout_set`, returning `true` if `inout_set` changed. - /// - /// It is almost certainly wrong to override this, since it automatically applies - /// * `inout_set & in_set` if `BOTTOM_VALUE == true` - /// * `inout_set | in_set` if `BOTTOM_VALUE == false` - /// - /// This means that if a bit is not `BOTTOM_VALUE`, it is propagated into all target blocks. - /// For clarity, the above statement again from a different perspective: - /// A bit in the block's entry set is `!BOTTOM_VALUE` if *any* predecessor block's bit value is - /// `!BOTTOM_VALUE`. - /// - /// There are situations where you want the opposite behaviour: propagate only if *all* - /// predecessor blocks's value is `!BOTTOM_VALUE`. - /// E.g. if you want to know whether a bit is *definitely* set at a specific location. This - /// means that all code paths leading to the location must have set the bit, instead of any - /// code path leading there. - /// - /// If you want this kind of "definitely set" analysis, you need to - /// 1. Invert `BOTTOM_VALUE` - /// 2. Reset the `entry_set` in `start_block_effect` to `!BOTTOM_VALUE` - /// 3. Override `join` to do the opposite from what it's doing now. - #[inline] - fn join(&self, inout_set: &mut BitSet, in_set: &BitSet) -> bool { - if !Self::BOTTOM_VALUE { inout_set.union(in_set) } else { inout_set.intersect(in_set) } - } -} - /// Define the domain of a dataflow problem. /// -/// This trait specifies the lattice on which this analysis operates. For now, this must be a -/// powerset of values of type `Idx`. The elements of this lattice are represented with a `BitSet` -/// and referred to as the state vector. -/// -/// This trait also defines the initial value for the dataflow state upon entry to the -/// `START_BLOCK`, as well as some names used to refer to this analysis when debugging. -pub trait AnalysisDomain<'tcx>: BottomValue { - /// The type of the elements in the state vector. - type Idx: Idx; +/// 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 analyis. Either `Forward` or `Backward`. + /// The direction of this analysis. Either `Forward` or `Backward`. type Direction: Direction = Forward; /// A descriptive name for this analysis. Used only for debugging. @@ -114,11 +71,10 @@ pub trait AnalysisDomain<'tcx>: BottomValue { /// suitable as part of a filename. const NAME: &'static str; - /// The size of the state vector. - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize; + /// 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 entry set of the `START_BLOCK` to contain the initial state for dataflow - /// analysis. + /// 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. @@ -126,20 +82,30 @@ pub trait AnalysisDomain<'tcx>: BottomValue { // 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 BitSet); - - /// Prints an element in the state vector for debugging. - fn pretty_print_idx(&self, w: &mut impl io::Write, idx: Self::Idx) -> io::Result<()> { - write!(w, "{:?}", idx) - } + 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 BitSet, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ); @@ -152,7 +118,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// analyses should not implement this without implementing `apply_statement_effect`. fn apply_before_statement_effect( &self, - _state: &mut BitSet, + _state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, _location: Location, ) { @@ -166,7 +132,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// initialized here. fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ); @@ -179,12 +145,14 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// analyses should not implement this without implementing `apply_terminator_effect`. fn apply_before_terminator_effect( &self, - _state: &mut BitSet, + _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. /// @@ -192,7 +160,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// edges. fn apply_call_return_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, block: BasicBlock, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], @@ -207,7 +175,7 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// By default, no effects happen. fn apply_yield_resume_effect( &self, - _state: &mut BitSet, + _state: &mut Self::Domain, _resume_block: BasicBlock, _resume_place: mir::Place<'tcx>, ) { @@ -216,20 +184,28 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// Updates the current dataflow state with the effect of taking a particular branch in a /// `SwitchInt` terminator. /// - /// Much like `apply_call_return_effect`, this effect is only propagated along a single - /// outgoing edge from this basic block. + /// 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_discriminant_switch_effect( + fn apply_switch_int_edge_effects( &self, - _state: &mut BitSet, _block: BasicBlock, - _enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - _variant: VariantIdx, + _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 @@ -264,6 +240,8 @@ pub trait Analysis<'tcx>: AnalysisDomain<'tcx> { /// /// `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, @@ -298,6 +276,8 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { ) { } + /* Edge-specific effects */ + /// See `Analysis::apply_call_return_effect`. fn call_return_effect( &self, @@ -317,14 +297,12 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { ) { } - /// See `Analysis::apply_discriminant_switch_effect`. - fn discriminant_switch_effect( + /// See `Analysis::apply_switch_int_edge_effects`. + fn switch_int_edge_effects>( &self, - _state: &mut impl GenKill, _block: BasicBlock, - _enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - _variant: VariantIdx, + _discr: &mir::Operand<'tcx>, + _edge_effects: &mut impl SwitchIntEdgeEffects, ) { } } @@ -332,10 +310,11 @@ pub trait GenKillAnalysis<'tcx>: Analysis<'tcx> { impl
Analysis<'tcx> for A where A: GenKillAnalysis<'tcx>, + A::Domain: GenKill + BorrowMut>, { fn apply_statement_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -344,7 +323,7 @@ where fn apply_before_statement_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -353,7 +332,7 @@ where fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -362,16 +341,18 @@ where fn apply_before_terminator_effect( &self, - state: &mut BitSet, + 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 BitSet, + state: &mut A::Domain, block: BasicBlock, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], @@ -382,24 +363,24 @@ where fn apply_yield_resume_effect( &self, - state: &mut BitSet, + state: &mut A::Domain, resume_block: BasicBlock, resume_place: mir::Place<'tcx>, ) { self.yield_resume_effect(state, resume_block, resume_place); } - fn apply_discriminant_switch_effect( + fn apply_switch_int_edge_effects( &self, - state: &mut BitSet, block: BasicBlock, - enum_place: mir::Place<'tcx>, - adt: &ty::AdtDef, - variant: VariantIdx, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { - self.discriminant_switch_effect(state, block, enum_place, adt, variant); + self.switch_int_edge_effects(block, discr, edge_effects); } + /* Extension methods */ + fn into_engine( self, tcx: TyCtxt<'tcx>, @@ -450,7 +431,7 @@ pub trait GenKill { /// 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 { +pub struct GenKillSet { gen: HybridBitSet, kill: HybridBitSet, } @@ -464,7 +445,6 @@ impl GenKillSet { } } - /// Applies this transfer function to the given state vector. pub fn apply(&self, state: &mut BitSet) { state.union(&self.gen); state.subtract(&self.kill); @@ -493,6 +473,16 @@ impl GenKill for BitSet { } } +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 { @@ -552,5 +542,17 @@ impl EffectIndex { } } +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 --git a/src/librustc_mir/dataflow/framework/tests.rs b/compiler/rustc_mir/src/dataflow/framework/tests.rs similarity index 93% rename from src/librustc_mir/dataflow/framework/tests.rs rename to compiler/rustc_mir/src/dataflow/framework/tests.rs index 9349f5133a..a598912167 100644 --- a/src/librustc_mir/dataflow/framework/tests.rs +++ b/compiler/rustc_mir/src/dataflow/framework/tests.rs @@ -9,7 +9,6 @@ use rustc_middle::ty; use rustc_span::DUMMY_SP; use super::*; -use crate::dataflow::BottomValue; /// Creates a `mir::Body` with a few disconnected basic blocks. /// @@ -92,13 +91,13 @@ impl MockAnalysis<'tcx, D> { /// 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 = BitSet::new_empty(self.bits_per_block(self.body)); + 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 = BitSet::new_empty(self.bits_per_block(self.body)); + 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() { @@ -130,7 +129,7 @@ impl MockAnalysis<'tcx, D> { /// would be `[102, 0, 1, 2, 3, 4]`. fn expected_state_at_target(&self, target: SeekTarget) -> BitSet { let block = target.block(); - let mut ret = BitSet::new_empty(self.bits_per_block(self.body)); + let mut ret = self.bottom_value(self.body); ret.insert(Self::BASIC_BLOCK_OFFSET + block.index()); let target = match target { @@ -161,21 +160,17 @@ impl MockAnalysis<'tcx, D> { } } -impl BottomValue for MockAnalysis<'tcx, D> { - const BOTTOM_VALUE: bool = false; -} - impl AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { - type Idx = usize; + type Domain = BitSet; type Direction = D; const NAME: &'static str = "mock"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - Self::BASIC_BLOCK_OFFSET + body.basic_blocks().len() + 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 BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { unimplemented!("This is never called since `MockAnalysis` is never iterated to fixpoint"); } } @@ -183,7 +178,7 @@ impl AnalysisDomain<'tcx> for MockAnalysis<'tcx, D> { impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_statement_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { @@ -193,7 +188,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_before_statement_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _statement: &mir::Statement<'tcx>, location: Location, ) { @@ -203,7 +198,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -213,7 +208,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_before_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, _terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -223,7 +218,7 @@ impl Analysis<'tcx> for MockAnalysis<'tcx, D> { fn apply_call_return_effect( &self, - _state: &mut BitSet, + _state: &mut Self::Domain, _block: BasicBlock, _func: &mir::Operand<'tcx>, _args: &[mir::Operand<'tcx>], diff --git a/src/librustc_mir/dataflow/framework/visitor.rs b/compiler/rustc_mir/src/dataflow/framework/visitor.rs similarity index 95% rename from src/librustc_mir/dataflow/framework/visitor.rs rename to compiler/rustc_mir/src/dataflow/framework/visitor.rs index 257f3cb9a6..82eb734ed0 100644 --- a/src/librustc_mir/dataflow/framework/visitor.rs +++ b/compiler/rustc_mir/src/dataflow/framework/visitor.rs @@ -1,4 +1,3 @@ -use rustc_index::bit_set::BitSet; use rustc_middle::mir::{self, BasicBlock, Location}; use super::{Analysis, Direction, Results}; @@ -139,16 +138,16 @@ impl<'tcx, A> ResultsVisitable<'tcx> for Results<'tcx, A> where A: Analysis<'tcx>, { - type FlowState = BitSet; + type FlowState = A::Domain; type Direction = A::Direction; fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { - BitSet::new_empty(self.analysis.bits_per_block(body)) + self.analysis.bottom_value(body) } fn reset_to_block_entry(&self, state: &mut Self::FlowState, block: BasicBlock) { - state.overwrite(&self.entry_set_for_block(block)); + state.clone_from(&self.entry_set_for_block(block)); } fn reconstruct_before_statement_effect( @@ -217,11 +216,11 @@ macro_rules! impl_visitable { $( $A: Analysis<'tcx, Direction = D>, )* { type Direction = D; - type FlowState = $T<$( BitSet<$A::Idx> ),*>; + type FlowState = $T<$( $A::Domain ),*>; fn new_flow_state(&self, body: &mir::Body<'tcx>) -> Self::FlowState { $T { - $( $field: BitSet::new_empty(self.$field.analysis.bits_per_block(body)) ),* + $( $field: self.$field.analysis.bottom_value(body) ),* } } @@ -230,7 +229,7 @@ macro_rules! impl_visitable { state: &mut Self::FlowState, block: BasicBlock, ) { - $( state.$field.overwrite(&self.$field.entry_set_for_block(block)); )* + $( state.$field.clone_from(&self.$field.entry_set_for_block(block)); )* } fn reconstruct_before_statement_effect( diff --git a/src/librustc_mir/dataflow/impls/borrowed_locals.rs b/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs similarity index 97% rename from src/librustc_mir/dataflow/impls/borrowed_locals.rs rename to compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs index a3fc51cad6..65e04ed683 100644 --- a/src/librustc_mir/dataflow/impls/borrowed_locals.rs +++ b/compiler/rustc_mir/src/dataflow/impls/borrowed_locals.rs @@ -82,15 +82,15 @@ impl AnalysisDomain<'tcx> for MaybeBorrowedLocals where K: BorrowAnalysisKind<'tcx>, { - type Idx = Local; - + type Domain = BitSet; const NAME: &'static str = K::ANALYSIS_NAME; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls().len() + 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 BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, _: &mut Self::Domain) { // No locals are aliased on function entry } } @@ -99,6 +99,8 @@ impl GenKillAnalysis<'tcx> for MaybeBorrowedLocals where K: BorrowAnalysisKind<'tcx>, { + type Idx = Local; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -128,11 +130,6 @@ where } } -impl BottomValue for MaybeBorrowedLocals { - // bottom = unborrowed - const BOTTOM_VALUE: bool = false; -} - /// A `Visitor` that defines the transfer function for `MaybeBorrowedLocals`. struct TransferFunction<'a, T, K> { trans: &'a mut T, diff --git a/src/librustc_mir/dataflow/impls/borrows.rs b/compiler/rustc_mir/src/dataflow/impls/borrows.rs similarity index 96% rename from src/librustc_mir/dataflow/impls/borrows.rs rename to compiler/rustc_mir/src/dataflow/impls/borrows.rs index aeb7ffe3e3..0be13b6ba8 100644 --- a/src/librustc_mir/dataflow/impls/borrows.rs +++ b/compiler/rustc_mir/src/dataflow/impls/borrows.rs @@ -8,9 +8,9 @@ use rustc_index::bit_set::BitSet; use crate::borrow_check::{ places_conflict, BorrowSet, PlaceConflictBias, PlaceExt, RegionInferenceContext, ToRegionVid, }; -use crate::dataflow::BottomValue; -use crate::dataflow::{self, GenKill}; +use crate::dataflow::{self, fmt::DebugWithContext, GenKill}; +use std::fmt; use std::rc::Rc; rustc_index::newtype_index! { @@ -227,25 +227,24 @@ impl<'a, 'tcx> Borrows<'a, 'tcx> { } impl<'tcx> dataflow::AnalysisDomain<'tcx> for Borrows<'_, 'tcx> { - type Idx = BorrowIndex; + type Domain = BitSet; const NAME: &'static str = "borrows"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.borrow_set.len() * 2 + 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 BitSet) { + 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. } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, idx: Self::Idx) -> std::io::Result<()> { - write!(w, "{:?}", self.location(idx)) - } } impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { + type Idx = BorrowIndex; + fn before_statement_effect( &self, trans: &mut impl GenKill, @@ -344,7 +343,8 @@ impl<'tcx> dataflow::GenKillAnalysis<'tcx> for Borrows<'_, 'tcx> { } } -impl<'a, 'tcx> BottomValue for Borrows<'a, 'tcx> { - /// bottom = nothing is reserved or activated yet; - const BOTTOM_VALUE: bool = false; +impl DebugWithContext> for BorrowIndex { + fn fmt_with(&self, ctxt: &Borrows<'_, '_>, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", ctxt.location(*self)) + } } diff --git a/src/librustc_mir/dataflow/impls/init_locals.rs b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs similarity index 91% rename from src/librustc_mir/dataflow/impls/init_locals.rs rename to compiler/rustc_mir/src/dataflow/impls/init_locals.rs index 0e7cd1bb0e..bb7292cd03 100644 --- a/src/librustc_mir/dataflow/impls/init_locals.rs +++ b/compiler/rustc_mir/src/dataflow/impls/init_locals.rs @@ -2,7 +2,7 @@ //! //! A local will be maybe initialized if *any* projections of that local might be initialized. -use crate::dataflow::{self, BottomValue, GenKill}; +use crate::dataflow::{self, GenKill}; use rustc_index::bit_set::BitSet; use rustc_middle::mir::visit::{PlaceContext, Visitor}; @@ -10,21 +10,17 @@ use rustc_middle::mir::{self, BasicBlock, Local, Location}; pub struct MaybeInitializedLocals; -impl BottomValue for MaybeInitializedLocals { - /// bottom = uninit - const BOTTOM_VALUE: bool = false; -} - impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = "maybe_init_locals"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + 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 BitSet) { + 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); @@ -33,6 +29,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeInitializedLocals { } impl dataflow::GenKillAnalysis<'tcx> for MaybeInitializedLocals { + type Idx = Local; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -99,7 +97,6 @@ where PlaceContext::NonUse( NonUseContext::StorageLive | NonUseContext::AscribeUserTy - | NonUseContext::Coverage | NonUseContext::VarDebugInfo, ) | PlaceContext::NonMutatingUse( diff --git a/src/librustc_mir/dataflow/impls/liveness.rs b/compiler/rustc_mir/src/dataflow/impls/liveness.rs similarity index 94% rename from src/librustc_mir/dataflow/impls/liveness.rs rename to compiler/rustc_mir/src/dataflow/impls/liveness.rs index 784b0bd929..b0da28156d 100644 --- a/src/librustc_mir/dataflow/impls/liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/liveness.rs @@ -2,7 +2,7 @@ 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, BottomValue, GenKill, GenKillAnalysis}; +use crate::dataflow::{AnalysisDomain, Backward, GenKill, GenKillAnalysis}; /// A [live-variable dataflow analysis][liveness]. /// @@ -22,27 +22,25 @@ impl MaybeLiveLocals { } } -impl BottomValue for MaybeLiveLocals { - // bottom = not live - const BOTTOM_VALUE: bool = false; -} - impl AnalysisDomain<'tcx> for MaybeLiveLocals { - type Idx = Local; + type Domain = BitSet; type Direction = Backward; const NAME: &'static str = "liveness"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + 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 BitSet) { + 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, diff --git a/src/librustc_mir/dataflow/impls/mod.rs b/compiler/rustc_mir/src/dataflow/impls/mod.rs similarity index 74% rename from src/librustc_mir/dataflow/impls/mod.rs rename to compiler/rustc_mir/src/dataflow/impls/mod.rs index 8975faec48..185f0edfeb 100644 --- a/src/librustc_mir/dataflow/impls/mod.rs +++ b/compiler/rustc_mir/src/dataflow/impls/mod.rs @@ -6,19 +6,19 @@ 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 rustc_target::abi::VariantIdx; use super::MoveDataParamEnv; use crate::util::elaborate_drops::DropFlagState; use super::move_paths::{HasMoveData, InitIndex, InitKind, MoveData, MovePathIndex}; -use super::{AnalysisDomain, BottomValue, GenKill, GenKillAnalysis}; +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; @@ -204,7 +204,7 @@ impl<'a, 'tcx> HasMoveData<'tcx> for DefinitelyInitializedPlaces<'a, 'tcx> { /// `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 `Storage Dead`. +/// for a function, without an intervening `StorageDead`. /// /// This dataflow is used to determine if an immutable local variable may /// be assigned to. @@ -290,27 +290,25 @@ impl<'a, 'tcx> DefinitelyInitializedPlaces<'a, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { - type Idx = MovePathIndex; - + type Domain = BitSet; const NAME: &'static str = "maybe_init"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().move_paths.len() + 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 BitSet) { + 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); }); } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { - write!(w, "{}", self.move_data().move_paths[mpi]) - } } impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -354,40 +352,66 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeInitializedPlaces<'_, 'tcx> { ); } - fn discriminant_switch_effect( + fn switch_int_edge_effects>( &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - variant: VariantIdx, + block: mir::BasicBlock, + discr: &mir::Operand<'tcx>, + edge_effects: &mut impl SwitchIntEdgeEffects, ) { - // 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), - ); + 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 Idx = MovePathIndex; + type Domain = BitSet; const NAME: &'static str = "maybe_uninit"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().move_paths.len() + 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, body: &mir::Body<'tcx>, state: &mut BitSet) { + fn initialize_start_block(&self, _: &mir::Body<'tcx>, state: &mut Self::Domain) { // set all bits to 1 (uninit) before gathering counterevidence - assert!(self.bits_per_block(body) == state.domain_size()); state.insert_all(); drop_flag_effects_for_function_entry(self.tcx, self.body, self.mdpe, |path, s| { @@ -395,13 +419,11 @@ impl<'tcx> AnalysisDomain<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { state.remove(path); }); } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { - write!(w, "{}", self.move_data().move_paths[mpi]) - } } impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -445,56 +467,82 @@ impl<'tcx> GenKillAnalysis<'tcx> for MaybeUninitializedPlaces<'_, 'tcx> { ); } - fn discriminant_switch_effect( + fn switch_int_edge_effects>( &self, - trans: &mut impl GenKill, - _block: mir::BasicBlock, - enum_place: mir::Place<'tcx>, - _adt: &ty::AdtDef, - variant: VariantIdx, + 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; } - // 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), - ); + 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> { - type Idx = MovePathIndex; + /// Use set intersection as the join operator. + type Domain = lattice::Dual>; const NAME: &'static str = "definite_init"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().move_paths.len() + 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 BitSet) { - state.clear(); + 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.insert(path); + state.0.insert(path); }); } - - fn pretty_print_idx(&self, w: &mut impl std::io::Write, mpi: Self::Idx) -> std::io::Result<()> { - write!(w, "{}", self.move_data().move_paths[mpi]) - } } impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { + type Idx = MovePathIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -540,15 +588,16 @@ impl<'tcx> GenKillAnalysis<'tcx> for DefinitelyInitializedPlaces<'_, 'tcx> { } impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { - type Idx = InitIndex; + type Domain = BitSet; const NAME: &'static str = "ever_init"; - fn bits_per_block(&self, _: &mir::Body<'tcx>) -> usize { - self.move_data().inits.len() + 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 BitSet) { + 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)); } @@ -556,6 +605,8 @@ impl<'tcx> AnalysisDomain<'tcx> for EverInitializedPlaces<'_, 'tcx> { } impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { + type Idx = InitIndex; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -626,22 +677,41 @@ impl<'tcx> GenKillAnalysis<'tcx> for EverInitializedPlaces<'_, 'tcx> { } } -impl<'a, 'tcx> BottomValue for MaybeInitializedPlaces<'a, 'tcx> { - /// bottom = uninitialized - const BOTTOM_VALUE: bool = false; -} +/// 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)), -impl<'a, 'tcx> BottomValue for MaybeUninitializedPlaces<'a, 'tcx> { - /// bottom = initialized (start_block_effect counters this at outset) - const BOTTOM_VALUE: bool = false; -} + // `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, -impl<'a, 'tcx> BottomValue for DefinitelyInitializedPlaces<'a, 'tcx> { - /// bottom = initialized (start_block_effect counters this at outset) - const BOTTOM_VALUE: bool = true; -} + t => bug!("`discriminant` called on unexpected type {:?}", t), + } + } -impl<'a, 'tcx> BottomValue for EverInitializedPlaces<'a, 'tcx> { - /// bottom = no initialized variables by default - const BOTTOM_VALUE: bool = false; + _ => None, + } } diff --git a/src/librustc_mir/dataflow/impls/storage_liveness.rs b/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs similarity index 95% rename from src/librustc_mir/dataflow/impls/storage_liveness.rs rename to compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs index 21623e3cad..9250cd4084 100644 --- a/src/librustc_mir/dataflow/impls/storage_liveness.rs +++ b/compiler/rustc_mir/src/dataflow/impls/storage_liveness.rs @@ -1,6 +1,5 @@ pub use super::*; -use crate::dataflow::BottomValue; use crate::dataflow::{self, GenKill, Results, ResultsRefCursor}; use crate::util::storage::AlwaysLiveLocals; use rustc_middle::mir::visit::{NonMutatingUseContext, PlaceContext, Visitor}; @@ -19,15 +18,16 @@ impl MaybeStorageLive { } impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = "maybe_storage_live"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + 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 BitSet) { + 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); @@ -40,6 +40,8 @@ impl dataflow::AnalysisDomain<'tcx> for MaybeStorageLive { } impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive { + type Idx = Local; + fn statement_effect( &self, trans: &mut impl GenKill, @@ -74,11 +76,6 @@ impl dataflow::GenKillAnalysis<'tcx> for MaybeStorageLive { } } -impl BottomValue for MaybeStorageLive { - /// bottom = dead - const BOTTOM_VALUE: bool = false; -} - type BorrowedLocalsResults<'a, 'tcx> = ResultsRefCursor<'a, 'a, 'tcx, MaybeBorrowedLocals>; /// Dataflow analysis that determines whether each local requires storage at a @@ -101,15 +98,16 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { } impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = "requires_storage"; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + 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 BitSet) { + 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) { @@ -119,6 +117,8 @@ impl<'mir, 'tcx> dataflow::AnalysisDomain<'tcx> for MaybeRequiresStorage<'mir, ' } impl<'mir, 'tcx> dataflow::GenKillAnalysis<'tcx> for MaybeRequiresStorage<'mir, 'tcx> { + type Idx = Local; + fn before_statement_effect( &self, trans: &mut impl GenKill, @@ -285,11 +285,6 @@ impl<'mir, 'tcx> MaybeRequiresStorage<'mir, 'tcx> { } } -impl<'mir, 'tcx> BottomValue for MaybeRequiresStorage<'mir, 'tcx> { - /// bottom = dead - const BOTTOM_VALUE: bool = false; -} - struct MoveVisitor<'a, 'mir, 'tcx, T> { borrowed_locals: &'a RefCell>, trans: &'a mut T, diff --git a/src/librustc_mir/dataflow/mod.rs b/compiler/rustc_mir/src/dataflow/mod.rs similarity index 82% rename from src/librustc_mir/dataflow/mod.rs rename to compiler/rustc_mir/src/dataflow/mod.rs index a0c2463605..5575a97982 100644 --- a/src/librustc_mir/dataflow/mod.rs +++ b/compiler/rustc_mir/src/dataflow/mod.rs @@ -5,9 +5,9 @@ use rustc_span::symbol::{sym, Symbol}; pub(crate) use self::drop_flag_effects::*; pub use self::framework::{ - visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState, BorrowckResults, - BottomValue, Engine, Forward, GenKill, GenKillAnalysis, Results, ResultsCursor, - ResultsRefCursor, ResultsVisitor, + fmt, lattice, visit_results, Analysis, AnalysisDomain, Backward, BorrowckFlowState, + BorrowckResults, Engine, Forward, GenKill, GenKillAnalysis, JoinSemiLattice, Results, + ResultsCursor, ResultsRefCursor, ResultsVisitor, }; use self::move_paths::MoveData; diff --git a/src/librustc_mir/dataflow/move_paths/abs_domain.rs b/compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs similarity index 100% rename from src/librustc_mir/dataflow/move_paths/abs_domain.rs rename to compiler/rustc_mir/src/dataflow/move_paths/abs_domain.rs diff --git a/src/librustc_mir/dataflow/move_paths/builder.rs b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs similarity index 97% rename from src/librustc_mir/dataflow/move_paths/builder.rs rename to compiler/rustc_mir/src/dataflow/move_paths/builder.rs index e567063e0d..5c3e353840 100644 --- a/src/librustc_mir/dataflow/move_paths/builder.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/builder.rs @@ -4,7 +4,6 @@ use rustc_middle::mir::*; use rustc_middle::ty::{self, TyCtxt}; use smallvec::{smallvec, SmallVec}; -use std::convert::TryInto; use std::mem; use super::abs_domain::Lift; @@ -110,7 +109,7 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { 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 { + match place_ty.kind() { ty::Ref(..) | ty::RawPtr(..) => { let proj = &place.projection[..i + 1]; return Err(MoveError::cannot_move_out_of( @@ -480,13 +479,8 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { } }; let base_ty = base_place.ty(self.builder.body, self.builder.tcx).ty; - let len: u32 = match base_ty.kind { - ty::Array(_, size) => { - let length = size.eval_usize(self.builder.tcx, self.builder.param_env); - length - .try_into() - .expect("slice pattern of array with more than u32::MAX elements") - } + 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 { @@ -525,7 +519,9 @@ impl<'b, 'a, 'tcx> Gatherer<'b, 'a, 'tcx> { // of the union so it is marked as initialized again. if let [proj_base @ .., ProjectionElem::Field(_, _)] = place.projection { if let ty::Adt(def, _) = - Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx).ty.kind + Place::ty_from(place.local, proj_base, self.builder.body, self.builder.tcx) + .ty + .kind() { if def.is_union() { place = PlaceRef { local: place.local, projection: proj_base } diff --git a/src/librustc_mir/dataflow/move_paths/mod.rs b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs similarity index 99% rename from src/librustc_mir/dataflow/move_paths/mod.rs rename to compiler/rustc_mir/src/dataflow/move_paths/mod.rs index d66d2625d7..7c63025918 100644 --- a/src/librustc_mir/dataflow/move_paths/mod.rs +++ b/compiler/rustc_mir/src/dataflow/move_paths/mod.rs @@ -144,7 +144,6 @@ impl<'tcx> fmt::Display for MovePath<'tcx> { } } -#[allow(unused)] struct MovePathLinearIter<'a, 'tcx, F> { next: Option<(MovePathIndex, &'a MovePath<'tcx>)>, fetch_next: F, diff --git a/src/librustc_mir/interpret/cast.rs b/compiler/rustc_mir/src/interpret/cast.rs similarity index 97% rename from src/librustc_mir/interpret/cast.rs rename to compiler/rustc_mir/src/interpret/cast.rs index 501a5bcddb..0e16b0caef 100644 --- a/src/librustc_mir/interpret/cast.rs +++ b/compiler/rustc_mir/src/interpret/cast.rs @@ -47,7 +47,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::ReifyFnPointer) => { // The src operand does not matter, just its type - match src.layout.ty.kind { + 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)?; @@ -76,7 +76,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::UnsafeFnPointer) => { let src = self.read_immediate(src)?; - match cast_ty.kind { + match cast_ty.kind() { ty::FnPtr(_) => { // No change to value self.write_immediate(*src, dest)?; @@ -87,7 +87,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Pointer(PointerCast::ClosureFnPointer(_)) => { // The src operand does not matter, just its type - match src.layout.ty.kind { + 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)?; @@ -116,7 +116,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { use rustc_middle::ty::TyKind::*; trace!("Casting {:?}: {:?} to {:?}", *src, src.layout.ty, cast_ty); - match src.layout.ty.kind { + match src.layout.ty.kind() { // Floating point Float(FloatTy::F32) => { return Ok(self.cast_from_float(src.to_scalar()?.to_f32()?, cast_ty).into()); @@ -196,9 +196,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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 { + match *cast_ty.kind() { Int(_) | Uint(_) | RawPtr(_) => { - let size = match cast_ty.kind { + let size = match *cast_ty.kind() { Int(t) => Integer::from_attr(self, attr::IntType::SignedInt(t)).size(), Uint(t) => Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(), RawPtr(_) => self.pointer_size(), @@ -228,7 +228,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { F: Float + Into> + FloatConvert + FloatConvert, { use rustc_middle::ty::TyKind::*; - match dest_ty.kind { + match *dest_ty.kind() { // float -> uint Uint(t) => { let size = Integer::from_attr(self, attr::IntType::UnsignedInt(t)).size(); @@ -267,7 +267,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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) { + 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 @@ -303,7 +303,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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) { + 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) diff --git a/src/librustc_mir/interpret/eval_context.rs b/compiler/rustc_mir/src/interpret/eval_context.rs similarity index 95% rename from src/librustc_mir/interpret/eval_context.rs rename to compiler/rustc_mir/src/interpret/eval_context.rs index 525da87463..f97096984f 100644 --- a/src/librustc_mir/interpret/eval_context.rs +++ b/compiler/rustc_mir/src/interpret/eval_context.rs @@ -20,7 +20,7 @@ use rustc_span::{Pos, Span}; use rustc_target::abi::{Align, HasDataLayout, LayoutOf, Size, TargetDataLayout}; use super::{ - Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, OpTy, Operand, Place, PlaceTy, + Immediate, MPlaceTy, Machine, MemPlace, MemPlaceMeta, Memory, Operand, Place, PlaceTy, ScalarMaybeUninit, StackPopJump, }; use crate::transform::validate::equal_up_to_regions; @@ -482,13 +482,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { /// The `substs` are assumed to already be in our interpreter "universe" (param_env). pub(super) fn resolve( &self, - def_id: DefId, + def: ty::WithOptConstParam, substs: SubstsRef<'tcx>, ) -> InterpResult<'tcx, ty::Instance<'tcx>> { - trace!("resolve: {:?}, {:#?}", def_id, substs); + trace!("resolve: {:?}, {:#?}", def, substs); trace!("param_env: {:#?}", self.param_env); trace!("substs: {:#?}", substs); - match ty::Instance::resolve(*self.tcx, self.param_env, def_id, 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), @@ -534,7 +534,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { if !layout.is_unsized() { return Ok(Some((layout.size, layout.align.abi))); } - match layout.ty.kind { + 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, @@ -875,32 +875,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(()) } - pub(super) fn const_eval( - &self, - gid: GlobalId<'tcx>, - ty: Ty<'tcx>, - ) -> InterpResult<'tcx, OpTy<'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.const_eval_global_id(param_env, gid, Some(self.tcx.span))?; - - // Even though `ecx.const_eval` is called from `const_to_op` we can never have a - // recursion deeper than one level, because the `tcx.const_eval` above is guaranteed to not - // return `ConstValue::Unevaluated`, which is the only way that `const_to_op` will call - // `ecx.const_eval`. - let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; - self.const_to_op(&const_, None) - } - - pub fn const_eval_raw( + pub fn eval_to_allocation( &self, gid: GlobalId<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { @@ -914,14 +889,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } else { self.param_env }; - // We use `const_eval_raw` here, and get an unvalidated result. That is okay: - // Our result will later be validated anyway, and there seems no good reason - // to have to fail early here. This is also more consistent with - // `Memory::get_static_alloc` which has to use `const_eval_raw` to avoid cycles. - // FIXME: We can hit delay_span_bug if this is an invalid const, interning finds - // that problem, but we never run validation to show an error. Can we ensure - // this does not happen? - let val = self.tcx.const_eval_raw(param_env.and(gid))?; + let val = self.tcx.eval_to_allocation_raw(param_env.and(gid))?; self.raw_const_to_mplace(val) } diff --git a/src/librustc_mir/interpret/intern.rs b/compiler/rustc_mir/src/interpret/intern.rs similarity index 99% rename from src/librustc_mir/interpret/intern.rs rename to compiler/rustc_mir/src/interpret/intern.rs index 606be7cad2..dd5e9c9977 100644 --- a/src/librustc_mir/interpret/intern.rs +++ b/compiler/rustc_mir/src/interpret/intern.rs @@ -195,13 +195,13 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // 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 { + 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 + tcx.struct_tail_erasing_lifetimes(referenced_ty, self.ecx.param_env).kind() { // Validation will error (with a better message) on an invalid vtable pointer // so we can safely not do anything if this is not a real pointer. @@ -253,7 +253,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: CompileTimeMachine<'mir, 'tcx>> ValueVisitor<'mir // This helps to prevent users from accidentally exploiting UB that they // caused (by somehow getting a mutable reference in a `const`). if ref_mutability == Mutability::Mut { - match referenced_ty.kind { + match referenced_ty.kind() { ty::Array(_, n) if n.eval_usize(*tcx, self.ecx.param_env) == 0 => {} ty::Slice(_) if mplace.meta.unwrap_meta().to_machine_usize(self.ecx)? diff --git a/src/librustc_mir/interpret/intrinsics.rs b/compiler/rustc_mir/src/interpret/intrinsics.rs similarity index 90% rename from src/librustc_mir/interpret/intrinsics.rs rename to compiler/rustc_mir/src/interpret/intrinsics.rs index b37dcd42f4..d3b6d70633 100644 --- a/src/librustc_mir/interpret/intrinsics.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics.rs @@ -76,7 +76,7 @@ crate fn eval_nullary_intrinsic<'tcx>( ConstValue::from_u64(tcx.type_id_hash(tp_ty)) } sym::variant_count => { - if let ty::Adt(ref adt, _) = tp_ty.kind { + if let ty::Adt(ref adt, _) = tp_ty.kind() { ConstValue::from_machine_usize(adt.variants.len() as u64, &tcx) } else { ConstValue::from_machine_usize(0u64, &tcx) @@ -88,6 +88,8 @@ crate fn eval_nullary_intrinsic<'tcx>( 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>, @@ -150,7 +152,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { sym::type_name => self.tcx.mk_static_str(), _ => bug!("already checked for nullary intrinsics"), }; - let val = self.const_eval(gid, ty)?; + let val = + self.tcx.const_eval_global_id(self.param_env, gid, Some(self.tcx.span))?; + let const_ = ty::Const { val: ty::ConstKind::Value(val), ty }; + let val = self.const_to_op(&const_, None)?; self.copy_op(val, dest)?; } @@ -328,16 +333,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let offset_ptr = ptr.ptr_wrapping_signed_offset(offset_bytes, self); self.write_scalar(offset_ptr, dest)?; } - sym::ptr_guaranteed_eq | sym::ptr_guaranteed_ne => { - let a = self.read_immediate(args[0])?.to_scalar()?; - let b = self.read_immediate(args[1])?.to_scalar()?; - let cmp = if intrinsic_name == sym::ptr_guaranteed_eq { - self.guaranteed_eq(a, b) - } else { - self.guaranteed_ne(a, b) - }; - self.write_scalar(Scalar::from_bool(cmp), dest)?; - } sym::ptr_offset_from => { let a = self.read_immediate(args[0])?.to_scalar()?; let b = self.read_immediate(args[1])?.to_scalar()?; @@ -440,6 +435,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // 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`"); + } + } _ => return Ok(false), } @@ -448,37 +449,6 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { Ok(true) } - fn guaranteed_eq(&mut self, a: Scalar, b: Scalar) -> bool { - match (a, b) { - // Comparisons between integers are always known. - (Scalar::Raw { .. }, Scalar::Raw { .. }) => a == b, - // Equality with integers can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => 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. - (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::Raw { .. }, Scalar::Raw { .. }) => 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. - (Scalar::Raw { data: 0, .. }, Scalar::Ptr(ptr)) - | (Scalar::Ptr(ptr), Scalar::Raw { data: 0, .. }) => !self.memory.ptr_may_be_null(ptr), - // Inequality with integers other than null can never be known for sure. - (Scalar::Raw { .. }, Scalar::Ptr(_)) | (Scalar::Ptr(_), Scalar::Raw { .. }) => false, - // 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 static items, for these we can - // give reliable results. - (Scalar::Ptr(_), Scalar::Ptr(_)) => false, - } - } - pub fn exact_div( &mut self, a: ImmTy<'tcx, M::PointerTag>, diff --git a/src/librustc_mir/interpret/intrinsics/caller_location.rs b/compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs similarity index 100% rename from src/librustc_mir/interpret/intrinsics/caller_location.rs rename to compiler/rustc_mir/src/interpret/intrinsics/caller_location.rs diff --git a/src/librustc_mir/interpret/intrinsics/type_name.rs b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs similarity index 97% rename from src/librustc_mir/interpret/intrinsics/type_name.rs rename to compiler/rustc_mir/src/interpret/intrinsics/type_name.rs index 379117f3b8..554ada1ab2 100644 --- a/src/librustc_mir/interpret/intrinsics/type_name.rs +++ b/compiler/rustc_mir/src/interpret/intrinsics/type_name.rs @@ -32,7 +32,7 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { } fn print_type(mut self, ty: Ty<'tcx>) -> Result { - match ty.kind { + match *ty.kind() { // Types without identity. ty::Bool | ty::Char @@ -132,9 +132,8 @@ impl<'tcx> Printer<'tcx> for AbsolutePathPrinter<'tcx> { return Ok(self); } - self.path.push_str("::"); + write!(self.path, "::{}", disambiguated_data.data).unwrap(); - self.path.push_str(&disambiguated_data.data.as_symbol().as_str()); Ok(self) } diff --git a/src/librustc_mir/interpret/machine.rs b/compiler/rustc_mir/src/interpret/machine.rs similarity index 100% rename from src/librustc_mir/interpret/machine.rs rename to compiler/rustc_mir/src/interpret/machine.rs diff --git a/src/librustc_mir/interpret/memory.rs b/compiler/rustc_mir/src/interpret/memory.rs similarity index 98% rename from src/librustc_mir/interpret/memory.rs rename to compiler/rustc_mir/src/interpret/memory.rs index d4be2ce056..f3e373813c 100644 --- a/src/librustc_mir/interpret/memory.rs +++ b/compiler/rustc_mir/src/interpret/memory.rs @@ -285,9 +285,11 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { None => { // Deallocating global memory -- always an error return Err(match self.tcx.get_global_alloc(ptr.alloc_id) { - Some(GlobalAlloc::Function(..)) => err_ub_format!("deallocating a function"), + Some(GlobalAlloc::Function(..)) => { + err_ub_format!("deallocating {}, which is a function", ptr.alloc_id) + } Some(GlobalAlloc::Static(..) | GlobalAlloc::Memory(..)) => { - err_ub_format!("deallocating static memory") + err_ub_format!("deallocating {}, which is static memory", ptr.alloc_id) } None => err_ub!(PointerUseAfterFree(ptr.alloc_id)), } @@ -297,7 +299,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if alloc_kind != kind { throw_ub_format!( - "deallocating {} memory using {} deallocation operation", + "deallocating {}, which is {} memory, using {} deallocation operation", + ptr.alloc_id, alloc_kind, kind ); @@ -305,7 +308,8 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { if let Some((size, align)) = old_size_and_align { if size != alloc.size || align != alloc.align { throw_ub_format!( - "incorrect layout on deallocation: allocation has size {} and alignment {}, but gave size {} and alignment {}", + "incorrect layout on deallocation: {} has size {} and alignment {}, but gave size {} and alignment {}", + ptr.alloc_id, alloc.size.bytes(), alloc.align.bytes(), size.bytes(), @@ -469,7 +473,7 @@ impl<'mir, 'tcx, M: Machine<'mir, 'tcx>> Memory<'mir, 'tcx, M> { // 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 - // `const_eval_raw` and it is the "resolved" ID. + // `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! diff --git a/src/librustc_mir/interpret/mod.rs b/compiler/rustc_mir/src/interpret/mod.rs similarity index 100% rename from src/librustc_mir/interpret/mod.rs rename to compiler/rustc_mir/src/interpret/mod.rs diff --git a/src/librustc_mir/interpret/operand.rs b/compiler/rustc_mir/src/interpret/operand.rs similarity index 97% rename from src/librustc_mir/interpret/operand.rs rename to compiler/rustc_mir/src/interpret/operand.rs index 0b58caef54..735f890a33 100644 --- a/src/librustc_mir/interpret/operand.rs +++ b/compiler/rustc_mir/src/interpret/operand.rs @@ -549,21 +549,13 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { }; // Early-return cases. let val_val = match val.val { - ty::ConstKind::Param(_) => throw_inval!(TooGeneric), + ty::ConstKind::Param(_) | ty::ConstKind::Bound(..) => throw_inval!(TooGeneric), ty::ConstKind::Error(_) => throw_inval!(TypeckError(ErrorReported)), ty::ConstKind::Unevaluated(def, substs, promoted) => { - let instance = self.resolve(def.did, substs)?; - // We use `const_eval` here and `const_eval_raw` elsewhere in mir interpretation. - // The reason we use `const_eval_raw` everywhere else is to prevent cycles during - // validation, because validation automatically reads through any references, thus - // potentially requiring the current static to be evaluated again. This is not a - // problem here, because we are building an operand which means an actual read is - // happening. - return Ok(self.const_eval(GlobalId { instance, promoted }, val.ty)?); + let instance = self.resolve(def, substs)?; + return Ok(self.eval_to_allocation(GlobalId { instance, promoted })?.into()); } - ty::ConstKind::Infer(..) - | ty::ConstKind::Bound(..) - | ty::ConstKind::Placeholder(..) => { + ty::ConstKind::Infer(..) | ty::ConstKind::Placeholder(..) => { span_bug!(self.cur_span(), "const_to_op: Unexpected ConstKind {:?}", val) } ty::ConstKind::Value(val_val) => val_val, @@ -662,7 +654,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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 { + let index = match *op.layout.ty.kind() { ty::Adt(adt, _) => { adt.discriminants(*self.tcx).find(|(_, var)| var.val == discr_bits) } diff --git a/src/librustc_mir/interpret/operator.rs b/compiler/rustc_mir/src/interpret/operator.rs similarity index 99% rename from src/librustc_mir/interpret/operator.rs rename to compiler/rustc_mir/src/interpret/operator.rs index 30c40b8fde..fc266fa74b 100644 --- a/src/librustc_mir/interpret/operator.rs +++ b/compiler/rustc_mir/src/interpret/operator.rs @@ -282,7 +282,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { right.layout.ty ); - match left.layout.ty.kind { + match left.layout.ty.kind() { ty::Char => { assert_eq!(left.layout.ty, right.layout.ty); let left = left.to_scalar()?; @@ -368,7 +368,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let val = val.to_scalar()?; trace!("Running unary op {:?}: {:?} ({:?})", un_op, val, layout.ty); - match layout.ty.kind { + match layout.ty.kind() { ty::Bool => { let val = val.to_bool()?; let res = match un_op { diff --git a/src/librustc_mir/interpret/place.rs b/compiler/rustc_mir/src/interpret/place.rs similarity index 98% rename from src/librustc_mir/interpret/place.rs rename to compiler/rustc_mir/src/interpret/place.rs index 20fd8e4336..72551b2337 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/compiler/rustc_mir/src/interpret/place.rs @@ -13,9 +13,9 @@ use rustc_target::abi::{Abi, Align, FieldsShape, TagEncoding}; use rustc_target::abi::{HasDataLayout, LayoutOf, Size, VariantIdx, Variants}; use super::{ - mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ImmTy, - Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, Pointer, - PointerArithmetic, RawConst, Scalar, ScalarMaybeUninit, + mir_assign_valid_types, truncate, AllocId, AllocMap, Allocation, AllocationExtra, ConstAlloc, + ImmTy, Immediate, InterpCx, InterpResult, LocalValue, Machine, MemoryKind, OpTy, Operand, + Pointer, PointerArithmetic, Scalar, ScalarMaybeUninit, }; #[derive(Copy, Clone, Debug, Hash, PartialEq, Eq, HashStable)] @@ -202,7 +202,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { 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 { + 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), } @@ -218,7 +218,7 @@ impl<'tcx, Tag> MPlaceTy<'tcx, Tag> { #[inline] pub(super) fn vtable(self) -> Scalar { - match self.layout.ty.kind { + match self.layout.ty.kind() { ty::Dynamic(..) => self.mplace.meta.unwrap_meta(), _ => bug!("vtable not supported on type {:?}", self.layout.ty), } @@ -498,7 +498,7 @@ where // Compute meta and new layout let inner_len = actual_to.checked_sub(from).unwrap(); - let (meta, ty) = match base.layout.ty.kind { + 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)), @@ -549,25 +549,23 @@ where ConstantIndex { offset, min_length, from_end } => { let n = base.len(self)?; - if n < u64::from(min_length) { + if n < min_length { // This can only be reached in ConstProp and non-rustc-MIR. - throw_ub!(BoundsCheckFailed { len: min_length.into(), index: n }); + throw_ub!(BoundsCheckFailed { len: min_length, index: n }); } let index = if from_end { assert!(0 < offset && offset <= min_length); - n.checked_sub(u64::from(offset)).unwrap() + n.checked_sub(offset).unwrap() } else { assert!(offset < min_length); - u64::from(offset) + offset }; self.mplace_index(base, index)? } - Subslice { from, to, from_end } => { - self.mplace_subslice(base, u64::from(from), u64::from(to), from_end)? - } + Subslice { from, to, from_end } => self.mplace_subslice(base, from, to, from_end)?, }) } @@ -1122,7 +1120,7 @@ where pub fn raw_const_to_mplace( &self, - raw: RawConst<'tcx>, + raw: ConstAlloc<'tcx>, ) -> InterpResult<'tcx, MPlaceTy<'tcx, M::PointerTag>> { // This must be an allocation in `tcx` let _ = self.tcx.global_alloc(raw.alloc_id); diff --git a/src/librustc_mir/interpret/step.rs b/compiler/rustc_mir/src/interpret/step.rs similarity index 100% rename from src/librustc_mir/interpret/step.rs rename to compiler/rustc_mir/src/interpret/step.rs diff --git a/src/librustc_mir/interpret/terminator.rs b/compiler/rustc_mir/src/interpret/terminator.rs similarity index 96% rename from src/librustc_mir/interpret/terminator.rs rename to compiler/rustc_mir/src/interpret/terminator.rs index 9a036a0f29..9f200ca62b 100644 --- a/src/librustc_mir/interpret/terminator.rs +++ b/compiler/rustc_mir/src/interpret/terminator.rs @@ -55,7 +55,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { let old_stack = self.frame_idx(); let old_loc = self.frame().loc; let func = self.eval_operand(func, None)?; - let (fn_val, abi) = match func.layout.ty.kind { + let (fn_val, abi) = match *func.layout.ty.kind() { ty::FnPtr(sig) => { let caller_abi = sig.abi(); let fn_ptr = self.read_scalar(func)?.check_init()?; @@ -64,7 +64,12 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { } ty::FnDef(def_id, substs) => { let sig = func.layout.ty.fn_sig(*self.tcx); - (FnVal::Instance(self.resolve(def_id, substs)?), sig.abi()) + ( + FnVal::Instance( + self.resolve(ty::WithOptConstParam::unknown(def_id), substs)?, + ), + sig.abi(), + ) } _ => span_bug!( terminator.source_info.span, @@ -222,7 +227,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { { let callee_abi = { let instance_ty = instance.ty(*self.tcx, self.param_env); - match instance_ty.kind { + match instance_ty.kind() { ty::FnDef(..) => instance_ty.fn_sig(*self.tcx).abi(), ty::Closure(..) => Abi::RustCall, ty::Generator(..) => Abi::Rust, @@ -385,9 +390,9 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { 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 + // support built-in pointers `(&, &mut, Box)` as well as unsized-self. We do // not yet support custom self types. - // Also see librustc_codegen_llvm/abi.rs and librustc_codegen_llvm/mir/block.rs. + // 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. @@ -431,7 +436,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { // implementation fail -- a problem shared by rustc. let place = self.force_allocation(place)?; - let (instance, place) = match place.layout.ty.kind { + let (instance, place) = match place.layout.ty.kind() { ty::Dynamic(..) => { // Dropping a trait object. self.unpack_dyn_trait(place)? diff --git a/src/librustc_mir/interpret/traits.rs b/compiler/rustc_mir/src/interpret/traits.rs similarity index 100% rename from src/librustc_mir/interpret/traits.rs rename to compiler/rustc_mir/src/interpret/traits.rs diff --git a/src/librustc_mir/interpret/util.rs b/compiler/rustc_mir/src/interpret/util.rs similarity index 96% rename from src/librustc_mir/interpret/util.rs rename to compiler/rustc_mir/src/interpret/util.rs index 57c5fc59cc..fc5a25ffbf 100644 --- a/src/librustc_mir/interpret/util.rs +++ b/compiler/rustc_mir/src/interpret/util.rs @@ -33,7 +33,7 @@ where return false; } - match ty.kind { + match *ty.kind() { ty::Param(_) => true, ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) @@ -59,7 +59,7 @@ where // `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(_))) + assert!(matches!(ty.kind(), ty::Param(_))) } ty::subst::GenericArgKind::Const(ct) => { assert!(matches!(ct.val, ty::ConstKind::Param(_))) diff --git a/src/librustc_mir/interpret/validity.rs b/compiler/rustc_mir/src/interpret/validity.rs similarity index 94% rename from src/librustc_mir/interpret/validity.rs rename to compiler/rustc_mir/src/interpret/validity.rs index 9cd2034013..2b83e1c813 100644 --- a/src/librustc_mir/interpret/validity.rs +++ b/compiler/rustc_mir/src/interpret/validity.rs @@ -26,18 +26,22 @@ use super::{ 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(); - let where_ = &$where; - if !where_.is_empty() { - msg.push_str(" at "); - write_path(&mut msg, where_); - } - $( - msg.push_str(", but expected "); - write!(&mut msg, $($expected_fmt),+).unwrap(); - )? + let msg = rustc_middle::ty::print::with_no_trimmed_paths(|| { + let mut msg = String::new(); + msg.push_str("encountered "); + write!(&mut msg, $($what_fmt),+).unwrap(); + let where_ = &$where; + if !where_.is_empty() { + msg.push_str(" at "); + write_path(&mut msg, where_); + } + $( + msg.push_str(", but expected "); + write!(&mut msg, $($expected_fmt),+).unwrap(); + )? + + msg + }); throw_ub!(ValidationFailure(msg)) }}; } @@ -210,7 +214,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' match layout.variants { Variants::Multiple { tag_field, .. } => { if tag_field == field { - return match layout.ty.kind { + return match layout.ty.kind() { ty::Adt(def, ..) if def.is_enum() => PathElem::EnumTag, ty::Generator(..) => PathElem::GeneratorTag, _ => bug!("non-variant type {:?}", layout.ty), @@ -221,7 +225,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' } // Now we know we are projecting to a field, so figure out which one. - match layout.ty.kind { + match layout.ty.kind() { // generators and closures. ty::Closure(def_id, _) | ty::Generator(def_id, _, _) => { let mut name = None; @@ -299,7 +303,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' pointee: TyAndLayout<'tcx>, ) -> InterpResult<'tcx> { let tail = self.ecx.tcx.struct_tail_erasing_lifetimes(pointee.ty, self.ecx.param_env); - match tail.kind { + match tail.kind() { ty::Dynamic(..) => { let vtable = meta.unwrap_meta(); // Direct call to `check_ptr_access_align` checks alignment even on CTFE machines. @@ -421,26 +425,28 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' let alloc_kind = self.ecx.tcx.get_global_alloc(ptr.alloc_id); if let Some(GlobalAlloc::Static(did)) = alloc_kind { assert!(!self.ecx.tcx.is_thread_local_static(did)); - // 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`). - // We also need to do it here instead of going on to avoid running - // into the `before_access_global` check during validation. - if !self.may_ref_to_static && self.ecx.tcx.is_static(did) { + assert!(self.ecx.tcx.is_static(did)); + if self.may_ref_to_static { + // 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(()); + } else { + // 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 } ); } - // `extern static` cannot be validated as they have no body. - // FIXME: Statics from other crates are also skipped. - // They might be checked at a different type, but for now we - // want to avoid recursing too deeply. We might miss const-invalid data, - // but things are still sound otherwise (in particular re: consts - // referring to statics). - if !did.is_local() || self.ecx.tcx.is_foreign_item(did) { - return Ok(()); - } } } // Proceed recursively even for ZST, no reason to skip them! @@ -473,7 +479,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValidityVisitor<'rt, 'mir, ' ) -> InterpResult<'tcx, bool> { // Go over all the primitive types let ty = value.layout.ty; - match ty.kind { + match ty.kind() { ty::Bool => { let value = self.ecx.read_scalar(value)?; try_validation!( @@ -688,7 +694,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> variant_id: VariantIdx, new_op: OpTy<'tcx, M::PointerTag>, ) -> InterpResult<'tcx> { - let name = match old_op.layout.ty.kind { + 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), @@ -758,7 +764,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> op: OpTy<'tcx, M::PointerTag>, fields: impl Iterator>, ) -> InterpResult<'tcx> { - match op.layout.ty.kind { + match op.layout.ty.kind() { ty::Str => { let mplace = op.assert_mem_place(self.ecx); // strings are never immediate let len = mplace.len(self.ecx)?; @@ -775,7 +781,7 @@ impl<'rt, 'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> ValueVisitor<'mir, 'tcx, M> // 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. - match tys.kind { + match tys.kind() { ty::Int(..) | ty::Uint(..) | ty::Float(..) => true, _ => false, } diff --git a/src/librustc_mir/interpret/visitor.rs b/compiler/rustc_mir/src/interpret/visitor.rs similarity index 99% rename from src/librustc_mir/interpret/visitor.rs rename to compiler/rustc_mir/src/interpret/visitor.rs index 6c53df40a7..097b9ae6ca 100644 --- a/src/librustc_mir/interpret/visitor.rs +++ b/compiler/rustc_mir/src/interpret/visitor.rs @@ -203,7 +203,7 @@ macro_rules! make_value_visitor { trace!("walk_value: type: {}", v.layout().ty); // Special treatment for special types, where the (static) layout is not sufficient. - match v.layout().ty.kind { + 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 diff --git a/src/librustc_mir/lib.rs b/compiler/rustc_mir/src/lib.rs similarity index 75% rename from src/librustc_mir/lib.rs rename to compiler/rustc_mir/src/lib.rs index 2e3b508463..c00c686090 100644 --- a/src/librustc_mir/lib.rs +++ b/compiler/rustc_mir/src/lib.rs @@ -6,6 +6,8 @@ Rust MIR: a lowered representation of Rust. #![feature(nll)] #![feature(in_band_lifetimes)] +#![feature(array_windows)] +#![feature(bindings_after_at)] #![feature(bool_to_option)] #![feature(box_patterns)] #![feature(box_syntax)] @@ -13,19 +15,18 @@ Rust MIR: a lowered representation of Rust. #![feature(const_panic)] #![feature(crate_visibility_modifier)] #![feature(decl_macro)] -#![feature(drain_filter)] +#![feature(exact_size_is_empty)] #![feature(exhaustive_patterns)] -#![feature(iter_order_by)] #![feature(never_type)] #![feature(min_specialization)] #![feature(trusted_len)] #![feature(try_blocks)] -#![feature(associated_type_bounds)] #![feature(associated_type_defaults)] #![feature(stmt_expr_attributes)] #![feature(trait_alias)] #![feature(option_expect_none)] #![feature(or_patterns)] +#![feature(once_cell)] #![recursion_limit = "256"] #[macro_use] @@ -51,11 +52,15 @@ pub fn provide(providers: &mut Providers) { transform::provide(providers); monomorphize::partitioning::provide(providers); monomorphize::polymorphize::provide(providers); - providers.const_eval_validated = const_eval::const_eval_validated_provider; - providers.const_eval_raw = const_eval::const_eval_raw_provider; + 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.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 --git a/src/librustc_mir/monomorphize/collector.rs b/compiler/rustc_mir/src/monomorphize/collector.rs similarity index 94% rename from src/librustc_mir/monomorphize/collector.rs rename to compiler/rustc_mir/src/monomorphize/collector.rs index 1afa720f69..7e12cc9176 100644 --- a/src/librustc_mir/monomorphize/collector.rs +++ b/compiler/rustc_mir/src/monomorphize/collector.rs @@ -191,13 +191,13 @@ 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::obsolete::DefPathBasedNames; use rustc_middle::ty::subst::{GenericArgKind, InternalSubsts}; use rustc_middle::ty::{self, GenericParamDefKind, Instance, Ty, TyCtxt, TypeFoldable}; use rustc_session::config::EntryFnType; use rustc_span::source_map::{dummy_spanned, respan, Span, Spanned, DUMMY_SP}; use smallvec::SmallVec; use std::iter; +use std::path::PathBuf; #[derive(PartialEq)] pub enum MonoItemCollectionMode { @@ -348,7 +348,7 @@ fn collect_items_rec<'tcx>( // We've been here already, no need to search again. return; } - debug!("BEGIN collect_items_rec({})", starting_point.node.to_string(tcx, true)); + debug!("BEGIN collect_items_rec({})", starting_point.node); let mut neighbors = Vec::new(); let recursion_depth_reset; @@ -365,8 +365,10 @@ fn collect_items_rec<'tcx>( recursion_depth_reset = None; - if let Ok(val) = tcx.const_eval_poly(def_id) { - collect_const_value(tcx, val, &mut neighbors); + 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) => { @@ -397,7 +399,7 @@ fn collect_items_rec<'tcx>( recursion_depths.insert(def_id, depth); } - debug!("END collect_items_rec({})", starting_point.node.to_string(tcx, true)); + debug!("END collect_items_rec({})", starting_point.node); } fn record_accesses<'a, 'tcx: 'a>( @@ -419,27 +421,38 @@ fn record_accesses<'a, 'tcx: 'a>( inlining_map.lock_mut().record_accesses(caller, &accesses); } -// Shrinks string by keeping prefix and suffix of given sizes. -fn shrink(s: String, before: usize, after: usize) -> String { - // 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)..], - ); +/// 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 shrunk.len() < s.len() { shrunk } else { s } -} + 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())); -// 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. -fn shrunk_instance_name(instance: &Instance<'tcx>) -> String { - shrink(instance.to_string(), 32, 32) + 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(LOCAL_CRATE).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>( @@ -464,15 +477,16 @@ fn check_recursion_limit<'tcx>( // more than the recursion limit is assumed to be causing an // infinite expansion. if !tcx.sess.recursion_limit().value_within_limit(adjusted_recursion_depth) { - let error = format!( - "reached the recursion limit while instantiating `{}`", - shrunk_instance_name(&instance), - ); + 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(); } @@ -501,12 +515,13 @@ fn check_type_length_limit<'tcx>(tcx: TyCtxt<'tcx>, instance: Instance<'tcx>) { // // Bail out in these cases to avoid that bad user experience. if !tcx.sess.type_length_limit().value_within_limit(type_length) { - let msg = format!( - "reached the type-length limit while instantiating `{}`", - shrunk_instance_name(&instance), - ); + 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); - diag.note(&format!( + 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 )); @@ -585,7 +600,7 @@ impl<'a, 'tcx> MirVisitor<'tcx> for MirNeighborCollector<'a, 'tcx> { ) => { let source_ty = operand.ty(self.body, self.tcx); let source_ty = self.monomorphize(source_ty); - match source_ty.kind { + match *source_ty.kind() { ty::Closure(def_id, substs) => { let instance = Instance::resolve_closure( self.tcx, @@ -726,7 +741,7 @@ fn visit_fn_use<'tcx>( source: Span, output: &mut Vec>>, ) { - if let ty::FnDef(def_id, substs) = ty.kind { + 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 { @@ -863,7 +878,7 @@ fn find_vtable_types_for_unsizing<'tcx>( return false; } let tail = tcx.struct_tail_erasing_lifetimes(ty, param_env); - match tail.kind { + match tail.kind() { ty::Foreign(..) => false, ty::Str | ty::Slice(..) | ty::Dynamic(..) => true, _ => bug!("unexpected unsized tail: {:?}", tail), @@ -876,7 +891,7 @@ fn find_vtable_types_for_unsizing<'tcx>( } }; - match (&source_ty.kind, &target_ty.kind) { + 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) @@ -932,7 +947,7 @@ fn create_mono_items_for_vtable_methods<'tcx>( ) { 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 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()); @@ -1001,7 +1016,7 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { let def_id = self.tcx.hir().local_def_id(item.hir_id); debug!( "RootCollector: ADT drop-glue for {}", - def_id_to_string(self.tcx, def_id) + self.tcx.def_path_str(def_id.to_def_id()) ); let ty = Instance::new(def_id.to_def_id(), InternalSubsts::empty()) @@ -1013,14 +1028,14 @@ impl ItemLikeVisitor<'v> for RootCollector<'_, 'v> { hir::ItemKind::GlobalAsm(..) => { debug!( "RootCollector: ItemKind::GlobalAsm({})", - def_id_to_string(self.tcx, self.tcx.hir().local_def_id(item.hir_id)) + self.tcx.def_path_str(self.tcx.hir().local_def_id(item.hir_id).to_def_id()) ); self.output.push(dummy_spanned(MonoItem::GlobalAsm(item.hir_id))); } hir::ItemKind::Static(..) => { - let def_id = self.tcx.hir().local_def_id(item.hir_id); - debug!("RootCollector: ItemKind::Static({})", def_id_to_string(self.tcx, def_id)); - self.output.push(dummy_spanned(MonoItem::Static(def_id.to_def_id()))); + let def_id = self.tcx.hir().local_def_id(item.hir_id).to_def_id(); + debug!("RootCollector: ItemKind::Static({})", self.tcx.def_path_str(def_id)); + self.output.push(dummy_spanned(MonoItem::Static(def_id))); } hir::ItemKind::Const(..) => { // const items only generate mono items if they are @@ -1143,7 +1158,7 @@ fn create_mono_items_for_default_impls<'tcx>( debug!( "create_mono_items_for_default_impls(item={})", - def_id_to_string(tcx, impl_def_id) + tcx.def_path_str(impl_def_id.to_def_id()) ); if let Some(trait_ref) = tcx.impl_trait_ref(impl_def_id) { @@ -1227,13 +1242,6 @@ fn collect_neighbours<'tcx>( MirNeighborCollector { tcx, body: &body, output, instance }.visit_body(&body); } -fn def_id_to_string(tcx: TyCtxt<'_>, def_id: LocalDefId) -> String { - let mut output = String::new(); - let printer = DefPathBasedNames::new(tcx, false, false); - printer.push_def_path(def_id.to_def_id(), &mut output); - output -} - fn collect_const_value<'tcx>( tcx: TyCtxt<'tcx>, value: ConstValue<'tcx>, diff --git a/src/librustc_mir/monomorphize/mod.rs b/compiler/rustc_mir/src/monomorphize/mod.rs similarity index 91% rename from src/librustc_mir/monomorphize/mod.rs rename to compiler/rustc_mir/src/monomorphize/mod.rs index edafa00a03..d2586f0f84 100644 --- a/src/librustc_mir/monomorphize/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/mod.rs @@ -21,7 +21,7 @@ pub fn custom_coerce_unsize_info<'tcx>( }); match tcx.codegen_fulfill_obligation((ty::ParamEnv::reveal_all(), trait_ref)) { - Ok(traits::ImplSourceUserDefined(traits::ImplSourceUserDefinedData { + Ok(traits::ImplSource::UserDefined(traits::ImplSourceUserDefinedData { impl_def_id, .. })) => tcx.coerce_unsized_info(impl_def_id).custom_kind.unwrap(), diff --git a/src/librustc_mir/monomorphize/partitioning/default.rs b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs similarity index 95% rename from src/librustc_mir/monomorphize/partitioning/default.rs rename to compiler/rustc_mir/src/monomorphize/partitioning/default.rs index b48bae8378..3c89111a65 100644 --- a/src/librustc_mir/monomorphize/partitioning/default.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/default.rs @@ -3,6 +3,7 @@ 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}; @@ -11,6 +12,7 @@ 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::{ @@ -22,35 +24,36 @@ pub struct DefaultPartitioning; impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn place_root_mono_items( &mut self, - tcx: TyCtxt<'tcx>, + 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 = tcx.sess.opts.incremental.is_some(); + 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 = tcx.sess.opts.share_generics() && tcx.local_crate_exports_generics(); + let export_generics = + cx.tcx.sess.opts.share_generics() && cx.tcx.local_crate_exports_generics(); - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + 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(tcx) { + match mono_item.instantiation_mode(cx.tcx) { InstantiationMode::GloballyShared { .. } => {} InstantiationMode::LocalCopy => continue, } - let characteristic_def_id = characteristic_def_id_of_mono_item(tcx, mono_item); + 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( - tcx, + cx.tcx, cgu_name_builder, def_id, is_volatile, @@ -65,7 +68,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { let mut can_be_internalized = true; let (linkage, visibility) = mono_item_linkage_and_visibility( - tcx, + cx.tcx, &mono_item, &mut can_be_internalized, export_generics, @@ -97,17 +100,16 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - merging::merge_codegen_units(tcx, initial_partitioning, target_cgu_count); + merging::merge_codegen_units(cx, initial_partitioning); } fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx> { let mut new_partitioning = Vec::new(); let mut mono_item_placements = FxHashMap::default(); @@ -124,7 +126,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // 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, inlining_map, &mut reachable); + follow_inlining(*root, cx.inlining_map, &mut reachable); } let mut new_codegen_unit = CodegenUnit::new(old_codegen_unit.name()); @@ -198,9 +200,8 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { fn internalize_symbols( &mut self, - _tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) { if partitioning.codegen_units.len() == 1 { // Fast path for when there is only one codegen unit. In this case we @@ -218,7 +219,7 @@ impl<'tcx> Partitioner<'tcx> for DefaultPartitioning { // Build a map from every monomorphization to all the monomorphizations that // reference it. let mut accessor_map: FxHashMap, Vec>> = Default::default(); - inlining_map.iter_accesses(|accessor, accessees| { + cx.inlining_map.iter_accesses(|accessor, accessees| { for accessee in accessees { accessor_map.entry(*accessee).or_default().push(accessor); } @@ -354,7 +355,10 @@ fn compute_codegen_unit_name( *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| part.data.as_symbol()); + 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"); diff --git a/src/librustc_mir/monomorphize/partitioning/merging.rs b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs similarity index 90% rename from src/librustc_mir/monomorphize/partitioning/merging.rs rename to compiler/rustc_mir/src/monomorphize/partitioning/merging.rs index 1787e6df1b..5107e69726 100644 --- a/src/librustc_mir/monomorphize/partitioning/merging.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/merging.rs @@ -3,17 +3,16 @@ 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_middle::ty::TyCtxt; use rustc_span::symbol::{Symbol, SymbolStr}; +use super::PartitioningCx; use crate::monomorphize::partitioning::PreInliningPartitioning; pub fn merge_codegen_units<'tcx>( - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ) { - assert!(target_cgu_count >= 1); + 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 @@ -32,7 +31,7 @@ pub fn merge_codegen_units<'tcx>( 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() > target_cgu_count { + 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(); @@ -56,9 +55,9 @@ pub fn merge_codegen_units<'tcx>( ); } - let cgu_name_builder = &mut CodegenUnitNameBuilder::new(tcx); + let cgu_name_builder = &mut CodegenUnitNameBuilder::new(cx.tcx); - if tcx.sess.opts.incremental.is_some() { + 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 @@ -74,7 +73,9 @@ pub fn merge_codegen_units<'tcx>( // Sort the names, so things are deterministic and easy to // predict. - cgu_contents.sort(); + + // We are sorting primitive &strs here so we can use unstable sort + cgu_contents.sort_unstable(); (current_cgu_name, cgu_contents.join("--")) }) @@ -82,7 +83,7 @@ pub fn merge_codegen_units<'tcx>( for cgu in codegen_units.iter_mut() { if let Some(new_cgu_name) = new_cgu_names.get(&cgu.name()) { - if tcx.sess.opts.debugging_opts.human_readable_cgu_names { + 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 diff --git a/src/librustc_mir/monomorphize/partitioning/mod.rs b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs similarity index 93% rename from src/librustc_mir/monomorphize/partitioning/mod.rs rename to compiler/rustc_mir/src/monomorphize/partitioning/mod.rs index 9dfbd65e1b..db6d3b2d91 100644 --- a/src/librustc_mir/monomorphize/partitioning/mod.rs +++ b/compiler/rustc_mir/src/monomorphize/partitioning/mod.rs @@ -100,6 +100,7 @@ use rustc_data_structures::sync; use rustc_hir::def_id::{CrateNum, DefIdSet, LOCAL_CRATE}; 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; @@ -107,31 +108,35 @@ 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, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, mono_items: &mut dyn Iterator>, ) -> PreInliningPartitioning<'tcx>; fn merge_codegen_units( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: &mut PreInliningPartitioning<'tcx>, - target_cgu_count: usize, ); fn place_inlined_mono_items( &mut self, + cx: &PartitioningCx<'_, 'tcx>, initial_partitioning: PreInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ) -> PostInliningPartitioning<'tcx>; fn internalize_symbols( &mut self, - tcx: TyCtxt<'tcx>, + cx: &PartitioningCx<'_, 'tcx>, partitioning: &mut PostInliningPartitioning<'tcx>, - inlining_map: &InliningMap<'tcx>, ); } @@ -156,12 +161,13 @@ pub fn partition<'tcx>( 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(tcx, mono_items) + partitioner.place_root_mono_items(cx, mono_items) }; initial_partitioning.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -171,7 +177,7 @@ pub fn partition<'tcx>( // 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(tcx, &mut initial_partitioning, max_cgu_count); + partitioner.merge_codegen_units(cx, &mut initial_partitioning); debug_dump(tcx, "POST MERGING:", initial_partitioning.codegen_units.iter()); } @@ -181,7 +187,7 @@ pub fn partition<'tcx>( // 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(initial_partitioning, inlining_map) + partitioner.place_inlined_mono_items(cx, initial_partitioning) }; post_inlining.codegen_units.iter_mut().for_each(|cgu| cgu.estimate_size(tcx)); @@ -190,9 +196,9 @@ pub fn partition<'tcx>( // Next we try to make as many symbols "internal" as possible, so LLVM has // more freedom to optimize. - if tcx.sess.opts.cg.link_dead_code != Some(true) { + if !tcx.sess.link_dead_code() { let _prof_timer = tcx.prof.generic_activity("cgu_partitioning_internalize_symbols"); - partitioner.internalize_symbols(tcx, &mut post_inlining, inlining_map); + partitioner.internalize_symbols(cx, &mut post_inlining); } // Finally, sort by codegen unit name, so that we get deterministic results. @@ -246,7 +252,7 @@ where debug!( " - {} [{:?}] [{}] estimated size {}", - mono_item.to_string(tcx, true), + mono_item, linkage, symbol_hash, mono_item.size_estimate(tcx) @@ -271,14 +277,8 @@ where symbols.sort_by_key(|sym| sym.1); - for pair in symbols.windows(2) { - let sym1 = &pair[0].1; - let sym2 = &pair[1].1; - + for &[(mono_item1, ref sym1), (mono_item2, ref sym2)] in symbols.array_windows() { if sym1 == sym2 { - let mono_item1 = pair[0].0; - let mono_item2 = pair[1].0; - let span1 = mono_item1.local_span(tcx); let span2 = mono_item2.local_span(tcx); @@ -327,7 +327,7 @@ fn collect_and_partition_mono_items<'tcx>( } } None => { - if tcx.sess.opts.cg.link_dead_code == Some(true) { + if tcx.sess.link_dead_code() { MonoItemCollectionMode::Eager } else { MonoItemCollectionMode::Lazy @@ -374,14 +374,14 @@ fn collect_and_partition_mono_items<'tcx>( let mut item_keys: Vec<_> = items .iter() .map(|i| { - let mut output = i.to_string(tcx, false); + 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_str(" "); + output.push(' '); output.push_str(&cgu_name.as_str()); let linkage_abbrev = match linkage { @@ -398,9 +398,9 @@ fn collect_and_partition_mono_items<'tcx>( Linkage::Common => "Common", }; - output.push_str("["); + output.push('['); output.push_str(linkage_abbrev); - output.push_str("]"); + output.push(']'); } output }) diff --git a/src/librustc_mir/monomorphize/polymorphize.rs b/compiler/rustc_mir/src/monomorphize/polymorphize.rs similarity index 99% rename from src/librustc_mir/monomorphize/polymorphize.rs rename to compiler/rustc_mir/src/monomorphize/polymorphize.rs index 69f3288ee3..3f6f117acd 100644 --- a/src/librustc_mir/monomorphize/polymorphize.rs +++ b/compiler/rustc_mir/src/monomorphize/polymorphize.rs @@ -288,7 +288,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { return false; } - match ty.kind { + match *ty.kind() { ty::Closure(def_id, substs) | ty::Generator(def_id, substs, ..) => { debug!("visit_ty: def_id={:?}", def_id); // Avoid cycle errors with generators. @@ -337,7 +337,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for HasUsedGenericParams<'a> { return false; } - match ty.kind { + match ty.kind() { ty::Param(param) => !self.unused_parameters.contains(param.index).unwrap_or(false), _ => ty.super_visit_with(self), } diff --git a/src/librustc_mir/shim.rs b/compiler/rustc_mir/src/shim.rs similarity index 94% rename from src/librustc_mir/shim.rs rename to compiler/rustc_mir/src/shim.rs index 08ed0d3770..7e4d189f0b 100644 --- a/src/librustc_mir/shim.rs +++ b/compiler/rustc_mir/src/shim.rs @@ -33,7 +33,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' 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), None) + 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(); @@ -42,16 +42,8 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' Some(ty::ClosureKind::FnMut | ty::ClosureKind::Fn) => Adjustment::Deref, None => bug!("fn pointer {:?} is not an fn", ty), }; - // HACK: we need the "real" argument types for the MIR, - // but because our substs are (Self, Args), where Args - // is a tuple, we must include the *concrete* argument - // types in the MIR. They will be substituted again with - // the param-substs, but because they are concrete, this - // will not do any harm. - let sig = tcx.erase_late_bound_regions(&ty.fn_sig(tcx)); - let arg_tys = sig.inputs(); - build_call_shim(tcx, instance, Some(adjustment), CallKind::Indirect(ty), Some(arg_tys)) + 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 @@ -59,7 +51,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' // 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), None) + 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); @@ -70,13 +62,7 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<' .unwrap() .def_id; - build_call_shim( - tcx, - instance, - Some(Adjustment::RefMut), - CallKind::Direct(call_mut), - None, - ) + 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), @@ -149,7 +135,7 @@ fn build_drop_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, ty: Option>) 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::TyS { kind: ty::Generator(gen_def_id, substs, _), .. }) = ty { + if let Some(&ty::Generator(gen_def_id, substs, _)) = ty.map(|ty| ty.kind()) { let body = &**tcx.optimized_mir(gen_def_id).generator_drop.as_ref().unwrap(); return body.subst(tcx, substs); } @@ -295,7 +281,7 @@ impl<'a, 'tcx> DropElaborator<'a, 'tcx> for DropShimElaborator<'a, 'tcx> { fn downcast_subpath(&self, _path: Self::Path, _variant: VariantIdx) -> Option { Some(()) } - fn array_subpath(&self, _path: Self::Path, _index: u32, _size: u32) -> Option { + fn array_subpath(&self, _path: Self::Path, _index: u64, _size: u64) -> Option { None } } @@ -312,7 +298,7 @@ fn build_clone_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'tcx>) - let dest = Place::return_place(); let src = tcx.mk_place_deref(Place::from(Local::new(1 + 0))); - match self_ty.kind { + match self_ty.kind() { _ if is_copy => builder.copy_shim(), ty::Array(ty, len) => { let len = len.eval_usize(tcx, param_env); @@ -641,29 +627,45 @@ impl CloneShimBuilder<'tcx> { } } -/// Builds a "call" shim for `instance`. The shim calls the -/// function specified by `call_kind`, first adjusting its first -/// argument according to `rcvr_adjustment`. -/// -/// If `untuple_args` is a vec of types, the second argument of the -/// function will be untupled as these types. +/// 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>, - untuple_args: Option<&[Ty<'tcx>]>, ) -> Body<'tcx> { debug!( - "build_call_shim(instance={:?}, rcvr_adjustment={:?}, \ - call_kind={:?}, untuple_args={:?})", - instance, rcvr_adjustment, call_kind, untuple_args + "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 @@ -853,7 +855,7 @@ pub fn build_adt_ctor(tcx: TyCtxt<'_>, ctor_id: DefId) -> Body<'_> { 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 { + let (adt_def, substs) = match sig.output().kind() { ty::Adt(adt_def, substs) => (adt_def, substs), _ => bug!("unexpected type for ADT ctor {:?}", sig.output()), }; diff --git a/src/librustc_mir/transform/add_call_guards.rs b/compiler/rustc_mir/src/transform/add_call_guards.rs similarity index 100% rename from src/librustc_mir/transform/add_call_guards.rs rename to compiler/rustc_mir/src/transform/add_call_guards.rs diff --git a/src/librustc_mir/transform/add_moves_for_packed_drops.rs b/compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs similarity index 100% rename from src/librustc_mir/transform/add_moves_for_packed_drops.rs rename to compiler/rustc_mir/src/transform/add_moves_for_packed_drops.rs diff --git a/src/librustc_mir/transform/add_retag.rs b/compiler/rustc_mir/src/transform/add_retag.rs similarity index 99% rename from src/librustc_mir/transform/add_retag.rs rename to compiler/rustc_mir/src/transform/add_retag.rs index 324289166b..0c596ba715 100644 --- a/src/librustc_mir/transform/add_retag.rs +++ b/compiler/rustc_mir/src/transform/add_retag.rs @@ -35,7 +35,7 @@ fn is_stable(place: PlaceRef<'_>) -> bool { /// 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 { + match ty.kind() { // Primitive types that are not references ty::Bool | ty::Char diff --git a/compiler/rustc_mir/src/transform/check_const_item_mutation.rs b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs new file mode 100644 index 0000000000..b6d57b899d --- /dev/null +++ b/compiler/rustc_mir/src/transform/check_const_item_mutation.rs @@ -0,0 +1,147 @@ +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, MirSource}; + +pub struct CheckConstItemMutation; + +impl<'tcx> MirPass<'tcx> for CheckConstItemMutation { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _src: MirSource<'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)?; + let mut any_dtor = |_tcx, _def_id| Ok(()); + + // 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, &mut any_dtor) { + Some(_) => None, + None => Some(def_id), + } + } + + fn lint_const_item_usage( + &self, + const_item: DefId, + location: Location, + decorate: impl for<'b> FnOnce(LintDiagnosticBuilder<'b>) -> DiagnosticBuilder<'b>, + ) { + 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) { + // Don't lint on writes through a pointer + // (e.g. `unsafe { *FOO = 0; *BAR.field = 1; }`) + if !matches!(lhs.projection.last(), Some(PlaceElem::Deref)) { + self.lint_const_item_usage(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(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 --git a/compiler/rustc_mir/src/transform/check_consts/mod.rs b/compiler/rustc_mir/src/transform/check_consts/mod.rs new file mode 100644 index 0000000000..8df134860a --- /dev/null +++ b/compiler/rustc_mir/src/transform/check_consts/mod.rs @@ -0,0 +1,115 @@ +//! 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::Symbol; + +pub use self::qualifs::Qualif; + +mod ops; +pub mod post_drop_elaboration; +pub mod qualifs; +mod resolver; +pub mod validation; + +/// 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 def_id: LocalDefId, + pub param_env: ty::ParamEnv<'tcx>, + pub const_kind: Option, +} + +impl ConstCx<'mir, 'tcx> { + pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'mir mir::Body<'tcx>) -> Self { + let param_env = tcx.param_env(def_id); + Self::new_with_param_env(tcx, def_id, body, param_env) + } + + pub fn new_with_param_env( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + body: &'mir mir::Body<'tcx>, + param_env: ty::ParamEnv<'tcx>, + ) -> Self { + let const_kind = tcx.hir().body_const_context(def_id); + ConstCx { body, tcx, def_id: def_id, param_env, const_kind } + } + + /// 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().begin_panic_fn() +} + +pub fn allow_internal_unstable(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { + let attrs = tcx.get_attrs(def_id); + attr::allow_internal_unstable(&tcx.sess, attrs) + .map_or(false, |mut features| features.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}; + + // 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 --git a/compiler/rustc_mir/src/transform/check_consts/ops.rs b/compiler/rustc_mir/src/transform/check_consts/ops.rs new file mode 100644 index 0000000000..32e233e337 --- /dev/null +++ b/compiler/rustc_mir/src/transform/check_consts/ops.rs @@ -0,0 +1,642 @@ +//! 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::config::nightly_options; +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 Abort; +impl NonConstOp for Abort { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error(ccx, span, "abort is not stable in const fn") + } +} + +#[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(pub DefId); +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 a `#[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 nightly_options::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 { + 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()); + 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)] +pub struct CellBorrow; +impl NonConstOp for CellBorrow { + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + struct_span_err!( + ccx.tcx.sess, + span, + E0492, + "cannot borrow a constant which may contain \ + interior mutability, create a static instead" + ) + } +} + +#[derive(Debug)] +pub struct MutBorrow; +impl NonConstOp for MutBorrow { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("mutable references are not allowed in {}s", ccx.const_kind()), + ) + } else { + let mut err = struct_span_err!( + ccx.tcx.sess, + span, + E0764, + "mutable references are not allowed in {}s", + ccx.const_kind(), + ); + err.span_label(span, format!("`&mut` is only allowed in `const fn`")); + err + }; + 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 + } +} + +// FIXME(ecstaticmorse): Unify this with `MutBorrow`. It has basically the same issues. +#[derive(Debug)] +pub struct MutAddressOf; +impl NonConstOp for MutAddressOf { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Forbid everywhere except in const fn with a feature gate + if ccx.const_kind() == hir::ConstContext::ConstFn { + Status::Unstable(sym::const_mut_refs) + } else { + Status::Forbidden + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_mut_refs, + span, + &format!("`&raw mut` is not allowed in {}s", 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 `MutBorrow` 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()), + ) + } +} + +#[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(),), + ) + } +} + +#[derive(Debug)] +pub struct RawPtrToIntCast; +impl NonConstOp for RawPtrToIntCast { + fn status_in_item(&self, _: &ConstCx<'_, '_>) -> Status { + Status::Unstable(sym::const_raw_ptr_to_usize_cast) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_raw_ptr_to_usize_cast, + span, + &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),), + ) + } +} + +/// 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" + ) + } +} + +#[derive(Debug)] +pub struct Transmute; +impl NonConstOp for Transmute { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_transmute) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + let mut err = feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_transmute, + span, + &format!("`transmute` is not allowed in {}s", ccx.const_kind()), + ); + err.note("`transmute` is only allowed in constants and statics for now"); + err + } +} + +#[derive(Debug)] +pub struct UnionAccess; +impl NonConstOp for UnionAccess { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + // Union accesses are stable in all contexts except `const fn`. + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn_union) + } + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + feature_err( + &ccx.tcx.sess.parse_sess, + sym::const_fn_union, + span, + "unions in const fn are unstable", + ) + } +} + +/// See [#64992]. +/// +/// [#64992]: https://github.com/rust-lang/rust/issues/64992 +#[derive(Debug)] +pub struct UnsizingCast; +impl NonConstOp for UnsizingCast { + fn status_in_item(&self, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error( + ccx, + span, + "unsizing casts to types besides slices are not allowed in const fn", + ) + } +} + +// 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, ccx: &ConstCx<'_, '_>) -> Status { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error(ccx, span, "`impl Trait` in const fn is unstable") + } + } + + #[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 { + mcf_status_in_item(ccx) + } + + fn build_error(&self, ccx: &ConstCx<'_, 'tcx>, span: Span) -> DiagnosticBuilder<'tcx> { + mcf_build_error( + ccx, + 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", + ) + } + } +} + +fn mcf_status_in_item(ccx: &ConstCx<'_, '_>) -> Status { + if ccx.const_kind() != hir::ConstContext::ConstFn { + Status::Allowed + } else { + Status::Unstable(sym::const_fn) + } +} + +fn mcf_build_error(ccx: &ConstCx<'_, 'tcx>, span: Span, msg: &str) -> DiagnosticBuilder<'tcx> { + let mut err = struct_span_err!(ccx.tcx.sess, span, E0723, "{}", msg); + err.note( + "see issue #57563 \ + for more information", + ); + err.help("add `#![feature(const_fn)]` to the crate attributes to enable"); + err +} diff --git a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs similarity index 90% rename from src/librustc_mir/transform/check_consts/post_drop_elaboration.rs rename to compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs index 55075b3ab5..9b2568d5ab 100644 --- a/src/librustc_mir/transform/check_consts/post_drop_elaboration.rs +++ b/compiler/rustc_mir/src/transform/check_consts/post_drop_elaboration.rs @@ -4,15 +4,20 @@ use rustc_middle::mir::{self, BasicBlock, Location}; use rustc_middle::ty::TyCtxt; use rustc_span::Span; -use super::ops; +use super::ops::{self, NonConstOp}; use super::qualifs::{NeedsDrop, Qualif}; use super::validation::Qualifs; use super::ConstCx; /// Returns `true` if we should use the more precise live drop checker that runs after drop /// elaboration. -pub fn checking_enabled(tcx: TyCtxt<'tcx>) -> bool { - tcx.features().const_precise_live_drops +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. @@ -25,12 +30,11 @@ pub fn check_live_drops(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &mir::Body< return; } - if !checking_enabled(tcx) { + let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; + if !checking_enabled(&ccx) { return; } - let ccx = ConstCx { body, tcx, def_id, const_kind, param_env: tcx.param_env(def_id) }; - let mut visitor = CheckLiveDrops { ccx: &ccx, qualifs: Qualifs::default() }; visitor.visit_body(body); @@ -52,7 +56,7 @@ impl std::ops::Deref for CheckLiveDrops<'mir, 'tcx> { impl CheckLiveDrops<'mir, 'tcx> { fn check_live_drop(&self, span: Span) { - ops::non_const(self.ccx, ops::LiveDrop(None), span); + ops::LiveDrop { dropped_at: None }.build_error(self.ccx, span).emit(); } } diff --git a/src/librustc_mir/transform/check_consts/qualifs.rs b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs similarity index 99% rename from src/librustc_mir/transform/check_consts/qualifs.rs rename to compiler/rustc_mir/src/transform/check_consts/qualifs.rs index 445a0230af..3f4b3ca2ee 100644 --- a/src/librustc_mir/transform/check_consts/qualifs.rs +++ b/compiler/rustc_mir/src/transform/check_consts/qualifs.rs @@ -170,7 +170,7 @@ where // Special-case reborrows to be more like a copy of the reference. if let &[ref proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { let base_ty = Place::ty_from(place.local, proj_base, cx.body, cx.tcx).ty; - if let ty::Ref(..) = base_ty.kind { + if let ty::Ref(..) = base_ty.kind() { return in_place::( cx, in_local, diff --git a/src/librustc_mir/transform/check_consts/resolver.rs b/compiler/rustc_mir/src/transform/check_consts/resolver.rs similarity index 94% rename from src/librustc_mir/transform/check_consts/resolver.rs rename to compiler/rustc_mir/src/transform/check_consts/resolver.rs index b8104292aa..a00301952b 100644 --- a/src/librustc_mir/transform/check_consts/resolver.rs +++ b/compiler/rustc_mir/src/transform/check_consts/resolver.rs @@ -165,23 +165,19 @@ where } } -impl dataflow::BottomValue for FlowSensitiveAnalysis<'_, '_, '_, Q> { - const BOTTOM_VALUE: bool = false; -} - impl dataflow::AnalysisDomain<'tcx> for FlowSensitiveAnalysis<'_, '_, 'tcx, Q> where Q: Qualif, { - type Idx = Local; + type Domain = BitSet; const NAME: &'static str = Q::ANALYSIS_NAME; - fn bits_per_block(&self, body: &mir::Body<'tcx>) -> usize { - body.local_decls.len() + 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 BitSet) { + fn initialize_start_block(&self, _body: &mir::Body<'tcx>, state: &mut Self::Domain) { self.transfer_function(state).initialize_state(); } } @@ -192,7 +188,7 @@ where { fn apply_statement_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, statement: &mir::Statement<'tcx>, location: Location, ) { @@ -201,7 +197,7 @@ where fn apply_terminator_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, terminator: &mir::Terminator<'tcx>, location: Location, ) { @@ -210,7 +206,7 @@ where fn apply_call_return_effect( &self, - state: &mut BitSet, + state: &mut Self::Domain, block: BasicBlock, func: &mir::Operand<'tcx>, args: &[mir::Operand<'tcx>], diff --git a/src/librustc_mir/transform/check_consts/validation.rs b/compiler/rustc_mir/src/transform/check_consts/validation.rs similarity index 55% rename from src/librustc_mir/transform/check_consts/validation.rs rename to compiler/rustc_mir/src/transform/check_consts/validation.rs index e21f314ca1..4e714bfeed 100644 --- a/src/librustc_mir/transform/check_consts/validation.rs +++ b/compiler/rustc_mir/src/transform/check_consts/validation.rs @@ -1,25 +1,28 @@ //! The `Visitor` responsible for actually checking a `mir::Body` for invalid operations. -use rustc_errors::struct_span_err; -use rustc_hir::{self as hir, LangItem}; -use rustc_hir::{def_id::DefId, HirId}; +use rustc_errors::{struct_span_err, Applicability, Diagnostic}; +use rustc_hir::def_id::DefId; +use rustc_hir::{self as hir, HirId, LangItem}; use rustc_infer::infer::TyCtxtInferExt; use rustc_middle::mir::visit::{MutatingUseContext, NonMutatingUseContext, PlaceContext, Visitor}; use rustc_middle::mir::*; use rustc_middle::ty::cast::CastTy; -use rustc_middle::ty::{self, Instance, InstanceDef, TyCtxt}; -use rustc_span::Span; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::{ + self, adjustment::PointerCast, Instance, InstanceDef, Ty, TyCtxt, TypeAndMut, +}; +use rustc_span::{sym, Span, Symbol}; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, TraitEngine}; -use std::borrow::Cow; +use std::mem; use std::ops::Deref; -use super::ops::{self, NonConstOp}; +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_const_fn, is_unstable_const_fn}; +use crate::const_eval::is_unstable_const_fn; use crate::dataflow::impls::MaybeMutBorrowedLocals; use crate::dataflow::{self, Analysis}; @@ -57,6 +60,7 @@ impl Qualifs<'mir, 'tcx> { MaybeMutBorrowedLocals::mut_borrows_only(tcx, &body, param_env) .unsound_ignore_borrow_on_drop() .into_engine(tcx, &body, def_id.to_def_id()) + .pass_name("const_qualification") .iterate_to_fixpoint() .into_results_cursor(&body) }); @@ -176,6 +180,9 @@ pub struct Validator<'mir, 'tcx> { /// The span of the current statement. span: Span, + + error_emitted: bool, + secondary_errors: Vec, } impl Deref for Validator<'mir, 'tcx> { @@ -188,36 +195,83 @@ impl Deref for Validator<'mir, 'tcx> { impl Validator<'mir, 'tcx> { pub fn new(ccx: &'mir ConstCx<'mir, 'tcx>) -> Self { - Validator { span: ccx.body.span, ccx, qualifs: Default::default() } + Validator { + span: ccx.body.span, + ccx, + qualifs: Default::default(), + error_emitted: false, + secondary_errors: Vec::new(), + } } pub fn check_body(&mut self) { - let ConstCx { tcx, body, def_id, const_kind, .. } = *self.ccx; + let ConstCx { tcx, body, def_id, .. } = *self.ccx; - let use_min_const_fn_checks = (const_kind == Some(hir::ConstContext::ConstFn) - && crate::const_eval::is_min_const_fn(tcx, def_id.to_def_id())) - && !tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you; + // `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_kind.is_some() { + tcx.sess.delay_span_bug(body.span, "`async` functions cannot be `const fn`"); + return; + } - if use_min_const_fn_checks { - // Enforce `min_const_fn` for stable `const fn`s. - use crate::transform::qualify_min_const_fn::is_min_const_fn; - if let Err((span, err)) = is_min_const_fn(tcx, def_id.to_def_id(), &body) { - error_min_const_fn_violation(tcx, span, err); - 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(self.def_id); + if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { + struct_span_err!( + self.ccx.tcx.sess, + self.span, + E0723, + "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 = const_kind - == Some(hir::ConstContext::Static(hir::Mutability::Not)) + 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 { + for error in secondary_errors { + self.tcx.sess.diagnostic().emit_diagnostic(&error); + } + } else { + assert!(self.tcx.sess.has_errors()); + } } pub fn qualifs_in_return_place(&mut self) -> ConstQualifs { @@ -226,13 +280,45 @@ impl Validator<'mir, 'tcx> { /// Emits an error if an expression cannot be evaluated in the current context. pub fn check_op(&mut self, op: impl NonConstOp) { - ops::non_const(self.ccx, op, self.span); + 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: impl NonConstOp, span: Span) { - ops::non_const(self.ccx, op, span); + 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::allow_internal_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 = true; + err.emit(); + } + + ops::DiagnosticImportance::Secondary => err.buffer(&mut self.secondary_errors), + } } fn check_static(&mut self, def_id: DefId, span: Span) { @@ -242,6 +328,106 @@ impl Validator<'mir, 'tcx> { ); 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() { + 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, def_id, .. } = *self.ccx; + + let mut current = def_id.to_def_id(); + loop { + let predicates = tcx.predicates_of(current); + for (predicate, _) in predicates.predicates { + match predicate.skip_binders() { + ty::PredicateAtom::RegionOutlives(_) + | ty::PredicateAtom::TypeOutlives(_) + | ty::PredicateAtom::WellFormed(_) + | ty::PredicateAtom::Projection(_) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => continue, + ty::PredicateAtom::ObjectSafe(_) => { + bug!("object safe predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::ClosureKind(..) => { + bug!("closure kind predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Subtype(_) => { + bug!("subtype predicate on function: {:#?}", predicate) + } + ty::PredicateAtom::Trait(pred, constness) => { + 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; + + if constness == hir::Constness::Const { + self.check_op_spanned(ops::ty::TraitBound(kind), span); + } else if !tcx.features().const_fn + || self.ccx.is_const_stable_const_fn() + { + // HACK: We shouldn't need the conditional above, but trait + // bounds on containing impl blocks are wrongly being marked as + // "not-const". + 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, + } + } + } } impl Visitor<'tcx> for Validator<'mir, 'tcx> { @@ -309,11 +495,6 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { Rvalue::Use(_) | Rvalue::Repeat(..) - | Rvalue::UnaryOp(UnOp::Neg, _) - | Rvalue::UnaryOp(UnOp::Not, _) - | Rvalue::NullaryOp(NullOp::SizeOf, _) - | Rvalue::CheckedBinaryOp(..) - | Rvalue::Cast(CastKind::Pointer(_), ..) | Rvalue::Discriminant(..) | Rvalue::Len(_) | Rvalue::Aggregate(..) => {} @@ -321,7 +502,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { 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 { + 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) => @@ -363,6 +544,35 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } + 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), _, cast_ty) => { + if let Some(TypeAndMut { ty, .. }) = cast_ty.builtin_deref(true) { + let unsized_ty = self.tcx.struct_tail_erasing_lifetimes(ty, self.param_env); + + // Casting/coercing things to slices is fine. + if let ty::Slice(_) | ty::Str = unsized_ty.kind() { + return; + } + } + + self.check_op(ops::UnsizingCast); + } + 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"); @@ -373,8 +583,29 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } } - Rvalue::BinaryOp(op, ref lhs, _) => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { + 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, ref lhs, ref rhs) + | Rvalue::CheckedBinaryOp(op, 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 @@ -386,12 +617,17 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { ); 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 + ); } } - - Rvalue::NullaryOp(NullOp::Box, _) => { - self.check_op(ops::HeapAllocation); - } } } @@ -426,7 +662,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { 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 let ty::RawPtr(_) = base_ty.kind() { if proj_base.is_empty() { if let (local, []) = (place_local, proj_base) { let decl = &self.body.local_decls[local]; @@ -491,14 +727,19 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + use rustc_target::spec::abi::Abi::RustIntrinsic; + trace!("visit_terminator: terminator={:?} location={:?}", terminator, location); self.super_terminator(terminator, location); match &terminator.kind { TerminatorKind::Call { func, .. } => { - let fn_ty = func.ty(self.body, self.tcx); + let ConstCx { tcx, body, def_id: caller, param_env, .. } = *self.ccx; + let caller = caller.to_def_id(); - let (def_id, substs) = match fn_ty.kind { + let fn_ty = func.ty(body, tcx); + + let (mut callee, substs) = match *fn_ty.kind() { ty::FnDef(def_id, substs) => (def_id, substs), ty::FnPtr(_) => { @@ -510,38 +751,88 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { } }; - // At this point, we are calling a function whose `DefId` is known... - if is_const_fn(self.tcx, def_id) { - return; - } - - // See if this is a trait method for a concrete type whose impl of that trait is - // `const`. + // Resolve a trait method call to its concrete implementation, which may be in a + // `const` trait impl. if self.tcx.features().const_trait_impl { - let instance = Instance::resolve(self.tcx, self.param_env, def_id, substs); - debug!("Resolving ({:?}) -> {:?}", def_id, instance); + 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 { - if is_const_fn(self.tcx, def.did) { - return; - } + callee = def.did; } } } - if is_lang_panic_fn(self.tcx, def_id) { + // 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); - } else if let Some(feature) = is_unstable_const_fn(self.tcx, def_id) { - // Exempt unstable const fns inside of macros or functions with - // `#[allow_internal_unstable]`. - use crate::transform::qualify_min_const_fn::lib_feature_allowed; - if !self.span.allows_unstable(feature) - && !lib_feature_allowed(self.tcx, self.def_id.to_def_id(), feature) - { - self.check_op(ops::FnCallUnstable(def_id, feature)); + 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; + } + + // HACK: This is to "unstabilize" the `transmute` intrinsic + // within const fns. `transmute` is allowed in all other const contexts. + // This won't really scale to more intrinsics or functions. Let's allow const + // transmutes in const fn before we add more hacks to this. + if tcx.fn_sig(callee).abi() == RustIntrinsic + && tcx.item_name(callee) == sym::transmute + { + self.check_op(ops::Transmute); + return; + } + + if !tcx.is_const_fn_raw(callee) { + self.check_op(ops::FnCallNonConst(callee)); + 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) { + if self.span.allows_unstable(gate) { + return; + } + + // Calling an unstable function *always* requires that the corresponding gate + // be enabled, even if the function has `#[allow_internal_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() { + return; + } + + // Otherwise, we are something const-stable calling a const-unstable fn. + + if super::allow_internal_unstable(tcx, caller, gate) { + 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 { + if self.ccx.is_const_stable_const_fn() { + self.check_op(ops::FnCallUnstable(callee, None)); } - } else { - self.check_op(ops::FnCallNonConst(def_id)); } } @@ -551,7 +842,7 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { | 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.tcx) { + if super::post_drop_elaboration::checking_enabled(self.ccx) { return; } @@ -576,43 +867,31 @@ impl Visitor<'tcx> for Validator<'mir, 'tcx> { if needs_drop { self.check_op_spanned( - ops::LiveDrop(Some(terminator.source_info.span)), + ops::LiveDrop { dropped_at: Some(terminator.source_info.span) }, err_span, ); } } - TerminatorKind::InlineAsm { .. } => { - self.check_op(ops::InlineAsm); + TerminatorKind::InlineAsm { .. } => self.check_op(ops::InlineAsm), + TerminatorKind::Abort => self.check_op(ops::Abort), + + TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { + self.check_op(ops::Generator(hir::GeneratorKind::Gen)) } - // FIXME: Some of these are only caught by `min_const_fn`, but should error here - // instead. - TerminatorKind::Abort - | TerminatorKind::Assert { .. } + TerminatorKind::Assert { .. } | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::GeneratorDrop | TerminatorKind::Goto { .. } | TerminatorKind::Resume | TerminatorKind::Return | TerminatorKind::SwitchInt { .. } - | TerminatorKind::Unreachable - | TerminatorKind::Yield { .. } => {} + | TerminatorKind::Unreachable => {} } } } -fn error_min_const_fn_violation(tcx: TyCtxt<'_>, span: Span, msg: Cow<'_, str>) { - struct_span_err!(tcx.sess, span, E0723, "{}", msg) - .note( - "see issue #57563 \ - for more information", - ) - .help("add `#![feature(const_fn)]` to the crate attributes to enable") - .emit(); -} - 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| { @@ -647,9 +926,41 @@ fn place_as_reborrow( // 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::ty_from(place.local, inner, body, tcx).ty; - match inner_ty.kind { + match inner_ty.kind() { ty::Ref(..) => Some(inner), _ => 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 `#[allow_internal_unstable]` can be used to bypass stability checks", + format!("#[allow_internal_unstable({})]\n", gate), + Applicability::MaybeIncorrect, + ) + .emit(); +} diff --git a/src/librustc_mir/transform/check_packed_ref.rs b/compiler/rustc_mir/src/transform/check_packed_ref.rs similarity index 100% rename from src/librustc_mir/transform/check_packed_ref.rs rename to compiler/rustc_mir/src/transform/check_packed_ref.rs diff --git a/src/librustc_mir/transform/check_unsafety.rs b/compiler/rustc_mir/src/transform/check_unsafety.rs similarity index 99% rename from src/librustc_mir/transform/check_unsafety.rs rename to compiler/rustc_mir/src/transform/check_unsafety.rs index c3e04e698d..7309a4129e 100644 --- a/src/librustc_mir/transform/check_unsafety.rs +++ b/compiler/rustc_mir/src/transform/check_unsafety.rs @@ -91,8 +91,8 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { ) } - if let ty::FnDef(func_id, _) = func_ty.kind { - self.check_target_features(func_id); + if let ty::FnDef(func_id, _) = func_ty.kind() { + self.check_target_features(*func_id); } } @@ -227,7 +227,7 @@ impl<'a, 'tcx> Visitor<'tcx> for UnsafetyChecker<'a, 'tcx> { } } let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - match base_ty.kind { + match base_ty.kind() { ty::RawPtr(..) => self.require_unsafe( UnsafetyViolationKind::GeneralAndConstFn, UnsafetyViolationDetails::DerefOfRawPointer, @@ -394,7 +394,7 @@ impl<'a, 'tcx> UnsafetyChecker<'a, 'tcx> { ProjectionElem::Field(..) => { let ty = Place::ty_from(place.local, proj_base, &self.body.local_decls, self.tcx).ty; - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if self.tcx.layout_scalar_valid_range(def.did) != (Bound::Unbounded, Bound::Unbounded) { diff --git a/src/librustc_mir/transform/cleanup_post_borrowck.rs b/compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs similarity index 100% rename from src/librustc_mir/transform/cleanup_post_borrowck.rs rename to compiler/rustc_mir/src/transform/cleanup_post_borrowck.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/compiler/rustc_mir/src/transform/const_prop.rs similarity index 99% rename from src/librustc_mir/transform/const_prop.rs rename to compiler/rustc_mir/src/transform/const_prop.rs index 56479b047f..0f04ead94d 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/compiler/rustc_mir/src/transform/const_prop.rs @@ -832,7 +832,7 @@ impl<'mir, 'tcx> ConstPropagator<'mir, 'tcx> { // FIXME: enable the general case stated above ^. let ty = &value.layout.ty; // Only do it for tuples - if let ty::Tuple(substs) = ty.kind { + 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| { @@ -1046,9 +1046,9 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { 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 increases compile time. - if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 3 { + // Only const prop copies and moves on `mir_opt_level=2` as doing so + // currently slightly increases compile time in some cases. + if self.tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { self.propagate_operand(operand) } } @@ -1246,8 +1246,8 @@ impl<'mir, 'tcx> MutVisitor<'tcx> for ConstPropagator<'mir, 'tcx> { | TerminatorKind::InlineAsm { .. } => {} // Every argument in our function calls have already been propagated in `visit_operand`. // - // NOTE: because LLVM codegen gives performance regressions with it, so this is gated - // on `mir_opt_level=3`. + // NOTE: because LLVM codegen gives slight performance regressions with it, so this is + // gated on `mir_opt_level=2`. TerminatorKind::Call { .. } => {} } diff --git a/src/librustc_mir/transform/copy_prop.rs b/compiler/rustc_mir/src/transform/copy_prop.rs similarity index 98% rename from src/librustc_mir/transform/copy_prop.rs rename to compiler/rustc_mir/src/transform/copy_prop.rs index ba406c72df..74194467b3 100644 --- a/src/librustc_mir/transform/copy_prop.rs +++ b/compiler/rustc_mir/src/transform/copy_prop.rs @@ -31,9 +31,11 @@ pub struct CopyPropagation; impl<'tcx> MirPass<'tcx> for CopyPropagation { fn run_pass(&self, tcx: TyCtxt<'tcx>, _source: MirSource<'tcx>, body: &mut Body<'tcx>) { + let opts = &tcx.sess.opts.debugging_opts; // We only run when the MIR optimization level is > 1. // This avoids a slow pass, and messing up debug info. - if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + // FIXME(76740): This optimization is buggy and can cause unsoundness. + if opts.mir_opt_level <= 1 || !opts.unsound_mir_opts { return; } diff --git a/src/librustc_mir/transform/deaggregator.rs b/compiler/rustc_mir/src/transform/deaggregator.rs similarity index 100% rename from src/librustc_mir/transform/deaggregator.rs rename to compiler/rustc_mir/src/transform/deaggregator.rs diff --git a/compiler/rustc_mir/src/transform/dest_prop.rs b/compiler/rustc_mir/src/transform/dest_prop.rs new file mode 100644 index 0000000000..97d2617607 --- /dev/null +++ b/compiler/rustc_mir/src/transform/dest_prop.rs @@ -0,0 +1,1057 @@ +//! 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 +//! https://github.com/rust-lang/rust/issues/32966), 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, MirSource}, + 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::{self, 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>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + // Only run at mir-opt-level=2 or higher for now (we don't fix up debuginfo and remove + // storage statements at the moment). + if tcx.sess.opts.debugging_opts.mir_opt_level <= 1 { + return; + } + + let candidates = find_candidates(tcx, body); + if candidates.is_empty() { + debug!("{:?}: no dest prop candidates, done", source.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", + source.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", + source.def_id(), + relevant, + MAX_LOCALS + ); + return; + } + if body.basic_blocks().len() > MAX_BLOCKS { + warn!( + "too many blocks in {:?} ({}, max is {}), not optimizing", + source.def_id(), + body.basic_blocks().len(), + MAX_BLOCKS + ); + return; + } + + let mut conflicts = Conflicts::build(tcx, body, source, &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 {:?} {:?}", source.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>, + source: MirSource<'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 def_id = source.def_id(); + let mut init = MaybeInitializedLocals + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + let mut live = MaybeLiveLocals + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + + let mut reachable = None; + dump_mir( + tcx, + None, + "DestinationPropagation-dataflow", + &"", + source, + 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::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::Const { value } => { + assert!(value.place().is_none()); + } + InlineAsmOperand::InOut { + reg: _, + late: _, + in_value: _, + out_place: None, + } + | InlineAsmOperand::In { reg: _, value: _ } + | InlineAsmOperand::Out { reg: _, late: _, place: None } + | 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 is_union = |ty: Ty<'_>| { + if let ty::Adt(def, _) = ty.kind() { + if def.is_union() { + return true; + } + } + + false + }; + let mut place_ty = PlaceTy::from_ty(self.body.local_decls[dest.local].ty); + if is_union(place_ty.ty) { + 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 is_union(place_ty.ty) { + 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 --git a/src/librustc_mir/transform/dump_mir.rs b/compiler/rustc_mir/src/transform/dump_mir.rs similarity index 100% rename from src/librustc_mir/transform/dump_mir.rs rename to compiler/rustc_mir/src/transform/dump_mir.rs diff --git a/compiler/rustc_mir/src/transform/early_otherwise_branch.rs b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs new file mode 100644 index 0000000000..ba64e6c1e5 --- /dev/null +++ b/compiler/rustc_mir/src/transform/early_otherwise_branch.rs @@ -0,0 +1,339 @@ +use crate::{ + transform::{MirPass, MirSource}, + util::patch::MirPatch, +}; +use rustc_middle::mir::*; +use rustc_middle::ty::{Ty, TyCtxt}; +use std::{borrow::Cow, 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>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { + return; + } + trace!("running EarlyOtherwiseBranch on {:?}", 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 { + 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, + Operand::Copy(Place::from(second_discriminant_temp)), + Operand::Copy(first_descriminant_place), + ); + patch.add_statement( + end_of_block_location, + StatementKind::Assign(box (Place::from(not_equal_temp), not_equal_rvalue)), + ); + + let (mut targets_to_jump_to, values_to_jump_to): (Vec<_>, Vec<_>) = opt_to_apply + .infos + .iter() + .flat_map(|x| x.second_switch_info.targets_with_values.iter()) + .cloned() + .unzip(); + + // add otherwise case in the end + targets_to_jump_to.push(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, + values: Cow::from(values_to_jump_to), + targets: targets_to_jump_to, + }, + })); + + 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(body); + } + } +} + +fn is_switch<'tcx>(terminator: &Terminator<'tcx>) -> bool { + match terminator.kind { + TerminatorKind::SwitchInt { .. } => true, + _ => false, + } +} + +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<(BasicBlock, u128)>, + 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(|(target, value)| { + self.find_discriminant_switch_pairing(&discr, target.clone(), value.clone()) + }); + + // 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.1 == 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].1 == 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; + } + + // 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, values, .. } => { + 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.get(values.len())?.clone(); + let targets_with_values = targets + .iter() + .zip(values.iter()) + .map(|(t, v)| (t.clone(), v.clone())) + .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 --git a/src/librustc_mir/transform/elaborate_drops.rs b/compiler/rustc_mir/src/transform/elaborate_drops.rs similarity index 99% rename from src/librustc_mir/transform/elaborate_drops.rs rename to compiler/rustc_mir/src/transform/elaborate_drops.rs index ad49090bfc..a8b2ee5705 100644 --- a/src/librustc_mir/transform/elaborate_drops.rs +++ b/compiler/rustc_mir/src/transform/elaborate_drops.rs @@ -44,6 +44,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { let inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); @@ -51,6 +52,7 @@ impl<'tcx> MirPass<'tcx> for ElaborateDrops { .mark_inactive_variants_as_uninit() .into_engine(tcx, body, def_id) .dead_unwinds(&dead_unwinds) + .pass_name("elaborate_drops") .iterate_to_fixpoint() .into_results_cursor(body); @@ -83,6 +85,7 @@ fn find_dead_unwinds<'tcx>( let mut dead_unwinds = BitSet::new_empty(body.basic_blocks().len()); let mut flow_inits = MaybeInitializedPlaces::new(tcx, body, &env) .into_engine(tcx, body, def_id) + .pass_name("find_dead_unwinds") .iterate_to_fixpoint() .into_results_cursor(body); for (bb, bb_data) in body.basic_blocks().iter_enumerated() { @@ -219,7 +222,7 @@ impl<'a, 'b, 'tcx> DropElaborator<'a, 'tcx> for Elaborator<'a, 'b, 'tcx> { }) } - fn array_subpath(&self, path: Self::Path, index: u32, size: u32) -> Option { + 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"); diff --git a/src/librustc_mir/transform/generator.rs b/compiler/rustc_mir/src/transform/generator.rs similarity index 99% rename from src/librustc_mir/transform/generator.rs rename to compiler/rustc_mir/src/transform/generator.rs index a22075e760..1fffcf8151 100644 --- a/src/librustc_mir/transform/generator.rs +++ b/compiler/rustc_mir/src/transform/generator.rs @@ -467,8 +467,10 @@ fn locals_live_across_suspend_points( // 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, def_id).iterate_to_fixpoint(); + let borrowed_locals_results = MaybeBorrowedLocals::all_borrows() + .into_engine(tcx, body_ref, def_id) + .pass_name("generator") + .iterate_to_fixpoint(); let mut borrowed_locals_cursor = dataflow::ResultsCursor::new(body_ref, &borrowed_locals_results); @@ -484,6 +486,7 @@ fn locals_live_across_suspend_points( // Calculate the liveness of MIR locals ignoring borrows. let mut liveness = MaybeLiveLocals .into_engine(tcx, body_ref, def_id) + .pass_name("generator") .iterate_to_fixpoint() .into_results_cursor(body_ref); @@ -726,12 +729,12 @@ fn sanitize_witness<'tcx>( saved_locals: &GeneratorSavedLocals, ) { let allowed_upvars = tcx.erase_regions(upvars); - let allowed = match witness.kind { + 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), + &format!("unexpected generator witness type {:?}", witness.kind()), ); return; } @@ -1252,7 +1255,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { 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 { + let (upvars, interior, discr_ty, movable) = match *gen_ty.kind() { ty::Generator(_, substs, movability) => { let substs = substs.as_generator(); ( diff --git a/src/librustc_mir/transform/inline.rs b/compiler/rustc_mir/src/transform/inline.rs similarity index 92% rename from src/librustc_mir/transform/inline.rs rename to compiler/rustc_mir/src/transform/inline.rs index 315d4fa9d4..4e7cacc2f4 100644 --- a/src/librustc_mir/transform/inline.rs +++ b/compiler/rustc_mir/src/transform/inline.rs @@ -4,7 +4,7 @@ use rustc_attr as attr; use rustc_hir::def_id::DefId; use rustc_index::bit_set::BitSet; use rustc_index::vec::{Idx, IndexVec}; -use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; +use rustc_middle::middle::codegen_fn_attrs::{CodegenFnAttrFlags, CodegenFnAttrs}; use rustc_middle::mir::visit::*; use rustc_middle::mir::*; use rustc_middle::ty::subst::{Subst, SubstsRef}; @@ -45,7 +45,8 @@ impl<'tcx> MirPass<'tcx> for Inline { // based function. debug!("function inlining is disabled when compiling with `instrument_coverage`"); } else { - Inliner { tcx, source }.run_pass(body); + Inliner { tcx, source, codegen_fn_attrs: tcx.codegen_fn_attrs(source.def_id()) } + .run_pass(body); } } } @@ -54,6 +55,7 @@ impl<'tcx> MirPass<'tcx> for Inline { struct Inliner<'tcx> { tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, + codegen_fn_attrs: &'tcx CodegenFnAttrs, } impl Inliner<'tcx> { @@ -107,8 +109,14 @@ impl Inliner<'tcx> { // Avoid a cycle here by only using `optimized_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 { + // So don't do it if that is enabled. Also 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 !self.tcx.dep_graph.is_fully_enabled() + && self_hir_id < callee_hir_id + && caller_body.generator_kind.is_none() + { self.tcx.optimized_mir(callsite.callee) } else { continue; @@ -191,7 +199,7 @@ impl Inliner<'tcx> { // Only consider direct calls to functions let terminator = bb_data.terminator(); if let TerminatorKind::Call { func: ref op, .. } = terminator.kind { - if let ty::FnDef(callee_def_id, substs) = op.ty(caller_body, self.tcx).kind { + if let ty::FnDef(callee_def_id, substs) = *op.ty(caller_body, self.tcx).kind() { let instance = Instance::resolve(self.tcx, param_env, callee_def_id, substs).ok().flatten()?; @@ -236,9 +244,19 @@ impl Inliner<'tcx> { return false; } - // Avoid inlining functions marked as no_sanitize if sanitizer is enabled, - // since instrumentation might be enabled and performed on the caller. - if self.tcx.sess.opts.debugging_opts.sanitizer.intersects(codegen_fn_attrs.no_sanitize) { + let self_features = &self.codegen_fn_attrs.target_features; + let callee_features = &codegen_fn_attrs.target_features; + if callee_features.iter().any(|feature| !self_features.contains(feature)) { + debug!("`callee has extra target features - not inlining"); + return false; + } + + let self_no_sanitize = + self.codegen_fn_attrs.no_sanitize & self.tcx.sess.opts.debugging_opts.sanitizer; + let callee_no_sanitize = + codegen_fn_attrs.no_sanitize & self.tcx.sess.opts.debugging_opts.sanitizer; + if self_no_sanitize != callee_no_sanitize { + debug!("`callee has incompatible no_sanitize attribute - not inlining"); return false; } @@ -336,7 +354,7 @@ impl Inliner<'tcx> { } TerminatorKind::Call { func: Operand::Constant(ref f), cleanup, .. } => { - if let ty::FnDef(def_id, _) = f.literal.ty.kind { + if let ty::FnDef(def_id, _) = *f.literal.ty.kind() { // 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 { @@ -488,7 +506,7 @@ impl Inliner<'tcx> { let return_block = destination.1; // Copy the arguments if needed. - let args: Vec<_> = self.make_call_args(args, &callsite, caller_body); + let args: Vec<_> = self.make_call_args(args, &callsite, caller_body, return_block); let bb_len = caller_body.basic_blocks().len(); let mut integrator = Integrator { @@ -535,6 +553,7 @@ impl Inliner<'tcx> { args: Vec>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + return_block: BasicBlock, ) -> Vec { let tcx = self.tcx; @@ -563,12 +582,22 @@ impl Inliner<'tcx> { // and the vector is `[closure_ref, tmp0, tmp1, tmp2]`. if tcx.is_closure(callsite.callee) { 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); + let self_ = self.create_temp_if_necessary( + args.next().unwrap(), + callsite, + caller_body, + return_block, + ); + let tuple = self.create_temp_if_necessary( + args.next().unwrap(), + callsite, + caller_body, + return_block, + ); 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 { + 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"); @@ -584,13 +613,13 @@ impl Inliner<'tcx> { 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) + self.create_temp_if_necessary(tuple_field, callsite, caller_body, return_block) }); closure_ref_arg.chain(tuple_tmp_args).collect() } else { args.into_iter() - .map(|a| self.create_temp_if_necessary(a, callsite, caller_body)) + .map(|a| self.create_temp_if_necessary(a, callsite, caller_body, return_block)) .collect() } } @@ -602,6 +631,7 @@ impl Inliner<'tcx> { arg: Operand<'tcx>, callsite: &CallSite<'tcx>, caller_body: &mut Body<'tcx>, + return_block: BasicBlock, ) -> Local { // FIXME: Analysis of the usage of the arguments to avoid // unnecessary temporaries. @@ -624,11 +654,19 @@ impl Inliner<'tcx> { let arg_tmp = LocalDecl::new(ty, callsite.location.span); let arg_tmp = caller_body.local_decls.push(arg_tmp); - let stmt = Statement { + caller_body[callsite.bb].statements.push(Statement { + source_info: callsite.location, + kind: StatementKind::StorageLive(arg_tmp), + }); + caller_body[callsite.bb].statements.push(Statement { source_info: callsite.location, kind: StatementKind::Assign(box (Place::from(arg_tmp), arg)), - }; - caller_body[callsite.bb].statements.push(stmt); + }); + caller_body[return_block].statements.insert( + 0, + Statement { source_info: callsite.location, kind: StatementKind::StorageDead(arg_tmp) }, + ); + arg_tmp } } diff --git a/compiler/rustc_mir/src/transform/instcombine.rs b/compiler/rustc_mir/src/transform/instcombine.rs new file mode 100644 index 0000000000..ada24899e1 --- /dev/null +++ b/compiler/rustc_mir/src/transform/instcombine.rs @@ -0,0 +1,285 @@ +//! Performs various peephole optimizations. + +use crate::transform::{MirPass, MirSource}; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_hir::Mutability; +use rustc_index::vec::Idx; +use rustc_middle::mir::{ + visit::PlaceContext, + visit::{MutVisitor, Visitor}, + Statement, +}; +use rustc_middle::mir::{ + BinOp, Body, BorrowKind, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, + Rvalue, +}; +use rustc_middle::ty::{self, TyCtxt}; +use std::mem; + +pub struct InstCombine; + +impl<'tcx> MirPass<'tcx> for InstCombine { + fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + // First, find optimization opportunities. This is done in a pre-pass to keep the MIR + // read-only so that we can do global analyses on the MIR in the process (e.g. + // `Place::ty()`). + let optimizations = { + let mut optimization_finder = OptimizationFinder::new(body, tcx); + optimization_finder.visit_body(body); + optimization_finder.optimizations + }; + + // Then carry out those optimizations. + MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); + } +} + +pub struct InstCombineVisitor<'tcx> { + optimizations: OptimizationList<'tcx>, + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { + fn tcx(&self) -> TyCtxt<'tcx> { + self.tcx + } + + fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { + if self.optimizations.and_stars.remove(&location) { + debug!("replacing `&*`: {:?}", rvalue); + let new_place = match rvalue { + Rvalue::Ref(_, _, place) => { + if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { + place.projection = self.tcx().intern_place_elems(&[proj_r]); + + Place { + // Replace with dummy + local: mem::replace(&mut place.local, Local::new(0)), + projection: self.tcx().intern_place_elems(proj_l), + } + } else { + unreachable!(); + } + } + _ => bug!("Detected `&*` but didn't find `&*`!"), + }; + *rvalue = Rvalue::Use(Operand::Copy(new_place)) + } + + if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { + debug!("replacing `Len([_; N])`: {:?}", rvalue); + *rvalue = Rvalue::Use(Operand::Constant(box constant)); + } + + if let Some(operand) = self.optimizations.unneeded_equality_comparison.remove(&location) { + debug!("replacing {:?} with {:?}", rvalue, operand); + *rvalue = Rvalue::Use(operand); + } + + if let Some(place) = self.optimizations.unneeded_deref.remove(&location) { + debug!("unneeded_deref: replacing {:?} with {:?}", rvalue, place); + *rvalue = Rvalue::Use(Operand::Copy(place)); + } + + self.super_rvalue(rvalue, location) + } +} + +struct MutatingUseVisitor { + has_mutating_use: bool, + local_to_look_for: Local, +} + +impl MutatingUseVisitor { + fn has_mutating_use_in_stmt(local: Local, stmt: &Statement<'tcx>, location: Location) -> bool { + let mut _self = Self { has_mutating_use: false, local_to_look_for: local }; + _self.visit_statement(stmt, location); + _self.has_mutating_use + } +} + +impl<'tcx> Visitor<'tcx> for MutatingUseVisitor { + fn visit_local(&mut self, local: &Local, context: PlaceContext, _: Location) { + if *local == self.local_to_look_for { + self.has_mutating_use |= context.is_mutating_use(); + } + } +} + +/// Finds optimization opportunities on the MIR. +struct OptimizationFinder<'b, 'tcx> { + body: &'b Body<'tcx>, + tcx: TyCtxt<'tcx>, + optimizations: OptimizationList<'tcx>, +} + +impl OptimizationFinder<'b, 'tcx> { + fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> { + OptimizationFinder { body, tcx, optimizations: OptimizationList::default() } + } + + fn find_deref_of_address(&mut self, rvalue: &Rvalue<'tcx>, location: Location) -> Option<()> { + // FIXME(#78192): This optimization can result in unsoundness. + if !self.tcx.sess.opts.debugging_opts.unsound_mir_opts { + return None; + } + + // Look for the sequence + // + // _2 = &_1; + // ... + // _5 = (*_2); + // + // which we can replace the last statement with `_5 = _1;` to avoid the load of `_2`. + if let Rvalue::Use(op) = rvalue { + let local_being_derefed = match op.place()?.as_ref() { + PlaceRef { local, projection: [ProjectionElem::Deref] } => Some(local), + _ => None, + }?; + + let stmt_index = location.statement_index; + // Look behind for statement that assigns the local from a address of operator. + // 6 is chosen as a heuristic determined by seeing the number of times + // the optimization kicked in compiling rust std. + let lower_index = stmt_index.saturating_sub(6); + let statements_to_look_in = self.body.basic_blocks()[location.block].statements + [lower_index..stmt_index] + .iter() + .rev(); + for stmt in statements_to_look_in { + match &stmt.kind { + // Exhaustive match on statements to detect conditions that warrant we bail out of the optimization. + rustc_middle::mir::StatementKind::Assign(box (l, r)) + if l.local == local_being_derefed => + { + match r { + // Looking for immutable reference e.g _local_being_deref = &_1; + Rvalue::Ref( + _, + // Only apply the optimization if it is an immutable borrow. + BorrowKind::Shared, + place_taken_address_of, + ) => { + self.optimizations + .unneeded_deref + .insert(location, *place_taken_address_of); + return Some(()); + } + + // We found an assignment of `local_being_deref` that is not an immutable ref, e.g the following sequence + // _2 = &_1; + // _3 = &5 + // _2 = _3; <-- this means it is no longer valid to replace the last statement with `_5 = _1;` + // _5 = (*_2); + _ => return None, + } + } + + // Inline asm can do anything, so bail out of the optimization. + rustc_middle::mir::StatementKind::LlvmInlineAsm(_) => return None, + + // Check that `local_being_deref` is not being used in a mutating way which can cause misoptimization. + rustc_middle::mir::StatementKind::Assign(box (_, _)) + | rustc_middle::mir::StatementKind::Coverage(_) + | rustc_middle::mir::StatementKind::Nop + | rustc_middle::mir::StatementKind::FakeRead(_, _) + | rustc_middle::mir::StatementKind::StorageLive(_) + | rustc_middle::mir::StatementKind::StorageDead(_) + | rustc_middle::mir::StatementKind::Retag(_, _) + | rustc_middle::mir::StatementKind::AscribeUserType(_, _) + | rustc_middle::mir::StatementKind::SetDiscriminant { .. } => { + if MutatingUseVisitor::has_mutating_use_in_stmt( + local_being_derefed, + stmt, + location, + ) { + return None; + } + } + } + } + } + Some(()) + } + + fn find_unneeded_equality_comparison(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + // find Ne(_place, false) or Ne(false, _place) + // or Eq(_place, true) or Eq(true, _place) + if let Rvalue::BinaryOp(op, l, r) = rvalue { + let const_to_find = if *op == BinOp::Ne { + false + } else if *op == BinOp::Eq { + true + } else { + return; + }; + // (const, _place) + if let Some(o) = self.find_operand_in_equality_comparison_pattern(l, r, const_to_find) { + self.optimizations.unneeded_equality_comparison.insert(location, o.clone()); + } + // (_place, const) + else if let Some(o) = + self.find_operand_in_equality_comparison_pattern(r, l, const_to_find) + { + self.optimizations.unneeded_equality_comparison.insert(location, o.clone()); + } + } + } + + fn find_operand_in_equality_comparison_pattern( + &self, + l: &Operand<'tcx>, + r: &'a Operand<'tcx>, + const_to_find: bool, + ) -> Option<&'a Operand<'tcx>> { + let const_ = l.constant()?; + if const_.literal.ty == self.tcx.types.bool + && const_.literal.val.try_to_bool() == Some(const_to_find) + { + if r.place().is_some() { + return Some(r); + } + } + + None + } +} + +impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { + fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { + if let Rvalue::Ref(_, _, place) = rvalue { + if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } = + place.as_ref() + { + // The dereferenced place must have type `&_`. + let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty; + if let ty::Ref(_, _, Mutability::Not) = ty.kind() { + self.optimizations.and_stars.insert(location); + } + } + } + + if let Rvalue::Len(ref place) = *rvalue { + let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; + if let ty::Array(_, len) = place_ty.kind() { + let span = self.body.source_info(location).span; + let constant = Constant { span, literal: len, user_ty: None }; + self.optimizations.arrays_lengths.insert(location, constant); + } + } + + let _ = self.find_deref_of_address(rvalue, location); + + self.find_unneeded_equality_comparison(rvalue, location); + + self.super_rvalue(rvalue, location) + } +} + +#[derive(Default)] +struct OptimizationList<'tcx> { + and_stars: FxHashSet, + arrays_lengths: FxHashMap>, + unneeded_equality_comparison: FxHashMap>, + unneeded_deref: FxHashMap>, +} diff --git a/compiler/rustc_mir/src/transform/instrument_coverage.rs b/compiler/rustc_mir/src/transform/instrument_coverage.rs new file mode 100644 index 0000000000..a5b30a25a9 --- /dev/null +++ b/compiler/rustc_mir/src/transform/instrument_coverage.rs @@ -0,0 +1,491 @@ +use crate::transform::{MirPass, MirSource}; +use crate::util::pretty; +use crate::util::spanview::{ + source_range_no_file, statement_kind_name, terminator_kind_name, write_spanview_document, + SpanViewable, TOOLTIP_INDENT, +}; + +use rustc_data_structures::fingerprint::Fingerprint; +use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_index::bit_set::BitSet; +use rustc_middle::hir; +use rustc_middle::ich::StableHashingContext; +use rustc_middle::mir; +use rustc_middle::mir::coverage::*; +use rustc_middle::mir::visit::Visitor; +use rustc_middle::mir::{ + BasicBlock, BasicBlockData, Coverage, CoverageInfo, Location, Statement, StatementKind, + TerminatorKind, +}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::TyCtxt; +use rustc_span::def_id::DefId; +use rustc_span::{FileName, Pos, RealFileName, Span, Symbol}; + +/// 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; + +/// The `query` provider for `CoverageInfo`, requested by `codegen_coverage()` (to inject each +/// counter) and `FunctionCoverage::new()` (to extract the coverage map metadata from the MIR). +pub(crate) fn provide(providers: &mut Providers) { + providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); +} + +struct CoverageVisitor { + info: CoverageInfo, +} + +impl Visitor<'_> for CoverageVisitor { + fn visit_coverage(&mut self, coverage: &Coverage, _location: Location) { + match coverage.kind { + CoverageKind::Counter { id, .. } => { + let counter_id = u32::from(id); + self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); + } + CoverageKind::Expression { id, .. } => { + let expression_index = u32::MAX - u32::from(id); + self.info.num_expressions = + std::cmp::max(self.info.num_expressions, expression_index + 1); + } + _ => {} + } + } +} + +fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> CoverageInfo { + let mir_body = tcx.optimized_mir(def_id); + + // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected + // counters, with each counter having a counter ID from `0..num_counters-1`. MIR optimization + // may split and duplicate some BasicBlock sequences. Simply counting the calls may not + // work; but computing the num_counters by adding `1` to the highest counter_id (for a given + // instrumented function) is valid. + // + // `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. + let mut coverage_visitor = + CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } }; + + coverage_visitor.visit_body(mir_body); + coverage_visitor.info +} + +impl<'tcx> MirPass<'tcx> for InstrumentCoverage { + fn run_pass( + &self, + tcx: TyCtxt<'tcx>, + mir_source: MirSource<'tcx>, + mir_body: &mut mir::Body<'tcx>, + ) { + // 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_none() { + Instrumentor::new(&self.name(), tcx, mir_source, mir_body).inject_counters(); + } + } +} + +#[derive(Clone)] +struct CoverageRegion { + pub span: Span, + pub blocks: Vec, +} + +struct Instrumentor<'a, 'tcx> { + pass_name: &'a str, + tcx: TyCtxt<'tcx>, + mir_source: MirSource<'tcx>, + mir_body: &'a mut mir::Body<'tcx>, + hir_body: &'tcx rustc_hir::Body<'tcx>, + function_source_hash: Option, + num_counters: u32, + num_expressions: u32, +} + +impl<'a, 'tcx> Instrumentor<'a, 'tcx> { + fn new( + pass_name: &'a str, + tcx: TyCtxt<'tcx>, + mir_source: MirSource<'tcx>, + mir_body: &'a mut mir::Body<'tcx>, + ) -> Self { + let hir_body = hir_body(tcx, mir_source.def_id()); + Self { + pass_name, + tcx, + mir_source, + mir_body, + hir_body, + function_source_hash: None, + num_counters: 0, + num_expressions: 0, + } + } + + /// Counter IDs start from zero and go up. + fn next_counter(&mut self) -> CounterValueReference { + assert!(self.num_counters < u32::MAX - self.num_expressions); + let next = self.num_counters; + self.num_counters += 1; + CounterValueReference::from(next) + } + + /// Expression IDs start from u32::MAX and go down because a CounterExpression can reference + /// (add or subtract counts) of both Counter regions and CounterExpression regions. The counter + /// expression operand IDs must be unique across both types. + fn next_expression(&mut self) -> InjectedExpressionIndex { + assert!(self.num_counters < u32::MAX - self.num_expressions); + let next = u32::MAX - self.num_expressions; + self.num_expressions += 1; + InjectedExpressionIndex::from(next) + } + + fn function_source_hash(&mut self) -> u64 { + match self.function_source_hash { + Some(hash) => hash, + None => { + let hash = hash_mir_source(self.tcx, self.hir_body); + self.function_source_hash.replace(hash); + hash + } + } + } + + fn inject_counters(&mut self) { + let tcx = self.tcx; + let def_id = self.mir_source.def_id(); + let mir_body = &self.mir_body; + let body_span = self.hir_body.value.span; + debug!( + "instrumenting {:?}, span: {}", + def_id, + tcx.sess.source_map().span_to_string(body_span) + ); + + if !tcx.sess.opts.debugging_opts.experimental_coverage { + // Coverage at the function level should be accurate. This is the default implementation + // if `-Z experimental-coverage` is *NOT* enabled. + let block = rustc_middle::mir::START_BLOCK; + let counter = self.make_counter(); + self.inject_statement(counter, body_span, block); + return; + } + // FIXME(richkadel): else if `-Z experimental-coverage` *IS* enabled: Efforts are still in + // progress to identify the correct code region spans and associated counters to generate + // accurate Rust coverage reports. + + let block_span = |data: &BasicBlockData<'tcx>| { + // The default span will be the `Terminator` span; but until we have a smarter solution, + // the coverage region also incorporates at least the statements in this BasicBlock as + // well. Extend the span to encompass all, if possible. + // FIXME(richkadel): Assuming the terminator's span is already known to be contained in `body_span`. + let mut span = data.terminator().source_info.span; + // FIXME(richkadel): It's looking unlikely that we should compute a span from MIR + // spans, but if we do keep something like this logic, we will need a smarter way + // to combine `Statement`s and/or `Terminator`s with `Span`s from different + // files. + for statement_span in data.statements.iter().map(|statement| statement.source_info.span) + { + // Only combine Spans from the function's body_span. + if body_span.contains(statement_span) { + span = span.to(statement_span); + } + } + span + }; + + // Traverse the CFG but ignore anything following an `unwind` + let cfg_without_unwind = ShortCircuitPreorder::new(mir_body, |term_kind| { + let mut successors = term_kind.successors(); + 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 + _ => successors.next().into_iter().chain(&[]), + } + }); + + let mut coverage_regions = Vec::with_capacity(cfg_without_unwind.size_hint().0); + for (bb, data) in cfg_without_unwind { + if !body_span.contains(data.terminator().source_info.span) { + continue; + } + + // FIXME(richkadel): Regions will soon contain multiple blocks. + let mut blocks = Vec::new(); + blocks.push(bb); + let span = block_span(data); + coverage_regions.push(CoverageRegion { span, blocks }); + } + + let span_viewables = if pretty::dump_enabled(tcx, self.pass_name, def_id) { + Some(self.span_viewables(&coverage_regions)) + } else { + None + }; + + // Inject counters for the selected spans + for CoverageRegion { span, blocks } in coverage_regions { + debug!( + "Injecting counter at: {:?}:\n{}\n==========", + span, + tcx.sess.source_map().span_to_snippet(span).expect("Error getting source for span"), + ); + let counter = self.make_counter(); + self.inject_statement(counter, span, blocks[0]); + } + + if let Some(span_viewables) = span_viewables { + let mut file = + pretty::create_dump_file(tcx, "html", None, self.pass_name, &0, self.mir_source) + .expect("Unexpected error creating MIR spanview HTML file"); + write_spanview_document(tcx, def_id, span_viewables, &mut file) + .expect("Unexpected IO error dumping coverage spans as HTML"); + } + + // FIXME(richkadel): Some regions will be counted by "counter expression". Counter + // expressions are supported, but are not yet generated. When they are, remove this `fake_use` + // block. + let fake_use = false; + if fake_use { + let add = false; + let fake_counter = CoverageKind::Counter { + function_source_hash: self.function_source_hash(), + id: CounterValueReference::from_u32(1), + }; + let fake_expression = CoverageKind::Expression { + id: InjectedExpressionIndex::from(u32::MAX - 1), + lhs: ExpressionOperandId::from_u32(1), + op: Op::Add, + rhs: ExpressionOperandId::from_u32(2), + }; + + let lhs = fake_counter.as_operand_id(); + let op = if add { Op::Add } else { Op::Subtract }; + let rhs = fake_expression.as_operand_id(); + + let block = rustc_middle::mir::START_BLOCK; + + let expression = self.make_expression(lhs, op, rhs); + self.inject_statement(expression, body_span, block); + } + } + + fn make_counter(&mut self) -> CoverageKind { + CoverageKind::Counter { + function_source_hash: self.function_source_hash(), + id: self.next_counter(), + } + } + + fn make_expression( + &mut self, + lhs: ExpressionOperandId, + op: Op, + rhs: ExpressionOperandId, + ) -> CoverageKind { + CoverageKind::Expression { id: self.next_expression(), lhs, op, rhs } + } + + fn inject_statement(&mut self, coverage_kind: CoverageKind, span: Span, block: BasicBlock) { + let code_region = make_code_region(self.tcx, &span); + debug!(" injecting statement {:?} covering {:?}", coverage_kind, code_region); + + let data = &mut self.mir_body[block]; + let source_info = data.terminator().source_info; + let statement = Statement { + source_info, + kind: StatementKind::Coverage(box Coverage { kind: coverage_kind, code_region }), + }; + data.statements.push(statement); + } + + /// Converts the computed `CoverageRegion`s into `SpanViewable`s. + fn span_viewables(&self, coverage_regions: &Vec) -> Vec { + let mut span_viewables = Vec::new(); + for coverage_region in coverage_regions { + span_viewables.push(SpanViewable { + span: coverage_region.span, + id: format!("{}", coverage_region.blocks[0].index()), + tooltip: self.make_tooltip_text(coverage_region), + }); + } + span_viewables + } + + /// A custom tooltip renderer used in a spanview HTML+CSS document used for coverage analysis. + fn make_tooltip_text(&self, coverage_region: &CoverageRegion) -> String { + const INCLUDE_COVERAGE_STATEMENTS: bool = false; + let tcx = self.tcx; + let source_map = tcx.sess.source_map(); + let mut text = Vec::new(); + for (i, &bb) in coverage_region.blocks.iter().enumerate() { + if i > 0 { + text.push("\n".to_owned()); + } + text.push(format!("{:?}: {}:", bb, &source_map.span_to_string(coverage_region.span))); + let data = &self.mir_body.basic_blocks()[bb]; + for statement in &data.statements { + let statement_string = match statement.kind { + StatementKind::Coverage(box ref coverage) => match coverage.kind { + CoverageKind::Counter { id, .. } => { + if !INCLUDE_COVERAGE_STATEMENTS { + continue; + } + format!("increment counter #{}", id.index()) + } + CoverageKind::Expression { id, lhs, op, rhs } => { + if !INCLUDE_COVERAGE_STATEMENTS { + continue; + } + format!( + "expression #{} = {} {} {}", + id.index(), + lhs.index(), + if op == Op::Add { "+" } else { "-" }, + rhs.index() + ) + } + CoverageKind::Unreachable => { + if !INCLUDE_COVERAGE_STATEMENTS { + continue; + } + String::from("unreachable") + } + }, + _ => format!("{:?}", statement), + }; + let source_range = source_range_no_file(tcx, &statement.source_info.span); + text.push(format!( + "\n{}{}: {}: {}", + TOOLTIP_INDENT, + source_range, + statement_kind_name(statement), + statement_string + )); + } + let term = data.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("") + } +} + +/// Convert the Span into its file name, start line and column, and end line and column +fn make_code_region<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> CodeRegion { + let source_map = tcx.sess.source_map(); + let start = source_map.lookup_char_pos(span.lo()); + let end = if span.hi() == span.lo() { + start.clone() + } else { + let end = source_map.lookup_char_pos(span.hi()); + debug_assert_eq!( + start.file.name, + end.file.name, + "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!", + span.lo(), + start, + span.hi(), + end + ); + end + }; + match &start.file.name { + FileName::Real(RealFileName::Named(path)) => CodeRegion { + file_name: Symbol::intern(&path.to_string_lossy()), + 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, + }, + _ => bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name), + } +} + +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { + let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); + let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + tcx.hir().body(fn_body_id) +} + +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() +} + +pub struct ShortCircuitPreorder< + 'a, + 'tcx, + F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>, +> { + body: &'a mir::Body<'tcx>, + visited: BitSet, + worklist: Vec, + filtered_successors: F, +} + +impl<'a, 'tcx, F: Fn(&'tcx TerminatorKind<'tcx>) -> mir::Successors<'tcx>> + ShortCircuitPreorder<'a, 'tcx, F> +{ + pub fn new( + body: &'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 TerminatorKind<'tcx>) -> mir::Successors<'tcx>> 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)(&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 --git a/src/librustc_mir/transform/match_branches.rs b/compiler/rustc_mir/src/transform/match_branches.rs similarity index 95% rename from src/librustc_mir/transform/match_branches.rs rename to compiler/rustc_mir/src/transform/match_branches.rs index c1d574d6ef..70ae5474a4 100644 --- a/src/librustc_mir/transform/match_branches.rs +++ b/compiler/rustc_mir/src/transform/match_branches.rs @@ -38,6 +38,13 @@ pub struct MatchBranchSimplification; impl<'tcx> MirPass<'tcx> for MatchBranchSimplification { fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, body: &mut Body<'tcx>) { + // FIXME: This optimization can result in unsoundness, because it introduces + // additional uses of a place holding the discriminant value without ensuring that + // it is valid to do so. + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { + return; + } + let param_env = tcx.param_env(src.def_id()); let bbs = body.basic_blocks_mut(); 'outer: for bb_idx in bbs.indices() { diff --git a/src/librustc_mir/transform/mod.rs b/compiler/rustc_mir/src/transform/mod.rs similarity index 95% rename from src/librustc_mir/transform/mod.rs rename to compiler/rustc_mir/src/transform/mod.rs index 0db5bd662c..67193814a4 100644 --- a/src/librustc_mir/transform/mod.rs +++ b/compiler/rustc_mir/src/transform/mod.rs @@ -16,6 +16,7 @@ use std::borrow::Cow; 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; @@ -23,22 +24,26 @@ pub mod cleanup_post_borrowck; pub mod const_prop; pub mod copy_prop; pub mod deaggregator; +pub mod dest_prop; pub mod dump_mir; +pub mod early_otherwise_branch; pub mod elaborate_drops; pub mod generator; pub mod inline; pub mod instcombine; pub mod instrument_coverage; pub mod match_branches; +pub mod multiple_return_terminators; pub mod no_landing_pads; pub mod nrvo; pub mod promote_consts; -pub mod qualify_min_const_fn; pub mod remove_noop_landing_pads; +pub mod remove_unneeded_drops; pub mod required_consts; pub mod rustc_peek; 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; @@ -306,6 +311,7 @@ fn mir_const<'tcx>( &[&[ // MIR-level lints. &check_packed_ref::CheckPackedRef, + &check_const_item_mutation::CheckConstItemMutation, // What we need to do constant evaluation. &simplify::SimplifyCfg::new("initial"), &rustc_peek::SanityCheck, @@ -326,7 +332,11 @@ fn mir_promoted( // 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 _ = if let Some(param_did) = def.const_param_did { + tcx.mir_abstract_const_of_const_arg((def.did, param_did)) + } else { + tcx.mir_abstract_const(def.did.to_def_id()) + }; let mut body = tcx.mir_const(def).steal(); let mut required_consts = Vec::new(); @@ -452,19 +462,25 @@ fn run_optimization_passes<'tcx>( // The main optimizations that we do on MIR. let optimizations: &[&dyn MirPass<'tcx>] = &[ - &instcombine::InstCombine, + &remove_unneeded_drops::RemoveUnneededDrops, &match_branches::MatchBranchSimplification, + // inst combine is after MatchBranchSimplification to clean up Ne(_1, false) + &multiple_return_terminators::MultipleReturnTerminators, + &instcombine::InstCombine, &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, ©_prop::CopyPropagation, &simplify_branches::SimplifyBranches::new("after-copy-prop"), &remove_noop_landing_pads::RemoveNoopLandingPads, - &simplify::SimplifyCfg::new("after-remove-noop-landing-pads"), &simplify::SimplifyCfg::new("final"), &nrvo::RenameReturnPlace, &simplify::SimplifyLocals, + &multiple_return_terminators::MultipleReturnTerminators, ]; // Optimizations to run even if mir optimizations have been disabled. diff --git a/compiler/rustc_mir/src/transform/multiple_return_terminators.rs b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs new file mode 100644 index 0000000000..3c9c8454f7 --- /dev/null +++ b/compiler/rustc_mir/src/transform/multiple_return_terminators.rs @@ -0,0 +1,38 @@ +//! This pass removes jumps to basic blocks containing only a return, and replaces them with a +//! return instead. + +use crate::transform::{simplify, MirPass, MirSource}; +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>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { + if tcx.sess.opts.debugging_opts.mir_opt_level < 3 { + return; + } + + // find basic blocks with no statement and a return terminator + let mut bbs_simple_returns = BitSet::new_empty(body.basic_blocks().len()); + 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 let TerminatorKind::Goto { target } = bb.terminator().kind { + if bbs_simple_returns.contains(target) { + bb.terminator_mut().kind = TerminatorKind::Return; + } + } + } + + simplify::remove_dead_blocks(body) + } +} diff --git a/src/librustc_mir/transform/no_landing_pads.rs b/compiler/rustc_mir/src/transform/no_landing_pads.rs similarity index 100% rename from src/librustc_mir/transform/no_landing_pads.rs rename to compiler/rustc_mir/src/transform/no_landing_pads.rs diff --git a/src/librustc_mir/transform/nrvo.rs b/compiler/rustc_mir/src/transform/nrvo.rs similarity index 93% rename from src/librustc_mir/transform/nrvo.rs rename to compiler/rustc_mir/src/transform/nrvo.rs index 1f3d7bb7cc..1ffb5a87c4 100644 --- a/src/librustc_mir/transform/nrvo.rs +++ b/compiler/rustc_mir/src/transform/nrvo.rs @@ -1,6 +1,6 @@ use rustc_hir::Mutability; use rustc_index::bit_set::HybridBitSet; -use rustc_middle::mir::visit::{MutVisitor, PlaceContext, Visitor}; +use rustc_middle::mir::visit::{MutVisitor, NonUseContext, PlaceContext, Visitor}; use rustc_middle::mir::{self, BasicBlock, Local, Location}; use rustc_middle::ty::TyCtxt; @@ -36,6 +36,12 @@ impl<'tcx> MirPass<'tcx> for RenameReturnPlace { return; } + if tcx.sess.opts.debugging_opts.mir_opt_level >= 2 { + // The `DestinationPropagation` pass runs at level 2, so this pass is redundant (and + // fails some asserts). + return; + } + let returned_local = match local_eligible_for_nrvo(body) { Some(l) => l, None => { @@ -196,9 +202,10 @@ impl MutVisitor<'tcx> for RenameToReturnPlace<'tcx> { self.super_terminator(terminator, loc); } - fn visit_local(&mut self, l: &mut Local, _: PlaceContext, _: Location) { - assert_ne!(*l, mir::RETURN_PLACE); - if *l == self.to_rename { + 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; } } diff --git a/src/librustc_mir/transform/promote_consts.rs b/compiler/rustc_mir/src/transform/promote_consts.rs similarity index 93% rename from src/librustc_mir/transform/promote_consts.rs rename to compiler/rustc_mir/src/transform/promote_consts.rs index b2dda1caa5..89f7531b3a 100644 --- a/src/librustc_mir/transform/promote_consts.rs +++ b/compiler/rustc_mir/src/transform/promote_consts.rs @@ -92,7 +92,7 @@ pub enum TempState { impl TempState { pub fn is_promotable(&self) -> bool { debug!("is_promotable: self={:?}", self); - if let TempState::Defined { .. } = *self { true } else { false } + matches!(self, TempState::Defined { .. } ) } } @@ -137,7 +137,7 @@ fn args_required_const(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { LitKind::Int(a, _) => { ret.push(a as usize); } - _ => return None, + _ => bug!("invalid arg index"), } } Some(ret) @@ -220,7 +220,7 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { match terminator.kind { TerminatorKind::Call { ref func, .. } => { - if let ty::FnDef(def_id, _) = func.ty(self.ccx.body, self.ccx.tcx).kind { + if let ty::FnDef(def_id, _) = *func.ty(self.ccx.body, self.ccx.tcx).kind() { let fn_sig = self.ccx.tcx.fn_sig(def_id); if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = fn_sig.abi() { let name = self.ccx.tcx.item_name(def_id); @@ -242,11 +242,8 @@ impl<'tcx> Visitor<'tcx> for Collector<'_, 'tcx> { } TerminatorKind::InlineAsm { ref operands, .. } => { for (index, op) in operands.iter().enumerate() { - match op { - InlineAsmOperand::Const { .. } => { - self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) - } - _ => {} + if let InlineAsmOperand::Const { .. } = op { + self.candidates.push(Candidate::InlineAsm { bb: location.block, index }) } } } @@ -297,6 +294,17 @@ impl std::ops::Deref for Validator<'a, 'tcx> { struct Unpromotable; impl<'tcx> Validator<'_, 'tcx> { + /// Determines if this code could be executed at runtime and thus is subject to codegen. + /// That means even unused constants need to be evaluated. + /// + /// `const_kind` should not be used in this file other than through this method! + fn maybe_runtime(&self) -> bool { + match self.const_kind { + None | Some(hir::ConstContext::ConstFn) => true, + Some(hir::ConstContext::Static(_) | hir::ConstContext::Const) => false, + } + } + fn validate_candidate(&self, candidate: Candidate) -> Result<(), Unpromotable> { match candidate { Candidate::Ref(loc) => { @@ -363,20 +371,10 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] - // is allowed right now, and only in functions. - if self.const_kind - == Some(hir::ConstContext::Static(hir::Mutability::Mut)) - { - // Inside a `static mut`, &mut [...] is also allowed. - match ty.kind { - ty::Array(..) | ty::Slice(_) => {} - _ => return Err(Unpromotable), - } - } else if let ty::Array(_, len) = ty.kind { - // FIXME(eddyb) the `self.is_non_const_fn` condition - // seems unnecessary, given that this is merely a ZST. + // is allowed right now. + if let ty::Array(_, len) = ty.kind() { match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) if self.const_kind.is_none() => {} + Some(0) => {} _ => return Err(Unpromotable), } } else { @@ -503,9 +501,10 @@ impl<'tcx> Validator<'_, 'tcx> { match place { PlaceRef { local, projection: [] } => self.validate_local(local), PlaceRef { local, projection: [proj_base @ .., elem] } => { + // Validate topmost projection, then recurse. match *elem { ProjectionElem::Deref => { - let mut not_promotable = true; + let mut promotable = false; // 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 @@ -520,6 +519,9 @@ impl<'tcx> Validator<'_, 'tcx> { }) = 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 { // The `is_empty` predicate is introduced to exclude the case // where the projection operations are [ .field, * ]. @@ -532,13 +534,13 @@ impl<'tcx> Validator<'_, 'tcx> { if proj_base.is_empty() && !self.tcx.is_thread_local_static(did) { - not_promotable = false; + promotable = true; } } } } } - if not_promotable { + if !promotable { return Err(Unpromotable); } } @@ -553,7 +555,7 @@ impl<'tcx> Validator<'_, 'tcx> { } ProjectionElem::Field(..) => { - if self.const_kind.is_none() { + if self.maybe_runtime() { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; if let Some(def) = base_ty.ty_adt_def() { @@ -581,6 +583,10 @@ impl<'tcx> Validator<'_, 'tcx> { 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); @@ -599,21 +605,18 @@ impl<'tcx> Validator<'_, 'tcx> { fn validate_rvalue(&self, rvalue: &Rvalue<'tcx>) -> Result<(), Unpromotable> { match *rvalue { - Rvalue::Cast(CastKind::Misc, ref operand, cast_ty) if self.const_kind.is_none() => { + 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"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - // in normal functions, mark such casts as not promotable - return Err(Unpromotable); - } - _ => {} + 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); } } - Rvalue::BinaryOp(op, ref lhs, _) if self.const_kind.is_none() => { - if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind { + Rvalue::BinaryOp(op, ref lhs, _) => { + if let ty::RawPtr(_) | ty::FnPtr(..) = lhs.ty(self.body, self.tcx).kind() { assert!( op == BinOp::Eq || op == BinOp::Ne @@ -624,13 +627,14 @@ impl<'tcx> Validator<'_, 'tcx> { || op == BinOp::Offset ); - // raw pointer operations are not allowed inside promoteds + // raw pointer operations are not allowed inside consts and thus not promotable return Err(Unpromotable); } } Rvalue::NullaryOp(NullOp::Box, _) => return Err(Unpromotable), + // FIXME(RalfJung): the rest is *implicitly considered promotable*... that seems dangerous. _ => {} } @@ -652,11 +656,11 @@ impl<'tcx> Validator<'_, 'tcx> { } Rvalue::AddressOf(_, place) => { - // Raw reborrows can come from reference to pointer coercions, - // so are allowed. + // We accept `&raw *`, i.e., raw reborrows -- creating a raw pointer is + // no problem, only using it is. if let [proj_base @ .., ProjectionElem::Deref] = place.projection.as_ref() { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.kind { + if let ty::Ref(..) = base_ty.kind() { return self.validate_place(PlaceRef { local: place.local, projection: proj_base, @@ -672,18 +676,10 @@ impl<'tcx> Validator<'_, 'tcx> { // In theory, any zero-sized value could be borrowed // mutably without consequences. However, only &mut [] - // is allowed right now, and only in functions. - if self.const_kind == Some(hir::ConstContext::Static(hir::Mutability::Mut)) { - // Inside a `static mut`, &mut [...] is also allowed. - match ty.kind { - ty::Array(..) | ty::Slice(_) => {} - _ => return Err(Unpromotable), - } - } else if let ty::Array(_, len) = ty.kind { - // FIXME(eddyb): We only return `Unpromotable` for `&mut []` inside a - // const context which seems unnecessary given that this is merely a ZST. + // is allowed right now. + if let ty::Array(_, len) = ty.kind() { match len.try_eval_usize(self.tcx, self.param_env) { - Some(0) if self.const_kind.is_none() => {} + Some(0) => {} _ => return Err(Unpromotable), } } else { @@ -695,7 +691,7 @@ impl<'tcx> Validator<'_, 'tcx> { let mut place = place.as_ref(); if let [proj_base @ .., ProjectionElem::Deref] = &place.projection { let base_ty = Place::ty_from(place.local, proj_base, self.body, self.tcx).ty; - if let ty::Ref(..) = base_ty.kind { + if let ty::Ref(..) = base_ty.kind() { place = PlaceRef { local: place.local, projection: proj_base }; } } @@ -748,8 +744,8 @@ impl<'tcx> Validator<'_, 'tcx> { ) -> Result<(), Unpromotable> { let fn_ty = callee.ty(self.body, self.tcx); - if !self.explicit && self.const_kind.is_none() { - if let ty::FnDef(def_id, _) = fn_ty.kind { + if !self.explicit && self.maybe_runtime() { + 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) { @@ -758,7 +754,7 @@ impl<'tcx> Validator<'_, 'tcx> { } } - let is_const_fn = match fn_ty.kind { + 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() diff --git a/src/librustc_mir/transform/remove_noop_landing_pads.rs b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs similarity index 94% rename from src/librustc_mir/transform/remove_noop_landing_pads.rs rename to compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs index 0bad1e5037..4079f0110e 100644 --- a/src/librustc_mir/transform/remove_noop_landing_pads.rs +++ b/compiler/rustc_mir/src/transform/remove_noop_landing_pads.rs @@ -102,6 +102,16 @@ impl RemoveNoopLandingPads { 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); @@ -110,15 +120,6 @@ impl RemoveNoopLandingPads { } } - if let Some(unwind) = body[bb].terminator_mut().unwind_mut() { - if *unwind == Some(resume_block) { - debug!(" removing noop landing pad"); - jumps_folded -= 1; - landing_pads_removed += 1; - *unwind = None; - } - } - 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); diff --git a/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs new file mode 100644 index 0000000000..b9f29786c6 --- /dev/null +++ b/compiler/rustc_mir/src/transform/remove_unneeded_drops.rs @@ -0,0 +1,58 @@ +//! This pass replaces a drop of a type that does not need dropping, with a goto + +use crate::transform::{MirPass, MirSource}; +use rustc_hir::def_id::LocalDefId; +use rustc_middle::mir::visit::Visitor; +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>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("Running RemoveUnneededDrops on {:?}", source); + let mut opt_finder = RemoveUnneededDropsOptimizationFinder { + tcx, + body, + optimizations: vec![], + def_id: source.def_id().expect_local(), + }; + opt_finder.visit_body(body); + let should_simplify = !opt_finder.optimizations.is_empty(); + for (loc, target) in opt_finder.optimizations { + let terminator = body.basic_blocks_mut()[loc.block].terminator_mut(); + debug!("SUCCESS: replacing `drop` with goto({:?})", target); + terminator.kind = TerminatorKind::Goto { target }; + } + + // if we applied optimizations, we potentially have some cfg to cleanup to + // make it easier for further passes + if should_simplify { + simplify_cfg(body); + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location) { + match terminator.kind { + TerminatorKind::Drop { place, target, .. } => { + let ty = place.ty(self.body, self.tcx); + let needs_drop = ty.ty.needs_drop(self.tcx, self.tcx.param_env(self.def_id)); + if !needs_drop { + self.optimizations.push((location, target)); + } + } + _ => {} + } + self.super_terminator(terminator, location); + } +} +pub struct RemoveUnneededDropsOptimizationFinder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a Body<'tcx>, + optimizations: Vec<(Location, BasicBlock)>, + def_id: LocalDefId, +} diff --git a/src/librustc_mir/transform/required_consts.rs b/compiler/rustc_mir/src/transform/required_consts.rs similarity index 100% rename from src/librustc_mir/transform/required_consts.rs rename to compiler/rustc_mir/src/transform/required_consts.rs diff --git a/src/librustc_mir/transform/rustc_peek.rs b/compiler/rustc_mir/src/transform/rustc_peek.rs similarity index 95% rename from src/librustc_mir/transform/rustc_peek.rs rename to compiler/rustc_mir/src/transform/rustc_peek.rs index 00d269a4af..015af44b80 100644 --- a/src/librustc_mir/transform/rustc_peek.rs +++ b/compiler/rustc_mir/src/transform/rustc_peek.rs @@ -1,4 +1,6 @@ -use rustc_ast as ast; +use std::borrow::Borrow; + +use rustc_ast::ast; use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::spec::abi::Abi; @@ -16,7 +18,7 @@ use crate::dataflow::impls::{ use crate::dataflow::move_paths::{HasMoveData, MoveData}; use crate::dataflow::move_paths::{LookupResult, MovePathIndex}; use crate::dataflow::MoveDataParamEnv; -use crate::dataflow::{Analysis, Results, ResultsCursor}; +use crate::dataflow::{Analysis, JoinSemiLattice, Results, ResultsCursor}; pub struct SanityCheck; @@ -180,7 +182,7 @@ enum PeekCallKind { impl PeekCallKind { fn from_arg_ty(arg: Ty<'_>) -> Self { - match arg.kind { + match arg.kind() { ty::Ref(_, _, _) => PeekCallKind::ByRef, _ => PeekCallKind::ByVal, } @@ -205,7 +207,7 @@ impl PeekCall { if let mir::TerminatorKind::Call { func: Operand::Constant(func), args, .. } = &terminator.kind { - if let ty::FnDef(def_id, substs) = func.literal.ty.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 { @@ -248,25 +250,26 @@ pub trait RustcPeekAt<'tcx>: Analysis<'tcx> { &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &BitSet, + flow_state: &Self::Domain, call: PeekCall, ); } -impl<'tcx, A> RustcPeekAt<'tcx> for A +impl<'tcx, A, D> RustcPeekAt<'tcx> for A where - A: Analysis<'tcx, Idx = MovePathIndex> + HasMoveData<'tcx>, + A: Analysis<'tcx, Domain = D> + HasMoveData<'tcx>, + D: JoinSemiLattice + Clone + Borrow>, { fn peek_at( &self, tcx: TyCtxt<'tcx>, place: mir::Place<'tcx>, - flow_state: &BitSet, + 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.contains(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"); diff --git a/src/librustc_mir/transform/simplify.rs b/compiler/rustc_mir/src/transform/simplify.rs similarity index 99% rename from src/librustc_mir/transform/simplify.rs rename to compiler/rustc_mir/src/transform/simplify.rs index d8995e92ab..3fc8e6d4b0 100644 --- a/src/librustc_mir/transform/simplify.rs +++ b/compiler/rustc_mir/src/transform/simplify.rs @@ -281,8 +281,7 @@ impl<'a, 'tcx> CfgSimplifier<'a, 'tcx> { fn strip_nops(&mut self) { for blk in self.basic_blocks.iter_mut() { - blk.statements - .retain(|stmt| if let StatementKind::Nop = stmt.kind { false } else { true }) + blk.statements.retain(|stmt| !matches!(stmt.kind, StatementKind::Nop)) } } } diff --git a/src/librustc_mir/transform/simplify_branches.rs b/compiler/rustc_mir/src/transform/simplify_branches.rs similarity index 100% rename from src/librustc_mir/transform/simplify_branches.rs rename to compiler/rustc_mir/src/transform/simplify_branches.rs diff --git a/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs new file mode 100644 index 0000000000..9b460c9ecb --- /dev/null +++ b/compiler/rustc_mir/src/transform/simplify_comparison_integral.rs @@ -0,0 +1,227 @@ +use super::{MirPass, MirSource}; +use rustc_middle::{ + mir::{ + interpret::Scalar, BasicBlock, BinOp, Body, Operand, Place, Rvalue, Statement, + StatementKind, 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, _: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { + trace!("Running SimplifyComparisonIntegral on {:?}", 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![]; + 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]; + // We only use the bits for the untyped, not length checked `values` field. Thus we are + // not using any of the convenience wrappers here and directly access the bits. + let new_value = match opt.branch_value_scalar { + Scalar::Raw { data, .. } => data, + Scalar::Ptr(_) => continue, + }; + const FALSE: u128 = 0; + let mut new_targets = opt.targets.clone(); + let first_is_false_target = opt.values[0] == 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.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.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 box (_, rhs) = bb.statements[opt.bin_op_stmt_idx].kind.as_assign_mut().unwrap(); + + use Operand::*; + match rhs { + Rvalue::BinaryOp(_, ref mut left @ Move(_), Constant(_)) => { + *left = Copy(opt.to_switch_on); + } + Rvalue::BinaryOp(_, 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.iter() { + storage_deads_to_insert.push(( + *bb_idx, + Statement { + source_info: terminator.source_info, + kind: StatementKind::StorageDead(opt.to_switch_on.local), + }, + )); + } + } + + let terminator = bb.terminator_mut(); + + terminator.kind = TerminatorKind::SwitchInt { + discr: Operand::Move(opt.to_switch_on), + switch_ty: opt.branch_value_ty, + values: vec![new_value].into(), + targets: new_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, values, targets, place_switched_on_moved) = match &bb + .terminator() + .kind + { + rustc_middle::mir::TerminatorKind::SwitchInt { + discr, values, targets, .. + } => Some((discr.place()?, values, 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), 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, + values: values.clone().into_owned(), + 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.val.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 values used in the switch target. This needs to be replaced with the branch_value + values: Vec, + /// Current targets used in the switch + targets: Vec, +} diff --git a/src/librustc_mir/transform/simplify_try.rs b/compiler/rustc_mir/src/transform/simplify_try.rs similarity index 91% rename from src/librustc_mir/transform/simplify_try.rs rename to compiler/rustc_mir/src/transform/simplify_try.rs index 9a80f0818c..45fa3b700c 100644 --- a/src/librustc_mir/transform/simplify_try.rs +++ b/compiler/rustc_mir/src/transform/simplify_try.rs @@ -16,7 +16,7 @@ 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::{Enumerate, Peekable}; +use std::iter::{once, Enumerate, Peekable}; use std::slice::Iter; /// Simplifies arms of form `Variant(x) => Variant(x)` to just a move. @@ -230,8 +230,8 @@ fn get_arm_identity_info<'a, 'tcx>( } } } - - nop_stmts.sort(); + // 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 @@ -368,7 +368,8 @@ fn optimization_applies<'tcx>( impl<'tcx> MirPass<'tcx> for SimplifyArmIdentity { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - if tcx.sess.opts.debugging_opts.mir_opt_level < 2 { + // FIXME(77359): This optimization can result in unsoundness. + if !tcx.sess.opts.debugging_opts.unsound_mir_opts { return; } @@ -555,6 +556,12 @@ struct SimplifyBranchSameOptimization { 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>, @@ -566,8 +573,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { .basic_blocks() .iter_enumerated() .filter_map(|(bb_idx, bb)| { - let (discr_switched_on, targets) = match &bb.terminator().kind { - TerminatorKind::SwitchInt { targets, discr, .. } => (discr, targets), + let (discr_switched_on, targets_and_values) = match &bb.terminator().kind { + TerminatorKind::SwitchInt { targets, discr, values, .. } => { + // if values.len() == targets.len() - 1, we need to include None where no value is present + // such that the zip does not throw away targets. If no `otherwise` case is in targets, the zip will simply throw away the added None + let values_extended = values.iter().map(|x|Some(*x)).chain(once(None)); + let targets_and_values:Vec<_> = targets.iter().zip(values_extended) + .map(|(target, value)| SwitchTargetAndValue{target:*target, value}) + .collect(); + assert_eq!(targets.len(), targets_and_values.len()); + (discr, targets_and_values)}, _ => return None, }; @@ -591,9 +606,9 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }, }; - let mut iter_bbs_reachable = targets + let mut iter_bbs_reachable = targets_and_values .iter() - .map(|idx| (*idx, &self.body.basic_blocks()[*idx])) + .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 @@ -607,17 +622,17 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { }) .peekable(); - let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(targets[0]); + let bb_first = iter_bbs_reachable.peek().map(|(idx, _)| *idx).unwrap_or(&targets_and_values[0]); let mut all_successors_equivalent = StatementEquality::TrivialEqual; // All successor basic blocks must be equal or contain statements that are pairwise considered equal. - for ((bb_l_idx,bb_l), (bb_r_idx,bb_r)) in iter_bbs_reachable.tuple_windows() { + 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, bb_l_idx, &r, bb_r_idx, self.tcx.sess.opts.debugging_opts.mir_opt_level); + 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 @@ -639,7 +654,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { // statements are trivially equal, so just take first trace!("Statements are trivially equal"); Some(SimplifyBranchSameOptimization { - bb_to_goto: bb_first, + bb_to_goto: bb_first.target, bb_to_opt_terminator: bb_idx, }) } @@ -674,17 +689,16 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { &self, adt_matched_on: Place<'tcx>, x: &Statement<'tcx>, - x_bb_idx: BasicBlock, + x_target_and_value: &SwitchTargetAndValue, y: &Statement<'tcx>, - y_bb_idx: BasicBlock, - mir_opt_level: usize, + y_target_and_value: &SwitchTargetAndValue, ) -> StatementEquality { let helper = |rhs: &Rvalue<'tcx>, - place: &Box>, + place: &Place<'tcx>, variant_index: &VariantIdx, side_to_choose| { let place_type = place.ty(self.body, self.tcx).ty; - let adt = match place_type.kind { + let adt = match *place_type.kind() { ty::Adt(adt, _) if adt.is_enum() => adt, _ => return StatementEquality::NotEqual, }; @@ -696,13 +710,7 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { match rhs { Rvalue::Use(operand) if operand.place() == Some(adt_matched_on) => { - // FIXME(76803): This logic is currently broken because it does not take into - // account the current discriminant value. - if mir_opt_level > 2 { - StatementEquality::ConsideredEqual(side_to_choose) - } else { - StatementEquality::NotEqual - } + StatementEquality::ConsideredEqual(side_to_choose) } _ => { trace!( @@ -722,16 +730,20 @@ impl<'a, 'tcx> SimplifyBranchSameOptimizationFinder<'a, 'tcx> { ( StatementKind::Assign(box (_, rhs)), StatementKind::SetDiscriminant { place, variant_index }, - ) => { + ) + // we need to make sure that the switch value that targets the bb with SetDiscriminant (y), is the same as the variant index + if Some(variant_index.index() as u128) == y_target_and_value.value => { // choose basic block of x, as that has the assign - helper(rhs, place, variant_index, x_bb_idx) + helper(rhs, place, variant_index, x_target_and_value.target) } ( StatementKind::SetDiscriminant { place, variant_index }, StatementKind::Assign(box (_, rhs)), - ) => { + ) + // we need to make sure that the switch value that targets the bb with SetDiscriminant (x), is the same as the variant index + if Some(variant_index.index() as u128) == x_target_and_value.value => { // choose basic block of y, as that has the assign - helper(rhs, place, variant_index, y_bb_idx) + helper(rhs, place, variant_index, y_target_and_value.target) } _ => { trace!("NO: statements `{:?}` and `{:?}` not considered equal", x, y); diff --git a/src/librustc_mir/transform/uninhabited_enum_branching.rs b/compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs similarity index 100% rename from src/librustc_mir/transform/uninhabited_enum_branching.rs rename to compiler/rustc_mir/src/transform/uninhabited_enum_branching.rs diff --git a/src/librustc_mir/transform/unreachable_prop.rs b/compiler/rustc_mir/src/transform/unreachable_prop.rs similarity index 100% rename from src/librustc_mir/transform/unreachable_prop.rs rename to compiler/rustc_mir/src/transform/unreachable_prop.rs diff --git a/src/librustc_mir/transform/validate.rs b/compiler/rustc_mir/src/transform/validate.rs similarity index 78% rename from src/librustc_mir/transform/validate.rs rename to compiler/rustc_mir/src/transform/validate.rs index d7c9ecd065..94018a39b1 100644 --- a/src/librustc_mir/transform/validate.rs +++ b/compiler/rustc_mir/src/transform/validate.rs @@ -1,18 +1,18 @@ //! 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, MirSource}; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::{ - mir::{ - AggregateKind, BasicBlock, Body, Location, MirPhase, Operand, Rvalue, Statement, - StatementKind, Terminator, TerminatorKind, - }, - ty::{ - self, - relate::{Relate, RelateResult, TypeRelation}, - ParamEnv, Ty, TyCtxt, - }, +use rustc_infer::infer::TyCtxtInferExt; +use rustc_middle::mir::visit::{PlaceContext, Visitor}; +use rustc_middle::mir::{ + AggregateKind, BasicBlock, Body, BorrowKind, Local, Location, MirPhase, Operand, Rvalue, + Statement, StatementKind, Terminator, TerminatorKind, VarDebugInfo, }; +use rustc_middle::ty::fold::BottomUpFolder; +use rustc_middle::ty::{self, ParamEnv, Ty, TyCtxt, TypeFoldable}; #[derive(Copy, Clone, Debug)] enum EdgeKind { @@ -33,9 +33,18 @@ pub struct Validator { impl<'tcx> MirPass<'tcx> for Validator { fn run_pass(&self, tcx: TyCtxt<'tcx>, source: MirSource<'tcx>, body: &mut Body<'tcx>) { - let param_env = tcx.param_env(source.def_id()); + let def_id = source.def_id(); + let param_env = tcx.param_env(def_id); let mir_phase = self.mir_phase; - TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase }.visit_body(body); + + let always_live_locals = AlwaysLiveLocals::new(body); + let storage_liveness = MaybeStorageLive::new(always_live_locals) + .into_engine(tcx, body, def_id) + .iterate_to_fixpoint() + .into_results_cursor(body); + + TypeChecker { when: &self.when, source, body, tcx, param_env, mir_phase, storage_liveness } + .visit_body(body); } } @@ -56,79 +65,24 @@ pub fn equal_up_to_regions( return true; } - struct LifetimeIgnoreRelation<'tcx> { - tcx: TyCtxt<'tcx>, - param_env: ty::ParamEnv<'tcx>, - } - - impl TypeRelation<'tcx> for LifetimeIgnoreRelation<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn param_env(&self) -> ty::ParamEnv<'tcx> { - self.param_env - } - - fn tag(&self) -> &'static str { - "librustc_mir::transform::validate" - } - - fn a_is_expected(&self) -> bool { - true - } - - fn relate_with_variance>( - &mut self, - _: ty::Variance, - a: T, - b: T, - ) -> RelateResult<'tcx, T> { - // Ignore variance, require types to be exactly the same. - self.relate(a, b) - } - - fn tys(&mut self, a: Ty<'tcx>, b: Ty<'tcx>) -> RelateResult<'tcx, Ty<'tcx>> { - if a == b { - // Short-circuit. - return Ok(a); - } - ty::relate::super_relate_tys(self, a, b) - } - - fn regions( - &mut self, - a: ty::Region<'tcx>, - _b: ty::Region<'tcx>, - ) -> RelateResult<'tcx, ty::Region<'tcx>> { - // Ignore regions. - Ok(a) - } - - fn consts( - &mut self, - a: &'tcx ty::Const<'tcx>, - b: &'tcx ty::Const<'tcx>, - ) -> RelateResult<'tcx, &'tcx ty::Const<'tcx>> { - ty::relate::super_relate_consts(self, a, b) - } - - fn binders( - &mut self, - a: ty::Binder, - b: ty::Binder, - ) -> RelateResult<'tcx, ty::Binder> - where - T: Relate<'tcx>, - { - self.relate(a.skip_binder(), b.skip_binder())?; - Ok(a) - } - } - - // Instantiate and run relation. - let mut relator: LifetimeIgnoreRelation<'tcx> = LifetimeIgnoreRelation { tcx: tcx, param_env }; - relator.relate(src, dest).is_ok() + // 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, + // We just erase all late-bound lifetimes, but this is not fully correct (FIXME): + // lifetimes in invariant positions could matter (e.g. through associated types). + // We rely on the fact that layout was confirmed to be equal above. + 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> { @@ -138,6 +92,7 @@ struct TypeChecker<'a, 'tcx> { tcx: TyCtxt<'tcx>, param_env: ParamEnv<'tcx>, mir_phase: MirPhase, + storage_liveness: ResultsCursor<'a, 'tcx, MaybeStorageLive>, } impl<'a, 'tcx> TypeChecker<'a, 'tcx> { @@ -210,6 +165,22 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { + fn visit_local(&mut self, local: &Local, context: PlaceContext, location: Location) { + if 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_var_debug_info(&mut self, _var_debug_info: &VarDebugInfo<'tcx>) { + // Debuginfo can contain field projections, which count as a use of the base local. Skip + // debuginfo so that we avoid the storage liveness assertion in that case. + } + fn visit_operand(&mut self, operand: &Operand<'tcx>, location: Location) { // `Operand::Copy` is only supposed to be used with `Copy` types. if let Operand::Copy(place) = operand { @@ -274,9 +245,33 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { ) } } + 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", + ); + } + } _ => {} } } @@ -331,7 +326,7 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> { } TerminatorKind::Call { func, destination, cleanup, .. } => { let func_ty = func.ty(&self.body.local_decls, self.tcx); - match func_ty.kind { + match func_ty.kind() { ty::FnPtr(..) | ty::FnDef(..) => {} _ => self.fail( location, diff --git a/src/librustc_mir/util/aggregate.rs b/compiler/rustc_mir/src/util/aggregate.rs similarity index 91% rename from src/librustc_mir/util/aggregate.rs rename to compiler/rustc_mir/src/util/aggregate.rs index 1a22eee3a0..130409b9df 100644 --- a/src/librustc_mir/util/aggregate.rs +++ b/compiler/rustc_mir/src/util/aggregate.rs @@ -3,6 +3,7 @@ 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. @@ -52,14 +53,11 @@ pub fn expand_aggregate<'tcx>( .enumerate() .map(move |(i, (op, ty))| { let lhs_field = if let AggregateKind::Array(_) = kind { - // FIXME(eddyb) `offset` should be u64. - let offset = i as u32; - assert_eq!(offset as usize, i); + let offset = u64::try_from(i).unwrap(); tcx.mk_place_elem( lhs, ProjectionElem::ConstantIndex { offset, - // FIXME(eddyb) `min_length` doesn't appear to be used. min_length: offset + 1, from_end: false, }, diff --git a/src/librustc_mir/util/alignment.rs b/compiler/rustc_mir/src/util/alignment.rs similarity index 98% rename from src/librustc_mir/util/alignment.rs rename to compiler/rustc_mir/src/util/alignment.rs index 202e5e27f1..a0728a6a63 100644 --- a/src/librustc_mir/util/alignment.rs +++ b/compiler/rustc_mir/src/util/alignment.rs @@ -47,7 +47,7 @@ where ProjectionElem::Deref => break, ProjectionElem::Field(..) => { let ty = Place::ty_from(place.local, proj_base, local_decls, tcx).ty; - match ty.kind { + match ty.kind() { ty::Adt(def, _) if def.repr.packed() => return true, _ => {} } diff --git a/src/librustc_mir/util/borrowck_errors.rs b/compiler/rustc_mir/src/util/borrowck_errors.rs similarity index 99% rename from src/librustc_mir/util/borrowck_errors.rs rename to compiler/rustc_mir/src/util/borrowck_errors.rs index f8bb7e7a85..83bf7584f2 100644 --- a/src/librustc_mir/util/borrowck_errors.rs +++ b/compiler/rustc_mir/src/util/borrowck_errors.rs @@ -287,7 +287,7 @@ impl<'cx, 'tcx> crate::borrow_check::MirBorrowckCtxt<'cx, 'tcx> { ty: Ty<'_>, is_index: Option, ) -> DiagnosticBuilder<'cx> { - let type_name = match (&ty.kind, is_index) { + 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"), diff --git a/src/librustc_mir/util/collect_writes.rs b/compiler/rustc_mir/src/util/collect_writes.rs similarity index 100% rename from src/librustc_mir/util/collect_writes.rs rename to compiler/rustc_mir/src/util/collect_writes.rs diff --git a/src/librustc_mir/util/def_use.rs b/compiler/rustc_mir/src/util/def_use.rs similarity index 100% rename from src/librustc_mir/util/def_use.rs rename to compiler/rustc_mir/src/util/def_use.rs diff --git a/src/librustc_mir/util/elaborate_drops.rs b/compiler/rustc_mir/src/util/elaborate_drops.rs similarity index 99% rename from src/librustc_mir/util/elaborate_drops.rs rename to compiler/rustc_mir/src/util/elaborate_drops.rs index 5d84a008d4..bf0a6be9a7 100644 --- a/src/librustc_mir/util/elaborate_drops.rs +++ b/compiler/rustc_mir/src/util/elaborate_drops.rs @@ -10,8 +10,6 @@ use rustc_middle::ty::{self, Ty, TyCtxt}; use rustc_target::abi::VariantIdx; use std::fmt; -use std::convert::TryInto; - /// The value of an inserted drop flag. #[derive(Debug, PartialEq, Eq, Copy, Clone)] pub enum DropFlagState { @@ -150,7 +148,7 @@ pub trait DropElaborator<'a, 'tcx>: fmt::Debug { /// 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: u32, size: u32) -> Option; + fn array_subpath(&self, path: Self::Path, index: u64, size: u64) -> Option; } #[derive(Debug)] @@ -744,9 +742,6 @@ where let tcx = self.tcx(); if let Some(size) = opt_size { - let size: u32 = size.try_into().unwrap_or_else(|_| { - bug!("move out check isn't implemented for array sizes bigger than u32::MAX"); - }); let fields: Vec<(Place<'tcx>, Option)> = (0..size) .map(|i| { ( @@ -863,7 +858,7 @@ where /// 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 { + match ty.kind() { ty::Closure(_, substs) => { let tys: Vec<_> = substs.as_closure().upvar_tys().collect(); self.open_drop_for_tuple(&tys) diff --git a/compiler/rustc_mir/src/util/find_self_call.rs b/compiler/rustc_mir/src/util/find_self_call.rs new file mode 100644 index 0000000000..5b146eeb87 --- /dev/null +++ b/compiler/rustc_mir/src/util/find_self_call.rs @@ -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` prameter 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: ty::Const { ty, .. }, .. }) = func { + if let ty::FnDef(def_id, substs) = *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 --git a/src/librustc_mir/util/graphviz.rs b/compiler/rustc_mir/src/util/graphviz.rs similarity index 85% rename from src/librustc_mir/util/graphviz.rs rename to compiler/rustc_mir/src/util/graphviz.rs index 50193c4a0d..4511962d68 100644 --- a/src/librustc_mir/util/graphviz.rs +++ b/compiler/rustc_mir/src/util/graphviz.rs @@ -55,16 +55,28 @@ where writeln!(w, "{} {}Mir_{} {{", kind, cluster, def_name)?; // Global graph properties - writeln!(w, r#" graph [fontname="monospace"];"#)?; - writeln!(w, r#" node [fontname="monospace"];"#)?; - writeln!(w, r#" edge [fontname="monospace"];"#)?; + 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""#); + 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 write_graph_label(tcx, def_id, body, w)?; // Nodes for (block, _) in body.basic_blocks().iter_enumerated() { - write_node(def_id, block, body, w)?; + write_node(def_id, block, body, dark_mode, w)?; } // Edges @@ -84,6 +96,7 @@ where pub fn write_node_label( block: BasicBlock, body: &Body<'_>, + dark_mode: bool, w: &mut W, num_cols: u32, init: INIT, @@ -100,8 +113,9 @@ where // Basic block number at the top. write!( w, - r#"{blk}"#, - attrs = r#"bgcolor="gray" align="center""#, + r#"{blk}"#, + bgcolor = if dark_mode { "dimgray" } else { "gray" }, + attrs = r#"align="center""#, colspan = num_cols, blk = block.index() )?; @@ -134,11 +148,12 @@ fn write_node( def_id: DefId, block: BasicBlock, body: &Body<'_>, + dark_mode: bool, w: &mut W, ) -> io::Result<()> { // Start a new node with the label to follow, in one of DOT's pseudo-HTML tables. write!(w, r#" {} [shape="none", label=<"#, node(def_id, block))?; - write_node_label(block, body, w, 1, |_| Ok(()), |_| Ok(()))?; + write_node_label(block, body, dark_mode, w, 1, |_| Ok(()), |_| Ok(()))?; // Close the node label and the node itself. writeln!(w, ">];") } diff --git a/src/librustc_mir/util/mod.rs b/compiler/rustc_mir/src/util/mod.rs similarity index 84% rename from src/librustc_mir/util/mod.rs rename to compiler/rustc_mir/src/util/mod.rs index 8bbe207c07..699f3bcf01 100644 --- a/src/librustc_mir/util/mod.rs +++ b/compiler/rustc_mir/src/util/mod.rs @@ -7,11 +7,14 @@ pub mod storage; mod alignment; pub mod collect_writes; +mod find_self_call; 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::graphviz::write_node_label as write_graphviz_node_label; pub use self::graphviz::{graphviz_safe_def_name, write_mir_graphviz}; pub use self::pretty::{dump_enabled, dump_mir, write_mir_pretty, PassWhere}; diff --git a/src/librustc_mir/util/patch.rs b/compiler/rustc_mir/src/util/patch.rs similarity index 100% rename from src/librustc_mir/util/patch.rs rename to compiler/rustc_mir/src/util/patch.rs diff --git a/src/librustc_mir/util/pretty.rs b/compiler/rustc_mir/src/util/pretty.rs similarity index 98% rename from src/librustc_mir/util/pretty.rs rename to compiler/rustc_mir/src/util/pretty.rs index 2a9cbc7fc0..49c644a20b 100644 --- a/src/librustc_mir/util/pretty.rs +++ b/compiler/rustc_mir/src/util/pretty.rs @@ -6,6 +6,7 @@ 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; @@ -147,6 +148,16 @@ fn dump_matched_mir_node<'tcx, F>( write_mir_fn_graphviz(tcx, source.def_id(), body, false, &mut file)?; }; } + + if let Some(spanview) = tcx.sess.opts.debugging_opts.dump_mir_spanview { + let _: io::Result<()> = try { + let mut file = + create_dump_file(tcx, "html", pass_num, pass_name, disambiguator, source)?; + if source.def_id().is_local() { + write_mir_fn_spanview(tcx, source.def_id(), body, spanview, &mut file)?; + } + }; + } } /// Returns the path to the filename where we should dump a given MIR. @@ -387,7 +398,7 @@ 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; - match literal.ty.kind { + match literal.ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char => {} // Unit type ty::Tuple(tys) if tys.is_empty() => {} @@ -405,7 +416,7 @@ impl Visitor<'tcx> for ExtraComments<'tcx> { fn visit_const(&mut self, constant: &&'tcx ty::Const<'tcx>, _: Location) { self.super_const(constant); let ty::Const { ty, val, .. } = constant; - match ty.kind { + match ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Bool | ty::Char | ty::Float(_) => {} // Unit type ty::Tuple(tys) if tys.is_empty() => {} @@ -503,7 +514,7 @@ fn write_scope_tree( write!(indented_decl, " as {:?}", user_ty).unwrap(); } } - indented_decl.push_str(";"); + indented_decl.push(';'); let local_name = if local == RETURN_PLACE { " return place".to_string() } else { String::new() }; @@ -620,14 +631,11 @@ pub fn write_allocations<'tcx>( None => write!(w, " (deallocated)")?, Some(GlobalAlloc::Function(inst)) => write!(w, " (fn: {})", inst)?, Some(GlobalAlloc::Static(did)) if !tcx.is_foreign_item(did) => { - match tcx.const_eval_poly(did) { - Ok(ConstValue::ByRef { alloc, .. }) => { + match tcx.eval_static_initializer(did) { + Ok(alloc) => { write!(w, " (static: {}, ", tcx.def_path_str(did))?; write_allocation_track_relocs(w, alloc)?; } - Ok(_) => { - span_bug!(tcx.def_span(did), " static item without `ByRef` initializer") - } Err(_) => write!( w, " (static: {}, error during initializer evaluation)", diff --git a/compiler/rustc_mir/src/util/spanview.rs b/compiler/rustc_mir/src/util/spanview.rs new file mode 100644 index 0000000000..fe33fffe0e --- /dev/null +++ b/compiler/rustc_mir/src/util/spanview.rs @@ -0,0 +1,672 @@ +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#" + + + coverage_of_if_else - Code Regions + + +"#; + +const FOOTER: &str = r#" + +"#; + +/// Metadata to highlight the span of a MIR BasicBlock, Statement, or Terminator. +pub struct SpanViewable { + 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>, + def_id: DefId, + body: &Body<'tcx>, + spanview: MirSpanview, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let body_span = hir_body(tcx, def_id).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_spanview_document(tcx, def_id, span_viewables, 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_spanview_document<'tcx, W>( + tcx: TyCtxt<'tcx>, + def_id: DefId, + mut span_viewables: Vec, + w: &mut W, +) -> io::Result<()> +where + W: Write, +{ + let fn_span = fn_span(tcx, def_id); + let mut from_pos = fn_span.lo(); + let end_pos = fn_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!( + "fn_span source is:\n{}{}", + indent_to_initial_start_col, + source_map.span_to_snippet(fn_span).expect("function should have printable source") + ); + writeln!(w, "{}", HEADER)?; + 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 (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; + alt = !alt; + } + } + if from_pos < end_pos { + write_coverage_gap(tcx, from_pos, end_pos, w)?; + } + write!(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", + 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 { 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 { 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 { 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 (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; + 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_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); + let body_span = hir_body(tcx, def_id).value.span; + debug_assert_eq!(fn_decl_span.ctxt(), body_span.ctxt()); + fn_decl_span.to(body_span) +} + +fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { + let hir_node = tcx.hir().get_if_local(def_id).expect("expected DefId is local"); + let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); + tcx.hir().body(fn_body_id) +} + +fn escape_html(s: &str) -> String { + s.replace("&", "&").replace("<", "<").replace(">", ">") +} + +fn escape_attr(s: &str) -> String { + s.replace("&", "&") + .replace("\"", """) + .replace("'", "'") + .replace("<", "<") + .replace(">", ">") +} diff --git a/src/librustc_mir/util/storage.rs b/compiler/rustc_mir/src/util/storage.rs similarity index 100% rename from src/librustc_mir/util/storage.rs rename to compiler/rustc_mir/src/util/storage.rs diff --git a/compiler/rustc_mir_build/Cargo.toml b/compiler/rustc_mir_build/Cargo.toml new file mode 100644 index 0000000000..2dd894a67a --- /dev/null +++ b/compiler/rustc_mir_build/Cargo.toml @@ -0,0 +1,27 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_mir_build" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_apfloat = { path = "../rustc_apfloat" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_infer = { path = "../rustc_infer" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } +rustc_ast = { path = "../rustc_ast" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir_build/build/block.rs b/compiler/rustc_mir_build/src/build/block.rs similarity index 98% rename from src/librustc_mir_build/build/block.rs rename to compiler/rustc_mir_build/src/build/block.rs index d1cbf209b0..beaf12b1db 100644 --- a/src/librustc_mir_build/build/block.rs +++ b/compiler/rustc_mir_build/src/build/block.rs @@ -96,8 +96,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { ); } StmtKind::Let { remainder_scope, init_scope, pattern, initializer, lint_level } => { - let ignores_expr_result = - if let PatKind::Wild = *pattern.kind { true } else { false }; + let ignores_expr_result = matches!(*pattern.kind, PatKind::Wild); this.block_context.push(BlockFrame::Statement { ignores_expr_result }); // Enter the remainder scope, i.e., the bindings' destruction scope. diff --git a/src/librustc_mir_build/build/cfg.rs b/compiler/rustc_mir_build/src/build/cfg.rs similarity index 100% rename from src/librustc_mir_build/build/cfg.rs rename to compiler/rustc_mir_build/src/build/cfg.rs diff --git a/src/librustc_mir_build/build/expr/as_constant.rs b/compiler/rustc_mir_build/src/build/expr/as_constant.rs similarity index 95% rename from src/librustc_mir_build/build/expr/as_constant.rs rename to compiler/rustc_mir_build/src/build/expr/as_constant.rs index 982aefcf60..244a70f83b 100644 --- a/src/librustc_mir_build/build/expr/as_constant.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_constant.rs @@ -21,7 +21,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let Expr { ty, temp_lifetime: _, span, kind } = expr; match kind { ExprKind::Scope { region_scope: _, lint_level: _, value } => this.as_constant(value), - ExprKind::Literal { literal, user_ty } => { + ExprKind::Literal { literal, user_ty, const_id: _ } => { let user_ty = user_ty.map(|user_ty| { this.canonical_user_type_annotations.push(CanonicalUserTypeAnnotation { span, diff --git a/src/librustc_mir_build/build/expr/as_operand.rs b/compiler/rustc_mir_build/src/build/expr/as_operand.rs similarity index 100% rename from src/librustc_mir_build/build/expr/as_operand.rs rename to compiler/rustc_mir_build/src/build/expr/as_operand.rs diff --git a/src/librustc_mir_build/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs similarity index 99% rename from src/librustc_mir_build/build/expr/as_place.rs rename to compiler/rustc_mir_build/src/build/expr/as_place.rs index 1e3e104c2b..39dbb6dd3f 100644 --- a/src/librustc_mir_build/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -367,7 +367,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let tcx = self.hir.tcx(); let place_ty = Place::ty_from(base_place.local, &base_place.projection, &self.local_decls, tcx); - if let ty::Slice(_) = place_ty.ty.kind { + if let ty::Slice(_) = place_ty.ty.kind() { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to // unsized values, we only need to ensure that none of the @@ -406,7 +406,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { &self.local_decls, tcx, ); - match index_ty.ty.kind { + match index_ty.ty.kind() { // The previous index expression has already // done any index expressions needed here. ty::Slice(_) => break, diff --git a/src/librustc_mir_build/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs similarity index 100% rename from src/librustc_mir_build/build/expr/as_rvalue.rs rename to compiler/rustc_mir_build/src/build/expr/as_rvalue.rs diff --git a/src/librustc_mir_build/build/expr/as_temp.rs b/compiler/rustc_mir_build/src/build/expr/as_temp.rs similarity index 96% rename from src/librustc_mir_build/build/expr/as_temp.rs rename to compiler/rustc_mir_build/src/build/expr/as_temp.rs index a9cc0cc2f2..9984b527ff 100644 --- a/src/librustc_mir_build/build/expr/as_temp.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_temp.rs @@ -76,6 +76,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { local_decl.local_info = Some(box LocalInfo::StaticRef { def_id, is_thread_local: true }); } + ExprKind::Literal { const_id: Some(def_id), .. } => { + local_decl.local_info = Some(box LocalInfo::ConstRef { def_id }); + } _ => {} } this.local_decls.push(local_decl) diff --git a/src/librustc_mir_build/build/expr/category.rs b/compiler/rustc_mir_build/src/build/expr/category.rs similarity index 100% rename from src/librustc_mir_build/build/expr/category.rs rename to compiler/rustc_mir_build/src/build/expr/category.rs diff --git a/src/librustc_mir_build/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs similarity index 99% rename from src/librustc_mir_build/build/expr/into.rs rename to compiler/rustc_mir_build/src/build/expr/into.rs index 3d623abfa6..319fae5009 100644 --- a/src/librustc_mir_build/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -168,7 +168,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { exit_block.unit() } ExprKind::Call { ty, fun, args, from_hir_call, fn_span } => { - let intrinsic = match ty.kind { + let intrinsic = match *ty.kind() { ty::FnDef(def_id, _) => { let f = ty.fn_sig(this.hir.tcx()); if f.abi() == Abi::RustIntrinsic || f.abi() == Abi::PlatformIntrinsic { diff --git a/src/librustc_mir_build/build/expr/mod.rs b/compiler/rustc_mir_build/src/build/expr/mod.rs similarity index 100% rename from src/librustc_mir_build/build/expr/mod.rs rename to compiler/rustc_mir_build/src/build/expr/mod.rs diff --git a/src/librustc_mir_build/build/expr/stmt.rs b/compiler/rustc_mir_build/src/build/expr/stmt.rs similarity index 100% rename from src/librustc_mir_build/build/expr/stmt.rs rename to compiler/rustc_mir_build/src/build/expr/stmt.rs diff --git a/src/librustc_mir_build/build/into.rs b/compiler/rustc_mir_build/src/build/into.rs similarity index 100% rename from src/librustc_mir_build/build/into.rs rename to compiler/rustc_mir_build/src/build/into.rs diff --git a/src/librustc_mir_build/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs similarity index 99% rename from src/librustc_mir_build/build/matches/mod.rs rename to compiler/rustc_mir_build/src/build/matches/mod.rs index 5f87cb364b..a9b8a6181d 100644 --- a/src/librustc_mir_build/build/matches/mod.rs +++ b/compiler/rustc_mir_build/src/build/matches/mod.rs @@ -321,7 +321,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let target_block = self.cfg.start_new_block(); let mut schedule_drops = true; // We keep a stack of all of the bindings and type asciptions - // from the the parent candidates that we visit, that also need to + // from the parent candidates that we visit, that also need to // be bound for each candidate. traverse_candidate( candidate, @@ -609,8 +609,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Array { ref prefix, ref slice, ref suffix } | PatKind::Slice { ref prefix, ref slice, ref suffix } => { - let from = u32::try_from(prefix.len()).unwrap(); - let to = u32::try_from(suffix.len()).unwrap(); + let from = u64::try_from(prefix.len()).unwrap(); + let to = u64::try_from(suffix.len()).unwrap(); for subpattern in prefix { self.visit_primary_bindings(subpattern, pattern_user_ty.clone().index(), f); } @@ -1793,7 +1793,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .flat_map(|(bindings, _)| bindings) .chain(&candidate.bindings) .filter(|binding| { - if let BindingMode::ByValue = binding.binding_mode { true } else { false } + matches!(binding.binding_mode, BindingMode::ByValue ) }); // Read all of the by reference bindings to ensure that the // place they refer to can't be modified by the guard. diff --git a/src/librustc_mir_build/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs similarity index 99% rename from src/librustc_mir_build/build/matches/simplify.rs rename to compiler/rustc_mir_build/src/build/matches/simplify.rs index e584aeb922..a28a181e93 100644 --- a/src/librustc_mir_build/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -154,7 +154,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } PatKind::Range(PatRange { lo, hi, end }) => { - let (range, bias) = match lo.ty.kind { + let (range, bias) = match *lo.ty.kind() { ty::Char => { (Some(('\u{0000}' as u128, '\u{10FFFF}' as u128, Size::from_bits(32))), 0) } diff --git a/src/librustc_mir_build/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs similarity index 99% rename from src/librustc_mir_build/build/matches/test.rs rename to compiler/rustc_mir_build/src/build/matches/test.rs index c4a87a554a..d81c3b68f4 100644 --- a/src/librustc_mir_build/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -215,7 +215,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { TestKind::SwitchInt { switch_ty, ref options } => { let target_blocks = make_target_blocks(self); - let terminator = if switch_ty.kind == ty::Bool { + let terminator = if *switch_ty.kind() == ty::Bool { assert!(!options.is_empty() && options.len() <= 2); if let [first_bb, second_bb] = *target_blocks { let (true_bb, false_bb) = match options[0] { @@ -368,8 +368,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // We want to do this even when the scrutinee is a reference to an // array, so we can call `<[u8]>::eq` rather than having to find an // `<[u8; N]>::eq`. - let unsize = |ty: Ty<'tcx>| match ty.kind { - ty::Ref(region, rty, _) => match rty.kind { + let unsize = |ty: Ty<'tcx>| match ty.kind() { + ty::Ref(region, rty, _) => match rty.kind() { ty::Array(inner_ty, n) => Some((region, inner_ty, n)), _ => None, }, @@ -407,7 +407,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } } - let deref_ty = match ty.kind { + let deref_ty = match *ty.kind() { ty::Ref(_, deref_ty, _) => deref_ty, _ => bug!("non_scalar_compare called on non-reference type: {}", ty), }; diff --git a/src/librustc_mir_build/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs similarity index 91% rename from src/librustc_mir_build/build/matches/util.rs rename to compiler/rustc_mir_build/src/build/matches/util.rs index 605396c5eb..4ef88c25ca 100644 --- a/src/librustc_mir_build/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -31,26 +31,26 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { suffix: &'pat [Pat<'tcx>], ) { let tcx = self.hir.tcx(); - let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind { + let (min_length, exact_size) = match place.ty(&self.local_decls, tcx).ty.kind() { ty::Array(_, length) => { - (length.eval_usize(tcx, self.hir.param_env).try_into().unwrap(), true) + (length.eval_usize(tcx, self.hir.param_env), true) } _ => ((prefix.len() + suffix.len()).try_into().unwrap(), false), }; match_pairs.extend(prefix.iter().enumerate().map(|(idx, subpattern)| { let elem = - ProjectionElem::ConstantIndex { offset: idx as u32, min_length, from_end: false }; + ProjectionElem::ConstantIndex { offset: idx as u64, min_length, from_end: false }; let place = tcx.mk_place_elem(*place, elem); MatchPair::new(place, subpattern) })); if let Some(subslice_pat) = opt_slice { - let suffix_len = suffix.len() as u32; + let suffix_len = suffix.len() as u64; let subslice = tcx.mk_place_elem( *place, ProjectionElem::Subslice { - from: prefix.len() as u32, + from: prefix.len() as u64, to: if exact_size { min_length - suffix_len } else { suffix_len }, from_end: !exact_size, }, @@ -59,7 +59,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } match_pairs.extend(suffix.iter().rev().enumerate().map(|(idx, subpattern)| { - let end_offset = (idx + 1) as u32; + let end_offset = (idx + 1) as u64; let elem = ProjectionElem::ConstantIndex { offset: if exact_size { min_length - end_offset } else { end_offset }, min_length, diff --git a/src/librustc_mir_build/build/misc.rs b/compiler/rustc_mir_build/src/build/misc.rs similarity index 100% rename from src/librustc_mir_build/build/misc.rs rename to compiler/rustc_mir_build/src/build/misc.rs diff --git a/src/librustc_mir_build/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs similarity index 99% rename from src/librustc_mir_build/build/mod.rs rename to compiler/rustc_mir_build/src/build/mod.rs index 71026f5096..aa96ae8759 100644 --- a/src/librustc_mir_build/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -96,7 +96,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ let body = tcx.hir().body(body_id); let ty = tcx.type_of(fn_def_id); let mut abi = fn_sig.abi; - let implicit_argument = match ty.kind { + let implicit_argument = match ty.kind() { ty::Closure(..) => { // HACK(eddyb) Avoid having RustCall on closures, // as it adds unnecessary (and wrong) auto-tupling. @@ -159,7 +159,7 @@ fn mir_build(tcx: TyCtxt<'_>, def: ty::WithOptConstParam) -> Body<'_ let (yield_ty, return_ty) = if body.generator_kind.is_some() { let gen_ty = tcx.typeck_body(body_id).node_type(id); - let gen_sig = match gen_ty.kind { + let gen_sig = match gen_ty.kind() { ty::Generator(_, gen_substs, ..) => gen_substs.as_generator().sig(), _ => span_bug!(tcx.hir().span(id), "generator w/o generator type: {:?}", ty), }; @@ -228,7 +228,7 @@ fn liberated_closure_env_ty( ) -> Ty<'_> { let closure_ty = tcx.typeck_body(body_id).node_type(closure_expr_id); - let (closure_def_id, closure_substs) = match closure_ty.kind { + let (closure_def_id, closure_substs) = match *closure_ty.kind() { ty::Closure(closure_def_id, closure_substs) => (closure_def_id, closure_substs), _ => bug!("closure expr does not have closure type: {:?}", closure_ty), }; @@ -840,11 +840,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let closure_env_arg = Local::new(1); let mut closure_env_projs = vec![]; let mut closure_ty = self.local_decls[closure_env_arg].ty; - if let ty::Ref(_, ty, _) = closure_ty.kind { + if let ty::Ref(_, ty, _) = closure_ty.kind() { closure_env_projs.push(ProjectionElem::Deref); closure_ty = ty; } - let upvar_substs = match closure_ty.kind { + let upvar_substs = match closure_ty.kind() { ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs), ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs), _ => span_bug!(self.fn_span, "upvars with non-closure env ty {:?}", closure_ty), @@ -876,7 +876,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let mut projs = closure_env_projs.clone(); projs.push(ProjectionElem::Field(Field::new(i), ty)); match capture { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} ty::UpvarCapture::ByRef(..) => { projs.push(ProjectionElem::Deref); } diff --git a/src/librustc_mir_build/build/scope.rs b/compiler/rustc_mir_build/src/build/scope.rs similarity index 100% rename from src/librustc_mir_build/build/scope.rs rename to compiler/rustc_mir_build/src/build/scope.rs diff --git a/src/librustc_mir_build/lib.rs b/compiler/rustc_mir_build/src/lib.rs similarity index 92% rename from src/librustc_mir_build/lib.rs rename to compiler/rustc_mir_build/src/lib.rs index 313bb979a5..714041ad4e 100644 --- a/src/librustc_mir_build/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -1,11 +1,12 @@ //! Construction of MIR from HIR. //! //! This crate also contains the match exhaustiveness and usefulness checking. - +#![feature(array_windows)] #![feature(box_patterns)] #![feature(box_syntax)] #![feature(const_fn)] #![feature(const_panic)] +#![feature(control_flow_enum)] #![feature(crate_visibility_modifier)] #![feature(bool_to_option)] #![feature(or_patterns)] diff --git a/src/librustc_mir_build/lints.rs b/compiler/rustc_mir_build/src/lints.rs similarity index 97% rename from src/librustc_mir_build/lints.rs rename to compiler/rustc_mir_build/src/lints.rs index fd2d5a4abd..a8d7c612a8 100644 --- a/src/librustc_mir_build/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -70,7 +70,7 @@ impl<'mir, 'tcx> Search<'mir, 'tcx> { let param_env = tcx.param_env(def_id); let func_ty = func.ty(body, tcx); - if let ty::FnDef(fn_def_id, substs) = func_ty.kind { + if let ty::FnDef(fn_def_id, substs) = *func_ty.kind() { let (call_fn_id, call_substs) = if let Ok(Some(instance)) = Instance::resolve(tcx, param_env, fn_def_id, substs) { (instance.def_id(), instance.substs) @@ -117,7 +117,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { // A diverging InlineAsm is treated as non-recursing TerminatorKind::InlineAsm { destination, .. } => { if destination.is_some() { - ControlFlow::Continue + ControlFlow::CONTINUE } else { ControlFlow::Break(NonRecursive) } @@ -131,7 +131,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { | TerminatorKind::FalseEdge { .. } | TerminatorKind::FalseUnwind { .. } | TerminatorKind::Goto { .. } - | TerminatorKind::SwitchInt { .. } => ControlFlow::Continue, + | TerminatorKind::SwitchInt { .. } => ControlFlow::CONTINUE, } } @@ -144,7 +144,7 @@ impl<'mir, 'tcx> TriColorVisitor<&'mir Body<'tcx>> for Search<'mir, 'tcx> { } } - ControlFlow::Continue + ControlFlow::CONTINUE } fn ignore_edge(&mut self, bb: BasicBlock, target: BasicBlock) -> bool { diff --git a/src/librustc_mir_build/thir/constant.rs b/compiler/rustc_mir_build/src/thir/constant.rs similarity index 89% rename from src/librustc_mir_build/thir/constant.rs rename to compiler/rustc_mir_build/src/thir/constant.rs index dd5515d39b..a7bb2864da 100644 --- a/src/librustc_mir_build/thir/constant.rs +++ b/compiler/rustc_mir_build/src/thir/constant.rs @@ -2,7 +2,7 @@ use rustc_ast as ast; use rustc_middle::mir::interpret::{ truncate, Allocation, ConstValue, LitToConstError, LitToConstInput, Scalar, }; -use rustc_middle::ty::{self, ParamEnv, TyCtxt, TyS}; +use rustc_middle::ty::{self, ParamEnv, TyCtxt}; use rustc_span::symbol::Symbol; use rustc_target::abi::Size; @@ -21,19 +21,21 @@ crate fn lit_to_const<'tcx>( Ok(ConstValue::Scalar(Scalar::from_uint(result, width))) }; - let lit = match (lit, &ty.kind) { - (ast::LitKind::Str(s, _), ty::Ref(_, TyS { kind: ty::Str, .. }, _)) => { + let lit = match (lit, &ty.kind()) { + (ast::LitKind::Str(s, _), ty::Ref(_, inner_ty, _)) if inner_ty.is_str() => { let s = s.as_str(); let allocation = Allocation::from_byte_aligned_bytes(s.as_bytes()); let allocation = tcx.intern_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: s.len() } } - (ast::LitKind::ByteStr(data), ty::Ref(_, TyS { kind: ty::Slice(_), .. }, _)) => { + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) + if matches!(inner_ty.kind(), ty::Slice(_)) => + { let allocation = Allocation::from_byte_aligned_bytes(data as &Vec); let allocation = tcx.intern_const_alloc(allocation); ConstValue::Slice { data: allocation, start: 0, end: data.len() } } - (ast::LitKind::ByteStr(data), ty::Ref(_, TyS { kind: ty::Array(_, _), .. }, _)) => { + (ast::LitKind::ByteStr(data), ty::Ref(_, inner_ty, _)) if inner_ty.is_array() => { let id = tcx.allocate_bytes(data); ConstValue::Scalar(Scalar::Ptr(id.into())) } diff --git a/src/librustc_mir_build/thir/cx/block.rs b/compiler/rustc_mir_build/src/thir/cx/block.rs similarity index 100% rename from src/librustc_mir_build/thir/cx/block.rs rename to compiler/rustc_mir_build/src/thir/cx/block.rs diff --git a/src/librustc_mir_build/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs similarity index 96% rename from src/librustc_mir_build/thir/cx/expr.rs rename to compiler/rustc_mir_build/src/thir/cx/expr.rs index c51c3bcf56..13e69474cf 100644 --- a/src/librustc_mir_build/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -117,7 +117,14 @@ fn apply_adjustment<'a, 'tcx>( }, }; - overloaded_place(cx, hir_expr, adjustment.target, Some(call), vec![expr.to_ref()]) + overloaded_place( + cx, + hir_expr, + adjustment.target, + Some(call), + vec![expr.to_ref()], + deref.span, + ) } Adjust::Borrow(AutoBorrow::Ref(_, m)) => { ExprKind::Borrow { borrow_kind: m.to_borrow_kind(), arg: expr.to_ref() } @@ -247,6 +254,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Lit(ref lit) => ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, false), user_ty: None, + const_id: None, }, hir::ExprKind::Binary(op, ref lhs, ref rhs) => { @@ -276,7 +284,14 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Index(ref lhs, ref index) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![lhs.to_ref(), index.to_ref()]) + overloaded_place( + cx, + expr, + expr_ty, + None, + vec![lhs.to_ref(), index.to_ref()], + expr.span, + ) } else { ExprKind::Index { lhs: lhs.to_ref(), index: index.to_ref() } } @@ -284,7 +299,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Unary(hir::UnOp::UnDeref, ref arg) => { if cx.typeck_results().is_method_call(expr) { - overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()]) + overloaded_place(cx, expr, expr_ty, None, vec![arg.to_ref()], expr.span) } else { ExprKind::Deref { arg: arg.to_ref() } } @@ -306,6 +321,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( ExprKind::Literal { literal: cx.const_eval_literal(&lit.node, expr_ty, lit.span, true), user_ty: None, + const_id: None, } } else { ExprKind::Unary { op: UnOp::Neg, arg: arg.to_ref() } @@ -313,7 +329,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( } } - hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind { + hir::ExprKind::Struct(ref qpath, ref fields, ref base) => match expr_ty.kind() { ty::Adt(adt, substs) => match adt.adt_kind() { AdtKind::Struct | AdtKind::Union => { let user_provided_types = cx.typeck_results().user_provided_types(); @@ -363,7 +379,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( hir::ExprKind::Closure(..) => { let closure_ty = cx.typeck_results().expr_ty(expr); - let (def_id, substs, movability) = match closure_ty.kind { + let (def_id, substs, movability) = match *closure_ty.kind() { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs), None), ty::Generator(def_id, substs, movability) => { (def_id, UpvarSubsts::Generator(substs), Some(movability)) @@ -447,6 +463,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, ty), user_ty, + const_id: None, }, } .to_ref(), @@ -473,6 +490,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, ty), user_ty: None, + const_id: None, }, } .to_ref(), @@ -585,7 +603,7 @@ fn make_mirror_unadjusted<'a, 'tcx>( temp_lifetime, ty: var_ty, span: expr.span, - kind: ExprKind::Literal { literal, user_ty: None }, + kind: ExprKind::Literal { literal, user_ty: None, const_id: None }, } .to_ref() }; @@ -714,7 +732,11 @@ fn method_callee<'a, 'tcx>( temp_lifetime, ty, span, - kind: ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx(), ty), user_ty }, + kind: ExprKind::Literal { + literal: ty::Const::zero_sized(cx.tcx(), ty), + user_ty, + const_id: None, + }, } } @@ -777,6 +799,7 @@ fn convert_path_expr<'a, 'tcx>( ExprKind::Literal { literal: ty::Const::zero_sized(cx.tcx, cx.typeck_results().node_type(expr.hir_id)), user_ty, + const_id: None, } } @@ -794,6 +817,7 @@ fn convert_path_expr<'a, 'tcx>( .tcx .mk_const(ty::Const { val, ty: cx.typeck_results().node_type(expr.hir_id) }), user_ty: None, + const_id: Some(def_id), } } @@ -810,6 +834,7 @@ fn convert_path_expr<'a, 'tcx>( ty: cx.typeck_results().node_type(expr.hir_id), }), user_ty, + const_id: Some(def_id), } } @@ -818,7 +843,7 @@ fn convert_path_expr<'a, 'tcx>( let user_provided_type = user_provided_types.get(expr.hir_id).copied(); debug!("convert_path_expr: user_provided_type={:?}", user_provided_type); let ty = cx.typeck_results().node_type(expr.hir_id); - match ty.kind { + match ty.kind() { // A unit struct/variant which is used as a value. // We return a completely different ExprKind here to account for this special case. ty::Adt(adt_def, substs) => ExprKind::Adt { @@ -899,7 +924,7 @@ fn convert_var<'tcx>( }); let region = cx.tcx.mk_region(region); - let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind { + let self_expr = if let ty::Closure(_, closure_substs) = closure_ty.kind() { match cx.infcx.closure_kind(closure_substs).unwrap() { ty::ClosureKind::Fn => { let ref_closure_ty = cx.tcx.mk_ref( @@ -959,7 +984,7 @@ fn convert_var<'tcx>( // ...but the upvar might be an `&T` or `&mut T` capture, at which // point we need an implicit deref match cx.typeck_results().upvar_capture(upvar_id) { - ty::UpvarCapture::ByValue => field_kind, + ty::UpvarCapture::ByValue(_) => field_kind, ty::UpvarCapture::ByRef(borrow) => ExprKind::Deref { arg: Expr { temp_lifetime, @@ -1014,6 +1039,7 @@ fn overloaded_place<'a, 'tcx>( place_ty: Ty<'tcx>, overloaded_callee: Option<(DefId, SubstsRef<'tcx>)>, args: Vec>, + span: Span, ) -> ExprKind<'tcx> { // For an overloaded *x or x[y] expression of type T, the method // call returns an &T and we must add the deref so that the types @@ -1027,26 +1053,26 @@ fn overloaded_place<'a, 'tcx>( // Reconstruct the output assuming it's a reference with the // same region and mutability as the receiver. This holds for // `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`. - let (region, mutbl) = match recv_ty.kind { + let (region, mutbl) = match *recv_ty.kind() { ty::Ref(region, _, mutbl) => (region, mutbl), - _ => span_bug!(expr.span, "overloaded_place: receiver is not a reference"), + _ => span_bug!(span, "overloaded_place: receiver is not a reference"), }; let ref_ty = cx.tcx.mk_ref(region, ty::TypeAndMut { ty: place_ty, mutbl }); // construct the complete expression `foo()` for the overloaded call, // which will yield the &T type let temp_lifetime = cx.region_scope_tree.temporary_scope(expr.hir_id.local_id); - let fun = method_callee(cx, expr, expr.span, overloaded_callee); + let fun = method_callee(cx, expr, span, overloaded_callee); let ref_expr = Expr { temp_lifetime, ty: ref_ty, - span: expr.span, + span, kind: ExprKind::Call { ty: fun.ty, fun: fun.to_ref(), args, from_hir_call: false, - fn_span: expr.span, + fn_span: span, }, }; @@ -1074,7 +1100,7 @@ fn capture_upvar<'tcx>( kind: convert_var(cx, closure_expr, var_hir_id), }; match upvar_capture { - ty::UpvarCapture::ByValue => captured_var.to_ref(), + ty::UpvarCapture::ByValue(_) => captured_var.to_ref(), ty::UpvarCapture::ByRef(upvar_borrow) => { let borrow_kind = match upvar_borrow.kind { ty::BorrowKind::ImmBorrow => BorrowKind::Shared, diff --git a/src/librustc_mir_build/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs similarity index 100% rename from src/librustc_mir_build/thir/cx/mod.rs rename to compiler/rustc_mir_build/src/thir/cx/mod.rs diff --git a/src/librustc_mir_build/thir/cx/to_ref.rs b/compiler/rustc_mir_build/src/thir/cx/to_ref.rs similarity index 100% rename from src/librustc_mir_build/thir/cx/to_ref.rs rename to compiler/rustc_mir_build/src/thir/cx/to_ref.rs diff --git a/src/librustc_mir_build/thir/mod.rs b/compiler/rustc_mir_build/src/thir/mod.rs similarity index 98% rename from src/librustc_mir_build/thir/mod.rs rename to compiler/rustc_mir_build/src/thir/mod.rs index 2837bfa040..4d57fd5c64 100644 --- a/src/librustc_mir_build/thir/mod.rs +++ b/compiler/rustc_mir_build/src/thir/mod.rs @@ -273,6 +273,10 @@ crate enum ExprKind<'tcx> { Literal { literal: &'tcx Const<'tcx>, user_ty: Option>>, + /// The `DefId` of the `const` item this literal + /// was produced from, if this is not a user-written + /// literal value. + const_id: Option, }, /// A literal containing the address of a `static`. /// diff --git a/src/librustc_mir_build/thir/pattern/_match.rs b/compiler/rustc_mir_build/src/thir/pattern/_match.rs similarity index 90% rename from src/librustc_mir_build/thir/pattern/_match.rs rename to compiler/rustc_mir_build/src/thir/pattern/_match.rs index 3202f7d1b1..04de9a7a58 100644 --- a/src/librustc_mir_build/thir/pattern/_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/_match.rs @@ -139,10 +139,10 @@ //! //! It is computed as follows. We look at the pattern `p_1` on top of the stack, //! and we have three cases: -//! 1.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. -//! 1.2. `p_1 = _`. We return the rest of the stack: +//! 2.1. `p_1 = c(r_1, .., r_a)`. We discard the current stack and return nothing. +//! 2.2. `p_1 = _`. We return the rest of the stack: //! p_2, .., p_n -//! 1.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting +//! 2.3. `p_1 = r_1 | r_2`. We expand the OR-pattern and then recurse on each resulting //! stack. //! D((r_1, p_2, .., p_n)) //! D((r_2, p_2, .., p_n)) @@ -276,7 +276,7 @@ use self::Usefulness::*; use self::WitnessPreference::*; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::FxHashSet; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_index::vec::Idx; use super::{compare_const_vals, PatternFoldable, PatternFolder}; @@ -327,7 +327,7 @@ impl<'tcx> LiteralExpander<'tcx> { crty: Ty<'tcx>, ) -> ConstValue<'tcx> { debug!("fold_const_value_deref {:?} {:?} {:?}", val, rty, crty); - match (val, &crty.kind, &rty.kind) { + match (val, &crty.kind(), &rty.kind()) { // the easy case, deref a reference (ConstValue::Scalar(p), x, y) if x == y => { match p { @@ -368,41 +368,35 @@ impl<'tcx> LiteralExpander<'tcx> { impl<'tcx> PatternFolder<'tcx> for LiteralExpander<'tcx> { 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) { - ( - &ty::Ref(_, rty, _), - &PatKind::Constant { - value: - Const { - val: ty::ConstKind::Value(val), - ty: ty::TyS { kind: ty::Ref(_, crty, _), .. }, - }, - }, - ) => Pat { - ty: pat.ty, - span: pat.span, - kind: box PatKind::Deref { - subpattern: Pat { - ty: rty, + debug!("fold_pattern {:?} {:?} {:?}", pat, pat.ty.kind(), pat.kind); + match (pat.ty.kind(), &*pat.kind) { + (&ty::Ref(_, rty, _), &PatKind::Constant { value: Const { val, ty: const_ty } }) + if const_ty.is_ref() => + { + let crty = + if let ty::Ref(_, crty, _) = const_ty.kind() { crty } else { unreachable!() }; + if let ty::ConstKind::Value(val) = val { + Pat { + ty: pat.ty, span: pat.span, - kind: box PatKind::Constant { - value: Const::from_value( - self.tcx, - self.fold_const_value_deref(*val, rty, crty), - rty, - ), + kind: box PatKind::Deref { + subpattern: Pat { + ty: rty, + span: pat.span, + kind: box PatKind::Constant { + value: Const::from_value( + self.tcx, + self.fold_const_value_deref(*val, rty, crty), + rty, + ), + }, + }, }, - }, - }, - }, - - ( - &ty::Ref(_, rty, _), - &PatKind::Constant { - value: Const { val, ty: ty::TyS { kind: ty::Ref(_, crty, _), .. } }, - }, - ) => bug!("cannot deref {:#?}, {} -> {}", val, crty, rty), + } + } else { + bug!("cannot deref {:#?}, {} -> {}", val, crty, rty) + } + } (_, &PatKind::Binding { subpattern: Some(ref s), .. }) => s.fold_with(self), (_, &PatKind::AscribeUserType { subpattern: ref s, .. }) => s.fold_with(self), @@ -422,7 +416,7 @@ impl<'tcx> Pat<'tcx> { /// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` /// works well. -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] crate struct PatStack<'p, 'tcx>(SmallVec<[&'p Pat<'tcx>; 2]>); impl<'p, 'tcx> PatStack<'p, 'tcx> { @@ -510,13 +504,36 @@ impl<'p, 'tcx> FromIterator<&'p Pat<'tcx>> for PatStack<'p, 'tcx> { } } +/// Depending on the match patterns, the specialization process might be able to use a fast path. +/// Tracks whether we can use the fast path and the lookup table needed in those cases. +#[derive(Clone, Debug, PartialEq)] +enum SpecializationCache { + /// Patterns consist of only enum variants. + /// Variant patterns does not intersect with each other (in contrast to range patterns), + /// so it is possible to precompute the result of `Matrix::specialize_constructor` at a + /// lower computational complexity. + /// `lookup` is responsible for holding the precomputed result of + /// `Matrix::specialize_constructor`, while `wilds` is used for two purposes: the first one is + /// the precomputed result of `Matrix::specialize_wildcard`, and the second is to be used as a + /// fallback for `Matrix::specialize_constructor` when it tries to apply a constructor that + /// has not been seen in the `Matrix`. See `update_cache` for further explanations. + Variants { lookup: FxHashMap>, wilds: SmallVec<[usize; 1]> }, + /// Does not belong to the cases above, use the slow path. + Incompatible, +} + /// A 2D matrix. -#[derive(Clone)] -crate struct Matrix<'p, 'tcx>(Vec>); +#[derive(Clone, PartialEq)] +crate struct Matrix<'p, 'tcx> { + patterns: Vec>, + cache: SpecializationCache, +} impl<'p, 'tcx> Matrix<'p, 'tcx> { crate fn empty() -> Self { - Matrix(vec![]) + // Use `SpecializationCache::Incompatible` as a placeholder; we will initialize it on the + // first call to `push`. See the first half of `update_cache`. + Matrix { patterns: vec![], cache: SpecializationCache::Incompatible } } /// Pushes a new row to the matrix. If the row starts with an or-pattern, this expands it. @@ -528,18 +545,101 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { self.push(row) } } else { - self.0.push(row); + self.patterns.push(row); + self.update_cache(self.patterns.len() - 1); + } + } + + fn update_cache(&mut self, idx: usize) { + let row = &self.patterns[idx]; + // We don't know which kind of cache could be used until we see the first row; therefore an + // empty `Matrix` is initialized with `SpecializationCache::Empty`, then the cache is + // assigned the appropriate variant below on the first call to `push`. + if self.patterns.is_empty() { + self.cache = if row.is_empty() { + SpecializationCache::Incompatible + } else { + match *row.head().kind { + PatKind::Variant { .. } => SpecializationCache::Variants { + lookup: FxHashMap::default(), + wilds: SmallVec::new(), + }, + // Note: If the first pattern is a wildcard, then all patterns after that is not + // useful. The check is simple enough so we treat it as the same as unsupported + // patterns. + _ => SpecializationCache::Incompatible, + } + }; + } + // Update the cache. + match &mut self.cache { + SpecializationCache::Variants { ref mut lookup, ref mut wilds } => { + let head = row.head(); + match *head.kind { + _ if head.is_wildcard() => { + // Per rule 1.3 in the top-level comments, a wildcard pattern is included in + // the result of `specialize_constructor` for *any* `Constructor`. + // We push the wildcard pattern to the precomputed result for constructors + // that we have seen before; results for constructors we have not yet seen + // defaults to `wilds`, which is updated right below. + for (_, v) in lookup.iter_mut() { + v.push(idx); + } + // Per rule 2.1 and 2.2 in the top-level comments, only wildcard patterns + // are included in the result of `specialize_wildcard`. + // What we do here is to track the wildcards we have seen; so in addition to + // acting as the precomputed result of `specialize_wildcard`, `wilds` also + // serves as the default value of `specialize_constructor` for constructors + // that are not in `lookup`. + wilds.push(idx); + } + PatKind::Variant { adt_def, variant_index, .. } => { + // Handle the cases of rule 1.1 and 1.2 in the top-level comments. + // A variant pattern can only be included in the results of + // `specialize_constructor` for a particular constructor, therefore we are + // using a HashMap to track that. + lookup + .entry(adt_def.variants[variant_index].def_id) + // Default to `wilds` for absent keys. See above for an explanation. + .or_insert_with(|| wilds.clone()) + .push(idx); + } + _ => { + self.cache = SpecializationCache::Incompatible; + } + } + } + SpecializationCache::Incompatible => {} } } /// Iterate over the first component of each row fn heads<'a>(&'a self) -> impl Iterator> + Captures<'p> { - self.0.iter().map(|r| r.head()) + self.patterns.iter().map(|r| r.head()) } /// This computes `D(self)`. See top of the file for explanations. fn specialize_wildcard(&self) -> Self { - self.0.iter().filter_map(|r| r.specialize_wildcard()).collect() + match &self.cache { + SpecializationCache::Variants { wilds, .. } => { + let result = + wilds.iter().filter_map(|&i| self.patterns[i].specialize_wildcard()).collect(); + // When debug assertions are enabled, check the results against the "slow path" + // result. + debug_assert_eq!( + result, + Self { + patterns: self.patterns.clone(), + cache: SpecializationCache::Incompatible + } + .specialize_wildcard() + ); + result + } + SpecializationCache::Incompatible => { + self.patterns.iter().filter_map(|r| r.specialize_wildcard()).collect() + } + } } /// This computes `S(constructor, self)`. See top of the file for explanations. @@ -549,10 +649,47 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { constructor: &Constructor<'tcx>, ctor_wild_subpatterns: &Fields<'p, 'tcx>, ) -> Matrix<'p, 'tcx> { - self.0 - .iter() - .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) - .collect() + match &self.cache { + SpecializationCache::Variants { lookup, wilds } => { + let result: Self = if let Constructor::Variant(id) = constructor { + lookup + .get(id) + // Default to `wilds` for absent keys. See `update_cache` for an explanation. + .unwrap_or(&wilds) + .iter() + .filter_map(|&i| { + self.patterns[i].specialize_constructor( + cx, + constructor, + ctor_wild_subpatterns, + ) + }) + .collect() + } else { + unreachable!() + }; + // When debug assertions are enabled, check the results against the "slow path" + // result. + debug_assert_eq!( + result, + Matrix { + patterns: self.patterns.clone(), + cache: SpecializationCache::Incompatible + } + .specialize_constructor( + cx, + constructor, + ctor_wild_subpatterns + ) + ); + result + } + SpecializationCache::Incompatible => self + .patterns + .iter() + .filter_map(|r| r.specialize_constructor(cx, constructor, ctor_wild_subpatterns)) + .collect(), + } } } @@ -574,7 +711,7 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\n")?; - let &Matrix(ref m) = self; + let Matrix { patterns: m, .. } = self; let pretty_printed_matrix: Vec> = m.iter().map(|row| row.iter().map(|pat| format!("{:?}", pat)).collect()).collect(); @@ -639,7 +776,7 @@ impl<'a, 'tcx> MatchCheckCtxt<'a, 'tcx> { /// Returns whether the given type is an enum from another crate declared `#[non_exhaustive]`. crate fn is_foreign_non_exhaustive_enum(&self, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(def, ..) => { def.is_enum() && def.is_variant_list_non_exhaustive() && !def.did.is_local() } @@ -920,14 +1057,14 @@ impl<'tcx> Constructor<'tcx> { let mut subpatterns = fields.all_patterns(); let pat = match self { - Single | Variant(_) => match ty.kind { + Single | Variant(_) => match ty.kind() { ty::Adt(..) | ty::Tuple(..) => { let subpatterns = subpatterns .enumerate() .map(|(i, p)| FieldPat { field: Field::new(i), pattern: p }) .collect(); - if let ty::Adt(adt, substs) = ty.kind { + if let ty::Adt(adt, substs) = ty.kind() { if adt.is_enum() { PatKind::Variant { adt_def: adt, @@ -1074,7 +1211,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { let wildcard_from_ty = |ty| &*cx.pattern_arena.alloc(Pat::wildcard_from_ty(ty)); let ret = match constructor { - Single | Variant(_) => match ty.kind { + Single | Variant(_) => match ty.kind() { ty::Tuple(ref fs) => { Fields::wildcards_from_tys(cx, fs.into_iter().map(|ty| ty.expect_ty())) } @@ -1125,7 +1262,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { } _ => Fields::empty(), }, - Slice(slice) => match ty.kind { + Slice(slice) => match *ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); Fields::wildcards_from_tys(cx, (0..arity).map(|_| ty)) @@ -1443,7 +1580,7 @@ fn all_constructors<'a, 'tcx>( .unwrap(), ) }; - match pcx.ty.kind { + match *pcx.ty.kind() { ty::Bool => { [true, false].iter().map(|&b| ConstantValue(ty::Const::from_bool(cx.tcx, b))).collect() } @@ -1558,7 +1695,7 @@ struct IntRange<'tcx> { impl<'tcx> IntRange<'tcx> { #[inline] fn is_integral(ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Char | ty::Int(_) | ty::Uint(_) => true, _ => false, } @@ -1580,7 +1717,7 @@ impl<'tcx> IntRange<'tcx> { #[inline] fn integral_size_and_signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'_>) -> Option<(Size, u128)> { - match ty.kind { + match *ty.kind() { ty::Char => Some((Size::from_bytes(4), 0)), ty::Int(ity) => { let size = Integer::from_attr(&tcx, SignedInt(ity)).size(); @@ -1650,15 +1787,38 @@ impl<'tcx> IntRange<'tcx> { param_env: ty::ParamEnv<'tcx>, pat: &Pat<'tcx>, ) -> Option> { - match pat_constructor(tcx, param_env, pat)? { - IntRange(range) => Some(range), - _ => None, + // This MUST be kept in sync with `pat_constructor`. + match *pat.kind { + PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` + PatKind::Or { .. } => bug!("Or-pattern should have been expanded earlier on."), + + PatKind::Binding { .. } + | PatKind::Wild + | PatKind::Leaf { .. } + | PatKind::Deref { .. } + | PatKind::Variant { .. } + | PatKind::Array { .. } + | PatKind::Slice { .. } => None, + + PatKind::Constant { value } => Self::from_const(tcx, param_env, value, pat.span), + + PatKind::Range(PatRange { lo, hi, end }) => { + let ty = lo.ty; + Self::from_range( + tcx, + lo.eval_bits(tcx, param_env, lo.ty), + hi.eval_bits(tcx, param_env, hi.ty), + ty, + &end, + pat.span, + ) + } } } // The return value of `signed_bias` should be XORed with an endpoint to encode/decode it. fn signed_bias(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> u128 { - match ty.kind { + match *ty.kind() { ty::Int(ity) => { let bits = Integer::from_attr(&tcx, SignedInt(ity)).size().bits() as u128; 1u128 << (bits - 1) @@ -1830,7 +1990,7 @@ crate fn is_useful<'p, 'tcx>( is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'tcx> { - let &Matrix(ref rows) = matrix; + let Matrix { patterns: rows, .. } = matrix; debug!("is_useful({:#?}, {:#?})", matrix, v); // The base case. We are pattern-matching on () and the return value is @@ -2059,6 +2219,7 @@ fn pat_constructor<'tcx>( param_env: ty::ParamEnv<'tcx>, pat: &Pat<'tcx>, ) -> Option> { + // This MUST be kept in sync with `IntRange::from_pat`. match *pat.kind { PatKind::AscribeUserType { .. } => bug!(), // Handled by `expand_pattern` PatKind::Binding { .. } | PatKind::Wild => None, @@ -2070,7 +2231,7 @@ fn pat_constructor<'tcx>( if let Some(int_range) = IntRange::from_const(tcx, param_env, value, pat.span) { Some(IntRange(int_range)) } else { - match (value.val, &value.ty.kind) { + match (value.val, &value.ty.kind()) { (_, ty::Array(_, n)) => { let len = n.eval_usize(tcx, param_env); Some(Slice(Slice { array_len: Some(len), kind: FixedLen(len) })) @@ -2102,7 +2263,7 @@ fn pat_constructor<'tcx>( } PatKind::Array { ref prefix, ref slice, ref suffix } | PatKind::Slice { ref prefix, ref slice, ref suffix } => { - let array_len = match pat.ty.kind { + let array_len = match pat.ty.kind() { ty::Array(_, length) => Some(length.eval_usize(tcx, param_env)), ty::Slice(_) => None, _ => span_bug!(pat.span, "bad ty {:?} for slice pattern", pat.ty), @@ -2141,7 +2302,7 @@ fn slice_pat_covered_by_const<'tcx>( ) }; - let data: &[u8] = match (const_val_val, &const_val.ty.kind) { + let data: &[u8] = match (const_val_val, &const_val.ty.kind()) { (ConstValue::ByRef { offset, alloc, .. }, ty::Array(t, n)) => { assert_eq!(*t, tcx.types.u8); let n = n.eval_usize(tcx, param_env); @@ -2272,7 +2433,7 @@ fn split_grouped_constructors<'p, 'tcx>( // `borders` is the set of borders between equivalence classes: each equivalence // class lies between 2 borders. let row_borders = matrix - .0 + .patterns .iter() .flat_map(|row| { IntRange::from_pat(tcx, param_env, row.head()).map(|r| (r, row.len())) @@ -2305,19 +2466,19 @@ fn split_grouped_constructors<'p, 'tcx>( // interval into a constructor. split_ctors.extend( borders - .windows(2) - .filter_map(|window| match (window[0], window[1]) { - (Border::JustBefore(n), Border::JustBefore(m)) => { + .array_windows() + .filter_map(|&pair| match pair { + [Border::JustBefore(n), Border::JustBefore(m)] => { if n < m { Some(IntRange { range: n..=(m - 1), ty, span }) } else { None } } - (Border::JustBefore(n), Border::AfterMax) => { + [Border::JustBefore(n), Border::AfterMax] => { Some(IntRange { range: n..=u128::MAX, ty, span }) } - (Border::AfterMax, _) => None, + [Border::AfterMax, _] => None, }) .map(IntRange), ); @@ -2561,7 +2722,7 @@ fn specialize_one_pattern<'p, 'tcx>( // elements don't necessarily point to memory, they are usually // just integers. The only time they should be pointing to memory // is when they are subslices of nonzero slices. - let (alloc, offset, n, ty) = match value.ty.kind { + let (alloc, offset, n, ty) = match value.ty.kind() { ty::Array(t, n) => { let n = n.eval_usize(cx.tcx, cx.param_env); // Shortcut for `n == 0` where no matter what `alloc` and `offset` we produce, diff --git a/src/librustc_mir_build/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs similarity index 99% rename from src/librustc_mir_build/thir/pattern/check_match.rs rename to compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 4e7108667e..047bf7db4c 100644 --- a/src/librustc_mir_build/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -289,7 +289,7 @@ fn check_for_bindings_named_same_as_variants(cx: &MatchVisitor<'_, '_>, pat: &Pa cx.typeck_results.extract_binding_mode(cx.tcx.sess, p.hir_id, p.span) { let pat_ty = cx.typeck_results.pat_ty(p).peel_refs(); - if let ty::Adt(edef, _) = pat_ty.kind { + if let ty::Adt(edef, _) = pat_ty.kind() { if edef.is_enum() && edef.variants.iter().any(|variant| { variant.ident == ident && variant.ctor_kind == CtorKind::Const @@ -442,7 +442,7 @@ fn check_exhaustive<'p, 'tcx>( // In the absence of the `exhaustive_patterns` feature, empty matches are not detected by // `is_useful` to exhaustively match uninhabited types, so we manually check here. if is_empty_match && !cx.tcx.features().exhaustive_patterns { - let scrutinee_is_visibly_uninhabited = match scrut_ty.kind { + let scrutinee_is_visibly_uninhabited = match scrut_ty.kind() { ty::Never => true, ty::Adt(def, _) => { def.is_enum() @@ -462,7 +462,7 @@ fn check_exhaustive<'p, 'tcx>( Err(err) => err, }; - let non_empty_enum = match scrut_ty.kind { + let non_empty_enum = match scrut_ty.kind() { ty::Adt(def, _) => def.is_enum() && !def.variants.is_empty(), _ => false, }; @@ -541,7 +541,7 @@ fn adt_defined_here( witnesses: &[super::Pat<'_>], ) { let ty = ty.peel_refs(); - if let ty::Adt(def, _) = ty.kind { + if let ty::Adt(def, _) = ty.kind() { if let Some(sp) = cx.tcx.hir().span_if_local(def.did) { err.span_label(sp, format!("`{}` defined here", ty)); } @@ -556,7 +556,7 @@ fn adt_defined_here( fn maybe_point_at_variant(ty: Ty<'_>, patterns: &[super::Pat<'_>]) -> Vec { let mut covered = vec![]; - if let ty::Adt(def, _) = ty.kind { + 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 { diff --git a/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs new file mode 100644 index 0000000000..a203b3a142 --- /dev/null +++ b/compiler/rustc_mir_build/src/thir/pattern/const_to_pat.rs @@ -0,0 +1,535 @@ +use rustc_hir as hir; +use rustc_index::vec::Idx; +use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; +use rustc_middle::mir::Field; +use rustc_middle::ty::print::with_no_trimmed_paths; +use rustc_middle::ty::{self, AdtDef, Ty, TyCtxt}; +use rustc_session::lint; +use rustc_span::Span; +use rustc_trait_selection::traits::predicate_for_trait_def; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; + +use std::cell::Cell; + +use super::{FieldPat, Pat, PatCtxt, PatKind}; + +impl<'a, 'tcx> PatCtxt<'a, 'tcx> { + /// Converts an evaluated constant to a pattern (if possible). + /// This means aggregate values (like structs and enums) are converted + /// to a pattern that matches the value (as if you'd compared via structural equality). + pub(super) fn const_to_pat( + &self, + cv: &'tcx ty::Const<'tcx>, + id: hir::HirId, + span: Span, + mir_structural_match_violation: bool, + ) -> Pat<'tcx> { + debug!("const_to_pat: cv={:#?} id={:?}", cv, id); + debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); + + let pat = self.tcx.infer_ctxt().enter(|infcx| { + let mut convert = ConstToPat::new(self, id, span, infcx); + convert.to_pat(cv, mir_structural_match_violation) + }); + + debug!("const_to_pat: pat={:?}", pat); + pat + } +} + +struct ConstToPat<'a, 'tcx> { + id: hir::HirId, + span: Span, + param_env: ty::ParamEnv<'tcx>, + + // This tracks if we emitted some hard error for a given const value, so that + // we will not subsequently issue an irrelevant lint for the same const + // value. + saw_const_match_error: Cell, + + // This tracks if we emitted some diagnostic for a given const value, so that + // we will not subsequently issue an irrelevant lint for the same const + // value. + saw_const_match_lint: Cell, + + // For backcompat we need to keep allowing non-structurally-eq types behind references. + // See also all the `cant-hide-behind` tests. + behind_reference: Cell, + + // inference context used for checking `T: Structural` bounds. + infcx: InferCtxt<'a, 'tcx>, + + include_lint_checks: bool, +} + +mod fallback_to_const_ref { + #[derive(Debug)] + /// This error type signals that we encountered a non-struct-eq situation behind a reference. + /// We bubble this up in order to get back to the reference destructuring and make that emit + /// a const pattern instead of a deref pattern. This allows us to simply call `PartialEq::eq` + /// on such patterns (since that function takes a reference) and not have to jump through any + /// hoops to get a reference to the value. + pub(super) struct FallbackToConstRef(()); + + pub(super) fn fallback_to_const_ref<'a, 'tcx>( + c2p: &super::ConstToPat<'a, 'tcx>, + ) -> FallbackToConstRef { + assert!(c2p.behind_reference.get()); + FallbackToConstRef(()) + } +} +use fallback_to_const_ref::{fallback_to_const_ref, FallbackToConstRef}; + +impl<'a, 'tcx> ConstToPat<'a, 'tcx> { + fn new( + pat_ctxt: &PatCtxt<'_, 'tcx>, + id: hir::HirId, + span: Span, + infcx: InferCtxt<'a, 'tcx>, + ) -> Self { + ConstToPat { + id, + span, + infcx, + param_env: pat_ctxt.param_env, + include_lint_checks: pat_ctxt.include_lint_checks, + saw_const_match_error: Cell::new(false), + saw_const_match_lint: Cell::new(false), + behind_reference: Cell::new(false), + } + } + + fn tcx(&self) -> TyCtxt<'tcx> { + self.infcx.tcx + } + + fn adt_derive_msg(&self, adt_def: &AdtDef) -> String { + let path = self.tcx().def_path_str(adt_def.did); + format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ) + } + + fn search_for_structural_match_violation(&self, ty: Ty<'tcx>) -> Option { + traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty).map( + |non_sm_ty| { + with_no_trimmed_paths(|| match non_sm_ty { + traits::NonStructuralMatchTy::Adt(adt) => self.adt_derive_msg(adt), + traits::NonStructuralMatchTy::Dynamic => { + "trait objects cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Opaque => { + "opaque types cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Generator => { + "generators cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Closure => { + "closures cannot be used in patterns".to_string() + } + traits::NonStructuralMatchTy::Param => { + bug!("use of a constant whose type is a parameter inside a pattern") + } + traits::NonStructuralMatchTy::Projection => { + bug!("use of a constant whose type is a projection inside a pattern") + } + traits::NonStructuralMatchTy::Foreign => { + bug!("use of a value of a foreign type inside a pattern") + } + }) + }, + ) + } + + fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { + ty.is_structural_eq_shallow(self.infcx.tcx) + } + + fn to_pat( + &mut self, + cv: &'tcx ty::Const<'tcx>, + mir_structural_match_violation: bool, + ) -> Pat<'tcx> { + // This method is just a wrapper handling a validity check; the heavy lifting is + // performed by the recursive `recur` method, which is not meant to be + // invoked except by this method. + // + // once indirect_structural_match is a full fledged error, this + // level of indirection can be eliminated + + let inlined_const_as_pat = self.recur(cv, mir_structural_match_violation).unwrap(); + + if self.include_lint_checks && !self.saw_const_match_error.get() { + // If we were able to successfully convert the const to some pat, + // double-check that all types in the const implement `Structural`. + + let structural = self.search_for_structural_match_violation(cv.ty); + debug!( + "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", + cv.ty, structural + ); + + // This can occur because const qualification treats all associated constants as + // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them + // before it runs. + // + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation`. + if structural.is_none() && mir_structural_match_violation { + warn!("MIR const-checker found novel structural match violation. See #73448."); + return inlined_const_as_pat; + } + + if let Some(msg) = structural { + if !self.type_may_have_partial_eq_impl(cv.ty) { + // span_fatal avoids ICE from resolution of non-existent method (rare case). + self.tcx().sess.span_fatal(self.span, &msg); + } else if mir_structural_match_violation && !self.saw_const_match_lint.get() { + self.tcx().struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + self.id, + self.span, + |lint| lint.build(&msg).emit(), + ); + } else { + debug!( + "`search_for_structural_match_violation` found one, but `CustomEq` was \ + not in the qualifs for that `const`" + ); + } + } + } + + inlined_const_as_pat + } + + fn type_may_have_partial_eq_impl(&self, ty: Ty<'tcx>) -> bool { + // double-check there even *is* a semantic `PartialEq` to dispatch to. + // + // (If there isn't, then we can safely issue a hard + // error, because that's never worked, due to compiler + // using `PartialEq::eq` in this scenario in the past.) + let partial_eq_trait_id = + self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); + let obligation: PredicateObligation<'_> = predicate_for_trait_def( + self.tcx(), + self.param_env, + ObligationCause::misc(self.span, self.id), + partial_eq_trait_id, + 0, + ty, + &[], + ); + // FIXME: should this call a `predicate_must_hold` variant instead? + + let has_impl = self.infcx.predicate_may_hold(&obligation); + + // Note: To fix rust-lang/rust#65466, we could just remove this type + // walk hack for function pointers, and unconditionally error + // if `PartialEq` is not implemented. However, that breaks stable + // code at the moment, because types like `for <'a> fn(&'a ())` do + // not *yet* implement `PartialEq`. So for now we leave this here. + has_impl + || ty.walk().any(|t| match t.unpack() { + ty::subst::GenericArgKind::Lifetime(_) => false, + ty::subst::GenericArgKind::Type(t) => t.is_fn_ptr(), + ty::subst::GenericArgKind::Const(_) => false, + }) + } + + // Recursive helper for `to_pat`; invoke that (instead of calling this directly). + fn recur( + &self, + cv: &'tcx ty::Const<'tcx>, + mir_structural_match_violation: bool, + ) -> Result, FallbackToConstRef> { + let id = self.id; + let span = self.span; + let tcx = self.tcx(); + let param_env = self.param_env; + + let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| -> Result<_, _> { + vals.iter() + .enumerate() + .map(|(idx, val)| { + let field = Field::new(idx); + Ok(FieldPat { field, pattern: self.recur(val, false)? }) + }) + .collect() + }; + + let kind = match cv.ty.kind() { + ty::Float(_) => { + tcx.struct_span_lint_hir( + lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + id, + span, + |lint| lint.build("floating-point types cannot be used in patterns").emit(), + ); + PatKind::Constant { value: cv } + } + ty::Adt(adt_def, _) if adt_def.is_union() => { + // Matching on union fields is unsafe, we can't hide it in constants + self.saw_const_match_error.set(true); + let msg = "cannot use unions in constant patterns"; + if self.include_lint_checks { + tcx.sess.span_err(span, msg); + } else { + tcx.sess.delay_span_bug(span, msg) + } + PatKind::Wild + } + ty::Adt(..) + if !self.type_may_have_partial_eq_impl(cv.ty) + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation` and then remove this condition. + && self.search_for_structural_match_violation(cv.ty).is_some() => + { + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we + // could get `Option`, even though `Option` is annotated with derive. + let msg = self.search_for_structural_match_violation(cv.ty).unwrap(); + self.saw_const_match_error.set(true); + if self.include_lint_checks { + tcx.sess.span_err(self.span, &msg); + } else { + tcx.sess.delay_span_bug(self.span, &msg) + } + PatKind::Wild + } + // If the type is not structurally comparable, just emit the constant directly, + // causing the pattern match code to treat it opaquely. + // FIXME: This code doesn't emit errors itself, the caller emits the errors. + // So instead of specific errors, you just get blanket errors about the whole + // const type. See + // https://github.com/rust-lang/rust/pull/70743#discussion_r404701963 for + // details. + // Backwards compatibility hack because we can't cause hard errors on these + // types, so we compare them via `PartialEq::eq` at runtime. + ty::Adt(..) if !self.type_marked_structural(cv.ty) && self.behind_reference.get() => { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !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(), + ); + } + // Since we are behind a reference, we can just bubble the error up so we get a + // constant at reference type, making it easy to let the fallback call + // `PartialEq::eq` on it. + return Err(fallback_to_const_ref(self)); + } + ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { + debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); + let path = tcx.def_path_str(adt_def.did); + let msg = format!( + "to use a constant of type `{}` in a pattern, \ + `{}` must be annotated with `#[derive(PartialEq, Eq)]`", + path, path, + ); + self.saw_const_match_error.set(true); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + PatKind::Wild + } + ty::Adt(adt_def, substs) if adt_def.is_enum() => { + let destructured = tcx.destructure_const(param_env.and(cv)); + PatKind::Variant { + adt_def, + substs, + variant_index: destructured + .variant + .expect("destructed const of adt without variant id"), + subpatterns: field_pats(destructured.fields)?, + } + } + ty::Tuple(_) | ty::Adt(_, _) => { + let destructured = tcx.destructure_const(param_env.and(cv)); + PatKind::Leaf { subpatterns: field_pats(destructured.fields)? } + } + ty::Array(..) => PatKind::Array { + prefix: tcx + .destructure_const(param_env.and(cv)) + .fields + .iter() + .map(|val| self.recur(val, false)) + .collect::>()?, + slice: None, + suffix: Vec::new(), + }, + ty::Ref(_, pointee_ty, ..) => match *pointee_ty.kind() { + // These are not allowed and will error elsewhere anyway. + ty::Dynamic(..) => { + self.saw_const_match_error.set(true); + let msg = format!("`{}` cannot be used in patterns", cv.ty); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + PatKind::Wild + } + // `&str` and `&[u8]` are represented as `ConstValue::Slice`, let's keep using this + // optimization for now. + ty::Str => PatKind::Constant { value: cv }, + ty::Slice(elem_ty) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // `b"foo"` produces a `&[u8; 3]`, but you can't use constants of array type when + // matching against references, you can only use byte string literals. + // FIXME: clean this up, likely by permitting array patterns when matching on slices + ty::Array(elem_ty, _) if elem_ty == tcx.types.u8 => PatKind::Constant { value: cv }, + // Cannot merge this with the catch all branch below, because the `const_deref` + // changes the type from slice to array, and slice patterns behave differently from + // array patterns. + ty::Slice(..) => { + let old = self.behind_reference.replace(true); + let array = tcx.deref_const(self.param_env.and(cv)); + let val = PatKind::Deref { + subpattern: Pat { + kind: Box::new(PatKind::Slice { + prefix: tcx + .destructure_const(param_env.and(array)) + .fields + .iter() + .map(|val| self.recur(val, false)) + .collect::>()?, + slice: None, + suffix: vec![], + }), + span, + ty: pointee_ty, + }, + }; + self.behind_reference.set(old); + val + } + // Backwards compatibility hack: support references to non-structural types. + // We'll lower + // this pattern to a `PartialEq::eq` comparison and `PartialEq::eq` takes a + // reference. This makes the rest of the matching logic simpler as it doesn't have + // to figure out how to get a reference again. + ty::Adt(adt_def, _) if !self.type_marked_structural(pointee_ty) => { + if self.behind_reference.get() { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let msg = self.adt_derive_msg(adt_def); + self.tcx().struct_span_lint_hir( + lint::builtin::INDIRECT_STRUCTURAL_MATCH, + self.id, + self.span, + |lint| lint.build(&msg).emit(), + ); + } + PatKind::Constant { value: cv } + } else { + if !self.saw_const_match_error.get() { + self.saw_const_match_error.set(true); + let msg = self.adt_derive_msg(adt_def); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + } + PatKind::Wild + } + } + // All other references are converted into deref patterns and then recursively + // convert the dereferenced constant to a pattern that is the sub-pattern of the + // deref pattern. + _ => { + let old = self.behind_reference.replace(true); + // In case there are structural-match violations somewhere in this subpattern, + // we fall back to a const pattern. If we do not do this, we may end up with + // a !structural-match constant that is not of reference type, which makes it + // very hard to invoke `PartialEq::eq` on it as a fallback. + let val = match self.recur(tcx.deref_const(self.param_env.and(cv)), false) { + Ok(subpattern) => PatKind::Deref { subpattern }, + Err(_) => PatKind::Constant { value: cv }, + }; + self.behind_reference.set(old); + val + } + }, + ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::FnDef(..) => { + PatKind::Constant { value: cv } + } + ty::RawPtr(pointee) if pointee.ty.is_sized(tcx.at(span), param_env) => { + PatKind::Constant { value: cv } + } + // FIXME: these can have very suprising behaviour where optimization levels or other + // compilation choices change the runtime behaviour of the match. + // See https://github.com/rust-lang/rust/issues/70861 for examples. + ty::FnPtr(..) | ty::RawPtr(..) => { + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + { + self.saw_const_match_lint.set(true); + let msg = "function pointers and unsized pointers in patterns behave \ + unpredictably and should not be relied upon. \ + See https://github.com/rust-lang/rust/issues/70861 for details."; + tcx.struct_span_lint_hir( + lint::builtin::POINTER_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + PatKind::Constant { value: cv } + } + _ => { + self.saw_const_match_error.set(true); + let msg = format!("`{}` cannot be used in patterns", cv.ty); + if self.include_lint_checks { + tcx.sess.span_err(span, &msg); + } else { + tcx.sess.delay_span_bug(span, &msg) + } + PatKind::Wild + } + }; + + if self.include_lint_checks + && !self.saw_const_match_error.get() + && !self.saw_const_match_lint.get() + && mir_structural_match_violation + // FIXME(#73448): Find a way to bring const qualification into parity with + // `search_for_structural_match_violation` and then remove this condition. + && self.search_for_structural_match_violation(cv.ty).is_some() + { + self.saw_const_match_lint.set(true); + // Obtain the actual type that isn't annotated. If we just looked at `cv.ty` we + // could get `Option`, even though `Option` is annotated with derive. + let msg = self.search_for_structural_match_violation(cv.ty).unwrap().replace( + "in a pattern,", + "in a pattern, the constant's initializer must be trivial or", + ); + tcx.struct_span_lint_hir( + lint::builtin::NONTRIVIAL_STRUCTURAL_MATCH, + id, + span, + |lint| lint.build(&msg).emit(), + ); + } + + Ok(Pat { span, ty: cv.ty, kind: Box::new(kind) }) + } +} diff --git a/src/librustc_mir_build/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs similarity index 98% rename from src/librustc_mir_build/thir/pattern/mod.rs rename to compiler/rustc_mir_build/src/thir/pattern/mod.rs index c163cb0e60..718ed78889 100644 --- a/src/librustc_mir_build/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -39,19 +39,19 @@ crate enum PatternError { NonConstPath(Span), } -#[derive(Copy, Clone, Debug)] +#[derive(Copy, Clone, Debug, PartialEq)] crate enum BindingMode { ByValue, ByRef(BorrowKind), } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate struct FieldPat<'tcx> { crate field: Field, crate pattern: Pat<'tcx>, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate struct Pat<'tcx> { crate ty: Ty<'tcx>, crate span: Span, @@ -116,7 +116,7 @@ crate struct Ascription<'tcx> { crate user_ty_span: Span, } -#[derive(Clone, Debug)] +#[derive(Clone, Debug, PartialEq)] crate enum PatKind<'tcx> { Wild, @@ -237,7 +237,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Some(&adt_def.variants[variant_index]) } _ => { - if let ty::Adt(adt, _) = self.ty.kind { + if let ty::Adt(adt, _) = self.ty.kind() { if !adt.is_enum() { Some(&adt.variants[VariantIdx::new(0)]) } else { @@ -302,7 +302,7 @@ impl<'tcx> fmt::Display for Pat<'tcx> { Ok(()) } PatKind::Deref { ref subpattern } => { - match self.ty.kind { + match self.ty.kind() { ty::Adt(def, _) if def.is_box() => write!(f, "box ")?, ty::Ref(_, _, mutbl) => { write!(f, "&{}", mutbl.prefix_str())?; @@ -559,7 +559,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { } hir::PatKind::Tuple(ref pats, ddpos) => { - let tys = match ty.kind { + let tys = match ty.kind() { ty::Tuple(ref tys) => tys, _ => span_bug!(pat.span, "unexpected type for tuple pattern: {:?}", ty), }; @@ -588,7 +588,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { // x's type, which is &T, where we want T (the type being matched). let var_ty = ty; if let ty::BindByReference(_) = bm { - if let ty::Ref(_, rty, _) = ty.kind { + if let ty::Ref(_, rty, _) = ty.kind() { ty = rty; } else { bug!("`ref {}` has wrong type {}", ident, ty); @@ -608,7 +608,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { hir::PatKind::TupleStruct(ref qpath, ref pats, ddpos) => { let res = self.typeck_results.qpath_res(qpath, pat.hir_id); - let adt_def = match ty.kind { + let adt_def = match ty.kind() { ty::Adt(adt_def, _) => adt_def, _ => span_bug!(pat.span, "tuple struct pattern not applied to an ADT {:?}", ty), }; @@ -670,7 +670,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let prefix = self.lower_patterns(prefix); let slice = self.lower_opt_pattern(slice); let suffix = self.lower_patterns(suffix); - match ty.kind { + match ty.kind() { // Matching a slice, `[T]`. ty::Slice(..) => PatKind::Slice { prefix, slice, suffix }, // Fixed-length array, `[T; len]`. @@ -704,7 +704,7 @@ impl<'a, 'tcx> PatCtxt<'a, 'tcx> { let enum_id = self.tcx.parent(variant_id).unwrap(); let adt_def = self.tcx.adt_def(enum_id); if adt_def.is_enum() { - let substs = match ty.kind { + let substs = match ty.kind() { ty::Adt(_, substs) | ty::FnDef(_, substs) => substs, ty::Error(_) => { // Avoid ICE (#50585) @@ -1058,7 +1058,7 @@ crate fn compare_const_vals<'tcx>( if let (Some(a), Some(b)) = (a_bits, b_bits) { use rustc_apfloat::Float; - return match ty.kind { + return match *ty.kind() { ty::Float(ast::FloatTy::F32) => { let l = ::rustc_apfloat::ieee::Single::from_bits(a); let r = ::rustc_apfloat::ieee::Single::from_bits(b); @@ -1081,7 +1081,7 @@ crate fn compare_const_vals<'tcx>( }; } - if let ty::Str = ty.kind { + if let ty::Str = ty.kind() { if let ( ty::ConstKind::Value(a_val @ ConstValue::Slice { .. }), ty::ConstKind::Value(b_val @ ConstValue::Slice { .. }), diff --git a/src/librustc_mir_build/thir/util.rs b/compiler/rustc_mir_build/src/thir/util.rs similarity index 97% rename from src/librustc_mir_build/thir/util.rs rename to compiler/rustc_mir_build/src/thir/util.rs index 7de60ddda4..aea8667314 100644 --- a/src/librustc_mir_build/thir/util.rs +++ b/compiler/rustc_mir_build/src/thir/util.rs @@ -17,7 +17,7 @@ crate trait UserAnnotatedTyHelpers<'tcx> { let mut user_ty = *user_provided_types.get(hir_id)?; debug!("user_subts_applied_to_ty_of_hir_id: user_ty={:?}", user_ty); let ty = self.typeck_results().node_type(hir_id); - match ty.kind { + match ty.kind() { ty::Adt(adt_def, ..) => { if let UserType::TypeOf(ref mut did, _) = &mut user_ty.value { *did = adt_def.did; diff --git a/compiler/rustc_parse/Cargo.toml b/compiler/rustc_parse/Cargo.toml new file mode 100644 index 0000000000..52835e5c8a --- /dev/null +++ b/compiler/rustc_parse/Cargo.toml @@ -0,0 +1,22 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_parse" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +bitflags = "1.0" +tracing = "0.1" +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_feature = { path = "../rustc_feature" } +rustc_lexer = { path = "../rustc_lexer" } +rustc_errors = { path = "../rustc_errors" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_ast = { path = "../rustc_ast" } +unicode-normalization = "0.1.11" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_parse/lexer/mod.rs b/compiler/rustc_parse/src/lexer/mod.rs similarity index 81% rename from src/librustc_parse/lexer/mod.rs rename to compiler/rustc_parse/src/lexer/mod.rs index 7503f15ac5..32b124970c 100644 --- a/src/librustc_parse/lexer/mod.rs +++ b/compiler/rustc_parse/src/lexer/mod.rs @@ -1,21 +1,19 @@ use rustc_ast::ast::AttrStyle; use rustc_ast::token::{self, CommentKind, Token, TokenKind}; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError}; -use rustc_lexer::Base; -use rustc_lexer::{unescape, RawStrError}; +use rustc_ast::tokenstream::{Spacing, TokenStream}; +use rustc_errors::{error_code, Applicability, DiagnosticBuilder, FatalError, PResult}; +use rustc_lexer::unescape::{self, Mode}; +use rustc_lexer::{Base, DocStyle, RawStrError}; use rustc_session::parse::ParseSess; use rustc_span::symbol::{sym, Symbol}; use rustc_span::{BytePos, Pos, Span}; -use std::char; use tracing::debug; mod tokentrees; mod unescape_error_reporting; mod unicode_chars; -use rustc_lexer::{unescape::Mode, DocStyle}; use unescape_error_reporting::{emit_unescape_error, push_escaped_char}; #[derive(Clone, Debug)] @@ -27,7 +25,17 @@ pub struct UnmatchedBrace { pub candidate_span: Option, } -pub struct StringReader<'a> { +crate fn parse_token_trees<'a>( + sess: &'a ParseSess, + src: &'a str, + start_pos: BytePos, + override_span: Option, +) -> (PResult<'a, TokenStream>, Vec) { + StringReader { sess, start_pos, pos: start_pos, end_src_index: src.len(), src, override_span } + .into_token_trees() +} + +struct StringReader<'a> { sess: &'a ParseSess, /// Initial position, read-only. start_pos: BytePos, @@ -36,97 +44,55 @@ pub struct StringReader<'a> { /// Stop reading src at this index. end_src_index: usize, /// Source text to tokenize. - src: Lrc, + src: &'a str, override_span: Option, } impl<'a> StringReader<'a> { - pub fn new( - sess: &'a ParseSess, - source_file: Lrc, - override_span: Option, - ) -> Self { - // Make sure external source is loaded first, before accessing it. - // While this can't show up during normal parsing, `retokenize` may - // be called with a source file from an external crate. - sess.source_map().ensure_source_file_source_present(Lrc::clone(&source_file)); - - let src = if let Some(src) = &source_file.src { - Lrc::clone(&src) - } else if let Some(src) = source_file.external_src.borrow().get_source() { - Lrc::clone(&src) - } else { - sess.span_diagnostic - .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); - }; - - StringReader { - sess, - start_pos: source_file.start_pos, - pos: source_file.start_pos, - end_src_index: src.len(), - src, - override_span, - } - } - - pub fn retokenize(sess: &'a ParseSess, mut span: Span) -> Self { - let begin = sess.source_map().lookup_byte_offset(span.lo()); - let end = sess.source_map().lookup_byte_offset(span.hi()); - - // Make the range zero-length if the span is invalid. - if begin.sf.start_pos != end.sf.start_pos { - span = span.shrink_to_lo(); - } - - let mut sr = StringReader::new(sess, begin.sf, None); - - // Seek the lexer to the right byte range. - sr.end_src_index = sr.src_index(span.hi()); - - sr - } - fn mk_sp(&self, lo: BytePos, hi: BytePos) -> Span { self.override_span.unwrap_or_else(|| Span::with_root_ctxt(lo, hi)) } - /// Returns the next token, including trivia like whitespace or comments. - pub fn next_token(&mut self) -> Token { + /// Returns the next token, and info about preceding whitespace, if any. + fn next_token(&mut self) -> (Spacing, Token) { + let mut spacing = Spacing::Joint; + + // Skip `#!` at the start of the file let start_src_index = self.src_index(self.pos); let text: &str = &self.src[start_src_index..self.end_src_index]; - - if text.is_empty() { - let span = self.mk_sp(self.pos, self.pos); - return Token::new(token::Eof, span); - } - - { - let is_beginning_of_file = self.pos == self.start_pos; - if is_beginning_of_file { - if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { - let start = self.pos; - self.pos = self.pos + BytePos::from_usize(shebang_len); - - let sym = self.symbol_from(start + BytePos::from_usize("#!".len())); - let kind = token::Shebang(sym); - - let span = self.mk_sp(start, self.pos); - return Token::new(kind, span); - } + let is_beginning_of_file = self.pos == self.start_pos; + if is_beginning_of_file { + if let Some(shebang_len) = rustc_lexer::strip_shebang(text) { + self.pos = self.pos + BytePos::from_usize(shebang_len); + spacing = Spacing::Alone; } } - let token = rustc_lexer::first_token(text); + // Skip trivial (whitespace & comments) tokens + loop { + let start_src_index = self.src_index(self.pos); + let text: &str = &self.src[start_src_index..self.end_src_index]; - let start = self.pos; - self.pos = self.pos + BytePos::from_usize(token.len); + if text.is_empty() { + let span = self.mk_sp(self.pos, self.pos); + return (spacing, Token::new(token::Eof, span)); + } - debug!("try_next_token: {:?}({:?})", token.kind, self.str_from(start)); + let token = rustc_lexer::first_token(text); - let kind = self.cook_lexer_token(token.kind, start); - let span = self.mk_sp(start, self.pos); - Token::new(kind, span) + let start = self.pos; + self.pos = self.pos + BytePos::from_usize(token.len); + + debug!("next_token: {:?}({:?})", token.kind, self.str_from(start)); + + match self.cook_lexer_token(token.kind, start) { + Some(kind) => { + let span = self.mk_sp(start, self.pos); + return (spacing, Token::new(kind, span)); + } + None => spacing = Spacing::Alone, + } + } } /// Report a fatal lexical error with a given span. @@ -166,19 +132,16 @@ impl<'a> StringReader<'a> { /// Turns simple `rustc_lexer::TokenKind` enum into a rich /// `librustc_ast::TokenKind`. This turns strings into interned /// symbols and runs additional validation. - fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> TokenKind { - match token { + fn cook_lexer_token(&self, token: rustc_lexer::TokenKind, start: BytePos) -> Option { + Some(match token { rustc_lexer::TokenKind::LineComment { doc_style } => { - match doc_style { - Some(doc_style) => { - // Opening delimiter of the length 3 is not included into the symbol. - let content_start = start + BytePos(3); - let content = self.str_from(content_start); + // Skip non-doc comments + let doc_style = doc_style?; - self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style) - } - None => token::Comment, - } + // Opening delimiter of the length 3 is not included into the symbol. + let content_start = start + BytePos(3); + let content = self.str_from(content_start); + self.cook_doc_comment(content_start, content, CommentKind::Line, doc_style) } rustc_lexer::TokenKind::BlockComment { doc_style, terminated } => { if !terminated { @@ -197,20 +160,18 @@ impl<'a> StringReader<'a> { .emit(); FatalError.raise(); } - match doc_style { - Some(doc_style) => { - // Opening delimiter of the length 3 and closing delimiter of the length 2 - // are not included into the symbol. - let content_start = start + BytePos(3); - let content_end = self.pos - BytePos(if terminated { 2 } else { 0 }); - let content = self.str_from_to(content_start, content_end); - self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) - } - None => token::Comment, - } + // Skip non-doc comments + let doc_style = doc_style?; + + // Opening delimiter of the length 3 and closing delimiter of the length 2 + // are not included into the symbol. + let content_start = start + BytePos(3); + let content_end = self.pos - BytePos(if terminated { 2 } else { 0 }); + let content = self.str_from_to(content_start, content_end); + self.cook_doc_comment(content_start, content, CommentKind::Block, doc_style) } - rustc_lexer::TokenKind::Whitespace => token::Whitespace, + rustc_lexer::TokenKind::Whitespace => return None, rustc_lexer::TokenKind::Ident | rustc_lexer::TokenKind::RawIdent => { let is_raw_ident = token == rustc_lexer::TokenKind::RawIdent; let mut ident_start = start; @@ -308,12 +269,11 @@ impl<'a> StringReader<'a> { // this should be inside `rustc_lexer`. However, we should first remove compound // tokens like `<<` from `rustc_lexer`, and then add fancier error recovery to it, // as there will be less overall work to do this way. - let token = unicode_chars::check_for_substitution(self, start, c, &mut err) - .unwrap_or_else(|| token::Unknown(self.symbol_from(start))); + let token = unicode_chars::check_for_substitution(self, start, c, &mut err); err.emit(); - token + token? } - } + }) } fn cook_doc_comment( @@ -465,10 +425,6 @@ impl<'a> StringReader<'a> { (lit_kind, id) } - pub fn pos(&self) -> BytePos { - self.pos - } - #[inline] fn src_index(&self, pos: BytePos) -> usize { (pos - self.start_pos).to_usize() @@ -480,12 +436,6 @@ impl<'a> StringReader<'a> { self.str_from_to(start, self.pos) } - /// Creates a Symbol from a given offset to the current offset. - fn symbol_from(&self, start: BytePos) -> Symbol { - debug!("taking an ident from {:?} to {:?}", start, self.pos); - Symbol::intern(self.str_from(start)) - } - /// As symbol_from, with an explicit endpoint. fn symbol_from_to(&self, start: BytePos, end: BytePos) -> Symbol { debug!("taking an ident from {:?} to {:?}", start, end); diff --git a/src/librustc_parse/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs similarity index 89% rename from src/librustc_parse/lexer/tokentrees.rs rename to compiler/rustc_parse/src/lexer/tokentrees.rs index c08659ec9f..6233549dc8 100644 --- a/src/librustc_parse/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -3,8 +3,8 @@ use super::{StringReader, UnmatchedBrace}; use rustc_ast::token::{self, DelimToken, Token}; use rustc_ast::tokenstream::{ DelimSpan, - IsJoint::{self, *}, - TokenStream, TokenTree, TreeAndJoint, + Spacing::{self, *}, + TokenStream, TokenTree, TreeAndSpacing, }; use rustc_ast_pretty::pprust::token_to_string; use rustc_data_structures::fx::FxHashMap; @@ -12,11 +12,10 @@ use rustc_errors::PResult; use rustc_span::Span; impl<'a> StringReader<'a> { - crate fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { + pub(super) fn into_token_trees(self) -> (PResult<'a, TokenStream>, Vec) { let mut tt_reader = TokenTreesReader { string_reader: self, token: Token::dummy(), - joint_to_prev: Joint, open_braces: Vec::new(), unmatched_braces: Vec::new(), matching_delim_spans: Vec::new(), @@ -32,7 +31,6 @@ impl<'a> StringReader<'a> { struct TokenTreesReader<'a> { string_reader: StringReader<'a>, token: Token, - joint_to_prev: IsJoint, /// Stack of open delimiters and their spans. Used for error message. open_braces: Vec<(token::DelimToken, Span)>, unmatched_braces: Vec, @@ -53,7 +51,7 @@ impl<'a> TokenTreesReader<'a> { fn parse_all_token_trees(&mut self) -> PResult<'a, TokenStream> { let mut buf = TokenStreamBuilder::default(); - self.real_token(); + self.bump(); while self.token != token::Eof { buf.push(self.parse_token_tree()?); } @@ -79,7 +77,7 @@ impl<'a> TokenTreesReader<'a> { } } - fn parse_token_tree(&mut self) -> PResult<'a, TreeAndJoint> { + fn parse_token_tree(&mut self) -> PResult<'a, TreeAndSpacing> { let sm = self.string_reader.sess.source_map(); match self.token.kind { @@ -126,7 +124,7 @@ impl<'a> TokenTreesReader<'a> { // Parse the open delimiter. self.open_braces.push((delim, self.token.span)); - self.real_token(); + self.bump(); // Parse the token trees within the delimiters. // We stop at any delimiter so we can try to recover if the user @@ -151,12 +149,9 @@ impl<'a> TokenTreesReader<'a> { } } - match (open_brace, delim) { - //only add braces - (DelimToken::Brace, DelimToken::Brace) => { - self.matching_block_spans.push((open_brace_span, close_brace_span)); - } - _ => {} + //only add braces + if let (DelimToken::Brace, DelimToken::Brace) = (open_brace, delim) { + self.matching_block_spans.push((open_brace_span, close_brace_span)); } if self.open_braces.is_empty() { @@ -171,7 +166,7 @@ impl<'a> TokenTreesReader<'a> { )); } // Parse the closing delimiter. - self.real_token(); + self.bump(); } // Incorrect delimiter. token::CloseDelim(other) => { @@ -217,7 +212,7 @@ impl<'a> TokenTreesReader<'a> { // bar(baz( // } // Incorrect delimiter but matches the earlier `{` if !self.open_braces.iter().any(|&(b, _)| b == other) { - self.real_token(); + self.bump(); } } token::Eof => { @@ -264,37 +259,29 @@ impl<'a> TokenTreesReader<'a> { } _ => { let tt = TokenTree::Token(self.token.take()); - self.real_token(); - let is_joint = self.joint_to_prev == Joint && self.token.is_op(); - Ok((tt, if is_joint { Joint } else { NonJoint })) + let mut spacing = self.bump(); + if !self.token.is_op() { + spacing = Alone; + } + Ok((tt, spacing)) } } } - fn real_token(&mut self) { - self.joint_to_prev = Joint; - loop { - let token = self.string_reader.next_token(); - match token.kind { - token::Whitespace | token::Comment | token::Shebang(_) | token::Unknown(_) => { - self.joint_to_prev = NonJoint; - } - _ => { - self.token = token; - return; - } - } - } + fn bump(&mut self) -> Spacing { + let (spacing, token) = self.string_reader.next_token(); + self.token = token; + spacing } } #[derive(Default)] struct TokenStreamBuilder { - buf: Vec, + buf: Vec, } impl TokenStreamBuilder { - fn push(&mut self, (tree, joint): TreeAndJoint) { + fn push(&mut self, (tree, joint): TreeAndSpacing) { if let Some((TokenTree::Token(prev_token), Joint)) = self.buf.last() { if let TokenTree::Token(token) = &tree { if let Some(glued) = prev_token.glue(token) { diff --git a/src/librustc_parse/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs similarity index 100% rename from src/librustc_parse/lexer/unescape_error_reporting.rs rename to compiler/rustc_parse/src/lexer/unescape_error_reporting.rs diff --git a/src/librustc_parse/lexer/unicode_chars.rs b/compiler/rustc_parse/src/lexer/unicode_chars.rs similarity index 99% rename from src/librustc_parse/lexer/unicode_chars.rs rename to compiler/rustc_parse/src/lexer/unicode_chars.rs index ac395f6cbc..40e2e34aa0 100644 --- a/src/librustc_parse/lexer/unicode_chars.rs +++ b/compiler/rustc_parse/src/lexer/unicode_chars.rs @@ -303,7 +303,7 @@ const UNICODE_ARRAY: &[(char, &str, char)] = &[ // However, we should first remove compound tokens like `<<` from `rustc_lexer`, and then add // fancier error recovery to it, as there will be less overall work to do this way. const ASCII_ARRAY: &[(char, &str, Option)] = &[ - (' ', "Space", Some(token::Whitespace)), + (' ', "Space", None), ('_', "Underscore", Some(token::Ident(kw::Underscore, false))), ('-', "Minus/Hyphen", Some(token::BinOp(token::Minus))), (',', "Comma", Some(token::Comma)), @@ -332,7 +332,7 @@ const ASCII_ARRAY: &[(char, &str, Option)] = &[ ('"', "Quotation Mark", None), ]; -crate fn check_for_substitution<'a>( +pub(super) fn check_for_substitution<'a>( reader: &StringReader<'a>, pos: BytePos, ch: char, diff --git a/src/librustc_parse/lib.rs b/compiler/rustc_parse/src/lib.rs similarity index 82% rename from src/librustc_parse/lib.rs rename to compiler/rustc_parse/src/lib.rs index bc857c9774..b68d36c9a8 100644 --- a/src/librustc_parse/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -3,12 +3,12 @@ #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(bindings_after_at)] -#![feature(try_blocks)] +#![feature(iter_order_by)] #![feature(or_patterns)] use rustc_ast as ast; -use rustc_ast::token::{self, DelimToken, Nonterminal, Token, TokenKind}; -use rustc_ast::tokenstream::{self, IsJoint, TokenStream, TokenTree}; +use rustc_ast::token::{self, Nonterminal, Token, TokenKind}; +use rustc_ast::tokenstream::{self, TokenStream, TokenTree}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; @@ -109,7 +109,7 @@ pub fn maybe_new_parser_from_source_str( } /// Creates a new parser, handling errors as appropriate if the file doesn't exist. -/// If a span is given, that is used on an error as the as the source of the problem. +/// If a span is given, that is used on an error as the source of the problem. pub fn new_parser_from_file<'a>(sess: &'a ParseSess, path: &Path, sp: Option) -> Parser<'a> { source_file_to_parser(sess, file_to_source_file(sess, path, sp)) } @@ -200,8 +200,13 @@ pub fn maybe_file_to_stream( source_file: Lrc, override_span: Option, ) -> Result<(TokenStream, Vec), Vec> { - let srdr = lexer::StringReader::new(sess, source_file, override_span); - let (token_trees, unmatched_braces) = srdr.into_token_trees(); + let src = source_file.src.as_ref().unwrap_or_else(|| { + sess.span_diagnostic + .bug(&format!("cannot lex `source_file` without source: {}", source_file.name)); + }); + + let (token_trees, unmatched_braces) = + lexer::parse_token_trees(sess, src.as_str(), source_file.start_pos, override_span); match token_trees { Ok(stream) => Ok((stream, unmatched_braces)), @@ -263,27 +268,38 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke Nonterminal::NtItem(ref item) => { prepend_attrs(sess, &item.attrs, item.tokens.as_ref(), span) } + Nonterminal::NtBlock(ref block) => block.tokens.clone(), + Nonterminal::NtStmt(ref stmt) => { + // FIXME: We currently only collect tokens for `:stmt` + // matchers in `macro_rules!` macros. When we start collecting + // tokens for attributes on statements, we will need to prepend + // attributes here + stmt.tokens.clone() + } Nonterminal::NtPat(ref pat) => pat.tokens.clone(), + Nonterminal::NtTy(ref ty) => ty.tokens.clone(), Nonterminal::NtIdent(ident, is_raw) => { Some(tokenstream::TokenTree::token(token::Ident(ident.name, is_raw), ident.span).into()) } Nonterminal::NtLifetime(ident) => { Some(tokenstream::TokenTree::token(token::Lifetime(ident.name), ident.span).into()) } + Nonterminal::NtMeta(ref attr) => attr.tokens.clone(), + Nonterminal::NtPath(ref path) => path.tokens.clone(), + Nonterminal::NtVis(ref vis) => vis.tokens.clone(), Nonterminal::NtTT(ref tt) => Some(tt.clone().into()), - Nonterminal::NtExpr(ref expr) => { + Nonterminal::NtExpr(ref expr) | Nonterminal::NtLiteral(ref expr) => { if expr.tokens.is_none() { debug!("missing tokens for expr {:?}", expr); } prepend_attrs(sess, &expr.attrs, expr.tokens.as_ref(), span) } - _ => None, }; // FIXME(#43081): Avoid this pretty-print + reparse hack let source = pprust::nonterminal_to_string(nt); let filename = FileName::macro_expansion_source_code(&source); - let tokens_for_real = parse_stream_from_source_str(filename, source, sess, Some(span)); + let reparsed_tokens = parse_stream_from_source_str(filename, source, sess, Some(span)); // During early phases of the compiler the AST could get modified // directly (e.g., attributes added or removed) and the internal cache @@ -309,7 +325,7 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // modifications, including adding/removing typically non-semantic // tokens such as extra braces and commas, don't happen. if let Some(tokens) = tokens { - if tokenstream_probably_equal_for_proc_macro(&tokens, &tokens_for_real, sess) { + if tokenstream_probably_equal_for_proc_macro(&tokens, &reparsed_tokens, sess) { return tokens; } info!( @@ -317,9 +333,9 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke going with stringified version" ); info!("cached tokens: {:?}", tokens); - info!("reparsed tokens: {:?}", tokens_for_real); + info!("reparsed tokens: {:?}", reparsed_tokens); } - tokens_for_real + reparsed_tokens } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -328,8 +344,8 @@ pub fn nt_to_tokenstream(nt: &Nonterminal, sess: &ParseSess, span: Span) -> Toke // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. pub fn tokenstream_probably_equal_for_proc_macro( - first: &TokenStream, - other: &TokenStream, + tokens: &TokenStream, + reparsed_tokens: &TokenStream, sess: &ParseSess, ) -> bool { // When checking for `probably_eq`, we ignore certain tokens that aren't @@ -343,14 +359,14 @@ pub fn tokenstream_probably_equal_for_proc_macro( // The pretty printer tends to add trailing commas to // everything, and in particular, after struct fields. | token::Comma - // The pretty printer emits `NoDelim` as whitespace. - | token::OpenDelim(DelimToken::NoDelim) - | token::CloseDelim(DelimToken::NoDelim) // The pretty printer collapses many semicolons into one. | token::Semi - // The pretty printer collapses whitespace arbitrarily and can - // introduce whitespace from `NoDelim`. - | token::Whitespace + // We don't preserve leading `|` tokens in patterns, so + // we ignore them entirely + | token::BinOp(token::BinOpToken::Or) + // We don't preserve trailing '+' tokens in trait bounds, + // so we ignore them entirely + | token::BinOp(token::BinOpToken::Plus) // The pretty printer can turn `$crate` into `::crate_name` | token::ModSep = token.kind { return false; @@ -419,36 +435,44 @@ pub fn tokenstream_probably_equal_for_proc_macro( token_trees.into_iter() } - let expand_nt = |tree: TokenTree| { - if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree { - // When checking tokenstreams for 'probable equality', we are comparing - // a captured (from parsing) `TokenStream` to a reparsed tokenstream. - // The reparsed Tokenstream will never have `None`-delimited groups, - // since they are only ever inserted as a result of macro expansion. - // Therefore, inserting a `None`-delimtied group here (when we - // convert a nested `Nonterminal` to a tokenstream) would cause - // a mismatch with the reparsed tokenstream. - // - // Note that we currently do not handle the case where the - // reparsed stream has a `Parenthesis`-delimited group - // inserted. This will cause a spurious mismatch: - // issue #75734 tracks resolving this. - nt_to_tokenstream(nt, sess, *span).into_trees() - } else { - TokenStream::new(vec![(tree, IsJoint::NonJoint)]).into_trees() - } - }; + fn expand_token(tree: TokenTree, sess: &ParseSess) -> impl Iterator { + // When checking tokenstreams for 'probable equality', we are comparing + // a captured (from parsing) `TokenStream` to a reparsed tokenstream. + // The reparsed Tokenstream will never have `None`-delimited groups, + // since they are only ever inserted as a result of macro expansion. + // Therefore, inserting a `None`-delimtied group here (when we + // convert a nested `Nonterminal` to a tokenstream) would cause + // a mismatch with the reparsed tokenstream. + // + // Note that we currently do not handle the case where the + // reparsed stream has a `Parenthesis`-delimited group + // inserted. This will cause a spurious mismatch: + // issue #75734 tracks resolving this. + + let expanded: SmallVec<[_; 1]> = + if let TokenTree::Token(Token { kind: TokenKind::Interpolated(nt), span }) = &tree { + nt_to_tokenstream(nt, sess, *span) + .into_trees() + .flat_map(|t| expand_token(t, sess)) + .collect() + } else { + // Filter before and after breaking tokens, + // since we may want to ignore both glued and unglued tokens. + std::iter::once(tree) + .filter(semantic_tree) + .flat_map(break_tokens) + .filter(semantic_tree) + .collect() + }; + expanded.into_iter() + } // Break tokens after we expand any nonterminals, so that we break tokens // that are produced as a result of nonterminal expansion. - let mut t1 = first.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - let mut t2 = other.trees().filter(semantic_tree).flat_map(expand_nt).flat_map(break_tokens); - for (t1, t2) in t1.by_ref().zip(t2.by_ref()) { - if !tokentree_probably_equal_for_proc_macro(&t1, &t2, sess) { - return false; - } - } - t1.next().is_none() && t2.next().is_none() + let tokens = tokens.trees().flat_map(|t| expand_token(t, sess)); + let reparsed_tokens = reparsed_tokens.trees().flat_map(|t| expand_token(t, sess)); + + tokens.eq_by(reparsed_tokens, |t, rt| tokentree_probably_equal_for_proc_macro(&t, &rt, sess)) } // See comments in `Nonterminal::to_tokenstream` for why we care about @@ -457,16 +481,20 @@ pub fn tokenstream_probably_equal_for_proc_macro( // This is otherwise the same as `eq_unspanned`, only recursing with a // different method. pub fn tokentree_probably_equal_for_proc_macro( - first: &TokenTree, - other: &TokenTree, + token: &TokenTree, + reparsed_token: &TokenTree, sess: &ParseSess, ) -> bool { - match (first, other) { - (TokenTree::Token(token), TokenTree::Token(token2)) => { - token_probably_equal_for_proc_macro(token, token2) + match (token, reparsed_token) { + (TokenTree::Token(token), TokenTree::Token(reparsed_token)) => { + token_probably_equal_for_proc_macro(token, reparsed_token) } - (TokenTree::Delimited(_, delim, tts), TokenTree::Delimited(_, delim2, tts2)) => { - delim == delim2 && tokenstream_probably_equal_for_proc_macro(&tts, &tts2, sess) + ( + TokenTree::Delimited(_, delim, tokens), + TokenTree::Delimited(_, reparsed_delim, reparsed_tokens), + ) => { + delim == reparsed_delim + && tokenstream_probably_equal_for_proc_macro(tokens, reparsed_tokens, sess) } _ => false, } @@ -506,8 +534,6 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { | (&Pound, &Pound) | (&Dollar, &Dollar) | (&Question, &Question) - | (&Whitespace, &Whitespace) - | (&Comment, &Comment) | (&Eof, &Eof) => true, (&BinOp(a), &BinOp(b)) | (&BinOpEq(a), &BinOpEq(b)) => a == b, @@ -516,8 +542,6 @@ fn token_probably_equal_for_proc_macro(first: &Token, other: &Token) -> bool { (&DocComment(a1, a2, a3), &DocComment(b1, b2, b3)) => a1 == b1 && a2 == b2 && a3 == b3, - (&Shebang(a), &Shebang(b)) => a == b, - (&Literal(a), &Literal(b)) => a == b, (&Lifetime(a), &Lifetime(b)) => a == b, diff --git a/src/librustc_parse/parser/attr.rs b/compiler/rustc_parse/src/parser/attr.rs similarity index 99% rename from src/librustc_parse/parser/attr.rs rename to compiler/rustc_parse/src/parser/attr.rs index 4e4429e461..98f94098bf 100644 --- a/src/librustc_parse/parser/attr.rs +++ b/compiler/rustc_parse/src/parser/attr.rs @@ -162,7 +162,7 @@ impl<'a> Parser<'a> { } else { let path = self.parse_path(PathStyle::Mod)?; let args = self.parse_attr_args()?; - ast::AttrItem { path, args } + ast::AttrItem { path, args, tokens: None } }) } diff --git a/src/librustc_parse/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs similarity index 96% rename from src/librustc_parse/parser/diagnostics.rs rename to compiler/rustc_parse/src/parser/diagnostics.rs index 12efe391fb..9ab13db4b5 100644 --- a/src/librustc_parse/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -28,7 +28,7 @@ pub(super) fn dummy_arg(ident: Ident) -> Param { span: ident.span, tokens: None, }); - let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID }; + let ty = Ty { kind: TyKind::Err, span: ident.span, id: ast::DUMMY_NODE_ID, tokens: None }; Param { attrs: AttrVec::default(), id: ast::DUMMY_NODE_ID, @@ -75,7 +75,12 @@ impl RecoverQPath for Ty { Some(P(self.clone())) } fn recovered(qself: Option, path: ast::Path) -> Self { - Self { span: path.span, kind: TyKind::Path(qself, path), id: ast::DUMMY_NODE_ID } + Self { + span: path.span, + kind: TyKind::Path(qself, path), + id: ast::DUMMY_NODE_ID, + tokens: None, + } } } @@ -548,6 +553,52 @@ impl<'a> Parser<'a> { } } + /// When writing a turbofish with multiple type parameters missing the leading `::`, we will + /// encounter a parse error when encountering the first `,`. + pub(super) fn check_mistyped_turbofish_with_multiple_type_params( + &mut self, + mut e: DiagnosticBuilder<'a>, + expr: &mut P, + ) -> PResult<'a, ()> { + if let ExprKind::Binary(binop, _, _) = &expr.kind { + if let ast::BinOpKind::Lt = binop.node { + if self.eat(&token::Comma) { + let x = self.parse_seq_to_before_end( + &token::Gt, + SeqSep::trailing_allowed(token::Comma), + |p| p.parse_ty(), + ); + match x { + Ok((_, _, false)) => { + self.bump(); // `>` + match self.parse_expr() { + Ok(_) => { + e.span_suggestion_verbose( + binop.span.shrink_to_lo(), + "use `::<...>` instead of `<...>` to specify type arguments", + "::".to_string(), + Applicability::MaybeIncorrect, + ); + e.emit(); + *expr = self.mk_expr_err(expr.span.to(self.prev_token.span)); + return Ok(()); + } + Err(mut err) => { + err.cancel(); + } + } + } + Err(mut err) => { + err.cancel(); + } + _ => {} + } + } + } + } + Err(e) + } + /// Check to see if a pair of chained operators looks like an attempt at chained comparison, /// e.g. `1 < x <= 3`. If so, suggest either splitting the comparison into two, or /// parenthesising the leftmost comparison. @@ -896,7 +947,7 @@ impl<'a> Parser<'a> { ) -> PResult<'a, P> { self.expect(&token::ModSep)?; - let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP }; + let mut path = ast::Path { segments: Vec::new(), span: DUMMY_SP, tokens: None }; self.parse_path_segments(&mut path.segments, T::PATH_STYLE)?; path.span = ty_span.to(self.prev_token.span); diff --git a/src/librustc_parse/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs similarity index 98% rename from src/librustc_parse/parser/expr.rs rename to compiler/rustc_parse/src/parser/expr.rs index f022c628fe..a11ad6e89c 100644 --- a/src/librustc_parse/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -16,6 +16,7 @@ use rustc_ast_pretty::pprust; use rustc_errors::{Applicability, DiagnosticBuilder, PResult}; use rustc_span::source_map::{self, Span, Spanned}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; +use rustc_span::{BytePos, Pos}; use std::mem; use tracing::debug; @@ -839,9 +840,10 @@ impl<'a> Parser<'a> { } use FloatComponent::*; + let float_str = float.as_str(); let mut components = Vec::new(); let mut ident_like = String::new(); - for c in float.as_str().chars() { + for c in float_str.chars() { if c == '_' || c.is_ascii_alphanumeric() { ident_like.push(c); } else if matches!(c, '.' | '+' | '-') { @@ -857,8 +859,13 @@ impl<'a> Parser<'a> { components.push(IdentLike(ident_like)); } - // FIXME: Make the span more precise. + // With proc macros the span can refer to anything, the source may be too short, + // or too long, or non-ASCII. It only makes sense to break our span into components + // if its underlying text is identical to our float literal. let span = self.token.span; + let can_take_span_apart = + || self.span_to_snippet(span).as_deref() == Ok(float_str).as_deref(); + match &*components { // 1e2 [IdentLike(i)] => { @@ -866,21 +873,40 @@ impl<'a> Parser<'a> { } // 1. [IdentLike(i), Punct('.')] => { + let (ident_span, dot_span) = if can_take_span_apart() { + let (span, ident_len) = (span.data(), BytePos::from_usize(i.len())); + let ident_span = span.with_hi(span.lo + ident_len); + let dot_span = span.with_lo(span.lo + ident_len); + (ident_span, dot_span) + } else { + (span, span) + }; assert!(suffix.is_none()); let symbol = Symbol::intern(&i); - self.token = Token::new(token::Ident(symbol, false), span); - let next_token = Token::new(token::Dot, span); + self.token = Token::new(token::Ident(symbol, false), ident_span); + let next_token = Token::new(token::Dot, dot_span); self.parse_tuple_field_access_expr(lo, base, symbol, None, Some(next_token)) } // 1.2 | 1.2e3 [IdentLike(i1), Punct('.'), IdentLike(i2)] => { + let (ident1_span, dot_span, ident2_span) = if can_take_span_apart() { + let (span, ident1_len) = (span.data(), BytePos::from_usize(i1.len())); + let ident1_span = span.with_hi(span.lo + ident1_len); + let dot_span = span + .with_lo(span.lo + ident1_len) + .with_hi(span.lo + ident1_len + BytePos(1)); + let ident2_span = self.token.span.with_lo(span.lo + ident1_len + BytePos(1)); + (ident1_span, dot_span, ident2_span) + } else { + (span, span, span) + }; let symbol1 = Symbol::intern(&i1); - self.token = Token::new(token::Ident(symbol1, false), span); - let next_token1 = Token::new(token::Dot, span); + self.token = Token::new(token::Ident(symbol1, false), ident1_span); + let next_token1 = Token::new(token::Dot, dot_span); let base1 = self.parse_tuple_field_access_expr(lo, base, symbol1, None, Some(next_token1)); let symbol2 = Symbol::intern(&i2); - let next_token2 = Token::new(token::Ident(symbol2, false), span); + let next_token2 = Token::new(token::Ident(symbol2, false), ident2_span); self.bump_with(next_token2); // `.` self.parse_tuple_field_access_expr(lo, base1, symbol2, suffix, None) } @@ -1480,7 +1506,7 @@ impl<'a> Parser<'a> { /// Matches `'-' lit | lit` (cf. `ast_validation::AstValidator::check_expr_within_pat`). /// Keep this in sync with `Token::can_begin_literal_maybe_minus`. - pub(super) fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { + pub fn parse_literal_maybe_minus(&mut self) -> PResult<'a, P> { maybe_whole_expr!(self); let lo = self.token.span; diff --git a/src/librustc_parse/parser/generics.rs b/compiler/rustc_parse/src/parser/generics.rs similarity index 100% rename from src/librustc_parse/parser/generics.rs rename to compiler/rustc_parse/src/parser/generics.rs diff --git a/src/librustc_parse/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs similarity index 96% rename from src/librustc_parse/parser/item.rs rename to compiler/rustc_parse/src/parser/item.rs index 9143af651d..26ca998012 100644 --- a/src/librustc_parse/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -28,7 +28,7 @@ impl<'a> Parser<'a> { /// Parses a source module as a crate. This is the main entry point for the parser. pub fn parse_crate_mod(&mut self) -> PResult<'a, ast::Crate> { let lo = self.token.span; - let (module, attrs) = self.parse_mod(&token::Eof)?; + let (module, attrs) = self.parse_mod(&token::Eof, Unsafe::No)?; let span = lo.to(self.token.span); let proc_macros = Vec::new(); // Filled in by `proc_macro_harness::inject()`. Ok(ast::Crate { attrs, module, span, proc_macros }) @@ -36,27 +36,38 @@ impl<'a> Parser<'a> { /// Parses a `mod { ... }` or `mod ;` item. fn parse_item_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + let unsafety = self.parse_unsafety(); + self.expect_keyword(kw::Mod)?; let id = self.parse_ident()?; let (module, mut inner_attrs) = if self.eat(&token::Semi) { - Default::default() + (Mod { inner: Span::default(), unsafety, items: Vec::new(), inline: false }, Vec::new()) } else { self.expect(&token::OpenDelim(token::Brace))?; - self.parse_mod(&token::CloseDelim(token::Brace))? + self.parse_mod(&token::CloseDelim(token::Brace), unsafety)? }; attrs.append(&mut inner_attrs); Ok((id, ItemKind::Mod(module))) } /// Parses the contents of a module (inner attributes followed by module items). - pub fn parse_mod(&mut self, term: &TokenKind) -> PResult<'a, (Mod, Vec)> { + pub fn parse_mod( + &mut self, + term: &TokenKind, + unsafety: Unsafe, + ) -> PResult<'a, (Mod, Vec)> { let lo = self.token.span; let attrs = self.parse_inner_attributes()?; - let module = self.parse_mod_items(term, lo)?; + let module = self.parse_mod_items(term, lo, unsafety)?; Ok((module, attrs)) } /// Given a termination token, parses all of the items in a module. - fn parse_mod_items(&mut self, term: &TokenKind, inner_lo: Span) -> PResult<'a, Mod> { + fn parse_mod_items( + &mut self, + term: &TokenKind, + inner_lo: Span, + unsafety: Unsafe, + ) -> PResult<'a, Mod> { let mut items = vec![]; while let Some(item) = self.parse_item()? { items.push(item); @@ -75,7 +86,7 @@ impl<'a> Parser<'a> { let hi = if self.token.span.is_dummy() { inner_lo } else { self.prev_token.span }; - Ok(Mod { inner: inner_lo.to(hi), items, inline: true }) + Ok(Mod { inner: inner_lo.to(hi), unsafety, items, inline: true }) } } @@ -176,7 +187,7 @@ impl<'a> Parser<'a> { /// Error in-case a non-inherited visibility was parsed but no item followed. fn error_on_unmatched_vis(&self, vis: &Visibility) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } let vs = pprust::vis_to_string(&vis); @@ -235,8 +246,13 @@ impl<'a> Parser<'a> { self.parse_item_extern_crate()? } else { // EXTERN BLOCK - self.parse_item_foreign_mod(attrs)? + self.parse_item_foreign_mod(attrs, Unsafe::No)? } + } else if self.is_unsafe_foreign_mod() { + // EXTERN BLOCK + let unsafety = self.parse_unsafety(); + self.expect_keyword(kw::Extern)?; + self.parse_item_foreign_mod(attrs, unsafety)? } else if self.is_static_global() { // STATIC ITEM self.bump(); // `static` @@ -256,7 +272,9 @@ impl<'a> Parser<'a> { { // IMPL ITEM self.parse_item_impl(attrs, def())? - } else if self.eat_keyword(kw::Mod) { + } else if self.check_keyword(kw::Mod) + || self.check_keyword(kw::Unsafe) && self.is_keyword_ahead(1, &[kw::Mod]) + { // MODULE ITEM self.parse_item_mod(attrs)? } else if self.eat_keyword(kw::Type) { @@ -278,7 +296,7 @@ impl<'a> Parser<'a> { } else if self.is_macro_rules_item() { // MACRO_RULES ITEM self.parse_item_macro_rules(vis)? - } else if vis.node.is_pub() && self.isnt_macro_invocation() { + } else if vis.kind.is_pub() && self.isnt_macro_invocation() { self.recover_missing_kw_before_item()?; return Ok(None); } else if macros_allowed && self.check_path() { @@ -492,7 +510,12 @@ impl<'a> Parser<'a> { { let span = self.prev_token.span.between(self.token.span); self.struct_span_err(span, "missing trait in a trait impl").emit(); - P(Ty { kind: TyKind::Path(None, err_path(span)), span, id: DUMMY_NODE_ID }) + P(Ty { + kind: TyKind::Path(None, err_path(span)), + span, + id: DUMMY_NODE_ID, + tokens: None, + }) } else { self.parse_ty()? }; @@ -764,7 +787,7 @@ impl<'a> Parser<'a> { fn parse_use_tree(&mut self) -> PResult<'a, UseTree> { let lo = self.token.span; - let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo() }; + let mut prefix = ast::Path { segments: Vec::new(), span: lo.shrink_to_lo(), tokens: None }; let kind = if self.check(&token::OpenDelim(token::Brace)) || self.check(&token::BinOp(token::Star)) || self.is_import_coupler() @@ -893,10 +916,14 @@ impl<'a> Parser<'a> { /// extern "C" {} /// extern {} /// ``` - fn parse_item_foreign_mod(&mut self, attrs: &mut Vec) -> PResult<'a, ItemInfo> { + fn parse_item_foreign_mod( + &mut self, + attrs: &mut Vec, + unsafety: Unsafe, + ) -> PResult<'a, ItemInfo> { let abi = self.parse_abi(); // ABI? let items = self.parse_item_list(attrs, |p| p.parse_foreign_item())?; - let module = ast::ForeignMod { abi, items }; + let module = ast::ForeignMod { unsafety, abi, items }; Ok((Ident::invalid(), ItemKind::ForeignMod(module))) } @@ -938,6 +965,15 @@ impl<'a> Parser<'a> { .emit(); } + fn is_unsafe_foreign_mod(&self) -> bool { + self.token.is_keyword(kw::Unsafe) + && self.is_keyword_ahead(1, &[kw::Extern]) + && self.look_ahead( + 2 + self.look_ahead(2, |t| t.can_begin_literal_maybe_minus() as usize), + |t| t.kind == token::OpenDelim(token::Brace), + ) + } + fn is_static_global(&mut self) -> bool { if self.check_keyword(kw::Static) { // Check if this could be a closure. @@ -1015,7 +1051,7 @@ impl<'a> Parser<'a> { // The user intended that the type be inferred, // so treat this as if the user wrote e.g. `const A: _ = expr;`. - P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID }) + P(Ty { kind: TyKind::Infer, span: id.span, id: ast::DUMMY_NODE_ID, tokens: None }) } /// Parses an enum declaration. @@ -1382,7 +1418,7 @@ impl<'a> Parser<'a> { /// Item macro invocations or `macro_rules!` definitions need inherited visibility. /// If that's not the case, emit an error. fn complain_if_pub_macro(&self, vis: &Visibility, macro_rules: bool) { - if let VisibilityKind::Inherited = vis.node { + if let VisibilityKind::Inherited = vis.kind { return; } @@ -1552,10 +1588,14 @@ impl<'a> Parser<'a> { // `$qual fn` or `$qual $qual`: || QUALS.iter().any(|&kw| self.check_keyword(kw)) && self.look_ahead(1, |t| { - // ...qualified and then `fn`, e.g. `const fn`. + // `$qual fn`, e.g. `const fn` or `async fn`. t.is_keyword(kw::Fn) - // Two qualifiers. This is enough. Due `async` we need to check that it's reserved. - || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) && i.is_reserved()) + // Two qualifiers `$qual $qual` is enough, e.g. `async unsafe`. + || t.is_non_raw_ident_where(|i| QUALS.contains(&i.name) + // Rule out 2015 `const async: T = val`. + && i.is_reserved() + // Rule out unsafe extern block. + && !self.is_unsafe_foreign_mod()) }) // `extern ABI fn` || self.check_keyword(kw::Extern) @@ -1567,9 +1607,9 @@ impl<'a> Parser<'a> { /// up to and including the `fn` keyword. The formal grammar is: /// /// ``` - /// Extern = "extern" StringLit ; + /// Extern = "extern" StringLit? ; /// FnQual = "const"? "async"? "unsafe"? Extern? ; - /// FnFrontMatter = FnQual? "fn" ; + /// FnFrontMatter = FnQual "fn" ; /// ``` pub(super) fn parse_fn_front_matter(&mut self) -> PResult<'a, FnHeader> { let constness = self.parse_constness(); diff --git a/src/librustc_parse/parser/mod.rs b/compiler/rustc_parse/src/parser/mod.rs similarity index 96% rename from src/librustc_parse/parser/mod.rs rename to compiler/rustc_parse/src/parser/mod.rs index 8803e3add4..7340c57448 100644 --- a/src/librustc_parse/parser/mod.rs +++ b/compiler/rustc_parse/src/parser/mod.rs @@ -15,14 +15,14 @@ pub use path::PathStyle; use rustc_ast::ptr::P; use rustc_ast::token::{self, DelimToken, Token, TokenKind}; -use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndJoint}; +use rustc_ast::tokenstream::{self, DelimSpan, TokenStream, TokenTree, TreeAndSpacing}; use rustc_ast::DUMMY_NODE_ID; use rustc_ast::{self as ast, AttrStyle, AttrVec, Const, CrateSugar, Extern, Unsafe}; use rustc_ast::{Async, MacArgs, MacDelimiter, Mutability, StrLit, Visibility, VisibilityKind}; use rustc_ast_pretty::pprust; use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder, FatalError, PResult}; use rustc_session::parse::ParseSess; -use rustc_span::source_map::{respan, Span, DUMMY_SP}; +use rustc_span::source_map::{Span, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use tracing::debug; @@ -118,7 +118,7 @@ impl<'a> Drop for Parser<'a> { struct TokenCursor { frame: TokenCursorFrame, stack: Vec, - cur_token: Option, + cur_token: Option, collecting: Option, } @@ -136,7 +136,7 @@ struct TokenCursorFrame { struct Collecting { /// Holds the current tokens captured during the most /// recent call to `collect_tokens` - buf: Vec, + buf: Vec, /// The depth of the `TokenCursor` stack at the time /// collection was started. When we encounter a `TokenTree::Delimited`, /// we want to record the `TokenTree::Delimited` itself, @@ -167,7 +167,7 @@ impl TokenCursor { let tree = if !self.frame.open_delim { self.frame.open_delim = true; TokenTree::open_tt(self.frame.span, self.frame.delim).into() - } else if let Some(tree) = self.frame.tree_cursor.next_with_joint() { + } else if let Some(tree) = self.frame.tree_cursor.next_with_spacing() { tree } else if !self.frame.close_delim { self.frame.close_delim = true; @@ -1018,21 +1018,30 @@ impl<'a> Parser<'a> { /// If the following element can't be a tuple (i.e., it's a function definition), then /// it's not a tuple struct field), and the contents within the parentheses isn't valid, /// so emit a proper diagnostic. - pub(crate) fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> { + // Public for rustfmt usage. + pub fn parse_visibility(&mut self, fbt: FollowedByType) -> PResult<'a, Visibility> { maybe_whole!(self, NtVis, |x| x); self.expected_tokens.push(TokenType::Keyword(kw::Crate)); if self.is_crate_vis() { self.bump(); // `crate` self.sess.gated_spans.gate(sym::crate_visibility_modifier, self.prev_token.span); - return Ok(respan(self.prev_token.span, VisibilityKind::Crate(CrateSugar::JustCrate))); + return Ok(Visibility { + span: self.prev_token.span, + kind: VisibilityKind::Crate(CrateSugar::JustCrate), + tokens: None, + }); } if !self.eat_keyword(kw::Pub) { // We need a span for our `Spanned`, but there's inherently no // keyword to grab a span from for inherited visibility; an empty span at the // beginning of the current token would seem to be the "Schelling span". - return Ok(respan(self.token.span.shrink_to_lo(), VisibilityKind::Inherited)); + return Ok(Visibility { + span: self.token.span.shrink_to_lo(), + kind: VisibilityKind::Inherited, + tokens: None, + }); } let lo = self.prev_token.span; @@ -1049,7 +1058,11 @@ impl<'a> Parser<'a> { self.bump(); // `crate` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Crate(CrateSugar::PubCrate); - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if self.is_keyword_ahead(1, &[kw::In]) { // Parse `pub(in path)`. self.bump(); // `(` @@ -1057,7 +1070,11 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `path` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if self.look_ahead(2, |t| t == &token::CloseDelim(token::Paren)) && self.is_keyword_ahead(1, &[kw::Super, kw::SelfLower]) { @@ -1066,7 +1083,11 @@ impl<'a> Parser<'a> { let path = self.parse_path(PathStyle::Mod)?; // `super`/`self` self.expect(&token::CloseDelim(token::Paren))?; // `)` let vis = VisibilityKind::Restricted { path: P(path), id: ast::DUMMY_NODE_ID }; - return Ok(respan(lo.to(self.prev_token.span), vis)); + return Ok(Visibility { + span: lo.to(self.prev_token.span), + kind: vis, + tokens: None, + }); } else if let FollowedByType::No = fbt { // Provide this diagnostic if a type cannot follow; // in particular, if this is not a tuple struct. @@ -1075,7 +1096,7 @@ impl<'a> Parser<'a> { } } - Ok(respan(lo, VisibilityKind::Public)) + Ok(Visibility { span: lo, kind: VisibilityKind::Public, tokens: None }) } /// Recovery for e.g. `pub(something) fn ...` or `struct X { pub(something) y: Z }` @@ -1157,7 +1178,7 @@ impl<'a> Parser<'a> { f: impl FnOnce(&mut Self) -> PResult<'a, R>, ) -> PResult<'a, (R, TokenStream)> { // Record all tokens we parse when parsing this item. - let tokens: Vec = self.token_cursor.cur_token.clone().into_iter().collect(); + let tokens: Vec = self.token_cursor.cur_token.clone().into_iter().collect(); debug!("collect_tokens: starting with {:?}", tokens); // We need special handling for the case where `collect_tokens` is called @@ -1237,6 +1258,10 @@ impl<'a> Parser<'a> { *t == token::OpenDelim(token::Brace) || *t == token::BinOp(token::Star) }) } + + pub fn clear_expected_tokens(&mut self) { + self.expected_tokens.clear(); + } } crate fn make_unclosed_delims_error( diff --git a/src/librustc_parse/parser/nonterminal.rs b/compiler/rustc_parse/src/parser/nonterminal.rs similarity index 72% rename from src/librustc_parse/parser/nonterminal.rs rename to compiler/rustc_parse/src/parser/nonterminal.rs index f40cd1131d..15660fd574 100644 --- a/src/librustc_parse/parser/nonterminal.rs +++ b/compiler/rustc_parse/src/parser/nonterminal.rs @@ -111,11 +111,28 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, "expected an item keyword")); } }, - NonterminalKind::Block => token::NtBlock(self.parse_block()?), - NonterminalKind::Stmt => match self.parse_stmt()? { - Some(s) => token::NtStmt(s), - None => return Err(self.struct_span_err(self.token.span, "expected a statement")), - }, + NonterminalKind::Block => { + let (mut block, tokens) = self.collect_tokens(|this| this.parse_block())?; + // We have have eaten an NtBlock, which could already have tokens + if block.tokens.is_none() { + block.tokens = Some(tokens); + } + token::NtBlock(block) + } + NonterminalKind::Stmt => { + let (stmt, tokens) = self.collect_tokens(|this| this.parse_stmt())?; + match stmt { + Some(mut s) => { + if s.tokens.is_none() { + s.tokens = Some(tokens); + } + token::NtStmt(s) + } + None => { + return Err(self.struct_span_err(self.token.span, "expected a statement")); + } + } + } NonterminalKind::Pat => { let (mut pat, tokens) = self.collect_tokens(|this| this.parse_pat(None))?; // We have have eaten an NtPat, which could already have tokens @@ -133,8 +150,23 @@ impl<'a> Parser<'a> { } token::NtExpr(expr) } - NonterminalKind::Literal => token::NtLiteral(self.parse_literal_maybe_minus()?), - NonterminalKind::Ty => token::NtTy(self.parse_ty()?), + NonterminalKind::Literal => { + let (mut lit, tokens) = + self.collect_tokens(|this| this.parse_literal_maybe_minus())?; + // We have have eaten a nonterminal, which could already have tokens + if lit.tokens.is_none() { + lit.tokens = Some(tokens); + } + token::NtLiteral(lit) + } + NonterminalKind::Ty => { + let (mut ty, tokens) = self.collect_tokens(|this| this.parse_ty())?; + // We have an eaten an NtTy, which could already have tokens + if ty.tokens.is_none() { + ty.tokens = Some(tokens); + } + token::NtTy(ty) + } // this could be handled like a token, since it is one NonterminalKind::Ident => { if let Some((ident, is_raw)) = get_macro_ident(&self.token) { @@ -146,10 +178,33 @@ impl<'a> Parser<'a> { return Err(self.struct_span_err(self.token.span, msg)); } } - NonterminalKind::Path => token::NtPath(self.parse_path(PathStyle::Type)?), - NonterminalKind::Meta => token::NtMeta(P(self.parse_attr_item()?)), + NonterminalKind::Path => { + let (mut path, tokens) = + self.collect_tokens(|this| this.parse_path(PathStyle::Type))?; + // We have have eaten an NtPath, which could already have tokens + if path.tokens.is_none() { + path.tokens = Some(tokens); + } + token::NtPath(path) + } + NonterminalKind::Meta => { + let (mut attr, tokens) = self.collect_tokens(|this| this.parse_attr_item())?; + // We may have eaten a nonterminal, which could already have tokens + if attr.tokens.is_none() { + attr.tokens = Some(tokens); + } + token::NtMeta(P(attr)) + } NonterminalKind::TT => token::NtTT(self.parse_token_tree()), - NonterminalKind::Vis => token::NtVis(self.parse_visibility(FollowedByType::Yes)?), + NonterminalKind::Vis => { + let (mut vis, tokens) = + self.collect_tokens(|this| this.parse_visibility(FollowedByType::Yes))?; + // We may have etan an `NtVis`, which could already have tokens + if vis.tokens.is_none() { + vis.tokens = Some(tokens); + } + token::NtVis(vis) + } NonterminalKind::Lifetime => { if self.check_lifetime() { token::NtLifetime(self.expect_lifetime().ident) diff --git a/src/librustc_parse/parser/pat.rs b/compiler/rustc_parse/src/parser/pat.rs similarity index 99% rename from src/librustc_parse/parser/pat.rs rename to compiler/rustc_parse/src/parser/pat.rs index 2c0133a24d..5aced9dc37 100644 --- a/src/librustc_parse/parser/pat.rs +++ b/compiler/rustc_parse/src/parser/pat.rs @@ -795,6 +795,7 @@ impl<'a> Parser<'a> { } self.bump(); let (fields, etc) = self.parse_pat_fields().unwrap_or_else(|mut e| { + e.span_label(path.span, "while parsing the fields for this pattern"); e.emit(); self.recover_stmt(); (vec![], true) @@ -844,7 +845,7 @@ impl<'a> Parser<'a> { // check that a comma comes after every field if !ate_comma { - let err = self.struct_span_err(self.prev_token.span, "expected `,`"); + let err = self.struct_span_err(self.token.span, "expected `,`"); if let Some(mut delayed) = delayed_err { delayed.emit(); } diff --git a/src/librustc_parse/parser/path.rs b/compiler/rustc_parse/src/parser/path.rs similarity index 98% rename from src/librustc_parse/parser/path.rs rename to compiler/rustc_parse/src/parser/path.rs index 54b4df8613..66ce015d02 100644 --- a/src/librustc_parse/parser/path.rs +++ b/compiler/rustc_parse/src/parser/path.rs @@ -64,7 +64,7 @@ impl<'a> Parser<'a> { path_span = path_lo.to(self.prev_token.span); } else { path_span = self.token.span.to(self.token.span); - path = ast::Path { segments: Vec::new(), span: path_span }; + path = ast::Path { segments: Vec::new(), span: path_span, tokens: None }; } // See doc comment for `unmatched_angle_bracket_count`. @@ -81,7 +81,10 @@ impl<'a> Parser<'a> { let qself = QSelf { ty, path_span, position: path.segments.len() }; self.parse_path_segments(&mut path.segments, style)?; - Ok((qself, Path { segments: path.segments, span: lo.to(self.prev_token.span) })) + Ok(( + qself, + Path { segments: path.segments, span: lo.to(self.prev_token.span), tokens: None }, + )) } /// Recover from an invalid single colon, when the user likely meant a qualified path. @@ -144,7 +147,7 @@ impl<'a> Parser<'a> { } self.parse_path_segments(&mut segments, style)?; - Ok(Path { segments, span: lo.to(self.prev_token.span) }) + Ok(Path { segments, span: lo.to(self.prev_token.span), tokens: None }) } pub(super) fn parse_path_segments( diff --git a/src/librustc_parse/parser/stmt.rs b/compiler/rustc_parse/src/parser/stmt.rs similarity index 92% rename from src/librustc_parse/parser/stmt.rs rename to compiler/rustc_parse/src/parser/stmt.rs index ac067cb0ea..fd1c6b25ae 100644 --- a/src/librustc_parse/parser/stmt.rs +++ b/compiler/rustc_parse/src/parser/stmt.rs @@ -10,7 +10,7 @@ use rustc_ast as ast; use rustc_ast::ptr::P; use rustc_ast::token::{self, TokenKind}; use rustc_ast::util::classify; -use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacStmtStyle}; +use rustc_ast::{AttrStyle, AttrVec, Attribute, MacCall, MacCallStmt, MacStmtStyle}; use rustc_ast::{Block, BlockCheckMode, Expr, ExprKind, Local, Stmt, StmtKind, DUMMY_NODE_ID}; use rustc_errors::{Applicability, PResult}; use rustc_span::source_map::{BytePos, Span}; @@ -21,7 +21,8 @@ use std::mem; impl<'a> Parser<'a> { /// Parses a statement. This stops just before trailing semicolons on everything but items. /// e.g., a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed. - pub(super) fn parse_stmt(&mut self) -> PResult<'a, Option> { + // Public for rustfmt usage. + pub fn parse_stmt(&mut self) -> PResult<'a, Option> { Ok(self.parse_stmt_without_recovery().unwrap_or_else(|mut e| { e.emit(); self.recover_stmt_(SemiColonMode::Break, BlockMode::Ignore); @@ -106,7 +107,7 @@ impl<'a> Parser<'a> { let kind = if delim == token::Brace || self.token == token::Semi || self.token == token::Eof { - StmtKind::MacCall(P((mac, style, attrs))) + StmtKind::MacCall(P(MacCallStmt { mac, style, attrs })) } 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()); @@ -363,7 +364,7 @@ impl<'a> Parser<'a> { let mut eat_semi = true; match stmt.kind { // Expression without semicolon. - StmtKind::Expr(ref expr) + StmtKind::Expr(ref mut expr) if self.token != token::Eof && classify::expr_requires_semi_to_be_stmt(expr) => { // Just check for errors and recover; do not eat semicolon yet. @@ -387,15 +388,29 @@ impl<'a> Parser<'a> { ); } } - e.emit(); - self.recover_stmt(); + if let Err(mut e) = + self.check_mistyped_turbofish_with_multiple_type_params(e, expr) + { + e.emit(); + self.recover_stmt(); + } // Don't complain about type errors in body tail after parse error (#57383). let sp = expr.span.to(self.prev_token.span); - stmt.kind = StmtKind::Expr(self.mk_expr_err(sp)); + *expr = self.mk_expr_err(sp); } } - StmtKind::Local(..) => { - self.expect_semi()?; + StmtKind::Local(ref mut local) => { + if let Err(e) = self.expect_semi() { + // We might be at the `,` in `let x = foo;`. Try to recover. + match &mut local.init { + Some(ref mut expr) => { + self.check_mistyped_turbofish_with_multiple_type_params(e, expr)?; + // We found `foo`, have we fully recovered? + self.expect_semi()?; + } + None => return Err(e), + } + } eat_semi = false; } StmtKind::Empty => eat_semi = false, @@ -410,11 +425,11 @@ impl<'a> Parser<'a> { } pub(super) fn mk_block(&self, stmts: Vec, rules: BlockCheckMode, span: Span) -> P { - P(Block { stmts, id: DUMMY_NODE_ID, rules, span }) + P(Block { stmts, id: DUMMY_NODE_ID, rules, span, tokens: None }) } pub(super) fn mk_stmt(&self, span: Span, kind: StmtKind) -> Stmt { - Stmt { id: DUMMY_NODE_ID, kind, span } + Stmt { id: DUMMY_NODE_ID, kind, span, tokens: None } } fn mk_stmt_err(&self, span: Span) -> Stmt { diff --git a/src/librustc_parse/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs similarity index 94% rename from src/librustc_parse/parser/ty.rs rename to compiler/rustc_parse/src/parser/ty.rs index 4356850818..d42a786a18 100644 --- a/src/librustc_parse/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -67,7 +67,7 @@ impl<'a> Parser<'a> { /// Parse a type suitable for a function or function pointer parameter. /// The difference from `parse_ty` is that this version allows `...` - /// (`CVarArgs`) at the top level of the the type. + /// (`CVarArgs`) at the top level of the type. pub(super) fn parse_ty_for_param(&mut self) -> PResult<'a, P> { self.parse_ty_common(AllowPlus::Yes, RecoverQPath::Yes, AllowCVariadic::Yes) } @@ -276,8 +276,34 @@ impl<'a> Parser<'a> { } fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { - let opt_lifetime = if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; + let and_span = self.prev_token.span; + let mut opt_lifetime = + if self.check_lifetime() { Some(self.expect_lifetime()) } else { None }; let mutbl = self.parse_mutability(); + if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() { + // A lifetime is invalid here: it would be part of a bare trait bound, which requires + // it to be followed by a plus, but we disallow plus in the pointee type. + // So we can handle this case as an error here, and suggest `'a mut`. + // If there *is* a plus next though, handling the error later provides better suggestions + // (like adding parentheses) + if !self.look_ahead(1, |t| t.is_like_plus()) { + let lifetime_span = self.token.span; + let span = and_span.to(lifetime_span); + + let mut err = self.struct_span_err(span, "lifetime must precede `mut`"); + if let Ok(lifetime_src) = self.span_to_snippet(lifetime_span) { + err.span_suggestion( + span, + "place the lifetime before `mut`", + format!("&{} mut", lifetime_src), + Applicability::MaybeIncorrect, + ); + } + err.emit(); + + opt_lifetime = Some(self.expect_lifetime()); + } + } let ty = self.parse_ty_no_plus()?; Ok(TyKind::Rptr(opt_lifetime, MutTy { ty, mutbl })) } @@ -626,6 +652,6 @@ impl<'a> Parser<'a> { } pub(super) fn mk_ty(&self, span: Span, kind: TyKind) -> P { - P(Ty { kind, span, id: ast::DUMMY_NODE_ID }) + P(Ty { kind, span, id: ast::DUMMY_NODE_ID, tokens: None }) } } diff --git a/src/librustc_parse/validate_attr.rs b/compiler/rustc_parse/src/validate_attr.rs similarity index 100% rename from src/librustc_parse/validate_attr.rs rename to compiler/rustc_parse/src/validate_attr.rs diff --git a/compiler/rustc_parse_format/Cargo.toml b/compiler/rustc_parse_format/Cargo.toml new file mode 100644 index 0000000000..c2317d91a6 --- /dev/null +++ b/compiler/rustc_parse_format/Cargo.toml @@ -0,0 +1,9 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_parse_format" +version = "0.0.0" +edition = "2018" + +[dependencies] +rustc_span = { path = "../rustc_span" } +rustc_lexer = { path = "../rustc_lexer" } diff --git a/src/librustc_parse_format/lib.rs b/compiler/rustc_parse_format/src/lib.rs similarity index 98% rename from src/librustc_parse_format/lib.rs rename to compiler/rustc_parse_format/src/lib.rs index ebb3aa3866..25e3e67e28 100644 --- a/src/librustc_parse_format/lib.rs +++ b/compiler/rustc_parse_format/src/lib.rs @@ -5,14 +5,12 @@ //! generated instead. #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(deny(warnings))) )] #![feature(nll)] #![feature(or_patterns)] -#![feature(rustc_private)] -#![feature(unicode_internals)] #![feature(bool_to_option)] pub use Alignment::*; @@ -527,12 +525,9 @@ impl<'a> Parser<'a> { // fill character if let Some(&(_, c)) = self.cur.peek() { - match self.cur.clone().nth(1) { - Some((_, '>' | '<' | '^')) => { - spec.fill = Some(c); - self.cur.next(); - } - _ => {} + if let Some((_, '>' | '<' | '^')) = self.cur.clone().nth(1) { + spec.fill = Some(c); + self.cur.next(); } } // Alignment @@ -760,7 +755,7 @@ fn find_skips_from_snippet( (' ' | '\n' | '\t', _) if eat_ws => { skips.push(pos); } - ('\\', Some((next_pos, 'n' | 't' | '0' | '\\' | '\'' | '\"'))) => { + ('\\', Some((next_pos, 'n' | 't' | 'r' | '0' | '\\' | '\'' | '\"'))) => { skips.push(*next_pos); let _ = s.next(); } diff --git a/src/librustc_parse_format/tests.rs b/compiler/rustc_parse_format/src/tests.rs similarity index 100% rename from src/librustc_parse_format/tests.rs rename to compiler/rustc_parse_format/src/tests.rs diff --git a/compiler/rustc_passes/Cargo.toml b/compiler/rustc_passes/Cargo.toml new file mode 100644 index 0000000000..df6667a29d --- /dev/null +++ b/compiler/rustc_passes/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_passes" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.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_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_ast = { path = "../rustc_ast" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_passes/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs similarity index 56% rename from src/librustc_passes/check_attr.rs rename to compiler/rustc_passes/src/check_attr.rs index 832cde86d0..b52216c45c 100644 --- a/src/librustc_passes/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -8,12 +8,12 @@ use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; -use rustc_ast::{Attribute, NestedMetaItem}; -use rustc_errors::struct_span_err; +use rustc_ast::{Attribute, LitKind, NestedMetaItem}; +use rustc_errors::{pluralize, struct_span_err}; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{self, HirId, Item, ItemKind, TraitItem}; +use rustc_hir::{self, FnSig, ForeignItem, ForeignItemKind, HirId, Item, ItemKind, TraitItem}; use rustc_hir::{MethodKind, Target}; use rustc_session::lint::builtin::{CONFLICTING_REPR_HINTS, UNUSED_ATTRIBUTES}; use rustc_session::parse::feature_err; @@ -43,6 +43,12 @@ pub(crate) fn target_from_impl_item<'tcx>( } } +#[derive(Clone, Copy)] +enum ItemLike<'tcx> { + Item(&'tcx Item<'tcx>), + ForeignItem(&'tcx ForeignItem<'tcx>), +} + struct CheckAttrVisitor<'tcx> { tcx: TyCtxt<'tcx>, } @@ -55,7 +61,7 @@ impl CheckAttrVisitor<'tcx> { attrs: &'hir [Attribute], span: &Span, target: Target, - item: Option<&Item<'_>>, + item: Option>, ) { let mut is_valid = true; for attr in attrs { @@ -66,12 +72,28 @@ impl CheckAttrVisitor<'tcx> { } else if self.tcx.sess.check_name(attr, sym::marker) { self.check_marker(attr, span, target) } else if self.tcx.sess.check_name(attr, sym::target_feature) { - self.check_target_feature(attr, span, target) + self.check_target_feature(hir_id, attr, span, target) } else if self.tcx.sess.check_name(attr, sym::track_caller) { self.check_track_caller(&attr.span, attrs, span, target) } else if self.tcx.sess.check_name(attr, sym::doc) { self.check_doc_alias(attr, hir_id, target) + } else if self.tcx.sess.check_name(attr, sym::no_link) { + self.check_no_link(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::export_name) { + self.check_export_name(&attr, span, target) + } else if self.tcx.sess.check_name(attr, sym::rustc_args_required_const) { + self.check_rustc_args_required_const(&attr, span, target, item) } else { + // lint-only checks + if self.tcx.sess.check_name(attr, sym::cold) { + self.check_cold(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::link_name) { + self.check_link_name(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::link_section) { + self.check_link_section(hir_id, attr, span, target); + } else if self.tcx.sess.check_name(attr, sym::no_mangle) { + self.check_no_mangle(hir_id, attr, span, target); + } true }; } @@ -109,12 +131,12 @@ impl CheckAttrVisitor<'tcx> { lint.build("`#[inline]` is ignored on constants") .warn( "this was previously accepted by the compiler but is \ - being phased out; it will become a hard error in \ - a future release!", + being phased out; it will become a hard error in \ + a future release!", ) .note( "see issue #65833 \ - for more information", + for more information", ) .emit(); }); @@ -153,7 +175,7 @@ impl CheckAttrVisitor<'tcx> { .emit(); false } - Target::Fn | Target::Method(..) | Target::ForeignFn => true, + Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => true, _ => { struct_span_err!( self.tcx.sess, @@ -202,10 +224,31 @@ impl CheckAttrVisitor<'tcx> { } /// Checks if the `#[target_feature]` attribute on `item` is valid. Returns `true` if valid. - fn check_target_feature(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + fn check_target_feature( + &self, + hir_id: HirId, + attr: &Attribute, + span: &Span, + target: Target, + ) -> bool { match target { Target::Fn | Target::Method(MethodKind::Trait { body: true } | MethodKind::Inherent) => true, + // FIXME: #[target_feature] was previously erroneously allowed on statements and some + // crates used this, so only emit a warning. + Target::Statement => { + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function") + .emit(); + }); + true + } _ => { self.tcx .sess @@ -217,23 +260,42 @@ impl CheckAttrVisitor<'tcx> { } } + fn doc_alias_str_error(&self, meta: &NestedMetaItem) { + self.tcx + .sess + .struct_span_err( + meta.span(), + "doc alias attribute expects a string: #[doc(alias = \"0\")]", + ) + .emit(); + } + fn check_doc_alias(&self, attr: &Attribute, hir_id: HirId, target: Target) -> bool { if let Some(mi) = attr.meta() { if let Some(list) = mi.meta_item_list() { for meta in list { if meta.has_name(sym::alias) { - if !meta.is_value_str() - || meta - .value_str() - .map(|s| s.to_string()) - .unwrap_or_else(String::new) - .is_empty() + if !meta.is_value_str() { + self.doc_alias_str_error(meta); + return false; + } + let doc_alias = + meta.value_str().map(|s| s.to_string()).unwrap_or_else(String::new); + if doc_alias.is_empty() { + self.doc_alias_str_error(meta); + return false; + } + if let Some(c) = + doc_alias.chars().find(|&c| c == '"' || c == '\'' || c.is_whitespace()) { self.tcx .sess .struct_span_err( meta.span(), - "doc alias attribute expects a string: #[doc(alias = \"0\")]", + &format!( + "{:?} character isn't allowed in `#[doc(alias = \"...\")]`", + c, + ), ) .emit(); return false; @@ -250,15 +312,26 @@ impl CheckAttrVisitor<'tcx> { None } } + Target::AssocConst => { + let parent_hir_id = self.tcx.hir().get_parent_item(hir_id); + let containing_item = self.tcx.hir().expect_item(parent_hir_id); + // We can't link to trait impl's consts. + let err = "associated constant in trait implementation block"; + match containing_item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => Some(err), + _ => None, + } + } _ => None, } { self.tcx .sess .struct_span_err( meta.span(), - &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err,), + &format!("`#[doc(alias = \"...\")]` isn't allowed on {}", err), ) .emit(); + return false; } } } @@ -267,13 +340,208 @@ impl CheckAttrVisitor<'tcx> { true } + /// 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 { + Target::Fn | Target::Method(..) | Target::ForeignFn | Target::Closure => {} + _ => { + // FIXME: #[cold] was previously allowed on non-functions and some crates used + // this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function") + .emit(); + }); + } + } + } + + /// Checks if `#[link_name]` is applied to an item other than a foreign function or static. + fn check_link_name(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::ForeignFn | Target::ForeignStatic => {} + _ => { + // FIXME: #[cold] was previously allowed on non-functions/statics and some crates + // used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + let mut diag = + lint.build("attribute should be applied to a foreign function or static"); + diag.warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ); + + // See issue #47725 + if let Target::ForeignMod = target { + if let Some(value) = attr.value_str() { + diag.span_help( + attr.span, + &format!(r#"try `#[link(name = "{}")]` instead"#, value), + ); + } else { + diag.span_help(attr.span, r#"try `#[link(name = "...")]` instead"#); + } + } + + diag.span_label(*span, "not a foreign function or static"); + diag.emit(); + }); + } + } + } + + /// Checks if `#[no_link]` is applied to an `extern crate`. Returns `true` if valid. + fn check_no_link(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + if target == Target::ExternCrate { + true + } else { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to an `extern crate` item") + .span_label(*span, "not an `extern crate` item") + .emit(); + false + } + } + + /// Checks if `#[export_name]` is applied to a function or static. Returns `true` if valid. + fn check_export_name(&self, attr: &Attribute, span: &Span, target: Target) -> bool { + match target { + Target::Static | Target::Fn | Target::Method(..) => true, + _ => { + self.tcx + .sess + .struct_span_err( + attr.span, + "attribute should be applied to a function or static", + ) + .span_label(*span, "not a function or static") + .emit(); + false + } + } + } + + /// Checks if `#[rustc_args_required_const]` is applied to a function and has a valid argument. + fn check_rustc_args_required_const( + &self, + attr: &Attribute, + span: &Span, + target: Target, + item: Option>, + ) -> bool { + if let Target::Fn | Target::Method(..) | Target::ForeignFn = target { + let mut invalid_args = vec![]; + for meta in attr.meta_item_list().expect("no meta item list") { + if let Some(LitKind::Int(val, _)) = meta.literal().map(|lit| &lit.kind) { + if let Some(ItemLike::Item(Item { + kind: ItemKind::Fn(FnSig { decl, .. }, ..), + .. + })) + | Some(ItemLike::ForeignItem(ForeignItem { + kind: ForeignItemKind::Fn(decl, ..), + .. + })) = item + { + let arg_count = decl.inputs.len() as u128; + if *val >= arg_count { + let span = meta.span(); + self.tcx + .sess + .struct_span_err(span, "index exceeds number of arguments") + .span_label( + span, + format!( + "there {} only {} argument{}", + if arg_count != 1 { "are" } else { "is" }, + arg_count, + pluralize!(arg_count) + ), + ) + .emit(); + return false; + } + } else { + bug!("should be a function item"); + } + } else { + invalid_args.push(meta.span()); + } + } + if !invalid_args.is_empty() { + self.tcx + .sess + .struct_span_err(invalid_args, "arguments should be non-negative integers") + .emit(); + false + } else { + true + } + } else { + self.tcx + .sess + .struct_span_err(attr.span, "attribute should be applied to a function") + .span_label(*span, "not a function") + .emit(); + false + } + } + + /// Checks if `#[link_section]` is applied to a function or static. + fn check_link_section(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::Static | Target::Fn | Target::Method(..) => {} + _ => { + // FIXME: #[link_section] was previously allowed on non-functions/statics and some + // crates used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function or static") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function or static") + .emit(); + }); + } + } + } + + /// Checks if `#[no_mangle]` is applied to a function or static. + fn check_no_mangle(&self, hir_id: HirId, attr: &Attribute, span: &Span, target: Target) { + match target { + Target::Static | Target::Fn | Target::Method(..) => {} + _ => { + // FIXME: #[no_mangle] was previously allowed on non-functions/statics and some + // crates used this, so only emit a warning. + self.tcx.struct_span_lint_hir(UNUSED_ATTRIBUTES, hir_id, attr.span, |lint| { + lint.build("attribute should be applied to a function or static") + .warn( + "this was previously accepted by the compiler but is \ + being phased out; it will become a hard error in \ + a future release!", + ) + .span_label(*span, "not a function or static") + .emit(); + }); + } + } + } + /// Checks if the `#[repr]` attributes on `item` are valid. fn check_repr( &self, attrs: &'hir [Attribute], span: &Span, target: Target, - item: Option<&Item<'_>>, + item: Option>, hir_id: HirId, ) { // Extract the names of all repr hints, e.g., [foo, bar, align] for: @@ -311,7 +579,11 @@ impl CheckAttrVisitor<'tcx> { } sym::simd => { is_simd = true; - if target != Target::Struct { ("a", "struct") } else { continue } + if target != Target::Struct { + ("a", "struct") + } else { + continue; + } } sym::transparent => { is_transparent = true; @@ -348,7 +620,11 @@ impl CheckAttrVisitor<'tcx> { | sym::isize | sym::usize => { int_reprs += 1; - if target != Target::Enum { ("an", "enum") } else { continue } + if target != Target::Enum { + ("an", "enum") + } else { + continue; + } } _ => continue, }; @@ -381,7 +657,14 @@ impl CheckAttrVisitor<'tcx> { // Warn on repr(u8, u16), repr(C, simd), and c-like-enum-repr(C, u8) if (int_reprs > 1) || (is_simd && is_c) - || (int_reprs == 1 && is_c && item.map_or(false, |item| is_c_like_enum(item))) + || (int_reprs == 1 + && is_c + && item.map_or(false, |item| { + if let ItemLike::Item(item) = item { + return is_c_like_enum(item); + } + return false; + })) { self.tcx.struct_span_lint_hir( CONFLICTING_REPR_HINTS, @@ -411,10 +694,8 @@ impl CheckAttrVisitor<'tcx> { fn check_stmt_attributes(&self, stmt: &hir::Stmt<'_>) { // When checking statements ignore expressions, they will be checked later if let hir::StmtKind::Local(ref l) = stmt.kind { + self.check_attributes(l.hir_id, &l.attrs, &stmt.span, Target::Statement, None); for attr in l.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(l.hir_id, attr, &stmt.span, Target::Statement); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, @@ -432,10 +713,8 @@ impl CheckAttrVisitor<'tcx> { hir::ExprKind::Closure(..) => Target::Closure, _ => Target::Expression, }; + self.check_attributes(expr.hir_id, &expr.attrs, &expr.span, target, None); for attr in expr.attrs.iter() { - if self.tcx.sess.check_name(attr, sym::inline) { - self.check_inline(expr.hir_id, attr, &expr.span, target); - } if self.tcx.sess.check_name(attr, sym::repr) { self.emit_repr_error( attr.span, @@ -470,7 +749,13 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { fn visit_item(&mut self, item: &'tcx Item<'tcx>) { let target = Target::from_item(item); - self.check_attributes(item.hir_id, item.attrs, &item.span, target, Some(item)); + self.check_attributes( + item.hir_id, + item.attrs, + &item.span, + target, + Some(ItemLike::Item(item)), + ); intravisit::walk_item(self, item) } @@ -480,9 +765,15 @@ impl Visitor<'tcx> for CheckAttrVisitor<'tcx> { intravisit::walk_trait_item(self, trait_item) } - fn visit_foreign_item(&mut self, f_item: &'tcx hir::ForeignItem<'tcx>) { + fn visit_foreign_item(&mut self, f_item: &'tcx ForeignItem<'tcx>) { let target = Target::from_foreign_item(f_item); - self.check_attributes(f_item.hir_id, &f_item.attrs, &f_item.span, target, None); + self.check_attributes( + f_item.hir_id, + &f_item.attrs, + &f_item.span, + target, + Some(ItemLike::ForeignItem(f_item)), + ); intravisit::walk_foreign_item(self, f_item) } diff --git a/src/librustc_passes/check_const.rs b/compiler/rustc_passes/src/check_const.rs similarity index 100% rename from src/librustc_passes/check_const.rs rename to compiler/rustc_passes/src/check_const.rs diff --git a/src/librustc_passes/dead.rs b/compiler/rustc_passes/src/dead.rs similarity index 98% rename from src/librustc_passes/dead.rs rename to compiler/rustc_passes/src/dead.rs index 01da33ddd2..98ded4189c 100644 --- a/src/librustc_passes/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -104,7 +104,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { if let Some(t) = t { self.check_def_id(t); } - if let Some(i) = i { + if let Some((i, _)) = i { self.check_def_id(i); } } @@ -124,7 +124,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { } fn handle_field_access(&mut self, lhs: &hir::Expr<'_>, hir_id: hir::HirId) { - match self.typeck_results().expr_ty_adjusted(lhs).kind { + match self.typeck_results().expr_ty_adjusted(lhs).kind() { ty::Adt(def, _) => { let index = self.tcx.field_index(hir_id, self.typeck_results()); self.insert_def_id(def.non_enum_variant().fields[index].did); @@ -140,7 +140,7 @@ impl<'tcx> MarkSymbolVisitor<'tcx> { res: Res, pats: &[hir::FieldPat<'_>], ) { - let variant = match self.typeck_results().node_type(lhs.hir_id).kind { + let variant = match self.typeck_results().node_type(lhs.hir_id).kind() { ty::Adt(adt, _) => adt.variant_of_res(res), _ => span_bug!(lhs.span, "non-ADT in struct pattern"), }; @@ -269,7 +269,7 @@ impl<'tcx> Visitor<'tcx> for MarkSymbolVisitor<'tcx> { hir::ExprKind::Struct(ref qpath, ref fields, _) => { let res = self.typeck_results().qpath_res(qpath, expr.hir_id); self.handle_res(res); - if let ty::Adt(ref adt, _) = self.typeck_results().expr_ty(expr).kind { + if let ty::Adt(ref adt, _) = self.typeck_results().expr_ty(expr).kind() { self.mark_as_used_if_union(adt, fields); } } @@ -369,7 +369,7 @@ fn has_allow_dead_code_or_lang_attr( // - This is because lang items are always callable from elsewhere. // or // 2) We are not sure to be live or not -// * Implementation of a trait method +// * Implementations of traits and trait methods struct LifeSeeder<'k, 'tcx> { worklist: Vec, krate: &'k hir::Crate<'k>, @@ -415,6 +415,9 @@ impl<'v, 'k, 'tcx> ItemLikeVisitor<'v> for LifeSeeder<'k, 'tcx> { } } hir::ItemKind::Impl { ref of_trait, items, .. } => { + if of_trait.is_some() { + self.worklist.push(item.hir_id); + } for impl_item_ref in items { let impl_item = self.krate.impl_item(impl_item_ref.id); if of_trait.is_some() diff --git a/src/librustc_passes/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs similarity index 87% rename from src/librustc_passes/diagnostic_items.rs rename to compiler/rustc_passes/src/diagnostic_items.rs index df0f9f157a..94592935c7 100644 --- a/src/librustc_passes/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -12,11 +12,11 @@ use rustc_ast as ast; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; -use rustc_hir::def_id::{DefId, LOCAL_CRATE}; use rustc_hir::itemlikevisit::ItemLikeVisitor; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::Session; +use rustc_span::def_id::{DefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; struct DiagnosticItemCollector<'tcx> { @@ -100,6 +100,18 @@ fn collect<'tcx>(tcx: TyCtxt<'tcx>) -> FxHashMap { // Collect diagnostic items in this crate. tcx.hir().krate().visit_all_item_likes(&mut collector); + // FIXME(visit_all_item_likes): Foreign items are not visited + // here, so we have to manually look at them for now. + for foreign_module in tcx.foreign_modules(LOCAL_CRATE) { + for &foreign_item in foreign_module.foreign_items.iter() { + match tcx.hir().get(tcx.hir().local_def_id_to_hir_id(foreign_item.expect_local())) { + hir::Node::ForeignItem(item) => { + collector.observe_item(item.attrs, item.hir_id); + } + item => bug!("unexpected foreign item {:?}", item), + } + } + } collector.items } diff --git a/src/librustc_passes/entry.rs b/compiler/rustc_passes/src/entry.rs similarity index 100% rename from src/librustc_passes/entry.rs rename to compiler/rustc_passes/src/entry.rs diff --git a/src/librustc_passes/hir_id_validator.rs b/compiler/rustc_passes/src/hir_id_validator.rs similarity index 98% rename from src/librustc_passes/hir_id_validator.rs rename to compiler/rustc_passes/src/hir_id_validator.rs index 2edbc29b7e..24695f5cdf 100644 --- a/src/librustc_passes/hir_id_validator.rs +++ b/compiler/rustc_passes/src/hir_id_validator.rs @@ -112,14 +112,14 @@ impl<'a, 'hir> HirIdValidator<'a, 'hir> { missing_items.push(format!( "[local_id: {}, owner: {}]", local_id, - self.hir_map.def_path(owner).to_string_no_crate() + self.hir_map.def_path(owner).to_string_no_crate_verbose() )); } self.error(|| { format!( "ItemLocalIds not assigned densely in {}. \ Max ItemLocalId = {}, missing IDs = {:?}; seens IDs = {:?}", - self.hir_map.def_path(owner).to_string_no_crate(), + self.hir_map.def_path(owner).to_string_no_crate_verbose(), max, missing_items, self.hir_ids_seen @@ -148,8 +148,8 @@ impl<'a, 'hir> intravisit::Visitor<'hir> for HirIdValidator<'a, 'hir> { format!( "HirIdValidator: The recorded owner of {} is {} instead of {}", self.hir_map.node_to_string(hir_id), - self.hir_map.def_path(hir_id.owner).to_string_no_crate(), - self.hir_map.def_path(owner).to_string_no_crate() + self.hir_map.def_path(hir_id.owner).to_string_no_crate_verbose(), + self.hir_map.def_path(owner).to_string_no_crate_verbose() ) }); } diff --git a/src/librustc_passes/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs similarity index 100% rename from src/librustc_passes/hir_stats.rs rename to compiler/rustc_passes/src/hir_stats.rs diff --git a/src/librustc_passes/intrinsicck.rs b/compiler/rustc_passes/src/intrinsicck.rs similarity index 98% rename from src/librustc_passes/intrinsicck.rs rename to compiler/rustc_passes/src/intrinsicck.rs index ebe231009d..79f1c2b9da 100644 --- a/src/librustc_passes/intrinsicck.rs +++ b/compiler/rustc_passes/src/intrinsicck.rs @@ -35,7 +35,7 @@ struct ExprVisitor<'tcx> { /// If the type is `Option`, it will return `T`, otherwise /// the type itself. Works on most `Option`-like types. fn unpack_option_like<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Ty<'tcx> { - let (def, substs) = match ty.kind { + let (def, substs) = match *ty.kind() { ty::Adt(def, substs) => (def, substs), _ => return ty, }; @@ -81,7 +81,7 @@ impl ExprVisitor<'tcx> { // Special-case transmutting from `typeof(function)` and // `Option` to present a clearer error. let from = unpack_option_like(self.tcx, from); - if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (&from.kind, sk_to) { + if let (&ty::FnDef(..), SizeSkeleton::Known(size_to)) = (from.kind(), sk_to) { if size_to == Pointer.size(&self.tcx) { struct_span_err!(self.tcx.sess, span, E0591, "can't transmute zero-sized type") .note(&format!("source type: {}", from)) @@ -127,7 +127,7 @@ impl ExprVisitor<'tcx> { if ty.is_sized(self.tcx.at(DUMMY_SP), self.param_env) { return true; } - if let ty::Foreign(..) = ty.kind { + if let ty::Foreign(..) = ty.kind() { return true; } false @@ -149,7 +149,7 @@ impl ExprVisitor<'tcx> { 64 => InlineAsmType::I64, _ => unreachable!(), }; - let asm_ty = match ty.kind { + let asm_ty = match *ty.kind() { ty::Never | ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => Some(InlineAsmType::I8), ty::Int(IntTy::I16) | ty::Uint(UintTy::U16) => Some(InlineAsmType::I16), @@ -166,7 +166,7 @@ impl ExprVisitor<'tcx> { ty::Adt(adt, substs) if adt.repr.simd() => { let fields = &adt.non_enum_variant().fields; let elem_ty = fields[0].ty(self.tcx, substs); - match elem_ty.kind { + match elem_ty.kind() { ty::Never | ty::Error(_) => return None, ty::Int(IntTy::I8) | ty::Uint(UintTy::U8) => { Some(InlineAsmType::VecI8(fields.len() as u64)) @@ -374,7 +374,7 @@ impl ExprVisitor<'tcx> { } hir::InlineAsmOperand::Const { ref expr } => { let ty = self.typeck_results.expr_ty_adjusted(expr); - match ty.kind { + match ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) => {} _ => { let msg = diff --git a/src/librustc_passes/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs similarity index 100% rename from src/librustc_passes/lang_items.rs rename to compiler/rustc_passes/src/lang_items.rs diff --git a/src/librustc_passes/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs similarity index 100% rename from src/librustc_passes/layout_test.rs rename to compiler/rustc_passes/src/layout_test.rs diff --git a/src/librustc_passes/lib.rs b/compiler/rustc_passes/src/lib.rs similarity index 90% rename from src/librustc_passes/lib.rs rename to compiler/rustc_passes/src/lib.rs index be4c542ec3..c32c9c8eaa 100644 --- a/src/librustc_passes/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -4,7 +4,9 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(const_fn)] +#![feature(const_panic)] #![feature(in_band_lifetimes)] #![feature(nll)] #![feature(or_patterns)] diff --git a/src/librustc_passes/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs similarity index 100% rename from src/librustc_passes/lib_features.rs rename to compiler/rustc_passes/src/lib_features.rs diff --git a/src/librustc_passes/liveness.rs b/compiler/rustc_passes/src/liveness.rs similarity index 79% rename from src/librustc_passes/liveness.rs rename to compiler/rustc_passes/src/liveness.rs index de21f0b5e0..e8b97d7dc7 100644 --- a/src/librustc_passes/liveness.rs +++ b/compiler/rustc_passes/src/liveness.rs @@ -62,13 +62,13 @@ //! - `reader`: the `LiveNode` ID of some node which will read the value //! that `V` holds on entry to `N`. Formally: a node `M` such //! that there exists a path `P` from `N` to `M` where `P` does not -//! write `V`. If the `reader` is `invalid_node()`, then the current +//! write `V`. If the `reader` is `None`, then the current //! value will never be read (the variable is dead, essentially). //! //! - `writer`: the `LiveNode` ID of some node which will write the //! variable `V` and which is reachable from `N`. Formally: a node `M` //! such that there exists a path `P` from `N` to `M` and `M` writes -//! `V`. If the `writer` is `invalid_node()`, then there is no writer +//! `V`. If the `writer` is `None`, then there is no writer //! of `V` that follows `N`. //! //! - `used`: a boolean value indicating whether `V` is *used*. We @@ -79,7 +79,7 @@ //! ## Special nodes and variables //! //! We generate various special nodes for various, well, special purposes. -//! These are described in the `Specials` struct. +//! These are described in the `Liveness` struct. use self::LiveNodeKind::*; use self::VarKind::*; @@ -90,36 +90,30 @@ use rustc_errors::Applicability; use rustc_hir as hir; use rustc_hir::def::*; use rustc_hir::def_id::LocalDefId; -use rustc_hir::intravisit::{self, FnKind, NestedVisitorMap, Visitor}; -use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet, Node}; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::{Expr, HirId, HirIdMap, HirIdSet}; +use rustc_index::vec::IndexVec; use rustc_middle::hir::map::Map; use rustc_middle::ty::query::Providers; -use rustc_middle::ty::{self, TyCtxt}; +use rustc_middle::ty::{self, DefIdTree, TyCtxt}; use rustc_session::lint; -use rustc_span::symbol::{sym, Symbol}; +use rustc_span::symbol::{kw, sym, Symbol}; use rustc_span::Span; use std::collections::VecDeque; -use std::fmt; use std::io; use std::io::prelude::*; use std::rc::Rc; -#[derive(Copy, Clone, PartialEq)] -struct Variable(u32); - -#[derive(Copy, Clone, PartialEq)] -struct LiveNode(u32); - -impl Variable { - fn get(&self) -> usize { - self.0 as usize +rustc_index::newtype_index! { + pub struct Variable { + DEBUG_FORMAT = "v({})", } } -impl LiveNode { - fn get(&self) -> usize { - self.0 as usize +rustc_index::newtype_index! { + pub struct LiveNode { + DEBUG_FORMAT = "ln({})", } } @@ -143,58 +137,14 @@ fn live_node_kind_to_string(lnk: LiveNodeKind, tcx: TyCtxt<'_>) -> String { } } -impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { - type Map = Map<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::OnlyBodies(self.tcx.hir()) - } - - fn visit_fn( - &mut self, - fk: FnKind<'tcx>, - fd: &'tcx hir::FnDecl<'tcx>, - b: hir::BodyId, - s: Span, - id: HirId, - ) { - visit_fn(self, fk, fd, b, s, id); - } - - fn visit_local(&mut self, l: &'tcx hir::Local<'tcx>) { - visit_local(self, l); - } - fn visit_expr(&mut self, ex: &'tcx Expr<'tcx>) { - visit_expr(self, ex); - } - fn visit_arm(&mut self, a: &'tcx hir::Arm<'tcx>) { - visit_arm(self, a); - } -} - fn check_mod_liveness(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module( - module_def_id, - &mut IrMaps::new(tcx, module_def_id).as_deep_visitor(), - ); + tcx.hir().visit_item_likes_in_module(module_def_id, &mut IrMaps::new(tcx).as_deep_visitor()); } pub fn provide(providers: &mut Providers) { *providers = Providers { check_mod_liveness, ..*providers }; } -impl fmt::Debug for LiveNode { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "ln({})", self.get()) - } -} - -impl fmt::Debug for Variable { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "v({})", self.get()) - } -} - // ______________________________________________________________________ // Creating ir_maps // @@ -217,16 +167,6 @@ impl fmt::Debug for Variable { // variable must not be assigned if there is some successor // assignment. And so forth. -impl LiveNode { - fn is_valid(&self) -> bool { - self.0 != u32::MAX - } -} - -fn invalid_node() -> LiveNode { - LiveNode(u32::MAX) -} - struct CaptureInfo { ln: LiveNode, var_hid: HirId, @@ -248,35 +188,27 @@ enum VarKind { struct IrMaps<'tcx> { tcx: TyCtxt<'tcx>, - body_owner: LocalDefId, - num_live_nodes: usize, - num_vars: usize, live_node_map: HirIdMap, variable_map: HirIdMap, capture_info_map: HirIdMap>>, - var_kinds: Vec, - lnks: Vec, + var_kinds: IndexVec, + lnks: IndexVec, } impl IrMaps<'tcx> { - fn new(tcx: TyCtxt<'tcx>, body_owner: LocalDefId) -> IrMaps<'tcx> { + fn new(tcx: TyCtxt<'tcx>) -> IrMaps<'tcx> { IrMaps { tcx, - body_owner, - num_live_nodes: 0, - num_vars: 0, live_node_map: HirIdMap::default(), variable_map: HirIdMap::default(), capture_info_map: Default::default(), - var_kinds: Vec::new(), - lnks: Vec::new(), + var_kinds: IndexVec::new(), + lnks: IndexVec::new(), } } fn add_live_node(&mut self, lnk: LiveNodeKind) -> LiveNode { - let ln = LiveNode(self.num_live_nodes as u32); - self.lnks.push(lnk); - self.num_live_nodes += 1; + let ln = self.lnks.push(lnk); debug!("{:?} is of kind {}", ln, live_node_kind_to_string(lnk, self.tcx)); @@ -291,9 +223,7 @@ impl IrMaps<'tcx> { } fn add_variable(&mut self, vk: VarKind) -> Variable { - let v = Variable(self.num_vars as u32); - self.var_kinds.push(vk); - self.num_vars += 1; + let v = self.var_kinds.push(vk); match vk { Local(LocalInfo { id: node_id, .. }) | Param(node_id, _) | Upvar(node_id, _) => { @@ -315,14 +245,14 @@ impl IrMaps<'tcx> { } } - fn variable_name(&self, var: Variable) -> String { - match self.var_kinds[var.get()] { - Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name.to_string(), + fn variable_name(&self, var: Variable) -> Symbol { + match self.var_kinds[var] { + Local(LocalInfo { name, .. }) | Param(_, name) | Upvar(_, name) => name, } } fn variable_is_shorthand(&self, var: Variable) -> bool { - match self.var_kinds[var.get()] { + match self.var_kinds[var] { Local(LocalInfo { is_shorthand, .. }) => is_shorthand, Param(..) | Upvar(..) => false, } @@ -332,203 +262,192 @@ impl IrMaps<'tcx> { self.capture_info_map.insert(hir_id, Rc::new(cs)); } - fn lnk(&self, ln: LiveNode) -> LiveNodeKind { - self.lnks[ln.get()] + fn add_from_pat(&mut self, pat: &hir::Pat<'tcx>) { + // 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 { + Binding(.., inner_pat) => { + 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); + } + Ref(inner_pat, _) | Box(inner_pat) => { + pats.push_back(inner_pat); + } + TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => { + pats.extend(inner_pats.iter()); + } + Slice(pre_pats, inner_pat, post_pats) => { + pats.extend(pre_pats.iter()); + pats.extend(inner_pat.iter()); + pats.extend(post_pats.iter()); + } + _ => {} + } + } + + pat.each_binding(|_, hir_id, _, ident| { + self.add_live_node_for_node(hir_id, VarDefNode(ident.span)); + self.add_variable(Local(LocalInfo { + id: hir_id, + name: ident.name, + is_shorthand: shorthand_field_ids.contains(&hir_id), + })); + }); } } -fn visit_fn<'tcx>( - ir: &mut IrMaps<'tcx>, - fk: FnKind<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - body_id: hir::BodyId, - sp: Span, - id: hir::HirId, -) { - debug!("visit_fn {:?}", id); +impl<'tcx> Visitor<'tcx> for IrMaps<'tcx> { + type Map = Map<'tcx>; - // swap in a new set of IR maps for this function body: - let def_id = ir.tcx.hir().local_def_id(id); - let mut fn_maps = IrMaps::new(ir.tcx, def_id); + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::OnlyBodies(self.tcx.hir()) + } - // Don't run unused pass for #[derive()] - if let FnKind::Method(..) = fk { - let parent = ir.tcx.hir().get_parent_item(id); - if let Some(Node::Item(i)) = ir.tcx.hir().find(parent) { - if i.attrs.iter().any(|a| ir.tcx.sess.check_name(a, sym::automatically_derived)) { - return; + fn visit_body(&mut self, body: &'tcx hir::Body<'tcx>) { + debug!("visit_body {:?}", body.id()); + + // swap in a new set of IR maps for this body + let mut maps = IrMaps::new(self.tcx); + let hir_id = maps.tcx.hir().body_owner(body.id()); + let def_id = maps.tcx.hir().local_def_id(hir_id); + + // Don't run unused pass for #[derive()] + if let Some(parent) = self.tcx.parent(def_id.to_def_id()) { + if let DefKind::Impl = self.tcx.def_kind(parent.expect_local()) { + if self.tcx.has_attr(parent, sym::automatically_derived) { + return; + } } } - } - debug!("creating fn_maps: {:p}", &fn_maps); - - let body = ir.tcx.hir().body(body_id); - - if let Some(upvars) = ir.tcx.upvars_mentioned(def_id) { - for (&var_hir_id, _upvar) in upvars { - debug!("adding upvar {:?}", var_hir_id); - let var_name = ir.tcx.hir().name(var_hir_id); - fn_maps.add_variable(Upvar(var_hir_id, var_name)); + if let Some(upvars) = maps.tcx.upvars_mentioned(def_id) { + for (&var_hir_id, _upvar) in upvars { + let var_name = maps.tcx.hir().name(var_hir_id); + maps.add_variable(Upvar(var_hir_id, var_name)); + } } + + // gather up the various local variables, significant expressions, + // and so forth: + intravisit::walk_body(&mut maps, body); + + // compute liveness + let mut lsets = Liveness::new(&mut maps, def_id); + let entry_ln = lsets.compute(&body, hir_id); + lsets.log_liveness(entry_ln, body.id().hir_id); + + // check for various error conditions + lsets.visit_body(body); + lsets.warn_about_unused_upvars(entry_ln); + lsets.warn_about_unused_args(body, entry_ln); } - for param in body.params { + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + self.add_from_pat(&local.pat); + intravisit::walk_local(self, local); + } + + fn visit_arm(&mut self, arm: &'tcx hir::Arm<'tcx>) { + self.add_from_pat(&arm.pat); + intravisit::walk_arm(self, arm); + } + + fn visit_param(&mut self, param: &'tcx hir::Param<'tcx>) { let is_shorthand = match param.pat.kind { rustc_hir::PatKind::Struct(..) => true, _ => false, }; param.pat.each_binding(|_bm, hir_id, _x, ident| { - debug!("adding parameters {:?}", hir_id); let var = if is_shorthand { Local(LocalInfo { id: hir_id, name: ident.name, is_shorthand: true }) } else { Param(hir_id, ident.name) }; - fn_maps.add_variable(var); - }) + self.add_variable(var); + }); + intravisit::walk_param(self, param); } - // gather up the various local variables, significant expressions, - // and so forth: - intravisit::walk_fn(&mut fn_maps, fk, decl, body_id, sp, id); - - // compute liveness - let mut lsets = Liveness::new(&mut fn_maps, def_id); - let entry_ln = lsets.compute(fk, &body, sp, id); - lsets.log_liveness(entry_ln, id); - - // check for various error conditions - lsets.visit_body(body); - lsets.warn_about_unused_upvars(entry_ln); - lsets.warn_about_unused_args(body, entry_ln); -} - -fn add_from_pat(ir: &mut IrMaps<'_>, pat: &hir::Pat<'_>) { - // 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 { - Binding(.., inner_pat) => { - pats.extend(inner_pat.iter()); + fn visit_expr(&mut self, expr: &'tcx Expr<'tcx>) { + match expr.kind { + // live nodes required for uses or definitions of variables: + hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { + debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); + if let Res::Local(_var_hir_id) = path.res { + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + } + intravisit::walk_expr(self, expr); } - Struct(_, fields, _) => { - let ids = fields.iter().filter(|f| f.is_shorthand).map(|f| f.pat.hir_id); - shorthand_field_ids.extend(ids); + hir::ExprKind::Closure(..) => { + // Interesting control flow (for loops can contain labeled + // breaks or continues) + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + + // Make a live_node for each captured variable, with the span + // being the location that the variable is used. This results + // in better error messages than just pointing at the closure + // construction site. + let mut call_caps = Vec::new(); + let closure_def_id = self.tcx.hir().local_def_id(expr.hir_id); + if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { + call_caps.extend(upvars.iter().map(|(&var_id, upvar)| { + let upvar_ln = self.add_live_node(UpvarNode(upvar.span)); + CaptureInfo { ln: upvar_ln, var_hid: var_id } + })); + } + self.set_captures(expr.hir_id, call_caps); + intravisit::walk_expr(self, expr); } - Ref(inner_pat, _) | Box(inner_pat) => { - pats.push_back(inner_pat); + + // live nodes required for interesting control flow: + hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => { + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + intravisit::walk_expr(self, expr); } - TupleStruct(_, inner_pats, _) | Tuple(inner_pats, _) | Or(inner_pats) => { - pats.extend(inner_pats.iter()); + hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { + self.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); + intravisit::walk_expr(self, expr); } - Slice(pre_pats, inner_pat, post_pats) => { - pats.extend(pre_pats.iter()); - pats.extend(inner_pat.iter()); - pats.extend(post_pats.iter()); + + // otherwise, live nodes are not required: + hir::ExprKind::Index(..) + | hir::ExprKind::Field(..) + | hir::ExprKind::Array(..) + | hir::ExprKind::Call(..) + | hir::ExprKind::MethodCall(..) + | hir::ExprKind::Tup(..) + | hir::ExprKind::Binary(..) + | hir::ExprKind::AddrOf(..) + | hir::ExprKind::Cast(..) + | hir::ExprKind::DropTemps(..) + | hir::ExprKind::Unary(..) + | hir::ExprKind::Break(..) + | hir::ExprKind::Continue(_) + | hir::ExprKind::Lit(_) + | hir::ExprKind::Ret(..) + | hir::ExprKind::Block(..) + | hir::ExprKind::Assign(..) + | hir::ExprKind::AssignOp(..) + | hir::ExprKind::Struct(..) + | hir::ExprKind::Repeat(..) + | hir::ExprKind::InlineAsm(..) + | hir::ExprKind::LlvmInlineAsm(..) + | hir::ExprKind::Box(..) + | hir::ExprKind::Yield(..) + | hir::ExprKind::Type(..) + | hir::ExprKind::Err + | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) + | hir::ExprKind::Path(hir::QPath::LangItem(..)) => { + intravisit::walk_expr(self, expr); } - _ => {} - } - } - - pat.each_binding(|_, hir_id, _, ident| { - ir.add_live_node_for_node(hir_id, VarDefNode(ident.span)); - ir.add_variable(Local(LocalInfo { - id: hir_id, - name: ident.name, - is_shorthand: shorthand_field_ids.contains(&hir_id), - })); - }); -} - -fn visit_local<'tcx>(ir: &mut IrMaps<'tcx>, local: &'tcx hir::Local<'tcx>) { - add_from_pat(ir, &local.pat); - intravisit::walk_local(ir, local); -} - -fn visit_arm<'tcx>(ir: &mut IrMaps<'tcx>, arm: &'tcx hir::Arm<'tcx>) { - add_from_pat(ir, &arm.pat); - intravisit::walk_arm(ir, arm); -} - -fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { - match expr.kind { - // live nodes required for uses or definitions of variables: - hir::ExprKind::Path(hir::QPath::Resolved(_, ref path)) => { - debug!("expr {}: path that leads to {:?}", expr.hir_id, path.res); - if let Res::Local(_var_hir_id) = path.res { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - } - intravisit::walk_expr(ir, expr); - } - hir::ExprKind::Closure(..) => { - // Interesting control flow (for loops can contain labeled - // breaks or continues) - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - - // Make a live_node for each captured variable, with the span - // being the location that the variable is used. This results - // in better error messages than just pointing at the closure - // construction site. - let mut call_caps = Vec::new(); - let closure_def_id = ir.tcx.hir().local_def_id(expr.hir_id); - if let Some(upvars) = ir.tcx.upvars_mentioned(closure_def_id) { - call_caps.extend(upvars.iter().map(|(&var_id, upvar)| { - let upvar_ln = ir.add_live_node(UpvarNode(upvar.span)); - CaptureInfo { ln: upvar_ln, var_hid: var_id } - })); - } - ir.set_captures(expr.hir_id, call_caps); - let old_body_owner = ir.body_owner; - ir.body_owner = closure_def_id; - intravisit::walk_expr(ir, expr); - ir.body_owner = old_body_owner; - } - - // live nodes required for interesting control flow: - hir::ExprKind::Match(..) | hir::ExprKind::Loop(..) => { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - intravisit::walk_expr(ir, expr); - } - hir::ExprKind::Binary(op, ..) if op.node.is_lazy() => { - ir.add_live_node_for_node(expr.hir_id, ExprNode(expr.span)); - intravisit::walk_expr(ir, expr); - } - - // otherwise, live nodes are not required: - hir::ExprKind::Index(..) - | hir::ExprKind::Field(..) - | hir::ExprKind::Array(..) - | hir::ExprKind::Call(..) - | hir::ExprKind::MethodCall(..) - | hir::ExprKind::Tup(..) - | hir::ExprKind::Binary(..) - | hir::ExprKind::AddrOf(..) - | hir::ExprKind::Cast(..) - | hir::ExprKind::DropTemps(..) - | hir::ExprKind::Unary(..) - | hir::ExprKind::Break(..) - | hir::ExprKind::Continue(_) - | hir::ExprKind::Lit(_) - | hir::ExprKind::Ret(..) - | hir::ExprKind::Block(..) - | hir::ExprKind::Assign(..) - | hir::ExprKind::AssignOp(..) - | hir::ExprKind::Struct(..) - | hir::ExprKind::Repeat(..) - | hir::ExprKind::InlineAsm(..) - | hir::ExprKind::LlvmInlineAsm(..) - | hir::ExprKind::Box(..) - | hir::ExprKind::Yield(..) - | hir::ExprKind::Type(..) - | hir::ExprKind::Err - | hir::ExprKind::Path(hir::QPath::TypeRelative(..)) - | hir::ExprKind::Path(hir::QPath::LangItem(..)) => { - intravisit::walk_expr(ir, expr); } } } @@ -541,8 +460,8 @@ fn visit_expr<'tcx>(ir: &mut IrMaps<'tcx>, expr: &'tcx Expr<'tcx>) { #[derive(Clone, Copy)] struct RWU { - reader: LiveNode, - writer: LiveNode, + reader: Option, + writer: Option, used: bool, } @@ -564,10 +483,10 @@ struct RWUTable { unpacked_rwus: Vec, } -// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: false }`. +// A constant representing `RWU { reader: None; writer: None; used: false }`. const INV_INV_FALSE: u32 = u32::MAX; -// A constant representing `RWU { reader: invalid_node(); writer: invalid_node(); used: true }`. +// A constant representing `RWU { reader: None; writer: None; used: true }`. const INV_INV_TRUE: u32 = u32::MAX - 1; impl RWUTable { @@ -578,24 +497,24 @@ impl RWUTable { fn get(&self, idx: usize) -> RWU { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE => RWU { reader: invalid_node(), writer: invalid_node(), used: false }, - INV_INV_TRUE => RWU { reader: invalid_node(), writer: invalid_node(), used: true }, + INV_INV_FALSE => RWU { reader: None, writer: None, used: false }, + INV_INV_TRUE => RWU { reader: None, writer: None, used: true }, _ => self.unpacked_rwus[packed_rwu as usize], } } - fn get_reader(&self, idx: usize) -> LiveNode { + fn get_reader(&self, idx: usize) -> Option { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => invalid_node(), + INV_INV_FALSE | INV_INV_TRUE => None, _ => self.unpacked_rwus[packed_rwu as usize].reader, } } - fn get_writer(&self, idx: usize) -> LiveNode { + fn get_writer(&self, idx: usize) -> Option { let packed_rwu = self.packed_rwus[idx]; match packed_rwu { - INV_INV_FALSE | INV_INV_TRUE => invalid_node(), + INV_INV_FALSE | INV_INV_TRUE => None, _ => self.unpacked_rwus[packed_rwu as usize].writer, } } @@ -615,7 +534,7 @@ impl RWUTable { } fn assign_unpacked(&mut self, idx: usize, rwu: RWU) { - if rwu.reader == invalid_node() && rwu.writer == invalid_node() { + if rwu.reader == None && rwu.writer == None { // When we overwrite an indexing entry in `self.packed_rwus` with // `INV_INV_{TRUE,FALSE}` we don't remove the corresponding entry // from `self.unpacked_rwus`; it's not worth the effort, and we @@ -634,8 +553,19 @@ impl RWUTable { } } -#[derive(Copy, Clone)] -struct Specials { +const ACC_READ: u32 = 1; +const ACC_WRITE: u32 = 2; +const ACC_USE: u32 = 4; + +struct Liveness<'a, 'tcx> { + ir: &'a mut IrMaps<'tcx>, + body_owner: LocalDefId, + typeck_results: &'a ty::TypeckResults<'tcx>, + param_env: ty::ParamEnv<'tcx>, + upvars: Option<&'tcx FxIndexMap>, + successors: IndexVec>, + rwu_table: RWUTable, + /// A live node representing a point of execution before closure entry & /// after closure exit. Used to calculate liveness of captured variables /// through calls to the same closure. Used for Fn & FnMut closures only. @@ -643,19 +573,6 @@ struct Specials { /// A live node representing every 'exit' from the function, whether it be /// by explicit return, panic, or other means. exit_ln: LiveNode, -} - -const ACC_READ: u32 = 1; -const ACC_WRITE: u32 = 2; -const ACC_USE: u32 = 4; - -struct Liveness<'a, 'tcx> { - ir: &'a mut IrMaps<'tcx>, - typeck_results: &'a ty::TypeckResults<'tcx>, - param_env: ty::ParamEnv<'tcx>, - s: Specials, - successors: Vec, - rwu_table: RWUTable, // mappings from loop node ID to LiveNode // ("break" label should map to loop node ID, @@ -665,25 +582,27 @@ struct Liveness<'a, 'tcx> { } impl<'a, 'tcx> Liveness<'a, 'tcx> { - fn new(ir: &'a mut IrMaps<'tcx>, def_id: LocalDefId) -> Liveness<'a, 'tcx> { - let specials = Specials { - closure_ln: ir.add_live_node(ClosureNode), - exit_ln: ir.add_live_node(ExitNode), - }; + fn new(ir: &'a mut IrMaps<'tcx>, body_owner: LocalDefId) -> Liveness<'a, 'tcx> { + let typeck_results = ir.tcx.typeck(body_owner); + let param_env = ir.tcx.param_env(body_owner); + let upvars = ir.tcx.upvars_mentioned(body_owner); - let typeck_results = ir.tcx.typeck(def_id); - let param_env = ir.tcx.param_env(def_id); + let closure_ln = ir.add_live_node(ClosureNode); + let exit_ln = ir.add_live_node(ExitNode); - let num_live_nodes = ir.num_live_nodes; - let num_vars = ir.num_vars; + let num_live_nodes = ir.lnks.len(); + let num_vars = ir.var_kinds.len(); Liveness { ir, + body_owner, typeck_results, param_env, - s: specials, - successors: vec![invalid_node(); num_live_nodes], + upvars, + successors: IndexVec::from_elem_n(None, num_live_nodes), rwu_table: RWUTable::new(num_live_nodes * num_vars), + closure_ln, + exit_ln, break_ln: Default::default(), cont_ln: Default::default(), } @@ -721,34 +640,37 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn idx(&self, ln: LiveNode, var: Variable) -> usize { - ln.get() * self.ir.num_vars + var.get() + ln.index() * self.ir.var_kinds.len() + var.index() } fn live_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - assert!(ln.is_valid()); - let reader = self.rwu_table.get_reader(self.idx(ln, var)); - if reader.is_valid() { Some(self.ir.lnk(reader)) } else { None } + if let Some(reader) = self.rwu_table.get_reader(self.idx(ln, var)) { + Some(self.ir.lnks[reader]) + } else { + None + } } // Is this variable live on entry to any of its successor nodes? fn live_on_exit(&self, ln: LiveNode, var: Variable) -> Option { - let successor = self.successors[ln.get()]; + let successor = self.successors[ln].unwrap(); self.live_on_entry(successor, var) } fn used_on_entry(&self, ln: LiveNode, var: Variable) -> bool { - assert!(ln.is_valid()); self.rwu_table.get_used(self.idx(ln, var)) } fn assigned_on_entry(&self, ln: LiveNode, var: Variable) -> Option { - assert!(ln.is_valid()); - let writer = self.rwu_table.get_writer(self.idx(ln, var)); - if writer.is_valid() { Some(self.ir.lnk(writer)) } else { None } + if let Some(writer) = self.rwu_table.get_writer(self.idx(ln, var)) { + Some(self.ir.lnks[writer]) + } else { + None + } } fn assigned_on_exit(&self, ln: LiveNode, var: Variable) -> Option { - let successor = self.successors[ln.get()]; + let successor = self.successors[ln].unwrap(); self.assigned_on_entry(successor, var) } @@ -756,9 +678,9 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(&mut Liveness<'a, 'tcx>, usize, usize), { - let node_base_idx = self.idx(ln, Variable(0)); - let succ_base_idx = self.idx(succ_ln, Variable(0)); - for var_idx in 0..self.ir.num_vars { + let node_base_idx = self.idx(ln, Variable::from(0u32)); + let succ_base_idx = self.idx(succ_ln, Variable::from(0u32)); + for var_idx in 0..self.ir.var_kinds.len() { op(self, node_base_idx + var_idx, succ_base_idx + var_idx); } } @@ -767,11 +689,11 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { where F: FnMut(usize) -> bool, { - let node_base_idx = self.idx(ln, Variable(0)); - for var_idx in 0..self.ir.num_vars { + let node_base_idx = self.idx(ln, Variable::from(0u32)); + for var_idx in 0..self.ir.var_kinds.len() { let idx = node_base_idx + var_idx; if test(idx) { - write!(wr, " {:?}", Variable(var_idx as u32))?; + write!(wr, " {:?}", Variable::from(var_idx))?; } } Ok(()) @@ -782,14 +704,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut wr = Vec::new(); { let wr = &mut wr as &mut dyn Write; - write!(wr, "[ln({:?}) of kind {:?} reads", ln.get(), self.ir.lnk(ln)); - self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_valid()); + write!(wr, "[{:?} of kind {:?} reads", ln, self.ir.lnks[ln]); + self.write_vars(wr, ln, |idx| self.rwu_table.get_reader(idx).is_some()); write!(wr, " writes"); - self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_valid()); + self.write_vars(wr, ln, |idx| self.rwu_table.get_writer(idx).is_some()); write!(wr, " uses"); self.write_vars(wr, ln, |idx| self.rwu_table.get_used(idx)); - write!(wr, " precedes {:?}]", self.successors[ln.get()]); + write!(wr, " precedes {:?}]", self.successors[ln]); } String::from_utf8(wr).unwrap() } @@ -799,8 +721,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { debug!( "^^ liveness computation results for body {} (entry={:?})", { - for ln_idx in 0..self.ir.num_live_nodes { - debug!("{:?}", self.ln_str(LiveNode(ln_idx as u32))); + for ln_idx in 0..self.ir.lnks.len() { + debug!("{:?}", self.ln_str(LiveNode::from(ln_idx))); } hir_id }, @@ -809,7 +731,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } fn init_empty(&mut self, ln: LiveNode, succ_ln: LiveNode) { - self.successors[ln.get()] = succ_ln; + self.successors[ln] = Some(succ_ln); // It is not necessary to initialize the RWUs here because they are all // set to INV_INV_FALSE when they are created, and the sets only grow @@ -818,7 +740,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { fn init_from_succ(&mut self, ln: LiveNode, succ_ln: LiveNode) { // more efficient version of init_empty() / merge_from_succ() - self.successors[ln.get()] = succ_ln; + self.successors[ln] = Some(succ_ln); self.indices2(ln, succ_ln, |this, idx, succ_idx| { this.rwu_table.copy_packed(idx, succ_idx); @@ -842,12 +764,12 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut changed = false; let mut rwu = this.rwu_table.get(idx); let succ_rwu = this.rwu_table.get(succ_idx); - if succ_rwu.reader.is_valid() && !rwu.reader.is_valid() { + if succ_rwu.reader.is_some() && rwu.reader.is_none() { rwu.reader = succ_rwu.reader; changed = true } - if succ_rwu.writer.is_valid() && !rwu.writer.is_valid() { + if succ_rwu.writer.is_some() && rwu.writer.is_none() { rwu.writer = succ_rwu.writer; changed = true } @@ -891,14 +813,14 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { let mut rwu = self.rwu_table.get(idx); if (acc & ACC_WRITE) != 0 { - rwu.reader = invalid_node(); - rwu.writer = ln; + rwu.reader = None; + rwu.writer = Some(ln); } // Important: if we both read/write, must do read second // or else the write will override. if (acc & ACC_READ) != 0 { - rwu.reader = ln; + rwu.reader = Some(ln); } if (acc & ACC_USE) != 0 { @@ -908,14 +830,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.rwu_table.assign_unpacked(idx, rwu); } - fn compute( - &mut self, - fk: FnKind<'_>, - body: &hir::Body<'_>, - span: Span, - id: hir::HirId, - ) -> LiveNode { - debug!("compute: using id for body, {:?}", body.value); + fn compute(&mut self, body: &hir::Body<'_>, hir_id: HirId) -> LiveNode { + debug!("compute: for body {:?}", body.id().hir_id); // # Liveness of captured variables // @@ -933,32 +849,34 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { // if they are live on the entry to the closure, since only the closure // itself can access them on subsequent calls. - if let Some(upvars) = self.ir.tcx.upvars_mentioned(self.ir.body_owner) { + if let Some(upvars) = self.upvars { // Mark upvars captured by reference as used after closure exits. for (&var_hir_id, upvar) in upvars.iter().rev() { let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.ir.body_owner, + closure_expr_id: self.body_owner, }; match self.typeck_results.upvar_capture(upvar_id) { ty::UpvarCapture::ByRef(_) => { let var = self.variable(var_hir_id, upvar.span); - self.acc(self.s.exit_ln, var, ACC_READ | ACC_USE); + self.acc(self.exit_ln, var, ACC_READ | ACC_USE); } - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} } } } - let succ = self.propagate_through_expr(&body.value, self.s.exit_ln); + let succ = self.propagate_through_expr(&body.value, self.exit_ln); - match fk { - FnKind::Method(..) | FnKind::ItemFn(..) => return succ, - FnKind::Closure(..) => {} + if self.upvars.is_none() { + // Either not a closure, or closure without any captured variables. + // No need to determine liveness of captured variables, since there + // are none. + return succ; } - let ty = self.typeck_results.node_type(id); - match ty.kind { + let ty = self.typeck_results.node_type(hir_id); + match ty.kind() { ty::Closure(_def_id, substs) => match substs.as_closure().kind() { ty::ClosureKind::Fn => {} ty::ClosureKind::FnMut => {} @@ -966,26 +884,31 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { }, ty::Generator(..) => return succ, _ => { - span_bug!(span, "type of closure expr {:?} is not a closure {:?}", id, ty,); + span_bug!( + body.value.span, + "{} has upvars so it should have a closure type: {:?}", + hir_id, + ty + ); } }; // Propagate through calls to the closure. let mut first_merge = true; loop { - self.init_from_succ(self.s.closure_ln, succ); + self.init_from_succ(self.closure_ln, succ); for param in body.params { param.pat.each_binding(|_bm, hir_id, _x, ident| { let var = self.variable(hir_id, ident.span); - self.define(self.s.closure_ln, var); + self.define(self.closure_ln, var); }) } - if !self.merge_from_succ(self.s.exit_ln, self.s.closure_ln, first_merge) { + if !self.merge_from_succ(self.exit_ln, self.closure_ln, first_merge) { break; } first_merge = false; - assert_eq!(succ, self.propagate_through_expr(&body.value, self.s.exit_ln)); + assert_eq!(succ, self.propagate_through_expr(&body.value, self.exit_ln)); } succ @@ -1106,9 +1029,8 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { } hir::ExprKind::Ret(ref o_e) => { - // ignore succ and subst exit_ln: - let exit_ln = self.s.exit_ln; - self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), exit_ln) + // Ignore succ and subst exit_ln. + self.propagate_through_opt_expr(o_e.as_ref().map(|e| &**e), self.exit_ln) } hir::ExprKind::Break(label, ref opt_expr) => { @@ -1182,7 +1104,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.typeck_results.expr_ty(expr), self.param_env, ) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1197,7 +1119,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { self.typeck_results.expr_ty(expr), self.param_env, ) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1234,7 +1156,7 @@ impl<'a, 'tcx> Liveness<'a, 'tcx> { hir::ExprKind::InlineAsm(ref asm) => { // Handle non-returning asm let mut succ = if asm.options.contains(InlineAsmOptions::NORETURN) { - self.s.exit_ln + self.exit_ln } else { succ }; @@ -1595,11 +1517,18 @@ impl<'tcx> Liveness<'_, 'tcx> { fn should_warn(&self, var: Variable) -> Option { let name = self.ir.variable_name(var); - if name.is_empty() || name.as_bytes()[0] == b'_' { None } else { Some(name) } + if name == kw::Invalid { + return None; + } + let name: &str = &name.as_str(); + if name.as_bytes()[0] == b'_' { + return None; + } + Some(name.to_owned()) } fn warn_about_unused_upvars(&self, entry_ln: LiveNode) { - let upvars = match self.ir.tcx.upvars_mentioned(self.ir.body_owner) { + let upvars = match self.upvars { None => return, Some(upvars) => upvars, }; @@ -1607,10 +1536,10 @@ impl<'tcx> Liveness<'_, 'tcx> { let var = self.variable(var_hir_id, upvar.span); let upvar_id = ty::UpvarId { var_path: ty::UpvarPath { hir_id: var_hir_id }, - closure_expr_id: self.ir.body_owner, + closure_expr_id: self.body_owner, }; match self.typeck_results.upvar_capture(upvar_id) { - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} ty::UpvarCapture::ByRef(..) => continue, }; if self.used_on_entry(entry_ln, var) { @@ -1667,7 +1596,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // bindings, and we also consider the first pattern to be the "authoritative" set of ids. // However, we should take the ids and spans of variables with the same name from the later // patterns so the suggestions to prefix with underscores will apply to those too. - let mut vars: FxIndexMap)> = <_>::default(); + let mut vars: FxIndexMap)> = <_>::default(); pat.each_binding(|_, hir_id, pat_sp, ident| { let ln = entry_ln.unwrap_or_else(|| self.live_node(hir_id, pat_sp)); @@ -1697,7 +1626,7 @@ impl<'tcx> Liveness<'_, 'tcx> { // {ret}`, there is only one node, so asking about // assigned_on_exit() is not meaningful. let is_assigned = - if ln == self.s.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; + if ln == self.exit_ln { false } else { self.assigned_on_exit(ln, var).is_some() }; if is_assigned { self.ir.tcx.struct_span_lint_hir( diff --git a/src/librustc_passes/loops.rs b/compiler/rustc_passes/src/loops.rs similarity index 100% rename from src/librustc_passes/loops.rs rename to compiler/rustc_passes/src/loops.rs diff --git a/src/librustc_passes/reachable.rs b/compiler/rustc_passes/src/reachable.rs similarity index 100% rename from src/librustc_passes/reachable.rs rename to compiler/rustc_passes/src/reachable.rs diff --git a/src/librustc_passes/region.rs b/compiler/rustc_passes/src/region.rs similarity index 100% rename from src/librustc_passes/region.rs rename to compiler/rustc_passes/src/region.rs diff --git a/src/librustc_passes/stability.rs b/compiler/rustc_passes/src/stability.rs similarity index 74% rename from src/librustc_passes/stability.rs rename to compiler/rustc_passes/src/stability.rs index 91edc7d9db..1378b0d570 100644 --- a/src/librustc_passes/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -9,13 +9,14 @@ use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::{Generics, HirId, Item, StructField, Variant}; +use rustc_hir::{Generics, HirId, Item, StructField, TraitRef, Ty, TyKind, Variant}; use rustc_middle::hir::map::Map; use rustc_middle::middle::privacy::AccessLevels; use rustc_middle::middle::stability::{DeprecationEntry, Index}; use rustc_middle::ty::query::Providers; use rustc_middle::ty::TyCtxt; use rustc_session::lint; +use rustc_session::lint::builtin::INEFFECTIVE_UNSTABLE_TRAIT_IMPL; use rustc_session::parse::feature_err; use rustc_session::Session; use rustc_span::symbol::{sym, Symbol}; @@ -36,6 +37,24 @@ enum AnnotationKind { Container, } +/// Whether to inherit deprecation flags for nested items. In most cases, we do want to inherit +/// deprecation, because nested items rarely have individual deprecation attributes, and so +/// should be treated as deprecated if their parent is. However, default generic parameters +/// have separate deprecation attributes from their parents, so we do not wish to inherit +/// deprecation in this case. For example, inheriting deprecation for `T` in `Foo` +/// would cause a duplicate warning arising from both `Foo` and `T` being deprecated. +#[derive(Clone)] +enum InheritDeprecation { + Yes, + No, +} + +impl InheritDeprecation { + fn yes(&self) -> bool { + matches!(self, InheritDeprecation::Yes) + } +} + // A private tree-walker for producing an Index. struct Annotator<'a, 'tcx> { tcx: TyCtxt<'tcx>, @@ -55,6 +74,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { attrs: &[Attribute], item_sp: Span, kind: AnnotationKind, + inherit_deprecation: InheritDeprecation, visit_children: F, ) where F: FnOnce(&mut Self), @@ -62,7 +82,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { debug!("annotate(id = {:?}, attrs = {:?})", hir_id, attrs); let mut did_error = false; if !self.tcx.features().staged_api { - did_error = self.forbid_staged_api_attrs(hir_id, attrs); + did_error = self.forbid_staged_api_attrs(hir_id, attrs, inherit_deprecation.clone()); } let depr = @@ -79,9 +99,11 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { let depr_entry = DeprecationEntry::local(depr.clone(), hir_id); self.index.depr_map.insert(hir_id, depr_entry); } else if let Some(parent_depr) = self.parent_depr.clone() { - is_deprecated = true; - info!("tagging child {:?} as deprecated from parent", hir_id); - self.index.depr_map.insert(hir_id, parent_depr); + if inherit_deprecation.yes() { + is_deprecated = true; + info!("tagging child {:?} as deprecated from parent", hir_id); + self.index.depr_map.insert(hir_id, parent_depr); + } } if self.tcx.features().staged_api { @@ -185,7 +207,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { if stab.is_none() { debug!("annotate: stab not found, parent = {:?}", self.parent_stab); if let Some(stab) = self.parent_stab { - if stab.level.is_unstable() { + if inherit_deprecation.yes() && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -236,7 +258,12 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { } // returns true if an error occurred, used to suppress some spurious errors - fn forbid_staged_api_attrs(&mut self, hir_id: HirId, attrs: &[Attribute]) -> bool { + fn forbid_staged_api_attrs( + &mut self, + hir_id: HirId, + attrs: &[Attribute], + inherit_deprecation: InheritDeprecation, + ) -> bool { // Emit errors for non-staged-api crates. let unstable_attrs = [ sym::unstable, @@ -264,7 +291,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { // Propagate unstability. This can happen even for non-staged-api crates in case // -Zforce-unstable-if-unmarked is set. if let Some(stab) = self.parent_stab { - if stab.level.is_unstable() { + if inherit_deprecation.yes() && stab.level.is_unstable() { self.index.stab_map.insert(hir_id, stab); } } @@ -300,54 +327,119 @@ impl<'a, 'tcx> Visitor<'tcx> for Annotator<'a, 'tcx> { } hir::ItemKind::Struct(ref sd, _) => { if let Some(ctor_hir_id) = sd.ctor_hir_id() { - self.annotate(ctor_hir_id, &i.attrs, i.span, AnnotationKind::Required, |_| {}) + self.annotate( + ctor_hir_id, + &i.attrs, + i.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ) } } _ => {} } - self.annotate(i.hir_id, &i.attrs, i.span, kind, |v| intravisit::walk_item(v, i)); + self.annotate(i.hir_id, &i.attrs, i.span, kind, InheritDeprecation::Yes, |v| { + intravisit::walk_item(v, i) + }); self.in_trait_impl = orig_in_trait_impl; } fn visit_trait_item(&mut self, ti: &'tcx hir::TraitItem<'tcx>) { - self.annotate(ti.hir_id, &ti.attrs, ti.span, AnnotationKind::Required, |v| { - intravisit::walk_trait_item(v, ti); - }); + self.annotate( + ti.hir_id, + &ti.attrs, + ti.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_trait_item(v, ti); + }, + ); } fn visit_impl_item(&mut self, ii: &'tcx hir::ImplItem<'tcx>) { let kind = if self.in_trait_impl { AnnotationKind::Prohibited } else { AnnotationKind::Required }; - self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, |v| { + self.annotate(ii.hir_id, &ii.attrs, ii.span, kind, InheritDeprecation::Yes, |v| { intravisit::walk_impl_item(v, ii); }); } fn visit_variant(&mut self, var: &'tcx Variant<'tcx>, g: &'tcx Generics<'tcx>, item_id: HirId) { - self.annotate(var.id, &var.attrs, var.span, AnnotationKind::Required, |v| { - if let Some(ctor_hir_id) = var.data.ctor_hir_id() { - v.annotate(ctor_hir_id, &var.attrs, var.span, AnnotationKind::Required, |_| {}); - } + self.annotate( + var.id, + &var.attrs, + var.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + if let Some(ctor_hir_id) = var.data.ctor_hir_id() { + v.annotate( + ctor_hir_id, + &var.attrs, + var.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ); + } - intravisit::walk_variant(v, var, g, item_id) - }) + intravisit::walk_variant(v, var, g, item_id) + }, + ) } fn visit_struct_field(&mut self, s: &'tcx StructField<'tcx>) { - self.annotate(s.hir_id, &s.attrs, s.span, AnnotationKind::Required, |v| { - intravisit::walk_struct_field(v, s); - }); + self.annotate( + s.hir_id, + &s.attrs, + s.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_struct_field(v, s); + }, + ); } fn visit_foreign_item(&mut self, i: &'tcx hir::ForeignItem<'tcx>) { - self.annotate(i.hir_id, &i.attrs, i.span, AnnotationKind::Required, |v| { - intravisit::walk_foreign_item(v, i); - }); + self.annotate( + i.hir_id, + &i.attrs, + i.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |v| { + intravisit::walk_foreign_item(v, i); + }, + ); } fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { - self.annotate(md.hir_id, &md.attrs, md.span, AnnotationKind::Required, |_| {}); + self.annotate( + md.hir_id, + &md.attrs, + md.span, + AnnotationKind::Required, + InheritDeprecation::Yes, + |_| {}, + ); + } + + fn visit_generic_param(&mut self, p: &'tcx hir::GenericParam<'tcx>) { + let kind = match &p.kind { + // FIXME(const_generics:defaults) + hir::GenericParamKind::Type { default, .. } if default.is_some() => { + AnnotationKind::Container + } + _ => AnnotationKind::Prohibited, + }; + + self.annotate(p.hir_id, &p.attrs, p.span, kind, InheritDeprecation::No, |v| { + intravisit::walk_generic_param(v, p); + }); } } @@ -367,6 +459,21 @@ impl<'tcx> MissingStabilityAnnotations<'tcx> { self.tcx.sess.span_err(span, &format!("{} has missing stability attribute", descr)); } } + + fn check_missing_const_stability(&self, hir_id: HirId, span: Span) { + let stab_map = self.tcx.stability(); + let stab = stab_map.local_stability(hir_id); + if stab.map_or(false, |stab| stab.level.is_stable()) { + let const_stab = stab_map.local_const_stability(hir_id); + if const_stab.is_none() { + self.tcx.sess.span_err( + span, + "`#[stable]` const functions must also be either \ + `#[rustc_const_stable]` or `#[rustc_const_unstable]`", + ); + } + } + } } impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { @@ -377,14 +484,23 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { } fn visit_item(&mut self, i: &'tcx Item<'tcx>) { - match i.kind { - // Inherent impls and foreign modules serve only as containers for other items, - // they don't have their own stability. They still can be annotated as unstable - // and propagate this unstability to children, but this annotation is completely - // optional. They inherit stability from their parents when unannotated. - hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) => {} + // Inherent impls and foreign modules serve only as containers for other items, + // they don't have their own stability. They still can be annotated as unstable + // and propagate this unstability to children, but this annotation is completely + // optional. They inherit stability from their parents when unannotated. + if !matches!( + i.kind, + hir::ItemKind::Impl { of_trait: None, .. } | hir::ItemKind::ForeignMod(..) + ) { + self.check_missing_stability(i.hir_id, i.span); + } - _ => self.check_missing_stability(i.hir_id, i.span), + // Ensure `const fn` that are `stable` have one of `rustc_const_unstable` or + // `rustc_const_stable`. + if self.tcx.features().staged_api + && matches!(&i.kind, hir::ItemKind::Fn(sig, ..) if sig.header.is_const()) + { + self.check_missing_const_stability(i.hir_id, i.span); } intravisit::walk_item(self, i) @@ -421,6 +537,10 @@ impl<'tcx> Visitor<'tcx> for MissingStabilityAnnotations<'tcx> { fn visit_macro_def(&mut self, md: &'tcx hir::MacroDef<'tcx>) { self.check_missing_stability(md.hir_id, md.span); } + + // Note that we don't need to `check_missing_stability` for default generic parameters, + // as we assume that any default generic parameters without attributes are automatically + // stable (assuming they have not inherited instability from their parent). } fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { @@ -483,6 +603,7 @@ fn new_index(tcx: TyCtxt<'tcx>) -> Index<'tcx> { &krate.item.attrs, krate.item.span, AnnotationKind::Required, + InheritDeprecation::Yes, |v| intravisit::walk_crate(v, krate), ); } @@ -538,7 +659,37 @@ impl Visitor<'tcx> for Checker<'tcx> { // For implementations of traits, check the stability of each item // individually as it's possible to have a stable trait with unstable // items. - hir::ItemKind::Impl { of_trait: Some(ref t), items, .. } => { + hir::ItemKind::Impl { of_trait: Some(ref t), self_ty, items, .. } => { + if self.tcx.features().staged_api { + // If this impl block has an #[unstable] attribute, give an + // error if all involved types and traits are stable, because + // it will have no effect. + // See: https://github.com/rust-lang/rust/issues/55436 + if let (Some(Stability { level: attr::Unstable { .. }, .. }), _) = + attr::find_stability(&self.tcx.sess, &item.attrs, item.span) + { + let mut c = CheckTraitImplStable { tcx: self.tcx, fully_stable: true }; + c.visit_ty(self_ty); + c.visit_trait_ref(t); + if c.fully_stable { + let span = item + .attrs + .iter() + .find(|a| a.has_name(sym::unstable)) + .map_or(item.span, |a| a.span); + self.tcx.struct_span_lint_hir( + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + item.hir_id, + span, + |lint| lint + .build("an `#[unstable]` annotation here has no effect") + .note("see issue #55436 for more information") + .emit() + ); + } + } + } + if let Res::Def(DefKind::Trait, trait_did) = t.path.res { for impl_item_ref in items { let impl_item = self.tcx.hir().impl_item(impl_item_ref.id); @@ -598,6 +749,44 @@ impl Visitor<'tcx> for Checker<'tcx> { } } +struct CheckTraitImplStable<'tcx> { + tcx: TyCtxt<'tcx>, + fully_stable: bool, +} + +impl Visitor<'tcx> for CheckTraitImplStable<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + fn visit_path(&mut self, path: &'tcx hir::Path<'tcx>, _id: hir::HirId) { + if let Some(def_id) = path.res.opt_def_id() { + if let Some(stab) = self.tcx.lookup_stability(def_id) { + self.fully_stable &= stab.level.is_stable(); + } + } + intravisit::walk_path(self, path) + } + + fn visit_trait_ref(&mut self, t: &'tcx TraitRef<'tcx>) { + if let Res::Def(DefKind::Trait, trait_did) = t.path.res { + if let Some(stab) = self.tcx.lookup_stability(trait_did) { + self.fully_stable &= stab.level.is_stable(); + } + } + intravisit::walk_trait_ref(self, t) + } + + fn visit_ty(&mut self, t: &'tcx Ty<'tcx>) { + if let TyKind::Never = t.kind { + self.fully_stable = false; + } + intravisit::walk_ty(self, t) + } +} + /// Given the list of enabled features that were not language features (i.e., that /// were expected to be library features), and the list of features used from /// libraries, identify activated features that don't exist and error about them. diff --git a/src/librustc_passes/upvars.rs b/compiler/rustc_passes/src/upvars.rs similarity index 100% rename from src/librustc_passes/upvars.rs rename to compiler/rustc_passes/src/upvars.rs diff --git a/src/librustc_passes/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs similarity index 95% rename from src/librustc_passes/weak_lang_items.rs rename to compiler/rustc_passes/src/weak_lang_items.rs index f559d66587..6bc2110bfb 100644 --- a/src/librustc_passes/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -26,6 +26,9 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem if items.eh_personality().is_none() { items.missing.push(LangItem::EhPersonality); } + if tcx.sess.target.target.options.is_like_emscripten && items.eh_catch_typeinfo().is_none() { + items.missing.push(LangItem::EhCatchTypeinfo); + } { let mut cx = Context { tcx, items }; diff --git a/compiler/rustc_plugin_impl/Cargo.toml b/compiler/rustc_plugin_impl/Cargo.toml new file mode 100644 index 0000000000..500d13a8c1 --- /dev/null +++ b/compiler/rustc_plugin_impl/Cargo.toml @@ -0,0 +1,19 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_plugin_impl" +version = "0.0.0" +build = false +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_middle = { path = "../rustc_middle" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_lint = { path = "../rustc_lint" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_ast = { path = "../rustc_ast" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } diff --git a/src/librustc_plugin_impl/build.rs b/compiler/rustc_plugin_impl/src/build.rs similarity index 100% rename from src/librustc_plugin_impl/build.rs rename to compiler/rustc_plugin_impl/src/build.rs diff --git a/src/librustc_plugin_impl/lib.rs b/compiler/rustc_plugin_impl/src/lib.rs similarity index 89% rename from src/librustc_plugin_impl/lib.rs rename to compiler/rustc_plugin_impl/src/lib.rs index 1eb65dd96b..5bf4d300e9 100644 --- a/src/librustc_plugin_impl/lib.rs +++ b/compiler/rustc_plugin_impl/src/lib.rs @@ -6,7 +6,7 @@ //! feature](https://doc.rust-lang.org/nightly/unstable-book/language-features/plugin.html) //! of the Unstable Book for some examples. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/src/librustc_plugin_impl/load.rs b/compiler/rustc_plugin_impl/src/load.rs similarity index 100% rename from src/librustc_plugin_impl/load.rs rename to compiler/rustc_plugin_impl/src/load.rs diff --git a/compiler/rustc_privacy/Cargo.toml b/compiler/rustc_privacy/Cargo.toml new file mode 100644 index 0000000000..ce83dc1de7 --- /dev/null +++ b/compiler/rustc_privacy/Cargo.toml @@ -0,0 +1,16 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_privacy" +version = "0.0.0" +edition = "2018" + +[dependencies] +rustc_middle = { path = "../rustc_middle" } +rustc_attr = { path = "../rustc_attr" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_typeck = { path = "../rustc_typeck" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_data_structures = { path = "../rustc_data_structures" } +tracing = "0.1" diff --git a/src/librustc_privacy/lib.rs b/compiler/rustc_privacy/src/lib.rs similarity index 99% rename from src/librustc_privacy/lib.rs rename to compiler/rustc_privacy/src/lib.rs index deb4277cb3..8d1b826ea3 100644 --- a/src/librustc_privacy/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -1,7 +1,6 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] use rustc_attr as attr; @@ -97,6 +96,15 @@ where ty.visit_with(self) } ty::PredicateAtom::RegionOutlives(..) => false, + ty::PredicateAtom::ConstEvaluatable(..) + if self.def_id_visitor.tcx().features().const_evaluatable_checked => + { + // FIXME(const_evaluatable_checked): If the constant used here depends on a + // private function we may have to do something here... + // + // For now, let's just pretend that everything is fine. + false + } _ => bug!("unexpected predicate: {:?}", predicate), } } @@ -119,7 +127,7 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { let tcx = self.def_id_visitor.tcx(); // InternalSubsts are not visited here because they are visited below in `super_visit_with`. - match ty.kind { + match *ty.kind() { ty::Adt(&ty::AdtDef { did: def_id, .. }, ..) | ty::Foreign(def_id) | ty::FnDef(def_id, ..) @@ -134,7 +142,7 @@ where // Default type visitor doesn't visit signatures of fn types. // Something like `fn() -> Priv {my_func}` is considered a private type even if // `my_func` is public, so we need to visit signatures. - if let ty::FnDef(..) = ty.kind { + if let ty::FnDef(..) = ty.kind() { if tcx.fn_sig(def_id).visit_with(self) { return true; } diff --git a/compiler/rustc_query_system/Cargo.toml b/compiler/rustc_query_system/Cargo.toml new file mode 100644 index 0000000000..f38d62dec0 --- /dev/null +++ b/compiler/rustc_query_system/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_query_system" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +rustc-rayon-core = "0.3.0" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_macros = { path = "../rustc_macros" } +rustc_index = { path = "../rustc_index" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +parking_lot = "0.11" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_query_system/cache.rs b/compiler/rustc_query_system/src/cache.rs similarity index 100% rename from src/librustc_query_system/cache.rs rename to compiler/rustc_query_system/src/cache.rs diff --git a/src/librustc_query_system/dep_graph/README.md b/compiler/rustc_query_system/src/dep_graph/README.md similarity index 100% rename from src/librustc_query_system/dep_graph/README.md rename to compiler/rustc_query_system/src/dep_graph/README.md diff --git a/src/librustc_query_system/dep_graph/debug.rs b/compiler/rustc_query_system/src/dep_graph/debug.rs similarity index 100% rename from src/librustc_query_system/dep_graph/debug.rs rename to compiler/rustc_query_system/src/dep_graph/debug.rs diff --git a/src/librustc_query_system/dep_graph/dep_node.rs b/compiler/rustc_query_system/src/dep_graph/dep_node.rs similarity index 100% rename from src/librustc_query_system/dep_graph/dep_node.rs rename to compiler/rustc_query_system/src/dep_graph/dep_node.rs diff --git a/src/librustc_query_system/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs similarity index 100% rename from src/librustc_query_system/dep_graph/graph.rs rename to compiler/rustc_query_system/src/dep_graph/graph.rs diff --git a/src/librustc_query_system/dep_graph/mod.rs b/compiler/rustc_query_system/src/dep_graph/mod.rs similarity index 100% rename from src/librustc_query_system/dep_graph/mod.rs rename to compiler/rustc_query_system/src/dep_graph/mod.rs diff --git a/src/librustc_query_system/dep_graph/prev.rs b/compiler/rustc_query_system/src/dep_graph/prev.rs similarity index 100% rename from src/librustc_query_system/dep_graph/prev.rs rename to compiler/rustc_query_system/src/dep_graph/prev.rs diff --git a/src/librustc_query_system/dep_graph/query.rs b/compiler/rustc_query_system/src/dep_graph/query.rs similarity index 100% rename from src/librustc_query_system/dep_graph/query.rs rename to compiler/rustc_query_system/src/dep_graph/query.rs diff --git a/src/librustc_query_system/dep_graph/serialized.rs b/compiler/rustc_query_system/src/dep_graph/serialized.rs similarity index 100% rename from src/librustc_query_system/dep_graph/serialized.rs rename to compiler/rustc_query_system/src/dep_graph/serialized.rs diff --git a/src/librustc_query_system/lib.rs b/compiler/rustc_query_system/src/lib.rs similarity index 100% rename from src/librustc_query_system/lib.rs rename to compiler/rustc_query_system/src/lib.rs diff --git a/src/librustc_query_system/query/README.md b/compiler/rustc_query_system/src/query/README.md similarity index 100% rename from src/librustc_query_system/query/README.md rename to compiler/rustc_query_system/src/query/README.md diff --git a/src/librustc_query_system/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs similarity index 100% rename from src/librustc_query_system/query/caches.rs rename to compiler/rustc_query_system/src/query/caches.rs diff --git a/src/librustc_query_system/query/config.rs b/compiler/rustc_query_system/src/query/config.rs similarity index 100% rename from src/librustc_query_system/query/config.rs rename to compiler/rustc_query_system/src/query/config.rs diff --git a/src/librustc_query_system/query/job.rs b/compiler/rustc_query_system/src/query/job.rs similarity index 100% rename from src/librustc_query_system/query/job.rs rename to compiler/rustc_query_system/src/query/job.rs diff --git a/src/librustc_query_system/query/mod.rs b/compiler/rustc_query_system/src/query/mod.rs similarity index 100% rename from src/librustc_query_system/query/mod.rs rename to compiler/rustc_query_system/src/query/mod.rs diff --git a/src/librustc_query_system/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs similarity index 100% rename from src/librustc_query_system/query/plumbing.rs rename to compiler/rustc_query_system/src/query/plumbing.rs diff --git a/compiler/rustc_resolve/Cargo.toml b/compiler/rustc_resolve/Cargo.toml new file mode 100644 index 0000000000..821f9ea473 --- /dev/null +++ b/compiler/rustc_resolve/Cargo.toml @@ -0,0 +1,29 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_resolve" +version = "0.0.0" +edition = "2018" + +[lib] +test = false +doctest = false + +[dependencies] +bitflags = "1.2.1" +tracing = "0.1" +rustc_ast = { path = "../rustc_ast" } +rustc_arena = { path = "../rustc_arena" } +rustc_middle = { path = "../rustc_middle" } +rustc_ast_lowering = { path = "../rustc_ast_lowering" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_attr = { path = "../rustc_attr" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_expand = { path = "../rustc_expand" } +rustc_feature = { path = "../rustc_feature" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_metadata = { path = "../rustc_metadata" } +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs similarity index 99% rename from src/librustc_resolve/build_reduced_graph.rs rename to compiler/rustc_resolve/src/build_reduced_graph.rs index 761724be57..a48d002b2a 100644 --- a/src/librustc_resolve/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -218,7 +218,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { speculative: bool, ) -> Result> { let parent_scope = &self.parent_scope; - match vis.node { + match vis.kind { ast::VisibilityKind::Public => Ok(ty::Visibility::Public), ast::VisibilityKind::Crate(..) => { Ok(ty::Visibility::Restricted(DefId::local(CRATE_DEF_INDEX))) @@ -395,7 +395,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { // so prefixes are prepended with crate root segment if necessary. // The root is prepended lazily, when the first non-empty prefix or terminating glob // appears, so imports in braced groups can have roots prepended independently. - let is_glob = if let ast::UseTreeKind::Glob = use_tree.kind { true } else { false }; + let is_glob = matches!(use_tree.kind, ast::UseTreeKind::Glob); let crate_root = match prefix_iter.peek() { Some(seg) if !seg.ident.is_path_segment_keyword() && seg.ident.span.rust_2015() => { Some(seg.ident.span.ctxt()) @@ -796,23 +796,26 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { vis }; + let mut ret_fields = Vec::with_capacity(vdata.fields().len()); + for field in vdata.fields() { // NOTE: The field may be an expansion placeholder, but expansion sets // correct visibilities for unnamed field placeholders specifically, so the // constructor visibility should still be determined correctly. - if let Ok(field_vis) = self.resolve_visibility_speculative(&field.vis, true) - { - if ctor_vis.is_at_least(field_vis, &*self.r) { - ctor_vis = field_vis; - } + let field_vis = self + .resolve_visibility_speculative(&field.vis, true) + .unwrap_or(ty::Visibility::Public); + if ctor_vis.is_at_least(field_vis, &*self.r) { + ctor_vis = field_vis; } + ret_fields.push(field_vis); } let ctor_res = Res::Def( DefKind::Ctor(CtorOf::Struct, CtorKind::from_ast(vdata)), self.r.local_def_id(ctor_node_id).to_def_id(), ); self.r.define(parent, ident, ValueNS, (ctor_res, ctor_vis, sp, expansion)); - self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis)); + self.r.struct_constructors.insert(def_id, (ctor_res, ctor_vis, ret_fields)); } } @@ -964,7 +967,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> { Res::Def(DefKind::Ctor(CtorOf::Struct, ..), def_id) => { let parent = cstore.def_key(def_id).parent; if let Some(struct_def_id) = parent.map(|index| DefId { index, ..def_id }) { - self.r.struct_constructors.insert(struct_def_id, (res, vis)); + self.r.struct_constructors.insert(struct_def_id, (res, vis, vec![])); } } _ => {} diff --git a/src/librustc_resolve/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs similarity index 99% rename from src/librustc_resolve/check_unused.rs rename to compiler/rustc_resolve/src/check_unused.rs index 5624a6b6ac..89ce89b2e9 100644 --- a/src/librustc_resolve/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -105,7 +105,7 @@ impl<'a, 'b> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b> { // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. if let ast::ItemKind::Use(..) = item.kind { - if item.vis.node.is_pub() || item.span.is_dummy() { + if item.vis.kind.is_pub() || item.span.is_dummy() { return; } } diff --git a/src/librustc_resolve/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs similarity index 100% rename from src/librustc_resolve/def_collector.rs rename to compiler/rustc_resolve/src/def_collector.rs diff --git a/src/librustc_resolve/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs similarity index 99% rename from src/librustc_resolve/diagnostics.rs rename to compiler/rustc_resolve/src/diagnostics.rs index 48e1068b8d..612bc3e749 100644 --- a/src/librustc_resolve/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -112,7 +112,7 @@ impl<'a> Resolver<'a> { match outer_res { Res::SelfTy(maybe_trait_defid, maybe_impl_defid) => { if let Some(impl_span) = - maybe_impl_defid.and_then(|def_id| self.opt_span(def_id)) + maybe_impl_defid.and_then(|(def_id, _)| self.opt_span(def_id)) { err.span_label( reduce_impl_span_to_impl_keyword(sm, impl_span), @@ -466,7 +466,7 @@ impl<'a> Resolver<'a> { ); err } - ResolutionError::ParamInNonTrivialAnonConst(name) => { + ResolutionError::ParamInNonTrivialAnonConst { name, is_type } => { let mut err = self.session.struct_span_err( span, "generic parameters must not be used inside of non trivial constant values", @@ -478,9 +478,17 @@ impl<'a> Resolver<'a> { name ), ); - err.help( - &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", name) - ); + + if is_type { + err.note("type parameters are currently not permitted in anonymous constants"); + } else { + err.help( + &format!("it is currently only allowed to use either `{0}` or `{{ {0} }}` as generic constants", + name + ) + ); + } + err } ResolutionError::SelfInTyParamDefault => { @@ -794,7 +802,7 @@ impl<'a> Resolver<'a> { } segms.push(ast::PathSegment::from_ident(ident)); - let path = Path { span: name_binding.span, segments: segms }; + let path = Path { span: name_binding.span, segments: segms, tokens: None }; let did = match res { Res::Def(DefKind::Ctor(..), did) => this.parent(did), _ => res.opt_def_id(), diff --git a/src/librustc_resolve/imports.rs b/compiler/rustc_resolve/src/imports.rs similarity index 99% rename from src/librustc_resolve/imports.rs rename to compiler/rustc_resolve/src/imports.rs index b02fc427d6..adff4542b0 100644 --- a/src/librustc_resolve/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -875,12 +875,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { /// consolidate multiple unresolved import errors into a single diagnostic. fn finalize_import(&mut self, import: &'b Import<'b>) -> Option { let orig_vis = import.vis.replace(ty::Visibility::Invisible); - let orig_unusable_binding = match &import.kind { - ImportKind::Single { target_bindings, .. } => { - Some(mem::replace(&mut self.r.unusable_binding, target_bindings[TypeNS].get())) - } - _ => None, - }; let prev_ambiguity_errors_len = self.r.ambiguity_errors.len(); let path_res = self.r.resolve_path( &import.module_path, @@ -891,9 +885,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { import.crate_lint(), ); let no_ambiguity = self.r.ambiguity_errors.len() == prev_ambiguity_errors_len; - if let Some(orig_unusable_binding) = orig_unusable_binding { - self.r.unusable_binding = orig_unusable_binding; - } import.vis.set(orig_vis); if let PathResult::Failed { .. } | PathResult::NonModule(..) = path_res { // Consider erroneous imports used to avoid duplicate diagnostics. @@ -904,7 +895,8 @@ impl<'a, 'b> ImportResolver<'a, 'b> { // Consistency checks, analogous to `finalize_macro_resolutions`. if let Some(initial_module) = import.imported_module.get() { if !ModuleOrUniformRoot::same_def(module, initial_module) && no_ambiguity { - span_bug!(import.span, "inconsistent resolution for an import"); + let msg = "inconsistent resolution for an import"; + self.r.session.span_err(import.span, msg); } } else { if self.r.privacy_errors.is_empty() { @@ -926,7 +918,6 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } PathResult::Failed { is_error_from_last_segment: true, span, label, suggestion } => { if no_ambiguity { - assert!(import.imported_module.get().is_none()); let err = match self.make_path_suggestion( span, import.module_path.clone(), @@ -1157,7 +1148,7 @@ impl<'a, 'b> ImportResolver<'a, 'b> { } _ => { if !ident.is_path_segment_keyword() { - format!("no `{}` external crate", ident) + format!("no external crate `{}`", ident) } else { // HACK(eddyb) this shows up for `self` & `super`, which // should work instead - for now keep the same error message. diff --git a/src/librustc_resolve/late.rs b/compiler/rustc_resolve/src/late.rs similarity index 98% rename from src/librustc_resolve/late.rs rename to compiler/rustc_resolve/src/late.rs index d113eb22ab..2c01934b49 100644 --- a/src/librustc_resolve/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -110,6 +110,9 @@ crate enum RibKind<'a> { ItemRibKind(HasGenericParams), /// We're in a constant item. Can't refer to dynamic stuff. + /// + /// The `bool` indicates if this constant may reference generic parameters + /// and is used to only allow generic parameters to be used in trivial constant expressions. ConstantItemRibKind(bool), /// We passed through a module. @@ -188,7 +191,7 @@ crate enum PathSource<'a> { // Paths in struct expressions and patterns `Path { .. }`. Struct, // Paths in tuple struct patterns `Path(..)`. - TupleStruct(Span), + TupleStruct(Span, &'a [Span]), // `m::A::B` in `::B::C`. TraitItem(Namespace), } @@ -197,7 +200,7 @@ impl<'a> PathSource<'a> { fn namespace(self) -> Namespace { match self { PathSource::Type | PathSource::Trait(_) | PathSource::Struct => TypeNS, - PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(_) => ValueNS, + PathSource::Expr(..) | PathSource::Pat | PathSource::TupleStruct(..) => ValueNS, PathSource::TraitItem(ns) => ns, } } @@ -208,7 +211,7 @@ impl<'a> PathSource<'a> { | PathSource::Expr(..) | PathSource::Pat | PathSource::Struct - | PathSource::TupleStruct(_) => true, + | PathSource::TupleStruct(..) => true, PathSource::Trait(_) | PathSource::TraitItem(..) => false, } } @@ -219,7 +222,7 @@ impl<'a> PathSource<'a> { PathSource::Trait(_) => "trait", PathSource::Pat => "unit struct, unit variant or constant", PathSource::Struct => "struct, variant or union type", - PathSource::TupleStruct(_) => "tuple struct or tuple variant", + PathSource::TupleStruct(..) => "tuple struct or tuple variant", PathSource::TraitItem(ns) => match ns { TypeNS => "associated type", ValueNS => "method or associated constant", @@ -305,7 +308,7 @@ impl<'a> PathSource<'a> { | Res::SelfCtor(..) => true, _ => false, }, - PathSource::TupleStruct(_) => match res { + PathSource::TupleStruct(..) => match res { Res::Def(DefKind::Ctor(_, CtorKind::Fn), _) | Res::SelfCtor(..) => true, _ => false, }, @@ -340,8 +343,8 @@ impl<'a> PathSource<'a> { (PathSource::Struct, false) => error_code!(E0422), (PathSource::Expr(..), true) => error_code!(E0423), (PathSource::Expr(..), false) => error_code!(E0425), - (PathSource::Pat | PathSource::TupleStruct(_), true) => error_code!(E0532), - (PathSource::Pat | PathSource::TupleStruct(_), false) => error_code!(E0531), + (PathSource::Pat | PathSource::TupleStruct(..), true) => error_code!(E0532), + (PathSource::Pat | PathSource::TupleStruct(..), false) => error_code!(E0531), (PathSource::TraitItem(..), true) => error_code!(E0575), (PathSource::TraitItem(..), false) => error_code!(E0576), } @@ -378,6 +381,9 @@ struct DiagnosticMetadata<'ast> { /// Only used for better errors on `let : ;`. current_let_binding: Option<(Span, Option, Option)>, + + /// Used to detect possible `if let` written without `let` and to provide structured suggestion. + in_if_condition: Option<&'ast Expr>, } struct LateResolutionVisitor<'a, 'b, 'ast> { @@ -403,12 +409,12 @@ struct LateResolutionVisitor<'a, 'b, 'ast> { /// /// In particular, rustdoc uses this to avoid giving errors for `cfg()` items. /// In most cases this will be `None`, in which case errors will always be reported. - /// If it is `Some(_)`, then it will be updated when entering a nested function or trait body. + /// If it is `true`, then it will be updated when entering a nested function or trait body. in_func_body: bool, } /// Walks the whole crate in DFS order, visiting each item, resolving names as it goes. -impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { +impl<'a: 'ast, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { fn visit_item(&mut self, item: &'ast Item) { let prev = replace(&mut self.diagnostic_metadata.current_item, Some(item)); // Always report errors in items we just entered. @@ -656,7 +662,7 @@ impl<'a, 'ast> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast> { } } -impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { +impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { fn new(resolver: &'b mut Resolver<'a>) -> LateResolutionVisitor<'a, 'b, 'ast> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. @@ -845,7 +851,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { self.with_current_self_item(item, |this| { this.with_generic_param_rib(generics, ItemRibKind(HasGenericParams::Yes), |this| { let item_def_id = this.r.local_def_id(item.id).to_def_id(); - this.with_self_rib(Res::SelfTy(None, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(None, Some((item_def_id, false))), |this| { visit::walk_item(this, item); }); }); @@ -1028,7 +1034,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { let mut add_bindings_for_ns = |ns| { let parent_rib = self.ribs[ns] .iter() - .rfind(|r| if let ItemRibKind(_) = r.kind { true } else { false }) + .rfind(|r| matches!(r.kind, ItemRibKind(_))) .expect("associated item outside of an item"); seen_bindings .extend(parent_rib.bindings.iter().map(|(ident, _)| (*ident, ident.span))); @@ -1212,7 +1218,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { // Resolve the trait reference, if necessary. this.with_optional_trait_ref(opt_trait_reference.as_ref(), |this, trait_id| { let item_def_id = this.r.local_def_id(item_id).to_def_id(); - this.with_self_rib(Res::SelfTy(trait_id, Some(item_def_id)), |this| { + this.with_self_rib(Res::SelfTy(trait_id, Some((item_def_id, false))), |this| { if let Some(trait_ref) = opt_trait_reference.as_ref() { // Resolve type arguments in the trait path. visit::walk_trait_ref(this, trait_ref); @@ -1536,8 +1542,16 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { .unwrap_or_else(|| self.fresh_binding(ident, pat.id, pat_src, bindings)); self.r.record_partial_res(pat.id, PartialRes::new(res)); } - PatKind::TupleStruct(ref path, ..) => { - self.smart_resolve_path(pat.id, None, path, PathSource::TupleStruct(pat.span)); + PatKind::TupleStruct(ref path, ref sub_patterns) => { + self.smart_resolve_path( + pat.id, + None, + path, + PathSource::TupleStruct( + pat.span, + self.r.arenas.alloc_pattern_spans(sub_patterns.iter().map(|p| p.span)), + ), + ); } PatKind::Path(ref qself, ref path) => { self.smart_resolve_path(pat.id, qself.as_ref(), path, PathSource::Pat); @@ -1964,7 +1978,7 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); - let path = Path { segments: path.iter().map(path_seg).collect(), span }; + let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; if let Ok((_, res)) = self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false) { @@ -2199,7 +2213,9 @@ impl<'a, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { ExprKind::If(ref cond, ref then, ref opt_else) => { self.with_rib(ValueNS, NormalRibKind, |this| { + let old = this.diagnostic_metadata.in_if_condition.replace(cond); this.visit_expr(cond); + this.diagnostic_metadata.in_if_condition = old; this.visit_block(then); }); if let Some(expr) = opt_else { diff --git a/src/librustc_resolve/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs similarity index 93% rename from src/librustc_resolve/late/diagnostics.rs rename to compiler/rustc_resolve/src/late/diagnostics.rs index d392967af3..521ea7ad18 100644 --- a/src/librustc_resolve/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -16,6 +16,7 @@ use rustc_hir::def::{self, CtorKind, DefKind}; use rustc_hir::def_id::{DefId, CRATE_DEF_INDEX, LOCAL_CRATE}; use rustc_hir::PrimTy; use rustc_session::config::nightly_options; +use rustc_session::parse::feature_err; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{BytePos, Span, DUMMY_SP}; @@ -83,13 +84,14 @@ fn import_candidate_to_enum_paths(suggestion: &ImportSuggestion) -> (String, Str let enum_path = ast::Path { span: suggestion.path.span, segments: suggestion.path.segments[0..path_len - 1].to_vec(), + tokens: None, }; let enum_path_string = path_names_to_string(&enum_path); (variant_path_string, enum_path_string) } -impl<'a> LateResolutionVisitor<'a, '_, '_> { +impl<'a: 'ast, 'ast> LateResolutionVisitor<'a, '_, 'ast> { fn def_span(&self, def_id: DefId) -> Option { match def_id.krate { LOCAL_CRATE => self.r.opt_span(def_id), @@ -176,6 +178,19 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { let code = source.error_code(res.is_some()); let mut err = self.r.session.struct_span_err_with_code(base_span, &base_msg, code); + match (source, self.diagnostic_metadata.in_if_condition) { + (PathSource::Expr(_), Some(Expr { span, kind: ExprKind::Assign(..), .. })) => { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "you might have meant to use pattern matching", + "let ".to_string(), + Applicability::MaybeIncorrect, + ); + self.r.session.if_let_suggestions.borrow_mut().insert(*span); + } + _ => {} + } + let is_assoc_fn = self.self_type_is_available(span); // Emit help message for fake-self from other languages (e.g., `this` in Javascript). if ["this", "my"].contains(&&*item_str.as_str()) && is_assoc_fn { @@ -609,12 +624,12 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { ); } } - PathSource::Expr(_) | PathSource::TupleStruct(_) | PathSource::Pat => { + PathSource::Expr(_) | PathSource::TupleStruct(..) | PathSource::Pat => { let span = match &source { PathSource::Expr(Some(Expr { span, kind: ExprKind::Call(_, _), .. })) - | PathSource::TupleStruct(span) => { + | PathSource::TupleStruct(span, _) => { // We want the main underline to cover the suggested code as well for // cleaner output. err.set_span(*span); @@ -626,7 +641,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { err.span_label(span, &format!("`{}` defined here", path_str)); } let (tail, descr, applicability) = match source { - PathSource::Pat | PathSource::TupleStruct(_) => { + PathSource::Pat | PathSource::TupleStruct(..) => { ("", "pattern", Applicability::MachineApplicable) } _ => (": val", "literal", Applicability::HasPlaceholders), @@ -691,7 +706,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } ( Res::Def(DefKind::Enum, def_id), - PathSource::TupleStruct(_) | PathSource::Expr(..), + PathSource::TupleStruct(..) | PathSource::Expr(..), ) => { if self .diagnostic_metadata @@ -731,15 +746,50 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { } } (Res::Def(DefKind::Struct, def_id), _) if ns == ValueNS => { - if let Some((ctor_def, ctor_vis)) = self.r.struct_constructors.get(&def_id).cloned() + if let Some((ctor_def, ctor_vis, fields)) = + self.r.struct_constructors.get(&def_id).cloned() { let accessible_ctor = self.r.is_accessible_from(ctor_vis, self.parent_scope.module); if is_expected(ctor_def) && !accessible_ctor { - err.span_label( - span, - "constructor is not visible here due to private fields".to_string(), - ); + let mut better_diag = false; + if let PathSource::TupleStruct(_, pattern_spans) = source { + if pattern_spans.len() > 0 && fields.len() == pattern_spans.len() { + let non_visible_spans: Vec = fields + .iter() + .zip(pattern_spans.iter()) + .filter_map(|(vis, span)| { + match self + .r + .is_accessible_from(*vis, self.parent_scope.module) + { + true => None, + false => Some(*span), + } + }) + .collect(); + // Extra check to be sure + if non_visible_spans.len() > 0 { + let mut m: rustc_span::MultiSpan = + non_visible_spans.clone().into(); + non_visible_spans.into_iter().for_each(|s| { + m.push_span_label(s, "private field".to_string()) + }); + err.span_note( + m, + "constructor is not visible here due to private fields", + ); + better_diag = true; + } + } + } + + if !better_diag { + err.span_label( + span, + "constructor is not visible here due to private fields".to_string(), + ); + } } } else { bad_struct_syntax_suggestion(def_id); @@ -1052,7 +1102,8 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { path_segments.push(ast::PathSegment::from_ident(ident)); let module_def_id = module.def_id().unwrap(); if module_def_id == def_id { - let path = Path { span: name_binding.span, segments: path_segments }; + let path = + Path { span: name_binding.span, segments: path_segments, tokens: None }; result = Some(( module, ImportSuggestion { @@ -1082,7 +1133,7 @@ impl<'a> LateResolutionVisitor<'a, '_, '_> { if let Res::Def(DefKind::Variant, _) = name_binding.res() { let mut segms = enum_import_suggestion.path.segments.clone(); segms.push(ast::PathSegment::from_ident(ident)); - variants.push(Path { span: name_binding.span, segments: segms }); + variants.push(Path { span: name_binding.span, segments: segms, tokens: None }); } }); variants @@ -1368,13 +1419,13 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { if snippet.starts_with('&') && !snippet.starts_with("&'") { introduce_suggestion .push((param.span, format!("&{} {}", lt_name, &snippet[1..]))); - } else if snippet.starts_with("&'_ ") { + } else if let Some(stripped) = snippet.strip_prefix("&'_ ") { introduce_suggestion - .push((param.span, format!("&{} {}", lt_name, &snippet[4..]))); + .push((param.span, format!("&{} {}", lt_name, stripped))); } } } - introduce_suggestion.push((*for_span, for_sugg.to_string())); + introduce_suggestion.push((*for_span, for_sugg)); introduce_suggestion.push((span, formatter(<_name))); err.multipart_suggestion(&msg, introduce_suggestion, Applicability::MaybeIncorrect); } @@ -1484,7 +1535,7 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { } }; - let lifetime_names: Vec<_> = lifetime_names.into_iter().collect(); + let lifetime_names: Vec<_> = lifetime_names.iter().collect(); match (&lifetime_names[..], snippet.as_deref()) { ([name], Some("&")) => { suggest_existing(err, &name.as_str()[..], &|name| format!("&{} ", name)); @@ -1549,4 +1600,32 @@ impl<'tcx> LifetimeContext<'_, 'tcx> { _ => {} } } + + /// Non-static lifetimes are prohibited in anonymous constants under `min_const_generics` so + /// this function will emit an error if `min_const_generics` is enabled, the body identified by + /// `body_id` is an anonymous constant and `lifetime_ref` is non-static. + crate fn maybe_emit_forbidden_non_static_lifetime_error( + &self, + body_id: hir::BodyId, + lifetime_ref: &'tcx hir::Lifetime, + ) { + let is_anon_const = matches!( + self.tcx.def_kind(self.tcx.hir().body_owner_def_id(body_id)), + hir::def::DefKind::AnonConst + ); + let is_allowed_lifetime = matches!( + lifetime_ref.name, + hir::LifetimeName::Implicit | hir::LifetimeName::Static | hir::LifetimeName::Underscore + ); + + if self.tcx.features().min_const_generics && is_anon_const && !is_allowed_lifetime { + feature_err( + &self.tcx.sess.parse_sess, + sym::const_generics, + lifetime_ref.span, + "a non-static lifetime is not allowed in a `const`", + ) + .emit(); + } + } } diff --git a/src/librustc_resolve/late/lifetimes.rs b/compiler/rustc_resolve/src/late/lifetimes.rs similarity index 99% rename from src/librustc_resolve/late/lifetimes.rs rename to compiler/rustc_resolve/src/late/lifetimes.rs index 31360d4747..072fb509b1 100644 --- a/src/librustc_resolve/late/lifetimes.rs +++ b/compiler/rustc_resolve/src/late/lifetimes.rs @@ -1777,6 +1777,10 @@ impl<'a, 'tcx> LifetimeContext<'a, 'tcx> { let result = loop { match *scope { Scope::Body { id, s } => { + // Non-static lifetimes are prohibited in anonymous constants under + // `min_const_generics`. + self.maybe_emit_forbidden_non_static_lifetime_error(id, lifetime_ref); + outermost_body = Some(id); scope = s; } diff --git a/src/librustc_resolve/lib.rs b/compiler/rustc_resolve/src/lib.rs similarity index 97% rename from src/librustc_resolve/lib.rs rename to compiler/rustc_resolve/src/lib.rs index f2319bfe64..283db1404d 100644 --- a/src/librustc_resolve/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -8,7 +8,7 @@ //! //! Type-relative name resolution (methods, fields, associated items) happens in `librustc_typeck`. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(nll)] @@ -221,7 +221,7 @@ enum ResolutionError<'a> { /// generic parameters must not be used inside of non trivial constant values. /// /// This error is only emitted when using `min_const_generics`. - ParamInNonTrivialAnonConst(Symbol), + ParamInNonTrivialAnonConst { name: Symbol, is_type: bool }, /// Error E0735: type parameters with a default cannot use `Self` SelfInTyParamDefault, /// Error E0767: use of unreachable label @@ -534,11 +534,8 @@ impl<'a> ModuleData<'a> { if ns != TypeNS { return; } - match binding.res() { - Res::Def(DefKind::Trait | DefKind::TraitAlias, _) => { - collected_traits.push((name, binding)) - } - _ => (), + if let Res::Def(DefKind::Trait | DefKind::TraitAlias, _) = binding.res() { + collected_traits.push((name, binding)) } }); *traits = Some(collected_traits.into_boxed_slice()); @@ -867,6 +864,12 @@ pub struct ExternPreludeEntry<'a> { pub introduced_by_item: bool, } +/// Used for better errors for E0773 +enum BuiltinMacroState { + NotYetSeen(SyntaxExtension), + AlreadySeen(Span), +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -960,7 +963,7 @@ pub struct Resolver<'a> { crate_loader: CrateLoader<'a>, macro_names: FxHashSet, - builtin_macros: FxHashMap, + builtin_macros: FxHashMap, registered_attrs: FxHashSet, registered_tools: FxHashSet, macro_use_prelude: FxHashMap>, @@ -999,7 +1002,8 @@ pub struct Resolver<'a> { /// Table for mapping struct IDs into struct constructor IDs, /// it's not used during normal resolution, only for better error reporting. - struct_constructors: DefIdMap<(Res, ty::Visibility)>, + /// Also includes of list of each fields visibility + struct_constructors: DefIdMap<(Res, ty::Visibility, Vec)>, /// Features enabled for this crate. active_features: FxHashSet, @@ -1036,6 +1040,7 @@ pub struct ResolverArenas<'a> { name_resolutions: TypedArena>>, macro_rules_bindings: TypedArena>, ast_paths: TypedArena, + pattern_spans: TypedArena, } impl<'a> ResolverArenas<'a> { @@ -1067,6 +1072,9 @@ impl<'a> ResolverArenas<'a> { fn alloc_ast_paths(&'a self, paths: &[ast::Path]) -> &'a [ast::Path] { self.ast_paths.alloc_from_iter(paths.iter().cloned()) } + fn alloc_pattern_spans(&'a self, spans: impl Iterator) -> &'a [Span] { + self.pattern_spans.alloc_from_iter(spans) + } } impl<'a> AsMut> for Resolver<'a> { @@ -2385,8 +2393,12 @@ impl<'a> Resolver<'a> { Res::Def(DefKind::Mod, _) => true, _ => false, }; - let mut candidates = - self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod); + // Don't look up import candidates if this is a speculative resolve + let mut candidates = if record_used { + self.lookup_import_candidates(ident, TypeNS, parent_scope, is_mod) + } else { + Vec::new() + }; candidates.sort_by_cached_key(|c| { (c.path.segments.len(), pprust::path_to_string(&c.path)) }); @@ -2403,7 +2415,14 @@ impl<'a> Resolver<'a> { (format!("maybe a missing crate `{}`?", ident), None) } } else if i == 0 { - (format!("use of undeclared type or module `{}`", ident), None) + if ident + .name + .with(|n| n.chars().next().map_or(false, |c| c.is_ascii_uppercase())) + { + (format!("use of undeclared type `{}`", ident), None) + } else { + (format!("use of undeclared crate or module `{}`", ident), None) + } } else { let mut msg = format!("could not find `{}` in `{}`", ident, path[i - 1].ident); @@ -2517,7 +2536,7 @@ impl<'a> Resolver<'a> { &mut self, rib_index: usize, rib_ident: Ident, - res: Res, + mut res: Res, record_used: bool, span: Span, all_ribs: &[Rib<'a>], @@ -2607,13 +2626,23 @@ impl<'a> Resolver<'a> { ConstantItemRibKind(trivial) => { // HACK(min_const_generics): We currently only allow `N` or `{ N }`. if !trivial && self.session.features_untracked().min_const_generics { - if record_used { - self.report_error( - span, - ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), - ); + // HACK(min_const_generics): If we encounter `Self` in an anonymous constant + // we can't easily tell if it's generic at this stage, so we instead remember + // this and then enforce the self type to be concrete later on. + if let Res::SelfTy(trait_def, Some((impl_def, _))) = res { + res = Res::SelfTy(trait_def, Some((impl_def, true))); + } else { + if record_used { + self.report_error( + span, + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: true, + }, + ); + } + return Res::Err; } - return Res::Err; } if in_ty_param_default { @@ -2687,7 +2716,10 @@ impl<'a> Resolver<'a> { if record_used { self.report_error( span, - ResolutionError::ParamInNonTrivialAnonConst(rib_ident.name), + ResolutionError::ParamInNonTrivialAnonConst { + name: rib_ident.name, + is_type: false, + }, ); } return Res::Err; @@ -3172,6 +3204,7 @@ impl<'a> Resolver<'a> { .chain(path_str.split("::").skip(1).map(Ident::from_str)) .map(|i| self.new_ast_path_segment(i)) .collect(), + tokens: None, } } else { ast::Path { @@ -3181,6 +3214,7 @@ impl<'a> Resolver<'a> { .map(Ident::from_str) .map(|i| self.new_ast_path_segment(i)) .collect(), + tokens: None, } }; let module = self.get_module(module_id); @@ -3200,7 +3234,7 @@ impl<'a> Resolver<'a> { &Segment::from_path(path), Some(ns), parent_scope, - true, + false, path.span, CrateLint::No, ) { diff --git a/src/librustc_resolve/macros.rs b/compiler/rustc_resolve/src/macros.rs similarity index 97% rename from src/librustc_resolve/macros.rs rename to compiler/rustc_resolve/src/macros.rs index 51518d63ae..bea7138964 100644 --- a/src/librustc_resolve/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -3,7 +3,7 @@ use crate::imports::ImportResolver; use crate::Namespace::*; -use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, Determinacy}; +use crate::{AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BuiltinMacroState, Determinacy}; use crate::{CrateLint, ParentScope, ResolutionError, Resolver, Scope, ScopeSet, Weak}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::{self as ast, NodeId}; @@ -11,6 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering; use rustc_ast_pretty::pprust; use rustc_attr::StabilityLevel; use rustc_data_structures::fx::FxHashSet; +use rustc_errors::struct_span_err; use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension}; use rustc_expand::compile_declarative_macro; use rustc_expand::expand::{AstFragment, AstFragmentKind, Invocation, InvocationKind}; @@ -166,7 +167,7 @@ impl<'a> ResolverExpand for Resolver<'a> { } fn register_builtin_macro(&mut self, ident: Ident, ext: SyntaxExtension) { - if self.builtin_macros.insert(ident.name, ext).is_some() { + if self.builtin_macros.insert(ident.name, BuiltinMacroState::NotYetSeen(ext)).is_some() { self.session .span_err(ident.span, &format!("built-in macro `{}` was already defined", ident)); } @@ -1076,10 +1077,23 @@ impl<'a> Resolver<'a> { if result.is_builtin { // The macro was marked with `#[rustc_builtin_macro]`. - if let Some(ext) = self.builtin_macros.remove(&item.ident.name) { + if let Some(builtin_macro) = self.builtin_macros.get_mut(&item.ident.name) { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. - result.kind = ext.kind; + // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. + match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { + BuiltinMacroState::NotYetSeen(ext) => result.kind = ext.kind, + BuiltinMacroState::AlreadySeen(span) => { + struct_span_err!( + self.session, + item.span, + E0773, + "attempted to define built-in macro more than once" + ) + .span_note(span, "previously defined here") + .emit(); + } + } } else { let msg = format!("cannot find a built-in macro with name `{}`", item.ident); self.session.span_err(item.span, &msg); diff --git a/compiler/rustc_save_analysis/Cargo.toml b/compiler/rustc_save_analysis/Cargo.toml new file mode 100644 index 0000000000..da1bed37a9 --- /dev/null +++ b/compiler/rustc_save_analysis/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_save_analysis" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_ast = { path = "../rustc_ast" } +rustc_ast_pretty = { path = "../rustc_ast_pretty" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_lexer = { path = "../rustc_lexer" } +serde_json = "1" +rustc_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rls-data = "0.19" +rls-span = "0.5" diff --git a/src/librustc_save_analysis/dump_visitor.rs b/compiler/rustc_save_analysis/src/dump_visitor.rs similarity index 99% rename from src/librustc_save_analysis/dump_visitor.rs rename to compiler/rustc_save_analysis/src/dump_visitor.rs index 77aecefe5a..ce484858cb 100644 --- a/src/librustc_save_analysis/dump_visitor.rs +++ b/compiler/rustc_save_analysis/src/dump_visitor.rs @@ -14,7 +14,7 @@ //! recording the output. use rustc_ast as ast; -use rustc_ast::{token, walk_list}; +use rustc_ast::walk_list; use rustc_data_structures::fx::FxHashSet; use rustc_hir as hir; use rustc_hir::def::{DefKind as HirDefKind, Res}; @@ -1207,9 +1207,7 @@ impl<'tcx> Visitor<'tcx> for DumpVisitor<'tcx> { // Otherwise it's a span with wrong macro expansion info, which // we don't want to track anyway, since it's probably macro-internal `use` - if let Some(sub_span) = - self.span.sub_span_of_token(item.span, token::BinOp(token::Star)) - { + if let Some(sub_span) = self.span.sub_span_of_star(item.span) { if !self.span.filter_generated(item.span) { let access = access_from!(self.save_ctxt, item, item.hir_id); let span = self.span_from_span(sub_span); diff --git a/src/librustc_save_analysis/dumper.rs b/compiler/rustc_save_analysis/src/dumper.rs similarity index 100% rename from src/librustc_save_analysis/dumper.rs rename to compiler/rustc_save_analysis/src/dumper.rs diff --git a/src/librustc_save_analysis/lib.rs b/compiler/rustc_save_analysis/src/lib.rs similarity index 96% rename from src/librustc_save_analysis/lib.rs rename to compiler/rustc_save_analysis/src/lib.rs index 629051c182..f6434689fe 100644 --- a/src/librustc_save_analysis/lib.rs +++ b/compiler/rustc_save_analysis/src/lib.rs @@ -1,4 +1,4 @@ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![feature(or_patterns)] #![recursion_limit = "256"] @@ -21,7 +21,7 @@ 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, DefIdTree, TyCtxt}; +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::output::{filename_for_metadata, out_filename}; @@ -438,7 +438,7 @@ impl<'tcx> SaveContext<'tcx> { .next() .map(|item| item.def_id); } - qualname.push_str(">"); + qualname.push('>'); (qualname, trait_id, decl_id, docs, attrs) } @@ -524,12 +524,12 @@ impl<'tcx> SaveContext<'tcx> { pub fn get_expr_data(&self, expr: &hir::Expr<'_>) -> Option { let ty = self.typeck_results().expr_ty_adjusted_opt(expr)?; - if matches!(ty.kind, ty::Error(_)) { + if matches!(ty.kind(), ty::Error(_)) { return None; } match expr.kind { hir::ExprKind::Field(ref sub_ex, ident) => { - match self.typeck_results().expr_ty_adjusted(&sub_ex).kind { + match self.typeck_results().expr_ty_adjusted(&sub_ex).kind() { ty::Adt(def, _) if !def.is_enum() => { let variant = &def.non_enum_variant(); filter!(self.span_utils, ident.span); @@ -551,7 +551,7 @@ impl<'tcx> SaveContext<'tcx> { } } } - hir::ExprKind::Struct(qpath, ..) => match ty.kind { + hir::ExprKind::Struct(qpath, ..) => match ty.kind() { ty::Adt(def, _) => { let sub_span = qpath.last_segment_span(); filter!(self.span_utils, sub_span); @@ -989,32 +989,34 @@ pub fn process_crate<'l, 'tcx, H: SaveHandler>( config: Option, mut handler: H, ) { - tcx.dep_graph.with_ignore(|| { - info!("Dumping crate {}", cratename); + with_no_trimmed_paths(|| { + tcx.dep_graph.with_ignore(|| { + info!("Dumping crate {}", cratename); - // Privacy checking requires and is done after type checking; use a - // fallback in case the access levels couldn't have been correctly computed. - let access_levels = match tcx.sess.compile_status() { - Ok(..) => tcx.privacy_access_levels(LOCAL_CRATE), - Err(..) => tcx.arena.alloc(AccessLevels::default()), - }; + // Privacy checking requires and is done after type checking; use a + // fallback in case the access levels couldn't have been correctly computed. + let access_levels = match tcx.sess.compile_status() { + Ok(..) => tcx.privacy_access_levels(LOCAL_CRATE), + Err(..) => tcx.arena.alloc(AccessLevels::default()), + }; - let save_ctxt = SaveContext { - tcx, - maybe_typeck_results: None, - access_levels: &access_levels, - span_utils: SpanUtils::new(&tcx.sess), - config: find_config(config), - impl_counter: Cell::new(0), - }; + let save_ctxt = SaveContext { + tcx, + maybe_typeck_results: None, + access_levels: &access_levels, + span_utils: SpanUtils::new(&tcx.sess), + config: find_config(config), + impl_counter: Cell::new(0), + }; - let mut visitor = DumpVisitor::new(save_ctxt); + let mut visitor = DumpVisitor::new(save_ctxt); - visitor.dump_crate_info(cratename, tcx.hir().krate()); - visitor.dump_compilation_options(input, cratename); - visitor.process_crate(tcx.hir().krate()); + visitor.dump_crate_info(cratename, tcx.hir().krate()); + visitor.dump_compilation_options(input, cratename); + visitor.process_crate(tcx.hir().krate()); - handler.save(&visitor.save_ctxt, &visitor.analysis()) + handler.save(&visitor.save_ctxt, &visitor.analysis()) + }) }) } diff --git a/src/librustc_save_analysis/sig.rs b/compiler/rustc_save_analysis/src/sig.rs similarity index 99% rename from src/librustc_save_analysis/sig.rs rename to compiler/rustc_save_analysis/src/sig.rs index 6dd7f89d59..747e198cd9 100644 --- a/src/librustc_save_analysis/sig.rs +++ b/compiler/rustc_save_analysis/src/sig.rs @@ -497,7 +497,7 @@ impl<'hir> Sig for hir::Item<'hir> { sig.text.push_str(&bounds_to_string(bounds)); } // FIXME where clause - sig.text.push_str(";"); + sig.text.push(';'); Ok(sig) } diff --git a/src/librustc_save_analysis/span_utils.rs b/compiler/rustc_save_analysis/src/span_utils.rs similarity index 50% rename from src/librustc_save_analysis/span_utils.rs rename to compiler/rustc_save_analysis/src/span_utils.rs index d5f992b0de..edcd492577 100644 --- a/src/librustc_save_analysis/span_utils.rs +++ b/compiler/rustc_save_analysis/src/span_utils.rs @@ -1,6 +1,6 @@ use crate::generated_code; -use rustc_ast::token::{self, TokenKind}; -use rustc_parse::lexer::{self, StringReader}; +use rustc_data_structures::sync::Lrc; +use rustc_lexer::{tokenize, TokenKind}; use rustc_session::Session; use rustc_span::*; @@ -43,62 +43,38 @@ impl<'a> SpanUtils<'a> { } } - pub fn retokenise_span(&self, span: Span) -> StringReader<'a> { - lexer::StringReader::retokenize(&self.sess.parse_sess, span) - } - - pub fn sub_span_of_token(&self, span: Span, tok: TokenKind) -> Option { - let mut toks = self.retokenise_span(span); - loop { - let next = toks.next_token(); - if next == token::Eof { - return None; - } - if next == tok { - return Some(next.span); - } + /// Finds the span of `*` token withing the larger `span`. + pub fn sub_span_of_star(&self, mut span: Span) -> Option { + let begin = self.sess.source_map().lookup_byte_offset(span.lo()); + let end = self.sess.source_map().lookup_byte_offset(span.hi()); + // Make the range zero-length if the span is invalid. + if begin.sf.start_pos != end.sf.start_pos { + span = span.shrink_to_lo(); } + + let sf = Lrc::clone(&begin.sf); + + self.sess.source_map().ensure_source_file_source_present(Lrc::clone(&sf)); + let src = + sf.src.clone().or_else(|| sf.external_src.borrow().get_source().map(Lrc::clone))?; + let to_index = |pos: BytePos| -> usize { (pos - sf.start_pos).0 as usize }; + let text = &src[to_index(span.lo())..to_index(span.hi())]; + let start_pos = { + let mut pos = 0; + tokenize(text) + .map(|token| { + let start = pos; + pos += token.len; + (start, token) + }) + .find(|(_pos, token)| token.kind == TokenKind::Star)? + .0 + }; + let lo = span.lo() + BytePos(start_pos as u32); + let hi = lo + BytePos(1); + Some(span.with_lo(lo).with_hi(hi)) } - // // Return the name for a macro definition (identifier after first `!`) - // pub fn span_for_macro_def_name(&self, span: Span) -> Option { - // let mut toks = self.retokenise_span(span); - // loop { - // let ts = toks.real_token(); - // if ts == token::Eof { - // return None; - // } - // if ts == token::Not { - // let ts = toks.real_token(); - // if ts.kind.is_ident() { - // return Some(ts.sp); - // } else { - // return None; - // } - // } - // } - // } - - // // Return the name for a macro use (identifier before first `!`). - // pub fn span_for_macro_use_name(&self, span:Span) -> Option { - // let mut toks = self.retokenise_span(span); - // let mut prev = toks.real_token(); - // loop { - // if prev == token::Eof { - // return None; - // } - // let ts = toks.real_token(); - // if ts == token::Not { - // if prev.kind.is_ident() { - // return Some(prev.sp); - // } else { - // return None; - // } - // } - // prev = ts; - // } - // } - /// Return true if the span is generated code, and /// it is not a subspan of the root callsite. /// diff --git a/src/librustc_serialize/Cargo.toml b/compiler/rustc_serialize/Cargo.toml similarity index 70% rename from src/librustc_serialize/Cargo.toml rename to compiler/rustc_serialize/Cargo.toml index 939e6a59ba..16c5dff734 100644 --- a/src/librustc_serialize/Cargo.toml +++ b/compiler/rustc_serialize/Cargo.toml @@ -4,13 +4,9 @@ name = "rustc_serialize" version = "0.0.0" edition = "2018" -[lib] -name = "rustc_serialize" -path = "lib.rs" - [dependencies] indexmap = "1" smallvec = { version = "1.0", features = ["union", "may_dangle"] } [dev-dependencies] -rustc_macros = { path = "../librustc_macros" } +rustc_macros = { path = "../rustc_macros" } diff --git a/src/librustc_serialize/collection_impls.rs b/compiler/rustc_serialize/src/collection_impls.rs similarity index 100% rename from src/librustc_serialize/collection_impls.rs rename to compiler/rustc_serialize/src/collection_impls.rs diff --git a/src/librustc_serialize/json.rs b/compiler/rustc_serialize/src/json.rs similarity index 100% rename from src/librustc_serialize/json.rs rename to compiler/rustc_serialize/src/json.rs diff --git a/src/librustc_serialize/json/tests.rs b/compiler/rustc_serialize/src/json/tests.rs similarity index 100% rename from src/librustc_serialize/json/tests.rs rename to compiler/rustc_serialize/src/json/tests.rs diff --git a/src/librustc_serialize/leb128.rs b/compiler/rustc_serialize/src/leb128.rs similarity index 100% rename from src/librustc_serialize/leb128.rs rename to compiler/rustc_serialize/src/leb128.rs diff --git a/src/librustc_serialize/lib.rs b/compiler/rustc_serialize/src/lib.rs similarity index 83% rename from src/librustc_serialize/lib.rs rename to compiler/rustc_serialize/src/lib.rs index 265b3b95e9..fab29f29e8 100644 --- a/src/librustc_serialize/lib.rs +++ b/compiler/rustc_serialize/src/lib.rs @@ -5,7 +5,7 @@ Core encoding and decoding interfaces. */ #![doc( - html_root_url = "https://doc.rust-lang.org/nightly/", + html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/", html_playground_url = "https://play.rust-lang.org/", test(attr(allow(unused_variables), deny(warnings))) )] @@ -13,6 +13,7 @@ Core encoding and decoding interfaces. #![feature(never_type)] #![feature(nll)] #![feature(associated_type_bounds)] +#![feature(min_const_generics)] #![cfg_attr(test, feature(test))] #![allow(rustc::internal)] diff --git a/src/librustc_serialize/opaque.rs b/compiler/rustc_serialize/src/opaque.rs similarity index 100% rename from src/librustc_serialize/opaque.rs rename to compiler/rustc_serialize/src/opaque.rs diff --git a/src/librustc_serialize/serialize.rs b/compiler/rustc_serialize/src/serialize.rs similarity index 96% rename from src/librustc_serialize/serialize.rs rename to compiler/rustc_serialize/src/serialize.rs index c0e23b89a6..aa305f3c7f 100644 --- a/src/librustc_serialize/serialize.rs +++ b/compiler/rustc_serialize/src/serialize.rs @@ -539,12 +539,8 @@ impl> Encodable for [T] { impl> Encodable for Vec { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } @@ -560,22 +556,18 @@ impl> Decodable for Vec { } } -impl Encodable for [u8; 20] { +impl, const N: usize> Encodable for [T; N] { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } -impl Decodable for [u8; 20] { - fn decode(d: &mut D) -> Result<[u8; 20], D::Error> { +impl Decodable for [u8; N] { + fn decode(d: &mut D) -> Result<[u8; N], D::Error> { d.read_seq(|d, len| { - assert!(len == 20); - let mut v = [0u8; 20]; + assert!(len == N); + let mut v = [0u8; N]; for i in 0..len { v[i] = d.read_seq_elt(i, |d| Decodable::decode(d))?; } @@ -589,12 +581,8 @@ where [T]: ToOwned>, { fn encode(&self, s: &mut S) -> Result<(), S::Error> { - s.emit_seq(self.len(), |s| { - for (i, e) in self.iter().enumerate() { - s.emit_seq_elt(i, |s| e.encode(s))? - } - Ok(()) - }) + let slice: &[T] = self; + slice.encode(s) } } diff --git a/src/librustc_serialize/tests/json.rs b/compiler/rustc_serialize/tests/json.rs similarity index 100% rename from src/librustc_serialize/tests/json.rs rename to compiler/rustc_serialize/tests/json.rs diff --git a/src/librustc_serialize/tests/leb128.rs b/compiler/rustc_serialize/tests/leb128.rs similarity index 100% rename from src/librustc_serialize/tests/leb128.rs rename to compiler/rustc_serialize/tests/leb128.rs diff --git a/src/librustc_serialize/tests/opaque.rs b/compiler/rustc_serialize/tests/opaque.rs similarity index 100% rename from src/librustc_serialize/tests/opaque.rs rename to compiler/rustc_serialize/tests/opaque.rs diff --git a/compiler/rustc_session/Cargo.toml b/compiler/rustc_session/Cargo.toml new file mode 100644 index 0000000000..cdff1662fd --- /dev/null +++ b/compiler/rustc_session/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_session" +version = "0.0.0" +edition = "2018" + +[dependencies] +bitflags = "1.2.1" +getopts = "0.2" +rustc_macros = { path = "../rustc_macros" } +tracing = "0.1" +rustc_errors = { path = "../rustc_errors" } +rustc_feature = { path = "../rustc_feature" } +rustc_target = { path = "../rustc_target" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_span = { path = "../rustc_span" } +rustc_fs_util = { path = "../rustc_fs_util" } +num_cpus = "1.0" +rustc_ast = { path = "../rustc_ast" } diff --git a/src/librustc_session/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs similarity index 100% rename from src/librustc_session/cgu_reuse_tracker.rs rename to compiler/rustc_session/src/cgu_reuse_tracker.rs diff --git a/src/librustc_session/code_stats.rs b/compiler/rustc_session/src/code_stats.rs similarity index 100% rename from src/librustc_session/code_stats.rs rename to compiler/rustc_session/src/code_stats.rs diff --git a/src/librustc_session/config.rs b/compiler/rustc_session/src/config.rs similarity index 95% rename from src/librustc_session/config.rs rename to compiler/rustc_session/src/config.rs index 1808a0ca59..ab96b0333f 100644 --- a/src/librustc_session/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -12,6 +12,7 @@ use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::impl_stable_hash_via_hash; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; +use rustc_target::abi::{Align, TargetDataLayout}; use rustc_target::spec::{Target, TargetTriple}; use crate::parse::CrateConfig; @@ -163,6 +164,21 @@ pub enum LtoCli { Unspecified, } +/// The different settings that the `-Z dump_mir_spanview` flag can have. `Statement` generates a +/// document highlighting each span of every statement (including terminators). `Terminator` and +/// `Block` highlight a single span per `BasicBlock`: the span of the block's `Terminator`, or a +/// computed span for the block, representing the entire range, covering the block's terminator and +/// all of its statements. +#[derive(Clone, Copy, PartialEq, Hash, Debug)] +pub enum MirSpanview { + /// Default `-Z dump_mir_spanview` or `-Z dump_mir_spanview=statement` + Statement, + /// `-Z dump_mir_spanview=terminator` + Terminator, + /// `-Z dump_mir_spanview=block` + Block, +} + #[derive(Clone, PartialEq, Hash)] pub enum LinkerPluginLto { LinkerPlugin(PathBuf), @@ -313,6 +329,23 @@ impl Default for ErrorOutputType { } } +/// Parameter to control path trimming. +#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] +pub enum TrimmedDefPaths { + /// `try_print_trimmed_def_path` never prints a trimmed path and never calls the expensive query + Never, + /// `try_print_trimmed_def_path` calls the expensive query, the query doesn't call `delay_good_path_bug` + Always, + /// `try_print_trimmed_def_path` calls the expensive query, the query calls `delay_good_path_bug` + GoodPath, +} + +impl Default for TrimmedDefPaths { + fn default() -> Self { + Self::Never + } +} + /// Use tree-based collections to cheaply get a deterministic `Hash` implementation. /// *Do not* switch `BTreeMap` out for an unsorted container type! That would break /// dependency tracking for command-line arguments. @@ -549,9 +582,9 @@ impl OutputFilenames { if !ext.is_empty() { if !extension.is_empty() { - extension.push_str("."); + extension.push('.'); extension.push_str(RUST_CGU_EXT); - extension.push_str("."); + extension.push('.'); } extension.push_str(ext); @@ -606,6 +639,7 @@ impl Default for Options { unstable_features: UnstableFeatures::Disallow, debug_assertions: true, actually_rustdoc: false, + trimmed_def_paths: TrimmedDefPaths::default(), cli_forced_codegen_units: None, cli_forced_thinlto_off: false, remap_path_prefix: Vec::new(), @@ -715,6 +749,9 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { let min_atomic_width = sess.target.target.min_atomic_width(); let max_atomic_width = sess.target.target.max_atomic_width(); let atomic_cas = sess.target.target.options.atomic_cas; + let layout = TargetDataLayout::parse(&sess.target.target).unwrap_or_else(|err| { + sess.fatal(&err); + }); let mut ret = FxHashSet::default(); ret.reserve(6); // the minimum number of insertions @@ -736,18 +773,27 @@ pub fn default_configuration(sess: &Session) -> CrateConfig { if sess.target.target.options.has_elf_tls { ret.insert((sym::target_thread_local, None)); } - for &i in &[8, 16, 32, 64, 128] { + for &(i, align) in &[ + (8, layout.i8_align.abi), + (16, layout.i16_align.abi), + (32, layout.i32_align.abi), + (64, layout.i64_align.abi), + (128, layout.i128_align.abi), + ] { if i >= min_atomic_width && i <= max_atomic_width { - let mut insert_atomic = |s| { + let mut insert_atomic = |s, align: Align| { ret.insert((sym::target_has_atomic_load_store, Some(Symbol::intern(s)))); if atomic_cas { ret.insert((sym::target_has_atomic, Some(Symbol::intern(s)))); } + if align.bits() == i { + ret.insert((sym::target_has_atomic_equal_alignment, Some(Symbol::intern(s)))); + } }; let s = i.to_string(); - insert_atomic(&s); + insert_atomic(&s, align); if &s == wordsz { - insert_atomic("ptr"); + insert_atomic("ptr", layout.pointer_align.abi); } } } @@ -785,10 +831,11 @@ pub fn build_configuration(sess: &Session, mut user_cfg: CrateConfig) -> CrateCo user_cfg } -pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Config { - let target = Target::search(&opts.target_triple).unwrap_or_else(|e| { +pub fn build_target_config(opts: &Options, target_override: Option) -> Config { + let target_result = target_override.map_or_else(|| Target::search(&opts.target_triple), Ok); + let target = target_result.unwrap_or_else(|e| { early_error( - error_format, + opts.error_format, &format!( "Error loading target specification: {}. \ Use `--print target-list` for a list of built-in targets", @@ -802,7 +849,7 @@ pub fn build_target_config(opts: &Options, error_format: ErrorOutputType) -> Con "32" => 32, "64" => 64, w => early_error( - error_format, + opts.error_format, &format!( "target specification was invalid: \ unrecognized target-pointer-width {}", @@ -1709,6 +1756,10 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } + if debugging_opts.experimental_coverage { + debugging_opts.instrument_coverage = true; + } + if debugging_opts.instrument_coverage { if cg.profile_generate.enabled() || cg.profile_use.is_some() { early_error( @@ -1718,20 +1769,15 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { ); } - // `-Z instrument-coverage` implies: - // * `-Z symbol-mangling-version=v0` - to ensure consistent and reversible name mangling. - // Note, LLVM coverage tools can analyze coverage over multiple runs, including some - // changes to source code; so mangled names must be consistent across compilations. - // * `-C link-dead-code` - so unexecuted code is still counted as zero, rather than be - // optimized out. Note that instrumenting dead code can be explicitly disabled with: - // `-Z instrument-coverage -C link-dead-code=no`. + // `-Z instrument-coverage` implies `-Z symbol-mangling-version=v0` - to ensure consistent + // and reversible name mangling. Note, LLVM coverage tools can analyze coverage over + // multiple runs, including some changes to source code; so mangled names must be consistent + // across compilations. debugging_opts.symbol_mangling_version = SymbolManglingVersion::V0; - if cg.link_dead_code == None { - // FIXME(richkadel): Investigate if the `instrument-coverage` implementation can - // inject ["zero counters"](https://llvm.org/docs/CoverageMappingFormat.html#counter) - // in the coverage map when "dead code" is removed, rather than forcing `link-dead-code`. - cg.link_dead_code = Some(true); - } + } + + if let Ok(graphviz_font) = std::env::var("RUSTC_GRAPHVIZ_FONT") { + debugging_opts.graphviz_font = graphviz_font; } if !cg.embed_bitcode { @@ -1805,6 +1851,7 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options { unstable_features: UnstableFeatures::from_environment(), debug_assertions, actually_rustdoc: false, + trimmed_def_paths: TrimmedDefPaths::default(), cli_forced_codegen_units: codegen_units, cli_forced_thinlto_off: disable_thinlto, remap_path_prefix, @@ -2051,7 +2098,7 @@ crate mod dep_tracking { use super::{ CFGuard, CrateType, DebugInfo, ErrorOutputType, LinkerPluginLto, LtoCli, OptLevel, OutputTypes, Passes, SanitizerSet, SourceFileHashAlgorithm, SwitchWithOptPath, - SymbolManglingVersion, + SymbolManglingVersion, TrimmedDefPaths, }; use crate::lint; use crate::utils::NativeLibKind; @@ -2132,6 +2179,7 @@ crate mod dep_tracking { impl_dep_tracking_hash_via_hash!(SwitchWithOptPath); impl_dep_tracking_hash_via_hash!(SymbolManglingVersion); impl_dep_tracking_hash_via_hash!(Option); + impl_dep_tracking_hash_via_hash!(TrimmedDefPaths); impl_dep_tracking_hash_for_sortable_vec_of!(String); impl_dep_tracking_hash_for_sortable_vec_of!(PathBuf); diff --git a/src/librustc_session/filesearch.rs b/compiler/rustc_session/src/filesearch.rs similarity index 99% rename from src/librustc_session/filesearch.rs rename to compiler/rustc_session/src/filesearch.rs index 284fca652e..12a268d5b1 100644 --- a/src/librustc_session/filesearch.rs +++ b/compiler/rustc_session/src/filesearch.rs @@ -1,5 +1,3 @@ -#![allow(non_camel_case_types)] - pub use self::FileMatch::*; use std::borrow::Cow; diff --git a/src/librustc_session/lib.rs b/compiler/rustc_session/src/lib.rs similarity index 94% rename from src/librustc_session/lib.rs rename to compiler/rustc_session/src/lib.rs index c2ea141a06..a808261798 100644 --- a/src/librustc_session/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -1,4 +1,5 @@ #![feature(crate_visibility_modifier)] +#![feature(once_cell)] #![feature(or_patterns)] #[macro_use] diff --git a/src/librustc_session/lint.rs b/compiler/rustc_session/src/lint.rs similarity index 84% rename from src/librustc_session/lint.rs rename to compiler/rustc_session/src/lint.rs index 0dcbee08ab..62e021d5e4 100644 --- a/src/librustc_session/lint.rs +++ b/compiler/rustc_session/src/lint.rs @@ -65,9 +65,15 @@ pub struct Lint { /// /// The name is written with underscores, e.g., "unused_imports". /// On the command line, underscores become dashes. + /// + /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#lint-naming + /// for naming guidelines. pub name: &'static str, /// Default level for the lint. + /// + /// See https://rustc-dev-guide.rust-lang.org/diagnostics.html#diagnostic-levels + /// for guidelines on choosing a default level. pub default_level: Level, /// Description of the lint or the issue it detects. @@ -275,17 +281,60 @@ impl LintBuffer { } /// Declares a static item of type `&'static Lint`. +/// +/// See https://rustc-dev-guide.rust-lang.org/diagnostics.html for documentation +/// and guidelines on writing lints. +/// +/// The macro call should start with a doc comment explaining the lint +/// which will be embedded in the rustc user documentation book. It should +/// be written in markdown and have a format that looks like this: +/// +/// ```rust,ignore (doc-example) +/// /// The `my_lint_name` lint detects [short explanation here]. +/// /// +/// /// ### Example +/// /// +/// /// ```rust +/// /// [insert a concise example that triggers the lint] +/// /// ``` +/// /// +/// /// {{produces}} +/// /// +/// /// ### Explanation +/// /// +/// /// This should be a detailed explanation of *why* the lint exists, +/// /// and also include suggestions on how the user should fix the problem. +/// /// Try to keep the text simple enough that a beginner can understand, +/// /// and include links to other documentation for terminology that a +/// /// beginner may not be familiar with. If this is "allow" by default, +/// /// it should explain why (are there false positives or other issues?). If +/// /// this is a future-incompatible lint, it should say so, with text that +/// /// looks roughly like this: +/// /// +/// /// This is a [future-incompatible] lint to transition this to a hard +/// /// error in the future. See [issue #xxxxx] for more details. +/// /// +/// /// [issue #xxxxx]: https://github.com/rust-lang/rust/issues/xxxxx +/// ``` +/// +/// The `{{produces}}` tag will be automatically replaced with the output from +/// the example by the build system. You can build and view the rustc book +/// with `x.py doc --stage=1 src/doc/rustc --open`. If the lint example is too +/// complex to run as a simple example (for example, it needs an extern +/// crate), mark it with `ignore` and manually paste the expected output below +/// the example. #[macro_export] macro_rules! declare_lint { - ($vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr) => ( $crate::declare_lint!( - $vis $NAME, $Level, $desc, + $(#[$attr])* $vis $NAME, $Level, $desc, ); ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $(@future_incompatible = $fi:expr;)? $(@feature_gate = $gate:expr;)? $($v:ident),*) => ( + $(#[$attr])* $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, @@ -298,9 +347,10 @@ macro_rules! declare_lint { ..$crate::lint::Lint::default_fields_for_macro() }; ); - ($vis: vis $NAME: ident, $Level: ident, $desc: expr, + ($(#[$attr:meta])* $vis: vis $NAME: ident, $Level: ident, $desc: expr, $lint_edition: expr => $edition_level: ident ) => ( + $(#[$attr])* $vis static $NAME: &$crate::lint::Lint = &$crate::lint::Lint { name: stringify!($NAME), default_level: $crate::lint::$Level, diff --git a/compiler/rustc_session/src/lint/builtin.rs b/compiler/rustc_session/src/lint/builtin.rs new file mode 100644 index 0000000000..6133f4d94a --- /dev/null +++ b/compiler/rustc_session/src/lint/builtin.rs @@ -0,0 +1,2783 @@ +//! Some lints that are built in to the compiler. +//! +//! These are the built-in lints that are emitted direct in the main +//! compiler code, rather than using their own custom pass. Those +//! lints are all available in `rustc_lint::builtin`. + +use crate::lint::FutureIncompatibleInfo; +use crate::{declare_lint, declare_lint_pass, declare_tool_lint}; +use rustc_span::edition::Edition; +use rustc_span::symbol::sym; + +declare_lint! { + /// The `ill_formed_attribute_input` lint detects ill-formed attribute + /// inputs that were previously accepted and used in practice. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[inline = "this is not valid"] + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previously, inputs for many built-in attributes weren't validated and + /// nonsensical attribute inputs were accepted. After validation was + /// added, it was determined that some existing projects made use of these + /// invalid forms. This is a [future-incompatible] lint to transition this + /// to a hard error in the future. See [issue #57571] for more details. + /// + /// Check the [attribute reference] for details on the valid inputs for + /// attributes. + /// + /// [issue #57571]: https://github.com/rust-lang/rust/issues/57571 + /// [attribute reference]: https://doc.rust-lang.org/nightly/reference/attributes.html + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub ILL_FORMED_ATTRIBUTE_INPUT, + Deny, + "ill-formed attribute inputs that were previously accepted and used in practice", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #57571 ", + edition: None, + }; + crate_level_only +} + +declare_lint! { + /// The `conflicting_repr_hints` lint detects [`repr` attributes] with + /// conflicting hints. + /// + /// [`repr` attributes]: https://doc.rust-lang.org/reference/type-layout.html#representations + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[repr(u32, u64)] + /// enum Foo { + /// Variant1, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler incorrectly accepted these conflicting representations in + /// the past. This is a [future-incompatible] lint to transition this to a + /// hard error in the future. See [issue #68585] for more details. + /// + /// To correct the issue, remove one of the conflicting hints. + /// + /// [issue #68585]: https://github.com/rust-lang/rust/issues/68585 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub CONFLICTING_REPR_HINTS, + Deny, + "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #68585 ", + edition: None, + }; +} + +declare_lint! { + /// The `meta_variable_misuse` lint detects possible meta-variable misuse + /// in macro definitions. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(meta_variable_misuse)] + /// + /// macro_rules! foo { + /// () => {}; + /// ($( $i:ident = $($j:ident),+ );*) => { $( $( $i = $k; )+ )* }; + /// } + /// + /// fn main() { + /// foo!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There are quite a few different ways a [`macro_rules`] macro can be + /// improperly defined. Many of these errors were previously only detected + /// when the macro was expanded or not at all. This lint is an attempt to + /// catch some of these problems when the macro is *defined*. + /// + /// This lint is "allow" by default because it may have false positives + /// and other issues. See [issue #61053] for more details. + /// + /// [`macro_rules`]: https://doc.rust-lang.org/reference/macros-by-example.html + /// [issue #61053]: https://github.com/rust-lang/rust/issues/61053 + pub META_VARIABLE_MISUSE, + Allow, + "possible meta-variable misuse at macro definition" +} + +declare_lint! { + /// The `incomplete_include` lint detects the use of the [`include!`] + /// macro with a file that contains more than one expression. + /// + /// [`include!`]: https://doc.rust-lang.org/std/macro.include.html + /// + /// ### Example + /// + /// ```rust,ignore (needs separate file) + /// fn main() { + /// include!("foo.txt"); + /// } + /// ``` + /// + /// where the file `foo.txt` contains: + /// + /// ```text + /// println!("hi!"); + /// ``` + /// + /// produces: + /// + /// ```text + /// error: include macro expected single expression in source + /// --> foo.txt:1:14 + /// | + /// 1 | println!("1"); + /// | ^ + /// | + /// = note: `#[deny(incomplete_include)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// The [`include!`] macro is currently only intended to be used to + /// include a single [expression] or multiple [items]. Historically it + /// would ignore any contents after the first expression, but that can be + /// confusing. In the example above, the `println!` expression ends just + /// before the semicolon, making the semicolon "extra" information that is + /// ignored. Perhaps even more surprising, if the included file had + /// multiple print statements, the subsequent ones would be ignored! + /// + /// One workaround is to place the contents in braces to create a [block + /// expression]. Also consider alternatives, like using functions to + /// encapsulate the expressions, or use [proc-macros]. + /// + /// This is a lint instead of a hard error because existing projects were + /// found to hit this error. To be cautious, it is a lint for now. The + /// future semantics of the `include!` macro are also uncertain, see + /// [issue #35560]. + /// + /// [items]: https://doc.rust-lang.org/reference/items.html + /// [expression]: https://doc.rust-lang.org/reference/expressions.html + /// [block expression]: https://doc.rust-lang.org/reference/expressions/block-expr.html + /// [proc-macros]: https://doc.rust-lang.org/reference/procedural-macros.html + /// [issue #35560]: https://github.com/rust-lang/rust/issues/35560 + pub INCOMPLETE_INCLUDE, + Deny, + "trailing content in included file" +} + +declare_lint! { + /// The `arithmetic_overflow` lint detects that an arithmetic operation + /// will [overflow]. + /// + /// [overflow]: https://doc.rust-lang.org/reference/expressions/operator-expr.html#overflow + /// + /// ### Example + /// + /// ```rust,compile_fail + /// 1_i32 << 32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is very likely a mistake to perform an arithmetic operation that + /// overflows its value. If the compiler is able to detect these kinds of + /// overflows at compile-time, it will trigger this lint. Consider + /// adjusting the expression to avoid overflow, or use a data type that + /// will not overflow. + pub ARITHMETIC_OVERFLOW, + Deny, + "arithmetic operation overflows" +} + +declare_lint! { + /// The `unconditional_panic` lint detects an operation that will cause a + /// panic at runtime. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// let x = 1 / 0; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint detects code that is very likely incorrect. When possible, + /// the compiler will attempt to detect situations where code can be + /// evaluated at compile-time to generate more efficient code. While + /// evaluating such code, if it detects that the code will unconditionally + /// panic, this usually indicates that it is doing something incorrectly. + /// If this lint is allowed, then the code will not be evaluated at + /// compile-time, and instead continue to generate code to evaluate at + /// runtime, which may panic during runtime. + pub UNCONDITIONAL_PANIC, + Deny, + "operation will cause a panic at runtime" +} + +declare_lint! { + /// The `const_err` lint detects an erroneous expression while doing + /// constant evaluation. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![allow(unconditional_panic)] + /// let x: &'static i32 = &(1 / 0); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This lint detects code that is very likely incorrect. If this lint is + /// allowed, then the code will not be evaluated at compile-time, and + /// instead continue to generate code to evaluate at runtime, which may + /// panic during runtime. + /// + /// Note that this lint may trigger in either inside or outside of a + /// [const context]. Outside of a [const context], the compiler can + /// sometimes evaluate an expression at compile-time in order to generate + /// more efficient code. As the compiler becomes better at doing this, it + /// needs to decide what to do when it encounters code that it knows for + /// certain will panic or is otherwise incorrect. Making this a hard error + /// would prevent existing code that exhibited this behavior from + /// compiling, breaking backwards-compatibility. However, this is almost + /// certainly incorrect code, so this is a deny-by-default lint. For more + /// details, see [RFC 1229] and [issue #28238]. + /// + /// Note that there are several other more specific lints associated with + /// compile-time evaluation, such as [`arithmetic_overflow`], + /// [`unconditional_panic`]. + /// + /// [const context]: https://doc.rust-lang.org/reference/const_eval.html#const-context + /// [RFC 1229]: https://github.com/rust-lang/rfcs/blob/master/text/1229-compile-time-asserts.md + /// [issue #28238]: https://github.com/rust-lang/rust/issues/28238 + /// [`arithmetic_overflow`]: deny-by-default.html#arithmetic-overflow + /// [`unconditional_panic`]: deny-by-default.html#unconditional-panic + pub CONST_ERR, + Deny, + "constant evaluation detected erroneous expression", + report_in_external_macro +} + +declare_lint! { + /// The `unused_imports` lint detects imports that are never used. + /// + /// ### Example + /// + /// ```rust + /// use std::collections::HashMap; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused imports may signal a mistake or unfinished code, and clutter + /// the code, and should be removed. If you intended to re-export the item + /// to make it available outside of the module, add a visibility modifier + /// like `pub`. + pub UNUSED_IMPORTS, + Warn, + "imports that are never used" +} + +declare_lint! { + /// The `unused_extern_crates` lint guards against `extern crate` items + /// that are never used. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_extern_crates)] + /// extern crate proc_macro; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `extern crate` items that are unused have no effect and should be + /// removed. Note that there are some cases where specifying an `extern + /// crate` is desired for the side effect of ensuring the given crate is + /// linked, even though it is not otherwise directly referenced. The lint + /// can be silenced by aliasing the crate to an underscore, such as + /// `extern crate foo as _`. Also note that it is no longer idiomatic to + /// use `extern crate` in the [2018 edition], as extern crates are now + /// automatically added in scope. + /// + /// This lint is "allow" by default because it can be noisy, and produce + /// false-positives. If a dependency is being removed from a project, it + /// is recommended to remove it from the build configuration (such as + /// `Cargo.toml`) to ensure stale build entries aren't left behind. + /// + /// [2018 edition]: https://doc.rust-lang.org/edition-guide/rust-2018/module-system/path-clarity.html#no-more-extern-crate + pub UNUSED_EXTERN_CRATES, + Allow, + "extern crates that are never used" +} + +declare_lint! { + /// The `unused_crate_dependencies` lint detects crate dependencies that + /// are never used. + /// + /// ### Example + /// + /// ```rust,ignore (needs extern crate) + /// #![deny(unused_crate_dependencies)] + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: external crate `regex` unused in `lint_example`: remove the dependency or add `use regex as _;` + /// | + /// note: the lint level is defined here + /// --> src/lib.rs:1:9 + /// | + /// 1 | #![deny(unused_crate_dependencies)] + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// After removing the code that uses a dependency, this usually also + /// requires removing the dependency from the build configuration. + /// However, sometimes that step can be missed, which leads to time wasted + /// building dependencies that are no longer used. This lint can be + /// enabled to detect dependencies that are never used (more specifically, + /// any dependency passed with the `--extern` command-line flag that is + /// never referenced via [`use`], [`extern crate`], or in any [path]). + /// + /// This lint is "allow" by default because it can provide false positives + /// depending on how the build system is configured. For example, when + /// using Cargo, a "package" consists of multiple crates (such as a + /// library and a binary), but the dependencies are defined for the + /// package as a whole. If there is a dependency that is only used in the + /// binary, but not the library, then the lint will be incorrectly issued + /// in the library. + /// + /// [path]: https://doc.rust-lang.org/reference/paths.html + /// [`use`]: https://doc.rust-lang.org/reference/items/use-declarations.html + /// [`extern crate`]: https://doc.rust-lang.org/reference/items/extern-crates.html + pub UNUSED_CRATE_DEPENDENCIES, + Allow, + "crate dependencies that are never used", + crate_level_only +} + +declare_lint! { + /// The `unused_qualifications` lint detects unnecessarily qualified + /// names. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unused_qualifications)] + /// mod foo { + /// pub fn bar() {} + /// } + /// + /// fn main() { + /// use foo::bar; + /// foo::bar(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If an item from another module is already brought into scope, then + /// there is no need to qualify it in this case. You can call `bar()` + /// directly, without the `foo::`. + /// + /// This lint is "allow" by default because it is somewhat pedantic, and + /// doesn't indicate an actual problem, but rather a stylistic choice, and + /// can be noisy when refactoring or moving around code. + pub UNUSED_QUALIFICATIONS, + Allow, + "detects unnecessarily qualified names" +} + +declare_lint! { + /// The `unknown_lints` lint detects unrecognized lint attribute. + /// + /// ### Example + /// + /// ```rust + /// #![allow(not_a_real_lint)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to specify a lint that does not exist. Check + /// the spelling, and check the lint listing for the correct name. Also + /// consider if you are using an old version of the compiler, and the lint + /// is only available in a newer version. + pub UNKNOWN_LINTS, + Warn, + "unrecognized lint attribute" +} + +declare_lint! { + /// The `unused_variables` lint detects variables which are not used in + /// any way. + /// + /// ### Example + /// + /// ```rust + /// let x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused variables may signal a mistake or unfinished code. To silence + /// the warning for the individual variable, prefix it with an underscore + /// such as `_x`. + pub UNUSED_VARIABLES, + Warn, + "detect variables which are not used in any way" +} + +declare_lint! { + /// The `unused_assignments` lint detects assignments that will never be read. + /// + /// ### Example + /// + /// ```rust + /// let mut x = 5; + /// x = 6; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused assignments may signal a mistake or unfinished code. If the + /// variable is never used after being assigned, then the assignment can + /// be removed. Variables with an underscore prefix such as `_x` will not + /// trigger this lint. + pub UNUSED_ASSIGNMENTS, + Warn, + "detect assignments that will never be read" +} + +declare_lint! { + /// The `dead_code` lint detects unused, unexported items. + /// + /// ### Example + /// + /// ```rust + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Dead code may signal a mistake or unfinished code. To silence the + /// warning for individual items, prefix the name with an underscore such + /// as `_foo`. If it was intended to expose the item outside of the crate, + /// consider adding a visibility modifier like `pub`. Otherwise consider + /// removing the unused code. + pub DEAD_CODE, + Warn, + "detect unused, unexported items" +} + +declare_lint! { + /// The `unused_attributes` lint detects attributes that were not used by + /// the compiler. + /// + /// ### Example + /// + /// ```rust + /// #![macro_export] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused [attributes] may indicate the attribute is placed in the wrong + /// position. Consider removing it, or placing it in the correct position. + /// Also consider if you intended to use an _inner attribute_ (with a `!` + /// such as `#![allow(unused)]`) which applies to the item the attribute + /// is within, or an _outer attribute_ (without a `!` such as + /// `#[allow(unsued)]`) which applies to the item *following* the + /// attribute. + /// + /// [attributes]: https://doc.rust-lang.org/reference/attributes.html + pub UNUSED_ATTRIBUTES, + Warn, + "detects attributes that were not used by the compiler" +} + +declare_lint! { + /// The `unreachable_code` lint detects unreachable code paths. + /// + /// ### Example + /// + /// ```rust,no_run + /// panic!("we never go past here!"); + /// + /// let x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unreachable code may signal a mistake or unfinished code. If the code + /// is no longer in use, consider removing it. + pub UNREACHABLE_CODE, + Warn, + "detects unreachable code paths", + report_in_external_macro +} + +declare_lint! { + /// The `unreachable_patterns` lint detects unreachable patterns. + /// + /// ### Example + /// + /// ```rust + /// let x = 5; + /// match x { + /// y => (), + /// 5 => (), + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This usually indicates a mistake in how the patterns are specified or + /// ordered. In this example, the `y` pattern will always match, so the + /// five is impossible to reach. Remember, match arms match in order, you + /// probably wanted to put the `5` case above the `y` case. + pub UNREACHABLE_PATTERNS, + Warn, + "detects unreachable patterns" +} + +declare_lint! { + /// The `overlapping_patterns` lint detects `match` arms that have + /// [range patterns] that overlap. + /// + /// [range patterns]: https://doc.rust-lang.org/nightly/reference/patterns.html#range-patterns + /// + /// ### Example + /// + /// ```rust + /// let x = 123u8; + /// match x { + /// 0..=100 => { println!("small"); } + /// 100..=255 => { println!("large"); } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is likely a mistake to have range patterns in a match expression + /// that overlap. Check that the beginning and end values are what you + /// expect, and keep in mind that with `..=` the left and right bounds are + /// inclusive. + pub OVERLAPPING_PATTERNS, + Warn, + "detects overlapping patterns" +} + +declare_lint! { + /// The `bindings_with_variant_name` lint detects pattern bindings with + /// the same name as one of the matched variants. + /// + /// ### Example + /// + /// ```rust + /// pub enum Enum { + /// Foo, + /// Bar, + /// } + /// + /// pub fn foo(x: Enum) { + /// match x { + /// Foo => {} + /// Bar => {} + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to specify an enum variant name as an + /// [identifier pattern]. In the example above, the `match` arms are + /// specifying a variable name to bind the value of `x` to. The second arm + /// is ignored because the first one matches *all* values. The likely + /// intent is that the arm was intended to match on the enum variant. + /// + /// Two possible solutions are: + /// + /// * Specify the enum variant using a [path pattern], such as + /// `Enum::Foo`. + /// * Bring the enum variants into local scope, such as adding `use + /// Enum::*;` to the beginning of the `foo` function in the example + /// above. + /// + /// [identifier pattern]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns + /// [path pattern]: https://doc.rust-lang.org/reference/patterns.html#path-patterns + pub BINDINGS_WITH_VARIANT_NAME, + Warn, + "detects pattern bindings with the same name as one of the matched variants" +} + +declare_lint! { + /// The `unused_macros` lint detects macros that were not used. + /// + /// ### Example + /// + /// ```rust + /// macro_rules! unused { + /// () => {}; + /// } + /// + /// fn main() { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused macros may signal a mistake or unfinished code. To silence the + /// warning for the individual macro, prefix the name with an underscore + /// such as `_my_macro`. If you intended to export the macro to make it + /// available outside of the crate, use the [`macro_export` attribute]. + /// + /// [`macro_export` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope + pub UNUSED_MACROS, + Warn, + "detects macros that were not used" +} + +declare_lint! { + /// The `warnings` lint allows you to change the level of other + /// lints which produce warnings. + /// + /// ### Example + /// + /// ```rust + /// #![deny(warnings)] + /// fn foo() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The `warnings` lint is a bit special; by changing its level, you + /// change every other warning that would produce a warning to whatever + /// value you'd like. As such, you won't ever trigger this lint in your + /// code directly. + pub WARNINGS, + Warn, + "mass-change the level for lints which produce warnings" +} + +declare_lint! { + /// The `unused_features` lint detects unused or unknown features found in + /// crate-level [`feature` attributes]. + /// + /// [`feature` attributes]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// Note: This lint is currently not functional, see [issue #44232] for + /// more details. + /// + /// [issue #44232]: https://github.com/rust-lang/rust/issues/44232 + pub UNUSED_FEATURES, + Warn, + "unused features found in crate-level `#[feature]` directives" +} + +declare_lint! { + /// The `stable_features` lint detects a [`feature` attribute] that + /// has since been made stable. + /// + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + /// + /// ### Example + /// + /// ```rust + /// #![feature(test_accepted_feature)] + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When a feature is stabilized, it is no longer necessary to include a + /// `#![feature]` attribute for it. To fix, simply remove the + /// `#![feature]` attribute. + pub STABLE_FEATURES, + Warn, + "stable features found in `#[feature]` directive" +} + +declare_lint! { + /// The `unknown_crate_types` lint detects an unknown crate type found in + /// a [`crate_type` attribute]. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![crate_type="lol"] + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// An unknown value give to the `crate_type` attribute is almost + /// certainly a mistake. + /// + /// [`crate_type` attribute]: https://doc.rust-lang.org/reference/linkage.html + pub UNKNOWN_CRATE_TYPES, + Deny, + "unknown crate type found in `#[crate_type]` directive", + crate_level_only +} + +declare_lint! { + /// The `trivial_casts` lint detects trivial casts which could be replaced + /// with coercion, which may require [type ascription] or a temporary + /// variable. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(trivial_casts)] + /// let x: &u32 = &42; + /// let y = x as *const u32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trivial cast is a cast `e as T` where `e` has type `U` and `U` is a + /// subtype of `T`. This type of cast is usually unnecessary, as it can be + /// usually be inferred. + /// + /// This lint is "allow" by default because there are situations, such as + /// with FFI interfaces or complex type aliases, where it triggers + /// incorrectly, or in situations where it will be more difficult to + /// clearly express the intent. It may be possible that this will become a + /// warning in the future, possibly with [type ascription] providing a + /// convenient way to work around the current issues. See [RFC 401] for + /// historical context. + /// + /// [type ascription]: https://github.com/rust-lang/rust/issues/23416 + /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md + pub TRIVIAL_CASTS, + Allow, + "detects trivial casts which could be removed" +} + +declare_lint! { + /// The `trivial_numeric_casts` lint detects trivial numeric casts of types + /// which could be removed. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(trivial_numeric_casts)] + /// let x = 42_i32 as i32; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A trivial numeric cast is a cast of a numeric type to the same numeric + /// type. This type of cast is usually unnecessary. + /// + /// This lint is "allow" by default because there are situations, such as + /// with FFI interfaces or complex type aliases, where it triggers + /// incorrectly, or in situations where it will be more difficult to + /// clearly express the intent. It may be possible that this will become a + /// warning in the future, possibly with [type ascription] providing a + /// convenient way to work around the current issues. See [RFC 401] for + /// historical context. + /// + /// [type ascription]: https://github.com/rust-lang/rust/issues/23416 + /// [RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md + pub TRIVIAL_NUMERIC_CASTS, + Allow, + "detects trivial casts of numeric types which could be removed" +} + +declare_lint! { + /// The `private_in_public` lint detects private items in public + /// interfaces not caught by the old implementation. + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// struct SemiPriv; + /// + /// mod m1 { + /// struct Priv; + /// impl super::SemiPriv { + /// pub fn f(_: Priv) {} + /// } + /// } + /// # fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The visibility rules are intended to prevent exposing private items in + /// public interfaces. This is a [future-incompatible] lint to transition + /// this to a hard error in the future. See [issue #34537] for more + /// details. + /// + /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PRIVATE_IN_PUBLIC, + Warn, + "detect private items in public interfaces not caught by the old implementation", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #34537 ", + edition: None, + }; +} + +declare_lint! { + /// The `exported_private_dependencies` lint detects private dependencies + /// that are exposed in a public interface. + /// + /// ### Example + /// + /// ```rust,ignore (needs-dependency) + /// pub fn foo() -> Option { + /// None + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: type `bar::Thing` from private dependency 'bar' in public interface + /// --> src/lib.rs:3:1 + /// | + /// 3 | pub fn foo() -> Option { + /// | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + /// | + /// = note: `#[warn(exported_private_dependencies)]` on by default + /// ``` + /// + /// ### Explanation + /// + /// Dependencies can be marked as "private" to indicate that they are not + /// exposed in the public interface of a crate. This can be used by Cargo + /// to independently resolve those dependencies because it can assume it + /// does not need to unify them with other packages using that same + /// dependency. This lint is an indication of a violation of that + /// contract. + /// + /// To fix this, avoid exposing the dependency in your public interface. + /// Or, switch the dependency to a public dependency. + /// + /// Note that support for this is only available on the nightly channel. + /// See [RFC 1977] for more details, as well as the [Cargo documentation]. + /// + /// [RFC 1977]: https://github.com/rust-lang/rfcs/blob/master/text/1977-public-private-dependencies.md + /// [Cargo documentation]: https://doc.rust-lang.org/nightly/cargo/reference/unstable.html#public-dependency + pub EXPORTED_PRIVATE_DEPENDENCIES, + Warn, + "public interface leaks type from a private dependency" +} + +declare_lint! { + /// The `pub_use_of_private_extern_crate` lint detects a specific + /// situation of re-exporting a private `extern crate`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// extern crate core; + /// pub use core as reexported_core; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A public `use` declaration should not be used to publicly re-export a + /// private `extern crate`. `pub extern crate` should be used instead. + /// + /// This was historically allowed, but is not the intended behavior + /// according to the visibility rules. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #34537] for more details. + /// + /// [issue #34537]: https://github.com/rust-lang/rust/issues/34537 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, + Deny, + "detect public re-exports of private extern crates", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #34537 ", + edition: None, + }; +} + +declare_lint! { + /// The `invalid_type_param_default` lint detects type parameter defaults + /// erroneously allowed in an invalid location. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// fn foo(t: T) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Default type parameters were only intended to be allowed in certain + /// situations, but historically the compiler allowed them everywhere. + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #36887] for more details. + /// + /// [issue #36887]: https://github.com/rust-lang/rust/issues/36887 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub INVALID_TYPE_PARAM_DEFAULT, + Deny, + "type parameter default erroneously allowed in invalid location", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #36887 ", + edition: None, + }; +} + +declare_lint! { + /// The `renamed_and_removed_lints` lint detects lints that have been + /// renamed or removed. + /// + /// ### Example + /// + /// ```rust + /// #![deny(raw_pointer_derive)] + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, either remove the lint or use the new name. This can help + /// avoid confusion about lints that are no longer valid, and help + /// maintain consistency for renamed lints. + pub RENAMED_AND_REMOVED_LINTS, + Warn, + "lints that have been renamed or removed" +} + +declare_lint! { + /// The `unaligned_references` lint detects unaligned references to fields + /// of [packed] structs. + /// + /// [packed]: https://doc.rust-lang.org/reference/type-layout.html#the-alignment-modifiers + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(unaligned_references)] + /// + /// #[repr(packed)] + /// pub struct Foo { + /// field1: u64, + /// field2: u8, + /// } + /// + /// fn main() { + /// unsafe { + /// let foo = Foo { field1: 0, field2: 0 }; + /// let _ = &foo.field1; + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Creating a reference to an insufficiently aligned packed field is + /// [undefined behavior] and should be disallowed. + /// + /// This lint is "allow" by default because there is no stable + /// alternative, and it is not yet certain how widespread existing code + /// will trigger this lint. + /// + /// See [issue #27060] for more discussion. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// [issue #27060]: https://github.com/rust-lang/rust/issues/27060 + pub UNALIGNED_REFERENCES, + Allow, + "detects unaligned references to fields of packed structs", +} + +declare_lint! { + /// The `const_item_mutation` lint detects attempts to mutate a `const` + /// item. + /// + /// ### Example + /// + /// ```rust + /// const FOO: [i32; 1] = [0]; + /// + /// fn main() { + /// FOO[0] = 1; + /// // This will print "[0]". + /// println!("{:?}", FOO); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Trying to directly mutate a `const` item is almost always a mistake. + /// What is happening in the example above is that a temporary copy of the + /// `const` is mutated, but the original `const` is not. Each time you + /// refer to the `const` by name (such as `FOO` in the example above), a + /// separate copy of the value is inlined at that location. + /// + /// This lint checks for writing directly to a field (`FOO.field = + /// some_value`) or array entry (`FOO[0] = val`), or taking a mutable + /// reference to the const item (`&mut FOO`), including through an + /// autoderef (`FOO.some_mut_self_method()`). + /// + /// There are various alternatives depending on what you are trying to + /// accomplish: + /// + /// * First, always reconsider using mutable globals, as they can be + /// difficult to use correctly, and can make the code more difficult to + /// use or understand. + /// * If you are trying to perform a one-time initialization of a global: + /// * If the value can be computed at compile-time, consider using + /// const-compatible values (see [Constant Evaluation]). + /// * For more complex single-initialization cases, consider using a + /// third-party crate, such as [`lazy_static`] or [`once_cell`]. + /// * If you are using the [nightly channel], consider the new + /// [`lazy`] module in the standard library. + /// * If you truly need a mutable global, consider using a [`static`], + /// which has a variety of options: + /// * Simple data types can be directly defined and mutated with an + /// [`atomic`] type. + /// * More complex types can be placed in a synchronization primitive + /// like a [`Mutex`], which can be initialized with one of the options + /// listed above. + /// * A [mutable `static`] is a low-level primitive, requiring unsafe. + /// Typically This should be avoided in preference of something + /// higher-level like one of the above. + /// + /// [Constant Evaluation]: https://doc.rust-lang.org/reference/const_eval.html + /// [`static`]: https://doc.rust-lang.org/reference/items/static-items.html + /// [mutable `static`]: https://doc.rust-lang.org/reference/items/static-items.html#mutable-statics + /// [`lazy`]: https://doc.rust-lang.org/nightly/std/lazy/index.html + /// [`lazy_static`]: https://crates.io/crates/lazy_static + /// [`once_cell`]: https://crates.io/crates/once_cell + /// [`atomic`]: https://doc.rust-lang.org/std/sync/atomic/index.html + /// [`Mutex`]: https://doc.rust-lang.org/std/sync/struct.Mutex.html + pub CONST_ITEM_MUTATION, + Warn, + "detects attempts to mutate a `const` item", +} + +declare_lint! { + /// The `safe_packed_borrows` lint detects borrowing a field in the + /// interior of a packed structure with alignment other than 1. + /// + /// ### Example + /// + /// ```rust + /// #[repr(packed)] + /// pub struct Unaligned(pub T); + /// + /// pub struct Foo { + /// start: u8, + /// data: Unaligned, + /// } + /// + /// fn main() { + /// let x = Foo { start: 0, data: Unaligned(1) }; + /// let y = &x.data.0; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This type of borrow is unsafe and can cause errors on some platforms + /// and violates some assumptions made by the compiler. This was + /// previously allowed unintentionally. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #46043] for more details, including guidance on how to solve the + /// problem. + /// + /// [issue #46043]: https://github.com/rust-lang/rust/issues/46043 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub SAFE_PACKED_BORROWS, + Warn, + "safe borrows of fields of packed structs were erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #46043 ", + edition: None, + }; +} + +declare_lint! { + /// The `patterns_in_fns_without_body` lint detects `mut` identifier + /// patterns as a parameter in functions without a body. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// trait Trait { + /// fn foo(mut arg: u8); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// To fix this, remove `mut` from the parameter in the trait definition; + /// it can be used in the implementation. That is, the following is OK: + /// + /// ```rust + /// trait Trait { + /// fn foo(arg: u8); // Removed `mut` here + /// } + /// + /// impl Trait for i32 { + /// fn foo(mut arg: u8) { // `mut` here is OK + /// + /// } + /// } + /// ``` + /// + /// Trait definitions can define functions without a body to specify a + /// function that implementors must define. The parameter names in the + /// body-less functions are only allowed to be `_` or an [identifier] for + /// documentation purposes (only the type is relevant). Previous versions + /// of the compiler erroneously allowed [identifier patterns] with the + /// `mut` keyword, but this was not intended to be allowed. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #35203] for more details. + /// + /// [identifier]: https://doc.rust-lang.org/reference/identifiers.html + /// [identifier patterns]: https://doc.rust-lang.org/reference/patterns.html#identifier-patterns + /// [issue #35203]: https://github.com/rust-lang/rust/issues/35203 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PATTERNS_IN_FNS_WITHOUT_BODY, + Deny, + "patterns in functions without body were erroneously allowed", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #35203 ", + edition: None, + }; +} + +declare_lint! { + /// The `missing_fragment_specifier` lint is issued when an unused pattern + /// in a `macro_rules!` macro definition has a meta-variable (e.g. `$e`) + /// that is not followed by a fragment specifier (e.g. `:expr`). + /// + /// This warning can always be fixed by removing the unused pattern in the + /// `macro_rules!` macro definition. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! foo { + /// ($e) => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// + /// ### Explanation + /// + /// The meta-variable (`$e` above) lacks a fragment specifier, which is a + /// malformed input. It can be fixed by adding a fragment specifier. + pub MISSING_FRAGMENT_SPECIFIER, + Deny, + "detects missing fragment specifiers in unused `macro_rules!` patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #40107 ", + edition: None, + }; +} + +declare_lint! { + /// The `late_bound_lifetime_arguments` lint detects generic lifetime + /// arguments in path segments with late bound lifetime parameters. + /// + /// ### Example + /// + /// ```rust + /// struct S; + /// + /// impl S { + /// fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} + /// } + /// + /// fn main() { + /// S.late::<'static>(&0, &0); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is not clear how to provide arguments for early-bound lifetime + /// parameters if they are intermixed with late-bound parameters in the + /// same list. For now, providing any explicit arguments will trigger this + /// lint if late-bound parameters are present, so in the future a solution + /// can be adopted without hitting backward compatibility issues. This is + /// a [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #42868] for more details, along with a description + /// of the difference between early and late-bound parameters. + /// + /// [issue #42868]: https://github.com/rust-lang/rust/issues/42868 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub LATE_BOUND_LIFETIME_ARGUMENTS, + Warn, + "detects generic lifetime arguments in path segments with late bound lifetime parameters", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #42868 ", + edition: None, + }; +} + +declare_lint! { + /// The `order_dependent_trait_objects` lint detects a trait coherency + /// violation that would allow creating two trait impls for the same + /// dynamic trait object involving marker traits. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// pub trait Trait {} + /// + /// impl Trait for dyn Send + Sync { } + /// impl Trait for dyn Sync + Send { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// A previous bug caused the compiler to interpret traits with different + /// orders (such as `Send + Sync` and `Sync + Send`) as distinct types + /// when they were intended to be treated the same. This allowed code to + /// define separate trait implementations when there should be a coherence + /// error. This is a [future-incompatible] lint to transition this to a + /// hard error in the future. See [issue #56484] for more details. + /// + /// [issue #56484]: https://github.com/rust-lang/rust/issues/56484 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub ORDER_DEPENDENT_TRAIT_OBJECTS, + Deny, + "trait-object types were treated as different depending on marker-trait order", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #56484 ", + edition: None, + }; +} + +declare_lint! { + /// The `coherence_leak_check` lint detects conflicting implementations of + /// a trait that are only distinguished by the old leak-check code. + /// + /// ### Example + /// + /// ```rust + /// trait SomeTrait { } + /// impl SomeTrait for for<'a> fn(&'a u8) { } + /// impl<'a> SomeTrait for fn(&'a u8) { } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the past, the compiler would accept trait implementations for + /// identical functions that differed only in where the lifetime binder + /// appeared. Due to a change in the borrow checker implementation to fix + /// several bugs, this is no longer allowed. However, since this affects + /// existing code, this is a [future-incompatible] lint to transition this + /// to a hard error in the future. + /// + /// Code relying on this pattern should introduce "[newtypes]", + /// like `struct Foo(for<'a> fn(&'a u8))`. + /// + /// See [issue #56105] for more details. + /// + /// [issue #56105]: https://github.com/rust-lang/rust/issues/56105 + /// [newtypes]: https://doc.rust-lang.org/book/ch19-04-advanced-types.html#using-the-newtype-pattern-for-type-safety-and-abstraction + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub COHERENCE_LEAK_CHECK, + Warn, + "distinct impls distinguished only by the leak-check code", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #56105 ", + edition: None, + }; +} + +declare_lint! { + /// The `deprecated` lint detects use of deprecated items. + /// + /// ### Example + /// + /// ```rust + /// #[deprecated] + /// fn foo() {} + /// + /// fn bar() { + /// foo(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Items may be marked "deprecated" with the [`deprecated` attribute] to + /// indicate that they should no longer be used. Usually the attribute + /// should include a note on what to use instead, or check the + /// documentation. + /// + /// [`deprecated` attribute]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-deprecated-attribute + pub DEPRECATED, + Warn, + "detects use of deprecated items", + report_in_external_macro +} + +declare_lint! { + /// The `unused_unsafe` lint detects unnecessary use of an `unsafe` block. + /// + /// ### Example + /// + /// ```rust + /// unsafe {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If nothing within the block requires `unsafe`, then remove the + /// `unsafe` marker because it is not required and may cause confusion. + pub UNUSED_UNSAFE, + Warn, + "unnecessary use of an `unsafe` block" +} + +declare_lint! { + /// The `unused_mut` lint detects mut variables which don't need to be + /// mutable. + /// + /// ### Example + /// + /// ```rust + /// let mut x = 5; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The preferred style is to only mark variables as `mut` if it is + /// required. + pub UNUSED_MUT, + Warn, + "detect mut variables which don't need to be mutable" +} + +declare_lint! { + /// The `unconditional_recursion` lint detects functions that cannot + /// return without calling themselves. + /// + /// ### Example + /// + /// ```rust + /// fn foo() { + /// foo(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// It is usually a mistake to have a recursive call that does not have + /// some condition to cause it to terminate. If you really intend to have + /// an infinite loop, using a `loop` expression is recommended. + pub UNCONDITIONAL_RECURSION, + Warn, + "functions that cannot return without calling themselves" +} + +declare_lint! { + /// The `single_use_lifetimes` lint detects lifetimes that are only used + /// once. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(single_use_lifetimes)] + /// + /// fn foo<'a>(x: &'a u32) {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Specifying an explicit lifetime like `'a` in a function or `impl` + /// should only be used to link together two things. Otherwise, you should + /// just use `'_` to indicate that the lifetime is not linked to anything, + /// or elide the lifetime altogether if possible. + /// + /// This lint is "allow" by default because it was introduced at a time + /// when `'_` and elided lifetimes were first being introduced, and this + /// lint would be too noisy. Also, there are some known false positives + /// that it produces. See [RFC 2115] for historical context, and [issue + /// #44752] for more details. + /// + /// [RFC 2115]: https://github.com/rust-lang/rfcs/blob/master/text/2115-argument-lifetimes.md + /// [issue #44752]: https://github.com/rust-lang/rust/issues/44752 + pub SINGLE_USE_LIFETIMES, + Allow, + "detects lifetime parameters that are only used once" +} + +declare_lint! { + /// The `unused_lifetimes` lint detects lifetime parameters that are never + /// used. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[deny(unused_lifetimes)] + /// + /// pub fn foo<'a>() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused lifetime parameters may signal a mistake or unfinished code. + /// Consider removing the parameter. + pub UNUSED_LIFETIMES, + Allow, + "detects lifetime parameters that are never used" +} + +declare_lint! { + /// The `tyvar_behind_raw_pointer` lint detects raw pointer to an + /// inference variable. + /// + /// ### Example + /// + /// ```rust,edition2015 + /// // edition 2015 + /// let data = std::ptr::null(); + /// let _ = &data as *const *const (); + /// + /// if data.is_null() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This kind of inference was previously allowed, but with the future + /// arrival of [arbitrary self types], this can introduce ambiguity. To + /// resolve this, use an explicit type instead of relying on type + /// inference. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the 2018 edition. See [issue #46906] for more details. This + /// is currently a hard-error on the 2018 edition, and is "warn" by + /// default in the 2015 edition. + /// + /// [arbitrary self types]: https://github.com/rust-lang/rust/issues/44874 + /// [issue #46906]: https://github.com/rust-lang/rust/issues/46906 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub TYVAR_BEHIND_RAW_POINTER, + Warn, + "raw pointer to an inference variable", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #46906 ", + edition: Some(Edition::Edition2018), + }; +} + +declare_lint! { + /// The `elided_lifetimes_in_paths` lint detects the use of hidden + /// lifetime parameters. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(elided_lifetimes_in_paths)] + /// struct Foo<'a> { + /// x: &'a u32 + /// } + /// + /// fn foo(x: &Foo) { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Elided lifetime parameters can make it difficult to see at a glance + /// that borrowing is occurring. This lint ensures that lifetime + /// parameters are always explicitly stated, even if it is the `'_` + /// [placeholder lifetime]. + /// + /// This lint is "allow" by default because it has some known issues, and + /// may require a significant transition for old code. + /// + /// [placeholder lifetime]: https://doc.rust-lang.org/reference/lifetime-elision.html#lifetime-elision-in-functions + pub ELIDED_LIFETIMES_IN_PATHS, + Allow, + "hidden lifetime parameters in types are deprecated", + crate_level_only +} + +declare_lint! { + /// The `bare_trait_objects` lint suggests using `dyn Trait` for trait + /// objects. + /// + /// ### Example + /// + /// ```rust + /// trait Trait { } + /// + /// fn takes_trait_object(_: Box) { + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Without the `dyn` indicator, it can be ambiguous or confusing when + /// reading code as to whether or not you are looking at a trait object. + /// The `dyn` keyword makes it explicit, and adds a symmetry to contrast + /// with [`impl Trait`]. + /// + /// [`impl Trait`]: https://doc.rust-lang.org/book/ch10-02-traits.html#traits-as-parameters + pub BARE_TRAIT_OBJECTS, + Warn, + "suggest using `dyn Trait` for trait objects" +} + +declare_lint! { + /// The `absolute_paths_not_starting_with_crate` lint detects fully + /// qualified paths that start with a module name instead of `crate`, + /// `self`, or an extern crate name + /// + /// ### Example + /// + /// ```rust,edition2015,compile_fail + /// #![deny(absolute_paths_not_starting_with_crate)] + /// + /// mod foo { + /// pub fn bar() {} + /// } + /// + /// fn main() { + /// ::foo::bar(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Rust [editions] allow the language to evolve without breaking + /// backwards compatibility. This lint catches code that uses absolute + /// paths in the style of the 2015 edition. In the 2015 edition, absolute + /// paths (those starting with `::`) refer to either the crate root or an + /// external crate. In the 2018 edition it was changed so that they only + /// refer to external crates. The path prefix `crate::` should be used + /// instead to reference items from the crate root. + /// + /// If you switch the compiler from the 2015 to 2018 edition without + /// updating the code, then it will fail to compile if the old style paths + /// are used. You can manually change the paths to use the `crate::` + /// prefix to transition to the 2018 edition. + /// + /// This lint solves the problem automatically. It is "allow" by default + /// because the code is perfectly valid in the 2015 edition. The [`cargo + /// fix`] tool with the `--edition` flag will switch this lint to "warn" + /// and automatically apply the suggested fix from the compiler. This + /// provides a completely automated way to update old code to the 2018 + /// edition. + /// + /// [editions]: https://doc.rust-lang.org/edition-guide/ + /// [`cargo fix`]: https://doc.rust-lang.org/cargo/commands/cargo-fix.html + pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + Allow, + "fully qualified paths that start with a module name \ + instead of `crate`, `self`, or an extern crate name", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #53130 ", + edition: Some(Edition::Edition2018), + }; +} + +declare_lint! { + /// The `illegal_floating_point_literal_pattern` lint detects + /// floating-point literals used in patterns. + /// + /// ### Example + /// + /// ```rust + /// let x = 42.0; + /// + /// match x { + /// 5.0 => {} + /// _ => {} + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of the compiler accepted floating-point literals in + /// patterns, but it was later determined this was a mistake. The + /// semantics of comparing floating-point values may not be clear in a + /// pattern when contrasted with "structural equality". Typically you can + /// work around this by using a [match guard], such as: + /// + /// ```rust + /// # let x = 42.0; + /// + /// match x { + /// y if y == 5.0 => {} + /// _ => {} + /// } + /// ``` + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #41620] for more details. + /// + /// [issue #41620]: https://github.com/rust-lang/rust/issues/41620 + /// [match guard]: https://doc.rust-lang.org/reference/expressions/match-expr.html#match-guards + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + Warn, + "floating-point literals cannot be used in patterns", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #41620 ", + edition: None, + }; +} + +declare_lint! { + /// The `unstable_name_collisions` lint detects that you have used a name + /// that the standard library plans to add in the future. + /// + /// ### Example + /// + /// ```rust + /// trait MyIterator : Iterator { + /// // is_sorted is an unstable method that already exists on the Iterator trait + /// fn is_sorted(self) -> bool where Self: Sized {true} + /// } + /// + /// impl MyIterator for T where T: Iterator { } + /// + /// let x = vec![1,2,3]; + /// let _ = x.iter().is_sorted(); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// When new methods are added to traits in the standard library, they are + /// usually added in an "unstable" form which is only available on the + /// [nightly channel] with a [`feature` attribute]. If there is any + /// pre-existing code which extends a trait to have a method with the same + /// name, then the names will collide. In the future, when the method is + /// stabilized, this will cause an error due to the ambiguity. This lint + /// is an early-warning to let you know that there may be a collision in + /// the future. This can be avoided by adding type annotations to + /// disambiguate which trait method you intend to call, such as + /// `MyIterator::is_sorted(my_iter)` or renaming or removing the method. + /// + /// [nightly channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// [`feature` attribute]: https://doc.rust-lang.org/nightly/unstable-book/ + pub UNSTABLE_NAME_COLLISIONS, + Warn, + "detects name collision with an existing but unstable method", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #48919 ", + edition: None, + // Note: this item represents future incompatibility of all unstable functions in the + // standard library, and thus should never be removed or changed to an error. + }; +} + +declare_lint! { + /// The `irrefutable_let_patterns` lint detects detects [irrefutable + /// patterns] in [if-let] and [while-let] statements. + /// + /// + /// + /// ### Example + /// + /// ```rust + /// if let _ = 123 { + /// println!("always runs!"); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// There usually isn't a reason to have an irrefutable pattern in an + /// if-let or while-let statement, because the pattern will always match + /// successfully. A [`let`] or [`loop`] statement will suffice. However, + /// when generating code with a macro, forbidding irrefutable patterns + /// would require awkward workarounds in situations where the macro + /// doesn't know if the pattern is refutable or not. This lint allows + /// macros to accept this form, while alerting for a possibly incorrect + /// use in normal code. + /// + /// See [RFC 2086] for more details. + /// + /// [irrefutable patterns]: https://doc.rust-lang.org/reference/patterns.html#refutability + /// [if-let]: https://doc.rust-lang.org/reference/expressions/if-expr.html#if-let-expressions + /// [while-let]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#predicate-pattern-loops + /// [`let`]: https://doc.rust-lang.org/reference/statements.html#let-statements + /// [`loop`]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#infinite-loops + /// [RFC 2086]: https://github.com/rust-lang/rfcs/blob/master/text/2086-allow-if-let-irrefutables.md + pub IRREFUTABLE_LET_PATTERNS, + Warn, + "detects irrefutable patterns in if-let and while-let statements" +} + +declare_lint! { + /// The `unused_labels` lint detects [labels] that are never used. + /// + /// [labels]: https://doc.rust-lang.org/reference/expressions/loop-expr.html#loop-labels + /// + /// ### Example + /// + /// ```rust,no_run + /// 'unused_label: loop {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Unused labels may signal a mistake or unfinished code. To silence the + /// warning for the individual label, prefix it with an underscore such as + /// `'_my_label:`. + pub UNUSED_LABELS, + Warn, + "detects labels that are never used" +} + +declare_lint! { + /// The `broken_intra_doc_links` lint detects failures in resolving + /// intra-doc link targets. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#broken_intra_doc_links + pub BROKEN_INTRA_DOC_LINKS, + Warn, + "failures in resolving intra-doc link targets" +} + +declare_lint! { + /// This is a subset of `broken_intra_doc_links` that warns when linking from + /// a public item to a private one. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_intra_doc_links + pub PRIVATE_INTRA_DOC_LINKS, + Warn, + "linking from a public item to a private one" +} + +declare_lint! { + /// The `invalid_codeblock_attributes` lint detects code block attributes + /// in documentation examples that have potentially mis-typed values. This + /// is a `rustdoc` only lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#invalid_codeblock_attributes + pub INVALID_CODEBLOCK_ATTRIBUTES, + Warn, + "codeblock attribute looks a lot like a known one" +} + +declare_lint! { + /// The `missing_crate_level_docs` lint detects if documentation is + /// missing at the crate root. This is a `rustdoc` only lint, see the + /// documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_crate_level_docs + pub MISSING_CRATE_LEVEL_DOCS, + Allow, + "detects crates with no crate-level documentation" +} + +declare_lint! { + /// The `missing_doc_code_examples` lint detects publicly-exported items + /// without code samples in their documentation. This is a `rustdoc` only + /// lint, see the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#missing_doc_code_examples + pub MISSING_DOC_CODE_EXAMPLES, + Allow, + "detects publicly-exported items without code samples in their documentation" +} + +declare_lint! { + /// The `private_doc_tests` lint detects code samples in docs of private + /// items not documented by `rustdoc`. This is a `rustdoc` only lint, see + /// the documentation in the [rustdoc book]. + /// + /// [rustdoc book]: ../../../rustdoc/lints.html#private_doc_tests + pub PRIVATE_DOC_TESTS, + Allow, + "detects code samples in docs of private items not documented by rustdoc" +} + +declare_lint! { + /// The `where_clauses_object_safety` lint detects for [object safety] of + /// [where clauses]. + /// + /// [object safety]: https://doc.rust-lang.org/reference/items/traits.html#object-safety + /// [where clauses]: https://doc.rust-lang.org/reference/items/generics.html#where-clauses + /// + /// ### Example + /// + /// ```rust,no_run + /// trait Trait {} + /// + /// trait X { fn foo(&self) where Self: Trait; } + /// + /// impl X for () { fn foo(&self) {} } + /// + /// impl Trait for dyn X {} + /// + /// // Segfault at opt-level 0, SIGILL otherwise. + /// pub fn main() { ::foo(&()); } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler previously allowed these object-unsafe bounds, which was + /// incorrect. This is a [future-incompatible] lint to transition this to + /// a hard error in the future. See [issue #51443] for more details. + /// + /// [issue #51443]: https://github.com/rust-lang/rust/issues/51443 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub WHERE_CLAUSES_OBJECT_SAFETY, + Warn, + "checks the object safety of where clauses", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #51443 ", + edition: None, + }; +} + +declare_lint! { + /// The `proc_macro_derive_resolution_fallback` lint detects proc macro + /// derives using inaccessible names from parent modules. + /// + /// ### Example + /// + /// ```rust,ignore (proc-macro) + /// // foo.rs + /// #![crate_type = "proc-macro"] + /// + /// extern crate proc_macro; + /// + /// use proc_macro::*; + /// + /// #[proc_macro_derive(Foo)] + /// pub fn foo1(a: TokenStream) -> TokenStream { + /// drop(a); + /// "mod __bar { static mut BAR: Option = None; }".parse().unwrap() + /// } + /// ``` + /// + /// ```rust,ignore (needs-dependency) + /// // bar.rs + /// #[macro_use] + /// extern crate foo; + /// + /// struct Something; + /// + /// #[derive(Foo)] + /// struct Another; + /// + /// fn main() {} + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: cannot find type `Something` in this scope + /// --> src/main.rs:8:10 + /// | + /// 8 | #[derive(Foo)] + /// | ^^^ 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 #50504 + /// ``` + /// + /// ### Explanation + /// + /// If a proc-macro generates a module, the compiler unintentionally + /// allowed items in that module to refer to items in the crate root + /// without importing them. This is a [future-incompatible] lint to + /// transition this to a hard error in the future. See [issue #50504] for + /// more details. + /// + /// [issue #50504]: https://github.com/rust-lang/rust/issues/50504 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + Warn, + "detects proc macro derives using inaccessible names from parent modules", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #50504 ", + edition: None, + }; +} + +declare_lint! { + /// The `macro_use_extern_crate` lint detects the use of the + /// [`macro_use` attribute]. + /// + /// ### Example + /// + /// ```rust,ignore (needs extern crate) + /// #![deny(macro_use_extern_crate)] + /// + /// #[macro_use] + /// extern crate serde_json; + /// + /// fn main() { + /// let _ = json!{{}}; + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// error: deprecated `#[macro_use]` attribute used to import macros should be replaced at use sites with a `use` item to import the macro instead + /// --> src/main.rs:3:1 + /// | + /// 3 | #[macro_use] + /// | ^^^^^^^^^^^^ + /// | + /// note: the lint level is defined here + /// --> src/main.rs:1:9 + /// | + /// 1 | #![deny(macro_use_extern_crate)] + /// | ^^^^^^^^^^^^^^^^^^^^^^ + /// ``` + /// + /// ### Explanation + /// + /// The [`macro_use` attribute] on an [`extern crate`] item causes + /// macros in that external crate to be brought into the prelude of the + /// crate, making the macros in scope everywhere. As part of the efforts + /// to simplify handling of dependencies in the [2018 edition], the use of + /// `extern crate` is being phased out. To bring macros from extern crates + /// into scope, it is recommended to use a [`use` import]. + /// + /// This lint is "allow" by default because this is a stylistic choice + /// that has not been settled, see [issue #52043] for more information. + /// + /// [`macro_use` attribute]: https://doc.rust-lang.org/reference/macros-by-example.html#the-macro_use-attribute + /// [`use` import]: https://doc.rust-lang.org/reference/items/use-declarations.html + /// [issue #52043]: https://github.com/rust-lang/rust/issues/52043 + pub MACRO_USE_EXTERN_CRATE, + Allow, + "the `#[macro_use]` attribute is now deprecated in favor of using macros \ + via the module system" +} + +declare_lint! { + /// The `macro_expanded_macro_exports_accessed_by_absolute_paths` lint + /// detects macro-expanded [`macro_export`] macros from the current crate + /// that cannot be referred to by absolute paths. + /// + /// [`macro_export`]: https://doc.rust-lang.org/reference/macros-by-example.html#path-based-scope + /// + /// ### Example + /// + /// ```rust,compile_fail + /// macro_rules! define_exported { + /// () => { + /// #[macro_export] + /// macro_rules! exported { + /// () => {}; + /// } + /// }; + /// } + /// + /// define_exported!(); + /// + /// fn main() { + /// crate::exported!(); + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The intent is that all macros marked with the `#[macro_export]` + /// attribute are made available in the root of the crate. However, when a + /// `macro_rules!` definition is generated by another macro, the macro + /// expansion is unable to uphold this rule. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #53495] for more details. + /// + /// [issue #53495]: https://github.com/rust-lang/rust/issues/53495 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + Deny, + "macro-expanded `macro_export` macros from the current crate \ + cannot be referred to by absolute paths", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #52234 ", + edition: None, + }; + crate_level_only +} + +declare_lint! { + /// The `explicit_outlives_requirements` lint detects unnecessary + /// lifetime bounds that can be inferred. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// # #![allow(unused)] + /// #![deny(explicit_outlives_requirements)] + /// + /// struct SharedRef<'a, T> + /// where + /// T: 'a, + /// { + /// data: &'a T, + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// If a `struct` contains a reference, such as `&'a T`, the compiler + /// requires that `T` outlives the lifetime `'a`. This historically + /// required writing an explicit lifetime bound to indicate this + /// requirement. However, this can be overly explicit, causing clutter and + /// unnecessary complexity. The language was changed to automatically + /// infer the bound if it is not specified. Specifically, if the struct + /// contains a reference, directly or indirectly, to `T` with lifetime + /// `'x`, then it will infer that `T: 'x` is a requirement. + /// + /// This lint is "allow" by default because it can be noisy for existing + /// code that already had these requirements. This is a stylistic choice, + /// as it is still valid to explicitly state the bound. It also has some + /// false positives that can cause confusion. + /// + /// See [RFC 2093] for more details. + /// + /// [RFC 2093]: https://github.com/rust-lang/rfcs/blob/master/text/2093-infer-outlives.md + pub EXPLICIT_OUTLIVES_REQUIREMENTS, + Allow, + "outlives requirements can be inferred" +} + +declare_lint! { + /// The `indirect_structural_match` lint detects a `const` in a pattern + /// that manually implements [`PartialEq`] and [`Eq`]. + /// + /// [`PartialEq`]: https://doc.rust-lang.org/std/cmp/trait.PartialEq.html + /// [`Eq`]: https://doc.rust-lang.org/std/cmp/trait.Eq.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(indirect_structural_match)] + /// + /// struct NoDerive(i32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } + /// #[derive(PartialEq, Eq)] + /// struct WrapParam(T); + /// const WRAP_INDIRECT_PARAM: & &WrapParam = & &WrapParam(NoDerive(0)); + /// fn main() { + /// match WRAP_INDIRECT_PARAM { + /// WRAP_INDIRECT_PARAM => { } + /// _ => { } + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The compiler unintentionally accepted this form in the past. This is a + /// [future-incompatible] lint to transition this to a hard error in the + /// future. See [issue #62411] for a complete description of the problem, + /// and some possible solutions. + /// + /// [issue #62411]: https://github.com/rust-lang/rust/issues/62411 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub INDIRECT_STRUCTURAL_MATCH, + Warn, + "constant used in pattern contains value of non-structural-match type in a field or a variant", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #62411 ", + edition: None, + }; +} + +declare_lint! { + /// The `deprecated_in_future` lint is internal to rustc and should not be + /// used by user code. + /// + /// This lint is only enabled in the standard library. It works with the + /// use of `#[rustc_deprecated]` with a `since` field of a version in the + /// future. This allows something to be marked as deprecated in a future + /// version, and then this lint will ensure that the item is no longer + /// used in the standard library. See the [stability documentation] for + /// more details. + /// + /// [stability documentation]: https://rustc-dev-guide.rust-lang.org/stability.html#rustc_deprecated + pub DEPRECATED_IN_FUTURE, + Allow, + "detects use of items that will be deprecated in a future version", + report_in_external_macro +} + +declare_lint! { + /// The `pointer_structural_match` lint detects pointers used in patterns whose behaviour + /// cannot be relied upon across compiler versions and optimization levels. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(pointer_structural_match)] + /// fn foo(a: usize, b: usize) -> usize { a + b } + /// const FOO: fn(usize, usize) -> usize = foo; + /// fn main() { + /// match FOO { + /// FOO => {}, + /// _ => {}, + /// } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust allowed function pointers and wide raw pointers in patterns. + /// While these work in many cases as expected by users, it is possible that due to + /// optimizations pointers are "not equal to themselves" or pointers to different functions + /// compare as equal during runtime. This is because LLVM optimizations can deduplicate + /// functions if their bodies are the same, thus also making pointers to these functions point + /// to the same location. Additionally functions may get duplicated if they are instantiated + /// in different crates and not deduplicated again via LTO. + pub POINTER_STRUCTURAL_MATCH, + Allow, + "pointers are not structural-match", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #62411 ", + edition: None, + }; +} + +declare_lint! { + /// The `nontrivial_structural_match` lint detects constants that are used in patterns, + /// whose type is not structural-match and whose initializer body actually uses values + /// that are not structural-match. So `Option` is ok if the constant + /// is just `None`. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![deny(nontrivial_structural_match)] + /// + /// #[derive(Copy, Clone, Debug)] + /// struct NoDerive(u32); + /// impl PartialEq for NoDerive { fn eq(&self, _: &Self) -> bool { false } } + /// impl Eq for NoDerive { } + /// fn main() { + /// const INDEX: Option = [None, Some(NoDerive(10))][0]; + /// match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust accepted constants in patterns, even if those constants's types + /// did not have `PartialEq` derived. Thus the compiler falls back to runtime execution of + /// `PartialEq`, which can report that two constants are not equal even if they are + /// bit-equivalent. + pub NONTRIVIAL_STRUCTURAL_MATCH, + Warn, + "constant used in pattern of non-structural-match type and the constant's initializer \ + expression contains values of non-structural-match types", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73448 ", + edition: None, + }; +} + +declare_lint! { + /// The `ambiguous_associated_items` lint detects ambiguity between + /// [associated items] and [enum variants]. + /// + /// [associated items]: https://doc.rust-lang.org/reference/items/associated-items.html + /// [enum variants]: https://doc.rust-lang.org/reference/items/enumerations.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// enum E { + /// V + /// } + /// + /// trait Tr { + /// type V; + /// fn foo() -> Self::V; + /// } + /// + /// impl Tr for E { + /// type V = u8; + /// // `Self::V` is ambiguous because it may refer to the associated type or + /// // the enum variant. + /// fn foo() -> Self::V { 0 } + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Previous versions of Rust did not allow accessing enum variants + /// through [type aliases]. When this ability was added (see [RFC 2338]), this + /// introduced some situations where it can be ambiguous what a type + /// was referring to. + /// + /// To fix this ambiguity, you should use a [qualified path] to explicitly + /// state which type to use. For example, in the above example the + /// function can be written as `fn f() -> ::V { 0 }` to + /// specifically refer to the associated type. + /// + /// This is a [future-incompatible] lint to transition this to a hard + /// error in the future. See [issue #57644] for more details. + /// + /// [issue #57644]: https://github.com/rust-lang/rust/issues/57644 + /// [type aliases]: https://doc.rust-lang.org/reference/items/type-aliases.html#type-aliases + /// [RFC 2338]: https://github.com/rust-lang/rfcs/blob/master/text/2338-type-alias-enum-variants.md + /// [qualified path]: https://doc.rust-lang.org/reference/paths.html#qualified-paths + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub AMBIGUOUS_ASSOCIATED_ITEMS, + Deny, + "ambiguous associated items", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #57644 ", + edition: None, + }; +} + +declare_lint! { + /// The `mutable_borrow_reservation_conflict` lint detects the reservation + /// of a two-phased borrow that conflicts with other shared borrows. + /// + /// ### Example + /// + /// ```rust + /// let mut v = vec![0, 1, 2]; + /// let shared = &v; + /// v.push(shared.len()); + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #59159] for a complete description of the + /// problem, and some possible solutions. + /// + /// [issue #59159]: https://github.com/rust-lang/rust/issues/59159 + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub MUTABLE_BORROW_RESERVATION_CONFLICT, + Warn, + "reservation of a two-phased borrow conflicts with other shared borrows", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #59159 ", + edition: None, + }; +} + +declare_lint! { + /// The `soft_unstable` lint detects unstable features that were + /// unintentionally allowed on stable. + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #[cfg(test)] + /// extern crate test; + /// + /// #[bench] + /// fn name(b: &mut test::Bencher) { + /// b.iter(|| 123) + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The [`bench` attribute] was accidentally allowed to be specified on + /// the [stable release channel]. Turning this to a hard error would have + /// broken some projects. This lint allows those projects to continue to + /// build correctly when [`--cap-lints`] is used, but otherwise signal an + /// error that `#[bench]` should not be used on the stable channel. This + /// is a [future-incompatible] lint to transition this to a hard error in + /// the future. See [issue #64266] for more details. + /// + /// [issue #64266]: https://github.com/rust-lang/rust/issues/64266 + /// [`bench` attribute]: https://doc.rust-lang.org/nightly/unstable-book/library-features/test.html + /// [stable release channel]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// [`--cap-lints`]: https://doc.rust-lang.org/rustc/lints/levels.html#capping-lints + /// [future-incompatible]: ../index.md#future-incompatible-lints + pub SOFT_UNSTABLE, + Deny, + "a feature gate that doesn't break dependent crates", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #64266 ", + edition: None, + }; +} + +declare_lint! { + /// The `inline_no_sanitize` lint detects incompatible use of + /// [`#[inline(always)]`][inline] and [`#[no_sanitize(...)]`][no_sanitize]. + /// + /// [inline]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-inline-attribute + /// [no_sanitize]: https://doc.rust-lang.org/nightly/unstable-book/language-features/no-sanitize.html + /// + /// ### Example + /// + /// ```rust + /// #![feature(no_sanitize)] + /// + /// #[inline(always)] + /// #[no_sanitize(address)] + /// fn x() {} + /// + /// fn main() { + /// x() + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// The use of the [`#[inline(always)]`][inline] attribute prevents the + /// the [`#[no_sanitize(...)]`][no_sanitize] attribute from working. + /// Consider temporarily removing `inline` attribute. + pub INLINE_NO_SANITIZE, + Warn, + "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`", +} + +declare_lint! { + /// The `asm_sub_register` lint detects using only a subset of a register + /// for inline asm inputs. + /// + /// ### Example + /// + /// ```rust,ignore (fails on system llvm) + /// #![feature(asm)] + /// + /// fn main() { + /// #[cfg(target_arch="x86_64")] + /// unsafe { + /// asm!("mov {0}, {0}", in(reg) 0i16); + /// } + /// } + /// ``` + /// + /// This will produce: + /// + /// ```text + /// warning: formatting may not be suitable for sub-register argument + /// --> src/main.rs:6:19 + /// | + /// 6 | asm!("mov {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` + /// ``` + /// + /// ### Explanation + /// + /// Registers on some architectures can use different names to refer to a + /// subset of the register. By default, the compiler will use the name for + /// the full register size. To explicitly use a subset of the register, + /// you can override the default by using a modifier on the template + /// string operand to specify when subregister to use. This lint is issued + /// if you pass in a value with a smaller data type than the default + /// register size, to alert you of possibly using the incorrect width. To + /// fix this, add the suggested modifier to the template, or cast the + /// value to the correct size. + /// + /// See [register template modifiers] for more details. + /// + /// [register template modifiers]: https://doc.rust-lang.org/nightly/unstable-book/library-features/asm.html#register-template-modifiers + pub ASM_SUB_REGISTER, + Warn, + "using only a subset of a register for inline asm inputs", +} + +declare_lint! { + /// The `unsafe_op_in_unsafe_fn` lint detects unsafe operations in unsafe + /// functions without an explicit unsafe block. This lint only works on + /// the [**nightly channel**] with the + /// `#![feature(unsafe_block_in_unsafe_fn)]` feature. + /// + /// [**nightly channel**]: https://doc.rust-lang.org/book/appendix-07-nightly-rust.html + /// + /// ### Example + /// + /// ```rust,compile_fail + /// #![feature(unsafe_block_in_unsafe_fn)] + /// #![deny(unsafe_op_in_unsafe_fn)] + /// + /// unsafe fn foo() {} + /// + /// unsafe fn bar() { + /// foo(); + /// } + /// + /// fn main() {} + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Currently, an [`unsafe fn`] allows any [unsafe] operation within its + /// body. However, this can increase the surface area of code that needs + /// to be scrutinized for proper behavior. The [`unsafe` block] provides a + /// convenient way to make it clear exactly which parts of the code are + /// performing unsafe operations. In the future, it is desired to change + /// it so that unsafe operations cannot be performed in an `unsafe fn` + /// without an `unsafe` block. + /// + /// The fix to this is to wrap the unsafe code in an `unsafe` block. + /// + /// This lint is "allow" by default because it has not yet been + /// stabilized, and is not yet complete. See [RFC #2585] and [issue + /// #71668] for more details + /// + /// [`unsafe fn`]: https://doc.rust-lang.org/reference/unsafe-functions.html + /// [`unsafe` block]: https://doc.rust-lang.org/reference/expressions/block-expr.html#unsafe-blocks + /// [unsafe]: https://doc.rust-lang.org/reference/unsafety.html + /// [RFC #2585]: https://github.com/rust-lang/rfcs/blob/master/text/2585-unsafe-block-in-unsafe-fn.md + /// [issue #71668]: https://github.com/rust-lang/rust/issues/71668 + pub UNSAFE_OP_IN_UNSAFE_FN, + Allow, + "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", + @feature_gate = sym::unsafe_block_in_unsafe_fn; +} + +declare_lint! { + /// The `cenum_impl_drop_cast` lint detects an `as` cast of a field-less + /// `enum` that implements [`Drop`]. + /// + /// [`Drop`]: https://doc.rust-lang.org/std/ops/trait.Drop.html + /// + /// ### Example + /// + /// ```rust + /// # #![allow(unused)] + /// enum E { + /// A, + /// } + /// + /// impl Drop for E { + /// fn drop(&mut self) { + /// println!("Drop"); + /// } + /// } + /// + /// fn main() { + /// let e = E::A; + /// let i = e as u32; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// Casting a field-less `enum` that does not implement [`Copy`] to an + /// integer moves the value without calling `drop`. This can result in + /// surprising behavior if it was expected that `drop` should be called. + /// Calling `drop` automatically would be inconsistent with other move + /// operations. Since neither behavior is clear or consistent, it was + /// decided that a cast of this nature will no longer be allowed. + /// + /// This is a [future-incompatible] lint to transition this to a hard error + /// in the future. See [issue #73333] for more details. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + /// [issue #73333]: https://github.com/rust-lang/rust/issues/73333 + /// [`Copy`]: https://doc.rust-lang.org/std/marker/trait.Copy.html + pub CENUM_IMPL_DROP_CAST, + Warn, + "a C-like enum implementing Drop is cast", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #73333 ", + edition: None, + }; +} + +declare_lint! { + /// The `const_evaluatable_unchecked` lint detects a generic constant used + /// in a type. + /// + /// ### Example + /// + /// ```rust + /// const fn foo() -> usize { + /// if std::mem::size_of::<*mut T>() < 8 { // size of *mut T does not depend on T + /// 4 + /// } else { + /// 8 + /// } + /// } + /// + /// fn test() { + /// let _ = [0; foo::()]; + /// } + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// In the 1.43 release, some uses of generic parameters in array repeat + /// expressions were accidentally allowed. This is a [future-incompatible] + /// lint to transition this to a hard error in the future. See [issue + /// #76200] for a more detailed description and possible fixes. + /// + /// [future-incompatible]: ../index.md#future-incompatible-lints + /// [issue #76200]: https://github.com/rust-lang/rust/issues/76200 + pub CONST_EVALUATABLE_UNCHECKED, + Warn, + "detects a generic constant is used in a type without a emitting a warning", + @future_incompatible = FutureIncompatibleInfo { + reference: "issue #76200 ", + edition: None, + }; +} + +declare_tool_lint! { + pub rustc::INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + Deny, + "detects `#[unstable]` on stable trait implementations for stable types" +} + +declare_lint_pass! { + /// Does nothing as a lint pass, but registers some `Lint`s + /// that are used by other parts of the compiler. + HardwiredLints => [ + ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, + ARITHMETIC_OVERFLOW, + UNCONDITIONAL_PANIC, + UNUSED_IMPORTS, + UNUSED_EXTERN_CRATES, + UNUSED_CRATE_DEPENDENCIES, + UNUSED_QUALIFICATIONS, + UNKNOWN_LINTS, + UNUSED_VARIABLES, + UNUSED_ASSIGNMENTS, + DEAD_CODE, + UNREACHABLE_CODE, + UNREACHABLE_PATTERNS, + OVERLAPPING_PATTERNS, + BINDINGS_WITH_VARIANT_NAME, + UNUSED_MACROS, + WARNINGS, + UNUSED_FEATURES, + STABLE_FEATURES, + UNKNOWN_CRATE_TYPES, + TRIVIAL_CASTS, + TRIVIAL_NUMERIC_CASTS, + PRIVATE_IN_PUBLIC, + EXPORTED_PRIVATE_DEPENDENCIES, + PUB_USE_OF_PRIVATE_EXTERN_CRATE, + INVALID_TYPE_PARAM_DEFAULT, + CONST_ERR, + RENAMED_AND_REMOVED_LINTS, + UNALIGNED_REFERENCES, + CONST_ITEM_MUTATION, + SAFE_PACKED_BORROWS, + PATTERNS_IN_FNS_WITHOUT_BODY, + LATE_BOUND_LIFETIME_ARGUMENTS, + ORDER_DEPENDENT_TRAIT_OBJECTS, + COHERENCE_LEAK_CHECK, + DEPRECATED, + UNUSED_UNSAFE, + UNUSED_MUT, + UNCONDITIONAL_RECURSION, + SINGLE_USE_LIFETIMES, + UNUSED_LIFETIMES, + UNUSED_LABELS, + TYVAR_BEHIND_RAW_POINTER, + ELIDED_LIFETIMES_IN_PATHS, + BARE_TRAIT_OBJECTS, + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + UNSTABLE_NAME_COLLISIONS, + IRREFUTABLE_LET_PATTERNS, + BROKEN_INTRA_DOC_LINKS, + INVALID_CODEBLOCK_ATTRIBUTES, + MISSING_CRATE_LEVEL_DOCS, + MISSING_DOC_CODE_EXAMPLES, + PRIVATE_DOC_TESTS, + WHERE_CLAUSES_OBJECT_SAFETY, + PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, + MACRO_USE_EXTERN_CRATE, + MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, + ILL_FORMED_ATTRIBUTE_INPUT, + CONFLICTING_REPR_HINTS, + META_VARIABLE_MISUSE, + DEPRECATED_IN_FUTURE, + AMBIGUOUS_ASSOCIATED_ITEMS, + MUTABLE_BORROW_RESERVATION_CONFLICT, + INDIRECT_STRUCTURAL_MATCH, + POINTER_STRUCTURAL_MATCH, + NONTRIVIAL_STRUCTURAL_MATCH, + SOFT_UNSTABLE, + INLINE_NO_SANITIZE, + ASM_SUB_REGISTER, + UNSAFE_OP_IN_UNSAFE_FN, + INCOMPLETE_INCLUDE, + CENUM_IMPL_DROP_CAST, + CONST_EVALUATABLE_UNCHECKED, + INEFFECTIVE_UNSTABLE_TRAIT_IMPL, + MISSING_FRAGMENT_SPECIFIER, + ] +} + +declare_lint! { + /// The `unused_doc_comments` lint detects doc comments that aren't used + /// by `rustdoc`. + /// + /// ### Example + /// + /// ```rust + /// /// docs for x + /// let x = 12; + /// ``` + /// + /// {{produces}} + /// + /// ### Explanation + /// + /// `rustdoc` does not use doc comments in all positions, and so the doc + /// comment will be ignored. Try changing it to a normal comment with `//` + /// to avoid the warning. + pub UNUSED_DOC_COMMENTS, + Warn, + "detects doc comments that aren't used by rustdoc" +} + +declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); diff --git a/src/librustc_session/options.rs b/compiler/rustc_session/src/options.rs similarity index 93% rename from src/librustc_session/options.rs rename to compiler/rustc_session/src/options.rs index d05f1a3f34..b705ab6d93 100644 --- a/src/librustc_session/options.rs +++ b/compiler/rustc_session/src/options.rs @@ -125,6 +125,9 @@ top_level_options!( // try to not rely on this too much. actually_rustdoc: bool [TRACKED], + // Control path trimming. + trimmed_def_paths: TrimmedDefPaths [TRACKED], + // Specifications of codegen units / ThinLTO which are forced as a // result of parsing command line options. These are not necessarily // what rustc was invoked with, but massaged a bit to agree with @@ -255,6 +258,7 @@ macro_rules! options { pub const parse_strip: &str = "either `none`, `debuginfo`, or `symbols`"; pub const parse_linker_flavor: &str = ::rustc_target::spec::LinkerFlavor::one_of(); pub const parse_optimization_fuel: &str = "crate=integer"; + pub const parse_mir_spanview: &str = "`statement` (default), `terminator`, or `block`"; pub const parse_unpretty: &str = "`string` or `string=string`"; pub const parse_treat_err_as_bug: &str = "either no value or a number bigger than 0"; pub const parse_lto: &str = @@ -551,6 +555,36 @@ macro_rules! options { } } + fn parse_mir_spanview(slot: &mut Option, v: Option<&str>) -> bool { + if v.is_some() { + let mut bool_arg = None; + if parse_opt_bool(&mut bool_arg, v) { + *slot = if bool_arg.unwrap() { + Some(MirSpanview::Statement) + } else { + None + }; + return true + } + } + + let v = match v { + None => { + *slot = Some(MirSpanview::Statement); + return true; + } + Some(v) => v, + }; + + *slot = Some(match v.trim_end_matches("s") { + "statement" | "stmt" => MirSpanview::Statement, + "terminator" | "term" => MirSpanview::Terminator, + "block" | "basicblock" => MirSpanview::Block, + _ => return false, + }); + true + } + fn parse_treat_err_as_bug(slot: &mut Option, v: Option<&str>) -> bool { match v { Some(s) => { *slot = s.parse().ok().filter(|&x| x != 0); slot.unwrap_or(0) != 0 } @@ -719,6 +753,9 @@ options! {CodegenOptions, CodegenSetter, basic_codegen_options, "extra arguments to append to the linker invocation (space separated)"), link_dead_code: Option = (None, parse_opt_bool, [UNTRACKED], "keep dead code at link time (useful for code coverage) (default: no)"), + link_self_contained: Option = (None, parse_opt_bool, [UNTRACKED], + "control whether to link Rust provided C objects/libraries or rely + on C toolchain installed in the system"), linker: Option = (None, parse_opt_pathbuf, [UNTRACKED], "system linker to link outputs with"), linker_flavor: Option = (None, parse_linker_flavor, [UNTRACKED], @@ -813,6 +850,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "enable the experimental Chalk-based trait solving engine"), codegen_backend: Option = (None, parse_opt_string, [TRACKED], "the backend to use"), + combine_cgu: bool = (false, parse_bool, [TRACKED], + "combine CGUs into a single one"), crate_attr: Vec = (Vec::new(), parse_string_push, [TRACKED], "inject the given attribute in the crate"), debug_macros: bool = (false, parse_bool, [TRACKED], @@ -849,8 +888,18 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "exclude the pass number when dumping MIR (used in tests) (default: no)"), dump_mir_graphviz: bool = (false, parse_bool, [UNTRACKED], "in addition to `.mir` files, create graphviz `.dot` files (default: no)"), + dump_mir_spanview: Option = (None, parse_mir_spanview, [UNTRACKED], + "in addition to `.mir` files, create `.html` files to view spans for \ + all `statement`s (including terminators), only `terminator` spans, or \ + computed `block` spans (one span encompassing a block's terminator and \ + all statements)."), emit_stack_sizes: bool = (false, parse_bool, [UNTRACKED], "emit a section containing stack size metadata (default: no)"), + experimental_coverage: bool = (false, parse_bool, [TRACKED], + "enable and extend the `-Z instrument-coverage` function-level coverage \ + feature, adding additional experimental (likely inaccurate) counters and \ + code regions (used by `rustc` compiler developers to test new coverage \ + counter placements) (default: no)"), fewer_names: bool = (false, parse_bool, [TRACKED], "reduce memory use by retaining fewer names within compilation artifacts (LLVM-IR) \ (default: no)"), @@ -860,6 +909,11 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "force all crates to be `rustc_private` unstable (default: no)"), fuel: Option<(String, u64)> = (None, parse_optimization_fuel, [TRACKED], "set the optimization fuel quota for a crate"), + graphviz_dark_mode: bool = (false, parse_bool, [UNTRACKED], + "use dark-themed colors in graphviz output (default: no)"), + graphviz_font: String = ("Courier, monospace".to_string(), parse_string, [UNTRACKED], + "use the given `fontname` in graphviz output; can be overridden by setting \ + environment variable `RUSTC_GRAPHVIZ_FONT` (default: `Courier, monospace`)"), hir_stats: bool = (false, parse_bool, [UNTRACKED], "print some statistics about AST and HIR (default: no)"), human_readable_cgu_names: bool = (false, parse_bool, [TRACKED], @@ -885,18 +939,15 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "instrument the generated code to support LLVM source-based code coverage \ reports (note, the compiler build config must include `profiler = true`, \ and is mutually exclusive with `-C profile-generate`/`-C profile-use`); \ - implies `-C link-dead-code` (unless explicitly disabled)` and \ - `-Z symbol-mangling-version=v0`; and disables/overrides some optimization \ - options (default: no)"), + implies `-C link-dead-code` (unless targeting MSVC, or explicitly disabled) \ + and `-Z symbol-mangling-version=v0`; disables/overrides some Rust \ + optimizations (default: no)"), instrument_mcount: bool = (false, parse_bool, [TRACKED], "insert function instrument code for mcount-based tracing (default: no)"), keep_hygiene_data: bool = (false, parse_bool, [UNTRACKED], "keep hygiene data after analysis (default: no)"), link_native_libraries: bool = (true, parse_bool, [UNTRACKED], "link native libraries in the linker invocation (default: yes)"), - link_self_contained: Option = (None, parse_opt_bool, [TRACKED], - "control whether to link Rust provided C objects/libraries or rely - on C toolchain installed in the system"), link_only: bool = (false, parse_bool, [TRACKED], "link the `.rlink` file generated by `-Z no-link` (default: no)"), llvm_time_trace: bool = (false, parse_bool, [UNTRACKED], @@ -957,6 +1008,10 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "a single extra argument to prepend the linker invocation (can be used several times)"), pre_link_args: Vec = (Vec::new(), parse_list, [UNTRACKED], "extra arguments to prepend to the linker invocation (space separated)"), + precise_enum_drop_elaboration: bool = (true, parse_bool, [TRACKED], + "use a more precise version of drop elaboration for matches on enums (default: yes). \ + This results in better codegen, but has caused miscompilations on some tier 2 platforms. \ + See #77382 and #74551."), print_fuel: Option = (None, parse_opt_string, [TRACKED], "make rustc print the total optimization fuel used by a crate"), print_link_args: bool = (false, parse_bool, [UNTRACKED], @@ -967,6 +1022,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "print the result of the monomorphization collection pass"), print_type_sizes: bool = (false, parse_bool, [UNTRACKED], "print layout information for each type encountered (default: no)"), + proc_macro_backtrace: bool = (false, parse_bool, [UNTRACKED], + "show backtraces for panics during proc-macro execution (default: no)"), profile: bool = (false, parse_bool, [TRACKED], "insert profiling code (default: no)"), profile_emit: Option = (None, parse_opt_pathbuf, [TRACKED], @@ -1046,6 +1103,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, "for every macro invocation, print its name and arguments (default: no)"), treat_err_as_bug: Option = (None, parse_treat_err_as_bug, [TRACKED], "treat error number `val` that occurs as bug"), + trim_diagnostic_paths: bool = (true, parse_bool, [UNTRACKED], + "in diagnostics, use heuristics to shorten paths referring to items"), ui_testing: bool = (false, parse_bool, [UNTRACKED], "emit compiler diagnostics in a form suitable for UI testing (default: no)"), unleash_the_miri_inside_of_you: bool = (false, parse_bool, [TRACKED], @@ -1060,6 +1119,8 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options, `hir,typed` (HIR with types for each node), `hir-tree` (dump the raw HIR), `mir` (the MIR), or `mir-cfg` (graphviz formatted MIR)"), + unsound_mir_opts: bool = (false, parse_bool, [TRACKED], + "enable unsound and buggy MIR optimizations (default: no)"), unstable_options: bool = (false, parse_bool, [UNTRACKED], "adds unstable command line options to rustc interface (default: no)"), use_ctors_section: Option = (None, parse_opt_bool, [TRACKED], diff --git a/src/librustc_session/output.rs b/compiler/rustc_session/src/output.rs similarity index 100% rename from src/librustc_session/output.rs rename to compiler/rustc_session/src/output.rs diff --git a/src/librustc_session/parse.rs b/compiler/rustc_session/src/parse.rs similarity index 100% rename from src/librustc_session/parse.rs rename to compiler/rustc_session/src/parse.rs diff --git a/src/librustc_session/search_paths.rs b/compiler/rustc_session/src/search_paths.rs similarity index 81% rename from src/librustc_session/search_paths.rs rename to compiler/rustc_session/src/search_paths.rs index e12364b7da..83b737a73b 100644 --- a/src/librustc_session/search_paths.rs +++ b/compiler/rustc_session/src/search_paths.rs @@ -56,16 +56,16 @@ impl PathKind { impl SearchPath { pub fn from_cli_opt(path: &str, output: config::ErrorOutputType) -> Self { - let (kind, path) = if path.starts_with("native=") { - (PathKind::Native, &path["native=".len()..]) - } else if path.starts_with("crate=") { - (PathKind::Crate, &path["crate=".len()..]) - } else if path.starts_with("dependency=") { - (PathKind::Dependency, &path["dependency=".len()..]) - } else if path.starts_with("framework=") { - (PathKind::Framework, &path["framework=".len()..]) - } else if path.starts_with("all=") { - (PathKind::All, &path["all=".len()..]) + let (kind, path) = if let Some(stripped) = path.strip_prefix("native=") { + (PathKind::Native, stripped) + } else if let Some(stripped) = path.strip_prefix("crate=") { + (PathKind::Crate, stripped) + } else if let Some(stripped) = path.strip_prefix("dependency=") { + (PathKind::Dependency, stripped) + } else if let Some(stripped) = path.strip_prefix("framework=") { + (PathKind::Framework, stripped) + } else if let Some(stripped) = path.strip_prefix("all=") { + (PathKind::All, stripped) } else { (PathKind::All, path) }; diff --git a/src/librustc_session/session.rs b/compiler/rustc_session/src/session.rs similarity index 94% rename from src/librustc_session/session.rs rename to compiler/rustc_session/src/session.rs index c006e593e4..ff5e6156d8 100644 --- a/src/librustc_session/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -213,6 +213,9 @@ pub struct Session { known_attrs: Lock, used_attrs: Lock, + + /// `Span`s for `if` conditions that we have suggested turning into `if let`. + pub if_let_suggestions: Lock>, } pub struct PerfStats { @@ -234,6 +237,14 @@ enum DiagnosticBuilderMethod { // Add more variants as needed to support one-time diagnostics. } +/// Trait implemented by error types. This should not be implemented manually. Instead, use +/// `#[derive(SessionDiagnostic)]` -- see [rustc_macros::SessionDiagnostic]. +pub trait SessionDiagnostic<'a> { + /// Write out as a diagnostic out of `sess`. + #[must_use] + fn into_diagnostic(self, sess: &'a Session) -> DiagnosticBuilder<'a>; +} + /// Diagnostic message ID, used by `Session.one_time_diagnostics` to avoid /// emitting the same message more than once. #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)] @@ -389,6 +400,9 @@ impl Session { pub fn err(&self, msg: &str) { self.diagnostic().err(msg) } + pub fn emit_err<'a>(&'a self, err: impl SessionDiagnostic<'a>) { + err.into_diagnostic(self).emit() + } pub fn err_count(&self) -> usize { self.diagnostic().err_count() } @@ -439,6 +453,24 @@ impl Session { pub fn delay_span_bug>(&self, sp: S, msg: &str) { self.diagnostic().delay_span_bug(sp, msg) } + + /// Used for code paths of expensive computations that should only take place when + /// warnings or errors are emitted. If no messages are emitted ("good path"), then + /// it's likely a bug. + pub fn delay_good_path_bug(&self, msg: &str) { + if self.opts.debugging_opts.print_type_sizes + || self.opts.debugging_opts.query_dep_graph + || self.opts.debugging_opts.dump_mir.is_some() + || self.opts.debugging_opts.unpretty.is_some() + || self.opts.output_types.contains_key(&OutputType::Mir) + || std::env::var_os("RUSTC_LOG").is_some() + { + return; + } + + self.diagnostic().delay_good_path_bug(msg) + } + pub fn note_without_error(&self, msg: &str) { self.diagnostic().note_without_error(msg) } @@ -1021,6 +1053,40 @@ impl Session { || self.opts.debugging_opts.sanitizer.intersects(SanitizerSet::ADDRESS | SanitizerSet::MEMORY) } + pub fn link_dead_code(&self) -> bool { + match self.opts.cg.link_dead_code { + Some(explicitly_set) => explicitly_set, + None => { + self.opts.debugging_opts.instrument_coverage + && !self.target.target.options.is_like_msvc + // Issue #76038: (rustc `-Clink-dead-code` causes MSVC linker to produce invalid + // binaries when LLVM InstrProf counters are enabled). As described by this issue, + // the "link dead code" option produces incorrect binaries when compiled and linked + // under MSVC. The resulting Rust programs typically crash with a segmentation + // fault, or produce an empty "*.profraw" file (profiling counter results normally + // generated during program exit). + // + // If not targeting MSVC, `-Z instrument-coverage` implies `-C link-dead-code`, so + // unexecuted code is still counted as zero, rather than be optimized out. Note that + // instrumenting dead code can be explicitly disabled with: + // + // `-Z instrument-coverage -C link-dead-code=no`. + // + // FIXME(richkadel): Investigate if `instrument-coverage` implementation can inject + // [zero counters](https://llvm.org/docs/CoverageMappingFormat.html#counter) in the + // coverage map when "dead code" is removed, rather than forcing `link-dead-code`. + // This may not be possible, however, if (as it seems to appear) the "dead code" + // that would otherwise not be linked is only identified as "dead" by the native + // linker. If that's the case, I believe it is too late for the Rust compiler to + // leverage any information it might be able to get from the linker regarding what + // code is dead, to be able to add those counters. + // + // On the other hand, if any Rust compiler passes are optimizing out dead code blocks + // we should inject "zero" counters for those code regions. + } + } + } + pub fn mark_attr_known(&self, attr: &Attribute) { self.known_attrs.lock().mark(attr) } @@ -1037,9 +1103,6 @@ impl Session { self.used_attrs.lock().is_marked(attr) } - /// Returns `true` if the attribute's path matches the argument. If it matches, then the - /// attribute is marked as used. - /// Returns `true` if the attribute's path matches the argument. If it /// matches, then the attribute is marked as used. /// @@ -1168,6 +1231,7 @@ pub fn build_session( diagnostics_output: DiagnosticOutput, driver_lint_caps: FxHashMap, file_loader: Option>, + target_override: Option, ) -> Session { // FIXME: This is not general enough to make the warning lint completely override // normal diagnostic warnings, since the warning lint can also be denied and changed @@ -1187,7 +1251,7 @@ pub fn build_session( DiagnosticOutput::Raw(write) => Some(write), }; - let target_cfg = config::build_target_config(&sopts, sopts.error_format); + let target_cfg = config::build_target_config(&sopts, target_override); let host_triple = TargetTriple::from_triple(config::host_triple()); let host = Target::search(&host_triple).unwrap_or_else(|e| { early_error(sopts.error_format, &format!("Error loading host specification: {}", e)) @@ -1354,6 +1418,7 @@ pub fn build_session( target_features: FxHashSet::default(), known_attrs: Lock::new(MarkedAttrs::new()), used_attrs: Lock::new(MarkedAttrs::new()), + if_let_suggestions: Default::default(), }; validate_commandline_args_with_session_available(&sess); @@ -1428,20 +1493,6 @@ fn validate_commandline_args_with_session_available(sess: &Session) { ); } - // FIXME(richkadel): See `src/test/run-make-fulldeps/instrument-coverage/Makefile`. After - // compiling with `-Zinstrument-coverage`, the resulting binary generates a segfault during - // the program's exit process (likely while attempting to generate the coverage stats in - // the "*.profraw" file). An investigation to resolve the problem on Windows is ongoing, - // but until this is resolved, the option is disabled on Windows, and the test is skipped - // when targeting `MSVC`. - if sess.opts.debugging_opts.instrument_coverage && sess.target.target.options.is_like_msvc { - sess.warn( - "Rust source-based code coverage instrumentation (with `-Z instrument-coverage`) \ - is not yet supported on Windows when targeting MSVC. The resulting binaries will \ - still be instrumented for experimentation purposes, but may not execute correctly.", - ); - } - const ASAN_SUPPORTED_TARGETS: &[&str] = &[ "aarch64-fuchsia", "aarch64-unknown-linux-gnu", diff --git a/src/librustc_session/utils.rs b/compiler/rustc_session/src/utils.rs similarity index 100% rename from src/librustc_session/utils.rs rename to compiler/rustc_session/src/utils.rs diff --git a/compiler/rustc_span/Cargo.toml b/compiler/rustc_span/Cargo.toml new file mode 100644 index 0000000000..1abfd50f00 --- /dev/null +++ b/compiler/rustc_span/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_span" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_serialize = { path = "../rustc_serialize" } +rustc_macros = { path = "../rustc_macros" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_index = { path = "../rustc_index" } +rustc_arena = { path = "../rustc_arena" } +scoped-tls = "1.0" +unicode-width = "0.1.4" +cfg-if = "0.1.2" +tracing = "0.1" +sha-1 = "0.8" +md-5 = "0.8" diff --git a/src/librustc_span/analyze_source_file.rs b/compiler/rustc_span/src/analyze_source_file.rs similarity index 100% rename from src/librustc_span/analyze_source_file.rs rename to compiler/rustc_span/src/analyze_source_file.rs diff --git a/src/librustc_span/analyze_source_file/tests.rs b/compiler/rustc_span/src/analyze_source_file/tests.rs similarity index 100% rename from src/librustc_span/analyze_source_file/tests.rs rename to compiler/rustc_span/src/analyze_source_file/tests.rs diff --git a/src/librustc_span/caching_source_map_view.rs b/compiler/rustc_span/src/caching_source_map_view.rs similarity index 100% rename from src/librustc_span/caching_source_map_view.rs rename to compiler/rustc_span/src/caching_source_map_view.rs diff --git a/src/librustc_span/def_id.rs b/compiler/rustc_span/src/def_id.rs similarity index 100% rename from src/librustc_span/def_id.rs rename to compiler/rustc_span/src/def_id.rs diff --git a/src/librustc_span/edition.rs b/compiler/rustc_span/src/edition.rs similarity index 100% rename from src/librustc_span/edition.rs rename to compiler/rustc_span/src/edition.rs diff --git a/src/librustc_span/fatal_error.rs b/compiler/rustc_span/src/fatal_error.rs similarity index 100% rename from src/librustc_span/fatal_error.rs rename to compiler/rustc_span/src/fatal_error.rs diff --git a/src/librustc_span/hygiene.rs b/compiler/rustc_span/src/hygiene.rs similarity index 99% rename from src/librustc_span/hygiene.rs rename to compiler/rustc_span/src/hygiene.rs index 942c664834..fb80dcb756 100644 --- a/src/librustc_span/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -702,7 +702,7 @@ pub struct ExpnData { /// The `DefId` of the macro being invoked, /// if this `ExpnData` corresponds to a macro invocation pub macro_def_id: Option, - /// The crate that originally created this `ExpnData. During + /// The crate that originally created this `ExpnData`. During /// metadata serialization, we only encode `ExpnData`s that were /// created locally - when our serialized metadata is decoded, /// foreign `ExpnId`s will have their `ExpnData` looked up @@ -759,7 +759,7 @@ impl ExpnData { #[inline] pub fn is_root(&self) -> bool { - if let ExpnKind::Root = self.kind { true } else { false } + matches!(self.kind, ExpnKind::Root) } } diff --git a/src/librustc_span/lib.rs b/compiler/rustc_span/src/lib.rs similarity index 95% rename from src/librustc_span/lib.rs rename to compiler/rustc_span/src/lib.rs index c654dade2a..96a6956a40 100644 --- a/src/librustc_span/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -4,16 +4,15 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] +#![feature(array_windows)] #![feature(crate_visibility_modifier)] #![feature(const_fn)] #![feature(const_panic)] #![feature(negative_impls)] #![feature(nll)] -#![feature(optin_builtin_traits)] #![feature(min_specialization)] #![feature(option_expect_none)] -#![feature(refcell_take)] #[macro_use] extern crate rustc_macros; @@ -400,6 +399,13 @@ impl Span { span.with_lo(span.hi) } + #[inline] + /// Returns true if hi == lo + pub fn is_empty(&self) -> bool { + let span = self.data(); + span.hi == span.lo + } + /// Returns `self` if `self` is not the dummy span, and `other` otherwise. pub fn substitute_dummy(self, other: Span) -> Span { if self.is_dummy() { other } else { self } @@ -537,6 +543,12 @@ impl Span { } /// Returns a `Span` that would enclose both `self` and `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^^^^ + /// ``` pub fn to(self, end: Span) -> Span { let span_data = self.data(); let end_data = end.data(); @@ -560,6 +572,12 @@ impl Span { } /// Returns a `Span` between the end of `self` to the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^ + /// ``` pub fn between(self, end: Span) -> Span { let span = self.data(); let end = end.data(); @@ -570,7 +588,13 @@ impl Span { ) } - /// Returns a `Span` between the beginning of `self` to the beginning of `end`. + /// Returns a `Span` from the beginning of `self` until the beginning of `end`. + /// + /// ```text + /// ____ ___ + /// self lorem ipsum end + /// ^^^^^^^^^^^^^^^^^ + /// ``` pub fn until(self, end: Span) -> Span { let span = self.data(); let end = end.data(); @@ -1133,7 +1157,12 @@ impl Encodable for SourceFile { let max_line_length = if lines.len() == 1 { 0 } else { - lines.windows(2).map(|w| w[1] - w[0]).map(|bp| bp.to_usize()).max().unwrap() + lines + .array_windows() + .map(|&[fst, snd]| snd - fst) + .map(|bp| bp.to_usize()) + .max() + .unwrap() }; let bytes_per_diff: u8 = match max_line_length { @@ -1148,7 +1177,7 @@ impl Encodable for SourceFile { // Encode the first element. lines[0].encode(s)?; - let diff_iter = (&lines[..]).windows(2).map(|w| (w[1] - w[0])); + let diff_iter = lines[..].array_windows().map(|&[fst, snd]| snd - fst); match bytes_per_diff { 1 => { @@ -1529,58 +1558,71 @@ pub trait Pos { fn to_u32(&self) -> u32; } -/// A byte offset. Keep this small (currently 32-bits), as AST contains -/// a lot of them. -#[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] -pub struct BytePos(pub u32); +macro_rules! impl_pos { + ( + $( + $(#[$attr:meta])* + $vis:vis struct $ident:ident($inner_vis:vis $inner_ty:ty); + )* + ) => { + $( + $(#[$attr])* + $vis struct $ident($inner_vis $inner_ty); -/// A character offset. Because of multibyte UTF-8 characters, a byte offset -/// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` -/// values to `CharPos` values as necessary. -#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] -pub struct CharPos(pub usize); + impl Pos for $ident { + #[inline(always)] + fn from_usize(n: usize) -> $ident { + $ident(n as $inner_ty) + } -// FIXME: lots of boilerplate in these impls, but so far my attempts to fix -// have been unsuccessful. + #[inline(always)] + fn to_usize(&self) -> usize { + self.0 as usize + } -impl Pos for BytePos { - #[inline(always)] - fn from_usize(n: usize) -> BytePos { - BytePos(n as u32) - } + #[inline(always)] + fn from_u32(n: u32) -> $ident { + $ident(n as $inner_ty) + } - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 as usize - } + #[inline(always)] + fn to_u32(&self) -> u32 { + self.0 as u32 + } + } - #[inline(always)] - fn from_u32(n: u32) -> BytePos { - BytePos(n) - } + impl Add for $ident { + type Output = $ident; - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 - } + #[inline(always)] + fn add(self, rhs: $ident) -> $ident { + $ident(self.0 + rhs.0) + } + } + + impl Sub for $ident { + type Output = $ident; + + #[inline(always)] + fn sub(self, rhs: $ident) -> $ident { + $ident(self.0 - rhs.0) + } + } + )* + }; } -impl Add for BytePos { - type Output = BytePos; +impl_pos! { + /// A byte offset. Keep this small (currently 32-bits), as AST contains + /// a lot of them. + #[derive(Clone, Copy, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] + pub struct BytePos(pub u32); - #[inline(always)] - fn add(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() + rhs.to_usize()) as u32) - } -} - -impl Sub for BytePos { - type Output = BytePos; - - #[inline(always)] - fn sub(self, rhs: BytePos) -> BytePos { - BytePos((self.to_usize() - rhs.to_usize()) as u32) - } + /// A character offset. Because of multibyte UTF-8 characters, a byte offset + /// is not equivalent to a character offset. The `SourceMap` will convert `BytePos` + /// values to `CharPos` values as necessary. + #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Debug)] + pub struct CharPos(pub usize); } impl Encodable for BytePos { @@ -1595,46 +1637,6 @@ impl Decodable for BytePos { } } -impl Pos for CharPos { - #[inline(always)] - fn from_usize(n: usize) -> CharPos { - CharPos(n) - } - - #[inline(always)] - fn to_usize(&self) -> usize { - self.0 - } - - #[inline(always)] - fn from_u32(n: u32) -> CharPos { - CharPos(n as usize) - } - - #[inline(always)] - fn to_u32(&self) -> u32 { - self.0 as u32 - } -} - -impl Add for CharPos { - type Output = CharPos; - - #[inline(always)] - fn add(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() + rhs.to_usize()) - } -} - -impl Sub for CharPos { - type Output = CharPos; - - #[inline(always)] - fn sub(self, rhs: CharPos) -> CharPos { - CharPos(self.to_usize() - rhs.to_usize()) - } -} - // _____________________________________________________________________________ // Loc, SourceFileAndLine, SourceFileAndBytePos // diff --git a/src/librustc_span/source_map.rs b/compiler/rustc_span/src/source_map.rs similarity index 98% rename from src/librustc_span/source_map.rs rename to compiler/rustc_span/src/source_map.rs index 7c656db22e..37596b8ef6 100644 --- a/src/librustc_span/source_map.rs +++ b/compiler/rustc_span/src/source_map.rs @@ -487,6 +487,15 @@ impl SourceMap { } } + /// Returns a new `Span` covering the start and end `BytePos`s of the file containing the given + /// `pos`. This can be used to quickly determine if another `BytePos` or `Span` is from the same + /// file. + pub fn lookup_file_span(&self, pos: BytePos) -> Span { + let idx = self.lookup_source_file_idx(pos); + let SourceFile { start_pos, end_pos, .. } = *(*self.files.borrow().source_files)[idx]; + Span::with_root_ctxt(start_pos, end_pos) + } + /// Returns `Some(span)`, a union of the LHS and RHS span. The LHS must precede the RHS. If /// there are gaps between LHS and RHS, the resulting union will cross these gaps. /// For this to work, diff --git a/src/librustc_span/source_map/tests.rs b/compiler/rustc_span/src/source_map/tests.rs similarity index 100% rename from src/librustc_span/source_map/tests.rs rename to compiler/rustc_span/src/source_map/tests.rs diff --git a/src/librustc_span/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs similarity index 100% rename from src/librustc_span/span_encoding.rs rename to compiler/rustc_span/src/span_encoding.rs diff --git a/src/librustc_span/symbol.rs b/compiler/rustc_span/src/symbol.rs similarity index 99% rename from src/librustc_span/symbol.rs rename to compiler/rustc_span/src/symbol.rs index 46612145bf..e3ad31469b 100644 --- a/src/librustc_span/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -110,7 +110,7 @@ symbols! { // called `sym::proc_macro` because then it's easy to mistakenly think it // represents "proc_macro". // - // As well as the symbols listed, there are symbols for the the strings + // As well as the symbols listed, there are symbols for the strings // "0", "1", ..., "9", which are accessible via `sym::integer`. // // The proc macro will abort if symbols are not in alphabetical order (as @@ -333,9 +333,11 @@ symbols! { clone, clone_closures, clone_from, + closure, closure_to_fn_coercion, cmp, cmpxchg16b_target_feature, + cmse_nonsecure_entry, coerce_unsized, cold, column, @@ -348,8 +350,11 @@ symbols! { const_compare_raw_pointers, const_constructor, const_eval_limit, + const_evaluatable_checked, const_extern_fn, const_fn, + const_fn_floating_point_arithmetic, + const_fn_fn_ptr_basics, const_fn_transmute, const_fn_union, const_generics, @@ -368,6 +373,8 @@ symbols! { const_trait_bound_opt_out, const_trait_impl, const_transmute, + constant, + constructor, contents, context, convert, @@ -415,7 +422,9 @@ symbols! { deny, deprecated, deref, + deref_method, deref_mut, + deref_target, derive, diagnostic, direct, @@ -435,13 +444,6 @@ symbols! { document_private_items, dotdot_in_tuple_patterns, dotdoteq_in_patterns, - double_braced_closure: "{{closure}}", - double_braced_constant: "{{constant}}", - double_braced_constructor: "{{constructor}}", - double_braced_crate: "{{crate}}", - double_braced_impl: "{{impl}}", - double_braced_misc: "{{misc}}", - double_braced_opaque: "{{opaque}}", drop, drop_in_place, drop_types_in_const, @@ -676,7 +678,7 @@ symbols! { minnumf32, minnumf64, mips_target_feature, - mmx_target_feature, + misc, module, module_path, more_struct_aliases, @@ -876,6 +878,7 @@ symbols! { rust_2015_preview, rust_2018_preview, rust_begin_unwind, + rust_eh_catch_typeinfo, rust_eh_personality, rust_eh_register_frames, rust_eh_unregister_frames, @@ -883,7 +886,6 @@ symbols! { rustc, rustc_allocator, rustc_allocator_nounwind, - rustc_allow_const_fn_ptr, rustc_args_required_const, rustc_attrs, rustc_builtin_macro, @@ -1068,6 +1070,7 @@ symbols! { target_feature, target_feature_11, target_has_atomic, + target_has_atomic_equal_alignment, target_has_atomic_load_store, target_os, target_pointer_width, diff --git a/src/librustc_span/symbol/tests.rs b/compiler/rustc_span/src/symbol/tests.rs similarity index 100% rename from src/librustc_span/symbol/tests.rs rename to compiler/rustc_span/src/symbol/tests.rs diff --git a/src/librustc_span/tests.rs b/compiler/rustc_span/src/tests.rs similarity index 100% rename from src/librustc_span/tests.rs rename to compiler/rustc_span/src/tests.rs diff --git a/compiler/rustc_symbol_mangling/Cargo.toml b/compiler/rustc_symbol_mangling/Cargo.toml new file mode 100644 index 0000000000..c0dacd24c3 --- /dev/null +++ b/compiler/rustc_symbol_mangling/Cargo.toml @@ -0,0 +1,21 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_symbol_mangling" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +tracing = "0.1" +punycode = "0.4.0" +rustc-demangle = "0.1.16" + +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_middle = { path = "../rustc_middle" } +rustc_hir = { path = "../rustc_hir" } +rustc_target = { path = "../rustc_target" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_session = { path = "../rustc_session" } diff --git a/src/librustc_symbol_mangling/legacy.rs b/compiler/rustc_symbol_mangling/src/legacy.rs similarity index 98% rename from src/librustc_symbol_mangling/legacy.rs rename to compiler/rustc_symbol_mangling/src/legacy.rs index 24356844ba..b96e318bd3 100644 --- a/src/librustc_symbol_mangling/legacy.rs +++ b/compiler/rustc_symbol_mangling/src/legacy.rs @@ -110,7 +110,7 @@ fn get_symbol_hash<'tcx>( // If this is a function, we hash the signature as well. // This is not *strictly* needed, but it may help in some // situations, see the `run-make/a-b-a-linker-guard` test. - if let ty::FnDef(..) = item_type.kind { + if let ty::FnDef(..) = item_type.kind() { item_type.fn_sig(tcx).hash_stable(&mut hcx, &mut hasher); } @@ -210,7 +210,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { } fn print_type(self, ty: Ty<'tcx>) -> Result { - match ty.kind { + match *ty.kind() { // Print all nominal types as paths (unlike `pretty_print_type`). ty::FnDef(def_id, substs) | ty::Opaque(def_id, substs) @@ -258,7 +258,7 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { ) -> Result { // Similar to `pretty_path_qualified`, but for the other // types that are printed as paths (see `print_type` above). - match self_ty.kind { + match self_ty.kind() { ty::FnDef(..) | ty::Opaque(..) | ty::Projection(_) @@ -316,7 +316,8 @@ impl Printer<'tcx> for SymbolPrinter<'tcx> { self.path.finalize_pending_component(); } - self.write_str(&disambiguated_data.data.as_symbol().as_str())?; + write!(self, "{}", disambiguated_data.data)?; + Ok(self) } fn path_generic_args( diff --git a/src/librustc_symbol_mangling/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs similarity index 99% rename from src/librustc_symbol_mangling/lib.rs rename to compiler/rustc_symbol_mangling/src/lib.rs index 296b40c4e3..75150a56c4 100644 --- a/src/librustc_symbol_mangling/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -87,7 +87,7 @@ //! virtually impossible. Thus, symbol hash generation exclusively relies on //! DefPaths which are much more robust in the face of changes to the code base. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(never_type)] #![feature(nll)] #![feature(or_patterns)] diff --git a/src/librustc_symbol_mangling/test.rs b/compiler/rustc_symbol_mangling/src/test.rs similarity index 100% rename from src/librustc_symbol_mangling/test.rs rename to compiler/rustc_symbol_mangling/src/test.rs diff --git a/src/librustc_symbol_mangling/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs similarity index 98% rename from src/librustc_symbol_mangling/v0.rs rename to compiler/rustc_symbol_mangling/src/v0.rs index f01c3da8b5..da9c93143b 100644 --- a/src/librustc_symbol_mangling/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -152,11 +152,8 @@ impl SymbolMangler<'tcx> { let _ = write!(self.out, "{}", ident.len()); // Write a separating `_` if necessary (leading digit or `_`). - match ident.chars().next() { - Some('_' | '0'..='9') => { - self.push("_"); - } - _ => {} + if let Some('_' | '0'..='9') = ident.chars().next() { + self.push("_"); } self.push(ident); @@ -323,7 +320,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { fn print_type(mut self, ty: Ty<'tcx>) -> Result { // Basic types, never cached (single-character). - let basic_type = match ty.kind { + let basic_type = match ty.kind() { ty::Bool => "b", ty::Char => "c", ty::Str => "e", @@ -359,7 +356,7 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - match ty.kind { + match *ty.kind() { // Basic types, handled above. ty::Bool | ty::Char | ty::Str | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Never => { unreachable!() @@ -505,8 +502,9 @@ impl Printer<'tcx> for SymbolMangler<'tcx> { } let start = self.out.len(); - match ct.ty.kind { + match ct.ty.kind() { ty::Uint(_) => {} + ty::Bool => {} _ => { bug!("symbol_names: unsupported constant of type `{}` ({:?})", ct.ty, ct); } diff --git a/compiler/rustc_target/Cargo.toml b/compiler/rustc_target/Cargo.toml new file mode 100644 index 0000000000..2d7d9f1d82 --- /dev/null +++ b/compiler/rustc_target/Cargo.toml @@ -0,0 +1,14 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_target" +version = "0.0.0" +edition = "2018" + +[dependencies] +bitflags = "1.2.1" +tracing = "0.1" +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_macros = { path = "../rustc_macros" } +rustc_serialize = { path = "../rustc_serialize" } +rustc_span = { path = "../rustc_span" } +rustc_index = { path = "../rustc_index" } diff --git a/src/librustc_target/README.md b/compiler/rustc_target/README.md similarity index 100% rename from src/librustc_target/README.md rename to compiler/rustc_target/README.md diff --git a/src/librustc_target/abi/call/aarch64.rs b/compiler/rustc_target/src/abi/call/aarch64.rs similarity index 100% rename from src/librustc_target/abi/call/aarch64.rs rename to compiler/rustc_target/src/abi/call/aarch64.rs diff --git a/src/librustc_target/abi/call/amdgpu.rs b/compiler/rustc_target/src/abi/call/amdgpu.rs similarity index 100% rename from src/librustc_target/abi/call/amdgpu.rs rename to compiler/rustc_target/src/abi/call/amdgpu.rs diff --git a/src/librustc_target/abi/call/arm.rs b/compiler/rustc_target/src/abi/call/arm.rs similarity index 100% rename from src/librustc_target/abi/call/arm.rs rename to compiler/rustc_target/src/abi/call/arm.rs diff --git a/src/librustc_target/abi/call/avr.rs b/compiler/rustc_target/src/abi/call/avr.rs similarity index 100% rename from src/librustc_target/abi/call/avr.rs rename to compiler/rustc_target/src/abi/call/avr.rs diff --git a/src/librustc_target/abi/call/hexagon.rs b/compiler/rustc_target/src/abi/call/hexagon.rs similarity index 100% rename from src/librustc_target/abi/call/hexagon.rs rename to compiler/rustc_target/src/abi/call/hexagon.rs diff --git a/src/librustc_target/abi/call/mips.rs b/compiler/rustc_target/src/abi/call/mips.rs similarity index 100% rename from src/librustc_target/abi/call/mips.rs rename to compiler/rustc_target/src/abi/call/mips.rs diff --git a/src/librustc_target/abi/call/mips64.rs b/compiler/rustc_target/src/abi/call/mips64.rs similarity index 100% rename from src/librustc_target/abi/call/mips64.rs rename to compiler/rustc_target/src/abi/call/mips64.rs diff --git a/src/librustc_target/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs similarity index 97% rename from src/librustc_target/abi/call/mod.rs rename to compiler/rustc_target/src/abi/call/mod.rs index 8f7e2bba5a..602c424a04 100644 --- a/src/librustc_target/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -610,3 +610,15 @@ impl<'a, Ty> FnAbi<'a, Ty> { Ok(()) } } + +/// Returns the maximum size of return values to be passed by value in the Rust ABI. +/// +/// Return values beyond this size will use an implicit out-pointer instead. +pub fn max_ret_by_val(spec: &C) -> Size { + match spec.target_spec().arch.as_str() { + // System-V will pass return values up to 128 bits in RAX/RDX. + "x86_64" => Size::from_bits(128), + + _ => spec.data_layout().pointer_size, + } +} diff --git a/src/librustc_target/abi/call/msp430.rs b/compiler/rustc_target/src/abi/call/msp430.rs similarity index 100% rename from src/librustc_target/abi/call/msp430.rs rename to compiler/rustc_target/src/abi/call/msp430.rs diff --git a/src/librustc_target/abi/call/nvptx.rs b/compiler/rustc_target/src/abi/call/nvptx.rs similarity index 100% rename from src/librustc_target/abi/call/nvptx.rs rename to compiler/rustc_target/src/abi/call/nvptx.rs diff --git a/src/librustc_target/abi/call/nvptx64.rs b/compiler/rustc_target/src/abi/call/nvptx64.rs similarity index 100% rename from src/librustc_target/abi/call/nvptx64.rs rename to compiler/rustc_target/src/abi/call/nvptx64.rs diff --git a/src/librustc_target/abi/call/powerpc.rs b/compiler/rustc_target/src/abi/call/powerpc.rs similarity index 100% rename from src/librustc_target/abi/call/powerpc.rs rename to compiler/rustc_target/src/abi/call/powerpc.rs diff --git a/src/librustc_target/abi/call/powerpc64.rs b/compiler/rustc_target/src/abi/call/powerpc64.rs similarity index 100% rename from src/librustc_target/abi/call/powerpc64.rs rename to compiler/rustc_target/src/abi/call/powerpc64.rs diff --git a/src/librustc_target/abi/call/riscv.rs b/compiler/rustc_target/src/abi/call/riscv.rs similarity index 100% rename from src/librustc_target/abi/call/riscv.rs rename to compiler/rustc_target/src/abi/call/riscv.rs diff --git a/src/librustc_target/abi/call/s390x.rs b/compiler/rustc_target/src/abi/call/s390x.rs similarity index 100% rename from src/librustc_target/abi/call/s390x.rs rename to compiler/rustc_target/src/abi/call/s390x.rs diff --git a/src/librustc_target/abi/call/sparc.rs b/compiler/rustc_target/src/abi/call/sparc.rs similarity index 100% rename from src/librustc_target/abi/call/sparc.rs rename to compiler/rustc_target/src/abi/call/sparc.rs diff --git a/src/librustc_target/abi/call/sparc64.rs b/compiler/rustc_target/src/abi/call/sparc64.rs similarity index 100% rename from src/librustc_target/abi/call/sparc64.rs rename to compiler/rustc_target/src/abi/call/sparc64.rs diff --git a/src/librustc_target/abi/call/wasm32.rs b/compiler/rustc_target/src/abi/call/wasm32.rs similarity index 100% rename from src/librustc_target/abi/call/wasm32.rs rename to compiler/rustc_target/src/abi/call/wasm32.rs diff --git a/src/librustc_target/abi/call/wasm32_bindgen_compat.rs b/compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs similarity index 100% rename from src/librustc_target/abi/call/wasm32_bindgen_compat.rs rename to compiler/rustc_target/src/abi/call/wasm32_bindgen_compat.rs diff --git a/src/librustc_target/abi/call/x86.rs b/compiler/rustc_target/src/abi/call/x86.rs similarity index 100% rename from src/librustc_target/abi/call/x86.rs rename to compiler/rustc_target/src/abi/call/x86.rs diff --git a/src/librustc_target/abi/call/x86_64.rs b/compiler/rustc_target/src/abi/call/x86_64.rs similarity index 100% rename from src/librustc_target/abi/call/x86_64.rs rename to compiler/rustc_target/src/abi/call/x86_64.rs diff --git a/src/librustc_target/abi/call/x86_win64.rs b/compiler/rustc_target/src/abi/call/x86_win64.rs similarity index 100% rename from src/librustc_target/abi/call/x86_win64.rs rename to compiler/rustc_target/src/abi/call/x86_win64.rs diff --git a/src/librustc_target/abi/mod.rs b/compiler/rustc_target/src/abi/mod.rs similarity index 97% rename from src/librustc_target/abi/mod.rs rename to compiler/rustc_target/src/abi/mod.rs index 4b565dd246..3c1a2ea39d 100644 --- a/src/librustc_target/abi/mod.rs +++ b/compiler/rustc_target/src/abi/mod.rs @@ -1135,16 +1135,31 @@ impl<'a, Ty> TyAndLayout<'a, Ty> { 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::Aggregate { .. } => true, // Cannot be excluded *right now*. + Abi::Aggregate { .. } => true, // Fields are checked below. }; if !valid { // This is definitely not okay. - trace!("might_permit_raw_init({:?}, zero={}): not valid", self.layout, zero); return Ok(false); } - // If we have not found an error yet, we need to recursively descend. - // FIXME(#66151): For now, we are conservative and do not do this. + // If we have not found an error yet, we need to recursively descend into fields. + match &self.fields { + FieldsShape::Primitive | FieldsShape::Union { .. } => {} + FieldsShape::Array { .. } => { + // FIXME(#66151): For now, we are conservative and do not check arrays. + } + FieldsShape::Arbitrary { offsets, .. } => { + for idx in 0..offsets.len() { + let field = self.field(cx, idx).to_result()?; + if !field.might_permit_raw_init(cx, zero)? { + // We found a field that is unhappy with this kind of initialization. + return Ok(false); + } + } + } + } + + // FIXME(#66151): For now, we are conservative and do not check `self.variants`. Ok(true) } } diff --git a/src/librustc_target/asm/aarch64.rs b/compiler/rustc_target/src/asm/aarch64.rs similarity index 100% rename from src/librustc_target/asm/aarch64.rs rename to compiler/rustc_target/src/asm/aarch64.rs diff --git a/src/librustc_target/asm/arm.rs b/compiler/rustc_target/src/asm/arm.rs similarity index 100% rename from src/librustc_target/asm/arm.rs rename to compiler/rustc_target/src/asm/arm.rs diff --git a/src/librustc_target/asm/hexagon.rs b/compiler/rustc_target/src/asm/hexagon.rs similarity index 100% rename from src/librustc_target/asm/hexagon.rs rename to compiler/rustc_target/src/asm/hexagon.rs diff --git a/compiler/rustc_target/src/asm/mips.rs b/compiler/rustc_target/src/asm/mips.rs new file mode 100644 index 0000000000..638c52d97f --- /dev/null +++ b/compiler/rustc_target/src/asm/mips.rs @@ -0,0 +1,132 @@ +use super::{InlineAsmArch, InlineAsmType}; +use rustc_macros::HashStable_Generic; +use std::fmt; + +def_reg_class! { + Mips MipsInlineAsmRegClass { + reg, + freg, + } +} + +impl MipsInlineAsmRegClass { + pub fn valid_modifiers(self, _arch: super::InlineAsmArch) -> &'static [char] { + &[] + } + + pub fn suggest_class(self, _arch: InlineAsmArch, _ty: InlineAsmType) -> Option { + None + } + + pub fn suggest_modifier( + self, + _arch: InlineAsmArch, + _ty: InlineAsmType, + ) -> Option<(char, &'static str)> { + None + } + + pub fn default_modifier(self, _arch: InlineAsmArch) -> Option<(char, &'static str)> { + None + } + + pub fn supported_types( + self, + _arch: InlineAsmArch, + ) -> &'static [(InlineAsmType, Option<&'static str>)] { + match self { + Self::reg => types! { _: I8, I16, I32, F32; }, + Self::freg => types! { _: F32; }, + } + } +} + +// The reserved registers are somewhat taken from . +def_regs! { + Mips MipsInlineAsmReg MipsInlineAsmRegClass { + v0: reg = ["$2", "$v0"], + v1: reg = ["$3", "$v1"], + a0: reg = ["$4", "$a0"], + a1: reg = ["$5", "$a1"], + a2: reg = ["$6", "$a2"], + a3: reg = ["$7", "$a3"], + // FIXME: Reserve $t0, $t1 if in mips16 mode. + t0: reg = ["$8", "$t0"], + t1: reg = ["$9", "$t1"], + t2: reg = ["$10", "$t2"], + t3: reg = ["$11", "$t3"], + t4: reg = ["$12", "$t4"], + t5: reg = ["$13", "$t5"], + t6: reg = ["$14", "$t6"], + t7: reg = ["$15", "$t7"], + s0: reg = ["$16", "$s0"], + s1: reg = ["$17", "$s1"], + s2: reg = ["$18", "$s2"], + s3: reg = ["$19", "$s3"], + s4: reg = ["$20", "$s4"], + s5: reg = ["$21", "$s5"], + s6: reg = ["$22", "$s6"], + s7: reg = ["$23", "$s7"], + t8: reg = ["$24", "$t8"], + t9: reg = ["$25", "$t9"], + f0: freg = ["$f0"], + f1: freg = ["$f1"], + f2: freg = ["$f2"], + f3: freg = ["$f3"], + f4: freg = ["$f4"], + f5: freg = ["$f5"], + f6: freg = ["$f6"], + f7: freg = ["$f7"], + f8: freg = ["$f8"], + f9: freg = ["$f9"], + f10: freg = ["$f10"], + f11: freg = ["$f11"], + f12: freg = ["$f12"], + f13: freg = ["$f13"], + f14: freg = ["$f14"], + f15: freg = ["$f15"], + f16: freg = ["$f16"], + f17: freg = ["$f17"], + f18: freg = ["$f18"], + f19: freg = ["$f19"], + f20: freg = ["$f20"], + f21: freg = ["$f21"], + f22: freg = ["$f22"], + f23: freg = ["$f23"], + f24: freg = ["$f24"], + f25: freg = ["$f25"], + f26: freg = ["$f26"], + f27: freg = ["$f27"], + f28: freg = ["$f28"], + f29: freg = ["$f29"], + f30: freg = ["$f30"], + f31: freg = ["$f31"], + #error = ["$0", "$zero"] => + "constant zero cannot be used as an operand for inline asm", + #error = ["$1", "$at"] => + "reserved for assembler (Assembler Temp)", + #error = ["$26", "$k0"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$27", "$k1"] => + "OS-reserved register cannot be used as an operand for inline asm", + #error = ["$28", "$gp"] => + "the global pointer cannot be used as an operand for inline asm", + #error = ["$29", "$sp"] => + "the stack pointer cannot be used as an operand for inline asm", + #error = ["$30", "$s8", "$fp"] => + "the frame pointer cannot be used as an operand for inline asm", + #error = ["$31", "$ra"] => + "the return address register cannot be used as an operand for inline asm", + } +} + +impl MipsInlineAsmReg { + pub fn emit( + self, + out: &mut dyn fmt::Write, + _arch: InlineAsmArch, + _modifier: Option, + ) -> fmt::Result { + out.write_str(self.name()) + } +} diff --git a/src/librustc_target/asm/mod.rs b/compiler/rustc_target/src/asm/mod.rs similarity index 94% rename from src/librustc_target/asm/mod.rs rename to compiler/rustc_target/src/asm/mod.rs index c22644bf81..e2f8e91fa9 100644 --- a/src/librustc_target/asm/mod.rs +++ b/compiler/rustc_target/src/asm/mod.rs @@ -152,6 +152,7 @@ macro_rules! types { mod aarch64; mod arm; mod hexagon; +mod mips; mod nvptx; mod riscv; mod x86; @@ -159,6 +160,7 @@ mod x86; pub use aarch64::{AArch64InlineAsmReg, AArch64InlineAsmRegClass}; pub use arm::{ArmInlineAsmReg, ArmInlineAsmRegClass}; pub use hexagon::{HexagonInlineAsmReg, HexagonInlineAsmRegClass}; +pub use mips::{MipsInlineAsmReg, MipsInlineAsmRegClass}; pub use nvptx::{NvptxInlineAsmReg, NvptxInlineAsmRegClass}; pub use riscv::{RiscVInlineAsmReg, RiscVInlineAsmRegClass}; pub use x86::{X86InlineAsmReg, X86InlineAsmRegClass}; @@ -173,6 +175,7 @@ pub enum InlineAsmArch { RiscV64, Nvptx64, Hexagon, + Mips, } impl FromStr for InlineAsmArch { @@ -188,6 +191,7 @@ impl FromStr for InlineAsmArch { "riscv64" => Ok(Self::RiscV64), "nvptx64" => Ok(Self::Nvptx64), "hexagon" => Ok(Self::Hexagon), + "mips" => Ok(Self::Mips), _ => Err(()), } } @@ -201,6 +205,7 @@ pub enum InlineAsmReg { RiscV(RiscVInlineAsmReg), Nvptx(NvptxInlineAsmReg), Hexagon(HexagonInlineAsmReg), + Mips(MipsInlineAsmReg), } impl InlineAsmReg { @@ -211,6 +216,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.name(), Self::RiscV(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -221,6 +227,7 @@ impl InlineAsmReg { Self::AArch64(r) => InlineAsmRegClass::AArch64(r.reg_class()), Self::RiscV(r) => InlineAsmRegClass::RiscV(r.reg_class()), Self::Hexagon(r) => InlineAsmRegClass::Hexagon(r.reg_class()), + Self::Mips(r) => InlineAsmRegClass::Mips(r.reg_class()), } } @@ -252,6 +259,9 @@ impl InlineAsmReg { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmReg::parse(arch, has_feature, target, &name)?) } + InlineAsmArch::Mips => { + Self::Mips(MipsInlineAsmReg::parse(arch, has_feature, target, &name)?) + } }) } @@ -269,6 +279,7 @@ impl InlineAsmReg { Self::AArch64(r) => r.emit(out, arch, modifier), Self::RiscV(r) => r.emit(out, arch, modifier), Self::Hexagon(r) => r.emit(out, arch, modifier), + Self::Mips(r) => r.emit(out, arch, modifier), } } @@ -279,6 +290,7 @@ impl InlineAsmReg { Self::AArch64(_) => cb(self), Self::RiscV(_) => cb(self), Self::Hexagon(r) => r.overlapping_regs(|r| cb(Self::Hexagon(r))), + Self::Mips(_) => cb(self), } } } @@ -291,6 +303,7 @@ pub enum InlineAsmRegClass { RiscV(RiscVInlineAsmRegClass), Nvptx(NvptxInlineAsmRegClass), Hexagon(HexagonInlineAsmRegClass), + Mips(MipsInlineAsmRegClass), } impl InlineAsmRegClass { @@ -302,6 +315,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.name(), Self::Nvptx(r) => r.name(), Self::Hexagon(r) => r.name(), + Self::Mips(r) => r.name(), } } @@ -316,6 +330,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::RiscV), Self::Nvptx(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Nvptx), Self::Hexagon(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Hexagon), + Self::Mips(r) => r.suggest_class(arch, ty).map(InlineAsmRegClass::Mips), } } @@ -337,6 +352,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.suggest_modifier(arch, ty), Self::Nvptx(r) => r.suggest_modifier(arch, ty), Self::Hexagon(r) => r.suggest_modifier(arch, ty), + Self::Mips(r) => r.suggest_modifier(arch, ty), } } @@ -354,6 +370,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.default_modifier(arch), Self::Nvptx(r) => r.default_modifier(arch), Self::Hexagon(r) => r.default_modifier(arch), + Self::Mips(r) => r.default_modifier(arch), } } @@ -370,6 +387,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.supported_types(arch), Self::Nvptx(r) => r.supported_types(arch), Self::Hexagon(r) => r.supported_types(arch), + Self::Mips(r) => r.supported_types(arch), } } @@ -391,6 +409,7 @@ impl InlineAsmRegClass { InlineAsmArch::Hexagon => { Self::Hexagon(HexagonInlineAsmRegClass::parse(arch, name)?) } + InlineAsmArch::Mips => Self::Mips(MipsInlineAsmRegClass::parse(arch, name)?), }) }) } @@ -405,6 +424,7 @@ impl InlineAsmRegClass { Self::RiscV(r) => r.valid_modifiers(arch), Self::Nvptx(r) => r.valid_modifiers(arch), Self::Hexagon(r) => r.valid_modifiers(arch), + Self::Mips(r) => r.valid_modifiers(arch), } } } @@ -545,5 +565,10 @@ pub fn allocatable_registers( hexagon::fill_reg_map(arch, has_feature, target, &mut map); map } + InlineAsmArch::Mips => { + let mut map = mips::regclass_map(); + mips::fill_reg_map(arch, has_feature, target, &mut map); + map + } } } diff --git a/src/librustc_target/asm/nvptx.rs b/compiler/rustc_target/src/asm/nvptx.rs similarity index 100% rename from src/librustc_target/asm/nvptx.rs rename to compiler/rustc_target/src/asm/nvptx.rs diff --git a/src/librustc_target/asm/riscv.rs b/compiler/rustc_target/src/asm/riscv.rs similarity index 100% rename from src/librustc_target/asm/riscv.rs rename to compiler/rustc_target/src/asm/riscv.rs diff --git a/src/librustc_target/asm/x86.rs b/compiler/rustc_target/src/asm/x86.rs similarity index 100% rename from src/librustc_target/asm/x86.rs rename to compiler/rustc_target/src/asm/x86.rs diff --git a/src/librustc_target/lib.rs b/compiler/rustc_target/src/lib.rs similarity index 92% rename from src/librustc_target/lib.rs rename to compiler/rustc_target/src/lib.rs index 5788e1e838..fb747dfcbd 100644 --- a/src/librustc_target/lib.rs +++ b/compiler/rustc_target/src/lib.rs @@ -7,7 +7,7 @@ //! more 'stuff' here in the future. It does not have a dependency on //! LLVM. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(const_fn)] #![feature(const_panic)] diff --git a/src/librustc_target/spec/aarch64_apple_darwin.rs b/compiler/rustc_target/src/spec/aarch64_apple_darwin.rs similarity index 100% rename from src/librustc_target/spec/aarch64_apple_darwin.rs rename to compiler/rustc_target/src/spec/aarch64_apple_darwin.rs diff --git a/src/librustc_target/spec/aarch64_apple_ios.rs b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs similarity index 93% rename from src/librustc_target/spec/aarch64_apple_ios.rs rename to compiler/rustc_target/src/spec/aarch64_apple_ios.rs index 21dcec8d5e..168cd01878 100644 --- a/src/librustc_target/spec/aarch64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Arm64, AppleOS::iOS)?; + let base = opts(Arch::Arm64); Ok(Target { llvm_target: "arm64-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/aarch64_apple_tvos.rs b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs similarity index 90% rename from src/librustc_target/spec/aarch64_apple_tvos.rs rename to compiler/rustc_target/src/spec/aarch64_apple_tvos.rs index 2b0cd6cabf..5e2cab0df1 100644 --- a/src/librustc_target/spec/aarch64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/aarch64_apple_tvos.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Arm64, AppleOS::tvOS)?; + let base = opts(Arch::Arm64); Ok(Target { llvm_target: "arm64-apple-tvos".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/aarch64_fuchsia.rs b/compiler/rustc_target/src/spec/aarch64_fuchsia.rs similarity index 100% rename from src/librustc_target/spec/aarch64_fuchsia.rs rename to compiler/rustc_target/src/spec/aarch64_fuchsia.rs diff --git a/src/librustc_target/spec/aarch64_linux_android.rs b/compiler/rustc_target/src/spec/aarch64_linux_android.rs similarity index 100% rename from src/librustc_target/spec/aarch64_linux_android.rs rename to compiler/rustc_target/src/spec/aarch64_linux_android.rs diff --git a/src/librustc_target/spec/aarch64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/aarch64_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/aarch64_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/aarch64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_cloudabi.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_cloudabi.rs diff --git a/src/librustc_target/spec/aarch64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_freebsd.rs diff --git a/src/librustc_target/spec/aarch64_unknown_hermit.rs b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs similarity index 73% rename from src/librustc_target/spec/aarch64_unknown_hermit.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs index 5f978c0324..e07b8f7a75 100644 --- a/src/librustc_target/spec/aarch64_unknown_hermit.rs +++ b/compiler/rustc_target/src/spec/aarch64_unknown_hermit.rs @@ -1,10 +1,8 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; +use crate::spec::{LinkerFlavor, LldFlavor, Target, TargetResult}; pub fn target() -> TargetResult { let mut base = super::hermit_base::opts(); base.max_atomic_width = Some(128); - base.unsupported_abis = super::arm_base::unsupported_abis(); - base.linker = Some("aarch64-hermit-gcc".to_string()); Ok(Target { llvm_target: "aarch64-unknown-hermit".to_string(), @@ -16,7 +14,7 @@ pub fn target() -> TargetResult { target_os: "hermit".to_string(), target_env: String::new(), target_vendor: "unknown".to_string(), - linker_flavor: LinkerFlavor::Gcc, + linker_flavor: LinkerFlavor::Lld(LldFlavor::Ld), options: base, }) } diff --git a/src/librustc_target/spec/aarch64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/aarch64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/aarch64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_netbsd.rs diff --git a/src/librustc_target/spec/aarch64_unknown_none.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_none.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_none.rs diff --git a/src/librustc_target/spec/aarch64_unknown_none_softfloat.rs b/compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_none_softfloat.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_none_softfloat.rs diff --git a/src/librustc_target/spec/aarch64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_openbsd.rs diff --git a/src/librustc_target/spec/aarch64_unknown_redox.rs b/compiler/rustc_target/src/spec/aarch64_unknown_redox.rs similarity index 100% rename from src/librustc_target/spec/aarch64_unknown_redox.rs rename to compiler/rustc_target/src/spec/aarch64_unknown_redox.rs diff --git a/src/librustc_target/spec/aarch64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/aarch64_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/aarch64_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/aarch64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/aarch64_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/aarch64_wrs_vxworks.rs diff --git a/src/librustc_target/spec/abi.rs b/compiler/rustc_target/src/spec/abi.rs similarity index 100% rename from src/librustc_target/spec/abi.rs rename to compiler/rustc_target/src/spec/abi.rs diff --git a/src/librustc_target/spec/abi/tests.rs b/compiler/rustc_target/src/spec/abi/tests.rs similarity index 100% rename from src/librustc_target/spec/abi/tests.rs rename to compiler/rustc_target/src/spec/abi/tests.rs diff --git a/src/librustc_target/spec/android_base.rs b/compiler/rustc_target/src/spec/android_base.rs similarity index 100% rename from src/librustc_target/spec/android_base.rs rename to compiler/rustc_target/src/spec/android_base.rs diff --git a/src/librustc_target/spec/apple_base.rs b/compiler/rustc_target/src/spec/apple_base.rs similarity index 100% rename from src/librustc_target/spec/apple_base.rs rename to compiler/rustc_target/src/spec/apple_base.rs diff --git a/compiler/rustc_target/src/spec/apple_sdk_base.rs b/compiler/rustc_target/src/spec/apple_sdk_base.rs new file mode 100644 index 0000000000..e34277d5af --- /dev/null +++ b/compiler/rustc_target/src/spec/apple_sdk_base.rs @@ -0,0 +1,43 @@ +use crate::spec::TargetOptions; + +use Arch::*; +#[allow(non_camel_case_types)] +#[derive(Copy, Clone)] +pub enum Arch { + Armv7, + Armv7s, + Arm64, + I386, + X86_64, + X86_64_macabi, +} + +fn target_cpu(arch: Arch) -> String { + match arch { + Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher + Armv7s => "cortex-a9", + Arm64 => "apple-a7", + I386 => "yonah", + X86_64 => "core2", + X86_64_macabi => "core2", + } + .to_string() +} + +fn link_env_remove(arch: Arch) -> Vec { + match arch { + Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()], + X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()], + } +} + +pub fn opts(arch: Arch) -> TargetOptions { + TargetOptions { + cpu: target_cpu(arch), + executables: true, + link_env_remove: link_env_remove(arch), + has_elf_tls: false, + eliminate_frame_pointer: false, + ..super::apple_base::opts() + } +} diff --git a/src/librustc_target/spec/arm_base.rs b/compiler/rustc_target/src/spec/arm_base.rs similarity index 100% rename from src/librustc_target/spec/arm_base.rs rename to compiler/rustc_target/src/spec/arm_base.rs diff --git a/src/librustc_target/spec/arm_linux_androideabi.rs b/compiler/rustc_target/src/spec/arm_linux_androideabi.rs similarity index 100% rename from src/librustc_target/spec/arm_linux_androideabi.rs rename to compiler/rustc_target/src/spec/arm_linux_androideabi.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_gnueabihf.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_gnueabihf.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_musleabi.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_musleabi.rs diff --git a/src/librustc_target/spec/arm_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs similarity index 100% rename from src/librustc_target/spec/arm_unknown_linux_musleabihf.rs rename to compiler/rustc_target/src/spec/arm_unknown_linux_musleabihf.rs diff --git a/src/librustc_target/spec/armebv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/armebv7r_none_eabi.rs rename to compiler/rustc_target/src/spec/armebv7r_none_eabi.rs diff --git a/src/librustc_target/spec/armebv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armebv7r_none_eabihf.rs rename to compiler/rustc_target/src/spec/armebv7r_none_eabihf.rs diff --git a/src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/armv4t_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/armv4t_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/armv5te_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/armv5te_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs similarity index 100% rename from src/librustc_target/spec/armv5te_unknown_linux_musleabi.rs rename to compiler/rustc_target/src/spec/armv5te_unknown_linux_musleabi.rs diff --git a/src/librustc_target/spec/armv6_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/armv6_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/armv6_unknown_freebsd.rs diff --git a/src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv6_unknown_netbsd_eabihf.rs rename to compiler/rustc_target/src/spec/armv6_unknown_netbsd_eabihf.rs diff --git a/src/librustc_target/spec/armv7_apple_ios.rs b/compiler/rustc_target/src/spec/armv7_apple_ios.rs similarity index 89% rename from src/librustc_target/spec/armv7_apple_ios.rs rename to compiler/rustc_target/src/spec/armv7_apple_ios.rs index 393843526a..6dafcc2c34 100644 --- a/src/librustc_target/spec/armv7_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Armv7, AppleOS::iOS)?; + let base = opts(Arch::Armv7); Ok(Target { llvm_target: "armv7-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/armv7_linux_androideabi.rs b/compiler/rustc_target/src/spec/armv7_linux_androideabi.rs similarity index 100% rename from src/librustc_target/spec/armv7_linux_androideabi.rs rename to compiler/rustc_target/src/spec/armv7_linux_androideabi.rs diff --git a/src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_cloudabi_eabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_cloudabi_eabihf.rs diff --git a/src/librustc_target/spec/armv7_unknown_freebsd.rs b/compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/armv7_unknown_freebsd.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_gnueabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_gnueabi.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabi.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_gnueabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_gnueabihf.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_musleabi.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_musleabi.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_musleabi.rs diff --git a/src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_linux_musleabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_linux_musleabihf.rs diff --git a/src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs b/compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_unknown_netbsd_eabihf.rs rename to compiler/rustc_target/src/spec/armv7_unknown_netbsd_eabihf.rs diff --git a/src/librustc_target/spec/armv7_wrs_vxworks_eabihf.rs b/compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7_wrs_vxworks_eabihf.rs rename to compiler/rustc_target/src/spec/armv7_wrs_vxworks_eabihf.rs diff --git a/src/librustc_target/spec/armv7a_none_eabi.rs b/compiler/rustc_target/src/spec/armv7a_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/armv7a_none_eabi.rs rename to compiler/rustc_target/src/spec/armv7a_none_eabi.rs diff --git a/src/librustc_target/spec/armv7a_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7a_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7a_none_eabihf.rs rename to compiler/rustc_target/src/spec/armv7a_none_eabihf.rs diff --git a/src/librustc_target/spec/armv7r_none_eabi.rs b/compiler/rustc_target/src/spec/armv7r_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/armv7r_none_eabi.rs rename to compiler/rustc_target/src/spec/armv7r_none_eabi.rs diff --git a/src/librustc_target/spec/armv7r_none_eabihf.rs b/compiler/rustc_target/src/spec/armv7r_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/armv7r_none_eabihf.rs rename to compiler/rustc_target/src/spec/armv7r_none_eabihf.rs diff --git a/src/librustc_target/spec/armv7s_apple_ios.rs b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs similarity index 89% rename from src/librustc_target/spec/armv7s_apple_ios.rs rename to compiler/rustc_target/src/spec/armv7s_apple_ios.rs index 998a7b2e16..d6c99c4ade 100644 --- a/src/librustc_target/spec/armv7s_apple_ios.rs +++ b/compiler/rustc_target/src/spec/armv7s_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::Armv7s, AppleOS::iOS)?; + let base = opts(Arch::Armv7s); Ok(Target { llvm_target: "armv7s-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/asmjs_unknown_emscripten.rs b/compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs similarity index 100% rename from src/librustc_target/spec/asmjs_unknown_emscripten.rs rename to compiler/rustc_target/src/spec/asmjs_unknown_emscripten.rs diff --git a/compiler/rustc_target/src/spec/avr_gnu_base.rs b/compiler/rustc_target/src/spec/avr_gnu_base.rs new file mode 100644 index 0000000000..527a322d56 --- /dev/null +++ b/compiler/rustc_target/src/spec/avr_gnu_base.rs @@ -0,0 +1,53 @@ +use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; + +/// A base target for AVR devices using the GNU toolchain. +/// +/// Requires GNU avr-gcc and avr-binutils on the host system. +pub fn target(target_cpu: String) -> TargetResult { + Ok(Target { + arch: "avr".to_string(), + data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), + llvm_target: "avr-unknown-unknown".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "16".to_string(), + linker_flavor: LinkerFlavor::Gcc, + target_os: "unknown".to_string(), + target_env: "".to_string(), + target_vendor: "unknown".to_string(), + target_c_int_width: 16.to_string(), + options: TargetOptions { + cpu: target_cpu.clone(), + exe_suffix: ".elf".to_string(), + + linker: Some("avr-gcc".to_owned()), + dynamic_linking: false, + executables: true, + linker_is_gnu: true, + has_rpath: false, + position_independent_executables: false, + eh_frame_header: false, + pre_link_args: vec![( + LinkerFlavor::Gcc, + vec![ + format!("-mmcu={}", target_cpu), + // We want to be able to strip as much executable code as possible + // from the linker command line, and this flag indicates to the + // linker that it can avoid linking in dynamic libraries that don't + // actually satisfy any symbols up to that point (as with many other + // resolutions the linker does). This option only applies to all + // following libraries so we're sure to pass it as one of the first + // arguments. + "-Wl,--as-needed".to_string(), + ], + )] + .into_iter() + .collect(), + late_link_args: vec![(LinkerFlavor::Gcc, vec!["-lgcc".to_owned()])] + .into_iter() + .collect(), + max_atomic_width: Some(0), + atomic_cas: false, + ..TargetOptions::default() + }, + }) +} diff --git a/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs new file mode 100644 index 0000000000..5d22598b57 --- /dev/null +++ b/compiler/rustc_target/src/spec/avr_unknown_gnu_atmega328.rs @@ -0,0 +1,5 @@ +use crate::spec::TargetResult; + +pub fn target() -> TargetResult { + super::avr_gnu_base::target("atmega328".to_owned()) +} diff --git a/src/librustc_target/spec/cloudabi_base.rs b/compiler/rustc_target/src/spec/cloudabi_base.rs similarity index 100% rename from src/librustc_target/spec/cloudabi_base.rs rename to compiler/rustc_target/src/spec/cloudabi_base.rs diff --git a/src/librustc_target/spec/crt_objects.rs b/compiler/rustc_target/src/spec/crt_objects.rs similarity index 100% rename from src/librustc_target/spec/crt_objects.rs rename to compiler/rustc_target/src/spec/crt_objects.rs diff --git a/src/librustc_target/spec/dragonfly_base.rs b/compiler/rustc_target/src/spec/dragonfly_base.rs similarity index 100% rename from src/librustc_target/spec/dragonfly_base.rs rename to compiler/rustc_target/src/spec/dragonfly_base.rs diff --git a/src/librustc_target/spec/freebsd_base.rs b/compiler/rustc_target/src/spec/freebsd_base.rs similarity index 100% rename from src/librustc_target/spec/freebsd_base.rs rename to compiler/rustc_target/src/spec/freebsd_base.rs diff --git a/src/librustc_target/spec/fuchsia_base.rs b/compiler/rustc_target/src/spec/fuchsia_base.rs similarity index 100% rename from src/librustc_target/spec/fuchsia_base.rs rename to compiler/rustc_target/src/spec/fuchsia_base.rs diff --git a/src/librustc_target/spec/haiku_base.rs b/compiler/rustc_target/src/spec/haiku_base.rs similarity index 100% rename from src/librustc_target/spec/haiku_base.rs rename to compiler/rustc_target/src/spec/haiku_base.rs diff --git a/src/librustc_target/spec/hermit_base.rs b/compiler/rustc_target/src/spec/hermit_base.rs similarity index 88% rename from src/librustc_target/spec/hermit_base.rs rename to compiler/rustc_target/src/spec/hermit_base.rs index 18fb2aa3d5..e063c94cf2 100644 --- a/src/librustc_target/spec/hermit_base.rs +++ b/compiler/rustc_target/src/spec/hermit_base.rs @@ -16,7 +16,8 @@ pub fn opts() -> TargetOptions { pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, - relocation_model: RelocModel::Static, + static_position_independent_executables: true, + relocation_model: RelocModel::Pic, target_family: None, tls_model: TlsModel::InitialExec, ..Default::default() diff --git a/src/librustc_target/spec/hermit_kernel_base.rs b/compiler/rustc_target/src/spec/hermit_kernel_base.rs similarity index 88% rename from src/librustc_target/spec/hermit_kernel_base.rs rename to compiler/rustc_target/src/spec/hermit_kernel_base.rs index 7f2dada714..01b9f75637 100644 --- a/src/librustc_target/spec/hermit_kernel_base.rs +++ b/compiler/rustc_target/src/spec/hermit_kernel_base.rs @@ -17,7 +17,8 @@ pub fn opts() -> TargetOptions { pre_link_args, panic_strategy: PanicStrategy::Abort, position_independent_executables: true, - relocation_model: RelocModel::Static, + static_position_independent_executables: true, + relocation_model: RelocModel::Pic, target_family: None, tls_model: TlsModel::InitialExec, ..Default::default() diff --git a/src/librustc_target/spec/hexagon_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/hexagon_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/hexagon_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/i386_apple_ios.rs b/compiler/rustc_target/src/spec/i386_apple_ios.rs similarity index 88% rename from src/librustc_target/spec/i386_apple_ios.rs rename to compiler/rustc_target/src/spec/i386_apple_ios.rs index a121d49769..6cb209ab1c 100644 --- a/src/librustc_target/spec/i386_apple_ios.rs +++ b/compiler/rustc_target/src/spec/i386_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::I386, AppleOS::iOS)?; + let base = opts(Arch::I386); Ok(Target { llvm_target: "i386-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/i586_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/i586_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/i586_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/i586_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/i586_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/i586_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/i586_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/i586_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/i586_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/i686_apple_darwin.rs b/compiler/rustc_target/src/spec/i686_apple_darwin.rs similarity index 100% rename from src/librustc_target/spec/i686_apple_darwin.rs rename to compiler/rustc_target/src/spec/i686_apple_darwin.rs diff --git a/src/librustc_target/spec/i686_linux_android.rs b/compiler/rustc_target/src/spec/i686_linux_android.rs similarity index 100% rename from src/librustc_target/spec/i686_linux_android.rs rename to compiler/rustc_target/src/spec/i686_linux_android.rs diff --git a/src/librustc_target/spec/i686_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/i686_pc_windows_gnu.rs rename to compiler/rustc_target/src/spec/i686_pc_windows_gnu.rs diff --git a/src/librustc_target/spec/i686_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/i686_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/i686_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/i686_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_cloudabi.rs rename to compiler/rustc_target/src/spec/i686_unknown_cloudabi.rs diff --git a/src/librustc_target/spec/i686_unknown_freebsd.rs b/compiler/rustc_target/src/spec/i686_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/i686_unknown_freebsd.rs diff --git a/src/librustc_target/spec/i686_unknown_haiku.rs b/compiler/rustc_target/src/spec/i686_unknown_haiku.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_haiku.rs rename to compiler/rustc_target/src/spec/i686_unknown_haiku.rs diff --git a/src/librustc_target/spec/i686_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/i686_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/i686_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/i686_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/i686_unknown_netbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/i686_unknown_netbsd.rs diff --git a/src/librustc_target/spec/i686_unknown_openbsd.rs b/compiler/rustc_target/src/spec/i686_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/i686_unknown_openbsd.rs diff --git a/src/librustc_target/spec/i686_unknown_uefi.rs b/compiler/rustc_target/src/spec/i686_unknown_uefi.rs similarity index 100% rename from src/librustc_target/spec/i686_unknown_uefi.rs rename to compiler/rustc_target/src/spec/i686_unknown_uefi.rs diff --git a/src/librustc_target/spec/i686_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/i686_uwp_windows_gnu.rs rename to compiler/rustc_target/src/spec/i686_uwp_windows_gnu.rs diff --git a/src/librustc_target/spec/i686_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/i686_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/i686_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/i686_wrs_vxworks.rs b/compiler/rustc_target/src/spec/i686_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/i686_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/i686_wrs_vxworks.rs diff --git a/src/librustc_target/spec/illumos_base.rs b/compiler/rustc_target/src/spec/illumos_base.rs similarity index 100% rename from src/librustc_target/spec/illumos_base.rs rename to compiler/rustc_target/src/spec/illumos_base.rs diff --git a/src/librustc_target/spec/l4re_base.rs b/compiler/rustc_target/src/spec/l4re_base.rs similarity index 100% rename from src/librustc_target/spec/l4re_base.rs rename to compiler/rustc_target/src/spec/l4re_base.rs diff --git a/src/librustc_target/spec/linux_base.rs b/compiler/rustc_target/src/spec/linux_base.rs similarity index 100% rename from src/librustc_target/spec/linux_base.rs rename to compiler/rustc_target/src/spec/linux_base.rs diff --git a/src/librustc_target/spec/linux_kernel_base.rs b/compiler/rustc_target/src/spec/linux_kernel_base.rs similarity index 100% rename from src/librustc_target/spec/linux_kernel_base.rs rename to compiler/rustc_target/src/spec/linux_kernel_base.rs diff --git a/src/librustc_target/spec/linux_musl_base.rs b/compiler/rustc_target/src/spec/linux_musl_base.rs similarity index 100% rename from src/librustc_target/spec/linux_musl_base.rs rename to compiler/rustc_target/src/spec/linux_musl_base.rs diff --git a/src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mips64_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mips64_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64_unknown_linux_muslabi64.rs rename to compiler/rustc_target/src/spec/mips64_unknown_linux_muslabi64.rs diff --git a/src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64el_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mips64el_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mips64el_unknown_linux_muslabi64.rs b/compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs similarity index 100% rename from src/librustc_target/spec/mips64el_unknown_linux_muslabi64.rs rename to compiler/rustc_target/src/spec/mips64el_unknown_linux_muslabi64.rs diff --git a/src/librustc_target/spec/mips_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mips_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mips_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mips_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/mips_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/mips_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/mips_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs similarity index 100% rename from src/librustc_target/spec/mips_unknown_linux_uclibc.rs rename to compiler/rustc_target/src/spec/mips_unknown_linux_uclibc.rs diff --git a/src/librustc_target/spec/mipsel_sony_psp.rs b/compiler/rustc_target/src/spec/mipsel_sony_psp.rs similarity index 100% rename from src/librustc_target/spec/mipsel_sony_psp.rs rename to compiler/rustc_target/src/spec/mipsel_sony_psp.rs diff --git a/src/librustc_target/spec/mipsel_sony_psp_linker_script.ld b/compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld similarity index 100% rename from src/librustc_target/spec/mipsel_sony_psp_linker_script.ld rename to compiler/rustc_target/src/spec/mipsel_sony_psp_linker_script.ld diff --git a/src/librustc_target/spec/mipsel_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mipsel_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mipsel_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mipsel_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/mipsel_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/mipsel_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs b/compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs similarity index 100% rename from src/librustc_target/spec/mipsel_unknown_linux_uclibc.rs rename to compiler/rustc_target/src/spec/mipsel_unknown_linux_uclibc.rs diff --git a/src/librustc_target/spec/mipsisa32r6_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mipsisa32r6_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mipsisa32r6_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mipsisa32r6el_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/mipsisa32r6el_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/mipsisa32r6el_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/mipsisa64r6_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mipsisa64r6_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mipsisa64r6_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs b/compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs similarity index 100% rename from src/librustc_target/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs rename to compiler/rustc_target/src/spec/mipsisa64r6el_unknown_linux_gnuabi64.rs diff --git a/src/librustc_target/spec/mod.rs b/compiler/rustc_target/src/spec/mod.rs similarity index 99% rename from src/librustc_target/spec/mod.rs rename to compiler/rustc_target/src/spec/mod.rs index fa29ff3f8d..f1e8330425 100644 --- a/src/librustc_target/spec/mod.rs +++ b/compiler/rustc_target/src/spec/mod.rs @@ -51,10 +51,10 @@ mod android_base; mod apple_base; mod apple_sdk_base; mod arm_base; +mod avr_gnu_base; mod cloudabi_base; mod dragonfly_base; mod freebsd_base; -mod freestanding_base; mod fuchsia_base; mod haiku_base; mod hermit_base; @@ -581,7 +581,7 @@ supported_targets! { ("aarch64-fuchsia", aarch64_fuchsia), ("x86_64-fuchsia", x86_64_fuchsia), - ("avr-unknown-unknown", avr_unknown_unknown), + ("avr-unknown-gnu-atmega328", avr_unknown_gnu_atmega328), ("x86_64-unknown-l4re-uclibc", x86_64_unknown_l4re_uclibc), @@ -654,6 +654,7 @@ supported_targets! { ("riscv32i-unknown-none-elf", riscv32i_unknown_none_elf), ("riscv32imc-unknown-none-elf", riscv32imc_unknown_none_elf), ("riscv32imac-unknown-none-elf", riscv32imac_unknown_none_elf), + ("riscv32gc-unknown-linux-gnu", riscv32gc_unknown_linux_gnu), ("riscv64imac-unknown-none-elf", riscv64imac_unknown_none_elf), ("riscv64gc-unknown-none-elf", riscv64gc_unknown_none_elf), ("riscv64gc-unknown-linux-gnu", riscv64gc_unknown_linux_gnu), diff --git a/src/librustc_target/spec/msp430_none_elf.rs b/compiler/rustc_target/src/spec/msp430_none_elf.rs similarity index 100% rename from src/librustc_target/spec/msp430_none_elf.rs rename to compiler/rustc_target/src/spec/msp430_none_elf.rs diff --git a/src/librustc_target/spec/msvc_base.rs b/compiler/rustc_target/src/spec/msvc_base.rs similarity index 100% rename from src/librustc_target/spec/msvc_base.rs rename to compiler/rustc_target/src/spec/msvc_base.rs diff --git a/src/librustc_target/spec/netbsd_base.rs b/compiler/rustc_target/src/spec/netbsd_base.rs similarity index 100% rename from src/librustc_target/spec/netbsd_base.rs rename to compiler/rustc_target/src/spec/netbsd_base.rs diff --git a/src/librustc_target/spec/nvptx64_nvidia_cuda.rs b/compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs similarity index 100% rename from src/librustc_target/spec/nvptx64_nvidia_cuda.rs rename to compiler/rustc_target/src/spec/nvptx64_nvidia_cuda.rs diff --git a/src/librustc_target/spec/openbsd_base.rs b/compiler/rustc_target/src/spec/openbsd_base.rs similarity index 100% rename from src/librustc_target/spec/openbsd_base.rs rename to compiler/rustc_target/src/spec/openbsd_base.rs diff --git a/src/librustc_target/spec/powerpc64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/powerpc64_unknown_freebsd.rs diff --git a/src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/powerpc64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/powerpc64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/powerpc64_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/powerpc64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/powerpc64_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/powerpc64_wrs_vxworks.rs diff --git a/src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/powerpc64le_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/powerpc64le_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/powerpc64le_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/powerpc64le_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/powerpc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_linux_gnuspe.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_linux_gnuspe.rs diff --git a/src/librustc_target/spec/powerpc_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/powerpc_unknown_netbsd.rs b/compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/powerpc_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/powerpc_unknown_netbsd.rs diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/powerpc_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/powerpc_wrs_vxworks.rs diff --git a/src/librustc_target/spec/powerpc_wrs_vxworks_spe.rs b/compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs similarity index 100% rename from src/librustc_target/spec/powerpc_wrs_vxworks_spe.rs rename to compiler/rustc_target/src/spec/powerpc_wrs_vxworks_spe.rs diff --git a/src/librustc_target/spec/redox_base.rs b/compiler/rustc_target/src/spec/redox_base.rs similarity index 100% rename from src/librustc_target/spec/redox_base.rs rename to compiler/rustc_target/src/spec/redox_base.rs diff --git a/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs new file mode 100644 index 0000000000..28710c6017 --- /dev/null +++ b/compiler/rustc_target/src/spec/riscv32gc_unknown_linux_gnu.rs @@ -0,0 +1,25 @@ +use crate::spec::{CodeModel, LinkerFlavor, Target, TargetOptions, TargetResult}; + +pub fn target() -> TargetResult { + Ok(Target { + llvm_target: "riscv32-unknown-linux-gnu".to_string(), + target_endian: "little".to_string(), + target_pointer_width: "32".to_string(), + target_c_int_width: "32".to_string(), + target_env: "gnu".to_string(), + data_layout: "e-m:e-p:32:32-i64:64-n32-S128".to_string(), + arch: "riscv32".to_string(), + target_os: "linux".to_string(), + target_vendor: "unknown".to_string(), + linker_flavor: LinkerFlavor::Gcc, + options: TargetOptions { + unsupported_abis: super::riscv_base::unsupported_abis(), + code_model: Some(CodeModel::Medium), + cpu: "generic-rv32".to_string(), + features: "+m,+a,+f,+d,+c".to_string(), + llvm_abiname: "ilp32d".to_string(), + max_atomic_width: Some(32), + ..super::linux_base::opts() + }, + }) +} diff --git a/src/librustc_target/spec/riscv32i_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv32i_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv32i_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv32imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv32imac_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv32imac_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv32imc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv32imc_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv32imc_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/riscv64gc_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/riscv64gc_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/riscv64gc_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv64gc_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv64gc_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv64imac_unknown_none_elf.rs b/compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs similarity index 100% rename from src/librustc_target/spec/riscv64imac_unknown_none_elf.rs rename to compiler/rustc_target/src/spec/riscv64imac_unknown_none_elf.rs diff --git a/src/librustc_target/spec/riscv_base.rs b/compiler/rustc_target/src/spec/riscv_base.rs similarity index 100% rename from src/librustc_target/spec/riscv_base.rs rename to compiler/rustc_target/src/spec/riscv_base.rs diff --git a/src/librustc_target/spec/s390x_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/s390x_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/s390x_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/solaris_base.rs b/compiler/rustc_target/src/spec/solaris_base.rs similarity index 100% rename from src/librustc_target/spec/solaris_base.rs rename to compiler/rustc_target/src/spec/solaris_base.rs diff --git a/src/librustc_target/spec/sparc64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/sparc64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/sparc64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/sparc64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/sparc64_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/sparc64_unknown_netbsd.rs diff --git a/src/librustc_target/spec/sparc64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/sparc64_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/sparc64_unknown_openbsd.rs diff --git a/src/librustc_target/spec/sparc_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/sparc_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/sparc_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/sparcv9_sun_solaris.rs b/compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs similarity index 100% rename from src/librustc_target/spec/sparcv9_sun_solaris.rs rename to compiler/rustc_target/src/spec/sparcv9_sun_solaris.rs diff --git a/src/librustc_target/spec/tests/tests_impl.rs b/compiler/rustc_target/src/spec/tests/tests_impl.rs similarity index 100% rename from src/librustc_target/spec/tests/tests_impl.rs rename to compiler/rustc_target/src/spec/tests/tests_impl.rs diff --git a/src/librustc_target/spec/thumb_base.rs b/compiler/rustc_target/src/spec/thumb_base.rs similarity index 100% rename from src/librustc_target/spec/thumb_base.rs rename to compiler/rustc_target/src/spec/thumb_base.rs diff --git a/src/librustc_target/spec/thumbv4t_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv4t_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv4t_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv6m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv6m_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv6m_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/thumbv7a_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/thumbv7a_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/thumbv7a_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/thumbv7a_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/thumbv7em_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv7em_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv7em_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv7em_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv7em_none_eabihf.rs rename to compiler/rustc_target/src/spec/thumbv7em_none_eabihf.rs diff --git a/src/librustc_target/spec/thumbv7m_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv7m_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv7m_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv7neon_linux_androideabi.rs b/compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv7neon_linux_androideabi.rs rename to compiler/rustc_target/src/spec/thumbv7neon_linux_androideabi.rs diff --git a/src/librustc_target/spec/thumbv7neon_unknown_linux_gnueabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv7neon_unknown_linux_gnueabihf.rs rename to compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_gnueabihf.rs diff --git a/src/librustc_target/spec/thumbv7neon_unknown_linux_musleabihf.rs b/compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv7neon_unknown_linux_musleabihf.rs rename to compiler/rustc_target/src/spec/thumbv7neon_unknown_linux_musleabihf.rs diff --git a/src/librustc_target/spec/thumbv8m_base_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv8m_base_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv8m_base_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv8m_main_none_eabi.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs similarity index 100% rename from src/librustc_target/spec/thumbv8m_main_none_eabi.rs rename to compiler/rustc_target/src/spec/thumbv8m_main_none_eabi.rs diff --git a/src/librustc_target/spec/thumbv8m_main_none_eabihf.rs b/compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs similarity index 100% rename from src/librustc_target/spec/thumbv8m_main_none_eabihf.rs rename to compiler/rustc_target/src/spec/thumbv8m_main_none_eabihf.rs diff --git a/src/librustc_target/spec/uefi_msvc_base.rs b/compiler/rustc_target/src/spec/uefi_msvc_base.rs similarity index 100% rename from src/librustc_target/spec/uefi_msvc_base.rs rename to compiler/rustc_target/src/spec/uefi_msvc_base.rs diff --git a/src/librustc_target/spec/vxworks_base.rs b/compiler/rustc_target/src/spec/vxworks_base.rs similarity index 100% rename from src/librustc_target/spec/vxworks_base.rs rename to compiler/rustc_target/src/spec/vxworks_base.rs diff --git a/src/librustc_target/spec/wasm32_base.rs b/compiler/rustc_target/src/spec/wasm32_base.rs similarity index 99% rename from src/librustc_target/spec/wasm32_base.rs rename to compiler/rustc_target/src/spec/wasm32_base.rs index 62fc8f0618..a7957d84cb 100644 --- a/src/librustc_target/spec/wasm32_base.rs +++ b/compiler/rustc_target/src/spec/wasm32_base.rs @@ -83,6 +83,7 @@ pub fn options() -> TargetOptions { dll_prefix: String::new(), dll_suffix: ".wasm".to_string(), linker_is_gnu: false, + eh_frame_header: false, max_atomic_width: Some(64), diff --git a/src/librustc_target/spec/wasm32_unknown_emscripten.rs b/compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs similarity index 100% rename from src/librustc_target/spec/wasm32_unknown_emscripten.rs rename to compiler/rustc_target/src/spec/wasm32_unknown_emscripten.rs diff --git a/src/librustc_target/spec/wasm32_unknown_unknown.rs b/compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs similarity index 100% rename from src/librustc_target/spec/wasm32_unknown_unknown.rs rename to compiler/rustc_target/src/spec/wasm32_unknown_unknown.rs diff --git a/src/librustc_target/spec/wasm32_wasi.rs b/compiler/rustc_target/src/spec/wasm32_wasi.rs similarity index 98% rename from src/librustc_target/spec/wasm32_wasi.rs rename to compiler/rustc_target/src/spec/wasm32_wasi.rs index 0bba7bdd47..351167105e 100644 --- a/src/librustc_target/spec/wasm32_wasi.rs +++ b/compiler/rustc_target/src/spec/wasm32_wasi.rs @@ -30,7 +30,7 @@ //! ## No interop with C required //! //! By default the `crt-static` target feature is enabled, and when enabled -//! this means that the the bundled version of `libc.a` found in `liblibc.rlib` +//! this means that the bundled version of `libc.a` found in `liblibc.rlib` //! is used. This isn't intended really for interoperation with a C because it //! may be the case that Rust's bundled C library is incompatible with a //! foreign-compiled C library. In this use case, though, we use `rust-lld` and diff --git a/src/librustc_target/spec/windows_gnu_base.rs b/compiler/rustc_target/src/spec/windows_gnu_base.rs similarity index 94% rename from src/librustc_target/spec/windows_gnu_base.rs rename to compiler/rustc_target/src/spec/windows_gnu_base.rs index a864918655..0234ff55f0 100644 --- a/src/librustc_target/spec/windows_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_gnu_base.rs @@ -23,6 +23,7 @@ pub fn opts() -> TargetOptions { "-lmsvcrt".to_string(), "-lmingwex".to_string(), "-lmingw32".to_string(), + "-lgcc".to_string(), // alas, mingw* libraries above depend on libgcc // mingw's msvcrt is a weird hybrid import library and static library. // And it seems that the linker fails to use import symbols from msvcrt // that are required from functions in msvcrt in certain cases. For example @@ -41,8 +42,6 @@ pub fn opts() -> TargetOptions { // the shared libgcc_s-dw2-1.dll. This is required to support // unwinding across DLL boundaries. "-lgcc_s".to_string(), - "-lgcc".to_string(), - "-lkernel32".to_string(), ]; late_link_args_dynamic.insert(LinkerFlavor::Gcc, dynamic_unwind_libs.clone()); late_link_args_dynamic.insert(LinkerFlavor::Lld(LldFlavor::Ld), dynamic_unwind_libs); @@ -54,10 +53,6 @@ pub fn opts() -> TargetOptions { // boundaries when unwinding across FFI boundaries. "-lgcc_eh".to_string(), "-l:libpthread.a".to_string(), - "-lgcc".to_string(), - // libpthread depends on libmsvcrt, so we need to link it *again*. - "-lmsvcrt".to_string(), - "-lkernel32".to_string(), ]; late_link_args_static.insert(LinkerFlavor::Gcc, static_unwind_libs.clone()); late_link_args_static.insert(LinkerFlavor::Lld(LldFlavor::Ld), static_unwind_libs); diff --git a/src/librustc_target/spec/windows_msvc_base.rs b/compiler/rustc_target/src/spec/windows_msvc_base.rs similarity index 100% rename from src/librustc_target/spec/windows_msvc_base.rs rename to compiler/rustc_target/src/spec/windows_msvc_base.rs diff --git a/src/librustc_target/spec/windows_uwp_gnu_base.rs b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs similarity index 98% rename from src/librustc_target/spec/windows_uwp_gnu_base.rs rename to compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs index fd55a0fc6a..fcb2af0005 100644 --- a/src/librustc_target/spec/windows_uwp_gnu_base.rs +++ b/compiler/rustc_target/src/spec/windows_uwp_gnu_base.rs @@ -22,7 +22,7 @@ pub fn opts() -> TargetOptions { "-lmingw32".to_string(), ]; late_link_args.insert(LinkerFlavor::Gcc, mingw_libs.clone()); - late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs.clone()); + late_link_args.insert(LinkerFlavor::Lld(LldFlavor::Ld), mingw_libs); TargetOptions { executables: false, diff --git a/src/librustc_target/spec/windows_uwp_msvc_base.rs b/compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs similarity index 100% rename from src/librustc_target/spec/windows_uwp_msvc_base.rs rename to compiler/rustc_target/src/spec/windows_uwp_msvc_base.rs diff --git a/src/librustc_target/spec/x86_64_apple_darwin.rs b/compiler/rustc_target/src/spec/x86_64_apple_darwin.rs similarity index 100% rename from src/librustc_target/spec/x86_64_apple_darwin.rs rename to compiler/rustc_target/src/spec/x86_64_apple_darwin.rs diff --git a/src/librustc_target/spec/x86_64_apple_ios.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs similarity index 87% rename from src/librustc_target/spec/x86_64_apple_ios.rs rename to compiler/rustc_target/src/spec/x86_64_apple_ios.rs index cfcf856836..fd3e4e2f57 100644 --- a/src/librustc_target/spec/x86_64_apple_ios.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::X86_64, AppleOS::iOS)?; + let base = opts(Arch::X86_64); Ok(Target { llvm_target: "x86_64-apple-ios".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/x86_64_apple_ios_macabi.rs b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs similarity index 87% rename from src/librustc_target/spec/x86_64_apple_ios_macabi.rs rename to compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs index c42d091172..4cfbd9eba0 100644 --- a/src/librustc_target/spec/x86_64_apple_ios_macabi.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_ios_macabi.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::X86_64_macabi, AppleOS::iOS)?; + let base = opts(Arch::X86_64_macabi); Ok(Target { llvm_target: "x86_64-apple-ios13.0-macabi".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/x86_64_apple_tvos.rs b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs similarity index 87% rename from src/librustc_target/spec/x86_64_apple_tvos.rs rename to compiler/rustc_target/src/spec/x86_64_apple_tvos.rs index a56062c0b2..664a3ed881 100644 --- a/src/librustc_target/spec/x86_64_apple_tvos.rs +++ b/compiler/rustc_target/src/spec/x86_64_apple_tvos.rs @@ -1,8 +1,8 @@ -use super::apple_sdk_base::{opts, AppleOS, Arch}; +use super::apple_sdk_base::{opts, Arch}; use crate::spec::{LinkerFlavor, Target, TargetOptions, TargetResult}; pub fn target() -> TargetResult { - let base = opts(Arch::X86_64, AppleOS::iOS)?; + let base = opts(Arch::X86_64); Ok(Target { llvm_target: "x86_64-apple-tvos".to_string(), target_endian: "little".to_string(), diff --git a/src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs b/compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs similarity index 100% rename from src/librustc_target/spec/x86_64_fortanix_unknown_sgx.rs rename to compiler/rustc_target/src/spec/x86_64_fortanix_unknown_sgx.rs diff --git a/src/librustc_target/spec/x86_64_fuchsia.rs b/compiler/rustc_target/src/spec/x86_64_fuchsia.rs similarity index 100% rename from src/librustc_target/spec/x86_64_fuchsia.rs rename to compiler/rustc_target/src/spec/x86_64_fuchsia.rs diff --git a/src/librustc_target/spec/x86_64_linux_android.rs b/compiler/rustc_target/src/spec/x86_64_linux_android.rs similarity index 100% rename from src/librustc_target/spec/x86_64_linux_android.rs rename to compiler/rustc_target/src/spec/x86_64_linux_android.rs diff --git a/src/librustc_target/spec/x86_64_linux_kernel.rs b/compiler/rustc_target/src/spec/x86_64_linux_kernel.rs similarity index 100% rename from src/librustc_target/spec/x86_64_linux_kernel.rs rename to compiler/rustc_target/src/spec/x86_64_linux_kernel.rs diff --git a/src/librustc_target/spec/x86_64_pc_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/x86_64_pc_windows_gnu.rs rename to compiler/rustc_target/src/spec/x86_64_pc_windows_gnu.rs diff --git a/src/librustc_target/spec/x86_64_pc_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/x86_64_pc_windows_msvc.rs rename to compiler/rustc_target/src/spec/x86_64_pc_windows_msvc.rs diff --git a/src/librustc_target/spec/x86_64_rumprun_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_rumprun_netbsd.rs rename to compiler/rustc_target/src/spec/x86_64_rumprun_netbsd.rs diff --git a/src/librustc_target/spec/x86_64_sun_solaris.rs b/compiler/rustc_target/src/spec/x86_64_sun_solaris.rs similarity index 100% rename from src/librustc_target/spec/x86_64_sun_solaris.rs rename to compiler/rustc_target/src/spec/x86_64_sun_solaris.rs diff --git a/src/librustc_target/spec/x86_64_unknown_cloudabi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_cloudabi.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_cloudabi.rs diff --git a/src/librustc_target/spec/x86_64_unknown_dragonfly.rs b/compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_dragonfly.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_dragonfly.rs diff --git a/src/librustc_target/spec/x86_64_unknown_freebsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_freebsd.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_freebsd.rs diff --git a/src/librustc_target/spec/x86_64_unknown_haiku.rs b/compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_haiku.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_haiku.rs diff --git a/src/librustc_target/spec/x86_64_unknown_hermit.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_hermit.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_hermit.rs diff --git a/src/librustc_target/spec/x86_64_unknown_hermit_kernel.rs b/compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_hermit_kernel.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_hermit_kernel.rs diff --git a/src/librustc_target/spec/x86_64_unknown_illumos.rs b/compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_illumos.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_illumos.rs diff --git a/src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs b/compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_l4re_uclibc.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_l4re_uclibc.rs diff --git a/src/librustc_target/spec/x86_64_unknown_linux_gnu.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_linux_gnu.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_linux_gnu.rs diff --git a/src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_linux_gnux32.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_linux_gnux32.rs diff --git a/src/librustc_target/spec/x86_64_unknown_linux_musl.rs b/compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_linux_musl.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_linux_musl.rs diff --git a/src/librustc_target/spec/x86_64_unknown_netbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_netbsd.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_netbsd.rs diff --git a/src/librustc_target/spec/x86_64_unknown_openbsd.rs b/compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_openbsd.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_openbsd.rs diff --git a/src/librustc_target/spec/x86_64_unknown_redox.rs b/compiler/rustc_target/src/spec/x86_64_unknown_redox.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_redox.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_redox.rs diff --git a/src/librustc_target/spec/x86_64_unknown_uefi.rs b/compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs similarity index 100% rename from src/librustc_target/spec/x86_64_unknown_uefi.rs rename to compiler/rustc_target/src/spec/x86_64_unknown_uefi.rs diff --git a/src/librustc_target/spec/x86_64_uwp_windows_gnu.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs similarity index 100% rename from src/librustc_target/spec/x86_64_uwp_windows_gnu.rs rename to compiler/rustc_target/src/spec/x86_64_uwp_windows_gnu.rs diff --git a/src/librustc_target/spec/x86_64_uwp_windows_msvc.rs b/compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs similarity index 100% rename from src/librustc_target/spec/x86_64_uwp_windows_msvc.rs rename to compiler/rustc_target/src/spec/x86_64_uwp_windows_msvc.rs diff --git a/src/librustc_target/spec/x86_64_wrs_vxworks.rs b/compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs similarity index 100% rename from src/librustc_target/spec/x86_64_wrs_vxworks.rs rename to compiler/rustc_target/src/spec/x86_64_wrs_vxworks.rs diff --git a/compiler/rustc_trait_selection/Cargo.toml b/compiler/rustc_trait_selection/Cargo.toml new file mode 100644 index 0000000000..a72c172918 --- /dev/null +++ b/compiler/rustc_trait_selection/Cargo.toml @@ -0,0 +1,25 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_trait_selection" +version = "0.0.0" +edition = "2018" + +[lib] +doctest = false + +[dependencies] +rustc_parse_format = { path = "../rustc_parse_format" } +tracing = "0.1" +rustc_attr = { path = "../rustc_attr" } +rustc_middle = { path = "../rustc_middle" } +rustc_ast = { path = "../rustc_ast" } +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_session = { path = "../rustc_session" } +rustc_span = { path = "../rustc_span" } +rustc_target = { path = "../rustc_target" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_trait_selection/autoderef.rs b/compiler/rustc_trait_selection/src/autoderef.rs similarity index 97% rename from src/librustc_trait_selection/autoderef.rs rename to compiler/rustc_trait_selection/src/autoderef.rs index 02eefe5622..b9c5123e49 100644 --- a/src/librustc_trait_selection/autoderef.rs +++ b/compiler/rustc_trait_selection/src/autoderef.rs @@ -27,6 +27,7 @@ pub struct Autoderef<'a, 'tcx> { // Meta infos: infcx: &'a InferCtxt<'a, 'tcx>, span: Span, + overloaded_span: Span, body_id: hir::HirId, param_env: ty::ParamEnv<'tcx>, @@ -98,10 +99,12 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { body_id: hir::HirId, span: Span, base_ty: Ty<'tcx>, + overloaded_span: Span, ) -> Autoderef<'a, 'tcx> { Autoderef { infcx, span, + overloaded_span, body_id, param_env, state: AutoderefSnapshot { @@ -190,6 +193,10 @@ impl<'a, 'tcx> Autoderef<'a, 'tcx> { self.span } + pub fn overloaded_span(&self) -> Span { + self.overloaded_span + } + pub fn reached_recursion_limit(&self) -> bool { self.state.reached_recursion_limit } diff --git a/src/librustc_trait_selection/infer.rs b/compiler/rustc_trait_selection/src/infer.rs similarity index 100% rename from src/librustc_trait_selection/infer.rs rename to compiler/rustc_trait_selection/src/infer.rs diff --git a/src/librustc_trait_selection/lib.rs b/compiler/rustc_trait_selection/src/lib.rs similarity index 86% rename from src/librustc_trait_selection/lib.rs rename to compiler/rustc_trait_selection/src/lib.rs index b5882df472..ddeab340f3 100644 --- a/src/librustc_trait_selection/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -10,10 +10,12 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] +#![feature(box_patterns)] #![feature(drain_filter)] #![feature(in_band_lifetimes)] +#![feature(never_type)] #![feature(crate_visibility_modifier)] #![feature(or_patterns)] #![recursion_limit = "512"] // For rustdoc diff --git a/src/librustc_trait_selection/opaque_types.rs b/compiler/rustc_trait_selection/src/opaque_types.rs similarity index 99% rename from src/librustc_trait_selection/opaque_types.rs rename to compiler/rustc_trait_selection/src/opaque_types.rs index 379c976df6..28697ec4e3 100644 --- a/src/librustc_trait_selection/opaque_types.rs +++ b/compiler/rustc_trait_selection/src/opaque_types.rs @@ -708,11 +708,11 @@ where fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { // We're only interested in types involving regions - if !ty.flags.intersects(ty::TypeFlags::HAS_FREE_REGIONS) { + if !ty.flags().intersects(ty::TypeFlags::HAS_FREE_REGIONS) { return false; // keep visiting } - match ty.kind { + match ty.kind() { ty::Closure(_, ref substs) => { // Skip lifetime parameters of the enclosing item(s) @@ -866,7 +866,7 @@ impl TypeFolder<'tcx> for ReverseMapper<'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match *ty.kind() { ty::Closure(def_id, substs) => { // I am a horrible monster and I pray for death. When // we encounter a closure here, it is always a closure @@ -1003,7 +1003,7 @@ impl<'a, 'tcx> Instantiator<'a, 'tcx> { ty_op: |ty| { if ty.references_error() { return tcx.ty_error(); - } else if let ty::Opaque(def_id, substs) = ty.kind { + } else if let ty::Opaque(def_id, substs) = ty.kind() { // Check that this is `impl Trait` type is // declared by `parent_def_id` -- i.e., one whose // value we are inferring. At present, this is @@ -1261,7 +1261,8 @@ crate fn required_region_bounds( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::RegionOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ref t, ref r)) => { // Search for a bound of the form `erased_self_ty // : 'a`, but be wary of something like `for<'a> diff --git a/src/librustc_trait_selection/traits/auto_trait.rs b/compiler/rustc_trait_selection/src/traits/auto_trait.rs similarity index 98% rename from src/librustc_trait_selection/traits/auto_trait.rs rename to compiler/rustc_trait_selection/src/traits/auto_trait.rs index fa3d024199..e40067202e 100644 --- a/src/librustc_trait_selection/traits/auto_trait.rs +++ b/compiler/rustc_trait_selection/src/traits/auto_trait.rs @@ -32,6 +32,7 @@ pub enum AutoTraitResult { NegativeImpl, } +#[allow(dead_code)] impl AutoTraitResult { fn is_auto(&self) -> bool { match *self { @@ -96,7 +97,7 @@ impl<'tcx> AutoTraitFinder<'tcx> { )); match result { - Ok(Some(ImplSource::ImplSourceUserDefined(_))) => { + Ok(Some(ImplSource::UserDefined(_))) => { debug!( "find_auto_trait_generics({:?}): \ manual impl found, bailing out", @@ -315,9 +316,8 @@ impl AutoTraitFinder<'tcx> { // If we see an explicit negative impl (e.g., `impl !Send for MyStruct`), // we immediately bail out, since it's impossible for us to continue. - if let ImplSource::ImplSourceUserDefined(ImplSourceUserDefinedData { - impl_def_id, - .. + if let ImplSource::UserDefined(ImplSourceUserDefinedData { + impl_def_id, .. }) = impl_source { // Blame 'tidy' for the weird bracket placement. @@ -373,14 +373,12 @@ impl AutoTraitFinder<'tcx> { computed_preds.clone().chain(user_computed_preds.iter().cloned()), ) .map(|o| o.predicate); - new_env = - ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal(), None); + new_env = ty::ParamEnv::new(tcx.mk_predicates(normalized_preds), param_env.reveal()); } let final_user_env = ty::ParamEnv::new( tcx.mk_predicates(user_computed_preds.into_iter()), user_env.reveal(), - None, ); debug!( "evaluate_nested_obligations(ty={:?}, trait_did={:?}): succeeded with '{:?}' \ @@ -598,7 +596,7 @@ impl AutoTraitFinder<'tcx> { } pub fn is_of_param(&self, ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Param(_) => true, ty::Projection(p) => self.is_of_param(p.self_ty()), _ => false, @@ -606,7 +604,7 @@ impl AutoTraitFinder<'tcx> { } fn is_self_referential_projection(&self, p: ty::PolyProjectionPredicate<'_>) -> bool { - match p.ty().skip_binder().kind { + match *p.ty().skip_binder().kind() { ty::Projection(proj) if proj == p.skip_binder().projection_ty => true, _ => false, } diff --git a/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs new file mode 100644 index 0000000000..adc8ae5908 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/chalk_fulfill.rs @@ -0,0 +1,143 @@ +//! Defines a Chalk-based `TraitEngine` + +use crate::infer::canonical::OriginalQueryValues; +use crate::infer::InferCtxt; +use crate::traits::query::NoSolution; +use crate::traits::{ + ChalkEnvironmentAndGoal, FulfillmentError, FulfillmentErrorCode, ObligationCause, + PredicateObligation, SelectionError, TraitEngine, +}; +use rustc_data_structures::fx::FxIndexSet; +use rustc_middle::ty::{self, Ty}; + +pub struct FulfillmentContext<'tcx> { + obligations: FxIndexSet>, +} + +impl FulfillmentContext<'tcx> { + crate fn new() -> Self { + FulfillmentContext { obligations: FxIndexSet::default() } + } +} + +impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { + fn normalize_projection_type( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + _param_env: ty::ParamEnv<'tcx>, + projection_ty: ty::ProjectionTy<'tcx>, + _cause: ObligationCause<'tcx>, + ) -> Ty<'tcx> { + infcx.tcx.mk_ty(ty::Projection(projection_ty)) + } + + fn register_predicate_obligation( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + obligation: PredicateObligation<'tcx>, + ) { + assert!(!infcx.is_in_snapshot()); + let obligation = infcx.resolve_vars_if_possible(&obligation); + + self.obligations.insert(obligation); + } + + fn select_all_or_error( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec>> { + self.select_where_possible(infcx)?; + + if self.obligations.is_empty() { + Ok(()) + } else { + let errors = self + .obligations + .iter() + .map(|obligation| FulfillmentError { + obligation: obligation.clone(), + code: FulfillmentErrorCode::CodeAmbiguity, + points_at_arg_span: false, + }) + .collect(); + Err(errors) + } + } + + fn select_where_possible( + &mut self, + infcx: &InferCtxt<'_, 'tcx>, + ) -> Result<(), Vec>> { + assert!(!infcx.is_in_snapshot()); + + let mut errors = Vec::new(); + let mut next_round = FxIndexSet::default(); + let mut making_progress; + + loop { + making_progress = false; + + // We iterate over all obligations, and record if we are able + // to unambiguously prove at least one obligation. + for obligation in self.obligations.drain(..) { + let obligation = infcx.resolve_vars_if_possible(&obligation); + let environment = obligation.param_env.caller_bounds(); + let goal = ChalkEnvironmentAndGoal { environment, goal: obligation.predicate }; + let mut orig_values = OriginalQueryValues::default(); + let canonical_goal = infcx.canonicalize_query(&goal, &mut orig_values); + + match infcx.tcx.evaluate_goal(canonical_goal) { + Ok(response) => { + if response.is_proven() { + making_progress = true; + + match infcx.instantiate_query_response_and_region_obligations( + &obligation.cause, + obligation.param_env, + &orig_values, + &response, + ) { + Ok(infer_ok) => next_round.extend( + infer_ok.obligations.into_iter().map(|obligation| { + assert!(!infcx.is_in_snapshot()); + infcx.resolve_vars_if_possible(&obligation) + }), + ), + + Err(_err) => errors.push(FulfillmentError { + obligation, + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + points_at_arg_span: false, + }), + } + } else { + // Ambiguous: retry at next round. + next_round.insert(obligation); + } + } + + Err(NoSolution) => errors.push(FulfillmentError { + obligation, + code: FulfillmentErrorCode::CodeSelectionError( + SelectionError::Unimplemented, + ), + points_at_arg_span: false, + }), + } + } + next_round = std::mem::replace(&mut self.obligations, next_round); + + if !making_progress { + break; + } + } + + if errors.is_empty() { Ok(()) } else { Err(errors) } + } + + fn pending_obligations(&self) -> Vec> { + self.obligations.iter().cloned().collect() + } +} diff --git a/src/librustc_trait_selection/traits/codegen/mod.rs b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs similarity index 96% rename from src/librustc_trait_selection/traits/codegen/mod.rs rename to compiler/rustc_trait_selection/src/traits/codegen/mod.rs index dd7ea55cc1..6b1ed5f493 100644 --- a/src/librustc_trait_selection/traits/codegen/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/codegen/mod.rs @@ -118,7 +118,10 @@ where // contains unbound type parameters. It could be a slight // optimization to stop iterating early. if let Err(errors) = fulfill_cx.select_all_or_error(infcx) { - bug!("Encountered errors `{:?}` resolving bounds after type-checking", errors); + infcx.tcx.sess.delay_span_bug( + rustc_span::DUMMY_SP, + &format!("Encountered errors `{:?}` resolving bounds after type-checking", errors), + ); } let result = infcx.resolve_vars_if_possible(result); diff --git a/src/librustc_trait_selection/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs similarity index 99% rename from src/librustc_trait_selection/traits/coherence.rs rename to compiler/rustc_trait_selection/src/traits/coherence.rs index b06cf4411d..c53c65c00b 100644 --- a/src/librustc_trait_selection/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -182,7 +182,7 @@ fn overlap_within_probe( } if !skip_leak_check.is_yes() { - if let Err(_) = infcx.leak_check(true, snapshot) { + if infcx.leak_check(true, snapshot).is_err() { debug!("overlap: leak check failed"); return None; } @@ -412,7 +412,7 @@ fn orphan_check_trait_ref<'tcx>( if non_local_tys.is_empty() { debug!("orphan_check_trait_ref: ty_is_local `{:?}`", input_ty); return Ok(()); - } else if let ty::Param(_) = input_ty.kind { + } else if let ty::Param(_) = input_ty.kind() { debug!("orphan_check_trait_ref: uncovered ty: `{:?}`", input_ty); let local_type = trait_ref .substs @@ -467,7 +467,7 @@ fn fundamental_ty_inner_tys( tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, ) -> Option>> { - let (first_ty, rest_tys) = match ty.kind { + let (first_ty, rest_tys) = match *ty.kind() { ty::Ref(_, ty, _) => (ty, ty::subst::InternalSubsts::empty().types()), ty::Adt(def, substs) if def.is_fundamental() => { let mut types = substs.types(); @@ -504,7 +504,7 @@ fn def_id_is_local(def_id: DefId, in_crate: InCrate) -> bool { fn ty_is_local_constructor(ty: Ty<'_>, in_crate: InCrate) -> bool { debug!("ty_is_local_constructor({:?})", ty); - match ty.kind { + match *ty.kind() { ty::Bool | ty::Char | ty::Int(..) diff --git a/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs new file mode 100644 index 0000000000..3828cf4d30 --- /dev/null +++ b/compiler/rustc_trait_selection/src/traits/const_evaluatable.rs @@ -0,0 +1,593 @@ +//! Checking that constant values used in types can be successfully evaluated. +//! +//! For concrete constants, this is fairly simple as we can just try and evaluate it. +//! +//! When dealing with polymorphic constants, for example `std::mem::size_of::() - 1`, +//! 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 +//! 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}; +use rustc_middle::mir::interpret::ErrorHandled; +use rustc_middle::mir::{self, Rvalue, StatementKind, TerminatorKind}; +use rustc_middle::ty::subst::Subst; +use rustc_middle::ty::subst::SubstsRef; +use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; +use rustc_session::lint; +use rustc_span::def_id::{DefId, LocalDefId}; +use rustc_span::Span; + +use std::cmp; + +/// Check if a given constant can be evaluated. +pub fn is_const_evaluatable<'cx, 'tcx>( + infcx: &InferCtxt<'cx, 'tcx>, + def: ty::WithOptConstParam, + substs: SubstsRef<'tcx>, + param_env: ty::ParamEnv<'tcx>, + span: Span, +) -> Result<(), ErrorHandled> { + debug!("is_const_evaluatable({:?}, {:?})", def, substs); + if infcx.tcx.features().const_evaluatable_checked { + let tcx = infcx.tcx; + match AbstractConst::new(tcx, def, substs)? { + // We are looking at a generic abstract constant. + Some(ct) => { + for pred in param_env.caller_bounds() { + match pred.skip_binders() { + ty::PredicateAtom::ConstEvaluatable(b_def, b_substs) => { + debug!( + "is_const_evaluatable: caller_bound={:?}, {:?}", + b_def, b_substs + ); + if b_def == def && b_substs == substs { + debug!("is_const_evaluatable: caller_bound ~~> ok"); + return Ok(()); + } else if AbstractConst::new(tcx, b_def, b_substs)? + .map_or(false, |b_ct| try_unify(tcx, ct, b_ct)) + { + debug!("is_const_evaluatable: abstract_const ~~> ok"); + return Ok(()); + } + } + _ => {} // don't care + } + } + + // We were unable to unify the abstract constant with + // a constant found in the caller bounds, there are + // now three possible cases here. + // + // - The substs are concrete enough that we can simply + // try and evaluate the given constant. + // - The abstract const still references an inference + // variable, in this case we return `TooGeneric`. + // - The abstract const references a generic parameter, + // this means that we emit an error here. + #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] + enum FailureKind { + MentionsInfer, + MentionsParam, + Concrete, + } + let mut failure_kind = FailureKind::Concrete; + walk_abstract_const(tcx, ct, |node| match node { + Node::Leaf(leaf) => { + let leaf = leaf.subst(tcx, ct.substs); + if leaf.has_infer_types_or_consts() { + failure_kind = FailureKind::MentionsInfer; + } else if leaf.has_param_types_or_consts() { + failure_kind = cmp::min(failure_kind, FailureKind::MentionsParam); + } + } + Node::Binop(_, _, _) | Node::UnaryOp(_, _) | Node::FunctionCall(_, _) => (), + }); + + match failure_kind { + FailureKind::MentionsInfer => { + return Err(ErrorHandled::TooGeneric); + } + FailureKind::MentionsParam => { + // FIXME(const_evaluatable_checked): Better error message. + infcx + .tcx + .sess + .struct_span_err(span, "unconstrained generic constant") + .span_help( + tcx.def_span(def.did), + "consider adding a `where` bound for this expression", + ) + .emit(); + return Err(ErrorHandled::Reported(ErrorReported)); + } + FailureKind::Concrete => { + // Dealt with below by the same code which handles this + // without the feature gate. + } + } + } + None => { + // If we are dealing with a concrete constant, we can + // reuse the old code path and try to evaluate + // the constant. + } + } + } + + let future_compat_lint = || { + if let Some(local_def_id) = def.did.as_local() { + infcx.tcx.struct_span_lint_hir( + lint::builtin::CONST_EVALUATABLE_UNCHECKED, + infcx.tcx.hir().local_def_id_to_hir_id(local_def_id), + span, + |err| { + err.build("cannot use constants which depend on generic parameters in types") + .emit(); + }, + ); + } + }; + + // FIXME: We should only try to evaluate a given constant here if it is fully concrete + // as we don't want to allow things like `[u8; std::mem::size_of::<*mut T>()]`. + // + // We previously did not check this, so we only emit a future compat warning if + // const evaluation succeeds and the given constant is still polymorphic for now + // and hopefully soon change this to an error. + // + // See #74595 for more details about this. + let concrete = infcx.const_eval_resolve(param_env, def, substs, None, Some(span)); + + if concrete.is_ok() && substs.has_param_types_or_consts() { + match infcx.tcx.def_kind(def.did) { + DefKind::AnonConst => { + let mir_body = if let Some(def) = def.as_const_arg() { + infcx.tcx.optimized_mir_of_const_arg(def) + } else { + infcx.tcx.optimized_mir(def.did) + }; + + if mir_body.is_polymorphic { + future_compat_lint(); + } + } + _ => future_compat_lint(), + } + } + + debug!(?concrete, "is_const_evaluatable"); + match concrete { + Err(ErrorHandled::TooGeneric) if !substs.has_infer_types_or_consts() => { + // FIXME(const_evaluatable_checked): We really should move + // emitting this error message to fulfill instead. For + // now this is easier. + // + // This is not a problem without `const_evaluatable_checked` as + // all `ConstEvaluatable` predicates have to be fulfilled for compilation + // to succeed. + // + // @lcnr: We already emit an error for things like + // `fn test() -> [0 - N]` eagerly here, + // so until we fix this I don't really care. + + let mut err = infcx + .tcx + .sess + .struct_span_err(span, "constant expression depends on a generic parameter"); + // FIXME(const_generics): we should suggest to the user how they can resolve this + // issue. However, this is currently not actually possible + // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). + // + // Note that with `feature(const_evaluatable_checked)` this case should not + // be reachable. + err.note("this may fail depending on what value the parameter takes"); + err.emit(); + Err(ErrorHandled::Reported(ErrorReported)) + } + c => c.map(drop), + } +} + +/// A tree representing an anonymous constant. +/// +/// This is only able to represent a subset of `MIR`, +/// and should not leak any information about desugarings. +#[derive(Clone, Copy)] +pub struct AbstractConst<'tcx> { + // FIXME: Consider adding something like `IndexSlice` + // and use this here. + inner: &'tcx [Node<'tcx>], + substs: SubstsRef<'tcx>, +} + +impl AbstractConst<'tcx> { + pub fn new( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, + substs: SubstsRef<'tcx>, + ) -> Result>, ErrorReported> { + let inner = match (def.did.as_local(), def.const_param_did) { + (Some(did), Some(param_did)) => { + tcx.mir_abstract_const_of_const_arg((did, param_did))? + } + _ => tcx.mir_abstract_const(def.did)?, + }; + + Ok(inner.map(|inner| AbstractConst { inner, substs })) + } + + #[inline] + pub fn subtree(self, node: NodeId) -> AbstractConst<'tcx> { + AbstractConst { inner: &self.inner[..=node.index()], substs: self.substs } + } + + #[inline] + pub fn root(self) -> Node<'tcx> { + self.inner.last().copied().unwrap() + } +} + +struct AbstractConstBuilder<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + /// The current WIP node tree. + nodes: IndexVec>, + locals: IndexVec, + /// We only allow field accesses if they access + /// the result of a checked operation. + checked_op_locals: BitSet, +} + +impl<'a, 'tcx> AbstractConstBuilder<'a, 'tcx> { + fn error(&mut self, span: Option, 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) + .help("consider moving this anonymous constant into a `const` function") + .emit(); + + Err(ErrorReported) + } + + fn new( + tcx: TyCtxt<'tcx>, + body: &'a mir::Body<'tcx>, + ) -> 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); + } + + // 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")?; + } + + Ok(Some(builder)) + } + + 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 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) => Ok(self.nodes.push(Node::Leaf(ct.literal))), + } + } + + /// We do not allow all binary operations in abstract consts, so filter disallowed ones. + fn check_binop(op: mir::BinOp) -> bool { + use mir::BinOp::*; + match op { + Add | Sub | Mul | Div | Rem | BitXor | BitAnd | BitOr | Shl | Shr | Eq | Lt | Le + | Ne | Ge | Gt => true, + Offset => false, + } + } + + /// While we currently allow all unary operations, we still want to explicitly guard against + /// future changes here. + fn check_unop(op: mir::UnOp) -> bool { + use mir::UnOp::*; + match op { + Not | Neg => true, + } + } + + fn build_statement(&mut self, stmt: &mir::Statement<'tcx>) -> Result<(), ErrorReported> { + debug!("AbstractConstBuilder: stmt={:?}", stmt); + match stmt.kind { + StatementKind::Assign(box (ref place, ref rvalue)) => { + let local = self.place_to_local(stmt.source_info.span, place)?; + match *rvalue { + Rvalue::Use(ref operand) => { + self.locals[local] = + self.operand_to_node(stmt.source_info.span, operand)?; + Ok(()) + } + Rvalue::BinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { + let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; + let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; + self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); + if op.is_checkable() { + bug!("unexpected unchecked checkable binary operation"); + } else { + Ok(()) + } + } + Rvalue::CheckedBinaryOp(op, ref lhs, ref rhs) if Self::check_binop(op) => { + let lhs = self.operand_to_node(stmt.source_info.span, lhs)?; + let rhs = self.operand_to_node(stmt.source_info.span, rhs)?; + self.locals[local] = self.nodes.push(Node::Binop(op, lhs, rhs)); + self.checked_op_locals.insert(local); + Ok(()) + } + Rvalue::UnaryOp(op, ref operand) if Self::check_unop(op) => { + let operand = self.operand_to_node(stmt.source_info.span, operand)?; + self.locals[local] = self.nodes.push(Node::UnaryOp(op, operand)); + Ok(()) + } + _ => self.error(Some(stmt.source_info.span), "unsupported rvalue")?, + } + } + // These are not actually relevant for us here, so we can ignore them. + 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.nodes.push(Node::FunctionCall(func, args)); + Ok(Some(target)) + } + // We only allow asserts for checked operations. + // + // These asserts seem to all have the form `!_local.0` so + // we only allow exactly that. + 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 &[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. + 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 { + return Ok(self.tcx.arena.alloc_from_iter(self.nodes)); + } + } + } +} + +/// Builds an abstract const, do not use this directly, but use `AbstractConst::new` instead. +pub(super) fn mir_abstract_const<'tcx>( + tcx: TyCtxt<'tcx>, + def: ty::WithOptConstParam, +) -> Result]>, ErrorReported> { + if tcx.features().const_evaluatable_checked { + match tcx.def_kind(def.did) { + // FIXME(const_evaluatable_checked): We currently only do this for anonymous constants, + // meaning that we do not look into associated constants. I(@lcnr) am not yet sure whether + // we want to look into them or treat them as opaque projections. + // + // Right now we do neither of that and simply always fail to unify them. + DefKind::AnonConst => (), + _ => return Ok(None), + } + let body = tcx.mir_const(def).borrow(); + AbstractConstBuilder::new(tcx, &body)?.map(AbstractConstBuilder::build).transpose() + } else { + Ok(None) + } +} + +pub(super) fn try_unify_abstract_consts<'tcx>( + tcx: TyCtxt<'tcx>, + ((a, a_substs), (b, b_substs)): ( + (ty::WithOptConstParam, SubstsRef<'tcx>), + (ty::WithOptConstParam, SubstsRef<'tcx>), + ), +) -> bool { + (|| { + if let Some(a) = AbstractConst::new(tcx, a, a_substs)? { + if let Some(b) = AbstractConst::new(tcx, b, b_substs)? { + return Ok(try_unify(tcx, a, b)); + } + } + + Ok(false) + })() + .unwrap_or_else(|ErrorReported| true) + // FIXME(const_evaluatable_checked): We should instead have this + // method return the resulting `ty::Const` and return `ConstKind::Error` + // on `ErrorReported`. +} + +fn walk_abstract_const<'tcx, F>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, mut f: F) +where + F: FnMut(Node<'tcx>), +{ + recurse(tcx, ct, &mut f); + fn recurse<'tcx>(tcx: TyCtxt<'tcx>, ct: AbstractConst<'tcx>, f: &mut dyn FnMut(Node<'tcx>)) { + let root = ct.root(); + f(root); + match root { + Node::Leaf(_) => (), + Node::Binop(_, l, r) => { + recurse(tcx, ct.subtree(l), f); + recurse(tcx, ct.subtree(r), f); + } + Node::UnaryOp(_, v) => { + recurse(tcx, ct.subtree(v), f); + } + Node::FunctionCall(func, args) => { + recurse(tcx, ct.subtree(func), f); + for &arg in args { + recurse(tcx, ct.subtree(arg), f); + } + } + } + } +} + +/// Tries to unify two abstract constants using structural equality. +pub(super) fn try_unify<'tcx>( + tcx: TyCtxt<'tcx>, + a: AbstractConst<'tcx>, + b: AbstractConst<'tcx>, +) -> bool { + match (a.root(), b.root()) { + (Node::Leaf(a_ct), Node::Leaf(b_ct)) => { + let a_ct = a_ct.subst(tcx, a.substs); + let b_ct = b_ct.subst(tcx, b.substs); + match (a_ct.val, b_ct.val) { + // We can just unify errors with everything to reduce the amount of + // emitted errors here. + (ty::ConstKind::Error(_), _) | (_, ty::ConstKind::Error(_)) => true, + (ty::ConstKind::Param(a_param), ty::ConstKind::Param(b_param)) => { + a_param == b_param + } + (ty::ConstKind::Value(a_val), ty::ConstKind::Value(b_val)) => a_val == b_val, + // If we have `fn a() -> [u8; N + 1]` and `fn b() -> [u8; 1 + M]` + // we do not want to use `assert_eq!(a(), b())` to infer that `N` and `M` have to be `1`. This + // means that we only allow inference variables if they are equal. + (ty::ConstKind::Infer(a_val), ty::ConstKind::Infer(b_val)) => a_val == b_val, + // FIXME(const_evaluatable_checked): We may want to either actually try + // to evaluate `a_ct` and `b_ct` if they are are fully concrete or something like + // this, for now we just return false here. + _ => false, + } + } + (Node::Binop(a_op, al, ar), Node::Binop(b_op, bl, br)) if a_op == b_op => { + try_unify(tcx, a.subtree(al), b.subtree(bl)) + && try_unify(tcx, a.subtree(ar), b.subtree(br)) + } + (Node::UnaryOp(a_op, av), Node::UnaryOp(b_op, bv)) if a_op == b_op => { + try_unify(tcx, a.subtree(av), b.subtree(bv)) + } + (Node::FunctionCall(a_f, a_args), Node::FunctionCall(b_f, b_args)) + if a_args.len() == b_args.len() => + { + try_unify(tcx, a.subtree(a_f), b.subtree(b_f)) + && a_args + .iter() + .zip(b_args) + .all(|(&an, &bn)| try_unify(tcx, a.subtree(an), b.subtree(bn))) + } + _ => false, + } +} diff --git a/src/librustc_trait_selection/traits/engine.rs b/compiler/rustc_trait_selection/src/traits/engine.rs similarity index 100% rename from src/librustc_trait_selection/traits/engine.rs rename to compiler/rustc_trait_selection/src/traits/engine.rs diff --git a/src/librustc_trait_selection/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs similarity index 96% rename from src/librustc_trait_selection/traits/error_reporting/mod.rs rename to compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 28542d4b12..cb3de57cfe 100644 --- a/src/librustc_trait_selection/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -20,7 +20,6 @@ use rustc_hir::Node; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::error::ExpectedFound; use rustc_middle::ty::fold::TypeFolder; -use rustc_middle::ty::subst::GenericArgKind; use rustc_middle::ty::{ self, fast_reject, AdtKind, SubtypePredicate, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness, @@ -382,7 +381,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { // If it has a custom `#[rustc_on_unimplemented]` // error message, let's display it as the label! err.span_label(span, s.as_str()); - if !matches!(trait_ref.skip_binder().self_ty().kind, ty::Param(_)) { + if !matches!(trait_ref.skip_binder().self_ty().kind(), ty::Param(_)) { // When the self type is a type param We don't need to "the trait // `std::marker::Sized` is not implemented for `T`" as we will point // at the type param with a label to suggest constraining it. @@ -446,12 +445,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.tcx.lang_items().fn_once_trait(), ] .contains(&Some(trait_ref.def_id())); - let is_target_feature_fn = - if let ty::FnDef(def_id, _) = trait_ref.skip_binder().self_ty().kind { - !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() - } else { - false - }; + let is_target_feature_fn = if let ty::FnDef(def_id, _) = + *trait_ref.skip_binder().self_ty().kind() + { + !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() + } else { + false + }; if is_fn_trait && is_target_feature_fn { err.note( "`#[target_feature]` functions do not implement the `Fn` traits", @@ -662,6 +662,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { obligation ) } + + ty::PredicateAtom::TypeWellFormedFromEnv(..) => span_bug!( + span, + "TypeWellFormedFromEnv predicate should only exist in the environment" + ), } } @@ -678,7 +683,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { None => return, }; - let found_did = match found_trait_ty.kind { + let found_did = match *found_trait_ty.kind() { ty::Closure(did, _) | ty::Foreign(did) | ty::FnDef(did, _) => Some(did), ty::Adt(def, _) => Some(def.did), _ => None, @@ -696,13 +701,13 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { self.reported_closure_mismatch.borrow_mut().insert((span, found_span)); - let found = match found_trait_ref.skip_binder().substs.type_at(1).kind { + let found = match found_trait_ref.skip_binder().substs.type_at(1).kind() { ty::Tuple(ref tys) => vec![ArgKind::empty(); tys.len()], _ => vec![ArgKind::empty()], }; let expected_ty = expected_trait_ref.skip_binder().substs.type_at(1); - let expected = match expected_ty.kind { + let expected = match expected_ty.kind() { ty::Tuple(ref tys) => tys .iter() .map(|t| ArgKind::from_expected_ty(t.expect_ty(), Some(span))) @@ -740,25 +745,9 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let violations = self.tcx.object_safety_violations(did); report_object_safety_error(self.tcx, span, did, violations) } - ConstEvalFailure(ErrorHandled::TooGeneric) => { - // In this instance, we have a const expression containing an unevaluated - // generic parameter. We have no idea whether this expression is valid or - // not (e.g. it might result in an error), but we don't want to just assume - // that it's okay, because that might result in post-monomorphisation time - // errors. The onus is really on the caller to provide values that it can - // prove are well-formed. - let mut err = self - .tcx - .sess - .struct_span_err(span, "constant expression depends on a generic parameter"); - // FIXME(const_generics): we should suggest to the user how they can resolve this - // issue. However, this is currently not actually possible - // (see https://github.com/rust-lang/rust/issues/66962#issuecomment-575907083). - err.note("this may fail depending on what value the parameter takes"); - err + bug!("too generic should have been handled in `is_const_evaluatable`"); } - // Already reported in the query. ConstEvalFailure(ErrorHandled::Reported(ErrorReported)) => { // FIXME(eddyb) remove this once `ErrorReported` becomes a proof token. @@ -1252,7 +1241,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { /// returns the fuzzy category of a given type, or None /// if the type can be equated to any type. fn type_category(t: Ty<'_>) -> Option { - match t.kind { + match t.kind() { ty::Bool => Some(0), ty::Char => Some(1), ty::Str => Some(2), @@ -1281,7 +1270,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } match (type_category(a), type_category(b)) { - (Some(cat_a), Some(cat_b)) => match (&a.kind, &b.kind) { + (Some(cat_a), Some(cat_b)) => match (a.kind(), b.kind()) { (&ty::Adt(def_a, _), &ty::Adt(def_b, _)) => def_a == def_b, _ => cat_a == cat_b, }, @@ -1342,8 +1331,8 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { .normalize(candidate) .ok(); match normalized { - Some(normalized) => format!("\n {:?}", normalized.value), - None => format!("\n {:?}", candidate), + Some(normalized) => format!("\n {}", normalized.value), + None => format!("\n {}", candidate), } }) }; @@ -1476,7 +1465,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { ty::PredicateAtom::Trait(data, _) => { let trait_ref = ty::Binder::bind(data.trait_ref); let self_ty = trait_ref.skip_binder().self_ty(); - debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind, trait_ref); + debug!("self_ty {:?} {:?} trait_ref {:?}", self_ty, self_ty.kind(), trait_ref); if predicate.references_error() { return; @@ -1506,16 +1495,22 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { // avoid inundating the user with unnecessary errors, but we now // check upstream for type errors and don't add the obligations to // begin with in those cases. - if self - .tcx - .lang_items() - .sized_trait() - .map_or(false, |sized_id| sized_id == trait_ref.def_id()) - { - self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0282).emit(); + if self.tcx.lang_items().sized_trait() == Some(trait_ref.def_id()) { + self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0282, + ) + .emit(); return; } - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0283); + let mut err = self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0283, + ); err.note(&format!("cannot satisfy `{}`", predicate)); if let ObligationCauseCode::ItemObligation(def_id) = obligation.cause.code { self.suggest_fully_qualified_path(&mut err, def_id, span, trait_ref.def_id()); @@ -1579,17 +1574,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - match arg.unpack() { - GenericArgKind::Lifetime(lt) => { - span_bug!(span, "unexpected well formed predicate: {:?}", lt) - } - GenericArgKind::Type(ty) => { - self.need_type_info_err(body_id, span, ty, ErrorCode::E0282) - } - GenericArgKind::Const(ct) => { - self.need_type_info_err_const(body_id, span, ct, ErrorCode::E0282) - } - } + self.emit_inference_failure_err(body_id, span, arg, ErrorCode::E0282) } ty::PredicateAtom::Subtype(data) => { @@ -1600,7 +1585,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { let SubtypePredicate { a_is_expected: _, a, b } = data; // both must be type variables, or the other would've been instantiated assert!(a.is_ty_var() && b.is_ty_var()); - self.need_type_info_err(body_id, span, a, ErrorCode::E0282) + self.emit_inference_failure_err(body_id, span, a.into(), ErrorCode::E0282) } ty::PredicateAtom::Projection(data) => { let trait_ref = ty::Binder::bind(data).to_poly_trait_ref(self.tcx); @@ -1611,7 +1596,12 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } if self_ty.needs_infer() && ty.needs_infer() { // We do this for the `foo.collect()?` case to produce a suggestion. - let mut err = self.need_type_info_err(body_id, span, self_ty, ErrorCode::E0284); + let mut err = self.emit_inference_failure_err( + body_id, + span, + self_ty.into(), + ErrorCode::E0284, + ); err.note(&format!("cannot satisfy `{}`", predicate)); err } else { @@ -1664,7 +1654,7 @@ impl<'a, 'tcx> InferCtxtPrivExt<'tcx> for InferCtxt<'a, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - if let ty::Param(ty::ParamTy { name, .. }) = ty.kind { + if let ty::Param(ty::ParamTy { name, .. }) = *ty.kind() { let infcx = self.infcx; self.var_map.entry(ty).or_insert_with(|| { infcx.next_ty_var(TypeVariableOrigin { @@ -1938,8 +1928,8 @@ impl ArgKind { /// Creates an `ArgKind` from the expected type of an /// argument. It has no name (`_`) and an optional source span. pub fn from_expected_ty(t: Ty<'_>, span: Option) -> ArgKind { - match t.kind { - ty::Tuple(ref tys) => ArgKind::Tuple( + match t.kind() { + ty::Tuple(tys) => ArgKind::Tuple( span, tys.iter().map(|ty| ("_".to_owned(), ty.to_string())).collect::>(), ), diff --git a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs similarity index 98% rename from src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs rename to compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index d2b9f84af3..0f5aad5af1 100644 --- a/src/librustc_trait_selection/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -194,7 +194,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { flags.push((sym::_Self, Some("{integral}".to_owned()))); } - if let ty::Array(aty, len) = self_ty.kind { + if let ty::Array(aty, len) = self_ty.kind() { flags.push((sym::_Self, Some("[]".to_owned()))); flags.push((sym::_Self, Some(format!("[{}]", aty)))); if let Some(def) = aty.ty_adt_def() { @@ -218,7 +218,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { } } } - if let ty::Dynamic(traits, _) = self_ty.kind { + if let ty::Dynamic(traits, _) = self_ty.kind() { for t in traits.skip_binder() { if let ty::ExistentialPredicate::Trait(trait_ref) = t { flags.push((sym::_Self, Some(self.tcx.def_path_str(trait_ref.def_id)))) diff --git a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs similarity index 99% rename from src/librustc_trait_selection/traits/error_reporting/suggestions.rs rename to compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 138293c953..90a8d9634a 100644 --- a/src/librustc_trait_selection/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -207,7 +207,7 @@ fn suggest_restriction( } // Given `fn foo(t: impl Trait)` where `Trait` requires assoc type `A`... if let Some((bound_str, fn_sig)) = - fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind { + fn_sig.zip(projection).and_then(|(sig, p)| match p.self_ty().kind() { // Shenanigans to get the `Trait` from the `impl Trait`. ty::Param(param) => { // `fn foo(t: impl Trait)` @@ -323,7 +323,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { body_id: hir::HirId, ) { let self_ty = trait_ref.skip_binder().self_ty(); - let (param_ty, projection) = match &self_ty.kind { + let (param_ty, projection) = match self_ty.kind() { ty::Param(_) => (true, None), ty::Projection(projection) => (false, Some(projection)), _ => return, @@ -482,8 +482,8 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { None => return, }; - if let ty::Ref(region, base_ty, mutbl) = real_ty.kind { - let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty); + if let ty::Ref(region, base_ty, mutbl) = *real_ty.kind() { + let mut autoderef = Autoderef::new(self, param_env, body_id, span, base_ty, span); if let Some(steps) = autoderef.find_map(|(ty, steps)| { // Re-add the `&` let ty = self.tcx.mk_ref(region, TypeAndMut { ty, mutbl }); @@ -563,7 +563,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { Some(ty) => ty, }; - let (def_id, output_ty, callable) = match self_ty.kind { + let (def_id, output_ty, callable) = match *self_ty.kind() { ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig().output(), "closure"), ty::FnDef(def_id, _) => (def_id, self_ty.fn_sig(self.tcx).output(), "function"), _ => return, @@ -751,7 +751,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { }; for refs_remaining in 0..refs_number { - if let ty::Ref(_, inner_ty, _) = suggested_ty.kind { + if let ty::Ref(_, inner_ty, _) = suggested_ty.kind() { suggested_ty = inner_ty; let new_obligation = self.mk_trait_obligation_with_new_self_ty( @@ -814,7 +814,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { return; } - if let ty::Ref(region, t_type, mutability) = trait_ref.skip_binder().self_ty().kind { + if let ty::Ref(region, t_type, mutability) = *trait_ref.skip_binder().self_ty().kind() { if region.is_late_bound() || t_type.has_escaping_bound_vars() { // Avoid debug assertion in `mk_obligation_for_def_id`. // @@ -871,7 +871,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: &ty::Binder>, ) { let is_empty_tuple = - |ty: ty::Binder>| ty.skip_binder().kind == ty::Tuple(ty::List::empty()); + |ty: ty::Binder>| *ty.skip_binder().kind() == ty::Tuple(ty::List::empty()); let hir = self.tcx.hir(); let parent_node = hir.get_parent_node(obligation.cause.body_id); @@ -941,7 +941,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { let body = hir.body(*body_id); let trait_ref = self.resolve_vars_if_possible(trait_ref); let ty = trait_ref.skip_binder().self_ty(); - let is_object_safe = match ty.kind { + let is_object_safe = match ty.kind() { ty::Dynamic(predicates, _) => { // If the `dyn Trait` is not object safe, do not suggest `Box`. predicates @@ -982,11 +982,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { ty| { let ty = self.resolve_vars_if_possible(&ty); same &= - !matches!(ty.kind, ty::Error(_)) + !matches!(ty.kind(), ty::Error(_)) && last_ty.map_or(true, |last_ty| { // FIXME: ideally we would use `can_coerce` here instead, but `typeck` comes // *after* in the dependency graph. - match (&ty.kind, &last_ty.kind) { + match (ty.kind(), last_ty.kind()) { (Infer(InferTy::IntVar(_)), Infer(InferTy::IntVar(_))) | (Infer(InferTy::FloatVar(_)), Infer(InferTy::FloatVar(_))) | (Infer(InferTy::FreshIntTy(_)), Infer(InferTy::FreshIntTy(_))) @@ -997,12 +997,12 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { _ => ty == last_ty, } }); - (Some(ty), same, only_never_return && matches!(ty.kind, ty::Never)) + (Some(ty), same, only_never_return && matches!(ty.kind(), ty::Never)) }, ); let all_returns_conform_to_trait = if let Some(ty_ret_ty) = typeck_results.node_type_opt(ret_ty.hir_id) { - match ty_ret_ty.kind { + match ty_ret_ty.kind() { ty::Dynamic(predicates, _) => { let cause = ObligationCause::misc(ret_ty.span, ret_ty.hir_id); let param_env = ty::ParamEnv::empty(); @@ -1151,7 +1151,7 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { trait_ref: ty::TraitRef<'tcx>, ) -> String { let inputs = trait_ref.substs.type_at(1); - let sig = if let ty::Tuple(inputs) = inputs.kind { + 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 })), @@ -1317,10 +1317,11 @@ impl<'a, 'tcx> InferCtxtExt<'tcx> for InferCtxt<'a, 'tcx> { debug!( "maybe_note_obligation_cause_for_async_await: \ parent_trait_ref={:?} self_ty.kind={:?}", - derived_obligation.parent_trait_ref, ty.kind + derived_obligation.parent_trait_ref, + ty.kind() ); - match ty.kind { + match *ty.kind() { ty::Generator(did, ..) => { generator = generator.or(Some(did)); outer_generator = Some(did); diff --git a/src/librustc_trait_selection/traits/fulfill.rs b/compiler/rustc_trait_selection/src/traits/fulfill.rs similarity index 90% rename from src/librustc_trait_selection/traits/fulfill.rs rename to compiler/rustc_trait_selection/src/traits/fulfill.rs index a5c6dc042a..8586a55023 100644 --- a/src/librustc_trait_selection/traits/fulfill.rs +++ b/compiler/rustc_trait_selection/src/traits/fulfill.rs @@ -10,6 +10,7 @@ use rustc_middle::ty::ToPredicate; use rustc_middle::ty::{self, Binder, Const, Ty, TypeFoldable}; use std::marker::PhantomData; +use super::const_evaluatable; use super::project; use super::select::SelectionContext; use super::wf; @@ -86,7 +87,7 @@ pub struct PendingPredicateObligation<'tcx> { // `PendingPredicateObligation` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] -static_assert_size!(PendingPredicateObligation<'_>, 64); +static_assert_size!(PendingPredicateObligation<'_>, 56); impl<'a, 'tcx> FulfillmentContext<'tcx> { /// Creates a new fulfillment context. @@ -304,8 +305,34 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { return ProcessResult::Unchanged; } - // This part of the code is much colder. + self.progress_changed_obligations(pending_obligation) + } + fn process_backedge<'c, I>( + &mut self, + cycle: I, + _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, + ) where + I: Clone + Iterator>, + { + if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { + debug!("process_child_obligations: coinductive match"); + } else { + let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); + self.selcx.infcx().report_overflow_error_cycle(&cycle); + } + } +} + +impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { + // The code calling this method is extremely hot and only rarely + // actually uses this, so move this part of the code + // out of that loop. + #[inline(never)] + fn progress_changed_obligations( + &mut self, + pending_obligation: &mut PendingPredicateObligation<'tcx>, + ) -> ProcessResult, FulfillmentErrorCode<'tcx>> { pending_obligation.stalled_on.truncate(0); let obligation = &mut pending_obligation.obligation; @@ -354,6 +381,9 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { obligation.with(pred.to_predicate(self.selcx.tcx())), ])) } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } }, &ty::PredicateKind::Atom(atom) => match atom { ty::PredicateAtom::Trait(ref data, _) => { @@ -458,20 +488,46 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - match self.selcx.infcx().const_eval_resolve( - obligation.param_env, + match const_evaluatable::is_const_evaluatable( + self.selcx.infcx(), def_id, substs, - None, - Some(obligation.cause.span), + obligation.param_env, + obligation.cause.span, ) { - Ok(_) => ProcessResult::Changed(vec![]), - Err(err) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(err))), + Ok(()) => ProcessResult::Changed(vec![]), + Err(ErrorHandled::TooGeneric) => { + pending_obligation.stalled_on = substs + .iter() + .filter_map(|ty| TyOrConstInferVar::maybe_from_generic_arg(ty)) + .collect(); + ProcessResult::Unchanged + } + Err(e) => ProcessResult::Error(CodeSelectionError(ConstEvalFailure(e))), } } ty::PredicateAtom::ConstEquate(c1, c2) => { debug!("equating consts: c1={:?} c2={:?}", c1, c2); + if self.selcx.tcx().features().const_evaluatable_checked { + // FIXME: we probably should only try to unify abstract constants + // if the constants depend on generic parameters. + // + // Let's just see where this breaks :shrug: + if let ( + ty::ConstKind::Unevaluated(a_def, a_substs, None), + ty::ConstKind::Unevaluated(b_def, b_substs, None), + ) = (c1.val, c2.val) + { + if self + .selcx + .tcx() + .try_unify_abstract_consts(((a_def, a_substs), (b_def, b_substs))) + { + return ProcessResult::Changed(vec![]); + } + } + } let stalled_on = &mut pending_obligation.stalled_on; @@ -488,8 +544,10 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { Err(ErrorHandled::TooGeneric) => { stalled_on.append( &mut substs - .types() - .filter_map(|ty| TyOrConstInferVar::maybe_from_ty(ty)) + .iter() + .filter_map(|arg| { + TyOrConstInferVar::maybe_from_generic_arg(arg) + }) .collect(), ); Err(ErrorHandled::TooGeneric) @@ -535,27 +593,13 @@ impl<'a, 'b, 'tcx> ObligationProcessor for FulfillProcessor<'a, 'b, 'tcx> { } } } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } }, } } - fn process_backedge<'c, I>( - &mut self, - cycle: I, - _marker: PhantomData<&'c PendingPredicateObligation<'tcx>>, - ) where - I: Clone + Iterator>, - { - if self.selcx.coinductive_match(cycle.clone().map(|s| s.obligation.predicate)) { - debug!("process_child_obligations: coinductive match"); - } else { - let cycle: Vec<_> = cycle.map(|c| c.obligation.clone()).collect(); - self.selcx.infcx().report_overflow_error_cycle(&cycle); - } - } -} - -impl<'a, 'b, 'tcx> FulfillProcessor<'a, 'b, 'tcx> { fn process_trait_obligation( &mut self, obligation: &PredicateObligation<'tcx>, diff --git a/src/librustc_trait_selection/traits/misc.rs b/compiler/rustc_trait_selection/src/traits/misc.rs similarity index 97% rename from src/librustc_trait_selection/traits/misc.rs rename to compiler/rustc_trait_selection/src/traits/misc.rs index 61567aeb57..e23f5a583b 100644 --- a/src/librustc_trait_selection/traits/misc.rs +++ b/compiler/rustc_trait_selection/src/traits/misc.rs @@ -23,7 +23,7 @@ pub fn can_type_implement_copy( ) -> Result<(), CopyImplementationError<'tcx>> { // FIXME: (@jroesch) float this code up tcx.infer_ctxt().enter(|infcx| { - let (adt, substs) = match self_type.kind { + let (adt, substs) = match self_type.kind() { // These types used to have a builtin impl. // Now libcore provides that impl. ty::Uint(_) diff --git a/src/librustc_trait_selection/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs similarity index 95% rename from src/librustc_trait_selection/traits/mod.rs rename to compiler/rustc_trait_selection/src/traits/mod.rs index fe406e88c5..c93087a18c 100644 --- a/src/librustc_trait_selection/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -2,11 +2,11 @@ //! //! [rustc dev guide]: https://rustc-dev-guide.rust-lang.org/traits/resolution.html -#[allow(dead_code)] pub mod auto_trait; mod chalk_fulfill; pub mod codegen; mod coherence; +mod const_evaluatable; mod engine; pub mod error_reporting; mod fulfill; @@ -301,11 +301,8 @@ pub fn normalize_param_env_or_error<'tcx>( debug!("normalize_param_env_or_error: elaborated-predicates={:?}", predicates); - let elaborated_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal(), - unnormalized_env.def_id, - ); + let elaborated_env = + ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()); // HACK: we are trying to normalize the param-env inside *itself*. The problem is that // normalization expects its param-env to be already normalized, which means we have @@ -359,7 +356,7 @@ pub fn normalize_param_env_or_error<'tcx>( let outlives_env: Vec<_> = non_outlives_predicates.iter().chain(&outlives_predicates).cloned().collect(); let outlives_env = - ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal(), None); + ty::ParamEnv::new(tcx.intern_predicates(&outlives_env), unnormalized_env.reveal()); let outlives_predicates = match do_normalize_predicates( tcx, region_context, @@ -379,11 +376,7 @@ pub fn normalize_param_env_or_error<'tcx>( let mut predicates = non_outlives_predicates; predicates.extend(outlives_predicates); debug!("normalize_param_env_or_error: final predicates={:?}", predicates); - ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - unnormalized_env.reveal(), - unnormalized_env.def_id, - ) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), unnormalized_env.reveal()) } pub fn fully_normalize<'a, 'tcx, T>( @@ -558,6 +551,21 @@ pub fn provide(providers: &mut ty::query::Providers) { vtable_methods, type_implements_trait, subst_and_check_impossible_predicates, + mir_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) + } else { + const_evaluatable::mir_abstract_const(tcx, ty::WithOptConstParam::unknown(def_id)) + } + }, + mir_abstract_const_of_const_arg: |tcx, (did, param_did)| { + const_evaluatable::mir_abstract_const( + tcx, + ty::WithOptConstParam { did, const_param_did: Some(param_did) }, + ) + }, + try_unify_abstract_consts: const_evaluatable::try_unify_abstract_consts, ..*providers }; } diff --git a/src/librustc_trait_selection/traits/object_safety.rs b/compiler/rustc_trait_selection/src/traits/object_safety.rs similarity index 97% rename from src/librustc_trait_selection/traits/object_safety.rs rename to compiler/rustc_trait_selection/src/traits/object_safety.rs index c003e4f806..86fc3cbfea 100644 --- a/src/librustc_trait_selection/traits/object_safety.rs +++ b/compiler/rustc_trait_selection/src/traits/object_safety.rs @@ -276,7 +276,8 @@ fn predicates_reference_self( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } }) .collect() @@ -310,7 +311,8 @@ fn generics_require_sized_self(tcx: TyCtxt<'_>, def_id: DefId) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => false, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => false, } }) } @@ -422,10 +424,17 @@ fn virtual_call_violation_for_method<'tcx>( let param_env = tcx.param_env(method.def_id); - let abi_of_ty = |ty: Ty<'tcx>| -> &Abi { + let abi_of_ty = |ty: Ty<'tcx>| -> Option<&Abi> { match tcx.layout_of(param_env.and(ty)) { - Ok(layout) => &layout.abi, - Err(err) => bug!("error: {}\n while computing layout for type {:?}", err, ty), + Ok(layout) => Some(&layout.abi), + Err(err) => { + // #78372 + tcx.sess.delay_span_bug( + tcx.def_span(method.def_id), + &format!("error: {}\n while computing layout for type {:?}", err, ty), + ); + None + } } }; @@ -434,7 +443,7 @@ fn virtual_call_violation_for_method<'tcx>( receiver_for_self_ty(tcx, receiver_ty, tcx.mk_unit(), method.def_id); match abi_of_ty(unit_receiver_ty) { - &Abi::Scalar(..) => (), + Some(Abi::Scalar(..)) => (), abi => { tcx.sess.delay_span_bug( tcx.def_span(method.def_id), @@ -454,13 +463,12 @@ fn virtual_call_violation_for_method<'tcx>( receiver_for_self_ty(tcx, receiver_ty, trait_object_ty, method.def_id); match abi_of_ty(trait_object_receiver) { - &Abi::ScalarPair(..) => (), + Some(Abi::ScalarPair(..)) => (), abi => { tcx.sess.delay_span_bug( tcx.def_span(method.def_id), &format!( - "receiver when `Self = {}` should have a ScalarPair ABI; \ - found {:?}", + "receiver when `Self = {}` should have a ScalarPair ABI; found {:?}", trait_object_ty, abi ), ); @@ -654,11 +662,7 @@ fn receiver_is_dispatchable<'tcx>( .chain(iter::once(trait_predicate)) .collect(); - ty::ParamEnv::new( - tcx.intern_predicates(&caller_bounds), - param_env.reveal(), - param_env.def_id, - ) + ty::ParamEnv::new(tcx.intern_predicates(&caller_bounds), param_env.reveal()) }; // Receiver: DispatchFromDyn U]> @@ -732,7 +736,7 @@ fn contains_illegal_self_type_reference<'tcx>( impl<'tcx> TypeVisitor<'tcx> for IllegalSelfTypeVisitor<'tcx> { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { + match t.kind() { ty::Param(_) => t == self.self_ty, ty::Projection(ref data) => { // This is a projected type `::X`. diff --git a/src/librustc_trait_selection/traits/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/on_unimplemented.rs similarity index 100% rename from src/librustc_trait_selection/traits/on_unimplemented.rs rename to compiler/rustc_trait_selection/src/traits/on_unimplemented.rs diff --git a/src/librustc_trait_selection/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs similarity index 97% rename from src/librustc_trait_selection/traits/project.rs rename to compiler/rustc_trait_selection/src/traits/project.rs index c788e4f5c9..6ac620b01b 100644 --- a/src/librustc_trait_selection/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -345,8 +345,8 @@ impl<'a, 'b, 'tcx> TypeFolder<'tcx> for AssocTypeNormalizer<'a, 'b, 'tcx> { // should occur eventually). let ty = ty.super_fold_with(self); - match ty.kind { - ty::Opaque(def_id, substs) => { + match *ty.kind() { + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty, @@ -908,7 +908,7 @@ fn assemble_candidates_from_trait_def<'cx, 'tcx>( let tcx = selcx.tcx(); // Check whether the self-type is itself a projection. // If so, extract what we know from the trait and try to come up with a good answer. - let bounds = match obligation_trait_ref.self_ty().kind { + let bounds = match *obligation_trait_ref.self_ty().kind() { ty::Projection(ref data) => { tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) } @@ -1000,15 +1000,15 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( }; let eligible = match &impl_source { - super::ImplSourceClosure(_) - | super::ImplSourceGenerator(_) - | super::ImplSourceFnPointer(_) - | super::ImplSourceObject(_) - | super::ImplSourceTraitAlias(_) => { + super::ImplSource::Closure(_) + | super::ImplSource::Generator(_) + | super::ImplSource::FnPointer(_) + | super::ImplSource::Object(_) + | super::ImplSource::TraitAlias(_) => { debug!("assemble_candidates_from_impls: impl_source={:?}", impl_source); true } - super::ImplSourceUserDefined(impl_data) => { + super::ImplSource::UserDefined(impl_data) => { // We have to be careful when projecting out of an // impl because of specialization. If we are not in // codegen (i.e., projection mode is not "any"), and the @@ -1060,14 +1060,14 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( } } } - super::ImplSourceDiscriminantKind(..) => { + super::ImplSource::DiscriminantKind(..) => { // While `DiscriminantKind` is automatically implemented for every type, // the concrete discriminant may not be known yet. // // Any type with multiple potential discriminant types is therefore not eligible. let self_ty = selcx.infcx().shallow_resolve(obligation.predicate.self_ty()); - match self_ty.kind { + match self_ty.kind() { ty::Bool | ty::Char | ty::Int(_) @@ -1100,7 +1100,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( | ty::Error(_) => false, } } - super::ImplSourceParam(..) => { + super::ImplSource::Param(..) => { // This case tell us nothing about the value of an // associated type. Consider: // @@ -1128,7 +1128,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( // in `assemble_candidates_from_param_env`. false } - super::ImplSourceAutoImpl(..) | super::ImplSourceBuiltin(..) => { + super::ImplSource::AutoImpl(..) | super::ImplSource::Builtin(..) => { // These traits have no associated types. selcx.tcx().sess.delay_span_bug( obligation.cause.span, @@ -1186,20 +1186,20 @@ fn confirm_select_candidate<'cx, 'tcx>( impl_source: Selection<'tcx>, ) -> Progress<'tcx> { match impl_source { - super::ImplSourceUserDefined(data) => confirm_impl_candidate(selcx, obligation, data), - super::ImplSourceGenerator(data) => confirm_generator_candidate(selcx, obligation, data), - super::ImplSourceClosure(data) => confirm_closure_candidate(selcx, obligation, data), - super::ImplSourceFnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), - super::ImplSourceDiscriminantKind(data) => { + super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), + super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), + super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data), + super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), + super::ImplSource::DiscriminantKind(data) => { confirm_discriminant_kind_candidate(selcx, obligation, data) } - super::ImplSourceObject(_) => { + super::ImplSource::Object(_) => { confirm_object_candidate(selcx, obligation, obligation_trait_ref) } - super::ImplSourceAutoImpl(..) - | super::ImplSourceParam(..) - | super::ImplSourceBuiltin(..) - | super::ImplSourceTraitAlias(..) => + super::ImplSource::AutoImpl(..) + | super::ImplSource::Param(..) + | super::ImplSource::Builtin(..) + | super::ImplSource::TraitAlias(..) => // we don't create Select candidates with this kind of resolution { span_bug!( @@ -1219,8 +1219,8 @@ fn confirm_object_candidate<'cx, 'tcx>( let self_ty = obligation_trait_ref.self_ty(); let object_ty = selcx.infcx().shallow_resolve(self_ty); debug!("confirm_object_candidate(object_ty={:?})", object_ty); - let data = match object_ty.kind { - ty::Dynamic(ref data, ..) => data, + let data = match object_ty.kind() { + ty::Dynamic(data, ..) => data, _ => span_bug!( obligation.cause.span, "confirm_object_candidate called with non-object: {:?}", diff --git a/src/librustc_trait_selection/traits/query/dropck_outlives.rs b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs similarity index 99% rename from src/librustc_trait_selection/traits/query/dropck_outlives.rs rename to compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs index d07c95270e..424b3bd67f 100644 --- a/src/librustc_trait_selection/traits/query/dropck_outlives.rs +++ b/compiler/rustc_trait_selection/src/traits/query/dropck_outlives.rs @@ -82,7 +82,7 @@ impl<'cx, 'tcx> AtExt<'tcx> for At<'cx, 'tcx> { /// Note also that `needs_drop` requires a "global" type (i.e., one /// with erased regions), but this function does not. pub fn trivial_dropck_outlives<'tcx>(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> bool { - match ty.kind { + match ty.kind() { // None of these types have a destructor and hence they do not // require anything in particular to outlive the dtor's // execution. diff --git a/src/librustc_trait_selection/traits/query/evaluate_obligation.rs b/compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/evaluate_obligation.rs rename to compiler/rustc_trait_selection/src/traits/query/evaluate_obligation.rs diff --git a/src/librustc_trait_selection/traits/query/method_autoderef.rs b/compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/method_autoderef.rs rename to compiler/rustc_trait_selection/src/traits/query/method_autoderef.rs diff --git a/src/librustc_trait_selection/traits/query/mod.rs b/compiler/rustc_trait_selection/src/traits/query/mod.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/mod.rs rename to compiler/rustc_trait_selection/src/traits/query/mod.rs diff --git a/src/librustc_trait_selection/traits/query/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/normalize.rs similarity index 98% rename from src/librustc_trait_selection/traits/query/normalize.rs rename to compiler/rustc_trait_selection/src/traits/query/normalize.rs index 17963a6c82..c0ae7bf697 100644 --- a/src/librustc_trait_selection/traits/query/normalize.rs +++ b/compiler/rustc_trait_selection/src/traits/query/normalize.rs @@ -107,8 +107,8 @@ impl<'cx, 'tcx> TypeFolder<'tcx> for QueryNormalizer<'cx, 'tcx> { } let ty = ty.super_fold_with(self); - let res = (|| match ty.kind { - ty::Opaque(def_id, substs) => { + let res = (|| match *ty.kind() { + ty::Opaque(def_id, substs) if !substs.has_escaping_bound_vars() => { // Only normalize `impl Trait` after type-checking, usually in codegen. match self.param_env.reveal() { Reveal::UserFacing => ty, diff --git a/src/librustc_trait_selection/traits/query/outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/outlives_bounds.rs rename to compiler/rustc_trait_selection/src/traits/query/outlives_bounds.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/ascribe_user_type.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/ascribe_user_type.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/custom.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/custom.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/custom.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/eq.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/eq.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/eq.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/implied_outlives_bounds.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/mod.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/mod.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/mod.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/normalize.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/normalize.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/normalize.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/outlives.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/outlives.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/outlives.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/prove_predicate.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/prove_predicate.rs diff --git a/src/librustc_trait_selection/traits/query/type_op/subtype.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs similarity index 100% rename from src/librustc_trait_selection/traits/query/type_op/subtype.rs rename to compiler/rustc_trait_selection/src/traits/query/type_op/subtype.rs diff --git a/src/librustc_trait_selection/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs similarity index 77% rename from src/librustc_trait_selection/traits/select/candidate_assembly.rs rename to compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 1d5441b8ef..9cb5c23264 100644 --- a/src/librustc_trait_selection/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -7,14 +7,19 @@ //! [rustc dev guide]:https://rustc-dev-guide.rust-lang.org/traits/resolution.html#candidate-assembly use rustc_hir as hir; use rustc_infer::traits::{Obligation, SelectionError, TraitObligation}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TypeFoldable}; use rustc_target::spec::abi::Abi; +use crate::traits::coherence::Conflict; use crate::traits::{util, SelectionResult}; +use crate::traits::{Overflow, Unimplemented}; use super::BuiltinImplConditions; +use super::IntercrateAmbiguityCause; +use super::OverflowError; use super::SelectionCandidate::{self, *}; -use super::{SelectionCandidateSet, SelectionContext, TraitObligationStack}; +use super::{EvaluatedCandidate, SelectionCandidateSet, SelectionContext, TraitObligationStack}; impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { pub(super) fn candidate_from_obligation<'o>( @@ -62,6 +67,161 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { candidate } + fn candidate_from_obligation_no_cache<'o>( + &mut self, + stack: &TraitObligationStack<'o, 'tcx>, + ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { + if let Some(conflict) = self.is_knowable(stack) { + debug!("coherence stage: not knowable"); + if self.intercrate_ambiguity_causes.is_some() { + debug!("evaluate_stack: intercrate_ambiguity_causes is some"); + // Heuristics: show the diagnostics when there are no candidates in crate. + if let Ok(candidate_set) = self.assemble_candidates(stack) { + let mut no_candidates_apply = true; + + for c in candidate_set.vec.iter() { + if self.evaluate_candidate(stack, &c)?.may_apply() { + no_candidates_apply = false; + break; + } + } + + if !candidate_set.ambiguous && no_candidates_apply { + let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; + let self_ty = trait_ref.self_ty(); + let (trait_desc, self_desc) = with_no_trimmed_paths(|| { + let trait_desc = trait_ref.print_only_trait_path().to_string(); + let self_desc = if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }; + (trait_desc, self_desc) + }); + let cause = if let Conflict::Upstream = conflict { + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } + } else { + IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + }; + debug!("evaluate_stack: pushing cause = {:?}", cause); + self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); + } + } + } + return Ok(None); + } + + let candidate_set = self.assemble_candidates(stack)?; + + if candidate_set.ambiguous { + debug!("candidate set contains ambig"); + return Ok(None); + } + + let mut candidates = candidate_set.vec; + + debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + // At this point, we know that each of the entries in the + // candidate set is *individually* applicable. Now we have to + // figure out if they contain mutual incompatibilities. This + // frequently arises if we have an unconstrained input type -- + // for example, we are looking for `$0: Eq` where `$0` is some + // unconstrained type variable. In that case, we'll get a + // candidate which assumes $0 == int, one that assumes `$0 == + // usize`, etc. This spells an ambiguity. + + // If there is more than one candidate, first winnow them down + // by considering extra conditions (nested obligations and so + // forth). We don't winnow if there is exactly one + // candidate. This is a relatively minor distinction but it + // can lead to better inference and error-reporting. An + // example would be if there was an impl: + // + // impl Vec { fn push_clone(...) { ... } } + // + // and we were to see some code `foo.push_clone()` where `boo` + // is a `Vec` and `Bar` does not implement `Clone`. If + // we were to winnow, we'd wind up with zero candidates. + // Instead, we select the right impl now but report "`Bar` does + // not implement `Clone`". + if candidates.len() == 1 { + return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); + } + + // Winnow, but record the exact outcome of evaluation, which + // is needed for specialization. Propagate overflow if it occurs. + let mut candidates = candidates + .into_iter() + .map(|c| match self.evaluate_candidate(stack, &c) { + Ok(eval) if eval.may_apply() => { + Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) + } + Ok(_) => Ok(None), + Err(OverflowError) => Err(Overflow), + }) + .flat_map(Result::transpose) + .collect::, _>>()?; + + debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); + + let needs_infer = stack.obligation.predicate.needs_infer(); + + // If there are STILL multiple candidates, we can further + // reduce the list by dropping duplicates -- including + // resolving specializations. + if candidates.len() > 1 { + let mut i = 0; + while i < candidates.len() { + let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { + self.candidate_should_be_dropped_in_favor_of( + &candidates[i], + &candidates[j], + needs_infer, + ) + }); + if is_dup { + debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + candidates.swap_remove(i); + } else { + debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); + i += 1; + + // If there are *STILL* multiple candidates, give up + // and report ambiguity. + if i > 1 { + debug!("multiple matches, ambig"); + return Ok(None); + } + } + } + } + + // If there are *NO* candidates, then there are no impls -- + // that we know of, anyway. Note that in the case where there + // are unbound type variables within the obligation, it might + // be the case that you could still satisfy the obligation + // from another crate by instantiating the type variables with + // a type from another crate that does have an impl. This case + // is checked for in `evaluate_stack` (and hence users + // who might care about this case, like coherence, should use + // that function). + if candidates.is_empty() { + // If there's an error type, 'downgrade' our result from + // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid + // emitting additional spurious errors, since we're guaranteed + // to have emitted at least one. + if stack.obligation.references_error() { + debug!("no results for error type, treating as ambiguous"); + return Ok(None); + } + return Err(Unimplemented); + } + + // Just one candidate left. + self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) + } + pub(super) fn assemble_candidates<'o>( &mut self, stack: &TraitObligationStack<'o, 'tcx>, @@ -152,7 +312,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Before we go into the whole placeholder thing, just // quickly check if the self-type is a projection at all. - match obligation.predicate.skip_binder().trait_ref.self_ty().kind { + match obligation.predicate.skip_binder().trait_ref.self_ty().kind() { ty::Projection(_) | ty::Opaque(..) => {} ty::Infer(ty::TyVar(_)) => { span_bug!( @@ -221,7 +381,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = obligation.self_ty().skip_binder(); - match self_ty.kind { + match self_ty.kind() { ty::Generator(..) => { debug!( "assemble_generator_candidates: self_ty={:?} obligation={:?}", @@ -261,7 +421,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because the substs on closure types never // touch bound regions, they just capture the in-scope // type/region parameters - match obligation.self_ty().skip_binder().kind { + match *obligation.self_ty().skip_binder().kind() { ty::Closure(_, closure_substs) => { debug!("assemble_unboxed_candidates: kind={:?} obligation={:?}", kind, obligation); match self.infcx.closure_kind(closure_substs) { @@ -300,7 +460,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // Okay to skip binder because what we are inspecting doesn't involve bound regions. let self_ty = obligation.self_ty().skip_binder(); - match self_ty.kind { + match *self_ty.kind() { ty::Infer(ty::TyVar(_)) => { debug!("assemble_fn_pointer_candidates: ambiguous self-type"); candidates.ambiguous = true; // Could wind up being a fn() type. @@ -382,7 +542,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { let def_id = obligation.predicate.def_id(); if self.tcx().trait_is_auto(def_id) { - match self_ty.kind { + match self_ty.kind() { ty::Dynamic(..) => { // For object types, we don't know what the closed // over types are. This means we conservatively @@ -453,7 +613,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // self-ty here doesn't escape this probe, so just erase // any LBR. let self_ty = self.tcx().erase_late_bound_regions(&obligation.self_ty()); - let poly_trait_ref = match self_ty.kind { + let poly_trait_ref = match self_ty.kind() { ty::Dynamic(ref data, ..) => { if data.auto_traits().any(|did| did == obligation.predicate.def_id()) { debug!( @@ -539,7 +699,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("assemble_candidates_for_unsizing(source={:?}, target={:?})", source, target); - let may_apply = match (&source.kind, &target.kind) { + let may_apply = match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { // Upcasts permit two things: diff --git a/src/librustc_trait_selection/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs similarity index 96% rename from src/librustc_trait_selection/traits/select/confirmation.rs rename to compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 3d6eb84513..88b656ce68 100644 --- a/src/librustc_trait_selection/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -19,16 +19,12 @@ use crate::traits::project::{self, normalize_with_depth}; use crate::traits::select::TraitObligationExt; use crate::traits::util; use crate::traits::util::{closure_trait_ref_and_return_type, predicate_for_trait_def}; +use crate::traits::ImplSource; use crate::traits::Normalized; use crate::traits::OutputTypeParameterMismatch; use crate::traits::Selection; use crate::traits::TraitNotObjectSafe; use crate::traits::{BuiltinDerivedObligation, ImplDerivedObligation}; -use crate::traits::{ - ImplSourceAutoImpl, ImplSourceBuiltin, ImplSourceClosure, ImplSourceDiscriminantKind, - ImplSourceFnPointer, ImplSourceGenerator, ImplSourceObject, ImplSourceParam, - ImplSourceTraitAlias, ImplSourceUserDefined, -}; use crate::traits::{ ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, ImplSourceGeneratorData, @@ -55,67 +51,67 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { match candidate { BuiltinCandidate { has_nested } => { let data = self.confirm_builtin_candidate(obligation, has_nested); - Ok(ImplSourceBuiltin(data)) + Ok(ImplSource::Builtin(data)) } ParamCandidate(param) => { let obligations = self.confirm_param_candidate(obligation, param); - Ok(ImplSourceParam(obligations)) + Ok(ImplSource::Param(obligations)) } ImplCandidate(impl_def_id) => { - Ok(ImplSourceUserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) + Ok(ImplSource::UserDefined(self.confirm_impl_candidate(obligation, impl_def_id))) } AutoImplCandidate(trait_def_id) => { let data = self.confirm_auto_impl_candidate(obligation, trait_def_id); - Ok(ImplSourceAutoImpl(data)) + Ok(ImplSource::AutoImpl(data)) } ProjectionCandidate => { self.confirm_projection_candidate(obligation); - Ok(ImplSourceParam(Vec::new())) + Ok(ImplSource::Param(Vec::new())) } ClosureCandidate => { let vtable_closure = self.confirm_closure_candidate(obligation)?; - Ok(ImplSourceClosure(vtable_closure)) + Ok(ImplSource::Closure(vtable_closure)) } GeneratorCandidate => { let vtable_generator = self.confirm_generator_candidate(obligation)?; - Ok(ImplSourceGenerator(vtable_generator)) + Ok(ImplSource::Generator(vtable_generator)) } FnPointerCandidate => { let data = self.confirm_fn_pointer_candidate(obligation)?; - Ok(ImplSourceFnPointer(data)) + Ok(ImplSource::FnPointer(data)) } DiscriminantKindCandidate => { - Ok(ImplSourceDiscriminantKind(ImplSourceDiscriminantKindData)) + Ok(ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData)) } TraitAliasCandidate(alias_def_id) => { let data = self.confirm_trait_alias_candidate(obligation, alias_def_id); - Ok(ImplSourceTraitAlias(data)) + Ok(ImplSource::TraitAlias(data)) } ObjectCandidate => { let data = self.confirm_object_candidate(obligation); - Ok(ImplSourceObject(data)) + Ok(ImplSource::Object(data)) } BuiltinObjectCandidate => { // This indicates something like `Trait + Send: Send`. In this case, we know that // this holds because that's what the object type is telling us, and there's really // no additional obligations to prove and no types in particular to unify, etc. - Ok(ImplSourceParam(Vec::new())) + Ok(ImplSource::Param(Vec::new())) } BuiltinUnsizeCandidate => { let data = self.confirm_builtin_unsize_candidate(obligation)?; - Ok(ImplSourceBuiltin(data)) + Ok(ImplSource::Builtin(data)) } } } @@ -327,8 +323,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // from the object. Have to try to make a broken test case that // results. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let poly_trait_ref = match self_ty.kind { - ty::Dynamic(ref data, ..) => data + let poly_trait_ref = match self_ty.kind() { + ty::Dynamic(data, ..) => data .principal() .unwrap_or_else(|| { span_bug!(obligation.cause.span, "object candidate with no principal") @@ -449,7 +445,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let (generator_def_id, substs) = match self_ty.kind { + let (generator_def_id, substs) = match *self_ty.kind() { ty::Generator(id, substs, _) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), }; @@ -498,7 +494,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // touch bound regions, they just capture the in-scope // type/region parameters. let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); - let (closure_def_id, substs) = match self_ty.kind { + let (closure_def_id, substs) = match *self_ty.kind() { ty::Closure(id, substs) => (id, substs), _ => bug!("closure candidate for non-closure {:?}", obligation), }; @@ -594,7 +590,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!("confirm_builtin_unsize_candidate(source={:?}, target={:?})", source, target); let mut nested = vec![]; - match (&source.kind, &target.kind) { + match (source.kind(), target.kind()) { // Trait+Kx+'a -> Trait+Ky+'b (upcasts). (&ty::Dynamic(ref data_a, r_a), &ty::Dynamic(ref data_b, r_b)) => { // See `assemble_candidates_for_unsizing` for more info. @@ -693,7 +689,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // `Struct` -> `Struct` (&ty::Adt(def, substs_a), &ty::Adt(_, substs_b)) => { let maybe_unsizing_param_idx = |arg: GenericArg<'tcx>| match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind { + GenericArgKind::Type(ty) => match ty.kind() { ty::Param(p) => Some(p.index), _ => None, }, diff --git a/src/librustc_trait_selection/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs similarity index 86% rename from src/librustc_trait_selection/traits/select/mod.rs rename to compiler/rustc_trait_selection/src/traits/select/mod.rs index 82f476b463..114dc79c44 100644 --- a/src/librustc_trait_selection/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -6,6 +6,7 @@ use self::EvaluationResult::*; use self::SelectionCandidate::*; use super::coherence::{self, Conflict}; +use super::const_evaluatable; use super::project; use super::project::normalize_with_depth_to; use super::util; @@ -32,6 +33,7 @@ use rustc_hir::def_id::DefId; use rustc_middle::dep_graph::{DepKind, DepNodeIndex}; use rustc_middle::mir::interpret::ErrorHandled; use rustc_middle::ty::fast_reject; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::relate::TypeRelation; use rustc_middle::ty::subst::{GenericArgKind, Subst, SubstsRef}; use rustc_middle::ty::{ @@ -448,150 +450,167 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { None => self.check_recursion_limit(&obligation, &obligation)?, } - match obligation.predicate.skip_binders() { - ty::PredicateAtom::Trait(t, _) => { - let t = ty::Binder::bind(t); - debug_assert!(!t.has_escaping_bound_vars()); - let obligation = obligation.with(t); - self.evaluate_trait_predicate_recursively(previous_stack, obligation) - } + ensure_sufficient_stack(|| { + match obligation.predicate.skip_binders() { + ty::PredicateAtom::Trait(t, _) => { + let t = ty::Binder::bind(t); + debug_assert!(!t.has_escaping_bound_vars()); + let obligation = obligation.with(t); + self.evaluate_trait_predicate_recursively(previous_stack, obligation) + } - ty::PredicateAtom::Subtype(p) => { - let p = ty::Binder::bind(p); - // Does this code ever run? - match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { - Some(Ok(InferOk { mut obligations, .. })) => { + ty::PredicateAtom::Subtype(p) => { + let p = ty::Binder::bind(p); + // Does this code ever run? + match self.infcx.subtype_predicate(&obligation.cause, obligation.param_env, p) { + Some(Ok(InferOk { mut obligations, .. })) => { + self.add_depth(obligations.iter_mut(), obligation.recursion_depth); + self.evaluate_predicates_recursively( + previous_stack, + obligations.into_iter(), + ) + } + Some(Err(_)) => Ok(EvaluatedToErr), + None => Ok(EvaluatedToAmbig), + } + } + + ty::PredicateAtom::WellFormed(arg) => match wf::obligations( + self.infcx, + obligation.param_env, + obligation.cause.body_id, + arg, + obligation.cause.span, + ) { + Some(mut obligations) => { self.add_depth(obligations.iter_mut(), obligation.recursion_depth); self.evaluate_predicates_recursively( previous_stack, obligations.into_iter(), ) } - Some(Err(_)) => Ok(EvaluatedToErr), None => Ok(EvaluatedToAmbig), + }, + + ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { + // We do not consider region relationships when evaluating trait matches. + Ok(EvaluatedToOkModuloRegions) } - } - ty::PredicateAtom::WellFormed(arg) => match wf::obligations( - self.infcx, - obligation.param_env, - obligation.cause.body_id, - arg, - obligation.cause.span, - ) { - Some(mut obligations) => { - self.add_depth(obligations.iter_mut(), obligation.recursion_depth); - self.evaluate_predicates_recursively(previous_stack, obligations.into_iter()) - } - None => Ok(EvaluatedToAmbig), - }, - - ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::RegionOutlives(..) => { - // We do not consider region relationships when evaluating trait matches. - Ok(EvaluatedToOkModuloRegions) - } - - ty::PredicateAtom::ObjectSafe(trait_def_id) => { - if self.tcx().is_object_safe(trait_def_id) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - - ty::PredicateAtom::Projection(data) => { - let data = ty::Binder::bind(data); - let project_obligation = obligation.with(data); - 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.into_iter(), - ); - if let Some(key) = - ProjectionCacheKey::from_poly_projection_predicate(self, data) - { - self.infcx.inner.borrow_mut().projection_cache().complete(key); - } - result - } - Ok(Ok(None)) => Ok(EvaluatedToAmbig), - // EvaluatedToRecur might also be acceptable here, but use - // Unknown for now because it means that we won't dismiss a - // selection candidate solely because it has a projection - // cycle. This is closest to the previous behavior of - // immediately erroring. - Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), - Err(_) => Ok(EvaluatedToErr), - } - } - - ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { - match self.infcx.closure_kind(closure_substs) { - Some(closure_kind) => { - if closure_kind.extends(kind) { - Ok(EvaluatedToOk) - } else { - Ok(EvaluatedToErr) - } - } - None => Ok(EvaluatedToAmbig), - } - } - - ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { - match self.tcx().const_eval_resolve( - obligation.param_env, - def_id, - substs, - None, - None, - ) { - Ok(_) => Ok(EvaluatedToOk), - Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), - Err(_) => Ok(EvaluatedToErr), - } - } - - ty::PredicateAtom::ConstEquate(c1, c2) => { - debug!("evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", c1, c2); - - let evaluate = |c: &'tcx ty::Const<'tcx>| { - if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { - self.infcx - .const_eval_resolve( - obligation.param_env, - def, - substs, - promoted, - Some(obligation.cause.span), - ) - .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) + ty::PredicateAtom::ObjectSafe(trait_def_id) => { + if self.tcx().is_object_safe(trait_def_id) { + Ok(EvaluatedToOk) } else { - Ok(c) - } - }; - - match (evaluate(c1), evaluate(c2)) { - (Ok(c1), Ok(c2)) => { - match self.infcx().at(&obligation.cause, obligation.param_env).eq(c1, c2) { - Ok(_) => Ok(EvaluatedToOk), - Err(_) => Ok(EvaluatedToErr), - } - } - (Err(ErrorHandled::Reported(ErrorReported)), _) - | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), - (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => span_bug!( - obligation.cause.span(self.tcx()), - "ConstEquate: const_eval_resolve returned an unexpected error" - ), - (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { - Ok(EvaluatedToAmbig) + Ok(EvaluatedToErr) } } + + ty::PredicateAtom::Projection(data) => { + let data = ty::Binder::bind(data); + let project_obligation = obligation.with(data); + 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.into_iter(), + ); + if let Some(key) = + ProjectionCacheKey::from_poly_projection_predicate(self, data) + { + self.infcx.inner.borrow_mut().projection_cache().complete(key); + } + result + } + Ok(Ok(None)) => Ok(EvaluatedToAmbig), + // EvaluatedToRecur might also be acceptable here, but use + // Unknown for now because it means that we won't dismiss a + // selection candidate solely because it has a projection + // cycle. This is closest to the previous behavior of + // immediately erroring. + Ok(Err(project::InProgress)) => Ok(EvaluatedToUnknown), + Err(_) => Ok(EvaluatedToErr), + } + } + + ty::PredicateAtom::ClosureKind(_, closure_substs, kind) => { + match self.infcx.closure_kind(closure_substs) { + Some(closure_kind) => { + if closure_kind.extends(kind) { + Ok(EvaluatedToOk) + } else { + Ok(EvaluatedToErr) + } + } + None => Ok(EvaluatedToAmbig), + } + } + + ty::PredicateAtom::ConstEvaluatable(def_id, substs) => { + match const_evaluatable::is_const_evaluatable( + self.infcx, + def_id, + substs, + obligation.param_env, + obligation.cause.span, + ) { + Ok(()) => Ok(EvaluatedToOk), + Err(ErrorHandled::TooGeneric) => Ok(EvaluatedToAmbig), + Err(_) => Ok(EvaluatedToErr), + } + } + + ty::PredicateAtom::ConstEquate(c1, c2) => { + debug!( + "evaluate_predicate_recursively: equating consts c1={:?} c2={:?}", + c1, c2 + ); + + let evaluate = |c: &'tcx ty::Const<'tcx>| { + if let ty::ConstKind::Unevaluated(def, substs, promoted) = c.val { + self.infcx + .const_eval_resolve( + obligation.param_env, + def, + substs, + promoted, + Some(obligation.cause.span), + ) + .map(|val| ty::Const::from_value(self.tcx(), val, c.ty)) + } else { + Ok(c) + } + }; + + match (evaluate(c1), evaluate(c2)) { + (Ok(c1), Ok(c2)) => { + match self + .infcx() + .at(&obligation.cause, obligation.param_env) + .eq(c1, c2) + { + Ok(_) => Ok(EvaluatedToOk), + Err(_) => Ok(EvaluatedToErr), + } + } + (Err(ErrorHandled::Reported(ErrorReported)), _) + | (_, Err(ErrorHandled::Reported(ErrorReported))) => Ok(EvaluatedToErr), + (Err(ErrorHandled::Linted), _) | (_, Err(ErrorHandled::Linted)) => { + span_bug!( + obligation.cause.span(self.tcx()), + "ConstEquate: const_eval_resolve returned an unexpected error" + ) + } + (Err(ErrorHandled::TooGeneric), _) | (_, Err(ErrorHandled::TooGeneric)) => { + Ok(EvaluatedToAmbig) + } + } + } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for chalk") + } } - } + }) } fn evaluate_trait_predicate_recursively<'o>( @@ -778,14 +797,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if !candidate_set.ambiguous && candidate_set.vec.is_empty() { let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; let self_ty = trait_ref.self_ty(); - let cause = IntercrateAmbiguityCause::DownstreamCrate { - trait_desc: trait_ref.print_only_trait_path().to_string(), - self_desc: if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }, - }; + let cause = + with_no_trimmed_paths(|| IntercrateAmbiguityCause::DownstreamCrate { + trait_desc: trait_ref.print_only_trait_path().to_string(), + self_desc: if self_ty.has_concrete_skeleton() { + Some(self_ty.to_string()) + } else { + None + }, + }); + debug!("evaluate_stack: pushing cause = {:?}", cause); self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); } @@ -1008,158 +1029,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(Some(candidate)) } - fn candidate_from_obligation_no_cache<'o>( - &mut self, - stack: &TraitObligationStack<'o, 'tcx>, - ) -> SelectionResult<'tcx, SelectionCandidate<'tcx>> { - if let Some(conflict) = self.is_knowable(stack) { - debug!("coherence stage: not knowable"); - if self.intercrate_ambiguity_causes.is_some() { - debug!("evaluate_stack: intercrate_ambiguity_causes is some"); - // Heuristics: show the diagnostics when there are no candidates in crate. - if let Ok(candidate_set) = self.assemble_candidates(stack) { - let mut no_candidates_apply = true; - - for c in candidate_set.vec.iter() { - if self.evaluate_candidate(stack, &c)?.may_apply() { - no_candidates_apply = false; - break; - } - } - - if !candidate_set.ambiguous && no_candidates_apply { - let trait_ref = stack.obligation.predicate.skip_binder().trait_ref; - let self_ty = trait_ref.self_ty(); - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = if self_ty.has_concrete_skeleton() { - Some(self_ty.to_string()) - } else { - None - }; - let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } - } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } - }; - debug!("evaluate_stack: pushing cause = {:?}", cause); - self.intercrate_ambiguity_causes.as_mut().unwrap().push(cause); - } - } - } - return Ok(None); - } - - let candidate_set = self.assemble_candidates(stack)?; - - if candidate_set.ambiguous { - debug!("candidate set contains ambig"); - return Ok(None); - } - - let mut candidates = candidate_set.vec; - - debug!("assembled {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - // At this point, we know that each of the entries in the - // candidate set is *individually* applicable. Now we have to - // figure out if they contain mutual incompatibilities. This - // frequently arises if we have an unconstrained input type -- - // for example, we are looking for `$0: Eq` where `$0` is some - // unconstrained type variable. In that case, we'll get a - // candidate which assumes $0 == int, one that assumes `$0 == - // usize`, etc. This spells an ambiguity. - - // If there is more than one candidate, first winnow them down - // by considering extra conditions (nested obligations and so - // forth). We don't winnow if there is exactly one - // candidate. This is a relatively minor distinction but it - // can lead to better inference and error-reporting. An - // example would be if there was an impl: - // - // impl Vec { fn push_clone(...) { ... } } - // - // and we were to see some code `foo.push_clone()` where `boo` - // is a `Vec` and `Bar` does not implement `Clone`. If - // we were to winnow, we'd wind up with zero candidates. - // Instead, we select the right impl now but report "`Bar` does - // not implement `Clone`". - if candidates.len() == 1 { - return self.filter_negative_and_reservation_impls(candidates.pop().unwrap()); - } - - // Winnow, but record the exact outcome of evaluation, which - // is needed for specialization. Propagate overflow if it occurs. - let mut candidates = candidates - .into_iter() - .map(|c| match self.evaluate_candidate(stack, &c) { - Ok(eval) if eval.may_apply() => { - Ok(Some(EvaluatedCandidate { candidate: c, evaluation: eval })) - } - Ok(_) => Ok(None), - Err(OverflowError) => Err(Overflow), - }) - .flat_map(Result::transpose) - .collect::, _>>()?; - - debug!("winnowed to {} candidates for {:?}: {:?}", candidates.len(), stack, candidates); - - let needs_infer = stack.obligation.predicate.needs_infer(); - - // If there are STILL multiple candidates, we can further - // reduce the list by dropping duplicates -- including - // resolving specializations. - if candidates.len() > 1 { - let mut i = 0; - while i < candidates.len() { - let is_dup = (0..candidates.len()).filter(|&j| i != j).any(|j| { - self.candidate_should_be_dropped_in_favor_of( - &candidates[i], - &candidates[j], - needs_infer, - ) - }); - if is_dup { - debug!("Dropping candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - candidates.swap_remove(i); - } else { - debug!("Retaining candidate #{}/{}: {:?}", i, candidates.len(), candidates[i]); - i += 1; - - // If there are *STILL* multiple candidates, give up - // and report ambiguity. - if i > 1 { - debug!("multiple matches, ambig"); - return Ok(None); - } - } - } - } - - // If there are *NO* candidates, then there are no impls -- - // that we know of, anyway. Note that in the case where there - // are unbound type variables within the obligation, it might - // be the case that you could still satisfy the obligation - // from another crate by instantiating the type variables with - // a type from another crate that does have an impl. This case - // is checked for in `evaluate_stack` (and hence users - // who might care about this case, like coherence, should use - // that function). - if candidates.is_empty() { - // If there's an error type, 'downgrade' our result from - // `Err(Unimplemented)` to `Ok(None)`. This helps us avoid - // emitting additional spurious errors, since we're guaranteed - // to have emitted at least one. - if stack.obligation.references_error() { - debug!("no results for error type, treating as ambiguous"); - return Ok(None); - } - return Err(Unimplemented); - } - - // Just one candidate left. - self.filter_negative_and_reservation_impls(candidates.pop().unwrap().candidate) - } - fn is_knowable<'o>(&mut self, stack: &TraitObligationStack<'o, 'tcx>) -> Option { debug!("is_knowable(intercrate={:?})", self.intercrate); @@ -1301,7 +1170,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); let tcx = self.infcx.tcx; - let predicates = match placeholder_trait_predicate.trait_ref.self_ty().kind { + let predicates = match *placeholder_trait_predicate.trait_ref.self_ty().kind() { ty::Projection(ref data) => { tcx.projection_predicates(data.item_def_id).subst(tcx, data.substs) } @@ -1560,7 +1429,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { // NOTE: binder moved to (*) let self_ty = self.infcx.shallow_resolve(obligation.predicate.skip_binder().self_ty()); - match self_ty.kind { + match self_ty.kind() { ty::Infer(ty::IntVar(_) | ty::FloatVar(_)) | ty::Uint(_) | ty::Int(_) @@ -1615,7 +1484,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { use self::BuiltinImplConditions::{Ambiguous, None, Where}; - match self_ty.kind { + match self_ty.kind() { ty::Infer(ty::IntVar(_)) | ty::Infer(ty::FloatVar(_)) | ty::FnDef(..) @@ -1689,7 +1558,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Zed where enum Zed { A(T), B(u32) } -> [i32, u32] /// ``` fn constituent_types_for_ty(&self, t: Ty<'tcx>) -> Vec> { - match t.kind { + match *t.kind() { ty::Uint(_) | ty::Int(_) | ty::Bool @@ -2124,7 +1993,6 @@ trait TraitObligationExt<'tcx> { } impl<'tcx> TraitObligationExt<'tcx> for TraitObligation<'tcx> { - #[allow(unused_comparisons)] fn derived_cause( &self, variant: fn(DerivedObligationCause<'tcx>) -> ObligationCauseCode<'tcx>, diff --git a/src/librustc_trait_selection/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs similarity index 100% rename from src/librustc_trait_selection/traits/specialize/mod.rs rename to compiler/rustc_trait_selection/src/traits/specialize/mod.rs diff --git a/src/librustc_trait_selection/traits/specialize/specialization_graph.rs b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs similarity index 98% rename from src/librustc_trait_selection/traits/specialize/specialization_graph.rs rename to compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs index 56b8354d68..c8bcab6efd 100644 --- a/src/librustc_trait_selection/traits/specialize/specialization_graph.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/specialization_graph.rs @@ -3,6 +3,7 @@ use super::OverlapError; use crate::traits; use rustc_hir::def_id::DefId; use rustc_middle::ty::fast_reject::{self, SimplifiedType}; +use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::{self, TyCtxt, TypeFoldable}; pub use rustc_middle::traits::specialization_graph::*; @@ -102,7 +103,8 @@ impl ChildrenExt for Children { let trait_ref = overlap.impl_header.trait_ref.unwrap(); let self_ty = trait_ref.self_ty(); - OverlapError { + // 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 @@ -115,7 +117,7 @@ impl ChildrenExt for Children { }, intercrate_ambiguity_causes: overlap.intercrate_ambiguity_causes, involves_placeholder: overlap.involves_placeholder, - } + }) }; let report_overlap_error = |overlap: traits::coherence::OverlapResult<'_>, diff --git a/src/librustc_trait_selection/traits/structural_match.rs b/compiler/rustc_trait_selection/src/traits/structural_match.rs similarity index 99% rename from src/librustc_trait_selection/traits/structural_match.rs rename to compiler/rustc_trait_selection/src/traits/structural_match.rs index 78186a5e8a..4f7fa2c398 100644 --- a/src/librustc_trait_selection/traits/structural_match.rs +++ b/compiler/rustc_trait_selection/src/traits/structural_match.rs @@ -137,7 +137,7 @@ impl<'a, 'tcx> TypeVisitor<'tcx> for Search<'a, 'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { debug!("Search visiting ty: {:?}", ty); - let (adt_def, substs) = match ty.kind { + let (adt_def, substs) = match *ty.kind() { ty::Adt(adt_def, substs) => (adt_def, substs), ty::Param(_) => { self.found = Some(NonStructuralMatchTy::Param); diff --git a/src/librustc_trait_selection/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs similarity index 100% rename from src/librustc_trait_selection/traits/util.rs rename to compiler/rustc_trait_selection/src/traits/util.rs diff --git a/src/librustc_trait_selection/traits/wf.rs b/compiler/rustc_trait_selection/src/traits/wf.rs similarity index 96% rename from src/librustc_trait_selection/traits/wf.rs rename to compiler/rustc_trait_selection/src/traits/wf.rs index 0ac3c6ffe6..909cd2aa15 100644 --- a/src/librustc_trait_selection/traits/wf.rs +++ b/compiler/rustc_trait_selection/src/traits/wf.rs @@ -7,8 +7,9 @@ use rustc_hir::lang_items::LangItem; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, TypeFoldable, WithConstness}; use rustc_span::Span; -use std::rc::Rc; +use std::iter; +use std::rc::Rc; /// Returns the set of obligations needed to make `arg` well-formed. /// If `arg` contains unresolved inference variables, this may include /// further WF obligations. However, if `arg` IS an unresolved @@ -25,7 +26,7 @@ pub fn obligations<'a, 'tcx>( // Handle the "livelock" case (see comment above) by bailing out if necessary. let arg = match arg.unpack() { GenericArgKind::Type(ty) => { - match ty.kind { + match ty.kind() { ty::Infer(ty::TyVar(_)) => { let resolved_ty = infcx.shallow_resolve(ty); if resolved_ty == ty { @@ -127,6 +128,9 @@ pub fn predicate_obligations<'a, 'tcx>( wf.compute(c1.into()); wf.compute(c2.into()); } + ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("TypeWellFormedFromEnv is only used for Chalk") + } } wf.normalize() @@ -200,7 +204,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // projection coming from another associated type. See // `src/test/ui/associated-types/point-at-type-on-obligation-failure.rs` and // `traits-assoc-type-in-supertrait-bad.rs`. - if let ty::Projection(projection_ty) = proj.ty.kind { + if let ty::Projection(projection_ty) = proj.ty.kind() { let trait_assoc_item = tcx.associated_item(projection_ty.item_def_id); if let Some(impl_item_span) = items.iter().find(|item| item.ident == trait_assoc_item.ident).map(fix_span) @@ -213,7 +217,7 @@ fn extend_cause_with_original_assoc_item_obligation<'tcx>( // An associated item obligation born out of the `trait` failed to be met. An example // can be seen in `ui/associated-types/point-at-type-on-obligation-failure-2.rs`. debug!("extended_cause_with_original_assoc_item_obligation trait proj {:?}", pred); - if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = pred.self_ty().kind { + if let ty::Projection(ty::ProjectionTy { item_def_id, .. }) = *pred.self_ty().kind() { if let Some(impl_item_span) = trait_assoc_items .find(|i| i.def_id == item_def_id) .and_then(|trait_assoc_item| { @@ -412,7 +416,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { } }; - match ty.kind { + match *ty.kind() { ty::Bool | ty::Char | ty::Int(..) @@ -590,7 +594,7 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { // prevention, which happens before this can be reached. ty::Infer(_) => { let ty = self.infcx.shallow_resolve(ty); - if let ty::Infer(ty::TyVar(_)) = ty.kind { + if let ty::Infer(ty::TyVar(_)) = ty.kind() { // Not yet resolved, but we've made progress. let cause = self.cause(traits::MiscObligation); self.out.push(traits::Obligation::new( @@ -613,13 +617,24 @@ impl<'a, 'tcx> WfPredicates<'a, 'tcx> { def_id: DefId, substs: SubstsRef<'tcx>, ) -> Vec> { - let predicates = self.infcx.tcx.predicates_of(def_id).instantiate(self.infcx.tcx, substs); + let predicates = self.infcx.tcx.predicates_of(def_id); + let mut origins = vec![def_id; predicates.predicates.len()]; + let mut head = predicates; + while let Some(parent) = head.parent { + head = self.infcx.tcx.predicates_of(parent); + origins.extend(iter::repeat(parent).take(head.predicates.len())); + } + + let predicates = predicates.instantiate(self.infcx.tcx, substs); + debug_assert_eq!(predicates.predicates.len(), origins.len()); + predicates .predicates .into_iter() .zip(predicates.spans.into_iter()) - .map(|(pred, span)| { - let cause = self.cause(traits::BindingObligation(def_id, span)); + .zip(origins.into_iter().rev()) + .map(|((pred, span), origin_def_id)| { + let cause = self.cause(traits::BindingObligation(origin_def_id, span)); traits::Obligation::new(cause, self.param_env, pred) }) .filter(|pred| !pred.has_escaping_bound_vars()) diff --git a/compiler/rustc_traits/Cargo.toml b/compiler/rustc_traits/Cargo.toml new file mode 100644 index 0000000000..6d49571827 --- /dev/null +++ b/compiler/rustc_traits/Cargo.toml @@ -0,0 +1,20 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_traits" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_hir = { path = "../rustc_hir" } +rustc_index = { path = "../rustc_index" } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +chalk-ir = "0.29.0" +chalk-solve = "0.29.0" +chalk-engine = "0.29.0" +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_infer = { path = "../rustc_infer" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_traits/chalk/db.rs b/compiler/rustc_traits/src/chalk/db.rs similarity index 57% rename from src/librustc_traits/chalk/db.rs rename to compiler/rustc_traits/src/chalk/db.rs index 4c8be8eb61..828ee6dea6 100644 --- a/src/librustc_traits/chalk/db.rs +++ b/compiler/rustc_traits/src/chalk/db.rs @@ -8,7 +8,7 @@ use rustc_middle::traits::ChalkRustInterner as RustInterner; use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt}; +use rustc_middle::ty::{self, AssocItemContainer, AssocKind, TyCtxt, TypeFoldable}; use rustc_hir::def_id::DefId; @@ -17,11 +17,13 @@ use rustc_span::symbol::sym; use std::fmt; use std::sync::Arc; -use crate::chalk::lowering::LowerInto; +use crate::chalk::lowering::{self, LowerInto}; +use rustc_ast::ast; pub struct RustIrDatabase<'tcx> { - pub tcx: TyCtxt<'tcx>, - pub interner: RustInterner<'tcx>, + pub(crate) interner: RustInterner<'tcx>, + pub(crate) restatic_placeholder: ty::Region<'tcx>, + pub(crate) reempty_placeholder: ty::Region<'tcx>, } impl fmt::Debug for RustIrDatabase<'_> { @@ -30,6 +32,26 @@ impl fmt::Debug for RustIrDatabase<'_> { } } +impl<'tcx> RustIrDatabase<'tcx> { + fn where_clauses_for( + &self, + def_id: DefId, + bound_vars: SubstsRef<'tcx>, + ) -> Vec>> { + let predicates = self.interner.tcx.predicates_of(def_id).predicates; + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + predicates + .iter() + .map(|(wc, _)| wc.subst(self.interner.tcx, bound_vars)) + .map(|wc| wc.fold_with(&mut regions_substitutor)) + .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect() + } +} + impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'tcx> { fn interner(&self) -> &RustInterner<'tcx> { &self.interner @@ -40,7 +62,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t assoc_type_id: chalk_ir::AssocTypeId>, ) -> Arc>> { let def_id = assoc_type_id.0; - let assoc_item = self.tcx.associated_item(def_id); + let assoc_item = self.interner.tcx.associated_item(def_id); let trait_def_id = match assoc_item.container { AssocItemContainer::TraitContainer(def_id) => def_id, _ => unimplemented!("Not possible??"), @@ -49,16 +71,12 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t AssocKind::Type => {} _ => unimplemented!("Not possible??"), } - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); // FIXME(chalk): this really isn't right I don't think. The functions // for GATs are a bit hard to figure out. Are these supposed to be where // clauses or bounds? - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); Arc::new(chalk_solve::rust_ir::AssociatedTyDatum { trait_id: chalk_ir::TraitId(trait_def_id), @@ -76,16 +94,15 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t trait_id: chalk_ir::TraitId>, ) -> Arc>> { let def_id = trait_id.0; - let trait_def = self.tcx.trait_def(def_id); + let trait_def = self.interner.tcx.trait_def(def_id); - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + + let where_clauses = self.where_clauses_for(def_id, bound_vars); + let associated_ty_ids: Vec<_> = self + .interner .tcx .associated_items(def_id) .in_definition_order() @@ -93,24 +110,37 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t .map(|i| chalk_ir::AssocTypeId(i.def_id)) .collect(); - let well_known = - if self.tcx.lang_items().sized_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Sized) - } else if self.tcx.lang_items().copy_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Copy) - } else if self.tcx.lang_items().clone_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Clone) - } else if self.tcx.lang_items().drop_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Drop) - } else if self.tcx.lang_items().fn_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::Fn) - } else if self.tcx.lang_items().fn_once_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce) - } else if self.tcx.lang_items().fn_mut_trait().map(|t| def_id == t).unwrap_or(false) { - Some(chalk_solve::rust_ir::WellKnownTrait::FnMut) - } else { - None - }; + let well_known = if self.interner.tcx.lang_items().sized_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Sized) + } else if self.interner.tcx.lang_items().copy_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Copy) + } else if self.interner.tcx.lang_items().clone_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Clone) + } else if self.interner.tcx.lang_items().drop_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Drop) + } else if self.interner.tcx.lang_items().fn_trait() == Some(def_id) { + Some(chalk_solve::rust_ir::WellKnownTrait::Fn) + } else if self + .interner + .tcx + .lang_items() + .fn_once_trait() + .map(|t| def_id == t) + .unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::FnOnce) + } else if self + .interner + .tcx + .lang_items() + .fn_mut_trait() + .map(|t| def_id == t) + .unwrap_or(false) + { + Some(chalk_solve::rust_ir::WellKnownTrait::FnMut) + } else { + None + }; Arc::new(chalk_solve::rust_ir::TraitDatum { id: trait_id, binders: chalk_ir::Binders::new( @@ -121,7 +151,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t auto: trait_def.has_auto_impl, marker: trait_def.is_marker, upstream: !def_id.is_local(), - fundamental: self.tcx.has_attr(def_id, sym::fundamental), + fundamental: self.interner.tcx.has_attr(def_id, sym::fundamental), non_enumerable: true, coinductive: false, }, @@ -136,45 +166,50 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t ) -> Arc>> { let adt_def = adt_id.0; - let bound_vars = bound_vars_for_item(self.tcx, adt_def.did); + let bound_vars = bound_vars_for_item(self.interner.tcx, adt_def.did); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_of(adt_def.did).predicates; - let where_clauses: Vec<_> = predicates + let where_clauses = self.where_clauses_for(adt_def.did, bound_vars); + + let variants: Vec<_> = adt_def + .variants .iter() - .map(|(wc, _)| wc.subst(self.tcx, bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)) - .collect(); - let fields = match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => { - let variant = adt_def.non_enum_variant(); - variant + .map(|variant| chalk_solve::rust_ir::AdtVariantDatum { + fields: variant .fields .iter() - .map(|field| { - self.tcx - .type_of(field.did) - .subst(self.tcx, bound_vars) - .lower_into(&self.interner) - }) - .collect() - } - // FIXME(chalk): handle enums; force_impl_for requires this - ty::AdtKind::Enum => vec![], - }; - let struct_datum = Arc::new(chalk_solve::rust_ir::AdtDatum { + .map(|field| field.ty(self.interner.tcx, bound_vars).lower_into(&self.interner)) + .collect(), + }) + .collect(); + Arc::new(chalk_solve::rust_ir::AdtDatum { id: adt_id, binders: chalk_ir::Binders::new( binders, - chalk_solve::rust_ir::AdtDatumBound { fields, where_clauses }, + chalk_solve::rust_ir::AdtDatumBound { variants, where_clauses }, ), flags: chalk_solve::rust_ir::AdtFlags { upstream: !adt_def.did.is_local(), fundamental: adt_def.is_fundamental(), phantom_data: adt_def.is_phantom_data(), }, - }); - struct_datum + kind: match adt_def.adt_kind() { + ty::AdtKind::Struct => chalk_solve::rust_ir::AdtKind::Struct, + ty::AdtKind::Union => chalk_solve::rust_ir::AdtKind::Union, + ty::AdtKind::Enum => chalk_solve::rust_ir::AdtKind::Enum, + }, + }) + } + + fn adt_repr( + &self, + adt_id: chalk_ir::AdtId>, + ) -> chalk_solve::rust_ir::AdtRepr { + let adt_def = adt_id.0; + chalk_solve::rust_ir::AdtRepr { + repr_c: adt_def.repr.c(), + repr_packed: adt_def.repr.packed(), + } } fn fn_def_datum( @@ -182,30 +217,25 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t fn_def_id: chalk_ir::FnDefId>, ) -> Arc>> { let def_id = fn_def_id.0; - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); - let sig = self.tcx.fn_sig(def_id); - let inputs_and_output = sig.inputs_and_output(); + let sig = self.interner.tcx.fn_sig(def_id); let (inputs_and_output, iobinders, _) = crate::chalk::lowering::collect_bound_vars( &self.interner, - self.tcx, - &inputs_and_output, + self.interner.tcx, + &sig.inputs_and_output().subst(self.interner.tcx, bound_vars), ); let argument_types = inputs_and_output[..inputs_and_output.len() - 1] .iter() - .map(|t| t.subst(self.tcx, &bound_vars).lower_into(&self.interner)) + .map(|t| t.subst(self.interner.tcx, &bound_vars).lower_into(&self.interner)) .collect(); let return_type = inputs_and_output[inputs_and_output.len() - 1] - .subst(self.tcx, &bound_vars) + .subst(self.interner.tcx, &bound_vars) .lower_into(&self.interner); let bound = chalk_solve::rust_ir::FnDefDatumBound { @@ -217,7 +247,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; Arc::new(chalk_solve::rust_ir::FnDefDatum { id: fn_def_id, - abi: sig.abi(), + sig: sig.lower_into(&self.interner), binders: chalk_ir::Binders::new(binders, bound), }) } @@ -227,17 +257,19 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t impl_id: chalk_ir::ImplId>, ) -> Arc>> { let def_id = impl_id.0; - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let trait_ref = self.tcx.impl_trait_ref(def_id).expect("not an impl"); - let trait_ref = trait_ref.subst(self.tcx, bound_vars); + let trait_ref = self.interner.tcx.impl_trait_ref(def_id).expect("not an impl"); + let trait_ref = trait_ref.subst(self.interner.tcx, bound_vars); + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + let trait_ref = trait_ref.fold_with(&mut regions_substitutor); - let predicates = self.tcx.predicates_of(def_id).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(def_id, bound_vars); let value = chalk_solve::rust_ir::ImplDatumBound { trait_ref: trait_ref.lower_into(&self.interner), @@ -256,6 +288,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t &self, trait_id: chalk_ir::TraitId>, parameters: &[chalk_ir::GenericArg>], + _binders: &chalk_ir::CanonicalVarKinds>, ) -> Vec>> { let def_id = trait_id.0; @@ -263,14 +296,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t // require us to be able to interconvert `Ty<'tcx>`, and we're // not there yet. - let all_impls = self.tcx.all_impls(def_id); + let all_impls = self.interner.tcx.all_impls(def_id); let matched_impls = all_impls.filter(|impl_def_id| { use chalk_ir::could_match::CouldMatch; - let trait_ref = self.tcx.impl_trait_ref(*impl_def_id).unwrap(); - let bound_vars = bound_vars_for_item(self.tcx, *impl_def_id); + let trait_ref = self.interner.tcx.impl_trait_ref(*impl_def_id).unwrap(); + let bound_vars = bound_vars_for_item(self.interner.tcx, *impl_def_id); let self_ty = trait_ref.self_ty(); - let self_ty = self_ty.subst(self.tcx, bound_vars); + let self_ty = self_ty.subst(self.interner.tcx, bound_vars); + let mut regions_substitutor = lowering::RegionsSubstitutor::new( + self.interner.tcx, + self.restatic_placeholder, + self.reempty_placeholder, + ); + let self_ty = self_ty.fold_with(&mut regions_substitutor); let lowered_ty = self_ty.lower_into(&self.interner); parameters[0].assert_ty_ref(&self.interner).could_match(&self.interner, &lowered_ty) @@ -283,21 +322,75 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t fn impl_provided_for( &self, auto_trait_id: chalk_ir::TraitId>, - adt_id: chalk_ir::AdtId>, + app_ty: &chalk_ir::ApplicationTy>, ) -> bool { + use chalk_ir::Scalar::*; + use chalk_ir::TypeName::*; + let trait_def_id = auto_trait_id.0; - let adt_def = adt_id.0; - let all_impls = self.tcx.all_impls(trait_def_id); + let all_impls = self.interner.tcx.all_impls(trait_def_id); for impl_def_id in all_impls { - let trait_ref = self.tcx.impl_trait_ref(impl_def_id).unwrap(); + let trait_ref = self.interner.tcx.impl_trait_ref(impl_def_id).unwrap(); let self_ty = trait_ref.self_ty(); - match self_ty.kind { - ty::Adt(impl_adt_def, _) => { - if impl_adt_def == adt_def { - return true; + let provides = match (self_ty.kind(), app_ty.name) { + (&ty::Adt(impl_adt_def, ..), Adt(id)) => impl_adt_def.did == id.0.did, + (_, AssociatedType(_ty_id)) => { + // FIXME(chalk): See https://github.com/rust-lang/rust/pull/77152#discussion_r494484774 + false + } + (ty::Bool, Scalar(Bool)) => true, + (ty::Char, Scalar(Char)) => true, + (ty::Int(ty1), Scalar(Int(ty2))) => match (ty1, ty2) { + (ast::IntTy::Isize, chalk_ir::IntTy::Isize) + | (ast::IntTy::I8, chalk_ir::IntTy::I8) + | (ast::IntTy::I16, chalk_ir::IntTy::I16) + | (ast::IntTy::I32, chalk_ir::IntTy::I32) + | (ast::IntTy::I64, chalk_ir::IntTy::I64) + | (ast::IntTy::I128, chalk_ir::IntTy::I128) => true, + _ => false, + }, + (ty::Uint(ty1), Scalar(Uint(ty2))) => match (ty1, ty2) { + (ast::UintTy::Usize, chalk_ir::UintTy::Usize) + | (ast::UintTy::U8, chalk_ir::UintTy::U8) + | (ast::UintTy::U16, chalk_ir::UintTy::U16) + | (ast::UintTy::U32, chalk_ir::UintTy::U32) + | (ast::UintTy::U64, chalk_ir::UintTy::U64) + | (ast::UintTy::U128, chalk_ir::UintTy::U128) => true, + _ => false, + }, + (ty::Float(ty1), Scalar(Float(ty2))) => match (ty1, ty2) { + (ast::FloatTy::F32, chalk_ir::FloatTy::F32) + | (ast::FloatTy::F64, chalk_ir::FloatTy::F64) => true, + _ => false, + }, + (&ty::Tuple(..), Tuple(..)) => true, + (&ty::Array(..), Array) => true, + (&ty::Slice(..), Slice) => true, + (&ty::RawPtr(type_and_mut), Raw(mutability)) => { + match (type_and_mut.mutbl, mutability) { + (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, + (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, } } - _ => {} + (&ty::Ref(.., mutability1), Ref(mutability2)) => match (mutability1, mutability2) { + (ast::Mutability::Mut, chalk_ir::Mutability::Mut) => true, + (ast::Mutability::Mut, chalk_ir::Mutability::Not) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Mut) => false, + (ast::Mutability::Not, chalk_ir::Mutability::Not) => true, + }, + (&ty::Opaque(def_id, ..), OpaqueType(opaque_ty_id)) => def_id == opaque_ty_id.0, + (&ty::FnDef(def_id, ..), FnDef(fn_def_id)) => def_id == fn_def_id.0, + (&ty::Str, Str) => true, + (&ty::Never, Never) => true, + (&ty::Closure(def_id, ..), Closure(closure_id)) => def_id == closure_id.0, + (&ty::Foreign(def_id), Foreign(foreign_def_id)) => def_id == foreign_def_id.0, + (&ty::Error(..), Error) => false, + _ => false, + }; + if provides { + return true; } } false @@ -308,7 +401,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t associated_ty_id: chalk_solve::rust_ir::AssociatedTyValueId>, ) -> Arc>> { let def_id = associated_ty_id.0; - let assoc_item = self.tcx.associated_item(def_id); + let assoc_item = self.interner.tcx.associated_item(def_id); let impl_id = match assoc_item.container { AssocItemContainer::TraitContainer(def_id) => def_id, _ => unimplemented!("Not possible??"), @@ -317,9 +410,9 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t AssocKind::Type => {} _ => unimplemented!("Not possible??"), } - let bound_vars = bound_vars_for_item(self.tcx, def_id); + let bound_vars = bound_vars_for_item(self.interner.tcx, def_id); let binders = binders_for(&self.interner, bound_vars); - let ty = self.tcx.type_of(def_id); + let ty = self.interner.tcx.type_of(def_id); Arc::new(chalk_solve::rust_ir::AssociatedTyValue { impl_id: chalk_ir::ImplId(impl_id), @@ -346,78 +439,20 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t &self, opaque_ty_id: chalk_ir::OpaqueTyId>, ) -> Arc>> { - let bound_vars = bound_vars_for_item(self.tcx, opaque_ty_id.0); + let bound_vars = bound_vars_for_item(self.interner.tcx, opaque_ty_id.0); let binders = binders_for(&self.interner, bound_vars); - let predicates = self.tcx.predicates_defined_on(opaque_ty_id.0).predicates; - let where_clauses: Vec<_> = predicates - .iter() - .map(|(wc, _)| wc.subst(self.tcx, &bound_vars)) - .filter_map(|wc| LowerInto::>>>::lower_into(wc, &self.interner)).collect(); + let where_clauses = self.where_clauses_for(opaque_ty_id.0, bound_vars); let value = chalk_solve::rust_ir::OpaqueTyDatumBound { - bounds: chalk_ir::Binders::new(binders, where_clauses), + bounds: chalk_ir::Binders::new(binders.clone(), vec![]), + where_clauses: chalk_ir::Binders::new(binders, where_clauses), }; Arc::new(chalk_solve::rust_ir::OpaqueTyDatum { opaque_ty_id, - bound: chalk_ir::Binders::new(chalk_ir::VariableKinds::new(&self.interner), value), + bound: chalk_ir::Binders::empty(&self.interner, value), }) } - /// Since Chalk can't handle all Rust types currently, we have to handle - /// some specially for now. Over time, these `Some` returns will change to - /// `None` and eventually this function will be removed. - fn force_impl_for( - &self, - well_known: chalk_solve::rust_ir::WellKnownTrait, - ty: &chalk_ir::TyData>, - ) -> Option { - use chalk_ir::TyData::*; - match well_known { - chalk_solve::rust_ir::WellKnownTrait::Sized => match ty { - Apply(apply) => match apply.name { - chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => None, - ty::AdtKind::Enum => { - let constraint = self.tcx.adt_sized_constraint(adt_def.did); - if !constraint.0.is_empty() { unimplemented!() } else { Some(true) } - } - }, - _ => None, - }, - Dyn(_) - | Alias(_) - | Placeholder(_) - | Function(_) - | InferenceVar(_, _) - | BoundVar(_) => None, - }, - chalk_solve::rust_ir::WellKnownTrait::Copy - | chalk_solve::rust_ir::WellKnownTrait::Clone => match ty { - Apply(apply) => match apply.name { - chalk_ir::TypeName::Adt(chalk_ir::AdtId(adt_def)) => match adt_def.adt_kind() { - ty::AdtKind::Struct | ty::AdtKind::Union => None, - ty::AdtKind::Enum => { - let constraint = self.tcx.adt_sized_constraint(adt_def.did); - if !constraint.0.is_empty() { unimplemented!() } else { Some(true) } - } - }, - _ => None, - }, - Dyn(_) - | Alias(_) - | Placeholder(_) - | Function(_) - | InferenceVar(_, _) - | BoundVar(_) => None, - }, - chalk_solve::rust_ir::WellKnownTrait::Drop => None, - chalk_solve::rust_ir::WellKnownTrait::Fn => None, - chalk_solve::rust_ir::WellKnownTrait::FnMut => None, - chalk_solve::rust_ir::WellKnownTrait::FnOnce => None, - chalk_solve::rust_ir::WellKnownTrait::Unsize => None, - } - } - fn program_clauses_for_env( &self, environment: &chalk_ir::Environment>, @@ -430,21 +465,24 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t well_known_trait: chalk_solve::rust_ir::WellKnownTrait, ) -> Option>> { use chalk_solve::rust_ir::WellKnownTrait::*; + let lang_items = self.interner.tcx.lang_items(); let def_id = match well_known_trait { - Sized => self.tcx.lang_items().sized_trait(), - Copy => self.tcx.lang_items().copy_trait(), - Clone => self.tcx.lang_items().clone_trait(), - Drop => self.tcx.lang_items().drop_trait(), - Fn => self.tcx.lang_items().fn_trait(), - FnMut => self.tcx.lang_items().fn_mut_trait(), - FnOnce => self.tcx.lang_items().fn_once_trait(), - Unsize => self.tcx.lang_items().unsize_trait(), + Sized => lang_items.sized_trait(), + Copy => lang_items.copy_trait(), + Clone => lang_items.clone_trait(), + Drop => lang_items.drop_trait(), + Fn => lang_items.fn_trait(), + FnMut => lang_items.fn_mut_trait(), + FnOnce => lang_items.fn_once_trait(), + Unsize => lang_items.unsize_trait(), + Unpin => lang_items.unpin_trait(), + CoerceUnsized => lang_items.coerce_unsized_trait(), }; def_id.map(chalk_ir::TraitId) } fn is_object_safe(&self, trait_id: chalk_ir::TraitId>) -> bool { - self.tcx.is_object_safe(trait_id.0) + self.interner.tcx.is_object_safe(trait_id.0) } fn hidden_opaque_type( @@ -452,7 +490,10 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _id: chalk_ir::OpaqueTyId>, ) -> chalk_ir::Ty> { // FIXME(chalk): actually get hidden ty - self.tcx.mk_ty(ty::Tuple(self.tcx.intern_substs(&[]))).lower_into(&self.interner) + self.interner + .tcx + .mk_ty(ty::Tuple(self.interner.tcx.intern_substs(&[]))) + .lower_into(&self.interner) } fn closure_kind( @@ -460,7 +501,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _closure_id: chalk_ir::ClosureId>, substs: &chalk_ir::Substitution>, ) -> chalk_solve::rust_ir::ClosureKind { - let kind = &substs.parameters(&self.interner)[substs.len(&self.interner) - 3]; + let kind = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 3]; match kind.assert_ty_ref(&self.interner).data(&self.interner) { chalk_ir::TyData::Apply(apply) => match apply.name { chalk_ir::TypeName::Scalar(scalar) => match scalar { @@ -484,10 +525,10 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t substs: &chalk_ir::Substitution>, ) -> chalk_ir::Binders>> { - let sig = &substs.parameters(&self.interner)[substs.len(&self.interner) - 2]; + let sig = &substs.as_slice(&self.interner)[substs.len(&self.interner) - 2]; match sig.assert_ty_ref(&self.interner).data(&self.interner) { chalk_ir::TyData::Function(f) => { - let substitution = f.substitution.parameters(&self.interner); + let substitution = f.substitution.as_slice(&self.interner); let return_type = substitution.last().unwrap().assert_ty_ref(&self.interner).clone(); // Closure arguments are tupled @@ -506,7 +547,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t }; chalk_ir::Binders::new( - chalk_ir::VariableKinds::from( + chalk_ir::VariableKinds::from_iter( &self.interner, (0..f.num_binders).map(|_| chalk_ir::VariableKind::Lifetime), ), @@ -523,7 +564,7 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t substs: &chalk_ir::Substitution>, ) -> chalk_ir::Binders>> { let inputs_and_output = self.closure_inputs_and_output(_closure_id, substs); - let tuple = substs.parameters(&self.interner).last().unwrap().assert_ty_ref(&self.interner); + let tuple = substs.as_slice(&self.interner).last().unwrap().assert_ty_ref(&self.interner); inputs_and_output.map_ref(|_| tuple.clone()) } @@ -532,8 +573,8 @@ impl<'tcx> chalk_solve::RustIrDatabase> for RustIrDatabase<'t _closure_id: chalk_ir::ClosureId>, substs: &chalk_ir::Substitution>, ) -> chalk_ir::Substitution> { - let substitution = &substs.parameters(&self.interner)[0..substs.len(&self.interner) - 3]; - chalk_ir::Substitution::from(&self.interner, substitution) + let substitution = &substs.as_slice(&self.interner)[0..substs.len(&self.interner) - 3]; + chalk_ir::Substitution::from_iter(&self.interner, substitution) } } @@ -573,7 +614,7 @@ fn binders_for<'tcx>( interner: &RustInterner<'tcx>, bound_vars: SubstsRef<'tcx>, ) -> chalk_ir::VariableKinds> { - chalk_ir::VariableKinds::from( + chalk_ir::VariableKinds::from_iter( interner, bound_vars.iter().map(|arg| match arg.unpack() { ty::subst::GenericArgKind::Lifetime(_re) => chalk_ir::VariableKind::Lifetime, diff --git a/src/librustc_traits/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs similarity index 59% rename from src/librustc_traits/chalk/lowering.rs rename to compiler/rustc_traits/src/chalk/lowering.rs index a043fa3f4c..1e1841a57f 100644 --- a/src/librustc_traits/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -31,9 +31,7 @@ //! not. To lower anything wrapped in a `Binder`, we first deeply find any bound //! variables from the current `Binder`. -use rustc_middle::traits::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, ChalkRustInterner as RustInterner, -}; +use rustc_middle::traits::{ChalkEnvironmentAndGoal, ChalkRustInterner as RustInterner}; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::{GenericArg, GenericArgKind, SubstsRef}; use rustc_middle::ty::{ @@ -41,10 +39,10 @@ use rustc_middle::ty::{ }; use rustc_span::def_id::DefId; +use chalk_ir::{FnSig, ForeignDefId}; +use rustc_hir::Unsafety; use std::collections::btree_map::{BTreeMap, Entry}; -use chalk_ir::fold::shift::Shift; - /// Essentially an `Into` with a `&RustInterner` parameter crate trait LowerInto<'tcx, T> { /// Lower a rustc construct (e.g., `ty::TraitPredicate`) to a chalk type, consuming `self`. @@ -56,7 +54,13 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Substitution>> for Subst self, interner: &RustInterner<'tcx>, ) -> chalk_ir::Substitution> { - chalk_ir::Substitution::from(interner, self.iter().map(|s| s.lower_into(interner))) + chalk_ir::Substitution::from_iter(interner, self.iter().map(|s| s.lower_into(interner))) + } +} + +impl<'tcx> LowerInto<'tcx, SubstsRef<'tcx>> for &chalk_ir::Substitution> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> SubstsRef<'tcx> { + interner.tcx.mk_substs(self.iter(interner).map(|subst| subst.lower_into(interner))) } } @@ -76,107 +80,51 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment, ) -> chalk_ir::InEnvironment>> { - let clauses = self.environment.into_iter().filter_map(|clause| match clause { - ChalkEnvironmentClause::Predicate(predicate) => { - // FIXME(chalk): forall - match predicate.bound_atom(interner.tcx).skip_binder() { - ty::PredicateAtom::Trait(predicate, _) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::FromEnv( - chalk_ir::FromEnv::Trait( - predicate.trait_ref.lower_into(interner), - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives( - chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }, - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - // FIXME(chalk): need to add TypeOutlives - ty::PredicateAtom::TypeOutlives(_) => None, - ty::PredicateAtom::Projection(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - binders, - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq( - predicate.lower_into(interner), - ), - ), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ) - } - ty::PredicateAtom::WellFormed(..) - | ty::PredicateAtom::ObjectSafe(..) - | ty::PredicateAtom::ClosureKind(..) - | ty::PredicateAtom::Subtype(..) - | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => { - bug!("unexpected predicate {}", predicate) - } + let clauses = self.environment.into_iter().map(|predicate| { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &predicate.bound_atom(interner.tcx)); + let consequence = match predicate { + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => { + chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))) } - } - ChalkEnvironmentClause::TypeFromEnv(ty) => Some( - chalk_ir::ProgramClauseData(chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), - chalk_ir::ProgramClauseImplication { - consequence: chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty( - ty.lower_into(interner).shifted_in(interner), - )), - conditions: chalk_ir::Goals::new(interner), - priority: chalk_ir::ClausePriority::High, - }, - )) - .intern(interner), - ), + ty::PredicateAtom::Trait(predicate, _) => chalk_ir::DomainGoal::FromEnv( + chalk_ir::FromEnv::Trait(predicate.trait_ref.lower_into(interner)), + ), + ty::PredicateAtom::RegionOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::TypeOutlives(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }), + ), + ty::PredicateAtom::Projection(predicate) => chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), + ), + ty::PredicateAtom::WellFormed(..) + | ty::PredicateAtom::ObjectSafe(..) + | ty::PredicateAtom::ClosureKind(..) + | ty::PredicateAtom::Subtype(..) + | ty::PredicateAtom::ConstEvaluatable(..) + | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", predicate), + }; + let value = chalk_ir::ProgramClauseImplication { + consequence, + conditions: chalk_ir::Goals::empty(interner), + priority: chalk_ir::ClausePriority::High, + constraints: chalk_ir::Constraints::empty(interner), + }; + chalk_ir::ProgramClauseData(chalk_ir::Binders::new(binders, value)).intern(interner) }); let goal: chalk_ir::GoalData> = self.goal.lower_into(&interner); chalk_ir::InEnvironment { environment: chalk_ir::Environment { - clauses: chalk_ir::ProgramClauses::from(&interner, clauses), + clauses: chalk_ir::ProgramClauses::from_iter(&interner, clauses), }, goal: goal.intern(&interner), } @@ -185,63 +133,52 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::InEnvironment LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predicate<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - // FIXME(chalk): forall - match self.bound_atom(interner.tcx).skip_binder() { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + + let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { - ty::Binder::bind(predicate).lower_into(interner) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), + )) } ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - )) - .intern(interner), - ), - ) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + }), + )) } - // FIXME(chalk): TypeOutlives - ty::PredicateAtom::TypeOutlives(_predicate) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + ty::PredicateAtom::TypeOutlives(predicate) => { + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + }), + )) } ty::PredicateAtom::Projection(predicate) => { - ty::Binder::bind(predicate).lower_into(interner) + chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( + chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner)), + )) } ty::PredicateAtom::WellFormed(arg) => match arg.unpack() { - GenericArgKind::Type(ty) => match ty.kind { + GenericArgKind::Type(ty) => match ty.kind() { // FIXME(chalk): In Chalk, a placeholder is WellFormed if it // `FromEnv`. However, when we "lower" Params, we don't update // the environment. - ty::Placeholder(..) => chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)), - - _ => { - let (ty, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &ty::Binder::bind(ty)); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( - chalk_ir::WellFormed::Ty(ty.lower_into(interner)), - )) - .intern(interner), - ), - ) + ty::Placeholder(..) => { + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } + + _ => chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::WellFormed( + chalk_ir::WellFormed::Ty(ty.lower_into(interner)), + )), }, // FIXME(chalk): handle well formed consts GenericArgKind::Const(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } GenericArgKind::Lifetime(lt) => bug!("unexpect well formed predicate: {:?}", lt), }, @@ -258,9 +195,17 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> for ty::Predi | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) | ty::PredicateAtom::ConstEquate(..) => { - chalk_ir::GoalData::All(chalk_ir::Goals::new(interner)) + chalk_ir::GoalData::All(chalk_ir::Goals::empty(interner)) } - } + ty::PredicateAtom::TypeWellFormedFromEnv(ty) => chalk_ir::GoalData::DomainGoal( + chalk_ir::DomainGoal::FromEnv(chalk_ir::FromEnv::Ty(ty.lower_into(interner))), + ), + }; + + chalk_ir::GoalData::Quantified( + chalk_ir::QuantifierKind::ForAll, + chalk_ir::Binders::new(binders, value.intern(interner)), + ) } } @@ -275,25 +220,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::TraitRef>> } } -impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> - for ty::PolyTraitPredicate<'tcx> -{ - fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::Implemented(ty.trait_ref.lower_into(interner)), - )) - .intern(interner), - ), - ) - } -} - impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq>> for rustc_middle::ty::ProjectionPredicate<'tcx> { @@ -305,25 +231,6 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::AliasEq>> } } -impl<'tcx> LowerInto<'tcx, chalk_ir::GoalData>> - for ty::PolyProjectionPredicate<'tcx> -{ - fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GoalData> { - let (ty, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); - - chalk_ir::GoalData::Quantified( - chalk_ir::QuantifierKind::ForAll, - chalk_ir::Binders::new( - binders, - chalk_ir::GoalData::DomainGoal(chalk_ir::DomainGoal::Holds( - chalk_ir::WhereClause::AliasEq(ty.lower_into(interner)), - )) - .intern(interner), - ), - ) - } -} - impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Ty> { use chalk_ir::TyData; @@ -340,7 +247,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { let uint = |i| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Uint(i)), empty()); let float = |f| apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Float(f)), empty()); - match self.kind { + match *self.kind() { Bool => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Bool), empty()), Char => apply(chalk_ir::TypeName::Scalar(chalk_ir::Scalar::Char), empty()), Int(ty) => match ty { @@ -364,7 +271,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { ast::FloatTy::F64 => float(chalk_ir::FloatTy::F64), }, Adt(def, substs) => apply(struct_ty(def.did), substs.lower_into(interner)), - Foreign(_def_id) => unimplemented!(), + Foreign(def_id) => apply(chalk_ir::TypeName::Foreign(ForeignDefId(def_id)), empty()), Str => apply(chalk_ir::TypeName::Str, empty()), Array(ty, len) => { let value = match len.val { @@ -381,7 +288,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { }; apply( chalk_ir::TypeName::Array, - chalk_ir::Substitution::from( + chalk_ir::Substitution::from_iter( interner, &[ chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner), @@ -415,7 +322,7 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { }; apply( name, - chalk_ir::Substitution::from( + chalk_ir::Substitution::from_iter( interner, &[ chalk_ir::GenericArgData::Lifetime(region.lower_into(interner)) @@ -432,9 +339,10 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { FnPtr(sig) => { let (inputs_and_outputs, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &sig.inputs_and_output()); - TyData::Function(chalk_ir::Fn { + TyData::Function(chalk_ir::FnPointer { num_binders: binders.len(interner), - substitution: chalk_ir::Substitution::from( + sig: sig.lower_into(interner), + substitution: chalk_ir::Substitution::from_iter( interner, inputs_and_outputs.iter().map(|ty| { chalk_ir::GenericArgData::Ty(ty.lower_into(interner)).intern(interner) @@ -485,6 +393,112 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Ty>> for Ty<'tcx> { } } +impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> Ty<'tcx> { + use chalk_ir::TyData; + use rustc_ast::ast; + + let kind = match self.data(interner) { + TyData::Apply(application_ty) => match application_ty.name { + chalk_ir::TypeName::Adt(struct_id) => { + ty::Adt(struct_id.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Scalar(scalar) => match scalar { + chalk_ir::Scalar::Bool => ty::Bool, + chalk_ir::Scalar::Char => ty::Char, + chalk_ir::Scalar::Int(int_ty) => match int_ty { + chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize), + chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8), + chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16), + chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32), + chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64), + chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128), + }, + chalk_ir::Scalar::Uint(int_ty) => match int_ty { + chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize), + chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8), + chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16), + chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32), + chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64), + chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128), + }, + chalk_ir::Scalar::Float(float_ty) => match float_ty { + chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32), + chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64), + }, + }, + chalk_ir::TypeName::Array => unimplemented!(), + chalk_ir::TypeName::FnDef(id) => { + ty::FnDef(id.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Closure(closure) => { + ty::Closure(closure.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Never => ty::Never, + chalk_ir::TypeName::Tuple(_size) => { + ty::Tuple(application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::Slice => ty::Slice( + application_ty.substitution.as_slice(interner)[0] + .ty(interner) + .unwrap() + .lower_into(interner), + ), + chalk_ir::TypeName::Raw(mutbl) => ty::RawPtr(ty::TypeAndMut { + ty: application_ty.substitution.as_slice(interner)[0] + .ty(interner) + .unwrap() + .lower_into(interner), + mutbl: match mutbl { + chalk_ir::Mutability::Mut => ast::Mutability::Mut, + chalk_ir::Mutability::Not => ast::Mutability::Not, + }, + }), + chalk_ir::TypeName::Ref(mutbl) => ty::Ref( + application_ty.substitution.as_slice(interner)[0] + .lifetime(interner) + .unwrap() + .lower_into(interner), + application_ty.substitution.as_slice(interner)[1] + .ty(interner) + .unwrap() + .lower_into(interner), + match mutbl { + chalk_ir::Mutability::Mut => ast::Mutability::Mut, + chalk_ir::Mutability::Not => ast::Mutability::Not, + }, + ), + chalk_ir::TypeName::Str => ty::Str, + chalk_ir::TypeName::OpaqueType(opaque_ty) => { + ty::Opaque(opaque_ty.0, application_ty.substitution.lower_into(interner)) + } + chalk_ir::TypeName::AssociatedType(assoc_ty) => ty::Projection(ty::ProjectionTy { + substs: application_ty.substitution.lower_into(interner), + item_def_id: assoc_ty.0, + }), + chalk_ir::TypeName::Foreign(def_id) => ty::Foreign(def_id.0), + chalk_ir::TypeName::Error => unimplemented!(), + }, + TyData::Placeholder(placeholder) => ty::Placeholder(ty::Placeholder { + universe: ty::UniverseIndex::from_usize(placeholder.ui.counter), + name: ty::BoundVar::from_usize(placeholder.idx), + }), + TyData::Alias(_alias_ty) => unimplemented!(), + TyData::Function(_quantified_ty) => unimplemented!(), + TyData::BoundVar(_bound) => ty::Bound( + ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize), + ty::BoundTy { + var: ty::BoundVar::from_usize(_bound.index), + kind: ty::BoundTyKind::Anon, + }, + ), + TyData::InferenceVar(_, _) => unimplemented!(), + TyData::Dyn(_) => unimplemented!(), + }; + interner.tcx.mk_ty(kind) + } +} + impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Lifetime> { use rustc_middle::ty::RegionKind::*; @@ -522,6 +536,59 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Lifetime>> for Region<'t } } +impl<'tcx> LowerInto<'tcx, Region<'tcx>> for &chalk_ir::Lifetime> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> Region<'tcx> { + let kind = match self.data(interner) { + chalk_ir::LifetimeData::BoundVar(var) => ty::RegionKind::ReLateBound( + ty::DebruijnIndex::from_u32(var.debruijn.depth()), + ty::BoundRegion::BrAnon(var.index as u32), + ), + chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), + chalk_ir::LifetimeData::Placeholder(p) => { + ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::from_usize(p.ui.counter), + name: ty::BoundRegion::BrAnon(p.idx as u32), + }) + } + chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(), + }; + interner.tcx.mk_region(kind) + } +} + +impl<'tcx> LowerInto<'tcx, chalk_ir::Const>> for ty::Const<'tcx> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::Const> { + let ty = self.ty.lower_into(interner); + let value = match self.val { + ty::ConstKind::Value(val) => { + chalk_ir::ConstValue::Concrete(chalk_ir::ConcreteConst { interned: val }) + } + ty::ConstKind::Bound(db, bound) => chalk_ir::ConstValue::BoundVar( + chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new(db.as_u32()), bound.index()), + ), + _ => unimplemented!("Const not implemented. {:?}", self), + }; + chalk_ir::ConstData { ty, value }.intern(interner) + } +} + +impl<'tcx> LowerInto<'tcx, ty::Const<'tcx>> for &chalk_ir::Const> { + fn lower_into(self, interner: &RustInterner<'tcx>) -> ty::Const<'tcx> { + let data = self.data(interner); + let ty = data.ty.lower_into(interner); + let val = match data.value { + chalk_ir::ConstValue::BoundVar(var) => ty::ConstKind::Bound( + ty::DebruijnIndex::from_u32(var.debruijn.depth()), + ty::BoundVar::from_u32(var.index as u32), + ), + chalk_ir::ConstValue::InferenceVar(_var) => unimplemented!(), + chalk_ir::ConstValue::Placeholder(_p) => unimplemented!(), + chalk_ir::ConstValue::Concrete(c) => ty::ConstKind::Value(c.interned), + }; + ty::Const { ty, val } + } +} + impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg>> for GenericArg<'tcx> { fn lower_into(self, interner: &RustInterner<'tcx>) -> chalk_ir::GenericArg> { match self.unpack() { @@ -531,18 +598,35 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::GenericArg>> for Generic ty::subst::GenericArgKind::Lifetime(lifetime) => { chalk_ir::GenericArgData::Lifetime(lifetime.lower_into(interner)) } - ty::subst::GenericArgKind::Const(_) => chalk_ir::GenericArgData::Ty( - chalk_ir::TyData::Apply(chalk_ir::ApplicationTy { - name: chalk_ir::TypeName::Tuple(0), - substitution: chalk_ir::Substitution::empty(interner), - }) - .intern(interner), - ), + ty::subst::GenericArgKind::Const(c) => { + chalk_ir::GenericArgData::Const(c.lower_into(interner)) + } } .intern(interner) } } +impl<'tcx> LowerInto<'tcx, ty::subst::GenericArg<'tcx>> + for &chalk_ir::GenericArg> +{ + fn lower_into(self, interner: &RustInterner<'tcx>) -> ty::subst::GenericArg<'tcx> { + match self.data(interner) { + chalk_ir::GenericArgData::Ty(ty) => { + let t: Ty<'tcx> = ty.lower_into(interner); + t.into() + } + chalk_ir::GenericArgData::Lifetime(lifetime) => { + let r: Region<'tcx> = lifetime.lower_into(interner); + r.into() + } + chalk_ir::GenericArgData::Const(c) => { + let c: ty::Const<'tcx> = c.lower_into(interner); + interner.tcx.mk_const(c).into() + } + } + } +} + // We lower into an Option here since there are some predicates which Chalk // doesn't have a representation for yet (as a `WhereClause`), but are so common // that we just are accepting the unsoundness for now. The `Option` will @@ -554,41 +638,39 @@ impl<'tcx> LowerInto<'tcx, Option, ) -> Option>> { - // FIXME(chalk): forall - match self.bound_atom(interner.tcx).skip_binder() { + let (predicate, binders, _named_regions) = + collect_bound_vars(interner, interner.tcx, &self.bound_atom(interner.tcx)); + let value = match predicate { ty::PredicateAtom::Trait(predicate, _) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some(chalk_ir::Binders::new( - binders, - chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner)), - )) + Some(chalk_ir::WhereClause::Implemented(predicate.trait_ref.lower_into(interner))) } ty::PredicateAtom::RegionOutlives(predicate) => { - let predicate = ty::Binder::bind(predicate); - let (predicate, binders, _named_regions) = - collect_bound_vars(interner, interner.tcx, &predicate); - - Some(chalk_ir::Binders::new( - binders, - chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { - a: predicate.0.lower_into(interner), - b: predicate.1.lower_into(interner), - }), - )) + Some(chalk_ir::WhereClause::LifetimeOutlives(chalk_ir::LifetimeOutlives { + a: predicate.0.lower_into(interner), + b: predicate.1.lower_into(interner), + })) + } + ty::PredicateAtom::TypeOutlives(predicate) => { + Some(chalk_ir::WhereClause::TypeOutlives(chalk_ir::TypeOutlives { + ty: predicate.0.lower_into(interner), + lifetime: predicate.1.lower_into(interner), + })) + } + ty::PredicateAtom::Projection(predicate) => { + Some(chalk_ir::WhereClause::AliasEq(predicate.lower_into(interner))) } - ty::PredicateAtom::TypeOutlives(_predicate) => None, - ty::PredicateAtom::Projection(_predicate) => None, ty::PredicateAtom::WellFormed(_ty) => None, ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => bug!("unexpected predicate {}", &self), - } + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => { + bug!("unexpected predicate {}", &self) + } + }; + value.map(|value| chalk_ir::Binders::new(binders, value)) } } @@ -601,30 +683,51 @@ impl<'tcx> LowerInto<'tcx, chalk_ir::Binders chalk_ir::Binders>> { let (predicates, binders, _named_regions) = collect_bound_vars(interner, interner.tcx, &self); + let self_ty = interner.tcx.mk_ty(ty::Bound( + // This is going to be wrapped in a binder + ty::DebruijnIndex::from_usize(1), + ty::BoundTy { var: ty::BoundVar::from_usize(0), kind: ty::BoundTyKind::Anon }, + )); let where_clauses = predicates.into_iter().map(|predicate| match predicate { ty::ExistentialPredicate::Trait(ty::ExistentialTraitRef { def_id, substs }) => { chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), + chalk_ir::VariableKinds::empty(interner), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), - substitution: substs.lower_into(interner), + substitution: interner + .tcx + .mk_substs_trait(self_ty, substs) + .lower_into(interner), }), ) } ty::ExistentialPredicate::Projection(_predicate) => unimplemented!(), ty::ExistentialPredicate::AutoTrait(def_id) => chalk_ir::Binders::new( - chalk_ir::VariableKinds::new(interner), + chalk_ir::VariableKinds::empty(interner), chalk_ir::WhereClause::Implemented(chalk_ir::TraitRef { trait_id: chalk_ir::TraitId(def_id), - substitution: chalk_ir::Substitution::empty(interner), + substitution: interner.tcx.mk_substs_trait(self_ty, &[]).lower_into(interner), }), ), }); - let value = chalk_ir::QuantifiedWhereClauses::from(interner, where_clauses); + let value = chalk_ir::QuantifiedWhereClauses::from_iter(interner, where_clauses); chalk_ir::Binders::new(binders, value) } } +impl<'tcx> LowerInto<'tcx, chalk_ir::FnSig>> for ty::Binder> { + fn lower_into(self, _interner: &RustInterner<'_>) -> FnSig> { + chalk_ir::FnSig { + abi: self.abi(), + safety: match self.unsafety() { + Unsafety::Normal => chalk_ir::Safety::Safe, + Unsafety::Unsafe => chalk_ir::Safety::Unsafe, + }, + variadic: self.c_variadic(), + } + } +} + /// To collect bound vars, we have to do two passes. In the first pass, we /// collect all `BoundRegion`s and `ty::Bound`s. In the second pass, we then /// replace `BrNamed` into `BrAnon`. The two separate passes are important, @@ -662,7 +765,8 @@ crate fn collect_bound_vars<'a, 'tcx, T: TypeFoldable<'tcx>>( .or_else(|| bug!("Skipped bound var index: ty={:?}, parameters={:?}", ty, parameters)); }); - let binders = chalk_ir::VariableKinds::from(interner, parameters.into_iter().map(|(_, v)| v)); + let binders = + chalk_ir::VariableKinds::from_iter(interner, parameters.into_iter().map(|(_, v)| v)); (new_ty, binders, named_parameters) } @@ -692,7 +796,7 @@ impl<'tcx> TypeVisitor<'tcx> for BoundVarsCollector<'tcx> { } fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { + match *t.kind() { ty::Bound(debruijn, bound_ty) if debruijn == self.binder_index => { match self.parameters.entry(bound_ty.var.as_u32()) { Entry::Vacant(entry) => { @@ -773,10 +877,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for NamedBoundVarSubstitutor<'a, 'tcx> { result } - fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - t.super_fold_with(self) - } - fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { match r { ty::ReLateBound(index, br) if *index == self.binder_index => match br { @@ -807,16 +907,18 @@ crate struct ParamsSubstitutor<'tcx> { tcx: TyCtxt<'tcx>, binder_index: ty::DebruijnIndex, list: Vec, + next_ty_placeholder: usize, crate params: rustc_data_structures::fx::FxHashMap, crate named_regions: BTreeMap, } impl<'tcx> ParamsSubstitutor<'tcx> { - crate fn new(tcx: TyCtxt<'tcx>) -> Self { + crate fn new(tcx: TyCtxt<'tcx>, next_ty_placeholder: usize) -> Self { ParamsSubstitutor { tcx, binder_index: ty::INNERMOST, list: vec![], + next_ty_placeholder, params: rustc_data_structures::fx::FxHashMap::default(), named_regions: BTreeMap::default(), } @@ -836,19 +938,19 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match *t.kind() { // FIXME(chalk): currently we convert params to placeholders starting at // index `0`. To support placeholders, we'll actually need to do a // first pass to collect placeholders. Then we can insert params after. ty::Placeholder(_) => unimplemented!(), ty::Param(param) => match self.list.iter().position(|r| r == ¶m) { - Some(_idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { + Some(idx) => self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), - name: ty::BoundVar::from_usize(_idx), + name: ty::BoundVar::from_usize(idx), })), None => { self.list.push(param); - let idx = self.list.len() - 1; + let idx = self.list.len() - 1 + self.next_ty_placeholder; self.params.insert(idx, param); self.tcx.mk_ty(ty::Placeholder(ty::PlaceholderType { universe: ty::UniverseIndex::from_usize(0), @@ -884,3 +986,83 @@ impl<'tcx> TypeFolder<'tcx> for ParamsSubstitutor<'tcx> { } } } + +/// Used to collect `Placeholder`s. +crate struct PlaceholdersCollector { + universe_index: ty::UniverseIndex, + crate next_ty_placeholder: usize, + crate next_anon_region_placeholder: u32, +} + +impl PlaceholdersCollector { + crate fn new() -> Self { + PlaceholdersCollector { + universe_index: ty::UniverseIndex::ROOT, + next_ty_placeholder: 0, + next_anon_region_placeholder: 0, + } + } +} + +impl<'tcx> TypeVisitor<'tcx> for PlaceholdersCollector { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match t.kind() { + ty::Placeholder(p) if p.universe == self.universe_index => { + self.next_ty_placeholder = self.next_ty_placeholder.max(p.name.as_usize() + 1); + } + + _ => (), + }; + + t.super_visit_with(self) + } + + fn visit_region(&mut self, r: Region<'tcx>) -> bool { + match r { + ty::RePlaceholder(p) if p.universe == self.universe_index => { + if let ty::BoundRegion::BrAnon(anon) = p.name { + self.next_anon_region_placeholder = self.next_anon_region_placeholder.max(anon); + } + } + + _ => (), + }; + + r.super_visit_with(self) + } +} + +/// Used to substitute specific `Regions`s with placeholders. +crate struct RegionsSubstitutor<'tcx> { + tcx: TyCtxt<'tcx>, + restatic_placeholder: ty::Region<'tcx>, + reempty_placeholder: ty::Region<'tcx>, +} + +impl<'tcx> RegionsSubstitutor<'tcx> { + crate fn new( + tcx: TyCtxt<'tcx>, + restatic_placeholder: ty::Region<'tcx>, + reempty_placeholder: ty::Region<'tcx>, + ) -> Self { + RegionsSubstitutor { tcx, restatic_placeholder, reempty_placeholder } + } +} + +impl<'tcx> TypeFolder<'tcx> for RegionsSubstitutor<'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_region(&mut self, r: Region<'tcx>) -> Region<'tcx> { + match r { + ty::ReStatic => self.restatic_placeholder, + ty::ReEmpty(ui) => { + assert_eq!(ui.as_usize(), 0); + self.reempty_placeholder + } + + _ => r.super_fold_with(self), + } + } +} diff --git a/compiler/rustc_traits/src/chalk/mod.rs b/compiler/rustc_traits/src/chalk/mod.rs new file mode 100644 index 0000000000..63c5b88435 --- /dev/null +++ b/compiler/rustc_traits/src/chalk/mod.rs @@ -0,0 +1,159 @@ +//! Calls `chalk-solve` to solve a `ty::Predicate` +//! +//! In order to call `chalk-solve`, this file must convert a `CanonicalChalkEnvironmentAndGoal` into +//! a Chalk uncanonical goal. It then calls Chalk, and converts the answer back into rustc solution. + +crate mod db; +crate mod lowering; + +use rustc_data_structures::fx::FxHashMap; + +use rustc_index::vec::IndexVec; + +use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; +use rustc_middle::traits::ChalkRustInterner; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::subst::GenericArg; +use rustc_middle::ty::{self, BoundVar, ParamTy, TyCtxt, TypeFoldable}; + +use rustc_infer::infer::canonical::{ + Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, +}; +use rustc_infer::traits::{self, CanonicalChalkEnvironmentAndGoal}; + +use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; +use crate::chalk::lowering::{ + LowerInto, ParamsSubstitutor, PlaceholdersCollector, RegionsSubstitutor, +}; + +use chalk_solve::Solution; + +crate fn provide(p: &mut Providers) { + *p = Providers { evaluate_goal, ..*p }; +} + +crate fn evaluate_goal<'tcx>( + tcx: TyCtxt<'tcx>, + obligation: CanonicalChalkEnvironmentAndGoal<'tcx>, +) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { + let interner = ChalkRustInterner { tcx }; + + // Chalk doesn't have a notion of `Params`, so instead we use placeholders. + let mut placeholders_collector = PlaceholdersCollector::new(); + obligation.visit_with(&mut placeholders_collector); + + let restatic_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder), + })); + let reempty_placeholder = tcx.mk_region(ty::RegionKind::RePlaceholder(ty::Placeholder { + universe: ty::UniverseIndex::ROOT, + name: ty::BoundRegion::BrAnon(placeholders_collector.next_anon_region_placeholder + 1), + })); + + let mut params_substitutor = + ParamsSubstitutor::new(tcx, placeholders_collector.next_ty_placeholder); + let obligation = obligation.fold_with(&mut params_substitutor); + // FIXME(chalk): we really should be substituting these back in the solution + let _params: FxHashMap = params_substitutor.params; + + let mut regions_substitutor = + RegionsSubstitutor::new(tcx, restatic_placeholder, reempty_placeholder); + let obligation = obligation.fold_with(&mut regions_substitutor); + + let max_universe = obligation.max_universe.index(); + + let lowered_goal: chalk_ir::UCanonical< + chalk_ir::InEnvironment>>, + > = chalk_ir::UCanonical { + canonical: chalk_ir::Canonical { + binders: chalk_ir::CanonicalVarKinds::from_iter( + &interner, + obligation.variables.iter().map(|v| match v.kind { + CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(), + CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(), + CanonicalVarKind::Ty(ty) => match ty { + CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), + chalk_ir::UniverseIndex { counter: ui.index() }, + ), + CanonicalTyVarKind::Int => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Integer), + chalk_ir::UniverseIndex::root(), + ), + CanonicalTyVarKind::Float => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Float), + chalk_ir::UniverseIndex::root(), + ), + }, + CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new( + chalk_ir::VariableKind::Lifetime, + chalk_ir::UniverseIndex { counter: ui.index() }, + ), + CanonicalVarKind::Const(_ui) => unimplemented!(), + CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(), + }), + ), + value: obligation.value.lower_into(&interner), + }, + universes: max_universe + 1, + }; + + use chalk_solve::Solver; + let mut solver = chalk_engine::solve::SLGSolver::new(32, None); + let db = ChalkRustIrDatabase { interner, restatic_placeholder, reempty_placeholder }; + let solution = chalk_solve::logging::with_tracing_logs(|| solver.solve(&db, &lowered_goal)); + + // Ideally, the code to convert *back* to rustc types would live close to + // the code to convert *from* rustc types. Right now though, we don't + // really need this and so it's really minimal. + // Right now, we also treat a `Unique` solution the same as + // `Ambig(Definite)`. This really isn't right. + let make_solution = |subst: chalk_ir::Substitution<_>| { + let mut var_values: IndexVec> = IndexVec::new(); + subst.as_slice(&interner).iter().for_each(|p| { + var_values.push(p.lower_into(&interner)); + }); + let sol = Canonical { + max_universe: ty::UniverseIndex::from_usize(0), + variables: obligation.variables.clone(), + value: QueryResponse { + var_values: CanonicalVarValues { var_values }, + region_constraints: QueryRegionConstraints::default(), + certainty: Certainty::Proven, + value: (), + }, + }; + tcx.arena.alloc(sol) + }; + solution + .map(|s| match s { + Solution::Unique(subst) => { + // FIXME(chalk): handle constraints + make_solution(subst.value.subst) + } + Solution::Ambig(guidance) => { + match guidance { + chalk_solve::Guidance::Definite(subst) => make_solution(subst.value), + chalk_solve::Guidance::Suggested(_) => unimplemented!(), + chalk_solve::Guidance::Unknown => { + // chalk_fulfill doesn't use the var_values here, so + // let's just ignore that + let sol = Canonical { + max_universe: ty::UniverseIndex::from_usize(0), + variables: obligation.variables.clone(), + value: QueryResponse { + var_values: CanonicalVarValues { var_values: IndexVec::new() } + .make_identity(tcx), + region_constraints: QueryRegionConstraints::default(), + certainty: Certainty::Ambiguous, + value: (), + }, + }; + &*tcx.arena.alloc(sol) + } + } + } + }) + .ok_or(traits::query::NoSolution) +} diff --git a/src/librustc_traits/dropck_outlives.rs b/compiler/rustc_traits/src/dropck_outlives.rs similarity index 99% rename from src/librustc_traits/dropck_outlives.rs rename to compiler/rustc_traits/src/dropck_outlives.rs index ce00060b9b..3ee391d6dc 100644 --- a/src/librustc_traits/dropck_outlives.rs +++ b/compiler/rustc_traits/src/dropck_outlives.rs @@ -112,7 +112,7 @@ fn dropck_outlives<'tcx>( debug!("dropck_outlives: ty from dtorck_types = {:?}", ty); - match ty.kind { + match ty.kind() { // All parameters live for the duration of the // function. ty::Param(..) => {} @@ -172,7 +172,7 @@ fn dtorck_constraint_for_ty<'tcx>( return Ok(()); } - match ty.kind { + match ty.kind() { ty::Bool | ty::Char | ty::Int(_) diff --git a/src/librustc_traits/evaluate_obligation.rs b/compiler/rustc_traits/src/evaluate_obligation.rs similarity index 100% rename from src/librustc_traits/evaluate_obligation.rs rename to compiler/rustc_traits/src/evaluate_obligation.rs diff --git a/src/librustc_traits/implied_outlives_bounds.rs b/compiler/rustc_traits/src/implied_outlives_bounds.rs similarity index 98% rename from src/librustc_traits/implied_outlives_bounds.rs rename to compiler/rustc_traits/src/implied_outlives_bounds.rs index de3096eac9..79308b032e 100644 --- a/src/librustc_traits/implied_outlives_bounds.rs +++ b/compiler/rustc_traits/src/implied_outlives_bounds.rs @@ -103,7 +103,8 @@ fn compute_implied_outlives_bounds<'tcx>( | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => vec![], + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => vec![], ty::PredicateAtom::WellFormed(arg) => { wf_args.push(arg); vec![] diff --git a/src/librustc_traits/lib.rs b/compiler/rustc_traits/src/lib.rs similarity index 97% rename from src/librustc_traits/lib.rs rename to compiler/rustc_traits/src/lib.rs index 6fea4732dd..d0b05beb4e 100644 --- a/src/librustc_traits/lib.rs +++ b/compiler/rustc_traits/src/lib.rs @@ -4,7 +4,6 @@ #![feature(crate_visibility_modifier)] #![feature(in_band_lifetimes)] #![feature(nll)] -#![feature(or_patterns)] #![recursion_limit = "256"] #[macro_use] diff --git a/src/librustc_traits/normalize_erasing_regions.rs b/compiler/rustc_traits/src/normalize_erasing_regions.rs similarity index 95% rename from src/librustc_traits/normalize_erasing_regions.rs rename to compiler/rustc_traits/src/normalize_erasing_regions.rs index 83aee31a39..3e7c9ac62e 100644 --- a/src/librustc_traits/normalize_erasing_regions.rs +++ b/compiler/rustc_traits/src/normalize_erasing_regions.rs @@ -49,6 +49,7 @@ fn not_outlives_predicate(p: &ty::Predicate<'tcx>) -> bool { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => true, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => true, } } diff --git a/src/librustc_traits/normalize_projection_ty.rs b/compiler/rustc_traits/src/normalize_projection_ty.rs similarity index 100% rename from src/librustc_traits/normalize_projection_ty.rs rename to compiler/rustc_traits/src/normalize_projection_ty.rs diff --git a/src/librustc_traits/type_op.rs b/compiler/rustc_traits/src/type_op.rs similarity index 100% rename from src/librustc_traits/type_op.rs rename to compiler/rustc_traits/src/type_op.rs diff --git a/compiler/rustc_ty/Cargo.toml b/compiler/rustc_ty/Cargo.toml new file mode 100644 index 0000000000..acb011b2dc --- /dev/null +++ b/compiler/rustc_ty/Cargo.toml @@ -0,0 +1,17 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_ty" +version = "0.0.0" +edition = "2018" + +[dependencies] +tracing = "0.1" +rustc_middle = { path = "../rustc_middle" } +rustc_data_structures = { path = "../rustc_data_structures" } +rustc_errors = { path = "../rustc_errors" } +rustc_hir = { path = "../rustc_hir" } +rustc_infer = { path = "../rustc_infer" } +rustc_span = { path = "../rustc_span" } +rustc_session = { path = "../rustc_session" } +rustc_target = { path = "../rustc_target" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_ty/common_traits.rs b/compiler/rustc_ty/src/common_traits.rs similarity index 100% rename from src/librustc_ty/common_traits.rs rename to compiler/rustc_ty/src/common_traits.rs diff --git a/src/librustc_ty/instance.rs b/compiler/rustc_ty/src/instance.rs similarity index 93% rename from src/librustc_ty/instance.rs rename to compiler/rustc_ty/src/instance.rs index d0bd88af1f..220f4cec74 100644 --- a/src/librustc_ty/instance.rs +++ b/compiler/rustc_ty/src/instance.rs @@ -53,7 +53,7 @@ fn inner_resolve_instance<'tcx>( let ty = tcx.type_of(def.def_id_for_type_of()); let item_type = tcx.subst_and_normalize_erasing_regions(substs, param_env, &ty); - let def = match item_type.kind { + let def = match *item_type.kind() { ty::FnDef(..) if { let f = item_type.fn_sig(tcx); @@ -68,7 +68,7 @@ fn inner_resolve_instance<'tcx>( if ty.needs_drop(tcx, param_env) { debug!(" => nontrivial drop glue"); - match ty.kind { + match *ty.kind() { ty::Closure(..) | ty::Generator(..) | ty::Tuple(..) @@ -119,9 +119,9 @@ fn resolve_associated_item<'tcx>( // Now that we know which impl is being used, we can dispatch to // the actual function: Ok(match vtbl { - traits::ImplSourceUserDefined(impl_data) => { + traits::ImplSource::UserDefined(impl_data) => { debug!( - "resolving ImplSourceUserDefined: {:?}, {:?}, {:?}, {:?}", + "resolving ImplSource::UserDefined: {:?}, {:?}, {:?}, {:?}", param_env, trait_item, rcvr_substs, impl_data ); assert!(!rcvr_substs.needs_infer()); @@ -216,13 +216,13 @@ fn resolve_associated_item<'tcx>( Some(ty::Instance::new(leaf_def.item.def_id, substs)) } - traits::ImplSourceGenerator(generator_data) => Some(Instance { + traits::ImplSource::Generator(generator_data) => Some(Instance { def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( generator_data.generator_def_id, )), substs: generator_data.substs, }), - traits::ImplSourceClosure(closure_data) => { + traits::ImplSource::Closure(closure_data) => { let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); Some(Instance::resolve_closure( tcx, @@ -231,18 +231,18 @@ fn resolve_associated_item<'tcx>( trait_closure_kind, )) } - traits::ImplSourceFnPointer(ref data) => match data.fn_ty.kind { + traits::ImplSource::FnPointer(ref data) => match data.fn_ty.kind() { ty::FnDef(..) | ty::FnPtr(..) => Some(Instance { def: ty::InstanceDef::FnPtrShim(trait_item.def_id, data.fn_ty), substs: rcvr_substs, }), _ => None, }, - traits::ImplSourceObject(ref data) => { + traits::ImplSource::Object(ref data) => { let index = traits::get_vtable_index_of_object_method(tcx, data, def_id); Some(Instance { def: ty::InstanceDef::Virtual(def_id, index), substs: rcvr_substs }) } - traits::ImplSourceBuiltin(..) => { + traits::ImplSource::Builtin(..) => { if Some(trait_ref.def_id) == tcx.lang_items().clone_trait() { // FIXME(eddyb) use lang items for methods instead of names. let name = tcx.item_name(def_id); @@ -250,7 +250,7 @@ fn resolve_associated_item<'tcx>( let self_ty = trait_ref.self_ty(); let is_copy = self_ty.is_copy_modulo_regions(tcx.at(DUMMY_SP), param_env); - match self_ty.kind { + match self_ty.kind() { _ if is_copy => (), ty::Array(..) | ty::Closure(..) | ty::Tuple(..) => {} _ => return Ok(None), @@ -271,10 +271,10 @@ fn resolve_associated_item<'tcx>( None } } - traits::ImplSourceAutoImpl(..) - | traits::ImplSourceParam(..) - | traits::ImplSourceTraitAlias(..) - | traits::ImplSourceDiscriminantKind(..) => None, + traits::ImplSource::AutoImpl(..) + | traits::ImplSource::Param(..) + | traits::ImplSource::TraitAlias(..) + | traits::ImplSource::DiscriminantKind(..) => None, }) } diff --git a/src/librustc_ty/lib.rs b/compiler/rustc_ty/src/lib.rs similarity index 84% rename from src/librustc_ty/lib.rs rename to compiler/rustc_ty/src/lib.rs index 6e9042d1ba..904c0062a9 100644 --- a/src/librustc_ty/lib.rs +++ b/compiler/rustc_ty/src/lib.rs @@ -4,8 +4,7 @@ //! //! This API is completely unstable and subject to change. -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![feature(bool_to_option)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(nll)] #![recursion_limit = "256"] diff --git a/src/librustc_ty/needs_drop.rs b/compiler/rustc_ty/src/needs_drop.rs similarity index 98% rename from src/librustc_ty/needs_drop.rs rename to compiler/rustc_ty/src/needs_drop.rs index c4af95205f..0356bcec54 100644 --- a/src/librustc_ty/needs_drop.rs +++ b/compiler/rustc_ty/src/needs_drop.rs @@ -90,7 +90,7 @@ where }; for component in components { - match component.kind { + match *component.kind() { _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), ty::Closure(_, substs) => { @@ -106,7 +106,7 @@ where } let witness = substs.witness(); - let interior_tys = match &witness.kind { + let interior_tys = match witness.kind() { ty::GeneratorWitness(tys) => tcx.erase_late_bound_regions(tys), _ => { tcx.sess.delay_span_bug( diff --git a/src/librustc_ty/ty.rs b/compiler/rustc_ty/src/ty.rs similarity index 79% rename from src/librustc_ty/ty.rs rename to compiler/rustc_ty/src/ty.rs index 0f1dee7e2e..c4b6b64339 100644 --- a/src/librustc_ty/ty.rs +++ b/compiler/rustc_ty/src/ty.rs @@ -1,3 +1,4 @@ +use rustc_data_structures::fx::FxIndexSet; use rustc_data_structures::svh::Svh; use rustc_hir as hir; use rustc_hir::def::DefKind; @@ -5,7 +6,9 @@ use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_infer::traits::util; use rustc_middle::hir::map as hir_map; use rustc_middle::ty::subst::{InternalSubsts, Subst}; -use rustc_middle::ty::{self, ToPredicate, Ty, TyCtxt, WithConstness}; +use rustc_middle::ty::{ + self, Binder, Predicate, PredicateAtom, PredicateKind, ToPredicate, Ty, TyCtxt, WithConstness, +}; use rustc_session::CrateDisambiguator; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -18,7 +21,7 @@ fn sized_constraint_for_ty<'tcx>( ) -> Vec> { use ty::TyKind::*; - let result = match ty.kind { + let result = match ty.kind() { Bool | Char | Int(..) | Uint(..) | Float(..) | RawPtr(..) | Ref(..) | FnDef(..) | FnPtr(_) | Array(..) | Closure(..) | Generator(..) | Never => vec![], @@ -245,7 +248,7 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { } // Compute the bounds on Self and the type parameters. - let ty::InstantiatedPredicates { predicates, .. } = + let ty::InstantiatedPredicates { mut predicates, .. } = tcx.predicates_of(def_id).instantiate_identity(tcx); // Finally, we have to normalize the bounds in the environment, in @@ -260,11 +263,13 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { // are any errors at that point, so after type checking you can be // sure that this will succeed without errors anyway. - let unnormalized_env = ty::ParamEnv::new( - tcx.intern_predicates(&predicates), - traits::Reveal::UserFacing, - tcx.sess.opts.debugging_opts.chalk.then_some(def_id), - ); + if tcx.sess.opts.debugging_opts.chalk { + let environment = well_formed_types_in_env(tcx, def_id); + predicates.extend(environment); + } + + let unnormalized_env = + ty::ParamEnv::new(tcx.intern_predicates(&predicates), traits::Reveal::UserFacing); let body_id = def_id .as_local() @@ -276,6 +281,122 @@ fn param_env(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { traits::normalize_param_env_or_error(tcx, def_id, unnormalized_env, cause) } +/// Elaborate the environment. +/// +/// Collect a list of `Predicate`'s used for building the `ParamEnv`. Adds `TypeWellFormedFromEnv`'s +/// that are assumed to be well-formed (because they come from the environment). +/// +/// Used only in chalk mode. +fn well_formed_types_in_env<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: DefId, +) -> &'tcx ty::List> { + use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind}; + use rustc_middle::ty::subst::GenericArgKind; + + debug!("environment(def_id = {:?})", def_id); + + // The environment of an impl Trait type is its defining function's environment. + if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { + return well_formed_types_in_env(tcx, parent); + } + + // Compute the bounds on `Self` and the type parameters. + let ty::InstantiatedPredicates { predicates, .. } = + tcx.predicates_of(def_id).instantiate_identity(tcx); + + let clauses = predicates.into_iter(); + + if !def_id.is_local() { + return ty::List::empty(); + } + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let node = tcx.hir().get(hir_id); + + enum NodeKind { + TraitImpl, + InherentImpl, + Fn, + Other, + }; + + let node_kind = match node { + Node::TraitItem(item) => match item.kind { + TraitItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::ImplItem(item) => match item.kind { + ImplItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::Item(item) => match item.kind { + ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl, + ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl, + ItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + Node::ForeignItem(item) => match item.kind { + ForeignItemKind::Fn(..) => NodeKind::Fn, + _ => NodeKind::Other, + }, + + // FIXME: closures? + _ => NodeKind::Other, + }; + + // FIXME(eddyb) isn't the unordered nature of this a hazard? + let mut inputs = FxIndexSet::default(); + + match node_kind { + // In a trait impl, we assume that the header trait ref and all its + // constituents are well-formed. + NodeKind::TraitImpl => { + let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); + + // FIXME(chalk): this has problems because of late-bound regions + //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); + inputs.extend(trait_ref.substs.iter()); + } + + // In an inherent impl, we assume that the receiver type and all its + // constituents are well-formed. + NodeKind::InherentImpl => { + let self_ty = tcx.type_of(def_id); + inputs.extend(self_ty.walk()); + } + + // In an fn, we assume that the arguments and all their constituents are + // well-formed. + NodeKind::Fn => { + let fn_sig = tcx.fn_sig(def_id); + let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); + + inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); + } + + NodeKind::Other => (), + } + let input_clauses = inputs.into_iter().filter_map(|arg| { + match arg.unpack() { + GenericArgKind::Type(ty) => { + let binder = Binder::dummy(PredicateAtom::TypeWellFormedFromEnv(ty)); + Some(tcx.mk_predicate(PredicateKind::ForAll(binder))) + } + + // FIXME(eddyb) no WF conditions from lifetimes? + GenericArgKind::Lifetime(_) => None, + + // FIXME(eddyb) support const generics in Chalk + GenericArgKind::Const(_) => None, + } + }); + + tcx.mk_predicates(clauses.chain(input_clauses)) +} + fn param_env_reveal_all_normalized(tcx: TyCtxt<'_>, def_id: DefId) -> ty::ParamEnv<'_> { tcx.param_env(def_id).with_reveal_all_normalized(tcx) } @@ -344,7 +465,7 @@ fn issue33140_self_ty(tcx: TyCtxt<'_>, def_id: DefId) -> Option> { } let self_ty = trait_ref.self_ty(); - let self_ty_matches = match self_ty.kind { + let self_ty_matches = match self_ty.kind() { ty::Dynamic(ref data, ty::ReStatic) => data.principal().is_none(), _ => false, }; @@ -398,21 +519,21 @@ fn associated_type_projection_predicates( let pred = obligation.predicate; match pred.skip_binders() { ty::PredicateAtom::Trait(tr, _) => { - if let ty::Projection(p) = tr.self_ty().kind { + if let ty::Projection(p) = *tr.self_ty().kind() { if p == assoc_item_ty { return Some(pred); } } } ty::PredicateAtom::Projection(proj) => { - if let ty::Projection(p) = proj.projection_ty.self_ty().kind { + if let ty::Projection(p) = *proj.projection_ty.self_ty().kind() { if p == assoc_item_ty { return Some(pred); } } } ty::PredicateAtom::TypeOutlives(outlives) => { - if let ty::Projection(p) = outlives.0.kind { + if let ty::Projection(p) = *outlives.0.kind() { if p == assoc_item_ty { return Some(pred); } @@ -449,14 +570,15 @@ fn opaque_type_projection_predicates( let pred = obligation.predicate; match pred.skip_binders() { ty::PredicateAtom::Trait(tr, _) => { - if let ty::Opaque(opaque_def_id, opaque_substs) = tr.self_ty().kind { + if let ty::Opaque(opaque_def_id, opaque_substs) = *tr.self_ty().kind() { if opaque_def_id == def_id && opaque_substs == substs { return Some(pred); } } } ty::PredicateAtom::Projection(proj) => { - if let ty::Opaque(opaque_def_id, opaque_substs) = proj.projection_ty.self_ty().kind + if let ty::Opaque(opaque_def_id, opaque_substs) = + *proj.projection_ty.self_ty().kind() { if opaque_def_id == def_id && opaque_substs == substs { return Some(pred); @@ -464,7 +586,7 @@ fn opaque_type_projection_predicates( } } ty::PredicateAtom::TypeOutlives(outlives) => { - if let ty::Opaque(opaque_def_id, opaque_substs) = outlives.0.kind { + if let ty::Opaque(opaque_def_id, opaque_substs) = *outlives.0.kind() { if opaque_def_id == def_id && opaque_substs == substs { return Some(pred); } diff --git a/compiler/rustc_typeck/Cargo.toml b/compiler/rustc_typeck/Cargo.toml new file mode 100644 index 0000000000..e3ba0bea7e --- /dev/null +++ b/compiler/rustc_typeck/Cargo.toml @@ -0,0 +1,28 @@ +[package] +authors = ["The Rust Project Developers"] +name = "rustc_typeck" +version = "0.0.0" +edition = "2018" + +[lib] +test = false +doctest = false + +[dependencies] +rustc_arena = { path = "../rustc_arena" } +tracing = "0.1" +rustc_macros = { path = "../rustc_macros" } +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_hir_pretty = { path = "../rustc_hir_pretty" } +rustc_target = { path = "../rustc_target" } +rustc_session = { path = "../rustc_session" } +smallvec = { version = "1.0", features = ["union", "may_dangle"] } +rustc_ast = { path = "../rustc_ast" } +rustc_span = { path = "../rustc_span" } +rustc_index = { path = "../rustc_index" } +rustc_infer = { path = "../rustc_infer" } +rustc_trait_selection = { path = "../rustc_trait_selection" } diff --git a/src/librustc_typeck/README.md b/compiler/rustc_typeck/README.md similarity index 100% rename from src/librustc_typeck/README.md rename to compiler/rustc_typeck/README.md diff --git a/src/librustc_typeck/astconv/errors.rs b/compiler/rustc_typeck/src/astconv/errors.rs similarity index 100% rename from src/librustc_typeck/astconv/errors.rs rename to compiler/rustc_typeck/src/astconv/errors.rs diff --git a/src/librustc_typeck/astconv/generics.rs b/compiler/rustc_typeck/src/astconv/generics.rs similarity index 90% rename from src/librustc_typeck/astconv/generics.rs rename to compiler/rustc_typeck/src/astconv/generics.rs index 84dab6de95..b54de1d091 100644 --- a/src/librustc_typeck/astconv/generics.rs +++ b/compiler/rustc_typeck/src/astconv/generics.rs @@ -1,8 +1,9 @@ use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, GenericArgPosition, }; +use crate::errors::AssocTypeBindingNotAllowed; use rustc_ast::ast::ParamKindOrd; -use rustc_errors::{pluralize, struct_span_err, DiagnosticId, ErrorReported}; +use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_hir::{GenericArg, GenericArgs}; @@ -367,7 +368,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if position != GenericArgPosition::Type && !args.bindings.is_empty() { - Self::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); + AstConv::prohibit_assoc_ty_binding(tcx, args.bindings[0].span); } let explicit_late_bound = @@ -392,7 +393,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if silent { - return Err(true); + return Err((0i32, None)); } // Unfortunately lifetime and type parameter mismatches are typically styled @@ -441,16 +442,16 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { for span in spans { err.span_label(span, label.as_str()); } - err.emit(); - Err(true) + assert_ne!(bound, provided); + Err((bound as i32 - provided as i32, Some(err))) }; - let mut arg_count_correct = Ok(()); let mut unexpected_spans = vec![]; + let mut lifetime_count_correct = Ok(()); if !infer_lifetimes || arg_counts.lifetimes > param_counts.lifetimes { - arg_count_correct = check_kind_count( + lifetime_count_correct = check_kind_count( "lifetime", param_counts.lifetimes, param_counts.lifetimes, @@ -458,12 +459,13 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { 0, &mut unexpected_spans, explicit_late_bound == ExplicitLateBound::Yes, - ) - .and(arg_count_correct); + ); } + // FIXME(const_generics:defaults) + let mut const_count_correct = Ok(()); if !infer_args || arg_counts.consts > param_counts.consts { - arg_count_correct = check_kind_count( + const_count_correct = check_kind_count( "const", param_counts.consts, param_counts.consts, @@ -471,13 +473,14 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes + arg_counts.types, &mut unexpected_spans, false, - ) - .and(arg_count_correct); + ); } + // Note that type errors are currently be emitted *after* const errors. + let mut type_count_correct = Ok(()); if !infer_args || arg_counts.types > param_counts.types - defaults.types - has_self as usize { - arg_count_correct = check_kind_count( + type_count_correct = check_kind_count( "type", param_counts.types - defaults.types - has_self as usize, param_counts.types - has_self as usize, @@ -485,14 +488,54 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { arg_counts.lifetimes, &mut unexpected_spans, false, - ) - .and(arg_count_correct); + ); } + // Emit a help message if it's possible that a type could be surrounded in braces + if let Err((c_mismatch, Some(ref mut _const_err))) = const_count_correct { + if let Err((_, Some(ref mut type_err))) = type_count_correct { + let possible_matches = args.args[arg_counts.lifetimes..] + .iter() + .filter(|arg| { + matches!( + arg, + GenericArg::Type(hir::Ty { kind: hir::TyKind::Path { .. }, .. }) + ) + }) + .take(c_mismatch.max(0) as usize); + for arg in possible_matches { + let suggestions = vec![ + (arg.span().shrink_to_lo(), String::from("{ ")), + (arg.span().shrink_to_hi(), String::from(" }")), + ]; + type_err.multipart_suggestion( + "If this generic argument was intended as a const parameter, \ + try surrounding it with braces:", + suggestions, + Applicability::MaybeIncorrect, + ); + } + } + } + + let emit_correct = + |correct: Result<(), (_, Option>)>| match correct { + Ok(()) => Ok(()), + Err((_, None)) => Err(()), + Err((_, Some(mut err))) => { + err.emit(); + Err(()) + } + }; + + let arg_count_correct = emit_correct(lifetime_count_correct) + .and(emit_correct(const_count_correct)) + .and(emit_correct(type_count_correct)); + GenericArgCountResult { explicit_late_bound, - correct: arg_count_correct.map_err(|reported_err| GenericArgCountMismatch { - reported: if reported_err { Some(ErrorReported) } else { None }, + correct: arg_count_correct.map_err(|()| GenericArgCountMismatch { + reported: Some(ErrorReported), invalid_args: unexpected_spans, }), } @@ -544,13 +587,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { /// Emits an error regarding forbidden type binding associations pub fn prohibit_assoc_ty_binding(tcx: TyCtxt<'_>, span: Span) { - let mut err = struct_span_err!( - tcx.sess, - span, - E0229, - "associated type bindings are not allowed here" - ); - err.span_label(span, "associated type not allowed here").emit(); + tcx.sess.emit_err(AssocTypeBindingNotAllowed { span }); } /// Prohibits explicit lifetime arguments if late-bound lifetime parameters diff --git a/src/librustc_typeck/astconv/mod.rs b/compiler/rustc_typeck/src/astconv/mod.rs similarity index 97% rename from src/librustc_typeck/astconv/mod.rs rename to compiler/rustc_typeck/src/astconv/mod.rs index 80dd26e915..46b8b2e14c 100644 --- a/src/librustc_typeck/astconv/mod.rs +++ b/compiler/rustc_typeck/src/astconv/mod.rs @@ -7,6 +7,10 @@ mod generics; use crate::bounds::Bounds; use crate::collect::PlaceholderHirTyCollector; +use crate::errors::{ + AmbiguousLifetimeBound, MultipleRelaxedDefaultBounds, TraitObjectDeclaredWithNoTraits, + TypeofReservedKeywordUsed, ValueOfAssociatedStructAlreadySpecified, +}; use crate::middle::resolve_lifetime as rl; use crate::require_c_abi_if_c_variadic; use rustc_ast::util::lev_distance::find_best_match_for_name; @@ -356,7 +360,21 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { (GenericParamDefKind::Lifetime, GenericArg::Lifetime(lt)) => { self.ast_region_to_region(<, Some(param)).into() } - (GenericParamDefKind::Type { .. }, GenericArg::Type(ty)) => { + (GenericParamDefKind::Type { has_default, .. }, GenericArg::Type(ty)) => { + if *has_default { + tcx.check_optional_stability( + param.def_id, + Some(arg.id()), + arg.span(), + |_, _| { + // Default generic parameters may not be marked + // with stability attributes, i.e. when the + // default parameter was defined at the same time + // as the rest of the type. As such, we ignore missing + // stability attributes. + }, + ) + } if let (hir::TyKind::Infer, false) = (&ty.kind, self.allow_ty_infer()) { inferred_params.push(ty.span); tcx.ty_error().into() @@ -684,14 +702,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { if unbound.is_none() { unbound = Some(&ptr.trait_ref); } else { - struct_span_err!( - tcx.sess, - span, - E0203, - "type parameter has more than one relaxed default \ - bound, only one is supported" - ) - .emit(); + tcx.sess.emit_err(MultipleRelaxedDefaultBounds { span }); } } } @@ -927,18 +938,12 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { dup_bindings .entry(assoc_ty.def_id) .and_modify(|prev_span| { - struct_span_err!( - self.tcx().sess, - binding.span, - E0719, - "the value of the associated type `{}` (from trait `{}`) \ - is already specified", - binding.item_name, - tcx.def_path_str(assoc_ty.container.id()) - ) - .span_label(binding.span, "re-bound here") - .span_label(*prev_span, format!("`{}` bound here first", binding.item_name)) - .emit(); + self.tcx().sess.emit_err(ValueOfAssociatedStructAlreadySpecified { + span: binding.span, + prev_span: *prev_span, + item_name: binding.item_name, + def_path: tcx.def_path_str(assoc_ty.container.id()), + }); }) .or_insert(binding.span); } @@ -1051,13 +1056,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { } if regular_traits.is_empty() && auto_traits.is_empty() { - struct_span_err!( - tcx.sess, - span, - E0224, - "at least one trait is required for an object type" - ) - .emit(); + tcx.sess.emit_err(TraitObjectDeclaredWithNoTraits { span }); return tcx.ty_error(); } @@ -1454,7 +1453,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Check if we have an enum variant. let mut variant_resolution = None; - if let ty::Adt(adt_def, _) = qself_ty.kind { + if let ty::Adt(adt_def, _) = qself_ty.kind() { if adt_def.is_enum() { let variant_def = adt_def .variants @@ -1474,8 +1473,8 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // Find the type of the associated item, and the trait where the associated // item is declared. - let bound = match (&qself_ty.kind, qself_res) { - (_, Res::SelfTy(Some(_), Some(impl_def_id))) => { + let bound = match (&qself_ty.kind(), qself_res) { + (_, Res::SelfTy(Some(_), Some((impl_def_id, _)))) => { // `Self` in an impl of a trait -- we have a concrete self type and a // trait reference. let trait_ref = match tcx.impl_trait_ref(impl_def_id) { @@ -1932,12 +1931,29 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.prohibit_generics(path.segments); tcx.types.self_param } - Res::SelfTy(_, Some(def_id)) => { + Res::SelfTy(_, Some((def_id, forbid_generic))) => { // `Self` in impl (we know the concrete type). assert_eq!(opt_self_ty, None); self.prohibit_generics(path.segments); // Try to evaluate any array length constants. - self.normalize_ty(span, tcx.at(span).type_of(def_id)) + let normalized_ty = self.normalize_ty(span, tcx.at(span).type_of(def_id)); + if forbid_generic && normalized_ty.needs_subst() { + let mut err = tcx.sess.struct_span_err( + path.span, + "generic `Self` types are currently not permitted in anonymous constants", + ); + if let Some(hir::Node::Item(&hir::Item { + kind: hir::ItemKind::Impl { self_ty, .. }, + .. + })) = tcx.hir().get_if_local(def_id) + { + err.span_note(self_ty.span, "not a concrete type"); + } + err.emit(); + tcx.ty_error() + } else { + normalized_ty + } } Res::Def(DefKind::AssocTy, def_id) => { debug_assert!(path.segments.len() >= 2); @@ -2059,15 +2075,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { self.normalize_ty(ast_ty.span, array_ty) } hir::TyKind::Typeof(ref _e) => { - struct_span_err!( - tcx.sess, - ast_ty.span, - E0516, - "`typeof` is a reserved keyword but unimplemented" - ) - .span_label(ast_ty.span, "reserved keyword") - .emit(); - + tcx.sess.emit_err(TypeofReservedKeywordUsed { span: ast_ty.span }); tcx.ty_error() } hir::TyKind::Infer => { @@ -2283,13 +2291,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { // error. let r = derived_region_bounds[0]; if derived_region_bounds[1..].iter().any(|r1| r != *r1) { - struct_span_err!( - tcx.sess, - span, - E0227, - "ambiguous lifetime bound, explicit lifetime bound required" - ) - .emit(); + tcx.sess.emit_err(AmbiguousLifetimeBound { span }); } Some(r) } diff --git a/src/librustc_typeck/bounds.rs b/compiler/rustc_typeck/src/bounds.rs similarity index 100% rename from src/librustc_typeck/bounds.rs rename to compiler/rustc_typeck/src/bounds.rs diff --git a/src/librustc_typeck/check/_match.rs b/compiler/rustc_typeck/src/check/_match.rs similarity index 81% rename from src/librustc_typeck/check/_match.rs rename to compiler/rustc_typeck/src/check/_match.rs index 40088bc069..7cb23dc053 100644 --- a/src/librustc_typeck/check/_match.rs +++ b/compiler/rustc_typeck/src/check/_match.rs @@ -1,12 +1,15 @@ use crate::check::coercion::CoerceMany; use crate::check::{Diverges, Expectation, FnCtxt, Needs}; -use rustc_hir as hir; -use rustc_hir::ExprKind; +use rustc_hir::{self as hir, ExprKind}; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; -use rustc_middle::ty::Ty; +use rustc_infer::traits::Obligation; +use rustc_middle::ty::{self, ToPredicate, Ty}; use rustc_span::Span; -use rustc_trait_selection::traits::ObligationCauseCode; -use rustc_trait_selection::traits::{IfExpressionCause, MatchExpressionArmCause, ObligationCause}; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; +use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; +use rustc_trait_selection::traits::{ + IfExpressionCause, MatchExpressionArmCause, ObligationCause, ObligationCauseCode, +}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_match( @@ -14,7 +17,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, scrut: &'tcx hir::Expr<'tcx>, arms: &'tcx [hir::Arm<'tcx>], - expected: Expectation<'tcx>, + orig_expected: Expectation<'tcx>, match_src: hir::MatchSource, ) -> Ty<'tcx> { let tcx = self.tcx; @@ -22,13 +25,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { use hir::MatchSource::*; let (source_if, if_no_else, force_scrutinee_bool) = match match_src { IfDesugar { contains_else_clause } => (true, !contains_else_clause, true), - IfLetDesugar { contains_else_clause } => (true, !contains_else_clause, false), + IfLetDesugar { contains_else_clause, .. } => (true, !contains_else_clause, false), WhileDesugar => (false, false, true), _ => (false, false, false), }; // Type check the descriminant and get its type. - let scrut_ty = if force_scrutinee_bool { + let scrutinee_ty = if force_scrutinee_bool { // Here we want to ensure: // // 1. That default match bindings are *not* accepted in the condition of an @@ -55,7 +58,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // #55810: Type check patterns first so we get types for all bindings. for arm in arms { - self.check_pat_top(&arm.pat, scrut_ty, Some(scrut.span), true); + self.check_pat_top(&arm.pat, scrutinee_ty, Some(scrut.span), true); } // Now typecheck the blocks. @@ -69,7 +72,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // type in that case) let mut all_arms_diverge = Diverges::WarnedAlways; - let expected = expected.adjust_for_branches(self); + let expected = orig_expected.adjust_for_branches(self); let mut coercion = { let coerce_first = match expected { @@ -112,6 +115,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.check_expr_with_expectation(&arm.body, expected) }; all_arms_diverge &= self.diverges.get(); + + // When we have a `match` as a tail expression in a `fn` with a returned `impl Trait` + // we check if the different arms would work with boxed trait objects instead and + // provide a structured suggestion in that case. + let opt_suggest_box_span = match ( + orig_expected, + self.ret_coercion_impl_trait.map(|ty| (self.body_id.owner, ty)), + ) { + (Expectation::ExpectHasType(expected), Some((id, ty))) + if self.in_tail_expr && self.can_coerce(arm_ty, expected) => + { + let impl_trait_ret_ty = self.infcx.instantiate_opaque_types( + id, + self.body_id, + self.param_env, + &ty, + arm.body.span, + ); + let mut suggest_box = !impl_trait_ret_ty.obligations.is_empty(); + for o in impl_trait_ret_ty.obligations { + match o.predicate.skip_binders_unchecked() { + ty::PredicateAtom::Trait(t, constness) => { + let pred = ty::PredicateAtom::Trait( + ty::TraitPredicate { + trait_ref: ty::TraitRef { + def_id: t.def_id(), + substs: self.infcx.tcx.mk_substs_trait(arm_ty, &[]), + }, + }, + constness, + ); + let obl = Obligation::new( + o.cause.clone(), + self.param_env, + pred.to_predicate(self.infcx.tcx), + ); + suggest_box &= self.infcx.predicate_must_hold_modulo_regions(&obl); + if !suggest_box { + // We've encountered some obligation that didn't hold, so the + // return expression can't just be boxed. We don't need to + // evaluate the rest of the obligations. + break; + } + } + _ => {} + } + } + // If all the obligations hold (or there are no obligations) the tail expression + // we can suggest to return a boxed trait object instead of an opaque type. + if suggest_box { self.ret_type_span } else { None } + } + _ => None, + }; + if source_if { let then_expr = &arms[0].body; match (i, if_no_else) { @@ -119,7 +176,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (_, true) => {} // Handled above to avoid duplicated type errors (#60254). (_, _) => { let then_ty = prior_arm_ty.unwrap(); - let cause = self.if_cause(expr.span, then_expr, &arm.body, then_ty, arm_ty); + let cause = self.if_cause( + expr.span, + then_expr, + &arm.body, + then_ty, + arm_ty, + opt_suggest_box_span, + ); coercion.coerce(self, &cause, &arm.body, arm_ty); } } @@ -142,6 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { prior_arms: other_arms.clone(), last_ty: prior_arm_ty.unwrap(), scrut_hir_id: scrut.hir_id, + opt_suggest_box_span, }), ), }; @@ -266,6 +331,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { else_expr: &'tcx hir::Expr<'tcx>, then_ty: Ty<'tcx>, else_ty: Ty<'tcx>, + opt_suggest_box_span: Option, ) -> ObligationCause<'tcx> { let mut outer_sp = if self.tcx.sess.source_map().is_multiline(span) { // The `if`/`else` isn't in one line in the output, include some context to make it @@ -353,8 +419,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error_sp, ObligationCauseCode::IfExpression(box IfExpressionCause { then: then_sp, + else_sp: error_sp, outer: outer_sp, semicolon: remove_semicolon, + opt_suggest_box_span, }), ) } diff --git a/src/librustc_typeck/check/autoderef.rs b/compiler/rustc_typeck/src/check/autoderef.rs similarity index 74% rename from src/librustc_typeck/check/autoderef.rs rename to compiler/rustc_typeck/src/check/autoderef.rs index 97d2b3e5a8..59c366ad7d 100644 --- a/src/librustc_typeck/check/autoderef.rs +++ b/compiler/rustc_typeck/src/check/autoderef.rs @@ -12,7 +12,18 @@ use std::iter; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn autoderef(&'a self, span: Span, base_ty: Ty<'tcx>) -> Autoderef<'a, 'tcx> { - Autoderef::new(self, self.param_env, self.body_id, span, base_ty) + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, span) + } + + /// Like `autoderef`, but provides a custom `Span` to use for calls to + /// an overloaded `Deref` operator + pub fn autoderef_overloaded_span( + &'a self, + span: Span, + base_ty: Ty<'tcx>, + overloaded_span: Span, + ) -> Autoderef<'a, 'tcx> { + Autoderef::new(self, self.param_env, self.body_id, span, base_ty, overloaded_span) } pub fn try_overloaded_deref( @@ -43,8 +54,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.try_overloaded_deref(autoderef.span(), source).and_then( |InferOk { value: method, obligations: o }| { obligations.extend(o); - if let ty::Ref(region, _, mutbl) = method.sig.output().kind { - Some(OverloadedDeref { region, mutbl }) + if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { + Some(OverloadedDeref { + region, + mutbl, + span: autoderef.overloaded_span(), + }) } else { None } diff --git a/src/librustc_typeck/check/callee.rs b/compiler/rustc_typeck/src/check/callee.rs similarity index 98% rename from src/librustc_typeck/check/callee.rs rename to compiler/rustc_typeck/src/check/callee.rs index 4ba64035ca..740783aeb9 100644 --- a/src/librustc_typeck/check/callee.rs +++ b/compiler/rustc_typeck/src/check/callee.rs @@ -114,7 +114,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); // If the callee is a bare function or a closure, then we're all set. - match adjusted_ty.kind { + match *adjusted_ty.kind() { ty::FnDef(..) | ty::FnPtr(_) => { let adjustments = self.adjust_steps(autoderef); self.apply_adjustments(callee_expr, adjustments); @@ -223,12 +223,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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 { + span_bug!(call_expr.span, "input to call/call_mut is not a ref?"); + }; let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, @@ -285,7 +285,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { arg_exprs: &'tcx [hir::Expr<'tcx>], expected: Expectation<'tcx>, ) -> Ty<'tcx> { - let (fn_sig, def_span) = match callee_ty.kind { + let (fn_sig, def_span) = match *callee_ty.kind() { ty::FnDef(def_id, _) => { (callee_ty.fn_sig(self.tcx), self.tcx.hir().span_if_local(def_id)) } diff --git a/src/librustc_typeck/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs similarity index 98% rename from src/librustc_typeck/check/cast.rs rename to compiler/rustc_typeck/src/check/cast.rs index e41314e8ab..5c2bdb86f7 100644 --- a/src/librustc_typeck/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -97,7 +97,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return Ok(Some(PointerKind::Thin)); } - Ok(match t.kind { + Ok(match *t.kind() { ty::Slice(_) | ty::Str => Some(PointerKind::Length), ty::Dynamic(ref tty, ..) => Some(PointerKind::Vtable(tty.principal_def_id())), ty::Adt(def, substs) if def.is_struct() => match def.non_enum_variant().fields.last() { @@ -203,7 +203,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // For better error messages, check for some obviously unsized // cases now. We do a more thorough check at the end, once // inference is more completely known. - match cast_ty.kind { + match cast_ty.kind() { ty::Dynamic(..) | ty::Slice(..) => { check.report_cast_to_unsized_type(fcx); Err(ErrorReported) @@ -348,7 +348,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx.ty_to_string(self.cast_ty) ); let mut sugg = None; - if let ty::Ref(reg, _, mutbl) = self.cast_ty.kind { + if let ty::Ref(reg, _, mutbl) = *self.cast_ty.kind() { if fcx .try_coerce( self.expr, @@ -370,7 +370,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { Applicability::MachineApplicable, ); } else if !matches!( - self.cast_ty.kind, + self.cast_ty.kind(), ty::FnDef(..) | ty::FnPtr(..) | ty::Closure(..) ) { let mut label = true; @@ -474,7 +474,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { fcx.resolve_vars_if_possible(&self.expr_ty), tstr ); - match self.expr_ty.kind { + match self.expr_ty.kind() { ty::Ref(_, _, mt) => { let mtstr = mt.prefix_str(); if self.cast_ty.is_trait() { @@ -602,7 +602,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { (Some(t_from), Some(t_cast)) => (t_from, t_cast), // Function item types may need to be reified before casts. (None, Some(t_cast)) => { - match self.expr_ty.kind { + match *self.expr_ty.kind() { ty::FnDef(..) => { // Attempt a coercion to a fn pointer type. let f = fcx.normalize_associated_types_in( @@ -629,7 +629,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // a cast. ty::Ref(_, inner_ty, mutbl) => { return match t_cast { - Int(_) | Float => match inner_ty.kind { + Int(_) | Float => match *inner_ty.kind() { ty::Int(_) | ty::Uint(_) | ty::Float(_) @@ -768,7 +768,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { // array-ptr-cast. if m_expr.mutbl == hir::Mutability::Not && m_cast.mutbl == hir::Mutability::Not { - if let ty::Array(ety, _) = m_expr.ty.kind { + if let ty::Array(ety, _) = m_expr.ty.kind() { // Due to the limitations of LLVM global constants, // region pointers end up pointing at copies of // vector elements instead of the original values. @@ -817,7 +817,7 @@ impl<'a, 'tcx> CastCheck<'tcx> { } fn cenum_impl_drop_lint(&self, fcx: &FnCtxt<'a, 'tcx>) { - if let ty::Adt(d, _) = self.expr_ty.kind { + if let ty::Adt(d, _) = self.expr_ty.kind() { if d.has_dtor(fcx.tcx) { fcx.tcx.struct_span_lint_hir( lint::builtin::CENUM_IMPL_DROP_CAST, diff --git a/compiler/rustc_typeck/src/check/check.rs b/compiler/rustc_typeck/src/check/check.rs new file mode 100644 index 0000000000..0647be2dfd --- /dev/null +++ b/compiler/rustc_typeck/src/check/check.rs @@ -0,0 +1,1345 @@ +use super::coercion::CoerceMany; +use super::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; +use super::*; + +use rustc_attr as attr; +use rustc_errors::Applicability; +use rustc_hir as hir; +use rustc_hir::def_id::{DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::lang_items::LangItem; +use rustc_hir::{ItemKind, Node}; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_infer::infer::RegionVariableOrigin; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; +use rustc_middle::ty::{self, RegionKind, ToPredicate, Ty, TyCtxt}; +use rustc_session::config::EntryFnType; +use rustc_span::symbol::sym; +use rustc_span::{self, MultiSpan, Span}; +use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits::{self, ObligationCauseCode}; + +pub fn check_wf_new(tcx: TyCtxt<'_>) { + let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); + tcx.hir().krate().par_visit_all_item_likes(&visit); +} + +pub(super) fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { + if !tcx.sess.target.target.is_abi_supported(abi) { + struct_span_err!( + tcx.sess, + span, + E0570, + "The ABI `{}` is not supported for the current target", + abi + ) + .emit() + } +} + +/// Helper used for fns and closures. Does the grungy work of checking a function +/// body and returns the function context used for that purpose, since in the case of a fn item +/// there is still a bit more to do. +/// +/// * ... +/// * inherited: other fields inherited from the enclosing fn (if any) +pub(super) fn check_fn<'a, 'tcx>( + inherited: &'a Inherited<'a, 'tcx>, + param_env: ty::ParamEnv<'tcx>, + fn_sig: ty::FnSig<'tcx>, + decl: &'tcx hir::FnDecl<'tcx>, + fn_id: hir::HirId, + body: &'tcx hir::Body<'tcx>, + can_be_generator: Option, +) -> (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); + *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); + + let tcx = fcx.tcx; + let sess = tcx.sess; + let hir = tcx.hir(); + + let declared_ret_ty = fn_sig.output(); + + let revealed_ret_ty = + fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); + debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); + fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); + fcx.ret_type_span = Some(decl.output.span()); + if let ty::Opaque(..) = declared_ret_ty.kind() { + fcx.ret_coercion_impl_trait = Some(declared_ret_ty); + } + fn_sig = tcx.mk_fn_sig( + fn_sig.inputs().iter().cloned(), + revealed_ret_ty, + fn_sig.c_variadic, + fn_sig.unsafety, + fn_sig.abi, + ); + + let span = body.value.span; + + fn_maybe_err(tcx, span, fn_sig.abi); + + if body.generator_kind.is_some() && can_be_generator.is_some() { + let yield_ty = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + + // Resume type defaults to `()` if the generator has no argument. + let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); + + fcx.resume_yield_tys = Some((resume_ty, yield_ty)); + } + + let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); + let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); + GatherLocalsVisitor::new(&fcx, outer_hir_id).visit_body(body); + + // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` + // (as it's created inside the body itself, not passed in from outside). + let maybe_va_list = if fn_sig.c_variadic { + let span = body.params.last().unwrap().span; + let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); + let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); + + Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) + } else { + None + }; + + // Add formal parameters. + let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); + let inputs_fn = fn_sig.inputs().iter().copied(); + for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { + // Check the pattern. + let ty_span = try { inputs_hir?.get(idx)?.span }; + fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); + + // Check that argument is Sized. + // The check for a non-trivial pattern is a hack to avoid duplicate warnings + // for simple cases like `fn foo(x: Trait)`, + // where we would error once on the parameter as a whole, and once on the binding `x`. + if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { + fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); + } + + fcx.write_ty(param.hir_id, param_ty); + } + + inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); + + fcx.in_tail_expr = true; + if let ty::Dynamic(..) = declared_ret_ty.kind() { + // FIXME: We need to verify that the return type is `Sized` after the return expression has + // been evaluated so that we have types available for all the nodes being returned, but that + // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this + // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, + // while keeping the current ordering we will ignore the tail expression's type because we + // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` + // because we will trigger "unreachable expression" lints unconditionally. + // Because of all of this, we perform a crude check to know whether the simplest `!Sized` + // case that a newcomer might make, returning a bare trait, and in that case we populate + // the tail expression's type so that the suggestion will be correct, but ignore all other + // possible cases. + fcx.check_expr(&body.value); + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); + } else { + fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); + fcx.check_return_expr(&body.value); + } + fcx.in_tail_expr = false; + + // We insert the deferred_generator_interiors entry after visiting the body. + // This ensures that all nested generators appear before the entry of this generator. + // resolve_generator_interiors relies on this property. + let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { + let interior = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); + fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); + + let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); + Some(GeneratorTypes { + resume_ty, + yield_ty, + interior, + movability: can_be_generator.unwrap(), + }) + } else { + None + }; + + // Finalize the return check by taking the LUB of the return types + // 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, + }); + } + fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); + + // Check that the main return type implements the termination trait. + if let Some(term_id) = tcx.lang_items().termination() { + if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { + let main_id = hir.local_def_id_to_hir_id(def_id); + if main_id == fn_id { + let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); + let trait_ref = ty::TraitRef::new(term_id, substs); + let return_ty_span = decl.output.span(); + let cause = traits::ObligationCause::new( + return_ty_span, + fn_id, + ObligationCauseCode::MainFunctionType, + ); + + inherited.register_predicate(traits::Obligation::new( + cause, + param_env, + trait_ref.without_const().to_predicate(tcx), + )); + } + } + } + + // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` + if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { + if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { + if let Some(panic_info_did) = tcx.lang_items().panic_info() { + if *declared_ret_ty.kind() != ty::Never { + sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + let span = hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_panic_info = match *inputs[0].kind() { + ty::Ref(region, ty, mutbl) => match *ty.kind() { + ty::Adt(ref adt, _) => { + adt.did == panic_info_did + && mutbl == hir::Mutability::Not + && *region != RegionKind::ReStatic + } + _ => false, + }, + _ => false, + }; + + if !arg_is_panic_info { + sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); + } + + if let Node::Item(item) = hir.get(fn_id) { + if let ItemKind::Fn(_, ref generics, _) = item.kind { + if !generics.params.is_empty() { + sess.span_err(span, "should have no type parameters"); + } + } + } + } else { + let span = sess.source_map().guess_head_span(span); + sess.span_err(span, "function should have one argument"); + } + } else { + sess.err("language item required, but not found: `panic_info`"); + } + } + } + + // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` + if let Some(alloc_error_handler_did) = tcx.lang_items().oom() { + if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() { + if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { + if *declared_ret_ty.kind() != ty::Never { + sess.span_err(decl.output.span(), "return type should be `!`"); + } + + let inputs = fn_sig.inputs(); + let span = hir.span(fn_id); + if inputs.len() == 1 { + let arg_is_alloc_layout = match inputs[0].kind() { + ty::Adt(ref adt, _) => adt.did == alloc_layout_did, + _ => false, + }; + + if !arg_is_alloc_layout { + sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); + } + + if let Node::Item(item) = hir.get(fn_id) { + if let ItemKind::Fn(_, ref generics, _) = item.kind { + if !generics.params.is_empty() { + sess.span_err( + span, + "`#[alloc_error_handler]` function should have no type \ + parameters", + ); + } + } + } + } else { + let span = sess.source_map().guess_head_span(span); + sess.span_err(span, "function should have one argument"); + } + } else { + sess.err("language item required, but not found: `alloc_layout`"); + } + } + } + + (fcx, gen_ty) +} + +pub(super) fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + check_representable(tcx, span, def_id); + + if def.repr.simd() { + check_simd(tcx, span, def_id); + } + + check_transparent(tcx, span, def); + check_packed(tcx, span, def); +} + +pub(super) fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + check_representable(tcx, span, def_id); + check_transparent(tcx, span, def); + check_union_fields(tcx, span, def_id); + check_packed(tcx, span, def); +} + +/// When the `#![feature(untagged_unions)]` gate is active, +/// check that the fields of the `union` does not contain fields that need dropping. +pub(super) fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { + let item_type = tcx.type_of(item_def_id); + if let ty::Adt(def, substs) = item_type.kind() { + assert!(def.is_union()); + let fields = &def.non_enum_variant().fields; + let param_env = tcx.param_env(item_def_id); + for field in fields { + let field_ty = field.ty(tcx, substs); + // We are currently checking the type this field came from, so it must be local. + let field_span = tcx.hir().span_if_local(field.did).unwrap(); + if field_ty.needs_drop(tcx, param_env) { + struct_span_err!( + tcx.sess, + field_span, + E0740, + "unions may not contain fields that need dropping" + ) + .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type") + .emit(); + return false; + } + } + } else { + span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind()); + } + true +} + +/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` +/// projections that would result in "inheriting lifetimes". +pub(super) fn check_opaque<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + span: Span, + origin: &hir::OpaqueTyOrigin, +) { + check_opaque_for_inheriting_lifetimes(tcx, def_id, span); + tcx.ensure().type_of(def_id); + check_opaque_for_cycles(tcx, def_id, substs, span, origin); +} + +/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result +/// in "inheriting lifetimes". +pub(super) fn check_opaque_for_inheriting_lifetimes( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + span: Span, +) { + let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); + debug!( + "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", + def_id, span, item + ); + + #[derive(Debug)] + struct ProhibitOpaqueVisitor<'tcx> { + opaque_identity_ty: Ty<'tcx>, + generics: &'tcx ty::Generics, + ty: Option>, + }; + + impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); + if t != self.opaque_identity_ty && t.super_visit_with(self) { + self.ty = Some(t); + return true; + } + false + } + + fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { + debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); + if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { + return *index < self.generics.parent_count as u32; + } + + r.super_visit_with(self) + } + + fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(..) = c.val { + // FIXME(#72219) We currenctly don't detect lifetimes within substs + // which would violate this check. Even though the particular substitution is not used + // within the const, this should still be fixed. + return false; + } + c.super_visit_with(self) + } + } + + if let ItemKind::OpaqueTy(hir::OpaqueTy { + origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, + .. + }) = item.kind + { + let mut visitor = ProhibitOpaqueVisitor { + opaque_identity_ty: tcx.mk_opaque( + def_id.to_def_id(), + InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), + ), + generics: tcx.generics_of(def_id), + ty: None, + }; + let prohibit_opaque = tcx + .predicates_of(def_id) + .predicates + .iter() + .any(|(predicate, _)| predicate.visit_with(&mut visitor)); + debug!( + "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", + prohibit_opaque, visitor + ); + + if prohibit_opaque { + let is_async = match item.kind { + ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { + hir::OpaqueTyOrigin::AsyncFn => true, + _ => false, + }, + _ => unreachable!(), + }; + + let mut err = struct_span_err!( + tcx.sess, + span, + E0760, + "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ + a parent scope", + if is_async { "async fn" } else { "impl Trait" }, + ); + + if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { + if snippet == "Self" { + if let Some(ty) = visitor.ty { + err.span_suggestion( + span, + "consider spelling out the type instead", + format!("{:?}", ty), + Applicability::MaybeIncorrect, + ); + } + } + } + err.emit(); + } + } +} + +/// Checks that an opaque type does not contain cycles. +pub(super) fn check_opaque_for_cycles<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + substs: SubstsRef<'tcx>, + span: Span, + origin: &hir::OpaqueTyOrigin, +) { + if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) + { + match origin { + hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span), + hir::OpaqueTyOrigin::Binding => { + binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type) + } + _ => opaque_type_cycle_error(tcx, def_id, span), + } + } +} + +pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { + debug!( + "check_item_type(it.hir_id={}, it.name={})", + it.hir_id, + tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id()) + ); + let _indenter = indenter(); + match it.kind { + // Consts can play a role in type-checking, so they are included here. + hir::ItemKind::Static(..) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + tcx.ensure().typeck(def_id); + maybe_check_static_with_link_section(tcx, def_id, it.span); + } + hir::ItemKind::Const(..) => { + tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id)); + } + hir::ItemKind::Enum(ref enum_definition, _) => { + check_enum(tcx, it.span, &enum_definition.variants, it.hir_id); + } + hir::ItemKind::Fn(..) => {} // entirely within check_item_body + hir::ItemKind::Impl { ref items, .. } => { + debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id); + let impl_def_id = tcx.hir().local_def_id(it.hir_id); + if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { + check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items); + let trait_def_id = impl_trait_ref.def_id; + check_on_unimplemented(tcx, trait_def_id, it); + } + } + hir::ItemKind::Trait(_, _, _, _, ref items) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + check_on_unimplemented(tcx, def_id.to_def_id(), it); + + for item in items.iter() { + let item = tcx.hir().trait_item(item.id); + if let hir::TraitItemKind::Fn(sig, _) = &item.kind { + let abi = sig.header.abi; + fn_maybe_err(tcx, item.ident.span, abi); + } + } + } + hir::ItemKind::Struct(..) => { + check_struct(tcx, it.hir_id, it.span); + } + hir::ItemKind::Union(..) => { + check_union(tcx, it.hir_id, it.span); + } + hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { + // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting + // `async-std` (and `pub async fn` in general). + // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! + // See https://github.com/rust-lang/rust/issues/75100 + if !tcx.sess.opts.actually_rustdoc { + let def_id = tcx.hir().local_def_id(it.hir_id); + + let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); + check_opaque(tcx, def_id, substs, it.span, &origin); + } + } + hir::ItemKind::TyAlias(..) => { + let def_id = tcx.hir().local_def_id(it.hir_id); + let pty_ty = tcx.type_of(def_id); + let generics = tcx.generics_of(def_id); + check_type_params_are_used(tcx, &generics, pty_ty); + } + hir::ItemKind::ForeignMod(ref m) => { + check_abi(tcx, it.span, m.abi); + + if m.abi == Abi::RustIntrinsic { + for item in m.items { + intrinsic::check_intrinsic_type(tcx, item); + } + } else if m.abi == Abi::PlatformIntrinsic { + for item in m.items { + intrinsic::check_platform_intrinsic_type(tcx, item); + } + } else { + for item in m.items { + let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id)); + let own_counts = generics.own_counts(); + if generics.params.len() - own_counts.lifetimes != 0 { + let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { + (_, 0) => ("type", "types", Some("u32")), + // We don't specify an example value, because we can't generate + // a valid value for any type. + (0, _) => ("const", "consts", None), + _ => ("type or const", "types or consts", None), + }; + struct_span_err!( + tcx.sess, + item.span, + E0044, + "foreign items may not have {} parameters", + kinds, + ) + .span_label(item.span, &format!("can't have {} parameters", kinds)) + .help( + // FIXME: once we start storing spans for type arguments, turn this + // into a suggestion. + &format!( + "replace the {} parameters with concrete {}{}", + kinds, + kinds_pl, + egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), + ), + ) + .emit(); + } + + if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind { + require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); + } + } + } + } + _ => { /* nothing to do */ } + } +} + +pub(super) fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) { + let item_def_id = tcx.hir().local_def_id(item.hir_id); + // an error would be reported if this fails. + let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id()); +} + +pub(super) fn check_specialization_validity<'tcx>( + tcx: TyCtxt<'tcx>, + trait_def: &ty::TraitDef, + trait_item: &ty::AssocItem, + impl_id: DefId, + impl_item: &hir::ImplItem<'_>, +) { + let kind = match impl_item.kind { + hir::ImplItemKind::Const(..) => ty::AssocKind::Const, + hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, + hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, + }; + + let ancestors = match trait_def.ancestors(tcx, impl_id) { + Ok(ancestors) => ancestors, + Err(_) => return, + }; + let mut ancestor_impls = ancestors + .skip(1) + .filter_map(|parent| { + if parent.is_from_trait() { + None + } else { + Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) + } + }) + .peekable(); + + if ancestor_impls.peek().is_none() { + // No parent, nothing to specialize. + return; + } + + let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { + match parent_item { + // Parent impl exists, and contains the parent item we're trying to specialize, but + // doesn't mark it `default`. + Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { + Some(Err(parent_impl.def_id())) + } + + // Parent impl contains item and makes it specializable. + Some(_) => Some(Ok(())), + + // Parent impl doesn't mention the item. This means it's inherited from the + // grandparent. In that case, if parent is a `default impl`, inherited items use the + // "defaultness" from the grandparent, else they are final. + None => { + if tcx.impl_defaultness(parent_impl.def_id()).is_default() { + None + } else { + Some(Err(parent_impl.def_id())) + } + } + } + }); + + // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the + // item. This is allowed, the item isn't actually getting specialized here. + let result = opt_result.unwrap_or(Ok(())); + + if let Err(parent_impl) = result { + report_forbidden_specialization(tcx, impl_item, parent_impl); + } +} + +pub(super) fn check_impl_items_against_trait<'tcx>( + tcx: TyCtxt<'tcx>, + full_impl_span: Span, + impl_id: LocalDefId, + impl_trait_ref: ty::TraitRef<'tcx>, + impl_item_refs: &[hir::ImplItemRef<'_>], +) { + let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); + + // 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` + // isn't populated for such impls. + if impl_trait_ref.references_error() { + return; + } + + // Negative impls are not expected to have any items + match tcx.impl_polarity(impl_id) { + ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} + ty::ImplPolarity::Negative => { + if let [first_item_ref, ..] = impl_item_refs { + let first_item_span = tcx.hir().impl_item(first_item_ref.id).span; + struct_span_err!( + tcx.sess, + first_item_span, + E0749, + "negative impls cannot have any items" + ) + .emit(); + } + return; + } + } + + // Locate trait definition and items + let trait_def = tcx.trait_def(impl_trait_ref.def_id); + + let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); + + // Check existing impl methods to see if they are both present in trait + // and compatible with trait signature + for impl_item in impl_items() { + let namespace = impl_item.kind.namespace(); + let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); + let ty_trait_item = tcx + .associated_items(impl_trait_ref.def_id) + .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) + .or_else(|| { + // Not compatible, but needed for the error message + tcx.associated_items(impl_trait_ref.def_id) + .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) + .next() + }); + + // Check that impl definition matches trait definition + if let Some(ty_trait_item) = ty_trait_item { + match impl_item.kind { + hir::ImplItemKind::Const(..) => { + // Find associated const definition. + if ty_trait_item.kind == ty::AssocKind::Const { + compare_const_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0323, + "item `{}` is an associated const, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + // We can only get the spans from local trait definition + // Same for E0324 and E0325 + if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + hir::ImplItemKind::Fn(..) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssocKind::Fn { + compare_impl_method( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0324, + "item `{}` is an associated method, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + hir::ImplItemKind::TyAlias(_) => { + let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); + if ty_trait_item.kind == ty::AssocKind::Type { + compare_ty_impl( + tcx, + &ty_impl_item, + impl_item.span, + &ty_trait_item, + impl_trait_ref, + opt_trait_span, + ); + } else { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0325, + "item `{}` is an associated type, \ + which doesn't match its trait `{}`", + ty_impl_item.ident, + impl_trait_ref.print_only_trait_path() + ); + err.span_label(impl_item.span, "does not match trait"); + if let Some(trait_span) = opt_trait_span { + err.span_label(trait_span, "item in trait"); + } + err.emit() + } + } + } + + check_specialization_validity( + tcx, + trait_def, + &ty_trait_item, + impl_id.to_def_id(), + impl_item, + ); + } + } + + // Check for missing items from trait + let mut missing_items = Vec::new(); + if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { + for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { + let is_implemented = ancestors + .leaf_def(tcx, trait_item.ident, trait_item.kind) + .map(|node_item| !node_item.defining_node.is_from_trait()) + .unwrap_or(false); + + if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { + if !trait_item.defaultness.has_value() { + missing_items.push(*trait_item); + } + } + } + } + + if !missing_items.is_empty() { + missing_items_err(tcx, impl_span, &missing_items, full_impl_span); + } +} + +/// Checks whether a type can be represented in memory. In particular, it +/// identifies types that contain themselves without indirection through a +/// pointer, which would mean their size is unbounded. +pub(super) fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool { + let rty = tcx.type_of(item_def_id); + + // Check that it is possible to represent this type. This call identifies + // (1) types that contain themselves and (2) types that contain a different + // recursive type. It is only necessary to throw an error on those that + // contain themselves. For case 2, there must be an inner type that will be + // caught by case 1. + match rty.is_representable(tcx, sp) { + Representability::SelfRecursive(spans) => { + recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); + return false; + } + Representability::Representable | Representability::ContainsRecursive => (), + } + true +} + +pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { + let t = tcx.type_of(def_id); + if let ty::Adt(def, substs) = t.kind() { + if def.is_struct() { + let fields = &def.non_enum_variant().fields; + if fields.is_empty() { + struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); + return; + } + let e = fields[0].ty(tcx, substs); + if !fields.iter().all(|f| f.ty(tcx, substs) == e) { + struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") + .span_label(sp, "SIMD elements must have the same type") + .emit(); + return; + } + match e.kind() { + ty::Param(_) => { /* struct(T, T, T, T) is ok */ } + _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } + _ => { + struct_span_err!( + tcx.sess, + sp, + E0077, + "SIMD vector element type should be machine type" + ) + .emit(); + return; + } + } + } + } +} + +pub(super) fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { + let repr = def.repr; + if repr.packed() { + for attr in tcx.get_attrs(def.did).iter() { + for r in attr::find_repr_attrs(&tcx.sess, attr) { + if let attr::ReprPacked(pack) = r { + if let Some(repr_pack) = repr.pack { + if pack as u64 != repr_pack.bytes() { + struct_span_err!( + tcx.sess, + sp, + E0634, + "type has conflicting packed representation hints" + ) + .emit(); + } + } + } + } + } + if repr.align.is_some() { + struct_span_err!( + tcx.sess, + sp, + E0587, + "type has conflicting packed and align representation hints" + ) + .emit(); + } else { + if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) { + let mut err = struct_span_err!( + tcx.sess, + sp, + E0588, + "packed type cannot transitively contain a `#[repr(align)]` type" + ); + + err.span_note( + tcx.def_span(def_spans[0].0), + &format!( + "`{}` has a `#[repr(align)]` attribute", + tcx.item_name(def_spans[0].0) + ), + ); + + if def_spans.len() > 2 { + let mut first = true; + for (adt_def, span) in def_spans.iter().skip(1).rev() { + let ident = tcx.item_name(*adt_def); + err.span_note( + *span, + &if first { + format!( + "`{}` contains a field of type `{}`", + tcx.type_of(def.did), + ident + ) + } else { + format!("...which contains a field of type `{}`", ident) + }, + ); + first = false; + } + } + + err.emit(); + } + } + } +} + +pub(super) fn check_packed_inner( + tcx: TyCtxt<'_>, + def_id: DefId, + stack: &mut Vec, +) -> Option> { + if let ty::Adt(def, substs) = tcx.type_of(def_id).kind() { + if def.is_struct() || def.is_union() { + if def.repr.align.is_some() { + return Some(vec![(def.did, DUMMY_SP)]); + } + + stack.push(def_id); + for field in &def.non_enum_variant().fields { + if let ty::Adt(def, _) = field.ty(tcx, substs).kind() { + if !stack.contains(&def.did) { + if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) { + defs.push((def.did, field.ident.span)); + return Some(defs); + } + } + } + } + stack.pop(); + } + } + + None +} + +pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) { + if !adt.repr.transparent() { + return; + } + let sp = tcx.sess.source_map().guess_head_span(sp); + + if adt.is_union() && !tcx.features().transparent_unions { + feature_err( + &tcx.sess.parse_sess, + sym::transparent_unions, + sp, + "transparent unions are unstable", + ) + .emit(); + } + + if adt.variants.len() != 1 { + bad_variant_count(tcx, adt, sp, adt.did); + if adt.variants.is_empty() { + // Don't bother checking the fields. No variants (and thus no fields) exist. + return; + } + } + + // For each field, figure out if it's known to be a ZST and align(1) + let field_infos = adt.all_fields().map(|field| { + let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); + let param_env = tcx.param_env(field.did); + let layout = tcx.layout_of(param_env.and(ty)); + // We are currently checking the type this field came from, so it must be local + let span = tcx.hir().span_if_local(field.did).unwrap(); + let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); + let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); + (span, zst, align1) + }); + + let non_zst_fields = + field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); + let non_zst_count = non_zst_fields.clone().count(); + if non_zst_count != 1 { + bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); + } + for (span, zst, align1) in field_infos { + if zst && !align1 { + struct_span_err!( + tcx.sess, + span, + E0691, + "zero-sized field in transparent {} has alignment larger than 1", + adt.descr(), + ) + .span_label(span, "has alignment larger than 1") + .emit(); + } + } +} + +#[allow(trivial_numeric_casts)] +pub fn check_enum<'tcx>( + tcx: TyCtxt<'tcx>, + sp: Span, + vs: &'tcx [hir::Variant<'tcx>], + id: hir::HirId, +) { + let def_id = tcx.hir().local_def_id(id); + let def = tcx.adt_def(def_id); + def.destructor(tcx); // force the destructor to be evaluated + + if vs.is_empty() { + let attributes = tcx.get_attrs(def_id.to_def_id()); + if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) { + struct_span_err!( + tcx.sess, + attr.span, + E0084, + "unsupported representation for zero-variant enum" + ) + .span_label(sp, "zero-variant enum") + .emit(); + } + } + + let repr_type_ty = def.repr.discr_type().to_ty(tcx); + if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { + if !tcx.features().repr128 { + feature_err( + &tcx.sess.parse_sess, + sym::repr128, + sp, + "repr with 128-bit type is unstable", + ) + .emit(); + } + } + + for v in vs { + if let Some(ref e) = v.disr_expr { + tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); + } + } + + if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { + let is_unit = |var: &hir::Variant<'_>| match var.data { + hir::VariantData::Unit(..) => true, + _ => false, + }; + + let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); + let has_non_units = vs.iter().any(|var| !is_unit(var)); + let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); + let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); + + if disr_non_unit || (disr_units && has_non_units) { + let mut err = + struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); + err.emit(); + } + } + + let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); + for ((_, discr), v) in def.discriminants(tcx).zip(vs) { + // Check for duplicate discriminant values + if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { + let variant_did = def.variants[VariantIdx::new(i)].def_id; + let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local()); + let variant_i = tcx.hir().expect_variant(variant_i_hir_id); + let i_span = match variant_i.disr_expr { + Some(ref expr) => tcx.hir().span(expr.hir_id), + None => tcx.hir().span(variant_i_hir_id), + }; + let span = match v.disr_expr { + Some(ref expr) => tcx.hir().span(expr.hir_id), + None => v.span, + }; + struct_span_err!( + tcx.sess, + span, + E0081, + "discriminant value `{}` already exists", + disr_vals[i] + ) + .span_label(i_span, format!("first use of `{}`", disr_vals[i])) + .span_label(span, format!("enum already has `{}`", disr_vals[i])) + .emit(); + } + disr_vals.push(discr); + } + + check_representable(tcx, sp, def_id); + check_transparent(tcx, sp, def); +} + +pub(super) fn check_type_params_are_used<'tcx>( + tcx: TyCtxt<'tcx>, + generics: &ty::Generics, + ty: Ty<'tcx>, +) { + debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); + + assert_eq!(generics.parent, None); + + if generics.own_counts().types == 0 { + return; + } + + let mut params_used = BitSet::new_empty(generics.params.len()); + + if ty.references_error() { + // If there is already another error, do not emit + // an error for not using a type parameter. + assert!(tcx.sess.has_errors()); + return; + } + + for leaf in ty.walk() { + if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { + if let ty::Param(param) = leaf_ty.kind() { + debug!("found use of ty param {:?}", param); + params_used.insert(param.index); + } + } + } + + for param in &generics.params { + if !params_used.contains(param.index) { + if let ty::GenericParamDefKind::Type { .. } = param.kind { + let span = tcx.def_span(param.def_id); + struct_span_err!( + tcx.sess, + span, + E0091, + "type parameter `{}` is unused", + param.name, + ) + .span_label(span, "unused type parameter") + .emit(); + } + } + } +} + +pub(super) fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { + tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); +} + +pub(super) fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_item_well_formed(tcx, def_id); +} + +pub(super) fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_trait_item(tcx, def_id); +} + +pub(super) fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { + wfcheck::check_impl_item(tcx, def_id); +} + +fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { + struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") + .span_label(span, "recursive `async fn`") + .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") + .emit(); +} + +/// Emit an error for recursive opaque types. +/// +/// If this is a return `impl Trait`, find the item's return expressions and point at them. For +/// direct recursion this is enough, but for indirect recursion also point at the last intermediary +/// `impl Trait`. +/// +/// If all the return expressions evaluate to `!`, then we explain that the error will go away +/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. +fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { + let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); + + let mut label = false; + if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) { + let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id)); + if visitor + .returns + .iter() + .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) + .all(|ty| matches!(ty.kind(), ty::Never)) + { + let spans = visitor + .returns + .iter() + .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some()) + .map(|expr| expr.span) + .collect::>(); + let span_len = spans.len(); + if span_len == 1 { + err.span_label(spans[0], "this returned value is of `!` type"); + } else { + let mut multispan: MultiSpan = spans.clone().into(); + for span in spans { + multispan + .push_span_label(span, "this returned value is of `!` type".to_string()); + } + err.span_note(multispan, "these returned values have a concrete \"never\" type"); + } + err.help("this error will resolve once the item's body returns a concrete type"); + } else { + let mut seen = FxHashSet::default(); + seen.insert(span); + err.span_label(span, "recursive opaque type"); + label = true; + for (sp, ty) in visitor + .returns + .iter() + .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) + .filter(|(_, ty)| !matches!(ty.kind(), ty::Never)) + { + struct VisitTypes(Vec); + impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { + fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { + match *t.kind() { + ty::Opaque(def, _) => { + self.0.push(def); + false + } + _ => t.super_visit_with(self), + } + } + } + let mut visitor = VisitTypes(vec![]); + ty.visit_with(&mut visitor); + for def_id in visitor.0 { + let ty_span = tcx.def_span(def_id); + if !seen.contains(&ty_span) { + err.span_label(ty_span, &format!("returning this opaque type `{}`", ty)); + seen.insert(ty_span); + } + err.span_label(sp, &format!("returning here with type `{}`", ty)); + } + } + } + } + if !label { + err.span_label(span, "cannot resolve opaque type"); + } + err.emit(); +} diff --git a/src/librustc_typeck/check/closure.rs b/compiler/rustc_typeck/src/check/closure.rs similarity index 99% rename from src/librustc_typeck/check/closure.rs rename to compiler/rustc_typeck/src/check/closure.rs index 97f7e4537c..8898a54522 100644 --- a/src/librustc_typeck/check/closure.rs +++ b/compiler/rustc_typeck/src/check/closure.rs @@ -170,7 +170,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> (Option>, Option) { debug!("deduce_expectations_from_expected_type(expected_ty={:?})", expected_ty); - match expected_ty.kind { + match *expected_ty.kind() { ty::Dynamic(ref object_type, ..) => { let sig = object_type.projection_bounds().find_map(|pb| { let pb = pb.with_self_ty(self.tcx, self.tcx.types.trait_object_dummy_self); @@ -268,7 +268,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let arg_param_ty = self.resolve_vars_if_possible(&arg_param_ty); debug!("deduce_sig_from_projection: arg_param_ty={:?}", arg_param_ty); - match arg_param_ty.kind { + match arg_param_ty.kind() { ty::Tuple(tys) => tys.into_iter().map(|k| k.expect_ty()).collect::>(), _ => return None, } @@ -611,7 +611,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // be inferring. let ret_ty = ret_coercion.borrow().expected_ty(); let ret_ty = self.inh.infcx.shallow_resolve(ret_ty); - let ret_vid = match ret_ty.kind { + let ret_vid = match *ret_ty.kind() { ty::Infer(ty::TyVar(ret_vid)) => ret_vid, _ => span_bug!( self.tcx.def_span(expr_def_id), diff --git a/src/librustc_typeck/check/coercion.rs b/compiler/rustc_typeck/src/check/coercion.rs similarity index 96% rename from src/librustc_typeck/check/coercion.rs rename to compiler/rustc_typeck/src/check/coercion.rs index f0802c45ae..4addee1a4c 100644 --- a/src/librustc_typeck/check/coercion.rs +++ b/compiler/rustc_typeck/src/check/coercion.rs @@ -37,7 +37,7 @@ use crate::astconv::AstConv; use crate::check::FnCtxt; -use rustc_errors::{struct_span_err, DiagnosticBuilder}; +use rustc_errors::{struct_span_err, Applicability, DiagnosticBuilder}; use rustc_hir as hir; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::{Coercion, InferOk, InferResult}; @@ -51,7 +51,7 @@ use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{self, Ty, TypeAndMut}; use rustc_session::parse::feature_err; use rustc_span::symbol::sym; -use rustc_span::{self, Span}; +use rustc_span::{self, BytePos, Span}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::traits::error_reporting::InferCtxtExt; use rustc_trait_selection::traits::{self, ObligationCause, ObligationCauseCode}; @@ -197,7 +197,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // // Note: does not attempt to resolve type variables we encounter. // See above for details. - match b.kind { + match *b.kind() { ty::RawPtr(mt_b) => { return self.coerce_unsafe_ptr(a, b, mt_b.mutbl); } @@ -207,7 +207,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { _ => {} } - match a.kind { + match *a.kind() { ty::FnDef(..) => { // Function items are coercible to any closure // type; function pointers are not (that would @@ -252,7 +252,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // to type check, we will construct the type that `&M*expr` would // yield. - let (r_a, mt_a) = match a.kind { + let (r_a, mt_a) = match *a.kind() { ty::Ref(r_a, ty, mutbl) => { let mt_a = ty::TypeAndMut { ty, mutbl }; coerce_mutbls(mt_a.mutbl, mutbl_b)?; @@ -415,7 +415,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // Now apply the autoref. We have to extract the region out of // the final ref type we got. - let r_borrow = match ty.kind { + let r_borrow = match ty.kind() { ty::Ref(r_borrow, _, _) => r_borrow, _ => span_bug!(span, "expected a ref type, got {:?}", ty), }; @@ -490,7 +490,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { // that, at which point we will need extra checks on the target here. // Handle reborrows before selecting `Source: CoerceUnsized`. - let reborrow = match (&source.kind, &target.kind) { + let reborrow = match (source.kind(), target.kind()) { (&ty::Ref(_, ty_a, mutbl_a), &ty::Ref(_, _, mutbl_b)) => { coerce_mutbls(mutbl_a, mutbl_b)?; @@ -588,7 +588,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { { if unsize_did == trait_pred.def_id() { let unsize_ty = trait_pred.trait_ref.substs[1].expect_ty(); - if let ty::Tuple(..) = unsize_ty.kind { + if let ty::Tuple(..) = unsize_ty.kind() { debug!("coerce_unsized: found unsized tuple coercion"); has_unsized_tuple_coercion = true; } @@ -608,7 +608,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let self_ty = trait_pred.skip_binder().self_ty(); let unsize_ty = trait_pred.skip_binder().trait_ref.substs[1].expect_ty(); debug!("coerce_unsized: ambiguous unsize case for {:?}", trait_pred); - match (&self_ty.kind, &unsize_ty.kind) { + match (&self_ty.kind(), &unsize_ty.kind()) { (ty::Infer(ty::TyVar(v)), ty::Dynamic(..)) if self.type_var_is_sized(*v) => { @@ -672,7 +672,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { F: FnOnce(Ty<'tcx>) -> Vec>, G: FnOnce(Ty<'tcx>) -> Vec>, { - if let ty::FnPtr(fn_ty_b) = b.kind { + if let ty::FnPtr(fn_ty_b) = b.kind() { if let (hir::Unsafety::Normal, hir::Unsafety::Unsafe) = (fn_ty_a.unsafety(), fn_ty_b.unsafety()) { @@ -712,7 +712,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let b = self.shallow_resolve(b); debug!("coerce_from_fn_item(a={:?}, b={:?})", a, b); - match b.kind { + match b.kind() { ty::FnPtr(b_sig) => { let a_sig = a.fn_sig(self.tcx); // Intrinsics are not coercible to function pointers @@ -721,7 +721,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { } // Safe `#[target_feature]` functions are not assignable to safe fn pointers (RFC 2396). - if let ty::FnDef(def_id, _) = a.kind { + if let ty::FnDef(def_id, _) = *a.kind() { if b_sig.unsafety() == hir::Unsafety::Normal && !self.tcx.codegen_fn_attrs(def_id).target_features.is_empty() { @@ -771,7 +771,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { let b = self.shallow_resolve(b); - match b.kind { + match b.kind() { ty::FnPtr(fn_ty) if substs_a.as_closure().upvar_tys().next().is_none() => { // We coerce the closure, which has fn type // `extern "rust-call" fn((arg0,arg1,...)) -> _` @@ -802,7 +802,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> { ) -> CoerceResult<'tcx> { debug!("coerce_unsafe_ptr(a={:?}, b={:?})", a, b); - let (is_ref, mt_a) = match a.kind { + let (is_ref, mt_a) = match *a.kind() { ty::Ref(_, ty, mutbl) => (true, ty::TypeAndMut { ty, mutbl }), ty::RawPtr(mt) => (false, mt), _ => return self.unify_and(a, b, identity), @@ -912,10 +912,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } }; - if is_capturing_closure(&prev_ty.kind) || is_capturing_closure(&new_ty.kind) { + if is_capturing_closure(&prev_ty.kind()) || is_capturing_closure(&new_ty.kind()) { (None, None) } else { - match (&prev_ty.kind, &new_ty.kind) { + match (&prev_ty.kind(), &new_ty.kind()) { (&ty::FnDef(..), &ty::FnDef(..)) => { // Don't reify if the function types have a LUB, i.e., they // are the same function and their parameters have a LUB. @@ -969,12 +969,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Reify both sides and return the reified fn pointer type. let fn_ptr = self.tcx.mk_fn_ptr(sig); - let prev_adjustment = match prev_ty.kind { + let prev_adjustment = match prev_ty.kind() { ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(a_sig.unsafety())), ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), _ => unreachable!(), }; - let next_adjustment = match new_ty.kind { + let next_adjustment = match new_ty.kind() { ty::Closure(..) => Adjust::Pointer(PointerCast::ClosureFnPointer(b_sig.unsafety())), ty::FnDef(..) => Adjust::Pointer(PointerCast::ReifyFnPointer), _ => unreachable!(), @@ -1024,7 +1024,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let noop = match self.typeck_results.borrow().expr_adjustments(expr) { &[Adjustment { kind: Adjust::Deref(_), .. }, Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(_, mutbl_adj)), .. }] => { - match self.node_ty(expr.hir_id).kind { + match *self.node_ty(expr.hir_id).kind() { ty::Ref(_, _, mt_orig) => { let mutbl_adj: hir::Mutability = mutbl_adj.into(); // Reborrow that we can safely ignore, because @@ -1459,7 +1459,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } } if let (Some(sp), Some(fn_output)) = (fcx.ret_coercion_span.borrow().as_ref(), fn_output) { - self.add_impl_trait_explanation(&mut err, fcx, expected, *sp, fn_output); + self.add_impl_trait_explanation(&mut err, cause, fcx, expected, *sp, fn_output); } err } @@ -1467,6 +1467,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { fn add_impl_trait_explanation<'a>( &self, err: &mut DiagnosticBuilder<'a>, + cause: &ObligationCause<'tcx>, fcx: &FnCtxt<'a, 'tcx>, expected: Ty<'tcx>, sp: Span, @@ -1501,7 +1502,7 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { if let hir::TyKind::OpaqueDef(..) = ty.kind { let ty = AstConv::ast_ty_to_ty(fcx, ty); // Get the `impl Trait`'s `DefId`. - if let ty::Opaque(def_id, _) = ty.kind { + if let ty::Opaque(def_id, _) = ty.kind() { let hir_id = fcx.tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); // Get the `impl Trait`'s `Item` so that we can get its trait bounds and // get the `Trait`'s `DefId`. @@ -1523,10 +1524,30 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { }; if has_impl { if is_object_safe { - err.help(&format!( - "you can instead return a boxed trait object using `Box`", - &snippet[5..] - )); + err.multipart_suggestion( + "you could change the return type to be a boxed trait object", + vec![ + (return_sp.with_hi(return_sp.lo() + BytePos(4)), "Box".to_string()), + ], + Applicability::MachineApplicable, + ); + let sugg = vec![sp, cause.span] + .into_iter() + .flat_map(|sp| { + vec![ + (sp.shrink_to_lo(), "Box::new(".to_string()), + (sp.shrink_to_hi(), ")".to_string()), + ] + .into_iter() + }) + .collect::>(); + err.multipart_suggestion( + "if you change the return type to expect trait objects, box the returned \ + expressions", + sugg, + Applicability::MaybeIncorrect, + ); } else { err.help(&format!( "if the trait `{}` were object safe, you could return a boxed trait object", @@ -1535,14 +1556,14 @@ impl<'tcx, 'exprs, E: AsCoercionSite> CoerceMany<'tcx, 'exprs, E> { } err.note(trait_obj_msg); } - err.help("alternatively, create a new `enum` with a variant for each returned type"); + err.help("you could instead create a new `enum` with a variant for each returned type"); } fn is_return_ty_unsized(&self, fcx: &FnCtxt<'a, 'tcx>, blk_id: hir::HirId) -> bool { if let Some((fn_decl, _)) = fcx.get_fn_decl(blk_id) { if let hir::FnRetTy::Return(ty) = fn_decl.output { let ty = AstConv::ast_ty_to_ty(fcx, ty); - if let ty::Dynamic(..) = ty.kind { + if let ty::Dynamic(..) = ty.kind() { return true; } } diff --git a/src/librustc_typeck/check/compare_method.rs b/compiler/rustc_typeck/src/check/compare_method.rs similarity index 98% rename from src/librustc_typeck/check/compare_method.rs rename to compiler/rustc_typeck/src/check/compare_method.rs index 7adcd7b472..7aa54e0ebc 100644 --- a/src/librustc_typeck/check/compare_method.rs +++ b/compiler/rustc_typeck/src/check/compare_method.rs @@ -1,3 +1,4 @@ +use crate::errors::LifetimesOrBoundsMismatchOnTrait; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticId, ErrorReported}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; @@ -201,11 +202,8 @@ fn compare_predicate_entailment<'tcx>( // The key step here is to update the caller_bounds's predicates to be // the new hybrid bounds we computed. let normalize_cause = traits::ObligationCause::misc(impl_m_span, impl_m_hir_id); - let param_env = ty::ParamEnv::new( - tcx.intern_predicates(&hybrid_preds.predicates), - Reveal::UserFacing, - None, - ); + let param_env = + ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, impl_m.def_id, @@ -366,24 +364,18 @@ fn check_region_bounds_on_impl_item<'tcx>( let item_kind = assoc_item_kind_str(impl_m); let def_span = tcx.sess.source_map().guess_head_span(span); let span = tcx.hir().get_generics(impl_m.def_id).map(|g| g.span).unwrap_or(def_span); - let mut err = struct_span_err!( - tcx.sess, - span, - E0195, - "lifetime parameters or bounds on {} `{}` do not match the trait declaration", - item_kind, - impl_m.ident, - ); - err.span_label(span, &format!("lifetimes do not match {} in trait", item_kind)); - if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { + let generics_span = if let Some(sp) = tcx.hir().span_if_local(trait_m.def_id) { let def_sp = tcx.sess.source_map().guess_head_span(sp); - let sp = tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp); - err.span_label( - sp, - &format!("lifetimes in impl do not match this {} in trait", item_kind), - ); - } - err.emit(); + Some(tcx.hir().get_generics(trait_m.def_id).map(|g| g.span).unwrap_or(def_sp)) + } else { + None + }; + tcx.sess.emit_err(LifetimesOrBoundsMismatchOnTrait { + span, + item_kind, + ident: impl_m.ident, + generics_span, + }); return Err(ErrorReported); } @@ -1125,11 +1117,8 @@ fn compare_type_predicate_entailment<'tcx>( debug!("compare_type_predicate_entailment: bounds={:?}", hybrid_preds); let normalize_cause = traits::ObligationCause::misc(impl_ty_span, impl_ty_hir_id); - let param_env = ty::ParamEnv::new( - tcx.intern_predicates(&hybrid_preds.predicates), - Reveal::UserFacing, - None, - ); + let param_env = + ty::ParamEnv::new(tcx.intern_predicates(&hybrid_preds.predicates), Reveal::UserFacing); let param_env = traits::normalize_param_env_or_error( tcx, impl_ty.def_id, @@ -1232,7 +1221,7 @@ fn compare_projection_bounds<'tcx>( }) .to_predicate(tcx), ); - ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing, None) + ty::ParamEnv::new(tcx.intern_predicates(&predicates), Reveal::UserFacing) }; tcx.infer_ctxt().enter(move |infcx| { diff --git a/src/librustc_typeck/check/demand.rs b/compiler/rustc_typeck/src/check/demand.rs similarity index 97% rename from src/librustc_typeck/check/demand.rs rename to compiler/rustc_typeck/src/check/demand.rs index 5dc5480c33..3e66885448 100644 --- a/src/librustc_typeck/check/demand.rs +++ b/compiler/rustc_typeck/src/check/demand.rs @@ -117,11 +117,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - // Checks that the type of `expr` can be coerced to `expected`. - // - // N.B., this code relies on `self.diverges` to be accurate. In - // particular, assignments to `!` will be permitted if the - // diverges flag is currently "always". + /// Checks that the type of `expr` can be coerced to `expected`. + /// + /// N.B., this code relies on `self.diverges` to be accurate. In particular, assignments to `!` + /// will be permitted if the diverges flag is currently "always". pub fn demand_coerce_diag( &self, expr: &hir::Expr<'_>, @@ -186,7 +185,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expected: Ty<'tcx>, expr_ty: Ty<'tcx>, ) { - if let ty::Adt(expected_adt, substs) = expected.kind { + if let ty::Adt(expected_adt, substs) = expected.kind() { if !expected_adt.is_enum() { return; } @@ -362,15 +361,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { false } - fn replace_prefix(&self, s: A, old: B, new: C) -> Option - where - A: AsRef, - B: AsRef, - C: AsRef, - { - let s = s.as_ref(); - let old = old.as_ref(); - if s.starts_with(old) { Some(new.as_ref().to_owned() + &s[old.len()..]) } else { None } + fn replace_prefix(&self, s: &str, old: &str, new: &str) -> Option { + if let Some(stripped) = s.strip_prefix(old) { + Some(new.to_string() + stripped) + } else { + None + } } /// This function is used to determine potential "simple" improvements or users' errors and @@ -413,12 +409,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `ExprKind::DropTemps` is semantically irrelevant for these suggestions. let expr = expr.peel_drop_temps(); - match (&expr.kind, &expected.kind, &checked_ty.kind) { - (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (&exp.kind, &check.kind) { + match (&expr.kind, expected.kind(), checked_ty.kind()) { + (_, &ty::Ref(_, exp, _), &ty::Ref(_, check, _)) => match (exp.kind(), check.kind()) { (&ty::Str, &ty::Array(arr, _) | &ty::Slice(arr)) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "b\"", "\"") { + if let Some(src) = self.replace_prefix(&src, "b\"", "\"") { return Some(( sp, "consider removing the leading `b`", @@ -432,7 +428,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (&ty::Array(arr, _) | &ty::Slice(arr), &ty::Str) if arr == self.tcx.types.u8 => { if let hir::ExprKind::Lit(_) = expr.kind { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "\"", "b\"") { + if let Some(src) = self.replace_prefix(&src, "\"", "b\"") { return Some(( sp, "consider adding a leading `b`", @@ -557,7 +553,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // we may want to suggest removing a `&`. if sm.is_imported(expr.span) { if let Ok(src) = sm.span_to_snippet(sp) { - if let Some(src) = self.replace_prefix(src, "&", "") { + if let Some(src) = self.replace_prefix(&src, "&", "") { return Some(( sp, "consider removing the borrow", @@ -594,7 +590,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match mutbl_a { hir::Mutability::Mut => { if let Some(s) = - self.replace_prefix(src, "&mut ", new_prefix) + self.replace_prefix(&src, "&mut ", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -603,7 +599,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } hir::Mutability::Not => { if let Some(s) = - self.replace_prefix(src, "&", new_prefix) + self.replace_prefix(&src, "&", &new_prefix) { Some((s, Applicability::Unspecified)) } else { @@ -617,7 +613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match mutbl_a { hir::Mutability::Mut => { if let Some(s) = - self.replace_prefix(src, "&mut ", new_prefix) + self.replace_prefix(&src, "&mut ", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -626,7 +622,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } hir::Mutability::Not => { if let Some(s) = - self.replace_prefix(src, "&", new_prefix) + self.replace_prefix(&src, "&", &new_prefix) { Some((s, Applicability::MachineApplicable)) } else { @@ -774,7 +770,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let suffix_suggestion = with_opt_paren(&format_args!( "{}{}", if matches!( - (&expected_ty.kind, &checked_ty.kind), + (&expected_ty.kind(), &checked_ty.kind()), (ty::Int(_) | ty::Uint(_), ty::Float(_)) ) { // Remove fractional part from literal, for example `42.0f32` into `42` @@ -790,7 +786,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { }; let is_negative_int = |expr: &hir::Expr<'_>| matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnNeg, ..)); - let is_uint = |ty: Ty<'_>| matches!(ty.kind, ty::Uint(..)); + let is_uint = |ty: Ty<'_>| matches!(ty.kind(), ty::Uint(..)); let in_const_context = self.tcx.hir().is_inside_const_context(expr.hir_id); @@ -857,7 +853,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { err.span_suggestion(expr.span, msg, suggestion, Applicability::MachineApplicable); }; - match (&expected_ty.kind, &checked_ty.kind) { + match (&expected_ty.kind(), &checked_ty.kind()) { (&ty::Int(ref exp), &ty::Int(ref found)) => { let (f2e_is_fallible, e2f_is_fallible) = match (exp.bit_width(), found.bit_width()) { diff --git a/compiler/rustc_typeck/src/check/diverges.rs b/compiler/rustc_typeck/src/check/diverges.rs new file mode 100644 index 0000000000..963a93a95c --- /dev/null +++ b/compiler/rustc_typeck/src/check/diverges.rs @@ -0,0 +1,78 @@ +use rustc_span::source_map::DUMMY_SP; +use rustc_span::{self, Span}; +use std::{cmp, ops}; + +/// Tracks whether executing a node may exit normally (versus +/// return/break/panic, which "diverge", leaving dead code in their +/// wake). Tracked semi-automatically (through type variables marked +/// as diverging), with some manual adjustments for control-flow +/// primitives (approximating a CFG). +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +pub enum Diverges { + /// Potentially unknown, some cases converge, + /// others require a CFG to determine them. + Maybe, + + /// Definitely known to diverge and therefore + /// not reach the next sibling or its parent. + Always { + /// The `Span` points to the expression + /// that caused us to diverge + /// (e.g. `return`, `break`, etc). + span: Span, + /// In some cases (e.g. a `match` expression + /// where all arms diverge), we may be + /// able to provide a more informative + /// message to the user. + /// If this is `None`, a default message + /// will be generated, which is suitable + /// for most cases. + custom_note: Option<&'static str>, + }, + + /// Same as `Always` but with a reachability + /// warning already emitted. + WarnedAlways, +} + +// Convenience impls for combining `Diverges`. + +impl ops::BitAnd for Diverges { + type Output = Self; + fn bitand(self, other: Self) -> Self { + cmp::min(self, other) + } +} + +impl ops::BitOr for Diverges { + type Output = Self; + fn bitor(self, other: Self) -> Self { + cmp::max(self, other) + } +} + +impl ops::BitAndAssign for Diverges { + fn bitand_assign(&mut self, other: Self) { + *self = *self & other; + } +} + +impl ops::BitOrAssign for Diverges { + fn bitor_assign(&mut self, other: Self) { + *self = *self | other; + } +} + +impl Diverges { + /// Creates a `Diverges::Always` with the provided `span` and the default note message. + pub(super) fn always(span: Span) -> Diverges { + Diverges::Always { span, custom_note: None } + } + + pub(super) fn is_always(self) -> bool { + // Enum comparison ignores the + // contents of fields, so we just + // fill them in with garbage here. + self >= Diverges::Always { span: DUMMY_SP, custom_note: None } + } +} diff --git a/src/librustc_typeck/check/dropck.rs b/compiler/rustc_typeck/src/check/dropck.rs similarity index 99% rename from src/librustc_typeck/check/dropck.rs rename to compiler/rustc_typeck/src/check/dropck.rs index 434886538f..ae94a6df5f 100644 --- a/src/librustc_typeck/check/dropck.rs +++ b/compiler/rustc_typeck/src/check/dropck.rs @@ -34,7 +34,7 @@ use rustc_trait_selection::traits::{ObligationCause, TraitEngine, TraitEngineExt pub fn check_drop_impl(tcx: TyCtxt<'_>, drop_impl_did: DefId) -> Result<(), ErrorReported> { let dtor_self_type = tcx.type_of(drop_impl_did); let dtor_predicates = tcx.predicates_of(drop_impl_did); - match dtor_self_type.kind { + match dtor_self_type.kind() { ty::Adt(adt_def, self_to_impl_substs) => { ensure_drop_params_and_item_params_correspond( tcx, diff --git a/compiler/rustc_typeck/src/check/expectation.rs b/compiler/rustc_typeck/src/check/expectation.rs new file mode 100644 index 0000000000..fd6fe1406c --- /dev/null +++ b/compiler/rustc_typeck/src/check/expectation.rs @@ -0,0 +1,117 @@ +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::ty::{self, Ty}; +use rustc_span::{self, Span}; + +use super::Expectation::*; +use super::FnCtxt; + +/// When type-checking an expression, we propagate downward +/// whatever type hint we are able in the form of an `Expectation`. +#[derive(Copy, Clone, Debug)] +pub enum Expectation<'tcx> { + /// We know nothing about what type this expression should have. + NoExpectation, + + /// This expression should have the type given (or some subtype). + ExpectHasType(Ty<'tcx>), + + /// This expression will be cast to the `Ty`. + ExpectCastableToType(Ty<'tcx>), + + /// This rvalue expression will be wrapped in `&` or `Box` and coerced + /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. + ExpectRvalueLikeUnsized(Ty<'tcx>), +} + +impl<'a, 'tcx> Expectation<'tcx> { + // Disregard "castable to" expectations because they + // can lead us astray. Consider for example `if cond + // {22} else {c} as u8` -- if we propagate the + // "castable to u8" constraint to 22, it will pick the + // type 22u8, which is overly constrained (c might not + // be a u8). In effect, the problem is that the + // "castable to" expectation is not the tightest thing + // we can say, so we want to drop it in this case. + // The tightest thing we can say is "must unify with + // else branch". Note that in the case of a "has type" + // constraint, this limitation does not hold. + + // If the expected type is just a type variable, then don't use + // an expected type. Otherwise, we might write parts of the type + // when checking the 'then' block which are incompatible with the + // 'else' branch. + pub(super) fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + match *self { + ExpectHasType(ety) => { + let ety = fcx.shallow_resolve(ety); + if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } + } + ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), + _ => NoExpectation, + } + } + + /// Provides an expectation for an rvalue expression given an *optional* + /// hint, which is not required for type safety (the resulting type might + /// be checked higher up, as is the case with `&expr` and `box expr`), but + /// is useful in determining the concrete type. + /// + /// The primary use case is where the expected type is a fat pointer, + /// like `&[isize]`. For example, consider the following statement: + /// + /// let x: &[isize] = &[1, 2, 3]; + /// + /// In this case, the expected type for the `&[1, 2, 3]` expression is + /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the + /// expectation `ExpectHasType([isize])`, that would be too strong -- + /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. + /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced + /// to the type `&[isize]`. Therefore, we propagate this more limited hint, + /// which still is useful, because it informs integer literals and the like. + /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 + /// for examples of where this comes up,. + pub(super) fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { + match fcx.tcx.struct_tail_without_normalization(ty).kind() { + ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty), + _ => ExpectHasType(ty), + } + } + + // Resolves `expected` by a single level if it is a variable. If + // there is no expected type or resolution is not possible (e.g., + // no constraints yet present), just returns `None`. + fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { + match self { + NoExpectation => NoExpectation, + ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), + ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), + ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), + } + } + + pub(super) fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + NoExpectation => None, + ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), + } + } + + /// It sometimes happens that we want to turn an expectation into + /// a **hard constraint** (i.e., something that must be satisfied + /// for the program to type-check). `only_has_type` will return + /// such a constraint, if it exists. + pub(super) fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { + match self.resolve(fcx) { + ExpectHasType(ty) => Some(ty), + NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, + } + } + + /// Like `only_has_type`, but instead of returning `None` if no + /// hard constraint exists, creates a fresh type variable. + pub(super) fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { + self.only_has_type(fcx).unwrap_or_else(|| { + fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }) + }) + } +} diff --git a/src/librustc_typeck/check/expr.rs b/compiler/rustc_typeck/src/check/expr.rs similarity index 88% rename from src/librustc_typeck/check/expr.rs rename to compiler/rustc_typeck/src/check/expr.rs index 0e9f64c359..275f2ed7c8 100644 --- a/src/librustc_typeck/check/expr.rs +++ b/compiler/rustc_typeck/src/check/expr.rs @@ -14,8 +14,13 @@ use crate::check::Expectation::{self, ExpectCastableToType, ExpectHasType, NoExp use crate::check::FnCtxt; use crate::check::Needs; use crate::check::TupleArgumentsFlag::DontTupleArguments; +use crate::errors::{ + FieldMultiplySpecifiedInInitializer, FunctionalRecordUpdateOnNonStruct, + YieldExprOutsideOfGenerator, +}; use crate::type_error_struct; +use crate::errors::{AddressOfTemporaryTaken, ReturnStmtOutsideOfFnBody, StructExprNonExhaustive}; use rustc_ast as ast; use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; @@ -37,7 +42,7 @@ use rustc_middle::ty::{AdtKind, Visibility}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::Span; use rustc_span::symbol::{kw, sym, Ident, Symbol}; -use rustc_trait_selection::traits::{self, ObligationCauseCode}; +use rustc_trait_selection::traits::{self, ObligationCauseCode, SelectionContext}; use std::fmt::Display; @@ -296,7 +301,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } fn check_expr_box(&self, expr: &'tcx hir::Expr<'tcx>, expected: Expectation<'tcx>) -> Ty<'tcx> { - let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind { + let expected_inner = expected.to_option(self).map_or(NoExpectation, |ty| match ty.kind() { ty::Adt(def, _) if def.is_box() => Expectation::rvalue_hint(self, ty.boxed_ty()), _ => NoExpectation, }); @@ -346,7 +351,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { hir::UnOp::UnNot => { let result = self.check_user_unop(expr, oprnd_t, unop); // If it's builtin, we can reuse the type, this helps inference. - if !(oprnd_t.is_integral() || oprnd_t.kind == ty::Bool) { + if !(oprnd_t.is_integral() || *oprnd_t.kind() == ty::Bool) { oprnd_t = result; } } @@ -371,7 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { let hint = expected.only_has_type(self).map_or(NoExpectation, |ty| { - match ty.kind { + match ty.kind() { ty::Ref(_, ty, _) | ty::RawPtr(ty::TypeAndMut { ty, .. }) => { if oprnd.is_syntactic_place_expr() { // Places may legitimately have unsized types. @@ -434,19 +439,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // This is maybe too permissive, since it allows // `let u = &raw const Box::new((1,)).0`, which creates an // immediately dangling raw pointer. - self.typeck_results.borrow().adjustments().get(base.hir_id).map_or(false, |x| { - x.iter().any(|adj| if let Adjust::Deref(_) = adj.kind { true } else { false }) - }) + self.typeck_results + .borrow() + .adjustments() + .get(base.hir_id) + .map_or(false, |x| x.iter().any(|adj| matches!(adj.kind, Adjust::Deref(_)))) }); if !is_named { - struct_span_err!( - self.tcx.sess, - oprnd.span, - E0745, - "cannot take address of a temporary" - ) - .span_label(oprnd.span, "temporary value") - .emit(); + self.tcx.sess.emit_err(AddressOfTemporaryTaken { span: oprnd.span }) } } @@ -473,7 +473,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => self.instantiate_value_path(segs, opt_ty, res, expr.span, expr.hir_id).0, }; - if let ty::FnDef(..) = ty.kind { + if let ty::FnDef(..) = ty.kind() { let fn_sig = ty.fn_sig(tcx); if !tcx.features().unsized_locals { // We want to remove some Sized bounds from std functions, @@ -665,13 +665,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, ) -> Ty<'tcx> { if self.ret_coercion.is_none() { - struct_span_err!( - self.tcx.sess, - expr.span, - E0572, - "return statement outside of function body", - ) - .emit(); + self.tcx.sess.emit_err(ReturnStmtOutsideOfFnBody { span: expr.span }); } else if let Some(ref e) = expr_opt { if self.ret_coercion_span.borrow().is_none() { *self.ret_coercion_span.borrow_mut() = Some(e.span); @@ -740,6 +734,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr_span: &Span, ) { if !lhs.is_syntactic_place_expr() { + // FIXME: Make this use SessionDiagnostic once error codes can be dynamically set. let mut err = self.tcx.sess.struct_span_err_with_code( *expr_span, "invalid left-hand side of assignment", @@ -764,9 +759,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { rhs: &'tcx hir::Expr<'tcx>, span: &Span, ) -> Ty<'tcx> { - let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); - let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs)); - let expected_ty = expected.coercion_target_type(self, expr.span); if expected_ty == self.tcx.types.bool { // The expected type is `bool` but this will result in `()` so we can reasonably @@ -774,20 +766,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // The likely cause of this is `if foo = bar { .. }`. let actual_ty = self.tcx.mk_unit(); let mut err = self.demand_suptype_diag(expr.span, expected_ty, actual_ty).unwrap(); - let msg = "try comparing for equality"; - let left = self.tcx.sess.source_map().span_to_snippet(lhs.span); - let right = self.tcx.sess.source_map().span_to_snippet(rhs.span); - if let (Ok(left), Ok(right)) = (left, right) { - let help = format!("{} == {}", left, right); - err.span_suggestion(expr.span, msg, help, Applicability::MaybeIncorrect); + let lhs_ty = self.check_expr(&lhs); + let rhs_ty = self.check_expr(&rhs); + let (applicability, eq) = if self.can_coerce(rhs_ty, lhs_ty) { + (Applicability::MachineApplicable, true) } else { - err.help(msg); + (Applicability::MaybeIncorrect, false) + }; + if !lhs.is_syntactic_place_expr() { + // Do not suggest `if let x = y` as `==` is way more likely to be the intention. + if let hir::Node::Expr(hir::Expr { + kind: + ExprKind::Match( + _, + _, + hir::MatchSource::IfDesugar { .. } | hir::MatchSource::WhileDesugar, + ), + .. + }) = self.tcx.hir().get( + self.tcx.hir().get_parent_node(self.tcx.hir().get_parent_node(expr.hir_id)), + ) { + // Likely `if let` intended. + err.span_suggestion_verbose( + expr.span.shrink_to_lo(), + "you might have meant to use pattern matching", + "let ".to_string(), + applicability, + ); + } } - err.emit(); - } else { - self.check_lhs_assignable(lhs, "E0070", span); + if eq { + err.span_suggestion_verbose( + *span, + "you might have meant to compare for equality", + "==".to_string(), + applicability, + ); + } + + if self.sess().if_let_suggestions.borrow().get(&expr.span).is_some() { + // We already emitted an `if let` suggestion due to an identifier not found. + err.delay_as_bug(); + } else { + err.emit(); + } + return self.tcx.ty_error(); } + self.check_lhs_assignable(lhs, "E0070", span); + + let lhs_ty = self.check_expr_with_needs(&lhs, Needs::MutPlace); + let rhs_ty = self.check_expr_coercable_to_type(&rhs, lhs_ty, Some(lhs)); + self.require_type_is_sized(lhs_ty, lhs.span, traits::AssignmentLhsSized); if lhs_ty.references_error() || rhs_ty.references_error() { @@ -922,7 +952,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { error, Some(args), ) { - if let ty::Adt(..) = rcvr_t.kind { + if let ty::Adt(..) = rcvr_t.kind() { // Try alternative arbitrary self types that could fulfill this call. // FIXME: probe for all types that *could* be arbitrary self-types, not // just this list. @@ -973,7 +1003,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let element_ty = if !args.is_empty() { let coerce_to = expected .to_option(self) - .and_then(|uty| match uty.kind { + .and_then(|uty| match *uty.kind() { ty::Array(ty, _) | ty::Slice(ty) => Some(ty), _ => None, }) @@ -1011,7 +1041,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let count = self.to_const(count); let uty = match expected { - ExpectHasType(uty) => match uty.kind { + ExpectHasType(uty) => match *uty.kind() { ty::Array(ty, _) | ty::Slice(ty) => Some(ty), _ => None, }, @@ -1048,7 +1078,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> Ty<'tcx> { let flds = expected.only_has_type(self).and_then(|ty| { let ty = self.resolve_vars_with_obligations(ty); - match ty.kind { + match ty.kind() { ty::Tuple(ref flds) => Some(&flds[..]), _ => None, } @@ -1091,14 +1121,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Prohibit struct expressions when non-exhaustive flag is set. let adt = adt_ty.ty_adt_def().expect("`check_struct_path` returned non-ADT type"); if !adt.did.is_local() && variant.is_field_list_non_exhaustive() { - struct_span_err!( - self.tcx.sess, - expr.span, - E0639, - "cannot create non-exhaustive {} using struct expression", - adt.variant_descr() - ) - .emit(); + self.tcx + .sess + .emit_err(StructExprNonExhaustive { span: expr.span, what: adt.variant_descr() }); } let error_happened = self.check_expr_struct_fields( @@ -1116,7 +1141,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // when certain fields are assumed to exist that in fact do not. if !error_happened { self.check_expr_has_type_or_error(base_expr, adt_ty, |_| {}); - match adt_ty.kind { + match adt_ty.kind() { ty::Adt(adt, substs) if adt.is_struct() => { let fru_field_types = adt .non_enum_variant() @@ -1136,13 +1161,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .insert(expr.hir_id, fru_field_types); } _ => { - struct_span_err!( - self.tcx.sess, - base_expr.span, - E0436, - "functional record update syntax requires a struct" - ) - .emit(); + self.tcx + .sess + .emit_err(FunctionalRecordUpdateOnNonStruct { span: base_expr.span }); } } } @@ -1171,7 +1192,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // re-link the regions that EIfEO can erase. self.demand_eqtype(span, adt_ty_hint, adt_ty); - let (substs, adt_kind, kind_name) = match &adt_ty.kind { + let (substs, adt_kind, kind_name) = match &adt_ty.kind() { &ty::Adt(adt, substs) => (substs, adt.adt_kind(), adt.variant_descr()), _ => span_bug!(span, "non-ADT passed to check_expr_struct_fields"), }; @@ -1205,18 +1226,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { error_happened = true; if let Some(prev_span) = seen_fields.get(&ident) { - let mut err = struct_span_err!( - self.tcx.sess, - field.ident.span, - E0062, - "field `{}` specified more than once", - ident - ); - - err.span_label(field.ident.span, "used more than once"); - err.span_label(*prev_span, format!("first use of `{}`", ident)); - - err.emit(); + tcx.sess.emit_err(FieldMultiplySpecifiedInInitializer { + span: field.ident.span, + prev_span: *prev_span, + ident, + }); } else { self.report_unknown_field(adt_ty, variant, field, ast_fields, kind_name, span); } @@ -1235,42 +1249,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.span_err(span, "union expressions should have exactly one field"); } } else if check_completeness && !error_happened && !remaining_fields.is_empty() { - let len = remaining_fields.len(); - - let mut displayable_field_names = - remaining_fields.keys().map(|ident| ident.as_str()).collect::>(); - - displayable_field_names.sort(); - - let truncated_fields_error = if len <= 3 { - String::new() - } else { - format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" }) - }; - - let remaining_fields_names = displayable_field_names + let no_accessible_remaining_fields = remaining_fields .iter() - .take(3) - .map(|n| format!("`{}`", n)) - .collect::>() - .join(", "); + .find(|(_, (_, field))| { + field.vis.is_accessible_from(tcx.parent_module(expr_id).to_def_id(), tcx) + }) + .is_none(); - struct_span_err!( - tcx.sess, - span, - E0063, - "missing field{} {}{} in initializer of `{}`", - pluralize!(remaining_fields.len()), - remaining_fields_names, - truncated_fields_error, - adt_ty - ) - .span_label( - span, - format!("missing {}{}", remaining_fields_names, truncated_fields_error), - ) - .emit(); + if no_accessible_remaining_fields { + self.report_no_accessible_fields(adt_ty, span); + } else { + self.report_missing_field(adt_ty, span, remaining_fields); + } } + error_happened } @@ -1287,6 +1279,79 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } + /// Report an error for a struct field expression when there are fields which aren't provided. + /// + /// ```ignore (diagnostic) + /// error: missing field `you_can_use_this_field` in initializer of `foo::Foo` + /// --> src/main.rs:8:5 + /// | + /// 8 | foo::Foo {}; + /// | ^^^^^^^^ missing `you_can_use_this_field` + /// + /// error: aborting due to previous error + /// ``` + fn report_missing_field( + &self, + adt_ty: Ty<'tcx>, + span: Span, + remaining_fields: FxHashMap, + ) { + let tcx = self.tcx; + let len = remaining_fields.len(); + + let mut displayable_field_names = + remaining_fields.keys().map(|ident| ident.as_str()).collect::>(); + + displayable_field_names.sort(); + + let truncated_fields_error = if len <= 3 { + String::new() + } else { + format!(" and {} other field{}", (len - 3), if len - 3 == 1 { "" } else { "s" }) + }; + + let remaining_fields_names = displayable_field_names + .iter() + .take(3) + .map(|n| format!("`{}`", n)) + .collect::>() + .join(", "); + + struct_span_err!( + tcx.sess, + span, + E0063, + "missing field{} {}{} in initializer of `{}`", + pluralize!(remaining_fields.len()), + remaining_fields_names, + truncated_fields_error, + adt_ty + ) + .span_label(span, format!("missing {}{}", remaining_fields_names, truncated_fields_error)) + .emit(); + } + + /// Report an error for a struct field expression when there are no visible fields. + /// + /// ```ignore (diagnostic) + /// error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + /// --> src/main.rs:8:5 + /// | + /// 8 | foo::Foo {}; + /// | ^^^^^^^^ + /// + /// error: aborting due to previous error + /// ``` + fn report_no_accessible_fields(&self, adt_ty: Ty<'tcx>, span: Span) { + self.tcx.sess.span_err( + span, + &format!( + "cannot construct `{}` with struct literal syntax due to inaccessible fields", + adt_ty, + ), + ); + } + fn report_unknown_field( &self, ty: Ty<'tcx>, @@ -1296,13 +1361,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { kind_name: &str, ty_span: Span, ) { - if variant.recovered { + if variant.is_recovered() { self.set_tainted_by_errors(); return; } let mut err = self.type_error_struct_with_diag( field.ident.span, - |actual| match ty.kind { + |actual| match ty.kind() { ty::Adt(adt, ..) if adt.is_enum() => struct_span_err!( self.tcx.sess, field.ident.span, @@ -1352,7 +1417,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Applicability::MaybeIncorrect, ); } else { - match ty.kind { + match ty.kind() { ty::Adt(adt, ..) => { if adt.is_enum() { err.span_label( @@ -1439,7 +1504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut private_candidate = None; let mut autoderef = self.autoderef(expr.span, expr_t); while let Some((base_t, _)) = autoderef.next() { - match base_t.kind { + match base_t.kind() { ty::Adt(base_def, substs) if !base_def.is_enum() => { debug!("struct named {:?}", base_t); let (ident, def_scope) = @@ -1509,6 +1574,58 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx().ty_error() } + fn suggest_await_on_field_access( + &self, + err: &mut DiagnosticBuilder<'_>, + field_ident: Ident, + base: &'tcx hir::Expr<'tcx>, + expr: &'tcx hir::Expr<'tcx>, + def_id: DefId, + ) { + let param_env = self.tcx().param_env(def_id); + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + // Future::Output + let item_def_id = + self.tcx.associated_items(future_trait).in_definition_order().next().unwrap().def_id; + + let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); + debug!("suggest_await_on_field_access: projection_ty={:?}", projection_ty); + + let cause = self.misc(expr.span); + let mut selcx = SelectionContext::new(&self.infcx); + + let mut obligations = vec![]; + if let Some(projection_ty) = projection_ty { + let normalized_ty = rustc_trait_selection::traits::normalize_projection_type( + &mut selcx, + param_env, + projection_ty, + cause, + 0, + &mut obligations, + ); + debug!( + "suggest_await_on_field_access: normalized_ty={:?}, ty_kind={:?}", + self.resolve_vars_if_possible(&normalized_ty), + normalized_ty.kind(), + ); + if let ty::Adt(def, _) = normalized_ty.kind() { + // no field access on enum type + if !def.is_enum() { + if def.non_enum_variant().fields.iter().any(|field| field.ident == field_ident) + { + err.span_suggestion_verbose( + base.span.shrink_to_hi(), + "consider awaiting before field access", + ".await".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + } + fn ban_nonexisting_field( &self, field: Ident, @@ -1516,9 +1633,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr: &'tcx hir::Expr<'tcx>, expr_t: Ty<'tcx>, ) { + debug!( + "ban_nonexisting_field: field={:?}, base={:?}, expr={:?}, expr_ty={:?}", + field, base, expr, expr_t + ); let mut err = self.no_such_field_err(field.span, field, expr_t); - match expr_t.peel_refs().kind { + match *expr_t.peel_refs().kind() { ty::Array(_, len) => { self.maybe_suggest_array_indexing(&mut err, expr, base, field, len); } @@ -1531,6 +1652,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty::Param(param_ty) => { self.point_at_param_definition(&mut err, param_ty); } + ty::Opaque(def_id, _) => { + self.suggest_await_on_field_access(&mut err, field, base, expr, def_id); + } _ => {} } @@ -1735,7 +1859,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { base_t ); // Try to give some advice about indexing tuples. - if let ty::Tuple(..) = base_t.kind { + if let ty::Tuple(..) = base_t.kind() { let mut needs_note = true; // If the index is an integer, we can show the actual // fixed expression: @@ -1788,13 +1912,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.mk_unit() } _ => { - struct_span_err!( - self.tcx.sess, - expr.span, - E0627, - "yield expression outside of generator literal" - ) - .emit(); + self.tcx.sess.emit_err(YieldExprOutsideOfGenerator { span: expr.span }); self.tcx.mk_unit() } } @@ -1820,7 +1938,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // function. if is_input { let ty = self.structurally_resolved_type(expr.span, &ty); - match ty.kind { + match *ty.kind() { ty::FnDef(..) => { let fnptr_ty = self.tcx.mk_fn_ptr(ty.fn_sig(self.tcx)); self.demand_coerce(expr, ty, fnptr_ty, None, AllowTwoPhase::No); @@ -1868,7 +1986,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } pub(super) fn ty_kind_suggestion(ty: Ty<'_>) -> Option<&'static str> { - Some(match ty.kind { + Some(match ty.kind() { ty::Bool => "true", ty::Char => "'a'", ty::Int(_) | ty::Uint(_) => "42", diff --git a/src/librustc_typeck/check/mod.rs b/compiler/rustc_typeck/src/check/fn_ctxt.rs similarity index 52% rename from src/librustc_typeck/check/mod.rs rename to compiler/rustc_typeck/src/check/fn_ctxt.rs index 031d48f8a6..79d6c7dbfd 100644 --- a/src/librustc_typeck/check/mod.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt.rs @@ -1,546 +1,71 @@ // ignore-tidy-filelength +// FIXME: This file seems to have too much functionality wrapped into it, +// leading to it being too long. +// Splitting this file may involve abstracting functionality into other files. -/*! - -# typeck: check phase - -Within the check phase of type check, we check each item one at a time -(bodies of function expressions are checked as part of the containing -function). Inference is used to supply types wherever they are unknown. - -By far the most complex case is checking the body of a function. This -can be broken down into several distinct phases: - -- gather: creates type variables to represent the type of each local - variable and pattern binding. - -- main: the main pass does the lion's share of the work: it - determines the types of all expressions, resolves - methods, checks for most invalid conditions, and so forth. In - some cases, where a type is unknown, it may create a type or region - variable and use that as the type of an expression. - - In the process of checking, various constraints will be placed on - these type variables through the subtyping relationships requested - through the `demand` module. The `infer` module is in charge - of resolving those constraints. - -- regionck: after main is complete, the regionck pass goes over all - types looking for regions and making sure that they did not escape - into places they are not in scope. This may also influence the - final assignments of the various region variables if there is some - flexibility. - -- writeback: writes the final types within a function body, replacing - type variables with their final inferred types. These final types - are written into the `tcx.node_types` table, which should *never* contain - any reference to a type variable. - -## Intermediate types - -While type checking a function, the intermediate types for the -expressions, blocks, and so forth contained within the function are -stored in `fcx.node_types` and `fcx.node_substs`. These types -may contain unresolved type variables. After type checking is -complete, the functions in the writeback module are used to take the -types from this table, resolve them, and then write them into their -permanent home in the type context `tcx`. - -This means that during inferencing you should use `fcx.write_ty()` -and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of -nodes within the function. - -The types of top-level items, which never contain unbound type -variables, are stored directly into the `tcx` typeck_results. - -N.B., a type variable is not the same thing as a type parameter. A -type variable is rather an "instance" of a type parameter: that is, -given a generic function `fn foo(t: T)`: while checking the -function `foo`, the type `ty_param(0)` refers to the type `T`, which -is treated in abstract. When `foo()` is called, however, `T` will be -substituted for a fresh type variable `N`. This variable will -eventually be resolved to some concrete type (which might itself be -type parameter). - -*/ - -pub mod _match; -mod autoderef; -mod callee; -pub mod cast; -mod closure; -pub mod coercion; -mod compare_method; -pub mod demand; -pub mod dropck; -mod expr; -mod generator_interior; -pub mod intrinsic; -pub mod method; -mod op; -mod pat; -mod place_op; -mod regionck; -mod upvar; -mod wfcheck; -pub mod writeback; - +use super::callee::{self, DeferredCallResolution}; +use super::coercion::{CoerceMany, DynamicCoerceMany}; +use super::method::{self, MethodCallee, SelfSource}; +use super::Expectation::*; +use super::TupleArgumentsFlag::*; +use super::{ + potentially_plural_count, struct_span_err, BreakableCtxt, Diverges, EnclosingBreakables, + Expectation, FallbackMode, Inherited, LocalTy, Needs, TupleArgumentsFlag, UnsafetyState, +}; use crate::astconv::{ AstConv, ExplicitLateBound, GenericArgCountMismatch, GenericArgCountResult, PathSeg, }; + use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; -use rustc_attr as attr; use rustc_data_structures::captures::Captures; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_data_structures::fx::FxHashSet; use rustc_errors::ErrorReported; -use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder, DiagnosticId}; +use rustc_errors::{Applicability, DiagnosticBuilder, DiagnosticId}; use rustc_hir as hir; use rustc_hir::def::{CtorOf, DefKind, Res}; -use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LOCAL_CRATE}; -use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; -use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::def_id::DefId; use rustc_hir::lang_items::LangItem; -use rustc_hir::{ExprKind, GenericArg, HirIdMap, ItemKind, Node, PatKind, QPath}; -use rustc_index::bit_set::BitSet; -use rustc_index::vec::Idx; -use rustc_infer::infer; +use rustc_hir::{ExprKind, GenericArg, ItemKind, Node, QPath}; use rustc_infer::infer::canonical::{Canonical, OriginalQueryValues, QueryResponse}; use rustc_infer::infer::error_reporting::TypeAnnotationNeeded::E0282; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_infer::infer::unify_key::{ConstVariableOrigin, ConstVariableOriginKind}; -use rustc_infer::infer::{InferCtxt, InferOk, InferResult, RegionVariableOrigin, TyCtxtInferExt}; +use rustc_infer::infer::{self, InferOk, InferResult}; use rustc_middle::hir::map::blocks::FnLikeNode; -use rustc_middle::mir::interpret::ConstValue; use rustc_middle::ty::adjustment::{ Adjust, Adjustment, AllowTwoPhase, AutoBorrow, AutoBorrowMutability, }; -use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::{self, InternalSubsts, Subst, SubstsRef}; -use rustc_middle::ty::subst::{GenericArgKind, UserSelfTy, UserSubsts}; -use rustc_middle::ty::util::{Discr, IntTypeExt, Representability}; -use rustc_middle::ty::WithConstness; -use rustc_middle::ty::{self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind}; -use rustc_middle::ty::{RegionKind, ToPolyTraitRef, ToPredicate, Ty, TyCtxt, UserType}; -use rustc_session::config::{self, EntryFnType}; -use rustc_session::lint; -use rustc_session::parse::feature_err; -use rustc_session::Session; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::subst::{ + self, GenericArgKind, InternalSubsts, Subst, SubstsRef, UserSelfTy, UserSubsts, +}; +use rustc_middle::ty::{ + self, AdtKind, CanonicalUserType, Const, DefIdTree, GenericParamDefKind, ToPolyTraitRef, + ToPredicate, Ty, TyCtxt, UserType, +}; +use rustc_session::{lint, Session}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{original_sp, DUMMY_SP}; use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{self, BytePos, MultiSpan, Span}; -use rustc_target::abi::VariantIdx; -use rustc_target::spec::abi::Abi; use rustc_trait_selection::infer::InferCtxtExt as _; -use rustc_trait_selection::opaque_types::{InferCtxtExt as _, OpaqueTypeDecl}; -use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; -use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; +use rustc_trait_selection::opaque_types::InferCtxtExt as _; use rustc_trait_selection::traits::error_reporting::InferCtxtExt as _; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt as _; use rustc_trait_selection::traits::{ self, ObligationCause, ObligationCauseCode, TraitEngine, TraitEngineExt, }; -use std::cell::{Cell, Ref, RefCell, RefMut}; -use std::cmp; +use std::cell::{Cell, RefCell}; use std::collections::hash_map::Entry; use std::iter; use std::mem::replace; -use std::ops::{self, Deref}; +use std::ops::Deref; use std::slice; -use crate::require_c_abi_if_c_variadic; -use crate::util::common::indenter; - -use self::callee::DeferredCallResolution; -use self::coercion::{CoerceMany, DynamicCoerceMany}; -use self::compare_method::{compare_const_impl, compare_impl_method, compare_ty_impl}; -use self::method::{MethodCallee, SelfSource}; -pub use self::Expectation::*; -use self::TupleArgumentsFlag::*; - -#[macro_export] -macro_rules! type_error_struct { - ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ - if $typ.references_error() { - $session.diagnostic().struct_dummy() - } else { - rustc_errors::struct_span_err!($session, $span, $code, $($message)*) - } - }) -} - -/// The type of a local binding, including the revealed type for anon types. -#[derive(Copy, Clone, Debug)] -pub struct LocalTy<'tcx> { - decl_ty: Ty<'tcx>, - revealed_ty: Ty<'tcx>, -} - -/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. -#[derive(Copy, Clone)] -struct MaybeInProgressTables<'a, 'tcx> { - maybe_typeck_results: Option<&'a RefCell>>, -} - -impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { - fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" - ), - } - } - - fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { - match self.maybe_typeck_results { - Some(typeck_results) => typeck_results.borrow_mut(), - None => bug!( - "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" - ), - } - } -} - -/// Closures defined within the function. For example: -/// -/// fn foo() { -/// bar(move|| { ... }) -/// } -/// -/// Here, the function `foo()` and the closure passed to -/// `bar()` will each have their own `FnCtxt`, but they will -/// share the inherited fields. -pub struct Inherited<'a, 'tcx> { - infcx: InferCtxt<'a, 'tcx>, - - typeck_results: MaybeInProgressTables<'a, 'tcx>, - - locals: RefCell>>, - - fulfillment_cx: RefCell>>, - - // Some additional `Sized` obligations badly affect type inference. - // These obligations are added in a later stage of typeck. - deferred_sized_obligations: RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, - - // When we process a call like `c()` where `c` is a closure type, - // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or - // `FnOnce` closure. In that case, we defer full resolution of the - // call until upvar inference can kick in and make the - // decision. We keep these deferred resolutions grouped by the - // def-id of the closure, so that once we decide, we can easily go - // back and process them. - deferred_call_resolutions: RefCell>>>, - - deferred_cast_checks: RefCell>>, - - deferred_generator_interiors: RefCell, hir::GeneratorKind)>>, - - // Opaque types found in explicit return types and their - // associated fresh inference variable. Writeback resolves these - // variables to get the concrete type, which can be used to - // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. - opaque_types: RefCell>>, - - /// A map from inference variables created from opaque - /// type instantiations (`ty::Infer`) to the actual opaque - /// type (`ty::Opaque`). Used during fallback to map unconstrained - /// opaque type inference variables to their corresponding - /// opaque type. - opaque_types_vars: RefCell, Ty<'tcx>>>, - - body_id: Option, -} - -impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { - type Target = InferCtxt<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.infcx - } -} - -/// When type-checking an expression, we propagate downward -/// whatever type hint we are able in the form of an `Expectation`. -#[derive(Copy, Clone, Debug)] -pub enum Expectation<'tcx> { - /// We know nothing about what type this expression should have. - NoExpectation, - - /// This expression should have the type given (or some subtype). - ExpectHasType(Ty<'tcx>), - - /// This expression will be cast to the `Ty`. - ExpectCastableToType(Ty<'tcx>), - - /// This rvalue expression will be wrapped in `&` or `Box` and coerced - /// to `&Ty` or `Box`, respectively. `Ty` is `[A]` or `Trait`. - ExpectRvalueLikeUnsized(Ty<'tcx>), -} - -impl<'a, 'tcx> Expectation<'tcx> { - // Disregard "castable to" expectations because they - // can lead us astray. Consider for example `if cond - // {22} else {c} as u8` -- if we propagate the - // "castable to u8" constraint to 22, it will pick the - // type 22u8, which is overly constrained (c might not - // be a u8). In effect, the problem is that the - // "castable to" expectation is not the tightest thing - // we can say, so we want to drop it in this case. - // The tightest thing we can say is "must unify with - // else branch". Note that in the case of a "has type" - // constraint, this limitation does not hold. - - // If the expected type is just a type variable, then don't use - // an expected type. Otherwise, we might write parts of the type - // when checking the 'then' block which are incompatible with the - // 'else' branch. - fn adjust_for_branches(&self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { - match *self { - ExpectHasType(ety) => { - let ety = fcx.shallow_resolve(ety); - if !ety.is_ty_var() { ExpectHasType(ety) } else { NoExpectation } - } - ExpectRvalueLikeUnsized(ety) => ExpectRvalueLikeUnsized(ety), - _ => NoExpectation, - } - } - - /// Provides an expectation for an rvalue expression given an *optional* - /// hint, which is not required for type safety (the resulting type might - /// be checked higher up, as is the case with `&expr` and `box expr`), but - /// is useful in determining the concrete type. - /// - /// The primary use case is where the expected type is a fat pointer, - /// like `&[isize]`. For example, consider the following statement: - /// - /// let x: &[isize] = &[1, 2, 3]; - /// - /// In this case, the expected type for the `&[1, 2, 3]` expression is - /// `&[isize]`. If however we were to say that `[1, 2, 3]` has the - /// expectation `ExpectHasType([isize])`, that would be too strong -- - /// `[1, 2, 3]` does not have the type `[isize]` but rather `[isize; 3]`. - /// It is only the `&[1, 2, 3]` expression as a whole that can be coerced - /// to the type `&[isize]`. Therefore, we propagate this more limited hint, - /// which still is useful, because it informs integer literals and the like. - /// See the test case `test/ui/coerce-expect-unsized.rs` and #20169 - /// for examples of where this comes up,. - fn rvalue_hint(fcx: &FnCtxt<'a, 'tcx>, ty: Ty<'tcx>) -> Expectation<'tcx> { - match fcx.tcx.struct_tail_without_normalization(ty).kind { - ty::Slice(_) | ty::Str | ty::Dynamic(..) => ExpectRvalueLikeUnsized(ty), - _ => ExpectHasType(ty), - } - } - - // Resolves `expected` by a single level if it is a variable. If - // there is no expected type or resolution is not possible (e.g., - // no constraints yet present), just returns `None`. - fn resolve(self, fcx: &FnCtxt<'a, 'tcx>) -> Expectation<'tcx> { - match self { - NoExpectation => NoExpectation, - ExpectCastableToType(t) => ExpectCastableToType(fcx.resolve_vars_if_possible(&t)), - ExpectHasType(t) => ExpectHasType(fcx.resolve_vars_if_possible(&t)), - ExpectRvalueLikeUnsized(t) => ExpectRvalueLikeUnsized(fcx.resolve_vars_if_possible(&t)), - } - } - - fn to_option(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - NoExpectation => None, - ExpectCastableToType(ty) | ExpectHasType(ty) | ExpectRvalueLikeUnsized(ty) => Some(ty), - } - } - - /// It sometimes happens that we want to turn an expectation into - /// a **hard constraint** (i.e., something that must be satisfied - /// for the program to type-check). `only_has_type` will return - /// such a constraint, if it exists. - fn only_has_type(self, fcx: &FnCtxt<'a, 'tcx>) -> Option> { - match self.resolve(fcx) { - ExpectHasType(ty) => Some(ty), - NoExpectation | ExpectCastableToType(_) | ExpectRvalueLikeUnsized(_) => None, - } - } - - /// Like `only_has_type`, but instead of returning `None` if no - /// hard constraint exists, creates a fresh type variable. - fn coercion_target_type(self, fcx: &FnCtxt<'a, 'tcx>, span: Span) -> Ty<'tcx> { - self.only_has_type(fcx).unwrap_or_else(|| { - fcx.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }) - }) - } -} - -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -pub enum Needs { - MutPlace, - None, -} - -impl Needs { - fn maybe_mut_place(m: hir::Mutability) -> Self { - match m { - hir::Mutability::Mut => Needs::MutPlace, - hir::Mutability::Not => Needs::None, - } - } -} - -#[derive(Copy, Clone)] -pub struct UnsafetyState { - pub def: hir::HirId, - pub unsafety: hir::Unsafety, - pub unsafe_push_count: u32, - from_fn: bool, -} - -impl UnsafetyState { - pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState { - UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true } - } - - pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState { - use hir::BlockCheckMode; - match self.unsafety { - // If this unsafe, then if the outer function was already marked as - // unsafe we shouldn't attribute the unsafe'ness to the block. This - // way the block can be warned about instead of ignoring this - // extraneous block (functions are never warned about). - hir::Unsafety::Unsafe if self.from_fn => *self, - - unsafety => { - let (unsafety, def, count) = match blk.rules { - BlockCheckMode::PushUnsafeBlock(..) => { - (unsafety, blk.hir_id, self.unsafe_push_count.checked_add(1).unwrap()) - } - BlockCheckMode::PopUnsafeBlock(..) => { - (unsafety, blk.hir_id, self.unsafe_push_count.checked_sub(1).unwrap()) - } - BlockCheckMode::UnsafeBlock(..) => { - (hir::Unsafety::Unsafe, blk.hir_id, self.unsafe_push_count) - } - BlockCheckMode::DefaultBlock => (unsafety, self.def, self.unsafe_push_count), - }; - UnsafetyState { def, unsafety, unsafe_push_count: count, from_fn: false } - } - } - } -} - -#[derive(Debug, Copy, Clone)] -pub enum PlaceOp { - Deref, - Index, -} - -/// Tracks whether executing a node may exit normally (versus -/// return/break/panic, which "diverge", leaving dead code in their -/// wake). Tracked semi-automatically (through type variables marked -/// as diverging), with some manual adjustments for control-flow -/// primitives (approximating a CFG). -#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] -pub enum Diverges { - /// Potentially unknown, some cases converge, - /// others require a CFG to determine them. - Maybe, - - /// Definitely known to diverge and therefore - /// not reach the next sibling or its parent. - Always { - /// The `Span` points to the expression - /// that caused us to diverge - /// (e.g. `return`, `break`, etc). - span: Span, - /// In some cases (e.g. a `match` expression - /// where all arms diverge), we may be - /// able to provide a more informative - /// message to the user. - /// If this is `None`, a default message - /// will be generated, which is suitable - /// for most cases. - custom_note: Option<&'static str>, - }, - - /// Same as `Always` but with a reachability - /// warning already emitted. - WarnedAlways, -} - -// Convenience impls for combining `Diverges`. - -impl ops::BitAnd for Diverges { - type Output = Self; - fn bitand(self, other: Self) -> Self { - cmp::min(self, other) - } -} - -impl ops::BitOr for Diverges { - type Output = Self; - fn bitor(self, other: Self) -> Self { - cmp::max(self, other) - } -} - -impl ops::BitAndAssign for Diverges { - fn bitand_assign(&mut self, other: Self) { - *self = *self & other; - } -} - -impl ops::BitOrAssign for Diverges { - fn bitor_assign(&mut self, other: Self) { - *self = *self | other; - } -} - -impl Diverges { - /// Creates a `Diverges::Always` with the provided `span` and the default note message. - fn always(span: Span) -> Diverges { - Diverges::Always { span, custom_note: None } - } - - fn is_always(self) -> bool { - // Enum comparison ignores the - // contents of fields, so we just - // fill them in with garbage here. - self >= Diverges::Always { span: DUMMY_SP, custom_note: None } - } -} - -pub struct BreakableCtxt<'tcx> { - may_break: bool, - - // this is `null` for loops where break with a value is illegal, - // such as `while`, `for`, and `while let` - coerce: Option>, -} - -pub struct EnclosingBreakables<'tcx> { - stack: Vec>, - by_id: HirIdMap, -} - -impl<'tcx> EnclosingBreakables<'tcx> { - fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { - self.opt_find_breakable(target_id).unwrap_or_else(|| { - bug!("could not find enclosing breakable with id {}", target_id); - }) - } - - fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { - match self.by_id.get(&target_id) { - Some(ix) => Some(&mut self.stack[*ix]), - None => None, - } - } -} - pub struct FnCtxt<'a, 'tcx> { - body_id: hir::HirId, + pub(super) body_id: hir::HirId, /// The parameter environment used for proving trait obligations /// in this function. This can change when we descend into @@ -548,7 +73,7 @@ pub struct FnCtxt<'a, 'tcx> { /// not part of `Inherited` (as of the time of this writing, /// closures do not yet change the environment, but they will /// eventually). - param_env: ty::ParamEnv<'tcx>, + pub(super) param_env: ty::ParamEnv<'tcx>, /// Number of errors that had been reported when we started /// checking this function. On exit, if we find that *more* errors @@ -568,14 +93,22 @@ pub struct FnCtxt<'a, 'tcx> { /// expression or other branching context. You can use methods /// like `expected_ty` to access the declared return type (if /// any). - ret_coercion: Option>>, + pub(super) ret_coercion: Option>>, + + pub(super) ret_coercion_impl_trait: Option>, + + pub(super) ret_type_span: Option, + + /// Used exclusively to reduce cost of advanced evaluation used for + /// more helpful diagnostics. + pub(super) in_tail_expr: bool, /// First span of a return site that we find. Used in error messages. - ret_coercion_span: RefCell>, + pub(super) ret_coercion_span: RefCell>, - resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, + pub(super) resume_yield_tys: Option<(Ty<'tcx>, Ty<'tcx>)>, - ps: RefCell, + pub(super) ps: RefCell, /// Whether the last checked node generates a divergence (e.g., /// `return` will set this to `Always`). In general, when entering @@ -608,2469 +141,14 @@ pub struct FnCtxt<'a, 'tcx> { /// /// An expression represents dead code if, after checking it, /// the diverges flag is set to something other than `Maybe`. - diverges: Cell, + pub(super) diverges: Cell, /// Whether any child nodes have any type errors. - has_errors: Cell, + pub(super) has_errors: Cell, - enclosing_breakables: RefCell>, + pub(super) enclosing_breakables: RefCell>, - inh: &'a Inherited<'a, 'tcx>, -} - -impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { - type Target = Inherited<'a, 'tcx>; - fn deref(&self) -> &Self::Target { - &self.inh - } -} - -/// Helper type of a temporary returned by `Inherited::build(...)`. -/// Necessary because we can't write the following bound: -/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. -pub struct InheritedBuilder<'tcx> { - infcx: infer::InferCtxtBuilder<'tcx>, - def_id: LocalDefId, -} - -impl Inherited<'_, 'tcx> { - pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> { - let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; - - InheritedBuilder { - infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), - def_id, - } - } -} - -impl<'tcx> InheritedBuilder<'tcx> { - pub fn enter(&mut self, f: F) -> R - where - F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, - { - let def_id = self.def_id; - self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) - } -} - -impl Inherited<'a, 'tcx> { - fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { - let tcx = infcx.tcx; - let item_id = tcx.hir().local_def_id_to_hir_id(def_id); - let body_id = tcx.hir().maybe_body_owned_by(item_id); - - Inherited { - typeck_results: MaybeInProgressTables { - maybe_typeck_results: infcx.in_progress_typeck_results, - }, - infcx, - fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), - locals: RefCell::new(Default::default()), - deferred_sized_obligations: RefCell::new(Vec::new()), - deferred_call_resolutions: RefCell::new(Default::default()), - deferred_cast_checks: RefCell::new(Vec::new()), - deferred_generator_interiors: RefCell::new(Vec::new()), - opaque_types: RefCell::new(Default::default()), - opaque_types_vars: RefCell::new(Default::default()), - body_id, - } - } - - fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { - debug!("register_predicate({:?})", obligation); - if obligation.has_escaping_bound_vars() { - span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); - } - self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); - } - - fn register_predicates(&self, obligations: I) - where - I: IntoIterator>, - { - for obligation in obligations { - self.register_predicate(obligation); - } - } - - fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { - self.register_predicates(infer_ok.obligations); - infer_ok.value - } - - fn normalize_associated_types_in( - &self, - span: Span, - body_id: hir::HirId, - param_env: ty::ParamEnv<'tcx>, - value: &T, - ) -> T - where - T: TypeFoldable<'tcx>, - { - let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); - self.register_infer_ok_obligations(ok) - } -} - -struct CheckItemTypesVisitor<'tcx> { - tcx: TyCtxt<'tcx>, -} - -impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { - fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { - check_item_type(self.tcx, i); - } - fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} - fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} -} - -pub fn check_wf_new(tcx: TyCtxt<'_>) { - let visit = wfcheck::CheckTypeWellFormedVisitor::new(tcx); - tcx.hir().krate().par_visit_all_item_likes(&visit); -} - -fn check_mod_item_types(tcx: TyCtxt<'_>, module_def_id: LocalDefId) { - tcx.hir().visit_item_likes_in_module(module_def_id, &mut CheckItemTypesVisitor { tcx }); -} - -fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { - debug_assert!(crate_num == LOCAL_CRATE); - tcx.par_body_owners(|body_owner_def_id| { - tcx.ensure().typeck(body_owner_def_id); - }); -} - -fn check_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_item_well_formed(tcx, def_id); -} - -fn check_trait_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_trait_item(tcx, def_id); -} - -fn check_impl_item_well_formed(tcx: TyCtxt<'_>, def_id: LocalDefId) { - wfcheck::check_impl_item(tcx, def_id); -} - -pub fn provide(providers: &mut Providers) { - method::provide(providers); - *providers = Providers { - typeck_item_bodies, - typeck_const_arg, - typeck, - diagnostic_only_typeck, - has_typeck_results, - adt_destructor, - used_trait_imports, - check_item_well_formed, - check_trait_item_well_formed, - check_impl_item_well_formed, - check_mod_item_types, - ..*providers - }; -} - -fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) -} - -/// If this `DefId` is a "primary tables entry", returns -/// `Some((body_id, header, decl))` with information about -/// it's body-id, fn-header and fn-decl (if any). Otherwise, -/// returns `None`. -/// -/// If this function returns `Some`, then `typeck_results(def_id)` will -/// succeed; if it returns `None`, then `typeck_results(def_id)` may or -/// may not succeed. In some cases where this function returns `None` -/// (notably closures), `typeck_results(def_id)` would wind up -/// redirecting to the owning function. -fn primary_body_of( - tcx: TyCtxt<'_>, - id: hir::HirId, -) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnHeader>, Option<&hir::FnDecl<'_>>)> { - match tcx.hir().get(id) { - Node::Item(item) => match item.kind { - hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => { - Some((body, Some(ty), None, None)) - } - hir::ItemKind::Fn(ref sig, .., body) => { - Some((body, None, Some(&sig.header), Some(&sig.decl))) - } - _ => None, - }, - Node::TraitItem(item) => match item.kind { - hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None, None)), - hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { - Some((body, None, Some(&sig.header), Some(&sig.decl))) - } - _ => None, - }, - Node::ImplItem(item) => match item.kind { - hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None, None)), - hir::ImplItemKind::Fn(ref sig, body) => { - Some((body, None, Some(&sig.header), Some(&sig.decl))) - } - _ => None, - }, - Node::AnonConst(constant) => Some((constant.body, None, None, None)), - _ => None, - } -} - -fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id); - if outer_def_id != def_id { - return tcx.has_typeck_results(outer_def_id); - } - - if let Some(def_id) = def_id.as_local() { - let id = tcx.hir().local_def_id_to_hir_id(def_id); - primary_body_of(tcx, id).is_some() - } else { - false - } -} - -fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet { - &*tcx.typeck(def_id).used_trait_imports -} - -/// Inspects the substs of opaque types, replacing any inference variables -/// with proper generic parameter from the identity substs. -/// -/// This is run after we normalize the function signature, to fix any inference -/// variables introduced by the projection of associated types. This ensures that -/// any opaque types used in the signature continue to refer to generic parameters, -/// allowing them to be considered for defining uses in the function body -/// -/// For example, consider this code. -/// -/// ```rust -/// trait MyTrait { -/// type MyItem; -/// fn use_it(self) -> Self::MyItem -/// } -/// impl MyTrait for T where T: Iterator { -/// type MyItem = impl Iterator; -/// fn use_it(self) -> Self::MyItem { -/// self -/// } -/// } -/// ``` -/// -/// When we normalize the signature of `use_it` from the impl block, -/// we will normalize `Self::MyItem` to the opaque type `impl Iterator` -/// However, this projection result may contain inference variables, due -/// to the way that projection works. We didn't have any inference variables -/// in the signature to begin with - leaving them in will cause us to incorrectly -/// conclude that we don't have a defining use of `MyItem`. By mapping inference -/// variables back to the actual generic parameters, we will correctly see that -/// we have a defining use of `MyItem` -fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T -where - T: TypeFoldable<'tcx>, -{ - struct FixupFolder<'tcx> { - tcx: TyCtxt<'tcx>, - } - - impl<'tcx> TypeFolder<'tcx> for FixupFolder<'tcx> { - fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { - self.tcx - } - - fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { - ty::Opaque(def_id, substs) => { - debug!("fixup_opaque_types: found type {:?}", ty); - // Here, we replace any inference variables that occur within - // the substs of an opaque type. By definition, any type occurring - // in the substs has a corresponding generic parameter, which is what - // we replace it with. - // This replacement is only run on the function signature, so any - // inference variables that we come across must be the rust of projection - // (there's no other way for a user to get inference variables into - // a function signature). - if ty.needs_infer() { - let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| { - let old_param = substs[param.index as usize]; - match old_param.unpack() { - GenericArgKind::Type(old_ty) => { - if let ty::Infer(_) = old_ty.kind { - // Replace inference type with a generic parameter - self.tcx.mk_param_from_def(param) - } else { - old_param.fold_with(self) - } - } - GenericArgKind::Const(old_const) => { - if let ty::ConstKind::Infer(_) = old_const.val { - // This should never happen - we currently do not support - // 'const projections', e.g.: - // `impl MyTrait for T where ::MyConst == 25` - // which should be the only way for us to end up with a const inference - // variable after projection. If Rust ever gains support for this kind - // of projection, this should *probably* be changed to - // `self.tcx.mk_param_from_def(param)` - bug!( - "Found infer const: `{:?}` in opaque type: {:?}", - old_const, - ty - ); - } else { - old_param.fold_with(self) - } - } - GenericArgKind::Lifetime(old_region) => { - if let RegionKind::ReVar(_) = old_region { - self.tcx.mk_param_from_def(param) - } else { - old_param.fold_with(self) - } - } - } - }); - let new_ty = self.tcx.mk_opaque(def_id, new_substs); - debug!("fixup_opaque_types: new type: {:?}", new_ty); - new_ty - } else { - ty - } - } - _ => ty.super_fold_with(self), - } - } - } - - debug!("fixup_opaque_types({:?})", val); - val.fold_with(&mut FixupFolder { tcx }) -} - -fn typeck_const_arg<'tcx>( - tcx: TyCtxt<'tcx>, - (did, param_did): (LocalDefId, DefId), -) -> &ty::TypeckResults<'tcx> { - let fallback = move || tcx.type_of(param_did); - typeck_with_fallback(tcx, did, fallback) -} - -fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - if let Some(param_did) = tcx.opt_const_param_of(def_id) { - tcx.typeck_const_arg((def_id, param_did)) - } else { - let fallback = move || tcx.type_of(def_id.to_def_id()); - typeck_with_fallback(tcx, def_id, fallback) - } -} - -/// Used only to get `TypeckResults` for type inference during error recovery. -/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. -fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { - let fallback = move || { - let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); - tcx.ty_error_with_message(span, "diagnostic only typeck table used") - }; - typeck_with_fallback(tcx, def_id, fallback) -} - -fn typeck_with_fallback<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - fallback: impl Fn() -> Ty<'tcx> + 'tcx, -) -> &'tcx ty::TypeckResults<'tcx> { - // Closures' typeck results come from their outermost function, - // as they are part of the same "inference environment". - let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); - if outer_def_id != def_id { - return tcx.typeck(outer_def_id); - } - - let id = tcx.hir().local_def_id_to_hir_id(def_id); - let span = tcx.hir().span(id); - - // Figure out what primary body this item has. - let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| { - span_bug!(span, "can't type-check body of {:?}", def_id); - }); - let body = tcx.hir().body(body_id); - - let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { - let param_env = tcx.param_env(def_id); - let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) { - let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { - let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - AstConv::ty_of_fn( - &fcx, - header.unsafety, - header.abi, - decl, - &hir::Generics::empty(), - None, - ) - } else { - tcx.fn_sig(def_id) - }; - - check_abi(tcx, span, fn_sig.abi()); - - // 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); - let fn_sig = inh.normalize_associated_types_in( - body.value.span, - body_id.hir_id, - param_env, - &fn_sig, - ); - - let fn_sig = fixup_opaque_types(tcx, &fn_sig); - - let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; - fcx - } else { - let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); - let expected_type = body_ty - .and_then(|ty| match ty.kind { - hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)), - _ => None, - }) - .unwrap_or_else(fallback); - let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); - fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); - - let revealed_ty = if tcx.features().impl_trait_in_bindings { - fcx.instantiate_opaque_types_from_value(id, &expected_type, body.value.span) - } else { - expected_type - }; - - // Gather locals in statics (because of block expressions). - GatherLocalsVisitor { fcx: &fcx, parent_id: id }.visit_body(body); - - fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); - - fcx.write_ty(id, revealed_ty); - - fcx - }; - - // All type checking constraints were added, try to fallback unsolved variables. - fcx.select_obligations_where_possible(false, |_| {}); - 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 &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque); - } - // 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: - // - // ```rust - // type MyType = impl Copy; - // fn produce() -> MyType { true } - // fn bad_produce() -> MyType { panic!() } - // ``` - // - // we want to unify the opaque inference variable in `bad_produce` - // with the diverging fallback for `panic!` (e.g. `()` or `!`). - // This will produce a nice error message about conflicting concrete - // types for `MyType`. - // - // If we had tried to fallback the opaque inference variable to `MyType`, - // we will generate a confusing type-check error that does not explicitly - // refer to opaque types. - fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); - - // We now run fallback again, but this time we allow it to replace - // unconstrained opaque type variables, in addition to performing - // other kinds of fallback. - for ty in &fcx.unsolved_variables() { - fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All); - } - - // See if we can make any more progress. - fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); - - // Even though coercion casts provide type hints, we check casts after fallback for - // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. - fcx.check_casts(); - - // Closure and generator analysis may run after fallback - // because they don't constrain other type variables. - fcx.closure_analyze(body); - assert!(fcx.deferred_call_resolutions.borrow().is_empty()); - fcx.resolve_generator_interiors(def_id.to_def_id()); - - for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { - let ty = fcx.normalize_ty(span, ty); - fcx.require_type_is_sized(ty, span, code); - } - - fcx.select_all_obligations_or_error(); - - if fn_decl.is_some() { - fcx.regionck_fn(id, body); - } else { - fcx.regionck_expr(body); - } - - fcx.resolve_type_vars_in_body(body) - }); - - // Consistency check our TypeckResults instance can hold all ItemLocalIds - // it will need to hold. - assert_eq!(typeck_results.hir_owner, id.owner); - - typeck_results -} - -fn check_abi(tcx: TyCtxt<'_>, span: Span, abi: Abi) { - if !tcx.sess.target.target.is_abi_supported(abi) { - struct_span_err!( - tcx.sess, - span, - E0570, - "The ABI `{}` is not supported for the current target", - abi - ) - .emit() - } -} - -struct GatherLocalsVisitor<'a, 'tcx> { - fcx: &'a FnCtxt<'a, 'tcx>, - parent_id: hir::HirId, -} - -impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { - fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { - match ty_opt { - None => { - // Infer the variable's type. - let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }); - self.fcx - .locals - .borrow_mut() - .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); - var_ty - } - Some(typ) => { - // Take type that the user specified. - self.fcx.locals.borrow_mut().insert(nid, typ); - typ.revealed_ty - } - } - } -} - -impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { - type Map = intravisit::ErasedMap<'tcx>; - - fn nested_visit_map(&mut self) -> NestedVisitorMap { - NestedVisitorMap::None - } - - // Add explicitly-declared locals. - fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { - let local_ty = match local.ty { - Some(ref ty) => { - let o_ty = self.fcx.to_ty(&ty); - - let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { - self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) - } else { - o_ty - }; - - let c_ty = self - .fcx - .inh - .infcx - .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); - debug!( - "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", - ty.hir_id, o_ty, revealed_ty, c_ty - ); - self.fcx - .typeck_results - .borrow_mut() - .user_provided_types_mut() - .insert(ty.hir_id, c_ty); - - Some(LocalTy { decl_ty: o_ty, revealed_ty }) - } - None => None, - }; - self.assign(local.span, local.hir_id, local_ty); - - debug!( - "local variable {:?} is assigned type {}", - local.pat, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty) - ); - intravisit::walk_local(self, local); - } - - // Add pattern bindings. - fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { - if let PatKind::Binding(_, _, ident, _) = p.kind { - let var_ty = self.assign(p.span, p.hir_id, None); - - if !self.fcx.tcx.features().unsized_locals { - self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); - } - - debug!( - "pattern binding {} is assigned to {} with type {:?}", - ident, - self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), - var_ty - ); - } - intravisit::walk_pat(self, p); - } - - // Don't descend into the bodies of nested closures. - fn visit_fn( - &mut self, - _: intravisit::FnKind<'tcx>, - _: &'tcx hir::FnDecl<'tcx>, - _: hir::BodyId, - _: Span, - _: hir::HirId, - ) { - } -} - -/// When `check_fn` is invoked on a generator (i.e., a body that -/// includes yield), it returns back some information about the yield -/// points. -struct GeneratorTypes<'tcx> { - /// Type of generator argument / values returned by `yield`. - resume_ty: Ty<'tcx>, - - /// Type of value that is yielded. - yield_ty: Ty<'tcx>, - - /// Types that are captured (see `GeneratorInterior` for more). - interior: Ty<'tcx>, - - /// Indicates if the generator is movable or static (immovable). - movability: hir::Movability, -} - -/// Helper used for fns and closures. Does the grungy work of checking a function -/// body and returns the function context used for that purpose, since in the case of a fn item -/// there is still a bit more to do. -/// -/// * ... -/// * inherited: other fields inherited from the enclosing fn (if any) -fn check_fn<'a, 'tcx>( - inherited: &'a Inherited<'a, 'tcx>, - param_env: ty::ParamEnv<'tcx>, - fn_sig: ty::FnSig<'tcx>, - decl: &'tcx hir::FnDecl<'tcx>, - fn_id: hir::HirId, - body: &'tcx hir::Body<'tcx>, - can_be_generator: Option, -) -> (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); - *fcx.ps.borrow_mut() = UnsafetyState::function(fn_sig.unsafety, fn_id); - - let tcx = fcx.tcx; - let sess = tcx.sess; - let hir = tcx.hir(); - - let declared_ret_ty = fn_sig.output(); - let revealed_ret_ty = - fcx.instantiate_opaque_types_from_value(fn_id, &declared_ret_ty, decl.output.span()); - debug!("check_fn: declared_ret_ty: {}, revealed_ret_ty: {}", declared_ret_ty, revealed_ret_ty); - fcx.ret_coercion = Some(RefCell::new(CoerceMany::new(revealed_ret_ty))); - fn_sig = tcx.mk_fn_sig( - fn_sig.inputs().iter().cloned(), - revealed_ret_ty, - fn_sig.c_variadic, - fn_sig.unsafety, - fn_sig.abi, - ); - - let span = body.value.span; - - fn_maybe_err(tcx, span, fn_sig.abi); - - if body.generator_kind.is_some() && can_be_generator.is_some() { - let yield_ty = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); - - // Resume type defaults to `()` if the generator has no argument. - let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); - - fcx.resume_yield_tys = Some((resume_ty, yield_ty)); - } - - let outer_def_id = tcx.closure_base_def_id(hir.local_def_id(fn_id).to_def_id()).expect_local(); - let outer_hir_id = hir.local_def_id_to_hir_id(outer_def_id); - GatherLocalsVisitor { fcx: &fcx, parent_id: outer_hir_id }.visit_body(body); - - // C-variadic fns also have a `VaList` input that's not listed in `fn_sig` - // (as it's created inside the body itself, not passed in from outside). - let maybe_va_list = if fn_sig.c_variadic { - let span = body.params.last().unwrap().span; - let va_list_did = tcx.require_lang_item(LangItem::VaList, Some(span)); - let region = fcx.next_region_var(RegionVariableOrigin::MiscVariable(span)); - - Some(tcx.type_of(va_list_did).subst(tcx, &[region.into()])) - } else { - None - }; - - // Add formal parameters. - let inputs_hir = hir.fn_decl_by_hir_id(fn_id).map(|decl| &decl.inputs); - let inputs_fn = fn_sig.inputs().iter().copied(); - for (idx, (param_ty, param)) in inputs_fn.chain(maybe_va_list).zip(body.params).enumerate() { - // Check the pattern. - let ty_span = try { inputs_hir?.get(idx)?.span }; - fcx.check_pat_top(¶m.pat, param_ty, ty_span, false); - - // Check that argument is Sized. - // The check for a non-trivial pattern is a hack to avoid duplicate warnings - // for simple cases like `fn foo(x: Trait)`, - // where we would error once on the parameter as a whole, and once on the binding `x`. - if param.pat.simple_ident().is_none() && !tcx.features().unsized_locals { - fcx.require_type_is_sized(param_ty, param.pat.span, traits::SizedArgumentType(ty_span)); - } - - fcx.write_ty(param.hir_id, param_ty); - } - - inherited.typeck_results.borrow_mut().liberated_fn_sigs_mut().insert(fn_id, fn_sig); - - if let ty::Dynamic(..) = declared_ret_ty.kind { - // FIXME: We need to verify that the return type is `Sized` after the return expression has - // been evaluated so that we have types available for all the nodes being returned, but that - // requires the coerced evaluated type to be stored. Moving `check_return_expr` before this - // causes unsized errors caused by the `declared_ret_ty` to point at the return expression, - // while keeping the current ordering we will ignore the tail expression's type because we - // don't know it yet. We can't do `check_expr_kind` while keeping `check_return_expr` - // because we will trigger "unreachable expression" lints unconditionally. - // Because of all of this, we perform a crude check to know whether the simplest `!Sized` - // case that a newcomer might make, returning a bare trait, and in that case we populate - // the tail expression's type so that the suggestion will be correct, but ignore all other - // possible cases. - fcx.check_expr(&body.value); - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - tcx.sess.delay_span_bug(decl.output.span(), "`!Sized` return type"); - } else { - fcx.require_type_is_sized(declared_ret_ty, decl.output.span(), traits::SizedReturnType); - fcx.check_return_expr(&body.value); - } - - // We insert the deferred_generator_interiors entry after visiting the body. - // This ensures that all nested generators appear before the entry of this generator. - // resolve_generator_interiors relies on this property. - let gen_ty = if let (Some(_), Some(gen_kind)) = (can_be_generator, body.generator_kind) { - let interior = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span }); - fcx.deferred_generator_interiors.borrow_mut().push((body.id(), interior, gen_kind)); - - let (resume_ty, yield_ty) = fcx.resume_yield_tys.unwrap(); - Some(GeneratorTypes { - resume_ty, - yield_ty, - interior, - movability: can_be_generator.unwrap(), - }) - } else { - None - }; - - // Finalize the return check by taking the LUB of the return types - // 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, - }); - } - fcx.demand_suptype(span, revealed_ret_ty, actual_return_ty); - - // Check that the main return type implements the termination trait. - if let Some(term_id) = tcx.lang_items().termination() { - if let Some((def_id, EntryFnType::Main)) = tcx.entry_fn(LOCAL_CRATE) { - let main_id = hir.local_def_id_to_hir_id(def_id); - if main_id == fn_id { - let substs = tcx.mk_substs_trait(declared_ret_ty, &[]); - let trait_ref = ty::TraitRef::new(term_id, substs); - let return_ty_span = decl.output.span(); - let cause = traits::ObligationCause::new( - return_ty_span, - fn_id, - ObligationCauseCode::MainFunctionType, - ); - - inherited.register_predicate(traits::Obligation::new( - cause, - param_env, - trait_ref.without_const().to_predicate(tcx), - )); - } - } - } - - // Check that a function marked as `#[panic_handler]` has signature `fn(&PanicInfo) -> !` - if let Some(panic_impl_did) = tcx.lang_items().panic_impl() { - if panic_impl_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(panic_info_did) = tcx.lang_items().panic_info() { - if declared_ret_ty.kind != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_panic_info = match inputs[0].kind { - ty::Ref(region, ty, mutbl) => match ty.kind { - ty::Adt(ref adt, _) => { - adt.did == panic_info_did - && mutbl == hir::Mutability::Not - && *region != RegionKind::ReStatic - } - _ => false, - }, - _ => false, - }; - - if !arg_is_panic_info { - sess.span_err(decl.inputs[0].span, "argument should be `&PanicInfo`"); - } - - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { - sess.span_err(span, "should have no type parameters"); - } - } - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); - } - } else { - sess.err("language item required, but not found: `panic_info`"); - } - } - } - - // Check that a function marked as `#[alloc_error_handler]` has signature `fn(Layout) -> !` - if let Some(alloc_error_handler_did) = tcx.lang_items().oom() { - if alloc_error_handler_did == hir.local_def_id(fn_id).to_def_id() { - if let Some(alloc_layout_did) = tcx.lang_items().alloc_layout() { - if declared_ret_ty.kind != ty::Never { - sess.span_err(decl.output.span(), "return type should be `!`"); - } - - let inputs = fn_sig.inputs(); - let span = hir.span(fn_id); - if inputs.len() == 1 { - let arg_is_alloc_layout = match inputs[0].kind { - ty::Adt(ref adt, _) => adt.did == alloc_layout_did, - _ => false, - }; - - if !arg_is_alloc_layout { - sess.span_err(decl.inputs[0].span, "argument should be `Layout`"); - } - - if let Node::Item(item) = hir.get(fn_id) { - if let ItemKind::Fn(_, ref generics, _) = item.kind { - if !generics.params.is_empty() { - sess.span_err( - span, - "`#[alloc_error_handler]` function should have no type \ - parameters", - ); - } - } - } - } else { - let span = sess.source_map().guess_head_span(span); - sess.span_err(span, "function should have one argument"); - } - } else { - sess.err("language item required, but not found: `alloc_layout`"); - } - } - } - - (fcx, gen_ty) -} - -fn check_struct(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - check_representable(tcx, span, def_id); - - if def.repr.simd() { - check_simd(tcx, span, def_id); - } - - check_transparent(tcx, span, def); - check_packed(tcx, span, def); -} - -fn check_union(tcx: TyCtxt<'_>, id: hir::HirId, span: Span) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - check_representable(tcx, span, def_id); - check_transparent(tcx, span, def); - check_union_fields(tcx, span, def_id); - check_packed(tcx, span, def); -} - -/// When the `#![feature(untagged_unions)]` gate is active, -/// check that the fields of the `union` does not contain fields that need dropping. -fn check_union_fields(tcx: TyCtxt<'_>, span: Span, item_def_id: LocalDefId) -> bool { - let item_type = tcx.type_of(item_def_id); - if let ty::Adt(def, substs) = item_type.kind { - assert!(def.is_union()); - let fields = &def.non_enum_variant().fields; - let param_env = tcx.param_env(item_def_id); - for field in fields { - let field_ty = field.ty(tcx, substs); - // We are currently checking the type this field came from, so it must be local. - let field_span = tcx.hir().span_if_local(field.did).unwrap(); - if field_ty.needs_drop(tcx, param_env) { - struct_span_err!( - tcx.sess, - field_span, - E0740, - "unions may not contain fields that need dropping" - ) - .span_note(field_span, "`std::mem::ManuallyDrop` can be used to wrap the type") - .emit(); - return false; - } - } - } else { - span_bug!(span, "unions must be ty::Adt, but got {:?}", item_type.kind); - } - true -} - -/// Checks that an opaque type does not contain cycles and does not use `Self` or `T::Foo` -/// projections that would result in "inheriting lifetimes". -fn check_opaque<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - substs: SubstsRef<'tcx>, - span: Span, - origin: &hir::OpaqueTyOrigin, -) { - check_opaque_for_inheriting_lifetimes(tcx, def_id, span); - check_opaque_for_cycles(tcx, def_id, substs, span, origin); -} - -/// Checks that an opaque type does not use `Self` or `T::Foo` projections that would result -/// in "inheriting lifetimes". -fn check_opaque_for_inheriting_lifetimes(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { - let item = tcx.hir().expect_item(tcx.hir().local_def_id_to_hir_id(def_id)); - debug!( - "check_opaque_for_inheriting_lifetimes: def_id={:?} span={:?} item={:?}", - def_id, span, item - ); - - #[derive(Debug)] - struct ProhibitOpaqueVisitor<'tcx> { - opaque_identity_ty: Ty<'tcx>, - generics: &'tcx ty::Generics, - ty: Option>, - }; - - impl<'tcx> ty::fold::TypeVisitor<'tcx> for ProhibitOpaqueVisitor<'tcx> { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - debug!("check_opaque_for_inheriting_lifetimes: (visit_ty) t={:?}", t); - if t != self.opaque_identity_ty && t.super_visit_with(self) { - self.ty = Some(t); - return true; - } - false - } - - fn visit_region(&mut self, r: ty::Region<'tcx>) -> bool { - debug!("check_opaque_for_inheriting_lifetimes: (visit_region) r={:?}", r); - if let RegionKind::ReEarlyBound(ty::EarlyBoundRegion { index, .. }) = r { - return *index < self.generics.parent_count as u32; - } - - r.super_visit_with(self) - } - - fn visit_const(&mut self, c: &'tcx ty::Const<'tcx>) -> bool { - if let ty::ConstKind::Unevaluated(..) = c.val { - // FIXME(#72219) We currenctly don't detect lifetimes within substs - // which would violate this check. Even though the particular substitution is not used - // within the const, this should still be fixed. - return false; - } - c.super_visit_with(self) - } - } - - if let ItemKind::OpaqueTy(hir::OpaqueTy { - origin: hir::OpaqueTyOrigin::AsyncFn | hir::OpaqueTyOrigin::FnReturn, - .. - }) = item.kind - { - let mut visitor = ProhibitOpaqueVisitor { - opaque_identity_ty: tcx.mk_opaque( - def_id.to_def_id(), - InternalSubsts::identity_for_item(tcx, def_id.to_def_id()), - ), - generics: tcx.generics_of(def_id), - ty: None, - }; - let prohibit_opaque = tcx - .predicates_of(def_id) - .predicates - .iter() - .any(|(predicate, _)| predicate.visit_with(&mut visitor)); - debug!( - "check_opaque_for_inheriting_lifetimes: prohibit_opaque={:?}, visitor={:?}", - prohibit_opaque, visitor - ); - - if prohibit_opaque { - let is_async = match item.kind { - ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => match origin { - hir::OpaqueTyOrigin::AsyncFn => true, - _ => false, - }, - _ => unreachable!(), - }; - - let mut err = struct_span_err!( - tcx.sess, - span, - E0760, - "`{}` return type cannot contain a projection or `Self` that references lifetimes from \ - a parent scope", - if is_async { "async fn" } else { "impl Trait" }, - ); - - if let Ok(snippet) = tcx.sess.source_map().span_to_snippet(span) { - if snippet == "Self" { - if let Some(ty) = visitor.ty { - err.span_suggestion( - span, - "consider spelling out the type instead", - format!("{:?}", ty), - Applicability::MaybeIncorrect, - ); - } - } - } - err.emit(); - } - } -} - -/// Given a `DefId` for an opaque type in return position, find its parent item's return -/// expressions. -fn get_owner_return_paths( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, -) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let id = tcx.hir().get_parent_item(hir_id); - tcx.hir() - .find(id) - .map(|n| (id, n)) - .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b))) - .map(|(hir_id, body_id)| { - let body = tcx.hir().body(body_id); - let mut visitor = ReturnsVisitor::default(); - visitor.visit_body(body); - (hir_id, visitor) - }) -} - -/// Emit an error for recursive opaque types. -/// -/// If this is a return `impl Trait`, find the item's return expressions and point at them. For -/// direct recursion this is enough, but for indirect recursion also point at the last intermediary -/// `impl Trait`. -/// -/// If all the return expressions evaluate to `!`, then we explain that the error will go away -/// after changing it. This can happen when a user uses `panic!()` or similar as a placeholder. -fn opaque_type_cycle_error(tcx: TyCtxt<'tcx>, def_id: LocalDefId, span: Span) { - let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); - - let mut label = false; - if let Some((hir_id, visitor)) = get_owner_return_paths(tcx, def_id) { - let typeck_results = tcx.typeck(tcx.hir().local_def_id(hir_id)); - if visitor - .returns - .iter() - .filter_map(|expr| typeck_results.node_type_opt(expr.hir_id)) - .all(|ty| matches!(ty.kind, ty::Never)) - { - let spans = visitor - .returns - .iter() - .filter(|expr| typeck_results.node_type_opt(expr.hir_id).is_some()) - .map(|expr| expr.span) - .collect::>(); - let span_len = spans.len(); - if span_len == 1 { - err.span_label(spans[0], "this returned value is of `!` type"); - } else { - let mut multispan: MultiSpan = spans.clone().into(); - for span in spans { - multispan - .push_span_label(span, "this returned value is of `!` type".to_string()); - } - err.span_note(multispan, "these returned values have a concrete \"never\" type"); - } - err.help("this error will resolve once the item's body returns a concrete type"); - } else { - let mut seen = FxHashSet::default(); - seen.insert(span); - err.span_label(span, "recursive opaque type"); - label = true; - for (sp, ty) in visitor - .returns - .iter() - .filter_map(|e| typeck_results.node_type_opt(e.hir_id).map(|t| (e.span, t))) - .filter(|(_, ty)| !matches!(ty.kind, ty::Never)) - { - struct VisitTypes(Vec); - impl<'tcx> ty::fold::TypeVisitor<'tcx> for VisitTypes { - fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { - ty::Opaque(def, _) => { - self.0.push(def); - false - } - _ => t.super_visit_with(self), - } - } - } - let mut visitor = VisitTypes(vec![]); - ty.visit_with(&mut visitor); - for def_id in visitor.0 { - let ty_span = tcx.def_span(def_id); - if !seen.contains(&ty_span) { - err.span_label(ty_span, &format!("returning this opaque type `{}`", ty)); - seen.insert(ty_span); - } - err.span_label(sp, &format!("returning here with type `{}`", ty)); - } - } - } - } - if !label { - err.span_label(span, "cannot resolve opaque type"); - } - err.emit(); -} - -/// Emit an error for recursive opaque types in a `let` binding. -fn binding_opaque_type_cycle_error( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - span: Span, - partially_expanded_type: Ty<'tcx>, -) { - let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); - err.span_label(span, "cannot resolve opaque type"); - // Find the the owner that declared this `impl Trait` type. - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let mut prev_hir_id = hir_id; - let mut hir_id = tcx.hir().get_parent_node(hir_id); - while let Some(node) = tcx.hir().find(hir_id) { - match node { - hir::Node::Local(hir::Local { - pat, - init: None, - ty: Some(ty), - source: hir::LocalSource::Normal, - .. - }) => { - err.span_label(pat.span, "this binding might not have a concrete type"); - err.span_suggestion_verbose( - ty.span.shrink_to_hi(), - "set the binding to a value for a concrete type to be resolved", - " = /* value */".to_string(), - Applicability::HasPlaceholders, - ); - } - hir::Node::Local(hir::Local { - init: Some(expr), - source: hir::LocalSource::Normal, - .. - }) => { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); - let typeck_results = - tcx.typeck(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id))); - if let Some(ty) = typeck_results.node_type_opt(expr.hir_id) { - err.span_label( - expr.span, - &format!( - "this is of type `{}`, which doesn't constrain \ - `{}` enough to arrive to a concrete type", - ty, partially_expanded_type - ), - ); - } - } - _ => {} - } - if prev_hir_id == hir_id { - break; - } - prev_hir_id = hir_id; - hir_id = tcx.hir().get_parent_node(hir_id); - } - err.emit(); -} - -fn async_opaque_type_cycle_error(tcx: TyCtxt<'tcx>, span: Span) { - struct_span_err!(tcx.sess, span, E0733, "recursion in an `async fn` requires boxing") - .span_label(span, "recursive `async fn`") - .note("a recursive `async fn` must be rewritten to return a boxed `dyn Future`") - .emit(); -} - -/// Checks that an opaque type does not contain cycles. -fn check_opaque_for_cycles<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - substs: SubstsRef<'tcx>, - span: Span, - origin: &hir::OpaqueTyOrigin, -) { - if let Err(partially_expanded_type) = tcx.try_expand_impl_trait_type(def_id.to_def_id(), substs) - { - match origin { - hir::OpaqueTyOrigin::AsyncFn => async_opaque_type_cycle_error(tcx, span), - hir::OpaqueTyOrigin::Binding => { - binding_opaque_type_cycle_error(tcx, def_id, span, partially_expanded_type) - } - _ => opaque_type_cycle_error(tcx, def_id, span), - } - } -} - -// Forbid defining intrinsics in Rust code, -// as they must always be defined by the compiler. -fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { - if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { - tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); - } -} - -pub fn check_item_type<'tcx>(tcx: TyCtxt<'tcx>, it: &'tcx hir::Item<'tcx>) { - debug!( - "check_item_type(it.hir_id={}, it.name={})", - it.hir_id, - tcx.def_path_str(tcx.hir().local_def_id(it.hir_id).to_def_id()) - ); - let _indenter = indenter(); - match it.kind { - // Consts can play a role in type-checking, so they are included here. - hir::ItemKind::Static(..) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - tcx.ensure().typeck(def_id); - maybe_check_static_with_link_section(tcx, def_id, it.span); - } - hir::ItemKind::Const(..) => { - tcx.ensure().typeck(tcx.hir().local_def_id(it.hir_id)); - } - hir::ItemKind::Enum(ref enum_definition, _) => { - check_enum(tcx, it.span, &enum_definition.variants, it.hir_id); - } - hir::ItemKind::Fn(..) => {} // entirely within check_item_body - hir::ItemKind::Impl { ref items, .. } => { - debug!("ItemKind::Impl {} with id {}", it.ident, it.hir_id); - let impl_def_id = tcx.hir().local_def_id(it.hir_id); - if let Some(impl_trait_ref) = tcx.impl_trait_ref(impl_def_id) { - check_impl_items_against_trait(tcx, it.span, impl_def_id, impl_trait_ref, items); - let trait_def_id = impl_trait_ref.def_id; - check_on_unimplemented(tcx, trait_def_id, it); - } - } - hir::ItemKind::Trait(_, _, _, _, ref items) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - check_on_unimplemented(tcx, def_id.to_def_id(), it); - - for item in items.iter() { - let item = tcx.hir().trait_item(item.id); - if let hir::TraitItemKind::Fn(sig, _) = &item.kind { - let abi = sig.header.abi; - fn_maybe_err(tcx, item.ident.span, abi); - } - } - } - hir::ItemKind::Struct(..) => { - check_struct(tcx, it.hir_id, it.span); - } - hir::ItemKind::Union(..) => { - check_union(tcx, it.hir_id, it.span); - } - hir::ItemKind::OpaqueTy(hir::OpaqueTy { origin, .. }) => { - // HACK(jynelson): trying to infer the type of `impl trait` breaks documenting - // `async-std` (and `pub async fn` in general). - // Since rustdoc doesn't care about the concrete type behind `impl Trait`, just don't look at it! - // See https://github.com/rust-lang/rust/issues/75100 - if !tcx.sess.opts.actually_rustdoc { - let def_id = tcx.hir().local_def_id(it.hir_id); - - let substs = InternalSubsts::identity_for_item(tcx, def_id.to_def_id()); - check_opaque(tcx, def_id, substs, it.span, &origin); - } - } - hir::ItemKind::TyAlias(..) => { - let def_id = tcx.hir().local_def_id(it.hir_id); - let pty_ty = tcx.type_of(def_id); - let generics = tcx.generics_of(def_id); - check_type_params_are_used(tcx, &generics, pty_ty); - } - hir::ItemKind::ForeignMod(ref m) => { - check_abi(tcx, it.span, m.abi); - - if m.abi == Abi::RustIntrinsic { - for item in m.items { - intrinsic::check_intrinsic_type(tcx, item); - } - } else if m.abi == Abi::PlatformIntrinsic { - for item in m.items { - intrinsic::check_platform_intrinsic_type(tcx, item); - } - } else { - for item in m.items { - let generics = tcx.generics_of(tcx.hir().local_def_id(item.hir_id)); - let own_counts = generics.own_counts(); - if generics.params.len() - own_counts.lifetimes != 0 { - let (kinds, kinds_pl, egs) = match (own_counts.types, own_counts.consts) { - (_, 0) => ("type", "types", Some("u32")), - // We don't specify an example value, because we can't generate - // a valid value for any type. - (0, _) => ("const", "consts", None), - _ => ("type or const", "types or consts", None), - }; - struct_span_err!( - tcx.sess, - item.span, - E0044, - "foreign items may not have {} parameters", - kinds, - ) - .span_label(item.span, &format!("can't have {} parameters", kinds)) - .help( - // FIXME: once we start storing spans for type arguments, turn this - // into a suggestion. - &format!( - "replace the {} parameters with concrete {}{}", - kinds, - kinds_pl, - egs.map(|egs| format!(" like `{}`", egs)).unwrap_or_default(), - ), - ) - .emit(); - } - - if let hir::ForeignItemKind::Fn(ref fn_decl, _, _) = item.kind { - require_c_abi_if_c_variadic(tcx, fn_decl, m.abi, item.span); - } - } - } - } - _ => { /* nothing to do */ } - } -} - -fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) { - // Only restricted on wasm32 target for now - if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") { - return; - } - - // If `#[link_section]` is missing, then nothing to verify - let attrs = tcx.codegen_fn_attrs(id); - if attrs.link_section.is_none() { - return; - } - - // For the wasm32 target statics with `#[link_section]` are placed into custom - // sections of the final output file, but this isn't link custom sections of - // other executable formats. Namely we can only embed a list of bytes, - // nothing with pointers to anything else or relocations. If any relocation - // show up, reject them here. - // `#[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.const_eval_poly(id.to_def_id()) { - Ok(ConstValue::ByRef { alloc, .. }) => { - 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); - } - } - Ok(_) => bug!("Matching on non-ByRef static"), - Err(_) => {} - } -} - -fn check_on_unimplemented(tcx: TyCtxt<'_>, trait_def_id: DefId, item: &hir::Item<'_>) { - let item_def_id = tcx.hir().local_def_id(item.hir_id); - // an error would be reported if this fails. - let _ = traits::OnUnimplementedDirective::of_item(tcx, trait_def_id, item_def_id.to_def_id()); -} - -fn report_forbidden_specialization( - tcx: TyCtxt<'_>, - impl_item: &hir::ImplItem<'_>, - parent_impl: DefId, -) { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0520, - "`{}` specializes an item from a parent `impl`, but \ - that item is not marked `default`", - impl_item.ident - ); - err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident)); - - match tcx.span_of_impl(parent_impl) { - Ok(span) => { - err.span_label(span, "parent `impl` is here"); - err.note(&format!( - "to specialize, `{}` in the parent `impl` must be marked `default`", - impl_item.ident - )); - } - Err(cname) => { - err.note(&format!("parent implementation is in crate `{}`", cname)); - } - } - - err.emit(); -} - -fn check_specialization_validity<'tcx>( - tcx: TyCtxt<'tcx>, - trait_def: &ty::TraitDef, - trait_item: &ty::AssocItem, - impl_id: DefId, - impl_item: &hir::ImplItem<'_>, -) { - let kind = match impl_item.kind { - hir::ImplItemKind::Const(..) => ty::AssocKind::Const, - hir::ImplItemKind::Fn(..) => ty::AssocKind::Fn, - hir::ImplItemKind::TyAlias(_) => ty::AssocKind::Type, - }; - - let ancestors = match trait_def.ancestors(tcx, impl_id) { - Ok(ancestors) => ancestors, - Err(_) => return, - }; - let mut ancestor_impls = ancestors - .skip(1) - .filter_map(|parent| { - if parent.is_from_trait() { - None - } else { - Some((parent, parent.item(tcx, trait_item.ident, kind, trait_def.def_id))) - } - }) - .peekable(); - - if ancestor_impls.peek().is_none() { - // No parent, nothing to specialize. - return; - } - - let opt_result = ancestor_impls.find_map(|(parent_impl, parent_item)| { - match parent_item { - // Parent impl exists, and contains the parent item we're trying to specialize, but - // doesn't mark it `default`. - Some(parent_item) if traits::impl_item_is_final(tcx, &parent_item) => { - Some(Err(parent_impl.def_id())) - } - - // Parent impl contains item and makes it specializable. - Some(_) => Some(Ok(())), - - // Parent impl doesn't mention the item. This means it's inherited from the - // grandparent. In that case, if parent is a `default impl`, inherited items use the - // "defaultness" from the grandparent, else they are final. - None => { - if tcx.impl_defaultness(parent_impl.def_id()).is_default() { - None - } else { - Some(Err(parent_impl.def_id())) - } - } - } - }); - - // If `opt_result` is `None`, we have only encountered `default impl`s that don't contain the - // item. This is allowed, the item isn't actually getting specialized here. - let result = opt_result.unwrap_or(Ok(())); - - if let Err(parent_impl) = result { - report_forbidden_specialization(tcx, impl_item, parent_impl); - } -} - -fn check_impl_items_against_trait<'tcx>( - tcx: TyCtxt<'tcx>, - full_impl_span: Span, - impl_id: LocalDefId, - impl_trait_ref: ty::TraitRef<'tcx>, - impl_item_refs: &[hir::ImplItemRef<'_>], -) { - let impl_span = tcx.sess.source_map().guess_head_span(full_impl_span); - - // 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` - // isn't populated for such impls. - if impl_trait_ref.references_error() { - return; - } - - // Negative impls are not expected to have any items - match tcx.impl_polarity(impl_id) { - ty::ImplPolarity::Reservation | ty::ImplPolarity::Positive => {} - ty::ImplPolarity::Negative => { - if let [first_item_ref, ..] = impl_item_refs { - let first_item_span = tcx.hir().impl_item(first_item_ref.id).span; - struct_span_err!( - tcx.sess, - first_item_span, - E0749, - "negative impls cannot have any items" - ) - .emit(); - } - return; - } - } - - // Locate trait definition and items - let trait_def = tcx.trait_def(impl_trait_ref.def_id); - - let impl_items = || impl_item_refs.iter().map(|iiref| tcx.hir().impl_item(iiref.id)); - - // Check existing impl methods to see if they are both present in trait - // and compatible with trait signature - for impl_item in impl_items() { - let namespace = impl_item.kind.namespace(); - let ty_impl_item = tcx.associated_item(tcx.hir().local_def_id(impl_item.hir_id)); - let ty_trait_item = tcx - .associated_items(impl_trait_ref.def_id) - .find_by_name_and_namespace(tcx, ty_impl_item.ident, namespace, impl_trait_ref.def_id) - .or_else(|| { - // Not compatible, but needed for the error message - tcx.associated_items(impl_trait_ref.def_id) - .filter_by_name(tcx, ty_impl_item.ident, impl_trait_ref.def_id) - .next() - }); - - // Check that impl definition matches trait definition - if let Some(ty_trait_item) = ty_trait_item { - match impl_item.kind { - hir::ImplItemKind::Const(..) => { - // Find associated const definition. - if ty_trait_item.kind == ty::AssocKind::Const { - compare_const_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0323, - "item `{}` is an associated const, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - // We can only get the spans from local trait definition - // Same for E0324 and E0325 - if let Some(trait_span) = tcx.hir().span_if_local(ty_trait_item.def_id) { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - hir::ImplItemKind::Fn(..) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - if ty_trait_item.kind == ty::AssocKind::Fn { - compare_impl_method( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0324, - "item `{}` is an associated method, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = opt_trait_span { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - hir::ImplItemKind::TyAlias(_) => { - let opt_trait_span = tcx.hir().span_if_local(ty_trait_item.def_id); - if ty_trait_item.kind == ty::AssocKind::Type { - compare_ty_impl( - tcx, - &ty_impl_item, - impl_item.span, - &ty_trait_item, - impl_trait_ref, - opt_trait_span, - ); - } else { - let mut err = struct_span_err!( - tcx.sess, - impl_item.span, - E0325, - "item `{}` is an associated type, \ - which doesn't match its trait `{}`", - ty_impl_item.ident, - impl_trait_ref.print_only_trait_path() - ); - err.span_label(impl_item.span, "does not match trait"); - if let Some(trait_span) = opt_trait_span { - err.span_label(trait_span, "item in trait"); - } - err.emit() - } - } - } - - check_specialization_validity( - tcx, - trait_def, - &ty_trait_item, - impl_id.to_def_id(), - impl_item, - ); - } - } - - // Check for missing items from trait - let mut missing_items = Vec::new(); - if let Ok(ancestors) = trait_def.ancestors(tcx, impl_id.to_def_id()) { - for trait_item in tcx.associated_items(impl_trait_ref.def_id).in_definition_order() { - let is_implemented = ancestors - .leaf_def(tcx, trait_item.ident, trait_item.kind) - .map(|node_item| !node_item.defining_node.is_from_trait()) - .unwrap_or(false); - - if !is_implemented && tcx.impl_defaultness(impl_id).is_final() { - if !trait_item.defaultness.has_value() { - missing_items.push(*trait_item); - } - } - } - } - - if !missing_items.is_empty() { - missing_items_err(tcx, impl_span, &missing_items, full_impl_span); - } -} - -fn missing_items_err( - tcx: TyCtxt<'_>, - impl_span: Span, - missing_items: &[ty::AssocItem], - full_impl_span: Span, -) { - let missing_items_msg = missing_items - .iter() - .map(|trait_item| trait_item.ident.to_string()) - .collect::>() - .join("`, `"); - - let mut err = struct_span_err!( - tcx.sess, - impl_span, - E0046, - "not all trait items implemented, missing: `{}`", - missing_items_msg - ); - err.span_label(impl_span, format!("missing `{}` in implementation", missing_items_msg)); - - // `Span` before impl block closing brace. - let hi = full_impl_span.hi() - BytePos(1); - // Point at the place right before the closing brace of the relevant `impl` to suggest - // adding the associated item at the end of its body. - let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); - // Obtain the level of indentation ending in `sugg_sp`. - let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0); - // Make the whitespace that will make the suggestion have the right indentation. - let padding: String = (0..indentation).map(|_| " ").collect(); - - for trait_item in missing_items { - 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; - if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { - err.span_label(span, format!("`{}` from trait", trait_item.ident)); - err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); - } else { - err.span_suggestion_hidden(sugg_sp, &msg, code, appl); - } - } - err.emit(); -} - -/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. -fn bounds_from_generic_predicates<'tcx>( - tcx: TyCtxt<'tcx>, - predicates: ty::GenericPredicates<'tcx>, -) -> (String, String) { - let mut types: FxHashMap, Vec> = FxHashMap::default(); - let mut projections = vec![]; - for (predicate, _) in predicates.predicates { - debug!("predicate {:?}", predicate); - match predicate.skip_binders() { - ty::PredicateAtom::Trait(trait_predicate, _) => { - let entry = types.entry(trait_predicate.self_ty()).or_default(); - let def_id = trait_predicate.def_id(); - if Some(def_id) != tcx.lang_items().sized_trait() { - // Type params are `Sized` by default, do not add that restriction to the list - // if it is a positive requirement. - entry.push(trait_predicate.def_id()); - } - } - ty::PredicateAtom::Projection(projection_pred) => { - projections.push(ty::Binder::bind(projection_pred)); - } - _ => {} - } - } - let generics = if types.is_empty() { - "".to_string() - } else { - format!( - "<{}>", - types - .keys() - .filter_map(|t| match t.kind { - ty::Param(_) => Some(t.to_string()), - // Avoid suggesting the following: - // fn foo::Bar>(_: T) where T: Trait, ::Bar: Other {} - _ => None, - }) - .collect::>() - .join(", ") - ) - }; - let mut where_clauses = vec![]; - for (ty, bounds) in types { - for bound in &bounds { - where_clauses.push(format!("{}: {}", ty, tcx.def_path_str(*bound))); - } - } - for projection in &projections { - let p = projection.skip_binder(); - // FIXME: this is not currently supported syntax, we should be looking at the `types` and - // insert the associated types where they correspond, but for now let's be "lazy" and - // propose this instead of the following valid resugaring: - // `T: Trait, Trait::Assoc = K` → `T: Trait` - where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty)); - } - let where_clauses = if where_clauses.is_empty() { - String::new() - } else { - format!(" where {}", where_clauses.join(", ")) - }; - (generics, where_clauses) -} - -/// Return placeholder code for the given function. -fn fn_sig_suggestion<'tcx>( - tcx: TyCtxt<'tcx>, - sig: ty::FnSig<'tcx>, - ident: Ident, - predicates: ty::GenericPredicates<'tcx>, - assoc: &ty::AssocItem, -) -> String { - let args = sig - .inputs() - .iter() - .enumerate() - .map(|(i, ty)| { - Some(match ty.kind { - ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), - ty::Ref(reg, ref_ty, mutability) if i == 0 => { - let reg = match &format!("{}", reg)[..] { - "'_" | "" => String::new(), - reg => format!("{} ", reg), - }; - if assoc.fn_has_self_parameter { - match ref_ty.kind { - ty::Param(param) if param.name == kw::SelfUpper => { - format!("&{}{}self", reg, mutability.prefix_str()) - } - - _ => format!("self: {}", ty), - } - } else { - format!("_: {:?}", ty) - } - } - _ => { - if assoc.fn_has_self_parameter && i == 0 { - format!("self: {:?}", ty) - } else { - format!("_: {:?}", ty) - } - } - }) - }) - .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None })) - .filter_map(|arg| arg) - .collect::>() - .join(", "); - let output = sig.output(); - let output = if !output.is_unit() { format!(" -> {:?}", output) } else { String::new() }; - - let unsafety = sig.unsafety.prefix_str(); - let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); - - // FIXME: this is not entirely correct, as the lifetimes from borrowed params will - // not be present in the `fn` definition, not will we account for renamed - // lifetimes between the `impl` and the `trait`, but this should be good enough to - // fill in a significant portion of the missing code, and other subsequent - // suggestions can help the user fix the code. - format!( - "{}fn {}{}({}){}{} {{ todo!() }}", - unsafety, ident, generics, args, output, where_clauses - ) -} - -/// Return placeholder code for the given associated item. -/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a -/// structured suggestion. -fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { - match assoc.kind { - ty::AssocKind::Fn => { - // We skip the binder here because the binder would deanonymize all - // late-bound regions, and we don't want method signatures to show up - // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound - // regions just fine, showing `fn(&MyType)`. - fn_sig_suggestion( - tcx, - tcx.fn_sig(assoc.def_id).skip_binder(), - assoc.ident, - tcx.predicates_of(assoc.def_id), - assoc, - ) - } - ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), - ty::AssocKind::Const => { - let ty = tcx.type_of(assoc.def_id); - let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); - format!("const {}: {:?} = {};", assoc.ident, ty, val) - } - } -} - -/// Checks whether a type can be represented in memory. In particular, it -/// identifies types that contain themselves without indirection through a -/// pointer, which would mean their size is unbounded. -fn check_representable(tcx: TyCtxt<'_>, sp: Span, item_def_id: LocalDefId) -> bool { - let rty = tcx.type_of(item_def_id); - - // Check that it is possible to represent this type. This call identifies - // (1) types that contain themselves and (2) types that contain a different - // recursive type. It is only necessary to throw an error on those that - // contain themselves. For case 2, there must be an inner type that will be - // caught by case 1. - match rty.is_representable(tcx, sp) { - Representability::SelfRecursive(spans) => { - recursive_type_with_infinite_size_error(tcx, item_def_id.to_def_id(), spans); - return false; - } - Representability::Representable | Representability::ContainsRecursive => (), - } - true -} - -pub fn check_simd(tcx: TyCtxt<'_>, sp: Span, def_id: LocalDefId) { - let t = tcx.type_of(def_id); - if let ty::Adt(def, substs) = t.kind { - if def.is_struct() { - let fields = &def.non_enum_variant().fields; - if fields.is_empty() { - struct_span_err!(tcx.sess, sp, E0075, "SIMD vector cannot be empty").emit(); - return; - } - let e = fields[0].ty(tcx, substs); - if !fields.iter().all(|f| f.ty(tcx, substs) == e) { - struct_span_err!(tcx.sess, sp, E0076, "SIMD vector should be homogeneous") - .span_label(sp, "SIMD elements must have the same type") - .emit(); - return; - } - match e.kind { - ty::Param(_) => { /* struct(T, T, T, T) is ok */ } - _ if e.is_machine() => { /* struct(u8, u8, u8, u8) is ok */ } - _ => { - struct_span_err!( - tcx.sess, - sp, - E0077, - "SIMD vector element type should be machine type" - ) - .emit(); - return; - } - } - } - } -} - -fn check_packed(tcx: TyCtxt<'_>, sp: Span, def: &ty::AdtDef) { - let repr = def.repr; - if repr.packed() { - for attr in tcx.get_attrs(def.did).iter() { - for r in attr::find_repr_attrs(&tcx.sess, attr) { - if let attr::ReprPacked(pack) = r { - if let Some(repr_pack) = repr.pack { - if pack as u64 != repr_pack.bytes() { - struct_span_err!( - tcx.sess, - sp, - E0634, - "type has conflicting packed representation hints" - ) - .emit(); - } - } - } - } - } - if repr.align.is_some() { - struct_span_err!( - tcx.sess, - sp, - E0587, - "type has conflicting packed and align representation hints" - ) - .emit(); - } else { - if let Some(def_spans) = check_packed_inner(tcx, def.did, &mut vec![]) { - let mut err = struct_span_err!( - tcx.sess, - sp, - E0588, - "packed type cannot transitively contain a `#[repr(align)]` type" - ); - - err.span_note( - tcx.def_span(def_spans[0].0), - &format!( - "`{}` has a `#[repr(align)]` attribute", - tcx.item_name(def_spans[0].0) - ), - ); - - if def_spans.len() > 2 { - let mut first = true; - for (adt_def, span) in def_spans.iter().skip(1).rev() { - let ident = tcx.item_name(*adt_def); - err.span_note( - *span, - &if first { - format!( - "`{}` contains a field of type `{}`", - tcx.type_of(def.did), - ident - ) - } else { - format!("...which contains a field of type `{}`", ident) - }, - ); - first = false; - } - } - - err.emit(); - } - } - } -} - -fn check_packed_inner( - tcx: TyCtxt<'_>, - def_id: DefId, - stack: &mut Vec, -) -> Option> { - if let ty::Adt(def, substs) = tcx.type_of(def_id).kind { - if def.is_struct() || def.is_union() { - if def.repr.align.is_some() { - return Some(vec![(def.did, DUMMY_SP)]); - } - - stack.push(def_id); - for field in &def.non_enum_variant().fields { - if let ty::Adt(def, _) = field.ty(tcx, substs).kind { - if !stack.contains(&def.did) { - if let Some(mut defs) = check_packed_inner(tcx, def.did, stack) { - defs.push((def.did, field.ident.span)); - return Some(defs); - } - } - } - } - stack.pop(); - } - } - - None -} - -/// Emit an error when encountering more or less than one variant in a transparent enum. -fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) { - let variant_spans: Vec<_> = adt - .variants - .iter() - .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap()) - .collect(); - let msg = format!("needs exactly one variant, but has {}", adt.variants.len(),); - let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg); - err.span_label(sp, &msg); - if let [start @ .., end] = &*variant_spans { - for variant_span in start { - err.span_label(*variant_span, ""); - } - err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); - } - err.emit(); -} - -/// Emit an error when encountering more or less than one non-zero-sized field in a transparent -/// enum. -fn bad_non_zero_sized_fields<'tcx>( - tcx: TyCtxt<'tcx>, - adt: &'tcx ty::AdtDef, - field_count: usize, - field_spans: impl Iterator, - sp: Span, -) { - let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count); - let mut err = struct_span_err!( - tcx.sess, - sp, - E0690, - "{}transparent {} {}", - if adt.is_enum() { "the variant of a " } else { "" }, - adt.descr(), - msg, - ); - err.span_label(sp, &msg); - for sp in field_spans { - err.span_label(sp, "this field is non-zero-sized"); - } - err.emit(); -} - -fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, sp: Span, adt: &'tcx ty::AdtDef) { - if !adt.repr.transparent() { - return; - } - let sp = tcx.sess.source_map().guess_head_span(sp); - - if adt.is_union() && !tcx.features().transparent_unions { - feature_err( - &tcx.sess.parse_sess, - sym::transparent_unions, - sp, - "transparent unions are unstable", - ) - .emit(); - } - - if adt.variants.len() != 1 { - bad_variant_count(tcx, adt, sp, adt.did); - if adt.variants.is_empty() { - // Don't bother checking the fields. No variants (and thus no fields) exist. - return; - } - } - - // For each field, figure out if it's known to be a ZST and align(1) - let field_infos = adt.all_fields().map(|field| { - let ty = field.ty(tcx, InternalSubsts::identity_for_item(tcx, field.did)); - let param_env = tcx.param_env(field.did); - let layout = tcx.layout_of(param_env.and(ty)); - // We are currently checking the type this field came from, so it must be local - let span = tcx.hir().span_if_local(field.did).unwrap(); - let zst = layout.map(|layout| layout.is_zst()).unwrap_or(false); - let align1 = layout.map(|layout| layout.align.abi.bytes() == 1).unwrap_or(false); - (span, zst, align1) - }); - - let non_zst_fields = - field_infos.clone().filter_map(|(span, zst, _align1)| if !zst { Some(span) } else { None }); - let non_zst_count = non_zst_fields.clone().count(); - if non_zst_count != 1 { - bad_non_zero_sized_fields(tcx, adt, non_zst_count, non_zst_fields, sp); - } - for (span, zst, align1) in field_infos { - if zst && !align1 { - struct_span_err!( - tcx.sess, - span, - E0691, - "zero-sized field in transparent {} has alignment larger than 1", - adt.descr(), - ) - .span_label(span, "has alignment larger than 1") - .emit(); - } - } -} - -#[allow(trivial_numeric_casts)] -pub fn check_enum<'tcx>( - tcx: TyCtxt<'tcx>, - sp: Span, - vs: &'tcx [hir::Variant<'tcx>], - id: hir::HirId, -) { - let def_id = tcx.hir().local_def_id(id); - let def = tcx.adt_def(def_id); - def.destructor(tcx); // force the destructor to be evaluated - - if vs.is_empty() { - let attributes = tcx.get_attrs(def_id.to_def_id()); - if let Some(attr) = tcx.sess.find_by_name(&attributes, sym::repr) { - struct_span_err!( - tcx.sess, - attr.span, - E0084, - "unsupported representation for zero-variant enum" - ) - .span_label(sp, "zero-variant enum") - .emit(); - } - } - - let repr_type_ty = def.repr.discr_type().to_ty(tcx); - if repr_type_ty == tcx.types.i128 || repr_type_ty == tcx.types.u128 { - if !tcx.features().repr128 { - feature_err( - &tcx.sess.parse_sess, - sym::repr128, - sp, - "repr with 128-bit type is unstable", - ) - .emit(); - } - } - - for v in vs { - if let Some(ref e) = v.disr_expr { - tcx.ensure().typeck(tcx.hir().local_def_id(e.hir_id)); - } - } - - if tcx.adt_def(def_id).repr.int.is_none() && tcx.features().arbitrary_enum_discriminant { - let is_unit = |var: &hir::Variant<'_>| match var.data { - hir::VariantData::Unit(..) => true, - _ => false, - }; - - let has_disr = |var: &hir::Variant<'_>| var.disr_expr.is_some(); - let has_non_units = vs.iter().any(|var| !is_unit(var)); - let disr_units = vs.iter().any(|var| is_unit(&var) && has_disr(&var)); - let disr_non_unit = vs.iter().any(|var| !is_unit(&var) && has_disr(&var)); - - if disr_non_unit || (disr_units && has_non_units) { - let mut err = - struct_span_err!(tcx.sess, sp, E0732, "`#[repr(inttype)]` must be specified"); - err.emit(); - } - } - - let mut disr_vals: Vec> = Vec::with_capacity(vs.len()); - for ((_, discr), v) in def.discriminants(tcx).zip(vs) { - // Check for duplicate discriminant values - if let Some(i) = disr_vals.iter().position(|&x| x.val == discr.val) { - let variant_did = def.variants[VariantIdx::new(i)].def_id; - let variant_i_hir_id = tcx.hir().local_def_id_to_hir_id(variant_did.expect_local()); - let variant_i = tcx.hir().expect_variant(variant_i_hir_id); - let i_span = match variant_i.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => tcx.hir().span(variant_i_hir_id), - }; - let span = match v.disr_expr { - Some(ref expr) => tcx.hir().span(expr.hir_id), - None => v.span, - }; - struct_span_err!( - tcx.sess, - span, - E0081, - "discriminant value `{}` already exists", - disr_vals[i] - ) - .span_label(i_span, format!("first use of `{}`", disr_vals[i])) - .span_label(span, format!("enum already has `{}`", disr_vals[i])) - .emit(); - } - disr_vals.push(discr); - } - - check_representable(tcx, sp, def_id); - check_transparent(tcx, sp, def); -} - -fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { - struct_span_err!( - tcx.sess, - span, - E0533, - "expected unit struct, unit variant or constant, found {}{}", - res.descr(), - tcx.sess.source_map().span_to_snippet(span).map_or(String::new(), |s| format!(" `{}`", s)), - ) - .emit(); -} - -impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { - fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { - self.tcx - } - - fn item_def_id(&self) -> Option { - None - } - - fn default_constness_for_trait_bounds(&self) -> hir::Constness { - // FIXME: refactor this into a method - let node = self.tcx.hir().get(self.body_id); - if let Some(fn_like) = FnLikeNode::from_node(node) { - fn_like.constness() - } else { - hir::Constness::NotConst - } - } - - fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { - let tcx = self.tcx; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let item_id = tcx.hir().ty_param_owner(hir_id); - let item_def_id = tcx.hir().local_def_id(item_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - ty::GenericPredicates { - parent: None, - predicates: tcx.arena.alloc_from_iter( - self.param_env.caller_bounds().iter().filter_map(|predicate| { - match predicate.skip_binders() { - ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { - // HACK(eddyb) should get the original `Span`. - let span = tcx.def_span(def_id); - Some((predicate, span)) - } - _ => None, - } - }), - ), - } - } - - fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option> { - let v = match def { - Some(def) => infer::EarlyBoundRegion(span, def.name), - None => infer::MiscVariable(span), - }; - Some(self.next_region_var(v)) - } - - fn allow_ty_infer(&self) -> bool { - true - } - - fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { - return ty; - } - unreachable!() - } else { - self.next_ty_var(TypeVariableOrigin { - kind: TypeVariableOriginKind::TypeInference, - span, - }) - } - } - - fn ct_infer( - &self, - ty: Ty<'tcx>, - param: Option<&ty::GenericParamDef>, - span: Span, - ) -> &'tcx Const<'tcx> { - if let Some(param) = param { - if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { - return ct; - } - unreachable!() - } else { - self.next_const_var( - ty, - ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, - ) - } - } - - fn projected_ty_from_poly_trait_ref( - &self, - span: Span, - item_def_id: DefId, - item_segment: &hir::PathSegment<'_>, - poly_trait_ref: ty::PolyTraitRef<'tcx>, - ) -> Ty<'tcx> { - let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( - span, - infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), - &poly_trait_ref, - ); - - let item_substs = >::create_substs_for_associated_item( - self, - self.tcx, - span, - item_def_id, - item_segment, - trait_ref.substs, - ); - - self.tcx().mk_projection(item_def_id, item_substs) - } - - fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { - if ty.has_escaping_bound_vars() { - ty // FIXME: normalization and escaping regions - } else { - self.normalize_associated_types_in(span, &ty) - } - } - - fn set_tainted_by_errors(&self) { - self.infcx.set_tainted_by_errors() - } - - fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { - self.write_ty(hir_id, ty) - } -} - -/// Controls whether the arguments are tupled. This is used for the call -/// operator. -/// -/// Tupling means that all call-side arguments are packed into a tuple and -/// passed as a single parameter. For example, if tupling is enabled, this -/// function: -/// -/// fn f(x: (isize, isize)) -/// -/// Can be called as: -/// -/// f(1, 2); -/// -/// Instead of: -/// -/// f((1, 2)); -#[derive(Clone, Eq, PartialEq)] -enum TupleArgumentsFlag { - DontTupleArguments, - TupleArguments, -} - -/// Controls how we perform fallback for unconstrained -/// type variables. -enum FallbackMode { - /// Do not fallback type variables to opaque types. - NoOpaque, - /// Perform all possible kinds of fallback, including - /// turning type variables to opaque types. - All, + pub(super) inh: &'a Inherited<'a, 'tcx>, } impl<'a, 'tcx> FnCtxt<'a, 'tcx> { @@ -3084,6 +162,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { param_env, err_count_on_creation: inh.tcx.sess.err_count(), ret_coercion: None, + ret_coercion_impl_trait: None, + ret_type_span: None, + in_tail_expr: false, ret_coercion_span: RefCell::new(None), resume_yield_tys: None, ps: RefCell::new(UnsafetyState::function(hir::Unsafety::Normal, hir::CRATE_HIR_ID)), @@ -3107,7 +188,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Produces warning on the given node, if the current point in the /// function is unreachable, and there hasn't been another warning. - fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { + pub(super) fn warn_if_unreachable(&self, id: hir::HirId, span: Span, kind: &str) { // FIXME: Combine these two 'if' expressions into one once // let chains are implemented if let Diverges::Always { span: orig_span, custom_note } = self.diverges.get() { @@ -3149,7 +230,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// version (resolve_vars_if_possible), this version will /// also select obligations if it seems useful, in an effort /// to get more type information. - fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { + pub(super) fn resolve_vars_with_obligations(&self, mut ty: Ty<'tcx>) -> Ty<'tcx> { debug!("resolve_vars_with_obligations(ty={:?})", ty); // No Infer()? Nothing needs doing. @@ -3176,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } - fn record_deferred_call_resolution( + pub(super) fn record_deferred_call_resolution( &self, closure_def_id: DefId, r: DeferredCallResolution<'tcx>, @@ -3185,7 +266,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { deferred_call_resolutions.entry(closure_def_id).or_default().push(r); } - fn remove_deferred_call_resolutions( + pub(super) fn remove_deferred_call_resolutions( &self, closure_def_id: DefId, ) -> Vec> { @@ -3425,7 +506,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Replaces the opaque types from the given value with type variables, /// and records the `OpaqueTypeMap` for later use during writeback. See /// `InferCtxt::instantiate_opaque_types` for more details. - fn instantiate_opaque_types_from_value>( + pub(super) fn instantiate_opaque_types_from_value>( &self, parent_id: hir::HirId, value: &T, @@ -3456,14 +537,14 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { value } - fn normalize_associated_types_in(&self, span: Span, value: &T) -> T + pub(super) fn normalize_associated_types_in(&self, span: Span, value: &T) -> T where T: TypeFoldable<'tcx>, { self.inh.normalize_associated_types_in(span, self.body_id, self.param_env, value) } - fn normalize_associated_types_in_as_infer_ok( + pub(super) fn normalize_associated_types_in_as_infer_ok( &self, span: Span, value: &T, @@ -3670,18 +751,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.normalize_associated_types_in(span, &field.ty(self.tcx, substs)) } - fn check_casts(&self) { + pub(super) fn check_casts(&self) { let mut deferred_cast_checks = self.deferred_cast_checks.borrow_mut(); for cast in deferred_cast_checks.drain(..) { cast.check(self); } } - fn resolve_generator_interiors(&self, def_id: DefId) { + pub(super) fn resolve_generator_interiors(&self, def_id: DefId) { let mut generators = self.deferred_generator_interiors.borrow_mut(); for (body_id, interior, kind) in generators.drain(..) { self.select_obligations_where_possible(false, |_| {}); - generator_interior::resolve_interior(self, def_id, body_id, interior, kind); + super::generator_interior::resolve_interior(self, def_id, body_id, interior, kind); } } @@ -3697,7 +778,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // 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>, mode: FallbackMode) -> bool { + pub(super) fn fallback_if_possible(&self, ty: Ty<'tcx>, mode: FallbackMode) -> bool { use rustc_middle::ty::error::UnconstrainedNumeric::Neither; use rustc_middle::ty::error::UnconstrainedNumeric::{UnconstrainedFloat, UnconstrainedInt}; @@ -3762,7 +843,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } - fn select_all_obligations_or_error(&self) { + pub(super) fn select_all_obligations_or_error(&self) { debug!("select_all_obligations_or_error"); if let Err(errors) = self.fulfillment_cx.borrow_mut().select_all_or_error(&self) { self.report_fulfillment_errors(&errors, self.inh.body_id, false); @@ -3770,7 +851,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Select as many obligations as we can at present. - fn select_obligations_where_possible( + pub(super) fn select_obligations_where_possible( &self, fallback_has_occurred: bool, mutate_fullfillment_errors: impl Fn(&mut Vec>), @@ -3786,7 +867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// returns a type of `&T`, but the actual type we assign to the /// *expression* is `T`. So this function just peels off the return /// type by one layer to yield `T`. - fn make_overloaded_place_return_type( + pub(super) fn make_overloaded_place_return_type( &self, method: MethodCallee<'tcx>, ) -> ty::TypeAndMut<'tcx> { @@ -3797,7 +878,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ret_ty.builtin_deref(true).unwrap() } - fn check_method_argument_types( + pub(super) fn check_method_argument_types( &self, sp: Span, expr: &'tcx hir::Expr<'tcx>, @@ -3862,7 +943,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "self_type_matches_expected_vid(trait_ref={:?}, self_ty={:?}, expected_vid={:?})", trait_ref, self_ty, expected_vid ); - match self_ty.kind { + match *self_ty.kind() { ty::Infer(ty::TyVar(found_vid)) => { // FIXME: consider using `sub_root_var` here so we // can see through subtyping. @@ -3874,7 +955,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn obligations_for_self_ty<'b>( + pub(super) fn obligations_for_self_ty<'b>( &'b self, self_ty: ty::TyVid, ) -> impl Iterator, traits::PredicateObligation<'tcx>)> @@ -3918,19 +999,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // code is looking for a self type of a unresolved // inference variable. ty::PredicateAtom::ClosureKind(..) => None, + ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } }) .filter(move |(tr, _)| self.self_type_matches_expected_vid(*tr, ty_var_root)) } - fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { + pub(super) fn type_var_is_sized(&self, self_ty: ty::TyVid) -> bool { self.obligations_for_self_ty(self_ty) .any(|(tr, _)| Some(tr.def_id()) == self.tcx.lang_items().sized_trait()) } /// Generic function that factors out common logic from function calls, /// method calls and overloaded operators. - fn check_argument_types( + pub(super) fn check_argument_types( &self, sp: Span, expr: &'tcx hir::Expr<'tcx>, @@ -4042,7 +1124,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let formal_tys = if tuple_arguments == TupleArguments { let tuple_type = self.structurally_resolved_type(sp, fn_inputs[0]); - match tuple_type.kind { + match tuple_type.kind() { ty::Tuple(arg_types) if arg_types.len() != args.len() => { param_count_error(arg_types.len(), args.len(), "E0057", false, false); expected_arg_tys = vec![]; @@ -4050,7 +1132,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ty::Tuple(arg_types) => { expected_arg_tys = match expected_arg_tys.get(0) { - Some(&ty) => match ty.kind { + Some(&ty) => match ty.kind() { ty::Tuple(ref tys) => tys.iter().map(|k| k.expect_ty()).collect(), _ => vec![], }, @@ -4195,7 +1277,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // There are a few types which get autopromoted when passed via varargs // in C but we just error out instead and require explicit casts. let arg_ty = self.structurally_resolved_type(arg.span, arg_ty); - match arg_ty.kind { + match arg_ty.kind() { ty::Float(ast::FloatTy::F32) => { variadic_error(tcx.sess, arg.span, arg_ty, "c_double"); } @@ -4216,7 +1298,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn err_args(&self, len: usize) -> Vec> { + pub(super) fn err_args(&self, len: usize) -> Vec> { vec![self.tcx.ty_error(); len] } @@ -4266,11 +1348,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } }) - .collect::>(); + .collect::>(); // Both checked and coerced types could have matched, thus we need to remove // duplicates. - referenced_in.sort(); + + // We sort primitive type usize here and can use unstable sort + referenced_in.sort_unstable(); referenced_in.dedup(); if let (Some(ref_in), None) = (referenced_in.pop(), referenced_in.pop()) { @@ -4332,7 +1416,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } // AST fragment checking - fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { + pub(super) fn check_lit(&self, lit: &hir::Lit, expected: Expectation<'tcx>) -> Ty<'tcx> { let tcx = self.tcx; match lit.node { @@ -4345,7 +1429,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ast::LitKind::Int(_, ast::LitIntType::Signed(t)) => tcx.mk_mach_int(t), ast::LitKind::Int(_, ast::LitIntType::Unsigned(t)) => tcx.mk_mach_uint(t), ast::LitKind::Int(_, ast::LitIntType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Int(_) | ty::Uint(_) => Some(ty), ty::Char => Some(tcx.types.u8), ty::RawPtr(..) => Some(tcx.types.usize), @@ -4356,7 +1440,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } ast::LitKind::Float(_, ast::LitFloatType::Suffixed(t)) => tcx.mk_mach_float(t), ast::LitKind::Float(_, ast::LitFloatType::Unsuffixed) => { - let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind { + let opt_ty = expected.to_option(self).and_then(|ty| match ty.kind() { ty::Float(_) => Some(ty), _ => None, }); @@ -4369,7 +1453,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Unifies the output type with the expected type early, for more coercions /// and forward type information on the input expressions. - fn expected_inputs_for_expected_output( + pub(super) fn expected_inputs_for_expected_output( &self, call_span: Span, expected_ret: Expectation<'tcx>, @@ -4434,12 +1518,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.set_tainted_by_errors(); return None; } - Res::Def(DefKind::Variant, _) => match ty.kind { + Res::Def(DefKind::Variant, _) => match ty.kind() { ty::Adt(adt, substs) => Some((adt.variant_of_res(def), adt.did, substs)), _ => bug!("unexpected type: {:?}", ty), }, Res::Def(DefKind::Struct | DefKind::Union | DefKind::TyAlias | DefKind::AssocTy, _) - | Res::SelfTy(..) => match ty.kind { + | Res::SelfTy(..) => match ty.kind() { ty::Adt(adt, substs) if !adt.is_enum() => { Some((adt.non_enum_variant(), adt.did, substs)) } @@ -4511,7 +1595,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn resolve_lang_item_path( + pub(super) fn resolve_lang_item_path( &self, lang_item: hir::LangItem, span: Span, @@ -4661,7 +1745,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { + pub(super) fn suggest_semicolon_at_end(&self, span: Span, err: &mut DiagnosticBuilder<'_>) { err.span_suggestion_short( span.shrink_to_hi(), "consider using a semicolon here", @@ -4754,7 +1838,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { expr.span } - fn check_block_with_expected( + pub(super) fn check_block_with_expected( &self, blk: &'tcx hir::Block<'tcx>, expected: Expectation<'tcx>, @@ -4905,7 +1989,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Given a function `Node`, return its `FnDecl` if it exists, or `None` otherwise. - fn get_node_fn_decl(&self, node: Node<'tcx>) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { + pub(super) fn get_node_fn_decl( + &self, + node: Node<'tcx>, + ) -> Option<(&'tcx hir::FnDecl<'tcx>, Ident, bool)> { match node { Node::Item(&hir::Item { ident, kind: hir::ItemKind::Fn(ref sig, ..), .. }) => { // This is less than ideal, it will not suggest a return type span on any @@ -4976,7 +2063,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { found: Ty<'tcx>, ) -> bool { let hir = self.tcx.hir(); - let (def_id, sig) = match found.kind { + let (def_id, sig) = match *found.kind() { ty::FnDef(def_id, _) => (def_id, found.fn_sig(self.tcx)), ty::Closure(def_id, substs) => (def_id, substs.as_closure().sig()), _ => return false, @@ -5109,7 +2196,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some((sp, msg, suggestion, applicability)) = self.check_ref(expr, found, expected) { err.span_suggestion(sp, msg, suggestion, applicability); } else if let (ty::FnDef(def_id, ..), true) = - (&found.kind, self.suggest_fn_call(err, expr, expected, found)) + (&found.kind(), self.suggest_fn_call(err, expr, expected, found)) { if let Some(sp) = self.tcx.hir().span_if_local(*def_id) { let sp = self.sess().source_map().guess_head_span(sp); @@ -5162,7 +2249,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// When encountering the expected boxed value allocated in the stack, suggest allocating it /// in the heap by calling `Box::new()`. - fn suggest_boxing_when_appropriate( + pub(super) fn suggest_boxing_when_appropriate( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5196,7 +2283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn note_internal_mutation_in_method( + pub(super) fn note_internal_mutation_in_method( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5242,7 +2329,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// When encountering an `impl Future` where `BoxFuture` is expected, suggest `Box::pin`. - fn suggest_calling_boxed_future_when_appropriate( + pub(super) fn suggest_calling_boxed_future_when_appropriate( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5256,7 +2343,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } let pin_did = self.tcx.lang_items().pin_type(); - match expected.kind { + 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, @@ -5268,7 +2355,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.can_coerce(new_found, expected), self.sess().source_map().span_to_snippet(expr.span), ) { - match found.kind { + match found.kind() { ty::Adt(def, _) if def.is_box() => { err.help("use `Box::pin`"); } @@ -5337,7 +2424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This routine checks if the return type is left as default, the method is not part of an /// `impl` block and that it isn't the `main` method. If so, it suggests setting the return /// type. - fn suggest_missing_return_type( + pub(super) fn suggest_missing_return_type( &self, err: &mut DiagnosticBuilder<'_>, fn_decl: &hir::FnDecl<'_>, @@ -5376,7 +2463,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ty = AstConv::ast_ty_to_ty(self, ty); debug!("suggest_missing_return_type: return type {:?}", ty); debug!("suggest_missing_return_type: expected type {:?}", ty); - if ty.kind == expected.kind { + if ty.kind() == expected.kind() { err.span_label(sp, format!("expected `{}` because of return type", expected)); return true; } @@ -5403,7 +2490,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// This routine checks if the found type `T` implements `Future` where `U` is the /// expected type. If this is the case, and we are inside of an async body, it suggests adding /// `.await` to the tail of the expression. - fn suggest_missing_await( + pub(super) fn suggest_missing_await( &self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>, @@ -5466,7 +2553,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn suggest_missing_parentheses(&self, err: &mut DiagnosticBuilder<'_>, expr: &hir::Expr<'_>) { + pub(super) fn suggest_missing_parentheses( + &self, + err: &mut DiagnosticBuilder<'_>, + expr: &hir::Expr<'_>, + ) { let sp = self.tcx.sess.source_map().start_point(expr.span); if let Some(sp) = self.tcx.sess.parse_sess.ambiguous_block_expr_parse.borrow().get(&sp) { // `{ 42 } &&x` (#61475) or `{ 42 } && if x { 1 } else { 0 }` @@ -5474,13 +2565,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn note_need_for_fn_pointer( + pub(super) fn note_need_for_fn_pointer( &self, err: &mut DiagnosticBuilder<'_>, expected: Ty<'tcx>, found: Ty<'tcx>, ) { - let (sig, did, substs) = match (&expected.kind, &found.kind) { + let (sig, did, substs) = match (&expected.kind(), &found.kind()) { (ty::FnDef(did1, substs1), ty::FnDef(did2, substs2)) => { let sig1 = self.tcx.fn_sig(*did1).subst(self.tcx, substs1); let sig2 = self.tcx.fn_sig(*did2).subst(self.tcx, substs2); @@ -5538,7 +2629,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn could_remove_semicolon( + pub(super) fn could_remove_semicolon( &self, blk: &'tcx hir::Block<'tcx>, expected_ty: Ty<'tcx>, @@ -5551,7 +2642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { _ => return None, }; let last_expr_ty = self.node_ty(last_expr.hir_id); - if matches!(last_expr_ty.kind, ty::Error(_)) + if matches!(last_expr_ty.kind(), ty::Error(_)) || self.can_sub(self.param_env, last_expr_ty, expected_ty).is_err() { return None; @@ -5680,7 +2771,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (res, self_ctor_substs) = if let Res::SelfCtor(impl_def_id) = res { let ty = self.normalize_ty(span, tcx.at(span).type_of(impl_def_id)); - match ty.kind { + match *ty.kind() { ty::Adt(adt_def, substs) if adt_def.has_ctor() => { let variant = adt_def.non_enum_variant(); let ctor_def_id = variant.ctor_def_id.unwrap(); @@ -5900,7 +2991,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ty } else { if !self.is_tainted_by_errors() { - self.need_type_info_err((**self).body_id, sp, ty, E0282) + self.emit_inference_failure_err((**self).body_id, sp, ty.into(), E0282) .note("type must be known at this point") .emit(); } @@ -5910,7 +3001,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } - fn with_breakable_ctxt R, R>( + pub(super) fn with_breakable_ctxt R, R>( &self, id: hir::HirId, ctxt: BreakableCtxt<'tcx>, @@ -5935,7 +3026,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Instantiate a QueryResponse in a probe context, without a /// good ObligationCause. - fn probe_instantiate_query_response( + pub(super) fn probe_instantiate_query_response( &self, span: Span, original_values: &OriginalQueryValues<'tcx>, @@ -5950,7 +3041,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } /// Returns `true` if an expression is contained inside the LHS of an assignment expression. - fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { + pub(super) fn expr_in_place(&self, mut expr_id: hir::HirId) -> bool { let mut contained_in_place = false; while let hir::Node::Expr(parent_expr) = @@ -5971,70 +3062,139 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { contained_in_place } } +impl<'a, 'tcx> Deref for FnCtxt<'a, 'tcx> { + type Target = Inherited<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.inh + } +} -fn check_type_params_are_used<'tcx>(tcx: TyCtxt<'tcx>, generics: &ty::Generics, ty: Ty<'tcx>) { - debug!("check_type_params_are_used(generics={:?}, ty={:?})", generics, ty); - - assert_eq!(generics.parent, None); - - if generics.own_counts().types == 0 { - return; +impl<'a, 'tcx> AstConv<'tcx> for FnCtxt<'a, 'tcx> { + fn tcx<'b>(&'b self) -> TyCtxt<'tcx> { + self.tcx } - let mut params_used = BitSet::new_empty(generics.params.len()); - - if ty.references_error() { - // If there is already another error, do not emit - // an error for not using a type parameter. - assert!(tcx.sess.has_errors()); - return; + fn item_def_id(&self) -> Option { + None } - for leaf in ty.walk() { - if let GenericArgKind::Type(leaf_ty) = leaf.unpack() { - if let ty::Param(param) = leaf_ty.kind { - debug!("found use of ty param {:?}", param); - params_used.insert(param.index); - } + fn default_constness_for_trait_bounds(&self) -> hir::Constness { + // FIXME: refactor this into a method + let node = self.tcx.hir().get(self.body_id); + if let Some(fn_like) = FnLikeNode::from_node(node) { + fn_like.constness() + } else { + hir::Constness::NotConst } } - for param in &generics.params { - if !params_used.contains(param.index) { - if let ty::GenericParamDefKind::Type { .. } = param.kind { - let span = tcx.def_span(param.def_id); - struct_span_err!( - tcx.sess, - span, - E0091, - "type parameter `{}` is unused", - param.name, - ) - .span_label(span, "unused type parameter") - .emit(); - } + fn get_type_parameter_bounds(&self, _: Span, def_id: DefId) -> ty::GenericPredicates<'tcx> { + let tcx = self.tcx; + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let item_id = tcx.hir().ty_param_owner(hir_id); + let item_def_id = tcx.hir().local_def_id(item_id); + let generics = tcx.generics_of(item_def_id); + let index = generics.param_def_id_to_index[&def_id]; + ty::GenericPredicates { + parent: None, + predicates: tcx.arena.alloc_from_iter( + self.param_env.caller_bounds().iter().filter_map(|predicate| { + match predicate.skip_binders() { + ty::PredicateAtom::Trait(data, _) if data.self_ty().is_param(index) => { + // HACK(eddyb) should get the original `Span`. + let span = tcx.def_span(def_id); + Some((predicate, span)) + } + _ => None, + } + }), + ), } } -} -fn fatally_break_rust(sess: &Session) { - let handler = sess.diagnostic(); - handler.span_bug_no_panic( - MultiSpan::new(), - "It looks like you're trying to break rust; would you like some ICE?", - ); - handler.note_without_error("the compiler expectedly panicked. this is a feature."); - handler.note_without_error( - "we would appreciate a joke overview: \ - https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", - ); - handler.note_without_error(&format!( - "rustc {} running on {}", - option_env!("CFG_VERSION").unwrap_or("unknown_version"), - config::host_triple(), - )); -} + fn re_infer(&self, def: Option<&ty::GenericParamDef>, span: Span) -> Option> { + let v = match def { + Some(def) => infer::EarlyBoundRegion(span, def.name), + None => infer::MiscVariable(span), + }; + Some(self.next_region_var(v)) + } -fn potentially_plural_count(count: usize, word: &str) -> String { - format!("{} {}{}", count, word, pluralize!(count)) + fn allow_ty_infer(&self) -> bool { + true + } + + fn ty_infer(&self, param: Option<&ty::GenericParamDef>, span: Span) -> Ty<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Type(ty) = self.var_for_def(span, param).unpack() { + return ty; + } + unreachable!() + } else { + self.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }) + } + } + + fn ct_infer( + &self, + ty: Ty<'tcx>, + param: Option<&ty::GenericParamDef>, + span: Span, + ) -> &'tcx Const<'tcx> { + if let Some(param) = param { + if let GenericArgKind::Const(ct) = self.var_for_def(span, param).unpack() { + return ct; + } + unreachable!() + } else { + self.next_const_var( + ty, + ConstVariableOrigin { kind: ConstVariableOriginKind::ConstInference, span }, + ) + } + } + + fn projected_ty_from_poly_trait_ref( + &self, + span: Span, + item_def_id: DefId, + item_segment: &hir::PathSegment<'_>, + poly_trait_ref: ty::PolyTraitRef<'tcx>, + ) -> Ty<'tcx> { + let (trait_ref, _) = self.replace_bound_vars_with_fresh_vars( + span, + infer::LateBoundRegionConversionTime::AssocTypeProjection(item_def_id), + &poly_trait_ref, + ); + + let item_substs = >::create_substs_for_associated_item( + self, + self.tcx, + span, + item_def_id, + item_segment, + trait_ref.substs, + ); + + self.tcx().mk_projection(item_def_id, item_substs) + } + + fn normalize_ty(&self, span: Span, ty: Ty<'tcx>) -> Ty<'tcx> { + if ty.has_escaping_bound_vars() { + ty // FIXME: normalization and escaping regions + } else { + self.normalize_associated_types_in(span, &ty) + } + } + + fn set_tainted_by_errors(&self) { + self.infcx.set_tainted_by_errors() + } + + fn record_ty(&self, hir_id: hir::HirId, ty: Ty<'tcx>, _span: Span) { + self.write_ty(hir_id, ty) + } } diff --git a/compiler/rustc_typeck/src/check/gather_locals.rs b/compiler/rustc_typeck/src/check/gather_locals.rs new file mode 100644 index 0000000000..1d505cfa69 --- /dev/null +++ b/compiler/rustc_typeck/src/check/gather_locals.rs @@ -0,0 +1,120 @@ +use crate::check::{FnCtxt, LocalTy, UserType}; +use rustc_hir as hir; +use rustc_hir::intravisit::{self, NestedVisitorMap, Visitor}; +use rustc_hir::PatKind; +use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; +use rustc_middle::ty::Ty; +use rustc_span::Span; +use rustc_trait_selection::traits; + +pub(super) struct GatherLocalsVisitor<'a, 'tcx> { + fcx: &'a FnCtxt<'a, 'tcx>, + parent_id: hir::HirId, +} + +impl<'a, 'tcx> GatherLocalsVisitor<'a, 'tcx> { + pub(super) fn new(fcx: &'a FnCtxt<'a, 'tcx>, parent_id: hir::HirId) -> Self { + Self { fcx, parent_id } + } + + fn assign(&mut self, span: Span, nid: hir::HirId, ty_opt: Option>) -> Ty<'tcx> { + match ty_opt { + None => { + // Infer the variable's type. + let var_ty = self.fcx.next_ty_var(TypeVariableOrigin { + kind: TypeVariableOriginKind::TypeInference, + span, + }); + self.fcx + .locals + .borrow_mut() + .insert(nid, LocalTy { decl_ty: var_ty, revealed_ty: var_ty }); + var_ty + } + Some(typ) => { + // Take type that the user specified. + self.fcx.locals.borrow_mut().insert(nid, typ); + typ.revealed_ty + } + } + } +} + +impl<'a, 'tcx> Visitor<'tcx> for GatherLocalsVisitor<'a, 'tcx> { + type Map = intravisit::ErasedMap<'tcx>; + + fn nested_visit_map(&mut self) -> NestedVisitorMap { + NestedVisitorMap::None + } + + // Add explicitly-declared locals. + fn visit_local(&mut self, local: &'tcx hir::Local<'tcx>) { + let local_ty = match local.ty { + Some(ref ty) => { + let o_ty = self.fcx.to_ty(&ty); + + let revealed_ty = if self.fcx.tcx.features().impl_trait_in_bindings { + self.fcx.instantiate_opaque_types_from_value(self.parent_id, &o_ty, ty.span) + } else { + o_ty + }; + + let c_ty = self + .fcx + .inh + .infcx + .canonicalize_user_type_annotation(&UserType::Ty(revealed_ty)); + debug!( + "visit_local: ty.hir_id={:?} o_ty={:?} revealed_ty={:?} c_ty={:?}", + ty.hir_id, o_ty, revealed_ty, c_ty + ); + self.fcx + .typeck_results + .borrow_mut() + .user_provided_types_mut() + .insert(ty.hir_id, c_ty); + + Some(LocalTy { decl_ty: o_ty, revealed_ty }) + } + None => None, + }; + self.assign(local.span, local.hir_id, local_ty); + + debug!( + "local variable {:?} is assigned type {}", + local.pat, + self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&local.hir_id).unwrap().decl_ty) + ); + intravisit::walk_local(self, local); + } + + // Add pattern bindings. + fn visit_pat(&mut self, p: &'tcx hir::Pat<'tcx>) { + if let PatKind::Binding(_, _, ident, _) = p.kind { + let var_ty = self.assign(p.span, p.hir_id, None); + + if !self.fcx.tcx.features().unsized_locals { + self.fcx.require_type_is_sized(var_ty, p.span, traits::VariableType(p.hir_id)); + } + + debug!( + "pattern binding {} is assigned to {} with type {:?}", + ident, + self.fcx.ty_to_string(&*self.fcx.locals.borrow().get(&p.hir_id).unwrap().decl_ty), + var_ty + ); + } + intravisit::walk_pat(self, p); + } + + // Don't descend into the bodies of nested closures. + fn visit_fn( + &mut self, + _: intravisit::FnKind<'tcx>, + _: &'tcx hir::FnDecl<'tcx>, + _: hir::BodyId, + _: Span, + _: hir::HirId, + ) { + } +} diff --git a/src/librustc_typeck/check/generator_interior.rs b/compiler/rustc_typeck/src/check/generator_interior.rs similarity index 100% rename from src/librustc_typeck/check/generator_interior.rs rename to compiler/rustc_typeck/src/check/generator_interior.rs diff --git a/compiler/rustc_typeck/src/check/inherited.rs b/compiler/rustc_typeck/src/check/inherited.rs new file mode 100644 index 0000000000..7e580485c3 --- /dev/null +++ b/compiler/rustc_typeck/src/check/inherited.rs @@ -0,0 +1,167 @@ +use super::callee::DeferredCallResolution; +use super::MaybeInProgressTables; + +use rustc_data_structures::fx::FxHashMap; +use rustc_hir as hir; +use rustc_hir::def_id::{DefIdMap, LocalDefId}; +use rustc_hir::HirIdMap; +use rustc_infer::infer; +use rustc_infer::infer::{InferCtxt, InferOk, TyCtxtInferExt}; +use rustc_middle::ty::fold::TypeFoldable; +use rustc_middle::ty::{self, Ty, TyCtxt}; +use rustc_span::{self, Span}; +use rustc_trait_selection::infer::InferCtxtExt as _; +use rustc_trait_selection::opaque_types::OpaqueTypeDecl; +use rustc_trait_selection::traits::{self, TraitEngine, TraitEngineExt}; + +use std::cell::RefCell; +use std::ops::Deref; + +/// Closures defined within the function. For example: +/// +/// fn foo() { +/// bar(move|| { ... }) +/// } +/// +/// Here, the function `foo()` and the closure passed to +/// `bar()` will each have their own `FnCtxt`, but they will +/// share the inherited fields. +pub struct Inherited<'a, 'tcx> { + pub(super) infcx: InferCtxt<'a, 'tcx>, + + pub(super) typeck_results: super::MaybeInProgressTables<'a, 'tcx>, + + pub(super) locals: RefCell>>, + + pub(super) fulfillment_cx: RefCell>>, + + // Some additional `Sized` obligations badly affect type inference. + // These obligations are added in a later stage of typeck. + pub(super) deferred_sized_obligations: + RefCell, Span, traits::ObligationCauseCode<'tcx>)>>, + + // When we process a call like `c()` where `c` is a closure type, + // we may not have decided yet whether `c` is a `Fn`, `FnMut`, or + // `FnOnce` closure. In that case, we defer full resolution of the + // call until upvar inference can kick in and make the + // decision. We keep these deferred resolutions grouped by the + // def-id of the closure, so that once we decide, we can easily go + // back and process them. + pub(super) deferred_call_resolutions: RefCell>>>, + + pub(super) deferred_cast_checks: RefCell>>, + + pub(super) deferred_generator_interiors: + RefCell, hir::GeneratorKind)>>, + + // Opaque types found in explicit return types and their + // associated fresh inference variable. Writeback resolves these + // variables to get the concrete type, which can be used to + // 'de-opaque' OpaqueTypeDecl, after typeck is done with all functions. + pub(super) opaque_types: RefCell>>, + + /// A map from inference variables created from opaque + /// type instantiations (`ty::Infer`) to the actual opaque + /// type (`ty::Opaque`). Used during fallback to map unconstrained + /// opaque type inference variables to their corresponding + /// opaque type. + pub(super) opaque_types_vars: RefCell, Ty<'tcx>>>, + + pub(super) body_id: Option, +} + +impl<'a, 'tcx> Deref for Inherited<'a, 'tcx> { + type Target = InferCtxt<'a, 'tcx>; + fn deref(&self) -> &Self::Target { + &self.infcx + } +} + +/// Helper type of a temporary returned by `Inherited::build(...)`. +/// Necessary because we can't write the following bound: +/// `F: for<'b, 'tcx> where 'tcx FnOnce(Inherited<'b, 'tcx>)`. +pub struct InheritedBuilder<'tcx> { + infcx: infer::InferCtxtBuilder<'tcx>, + def_id: LocalDefId, +} + +impl Inherited<'_, 'tcx> { + pub fn build(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> InheritedBuilder<'tcx> { + let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; + + InheritedBuilder { + infcx: tcx.infer_ctxt().with_fresh_in_progress_typeck_results(hir_owner), + def_id, + } + } +} + +impl<'tcx> InheritedBuilder<'tcx> { + pub fn enter(&mut self, f: F) -> R + where + F: for<'a> FnOnce(Inherited<'a, 'tcx>) -> R, + { + let def_id = self.def_id; + self.infcx.enter(|infcx| f(Inherited::new(infcx, def_id))) + } +} + +impl Inherited<'a, 'tcx> { + pub(super) fn new(infcx: InferCtxt<'a, 'tcx>, def_id: LocalDefId) -> Self { + let tcx = infcx.tcx; + let item_id = tcx.hir().local_def_id_to_hir_id(def_id); + let body_id = tcx.hir().maybe_body_owned_by(item_id); + + Inherited { + typeck_results: MaybeInProgressTables { + maybe_typeck_results: infcx.in_progress_typeck_results, + }, + infcx, + fulfillment_cx: RefCell::new(TraitEngine::new(tcx)), + locals: RefCell::new(Default::default()), + deferred_sized_obligations: RefCell::new(Vec::new()), + deferred_call_resolutions: RefCell::new(Default::default()), + deferred_cast_checks: RefCell::new(Vec::new()), + deferred_generator_interiors: RefCell::new(Vec::new()), + opaque_types: RefCell::new(Default::default()), + opaque_types_vars: RefCell::new(Default::default()), + body_id, + } + } + + pub(super) fn register_predicate(&self, obligation: traits::PredicateObligation<'tcx>) { + debug!("register_predicate({:?})", obligation); + if obligation.has_escaping_bound_vars() { + span_bug!(obligation.cause.span, "escaping bound vars in predicate {:?}", obligation); + } + self.fulfillment_cx.borrow_mut().register_predicate_obligation(self, obligation); + } + + pub(super) fn register_predicates(&self, obligations: I) + where + I: IntoIterator>, + { + for obligation in obligations { + self.register_predicate(obligation); + } + } + + pub(super) fn register_infer_ok_obligations(&self, infer_ok: InferOk<'tcx, T>) -> T { + self.register_predicates(infer_ok.obligations); + infer_ok.value + } + + pub(super) fn normalize_associated_types_in( + &self, + span: Span, + body_id: hir::HirId, + param_env: ty::ParamEnv<'tcx>, + value: &T, + ) -> T + where + T: TypeFoldable<'tcx>, + { + let ok = self.partially_normalize_associated_types_in(span, body_id, param_env, value); + self.register_infer_ok_obligations(ok) + } +} diff --git a/src/librustc_typeck/check/intrinsic.rs b/compiler/rustc_typeck/src/check/intrinsic.rs similarity index 93% rename from src/librustc_typeck/check/intrinsic.rs rename to compiler/rustc_typeck/src/check/intrinsic.rs index 47cea8649e..2ee867c2dd 100644 --- a/src/librustc_typeck/check/intrinsic.rs +++ b/compiler/rustc_typeck/src/check/intrinsic.rs @@ -1,6 +1,10 @@ //! Type-checking for the rust-intrinsic and platform-intrinsic //! intrinsics that the compiler exposes. +use crate::errors::{ + SimdShuffleMissingLength, UnrecognizedAtomicOperation, UnrecognizedIntrinsicFunction, + WrongNumberOfTypeArgumentsToInstrinsic, +}; use crate::require_same_types; use rustc_errors::struct_span_err; @@ -41,17 +45,11 @@ fn equate_intrinsic_type<'tcx>( _ => bug!(), }; - struct_span_err!( - tcx.sess, + tcx.sess.emit_err(WrongNumberOfTypeArgumentsToInstrinsic { span, - E0094, - "intrinsic has wrong number of type \ - parameters: found {}, expected {}", - i_n_tps, - n_tps - ) - .span_label(span, format!("expected {} type parameter", n_tps)) - .emit(); + found: i_n_tps, + expected: n_tps, + }); return; } @@ -108,8 +106,8 @@ pub fn intrinsic_operation_unsafety(intrinsic: Symbol) -> hir::Unsafety { } } -/// Remember to add all intrinsics here, in librustc_codegen_llvm/intrinsic.rs, -/// and in libcore/intrinsics.rs +/// Remember to add all intrinsics here, in `compiler/rustc_codegen_llvm/src/intrinsic.rs`, +/// and in `library/core/src/intrinsics.rs`. pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { let param = |n| tcx.mk_ty_param(n, Symbol::intern(&format!("P{}", n))); let def_id = tcx.hir().local_def_id(it.hir_id).to_def_id(); @@ -146,15 +144,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { | "umin" => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], param(0)), "fence" | "singlethreadfence" => (0, Vec::new(), tcx.mk_unit()), op => { - struct_span_err!( - tcx.sess, - it.span, - E0092, - "unrecognized atomic operation function: `{}`", - op - ) - .span_label(it.span, "unrecognized atomic operation") - .emit(); + tcx.sess.emit_err(UnrecognizedAtomicOperation { span: it.span, op }); return; } }; @@ -380,15 +370,7 @@ pub fn check_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) { sym::nontemporal_store => (1, vec![tcx.mk_mut_ptr(param(0)), param(0)], tcx.mk_unit()), other => { - struct_span_err!( - tcx.sess, - it.span, - E0093, - "unrecognized intrinsic function: `{}`", - other, - ) - .span_label(it.span, "unrecognized intrinsic") - .emit(); + tcx.sess.emit_err(UnrecognizedIntrinsicFunction { span: it.span, name: other }); return; } }; @@ -468,14 +450,7 @@ pub fn check_platform_intrinsic_type(tcx: TyCtxt<'_>, it: &hir::ForeignItem<'_>) (2, params, param(1)) } Err(_) => { - struct_span_err!( - tcx.sess, - it.span, - E0439, - "invalid `simd_shuffle`, needs length: `{}`", - name - ) - .emit(); + tcx.sess.emit_err(SimdShuffleMissingLength { span: it.span, name }); return; } } diff --git a/src/librustc_typeck/check/method/confirm.rs b/compiler/rustc_typeck/src/check/method/confirm.rs similarity index 99% rename from src/librustc_typeck/check/method/confirm.rs rename to compiler/rustc_typeck/src/check/method/confirm.rs index 41e37ee975..fd2700b85e 100644 --- a/src/librustc_typeck/check/method/confirm.rs +++ b/compiler/rustc_typeck/src/check/method/confirm.rs @@ -137,7 +137,8 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { ) -> Ty<'tcx> { // Commit the autoderefs by calling `autoderef` again, but this // time writing the results into the various typeck results. - let mut autoderef = self.autoderef(self.span, unadjusted_self_ty); + let mut autoderef = + self.autoderef_overloaded_span(self.span, unadjusted_self_ty, self.call_expr.span); let (_, n) = match autoderef.nth(pick.autoderefs) { Some(n) => n, None => { @@ -269,7 +270,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { self.fcx .autoderef(self.span, self_ty) .include_raw_pointers() - .find_map(|(ty, _)| match ty.kind { + .find_map(|(ty, _)| match ty.kind() { ty::Dynamic(ref data, ..) => Some(closure( self, ty, @@ -464,7 +465,7 @@ impl<'a, 'tcx> ConfirmContext<'a, 'tcx> { } _ => None, }) - .find_map(|(trait_pred, span)| match trait_pred.self_ty().kind { + .find_map(|(trait_pred, span)| match trait_pred.self_ty().kind() { ty::Dynamic(..) => Some(span), _ => None, }) diff --git a/src/librustc_typeck/check/method/mod.rs b/compiler/rustc_typeck/src/check/method/mod.rs similarity index 99% rename from src/librustc_typeck/check/method/mod.rs rename to compiler/rustc_typeck/src/check/method/mod.rs index c9a4df0317..84bc3979e1 100644 --- a/src/librustc_typeck/check/method/mod.rs +++ b/compiler/rustc_typeck/src/check/method/mod.rs @@ -207,7 +207,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(span) = result.illegal_sized_bound { let mut needs_mut = false; - if let ty::Ref(region, t_type, mutability) = self_ty.kind { + if let ty::Ref(region, t_type, mutability) = self_ty.kind() { let trait_type = self .tcx .mk_ref(region, ty::TypeAndMut { ty: t_type, mutbl: mutability.invert() }); @@ -424,7 +424,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let tcx = self.tcx; // Check if we have an enum variant. - if let ty::Adt(adt_def, _) = self_ty.kind { + if let ty::Adt(adt_def, _) = self_ty.kind() { if adt_def.is_enum() { let variant_def = adt_def .variants diff --git a/src/librustc_typeck/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs similarity index 98% rename from src/librustc_typeck/check/method/probe.rs rename to compiler/rustc_typeck/src/check/method/probe.rs index 7ac6681be1..c1ba29284d 100644 --- a/src/librustc_typeck/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -4,6 +4,7 @@ use super::NoMatchData; use super::{CandidateSource, ImplSource, TraitSource}; use crate::check::FnCtxt; +use crate::errors::MethodCallOnUnknownType; use crate::hir::def::DefKind; use crate::hir::def_id::DefId; @@ -11,7 +12,6 @@ use rustc_ast as ast; use rustc_ast::util::lev_distance::{find_best_match_for_name, lev_distance}; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::sync::Lrc; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def::Namespace; use rustc_infer::infer::canonical::OriginalQueryValues; @@ -376,14 +376,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // so we do a future-compat lint here for the 2015 edition // (see https://github.com/rust-lang/rust/issues/46906) if self.tcx.sess.rust_2018() { - struct_span_err!( - self.tcx.sess, - span, - E0699, - "the type of this value must be known to call a method on a raw pointer on \ - it" - ) - .emit(); + self.tcx.sess.emit_err(MethodCallOnUnknownType { span }); } else { self.tcx.struct_span_lint_hir( lint::builtin::TYVAR_BEHIND_RAW_POINTER, @@ -401,7 +394,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { .probe_instantiate_query_response(span, &orig_values, ty) .unwrap_or_else(|_| span_bug!(span, "instantiating {:?} failed?", ty)); let ty = self.structurally_resolved_type(span, ty.value); - assert!(matches!(ty.kind, ty::Error(_))); + assert!(matches!(ty.kind(), ty::Error(_))); return Err(MethodError::NoMatch(NoMatchData::new( Vec::new(), Vec::new(), @@ -453,9 +446,10 @@ fn method_autoderef_steps<'tcx>( tcx.infer_ctxt().enter_with_canonical(DUMMY_SP, &goal, |ref infcx, goal, inference_vars| { let ParamEnvAnd { param_env, value: self_ty } = goal; - let mut autoderef = Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty) - .include_raw_pointers() - .silence_errors(); + let mut autoderef = + Autoderef::new(infcx, param_env, hir::CRATE_HIR_ID, DUMMY_SP, self_ty, DUMMY_SP) + .include_raw_pointers() + .silence_errors(); let mut reached_raw_pointer = false; let mut steps: Vec<_> = autoderef .by_ref() @@ -469,7 +463,7 @@ fn method_autoderef_steps<'tcx>( from_unsafe_deref: reached_raw_pointer, unsize: false, }; - if let ty::RawPtr(_) = ty.kind { + if let ty::RawPtr(_) = ty.kind() { // all the subsequent steps will be from_unsafe_deref reached_raw_pointer = true; } @@ -478,7 +472,7 @@ fn method_autoderef_steps<'tcx>( .collect(); let final_ty = autoderef.final_ty(true); - let opt_bad_ty = match final_ty.kind { + let opt_bad_ty = match final_ty.kind() { ty::Infer(ty::TyVar(_)) | ty::Error(_) => Some(MethodAutoderefBadTy { reached_raw_pointer, ty: infcx @@ -587,7 +581,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { debug!("assemble_probe: self_ty={:?}", self_ty); let lang_items = self.tcx.lang_items(); - match self_ty.value.value.kind { + match *self_ty.value.value.kind() { ty::Dynamic(ref data, ..) => { if let Some(p) = data.principal() { // Subtle: we can't use `instantiate_query_response` here: using it will @@ -759,7 +753,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn assemble_inherent_candidates_from_object(&mut self, self_ty: Ty<'tcx>) { debug!("assemble_inherent_candidates_from_object(self_ty={:?})", self_ty); - let principal = match self_ty.kind { + let principal = match self_ty.kind() { ty::Dynamic(ref data, ..) => Some(data), _ => None, } @@ -806,7 +800,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { self.param_env.caller_bounds().iter().map(ty::Predicate::skip_binders).filter_map( |predicate| match predicate { ty::PredicateAtom::Trait(trait_predicate, _) => { - match trait_predicate.trait_ref.self_ty().kind { + match trait_predicate.trait_ref.self_ty().kind() { ty::Param(ref p) if *p == param_ty => { Some(ty::Binder::bind(trait_predicate.trait_ref)) } @@ -821,7 +815,8 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::TypeOutlives(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, }, ); @@ -1125,7 +1120,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { pick.autoderefs = step.autoderefs; // Insert a `&*` or `&mut *` if this is a reference type: - if let ty::Ref(_, _, mutbl) = step.self_ty.value.value.kind { + if let ty::Ref(_, _, mutbl) = *step.self_ty.value.value.kind() { pick.autoderefs += 1; pick.autoref = Some(mutbl); } @@ -1311,7 +1306,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .at(&ObligationCause::dummy(), self.param_env) .sup(candidate.xform_self_ty, self_ty); match self.select_trait_candidate(trait_ref) { - Ok(Some(traits::ImplSource::ImplSourceUserDefined(ref impl_data))) => { + Ok(Some(traits::ImplSource::UserDefined(ref impl_data))) => { // If only a single impl matches, make the error message point // to that impl. ImplSource(impl_data.impl_def_id) diff --git a/src/librustc_typeck/check/method/suggest.rs b/compiler/rustc_typeck/src/check/method/suggest.rs similarity index 95% rename from src/librustc_typeck/check/method/suggest.rs rename to compiler/rustc_typeck/src/check/method/suggest.rs index 896bfc0795..e33a4e98c5 100644 --- a/src/librustc_typeck/check/method/suggest.rs +++ b/compiler/rustc_typeck/src/check/method/suggest.rs @@ -21,6 +21,7 @@ use rustc_span::symbol::{kw, sym, Ident}; use rustc_span::{source_map, FileName, Span}; use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; use rustc_trait_selection::traits::Obligation; +use rustc_trait_selection::traits::SelectionContext; use std::cmp::Ordering; @@ -30,7 +31,7 @@ use super::{CandidateSource, MethodError, NoMatchData}; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn is_fn_ty(&self, ty: Ty<'tcx>, span: Span) -> bool { let tcx = self.tcx; - match ty.kind { + match ty.kind() { // Not all of these (e.g., unsafe fns) implement `FnOnce`, // so we look for these beforehand. ty::Closure(..) | ty::FnDef(..) | ty::FnPtr(_) => true, @@ -392,6 +393,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { actual.prefix_string(), ty_str, ); + if let Mode::MethodCall = mode { + if let SelfSource::MethodCall(call) = source { + self.suggest_await_before_method( + &mut err, item_name, actual, call, span, + ); + } + } if let Some(span) = tcx.sess.confused_type_with_std_module.borrow().get(&span) { @@ -405,7 +413,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } } - if let ty::RawPtr(_) = &actual.kind { + if let ty::RawPtr(_) = &actual.kind() { err.note( "try using `<*const T>::as_ref()` to get a reference to the \ type behind the pointer: https://doc.rust-lang.org/std/\ @@ -442,7 +450,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // give a helping note that it has to be called as `(x.f)(...)`. if let SelfSource::MethodCall(expr) = source { let field_receiver = - self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind { + self.autoderef(span, rcvr_ty).find_map(|(ty, _)| match ty.kind() { ty::Adt(def, substs) if !def.is_enum() => { let variant = &def.non_enum_variant(); self.tcx.find_field_index(item_name, variant).map(|index| { @@ -537,7 +545,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // original type that has the associated function for accurate suggestions. // (#61411) let ty = tcx.at(span).type_of(*impl_did); - match (&ty.peel_refs().kind, &actual.peel_refs().kind) { + match (&ty.peel_refs().kind(), &actual.peel_refs().kind()) { (ty::Adt(def, _), ty::Adt(def_actual, _)) if def == def_actual => { // Use `actual` as it will have more `substs` filled in. self.ty_to_value_string(actual.peel_refs()) @@ -575,9 +583,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { |self_ty: Ty<'tcx>, parent_pred: &ty::Predicate<'tcx>, obligation: &str| { // We don't care about regions here, so it's fine to skip the binder here. if let (ty::Param(_), ty::PredicateAtom::Trait(p, _)) = - (&self_ty.kind, parent_pred.skip_binders()) + (self_ty.kind(), parent_pred.skip_binders()) { - if let ty::Adt(def, _) = p.trait_ref.self_ty().kind { + if let ty::Adt(def, _) = p.trait_ref.self_ty().kind() { let node = def.did.as_local().map(|def_id| { self.tcx .hir() @@ -607,7 +615,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "doesn't satisfy `{}`", if obligation.len() > 50 { quiet } else { obligation } ); - match &self_ty.kind { + match &self_ty.kind() { // Point at the type that couldn't satisfy the bound. ty::Adt(def, _) => bound_spans.push((def_span(def.did), msg)), // Point at the trait object that couldn't satisfy the bound. @@ -829,7 +837,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); self.suggest_use_candidates(&mut err, help, candidates); } - if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind { + if let ty::Ref(region, t_type, mutability) = rcvr_ty.kind() { if needs_mut { let trait_type = self.tcx.mk_ref( region, @@ -848,12 +856,63 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Print out the type for use in value namespace. fn ty_to_value_string(&self, ty: Ty<'tcx>) -> String { - match ty.kind { + match ty.kind() { ty::Adt(def, substs) => format!("{}", ty::Instance::new(def.did, substs)), _ => self.ty_to_string(ty), } } + fn suggest_await_before_method( + &self, + err: &mut DiagnosticBuilder<'_>, + item_name: Ident, + ty: Ty<'tcx>, + call: &hir::Expr<'_>, + span: Span, + ) { + if let ty::Opaque(def_id, _) = *ty.kind() { + let future_trait = self.tcx.require_lang_item(LangItem::Future, None); + // Future::Output + let item_def_id = self + .tcx + .associated_items(future_trait) + .in_definition_order() + .next() + .unwrap() + .def_id; + + let projection_ty = self.tcx.projection_ty_from_predicates((def_id, item_def_id)); + let cause = self.misc(span); + let mut selcx = SelectionContext::new(&self.infcx); + let mut obligations = vec![]; + if let Some(projection_ty) = projection_ty { + let normalized_ty = rustc_trait_selection::traits::normalize_projection_type( + &mut selcx, + self.param_env, + projection_ty, + cause, + 0, + &mut obligations, + ); + debug!( + "suggest_await_before_method: normalized_ty={:?}, ty_kind={:?}", + self.resolve_vars_if_possible(&normalized_ty), + normalized_ty.kind(), + ); + let method_exists = self.method_exists(item_name, normalized_ty, call.hir_id, true); + debug!("suggest_await_before_method: is_method_exist={}", method_exists); + if method_exists { + err.span_suggestion_verbose( + span.shrink_to_lo(), + "consider awaiting before this method call", + "await.".to_string(), + Applicability::MaybeIncorrect, + ); + } + } + } + } + fn suggest_use_candidates( &self, err: &mut DiagnosticBuilder<'_>, @@ -1030,9 +1089,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { candidates.sort_by(|a, b| a.cmp(b).reverse()); candidates.dedup(); - let param_type = match rcvr_ty.kind { + let param_type = match rcvr_ty.kind() { ty::Param(param) => Some(param), - ty::Ref(_, ty, _) => match ty.kind { + ty::Ref(_, ty, _) => match ty.kind() { ty::Param(param) => Some(param), _ => None, }, @@ -1184,7 +1243,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// autoderefs of `rcvr_ty`. fn type_derefs_to_local(&self, span: Span, rcvr_ty: Ty<'tcx>, source: SelfSource<'_>) -> bool { fn is_local(ty: Ty<'_>) -> bool { - match ty.kind { + match ty.kind() { ty::Adt(def, _) => def.did.is_local(), ty::Foreign(did) => did.is_local(), diff --git a/compiler/rustc_typeck/src/check/mod.rs b/compiler/rustc_typeck/src/check/mod.rs new file mode 100644 index 0000000000..97172d391b --- /dev/null +++ b/compiler/rustc_typeck/src/check/mod.rs @@ -0,0 +1,1151 @@ +/*! + +# typeck: check phase + +Within the check phase of type check, we check each item one at a time +(bodies of function expressions are checked as part of the containing +function). Inference is used to supply types wherever they are unknown. + +By far the most complex case is checking the body of a function. This +can be broken down into several distinct phases: + +- gather: creates type variables to represent the type of each local + variable and pattern binding. + +- main: the main pass does the lion's share of the work: it + determines the types of all expressions, resolves + methods, checks for most invalid conditions, and so forth. In + some cases, where a type is unknown, it may create a type or region + variable and use that as the type of an expression. + + In the process of checking, various constraints will be placed on + these type variables through the subtyping relationships requested + through the `demand` module. The `infer` module is in charge + of resolving those constraints. + +- regionck: after main is complete, the regionck pass goes over all + types looking for regions and making sure that they did not escape + into places they are not in scope. This may also influence the + final assignments of the various region variables if there is some + flexibility. + +- writeback: writes the final types within a function body, replacing + type variables with their final inferred types. These final types + are written into the `tcx.node_types` table, which should *never* contain + any reference to a type variable. + +## Intermediate types + +While type checking a function, the intermediate types for the +expressions, blocks, and so forth contained within the function are +stored in `fcx.node_types` and `fcx.node_substs`. These types +may contain unresolved type variables. After type checking is +complete, the functions in the writeback module are used to take the +types from this table, resolve them, and then write them into their +permanent home in the type context `tcx`. + +This means that during inferencing you should use `fcx.write_ty()` +and `fcx.expr_ty()` / `fcx.node_ty()` to write/obtain the types of +nodes within the function. + +The types of top-level items, which never contain unbound type +variables, are stored directly into the `tcx` typeck_results. + +N.B., a type variable is not the same thing as a type parameter. A +type variable is rather an "instance" of a type parameter: that is, +given a generic function `fn foo(t: T)`: while checking the +function `foo`, the type `ty_param(0)` refers to the type `T`, which +is treated in abstract. When `foo()` is called, however, `T` will be +substituted for a fresh type variable `N`. This variable will +eventually be resolved to some concrete type (which might itself be +type parameter). + +*/ + +pub mod _match; +mod autoderef; +mod callee; +pub mod cast; +mod check; +mod closure; +pub mod coercion; +mod compare_method; +pub mod demand; +mod diverges; +pub mod dropck; +mod expectation; +mod expr; +mod fn_ctxt; +mod gather_locals; +mod generator_interior; +mod inherited; +pub mod intrinsic; +pub mod method; +mod op; +mod pat; +mod place_op; +mod regionck; +mod upvar; +mod wfcheck; +pub mod writeback; + +use check::{ + check_abi, check_fn, check_impl_item_well_formed, check_item_well_formed, check_mod_item_types, + check_trait_item_well_formed, +}; +pub use check::{check_item_type, check_wf_new}; +pub use diverges::Diverges; +pub use expectation::Expectation; +pub use fn_ctxt::FnCtxt; +pub use inherited::{Inherited, InheritedBuilder}; + +use crate::astconv::AstConv; +use crate::check::gather_locals::GatherLocalsVisitor; +use rustc_data_structures::fx::{FxHashMap, FxHashSet}; +use rustc_errors::{pluralize, struct_span_err, Applicability}; +use rustc_hir as hir; +use rustc_hir::def::Res; +use rustc_hir::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; +use rustc_hir::intravisit::Visitor; +use rustc_hir::itemlikevisit::ItemLikeVisitor; +use rustc_hir::{HirIdMap, Node}; +use rustc_index::bit_set::BitSet; +use rustc_index::vec::Idx; +use rustc_middle::ty::fold::{TypeFoldable, TypeFolder}; +use rustc_middle::ty::query::Providers; +use rustc_middle::ty::subst::GenericArgKind; +use rustc_middle::ty::subst::{InternalSubsts, Subst, SubstsRef}; +use rustc_middle::ty::WithConstness; +use rustc_middle::ty::{self, RegionKind, Ty, TyCtxt, UserType}; +use rustc_session::config; +use rustc_session::parse::feature_err; +use rustc_session::Session; +use rustc_span::source_map::DUMMY_SP; +use rustc_span::symbol::{kw, Ident}; +use rustc_span::{self, BytePos, MultiSpan, Span}; +use rustc_target::abi::VariantIdx; +use rustc_target::spec::abi::Abi; +use rustc_trait_selection::traits; +use rustc_trait_selection::traits::error_reporting::recursive_type_with_infinite_size_error; +use rustc_trait_selection::traits::error_reporting::suggestions::ReturnsVisitor; + +use std::cell::{Ref, RefCell, RefMut}; + +use crate::require_c_abi_if_c_variadic; +use crate::util::common::indenter; + +use self::coercion::DynamicCoerceMany; +pub use self::Expectation::*; + +#[macro_export] +macro_rules! type_error_struct { + ($session:expr, $span:expr, $typ:expr, $code:ident, $($message:tt)*) => ({ + if $typ.references_error() { + $session.diagnostic().struct_dummy() + } else { + rustc_errors::struct_span_err!($session, $span, $code, $($message)*) + } + }) +} + +/// The type of a local binding, including the revealed type for anon types. +#[derive(Copy, Clone, Debug)] +pub struct LocalTy<'tcx> { + decl_ty: Ty<'tcx>, + revealed_ty: Ty<'tcx>, +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq)] +pub enum Needs { + MutPlace, + None, +} + +impl Needs { + fn maybe_mut_place(m: hir::Mutability) -> Self { + match m { + hir::Mutability::Mut => Needs::MutPlace, + hir::Mutability::Not => Needs::None, + } + } +} + +#[derive(Copy, Clone)] +pub struct UnsafetyState { + pub def: hir::HirId, + pub unsafety: hir::Unsafety, + pub unsafe_push_count: u32, + from_fn: bool, +} + +impl UnsafetyState { + pub fn function(unsafety: hir::Unsafety, def: hir::HirId) -> UnsafetyState { + UnsafetyState { def, unsafety, unsafe_push_count: 0, from_fn: true } + } + + pub fn recurse(&mut self, blk: &hir::Block<'_>) -> UnsafetyState { + use hir::BlockCheckMode; + match self.unsafety { + // If this unsafe, then if the outer function was already marked as + // unsafe we shouldn't attribute the unsafe'ness to the block. This + // way the block can be warned about instead of ignoring this + // extraneous block (functions are never warned about). + hir::Unsafety::Unsafe if self.from_fn => *self, + + unsafety => { + let (unsafety, def, count) = match blk.rules { + BlockCheckMode::PushUnsafeBlock(..) => { + (unsafety, blk.hir_id, self.unsafe_push_count.checked_add(1).unwrap()) + } + BlockCheckMode::PopUnsafeBlock(..) => { + (unsafety, blk.hir_id, self.unsafe_push_count.checked_sub(1).unwrap()) + } + BlockCheckMode::UnsafeBlock(..) => { + (hir::Unsafety::Unsafe, blk.hir_id, self.unsafe_push_count) + } + BlockCheckMode::DefaultBlock => (unsafety, self.def, self.unsafe_push_count), + }; + UnsafetyState { def, unsafety, unsafe_push_count: count, from_fn: false } + } + } + } +} + +#[derive(Debug, Copy, Clone)] +pub enum PlaceOp { + Deref, + Index, +} + +pub struct BreakableCtxt<'tcx> { + may_break: bool, + + // this is `null` for loops where break with a value is illegal, + // such as `while`, `for`, and `while let` + coerce: Option>, +} + +pub struct EnclosingBreakables<'tcx> { + stack: Vec>, + by_id: HirIdMap, +} + +impl<'tcx> EnclosingBreakables<'tcx> { + fn find_breakable(&mut self, target_id: hir::HirId) -> &mut BreakableCtxt<'tcx> { + self.opt_find_breakable(target_id).unwrap_or_else(|| { + bug!("could not find enclosing breakable with id {}", target_id); + }) + } + + fn opt_find_breakable(&mut self, target_id: hir::HirId) -> Option<&mut BreakableCtxt<'tcx>> { + match self.by_id.get(&target_id) { + Some(ix) => Some(&mut self.stack[*ix]), + None => None, + } + } +} + +pub fn provide(providers: &mut Providers) { + method::provide(providers); + *providers = Providers { + typeck_item_bodies, + typeck_const_arg, + typeck, + diagnostic_only_typeck, + has_typeck_results, + adt_destructor, + used_trait_imports, + check_item_well_formed, + check_trait_item_well_formed, + check_impl_item_well_formed, + check_mod_item_types, + ..*providers + }; +} + +fn adt_destructor(tcx: TyCtxt<'_>, def_id: DefId) -> Option { + tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl) +} + +/// If this `DefId` is a "primary tables entry", returns +/// `Some((body_id, header, decl))` with information about +/// it's body-id, fn-header and fn-decl (if any). Otherwise, +/// returns `None`. +/// +/// If this function returns `Some`, then `typeck_results(def_id)` will +/// succeed; if it returns `None`, then `typeck_results(def_id)` may or +/// may not succeed. In some cases where this function returns `None` +/// (notably closures), `typeck_results(def_id)` would wind up +/// redirecting to the owning function. +fn primary_body_of( + tcx: TyCtxt<'_>, + id: hir::HirId, +) -> Option<(hir::BodyId, Option<&hir::Ty<'_>>, Option<&hir::FnHeader>, Option<&hir::FnDecl<'_>>)> { + match tcx.hir().get(id) { + Node::Item(item) => match item.kind { + hir::ItemKind::Const(ref ty, body) | hir::ItemKind::Static(ref ty, _, body) => { + Some((body, Some(ty), None, None)) + } + hir::ItemKind::Fn(ref sig, .., body) => { + Some((body, None, Some(&sig.header), Some(&sig.decl))) + } + _ => None, + }, + Node::TraitItem(item) => match item.kind { + hir::TraitItemKind::Const(ref ty, Some(body)) => Some((body, Some(ty), None, None)), + hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { + Some((body, None, Some(&sig.header), Some(&sig.decl))) + } + _ => None, + }, + Node::ImplItem(item) => match item.kind { + hir::ImplItemKind::Const(ref ty, body) => Some((body, Some(ty), None, None)), + hir::ImplItemKind::Fn(ref sig, body) => { + Some((body, None, Some(&sig.header), Some(&sig.decl))) + } + _ => None, + }, + Node::AnonConst(constant) => Some((constant.body, None, None, None)), + _ => None, + } +} + +fn has_typeck_results(tcx: TyCtxt<'_>, def_id: DefId) -> bool { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let outer_def_id = tcx.closure_base_def_id(def_id); + if outer_def_id != def_id { + return tcx.has_typeck_results(outer_def_id); + } + + if let Some(def_id) = def_id.as_local() { + let id = tcx.hir().local_def_id_to_hir_id(def_id); + primary_body_of(tcx, id).is_some() + } else { + false + } +} + +fn used_trait_imports(tcx: TyCtxt<'_>, def_id: LocalDefId) -> &FxHashSet { + &*tcx.typeck(def_id).used_trait_imports +} + +/// Inspects the substs of opaque types, replacing any inference variables +/// with proper generic parameter from the identity substs. +/// +/// This is run after we normalize the function signature, to fix any inference +/// variables introduced by the projection of associated types. This ensures that +/// any opaque types used in the signature continue to refer to generic parameters, +/// allowing them to be considered for defining uses in the function body +/// +/// For example, consider this code. +/// +/// ```rust +/// trait MyTrait { +/// type MyItem; +/// fn use_it(self) -> Self::MyItem +/// } +/// impl MyTrait for T where T: Iterator { +/// type MyItem = impl Iterator; +/// fn use_it(self) -> Self::MyItem { +/// self +/// } +/// } +/// ``` +/// +/// When we normalize the signature of `use_it` from the impl block, +/// we will normalize `Self::MyItem` to the opaque type `impl Iterator` +/// However, this projection result may contain inference variables, due +/// to the way that projection works. We didn't have any inference variables +/// in the signature to begin with - leaving them in will cause us to incorrectly +/// conclude that we don't have a defining use of `MyItem`. By mapping inference +/// variables back to the actual generic parameters, we will correctly see that +/// we have a defining use of `MyItem` +fn fixup_opaque_types<'tcx, T>(tcx: TyCtxt<'tcx>, val: &T) -> T +where + T: TypeFoldable<'tcx>, +{ + struct FixupFolder<'tcx> { + tcx: TyCtxt<'tcx>, + } + + impl<'tcx> TypeFolder<'tcx> for FixupFolder<'tcx> { + fn tcx<'a>(&'a self) -> TyCtxt<'tcx> { + self.tcx + } + + fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { + match *ty.kind() { + ty::Opaque(def_id, substs) => { + debug!("fixup_opaque_types: found type {:?}", ty); + // Here, we replace any inference variables that occur within + // the substs of an opaque type. By definition, any type occurring + // in the substs has a corresponding generic parameter, which is what + // we replace it with. + // This replacement is only run on the function signature, so any + // inference variables that we come across must be the rust of projection + // (there's no other way for a user to get inference variables into + // a function signature). + if ty.needs_infer() { + let new_substs = InternalSubsts::for_item(self.tcx, def_id, |param, _| { + let old_param = substs[param.index as usize]; + match old_param.unpack() { + GenericArgKind::Type(old_ty) => { + if let ty::Infer(_) = old_ty.kind() { + // Replace inference type with a generic parameter + self.tcx.mk_param_from_def(param) + } else { + old_param.fold_with(self) + } + } + GenericArgKind::Const(old_const) => { + if let ty::ConstKind::Infer(_) = old_const.val { + // This should never happen - we currently do not support + // 'const projections', e.g.: + // `impl MyTrait for T where ::MyConst == 25` + // which should be the only way for us to end up with a const inference + // variable after projection. If Rust ever gains support for this kind + // of projection, this should *probably* be changed to + // `self.tcx.mk_param_from_def(param)` + bug!( + "Found infer const: `{:?}` in opaque type: {:?}", + old_const, + ty + ); + } else { + old_param.fold_with(self) + } + } + GenericArgKind::Lifetime(old_region) => { + if let RegionKind::ReVar(_) = old_region { + self.tcx.mk_param_from_def(param) + } else { + old_param.fold_with(self) + } + } + } + }); + let new_ty = self.tcx.mk_opaque(def_id, new_substs); + debug!("fixup_opaque_types: new type: {:?}", new_ty); + new_ty + } else { + ty + } + } + _ => ty.super_fold_with(self), + } + } + } + + debug!("fixup_opaque_types({:?})", val); + val.fold_with(&mut FixupFolder { tcx }) +} + +fn typeck_const_arg<'tcx>( + tcx: TyCtxt<'tcx>, + (did, param_did): (LocalDefId, DefId), +) -> &ty::TypeckResults<'tcx> { + let fallback = move || tcx.type_of(param_did); + typeck_with_fallback(tcx, did, fallback) +} + +fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { + if let Some(param_did) = tcx.opt_const_param_of(def_id) { + tcx.typeck_const_arg((def_id, param_did)) + } else { + let fallback = move || tcx.type_of(def_id.to_def_id()); + typeck_with_fallback(tcx, def_id, fallback) + } +} + +/// Used only to get `TypeckResults` for type inference during error recovery. +/// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. +fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { + let fallback = move || { + let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); + tcx.ty_error_with_message(span, "diagnostic only typeck table used") + }; + typeck_with_fallback(tcx, def_id, fallback) +} + +fn typeck_with_fallback<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + fallback: impl Fn() -> Ty<'tcx> + 'tcx, +) -> &'tcx ty::TypeckResults<'tcx> { + // Closures' typeck results come from their outermost function, + // as they are part of the same "inference environment". + let outer_def_id = tcx.closure_base_def_id(def_id.to_def_id()).expect_local(); + if outer_def_id != def_id { + return tcx.typeck(outer_def_id); + } + + let id = tcx.hir().local_def_id_to_hir_id(def_id); + let span = tcx.hir().span(id); + + // Figure out what primary body this item has. + let (body_id, body_ty, fn_header, fn_decl) = primary_body_of(tcx, id).unwrap_or_else(|| { + span_bug!(span, "can't type-check body of {:?}", def_id); + }); + let body = tcx.hir().body(body_id); + + let typeck_results = Inherited::build(tcx, def_id).enter(|inh| { + let param_env = tcx.param_env(def_id); + let fcx = if let (Some(header), Some(decl)) = (fn_header, fn_decl) { + let fn_sig = if crate::collect::get_infer_ret_ty(&decl.output).is_some() { + let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); + AstConv::ty_of_fn( + &fcx, + header.unsafety, + header.abi, + decl, + &hir::Generics::empty(), + None, + ) + } else { + tcx.fn_sig(def_id) + }; + + check_abi(tcx, span, fn_sig.abi()); + + // 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); + let fn_sig = inh.normalize_associated_types_in( + body.value.span, + body_id.hir_id, + param_env, + &fn_sig, + ); + + let fn_sig = fixup_opaque_types(tcx, &fn_sig); + + let fcx = check_fn(&inh, param_env, fn_sig, decl, id, body, None).0; + fcx + } else { + let fcx = FnCtxt::new(&inh, param_env, body.value.hir_id); + let expected_type = body_ty + .and_then(|ty| match ty.kind { + hir::TyKind::Infer => Some(AstConv::ast_ty_to_ty(&fcx, ty)), + _ => None, + }) + .unwrap_or_else(fallback); + let expected_type = fcx.normalize_associated_types_in(body.value.span, &expected_type); + fcx.require_type_is_sized(expected_type, body.value.span, traits::ConstSized); + + let revealed_ty = if tcx.features().impl_trait_in_bindings { + fcx.instantiate_opaque_types_from_value(id, &expected_type, body.value.span) + } else { + expected_type + }; + + // Gather locals in statics (because of block expressions). + GatherLocalsVisitor::new(&fcx, id).visit_body(body); + + fcx.check_expr_coercable_to_type(&body.value, revealed_ty, None); + + fcx.write_ty(id, revealed_ty); + + fcx + }; + + // All type checking constraints were added, try to fallback unsolved variables. + fcx.select_obligations_where_possible(false, |_| {}); + 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 &fcx.unsolved_variables() { + fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::NoOpaque); + } + // 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: + // + // ```rust + // type MyType = impl Copy; + // fn produce() -> MyType { true } + // fn bad_produce() -> MyType { panic!() } + // ``` + // + // we want to unify the opaque inference variable in `bad_produce` + // with the diverging fallback for `panic!` (e.g. `()` or `!`). + // This will produce a nice error message about conflicting concrete + // types for `MyType`. + // + // If we had tried to fallback the opaque inference variable to `MyType`, + // we will generate a confusing type-check error that does not explicitly + // refer to opaque types. + fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); + + // We now run fallback again, but this time we allow it to replace + // unconstrained opaque type variables, in addition to performing + // other kinds of fallback. + for ty in &fcx.unsolved_variables() { + fallback_has_occurred |= fcx.fallback_if_possible(ty, FallbackMode::All); + } + + // See if we can make any more progress. + fcx.select_obligations_where_possible(fallback_has_occurred, |_| {}); + + // Even though coercion casts provide type hints, we check casts after fallback for + // backwards compatibility. This makes fallback a stronger type hint than a cast coercion. + fcx.check_casts(); + + // Closure and generator analysis may run after fallback + // because they don't constrain other type variables. + fcx.closure_analyze(body); + assert!(fcx.deferred_call_resolutions.borrow().is_empty()); + fcx.resolve_generator_interiors(def_id.to_def_id()); + + for (ty, span, code) in fcx.deferred_sized_obligations.borrow_mut().drain(..) { + let ty = fcx.normalize_ty(span, ty); + fcx.require_type_is_sized(ty, span, code); + } + + fcx.select_all_obligations_or_error(); + + if fn_decl.is_some() { + fcx.regionck_fn(id, body); + } else { + fcx.regionck_expr(body); + } + + fcx.resolve_type_vars_in_body(body) + }); + + // Consistency check our TypeckResults instance can hold all ItemLocalIds + // it will need to hold. + assert_eq!(typeck_results.hir_owner, id.owner); + + typeck_results +} + +/// When `check_fn` is invoked on a generator (i.e., a body that +/// includes yield), it returns back some information about the yield +/// points. +struct GeneratorTypes<'tcx> { + /// Type of generator argument / values returned by `yield`. + resume_ty: Ty<'tcx>, + + /// Type of value that is yielded. + yield_ty: Ty<'tcx>, + + /// Types that are captured (see `GeneratorInterior` for more). + interior: Ty<'tcx>, + + /// Indicates if the generator is movable or static (immovable). + movability: hir::Movability, +} + +/// Given a `DefId` for an opaque type in return position, find its parent item's return +/// expressions. +fn get_owner_return_paths( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> Option<(hir::HirId, ReturnsVisitor<'tcx>)> { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let id = tcx.hir().get_parent_item(hir_id); + tcx.hir() + .find(id) + .map(|n| (id, n)) + .and_then(|(hir_id, node)| node.body_id().map(|b| (hir_id, b))) + .map(|(hir_id, body_id)| { + let body = tcx.hir().body(body_id); + let mut visitor = ReturnsVisitor::default(); + visitor.visit_body(body); + (hir_id, visitor) + }) +} + +/// Emit an error for recursive opaque types in a `let` binding. +fn binding_opaque_type_cycle_error( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, + span: Span, + partially_expanded_type: Ty<'tcx>, +) { + let mut err = struct_span_err!(tcx.sess, span, E0720, "cannot resolve opaque type"); + err.span_label(span, "cannot resolve opaque type"); + // Find the owner that declared this `impl Trait` type. + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let mut prev_hir_id = hir_id; + let mut hir_id = tcx.hir().get_parent_node(hir_id); + while let Some(node) = tcx.hir().find(hir_id) { + match node { + hir::Node::Local(hir::Local { + pat, + init: None, + ty: Some(ty), + source: hir::LocalSource::Normal, + .. + }) => { + err.span_label(pat.span, "this binding might not have a concrete type"); + err.span_suggestion_verbose( + ty.span.shrink_to_hi(), + "set the binding to a value for a concrete type to be resolved", + " = /* value */".to_string(), + Applicability::HasPlaceholders, + ); + } + hir::Node::Local(hir::Local { + init: Some(expr), + source: hir::LocalSource::Normal, + .. + }) => { + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let typeck_results = + tcx.typeck(tcx.hir().local_def_id(tcx.hir().get_parent_item(hir_id))); + if let Some(ty) = typeck_results.node_type_opt(expr.hir_id) { + err.span_label( + expr.span, + &format!( + "this is of type `{}`, which doesn't constrain \ + `{}` enough to arrive to a concrete type", + ty, partially_expanded_type + ), + ); + } + } + _ => {} + } + if prev_hir_id == hir_id { + break; + } + prev_hir_id = hir_id; + hir_id = tcx.hir().get_parent_node(hir_id); + } + err.emit(); +} + +// Forbid defining intrinsics in Rust code, +// as they must always be defined by the compiler. +fn fn_maybe_err(tcx: TyCtxt<'_>, sp: Span, abi: Abi) { + if let Abi::RustIntrinsic | Abi::PlatformIntrinsic = abi { + tcx.sess.span_err(sp, "intrinsic must be in `extern \"rust-intrinsic\" { ... }` block"); + } +} + +fn maybe_check_static_with_link_section(tcx: TyCtxt<'_>, id: LocalDefId, span: Span) { + // Only restricted on wasm32 target for now + if !tcx.sess.opts.target_triple.triple().starts_with("wasm32") { + return; + } + + // If `#[link_section]` is missing, then nothing to verify + let attrs = tcx.codegen_fn_attrs(id); + if attrs.link_section.is_none() { + return; + } + + // For the wasm32 target statics with `#[link_section]` are placed into custom + // sections of the final output file, but this isn't link custom sections of + // other executable formats. Namely we can only embed a list of bytes, + // nothing with pointers to anything else or relocations. If any relocation + // show up, reject them here. + // `#[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 \ + simple list of bytes on the wasm target with no \ + extra levels of indirection such as references"; + tcx.sess.span_err(span, msg); + } + } + Err(_) => {} + } +} + +fn report_forbidden_specialization( + tcx: TyCtxt<'_>, + impl_item: &hir::ImplItem<'_>, + parent_impl: DefId, +) { + let mut err = struct_span_err!( + tcx.sess, + impl_item.span, + E0520, + "`{}` specializes an item from a parent `impl`, but \ + that item is not marked `default`", + impl_item.ident + ); + err.span_label(impl_item.span, format!("cannot specialize default item `{}`", impl_item.ident)); + + match tcx.span_of_impl(parent_impl) { + Ok(span) => { + err.span_label(span, "parent `impl` is here"); + err.note(&format!( + "to specialize, `{}` in the parent `impl` must be marked `default`", + impl_item.ident + )); + } + Err(cname) => { + err.note(&format!("parent implementation is in crate `{}`", cname)); + } + } + + err.emit(); +} + +fn missing_items_err( + tcx: TyCtxt<'_>, + impl_span: Span, + missing_items: &[ty::AssocItem], + full_impl_span: Span, +) { + let missing_items_msg = missing_items + .iter() + .map(|trait_item| trait_item.ident.to_string()) + .collect::>() + .join("`, `"); + + let mut err = struct_span_err!( + tcx.sess, + impl_span, + E0046, + "not all trait items implemented, missing: `{}`", + missing_items_msg + ); + err.span_label(impl_span, format!("missing `{}` in implementation", missing_items_msg)); + + // `Span` before impl block closing brace. + let hi = full_impl_span.hi() - BytePos(1); + // Point at the place right before the closing brace of the relevant `impl` to suggest + // adding the associated item at the end of its body. + let sugg_sp = full_impl_span.with_lo(hi).with_hi(hi); + // Obtain the level of indentation ending in `sugg_sp`. + let indentation = tcx.sess.source_map().span_to_margin(sugg_sp).unwrap_or(0); + // Make the whitespace that will make the suggestion have the right indentation. + let padding: String = (0..indentation).map(|_| " ").collect(); + + for trait_item in missing_items { + 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; + if let Some(span) = tcx.hir().span_if_local(trait_item.def_id) { + err.span_label(span, format!("`{}` from trait", trait_item.ident)); + err.tool_only_span_suggestion(sugg_sp, &msg, code, appl); + } else { + err.span_suggestion_hidden(sugg_sp, &msg, code, appl); + } + } + err.emit(); +} + +/// Resugar `ty::GenericPredicates` in a way suitable to be used in structured suggestions. +fn bounds_from_generic_predicates<'tcx>( + tcx: TyCtxt<'tcx>, + predicates: ty::GenericPredicates<'tcx>, +) -> (String, String) { + let mut types: FxHashMap, Vec> = FxHashMap::default(); + let mut projections = vec![]; + for (predicate, _) in predicates.predicates { + debug!("predicate {:?}", predicate); + match predicate.skip_binders() { + ty::PredicateAtom::Trait(trait_predicate, _) => { + let entry = types.entry(trait_predicate.self_ty()).or_default(); + let def_id = trait_predicate.def_id(); + if Some(def_id) != tcx.lang_items().sized_trait() { + // Type params are `Sized` by default, do not add that restriction to the list + // if it is a positive requirement. + entry.push(trait_predicate.def_id()); + } + } + ty::PredicateAtom::Projection(projection_pred) => { + projections.push(ty::Binder::bind(projection_pred)); + } + _ => {} + } + } + let generics = if types.is_empty() { + "".to_string() + } else { + format!( + "<{}>", + types + .keys() + .filter_map(|t| match t.kind() { + ty::Param(_) => Some(t.to_string()), + // Avoid suggesting the following: + // fn foo::Bar>(_: T) where T: Trait, ::Bar: Other {} + _ => None, + }) + .collect::>() + .join(", ") + ) + }; + let mut where_clauses = vec![]; + for (ty, bounds) in types { + for bound in &bounds { + where_clauses.push(format!("{}: {}", ty, tcx.def_path_str(*bound))); + } + } + for projection in &projections { + let p = projection.skip_binder(); + // FIXME: this is not currently supported syntax, we should be looking at the `types` and + // insert the associated types where they correspond, but for now let's be "lazy" and + // propose this instead of the following valid resugaring: + // `T: Trait, Trait::Assoc = K` → `T: Trait` + where_clauses.push(format!("{} = {}", tcx.def_path_str(p.projection_ty.item_def_id), p.ty)); + } + let where_clauses = if where_clauses.is_empty() { + String::new() + } else { + format!(" where {}", where_clauses.join(", ")) + }; + (generics, where_clauses) +} + +/// Return placeholder code for the given function. +fn fn_sig_suggestion<'tcx>( + tcx: TyCtxt<'tcx>, + sig: ty::FnSig<'tcx>, + ident: Ident, + predicates: ty::GenericPredicates<'tcx>, + assoc: &ty::AssocItem, +) -> String { + let args = sig + .inputs() + .iter() + .enumerate() + .map(|(i, ty)| { + Some(match ty.kind() { + ty::Param(_) if assoc.fn_has_self_parameter && i == 0 => "self".to_string(), + ty::Ref(reg, ref_ty, mutability) if i == 0 => { + let reg = match &format!("{}", reg)[..] { + "'_" | "" => String::new(), + reg => format!("{} ", reg), + }; + if assoc.fn_has_self_parameter { + match ref_ty.kind() { + ty::Param(param) if param.name == kw::SelfUpper => { + format!("&{}{}self", reg, mutability.prefix_str()) + } + + _ => format!("self: {}", ty), + } + } else { + format!("_: {}", ty) + } + } + _ => { + if assoc.fn_has_self_parameter && i == 0 { + format!("self: {}", ty) + } else { + format!("_: {}", ty) + } + } + }) + }) + .chain(std::iter::once(if sig.c_variadic { Some("...".to_string()) } else { None })) + .filter_map(|arg| arg) + .collect::>() + .join(", "); + let output = sig.output(); + let output = if !output.is_unit() { format!(" -> {}", output) } else { String::new() }; + + let unsafety = sig.unsafety.prefix_str(); + let (generics, where_clauses) = bounds_from_generic_predicates(tcx, predicates); + + // FIXME: this is not entirely correct, as the lifetimes from borrowed params will + // not be present in the `fn` definition, not will we account for renamed + // lifetimes between the `impl` and the `trait`, but this should be good enough to + // fill in a significant portion of the missing code, and other subsequent + // suggestions can help the user fix the code. + format!( + "{}fn {}{}({}){}{} {{ todo!() }}", + unsafety, ident, generics, args, output, where_clauses + ) +} + +/// Return placeholder code for the given associated item. +/// Similar to `ty::AssocItem::suggestion`, but appropriate for use as the code snippet of a +/// structured suggestion. +fn suggestion_signature(assoc: &ty::AssocItem, tcx: TyCtxt<'_>) -> String { + match assoc.kind { + ty::AssocKind::Fn => { + // We skip the binder here because the binder would deanonymize all + // late-bound regions, and we don't want method signatures to show up + // `as for<'r> fn(&'r MyType)`. Pretty-printing handles late-bound + // regions just fine, showing `fn(&MyType)`. + fn_sig_suggestion( + tcx, + tcx.fn_sig(assoc.def_id).skip_binder(), + assoc.ident, + tcx.predicates_of(assoc.def_id), + assoc, + ) + } + ty::AssocKind::Type => format!("type {} = Type;", assoc.ident), + ty::AssocKind::Const => { + let ty = tcx.type_of(assoc.def_id); + let val = expr::ty_kind_suggestion(ty).unwrap_or("value"); + format!("const {}: {} = {};", assoc.ident, ty, val) + } + } +} + +/// Emit an error when encountering more or less than one variant in a transparent enum. +fn bad_variant_count<'tcx>(tcx: TyCtxt<'tcx>, adt: &'tcx ty::AdtDef, sp: Span, did: DefId) { + let variant_spans: Vec<_> = adt + .variants + .iter() + .map(|variant| tcx.hir().span_if_local(variant.def_id).unwrap()) + .collect(); + let msg = format!("needs exactly one variant, but has {}", adt.variants.len(),); + let mut err = struct_span_err!(tcx.sess, sp, E0731, "transparent enum {}", msg); + err.span_label(sp, &msg); + if let [start @ .., end] = &*variant_spans { + for variant_span in start { + err.span_label(*variant_span, ""); + } + err.span_label(*end, &format!("too many variants in `{}`", tcx.def_path_str(did))); + } + err.emit(); +} + +/// Emit an error when encountering more or less than one non-zero-sized field in a transparent +/// enum. +fn bad_non_zero_sized_fields<'tcx>( + tcx: TyCtxt<'tcx>, + adt: &'tcx ty::AdtDef, + field_count: usize, + field_spans: impl Iterator, + sp: Span, +) { + let msg = format!("needs exactly one non-zero-sized field, but has {}", field_count); + let mut err = struct_span_err!( + tcx.sess, + sp, + E0690, + "{}transparent {} {}", + if adt.is_enum() { "the variant of a " } else { "" }, + adt.descr(), + msg, + ); + err.span_label(sp, &msg); + for sp in field_spans { + err.span_label(sp, "this field is non-zero-sized"); + } + err.emit(); +} + +fn report_unexpected_variant_res(tcx: TyCtxt<'_>, res: Res, span: Span) { + struct_span_err!( + tcx.sess, + span, + E0533, + "expected unit struct, unit variant or constant, found {}{}", + res.descr(), + tcx.sess.source_map().span_to_snippet(span).map_or(String::new(), |s| format!(" `{}`", s)), + ) + .emit(); +} + +/// Controls whether the arguments are tupled. This is used for the call +/// operator. +/// +/// Tupling means that all call-side arguments are packed into a tuple and +/// passed as a single parameter. For example, if tupling is enabled, this +/// function: +/// +/// fn f(x: (isize, isize)) +/// +/// Can be called as: +/// +/// f(1, 2); +/// +/// Instead of: +/// +/// f((1, 2)); +#[derive(Clone, Eq, PartialEq)] +enum TupleArgumentsFlag { + DontTupleArguments, + TupleArguments, +} + +/// Controls how we perform fallback for unconstrained +/// type variables. +enum FallbackMode { + /// Do not fallback type variables to opaque types. + NoOpaque, + /// Perform all possible kinds of fallback, including + /// turning type variables to opaque types. + All, +} + +/// A wrapper for `InferCtxt`'s `in_progress_typeck_results` field. +#[derive(Copy, Clone)] +struct MaybeInProgressTables<'a, 'tcx> { + maybe_typeck_results: Option<&'a RefCell>>, +} + +impl<'a, 'tcx> MaybeInProgressTables<'a, 'tcx> { + fn borrow(self) -> Ref<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow() with no typeck results" + ), + } + } + + fn borrow_mut(self) -> RefMut<'a, ty::TypeckResults<'tcx>> { + match self.maybe_typeck_results { + Some(typeck_results) => typeck_results.borrow_mut(), + None => bug!( + "MaybeInProgressTables: inh/fcx.typeck_results.borrow_mut() with no typeck results" + ), + } + } +} + +struct CheckItemTypesVisitor<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl ItemLikeVisitor<'tcx> for CheckItemTypesVisitor<'tcx> { + fn visit_item(&mut self, i: &'tcx hir::Item<'tcx>) { + check_item_type(self.tcx, i); + } + fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem<'tcx>) {} + fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem<'tcx>) {} +} + +fn typeck_item_bodies(tcx: TyCtxt<'_>, crate_num: CrateNum) { + debug_assert!(crate_num == LOCAL_CRATE); + tcx.par_body_owners(|body_owner_def_id| { + tcx.ensure().typeck(body_owner_def_id); + }); +} + +fn fatally_break_rust(sess: &Session) { + let handler = sess.diagnostic(); + handler.span_bug_no_panic( + MultiSpan::new(), + "It looks like you're trying to break rust; would you like some ICE?", + ); + handler.note_without_error("the compiler expectedly panicked. this is a feature."); + handler.note_without_error( + "we would appreciate a joke overview: \ + https://github.com/rust-lang/rust/issues/43162#issuecomment-320764675", + ); + handler.note_without_error(&format!( + "rustc {} running on {}", + option_env!("CFG_VERSION").unwrap_or("unknown_version"), + config::host_triple(), + )); +} + +fn potentially_plural_count(count: usize, word: &str) -> String { + format!("{} {}{}", count, word, pluralize!(count)) +} diff --git a/src/librustc_typeck/check/op.rs b/compiler/rustc_typeck/src/check/op.rs similarity index 97% rename from src/librustc_typeck/check/op.rs rename to compiler/rustc_typeck/src/check/op.rs index 66fb01a54f..66975f32a1 100644 --- a/src/librustc_typeck/check/op.rs +++ b/compiler/rustc_typeck/src/check/op.rs @@ -206,7 +206,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { Ok(method) => { let by_ref_binop = !op.node.is_by_value(); if is_assign == IsAssign::Yes || by_ref_binop { - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind { + if let ty::Ref(region, _, mutbl) = method.sig.inputs()[0].kind() { let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, hir::Mutability::Mut => AutoBorrowMutability::Mut { @@ -223,7 +223,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } } if by_ref_binop { - if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind { + if let ty::Ref(region, _, mutbl) = method.sig.inputs()[1].kind() { let mutbl = match mutbl { hir::Mutability::Not => AutoBorrowMutability::Not, hir::Mutability::Mut => AutoBorrowMutability::Mut { @@ -395,7 +395,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } }; let mut suggested_deref = false; - if let Ref(_, rty, _) = lhs_ty.kind { + if let Ref(_, rty, _) = lhs_ty.kind() { if { self.infcx.type_is_copy_modulo_regions(self.param_env, rty, lhs_expr.span) && self @@ -436,7 +436,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // concatenation (e.g., "Hello " + "World!"). This means // we don't want the note in the else clause to be emitted } else if let [ty] = &visitor.0[..] { - if let ty::Param(p) = ty.kind { + if let ty::Param(p) = *ty.kind() { // 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. @@ -468,7 +468,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { )); } } else { - bug!("type param visitor stored a non type param: {:?}", ty.kind); + 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); @@ -494,7 +494,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign: IsAssign, ) -> bool /* did we suggest to call a function because of missing parenthesis? */ { err.span_label(span, ty.to_string()); - if let FnDef(def_id, _) = ty.kind { + if let FnDef(def_id, _) = *ty.kind() { let source_map = self.tcx.sess.source_map(); if !self.tcx.has_typeck_results(def_id) { return false; @@ -502,7 +502,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // We're emitting a suggestion, so we can just ignore regions let fn_sig = self.tcx.fn_sig(def_id).skip_binder(); - let other_ty = if let FnDef(def_id, _) = other_ty.kind { + let other_ty = if let FnDef(def_id, _) = *other_ty.kind() { if !self.tcx.has_typeck_results(def_id) { return false; } @@ -568,10 +568,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None => false, }; - match (&lhs_ty.kind, &rhs_ty.kind) { + match (lhs_ty.kind(), rhs_ty.kind()) { (&Ref(_, l_ty, _), &Ref(_, r_ty, _)) // &str or &String + &str, &String or &&str - if (l_ty.kind == Str || is_std_string(l_ty)) && ( - r_ty.kind == Str || is_std_string(r_ty) || + if (*l_ty.kind() == Str || is_std_string(l_ty)) && ( + *r_ty.kind() == Str || is_std_string(r_ty) || &format!("{:?}", rhs_ty) == "&&str" ) => { @@ -589,10 +589,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } else { msg }, - if lstring.starts_with('&') { + if let Some(stripped) = lstring.strip_prefix('&') { // let a = String::new(); // let _ = &a + "bar"; - lstring[1..].to_string() + stripped.to_string() } else { format!("{}.to_owned()", lstring) }, @@ -605,7 +605,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { true } (&Ref(_, l_ty, _), &Adt(..)) // Handle `&str` & `&String` + `String` - if (l_ty.kind == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => + if (*l_ty.kind() == Str || is_std_string(l_ty)) && is_std_string(rhs_ty) => { err.span_label( op.span, @@ -617,10 +617,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { is_assign, ) { (Ok(l), Ok(r), IsAssign::No) => { - let to_string = if l.starts_with('&') { + let to_string = if let Some(stripped) = l.strip_prefix('&') { // let a = String::new(); let b = String::new(); // let _ = &a + b; - l[1..].to_string() + stripped.to_string() } else { format!("{}.to_owned()", l) }; @@ -670,12 +670,12 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ex.span, format!("cannot apply unary operator `{}`", op.as_str()), ); - match actual.kind { + match actual.kind() { Uint(_) if op == hir::UnOp::UnNeg => { err.note("unsigned values cannot be negated"); } Str | Never | Char | Tuple(_) | Array(_, _) => {} - Ref(_, ref lty, _) if lty.kind == Str => {} + Ref(_, ref lty, _) if *lty.kind() == Str => {} _ => { let missing_trait = match op { hir::UnOp::UnNeg => "std::ops::Neg", @@ -844,7 +844,7 @@ enum Op { /// Dereferences a single level of immutable referencing. fn deref_ty_if_possible(ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match ty.kind() { ty::Ref(_, ty, hir::Mutability::Not) => ty, _ => ty, } @@ -903,7 +903,7 @@ fn is_builtin_binop<'tcx>(lhs: Ty<'tcx>, rhs: Ty<'tcx>, op: hir::BinOp) -> bool /// 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 let Adt(def, _) = ty.peel_refs().kind() { if def.did.is_local() { err.note(&format!( "an implementation of `{}` might be missing for `{}`", @@ -957,7 +957,7 @@ struct TypeParamVisitor<'tcx>(Vec>); impl<'tcx> TypeVisitor<'tcx> for TypeParamVisitor<'tcx> { fn visit_ty(&mut self, ty: Ty<'tcx>) -> bool { - if let ty::Param(_) = ty.kind { + if let ty::Param(_) = ty.kind() { self.0.push(ty); } ty.super_visit_with(self) @@ -972,7 +972,7 @@ impl TypeFolder<'tcx> for TypeParamEraser<'_, 'tcx> { } fn fold_ty(&mut self, ty: Ty<'tcx>) -> Ty<'tcx> { - match ty.kind { + match ty.kind() { ty::Param(_) => self.0.next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::MiscVariable, span: self.1, diff --git a/src/librustc_typeck/check/pat.rs b/compiler/rustc_typeck/src/check/pat.rs similarity index 86% rename from src/librustc_typeck/check/pat.rs rename to compiler/rustc_typeck/src/check/pat.rs index dc1ce2d89b..3e431a9c00 100644 --- a/src/librustc_typeck/check/pat.rs +++ b/compiler/rustc_typeck/src/check/pat.rs @@ -1,5 +1,6 @@ use crate::check::FnCtxt; use rustc_ast as ast; + use rustc_ast::util::lev_distance::find_best_match_for_name; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{pluralize, struct_span_err, Applicability, DiagnosticBuilder}; @@ -10,7 +11,7 @@ use rustc_hir::{HirId, Pat, PatKind}; use rustc_infer::infer; use rustc_infer::infer::type_variable::{TypeVariableOrigin, TypeVariableOriginKind}; use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{self, BindingMode, Ty, TypeFoldable}; +use rustc_middle::ty::{self, Adt, BindingMode, Ty, TypeFoldable}; use rustc_span::hygiene::DesugaringKind; use rustc_span::source_map::{Span, Spanned}; use rustc_span::symbol::Ident; @@ -281,7 +282,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // String and byte-string literals result in types `&str` and `&[u8]` respectively. // All other literals result in non-reference types. // As a result, we allow `if let 0 = &&0 {}` but not `if let "foo" = &&"foo {}`. - PatKind::Lit(lt) => match self.check_expr(lt).kind { + PatKind::Lit(lt) => match self.check_expr(lt).kind() { ty::Ref(..) => AdjustMode::Pass, _ => AdjustMode::Peel, }, @@ -341,7 +342,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // // See the examples in `ui/match-defbm*.rs`. let mut pat_adjustments = vec![]; - while let ty::Ref(_, inner_ty, inner_mutability) = expected.kind { + while let ty::Ref(_, inner_ty, inner_mutability) = *expected.kind() { debug!("inspecting {:?}", expected); debug!("current discriminant is Ref, inserting implicit deref"); @@ -389,9 +390,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut pat_ty = ty; if let hir::ExprKind::Lit(Spanned { node: ast::LitKind::ByteStr(_), .. }) = lt.kind { let expected = self.structurally_resolved_type(span, expected); - if let ty::Ref(_, ty::TyS { kind: ty::Slice(_), .. }, _) = expected.kind { - let tcx = self.tcx; - pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); + if let ty::Ref(_, inner_ty, _) = expected.kind() { + if matches!(inner_ty.kind(), ty::Slice(_)) { + let tcx = self.tcx; + pat_ty = tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_slice(tcx.types.u8)); + } } } @@ -492,7 +495,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.tcx.sess, span, E0029, - "only char and numeric types are allowed in range patterns" + "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 mut one_side_err = |first_span, first_ty, second: Option<(bool, Ty<'tcx>, Span)>| { @@ -639,7 +642,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn check_dereferenceable(&self, span: Span, expected: Ty<'tcx>, inner: &Pat<'_>) -> bool { if let PatKind::Binding(..) = inner.kind { if let Some(mt) = self.shallow_resolve(expected).builtin_deref(true) { - if let ty::Dynamic(..) = mt.ty.kind { + if let ty::Dynamic(..) = mt.ty.kind() { // This is "x = SomeTrait" being reduced from // "let &x = &SomeTrait" or "let box x = Box", an error. let type_str = self.ty_to_string(expected); @@ -733,17 +736,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if let Some(err) = self.demand_suptype_with_origin(&self.pattern_cause(ti, pat.span), expected, pat_ty) { - self.emit_bad_pat_path(err, pat.span, res, pat_res, segments, ti.parent_pat); + self.emit_bad_pat_path(err, pat.span, res, pat_res, pat_ty, segments, ti.parent_pat); } pat_ty } + fn maybe_suggest_range_literal( + &self, + e: &mut DiagnosticBuilder<'_>, + opt_def_id: Option, + ident: Ident, + ) -> bool { + match opt_def_id { + Some(def_id) => match self.tcx.hir().get_if_local(def_id) { + Some(hir::Node::Item(hir::Item { + kind: hir::ItemKind::Const(_, body_id), .. + })) => match self.tcx.hir().get(body_id.hir_id) { + hir::Node::Expr(expr) => { + if hir::is_range_literal(expr) { + let span = self.tcx.hir().span(body_id.hir_id); + if let Ok(snip) = self.tcx.sess.source_map().span_to_snippet(span) { + e.span_suggestion_verbose( + ident.span, + "you may want to move the range into the match block", + snip, + Applicability::MachineApplicable, + ); + return true; + } + } + } + _ => (), + }, + _ => (), + }, + _ => (), + } + false + } + fn emit_bad_pat_path( &self, mut e: DiagnosticBuilder<'_>, pat_span: Span, res: Res, pat_res: Res, + pat_ty: Ty<'tcx>, segments: &'b [hir::PathSegment<'b>], parent_pat: Option<&Pat<'_>>, ) { @@ -769,9 +807,39 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ); } _ => { - let msg = "introduce a new binding instead"; - let sugg = format!("other_{}", ident.as_str().to_lowercase()); - e.span_suggestion(ident.span, msg, sugg, Applicability::HasPlaceholders); + let (type_def_id, item_def_id) = match pat_ty.kind() { + Adt(def, _) => match res { + Res::Def(DefKind::Const, def_id) => (Some(def.did), Some(def_id)), + _ => (None, None), + }, + _ => (None, None), + }; + + let ranges = &[ + self.tcx.lang_items().range_struct(), + self.tcx.lang_items().range_from_struct(), + self.tcx.lang_items().range_to_struct(), + self.tcx.lang_items().range_full_struct(), + self.tcx.lang_items().range_inclusive_struct(), + self.tcx.lang_items().range_to_inclusive_struct(), + ]; + if type_def_id != None && ranges.contains(&type_def_id) { + if !self.maybe_suggest_range_literal(&mut e, item_def_id, *ident) { + let msg = "constants only support matching by type, \ + if you meant to match against a range of values, \ + consider using a range pattern like `min ..= max` in the match block"; + e.note(msg); + } + } else { + let msg = "introduce a new binding instead"; + let sugg = format!("other_{}", ident.as_str().to_lowercase()); + e.span_suggestion( + ident.span, + msg, + sugg, + Applicability::HasPlaceholders, + ); + } } }; } @@ -871,7 +939,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { if subpats.len() == variant.fields.len() || subpats.len() < variant.fields.len() && ddpos.is_some() { - let substs = match pat_ty.kind { + let substs = match pat_ty.kind() { ty::Adt(_, substs) => substs, _ => bug!("unexpected pattern type {:?}", pat_ty), }; @@ -924,13 +992,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // More generally, the expected type wants a tuple variant with one field of an // N-arity-tuple, e.g., `V_i((p_0, .., p_N))`. Meanwhile, the user supplied a pattern // with the subpatterns directly in the tuple variant pattern, e.g., `V_i(p_0, .., p_N)`. - let missing_parenthesis = match (&expected.kind, fields, had_err) { + let missing_parenthesis = match (&expected.kind(), fields, had_err) { // #67037: only do this if we could successfully type-check the expected type against // the tuple struct pattern. Otherwise the substs could get out of range on e.g., // `let P() = U;` where `P != U` with `struct P(T);`. (ty::Adt(_, substs), [field], false) => { let field_ty = self.field_ty(pat_span, field, substs); - match field_ty.kind { + match field_ty.kind() { ty::Tuple(_) => field_ty.tuple_fields().count() == subpats.len(), _ => false, } @@ -981,7 +1049,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { 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(ref tys) = self.structurally_resolved_type(span, expected).kind() { expected_len = tys.len(); } } @@ -1025,7 +1093,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ) -> bool { let tcx = self.tcx; - let (substs, adt) = match adt_ty.kind { + let (substs, adt) = match adt_ty.kind() { ty::Adt(adt, substs) => (substs, adt), _ => span_bug!(pat.span, "struct pattern is not an ADT"), }; @@ -1076,11 +1144,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut unmentioned_fields = variant .fields .iter() - .map(|field| field.ident.normalize_to_macros_2_0()) - .filter(|ident| !used_fields.contains_key(&ident)) + .map(|field| (field, field.ident.normalize_to_macros_2_0())) + .filter(|(_, ident)| !used_fields.contains_key(&ident)) .collect::>(); - let inexistent_fields_err = if !inexistent_fields.is_empty() && !variant.recovered { + let inexistent_fields_err = if !(inexistent_fields.is_empty() || variant.is_recovered()) { Some(self.error_inexistent_fields( adt.variant_descr(), &inexistent_fields, @@ -1108,7 +1176,19 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { tcx.sess.struct_span_err(pat.span, "`..` cannot be used in union patterns").emit(); } } else if !etc && !unmentioned_fields.is_empty() { - unmentioned_err = Some(self.error_unmentioned_fields(pat, &unmentioned_fields)); + let no_accessible_unmentioned_fields = unmentioned_fields + .iter() + .find(|(field, _)| { + field.vis.is_accessible_from(tcx.parent_module(pat.hir_id).to_def_id(), tcx) + }) + .is_none(); + + if no_accessible_unmentioned_fields { + unmentioned_err = Some(self.error_no_accessible_fields(pat, &fields)); + } else { + unmentioned_err = + Some(self.error_unmentioned_fields(pat, &unmentioned_fields, &fields)); + } } match (inexistent_fields_err, unmentioned_err) { (Some(mut i), Some(mut u)) => { @@ -1171,7 +1251,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, kind_name: &str, inexistent_fields: &[Ident], - unmentioned_fields: &mut Vec, + unmentioned_fields: &mut Vec<(&ty::FieldDef, Ident)>, variant: &ty::VariantDef, ) -> DiagnosticBuilder<'tcx> { let tcx = self.tcx; @@ -1213,7 +1293,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ), ); if plural == "" { - let input = unmentioned_fields.iter().map(|field| &field.name); + let input = unmentioned_fields.iter().map(|(_, field)| &field.name); let suggested_name = find_best_match_for_name(input, ident.name, None); if let Some(suggested_name) = suggested_name { err.span_suggestion( @@ -1230,7 +1310,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // `smart_resolve_context_dependent_help`. if suggested_name.to_ident_string().parse::().is_err() { // We don't want to throw `E0027` in case we have thrown `E0026` for them. - unmentioned_fields.retain(|&x| x.name != suggested_name); + unmentioned_fields.retain(|&(_, x)| x.name != suggested_name); } } } @@ -1298,17 +1378,78 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { None } + /// Returns a diagnostic reporting a struct pattern which is missing an `..` due to + /// inaccessible fields. + /// + /// ```ignore (diagnostic) + /// error: pattern requires `..` due to inaccessible fields + /// --> src/main.rs:10:9 + /// | + /// LL | let foo::Foo {} = foo::Foo::default(); + /// | ^^^^^^^^^^^ + /// | + /// help: add a `..` + /// | + /// LL | let foo::Foo { .. } = foo::Foo::default(); + /// | ^^^^^^ + /// ``` + fn error_no_accessible_fields( + &self, + pat: &Pat<'_>, + fields: &'tcx [hir::FieldPat<'tcx>], + ) -> DiagnosticBuilder<'tcx> { + let mut err = self + .tcx + .sess + .struct_span_err(pat.span, "pattern requires `..` due to inaccessible fields"); + + if let Some(field) = fields.last() { + err.span_suggestion_verbose( + field.span.shrink_to_hi(), + "ignore the inaccessible and unused fields", + ", ..".to_string(), + Applicability::MachineApplicable, + ); + } else { + let qpath_span = if let PatKind::Struct(qpath, ..) = &pat.kind { + qpath.span() + } else { + bug!("`error_no_accessible_fields` called on non-struct pattern"); + }; + + // Shrink the span to exclude the `foo:Foo` in `foo::Foo { }`. + let span = pat.span.with_lo(qpath_span.shrink_to_hi().hi()); + err.span_suggestion_verbose( + span, + "ignore the inaccessible and unused fields", + " { .. }".to_string(), + Applicability::MachineApplicable, + ); + } + err + } + + /// Returns a diagnostic reporting a struct pattern which does not mention some fields. + /// + /// ```ignore (diagnostic) + /// error[E0027]: pattern does not mention field `you_cant_use_this_field` + /// --> src/main.rs:15:9 + /// | + /// LL | let foo::Foo {} = foo::Foo::new(); + /// | ^^^^^^^^^^^ missing field `you_cant_use_this_field` + /// ``` fn error_unmentioned_fields( &self, pat: &Pat<'_>, - unmentioned_fields: &[Ident], + unmentioned_fields: &[(&ty::FieldDef, Ident)], + fields: &'tcx [hir::FieldPat<'tcx>], ) -> DiagnosticBuilder<'tcx> { let field_names = if unmentioned_fields.len() == 1 { - format!("field `{}`", unmentioned_fields[0]) + format!("field `{}`", unmentioned_fields[0].1) } else { let fields = unmentioned_fields .iter() - .map(|name| format!("`{}`", name)) + .map(|(_, name)| format!("`{}`", name)) .collect::>() .join(", "); format!("fields {}", fields) @@ -1321,14 +1462,52 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { field_names ); err.span_label(pat.span, format!("missing {}", field_names)); - if self.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "This error indicates that a pattern for a struct fails to specify a \ - sub-pattern for every one of the struct's fields. Ensure that each field \ - from the struct's definition is mentioned in the pattern, or use `..` to \ - ignore unwanted fields.", - ); - } + let len = unmentioned_fields.len(); + let (prefix, postfix, sp) = match fields { + [] => match &pat.kind { + PatKind::Struct(path, [], false) => { + (" { ", " }", path.span().shrink_to_hi().until(pat.span.shrink_to_hi())) + } + _ => return err, + }, + [.., field] => ( + match pat.kind { + PatKind::Struct(_, [_, ..], _) => ", ", + _ => "", + }, + "", + field.span.shrink_to_hi(), + ), + }; + err.span_suggestion( + sp, + &format!( + "include the missing field{} in the pattern", + if len == 1 { "" } else { "s" }, + ), + format!( + "{}{}{}", + prefix, + unmentioned_fields + .iter() + .map(|(_, name)| name.to_string()) + .collect::>() + .join(", "), + postfix, + ), + Applicability::MachineApplicable, + ); + err.span_suggestion( + sp, + &format!( + "if you don't care about {} missing field{}, you can explicitely ignore {}", + if len == 1 { "this" } else { "these" }, + if len == 1 { "" } else { "s" }, + if len == 1 { "it" } else { "them" }, + ), + format!("{}..{}", prefix, postfix), + Applicability::MachineApplicable, + ); err } @@ -1378,7 +1557,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // to avoid creating needless variables. This also helps with // the bad interactions of the given hack detailed in (note_1). debug!("check_pat_ref: expected={:?}", expected); - match expected.kind { + match *expected.kind() { ty::Ref(_, r_ty, r_mutbl) if r_mutbl == mutbl => (expected, r_ty), _ => { let inner_ty = self.next_ty_var(TypeVariableOrigin { @@ -1434,7 +1613,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ti: TopInfo<'tcx>, ) -> Ty<'tcx> { let expected = self.structurally_resolved_type(span, expected); - let (element_ty, opt_slice_ty, inferred) = match expected.kind { + let (element_ty, opt_slice_ty, inferred) = match *expected.kind() { // An array, so we might have something like `let [a, b, c] = [0, 1, 2];`. ty::Array(element_ty, len) => { let min = before.len() as u64 + after.len() as u64; @@ -1570,8 +1749,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { "expected an array or slice, found `{}`", expected_ty ); - if let ty::Ref(_, ty, _) = expected_ty.kind { - if let ty::Array(..) | ty::Slice(..) = ty.kind { + if let ty::Ref(_, ty, _) = expected_ty.kind() { + if let ty::Array(..) | ty::Slice(..) = ty.kind() { err.help("the semantics of slice patterns changed recently; see issue #62254"); } } diff --git a/src/librustc_typeck/check/place_op.rs b/compiler/rustc_typeck/src/check/place_op.rs similarity index 89% rename from src/librustc_typeck/check/place_op.rs rename to compiler/rustc_typeck/src/check/place_op.rs index 4bef9aecd2..502cb56238 100644 --- a/src/librustc_typeck/check/place_op.rs +++ b/compiler/rustc_typeck/src/check/place_op.rs @@ -25,7 +25,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let ok = self.try_overloaded_deref(expr.span, oprnd_ty)?; let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { + if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { self.apply_adjustments( oprnd_expr, vec![Adjustment { @@ -86,7 +86,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let mut self_ty = adjusted_ty; if unsize { // We only unsize arrays here. - if let ty::Array(element_ty, _) = adjusted_ty.kind { + if let ty::Array(element_ty, _) = adjusted_ty.kind() { self_ty = self.tcx.mk_slice(element_ty); } else { continue; @@ -108,7 +108,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let method = self.register_infer_ok_obligations(ok); let mut adjustments = self.adjust_steps(autoderef); - if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind { + if let ty::Ref(region, _, hir::Mutability::Not) = method.sig.inputs()[0].kind() { adjustments.push(Adjustment { kind: Adjust::Borrow(AutoBorrow::Ref(region, AutoBorrowMutability::Not)), target: self.tcx.mk_ref( @@ -193,7 +193,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { /// Convert auto-derefs, indices, etc of an expression from `Deref` and `Index` /// into `DerefMut` and `IndexMut` respectively. /// - /// This is a second pass of typechecking derefs/indices. We need this we do not + /// This is a second pass of typechecking derefs/indices. We need this because we do not /// always know whether a place needs to be mutable or not in the first pass. /// This happens whether there is an implicit mutable reborrow, e.g. when the type /// is used as the receiver of a method call. @@ -211,13 +211,21 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("convert_place_derefs_to_mutable: exprs={:?}", exprs); // Fix up autoderefs and derefs. + let mut inside_union = false; for (i, &expr) in exprs.iter().rev().enumerate() { debug!("convert_place_derefs_to_mutable: i={} expr={:?}", i, expr); + let mut source = self.node_ty(expr.hir_id); + if matches!(expr.kind, hir::ExprKind::Unary(hir::UnOp::UnDeref, _)) { + // Clear previous flag; after a pointer indirection it does not apply any more. + inside_union = false; + } + if source.ty_adt_def().map_or(false, |adt| adt.is_union()) { + inside_union = true; + } // Fix up the autoderefs. Autorefs can only occur immediately preceding // overloaded place ops, and will be fixed by them in order to get // the correct region. - let mut source = self.node_ty(expr.hir_id); // Do not mutate adjustments in place, but rather take them, // and replace them after mutating them, to avoid having the // typeck results borrowed during (`deref_mut`) method resolution. @@ -233,8 +241,23 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { PlaceOp::Deref, ) { let method = self.register_infer_ok_obligations(ok); - if let ty::Ref(region, _, mutbl) = method.sig.output().kind { - *deref = OverloadedDeref { region, mutbl }; + if let ty::Ref(region, _, mutbl) = *method.sig.output().kind() { + *deref = OverloadedDeref { region, mutbl, span: deref.span }; + } + // If this is a union field, also throw an error for `DerefMut` of `ManuallyDrop` (see RFC 2514). + // This helps avoid accidental drops. + if inside_union + && source.ty_adt_def().map_or(false, |adt| adt.is_manually_drop()) + { + let mut err = self.tcx.sess.struct_span_err( + expr.span, + "not automatically applying `DerefMut` on `ManuallyDrop` union field", + ); + err.help( + "writing to this reference calls the destructor for the old value", + ); + err.help("add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor"); + err.emit(); } } } @@ -305,7 +328,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("convert_place_op_to_mutable: method={:?}", method); self.write_method_call(expr.hir_id, method); - let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind { + let region = if let ty::Ref(r, _, hir::Mutability::Mut) = method.sig.inputs()[0].kind() { r } else { span_bug!(expr.span, "input to mutable place op is not a mut ref?"); diff --git a/src/librustc_typeck/check/regionck.rs b/compiler/rustc_typeck/src/check/regionck.rs similarity index 99% rename from src/librustc_typeck/check/regionck.rs rename to compiler/rustc_typeck/src/check/regionck.rs index 221e5f72dc..ba0f22513a 100644 --- a/src/librustc_typeck/check/regionck.rs +++ b/compiler/rustc_typeck/src/check/regionck.rs @@ -624,7 +624,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { ); let rptr_ty = self.resolve_node_type(id); - if let ty::Ref(r, _, _) = rptr_ty.kind { + if let ty::Ref(r, _, _) = rptr_ty.kind() { debug!("rptr_ty={}", rptr_ty); self.link_region(span, r, ty::BorrowKind::from_mutbl(mutbl), cmt_borrowed); } @@ -649,7 +649,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { "link_region(borrow_region={:?}, borrow_kind={:?}, pointer_ty={:?})", borrow_region, borrow_kind, borrow_place ); - match pointer_ty.kind { + match *pointer_ty.kind() { ty::RawPtr(_) => return, ty::Ref(ref_region, _, ref_mutability) => { if self.link_reborrowed_region(span, borrow_region, ref_region, ref_mutability) @@ -786,7 +786,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { return; } } - ty::UpvarCapture::ByValue => {} + ty::UpvarCapture::ByValue(_) => {} } let fn_hir_id = self.tcx.hir().local_def_id_to_hir_id(upvar_id.closure_expr_id); let ty = self.resolve_node_type(fn_hir_id); @@ -794,7 +794,7 @@ impl<'a, 'tcx> RegionCtxt<'a, 'tcx> { // A closure capture can't be borrowed for longer than the // reference to the closure. - if let ty::Closure(_, substs) = ty.kind { + if let ty::Closure(_, substs) = ty.kind() { match self.infcx.closure_kind(substs) { Some(ty::ClosureKind::Fn | ty::ClosureKind::FnMut) => { // Region of environment pointer diff --git a/src/librustc_typeck/check/upvar.rs b/compiler/rustc_typeck/src/check/upvar.rs similarity index 92% rename from src/librustc_typeck/check/upvar.rs rename to compiler/rustc_typeck/src/check/upvar.rs index 030c0ab668..2c3be0da5d 100644 --- a/src/librustc_typeck/check/upvar.rs +++ b/compiler/rustc_typeck/src/check/upvar.rs @@ -42,6 +42,7 @@ use rustc_infer::infer::UpvarRegion; use rustc_middle::hir::place::{PlaceBase, PlaceWithHirId}; use rustc_middle::ty::{self, Ty, TyCtxt, UpvarSubsts}; use rustc_span::{Span, Symbol}; +use std::collections::hash_map::Entry; impl<'a, 'tcx> FnCtxt<'a, 'tcx> { pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) { @@ -87,7 +88,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Extract the type of the closure. let ty = self.node_ty(closure_hir_id); - let (closure_def_id, substs) = match ty.kind { + let (closure_def_id, substs) = match *ty.kind() { ty::Closure(def_id, substs) => (def_id, UpvarSubsts::Closure(substs)), ty::Generator(def_id, substs, _) => (def_id, UpvarSubsts::Generator(substs)), ty::Error(_) => { @@ -124,7 +125,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { closure_captures.insert(var_hir_id, upvar_id); let capture_kind = match capture_clause { - hir::CaptureBy::Value => ty::UpvarCapture::ByValue, + hir::CaptureBy::Value => ty::UpvarCapture::ByValue(None), hir::CaptureBy::Ref => { let origin = UpvarRegion(upvar_id, span); let upvar_region = self.next_region_var(origin); @@ -237,7 +238,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("var_id={:?} upvar_ty={:?} capture={:?}", var_hir_id, upvar_ty, capture); match capture { - ty::UpvarCapture::ByValue => upvar_ty, + ty::UpvarCapture::ByValue(_) => upvar_ty, ty::UpvarCapture::ByRef(borrow) => tcx.mk_ref( borrow.region, ty::TypeAndMut { ty: upvar_ty, mutbl: borrow.kind.to_mutbl_lossy() }, @@ -300,15 +301,43 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { debug!("adjust_upvar_borrow_kind_for_consume: upvar={:?}", upvar_id); + let usage_span = tcx.hir().span(place_with_id.hir_id); + // To move out of an upvar, this must be a FnOnce closure self.adjust_closure_kind( upvar_id.closure_expr_id, ty::ClosureKind::FnOnce, - tcx.hir().span(place_with_id.hir_id), + usage_span, var_name(tcx, upvar_id.var_path.hir_id), ); - self.adjust_upvar_captures.insert(upvar_id, ty::UpvarCapture::ByValue); + // In a case like `let pat = upvar`, don't use the span + // of the pattern, as this just looks confusing. + let by_value_span = match tcx.hir().get(place_with_id.hir_id) { + hir::Node::Pat(_) => None, + _ => Some(usage_span), + }; + + let new_capture = ty::UpvarCapture::ByValue(by_value_span); + match self.adjust_upvar_captures.entry(upvar_id) { + Entry::Occupied(mut e) => { + match e.get() { + // We always overwrite `ByRef`, since we require + // that the upvar be available by value. + // + // If we had a previous by-value usage without a specific + // span, use ours instead. Otherwise, keep the first span + // we encountered, since there isn't an obviously better one. + ty::UpvarCapture::ByRef(_) | ty::UpvarCapture::ByValue(None) => { + e.insert(new_capture); + } + _ => {} + } + } + Entry::Vacant(e) => { + e.insert(new_capture); + } + } } /// Indicates that `place_with_id` is being directly mutated (e.g., assigned @@ -320,7 +349,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { if let PlaceBase::Upvar(upvar_id) = place_with_id.place.base { let mut borrow_kind = ty::MutBorrow; for pointer_ty in place_with_id.place.deref_tys() { - match pointer_ty.kind { + match pointer_ty.kind() { // Raw pointers don't inherit mutability. ty::RawPtr(_) => return, // assignment to deref of an `&mut` @@ -404,7 +433,7 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> { ); match upvar_capture { - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue(_) => { // Upvar is already by-value, the strongest criteria. } ty::UpvarCapture::ByRef(mut upvar_borrow) => { diff --git a/src/librustc_typeck/check/wfcheck.rs b/compiler/rustc_typeck/src/check/wfcheck.rs similarity index 99% rename from src/librustc_typeck/check/wfcheck.rs rename to compiler/rustc_typeck/src/check/wfcheck.rs index 9c692edaa7..5203f3fa8f 100644 --- a/src/librustc_typeck/check/wfcheck.rs +++ b/compiler/rustc_typeck/src/check/wfcheck.rs @@ -291,7 +291,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { let err_ty_str; let mut is_ptr = true; let err = if tcx.features().min_const_generics { - match ty.kind { + match ty.kind() { ty::Bool | ty::Char | ty::Int(_) | ty::Uint(_) | ty::Error(_) => None, ty::FnPtr(_) => Some("function pointers"), ty::RawPtr(_) => Some("raw pointers"), @@ -302,7 +302,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { } } } else { - match ty.peel_refs().kind { + match ty.peel_refs().kind() { ty::FnPtr(_) => Some("function pointers"), ty::RawPtr(_) => Some("raw pointers"), _ => None, @@ -338,7 +338,7 @@ fn check_param_wf(tcx: TyCtxt<'_>, param: &hir::GenericParam<'_>) { // We use the same error code in both branches, because this is really the same // issue: we just special-case the message for type parameters to make it // clearer. - if let ty::Param(_) = ty.peel_refs().kind { + if let ty::Param(_) = ty.peel_refs().kind() { // Const parameters may not have type parameters as their types, // because we cannot be sure that the type parameter derives `PartialEq` // and `Eq` (just implementing them is not enough for `structural_match`). @@ -638,7 +638,7 @@ fn check_associated_type_defaults(fcx: &FnCtxt<'_, '_>, trait_def_id: DefId) { } fn fold_ty(&mut self, t: Ty<'tcx>) -> Ty<'tcx> { - match t.kind { + match t.kind() { ty::Projection(proj_ty) => { if let Some(default) = self.map.get(&proj_ty) { default @@ -709,7 +709,7 @@ fn check_item_type(tcx: TyCtxt<'_>, item_id: hir::HirId, ty_span: Span, allow_fo let mut forbid_unsized = true; if allow_foreign_ty { let tail = fcx.tcx.struct_tail_erasing_lifetimes(item_ty, fcx.param_env); - if let ty::Foreign(_) = tail.kind { + if let ty::Foreign(_) = tail.kind() { forbid_unsized = false; } } @@ -867,7 +867,7 @@ fn check_where_clauses<'tcx, 'fcx>( } impl<'tcx> ty::fold::TypeVisitor<'tcx> for CountParams { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - if let ty::Param(param) = t.kind { + if let ty::Param(param) = t.kind() { self.params.insert(param.index); } t.super_visit_with(self) @@ -1001,7 +1001,7 @@ fn check_opaque_types<'fcx, 'tcx>( ty.fold_with(&mut ty::fold::BottomUpFolder { tcx: fcx.tcx, ty_op: |ty| { - if let ty::Opaque(def_id, substs) = ty.kind { + 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); @@ -1044,7 +1044,7 @@ fn check_opaque_types<'fcx, 'tcx>( 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::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(region) => { if let ty::ReStatic = region { @@ -1177,7 +1177,7 @@ fn e0307(fcx: &FnCtxt<'fcx, 'tcx>, span: Span, receiver_ty: Ty<'_>) { fcx.tcx.sess.diagnostic(), span, E0307, - "invalid `self` parameter type: {:?}", + "invalid `self` parameter type: {}", receiver_ty, ) .note("type of `self` must be `Self` or a type that dereferences to it") diff --git a/src/librustc_typeck/check/writeback.rs b/compiler/rustc_typeck/src/check/writeback.rs similarity index 97% rename from src/librustc_typeck/check/writeback.rs rename to compiler/rustc_typeck/src/check/writeback.rs index 50e2d6a94b..5363702a5b 100644 --- a/src/librustc_typeck/check/writeback.rs +++ b/compiler/rustc_typeck/src/check/writeback.rs @@ -70,10 +70,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { debug!("used_trait_imports({:?}) = {:?}", item_def_id, used_trait_imports); wbcx.typeck_results.used_trait_imports = used_trait_imports; - wbcx.typeck_results.closure_captures = mem::replace( - &mut self.typeck_results.borrow_mut().closure_captures, - Default::default(), - ); + wbcx.typeck_results.closure_captures = + mem::take(&mut self.typeck_results.borrow_mut().closure_captures); if self.is_tainted_by_errors() { // FIXME(eddyb) keep track of `ErrorReported` from where the error was emitted. @@ -193,7 +191,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut typeck_results = self.fcx.typeck_results.borrow_mut(); // All valid indexing looks like this; might encounter non-valid indexes at this point. - let base_ty = typeck_results.expr_ty_adjusted_opt(&base).map(|t| &t.kind); + let base_ty = typeck_results.expr_ty_adjusted_opt(&base).map(|t| t.kind()); if base_ty.is_none() { // When encountering `return [0][0]` outside of a `fn` body we can encounter a base // that isn't in the type table. We assume more relevant errors have already been @@ -331,7 +329,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { fn visit_upvar_capture_map(&mut self) { for (upvar_id, upvar_capture) in self.fcx.typeck_results.borrow().upvar_capture_map.iter() { let new_upvar_capture = match *upvar_capture { - ty::UpvarCapture::ByValue => ty::UpvarCapture::ByValue, + ty::UpvarCapture::ByValue(span) => ty::UpvarCapture::ByValue(span), ty::UpvarCapture::ByRef(ref upvar_borrow) => { ty::UpvarCapture::ByRef(ty::UpvarBorrow { kind: upvar_borrow.kind, @@ -459,7 +457,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let mut skip_add = false; - if let ty::Opaque(defin_ty_def_id, _substs) = definition_ty.kind { + if let ty::Opaque(defin_ty_def_id, _substs) = *definition_ty.kind() { if let hir::OpaqueTyOrigin::Misc = opaque_defn.origin { if def_id == defin_ty_def_id { debug!( @@ -653,7 +651,12 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_type_error(&self, t: Ty<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err(Some(self.body.id()), self.span.to_span(self.tcx), t, E0282) + .emit_inference_failure_err( + Some(self.body.id()), + self.span.to_span(self.tcx), + t.into(), + E0282, + ) .emit(); } } @@ -661,10 +664,10 @@ impl<'cx, 'tcx> Resolver<'cx, 'tcx> { fn report_const_error(&self, c: &'tcx ty::Const<'tcx>) { if !self.tcx.sess.has_errors() { self.infcx - .need_type_info_err_const( + .emit_inference_failure_err( Some(self.body.id()), self.span.to_span(self.tcx), - c, + c.into(), E0282, ) .emit(); diff --git a/src/librustc_typeck/check_unused.rs b/compiler/rustc_typeck/src/check_unused.rs similarity index 100% rename from src/librustc_typeck/check_unused.rs rename to compiler/rustc_typeck/src/check_unused.rs diff --git a/src/librustc_typeck/coherence/builtin.rs b/compiler/rustc_typeck/src/coherence/builtin.rs similarity index 95% rename from src/librustc_typeck/coherence/builtin.rs rename to compiler/rustc_typeck/src/coherence/builtin.rs index 0d3cac7f7f..89270fb6c7 100644 --- a/src/librustc_typeck/coherence/builtin.rs +++ b/compiler/rustc_typeck/src/coherence/builtin.rs @@ -1,6 +1,7 @@ //! Check properties that are required by built-in traits and set //! up data structures required by type-checking/codegen. +use crate::errors::{CopyImplOnNonAdt, CopyImplOnTypeWithDtor, DropImplOnWrongItem}; use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -48,7 +49,7 @@ impl<'tcx> Checker<'tcx> { fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { // Destructors only work on nominal types. - if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind { + if let ty::Adt(..) | ty::Error(_) = tcx.type_of(impl_did).kind() { return; } @@ -58,14 +59,7 @@ fn visit_implementation_of_drop(tcx: TyCtxt<'_>, impl_did: LocalDefId) { _ => bug!("expected Drop impl item"), }; - struct_span_err!( - tcx.sess, - sp, - E0120, - "the `Drop` trait may only be implemented for structs, enums, and unions", - ) - .span_label(sp, "must be a struct, enum, or union") - .emit(); + tcx.sess.emit_err(DropImplOnWrongItem { span: sp }); } fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { @@ -108,25 +102,10 @@ fn visit_implementation_of_copy(tcx: TyCtxt<'_>, impl_did: LocalDefId) { let span = if let ItemKind::Impl { self_ty, .. } = item.kind { self_ty.span } else { span }; - struct_span_err!( - tcx.sess, - span, - E0206, - "the trait `Copy` may not be implemented for this type" - ) - .span_label(span, "type is not a structure or enumeration") - .emit(); + tcx.sess.emit_err(CopyImplOnNonAdt { span }); } Err(CopyImplementationError::HasDestructor) => { - struct_span_err!( - tcx.sess, - span, - E0184, - "the trait `Copy` may not be implemented for this type; the \ - type has a destructor" - ) - .span_label(span, "Copy not allowed on types with destructors") - .emit(); + tcx.sess.emit_err(CopyImplOnTypeWithDtor { span }); } } } @@ -168,7 +147,7 @@ fn visit_implementation_of_dispatch_from_dyn(tcx: TyCtxt<'_>, impl_did: LocalDef let cause = ObligationCause::misc(span, impl_hir_id); use ty::TyKind::*; - match (&source.kind, &target.kind) { + match (source.kind(), target.kind()) { (&Ref(r_a, _, mutbl_a), Ref(r_b, _, mutbl_b)) if infcx.at(&cause, param_env).eq(r_a, r_b).is_ok() && mutbl_a == *mutbl_b => {} (&RawPtr(tm_a), &RawPtr(tm_b)) if tm_a.mutbl == tm_b.mutbl => (), @@ -352,7 +331,7 @@ pub fn coerce_unsized_info(tcx: TyCtxt<'tcx>, impl_did: DefId) -> CoerceUnsizedI } (mt_a.ty, mt_b.ty, unsize_trait, None) }; - let (source, target, trait_def_id, kind) = match (&source.kind, &target.kind) { + let (source, target, trait_def_id, kind) = match (source.kind(), target.kind()) { (&ty::Ref(r_a, ty_a, mutbl_a), &ty::Ref(r_b, ty_b, mutbl_b)) => { infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a); let mt_a = ty::TypeAndMut { ty: ty_a, mutbl: mutbl_a }; diff --git a/src/librustc_typeck/coherence/inherent_impls.rs b/compiler/rustc_typeck/src/coherence/inherent_impls.rs similarity index 93% rename from src/librustc_typeck/coherence/inherent_impls.rs rename to compiler/rustc_typeck/src/coherence/inherent_impls.rs index 859d510dcb..373acb95c9 100644 --- a/src/librustc_typeck/coherence/inherent_impls.rs +++ b/compiler/rustc_typeck/src/coherence/inherent_impls.rs @@ -52,7 +52,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { let def_id = self.tcx.hir().local_def_id(item.hir_id); let self_ty = self.tcx.type_of(def_id); let lang_items = self.tcx.lang_items(); - match self_ty.kind { + match *self_ty.kind() { ty::Adt(def, _) => { self.check_def_id(item, def.did); } @@ -123,7 +123,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Not }) - if matches!(inner.kind, ty::Slice(_)) => + if matches!(inner.kind(), ty::Slice(_)) => { self.check_primitive_impl( def_id, @@ -135,7 +135,7 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { ); } ty::RawPtr(ty::TypeAndMut { ty: inner, mutbl: hir::Mutability::Mut }) - if matches!(inner.kind, ty::Slice(_)) => + if matches!(inner.kind(), ty::Slice(_)) => { self.check_primitive_impl( def_id, @@ -308,18 +308,25 @@ impl ItemLikeVisitor<'v> for InherentCollect<'tcx> { } ty::Error(_) => {} _ => { - struct_span_err!( + let mut err = struct_span_err!( self.tcx.sess, ty.span, E0118, - "no base type found for inherent implementation" - ) - .span_label(ty.span, "impl requires a base type") - .note( - "either implement a trait on it or create a newtype \ - to wrap it instead", - ) - .emit(); + "no nominal type found for inherent implementation" + ); + + err.span_label(ty.span, "impl requires a nominal type") + .note("either implement a trait on it or create a newtype to wrap it instead"); + + if let ty::Ref(_, subty, _) = self_ty.kind() { + err.note(&format!( + "you could also try moving the reference to \ + uses of `{}` (such as `self`) within the implementation", + subty + )); + } + + err.emit(); } } } diff --git a/src/librustc_typeck/coherence/inherent_impls_overlap.rs b/compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs similarity index 100% rename from src/librustc_typeck/coherence/inherent_impls_overlap.rs rename to compiler/rustc_typeck/src/coherence/inherent_impls_overlap.rs diff --git a/src/librustc_typeck/coherence/mod.rs b/compiler/rustc_typeck/src/coherence/mod.rs similarity index 99% rename from src/librustc_typeck/coherence/mod.rs rename to compiler/rustc_typeck/src/coherence/mod.rs index 1483244717..4294450333 100644 --- a/src/librustc_typeck/coherence/mod.rs +++ b/compiler/rustc_typeck/src/coherence/mod.rs @@ -209,7 +209,7 @@ fn check_object_overlap<'tcx>( } // 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(ref 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 --git a/src/librustc_typeck/coherence/orphan.rs b/compiler/rustc_typeck/src/coherence/orphan.rs similarity index 95% rename from src/librustc_typeck/coherence/orphan.rs rename to compiler/rustc_typeck/src/coherence/orphan.rs index 71469770f2..917fc5631c 100644 --- a/src/librustc_typeck/coherence/orphan.rs +++ b/compiler/rustc_typeck/src/coherence/orphan.rs @@ -52,7 +52,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { // Remove the lifetimes unnecessary for this error. ty = infcx.freshen(ty); }); - ty = match ty.kind { + ty = match ty.kind() { // Remove the type arguments from the output, as they are not relevant. // You can think of this as the reverse of `resolve_vars_if_possible`. // That way if we had `Vec`, we will properly attribute the @@ -62,7 +62,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { _ => ty, }; let this = "this".to_string(); - let (ty, postfix) = match &ty.kind { + let (ty, postfix) = match &ty.kind() { ty::Slice(_) => (this, " because slices are always foreign"), ty::Array(..) => (this, " because arrays are always foreign"), ty::Tuple(..) => (this, " because tuples are always foreign"), @@ -185,7 +185,7 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { ); if self.tcx.trait_is_auto(trait_def_id) && !trait_def_id.is_local() { let self_ty = trait_ref.self_ty(); - let opt_self_def_id = match self_ty.kind { + let opt_self_def_id = match *self_ty.kind() { ty::Adt(self_def, _) => Some(self_def.did), ty::Foreign(did) => Some(did), _ => None, @@ -230,6 +230,14 @@ impl ItemLikeVisitor<'v> for OrphanChecker<'tcx> { return; } } + + if let ty::Opaque(def_id, _) = *trait_ref.self_ty().kind() { + self.tcx + .sess + .struct_span_err(sp, "cannot implement trait on type alias impl trait") + .span_note(self.tcx.def_span(def_id), "type alias impl trait defined here") + .emit(); + } } } diff --git a/src/librustc_typeck/coherence/unsafety.rs b/compiler/rustc_typeck/src/coherence/unsafety.rs similarity index 100% rename from src/librustc_typeck/coherence/unsafety.rs rename to compiler/rustc_typeck/src/coherence/unsafety.rs diff --git a/src/librustc_typeck/collect.rs b/compiler/rustc_typeck/src/collect.rs similarity index 94% rename from src/librustc_typeck/collect.rs rename to compiler/rustc_typeck/src/collect.rs index 1b472810cc..9aca112a91 100644 --- a/src/librustc_typeck/collect.rs +++ b/compiler/rustc_typeck/src/collect.rs @@ -18,6 +18,7 @@ use crate::astconv::{AstConv, SizedByDefault}; use crate::bounds::Bounds; use crate::check::intrinsic::intrinsic_operation_unsafety; use crate::constrained_generic_params as cgp; +use crate::errors; use crate::middle::resolve_lifetime as rl; use rustc_ast as ast; use rustc_ast::MetaItemKind; @@ -70,6 +71,7 @@ pub fn provide(providers: &mut Providers) { generics_of, predicates_of, predicates_defined_on, + projection_ty_from_predicates, explicit_predicates_of, super_predicates_of, type_param_predicates, @@ -691,8 +693,14 @@ fn convert_item(tcx: TyCtxt<'_>, item_id: hir::HirId) { // Desugared from `impl Trait`, so visited by the function's return type. hir::ItemKind::OpaqueTy(hir::OpaqueTy { impl_trait_fn: Some(_), .. }) => {} - hir::ItemKind::OpaqueTy(..) - | hir::ItemKind::TyAlias(..) + // Don't call `type_of` on opaque types, since that depends on type + // checking function bodies. `check_item_type` ensures that it's called + // instead. + hir::ItemKind::OpaqueTy(..) => { + tcx.ensure().generics_of(def_id); + tcx.ensure().predicates_of(def_id); + } + hir::ItemKind::TyAlias(..) | hir::ItemKind::Static(..) | hir::ItemKind::Const(..) | hir::ItemKind::Fn(..) => { @@ -833,16 +841,11 @@ fn convert_variant( let fid = tcx.hir().local_def_id(f.hir_id); let dup_span = seen_fields.get(&f.ident.normalize_to_macros_2_0()).cloned(); if let Some(prev_span) = dup_span { - struct_span_err!( - tcx.sess, - f.span, - E0124, - "field `{}` is already declared", - f.ident - ) - .span_label(f.span, "field already declared") - .span_label(prev_span, format!("`{}` first declared here", f.ident)) - .emit(); + tcx.sess.emit_err(errors::FieldAlreadyDeclared { + field_name: f.ident, + span: f.span, + prev_span, + }); } else { seen_fields.insert(f.ident.normalize_to_macros_2_0(), f.span); } @@ -1675,6 +1678,7 @@ fn predicates_defined_on(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicate .alloc_from_iter(result.predicates.iter().chain(inferred_outlives).copied()); } } + debug!("predicates_defined_on({:?}) = {:?}", def_id, result); result } @@ -1716,29 +1720,6 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat debug!("explicit_predicates_of(def_id={:?})", def_id); - /// A data structure with unique elements, which preserves order of insertion. - /// Preserving the order of insertion is important here so as not to break - /// compile-fail UI tests. - struct UniquePredicates<'tcx> { - predicates: FxIndexSet<(ty::Predicate<'tcx>, Span)>, - } - - impl<'tcx> UniquePredicates<'tcx> { - fn new() -> Self { - UniquePredicates { predicates: FxIndexSet::default() } - } - - fn push(&mut self, value: (ty::Predicate<'tcx>, Span)) { - self.predicates.insert(value); - } - - fn extend, Span)>>(&mut self, iter: I) { - for value in iter { - self.push(value); - } - } - } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); let node = tcx.hir().get(hir_id); @@ -1751,7 +1732,10 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat const NO_GENERICS: &hir::Generics<'_> = &hir::Generics::empty(); - let mut predicates = UniquePredicates::new(); + // We use an `IndexSet` to preserves order of insertion. + // Preserving the order of insertion is important here so as not to break + // compile-fail UI tests. + let mut predicates: FxIndexSet<(ty::Predicate<'_>, Span)> = FxIndexSet::default(); let ast_generics = match node { Node::TraitItem(item) => { @@ -1853,7 +1837,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // (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.push(( + predicates.insert(( trait_ref.to_poly_trait_ref().without_const().to_predicate(tcx), tcx.def_span(def_id), )); @@ -1877,7 +1861,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat hir::GenericBound::Outlives(lt) => { let bound = AstConv::ast_region_to_region(&icx, <, None); let outlives = ty::Binder::bind(ty::OutlivesPredicate(region, bound)); - predicates.push((outlives.to_predicate(tcx), lt.span)); + predicates.insert((outlives.to_predicate(tcx), lt.span)); } _ => bug!(), }); @@ -1921,7 +1905,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat // That way, `where Ty:` is not a complete noop (see #53696) and `Ty` // is still checked for WF. if bound_pred.bounds.is_empty() { - if let ty::Param(_) = ty.kind { + if let ty::Param(_) = ty.kind() { // This is a `where T:`, which can be in the HIR from the // transformation that moves `?Sized` to `T`'s declaration. // We can skip the predicate because type parameters are @@ -1932,7 +1916,7 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat let span = bound_pred.bounded_ty.span; let re_root_empty = tcx.lifetimes.re_root_empty; let predicate = ty::OutlivesPredicate(ty, re_root_empty); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(predicate) .potentially_quantified(tcx, ty::PredicateKind::ForAll), span, @@ -1976,11 +1960,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat &hir::GenericBound::Outlives(ref lifetime) => { let region = AstConv::ast_region_to_region(&icx, lifetime, None); - predicates.push(( + predicates.insert(( ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, region)) .potentially_quantified(tcx, ty::PredicateKind::ForAll), lifetime.span, - )) + )); } } } @@ -2025,7 +2009,11 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat })) } - let mut predicates: Vec<_> = predicates.predicates.into_iter().collect(); + if tcx.features().const_evaluatable_checked { + predicates.extend(const_evaluatable_predicates_of(tcx, def_id.expect_local())); + } + + let mut predicates: Vec<_> = predicates.into_iter().collect(); // Subtle: before we store the predicates into the tcx, we // sort them so that predicates like `T: Foo` come @@ -2051,6 +2039,119 @@ fn explicit_predicates_of(tcx: TyCtxt<'_>, def_id: DefId) -> ty::GenericPredicat result } +fn const_evaluatable_predicates_of<'tcx>( + tcx: TyCtxt<'tcx>, + def_id: LocalDefId, +) -> FxIndexSet<(ty::Predicate<'tcx>, Span)> { + struct ConstCollector<'tcx> { + tcx: TyCtxt<'tcx>, + preds: FxIndexSet<(ty::Predicate<'tcx>, Span)>, + } + + impl<'tcx> intravisit::Visitor<'tcx> for ConstCollector<'tcx> { + type Map = Map<'tcx>; + + fn nested_visit_map(&mut self) -> intravisit::NestedVisitorMap { + intravisit::NestedVisitorMap::None + } + + fn visit_anon_const(&mut self, c: &'tcx hir::AnonConst) { + let def_id = self.tcx.hir().local_def_id(c.hir_id); + let ct = ty::Const::from_anon_const(self.tcx, def_id); + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + let span = self.tcx.hir().span(c.hir_id); + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + span, + )); + } + } + + // Look into `TyAlias`. + fn visit_ty(&mut self, ty: &'tcx hir::Ty<'tcx>) { + use ty::fold::{TypeFoldable, TypeVisitor}; + struct TyAliasVisitor<'a, 'tcx> { + tcx: TyCtxt<'tcx>, + preds: &'a mut FxIndexSet<(ty::Predicate<'tcx>, Span)>, + span: Span, + } + + impl<'a, 'tcx> TypeVisitor<'tcx> for TyAliasVisitor<'a, 'tcx> { + fn visit_const(&mut self, ct: &'tcx Const<'tcx>) -> bool { + if let ty::ConstKind::Unevaluated(def, substs, None) = ct.val { + self.preds.insert(( + ty::PredicateAtom::ConstEvaluatable(def, substs).to_predicate(self.tcx), + self.span, + )); + } + false + } + } + + if let hir::TyKind::Path(hir::QPath::Resolved(None, path)) = ty.kind { + if let Res::Def(DefKind::TyAlias, def_id) = path.res { + let mut visitor = + TyAliasVisitor { tcx: self.tcx, preds: &mut self.preds, span: path.span }; + self.tcx.type_of(def_id).visit_with(&mut visitor); + } + } + + intravisit::walk_ty(self, ty) + } + } + + let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let node = tcx.hir().get(hir_id); + + let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; + if let hir::Node::Item(item) = node { + if let hir::ItemKind::Impl { ref of_trait, ref self_ty, .. } = item.kind { + if let Some(of_trait) = of_trait { + warn!("const_evaluatable_predicates_of({:?}): visit impl trait_ref", def_id); + collector.visit_trait_ref(of_trait); + } + + warn!("const_evaluatable_predicates_of({:?}): visit_self_ty", def_id); + collector.visit_ty(self_ty); + } + } + + if let Some(generics) = node.generics() { + warn!("const_evaluatable_predicates_of({:?}): visit_generics", def_id); + collector.visit_generics(generics); + } + + if let Some(fn_sig) = tcx.hir().fn_sig_by_hir_id(hir_id) { + warn!("const_evaluatable_predicates_of({:?}): visit_fn_decl", def_id); + collector.visit_fn_decl(fn_sig.decl); + } + warn!("const_evaluatable_predicates_of({:?}) = {:?}", def_id, collector.preds); + + collector.preds +} + +fn projection_ty_from_predicates( + tcx: TyCtxt<'tcx>, + key: ( + // ty_def_id + DefId, + // def_id of `N` in `::N` + DefId, + ), +) -> Option> { + let (ty_def_id, item_def_id) = key; + let mut projection_ty = None; + for (predicate, _) in tcx.predicates_of(ty_def_id).predicates { + if let ty::PredicateAtom::Projection(projection_predicate) = predicate.skip_binders() { + if item_def_id == projection_predicate.projection_ty.item_def_id { + projection_ty = Some(projection_predicate.projection_ty); + break; + } + } + } + projection_ty +} + fn trait_associated_item_predicates( tcx: TyCtxt<'tcx>, def_id: DefId, @@ -2283,8 +2384,8 @@ fn from_target_feature( item.span(), format!("`{}` is not valid for this target", feature), ); - if feature.starts_with('+') { - let valid = supported_target_features.contains_key(&feature[1..]); + if let Some(stripped) = feature.strip_prefix('+') { + let valid = supported_target_features.contains_key(stripped); if valid { err.help("consider removing the leading `+` in the feature name"); } @@ -2303,7 +2404,6 @@ fn from_target_feature( Some(sym::mips_target_feature) => rust_features.mips_target_feature, Some(sym::riscv_target_feature) => rust_features.riscv_target_feature, Some(sym::avx512_target_feature) => rust_features.avx512_target_feature, - Some(sym::mmx_target_feature) => rust_features.mmx_target_feature, Some(sym::sse4a_target_feature) => rust_features.sse4a_target_feature, Some(sym::tbm_target_feature) => rust_features.tbm_target_feature, Some(sym::wasm_target_feature) => rust_features.wasm_target_feature, @@ -2443,6 +2543,21 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.flags |= CodegenFnAttrFlags::RUSTC_STD_INTERNAL_SYMBOL; } else if tcx.sess.check_name(attr, sym::used) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::USED; + } else if tcx.sess.check_name(attr, sym::cmse_nonsecure_entry) { + if tcx.fn_sig(id).abi() != abi::Abi::C { + struct_span_err!( + tcx.sess, + attr.span, + E0776, + "`#[cmse_nonsecure_entry]` requires C ABI" + ) + .emit(); + } + if !tcx.sess.target.target.llvm_target.contains("thumbv8m") { + struct_span_err!(tcx.sess, attr.span, E0775, "`#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension") + .emit(); + } + codegen_fn_attrs.flags |= CodegenFnAttrFlags::CMSE_NONSECURE_ENTRY; } else if tcx.sess.check_name(attr, sym::thread_local) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::THREAD_LOCAL; } else if tcx.sess.check_name(attr, sym::track_caller) { @@ -2467,10 +2582,17 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, id: DefId) -> CodegenFnAttrs { codegen_fn_attrs.export_name = Some(s); } } else if tcx.sess.check_name(attr, sym::target_feature) { - if !tcx.features().target_feature_11 { - check_target_feature_safe_fn(tcx, id, attr.span); - } else if let Some(local_id) = id.as_local() { - if tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.is_closure(id) && tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { + if !tcx.features().target_feature_11 { + let mut err = feature_err( + &tcx.sess.parse_sess, + sym::target_feature_11, + attr.span, + "`#[target_feature(..)]` can only be applied to `unsafe` functions", + ); + err.span_label(tcx.def_span(id), "not an `unsafe` function"); + err.emit(); + } else if let Some(local_id) = id.as_local() { check_target_feature_trait_unsafe(tcx, local_id, attr.span); } } @@ -2727,21 +2849,6 @@ fn check_link_name_xor_ordinal( } } -/// Checks the function annotated with `#[target_feature]` is unsafe, -/// reporting an error if it isn't. -fn check_target_feature_safe_fn(tcx: TyCtxt<'_>, id: DefId, attr_span: Span) { - if tcx.is_closure(id) || tcx.fn_sig(id).unsafety() == hir::Unsafety::Normal { - let mut err = feature_err( - &tcx.sess.parse_sess, - sym::target_feature_11, - attr_span, - "`#[target_feature(..)]` can only be applied to `unsafe` functions", - ); - err.span_label(tcx.def_span(id), "not an `unsafe` function"); - err.emit(); - } -} - /// Checks the function annotated with `#[target_feature]` is not a safe /// trait method implementation, reporting an error if it is. fn check_target_feature_trait_unsafe(tcx: TyCtxt<'_>, id: LocalDefId, attr_span: Span) { diff --git a/src/librustc_typeck/collect/type_of.rs b/compiler/rustc_typeck/src/collect/type_of.rs similarity index 98% rename from src/librustc_typeck/collect/type_of.rs rename to compiler/rustc_typeck/src/collect/type_of.rs index 70ed92c561..f6dca4a99c 100644 --- a/src/librustc_typeck/collect/type_of.rs +++ b/compiler/rustc_typeck/src/collect/type_of.rs @@ -1,5 +1,6 @@ +use crate::errors::AssocTypeOnInherentImpl; use rustc_data_structures::fx::FxHashSet; -use rustc_errors::{struct_span_err, Applicability, ErrorReported, StashKey}; +use rustc_errors::{Applicability, ErrorReported, StashKey}; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId}; @@ -78,7 +79,13 @@ pub(super) fn opt_const_param_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option< let _tables = tcx.typeck(body_owner); &*path } - _ => span_bug!(DUMMY_SP, "unexpected const parent path {:?}", parent_node), + _ => { + tcx.sess.delay_span_bug( + tcx.def_span(def_id), + &format!("unexpected const parent path {:?}", parent_node), + ); + return None; + } }; // We've encountered an `AnonConst` in some path, so we need to @@ -382,7 +389,7 @@ fn find_opaque_ty_constraints(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { let mut used_params: FxHashSet<_> = FxHashSet::default(); for (i, arg) in substs.iter().enumerate() { let arg_is_param = match arg.unpack() { - GenericArgKind::Type(ty) => matches!(ty.kind, ty::Param(_)), + GenericArgKind::Type(ty) => matches!(ty.kind(), ty::Param(_)), GenericArgKind::Lifetime(lt) => { matches!(lt, ty::ReEarlyBound(_) | ty::ReFree(_)) } @@ -607,7 +614,7 @@ fn infer_placeholder_type( } None => { let mut diag = bad_placeholder_type(tcx, vec![span]); - if !matches!(ty.kind, ty::Error(_)) { + if !matches!(ty.kind(), ty::Error(_)) { diag.span_suggestion( span, "replace `_` with the correct type", @@ -627,11 +634,5 @@ fn infer_placeholder_type( } fn report_assoc_ty_on_inherent_impl(tcx: TyCtxt<'_>, span: Span) { - struct_span_err!( - tcx.sess, - span, - E0202, - "associated types are not yet supported in inherent impls (see #8995)" - ) - .emit(); + tcx.sess.emit_err(AssocTypeOnInherentImpl { span }); } diff --git a/src/librustc_typeck/constrained_generic_params.rs b/compiler/rustc_typeck/src/constrained_generic_params.rs similarity index 99% rename from src/librustc_typeck/constrained_generic_params.rs rename to compiler/rustc_typeck/src/constrained_generic_params.rs index 7c80315ee1..09b5a9b0a6 100644 --- a/src/librustc_typeck/constrained_generic_params.rs +++ b/compiler/rustc_typeck/src/constrained_generic_params.rs @@ -57,7 +57,7 @@ struct ParameterCollector { impl<'tcx> TypeVisitor<'tcx> for ParameterCollector { fn visit_ty(&mut self, t: Ty<'tcx>) -> bool { - match t.kind { + match *t.kind() { ty::Projection(..) | ty::Opaque(..) if !self.include_nonconstraining => { // projections are not injective return false; diff --git a/compiler/rustc_typeck/src/errors.rs b/compiler/rustc_typeck/src/errors.rs new file mode 100644 index 0000000000..a769e48d2c --- /dev/null +++ b/compiler/rustc_typeck/src/errors.rs @@ -0,0 +1,199 @@ +//! Errors emitted by typeck. +use rustc_macros::SessionDiagnostic; +use rustc_span::{symbol::Ident, Span, Symbol}; + +#[derive(SessionDiagnostic)] +#[error = "E0062"] +pub struct FieldMultiplySpecifiedInInitializer { + #[message = "field `{ident}` specified more than once"] + #[label = "used more than once"] + pub span: Span, + #[label = "first use of `{ident}`"] + pub prev_span: Span, + pub ident: Ident, +} + +#[derive(SessionDiagnostic)] +#[error = "E0092"] +pub struct UnrecognizedAtomicOperation<'a> { + #[message = "unrecognized atomic operation function: `{op}`"] + #[label = "unrecognized atomic operation"] + pub span: Span, + pub op: &'a str, +} + +#[derive(SessionDiagnostic)] +#[error = "E0094"] +pub struct WrongNumberOfTypeArgumentsToInstrinsic { + #[message = "intrinsic has wrong number of type \ + parameters: found {found}, expected {expected}"] + #[label = "expected {expected} type parameter"] + pub span: Span, + pub found: usize, + pub expected: usize, +} + +#[derive(SessionDiagnostic)] +#[error = "E0093"] +pub struct UnrecognizedIntrinsicFunction { + #[message = "unrecognized intrinsic function: `{name}`"] + #[label = "unrecognized intrinsic"] + pub span: Span, + pub name: Symbol, +} + +#[derive(SessionDiagnostic)] +#[error = "E0195"] +pub struct LifetimesOrBoundsMismatchOnTrait { + #[message = "lifetime parameters or bounds on {item_kind} `{ident}` do not match the trait declaration"] + #[label = "lifetimes do not match {item_kind} in trait"] + pub span: Span, + #[label = "lifetimes in impl do not match this {item_kind} in trait"] + pub generics_span: Option, + pub item_kind: &'static str, + pub ident: Ident, +} + +#[derive(SessionDiagnostic)] +#[error = "E0120"] +pub struct DropImplOnWrongItem { + #[message = "the `Drop` trait may only be implemented for structs, enums, and unions"] + #[label = "must be a struct, enum, or union"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0124"] +pub struct FieldAlreadyDeclared { + pub field_name: Ident, + #[message = "field `{field_name}` is already declared"] + #[label = "field already declared"] + pub span: Span, + #[label = "`{field_name}` first declared here"] + pub prev_span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0184"] +pub struct CopyImplOnTypeWithDtor { + #[message = "the trait `Copy` may not be implemented for this type; the \ + type has a destructor"] + #[label = "Copy not allowed on types with destructors"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0202"] +pub struct AssocTypeOnInherentImpl { + #[message = "associated types are not yet supported in inherent impls (see #8995)"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0203"] +pub struct MultipleRelaxedDefaultBounds { + #[message = "type parameter has more than one relaxed default bound, only one is supported"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0206"] +pub struct CopyImplOnNonAdt { + #[message = "the trait `Copy` may not be implemented for this type"] + #[label = "type is not a structure or enumeration"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0224"] +pub struct TraitObjectDeclaredWithNoTraits { + #[message = "at least one trait is required for an object type"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0227"] +pub struct AmbiguousLifetimeBound { + #[message = "ambiguous lifetime bound, explicit lifetime bound required"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0229"] +pub struct AssocTypeBindingNotAllowed { + #[message = "associated type bindings are not allowed here"] + #[label = "associated type not allowed here"] + pub span: Span, +} + +#[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"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0516"] +pub struct TypeofReservedKeywordUsed { + #[message = "`typeof` is a reserved keyword but unimplemented"] + #[label = "reserved keyword"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0572"] +pub struct ReturnStmtOutsideOfFnBody { + #[message = "return statement outside of function body"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0627"] +pub struct YieldExprOutsideOfGenerator { + #[message = "yield expression outside of generator literal"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0639"] +pub struct StructExprNonExhaustive { + #[message = "cannot create non-exhaustive {what} using struct expression"] + pub span: Span, + pub what: &'static str, +} + +#[derive(SessionDiagnostic)] +#[error = "E0699"] +pub struct MethodCallOnUnknownType { + #[message = "the type of this value must be known to call a method on a raw pointer on it"] + pub span: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0719"] +pub struct ValueOfAssociatedStructAlreadySpecified { + #[message = "the value of the associated type `{item_name}` (from trait `{def_path}`) is already specified"] + #[label = "re-bound here"] + pub span: Span, + #[label = "`{item_name}` bound here first"] + pub prev_span: Span, + pub item_name: Ident, + pub def_path: String, +} + +#[derive(SessionDiagnostic)] +#[error = "E0745"] +pub struct AddressOfTemporaryTaken { + #[message = "cannot take address of a temporary"] + #[label = "temporary value"] + pub span: Span, +} diff --git a/src/librustc_typeck/expr_use_visitor.rs b/compiler/rustc_typeck/src/expr_use_visitor.rs similarity index 99% rename from src/librustc_typeck/expr_use_visitor.rs rename to compiler/rustc_typeck/src/expr_use_visitor.rs index d1b386c9d4..e16f26c330 100644 --- a/src/librustc_typeck/expr_use_visitor.rs +++ b/compiler/rustc_typeck/src/expr_use_visitor.rs @@ -387,7 +387,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // Select just those fields of the `with` // expression that will actually be used - match with_place.place.ty().kind { + match with_place.place.ty().kind() { ty::Adt(adt, substs) if adt.is_struct() => { // Consume those fields of the with expression that are needed. for (f_index, with_field) in adt.non_enum_variant().fields.iter().enumerate() { @@ -559,7 +559,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { var_id, )); match upvar_capture { - ty::UpvarCapture::ByValue => { + ty::UpvarCapture::ByValue(_) => { let mode = copy_or_move(&self.mc, &captured_place); self.delegate.consume(&captured_place, mode); } diff --git a/src/librustc_typeck/impl_wf_check.rs b/compiler/rustc_typeck/src/impl_wf_check.rs similarity index 95% rename from src/librustc_typeck/impl_wf_check.rs rename to compiler/rustc_typeck/src/impl_wf_check.rs index 891e482b43..4901d6041d 100644 --- a/src/librustc_typeck/impl_wf_check.rs +++ b/compiler/rustc_typeck/src/impl_wf_check.rs @@ -187,7 +187,7 @@ fn enforce_impl_params_are_constrained( } // (*) This is a horrible concession to reality. I think it'd be - // better to just ban unconstrianed lifetimes outright, but in + // better to just ban unconstrained lifetimes outright, but in // practice people do non-hygenic macros like: // // ``` @@ -207,7 +207,7 @@ fn enforce_impl_params_are_constrained( } fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) { - struct_span_err!( + let mut err = struct_span_err!( tcx.sess, span, E0207, @@ -215,9 +215,17 @@ fn report_unused_parameter(tcx: TyCtxt<'_>, span: Span, kind: &str, name: &str) impl trait, self type, or predicates", kind, name - ) - .span_label(span, format!("unconstrained {} parameter", kind)) - .emit(); + ); + err.span_label(span, format!("unconstrained {} parameter", kind)); + if kind == "const" { + err.note( + "expressions using a const parameter must map each value to a distinct output value", + ); + err.note( + "proving the result of expressions other than the parameter are unique is not supported", + ); + } + err.emit(); } /// Enforce that we do not have two items in an impl with the same name. diff --git a/src/librustc_typeck/impl_wf_check/min_specialization.rs b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs similarity index 99% rename from src/librustc_typeck/impl_wf_check/min_specialization.rs rename to compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs index 3746e5778a..60b9467fca 100644 --- a/src/librustc_typeck/impl_wf_check/min_specialization.rs +++ b/compiler/rustc_typeck/src/impl_wf_check/min_specialization.rs @@ -405,6 +405,7 @@ fn trait_predicate_kind<'tcx>( | ty::PredicateAtom::ObjectSafe(_) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => None, + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => None, } } diff --git a/src/librustc_typeck/lib.rs b/compiler/rustc_typeck/src/lib.rs similarity index 98% rename from src/librustc_typeck/lib.rs rename to compiler/rustc_typeck/src/lib.rs index 62f92fe7ff..21fb92ec88 100644 --- a/src/librustc_typeck/lib.rs +++ b/compiler/rustc_typeck/src/lib.rs @@ -55,8 +55,7 @@ This API is completely unstable and subject to change. */ -#![doc(html_root_url = "https://doc.rust-lang.org/nightly/")] -#![allow(non_camel_case_types)] +#![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(bool_to_option)] #![feature(box_syntax)] #![feature(crate_visibility_modifier)] @@ -84,6 +83,7 @@ mod check_unused; mod coherence; mod collect; mod constrained_generic_params; +mod errors; mod impl_wf_check; mod mem_categorization; mod outlives; @@ -158,7 +158,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: LocalDefId) { let main_id = tcx.hir().local_def_id_to_hir_id(main_def_id); let main_span = tcx.def_span(main_def_id); let main_t = tcx.type_of(main_def_id); - match main_t.kind { + match main_t.kind() { ty::FnDef(..) => { if let Some(Node::Item(it)) = tcx.hir().find(main_id) { if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { @@ -254,7 +254,7 @@ fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: LocalDefId) { let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id); let start_span = tcx.def_span(start_def_id); let start_t = tcx.type_of(start_def_id); - match start_t.kind { + match start_t.kind() { ty::FnDef(..) => { if let Some(Node::Item(it)) = tcx.hir().find(start_id) { if let hir::ItemKind::Fn(ref sig, ref generics, _) = it.kind { @@ -359,7 +359,7 @@ pub fn check_crate(tcx: TyCtxt<'_>) -> Result<(), ErrorReported> { // this ensures that later parts of type checking can assume that items // have valid types and not error - // FIXME(matthewjasper) We shouldn't need to do this. + // 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() { diff --git a/src/librustc_typeck/mem_categorization.rs b/compiler/rustc_typeck/src/mem_categorization.rs similarity index 99% rename from src/librustc_typeck/mem_categorization.rs rename to compiler/rustc_typeck/src/mem_categorization.rs index 8a6fe620af..04ead74936 100644 --- a/src/librustc_typeck/mem_categorization.rs +++ b/compiler/rustc_typeck/src/mem_categorization.rs @@ -482,7 +482,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { let place_ty = self.expr_ty(expr)?; let base_ty = self.expr_ty_adjusted(base)?; - let (region, mutbl) = match base_ty.kind { + let (region, mutbl) = match *base_ty.kind() { ty::Ref(region, _, mutbl) => (region, mutbl), _ => span_bug!(expr.span, "cat_overloaded_place: base is not a reference"), }; @@ -542,7 +542,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { ) -> McResult { let res = self.typeck_results.qpath_res(qpath, pat_hir_id); let ty = self.typeck_results.node_type(pat_hir_id); - let adt_def = match ty.kind { + let adt_def = match ty.kind() { ty::Adt(adt_def, _) => adt_def, _ => { self.tcx() @@ -577,7 +577,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { span: Span, ) -> McResult { let ty = self.typeck_results.node_type(pat_hir_id); - match ty.kind { + match ty.kind() { ty::Adt(adt_def, _) => Ok(adt_def.variants[variant_index].fields.len()), _ => { self.tcx() @@ -592,7 +592,7 @@ impl<'a, 'tcx> MemCategorizationContext<'a, 'tcx> { /// Here `pat_hir_id` is the HirId of the pattern itself. fn total_fields_in_tuple(&self, pat_hir_id: hir::HirId, span: Span) -> McResult { let ty = self.typeck_results.node_type(pat_hir_id); - match ty.kind { + match ty.kind() { ty::Tuple(substs) => Ok(substs.len()), _ => { self.tcx().sess.delay_span_bug(span, "tuple pattern not applied to a tuple"); diff --git a/src/librustc_typeck/outlives/explicit.rs b/compiler/rustc_typeck/src/outlives/explicit.rs similarity index 94% rename from src/librustc_typeck/outlives/explicit.rs rename to compiler/rustc_typeck/src/outlives/explicit.rs index 135960a4c1..ae336ccca4 100644 --- a/src/librustc_typeck/outlives/explicit.rs +++ b/compiler/rustc_typeck/src/outlives/explicit.rs @@ -57,7 +57,8 @@ impl<'tcx> ExplicitPredicatesMap<'tcx> { | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::Subtype(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => (), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => (), } } diff --git a/src/librustc_typeck/outlives/implicit_infer.rs b/compiler/rustc_typeck/src/outlives/implicit_infer.rs similarity index 99% rename from src/librustc_typeck/outlives/implicit_infer.rs rename to compiler/rustc_typeck/src/outlives/implicit_infer.rs index 762d4216f7..e7a9e078a7 100644 --- a/src/librustc_typeck/outlives/implicit_infer.rs +++ b/compiler/rustc_typeck/src/outlives/implicit_infer.rs @@ -128,7 +128,7 @@ fn insert_required_predicates_to_be_wf<'tcx>( GenericArgKind::Lifetime(_) | GenericArgKind::Const(_) => continue, }; - match ty.kind { + match *ty.kind() { // The field is of type &'a T which means that we will have // a predicate requirement of T: 'a (T outlives 'a). // diff --git a/src/librustc_typeck/outlives/mod.rs b/compiler/rustc_typeck/src/outlives/mod.rs similarity index 100% rename from src/librustc_typeck/outlives/mod.rs rename to compiler/rustc_typeck/src/outlives/mod.rs diff --git a/src/librustc_typeck/outlives/test.rs b/compiler/rustc_typeck/src/outlives/test.rs similarity index 100% rename from src/librustc_typeck/outlives/test.rs rename to compiler/rustc_typeck/src/outlives/test.rs diff --git a/src/librustc_typeck/outlives/utils.rs b/compiler/rustc_typeck/src/outlives/utils.rs similarity index 100% rename from src/librustc_typeck/outlives/utils.rs rename to compiler/rustc_typeck/src/outlives/utils.rs diff --git a/src/librustc_typeck/structured_errors.rs b/compiler/rustc_typeck/src/structured_errors.rs similarity index 100% rename from src/librustc_typeck/structured_errors.rs rename to compiler/rustc_typeck/src/structured_errors.rs diff --git a/src/librustc_typeck/variance/constraints.rs b/compiler/rustc_typeck/src/variance/constraints.rs similarity index 99% rename from src/librustc_typeck/variance/constraints.rs rename to compiler/rustc_typeck/src/variance/constraints.rs index 535530a2ed..b2b062e409 100644 --- a/src/librustc_typeck/variance/constraints.rs +++ b/compiler/rustc_typeck/src/variance/constraints.rs @@ -140,7 +140,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { let id = tcx.hir().local_def_id_to_hir_id(def_id); let inferred_start = self.terms_cx.inferred_starts[&id]; let current_item = &CurrentItem { inferred_start }; - match tcx.type_of(def_id).kind { + match tcx.type_of(def_id).kind() { ty::Adt(def, _) => { // Not entirely obvious: constraints on structs/enums do not // affect the variance of their type parameters. See discussion @@ -257,7 +257,7 @@ impl<'a, 'tcx> ConstraintContext<'a, 'tcx> { ) { debug!("add_constraints_from_ty(ty={:?}, variance={:?})", ty, variance); - match ty.kind { + match *ty.kind() { ty::Bool | ty::Char | ty::Int(_) diff --git a/src/librustc_typeck/variance/mod.rs b/compiler/rustc_typeck/src/variance/mod.rs similarity index 100% rename from src/librustc_typeck/variance/mod.rs rename to compiler/rustc_typeck/src/variance/mod.rs diff --git a/src/librustc_typeck/variance/solve.rs b/compiler/rustc_typeck/src/variance/solve.rs similarity index 98% rename from src/librustc_typeck/variance/solve.rs rename to compiler/rustc_typeck/src/variance/solve.rs index 7402117a7e..2d3369cba7 100644 --- a/src/librustc_typeck/variance/solve.rs +++ b/compiler/rustc_typeck/src/variance/solve.rs @@ -107,7 +107,7 @@ impl<'a, 'tcx> SolveContext<'a, 'tcx> { self.enforce_const_invariance(generics, variances); // Functions are permitted to have unused generic parameters: make those invariant. - if let ty::FnDef(..) = tcx.type_of(def_id).kind { + if let ty::FnDef(..) = tcx.type_of(def_id).kind() { for variance in variances.iter_mut() { if *variance == ty::Bivariant { *variance = ty::Invariant; diff --git a/src/librustc_typeck/variance/terms.rs b/compiler/rustc_typeck/src/variance/terms.rs similarity index 100% rename from src/librustc_typeck/variance/terms.rs rename to compiler/rustc_typeck/src/variance/terms.rs diff --git a/src/librustc_typeck/variance/test.rs b/compiler/rustc_typeck/src/variance/test.rs similarity index 100% rename from src/librustc_typeck/variance/test.rs rename to compiler/rustc_typeck/src/variance/test.rs diff --git a/src/librustc_typeck/variance/xform.rs b/compiler/rustc_typeck/src/variance/xform.rs similarity index 100% rename from src/librustc_typeck/variance/xform.rs rename to compiler/rustc_typeck/src/variance/xform.rs diff --git a/config.toml.example b/config.toml.example index 36587cc078..c5efb8ed5e 100644 --- a/config.toml.example +++ b/config.toml.example @@ -9,11 +9,42 @@ # a custom configuration file can also be specified with `--config` to the build # system. +# Keeps track of the last version of `x.py` used. +# If it does not match the version that is currently running, +# `x.py` will prompt you to update it and read the changelog. +# See `src/bootstrap/CHANGELOG.md` for more information. +changelog-seen = 1 + +# ============================================================================= +# Global Settings +# ============================================================================= + +# Use different pre-set defaults than the global defaults. +# +# See `src/bootstrap/defaults` for more information. +# Note that this has no default value (x.py uses the defaults in `config.toml.example`). +#profile = + # ============================================================================= # Tweaking how LLVM is compiled # ============================================================================= [llvm] +# Whether to use Rust CI built LLVM instead of locally building it. +# +# Unless you're developing for a target where Rust CI doesn't build a compiler +# toolchain or changing LLVM locally, you probably want to set this to true. +# +# It's currently false by default due to being newly added; please file bugs if +# enabling this did not work for you on x86_64-unknown-linux-gnu. +# Other target triples are currently not supported; see #77084. +# +# We also currently only support this when building LLVM for the build triple. +# +# Note that many of the LLVM options are not currently supported for +# downloading. Currently only the "assertions" option can be toggled. +#download-ci-llvm = false + # Indicates whether LLVM rebuild should be skipped when running bootstrap. If # this is `false` then the compiler's LLVM will be rebuilt whenever the built # version doesn't have the correct hash. If it is `true` then LLVM will never @@ -45,14 +76,12 @@ # this flag will indicate that this version check should not be done. #version-check = true -# Link libstdc++ statically into the librustc_llvm instead of relying on a +# Link libstdc++ statically into the rustc_llvm instead of relying on a # dynamic version to be available. #static-libstdcpp = false -# Tell the LLVM build system to use Ninja instead of the platform default for -# the generated build system. This can sometimes be faster than make, for -# example. -#ninja = false +# Whether to use Ninja to build LLVM. This runs much faster than make. +#ninja = true # LLVM targets to build support for. # Note: this is NOT related to Rust compilation targets. However, as Rust is @@ -113,6 +142,23 @@ # General build configuration options # ============================================================================= [build] +# The default stage to use for the `doc` subcommand +#doc-stage = 0 + +# The default stage to use for the `build` subcommand +#build-stage = 1 + +# The default stage to use for the `test` subcommand +#test-stage = 1 + +# The default stage to use for the `dist` subcommand +#dist-stage = 2 + +# The default stage to use for the `install` subcommand +#install-stage = 2 + +# The default stage to use for the `bench` subcommand +#bench-stage = 2 # Build triple for the original snapshot compiler. This must be a compiler that # nightlies are already produced for. The current platform must be able to run @@ -122,19 +168,18 @@ # Defaults to host platform #build = "x86_64-unknown-linux-gnu" -# In addition to the build triple, other triples to produce full compiler -# toolchains for. Each of these triples will be bootstrapped from the build -# triple and then will continue to bootstrap themselves. This platform must -# currently be able to run all of the triples provided here. +# Which triples to produce a compiler toolchain for. Each of these triples will +# be bootstrapped from the build triple themselves. # # Defaults to just the build triple #host = ["x86_64-unknown-linux-gnu"] -# In addition to all host triples, other triples to produce the standard library -# for. Each host triple will be used to produce a copy of the standard library -# for each target triple. +# Which triples to build libraries (core/alloc/std/test/proc_macro) for. Each of +# these triples will be bootstrapped from the build triple themselves. # -# Defaults to just the build triple +# Defaults to `host`. If you set this explicitly, you likely want to add all +# host triples to this list as well in order for those host toolchains to be +# able to compile programs for their native target. #target = ["x86_64-unknown-linux-gnu"] # Use this directory to store build artifacts. @@ -311,7 +356,9 @@ # Number of codegen units to use for each compiler invocation. A value of 0 # means "the number of cores on this machine", and 1+ is passed through to the # compiler. -#codegen-units = 1 +# +# Uses the rustc defaults: https://doc.rust-lang.org/rustc/codegen-options/index.html#codegen-units +#codegen-units = if incremental { 256 } else { 16 } # Sets the number of codegen units to build the standard library with, # regardless of what the codegen-unit setting for the rest of the compiler is. @@ -323,13 +370,19 @@ # binary, otherwise they are omitted. # # Defaults to rust.debug value -#debug-assertions = false +#debug-assertions = debug # Whether or not debug assertions are enabled for the standard library. # Overrides the `debug-assertions` option, if defined. # # Defaults to rust.debug-assertions value -#debug-assertions-std = false +#debug-assertions-std = debug-assertions + +# Whether or not to leave debug! and trace! calls in the rust binary. +# Overrides the `debug-assertions` option, if defined. +# +# Defaults to rust.debug-assertions value +#debug-logging = debug-assertions # Debuginfo level for most of Rust code, corresponds to the `-C debuginfo=N` option of `rustc`. # `0` - no debug info @@ -373,6 +426,7 @@ #incremental = false # Build a multi-threaded rustc +# FIXME(#75760): Some UI tests fail when this option is enabled. #parallel-compiler = false # The default linker that will be hard-coded into the generated compiler for @@ -394,7 +448,7 @@ # desired in distributions, for example. #rpath = true -# Emits extra output from tests so test failures are debuggable just from logfiles. +# Prints each test name as it is executed, to help debug issues in the test harness itself. #verbose-tests = false # Flag indicating whether tests are compiled with optimizations (the -O flag). @@ -431,7 +485,7 @@ # supported platforms. The LLD from the bootstrap distribution will be used # and not the LLD compiled during the bootstrap. # -# LLD will not be used if we're cross linking or running tests. +# LLD will not be used if we're cross linking. # # Explicitly setting the linker for a target will override this option when targeting MSVC. #use-lld = false diff --git a/git-commit-hash b/git-commit-hash index d00fffae96..c767182e4b 100644 --- a/git-commit-hash +++ b/git-commit-hash @@ -1 +1 @@ -18bf6b4f01a6feaf7259ba7cdae58031af1b7b39 \ No newline at end of file +1219014599fd873fcb640b675d8a662150c74e40 \ No newline at end of file diff --git a/library/alloc/benches/binary_heap.rs b/library/alloc/benches/binary_heap.rs new file mode 100644 index 0000000000..5b6538ea6c --- /dev/null +++ b/library/alloc/benches/binary_heap.rs @@ -0,0 +1,91 @@ +use std::collections::BinaryHeap; + +use rand::{seq::SliceRandom, thread_rng}; +use test::{black_box, Bencher}; + +#[bench] +fn bench_find_smallest_1000(b: &mut Bencher) { + let mut rng = thread_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + let mut iter = vec.iter().copied(); + let mut heap: BinaryHeap<_> = iter.by_ref().take(1000).collect(); + + for x in iter { + let mut max = heap.peek_mut().unwrap(); + // This comparison should be true only 1% of the time. + // Unnecessary `sift_down`s will degrade performance + if x < *max { + *max = x; + } + } + + heap + }) +} + +#[bench] +fn bench_peek_mut_deref_mut(b: &mut Bencher) { + let mut bheap = BinaryHeap::from(vec![42]); + let vec: Vec = (0..1_000_000).collect(); + + b.iter(|| { + let vec = black_box(&vec); + let mut peek_mut = bheap.peek_mut().unwrap(); + // The compiler shouldn't be able to optimize away the `sift_down` + // assignment in `PeekMut`'s `DerefMut` implementation since + // the loop may not run. + for &i in vec.iter() { + *peek_mut = i; + } + // Remove the already minimal overhead of the sift_down + std::mem::forget(peek_mut); + }) +} + +#[bench] +fn bench_from_vec(b: &mut Bencher) { + let mut rng = thread_rng(); + let mut vec: Vec = (0..100_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| BinaryHeap::from(vec.clone())) +} + +#[bench] +fn bench_into_sorted_vec(b: &mut Bencher) { + let bheap: BinaryHeap = (0..10_000).collect(); + + b.iter(|| bheap.clone().into_sorted_vec()) +} + +#[bench] +fn bench_push(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(50_000); + let mut rng = thread_rng(); + let mut vec: Vec = (0..50_000).collect(); + vec.shuffle(&mut rng); + + b.iter(|| { + for &i in vec.iter() { + bheap.push(i); + } + black_box(&mut bheap); + bheap.clear(); + }) +} + +#[bench] +fn bench_pop(b: &mut Bencher) { + let mut bheap = BinaryHeap::with_capacity(10_000); + + b.iter(|| { + bheap.extend((0..10_000).rev()); + black_box(&mut bheap); + while let Some(elem) = bheap.pop() { + black_box(elem); + } + }) +} diff --git a/library/alloc/benches/lib.rs b/library/alloc/benches/lib.rs index 608eafc88d..32edb86d10 100644 --- a/library/alloc/benches/lib.rs +++ b/library/alloc/benches/lib.rs @@ -8,6 +8,7 @@ extern crate test; +mod binary_heap; mod btree; mod linked_list; mod slice; diff --git a/library/alloc/benches/vec.rs b/library/alloc/benches/vec.rs index 4e71eec03e..789ae3a20e 100644 --- a/library/alloc/benches/vec.rs +++ b/library/alloc/benches/vec.rs @@ -1,5 +1,6 @@ +use rand::RngCore; use std::iter::{repeat, FromIterator}; -use test::Bencher; +use test::{black_box, Bencher}; #[bench] fn bench_new(b: &mut Bencher) { @@ -7,6 +8,7 @@ fn bench_new(b: &mut Bencher) { let v: Vec = Vec::new(); assert_eq!(v.len(), 0); assert_eq!(v.capacity(), 0); + v }) } @@ -17,6 +19,7 @@ fn do_bench_with_capacity(b: &mut Bencher, src_len: usize) { let v: Vec = Vec::with_capacity(src_len); assert_eq!(v.len(), 0); assert_eq!(v.capacity(), src_len); + v }) } @@ -47,6 +50,7 @@ fn do_bench_from_fn(b: &mut Bencher, src_len: usize) { let dst = (0..src_len).collect::>(); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }) } @@ -77,6 +81,7 @@ fn do_bench_from_elem(b: &mut Bencher, src_len: usize) { let dst: Vec = repeat(5).take(src_len).collect(); assert_eq!(dst.len(), src_len); assert!(dst.iter().all(|x| *x == 5)); + dst }) } @@ -109,6 +114,7 @@ fn do_bench_from_slice(b: &mut Bencher, src_len: usize) { let dst = src.clone()[..].to_vec(); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -141,6 +147,7 @@ fn do_bench_from_iter(b: &mut Bencher, src_len: usize) { let dst: Vec<_> = FromIterator::from_iter(src.clone()); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -175,6 +182,7 @@ fn do_bench_extend(b: &mut Bencher, dst_len: usize, src_len: usize) { dst.extend(src.clone()); assert_eq!(dst.len(), dst_len + src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -224,9 +232,24 @@ fn do_bench_extend_from_slice(b: &mut Bencher, dst_len: usize, src_len: usize) { dst.extend_from_slice(&src); assert_eq!(dst.len(), dst_len + src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } +#[bench] +fn bench_extend_recycle(b: &mut Bencher) { + let mut data = vec![0; 1000]; + + b.iter(|| { + let tmp = std::mem::take(&mut data); + let mut to_extend = black_box(Vec::new()); + to_extend.extend(tmp.into_iter()); + data = black_box(to_extend); + }); + + black_box(data); +} + #[bench] fn bench_extend_from_slice_0000_0000(b: &mut Bencher) { do_bench_extend_from_slice(b, 0, 0) @@ -271,6 +294,7 @@ fn do_bench_clone(b: &mut Bencher, src_len: usize) { let dst = src.clone(); assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| i == *x)); + dst }); } @@ -305,10 +329,10 @@ fn do_bench_clone_from(b: &mut Bencher, times: usize, dst_len: usize, src_len: u for _ in 0..times { dst.clone_from(&src); - assert_eq!(dst.len(), src_len); assert!(dst.iter().enumerate().all(|(i, x)| dst_len + i == *x)); } + dst }); } @@ -431,3 +455,219 @@ fn bench_clone_from_10_0100_0010(b: &mut Bencher) { fn bench_clone_from_10_1000_0100(b: &mut Bencher) { do_bench_clone_from(b, 10, 1000, 100) } + +macro_rules! bench_in_place { + ($($fname:ident, $type:ty, $count:expr, $init:expr);*) => { + $( + #[bench] + fn $fname(b: &mut Bencher) { + b.iter(|| { + let src: Vec<$type> = black_box(vec![$init; $count]); + let mut sink = src.into_iter() + .enumerate() + .map(|(idx, e)| idx as $type ^ e) + .collect::>(); + black_box(sink.as_mut_ptr()) + }); + } + )+ + }; +} + +bench_in_place![ + bench_in_place_xxu8_0010_i0, u8, 10, 0; + bench_in_place_xxu8_0100_i0, u8, 100, 0; + bench_in_place_xxu8_1000_i0, u8, 1000, 0; + bench_in_place_xxu8_0010_i1, u8, 10, 1; + bench_in_place_xxu8_0100_i1, u8, 100, 1; + bench_in_place_xxu8_1000_i1, u8, 1000, 1; + bench_in_place_xu32_0010_i0, u32, 10, 0; + bench_in_place_xu32_0100_i0, u32, 100, 0; + bench_in_place_xu32_1000_i0, u32, 1000, 0; + bench_in_place_xu32_0010_i1, u32, 10, 1; + bench_in_place_xu32_0100_i1, u32, 100, 1; + bench_in_place_xu32_1000_i1, u32, 1000, 1; + bench_in_place_u128_0010_i0, u128, 10, 0; + bench_in_place_u128_0100_i0, u128, 100, 0; + bench_in_place_u128_1000_i0, u128, 1000, 0; + bench_in_place_u128_0010_i1, u128, 10, 1; + bench_in_place_u128_0100_i1, u128, 100, 1; + bench_in_place_u128_1000_i1, u128, 1000, 1 +]; + +#[bench] +fn bench_in_place_recycle(b: &mut Bencher) { + let mut data = vec![0; 1000]; + + b.iter(|| { + let tmp = std::mem::take(&mut data); + data = black_box( + tmp.into_iter() + .enumerate() + .map(|(idx, e)| idx.wrapping_add(e)) + .fuse() + .peekable() + .collect::>(), + ); + }); +} + +#[bench] +fn bench_in_place_zip_recycle(b: &mut Bencher) { + let mut data = vec![0u8; 1000]; + let mut rng = rand::thread_rng(); + let mut subst = vec![0u8; 1000]; + rng.fill_bytes(&mut subst[..]); + + b.iter(|| { + let tmp = std::mem::take(&mut data); + let mangled = tmp + .into_iter() + .zip(subst.iter().copied()) + .enumerate() + .map(|(i, (d, s))| d.wrapping_add(i as u8) ^ s) + .collect::>(); + assert_eq!(mangled.len(), 1000); + data = black_box(mangled); + }); +} + +#[bench] +fn bench_in_place_zip_iter_mut(b: &mut Bencher) { + let mut data = vec![0u8; 256]; + let mut rng = rand::thread_rng(); + let mut subst = vec![0u8; 1000]; + rng.fill_bytes(&mut subst[..]); + + b.iter(|| { + data.iter_mut().enumerate().for_each(|(i, d)| { + *d = d.wrapping_add(i as u8) ^ subst[i]; + }); + }); + + black_box(data); +} + +#[derive(Clone)] +struct Droppable(usize); + +impl Drop for Droppable { + fn drop(&mut self) { + black_box(self); + } +} + +#[bench] +fn bench_in_place_collect_droppable(b: &mut Bencher) { + let v: Vec = std::iter::repeat_with(|| Droppable(0)).take(1000).collect(); + b.iter(|| { + v.clone() + .into_iter() + .skip(100) + .enumerate() + .map(|(i, e)| Droppable(i ^ e.0)) + .collect::>() + }) +} + +#[bench] +fn bench_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| data.iter().cloned().chain([1].iter().cloned()).collect::>()); +} + +#[bench] +fn bench_chain_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + data.iter() + .cloned() + .chain([1].iter().cloned()) + .chain([2].iter().cloned()) + .collect::>() + }); +} + +#[bench] +fn bench_nest_chain_chain_collect(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + data.iter().cloned().chain([1].iter().chain([2].iter()).cloned()).collect::>() + }); +} + +pub fn example_plain_slow(l: &[u32]) -> Vec { + let mut result = Vec::with_capacity(l.len()); + result.extend(l.iter().rev()); + result +} + +pub fn map_fast(l: &[(u32, u32)]) -> Vec { + let mut result = Vec::with_capacity(l.len()); + for i in 0..l.len() { + unsafe { + *result.get_unchecked_mut(i) = l[i].0; + result.set_len(i); + } + } + result +} + +const LEN: usize = 16384; + +#[bench] +fn bench_range_map_collect(b: &mut Bencher) { + b.iter(|| (0..LEN).map(|_| u32::default()).collect::>()); +} + +#[bench] +fn bench_chain_extend_ref(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::with_capacity(data.len() + 1); + v.extend(data.iter().chain([1].iter())); + v + }); +} + +#[bench] +fn bench_chain_extend_value(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::with_capacity(data.len() + 1); + v.extend(data.iter().cloned().chain(Some(1))); + v + }); +} + +#[bench] +fn bench_rev_1(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| { + let mut v = Vec::::new(); + v.extend(data.iter().rev()); + v + }); +} + +#[bench] +fn bench_rev_2(b: &mut Bencher) { + let data = black_box([0; LEN]); + b.iter(|| example_plain_slow(&data)); +} + +#[bench] +fn bench_map_regular(b: &mut Bencher) { + let data = black_box([(0, 0); LEN]); + b.iter(|| { + let mut v = Vec::::new(); + v.extend(data.iter().map(|t| t.1)); + v + }); +} + +#[bench] +fn bench_map_fast(b: &mut Bencher) { + let data = black_box([(0, 0); LEN]); + b.iter(|| map_fast(&data)); +} diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 87b86e590a..75158eefca 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -3,7 +3,7 @@ #![stable(feature = "alloc_module", since = "1.28.0")] use core::intrinsics::{self, min_align_of_val, size_of_val}; -use core::ptr::{NonNull, Unique}; +use core::ptr::{self, NonNull, Unique}; #[stable(feature = "alloc_module", since = "1.28.0")] #[doc(inline)] @@ -145,53 +145,62 @@ pub unsafe fn alloc_zeroed(layout: Layout) -> *mut u8 { impl Global { #[inline] - fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, AllocErr> { + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, size => unsafe { let raw_ptr = if zeroed { alloc_zeroed(layout) } else { alloc(layout) }; - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, size)) }, } } - // Safety: Same as `AllocRef::grow` + // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, zeroed: bool, - ) -> Result, AllocErr> { + ) -> Result, AllocError> { debug_assert!( - new_size >= layout.size(), - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - match layout.size() { - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - 0 => unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc_impl(new_layout, zeroed) - }, + match old_layout.size() { + 0 => self.alloc_impl(new_layout, zeroed), // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // as required by safety conditions. Other conditions must be upheld by the caller - old_size => unsafe { - // `realloc` probably checks for `new_size >= size` or something similar. - intrinsics::assume(new_size >= layout.size()); + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); - let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + intrinsics::assume(new_size >= old_layout.size()); + + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -199,17 +208,17 @@ impl Global { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for Global { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -219,54 +228,66 @@ unsafe impl AllocRef for Global { #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, false) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } } #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, true) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } } #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size <= layout.size(), - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - match new_size { + match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, layout); - Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)) + self.dealloc(ptr, old_layout); + Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller - new_size => unsafe { - // `realloc` probably checks for `new_size <= size` or something similar. - intrinsics::assume(new_size <= layout.size()); + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + intrinsics::assume(new_size <= old_layout.size()); - let raw_ptr = realloc(ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let raw_ptr = realloc(ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = self.alloc(new_layout)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); + self.dealloc(ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -279,7 +300,7 @@ unsafe impl AllocRef for Global { unsafe fn exchange_malloc(size: usize, align: usize) -> *mut u8 { let layout = unsafe { Layout::from_size_align_unchecked(size, align) }; match Global.alloc(layout) { - Ok(ptr) => ptr.as_non_null_ptr().as_ptr(), + Ok(ptr) => ptr.as_mut_ptr(), Err(_) => handle_alloc_error(layout), } } diff --git a/library/alloc/src/borrow.rs b/library/alloc/src/borrow.rs index 51c233a21f..f801c1ac75 100644 --- a/library/alloc/src/borrow.rs +++ b/library/alloc/src/borrow.rs @@ -217,7 +217,8 @@ impl Cow<'_, B> { /// assert!(!bull.is_borrowed()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] - pub fn is_borrowed(&self) -> bool { + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] + pub const fn is_borrowed(&self) -> bool { match *self { Borrowed(_) => true, Owned(_) => false, @@ -239,7 +240,8 @@ impl Cow<'_, B> { /// assert!(!bull.is_owned()); /// ``` #[unstable(feature = "cow_is_borrowed", issue = "65143")] - pub fn is_owned(&self) -> bool { + #[rustc_const_unstable(feature = "const_cow_is_borrowed", issue = "65143")] + pub const fn is_owned(&self) -> bool { !self.is_borrowed() } diff --git a/library/alloc/src/boxed.rs b/library/alloc/src/boxed.rs index 05211e2037..5c8c2c5a5a 100644 --- a/library/alloc/src/boxed.rs +++ b/library/alloc/src/boxed.rs @@ -217,7 +217,7 @@ impl Box { /// assert_eq!(*zero, 0) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Box> { let layout = alloc::Layout::new::>(); @@ -289,7 +289,7 @@ impl Box<[T]> { /// assert_eq!(*values, [0, 0, 0]) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_slice(len: usize) -> Box<[mem::MaybeUninit]> { unsafe { RawVec::with_capacity_zeroed(len).into_box(len) } @@ -307,7 +307,7 @@ impl Box> { /// 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 /// @@ -343,7 +343,7 @@ impl Box<[mem::MaybeUninit]> { /// 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 /// diff --git a/library/alloc/src/collections/binary_heap.rs b/library/alloc/src/collections/binary_heap.rs index 477a598ff5..f2852b1cc2 100644 --- a/library/alloc/src/collections/binary_heap.rs +++ b/library/alloc/src/collections/binary_heap.rs @@ -15,7 +15,6 @@ //! [dijkstra]: https://en.wikipedia.org/wiki/Dijkstra%27s_algorithm //! [sssp]: https://en.wikipedia.org/wiki/Shortest_path_problem //! [dir_graph]: https://en.wikipedia.org/wiki/Directed_graph -//! [`BinaryHeap`]: struct.BinaryHeap.html //! //! ``` //! use std::cmp::Ordering; @@ -31,7 +30,7 @@ //! // Explicitly implement the trait so the queue becomes a min-heap //! // instead of a max-heap. //! impl Ord for State { -//! fn cmp(&self, other: &State) -> Ordering { +//! fn cmp(&self, other: &Self) -> Ordering { //! // Notice that the we flip the ordering on costs. //! // In case of a tie we compare positions - this step is necessary //! // to make implementations of `PartialEq` and `Ord` consistent. @@ -42,7 +41,7 @@ //! //! // `PartialOrd` needs to be implemented as well. //! impl PartialOrd for State { -//! fn partial_cmp(&self, other: &State) -> Option { +//! fn partial_cmp(&self, other: &Self) -> Option { //! Some(self.cmp(other)) //! } //! } @@ -145,13 +144,13 @@ #![stable(feature = "rust1", since = "1.0.0")] use core::fmt; -use core::iter::{FromIterator, FusedIterator, TrustedLen}; -use core::mem::{self, size_of, swap, ManuallyDrop}; +use core::iter::{FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen}; +use core::mem::{self, swap, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::ptr; use crate::slice; -use crate::vec::{self, Vec}; +use crate::vec::{self, AsIntoIter, Vec}; use super::SpecExtend; @@ -240,10 +239,10 @@ use super::SpecExtend; /// The value for `push` is an expected cost; the method documentation gives a /// more detailed analysis. /// -/// [push]: #method.push -/// [pop]: #method.pop -/// [peek]: #method.peek -/// [peek\_mut]: #method.peek_mut +/// [push]: BinaryHeap::push +/// [pop]: BinaryHeap::pop +/// [peek]: BinaryHeap::peek +/// [peek\_mut]: BinaryHeap::peek_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct BinaryHeap { data: Vec, @@ -255,8 +254,7 @@ pub struct BinaryHeap { /// This `struct` is created by the [`peek_mut`] method on [`BinaryHeap`]. See /// its documentation for more. /// -/// [`peek_mut`]: struct.BinaryHeap.html#method.peek_mut -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`peek_mut`]: BinaryHeap::peek_mut #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub struct PeekMut<'a, T: 'a + Ord> { heap: &'a mut BinaryHeap, @@ -293,6 +291,7 @@ impl Deref for PeekMut<'_, T> { impl DerefMut for PeekMut<'_, T> { fn deref_mut(&mut self) -> &mut T { debug_assert!(!self.heap.is_empty()); + self.sift = true; // SAFE: PeekMut is only instantiated for non-empty heaps unsafe { self.heap.data.get_unchecked_mut(0) } } @@ -398,10 +397,11 @@ impl BinaryHeap { /// /// # Time complexity /// - /// Cost is *O*(1) in the worst case. + /// If the item is modified then the worst case time complexity is *O*(log(*n*)), + /// otherwise it's *O*(1). #[stable(feature = "binary_heap_peek_mut", since = "1.12.0")] pub fn peek_mut(&mut self) -> Option> { - if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: true }) } + if self.is_empty() { None } else { Some(PeekMut { heap: self, sift: false }) } } /// Removes the greatest item from the binary heap and returns it, or `None` if it @@ -617,7 +617,7 @@ impl BinaryHeap { #[inline(always)] fn log2_fast(x: usize) -> usize { - 8 * size_of::() - (x.leading_zeros() as usize) - 1 + (usize::BITS - x.leading_zeros() - 1) as usize } // `rebuild` takes O(len1 + len2) operations @@ -802,7 +802,7 @@ impl BinaryHeap { /// heap.push(4); /// ``` /// - /// [`reserve`]: #method.reserve + /// [`reserve`]: BinaryHeap::reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.data.reserve_exact(additional); @@ -1057,11 +1057,10 @@ impl Drop for Hole<'_, T> { /// An iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`iter`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::iter()`]. See its /// documentation for more. /// -/// [`iter`]: struct.BinaryHeap.html#method.iter -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`iter`]: BinaryHeap::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { iter: slice::Iter<'a, T>, @@ -1122,11 +1121,10 @@ impl FusedIterator for Iter<'_, T> {} /// An owning iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`into_iter`] method on [`BinaryHeap`] +/// This `struct` is created by [`BinaryHeap::into_iter()`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.BinaryHeap.html#method.into_iter -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`into_iter`]: BinaryHeap::into_iter #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct IntoIter { @@ -1173,6 +1171,27 @@ impl ExactSizeIterator for IntoIter { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IntoIter {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for IntoIter { + type Source = IntoIter; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut Self::Source { + self + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for IntoIter {} + +impl AsIntoIter for IntoIter { + type Item = I; + + fn as_into_iter(&mut self) -> &mut vec::IntoIter { + &mut self.iter + } +} + #[unstable(feature = "binary_heap_into_iter_sorted", issue = "59278")] #[derive(Clone, Debug)] pub struct IntoIterSorted { @@ -1206,11 +1225,10 @@ unsafe impl TrustedLen for IntoIterSorted {} /// A draining iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`drain`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::drain()`]. See its /// documentation for more. /// -/// [`drain`]: struct.BinaryHeap.html#method.drain -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`drain`]: BinaryHeap::drain #[stable(feature = "drain", since = "1.6.0")] #[derive(Debug)] pub struct Drain<'a, T: 'a> { @@ -1252,11 +1270,10 @@ impl FusedIterator for Drain<'_, T> {} /// A draining iterator over the elements of a `BinaryHeap`. /// -/// This `struct` is created by the [`drain_sorted`] method on [`BinaryHeap`]. See its +/// This `struct` is created by [`BinaryHeap::drain_sorted()`]. See its /// documentation for more. /// -/// [`drain_sorted`]: struct.BinaryHeap.html#method.drain_sorted -/// [`BinaryHeap`]: struct.BinaryHeap.html +/// [`drain_sorted`]: BinaryHeap::drain_sorted #[unstable(feature = "binary_heap_drain_sorted", issue = "59278")] #[derive(Debug)] pub struct DrainSorted<'a, T: Ord> { @@ -1322,6 +1339,10 @@ impl From> for BinaryHeap { #[stable(feature = "binary_heap_extras_15", since = "1.5.0")] impl From> for Vec { + /// Converts a `BinaryHeap` into a `Vec`. + /// + /// This conversion requires no data movement or allocation, and has + /// constant time complexity. fn from(heap: BinaryHeap) -> Vec { heap.data } diff --git a/library/alloc/src/collections/btree/borrow.rs b/library/alloc/src/collections/btree/borrow.rs new file mode 100644 index 0000000000..016f139a50 --- /dev/null +++ b/library/alloc/src/collections/btree/borrow.rs @@ -0,0 +1,47 @@ +use core::marker::PhantomData; +use core::ptr::NonNull; + +/// Models a reborrow of some unique reference, when you know that the reborrow +/// and all its descendants (i.e., all pointers and references derived from it) +/// will not be used any more at some point, after which you want to use the +/// original unique reference again. +/// +/// The borrow checker usually handles this stacking of borrows for you, but +/// some control flows that accomplish this stacking are too complicated for +/// the compiler to follow. A `DormantMutRef` allows you to check borrowing +/// yourself, while still expressing its stacked nature, and encapsulating +/// the raw pointer code needed to do this without undefined behavior. +pub struct DormantMutRef<'a, T> { + ptr: NonNull, + _marker: PhantomData<&'a mut T>, +} + +unsafe impl<'a, T> Sync for DormantMutRef<'a, T> where &'a mut T: Sync {} +unsafe impl<'a, T> Send for DormantMutRef<'a, T> where &'a mut T: Send {} + +impl<'a, T> DormantMutRef<'a, T> { + /// Capture a unique borrow, and immediately reborrow it. For the compiler, + /// the lifetime of the new reference is the same as the lifetime of the + /// original reference, but you promise to use it for a shorter period. + pub fn new(t: &'a mut T) -> (&'a mut T, Self) { + let ptr = NonNull::from(t); + // SAFETY: we hold the borrow throughout 'a via `_marker`, and we expose + // only this reference, so it is unique. + let new_ref = unsafe { &mut *ptr.as_ptr() }; + (new_ref, Self { ptr, _marker: PhantomData }) + } + + /// Revert to the unique borrow initially captured. + /// + /// # Safety + /// + /// The reborrow must have ended, i.e., the reference returned by `new` and + /// all pointers and references derived from it, must not be used anymore. + pub unsafe fn awaken(self) -> &'a mut T { + // SAFETY: our own safety conditions imply this reference is again unique. + unsafe { &mut *self.ptr.as_ptr() } + } +} + +#[cfg(test)] +mod tests; diff --git a/library/alloc/src/collections/btree/borrow/tests.rs b/library/alloc/src/collections/btree/borrow/tests.rs new file mode 100644 index 0000000000..56a8434fc7 --- /dev/null +++ b/library/alloc/src/collections/btree/borrow/tests.rs @@ -0,0 +1,19 @@ +use super::DormantMutRef; + +#[test] +fn test_borrow() { + let mut data = 1; + let mut stack = vec![]; + let mut rr = &mut data; + for factor in [2, 3, 7].iter() { + let (r, dormant_r) = DormantMutRef::new(rr); + rr = r; + assert_eq!(*rr, 1); + stack.push((factor, dormant_r)); + } + while let Some((factor, dormant_r)) = stack.pop() { + let r = unsafe { dormant_r.awaken() }; + *r *= factor; + } + assert_eq!(data, 42); +} diff --git a/library/alloc/src/collections/btree/map.rs b/library/alloc/src/collections/btree/map.rs index f8729c33c6..2b244a04d2 100644 --- a/library/alloc/src/collections/btree/map.rs +++ b/library/alloc/src/collections/btree/map.rs @@ -5,10 +5,10 @@ use core::hash::{Hash, Hasher}; use core::iter::{FromIterator, FusedIterator, Peekable}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop}; -use core::ops::Bound::{Excluded, Included, Unbounded}; use core::ops::{Index, RangeBounds}; use core::ptr; +use super::borrow::DormantMutRef; use super::node::{self, marker, ForceResult::*, Handle, InsertResult::*, NodeRef}; use super::search::{self, SearchResult::*}; use super::unwrap_unchecked; @@ -47,7 +47,6 @@ use UnderflowResult::*; /// any other key, as determined by the [`Ord`] trait, changes while it is in the map. This is /// normally only possible through [`Cell`], [`RefCell`], global state, I/O, or unsafe code. /// -/// [`Ord`]: core::cmp::Ord /// [`Cell`]: core::cell::Cell /// [`RefCell`]: core::cell::RefCell /// @@ -93,9 +92,10 @@ use UnderflowResult::*; /// } /// ``` /// -/// `BTreeMap` also implements an [`Entry API`](#method.entry), which allows -/// for more complex methods of getting, setting, updating and removing keys and -/// their values: +/// `BTreeMap` also implements an [`Entry API`], which allows for more complex +/// methods of getting, setting, updating and removing keys and their values: +/// +/// [`Entry API`]: BTreeMap::entry /// /// ``` /// use std::collections::BTreeMap; @@ -229,24 +229,23 @@ where } fn take(&mut self, key: &Q) -> Option { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); match search::search_tree(root_node, key) { - Found(handle) => Some( - OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData } - .remove_kv() - .0, - ), + Found(handle) => { + Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_kv().0) + } GoDown(_) => None, } } fn replace(&mut self, key: K) -> Option { - let root = Self::ensure_is_owned(&mut self.root); - match search::search_tree::, K, (), K>(root.node_as_mut(), &key) { + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + match search::search_tree::, K, (), K>(root_node, &key) { Found(handle) => Some(mem::replace(handle.into_key_mut(), key)), GoDown(handle) => { - VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData } - .insert(()); + VacantEntry { key, handle, dormant_map, _marker: PhantomData }.insert(()); None } } @@ -298,14 +297,23 @@ pub struct IntoIter { length: usize, } -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for IntoIter { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { +impl IntoIter { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { let range = Range { front: self.front.as_ref().map(|f| f.reborrow()), back: self.back.as_ref().map(|b| b.reborrow()), }; - f.debug_list().entries(range).finish() + + Iter { range: range, length: self.length } + } +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter()).finish() } } @@ -352,11 +360,17 @@ impl fmt::Debug for Values<'_, K, V> { /// /// [`values_mut`]: BTreeMap::values_mut #[stable(feature = "map_values_mut", since = "1.10.0")] -#[derive(Debug)] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, } +#[stable(feature = "map_values_mut", since = "1.10.0")] +impl fmt::Debug for ValuesMut<'_, K, V> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() + } +} + /// An owning iterator over the keys of a `BTreeMap`. /// /// This `struct` is created by the [`into_keys`] method on [`BTreeMap`]. @@ -364,11 +378,17 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// /// [`into_keys`]: BTreeMap::into_keys #[unstable(feature = "map_into_keys_values", issue = "75294")] -#[derive(Debug)] pub struct IntoKeys { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoKeys { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(key, _)| key)).finish() + } +} + /// An owning iterator over the values of a `BTreeMap`. /// /// This `struct` is created by the [`into_values`] method on [`BTreeMap`]. @@ -376,11 +396,17 @@ pub struct IntoKeys { /// /// [`into_values`]: BTreeMap::into_values #[unstable(feature = "map_into_keys_values", issue = "75294")] -#[derive(Debug)] pub struct IntoValues { inner: IntoIter, } +#[unstable(feature = "map_into_keys_values", issue = "75294")] +impl fmt::Debug for IntoValues { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() + } +} + /// An iterator over a sub-range of entries in a `BTreeMap`. /// /// This `struct` is created by the [`range`] method on [`BTreeMap`]. See its @@ -408,8 +434,8 @@ impl fmt::Debug for Range<'_, K, V> { /// [`range_mut`]: BTreeMap::range_mut #[stable(feature = "btree_range", since = "1.17.0")] pub struct RangeMut<'a, K: 'a, V: 'a> { - front: Option, K, V, marker::Leaf>, marker::Edge>>, - back: Option, K, V, marker::Leaf>, marker::Edge>>, + front: Option, K, V, marker::Leaf>, marker::Edge>>, + back: Option, K, V, marker::Leaf>, marker::Edge>>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -454,13 +480,11 @@ impl Debug for Entry<'_, K, V> { /// A view into a vacant entry in a `BTreeMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { key: K, handle: Handle, K, V, marker::Leaf>, marker::Edge>, - length: &'a mut usize, + dormant_map: DormantMutRef<'a, BTreeMap>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -475,13 +499,10 @@ impl Debug for VacantEntry<'_, K, V> { /// A view into an occupied entry in a `BTreeMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { handle: Handle, K, V, marker::LeafOrInternal>, marker::KV>, - - length: &'a mut usize, + dormant_map: DormantMutRef<'a, BTreeMap>, // Be invariant in `K` and `V` _marker: PhantomData<&'a mut (K, V)>, @@ -645,13 +666,10 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn first_entry(&mut self) -> Option> { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); let kv = root_node.first_leaf_edge().right_kv().ok()?; - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) + Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } /// Removes and returns the first element in the map. @@ -722,13 +740,10 @@ impl BTreeMap { /// ``` #[unstable(feature = "map_first_last", issue = "62924")] pub fn last_entry(&mut self) -> Option> { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); let kv = root_node.last_leaf_edge().left_kv().ok()?; - Some(OccupiedEntry { - handle: kv.forget_node_type(), - length: &mut self.length, - _marker: PhantomData, - }) + Some(OccupiedEntry { handle: kv.forget_node_type(), dormant_map, _marker: PhantomData }) } /// Removes and returns the last element in the map. @@ -902,12 +917,12 @@ impl BTreeMap { K: Borrow, Q: Ord, { - let root_node = self.root.as_mut()?.node_as_mut(); + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = map.root.as_mut()?.node_as_mut(); match search::search_tree(root_node, key) { - Found(handle) => Some( - OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData } - .remove_entry(), - ), + Found(handle) => { + Some(OccupiedEntry { handle, dormant_map, _marker: PhantomData }.remove_entry()) + } GoDown(_) => None, } } @@ -999,7 +1014,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &self.root { - let (f, b) = range_search(root.node_as_ref(), range); + let (f, b) = root.node_as_ref().range_search(range); Range { front: Some(f), back: Some(b) } } else { @@ -1045,7 +1060,7 @@ impl BTreeMap { R: RangeBounds, { if let Some(root) = &mut self.root { - let (f, b) = range_search(root.node_as_mut(), range); + let (f, b) = root.node_as_valmut().range_search(range); RangeMut { front: Some(f), back: Some(b), _marker: PhantomData } } else { @@ -1074,13 +1089,12 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn entry(&mut self, key: K) -> Entry<'_, K, V> { // FIXME(@porglezomp) Avoid allocating if we don't insert - let root = Self::ensure_is_owned(&mut self.root); - match search::search_tree(root.node_as_mut(), &key) { - Found(handle) => { - Occupied(OccupiedEntry { handle, length: &mut self.length, _marker: PhantomData }) - } + let (map, dormant_map) = DormantMutRef::new(self); + let root_node = Self::ensure_is_owned(&mut map.root).node_as_mut(); + match search::search_tree(root_node, &key) { + Found(handle) => Occupied(OccupiedEntry { handle, dormant_map, _marker: PhantomData }), GoDown(handle) => { - Vacant(VacantEntry { key, handle, length: &mut self.length, _marker: PhantomData }) + Vacant(VacantEntry { key, handle, dormant_map, _marker: PhantomData }) } } } @@ -1285,9 +1299,17 @@ impl BTreeMap { } pub(super) fn drain_filter_inner(&mut self) -> DrainFilterInner<'_, K, V> { - let root_node = self.root.as_mut().map(|r| r.node_as_mut()); - let front = root_node.map(|rn| rn.first_leaf_edge()); - DrainFilterInner { length: &mut self.length, cur_leaf_edge: front } + if let Some(root) = self.root.as_mut() { + let (root, dormant_root) = DormantMutRef::new(root); + let front = root.node_as_mut().first_leaf_edge(); + DrainFilterInner { + length: &mut self.length, + dormant_root: Some(dormant_root), + cur_leaf_edge: Some(front), + } + } else { + DrainFilterInner { length: &mut self.length, dormant_root: None, cur_leaf_edge: None } + } } /// Creates a consuming iterator visiting all the keys, in sorted order. @@ -1470,6 +1492,14 @@ impl ExactSizeIterator for IterMut<'_, K, V> { #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for IterMut<'_, K, V> {} +impl<'a, K, V> IterMut<'a, K, V> { + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Iter<'_, K, V> { + Iter { range: self.range.iter(), length: self.length } + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl IntoIterator for BTreeMap { type Item = (K, V); @@ -1478,7 +1508,7 @@ impl IntoIterator for BTreeMap { fn into_iter(self) -> IntoIter { let mut me = ManuallyDrop::new(self); if let Some(root) = me.root.take() { - let (f, b) = full_range_search(root.into_ref()); + let (f, b) = root.into_ref().full_range(); IntoIter { front: Some(f), back: Some(b), length: me.length } } else { @@ -1672,6 +1702,9 @@ where /// of the predicate, thus also serving for BTreeSet::DrainFilter. pub(super) struct DrainFilterInner<'a, K: 'a, V: 'a> { length: &'a mut usize, + // dormant_root is wrapped in an Option to be able to `take` it. + dormant_root: Option>>, + // cur_leaf_edge is wrapped in an Option because maps without root lack a leaf edge. cur_leaf_edge: Option, K, V, marker::Leaf>, marker::Edge>>, } @@ -1717,7 +1750,7 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { /// Allow Debug implementations to predict the next element. pub(super) fn peek(&self) -> Option<(&K, &V)> { let edge = self.cur_leaf_edge.as_ref()?; - edge.reborrow().next_kv().ok().map(|kv| kv.into_kv()) + edge.reborrow().next_kv().ok().map(Handle::into_kv) } /// Implementation of a typical `DrainFilter::next` method, given the predicate. @@ -1729,7 +1762,13 @@ impl<'a, K: 'a, V: 'a> DrainFilterInner<'a, K, V> { let (k, v) = kv.kv_mut(); if pred(k, v) { *self.length -= 1; - let (kv, pos) = kv.remove_kv_tracking(); + let (kv, pos) = kv.remove_kv_tracking(|| { + // SAFETY: we will touch the root in a way that will not + // invalidate the position returned. + let root = unsafe { self.dormant_root.take().unwrap().awaken() }; + root.pop_internal_level(); + self.dormant_root = Some(DormantMutRef::new(root).1); + }); self.cur_leaf_edge = Some(pos); return Some(kv); } @@ -1942,9 +1981,18 @@ impl<'a, K, V> RangeMut<'a, K, V> { self.front == self.back } - unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { unwrap_unchecked(self.front.as_mut()).next_unchecked() } } + + /// Returns an iterator of references over the remaining items. + #[inline] + pub(super) fn iter(&self) -> Range<'_, K, V> { + Range { + front: self.front.as_ref().map(|f| f.reborrow()), + back: self.back.as_ref().map(|b| b.reborrow()), + } + } } #[stable(feature = "btree_range", since = "1.17.0")] @@ -1963,7 +2011,7 @@ impl<'a, K, V> DoubleEndedIterator for RangeMut<'a, K, V> { impl FusedIterator for RangeMut<'_, K, V> {} impl<'a, K, V> RangeMut<'a, K, V> { - unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { unsafe { unwrap_unchecked(self.back.as_mut()).next_back_unchecked() } } } @@ -2073,119 +2121,6 @@ where } } -/// Finds the leaf edges delimiting a specified range in or underneath a node. -fn range_search>( - root: NodeRef, - range: R, -) -> ( - Handle, marker::Edge>, - Handle, marker::Edge>, -) -where - Q: Ord, - K: Borrow, -{ - match (range.start_bound(), range.end_bound()) { - (Excluded(s), Excluded(e)) if s == e => { - panic!("range start and end are equal and excluded in BTreeMap") - } - (Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => { - panic!("range start is greater than range end in BTreeMap") - } - _ => {} - }; - - // We duplicate the root NodeRef here -- we will never access it in a way - // that overlaps references obtained from the root. - let mut min_node = unsafe { ptr::read(&root) }; - let mut max_node = root; - let mut min_found = false; - let mut max_found = false; - - loop { - let front = match (min_found, range.start_bound()) { - (false, Included(key)) => match search::search_node(min_node, key) { - Found(kv) => { - min_found = true; - kv.left_edge() - } - GoDown(edge) => edge, - }, - (false, Excluded(key)) => match search::search_node(min_node, key) { - Found(kv) => { - min_found = true; - kv.right_edge() - } - GoDown(edge) => edge, - }, - (true, Included(_)) => min_node.last_edge(), - (true, Excluded(_)) => min_node.first_edge(), - (_, Unbounded) => min_node.first_edge(), - }; - - let back = match (max_found, range.end_bound()) { - (false, Included(key)) => match search::search_node(max_node, key) { - Found(kv) => { - max_found = true; - kv.right_edge() - } - GoDown(edge) => edge, - }, - (false, Excluded(key)) => match search::search_node(max_node, key) { - Found(kv) => { - max_found = true; - kv.left_edge() - } - GoDown(edge) => edge, - }, - (true, Included(_)) => max_node.first_edge(), - (true, Excluded(_)) => max_node.last_edge(), - (_, Unbounded) => max_node.last_edge(), - }; - - if front.partial_cmp(&back) == Some(Ordering::Greater) { - panic!("Ord is ill-defined in BTreeMap range"); - } - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return (f, b); - } - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - } - _ => unreachable!("BTreeMap has different depths"), - }; - } -} - -/// Equivalent to `range_search(k, v, ..)` without the `Ord` bound. -fn full_range_search( - root: NodeRef, -) -> ( - Handle, marker::Edge>, - Handle, marker::Edge>, -) { - // We duplicate the root NodeRef here -- we will never access it in a way - // that overlaps references obtained from the root. - let mut min_node = unsafe { ptr::read(&root) }; - let mut max_node = root; - loop { - let front = min_node.first_edge(); - let back = max_node.last_edge(); - match (front.force(), back.force()) { - (Leaf(f), Leaf(b)) => { - return (f, b); - } - (Internal(min_int), Internal(max_int)) => { - min_node = min_int.descend(); - max_node = max_int.descend(); - } - _ => unreachable!("BTreeMap has different depths"), - }; - } -} - impl BTreeMap { /// Gets an iterator over the entries of the map, sorted by key. /// @@ -2211,7 +2146,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, K, V> { if let Some(root) = &self.root { - let (f, b) = full_range_search(root.node_as_ref()); + let (f, b) = root.node_as_ref().full_range(); Iter { range: Range { front: Some(f), back: Some(b) }, length: self.length } } else { @@ -2243,7 +2178,7 @@ impl BTreeMap { #[stable(feature = "rust1", since = "1.0.0")] pub fn iter_mut(&mut self) -> IterMut<'_, K, V> { if let Some(root) = &mut self.root { - let (f, b) = full_range_search(root.node_as_mut()); + let (f, b) = root.node_as_valmut().full_range(); IterMut { range: RangeMut { front: Some(f), back: Some(b), _marker: PhantomData }, @@ -2570,13 +2505,20 @@ impl<'a, K: Ord, V> VacantEntry<'a, K, V> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(self, value: V) -> &'a mut V { - *self.length += 1; - let out_ptr = match self.handle.insert_recursing(self.key, value) { - (Fit(_), val_ptr) => val_ptr, + (Fit(_), val_ptr) => { + // Safety: We have consumed self.handle and the handle returned. + let map = unsafe { self.dormant_map.awaken() }; + map.length += 1; + val_ptr + } (Split(ins), val_ptr) => { - let root = ins.left.into_root_mut(); + drop(ins.left); + // Safety: We have consumed self.handle and the reference returned. + let map = unsafe { self.dormant_map.awaken() }; + let root = map.root.as_mut().unwrap(); root.push_internal_level().push(ins.k, ins.v, ins.right); + map.length += 1; val_ptr } }; @@ -2652,7 +2594,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// If you need a reference to the `OccupiedEntry` that may outlive the /// destruction of the `Entry` value, see [`into_mut`]. /// - /// [`into_mut`]: #method.into_mut + /// [`into_mut`]: OccupiedEntry::into_mut /// /// # Examples /// @@ -2682,7 +2624,7 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { /// /// If you need multiple references to the `OccupiedEntry`, see [`get_mut`]. /// - /// [`get_mut`]: #method.get_mut + /// [`get_mut`]: OccupiedEntry::get_mut /// /// # Examples /// @@ -2750,9 +2692,15 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { // Body of `remove_entry`, separate to keep the above implementations short. fn remove_kv(self) -> (K, V) { - *self.length -= 1; - - let (old_kv, _) = self.handle.remove_kv_tracking(); + let mut emptied_internal_root = false; + let (old_kv, _) = self.handle.remove_kv_tracking(|| emptied_internal_root = true); + // SAFETY: we consumed the intermediate root borrow, `self.handle`. + let map = unsafe { self.dormant_map.awaken() }; + map.length -= 1; + if emptied_internal_root { + let root = map.root.as_mut().unwrap(); + root.pop_internal_level(); + } old_kv } } @@ -2760,8 +2708,9 @@ impl<'a, K: Ord, V> OccupiedEntry<'a, K, V> { impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInternal>, marker::KV> { /// Removes a key/value-pair from the map, and returns that pair, as well as /// the leaf edge corresponding to that former pair. - fn remove_kv_tracking( + fn remove_kv_tracking( self, + handle_emptied_internal_root: F, ) -> ((K, V), Handle, K, V, marker::Leaf>, marker::Edge>) { let (old_kv, mut pos, was_internal) = match self.force() { Leaf(leaf) => { @@ -2814,7 +2763,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter // The parent that was just emptied must be the root, // because nodes on a lower level would not have been // left with a single child. - parent.into_root_mut().pop_internal_level(); + handle_emptied_internal_root(); break; } else { cur_node = parent.forget_type(); @@ -2826,7 +2775,7 @@ impl<'a, K: 'a, V: 'a> Handle, K, V, marker::LeafOrInter if stole_from_left && at_leaf { // SAFETY: This is safe since we just added an element to our node. unsafe { - pos.next_unchecked(); + pos.move_next_unchecked(); } } break; @@ -2910,8 +2859,8 @@ enum UnderflowResult<'a, K, V> { Stole(bool), } -fn handle_underfull_node( - node: NodeRef, K, V, marker::LeafOrInternal>, +fn handle_underfull_node<'a, K: 'a, V: 'a>( + node: NodeRef, K, V, marker::LeafOrInternal>, ) -> UnderflowResult<'_, K, V> { let parent = match node.ascend() { Ok(parent) => parent, diff --git a/library/alloc/src/collections/btree/map/tests.rs b/library/alloc/src/collections/btree/map/tests.rs index eb8d86b969..8018514fa1 100644 --- a/library/alloc/src/collections/btree/map/tests.rs +++ b/library/alloc/src/collections/btree/map/tests.rs @@ -77,7 +77,8 @@ impl<'a, K: 'a, V: 'a> BTreeMap { let min_len = if is_root { 0 } else { node::MIN_LEN }; assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); - for &key in node.keys() { + for idx in 0..node.len() { + let key = *unsafe { node.key_at(idx) }; checker.is_ascending(key); } leaf_length += node.len(); @@ -87,6 +88,11 @@ impl<'a, K: 'a, V: 'a> BTreeMap { let min_len = if is_root { 1 } else { node::MIN_LEN }; assert!(node.len() >= min_len, "{} < {}", node.len(), min_len); + for idx in 0..=node.len() { + let edge = unsafe { node::Handle::new_edge(node, idx) }; + assert!(edge.descend().ascend().ok().unwrap() == edge); + } + internal_length += node.len(); } Position::InternalKV(kv) => { @@ -120,7 +126,13 @@ impl<'a, K: 'a, V: 'a> BTreeMap { Position::Leaf(leaf) => { let depth = root_node.height(); let indent = " ".repeat(depth); - result += &format!("\n{}{:?}", indent, leaf.keys()) + result += &format!("\n{}", indent); + for idx in 0..leaf.len() { + if idx > 0 { + result += ", "; + } + result += &format!("{:?}", unsafe { leaf.key_at(idx) }); + } } Position::Internal(_) => {} Position::InternalKV(kv) => { @@ -432,7 +444,6 @@ fn test_iter_mut_mutation() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_values_mut() { let mut a: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_2).map(|i| (i, i)).collect(); test_all_refs(&mut 13, a.values_mut()); @@ -455,7 +466,6 @@ fn test_values_mut_mutation() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_entering_root_twice() { let mut map: BTreeMap<_, _> = (0..2).map(|i| (i, i)).collect(); let mut it = map.iter_mut(); @@ -471,7 +481,6 @@ fn test_iter_entering_root_twice() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_descending_to_same_node_twice() { let mut map: BTreeMap<_, _> = (0..MIN_INSERTS_HEIGHT_1).map(|i| (i, i)).collect(); let mut it = map.iter_mut(); @@ -515,7 +524,6 @@ fn test_iter_mixed() { } #[test] -#[cfg_attr(miri, ignore)] // FIXME: fails in Miri fn test_iter_min_max() { let mut a = BTreeMap::new(); assert_eq!(a.iter().min(), None); @@ -1415,6 +1423,146 @@ fn test_variance() { } } +#[test] +#[allow(dead_code)] +fn test_sync() { + fn map(v: &BTreeMap) -> impl Sync + '_ { + v + } + + fn into_iter(v: BTreeMap) -> impl Sync { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Sync { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Sync { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Sync + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Sync + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Sync + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Sync + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Sync + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Sync + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Sync + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Sync + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + +#[test] +#[allow(dead_code)] +fn test_send() { + fn map(v: BTreeMap) -> impl Send { + v + } + + fn into_iter(v: BTreeMap) -> impl Send { + v.into_iter() + } + + fn into_keys(v: BTreeMap) -> impl Send { + v.into_keys() + } + + fn into_values(v: BTreeMap) -> impl Send { + v.into_values() + } + + fn drain_filter(v: &mut BTreeMap) -> impl Send + '_ { + v.drain_filter(|_, _| false) + } + + fn iter(v: &BTreeMap) -> impl Send + '_ { + v.iter() + } + + fn iter_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.iter_mut() + } + + fn keys(v: &BTreeMap) -> impl Send + '_ { + v.keys() + } + + fn values(v: &BTreeMap) -> impl Send + '_ { + v.values() + } + + fn values_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.values_mut() + } + + fn range(v: &BTreeMap) -> impl Send + '_ { + v.range(..) + } + + fn range_mut(v: &mut BTreeMap) -> impl Send + '_ { + v.range_mut(..) + } + + fn entry(v: &mut BTreeMap) -> impl Send + '_ { + v.entry(Default::default()) + } + + fn occupied_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Occupied(entry) => entry, + _ => unreachable!(), + } + } + + fn vacant_entry(v: &mut BTreeMap) -> impl Send + '_ { + match v.entry(Default::default()) { + Vacant(entry) => entry, + _ => unreachable!(), + } + } +} + #[test] fn test_occupied_entry_key() { let mut a = BTreeMap::new(); @@ -1703,3 +1851,17 @@ fn test_into_values() { assert!(values.contains(&'b')); assert!(values.contains(&'c')); } + +#[test] +fn test_insert_remove_intertwined() { + let loops = if cfg!(miri) { 100 } else { 1_000_000 }; + let mut map = BTreeMap::new(); + let mut i = 1; + for _ in 0..loops { + i = (i + 421) & 0xFF; + map.insert(i, i); + map.remove(&(0xFF - i)); + } + + map.check(); +} diff --git a/library/alloc/src/collections/btree/mod.rs b/library/alloc/src/collections/btree/mod.rs index 6c8a588eb5..ecbdacda4b 100644 --- a/library/alloc/src/collections/btree/mod.rs +++ b/library/alloc/src/collections/btree/mod.rs @@ -1,3 +1,4 @@ +mod borrow; pub mod map; mod navigate; mod node; @@ -13,6 +14,9 @@ trait Recover { fn replace(&mut self, key: Self::Key) -> Option; } +/// Same purpose as `Option::unwrap` but doesn't always guarantee a panic +/// if the option contains no value. +/// SAFETY: the caller must ensure that the option contains a value. #[inline(always)] pub unsafe fn unwrap_unchecked(val: Option) -> T { val.unwrap_or_else(|| { diff --git a/library/alloc/src/collections/btree/navigate.rs b/library/alloc/src/collections/btree/navigate.rs index b7b66ac7ce..55ce7d2754 100644 --- a/library/alloc/src/collections/btree/navigate.rs +++ b/library/alloc/src/collections/btree/navigate.rs @@ -1,10 +1,210 @@ +use core::borrow::Borrow; +use core::cmp::Ordering; use core::intrinsics; use core::mem; +use core::ops::Bound::{Excluded, Included, Unbounded}; +use core::ops::RangeBounds; use core::ptr; use super::node::{marker, ForceResult::*, Handle, NodeRef}; +use super::search::{self, SearchResult}; use super::unwrap_unchecked; +/// Finds the leaf edges delimiting a specified range in or underneath a node. +fn range_search( + root1: NodeRef, + root2: NodeRef, + range: R, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) +where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, +{ + match (range.start_bound(), range.end_bound()) { + (Excluded(s), Excluded(e)) if s == e => { + panic!("range start and end are equal and excluded in BTreeMap") + } + (Included(s) | Excluded(s), Included(e) | Excluded(e)) if s > e => { + panic!("range start is greater than range end in BTreeMap") + } + _ => {} + }; + + let mut min_node = root1; + let mut max_node = root2; + let mut min_found = false; + let mut max_found = false; + + loop { + let front = match (min_found, range.start_bound()) { + (false, Included(key)) => match search::search_node(min_node, key) { + SearchResult::Found(kv) => { + min_found = true; + kv.left_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (false, Excluded(key)) => match search::search_node(min_node, key) { + SearchResult::Found(kv) => { + min_found = true; + kv.right_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (true, Included(_)) => min_node.last_edge(), + (true, Excluded(_)) => min_node.first_edge(), + (_, Unbounded) => min_node.first_edge(), + }; + + let back = match (max_found, range.end_bound()) { + (false, Included(key)) => match search::search_node(max_node, key) { + SearchResult::Found(kv) => { + max_found = true; + kv.right_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (false, Excluded(key)) => match search::search_node(max_node, key) { + SearchResult::Found(kv) => { + max_found = true; + kv.left_edge() + } + SearchResult::GoDown(edge) => edge, + }, + (true, Included(_)) => max_node.first_edge(), + (true, Excluded(_)) => max_node.last_edge(), + (_, Unbounded) => max_node.last_edge(), + }; + + if front.partial_cmp(&back) == Some(Ordering::Greater) { + panic!("Ord is ill-defined in BTreeMap range"); + } + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + +/// Equivalent to `range_search(k, v, ..)` but without the `Ord` bound. +fn full_range( + root1: NodeRef, + root2: NodeRef, +) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, +) { + let mut min_node = root1; + let mut max_node = root2; + loop { + let front = min_node.first_edge(); + let back = max_node.last_edge(); + match (front.force(), back.force()) { + (Leaf(f), Leaf(b)) => { + return (f, b); + } + (Internal(min_int), Internal(max_int)) => { + min_node = min_int.descend(); + max_node = max_int.descend(); + } + _ => unreachable!("BTreeMap has different depths"), + }; + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + /// Creates a pair of leaf edges delimiting a specified range in or underneath a node. + pub fn range_search( + self, + range: R, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) + where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, + { + range_search(self, self, range) + } + + /// Returns (self.first_leaf_edge(), self.last_leaf_edge()), but more efficiently. + pub fn full_range( + self, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) { + full_range(self, self) + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { + /// Splits a unique reference into a pair of leaf edges delimiting a specified range. + /// The result are non-unique references allowing (some) mutation, which must be used + /// carefully. + pub fn range_search( + self, + range: R, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) + where + Q: ?Sized + Ord, + K: Borrow, + R: RangeBounds, + { + // We duplicate the root NodeRef here -- we will never visit the same KV + // twice, and never end up with overlapping value references. + let self2 = unsafe { ptr::read(&self) }; + range_search(self, self2, range) + } + + /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. + /// The results are non-unique references allowing mutation (of values only), so must be used + /// with care. + pub fn full_range( + self, + ) -> ( + Handle, K, V, marker::Leaf>, marker::Edge>, + Handle, K, V, marker::Leaf>, marker::Edge>, + ) { + // We duplicate the root NodeRef here -- we will never visit the same KV + // twice, and never end up with overlapping value references. + let self2 = unsafe { ptr::read(&self) }; + full_range(self, self2) + } +} + +impl NodeRef { + /// Splits a unique reference into a pair of leaf edges delimiting the full range of the tree. + /// The results are non-unique references allowing massively destructive mutation, so must be + /// used with the utmost care. + pub fn full_range( + self, + ) -> ( + Handle, marker::Edge>, + Handle, marker::Edge>, + ) { + // We duplicate the root NodeRef here -- we will never access it in a way + // that overlaps references obtained from the root. + let self2 = unsafe { ptr::read(&self) }; + full_range(self, self2) + } +} + impl Handle, marker::Edge> { /// Given a leaf edge handle, returns [`Result::Ok`] with a handle to the neighboring KV /// on the right side, which is either in the same leaf node or in an ancestor node. @@ -18,7 +218,7 @@ impl Handle, marker::E let mut edge = self.forget_node_type(); loop { edge = match edge.right_kv() { - Ok(internal_kv) => return Ok(internal_kv), + Ok(kv) => return Ok(kv), Err(last_edge) => match last_edge.into_node().ascend() { Ok(parent_edge) => parent_edge.forget_node_type(), Err(root) => return Err(root), @@ -39,7 +239,7 @@ impl Handle, marker::E let mut edge = self.forget_node_type(); loop { edge = match edge.left_kv() { - Ok(internal_kv) => return Ok(internal_kv), + Ok(kv) => return Ok(kv), Err(last_edge) => match last_edge.into_node().ascend() { Ok(parent_edge) => parent_edge.forget_node_type(), Err(root) => return Err(root), @@ -75,12 +275,13 @@ impl Handle, marke macro_rules! def_next_kv_uncheched_dealloc { { unsafe fn $name:ident : $adjacent_kv:ident } => { /// Given a leaf edge handle into an owned tree, returns a handle to the next KV, - /// while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree. - /// - The node pointed at by the given handle, and its ancestors, may be deallocated, - /// while the reference to those nodes in the surviving ancestors is left dangling; - /// thus using the returned handle to navigate further is dangerous. + /// while deallocating any node left behind yet leaving the corresponding edge + /// in its parent node dangling. + /// + /// # Safety + /// - The leaf edge must not be the last one in the direction travelled. + /// - The node carrying the next KV returned must not have been deallocated by a + /// previous call on any handle obtained for this tree. unsafe fn $name ( leaf_edge: Handle, marker::Edge>, ) -> Handle, marker::KV> { @@ -103,6 +304,15 @@ macro_rules! def_next_kv_uncheched_dealloc { def_next_kv_uncheched_dealloc! {unsafe fn next_kv_unchecked_dealloc: right_kv} def_next_kv_uncheched_dealloc! {unsafe fn next_back_kv_unchecked_dealloc: left_kv} +/// This replaces the value behind the `v` unique reference by calling the +/// relevant function. +/// +/// If a panic occurs in the `change` closure, the entire process will be aborted. +#[inline] +fn take_mut(v: &mut T, change: impl FnOnce(T) -> T) { + replace(v, |value| (change(value), ())) +} + /// This replaces the value behind the `v` unique reference by calling the /// relevant function, and returns a result obtained along the way. /// @@ -128,7 +338,9 @@ fn replace(v: &mut T, change: impl FnOnce(T) -> (T, R)) -> R { impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns references to the /// key and value in between. - /// Unsafe because the caller must ensure that the leaf edge is not the last one in the tree. + /// + /// # Safety + /// There must be another KV in the direction travelled. pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a V) { replace(self, |leaf_edge| { let kv = leaf_edge.next_kv(); @@ -139,7 +351,9 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed /// Moves the leaf edge handle to the previous leaf edge and returns references to the /// key and value in between. - /// Unsafe because the caller must ensure that the leaf edge is not the first one in the tree. + /// + /// # Safety + /// There must be another KV in the direction travelled. pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a V) { replace(self, |leaf_edge| { let kv = leaf_edge.next_back_kv(); @@ -149,53 +363,65 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Ed } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns references to the /// key and value in between. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree. - /// - Using the updated handle may well invalidate the returned references. - pub unsafe fn next_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn next_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = replace(self, |leaf_edge| { let kv = leaf_edge.next_kv(); let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_leaf_edge(), kv) }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + // Doing this last is faster, according to benchmarks. + kv.into_kv_valmut() } /// Moves the leaf edge handle to the previous leaf and returns references to the /// key and value in between. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the first one in the tree. - /// - Using the updated handle may well invalidate the returned references. - pub unsafe fn next_back_unchecked(&mut self) -> (&'a mut K, &'a mut V) { + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn next_back_unchecked(&mut self) -> (&'a K, &'a mut V) { let kv = replace(self, |leaf_edge| { let kv = leaf_edge.next_back_kv(); let kv = unsafe { unwrap_unchecked(kv.ok()) }; (unsafe { ptr::read(&kv) }.next_back_leaf_edge(), kv) }); - // Doing the descend (and perhaps another move) invalidates the references - // returned by `into_kv_mut`, so we have to do this last. - kv.into_kv_mut() + // Doing this last is faster, according to benchmarks. + kv.into_kv_valmut() + } +} + +impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { + /// Moves the leaf edge handle to the next leaf edge. + /// + /// # Safety + /// There must be another KV in the direction travelled. + pub unsafe fn move_next_unchecked(&mut self) { + take_mut(self, |leaf_edge| { + let kv = leaf_edge.next_kv(); + let kv = unsafe { unwrap_unchecked(kv.ok()) }; + kv.next_leaf_edge() + }) } } impl Handle, marker::Edge> { /// Moves the leaf edge handle to the next leaf edge and returns the key and value - /// in between, while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the last one in the tree - /// and is not a handle previously resulting from counterpart `next_back_unchecked`. - /// - Further use of the updated leaf edge handle is very dangerous. In particular, - /// if the leaf edge is the last edge of a node, that node and possibly ancestors - /// will be deallocated, while the reference to those nodes in the surviving ancestor - /// is left dangling. - /// The only safe way to proceed with the updated handle is to compare it, drop it, - /// call this method again subject to both preconditions listed in the first point, - /// or call counterpart `next_back_unchecked` subject to its preconditions. + /// in between, deallocating any node left behind while leaving the corresponding + /// edge in its parent node dangling. + /// + /// # Safety + /// - There must be another KV in the direction travelled. + /// - That KV was not previously returned by counterpart `next_back_unchecked` + /// on any copy of the handles being used to traverse the tree. + /// + /// The only safe way to proceed with the updated handle is to compare it, drop it, + /// call this method again subject to its safety conditions, or call counterpart + /// `next_back_unchecked` subject to its safety conditions. pub unsafe fn next_unchecked(&mut self) -> (K, V) { replace(self, |leaf_edge| { let kv = unsafe { next_kv_unchecked_dealloc(leaf_edge) }; @@ -205,18 +431,18 @@ impl Handle, marker::Edge> { }) } - /// Moves the leaf edge handle to the previous leaf edge and returns the key - /// and value in between, while deallocating any node left behind. - /// Unsafe for two reasons: - /// - The caller must ensure that the leaf edge is not the first one in the tree - /// and is not a handle previously resulting from counterpart `next_unchecked`. - /// - Further use of the updated leaf edge handle is very dangerous. In particular, - /// if the leaf edge is the first edge of a node, that node and possibly ancestors - /// will be deallocated, while the reference to those nodes in the surviving ancestor - /// is left dangling. - /// The only safe way to proceed with the updated handle is to compare it, drop it, - /// call this method again subject to both preconditions listed in the first point, - /// or call counterpart `next_unchecked` subject to its preconditions. + /// Moves the leaf edge handle to the previous leaf edge and returns the key and value + /// in between, deallocating any node left behind while leaving the corresponding + /// edge in its parent node dangling. + /// + /// # Safety + /// - There must be another KV in the direction travelled. + /// - That leaf edge was not previously returned by counterpart `next_unchecked` + /// on any copy of the handles being used to traverse the tree. + /// + /// The only safe way to proceed with the updated handle is to compare it, drop it, + /// call this method again subject to its safety conditions, or call counterpart + /// `next_unchecked` subject to its safety conditions. pub unsafe fn next_back_unchecked(&mut self) -> (K, V) { replace(self, |leaf_edge| { let kv = unsafe { next_back_kv_unchecked_dealloc(leaf_edge) }; diff --git a/library/alloc/src/collections/btree/node.rs b/library/alloc/src/collections/btree/node.rs index acc2ae7357..ba08f65f90 100644 --- a/library/alloc/src/collections/btree/node.rs +++ b/library/alloc/src/collections/btree/node.rs @@ -12,7 +12,7 @@ // edges: if height > 0 { // [Box>; 2 * B] // } else { () }, -// parent: *const Node, +// parent: Option>>, // parent_idx: u16, // len: u16, // } @@ -47,12 +47,10 @@ const KV_IDX_CENTER: usize = B - 1; const EDGE_IDX_LEFT_OF_CENTER: usize = B - 1; const EDGE_IDX_RIGHT_OF_CENTER: usize = B; -/// The underlying representation of leaf nodes. -#[repr(C)] +/// The underlying representation of leaf nodes and part of the representation of internal nodes. struct LeafNode { - /// We use `*const` as opposed to `*mut` so as to be covariant in `K` and `V`. - /// This either points to an actual node or is null. - parent: *const InternalNode, + /// We want to be covariant in `K` and `V`. + parent: Option>>, /// This node's index into the parent node's `edges` array. /// `*node.parent.edges[node.parent_idx]` should be the same thing as `node`. @@ -60,9 +58,6 @@ struct LeafNode { parent_idx: MaybeUninit, /// The number of keys and values this node stores. - /// - /// This next to `parent_idx` to encourage the compiler to join `len` and - /// `parent_idx` into the same 32-bit word, reducing space overhead. len: u16, /// The arrays storing the actual data of the node. Only the first `len` elements of each @@ -78,9 +73,9 @@ impl LeafNode { LeafNode { // As a general policy, we leave fields uninitialized if they can be, as this should // be both slightly faster and easier to track in Valgrind. - keys: [MaybeUninit::UNINIT; CAPACITY], - vals: [MaybeUninit::UNINIT; CAPACITY], - parent: ptr::null(), + keys: MaybeUninit::uninit_array(), + vals: MaybeUninit::uninit_array(), + parent: None, parent_idx: MaybeUninit::uninit(), len: 0, } @@ -93,7 +88,9 @@ impl LeafNode { /// node, allowing code to act on leaf and internal nodes generically without having to even check /// which of the two a pointer is pointing at. This property is enabled by the use of `repr(C)`. #[repr(C)] +// gdb_providers.py uses this type name for introspection. struct InternalNode { + // gdb_providers.py uses this field name for introspection. data: LeafNode, /// The pointers to the children of this node. `len + 1` of these are considered @@ -111,7 +108,7 @@ impl InternalNode { /// `len` of 0), there must be one initialized and valid edge. This function does not set up /// such an edge. unsafe fn new() -> Self { - InternalNode { data: unsafe { LeafNode::new() }, edges: [MaybeUninit::UNINIT; 2 * B] } + InternalNode { data: unsafe { LeafNode::new() }, edges: MaybeUninit::uninit_array() } } } @@ -131,7 +128,7 @@ impl BoxedNode { } fn from_internal(node: Box>) -> Self { - BoxedNode { ptr: Box::into_unique(node).cast() } + BoxedNode { ptr: Unique::from(&mut Box::leak(node).data) } } unsafe fn from_ptr(ptr: NonNull>) -> Self { @@ -168,36 +165,25 @@ impl Root { /// Borrows and returns an immutable reference to the node owned by the root. pub fn node_as_ref(&self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null(), - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } /// Borrows and returns a mutable reference to the node owned by the root. pub fn node_as_mut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } + } + + pub fn node_as_valmut(&mut self) -> NodeRef, K, V, marker::LeafOrInternal> { + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } pub fn into_ref(self) -> NodeRef { - NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: ptr::null(), - _marker: PhantomData, - } + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData } } - /// Adds a new internal node with a single edge, pointing to the previous root, and make that - /// new node the root. This increases the height by 1 and is the opposite of - /// `pop_internal_level`. + /// Adds a new internal node with a single edge pointing to the previous root node, + /// make that new node the root node, and return it. This increases the height by 1 + /// and is the opposite of `pop_internal_level`. pub fn push_internal_level(&mut self) -> NodeRef, K, V, marker::Internal> { let mut new_node = Box::new(unsafe { InternalNode::new() }); new_node.edges[0].write(unsafe { BoxedNode::from_ptr(self.node.as_ptr()) }); @@ -205,12 +191,8 @@ impl Root { self.node = BoxedNode::from_internal(new_node); self.height += 1; - let mut ret = NodeRef { - height: self.height, - node: self.node.as_ptr(), - root: self as *mut _, - _marker: PhantomData, - }; + let mut ret = + NodeRef { height: self.height, node: self.node.as_ptr(), _marker: PhantomData }; unsafe { ret.reborrow_mut().first_edge().correct_parent_link(); @@ -219,11 +201,15 @@ impl Root { ret } - /// Removes the internal root node, using its first child as the new root. - /// As it is intended only to be called when the root has only one child, - /// no cleanup is done on any of the other children of the root. + /// Removes the internal root node, using its first child as the new root node. + /// As it is intended only to be called when the root node has only one child, + /// no cleanup is done on any of the other children. /// This decreases the height by 1 and is the opposite of `push_internal_level`. - /// Panics if there is no internal level, i.e. if the root is a leaf. + /// + /// Requires exclusive access to the `Root` object but not to the root node; + /// it will not invalidate existing handles or references to the root node. + /// + /// Panics if there is no internal level, i.e., if the root node is a leaf. pub fn pop_internal_level(&mut self) { assert!(self.height > 0); @@ -235,9 +221,7 @@ impl Root { ) }; self.height -= 1; - unsafe { - (*self.node_as_mut().as_leaf_mut()).parent = ptr::null(); - } + self.node_as_mut().as_leaf_mut().parent = None; unsafe { Global.dealloc(NonNull::from(top).cast(), Layout::new::>()); @@ -253,9 +237,12 @@ impl Root { /// A reference to a node. /// /// This type has a number of parameters that controls how it acts: -/// - `BorrowType`: This can be `Immut<'a>` or `Mut<'a>` for some `'a` or `Owned`. +/// - `BorrowType`: This can be `Immut<'a>`, `Mut<'a>` or `ValMut<'a>' for some `'a` +/// or `Owned`. /// When this is `Immut<'a>`, the `NodeRef` acts roughly like `&'a Node`, /// when this is `Mut<'a>`, the `NodeRef` acts roughly like `&'a mut Node`, +/// when this is `ValMut<'a>`, the `NodeRef` acts as immutable with respect +/// to keys and tree structure, but allows mutable references to values, /// and when this is `Owned`, the `NodeRef` acts roughly like `Box`. /// - `K` and `V`: These control what types of things are stored in the nodes. /// - `Type`: This can be `Leaf`, `Internal`, or `LeafOrInternal`. When this is @@ -266,8 +253,6 @@ pub struct NodeRef { /// The number of levels below the node. height: usize, node: NonNull>, - // `root` is null unless the borrow type is `Mut` - root: *const Root, _marker: PhantomData<(BorrowType, Type)>, } @@ -282,15 +267,31 @@ unsafe impl Sync for NodeRef Send for NodeRef, K, V, Type> {} unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} +unsafe impl<'a, K: Send + 'a, V: Send + 'a, Type> Send for NodeRef, K, V, Type> {} unsafe impl Send for NodeRef {} impl NodeRef { - fn as_internal(&self) -> &InternalNode { - unsafe { &*(self.node.as_ptr() as *mut InternalNode) } + /// Exposes the data of an internal node for reading. + /// + /// Returns a raw ptr to avoid invalidating other references to this node, + /// which is possible when BorrowType is marker::ValMut. + fn as_internal_ptr(&self) -> *const InternalNode { + self.node.as_ptr() as *const InternalNode } } impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Exposes the data of an internal node for reading, + /// when we know we have exclusive access. + fn as_internal(&mut self) -> &InternalNode { + unsafe { &*self.as_internal_ptr() } + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// Exposes the data of an internal node for writing. + /// + /// We don't need to return a raw ptr because we have unique access to the entire node. fn as_internal_mut(&mut self) -> &mut InternalNode { unsafe { &mut *(self.node.as_ptr() as *mut InternalNode) } } @@ -303,7 +304,9 @@ impl NodeRef { /// Note that, despite being safe, calling this function can have the side effect /// of invalidating mutable references that unsafe code has created. pub fn len(&self) -> usize { - self.as_leaf().len as usize + // Crucially, we only access the `len` field here. If BorrowType is marker::ValMut, + // there might be outstanding mutable references to values that we must not invalidate. + unsafe { usize::from((*self.as_leaf_ptr()).len) } } /// Returns the height of this node in the whole tree. Zero height denotes the @@ -314,30 +317,54 @@ impl NodeRef { /// Temporarily takes out another, immutable reference to the same node. fn reborrow(&self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - /// Exposes the leaf "portion" of any leaf or internal node. + /// Exposes the leaf portion of any leaf or internal node. /// If the node is a leaf, this function simply opens up its data. /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. - fn as_leaf(&self) -> &LeafNode { + /// + /// Returns a raw ptr to avoid invalidating other references to this node, + /// which is possible when BorrowType is marker::ValMut. + fn as_leaf_ptr(&self) -> *const LeafNode { // The node must be valid for at least the LeafNode portion. // This is not a reference in the NodeRef type because we don't know if // it should be unique or shared. - unsafe { self.node.as_ref() } + self.node.as_ptr() } - /// Borrows a view into the keys stored in the node. - pub fn keys(&self) -> &[K] { - self.reborrow().into_key_slice() + /// Borrows a reference to one of the keys stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn key_at(&self, idx: usize) -> &K { + unsafe { self.reborrow().into_key_at(idx) } } - /// Borrows a view into the values stored in the node. - fn vals(&self) -> &[V] { - self.reborrow().into_val_slice() + /// Borrows a reference to one of the values stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn val_at(&self, idx: usize) -> &V { + unsafe { self.reborrow().into_val_at(idx) } } +} +impl NodeRef { + /// Borrows a reference to the contents of one of the edges that delimit + /// the elements of the node, without invalidating other references. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn edge_at(&self, idx: usize) -> &BoxedNode { + debug_assert!(idx <= self.len()); + let node = self.as_internal_ptr(); + unsafe { (*node).edges.get_unchecked(idx).assume_init_ref() } + } +} + +impl NodeRef { /// Finds the parent of the current node. Returns `Ok(handle)` if the current /// node actually has a parent, where `handle` points to the edge of the parent /// that points to the current node. Returns `Err(self)` if the current node has @@ -348,21 +375,21 @@ impl NodeRef { pub fn ascend( self, ) -> Result, marker::Edge>, Self> { - let parent_as_leaf = self.as_leaf().parent as *const LeafNode; - if let Some(non_zero) = NonNull::new(parent_as_leaf as *mut _) { - Ok(Handle { + // We need to use raw pointers to nodes because, if BorrowType is marker::ValMut, + // there might be outstanding mutable references to values that we must not invalidate. + let leaf_ptr = self.as_leaf_ptr(); + unsafe { (*leaf_ptr).parent } + .as_ref() + .map(|parent| Handle { node: NodeRef { height: self.height + 1, - node: non_zero, - root: self.root, + node: parent.cast(), _marker: PhantomData, }, - idx: unsafe { usize::from(*self.as_leaf().parent_idx.as_ptr()) }, + idx: unsafe { usize::from((*leaf_ptr).parent_idx.assume_init()) }, _marker: PhantomData, }) - } else { - Err(self) - } + .ok_or(self) } pub fn first_edge(self) -> Handle { @@ -389,6 +416,15 @@ impl NodeRef { } } +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// Exposes the data of a leaf node for reading in an immutable tree. + fn into_leaf(self) -> &'a LeafNode { + // SAFETY: we can access the entire node freely and do no need raw pointers, + // because there can be no mutable references to this Immut tree. + unsafe { &(*self.as_leaf_ptr()) } + } +} + impl NodeRef { /// Similar to `ascend`, gets a reference to a node's parent node, but also /// deallocate the current node in the process. This is unsafe because the @@ -417,168 +453,208 @@ impl<'a, K, V, Type> NodeRef, K, V, Type> { /// Unsafely asserts to the compiler some static information about whether this /// node is a `Leaf` or an `Internal`. unsafe fn cast_unchecked(self) -> NodeRef, K, V, NewType> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } /// Temporarily takes out another, mutable reference to the same node. Beware, as /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + /// Because mutable pointers can roam anywhere around the tree, the returned + /// pointer can easily be used to make the original pointer dangling, out of + /// bounds, or invalid under stacked borrow rules. + // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` + // that restricts the use of navigation methods on reborrowed pointers, + // preventing this unsafety. unsafe fn reborrow_mut(&mut self) -> NodeRef, K, V, Type> { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } - /// Exposes the leaf "portion" of any leaf or internal node for writing. + /// Exposes the leaf portion of any leaf or internal node for writing. /// If the node is a leaf, this function simply opens up its data. /// If the node is an internal node, so not a leaf, it does have all the data a leaf has /// (header, keys and values), and this function exposes that. /// - /// Returns a raw ptr to avoid asserting exclusive access to the entire node. - fn as_leaf_mut(&mut self) -> *mut LeafNode { - self.node.as_ptr() + /// We don't need to return a raw ptr because we have unique access to the entire node. + fn as_leaf_mut(&mut self) -> &'a mut LeafNode { + unsafe { &mut (*self.node.as_ptr()) } } - fn keys_mut(&mut self) -> &mut [K] { + /// Borrows a mutable reference to one of the keys stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn key_mut_at(&mut self, idx: usize) -> &mut K { + unsafe { self.reborrow_mut().into_key_mut_at(idx) } + } + + /// Borrows a mutable reference to one of the values stored in the node. + /// + /// # Safety + /// The node has more than `idx` initialized elements. + pub unsafe fn val_mut_at(&mut self, idx: usize) -> &mut V { + unsafe { self.reborrow_mut().into_val_mut_at(idx) } + } + + fn keys_mut(&mut self) -> &mut [K] + where + K: 'a, + V: 'a, + { // SAFETY: the caller will not be able to call further methods on self // until the key slice reference is dropped, as we have unique access // for the lifetime of the borrow. - unsafe { self.reborrow_mut().into_key_slice_mut() } - } - - fn vals_mut(&mut self) -> &mut [V] { - // SAFETY: the caller will not be able to call further methods on self - // until the value slice reference is dropped, as we have unique access - // for the lifetime of the borrow. - unsafe { self.reborrow_mut().into_val_slice_mut() } - } -} - -impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - fn into_key_slice(self) -> &'a [K] { - unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().keys), self.len()) } - } - - fn into_val_slice(self) -> &'a [V] { - unsafe { slice::from_raw_parts(MaybeUninit::first_ptr(&self.as_leaf().vals), self.len()) } - } -} - -impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { - /// Gets a mutable reference to the root itself. This is useful primarily when the - /// height of the tree needs to be adjusted. Never call this on a reborrowed pointer. - pub fn into_root_mut(self) -> &'a mut Root { - unsafe { &mut *(self.root as *mut Root) } - } - - fn into_key_slice_mut(mut self) -> &'a mut [K] { // SAFETY: The keys of a node must always be initialized up to length. unsafe { slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).keys), + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().keys), self.len(), ) } } - fn into_val_slice_mut(mut self) -> &'a mut [V] { + fn vals_mut(&mut self) -> &mut [V] + where + K: 'a, + V: 'a, + { + // SAFETY: the caller will not be able to call further methods on self + // until the value slice reference is dropped, as we have unique access + // for the lifetime of the borrow. // SAFETY: The values of a node must always be initialized up to length. unsafe { slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut (*self.as_leaf_mut()).vals), + MaybeUninit::slice_as_mut_ptr(&mut self.as_leaf_mut().vals), self.len(), ) } } - - fn into_slices_mut(mut self) -> (&'a mut [K], &'a mut [V]) { - // We cannot use the getters here, because calling the second one - // invalidates the reference returned by the first. - // More precisely, it is the call to `len` that is the culprit, - // because that creates a shared reference to the header, which *can* - // overlap with the keys (and even the values, for ZST keys). - let len = self.len(); - let leaf = self.as_leaf_mut(); - // SAFETY: The keys and values of a node must always be initialized up to length. - let keys = unsafe { - slice::from_raw_parts_mut(MaybeUninit::first_ptr_mut(&mut (*leaf).keys), len) - }; - let vals = unsafe { - slice::from_raw_parts_mut(MaybeUninit::first_ptr_mut(&mut (*leaf).vals), len) - }; - (keys, vals) - } -} - -impl<'a, K, V> NodeRef, K, V, marker::Leaf> { - /// Adds a key/value pair to the end of the node. - pub fn push(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); - - let idx = self.len(); - - unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - - (*self.as_leaf_mut()).len += 1; - } - } - - /// Adds a key/value pair to the beginning of the node. - pub fn push_front(&mut self, key: K, val: V) { - assert!(self.len() < CAPACITY); - - unsafe { - slice_insert(self.keys_mut(), 0, key); - slice_insert(self.vals_mut(), 0, val); - - (*self.as_leaf_mut()).len += 1; - } - } } impl<'a, K, V> NodeRef, K, V, marker::Internal> { - /// Adds a key/value pair and an edge to go to the right of that pair to - /// the end of the node. - pub fn push(&mut self, key: K, val: V, edge: Root) { - assert!(edge.height == self.height - 1); - assert!(self.len() < CAPACITY); - - let idx = self.len(); - + fn edges_mut(&mut self) -> &mut [BoxedNode] { unsafe { - ptr::write(self.keys_mut().get_unchecked_mut(idx), key); - ptr::write(self.vals_mut().get_unchecked_mut(idx), val); - self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node); + slice::from_raw_parts_mut( + MaybeUninit::slice_as_mut_ptr(&mut self.as_internal_mut().edges), + self.len() + 1, + ) + } + } +} - (*self.as_leaf_mut()).len += 1; +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_at(self, idx: usize) -> &'a K { + unsafe { self.into_leaf().keys.get_unchecked(idx).assume_init_ref() } + } - Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_val_at(self, idx: usize) -> &'a V { + unsafe { self.into_leaf().vals.get_unchecked(idx).assume_init_ref() } + } +} + +impl<'a, K: 'a, V: 'a, Type> NodeRef, K, V, Type> { + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_mut_at(mut self, idx: usize) -> &'a mut K { + debug_assert!(idx < self.len()); + + let leaf = self.as_leaf_mut(); + unsafe { leaf.keys.get_unchecked_mut(idx).assume_init_mut() } + } + + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_val_mut_at(mut self, idx: usize) -> &'a mut V { + debug_assert!(idx < self.len()); + + let leaf = self.as_leaf_mut(); + unsafe { leaf.vals.get_unchecked_mut(idx).assume_init_mut() } + } +} + +impl<'a, K, V, Type> NodeRef, K, V, Type> { + /// # Safety + /// The node has more than `idx` initialized elements. + unsafe fn into_key_val_mut_at(self, idx: usize) -> (&'a K, &'a mut V) { + // We only create a reference to the one element we are interested in, + // to avoid aliasing with outstanding references to other elements, + // in particular, those returned to the caller in earlier iterations. + let leaf = self.node.as_ptr(); + // We must coerce to unsized array pointers because of Rust issue #74679. + let keys: *const [_] = unsafe { &raw const (*leaf).keys }; + let vals: *mut [_] = unsafe { &raw mut (*leaf).vals }; + // SAFETY: The keys and values of a node must always be initialized up to length. + let key = unsafe { (&*keys.get_unchecked(idx)).assume_init_ref() }; + let val = unsafe { (&mut *vals.get_unchecked_mut(idx)).assume_init_mut() }; + (key, val) + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Leaf> { + /// Adds a key/value pair to the end of the node. + pub fn push(&mut self, key: K, val: V) { + let len = &mut self.as_leaf_mut().len; + let idx = usize::from(*len); + assert!(idx < CAPACITY); + *len += 1; + unsafe { + ptr::write(self.key_mut_at(idx), key); + ptr::write(self.val_mut_at(idx), val); } } - // Unsafe because 'first' and 'after_last' must be in range - unsafe fn correct_childrens_parent_links(&mut self, first: usize, after_last: usize) { - debug_assert!(first <= self.len()); - debug_assert!(after_last <= self.len() + 1); - for i in first..after_last { + /// Adds a key/value pair to the beginning of the node. + fn push_front(&mut self, key: K, val: V) { + debug_assert!(self.len() < CAPACITY); + + unsafe { + slice_insert(self.keys_mut(), 0, key); + slice_insert(self.vals_mut(), 0, val); + } + self.as_leaf_mut().len += 1; + } +} + +impl<'a, K, V> NodeRef, K, V, marker::Internal> { + /// # Safety + /// Every item returned by `range` is a valid edge index for the node. + unsafe fn correct_childrens_parent_links>(&mut self, range: R) { + for i in range { + debug_assert!(i <= self.len()); unsafe { Handle::new_edge(self.reborrow_mut(), i) }.correct_parent_link(); } } fn correct_all_childrens_parent_links(&mut self) { let len = self.len(); - unsafe { self.correct_childrens_parent_links(0, len + 1) }; + unsafe { self.correct_childrens_parent_links(0..=len) }; + } +} + +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::Internal> { + /// Adds a key/value pair, and an edge to go to the right of that pair, + /// to the end of the node. + pub fn push(&mut self, key: K, val: V, edge: Root) { + assert!(edge.height == self.height - 1); + + let len = &mut self.as_leaf_mut().len; + let idx = usize::from(*len); + assert!(idx < CAPACITY); + *len += 1; + unsafe { + ptr::write(self.key_mut_at(idx), key); + ptr::write(self.val_mut_at(idx), val); + self.as_internal_mut().edges.get_unchecked_mut(idx + 1).write(edge.node); + Handle::new_edge(self.reborrow_mut(), idx + 1).correct_parent_link(); + } } - /// Adds a key/value pair and an edge to go to the left of that pair to - /// the beginning of the node. + /// Adds a key/value pair, and an edge to go to the left of that pair, + /// to the beginning of the node. pub fn push_front(&mut self, key: K, val: V, edge: Root) { assert!(edge.height == self.height - 1); assert!(self.len() < CAPACITY); @@ -588,53 +664,52 @@ impl<'a, K, V> NodeRef, K, V, marker::Internal> { slice_insert(self.vals_mut(), 0, val); slice_insert( slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut self.as_internal_mut().edges), + MaybeUninit::slice_as_mut_ptr(&mut self.as_internal_mut().edges), self.len() + 1, ), 0, edge.node, ); - - (*self.as_leaf_mut()).len += 1; - - self.correct_all_childrens_parent_links(); } + + self.as_leaf_mut().len += 1; + + self.correct_all_childrens_parent_links(); } } -impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { +impl<'a, K: 'a, V: 'a> NodeRef, K, V, marker::LeafOrInternal> { /// Removes a key/value pair from the end of this node and returns the pair. /// If this is an internal node, also removes the edge that was to the right - /// of that pair and returns the orphaned node that this edge owned with its - /// parent erased. - pub fn pop(&mut self) -> (K, V, Option>) { - assert!(self.len() > 0); + /// of that pair and returns the orphaned node that this edge owned. + fn pop(&mut self) -> (K, V, Option>) { + debug_assert!(self.len() > 0); let idx = self.len() - 1; unsafe { - let key = ptr::read(self.keys().get_unchecked(idx)); - let val = ptr::read(self.vals().get_unchecked(idx)); + let key = ptr::read(self.key_at(idx)); + let val = ptr::read(self.val_at(idx)); let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(internal) => { - let edge = - ptr::read(internal.as_internal().edges.get_unchecked(idx + 1).as_ptr()); + let edge = ptr::read(internal.edge_at(idx + 1)); let mut new_root = Root { node: edge, height: internal.height - 1 }; - (*new_root.node_as_mut().as_leaf_mut()).parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = None; Some(new_root) } }; - (*self.as_leaf_mut()).len -= 1; + self.as_leaf_mut().len -= 1; (key, val, edge) } } - /// Removes a key/value pair from the beginning of this node. If this is an internal node, - /// also removes the edge that was to the left of that pair. - pub fn pop_front(&mut self) -> (K, V, Option>) { - assert!(self.len() > 0); + /// Removes a key/value pair from the beginning of this node and returns the pair. + /// If this is an internal node, also removes the edge that was to the left + /// of that pair and returns the orphaned node that this edge owned. + fn pop_front(&mut self) -> (K, V, Option>) { + debug_assert!(self.len() > 0); let old_len = self.len(); @@ -644,26 +719,17 @@ impl<'a, K, V> NodeRef, K, V, marker::LeafOrInternal> { let edge = match self.reborrow_mut().force() { ForceResult::Leaf(_) => None, ForceResult::Internal(mut internal) => { - let edge = slice_remove( - slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut internal.as_internal_mut().edges), - old_len + 1, - ), - 0, - ); - + let edge = slice_remove(internal.edges_mut(), 0); let mut new_root = Root { node: edge, height: internal.height - 1 }; - (*new_root.node_as_mut().as_leaf_mut()).parent = ptr::null(); + new_root.node_as_mut().as_leaf_mut().parent = None; - for i in 0..old_len { - Handle::new_edge(internal.reborrow_mut(), i).correct_parent_link(); - } + internal.correct_childrens_parent_links(0..old_len); Some(new_root) } }; - (*self.as_leaf_mut()).len -= 1; + self.as_leaf_mut().len -= 1; (key, val, edge) } @@ -686,14 +752,12 @@ impl NodeRef { ForceResult::Leaf(NodeRef { height: self.height, node: self.node, - root: self.root, _marker: PhantomData, }) } else { ForceResult::Internal(NodeRef { height: self.height, node: self.node, - root: self.root, _marker: PhantomData, }) } @@ -784,12 +848,7 @@ impl<'a, K, V, NodeType, HandleType> Handle, K, V, NodeT /// this method is very dangerous, doubly so since it may not immediately appear /// dangerous. /// - /// Because mutable pointers can roam anywhere around the tree and can even (through - /// `into_root_mut`) mess with the root of the tree, the result of `reborrow_mut` - /// can easily be used to make the original mutable pointer dangling, or, in the case - /// of a reborrowed handle, out of bounds. - // FIXME(@gereeter) consider adding yet another type parameter to `NodeRef` that restricts - // the use of `ascend` and `into_root_mut` on reborrowed pointers, preventing this unsafety. + /// For details, see `NodeRef::reborrow_mut`. pub unsafe fn reborrow_mut( &mut self, ) -> Handle, K, V, NodeType>, HandleType> { @@ -845,26 +904,25 @@ fn splitpoint(edge_idx: usize) -> (usize, InsertionPlace) { } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::Edge> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::Edge> { /// Helps implementations of `insert_fit` for a particular `NodeType`, /// by taking care of leaf data. /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. fn leafy_insert_fit(&mut self, key: K, val: V) { - // Necessary for correctness, but in a private module debug_assert!(self.node.len() < CAPACITY); unsafe { slice_insert(self.node.keys_mut(), self.idx, key); slice_insert(self.node.vals_mut(), self.idx, val); - (*self.node.as_leaf_mut()).len += 1; + self.node.as_leaf_mut().len += 1; } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method assumes that there is enough space in the node for the new /// pair to fit. @@ -872,37 +930,37 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge /// The returned pointer points to the inserted value. fn insert_fit(&mut self, key: K, val: V) -> *mut V { self.leafy_insert_fit(key, val); - unsafe { self.node.vals_mut().get_unchecked_mut(self.idx) } + unsafe { self.node.val_mut_at(self.idx) } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room. /// /// The returned pointer points to the inserted value. fn insert(mut self, key: K, val: V) -> (InsertResult<'a, K, V, marker::Leaf>, *mut V) { if self.node.len() < CAPACITY { - let ptr = self.insert_fit(key, val); + let val_ptr = self.insert_fit(key, val); let kv = unsafe { Handle::new_kv(self.node, self.idx) }; - (InsertResult::Fit(kv), ptr) + (InsertResult::Fit(kv), val_ptr) } else { let (middle_kv_idx, insertion) = splitpoint(self.idx); let middle = unsafe { Handle::new_kv(self.node, middle_kv_idx) }; let (mut left, k, v, mut right) = middle.split(); - let ptr = match insertion { + let mut insertion_edge = match insertion { InsertionPlace::Left(insert_idx) => unsafe { - Handle::new_edge(left.reborrow_mut(), insert_idx).insert_fit(key, val) + Handle::new_edge(left.reborrow_mut(), insert_idx) }, InsertionPlace::Right(insert_idx) => unsafe { Handle::new_edge( right.node_as_mut().cast_unchecked::(), insert_idx, ) - .insert_fit(key, val) }, }; - (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), ptr) + let val_ptr = insertion_edge.insert_fit(key, val); + (InsertResult::Split(SplitResult { left: left.forget_type(), k, v, right }), val_ptr) } } } @@ -912,37 +970,25 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: /// when the ordering of edges has been changed, such as in the various `insert` methods. fn correct_parent_link(mut self) { let idx = self.idx as u16; - let ptr = self.node.as_internal_mut() as *mut _; + let ptr = NonNull::new(self.node.as_internal_mut()); let mut child = self.descend(); - unsafe { - (*child.as_leaf_mut()).parent = ptr; - (*child.as_leaf_mut()).parent_idx.write(idx); - } + child.as_leaf_mut().parent = ptr; + child.as_leaf_mut().parent_idx.write(idx); } +} +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::Edge> { /// Inserts a new key/value pair and an edge that will go to the right of that new pair /// between this edge and the key/value pair to the right of this edge. This method assumes /// that there is enough space in the node for the new pair to fit. fn insert_fit(&mut self, key: K, val: V, edge: Root) { - // Necessary for correctness, but in an internal module - debug_assert!(self.node.len() < CAPACITY); debug_assert!(edge.height == self.node.height - 1); unsafe { + slice_insert(self.node.edges_mut(), self.idx + 1, edge.node); self.leafy_insert_fit(key, val); - slice_insert( - slice::from_raw_parts_mut( - MaybeUninit::first_ptr_mut(&mut self.node.as_internal_mut().edges), - self.node.len(), - ), - self.idx + 1, - edge.node, - ); - - for i in (self.idx + 1)..(self.node.len() + 1) { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } + self.node.correct_childrens_parent_links((self.idx + 1)..=self.node.len()); } } @@ -982,7 +1028,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: } } -impl<'a, K: 'a, V> Handle, K, V, marker::Leaf>, marker::Edge> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::Edge> { /// Inserts a new key/value pair between the key/value pairs to the right and left of /// this edge. This method splits the node if there isn't enough room, and tries to /// insert the split off portion into the parent node recursively, until the root is reached. @@ -1024,12 +1070,17 @@ impl Handle, marke /// `edge.descend().ascend().unwrap()` and `node.ascend().unwrap().descend()` should /// both, upon success, do nothing. pub fn descend(self) -> NodeRef { + // We need to use raw pointers to nodes because, if BorrowType is + // marker::ValMut, there might be outstanding mutable references to + // values that we must not invalidate. There's no worry accessing the + // height field because that value is copied. Beware that, once the + // node pointer is dereferenced, we access the edges array with a + // reference (Rust issue #73987) and invalidate any other references + // to or inside the array, should any be around. + let internal_node = self.node.as_internal_ptr(); NodeRef { height: self.node.height - 1, - node: unsafe { - (&*self.node.as_internal().edges.get_unchecked(self.idx).as_ptr()).as_ptr() - }, - root: self.node.root, + node: unsafe { (&*(*internal_node).edges.get_unchecked(self.idx).as_ptr()).as_ptr() }, _marker: PhantomData, } } @@ -1037,74 +1088,71 @@ impl Handle, marke impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn into_kv(self) -> (&'a K, &'a V) { - let keys = self.node.into_key_slice(); - let vals = self.node.into_val_slice(); - unsafe { (keys.get_unchecked(self.idx), vals.get_unchecked(self.idx)) } + (unsafe { self.node.into_key_at(self.idx) }, unsafe { self.node.into_val_at(self.idx) }) } } impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn into_key_mut(self) -> &'a mut K { - let keys = self.node.into_key_slice_mut(); - unsafe { keys.get_unchecked_mut(self.idx) } + unsafe { self.node.into_key_mut_at(self.idx) } } pub fn into_val_mut(self) -> &'a mut V { - let vals = self.node.into_val_slice_mut(); - unsafe { vals.get_unchecked_mut(self.idx) } - } - - pub fn into_kv_mut(self) -> (&'a mut K, &'a mut V) { - unsafe { - let (keys, vals) = self.node.into_slices_mut(); - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) - } + unsafe { self.node.into_val_mut_at(self.idx) } } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { +impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { + pub fn into_kv_valmut(self) -> (&'a K, &'a mut V) { + unsafe { self.node.into_key_val_mut_at(self.idx) } + } +} + +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { pub fn kv_mut(&mut self) -> (&mut K, &mut V) { - unsafe { - let (keys, vals) = self.node.reborrow_mut().into_slices_mut(); - (keys.get_unchecked_mut(self.idx), vals.get_unchecked_mut(self.idx)) - } + // We cannot call into_key_mut_at and into_val_mut_at, because calling the second one + // invalidates the reference returned by the first. + let leaf = self.node.as_leaf_mut(); + let key = unsafe { leaf.keys.get_unchecked_mut(self.idx).assume_init_mut() }; + let val = unsafe { leaf.vals.get_unchecked_mut(self.idx).assume_init_mut() }; + (key, val) } } -impl<'a, K, V, NodeType> Handle, K, V, NodeType>, marker::KV> { +impl<'a, K: 'a, V: 'a, NodeType> Handle, K, V, NodeType>, marker::KV> { /// Helps implementations of `split` for a particular `NodeType`, /// by taking care of leaf data. fn leafy_split(&mut self, new_node: &mut LeafNode) -> (K, V, usize) { unsafe { - let k = ptr::read(self.node.keys().get_unchecked(self.idx)); - let v = ptr::read(self.node.vals().get_unchecked(self.idx)); + let k = ptr::read(self.node.key_at(self.idx)); + let v = ptr::read(self.node.val_at(self.idx)); let new_len = self.node.len() - self.idx - 1; ptr::copy_nonoverlapping( - self.node.keys().as_ptr().add(self.idx + 1), - new_node.keys.as_mut_ptr() as *mut K, + self.node.key_at(self.idx + 1), + MaybeUninit::slice_as_mut_ptr(&mut new_node.keys), new_len, ); ptr::copy_nonoverlapping( - self.node.vals().as_ptr().add(self.idx + 1), - new_node.vals.as_mut_ptr() as *mut V, + self.node.val_at(self.idx + 1), + MaybeUninit::slice_as_mut_ptr(&mut new_node.vals), new_len, ); - (*self.node.as_leaf_mut()).len = self.idx as u16; + self.node.as_leaf_mut().len = self.idx as u16; new_node.len = new_len as u16; (k, v, new_len) } } } -impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> { +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Leaf>, marker::KV> { /// Splits the underlying node into three parts: /// /// - The node is truncated to only contain the key/value pairs to the right of /// this handle. - /// - The key and value pointed to by this handle and extracted. + /// - The key and value pointed to by this handle are extracted. /// - All the key/value pairs to the right of this handle are put into a newly /// allocated node. pub fn split(mut self) -> (NodeRef, K, V, marker::Leaf>, K, V, Root) { @@ -1125,43 +1173,13 @@ impl<'a, K, V> Handle, K, V, marker::Leaf>, marker::KV> unsafe { let k = slice_remove(self.node.keys_mut(), self.idx); let v = slice_remove(self.node.vals_mut(), self.idx); - (*self.node.as_leaf_mut()).len -= 1; + self.node.as_leaf_mut().len -= 1; ((k, v), self.left_edge()) } } } impl<'a, K, V> Handle, K, V, marker::Internal>, marker::KV> { - /// Splits the underlying node into three parts: - /// - /// - The node is truncated to only contain the edges and key/value pairs to the - /// right of this handle. - /// - The key and value pointed to by this handle and extracted. - /// - All the edges and key/value pairs to the right of this handle are put into - /// a newly allocated node. - pub fn split(mut self) -> (NodeRef, K, V, marker::Internal>, K, V, Root) { - unsafe { - let mut new_node = Box::new(InternalNode::new()); - - let (k, v, new_len) = self.leafy_split(&mut new_node.data); - let height = self.node.height; - - ptr::copy_nonoverlapping( - self.node.as_internal().edges.as_ptr().add(self.idx + 1), - new_node.edges.as_mut_ptr(), - new_len + 1, - ); - - let mut new_root = Root { node: BoxedNode::from_internal(new_node), height }; - - for i in 0..(new_len + 1) { - Handle::new_edge(new_root.node_as_mut().cast_unchecked(), i).correct_parent_link(); - } - - (self.node, k, v, new_root) - } - } - /// Returns `true` if it is valid to call `.merge()`, i.e., whether there is enough room in /// a node to hold the combination of the nodes to the left and right of this handle along /// with the key/value pair at this handle. @@ -1171,6 +1189,37 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: + 1) <= CAPACITY } +} + +impl<'a, K: 'a, V: 'a> Handle, K, V, marker::Internal>, marker::KV> { + /// Splits the underlying node into three parts: + /// + /// - The node is truncated to only contain the edges and key/value pairs to the + /// right of this handle. + /// - The key and value pointed to by this handle are extracted. + /// - All the edges and key/value pairs to the right of this handle are put into + /// a newly allocated node. + pub fn split(mut self) -> (NodeRef, K, V, marker::Internal>, K, V, Root) { + unsafe { + let mut new_node = Box::new(InternalNode::new()); + + let (k, v, new_len) = self.leafy_split(&mut new_node.data); + let height = self.node.height; + let old_node = &*self.node.as_internal_ptr(); + + ptr::copy_nonoverlapping( + old_node.edges.as_ptr().add(self.idx + 1), + new_node.edges.as_mut_ptr(), + new_len + 1, + ); + + let mut new_root = Root { node: BoxedNode::from_internal(new_node), height }; + + new_root.node_as_mut().cast_unchecked().correct_childrens_parent_links(0..=new_len); + + (self.node, k, v, new_root) + } + } /// Combines the node immediately to the left of this handle, the key/value pair pointed /// to by this handle, and the node immediately to the right of this handle into one new @@ -1195,7 +1244,7 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: slice_remove(self.node.keys_mut(), self.idx), ); ptr::copy_nonoverlapping( - right_node.keys().as_ptr(), + right_node.key_at(0), left_node.keys_mut().as_mut_ptr().add(left_len + 1), right_len, ); @@ -1204,33 +1253,30 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: slice_remove(self.node.vals_mut(), self.idx), ); ptr::copy_nonoverlapping( - right_node.vals().as_ptr(), + right_node.val_at(0), left_node.vals_mut().as_mut_ptr().add(left_len + 1), right_len, ); - slice_remove(&mut self.node.as_internal_mut().edges, self.idx + 1); - for i in self.idx + 1..self.node.len() { - Handle::new_edge(self.node.reborrow_mut(), i).correct_parent_link(); - } - (*self.node.as_leaf_mut()).len -= 1; + slice_remove(&mut self.node.edges_mut(), self.idx + 1); + let self_len = self.node.len(); + self.node.correct_childrens_parent_links(self.idx + 1..self_len); + self.node.as_leaf_mut().len -= 1; - (*left_node.as_leaf_mut()).len += right_len as u16 + 1; + left_node.as_leaf_mut().len += right_len as u16 + 1; if self.node.height > 1 { // SAFETY: the height of the nodes being merged is one below the height // of the node of this edge, thus above zero, so they are internal. - let mut left_node = left_node.cast_unchecked(); - let right_node = right_node.cast_unchecked(); + let mut left_node = left_node.cast_unchecked::(); + let right_node = right_node.cast_unchecked::(); ptr::copy_nonoverlapping( - right_node.reborrow().as_internal().edges.as_ptr(), - left_node.reborrow_mut().as_internal_mut().edges.as_mut_ptr().add(left_len + 1), + right_node.edge_at(0), + left_node.edges_mut().as_mut_ptr().add(left_len + 1), right_len + 1, ); - for i in left_len + 1..left_len + right_len + 2 { - Handle::new_edge(left_node.reborrow_mut(), i).correct_parent_link(); - } + left_node.correct_childrens_parent_links(left_len + 1..=left_len + 1 + right_len); Global.dealloc(right_node.node.cast(), Layout::new::>()); } else { @@ -1312,22 +1358,20 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: move_kv(left_kv, new_left_len, parent_kv, 0, 1); } - (*left_node.reborrow_mut().as_leaf_mut()).len -= count as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len += count as u16; + left_node.as_leaf_mut().len -= count as u16; + right_node.as_leaf_mut().len += count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { // Make room for stolen edges. let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); ptr::copy(right_edges, right_edges.add(count), right_len + 1); - right.correct_childrens_parent_links(count, count + right_len + 1); + right.correct_childrens_parent_links(count..count + right_len + 1); move_edges(left, new_left_len + 1, right, 0, count); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1369,8 +1413,8 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: ptr::copy(right_kv.1.add(count), right_kv.1, new_right_len); } - (*left_node.reborrow_mut().as_leaf_mut()).len += count as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len -= count as u16; + left_node.as_leaf_mut().len += count as u16; + right_node.as_leaf_mut().len -= count as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(mut right)) => { @@ -1379,12 +1423,10 @@ impl<'a, K, V> Handle, K, V, marker::Internal>, marker:: // Fix right indexing. let right_edges = right.reborrow_mut().as_internal_mut().edges.as_mut_ptr(); ptr::copy(right_edges.add(count), right_edges, new_right_len + 1); - right.correct_childrens_parent_links(0, new_right_len + 1); + right.correct_childrens_parent_links(0..=new_right_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1411,25 +1453,25 @@ unsafe fn move_edges( dest_offset: usize, count: usize, ) { - let source_ptr = source.as_internal_mut().edges.as_mut_ptr(); + let source_ptr = source.as_internal().edges.as_ptr(); let dest_ptr = dest.as_internal_mut().edges.as_mut_ptr(); unsafe { ptr::copy_nonoverlapping(source_ptr.add(source_offset), dest_ptr.add(dest_offset), count); - dest.correct_childrens_parent_links(dest_offset, dest_offset + count); + dest.correct_childrens_parent_links(dest_offset..dest_offset + count); } } impl NodeRef { /// Removes any static information asserting that this node is a `Leaf` node. pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } impl NodeRef { /// Removes any static information asserting that this node is an `Internal` node. pub fn forget_type(self) -> NodeRef { - NodeRef { height: self.height, node: self.node, root: self.root, _marker: PhantomData } + NodeRef { height: self.height, node: self.node, _marker: PhantomData } } } @@ -1509,17 +1551,15 @@ impl<'a, K, V> Handle, K, V, marker::LeafOrInternal>, ma move_kv(left_kv, left_new_len, right_kv, 0, right_new_len); - (*left_node.reborrow_mut().as_leaf_mut()).len = left_new_len as u16; - (*right_node.reborrow_mut().as_leaf_mut()).len = right_new_len as u16; + left_node.as_leaf_mut().len = left_new_len as u16; + right_node.as_leaf_mut().len = right_new_len as u16; match (left_node.force(), right_node.force()) { (ForceResult::Internal(left), ForceResult::Internal(right)) => { move_edges(left, left_new_len + 1, right, 1, right_new_len); } (ForceResult::Leaf(_), ForceResult::Leaf(_)) => {} - _ => { - unreachable!(); - } + _ => unreachable!(), } } } @@ -1558,6 +1598,7 @@ pub mod marker { pub enum Owned {} pub struct Immut<'a>(PhantomData<&'a ()>); pub struct Mut<'a>(PhantomData<&'a mut ()>); + pub struct ValMut<'a>(PhantomData<&'a mut ()>); pub enum KV {} pub enum Edge {} diff --git a/library/alloc/src/collections/btree/node/tests.rs b/library/alloc/src/collections/btree/node/tests.rs index e2416974dd..54c3709821 100644 --- a/library/alloc/src/collections/btree/node/tests.rs +++ b/library/alloc/src/collections/btree/node/tests.rs @@ -23,3 +23,12 @@ fn test_splitpoint() { assert!(left_len + right_len == CAPACITY); } } + +#[test] +#[cfg(target_arch = "x86_64")] +fn test_sizes() { + assert_eq!(core::mem::size_of::>(), 16); + assert_eq!(core::mem::size_of::>(), 16 + CAPACITY * 8 * 2); + assert_eq!(core::mem::size_of::>(), 112); + assert_eq!(core::mem::size_of::>(), 112 + CAPACITY * 8 * 2); +} diff --git a/library/alloc/src/collections/btree/search.rs b/library/alloc/src/collections/btree/search.rs index 4e80f7f21e..1526c0673c 100644 --- a/library/alloc/src/collections/btree/search.rs +++ b/library/alloc/src/collections/btree/search.rs @@ -68,11 +68,11 @@ where K: Borrow, { // This function is defined over all borrow types (immutable, mutable, owned). - // Using `keys()` is fine here even if BorrowType is mutable, as all we return + // Using `keys_at()` is fine here even if BorrowType is mutable, as all we return // is an index -- not a reference. let len = node.len(); - let keys = node.keys(); - for (i, k) in keys.iter().enumerate() { + for i in 0..len { + let k = unsafe { node.key_at(i) }; match key.cmp(k.borrow()) { Ordering::Greater => {} Ordering::Equal => return (i, true), diff --git a/library/alloc/src/collections/linked_list.rs b/library/alloc/src/collections/linked_list.rs index 5390b57a1d..412c65681e 100644 --- a/library/alloc/src/collections/linked_list.rs +++ b/library/alloc/src/collections/linked_list.rs @@ -102,7 +102,7 @@ impl fmt::Debug for IterMut<'_, T> { /// This `struct` is created by the [`into_iter`] method on [`LinkedList`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.LinkedList.html#method.into_iter +/// [`into_iter`]: LinkedList::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/alloc/src/collections/vec_deque.rs b/library/alloc/src/collections/vec_deque.rs index d3c6d493d6..8e9acc42d9 100644 --- a/library/alloc/src/collections/vec_deque.rs +++ b/library/alloc/src/collections/vec_deque.rs @@ -14,8 +14,7 @@ use core::fmt; use core::hash::{Hash, Hasher}; use core::iter::{once, repeat_with, FromIterator, FusedIterator}; use core::mem::{self, replace, ManuallyDrop}; -use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{Index, IndexMut, RangeBounds, Try}; +use core::ops::{Index, IndexMut, Range, RangeBounds, Try}; use core::ptr::{self, NonNull}; use core::slice; @@ -33,12 +32,8 @@ mod tests; const INITIAL_CAPACITY: usize = 7; // 2^3 - 1 const MINIMUM_CAPACITY: usize = 1; // 2 - 1 -#[cfg(target_pointer_width = "16")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (16 - 1); // Largest possible power of two -#[cfg(target_pointer_width = "32")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (32 - 1); // Largest possible power of two -#[cfg(target_pointer_width = "64")] -const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of two + +const MAXIMUM_ZST_CAPACITY: usize = 1 << (core::mem::size_of::() * 8 - 1); // Largest possible power of two /// A double-ended queue implemented with a growable ring buffer. /// @@ -47,10 +42,17 @@ const MAXIMUM_ZST_CAPACITY: usize = 1 << (64 - 1); // Largest possible power of /// push onto the back in this manner, and iterating over `VecDeque` goes front /// to back. /// -/// [`push_back`]: #method.push_back -/// [`pop_front`]: #method.pop_front -/// [`extend`]: #method.extend -/// [`append`]: #method.append +/// Since `VecDeque` is a ring buffer, its elements are not necessarily contiguous +/// in memory. If you want to access the elements as a single slice, such as for +/// efficient sorting, you can use [`make_contiguous`]. It rotates the `VecDeque` +/// so that its elements do not wrap, and returns a mutable slice to the +/// now-contiguous element sequence. +/// +/// [`push_back`]: VecDeque::push_back +/// [`pop_front`]: VecDeque::pop_front +/// [`extend`]: VecDeque::extend +/// [`append`]: VecDeque::append +/// [`make_contiguous`]: VecDeque::make_contiguous #[cfg_attr(not(test), rustc_diagnostic_item = "vecdeque_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct VecDeque { @@ -638,7 +640,7 @@ impl VecDeque { /// assert!(buf.capacity() >= 11); /// ``` /// - /// [`reserve`]: #method.reserve + /// [`reserve`]: VecDeque::reserve #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve_exact(&mut self, additional: usize) { self.reserve(additional); @@ -678,7 +680,7 @@ impl VecDeque { } /// Tries to reserve the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `VecDeque`. After calling `reserve_exact`, + /// be inserted in the given `VecDeque`. After calling `try_reserve_exact`, /// capacity will be greater than or equal to `self.len() + additional`. /// Does nothing if the capacity is already sufficient. /// @@ -720,7 +722,7 @@ impl VecDeque { /// Tries to reserve capacity for at least `additional` more elements to be inserted /// in the given `VecDeque`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be + /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. /// @@ -985,8 +987,10 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. /// - /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements - /// of the `VecDeque` will be in the first slice and the second slice will be empty. + /// If [`make_contiguous`] was previously called, all elements of the + /// `VecDeque` will be in the first slice and the second slice will be empty. + /// + /// [`make_contiguous`]: VecDeque::make_contiguous /// /// # Examples /// @@ -1018,8 +1022,10 @@ impl VecDeque { /// Returns a pair of slices which contain, in order, the contents of the /// `VecDeque`. /// - /// If [`make_contiguous`](#method.make_contiguous) was previously called, all elements - /// of the `VecDeque` will be in the first slice and the second slice will be empty. + /// If [`make_contiguous`] was previously called, all elements of the + /// `VecDeque` will be in the first slice and the second slice will be empty. + /// + /// [`make_contiguous`]: VecDeque::make_contiguous /// /// # Examples /// @@ -1083,24 +1089,14 @@ impl VecDeque { self.tail == self.head } - fn range_start_end(&self, range: R) -> (usize, usize) + fn range_tail_head(&self, range: R) -> (usize, usize) where R: RangeBounds, { - let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; - assert!(start <= end, "lower bound was too large"); - assert!(end <= len, "upper bound was too large"); - (start, end) + let Range { start, end } = slice::check_range(self.len(), range); + let tail = self.wrap_add(self.tail, start); + let head = self.wrap_add(self.tail, end); + (tail, head) } /// Creates an iterator that covers the specified range in the `VecDeque`. @@ -1131,9 +1127,7 @@ impl VecDeque { where R: RangeBounds, { - let (start, end) = self.range_start_end(range); - let tail = self.wrap_add(self.tail, start); - let head = self.wrap_add(self.tail, end); + let (tail, head) = self.range_tail_head(range); Iter { tail, head, @@ -1174,9 +1168,7 @@ impl VecDeque { where R: RangeBounds, { - let (start, end) = self.range_start_end(range); - let tail = self.wrap_add(self.tail, start); - let head = self.wrap_add(self.tail, end); + let (tail, head) = self.range_tail_head(range); IterMut { tail, head, @@ -1230,7 +1222,7 @@ impl VecDeque { // When finished, the remaining data will be copied back to cover the hole, // and the head/tail values will be restored correctly. // - let (start, end) = self.range_start_end(range); + let (drain_tail, drain_head) = self.range_tail_head(range); // The deque's elements are parted into three segments: // * self.tail -> drain_tail @@ -1248,8 +1240,6 @@ impl VecDeque { // T t h H // [. . . o o x x o o . . .] // - let drain_tail = self.wrap_add(self.tail, start); - let drain_head = self.wrap_add(self.tail, end); let head = self.head; // "forget" about the values after the start of the drain until after @@ -2174,22 +2164,25 @@ impl VecDeque { } } - /// Rearranges the internal storage of this deque so it is one contiguous slice, which is then returned. + /// Rearranges the internal storage of this deque so it is one contiguous + /// slice, which is then returned. /// - /// This method does not allocate and does not change the order of the inserted elements. - /// As it returns a mutable slice, this can be used to sort or binary search a deque. + /// This method does not allocate and does not change the order of the + /// inserted elements. As it returns a mutable slice, this can be used to + /// sort or binary search a deque. /// - /// Once the internal storage is contiguous, the [`as_slices`](#method.as_slices) and - /// [`as_mut_slices`](#method.as_mut_slices) methods will return the entire contents of the + /// Once the internal storage is contiguous, the [`as_slices`] and + /// [`as_mut_slices`] methods will return the entire contents of the /// `VecDeque` in a single slice. /// + /// [`as_slices`]: VecDeque::as_slices + /// [`as_mut_slices`]: VecDeque::as_mut_slices + /// /// # Examples /// /// Sorting the content of a deque. /// /// ``` - /// #![feature(deque_make_contiguous)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::with_capacity(15); @@ -2210,8 +2203,6 @@ impl VecDeque { /// Getting immutable access to the contiguous slice. /// /// ```rust - /// #![feature(deque_make_contiguous)] - /// /// use std::collections::VecDeque; /// /// let mut buf = VecDeque::new(); @@ -2228,7 +2219,7 @@ impl VecDeque { /// assert_eq!(slice, &[3, 2, 1] as &[_]); /// } /// ``` - #[unstable(feature = "deque_make_contiguous", issue = "70929")] + #[stable(feature = "deque_make_contiguous", since = "1.48.0")] pub fn make_contiguous(&mut self) -> &mut [T] { if self.is_contiguous() { let tail = self.tail; @@ -2402,7 +2393,7 @@ impl VecDeque { } } - // Safety: the following two methods require that the rotation amount + // SAFETY: the following two methods require that the rotation amount // be less than half the length of the deque. // // `wrap_copy` requires that `min(x, cap() - x) + copy_len <= cap()`, @@ -2513,8 +2504,7 @@ fn count(tail: usize, head: usize, size: usize) -> usize { /// This `struct` is created by the [`iter`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`iter`]: struct.VecDeque.html#method.iter -/// [`VecDeque`]: struct.VecDeque.html +/// [`iter`]: VecDeque::iter #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, T: 'a> { ring: &'a [T], @@ -2668,8 +2658,7 @@ impl FusedIterator for Iter<'_, T> {} /// This `struct` is created by the [`iter_mut`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`iter_mut`]: struct.VecDeque.html#method.iter_mut -/// [`VecDeque`]: struct.VecDeque.html +/// [`iter_mut`]: VecDeque::iter_mut #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, T: 'a> { ring: &'a mut [T], @@ -2774,8 +2763,7 @@ impl FusedIterator for IterMut<'_, T> {} /// This `struct` is created by the [`into_iter`] method on [`VecDeque`] /// (provided by the `IntoIterator` trait). See its documentation for more. /// -/// [`into_iter`]: struct.VecDeque.html#method.into_iter -/// [`VecDeque`]: struct.VecDeque.html +/// [`into_iter`]: VecDeque::into_iter #[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/alloc/src/collections/vec_deque/drain.rs b/library/alloc/src/collections/vec_deque/drain.rs index 1ae94de75a..4ffb435d1e 100644 --- a/library/alloc/src/collections/vec_deque/drain.rs +++ b/library/alloc/src/collections/vec_deque/drain.rs @@ -9,8 +9,7 @@ use super::{count, Iter, VecDeque}; /// This `struct` is created by the [`drain`] method on [`VecDeque`]. See its /// documentation for more. /// -/// [`drain`]: struct.VecDeque.html#method.drain -/// [`VecDeque`]: struct.VecDeque.html +/// [`drain`]: VecDeque::drain #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { pub(crate) after_tail: usize, diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index 755a21934f..b33cb3ad8e 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -74,24 +74,25 @@ #![deny(unsafe_op_in_unsafe_fn)] #![cfg_attr(not(test), feature(generator_trait))] #![cfg_attr(test, feature(test))] +#![cfg_attr(test, feature(new_uninit))] #![feature(allocator_api)] #![feature(array_chunks)] +#![feature(array_windows)] #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(box_patterns)] #![feature(box_syntax)] -#![feature(btree_drain_filter)] #![feature(cfg_sanitize)] #![feature(cfg_target_has_atomic)] #![feature(coerce_unsized)] #![feature(const_btree_new)] +#![feature(const_fn)] #![feature(const_generics)] #![feature(const_in_array_repeat_expressions)] #![feature(cow_is_borrowed)] -#![feature(deque_range)] +#![feature(const_cow_is_borrowed)] #![feature(dispatch_from_dyn)] #![feature(core_intrinsics)] -#![feature(container_error_extra)] #![feature(dropck_eyepatch)] #![feature(exact_size_is_empty)] #![feature(exclusive_range_pattern)] @@ -99,14 +100,13 @@ #![feature(fmt_internals)] #![feature(fn_traits)] #![feature(fundamental)] -#![feature(internal_uninit_const)] +#![feature(inplace_iteration)] +#![feature(int_bits_const)] #![feature(lang_items)] #![feature(layout_for_ptr)] -#![feature(libc)] -#![feature(map_first_last)] -#![feature(map_into_keys_values)] +#![feature(maybe_uninit_ref)] #![feature(negative_impls)] -#![feature(new_uninit)] +#![feature(never_type)] #![feature(nll)] #![feature(nonnull_slice_from_raw_parts)] #![feature(optin_builtin_traits)] @@ -117,13 +117,12 @@ #![feature(rustc_attrs)] #![feature(receiver_trait)] #![feature(min_specialization)] +#![feature(slice_check_range)] #![feature(slice_ptr_get)] #![feature(slice_ptr_len)] #![feature(staged_api)] -#![feature(std_internals)] #![feature(str_internals)] #![feature(trusted_len)] -#![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unicode_internals)] #![feature(unsafe_block_in_unsafe_fn)] @@ -131,9 +130,11 @@ #![feature(unsized_locals)] #![feature(allocator_internals)] #![feature(slice_partition_dedup)] -#![feature(maybe_uninit_extra, maybe_uninit_slice)] +#![feature(maybe_uninit_extra, maybe_uninit_slice, maybe_uninit_uninit_array)] #![feature(alloc_layout_extra)] +#![feature(trusted_random_access)] #![feature(try_trait)] +#![feature(type_alias_impl_trait)] #![feature(associated_type_bounds)] // Allow testing this library diff --git a/library/alloc/src/raw_vec.rs b/library/alloc/src/raw_vec.rs index 247b636c80..1844d3ae00 100644 --- a/library/alloc/src/raw_vec.rs +++ b/library/alloc/src/raw_vec.rs @@ -3,6 +3,7 @@ use core::alloc::LayoutErr; use core::cmp; +use core::intrinsics; use core::mem::{self, ManuallyDrop, MaybeUninit}; use core::ops::Drop; use core::ptr::{NonNull, Unique}; @@ -149,6 +150,7 @@ impl RawVec { impl RawVec { /// Like `new`, but parameterized over the choice of allocator for /// the returned `RawVec`. + #[allow_internal_unstable(const_fn)] pub const fn new_in(alloc: A) -> Self { // `cap: 0` means "unallocated". zero-sized types are ignored. Self { ptr: Unique::dangling(), cap: 0, alloc } @@ -168,7 +170,7 @@ impl RawVec { Self::allocate_in(capacity, AllocInit::Zeroed, alloc) } - fn allocate_in(capacity: usize, init: AllocInit, mut alloc: A) -> Self { + fn allocate_in(capacity: usize, init: AllocInit, alloc: A) -> Self { if mem::size_of::() == 0 { Self::new_in(alloc) } else { @@ -305,11 +307,7 @@ impl RawVec { /// # } /// ``` pub fn reserve(&mut self, len: usize, additional: usize) { - match self.try_reserve(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve(len, additional)); } /// The same as `reserve`, but returns on errors instead of panicking or aborting. @@ -339,11 +337,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn reserve_exact(&mut self, len: usize, additional: usize) { - match self.try_reserve_exact(len, additional) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.try_reserve_exact(len, additional)); } /// The same as `reserve_exact`, but returns on errors instead of panicking or aborting. @@ -366,11 +360,7 @@ impl RawVec { /// /// Aborts on OOM. pub fn shrink_to_fit(&mut self, amount: usize) { - match self.shrink(amount) { - Err(CapacityOverflow) => capacity_overflow(), - Err(AllocError { layout, .. }) => handle_alloc_error(layout), - Ok(()) => { /* yay */ } - } + handle_reserve(self.shrink(amount)); } } @@ -465,8 +455,9 @@ impl RawVec { let new_size = amount * mem::size_of::(); let ptr = unsafe { - self.alloc.shrink(ptr, layout, new_size).map_err(|_| TryReserveError::AllocError { - layout: Layout::from_size_align_unchecked(new_size, layout.align()), + let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); + self.alloc.shrink(ptr, layout, new_layout).map_err(|_| TryReserveError::AllocError { + layout: new_layout, non_exhaustive: (), })? }; @@ -494,13 +485,16 @@ where let memory = if let Some((ptr, old_layout)) = current_memory { debug_assert_eq!(old_layout.align(), new_layout.align()); - unsafe { alloc.grow(ptr, old_layout, new_layout.size()) } + unsafe { + // The allocator checks for alignment equality + intrinsics::assume(old_layout.align() == new_layout.align()); + alloc.grow(ptr, old_layout, new_layout) + } } else { alloc.alloc(new_layout) - } - .map_err(|_| AllocError { layout: new_layout, non_exhaustive: () })?; + }; - Ok(memory) + memory.map_err(|_| AllocError { layout: new_layout, non_exhaustive: () }) } unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { @@ -512,6 +506,16 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { } } +// Central function for reserve error handling. +#[inline] +fn handle_reserve(result: Result<(), TryReserveError>) { + match result { + Err(CapacityOverflow) => capacity_overflow(), + Err(AllocError { layout, .. }) => handle_alloc_error(layout), + Ok(()) => { /* yay */ } + } +} + // We need to guarantee the following: // * We don't ever allocate `> isize::MAX` byte-size objects. // * We don't overflow `usize::MAX` and actually allocate too little. @@ -523,7 +527,7 @@ unsafe impl<#[may_dangle] T, A: AllocRef> Drop for RawVec { #[inline] fn alloc_guard(alloc_size: usize) -> Result<(), TryReserveError> { - if mem::size_of::() < 8 && alloc_size > isize::MAX as usize { + if usize::BITS < 64 && alloc_size > isize::MAX as usize { Err(CapacityOverflow) } else { Ok(()) diff --git a/library/alloc/src/raw_vec/tests.rs b/library/alloc/src/raw_vec/tests.rs index cadd913aa6..cb4fe1b46c 100644 --- a/library/alloc/src/raw_vec/tests.rs +++ b/library/alloc/src/raw_vec/tests.rs @@ -1,8 +1,9 @@ use super::*; +use std::cell::Cell; #[test] fn allocator_param() { - use crate::alloc::AllocErr; + use crate::alloc::AllocError; // Writing a test of integration between third-party // allocators and `RawVec` is a little tricky because the `RawVec` @@ -17,32 +18,32 @@ fn allocator_param() { // A dumb allocator that consumes a fixed amount of fuel // before allocation attempts start failing. struct BoundedAlloc { - fuel: usize, + fuel: Cell, } unsafe impl AllocRef for BoundedAlloc { - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { let size = layout.size(); - if size > self.fuel { - return Err(AllocErr); + if size > self.fuel.get() { + return Err(AllocError); } match Global.alloc(layout) { ok @ Ok(_) => { - self.fuel -= size; + self.fuel.set(self.fuel.get() - size); ok } err @ Err(_) => err, } } - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { unsafe { Global.dealloc(ptr, layout) } } } - let a = BoundedAlloc { fuel: 500 }; + let a = BoundedAlloc { fuel: Cell::new(500) }; let mut v: RawVec = RawVec::with_capacity_in(50, a); - assert_eq!(v.alloc.fuel, 450); + assert_eq!(v.alloc.fuel.get(), 450); v.reserve(50, 150); // (causes a realloc, thus using 50 + 150 = 200 units of fuel) - assert_eq!(v.alloc.fuel, 250); + assert_eq!(v.alloc.fuel.get(), 250); } #[test] diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index 1046397f4b..5dbc42cc97 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -247,7 +247,7 @@ use core::pin::Pin; use core::ptr::{self, NonNull}; use core::slice::from_raw_parts_mut; -use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::string::String; use crate::vec::Vec; @@ -295,6 +295,13 @@ impl, U: ?Sized> CoerceUnsized> for Rc {} impl, U: ?Sized> DispatchFromDyn> for Rc {} impl Rc { + #[inline(always)] + fn inner(&self) -> &RcBox { + // This unsafety is ok because while this Rc is alive we're guaranteed + // that the inner pointer is valid. + unsafe { self.ptr.as_ref() } + } + fn from_inner(ptr: NonNull>) -> Self { Self { ptr, phantom: PhantomData } } @@ -325,6 +332,50 @@ impl Rc { ) } + /// Constructs a new `Rc` using a weak reference to itself. Attempting + /// to upgrade the weak reference before this function returns will result + /// in a `None` value. However, the weak reference may be cloned freely and + /// stored for use at a later time. + #[unstable(feature = "arc_new_cyclic", issue = "75861")] + pub fn new_cyclic(data_fn: impl FnOnce(&Weak) -> T) -> Rc { + // Construct the inner in the "uninitialized" state with a single + // weak reference. + let uninit_ptr: NonNull<_> = Box::leak(box RcBox { + strong: Cell::new(0), + weak: Cell::new(1), + value: mem::MaybeUninit::::uninit(), + }) + .into(); + + let init_ptr: NonNull> = uninit_ptr.cast(); + + let weak = Weak { ptr: init_ptr }; + + // It's important we don't give up ownership of the weak pointer, or + // else the memory might be freed by the time `data_fn` returns. If + // we really wanted to pass ownership, we could create an additional + // weak pointer for ourselves, but this would result in additional + // updates to the weak reference count which might not be necessary + // otherwise. + let data = data_fn(&weak); + + unsafe { + let inner = init_ptr.as_ptr(); + ptr::write(&raw mut (*inner).value, data); + + let prev_value = (*inner).strong.get(); + debug_assert_eq!(prev_value, 0, "No prior strong references should exist"); + (*inner).strong.set(1); + } + + let strong = Rc::from_inner(init_ptr); + + // Strong references should collectively own a shared weak reference, + // so don't run the destructor for our old weak reference. + mem::forget(weak); + strong + } + /// Constructs a new `Rc` with uninitialized contents. /// /// # Examples @@ -376,7 +427,7 @@ impl Rc { /// assert_eq!(*zero, 0) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed() -> Rc> { unsafe { @@ -425,7 +476,7 @@ impl Rc { // the strong count, and then remove the implicit "strong weak" // pointer while also handling drop logic by just crafting a // fake Weak. - this.dec_strong(); + this.inner().dec_strong(); let _weak = Weak { ptr: this.ptr }; forget(this); Ok(val) @@ -484,7 +535,7 @@ impl Rc<[T]> { /// assert_eq!(*values, [0, 0, 0]) /// ``` /// - /// [zeroed]: ../../std/mem/union.MaybeUninit.html#method.zeroed + /// [zeroed]: mem::MaybeUninit::zeroed #[unstable(feature = "new_uninit", issue = "63291")] pub fn new_zeroed_slice(len: usize) -> Rc<[mem::MaybeUninit]> { unsafe { @@ -511,7 +562,7 @@ impl Rc> { /// 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 /// @@ -550,7 +601,7 @@ impl Rc<[mem::MaybeUninit]> { /// 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 /// @@ -691,7 +742,7 @@ impl Rc { /// ``` #[stable(feature = "rc_weak", since = "1.4.0")] pub fn downgrade(this: &Self) -> Weak { - this.inc_weak(); + this.inner().inc_weak(); // Make sure we do not create a dangling Weak debug_assert!(!is_dangling(this.ptr)); Weak { ptr: this.ptr } @@ -712,7 +763,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn weak_count(this: &Self) -> usize { - this.weak() - 1 + this.inner().weak() - 1 } /// Gets the number of strong (`Rc`) pointers to this allocation. @@ -730,7 +781,7 @@ impl Rc { #[inline] #[stable(feature = "rc_counts", since = "1.15.0")] pub fn strong_count(this: &Self) -> usize { - this.strong() + this.inner().strong() } /// Returns `true` if there are no other `Rc` or [`Weak`] pointers to @@ -800,7 +851,9 @@ impl Rc { #[inline] #[unstable(feature = "get_mut_unchecked", issue = "63292")] pub unsafe fn get_mut_unchecked(this: &mut Self) -> &mut T { - unsafe { &mut this.ptr.as_mut().value } + // We are careful to *not* create a reference covering the "count" fields, as + // this would conflict with accesses to the reference counts (e.g. by `Weak`). + unsafe { &mut (*this.ptr.as_ptr()).value } } #[inline] @@ -887,10 +940,10 @@ impl Rc { unsafe { let mut swap = Rc::new(ptr::read(&this.ptr.as_ref().value)); mem::swap(this, &mut swap); - swap.dec_strong(); + swap.inner().dec_strong(); // Remove implicit strong-weak ref (no need to craft a fake // Weak here -- we know other Weaks can clean up for us) - swap.dec_weak(); + swap.inner().dec_weak(); forget(swap); } } @@ -943,7 +996,7 @@ impl Rc { /// and must return back a (potentially fat)-pointer for the `RcBox`. unsafe fn allocate_for_layout( value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocErr>, + allocate: impl FnOnce(Layout) -> Result, AllocError>, mem_to_rcbox: impl FnOnce(*mut u8) -> *mut RcBox, ) -> *mut RcBox { // Calculate layout using the given value layout. @@ -1148,16 +1201,16 @@ unsafe impl<#[may_dangle] T: ?Sized> Drop for Rc { /// ``` fn drop(&mut self) { unsafe { - self.dec_strong(); - if self.strong() == 0 { + self.inner().dec_strong(); + if self.inner().strong() == 0 { // destroy the contained object - ptr::drop_in_place(self.ptr.as_mut()); + ptr::drop_in_place(Self::get_mut_unchecked(self)); // remove the implicit "strong weak" pointer now that we've // destroyed the contents. - self.dec_weak(); + self.inner().dec_weak(); - if self.weak() == 0 { + if self.inner().weak() == 0 { Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } @@ -1183,7 +1236,7 @@ impl Clone for Rc { /// ``` #[inline] fn clone(&self) -> Rc { - self.inc_strong(); + self.inner().inc_strong(); Self::from_inner(self.ptr) } } @@ -1807,6 +1860,13 @@ pub(crate) fn is_dangling(ptr: NonNull) -> bool { address == usize::MAX } +/// Helper type to allow accessing the reference counts without +/// making any assertions about the data field. +struct WeakInner<'a> { + weak: &'a Cell, + strong: &'a Cell, +} + impl Weak { /// Attempts to upgrade the `Weak` pointer to an [`Rc`], delaying /// dropping of the inner value if successful. @@ -1866,11 +1926,21 @@ impl Weak { .unwrap_or(0) } - /// Returns `None` when the pointer is dangling and there is no allocated `RcBox` + /// Returns `None` when the pointer is dangling and there is no allocated `RcBox`, /// (i.e., when this `Weak` was created by `Weak::new`). #[inline] - fn inner(&self) -> Option<&RcBox> { - if is_dangling(self.ptr) { None } else { Some(unsafe { self.ptr.as_ref() }) } + fn inner(&self) -> Option> { + if is_dangling(self.ptr) { + None + } else { + // We are careful to *not* create a reference covering the "data" field, as + // the field may be mutated concurrently (for example, if the last `Rc` + // is dropped, the data field will be dropped in-place). + Some(unsafe { + let ptr = self.ptr.as_ptr(); + WeakInner { strong: &(*ptr).strong, weak: &(*ptr).weak } + }) + } } /// Returns `true` if the two `Weak`s point to the same allocation (similar to @@ -1948,14 +2018,14 @@ impl Drop for Weak { /// assert!(other_weak_foo.upgrade().is_none()); /// ``` fn drop(&mut self) { - if let Some(inner) = self.inner() { - inner.dec_weak(); - // the weak count starts at 1, and will only go to zero if all - // the strong pointers have disappeared. - if inner.weak() == 0 { - unsafe { - Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); - } + let inner = if let Some(inner) = self.inner() { inner } else { return }; + + inner.dec_weak(); + // the weak count starts at 1, and will only go to zero if all + // the strong pointers have disappeared. + if inner.weak() == 0 { + unsafe { + Global.dealloc(self.ptr.cast(), Layout::for_value(self.ptr.as_ref())); } } } @@ -2021,12 +2091,13 @@ impl Default for Weak { // clone these much in Rust thanks to ownership and move-semantics. #[doc(hidden)] -trait RcBoxPtr { - fn inner(&self) -> &RcBox; +trait RcInnerPtr { + fn weak_ref(&self) -> &Cell; + fn strong_ref(&self) -> &Cell; #[inline] fn strong(&self) -> usize { - self.inner().strong.get() + self.strong_ref().get() } #[inline] @@ -2040,17 +2111,17 @@ trait RcBoxPtr { if strong == 0 || strong == usize::MAX { abort(); } - self.inner().strong.set(strong + 1); + self.strong_ref().set(strong + 1); } #[inline] fn dec_strong(&self) { - self.inner().strong.set(self.strong() - 1); + self.strong_ref().set(self.strong() - 1); } #[inline] fn weak(&self) -> usize { - self.inner().weak.get() + self.weak_ref().get() } #[inline] @@ -2064,26 +2135,36 @@ trait RcBoxPtr { if weak == 0 || weak == usize::MAX { abort(); } - self.inner().weak.set(weak + 1); + self.weak_ref().set(weak + 1); } #[inline] fn dec_weak(&self) { - self.inner().weak.set(self.weak() - 1); + self.weak_ref().set(self.weak() - 1); } } -impl RcBoxPtr for Rc { +impl RcInnerPtr for RcBox { #[inline(always)] - fn inner(&self) -> &RcBox { - unsafe { self.ptr.as_ref() } + fn weak_ref(&self) -> &Cell { + &self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + &self.strong } } -impl RcBoxPtr for RcBox { +impl<'a> RcInnerPtr for WeakInner<'a> { #[inline(always)] - fn inner(&self) -> &RcBox { - self + fn weak_ref(&self) -> &Cell { + self.weak + } + + #[inline(always)] + fn strong_ref(&self) -> &Cell { + self.strong } } diff --git a/library/alloc/src/rc/tests.rs b/library/alloc/src/rc/tests.rs index e88385faf4..fed48a59f8 100644 --- a/library/alloc/src/rc/tests.rs +++ b/library/alloc/src/rc/tests.rs @@ -434,3 +434,69 @@ fn test_array_from_slice() { let a: Result, _> = r.clone().try_into(); assert!(a.is_err()); } + +#[test] +fn test_rc_cyclic_with_zero_refs() { + struct ZeroRefs { + inner: Weak, + } + + let zero_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + ZeroRefs { inner: Weak::new() } + }); + + assert_eq!(Rc::strong_count(&zero_refs), 1); + assert_eq!(Rc::weak_count(&zero_refs), 0); + assert_eq!(zero_refs.inner.strong_count(), 0); + assert_eq!(zero_refs.inner.weak_count(), 0); +} + +#[test] +fn test_rc_cyclic_with_one_ref() { + struct OneRef { + inner: Weak, + } + + let one_ref = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + OneRef { inner: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&one_ref), 1); + assert_eq!(Rc::weak_count(&one_ref), 1); + + let one_ref2 = Weak::upgrade(&one_ref.inner).unwrap(); + assert!(Rc::ptr_eq(&one_ref, &one_ref2)); + + assert_eq!(one_ref.inner.strong_count(), 2); + assert_eq!(one_ref.inner.weak_count(), 1); +} + +#[test] +fn test_rc_cyclic_with_two_ref() { + struct TwoRefs { + inner: Weak, + inner1: Weak, + } + + let two_refs = Rc::new_cyclic(|inner| { + assert_eq!(inner.strong_count(), 0); + assert!(inner.upgrade().is_none()); + TwoRefs { inner: inner.clone(), inner1: inner.clone() } + }); + + assert_eq!(Rc::strong_count(&two_refs), 1); + assert_eq!(Rc::weak_count(&two_refs), 2); + + let two_ref3 = Weak::upgrade(&two_refs.inner).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref3)); + + let two_ref2 = Weak::upgrade(&two_refs.inner1).unwrap(); + assert!(Rc::ptr_eq(&two_refs, &two_ref2)); + + assert_eq!(Rc::strong_count(&two_refs), 3); + assert_eq!(Rc::weak_count(&two_refs), 2); +} diff --git a/library/alloc/src/slice.rs b/library/alloc/src/slice.rs index 8ea2c6dc85..79403cf868 100644 --- a/library/alloc/src/slice.rs +++ b/library/alloc/src/slice.rs @@ -91,8 +91,14 @@ use crate::borrow::ToOwned; use crate::boxed::Box; use crate::vec::Vec; +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use core::slice::check_range; #[unstable(feature = "array_chunks", issue = "74985")] pub use core::slice::ArrayChunks; +#[unstable(feature = "array_chunks", issue = "74985")] +pub use core::slice::ArrayChunksMut; +#[unstable(feature = "array_windows", issue = "75027")] +pub use core::slice::ArrayWindows; #[stable(feature = "slice_get_slice", since = "1.28.0")] pub use core::slice::SliceIndex; #[stable(feature = "from_ref", since = "1.28.0")] diff --git a/library/alloc/src/string.rs b/library/alloc/src/string.rs index 05690e19d2..d3598ccfce 100644 --- a/library/alloc/src/string.rs +++ b/library/alloc/src/string.rs @@ -47,8 +47,9 @@ use core::fmt; use core::hash; use core::iter::{FromIterator, FusedIterator}; use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Add, AddAssign, Index, IndexMut, RangeBounds}; +use core::ops::{self, Add, AddAssign, Index, IndexMut, Range, RangeBounds}; use core::ptr; +use core::slice; use core::str::{lossy, pattern::Pattern}; use crate::borrow::{Cow, ToOwned}; @@ -1506,23 +1507,15 @@ impl String { // of the vector version. The data is just plain bytes. // Because the range removal happens in Drop, if the Drain iterator is leaked, // the removal will not happen. - let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; + let Range { start, end } = slice::check_range(self.len(), range); + assert!(self.is_char_boundary(start)); + assert!(self.is_char_boundary(end)); // Take out two simultaneous borrows. The &mut String won't be accessed // until iteration is over, in Drop. let self_ptr = self as *mut _; - // slicing does the appropriate bounds checks - let chars_iter = self[start..end].chars(); + // SAFETY: `check_range` and `is_char_boundary` do the appropriate bounds checks. + let chars_iter = unsafe { self.get_unchecked(start..end) }.chars(); Drain { start, end, iter: chars_iter, string: self_ptr } } @@ -2447,7 +2440,7 @@ pub struct Drain<'a> { #[stable(feature = "collection_debug", since = "1.17.0")] impl fmt::Debug for Drain<'_> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Drain { .. }") + f.debug_tuple("Drain").field(&self.as_str()).finish() } } @@ -2470,6 +2463,40 @@ impl Drop for Drain<'_> { } } +impl<'a> Drain<'a> { + /// Returns the remaining (sub)string of this iterator as a slice. + /// + /// # Examples + /// + /// ``` + /// #![feature(string_drain_as_str)] + /// let mut s = String::from("abc"); + /// let mut drain = s.drain(..); + /// assert_eq!(drain.as_str(), "abc"); + /// let _ = drain.next().unwrap(); + /// assert_eq!(drain.as_str(), "bc"); + /// ``` + #[unstable(feature = "string_drain_as_str", issue = "76905")] // Note: uncomment AsRef impls below when stabilizing. + pub fn as_str(&self) -> &str { + self.iter.as_str() + } +} + +// Uncomment when stabilizing `string_drain_as_str`. +// #[unstable(feature = "string_drain_as_str", issue = "76905")] +// impl<'a> AsRef for Drain<'a> { +// fn as_ref(&self) -> &str { +// self.as_str() +// } +// } +// +// #[unstable(feature = "string_drain_as_str", issue = "76905")] +// impl<'a> AsRef<[u8]> for Drain<'a> { +// fn as_ref(&self) -> &[u8] { +// self.as_str().as_bytes() +// } +// } + #[stable(feature = "drain", since = "1.6.0")] impl Iterator for Drain<'_> { type Item = char; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 73d2fe7482..3d7411c79d 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -21,7 +21,7 @@ use core::slice::from_raw_parts_mut; use core::sync::atomic; use core::sync::atomic::Ordering::{Acquire, Relaxed, Release, SeqCst}; -use crate::alloc::{box_free, handle_alloc_error, AllocErr, AllocRef, Global, Layout}; +use crate::alloc::{box_free, handle_alloc_error, AllocError, AllocRef, Global, Layout}; use crate::borrow::{Cow, ToOwned}; use crate::boxed::Box; use crate::rc::is_dangling; @@ -111,7 +111,7 @@ macro_rules! acquire { /// /// # Cloning references /// -/// Creating a new reference from an existing reference counted pointer is done using the +/// Creating a new reference from an existing reference-counted pointer is done using the /// `Clone` trait implemented for [`Arc`][Arc] and [`Weak`][Weak]. /// /// ``` @@ -152,7 +152,7 @@ macro_rules! acquire { /// [upgrade]: Weak::upgrade /// [`RefCell`]: core::cell::RefCell /// [`std::sync`]: ../../std/sync/index.html -/// [`Arc::clone(&from)`]: #method.clone +/// [`Arc::clone(&from)`]: Arc::clone /// /// # Examples /// @@ -201,7 +201,7 @@ macro_rules! acquire { /// See the [`rc` documentation][rc_examples] for more examples of reference /// counting in general. /// -/// [rc_examples]: ../../std/rc/index.html#examples +/// [rc_examples]: crate::rc#examples #[cfg_attr(not(test), rustc_diagnostic_item = "Arc")] #[stable(feature = "rust1", since = "1.0.0")] pub struct Arc { @@ -969,7 +969,7 @@ impl Arc { /// and must return back a (potentially fat)-pointer for the `ArcInner`. unsafe fn allocate_for_layout( value_layout: Layout, - allocate: impl FnOnce(Layout) -> Result, AllocErr>, + allocate: impl FnOnce(Layout) -> Result, AllocError>, mem_to_arcinner: impl FnOnce(*mut u8) -> *mut ArcInner, ) -> *mut ArcInner { // Calculate layout using the given value layout. diff --git a/library/alloc/src/task.rs b/library/alloc/src/task.rs index 5edc579605..fcab3fd0ba 100644 --- a/library/alloc/src/task.rs +++ b/library/alloc/src/task.rs @@ -33,6 +33,7 @@ pub trait Wake { } } +#[allow(rustc::ineffective_unstable_trait_impl)] #[unstable(feature = "wake_trait", issue = "69912")] impl From> for Waker { fn from(waker: Arc) -> Waker { @@ -42,6 +43,7 @@ impl From> for Waker { } } +#[allow(rustc::ineffective_unstable_trait_impl)] #[unstable(feature = "wake_trait", issue = "69912")] impl From> for RawWaker { fn from(waker: Arc) -> RawWaker { diff --git a/library/alloc/src/vec.rs b/library/alloc/src/vec.rs index 058a06e132..63ea61820d 100644 --- a/library/alloc/src/vec.rs +++ b/library/alloc/src/vec.rs @@ -9,7 +9,7 @@ //! //! # Examples //! -//! You can explicitly create a [`Vec`] with [`new`]: +//! You can explicitly create a [`Vec`] with [`Vec::new`]: //! //! ``` //! let v: Vec = Vec::new(); @@ -50,21 +50,21 @@ //! v[1] = v[1] + 5; //! ``` //! -//! [`Vec`]: Vec -//! [`new`]: Vec::new //! [`push`]: Vec::push #![stable(feature = "rust1", since = "1.0.0")] use core::cmp::{self, Ordering}; +use core::convert::TryFrom; use core::fmt; use core::hash::{Hash, Hasher}; use core::intrinsics::{arith_offset, assume}; -use core::iter::{FromIterator, FusedIterator, TrustedLen}; +use core::iter::{ + FromIterator, FusedIterator, InPlaceIterable, SourceIter, TrustedLen, TrustedRandomAccess, +}; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit}; -use core::ops::Bound::{Excluded, Included, Unbounded}; -use core::ops::{self, Index, IndexMut, RangeBounds}; +use core::ops::{self, Index, IndexMut, Range, RangeBounds}; use core::ptr::{self, NonNull}; use core::slice::{self, SliceIndex}; @@ -116,10 +116,14 @@ use crate::raw_vec::RawVec; /// assert_eq!(vec, [0, 0, 0, 0, 0]); /// /// // The following is equivalent, but potentially slower: -/// let mut vec1 = Vec::with_capacity(5); -/// vec1.resize(5, 0); +/// let mut vec = Vec::with_capacity(5); +/// vec.resize(5, 0); +/// assert_eq!(vec, [0, 0, 0, 0, 0]); /// ``` /// +/// For more information, see +/// [Capacity and Reallocation](#capacity-and-reallocation). +/// /// Use a `Vec` as an efficient stack: /// /// ``` @@ -159,7 +163,7 @@ use crate::raw_vec::RawVec; /// # Slicing /// /// A `Vec` can be mutable. Slices, on the other hand, are read-only objects. -/// To get a slice, use `&`. Example: +/// To get a [slice], use [`&`]. Example: /// /// ``` /// fn read_slice(slice: &[usize]) { @@ -171,7 +175,9 @@ use crate::raw_vec::RawVec; /// /// // ... and that's all! /// // you can also do it like this: -/// let x : &[usize] = &v; +/// let u: &[usize] = &v; +/// // or like this: +/// let u: &[_] = &v; /// ``` /// /// In Rust, it's more common to pass slices as arguments rather than vectors @@ -287,6 +293,8 @@ use crate::raw_vec::RawVec; /// [`insert`]: Vec::insert /// [`reserve`]: Vec::reserve /// [owned slice]: Box +/// [slice]: ../../std/primitive.slice.html +/// [`&`]: ../../std/primitive.reference.html #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "vec_type")] pub struct Vec { @@ -404,7 +412,7 @@ impl Vec { /// (at least, it's highly likely to be incorrect if it wasn't). /// * `T` needs to have the same size and alignment as what `ptr` was allocated with. /// (`T` having a less strict alignment is not sufficient, the alignment really - /// needs to be equal to satsify the [`dealloc`] requirement that memory must be + /// needs to be equal to satisfy the [`dealloc`] requirement that memory must be /// allocated and deallocated with the same layout.) /// * `length` needs to be less than or equal to `capacity`. /// * `capacity` needs to be the capacity that the pointer was allocated with. @@ -524,7 +532,7 @@ impl Vec { /// Tries to reserve capacity for at least `additional` more elements to be inserted /// in the given `Vec`. The collection may reserve more space to avoid - /// frequent reallocations. After calling `reserve`, capacity will be + /// frequent reallocations. After calling `try_reserve`, capacity will be /// greater than or equal to `self.len() + additional`. Does nothing if /// capacity is already sufficient. /// @@ -559,9 +567,10 @@ impl Vec { self.buf.try_reserve(self.len, additional) } - /// Tries to reserves the minimum capacity for exactly `additional` more elements to - /// be inserted in the given `Vec`. After calling `reserve_exact`, - /// capacity will be greater than or equal to `self.len() + additional`. + /// Tries to reserve the minimum capacity for exactly `additional` + /// elements to be inserted in the given `Vec`. After calling + /// `try_reserve_exact`, capacity will be greater than or equal to + /// `self.len() + additional` if it returns `Ok(())`. /// Does nothing if the capacity is already sufficient. /// /// Note that the allocator may give the collection more space than it @@ -583,7 +592,7 @@ impl Vec { /// let mut output = Vec::new(); /// /// // Pre-reserve the memory, exiting if we can't - /// output.try_reserve(data.len())?; + /// output.try_reserve_exact(data.len())?; /// /// // Now we know this can't OOM in the middle of our complex work /// output.extend(data.iter().map(|&val| { @@ -1305,35 +1314,7 @@ impl Vec { // the hole, and the vector length is restored to the new length. // let len = self.len(); - let start = match range.start_bound() { - Included(&n) => n, - Excluded(&n) => n + 1, - Unbounded => 0, - }; - let end = match range.end_bound() { - Included(&n) => n + 1, - Excluded(&n) => n, - Unbounded => len, - }; - - #[cold] - #[inline(never)] - fn start_assert_failed(start: usize, end: usize) -> ! { - panic!("start drain index (is {}) should be <= end drain index (is {})", start, end); - } - - #[cold] - #[inline(never)] - fn end_assert_failed(end: usize, len: usize) -> ! { - panic!("end drain index (is {}) should be <= len (is {})", end, len); - } - - if start > end { - start_assert_failed(start, end); - } - if end > len { - end_assert_failed(end, len); - } + let Range { start, end } = slice::check_range(len, range); unsafe { // set self.vec length's to start, to be safe in case Drain is leaked @@ -1433,6 +1414,11 @@ impl Vec { assert_failed(at, self.len()); } + if at == 0 { + // the new vector can take over the original buffer and avoid the copy + return mem::replace(self, Vec::with_capacity(self.capacity())); + } + let other_len = self.len - at; let mut other = Vec::with_capacity(other_len); @@ -1456,9 +1442,9 @@ impl Vec { /// If `new_len` is less than `len`, the `Vec` is simply truncated. /// /// This method uses a closure to create new values on every push. If - /// you'd rather [`Clone`] a given value, use [`resize`]. If you want - /// to use the [`Default`] trait to generate values, you can pass - /// [`Default::default()`] as the second argument. + /// you'd rather [`Clone`] a given value, use [`Vec::resize`]. If you + /// want to use the [`Default`] trait to generate values, you can + /// pass [`Default::default`] as the second argument. /// /// # Examples /// @@ -1472,8 +1458,6 @@ impl Vec { /// vec.resize_with(4, || { p *= 2; p }); /// assert_eq!(vec, [2, 4, 8, 16]); /// ``` - /// - /// [`resize`]: Vec::resize #[stable(feature = "vec_resize_with", since = "1.33.0")] pub fn resize_with(&mut self, new_len: usize, f: F) where @@ -1569,7 +1553,7 @@ impl Vec { /// This method requires `T` to implement [`Clone`], /// 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 [`resize_with`]. + /// [`Clone`]), use [`Vec::resize_with`]. /// /// # Examples /// @@ -1582,8 +1566,6 @@ impl Vec { /// vec.resize(2, 0); /// assert_eq!(vec, [1, 2]); /// ``` - /// - /// [`resize_with`]: Vec::resize_with #[stable(feature = "vec_resize", since = "1.5.0")] pub fn resize(&mut self, new_len: usize, value: T) { let len = self.len(); @@ -1613,7 +1595,7 @@ impl Vec { /// assert_eq!(vec, [1, 2, 3, 4]); /// ``` /// - /// [`extend`]: #method.extend + /// [`extend`]: Vec::extend #[stable(feature = "vec_extend_from_slice", since = "1.6.0")] pub fn extend_from_slice(&mut self, other: &[T]) { self.spec_extend(other.iter()) @@ -2017,7 +1999,7 @@ impl> IndexMut for Vec { impl FromIterator for Vec { #[inline] fn from_iter>(iter: I) -> Vec { - >::from_iter(iter.into_iter()) + >::from_iter(iter.into_iter()) } } @@ -2099,13 +2081,38 @@ impl Extend for Vec { } } -// Specialization trait used for Vec::from_iter and Vec::extend -trait SpecExtend { +/// Specialization trait used for Vec::from_iter +/// +/// ## The delegation graph: +/// +/// ```text +/// +-------------+ +/// |FromIterator | +/// +-+-----------+ +/// | +/// v +/// +-+-------------------------------+ +---------------------+ +/// |SpecFromIter +---->+SpecFromIterNested | +/// |where I: | | |where I: | +/// | Iterator (default)----------+ | | Iterator (default) | +/// | vec::IntoIter | | | TrustedLen | +/// | SourceIterMarker---fallback-+ | | | +/// | slice::Iter | | | +/// | Iterator | +---------------------+ +/// +---------------------------------+ +/// ``` +trait SpecFromIter { fn from_iter(iter: I) -> Self; - fn spec_extend(&mut self, iter: I); } -impl SpecExtend for Vec +/// Another specialization trait for Vec::from_iter +/// necessary to manually prioritize overlapping specializations +/// see [`SpecFromIter`] for details. +trait SpecFromIterNested { + fn from_iter(iter: I) -> Self; +} + +impl SpecFromIterNested for Vec where I: Iterator, { @@ -2127,10 +2134,222 @@ where vector } }; + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs as SpecExtend>::spec_extend(&mut vector, iterator); vector } +} +impl SpecFromIterNested for Vec +where + I: TrustedLen, +{ + fn from_iter(iterator: I) -> Self { + let mut vector = Vec::new(); + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + vector.spec_extend(iterator); + vector + } +} + +impl SpecFromIter for Vec +where + I: Iterator, +{ + default fn from_iter(iterator: I) -> Self { + SpecFromIterNested::from_iter(iterator) + } +} + +// A helper struct for in-place iteration that drops the destination slice of iteration, +// i.e. the head. The source slice (the tail) is dropped by IntoIter. +struct InPlaceDrop { + inner: *mut T, + dst: *mut T, +} + +impl InPlaceDrop { + fn len(&self) -> usize { + unsafe { self.dst.offset_from(self.inner) as usize } + } +} + +impl Drop for InPlaceDrop { + #[inline] + fn drop(&mut self) { + unsafe { + ptr::drop_in_place(slice::from_raw_parts_mut(self.inner, self.len())); + } + } +} + +impl SpecFromIter> for Vec { + fn from_iter(iterator: IntoIter) -> Self { + // A common case is passing a vector into a function which immediately + // re-collects into a vector. We can short circuit this if the IntoIter + // has not been advanced at all. + // When it has been advanced We can also reuse the memory and move the data to the front. + // But we only do so when the resulting Vec wouldn't have more unused capacity + // than creating it through the generic FromIterator implementation would. That limitation + // is not strictly necessary as Vec's allocation behavior is intentionally unspecified. + // But it is a conservative choice. + let has_advanced = iterator.buf.as_ptr() as *const _ != iterator.ptr; + if !has_advanced || iterator.len() >= iterator.cap / 2 { + unsafe { + let it = ManuallyDrop::new(iterator); + if has_advanced { + ptr::copy(it.ptr, it.buf.as_ptr(), it.len()); + } + return Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap); + } + } + + let mut vec = Vec::new(); + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + vec.spec_extend(iterator); + vec + } +} + +fn write_in_place_with_drop( + src_end: *const T, +) -> impl FnMut(InPlaceDrop, T) -> Result, !> { + move |mut sink, item| { + unsafe { + // the InPlaceIterable contract cannot be verified precisely here since + // try_fold has an exclusive reference to the source pointer + // all we can do is check if it's still in range + debug_assert!(sink.dst as *const _ <= src_end, "InPlaceIterable contract violation"); + ptr::write(sink.dst, item); + sink.dst = sink.dst.add(1); + } + Ok(sink) + } +} + +/// 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] +trait SourceIterMarker: SourceIter {} + +// 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 SpecFromIter for Vec +where + I: Iterator + SourceIterMarker, +{ + default fn from_iter(mut iterator: I) -> Self { + // Additional requirements which cannot expressed via trait bounds. We rely on const eval + // instead: + // a) no ZSTs as there would be no allocation to reuse and pointer arithmetic would panic + // b) size match as required by Alloc contract + // c) alignments match as required by Alloc contract + if mem::size_of::() == 0 + || mem::size_of::() + != mem::size_of::<<::Source as AsIntoIter>::Item>() + || mem::align_of::() + != mem::align_of::<<::Source as AsIntoIter>::Item>() + { + // fallback to more generic implementations + return SpecFromIterNested::from_iter(iterator); + } + + let (src_buf, src_ptr, dst_buf, dst_end, cap) = unsafe { + let inner = iterator.as_inner().as_into_iter(); + ( + inner.buf.as_ptr(), + inner.ptr, + inner.buf.as_ptr() as *mut T, + inner.end as *const T, + inner.cap, + ) + }; + + // use try-fold since + // - it vectorizes better for some iterator adapters + // - unlike most internal iteration methods, it only takes a &mut self + // - it lets us thread the write pointer through its innards and get it back in the end + let sink = InPlaceDrop { inner: dst_buf, dst: dst_buf }; + let sink = iterator + .try_fold::<_, _, Result<_, !>>(sink, write_in_place_with_drop(dst_end)) + .unwrap(); + // iteration succeeded, don't drop head + let dst = ManuallyDrop::new(sink).dst; + + let src = unsafe { iterator.as_inner().as_into_iter() }; + // check if SourceIter contract was upheld + // caveat: if they weren't we may not even make it to this point + debug_assert_eq!(src_buf, src.buf.as_ptr()); + // check InPlaceIterable contract. This is only possible if the iterator advanced the + // source pointer at all. If it uses unchecked access via TrustedRandomAccess + // then the source pointer will stay in its initial position and we can't use it as reference + if src.ptr != src_ptr { + debug_assert!( + dst as *const _ <= src.ptr, + "InPlaceIterable contract violation, write pointer advanced beyond read pointer" + ); + } + + // drop any remaining values at the tail of the source + src.drop_remaining(); + // but prevent drop of the allocation itself once IntoIter goes out of scope + src.forget_allocation(); + + let vec = unsafe { + let len = dst.offset_from(dst_buf) as usize; + Vec::from_raw_parts(dst_buf, len, cap) + }; + + vec + } +} + +impl<'a, T: 'a, I> SpecFromIter<&'a T, I> for Vec +where + I: Iterator, + T: Clone, +{ + default fn from_iter(iterator: I) -> Self { + SpecFromIter::from_iter(iterator.cloned()) + } +} + +impl<'a, T: 'a> SpecFromIter<&'a T, slice::Iter<'a, T>> for Vec +where + T: Copy, +{ + // reuses the extend specialization for T: Copy + fn from_iter(iterator: slice::Iter<'a, T>) -> Self { + let mut vec = Vec::new(); + // must delegate to spec_extend() since extend() itself delegates + // to spec_from for empty Vecs + vec.spec_extend(iterator); + vec + } +} + +// Specialization trait used for Vec::extend +trait SpecExtend { + fn spec_extend(&mut self, iter: I); +} + +impl SpecExtend for Vec +where + I: Iterator, +{ default fn spec_extend(&mut self, iter: I) { self.extend_desugared(iter) } @@ -2140,12 +2359,6 @@ impl SpecExtend for Vec where I: TrustedLen, { - default fn from_iter(iterator: I) -> Self { - let mut vector = Vec::new(); - vector.spec_extend(iterator); - vector - } - default fn spec_extend(&mut self, iterator: I) { // This is the case for a TrustedLen iterator. let (low, high) = iterator.size_hint(); @@ -2176,22 +2389,6 @@ where } impl SpecExtend> for Vec { - fn from_iter(iterator: IntoIter) -> Self { - // A common case is passing a vector into a function which immediately - // re-collects into a vector. We can short circuit this if the IntoIter - // has not been advanced at all. - if iterator.buf.as_ptr() as *const _ == iterator.ptr { - unsafe { - let it = ManuallyDrop::new(iterator); - Vec::from_raw_parts(it.buf.as_ptr(), it.len(), it.cap) - } - } else { - let mut vector = Vec::new(); - vector.spec_extend(iterator); - vector - } - } - fn spec_extend(&mut self, mut iterator: IntoIter) { unsafe { self.append_elements(iterator.as_slice() as _); @@ -2205,10 +2402,6 @@ where I: Iterator, T: Clone, { - default fn from_iter(iterator: I) -> Self { - SpecExtend::from_iter(iterator.cloned()) - } - default fn spec_extend(&mut self, iterator: I) { self.spec_extend(iterator.cloned()) } @@ -2220,17 +2413,13 @@ where { fn spec_extend(&mut self, iterator: slice::Iter<'a, T>) { let slice = iterator.as_slice(); - self.reserve(slice.len()); - unsafe { - let len = self.len(); - let dst_slice = slice::from_raw_parts_mut(self.as_mut_ptr().add(len), slice.len()); - dst_slice.copy_from_slice(slice); - self.set_len(len + slice.len()); - } + unsafe { self.append_elements(slice) }; } } impl Vec { + // leaf method to which various SpecFrom/SpecExtend implementations delegate when + // they have no further optimizations to apply fn extend_desugared>(&mut self, mut iterator: I) { // This is the case for a general iterator. // @@ -2564,6 +2753,57 @@ impl From<&str> for Vec { } } +#[stable(feature = "array_try_from_vec", since = "1.48.0")] +impl TryFrom> for [T; N] { + type Error = Vec; + + /// Gets the entire contents of the `Vec` as an array, + /// if its size exactly matches that of the requested array. + /// + /// # Examples + /// + /// ``` + /// use std::convert::TryInto; + /// assert_eq!(vec![1, 2, 3].try_into(), Ok([1, 2, 3])); + /// assert_eq!(>::new().try_into(), Ok([])); + /// ``` + /// + /// If the length doesn't match, the input comes back in `Err`: + /// ``` + /// use std::convert::TryInto; + /// let r: Result<[i32; 4], _> = (0..10).collect::>().try_into(); + /// assert_eq!(r, Err(vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9])); + /// ``` + /// + /// If you're fine with just getting a prefix of the `Vec`, + /// you can call [`.truncate(N)`](Vec::truncate) first. + /// ``` + /// use std::convert::TryInto; + /// let mut v = String::from("hello world").into_bytes(); + /// v.sort(); + /// v.truncate(2); + /// let [a, b]: [_; 2] = v.try_into().unwrap(); + /// assert_eq!(a, b' '); + /// assert_eq!(b, b'd'); + /// ``` + fn try_from(mut vec: Vec) -> Result<[T; N], Vec> { + if vec.len() != N { + return Err(vec); + } + + // SAFETY: `.set_len(0)` is always sound. + unsafe { vec.set_len(0) }; + + // SAFETY: A `Vec`'s pointer is always aligned properly, and + // the alignment the array needs is the same as the items. + // We checked earlier that we have sufficient items. + // The items will not double-drop as the `set_len` + // tells the `Vec` not to also drop them. + let array = unsafe { ptr::read(vec.as_ptr() as *const [T; N]) }; + Ok(array) + } +} + //////////////////////////////////////////////////////////////////////////////// // Clone-on-write //////////////////////////////////////////////////////////////////////////////// @@ -2607,6 +2847,13 @@ where /// /// This `struct` is created by the `into_iter` method on [`Vec`] (provided /// by the [`IntoIterator`] trait). +/// +/// # Example +/// +/// ``` +/// let v = vec![0, 1, 2]; +/// let iter: std::vec::IntoIter<_> = v.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { buf: NonNull, @@ -2661,6 +2908,22 @@ impl IntoIter { fn as_raw_mut_slice(&mut self) -> *mut [T] { ptr::slice_from_raw_parts_mut(self.ptr as *mut T, self.len()) } + + fn drop_remaining(&mut self) { + unsafe { + ptr::drop_in_place(self.as_mut_slice()); + } + self.ptr = self.end; + } + + /// Relinquishes the backing allocation, equivalent to + /// `ptr::write(&mut self, Vec::new().into_iter())` + fn forget_allocation(&mut self) { + self.cap = 0; + self.buf = unsafe { NonNull::new_unchecked(RawVec::NEW.ptr()) }; + self.ptr = self.buf.as_ptr(); + self.end = self.buf.as_ptr(); + } } #[stable(feature = "vec_intoiter_as_ref", since = "1.46.0")] @@ -2681,25 +2944,21 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - unsafe { - if self.ptr as *const _ == self.end { - None - } else { - if mem::size_of::() == 0 { - // purposefully don't use 'ptr.offset' because for - // vectors with 0-size elements this would return the - // same pointer. - self.ptr = arith_offset(self.ptr as *const i8, 1) as *mut T; + if self.ptr as *const _ == self.end { + None + } else if mem::size_of::() == 0 { + // purposefully don't use 'ptr.offset' because for + // vectors with 0-size elements this would return the + // same pointer. + self.ptr = unsafe { arith_offset(self.ptr as *const i8, 1) as *mut T }; - // Make up a value of this ZST. - Some(mem::zeroed()) - } else { - let old = self.ptr; - self.ptr = self.ptr.offset(1); + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + let old = self.ptr; + self.ptr = unsafe { self.ptr.offset(1) }; - Some(ptr::read(old)) - } - } + Some(unsafe { ptr::read(old) }) } } @@ -2717,28 +2976,41 @@ impl Iterator for IntoIter { fn count(self) -> usize { self.len() } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> Self::Item + where + Self: TrustedRandomAccess, + { + // SAFETY: the caller must guarantee that `i` is in bounds of the + // `Vec`, so `i` cannot overflow an `isize`, and the `self.ptr.add(i)` + // is guaranteed to pointer to an element of the `Vec` and + // thus guaranteed to be valid to dereference. + // + // Also note the implementation of `Self: TrustedRandomAccess` requires + // that `T: Copy` so reading elements from the buffer doesn't invalidate + // them for `Drop`. + unsafe { + if mem::size_of::() == 0 { mem::zeroed() } else { ptr::read(self.ptr.add(i)) } + } + } } #[stable(feature = "rust1", since = "1.0.0")] impl DoubleEndedIterator for IntoIter { #[inline] fn next_back(&mut self) -> Option { - unsafe { - if self.end == self.ptr { - None - } else { - if mem::size_of::() == 0 { - // See above for why 'ptr.offset' isn't used - self.end = arith_offset(self.end as *const i8, -1) as *mut T; + if self.end == self.ptr { + None + } else if mem::size_of::() == 0 { + // See above for why 'ptr.offset' isn't used + self.end = unsafe { arith_offset(self.end as *const i8, -1) as *mut T }; - // Make up a value of this ZST. - Some(mem::zeroed()) - } else { - self.end = self.end.offset(-1); + // Make up a value of this ZST. + Some(unsafe { mem::zeroed() }) + } else { + self.end = unsafe { self.end.offset(-1) }; - Some(ptr::read(self.end)) - } - } + Some(unsafe { ptr::read(self.end) }) } } } @@ -2756,6 +3028,19 @@ impl FusedIterator for IntoIter {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for IntoIter {} +#[doc(hidden)] +#[unstable(issue = "none", feature = "std_internals")] +// T: Copy as approximation for !Drop since get_unchecked does not advance self.ptr +// and thus we can't implement drop-handling +unsafe impl TrustedRandomAccess for IntoIter +where + T: Copy, +{ + fn may_have_side_effect() -> bool { + false + } +} + #[stable(feature = "vec_into_iter_clone", since = "1.8.0")] impl Clone for IntoIter { fn clone(&self) -> IntoIter { @@ -2784,9 +3069,45 @@ unsafe impl<#[may_dangle] T> Drop for IntoIter { } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for IntoIter {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for IntoIter { + type Source = IntoIter; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut Self::Source { + self + } +} + +// internal helper trait for in-place iteration specialization. +#[rustc_specialization_trait] +pub(crate) trait AsIntoIter { + type Item; + fn as_into_iter(&mut self) -> &mut IntoIter; +} + +impl AsIntoIter for IntoIter { + type Item = T; + + fn as_into_iter(&mut self) -> &mut IntoIter { + self + } +} + /// A draining iterator for `Vec`. /// /// This `struct` is created by [`Vec::drain`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::Drain<_> = v.drain(..); +/// ``` #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, T: 'a> { /// Index of tail to preserve @@ -2916,6 +3237,14 @@ impl FusedIterator for Drain<'_, T> {} /// /// This struct is created by [`Vec::splice()`]. /// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// let mut v = vec![0, 1, 2]; +/// let new = [7, 8]; +/// let iter: std::vec::Splice<_> = v.splice(1.., new.iter().cloned()); +/// ``` #[derive(Debug)] #[stable(feature = "vec_splice", since = "1.21.0")] pub struct Splice<'a, I: Iterator + 'a> { @@ -3028,7 +3357,19 @@ impl Drain<'_, T> { } } -/// An iterator produced by calling `drain_filter` on Vec. +/// An iterator which uses a closure to determine if an element should be removed. +/// +/// This struct is created by [`Vec::drain_filter`]. +/// See its documentation for more. +/// +/// # Example +/// +/// ``` +/// #![feature(drain_filter)] +/// +/// let mut v = vec![0, 1, 2]; +/// let iter: std::vec::DrainFilter<_, _> = v.drain_filter(|x| *x % 2 == 0); +/// ``` #[unstable(feature = "drain_filter", reason = "recently added", issue = "43244")] #[derive(Debug)] pub struct DrainFilter<'a, T, F> @@ -3044,7 +3385,7 @@ where old_len: usize, /// The filter test predicate. pred: F, - /// A flag that indicates a panic has occurred in the filter test prodicate. + /// A flag that indicates a panic has occurred in the filter test predicate. /// This is used as a hint in the drop implementation to prevent consumption /// of the remainder of the `DrainFilter`. Any unprocessed items will be /// backshifted in the `vec`, but no further items will be dropped or diff --git a/library/alloc/tests/binary_heap.rs b/library/alloc/tests/binary_heap.rs index 62084ccf53..ce794a9a4a 100644 --- a/library/alloc/tests/binary_heap.rs +++ b/library/alloc/tests/binary_heap.rs @@ -230,6 +230,18 @@ fn test_to_vec() { check_to_vec(vec![5, 4, 3, 2, 1, 5, 4, 3, 2, 1, 5, 4, 3, 2, 1]); } +#[test] +fn test_in_place_iterator_specialization() { + let src: Vec = vec![1, 2, 3]; + let src_ptr = src.as_ptr(); + let heap: BinaryHeap<_> = src.into_iter().map(std::convert::identity).collect(); + let heap_ptr = heap.iter().next().unwrap() as *const usize; + assert_eq!(src_ptr, heap_ptr); + let sink: Vec<_> = heap.into_iter().map(std::convert::identity).collect(); + let sink_ptr = sink.as_ptr(); + assert_eq!(heap_ptr, sink_ptr); +} + #[test] fn test_empty_pop() { let mut heap = BinaryHeap::::new(); diff --git a/library/alloc/tests/borrow.rs b/library/alloc/tests/borrow.rs index 8bfcf323f6..57976aa6cd 100644 --- a/library/alloc/tests/borrow.rs +++ b/library/alloc/tests/borrow.rs @@ -45,3 +45,16 @@ fn test_from_cow_path() { let path = Path::new("hello"); test_from_cow!(path: &Path); } + +#[test] +fn cow_const() { + // test that the methods of `Cow` are usable in a const context + + const COW: Cow<'_, str> = Cow::Borrowed("moo"); + + const IS_BORROWED: bool = COW.is_borrowed(); + assert!(IS_BORROWED); + + const IS_OWNED: bool = COW.is_owned(); + assert!(!IS_OWNED); +} diff --git a/library/alloc/tests/boxed.rs b/library/alloc/tests/boxed.rs index 851ca17a36..6a83f5da87 100644 --- a/library/alloc/tests/boxed.rs +++ b/library/alloc/tests/boxed.rs @@ -1,3 +1,4 @@ +use std::cell::Cell; use std::mem::MaybeUninit; use std::ptr::NonNull; @@ -49,3 +50,10 @@ fn box_clone_from_ptr_stability() { assert_eq!(copy.as_ptr() as usize, copy_raw); } } + +#[test] +fn box_deref_lval() { + let x = Box::new(Cell::new(5)); + x.set(1000); + assert_eq!(x.get(), 1000); +} diff --git a/library/alloc/tests/fmt.rs b/library/alloc/tests/fmt.rs index 0ad092b499..757fddd241 100644 --- a/library/alloc/tests/fmt.rs +++ b/library/alloc/tests/fmt.rs @@ -1,7 +1,327 @@ -use std::fmt; +#![deny(warnings)] + +use std::cell::RefCell; +use std::fmt::{self, Write}; #[test] fn test_format() { let s = fmt::format(format_args!("Hello, {}!", "world")); assert_eq!(s, "Hello, world!"); } + +struct A; +struct B; +struct C; +struct D; + +impl fmt::LowerHex for A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("aloha") + } +} +impl fmt::UpperHex for B { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("adios") + } +} +impl fmt::Display for C { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad_integral(true, "☃", "123") + } +} +impl fmt::Binary for D { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("aa")?; + f.write_char('☃')?; + f.write_str("bb") + } +} + +macro_rules! t { + ($a:expr, $b:expr) => { + assert_eq!($a, $b) + }; +} + +#[test] +fn test_format_macro_interface() { + // Various edge cases without formats + t!(format!(""), ""); + t!(format!("hello"), "hello"); + t!(format!("hello {{"), "hello {"); + + // default formatters should work + t!(format!("{}", 1.0f32), "1"); + t!(format!("{}", 1.0f64), "1"); + t!(format!("{}", "a"), "a"); + t!(format!("{}", "a".to_string()), "a"); + t!(format!("{}", false), "false"); + t!(format!("{}", 'a'), "a"); + + // At least exercise all the formats + t!(format!("{}", true), "true"); + t!(format!("{}", '☃'), "☃"); + t!(format!("{}", 10), "10"); + t!(format!("{}", 10_usize), "10"); + t!(format!("{:?}", '☃'), "'☃'"); + t!(format!("{:?}", 10), "10"); + t!(format!("{:?}", 10_usize), "10"); + t!(format!("{:?}", "true"), "\"true\""); + t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); + t!( + format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), + r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""# + ); + t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), r#""foo\u{0}bar\u{1}baz\u{7f}qux""#); + t!(format!("{:o}", 10_usize), "12"); + t!(format!("{:x}", 10_usize), "a"); + t!(format!("{:X}", 10_usize), "A"); + t!(format!("{}", "foo"), "foo"); + t!(format!("{}", "foo".to_string()), "foo"); + if cfg!(target_pointer_width = "32") { + t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234"); + t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234"); + } else { + t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234"); + t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234"); + } + t!(format!("{:p}", 0x1234 as *const isize), "0x1234"); + t!(format!("{:p}", 0x1234 as *mut isize), "0x1234"); + t!(format!("{:x}", A), "aloha"); + t!(format!("{:X}", B), "adios"); + t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); + t!(format!("{1} {0}", 0, 1), "1 0"); + t!(format!("{foo} {bar}", foo = 0, bar = 1), "0 1"); + t!(format!("{foo} {1} {bar} {0}", 0, 1, foo = 2, bar = 3), "2 1 3 0"); + t!(format!("{} {0}", "a"), "a a"); + t!(format!("{_foo}", _foo = 6usize), "6"); + t!(format!("{foo_bar}", foo_bar = 1), "1"); + t!(format!("{}", 5 + 5), "10"); + t!(format!("{:#4}", C), "☃123"); + t!(format!("{:b}", D), "aa☃bb"); + + let a: &dyn fmt::Debug = &1; + t!(format!("{:?}", a), "1"); + + // Formatting strings and their arguments + t!(format!("{}", "a"), "a"); + t!(format!("{:4}", "a"), "a "); + t!(format!("{:4}", "☃"), "☃ "); + t!(format!("{:>4}", "a"), " a"); + t!(format!("{:<4}", "a"), "a "); + t!(format!("{:^5}", "a"), " a "); + t!(format!("{:^5}", "aa"), " aa "); + t!(format!("{:^4}", "a"), " a "); + t!(format!("{:^4}", "aa"), " aa "); + t!(format!("{:.4}", "a"), "a"); + t!(format!("{:4.4}", "a"), "a "); + t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); + t!(format!("{:2.4}", "aaaaa"), "aaaa"); + t!(format!("{:2.4}", "aaaa"), "aaaa"); + t!(format!("{:2.4}", "aaa"), "aaa"); + t!(format!("{:2.4}", "aa"), "aa"); + t!(format!("{:2.4}", "a"), "a "); + t!(format!("{:0>2}", "a"), "0a"); + t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); + t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); + t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a = 4), "aaaa"); + t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a = 4), "aaaa"); + t!(format!("{:1$}", "a", 4), "a "); + t!(format!("{1:0$}", 4, "a"), "a "); + t!(format!("{:a$}", "a", a = 4), "a "); + t!(format!("{:-#}", "a"), "a"); + t!(format!("{:+#}", "a"), "a"); + t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); + + // Some float stuff + t!(format!("{:}", 1.0f32), "1"); + t!(format!("{:}", 1.0f64), "1"); + t!(format!("{:.3}", 1.0f64), "1.000"); + t!(format!("{:10.3}", 1.0f64), " 1.000"); + t!(format!("{:+10.3}", 1.0f64), " +1.000"); + t!(format!("{:+10.3}", -1.0f64), " -1.000"); + + t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); + t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); + t!(format!("{:E}", 1.2345e6f64), "1.2345E6"); + t!(format!("{:.3e}", 1.2345e6f64), "1.234e6"); + t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6"); + t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); + t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); + + // Float edge cases + t!(format!("{}", -0.0), "0"); + t!(format!("{:?}", -0.0), "-0.0"); + t!(format!("{:?}", 0.0), "0.0"); + + // sign aware zero padding + t!(format!("{:<3}", 1), "1 "); + t!(format!("{:>3}", 1), " 1"); + t!(format!("{:^3}", 1), " 1 "); + t!(format!("{:03}", 1), "001"); + t!(format!("{:<03}", 1), "001"); + t!(format!("{:>03}", 1), "001"); + t!(format!("{:^03}", 1), "001"); + t!(format!("{:+03}", 1), "+01"); + t!(format!("{:<+03}", 1), "+01"); + t!(format!("{:>+03}", 1), "+01"); + t!(format!("{:^+03}", 1), "+01"); + t!(format!("{:#05x}", 1), "0x001"); + t!(format!("{:<#05x}", 1), "0x001"); + t!(format!("{:>#05x}", 1), "0x001"); + t!(format!("{:^#05x}", 1), "0x001"); + t!(format!("{:05}", 1.2), "001.2"); + t!(format!("{:<05}", 1.2), "001.2"); + t!(format!("{:>05}", 1.2), "001.2"); + t!(format!("{:^05}", 1.2), "001.2"); + t!(format!("{:05}", -1.2), "-01.2"); + t!(format!("{:<05}", -1.2), "-01.2"); + t!(format!("{:>05}", -1.2), "-01.2"); + t!(format!("{:^05}", -1.2), "-01.2"); + t!(format!("{:+05}", 1.2), "+01.2"); + t!(format!("{:<+05}", 1.2), "+01.2"); + t!(format!("{:>+05}", 1.2), "+01.2"); + t!(format!("{:^+05}", 1.2), "+01.2"); + + // Ergonomic format_args! + t!(format!("{0:x} {0:X}", 15), "f F"); + t!(format!("{0:x} {0:X} {}", 15), "f F 15"); + t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a = 15), "dDfEeF"); + t!(format!("{a:x} {a:X}", a = 15), "f F"); + + // And its edge cases + t!( + format!( + "{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}", + 4, + a = "abcdefg", + b = "hijklmn", + c = 3 + ), + "abcd hijk 4\nabc hij 3" + ); + t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a = "abcdef"), "abcd 4 efg"); + t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a = 2), "aa 2 0x2"); + + // Test that pointers don't get truncated. + { + let val = usize::MAX; + let exp = format!("{:#x}", val); + t!(format!("{:p}", val as *const isize), exp); + } + + // Escaping + t!(format!("{{"), "{"); + t!(format!("}}"), "}"); + + // make sure that format! doesn't move out of local variables + let a = Box::new(3); + format!("{}", a); + format!("{}", a); + + // make sure that format! doesn't cause spurious unused-unsafe warnings when + // it's inside of an outer unsafe block + unsafe { + let a: isize = ::std::mem::transmute(3_usize); + format!("{}", a); + } + + // test that trailing commas are acceptable + format!("{}", "test",); + format!("{foo}", foo = "test",); +} + +// Basic test to make sure that we can invoke the `write!` macro with an +// fmt::Write instance. +#[test] +fn test_write() { + let mut buf = String::new(); + let _ = write!(&mut buf, "{}", 3); + { + let w = &mut buf; + let _ = write!(w, "{foo}", foo = 4); + let _ = write!(w, "{}", "hello"); + let _ = writeln!(w, "{}", "line"); + let _ = writeln!(w, "{foo}", foo = "bar"); + let _ = w.write_char('☃'); + let _ = w.write_str("str"); + } + + t!(buf, "34helloline\nbar\n☃str"); +} + +// Just make sure that the macros are defined, there's not really a lot that we +// can do with them just yet (to test the output) +#[test] +fn test_print() { + print!("hi"); + print!("{:?}", vec![0u8]); + println!("hello"); + println!("this is a {}", "test"); + println!("{foo}", foo = "bar"); +} + +// Just make sure that the macros are defined, there's not really a lot that we +// can do with them just yet (to test the output) +#[test] +fn test_format_args() { + let mut buf = String::new(); + { + let w = &mut buf; + let _ = write!(w, "{}", format_args!("{}", 1)); + let _ = write!(w, "{}", format_args!("test")); + let _ = write!(w, "{}", format_args!("{test}", test = 3)); + } + let s = buf; + t!(s, "1test3"); + + let s = fmt::format(format_args!("hello {}", "world")); + t!(s, "hello world"); + let s = format!("{}: {}", "args were", format_args!("hello {}", "world")); + t!(s, "args were: hello world"); +} + +#[test] +fn test_order() { + // Make sure format!() arguments are always evaluated in a left-to-right + // ordering + fn foo() -> isize { + static mut FOO: isize = 0; + unsafe { + FOO += 1; + FOO + } + } + assert_eq!( + format!("{} {} {a} {b} {} {c}", foo(), foo(), foo(), a = foo(), b = foo(), c = foo()), + "1 2 4 5 3 6".to_string() + ); +} + +#[test] +fn test_once() { + // Make sure each argument are evaluated only once even though it may be + // formatted multiple times + fn foo() -> isize { + static mut FOO: isize = 0; + unsafe { + FOO += 1; + FOO + } + } + assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a = foo()), "1 1 1 2 2 2".to_string()); +} + +#[test] +fn test_refcell() { + let refcell = RefCell::new(5); + assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); + let borrow = refcell.borrow_mut(); + assert_eq!(format!("{:?}", refcell), "RefCell { value: }"); + drop(borrow); + assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); +} diff --git a/library/alloc/tests/heap.rs b/library/alloc/tests/heap.rs index cbde2a7e28..a7239a4b14 100644 --- a/library/alloc/tests/heap.rs +++ b/library/alloc/tests/heap.rs @@ -11,7 +11,7 @@ fn std_heap_overaligned_request() { check_overalign_requests(Global) } -fn check_overalign_requests(mut allocator: T) { +fn check_overalign_requests(allocator: T) { for &align in &[4, 8, 16, 32] { // less than and bigger than `MIN_ALIGN` for &size in &[align / 2, align - 1] { diff --git a/library/alloc/tests/lib.rs b/library/alloc/tests/lib.rs index f2ba1ab648..cff8ff9ac7 100644 --- a/library/alloc/tests/lib.rs +++ b/library/alloc/tests/lib.rs @@ -1,5 +1,7 @@ #![feature(allocator_api)] #![feature(box_syntax)] +#![feature(cow_is_borrowed)] +#![feature(const_cow_is_borrowed)] #![feature(drain_filter)] #![feature(exact_size_is_empty)] #![feature(new_uninit)] @@ -14,6 +16,10 @@ #![feature(slice_ptr_get)] #![feature(split_inclusive)] #![feature(binary_heap_retain)] +#![feature(deque_range)] +#![feature(inplace_iteration)] +#![feature(iter_map_while)] +#![feature(int_bits_const)] use std::collections::hash_map::DefaultHasher; use std::hash::{Hash, Hasher}; diff --git a/library/alloc/tests/slice.rs b/library/alloc/tests/slice.rs index 3c7d57f8b3..1f561bebd9 100644 --- a/library/alloc/tests/slice.rs +++ b/library/alloc/tests/slice.rs @@ -1459,6 +1459,15 @@ fn test_to_vec() { assert_eq!(ys, [1, 2, 3]); } +#[test] +fn test_in_place_iterator_specialization() { + let src: Box<[usize]> = box [1, 2, 3]; + let src_ptr = src.as_ptr(); + let sink: Box<_> = src.into_vec().into_iter().map(std::convert::identity).collect(); + let sink_ptr = sink.as_ptr(); + assert_eq!(src_ptr, sink_ptr); +} + #[test] fn test_box_slice_clone() { let data = vec![vec![0, 1], vec![0], vec![1]]; diff --git a/library/alloc/tests/str.rs b/library/alloc/tests/str.rs index b20cf076ac..ed8ee2d882 100644 --- a/library/alloc/tests/str.rs +++ b/library/alloc/tests/str.rs @@ -1921,3 +1921,24 @@ fn different_str_pattern_forwarding_lifetimes() { foo::<&str>("x"); } + +#[test] +fn test_str_multiline() { + let a: String = "this \ +is a test" + .to_string(); + let b: String = "this \ + is \ + another \ + test" + .to_string(); + assert_eq!(a, "this is a test".to_string()); + assert_eq!(b, "this is another test".to_string()); +} + +#[test] +fn test_str_escapes() { + let x = "\\\\\ + "; + assert_eq!(x, r"\\"); // extraneous whitespace stripped +} diff --git a/library/alloc/tests/string.rs b/library/alloc/tests/string.rs index d38655af78..a6e41b21b6 100644 --- a/library/alloc/tests/string.rs +++ b/library/alloc/tests/string.rs @@ -1,6 +1,6 @@ use std::borrow::Cow; use std::collections::TryReserveError::*; -use std::mem::size_of; +use std::ops::Bound::*; pub trait IntoCow<'a, B: ?Sized> where @@ -271,24 +271,28 @@ fn test_split_off_past_end() { #[test] #[should_panic] fn test_split_off_mid_char() { - let mut orig = String::from("山"); - let _ = orig.split_off(1); + let mut shan = String::from("山"); + let _broken_mountain = shan.split_off(1); } #[test] fn test_split_off_ascii() { let mut ab = String::from("ABCD"); + let orig_capacity = ab.capacity(); let cd = ab.split_off(2); assert_eq!(ab, "AB"); assert_eq!(cd, "CD"); + assert_eq!(ab.capacity(), orig_capacity); } #[test] fn test_split_off_unicode() { let mut nihon = String::from("日本語"); + let orig_capacity = nihon.capacity(); let go = nihon.split_off("日本".len()); assert_eq!(nihon, "日本"); assert_eq!(go, "語"); + assert_eq!(nihon.capacity(), orig_capacity); } #[test] @@ -463,6 +467,20 @@ fn test_drain() { assert_eq!(t, ""); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut s = String::from("abc"); + s.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut s = String::from("abc"); + s.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_replace_range() { let mut s = "Hello, world!".to_owned(); @@ -500,6 +518,20 @@ fn test_replace_range_inclusive_out_of_bounds() { s.replace_range(5..=5, "789"); } +#[test] +#[should_panic] +fn test_replace_range_start_overflow() { + let mut s = String::from("123"); + s.replace_range((Excluded(usize::MAX), Included(0)), ""); +} + +#[test] +#[should_panic] +fn test_replace_range_end_overflow() { + let mut s = String::from("456"); + s.replace_range((Included(0), Included(usize::MAX)), ""); +} + #[test] fn test_replace_range_empty() { let mut s = String::from("12345"); @@ -572,7 +604,7 @@ fn test_try_reserve() { // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. // Any platform that succeeds for these requests is technically broken with // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve @@ -653,7 +685,7 @@ fn test_try_reserve_exact() { const MAX_CAP: usize = isize::MAX as usize; const MAX_USIZE: usize = usize::MAX; - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { let mut empty_string: String = String::new(); @@ -721,3 +753,11 @@ fn test_from_char() { let s: String = 'x'.into(); assert_eq!(s, 'x'.to_string()); } + +#[test] +fn test_str_concat() { + let a: String = "hello".to_string(); + let b: String = "world".to_string(); + let s: String = format!("{}{}", a, b); + assert_eq!(s.as_bytes()[9], 'd' as u8); +} diff --git a/library/alloc/tests/vec.rs b/library/alloc/tests/vec.rs index ffff543b07..b7c7138db4 100644 --- a/library/alloc/tests/vec.rs +++ b/library/alloc/tests/vec.rs @@ -1,8 +1,12 @@ use std::borrow::Cow; +use std::cell::Cell; use std::collections::TryReserveError::*; use std::fmt::Debug; +use std::iter::InPlaceIterable; use std::mem::size_of; +use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; +use std::rc::Rc; use std::vec::{Drain, IntoIter}; struct DropCounter<'a> { @@ -72,6 +76,42 @@ fn test_zst_capacity() { assert_eq!(Vec::<()>::new().capacity(), usize::MAX); } +#[test] +fn test_indexing() { + let v: Vec = vec![10, 20]; + assert_eq!(v[0], 10); + assert_eq!(v[1], 20); + let mut x: usize = 0; + assert_eq!(v[x], 10); + assert_eq!(v[x + 1], 20); + x = x + 1; + assert_eq!(v[x], 20); + assert_eq!(v[x - 1], 10); +} + +#[test] +fn test_debug_fmt() { + let vec1: Vec = vec![]; + assert_eq!("[]", format!("{:?}", vec1)); + + let vec2 = vec![0, 1]; + assert_eq!("[0, 1]", format!("{:?}", vec2)); + + let slice: &[isize] = &[4, 5]; + assert_eq!("[4, 5]", format!("{:?}", slice)); +} + +#[test] +fn test_push() { + let mut v = vec![]; + v.push(1); + assert_eq!(v, [1]); + v.push(2); + assert_eq!(v, [1, 2]); + v.push(3); + assert_eq!(v, [1, 2, 3]); +} + #[test] fn test_extend() { let mut v = Vec::new(); @@ -117,6 +157,18 @@ fn test_extend() { assert_eq!(count_x, 1); } +#[test] +fn test_extend_from_slice() { + let a: Vec = vec![1, 2, 3, 4, 5]; + let b: Vec = vec![6, 7, 8, 9, 0]; + + let mut v: Vec = a; + + v.extend_from_slice(&b); + + assert_eq!(v, [1, 2, 3, 4, 5, 6, 7, 8, 9, 0]); +} + #[test] fn test_extend_ref() { let mut v = vec![1, 2]; @@ -132,6 +184,14 @@ fn test_extend_ref() { assert_eq!(v, [1, 2, 3, 4, 5, 6, 7]); } +#[test] +fn test_slice_from_ref() { + let values = vec![1, 2, 3, 4, 5]; + let slice = &values[1..3]; + + assert_eq!(slice, [2, 3]); +} + #[test] fn test_slice_from_mut() { let mut values = vec![1, 2, 3, 4, 5]; @@ -343,6 +403,29 @@ fn test_zip_unzip() { assert_eq!((3, 6), (left[2], right[2])); } +#[test] +fn test_cmp() { + let x: &[isize] = &[1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); + + let x: Vec = vec![1, 2, 3, 4, 5]; + let cmp: &[isize] = &[1, 2, 3, 4, 5]; + assert_eq!(&x[..], cmp); + let cmp: &[isize] = &[3, 4, 5]; + assert_eq!(&x[2..], cmp); + let cmp: &[isize] = &[1, 2, 3]; + assert_eq!(&x[..3], cmp); + let cmp: &[isize] = &[2, 3, 4]; + assert_eq!(&x[1..4], cmp); +} + #[test] fn test_vec_truncate_drop() { static mut DROPS: u32 = 0; @@ -564,6 +647,16 @@ fn test_drain_max_vec_size() { assert_eq!(v.len(), usize::MAX - 1); } +#[test] +#[should_panic] +fn test_drain_index_overflow() { + let mut v = Vec::<()>::with_capacity(usize::MAX); + unsafe { + v.set_len(usize::MAX); + } + v.drain(0..=usize::MAX); +} + #[test] #[should_panic] fn test_drain_inclusive_out_of_bounds() { @@ -571,6 +664,20 @@ fn test_drain_inclusive_out_of_bounds() { v.drain(5..=5); } +#[test] +#[should_panic] +fn test_drain_start_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Excluded(usize::MAX), Included(0))); +} + +#[test] +#[should_panic] +fn test_drain_end_overflow() { + let mut v = vec![1, 2, 3]; + v.drain((Included(0), Included(usize::MAX))); +} + #[test] fn test_drain_leak() { static mut DROPS: i32 = 0; @@ -691,9 +798,23 @@ fn test_append() { #[test] fn test_split_off() { let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_capacity = vec.capacity(); let vec2 = vec.split_off(4); assert_eq!(vec, [1, 2, 3, 4]); assert_eq!(vec2, [5, 6]); + assert_eq!(vec.capacity(), orig_capacity); +} + +#[test] +fn test_split_off_take_all() { + let mut vec = vec![1, 2, 3, 4, 5, 6]; + let orig_ptr = vec.as_ptr(); + let orig_capacity = vec.capacity(); + let vec2 = vec.split_off(0); + assert_eq!(vec, []); + assert_eq!(vec2, [1, 2, 3, 4, 5, 6]); + assert_eq!(vec.capacity(), orig_capacity); + assert_eq!(vec2.as_ptr(), orig_ptr); } #[test] @@ -775,6 +896,87 @@ fn test_into_iter_leak() { assert_eq!(unsafe { DROPS }, 3); } +#[test] +fn test_from_iter_specialization() { + let src: Vec = vec![0usize; 1]; + let srcptr = src.as_ptr(); + let sink = src.into_iter().collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); +} + +#[test] +fn test_from_iter_partially_drained_in_place_specialization() { + let src: Vec = vec![0usize; 10]; + let srcptr = src.as_ptr(); + let mut iter = src.into_iter(); + iter.next(); + iter.next(); + let sink = iter.collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr); +} + +#[test] +fn test_from_iter_specialization_with_iterator_adapters() { + fn assert_in_place_trait(_: &T) {}; + let src: Vec = vec![0usize; 256]; + let srcptr = src.as_ptr(); + let iter = src + .into_iter() + .enumerate() + .map(|i| i.0 + i.1) + .zip(std::iter::repeat(1usize)) + .map(|(a, b)| a + b) + .map_while(Option::Some) + .peekable() + .skip(1) + .map(|e| std::num::NonZeroUsize::new(e)); + assert_in_place_trait(&iter); + let sink = iter.collect::>(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr as *const usize); +} + +#[test] +fn test_from_iter_specialization_head_tail_drop() { + let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); + let src: Vec<_> = drop_count.iter().cloned().collect(); + let srcptr = src.as_ptr(); + let iter = src.into_iter(); + let sink: Vec<_> = iter.skip(1).take(1).collect(); + let sinkptr = sink.as_ptr(); + assert_eq!(srcptr, sinkptr, "specialization was applied"); + assert_eq!(Rc::strong_count(&drop_count[0]), 1, "front was dropped"); + assert_eq!(Rc::strong_count(&drop_count[1]), 2, "one element was collected"); + assert_eq!(Rc::strong_count(&drop_count[2]), 1, "tail was dropped"); + assert_eq!(sink.len(), 1); +} + +#[test] +fn test_from_iter_specialization_panic_drop() { + let drop_count: Vec<_> = (0..=2).map(|_| Rc::new(())).collect(); + let src: Vec<_> = drop_count.iter().cloned().collect(); + let iter = src.into_iter(); + + let _ = std::panic::catch_unwind(AssertUnwindSafe(|| { + let _ = iter + .enumerate() + .filter_map(|(i, e)| { + if i == 1 { + std::panic!("aborting iteration"); + } + Some(e) + }) + .collect::>(); + })); + + assert!( + drop_count.iter().map(Rc::strong_count).all(|count| count == 1), + "all items were dropped once" + ); +} + #[test] fn test_cow_from() { let borrowed: &[_] = &["borrowed", "(slice)"]; @@ -1140,7 +1342,7 @@ fn test_try_reserve() { // on 64-bit, we assume the OS will give an OOM for such a ridiculous size. // Any platform that succeeds for these requests is technically broken with // ptr::offset because LLVM is the worst. - let guards_against_isize = size_of::() < 8; + let guards_against_isize = usize::BITS < 64; { // Note: basic stuff is checked by test_reserve @@ -1349,6 +1551,9 @@ fn test_stable_pointers() { // Test that, if we reserved enough space, adding and removing elements does not // invalidate references into the vector (such as `v0`). This test also // runs in Miri, which would detect such problems. + // Note that this test does *not* constitute a stable guarantee that all these functions do not + // reallocate! Only what is explicitly documented at + // is stably guaranteed. let mut v = Vec::with_capacity(128); v.push(13); @@ -1627,3 +1832,82 @@ fn partialeq_vec_full() { assert_partial_eq_valid!(vec2,vec3; array2,array3); assert_partial_eq_valid!(vec2,vec3; arrayref2,arrayref3); } + +#[test] +fn test_vec_cycle() { + #[derive(Debug)] + struct C<'a> { + v: Vec>>>, + } + + impl<'a> C<'a> { + fn new() -> C<'a> { + C { v: Vec::new() } + } + } + + let mut c1 = C::new(); + let mut c2 = C::new(); + let mut c3 = C::new(); + + // Push + c1.v.push(Cell::new(None)); + c1.v.push(Cell::new(None)); + + c2.v.push(Cell::new(None)); + c2.v.push(Cell::new(None)); + + c3.v.push(Cell::new(None)); + c3.v.push(Cell::new(None)); + + // Set + c1.v[0].set(Some(&c2)); + c1.v[1].set(Some(&c3)); + + c2.v[0].set(Some(&c2)); + c2.v[1].set(Some(&c3)); + + c3.v[0].set(Some(&c1)); + c3.v[1].set(Some(&c2)); +} + +#[test] +fn test_vec_cycle_wrapped() { + struct Refs<'a> { + v: Vec>>>, + } + + struct C<'a> { + refs: Refs<'a>, + } + + impl<'a> Refs<'a> { + fn new() -> Refs<'a> { + Refs { v: Vec::new() } + } + } + + impl<'a> C<'a> { + fn new() -> C<'a> { + C { refs: Refs::new() } + } + } + + let mut c1 = C::new(); + let mut c2 = C::new(); + let mut c3 = C::new(); + + c1.refs.v.push(Cell::new(None)); + c1.refs.v.push(Cell::new(None)); + c2.refs.v.push(Cell::new(None)); + c2.refs.v.push(Cell::new(None)); + c3.refs.v.push(Cell::new(None)); + c3.refs.v.push(Cell::new(None)); + + c1.refs.v[0].set(Some(&c2)); + c1.refs.v[1].set(Some(&c3)); + c2.refs.v[0].set(Some(&c2)); + c2.refs.v[1].set(Some(&c3)); + c3.refs.v[0].set(Some(&c1)); + c3.refs.v[1].set(Some(&c2)); +} diff --git a/library/alloc/tests/vec_deque.rs b/library/alloc/tests/vec_deque.rs index 762dc4be44..46d8a3c4cb 100644 --- a/library/alloc/tests/vec_deque.rs +++ b/library/alloc/tests/vec_deque.rs @@ -2,6 +2,7 @@ use std::collections::TryReserveError::*; use std::collections::{vec_deque::Drain, VecDeque}; use std::fmt::Debug; use std::mem::size_of; +use std::ops::Bound::*; use std::panic::{catch_unwind, AssertUnwindSafe}; use crate::hash; @@ -115,6 +116,20 @@ fn test_index_out_of_bounds() { deq[3]; } +#[test] +#[should_panic] +fn test_range_start_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Included(0), Included(usize::MAX))); +} + +#[test] +#[should_panic] +fn test_range_end_overflow() { + let deq = VecDeque::from(vec![1, 2, 3]); + deq.range((Excluded(usize::MAX), Included(0))); +} + #[derive(Clone, PartialEq, Debug)] enum Taggy { One(i32), diff --git a/library/core/benches/num/flt2dec/strategy/dragon.rs b/library/core/benches/num/flt2dec/strategy/dragon.rs index 4e1fd8bf75..319b9773e4 100644 --- a/library/core/benches/num/flt2dec/strategy/dragon.rs +++ b/library/core/benches/num/flt2dec/strategy/dragon.rs @@ -1,59 +1,76 @@ use super::super::*; use core::num::flt2dec::strategy::dragon::*; +use std::mem::MaybeUninit; use test::Bencher; #[bench] fn bench_small_shortest(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_big_shortest(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_small_exact_3(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_3(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_12(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_12(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_inf(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_inf(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } diff --git a/library/core/benches/num/flt2dec/strategy/grisu.rs b/library/core/benches/num/flt2dec/strategy/grisu.rs index 77ca901a90..76425731e1 100644 --- a/library/core/benches/num/flt2dec/strategy/grisu.rs +++ b/library/core/benches/num/flt2dec/strategy/grisu.rs @@ -1,5 +1,6 @@ use super::super::*; use core::num::flt2dec::strategy::grisu::*; +use std::mem::MaybeUninit; use test::Bencher; pub fn decode_finite(v: T) -> Decoded { @@ -12,55 +13,71 @@ pub fn decode_finite(v: T) -> Decoded { #[bench] fn bench_small_shortest(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_big_shortest(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; MAX_SIG_DIGITS]; - b.iter(|| format_shortest(&decoded, &mut buf)); + let mut buf = [MaybeUninit::new(0); MAX_SIG_DIGITS]; + b.iter(|| { + format_shortest(&decoded, &mut buf); + }); } #[bench] fn bench_small_exact_3(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_3(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 3]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 3]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_12(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_12(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 12]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 12]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_small_exact_inf(b: &mut Bencher) { let decoded = decode_finite(3.141592f64); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } #[bench] fn bench_big_exact_inf(b: &mut Bencher) { let decoded = decode_finite(f64::MAX); - let mut buf = [0; 1024]; - b.iter(|| format_exact(&decoded, &mut buf, i16::MIN)); + let mut buf = [MaybeUninit::new(0); 1024]; + b.iter(|| { + format_exact(&decoded, &mut buf, i16::MIN); + }); } diff --git a/library/core/src/alloc/layout.rs b/library/core/src/alloc/layout.rs index a5ddf7619b..a3fbed2ec1 100644 --- a/library/core/src/alloc/layout.rs +++ b/library/core/src/alloc/layout.rs @@ -177,6 +177,7 @@ impl Layout { /// sentinel value. Types that lazily allocate must track initialization by /// some other means. #[unstable(feature = "alloc_layout_extra", issue = "55724")] + #[rustc_const_unstable(feature = "alloc_layout_extra", issue = "55724")] #[inline] pub const fn dangling(&self) -> NonNull { // SAFETY: align is guaranteed to be non-zero diff --git a/library/core/src/alloc/mod.rs b/library/core/src/alloc/mod.rs index ad4f8bf139..6d09b4f026 100644 --- a/library/core/src/alloc/mod.rs +++ b/library/core/src/alloc/mod.rs @@ -13,17 +13,17 @@ pub use self::layout::{Layout, LayoutErr}; use crate::fmt; use crate::ptr::{self, NonNull}; -/// The `AllocErr` error indicates an allocation failure +/// The `AllocError` error indicates an allocation failure /// that may be due to resource exhaustion or to /// something wrong when combining the given input arguments with this /// allocator. #[unstable(feature = "allocator_api", issue = "32838")] #[derive(Copy, Clone, PartialEq, Eq, Debug)] -pub struct AllocErr; +pub struct AllocError; // (we need this for downstream impl of trait Error) #[unstable(feature = "allocator_api", issue = "32838")] -impl fmt::Display for AllocErr { +impl fmt::Display for AllocError { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("memory allocation failed") } @@ -109,7 +109,7 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc(&mut self, layout: Layout) -> Result, AllocErr>; + fn alloc(&self, layout: Layout) -> Result, AllocError>; /// Behaves like `alloc`, but also ensures that the returned memory is zero-initialized. /// @@ -126,7 +126,7 @@ pub unsafe trait AllocRef { /// call the [`handle_alloc_error`] function, rather than directly invoking `panic!` or similar. /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { let ptr = self.alloc(layout)?; // SAFETY: `alloc` returns a valid memory block unsafe { ptr.as_non_null_ptr().as_ptr().write_bytes(0, ptr.len()) } @@ -142,14 +142,13 @@ pub unsafe trait AllocRef { /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout); + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout); /// Attempts to extend the memory block. /// /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated - /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s - /// alignment and a size given by `new_size`. To accomplish this, the allocator may extend the - /// allocation referenced by `ptr` to fit the new layout. + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may extend the allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be @@ -163,11 +162,9 @@ pub unsafe trait AllocRef { /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), - /// * `new_size` must be greater than or equal to `layout.size()`, and - /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow - /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -186,30 +183,26 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let size = layout.size(); + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc(new_layout)?; - // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `size` bytes. Also, because the old - // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -220,21 +213,19 @@ pub unsafe trait AllocRef { /// /// The memory block will contain the following contents after a successful call to /// `grow_zeroed`: - /// * Bytes `0..layout.size()` are preserved from the original allocation. - /// * Bytes `layout.size()..old_size` will either be preserved or zeroed, depending on the - /// allocator implementation. `old_size` refers to the size of the memory block prior to - /// the `grow_zeroed` call, which may be larger than the size that was originally requested - /// when it was allocated. + /// * Bytes `0..old_layout.size()` are preserved from the original allocation. + /// * Bytes `old_layout.size()..old_size` will either be preserved or zeroed, depending on + /// the allocator implementation. `old_size` refers to the size of the memory block prior + /// to the `grow_zeroed` call, which may be larger than the size that was originally + /// requested when it was allocated. /// * Bytes `old_size..new_size` are zeroed. `new_size` refers to the size of the memory - /// block returned by the `grow` call. + /// block returned by the `grow_zeroed` call. /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), - /// * `new_size` must be greater than or equal to `layout.size()`, and - /// * `new_size`, when rounded up to the nearest multiple of `layout.align()`, must not overflow - /// (i.e., the rounded value must be less than or equal to `usize::MAX`). + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be greater than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -253,30 +244,26 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let size = layout.size(); + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size >= size, - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc_zeroed(new_layout)?; - // SAFETY: because `new_size` must be greater than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `size` bytes. Also, because the old - // allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be greater than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `old_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -285,9 +272,8 @@ pub unsafe trait AllocRef { /// Attempts to shrink the memory block. /// /// Returns a new [`NonNull<[u8]>`] containing a pointer and the actual size of the allocated - /// memory. The pointer is suitable for holding data described by a new layout with `layout`’s - /// alignment and a size given by `new_size`. To accomplish this, the allocator may shrink the - /// allocation referenced by `ptr` to fit the new layout. + /// memory. The pointer is suitable for holding data described by `new_layout`. To accomplish + /// this, the allocator may shrink the allocation referenced by `ptr` to fit the new layout. /// /// If this returns `Ok`, then ownership of the memory block referenced by `ptr` has been /// transferred to this allocator. The memory may or may not have been freed, and should be @@ -301,9 +287,9 @@ pub unsafe trait AllocRef { /// /// # Safety /// - /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator, - /// * `layout` must [*fit*] that block of memory (The `new_size` argument need not fit it.), and - /// * `new_size` must be smaller than or equal to `layout.size()`. + /// * `ptr` must denote a block of memory [*currently allocated*] via this allocator. + /// * `old_layout` must [*fit*] that block of memory (The `new_layout` argument need not fit it.). + /// * `new_layout.size()` must be smaller than or equal to `old_layout.size()`. /// /// [*currently allocated*]: #currently-allocated-memory /// [*fit*]: #memory-fitting @@ -322,30 +308,26 @@ pub unsafe trait AllocRef { /// /// [`handle_alloc_error`]: ../../alloc/alloc/fn.handle_alloc_error.html unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { - let size = layout.size(); + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size <= size, - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - let new_layout = unsafe { Layout::from_size_align_unchecked(new_size, layout.align()) }; let new_ptr = self.alloc(new_layout)?; - // SAFETY: because `new_size` must be lower than or equal to `size`, both the old and new - // memory allocation are valid for reads and writes for `new_size` bytes. Also, because the - // old allocation wasn't yet deallocated, it cannot overlap `new_ptr`. Thus, the call to - // `copy_nonoverlapping` is safe. - // The safety contract for `dealloc` must be upheld by the caller. + // SAFETY: because `new_layout.size()` must be lower than or equal to + // `old_layout.size()`, both the old and new memory allocation are valid for reads and + // writes for `new_layout.size()` bytes. Also, because the old allocation wasn't yet + // deallocated, it cannot overlap `new_ptr`. Thus, the call to `copy_nonoverlapping` is + // safe. The safety contract for `dealloc` must be upheld by the caller. unsafe { - ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), size); - self.dealloc(ptr, layout); + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_layout.size()); + self.dealloc(ptr, old_layout); } Ok(new_ptr) @@ -355,62 +337,62 @@ pub unsafe trait AllocRef { /// /// The returned adaptor also implements `AllocRef` and will simply borrow this. #[inline(always)] - fn by_ref(&mut self) -> &mut Self { + fn by_ref(&self) -> &Self { self } } #[unstable(feature = "allocator_api", issue = "32838")] -unsafe impl AllocRef for &mut A +unsafe impl AllocRef for &A where A: AllocRef + ?Sized, { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { (**self).alloc(layout) } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { (**self).alloc_zeroed(layout) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { // SAFETY: the safety contract must be upheld by the caller unsafe { (**self).dealloc(ptr, layout) } } #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow(ptr, layout, new_size) } + unsafe { (**self).grow(ptr, old_layout, new_layout) } } #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).grow_zeroed(ptr, layout, new_size) } + unsafe { (**self).grow_zeroed(ptr, old_layout, new_layout) } } #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: the safety contract must be upheld by the caller - unsafe { (**self).shrink(ptr, layout, new_size) } + unsafe { (**self).shrink(ptr, old_layout, new_layout) } } } diff --git a/library/core/src/array/iter.rs b/library/core/src/array/iter.rs index 919070aadf..cafb002c01 100644 --- a/library/core/src/array/iter.rs +++ b/library/core/src/array/iter.rs @@ -73,7 +73,7 @@ impl IntoIter { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked(self.alive.clone()); - MaybeUninit::slice_get_ref(slice) + MaybeUninit::slice_assume_init_ref(slice) } } @@ -82,7 +82,7 @@ impl IntoIter { // SAFETY: We know that all elements within `alive` are properly initialized. unsafe { let slice = self.data.get_unchecked_mut(self.alive.clone()); - MaybeUninit::slice_get_mut(slice) + MaybeUninit::slice_assume_init_mut(slice) } } } @@ -103,7 +103,7 @@ impl Iterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the start of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } @@ -136,7 +136,7 @@ impl DoubleEndedIterator for IntoIter { // dead now (i.e. do not touch). As `idx` was the end of the // alive-zone, the alive zone is now `data[alive]` again, restoring // all invariants. - unsafe { self.data.get_unchecked(idx).read() } + unsafe { self.data.get_unchecked(idx).assume_init_read() } }) } } diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 88795d8429..966272ca11 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -19,6 +19,20 @@ mod iter; #[unstable(feature = "array_value_iter", issue = "65798")] pub use iter::IntoIter; +/// Converts a reference to `T` into a reference to an array of length 1 (without copying). +#[unstable(feature = "array_from_ref", issue = "77101")] +pub fn from_ref(s: &T) -> &[T; 1] { + // SAFETY: Converting `&T` to `&[T; 1]` is sound. + unsafe { &*(s as *const T).cast::<[T; 1]>() } +} + +/// Converts a mutable reference to `T` into a mutable reference to an array of length 1 (without copying). +#[unstable(feature = "array_from_ref", issue = "77101")] +pub fn from_mut(s: &mut T) -> &mut [T; 1] { + // SAFETY: Converting `&mut T` to `&mut [T; 1]` is sound. + unsafe { &mut *(s as *mut T).cast::<[T; 1]>() } +} + /// Utility trait implemented only on arrays of fixed size /// /// This trait can be used to implement other traits on fixed-size arrays @@ -362,7 +376,6 @@ macro_rules! array_impl_default { array_impl_default! {32, T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T T} -#[cfg(not(bootstrap))] #[lang = "array"] impl [T; N] { /// Returns an array of the same size as `self`, with function `f` applied to each element @@ -411,7 +424,7 @@ impl [T; N] { } let mut dst = MaybeUninit::uninit_array::(); let mut guard: Guard = - Guard { dst: MaybeUninit::first_ptr_mut(&mut dst), initialized: 0 }; + Guard { dst: MaybeUninit::slice_as_mut_ptr(&mut dst), initialized: 0 }; for (src, dst) in IntoIter::new(self).zip(&mut dst) { dst.write(f(src)); guard.initialized += 1; @@ -423,4 +436,17 @@ impl [T; N] { // and we just need to cast it to the correct type. unsafe { crate::mem::transmute_copy::<_, [U; N]>(&dst) } } + + /// Returns a slice containing the entire array. Equivalent to `&s[..]`. + #[unstable(feature = "array_methods", issue = "76118")] + pub fn as_slice(&self) -> &[T] { + self + } + + /// Returns a mutable slice containing the entire array. Equivalent to + /// `&mut s[..]`. + #[unstable(feature = "array_methods", issue = "76118")] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self + } } diff --git a/library/core/src/ascii.rs b/library/core/src/ascii.rs index e78dfd1ed4..a8a25f9271 100644 --- a/library/core/src/ascii.rs +++ b/library/core/src/ascii.rs @@ -6,8 +6,6 @@ //! //! The [`escape_default`] function provides an iterator over the bytes of an //! escaped version of the character given. -//! -//! [`escape_default`]: fn.escape_default.html #![stable(feature = "core_ascii", since = "1.26.0")] @@ -20,8 +18,6 @@ use crate::str::from_utf8_unchecked; /// /// This `struct` is created by the [`escape_default`] function. See its /// documentation for more. -/// -/// [`escape_default`]: fn.escape_default.html #[stable(feature = "rust1", since = "1.0.0")] #[derive(Clone)] pub struct EscapeDefault { diff --git a/library/core/src/cell.rs b/library/core/src/cell.rs index cbbfcb4611..15ec13ca65 100644 --- a/library/core/src/cell.rs +++ b/library/core/src/cell.rs @@ -496,10 +496,7 @@ impl Cell { #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] pub fn get_mut(&mut self) -> &mut T { - // SAFETY: This can cause data races if called from a separate thread, - // but `Cell` is `!Sync` so this won't happen, and `&mut` guarantees - // unique access. - unsafe { &mut *self.value.get() } + self.value.get_mut() } /// Returns a `&Cell` from a `&mut T` @@ -700,6 +697,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "refcell_replace", since = "1.24.0")] + #[track_caller] pub fn replace(&self, t: T) -> T { mem::replace(&mut *self.borrow_mut(), t) } @@ -722,6 +720,7 @@ impl RefCell { /// ``` #[inline] #[stable(feature = "refcell_replace_swap", since = "1.35.0")] + #[track_caller] pub fn replace_with T>(&self, f: F) -> T { let mut_borrow = &mut *self.borrow_mut(); let replacement = f(mut_borrow); @@ -945,8 +944,7 @@ impl RefCell { #[inline] #[stable(feature = "cell_get_mut", since = "1.11.0")] pub fn get_mut(&mut self) -> &mut T { - // SAFETY: `&mut` guarantees unique access. - unsafe { &mut *self.value.get() } + self.value.get_mut() } /// Undo the effect of leaked guards on the borrow state of the `RefCell`. @@ -1056,6 +1054,7 @@ impl Clone for RefCell { /// /// Panics if the value is currently mutably borrowed. #[inline] + #[track_caller] fn clone(&self) -> RefCell { RefCell::new(self.borrow().clone()) } @@ -1543,8 +1542,11 @@ impl fmt::Display for RefMut<'_, T> { /// allow internal mutability, such as `Cell` and `RefCell`, use `UnsafeCell` to wrap their /// internal data. There is *no* legal way to obtain aliasing `&mut`, not even with `UnsafeCell`. /// -/// The `UnsafeCell` API itself is technically very simple: it gives you a raw pointer `*mut T` to -/// its contents. It is up to _you_ as the abstraction designer to use that raw pointer correctly. +/// The `UnsafeCell` API itself is technically very simple: [`.get()`] gives you a raw pointer +/// `*mut T` to its contents. It is up to _you_ as the abstraction designer to use that raw pointer +/// correctly. +/// +/// [`.get()`]: `UnsafeCell::get` /// /// The precise Rust aliasing rules are somewhat in flux, but the main points are not contentious: /// @@ -1571,21 +1573,70 @@ impl fmt::Display for RefMut<'_, T> { /// 2. A `&mut T` reference may be released to safe code provided neither other `&mut T` nor `&T` /// co-exist with it. A `&mut T` must always be unique. /// -/// Note that while mutating or mutably aliasing the contents of an `&UnsafeCell` is -/// ok (provided you enforce the invariants some other way), it is still undefined behavior -/// to have multiple `&mut UnsafeCell` aliases. +/// Note that whilst mutating the contents of an `&UnsafeCell` (even while other +/// `&UnsafeCell` references alias the cell) is +/// ok (provided you enforce the above invariants some other way), it is still undefined behavior +/// to have multiple `&mut UnsafeCell` aliases. That is, `UnsafeCell` is a wrapper +/// designed to have a special interaction with _shared_ accesses (_i.e._, through an +/// `&UnsafeCell<_>` reference); there is no magic whatsoever when dealing with _exclusive_ +/// accesses (_e.g._, through an `&mut UnsafeCell<_>`): neither the cell nor the wrapped value +/// may be aliased for the duration of that `&mut` borrow. +/// This is showcased by the [`.get_mut()`] accessor, which is a non-`unsafe` getter that yields +/// a `&mut T`. +/// +/// [`.get_mut()`]: `UnsafeCell::get_mut` /// /// # Examples /// +/// Here is an example showcasing how to soundly mutate the contents of an `UnsafeCell<_>` despite +/// there being multiple references aliasing the cell: +/// /// ``` /// use std::cell::UnsafeCell; /// -/// # #[allow(dead_code)] -/// struct NotThreadSafe { -/// value: UnsafeCell, -/// } +/// let x: UnsafeCell = 42.into(); +/// // Get multiple / concurrent / shared references to the same `x`. +/// let (p1, p2): (&UnsafeCell, &UnsafeCell) = (&x, &x); /// -/// unsafe impl Sync for NotThreadSafe {} +/// unsafe { +/// // SAFETY: within this scope there are no other references to `x`'s contents, +/// // so ours is effectively unique. +/// let p1_exclusive: &mut i32 = &mut *p1.get(); // -- borrow --+ +/// *p1_exclusive += 27; // | +/// } // <---------- cannot go beyond this point -------------------+ +/// +/// unsafe { +/// // SAFETY: within this scope nobody expects to have exclusive access to `x`'s contents, +/// // so we can have multiple shared accesses concurrently. +/// let p2_shared: &i32 = &*p2.get(); +/// assert_eq!(*p2_shared, 42 + 27); +/// let p1_shared: &i32 = &*p1.get(); +/// assert_eq!(*p1_shared, *p2_shared); +/// } +/// ``` +/// +/// The following example showcases the fact that exclusive access to an `UnsafeCell` +/// implies exclusive access to its `T`: +/// +/// ```rust +/// #![feature(unsafe_cell_get_mut)] +/// #![forbid(unsafe_code)] // with exclusive accesses, +/// // `UnsafeCell` is a transparent no-op wrapper, +/// // so no need for `unsafe` here. +/// use std::cell::UnsafeCell; +/// +/// let mut x: UnsafeCell = 42.into(); +/// +/// // Get a compile-time-checked unique reference to `x`. +/// let p_unique: &mut UnsafeCell = &mut x; +/// // With an exclusive reference, we can mutate the contents for free. +/// *p_unique.get_mut() = 0; +/// // Or, equivalently: +/// x = UnsafeCell::new(0); +/// +/// // When we own the value, we can extract the contents for free. +/// let contents: i32 = x.into_inner(); +/// assert_eq!(contents, 0); /// ``` #[lang = "unsafe_cell"] #[stable(feature = "rust1", since = "1.0.0")] @@ -1663,6 +1714,29 @@ impl UnsafeCell { self as *const UnsafeCell as *const T as *mut T } + /// Returns a mutable reference to the underlying data. + /// + /// This call borrows the `UnsafeCell` mutably (at compile-time) which + /// guarantees that we possess the only reference. + /// + /// # Examples + /// + /// ``` + /// #![feature(unsafe_cell_get_mut)] + /// use std::cell::UnsafeCell; + /// + /// let mut c = UnsafeCell::new(5); + /// *c.get_mut() += 1; + /// + /// assert_eq!(*c.get_mut(), 6); + /// ``` + #[inline] + #[unstable(feature = "unsafe_cell_get_mut", issue = "76943")] + pub fn get_mut(&mut self) -> &mut T { + // SAFETY: (outer) `&mut` guarantees unique access. + unsafe { &mut *self.get() } + } + /// Gets a mutable pointer to the wrapped value. /// The difference to [`get`] is that this function accepts a raw pointer, /// which is useful to avoid the creation of temporary references. diff --git a/library/core/src/clone.rs b/library/core/src/clone.rs index 7784ec687e..a953a3a418 100644 --- a/library/core/src/clone.rs +++ b/library/core/src/clone.rs @@ -7,11 +7,9 @@ //! contain owned boxes or implement [`Drop`]), so the compiler considers //! them cheap and safe to copy. For other types copies must be made //! explicitly, by convention implementing the [`Clone`] trait and calling -//! the [`clone`][clone] method. +//! the [`clone`] method. //! -//! [`Clone`]: trait.Clone.html -//! [clone]: trait.Clone.html#tymethod.clone -//! [`Drop`]: ../../std/ops/trait.Drop.html +//! [`clone`]: Clone::clone //! //! Basic usage example: //! @@ -51,7 +49,9 @@ /// ## Derivable /// /// This trait can be used with `#[derive]` if all fields are `Clone`. The `derive`d -/// implementation of [`clone`] calls [`clone`] on each field. +/// implementation of [`Clone`] calls [`clone`] on each field. +/// +/// [`clone`]: Clone::clone /// /// For a generic struct, `#[derive]` implements `Clone` conditionally by adding bound `Clone` on /// generic parameters. @@ -74,9 +74,6 @@ /// An example is a generic struct holding a function pointer. In this case, the /// implementation of `Clone` cannot be `derive`d, but can be implemented as: /// -/// [`Copy`]: ../../std/marker/trait.Copy.html -/// [`clone`]: trait.Clone.html#tymethod.clone -/// /// ``` /// struct Generate(fn() -> T); /// diff --git a/library/core/src/cmp.rs b/library/core/src/cmp.rs index 3953c73319..ee79a94cc6 100644 --- a/library/core/src/cmp.rs +++ b/library/core/src/cmp.rs @@ -356,8 +356,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn reverse(self) -> Ordering { + pub const fn reverse(self) -> Ordering { match self { Less => Greater, Equal => Equal, @@ -394,8 +395,9 @@ impl Ordering { /// ``` #[inline] #[must_use] + #[rustc_const_stable(feature = "const_ordering", since = "1.48.0")] #[stable(feature = "ordering_chaining", since = "1.17.0")] - pub fn then(self, other: Ordering) -> Ordering { + pub const fn then(self, other: Ordering) -> Ordering { match self { Equal => other, _ => self, @@ -724,19 +726,19 @@ impl PartialOrd for Ordering { /// } /// /// impl PartialOrd for Person { -/// fn partial_cmp(&self, other: &Person) -> Option { +/// fn partial_cmp(&self, other: &Self) -> Option { /// Some(self.cmp(other)) /// } /// } /// /// impl Ord for Person { -/// fn cmp(&self, other: &Person) -> Ordering { +/// fn cmp(&self, other: &Self) -> Ordering { /// self.height.cmp(&other.height) /// } /// } /// /// impl PartialEq for Person { -/// fn eq(&self, other: &Person) -> bool { +/// fn eq(&self, other: &Self) -> bool { /// self.height == other.height /// } /// } diff --git a/library/core/src/convert/mod.rs b/library/core/src/convert/mod.rs index fcd07befae..2bfeb49b5f 100644 --- a/library/core/src/convert/mod.rs +++ b/library/core/src/convert/mod.rs @@ -31,13 +31,6 @@ //! `into` themselves and `from` themselves //! //! See each trait for usage examples. -//! -//! [`Into`]: trait.Into.html -//! [`From`]: trait.From.html -//! [`TryFrom`]: trait.TryFrom.html -//! [`TryInto`]: trait.TryInto.html -//! [`AsRef`]: trait.AsRef.html -//! [`AsMut`]: trait.AsMut.html #![stable(feature = "rust1", since = "1.0.0")] @@ -141,13 +134,11 @@ pub const fn identity(x: T) -> T { /// want to accept all references that can be converted to [`&str`] as an argument. /// Since both [`String`] and [`&str`] implement `AsRef` we can accept both as input argument. /// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html -/// [`Borrow`]: ../../std/borrow/trait.Borrow.html -/// [`Hash`]: ../../std/hash/trait.Hash.html -/// [`Eq`]: ../../std/cmp/trait.Eq.html -/// [`Ord`]: ../../std/cmp/trait.Ord.html -/// [`&str`]: ../../std/primitive.str.html +/// [`Option`]: Option +/// [`Result`]: Result +/// [`Borrow`]: crate::borrow::Borrow +/// [`Eq`]: crate::cmp::Eq +/// [`Ord`]: crate::cmp::Ord /// [`String`]: ../../std/string/struct.String.html /// /// ``` @@ -177,8 +168,8 @@ pub trait AsRef { /// **Note: This trait must not fail**. If the conversion can fail, use a /// dedicated method which returns an [`Option`] or a [`Result`]. /// -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html +/// [`Option`]: Option +/// [`Result`]: Result /// /// # Generic Implementations /// @@ -278,12 +269,9 @@ pub trait AsMut { /// is_hello(s); /// ``` /// -/// [`TryInto`]: trait.TryInto.html -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html +/// [`Option`]: Option +/// [`Result`]: Result /// [`String`]: ../../std/string/struct.String.html -/// [`From`]: trait.From.html -/// [`Into`]: trait.Into.html /// [`Vec`]: ../../std/vec/struct.Vec.html #[stable(feature = "rust1", since = "1.0.0")] pub trait Into: Sized { @@ -370,12 +358,10 @@ pub trait Into: Sized { /// } /// ``` /// -/// [`TryFrom`]: trait.TryFrom.html -/// [`Option`]: ../../std/option/enum.Option.html -/// [`Result`]: ../../std/result/enum.Result.html +/// [`Option`]: Option +/// [`Result`]: Result /// [`String`]: ../../std/string/struct.String.html -/// [`Into`]: trait.Into.html -/// [`from`]: trait.From.html#tymethod.from +/// [`from`]: From::from /// [book]: ../../book/ch09-00-error-handling.html #[rustc_diagnostic_item = "from_trait"] #[stable(feature = "rust1", since = "1.0.0")] @@ -385,7 +371,7 @@ pub trait Into: Sized { ))] pub trait From: Sized { /// Performs the conversion. - #[cfg_attr(not(bootstrap), lang = "from")] + #[lang = "from"] #[stable(feature = "rust1", since = "1.0.0")] fn from(_: T) -> Self; } @@ -404,9 +390,6 @@ pub trait From: Sized { /// /// This suffers the same restrictions and reasoning as implementing /// [`Into`], see there for details. -/// -/// [`TryFrom`]: trait.TryFrom.html -/// [`Into`]: trait.Into.html #[stable(feature = "try_from", since = "1.34.0")] pub trait TryInto: Sized { /// The type returned in the event of a conversion error. @@ -485,11 +468,9 @@ pub trait TryInto: Sized { /// assert!(try_successful_smaller_number.is_ok()); /// ``` /// -/// [`try_from`]: trait.TryFrom.html#tymethod.try_from -/// [`TryInto`]: trait.TryInto.html -/// [`i32::MAX`]: ../../std/i32/constant.MAX.html +/// [`i32::MAX`]: crate::i32::MAX +/// [`try_from`]: TryFrom::try_from /// [`!`]: ../../std/primitive.never.html -/// [`Infallible`]: enum.Infallible.html #[stable(feature = "try_from", since = "1.34.0")] pub trait TryFrom: Sized { /// The type returned in the event of a conversion error. @@ -676,7 +657,6 @@ impl AsRef for str { /// /// … and eventually deprecate `Infallible`. /// -/// /// 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: @@ -692,10 +672,6 @@ impl AsRef for str { /// the two `impl`s will start to overlap /// and therefore will be disallowed by the language’s trait coherence rules. /// -/// [`Ok`]: ../result/enum.Result.html#variant.Ok -/// [`Result`]: ../result/enum.Result.html -/// [`TryFrom`]: trait.TryFrom.html -/// [`Into`]: trait.Into.html /// [never]: ../../std/primitive.never.html #[stable(feature = "convert_infallible", since = "1.34.0")] #[derive(Copy)] diff --git a/library/core/src/fmt/float.rs b/library/core/src/fmt/float.rs index 52d8349bc9..5908da477e 100644 --- a/library/core/src/fmt/float.rs +++ b/library/core/src/fmt/float.rs @@ -14,25 +14,17 @@ fn float_to_decimal_common_exact( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit(); - // FIXME(#53491): This is calling `get_mut` on an uninitialized - // `MaybeUninit` (here and elsewhere in this file). Revisit this once - // we decided whether that is valid or not. - // We can do this only because we are libstd and coupled to the compiler. - // (FWIW, using `freeze` would not be enough; `flt2dec::Part` is an enum!) - let formatted = flt2dec::to_exact_fixed_str( - flt2dec::strategy::grisu::format_exact, - *num, - sign, - precision, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + let mut buf: [MaybeUninit; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64 + let mut parts: [MaybeUninit>; 4] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_exact_fixed_str( + flt2dec::strategy::grisu::format_exact, + *num, + sign, + precision, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Don't inline this so callers that call both this and the above won't wind @@ -47,22 +39,18 @@ fn float_to_decimal_common_shortest( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 4]>::uninit(); - // FIXME(#53491) - let formatted = flt2dec::to_shortest_str( - flt2dec::strategy::grisu::format_shortest, - *num, - sign, - precision, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + // enough for f32 and f64 + let mut buf: [MaybeUninit; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit>; 4] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_shortest_str( + flt2dec::strategy::grisu::format_shortest, + *num, + sign, + precision, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Common code of floating point Debug and Display. @@ -103,22 +91,18 @@ fn float_to_exponential_common_exact( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - let mut buf = MaybeUninit::<[u8; 1024]>::uninit(); // enough for f32 and f64 - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit(); - // FIXME(#53491) - let formatted = flt2dec::to_exact_exp_str( - flt2dec::strategy::grisu::format_exact, - *num, - sign, - precision, - upper, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + let mut buf: [MaybeUninit; 1024] = MaybeUninit::uninit_array(); // enough for f32 and f64 + let mut parts: [MaybeUninit>; 6] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_exact_exp_str( + flt2dec::strategy::grisu::format_exact, + *num, + sign, + precision, + upper, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Don't inline this so callers that call both this and the above won't wind @@ -133,23 +117,19 @@ fn float_to_exponential_common_shortest( where T: flt2dec::DecodableFloat, { - // SAFETY: Possible undefined behavior, see FIXME(#53491) - unsafe { - // enough for f32 and f64 - let mut buf = MaybeUninit::<[u8; flt2dec::MAX_SIG_DIGITS]>::uninit(); - let mut parts = MaybeUninit::<[flt2dec::Part<'_>; 6]>::uninit(); - // FIXME(#53491) - let formatted = flt2dec::to_shortest_exp_str( - flt2dec::strategy::grisu::format_shortest, - *num, - sign, - (0, 0), - upper, - buf.get_mut(), - parts.get_mut(), - ); - fmt.pad_formatted_parts(&formatted) - } + // enough for f32 and f64 + let mut buf: [MaybeUninit; flt2dec::MAX_SIG_DIGITS] = MaybeUninit::uninit_array(); + let mut parts: [MaybeUninit>; 6] = MaybeUninit::uninit_array(); + let formatted = flt2dec::to_shortest_exp_str( + flt2dec::strategy::grisu::format_shortest, + *num, + sign, + (0, 0), + upper, + &mut buf, + &mut parts, + ); + fmt.pad_formatted_parts(&formatted) } // Common code of floating point LowerExp and UpperExp. diff --git a/library/core/src/fmt/mod.rs b/library/core/src/fmt/mod.rs index 52f73c03e0..c1038ce426 100644 --- a/library/core/src/fmt/mod.rs +++ b/library/core/src/fmt/mod.rs @@ -168,8 +168,6 @@ pub trait Write { /// This method should generally not be invoked manually, but rather through /// the [`write!`] macro itself. /// - /// [`write!`]: ../../std/macro.write.html - /// /// # Examples /// /// ``` @@ -2088,7 +2086,7 @@ impl Pointer for *const T { f.flags |= 1 << (FlagV1::SignAwareZeroPad as u32); if f.width.is_none() { - f.width = Some(((mem::size_of::() * 8) / 4) + 2); + f.width = Some((usize::BITS / 4) as usize + 2); } } f.flags |= 1 << (FlagV1::Alternate as u32); @@ -2240,5 +2238,6 @@ impl Debug for UnsafeCell { } } -// If you expected tests to be here, look instead at the ui/ifmt.rs test, +// If you expected tests to be here, look instead at the core/tests/fmt.rs file, // it's a lot easier than creating all of the rt::Piece structures here. +// There are also tests in the alloc crate, for those that need allocations. diff --git a/library/core/src/fmt/num.rs b/library/core/src/fmt/num.rs index 7d77e33d74..ae3d0ddd46 100644 --- a/library/core/src/fmt/num.rs +++ b/library/core/src/fmt/num.rs @@ -85,7 +85,10 @@ trait GenericRadix { // SAFETY: The only chars in `buf` are created by `Self::digit` which are assumed to be // valid UTF-8 let buf = unsafe { - str::from_utf8_unchecked(slice::from_raw_parts(MaybeUninit::first_ptr(buf), buf.len())) + str::from_utf8_unchecked(slice::from_raw_parts( + MaybeUninit::slice_as_ptr(buf), + buf.len(), + )) }; f.pad_integral(is_nonnegative, Self::PREFIX, buf) } @@ -192,7 +195,7 @@ macro_rules! impl_Display { // 2^128 is about 3*10^38, so 39 gives an extra byte of space let mut buf = [MaybeUninit::::uninit(); 39]; let mut curr = buf.len() as isize; - let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); + let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); // SAFETY: Since `d1` and `d2` are always less than or equal to `198`, we @@ -322,7 +325,7 @@ macro_rules! impl_Exp { // that `curr >= 0`. let mut buf = [MaybeUninit::::uninit(); 40]; let mut curr = buf.len() as isize; //index for buf - let buf_ptr = MaybeUninit::first_ptr_mut(&mut buf); + let buf_ptr = MaybeUninit::slice_as_mut_ptr(&mut buf); let lut_ptr = DEC_DIGITS_LUT.as_ptr(); // decode 2 chars at a time @@ -370,7 +373,7 @@ macro_rules! impl_Exp { // stores 'e' (or 'E') and the up to 2-digit exponent let mut exp_buf = [MaybeUninit::::uninit(); 3]; - let exp_ptr = MaybeUninit::first_ptr_mut(&mut exp_buf); + let exp_ptr = MaybeUninit::slice_as_mut_ptr(&mut exp_buf); // SAFETY: In either case, `exp_buf` is written within bounds and `exp_ptr[..len]` // is contained within `exp_buf` since `len <= 3`. let exp_slice = unsafe { diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 8169c14613..e9a99ddb6b 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -23,7 +23,7 @@ use crate::task::{Context, Poll}; /// When using a future, you generally won't call `poll` directly, but instead /// `.await` the value. /// -/// [`Waker`]: ../task/struct.Waker.html +/// [`Waker`]: crate::task::Waker #[doc(spotlight)] #[must_use = "futures do nothing unless you `.await` or poll them"] #[stable(feature = "futures_api", since = "1.36.0")] @@ -91,12 +91,10 @@ pub trait Future { /// (memory corruption, incorrect use of `unsafe` functions, or the like), /// regardless of the future's state. /// - /// [`Poll::Pending`]: ../task/enum.Poll.html#variant.Pending - /// [`Poll::Ready(val)`]: ../task/enum.Poll.html#variant.Ready - /// [`Context`]: ../task/struct.Context.html - /// [`Waker`]: ../task/struct.Waker.html - /// [`Waker::wake`]: ../task/struct.Waker.html#method.wake - #[cfg_attr(not(bootstrap), lang = "poll")] + /// [`Poll::Ready(val)`]: Poll::Ready + /// [`Waker`]: crate::task::Waker + /// [`Waker::wake`]: crate::task::Waker::wake + #[lang = "poll"] #[stable(feature = "futures_api", since = "1.36.0")] fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index d44ef857c1..fa5655ca35 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -21,9 +21,9 @@ pub use self::future::Future; #[unstable(feature = "into_future", issue = "67644")] pub use into_future::IntoFuture; -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use pending::{pending, Pending}; -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use ready::{ready, Ready}; #[unstable(feature = "future_poll_fn", issue = "72302")] @@ -53,9 +53,10 @@ unsafe impl Sync for ResumeTy {} /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). // This is `const` to avoid extra errors after we recover from `const async fn` -#[cfg_attr(not(bootstrap), lang = "from_generator")] +#[lang = "from_generator"] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] +#[rustc_const_unstable(feature = "gen_future", issue = "50547")] #[inline] pub const fn from_generator(gen: T) -> impl Future where @@ -71,7 +72,7 @@ where impl> Future for GenFuture { type Output = T::Return; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Safety: Safe because we're !Unpin + !Drop, and this is just a field projection. + // SAFETY: Safe because we're !Unpin + !Drop, and this is just a field projection. let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The @@ -86,7 +87,7 @@ where GenFuture(gen) } -#[cfg_attr(not(bootstrap), lang = "get_context")] +#[lang = "get_context"] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[inline] diff --git a/library/core/src/future/pending.rs b/library/core/src/future/pending.rs index 74887b68aa..ab162638a1 100644 --- a/library/core/src/future/pending.rs +++ b/library/core/src/future/pending.rs @@ -1,3 +1,4 @@ +use crate::fmt::{self, Debug}; use crate::future::Future; use crate::marker; use crate::pin::Pin; @@ -6,12 +7,9 @@ use crate::task::{Context, Poll}; /// Creates a future which never resolves, representing a computation that never /// finishes. /// -/// This `struct` is created by the [`pending`] function. See its +/// This `struct` is created by [`pending()`]. See its /// documentation for more. -/// -/// [`pending`]: fn.pending.html -#[unstable(feature = "future_readiness_fns", issue = "70921")] -#[derive(Debug)] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Pending { _data: marker::PhantomData, @@ -23,7 +21,6 @@ pub struct Pending { /// # Examples /// /// ```no_run -/// #![feature(future_readiness_fns)] /// use core::future; /// /// # async fn run() { @@ -32,12 +29,12 @@ pub struct Pending { /// unreachable!(); /// # } /// ``` -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub fn pending() -> Pending { Pending { _data: marker::PhantomData } } -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Future for Pending { type Output = T; @@ -46,10 +43,17 @@ impl Future for Pending { } } -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Unpin for Pending {} -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] +impl Debug for Pending { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Pending").finish() + } +} + +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Clone for Pending { fn clone(&self) -> Self { pending() diff --git a/library/core/src/future/poll_fn.rs b/library/core/src/future/poll_fn.rs index 9ab3bfcea1..f302cda09e 100644 --- a/library/core/src/future/poll_fn.rs +++ b/library/core/src/future/poll_fn.rs @@ -33,10 +33,8 @@ where /// A Future that wraps a function returning `Poll`. /// -/// This `struct` is created by the [`poll_fn`] function. See its +/// This `struct` is created by [`poll_fn()`]. See its /// documentation for more. -/// -/// [`poll_fn`]: fn.poll_fn.html #[must_use = "futures do nothing unless you `.await` or poll them"] #[unstable(feature = "future_poll_fn", issue = "72302")] pub struct PollFn { diff --git a/library/core/src/future/ready.rs b/library/core/src/future/ready.rs index 31b39d7fb6..e98f5c570b 100644 --- a/library/core/src/future/ready.rs +++ b/library/core/src/future/ready.rs @@ -4,19 +4,17 @@ use crate::task::{Context, Poll}; /// Creates a future that is immediately ready with a value. /// -/// This `struct` is created by the [`ready`] function. See its +/// This `struct` is created by [`ready()`]. See its /// documentation for more. -/// -/// [`ready`]: fn.ready.html -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] #[derive(Debug, Clone)] #[must_use = "futures do nothing unless you `.await` or poll them"] pub struct Ready(Option); -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Unpin for Ready {} -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] impl Future for Ready { type Output = T; @@ -28,10 +26,13 @@ impl Future for Ready { /// Creates a future that is immediately ready with a value. /// +/// Futures created through this function are functionally similar to those +/// created through `async {}`. The main difference is that futures created +/// through this function are named and implement `Unpin`. +/// /// # Examples /// /// ``` -/// #![feature(future_readiness_fns)] /// use core::future; /// /// # async fn run() { @@ -39,7 +40,7 @@ impl Future for Ready { /// assert_eq!(a.await, 1); /// # } /// ``` -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub fn ready(t: T) -> Ready { Ready(Some(t)) } diff --git a/library/core/src/hash/mod.rs b/library/core/src/hash/mod.rs index 6abe19dc15..f53ba98143 100644 --- a/library/core/src/hash/mod.rs +++ b/library/core/src/hash/mod.rs @@ -39,8 +39,6 @@ //! If you need more control over how a value is hashed, you need to implement //! the [`Hash`] trait: //! -//! [`Hash`]: trait.Hash.html -//! //! ```rust //! use std::collections::hash_map::DefaultHasher; //! use std::hash::{Hash, Hasher}; @@ -149,11 +147,9 @@ mod sip; /// Thankfully, you won't need to worry about upholding this property when /// deriving both [`Eq`] and `Hash` with `#[derive(PartialEq, Eq, Hash)]`. /// -/// [`Eq`]: ../../std/cmp/trait.Eq.html -/// [`Hasher`]: trait.Hasher.html /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html -/// [`hash`]: #tymethod.hash +/// [`hash`]: Hash::hash #[stable(feature = "rust1", since = "1.0.0")] pub trait Hash { /// Feeds this value into the given [`Hasher`]. @@ -168,8 +164,6 @@ pub trait Hash { /// 7920.hash(&mut hasher); /// println!("Hash is {:x}!", hasher.finish()); /// ``` - /// - /// [`Hasher`]: trait.Hasher.html #[stable(feature = "rust1", since = "1.0.0")] fn hash(&self, state: &mut H); @@ -186,8 +180,6 @@ pub trait Hash { /// Hash::hash_slice(&numbers, &mut hasher); /// println!("Hash is {:x}!", hasher.finish()); /// ``` - /// - /// [`Hasher`]: trait.Hasher.html #[stable(feature = "hash_slice", since = "1.3.0")] fn hash_slice(data: &[Self], state: &mut H) where @@ -239,10 +231,9 @@ pub use macros::Hash; /// println!("Hash is {:x}!", hasher.finish()); /// ``` /// -/// [`Hash`]: trait.Hash.html -/// [`finish`]: #tymethod.finish -/// [`write`]: #tymethod.write -/// [`write_u8`]: #method.write_u8 +/// [`finish`]: Hasher::finish +/// [`write`]: Hasher::write +/// [`write_u8`]: Hasher::write_u8 #[stable(feature = "rust1", since = "1.0.0")] pub trait Hasher { /// Returns the hash value for the values written so far. @@ -264,7 +255,7 @@ pub trait Hasher { /// println!("Hash is {:x}!", hasher.finish()); /// ``` /// - /// [`write`]: #tymethod.write + /// [`write`]: Hasher::write #[stable(feature = "rust1", since = "1.0.0")] fn finish(&self) -> u64; @@ -433,8 +424,7 @@ impl Hasher for &mut H { /// assert_eq!(hasher_1.finish(), hasher_2.finish()); /// ``` /// -/// [`build_hasher`]: #tymethod.build_hasher -/// [`Hasher`]: trait.Hasher.html +/// [`build_hasher`]: BuildHasher::build_hasher /// [`HashMap`]: ../../std/collections/struct.HashMap.html #[stable(since = "1.7.0", feature = "build_hasher")] pub trait BuildHasher { @@ -456,8 +446,6 @@ pub trait BuildHasher { /// let s = RandomState::new(); /// let new_s = s.build_hasher(); /// ``` - /// - /// [`Hasher`]: trait.Hasher.html #[stable(since = "1.7.0", feature = "build_hasher")] fn build_hasher(&self) -> Self::Hasher; } @@ -470,7 +458,7 @@ pub trait BuildHasher { /// defined. /// /// Any `BuildHasherDefault` is [zero-sized]. It can be created with -/// [`default`][method.Default]. When using `BuildHasherDefault` with [`HashMap`] or +/// [`default`][method.default]. When using `BuildHasherDefault` with [`HashMap`] or /// [`HashSet`], this doesn't need to be done, since they implement appropriate /// [`Default`] instances themselves. /// @@ -503,10 +491,7 @@ pub trait BuildHasher { /// let hash_map = HashMap::::default(); /// ``` /// -/// [`BuildHasher`]: trait.BuildHasher.html -/// [`Default`]: ../default/trait.Default.html -/// [method.default]: #method.default -/// [`Hasher`]: trait.Hasher.html +/// [method.default]: BuildHasherDefault::default /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// [`HashSet`]: ../../std/collections/struct.HashSet.html /// [zero-sized]: https://doc.rust-lang.org/nomicon/exotic-sizes.html#zero-sized-types-zsts diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 461b4c79a1..4eb47dd137 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -101,17 +101,18 @@ pub fn spin_loop() { /// [`std::convert::identity`]: https://doc.rust-lang.org/core/convert/fn.identity.html /// /// Unlike [`std::convert::identity`], a Rust compiler is encouraged to assume that `black_box` can -/// use `x` in any possible valid way that Rust code is allowed to without introducing undefined +/// use `dummy` in any possible valid way that Rust code is allowed to without introducing undefined /// behavior in the calling code. This property makes `black_box` useful for writing code in which /// certain optimizations are not desired, such as benchmarks. /// /// Note however, that `black_box` is only (and can only be) provided on a "best-effort" basis. The /// extent to which it can block optimisations may vary depending upon the platform and code-gen /// backend used. Programs cannot rely on `black_box` for *correctness* in any way. -#[inline] +#[cfg_attr(not(miri), inline)] +#[cfg_attr(miri, inline(never))] #[unstable(feature = "test", issue = "50297")] -#[allow(unreachable_code)] // this makes #[cfg] a bit easier below. -pub fn black_box(dummy: T) -> T { +#[cfg_attr(miri, allow(unused_mut))] +pub fn black_box(mut dummy: T) -> T { // We need to "use" the argument in some way LLVM can't introspect, and on // targets that support it we can typically leverage inline assembly to do // this. LLVM's interpretation of inline assembly is that it's, well, a black @@ -121,7 +122,8 @@ pub fn black_box(dummy: T) -> T { #[cfg(not(miri))] // This is just a hint, so it is fine to skip in Miri. // SAFETY: the inline assembly is a no-op. unsafe { - llvm_asm!("" : : "r"(&dummy)); + // FIXME: Cannot use `asm!` because it doesn't support MIPS and other architectures. + llvm_asm!("" : : "r"(&mut dummy) : "memory" : "volatile"); } dummy diff --git a/library/core/src/intrinsics.rs b/library/core/src/intrinsics.rs index d0b12d6982..426cdb12ec 100644 --- a/library/core/src/intrinsics.rs +++ b/library/core/src/intrinsics.rs @@ -1,7 +1,7 @@ //! Compiler intrinsics. //! -//! The corresponding definitions are in `librustc_codegen_llvm/intrinsic.rs`. -//! The corresponding const implementations are in `librustc_mir/interpret/intrinsics.rs` +//! The corresponding definitions are in `compiler/rustc_codegen_llvm/src/intrinsic.rs`. +//! The corresponding const implementations are in `compiler/rustc_mir/src/interpret/intrinsics.rs` //! //! # Const intrinsics //! @@ -10,7 +10,7 @@ //! //! In order to make an intrinsic usable at compile-time, one needs to copy the implementation //! from https://github.com/rust-lang/miri/blob/master/src/shims/intrinsics.rs to -//! `librustc_mir/interpret/intrinsics.rs` and add a +//! `compiler/rustc_mir/src/interpret/intrinsics.rs` and add a //! `#[rustc_const_unstable(feature = "foo", issue = "01234")]` to the intrinsic. //! //! If an intrinsic is supposed to be used from a `const fn` with a `rustc_const_stable` attribute, @@ -733,6 +733,7 @@ extern "rust-intrinsic" { /// own, or if it does not enable any significant optimizations. /// /// This intrinsic does not have a stable counterpart. + #[rustc_const_unstable(feature = "const_assume", issue = "76972")] pub fn assume(b: bool); /// Hints to the compiler that branch condition is likely to be true. @@ -831,7 +832,7 @@ extern "rust-intrinsic" { /// Gets a reference to a static `Location` indicating where it was called. /// /// Consider using [`crate::panic::Location::caller`] instead. - #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] pub fn caller_location() -> &'static crate::panic::Location<'static>; /// Moves a value out of scope without running drop glue. @@ -904,7 +905,7 @@ extern "rust-intrinsic" { /// let raw_bytes = [0x78, 0x56, 0x34, 0x12]; /// /// let num = unsafe { - /// std::mem::transmute::<[u8; 4], u32>(raw_bytes); + /// std::mem::transmute::<[u8; 4], u32>(raw_bytes) /// }; /// /// // use `u32::from_ne_bytes` instead @@ -1071,6 +1072,7 @@ extern "rust-intrinsic" { // NOTE: While this makes the intrinsic const stable, we have some custom code in const fn // checks that prevent its use within `const fn`. #[rustc_const_stable(feature = "const_transmute", since = "1.46.0")] + #[cfg_attr(not(bootstrap), rustc_diagnostic_item = "transmute")] pub fn transmute(e: T) -> U; /// Returns `true` if the actual type given as `T` requires drop @@ -1899,11 +1901,22 @@ pub unsafe fn copy_nonoverlapping(src: *const T, dst: *mut T, count: usize) { /// ``` /// use std::ptr; /// +/// /// # Safety +/// /// +/// /// * `ptr` must be correctly aligned for its type and non-zero. +/// /// * `ptr` must be valid for reads of `elts` contiguous elements of type `T`. +/// /// * Those elements must not be used after calling this function unless `T: Copy`. /// # #[allow(dead_code)] /// unsafe fn from_buf_raw(ptr: *const T, elts: usize) -> Vec { /// let mut dst = Vec::with_capacity(elts); -/// dst.set_len(elts); +/// +/// // SAFETY: Our precondition ensures the source is aligned and valid, +/// // and `Vec::with_capacity` ensures that we have usable space to write them. /// ptr::copy(ptr, dst.as_mut_ptr(), elts); +/// +/// // SAFETY: We created it with this much capacity earlier, +/// // and the previous `copy` has initialized these elements. +/// dst.set_len(elts); /// dst /// } /// ``` diff --git a/library/core/src/iter/adapters/chain.rs b/library/core/src/iter/adapters/chain.rs index 6700ef017b..ac27ec19b3 100644 --- a/library/core/src/iter/adapters/chain.rs +++ b/library/core/src/iter/adapters/chain.rs @@ -4,11 +4,19 @@ use crate::usize; /// An iterator that links two iterators together, in a chain. /// -/// This `struct` is created by the [`chain`] method on [`Iterator`]. See its -/// documentation for more. +/// This `struct` is created by [`Iterator::chain`]. See its documentation +/// for more. /// -/// [`chain`]: trait.Iterator.html#method.chain -/// [`Iterator`]: trait.Iterator.html +/// # Examples +/// +/// ``` +/// use std::iter::Chain; +/// use std::slice::Iter; +/// +/// let a1 = [1, 2, 3]; +/// let a2 = [4, 5, 6]; +/// let iter: Chain, Iter<_>> = a1.iter().chain(a2.iter()); +/// ``` #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] diff --git a/library/core/src/iter/adapters/flatten.rs b/library/core/src/iter/adapters/flatten.rs index 4202e52448..ddb1aaebc1 100644 --- a/library/core/src/iter/adapters/flatten.rs +++ b/library/core/src/iter/adapters/flatten.rs @@ -7,11 +7,8 @@ use super::Map; /// An iterator that maps each element to an iterator, and yields the elements /// of the produced iterators. /// -/// This `struct` is created by the [`flat_map`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`flat_map`]: trait.Iterator.html#method.flat_map -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::flat_map`]. See its documentation +/// for more. #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] pub struct FlatMap { diff --git a/library/core/src/iter/adapters/fuse.rs b/library/core/src/iter/adapters/fuse.rs index ee5fbe9a84..a78da369c2 100644 --- a/library/core/src/iter/adapters/fuse.rs +++ b/library/core/src/iter/adapters/fuse.rs @@ -1,5 +1,7 @@ +use super::InPlaceIterable; use crate::intrinsics; use crate::iter::adapters::zip::try_get_unchecked; +use crate::iter::adapters::SourceIter; use crate::iter::TrustedRandomAccess; use crate::iter::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator}; use crate::ops::Try; @@ -7,11 +9,8 @@ use crate::ops::Try; /// An iterator that yields `None` forever after the underlying iterator /// yields `None` once. /// -/// This `struct` is created by the [`fuse`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`fuse`]: trait.Iterator.html#method.fuse -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::fuse`]. See its documentation +/// for more. #[derive(Clone, Debug)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -121,7 +120,8 @@ where Self: TrustedRandomAccess, { match self.iter { - // SAFETY: the caller must uphold the contract for `Iterator::get_unchecked`. + // SAFETY: the caller must uphold the contract for + // `Iterator::__iterator_get_unchecked`. Some(ref mut iter) => unsafe { try_get_unchecked(iter, idx) }, // SAFETY: the caller asserts there is an item at `i`, so we're not exhausted. None => unsafe { intrinsics::unreachable() }, @@ -517,3 +517,24 @@ where unchecked!(self).is_empty() } } + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Fuse +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + match self.iter { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + Some(ref mut iter) => unsafe { SourceIter::as_inner(iter) }, + // SAFETY: the specialized iterator never sets `None` + None => unsafe { intrinsics::unreachable() }, + } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Fuse {} diff --git a/library/core/src/iter/adapters/mod.rs b/library/core/src/iter/adapters/mod.rs index ce90607e76..1e520b62f7 100644 --- a/library/core/src/iter/adapters/mod.rs +++ b/library/core/src/iter/adapters/mod.rs @@ -1,10 +1,12 @@ use crate::cmp; use crate::fmt; use crate::intrinsics; -use crate::ops::{Add, AddAssign, Try}; +use crate::ops::{Add, AddAssign, ControlFlow, Try}; -use super::{from_fn, LoopState}; -use super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen}; +use super::from_fn; +use super::{ + DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, TrustedLen, +}; mod chain; mod flatten; @@ -16,9 +18,77 @@ pub use self::chain::Chain; pub use self::flatten::{FlatMap, Flatten}; pub use self::fuse::Fuse; use self::zip::try_get_unchecked; -pub(crate) use self::zip::TrustedRandomAccess; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::zip::TrustedRandomAccess; pub use self::zip::Zip; +/// This trait provides transitive access to source-stage in an interator-adapter pipeline +/// under the conditions that +/// * the iterator source `S` itself implements `SourceIter` +/// * there is a delegating implementation of this trait for each adapter in the pipeline between +/// the source and the pipeline consumer. +/// +/// When the source is an owning iterator struct (commonly called `IntoIter`) then +/// this can be useful for specializing [`FromIterator`] implementations or recovering the +/// remaining elements after an iterator has been partially exhausted. +/// +/// Note that implementations do not necessarily have to provide access to the inner-most +/// source of a pipeline. A stateful intermediate adapter might eagerly evaluate a part +/// of the pipeline and expose its internal storage as source. +/// +/// The trait is unsafe because implementers must uphold additional safety properties. +/// See [`as_inner`] for details. +/// +/// # Examples +/// +/// Retrieving a partially consumed source: +/// +/// ``` +/// # #![feature(inplace_iteration)] +/// # use std::iter::SourceIter; +/// +/// let mut iter = vec![9, 9, 9].into_iter().map(|i| i * i); +/// let _ = iter.next(); +/// let mut remainder = std::mem::replace(unsafe { iter.as_inner() }, Vec::new().into_iter()); +/// println!("n = {} elements remaining", remainder.len()); +/// ``` +/// +/// [`FromIterator`]: crate::iter::FromIterator +/// [`as_inner`]: SourceIter::as_inner +#[unstable(issue = "none", feature = "inplace_iteration")] +pub unsafe trait SourceIter { + /// A source stage in an iterator pipeline. + type Source: Iterator; + + /// Retrieve the source of an iterator pipeline. + /// + /// # Safety + /// + /// Implementations of must return the same mutable reference for their lifetime, unless + /// replaced by a caller. + /// Callers may only replace the reference when they stopped iteration and drop the + /// iterator pipeline after extracting the source. + /// + /// This means iterator adapters can rely on the source not changing during + /// iteration but they cannot rely on it in their Drop implementations. + /// + /// Implementing this method means adapters relinquish private-only access to their + /// source and can only rely on guarantees made based on method receiver types. + /// The lack of restricted access also requires that adapters must uphold the source's + /// public API even when they have access to its internals. + /// + /// Callers in turn must expect the source to be in any state that is consistent with + /// its public API since adapters sitting between it and the source have the same + /// access. In particular an adapter may have consumed more elements than strictly necessary. + /// + /// The overall goal of these requirements is to let the consumer of a pipeline use + /// * whatever remains in the source after iteration has stopped + /// * the memory that has become unused by advancing a consuming iterator + /// + /// [`next()`]: trait.Iterator.html#method.next + unsafe fn as_inner(&mut self) -> &mut Self::Source; +} + /// A double-ended iterator with the direction inverted. /// /// This `struct` is created by the [`rev`] method on [`Iterator`]. See its @@ -54,6 +124,11 @@ where self.iter.size_hint() } + #[inline] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_back_by(n) + } + #[inline] fn nth(&mut self, n: usize) -> Option<::Item> { self.iter.nth_back(n) @@ -94,6 +169,11 @@ where self.iter.next() } + #[inline] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + self.iter.advance_by(n) + } + #[inline] fn nth_back(&mut self, n: usize) -> Option<::Item> { self.iter.nth(n) @@ -220,7 +300,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. *unsafe { try_get_unchecked(&mut self.it, idx) } } } @@ -355,7 +435,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { try_get_unchecked(&mut self.it, idx).clone() } } } @@ -870,7 +950,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { (self.f)(try_get_unchecked(&mut self.iter, idx)) } } } @@ -939,6 +1019,24 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Map +where + F: FnMut(I::Item) -> B, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Map where F: FnMut(I::Item) -> B {} + /// An iterator that filters the elements of `iter` with `predicate`. /// /// This `struct` is created by the [`filter`] method on [`Iterator`]. See its @@ -1070,6 +1168,24 @@ where #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Filter where P: FnMut(&I::Item) -> bool {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Filter +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Filter where P: FnMut(&I::Item) -> bool {} + /// An iterator that uses `f` to both filter and map elements from `iter`. /// /// This `struct` is created by the [`filter_map`] method on [`Iterator`]. See its @@ -1164,10 +1280,10 @@ where #[inline] fn find( f: &mut impl FnMut(T) -> Option, - ) -> impl FnMut((), T) -> LoopState<(), B> + '_ { + ) -> impl FnMut((), T) -> ControlFlow<(), B> + '_ { move |(), x| match f(x) { - Some(x) => LoopState::Break(x), - None => LoopState::Continue(()), + Some(x) => ControlFlow::Break(x), + None => ControlFlow::CONTINUE, } } @@ -1196,6 +1312,27 @@ where #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for FilterMap where F: FnMut(I::Item) -> Option {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for FilterMap +where + F: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for FilterMap where + F: FnMut(I::Item) -> Option +{ +} + /// An iterator that yields the current count and the element during iteration. /// /// This `struct` is created by the [`enumerate`] method on [`Iterator`]. See its @@ -1309,7 +1446,7 @@ where Self: TrustedRandomAccess, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. let value = unsafe { try_get_unchecked(&mut self.iter, idx) }; (Add::add(self.count, idx), value) } @@ -1414,6 +1551,23 @@ impl FusedIterator for Enumerate where I: FusedIterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for Enumerate where I: TrustedLen {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Enumerate +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Enumerate {} + /// An iterator with a `peek()` that returns an optional reference to the next /// element. /// @@ -1628,7 +1782,7 @@ impl Peekable { self.peeked.get_or_insert_with(|| iter.next()).as_ref() } - /// Consume the next value of this iterator if a condition is true. + /// Consume and return the next value of this iterator if a condition is true. /// /// If `func` returns `true` for the next value of this iterator, consume and return it. /// Otherwise, return `None`. @@ -1668,7 +1822,7 @@ impl Peekable { } } - /// Consume the next item if it is equal to `expected`. + /// Consume and return the next item if it is equal to `expected`. /// /// # Example /// Consume a number if it's equal to 0. @@ -1683,15 +1837,35 @@ impl Peekable { /// assert_eq!(iter.next(), Some(1)); /// ``` #[unstable(feature = "peekable_next_if", issue = "72480")] - pub fn next_if_eq(&mut self, expected: &R) -> Option + pub fn next_if_eq(&mut self, expected: &T) -> Option where - R: ?Sized, - I::Item: PartialEq, + T: ?Sized, + I::Item: PartialEq, { self.next_if(|next| next == expected) } } +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Peekable where I: TrustedLen {} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Peekable +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Peekable {} + /// An iterator that rejects elements while `predicate` returns `true`. /// /// This `struct` is created by the [`skip_while`] method on [`Iterator`]. See its @@ -1793,6 +1967,27 @@ where { } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for SkipWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for SkipWhile where + F: FnMut(&I::Item) -> bool +{ +} + /// An iterator that only accepts elements while `predicate` returns `true`. /// /// This `struct` is created by the [`take_while`] method on [`Iterator`]. See its @@ -1864,13 +2059,13 @@ where flag: &'a mut bool, p: &'a mut impl FnMut(&T) -> bool, mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| { if p(&x) { - LoopState::from_try(fold(acc, x)) + ControlFlow::from_try(fold(acc, x)) } else { *flag = true; - LoopState::Break(Try::from_ok(acc)) + ControlFlow::Break(Try::from_ok(acc)) } } } @@ -1907,6 +2102,27 @@ where { } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for TakeWhile +where + P: FnMut(&I::Item) -> bool, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for TakeWhile where + F: FnMut(&I::Item) -> bool +{ +} + /// An iterator that only accepts elements while `predicate` returns `Some(_)`. /// /// This `struct` is created by the [`map_while`] method on [`Iterator`]. See its @@ -1963,8 +2179,8 @@ where { let Self { iter, predicate } = self; iter.try_fold(init, |acc, x| match predicate(x) { - Some(item) => LoopState::from_try(fold(acc, item)), - None => LoopState::Break(Try::from_ok(acc)), + Some(item) => ControlFlow::from_try(fold(acc, item)), + None => ControlFlow::Break(Try::from_ok(acc)), }) .into_try() } @@ -1984,6 +2200,27 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for MapWhile +where + P: FnMut(I::Item) -> Option, + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for MapWhile where + P: FnMut(I::Item) -> Option +{ +} + /// An iterator that skips over `n` elements of `iter`. /// /// This `struct` is created by the [`skip`] method on [`Iterator`]. See its @@ -2135,11 +2372,11 @@ where fn check>( mut n: usize, mut fold: impl FnMut(Acc, T) -> R, - ) -> impl FnMut(Acc, T) -> LoopState { + ) -> impl FnMut(Acc, T) -> ControlFlow { move |acc, x| { n -= 1; let r = fold(acc, x); - if n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } + if n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } } } @@ -2167,6 +2404,23 @@ where #[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 +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Skip {} + /// An iterator that only iterates over the first `n` iterations of `iter`. /// /// This `struct` is created by the [`take`] method on [`Iterator`]. See its @@ -2246,11 +2500,11 @@ where fn check<'a, T, Acc, R: Try>( n: &'a mut usize, mut fold: impl FnMut(Acc, T) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| { *n -= 1; let r = fold(acc, x); - if *n == 0 { LoopState::Break(r) } else { LoopState::from_try(r) } + if *n == 0 { ControlFlow::Break(r) } else { ControlFlow::from_try(r) } } } @@ -2277,6 +2531,23 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Take +where + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Take {} + #[stable(feature = "double_ended_take_iterator", since = "1.38.0")] impl DoubleEndedIterator for Take where @@ -2414,10 +2685,10 @@ where state: &'a mut St, f: &'a mut impl FnMut(&mut St, T) -> Option, mut fold: impl FnMut(Acc, B) -> R + 'a, - ) -> impl FnMut(Acc, T) -> LoopState + 'a { + ) -> impl FnMut(Acc, T) -> ControlFlow + 'a { move |acc, x| match f(state, x) { - None => LoopState::Break(Try::from_ok(acc)), - Some(x) => LoopState::from_try(fold(acc, x)), + None => ControlFlow::Break(Try::from_ok(acc)), + Some(x) => ControlFlow::from_try(fold(acc, x)), } } @@ -2441,6 +2712,27 @@ where } } +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Scan +where + I: SourceIter, + F: FnMut(&mut St, I::Item) -> Option, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Scan where + F: FnMut(&mut St, I::Item) -> Option +{ +} + /// An iterator that calls a function with a reference to each element before /// yielding it. /// @@ -2587,6 +2879,24 @@ where #[stable(feature = "fused", since = "1.26.0")] impl FusedIterator for Inspect where F: FnMut(&I::Item) {} +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl SourceIter for Inspect +where + F: FnMut(&I::Item), + I: SourceIter, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.iter) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +unsafe impl InPlaceIterable for Inspect where F: FnMut(&I::Item) {} + /// An iterator adapter that produces output as long as the underlying /// iterator produces `Result::Ok` values. /// @@ -2638,10 +2948,10 @@ where let error = &mut *self.error; self.iter .try_fold(init, |acc, x| match x { - Ok(x) => LoopState::from_try(f(acc, x)), + Ok(x) => ControlFlow::from_try(f(acc, x)), Err(e) => { *error = Err(e); - LoopState::Break(Try::from_ok(acc)) + ControlFlow::Break(Try::from_ok(acc)) } }) .into_try() diff --git a/library/core/src/iter/adapters/zip.rs b/library/core/src/iter/adapters/zip.rs index 581ac6e0d8..78712988ea 100644 --- a/library/core/src/iter/adapters/zip.rs +++ b/library/core/src/iter/adapters/zip.rs @@ -1,15 +1,15 @@ use crate::cmp; use crate::fmt::{self, Debug}; -use super::super::{DoubleEndedIterator, ExactSizeIterator, FusedIterator, Iterator, TrustedLen}; +use super::super::{ + DoubleEndedIterator, ExactSizeIterator, FusedIterator, InPlaceIterable, Iterator, SourceIter, + TrustedLen, +}; /// An iterator that iterates two other iterators simultaneously. /// -/// This `struct` is created by the [`zip`] method on [`Iterator`]. See its -/// documentation for more. -/// -/// [`zip`]: trait.Iterator.html#method.zip -/// [`Iterator`]: trait.Iterator.html +/// This `struct` is created by [`Iterator::zip`]. See its documentation +/// for more. #[derive(Clone)] #[must_use = "iterators are lazy and do nothing unless consumed"] #[stable(feature = "rust1", since = "1.0.0")] @@ -63,8 +63,8 @@ where where Self: TrustedRandomAccess, { - // SAFETY: `ZipImpl::get_unchecked` has same safety requirements as - // `Iterator::get_unchecked`. + // SAFETY: `ZipImpl::__iterator_get_unchecked` has same safety + // requirements as `Iterator::__iterator_get_unchecked`. unsafe { ZipImpl::get_unchecked(self, idx) } } } @@ -93,7 +93,7 @@ trait ZipImpl { where A: DoubleEndedIterator + ExactSizeIterator, B: DoubleEndedIterator + ExactSizeIterator; - // This has the same safety requirements as `Iterator::get_unchecked` + // This has the same safety requirements as `Iterator::__iterator_get_unchecked` unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item where Self: Iterator + TrustedRandomAccess; @@ -290,7 +290,7 @@ where #[inline] unsafe fn get_unchecked(&mut self, idx: usize) -> ::Item { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { (self.a.__iterator_get_unchecked(idx), self.b.__iterator_get_unchecked(idx)) } } } @@ -331,6 +331,32 @@ where { } +// 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 +where + A: SourceIter, + B: Iterator, + S: Iterator, +{ + type Source = S; + + #[inline] + unsafe fn as_inner(&mut self) -> &mut S { + // SAFETY: unsafe function forwarding to unsafe function with the same requirements + unsafe { SourceIter::as_inner(&mut self.a) } + } +} + +#[unstable(issue = "none", feature = "inplace_iteration")] +// Limited to Item: Copy since interaction between Zip's use of TrustedRandomAccess +// and Drop implementation of the source is unclear. +// +// An additional method returning the number of times the source has been logically advanced +// (without calling next()) would be needed to properly drop the remainder of the source. +unsafe impl InPlaceIterable for Zip where A::Item: Copy {} + #[stable(feature = "rust1", since = "1.0.0")] impl Debug for Zip { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -364,8 +390,8 @@ impl ZipFmt::get_unchecked` must be safe to call provided the -/// following conditions are met. +/// `::__iterator_get_unchecked` must be safe to call +/// provided the following conditions are met. /// /// 1. `0 <= idx` and `idx < self.size()`. /// 2. If `self: !Clone`, then `get_unchecked` is never called with the same @@ -377,7 +403,7 @@ impl ZipFmt bool; } -/// Like `Iterator::get_unchecked`, but doesn't require the compiler to +/// Like `Iterator::__iterator_get_unchecked`, but doesn't require the compiler to /// know that `U: TrustedRandomAccess`. /// /// ## Safety @@ -414,13 +440,13 @@ where I: Iterator, { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { it.try_get_unchecked(idx) } } unsafe trait SpecTrustedRandomAccess: Iterator { /// If `Self: TrustedRandomAccess`, it must be safe to call a - /// `Iterator::get_unchecked(self, index)`. + /// `Iterator::__iterator_get_unchecked(self, index)`. unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item; } @@ -433,7 +459,7 @@ unsafe impl SpecTrustedRandomAccess for I { unsafe impl SpecTrustedRandomAccess for I { unsafe fn try_get_unchecked(&mut self, index: usize) -> Self::Item { // SAFETY: the caller must uphold the contract for - // `Iterator::get_unchecked`. + // `Iterator::__iterator_get_unchecked`. unsafe { self.__iterator_get_unchecked(index) } } } diff --git a/library/core/src/iter/mod.rs b/library/core/src/iter/mod.rs index 9b528cdbe3..59f333e888 100644 --- a/library/core/src/iter/mod.rs +++ b/library/core/src/iter/mod.rs @@ -54,8 +54,7 @@ //! below for more details. //! //! [`Some(Item)`]: Some -//! [`Iterator`]: trait.Iterator.html -//! [`next`]: trait.Iterator.html#tymethod.next +//! [`next`]: Iterator::next //! [`TryIter`]: ../../std/sync/mpsc/struct.TryIter.html //! //! # The three forms of iteration @@ -136,7 +135,7 @@ //! methods like `nth` and `fold` if an iterator can compute them more efficiently without calling //! `next`. //! -//! # for Loops and IntoIterator +//! # `for` loops and `IntoIterator` //! //! Rust's `for` loop syntax is actually sugar for iterators. Here's a basic //! example of `for`: @@ -159,8 +158,7 @@ //! Let's take a look at that `for` loop again, and what the compiler converts //! it into: //! -//! [`IntoIterator`]: trait.IntoIterator.html -//! [`into_iter`]: trait.IntoIterator.html#tymethod.into_iter +//! [`into_iter`]: IntoIterator::into_iter //! //! ``` //! let values = vec![1, 2, 3, 4, 5]; @@ -222,9 +220,9 @@ //! across versions of Rust, so you should avoid relying on the exact values //! returned by an iterator which panicked. //! -//! [`map`]: trait.Iterator.html#method.map -//! [`take`]: trait.Iterator.html#method.take -//! [`filter`]: trait.Iterator.html#method.filter +//! [`map`]: Iterator::map +//! [`take`]: Iterator::take +//! [`filter`]: Iterator::filter //! //! # Laziness //! @@ -261,13 +259,13 @@ //! } //! ``` //! -//! [`map`]: trait.Iterator.html#method.map -//! [`for_each`]: trait.Iterator.html#method.for_each +//! [`map`]: Iterator::map +//! [`for_each`]: Iterator::for_each //! //! Another common way to evaluate an iterator is to use the [`collect`] //! method to produce a new collection. //! -//! [`collect`]: trait.Iterator.html#method.collect +//! [`collect`]: Iterator::collect //! //! # Infinity //! @@ -305,13 +303,11 @@ //! println!("The smallest number one is {}.", least); //! ``` //! -//! [`take`]: trait.Iterator.html#method.take -//! [`min`]: trait.Iterator.html#method.min +//! [`take`]: Iterator::take +//! [`min`]: Iterator::min #![stable(feature = "rust1", since = "1.0.0")] -use crate::ops::Try; - #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::Iterator; @@ -346,16 +342,24 @@ pub use self::traits::{DoubleEndedIterator, Extend, FromIterator, IntoIterator}; #[stable(feature = "rust1", since = "1.0.0")] pub use self::traits::{ExactSizeIterator, Product, Sum}; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::traits::InPlaceIterable; + #[stable(feature = "iter_cloned", since = "1.1.0")] pub use self::adapters::Cloned; #[stable(feature = "iter_copied", since = "1.36.0")] 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")] pub use self::adapters::MapWhile; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::adapters::SourceIter; #[stable(feature = "iterator_step_by", since = "1.28.0")] pub use self::adapters::StepBy; +#[unstable(feature = "trusted_random_access", issue = "none")] +pub use self::adapters::TrustedRandomAccess; #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{Chain, Cycle, Enumerate, Filter, FilterMap, Map, Rev, Zip}; #[stable(feature = "rust1", since = "1.0.0")] @@ -363,63 +367,9 @@ pub use self::adapters::{FlatMap, Peekable, Scan, Skip, SkipWhile, Take, TakeWhi #[stable(feature = "rust1", since = "1.0.0")] pub use self::adapters::{Fuse, Inspect}; -pub(crate) use self::adapters::{process_results, TrustedRandomAccess}; +pub(crate) use self::adapters::process_results; mod adapters; mod range; mod sources; mod traits; - -/// Used to make try_fold closures more like normal loops -#[derive(PartialEq)] -enum LoopState { - Continue(C), - Break(B), -} - -impl Try for LoopState { - type Ok = C; - type Error = B; - #[inline] - fn into_result(self) -> Result { - match self { - LoopState::Continue(y) => Ok(y), - LoopState::Break(x) => Err(x), - } - } - #[inline] - fn from_error(v: Self::Error) -> Self { - LoopState::Break(v) - } - #[inline] - fn from_ok(v: Self::Ok) -> Self { - LoopState::Continue(v) - } -} - -impl LoopState { - #[inline] - fn break_value(self) -> Option { - match self { - LoopState::Continue(..) => None, - LoopState::Break(x) => Some(x), - } - } -} - -impl LoopState { - #[inline] - fn from_try(r: R) -> Self { - match Try::into_result(r) { - Ok(v) => LoopState::Continue(v), - Err(v) => LoopState::Break(Try::from_error(v)), - } - } - #[inline] - fn into_try(self) -> R { - match self { - LoopState::Continue(v) => Try::from_ok(v), - LoopState::Break(v) => v, - } - } -} diff --git a/library/core/src/iter/sources.rs b/library/core/src/iter/sources.rs index d76fa89bd0..97562cf73b 100644 --- a/library/core/src/iter/sources.rs +++ b/library/core/src/iter/sources.rs @@ -5,9 +5,7 @@ use super::{FusedIterator, TrustedLen}; /// An iterator that repeats an element endlessly. /// -/// This `struct` is created by the [`repeat`] function. See its documentation for more. -/// -/// [`repeat`]: fn.repeat.html +/// This `struct` is created by the [`repeat()`] function. See its documentation for more. #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct Repeat { @@ -47,15 +45,11 @@ unsafe impl TrustedLen for Repeat {} /// The `repeat()` function repeats a single value over and over again. /// /// Infinite iterators like `repeat()` are often used with adapters like -/// [`take`], in order to make them finite. -/// -/// [`take`]: trait.Iterator.html#method.take +/// [`Iterator::take()`], in order to make them finite. /// /// If the element type of the iterator you need does not implement `Clone`, /// or if you do not want to keep the repeated element in memory, you can -/// instead use the [`repeat_with`] function. -/// -/// [`repeat_with`]: fn.repeat_with.html +/// instead use the [`repeat_with()`] function. /// /// # Examples /// @@ -77,7 +71,7 @@ unsafe impl TrustedLen for Repeat {} /// assert_eq!(Some(4), fours.next()); /// ``` /// -/// Going finite with [`take`]: +/// Going finite with [`Iterator::take()`]: /// /// ``` /// use std::iter; @@ -102,10 +96,8 @@ pub fn repeat(elt: T) -> Repeat { /// An iterator that repeats elements of type `A` endlessly by /// applying the provided closure `F: FnMut() -> A`. /// -/// This `struct` is created by the [`repeat_with`] function. +/// This `struct` is created by the [`repeat_with()`] function. /// See its documentation for more. -/// -/// [`repeat_with`]: fn.repeat_with.html #[derive(Copy, Clone, Debug)] #[stable(feature = "iterator_repeat_with", since = "1.28.0")] pub struct RepeatWith { @@ -139,20 +131,18 @@ unsafe impl A> TrustedLen for RepeatWith {} /// The `repeat_with()` function calls the repeater over and over again. /// /// Infinite iterators like `repeat_with()` are often used with adapters like -/// [`take`], in order to make them finite. +/// [`Iterator::take()`], in order to make them finite. /// -/// [`take`]: trait.Iterator.html#method.take -/// -/// If the element type of the iterator you need implements `Clone`, and +/// If the element type of the iterator you need implements [`Clone`], and /// it is OK to keep the source element in memory, you should instead use -/// the [`repeat`] function. +/// the [`repeat()`] function. /// -/// [`repeat`]: fn.repeat.html -/// -/// An iterator produced by `repeat_with()` is not a `DoubleEndedIterator`. -/// If you need `repeat_with()` to return a `DoubleEndedIterator`, +/// An iterator produced by `repeat_with()` is not a [`DoubleEndedIterator`]. +/// If you need `repeat_with()` to return a [`DoubleEndedIterator`], /// please open a GitHub issue explaining your use case. /// +/// [`DoubleEndedIterator`]: crate::iter::DoubleEndedIterator +/// /// # Examples /// /// Basic usage: @@ -201,9 +191,7 @@ pub fn repeat_with A>(repeater: F) -> RepeatWith { /// An iterator that yields nothing. /// -/// This `struct` is created by the [`empty`] function. See its documentation for more. -/// -/// [`empty`]: fn.empty.html +/// This `struct` is created by the [`empty()`] function. See its documentation for more. #[stable(feature = "iter_empty", since = "1.2.0")] pub struct Empty(marker::PhantomData); @@ -292,9 +280,7 @@ pub const fn empty() -> Empty { /// An iterator that yields an element exactly once. /// -/// This `struct` is created by the [`once`] function. See its documentation for more. -/// -/// [`once`]: fn.once.html +/// This `struct` is created by the [`once()`] function. See its documentation for more. #[derive(Clone, Debug)] #[stable(feature = "iter_once", since = "1.2.0")] pub struct Once { @@ -336,12 +322,12 @@ impl FusedIterator for Once {} /// Creates an iterator that yields an element exactly once. /// -/// This is commonly used to adapt a single value into a [`chain`] of other +/// This is commonly used to adapt a single value into a [`chain()`] of other /// kinds of iteration. Maybe you have an iterator that covers almost /// everything, but you need an extra special case. Maybe you have a function /// which works on iterators, but you only need to process one value. /// -/// [`chain`]: trait.Iterator.html#method.chain +/// [`chain()`]: Iterator::chain /// /// # Examples /// @@ -393,10 +379,8 @@ pub fn once(value: T) -> Once { /// An iterator that yields a single element of type `A` by /// applying the provided closure `F: FnOnce() -> A`. /// -/// This `struct` is created by the [`once_with`] function. +/// This `struct` is created by the [`once_with()`] function. /// See its documentation for more. -/// -/// [`once_with`]: fn.once_with.html #[derive(Clone, Debug)] #[stable(feature = "iter_once_with", since = "1.43.0")] pub struct OnceWith { @@ -442,15 +426,14 @@ unsafe impl A> TrustedLen for OnceWith {} /// Creates an iterator that lazily generates a value exactly once by invoking /// the provided closure. /// -/// This is commonly used to adapt a single value generator into a [`chain`] of +/// This is commonly used to adapt a single value generator into a [`chain()`] of /// other kinds of iteration. Maybe you have an iterator that covers almost /// everything, but you need an extra special case. Maybe you have a function /// which works on iterators, but you only need to process one value. /// -/// Unlike [`once`], this function will lazily generate the value on request. +/// Unlike [`once()`], this function will lazily generate the value on request. /// -/// [`once`]: fn.once.html -/// [`chain`]: trait.Iterator.html#method.chain +/// [`chain()`]: Iterator::chain /// /// # Examples /// @@ -505,17 +488,16 @@ pub fn once_with A>(gen: F) -> OnceWith { /// /// This allows creating a custom iterator with any behavior /// without using the more verbose syntax of creating a dedicated type -/// and implementing the `Iterator` trait for it. +/// and implementing the [`Iterator`] trait for it. /// /// Note that the `FromFn` iterator doesn’t make assumptions about the behavior of the closure, /// and therefore conservatively does not implement [`FusedIterator`], -/// or override [`Iterator::size_hint`] from its default `(0, None)`. -/// -/// [`FusedIterator`]: trait.FusedIterator.html -/// [`Iterator::size_hint`]: trait.Iterator.html#method.size_hint +/// or override [`Iterator::size_hint()`] from its default `(0, None)`. /// /// The closure can use captures and its environment to track state across iterations. Depending on -/// how the iterator is used, this may require specifying the `move` keyword on the closure. +/// how the iterator is used, this may require specifying the [`move`] keyword on the closure. +/// +/// [`move`]: ../../std/keyword.move.html /// /// # Examples /// @@ -549,10 +531,10 @@ where /// An iterator where each iteration calls the provided closure `F: FnMut() -> Option`. /// -/// This `struct` is created by the [`iter::from_fn`] function. +/// This `struct` is created by the [`iter::from_fn()`] function. /// See its documentation for more. /// -/// [`iter::from_fn`]: fn.from_fn.html +/// [`iter::from_fn()`]: from_fn #[derive(Clone)] #[stable(feature = "iter_from_fn", since = "1.34.0")] pub struct FromFn(F); @@ -601,10 +583,10 @@ where /// An new iterator where each successive item is computed based on the preceding one. /// -/// This `struct` is created by the [`successors`] function. +/// This `struct` is created by the [`iter::successors()`] function. /// See its documentation for more. /// -/// [`successors`]: fn.successors.html +/// [`iter::successors()`]: successors #[derive(Clone)] #[stable(feature = "iter_successors", since = "1.34.0")] pub struct Successors { diff --git a/library/core/src/iter/traits/accum.rs b/library/core/src/iter/traits/accum.rs index 494c75174f..dc0d8087ff 100644 --- a/library/core/src/iter/traits/accum.rs +++ b/library/core/src/iter/traits/accum.rs @@ -4,14 +4,13 @@ use crate::ops::{Add, Mul}; /// Trait to represent types that can be created by summing up an iterator. /// -/// This trait is used to implement the [`sum`] method on iterators. Types which -/// implement the trait can be generated by the [`sum`] method. Like +/// This trait is used to implement the [`sum()`] method on iterators. Types which +/// implement the trait can be generated by the [`sum()`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::sum`]. +/// interacted with through [`Iterator::sum()`]. /// -/// [`sum`]: #tymethod.sum -/// [`FromIterator`]: crate::iter::FromIterator -/// [`Iterator::sum`]: crate::iter::Iterator::sum +/// [`sum()`]: Sum::sum +/// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Sum: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -23,14 +22,13 @@ pub trait Sum: Sized { /// Trait to represent types that can be created by multiplying elements of an /// iterator. /// -/// This trait is used to implement the [`product`] method on iterators. Types -/// which implement the trait can be generated by the [`product`] method. Like +/// This trait is used to implement the [`product()`] method on iterators. Types +/// which implement the trait can be generated by the [`product()`] method. Like /// [`FromIterator`] this trait should rarely be called directly and instead -/// interacted with through [`Iterator::product`]. +/// interacted with through [`Iterator::product()`]. /// -/// [`product`]: #tymethod.product -/// [`FromIterator`]: crate::iter::FromIterator -/// [`Iterator::product`]: crate::iter::Iterator::product +/// [`product()`]: Product::product +/// [`FromIterator`]: iter::FromIterator #[stable(feature = "iter_arith_traits", since = "1.12.0")] pub trait Product: Sized { /// Method which takes an iterator and generates `Self` from the elements by @@ -120,9 +118,9 @@ impl Sum> for Result where T: Sum, { - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the sum of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further + /// elements are taken, and the [`Err`] is returned. Should no [`Err`] + /// occur, the sum of all elements is returned. /// /// # Examples /// @@ -150,9 +148,9 @@ impl Product> for Result where T: Product, { - /// Takes each element in the `Iterator`: if it is an `Err`, no further - /// elements are taken, and the `Err` is returned. Should no `Err` occur, - /// the product of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is an [`Err`], no further + /// elements are taken, and the [`Err`] is returned. Should no [`Err`] + /// occur, the product of all elements is returned. fn product(iter: I) -> Result where I: Iterator>, @@ -166,9 +164,9 @@ impl Sum> for Option where T: Sum, { - /// Takes each element in the `Iterator`: if it is a `None`, no further - /// elements are taken, and the `None` is returned. Should no `None` occur, - /// the sum of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is a [`None`], no further + /// elements are taken, and the [`None`] is returned. Should no [`None`] + /// occur, the sum of all elements is returned. /// /// # Examples /// @@ -193,9 +191,9 @@ impl Product> for Option where T: Product, { - /// Takes each element in the `Iterator`: if it is a `None`, no further - /// elements are taken, and the `None` is returned. Should no `None` occur, - /// the product of all elements is returned. + /// Takes each element in the [`Iterator`]: if it is a [`None`], no further + /// elements are taken, and the [`None`] is returned. Should no [`None`] + /// occur, the product of all elements is returned. fn product(iter: I) -> Option where I: Iterator>, diff --git a/library/core/src/iter/traits/collect.rs b/library/core/src/iter/traits/collect.rs index 84c7787a18..41a503c4ab 100644 --- a/library/core/src/iter/traits/collect.rs +++ b/library/core/src/iter/traits/collect.rs @@ -1,21 +1,15 @@ -/// Conversion from an `Iterator`. +/// Conversion from an [`Iterator`]. /// /// By implementing `FromIterator` for a type, you define how it will be /// created from an iterator. This is common for types which describe a /// collection of some kind. /// -/// `FromIterator`'s [`from_iter`] is rarely called explicitly, and is instead -/// used through [`Iterator`]'s [`collect`] method. See [`collect`]'s +/// [`FromIterator::from_iter()`] is rarely called explicitly, and is instead +/// used through [`Iterator::collect()`] method. See [`Iterator::collect()`]'s /// documentation for more examples. /// -/// [`from_iter`]: #tymethod.from_iter -/// [`Iterator`]: trait.Iterator.html -/// [`collect`]: trait.Iterator.html#method.collect -/// /// See also: [`IntoIterator`]. /// -/// [`IntoIterator`]: trait.IntoIterator.html -/// /// # Examples /// /// Basic usage: @@ -30,7 +24,7 @@ /// assert_eq!(v, vec![5, 5, 5, 5, 5]); /// ``` /// -/// Using [`collect`] to implicitly use `FromIterator`: +/// Using [`Iterator::collect()`] to implicitly use `FromIterator`: /// /// ``` /// let five_fives = std::iter::repeat(5).take(5); @@ -119,7 +113,7 @@ pub trait FromIterator: Sized { fn from_iter>(iter: T) -> Self; } -/// Conversion into an `Iterator`. +/// Conversion into an [`Iterator`]. /// /// By implementing `IntoIterator` for a type, you define how it will be /// converted to an iterator. This is common for types which describe a @@ -130,8 +124,6 @@ pub trait FromIterator: Sized { /// /// See also: [`FromIterator`]. /// -/// [`FromIterator`]: trait.FromIterator.html -/// /// # Examples /// /// Basic usage: @@ -235,7 +227,7 @@ pub trait IntoIterator { /// assert_eq!(Some(3), iter.next()); /// assert_eq!(None, iter.next()); /// ``` - #[cfg_attr(not(bootstrap), lang = "into_iter")] + #[lang = "into_iter"] #[stable(feature = "rust1", since = "1.0.0")] fn into_iter(self) -> Self::IntoIter; } @@ -326,7 +318,7 @@ pub trait Extend { /// As this is the only required method for this trait, the [trait-level] docs /// contain more details. /// - /// [trait-level]: trait.Extend.html + /// [trait-level]: Extend /// /// # Examples /// diff --git a/library/core/src/iter/traits/double_ended.rs b/library/core/src/iter/traits/double_ended.rs index 851a1e49a4..16bee0e2ee 100644 --- a/library/core/src/iter/traits/double_ended.rs +++ b/library/core/src/iter/traits/double_ended.rs @@ -1,5 +1,4 @@ -use crate::iter::LoopState; -use crate::ops::Try; +use crate::ops::{ControlFlow, Try}; /// An iterator able to yield elements from both ends. /// @@ -11,11 +10,12 @@ use crate::ops::Try; /// and do not cross: iteration is over when they meet in the middle. /// /// In a similar fashion to the [`Iterator`] protocol, once a -/// `DoubleEndedIterator` returns `None` from a `next_back()`, calling it again -/// may or may not ever return `Some` again. `next()` and `next_back()` are -/// interchangeable for this purpose. +/// `DoubleEndedIterator` returns [`None`] from a [`next_back()`], calling it +/// again may or may not ever return [`Some`] again. [`next()`] and +/// [`next_back()`] are interchangeable for this purpose. /// -/// [`Iterator`]: trait.Iterator.html +/// [`next_back()`]: DoubleEndedIterator::next_back +/// [`next()`]: Iterator::next /// /// # Examples /// @@ -43,7 +43,7 @@ pub trait DoubleEndedIterator: Iterator { /// /// The [trait-level] docs contain more details. /// - /// [trait-level]: trait.DoubleEndedIterator.html + /// [trait-level]: DoubleEndedIterator /// /// # Examples /// @@ -67,7 +67,7 @@ pub trait DoubleEndedIterator: Iterator { /// # Remarks /// /// The elements yielded by `DoubleEndedIterator`'s methods may differ from - /// the ones yielded by `Iterator`'s methods: + /// the ones yielded by [`Iterator`]'s methods: /// /// ``` /// let vec = vec![(1, 'a'), (1, 'b'), (1, 'c'), (2, 'a'), (2, 'b')]; @@ -88,25 +88,63 @@ pub trait DoubleEndedIterator: Iterator { /// vec![(2, 'b'), (1, 'c')] /// ); /// ``` - /// #[stable(feature = "rust1", since = "1.0.0")] fn next_back(&mut self) -> Option; + /// Advances the iterator from the back by `n` elements. + /// + /// `advance_back_by` is the reverse version of [`advance_by`]. This method will + /// eagerly skip `n` elements starting from the back by calling [`next_back`] up + /// to `n` times until [`None`] is encountered. + /// + /// `advance_back_by(n)` will return [`Ok(())`] if the iterator successfully advances by + /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number 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_back_by(0)` does not consume any elements and always returns [`Ok(())`]. + /// + /// [`advance_by`]: Iterator::advance_by + /// [`next_back`]: DoubleEndedIterator::next_back + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_advance_by)] + /// + /// let a = [3, 4, 5, 6]; + /// let mut iter = a.iter(); + /// + /// assert_eq!(iter.advance_back_by(2), Ok(())); + /// assert_eq!(iter.next_back(), Some(&4)); + /// assert_eq!(iter.advance_back_by(0), Ok(())); + /// assert_eq!(iter.advance_back_by(100), Err(1)); // only `&3` was skipped + /// ``` + #[inline] + #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + for i in 0..n { + self.next_back().ok_or(i)?; + } + Ok(()) + } + /// Returns the `n`th element from the end of the iterator. /// - /// This is essentially the reversed version of [`nth`]. Although like most indexing - /// operations, the count starts from zero, so `nth_back(0)` returns the first value from - /// the end, `nth_back(1)` the second, and so on. + /// This is essentially the reversed version of [`Iterator::nth()`]. + /// Although like most indexing operations, the count starts from zero, so + /// `nth_back(0)` returns the first value from the end, `nth_back(1)` the + /// second, and so on. /// /// Note that all elements between the end and the returned element will be /// consumed, including the returned element. This also means that calling /// `nth_back(0)` multiple times on the same iterator will return different /// elements. /// - /// `nth_back()` will return [`None`] if `n` is greater than or equal to the length of the - /// iterator. - /// - /// [`nth`]: crate::iter::Iterator::nth + /// `nth_back()` will return [`None`] if `n` is greater than or equal to the + /// length of the iterator. /// /// # Examples /// @@ -136,20 +174,13 @@ pub trait DoubleEndedIterator: Iterator { /// ``` #[inline] #[stable(feature = "iter_nth_back", since = "1.37.0")] - fn nth_back(&mut self, mut n: usize) -> Option { - for x in self.rev() { - if n == 0 { - return Some(x); - } - n -= 1; - } - None + fn nth_back(&mut self, n: usize) -> Option { + self.advance_back_by(n).ok()?; + self.next_back() } - /// This is the reverse version of [`try_fold()`]: it takes elements - /// starting from the back of the iterator. - /// - /// [`try_fold()`]: trait.Iterator.html#method.try_fold + /// This is the reverse version of [`Iterator::try_fold()`]: it takes + /// elements starting from the back of the iterator. /// /// # Examples /// @@ -196,8 +227,8 @@ pub trait DoubleEndedIterator: Iterator { /// An iterator method that reduces the iterator's elements to a single, /// final value, starting from the back. /// - /// This is the reverse version of [`fold()`]: it takes elements starting from - /// the back of the iterator. + /// This is the reverse version of [`Iterator::fold()`]: it takes elements + /// starting from the back of the iterator. /// /// `rfold()` takes two arguments: an initial value, and a closure with two /// arguments: an 'accumulator', and an element. The closure returns the value that @@ -214,8 +245,6 @@ pub trait DoubleEndedIterator: Iterator { /// Folding is useful whenever you have a collection of something, and want /// to produce a single value from it. /// - /// [`fold()`]: trait.Iterator.html#method.fold - /// /// # Examples /// /// Basic usage: @@ -309,9 +338,9 @@ pub trait DoubleEndedIterator: Iterator { #[inline] fn check( mut predicate: impl FnMut(&T) -> bool, - ) -> impl FnMut((), T) -> LoopState<(), T> { + ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } @@ -324,6 +353,9 @@ impl<'a, I: DoubleEndedIterator + ?Sized> DoubleEndedIterator for &'a mut I { fn next_back(&mut self) -> Option { (**self).next_back() } + fn advance_back_by(&mut self, n: usize) -> Result<(), usize> { + (**self).advance_back_by(n) + } fn nth_back(&mut self, n: usize) -> Option { (**self).nth_back(n) } diff --git a/library/core/src/iter/traits/exact_size.rs b/library/core/src/iter/traits/exact_size.rs index ad87d09588..33ace60a27 100644 --- a/library/core/src/iter/traits/exact_size.rs +++ b/library/core/src/iter/traits/exact_size.rs @@ -6,17 +6,14 @@ /// backwards, a good start is to know where the end is. /// /// When implementing an `ExactSizeIterator`, you must also implement -/// [`Iterator`]. When doing so, the implementation of [`size_hint`] *must* -/// return the exact size of the iterator. -/// -/// [`Iterator`]: trait.Iterator.html -/// [`size_hint`]: trait.Iterator.html#method.size_hint +/// [`Iterator`]. When doing so, the implementation of [`Iterator::size_hint`] +/// *must* return the exact size of the iterator. /// /// The [`len`] method has a default implementation, so you usually shouldn't /// implement it. However, you may be able to provide a more performant /// implementation than the default, so overriding it in this case makes sense. /// -/// [`len`]: #method.len +/// [`len`]: ExactSizeIterator::len /// /// # Examples /// @@ -72,17 +69,17 @@ pub trait ExactSizeIterator: Iterator { /// Returns the exact length of the iterator. /// /// The implementation ensures that the iterator will return exactly `len()` - /// more times a `Some(T)` value, before returning `None`. + /// more times a [`Some(T)`] value, before returning [`None`]. /// This method has a default implementation, so you usually should not /// implement it directly. However, if you can provide a more efficient /// implementation, you can do so. See the [trait-level] docs for an /// example. /// - /// This function has the same safety guarantees as the [`size_hint`] - /// function. + /// This function has the same safety guarantees as the + /// [`Iterator::size_hint`] function. /// - /// [trait-level]: trait.ExactSizeIterator.html - /// [`size_hint`]: trait.Iterator.html#method.size_hint + /// [trait-level]: ExactSizeIterator + /// [`Some(T)`]: Some /// /// # Examples /// @@ -108,8 +105,8 @@ pub trait ExactSizeIterator: Iterator { /// Returns `true` if the iterator is empty. /// - /// This method has a default implementation using `self.len()`, so you - /// don't need to implement it yourself. + /// This method has a default implementation using + /// [`ExactSizeIterator::len()`], so you don't need to implement it yourself. /// /// # Examples /// diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 10498f94c2..813afcc0ec 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -3,9 +3,8 @@ // can't split that into multiple files. use crate::cmp::{self, Ordering}; -use crate::ops::{Add, Try}; +use crate::ops::{Add, ControlFlow, Try}; -use super::super::LoopState; use super::super::TrustedRandomAccess; use super::super::{Chain, Cloned, Copied, Cycle, Enumerate, Filter, FilterMap, Fuse}; use super::super::{FlatMap, Flatten}; @@ -22,8 +21,8 @@ fn _assert_is_object_safe(_: &dyn Iterator) {} /// generally, please see the [module-level documentation]. In particular, you /// may want to know how to [implement `Iterator`][impl]. /// -/// [module-level documentation]: index.html -/// [impl]: index.html#implementing-iterator +/// [module-level documentation]: crate::iter +/// [impl]: crate::iter#implementing-iterator #[stable(feature = "rust1", since = "1.0.0")] #[rustc_on_unimplemented( on( @@ -130,7 +129,7 @@ pub trait Iterator { /// assert_eq!(None, iter.next()); /// assert_eq!(None, iter.next()); /// ``` - #[cfg_attr(not(bootstrap), lang = "next")] + #[lang = "next"] #[stable(feature = "rust1", since = "1.0.0")] fn next(&mut self) -> Option; @@ -212,7 +211,7 @@ pub trait Iterator { /// returning the number of times it saw [`Some`]. Note that [`next`] has to be /// called at least once even if the iterator does not have any elements. /// - /// [`next`]: #tymethod.next + /// [`next`]: Iterator::next /// /// # Overflow Behavior /// @@ -285,6 +284,44 @@ pub trait Iterator { self.fold(None, some) } + /// Advances the iterator by `n` elements. + /// + /// This method will eagerly skip `n` elements by calling [`next`] up to `n` + /// times until [`None`] is encountered. + /// + /// `advance_by(n)` will return [`Ok(())`] if the iterator successfully advances by + /// `n` elements, or [`Err(k)`] if [`None`] is encountered, where `k` is the number + /// 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(())`]. + /// + /// [`next`]: Iterator::next + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(iter_advance_by)] + /// + /// let a = [1, 2, 3, 4]; + /// let mut iter = a.iter(); + /// + /// assert_eq!(iter.advance_by(2), Ok(())); + /// assert_eq!(iter.next(), Some(&3)); + /// assert_eq!(iter.advance_by(0), Ok(())); + /// assert_eq!(iter.advance_by(100), Err(1)); // only `&4` was skipped + /// ``` + #[inline] + #[unstable(feature = "iter_advance_by", reason = "recently added", issue = "77404")] + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + for i in 0..n { + self.next().ok_or(i)?; + } + Ok(()) + } + /// Returns the `n`th element of the iterator. /// /// Like most indexing operations, the count starts from zero, so `nth(0)` @@ -326,14 +363,9 @@ pub trait Iterator { /// ``` #[inline] #[stable(feature = "rust1", since = "1.0.0")] - fn nth(&mut self, mut n: usize) -> Option { - while let Some(x) = self.next() { - if n == 0 { - return Some(x); - } - n -= 1; - } - None + fn nth(&mut self, n: usize) -> Option { + self.advance_by(n).ok()?; + self.next() } /// Creates an iterator starting at the same point, but stepping by @@ -449,9 +481,7 @@ pub trait Iterator { /// } /// ``` /// - /// [`once`]: fn.once.html - /// [`Iterator`]: trait.Iterator.html - /// [`IntoIterator`]: trait.IntoIterator.html + /// [`once`]: crate::iter::once /// [`OsStr`]: ../../std/ffi/struct.OsStr.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] @@ -496,9 +526,6 @@ pub trait Iterator { /// [`Iterator`] itself. For example, slices (`&[T]`) implement /// [`IntoIterator`], and so can be passed to `zip()` directly: /// - /// [`IntoIterator`]: trait.IntoIterator.html - /// [`Iterator`]: trait.Iterator.html - /// /// ``` /// let s1 = &[1, 2, 3]; /// let s2 = &[4, 5, 6]; @@ -530,8 +557,8 @@ pub trait Iterator { /// assert_eq!((2, 'o'), zipper[2]); /// ``` /// - /// [`enumerate`]: #method.enumerate - /// [`next`]: #tymethod.next + /// [`enumerate`]: Iterator::enumerate + /// [`next`]: Iterator::next #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn zip(self, other: U) -> Zip @@ -654,11 +681,9 @@ pub trait Iterator { /// Creates an iterator which uses a closure to determine if an element /// should be yielded. /// - /// The closure must return `true` or `false`. `filter()` creates an - /// iterator which calls this closure on each element. If the closure - /// returns `true`, then the element is returned. If the closure returns - /// `false`, it will try again, and call the closure on the next element, - /// seeing if it passes the test. + /// Given an element the closure must return `true` or `false`. The returned + /// iterator will yield only the elements for which the closure returns + /// true. /// /// # Examples /// @@ -725,23 +750,15 @@ pub trait Iterator { /// Creates an iterator that both filters and maps. /// - /// The closure must return an [`Option`]. `filter_map` creates an - /// iterator which calls this closure on each element. If the closure - /// returns [`Some(element)`][`Some`], then that element is returned. If the - /// closure returns [`None`], it will try again, and call the closure on the - /// next element, seeing if it will return [`Some`]. + /// The returned iterator yields only the `value`s for which the supplied + /// closure returns `Some(value)`. /// - /// Why `filter_map` and not just [`filter`] and [`map`]? The key is in this - /// part: + /// `filter_map` can be used to make chains of [`filter`] and [`map`] more + /// concise. The example below shows how a `map().filter().map()` can be + /// shortened to a single call to `filter_map`. /// - /// [`filter`]: #method.filter - /// [`map`]: #method.map - /// - /// > If the closure returns [`Some(element)`][`Some`], then that element is returned. - /// - /// In other words, it removes the [`Option`] layer automatically. If your - /// mapping is already returning an [`Option`] and you want to skip over - /// [`None`]s, then `filter_map` is much, much nicer to use. + /// [`filter`]: Iterator::filter + /// [`map`]: Iterator::map /// /// # Examples /// @@ -802,7 +819,7 @@ pub trait Iterator { /// /// [`usize`]: type@usize /// [`usize::MAX`]: crate::usize::MAX - /// [`zip`]: #method.zip + /// [`zip`]: Iterator::zip /// /// # Examples /// @@ -825,7 +842,7 @@ pub trait Iterator { Enumerate::new(self) } - /// Creates an iterator which can use `peek` to look at the next element of + /// Creates an iterator which can use [`peek`] to look at the next element of /// the iterator without consuming it. /// /// Adds a [`peek`] method to an iterator. See its documentation for @@ -837,8 +854,8 @@ pub trait Iterator { /// anything other than fetching the next value) of the [`next`] method /// will occur. /// - /// [`peek`]: crate::iter::Peekable::peek - /// [`next`]: #tymethod.next + /// [`peek`]: Peekable::peek + /// [`next`]: Iterator::next /// /// # Examples /// @@ -876,7 +893,7 @@ pub trait Iterator { /// Creates an iterator that [`skip`]s elements based on a predicate. /// - /// [`skip`]: #method.skip + /// [`skip`]: Iterator::skip /// /// `skip_while()` takes a closure as an argument. It will call this /// closure on each element of the iterator, and ignore elements @@ -1043,8 +1060,8 @@ pub trait Iterator { /// /// Here's the same example, but with [`take_while`] and [`map`]: /// - /// [`take_while`]: #method.take_while - /// [`map`]: #method.map + /// [`take_while`]: Iterator::take_while + /// [`map`]: Iterator::map /// /// ``` /// let a = [-1i32, 4, 0, 1]; @@ -1104,7 +1121,7 @@ pub trait Iterator { /// It is also not specified what this iterator returns after the first` None` is returned. /// If you need fused iterator, use [`fuse`]. /// - /// [`fuse`]: #method.fuse + /// [`fuse`]: Iterator::fuse #[inline] #[unstable(feature = "iter_map_while", reason = "recently added", issue = "68537")] fn map_while(self, predicate: P) -> MapWhile @@ -1190,7 +1207,7 @@ pub trait Iterator { /// An iterator adaptor similar to [`fold`] that holds internal state and /// produces a new iterator. /// - /// [`fold`]: #method.fold + /// [`fold`]: Iterator::fold /// /// `scan()` takes two arguments: an initial value which seeds the internal /// state, and a closure with two arguments, the first being a mutable @@ -1246,8 +1263,8 @@ pub trait Iterator { /// one item for each element, and `flat_map()`'s closure returns an /// iterator for each element. /// - /// [`map`]: #method.map - /// [`flatten`]: #method.flatten + /// [`map`]: Iterator::map + /// [`flatten`]: Iterator::flatten /// /// # Examples /// @@ -1333,7 +1350,7 @@ pub trait Iterator { /// two-dimensional and not one-dimensional. To get a one-dimensional /// structure, you have to `flatten()` again. /// - /// [`flat_map()`]: #method.flat_map + /// [`flat_map()`]: Iterator::flat_map #[inline] #[stable(feature = "iterator_flatten", since = "1.29.0")] fn flatten(self) -> Flatten @@ -1640,7 +1657,7 @@ pub trait Iterator { /// assert_eq!(Ok(vec![1, 3]), result); /// ``` /// - /// [`iter`]: #tymethod.next + /// [`iter`]: Iterator::next /// [`String`]: ../../std/string/struct.String.html /// [`char`]: type@char #[inline] @@ -1661,8 +1678,8 @@ pub trait Iterator { /// /// See also [`is_partitioned()`] and [`partition_in_place()`]. /// - /// [`is_partitioned()`]: #method.is_partitioned - /// [`partition_in_place()`]: #method.partition_in_place + /// [`is_partitioned()`]: Iterator::is_partitioned + /// [`partition_in_place()`]: Iterator::partition_in_place /// /// # Examples /// @@ -1716,8 +1733,8 @@ pub trait Iterator { /// /// See also [`is_partitioned()`] and [`partition()`]. /// - /// [`is_partitioned()`]: #method.is_partitioned - /// [`partition()`]: #method.partition + /// [`is_partitioned()`]: Iterator::is_partitioned + /// [`partition()`]: Iterator::partition /// /// # Examples /// @@ -1779,8 +1796,8 @@ pub trait Iterator { /// /// See also [`partition()`] and [`partition_in_place()`]. /// - /// [`partition()`]: #method.partition - /// [`partition_in_place()`]: #method.partition_in_place + /// [`partition()`]: Iterator::partition + /// [`partition_in_place()`]: Iterator::partition_in_place /// /// # Examples /// @@ -1879,8 +1896,8 @@ pub trait Iterator { /// This can also be thought of as the fallible form of [`for_each()`] /// or as the stateless version of [`try_fold()`]. /// - /// [`for_each()`]: #method.for_each - /// [`try_fold()`]: #method.try_fold + /// [`for_each()`]: Iterator::for_each + /// [`try_fold()`]: Iterator::try_fold /// /// # Examples /// @@ -1992,6 +2009,8 @@ pub trait Iterator { /// // they're the same /// assert_eq!(result, result2); /// ``` + #[doc(alias = "reduce")] + #[doc(alias = "inject")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn fold(mut self, init: B, mut f: F) -> B @@ -2006,11 +2025,13 @@ pub trait Iterator { accum } - /// The same as [`fold()`](#method.fold), but uses the first element in the + /// The same as [`fold()`], but uses the first element in the /// iterator as the initial value, folding every subsequent element into it. - /// If the iterator is empty, return `None`; otherwise, return the result + /// If the iterator is empty, return [`None`]; otherwise, return the result /// of the fold. /// + /// [`fold()`]: Iterator::fold + /// /// # Example /// /// Find the maximum value: @@ -2088,12 +2109,12 @@ pub trait Iterator { F: FnMut(Self::Item) -> bool, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { LoopState::Continue(()) } else { LoopState::Break(()) } + if f(x) { ControlFlow::CONTINUE } else { ControlFlow::BREAK } } } - self.try_fold((), check(f)) == LoopState::Continue(()) + self.try_fold((), check(f)) == ControlFlow::CONTINUE } /// Tests if any element of the iterator matches a predicate. @@ -2141,13 +2162,13 @@ pub trait Iterator { F: FnMut(Self::Item) -> bool, { #[inline] - fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> LoopState<(), ()> { + fn check(mut f: impl FnMut(T) -> bool) -> impl FnMut((), T) -> ControlFlow<(), ()> { move |(), x| { - if f(x) { LoopState::Break(()) } else { LoopState::Continue(()) } + if f(x) { ControlFlow::BREAK } else { ControlFlow::CONTINUE } } } - self.try_fold((), check(f)) == LoopState::Break(()) + self.try_fold((), check(f)) == ControlFlow::BREAK } /// Searches for an element of an iterator that satisfies a predicate. @@ -2203,9 +2224,9 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(&T) -> bool, - ) -> impl FnMut((), T) -> LoopState<(), T> { + ) -> impl FnMut((), T) -> ControlFlow<(), T> { move |(), x| { - if predicate(&x) { LoopState::Break(x) } else { LoopState::Continue(()) } + if predicate(&x) { ControlFlow::Break(x) } else { ControlFlow::CONTINUE } } } @@ -2217,7 +2238,6 @@ pub trait Iterator { /// /// `iter.find_map(f)` is equivalent to `iter.filter_map(f).next()`. /// - /// /// # Examples /// /// ``` @@ -2235,10 +2255,12 @@ pub trait Iterator { F: FnMut(Self::Item) -> Option, { #[inline] - fn check(mut f: impl FnMut(T) -> Option) -> impl FnMut((), T) -> LoopState<(), B> { + fn check( + mut f: impl FnMut(T) -> Option, + ) -> impl FnMut((), T) -> ControlFlow<(), B> { move |(), x| match f(x) { - Some(x) => LoopState::Break(x), - None => LoopState::Continue(()), + Some(x) => ControlFlow::Break(x), + None => ControlFlow::CONTINUE, } } @@ -2274,15 +2296,15 @@ pub trait Iterator { R: Try, { #[inline] - fn check(mut f: F) -> impl FnMut((), T) -> LoopState<(), Result> + fn check(mut f: F) -> impl FnMut((), T) -> ControlFlow<(), Result> where F: FnMut(&T) -> R, R: Try, { move |(), x| match f(&x).into_result() { - Ok(false) => LoopState::Continue(()), - Ok(true) => LoopState::Break(Ok(x)), - Err(x) => LoopState::Break(Err(x)), + Ok(false) => ControlFlow::CONTINUE, + Ok(true) => ControlFlow::Break(Ok(x)), + Err(x) => ControlFlow::Break(Err(x)), } } @@ -2352,10 +2374,14 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> LoopState { + ) -> impl FnMut(usize, T) -> ControlFlow { // The addition might panic on overflow move |i, x| { - if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(Add::add(i, 1)) } + if predicate(x) { + ControlFlow::Break(i) + } else { + ControlFlow::Continue(Add::add(i, 1)) + } } } @@ -2411,10 +2437,10 @@ pub trait Iterator { #[inline] fn check( mut predicate: impl FnMut(T) -> bool, - ) -> impl FnMut(usize, T) -> LoopState { + ) -> impl FnMut(usize, T) -> ControlFlow { move |i, x| { let i = i - 1; - if predicate(x) { LoopState::Break(i) } else { LoopState::Continue(i) } + if predicate(x) { ControlFlow::Break(i) } else { ControlFlow::Continue(i) } } } @@ -2602,8 +2628,6 @@ pub trait Iterator { /// This is only possible if the iterator has an end, so `rev()` only /// works on [`DoubleEndedIterator`]s. /// - /// [`DoubleEndedIterator`]: trait.DoubleEndedIterator.html - /// /// # Examples /// /// ``` @@ -2634,7 +2658,7 @@ pub trait Iterator { /// /// This function is, in some sense, the opposite of [`zip`]. /// - /// [`zip`]: #method.zip + /// [`zip`]: Iterator::zip /// /// # Examples /// @@ -2713,7 +2737,7 @@ pub trait Iterator { /// This is useful when you have an iterator over `&T`, but you need an /// iterator over `T`. /// - /// [`clone`]: crate::clone::Clone::clone + /// [`clone`]: Clone::clone /// /// # Examples /// @@ -2831,7 +2855,7 @@ pub trait Iterator { Product::product(self) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another. /// /// # Examples @@ -2853,7 +2877,7 @@ pub trait Iterator { self.cmp_by(other, |x, y| x.cmp(&y)) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another with respect to the specified comparison function. /// /// # Examples @@ -2905,7 +2929,7 @@ pub trait Iterator { } } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another. /// /// # Examples @@ -2929,7 +2953,7 @@ pub trait Iterator { self.partial_cmp_by(other, |x, y| x.partial_cmp(&y)) } - /// Lexicographically compares the elements of this `Iterator` with those + /// Lexicographically compares the elements of this [`Iterator`] with those /// of another with respect to the specified comparison function. /// /// # Examples @@ -2990,7 +3014,7 @@ pub trait Iterator { } } - /// Determines if the elements of this `Iterator` are equal to those of + /// Determines if the elements of this [`Iterator`] are equal to those of /// another. /// /// # Examples @@ -3009,7 +3033,7 @@ pub trait Iterator { self.eq_by(other, |x, y| x == y) } - /// Determines if the elements of this `Iterator` are equal to those of + /// Determines if the elements of this [`Iterator`] are equal to those of /// another with respect to the specified equality function. /// /// # Examples @@ -3050,7 +3074,7 @@ pub trait Iterator { } } - /// Determines if the elements of this `Iterator` are unequal to those of + /// Determines if the elements of this [`Iterator`] are unequal to those of /// another. /// /// # Examples @@ -3069,7 +3093,7 @@ pub trait Iterator { !self.eq(other) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// less than those of another. /// /// # Examples @@ -3078,6 +3102,7 @@ pub trait Iterator { /// assert_eq!([1].iter().lt([1].iter()), false); /// assert_eq!([1].iter().lt([1, 2].iter()), true); /// assert_eq!([1, 2].iter().lt([1].iter()), false); + /// assert_eq!([1, 2].iter().lt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn lt(self, other: I) -> bool @@ -3089,7 +3114,7 @@ pub trait Iterator { self.partial_cmp(other) == Some(Ordering::Less) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// less or equal to those of another. /// /// # Examples @@ -3098,6 +3123,7 @@ pub trait Iterator { /// assert_eq!([1].iter().le([1].iter()), true); /// assert_eq!([1].iter().le([1, 2].iter()), true); /// assert_eq!([1, 2].iter().le([1].iter()), false); + /// assert_eq!([1, 2].iter().le([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn le(self, other: I) -> bool @@ -3109,7 +3135,7 @@ pub trait Iterator { matches!(self.partial_cmp(other), Some(Ordering::Less | Ordering::Equal)) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// greater than those of another. /// /// # Examples @@ -3118,6 +3144,7 @@ pub trait Iterator { /// assert_eq!([1].iter().gt([1].iter()), false); /// assert_eq!([1].iter().gt([1, 2].iter()), false); /// assert_eq!([1, 2].iter().gt([1].iter()), true); + /// assert_eq!([1, 2].iter().gt([1, 2].iter()), false); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn gt(self, other: I) -> bool @@ -3129,7 +3156,7 @@ pub trait Iterator { self.partial_cmp(other) == Some(Ordering::Greater) } - /// Determines if the elements of this `Iterator` are lexicographically + /// Determines if the elements of this [`Iterator`] are lexicographically /// greater than or equal to those of another. /// /// # Examples @@ -3138,6 +3165,7 @@ pub trait Iterator { /// assert_eq!([1].iter().ge([1].iter()), true); /// assert_eq!([1].iter().ge([1, 2].iter()), false); /// assert_eq!([1, 2].iter().ge([1].iter()), true); + /// assert_eq!([1, 2].iter().ge([1, 2].iter()), true); /// ``` #[stable(feature = "iter_order", since = "1.5.0")] fn ge(self, other: I) -> bool @@ -3197,7 +3225,7 @@ pub trait Iterator { /// assert!(![0.0, 1.0, f32::NAN].iter().is_sorted_by(|a, b| a.partial_cmp(b))); /// ``` /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: Iterator::is_sorted #[unstable(feature = "is_sorted", reason = "new API", issue = "53485")] fn is_sorted_by(mut self, mut compare: F) -> bool where @@ -3226,7 +3254,7 @@ pub trait Iterator { /// the elements, as determined by `f`. Apart from that, it's equivalent to [`is_sorted`]; see /// its documentation for more information. /// - /// [`is_sorted`]: #method.is_sorted + /// [`is_sorted`]: Iterator::is_sorted /// /// # Examples /// @@ -3248,6 +3276,8 @@ pub trait Iterator { } /// See [TrustedRandomAccess] + // The unusual name is to avoid name collisions in method resolution + // see #76479. #[inline] #[doc(hidden)] #[unstable(feature = "trusted_random_access", issue = "none")] @@ -3268,6 +3298,9 @@ impl Iterator for &mut I { fn size_hint(&self) -> (usize, Option) { (**self).size_hint() } + fn advance_by(&mut self, n: usize) -> Result<(), usize> { + (**self).advance_by(n) + } fn nth(&mut self, n: usize) -> Option { (**self).nth(n) } diff --git a/library/core/src/iter/traits/marker.rs b/library/core/src/iter/traits/marker.rs index 3c893c0399..0900676146 100644 --- a/library/core/src/iter/traits/marker.rs +++ b/library/core/src/iter/traits/marker.rs @@ -2,14 +2,13 @@ /// /// Calling next on a fused iterator that has returned `None` once is guaranteed /// to return [`None`] again. This trait should be implemented by all iterators -/// that behave this way because it allows optimizing [`Iterator::fuse`]. +/// that behave this way because it allows optimizing [`Iterator::fuse()`]. /// /// Note: In general, you should not use `FusedIterator` in generic bounds if -/// you need a fused iterator. Instead, you should just call [`Iterator::fuse`] +/// you need a fused iterator. Instead, you should just call [`Iterator::fuse()`] /// on the iterator. If the iterator is already fused, the additional [`Fuse`] /// wrapper will be a no-op with no performance penalty. /// -/// [`Iterator::fuse`]: crate::iter::Iterator::fuse /// [`Fuse`]: crate::iter::Fuse #[stable(feature = "fused", since = "1.26.0")] #[rustc_unsafe_specialization_marker] @@ -24,21 +23,34 @@ impl FusedIterator for &mut I {} /// (lower bound is equal to upper bound), or the upper bound is [`None`]. /// The upper bound must only be [`None`] if the actual iterator length is /// larger than [`usize::MAX`]. In that case, the lower bound must be -/// [`usize::MAX`], resulting in a [`.size_hint`] of `(usize::MAX, None)`. +/// [`usize::MAX`], resulting in a [`Iterator::size_hint()`] of +/// `(usize::MAX, None)`. /// /// The iterator must produce exactly the number of elements it reported /// or diverge before reaching the end. /// /// # Safety /// -/// This trait must only be implemented when the contract is upheld. -/// Consumers of this trait must inspect [`.size_hint`]’s upper bound. +/// This trait must only be implemented when the contract is upheld. Consumers +/// of this trait must inspect [`Iterator::size_hint()`]’s upper bound. /// /// [`usize::MAX`]: crate::usize::MAX -/// [`.size_hint`]: crate::iter::Iterator::size_hint #[unstable(feature = "trusted_len", issue = "37572")] #[rustc_unsafe_specialization_marker] pub unsafe trait TrustedLen: Iterator {} #[unstable(feature = "trusted_len", issue = "37572")] unsafe impl TrustedLen for &mut I {} + +/// An iterator that when yielding an item will have taken at least one element +/// from its underlying [`SourceIter`]. +/// +/// Calling [`next()`] guarantees that at least one value of the iterator's underlying source +/// has been moved out and the result of the iterator chain could be inserted in its place, +/// assuming structural constraints of the source allow such an insertion. +/// In other words this trait indicates that an iterator pipeline can be collected in place. +/// +/// [`SourceIter`]: crate::iter::SourceIter +/// [`next()`]: Iterator::next +#[unstable(issue = "none", feature = "inplace_iteration")] +pub unsafe trait InPlaceIterable: Iterator {} diff --git a/library/core/src/iter/traits/mod.rs b/library/core/src/iter/traits/mod.rs index efd1580a54..880f8d831f 100644 --- a/library/core/src/iter/traits/mod.rs +++ b/library/core/src/iter/traits/mod.rs @@ -11,5 +11,7 @@ pub use self::double_ended::DoubleEndedIterator; pub use self::exact_size::ExactSizeIterator; #[stable(feature = "rust1", since = "1.0.0")] pub use self::iterator::Iterator; +#[unstable(issue = "none", feature = "inplace_iteration")] +pub use self::marker::InPlaceIterable; #[stable(feature = "rust1", since = "1.0.0")] pub use self::marker::{FusedIterator, TrustedLen}; diff --git a/library/core/src/lazy.rs b/library/core/src/lazy.rs index 5cf7217ef1..2c517371c2 100644 --- a/library/core/src/lazy.rs +++ b/library/core/src/lazy.rs @@ -92,7 +92,7 @@ impl OnceCell { /// Returns `None` if the cell is empty. #[unstable(feature = "once_cell", issue = "74465")] pub fn get(&self) -> Option<&T> { - // Safety: Safe due to `inner`'s invariant + // SAFETY: Safe due to `inner`'s invariant unsafe { &*self.inner.get() }.as_ref() } @@ -101,7 +101,7 @@ impl OnceCell { /// Returns `None` if the cell is empty. #[unstable(feature = "once_cell", issue = "74465")] pub fn get_mut(&mut self) -> Option<&mut T> { - // Safety: Safe because we have unique access + // SAFETY: Safe because we have unique access unsafe { &mut *self.inner.get() }.as_mut() } @@ -129,13 +129,13 @@ impl OnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn set(&self, value: T) -> Result<(), T> { - // Safety: Safe because we cannot have overlapping mutable borrows + // SAFETY: Safe because we cannot have overlapping mutable borrows let slot = unsafe { &*self.inner.get() }; if slot.is_some() { return Err(value); } - // Safety: This is the only place where we set the slot, no races + // SAFETY: This is the only place where we set the slot, no races // due to reentrancy/concurrency are possible, and we've // checked that slot is currently `None`, so this write // maintains the `inner`'s invariant. diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index 8270b73203..22bf2b15d6 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -66,9 +66,7 @@ #![feature(allow_internal_unstable)] #![feature(arbitrary_self_types)] #![feature(asm)] -#![feature(bound_cloned)] #![feature(cfg_target_has_atomic)] -#![feature(concat_idents)] #![feature(const_alloc_layout)] #![feature(const_discriminant)] #![feature(const_checked_int_methods)] @@ -77,17 +75,21 @@ #![feature(const_float_bits_conv)] #![feature(const_overflowing_int_methods)] #![feature(const_int_unchecked_arith)] +#![feature(const_mut_refs)] #![feature(const_int_pow)] #![feature(constctlz)] #![feature(const_panic)] +#![feature(const_pin)] #![feature(const_fn_union)] +#![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] +#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))] #![feature(const_generics)] #![feature(const_option)] #![feature(const_precise_live_drops)] #![feature(const_ptr_offset)] #![feature(const_ptr_offset_from)] #![feature(const_raw_ptr_comparison)] -#![feature(const_result)] #![feature(const_slice_from_raw_parts)] #![feature(const_slice_ptr_len)] #![feature(const_size_of_val)] @@ -99,13 +101,12 @@ #![feature(custom_inner_attributes)] #![feature(decl_macro)] #![feature(doc_cfg)] -#![cfg_attr(not(bootstrap), feature(doc_spotlight))] +#![feature(doc_spotlight)] #![feature(duration_consts_2)] +#![feature(duration_saturating_ops)] #![feature(extern_types)] #![feature(fundamental)] #![feature(intrinsics)] -#![feature(try_find)] -#![feature(is_sorted)] #![feature(lang_items)] #![feature(link_llvm_intrinsics)] #![feature(llvm_asm)] @@ -117,7 +118,6 @@ #![feature(optin_builtin_traits)] #![feature(or_patterns)] #![feature(prelude_import)] -#![feature(ptr_as_uninit)] #![feature(repr_simd, platform_intrinsics)] #![feature(rustc_attrs)] #![feature(simd_ffi)] @@ -131,8 +131,7 @@ #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(variant_count)] -#![feature(doc_alias)] -#![feature(mmx_target_feature)] +#![cfg_attr(bootstrap, feature(doc_alias))] #![feature(tbm_target_feature)] #![feature(sse4a_target_feature)] #![feature(arm_target_feature)] @@ -148,8 +147,6 @@ #![feature(const_fn_transmute)] #![feature(abi_unadjusted)] #![feature(adx_target_feature)] -#![feature(maybe_uninit_slice)] -#![feature(maybe_uninit_extra)] #![feature(external_doc)] #![feature(associated_type_bounds)] #![feature(const_caller_location)] @@ -169,34 +166,34 @@ mod macros; #[macro_use] mod internal_macros; -#[path = "num/int_macros.rs"] +#[path = "num/shells/int_macros.rs"] #[macro_use] mod int_macros; -#[path = "num/i128.rs"] +#[path = "num/shells/i128.rs"] pub mod i128; -#[path = "num/i16.rs"] +#[path = "num/shells/i16.rs"] pub mod i16; -#[path = "num/i32.rs"] +#[path = "num/shells/i32.rs"] pub mod i32; -#[path = "num/i64.rs"] +#[path = "num/shells/i64.rs"] pub mod i64; -#[path = "num/i8.rs"] +#[path = "num/shells/i8.rs"] pub mod i8; -#[path = "num/isize.rs"] +#[path = "num/shells/isize.rs"] pub mod isize; -#[path = "num/u128.rs"] +#[path = "num/shells/u128.rs"] pub mod u128; -#[path = "num/u16.rs"] +#[path = "num/shells/u16.rs"] pub mod u16; -#[path = "num/u32.rs"] +#[path = "num/shells/u32.rs"] pub mod u32; -#[path = "num/u64.rs"] +#[path = "num/shells/u64.rs"] pub mod u64; -#[path = "num/u8.rs"] +#[path = "num/shells/u8.rs"] pub mod u8; -#[path = "num/usize.rs"] +#[path = "num/shells/usize.rs"] pub mod usize; #[path = "num/f32.rs"] @@ -221,52 +218,41 @@ pub mod ptr; /* Core language traits */ pub mod borrow; -#[cfg(not(test))] // See #65860 pub mod clone; -#[cfg(not(test))] // See #65860 pub mod cmp; pub mod convert; -#[cfg(not(test))] // See #65860 pub mod default; -#[cfg(not(test))] // See #65860 pub mod marker; pub mod ops; /* Core types and methods on primitives */ pub mod any; -#[cfg(not(test))] // See #65860 pub mod array; pub mod ascii; pub mod cell; pub mod char; pub mod ffi; -#[cfg(not(test))] // See #65860 pub mod iter; #[unstable(feature = "once_cell", issue = "74465")] pub mod lazy; pub mod option; pub mod panic; pub mod panicking; -#[cfg(not(test))] // See #65860 pub mod pin; pub mod raw; pub mod result; pub mod sync; -#[cfg(not(test))] // See #65860 pub mod fmt; -#[cfg(not(test))] // See #65860 pub mod hash; pub mod slice; -#[cfg(not(test))] // See #65860 pub mod str; pub mod time; pub mod unicode; /* Async */ -#[cfg(not(test))] // See #65860 pub mod future; pub mod task; diff --git a/library/core/src/macros/mod.rs b/library/core/src/macros/mod.rs index d26f2124f1..a1b0821004 100644 --- a/library/core/src/macros/mod.rs +++ b/library/core/src/macros/mod.rs @@ -242,7 +242,7 @@ macro_rules! debug_assert_ne { #[macro_export] #[stable(feature = "matches_macro", since = "1.42.0")] macro_rules! matches { - ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )?) => { + ($expression:expr, $( $pattern:pat )|+ $( if $guard: expr )? $(,)?) => { match $expression { $( $pattern )|+ $( if $guard )? => true, _ => false @@ -333,16 +333,16 @@ macro_rules! r#try { /// This macro accepts a format string, a list of arguments, and a 'writer'. Arguments will be /// formatted according to the specified format string and the result will be passed to the writer. /// The writer may be any value with a `write_fmt` method; generally this comes from an -/// implementation of either the [`std::fmt::Write`] or the [`std::io::Write`] trait. The macro -/// returns whatever the `write_fmt` method returns; commonly a [`std::fmt::Result`], or an +/// implementation of either the [`fmt::Write`] or the [`io::Write`] trait. The macro +/// returns whatever the `write_fmt` method returns; commonly a [`fmt::Result`], or an /// [`io::Result`]. /// /// See [`std::fmt`] for more information on the format string syntax. /// /// [`std::fmt`]: crate::fmt -/// [`std::fmt::Write`]: crate::fmt::Write -/// [`std::io::Write`]: ../std/io/trait.Write.html -/// [`std::fmt::Result`]: crate::fmt::Result +/// [`fmt::Write`]: crate::fmt::Write +/// [`io::Write`]: ../std/io/trait.Write.html +/// [`fmt::Result`]: crate::fmt::Result /// [`io::Result`]: ../std/io/type.Result.html /// /// # Examples diff --git a/library/core/src/macros/panic.md b/library/core/src/macros/panic.md index 3ecfc43be0..a02e74d5e5 100644 --- a/library/core/src/macros/panic.md +++ b/library/core/src/macros/panic.md @@ -5,12 +5,12 @@ to the caller of the program. `panic!` should be used when a program reaches an unrecoverable state. This macro is the perfect way to assert conditions in example code and in -tests. `panic!` is closely tied with the `unwrap` method of both [`Option`] -and [`Result`][runwrap] enums. Both implementations call `panic!` when they are set -to None or Err variants. +tests. `panic!` is closely tied with the `unwrap` method of both +[`Option`][ounwrap] and [`Result`][runwrap] enums. Both implementations call +`panic!` when they are set to [`None`] or [`Err`] variants. This macro is used to inject panic into a Rust thread, causing the thread to -panic entirely. Each thread's panic can be reaped as the `Box` type, +panic entirely. Each thread's panic can be reaped as the [`Box`]`<`[`Any`]`>` type, and the single-argument form of the `panic!` macro will be the value which is transmitted. @@ -24,11 +24,11 @@ The multi-argument form of this macro panics with a string and has the See also the macro [`compile_error!`], for raising errors during compilation. -[runwrap]: ../std/result/enum.Result.html#method.unwrap -[`Option`]: ../std/option/enum.Option.html#method.unwrap -[`Result`]: ../std/result/enum.Result.html +[ounwrap]: Option::unwrap +[runwrap]: Result::unwrap +[`Box`]: ../std/boxed/struct.Box.html +[`Any`]: crate::any::Any [`format!`]: ../std/macro.format.html -[`compile_error!`]: ../std/macro.compile_error.html [book]: ../book/ch09-00-error-handling.html # Current implementation diff --git a/library/core/src/marker.rs b/library/core/src/marker.rs index 9326aaf568..cdf742057b 100644 --- a/library/core/src/marker.rs +++ b/library/core/src/marker.rs @@ -111,13 +111,13 @@ pub trait Sized { /// - `T` is not part of the type of any other fields /// - `Bar: Unsize>`, if the last field of `Foo` has type `Bar` /// -/// `Unsize` is used along with [`ops::CoerceUnsized`][coerceunsized] to allow -/// "user-defined" containers such as [`rc::Rc`][rc] to contain dynamically-sized +/// `Unsize` is used along with [`ops::CoerceUnsized`] to allow +/// "user-defined" containers such as [`Rc`] to contain dynamically-sized /// types. See the [DST coercion RFC][RFC982] and [the nomicon entry on coercion][nomicon-coerce] /// for more details. /// -/// [coerceunsized]: ../ops/trait.CoerceUnsized.html -/// [rc]: ../../std/rc/struct.Rc.html +/// [`ops::CoerceUnsized`]: crate::ops::CoerceUnsized +/// [`Rc`]: ../../std/rc/struct.Rc.html /// [RFC982]: https://github.com/rust-lang/rfcs/blob/master/text/0982-dst-coercion.md /// [nomicon-coerce]: ../../nomicon/coercions.html #[unstable(feature = "unsize", issue = "27732")] @@ -368,11 +368,7 @@ pub trait StructuralEq { /// /// [`Vec`]: ../../std/vec/struct.Vec.html /// [`String`]: ../../std/string/struct.String.html -/// [`Drop`]: ../../std/ops/trait.Drop.html -/// [`size_of::`]: ../../std/mem/fn.size_of.html -/// [`Clone`]: ../clone/trait.Clone.html -/// [`String`]: ../../std/string/struct.String.html -/// [`i32`]: ../../std/primitive.i32.html +/// [`size_of::`]: crate::mem::size_of /// [impls]: #implementors #[stable(feature = "rust1", since = "1.0.0")] #[lang = "copy"] @@ -400,18 +396,18 @@ pub macro Copy($item:item) { /// This trait is automatically implemented when the compiler determines /// it's appropriate. /// -/// The precise definition is: a type `T` is `Sync` if and only if `&T` is -/// [`Send`][send]. In other words, if there is no possibility of +/// The precise definition is: a type `T` is [`Sync`] if and only if `&T` is +/// [`Send`]. In other words, if there is no possibility of /// [undefined behavior][ub] (including data races) when passing /// `&T` references between threads. /// -/// As one would expect, primitive types like [`u8`][u8] and [`f64`][f64] -/// are all `Sync`, and so are simple aggregate types containing them, -/// like tuples, structs and enums. More examples of basic `Sync` +/// As one would expect, primitive types like [`u8`] and [`f64`] +/// are all [`Sync`], and so are simple aggregate types containing them, +/// like tuples, structs and enums. More examples of basic [`Sync`] /// types include "immutable" types like `&T`, and those with simple /// inherited mutability, such as [`Box`][box], [`Vec`][vec] and -/// most other collection types. (Generic parameters need to be `Sync` -/// for their container to be `Sync`.) +/// most other collection types. (Generic parameters need to be [`Sync`] +/// for their container to be [`Sync`].) /// /// A somewhat surprising consequence of the definition is that `&mut T` /// is `Sync` (if `T` is `Sync`) even though it seems like that might @@ -421,15 +417,15 @@ pub macro Copy($item:item) { /// of a data race. /// /// Types that are not `Sync` are those that have "interior -/// mutability" in a non-thread-safe form, such as [`cell::Cell`][cell] -/// and [`cell::RefCell`][refcell]. These types allow for mutation of +/// mutability" in a non-thread-safe form, such as [`Cell`][cell] +/// and [`RefCell`][refcell]. These types allow for mutation of /// their contents even through an immutable, shared reference. For /// example the `set` method on [`Cell`][cell] takes `&self`, so it requires /// only a shared reference [`&Cell`][cell]. The method performs no /// synchronization, thus [`Cell`][cell] cannot be `Sync`. /// /// Another example of a non-`Sync` type is the reference-counting -/// pointer [`rc::Rc`][rc]. Given any reference [`&Rc`][rc], you can clone +/// pointer [`Rc`][rc]. Given any reference [`&Rc`][rc], you can clone /// a new [`Rc`][rc], modifying the reference counts in a non-atomic way. /// /// For cases when one does need thread-safe interior mutability, @@ -445,24 +441,21 @@ pub macro Copy($item:item) { /// [undefined behavior][ub]. For example, [`transmute`][transmute]-ing /// from `&T` to `&mut T` is invalid. /// -/// See [the Nomicon](../../nomicon/send-and-sync.html) for more -/// details about `Sync`. +/// See [the Nomicon][nomicon-send-and-sync] for more details about `Sync`. /// -/// [send]: trait.Send.html -/// [u8]: ../../std/primitive.u8.html -/// [f64]: ../../std/primitive.f64.html /// [box]: ../../std/boxed/struct.Box.html /// [vec]: ../../std/vec/struct.Vec.html -/// [cell]: ../cell/struct.Cell.html -/// [refcell]: ../cell/struct.RefCell.html +/// [cell]: crate::cell::Cell +/// [refcell]: crate::cell::RefCell /// [rc]: ../../std/rc/struct.Rc.html /// [arc]: ../../std/sync/struct.Arc.html -/// [atomic data types]: ../sync/atomic/index.html +/// [atomic data types]: crate::sync::atomic /// [mutex]: ../../std/sync/struct.Mutex.html /// [rwlock]: ../../std/sync/struct.RwLock.html -/// [unsafecell]: ../cell/struct.UnsafeCell.html +/// [unsafecell]: crate::cell::UnsafeCell /// [ub]: ../../reference/behavior-considered-undefined.html -/// [transmute]: ../../std/mem/fn.transmute.html +/// [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")] #[lang = "sync"] @@ -650,9 +643,9 @@ macro_rules! impls { /// } /// /// impl ExternalResource { -/// fn new() -> ExternalResource { +/// fn new() -> Self { /// let size_of_res = mem::size_of::(); -/// ExternalResource { +/// Self { /// resource_handle: foreign_lib::new(size_of_res), /// resource_type: PhantomData, /// } @@ -698,7 +691,7 @@ mod impls { /// guarantees to [`mem::Discriminant`]. It is **undefined behavior** to transmute /// between `DiscriminantKind::Discriminant` and `mem::Discriminant`. /// -/// [`mem::Discriminant`]: https://doc.rust-lang.org/stable/core/mem/struct.Discriminant.html +/// [`mem::Discriminant`]: crate::mem::Discriminant #[unstable( feature = "discriminant_kind", issue = "none", @@ -708,7 +701,7 @@ mod impls { pub trait DiscriminantKind { /// The type of the discriminant, which must satisfy the trait /// bounds required by `mem::Discriminant`. - #[cfg_attr(not(bootstrap), lang = "discriminant_type")] + #[lang = "discriminant_type"] type Discriminant: Clone + Copy + Debug + Eq + PartialEq + Hash + Send + Sync + Unpin; } @@ -728,23 +721,23 @@ unsafe impl Freeze for &mut T {} /// Types that can be safely moved after being pinned. /// -/// Since Rust itself has no notion of immovable types, and considers moves -/// (e.g., through assignment or [`mem::replace`]) to always be safe, -/// this trait cannot prevent types from moving by itself. +/// Rust itself has no notion of immovable types, and considers moves (e.g., +/// through assignment or [`mem::replace`]) to always be safe. /// -/// Instead it is used to prevent moves through the type system, -/// by controlling the behavior of pointers `P` wrapped in the [`Pin

`] wrapper, -/// which "pin" the type in place by not allowing it to be moved out of them. -/// See the [`pin module`] documentation for more information on pinning. +/// The [`Pin`][Pin] type is used instead to prevent moves through the type +/// system. Pointers `P` wrapped in the [`Pin>`][Pin] wrapper can't be +/// moved out of. See the [`pin` module] documentation for more information on +/// pinning. /// -/// Implementing this trait lifts the restrictions of pinning off a type, -/// which then allows it to move out with functions such as [`mem::replace`]. +/// Implementing the `Unpin` trait for `T` lifts the restrictions of pinning off +/// the type, which then allows moving `T` out of [`Pin>`][Pin] with +/// functions such as [`mem::replace`]. /// /// `Unpin` has no consequence at all for non-pinned data. In particular, /// [`mem::replace`] happily moves `!Unpin` data (it works for any `&mut T`, not -/// just when `T: Unpin`). However, you cannot use -/// [`mem::replace`] on data wrapped inside a [`Pin

`] because you cannot get the -/// `&mut T` you need for that, and *that* is what makes this system work. +/// just when `T: Unpin`). However, you cannot use [`mem::replace`] on data +/// wrapped inside a [`Pin>`][Pin] because you cannot get the `&mut T` you +/// need for that, and *that* is what makes this system work. /// /// So this, for example, can only be done on types implementing `Unpin`: /// @@ -764,9 +757,9 @@ unsafe impl Freeze for &mut T {} /// /// This trait is automatically implemented for almost every type. /// -/// [`mem::replace`]: ../../std/mem/fn.replace.html -/// [`Pin

{ /// /// Unlike `Pin::new_unchecked`, this method is safe because the pointer /// `P` dereferences to an [`Unpin`] type, which cancels the pinning guarantees. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn new(pointer: P) -> Pin

{ - // Safety: the value pointed to is `Unpin`, and so has no requirements + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn new(pointer: P) -> Pin

{ + // SAFETY: the value pointed to is `Unpin`, and so has no requirements // around pinning. unsafe { Pin::new_unchecked(pointer) } } @@ -483,9 +484,10 @@ impl> Pin

{ /// /// This requires that the data inside this `Pin` is [`Unpin`] so that we /// can ignore the pinning invariants when unwrapping it. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub fn into_inner(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const fn into_inner(pin: Pin

) -> P { pin.pointer } } @@ -541,7 +543,7 @@ impl Pin

{ /// use std::pin::Pin; /// /// fn move_pinned_rc(mut x: Rc) { - /// let pinned = unsafe { Pin::new_unchecked(x.clone()) }; + /// let pinned = unsafe { Pin::new_unchecked(Rc::clone(&x)) }; /// { /// let p: Pin<&T> = pinned.as_ref(); /// // This should mean the pointee can never move again. @@ -555,10 +557,11 @@ impl Pin

{ /// ``` /// /// [`mem::swap`]: crate::mem::swap - #[cfg_attr(not(bootstrap), lang = "new_unchecked")] - #[stable(feature = "pin", since = "1.33.0")] + #[lang = "new_unchecked"] #[inline(always)] - pub unsafe fn new_unchecked(pointer: P) -> Pin

{ + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const unsafe fn new_unchecked(pointer: P) -> Pin

{ Pin { pointer } } @@ -589,9 +592,10 @@ impl Pin

{ /// /// If the underlying data is [`Unpin`], [`Pin::into_inner`] should be used /// instead. - #[stable(feature = "pin_into_inner", since = "1.39.0")] #[inline(always)] - pub unsafe fn into_inner_unchecked(pin: Pin

) -> P { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin_into_inner", since = "1.39.0")] + pub const unsafe fn into_inner_unchecked(pin: Pin

) -> P { pin.pointer } } @@ -661,7 +665,7 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. /// - /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning + /// [`pin` module]: self#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked(self, func: F) -> Pin<&'a U> where @@ -692,19 +696,21 @@ impl<'a, T: ?Sized> Pin<&'a T> { /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. /// - /// ["pinning projections"]: ../../std/pin/index.html#projections-and-structural-pinning - #[stable(feature = "pin", since = "1.33.0")] + /// ["pinning projections"]: self#projections-and-structural-pinning #[inline(always)] - pub fn get_ref(self) -> &'a T { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn get_ref(self) -> &'a T { self.pointer } } impl<'a, T: ?Sized> Pin<&'a mut T> { /// Converts this `Pin<&mut T>` into a `Pin<&T>` with the same lifetime. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn into_ref(self) -> Pin<&'a T> { + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + #[stable(feature = "pin", since = "1.33.0")] + pub const fn into_ref(self) -> Pin<&'a T> { Pin { pointer: self.pointer } } @@ -717,9 +723,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// that lives for as long as the borrow of the `Pin`, not the lifetime of /// the `Pin` itself. This method allows turning the `Pin` into a reference /// with the same lifetime as the original `Pin`. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub fn get_mut(self) -> &'a mut T + #[stable(feature = "pin", since = "1.33.0")] + #[rustc_const_unstable(feature = "const_pin", issue = "76654")] + pub const fn get_mut(self) -> &'a mut T where T: Unpin, { @@ -736,9 +743,10 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// /// If the underlying data is `Unpin`, `Pin::get_mut` should be used /// instead. - #[stable(feature = "pin", since = "1.33.0")] #[inline(always)] - pub unsafe fn get_unchecked_mut(self) -> &'a mut T { + #[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 { self.pointer } @@ -756,7 +764,7 @@ impl<'a, T: ?Sized> Pin<&'a mut T> { /// because it is one of the fields of that value), and also that you do /// not move out of the argument you receive to the interior function. /// - /// [`pin` module]: ../../std/pin/index.html#projections-and-structural-pinning + /// [`pin` module]: self#projections-and-structural-pinning #[stable(feature = "pin", since = "1.33.0")] pub unsafe fn map_unchecked_mut(self, func: F) -> Pin<&'a mut U> where diff --git a/library/core/src/ptr/const_ptr.rs b/library/core/src/ptr/const_ptr.rs index fc70dec16f..d09cdb44e0 100644 --- a/library/core/src/ptr/const_ptr.rs +++ b/library/core/src/ptr/const_ptr.rs @@ -836,7 +836,7 @@ impl *const T { /// # use std::mem::align_of; /// # unsafe { /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; + /// let ptr = x.as_ptr().add(n) as *const u8; /// let offset = ptr.align_offset(align_of::()); /// if offset < x.len() - n - 1 { /// let u16_ptr = ptr.add(offset) as *const u16; diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 68b5d1df71..92c4f2ccfe 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -54,16 +54,9 @@ //! [aliasing]: ../../nomicon/aliasing.html //! [book]: ../../book/ch19-01-unsafe-rust.html#dereferencing-a-raw-pointer //! [ub]: ../../reference/behavior-considered-undefined.html -//! [null]: ./fn.null.html //! [zst]: ../../nomicon/exotic-sizes.html#zero-sized-types-zsts -//! [atomic operations]: ../../std/sync/atomic/index.html -//! [`copy`]: ../../std/ptr/fn.copy.html +//! [atomic operations]: crate::sync::atomic //! [`offset`]: ../../std/primitive.pointer.html#method.offset -//! [`read_unaligned`]: ./fn.read_unaligned.html -//! [`write_unaligned`]: ./fn.write_unaligned.html -//! [`read_volatile`]: ./fn.read_volatile.html -//! [`write_volatile`]: ./fn.write_volatile.html -//! [`NonNull::dangling`]: ./struct.NonNull.html#method.dangling #![stable(feature = "rust1", since = "1.0.0")] @@ -118,9 +111,9 @@ mod mut_ptr; /// done automatically by the compiler. This means the fields of packed structs /// are not dropped in-place. /// -/// [`ptr::read`]: ../ptr/fn.read.html -/// [`ptr::read_unaligned`]: ../ptr/fn.read_unaligned.html -/// [pinned]: ../pin/index.html +/// [`ptr::read`]: self::read +/// [`ptr::read_unaligned`]: self::read_unaligned +/// [pinned]: crate::pin /// /// # Safety /// @@ -136,14 +129,12 @@ mod mut_ptr; /// Additionally, if `T` is not [`Copy`], using the pointed-to value after /// calling `drop_in_place` can cause undefined behavior. Note that `*to_drop = /// foo` counts as a use because it will cause the value to be dropped -/// again. [`write`] can be used to overwrite data without causing it to be +/// again. [`write()`] can be used to overwrite data without causing it to be /// dropped. /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`write`]: ../ptr/fn.write.html +/// [valid]: self#safety /// /// # Examples /// @@ -243,9 +234,9 @@ pub(crate) struct FatPtr { /// The `len` argument is the number of **elements**, not the number of bytes. /// /// This function is safe, but actually using the return value is unsafe. -/// See the documentation of [`from_raw_parts`] for slice safety requirements. +/// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. /// -/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html +/// [`slice::from_raw_parts`]: crate::slice::from_raw_parts /// /// # Examples /// @@ -274,10 +265,9 @@ pub const fn slice_from_raw_parts(data: *const T, len: usize) -> *const [T] { /// See the documentation of [`slice_from_raw_parts`] for more details. /// /// This function is safe, but actually using the return value is unsafe. -/// See the documentation of [`from_raw_parts_mut`] for slice safety requirements. +/// See the documentation of [`slice::from_raw_parts_mut`] for slice safety requirements. /// -/// [`slice_from_raw_parts`]: fn.slice_from_raw_parts.html -/// [`from_raw_parts_mut`]: ../../std/slice/fn.from_raw_parts_mut.html +/// [`slice::from_raw_parts_mut`]: crate::slice::from_raw_parts_mut /// /// # Examples /// @@ -316,8 +306,6 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// overlapping region of memory from `x` will be used. This is demonstrated /// in the second example below. /// -/// [`mem::swap`]: ../mem/fn.swap.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -328,7 +316,7 @@ pub const fn slice_from_raw_parts_mut(data: *mut T, len: usize) -> *mut [T] { /// /// Note that even if `T` has size `0`, the pointers must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// # Examples /// @@ -406,7 +394,7 @@ pub unsafe fn swap(x: *mut T, y: *mut T) { /// Note that even if the effectively copied size (`count * size_of::()`) is `0`, /// the pointers must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// # Examples /// @@ -533,8 +521,6 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// operates on raw pointers instead of references. When references are /// available, [`mem::replace`] should be preferred. /// -/// [`mem::replace`]: ../mem/fn.replace.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -547,7 +533,7 @@ unsafe fn swap_nonoverlapping_bytes(x: *mut u8, y: *mut u8, len: usize) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// # Examples /// @@ -653,7 +639,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// `*src` can violate memory safety. Note that assigning to `*src` counts as a /// use because it will attempt to drop the value at `*src`. /// -/// [`write`] can be used to overwrite data without causing it to be dropped. +/// [`write()`] can be used to overwrite data without causing it to be dropped. /// /// ``` /// use std::ptr; @@ -682,11 +668,7 @@ pub unsafe fn replace(dst: *mut T, mut src: T) -> T { /// assert_eq!(s, "bar"); /// ``` /// -/// [`mem::swap`]: ../mem/fn.swap.html -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// [`write`]: ./fn.write.html +/// [valid]: self#safety #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn read(src: *const T) -> T { @@ -723,11 +705,8 @@ pub unsafe fn read(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [`write_unaligned`]: ./fn.write_unaligned.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value -/// [valid]: ../ptr/index.html#safety +/// [read-ownership]: read#ownership-of-the-returned-value +/// [valid]: self#safety /// /// ## On `packed` structs /// @@ -819,8 +798,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been [`read`] from. /// -/// [`read`]: ./fn.read.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -832,8 +809,7 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`write_unaligned`]: ./fn.write_unaligned.html +/// [valid]: self#safety /// /// # Examples /// @@ -888,8 +864,6 @@ pub unsafe fn read_unaligned(src: *const T) -> T { /// assert_eq!(foo, "bar"); /// assert_eq!(bar, "foo"); /// ``` -/// -/// [`mem::swap`]: ../mem/fn.swap.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub unsafe fn write(dst: *mut T, src: T) { @@ -904,7 +878,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// Overwrites a memory location with the given value without reading or /// dropping the old value. /// -/// Unlike [`write`], the pointer may be unaligned. +/// Unlike [`write()`], the pointer may be unaligned. /// /// `write_unaligned` does not drop the contents of `dst`. This is safe, but it /// could leak allocations or resources, so care should be taken not to overwrite @@ -916,9 +890,6 @@ pub unsafe fn write(dst: *mut T, src: T) { /// This is appropriate for initializing uninitialized memory, or overwriting /// memory that has previously been read with [`read_unaligned`]. /// -/// [`write`]: ./fn.write.html -/// [`read_unaligned`]: ./fn.read_unaligned.html -/// /// # Safety /// /// Behavior is undefined if any of the following conditions are violated: @@ -927,7 +898,7 @@ pub unsafe fn write(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// ## On `packed` structs /// @@ -1007,8 +978,6 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// to not be elided or reordered by the compiler across other volatile /// operations. /// -/// [`write_volatile`]: ./fn.write_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -1041,10 +1010,8 @@ pub unsafe fn write_unaligned(dst: *mut T, src: T) { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety -/// [`Copy`]: ../marker/trait.Copy.html -/// [`read`]: ./fn.read.html -/// [read-ownership]: ./fn.read.html#ownership-of-the-returned-value +/// [valid]: self#safety +/// [read-ownership]: read#ownership-of-the-returned-value /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile @@ -1089,8 +1056,6 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// Additionally, it does not drop `src`. Semantically, `src` is moved into the /// location pointed to by `dst`. /// -/// [`read_volatile`]: ./fn.read_volatile.html -/// /// # Notes /// /// Rust does not currently have a rigorously and formally defined memory model, @@ -1115,7 +1080,7 @@ pub unsafe fn read_volatile(src: *const T) -> T { /// /// Note that even if `T` has size `0`, the pointer must be non-NULL and properly aligned. /// -/// [valid]: ../ptr/index.html#safety +/// [valid]: self#safety /// /// Just like in C, whether an operation is volatile has no bearing whatsoever /// on questions involving concurrent access from multiple threads. Volatile diff --git a/library/core/src/ptr/mut_ptr.rs b/library/core/src/ptr/mut_ptr.rs index 2d25f21e55..537aa20bf1 100644 --- a/library/core/src/ptr/mut_ptr.rs +++ b/library/core/src/ptr/mut_ptr.rs @@ -1094,7 +1094,7 @@ impl *mut T { /// # use std::mem::align_of; /// # unsafe { /// let x = [5u8, 6u8, 7u8, 8u8, 9u8]; - /// let ptr = &x[n] as *const u8; + /// let ptr = x.as_ptr().add(n) as *const u8; /// let offset = ptr.align_offset(align_of::()); /// if offset < x.len() - n - 1 { /// let u16_ptr = ptr.add(offset) as *const u16; diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 294a3173d0..5dc7171a7d 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -34,8 +34,8 @@ use crate::slice::{self, SliceIndex}; /// it is your responsibility to ensure that `as_mut` is never called, and `as_ptr` /// is never used for mutation. /// -/// [`PhantomData`]: ../marker/struct.PhantomData.html -/// [`UnsafeCell`]: ../cell/struct.UnsafeCell.html +/// [`PhantomData`]: crate::marker::PhantomData +/// [`UnsafeCell`]: crate::cell::UnsafeCell #[stable(feature = "nonnull", since = "1.25.0")] #[repr(transparent)] #[rustc_layout_scalar_valid_range_start(1)] @@ -82,8 +82,8 @@ impl NonNull { /// /// For the mutable counterpart see [`as_uninit_mut`]. /// - /// [`as_ref`]: #method.as_ref - /// [`as_uninit_mut`]: #method.as_uninit_mut + /// [`as_ref`]: NonNull::as_ref + /// [`as_uninit_mut`]: NonNull::as_uninit_mut /// /// # Safety /// @@ -114,8 +114,8 @@ impl NonNull { /// /// For the shared counterpart see [`as_uninit_ref`]. /// - /// [`as_mut`]: #method.as_mut - /// [`as_uninit_ref`]: #method.as_uninit_ref + /// [`as_mut`]: NonNull::as_mut + /// [`as_uninit_ref`]: NonNull::as_uninit_ref /// /// # Safety /// @@ -181,8 +181,8 @@ impl NonNull { /// /// For the mutable counterpart see [`as_mut`]. /// - /// [`as_uninit_ref`]: #method.as_uninit_ref - /// [`as_mut`]: #method.as_mut + /// [`as_uninit_ref`]: NonNull::as_uninit_ref + /// [`as_mut`]: NonNull::as_mut /// /// # Safety /// @@ -217,8 +217,8 @@ impl NonNull { /// /// For the shared counterpart see [`as_ref`]. /// - /// [`as_uninit_mut`]: #method.as_uninit_mut - /// [`as_ref`]: #method.as_ref + /// [`as_uninit_mut`]: NonNull::as_uninit_mut + /// [`as_ref`]: NonNull::as_ref /// /// # Safety /// @@ -266,8 +266,6 @@ impl NonNull<[T]> { /// This function is safe, but dereferencing the return value is unsafe. /// See the documentation of [`slice::from_raw_parts`] for slice safety requirements. /// - /// [`slice::from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html - /// /// # Examples /// /// ```rust @@ -357,8 +355,8 @@ impl NonNull<[T]> { /// /// For the mutable counterpart see [`as_uninit_slice_mut`]. /// - /// [`as_ref`]: #method.as_ref - /// [`as_uninit_slice_mut`]: #method.as_uninit_slice_mut + /// [`as_ref`]: NonNull::as_ref + /// [`as_uninit_slice_mut`]: NonNull::as_uninit_slice_mut /// /// # Safety /// @@ -386,10 +384,9 @@ impl NonNull<[T]> { /// /// This applies even if the result of this method is unused! /// - /// See also [`slice::from_raw_parts`][]. + /// See also [`slice::from_raw_parts`]. /// /// [valid]: crate::ptr#safety - /// [`NonNull::dangling()`]: NonNull::dangling /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] @@ -403,8 +400,8 @@ impl NonNull<[T]> { /// /// For the shared counterpart see [`as_uninit_slice`]. /// - /// [`as_mut`]: #method.as_mut - /// [`as_uninit_slice`]: #method.as_uninit_slice + /// [`as_mut`]: NonNull::as_mut + /// [`as_uninit_slice`]: NonNull::as_uninit_slice /// /// # Safety /// @@ -432,10 +429,9 @@ impl NonNull<[T]> { /// /// This applies even if the result of this method is unused! /// - /// See also [`slice::from_raw_parts_mut`][]. + /// See also [`slice::from_raw_parts_mut`]. /// /// [valid]: crate::ptr#safety - /// [`NonNull::dangling()`]: NonNull::dangling /// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset /// /// # Examples @@ -452,7 +448,7 @@ impl NonNull<[T]> { /// // Note that calling `memory.as_mut()` is not allowed here as the content may be uninitialized. /// # #[allow(unused_variables)] /// let slice: &mut [MaybeUninit] = unsafe { memory.as_uninit_slice_mut() }; - /// # Ok::<_, std::alloc::AllocErr>(()) + /// # Ok::<_, std::alloc::AllocError>(()) /// ``` #[inline] #[unstable(feature = "ptr_as_uninit", issue = "75402")] diff --git a/library/core/src/ptr/unique.rs b/library/core/src/ptr/unique.rs index 78647eee33..cd6afdccc2 100644 --- a/library/core/src/ptr/unique.rs +++ b/library/core/src/ptr/unique.rs @@ -4,8 +4,6 @@ use crate::marker::{PhantomData, Unsize}; use crate::mem; use crate::ops::{CoerceUnsized, DispatchFromDyn}; -// ignore-tidy-undocumented-unsafe - /// A wrapper around a raw non-null `*mut T` that indicates that the possessor /// of this wrapper owns the referent. Useful for building abstractions like /// `Box`, `Vec`, `String`, and `HashMap`. diff --git a/library/core/src/result.rs b/library/core/src/result.rs index ade5472717..5cec183c23 100644 --- a/library/core/src/result.rs +++ b/library/core/src/result.rs @@ -240,12 +240,12 @@ use crate::{convert, fmt}; #[stable(feature = "rust1", since = "1.0.0")] pub enum Result { /// Contains the success value - #[cfg_attr(not(bootstrap), lang = "Ok")] + #[lang = "Ok"] #[stable(feature = "rust1", since = "1.0.0")] Ok(#[stable(feature = "rust1", since = "1.0.0")] T), /// Contains the error value - #[cfg_attr(not(bootstrap), lang = "Err")] + #[lang = "Err"] #[stable(feature = "rust1", since = "1.0.0")] Err(#[stable(feature = "rust1", since = "1.0.0")] E), } @@ -273,7 +273,7 @@ impl Result { /// assert_eq!(x.is_ok(), false); /// ``` #[must_use = "if you intended to assert that this is ok, consider `.unwrap()` instead"] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_ok(&self) -> bool { @@ -294,7 +294,7 @@ impl Result { /// assert_eq!(x.is_err(), true); /// ``` #[must_use = "if you intended to assert that this is err, consider `.unwrap_err()` instead"] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_err(&self) -> bool { @@ -438,7 +438,7 @@ impl Result { /// assert_eq!(x.as_ref(), Err(&"Error")); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_result", issue = "67520")] + #[rustc_const_stable(feature = "const_result", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn as_ref(&self) -> Result<&T, &E> { match *self { diff --git a/library/core/src/slice/ascii.rs b/library/core/src/slice/ascii.rs new file mode 100644 index 0000000000..42032bc903 --- /dev/null +++ b/library/core/src/slice/ascii.rs @@ -0,0 +1,156 @@ +//! Operations on ASCII `[u8]`. + +use crate::mem; + +#[lang = "slice_u8"] +#[cfg(not(test))] +impl [u8] { + /// Checks if all bytes in this slice are within the ASCII range. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn is_ascii(&self) -> bool { + is_ascii(self) + } + + /// Checks that two slices are an ASCII case-insensitive match. + /// + /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, + /// but without allocating and copying temporaries. + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { + self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b)) + } + + /// Converts this slice to its ASCII upper case equivalent in-place. + /// + /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new uppercased value without modifying the existing one, use + /// [`to_ascii_uppercase`]. + /// + /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_uppercase(&mut self) { + for byte in self { + byte.make_ascii_uppercase(); + } + } + + /// Converts this slice to its ASCII lower case equivalent in-place. + /// + /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', + /// but non-ASCII letters are unchanged. + /// + /// To return a new lowercased value without modifying the existing one, use + /// [`to_ascii_lowercase`]. + /// + /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase + #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] + #[inline] + pub fn make_ascii_lowercase(&mut self) { + for byte in self { + byte.make_ascii_lowercase(); + } + } +} + +/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed +/// from `../str/mod.rs`, which does something similar for utf8 validation. +#[inline] +fn contains_nonascii(v: usize) -> bool { + const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; + (NONASCII_MASK & v) != 0 +} + +/// Optimized ASCII test that will use usize-at-a-time operations instead of +/// byte-at-a-time operations (when possible). +/// +/// The algorithm we use here is pretty simple. If `s` is too short, we just +/// check each byte and be done with it. Otherwise: +/// +/// - Read the first word with an unaligned load. +/// - Align the pointer, read subsequent words until end with aligned loads. +/// - Read the last `usize` from `s` with an unaligned load. +/// +/// If any of these loads produces something for which `contains_nonascii` +/// (above) returns true, then we know the answer is false. +#[inline] +fn is_ascii(s: &[u8]) -> bool { + const USIZE_SIZE: usize = mem::size_of::(); + + let len = s.len(); + let align_offset = s.as_ptr().align_offset(USIZE_SIZE); + + // If we wouldn't gain anything from the word-at-a-time implementation, fall + // back to a scalar loop. + // + // We also do this for architectures where `size_of::()` isn't + // sufficient alignment for `usize`, because it's a weird edge case. + if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { + return s.iter().all(|b| b.is_ascii()); + } + + // We always read the first word unaligned, which means `align_offset` is + // 0, we'd read the same value again for the aligned read. + let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; + + let start = s.as_ptr(); + // SAFETY: We verify `len < USIZE_SIZE` above. + let first_word = unsafe { (start as *const usize).read_unaligned() }; + + if contains_nonascii(first_word) { + return false; + } + // We checked this above, somewhat implicitly. Note that `offset_to_aligned` + // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked + // above. + debug_assert!(offset_to_aligned <= len); + + // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the + // middle chunk of the slice. + let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; + + // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. + let mut byte_pos = offset_to_aligned; + + // Paranoia check about alignment, since we're about to do a bunch of + // unaligned loads. In practice this should be impossible barring a bug in + // `align_offset` though. + debug_assert_eq!((word_ptr as usize) % mem::align_of::(), 0); + + // Read subsequent words until the last aligned word, excluding the last + // aligned word by itself to be done in tail check later, to ensure that + // tail is always one `usize` at most to extra branch `byte_pos == len`. + while byte_pos < len - USIZE_SIZE { + debug_assert!( + // Sanity check that the read is in bounds + (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) && + // And that our assumptions about `byte_pos` hold. + (word_ptr as usize) - (start as usize) == byte_pos + ); + + // SAFETY: We know `word_ptr` is properly aligned (because of + // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end + let word = unsafe { word_ptr.read() }; + if contains_nonascii(word) { + return false; + } + + byte_pos += USIZE_SIZE; + // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that + // after this `add`, `word_ptr` will be at most one-past-the-end. + word_ptr = unsafe { word_ptr.add(1) }; + } + + // Sanity check to ensure there really is only one `usize` left. This should + // be guaranteed by our loop condition. + debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); + + // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. + let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; + + !contains_nonascii(last_word) +} diff --git a/library/core/src/slice/cmp.rs b/library/core/src/slice/cmp.rs new file mode 100644 index 0000000000..ed26c59c17 --- /dev/null +++ b/library/core/src/slice/cmp.rs @@ -0,0 +1,288 @@ +//! Comparison traits for `[T]`. + +use crate::cmp; +use crate::cmp::Ordering::{self, Greater, Less}; +use crate::mem; + +use super::from_raw_parts; +use super::memchr; + +extern "C" { + /// Calls implementation provided memcmp. + /// + /// Interprets the data as u8. + /// + /// Returns 0 for equal, < 0 for less than and > 0 for greater + /// than. + // FIXME(#32610): Return type should be c_int + fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq<[B]> for [A] +where + A: PartialEq, +{ + fn eq(&self, other: &[B]) -> bool { + SlicePartialEq::equal(self, other) + } + + fn ne(&self, other: &[B]) -> bool { + SlicePartialEq::not_equal(self, other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for [T] {} + +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for [T] { + fn cmp(&self, other: &[T]) -> Ordering { + SliceOrd::compare(self, other) + } +} + +/// Implements comparison of vectors lexicographically. +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for [T] { + fn partial_cmp(&self, other: &[T]) -> Option { + SlicePartialOrd::partial_compare(self, other) + } +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialEq +trait SlicePartialEq { + fn equal(&self, other: &[B]) -> bool; + + fn not_equal(&self, other: &[B]) -> bool { + !self.equal(other) + } +} + +// Generic slice equality +impl SlicePartialEq for [A] +where + A: PartialEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use an equal-pointer optimization when types are `Eq` +// We can't make `A` and `B` the same type because `min_specialization` won't +// allow it. +impl SlicePartialEq for [A] +where + A: MarkerEq, +{ + default fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { + return true; + } + + self.iter().zip(other.iter()).all(|(x, y)| x == y) + } +} + +// Use memcmp for bytewise equality when the types allow +impl SlicePartialEq for [A] +where + A: BytewiseEquality, +{ + fn equal(&self, other: &[B]) -> bool { + if self.len() != other.len() { + return false; + } + + // While performance would suffer if `guaranteed_eq` just returned `false` + // for all arguments, correctness and return value of this function are not affected. + if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { + return true; + } + // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. + // The two slices have been checked to have the same size above. + unsafe { + let size = mem::size_of_val(self); + memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 + } + } +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's PartialOrd +trait SlicePartialOrd: Sized { + fn partial_compare(left: &[Self], right: &[Self]) -> Option; +} + +impl SlicePartialOrd for A { + default fn partial_compare(left: &[A], right: &[A]) -> Option { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + match lhs[i].partial_cmp(&rhs[i]) { + Some(Ordering::Equal) => (), + non_eq => return non_eq, + } + } + + left.len().partial_cmp(&right.len()) + } +} + +// This is the impl that we would like to have. Unfortunately it's not sound. +// See `partial_ord_slice.rs`. +/* +impl SlicePartialOrd for A +where + A: Ord, +{ + default fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) + } +} +*/ + +impl SlicePartialOrd for A { + fn partial_compare(left: &[A], right: &[A]) -> Option { + Some(SliceOrd::compare(left, right)) + } +} + +#[rustc_specialization_trait] +trait AlwaysApplicableOrd: SliceOrd + Ord {} + +macro_rules! always_applicable_ord { + ($([$($p:tt)*] $t:ty,)*) => { + $(impl<$($p)*> AlwaysApplicableOrd for $t {})* + } +} + +always_applicable_ord! { + [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, + [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, + [] bool, [] char, + [T: ?Sized] *const T, [T: ?Sized] *mut T, + [T: AlwaysApplicableOrd] &T, + [T: AlwaysApplicableOrd] &mut T, + [T: AlwaysApplicableOrd] Option, +} + +#[doc(hidden)] +// intermediate trait for specialization of slice's Ord +trait SliceOrd: Sized { + fn compare(left: &[Self], right: &[Self]) -> Ordering; +} + +impl SliceOrd for A { + default fn compare(left: &[Self], right: &[Self]) -> Ordering { + let l = cmp::min(left.len(), right.len()); + + // Slice to the loop iteration range to enable bound check + // elimination in the compiler + let lhs = &left[..l]; + let rhs = &right[..l]; + + for i in 0..l { + match lhs[i].cmp(&rhs[i]) { + Ordering::Equal => (), + non_eq => return non_eq, + } + } + + left.len().cmp(&right.len()) + } +} + +// memcmp compares a sequence of unsigned bytes lexicographically. +// this matches the order we want for [u8], but no others (not even [i8]). +impl SliceOrd for u8 { + #[inline] + fn compare(left: &[Self], right: &[Self]) -> Ordering { + let order = + // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. + // We use the minimum of both lengths which guarantees that both regions are + // valid for reads in that interval. + unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; + if order == 0 { + left.len().cmp(&right.len()) + } else if order < 0 { + Less + } else { + Greater + } + } +} + +// Hack to allow specializing on `Eq` even though `Eq` has a method. +#[rustc_unsafe_specialization_marker] +trait MarkerEq: PartialEq {} + +impl MarkerEq for T {} + +#[doc(hidden)] +/// Trait implemented for types that can be compared for equality using +/// their bytewise representation +#[rustc_specialization_trait] +trait BytewiseEquality: MarkerEq + Copy {} + +macro_rules! impl_marker_for { + ($traitname:ident, $($ty:ty)*) => { + $( + impl $traitname<$ty> for $ty { } + )* + } +} + +impl_marker_for!(BytewiseEquality, + u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); + +pub(super) trait SliceContains: Sized { + fn slice_contains(&self, x: &[Self]) -> bool; +} + +impl SliceContains for T +where + T: PartialEq, +{ + default fn slice_contains(&self, x: &[Self]) -> bool { + x.iter().any(|y| *y == *self) + } +} + +impl SliceContains for u8 { + #[inline] + fn slice_contains(&self, x: &[Self]) -> bool { + memchr::memchr(*self, x).is_some() + } +} + +impl SliceContains for i8 { + #[inline] + fn slice_contains(&self, x: &[Self]) -> bool { + let byte = *self as u8; + // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()` + // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed + // to be valid for reads for the length of the slice `x.len()`, which cannot be larger + // than `isize::MAX`. The returned slice is never mutated. + let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) }; + memchr::memchr(byte, bytes).is_some() + } +} diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs new file mode 100644 index 0000000000..16fcb6231d --- /dev/null +++ b/library/core/src/slice/index.rs @@ -0,0 +1,528 @@ +//! Indexing implementations for `[T]`. + +use crate::ops::{self, Bound, Range, RangeBounds}; +use crate::ptr; + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Index for [T] +where + I: SliceIndex<[T]>, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::IndexMut for [T] +where + I: SliceIndex<[T]>, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut I::Output { + index.index_mut(self) + } +} + +#[inline(never)] +#[cold] +#[track_caller] +fn slice_start_index_len_fail(index: usize, len: usize) -> ! { + panic!("range start index {} out of range for slice of length {}", index, len); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_end_index_len_fail(index: usize, len: usize) -> ! { + panic!("range end index {} out of range for slice of length {}", index, len); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_index_order_fail(index: usize, end: usize) -> ! { + panic!("slice index starts at {} but ends at {}", index, end); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_start_index_overflow_fail() -> ! { + panic!("attempted to index slice from after maximum usize"); +} + +#[inline(never)] +#[cold] +#[track_caller] +pub(super) fn slice_end_index_overflow_fail() -> ! { + panic!("attempted to index slice up to maximum usize"); +} + +/// Performs bounds-checking of the given range. +/// The returned [`Range`] is safe to pass to [`get_unchecked`] and [`get_unchecked_mut`] +/// for slices of the given length. +/// +/// [`get_unchecked`]: ../../std/primitive.slice.html#method.get_unchecked +/// [`get_unchecked_mut`]: ../../std/primitive.slice.html#method.get_unchecked_mut +/// +/// # Panics +/// +/// Panics if the range is out of bounds. +/// +/// # Examples +/// +/// ``` +/// #![feature(slice_check_range)] +/// use std::slice; +/// +/// let v = [10, 40, 30]; +/// assert_eq!(1..2, slice::check_range(v.len(), 1..2)); +/// assert_eq!(0..2, slice::check_range(v.len(), ..2)); +/// assert_eq!(1..3, slice::check_range(v.len(), 1..)); +/// ``` +/// +/// Panics when [`Index::index`] would panic: +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 2..1); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..4); +/// ``` +/// +/// ```should_panic +/// #![feature(slice_check_range)] +/// +/// std::slice::check_range(3, 1..=usize::MAX); +/// ``` +/// +/// [`Index::index`]: ops::Index::index +#[track_caller] +#[unstable(feature = "slice_check_range", issue = "76393")] +pub fn check_range>(len: usize, range: R) -> Range { + let start = match range.start_bound() { + Bound::Included(&start) => start, + Bound::Excluded(start) => { + start.checked_add(1).unwrap_or_else(|| slice_start_index_overflow_fail()) + } + Bound::Unbounded => 0, + }; + + let end = match range.end_bound() { + Bound::Included(end) => { + end.checked_add(1).unwrap_or_else(|| slice_end_index_overflow_fail()) + } + Bound::Excluded(&end) => end, + Bound::Unbounded => len, + }; + + if start > end { + slice_index_order_fail(start, end); + } + if end > len { + slice_end_index_len_fail(end, len); + } + + Range { start, end } +} + +mod private_slice_index { + use super::ops; + #[stable(feature = "slice_get_slice", since = "1.28.0")] + pub trait Sealed {} + + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for usize {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::Range {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeTo {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFrom {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeFull {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeInclusive {} + #[stable(feature = "slice_get_slice", since = "1.28.0")] + impl Sealed for ops::RangeToInclusive {} +} + +/// A helper trait used for indexing operations. +/// +/// Implementations of this trait have to promise that if the argument +/// to `get_(mut_)unchecked` is a safe reference, then so is the result. +#[stable(feature = "slice_get_slice", since = "1.28.0")] +#[rustc_on_unimplemented( + on(T = "str", label = "string indices are ranges of `usize`",), + on( + all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), + note = "you can use `.chars().nth()` or `.bytes().nth()`\n\ + for more information, see chapter 8 in The Book: \ + " + ), + message = "the type `{T}` cannot be indexed by `{Self}`", + label = "slice indices are of type `usize` or ranges of `usize`" +)] +pub unsafe trait SliceIndex: private_slice_index::Sealed { + /// The output type returned by methods. + #[stable(feature = "slice_get_slice", since = "1.28.0")] + type Output: ?Sized; + + /// Returns a shared reference to the output at this location, if in + /// bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + fn get(self, slice: &T) -> Option<&Self::Output>; + + /// Returns a mutable reference to the output at this location, if in + /// bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; + + /// Returns a shared reference to the output at this location, without + /// performing any bounds checking. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_index_methods", issue = "none")] + unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; + + /// Returns a mutable reference to the output at this location, without + /// performing any bounds checking. + /// Calling this method with an out-of-bounds index or a dangling `slice` pointer + /// is *[undefined behavior]* even if the resulting reference is not used. + /// + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + #[unstable(feature = "slice_index_methods", issue = "none")] + unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; + + /// Returns a shared reference to the output at this location, panicking + /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + #[track_caller] + fn index(self, slice: &T) -> &Self::Output; + + /// Returns a mutable reference to the output at this location, panicking + /// if out of bounds. + #[unstable(feature = "slice_index_methods", issue = "none")] + #[track_caller] + fn index_mut(self, slice: &mut T) -> &mut Self::Output; +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for usize { + type Output = T; + + #[inline] + fn get(self, slice: &[T]) -> Option<&T> { + // SAFETY: `self` is checked to be in bounds. + if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { + // SAFETY: `self` is checked to be in bounds. + if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { slice.as_ptr().add(self) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { + // SAFETY: see comments for `get_unchecked` above. + unsafe { slice.as_mut_ptr().add(self) } + } + + #[inline] + fn index(self, slice: &[T]) -> &T { + // N.B., use intrinsic indexing + &(*slice)[self] + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut T { + // N.B., use intrinsic indexing + &mut (*slice)[self] + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::Range { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { Some(&*self.get_unchecked(slice)) } + } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + if self.start > self.end || self.end > slice.len() { + None + } else { + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { Some(&mut *self.get_unchecked_mut(slice)) } + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller guarantees that `slice` is not dangling, so it + // cannot be longer than `isize::MAX`. They also guarantee that + // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, + // so the call to `add` is safe. + unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: see comments for `get_unchecked` above. + unsafe { + ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) + } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_end_index_len_fail(self.end, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &*self.get_unchecked(slice) } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if self.start > self.end { + slice_index_order_fail(self.start, self.end); + } else if self.end > slice.len() { + slice_end_index_len_fail(self.end, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &mut *self.get_unchecked_mut(slice) } + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeTo { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..self.end).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..self.end).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..self.end).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..self.end).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..self.end).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..self.end).index_mut(slice) + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeFrom { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (self.start..slice.len()).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (self.start..slice.len()).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (self.start..slice.len()).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if self.start > slice.len() { + slice_start_index_len_fail(self.start, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &*self.get_unchecked(slice) } + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if self.start > slice.len() { + slice_start_index_len_fail(self.start, slice.len()); + } + // SAFETY: `self` is checked to be valid and in bounds above. + unsafe { &mut *self.get_unchecked_mut(slice) } + } +} + +#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] +unsafe impl SliceIndex<[T]> for ops::RangeFull { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + Some(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + Some(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + slice + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + slice + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + slice + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + slice + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex<[T]> for ops::RangeInclusive { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + if *self.end() == usize::MAX { + None + } else { + (*self.start()..self.end() + 1).get_mut(slice) + } + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + if *self.end() == usize::MAX { + slice_end_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + if *self.end() == usize::MAX { + slice_end_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index_mut(slice) + } +} + +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { + type Output = [T]; + + #[inline] + fn get(self, slice: &[T]) -> Option<&[T]> { + (0..=self.end).get(slice) + } + + #[inline] + fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { + (0..=self.end).get_mut(slice) + } + + #[inline] + unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. + unsafe { (0..=self.end).get_unchecked(slice) } + } + + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { + // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. + unsafe { (0..=self.end).get_unchecked_mut(slice) } + } + + #[inline] + fn index(self, slice: &[T]) -> &[T] { + (0..=self.end).index(slice) + } + + #[inline] + fn index_mut(self, slice: &mut [T]) -> &mut [T] { + (0..=self.end).index_mut(slice) + } +} diff --git a/library/core/src/slice/iter.rs b/library/core/src/slice/iter.rs new file mode 100644 index 0000000000..793cbf9949 --- /dev/null +++ b/library/core/src/slice/iter.rs @@ -0,0 +1,2979 @@ +//! Definitions of a bunch of iterators for `[T]`. + +#[macro_use] // import iterator! and forward_iterator! +mod macros; + +use crate::cmp; +use crate::cmp::Ordering; +use crate::fmt; +use crate::intrinsics::{assume, exact_div, unchecked_sub}; +use crate::iter::{FusedIterator, TrustedLen, TrustedRandomAccess}; +use crate::marker::{PhantomData, Send, Sized, Sync}; +use crate::mem; +use crate::ptr::NonNull; + +use super::{from_raw_parts, from_raw_parts_mut}; + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a [T] { + type Item = &'a T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> IntoIterator for &'a mut [T] { + type Item = &'a mut T; + type IntoIter = IterMut<'a, T>; + + fn into_iter(self) -> IterMut<'a, T> { + self.iter_mut() + } +} + +// Macro helper functions +#[inline(always)] +fn size_from_ptr(_: *const T) -> usize { + mem::size_of::() +} + +/// Immutable slice iterator +/// +/// This struct is created by the [`iter`] method on [slices]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]): +/// let slice = &[1, 2, 3]; +/// +/// // Then, we iterate over it: +/// for element in slice.iter() { +/// println!("{}", element); +/// } +/// ``` +/// +/// [`iter`]: ../../std/primitive.slice.html#method.iter +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Iter<'a, T: 'a> { + ptr: NonNull, + end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + // ptr == end is a quick test for the Iterator being empty, that works + // for both ZST and non-ZST. + _marker: PhantomData<&'a T>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Iter<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("Iter").field(&self.as_slice()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for Iter<'_, T> {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for Iter<'_, T> {} + +impl<'a, T> Iter<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T]) -> Self { + let ptr = slice.as_ptr(); + // SAFETY: Similar to `IterMut::new`. + unsafe { + assume(!ptr.is_null()); + + let end = if mem::size_of::() == 0 { + (ptr as *const u8).wrapping_add(slice.len()) as *const T + } else { + ptr.add(slice.len()) + }; + + Self { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: PhantomData } + } + } + + /// Views the underlying data as a subslice of the original data. + /// + /// This has the same lifetime as the original slice, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // First, we declare a type which has the `iter` method to get the `Iter` + /// // struct (&[usize here]): + /// let slice = &[1, 2, 3]; + /// + /// // Then, we get the iterator: + /// let mut iter = slice.iter(); + /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]": + /// println!("{:?}", iter.as_slice()); + /// + /// // Next, we move to the second element of the slice: + /// iter.next(); + /// // Now `as_slice` returns "[2, 3]": + /// println!("{:?}", iter.as_slice()); + /// ``` + #[stable(feature = "iter_to_slice", since = "1.4.0")] + pub fn as_slice(&self) -> &'a [T] { + self.make_slice() + } +} + +iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, { + fn is_sorted_by(self, mut compare: F) -> bool + where + Self: Sized, + F: FnMut(&Self::Item, &Self::Item) -> Option, + { + self.as_slice().windows(2).all(|w| { + compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) + }) + } +}} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Iter<'_, T> { + fn clone(&self) -> Self { + Iter { ptr: self.ptr, end: self.end, _marker: self._marker } + } +} + +#[stable(feature = "slice_iter_as_ref", since = "1.13.0")] +impl AsRef<[T]> for Iter<'_, T> { + fn as_ref(&self) -> &[T] { + self.as_slice() + } +} + +/// Mutable slice iterator. +/// +/// This struct is created by the [`iter_mut`] method on [slices]. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// // First, we declare a type which has `iter_mut` method to get the `IterMut` +/// // struct (&[usize here]): +/// let mut slice = &mut [1, 2, 3]; +/// +/// // Then, we iterate over it and increment each element value: +/// for element in slice.iter_mut() { +/// *element += 1; +/// } +/// +/// // We now have "[2, 3, 4]": +/// println!("{:?}", slice); +/// ``` +/// +/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct IterMut<'a, T: 'a> { + ptr: NonNull, + end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that + // ptr == end is a quick test for the Iterator being empty, that works + // for both ZST and non-ZST. + _marker: PhantomData<&'a mut T>, +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for IterMut<'_, T> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("IterMut").field(&self.make_slice()).finish() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Sync for IterMut<'_, T> {} +#[stable(feature = "rust1", since = "1.0.0")] +unsafe impl Send for IterMut<'_, T> {} + +impl<'a, T> IterMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T]) -> Self { + let ptr = slice.as_mut_ptr(); + // SAFETY: There are several things here: + // + // `ptr` has been obtained by `slice.as_ptr()` where `slice` is a valid + // reference thus it is non-NUL and safe to use and pass to + // `NonNull::new_unchecked` . + // + // Adding `slice.len()` to the starting pointer gives a pointer + // at the end of `slice`. `end` will never be dereferenced, only checked + // for direct pointer equality with `ptr` to check if the iterator is + // done. + // + // In the case of a ZST, the end pointer is just the start pointer plus + // the length, to also allows for the fast `ptr == end` check. + // + // See the `next_unchecked!` and `is_empty!` macros as well as the + // `post_inc_start` method for more informations. + unsafe { + assume(!ptr.is_null()); + + let end = if mem::size_of::() == 0 { + (ptr as *mut u8).wrapping_add(slice.len()) as *mut T + } else { + ptr.add(slice.len()) + }; + + Self { ptr: NonNull::new_unchecked(ptr), end, _marker: PhantomData } + } + } + + /// Views the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut` references that alias, this is forced + /// to consume the iterator. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// // First, we declare a type which has `iter_mut` method to get the `IterMut` + /// // struct (&[usize here]): + /// let mut slice = &mut [1, 2, 3]; + /// + /// { + /// // Then, we get the iterator: + /// let mut iter = slice.iter_mut(); + /// // We move to next element: + /// iter.next(); + /// // So if we print what `into_slice` method returns here, we have "[2, 3]": + /// println!("{:?}", iter.into_slice()); + /// } + /// + /// // Now let's modify a value of the slice: + /// { + /// // First we get back the iterator: + /// let mut iter = slice.iter_mut(); + /// // We change the value of the first element of the slice returned by the `next` method: + /// *iter.next().unwrap() += 1; + /// } + /// // Now slice is "[2, 2, 3]": + /// println!("{:?}", slice); + /// ``` + #[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 + // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites + // for `from_raw_parts_mut` are fulfilled. + unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) } + } + + /// Views the underlying data as a subslice of the original data. + /// + /// To avoid creating `&mut [T]` references that alias, the returned slice + /// borrows its lifetime from the iterator the method is applied on. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// # #![feature(slice_iter_mut_as_slice)] + /// let mut slice: &mut [usize] = &mut [1, 2, 3]; + /// + /// // First, we get the iterator: + /// let mut iter = slice.iter_mut(); + /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": + /// assert_eq!(iter.as_slice(), &[1, 2, 3]); + /// + /// // Next, we move to the second element of the slice: + /// iter.next(); + /// // Now `as_slice` returns "[2, 3]": + /// assert_eq!(iter.as_slice(), &[2, 3]); + /// ``` + #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] + pub fn as_slice(&self) -> &[T] { + self.make_slice() + } +} + +iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} + +/// An internal abstraction over the splitting iterators, so that +/// splitn, splitn_mut etc can be implemented once. +#[doc(hidden)] +pub(super) trait SplitIter: DoubleEndedIterator { + /// Marks the underlying iterator as complete, extracting the remaining + /// portion of the slice. + fn finish(&mut self) -> Option; +} + +/// An iterator over subslices separated by elements that match a predicate +/// function. +/// +/// This struct is created by the [`split`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split(|num| num % 3 == 0); +/// ``` +/// +/// [`split`]: ../../std/primitive.slice.html#method.split +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Split<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> Split<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for Split<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Split<'_, T, P> +where + P: Clone + FnMut(&T) -> bool, +{ + fn clone(&self) -> Self { + Split { v: self.v, pred: self.pred.clone(), finished: self.finished } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> Iterator for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + match self.v.iter().position(|x| (self.pred)(x)) { + None => self.finish(), + Some(idx) => { + let ret = Some(&self.v[..idx]); + self.v = &self.v[idx + 1..]; + ret + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + match self.v.iter().rposition(|x| (self.pred)(x)) { + None => self.finish(), + Some(idx) => { + let ret = Some(&self.v[idx + 1..]); + self.v = &self.v[..idx]; + ret + } + } + } +} + +impl<'a, T, P> SplitIter for Split<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(self.v) + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over subslices separated by elements that match a predicate +/// function. Unlike `Split`, it contains the matched part as a terminator +/// of the subslice. +/// +/// This struct is created by the [`split_inclusive`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let slice = [10, 40, 33, 20]; +/// let mut iter = slice.split_inclusive(|num| num % 3 == 0); +/// ``` +/// +/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusive<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusive<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl fmt::Debug for SplitInclusive<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusive") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "split_inclusive", issue = "72360")] +impl Clone for SplitInclusive<'_, T, P> +where + P: Clone + FnMut(&T) -> bool, +{ + fn clone(&self) -> Self { + SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + let idx = + self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + let ret = Some(&self.v[..idx]); + self.v = &self.v[idx..]; + ret + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.finished { + return None; + } + + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; + let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let ret = Some(&self.v[idx..]); + self.v = &self.v[..idx]; + ret + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the mutable subslices of the vector which are separated +/// by elements that match `pred`. +/// +/// This struct is created by the [`split_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_mut(|num| *num % 3 == 0); +/// ``` +/// +/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a mut [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitMut<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() + } +} + +impl<'a, T, P> SplitIter for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + if self.finished { + None + } else { + self.finished = true; + Some(mem::replace(&mut self.v, &mut [])) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> Iterator for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().position(|x| (*pred)(x)) + }; + match idx_opt { + None => self.finish(), + Some(idx) => { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = &mut tail[1..]; + Some(head) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // if the predicate doesn't match anything, we yield one slice + // if it matches every element, we yield len+1 empty slices. + (1, Some(self.v.len() + 1)) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().rposition(|x| (*pred)(x)) + }; + match idx_opt { + None => self.finish(), + Some(idx) => { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = head; + Some(&mut tail[1..]) + } + } + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the mutable subslices of the vector which are separated +/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched +/// parts in the ends of the subslices. +/// +/// This struct is created by the [`split_inclusive_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(split_inclusive)] +/// +/// let mut v = [10, 40, 30, 20, 60, 50]; +/// let iter = v.split_inclusive_mut(|num| *num % 3 == 0); +/// ``` +/// +/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut +/// [slices]: ../../std/primitive.slice.html +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusiveMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + v: &'a mut [T], + pred: P, + finished: bool, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitInclusiveMut<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { v: slice, pred, finished: false } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl fmt::Debug for SplitInclusiveMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusiveMut") + .field("v", &self.v) + .field("finished", &self.finished) + .finish() + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = { + // work around borrowck limitations + let pred = &mut self.pred; + self.v.iter().position(|x| (*pred)(x)) + }; + let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); + if idx == self.v.len() { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = tail; + Some(head) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.finished { + (0, Some(0)) + } else { + // if the predicate doesn't match anything, we yield one slice + // if it matches every element, we yield len+1 empty slices. + (1, Some(self.v.len() + 1)) + } + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.finished { + return None; + } + + let idx_opt = if self.v.is_empty() { + None + } else { + // work around borrowck limitations + let pred = &mut self.pred; + + // The last index of self.v is already checked and found to match + // by the last iteration, so we start searching a new match + // one index to the left. + let remainder = &self.v[..(self.v.len() - 1)]; + remainder.iter().rposition(|x| (*pred)(x)) + }; + let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); + if idx == 0 { + self.finished = true; + } + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(idx); + self.v = head; + Some(tail) + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over subslices separated by elements that match a predicate +/// function, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit(|num| *num == 0); +/// ``` +/// +/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "slice_rsplit", since = "1.27.0")] +#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? +pub struct RSplit<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: Split<'a, T, P>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplit<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a [T], pred: P) -> Self { + Self { inner: Split::new(slice, pred) } + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl fmt::Debug for RSplit<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplit") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> Iterator for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + self.inner.next() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> SplitIter for RSplit<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a [T]> { + self.inner.finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An iterator over the subslices of the vector which are separated +/// by elements that match `pred`, starting from the end of the slice. +/// +/// This struct is created by the [`rsplit_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = [11, 22, 33, 0, 44, 55]; +/// let iter = slice.rsplit_mut(|num| *num == 0); +/// ``` +/// +/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub struct RSplitMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: SplitMut<'a, T, P>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitMut<'a, T, P> { + #[inline] + pub(super) fn new(slice: &'a mut [T], pred: P) -> Self { + Self { inner: SplitMut::new(slice, pred) } + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl fmt::Debug for RSplitMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitMut") + .field("v", &self.inner.v) + .field("finished", &self.inner.finished) + .finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn finish(&mut self) -> Option<&'a mut [T]> { + self.inner.finish() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> Iterator for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + self.inner.next_back() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> +where + P: FnMut(&T) -> bool, +{ + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + self.inner.next() + } +} + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} + +/// An private iterator over subslices separated by elements that +/// match a predicate function, splitting at most a fixed number of +/// times. +#[derive(Debug)] +struct GenericSplitN { + iter: I, + count: usize, +} + +impl> Iterator for GenericSplitN { + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + match self.count { + 0 => None, + 1 => { + self.count -= 1; + self.iter.finish() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (lower, upper_opt) = self.iter.size_hint(); + (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) + } +} + +/// An iterator over subslices separated by elements that match a predicate +/// function, limited to a given number of splits. +/// +/// This struct is created by the [`splitn`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`splitn`]: ../../std/primitive.slice.html#method.splitn +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitN<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitN<'a, T, P> { + #[inline] + pub(super) fn new(s: Split<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitN<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitN").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a +/// predicate function, limited to a given number of splits, starting +/// from the end of the slice. +/// +/// This struct is created by the [`rsplitn`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RSplitN<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitN<'a, T, P> { + #[inline] + pub(super) fn new(s: RSplit<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for RSplitN<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitN").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a predicate +/// function, limited to a given number of splits. +/// +/// This struct is created by the [`splitn_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.splitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct SplitNMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> SplitNMut<'a, T, P> { + #[inline] + pub(super) fn new(s: SplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for SplitNMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitNMut").field("inner", &self.inner).finish() + } +} + +/// An iterator over subslices separated by elements that match a +/// predicate function, limited to a given number of splits, starting +/// from the end of the slice. +/// +/// This struct is created by the [`rsplitn_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = [10, 40, 30, 20, 60, 50]; +/// let iter = slice.rsplitn_mut(2, |num| *num % 3 == 0); +/// ``` +/// +/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut +/// [slices]: ../../std/primitive.slice.html +#[stable(feature = "rust1", since = "1.0.0")] +pub struct RSplitNMut<'a, T: 'a, P> +where + P: FnMut(&T) -> bool, +{ + inner: GenericSplitN>, +} + +impl<'a, T: 'a, P: FnMut(&T) -> bool> RSplitNMut<'a, T, P> { + #[inline] + pub(super) fn new(s: RSplitMut<'a, T, P>, n: usize) -> Self { + Self { inner: GenericSplitN { iter: s, count: n } } + } +} + +#[stable(feature = "core_impl_debug", since = "1.9.0")] +impl fmt::Debug for RSplitNMut<'_, T, P> +where + P: FnMut(&T) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() + } +} + +forward_iterator! { SplitN: T, &'a [T] } +forward_iterator! { RSplitN: T, &'a [T] } +forward_iterator! { SplitNMut: T, &'a mut [T] } +forward_iterator! { RSplitNMut: T, &'a mut [T] } + +/// An iterator over overlapping subslices of length `size`. +/// +/// This struct is created by the [`windows`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['r', 'u', 's', 't']; +/// let iter = slice.windows(2); +/// ``` +/// +/// [`windows`]: ../../std/primitive.slice.html#method.windows +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Windows<'a, T: 'a> { + v: &'a [T], + size: usize, +} + +impl<'a, T: 'a> Windows<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, size } + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Windows<'_, T> { + fn clone(&self) -> Self { + Windows { v: self.v, size: self.size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Windows<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.size > self.v.len() { + None + } else { + let ret = Some(&self.v[..self.size]); + self.v = &self.v[1..]; + ret + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.size > self.v.len() { + (0, Some(0)) + } else { + let size = self.v.len() - self.size + 1; + (size, Some(size)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = self.size.overflowing_add(n); + if end > self.v.len() || overflow { + self.v = &[]; + None + } else { + let nth = &self.v[n..end]; + self.v = &self.v[n + 1..]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.size > self.v.len() { + None + } else { + let start = self.v.len() - self.size; + Some(&self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: since the caller guarantees that `i` is in bounds, + // which means that `i` cannot overflow an `isize`, and the + // slice created by `from_raw_parts` is a subslice of `self.v` + // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Windows<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.size > self.v.len() { + None + } else { + let ret = Some(&self.v[self.v.len() - self.size..]); + self.v = &self.v[..self.v.len() - 1]; + ret + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let (end, overflow) = self.v.len().overflowing_sub(n); + if end < self.size || overflow { + self.v = &[]; + None + } else { + let ret = &self.v[end - self.size..end]; + self.v = &self.v[..end - 1]; + Some(ret) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Windows<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Windows<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Windows<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`chunks`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks(2); +/// ``` +/// +/// [`chunks`]: ../../std/primitive.slice.html#method.chunks +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Chunks<'a, T: 'a> { + v: &'a [T], + chunk_size: usize, +} + +impl<'a, T: 'a> Chunks<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rust1", since = "1.0.0")] +impl Clone for Chunks<'_, T> { + fn clone(&self) -> Self { + Chunks { v: self.v, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for Chunks<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let chunksz = cmp::min(self.v.len(), self.chunk_size); + let (fst, snd) = self.v.split_at(chunksz); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let end = match start.checked_add(self.chunk_size) { + Some(sum) => cmp::min(self.v.len(), sum), + None => self.v.len(), + }; + let nth = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; + Some(&self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: the caller guarantees that `i` is in bounds, + // which means that `start` must be in bounds of the + // underlying `self.v` slice, and we made sure that `end` + // is also in bounds of `self.v`. Thus, `start` cannot overflow + // an `isize`, and the slice constructed by `from_raw_parts` + // is a subslice of `self.v` which is guaranteed to be valid + // for the lifetime `'a` of `self.v`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; + let (fst, snd) = self.v.split_at(self.v.len() - chunksz); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + Some(res) => cmp::min(res, self.v.len()), + None => self.v.len(), + }; + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Chunks<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Chunks<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Chunks<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`chunks_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_mut(2); +/// ``` +/// +/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ChunksMut<'a, T: 'a> { + v: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T: 'a> ChunksMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> Iterator for ChunksMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let sz = cmp::min(self.v.len(), self.chunk_size); + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); + self.v = tail; + Some(head) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let end = match start.checked_add(self.chunk_size) { + Some(sum) => cmp::min(self.v.len(), sum), + None => self.v.len(), + }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(end); + let (_, nth) = head.split_at_mut(start); + self.v = tail; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; + Some(&mut self.v[start..]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + None => self.v.len(), + Some(end) => cmp::min(end, self.v.len()), + }; + // SAFETY: see comments for `Chunks::__iterator_get_unchecked`. + // + // Also note that the caller also guarantees that we're never called + // with the same index again, and that no other methods that will + // access this subslice are called, so it is valid for the returned + // slice to be mutable. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - sz); + self.v = head; + Some(tail) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = match start.checked_add(self.chunk_size) { + Some(res) => cmp::min(res, self.v.len()), + None => self.v.len(), + }; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); + self.v = head; + Some(nth_back) + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for ChunksMut<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksMut<'_, T> {} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for ChunksMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`chunks_exact`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact(2); +/// ``` +/// +/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact +/// [`remainder`]: ChunksExact::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub struct ChunksExact<'a, T: 'a> { + v: &'a [T], + rem: &'a [T], + chunk_size: usize, +} + +impl<'a, T> ChunksExact<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_unchecked(fst_len) }; + Self { v: fst, rem: snd, chunk_size } + } + + /// 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. + #[stable(feature = "chunks_exact", since = "1.31.0")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl Clone for ChunksExact<'_, T> { + fn clone(&self) -> Self { + ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> Iterator for ChunksExact<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.chunk_size); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let (_, snd) = self.v.split_at(start); + self.v = snd; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = start + self.chunk_size; + let nth_back = &self.v[start..end]; + self.v = &self.v[..start]; + Some(nth_back) + } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl ExactSizeIterator for ChunksExact<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksExact<'_, T> {} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl FusedIterator for ChunksExact<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`chunks_exact_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.chunks_exact_mut(2); +/// ``` +/// +/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut +/// [`into_remainder`]: ChunksExactMut::into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub struct ChunksExactMut<'a, T: 'a> { + v: &'a mut [T], + rem: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T> ChunksExactMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + let fst_len = slice.len() - rem; + // SAFETY: 0 <= fst_len <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_mut_unchecked(fst_len) }; + Self { v: fst, rem: snd, chunk_size } + } + + /// 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. + #[stable(feature = "chunks_exact", since = "1.31.0")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> Iterator for ChunksExactMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); + self.v = tail; + Some(head) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (start, overflow) = n.overflowing_mul(self.chunk_size); + if start >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (_, snd) = tmp.split_at_mut(start); + self.v = snd; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let start = idx * self.chunk_size; + // SAFETY: see comments for `ChunksMut::__iterator_get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + self.v = head; + Some(tail) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + let start = (len - 1 - n) * self.chunk_size; + let end = start + self.chunk_size; + let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (head, nth_back) = temp.split_at_mut(start); + self.v = head; + Some(nth_back) + } + } +} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl ExactSizeIterator for ChunksExactMut<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ChunksExactMut<'_, T> {} + +#[stable(feature = "chunks_exact", since = "1.31.0")] +impl FusedIterator for ChunksExactMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// A windowed iterator over a slice in overlapping chunks (`N` elements at a +/// time), starting at the beginning of the slice +/// +/// This struct is created by the [`array_windows`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(array_windows)] +/// +/// let slice = [0, 1, 2, 3]; +/// let iter = slice.array_windows::<2>(); +/// ``` +/// +/// [`array_windows`]: ../../std/primitive.slice.html#method.array_windows +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug, Clone, Copy)] +#[unstable(feature = "array_windows", issue = "75027")] +pub struct ArrayWindows<'a, T: 'a, const N: usize> { + slice_head: *const T, + num: usize, + marker: PhantomData<&'a [T; N]>, +} + +impl<'a, T: 'a, const N: usize> ArrayWindows<'a, T, N> { + #[inline] + pub(super) fn new(slice: &'a [T]) -> Self { + let num_windows = slice.len().saturating_sub(N - 1); + Self { slice_head: slice.as_ptr(), num: num_windows, marker: PhantomData } + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl<'a, T, const N: usize> Iterator for ArrayWindows<'a, T, N> { + type Item = &'a [T; N]; + + #[inline] + fn next(&mut self) -> Option { + if self.num == 0 { + return None; + } + // SAFETY: + // This is safe because it's indexing into a slice guaranteed to be length > N. + let ret = unsafe { &*self.slice_head.cast::<[T; N]>() }; + // SAFETY: Guaranteed that there are at least 1 item remaining otherwise + // earlier branch would've been hit + self.slice_head = unsafe { self.slice_head.add(1) }; + + self.num -= 1; + Some(ret) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (self.num, Some(self.num)) + } + + #[inline] + fn count(self) -> usize { + self.num + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + if self.num <= n { + self.num = 0; + return None; + } + // SAFETY: + // This is safe because it's indexing into a slice guaranteed to be length > N. + let ret = unsafe { &*self.slice_head.add(n).cast::<[T; N]>() }; + // SAFETY: Guaranteed that there are at least n items remaining + self.slice_head = unsafe { self.slice_head.add(n + 1) }; + + self.num -= n + 1; + Some(ret) + } + + #[inline] + fn last(mut self) -> Option { + self.nth(self.num.checked_sub(1)?) + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayWindows<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T; N]> { + if self.num == 0 { + return None; + } + // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. + let ret = unsafe { &*self.slice_head.add(self.num - 1).cast::<[T; N]>() }; + self.num -= 1; + Some(ret) + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<&'a [T; N]> { + if self.num <= n { + self.num = 0; + return None; + } + // SAFETY: Guaranteed that there are n items remaining, n-1 for 0-indexing. + let ret = unsafe { &*self.slice_head.add(self.num - (n + 1)).cast::<[T; N]>() }; + self.num -= n + 1; + Some(ret) + } +} + +#[unstable(feature = "array_windows", issue = "75027")] +impl ExactSizeIterator for ArrayWindows<'_, T, N> { + fn is_empty(&self) -> bool { + self.num == 0 + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a +/// time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`array_chunks`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks::<2>(); +/// ``` +/// +/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks +/// [`remainder`]: ArrayChunks::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "array_chunks", issue = "74985")] +pub struct ArrayChunks<'a, T: 'a, const N: usize> { + iter: Iter<'a, [T; N]>, + rem: &'a [T], +} + +impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { + #[inline] + pub(super) fn new(slice: &'a [T]) -> Self { + let len = slice.len() / N; + let (fst, snd) = slice.split_at(len * N); + // SAFETY: We cast a slice of `len * N` elements into + // a slice of `len` many `N` elements chunks. + let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) }; + + Self { iter: array_slice.iter(), rem: snd } + } + + /// 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. + #[unstable(feature = "array_chunks", issue = "74985")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "array_chunks", issue = "74985")] +impl Clone for ArrayChunks<'_, T, N> { + fn clone(&self) -> Self { + ArrayChunks { iter: self.iter.clone(), rem: self.rem } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { + type Item = &'a [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are + // transferred to the caller. + unsafe { self.iter.__iterator_get_unchecked(i) } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl ExactSizeIterator for ArrayChunks<'_, T, N> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ArrayChunks<'_, T, N> {} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl FusedIterator for ArrayChunks<'_, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`N` elements +/// at a time), starting at the beginning of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `N-1` elements will be omitted but can be retrieved from +/// the [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`array_chunks_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// #![feature(array_chunks)] +/// +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.array_chunks_mut::<2>(); +/// ``` +/// +/// [`array_chunks_mut`]: ../../std/primitive.slice.html#method.array_chunks_mut +/// [`into_remainder`]: ../../std/slice/struct.ArrayChunksMut.html#method.into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[unstable(feature = "array_chunks", issue = "74985")] +pub struct ArrayChunksMut<'a, T: 'a, const N: usize> { + iter: IterMut<'a, [T; N]>, + rem: &'a mut [T], +} + +impl<'a, T, const N: usize> ArrayChunksMut<'a, T, N> { + #[inline] + pub(super) fn new(slice: &'a mut [T]) -> Self { + let len = slice.len() / N; + let (fst, snd) = slice.split_at_mut(len * N); + // SAFETY: We cast a slice of `len * N` elements into + // a slice of `len` many `N` elements chunks. + unsafe { + let array_slice: &mut [[T; N]] = from_raw_parts_mut(fst.as_mut_ptr().cast(), len); + Self { iter: array_slice.iter_mut(), rem: snd } + } + } + + /// 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. + #[unstable(feature = "array_chunks", issue = "74985")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> Iterator for ArrayChunksMut<'a, T, N> { + type Item = &'a mut [T; N]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.iter.nth(n) + } + + #[inline] + fn last(self) -> Option { + self.iter.last() + } + + unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a mut [T; N] { + // SAFETY: The safety guarantees of `__iterator_get_unchecked` are transferred to + // the caller. + unsafe { self.iter.__iterator_get_unchecked(i) } + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunksMut<'a, T, N> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T; N]> { + self.iter.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.iter.nth_back(n) + } +} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl ExactSizeIterator for ArrayChunksMut<'_, T, N> { + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for ArrayChunksMut<'_, T, N> {} + +#[unstable(feature = "array_chunks", issue = "74985")] +impl FusedIterator for ArrayChunksMut<'_, T, N> {} + +#[doc(hidden)] +#[unstable(feature = "array_chunks", issue = "74985")] +unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunksMut<'a, T, N> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks(2); +/// ``` +/// +/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunks<'a, T: 'a> { + v: &'a [T], + chunk_size: usize, +} + +impl<'a, T: 'a> RChunks<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rchunks", since = "1.31.0")] +impl Clone for RChunks<'_, T> { + fn clone(&self) -> Self { + RChunks { v: self.v, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunks<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let chunksz = cmp::min(self.v.len(), self.chunk_size); + let (fst, snd) = self.v.split_at(self.v.len() - chunksz); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let nth = &self.v[start..end]; + self.v = &self.v[0..start]; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&self.v[0..end]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: mostly identical to `Chunks::__iterator_get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; + let (fst, snd) = self.v.split_at(chunksz); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunks<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunks<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunks<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last slice +/// of the iteration will be the remainder. +/// +/// This struct is created by the [`rchunks_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_mut(2); +/// ``` +/// +/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksMut<'a, T: 'a> { + v: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T: 'a> RChunksMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], size: usize) -> Self { + Self { v: slice, chunk_size: size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let sz = cmp::min(self.v.len(), self.chunk_size); + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - sz); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + if self.v.is_empty() { + (0, Some(0)) + } else { + let n = self.v.len() / self.chunk_size; + let rem = self.v.len() % self.chunk_size; + let n = if rem > 0 { n + 1 } else { n }; + (n, Some(n)) + } + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + // Can't underflow because of the check above + let end = self.v.len() - end; + let start = match end.checked_sub(self.chunk_size) { + Some(sum) => sum, + None => 0, + }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(start); + let (nth, _) = tail.split_at_mut(end - start); + self.v = head; + Some(nth) + } + } + + #[inline] + fn last(self) -> Option { + if self.v.is_empty() { + None + } else { + let rem = self.v.len() % self.chunk_size; + let end = if rem == 0 { self.chunk_size } else { rem }; + Some(&mut self.v[0..end]) + } + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = match end.checked_sub(self.chunk_size) { + None => 0, + Some(start) => start, + }; + // SAFETY: see comments for `RChunks::__iterator_get_unchecked` and + // `ChunksMut::__iterator_get_unchecked` + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.is_empty() { + None + } else { + let remainder = self.v.len() % self.chunk_size; + let sz = if remainder != 0 { remainder } else { self.chunk_size }; + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(sz); + self.v = tail; + Some(head) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // can't underflow because `n < len` + let offset_from_end = (len - 1 - n) * self.chunk_size; + let end = self.v.len() - offset_from_end; + let start = end.saturating_sub(self.chunk_size); + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunksMut<'_, T> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksMut<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a +/// time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last +/// up to `chunk_size-1` elements will be omitted but can be retrieved from +/// the [`remainder`] function from the iterator. +/// +/// This struct is created by the [`rchunks_exact`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact(2); +/// ``` +/// +/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact +/// [`remainder`]: ChunksExact::remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksExact<'a, T: 'a> { + v: &'a [T], + rem: &'a [T], + chunk_size: usize, +} + +impl<'a, T> RChunksExact<'a, T> { + #[inline] + pub(super) fn new(slice: &'a [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_unchecked(rem) }; + Self { v: snd, rem: fst, chunk_size } + } + + /// 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. + #[stable(feature = "rchunks", since = "1.31.0")] + pub fn remainder(&self) -> &'a [T] { + self.rem + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Clone for RChunksExact<'a, T> { + fn clone(&self) -> RChunksExact<'a, T> { + RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksExact<'a, T> { + type Item = &'a [T]; + + #[inline] + fn next(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); + self.v = fst; + Some(snd) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &[]; + None + } else { + let (fst, _) = self.v.split_at(self.v.len() - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: + // SAFETY: mostmy identical to `Chunks::__iterator_get_unchecked`. + unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let (fst, snd) = self.v.split_at(self.chunk_size); + self.v = snd; + Some(fst) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &[]; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let nth_back = &self.v[start..end]; + self.v = &self.v[end..]; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksExact<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksExact<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` +/// elements at a time), starting at the end of the slice. +/// +/// When the slice len is not evenly divided by the chunk size, the last up to +/// `chunk_size-1` elements will be omitted but can be retrieved from the +/// [`into_remainder`] function from the iterator. +/// +/// This struct is created by the [`rchunks_exact_mut`] method on [slices]. +/// +/// # Example +/// +/// ``` +/// let mut slice = ['l', 'o', 'r', 'e', 'm']; +/// let iter = slice.rchunks_exact_mut(2); +/// ``` +/// +/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut +/// [`into_remainder`]: ChunksExactMut::into_remainder +/// [slices]: ../../std/primitive.slice.html +#[derive(Debug)] +#[stable(feature = "rchunks", since = "1.31.0")] +pub struct RChunksExactMut<'a, T: 'a> { + v: &'a mut [T], + rem: &'a mut [T], + chunk_size: usize, +} + +impl<'a, T> RChunksExactMut<'a, T> { + #[inline] + pub(super) fn new(slice: &'a mut [T], chunk_size: usize) -> Self { + let rem = slice.len() % chunk_size; + // SAFETY: 0 <= rem <= slice.len() by construction above + let (fst, snd) = unsafe { slice.split_at_mut_unchecked(rem) }; + Self { v: snd, rem: fst, chunk_size } + } + + /// 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. + #[stable(feature = "rchunks", since = "1.31.0")] + pub fn into_remainder(self) -> &'a mut [T] { + self.rem + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> Iterator for RChunksExactMut<'a, T> { + type Item = &'a mut [T]; + + #[inline] + fn next(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); + self.v = head; + Some(tail) + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let n = self.v.len() / self.chunk_size; + (n, Some(n)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { + let (end, overflow) = n.overflowing_mul(self.chunk_size); + if end >= self.v.len() || overflow { + self.v = &mut []; + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let tmp_len = tmp.len(); + let (fst, _) = tmp.split_at_mut(tmp_len - end); + self.v = fst; + self.next() + } + } + + #[inline] + fn last(mut self) -> Option { + self.next_back() + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + let end = self.v.len() - idx * self.chunk_size; + let start = end - self.chunk_size; + // SAFETY: see comments for `RChunksMut::__iterator_get_unchecked`. + unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<&'a mut [T]> { + if self.v.len() < self.chunk_size { + None + } else { + let tmp = mem::replace(&mut self.v, &mut []); + let (head, tail) = tmp.split_at_mut(self.chunk_size); + self.v = tail; + Some(head) + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + let len = self.len(); + if n >= len { + self.v = &mut []; + None + } else { + // now that we know that `n` corresponds to a chunk, + // none of these operations can underflow/overflow + let offset = (len - n) * self.chunk_size; + let start = self.v.len() - offset; + let end = start + self.chunk_size; + let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); + let (_, nth_back) = tmp.split_at_mut(start); + self.v = tail; + Some(nth_back) + } + } +} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl ExactSizeIterator for RChunksExactMut<'_, T> { + fn is_empty(&self) -> bool { + self.v.is_empty() + } +} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for RChunksExactMut<'_, T> {} + +#[stable(feature = "rchunks", since = "1.31.0")] +impl FusedIterator for RChunksExactMut<'_, T> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { + fn may_have_side_effect() -> bool { + false + } +} diff --git a/library/core/src/slice/iter/macros.rs b/library/core/src/slice/iter/macros.rs new file mode 100644 index 0000000000..457b2a3605 --- /dev/null +++ b/library/core/src/slice/iter/macros.rs @@ -0,0 +1,407 @@ +//! Macros used by iterators of slice. + +// Inlining is_empty and len makes a huge performance difference +macro_rules! is_empty { + // The way we encode the length of a ZST iterator, this works both for ZST + // and non-ZST. + ($self: ident) => { + $self.ptr.as_ptr() as *const T == $self.end + }; +} + +// To get rid of some bounds checks (see `position`), we compute the length in a somewhat +// unexpected way. (Tested by `codegen/slice-position-bounds-check`.) +macro_rules! len { + ($self: ident) => {{ + #![allow(unused_unsafe)] // we're sometimes used within an unsafe block + + let start = $self.ptr; + let size = size_from_ptr(start.as_ptr()); + if size == 0 { + // This _cannot_ use `unchecked_sub` because we depend on wrapping + // to represent the length of long ZST slice iterators. + ($self.end as usize).wrapping_sub(start.as_ptr() as usize) + } else { + // We know that `start <= end`, so can do better than `offset_from`, + // which needs to deal in signed. By setting appropriate flags here + // we can tell LLVM this, which helps it remove bounds checks. + // SAFETY: By the type invariant, `start <= end` + let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) }; + // By also telling LLVM that the pointers are apart by an exact + // multiple of the type size, it can optimize `len() == 0` down to + // `start == end` instead of `(end - start) < size`. + // SAFETY: By the type invariant, the pointers are aligned so the + // distance between them must be a multiple of pointee size + unsafe { exact_div(diff, size) } + } + }}; +} + +// The shared definition of the `Iter` and `IterMut` iterators +macro_rules! iterator { + ( + struct $name:ident -> $ptr:ty, + $elem:ty, + $raw_mut:tt, + {$( $mut_:tt )?}, + {$($extra:tt)*} + ) => { + // Returns the first element and moves the start of the iterator forwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_unchecked { + ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)} + } + + // Returns the last element and moves the end of the iterator backwards by 1. + // Greatly improves performance compared to an inlined function. The iterator + // must not be empty. + macro_rules! next_back_unchecked { + ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)} + } + + // Shrinks the iterator when T is a ZST, by moving the end of the iterator + // backwards by `n`. `n` must not exceed `self.len()`. + macro_rules! zst_shrink { + ($self: ident, $n: ident) => { + $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; + } + } + + impl<'a, T> $name<'a, T> { + // Helper function for creating a slice from the iterator. + #[inline(always)] + fn make_slice(&self) -> &'a [T] { + // SAFETY: the iterator was created from a slice with pointer + // `self.ptr` and length `len!(self)`. This guarantees that all + // the prerequisites for `from_raw_parts` are fulfilled. + unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) } + } + + // Helper function for moving the start of the iterator forwards by `offset` elements, + // returning the old start. + // Unsafe because the offset must not exceed `self.len()`. + #[inline(always)] + unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { + if mem::size_of::() == 0 { + zst_shrink!(self, offset); + self.ptr.as_ptr() + } else { + let old = self.ptr.as_ptr(); + // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, + // so this new pointer is inside `self` and thus guaranteed to be non-null. + self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; + old + } + } + + // Helper function for moving the end of the iterator backwards by `offset` elements, + // returning the new end. + // Unsafe because the offset must not exceed `self.len()`. + #[inline(always)] + unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { + if mem::size_of::() == 0 { + zst_shrink!(self, offset); + self.ptr.as_ptr() + } else { + // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, + // which is guaranteed to not overflow an `isize`. Also, the resulting pointer + // is in bounds of `slice`, which fulfills the other requirements for `offset`. + self.end = unsafe { self.end.offset(-offset) }; + self.end + } + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl ExactSizeIterator for $name<'_, T> { + #[inline(always)] + fn len(&self) -> usize { + len!(self) + } + + #[inline(always)] + fn is_empty(&self) -> bool { + is_empty!(self) + } + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T> Iterator for $name<'a, T> { + type Item = $elem; + + #[inline] + fn next(&mut self) -> Option<$elem> { + // could be implemented with slices, but this avoids bounds checks + + // SAFETY: `assume` calls are safe since a slice's start pointer + // must be non-null, and slices over non-ZSTs must also have a + // non-null end pointer. The call to `next_unchecked!` is safe + // since we check if the iterator is empty first. + unsafe { + assume(!self.ptr.as_ptr().is_null()); + if mem::size_of::() != 0 { + assume(!self.end.is_null()); + } + if is_empty!(self) { + None + } else { + Some(next_unchecked!(self)) + } + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let exact = len!(self); + (exact, Some(exact)) + } + + #[inline] + fn count(self) -> usize { + len!(self) + } + + #[inline] + fn nth(&mut self, n: usize) -> Option<$elem> { + if n >= len!(self) { + // This iterator is now empty. + if mem::size_of::() == 0 { + // We have to do it this way as `ptr` may never be 0, but `end` + // could be (due to wrapping). + self.end = self.ptr.as_ptr(); + } else { + // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr + unsafe { + self.ptr = NonNull::new_unchecked(self.end as *mut T); + } + } + return None; + } + // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. + unsafe { + self.post_inc_start(n as isize); + Some(next_unchecked!(self)) + } + } + + #[inline] + fn last(mut self) -> Option<$elem> { + self.next_back() + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn for_each(mut self, mut f: F) + where + Self: Sized, + F: FnMut(Self::Item), + { + while let Some(x) = self.next() { + f(x); + } + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn all(&mut self, mut f: F) -> bool + where + Self: Sized, + F: FnMut(Self::Item) -> bool, + { + while let Some(x) = self.next() { + if !f(x) { + return false; + } + } + true + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn any(&mut self, mut f: F) -> bool + where + Self: Sized, + F: FnMut(Self::Item) -> bool, + { + while let Some(x) = self.next() { + if f(x) { + return true; + } + } + false + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn find

(&mut self, mut predicate: P) -> Option + where + Self: Sized, + P: FnMut(&Self::Item) -> bool, + { + while let Some(x) = self.next() { + if predicate(&x) { + return Some(x); + } + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. + #[inline] + fn find_map(&mut self, mut f: F) -> Option + where + Self: Sized, + F: FnMut(Self::Item) -> Option, + { + while let Some(x) = self.next() { + if let Some(y) = f(x) { + return Some(y); + } + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. Also, the `assume` avoids a bounds check. + #[inline] + #[rustc_inherit_overflow_checks] + fn position

(&mut self, mut predicate: P) -> Option where + Self: Sized, + P: FnMut(Self::Item) -> bool, + { + let n = len!(self); + let mut i = 0; + while let Some(x) = self.next() { + if predicate(x) { + // SAFETY: we are guaranteed to be in bounds by the loop invariant: + // when `i >= n`, `self.next()` returns `None` and the loop breaks. + unsafe { assume(i < n) }; + return Some(i); + } + i += 1; + } + None + } + + // We override the default implementation, which uses `try_fold`, + // because this simple implementation generates less LLVM IR and is + // faster to compile. Also, the `assume` avoids a bounds check. + #[inline] + fn rposition

(&mut self, mut predicate: P) -> Option where + P: FnMut(Self::Item) -> bool, + Self: Sized + ExactSizeIterator + DoubleEndedIterator + { + let n = len!(self); + let mut i = n; + while let Some(x) = self.next_back() { + i -= 1; + if predicate(x) { + // SAFETY: `i` must be lower than `n` since it starts at `n` + // and is only decreasing. + unsafe { assume(i < n) }; + return Some(i); + } + } + None + } + + #[doc(hidden)] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { + // SAFETY: the caller must guarantee that `i` is in bounds of + // the underlying slice, so `i` cannot overflow an `isize`, and + // the returned references is guaranteed to refer to an element + // of the slice and thus guaranteed to be valid. + // + // Also note that the caller also guarantees that we're never + // called with the same index again, and that no other methods + // that will access this subslice are called, so it is valid + // for the returned reference to be mutable in the case of + // `IterMut` + unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } + } + + $($extra)* + } + + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, T> DoubleEndedIterator for $name<'a, T> { + #[inline] + fn next_back(&mut self) -> Option<$elem> { + // could be implemented with slices, but this avoids bounds checks + + // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null, + // and slices over non-ZSTs must also have a non-null end pointer. + // The call to `next_back_unchecked!` is safe since we check if the iterator is + // empty first. + unsafe { + assume(!self.ptr.as_ptr().is_null()); + if mem::size_of::() != 0 { + assume(!self.end.is_null()); + } + if is_empty!(self) { + None + } else { + Some(next_back_unchecked!(self)) + } + } + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option<$elem> { + if n >= len!(self) { + // This iterator is now empty. + self.end = self.ptr.as_ptr(); + return None; + } + // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. + unsafe { + self.pre_dec_end(n as isize); + Some(next_back_unchecked!(self)) + } + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl FusedIterator for $name<'_, T> {} + + #[unstable(feature = "trusted_len", issue = "37572")] + unsafe impl TrustedLen for $name<'_, T> {} + } +} + +macro_rules! forward_iterator { + ($name:ident: $elem:ident, $iter_of:ty) => { + #[stable(feature = "rust1", since = "1.0.0")] + impl<'a, $elem, P> Iterator for $name<'a, $elem, P> + where + P: FnMut(&T) -> bool, + { + type Item = $iter_of; + + #[inline] + fn next(&mut self) -> Option<$iter_of> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} + }; +} diff --git a/library/core/src/slice/memchr.rs b/library/core/src/slice/memchr.rs index 3b13ed5fed..0c0f175026 100644 --- a/library/core/src/slice/memchr.rs +++ b/library/core/src/slice/memchr.rs @@ -12,6 +12,7 @@ const HI_U64: u64 = 0x8080808080808080; // Use truncation. const LO_USIZE: usize = LO_U64 as usize; const HI_USIZE: usize = HI_U64 as usize; +const USIZE_BYTES: usize = mem::size_of::(); /// Returns `true` if `x` contains any zero byte. /// @@ -38,19 +39,29 @@ fn repeat_byte(b: u8) -> usize { } /// Returns the first index matching the byte `x` in `text`. +#[inline] pub fn memchr(x: u8, text: &[u8]) -> Option { + // Fast path for small slices + if text.len() < 2 * USIZE_BYTES { + return text.iter().position(|elt| *elt == x); + } + + memchr_general_case(x, text) +} + +fn memchr_general_case(x: u8, text: &[u8]) -> Option { // Scan for a single byte value by reading two `usize` words at a time. // // Split `text` in three parts // - unaligned initial part, before the first word aligned address in text // - body, scan by 2 words at a time // - the last remaining part, < 2 word size - let len = text.len(); - let ptr = text.as_ptr(); - let usize_bytes = mem::size_of::(); // search up to an aligned boundary - let mut offset = ptr.align_offset(usize_bytes); + let len = text.len(); + let ptr = text.as_ptr(); + let mut offset = ptr.align_offset(USIZE_BYTES); + if offset > 0 { offset = cmp::min(offset, len); if let Some(index) = text[..offset].iter().position(|elt| *elt == x) { @@ -60,22 +71,19 @@ pub fn memchr(x: u8, text: &[u8]) -> Option { // search the body of the text let repeated_x = repeat_byte(x); + while offset <= len - 2 * USIZE_BYTES { + unsafe { + let u = *(ptr.add(offset) as *const usize); + let v = *(ptr.add(offset + USIZE_BYTES) as *const usize); - if len >= 2 * usize_bytes { - while offset <= len - 2 * usize_bytes { - unsafe { - let u = *(ptr.add(offset) as *const usize); - let v = *(ptr.add(offset + usize_bytes) as *const usize); - - // break if there is a matching byte - let zu = contains_zero_byte(u ^ repeated_x); - let zv = contains_zero_byte(v ^ repeated_x); - if zu || zv { - break; - } + // break if there is a matching byte + let zu = contains_zero_byte(u ^ repeated_x); + let zv = contains_zero_byte(v ^ repeated_x); + if zu || zv { + break; } - offset += usize_bytes * 2; } + offset += USIZE_BYTES * 2; } // Find the byte after the point the body loop stopped. diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index e7eed43824..b1ca093add 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,31 +8,13 @@ #![stable(feature = "rust1", since = "1.0.0")] -// How this module is organized. -// -// The library infrastructure for slices is fairly messy. There's -// a lot of stuff defined here. Let's keep it clean. -// -// The layout of this file is thus: -// -// * Inherent methods. This is where most of the slice API resides. -// * Implementations of a few common traits with important slice ops. -// * Definitions of a bunch of iterators. -// * Free functions. -// * The `raw` and `bytes` submodules. -// * Boilerplate trait implementations. - -use crate::cmp; use crate::cmp::Ordering::{self, Equal, Greater, Less}; -use crate::fmt; -use crate::intrinsics::{assume, exact_div, is_aligned_and_not_null, unchecked_sub}; -use crate::iter::*; -use crate::marker::{self, Copy, Send, Sized, Sync}; +use crate::marker::Copy; use crate::mem; -use crate::ops::{self, FnMut, Range}; +use crate::ops::{FnMut, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; -use crate::ptr::{self, NonNull}; +use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; @@ -44,12 +26,54 @@ use crate::result::Result::{Err, Ok}; /// Pure rust memchr implementation, taken from rust-memchr pub mod memchr; +mod ascii; +mod cmp; +mod index; +mod iter; +mod raw; mod rotate; mod sort; -// -// Extension traits -// +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Chunks, ChunksMut, Windows}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Iter, IterMut}; +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, RSplitNMut, Split, SplitMut, SplitN, SplitNMut}; + +#[stable(feature = "slice_rsplit", since = "1.27.0")] +pub use iter::{RSplit, RSplitMut}; + +#[stable(feature = "chunks_exact", since = "1.31.0")] +pub use iter::{ChunksExact, ChunksExactMut}; + +#[stable(feature = "rchunks", since = "1.31.0")] +pub use iter::{RChunks, RChunksExact, RChunksExactMut, RChunksMut}; + +#[unstable(feature = "array_chunks", issue = "74985")] +pub use iter::{ArrayChunks, ArrayChunksMut}; + +#[unstable(feature = "array_windows", issue = "75027")] +pub use iter::ArrayWindows; + +#[unstable(feature = "split_inclusive", issue = "72360")] +pub use iter::{SplitInclusive, SplitInclusiveMut}; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use raw::{from_raw_parts, from_raw_parts_mut}; + +#[stable(feature = "from_ref", since = "1.28.0")] +pub use raw::{from_mut, from_ref}; + +// This function is public only because there is no other way to unit test heapsort. +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] +pub use sort::heapsort; + +#[stable(feature = "slice_get_slice", since = "1.28.0")] +pub use index::SliceIndex; + +#[unstable(feature = "slice_check_range", issue = "76393")] +pub use index::check_range; #[lang = "slice"] #[cfg(not(test))] @@ -66,7 +90,6 @@ impl [T] { #[rustc_const_stable(feature = "const_slice_len", since = "1.32.0")] #[inline] // SAFETY: const sound because we transmute out the length field as a usize (which it must be) - #[allow(unused_attributes)] #[allow_internal_unstable(const_fn_union)] pub const fn len(&self) -> usize { // SAFETY: this is safe because `&[T]` and `FatPtr` have the same layout. @@ -288,10 +311,12 @@ impl [T] { /// Returns a reference to an element or subslice, without doing bounds /// checking. /// - /// This is generally not recommended, use with caution! + /// For a safe alternative see [`get`]. + /// + /// # Safety + /// /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. - /// For a safe alternative see [`get`]. /// /// [`get`]: #method.get /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html @@ -320,10 +345,12 @@ impl [T] { /// Returns a mutable reference to an element or subslice, without doing /// bounds checking. /// - /// This is generally not recommended, use with caution! + /// For a safe alternative see [`get_mut`]. + /// + /// # Safety + /// /// Calling this method with an out-of-bounds index is *[undefined behavior]* /// even if the resulting reference is not used. - /// For a safe alternative see [`get_mut`]. /// /// [`get_mut`]: #method.get_mut /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html @@ -406,8 +433,9 @@ impl [T] { /// assert_eq!(x, &[3, 4, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_mut_ptr(&mut self) -> *mut T { + pub const fn as_mut_ptr(&mut self) -> *mut T { self as *mut [T] as *mut T } @@ -430,8 +458,6 @@ impl [T] { /// element of this slice: /// /// ``` - /// #![feature(slice_ptr_range)] - /// /// let a = [1, 2, 3]; /// let x = &a[1] as *const _; /// let y = &5 as *const _; @@ -441,9 +467,10 @@ impl [T] { /// ``` /// /// [`as_ptr`]: #method.as_ptr - #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_ptr_range(&self) -> Range<*const T> { + pub const fn as_ptr_range(&self) -> Range<*const T> { let start = self.as_ptr(); // SAFETY: The `add` here is safe, because: // @@ -482,9 +509,10 @@ impl [T] { /// common in C++. /// /// [`as_mut_ptr`]: #method.as_mut_ptr - #[unstable(feature = "slice_ptr_range", issue = "65807")] + #[stable(feature = "slice_ptr_range", since = "1.48.0")] + #[rustc_const_unstable(feature = "const_ptr_offset", issue = "71499")] #[inline] - pub fn as_mut_ptr_range(&mut self) -> Range<*mut T> { + pub const fn as_mut_ptr_range(&mut self) -> Range<*mut T> { let start = self.as_mut_ptr(); // SAFETY: See as_ptr_range() above for why `add` here is safe. let end = unsafe { start.add(self.len()) }; @@ -651,34 +679,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter(&self) -> Iter<'_, T> { - let ptr = self.as_ptr(); - // SAFETY: There are several things here: - // - // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid - // reference thus it is non-NUL and safe to use and pass to - // `NonNull::new_unchecked` . - // - // Adding `self.len()` to the starting pointer gives a pointer - // at the end of `self`. `end` will never be dereferenced, only checked - // for direct pointer equality with `ptr` to check if the iterator is - // done. - // - // In the case of a ZST, the end pointer is just the start pointer plus - // the length, to also allows for the fast `ptr == end` check. - // - // See the `next_unchecked!` and `is_empty!` macros as well as the - // `post_inc_start` method for more informations. - unsafe { - assume(!ptr.is_null()); - - let end = if mem::size_of::() == 0 { - (ptr as *const u8).wrapping_add(self.len()) as *const T - } else { - ptr.add(self.len()) - }; - - Iter { ptr: NonNull::new_unchecked(ptr as *mut T), end, _marker: marker::PhantomData } - } + Iter::new(self) } /// Returns an iterator that allows modifying each value. @@ -695,34 +696,7 @@ impl [T] { #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn iter_mut(&mut self) -> IterMut<'_, T> { - let ptr = self.as_mut_ptr(); - // SAFETY: There are several things here: - // - // `ptr` has been obtained by `self.as_ptr()` where `self` is a valid - // reference thus it is non-NUL and safe to use and pass to - // `NonNull::new_unchecked` . - // - // Adding `self.len()` to the starting pointer gives a pointer - // at the end of `self`. `end` will never be dereferenced, only checked - // for direct pointer equality with `ptr` to check if the iterator is - // done. - // - // In the case of a ZST, the end pointer is just the start pointer plus - // the length, to also allows for the fast `ptr == end` check. - // - // See the `next_unchecked!` and `is_empty!` macros as well as the - // `post_inc_start` method for more informations. - unsafe { - assume(!ptr.is_null()); - - let end = if mem::size_of::() == 0 { - (ptr as *mut u8).wrapping_add(self.len()) as *mut T - } else { - ptr.add(self.len()) - }; - - IterMut { ptr: NonNull::new_unchecked(ptr), end, _marker: marker::PhantomData } - } + IterMut::new(self) } /// Returns an iterator over all contiguous windows of length @@ -755,7 +729,7 @@ impl [T] { #[inline] pub fn windows(&self, size: usize) -> Windows<'_, T> { assert_ne!(size, 0); - Windows { v: self, size } + Windows::new(self, size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -789,7 +763,7 @@ impl [T] { #[inline] pub fn chunks(&self, chunk_size: usize) -> Chunks<'_, T> { assert_ne!(chunk_size, 0); - Chunks { v: self, chunk_size } + Chunks::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -827,7 +801,7 @@ impl [T] { #[inline] pub fn chunks_mut(&mut self, chunk_size: usize) -> ChunksMut<'_, T> { assert_ne!(chunk_size, 0); - ChunksMut { v: self, chunk_size } + ChunksMut::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -864,10 +838,7 @@ impl [T] { #[inline] pub fn chunks_exact(&self, chunk_size: usize) -> ChunksExact<'_, T> { assert_ne!(chunk_size, 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - let (fst, snd) = self.split_at(len); - ChunksExact { v: fst, rem: snd, chunk_size } + ChunksExact::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -909,18 +880,15 @@ impl [T] { #[inline] pub fn chunks_exact_mut(&mut self, chunk_size: usize) -> ChunksExactMut<'_, T> { assert_ne!(chunk_size, 0); - let rem = self.len() % chunk_size; - let len = self.len() - rem; - let (fst, snd) = self.split_at_mut(len); - ChunksExactMut { v: fst, rem: snd, chunk_size } + ChunksExactMut::new(self, chunk_size) } /// Returns an iterator over `N` elements of the slice at a time, starting at the /// beginning of the slice. /// - /// The chunks are slices and do not overlap. If `N` does not divide the length of the - /// slice, then the last up to `N-1` elements will be omitted and can be retrieved - /// from the `remainder` function of the iterator. + /// The chunks are array references and do not overlap. If `N` does not divide the + /// length of the slice, then the last up to `N-1` elements will be omitted and can be + /// retrieved from the `remainder` function of the iterator. /// /// This method is the const generic equivalent of [`chunks_exact`]. /// @@ -946,12 +914,75 @@ impl [T] { #[inline] pub fn array_chunks(&self) -> ArrayChunks<'_, T, N> { assert_ne!(N, 0); - let len = self.len() / N; - let (fst, snd) = self.split_at(len * N); - // SAFETY: We cast a slice of `len * N` elements into - // a slice of `len` many `N` elements chunks. - let array_slice: &[[T; N]] = unsafe { from_raw_parts(fst.as_ptr().cast(), len) }; - ArrayChunks { iter: array_slice.iter(), rem: snd } + ArrayChunks::new(self) + } + + /// Returns an iterator over `N` elements of the slice at a time, starting at the + /// beginning of the slice. + /// + /// The chunks are mutable array references and do not overlap. If `N` does not divide + /// the length of the slice, then the last up to `N-1` elements will be omitted and + /// can be retrieved from the `into_remainder` function of the iterator. + /// + /// This method is the const generic equivalent of [`chunks_exact_mut`]. + /// + /// # Panics + /// + /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// error before this method gets stabilized. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_chunks)] + /// let v = &mut [0, 0, 0, 0, 0]; + /// let mut count = 1; + /// + /// for chunk in v.array_chunks_mut() { + /// *chunk = [count; 2]; + /// count += 1; + /// } + /// assert_eq!(v, &[1, 1, 2, 2, 0]); + /// ``` + /// + /// [`chunks_exact_mut`]: #method.chunks_exact_mut + #[unstable(feature = "array_chunks", issue = "74985")] + #[inline] + pub fn array_chunks_mut(&mut self) -> ArrayChunksMut<'_, T, N> { + assert_ne!(N, 0); + ArrayChunksMut::new(self) + } + + /// Returns an iterator over overlapping windows of `N` elements of a slice, + /// starting at the beginning of the slice. + /// + /// This is the const generic equivalent of [`windows`]. + /// + /// If `N` is greater than the size of the slice, it will return no windows. + /// + /// # Panics + /// + /// Panics if `N` is 0. This check will most probably get changed to a compile time + /// error before this method gets stabilized. + /// + /// # Examples + /// + /// ``` + /// #![feature(array_windows)] + /// let slice = [0, 1, 2, 3]; + /// let mut iter = slice.array_windows(); + /// assert_eq!(iter.next().unwrap(), &[0, 1]); + /// assert_eq!(iter.next().unwrap(), &[1, 2]); + /// assert_eq!(iter.next().unwrap(), &[2, 3]); + /// assert!(iter.next().is_none()); + /// ``` + /// + /// [`windows`]: #method.windows + #[unstable(feature = "array_windows", issue = "75027")] + #[inline] + pub fn array_windows(&self) -> ArrayWindows<'_, T, N> { + assert_ne!(N, 0); + ArrayWindows::new(self) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -985,7 +1016,7 @@ impl [T] { #[inline] pub fn rchunks(&self, chunk_size: usize) -> RChunks<'_, T> { assert!(chunk_size != 0); - RChunks { v: self, chunk_size } + RChunks::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1023,7 +1054,7 @@ impl [T] { #[inline] pub fn rchunks_mut(&mut self, chunk_size: usize) -> RChunksMut<'_, T> { assert!(chunk_size != 0); - RChunksMut { v: self, chunk_size } + RChunksMut::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the @@ -1062,9 +1093,7 @@ impl [T] { #[inline] pub fn rchunks_exact(&self, chunk_size: usize) -> RChunksExact<'_, T> { assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let (fst, snd) = self.split_at(rem); - RChunksExact { v: snd, rem: fst, chunk_size } + RChunksExact::new(self, chunk_size) } /// Returns an iterator over `chunk_size` elements of the slice at a time, starting at the end @@ -1107,9 +1136,7 @@ impl [T] { #[inline] pub fn rchunks_exact_mut(&mut self, chunk_size: usize) -> RChunksExactMut<'_, T> { assert!(chunk_size != 0); - let rem = self.len() % chunk_size; - let (fst, snd) = self.split_at_mut(rem); - RChunksExactMut { v: snd, rem: fst, chunk_size } + RChunksExactMut::new(self, chunk_size) } /// Divides one slice into two at an index. @@ -1129,26 +1156,29 @@ impl [T] { /// /// { /// let (left, right) = v.split_at(0); - /// assert!(left == []); - /// assert!(right == [1, 2, 3, 4, 5, 6]); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); /// } /// /// { /// let (left, right) = v.split_at(2); - /// assert!(left == [1, 2]); - /// assert!(right == [3, 4, 5, 6]); + /// assert_eq!(left, [1, 2]); + /// assert_eq!(right, [3, 4, 5, 6]); /// } /// /// { /// let (left, right) = v.split_at(6); - /// assert!(left == [1, 2, 3, 4, 5, 6]); - /// assert!(right == []); + /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, []); /// } /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at(&self, mid: usize) -> (&[T], &[T]) { - (&self[..mid], &self[mid..]) + assert!(mid <= self.len()); + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `from_raw_parts_mut`. + unsafe { self.split_at_unchecked(mid) } } /// Divides one mutable slice into two at an index. @@ -1168,26 +1198,115 @@ impl [T] { /// // scoped to restrict the lifetime of the borrows /// { /// let (left, right) = v.split_at_mut(2); - /// assert!(left == [1, 0]); - /// assert!(right == [3, 0, 5, 6]); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); /// left[1] = 2; /// right[1] = 4; /// } - /// assert!(v == [1, 2, 3, 4, 5, 6]); + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); /// ``` #[stable(feature = "rust1", since = "1.0.0")] #[inline] pub fn split_at_mut(&mut self, mid: usize) -> (&mut [T], &mut [T]) { + assert!(mid <= self.len()); + // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which + // fulfills the requirements of `from_raw_parts_mut`. + unsafe { self.split_at_mut_unchecked(mid) } + } + + /// Divides one slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at`]: #method.split_at + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ```compile_fail + /// #![feature(slice_split_at_unchecked)] + /// + /// let v = [1, 2, 3, 4, 5, 6]; + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(0); + /// assert_eq!(left, []); + /// assert_eq!(right, [1, 2, 3, 4, 5, 6]); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(2); + /// assert_eq!(left, [1, 2]); + /// assert_eq!(right, [3, 4, 5, 6]); + /// } + /// + /// unsafe { + /// let (left, right) = v.split_at_unchecked(6); + /// assert_eq!(left, [1, 2, 3, 4, 5, 6]); + /// assert_eq!(right, []); + /// } + /// ``` + #[unstable(feature = "slice_split_at_unchecked", reason = "new API", issue = "76014")] + #[inline] + 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..)) } + } + + /// Divides one mutable slice into two at an index, without doing bounds checking. + /// + /// The first will contain all indices from `[0, mid)` (excluding + /// the index `mid` itself) and the second will contain all + /// indices from `[mid, len)` (excluding the index `len` itself). + /// + /// For a safe alternative see [`split_at_mut`]. + /// + /// # Safety + /// + /// Calling this method with an out-of-bounds index is *[undefined behavior]* + /// even if the resulting reference is not used. The caller has to ensure that + /// `0 <= mid <= self.len()`. + /// + /// [`split_at_mut`]: #method.split_at_mut + /// [undefined behavior]: https://doc.rust-lang.org/reference/behavior-considered-undefined.html + /// + /// # Examples + /// + /// ```compile_fail + /// #![feature(slice_split_at_unchecked)] + /// + /// let mut v = [1, 0, 3, 0, 5, 6]; + /// // scoped to restrict the lifetime of the borrows + /// unsafe { + /// let (left, right) = v.split_at_mut_unchecked(2); + /// assert_eq!(left, [1, 0]); + /// assert_eq!(right, [3, 0, 5, 6]); + /// left[1] = 2; + /// right[1] = 4; + /// } + /// assert_eq!(v, [1, 2, 3, 4, 5, 6]); + /// ``` + #[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]) { let len = self.len(); let ptr = self.as_mut_ptr(); - // SAFETY: `[ptr; mid]` and `[mid; len]` are inside `self`, which - // fulfills the requirements of `from_raw_parts_mut`. - unsafe { - assert!(mid <= len); - - (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) - } + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. + // + // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference + // is fine. + unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } /// Returns an iterator over subslices separated by elements that match @@ -1236,7 +1355,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - Split { v: self, pred, finished: false } + Split::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1258,7 +1377,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitMut { v: self, pred, finished: false } + SplitMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1296,7 +1415,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusive { v: self, pred, finished: false } + SplitInclusive::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1321,7 +1440,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitInclusiveMut { v: self, pred, finished: false } + SplitInclusiveMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1357,7 +1476,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplit { inner: self.split(pred) } + RSplit::new(self, pred) } /// Returns an iterator over mutable subslices separated by elements that @@ -1383,7 +1502,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitMut { inner: self.split_mut(pred) } + RSplitMut::new(self, pred) } /// Returns an iterator over subslices separated by elements that match @@ -1411,7 +1530,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitN { inner: GenericSplitN { iter: self.split(pred), count: n } } + SplitN::new(self.split(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1437,7 +1556,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - SplitNMut { inner: GenericSplitN { iter: self.split_mut(pred), count: n } } + SplitNMut::new(self.split_mut(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1466,7 +1585,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitN { inner: GenericSplitN { iter: self.rsplit(pred), count: n } } + RSplitN::new(self.rsplit(pred), n) } /// Returns an iterator over subslices separated by elements that match @@ -1493,7 +1612,7 @@ impl [T] { where F: FnMut(&T) -> bool, { - RSplitNMut { inner: GenericSplitN { iter: self.rsplit_mut(pred), count: n } } + RSplitNMut::new(self.rsplit_mut(pred), n) } /// Returns `true` if the slice contains an element with the given value. @@ -1515,11 +1634,12 @@ impl [T] { /// assert!(!v.iter().any(|e| e == "hi")); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn contains(&self, x: &T) -> bool where T: PartialEq, { - x.slice_contains(self) + cmp::SliceContains::slice_contains(x, self) } /// Returns `true` if `needle` is a prefix of the slice. @@ -2551,26 +2671,11 @@ impl [T] { /// ``` #[stable(feature = "copy_within", since = "1.37.0")] #[track_caller] - pub fn copy_within>(&mut self, src: R, dest: usize) + pub fn copy_within>(&mut self, src: R, dest: usize) where T: Copy, { - let src_start = match src.start_bound() { - ops::Bound::Included(&n) => n, - ops::Bound::Excluded(&n) => { - n.checked_add(1).unwrap_or_else(|| slice_index_overflow_fail()) - } - ops::Bound::Unbounded => 0, - }; - let src_end = match src.end_bound() { - ops::Bound::Included(&n) => { - n.checked_add(1).unwrap_or_else(|| slice_index_overflow_fail()) - } - ops::Bound::Excluded(&n) => n, - ops::Bound::Unbounded => self.len(), - }; - assert!(src_start <= src_end, "src end is before src start"); - assert!(src_end <= self.len(), "src is out of bounds"); + let Range { start: src_start, end: src_end } = check_range(self.len(), src); let count = src_end - src_start; assert!(dest <= self.len() - count, "dest is out of bounds"); // SAFETY: the conditions for `ptr::copy` have all been checked above, @@ -2958,606 +3063,6 @@ impl [T] { } } -#[lang = "slice_u8"] -#[cfg(not(test))] -impl [u8] { - /// Checks if all bytes in this slice are within the ASCII range. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn is_ascii(&self) -> bool { - is_ascii(self) - } - - /// Checks that two slices are an ASCII case-insensitive match. - /// - /// Same as `to_ascii_lowercase(a) == to_ascii_lowercase(b)`, - /// but without allocating and copying temporaries. - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn eq_ignore_ascii_case(&self, other: &[u8]) -> bool { - self.len() == other.len() && self.iter().zip(other).all(|(a, b)| a.eq_ignore_ascii_case(b)) - } - - /// Converts this slice to its ASCII upper case equivalent in-place. - /// - /// ASCII letters 'a' to 'z' are mapped to 'A' to 'Z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new uppercased value without modifying the existing one, use - /// [`to_ascii_uppercase`]. - /// - /// [`to_ascii_uppercase`]: #method.to_ascii_uppercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_uppercase(&mut self) { - for byte in self { - byte.make_ascii_uppercase(); - } - } - - /// Converts this slice to its ASCII lower case equivalent in-place. - /// - /// ASCII letters 'A' to 'Z' are mapped to 'a' to 'z', - /// but non-ASCII letters are unchanged. - /// - /// To return a new lowercased value without modifying the existing one, use - /// [`to_ascii_lowercase`]. - /// - /// [`to_ascii_lowercase`]: #method.to_ascii_lowercase - #[stable(feature = "ascii_methods_on_intrinsics", since = "1.23.0")] - #[inline] - pub fn make_ascii_lowercase(&mut self) { - for byte in self { - byte.make_ascii_lowercase(); - } - } -} - -/// Returns `true` if any byte in the word `v` is nonascii (>= 128). Snarfed -/// from `../str/mod.rs`, which does something similar for utf8 validation. -#[inline] -fn contains_nonascii(v: usize) -> bool { - const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; - (NONASCII_MASK & v) != 0 -} - -/// Optimized ASCII test that will use usize-at-a-time operations instead of -/// byte-at-a-time operations (when possible). -/// -/// The algorithm we use here is pretty simple. If `s` is too short, we just -/// check each byte and be done with it. Otherwise: -/// -/// - Read the first word with an unaligned load. -/// - Align the pointer, read subsequent words until end with aligned loads. -/// - Read the last `usize` from `s` with an unaligned load. -/// -/// If any of these loads produces something for which `contains_nonascii` -/// (above) returns true, then we know the answer is false. -#[inline] -fn is_ascii(s: &[u8]) -> bool { - const USIZE_SIZE: usize = mem::size_of::(); - - let len = s.len(); - let align_offset = s.as_ptr().align_offset(USIZE_SIZE); - - // If we wouldn't gain anything from the word-at-a-time implementation, fall - // back to a scalar loop. - // - // We also do this for architectures where `size_of::()` isn't - // sufficient alignment for `usize`, because it's a weird edge case. - if len < USIZE_SIZE || len < align_offset || USIZE_SIZE < mem::align_of::() { - return s.iter().all(|b| b.is_ascii()); - } - - // We always read the first word unaligned, which means `align_offset` is - // 0, we'd read the same value again for the aligned read. - let offset_to_aligned = if align_offset == 0 { USIZE_SIZE } else { align_offset }; - - let start = s.as_ptr(); - // SAFETY: We verify `len < USIZE_SIZE` above. - let first_word = unsafe { (start as *const usize).read_unaligned() }; - - if contains_nonascii(first_word) { - return false; - } - // We checked this above, somewhat implicitly. Note that `offset_to_aligned` - // is either `align_offset` or `USIZE_SIZE`, both of are explicitly checked - // above. - debug_assert!(offset_to_aligned <= len); - - // SAFETY: word_ptr is the (properly aligned) usize ptr we use to read the - // middle chunk of the slice. - let mut word_ptr = unsafe { start.add(offset_to_aligned) as *const usize }; - - // `byte_pos` is the byte index of `word_ptr`, used for loop end checks. - let mut byte_pos = offset_to_aligned; - - // Paranoia check about alignment, since we're about to do a bunch of - // unaligned loads. In practice this should be impossible barring a bug in - // `align_offset` though. - debug_assert_eq!((word_ptr as usize) % mem::align_of::(), 0); - - // Read subsequent words until the last aligned word, excluding the last - // aligned word by itself to be done in tail check later, to ensure that - // tail is always one `usize` at most to extra branch `byte_pos == len`. - while byte_pos < len - USIZE_SIZE { - debug_assert!( - // Sanity check that the read is in bounds - (word_ptr as usize + USIZE_SIZE) <= (start.wrapping_add(len) as usize) && - // And that our assumptions about `byte_pos` hold. - (word_ptr as usize) - (start as usize) == byte_pos - ); - - // Safety: We know `word_ptr` is properly aligned (because of - // `align_offset`), and we know that we have enough bytes between `word_ptr` and the end - let word = unsafe { word_ptr.read() }; - if contains_nonascii(word) { - return false; - } - - byte_pos += USIZE_SIZE; - // SAFETY: We know that `byte_pos <= len - USIZE_SIZE`, which means that - // after this `add`, `word_ptr` will be at most one-past-the-end. - word_ptr = unsafe { word_ptr.add(1) }; - } - - // Sanity check to ensure there really is only one `usize` left. This should - // be guaranteed by our loop condition. - debug_assert!(byte_pos <= len && len - byte_pos <= USIZE_SIZE); - - // SAFETY: This relies on `len >= USIZE_SIZE`, which we check at the start. - let last_word = unsafe { (start.add(len - USIZE_SIZE) as *const usize).read_unaligned() }; - - !contains_nonascii(last_word) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::Index for [T] -where - I: SliceIndex<[T]>, -{ - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &I::Output { - index.index(self) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ops::IndexMut for [T] -where - I: SliceIndex<[T]>, -{ - #[inline] - fn index_mut(&mut self, index: I) -> &mut I::Output { - index.index_mut(self) - } -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_start_index_len_fail(index: usize, len: usize) -> ! { - panic!("range start index {} out of range for slice of length {}", index, len); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_end_index_len_fail(index: usize, len: usize) -> ! { - panic!("range end index {} out of range for slice of length {}", index, len); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_index_order_fail(index: usize, end: usize) -> ! { - panic!("slice index starts at {} but ends at {}", index, end); -} - -#[inline(never)] -#[cold] -#[track_caller] -fn slice_index_overflow_fail() -> ! { - panic!("attempted to index slice up to maximum usize"); -} - -mod private_slice_index { - use super::ops; - #[stable(feature = "slice_get_slice", since = "1.28.0")] - pub trait Sealed {} - - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for usize {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::Range {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeTo {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeFrom {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeFull {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeInclusive {} - #[stable(feature = "slice_get_slice", since = "1.28.0")] - impl Sealed for ops::RangeToInclusive {} -} - -/// A helper trait used for indexing operations. -/// -/// Implementations of this trait have to promise that if the argument -/// to `get_(mut_)unchecked` is a safe reference, then so is the result. -#[stable(feature = "slice_get_slice", since = "1.28.0")] -#[rustc_on_unimplemented( - on(T = "str", label = "string indices are ranges of `usize`",), - on( - all(any(T = "str", T = "&str", T = "std::string::String"), _Self = "{integer}"), - note = "you can use `.chars().nth()` or `.bytes().nth()` -see chapter in The Book " - ), - message = "the type `{T}` cannot be indexed by `{Self}`", - label = "slice indices are of type `usize` or ranges of `usize`" -)] -pub unsafe trait SliceIndex: private_slice_index::Sealed { - /// The output type returned by methods. - #[stable(feature = "slice_get_slice", since = "1.28.0")] - type Output: ?Sized; - - /// Returns a shared reference to the output at this location, if in - /// bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - fn get(self, slice: &T) -> Option<&Self::Output>; - - /// Returns a mutable reference to the output at this location, if in - /// bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - fn get_mut(self, slice: &mut T) -> Option<&mut Self::Output>; - - /// Returns a shared reference to the output at this location, without - /// performing any bounds checking. - /// Calling this method with an out-of-bounds index or a dangling `slice` pointer - /// is *[undefined behavior]* even if the resulting reference is not used. - /// - /// [undefined behavior]: ../../reference/behavior-considered-undefined.html - #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked(self, slice: *const T) -> *const Self::Output; - - /// Returns a mutable reference to the output at this location, without - /// performing any bounds checking. - /// Calling this method with an out-of-bounds index or a dangling `slice` pointer - /// is *[undefined behavior]* even if the resulting reference is not used. - /// - /// [undefined behavior]: ../../reference/behavior-considered-undefined.html - #[unstable(feature = "slice_index_methods", issue = "none")] - unsafe fn get_unchecked_mut(self, slice: *mut T) -> *mut Self::Output; - - /// Returns a shared reference to the output at this location, panicking - /// if out of bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - #[track_caller] - fn index(self, slice: &T) -> &Self::Output; - - /// Returns a mutable reference to the output at this location, panicking - /// if out of bounds. - #[unstable(feature = "slice_index_methods", issue = "none")] - #[track_caller] - fn index_mut(self, slice: &mut T) -> &mut Self::Output; -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for usize { - type Output = T; - - #[inline] - fn get(self, slice: &[T]) -> Option<&T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&*self.get_unchecked(slice)) } } else { None } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut T> { - // SAFETY: `self` is checked to be in bounds. - if self < slice.len() { unsafe { Some(&mut *self.get_unchecked_mut(slice)) } } else { None } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { - // SAFETY: the caller guarantees that `slice` is not dangling, so it - // cannot be longer than `isize::MAX`. They also guarantee that - // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, - // so the call to `add` is safe. - unsafe { slice.as_ptr().add(self) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { - // SAFETY: see comments for `get_unchecked` above. - unsafe { slice.as_mut_ptr().add(self) } - } - - #[inline] - fn index(self, slice: &[T]) -> &T { - // N.B., use intrinsic indexing - &(*slice)[self] - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut T { - // N.B., use intrinsic indexing - &mut (*slice)[self] - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::Range { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&*self.get_unchecked(slice)) } - } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if self.start > self.end || self.end > slice.len() { - None - } else { - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { Some(&mut *self.get_unchecked_mut(slice)) } - } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller guarantees that `slice` is not dangling, so it - // cannot be longer than `isize::MAX`. They also guarantee that - // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, - // so the call to `add` is safe. - unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), self.end - self.start) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: see comments for `get_unchecked` above. - unsafe { - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), self.end - self.start) - } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > self.end { - slice_index_order_fail(self.start, self.end); - } else if self.end > slice.len() { - slice_end_index_len_fail(self.end, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeTo { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (0..self.end).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (0..self.end).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (0..self.end).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (0..self.end).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - (0..self.end).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - (0..self.end).index_mut(slice) - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFrom { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (self.start..slice.len()).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (self.start..slice.len()).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (self.start..slice.len()).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (self.start..slice.len()).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &*self.get_unchecked(slice) } - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if self.start > slice.len() { - slice_start_index_len_fail(self.start, slice.len()); - } - // SAFETY: `self` is checked to be valid and in bounds above. - unsafe { &mut *self.get_unchecked_mut(slice) } - } -} - -#[stable(feature = "slice_get_slice_impls", since = "1.15.0")] -unsafe impl SliceIndex<[T]> for ops::RangeFull { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - Some(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - Some(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - slice - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - slice - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - slice - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - slice - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeInclusive { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get_mut(slice) - } - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - if *self.end() == usize::MAX { - slice_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - if *self.end() == usize::MAX { - slice_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index_mut(slice) - } -} - -#[stable(feature = "inclusive_range", since = "1.26.0")] -unsafe impl SliceIndex<[T]> for ops::RangeToInclusive { - type Output = [T]; - - #[inline] - fn get(self, slice: &[T]) -> Option<&[T]> { - (0..=self.end).get(slice) - } - - #[inline] - fn get_mut(self, slice: &mut [T]) -> Option<&mut [T]> { - (0..=self.end).get_mut(slice) - } - - #[inline] - unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked`. - unsafe { (0..=self.end).get_unchecked(slice) } - } - - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - // SAFETY: the caller has to uphold the safety contract for `get_unchecked_mut`. - unsafe { (0..=self.end).get_unchecked_mut(slice) } - } - - #[inline] - fn index(self, slice: &[T]) -> &[T] { - (0..=self.end).index(slice) - } - - #[inline] - fn index_mut(self, slice: &mut [T]) -> &mut [T] { - (0..=self.end).index_mut(slice) - } -} - -//////////////////////////////////////////////////////////////////////////////// -// Common traits -//////////////////////////////////////////////////////////////////////////////// - #[stable(feature = "rust1", since = "1.0.0")] impl Default for &[T] { /// Creates an empty slice. @@ -3573,3240 +3078,3 @@ impl Default for &mut [T] { &mut [] } } - -// -// Iterators -// - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a [T] { - type Item = &'a T; - type IntoIter = Iter<'a, T>; - - fn into_iter(self) -> Iter<'a, T> { - self.iter() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> IntoIterator for &'a mut [T] { - type Item = &'a mut T; - type IntoIter = IterMut<'a, T>; - - fn into_iter(self) -> IterMut<'a, T> { - self.iter_mut() - } -} - -// Macro helper functions -#[inline(always)] -fn size_from_ptr(_: *const T) -> usize { - mem::size_of::() -} - -// Inlining is_empty and len makes a huge performance difference -macro_rules! is_empty { - // The way we encode the length of a ZST iterator, this works both for ZST - // and non-ZST. - ($self: ident) => { - $self.ptr.as_ptr() as *const T == $self.end - }; -} - -// To get rid of some bounds checks (see `position`), we compute the length in a somewhat -// unexpected way. (Tested by `codegen/slice-position-bounds-check`.) -macro_rules! len { - ($self: ident) => {{ - #![allow(unused_unsafe)] // we're sometimes used within an unsafe block - - let start = $self.ptr; - let size = size_from_ptr(start.as_ptr()); - if size == 0 { - // This _cannot_ use `unchecked_sub` because we depend on wrapping - // to represent the length of long ZST slice iterators. - ($self.end as usize).wrapping_sub(start.as_ptr() as usize) - } else { - // We know that `start <= end`, so can do better than `offset_from`, - // which needs to deal in signed. By setting appropriate flags here - // we can tell LLVM this, which helps it remove bounds checks. - // SAFETY: By the type invariant, `start <= end` - let diff = unsafe { unchecked_sub($self.end as usize, start.as_ptr() as usize) }; - // By also telling LLVM that the pointers are apart by an exact - // multiple of the type size, it can optimize `len() == 0` down to - // `start == end` instead of `(end - start) < size`. - // SAFETY: By the type invariant, the pointers are aligned so the - // distance between them must be a multiple of pointee size - unsafe { exact_div(diff, size) } - } - }}; -} - -// The shared definition of the `Iter` and `IterMut` iterators -macro_rules! iterator { - ( - struct $name:ident -> $ptr:ty, - $elem:ty, - $raw_mut:tt, - {$( $mut_:tt )?}, - {$($extra:tt)*} - ) => { - // Returns the first element and moves the start of the iterator forwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_unchecked { - ($self: ident) => {& $( $mut_ )? *$self.post_inc_start(1)} - } - - // Returns the last element and moves the end of the iterator backwards by 1. - // Greatly improves performance compared to an inlined function. The iterator - // must not be empty. - macro_rules! next_back_unchecked { - ($self: ident) => {& $( $mut_ )? *$self.pre_dec_end(1)} - } - - // Shrinks the iterator when T is a ZST, by moving the end of the iterator - // backwards by `n`. `n` must not exceed `self.len()`. - macro_rules! zst_shrink { - ($self: ident, $n: ident) => { - $self.end = ($self.end as * $raw_mut u8).wrapping_offset(-$n) as * $raw_mut T; - } - } - - impl<'a, T> $name<'a, T> { - // Helper function for creating a slice from the iterator. - #[inline(always)] - fn make_slice(&self) -> &'a [T] { - // SAFETY: the iterator was created from a slice with pointer - // `self.ptr` and length `len!(self)`. This guarantees that all - // the prerequisites for `from_raw_parts` are fulfilled. - unsafe { from_raw_parts(self.ptr.as_ptr(), len!(self)) } - } - - // Helper function for moving the start of the iterator forwards by `offset` elements, - // returning the old start. - // Unsafe because the offset must not exceed `self.len()`. - #[inline(always)] - unsafe fn post_inc_start(&mut self, offset: isize) -> * $raw_mut T { - if mem::size_of::() == 0 { - zst_shrink!(self, offset); - self.ptr.as_ptr() - } else { - let old = self.ptr.as_ptr(); - // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, - // so this new pointer is inside `self` and thus guaranteed to be non-null. - self.ptr = unsafe { NonNull::new_unchecked(self.ptr.as_ptr().offset(offset)) }; - old - } - } - - // Helper function for moving the end of the iterator backwards by `offset` elements, - // returning the new end. - // Unsafe because the offset must not exceed `self.len()`. - #[inline(always)] - unsafe fn pre_dec_end(&mut self, offset: isize) -> * $raw_mut T { - if mem::size_of::() == 0 { - zst_shrink!(self, offset); - self.ptr.as_ptr() - } else { - // SAFETY: the caller guarantees that `offset` doesn't exceed `self.len()`, - // which is guaranteed to not overflow an `isize`. Also, the resulting pointer - // is in bounds of `slice`, which fulfills the other requirements for `offset`. - self.end = unsafe { self.end.offset(-offset) }; - self.end - } - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ExactSizeIterator for $name<'_, T> { - #[inline(always)] - fn len(&self) -> usize { - len!(self) - } - - #[inline(always)] - fn is_empty(&self) -> bool { - is_empty!(self) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> Iterator for $name<'a, T> { - type Item = $elem; - - #[inline] - fn next(&mut self) -> Option<$elem> { - // could be implemented with slices, but this avoids bounds checks - - // SAFETY: `assume` calls are safe since a slice's start pointer - // must be non-null, and slices over non-ZSTs must also have a - // non-null end pointer. The call to `next_unchecked!` is safe - // since we check if the iterator is empty first. - unsafe { - assume(!self.ptr.as_ptr().is_null()); - if mem::size_of::() != 0 { - assume(!self.end.is_null()); - } - if is_empty!(self) { - None - } else { - Some(next_unchecked!(self)) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let exact = len!(self); - (exact, Some(exact)) - } - - #[inline] - fn count(self) -> usize { - len!(self) - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<$elem> { - if n >= len!(self) { - // This iterator is now empty. - if mem::size_of::() == 0 { - // We have to do it this way as `ptr` may never be 0, but `end` - // could be (due to wrapping). - self.end = self.ptr.as_ptr(); - } else { - // SAFETY: end can't be 0 if T isn't ZST because ptr isn't 0 and end >= ptr - unsafe { - self.ptr = NonNull::new_unchecked(self.end as *mut T); - } - } - return None; - } - // SAFETY: We are in bounds. `post_inc_start` does the right thing even for ZSTs. - unsafe { - self.post_inc_start(n as isize); - Some(next_unchecked!(self)) - } - } - - #[inline] - fn last(mut self) -> Option<$elem> { - self.next_back() - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn for_each(mut self, mut f: F) - where - Self: Sized, - F: FnMut(Self::Item), - { - while let Some(x) = self.next() { - f(x); - } - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn all(&mut self, mut f: F) -> bool - where - Self: Sized, - F: FnMut(Self::Item) -> bool, - { - while let Some(x) = self.next() { - if !f(x) { - return false; - } - } - true - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn any(&mut self, mut f: F) -> bool - where - Self: Sized, - F: FnMut(Self::Item) -> bool, - { - while let Some(x) = self.next() { - if f(x) { - return true; - } - } - false - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn find

(&mut self, mut predicate: P) -> Option - where - Self: Sized, - P: FnMut(&Self::Item) -> bool, - { - while let Some(x) = self.next() { - if predicate(&x) { - return Some(x); - } - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. - #[inline] - fn find_map(&mut self, mut f: F) -> Option - where - Self: Sized, - F: FnMut(Self::Item) -> Option, - { - while let Some(x) = self.next() { - if let Some(y) = f(x) { - return Some(y); - } - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. Also, the `assume` avoids a bounds check. - #[inline] - #[rustc_inherit_overflow_checks] - fn position

(&mut self, mut predicate: P) -> Option where - Self: Sized, - P: FnMut(Self::Item) -> bool, - { - let n = len!(self); - let mut i = 0; - while let Some(x) = self.next() { - if predicate(x) { - // SAFETY: we are guaranteed to be in bounds by the loop invariant: - // when `i >= n`, `self.next()` returns `None` and the loop breaks. - unsafe { assume(i < n) }; - return Some(i); - } - i += 1; - } - None - } - - // We override the default implementation, which uses `try_fold`, - // because this simple implementation generates less LLVM IR and is - // faster to compile. Also, the `assume` avoids a bounds check. - #[inline] - fn rposition

(&mut self, mut predicate: P) -> Option where - P: FnMut(Self::Item) -> bool, - Self: Sized + ExactSizeIterator + DoubleEndedIterator - { - let n = len!(self); - let mut i = n; - while let Some(x) = self.next_back() { - i -= 1; - if predicate(x) { - // SAFETY: `i` must be lower than `n` since it starts at `n` - // and is only decreasing. - unsafe { assume(i < n) }; - return Some(i); - } - } - None - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - // SAFETY: the caller must guarantee that `i` is in bounds of - // the underlying slice, so `i` cannot overflow an `isize`, and - // the returned references is guaranteed to refer to an element - // of the slice and thus guaranteed to be valid. - // - // Also note that the caller also guarantees that we're never - // called with the same index again, and that no other methods - // that will access this subslice are called, so it is valid - // for the returned reference to be mutable in the case of - // `IterMut` - unsafe { & $( $mut_ )? * self.ptr.as_ptr().add(idx) } - } - - $($extra)* - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, T> DoubleEndedIterator for $name<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<$elem> { - // could be implemented with slices, but this avoids bounds checks - - // SAFETY: `assume` calls are safe since a slice's start pointer must be non-null, - // and slices over non-ZSTs must also have a non-null end pointer. - // The call to `next_back_unchecked!` is safe since we check if the iterator is - // empty first. - unsafe { - assume(!self.ptr.as_ptr().is_null()); - if mem::size_of::() != 0 { - assume(!self.end.is_null()); - } - if is_empty!(self) { - None - } else { - Some(next_back_unchecked!(self)) - } - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option<$elem> { - if n >= len!(self) { - // This iterator is now empty. - self.end = self.ptr.as_ptr(); - return None; - } - // SAFETY: We are in bounds. `pre_dec_end` does the right thing even for ZSTs. - unsafe { - self.pre_dec_end(n as isize); - Some(next_back_unchecked!(self)) - } - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl FusedIterator for $name<'_, T> {} - - #[unstable(feature = "trusted_len", issue = "37572")] - unsafe impl TrustedLen for $name<'_, T> {} - } -} - -/// Immutable slice iterator -/// -/// This struct is created by the [`iter`] method on [slices]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // First, we declare a type which has `iter` method to get the `Iter` struct (&[usize here]): -/// let slice = &[1, 2, 3]; -/// -/// // Then, we iterate over it: -/// for element in slice.iter() { -/// println!("{}", element); -/// } -/// ``` -/// -/// [`iter`]: ../../std/primitive.slice.html#method.iter -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Iter<'a, T: 'a> { - ptr: NonNull, - end: *const T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that - // ptr == end is a quick test for the Iterator being empty, that works - // for both ZST and non-ZST. - _marker: marker::PhantomData<&'a T>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Iter<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("Iter").field(&self.as_slice()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for Iter<'_, T> {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for Iter<'_, T> {} - -impl<'a, T> Iter<'a, T> { - /// Views the underlying data as a subslice of the original data. - /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // First, we declare a type which has the `iter` method to get the `Iter` - /// // struct (&[usize here]): - /// let slice = &[1, 2, 3]; - /// - /// // Then, we get the iterator: - /// let mut iter = slice.iter(); - /// // So if we print what `as_slice` method returns here, we have "[1, 2, 3]": - /// println!("{:?}", iter.as_slice()); - /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// println!("{:?}", iter.as_slice()); - /// ``` - #[stable(feature = "iter_to_slice", since = "1.4.0")] - pub fn as_slice(&self) -> &'a [T] { - self.make_slice() - } -} - -iterator! {struct Iter -> *const T, &'a T, const, {/* no mut */}, { - fn is_sorted_by(self, mut compare: F) -> bool - where - Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Option, - { - self.as_slice().windows(2).all(|w| { - compare(&&w[0], &&w[1]).map(|o| o != Ordering::Greater).unwrap_or(false) - }) - } -}} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Iter<'_, T> { - fn clone(&self) -> Self { - Iter { ptr: self.ptr, end: self.end, _marker: self._marker } - } -} - -#[stable(feature = "slice_iter_as_ref", since = "1.13.0")] -impl AsRef<[T]> for Iter<'_, T> { - fn as_ref(&self) -> &[T] { - self.as_slice() - } -} - -/// Mutable slice iterator. -/// -/// This struct is created by the [`iter_mut`] method on [slices]. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// // First, we declare a type which has `iter_mut` method to get the `IterMut` -/// // struct (&[usize here]): -/// let mut slice = &mut [1, 2, 3]; -/// -/// // Then, we iterate over it and increment each element value: -/// for element in slice.iter_mut() { -/// *element += 1; -/// } -/// -/// // We now have "[2, 3, 4]": -/// println!("{:?}", slice); -/// ``` -/// -/// [`iter_mut`]: ../../std/primitive.slice.html#method.iter_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct IterMut<'a, T: 'a> { - ptr: NonNull, - end: *mut T, // If T is a ZST, this is actually ptr+len. This encoding is picked so that - // ptr == end is a quick test for the Iterator being empty, that works - // for both ZST and non-ZST. - _marker: marker::PhantomData<&'a mut T>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for IterMut<'_, T> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("IterMut").field(&self.make_slice()).finish() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Sync for IterMut<'_, T> {} -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl Send for IterMut<'_, T> {} - -impl<'a, T> IterMut<'a, T> { - /// Views the underlying data as a subslice of the original data. - /// - /// To avoid creating `&mut` references that alias, this is forced - /// to consume the iterator. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// // First, we declare a type which has `iter_mut` method to get the `IterMut` - /// // struct (&[usize here]): - /// let mut slice = &mut [1, 2, 3]; - /// - /// { - /// // Then, we get the iterator: - /// let mut iter = slice.iter_mut(); - /// // We move to next element: - /// iter.next(); - /// // So if we print what `into_slice` method returns here, we have "[2, 3]": - /// println!("{:?}", iter.into_slice()); - /// } - /// - /// // Now let's modify a value of the slice: - /// { - /// // First we get back the iterator: - /// let mut iter = slice.iter_mut(); - /// // We change the value of the first element of the slice returned by the `next` method: - /// *iter.next().unwrap() += 1; - /// } - /// // Now slice is "[2, 2, 3]": - /// println!("{:?}", slice); - /// ``` - #[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 - // `self.ptr` and length `len!(self)`. This guarantees that all the prerequisites - // for `from_raw_parts_mut` are fulfilled. - unsafe { from_raw_parts_mut(self.ptr.as_ptr(), len!(self)) } - } - - /// Views the underlying data as a subslice of the original data. - /// - /// To avoid creating `&mut [T]` references that alias, the returned slice - /// borrows its lifetime from the iterator the method is applied on. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// # #![feature(slice_iter_mut_as_slice)] - /// let mut slice: &mut [usize] = &mut [1, 2, 3]; - /// - /// // First, we get the iterator: - /// let mut iter = slice.iter_mut(); - /// // So if we check what the `as_slice` method returns here, we have "[1, 2, 3]": - /// assert_eq!(iter.as_slice(), &[1, 2, 3]); - /// - /// // Next, we move to the second element of the slice: - /// iter.next(); - /// // Now `as_slice` returns "[2, 3]": - /// assert_eq!(iter.as_slice(), &[2, 3]); - /// ``` - #[unstable(feature = "slice_iter_mut_as_slice", reason = "recently added", issue = "58957")] - pub fn as_slice(&self) -> &[T] { - self.make_slice() - } -} - -iterator! {struct IterMut -> *mut T, &'a mut T, mut, {mut}, {}} - -/// An internal abstraction over the splitting iterators, so that -/// splitn, splitn_mut etc can be implemented once. -#[doc(hidden)] -trait SplitIter: DoubleEndedIterator { - /// Marks the underlying iterator as complete, extracting the remaining - /// portion of the slice. - fn finish(&mut self) -> Option; -} - -/// An iterator over subslices separated by elements that match a predicate -/// function. -/// -/// This struct is created by the [`split`] method on [slices]. -/// -/// [`split`]: ../../std/primitive.slice.html#method.split -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Split<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for Split<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Split").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Split<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - Split { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().position(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx + 1..]; - ret - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - match self.v.iter().rposition(|x| (self.pred)(x)) { - None => self.finish(), - Some(idx) => { - let ret = Some(&self.v[idx + 1..]); - self.v = &self.v[..idx]; - ret - } - } - } -} - -impl<'a, T, P> SplitIter for Split<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(self.v) - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Split<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function. Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [slices]. -/// -/// [`split_inclusive`]: ../../std/primitive.slice.html#method.split_inclusive -/// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusive<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a [T], - pred: P, - finished: bool, -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl fmt::Debug for SplitInclusive<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive", issue = "72360")] -impl Clone for SplitInclusive<'_, T, P> -where - P: Clone + FnMut(&T) -> bool, -{ - fn clone(&self) -> Self { - SplitInclusive { v: self.v, pred: self.pred.clone(), finished: self.finished } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> Iterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - let idx = - self.v.iter().position(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let ret = Some(&self.v[..idx]); - self.v = &self.v[idx..]; - ret - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { (0, Some(0)) } else { (1, Some(self.v.len() + 1)) } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusive<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.finished { - return None; - } - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = if self.v.is_empty() { &[] } else { &self.v[..(self.v.len() - 1)] }; - let idx = remainder.iter().rposition(|x| (self.pred)(x)).map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let ret = Some(&self.v[idx..]); - self.v = &self.v[..idx]; - ret - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl FusedIterator for SplitInclusive<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. -/// -/// This struct is created by the [`split_mut`] method on [slices]. -/// -/// [`split_mut`]: ../../std/primitive.slice.html#method.split_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitMut").field("v", &self.v).field("finished", &self.finished).finish() - } -} - -impl<'a, T, P> SplitIter for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - if self.finished { - None - } else { - self.finished = true; - Some(mem::replace(&mut self.v, &mut [])) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> Iterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = &mut tail[1..]; - Some(head) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T, P> DoubleEndedIterator for SplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().rposition(|x| (*pred)(x)) - }; - match idx_opt { - None => self.finish(), - Some(idx) => { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(&mut tail[1..]) - } - } - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the mutable subslices of the vector which are separated -/// by elements that match `pred`. Unlike `SplitMut`, it contains the matched -/// parts in the ends of the subslices. -/// -/// This struct is created by the [`split_inclusive_mut`] method on [slices]. -/// -/// [`split_inclusive_mut`]: ../../std/primitive.slice.html#method.split_inclusive_mut -/// [slices]: ../../std/primitive.slice.html -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusiveMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - v: &'a mut [T], - pred: P, - finished: bool, -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl fmt::Debug for SplitInclusiveMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusiveMut") - .field("v", &self.v) - .field("finished", &self.finished) - .finish() - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> Iterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = { - // work around borrowck limitations - let pred = &mut self.pred; - self.v.iter().position(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(self.v.len()); - if idx == self.v.len() { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = tail; - Some(head) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.finished { - (0, Some(0)) - } else { - // if the predicate doesn't match anything, we yield one slice - // if it matches every element, we yield len+1 empty slices. - (1, Some(self.v.len() + 1)) - } - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, T, P> DoubleEndedIterator for SplitInclusiveMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.finished { - return None; - } - - let idx_opt = if self.v.is_empty() { - None - } else { - // work around borrowck limitations - let pred = &mut self.pred; - - // The last index of self.v is already checked and found to match - // by the last iteration, so we start searching a new match - // one index to the left. - let remainder = &self.v[..(self.v.len() - 1)]; - remainder.iter().rposition(|x| (*pred)(x)) - }; - let idx = idx_opt.map(|idx| idx + 1).unwrap_or(0); - if idx == 0 { - self.finished = true; - } - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(idx); - self.v = head; - Some(tail) - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl FusedIterator for SplitInclusiveMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over subslices separated by elements that match a predicate -/// function, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit`] method on [slices]. -/// -/// [`rsplit`]: ../../std/primitive.slice.html#method.rsplit -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "slice_rsplit", since = "1.27.0")] -#[derive(Clone)] // Is this correct, or does it incorrectly require `T: Clone`? -pub struct RSplit<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: Split<'a, T, P>, -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplit<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplit") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplit<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplit<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An iterator over the subslices of the vector which are separated -/// by elements that match `pred`, starting from the end of the slice. -/// -/// This struct is created by the [`rsplit_mut`] method on [slices]. -/// -/// [`rsplit_mut`]: ../../std/primitive.slice.html#method.rsplit_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "slice_rsplit", since = "1.27.0")] -pub struct RSplitMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: SplitMut<'a, T, P>, -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl fmt::Debug for RSplitMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitMut") - .field("v", &self.inner.v) - .field("finished", &self.inner.finished) - .finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> SplitIter for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn finish(&mut self) -> Option<&'a mut [T]> { - self.inner.finish() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> Iterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - self.inner.next_back() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl<'a, T, P> DoubleEndedIterator for RSplitMut<'a, T, P> -where - P: FnMut(&T) -> bool, -{ - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - self.inner.next() - } -} - -#[stable(feature = "slice_rsplit", since = "1.27.0")] -impl FusedIterator for RSplitMut<'_, T, P> where P: FnMut(&T) -> bool {} - -/// An private iterator over subslices separated by elements that -/// match a predicate function, splitting at most a fixed number of -/// times. -#[derive(Debug)] -struct GenericSplitN { - iter: I, - count: usize, -} - -impl> Iterator for GenericSplitN { - type Item = T; - - #[inline] - fn next(&mut self) -> Option { - match self.count { - 0 => None, - 1 => { - self.count -= 1; - self.iter.finish() - } - _ => { - self.count -= 1; - self.iter.next() - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (lower, upper_opt) = self.iter.size_hint(); - (lower, upper_opt.map(|upper| cmp::min(self.count, upper))) - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn`] method on [slices]. -/// -/// [`splitn`]: ../../std/primitive.slice.html#method.splitn -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn`] method on [slices]. -/// -/// [`rsplitn`]: ../../std/primitive.slice.html#method.rsplitn -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplitN<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitN<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitN").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a predicate -/// function, limited to a given number of splits. -/// -/// This struct is created by the [`splitn_mut`] method on [slices]. -/// -/// [`splitn_mut`]: ../../std/primitive.slice.html#method.splitn_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct SplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for SplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNMut").field("inner", &self.inner).finish() - } -} - -/// An iterator over subslices separated by elements that match a -/// predicate function, limited to a given number of splits, starting -/// from the end of the slice. -/// -/// This struct is created by the [`rsplitn_mut`] method on [slices]. -/// -/// [`rsplitn_mut`]: ../../std/primitive.slice.html#method.rsplitn_mut -/// [slices]: ../../std/primitive.slice.html -#[stable(feature = "rust1", since = "1.0.0")] -pub struct RSplitNMut<'a, T: 'a, P> -where - P: FnMut(&T) -> bool, -{ - inner: GenericSplitN>, -} - -#[stable(feature = "core_impl_debug", since = "1.9.0")] -impl fmt::Debug for RSplitNMut<'_, T, P> -where - P: FnMut(&T) -> bool, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("RSplitNMut").field("inner", &self.inner).finish() - } -} - -macro_rules! forward_iterator { - ($name:ident: $elem:ident, $iter_of:ty) => { - #[stable(feature = "rust1", since = "1.0.0")] - impl<'a, $elem, P> Iterator for $name<'a, $elem, P> - where - P: FnMut(&T) -> bool, - { - type Item = $iter_of; - - #[inline] - fn next(&mut self) -> Option<$iter_of> { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, $elem, P> FusedIterator for $name<'a, $elem, P> where P: FnMut(&T) -> bool {} - }; -} - -forward_iterator! { SplitN: T, &'a [T] } -forward_iterator! { RSplitN: T, &'a [T] } -forward_iterator! { SplitNMut: T, &'a mut [T] } -forward_iterator! { RSplitNMut: T, &'a mut [T] } - -/// An iterator over overlapping subslices of length `size`. -/// -/// This struct is created by the [`windows`] method on [slices]. -/// -/// [`windows`]: ../../std/primitive.slice.html#method.windows -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Windows<'a, T: 'a> { - v: &'a [T], - size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Windows<'_, T> { - fn clone(&self) -> Self { - Windows { v: self.v, size: self.size } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Windows<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.size > self.v.len() { - None - } else { - let ret = Some(&self.v[..self.size]); - self.v = &self.v[1..]; - ret - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.size > self.v.len() { - (0, Some(0)) - } else { - let size = self.v.len() - self.size + 1; - (size, Some(size)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = self.size.overflowing_add(n); - if end > self.v.len() || overflow { - self.v = &[]; - None - } else { - let nth = &self.v[n..end]; - self.v = &self.v[n + 1..]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.size > self.v.len() { - None - } else { - let start = self.v.len() - self.size; - Some(&self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - // SAFETY: since the caller guarantees that `i` is in bounds, - // which means that `i` cannot overflow an `isize`, and the - // slice created by `from_raw_parts` is a subslice of `self.v` - // thus is guaranteed to be valid for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(idx), self.size) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Windows<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.size > self.v.len() { - None - } else { - let ret = Some(&self.v[self.v.len() - self.size..]); - self.v = &self.v[..self.v.len() - 1]; - ret - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let (end, overflow) = self.v.len().overflowing_sub(n); - if end < self.size || overflow { - self.v = &[]; - None - } else { - let ret = &self.v[end - self.size..end]; - self.v = &self.v[..end - 1]; - Some(ret) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Windows<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Windows<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Windows<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Windows<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`chunks`] method on [slices]. -/// -/// [`chunks`]: ../../std/primitive.slice.html#method.chunks -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Chunks<'a, T: 'a> { - v: &'a [T], - chunk_size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rust1", since = "1.0.0")] -impl Clone for Chunks<'_, T> { - fn clone(&self) -> Self { - Chunks { v: self.v, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for Chunks<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let chunksz = cmp::min(self.v.len(), self.chunk_size); - let (fst, snd) = self.v.split_at(chunksz); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - let nth = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - Some(&self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: the caller guarantees that `i` is in bounds, - // which means that `start` must be in bounds of the - // underlying `self.v` slice, and we made sure that `end` - // is also in bounds of `self.v`. Thus, `start` cannot overflow - // an `isize`, and the slice constructed by `from_raw_parts` - // is a subslice of `self.v` which is guaranteed to be valid - // for the lifetime `'a` of `self.v`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for Chunks<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; - let (fst, snd) = self.v.split_at(self.v.len() - chunksz); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), - None => self.v.len(), - }; - let nth_back = &self.v[start..end]; - self.v = &self.v[..start]; - Some(nth_back) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Chunks<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Chunks<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Chunks<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Chunks<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`chunks_mut`] method on [slices]. -/// -/// [`chunks_mut`]: ../../std/primitive.slice.html#method.chunks_mut -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ChunksMut<'a, T: 'a> { - v: &'a mut [T], - chunk_size: usize, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> Iterator for ChunksMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(sz); - self.v = tail; - Some(head) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let end = match start.checked_add(self.chunk_size) { - Some(sum) => cmp::min(self.v.len(), sum), - None => self.v.len(), - }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(end); - let (_, nth) = head.split_at_mut(start); - self.v = tail; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let start = (self.v.len() - 1) / self.chunk_size * self.chunk_size; - Some(&mut self.v[start..]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - None => self.v.len(), - Some(end) => cmp::min(end, self.v.len()), - }; - // SAFETY: see comments for `Chunks::get_unchecked`. - // - // Also note that the caller also guarantees that we're never called - // with the same index again, and that no other methods that will - // access this subslice are called, so it is valid for the returned - // slice to be mutable. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a, T> DoubleEndedIterator for ChunksMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - sz); - self.v = head; - Some(tail) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = match start.checked_add(self.chunk_size) { - Some(res) => cmp::min(res, self.v.len()), - None => self.v.len(), - }; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); - self.v = head; - Some(nth_back) - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for ChunksMut<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksMut<'_, T> {} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for ChunksMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`chunks_exact`] method on [slices]. -/// -/// [`chunks_exact`]: ../../std/primitive.slice.html#method.chunks_exact -/// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "chunks_exact", since = "1.31.0")] -pub struct ChunksExact<'a, T: 'a> { - v: &'a [T], - rem: &'a [T], - chunk_size: usize, -} - -impl<'a, T> ChunksExact<'a, T> { - /// 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. - #[stable(feature = "chunks_exact", since = "1.31.0")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl Clone for ChunksExact<'_, T> { - fn clone(&self) -> Self { - ChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> Iterator for ChunksExact<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let (_, snd) = self.v.split_at(start); - self.v = snd; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for ChunksExact<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = start + self.chunk_size; - let nth_back = &self.v[start..end]; - self.v = &self.v[..start]; - Some(nth_back) - } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl ExactSizeIterator for ChunksExact<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksExact<'_, T> {} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl FusedIterator for ChunksExact<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExact<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last up to -/// `chunk_size-1` elements will be omitted but can be retrieved from the -/// [`into_remainder`] function from the iterator. -/// -/// This struct is created by the [`chunks_exact_mut`] method on [slices]. -/// -/// [`chunks_exact_mut`]: ../../std/primitive.slice.html#method.chunks_exact_mut -/// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "chunks_exact", since = "1.31.0")] -pub struct ChunksExactMut<'a, T: 'a> { - v: &'a mut [T], - rem: &'a mut [T], - chunk_size: usize, -} - -impl<'a, T> ChunksExactMut<'a, T> { - /// 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. - #[stable(feature = "chunks_exact", since = "1.31.0")] - pub fn into_remainder(self) -> &'a mut [T] { - self.rem - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> Iterator for ChunksExactMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); - self.v = tail; - Some(head) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (start, overflow) = n.overflowing_mul(self.chunk_size); - if start >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (_, snd) = tmp.split_at_mut(start); - self.v = snd; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let start = idx * self.chunk_size; - // SAFETY: see comments for `ChunksMut::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for ChunksExactMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); - self.v = head; - Some(tail) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - let start = (len - 1 - n) * self.chunk_size; - let end = start + self.chunk_size; - let (temp, _tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (head, nth_back) = temp.split_at_mut(start); - self.v = head; - Some(nth_back) - } - } -} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl ExactSizeIterator for ChunksExactMut<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ChunksExactMut<'_, T> {} - -#[stable(feature = "chunks_exact", since = "1.31.0")] -impl FusedIterator for ChunksExactMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for ChunksExactMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`N` elements at a -/// time), starting at the beginning of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`array_chunks`] method on [slices]. -/// -/// [`array_chunks`]: ../../std/primitive.slice.html#method.array_chunks -/// [`remainder`]: ../../std/slice/struct.ArrayChunks.html#method.remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[unstable(feature = "array_chunks", issue = "74985")] -pub struct ArrayChunks<'a, T: 'a, const N: usize> { - iter: Iter<'a, [T; N]>, - rem: &'a [T], -} - -impl<'a, T, const N: usize> ArrayChunks<'a, T, N> { - /// 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. - #[unstable(feature = "array_chunks", issue = "74985")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "array_chunks", issue = "74985")] -impl Clone for ArrayChunks<'_, T, N> { - fn clone(&self) -> Self { - ArrayChunks { iter: self.iter.clone(), rem: self.rem } - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> Iterator for ArrayChunks<'a, T, N> { - type Item = &'a [T; N]; - - #[inline] - fn next(&mut self) -> Option<&'a [T; N]> { - self.iter.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - self.iter.nth(n) - } - - #[inline] - fn last(self) -> Option { - self.iter.last() - } - - unsafe fn __iterator_get_unchecked(&mut self, i: usize) -> &'a [T; N] { - // SAFETY: The safety guarantees of `get_unchecked` are transferred to - // the caller. - unsafe { self.iter.__iterator_get_unchecked(i) } - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl<'a, T, const N: usize> DoubleEndedIterator for ArrayChunks<'a, T, N> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T; N]> { - self.iter.next_back() - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - self.iter.nth_back(n) - } -} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl ExactSizeIterator for ArrayChunks<'_, T, N> { - fn is_empty(&self) -> bool { - self.iter.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for ArrayChunks<'_, T, N> {} - -#[unstable(feature = "array_chunks", issue = "74985")] -impl FusedIterator for ArrayChunks<'_, T, N> {} - -#[doc(hidden)] -#[unstable(feature = "array_chunks", issue = "74985")] -unsafe impl<'a, T, const N: usize> TrustedRandomAccess for ArrayChunks<'a, T, N> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`rchunks`] method on [slices]. -/// -/// [`rchunks`]: ../../std/primitive.slice.html#method.rchunks -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunks<'a, T: 'a> { - v: &'a [T], - chunk_size: usize, -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rchunks", since = "1.31.0")] -impl Clone for RChunks<'_, T> { - fn clone(&self) -> Self { - RChunks { v: self.v, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunks<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let chunksz = cmp::min(self.v.len(), self.chunk_size); - let (fst, snd) = self.v.split_at(self.v.len() - chunksz); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &[]; - None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; - let nth = &self.v[start..end]; - self.v = &self.v[0..start]; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let rem = self.v.len() % self.chunk_size; - let end = if rem == 0 { self.chunk_size } else { rem }; - Some(&self.v[0..end]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: mostly identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunks<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let chunksz = if remainder != 0 { remainder } else { self.chunk_size }; - let (fst, snd) = self.v.split_at(chunksz); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - // can't underflow because `n < len` - let offset_from_end = (len - 1 - n) * self.chunk_size; - let end = self.v.len() - offset_from_end; - let start = end.saturating_sub(self.chunk_size); - let nth_back = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunks<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunks<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunks<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunks<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last slice -/// of the iteration will be the remainder. -/// -/// This struct is created by the [`rchunks_mut`] method on [slices]. -/// -/// [`rchunks_mut`]: ../../std/primitive.slice.html#method.rchunks_mut -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksMut<'a, T: 'a> { - v: &'a mut [T], - chunk_size: usize, -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let sz = cmp::min(self.v.len(), self.chunk_size); - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - sz); - self.v = head; - Some(tail) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - if self.v.is_empty() { - (0, Some(0)) - } else { - let n = self.v.len() / self.chunk_size; - let rem = self.v.len() % self.chunk_size; - let n = if rem > 0 { n + 1 } else { n }; - (n, Some(n)) - } - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - // Can't underflow because of the check above - let end = self.v.len() - end; - let start = match end.checked_sub(self.chunk_size) { - Some(sum) => sum, - None => 0, - }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(start); - let (nth, _) = tail.split_at_mut(end - start); - self.v = head; - Some(nth) - } - } - - #[inline] - fn last(self) -> Option { - if self.v.is_empty() { - None - } else { - let rem = self.v.len() % self.chunk_size; - let end = if rem == 0 { self.chunk_size } else { rem }; - Some(&mut self.v[0..end]) - } - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = match end.checked_sub(self.chunk_size) { - None => 0, - Some(start) => start, - }; - // SAFETY: see comments for `RChunks::get_unchecked` and `ChunksMut::get_unchecked` - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), end - start) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.is_empty() { - None - } else { - let remainder = self.v.len() % self.chunk_size; - let sz = if remainder != 0 { remainder } else { self.chunk_size }; - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(sz); - self.v = tail; - Some(head) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - // can't underflow because `n < len` - let offset_from_end = (len - 1 - n) * self.chunk_size; - let end = self.v.len() - offset_from_end; - let start = end.saturating_sub(self.chunk_size); - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); - self.v = tail; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunksMut<'_, T> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksMut<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) chunks (`chunk_size` elements at a -/// time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last -/// up to `chunk_size-1` elements will be omitted but can be retrieved from -/// the [`remainder`] function from the iterator. -/// -/// This struct is created by the [`rchunks_exact`] method on [slices]. -/// -/// [`rchunks_exact`]: ../../std/primitive.slice.html#method.rchunks_exact -/// [`remainder`]: ../../std/slice/struct.ChunksExact.html#method.remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksExact<'a, T: 'a> { - v: &'a [T], - rem: &'a [T], - chunk_size: usize, -} - -impl<'a, T> RChunksExact<'a, T> { - /// 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. - #[stable(feature = "rchunks", since = "1.31.0")] - pub fn remainder(&self) -> &'a [T] { - self.rem - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Clone for RChunksExact<'a, T> { - fn clone(&self) -> RChunksExact<'a, T> { - RChunksExact { v: self.v, rem: self.rem, chunk_size: self.chunk_size } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksExact<'a, T> { - type Item = &'a [T]; - - #[inline] - fn next(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.v.len() - self.chunk_size); - self.v = fst; - Some(snd) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &[]; - None - } else { - let (fst, _) = self.v.split_at(self.v.len() - end); - self.v = fst; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: - // SAFETY: mostmy identical to `Chunks::get_unchecked`. - unsafe { from_raw_parts(self.v.as_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksExact<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let (fst, snd) = self.v.split_at(self.chunk_size); - self.v = snd; - Some(fst) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &[]; - None - } else { - // now that we know that `n` corresponds to a chunk, - // none of these operations can underflow/overflow - let offset = (len - n) * self.chunk_size; - let start = self.v.len() - offset; - let end = start + self.chunk_size; - let nth_back = &self.v[start..end]; - self.v = &self.v[end..]; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> ExactSizeIterator for RChunksExact<'a, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksExact<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksExact<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExact<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -/// An iterator over a slice in (non-overlapping) mutable chunks (`chunk_size` -/// elements at a time), starting at the end of the slice. -/// -/// When the slice len is not evenly divided by the chunk size, the last up to -/// `chunk_size-1` elements will be omitted but can be retrieved from the -/// [`into_remainder`] function from the iterator. -/// -/// This struct is created by the [`rchunks_exact_mut`] method on [slices]. -/// -/// [`rchunks_exact_mut`]: ../../std/primitive.slice.html#method.rchunks_exact_mut -/// [`into_remainder`]: ../../std/slice/struct.ChunksExactMut.html#method.into_remainder -/// [slices]: ../../std/primitive.slice.html -#[derive(Debug)] -#[stable(feature = "rchunks", since = "1.31.0")] -pub struct RChunksExactMut<'a, T: 'a> { - v: &'a mut [T], - rem: &'a mut [T], - chunk_size: usize, -} - -impl<'a, T> RChunksExactMut<'a, T> { - /// 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. - #[stable(feature = "rchunks", since = "1.31.0")] - pub fn into_remainder(self) -> &'a mut [T] { - self.rem - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> Iterator for RChunksExactMut<'a, T> { - type Item = &'a mut [T]; - - #[inline] - fn next(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (head, tail) = tmp.split_at_mut(tmp_len - self.chunk_size); - self.v = head; - Some(tail) - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let n = self.v.len() / self.chunk_size; - (n, Some(n)) - } - - #[inline] - fn count(self) -> usize { - self.len() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option<&'a mut [T]> { - let (end, overflow) = n.overflowing_mul(self.chunk_size); - if end >= self.v.len() || overflow { - self.v = &mut []; - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let tmp_len = tmp.len(); - let (fst, _) = tmp.split_at_mut(tmp_len - end); - self.v = fst; - self.next() - } - } - - #[inline] - fn last(mut self) -> Option { - self.next_back() - } - - #[doc(hidden)] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> Self::Item { - let end = self.v.len() - idx * self.chunk_size; - let start = end - self.chunk_size; - // SAFETY: see comments for `RChunksMut::get_unchecked`. - unsafe { from_raw_parts_mut(self.v.as_mut_ptr().add(start), self.chunk_size) } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl<'a, T> DoubleEndedIterator for RChunksExactMut<'a, T> { - #[inline] - fn next_back(&mut self) -> Option<&'a mut [T]> { - if self.v.len() < self.chunk_size { - None - } else { - let tmp = mem::replace(&mut self.v, &mut []); - let (head, tail) = tmp.split_at_mut(self.chunk_size); - self.v = tail; - Some(head) - } - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - let len = self.len(); - if n >= len { - self.v = &mut []; - None - } else { - // now that we know that `n` corresponds to a chunk, - // none of these operations can underflow/overflow - let offset = (len - n) * self.chunk_size; - let start = self.v.len() - offset; - let end = start + self.chunk_size; - let (tmp, tail) = mem::replace(&mut self.v, &mut []).split_at_mut(end); - let (_, nth_back) = tmp.split_at_mut(start); - self.v = tail; - Some(nth_back) - } - } -} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl ExactSizeIterator for RChunksExactMut<'_, T> { - fn is_empty(&self) -> bool { - self.v.is_empty() - } -} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for RChunksExactMut<'_, T> {} - -#[stable(feature = "rchunks", since = "1.31.0")] -impl FusedIterator for RChunksExactMut<'_, T> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for RChunksExactMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -// -// Free functions -// - -/// Forms a slice from a pointer and a length. -/// -/// The `len` argument is the number of **elements**, not the number of bytes. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) -/// for an example incorrectly not taking this into account. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * The memory referenced by the returned slice must not be mutated for the duration -/// of lifetime `'a`, except inside an `UnsafeCell`. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// # Caveat -/// -/// The lifetime for the returned slice is inferred from its usage. To -/// prevent accidental misuse, it's suggested to tie the lifetime to whichever -/// source lifetime is safe in the context, such as by providing a helper -/// function taking the lifetime of a host value for the slice, or by explicit -/// annotation. -/// -/// # Examples -/// -/// ``` -/// use std::slice; -/// -/// // manifest a slice for a single element -/// let x = 42; -/// let ptr = &x as *const _; -/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; -/// assert_eq!(slice[0], 42); -/// ``` -/// -/// ### Incorrect usage -/// -/// The following `join_slices` function is **unsound** ⚠️ -/// -/// ```rust,no_run -/// use std::slice; -/// -/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { -/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); -/// let snd_start = snd.as_ptr(); -/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); -/// unsafe { -/// // The assertion above ensures `fst` and `snd` are contiguous, but they might -/// // still be contained within _different allocated objects_, in which case -/// // creating this slice is undefined behavior. -/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) -/// } -/// } -/// -/// fn main() { -/// // `a` and `b` are different allocated objects... -/// let a = 42; -/// let b = 27; -/// // ... which may nevertheless be laid out contiguously in memory: | a | b | -/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB -/// } -/// ``` -/// -/// [valid]: ../../std/ptr/index.html#safety -/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. - unsafe { &*ptr::slice_from_raw_parts(data, len) } -} - -/// Performs the same functionality as [`from_raw_parts`], except that a -/// mutable slice is returned. -/// -/// # Safety -/// -/// Behavior is undefined if any of the following conditions are violated: -/// -/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, -/// and it must be properly aligned. This means in particular: -/// -/// * The entire memory range of this slice must be contained within a single allocated object! -/// Slices can never span across multiple allocated objects. -/// * `data` must be non-null and aligned even for zero-length slices. One -/// reason for this is that enum layout optimizations may rely on references -/// (including slices of any length) being aligned and non-null to distinguish -/// them from other data. You can obtain a pointer that is usable as `data` -/// for zero-length slices using [`NonNull::dangling()`]. -/// -/// * The memory referenced by the returned slice must not be accessed through any other pointer -/// (not derived from the return value) for the duration of lifetime `'a`. -/// Both read and write accesses are forbidden. -/// -/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. -/// See the safety documentation of [`pointer::offset`]. -/// -/// [valid]: ../../std/ptr/index.html#safety -/// [`NonNull::dangling()`]: ../../std/ptr/struct.NonNull.html#method.dangling -/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset -/// [`from_raw_parts`]: ../../std/slice/fn.from_raw_parts.html -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { - debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); - debug_assert!( - mem::size_of::().saturating_mul(len) <= isize::MAX as usize, - "attempt to create slice covering at least half the address space" - ); - // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. - unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_ref(s: &T) -> &[T] { - // SAFETY: a reference is guaranteed to be valid for reads. The returned - // reference cannot be mutated as it is an immutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts` is safe. - unsafe { from_raw_parts(s, 1) } -} - -/// Converts a reference to T into a slice of length 1 (without copying). -#[stable(feature = "from_ref", since = "1.28.0")] -pub fn from_mut(s: &mut T) -> &mut [T] { - // SAFETY: a mutable reference is guaranteed to be valid for writes. - // The reference cannot be accessed by another pointer as it is an mutable reference. - // `mem::size_of::()` cannot be larger than `isize::MAX`. - // Thus the call to `from_raw_parts_mut` is safe. - unsafe { from_raw_parts_mut(s, 1) } -} - -// This function is public only because there is no other way to unit test heapsort. -#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] -#[doc(hidden)] -pub fn heapsort(v: &mut [T], mut is_less: F) -where - F: FnMut(&T, &T) -> bool, -{ - sort::heapsort(v, &mut is_less); -} - -// -// Comparison traits -// - -extern "C" { - /// Calls implementation provided memcmp. - /// - /// Interprets the data as u8. - /// - /// Returns 0 for equal, < 0 for less than and > 0 for greater - /// than. - // FIXME(#32610): Return type should be c_int - fn memcmp(s1: *const u8, s2: *const u8, n: usize) -> i32; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialEq<[B]> for [A] -where - A: PartialEq, -{ - fn eq(&self, other: &[B]) -> bool { - SlicePartialEq::equal(self, other) - } - - fn ne(&self, other: &[B]) -> bool { - SlicePartialEq::not_equal(self, other) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl Eq for [T] {} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl Ord for [T] { - fn cmp(&self, other: &[T]) -> Ordering { - SliceOrd::compare(self, other) - } -} - -/// Implements comparison of vectors lexicographically. -#[stable(feature = "rust1", since = "1.0.0")] -impl PartialOrd for [T] { - fn partial_cmp(&self, other: &[T]) -> Option { - SlicePartialOrd::partial_compare(self, other) - } -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's PartialEq -trait SlicePartialEq { - fn equal(&self, other: &[B]) -> bool; - - fn not_equal(&self, other: &[B]) -> bool { - !self.equal(other) - } -} - -// Generic slice equality -impl SlicePartialEq for [A] -where - A: PartialEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Use an equal-pointer optimization when types are `Eq` -// We can't make `A` and `B` the same type because `min_specialization` won't -// allow it. -impl SlicePartialEq for [A] -where - A: MarkerEq, -{ - default fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - // While performance would suffer if `guaranteed_eq` just returned `false` - // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { - return true; - } - - self.iter().zip(other.iter()).all(|(x, y)| x == y) - } -} - -// Use memcmp for bytewise equality when the types allow -impl SlicePartialEq for [A] -where - A: BytewiseEquality, -{ - fn equal(&self, other: &[B]) -> bool { - if self.len() != other.len() { - return false; - } - - // While performance would suffer if `guaranteed_eq` just returned `false` - // for all arguments, correctness and return value of this function are not affected. - if self.as_ptr().guaranteed_eq(other.as_ptr() as *const A) { - return true; - } - // SAFETY: `self` and `other` are references and are thus guaranteed to be valid. - // The two slices have been checked to have the same size above. - unsafe { - let size = mem::size_of_val(self); - memcmp(self.as_ptr() as *const u8, other.as_ptr() as *const u8, size) == 0 - } - } -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's PartialOrd -trait SlicePartialOrd: Sized { - fn partial_compare(left: &[Self], right: &[Self]) -> Option; -} - -impl SlicePartialOrd for A { - default fn partial_compare(left: &[A], right: &[A]) -> Option { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].partial_cmp(&rhs[i]) { - Some(Ordering::Equal) => (), - non_eq => return non_eq, - } - } - - left.len().partial_cmp(&right.len()) - } -} - -// This is the impl that we would like to have. Unfortunately it's not sound. -// See `partial_ord_slice.rs`. -/* -impl SlicePartialOrd for A -where - A: Ord, -{ - default fn partial_compare(left: &[A], right: &[A]) -> Option { - Some(SliceOrd::compare(left, right)) - } -} -*/ - -impl SlicePartialOrd for A { - fn partial_compare(left: &[A], right: &[A]) -> Option { - Some(SliceOrd::compare(left, right)) - } -} - -#[rustc_specialization_trait] -trait AlwaysApplicableOrd: SliceOrd + Ord {} - -macro_rules! always_applicable_ord { - ($([$($p:tt)*] $t:ty,)*) => { - $(impl<$($p)*> AlwaysApplicableOrd for $t {})* - } -} - -always_applicable_ord! { - [] u8, [] u16, [] u32, [] u64, [] u128, [] usize, - [] i8, [] i16, [] i32, [] i64, [] i128, [] isize, - [] bool, [] char, - [T: ?Sized] *const T, [T: ?Sized] *mut T, - [T: AlwaysApplicableOrd] &T, - [T: AlwaysApplicableOrd] &mut T, - [T: AlwaysApplicableOrd] Option, -} - -#[doc(hidden)] -// intermediate trait for specialization of slice's Ord -trait SliceOrd: Sized { - fn compare(left: &[Self], right: &[Self]) -> Ordering; -} - -impl SliceOrd for A { - default fn compare(left: &[Self], right: &[Self]) -> Ordering { - let l = cmp::min(left.len(), right.len()); - - // Slice to the loop iteration range to enable bound check - // elimination in the compiler - let lhs = &left[..l]; - let rhs = &right[..l]; - - for i in 0..l { - match lhs[i].cmp(&rhs[i]) { - Ordering::Equal => (), - non_eq => return non_eq, - } - } - - left.len().cmp(&right.len()) - } -} - -// memcmp compares a sequence of unsigned bytes lexicographically. -// this matches the order we want for [u8], but no others (not even [i8]). -impl SliceOrd for u8 { - #[inline] - fn compare(left: &[Self], right: &[Self]) -> Ordering { - let order = - // SAFETY: `left` and `right` are references and are thus guaranteed to be valid. - // We use the minimum of both lengths which guarantees that both regions are - // valid for reads in that interval. - unsafe { memcmp(left.as_ptr(), right.as_ptr(), cmp::min(left.len(), right.len())) }; - if order == 0 { - left.len().cmp(&right.len()) - } else if order < 0 { - Less - } else { - Greater - } - } -} - -// Hack to allow specializing on `Eq` even though `Eq` has a method. -#[rustc_unsafe_specialization_marker] -trait MarkerEq: PartialEq {} - -impl MarkerEq for T {} - -#[doc(hidden)] -/// Trait implemented for types that can be compared for equality using -/// their bytewise representation -#[rustc_specialization_trait] -trait BytewiseEquality: MarkerEq + Copy {} - -macro_rules! impl_marker_for { - ($traitname:ident, $($ty:ty)*) => { - $( - impl $traitname<$ty> for $ty { } - )* - } -} - -impl_marker_for!(BytewiseEquality, - u8 i8 u16 i16 u32 i32 u64 i64 u128 i128 usize isize char bool); - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for Iter<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl<'a, T> TrustedRandomAccess for IterMut<'a, T> { - fn may_have_side_effect() -> bool { - false - } -} - -trait SliceContains: Sized { - fn slice_contains(&self, x: &[Self]) -> bool; -} - -impl SliceContains for T -where - T: PartialEq, -{ - default fn slice_contains(&self, x: &[Self]) -> bool { - x.iter().any(|y| *y == *self) - } -} - -impl SliceContains for u8 { - fn slice_contains(&self, x: &[Self]) -> bool { - memchr::memchr(*self, x).is_some() - } -} - -impl SliceContains for i8 { - fn slice_contains(&self, x: &[Self]) -> bool { - let byte = *self as u8; - // SAFETY: `i8` and `u8` have the same memory layout, thus casting `x.as_ptr()` - // as `*const u8` is safe. The `x.as_ptr()` comes from a reference and is thus guaranteed - // to be valid for reads for the length of the slice `x.len()`, which cannot be larger - // than `isize::MAX`. The returned slice is never mutated. - let bytes: &[u8] = unsafe { from_raw_parts(x.as_ptr() as *const u8, x.len()) }; - memchr::memchr(byte, bytes).is_some() - } -} diff --git a/library/core/src/slice/raw.rs b/library/core/src/slice/raw.rs new file mode 100644 index 0000000000..09209306c9 --- /dev/null +++ b/library/core/src/slice/raw.rs @@ -0,0 +1,151 @@ +//! Free functions to create `&[T]` and `&mut [T]`. + +use crate::array; +use crate::intrinsics::is_aligned_and_not_null; +use crate::mem; +use crate::ptr; + +/// Forms a slice from a pointer and a length. +/// +/// The `len` argument is the number of **elements**, not the number of bytes. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for reads for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. See [below](#incorrect-usage) +/// for an example incorrectly not taking this into account. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be mutated for the duration +/// of lifetime `'a`, except inside an `UnsafeCell`. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// # Caveat +/// +/// The lifetime for the returned slice is inferred from its usage. To +/// prevent accidental misuse, it's suggested to tie the lifetime to whichever +/// source lifetime is safe in the context, such as by providing a helper +/// function taking the lifetime of a host value for the slice, or by explicit +/// annotation. +/// +/// # Examples +/// +/// ``` +/// use std::slice; +/// +/// // manifest a slice for a single element +/// let x = 42; +/// let ptr = &x as *const _; +/// let slice = unsafe { slice::from_raw_parts(ptr, 1) }; +/// assert_eq!(slice[0], 42); +/// ``` +/// +/// ### Incorrect usage +/// +/// The following `join_slices` function is **unsound** ⚠️ +/// +/// ```rust,no_run +/// use std::slice; +/// +/// fn join_slices<'a, T>(fst: &'a [T], snd: &'a [T]) -> &'a [T] { +/// let fst_end = fst.as_ptr().wrapping_add(fst.len()); +/// let snd_start = snd.as_ptr(); +/// assert_eq!(fst_end, snd_start, "Slices must be contiguous!"); +/// unsafe { +/// // The assertion above ensures `fst` and `snd` are contiguous, but they might +/// // still be contained within _different allocated objects_, in which case +/// // creating this slice is undefined behavior. +/// slice::from_raw_parts(fst.as_ptr(), fst.len() + snd.len()) +/// } +/// } +/// +/// fn main() { +/// // `a` and `b` are different allocated objects... +/// let a = 42; +/// let b = 27; +/// // ... which may nevertheless be laid out contiguously in memory: | a | b | +/// let _ = join_slices(slice::from_ref(&a), slice::from_ref(&b)); // UB +/// } +/// ``` +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn from_raw_parts<'a, T>(data: *const T, len: usize) -> &'a [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts`. + unsafe { &*ptr::slice_from_raw_parts(data, len) } +} + +/// Performs the same functionality as [`from_raw_parts`], except that a +/// mutable slice is returned. +/// +/// # Safety +/// +/// Behavior is undefined if any of the following conditions are violated: +/// +/// * `data` must be [valid] for boths reads and writes for `len * mem::size_of::()` many bytes, +/// and it must be properly aligned. This means in particular: +/// +/// * The entire memory range of this slice must be contained within a single allocated object! +/// Slices can never span across multiple allocated objects. +/// * `data` must be non-null and aligned even for zero-length slices. One +/// reason for this is that enum layout optimizations may rely on references +/// (including slices of any length) being aligned and non-null to distinguish +/// them from other data. You can obtain a pointer that is usable as `data` +/// for zero-length slices using [`NonNull::dangling()`]. +/// +/// * `data` must point to `len` consecutive properly initialized values of type `T`. +/// +/// * The memory referenced by the returned slice must not be accessed through any other pointer +/// (not derived from the return value) for the duration of lifetime `'a`. +/// Both read and write accesses are forbidden. +/// +/// * The total size `len * mem::size_of::()` of the slice must be no larger than `isize::MAX`. +/// See the safety documentation of [`pointer::offset`]. +/// +/// [valid]: ptr#safety +/// [`NonNull::dangling()`]: ptr::NonNull::dangling +/// [`pointer::offset`]: ../../std/primitive.pointer.html#method.offset +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +pub unsafe fn from_raw_parts_mut<'a, T>(data: *mut T, len: usize) -> &'a mut [T] { + debug_assert!(is_aligned_and_not_null(data), "attempt to create unaligned or null slice"); + debug_assert!( + mem::size_of::().saturating_mul(len) <= isize::MAX as usize, + "attempt to create slice covering at least half the address space" + ); + // SAFETY: the caller must uphold the safety contract for `from_raw_parts_mut`. + unsafe { &mut *ptr::slice_from_raw_parts_mut(data, len) } +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_ref(s: &T) -> &[T] { + array::from_ref(s) +} + +/// Converts a reference to T into a slice of length 1 (without copying). +#[stable(feature = "from_ref", since = "1.28.0")] +pub fn from_mut(s: &mut T) -> &mut [T] { + array::from_mut(s) +} diff --git a/library/core/src/slice/sort.rs b/library/core/src/slice/sort.rs index 972a33d648..71d2c2c9b2 100644 --- a/library/core/src/slice/sort.rs +++ b/library/core/src/slice/sort.rs @@ -180,7 +180,8 @@ where /// Sorts `v` using heapsort, which guarantees *O*(*n* \* log(*n*)) worst-case. #[cold] -pub fn heapsort(v: &mut [T], is_less: &mut F) +#[unstable(feature = "sort_internals", reason = "internal to sort module", issue = "none")] +pub fn heapsort(v: &mut [T], mut is_less: F) where F: FnMut(&T, &T) -> bool, { @@ -299,8 +300,8 @@ where if start_l == end_l { // Trace `block_l` elements from the left side. - start_l = MaybeUninit::first_ptr_mut(&mut offsets_l); - end_l = MaybeUninit::first_ptr_mut(&mut offsets_l); + start_l = MaybeUninit::slice_as_mut_ptr(&mut offsets_l); + end_l = MaybeUninit::slice_as_mut_ptr(&mut offsets_l); let mut elem = l; for i in 0..block_l { @@ -325,8 +326,8 @@ where if start_r == end_r { // Trace `block_r` elements from the right side. - start_r = MaybeUninit::first_ptr_mut(&mut offsets_r); - end_r = MaybeUninit::first_ptr_mut(&mut offsets_r); + start_r = MaybeUninit::slice_as_mut_ptr(&mut offsets_r); + end_r = MaybeUninit::slice_as_mut_ptr(&mut offsets_r); let mut elem = r; for i in 0..block_r { @@ -564,7 +565,7 @@ fn break_patterns(v: &mut [T]) { random }; let mut gen_usize = || { - if mem::size_of::() <= 4 { + if usize::BITS <= 32 { gen_u32() as usize } else { (((gen_u32() as u64) << 32) | (gen_u32() as u64)) as usize @@ -666,7 +667,7 @@ where /// /// `limit` is the number of allowed imbalanced partitions before switching to `heapsort`. If zero, /// this function will immediately switch to heapsort. -fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: usize) +fn recurse<'a, T, F>(mut v: &'a mut [T], is_less: &mut F, mut pred: Option<&'a T>, mut limit: u32) where F: FnMut(&T, &T) -> bool, { @@ -762,7 +763,7 @@ where } // Limit the number of imbalanced partitions to `floor(log2(len)) + 1`. - let limit = mem::size_of::() * 8 - v.len().leading_zeros() as usize; + let limit = usize::BITS - v.len().leading_zeros(); recurse(v, &mut is_less, None, limit); } diff --git a/library/core/src/str/converts.rs b/library/core/src/str/converts.rs new file mode 100644 index 0000000000..de2a93f735 --- /dev/null +++ b/library/core/src/str/converts.rs @@ -0,0 +1,192 @@ +//! Ways to create a `str` from bytes slice. + +use crate::mem; + +use super::validations::run_utf8_validation; +use super::Utf8Error; + +/// Converts a slice of bytes to a string slice. +/// +/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice +/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between +/// the two. Not all byte slices are valid string slices, however: [`&str`] requires +/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid +/// UTF-8, and then does the conversion. +/// +/// [`&str`]: str +/// [byteslice]: ../../std/primitive.slice.html +/// +/// If you are sure that the byte slice is valid UTF-8, and you don't want to +/// incur the overhead of the validity check, there is an unsafe version of +/// this function, [`from_utf8_unchecked`], which has the same +/// behavior but skips the check. +/// +/// If you need a `String` instead of a `&str`, consider +/// [`String::from_utf8`][string]. +/// +/// [string]: ../../std/string/struct.String.html#method.from_utf8 +/// +/// Because you can stack-allocate a `[u8; N]`, and you can take a +/// [`&[u8]`][byteslice] of it, this function is one way to have a +/// stack-allocated string. There is an example of this in the +/// examples section below. +/// +/// [byteslice]: ../../std/primitive.slice.html +/// +/// # Errors +/// +/// Returns `Err` if the slice is not UTF-8 with a description as to why the +/// provided slice is not UTF-8. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a vector +/// let sparkle_heart = vec![240, 159, 146, 150]; +/// +/// // We know these bytes are valid, so just use `unwrap()`. +/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +/// +/// Incorrect bytes: +/// +/// ``` +/// use std::str; +/// +/// // some invalid bytes, in a vector +/// let sparkle_heart = vec![0, 159, 146, 150]; +/// +/// assert!(str::from_utf8(&sparkle_heart).is_err()); +/// ``` +/// +/// See the docs for [`Utf8Error`] for more details on the kinds of +/// errors that can be returned. +/// +/// A "stack allocated string": +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a stack-allocated array +/// let sparkle_heart = [240, 159, 146, 150]; +/// +/// // We know these bytes are valid, so just use `unwrap()`. +/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { + run_utf8_validation(v)?; + // SAFETY: Just ran validation. + Ok(unsafe { from_utf8_unchecked(v) }) +} + +/// Converts a mutable slice of bytes to a mutable string slice. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // "Hello, Rust!" as a mutable vector +/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; +/// +/// // As we know these bytes are valid, we can use `unwrap()` +/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); +/// +/// assert_eq!("Hello, Rust!", outstr); +/// ``` +/// +/// Incorrect bytes: +/// +/// ``` +/// use std::str; +/// +/// // Some invalid bytes in a mutable vector +/// let mut invalid = vec![128, 223]; +/// +/// assert!(str::from_utf8_mut(&mut invalid).is_err()); +/// ``` +/// See the docs for [`Utf8Error`] for more details on the kinds of +/// errors that can be returned. +#[stable(feature = "str_mut_extras", since = "1.20.0")] +pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { + run_utf8_validation(v)?; + // SAFETY: Just ran validation. + Ok(unsafe { from_utf8_unchecked_mut(v) }) +} + +/// Converts a slice of bytes to a string slice without checking +/// that the string contains valid UTF-8. +/// +/// See the safe version, [`from_utf8`], for more information. +/// +/// # Safety +/// +/// This function is unsafe because it does not check that the bytes passed to +/// it are valid UTF-8. If this constraint is violated, undefined behavior +/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. +/// +/// [`&str`]: str +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// // some bytes, in a vector +/// let sparkle_heart = vec![240, 159, 146, 150]; +/// +/// let sparkle_heart = unsafe { +/// str::from_utf8_unchecked(&sparkle_heart) +/// }; +/// +/// assert_eq!("💖", sparkle_heart); +/// ``` +#[inline] +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")] +#[allow_internal_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. + unsafe { mem::transmute(v) } +} + +/// Converts a slice of bytes to a string slice without checking +/// that the string contains valid UTF-8; mutable version. +/// +/// See the immutable version, [`from_utf8_unchecked()`] for more information. +/// +/// # Examples +/// +/// Basic usage: +/// +/// ``` +/// use std::str; +/// +/// let mut heart = vec![240, 159, 146, 150]; +/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; +/// +/// assert_eq!("💖", heart); +/// ``` +#[inline] +#[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` + // are valid UTF-8, thus the cast to `*mut str` is safe. + // Also, the pointer dereference is safe because that pointer + // comes from a reference which is guaranteed to be valid for writes. + unsafe { &mut *(v as *mut [u8] as *mut str) } +} diff --git a/library/core/src/str/error.rs b/library/core/src/str/error.rs new file mode 100644 index 0000000000..427f720d68 --- /dev/null +++ b/library/core/src/str/error.rs @@ -0,0 +1,129 @@ +//! Defines utf8 error type. + +use crate::fmt; + +/// Errors which can occur when attempting to interpret a sequence of [`u8`] +/// as a string. +/// +/// As such, the `from_utf8` family of functions and methods for both [`String`]s +/// and [`&str`]s make use of this error, for example. +/// +/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 +/// [`&str`]: super::from_utf8 +/// +/// # Examples +/// +/// This error type’s methods can be used to create functionality +/// similar to `String::from_utf8_lossy` without allocating heap memory: +/// +/// ``` +/// fn from_utf8_lossy(mut input: &[u8], mut push: F) where F: FnMut(&str) { +/// loop { +/// match std::str::from_utf8(input) { +/// Ok(valid) => { +/// push(valid); +/// break +/// } +/// Err(error) => { +/// let (valid, after_valid) = input.split_at(error.valid_up_to()); +/// unsafe { +/// push(std::str::from_utf8_unchecked(valid)) +/// } +/// push("\u{FFFD}"); +/// +/// if let Some(invalid_sequence_length) = error.error_len() { +/// input = &after_valid[invalid_sequence_length..] +/// } else { +/// break +/// } +/// } +/// } +/// } +/// } +/// ``` +#[derive(Copy, Eq, PartialEq, Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Utf8Error { + pub(super) valid_up_to: usize, + pub(super) error_len: Option, +} + +impl Utf8Error { + /// Returns the index in the given string up to which valid UTF-8 was + /// verified. + /// + /// It is the maximum index such that `from_utf8(&input[..index])` + /// would return `Ok(_)`. + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// use std::str; + /// + /// // some invalid bytes, in a vector + /// let sparkle_heart = vec![0, 159, 146, 150]; + /// + /// // std::str::from_utf8 returns a Utf8Error + /// let error = str::from_utf8(&sparkle_heart).unwrap_err(); + /// + /// // the second byte is invalid here + /// assert_eq!(1, error.valid_up_to()); + /// ``` + #[stable(feature = "utf8_error", since = "1.5.0")] + pub fn valid_up_to(&self) -> usize { + self.valid_up_to + } + + /// Provides more information about the failure: + /// + /// * `None`: the end of the input was reached unexpectedly. + /// `self.valid_up_to()` is 1 to 3 bytes from the end of the input. + /// If a byte stream (such as a file or a network socket) is being decoded incrementally, + /// this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks. + /// + /// * `Some(len)`: an unexpected byte was encountered. + /// The length provided is that of the invalid byte sequence + /// that starts at the index given by `valid_up_to()`. + /// Decoding should resume after that sequence + /// (after inserting a [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]) in case of + /// lossy decoding. + /// + /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html + #[stable(feature = "utf8_error_error_len", since = "1.20.0")] + pub fn error_len(&self) -> Option { + self.error_len.map(|len| len as usize) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for Utf8Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + if let Some(error_len) = self.error_len { + write!( + f, + "invalid utf-8 sequence of {} bytes from index {}", + error_len, self.valid_up_to + ) + } else { + write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to) + } + } +} + +/// An error returned when parsing a `bool` using [`from_str`] fails +/// +/// [`from_str`]: super::FromStr::from_str +#[derive(Debug, Clone, PartialEq, Eq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseBoolError { + pub(super) _priv: (), +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseBoolError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + "provided string was not `true` or `false`".fmt(f) + } +} diff --git a/library/core/src/str/iter.rs b/library/core/src/str/iter.rs new file mode 100644 index 0000000000..27a67e2b22 --- /dev/null +++ b/library/core/src/str/iter.rs @@ -0,0 +1,1255 @@ +//! Iterators for `str` methods. + +use crate::char; +use crate::fmt::{self, Write}; +use crate::iter::TrustedRandomAccess; +use crate::iter::{Chain, FlatMap, Flatten}; +use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen}; +use crate::ops::Try; +use crate::option; +use crate::slice::{self, Split as SliceSplit}; + +use super::from_utf8_unchecked; +use super::pattern::Pattern; +use super::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; +use super::validations::{next_code_point, next_code_point_reverse, utf8_is_cont_byte}; +use super::LinesAnyMap; +use super::{BytesIsNotEmpty, UnsafeBytesToStr}; +use super::{CharEscapeDebugContinue, CharEscapeDefault, CharEscapeUnicode}; +use super::{IsAsciiWhitespace, IsNotEmpty, IsWhitespace}; + +/// An iterator over the [`char`]s of a string slice. +/// +/// +/// This struct is created by the [`chars`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char`]: prim@char +/// [`chars`]: str::chars +#[derive(Clone)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct Chars<'a> { + pub(super) iter: slice::Iter<'a, u8>, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for Chars<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { + next_code_point(&mut self.iter).map(|ch| { + // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. + unsafe { char::from_u32_unchecked(ch) } + }) + } + + #[inline] + fn count(self) -> usize { + // length in `char` is equal to the number of non-continuation bytes + let bytes_len = self.iter.len(); + let mut cont_bytes = 0; + for &byte in self.iter { + cont_bytes += utf8_is_cont_byte(byte) as usize; + } + bytes_len - cont_bytes + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.iter.len(); + // `(len + 3)` can't overflow, because we know that the `slice::Iter` + // belongs to a slice in memory which has a maximum length of + // `isize::MAX` (that's well below `usize::MAX`). + ((len + 3) / 4, Some(len)) + } + + #[inline] + fn last(mut self) -> Option { + // No need to go through the entire string. + self.next_back() + } +} + +#[stable(feature = "chars_debug_impl", since = "1.38.0")] +impl fmt::Debug for Chars<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "Chars(")?; + f.debug_list().entries(self.clone()).finish()?; + write!(f, ")")?; + Ok(()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for Chars<'a> { + #[inline] + fn next_back(&mut self) -> Option { + next_code_point_reverse(&mut self.iter).map(|ch| { + // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. + unsafe { char::from_u32_unchecked(ch) } + }) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Chars<'_> {} + +impl<'a> Chars<'a> { + /// Views the underlying data as a subslice of the original data. + /// + /// This has the same lifetime as the original slice, and so the + /// iterator can continue to be used while this exists. + /// + /// # Examples + /// + /// ``` + /// let mut chars = "abc".chars(); + /// + /// assert_eq!(chars.as_str(), "abc"); + /// chars.next(); + /// assert_eq!(chars.as_str(), "bc"); + /// chars.next(); + /// chars.next(); + /// assert_eq!(chars.as_str(), ""); + /// ``` + #[stable(feature = "iter_to_slice", since = "1.4.0")] + #[inline] + pub fn as_str(&self) -> &'a str { + // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. + unsafe { from_utf8_unchecked(self.iter.as_slice()) } + } +} + +/// An iterator over the [`char`]s of a string slice, and their positions. +/// +/// This struct is created by the [`char_indices`] method on [`str`]. +/// See its documentation for more. +/// +/// [`char`]: prim@char +/// [`char_indices`]: str::char_indices +#[derive(Clone, Debug)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct CharIndices<'a> { + pub(super) front_offset: usize, + pub(super) iter: Chars<'a>, +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for CharIndices<'a> { + type Item = (usize, char); + + #[inline] + fn next(&mut self) -> Option<(usize, char)> { + let pre_len = self.iter.iter.len(); + match self.iter.next() { + None => None, + Some(ch) => { + let index = self.front_offset; + let len = self.iter.iter.len(); + self.front_offset += pre_len - len; + Some((index, ch)) + } + } + } + + #[inline] + fn count(self) -> usize { + self.iter.count() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } + + #[inline] + fn last(mut self) -> Option<(usize, char)> { + // No need to go through the entire string. + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for CharIndices<'a> { + #[inline] + fn next_back(&mut self) -> Option<(usize, char)> { + self.iter.next_back().map(|ch| { + let index = self.front_offset + self.iter.iter.len(); + (index, ch) + }) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for CharIndices<'_> {} + +impl<'a> CharIndices<'a> { + /// Views the underlying data as a subslice of the original data. + /// + /// 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")] + #[inline] + pub fn as_str(&self) -> &'a str { + self.iter.as_str() + } +} + +/// An iterator over the bytes of a string slice. +/// +/// This struct is created by the [`bytes`] method on [`str`]. +/// See its documentation for more. +/// +/// [`bytes`]: str::bytes +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone, Debug)] +pub struct Bytes<'a>(pub(super) Copied>); + +#[stable(feature = "rust1", since = "1.0.0")] +impl Iterator for Bytes<'_> { + type Item = u8; + + #[inline] + fn next(&mut self) -> Option { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn count(self) -> usize { + self.0.count() + } + + #[inline] + fn last(self) -> Option { + self.0.last() + } + + #[inline] + fn nth(&mut self, n: usize) -> Option { + self.0.nth(n) + } + + #[inline] + fn all(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + self.0.all(f) + } + + #[inline] + fn any(&mut self, f: F) -> bool + where + F: FnMut(Self::Item) -> bool, + { + self.0.any(f) + } + + #[inline] + fn find

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.0.find(predicate) + } + + #[inline] + fn position

(&mut self, predicate: P) -> Option + where + P: FnMut(Self::Item) -> bool, + { + self.0.position(predicate) + } + + #[inline] + fn rposition

(&mut self, predicate: P) -> Option + where + P: FnMut(Self::Item) -> bool, + { + self.0.rposition(predicate) + } + + #[inline] + unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 { + // SAFETY: the caller must uphold the safety contract + // for `Iterator::__iterator_get_unchecked`. + unsafe { self.0.__iterator_get_unchecked(idx) } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl DoubleEndedIterator for Bytes<'_> { + #[inline] + fn next_back(&mut self) -> Option { + self.0.next_back() + } + + #[inline] + fn nth_back(&mut self, n: usize) -> Option { + self.0.nth_back(n) + } + + #[inline] + fn rfind

(&mut self, predicate: P) -> Option + where + P: FnMut(&Self::Item) -> bool, + { + self.0.rfind(predicate) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ExactSizeIterator for Bytes<'_> { + #[inline] + fn len(&self) -> usize { + self.0.len() + } + + #[inline] + fn is_empty(&self) -> bool { + self.0.is_empty() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Bytes<'_> {} + +#[unstable(feature = "trusted_len", issue = "37572")] +unsafe impl TrustedLen for Bytes<'_> {} + +#[doc(hidden)] +#[unstable(feature = "trusted_random_access", issue = "none")] +unsafe impl TrustedRandomAccess for Bytes<'_> { + fn may_have_side_effect() -> bool { + false + } +} + +/// This macro generates a Clone impl for string pattern API +/// wrapper types of the form X<'a, P> +macro_rules! derive_pattern_clone { + (clone $t:ident with |$s:ident| $e:expr) => { + impl<'a, P> Clone for $t<'a, P> + where + P: Pattern<'a, Searcher: Clone>, + { + fn clone(&self) -> Self { + let $s = self; + $e + } + } + }; +} + +/// This macro generates two public iterator structs +/// wrapping a private internal one that makes use of the `Pattern` API. +/// +/// For all patterns `P: Pattern<'a>` the following items will be +/// generated (generics omitted): +/// +/// struct $forward_iterator($internal_iterator); +/// struct $reverse_iterator($internal_iterator); +/// +/// impl Iterator for $forward_iterator +/// { /* internal ends up calling Searcher::next_match() */ } +/// +/// impl DoubleEndedIterator for $forward_iterator +/// where P::Searcher: DoubleEndedSearcher +/// { /* internal ends up calling Searcher::next_match_back() */ } +/// +/// impl Iterator for $reverse_iterator +/// where P::Searcher: ReverseSearcher +/// { /* internal ends up calling Searcher::next_match_back() */ } +/// +/// impl DoubleEndedIterator for $reverse_iterator +/// where P::Searcher: DoubleEndedSearcher +/// { /* internal ends up calling Searcher::next_match() */ } +/// +/// The internal one is defined outside the macro, and has almost the same +/// semantic as a DoubleEndedIterator by delegating to `pattern::Searcher` and +/// `pattern::ReverseSearcher` for both forward and reverse iteration. +/// +/// "Almost", because a `Searcher` and a `ReverseSearcher` for a given +/// `Pattern` might not return the same elements, so actually implementing +/// `DoubleEndedIterator` for it would be incorrect. +/// (See the docs in `str::pattern` for more details) +/// +/// However, the internal struct still represents a single ended iterator from +/// either end, and depending on pattern is also a valid double ended iterator, +/// so the two wrapper structs implement `Iterator` +/// and `DoubleEndedIterator` depending on the concrete pattern type, leading +/// to the complex impls seen above. +macro_rules! generate_pattern_iterators { + { + // Forward iterator + forward: + $(#[$forward_iterator_attribute:meta])* + struct $forward_iterator:ident; + + // Reverse iterator + reverse: + $(#[$reverse_iterator_attribute:meta])* + struct $reverse_iterator:ident; + + // Stability of all generated items + stability: + $(#[$common_stability_attribute:meta])* + + // Internal almost-iterator that is being delegated to + internal: + $internal_iterator:ident yielding ($iterty:ty); + + // Kind of delegation - either single ended or double ended + delegate $($t:tt)* + } => { + $(#[$forward_iterator_attribute])* + $(#[$common_stability_attribute])* + pub struct $forward_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + + $(#[$common_stability_attribute])* + impl<'a, P> fmt::Debug for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple(stringify!($forward_iterator)) + .field(&self.0) + .finish() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { + type Item = $iterty; + + #[inline] + fn next(&mut self) -> Option<$iterty> { + self.0.next() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> Clone for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: Clone>, + { + fn clone(&self) -> Self { + $forward_iterator(self.0.clone()) + } + } + + $(#[$reverse_iterator_attribute])* + $(#[$common_stability_attribute])* + pub struct $reverse_iterator<'a, P: Pattern<'a>>(pub(super) $internal_iterator<'a, P>); + + $(#[$common_stability_attribute])* + impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: fmt::Debug>, + { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple(stringify!($reverse_iterator)) + .field(&self.0) + .finish() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> Iterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + { + type Item = $iterty; + + #[inline] + fn next(&mut self) -> Option<$iterty> { + self.0.next_back() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> Clone for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: Clone>, + { + fn clone(&self) -> Self { + $reverse_iterator(self.0.clone()) + } + } + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} + + #[stable(feature = "fused", since = "1.26.0")] + impl<'a, P> FusedIterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: ReverseSearcher<'a>>, + {} + + generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, + $forward_iterator, + $reverse_iterator, $iterty); + }; + { + double ended; with $(#[$common_stability_attribute:meta])*, + $forward_iterator:ident, + $reverse_iterator:ident, $iterty:ty + } => { + $(#[$common_stability_attribute])* + impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> + where + P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + { + #[inline] + fn next_back(&mut self) -> Option<$iterty> { + self.0.next_back() + } + } + + $(#[$common_stability_attribute])* + impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> + where + P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, + { + #[inline] + fn next_back(&mut self) -> Option<$iterty> { + self.0.next() + } + } + }; + { + single ended; with $(#[$common_stability_attribute:meta])*, + $forward_iterator:ident, + $reverse_iterator:ident, $iterty:ty + } => {} +} + +derive_pattern_clone! { + clone SplitInternal + with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } +} + +pub(super) struct SplitInternal<'a, P: Pattern<'a>> { + pub(super) start: usize, + pub(super) end: usize, + pub(super) matcher: P::Searcher, + pub(super) allow_trailing_empty: bool, + pub(super) finished: bool, +} + +impl<'a, P> fmt::Debug for SplitInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInternal") + .field("start", &self.start) + .field("end", &self.end) + .field("matcher", &self.matcher) + .field("allow_trailing_empty", &self.allow_trailing_empty) + .field("finished", &self.finished) + .finish() + } +} + +impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { + #[inline] + fn get_end(&mut self) -> Option<&'a str> { + if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { + self.finished = true; + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + unsafe { + let string = self.matcher.haystack().get_unchecked(self.start..self.end); + Some(string) + } + } else { + None + } + } + + #[inline] + fn next(&mut self) -> Option<&'a str> { + if self.finished { + return None; + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let elt = haystack.get_unchecked(self.start..a); + self.start = b; + Some(elt) + }, + None => self.get_end(), + } + } + + #[inline] + fn next_inclusive(&mut self) -> Option<&'a str> { + if self.finished { + return None; + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match() { + // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, + // and self.start is either the start of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + Some((_, b)) => unsafe { + let elt = haystack.get_unchecked(self.start..b); + self.start = b; + Some(elt) + }, + None => self.get_end(), + } + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + if self.finished { + return None; + } + + if !self.allow_trailing_empty { + self.allow_trailing_empty = true; + match self.next_back() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } + } + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match_back() { + // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. + Some((a, b)) => unsafe { + let elt = haystack.get_unchecked(b..self.end); + self.end = a; + Some(elt) + }, + // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. + None => unsafe { + self.finished = true; + Some(haystack.get_unchecked(self.start..self.end)) + }, + } + } + + #[inline] + fn next_back_inclusive(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + if self.finished { + return None; + } + + if !self.allow_trailing_empty { + self.allow_trailing_empty = true; + match self.next_back_inclusive() { + Some(elt) if !elt.is_empty() => return Some(elt), + _ => { + if self.finished { + return None; + } + } + } + } + + let haystack = self.matcher.haystack(); + match self.matcher.next_match_back() { + // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, + // and self.end is either the end of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + Some((_, b)) => unsafe { + let elt = haystack.get_unchecked(b..self.end); + self.end = b; + Some(elt) + }, + // SAFETY: self.start is either the start of the original string, + // or start of a substring that represents the part of the string that hasn't + // iterated yet. Either way, it is guaranteed to lie on unicode boundary. + // self.end is either the end of the original string, + // or `b` was assigned to it, so it also lies on unicode boundary. + None => unsafe { + self.finished = true; + Some(haystack.get_unchecked(self.start..self.end)) + }, + } + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`split`]. + /// + /// [`split`]: str::split + struct Split; + reverse: + /// Created with the method [`rsplit`]. + /// + /// [`rsplit`]: str::rsplit + struct RSplit; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitInternal yielding (&'a str); + delegate double ended; +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`split_terminator`]. + /// + /// [`split_terminator`]: str::split_terminator + struct SplitTerminator; + reverse: + /// Created with the method [`rsplit_terminator`]. + /// + /// [`rsplit_terminator`]: str::rsplit_terminator + struct RSplitTerminator; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitInternal yielding (&'a str); + delegate double ended; +} + +derive_pattern_clone! { + clone SplitNInternal + with |s| SplitNInternal { iter: s.iter.clone(), ..*s } +} + +pub(super) struct SplitNInternal<'a, P: Pattern<'a>> { + pub(super) iter: SplitInternal<'a, P>, + /// The number of splits remaining + pub(super) count: usize, +} + +impl<'a, P> fmt::Debug for SplitNInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitNInternal") + .field("iter", &self.iter) + .field("count", &self.count) + .finish() + } +} + +impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<&'a str> { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.get_end() + } + _ => { + self.count -= 1; + self.iter.next() + } + } + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + match self.count { + 0 => None, + 1 => { + self.count = 0; + self.iter.get_end() + } + _ => { + self.count -= 1; + self.iter.next_back() + } + } + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`splitn`]. + /// + /// [`splitn`]: str::splitn + struct SplitN; + reverse: + /// Created with the method [`rsplitn`]. + /// + /// [`rsplitn`]: str::rsplitn + struct RSplitN; + stability: + #[stable(feature = "rust1", since = "1.0.0")] + internal: + SplitNInternal yielding (&'a str); + delegate single ended; +} + +derive_pattern_clone! { + clone MatchIndicesInternal + with |s| MatchIndicesInternal(s.0.clone()) +} + +pub(super) struct MatchIndicesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); + +impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("MatchIndicesInternal").field(&self.0).finish() + } +} + +impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<(usize, &'a str)> { + self.0 + .next_match() + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) + } + + #[inline] + fn next_back(&mut self) -> Option<(usize, &'a str)> + where + P::Searcher: ReverseSearcher<'a>, + { + self.0 + .next_match_back() + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`match_indices`]. + /// + /// [`match_indices`]: str::match_indices + struct MatchIndices; + reverse: + /// Created with the method [`rmatch_indices`]. + /// + /// [`rmatch_indices`]: str::rmatch_indices + struct RMatchIndices; + stability: + #[stable(feature = "str_match_indices", since = "1.5.0")] + internal: + MatchIndicesInternal yielding ((usize, &'a str)); + delegate double ended; +} + +derive_pattern_clone! { + clone MatchesInternal + with |s| MatchesInternal(s.0.clone()) +} + +pub(super) struct MatchesInternal<'a, P: Pattern<'a>>(pub(super) P::Searcher); + +impl<'a, P> fmt::Debug for MatchesInternal<'a, P> +where + P: Pattern<'a, Searcher: fmt::Debug>, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_tuple("MatchesInternal").field(&self.0).finish() + } +} + +impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { + #[inline] + fn next(&mut self) -> Option<&'a str> { + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + self.0.next_match().map(|(a, b)| unsafe { + // Indices are known to be on utf8 boundaries + self.0.haystack().get_unchecked(a..b) + }) + } + + #[inline] + fn next_back(&mut self) -> Option<&'a str> + where + P::Searcher: ReverseSearcher<'a>, + { + // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. + self.0.next_match_back().map(|(a, b)| unsafe { + // Indices are known to be on utf8 boundaries + self.0.haystack().get_unchecked(a..b) + }) + } +} + +generate_pattern_iterators! { + forward: + /// Created with the method [`matches`]. + /// + /// [`matches`]: str::matches + struct Matches; + reverse: + /// Created with the method [`rmatches`]. + /// + /// [`rmatches`]: str::rmatches + struct RMatches; + stability: + #[stable(feature = "str_matches", since = "1.2.0")] + internal: + MatchesInternal yielding (&'a str); + delegate double ended; +} + +/// An iterator over the lines of a string, as string slices. +/// +/// This struct is created with the [`lines`] method on [`str`]. +/// See its documentation for more. +/// +/// [`lines`]: str::lines +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(Clone, Debug)] +pub struct Lines<'a>(pub(super) Map, LinesAnyMap>); + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> Iterator for Lines<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } + + #[inline] + fn last(mut self) -> Option<&'a str> { + self.next_back() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl<'a> DoubleEndedIterator for Lines<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for Lines<'_> {} + +/// Created with the method [`lines_any`]. +/// +/// [`lines_any`]: str::lines_any +#[stable(feature = "rust1", since = "1.0.0")] +#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")] +#[derive(Clone, Debug)] +#[allow(deprecated)] +pub struct LinesAny<'a>(pub(super) Lines<'a>); + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl<'a> Iterator for LinesAny<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.0.size_hint() + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +impl<'a> DoubleEndedIterator for LinesAny<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +#[allow(deprecated)] +impl FusedIterator for LinesAny<'_> {} + +/// An iterator over the non-whitespace substrings of a string, +/// separated by any amount of whitespace. +/// +/// This struct is created by the [`split_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_whitespace`]: str::split_whitespace +#[stable(feature = "split_whitespace", since = "1.1.0")] +#[derive(Clone, Debug)] +pub struct SplitWhitespace<'a> { + pub(super) inner: Filter, IsNotEmpty>, +} + +/// An iterator over the non-ASCII-whitespace substrings of a string, +/// separated by any amount of ASCII whitespace. +/// +/// This struct is created by the [`split_ascii_whitespace`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_ascii_whitespace`]: str::split_ascii_whitespace +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct SplitAsciiWhitespace<'a> { + pub(super) inner: + Map, BytesIsNotEmpty>, UnsafeBytesToStr>, +} + +/// An iterator over the substrings of a string, +/// terminated by a substring matching to a predicate function +/// Unlike `Split`, it contains the matched part as a terminator +/// of the subslice. +/// +/// This struct is created by the [`split_inclusive`] method on [`str`]. +/// See its documentation for more. +/// +/// [`split_inclusive`]: str::split_inclusive +#[unstable(feature = "split_inclusive", issue = "72360")] +pub struct SplitInclusive<'a, P: Pattern<'a>>(pub(super) SplitInternal<'a, P>); + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> Iterator for SplitWhitespace<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + #[inline] + fn last(mut self) -> Option<&'a str> { + self.next_back() + } +} + +#[stable(feature = "split_whitespace", since = "1.1.0")] +impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for SplitWhitespace<'_> {} + +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +impl<'a> Iterator for SplitAsciiWhitespace<'a> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.inner.next() + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } + + #[inline] + fn last(mut self) -> Option<&'a str> { + self.next_back() + } +} + +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.inner.next_back() + } +} + +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +impl FusedIterator for SplitAsciiWhitespace<'_> {} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { + type Item = &'a str; + + #[inline] + fn next(&mut self) -> Option<&'a str> { + self.0.next_inclusive() + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("SplitInclusive").field("0", &self.0).finish() + } +} + +// FIXME(#26925) Remove in favor of `#[derive(Clone)]` +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { + fn clone(&self) -> Self { + SplitInclusive(self.0.clone()) + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator + for SplitInclusive<'a, P> +{ + #[inline] + fn next_back(&mut self) -> Option<&'a str> { + self.0.next_back_inclusive() + } +} + +#[unstable(feature = "split_inclusive", issue = "72360")] +impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} + +/// An iterator of [`u16`] over the string encoded as UTF-16. +/// +/// This struct is created by the [`encode_utf16`] method on [`str`]. +/// See its documentation for more. +/// +/// [`encode_utf16`]: str::encode_utf16 +#[derive(Clone)] +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub struct EncodeUtf16<'a> { + pub(super) chars: Chars<'a>, + pub(super) extra: u16, +} + +#[stable(feature = "collection_debug", since = "1.17.0")] +impl fmt::Debug for EncodeUtf16<'_> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("EncodeUtf16 { .. }") + } +} + +#[stable(feature = "encode_utf16", since = "1.8.0")] +impl<'a> Iterator for EncodeUtf16<'a> { + type Item = u16; + + #[inline] + fn next(&mut self) -> Option { + if self.extra != 0 { + let tmp = self.extra; + self.extra = 0; + return Some(tmp); + } + + let mut buf = [0; 2]; + self.chars.next().map(|ch| { + let n = ch.encode_utf16(&mut buf).len(); + if n == 2 { + self.extra = buf[1]; + } + buf[0] + }) + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let (low, high) = self.chars.size_hint(); + // every char gets either one u16 or two u16, + // so this iterator is between 1 or 2 times as + // long as the underlying iterator. + (low, high.and_then(|n| n.checked_mul(2))) + } +} + +#[stable(feature = "fused", since = "1.26.0")] +impl FusedIterator for EncodeUtf16<'_> {} + +/// The return type of [`str::escape_debug`]. +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeDebug<'a> { + pub(super) inner: Chain< + Flatten>, + FlatMap, char::EscapeDebug, CharEscapeDebugContinue>, + >, +} + +/// The return type of [`str::escape_default`]. +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeDefault<'a> { + pub(super) inner: FlatMap, char::EscapeDefault, CharEscapeDefault>, +} + +/// The return type of [`str::escape_unicode`]. +#[stable(feature = "str_escape", since = "1.34.0")] +#[derive(Clone, Debug)] +pub struct EscapeUnicode<'a> { + pub(super) inner: FlatMap, char::EscapeUnicode, CharEscapeUnicode>, +} + +macro_rules! escape_types_impls { + ($( $Name: ident ),+) => {$( + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> fmt::Display for $Name<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.clone().try_for_each(|c| f.write_char(c)) + } + } + + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> Iterator for $Name<'a> { + type Item = char; + + #[inline] + fn next(&mut self) -> Option { self.inner.next() } + + #[inline] + fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } + + #[inline] + fn try_fold(&mut self, init: Acc, fold: Fold) -> R where + Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try + { + self.inner.try_fold(init, fold) + } + + #[inline] + fn fold(self, init: Acc, fold: Fold) -> Acc + where Fold: FnMut(Acc, Self::Item) -> Acc, + { + self.inner.fold(init, fold) + } + } + + #[stable(feature = "str_escape", since = "1.34.0")] + impl<'a> FusedIterator for $Name<'a> {} + )+} +} + +escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode); diff --git a/library/core/src/str/lossy.rs b/library/core/src/str/lossy.rs index 88b2bc551b..720a35bbc8 100644 --- a/library/core/src/str/lossy.rs +++ b/library/core/src/str/lossy.rs @@ -1,7 +1,9 @@ use crate::char; use crate::fmt::{self, Write}; use crate::mem; -use crate::str as core_str; + +use super::from_utf8_unchecked; +use super::validations::utf8_char_width; /// Lossy UTF-8 string. #[unstable(feature = "str_internals", issue = "none")] @@ -66,14 +68,14 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { if byte < 128 { } else { - let w = core_str::utf8_char_width(byte); + let w = utf8_char_width(byte); macro_rules! error { () => {{ // SAFETY: We have checked up to `i` that source is valid UTF-8. unsafe { let r = Utf8LossyChunk { - valid: core_str::from_utf8_unchecked(&self.source[0..i_]), + valid: from_utf8_unchecked(&self.source[0..i_]), broken: &self.source[i_..i], }; self.source = &self.source[i..]; @@ -133,7 +135,7 @@ impl<'a> Iterator for Utf8LossyChunksIter<'a> { let r = Utf8LossyChunk { // SAFETY: We have checked that the entire source is valid UTF-8. - valid: unsafe { core_str::from_utf8_unchecked(self.source) }, + valid: unsafe { from_utf8_unchecked(self.source) }, broken: &[], }; self.source = &[]; diff --git a/library/core/src/str/mod.rs b/library/core/src/str/mod.rs index d7af5dd860..3e18a4e706 100644 --- a/library/core/src/str/mod.rs +++ b/library/core/src/str/mod.rs @@ -1,25 +1,23 @@ -// ignore-tidy-filelength - //! String manipulation. //! //! For more details, see the [`std::str`] module. //! -//! [`std::str`]: self +//! [`std::str`]: ../../std/str/index.html #![stable(feature = "rust1", since = "1.0.0")] +mod converts; +mod error; +mod iter; +mod traits; +mod validations; + use self::pattern::Pattern; use self::pattern::{DoubleEndedSearcher, ReverseSearcher, Searcher}; use crate::char; -use crate::fmt::{self, Write}; -use crate::iter::TrustedRandomAccess; -use crate::iter::{Chain, FlatMap, Flatten}; -use crate::iter::{Copied, Filter, FusedIterator, Map, TrustedLen}; use crate::mem; -use crate::ops::Try; -use crate::option; -use crate::slice::{self, SliceIndex, Split as SliceSplit}; +use crate::slice::{self, SliceIndex}; pub mod pattern; @@ -27,2202 +25,57 @@ pub mod pattern; #[allow(missing_docs)] pub mod lossy; -/// Parse a value from a string -/// -/// `FromStr`'s [`from_str`] method is often used implicitly, through -/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples. -/// -/// [`from_str`]: FromStr::from_str -/// [`parse`]: str::parse -/// -/// `FromStr` does not have a lifetime parameter, and so you can only parse types -/// that do not contain a lifetime parameter themselves. In other words, you can -/// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that -/// contains an `i32`, but not one that contains an `&i32`. -/// -/// # Examples -/// -/// Basic implementation of `FromStr` on an example `Point` type: -/// -/// ``` -/// use std::str::FromStr; -/// use std::num::ParseIntError; -/// -/// #[derive(Debug, PartialEq)] -/// struct Point { -/// x: i32, -/// y: i32 -/// } -/// -/// impl FromStr for Point { -/// type Err = ParseIntError; -/// -/// fn from_str(s: &str) -> Result { -/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) -/// .split(',') -/// .collect(); -/// -/// let x_fromstr = coords[0].parse::()?; -/// let y_fromstr = coords[1].parse::()?; -/// -/// Ok(Point { x: x_fromstr, y: y_fromstr }) -/// } -/// } -/// -/// let p = Point::from_str("(1,2)"); -/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) -/// ``` #[stable(feature = "rust1", since = "1.0.0")] -pub trait FromStr: Sized { - /// The associated error which can be returned from parsing. - #[stable(feature = "rust1", since = "1.0.0")] - type Err; +pub use converts::{from_utf8, from_utf8_unchecked}; - /// Parses a string `s` to return a value of this type. - /// - /// 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. - /// - /// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok - /// [`Err`]: ../../std/result/enum.Result.html#variant.Err - /// - /// # Examples - /// - /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`: - /// - /// [ithirtytwo]: ../../std/primitive.i32.html - /// - /// ``` - /// use std::str::FromStr; - /// - /// let s = "5"; - /// let x = i32::from_str(s).unwrap(); - /// - /// assert_eq!(5, x); - /// ``` - #[stable(feature = "rust1", since = "1.0.0")] - fn from_str(s: &str) -> Result; -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl FromStr for bool { - type Err = ParseBoolError; - - /// Parse a `bool` from a string. - /// - /// Yields a `Result`, because `s` may or may not - /// actually be parseable. - /// - /// # Examples - /// - /// ``` - /// use std::str::FromStr; - /// - /// assert_eq!(FromStr::from_str("true"), Ok(true)); - /// assert_eq!(FromStr::from_str("false"), Ok(false)); - /// assert!(::from_str("not even a boolean").is_err()); - /// ``` - /// - /// Note, in many cases, the `.parse()` method on `str` is more proper. - /// - /// ``` - /// assert_eq!("true".parse(), Ok(true)); - /// assert_eq!("false".parse(), Ok(false)); - /// assert!("not even a boolean".parse::().is_err()); - /// ``` - #[inline] - fn from_str(s: &str) -> Result { - match s { - "true" => Ok(true), - "false" => Ok(false), - _ => Err(ParseBoolError { _priv: () }), - } - } -} - -/// An error returned when parsing a `bool` using [`from_str`] fails -/// -/// [`from_str`]: FromStr::from_str -#[derive(Debug, Clone, PartialEq, Eq)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct ParseBoolError { - _priv: (), -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseBoolError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - "provided string was not `true` or `false`".fmt(f) - } -} - -/* -Section: Creating a string -*/ - -/// Errors which can occur when attempting to interpret a sequence of [`u8`] -/// as a string. -/// -/// As such, the `from_utf8` family of functions and methods for both [`String`]s -/// and [`&str`]s make use of this error, for example. -/// -/// [`String`]: ../../std/string/struct.String.html#method.from_utf8 -/// [`&str`]: from_utf8 -/// -/// # Examples -/// -/// This error type’s methods can be used to create functionality -/// similar to `String::from_utf8_lossy` without allocating heap memory: -/// -/// ``` -/// fn from_utf8_lossy(mut input: &[u8], mut push: F) where F: FnMut(&str) { -/// loop { -/// match std::str::from_utf8(input) { -/// Ok(valid) => { -/// push(valid); -/// break -/// } -/// Err(error) => { -/// let (valid, after_valid) = input.split_at(error.valid_up_to()); -/// unsafe { -/// push(std::str::from_utf8_unchecked(valid)) -/// } -/// push("\u{FFFD}"); -/// -/// if let Some(invalid_sequence_length) = error.error_len() { -/// input = &after_valid[invalid_sequence_length..] -/// } else { -/// break -/// } -/// } -/// } -/// } -/// } -/// ``` -#[derive(Copy, Eq, PartialEq, Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct Utf8Error { - valid_up_to: usize, - error_len: Option, -} - -impl Utf8Error { - /// Returns the index in the given string up to which valid UTF-8 was - /// verified. - /// - /// It is the maximum index such that `from_utf8(&input[..index])` - /// would return `Ok(_)`. - /// - /// # Examples - /// - /// Basic usage: - /// - /// ``` - /// use std::str; - /// - /// // some invalid bytes, in a vector - /// let sparkle_heart = vec![0, 159, 146, 150]; - /// - /// // std::str::from_utf8 returns a Utf8Error - /// let error = str::from_utf8(&sparkle_heart).unwrap_err(); - /// - /// // the second byte is invalid here - /// assert_eq!(1, error.valid_up_to()); - /// ``` - #[stable(feature = "utf8_error", since = "1.5.0")] - pub fn valid_up_to(&self) -> usize { - self.valid_up_to - } - - /// Provides more information about the failure: - /// - /// * `None`: the end of the input was reached unexpectedly. - /// `self.valid_up_to()` is 1 to 3 bytes from the end of the input. - /// If a byte stream (such as a file or a network socket) is being decoded incrementally, - /// this could be a valid `char` whose UTF-8 byte sequence is spanning multiple chunks. - /// - /// * `Some(len)`: an unexpected byte was encountered. - /// The length provided is that of the invalid byte sequence - /// that starts at the index given by `valid_up_to()`. - /// Decoding should resume after that sequence - /// (after inserting a [`U+FFFD REPLACEMENT CHARACTER`][U+FFFD]) in case of - /// lossy decoding. - /// - /// [U+FFFD]: ../../std/char/constant.REPLACEMENT_CHARACTER.html - #[stable(feature = "utf8_error_error_len", since = "1.20.0")] - pub fn error_len(&self) -> Option { - self.error_len.map(|len| len as usize) - } -} - -/// Converts a slice of bytes to a string slice. -/// -/// A string slice ([`&str`]) is made of bytes ([`u8`]), and a byte slice -/// ([`&[u8]`][byteslice]) is made of bytes, so this function converts between -/// the two. Not all byte slices are valid string slices, however: [`&str`] requires -/// that it is valid UTF-8. `from_utf8()` checks to ensure that the bytes are valid -/// UTF-8, and then does the conversion. -/// -/// [`&str`]: str -/// [byteslice]: ../../std/primitive.slice.html -/// -/// If you are sure that the byte slice is valid UTF-8, and you don't want to -/// incur the overhead of the validity check, there is an unsafe version of -/// this function, [`from_utf8_unchecked`][fromutf8u], which has the same -/// behavior but skips the check. -/// -/// [fromutf8u]: fn.from_utf8_unchecked.html -/// -/// If you need a `String` instead of a `&str`, consider -/// [`String::from_utf8`][string]. -/// -/// [string]: ../../std/string/struct.String.html#method.from_utf8 -/// -/// Because you can stack-allocate a `[u8; N]`, and you can take a -/// [`&[u8]`][byteslice] of it, this function is one way to have a -/// stack-allocated string. There is an example of this in the -/// examples section below. -/// -/// [byteslice]: ../../std/primitive.slice.html -/// -/// # Errors -/// -/// Returns `Err` if the slice is not UTF-8 with a description as to why the -/// provided slice is not UTF-8. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// // some bytes, in a vector -/// let sparkle_heart = vec![240, 159, 146, 150]; -/// -/// // We know these bytes are valid, so just use `unwrap()`. -/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); -/// -/// assert_eq!("💖", sparkle_heart); -/// ``` -/// -/// Incorrect bytes: -/// -/// ``` -/// use std::str; -/// -/// // some invalid bytes, in a vector -/// let sparkle_heart = vec![0, 159, 146, 150]; -/// -/// assert!(str::from_utf8(&sparkle_heart).is_err()); -/// ``` -/// -/// See the docs for [`Utf8Error`][error] for more details on the kinds of -/// errors that can be returned. -/// -/// [error]: struct.Utf8Error.html -/// -/// A "stack allocated string": -/// -/// ``` -/// use std::str; -/// -/// // some bytes, in a stack-allocated array -/// let sparkle_heart = [240, 159, 146, 150]; -/// -/// // We know these bytes are valid, so just use `unwrap()`. -/// let sparkle_heart = str::from_utf8(&sparkle_heart).unwrap(); -/// -/// assert_eq!("💖", sparkle_heart); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -pub fn from_utf8(v: &[u8]) -> Result<&str, Utf8Error> { - run_utf8_validation(v)?; - // SAFETY: Just ran validation. - Ok(unsafe { from_utf8_unchecked(v) }) -} - -/// Converts a mutable slice of bytes to a mutable string slice. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// // "Hello, Rust!" as a mutable vector -/// let mut hellorust = vec![72, 101, 108, 108, 111, 44, 32, 82, 117, 115, 116, 33]; -/// -/// // As we know these bytes are valid, we can use `unwrap()` -/// let outstr = str::from_utf8_mut(&mut hellorust).unwrap(); -/// -/// assert_eq!("Hello, Rust!", outstr); -/// ``` -/// -/// Incorrect bytes: -/// -/// ``` -/// use std::str; -/// -/// // Some invalid bytes in a mutable vector -/// let mut invalid = vec![128, 223]; -/// -/// assert!(str::from_utf8_mut(&mut invalid).is_err()); -/// ``` -/// See the docs for [`Utf8Error`][error] for more details on the kinds of -/// errors that can be returned. -/// -/// [error]: struct.Utf8Error.html #[stable(feature = "str_mut_extras", since = "1.20.0")] -pub fn from_utf8_mut(v: &mut [u8]) -> Result<&mut str, Utf8Error> { - run_utf8_validation(v)?; - // SAFETY: Just ran validation. - Ok(unsafe { from_utf8_unchecked_mut(v) }) -} - -/// Converts a slice of bytes to a string slice without checking -/// that the string contains valid UTF-8. -/// -/// See the safe version, [`from_utf8`][fromutf8], for more information. -/// -/// [fromutf8]: fn.from_utf8.html -/// -/// # Safety -/// -/// This function is unsafe because it does not check that the bytes passed to -/// it are valid UTF-8. If this constraint is violated, undefined behavior -/// results, as the rest of Rust assumes that [`&str`]s are valid UTF-8. -/// -/// [`&str`]: str -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// // some bytes, in a vector -/// let sparkle_heart = vec![240, 159, 146, 150]; -/// -/// let sparkle_heart = unsafe { -/// str::from_utf8_unchecked(&sparkle_heart) -/// }; -/// -/// assert_eq!("💖", sparkle_heart); -/// ``` -#[inline] -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_const_unstable(feature = "const_str_from_utf8_unchecked", issue = "75196")] -#[allow(unused_attributes)] -#[allow_internal_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. - unsafe { mem::transmute(v) } -} - -/// Converts a slice of bytes to a string slice without checking -/// that the string contains valid UTF-8; mutable version. -/// -/// See the immutable version, [`from_utf8_unchecked()`] for more information. -/// -/// # Examples -/// -/// Basic usage: -/// -/// ``` -/// use std::str; -/// -/// let mut heart = vec![240, 159, 146, 150]; -/// let heart = unsafe { str::from_utf8_unchecked_mut(&mut heart) }; -/// -/// assert_eq!("💖", heart); -/// ``` -#[inline] -#[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` - // are valid UTF-8, thus the cast to `*mut str` is safe. - // Also, the pointer dereference is safe because that pointer - // comes from a reference which is guaranteed to be valid for writes. - unsafe { &mut *(v as *mut [u8] as *mut str) } -} +pub use converts::{from_utf8_mut, from_utf8_unchecked_mut}; #[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for Utf8Error { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - if let Some(error_len) = self.error_len { - write!( - f, - "invalid utf-8 sequence of {} bytes from index {}", - error_len, self.valid_up_to - ) - } else { - write!(f, "incomplete utf-8 byte sequence from index {}", self.valid_up_to) - } - } -} +pub use error::{ParseBoolError, Utf8Error}; -/* -Section: Iterators -*/ - -/// An iterator over the [`char`]s of a string slice. -/// -/// -/// This struct is created by the [`chars`] method on [`str`]. -/// See its documentation for more. -/// -/// [`char`]: prim@char -/// [`chars`]: str::chars -#[derive(Clone)] #[stable(feature = "rust1", since = "1.0.0")] -pub struct Chars<'a> { - iter: slice::Iter<'a, u8>, -} +pub use traits::FromStr; -/// Returns the initial codepoint accumulator for the first byte. -/// The first byte is special, only want bottom 5 bits for width 2, 4 bits -/// for width 3, and 3 bits for width 4. -#[inline] -fn utf8_first_byte(byte: u8, width: u32) -> u32 { - (byte & (0x7F >> width)) as u32 -} +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{Bytes, CharIndices, Chars, Lines, SplitWhitespace}; -/// Returns the value of `ch` updated with continuation byte `byte`. -#[inline] -fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { - (ch << 6) | (byte & CONT_MASK) as u32 -} +#[stable(feature = "rust1", since = "1.0.0")] +#[allow(deprecated)] +pub use iter::LinesAny; -/// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the -/// bits `10`). -#[inline] -fn utf8_is_cont_byte(byte: u8) -> bool { - (byte & !CONT_MASK) == TAG_CONT_U8 -} +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplit, RSplitTerminator, Split, SplitTerminator}; -#[inline] -fn unwrap_or_0(opt: Option<&u8>) -> u8 { - match opt { - Some(&byte) => byte, - None => 0, - } -} +#[stable(feature = "rust1", since = "1.0.0")] +pub use iter::{RSplitN, SplitN}; + +#[stable(feature = "str_matches", since = "1.2.0")] +pub use iter::{Matches, RMatches}; + +#[stable(feature = "str_match_indices", since = "1.5.0")] +pub use iter::{MatchIndices, RMatchIndices}; + +#[stable(feature = "encode_utf16", since = "1.8.0")] +pub use iter::EncodeUtf16; + +#[stable(feature = "str_escape", since = "1.34.0")] +pub use iter::{EscapeDebug, EscapeDefault, EscapeUnicode}; + +#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] +pub use iter::SplitAsciiWhitespace; + +#[unstable(feature = "split_inclusive", issue = "72360")] +use iter::SplitInclusive; -/// Reads the next code point out of a byte iterator (assuming a -/// UTF-8-like encoding). #[unstable(feature = "str_internals", issue = "none")] -#[inline] -pub fn next_code_point<'a, I: Iterator>(bytes: &mut I) -> Option { - // Decode UTF-8 - let x = *bytes.next()?; - if x < 128 { - return Some(x as u32); - } +pub use validations::next_code_point; - // Multibyte case follows - // Decode from a byte combination out of: [[[x y] z] w] - // NOTE: Performance is sensitive to the exact formulation here - let init = utf8_first_byte(x, 2); - let y = unwrap_or_0(bytes.next()); - let mut ch = utf8_acc_cont_byte(init, y); - if x >= 0xE0 { - // [[x y z] w] case - // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid - let z = unwrap_or_0(bytes.next()); - let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z); - ch = init << 12 | y_z; - if x >= 0xF0 { - // [x y z w] case - // use only the lower 3 bits of `init` - let w = unwrap_or_0(bytes.next()); - ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w); - } - } +use iter::MatchIndicesInternal; +use iter::SplitInternal; +use iter::{MatchesInternal, SplitNInternal}; - Some(ch) -} - -/// Reads the last code point out of a byte iterator (assuming a -/// UTF-8-like encoding). -#[inline] -fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option -where - I: DoubleEndedIterator, -{ - // Decode UTF-8 - let w = match *bytes.next_back()? { - next_byte if next_byte < 128 => return Some(next_byte as u32), - back_byte => back_byte, - }; - - // Multibyte case follows - // Decode from a byte combination out of: [x [y [z w]]] - let mut ch; - let z = unwrap_or_0(bytes.next_back()); - ch = utf8_first_byte(z, 2); - if utf8_is_cont_byte(z) { - let y = unwrap_or_0(bytes.next_back()); - ch = utf8_first_byte(y, 3); - if utf8_is_cont_byte(y) { - let x = unwrap_or_0(bytes.next_back()); - ch = utf8_first_byte(x, 4); - ch = utf8_acc_cont_byte(ch, y); - } - ch = utf8_acc_cont_byte(ch, z); - } - ch = utf8_acc_cont_byte(ch, w); - - Some(ch) -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Chars<'a> { - type Item = char; - - #[inline] - fn next(&mut self) -> Option { - next_code_point(&mut self.iter).map(|ch| { - // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. - unsafe { char::from_u32_unchecked(ch) } - }) - } - - #[inline] - fn count(self) -> usize { - // length in `char` is equal to the number of non-continuation bytes - let bytes_len = self.iter.len(); - let mut cont_bytes = 0; - for &byte in self.iter { - cont_bytes += utf8_is_cont_byte(byte) as usize; - } - bytes_len - cont_bytes - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.iter.len(); - // `(len + 3)` can't overflow, because we know that the `slice::Iter` - // belongs to a slice in memory which has a maximum length of - // `isize::MAX` (that's well below `usize::MAX`). - ((len + 3) / 4, Some(len)) - } - - #[inline] - fn last(mut self) -> Option { - // No need to go through the entire string. - self.next_back() - } -} - -#[stable(feature = "chars_debug_impl", since = "1.38.0")] -impl fmt::Debug for Chars<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "Chars(")?; - f.debug_list().entries(self.clone()).finish()?; - write!(f, ")")?; - Ok(()) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Chars<'a> { - #[inline] - fn next_back(&mut self) -> Option { - next_code_point_reverse(&mut self.iter).map(|ch| { - // SAFETY: `str` invariant says `ch` is a valid Unicode Scalar Value. - unsafe { char::from_u32_unchecked(ch) } - }) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Chars<'_> {} - -impl<'a> Chars<'a> { - /// Views the underlying data as a subslice of the original data. - /// - /// This has the same lifetime as the original slice, and so the - /// iterator can continue to be used while this exists. - /// - /// # Examples - /// - /// ``` - /// let mut chars = "abc".chars(); - /// - /// assert_eq!(chars.as_str(), "abc"); - /// chars.next(); - /// assert_eq!(chars.as_str(), "bc"); - /// chars.next(); - /// chars.next(); - /// assert_eq!(chars.as_str(), ""); - /// ``` - #[stable(feature = "iter_to_slice", since = "1.4.0")] - #[inline] - pub fn as_str(&self) -> &'a str { - // SAFETY: `Chars` is only made from a str, which guarantees the iter is valid UTF-8. - unsafe { from_utf8_unchecked(self.iter.as_slice()) } - } -} - -/// An iterator over the [`char`]s of a string slice, and their positions. -/// -/// This struct is created by the [`char_indices`] method on [`str`]. -/// See its documentation for more. -/// -/// [`char`]: prim@char -/// [`char_indices`]: str::char_indices -#[derive(Clone, Debug)] -#[stable(feature = "rust1", since = "1.0.0")] -pub struct CharIndices<'a> { - front_offset: usize, - iter: Chars<'a>, -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for CharIndices<'a> { - type Item = (usize, char); - - #[inline] - fn next(&mut self) -> Option<(usize, char)> { - let pre_len = self.iter.iter.len(); - match self.iter.next() { - None => None, - Some(ch) => { - let index = self.front_offset; - let len = self.iter.iter.len(); - self.front_offset += pre_len - len; - Some((index, ch)) - } - } - } - - #[inline] - fn count(self) -> usize { - self.iter.count() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - #[inline] - fn last(mut self) -> Option<(usize, char)> { - // No need to go through the entire string. - self.next_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for CharIndices<'a> { - #[inline] - fn next_back(&mut self) -> Option<(usize, char)> { - self.iter.next_back().map(|ch| { - let index = self.front_offset + self.iter.iter.len(); - (index, ch) - }) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for CharIndices<'_> {} - -impl<'a> CharIndices<'a> { - /// Views the underlying data as a subslice of the original data. - /// - /// 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")] - #[inline] - pub fn as_str(&self) -> &'a str { - self.iter.as_str() - } -} - -/// An iterator over the bytes of a string slice. -/// -/// This struct is created by the [`bytes`] method on [`str`]. -/// See its documentation for more. -/// -/// [`bytes`]: str::bytes -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug)] -pub struct Bytes<'a>(Copied>); - -#[stable(feature = "rust1", since = "1.0.0")] -impl Iterator for Bytes<'_> { - type Item = u8; - - #[inline] - fn next(&mut self) -> Option { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - #[inline] - fn count(self) -> usize { - self.0.count() - } - - #[inline] - fn last(self) -> Option { - self.0.last() - } - - #[inline] - fn nth(&mut self, n: usize) -> Option { - self.0.nth(n) - } - - #[inline] - fn all(&mut self, f: F) -> bool - where - F: FnMut(Self::Item) -> bool, - { - self.0.all(f) - } - - #[inline] - fn any(&mut self, f: F) -> bool - where - F: FnMut(Self::Item) -> bool, - { - self.0.any(f) - } - - #[inline] - fn find

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.0.find(predicate) - } - - #[inline] - fn position

(&mut self, predicate: P) -> Option - where - P: FnMut(Self::Item) -> bool, - { - self.0.position(predicate) - } - - #[inline] - fn rposition

(&mut self, predicate: P) -> Option - where - P: FnMut(Self::Item) -> bool, - { - self.0.rposition(predicate) - } - - #[inline] - unsafe fn __iterator_get_unchecked(&mut self, idx: usize) -> u8 { - // SAFETY: the caller must uphold the safety contract - // for `Iterator::get_unchecked`. - unsafe { self.0.__iterator_get_unchecked(idx) } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl DoubleEndedIterator for Bytes<'_> { - #[inline] - fn next_back(&mut self) -> Option { - self.0.next_back() - } - - #[inline] - fn nth_back(&mut self, n: usize) -> Option { - self.0.nth_back(n) - } - - #[inline] - fn rfind

(&mut self, predicate: P) -> Option - where - P: FnMut(&Self::Item) -> bool, - { - self.0.rfind(predicate) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl ExactSizeIterator for Bytes<'_> { - #[inline] - fn len(&self) -> usize { - self.0.len() - } - - #[inline] - fn is_empty(&self) -> bool { - self.0.is_empty() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Bytes<'_> {} - -#[unstable(feature = "trusted_len", issue = "37572")] -unsafe impl TrustedLen for Bytes<'_> {} - -#[doc(hidden)] -#[unstable(feature = "trusted_random_access", issue = "none")] -unsafe impl TrustedRandomAccess for Bytes<'_> { - fn may_have_side_effect() -> bool { - false - } -} - -/// This macro generates a Clone impl for string pattern API -/// wrapper types of the form X<'a, P> -macro_rules! derive_pattern_clone { - (clone $t:ident with |$s:ident| $e:expr) => { - impl<'a, P> Clone for $t<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - let $s = self; - $e - } - } - }; -} - -/// This macro generates two public iterator structs -/// wrapping a private internal one that makes use of the `Pattern` API. -/// -/// For all patterns `P: Pattern<'a>` the following items will be -/// generated (generics omitted): -/// -/// struct $forward_iterator($internal_iterator); -/// struct $reverse_iterator($internal_iterator); -/// -/// impl Iterator for $forward_iterator -/// { /* internal ends up calling Searcher::next_match() */ } -/// -/// impl DoubleEndedIterator for $forward_iterator -/// where P::Searcher: DoubleEndedSearcher -/// { /* internal ends up calling Searcher::next_match_back() */ } -/// -/// impl Iterator for $reverse_iterator -/// where P::Searcher: ReverseSearcher -/// { /* internal ends up calling Searcher::next_match_back() */ } -/// -/// impl DoubleEndedIterator for $reverse_iterator -/// where P::Searcher: DoubleEndedSearcher -/// { /* internal ends up calling Searcher::next_match() */ } -/// -/// The internal one is defined outside the macro, and has almost the same -/// semantic as a DoubleEndedIterator by delegating to `pattern::Searcher` and -/// `pattern::ReverseSearcher` for both forward and reverse iteration. -/// -/// "Almost", because a `Searcher` and a `ReverseSearcher` for a given -/// `Pattern` might not return the same elements, so actually implementing -/// `DoubleEndedIterator` for it would be incorrect. -/// (See the docs in `str::pattern` for more details) -/// -/// However, the internal struct still represents a single ended iterator from -/// either end, and depending on pattern is also a valid double ended iterator, -/// so the two wrapper structs implement `Iterator` -/// and `DoubleEndedIterator` depending on the concrete pattern type, leading -/// to the complex impls seen above. -macro_rules! generate_pattern_iterators { - { - // Forward iterator - forward: - $(#[$forward_iterator_attribute:meta])* - struct $forward_iterator:ident; - - // Reverse iterator - reverse: - $(#[$reverse_iterator_attribute:meta])* - struct $reverse_iterator:ident; - - // Stability of all generated items - stability: - $(#[$common_stability_attribute:meta])* - - // Internal almost-iterator that is being delegated to - internal: - $internal_iterator:ident yielding ($iterty:ty); - - // Kind of delegation - either single ended or double ended - delegate $($t:tt)* - } => { - $(#[$forward_iterator_attribute])* - $(#[$common_stability_attribute])* - pub struct $forward_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); - - $(#[$common_stability_attribute])* - impl<'a, P> fmt::Debug for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: fmt::Debug>, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple(stringify!($forward_iterator)) - .field(&self.0) - .finish() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P: Pattern<'a>> Iterator for $forward_iterator<'a, P> { - type Item = $iterty; - - #[inline] - fn next(&mut self) -> Option<$iterty> { - self.0.next() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> Clone for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - $forward_iterator(self.0.clone()) - } - } - - $(#[$reverse_iterator_attribute])* - $(#[$common_stability_attribute])* - pub struct $reverse_iterator<'a, P: Pattern<'a>>($internal_iterator<'a, P>); - - $(#[$common_stability_attribute])* - impl<'a, P> fmt::Debug for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: fmt::Debug>, - { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple(stringify!($reverse_iterator)) - .field(&self.0) - .finish() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> Iterator for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, - { - type Item = $iterty; - - #[inline] - fn next(&mut self) -> Option<$iterty> { - self.0.next_back() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> Clone for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: Clone>, - { - fn clone(&self) -> Self { - $reverse_iterator(self.0.clone()) - } - } - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P: Pattern<'a>> FusedIterator for $forward_iterator<'a, P> {} - - #[stable(feature = "fused", since = "1.26.0")] - impl<'a, P> FusedIterator for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: ReverseSearcher<'a>>, - {} - - generate_pattern_iterators!($($t)* with $(#[$common_stability_attribute])*, - $forward_iterator, - $reverse_iterator, $iterty); - }; - { - double ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty - } => { - $(#[$common_stability_attribute])* - impl<'a, P> DoubleEndedIterator for $forward_iterator<'a, P> - where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, - { - #[inline] - fn next_back(&mut self) -> Option<$iterty> { - self.0.next_back() - } - } - - $(#[$common_stability_attribute])* - impl<'a, P> DoubleEndedIterator for $reverse_iterator<'a, P> - where - P: Pattern<'a, Searcher: DoubleEndedSearcher<'a>>, - { - #[inline] - fn next_back(&mut self) -> Option<$iterty> { - self.0.next() - } - } - }; - { - single ended; with $(#[$common_stability_attribute:meta])*, - $forward_iterator:ident, - $reverse_iterator:ident, $iterty:ty - } => {} -} - -derive_pattern_clone! { - clone SplitInternal - with |s| SplitInternal { matcher: s.matcher.clone(), ..*s } -} - -struct SplitInternal<'a, P: Pattern<'a>> { - start: usize, - end: usize, - matcher: P::Searcher, - allow_trailing_empty: bool, - finished: bool, -} - -impl<'a, P> fmt::Debug for SplitInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInternal") - .field("start", &self.start) - .field("end", &self.end) - .field("matcher", &self.matcher) - .field("allow_trailing_empty", &self.allow_trailing_empty) - .field("finished", &self.finished) - .finish() - } -} - -impl<'a, P: Pattern<'a>> SplitInternal<'a, P> { - #[inline] - fn get_end(&mut self) -> Option<&'a str> { - if !self.finished && (self.allow_trailing_empty || self.end - self.start > 0) { - self.finished = true; - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - unsafe { - let string = self.matcher.haystack().get_unchecked(self.start..self.end); - Some(string) - } - } else { - None - } - } - - #[inline] - fn next(&mut self) -> Option<&'a str> { - if self.finished { - return None; - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..a); - self.start = b; - Some(elt) - }, - None => self.get_end(), - } - } - - #[inline] - fn next_inclusive(&mut self) -> Option<&'a str> { - if self.finished { - return None; - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.start is either the start of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(self.start..b); - self.start = b; - Some(elt) - }, - None => self.get_end(), - } - } - - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; - } - - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; - match self.next_back() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; - } - } - } - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `a` and `b` lie on unicode boundaries. - Some((a, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = a; - Some(elt) - }, - // SAFETY: `self.start` and `self.end` always lie on unicode boundaries. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, - } - } - - #[inline] - fn next_back_inclusive(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - if self.finished { - return None; - } - - if !self.allow_trailing_empty { - self.allow_trailing_empty = true; - match self.next_back_inclusive() { - Some(elt) if !elt.is_empty() => return Some(elt), - _ => { - if self.finished { - return None; - } - } - } - } - - let haystack = self.matcher.haystack(); - match self.matcher.next_match_back() { - // SAFETY: `Searcher` guarantees that `b` lies on unicode boundary, - // and self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - Some((_, b)) => unsafe { - let elt = haystack.get_unchecked(b..self.end); - self.end = b; - Some(elt) - }, - // SAFETY: self.start is either the start of the original string, - // or start of a substring that represents the part of the string that hasn't - // iterated yet. Either way, it is guaranteed to lie on unicode boundary. - // self.end is either the end of the original string, - // or `b` was assigned to it, so it also lies on unicode boundary. - None => unsafe { - self.finished = true; - Some(haystack.get_unchecked(self.start..self.end)) - }, - } - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`split`]. - /// - /// [`split`]: str::split - struct Split; - reverse: - /// Created with the method [`rsplit`]. - /// - /// [`rsplit`]: str::rsplit - struct RSplit; - stability: - #[stable(feature = "rust1", since = "1.0.0")] - internal: - SplitInternal yielding (&'a str); - delegate double ended; -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`split_terminator`]. - /// - /// [`split_terminator`]: str::split_terminator - struct SplitTerminator; - reverse: - /// Created with the method [`rsplit_terminator`]. - /// - /// [`rsplit_terminator`]: str::rsplit_terminator - struct RSplitTerminator; - stability: - #[stable(feature = "rust1", since = "1.0.0")] - internal: - SplitInternal yielding (&'a str); - delegate double ended; -} - -derive_pattern_clone! { - clone SplitNInternal - with |s| SplitNInternal { iter: s.iter.clone(), ..*s } -} - -struct SplitNInternal<'a, P: Pattern<'a>> { - iter: SplitInternal<'a, P>, - /// The number of splits remaining - count: usize, -} - -impl<'a, P> fmt::Debug for SplitNInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitNInternal") - .field("iter", &self.iter) - .field("count", &self.count) - .finish() - } -} - -impl<'a, P: Pattern<'a>> SplitNInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<&'a str> { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next() - } - } - } - - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - match self.count { - 0 => None, - 1 => { - self.count = 0; - self.iter.get_end() - } - _ => { - self.count -= 1; - self.iter.next_back() - } - } - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`splitn`]. - /// - /// [`splitn`]: str::splitn - struct SplitN; - reverse: - /// Created with the method [`rsplitn`]. - /// - /// [`rsplitn`]: str::rsplitn - struct RSplitN; - stability: - #[stable(feature = "rust1", since = "1.0.0")] - internal: - SplitNInternal yielding (&'a str); - delegate single ended; -} - -derive_pattern_clone! { - clone MatchIndicesInternal - with |s| MatchIndicesInternal(s.0.clone()) -} - -struct MatchIndicesInternal<'a, P: Pattern<'a>>(P::Searcher); - -impl<'a, P> fmt::Debug for MatchIndicesInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("MatchIndicesInternal").field(&self.0).finish() - } -} - -impl<'a, P: Pattern<'a>> MatchIndicesInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<(usize, &'a str)> { - self.0 - .next_match() - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) - } - - #[inline] - fn next_back(&mut self) -> Option<(usize, &'a str)> - where - P::Searcher: ReverseSearcher<'a>, - { - self.0 - .next_match_back() - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - .map(|(start, end)| unsafe { (start, self.0.haystack().get_unchecked(start..end)) }) - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`match_indices`]. - /// - /// [`match_indices`]: str::match_indices - struct MatchIndices; - reverse: - /// Created with the method [`rmatch_indices`]. - /// - /// [`rmatch_indices`]: str::rmatch_indices - struct RMatchIndices; - stability: - #[stable(feature = "str_match_indices", since = "1.5.0")] - internal: - MatchIndicesInternal yielding ((usize, &'a str)); - delegate double ended; -} - -derive_pattern_clone! { - clone MatchesInternal - with |s| MatchesInternal(s.0.clone()) -} - -struct MatchesInternal<'a, P: Pattern<'a>>(P::Searcher); - -impl<'a, P> fmt::Debug for MatchesInternal<'a, P> -where - P: Pattern<'a, Searcher: fmt::Debug>, -{ - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_tuple("MatchesInternal").field(&self.0).finish() - } -} - -impl<'a, P: Pattern<'a>> MatchesInternal<'a, P> { - #[inline] - fn next(&mut self) -> Option<&'a str> { - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - self.0.next_match().map(|(a, b)| unsafe { - // Indices are known to be on utf8 boundaries - self.0.haystack().get_unchecked(a..b) - }) - } - - #[inline] - fn next_back(&mut self) -> Option<&'a str> - where - P::Searcher: ReverseSearcher<'a>, - { - // SAFETY: `Searcher` guarantees that `start` and `end` lie on unicode boundaries. - self.0.next_match_back().map(|(a, b)| unsafe { - // Indices are known to be on utf8 boundaries - self.0.haystack().get_unchecked(a..b) - }) - } -} - -generate_pattern_iterators! { - forward: - /// Created with the method [`matches`]. - /// - /// [`matches`]: str::matches - struct Matches; - reverse: - /// Created with the method [`rmatches`]. - /// - /// [`rmatches`]: str::rmatches - struct RMatches; - stability: - #[stable(feature = "str_matches", since = "1.2.0")] - internal: - MatchesInternal yielding (&'a str); - delegate double ended; -} - -/// An iterator over the lines of a string, as string slices. -/// -/// This struct is created with the [`lines`] method on [`str`]. -/// See its documentation for more. -/// -/// [`lines`]: str::lines -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(Clone, Debug)] -pub struct Lines<'a>(Map, LinesAnyMap>); - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> Iterator for Lines<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } - - #[inline] - fn last(mut self) -> Option<&'a str> { - self.next_back() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl<'a> DoubleEndedIterator for Lines<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for Lines<'_> {} - -/// Created with the method [`lines_any`]. -/// -/// [`lines_any`]: str::lines_any -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_deprecated(since = "1.4.0", reason = "use lines()/Lines instead now")] -#[derive(Clone, Debug)] -#[allow(deprecated)] -pub struct LinesAny<'a>(Lines<'a>); - -impl_fn_for_zst! { - /// A nameable, cloneable fn type - #[derive(Clone)] - struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str { - let l = line.len(); - if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } - else { line } - }; -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl<'a> Iterator for LinesAny<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -#[allow(deprecated)] -impl<'a> DoubleEndedIterator for LinesAny<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -#[allow(deprecated)] -impl FusedIterator for LinesAny<'_> {} - -/* -Section: UTF-8 validation -*/ - -// use truncation to fit u64 into usize -const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; - -/// Returns `true` if any byte in the word `x` is nonascii (>= 128). -#[inline] -fn contains_nonascii(x: usize) -> bool { - (x & NONASCII_MASK) != 0 -} - -/// Walks through `v` checking that it's a valid UTF-8 sequence, -/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`. -#[inline(always)] -fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { - let mut index = 0; - let len = v.len(); - - let usize_bytes = mem::size_of::(); - let ascii_block_size = 2 * usize_bytes; - let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 }; - let align = v.as_ptr().align_offset(usize_bytes); - - while index < len { - let old_offset = index; - macro_rules! err { - ($error_len: expr) => { - return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len }); - }; - } - - macro_rules! next { - () => {{ - index += 1; - // we needed data, but there was none: error! - if index >= len { - err!(None) - } - v[index] - }}; - } - - let first = v[index]; - if first >= 128 { - let w = UTF8_CHAR_WIDTH[first as usize]; - // 2-byte encoding is for codepoints \u{0080} to \u{07ff} - // first C2 80 last DF BF - // 3-byte encoding is for codepoints \u{0800} to \u{ffff} - // first E0 A0 80 last EF BF BF - // excluding surrogates codepoints \u{d800} to \u{dfff} - // ED A0 80 to ED BF BF - // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff - // first F0 90 80 80 last F4 8F BF BF - // - // Use the UTF-8 syntax from the RFC - // - // https://tools.ietf.org/html/rfc3629 - // UTF8-1 = %x00-7F - // UTF8-2 = %xC2-DF UTF8-tail - // UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / - // %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) - // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / - // %xF4 %x80-8F 2( UTF8-tail ) - match w { - 2 => { - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(1)) - } - } - 3 => { - match (first, next!()) { - (0xE0, 0xA0..=0xBF) - | (0xE1..=0xEC, 0x80..=0xBF) - | (0xED, 0x80..=0x9F) - | (0xEE..=0xEF, 0x80..=0xBF) => {} - _ => err!(Some(1)), - } - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(2)) - } - } - 4 => { - match (first, next!()) { - (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {} - _ => err!(Some(1)), - } - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(2)) - } - if next!() & !CONT_MASK != TAG_CONT_U8 { - err!(Some(3)) - } - } - _ => err!(Some(1)), - } - index += 1; - } else { - // Ascii case, try to skip forward quickly. - // When the pointer is aligned, read 2 words of data per iteration - // until we find a word containing a non-ascii byte. - if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 { - let ptr = v.as_ptr(); - while index < blocks_end { - // SAFETY: since `align - index` and `ascii_block_size` are - // multiples of `usize_bytes`, `block = ptr.add(index)` is - // always aligned with a `usize` so it's safe to dereference - // both `block` and `block.offset(1)`. - unsafe { - let block = ptr.add(index) as *const usize; - // break if there is a nonascii byte - let zu = contains_nonascii(*block); - let zv = contains_nonascii(*block.offset(1)); - if zu | zv { - break; - } - } - index += ascii_block_size; - } - // step from the point where the wordwise loop stopped - while index < len && v[index] < 128 { - index += 1; - } - } else { - index += 1; - } - } - } - - Ok(()) -} - -// https://tools.ietf.org/html/rfc3629 -static UTF8_CHAR_WIDTH: [u8; 256] = [ - 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, // 0x1F - 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, // 0x3F - 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, // 0x5F - 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, // 0x7F - 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, // 0x9F - 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, // 0xBF - 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, - 2, // 0xDF - 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF - 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF -]; - -/// Given a first byte, determines how many bytes are in this UTF-8 character. -#[unstable(feature = "str_internals", issue = "none")] -#[inline] -pub fn utf8_char_width(b: u8) -> usize { - UTF8_CHAR_WIDTH[b as usize] as usize -} - -/// 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; - -/* -Section: Trait implementations -*/ - -mod traits { - use crate::cmp::Ordering; - use crate::ops; - use crate::ptr; - use crate::slice::SliceIndex; - - /// Implements ordering of strings. - /// - /// Strings are ordered lexicographically by their byte values. This orders Unicode code - /// points based on their positions in the code charts. This is not necessarily the same as - /// "alphabetical" order, which varies by language and locale. Sorting strings according to - /// culturally-accepted standards requires locale-specific data that is outside the scope of - /// the `str` type. - #[stable(feature = "rust1", since = "1.0.0")] - impl Ord for str { - #[inline] - fn cmp(&self, other: &str) -> Ordering { - self.as_bytes().cmp(other.as_bytes()) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl PartialEq for str { - #[inline] - fn eq(&self, other: &str) -> bool { - self.as_bytes() == other.as_bytes() - } - #[inline] - fn ne(&self, other: &str) -> bool { - !(*self).eq(other) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl Eq for str {} - - /// Implements comparison operations on strings. - /// - /// Strings are compared lexicographically by their byte values. This compares Unicode code - /// points based on their positions in the code charts. This is not necessarily the same as - /// "alphabetical" order, which varies by language and locale. Comparing strings according to - /// culturally-accepted standards requires locale-specific data that is outside the scope of - /// the `str` type. - #[stable(feature = "rust1", since = "1.0.0")] - impl PartialOrd for str { - #[inline] - fn partial_cmp(&self, other: &str) -> Option { - Some(self.cmp(other)) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ops::Index for str - where - I: SliceIndex, - { - type Output = I::Output; - - #[inline] - fn index(&self, index: I) -> &I::Output { - index.index(self) - } - } - - #[stable(feature = "rust1", since = "1.0.0")] - impl ops::IndexMut for str - where - I: SliceIndex, - { - #[inline] - fn index_mut(&mut self, index: I) -> &mut I::Output { - index.index_mut(self) - } - } - - #[inline(never)] - #[cold] - #[track_caller] - fn str_index_overflow_fail() -> ! { - panic!("attempted to index str up to maximum usize"); - } - - /// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`. - /// - /// Returns a slice of the whole string, i.e., returns `&self` or `&mut - /// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike - /// other indexing operations, this can never panic. - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::RangeFull { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - Some(slice) - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - Some(slice) - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - slice - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - slice - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - slice - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - slice - } - } - - /// Implements substring slicing with syntax `&self[begin .. end]` or `&mut - /// self[begin .. end]`. - /// - /// Returns a slice of the given string from the byte range - /// [`begin`, `end`). - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// # Panics - /// - /// Panics if `begin` or `end` does not point to the starting byte offset of - /// a character (as defined by `is_char_boundary`), if `begin > end`, or if - /// `end > len`. - /// - /// # Examples - /// - /// ``` - /// let s = "Löwe 老虎 Léopard"; - /// assert_eq!(&s[0 .. 1], "L"); - /// - /// assert_eq!(&s[1 .. 9], "öwe 老"); - /// - /// // these will panic: - /// // byte 2 lies within `ö`: - /// // &s[2 ..3]; - /// - /// // byte 8 lies within `老` - /// // &s[1 .. 8]; - /// - /// // byte 100 is outside the string - /// // &s[3 .. 100]; - /// ``` - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::Range { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if self.start <= self.end - && slice.is_char_boundary(self.start) - && slice.is_char_boundary(self.end) - { - // SAFETY: just checked that `start` and `end` are on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - // We also checked char boundaries, so this is valid UTF-8. - Some(unsafe { &*self.get_unchecked(slice) }) - } else { - None - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.start <= self.end - && slice.is_char_boundary(self.start) - && slice.is_char_boundary(self.end) - { - // SAFETY: just checked that `start` and `end` are on a char boundary. - // We know the pointer is unique because we got it from `slice`. - Some(unsafe { &mut *self.get_unchecked_mut(slice) }) - } else { - None - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - let slice = slice as *const [u8]; - // SAFETY: the caller guarantees that `self` is in bounds of `slice` - // which satisfies all the conditions for `add`. - let ptr = unsafe { slice.as_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts(ptr, len) as *const str - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - let slice = slice as *mut [u8]; - // SAFETY: see comments for `get_unchecked`. - let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; - let len = self.end - self.start; - ptr::slice_from_raw_parts_mut(ptr, len) as *mut str - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - let (start, end) = (self.start, self.end); - match self.get(slice) { - Some(s) => s, - None => super::slice_error_fail(slice, start, end), - } - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - // is_char_boundary checks that the index is in [0, .len()] - // cannot reuse `get` as above, because of NLL trouble - if self.start <= self.end - && slice.is_char_boundary(self.start) - && slice.is_char_boundary(self.end) - { - // SAFETY: just checked that `start` and `end` are on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - unsafe { &mut *self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, self.start, self.end) - } - } - } - - /// Implements substring slicing with syntax `&self[.. end]` or `&mut - /// self[.. end]`. - /// - /// Returns a slice of the given string from the byte range [`0`, `end`). - /// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`. - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// # Panics - /// - /// Panics if `end` does not point to the starting byte offset of a - /// character (as defined by `is_char_boundary`), or if `end > len`. - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::RangeTo { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &*self.get_unchecked(slice) }) - } else { - None - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &mut *self.get_unchecked_mut(slice) }) - } else { - None - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - let slice = slice as *const [u8]; - let ptr = slice.as_ptr(); - ptr::slice_from_raw_parts(ptr, self.end) as *const str - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - let slice = slice as *mut [u8]; - let ptr = slice.as_mut_ptr(); - ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - let end = self.end; - match self.get(slice) { - Some(s) => s, - None => super::slice_error_fail(slice, 0, end), - } - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if slice.is_char_boundary(self.end) { - // SAFETY: just checked that `end` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - unsafe { &mut *self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, 0, self.end) - } - } - } - - /// Implements substring slicing with syntax `&self[begin ..]` or `&mut - /// self[begin ..]`. - /// - /// Returns a slice of the given string from the byte range [`begin`, - /// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin .. - /// len]`. - /// - /// This operation is `O(1)`. - /// - /// Prior to 1.20.0, these indexing operations were still supported by - /// direct implementation of `Index` and `IndexMut`. - /// - /// # Panics - /// - /// Panics if `begin` does not point to the starting byte offset of - /// a character (as defined by `is_char_boundary`), or if `begin > len`. - #[stable(feature = "str_checked_slicing", since = "1.20.0")] - unsafe impl SliceIndex for ops::RangeFrom { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &*self.get_unchecked(slice) }) - } else { - None - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - Some(unsafe { &mut *self.get_unchecked_mut(slice) }) - } else { - None - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - let slice = slice as *const [u8]; - // SAFETY: the caller guarantees that `self` is in bounds of `slice` - // which satisfies all the conditions for `add`. - let ptr = unsafe { slice.as_ptr().add(self.start) }; - let len = slice.len() - self.start; - ptr::slice_from_raw_parts(ptr, len) as *const str - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - let slice = slice as *mut [u8]; - // SAFETY: identical to `get_unchecked`. - let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; - let len = slice.len() - self.start; - ptr::slice_from_raw_parts_mut(ptr, len) as *mut str - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - let (start, end) = (self.start, slice.len()); - match self.get(slice) { - Some(s) => s, - None => super::slice_error_fail(slice, start, end), - } - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if slice.is_char_boundary(self.start) { - // SAFETY: just checked that `start` is on a char boundary, - // and we are passing in a safe reference, so the return value will also be one. - unsafe { &mut *self.get_unchecked_mut(slice) } - } else { - super::slice_error_fail(slice, self.start, slice.len()) - } - } - } - - /// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut - /// self[begin ..= end]`. - /// - /// Returns a slice of the given string from the byte range - /// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut - /// self[begin .. end + 1]`, except if `end` has the maximum value for - /// `usize`. - /// - /// This operation is `O(1)`. - /// - /// # Panics - /// - /// Panics if `begin` does not point to the starting byte offset of - /// a character (as defined by `is_char_boundary`), if `end` does not point - /// to the ending byte offset of a character (`end + 1` is either a starting - /// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. - #[stable(feature = "inclusive_range", since = "1.26.0")] - unsafe impl SliceIndex for ops::RangeInclusive { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get(slice) - } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if *self.end() == usize::MAX { - None - } else { - (*self.start()..self.end() + 1).get_mut(slice) - } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - if *self.end() == usize::MAX { - str_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index(slice) - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if *self.end() == usize::MAX { - str_index_overflow_fail(); - } - (*self.start()..self.end() + 1).index_mut(slice) - } - } - - /// Implements substring slicing with syntax `&self[..= end]` or `&mut - /// self[..= end]`. - /// - /// Returns a slice of the given string from the byte range [0, `end`]. - /// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum - /// value for `usize`. - /// - /// This operation is `O(1)`. - /// - /// # Panics - /// - /// Panics if `end` does not point to the ending byte offset of a character - /// (`end + 1` is either a starting byte offset as defined by - /// `is_char_boundary`, or equal to `len`), or if `end >= len`. - #[stable(feature = "inclusive_range", since = "1.26.0")] - unsafe impl SliceIndex for ops::RangeToInclusive { - type Output = str; - #[inline] - fn get(self, slice: &str) -> Option<&Self::Output> { - if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) } - } - #[inline] - fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { - if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) } - } - #[inline] - unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked`. - unsafe { (..self.end + 1).get_unchecked(slice) } - } - #[inline] - unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { - // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. - unsafe { (..self.end + 1).get_unchecked_mut(slice) } - } - #[inline] - fn index(self, slice: &str) -> &Self::Output { - if self.end == usize::MAX { - str_index_overflow_fail(); - } - (..self.end + 1).index(slice) - } - #[inline] - fn index_mut(self, slice: &mut str) -> &mut Self::Output { - if self.end == usize::MAX { - str_index_overflow_fail(); - } - (..self.end + 1).index_mut(slice) - } - } -} - -// truncate `&str` to length at most equal to `max` -// return `true` if it were truncated, and the new str. -fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) { - if max >= s.len() { - (false, s) - } else { - while !s.is_char_boundary(max) { - max -= 1; - } - (true, &s[..max]) - } -} +use validations::truncate_to_char_boundary; #[inline(never)] #[cold] @@ -4560,22 +2413,6 @@ impl str { } } -impl_fn_for_zst! { - #[derive(Clone)] - struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug { - c.escape_debug_ext(false) - }; - - #[derive(Clone)] - struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode { - c.escape_unicode() - }; - #[derive(Clone)] - struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault { - c.escape_default() - }; -} - #[stable(feature = "rust1", since = "1.0.0")] impl AsRef<[u8]> for str { #[inline] @@ -4601,45 +2438,29 @@ impl Default for &mut str { } } -/// An iterator over the non-whitespace substrings of a string, -/// separated by any amount of whitespace. -/// -/// This struct is created by the [`split_whitespace`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_whitespace`]: str::split_whitespace -#[stable(feature = "split_whitespace", since = "1.1.0")] -#[derive(Clone, Debug)] -pub struct SplitWhitespace<'a> { - inner: Filter, IsNotEmpty>, -} - -/// An iterator over the non-ASCII-whitespace substrings of a string, -/// separated by any amount of ASCII whitespace. -/// -/// This struct is created by the [`split_ascii_whitespace`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_ascii_whitespace`]: str::split_ascii_whitespace -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct SplitAsciiWhitespace<'a> { - inner: Map, BytesIsNotEmpty>, UnsafeBytesToStr>, -} - -/// An iterator over the substrings of a string, -/// terminated by a substring matching to a predicate function -/// Unlike `Split`, it contains the matched part as a terminator -/// of the subslice. -/// -/// This struct is created by the [`split_inclusive`] method on [`str`]. -/// See its documentation for more. -/// -/// [`split_inclusive`]: str::split_inclusive -#[unstable(feature = "split_inclusive", issue = "72360")] -pub struct SplitInclusive<'a, P: Pattern<'a>>(SplitInternal<'a, P>); - impl_fn_for_zst! { + /// A nameable, cloneable fn type + #[derive(Clone)] + struct LinesAnyMap impl<'a> Fn = |line: &'a str| -> &'a str { + let l = line.len(); + if l > 0 && line.as_bytes()[l - 1] == b'\r' { &line[0 .. l - 1] } + else { line } + }; + + #[derive(Clone)] + struct CharEscapeDebugContinue impl Fn = |c: char| -> char::EscapeDebug { + c.escape_debug_ext(false) + }; + + #[derive(Clone)] + struct CharEscapeUnicode impl Fn = |c: char| -> char::EscapeUnicode { + c.escape_unicode() + }; + #[derive(Clone)] + struct CharEscapeDefault impl Fn = |c: char| -> char::EscapeDefault { + c.escape_default() + }; + #[derive(Clone)] struct IsWhitespace impl Fn = |c: char| -> bool { c.is_whitespace() @@ -4666,223 +2487,3 @@ impl_fn_for_zst! { unsafe { from_utf8_unchecked(bytes) } }; } - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> Iterator for SplitWhitespace<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - - #[inline] - fn last(mut self) -> Option<&'a str> { - self.next_back() - } -} - -#[stable(feature = "split_whitespace", since = "1.1.0")] -impl<'a> DoubleEndedIterator for SplitWhitespace<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.inner.next_back() - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for SplitWhitespace<'_> {} - -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -impl<'a> Iterator for SplitAsciiWhitespace<'a> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.inner.next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - self.inner.size_hint() - } - - #[inline] - fn last(mut self) -> Option<&'a str> { - self.next_back() - } -} - -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -impl<'a> DoubleEndedIterator for SplitAsciiWhitespace<'a> { - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.inner.next_back() - } -} - -#[stable(feature = "split_ascii_whitespace", since = "1.34.0")] -impl FusedIterator for SplitAsciiWhitespace<'_> {} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a>> Iterator for SplitInclusive<'a, P> { - type Item = &'a str; - - #[inline] - fn next(&mut self) -> Option<&'a str> { - self.0.next_inclusive() - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a, Searcher: fmt::Debug>> fmt::Debug for SplitInclusive<'a, P> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("SplitInclusive").field("0", &self.0).finish() - } -} - -// FIXME(#26925) Remove in favor of `#[derive(Clone)]` -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a, Searcher: Clone>> Clone for SplitInclusive<'a, P> { - fn clone(&self) -> Self { - SplitInclusive(self.0.clone()) - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a, Searcher: ReverseSearcher<'a>>> DoubleEndedIterator - for SplitInclusive<'a, P> -{ - #[inline] - fn next_back(&mut self) -> Option<&'a str> { - self.0.next_back_inclusive() - } -} - -#[unstable(feature = "split_inclusive", issue = "72360")] -impl<'a, P: Pattern<'a>> FusedIterator for SplitInclusive<'a, P> {} - -/// An iterator of [`u16`] over the string encoded as UTF-16. -/// -/// This struct is created by the [`encode_utf16`] method on [`str`]. -/// See its documentation for more. -/// -/// [`encode_utf16`]: str::encode_utf16 -#[derive(Clone)] -#[stable(feature = "encode_utf16", since = "1.8.0")] -pub struct EncodeUtf16<'a> { - chars: Chars<'a>, - extra: u16, -} - -#[stable(feature = "collection_debug", since = "1.17.0")] -impl fmt::Debug for EncodeUtf16<'_> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("EncodeUtf16 { .. }") - } -} - -#[stable(feature = "encode_utf16", since = "1.8.0")] -impl<'a> Iterator for EncodeUtf16<'a> { - type Item = u16; - - #[inline] - fn next(&mut self) -> Option { - if self.extra != 0 { - let tmp = self.extra; - self.extra = 0; - return Some(tmp); - } - - let mut buf = [0; 2]; - self.chars.next().map(|ch| { - let n = ch.encode_utf16(&mut buf).len(); - if n == 2 { - self.extra = buf[1]; - } - buf[0] - }) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.chars.size_hint(); - // every char gets either one u16 or two u16, - // so this iterator is between 1 or 2 times as - // long as the underlying iterator. - (low, high.and_then(|n| n.checked_mul(2))) - } -} - -#[stable(feature = "fused", since = "1.26.0")] -impl FusedIterator for EncodeUtf16<'_> {} - -/// The return type of [`str::escape_debug`]. -#[stable(feature = "str_escape", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct EscapeDebug<'a> { - inner: Chain< - Flatten>, - FlatMap, char::EscapeDebug, CharEscapeDebugContinue>, - >, -} - -/// The return type of [`str::escape_default`]. -#[stable(feature = "str_escape", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct EscapeDefault<'a> { - inner: FlatMap, char::EscapeDefault, CharEscapeDefault>, -} - -/// The return type of [`str::escape_unicode`]. -#[stable(feature = "str_escape", since = "1.34.0")] -#[derive(Clone, Debug)] -pub struct EscapeUnicode<'a> { - inner: FlatMap, char::EscapeUnicode, CharEscapeUnicode>, -} - -macro_rules! escape_types_impls { - ($( $Name: ident ),+) => {$( - #[stable(feature = "str_escape", since = "1.34.0")] - impl<'a> fmt::Display for $Name<'a> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.clone().try_for_each(|c| f.write_char(c)) - } - } - - #[stable(feature = "str_escape", since = "1.34.0")] - impl<'a> Iterator for $Name<'a> { - type Item = char; - - #[inline] - fn next(&mut self) -> Option { self.inner.next() } - - #[inline] - fn size_hint(&self) -> (usize, Option) { self.inner.size_hint() } - - #[inline] - fn try_fold(&mut self, init: Acc, fold: Fold) -> R where - Self: Sized, Fold: FnMut(Acc, Self::Item) -> R, R: Try - { - self.inner.try_fold(init, fold) - } - - #[inline] - fn fold(self, init: Acc, fold: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.inner.fold(init, fold) - } - } - - #[stable(feature = "str_escape", since = "1.34.0")] - impl<'a> FusedIterator for $Name<'a> {} - )+} -} - -escape_types_impls!(EscapeDebug, EscapeDefault, EscapeUnicode); diff --git a/library/core/src/str/pattern.rs b/library/core/src/str/pattern.rs index 1cc2de5b87..508c522e71 100644 --- a/library/core/src/str/pattern.rs +++ b/library/core/src/str/pattern.rs @@ -28,7 +28,7 @@ //! assert_eq!(s.find(|c: char| c.is_ascii_punctuation()), Some(35)); //! ``` //! -//! [pattern-impls]: trait.Pattern.html#implementors +//! [pattern-impls]: Pattern#implementors #![unstable( feature = "pattern", diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs new file mode 100644 index 0000000000..4f8aa246e5 --- /dev/null +++ b/library/core/src/str/traits.rs @@ -0,0 +1,597 @@ +//! Trait implementations for `str`. + +use crate::cmp::Ordering; +use crate::ops; +use crate::ptr; +use crate::slice::SliceIndex; + +use super::ParseBoolError; + +/// Implements ordering of strings. +/// +/// Strings are ordered lexicographically by their byte values. This orders Unicode code +/// points based on their positions in the code charts. This is not necessarily the same as +/// "alphabetical" order, which varies by language and locale. Sorting strings according to +/// culturally-accepted standards requires locale-specific data that is outside the scope of +/// the `str` type. +#[stable(feature = "rust1", since = "1.0.0")] +impl Ord for str { + #[inline] + fn cmp(&self, other: &str) -> Ordering { + self.as_bytes().cmp(other.as_bytes()) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialEq for str { + #[inline] + fn eq(&self, other: &str) -> bool { + self.as_bytes() == other.as_bytes() + } + #[inline] + fn ne(&self, other: &str) -> bool { + !(*self).eq(other) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl Eq for str {} + +/// Implements comparison operations on strings. +/// +/// Strings are compared lexicographically by their byte values. This compares Unicode code +/// points based on their positions in the code charts. This is not necessarily the same as +/// "alphabetical" order, which varies by language and locale. Comparing strings according to +/// culturally-accepted standards requires locale-specific data that is outside the scope of +/// the `str` type. +#[stable(feature = "rust1", since = "1.0.0")] +impl PartialOrd for str { + #[inline] + fn partial_cmp(&self, other: &str) -> Option { + Some(self.cmp(other)) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::Index for str +where + I: SliceIndex, +{ + type Output = I::Output; + + #[inline] + fn index(&self, index: I) -> &I::Output { + index.index(self) + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl ops::IndexMut for str +where + I: SliceIndex, +{ + #[inline] + fn index_mut(&mut self, index: I) -> &mut I::Output { + index.index_mut(self) + } +} + +#[inline(never)] +#[cold] +#[track_caller] +fn str_index_overflow_fail() -> ! { + panic!("attempted to index str up to maximum usize"); +} + +/// Implements substring slicing with syntax `&self[..]` or `&mut self[..]`. +/// +/// Returns a slice of the whole string, i.e., returns `&self` or `&mut +/// self`. Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. Unlike +/// other indexing operations, this can never panic. +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// Equivalent to `&self[0 .. len]` or `&mut self[0 .. len]`. +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::RangeFull { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + Some(slice) + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + Some(slice) + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + slice + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + slice + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + slice + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + slice + } +} + +/// Implements substring slicing with syntax `&self[begin .. end]` or `&mut +/// self[begin .. end]`. +/// +/// Returns a slice of the given string from the byte range +/// [`begin`, `end`). +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// # Panics +/// +/// Panics if `begin` or `end` does not point to the starting byte offset of +/// a character (as defined by `is_char_boundary`), if `begin > end`, or if +/// `end > len`. +/// +/// # Examples +/// +/// ``` +/// let s = "Löwe 老虎 Léopard"; +/// assert_eq!(&s[0 .. 1], "L"); +/// +/// assert_eq!(&s[1 .. 9], "öwe 老"); +/// +/// // these will panic: +/// // byte 2 lies within `ö`: +/// // &s[2 ..3]; +/// +/// // byte 8 lies within `老` +/// // &s[1 .. 8]; +/// +/// // byte 100 is outside the string +/// // &s[3 .. 100]; +/// ``` +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::Range { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + // We also checked char boundaries, so this is valid UTF-8. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary. + // We know the pointer is unique because we got it from `slice`. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; + // SAFETY: the caller guarantees that `self` is in bounds of `slice` + // which satisfies all the conditions for `add`. + let ptr = unsafe { slice.as_ptr().add(self.start) }; + let len = self.end - self.start; + ptr::slice_from_raw_parts(ptr, len) as *const str + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; + // SAFETY: see comments for `get_unchecked`. + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; + let len = self.end - self.start; + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, self.end); + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + // is_char_boundary checks that the index is in [0, .len()] + // cannot reuse `get` as above, because of NLL trouble + if self.start <= self.end + && slice.is_char_boundary(self.start) + && slice.is_char_boundary(self.end) + { + // SAFETY: just checked that `start` and `end` are on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, self.end) + } + } +} + +/// Implements substring slicing with syntax `&self[.. end]` or `&mut +/// self[.. end]`. +/// +/// Returns a slice of the given string from the byte range [`0`, `end`). +/// Equivalent to `&self[0 .. end]` or `&mut self[0 .. end]`. +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// # Panics +/// +/// Panics if `end` does not point to the starting byte offset of a +/// character (as defined by `is_char_boundary`), or if `end > len`. +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::RangeTo { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.end) { + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.end) { + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; + let ptr = slice.as_ptr(); + ptr::slice_from_raw_parts(ptr, self.end) as *const str + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; + let ptr = slice.as_mut_ptr(); + ptr::slice_from_raw_parts_mut(ptr, self.end) as *mut str + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let end = self.end; + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, 0, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.end) { + // SAFETY: just checked that `end` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, 0, self.end) + } + } +} + +/// Implements substring slicing with syntax `&self[begin ..]` or `&mut +/// self[begin ..]`. +/// +/// Returns a slice of the given string from the byte range [`begin`, +/// `len`). Equivalent to `&self[begin .. len]` or `&mut self[begin .. +/// len]`. +/// +/// This operation is `O(1)`. +/// +/// Prior to 1.20.0, these indexing operations were still supported by +/// direct implementation of `Index` and `IndexMut`. +/// +/// # Panics +/// +/// Panics if `begin` does not point to the starting byte offset of +/// a character (as defined by `is_char_boundary`), or if `begin > len`. +#[stable(feature = "str_checked_slicing", since = "1.20.0")] +unsafe impl SliceIndex for ops::RangeFrom { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &*self.get_unchecked(slice) }) + } else { + None + } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + Some(unsafe { &mut *self.get_unchecked_mut(slice) }) + } else { + None + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + let slice = slice as *const [u8]; + // SAFETY: the caller guarantees that `self` is in bounds of `slice` + // which satisfies all the conditions for `add`. + let ptr = unsafe { slice.as_ptr().add(self.start) }; + let len = slice.len() - self.start; + ptr::slice_from_raw_parts(ptr, len) as *const str + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + let slice = slice as *mut [u8]; + // SAFETY: identical to `get_unchecked`. + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; + let len = slice.len() - self.start; + ptr::slice_from_raw_parts_mut(ptr, len) as *mut str + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + let (start, end) = (self.start, slice.len()); + match self.get(slice) { + Some(s) => s, + None => super::slice_error_fail(slice, start, end), + } + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if slice.is_char_boundary(self.start) { + // SAFETY: just checked that `start` is on a char boundary, + // and we are passing in a safe reference, so the return value will also be one. + unsafe { &mut *self.get_unchecked_mut(slice) } + } else { + super::slice_error_fail(slice, self.start, slice.len()) + } + } +} + +/// Implements substring slicing with syntax `&self[begin ..= end]` or `&mut +/// self[begin ..= end]`. +/// +/// Returns a slice of the given string from the byte range +/// [`begin`, `end`]. Equivalent to `&self [begin .. end + 1]` or `&mut +/// self[begin .. end + 1]`, except if `end` has the maximum value for +/// `usize`. +/// +/// This operation is `O(1)`. +/// +/// # Panics +/// +/// Panics if `begin` does not point to the starting byte offset of +/// a character (as defined by `is_char_boundary`), if `end` does not point +/// to the ending byte offset of a character (`end + 1` is either a starting +/// byte offset or equal to `len`), if `begin > end`, or if `end >= len`. +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex for ops::RangeInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if *self.end() == usize::MAX { None } else { (*self.start()..self.end() + 1).get(slice) } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if *self.end() == usize::MAX { + None + } else { + (*self.start()..self.end() + 1).get_mut(slice) + } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (*self.start()..self.end() + 1).get_unchecked(slice) } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (*self.start()..self.end() + 1).get_unchecked_mut(slice) } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + if *self.end() == usize::MAX { + str_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if *self.end() == usize::MAX { + str_index_overflow_fail(); + } + (*self.start()..self.end() + 1).index_mut(slice) + } +} + +/// Implements substring slicing with syntax `&self[..= end]` or `&mut +/// self[..= end]`. +/// +/// Returns a slice of the given string from the byte range [0, `end`]. +/// Equivalent to `&self [0 .. end + 1]`, except if `end` has the maximum +/// value for `usize`. +/// +/// This operation is `O(1)`. +/// +/// # Panics +/// +/// Panics if `end` does not point to the ending byte offset of a character +/// (`end + 1` is either a starting byte offset as defined by +/// `is_char_boundary`, or equal to `len`), or if `end >= len`. +#[stable(feature = "inclusive_range", since = "1.26.0")] +unsafe impl SliceIndex for ops::RangeToInclusive { + type Output = str; + #[inline] + fn get(self, slice: &str) -> Option<&Self::Output> { + if self.end == usize::MAX { None } else { (..self.end + 1).get(slice) } + } + #[inline] + fn get_mut(self, slice: &mut str) -> Option<&mut Self::Output> { + if self.end == usize::MAX { None } else { (..self.end + 1).get_mut(slice) } + } + #[inline] + unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked`. + unsafe { (..self.end + 1).get_unchecked(slice) } + } + #[inline] + unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { + // SAFETY: the caller must uphold the safety contract for `get_unchecked_mut`. + unsafe { (..self.end + 1).get_unchecked_mut(slice) } + } + #[inline] + fn index(self, slice: &str) -> &Self::Output { + if self.end == usize::MAX { + str_index_overflow_fail(); + } + (..self.end + 1).index(slice) + } + #[inline] + fn index_mut(self, slice: &mut str) -> &mut Self::Output { + if self.end == usize::MAX { + str_index_overflow_fail(); + } + (..self.end + 1).index_mut(slice) + } +} + +/// Parse a value from a string +/// +/// `FromStr`'s [`from_str`] method is often used implicitly, through +/// [`str`]'s [`parse`] method. See [`parse`]'s documentation for examples. +/// +/// [`from_str`]: FromStr::from_str +/// [`parse`]: str::parse +/// +/// `FromStr` does not have a lifetime parameter, and so you can only parse types +/// that do not contain a lifetime parameter themselves. In other words, you can +/// parse an `i32` with `FromStr`, but not a `&i32`. You can parse a struct that +/// contains an `i32`, but not one that contains an `&i32`. +/// +/// # Examples +/// +/// Basic implementation of `FromStr` on an example `Point` type: +/// +/// ``` +/// use std::str::FromStr; +/// use std::num::ParseIntError; +/// +/// #[derive(Debug, PartialEq)] +/// struct Point { +/// x: i32, +/// y: i32 +/// } +/// +/// impl FromStr for Point { +/// type Err = ParseIntError; +/// +/// fn from_str(s: &str) -> Result { +/// let coords: Vec<&str> = s.trim_matches(|p| p == '(' || p == ')' ) +/// .split(',') +/// .collect(); +/// +/// let x_fromstr = coords[0].parse::()?; +/// let y_fromstr = coords[1].parse::()?; +/// +/// Ok(Point { x: x_fromstr, y: y_fromstr }) +/// } +/// } +/// +/// let p = Point::from_str("(1,2)"); +/// assert_eq!(p.unwrap(), Point{ x: 1, y: 2} ) +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +pub trait FromStr: Sized { + /// The associated error which can be returned from parsing. + #[stable(feature = "rust1", since = "1.0.0")] + type Err; + + /// Parses a string `s` to return a value of this type. + /// + /// 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. + /// + /// # Examples + /// + /// Basic usage with [`i32`][ithirtytwo], a type that implements `FromStr`: + /// + /// [ithirtytwo]: ../../std/primitive.i32.html + /// + /// ``` + /// use std::str::FromStr; + /// + /// let s = "5"; + /// let x = i32::from_str(s).unwrap(); + /// + /// assert_eq!(5, x); + /// ``` + #[stable(feature = "rust1", since = "1.0.0")] + fn from_str(s: &str) -> Result; +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl FromStr for bool { + type Err = ParseBoolError; + + /// Parse a `bool` from a string. + /// + /// Yields a `Result`, because `s` may or may not + /// actually be parseable. + /// + /// # Examples + /// + /// ``` + /// use std::str::FromStr; + /// + /// assert_eq!(FromStr::from_str("true"), Ok(true)); + /// assert_eq!(FromStr::from_str("false"), Ok(false)); + /// assert!(::from_str("not even a boolean").is_err()); + /// ``` + /// + /// Note, in many cases, the `.parse()` method on `str` is more proper. + /// + /// ``` + /// assert_eq!("true".parse(), Ok(true)); + /// assert_eq!("false".parse(), Ok(false)); + /// assert!("not even a boolean".parse::().is_err()); + /// ``` + #[inline] + fn from_str(s: &str) -> Result { + match s { + "true" => Ok(true), + "false" => Ok(false), + _ => Err(ParseBoolError { _priv: () }), + } + } +} diff --git a/library/core/src/str/validations.rs b/library/core/src/str/validations.rs new file mode 100644 index 0000000000..10cf1e172e --- /dev/null +++ b/library/core/src/str/validations.rs @@ -0,0 +1,275 @@ +//! Operations related to UTF-8 validation. + +use crate::mem; + +use super::Utf8Error; + +/// Returns the initial codepoint accumulator for the first byte. +/// The first byte is special, only want bottom 5 bits for width 2, 4 bits +/// for width 3, and 3 bits for width 4. +#[inline] +fn utf8_first_byte(byte: u8, width: u32) -> u32 { + (byte & (0x7F >> width)) as u32 +} + +/// Returns the value of `ch` updated with continuation byte `byte`. +#[inline] +fn utf8_acc_cont_byte(ch: u32, byte: u8) -> u32 { + (ch << 6) | (byte & CONT_MASK) as u32 +} + +/// Checks whether the byte is a UTF-8 continuation byte (i.e., starts with the +/// bits `10`). +#[inline] +pub(super) fn utf8_is_cont_byte(byte: u8) -> bool { + (byte & !CONT_MASK) == TAG_CONT_U8 +} + +#[inline] +fn unwrap_or_0(opt: Option<&u8>) -> u8 { + match opt { + Some(&byte) => byte, + None => 0, + } +} + +/// Reads the next code point out of a byte iterator (assuming a +/// UTF-8-like encoding). +#[unstable(feature = "str_internals", issue = "none")] +#[inline] +pub fn next_code_point<'a, I: Iterator>(bytes: &mut I) -> Option { + // Decode UTF-8 + let x = *bytes.next()?; + if x < 128 { + return Some(x as u32); + } + + // Multibyte case follows + // Decode from a byte combination out of: [[[x y] z] w] + // NOTE: Performance is sensitive to the exact formulation here + let init = utf8_first_byte(x, 2); + let y = unwrap_or_0(bytes.next()); + let mut ch = utf8_acc_cont_byte(init, y); + if x >= 0xE0 { + // [[x y z] w] case + // 5th bit in 0xE0 .. 0xEF is always clear, so `init` is still valid + let z = unwrap_or_0(bytes.next()); + let y_z = utf8_acc_cont_byte((y & CONT_MASK) as u32, z); + ch = init << 12 | y_z; + if x >= 0xF0 { + // [x y z w] case + // use only the lower 3 bits of `init` + let w = unwrap_or_0(bytes.next()); + ch = (init & 7) << 18 | utf8_acc_cont_byte(y_z, w); + } + } + + Some(ch) +} + +/// Reads the last code point out of a byte iterator (assuming a +/// UTF-8-like encoding). +#[inline] +pub(super) fn next_code_point_reverse<'a, I>(bytes: &mut I) -> Option +where + I: DoubleEndedIterator, +{ + // Decode UTF-8 + let w = match *bytes.next_back()? { + next_byte if next_byte < 128 => return Some(next_byte as u32), + back_byte => back_byte, + }; + + // Multibyte case follows + // Decode from a byte combination out of: [x [y [z w]]] + let mut ch; + let z = unwrap_or_0(bytes.next_back()); + ch = utf8_first_byte(z, 2); + if utf8_is_cont_byte(z) { + let y = unwrap_or_0(bytes.next_back()); + ch = utf8_first_byte(y, 3); + if utf8_is_cont_byte(y) { + let x = unwrap_or_0(bytes.next_back()); + ch = utf8_first_byte(x, 4); + ch = utf8_acc_cont_byte(ch, y); + } + ch = utf8_acc_cont_byte(ch, z); + } + ch = utf8_acc_cont_byte(ch, w); + + Some(ch) +} + +// use truncation to fit u64 into usize +const NONASCII_MASK: usize = 0x80808080_80808080u64 as usize; + +/// Returns `true` if any byte in the word `x` is nonascii (>= 128). +#[inline] +fn contains_nonascii(x: usize) -> bool { + (x & NONASCII_MASK) != 0 +} + +/// Walks through `v` checking that it's a valid UTF-8 sequence, +/// returning `Ok(())` in that case, or, if it is invalid, `Err(err)`. +#[inline(always)] +pub(super) fn run_utf8_validation(v: &[u8]) -> Result<(), Utf8Error> { + let mut index = 0; + let len = v.len(); + + let usize_bytes = mem::size_of::(); + let ascii_block_size = 2 * usize_bytes; + let blocks_end = if len >= ascii_block_size { len - ascii_block_size + 1 } else { 0 }; + let align = v.as_ptr().align_offset(usize_bytes); + + while index < len { + let old_offset = index; + macro_rules! err { + ($error_len: expr) => { + return Err(Utf8Error { valid_up_to: old_offset, error_len: $error_len }); + }; + } + + macro_rules! next { + () => {{ + index += 1; + // we needed data, but there was none: error! + if index >= len { + err!(None) + } + v[index] + }}; + } + + let first = v[index]; + if first >= 128 { + let w = UTF8_CHAR_WIDTH[first as usize]; + // 2-byte encoding is for codepoints \u{0080} to \u{07ff} + // first C2 80 last DF BF + // 3-byte encoding is for codepoints \u{0800} to \u{ffff} + // first E0 A0 80 last EF BF BF + // excluding surrogates codepoints \u{d800} to \u{dfff} + // ED A0 80 to ED BF BF + // 4-byte encoding is for codepoints \u{1000}0 to \u{10ff}ff + // first F0 90 80 80 last F4 8F BF BF + // + // Use the UTF-8 syntax from the RFC + // + // https://tools.ietf.org/html/rfc3629 + // UTF8-1 = %x00-7F + // UTF8-2 = %xC2-DF UTF8-tail + // UTF8-3 = %xE0 %xA0-BF UTF8-tail / %xE1-EC 2( UTF8-tail ) / + // %xED %x80-9F UTF8-tail / %xEE-EF 2( UTF8-tail ) + // UTF8-4 = %xF0 %x90-BF 2( UTF8-tail ) / %xF1-F3 3( UTF8-tail ) / + // %xF4 %x80-8F 2( UTF8-tail ) + match w { + 2 => { + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(1)) + } + } + 3 => { + match (first, next!()) { + (0xE0, 0xA0..=0xBF) + | (0xE1..=0xEC, 0x80..=0xBF) + | (0xED, 0x80..=0x9F) + | (0xEE..=0xEF, 0x80..=0xBF) => {} + _ => err!(Some(1)), + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(2)) + } + } + 4 => { + match (first, next!()) { + (0xF0, 0x90..=0xBF) | (0xF1..=0xF3, 0x80..=0xBF) | (0xF4, 0x80..=0x8F) => {} + _ => err!(Some(1)), + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(2)) + } + if next!() & !CONT_MASK != TAG_CONT_U8 { + err!(Some(3)) + } + } + _ => err!(Some(1)), + } + index += 1; + } else { + // Ascii case, try to skip forward quickly. + // When the pointer is aligned, read 2 words of data per iteration + // until we find a word containing a non-ascii byte. + if align != usize::MAX && align.wrapping_sub(index) % usize_bytes == 0 { + let ptr = v.as_ptr(); + while index < blocks_end { + // SAFETY: since `align - index` and `ascii_block_size` are + // multiples of `usize_bytes`, `block = ptr.add(index)` is + // always aligned with a `usize` so it's safe to dereference + // both `block` and `block.offset(1)`. + unsafe { + let block = ptr.add(index) as *const usize; + // break if there is a nonascii byte + let zu = contains_nonascii(*block); + let zv = contains_nonascii(*block.offset(1)); + if zu | zv { + break; + } + } + index += ascii_block_size; + } + // step from the point where the wordwise loop stopped + while index < len && v[index] < 128 { + index += 1; + } + } else { + index += 1; + } + } + } + + Ok(()) +} + +// https://tools.ietf.org/html/rfc3629 +static UTF8_CHAR_WIDTH: [u8; 256] = [ + 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, // 0x1F + 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, // 0x3F + 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, // 0x5F + 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, // 0x7F + 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, // 0x9F + 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, // 0xBF + 0, 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, // 0xDF + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, // 0xEF + 4, 4, 4, 4, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0xFF +]; + +/// Given a first byte, determines how many bytes are in this UTF-8 character. +#[unstable(feature = "str_internals", issue = "none")] +#[inline] +pub fn utf8_char_width(b: u8) -> usize { + UTF8_CHAR_WIDTH[b as usize] as usize +} + +/// 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. +pub(super) fn truncate_to_char_boundary(s: &str, mut max: usize) -> (bool, &str) { + if max >= s.len() { + (false, s) + } else { + while !s.is_char_boundary(max) { + max -= 1; + } + (true, &s[..max]) + } +} diff --git a/library/core/src/sync/atomic.rs b/library/core/src/sync/atomic.rs index f31a4a0b75..5c9cfe2710 100644 --- a/library/core/src/sync/atomic.rs +++ b/library/core/src/sync/atomic.rs @@ -10,18 +10,10 @@ //! Atomic types present operations that, when used correctly, synchronize //! updates between threads. //! -//! [`AtomicBool`]: struct.AtomicBool.html -//! [`AtomicIsize`]: struct.AtomicIsize.html -//! [`AtomicUsize`]: struct.AtomicUsize.html -//! [`AtomicI8`]: struct.AtomicI8.html -//! [`AtomicU16`]: struct.AtomicU16.html -//! //! Each method takes an [`Ordering`] which represents the strength of //! the memory barrier for that operation. These orderings are the //! same as the [C++20 atomic orderings][1]. For more information see the [nomicon][2]. //! -//! [`Ordering`]: enum.Ordering.html -//! //! [1]: https://en.cppreference.com/w/cpp/atomic/memory_order //! [2]: ../../../nomicon/atomics.html //! @@ -31,15 +23,12 @@ //! The most common way to share an atomic variable is to put it into an [`Arc`][arc] (an //! atomically-reference-counted shared pointer). //! -//! [`Sync`]: ../../marker/trait.Sync.html //! [arc]: ../../../std/sync/struct.Arc.html //! //! Atomic types may be stored in static variables, initialized using //! the constant initializers like [`AtomicBool::new`]. Atomic statics //! are often used for lazy global initialization. //! -//! [`AtomicBool::new`]: struct.AtomicBool.html#method.new -//! //! # Portability //! //! All atomic types in this module are guaranteed to be [lock-free] if they're @@ -87,7 +76,7 @@ //! fn main() { //! let spinlock = Arc::new(AtomicUsize::new(1)); //! -//! let spinlock_clone = spinlock.clone(); +//! let spinlock_clone = Arc::clone(&spinlock); //! let thread = thread::spawn(move|| { //! spinlock_clone.store(0, Ordering::SeqCst); //! }); @@ -155,8 +144,6 @@ pub fn spin_loop_hint() { /// /// **Note**: This type is only available on platforms that support atomic /// loads and stores of `u8`. -/// -/// [`bool`]: ../../../std/primitive.bool.html #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "rust1", since = "1.0.0")] #[repr(C, align(1))] @@ -212,8 +199,8 @@ unsafe impl Sync for AtomicPtr {} /// Atomic memory orderings /// /// Memory orderings specify the way atomic operations synchronize memory. -/// In its weakest [`Relaxed`][Ordering::Relaxed], only the memory directly touched by the -/// operation is synchronized. On the other hand, a store-load pair of [`SeqCst`][Ordering::SeqCst] +/// In its weakest [`Ordering::Relaxed`], only the memory directly touched by the +/// operation is synchronized. On the other hand, a store-load pair of [`Ordering::SeqCst`] /// operations synchronize other memory while additionally preserving a total order of such /// operations across all threads. /// @@ -223,8 +210,6 @@ unsafe impl Sync for AtomicPtr {} /// For more information see the [nomicon]. /// /// [nomicon]: ../../../nomicon/atomics.html -/// [Ordering::Relaxed]: #variant.Relaxed -/// [Ordering::SeqCst]: #variant.SeqCst #[stable(feature = "rust1", since = "1.0.0")] #[derive(Copy, Clone, Debug, Eq, PartialEq, Hash)] #[non_exhaustive] @@ -248,9 +233,6 @@ pub enum Ordering { /// /// Corresponds to [`memory_order_release`] in C++20. /// - /// [`Release`]: #variant.Release - /// [`Acquire`]: #variant.Acquire - /// [`Relaxed`]: #variant.Relaxed /// [`memory_order_release`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering #[stable(feature = "rust1", since = "1.0.0")] Release, @@ -266,9 +248,6 @@ pub enum Ordering { /// /// Corresponds to [`memory_order_acquire`] in C++20. /// - /// [`Acquire`]: #variant.Acquire - /// [`Release`]: #variant.Release - /// [`Relaxed`]: #variant.Relaxed /// [`memory_order_acquire`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering #[stable(feature = "rust1", since = "1.0.0")] Acquire, @@ -284,9 +263,6 @@ pub enum Ordering { /// Corresponds to [`memory_order_acq_rel`] in C++20. /// /// [`memory_order_acq_rel`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Release-Acquire_ordering - /// [`Acquire`]: #variant.Acquire - /// [`Release`]: #variant.Release - /// [`Relaxed`]: #variant.Relaxed #[stable(feature = "rust1", since = "1.0.0")] AcqRel, /// Like [`Acquire`]/[`Release`]/[`AcqRel`] (for load, store, and load-with-store @@ -296,16 +272,11 @@ pub enum Ordering { /// Corresponds to [`memory_order_seq_cst`] in C++20. /// /// [`memory_order_seq_cst`]: https://en.cppreference.com/w/cpp/atomic/memory_order#Sequentially-consistent_ordering - /// [`Acquire`]: #variant.Acquire - /// [`Release`]: #variant.Release - /// [`AcqRel`]: #variant.AcqRel #[stable(feature = "rust1", since = "1.0.0")] SeqCst, } /// An [`AtomicBool`] initialized to `false`. -/// -/// [`AtomicBool`]: struct.AtomicBool.html #[cfg(target_has_atomic_load_store = "8")] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_deprecated( @@ -339,8 +310,6 @@ impl AtomicBool { /// This is safe because the mutable reference guarantees that no other threads are /// concurrently accessing the atomic data. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -358,6 +327,28 @@ impl AtomicBool { unsafe { &mut *(self.v.get() as *mut bool) } } + /// Get atomic access to a `&mut bool`. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicBool, Ordering}; + /// + /// let mut some_bool = true; + /// let a = AtomicBool::from_mut(&mut some_bool); + /// a.store(false, Ordering::Relaxed); + /// assert_eq!(some_bool, false); + /// ``` + #[inline] + #[cfg(target_has_atomic_equal_alignment = "8")] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut bool) -> &Self { + // SAFETY: the mutable reference guarantees unique ownership, and + // alignment of both `bool` and `Self` is 1. + unsafe { &*(v as *mut bool as *mut Self) } + } + /// Consumes the atomic and returns the contained value. /// /// This is safe because passing `self` by value guarantees that no other threads are @@ -386,13 +377,6 @@ impl AtomicBool { /// /// Panics if `order` is [`Release`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -419,13 +403,6 @@ impl AtomicBool { /// /// Panics if `order` is [`Acquire`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -456,11 +433,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -493,13 +465,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`bool`]: ../../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -539,13 +504,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -587,7 +545,7 @@ impl AtomicBool { /// Stores a value into the [`bool`] if the current value is the same as the `current` value. /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the + /// Unlike [`AtomicBool::compare_exchange`], this function is allowed to spuriously fail even when the /// comparison succeeds, which can result in more efficient code on some platforms. The /// return value is a result indicating whether the new value was written and containing the /// previous value. @@ -603,14 +561,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// [`compare_exchange`]: #method.compare_exchange - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -658,11 +608,6 @@ impl AtomicBool { /// [`Acquire`] makes the store part of this operation [`Relaxed`], and /// using [`Release`] makes the load part [`Relaxed`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// @@ -706,11 +651,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -763,11 +703,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -808,11 +743,6 @@ impl AtomicBool { /// **Note:** This method is only available on platforms that support atomic /// operations on `u8`. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -850,8 +780,6 @@ impl AtomicBool { /// use of the returned raw pointer requires an `unsafe` block and still has to uphold the same /// restriction: operations on it must be atomic. /// - /// [`bool`]: ../../../std/primitive.bool.html - /// /// # Examples /// /// ```ignore (extern-declaration) @@ -910,8 +838,33 @@ impl AtomicPtr { #[inline] #[stable(feature = "atomic_access", since = "1.15.0")] pub fn get_mut(&mut self) -> &mut *mut T { - // SAFETY: the mutable reference guarantees unique ownership. - unsafe { &mut *self.p.get() } + self.p.get_mut() + } + + /// Get atomic access to a pointer. + /// + /// # Examples + /// + /// ``` + /// #![feature(atomic_from_mut)] + /// use std::sync::atomic::{AtomicPtr, Ordering}; + /// + /// let mut some_ptr = &mut 123 as *mut i32; + /// let a = AtomicPtr::from_mut(&mut some_ptr); + /// a.store(&mut 456, Ordering::Relaxed); + /// assert_eq!(unsafe { *some_ptr }, 456); + /// ``` + #[inline] + #[cfg(target_has_atomic_equal_alignment = "ptr")] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut *mut T) -> &Self { + use crate::mem::align_of; + let [] = [(); align_of::>() - align_of::<*mut ()>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `*mut T` and `Self` is the same on all platforms + // supported by rust, as verified above. + unsafe { &*(v as *mut *mut T as *mut Self) } } /// Consumes the atomic and returns the contained value. @@ -942,13 +895,6 @@ impl AtomicPtr { /// /// Panics if `order` is [`Release`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -975,13 +921,6 @@ impl AtomicPtr { /// /// Panics if `order` is [`Acquire`] or [`AcqRel`]. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -1013,11 +952,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// /// # Examples /// /// ``` @@ -1052,12 +986,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`AcqRel`]: enum.Ordering.html#variant.AcqRel - /// /// # Examples /// /// ``` @@ -1096,12 +1024,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -1143,7 +1065,7 @@ impl AtomicPtr { /// Stores a value into the pointer if the current value is the same as the `current` value. /// - /// Unlike [`compare_exchange`], this function is allowed to spuriously fail even when the + /// Unlike [`AtomicPtr::compare_exchange`], this function is allowed to spuriously fail even when the /// comparison succeeds, which can result in more efficient code on some platforms. The /// return value is a result indicating whether the new value was written and containing the /// previous value. @@ -1159,13 +1081,6 @@ impl AtomicPtr { /// **Note:** This method is only available on platforms that support atomic /// operations on pointers. /// - /// [`compare_exchange`]: #method.compare_exchange - /// [`Ordering`]: enum.Ordering.html - /// [`Relaxed`]: enum.Ordering.html#variant.Relaxed - /// [`Release`]: enum.Ordering.html#variant.Release - /// [`Acquire`]: enum.Ordering.html#variant.Acquire - /// [`SeqCst`]: enum.Ordering.html#variant.SeqCst - /// /// # Examples /// /// ``` @@ -1236,9 +1151,17 @@ impl From<*mut T> for AtomicPtr { } } +#[allow(unused_macros)] // This macro ends up being unused on some architectures. +macro_rules! if_not_8_bit { + (u8, $($tt:tt)*) => { "" }; + (i8, $($tt:tt)*) => { "" }; + ($_:ident, $($tt:tt)*) => { $($tt)* }; +} + #[cfg(target_has_atomic_load_store = "8")] macro_rules! atomic_int { ($cfg_cas:meta, + $cfg_align:meta, $stable:meta, $stable_cxchg:meta, $stable_debug:meta, @@ -1247,7 +1170,7 @@ macro_rules! atomic_int { $stable_nand:meta, $const_stable:meta, $stable_init_const:meta, - $s_int_type:expr, $int_ref:expr, + $s_int_type:literal, $int_ref:expr, $extra_feature:expr, $min_fn:ident, $max_fn:ident, $align:expr, @@ -1271,7 +1194,7 @@ macro_rules! atomic_int { #[doc = $int_ref] /// ). /// - /// [module-level documentation]: index.html + /// [module-level documentation]: crate::sync::atomic #[$stable] #[repr(C, align($align))] pub struct $atomic_type { @@ -1353,8 +1276,46 @@ assert_eq!(some_var.load(Ordering::SeqCst), 5); #[inline] #[$stable_access] pub fn get_mut(&mut self) -> &mut $int_type { - // SAFETY: the mutable reference guarantees unique ownership. - unsafe { &mut *self.v.get() } + self.v.get_mut() + } + } + + doc_comment! { + concat!("Get atomic access to a `&mut ", stringify!($int_type), "`. + +", +if_not_8_bit! { + $int_type, + concat!( + "**Note:** This function is only available on targets where `", + stringify!($int_type), "` has an alignment of ", $align, " bytes." + ) +}, +" + +# Examples + +``` +#![feature(atomic_from_mut)] +", $extra_feature, "use std::sync::atomic::{", stringify!($atomic_type), ", Ordering}; + +let mut some_int = 123; +let a = ", stringify!($atomic_type), "::from_mut(&mut some_int); +a.store(100, Ordering::Relaxed); +assert_eq!(some_int, 100); +``` + "), + #[inline] + #[$cfg_align] + #[unstable(feature = "atomic_from_mut", issue = "76314")] + pub fn from_mut(v: &mut $int_type) -> &Self { + use crate::mem::align_of; + let [] = [(); align_of::() - align_of::<$int_type>()]; + // SAFETY: + // - the mutable reference guarantees unique ownership. + // - the alignment of `$int_type` and `Self` is the + // same, as promised by $cfg_align and verified above. + unsafe { &*(v as *mut $int_type as *mut Self) } } } @@ -1389,13 +1350,6 @@ Possible values are [`SeqCst`], [`Acquire`] and [`Relaxed`]. Panics if `order` is [`Release`] or [`AcqRel`]. -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`AcqRel`]: enum.Ordering.html#variant.AcqRel -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ``` @@ -1423,13 +1377,6 @@ assert_eq!(some_var.load(Ordering::Relaxed), 5); Panics if `order` is [`Acquire`] or [`AcqRel`]. -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`AcqRel`]: enum.Ordering.html#variant.AcqRel -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ``` @@ -1459,11 +1406,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1498,12 +1440,6 @@ happens, and using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`AcqRel`]: enum.Ordering.html#variant.AcqRel - # Examples ``` @@ -1553,12 +1489,6 @@ and must be equivalent to or weaker than the success ordering. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ``` @@ -1595,7 +1525,7 @@ assert_eq!(some_var.load(Ordering::Relaxed), 10); concat!("Stores a value into the atomic integer if the current value is the same as the `current` value. -Unlike [`compare_exchange`], this function is allowed to spuriously fail even +Unlike [`", stringify!($atomic_type), "::compare_exchange`], this function is allowed to spuriously fail even when the comparison succeeds, which can result in more efficient code on some platforms. The return value is a result indicating whether the new value was written and containing the previous value. @@ -1608,13 +1538,6 @@ of this operation [`Relaxed`], and using [`Release`] makes the successful load [`Relaxed`]. The failure ordering can only be [`SeqCst`], [`Acquire`] or [`Relaxed`] and must be equivalent to or weaker than the success ordering. -[`compare_exchange`]: #method.compare_exchange -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). @@ -1662,11 +1585,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1698,11 +1616,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1737,11 +1650,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1776,11 +1684,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1816,11 +1719,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1855,11 +1753,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -1890,7 +1783,7 @@ only once to the stored value. `fetch_update` takes two [`Ordering`] arguments to describe the memory ordering of this operation. The first describes the required ordering for when the operation finally succeeds while the second describes the required ordering for loads. These correspond to the success and failure orderings of -[`compare_exchange`] respectively. +[`", stringify!($atomic_type), "::compare_exchange`] respectively. Using [`Acquire`] as success ordering makes the store part of this operation [`Relaxed`], and using [`Release`] makes the final successful load @@ -1900,14 +1793,6 @@ and must be equivalent to or weaker than the success ordering. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`bool`]: ../../../std/primitive.bool.html -[`compare_exchange`]: #method.compare_exchange -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire -[`SeqCst`]: enum.Ordering.html#variant.SeqCst - # Examples ```rust @@ -1954,11 +1839,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -2004,11 +1884,6 @@ using [`Release`] makes the load part [`Relaxed`]. **Note**: This method is only available on platforms that support atomic operations on [`", $s_int_type, "`](", $int_ref, "). -[`Ordering`]: enum.Ordering.html -[`Relaxed`]: enum.Ordering.html#variant.Relaxed -[`Release`]: enum.Ordering.html#variant.Release -[`Acquire`]: enum.Ordering.html#variant.Acquire - # Examples ``` @@ -2086,6 +1961,7 @@ let mut atomic = ", stringify!($atomic_type), "::new(1); #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2104,6 +1980,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "8")] atomic_int! { cfg(target_has_atomic = "8"), + cfg(target_has_atomic_equal_alignment = "8"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2122,6 +1999,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2140,6 +2018,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "16")] atomic_int! { cfg(target_has_atomic = "16"), + cfg(target_has_atomic_equal_alignment = "16"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2158,6 +2037,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2176,6 +2056,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "32")] atomic_int! { cfg(target_has_atomic = "32"), + cfg(target_has_atomic_equal_alignment = "32"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2194,6 +2075,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2212,6 +2094,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "64")] atomic_int! { cfg(target_has_atomic = "64"), + cfg(target_has_atomic_equal_alignment = "64"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), stable(feature = "integer_atomics_stable", since = "1.34.0"), @@ -2230,6 +2113,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2248,6 +2132,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "128")] atomic_int! { cfg(target_has_atomic = "128"), + cfg(target_has_atomic_equal_alignment = "128"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), unstable(feature = "integer_atomics", issue = "32976"), @@ -2287,6 +2172,7 @@ macro_rules! ptr_width { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), @@ -2305,6 +2191,7 @@ atomic_int! { #[cfg(target_has_atomic_load_store = "ptr")] atomic_int! { cfg(target_has_atomic = "ptr"), + cfg(target_has_atomic_equal_alignment = "ptr"), stable(feature = "rust1", since = "1.0.0"), stable(feature = "extended_compare_and_swap", since = "1.10.0"), stable(feature = "atomic_debug", since = "1.3.0"), @@ -2660,13 +2547,6 @@ unsafe fn atomic_umin(dst: *mut T, val: T, order: Ordering) -> T { /// } /// } /// ``` -/// -/// [`Ordering`]: enum.Ordering.html -/// [`Acquire`]: enum.Ordering.html#variant.Acquire -/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst -/// [`Release`]: enum.Ordering.html#variant.Release -/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel -/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn fence(order: Ordering) { @@ -2747,13 +2627,6 @@ pub fn fence(order: Ordering) { /// } /// ``` /// -/// [`fence`]: fn.fence.html -/// [`Ordering`]: enum.Ordering.html -/// [`Acquire`]: enum.Ordering.html#variant.Acquire -/// [`SeqCst`]: enum.Ordering.html#variant.SeqCst -/// [`Release`]: enum.Ordering.html#variant.Release -/// [`AcqRel`]: enum.Ordering.html#variant.AcqRel -/// [`Relaxed`]: enum.Ordering.html#variant.Relaxed /// [memory barriers]: https://www.kernel.org/doc/Documentation/memory-barriers.txt #[inline] #[stable(feature = "compiler_fences", since = "1.21.0")] diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index fea396d20f..4e987a53b2 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -10,7 +10,7 @@ use crate::result::Result; #[stable(feature = "futures_api", since = "1.36.0")] pub enum Poll { /// Represents that a value is immediately ready. - #[cfg_attr(not(bootstrap), lang = "Ready")] + #[lang = "Ready"] #[stable(feature = "futures_api", since = "1.36.0")] Ready(#[stable(feature = "futures_api", since = "1.36.0")] T), @@ -19,7 +19,7 @@ pub enum Poll { /// When a function returns `Pending`, the function *must* also /// ensure that the current task is scheduled to be awoken when /// progress can be made. - #[cfg_attr(not(bootstrap), lang = "Pending")] + #[lang = "Pending"] #[stable(feature = "futures_api", since = "1.36.0")] Pending, } @@ -112,6 +112,14 @@ impl Poll>> { #[stable(feature = "futures_api", since = "1.36.0")] impl From for Poll { + /// Convert to a `Ready` variant. + /// + /// # Example + /// + /// ``` + /// # use core::task::Poll; + /// assert_eq!(Poll::from(true), Poll::Ready(true)); + /// ``` fn from(t: T) -> Poll { Poll::Ready(t) } diff --git a/library/core/src/task/ready.rs b/library/core/src/task/ready.rs index d4e733eb2b..e221aaf3fd 100644 --- a/library/core/src/task/ready.rs +++ b/library/core/src/task/ready.rs @@ -5,7 +5,6 @@ /// # Examples /// /// ``` -/// #![feature(future_readiness_fns)] /// #![feature(ready_macro)] /// /// use core::task::{ready, Context, Poll}; @@ -27,7 +26,6 @@ /// The `ready!` call expands to: /// /// ``` -/// # #![feature(future_readiness_fns)] /// # #![feature(ready_macro)] /// # /// # use core::task::{Context, Poll}; diff --git a/library/core/src/task/wake.rs b/library/core/src/task/wake.rs index 92057209d8..ba3fb35caa 100644 --- a/library/core/src/task/wake.rs +++ b/library/core/src/task/wake.rs @@ -8,10 +8,8 @@ use crate::marker::{PhantomData, Unpin}; /// /// [vtable]: https://en.wikipedia.org/wiki/Virtual_method_table /// -/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] that -/// customizes the behavior of the `RawWaker`. -/// -/// [`Waker`]: struct.Waker.html +/// It consists of a data pointer and a [virtual function pointer table (vtable)][vtable] +/// that customizes the behavior of the `RawWaker`. #[derive(PartialEq, Debug)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct RawWaker { @@ -52,12 +50,10 @@ impl RawWaker { /// The pointer passed to all functions inside the vtable is the `data` pointer /// from the enclosing [`RawWaker`] object. /// -/// The functions inside this struct are only intended be called on the `data` +/// The functions inside this struct are only intended to be called on the `data` /// pointer of a properly constructed [`RawWaker`] object from inside the /// [`RawWaker`] implementation. Calling one of the contained functions using /// any other `data` pointer will cause undefined behavior. -/// -/// [`RawWaker`]: struct.RawWaker.html #[stable(feature = "futures_api", since = "1.36.0")] #[derive(PartialEq, Copy, Clone, Debug)] pub struct RawWakerVTable { @@ -68,9 +64,6 @@ pub struct RawWakerVTable { /// required for this additional instance of a [`RawWaker`] and associated /// task. Calling `wake` on the resulting [`RawWaker`] should result in a wakeup /// of the same task that would have been awoken by the original [`RawWaker`]. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html clone: unsafe fn(*const ()) -> RawWaker, /// This function will be called when `wake` is called on the [`Waker`]. @@ -79,9 +72,6 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html wake: unsafe fn(*const ()), /// This function will be called when `wake_by_ref` is called on the [`Waker`]. @@ -89,9 +79,6 @@ pub struct RawWakerVTable { /// /// This function is similar to `wake`, but must not consume the provided data /// pointer. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html wake_by_ref: unsafe fn(*const ()), /// This function gets called when a [`RawWaker`] gets dropped. @@ -99,8 +86,6 @@ pub struct RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`RawWaker`]: struct.RawWaker.html drop: unsafe fn(*const ()), } @@ -142,18 +127,11 @@ impl RawWakerVTable { /// The implementation of this function must make sure to release any /// resources that are associated with this instance of a [`RawWaker`] and /// associated task. - /// - /// [`Waker`]: struct.Waker.html - /// [`RawWaker`]: struct.RawWaker.html #[rustc_promotable] #[stable(feature = "futures_api", since = "1.36.0")] - // `rustc_allow_const_fn_ptr` is a hack that should not be used anywhere else - // without first consulting with T-Lang. - // - // FIXME: remove whenever we have a stable way to accept fn pointers from const fn - // (see https://github.com/rust-rfcs/const-eval/issues/19#issuecomment-472799062) - #[rustc_allow_const_fn_ptr] #[rustc_const_stable(feature = "futures_api", since = "1.36.0")] + #[cfg_attr(not(bootstrap), allow_internal_unstable(const_fn_fn_ptr_basics))] + #[cfg_attr(bootstrap, rustc_allow_const_fn_ptr)] pub const fn new( clone: unsafe fn(*const ()) -> RawWaker, wake: unsafe fn(*const ()), @@ -208,8 +186,6 @@ impl fmt::Debug for Context<'_> { /// executor-specific wakeup behavior. /// /// Implements [`Clone`], [`Send`], and [`Sync`]. -/// -/// [`RawWaker`]: struct.RawWaker.html #[repr(transparent)] #[stable(feature = "futures_api", since = "1.36.0")] pub struct Waker { @@ -275,9 +251,6 @@ impl Waker { /// The behavior of the returned `Waker` is undefined if the contract defined /// in [`RawWaker`]'s and [`RawWakerVTable`]'s documentation is not upheld. /// Therefore this method is unsafe. - /// - /// [`RawWaker`]: struct.RawWaker.html - /// [`RawWakerVTable`]: struct.RawWakerVTable.html #[inline] #[stable(feature = "futures_api", since = "1.36.0")] pub unsafe fn from_raw(waker: RawWaker) -> Waker { diff --git a/library/core/src/time.rs b/library/core/src/time.rs index 5741f8a53b..6dc542dee5 100644 --- a/library/core/src/time.rs +++ b/library/core/src/time.rs @@ -108,6 +108,34 @@ impl Duration { #[unstable(feature = "duration_constants", issue = "57391")] pub const NANOSECOND: Duration = Duration::from_nanos(1); + /// The minimum duration. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MIN, Duration::new(0, 0)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MIN: Duration = Duration::from_nanos(0); + + /// The maximum duration. + /// + /// It is roughly equal to a duration of 584,942,417,355 years. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::MAX, Duration::new(u64::MAX, 1_000_000_000 - 1)); + /// ``` + #[unstable(feature = "duration_constants", issue = "57391")] + pub const MAX: Duration = Duration::new(u64::MAX, NANOS_PER_SEC - 1); + /// Creates a new `Duration` from the specified number of whole seconds and /// additional nanoseconds. /// @@ -450,6 +478,29 @@ impl Duration { } } + /// Saturating `Duration` addition. Computes `self + other`, returning [`Duration::MAX`] + /// if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_add(self, rhs: Duration) -> Duration { + match self.checked_add(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` subtraction. Computes `self - other`, returning [`None`] /// if the result would be negative or if overflow occurred. /// @@ -485,6 +536,29 @@ impl Duration { } } + /// Saturating `Duration` subtraction. Computes `self - other`, returning [`Duration::MIN`] + /// if the result would be negative or if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 1).saturating_sub(Duration::new(0, 0)), Duration::new(0, 1)); + /// assert_eq!(Duration::new(0, 0).saturating_sub(Duration::new(0, 1)), Duration::MIN); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_sub(self, rhs: Duration) -> Duration { + match self.checked_sub(rhs) { + Some(res) => res, + None => Duration::MIN, + } + } + /// Checked `Duration` multiplication. Computes `self * other`, returning /// [`None`] if overflow occurred. /// @@ -515,6 +589,29 @@ impl Duration { None } + /// Saturating `Duration` multiplication. Computes `self * other`, returning + /// [`Duration::MAX`] if overflow occurred. + /// + /// # Examples + /// + /// ``` + /// #![feature(duration_saturating_ops)] + /// #![feature(duration_constants)] + /// use std::time::Duration; + /// + /// assert_eq!(Duration::new(0, 500_000_001).saturating_mul(2), Duration::new(1, 2)); + /// assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); + /// ``` + #[unstable(feature = "duration_saturating_ops", issue = "76416")] + #[inline] + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn saturating_mul(self, rhs: u32) -> Duration { + match self.checked_mul(rhs) { + Some(res) => res, + None => Duration::MAX, + } + } + /// Checked `Duration` division. Computes `self / other`, returning [`None`] /// if `other == 0`. /// @@ -596,7 +693,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f64(secs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f64(secs: f64) -> Duration { const MAX_NANOS_F64: f64 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f64; let nanos = secs * (NANOS_PER_SEC as f64); if !nanos.is_finite() { @@ -630,7 +728,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn from_secs_f32(secs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn from_secs_f32(secs: f32) -> Duration { const MAX_NANOS_F32: f32 = ((u64::MAX as u128 + 1) * (NANOS_PER_SEC as u128)) as f32; let nanos = secs * (NANOS_PER_SEC as f32); if !nanos.is_finite() { @@ -664,7 +763,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(rhs * self.as_secs_f64()) } @@ -685,7 +785,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn mul_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn mul_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(rhs * self.as_secs_f32()) } @@ -705,7 +806,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f64(self, rhs: f64) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f64(self, rhs: f64) -> Duration { Duration::from_secs_f64(self.as_secs_f64() / rhs) } @@ -727,7 +829,8 @@ impl Duration { /// ``` #[stable(feature = "duration_float", since = "1.38.0")] #[inline] - pub fn div_f32(self, rhs: f32) -> Duration { + #[rustc_const_unstable(feature = "duration_consts_2", issue = "72440")] + pub const fn div_f32(self, rhs: f32) -> Duration { Duration::from_secs_f32(self.as_secs_f32() / rhs) } diff --git a/library/core/tests/array.rs b/library/core/tests/array.rs index 5aba1a5d95..89c2a969c2 100644 --- a/library/core/tests/array.rs +++ b/library/core/tests/array.rs @@ -1,4 +1,4 @@ -use core::array::{FixedSizeArray, IntoIter}; +use core::array::{self, FixedSizeArray, IntoIter}; use core::convert::TryFrom; #[test] @@ -19,6 +19,21 @@ fn fixed_size_array() { assert_eq!(FixedSizeArray::as_mut_slice(&mut empty_zero_sized).len(), 0); } +#[test] +fn array_from_ref() { + let value: String = "Hello World!".into(); + let arr: &[String; 1] = array::from_ref(&value); + assert_eq!(&[value.clone()], arr); +} + +#[test] +fn array_from_mut() { + let mut value: String = "Hello World".into(); + let arr: &mut [String; 1] = array::from_mut(&mut value); + arr[0].push_str("!"); + assert_eq!(&value, "Hello World!"); +} + #[test] fn array_try_from() { macro_rules! test { @@ -330,3 +345,32 @@ fn array_map_drop_safety() { assert_eq!(DROPPED.load(Ordering::SeqCst), num_to_create); panic!("test succeeded") } + +#[test] +fn cell_allows_array_cycle() { + use core::cell::Cell; + + #[derive(Debug)] + struct B<'a> { + a: [Cell>>; 2], + } + + impl<'a> B<'a> { + fn new() -> B<'a> { + B { a: [Cell::new(None), Cell::new(None)] } + } + } + + let b1 = B::new(); + let b2 = B::new(); + let b3 = B::new(); + + b1.a[0].set(Some(&b2)); + b1.a[1].set(Some(&b3)); + + b2.a[0].set(Some(&b2)); + b2.a[1].set(Some(&b3)); + + b3.a[0].set(Some(&b1)); + b3.a[1].set(Some(&b2)); +} diff --git a/library/core/tests/ascii.rs b/library/core/tests/ascii.rs index 0b97508394..3244bbc2d6 100644 --- a/library/core/tests/ascii.rs +++ b/library/core/tests/ascii.rs @@ -397,3 +397,14 @@ fn test_is_ascii_align_size_thoroughly() { } } } + +#[test] +fn ascii_const() { + // test that the `is_ascii` methods of `char` and `u8` are usable in a const context + + const CHAR_IS_ASCII: bool = 'a'.is_ascii(); + assert!(CHAR_IS_ASCII); + + const BYTE_IS_ASCII: bool = 97u8.is_ascii(); + assert!(BYTE_IS_ASCII); +} diff --git a/library/core/tests/cell.rs b/library/core/tests/cell.rs index 801b60be0f..40be01f443 100644 --- a/library/core/tests/cell.rs +++ b/library/core/tests/cell.rs @@ -303,6 +303,53 @@ fn cell_into_inner() { assert_eq!("Hello world".to_owned(), cell.into_inner()); } +#[test] +fn cell_exterior() { + #[derive(Copy, Clone)] + #[allow(dead_code)] + struct Point { + x: isize, + y: isize, + z: isize, + } + + fn f(p: &Cell) { + assert_eq!(p.get().z, 12); + p.set(Point { x: 10, y: 11, z: 13 }); + assert_eq!(p.get().z, 13); + } + + let a = Point { x: 10, y: 11, z: 12 }; + let b = &Cell::new(a); + assert_eq!(b.get().z, 12); + f(b); + assert_eq!(a.z, 12); + assert_eq!(b.get().z, 13); +} + +#[test] +fn cell_does_not_clone() { + #[derive(Copy)] + #[allow(dead_code)] + struct Foo { + x: isize, + } + + impl Clone for Foo { + fn clone(&self) -> Foo { + // Using Cell in any way should never cause clone() to be + // invoked -- after all, that would permit evil user code to + // abuse `Cell` and trigger crashes. + + panic!(); + } + } + + let x = Cell::new(Foo { x: 22 }); + let _y = x.get(); + let _z = x.clone(); +} + #[test] fn refcell_default() { let cell: RefCell = Default::default(); @@ -367,3 +414,11 @@ fn refcell_replace_borrows() { let _b = x.borrow(); x.replace(1); } + +#[test] +fn refcell_format() { + let name = RefCell::new("rust"); + let what = RefCell::new("rocks"); + let msg = format!("{name} {}", &*what.borrow(), name = &*name.borrow()); + assert_eq!(msg, "rust rocks".to_string()); +} diff --git a/library/core/tests/cmp.rs b/library/core/tests/cmp.rs index 4086917780..835289daf7 100644 --- a/library/core/tests/cmp.rs +++ b/library/core/tests/cmp.rs @@ -1,4 +1,7 @@ -use core::cmp::{self, Ordering::*}; +use core::cmp::{ + self, + Ordering::{self, *}, +}; #[test] fn test_int_totalord() { @@ -116,3 +119,16 @@ fn test_user_defined_eq() { assert!(SketchyNum { num: 37 } == SketchyNum { num: 34 }); assert!(SketchyNum { num: 25 } != SketchyNum { num: 57 }); } + +#[test] +fn ordering_const() { + // test that the methods of `Ordering` are usable in a const context + + const ORDERING: Ordering = Greater; + + const REVERSE: Ordering = ORDERING.reverse(); + assert_eq!(REVERSE, Less); + + const THEN: Ordering = Equal.then(ORDERING); + assert_eq!(THEN, Greater); +} diff --git a/library/core/tests/intrinsics.rs b/library/core/tests/intrinsics.rs index fed7c4a5bf..de163a60c9 100644 --- a/library/core/tests/intrinsics.rs +++ b/library/core/tests/intrinsics.rs @@ -1,4 +1,5 @@ use core::any::TypeId; +use core::intrinsics::assume; #[test] fn test_typeid_sized_types() { @@ -20,3 +21,17 @@ fn test_typeid_unsized_types() { assert_eq!(TypeId::of::(), TypeId::of::()); assert!(TypeId::of::() != TypeId::of::()); } + +// Check that `const_assume` feature allow `assume` intrinsic +// to be used in const contexts. +#[test] +fn test_assume_can_be_in_const_contexts() { + const unsafe fn foo(x: usize, y: usize) -> usize { + // SAFETY: the entire function is not safe, + // but it is just an example not used elsewhere. + unsafe { assume(y != 0) }; + x / y + } + let rs = unsafe { foo(42, 97) }; + assert_eq!(rs, 0); +} diff --git a/library/core/tests/iter.rs b/library/core/tests/iter.rs index 00e3972c42..b15d6d1b1f 100644 --- a/library/core/tests/iter.rs +++ b/library/core/tests/iter.rs @@ -376,6 +376,103 @@ fn test_zip_next_back_side_effects_exhausted() { assert_eq!(b, vec![200, 300, 400]); } +#[derive(Debug)] +struct CountClone(Cell); + +fn count_clone() -> CountClone { + CountClone(Cell::new(0)) +} + +impl PartialEq for CountClone { + fn eq(&self, rhs: &i32) -> bool { + self.0.get() == *rhs + } +} + +impl Clone for CountClone { + fn clone(&self) -> Self { + let ret = CountClone(self.0.clone()); + let n = self.0.get(); + self.0.set(n + 1); + ret + } +} + +#[test] +fn test_zip_cloned_sideffectful() { + let xs = [count_clone(), count_clone(), count_clone(), count_clone()]; + let ys = [count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1, 1, 0][..]); + assert_eq!(&ys, &[1, 1][..]); + + let xs = [count_clone(), count_clone()]; + let ys = [count_clone(), count_clone(), count_clone(), count_clone()]; + + for _ in xs.iter().cloned().zip(ys.iter().cloned()) {} + + assert_eq!(&xs, &[1, 1][..]); + assert_eq!(&ys, &[1, 1, 0, 0][..]); +} + +#[test] +fn test_zip_map_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); + assert_eq!(&ys, &[1, 1, 1, 1]); + + let mut xs = [0; 4]; + let mut ys = [0; 6]; + + for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) {} + + assert_eq!(&xs, &[1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); +} + +#[test] +fn test_zip_map_rev_sideffectful() { + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + it.next_back(); + } + assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); + assert_eq!(&ys, &[0, 0, 0, 1]); + + let mut xs = [0; 6]; + let mut ys = [0; 4]; + + { + let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); + (&mut it).take(5).count(); + it.next_back(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); + assert_eq!(&ys, &[1, 1, 1, 1]); +} + +#[test] +fn test_zip_nested_sideffectful() { + let mut xs = [0; 6]; + let ys = [0; 4]; + + { + // test that it has the side effect nested inside enumerate + let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); + it.count(); + } + assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); +} + #[test] fn test_zip_nth_back_side_effects_exhausted() { let mut a = Vec::new(); @@ -474,7 +571,7 @@ fn test_iterator_step_by_nth_overflow() { } let mut it = Test(0); - let root = usize::MAX >> (::std::mem::size_of::() * 8 / 2); + let root = usize::MAX >> (usize::BITS / 2); let n = root + 20; (&mut it).step_by(n).nth(n); assert_eq!(it.0, n as Bigger * n as Bigger); @@ -1473,6 +1570,66 @@ fn test_iterator_rev_nth() { assert_eq!(v.iter().rev().nth(v.len()), None); } +#[test] +fn test_iterator_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[i]); + assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().advance_back_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_rev_advance_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_by(i), Ok(())); + assert_eq!(iter.next().unwrap(), &v[v.len() - 1 - i]); + assert_eq!(iter.advance_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().rev().advance_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_by(100), Err(v.len())); +} + +#[test] +fn test_iterator_rev_advance_back_by() { + let v: &[_] = &[0, 1, 2, 3, 4]; + + for i in 0..v.len() { + let mut iter = v.iter().rev(); + assert_eq!(iter.advance_back_by(i), Ok(())); + assert_eq!(iter.next_back().unwrap(), &v[i]); + assert_eq!(iter.advance_back_by(100), Err(v.len() - 1 - i)); + } + + assert_eq!(v.iter().rev().advance_back_by(v.len()), Ok(())); + assert_eq!(v.iter().rev().advance_back_by(100), Err(v.len())); +} + #[test] fn test_iterator_last() { let v: &[_] = &[0, 1, 2, 3, 4]; diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 81e621318e..0c4ce867f5 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -1,14 +1,24 @@ #![feature(alloc_layout_extra)] #![feature(array_chunks)] +#![feature(array_from_ref)] +#![feature(array_methods)] #![feature(array_map)] +#![feature(array_windows)] #![feature(bool_to_option)] #![feature(bound_cloned)] #![feature(box_syntax)] #![feature(cell_update)] +#![feature(const_assume)] +#![feature(core_intrinsics)] #![feature(core_private_bignum)] #![feature(core_private_diy_float)] #![feature(debug_non_exhaustive)] #![feature(dec2flt)] +#![feature(div_duration)] +#![feature(duration_consts_2)] +#![feature(duration_constants)] +#![feature(duration_saturating_ops)] +#![feature(duration_zero)] #![feature(exact_size_is_empty)] #![feature(fixed_size_array)] #![feature(flt2dec)] @@ -31,11 +41,14 @@ #![feature(slice_partition_dedup)] #![feature(int_error_matching)] #![feature(array_value_iter)] +#![feature(iter_advance_by)] #![feature(iter_partition_in_place)] #![feature(iter_is_partitioned)] #![feature(iter_order_by)] #![feature(cmp_min_max_by)] #![feature(iter_map_while)] +#![feature(const_mut_refs)] +#![feature(const_pin)] #![feature(const_slice_from_raw_parts)] #![feature(const_raw_ptr_deref)] #![feature(never_type)] @@ -45,6 +58,7 @@ #![feature(partition_point)] #![feature(once_cell)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(int_bits_const)] #![deny(unsafe_op_in_unsafe_fn)] extern crate test; @@ -71,6 +85,7 @@ mod num; mod ops; mod option; mod pattern; +mod pin; mod ptr; mod result; mod slice; diff --git a/library/core/tests/nonzero.rs b/library/core/tests/nonzero.rs index 48aec6d718..825e5e63b5 100644 --- a/library/core/tests/nonzero.rs +++ b/library/core/tests/nonzero.rs @@ -195,3 +195,20 @@ fn test_nonzero_from_int_on_err() { assert!(NonZeroI8::try_from(0).is_err()); assert!(NonZeroI32::try_from(0).is_err()); } + +#[test] +fn nonzero_const() { + // test that the methods of `NonZeroX>` are usable in a const context + // Note: only tests NonZero8 + + const NONZERO: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; + + const GET: u8 = NONZERO.get(); + assert_eq!(GET, 5); + + const ZERO: Option = NonZeroU8::new(0); + assert!(ZERO.is_none()); + + const ONE: Option = NonZeroU8::new(1); + assert!(ONE.is_some()); +} diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs index ae892e3b0b..8e95249a79 100644 --- a/library/core/tests/num/flt2dec/mod.rs +++ b/library/core/tests/num/flt2dec/mod.rs @@ -1,3 +1,4 @@ +use std::mem::MaybeUninit; use std::{fmt, str}; use core::num::flt2dec::{decode, DecodableFloat, Decoded, FullDecoded}; @@ -36,20 +37,20 @@ macro_rules! check_shortest { ); ($f:ident($v:expr) => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let mut buf = [b'_'; MAX_SIG_DIGITS]; - let (len, k) = $f(&decode_finite($v), &mut buf); - assert!((&buf[..len], k) == ($buf, $exp), - $fmt, actual = (str::from_utf8(&buf[..len]).unwrap(), k), + let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; + let (buf, k) = $f(&decode_finite($v), &mut buf); + assert!((buf, k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($buf).unwrap(), $exp), $($key = $val),*); }); ($f:ident{$($k:ident: $v:expr),+} => $buf:expr, $exp:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let mut buf = [b'_'; MAX_SIG_DIGITS]; - let (len, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); - assert!((&buf[..len], k) == ($buf, $exp), - $fmt, actual = (str::from_utf8(&buf[..len]).unwrap(), k), + let mut buf = [MaybeUninit::new(b'_'); MAX_SIG_DIGITS]; + let (buf, k) = $f(&Decoded { $($k: $v),+ }, &mut buf); + assert!((buf, k) == ($buf, $exp), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($buf).unwrap(), $exp), $($key = $val),*); }) @@ -58,9 +59,9 @@ macro_rules! check_shortest { macro_rules! try_exact { ($f:ident($decoded:expr) => $buf:expr, $expected:expr, $expectedk:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let (len, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); - assert!((&$buf[..len], k) == ($expected, $expectedk), - $fmt, actual = (str::from_utf8(&$buf[..len]).unwrap(), k), + let (buf, k) = $f($decoded, &mut $buf[..$expected.len()], i16::MIN); + assert!((buf, k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($expected).unwrap(), $expectedk), $($key = $val),*); }) @@ -69,9 +70,9 @@ macro_rules! try_exact { macro_rules! try_fixed { ($f:ident($decoded:expr) => $buf:expr, $request:expr, $expected:expr, $expectedk:expr; $fmt:expr, $($key:ident = $val:expr),*) => ({ - let (len, k) = $f($decoded, &mut $buf[..], $request); - assert!((&$buf[..len], k) == ($expected, $expectedk), - $fmt, actual = (str::from_utf8(&$buf[..len]).unwrap(), k), + let (buf, k) = $f($decoded, &mut $buf[..], $request); + assert!((buf, k) == ($expected, $expectedk), + $fmt, actual = (str::from_utf8(buf).unwrap(), k), expected = (str::from_utf8($expected).unwrap(), $expectedk), $($key = $val),*); }) @@ -93,10 +94,10 @@ fn ldexp_f64(a: f64, b: i32) -> f64 { fn check_exact(mut f: F, v: T, vstr: &str, expected: &[u8], expectedk: i16) where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { // use a large enough buffer - let mut buf = [b'_'; 1024]; + let mut buf = [MaybeUninit::new(b'_'); 1024]; let mut expected_ = [b'_'; 1024]; let decoded = decode_finite(v); @@ -118,7 +119,7 @@ where // we should always return `100..00` (`i` digits) instead, since that's // what we can came up with `i` digits anyway. `round_up` assumes that // the adjustment to the length is done by caller, which we simply ignore. - if let Some(_) = round_up(&mut expected_, i) { + if let Some(_) = round_up(&mut expected_[..i]) { expectedk_ += 1; } } @@ -193,10 +194,10 @@ impl TestableFloat for f64 { fn check_exact_one(mut f: F, x: i64, e: isize, tstr: &str, expected: &[u8], expectedk: i16) where T: TestableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { // use a large enough buffer - let mut buf = [b'_'; 1024]; + let mut buf = [MaybeUninit::new(b'_'); 1024]; let v: T = TestableFloat::ldexpi(x, e); let decoded = decode_finite(v); @@ -230,7 +231,7 @@ macro_rules! check_exact_one { pub fn f32_shortest_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { // 0.0999999940395355224609375 // 0.100000001490116119384765625 @@ -277,7 +278,7 @@ where pub fn f32_exact_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { let minf32 = ldexp_f32(1.0, -149); @@ -321,7 +322,7 @@ where pub fn f64_shortest_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { // 0.0999999999999999777955395074968691915273... // 0.1000000000000000055511151231257827021181... @@ -387,7 +388,7 @@ where pub fn f64_exact_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { let minf64 = ldexp_f64(1.0, -1074); @@ -474,7 +475,7 @@ where pub fn more_shortest_sanity_test(mut f: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { check_shortest!(f{mant: 99_999_999_999_999_999, minus: 1, plus: 1, exp: 0, inclusive: true} => b"1", 18); @@ -484,10 +485,10 @@ where fn to_string_with_parts(mut f: F) -> String where - F: for<'a> FnMut(&'a mut [u8], &'a mut [Part<'a>]) -> Formatted<'a>, + F: for<'a> FnMut(&'a mut [MaybeUninit], &'a mut [MaybeUninit>]) -> Formatted<'a>, { - let mut buf = [0; 1024]; - let mut parts = [Part::Zero(0); 16]; + let mut buf = [MaybeUninit::new(0); 1024]; + let mut parts = [MaybeUninit::new(Part::Zero(0)); 16]; let formatted = f(&mut buf, &mut parts); let mut ret = vec![0; formatted.len()]; assert_eq!(formatted.write(&mut ret), Some(ret.len())); @@ -496,14 +497,14 @@ where pub fn to_shortest_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_shortest_str(|d, b| f(d, b), v, sign, frac_digits, buf, parts) @@ -597,14 +598,14 @@ where pub fn to_shortest_exp_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, exp_bounds: (i16, i16), upper: bool) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_shortest_exp_str(|d, b| f(d, b), v, sign, exp_bounds, upper, buf, parts) @@ -716,14 +717,14 @@ where pub fn to_exact_exp_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, ndigits: usize, upper: bool) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_exact_exp_str(|d, b, l| f(d, b, l), v, sign, ndigits, upper, buf, parts) @@ -989,14 +990,14 @@ where pub fn to_exact_fixed_str_test(mut f_: F) where - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { use core::num::flt2dec::Sign::*; fn to_string(f: &mut F, v: T, sign: Sign, frac_digits: usize) -> String where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { to_string_with_parts(|buf, parts| { to_exact_fixed_str(|d, b, l| f(d, b, l), v, sign, frac_digits, buf, parts) diff --git a/library/core/tests/num/flt2dec/random.rs b/library/core/tests/num/flt2dec/random.rs index e5656eb204..57b3dcf8e1 100644 --- a/library/core/tests/num/flt2dec/random.rs +++ b/library/core/tests/num/flt2dec/random.rs @@ -1,5 +1,6 @@ #![cfg(not(target_arch = "wasm32"))] +use std::mem::MaybeUninit; use std::str; use core::num::flt2dec::strategy::grisu::format_exact_opt; @@ -20,8 +21,8 @@ pub fn decode_finite(v: T) -> Decoded { fn iterate(func: &str, k: usize, n: usize, mut f: F, mut g: G, mut v: V) -> (usize, usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), V: FnMut(usize) -> Decoded, { assert!(k <= 1024); @@ -42,11 +43,11 @@ where } let decoded = v(i); - let mut buf1 = [0; 1024]; - if let Some((len1, e1)) = f(&decoded, &mut buf1[..k]) { - let mut buf2 = [0; 1024]; - let (len2, e2) = g(&decoded, &mut buf2[..k]); - if e1 == e2 && &buf1[..len1] == &buf2[..len2] { + let mut buf1 = [MaybeUninit::new(0); 1024]; + if let Some((buf1, e1)) = f(&decoded, &mut buf1[..k]) { + let mut buf2 = [MaybeUninit::new(0); 1024]; + let (buf2, e2) = g(&decoded, &mut buf2[..k]); + if e1 == e2 && buf1 == buf2 { npassed += 1; } else { println!( @@ -54,9 +55,9 @@ where i, n, decoded, - str::from_utf8(&buf1[..len1]).unwrap(), + str::from_utf8(buf1).unwrap(), e1, - str::from_utf8(&buf2[..len2]).unwrap(), + str::from_utf8(buf2).unwrap(), e2 ); } @@ -85,8 +86,8 @@ where pub fn f32_random_equivalence_test(f: F, g: G, k: usize, n: usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { if cfg!(target_os = "emscripten") { return; // using rng pulls in i128 support, which doesn't work @@ -101,8 +102,8 @@ where pub fn f64_random_equivalence_test(f: F, g: G, k: usize, n: usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { if cfg!(target_os = "emscripten") { return; // using rng pulls in i128 support, which doesn't work @@ -117,8 +118,8 @@ where pub fn f32_exhaustive_equivalence_test(f: F, g: G, k: usize) where - F: FnMut(&Decoded, &mut [u8]) -> Option<(usize, i16)>, - G: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> Option<(&'a [u8], i16)>, + G: for<'a> FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { // we have only 2^23 * (2^8 - 1) - 1 = 2,139,095,039 positive finite f32 values, // so why not simply testing all of them? diff --git a/library/core/tests/num/i32.rs b/library/core/tests/num/i32.rs index 39250ee84b..4acc760ffa 100644 --- a/library/core/tests/num/i32.rs +++ b/library/core/tests/num/i32.rs @@ -1 +1,30 @@ int_module!(i32, i32); + +#[test] +fn test_arith_operation() { + let a: isize = 10; + assert_eq!(a * (a - 1), 90); + let i32_a: isize = 10; + assert_eq!(i32_a, 10); + assert_eq!(i32_a - 10, 0); + assert_eq!(i32_a / 10, 1); + assert_eq!(i32_a - 20, -10); + assert_eq!(i32_a << 10, 10240); + assert_eq!(i32_a << 16, 655360); + assert_eq!(i32_a * 16, 160); + assert_eq!(i32_a * i32_a * i32_a, 1000); + assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); + assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); + assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); + let i32_b: isize = 0x10101010; + assert_eq!(i32_b + 1 - 1, i32_b); + assert_eq!(i32_b << 1, i32_b << 1); + assert_eq!(i32_b >> 1, i32_b >> 1); + assert_eq!(i32_b & i32_b << 1, 0); + assert_eq!(i32_b | i32_b << 1, 0x30303030); + let i32_c: isize = 0x10101010; + assert_eq!( + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), + i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3) + ); +} diff --git a/library/core/tests/num/int_macros.rs b/library/core/tests/num/int_macros.rs index 58a5856691..27e6760e7c 100644 --- a/library/core/tests/num/int_macros.rs +++ b/library/core/tests/num/int_macros.rs @@ -2,7 +2,6 @@ macro_rules! int_module { ($T:ident, $T_i:ident) => { #[cfg(test)] mod tests { - use core::mem; use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; @@ -82,30 +81,27 @@ macro_rules! int_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert_eq!(A.count_zeros(), bits as u32 - 3); - assert_eq!(B.count_zeros(), bits as u32 - 2); - assert_eq!(C.count_zeros(), bits as u32 - 5); + assert_eq!(A.count_zeros(), $T::BITS - 3); + assert_eq!(B.count_zeros(), $T::BITS - 2); + assert_eq!(C.count_zeros(), $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!(MAX.leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!(MAX.trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!(MAX.trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/core/tests/num/mod.rs b/library/core/tests/num/mod.rs index 939f1325c8..378c8af344 100644 --- a/library/core/tests/num/mod.rs +++ b/library/core/tests/num/mod.rs @@ -634,14 +634,18 @@ assume_usize_width! { macro_rules! test_float { ($modname: ident, $fty: ty, $inf: expr, $neginf: expr, $nan: expr) => { mod $modname { - // FIXME(nagisa): these tests should test for sign of -0.0 #[test] fn min() { assert_eq!((0.0 as $fty).min(0.0), 0.0); + assert!((0.0 as $fty).min(0.0).is_sign_positive()); assert_eq!((-0.0 as $fty).min(-0.0), -0.0); + assert!((-0.0 as $fty).min(-0.0).is_sign_negative()); assert_eq!((9.0 as $fty).min(9.0), 9.0); assert_eq!((-9.0 as $fty).min(0.0), -9.0); assert_eq!((0.0 as $fty).min(9.0), 0.0); + assert!((0.0 as $fty).min(9.0).is_sign_positive()); + assert_eq!((-0.0 as $fty).min(9.0), -0.0); + assert!((-0.0 as $fty).min(9.0).is_sign_negative()); assert_eq!((-0.0 as $fty).min(-9.0), -9.0); assert_eq!(($inf as $fty).min(9.0), 9.0); assert_eq!((9.0 as $fty).min($inf), 9.0); @@ -660,11 +664,19 @@ macro_rules! test_float { #[test] fn max() { assert_eq!((0.0 as $fty).max(0.0), 0.0); + assert!((0.0 as $fty).max(0.0).is_sign_positive()); assert_eq!((-0.0 as $fty).max(-0.0), -0.0); + assert!((-0.0 as $fty).max(-0.0).is_sign_negative()); assert_eq!((9.0 as $fty).max(9.0), 9.0); assert_eq!((-9.0 as $fty).max(0.0), 0.0); + assert!((-9.0 as $fty).max(0.0).is_sign_positive()); + assert_eq!((-9.0 as $fty).max(-0.0), -0.0); + assert!((-9.0 as $fty).max(-0.0).is_sign_negative()); assert_eq!((0.0 as $fty).max(9.0), 9.0); + assert_eq!((0.0 as $fty).max(-9.0), 0.0); + assert!((0.0 as $fty).max(-9.0).is_sign_positive()); assert_eq!((-0.0 as $fty).max(-9.0), -0.0); + assert!((-0.0 as $fty).max(-9.0).is_sign_negative()); assert_eq!(($inf as $fty).max(9.0), $inf); assert_eq!((9.0 as $fty).max($inf), $inf); assert_eq!(($inf as $fty).max(-9.0), $inf); diff --git a/library/core/tests/num/uint_macros.rs b/library/core/tests/num/uint_macros.rs index b84a8a7d9f..952ec188dc 100644 --- a/library/core/tests/num/uint_macros.rs +++ b/library/core/tests/num/uint_macros.rs @@ -4,7 +4,6 @@ macro_rules! uint_module { mod tests { use core::ops::{BitAnd, BitOr, BitXor, Not, Shl, Shr}; use core::$T_i::*; - use std::mem; use std::str::FromStr; use crate::num; @@ -47,30 +46,27 @@ macro_rules! uint_module { #[test] fn test_count_zeros() { - let bits = mem::size_of::<$T>() * 8; - assert!(A.count_zeros() == bits as u32 - 3); - assert!(B.count_zeros() == bits as u32 - 2); - assert!(C.count_zeros() == bits as u32 - 5); + assert!(A.count_zeros() == $T::BITS - 3); + assert!(B.count_zeros() == $T::BITS - 2); + assert!(C.count_zeros() == $T::BITS - 5); } #[test] fn test_leading_trailing_ones() { - let bits = (mem::size_of::<$T>() * 8) as u32; - let a: $T = 0b0101_1111; assert_eq!(a.trailing_ones(), 5); - assert_eq!((!a).leading_ones(), bits - 7); + assert_eq!((!a).leading_ones(), $T::BITS - 7); assert_eq!(a.reverse_bits().leading_ones(), 5); - assert_eq!(_1.leading_ones(), bits); - assert_eq!(_1.trailing_ones(), bits); + assert_eq!(_1.leading_ones(), $T::BITS); + assert_eq!(_1.trailing_ones(), $T::BITS); assert_eq!((_1 << 1).trailing_ones(), 0); assert_eq!((_1 >> 1).leading_ones(), 0); - assert_eq!((_1 << 1).leading_ones(), bits - 1); - assert_eq!((_1 >> 1).trailing_ones(), bits - 1); + assert_eq!((_1 << 1).leading_ones(), $T::BITS - 1); + assert_eq!((_1 >> 1).trailing_ones(), $T::BITS - 1); assert_eq!(_0.leading_ones(), 0); assert_eq!(_0.trailing_ones(), 0); diff --git a/library/core/tests/num/wrapping.rs b/library/core/tests/num/wrapping.rs new file mode 100644 index 0000000000..5d4ecb2669 --- /dev/null +++ b/library/core/tests/num/wrapping.rs @@ -0,0 +1,76 @@ +use core::num::Wrapping; + +macro_rules! wrapping_operation { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + assert_eq!($result, $lhs $op $rhs); + assert_eq!($result, &$lhs $op $rhs); + assert_eq!($result, $lhs $op &$rhs); + assert_eq!($result, &$lhs $op &$rhs); + }; + ($result:expr, $op:tt $expr:expr) => { + assert_eq!($result, $op $expr); + assert_eq!($result, $op &$expr); + }; +} + +macro_rules! wrapping_assignment { + ($result:expr, $lhs:ident $op:tt $rhs:expr) => { + let mut lhs1 = $lhs; + lhs1 $op $rhs; + assert_eq!($result, lhs1); + + let mut lhs2 = $lhs; + lhs2 $op &$rhs; + assert_eq!($result, lhs2); + }; +} + +macro_rules! wrapping_test { + ($type:ty, $min:expr, $max:expr) => { + #[test] + fn wrapping_$type() { + let zero: Wrapping<$type> = Wrapping(0); + let one: Wrapping<$type> = Wrapping(1); + let min: Wrapping<$type> = Wrapping($min); + let max: Wrapping<$type> = Wrapping($max); + + wrapping_operation!(min, max + one); + wrapping_assignment!(min, max += one); + wrapping_operation!(max, min - one); + wrapping_assignment!(max, min -= one); + wrapping_operation!(max, max * one); + wrapping_assignment!(max, max *= one); + wrapping_operation!(max, max / one); + wrapping_assignment!(max, max /= one); + wrapping_operation!(zero, max % one); + wrapping_assignment!(zero, max %= one); + wrapping_operation!(zero, zero & max); + wrapping_assignment!(zero, zero &= max); + wrapping_operation!(max, zero | max); + wrapping_assignment!(max, zero |= max); + wrapping_operation!(zero, max ^ max); + wrapping_assignment!(zero, max ^= max); + wrapping_operation!(zero, zero << 1usize); + wrapping_assignment!(zero, zero <<= 1usize); + wrapping_operation!(zero, zero >> 1usize); + wrapping_assignment!(zero, zero >>= 1usize); + wrapping_operation!(zero, -zero); + wrapping_operation!(max, !min); + } + }; +} + +wrapping_test!(i8, i8::MIN, i8::MAX); +wrapping_test!(i16, i16::MIN, i16::MAX); +wrapping_test!(i32, i32::MIN, i32::MAX); +wrapping_test!(i64, i64::MIN, i64::MAX); +#[cfg(not(target_os = "emscripten"))] +wrapping_test!(i128, i128::MIN, i128::MAX); +wrapping_test!(isize, isize::MIN, isize::MAX); +wrapping_test!(u8, u8::MIN, u8::MAX); +wrapping_test!(u16, u16::MIN, u16::MAX); +wrapping_test!(u32, u32::MIN, u32::MAX); +wrapping_test!(u64, u64::MIN, u64::MAX); +#[cfg(not(target_os = "emscripten"))] +wrapping_test!(u128, u128::MIN, u128::MAX); +wrapping_test!(usize, usize::MIN, usize::MAX); diff --git a/library/core/tests/option.rs b/library/core/tests/option.rs index fa308160fc..ae814efec2 100644 --- a/library/core/tests/option.rs +++ b/library/core/tests/option.rs @@ -1,4 +1,4 @@ -use core::array::FixedSizeArray; +use core::cell::Cell; use core::clone::Clone; use core::mem; use core::ops::DerefMut; @@ -357,3 +357,48 @@ fn test_replace() { assert_eq!(x, Some(3)); assert_eq!(old, None); } + +#[test] +fn option_const() { + // test that the methods of `Option` are usable in a const context + + const OPTION: Option = Some(32); + + const REF: Option<&usize> = OPTION.as_ref(); + assert_eq!(REF, Some(&32)); + + const IS_SOME: bool = OPTION.is_some(); + assert!(IS_SOME); + + const IS_NONE: bool = OPTION.is_none(); + assert!(!IS_NONE); +} + +#[test] +fn test_unwrap_drop() { + struct Dtor<'a> { + x: &'a Cell, + } + + impl<'a> std::ops::Drop for Dtor<'a> { + fn drop(&mut self) { + self.x.set(self.x.get() - 1); + } + } + + fn unwrap(o: Option) -> T { + match o { + Some(v) => v, + None => panic!(), + } + } + + let x = &Cell::new(1); + + { + let b = Some(Dtor { x }); + let _c = unwrap(b); + } + + assert_eq!(x.get(), 0); +} diff --git a/library/core/tests/pin.rs b/library/core/tests/pin.rs new file mode 100644 index 0000000000..6f617c8d0c --- /dev/null +++ b/library/core/tests/pin.rs @@ -0,0 +1,31 @@ +use core::pin::Pin; + +#[test] +fn pin_const() { + // test that the methods of `Pin` are usable in a const context + + const POINTER: &'static usize = &2; + + const PINNED: Pin<&'static usize> = Pin::new(POINTER); + const PINNED_UNCHECKED: Pin<&'static usize> = unsafe { Pin::new_unchecked(POINTER) }; + assert_eq!(PINNED_UNCHECKED, PINNED); + + const INNER: &'static usize = Pin::into_inner(PINNED); + assert_eq!(INNER, POINTER); + + const INNER_UNCHECKED: &'static usize = unsafe { Pin::into_inner_unchecked(PINNED) }; + assert_eq!(INNER_UNCHECKED, POINTER); + + const REF: &'static usize = PINNED.get_ref(); + assert_eq!(REF, POINTER); + + // Note: `pin_mut_const` tests that the methods of `Pin<&mut T>` are usable in a const context. + // A const fn is used because `&mut` is not (yet) usable in constants. + const fn pin_mut_const() { + let _ = Pin::new(&mut 2).into_ref(); + let _ = Pin::new(&mut 2).get_mut(); + let _ = unsafe { Pin::new(&mut 2).get_unchecked_mut() }; + } + + pin_mut_const(); +} diff --git a/library/core/tests/result.rs b/library/core/tests/result.rs index caa2d916cd..39ea4831b9 100644 --- a/library/core/tests/result.rs +++ b/library/core/tests/result.rs @@ -1,4 +1,3 @@ -use core::array::FixedSizeArray; use core::ops::DerefMut; use core::option::*; @@ -305,3 +304,19 @@ fn test_result_as_deref_mut() { let expected_result = Result::Err::<&mut u32, &mut Vec>(&mut expected_vec); assert_eq!(mut_err.as_deref_mut(), expected_result); } + +#[test] +fn result_const() { + // test that the methods of `Result` are usable in a const context + + const RESULT: Result = Ok(32); + + const REF: Result<&usize, &bool> = RESULT.as_ref(); + assert_eq!(REF, Ok(&32)); + + const IS_OK: bool = RESULT.is_ok(); + assert!(IS_OK); + + const IS_ERR: bool = RESULT.is_err(); + assert!(!IS_ERR) +} diff --git a/library/core/tests/slice.rs b/library/core/tests/slice.rs index 5650c98f9c..5ef30b1a88 100644 --- a/library/core/tests/slice.rs +++ b/library/core/tests/slice.rs @@ -1,3 +1,4 @@ +use core::cell::Cell; use core::result::Result::{Err, Ok}; #[test] @@ -564,6 +565,148 @@ fn test_array_chunks_zip() { assert_eq!(res, vec![14, 22]); } +#[test] +fn test_array_chunks_mut_infer() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + for a in v.array_chunks_mut() { + let sum = a.iter().sum::(); + *a = [sum; 3]; + } + assert_eq!(v, &[3, 3, 3, 12, 12, 12, 6]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + v2.array_chunks_mut().for_each(|[a, b]| core::mem::swap(a, b)); + assert_eq!(v2, &[1, 0, 3, 2, 5, 4, 6]); +} + +#[test] +fn test_array_chunks_mut_count() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<3>(); + assert_eq!(c.count(), 2); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.count(), 2); + + let v3: &mut [i32] = &mut []; + let c3 = v3.array_chunks_mut::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_chunks_mut_nth() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4, 5, 6]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth(1).unwrap(), &[3, 4, 5]); + assert_eq!(c2.next(), None); +} + +#[test] +fn test_array_chunks_mut_nth_back() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let mut c = v.array_chunks_mut::<2>(); + assert_eq!(c.nth_back(1).unwrap(), &[2, 3]); + assert_eq!(c.next().unwrap(), &[0, 1]); + assert_eq!(c.next(), None); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c2 = v2.array_chunks_mut::<3>(); + assert_eq!(c2.nth_back(0).unwrap(), &[0, 1, 2]); + assert_eq!(c2.next(), None); + assert_eq!(c2.next_back(), None); + + let v3: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let mut c3 = v3.array_chunks_mut::<10>(); + assert_eq!(c3.nth_back(0), None); +} + +#[test] +fn test_array_chunks_mut_last() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4, 5]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.last().unwrap(), &[4, 5]); + + let v2: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c2 = v2.array_chunks_mut::<2>(); + assert_eq!(c2.last().unwrap(), &[2, 3]); +} + +#[test] +fn test_array_chunks_mut_remainder() { + let v: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let c = v.array_chunks_mut::<2>(); + assert_eq!(c.into_remainder(), &[4]); +} + +#[test] +fn test_array_chunks_mut_zip() { + let v1: &mut [i32] = &mut [0, 1, 2, 3, 4]; + let v2: &[i32] = &[6, 7, 8, 9, 10]; + + for (a, b) in v1.array_chunks_mut::<2>().zip(v2.array_chunks::<2>()) { + let sum = b.iter().sum::(); + for v in a { + *v += sum; + } + } + assert_eq!(v1, [13, 14, 19, 20, 4]); +} + +#[test] +fn test_array_windows_infer() { + let v: &[i32] = &[0, 1, 0, 1]; + assert_eq!(v.array_windows::<2>().count(), 3); + let c = v.array_windows(); + for &[a, b] in c { + assert_eq!(a + b, 1); + } + + let v2: &[i32] = &[0, 1, 2, 3, 4, 5, 6]; + let total = v2.array_windows().map(|&[a, b, c]| a + b + c).sum::(); + assert_eq!(total, 3 + 6 + 9 + 12 + 15); +} + +#[test] +fn test_array_windows_count() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let c = v.array_windows::<3>(); + assert_eq!(c.count(), 4); + + let v2: &[i32] = &[0, 1, 2, 3, 4]; + let c2 = v2.array_windows::<6>(); + assert_eq!(c2.count(), 0); + + let v3: &[i32] = &[]; + let c3 = v3.array_windows::<2>(); + assert_eq!(c3.count(), 0); +} + +#[test] +fn test_array_windows_nth() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth(0), arr_windows.nth(0)); + let last = v.array_windows::<3>().last(); + assert_eq!(last, Some(&[3, 4, 5])); +} + +#[test] +fn test_array_windows_nth_back() { + let v: &[i32] = &[0, 1, 2, 3, 4, 5]; + let snd = v.array_windows::<4>().nth_back(1); + assert_eq!(snd, Some(&[1, 2, 3, 4])); + let mut arr_windows = v.array_windows::<2>(); + assert_ne!(arr_windows.nth_back(0), arr_windows.nth_back(0)); +} + #[test] fn test_rchunks_count() { let v: &[i32] = &[0, 1, 2, 3, 4, 5]; @@ -1795,7 +1938,7 @@ fn test_copy_within() { } #[test] -#[should_panic(expected = "src is out of bounds")] +#[should_panic(expected = "range end index 14 out of range for slice of length 13")] fn test_copy_within_panics_src_too_long() { let mut bytes = *b"Hello, World!"; // The length is only 13, so 14 is out of bounds. @@ -1810,7 +1953,7 @@ fn test_copy_within_panics_dest_too_long() { bytes.copy_within(0..4, 10); } #[test] -#[should_panic(expected = "src end is before src start")] +#[should_panic(expected = "slice index starts at 2 but ends at 1")] fn test_copy_within_panics_src_inverted() { let mut bytes = *b"Hello, World!"; // 2 is greater than 1, so this range is invalid. @@ -1838,3 +1981,30 @@ fn test_is_sorted() { assert!(!["c", "bb", "aaa"].is_sorted()); assert!(["c", "bb", "aaa"].is_sorted_by_key(|s| s.len())); } + +#[test] +fn test_slice_run_destructors() { + // Make sure that destructors get run on slice literals + struct Foo<'a> { + x: &'a Cell, + } + + impl<'a> Drop for Foo<'a> { + fn drop(&mut self) { + self.x.set(self.x.get() + 1); + } + } + + fn foo(x: &Cell) -> Foo<'_> { + Foo { x } + } + + let x = &Cell::new(0); + + { + let l = &[foo(x)]; + assert_eq!(l[0].x.get(), 0); + } + + assert_eq!(x.get(), 1); +} diff --git a/library/core/tests/time.rs b/library/core/tests/time.rs index 7a6675dc82..7c43885040 100644 --- a/library/core/tests/time.rs +++ b/library/core/tests/time.rs @@ -89,6 +89,16 @@ fn checked_add() { assert_eq!(Duration::new(1, 0).checked_add(Duration::new(u64::MAX, 0)), None); } +#[test] +fn saturating_add() { + assert_eq!(Duration::new(0, 0).saturating_add(Duration::new(0, 1)), Duration::new(0, 1)); + assert_eq!( + Duration::new(0, 500_000_000).saturating_add(Duration::new(0, 500_000_001)), + Duration::new(1, 1) + ); + assert_eq!(Duration::new(1, 0).saturating_add(Duration::new(u64::MAX, 0)), Duration::MAX); +} + #[test] fn sub() { assert_eq!(Duration::new(0, 1) - Duration::new(0, 0), Duration::new(0, 1)); @@ -107,6 +117,17 @@ fn checked_sub() { assert_eq!(zero.checked_sub(one_sec), None); } +#[test] +fn saturating_sub() { + let zero = Duration::new(0, 0); + let one_nano = Duration::new(0, 1); + let one_sec = Duration::new(1, 0); + assert_eq!(one_nano.saturating_sub(zero), Duration::new(0, 1)); + assert_eq!(one_sec.saturating_sub(one_nano), Duration::new(0, 999_999_999)); + assert_eq!(zero.saturating_sub(one_nano), Duration::MIN); + assert_eq!(zero.saturating_sub(one_sec), Duration::MIN); +} + #[test] #[should_panic] fn sub_bad1() { @@ -136,6 +157,15 @@ fn checked_mul() { assert_eq!(Duration::new(u64::MAX - 1, 0).checked_mul(2), None); } +#[test] +fn saturating_mul() { + assert_eq!(Duration::new(0, 1).saturating_mul(2), Duration::new(0, 2)); + assert_eq!(Duration::new(1, 1).saturating_mul(3), Duration::new(3, 3)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4), Duration::new(2, 4)); + assert_eq!(Duration::new(0, 500_000_001).saturating_mul(4000), Duration::new(2000, 4000)); + assert_eq!(Duration::new(u64::MAX - 1, 0).saturating_mul(2), Duration::MAX); +} + #[test] fn div() { assert_eq!(Duration::new(0, 1) / 2, Duration::new(0, 0)); @@ -291,3 +321,104 @@ fn debug_formatting_precision_high() { assert_eq!(format!("{:.10?}", Duration::new(4, 001_000_000)), "4.0010000000s"); assert_eq!(format!("{:.20?}", Duration::new(4, 001_000_000)), "4.00100000000000000000s"); } + +#[test] +fn duration_const() { + // test that the methods of `Duration` are usable in a const context + + const DURATION: Duration = Duration::new(0, 123_456_789); + + const SUB_SEC_MILLIS: u32 = DURATION.subsec_millis(); + assert_eq!(SUB_SEC_MILLIS, 123); + + const SUB_SEC_MICROS: u32 = DURATION.subsec_micros(); + assert_eq!(SUB_SEC_MICROS, 123_456); + + const SUB_SEC_NANOS: u32 = DURATION.subsec_nanos(); + assert_eq!(SUB_SEC_NANOS, 123_456_789); + + const ZERO: Duration = Duration::zero(); + assert_eq!(ZERO, Duration::new(0, 0)); + + const IS_ZERO: bool = ZERO.is_zero(); + assert!(IS_ZERO); + + const ONE: Duration = Duration::new(1, 0); + + const SECONDS: u64 = ONE.as_secs(); + assert_eq!(SECONDS, 1); + + const FROM_SECONDS: Duration = Duration::from_secs(1); + assert_eq!(FROM_SECONDS, ONE); + + const SECONDS_F32: f32 = ONE.as_secs_f32(); + assert_eq!(SECONDS_F32, 1.0); + + const FROM_SECONDS_F32: Duration = Duration::from_secs_f32(1.0); + assert_eq!(FROM_SECONDS_F32, ONE); + + const SECONDS_F64: f64 = ONE.as_secs_f64(); + assert_eq!(SECONDS_F64, 1.0); + + const FROM_SECONDS_F64: Duration = Duration::from_secs_f64(1.0); + assert_eq!(FROM_SECONDS_F64, ONE); + + const MILLIS: u128 = ONE.as_millis(); + assert_eq!(MILLIS, 1_000); + + const FROM_MILLIS: Duration = Duration::from_millis(1_000); + assert_eq!(FROM_MILLIS, ONE); + + const MICROS: u128 = ONE.as_micros(); + assert_eq!(MICROS, 1_000_000); + + const FROM_MICROS: Duration = Duration::from_micros(1_000_000); + assert_eq!(FROM_MICROS, ONE); + + const NANOS: u128 = ONE.as_nanos(); + assert_eq!(NANOS, 1_000_000_000); + + const FROM_NANOS: Duration = Duration::from_nanos(1_000_000_000); + assert_eq!(FROM_NANOS, ONE); + + const MAX: Duration = Duration::new(u64::MAX, 999_999_999); + + const CHECKED_ADD: Option = MAX.checked_add(ONE); + assert_eq!(CHECKED_ADD, None); + + const CHECKED_SUB: Option = ZERO.checked_sub(ONE); + assert_eq!(CHECKED_SUB, None); + + const CHECKED_MUL: Option = ONE.checked_mul(1); + assert_eq!(CHECKED_MUL, Some(ONE)); + + const MUL_F32: Duration = ONE.mul_f32(1.0); + assert_eq!(MUL_F32, ONE); + + const MUL_F64: Duration = ONE.mul_f64(1.0); + assert_eq!(MUL_F64, ONE); + + const CHECKED_DIV: Option = ONE.checked_div(1); + assert_eq!(CHECKED_DIV, Some(ONE)); + + const DIV_F32: Duration = ONE.div_f32(1.0); + assert_eq!(DIV_F32, ONE); + + const DIV_F64: Duration = ONE.div_f64(1.0); + assert_eq!(DIV_F64, ONE); + + const DIV_DURATION_F32: f32 = ONE.div_duration_f32(ONE); + assert_eq!(DIV_DURATION_F32, 1.0); + + const DIV_DURATION_F64: f64 = ONE.div_duration_f64(ONE); + assert_eq!(DIV_DURATION_F64, 1.0); + + const SATURATING_ADD: Duration = MAX.saturating_add(ONE); + assert_eq!(SATURATING_ADD, MAX); + + const SATURATING_SUB: Duration = ZERO.saturating_sub(ONE); + assert_eq!(SATURATING_SUB, ZERO); + + const SATURATING_MUL: Duration = MAX.saturating_mul(2); + assert_eq!(SATURATING_MUL, MAX); +} diff --git a/library/panic_abort/src/lib.rs b/library/panic_abort/src/lib.rs index ccc067a3c9..9690996e60 100644 --- a/library/panic_abort/src/lib.rs +++ b/library/panic_abort/src/lib.rs @@ -12,12 +12,11 @@ #![panic_runtime] #![allow(unused_features)] #![feature(core_intrinsics)] -#![feature(libc)] #![feature(nll)] #![feature(panic_runtime)] #![feature(staged_api)] #![feature(rustc_attrs)] -#![feature(llvm_asm)] +#![feature(asm)] use core::any::Any; @@ -47,7 +46,7 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { } __rust_abort(); } - } else if #[cfg(all(windows, any(target_arch = "x86", target_arch = "x86_64")))] { + } else if #[cfg(all(windows, not(miri)))] { // On Windows, use the processor-specific __fastfail mechanism. In Windows 8 // and later, this will terminate the process immediately without running any // in-process exception handlers. In earlier versions of Windows, this @@ -59,7 +58,18 @@ pub unsafe extern "C" fn __rust_start_panic(_payload: usize) -> u32 { // // Note: this is the same implementation as in libstd's `abort_internal` unsafe fn abort() -> ! { - llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT + const FAST_FAIL_FATAL_APP_EXIT: usize = 7; + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { + asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); + } else if #[cfg(target_arch = "aarch64")] { + asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); + } else { + core::intrinsics::abort(); + } + } core::intrinsics::unreachable(); } } else { @@ -117,6 +127,17 @@ pub mod personalities { 1 // `ExceptionContinueSearch` } + // Similar to above, this corresponds to the `eh_catch_typeinfo` lang item + // that's only used on Emscripten currently. + // + // Since panics don't generate exceptions and foreign exceptions are + // currently UB with -C panic=abort (although this may be subject to + // change), any catch_unwind calls will never use this typeinfo. + #[rustc_std_internal_symbol] + #[allow(non_upper_case_globals)] + #[cfg(target_os = "emscripten")] + static rust_eh_catch_typeinfo: [usize; 2] = [0; 2]; + // These two are called by our startup objects on i686-pc-windows-gnu, but // they don't need to do anything so the bodies are nops. #[rustc_std_internal_symbol] diff --git a/library/panic_unwind/src/dwarf/eh.rs b/library/panic_unwind/src/dwarf/eh.rs index 302478cfac..8ce4dcd2ac 100644 --- a/library/panic_unwind/src/dwarf/eh.rs +++ b/library/panic_unwind/src/dwarf/eh.rs @@ -51,11 +51,7 @@ pub enum EHAction { pub const USING_SJLJ_EXCEPTIONS: bool = cfg!(all(target_os = "ios", target_arch = "arm")); -pub unsafe fn find_eh_action( - lsda: *const u8, - context: &EHContext<'_>, - foreign_exception: bool, -) -> Result { +pub unsafe fn find_eh_action(lsda: *const u8, context: &EHContext<'_>) -> Result { if lsda.is_null() { return Ok(EHAction::None); } @@ -98,7 +94,7 @@ pub unsafe fn find_eh_action( return Ok(EHAction::None); } else { let lpad = lpad_base + cs_lpad; - return Ok(interpret_cs_action(cs_action, lpad, foreign_exception)); + return Ok(interpret_cs_action(cs_action, lpad)); } } } @@ -123,21 +119,17 @@ pub unsafe fn find_eh_action( // Can never have null landing pad for sjlj -- that would have // been indicated by a -1 call site index. let lpad = (cs_lpad + 1) as usize; - return Ok(interpret_cs_action(cs_action, lpad, foreign_exception)); + return Ok(interpret_cs_action(cs_action, lpad)); } } } } -fn interpret_cs_action(cs_action: u64, lpad: usize, foreign_exception: bool) -> EHAction { +fn interpret_cs_action(cs_action: u64, lpad: usize) -> EHAction { if cs_action == 0 { // If cs_action is 0 then this is a cleanup (Drop::drop). We run these // for both Rust panics and foreign exceptions. EHAction::Cleanup(lpad) - } else if foreign_exception { - // catch_unwind should not catch foreign exceptions, only Rust panics. - // Instead just continue unwinding. - EHAction::None } else { // Stop unwinding Rust panics at catch_unwind. EHAction::Catch(lpad) diff --git a/library/panic_unwind/src/dwarf/mod.rs b/library/panic_unwind/src/dwarf/mod.rs index 649bbce52a..652fbe95a1 100644 --- a/library/panic_unwind/src/dwarf/mod.rs +++ b/library/panic_unwind/src/dwarf/mod.rs @@ -53,7 +53,7 @@ impl DwarfReader { } pub unsafe fn read_sleb128(&mut self) -> i64 { - let mut shift: usize = 0; + let mut shift: u32 = 0; let mut result: u64 = 0; let mut byte: u8; loop { @@ -65,7 +65,7 @@ impl DwarfReader { } } // sign-extend - if shift < 8 * mem::size_of::() && (byte & 0x40) != 0 { + if shift < u64::BITS && (byte & 0x40) != 0 { result |= (!0 as u64) << shift; } result as i64 diff --git a/library/panic_unwind/src/emcc.rs b/library/panic_unwind/src/emcc.rs index a0bdb1481c..e428f2fdaa 100644 --- a/library/panic_unwind/src/emcc.rs +++ b/library/panic_unwind/src/emcc.rs @@ -8,8 +8,10 @@ use alloc::boxed::Box; use core::any::Any; +use core::intrinsics; use core::mem; use core::ptr; +use core::sync::atomic::{AtomicBool, Ordering}; use libc::{self, c_int}; use unwind as uw; @@ -47,6 +49,11 @@ static EXCEPTION_TYPE_INFO: TypeInfo = TypeInfo { }; struct Exception { + // This is necessary because C++ code can capture our execption with + // std::exception_ptr and rethrow it multiple times, possibly even in + // another thread. + caught: AtomicBool, + // This needs to be an Option because the object's lifetime follows C++ // semantics: when catch_unwind moves the Box out of the exception it must // still leave the exception object in a valid state because its destructor @@ -55,11 +62,27 @@ struct Exception { } pub unsafe fn cleanup(ptr: *mut u8) -> Box { - assert!(!ptr.is_null()); - let adjusted_ptr = __cxa_begin_catch(ptr as *mut libc::c_void) as *mut Exception; - let ex = (*adjusted_ptr).data.take(); + // intrinsics::try actually gives us a pointer to this structure. + #[repr(C)] + struct CatchData { + ptr: *mut u8, + is_rust_panic: bool, + } + let catch_data = &*(ptr as *mut CatchData); + + let adjusted_ptr = __cxa_begin_catch(catch_data.ptr as *mut libc::c_void) as *mut Exception; + let out = if catch_data.is_rust_panic { + let was_caught = (*adjusted_ptr).caught.swap(true, Ordering::SeqCst); + if was_caught { + // Since cleanup() isn't allowed to panic, we just abort instead. + intrinsics::abort(); + } + (*adjusted_ptr).data.take().unwrap() + } else { + super::__rust_foreign_exception(); + }; __cxa_end_catch(); - ex.unwrap() + out } pub unsafe fn panic(data: Box) -> u32 { @@ -68,25 +91,16 @@ pub unsafe fn panic(data: Box) -> u32 { if exception.is_null() { return uw::_URC_FATAL_PHASE1_ERROR as u32; } - ptr::write(exception, Exception { data: Some(data) }); + ptr::write(exception, Exception { caught: AtomicBool::new(false), data: Some(data) }); __cxa_throw(exception as *mut _, &EXCEPTION_TYPE_INFO, exception_cleanup); } -// On WASM and ARM, the destructor returns the pointer to the object. -cfg_if::cfg_if! { - if #[cfg(any(target_arch = "arm", target_arch = "wasm32"))] { - type DestructorRet = *mut libc::c_void; - } else { - type DestructorRet = (); - } -} -extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> DestructorRet { +extern "C" fn exception_cleanup(ptr: *mut libc::c_void) -> *mut libc::c_void { unsafe { if let Some(b) = (ptr as *mut Exception).read().data { drop(b); super::__rust_drop_panic(); } - #[cfg(any(target_arch = "arm", target_arch = "wasm32"))] ptr } } @@ -109,7 +123,7 @@ extern "C" { fn __cxa_throw( thrown_exception: *mut libc::c_void, tinfo: *const TypeInfo, - dest: extern "C" fn(*mut libc::c_void) -> DestructorRet, + dest: extern "C" fn(*mut libc::c_void) -> *mut libc::c_void, ) -> !; fn __gxx_personality_v0( version: c_int, diff --git a/library/panic_unwind/src/gcc.rs b/library/panic_unwind/src/gcc.rs index f5d83c21da..6b88bab827 100644 --- a/library/panic_unwind/src/gcc.rs +++ b/library/panic_unwind/src/gcc.rs @@ -73,8 +73,14 @@ pub unsafe fn panic(data: Box) -> u32 { } pub unsafe fn cleanup(ptr: *mut u8) -> Box { - let exception = Box::from_raw(ptr as *mut Exception); - exception.cause + let exception = ptr as *mut uw::_Unwind_Exception; + if (*exception).exception_class != rust_exception_class() { + uw::_Unwind_DeleteException(exception); + super::__rust_foreign_exception(); + } else { + let exception = Box::from_raw(exception as *mut Exception); + exception.cause + } } // Rust's exception class identifier. This is used by personality routines to @@ -108,13 +114,13 @@ const UNWIND_DATA_REG: (i32, i32) = (3, 4); // R3, R4 / X3, X4 #[cfg(target_arch = "s390x")] const UNWIND_DATA_REG: (i32, i32) = (6, 7); // R6, R7 -#[cfg(target_arch = "sparc64")] +#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] const UNWIND_DATA_REG: (i32, i32) = (24, 25); // I0, I1 #[cfg(target_arch = "hexagon")] const UNWIND_DATA_REG: (i32, i32) = (0, 1); // R0, R1 -#[cfg(target_arch = "riscv64")] +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] const UNWIND_DATA_REG: (i32, i32) = (10, 11); // x10, x11 // The following code is based on GCC's C and C++ personality routines. For reference, see: @@ -164,9 +170,7 @@ cfg_if::cfg_if! { // _Unwind_Context in our libunwind bindings and fetch the required data from there // directly, bypassing DWARF compatibility functions. - let exception_class = (*exception_object).exception_class; - let foreign_exception = exception_class != rust_exception_class(); - let eh_action = match find_eh_action(context, foreign_exception) { + let eh_action = match find_eh_action(context) { Ok(action) => action, Err(_) => return uw::_URC_FAILURE, }; @@ -221,15 +225,14 @@ cfg_if::cfg_if! { // and indirectly on Windows x86_64 via SEH. unsafe extern "C" fn rust_eh_personality_impl(version: c_int, actions: uw::_Unwind_Action, - exception_class: uw::_Unwind_Exception_Class, + _exception_class: uw::_Unwind_Exception_Class, exception_object: *mut uw::_Unwind_Exception, context: *mut uw::_Unwind_Context) -> uw::_Unwind_Reason_Code { if version != 1 { return uw::_URC_FATAL_PHASE1_ERROR; } - let foreign_exception = exception_class != rust_exception_class(); - let eh_action = match find_eh_action(context, foreign_exception) { + let eh_action = match find_eh_action(context) { Ok(action) => action, Err(_) => return uw::_URC_FATAL_PHASE1_ERROR, }; @@ -293,10 +296,7 @@ cfg_if::cfg_if! { } } -unsafe fn find_eh_action( - context: *mut uw::_Unwind_Context, - foreign_exception: bool, -) -> Result { +unsafe fn find_eh_action(context: *mut uw::_Unwind_Context) -> Result { let lsda = uw::_Unwind_GetLanguageSpecificData(context) as *const u8; let mut ip_before_instr: c_int = 0; let ip = uw::_Unwind_GetIPInfo(context, &mut ip_before_instr); @@ -308,7 +308,7 @@ unsafe fn find_eh_action( get_text_start: &|| uw::_Unwind_GetTextRelBase(context), get_data_start: &|| uw::_Unwind_GetDataRelBase(context), }; - eh::find_eh_action(lsda, &eh_context, foreign_exception) + eh::find_eh_action(lsda, &eh_context) } // Frame unwind info registration diff --git a/library/panic_unwind/src/lib.rs b/library/panic_unwind/src/lib.rs index 7d14893c4c..682289384c 100644 --- a/library/panic_unwind/src/lib.rs +++ b/library/panic_unwind/src/lib.rs @@ -18,8 +18,8 @@ issue_tracker_base_url = "https://github.com/rust-lang/rust/issues/" )] #![feature(core_intrinsics)] +#![feature(int_bits_const)] #![feature(lang_items)] -#![feature(libc)] #![feature(nll)] #![feature(panic_unwind)] #![feature(staged_api)] @@ -65,7 +65,7 @@ cfg_if::cfg_if! { // - os=none ("bare metal" targets) // - os=uefi // - nvptx64-nvidia-cuda - // - avr-unknown-unknown + // - arch=avr #[path = "dummy.rs"] mod real_imp; } @@ -88,6 +88,9 @@ extern "C" { /// Handler in libstd called when a panic object is dropped outside of /// `catch_unwind`. fn __rust_drop_panic() -> !; + + /// Handler in libstd called when a foreign exception is caught. + fn __rust_foreign_exception() -> !; } mod dwarf; diff --git a/library/panic_unwind/src/seh.rs b/library/panic_unwind/src/seh.rs index 1f812f8df6..5597bbb93d 100644 --- a/library/panic_unwind/src/seh.rs +++ b/library/panic_unwind/src/seh.rs @@ -175,7 +175,7 @@ pub struct _TypeDescriptor { // to be able to catch Rust panics by simply declaring a `struct rust_panic`. // // When modifying, make sure that the type name string exactly matches -// the one used in src/librustc_codegen_llvm/intrinsic.rs. +// the one used in `compiler/rustc_codegen_llvm/src/intrinsic.rs`. const TYPE_NAME: [u8; 11] = *b"rust_panic\0"; static mut THROW_INFO: _ThrowInfo = _ThrowInfo { @@ -309,15 +309,21 @@ pub unsafe fn panic(data: Box) -> u32 { extern "system" { #[unwind(allowed)] - pub fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; + fn _CxxThrowException(pExceptionObject: *mut c_void, pThrowInfo: *mut u8) -> !; } _CxxThrowException(throw_ptr, &mut THROW_INFO as *mut _ as *mut _); } pub unsafe fn cleanup(payload: *mut u8) -> Box { - let exception = &mut *(payload as *mut Exception); - exception.data.take().unwrap() + // A NULL payload here means that we got here from the catch (...) of + // __rust_try. This happens when a non-Rust foreign exception is caught. + if payload.is_null() { + super::__rust_foreign_exception(); + } else { + let exception = &mut *(payload as *mut Exception); + exception.data.take().unwrap() + } } // This is required by the compiler to exist (e.g., it's a lang item), but diff --git a/library/proc_macro/src/bridge/client.rs b/library/proc_macro/src/bridge/client.rs index c00e07388b..ba3d4c075e 100644 --- a/library/proc_macro/src/bridge/client.rs +++ b/library/proc_macro/src/bridge/client.rs @@ -305,17 +305,18 @@ impl Bridge<'_> { } fn enter(self, f: impl FnOnce() -> R) -> R { + let force_show_panics = self.force_show_panics; // Hide the default panic output within `proc_macro` expansions. // NB. the server can't do this because it may use a different libstd. static HIDE_PANICS_DURING_EXPANSION: Once = Once::new(); HIDE_PANICS_DURING_EXPANSION.call_once(|| { let prev = panic::take_hook(); panic::set_hook(Box::new(move |info| { - let hide = BridgeState::with(|state| match state { - BridgeState::NotConnected => false, - BridgeState::Connected(_) | BridgeState::InUse => true, + let show = BridgeState::with(|state| match state { + BridgeState::NotConnected => true, + BridgeState::Connected(_) | BridgeState::InUse => force_show_panics, }); - if !hide { + if show { prev(info) } })); @@ -400,6 +401,7 @@ fn run_client DecodeMut<'a, 's, ()>, R: Encode<()>>( } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand1(f: fn(crate::TokenStream) -> crate::TokenStream) -> Self { extern "C" fn run( bridge: Bridge<'_>, @@ -412,6 +414,7 @@ impl Client crate::TokenStream> { } impl Client crate::TokenStream> { + #[allow_internal_unstable(const_fn)] pub const fn expand2( f: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, ) -> Self { @@ -456,6 +459,7 @@ impl ProcMacro { } } + #[allow_internal_unstable(const_fn)] pub const fn custom_derive( trait_name: &'static str, attributes: &'static [&'static str], @@ -464,6 +468,7 @@ impl ProcMacro { ProcMacro::CustomDerive { trait_name, attributes, client: Client::expand1(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn attr( name: &'static str, expand: fn(crate::TokenStream, crate::TokenStream) -> crate::TokenStream, @@ -471,6 +476,7 @@ impl ProcMacro { ProcMacro::Attr { name, client: Client::expand2(expand) } } + #[allow_internal_unstable(const_fn)] pub const fn bang( name: &'static str, expand: fn(crate::TokenStream) -> crate::TokenStream, diff --git a/library/proc_macro/src/bridge/mod.rs b/library/proc_macro/src/bridge/mod.rs index 324be9f470..c898d483a8 100644 --- a/library/proc_macro/src/bridge/mod.rs +++ b/library/proc_macro/src/bridge/mod.rs @@ -220,6 +220,9 @@ pub struct Bridge<'a> { /// Server-side function that the client uses to make requests. dispatch: closure::Closure<'a, Buffer, Buffer>, + + /// If 'true', always invoke the default panic hook + force_show_panics: bool, } impl<'a> !Sync for Bridge<'a> {} diff --git a/library/proc_macro/src/bridge/scoped_cell.rs b/library/proc_macro/src/bridge/scoped_cell.rs index 2cde1f65ad..daa577f74b 100644 --- a/library/proc_macro/src/bridge/scoped_cell.rs +++ b/library/proc_macro/src/bridge/scoped_cell.rs @@ -35,6 +35,7 @@ impl<'a, 'b, T: LambdaL> DerefMut for RefMutL<'a, 'b, T> { pub struct ScopedCell(Cell<>::Out>); impl ScopedCell { + #[allow_internal_unstable(const_fn)] pub const fn new(value: >::Out) -> Self { ScopedCell(Cell::new(value)) } diff --git a/library/proc_macro/src/bridge/server.rs b/library/proc_macro/src/bridge/server.rs index eb39025e4c..1b3ccf4c18 100644 --- a/library/proc_macro/src/bridge/server.rs +++ b/library/proc_macro/src/bridge/server.rs @@ -135,6 +135,7 @@ pub trait ExecutionStrategy { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer; } @@ -147,10 +148,14 @@ impl ExecutionStrategy for SameThread { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { let mut dispatch = |b| dispatcher.dispatch(b); - run_client(Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, client_data) + run_client( + Bridge { cached_buffer: input, dispatch: (&mut dispatch).into(), force_show_panics }, + client_data, + ) } } @@ -166,6 +171,7 @@ impl ExecutionStrategy for CrossThread1 { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { use std::sync::mpsc::channel; @@ -179,7 +185,11 @@ impl ExecutionStrategy for CrossThread1 { }; run_client( - Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, + Bridge { + cached_buffer: input, + dispatch: (&mut dispatch).into(), + force_show_panics, + }, client_data, ) }); @@ -201,6 +211,7 @@ impl ExecutionStrategy for CrossThread2 { input: Buffer, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Buffer { use std::sync::{Arc, Mutex}; @@ -226,7 +237,11 @@ impl ExecutionStrategy for CrossThread2 { }; let r = run_client( - Bridge { cached_buffer: input, dispatch: (&mut dispatch).into() }, + Bridge { + cached_buffer: input, + dispatch: (&mut dispatch).into(), + force_show_panics, + }, client_data, ); @@ -265,6 +280,7 @@ fn run_server< input: I, run_client: extern "C" fn(Bridge<'_>, D) -> Buffer, client_data: D, + force_show_panics: bool, ) -> Result { let mut dispatcher = Dispatcher { handle_store: HandleStore::new(handle_counters), server: MarkedTypes(server) }; @@ -272,7 +288,13 @@ fn run_server< let mut b = Buffer::new(); input.encode(&mut b, &mut dispatcher.handle_store); - b = strategy.run_bridge_and_client(&mut dispatcher, b, run_client, client_data); + b = strategy.run_bridge_and_client( + &mut dispatcher, + b, + run_client, + client_data, + force_show_panics, + ); Result::decode(&mut &b[..], &mut dispatcher.handle_store) } @@ -283,6 +305,7 @@ impl client::Client crate::TokenStream> { strategy: &impl ExecutionStrategy, server: S, input: S::TokenStream, + force_show_panics: bool, ) -> Result { let client::Client { get_handle_counters, run, f } = *self; run_server( @@ -292,6 +315,7 @@ impl client::Client crate::TokenStream> { as Types>::TokenStream::mark(input), run, f, + force_show_panics, ) .map( as Types>::TokenStream::unmark) } @@ -304,6 +328,7 @@ impl client::Client crate::TokenSt server: S, input: S::TokenStream, input2: S::TokenStream, + force_show_panics: bool, ) -> Result { let client::Client { get_handle_counters, run, f } = *self; run_server( @@ -316,6 +341,7 @@ impl client::Client crate::TokenSt ), run, f, + force_show_panics, ) .map( as Types>::TokenStream::unmark) } diff --git a/library/proc_macro/src/lib.rs b/library/proc_macro/src/lib.rs index c5a871e09a..93fa1f4e58 100644 --- a/library/proc_macro/src/lib.rs +++ b/library/proc_macro/src/lib.rs @@ -20,6 +20,8 @@ )] #![feature(nll)] #![feature(staged_api)] +#![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))] #![feature(allow_internal_unstable)] #![feature(decl_macro)] #![feature(extern_types)] diff --git a/library/profiler_builtins/build.rs b/library/profiler_builtins/build.rs index b674f73ebf..7d5c601df5 100644 --- a/library/profiler_builtins/build.rs +++ b/library/profiler_builtins/build.rs @@ -20,6 +20,7 @@ fn main() { "InstrProfilingMergeFile.c", "InstrProfilingNameVar.c", "InstrProfilingPlatformDarwin.c", + "InstrProfilingPlatformFuchsia.c", "InstrProfilingPlatformLinux.c", "InstrProfilingPlatformOther.c", "InstrProfilingPlatformWindows.c", @@ -47,10 +48,10 @@ fn main() { // Turn off various features of gcc and such, mostly copying // compiler-rt's build system already cfg.flag("-fno-builtin"); - cfg.flag("-fvisibility=hidden"); cfg.flag("-fomit-frame-pointer"); cfg.define("VISIBILITY_HIDDEN", None); if !target.contains("windows") { + cfg.flag("-fvisibility=hidden"); cfg.define("COMPILER_RT_HAS_UNAME", Some("1")); } else { profile_sources.push("WindowsMMap.c"); diff --git a/library/std/Cargo.toml b/library/std/Cargo.toml index ef0ef415b4..b27b056086 100644 --- a/library/std/Cargo.toml +++ b/library/std/Cargo.toml @@ -16,11 +16,11 @@ cfg-if = { version = "0.1.8", features = ['rustc-dep-of-std'] } panic_unwind = { path = "../panic_unwind", optional = true } panic_abort = { path = "../panic_abort" } core = { path = "../core" } -libc = { version = "0.2.74", default-features = false, features = ['rustc-dep-of-std'] } -compiler_builtins = { version = "0.1.32" } +libc = { version = "0.2.77", default-features = false, features = ['rustc-dep-of-std'] } +compiler_builtins = { version = "0.1.35" } profiler_builtins = { path = "../profiler_builtins", optional = true } unwind = { path = "../unwind" } -hashbrown = { version = "0.8.1", default-features = false, features = ['rustc-dep-of-std'] } +hashbrown = { version = "0.9.0", default-features = false, features = ['rustc-dep-of-std'] } # Dependencies of the `backtrace` crate addr2line = { version = "0.13.0", optional = true, default-features = false } @@ -59,6 +59,7 @@ gimli-symbolize = [] panic-unwind = ["panic_unwind"] profiler = ["profiler_builtins"] compiler-builtins-c = ["alloc/compiler-builtins-c"] +compiler-builtins-mem = ["alloc/compiler-builtins-mem"] llvm-libunwind = ["unwind/llvm-libunwind"] # Make panics and failed asserts immediately abort without formatting any message diff --git a/library/std/build.rs b/library/std/build.rs index 04bfed1215..f2ed7552af 100644 --- a/library/std/build.rs +++ b/library/std/build.rs @@ -8,10 +8,6 @@ fn main() { println!("cargo:rustc-link-lib=dl"); println!("cargo:rustc-link-lib=log"); println!("cargo:rustc-link-lib=gcc"); - } else if !target.contains("musl") { - println!("cargo:rustc-link-lib=dl"); - println!("cargo:rustc-link-lib=rt"); - println!("cargo:rustc-link-lib=pthread"); } } else if target.contains("freebsd") { println!("cargo:rustc-link-lib=execinfo"); @@ -83,7 +79,7 @@ fn main() { // - os=none ("bare metal" targets) // - mipsel-sony-psp // - nvptx64-nvidia-cuda - // - avr-unknown-unknown + // - arch=avr // - tvos (aarch64-apple-tvos, x86_64-apple-tvos) // - uefi (x86_64-unknown-uefi, i686-unknown-uefi) // - JSON targets diff --git a/library/std/src/alloc.rs b/library/std/src/alloc.rs index b4009c8641..dd76006238 100644 --- a/library/std/src/alloc.rs +++ b/library/std/src/alloc.rs @@ -133,7 +133,7 @@ pub struct System; impl System { #[inline] - fn alloc_impl(&mut self, layout: Layout, zeroed: bool) -> Result, AllocErr> { + fn alloc_impl(&self, layout: Layout, zeroed: bool) -> Result, AllocError> { match layout.size() { 0 => Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)), // SAFETY: `layout` is non-zero in size, @@ -143,47 +143,56 @@ impl System { } else { GlobalAlloc::alloc(self, layout) }; - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, size)) }, } } - // Safety: Same as `AllocRef::grow` + // SAFETY: Same as `AllocRef::grow` #[inline] unsafe fn grow_impl( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, + old_layout: Layout, + new_layout: Layout, zeroed: bool, - ) -> Result, AllocErr> { + ) -> Result, AllocError> { debug_assert!( - new_size >= layout.size(), - "`new_size` must be greater than or equal to `layout.size()`" + new_layout.size() >= old_layout.size(), + "`new_layout.size()` must be greater than or equal to `old_layout.size()`" ); - match layout.size() { - // SAFETY: the caller must ensure that the `new_size` does not overflow. - // `layout.align()` comes from a `Layout` and is thus guaranteed to be valid for a Layout. - 0 => unsafe { - let new_layout = Layout::from_size_align_unchecked(new_size, layout.align()); - self.alloc_impl(new_layout, zeroed) - }, + match old_layout.size() { + 0 => self.alloc_impl(new_layout, zeroed), // SAFETY: `new_size` is non-zero as `old_size` is greater than or equal to `new_size` // as required by safety conditions. Other conditions must be upheld by the caller - old_size => unsafe { - // `realloc` probably checks for `new_size >= size` or something similar. - intrinsics::assume(new_size >= layout.size()); + old_size if old_layout.align() == new_layout.align() => unsafe { + let new_size = new_layout.size(); - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + // `realloc` probably checks for `new_size >= old_layout.size()` or something similar. + intrinsics::assume(new_size >= old_layout.size()); + + let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; if zeroed { raw_ptr.add(old_size).write_bytes(0, new_size - old_size); } Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_layout.size()` must be greater than or equal to `old_size`, + // both the old and new memory allocation are valid for reads and writes for `old_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + old_size => unsafe { + let new_ptr = self.alloc_impl(new_layout, zeroed)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), old_size); + AllocRef::dealloc(&self, ptr, old_layout); + Ok(new_ptr) + }, } } } @@ -193,17 +202,17 @@ impl System { #[unstable(feature = "allocator_api", issue = "32838")] unsafe impl AllocRef for System { #[inline] - fn alloc(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, false) } #[inline] - fn alloc_zeroed(&mut self, layout: Layout) -> Result, AllocErr> { + fn alloc_zeroed(&self, layout: Layout) -> Result, AllocError> { self.alloc_impl(layout, true) } #[inline] - unsafe fn dealloc(&mut self, ptr: NonNull, layout: Layout) { + unsafe fn dealloc(&self, ptr: NonNull, layout: Layout) { if layout.size() != 0 { // SAFETY: `layout` is non-zero in size, // other conditions must be upheld by the caller @@ -213,54 +222,66 @@ unsafe impl AllocRef for System { #[inline] unsafe fn grow( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, false) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, false) } } #[inline] unsafe fn grow_zeroed( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { // SAFETY: all conditions must be upheld by the caller - unsafe { self.grow_impl(ptr, layout, new_size, true) } + unsafe { self.grow_impl(ptr, old_layout, new_layout, true) } } #[inline] unsafe fn shrink( - &mut self, + &self, ptr: NonNull, - layout: Layout, - new_size: usize, - ) -> Result, AllocErr> { + old_layout: Layout, + new_layout: Layout, + ) -> Result, AllocError> { debug_assert!( - new_size <= layout.size(), - "`new_size` must be smaller than or equal to `layout.size()`" + new_layout.size() <= old_layout.size(), + "`new_layout.size()` must be smaller than or equal to `old_layout.size()`" ); - match new_size { + match new_layout.size() { // SAFETY: conditions must be upheld by the caller 0 => unsafe { - self.dealloc(ptr, layout); - Ok(NonNull::slice_from_raw_parts(layout.dangling(), 0)) + AllocRef::dealloc(&self, ptr, old_layout); + Ok(NonNull::slice_from_raw_parts(new_layout.dangling(), 0)) }, // SAFETY: `new_size` is non-zero. Other conditions must be upheld by the caller - new_size => unsafe { - // `realloc` probably checks for `new_size <= size` or something similar. - intrinsics::assume(new_size <= layout.size()); + new_size if old_layout.align() == new_layout.align() => unsafe { + // `realloc` probably checks for `new_size <= old_layout.size()` or something similar. + intrinsics::assume(new_size <= old_layout.size()); - let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), layout, new_size); - let ptr = NonNull::new(raw_ptr).ok_or(AllocErr)?; + let raw_ptr = GlobalAlloc::realloc(self, ptr.as_ptr(), old_layout, new_size); + let ptr = NonNull::new(raw_ptr).ok_or(AllocError)?; Ok(NonNull::slice_from_raw_parts(ptr, new_size)) }, + + // SAFETY: because `new_size` must be smaller than or equal to `old_layout.size()`, + // both the old and new memory allocation are valid for reads and writes for `new_size` + // bytes. Also, because the old allocation wasn't yet deallocated, it cannot overlap + // `new_ptr`. Thus, the call to `copy_nonoverlapping` is safe. The safety contract + // for `dealloc` must be upheld by the caller. + new_size => unsafe { + let new_ptr = AllocRef::alloc(&self, new_layout)?; + ptr::copy_nonoverlapping(ptr.as_ptr(), new_ptr.as_mut_ptr(), new_size); + AllocRef::dealloc(&self, ptr, old_layout); + Ok(new_ptr) + }, } } } diff --git a/library/std/src/ascii.rs b/library/std/src/ascii.rs index c9106136d3..035cd9f243 100644 --- a/library/std/src/ascii.rs +++ b/library/std/src/ascii.rs @@ -70,7 +70,6 @@ pub trait AsciiExt { /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`make_ascii_uppercase`]: AsciiExt::make_ascii_uppercase - /// [`str::to_uppercase`]: ../primitive.str.html#method.to_uppercase #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] fn to_ascii_uppercase(&self) -> Self::Owned; @@ -91,7 +90,6 @@ pub trait AsciiExt { /// inherent methods on `u8`, `char`, `[u8]` and `str`. /// /// [`make_ascii_lowercase`]: AsciiExt::make_ascii_lowercase - /// [`str::to_lowercase`]: ../primitive.str.html#method.to_lowercase #[stable(feature = "rust1", since = "1.0.0")] #[allow(deprecated)] fn to_ascii_lowercase(&self) -> Self::Owned; diff --git a/library/std/src/backtrace.rs b/library/std/src/backtrace.rs index 09f83ea5fc..cc29e1c0b0 100644 --- a/library/std/src/backtrace.rs +++ b/library/std/src/backtrace.rs @@ -66,6 +66,9 @@ #![unstable(feature = "backtrace", issue = "53487")] +#[cfg(test)] +mod tests; + // NB: A note on resolution of a backtrace: // // Backtraces primarily happen in two steps, one is where we actually capture @@ -438,55 +441,3 @@ impl RawFrame { } } } - -#[test] -fn test_debug() { - let backtrace = Backtrace { - inner: Inner::Captured(Mutex::new(Capture { - actual_start: 1, - resolved: true, - frames: vec![ - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![BacktraceSymbol { - name: Some(b"std::backtrace::Backtrace::create".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), - lineno: Some(100), - }], - }, - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![BacktraceSymbol { - name: Some(b"__rust_maybe_catch_panic".to_vec()), - filename: None, - lineno: None, - }], - }, - BacktraceFrame { - frame: RawFrame::Fake, - symbols: vec![ - BacktraceSymbol { - name: Some(b"std::rt::lang_start_internal".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), - lineno: Some(300), - }, - BacktraceSymbol { - name: Some(b"std::rt::lang_start".to_vec()), - filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), - lineno: Some(400), - }, - ], - }, - ], - })), - }; - - #[rustfmt::skip] - let expected = "Backtrace [\ - \n { fn: \"__rust_maybe_catch_panic\" },\ - \n { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\ - \n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\ - \n]"; - - assert_eq!(format!("{:#?}", backtrace), expected); -} diff --git a/library/std/src/backtrace/tests.rs b/library/std/src/backtrace/tests.rs new file mode 100644 index 0000000000..287359cd54 --- /dev/null +++ b/library/std/src/backtrace/tests.rs @@ -0,0 +1,53 @@ +use super::*; + +#[test] +fn test_debug() { + let backtrace = Backtrace { + inner: Inner::Captured(Mutex::new(Capture { + actual_start: 1, + resolved: true, + frames: vec![ + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"std::backtrace::Backtrace::create".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/backtrace.rs".to_vec())), + lineno: Some(100), + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![BacktraceSymbol { + name: Some(b"__rust_maybe_catch_panic".to_vec()), + filename: None, + lineno: None, + }], + }, + BacktraceFrame { + frame: RawFrame::Fake, + symbols: vec![ + BacktraceSymbol { + name: Some(b"std::rt::lang_start_internal".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(300), + }, + BacktraceSymbol { + name: Some(b"std::rt::lang_start".to_vec()), + filename: Some(BytesOrWide::Bytes(b"rust/rt.rs".to_vec())), + lineno: Some(400), + }, + ], + }, + ], + })), + }; + + #[rustfmt::skip] + let expected = "Backtrace [\ + \n { fn: \"__rust_maybe_catch_panic\" },\ + \n { fn: \"std::rt::lang_start_internal\", file: \"rust/rt.rs\", line: 300 },\ + \n { fn: \"std::rt::lang_start\", file: \"rust/rt.rs\", line: 400 },\ + \n]"; + + assert_eq!(format!("{:#?}", backtrace), expected); +} diff --git a/library/std/src/collections/hash/map.rs b/library/std/src/collections/hash/map.rs index 70f7214e2f..f12cefffbf 100644 --- a/library/std/src/collections/hash/map.rs +++ b/library/std/src/collections/hash/map.rs @@ -1,4 +1,5 @@ -// ignore-tidy-filelength +#[cfg(test)] +mod tests; use self::Entry::*; @@ -496,6 +497,50 @@ impl HashMap { Drain { base: self.base.drain() } } + /// Creates an iterator which uses a closure to determine if an element should be removed. + /// + /// If the closure returns true, the element is removed from the map and yielded. + /// If the closure returns false, or panics, the element remains in the map and will not be + /// yielded. + /// + /// Note that `drain_filter` lets you mutate every value in the filter closure, regardless of + /// whether you choose to keep or remove it. + /// + /// If the iterator is only partially consumed or not consumed at all, each of the remaining + /// elements will still be subjected to the closure and removed and dropped if it returns true. + /// + /// It is unspecified how many more elements will be subjected to the closure + /// if a panic occurs in the closure, or a panic occurs while dropping an element, + /// or if the `DrainFilter` value is leaked. + /// + /// # Examples + /// + /// Splitting a map into even and odd keys, reusing the original map: + /// + /// ``` + /// #![feature(hash_drain_filter)] + /// use std::collections::HashMap; + /// + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().copied().collect::>(); + /// let mut odds = map.keys().copied().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[unstable(feature = "hash_drain_filter", issue = "59618")] + pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, K, V, F> + where + F: FnMut(&K, &mut V) -> bool, + { + DrainFilter { base: self.base.drain_filter(pred) } + } + /// Clears the map, removing all key-value pairs. Keeps the allocated memory /// for reuse. /// @@ -1057,6 +1102,16 @@ where /// documentation for more. /// /// [`iter`]: HashMap::iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a, V: 'a> { base: base::Iter<'a, K, V>, @@ -1084,6 +1139,16 @@ impl fmt::Debug for Iter<'_, K, V> { /// documentation for more. /// /// [`iter_mut`]: HashMap::iter_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.iter_mut(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IterMut<'a, K: 'a, V: 'a> { base: base::IterMut<'a, K, V>, @@ -1103,6 +1168,16 @@ impl<'a, K, V> IterMut<'a, K, V> { /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { base: base::IntoIter, @@ -1122,6 +1197,16 @@ impl IntoIter { /// documentation for more. /// /// [`keys`]: HashMap::keys +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.keys(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Keys<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1149,6 +1234,16 @@ impl fmt::Debug for Keys<'_, K, V> { /// documentation for more. /// /// [`values`]: HashMap::values +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_values = map.values(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Values<'a, K: 'a, V: 'a> { inner: Iter<'a, K, V>, @@ -1176,6 +1271,16 @@ impl fmt::Debug for Values<'_, K, V> { /// documentation for more. /// /// [`drain`]: HashMap::drain +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.drain(); +/// ``` #[stable(feature = "drain", since = "1.6.0")] pub struct Drain<'a, K: 'a, V: 'a> { base: base::Drain<'a, K, V>, @@ -1189,12 +1294,47 @@ impl<'a, K, V> Drain<'a, K, V> { } } +/// A draining, filtering iterator over the entries of a `HashMap`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashMap`]. +/// +/// [`drain_filter`]: HashMap::drain_filter +/// +/// # Example +/// +/// ``` +/// #![feature(hash_drain_filter)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter = map.drain_filter(|_k, v| *v % 2 == 0); +/// ``` +#[unstable(feature = "hash_drain_filter", issue = "59618")] +pub struct DrainFilter<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + base: base::DrainFilter<'a, K, V, F>, +} + /// A mutable iterator over the values of a `HashMap`. /// /// This `struct` is created by the [`values_mut`] method on [`HashMap`]. See its /// documentation for more. /// /// [`values_mut`]: HashMap::values_mut +/// +/// # Example +/// +/// ``` +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_values = map.values_mut(); +/// ``` #[stable(feature = "map_values_mut", since = "1.10.0")] pub struct ValuesMut<'a, K: 'a, V: 'a> { inner: IterMut<'a, K, V>, @@ -1206,6 +1346,18 @@ pub struct ValuesMut<'a, K: 'a, V: 'a> { /// See its documentation for more. /// /// [`into_keys`]: HashMap::into_keys +/// +/// # Example +/// +/// ``` +/// #![feature(map_into_keys_values)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.into_keys(); +/// ``` #[unstable(feature = "map_into_keys_values", issue = "75294")] pub struct IntoKeys { inner: IntoIter, @@ -1217,6 +1369,18 @@ pub struct IntoKeys { /// See its documentation for more. /// /// [`into_values`]: HashMap::into_values +/// +/// # Example +/// +/// ``` +/// #![feature(map_into_keys_values)] +/// +/// use std::collections::HashMap; +/// +/// let mut map = HashMap::new(); +/// map.insert("a", 1); +/// let iter_keys = map.into_values(); +/// ``` #[unstable(feature = "map_into_keys_values", issue = "75294")] pub struct IntoValues { inner: IntoIter, @@ -1227,7 +1391,6 @@ pub struct IntoValues { /// See the [`HashMap::raw_entry_mut`] docs for usage examples. /// /// [`HashMap::raw_entry_mut`]: HashMap::raw_entry_mut - #[unstable(feature = "hash_raw_entry", issue = "56167")] pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { map: &'a mut HashMap, @@ -1240,13 +1403,11 @@ pub struct RawEntryBuilderMut<'a, K: 'a, V: 'a, S: 'a> { /// This `enum` is constructed through the [`raw_entry_mut`] method on [`HashMap`], /// then calling one of the methods of that [`RawEntryBuilderMut`]. /// -/// [`Entry`]: enum.Entry.html /// [`raw_entry_mut`]: HashMap::raw_entry_mut -/// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html #[unstable(feature = "hash_raw_entry", issue = "56167")] pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// An occupied entry. - Occupied(RawOccupiedEntryMut<'a, K, V>), + Occupied(RawOccupiedEntryMut<'a, K, V, S>), /// A vacant entry. Vacant(RawVacantEntryMut<'a, K, V, S>), } @@ -1254,8 +1415,8 @@ pub enum RawEntryMut<'a, K: 'a, V: 'a, S: 'a> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`RawEntryMut`] enum. #[unstable(feature = "hash_raw_entry", issue = "56167")] -pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a> { - base: base::RawOccupiedEntryMut<'a, K, V>, +pub struct RawOccupiedEntryMut<'a, K: 'a, V: 'a, S: 'a> { + base: base::RawOccupiedEntryMut<'a, K, V, S>, } /// A view into a vacant entry in a `HashMap`. @@ -1456,7 +1617,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { } } -impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { +impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Gets a reference to the key in the entry. #[inline] #[unstable(feature = "hash_raw_entry", issue = "56167")] @@ -1596,7 +1757,7 @@ impl Debug for RawEntryMut<'_, K, V, S> { } #[unstable(feature = "hash_raw_entry", issue = "56167")] -impl Debug for RawOccupiedEntryMut<'_, K, V> { +impl Debug for RawOccupiedEntryMut<'_, K, V, S> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") .field("key", self.key()) @@ -1647,8 +1808,6 @@ impl Debug for Entry<'_, K, V> { /// A view into an occupied entry in a `HashMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct OccupiedEntry<'a, K: 'a, V: 'a> { base: base::RustcOccupiedEntry<'a, K, V>, @@ -1663,8 +1822,6 @@ impl Debug for OccupiedEntry<'_, K, V> { /// A view into a vacant entry in a `HashMap`. /// It is part of the [`Entry`] enum. -/// -/// [`Entry`]: enum.Entry.html #[stable(feature = "rust1", since = "1.0.0")] pub struct VacantEntry<'a, K: 'a, V: 'a> { base: base::RustcVacantEntry<'a, K, V>, @@ -1885,13 +2042,9 @@ impl ExactSizeIterator for ValuesMut<'_, K, V> { impl FusedIterator for ValuesMut<'_, K, V> {} #[stable(feature = "std_debug", since = "1.16.0")] -impl fmt::Debug for ValuesMut<'_, K, V> -where - K: fmt::Debug, - V: fmt::Debug, -{ +impl fmt::Debug for ValuesMut<'_, K, V> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_list().entries(self.inner.iter()).finish() + f.debug_list().entries(self.inner.iter().map(|(_, val)| val)).finish() } } @@ -1919,7 +2072,7 @@ impl ExactSizeIterator for IntoKeys { impl FusedIterator for IntoKeys {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoKeys { +impl fmt::Debug for IntoKeys { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(k, _)| k)).finish() } @@ -1949,7 +2102,7 @@ impl ExactSizeIterator for IntoValues { impl FusedIterator for IntoValues {} #[unstable(feature = "map_into_keys_values", issue = "75294")] -impl fmt::Debug for IntoValues { +impl fmt::Debug for IntoValues { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_list().entries(self.inner.iter().map(|(_, v)| v)).finish() } @@ -1989,6 +2142,36 @@ where } } +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl Iterator for DrainFilter<'_, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + type Item = (K, V); + + #[inline] + fn next(&mut self) -> Option<(K, V)> { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl<'a, K, V, F> fmt::Debug for DrainFilter<'a, K, V, F> +where + F: FnMut(&K, &mut V) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("DrainFilter { .. }") + } +} + impl<'a, K, V> Entry<'a, K, V> { #[stable(feature = "rust1", since = "1.0.0")] /// Ensures a value is in the entry by inserting the default if empty, and returns @@ -2381,7 +2564,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// use std::rc::Rc; /// /// let mut map: HashMap, u32> = HashMap::new(); - /// let mut known_strings: Vec> = Vec::new(); + /// let known_strings: Vec> = Vec::new(); /// /// // Initialise known strings, run program, etc. /// @@ -2389,7 +2572,7 @@ impl<'a, K, V> OccupiedEntry<'a, K, V> { /// /// fn reclaim_memory(map: &mut HashMap, u32>, known_strings: &[Rc] ) { /// for s in known_strings { - /// if let Entry::Occupied(entry) = map.entry(s.clone()) { + /// if let Entry::Occupied(entry) = map.entry(Rc::clone(s)) { /// // Replaces the entry's key with our version of it in `known_strings`. /// entry.replace_key(); /// } @@ -2649,11 +2832,10 @@ impl DefaultHasher { #[stable(feature = "hashmap_default_hasher", since = "1.13.0")] impl Default for DefaultHasher { - // FIXME: here should link `new` to [DefaultHasher::new], but it occurs intra-doc link - // resolution failure when re-exporting libstd items. When #56922 fixed, - // link `new` to [DefaultHasher::new] again. - /// Creates a new `DefaultHasher` using `new`. + /// Creates a new `DefaultHasher` using [`new`]. /// See its documentation for more. + /// + /// [`new`]: DefaultHasher::new fn default() -> DefaultHasher { DefaultHasher::new() } @@ -2697,7 +2879,7 @@ fn map_entry<'a, K: 'a, V: 'a>(raw: base::RustcEntry<'a, K, V>) -> Entry<'a, K, } #[inline] -fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { +pub(super) fn map_try_reserve_error(err: hashbrown::TryReserveError) -> TryReserveError { match err { hashbrown::TryReserveError::CapacityOverflow => TryReserveError::CapacityOverflow, hashbrown::TryReserveError::AllocError { layout } => { @@ -2754,933 +2936,3 @@ fn assert_covariance() { d } } - -#[cfg(test)] -mod test_map { - use super::Entry::{Occupied, Vacant}; - use super::HashMap; - use super::RandomState; - use crate::cell::RefCell; - use rand::{thread_rng, Rng}; - use realstd::collections::TryReserveError::*; - - // https://github.com/rust-lang/rust/issues/62301 - fn _assert_hashmap_is_unwind_safe() { - fn assert_unwind_safe() {} - assert_unwind_safe::>>(); - } - - #[test] - fn test_zero_capacities() { - type HM = HashMap; - - let m = HM::new(); - assert_eq!(m.capacity(), 0); - - let m = HM::default(); - assert_eq!(m.capacity(), 0); - - let m = HM::with_hasher(RandomState::new()); - assert_eq!(m.capacity(), 0); - - let m = HM::with_capacity(0); - assert_eq!(m.capacity(), 0); - - let m = HM::with_capacity_and_hasher(0, RandomState::new()); - assert_eq!(m.capacity(), 0); - - let mut m = HM::new(); - m.insert(1, 1); - m.insert(2, 2); - m.remove(&1); - m.remove(&2); - m.shrink_to_fit(); - assert_eq!(m.capacity(), 0); - - let mut m = HM::new(); - m.reserve(0); - assert_eq!(m.capacity(), 0); - } - - #[test] - fn test_create_capacity_zero() { - let mut m = HashMap::with_capacity(0); - - assert!(m.insert(1, 1).is_none()); - - assert!(m.contains_key(&1)); - assert!(!m.contains_key(&0)); - } - - #[test] - fn test_insert() { - let mut m = HashMap::new(); - assert_eq!(m.len(), 0); - assert!(m.insert(1, 2).is_none()); - assert_eq!(m.len(), 1); - assert!(m.insert(2, 4).is_none()); - assert_eq!(m.len(), 2); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&2).unwrap(), 4); - } - - #[test] - fn test_clone() { - let mut m = HashMap::new(); - assert_eq!(m.len(), 0); - assert!(m.insert(1, 2).is_none()); - assert_eq!(m.len(), 1); - assert!(m.insert(2, 4).is_none()); - assert_eq!(m.len(), 2); - let m2 = m.clone(); - assert_eq!(*m2.get(&1).unwrap(), 2); - assert_eq!(*m2.get(&2).unwrap(), 4); - assert_eq!(m2.len(), 2); - } - - thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } - - #[derive(Hash, PartialEq, Eq)] - struct Droppable { - k: usize, - } - - impl Droppable { - fn new(k: usize) -> Droppable { - DROP_VECTOR.with(|slot| { - slot.borrow_mut()[k] += 1; - }); - - Droppable { k } - } - } - - impl Drop for Droppable { - fn drop(&mut self) { - DROP_VECTOR.with(|slot| { - slot.borrow_mut()[self.k] -= 1; - }); - } - } - - impl Clone for Droppable { - fn clone(&self) -> Droppable { - Droppable::new(self.k) - } - } - - #[test] - fn test_drops() { - DROP_VECTOR.with(|slot| { - *slot.borrow_mut() = vec![0; 200]; - }); - - { - let mut m = HashMap::new(); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - - for i in 0..100 { - let d1 = Droppable::new(i); - let d2 = Droppable::new(i + 100); - m.insert(d1, d2); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - for i in 0..50 { - let k = Droppable::new(i); - let v = m.remove(&k); - - assert!(v.is_some()); - - DROP_VECTOR.with(|v| { - assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i + 100], 1); - }); - } - - DROP_VECTOR.with(|v| { - for i in 0..50 { - assert_eq!(v.borrow()[i], 0); - assert_eq!(v.borrow()[i + 100], 0); - } - - for i in 50..100 { - assert_eq!(v.borrow()[i], 1); - assert_eq!(v.borrow()[i + 100], 1); - } - }); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - } - - #[test] - fn test_into_iter_drops() { - DROP_VECTOR.with(|v| { - *v.borrow_mut() = vec![0; 200]; - }); - - let hm = { - let mut hm = HashMap::new(); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - - for i in 0..100 { - let d1 = Droppable::new(i); - let d2 = Droppable::new(i + 100); - hm.insert(d1, d2); - } - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - hm - }; - - // By the way, ensure that cloning doesn't screw up the dropping. - drop(hm.clone()); - - { - let mut half = hm.into_iter().take(50); - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 1); - } - }); - - for _ in half.by_ref() {} - - DROP_VECTOR.with(|v| { - let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); - - let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); - - assert_eq!(nk, 50); - assert_eq!(nv, 50); - }); - }; - - DROP_VECTOR.with(|v| { - for i in 0..200 { - assert_eq!(v.borrow()[i], 0); - } - }); - } - - #[test] - fn test_empty_remove() { - let mut m: HashMap = HashMap::new(); - assert_eq!(m.remove(&0), None); - } - - #[test] - fn test_empty_entry() { - let mut m: HashMap = HashMap::new(); - match m.entry(0) { - Occupied(_) => panic!(), - Vacant(_) => {} - } - assert!(*m.entry(0).or_insert(true)); - assert_eq!(m.len(), 1); - } - - #[test] - fn test_empty_iter() { - let mut m: HashMap = HashMap::new(); - assert_eq!(m.drain().next(), None); - assert_eq!(m.keys().next(), None); - assert_eq!(m.values().next(), None); - assert_eq!(m.values_mut().next(), None); - assert_eq!(m.iter().next(), None); - assert_eq!(m.iter_mut().next(), None); - assert_eq!(m.len(), 0); - assert!(m.is_empty()); - assert_eq!(m.into_iter().next(), None); - } - - #[test] - fn test_lots_of_insertions() { - let mut m = HashMap::new(); - - // Try this a few times to make sure we never screw up the hashmap's - // internal state. - for _ in 0..10 { - assert!(m.is_empty()); - - for i in 1..1001 { - assert!(m.insert(i, i).is_none()); - - for j in 1..=i { - let r = m.get(&j); - assert_eq!(r, Some(&j)); - } - - for j in i + 1..1001 { - let r = m.get(&j); - assert_eq!(r, None); - } - } - - for i in 1001..2001 { - assert!(!m.contains_key(&i)); - } - - // remove forwards - for i in 1..1001 { - assert!(m.remove(&i).is_some()); - - for j in 1..=i { - assert!(!m.contains_key(&j)); - } - - for j in i + 1..1001 { - assert!(m.contains_key(&j)); - } - } - - for i in 1..1001 { - assert!(!m.contains_key(&i)); - } - - for i in 1..1001 { - assert!(m.insert(i, i).is_none()); - } - - // remove backwards - for i in (1..1001).rev() { - assert!(m.remove(&i).is_some()); - - for j in i..1001 { - assert!(!m.contains_key(&j)); - } - - for j in 1..i { - assert!(m.contains_key(&j)); - } - } - } - } - - #[test] - fn test_find_mut() { - let mut m = HashMap::new(); - assert!(m.insert(1, 12).is_none()); - assert!(m.insert(2, 8).is_none()); - assert!(m.insert(5, 14).is_none()); - let new = 100; - match m.get_mut(&5) { - None => panic!(), - Some(x) => *x = new, - } - assert_eq!(m.get(&5), Some(&new)); - } - - #[test] - fn test_insert_overwrite() { - let mut m = HashMap::new(); - assert!(m.insert(1, 2).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert!(!m.insert(1, 3).is_none()); - assert_eq!(*m.get(&1).unwrap(), 3); - } - - #[test] - fn test_insert_conflicts() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert!(m.insert(5, 3).is_none()); - assert!(m.insert(9, 4).is_none()); - assert_eq!(*m.get(&9).unwrap(), 4); - assert_eq!(*m.get(&5).unwrap(), 3); - assert_eq!(*m.get(&1).unwrap(), 2); - } - - #[test] - fn test_conflict_remove() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert!(m.insert(5, 3).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&5).unwrap(), 3); - assert!(m.insert(9, 4).is_none()); - assert_eq!(*m.get(&1).unwrap(), 2); - assert_eq!(*m.get(&5).unwrap(), 3); - assert_eq!(*m.get(&9).unwrap(), 4); - assert!(m.remove(&1).is_some()); - assert_eq!(*m.get(&9).unwrap(), 4); - assert_eq!(*m.get(&5).unwrap(), 3); - } - - #[test] - fn test_is_empty() { - let mut m = HashMap::with_capacity(4); - assert!(m.insert(1, 2).is_none()); - assert!(!m.is_empty()); - assert!(m.remove(&1).is_some()); - assert!(m.is_empty()); - } - - #[test] - fn test_remove() { - let mut m = HashMap::new(); - m.insert(1, 2); - assert_eq!(m.remove(&1), Some(2)); - assert_eq!(m.remove(&1), None); - } - - #[test] - fn test_remove_entry() { - let mut m = HashMap::new(); - m.insert(1, 2); - assert_eq!(m.remove_entry(&1), Some((1, 2))); - assert_eq!(m.remove(&1), None); - } - - #[test] - fn test_iterate() { - let mut m = HashMap::with_capacity(4); - for i in 0..32 { - assert!(m.insert(i, i * 2).is_none()); - } - assert_eq!(m.len(), 32); - - let mut observed: u32 = 0; - - for (k, v) in &m { - assert_eq!(*v, *k * 2); - observed |= 1 << *k; - } - assert_eq!(observed, 0xFFFF_FFFF); - } - - #[test] - fn test_keys() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let keys: Vec<_> = map.keys().cloned().collect(); - assert_eq!(keys.len(), 3); - assert!(keys.contains(&1)); - assert!(keys.contains(&2)); - assert!(keys.contains(&3)); - } - - #[test] - fn test_values() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let values: Vec<_> = map.values().cloned().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&'a')); - assert!(values.contains(&'b')); - assert!(values.contains(&'c')); - } - - #[test] - fn test_values_mut() { - let vec = vec![(1, 1), (2, 2), (3, 3)]; - let mut map: HashMap<_, _> = vec.into_iter().collect(); - for value in map.values_mut() { - *value = (*value) * 2 - } - let values: Vec<_> = map.values().cloned().collect(); - assert_eq!(values.len(), 3); - assert!(values.contains(&2)); - assert!(values.contains(&4)); - assert!(values.contains(&6)); - } - - #[test] - fn test_into_keys() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let keys: Vec<_> = map.into_keys().collect(); - - assert_eq!(keys.len(), 3); - assert!(keys.contains(&1)); - assert!(keys.contains(&2)); - assert!(keys.contains(&3)); - } - - #[test] - fn test_into_values() { - let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; - let map: HashMap<_, _> = vec.into_iter().collect(); - let values: Vec<_> = map.into_values().collect(); - - assert_eq!(values.len(), 3); - assert!(values.contains(&'a')); - assert!(values.contains(&'b')); - assert!(values.contains(&'c')); - } - - #[test] - fn test_find() { - let mut m = HashMap::new(); - assert!(m.get(&1).is_none()); - m.insert(1, 2); - match m.get(&1) { - None => panic!(), - Some(v) => assert_eq!(*v, 2), - } - } - - #[test] - fn test_eq() { - let mut m1 = HashMap::new(); - m1.insert(1, 2); - m1.insert(2, 3); - m1.insert(3, 4); - - let mut m2 = HashMap::new(); - m2.insert(1, 2); - m2.insert(2, 3); - - assert!(m1 != m2); - - m2.insert(3, 4); - - assert_eq!(m1, m2); - } - - #[test] - fn test_show() { - let mut map = HashMap::new(); - let empty: HashMap = HashMap::new(); - - map.insert(1, 2); - map.insert(3, 4); - - let map_str = format!("{:?}", map); - - assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); - assert_eq!(format!("{:?}", empty), "{}"); - } - - #[test] - fn test_reserve_shrink_to_fit() { - let mut m = HashMap::new(); - m.insert(0, 0); - m.remove(&0); - assert!(m.capacity() >= m.len()); - for i in 0..128 { - m.insert(i, i); - } - m.reserve(256); - - let usable_cap = m.capacity(); - for i in 128..(128 + 256) { - m.insert(i, i); - assert_eq!(m.capacity(), usable_cap); - } - - for i in 100..(128 + 256) { - assert_eq!(m.remove(&i), Some(i)); - } - m.shrink_to_fit(); - - assert_eq!(m.len(), 100); - assert!(!m.is_empty()); - assert!(m.capacity() >= m.len()); - - for i in 0..100 { - assert_eq!(m.remove(&i), Some(i)); - } - m.shrink_to_fit(); - m.insert(0, 0); - - assert_eq!(m.len(), 1); - assert!(m.capacity() >= m.len()); - assert_eq!(m.remove(&0), Some(0)); - } - - #[test] - fn test_from_iter() { - let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - for &(k, v) in &xs { - assert_eq!(map.get(&k), Some(&v)); - } - - assert_eq!(map.iter().len(), xs.len() - 1); - } - - #[test] - fn test_size_hint() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.size_hint(), (3, Some(3))); - } - - #[test] - fn test_iter_len() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.len(), 3); - } - - #[test] - fn test_mut_size_hint() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter_mut(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.size_hint(), (3, Some(3))); - } - - #[test] - fn test_iter_mut_len() { - let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let mut iter = map.iter_mut(); - - for _ in iter.by_ref().take(3) {} - - assert_eq!(iter.len(), 3); - } - - #[test] - fn test_index() { - let mut map = HashMap::new(); - - map.insert(1, 2); - map.insert(2, 1); - map.insert(3, 4); - - assert_eq!(map[&2], 1); - } - - #[test] - #[should_panic] - fn test_index_nonexistent() { - let mut map = HashMap::new(); - - map.insert(1, 2); - map.insert(2, 1); - map.insert(3, 4); - - map[&4]; - } - - #[test] - fn test_entry() { - let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - // Existing key (insert) - match map.entry(1) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - assert_eq!(view.get(), &10); - assert_eq!(view.insert(100), 10); - } - } - assert_eq!(map.get(&1).unwrap(), &100); - assert_eq!(map.len(), 6); - - // Existing key (update) - match map.entry(2) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - let v = view.get_mut(); - let new_v = (*v) * 10; - *v = new_v; - } - } - assert_eq!(map.get(&2).unwrap(), &200); - assert_eq!(map.len(), 6); - - // Existing key (take) - match map.entry(3) { - Vacant(_) => unreachable!(), - Occupied(view) => { - assert_eq!(view.remove(), 30); - } - } - assert_eq!(map.get(&3), None); - assert_eq!(map.len(), 5); - - // Inexistent key (insert) - match map.entry(10) { - Occupied(_) => unreachable!(), - Vacant(view) => { - assert_eq!(*view.insert(1000), 1000); - } - } - assert_eq!(map.get(&10).unwrap(), &1000); - assert_eq!(map.len(), 6); - } - - #[test] - fn test_entry_take_doesnt_corrupt() { - #![allow(deprecated)] //rand - // Test for #19292 - fn check(m: &HashMap) { - for k in m.keys() { - assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); - } - } - - let mut m = HashMap::new(); - let mut rng = thread_rng(); - - // Populate the map with some items. - for _ in 0..50 { - let x = rng.gen_range(-10, 10); - m.insert(x, ()); - } - - for _ in 0..1000 { - let x = rng.gen_range(-10, 10); - match m.entry(x) { - Vacant(_) => {} - Occupied(e) => { - e.remove(); - } - } - - check(&m); - } - } - - #[test] - fn test_extend_ref() { - let mut a = HashMap::new(); - a.insert(1, "one"); - let mut b = HashMap::new(); - b.insert(2, "two"); - b.insert(3, "three"); - - a.extend(&b); - - assert_eq!(a.len(), 3); - assert_eq!(a[&1], "one"); - assert_eq!(a[&2], "two"); - assert_eq!(a[&3], "three"); - } - - #[test] - fn test_capacity_not_less_than_len() { - let mut a = HashMap::new(); - let mut item = 0; - - for _ in 0..116 { - a.insert(item, 0); - item += 1; - } - - assert!(a.capacity() > a.len()); - - let free = a.capacity() - a.len(); - for _ in 0..free { - a.insert(item, 0); - item += 1; - } - - assert_eq!(a.len(), a.capacity()); - - // Insert at capacity should cause allocation. - a.insert(item, 0); - assert!(a.capacity() > a.len()); - } - - #[test] - fn test_occupied_entry_key() { - let mut a = HashMap::new(); - let key = "hello there"; - let value = "value goes here"; - assert!(a.is_empty()); - a.insert(key.clone(), value.clone()); - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - - match a.entry(key.clone()) { - Vacant(_) => panic!(), - Occupied(e) => assert_eq!(key, *e.key()), - } - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - } - - #[test] - fn test_vacant_entry_key() { - let mut a = HashMap::new(); - let key = "hello there"; - let value = "value goes here"; - - assert!(a.is_empty()); - match a.entry(key.clone()) { - Occupied(_) => panic!(), - Vacant(e) => { - assert_eq!(key, *e.key()); - e.insert(value.clone()); - } - } - assert_eq!(a.len(), 1); - assert_eq!(a[key], value); - } - - #[test] - fn test_retain() { - let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); - - map.retain(|&k, _| k % 2 == 0); - assert_eq!(map.len(), 50); - assert_eq!(map[&2], 20); - assert_eq!(map[&4], 40); - assert_eq!(map[&6], 60); - } - - #[test] - fn test_try_reserve() { - let mut empty_bytes: HashMap = HashMap::new(); - - const MAX_USIZE: usize = usize::MAX; - - if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { - } else { - panic!("usize::MAX should trigger an overflow!"); - } - - if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { - } else { - panic!("usize::MAX / 8 should trigger an OOM!") - } - } - - #[test] - fn test_raw_entry() { - use super::RawEntryMut::{Occupied, Vacant}; - - let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; - - let mut map: HashMap<_, _> = xs.iter().cloned().collect(); - - let compute_hash = |map: &HashMap, k: i32| -> u64 { - use core::hash::{BuildHasher, Hash, Hasher}; - - let mut hasher = map.hasher().build_hasher(); - k.hash(&mut hasher); - hasher.finish() - }; - - // Existing key (insert) - match map.raw_entry_mut().from_key(&1) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - assert_eq!(view.get(), &10); - assert_eq!(view.insert(100), 10); - } - } - let hash1 = compute_hash(&map, 1); - assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100)); - assert_eq!(map.len(), 6); - - // Existing key (update) - match map.raw_entry_mut().from_key(&2) { - Vacant(_) => unreachable!(), - Occupied(mut view) => { - let v = view.get_mut(); - let new_v = (*v) * 10; - *v = new_v; - } - } - let hash2 = compute_hash(&map, 2); - assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200)); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200)); - assert_eq!(map.len(), 6); - - // Existing key (take) - let hash3 = compute_hash(&map, 3); - match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { - Vacant(_) => unreachable!(), - Occupied(view) => { - assert_eq!(view.remove_entry(), (3, 30)); - } - } - assert_eq!(map.raw_entry().from_key(&3), None); - assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); - assert_eq!(map.len(), 5); - - // Nonexistent key (insert) - match map.raw_entry_mut().from_key(&10) { - Occupied(_) => unreachable!(), - Vacant(view) => { - assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); - } - } - assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); - assert_eq!(map.len(), 6); - - // Ensure all lookup methods produce equivalent results. - for k in 0..12 { - let hash = compute_hash(&map, k); - let v = map.get(&k).cloned(); - let kv = v.as_ref().map(|v| (&k, v)); - - assert_eq!(map.raw_entry().from_key(&k), kv); - assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); - assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); - - match map.raw_entry_mut().from_key(&k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - match map.raw_entry_mut().from_hash(hash, |q| *q == k) { - Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), - Vacant(_) => assert_eq!(v, None), - } - } - } -} diff --git a/library/std/src/collections/hash/map/tests.rs b/library/std/src/collections/hash/map/tests.rs new file mode 100644 index 0000000000..467968354e --- /dev/null +++ b/library/std/src/collections/hash/map/tests.rs @@ -0,0 +1,1087 @@ +use super::Entry::{Occupied, Vacant}; +use super::HashMap; +use super::RandomState; +use crate::cell::RefCell; +use rand::{thread_rng, Rng}; +use realstd::collections::TryReserveError::*; + +// https://github.com/rust-lang/rust/issues/62301 +fn _assert_hashmap_is_unwind_safe() { + fn assert_unwind_safe() {} + assert_unwind_safe::>>(); +} + +#[test] +fn test_zero_capacities() { + type HM = HashMap; + + let m = HM::new(); + assert_eq!(m.capacity(), 0); + + let m = HM::default(); + assert_eq!(m.capacity(), 0); + + let m = HM::with_hasher(RandomState::new()); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity(0); + assert_eq!(m.capacity(), 0); + + let m = HM::with_capacity_and_hasher(0, RandomState::new()); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.insert(1, 1); + m.insert(2, 2); + m.remove(&1); + m.remove(&2); + m.shrink_to_fit(); + assert_eq!(m.capacity(), 0); + + let mut m = HM::new(); + m.reserve(0); + assert_eq!(m.capacity(), 0); +} + +#[test] +fn test_create_capacity_zero() { + let mut m = HashMap::with_capacity(0); + + assert!(m.insert(1, 1).is_none()); + + assert!(m.contains_key(&1)); + assert!(!m.contains_key(&0)); +} + +#[test] +fn test_insert() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&2).unwrap(), 4); +} + +#[test] +fn test_clone() { + let mut m = HashMap::new(); + assert_eq!(m.len(), 0); + assert!(m.insert(1, 2).is_none()); + assert_eq!(m.len(), 1); + assert!(m.insert(2, 4).is_none()); + assert_eq!(m.len(), 2); + let m2 = m.clone(); + assert_eq!(*m2.get(&1).unwrap(), 2); + assert_eq!(*m2.get(&2).unwrap(), 4); + assert_eq!(m2.len(), 2); +} + +thread_local! { static DROP_VECTOR: RefCell> = RefCell::new(Vec::new()) } + +#[derive(Hash, PartialEq, Eq)] +struct Droppable { + k: usize, +} + +impl Droppable { + fn new(k: usize) -> Droppable { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[k] += 1; + }); + + Droppable { k } + } +} + +impl Drop for Droppable { + fn drop(&mut self) { + DROP_VECTOR.with(|slot| { + slot.borrow_mut()[self.k] -= 1; + }); + } +} + +impl Clone for Droppable { + fn clone(&self) -> Droppable { + Droppable::new(self.k) + } +} + +#[test] +fn test_drops() { + DROP_VECTOR.with(|slot| { + *slot.borrow_mut() = vec![0; 200]; + }); + + { + let mut m = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + m.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for i in 0..50 { + let k = Droppable::new(i); + let v = m.remove(&k); + + assert!(v.is_some()); + + DROP_VECTOR.with(|v| { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..50 { + assert_eq!(v.borrow()[i], 0); + assert_eq!(v.borrow()[i + 100], 0); + } + + for i in 50..100 { + assert_eq!(v.borrow()[i], 1); + assert_eq!(v.borrow()[i + 100], 1); + } + }); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); +} + +#[test] +fn test_into_iter_drops() { + DROP_VECTOR.with(|v| { + *v.borrow_mut() = vec![0; 200]; + }); + + let hm = { + let mut hm = HashMap::new(); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); + + for i in 0..100 { + let d1 = Droppable::new(i); + let d2 = Droppable::new(i + 100); + hm.insert(d1, d2); + } + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + hm + }; + + // By the way, ensure that cloning doesn't screw up the dropping. + drop(hm.clone()); + + { + let mut half = hm.into_iter().take(50); + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 1); + } + }); + + for _ in half.by_ref() {} + + DROP_VECTOR.with(|v| { + let nk = (0..100).filter(|&i| v.borrow()[i] == 1).count(); + + let nv = (0..100).filter(|&i| v.borrow()[i + 100] == 1).count(); + + assert_eq!(nk, 50); + assert_eq!(nv, 50); + }); + }; + + DROP_VECTOR.with(|v| { + for i in 0..200 { + assert_eq!(v.borrow()[i], 0); + } + }); +} + +#[test] +fn test_empty_remove() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.remove(&0), None); +} + +#[test] +fn test_empty_entry() { + let mut m: HashMap = HashMap::new(); + match m.entry(0) { + Occupied(_) => panic!(), + Vacant(_) => {} + } + assert!(*m.entry(0).or_insert(true)); + assert_eq!(m.len(), 1); +} + +#[test] +fn test_empty_iter() { + let mut m: HashMap = HashMap::new(); + assert_eq!(m.drain().next(), None); + assert_eq!(m.keys().next(), None); + assert_eq!(m.values().next(), None); + assert_eq!(m.values_mut().next(), None); + assert_eq!(m.iter().next(), None); + assert_eq!(m.iter_mut().next(), None); + assert_eq!(m.len(), 0); + assert!(m.is_empty()); + assert_eq!(m.into_iter().next(), None); +} + +#[test] +fn test_lots_of_insertions() { + let mut m = HashMap::new(); + + // Try this a few times to make sure we never screw up the hashmap's + // internal state. + for _ in 0..10 { + assert!(m.is_empty()); + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + + for j in 1..=i { + let r = m.get(&j); + assert_eq!(r, Some(&j)); + } + + for j in i + 1..1001 { + let r = m.get(&j); + assert_eq!(r, None); + } + } + + for i in 1001..2001 { + assert!(!m.contains_key(&i)); + } + + // remove forwards + for i in 1..1001 { + assert!(m.remove(&i).is_some()); + + for j in 1..=i { + assert!(!m.contains_key(&j)); + } + + for j in i + 1..1001 { + assert!(m.contains_key(&j)); + } + } + + for i in 1..1001 { + assert!(!m.contains_key(&i)); + } + + for i in 1..1001 { + assert!(m.insert(i, i).is_none()); + } + + // remove backwards + for i in (1..1001).rev() { + assert!(m.remove(&i).is_some()); + + for j in i..1001 { + assert!(!m.contains_key(&j)); + } + + for j in 1..i { + assert!(m.contains_key(&j)); + } + } + } +} + +#[test] +fn test_find_mut() { + let mut m = HashMap::new(); + assert!(m.insert(1, 12).is_none()); + assert!(m.insert(2, 8).is_none()); + assert!(m.insert(5, 14).is_none()); + let new = 100; + match m.get_mut(&5) { + None => panic!(), + Some(x) => *x = new, + } + assert_eq!(m.get(&5), Some(&new)); +} + +#[test] +fn test_insert_overwrite() { + let mut m = HashMap::new(); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(!m.insert(1, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 3); +} + +#[test] +fn test_insert_conflicts() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(m.insert(5, 3).is_none()); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&1).unwrap(), 2); +} + +#[test] +fn test_conflict_remove() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert!(m.insert(5, 3).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert!(m.insert(9, 4).is_none()); + assert_eq!(*m.get(&1).unwrap(), 2); + assert_eq!(*m.get(&5).unwrap(), 3); + assert_eq!(*m.get(&9).unwrap(), 4); + assert!(m.remove(&1).is_some()); + assert_eq!(*m.get(&9).unwrap(), 4); + assert_eq!(*m.get(&5).unwrap(), 3); +} + +#[test] +fn test_is_empty() { + let mut m = HashMap::with_capacity(4); + assert!(m.insert(1, 2).is_none()); + assert!(!m.is_empty()); + assert!(m.remove(&1).is_some()); + assert!(m.is_empty()); +} + +#[test] +fn test_remove() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove(&1), Some(2)); + assert_eq!(m.remove(&1), None); +} + +#[test] +fn test_remove_entry() { + let mut m = HashMap::new(); + m.insert(1, 2); + assert_eq!(m.remove_entry(&1), Some((1, 2))); + assert_eq!(m.remove(&1), None); +} + +#[test] +fn test_iterate() { + let mut m = HashMap::with_capacity(4); + for i in 0..32 { + assert!(m.insert(i, i * 2).is_none()); + } + assert_eq!(m.len(), 32); + + let mut observed: u32 = 0; + + for (k, v) in &m { + assert_eq!(*v, *k * 2); + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); +} + +#[test] +fn test_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.keys().cloned().collect(); + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn test_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +fn test_values_mut() { + let vec = vec![(1, 1), (2, 2), (3, 3)]; + let mut map: HashMap<_, _> = vec.into_iter().collect(); + for value in map.values_mut() { + *value = (*value) * 2 + } + let values: Vec<_> = map.values().cloned().collect(); + assert_eq!(values.len(), 3); + assert!(values.contains(&2)); + assert!(values.contains(&4)); + assert!(values.contains(&6)); +} + +#[test] +fn test_into_keys() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let keys: Vec<_> = map.into_keys().collect(); + + assert_eq!(keys.len(), 3); + assert!(keys.contains(&1)); + assert!(keys.contains(&2)); + assert!(keys.contains(&3)); +} + +#[test] +fn test_into_values() { + let vec = vec![(1, 'a'), (2, 'b'), (3, 'c')]; + let map: HashMap<_, _> = vec.into_iter().collect(); + let values: Vec<_> = map.into_values().collect(); + + assert_eq!(values.len(), 3); + assert!(values.contains(&'a')); + assert!(values.contains(&'b')); + assert!(values.contains(&'c')); +} + +#[test] +fn test_find() { + let mut m = HashMap::new(); + assert!(m.get(&1).is_none()); + m.insert(1, 2); + match m.get(&1) { + None => panic!(), + Some(v) => assert_eq!(*v, 2), + } +} + +#[test] +fn test_eq() { + let mut m1 = HashMap::new(); + m1.insert(1, 2); + m1.insert(2, 3); + m1.insert(3, 4); + + let mut m2 = HashMap::new(); + m2.insert(1, 2); + m2.insert(2, 3); + + assert!(m1 != m2); + + m2.insert(3, 4); + + assert_eq!(m1, m2); +} + +#[test] +fn test_show() { + let mut map = HashMap::new(); + let empty: HashMap = HashMap::new(); + + map.insert(1, 2); + map.insert(3, 4); + + let map_str = format!("{:?}", map); + + assert!(map_str == "{1: 2, 3: 4}" || map_str == "{3: 4, 1: 2}"); + assert_eq!(format!("{:?}", empty), "{}"); +} + +#[test] +fn test_reserve_shrink_to_fit() { + let mut m = HashMap::new(); + m.insert(0, 0); + m.remove(&0); + assert!(m.capacity() >= m.len()); + for i in 0..128 { + m.insert(i, i); + } + m.reserve(256); + + let usable_cap = m.capacity(); + for i in 128..(128 + 256) { + m.insert(i, i); + assert_eq!(m.capacity(), usable_cap); + } + + for i in 100..(128 + 256) { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + + assert_eq!(m.len(), 100); + assert!(!m.is_empty()); + assert!(m.capacity() >= m.len()); + + for i in 0..100 { + assert_eq!(m.remove(&i), Some(i)); + } + m.shrink_to_fit(); + m.insert(0, 0); + + assert_eq!(m.len(), 1); + assert!(m.capacity() >= m.len()); + assert_eq!(m.remove(&0), Some(0)); +} + +#[test] +fn test_from_iter() { + let xs = [(1, 1), (2, 2), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + for &(k, v) in &xs { + assert_eq!(map.get(&k), Some(&v)); + } + + assert_eq!(map.iter().len(), xs.len() - 1); +} + +#[test] +fn test_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); +} + +#[test] +fn test_iter_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); +} + +#[test] +fn test_mut_size_hint() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.size_hint(), (3, Some(3))); +} + +#[test] +fn test_iter_mut_len() { + let xs = [(1, 1), (2, 2), (3, 3), (4, 4), (5, 5), (6, 6)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let mut iter = map.iter_mut(); + + for _ in iter.by_ref().take(3) {} + + assert_eq!(iter.len(), 3); +} + +#[test] +fn test_index() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + assert_eq!(map[&2], 1); +} + +#[test] +#[should_panic] +fn test_index_nonexistent() { + let mut map = HashMap::new(); + + map.insert(1, 2); + map.insert(2, 1); + map.insert(3, 4); + + map[&4]; +} + +#[test] +fn test_entry() { + let xs = [(1, 10), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + // Existing key (insert) + match map.entry(1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + assert_eq!(map.get(&1).unwrap(), &100); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.entry(2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + assert_eq!(map.get(&2).unwrap(), &200); + assert_eq!(map.len(), 6); + + // Existing key (take) + match map.entry(3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove(), 30); + } + } + assert_eq!(map.get(&3), None); + assert_eq!(map.len(), 5); + + // Inexistent key (insert) + match map.entry(10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(*view.insert(1000), 1000); + } + } + assert_eq!(map.get(&10).unwrap(), &1000); + assert_eq!(map.len(), 6); +} + +#[test] +fn test_entry_take_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + } + } + + let mut m = HashMap::new(); + let mut rng = thread_rng(); + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10, 10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10, 10); + match m.entry(x) { + Vacant(_) => {} + Occupied(e) => { + e.remove(); + } + } + + check(&m); + } +} + +#[test] +fn test_extend_ref() { + let mut a = HashMap::new(); + a.insert(1, "one"); + let mut b = HashMap::new(); + b.insert(2, "two"); + b.insert(3, "three"); + + a.extend(&b); + + assert_eq!(a.len(), 3); + assert_eq!(a[&1], "one"); + assert_eq!(a[&2], "two"); + assert_eq!(a[&3], "three"); +} + +#[test] +fn test_capacity_not_less_than_len() { + let mut a = HashMap::new(); + let mut item = 0; + + for _ in 0..116 { + a.insert(item, 0); + item += 1; + } + + assert!(a.capacity() > a.len()); + + let free = a.capacity() - a.len(); + for _ in 0..free { + a.insert(item, 0); + item += 1; + } + + assert_eq!(a.len(), a.capacity()); + + // Insert at capacity should cause allocation. + a.insert(item, 0); + assert!(a.capacity() > a.len()); +} + +#[test] +fn test_occupied_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + assert!(a.is_empty()); + a.insert(key.clone(), value.clone()); + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); + + match a.entry(key.clone()) { + Vacant(_) => panic!(), + Occupied(e) => assert_eq!(key, *e.key()), + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); +} + +#[test] +fn test_vacant_entry_key() { + let mut a = HashMap::new(); + let key = "hello there"; + let value = "value goes here"; + + assert!(a.is_empty()); + match a.entry(key.clone()) { + Occupied(_) => panic!(), + Vacant(e) => { + assert_eq!(key, *e.key()); + e.insert(value.clone()); + } + } + assert_eq!(a.len(), 1); + assert_eq!(a[key], value); +} + +#[test] +fn test_retain() { + let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); + + map.retain(|&k, _| k % 2 == 0); + assert_eq!(map.len(), 50); + assert_eq!(map[&2], 20); + assert_eq!(map[&4], 40); + assert_eq!(map[&6], 60); +} + +#[test] +fn test_try_reserve() { + let mut empty_bytes: HashMap = HashMap::new(); + + const MAX_USIZE: usize = usize::MAX; + + if let Err(CapacityOverflow) = empty_bytes.try_reserve(MAX_USIZE) { + } else { + panic!("usize::MAX should trigger an overflow!"); + } + + if let Err(AllocError { .. }) = empty_bytes.try_reserve(MAX_USIZE / 8) { + } else { + panic!("usize::MAX / 8 should trigger an OOM!") + } +} + +#[test] +fn test_raw_entry() { + use super::RawEntryMut::{Occupied, Vacant}; + + let xs = [(1i32, 10i32), (2, 20), (3, 30), (4, 40), (5, 50), (6, 60)]; + + let mut map: HashMap<_, _> = xs.iter().cloned().collect(); + + let compute_hash = |map: &HashMap, k: i32| -> u64 { + use core::hash::{BuildHasher, Hash, Hasher}; + + let mut hasher = map.hasher().build_hasher(); + k.hash(&mut hasher); + hasher.finish() + }; + + // Existing key (insert) + match map.raw_entry_mut().from_key(&1) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + assert_eq!(view.get(), &10); + assert_eq!(view.insert(100), 10); + } + } + let hash1 = compute_hash(&map, 1); + assert_eq!(map.raw_entry().from_key(&1).unwrap(), (&1, &100)); + assert_eq!(map.raw_entry().from_hash(hash1, |k| *k == 1).unwrap(), (&1, &100)); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash1, &1).unwrap(), (&1, &100)); + assert_eq!(map.len(), 6); + + // Existing key (update) + match map.raw_entry_mut().from_key(&2) { + Vacant(_) => unreachable!(), + Occupied(mut view) => { + let v = view.get_mut(); + let new_v = (*v) * 10; + *v = new_v; + } + } + let hash2 = compute_hash(&map, 2); + assert_eq!(map.raw_entry().from_key(&2).unwrap(), (&2, &200)); + assert_eq!(map.raw_entry().from_hash(hash2, |k| *k == 2).unwrap(), (&2, &200)); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash2, &2).unwrap(), (&2, &200)); + assert_eq!(map.len(), 6); + + // Existing key (take) + let hash3 = compute_hash(&map, 3); + match map.raw_entry_mut().from_key_hashed_nocheck(hash3, &3) { + Vacant(_) => unreachable!(), + Occupied(view) => { + assert_eq!(view.remove_entry(), (3, 30)); + } + } + assert_eq!(map.raw_entry().from_key(&3), None); + assert_eq!(map.raw_entry().from_hash(hash3, |k| *k == 3), None); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash3, &3), None); + assert_eq!(map.len(), 5); + + // Nonexistent key (insert) + match map.raw_entry_mut().from_key(&10) { + Occupied(_) => unreachable!(), + Vacant(view) => { + assert_eq!(view.insert(10, 1000), (&mut 10, &mut 1000)); + } + } + assert_eq!(map.raw_entry().from_key(&10).unwrap(), (&10, &1000)); + assert_eq!(map.len(), 6); + + // Ensure all lookup methods produce equivalent results. + for k in 0..12 { + let hash = compute_hash(&map, k); + let v = map.get(&k).cloned(); + let kv = v.as_ref().map(|v| (&k, v)); + + assert_eq!(map.raw_entry().from_key(&k), kv); + assert_eq!(map.raw_entry().from_hash(hash, |q| *q == k), kv); + assert_eq!(map.raw_entry().from_key_hashed_nocheck(hash, &k), kv); + + match map.raw_entry_mut().from_key(&k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_key_hashed_nocheck(hash, &k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + match map.raw_entry_mut().from_hash(hash, |q| *q == k) { + Occupied(mut o) => assert_eq!(Some(o.get_key_value()), kv), + Vacant(_) => assert_eq!(v, None), + } + } +} + +mod test_drain_filter { + use super::*; + + use crate::panic::{catch_unwind, AssertUnwindSafe}; + use crate::sync::atomic::{AtomicUsize, Ordering}; + + trait EqSorted: Iterator { + fn eq_sorted>(self, other: I) -> bool; + } + + impl EqSorted for T + where + T::Item: Eq + Ord, + { + fn eq_sorted>(self, other: I) -> bool { + let mut v: Vec<_> = self.collect(); + v.sort_unstable(); + v.into_iter().eq(other) + } + } + + #[test] + fn empty() { + let mut map: HashMap = HashMap::new(); + map.drain_filter(|_, _| unreachable!("there's nothing to decide on")); + assert!(map.is_empty()); + } + + #[test] + fn consuming_nothing() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!(map.drain_filter(|_, _| false).eq_sorted(crate::iter::empty())); + assert_eq!(map.len(), 3); + } + + #[test] + fn consuming_all() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.clone().collect(); + assert!(map.drain_filter(|_, _| true).eq_sorted(pairs)); + assert!(map.is_empty()); + } + + #[test] + fn mutating_and_keeping() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!( + map.drain_filter(|_, v| { + *v += 6; + false + }) + .eq_sorted(crate::iter::empty()) + ); + assert!(map.keys().copied().eq_sorted(0..3)); + assert!(map.values().copied().eq_sorted(6..9)); + } + + #[test] + fn mutating_and_removing() { + let pairs = (0..3).map(|i| (i, i)); + let mut map: HashMap<_, _> = pairs.collect(); + assert!( + map.drain_filter(|_, v| { + *v += 6; + true + }) + .eq_sorted((0..3).map(|i| (i, i + 6))) + ); + assert!(map.is_empty()); + } + + #[test] + fn drop_panic_leak() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + panic!("panic in `drop`"); + } + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + catch_unwind(move || { + drop(map.drain_filter(|_, _| { + PREDS.fetch_add(1, Ordering::SeqCst); + true + })) + }) + .unwrap_err(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); + } + + #[test] + fn pred_panic_leak() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + catch_unwind(AssertUnwindSafe(|| { + drop(map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + })) + })) + .unwrap_err(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 2); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(map.len(), 2); + } + + // Same as above, but attempt to use the iterator again after the panic in the predicate + #[test] + fn pred_panic_reuse() { + static PREDS: AtomicUsize = AtomicUsize::new(0); + static DROPS: AtomicUsize = AtomicUsize::new(0); + + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut map = (0..3).map(|i| (i, D)).collect::>(); + + { + let mut it = map.drain_filter(|_, _| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + }); + catch_unwind(AssertUnwindSafe(|| while it.next().is_some() {})).unwrap_err(); + // Iterator behaviour after a panic is explicitly unspecified, + // so this is just the current implementation: + let result = catch_unwind(AssertUnwindSafe(|| it.next())); + assert!(result.is_err()); + } + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 1); + assert_eq!(map.len(), 2); + } +} diff --git a/library/std/src/collections/hash/set.rs b/library/std/src/collections/hash/set.rs index 10bf917dae..a0c39852ad 100644 --- a/library/std/src/collections/hash/set.rs +++ b/library/std/src/collections/hash/set.rs @@ -1,3 +1,8 @@ +#[cfg(test)] +mod tests; + +use hashbrown::hash_set as base; + use crate::borrow::Borrow; use crate::collections::TryReserveError; use crate::fmt; @@ -5,7 +10,7 @@ use crate::hash::{BuildHasher, Hash}; use crate::iter::{Chain, FromIterator, FusedIterator}; use crate::ops::{BitAnd, BitOr, BitXor, Sub}; -use super::map::{self, HashMap, Keys, RandomState}; +use super::map::{map_try_reserve_error, RandomState}; // Future Optimization (FIXME!) // ============================ @@ -98,13 +103,14 @@ use super::map::{self, HashMap, Keys, RandomState}; /// // use the values stored in the set /// ``` /// +/// [`HashMap`]: crate::collections::HashMap /// [`RefCell`]: crate::cell::RefCell /// [`Cell`]: crate::cell::Cell #[derive(Clone)] #[cfg_attr(not(test), rustc_diagnostic_item = "hashset_type")] #[stable(feature = "rust1", since = "1.0.0")] pub struct HashSet { - map: HashMap, + base: base::HashSet, } impl HashSet { @@ -122,7 +128,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn new() -> HashSet { - HashSet { map: HashMap::new() } + Default::default() } /// Creates an empty `HashSet` with the specified capacity. @@ -140,7 +146,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize) -> HashSet { - HashSet { map: HashMap::with_capacity(capacity) } + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, Default::default()) } } } @@ -157,7 +163,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn capacity(&self) -> usize { - self.map.capacity() + self.base.capacity() } /// An iterator visiting all elements in arbitrary order. @@ -179,7 +185,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn iter(&self) -> Iter<'_, T> { - Iter { iter: self.map.keys() } + Iter { base: self.base.iter() } } /// Returns the number of elements in the set. @@ -197,7 +203,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn len(&self) -> usize { - self.map.len() + self.base.len() } /// Returns `true` if the set contains no elements. @@ -215,7 +221,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn is_empty(&self) -> bool { - self.map.is_empty() + self.base.is_empty() } /// Clears the set, returning all elements in an iterator. @@ -238,7 +244,48 @@ impl HashSet { #[inline] #[stable(feature = "drain", since = "1.6.0")] pub fn drain(&mut self) -> Drain<'_, T> { - Drain { iter: self.map.drain() } + Drain { base: self.base.drain() } + } + + /// Creates an iterator which uses a closure to determine if a value should be removed. + /// + /// If the closure returns true, then the value is removed and yielded. + /// If the closure returns false, the value will remain in the list and will not be yielded + /// by the iterator. + /// + /// If the iterator is only partially consumed or not consumed at all, each of the remaining + /// values will still be subjected to the closure and removed and dropped if it returns true. + /// + /// It is unspecified how many more values will be subjected to the closure + /// if a panic occurs in the closure, or if a panic occurs while dropping a value, or if the + /// `DrainFilter` itself is leaked. + /// + /// # Examples + /// + /// Splitting a set into even and odd values, reusing the original set: + /// + /// ``` + /// #![feature(hash_drain_filter)] + /// use std::collections::HashSet; + /// + /// let mut set: HashSet = (0..8).collect(); + /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); + /// ``` + #[inline] + #[unstable(feature = "hash_drain_filter", issue = "59618")] + pub fn drain_filter(&mut self, pred: F) -> DrainFilter<'_, T, F> + where + F: FnMut(&T) -> bool, + { + DrainFilter { base: self.base.drain_filter(pred) } } /// Clears the set, removing all values. @@ -256,7 +303,7 @@ impl HashSet { #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn clear(&mut self) { - self.map.clear() + self.base.clear() } /// Creates a new empty hash set which will use the given hasher to hash @@ -285,7 +332,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_hasher(hasher: S) -> HashSet { - HashSet { map: HashMap::with_hasher(hasher) } + HashSet { base: base::HashSet::with_hasher(hasher) } } /// Creates an empty `HashSet` with the specified capacity, using @@ -315,7 +362,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_build_hasher", since = "1.7.0")] pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> HashSet { - HashSet { map: HashMap::with_capacity_and_hasher(capacity, hasher) } + HashSet { base: base::HashSet::with_capacity_and_hasher(capacity, hasher) } } /// Returns a reference to the set's [`BuildHasher`]. @@ -333,7 +380,7 @@ impl HashSet { #[inline] #[stable(feature = "hashmap_public_hasher", since = "1.9.0")] pub fn hasher(&self) -> &S { - self.map.hasher() + self.base.hasher() } } @@ -361,7 +408,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn reserve(&mut self, additional: usize) { - self.map.reserve(additional) + self.base.reserve(additional) } /// Tries to reserve capacity for at least `additional` more elements to be inserted @@ -384,7 +431,7 @@ where #[inline] #[unstable(feature = "try_reserve", reason = "new API", issue = "48043")] pub fn try_reserve(&mut self, additional: usize) -> Result<(), TryReserveError> { - self.map.try_reserve(additional) + self.base.try_reserve(additional).map_err(map_try_reserve_error) } /// Shrinks the capacity of the set as much as possible. It will drop @@ -406,7 +453,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn shrink_to_fit(&mut self) { - self.map.shrink_to_fit() + self.base.shrink_to_fit() } /// Shrinks the capacity of the set with a lower limit. It will drop @@ -434,7 +481,7 @@ where #[inline] #[unstable(feature = "shrink_to", reason = "new API", issue = "56431")] pub fn shrink_to(&mut self, min_capacity: usize) { - self.map.shrink_to(min_capacity) + self.base.shrink_to(min_capacity) } /// Visits the values representing the difference, @@ -574,7 +621,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.contains_key(value) + self.base.contains(value) } /// Returns a reference to the value in the set, if any, that is equal to the given value. @@ -599,7 +646,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.get_key_value(value).map(|(k, _)| k) + self.base.get(value) } /// Inserts the given `value` into the set if it is not present, then @@ -623,7 +670,7 @@ where pub fn get_or_insert(&mut self, value: T) -> &T { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(&value).or_insert(value, ()).0 + self.base.get_or_insert(value) } /// Inserts an owned copy of the given `value` into the set if it is not @@ -655,7 +702,7 @@ where { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(value).or_insert_with(|| (value.to_owned(), ())).0 + self.base.get_or_insert_owned(value) } /// Inserts a value computed from `f` into the set if the given `value` is @@ -688,7 +735,7 @@ where { // Although the raw entry gives us `&mut T`, we only return `&T` to be consistent with // `get`. Key mutation is "raw" because you're not supposed to affect `Eq` or `Hash`. - self.map.raw_entry_mut().from_key(value).or_insert_with(|| (f(value), ())).0 + self.base.get_or_insert_with(value, f) } /// Returns `true` if `self` has no elements in common with `other`. @@ -785,7 +832,7 @@ where #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn insert(&mut self, value: T) -> bool { - self.map.insert(value, ()).is_none() + self.base.insert(value) } /// Adds a value to the set, replacing the existing value, if any, that is equal to the given @@ -806,13 +853,7 @@ where #[inline] #[stable(feature = "set_recovery", since = "1.9.0")] pub fn replace(&mut self, value: T) -> Option { - match self.map.entry(value) { - map::Entry::Occupied(occupied) => Some(occupied.replace_key()), - map::Entry::Vacant(vacant) => { - vacant.insert(()); - None - } - } + self.base.replace(value) } /// Removes a value from the set. Returns whether the value was @@ -840,7 +881,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.remove(value).is_some() + self.base.remove(value) } /// Removes and returns the value in the set, if any, that is equal to the given one. @@ -865,7 +906,7 @@ where T: Borrow, Q: Hash + Eq, { - self.map.remove_entry(value).map(|(k, _)| k) + self.base.take(value) } /// Retains only the elements specified by the predicate. @@ -883,11 +924,11 @@ where /// assert_eq!(set.len(), 3); /// ``` #[stable(feature = "retain_hash_collection", since = "1.18.0")] - pub fn retain(&mut self, mut f: F) + pub fn retain(&mut self, f: F) where F: FnMut(&T) -> bool, { - self.map.retain(|k, _| f(k)); + self.base.retain(f) } } @@ -946,17 +987,17 @@ where { #[inline] fn extend>(&mut self, iter: I) { - self.map.extend(iter.into_iter().map(|k| (k, ()))); + self.base.extend(iter); } #[inline] fn extend_one(&mut self, item: T) { - self.map.insert(item, ()); + self.base.insert(item); } #[inline] fn extend_reserve(&mut self, additional: usize) { - self.map.extend_reserve(additional); + self.base.extend_reserve(additional); } } @@ -973,7 +1014,7 @@ where #[inline] fn extend_one(&mut self, &item: &'a T) { - self.map.insert(item, ()); + self.base.insert(item); } #[inline] @@ -990,7 +1031,7 @@ where /// Creates an empty `HashSet` with the `Default` value for the hasher. #[inline] fn default() -> HashSet { - HashSet { map: HashMap::default() } + HashSet { base: Default::default() } } } @@ -1132,9 +1173,19 @@ where /// See its documentation for more. /// /// [`iter`]: HashSet::iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut iter = a.iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Iter<'a, K: 'a> { - iter: Keys<'a, K, ()>, + base: base::Iter<'a, K>, } /// An owning iterator over the items of a `HashSet`. @@ -1143,9 +1194,19 @@ pub struct Iter<'a, K: 'a> { /// (provided by the `IntoIterator` trait). See its documentation for more. /// /// [`into_iter`]: IntoIterator::into_iter +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut iter = a.into_iter(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { - iter: map::IntoIter, + base: base::IntoIter, } /// A draining iterator over the items of a `HashSet`. @@ -1154,9 +1215,44 @@ pub struct IntoIter { /// See its documentation for more. /// /// [`drain`]: HashSet::drain +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let mut a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut drain = a.drain(); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Drain<'a, K: 'a> { - iter: map::Drain<'a, K, ()>, + base: base::Drain<'a, K>, +} + +/// A draining, filtering iterator over the items of a `HashSet`. +/// +/// This `struct` is created by the [`drain_filter`] method on [`HashSet`]. +/// +/// [`drain_filter`]: HashSet::drain_filter +/// +/// # Examples +/// +/// ``` +/// #![feature(hash_drain_filter)] +/// +/// use std::collections::HashSet; +/// +/// let mut a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// +/// let mut drain_filtered = a.drain_filter(|v| v % 2 == 0); +/// ``` +#[unstable(feature = "hash_drain_filter", issue = "59618")] +pub struct DrainFilter<'a, K, F> +where + F: FnMut(&K) -> bool, +{ + base: base::DrainFilter<'a, K, F>, } /// A lazy iterator producing elements in the intersection of `HashSet`s. @@ -1165,6 +1261,17 @@ pub struct Drain<'a, K: 'a> { /// See its documentation for more. /// /// [`intersection`]: HashSet::intersection +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut intersection = a.intersection(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Intersection<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1179,6 +1286,17 @@ pub struct Intersection<'a, T: 'a, S: 'a> { /// See its documentation for more. /// /// [`difference`]: HashSet::difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut difference = a.difference(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Difference<'a, T: 'a, S: 'a> { // iterator of the first set @@ -1193,6 +1311,17 @@ pub struct Difference<'a, T: 'a, S: 'a> { /// [`HashSet`]. See its documentation for more. /// /// [`symmetric_difference`]: HashSet::symmetric_difference +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut intersection = a.symmetric_difference(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct SymmetricDifference<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, @@ -1204,6 +1333,17 @@ pub struct SymmetricDifference<'a, T: 'a, S: 'a> { /// See its documentation for more. /// /// [`union`]: HashSet::union +/// +/// # Examples +/// +/// ``` +/// use std::collections::HashSet; +/// +/// let a: HashSet = vec![1, 2, 3].into_iter().collect(); +/// let b: HashSet<_> = [4, 2, 3, 4].iter().cloned().collect(); +/// +/// let mut union_iter = a.union(&b); +/// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Union<'a, T: 'a, S: 'a> { iter: Chain, Difference<'a, T, S>>, @@ -1247,7 +1387,7 @@ impl IntoIterator for HashSet { /// ``` #[inline] fn into_iter(self) -> IntoIter { - IntoIter { iter: self.map.into_iter() } + IntoIter { base: self.base.into_iter() } } } @@ -1255,7 +1395,7 @@ impl IntoIterator for HashSet { impl Clone for Iter<'_, K> { #[inline] fn clone(&self) -> Self { - Iter { iter: self.iter.clone() } + Iter { base: self.base.clone() } } } #[stable(feature = "rust1", since = "1.0.0")] @@ -1264,18 +1404,18 @@ impl<'a, K> Iterator for Iter<'a, K> { #[inline] fn next(&mut self) -> Option<&'a K> { - self.iter.next() + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Iter<'_, K> { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1294,18 +1434,18 @@ impl Iterator for IntoIter { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for IntoIter { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1314,8 +1454,7 @@ impl FusedIterator for IntoIter {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for IntoIter { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let entries_iter = self.iter.iter().map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() + fmt::Debug::fmt(&self.base, f) } } @@ -1325,18 +1464,18 @@ impl<'a, K> Iterator for Drain<'a, K> { #[inline] fn next(&mut self) -> Option { - self.iter.next().map(|(k, _)| k) + self.base.next() } #[inline] fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() + self.base.size_hint() } } #[stable(feature = "rust1", since = "1.0.0")] impl ExactSizeIterator for Drain<'_, K> { #[inline] fn len(&self) -> usize { - self.iter.len() + self.base.len() } } #[stable(feature = "fused", since = "1.26.0")] @@ -1345,8 +1484,37 @@ impl FusedIterator for Drain<'_, K> {} #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Drain<'_, K> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let entries_iter = self.iter.iter().map(|(k, _)| k); - f.debug_list().entries(entries_iter).finish() + fmt::Debug::fmt(&self.base, f) + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl Iterator for DrainFilter<'_, K, F> +where + F: FnMut(&K) -> bool, +{ + type Item = K; + + #[inline] + fn next(&mut self) -> Option { + self.base.next() + } + #[inline] + fn size_hint(&self) -> (usize, Option) { + self.base.size_hint() + } +} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {} + +#[unstable(feature = "hash_drain_filter", issue = "59618")] +impl<'a, K, F> fmt::Debug for DrainFilter<'a, K, F> +where + F: FnMut(&K) -> bool, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.pad("DrainFilter { .. }") } } @@ -1579,422 +1747,3 @@ fn assert_covariance() { d } } - -#[cfg(test)] -mod test_set { - use super::super::map::RandomState; - use super::HashSet; - - #[test] - fn test_zero_capacities() { - type HS = HashSet; - - let s = HS::new(); - assert_eq!(s.capacity(), 0); - - let s = HS::default(); - assert_eq!(s.capacity(), 0); - - let s = HS::with_hasher(RandomState::new()); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity(0); - assert_eq!(s.capacity(), 0); - - let s = HS::with_capacity_and_hasher(0, RandomState::new()); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.insert(1); - s.insert(2); - s.remove(&1); - s.remove(&2); - s.shrink_to_fit(); - assert_eq!(s.capacity(), 0); - - let mut s = HS::new(); - s.reserve(0); - assert_eq!(s.capacity(), 0); - } - - #[test] - fn test_disjoint() { - let mut xs = HashSet::new(); - let mut ys = HashSet::new(); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(5)); - assert!(ys.insert(11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(xs.insert(7)); - assert!(xs.insert(19)); - assert!(xs.insert(4)); - assert!(ys.insert(2)); - assert!(ys.insert(-11)); - assert!(xs.is_disjoint(&ys)); - assert!(ys.is_disjoint(&xs)); - assert!(ys.insert(7)); - assert!(!xs.is_disjoint(&ys)); - assert!(!ys.is_disjoint(&xs)); - } - - #[test] - fn test_subset_and_superset() { - let mut a = HashSet::new(); - assert!(a.insert(0)); - assert!(a.insert(5)); - assert!(a.insert(11)); - assert!(a.insert(7)); - - let mut b = HashSet::new(); - assert!(b.insert(0)); - assert!(b.insert(7)); - assert!(b.insert(19)); - assert!(b.insert(250)); - assert!(b.insert(11)); - assert!(b.insert(200)); - - assert!(!a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(!b.is_superset(&a)); - - assert!(b.insert(5)); - - assert!(a.is_subset(&b)); - assert!(!a.is_superset(&b)); - assert!(!b.is_subset(&a)); - assert!(b.is_superset(&a)); - } - - #[test] - fn test_iterate() { - let mut a = HashSet::new(); - for i in 0..32 { - assert!(a.insert(i)); - } - let mut observed: u32 = 0; - for k in &a { - observed |= 1 << *k; - } - assert_eq!(observed, 0xFFFF_FFFF); - } - - #[test] - fn test_intersection() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - assert!(a.intersection(&b).next().is_none()); - - assert!(a.insert(11)); - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(77)); - assert!(a.insert(103)); - assert!(a.insert(5)); - assert!(a.insert(-5)); - - assert!(b.insert(2)); - assert!(b.insert(11)); - assert!(b.insert(77)); - assert!(b.insert(-9)); - assert!(b.insert(-42)); - assert!(b.insert(5)); - assert!(b.insert(3)); - - let mut i = 0; - let expected = [3, 5, 11, 77]; - for x in a.intersection(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - assert!(a.insert(9)); // make a bigger than b - - i = 0; - for x in a.intersection(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - i = 0; - for x in b.intersection(&a) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(3)); - assert!(b.insert(9)); - - let mut i = 0; - let expected = [1, 5, 11]; - for x in a.difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_symmetric_difference() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(5)); - assert!(a.insert(9)); - assert!(a.insert(11)); - - assert!(b.insert(-2)); - assert!(b.insert(3)); - assert!(b.insert(9)); - assert!(b.insert(14)); - assert!(b.insert(22)); - - let mut i = 0; - let expected = [-2, 1, 5, 11, 14, 22]; - for x in a.symmetric_difference(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_union() { - let mut a = HashSet::new(); - let mut b = HashSet::new(); - assert!(a.union(&b).next().is_none()); - assert!(b.union(&a).next().is_none()); - - assert!(a.insert(1)); - assert!(a.insert(3)); - assert!(a.insert(11)); - assert!(a.insert(16)); - assert!(a.insert(19)); - assert!(a.insert(24)); - - assert!(b.insert(-2)); - assert!(b.insert(1)); - assert!(b.insert(5)); - assert!(b.insert(9)); - assert!(b.insert(13)); - assert!(b.insert(19)); - - let mut i = 0; - let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; - for x in a.union(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - assert!(a.insert(9)); // make a bigger than b - assert!(a.insert(5)); - - i = 0; - for x in a.union(&b) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - - i = 0; - for x in b.union(&a) { - assert!(expected.contains(x)); - i += 1 - } - assert_eq!(i, expected.len()); - } - - #[test] - fn test_from_iter() { - let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; - - let set: HashSet<_> = xs.iter().cloned().collect(); - - for x in &xs { - assert!(set.contains(x)); - } - - assert_eq!(set.iter().len(), xs.len() - 1); - } - - #[test] - fn test_move_iter() { - let hs = { - let mut hs = HashSet::new(); - - hs.insert('a'); - hs.insert('b'); - - hs - }; - - let v = hs.into_iter().collect::>(); - assert!(v == ['a', 'b'] || v == ['b', 'a']); - } - - #[test] - fn test_eq() { - // These constants once happened to expose a bug in insert(). - // I'm keeping them around to prevent a regression. - let mut s1 = HashSet::new(); - - s1.insert(1); - s1.insert(2); - s1.insert(3); - - let mut s2 = HashSet::new(); - - s2.insert(1); - s2.insert(2); - - assert!(s1 != s2); - - s2.insert(3); - - assert_eq!(s1, s2); - } - - #[test] - fn test_show() { - let mut set = HashSet::new(); - let empty = HashSet::::new(); - - set.insert(1); - set.insert(2); - - let set_str = format!("{:?}", set); - - assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); - assert_eq!(format!("{:?}", empty), "{}"); - } - - #[test] - fn test_trivial_drain() { - let mut s = HashSet::::new(); - for _ in s.drain() {} - assert!(s.is_empty()); - drop(s); - - let mut s = HashSet::::new(); - drop(s.drain()); - assert!(s.is_empty()); - } - - #[test] - fn test_drain() { - let mut s: HashSet<_> = (1..100).collect(); - - // try this a bunch of times to make sure we don't screw up internal state. - for _ in 0..20 { - assert_eq!(s.len(), 99); - - { - let mut last_i = 0; - let mut d = s.drain(); - for (i, x) in d.by_ref().take(50).enumerate() { - last_i = i; - assert!(x != 0); - } - assert_eq!(last_i, 49); - } - - for _ in &s { - panic!("s should be empty!"); - } - - // reset to try again. - s.extend(1..100); - } - } - - #[test] - fn test_replace() { - use crate::hash; - - #[derive(Debug)] - struct Foo(&'static str, i32); - - impl PartialEq for Foo { - fn eq(&self, other: &Self) -> bool { - self.0 == other.0 - } - } - - impl Eq for Foo {} - - impl hash::Hash for Foo { - fn hash(&self, h: &mut H) { - self.0.hash(h); - } - } - - let mut s = HashSet::new(); - assert_eq!(s.replace(Foo("a", 1)), None); - assert_eq!(s.len(), 1); - assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); - assert_eq!(s.len(), 1); - - let mut it = s.iter(); - assert_eq!(it.next(), Some(&Foo("a", 2))); - assert_eq!(it.next(), None); - } - - #[test] - fn test_extend_ref() { - let mut a = HashSet::new(); - a.insert(1); - - a.extend(&[2, 3, 4]); - - assert_eq!(a.len(), 4); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - - let mut b = HashSet::new(); - b.insert(5); - b.insert(6); - - a.extend(&b); - - assert_eq!(a.len(), 6); - assert!(a.contains(&1)); - assert!(a.contains(&2)); - assert!(a.contains(&3)); - assert!(a.contains(&4)); - assert!(a.contains(&5)); - assert!(a.contains(&6)); - } - - #[test] - fn test_retain() { - let xs = [1, 2, 3, 4, 5, 6]; - let mut set: HashSet = xs.iter().cloned().collect(); - set.retain(|&k| k % 2 == 0); - assert_eq!(set.len(), 3); - assert!(set.contains(&2)); - assert!(set.contains(&4)); - assert!(set.contains(&6)); - } -} diff --git a/library/std/src/collections/hash/set/tests.rs b/library/std/src/collections/hash/set/tests.rs new file mode 100644 index 0000000000..40f8467fd9 --- /dev/null +++ b/library/std/src/collections/hash/set/tests.rs @@ -0,0 +1,486 @@ +use super::super::map::RandomState; +use super::HashSet; + +use crate::panic::{catch_unwind, AssertUnwindSafe}; +use crate::sync::atomic::{AtomicU32, Ordering}; + +#[test] +fn test_zero_capacities() { + type HS = HashSet; + + let s = HS::new(); + assert_eq!(s.capacity(), 0); + + let s = HS::default(); + assert_eq!(s.capacity(), 0); + + let s = HS::with_hasher(RandomState::new()); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity(0); + assert_eq!(s.capacity(), 0); + + let s = HS::with_capacity_and_hasher(0, RandomState::new()); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.insert(1); + s.insert(2); + s.remove(&1); + s.remove(&2); + s.shrink_to_fit(); + assert_eq!(s.capacity(), 0); + + let mut s = HS::new(); + s.reserve(0); + assert_eq!(s.capacity(), 0); +} + +#[test] +fn test_disjoint() { + let mut xs = HashSet::new(); + let mut ys = HashSet::new(); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(5)); + assert!(ys.insert(11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(xs.insert(7)); + assert!(xs.insert(19)); + assert!(xs.insert(4)); + assert!(ys.insert(2)); + assert!(ys.insert(-11)); + assert!(xs.is_disjoint(&ys)); + assert!(ys.is_disjoint(&xs)); + assert!(ys.insert(7)); + assert!(!xs.is_disjoint(&ys)); + assert!(!ys.is_disjoint(&xs)); +} + +#[test] +fn test_subset_and_superset() { + let mut a = HashSet::new(); + assert!(a.insert(0)); + assert!(a.insert(5)); + assert!(a.insert(11)); + assert!(a.insert(7)); + + let mut b = HashSet::new(); + assert!(b.insert(0)); + assert!(b.insert(7)); + assert!(b.insert(19)); + assert!(b.insert(250)); + assert!(b.insert(11)); + assert!(b.insert(200)); + + assert!(!a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(!b.is_superset(&a)); + + assert!(b.insert(5)); + + assert!(a.is_subset(&b)); + assert!(!a.is_superset(&b)); + assert!(!b.is_subset(&a)); + assert!(b.is_superset(&a)); +} + +#[test] +fn test_iterate() { + let mut a = HashSet::new(); + for i in 0..32 { + assert!(a.insert(i)); + } + let mut observed: u32 = 0; + for k in &a { + observed |= 1 << *k; + } + assert_eq!(observed, 0xFFFF_FFFF); +} + +#[test] +fn test_intersection() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + assert!(a.intersection(&b).next().is_none()); + + assert!(a.insert(11)); + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(77)); + assert!(a.insert(103)); + assert!(a.insert(5)); + assert!(a.insert(-5)); + + assert!(b.insert(2)); + assert!(b.insert(11)); + assert!(b.insert(77)); + assert!(b.insert(-9)); + assert!(b.insert(-42)); + assert!(b.insert(5)); + assert!(b.insert(3)); + + let mut i = 0; + let expected = [3, 5, 11, 77]; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + assert!(a.insert(9)); // make a bigger than b + + i = 0; + for x in a.intersection(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + i = 0; + for x in b.intersection(&a) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(3)); + assert!(b.insert(9)); + + let mut i = 0; + let expected = [1, 5, 11]; + for x in a.difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_symmetric_difference() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(5)); + assert!(a.insert(9)); + assert!(a.insert(11)); + + assert!(b.insert(-2)); + assert!(b.insert(3)); + assert!(b.insert(9)); + assert!(b.insert(14)); + assert!(b.insert(22)); + + let mut i = 0; + let expected = [-2, 1, 5, 11, 14, 22]; + for x in a.symmetric_difference(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_union() { + let mut a = HashSet::new(); + let mut b = HashSet::new(); + assert!(a.union(&b).next().is_none()); + assert!(b.union(&a).next().is_none()); + + assert!(a.insert(1)); + assert!(a.insert(3)); + assert!(a.insert(11)); + assert!(a.insert(16)); + assert!(a.insert(19)); + assert!(a.insert(24)); + + assert!(b.insert(-2)); + assert!(b.insert(1)); + assert!(b.insert(5)); + assert!(b.insert(9)); + assert!(b.insert(13)); + assert!(b.insert(19)); + + let mut i = 0; + let expected = [-2, 1, 3, 5, 9, 11, 13, 16, 19, 24]; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + assert!(a.insert(9)); // make a bigger than b + assert!(a.insert(5)); + + i = 0; + for x in a.union(&b) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); + + i = 0; + for x in b.union(&a) { + assert!(expected.contains(x)); + i += 1 + } + assert_eq!(i, expected.len()); +} + +#[test] +fn test_from_iter() { + let xs = [1, 2, 2, 3, 4, 5, 6, 7, 8, 9]; + + let set: HashSet<_> = xs.iter().cloned().collect(); + + for x in &xs { + assert!(set.contains(x)); + } + + assert_eq!(set.iter().len(), xs.len() - 1); +} + +#[test] +fn test_move_iter() { + let hs = { + let mut hs = HashSet::new(); + + hs.insert('a'); + hs.insert('b'); + + hs + }; + + let v = hs.into_iter().collect::>(); + assert!(v == ['a', 'b'] || v == ['b', 'a']); +} + +#[test] +fn test_eq() { + // These constants once happened to expose a bug in insert(). + // I'm keeping them around to prevent a regression. + let mut s1 = HashSet::new(); + + s1.insert(1); + s1.insert(2); + s1.insert(3); + + let mut s2 = HashSet::new(); + + s2.insert(1); + s2.insert(2); + + assert!(s1 != s2); + + s2.insert(3); + + assert_eq!(s1, s2); +} + +#[test] +fn test_show() { + let mut set = HashSet::new(); + let empty = HashSet::::new(); + + set.insert(1); + set.insert(2); + + let set_str = format!("{:?}", set); + + assert!(set_str == "{1, 2}" || set_str == "{2, 1}"); + assert_eq!(format!("{:?}", empty), "{}"); +} + +#[test] +fn test_trivial_drain() { + let mut s = HashSet::::new(); + for _ in s.drain() {} + assert!(s.is_empty()); + drop(s); + + let mut s = HashSet::::new(); + drop(s.drain()); + assert!(s.is_empty()); +} + +#[test] +fn test_drain() { + let mut s: HashSet<_> = (1..100).collect(); + + // try this a bunch of times to make sure we don't screw up internal state. + for _ in 0..20 { + assert_eq!(s.len(), 99); + + { + let mut last_i = 0; + let mut d = s.drain(); + for (i, x) in d.by_ref().take(50).enumerate() { + last_i = i; + assert!(x != 0); + } + assert_eq!(last_i, 49); + } + + for _ in &s { + panic!("s should be empty!"); + } + + // reset to try again. + s.extend(1..100); + } +} + +#[test] +fn test_replace() { + use crate::hash; + + #[derive(Debug)] + struct Foo(&'static str, i32); + + impl PartialEq for Foo { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + impl Eq for Foo {} + + impl hash::Hash for Foo { + fn hash(&self, h: &mut H) { + self.0.hash(h); + } + } + + let mut s = HashSet::new(); + assert_eq!(s.replace(Foo("a", 1)), None); + assert_eq!(s.len(), 1); + assert_eq!(s.replace(Foo("a", 2)), Some(Foo("a", 1))); + assert_eq!(s.len(), 1); + + let mut it = s.iter(); + assert_eq!(it.next(), Some(&Foo("a", 2))); + assert_eq!(it.next(), None); +} + +#[test] +fn test_extend_ref() { + let mut a = HashSet::new(); + a.insert(1); + + a.extend(&[2, 3, 4]); + + assert_eq!(a.len(), 4); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + + let mut b = HashSet::new(); + b.insert(5); + b.insert(6); + + a.extend(&b); + + assert_eq!(a.len(), 6); + assert!(a.contains(&1)); + assert!(a.contains(&2)); + assert!(a.contains(&3)); + assert!(a.contains(&4)); + assert!(a.contains(&5)); + assert!(a.contains(&6)); +} + +#[test] +fn test_retain() { + let xs = [1, 2, 3, 4, 5, 6]; + let mut set: HashSet = xs.iter().cloned().collect(); + set.retain(|&k| k % 2 == 0); + assert_eq!(set.len(), 3); + assert!(set.contains(&2)); + assert!(set.contains(&4)); + assert!(set.contains(&6)); +} + +#[test] +fn test_drain_filter() { + let mut x: HashSet<_> = [1].iter().copied().collect(); + let mut y: HashSet<_> = [1].iter().copied().collect(); + + x.drain_filter(|_| true); + y.drain_filter(|_| false); + assert_eq!(x.len(), 0); + assert_eq!(y.len(), 1); +} + +#[test] +fn test_drain_filter_drop_panic_leak() { + static PREDS: AtomicU32 = AtomicU32::new(0); + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(PartialEq, Eq, PartialOrd, Hash)] + struct D(i32); + impl Drop for D { + fn drop(&mut self) { + if DROPS.fetch_add(1, Ordering::SeqCst) == 1 { + panic!("panic in `drop`"); + } + } + } + + let mut set = (0..3).map(|i| D(i)).collect::>(); + + catch_unwind(move || { + drop(set.drain_filter(|_| { + PREDS.fetch_add(1, Ordering::SeqCst); + true + })) + }) + .ok(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 3); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); +} + +#[test] +fn test_drain_filter_pred_panic_leak() { + static PREDS: AtomicU32 = AtomicU32::new(0); + static DROPS: AtomicU32 = AtomicU32::new(0); + + #[derive(PartialEq, Eq, PartialOrd, Hash)] + struct D; + impl Drop for D { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut set: HashSet<_> = (0..3).map(|_| D).collect(); + + catch_unwind(AssertUnwindSafe(|| { + drop(set.drain_filter(|_| match PREDS.fetch_add(1, Ordering::SeqCst) { + 0 => true, + _ => panic!(), + })) + })) + .ok(); + + assert_eq!(PREDS.load(Ordering::SeqCst), 1); + assert_eq!(DROPS.load(Ordering::SeqCst), 3); + assert_eq!(set.len(), 0); +} diff --git a/library/std/src/env.rs b/library/std/src/env.rs index 387c588f4a..b0fceb9b2f 100644 --- a/library/std/src/env.rs +++ b/library/std/src/env.rs @@ -10,6 +10,9 @@ #![stable(feature = "env", since = "1.0.0")] +#[cfg(test)] +mod tests; + use crate::error::Error; use crate::ffi::{OsStr, OsString}; use crate::fmt; @@ -65,10 +68,9 @@ pub fn set_current_dir>(path: P) -> io::Result<()> { /// An iterator over a snapshot of the environment variables of this process. /// -/// This structure is created by the [`std::env::vars`] function. See its -/// documentation for more. +/// This structure is created by [`env::vars()`]. See its documentation for more. /// -/// [`std::env::vars`]: vars +/// [`env::vars()`]: vars #[stable(feature = "env", since = "1.0.0")] pub struct Vars { inner: VarsOs, @@ -76,10 +78,9 @@ pub struct Vars { /// An iterator over a snapshot of the environment variables of this process. /// -/// This structure is created by the [`std::env::vars_os`] function. See -/// its documentation for more. +/// This structure is created by [`env::vars_os()`]. See its documentation for more. /// -/// [`std::env::vars_os`]: vars_os +/// [`env::vars_os()`]: vars_os #[stable(feature = "env", since = "1.0.0")] pub struct VarsOs { inner: os_imp::Env, @@ -95,10 +96,8 @@ pub struct VarsOs { /// # Panics /// /// While iterating, the returned iterator will panic if any key or value in the -/// environment is not valid unicode. If this is not desired, consider using the -/// [`env::vars_os`] function. -/// -/// [`env::vars_os`]: vars_os +/// environment is not valid unicode. If this is not desired, consider using +/// [`env::vars_os()`]. /// /// # Examples /// @@ -111,6 +110,8 @@ pub struct VarsOs { /// println!("{}: {}", key, value); /// } /// ``` +/// +/// [`env::vars_os()`]: vars_os #[stable(feature = "env", since = "1.0.0")] pub fn vars() -> Vars { Vars { inner: vars_os() } @@ -242,9 +243,9 @@ fn _var_os(key: &OsStr) -> Option { } /// The error type for operations interacting with environment variables. -/// Possibly returned from the [`env::var`] function. +/// Possibly returned from [`env::var()`]. /// -/// [`env::var`]: var +/// [`env::var()`]: var #[derive(Debug, PartialEq, Eq, Clone)] #[stable(feature = "env", since = "1.0.0")] pub enum VarError { @@ -369,10 +370,10 @@ fn _remove_var(k: &OsStr) { /// /// The iterator element type is [`PathBuf`]. /// -/// This structure is created by the [`std::env::split_paths`] function. See its +/// This structure is created by [`env::split_paths()`]. See its /// documentation for more. /// -/// [`std::env::split_paths`]: split_paths +/// [`env::split_paths()`]: split_paths #[stable(feature = "env", since = "1.0.0")] pub struct SplitPaths<'a> { inner: os_imp::SplitPaths<'a>, @@ -423,9 +424,9 @@ impl fmt::Debug for SplitPaths<'_> { } /// The error type for operations on the `PATH` variable. Possibly returned from -/// the [`env::join_paths`] function. +/// [`env::join_paths()`]. /// -/// [`env::join_paths`]: join_paths +/// [`env::join_paths()`]: join_paths #[derive(Debug)] #[stable(feature = "env", since = "1.0.0")] pub struct JoinPathsError { @@ -460,7 +461,8 @@ pub struct JoinPathsError { /// } /// ``` /// -/// Joining a path containing a colon on a Unix-like platform results in an error: +/// Joining a path containing a colon on a Unix-like platform results in an +/// error: /// /// ``` /// # if cfg!(unix) { @@ -472,8 +474,8 @@ pub struct JoinPathsError { /// # } /// ``` /// -/// Using `env::join_paths` with [`env::split_paths`] to append an item to the `PATH` environment -/// variable: +/// Using `env::join_paths()` with [`env::split_paths()`] to append an item to +/// the `PATH` environment variable: /// /// ``` /// use std::env; @@ -491,7 +493,7 @@ pub struct JoinPathsError { /// } /// ``` /// -/// [`env::split_paths`]: split_paths +/// [`env::split_paths()`]: split_paths #[stable(feature = "env", since = "1.0.0")] pub fn join_paths(paths: I) -> Result where @@ -664,14 +666,14 @@ pub fn current_exe() -> io::Result { /// An iterator over the arguments of a process, yielding a [`String`] value for /// each argument. /// -/// This struct is created by the [`std::env::args`] function. See its -/// documentation for more. +/// This struct is created by [`env::args()`]. See its documentation +/// for more. /// /// The first element is traditionally the path of the executable, but it can be /// set to arbitrary text, and may not even exist. This means this property /// should not be relied upon for security purposes. /// -/// [`std::env::args`]: args +/// [`env::args()`]: args #[stable(feature = "env", since = "1.0.0")] pub struct Args { inner: ArgsOs, @@ -680,34 +682,34 @@ pub struct Args { /// An iterator over the arguments of a process, yielding an [`OsString`] value /// for each argument. /// -/// This struct is created by the [`std::env::args_os`] function. See its -/// documentation for more. +/// This struct is created by [`env::args_os()`]. See its documentation +/// for more. /// /// The first element is traditionally the path of the executable, but it can be /// set to arbitrary text, and may not even exist. This means this property /// should not be relied upon for security purposes. /// -/// [`std::env::args_os`]: args_os +/// [`env::args_os()`]: args_os #[stable(feature = "env", since = "1.0.0")] pub struct ArgsOs { inner: sys::args::Args, } -/// Returns the arguments which this program was started with (normally passed +/// Returns the arguments that this program was started with (normally passed /// via the command line). /// /// The first element is traditionally the path of the executable, but it can be /// set to arbitrary text, and may not even exist. This means this property should /// not be relied upon for security purposes. /// -/// On Unix systems shell usually expands unquoted arguments with glob patterns +/// On Unix systems the shell usually expands unquoted arguments with glob patterns /// (such as `*` and `?`). On Windows this is not done, and such arguments are /// passed as-is. /// -/// On glibc Linux systems, arguments are retrieved by placing a function in ".init_array". -/// Glibc passes argc, argv, and envp to functions in ".init_array", as a non-standard extension. -/// This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it does on macOS -/// and Windows. +/// On glibc Linux systems, arguments are retrieved by placing a function in `.init_array`. +/// Glibc passes `argc`, `argv`, and `envp` to functions in `.init_array`, as a non-standard +/// extension. This allows `std::env::args` to work even in a `cdylib` or `staticlib`, as it +/// does on macOS and Windows. /// /// # Panics /// @@ -944,112 +946,3 @@ pub mod consts { #[stable(feature = "env", since = "1.0.0")] pub const EXE_EXTENSION: &str = os::EXE_EXTENSION; } - -#[cfg(test)] -mod tests { - use super::*; - - use crate::path::Path; - - #[test] - #[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] - fn test_self_exe_path() { - let path = current_exe(); - assert!(path.is_ok()); - let path = path.unwrap(); - - // Hard to test this function - assert!(path.is_absolute()); - } - - #[test] - fn test() { - assert!((!Path::new("test-path").is_absolute())); - - #[cfg(not(target_env = "sgx"))] - current_dir().unwrap(); - } - - #[test] - #[cfg(windows)] - fn split_paths_windows() { - use crate::path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() - == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse(r#""""#, &mut [""])); - assert!(check_parse(";;", &mut ["", "", ""])); - assert!(check_parse(r"c:\", &mut [r"c:\"])); - assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); - assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"])); - assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); - assert!(check_parse( - r#"c:\;c:\"foo;bar"\;c:\baz"#, - &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"] - )); - } - - #[test] - #[cfg(unix)] - fn split_paths_unix() { - use crate::path::PathBuf; - - fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { - split_paths(unparsed).collect::>() - == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() - } - - assert!(check_parse("", &mut [""])); - assert!(check_parse("::", &mut ["", "", ""])); - assert!(check_parse("/", &mut ["/"])); - assert!(check_parse("/:", &mut ["/", ""])); - assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); - } - - #[test] - #[cfg(unix)] - fn join_paths_unix() { - use crate::ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin")); - assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:")); - assert!(join_paths(["/te:st"].iter().cloned()).is_err()); - } - - #[test] - #[cfg(windows)] - fn join_paths_windows() { - use crate::ffi::OsStr; - - fn test_eq(input: &[&str], output: &str) -> bool { - &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) - } - - assert!(test_eq(&[], "")); - assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\")); - assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;")); - assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#)); - assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); - } - - #[test] - fn args_debug() { - assert_eq!( - format!("Args {{ inner: {:?} }}", args().collect::>()), - format!("{:?}", args()) - ); - assert_eq!( - format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()), - format!("{:?}", args_os()) - ); - } -} diff --git a/library/std/src/env/tests.rs b/library/std/src/env/tests.rs new file mode 100644 index 0000000000..94cace03af --- /dev/null +++ b/library/std/src/env/tests.rs @@ -0,0 +1,102 @@ +use super::*; + +use crate::path::Path; + +#[test] +#[cfg_attr(any(target_os = "emscripten", target_env = "sgx"), ignore)] +fn test_self_exe_path() { + let path = current_exe(); + assert!(path.is_ok()); + let path = path.unwrap(); + + // Hard to test this function + assert!(path.is_absolute()); +} + +#[test] +fn test() { + assert!((!Path::new("test-path").is_absolute())); + + #[cfg(not(target_env = "sgx"))] + current_dir().unwrap(); +} + +#[test] +#[cfg(windows)] +fn split_paths_windows() { + use crate::path::PathBuf; + + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() + == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse(r#""""#, &mut [""])); + assert!(check_parse(";;", &mut ["", "", ""])); + assert!(check_parse(r"c:\", &mut [r"c:\"])); + assert!(check_parse(r"c:\;", &mut [r"c:\", ""])); + assert!(check_parse(r"c:\;c:\Program Files\", &mut [r"c:\", r"c:\Program Files\"])); + assert!(check_parse(r#"c:\;c:\"foo"\"#, &mut [r"c:\", r"c:\foo\"])); + assert!(check_parse(r#"c:\;c:\"foo;bar"\;c:\baz"#, &mut [r"c:\", r"c:\foo;bar\", r"c:\baz"])); +} + +#[test] +#[cfg(unix)] +fn split_paths_unix() { + use crate::path::PathBuf; + + fn check_parse(unparsed: &str, parsed: &[&str]) -> bool { + split_paths(unparsed).collect::>() + == parsed.iter().map(|s| PathBuf::from(*s)).collect::>() + } + + assert!(check_parse("", &mut [""])); + assert!(check_parse("::", &mut ["", "", ""])); + assert!(check_parse("/", &mut ["/"])); + assert!(check_parse("/:", &mut ["/", ""])); + assert!(check_parse("/:/usr/local", &mut ["/", "/usr/local"])); +} + +#[test] +#[cfg(unix)] +fn join_paths_unix() { + use crate::ffi::OsStr; + + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&["/bin", "/usr/bin", "/usr/local/bin"], "/bin:/usr/bin:/usr/local/bin")); + assert!(test_eq(&["", "/bin", "", "", "/usr/bin", ""], ":/bin:::/usr/bin:")); + assert!(join_paths(["/te:st"].iter().cloned()).is_err()); +} + +#[test] +#[cfg(windows)] +fn join_paths_windows() { + use crate::ffi::OsStr; + + fn test_eq(input: &[&str], output: &str) -> bool { + &*join_paths(input.iter().cloned()).unwrap() == OsStr::new(output) + } + + assert!(test_eq(&[], "")); + assert!(test_eq(&[r"c:\windows", r"c:\"], r"c:\windows;c:\")); + assert!(test_eq(&["", r"c:\windows", "", "", r"c:\", ""], r";c:\windows;;;c:\;")); + assert!(test_eq(&[r"c:\te;st", r"c:\"], r#""c:\te;st";c:\"#)); + assert!(join_paths([r#"c:\te"st"#].iter().cloned()).is_err()); +} + +#[test] +fn args_debug() { + assert_eq!( + format!("Args {{ inner: {:?} }}", args().collect::>()), + format!("{:?}", args()) + ); + assert_eq!( + format!("ArgsOs {{ inner: {:?} }}", args_os().collect::>()), + format!("{:?}", args_os()) + ); +} diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 84e686c2fe..5771ca758a 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -13,10 +13,13 @@ // coherence challenge (e.g., specialization, neg impls, etc) we can // reconsider what crate these items belong in. +#[cfg(test)] +mod tests; + use core::array; use core::convert::Infallible; -use crate::alloc::{AllocErr, LayoutErr}; +use crate::alloc::{AllocError, LayoutErr}; use crate::any::TypeId; use crate::backtrace::Backtrace; use crate::borrow::Cow; @@ -33,15 +36,14 @@ use crate::string; /// themselves through the [`Display`] and [`Debug`] traits, and may provide /// cause chain information: /// -/// The [`source`] method is generally used when errors cross "abstraction -/// boundaries". If one module must report an error that is caused by an error -/// from a lower-level module, it can allow access to that error via the -/// [`source`] method. This makes it possible for the high-level module to -/// provide its own errors while also revealing some of the implementation for -/// debugging via [`source`] chains. +/// [`Error::source()`] is generally used when errors cross +/// "abstraction boundaries". If one module must report an error that is caused +/// by an error from a lower-level module, it can allow accessing that error +/// via [`Error::source()`]. This makes it possible for the high-level +/// module to provide its own errors while also revealing some of the +/// implementation for debugging via `source` chains. /// /// [`Result`]: Result -/// [`source`]: Error::source #[stable(feature = "rust1", since = "1.0.0")] pub trait Error: Debug + Display { /// The lower-level source of this error, if any. @@ -385,13 +387,9 @@ impl Error for ! {} reason = "the precise API and guarantees it provides may be tweaked.", issue = "32838" )] -impl Error for AllocErr {} +impl Error for AllocError {} -#[unstable( - feature = "allocator_api", - reason = "the precise API and guarantees it provides may be tweaked.", - issue = "32838" -)] +#[stable(feature = "alloc_layout", since = "1.28.0")] impl Error for LayoutErr {} #[stable(feature = "rust1", since = "1.0.0")] @@ -636,7 +634,7 @@ impl dyn Error { } /// Returns an iterator starting with the current error and continuing with - /// recursively calling [`source`]. + /// recursively calling [`Error::source`]. /// /// If you want to omit the current error and only use its sources, /// use `skip(1)`. @@ -686,8 +684,6 @@ impl dyn Error { /// assert!(iter.next().is_none()); /// assert!(iter.next().is_none()); /// ``` - /// - /// [`source`]: Error::source #[unstable(feature = "error_iter", issue = "58520")] #[inline] pub fn chain(&self) -> Chain<'_> { @@ -741,44 +737,3 @@ impl dyn Error + Send + Sync { }) } } - -#[cfg(test)] -mod tests { - use super::Error; - use crate::fmt; - - #[derive(Debug, PartialEq)] - struct A; - #[derive(Debug, PartialEq)] - struct B; - - impl fmt::Display for A { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "A") - } - } - impl fmt::Display for B { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "B") - } - } - - impl Error for A {} - impl Error for B {} - - #[test] - fn downcasting() { - let mut a = A; - let a = &mut a as &mut (dyn Error + 'static); - assert_eq!(a.downcast_ref::(), Some(&A)); - assert_eq!(a.downcast_ref::(), None); - assert_eq!(a.downcast_mut::(), Some(&mut A)); - assert_eq!(a.downcast_mut::(), None); - - let a: Box = Box::new(A); - match a.downcast::() { - Ok(..) => panic!("expected error"), - Err(e) => assert_eq!(*e.downcast::().unwrap(), A), - } - } -} diff --git a/library/std/src/error/tests.rs b/library/std/src/error/tests.rs new file mode 100644 index 0000000000..66d6924f34 --- /dev/null +++ b/library/std/src/error/tests.rs @@ -0,0 +1,37 @@ +use super::Error; +use crate::fmt; + +#[derive(Debug, PartialEq)] +struct A; +#[derive(Debug, PartialEq)] +struct B; + +impl fmt::Display for A { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "A") + } +} +impl fmt::Display for B { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "B") + } +} + +impl Error for A {} +impl Error for B {} + +#[test] +fn downcasting() { + let mut a = A; + let a = &mut a as &mut (dyn Error + 'static); + assert_eq!(a.downcast_ref::(), Some(&A)); + assert_eq!(a.downcast_ref::(), None); + assert_eq!(a.downcast_mut::(), Some(&mut A)); + assert_eq!(a.downcast_mut::(), None); + + let a: Box = Box::new(A); + match a.downcast::() { + Ok(..) => panic!("expected error"), + Err(e) => assert_eq!(*e.downcast::().unwrap(), A), + } +} diff --git a/library/std/src/f32.rs b/library/std/src/f32.rs index c905bcf5e3..59c2da5273 100644 --- a/library/std/src/f32.rs +++ b/library/std/src/f32.rs @@ -11,6 +11,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#[cfg(test)] +mod tests; + #[cfg(not(test))] use crate::intrinsics; #[cfg(not(test))] @@ -909,766 +912,3 @@ impl f32 { x } } - -#[cfg(test)] -mod tests { - use crate::f32::consts; - use crate::num::FpCategory as Fp; - use crate::num::*; - - #[test] - fn test_num_f32() { - test_num(10f32, 2f32); - } - - #[test] - fn test_min_nan() { - assert_eq!(f32::NAN.min(2.0), 2.0); - assert_eq!(2.0f32.min(f32::NAN), 2.0); - } - - #[test] - fn test_max_nan() { - assert_eq!(f32::NAN.max(2.0), 2.0); - assert_eq!(2.0f32.max(f32::NAN), 2.0); - } - - #[test] - fn test_nan() { - let nan: f32 = f32::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - } - - #[test] - fn test_infinity() { - let inf: f32 = f32::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); - } - - #[test] - fn test_neg_infinity() { - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); - } - - #[test] - fn test_zero() { - let zero: f32 = 0.0f32; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); - } - - #[test] - fn test_neg_zero() { - let neg_zero: f32 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); - } - - #[test] - fn test_one() { - let one: f32 = 1.0f32; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); - } - - #[test] - fn test_is_nan() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f32.is_nan()); - assert!(!5.3f32.is_nan()); - assert!(!(-10.732f32).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); - } - - #[test] - fn test_is_infinite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f32.is_infinite()); - assert!(!42.8f32.is_infinite()); - assert!(!(-109.2f32).is_infinite()); - } - - #[test] - fn test_is_finite() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f32.is_finite()); - assert!(42.8f32.is_finite()); - assert!((-109.2f32).is_finite()); - } - - #[test] - fn test_is_normal() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f32.is_normal()); - assert!(1e-37f32.is_normal()); - assert!(!1e-38f32.is_normal()); - } - - #[test] - fn test_classify() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let zero: f32 = 0.0f32; - let neg_zero: f32 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1f32.classify(), Fp::Normal); - assert_eq!(1e-37f32.classify(), Fp::Normal); - assert_eq!(1e-38f32.classify(), Fp::Subnormal); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f32.floor(), 1.0f32); - assert_approx_eq!(1.3f32.floor(), 1.0f32); - assert_approx_eq!(1.5f32.floor(), 1.0f32); - assert_approx_eq!(1.7f32.floor(), 1.0f32); - assert_approx_eq!(0.0f32.floor(), 0.0f32); - assert_approx_eq!((-0.0f32).floor(), -0.0f32); - assert_approx_eq!((-1.0f32).floor(), -1.0f32); - assert_approx_eq!((-1.3f32).floor(), -2.0f32); - assert_approx_eq!((-1.5f32).floor(), -2.0f32); - assert_approx_eq!((-1.7f32).floor(), -2.0f32); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f32.ceil(), 1.0f32); - assert_approx_eq!(1.3f32.ceil(), 2.0f32); - assert_approx_eq!(1.5f32.ceil(), 2.0f32); - assert_approx_eq!(1.7f32.ceil(), 2.0f32); - assert_approx_eq!(0.0f32.ceil(), 0.0f32); - assert_approx_eq!((-0.0f32).ceil(), -0.0f32); - assert_approx_eq!((-1.0f32).ceil(), -1.0f32); - assert_approx_eq!((-1.3f32).ceil(), -1.0f32); - assert_approx_eq!((-1.5f32).ceil(), -1.0f32); - assert_approx_eq!((-1.7f32).ceil(), -1.0f32); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f32.round(), 1.0f32); - assert_approx_eq!(1.3f32.round(), 1.0f32); - assert_approx_eq!(1.5f32.round(), 2.0f32); - assert_approx_eq!(1.7f32.round(), 2.0f32); - assert_approx_eq!(0.0f32.round(), 0.0f32); - assert_approx_eq!((-0.0f32).round(), -0.0f32); - assert_approx_eq!((-1.0f32).round(), -1.0f32); - assert_approx_eq!((-1.3f32).round(), -1.0f32); - assert_approx_eq!((-1.5f32).round(), -2.0f32); - assert_approx_eq!((-1.7f32).round(), -2.0f32); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f32.trunc(), 1.0f32); - assert_approx_eq!(1.3f32.trunc(), 1.0f32); - assert_approx_eq!(1.5f32.trunc(), 1.0f32); - assert_approx_eq!(1.7f32.trunc(), 1.0f32); - assert_approx_eq!(0.0f32.trunc(), 0.0f32); - assert_approx_eq!((-0.0f32).trunc(), -0.0f32); - assert_approx_eq!((-1.0f32).trunc(), -1.0f32); - assert_approx_eq!((-1.3f32).trunc(), -1.0f32); - assert_approx_eq!((-1.5f32).trunc(), -1.0f32); - assert_approx_eq!((-1.7f32).trunc(), -1.0f32); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f32.fract(), 0.0f32); - assert_approx_eq!(1.3f32.fract(), 0.3f32); - assert_approx_eq!(1.5f32.fract(), 0.5f32); - assert_approx_eq!(1.7f32.fract(), 0.7f32); - assert_approx_eq!(0.0f32.fract(), 0.0f32); - assert_approx_eq!((-0.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.0f32).fract(), -0.0f32); - assert_approx_eq!((-1.3f32).fract(), -0.3f32); - assert_approx_eq!((-1.5f32).fract(), -0.5f32); - assert_approx_eq!((-1.7f32).fract(), -0.7f32); - } - - #[test] - fn test_abs() { - assert_eq!(f32::INFINITY.abs(), f32::INFINITY); - assert_eq!(1f32.abs(), 1f32); - assert_eq!(0f32.abs(), 0f32); - assert_eq!((-0f32).abs(), 0f32); - assert_eq!((-1f32).abs(), 1f32); - assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY); - assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32); - assert!(f32::NAN.abs().is_nan()); - } - - #[test] - fn test_signum() { - assert_eq!(f32::INFINITY.signum(), 1f32); - assert_eq!(1f32.signum(), 1f32); - assert_eq!(0f32.signum(), 1f32); - assert_eq!((-0f32).signum(), -1f32); - assert_eq!((-1f32).signum(), -1f32); - assert_eq!(f32::NEG_INFINITY.signum(), -1f32); - assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32); - assert!(f32::NAN.signum().is_nan()); - } - - #[test] - fn test_is_sign_positive() { - assert!(f32::INFINITY.is_sign_positive()); - assert!(1f32.is_sign_positive()); - assert!(0f32.is_sign_positive()); - assert!(!(-0f32).is_sign_positive()); - assert!(!(-1f32).is_sign_positive()); - assert!(!f32::NEG_INFINITY.is_sign_positive()); - assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive()); - assert!(f32::NAN.is_sign_positive()); - assert!(!(-f32::NAN).is_sign_positive()); - } - - #[test] - fn test_is_sign_negative() { - assert!(!f32::INFINITY.is_sign_negative()); - assert!(!1f32.is_sign_negative()); - assert!(!0f32.is_sign_negative()); - assert!((-0f32).is_sign_negative()); - assert!((-1f32).is_sign_negative()); - assert!(f32::NEG_INFINITY.is_sign_negative()); - assert!((1f32 / f32::NEG_INFINITY).is_sign_negative()); - assert!(!f32::NAN.is_sign_negative()); - assert!((-f32::NAN).is_sign_negative()); - } - - #[test] - fn test_mul_add() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f32.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); - } - - #[test] - fn test_recip() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.recip(), 1.0); - assert_eq!(2.0f32.recip(), 0.5); - assert_eq!((-0.4f32).recip(), -2.5); - assert_eq!(0.0f32.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); - } - - #[test] - fn test_powi() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powi(1), 1.0); - assert_approx_eq!((-3.1f32).powi(2), 9.61); - assert_approx_eq!(5.9f32.powi(-2), 0.028727); - assert_eq!(8.3f32.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); - } - - #[test] - fn test_powf() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.powf(1.0), 1.0); - assert_approx_eq!(3.4f32.powf(4.5), 246.408218); - assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f32).powf(2.0), 9.61); - assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); - assert_eq!(8.3f32.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); - } - - #[test] - fn test_sqrt_domain() { - assert!(f32::NAN.sqrt().is_nan()); - assert!(f32::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f32).sqrt().is_nan()); - assert_eq!((-0.0f32).sqrt(), -0.0); - assert_eq!(0.0f32.sqrt(), 0.0); - assert_eq!(1.0f32.sqrt(), 1.0); - assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); - } - - #[test] - fn test_exp() { - assert_eq!(1.0, 0.0f32.exp()); - assert_approx_eq!(2.718282, 1.0f32.exp()); - assert_approx_eq!(148.413162, 5.0f32.exp()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); - } - - #[test] - fn test_exp2() { - assert_eq!(32.0, 5.0f32.exp2()); - assert_eq!(1.0, 0.0f32.exp2()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); - } - - #[test] - fn test_ln() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(1.0f32.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f32).ln().is_nan()); - assert_eq!((-0.0f32).ln(), neg_inf); - assert_eq!(0.0f32.ln(), neg_inf); - assert_approx_eq!(4.0f32.ln(), 1.386294); - } - - #[test] - fn test_log() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log(10.0), 1.0); - assert_approx_eq!(2.3f32.log(3.5), 0.664858); - assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); - assert!(1.0f32.log(1.0).is_nan()); - assert!(1.0f32.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f32).log(0.1).is_nan()); - assert_eq!((-0.0f32).log(2.0), neg_inf); - assert_eq!(0.0f32.log(7.0), neg_inf); - } - - #[test] - fn test_log2() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_approx_eq!(10.0f32.log2(), 3.321928); - assert_approx_eq!(2.3f32.log2(), 1.201634); - assert_approx_eq!(1.0f32.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f32).log2().is_nan()); - assert_eq!((-0.0f32).log2(), neg_inf); - assert_eq!(0.0f32.log2(), neg_inf); - } - - #[test] - fn test_log10() { - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(10.0f32.log10(), 1.0); - assert_approx_eq!(2.3f32.log10(), 0.361728); - assert_approx_eq!(1.0f32.exp().log10(), 0.434294); - assert_eq!(1.0f32.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f32).log10().is_nan()); - assert_eq!((-0.0f32).log10(), neg_inf); - assert_eq!(0.0f32.log10(), neg_inf); - } - - #[test] - fn test_to_degrees() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_degrees(), 0.0); - assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); - } - - #[test] - fn test_to_radians() { - let pi: f32 = consts::PI; - let nan: f32 = f32::NAN; - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - assert_eq!(0.0f32.to_radians(), 0.0); - assert_approx_eq!(154.6f32.to_radians(), 2.698279); - assert_approx_eq!((-332.31f32).to_radians(), -5.799903); - assert_eq!(180.0f32.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f32.asinh(), 0.0f32); - assert_eq!((-0.0f32).asinh(), -0.0f32); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 - assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); - assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f32.acosh(), 0.0f32); - assert!(0.999f32.acosh().is_nan()); - - let inf: f32 = f32::INFINITY; - let neg_inf: f32 = f32::NEG_INFINITY; - let nan: f32 = f32::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); - assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f32.atanh(), 0.0f32); - assert_eq!((-0.0f32).atanh(), -0.0f32); - - let inf32: f32 = f32::INFINITY; - let neg_inf32: f32 = f32::NEG_INFINITY; - assert_eq!(1.0f32.atanh(), inf32); - assert_eq!((-1.0f32).atanh(), neg_inf32); - - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - - let inf64: f32 = f32::INFINITY; - let neg_inf64: f32 = f32::NEG_INFINITY; - let nan32: f32 = f32::NAN; - assert!(inf64.atanh().is_nan()); - assert!(neg_inf64.atanh().is_nan()); - assert!(nan32.atanh().is_nan()); - - assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); - assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); - } - - #[test] - fn test_real_consts() { - use super::consts; - - let pi: f32 = consts::PI; - let frac_pi_2: f32 = consts::FRAC_PI_2; - let frac_pi_3: f32 = consts::FRAC_PI_3; - let frac_pi_4: f32 = consts::FRAC_PI_4; - let frac_pi_6: f32 = consts::FRAC_PI_6; - let frac_pi_8: f32 = consts::FRAC_PI_8; - let frac_1_pi: f32 = consts::FRAC_1_PI; - let frac_2_pi: f32 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; - let sqrt2: f32 = consts::SQRT_2; - let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; - let e: f32 = consts::E; - let log2_e: f32 = consts::LOG2_E; - let log10_e: f32 = consts::LOG10_E; - let ln_2: f32 = consts::LN_2; - let ln_10: f32 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f32); - assert_approx_eq!(frac_pi_3, pi / 3f32); - assert_approx_eq!(frac_pi_4, pi / 4f32); - assert_approx_eq!(frac_pi_6, pi / 6f32); - assert_approx_eq!(frac_pi_8, pi / 8f32); - assert_approx_eq!(frac_1_pi, 1f32 / pi); - assert_approx_eq!(frac_2_pi, 2f32 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f32.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f32.ln()); - assert_approx_eq!(ln_10, 10f32.ln()); - } - - #[test] - fn test_float_bits_conv() { - assert_eq!((1f32).to_bits(), 0x3f800000); - assert_eq!((12.5f32).to_bits(), 0x41480000); - assert_eq!((1337f32).to_bits(), 0x44a72000); - assert_eq!((-14.25f32).to_bits(), 0xc1640000); - assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); - assert_approx_eq!(f32::from_bits(0x41480000), 12.5); - assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); - assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA; - let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555; - assert!(f32::from_bits(masked_nan1).is_nan()); - assert!(f32::from_bits(masked_nan2).is_nan()); - - assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); - } - - #[test] - #[should_panic] - fn test_clamp_min_greater_than_max() { - let _ = 1.0f32.clamp(3.0, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_min_is_nan() { - let _ = 1.0f32.clamp(f32::NAN, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_max_is_nan() { - let _ = 1.0f32.clamp(3.0, f32::NAN); - } - - #[test] - fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u32 { - 1 << (f32::MANTISSA_DIGITS - 2) - } - - fn min_subnorm() -> f32 { - f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0) - } - - fn max_subnorm() -> f32 { - f32::MIN_POSITIVE - min_subnorm() - } - - fn q_nan() -> f32 { - f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f32 { - f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0)); - assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0)); - assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5)); - assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0)); - assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); - } -} diff --git a/library/std/src/f32/tests.rs b/library/std/src/f32/tests.rs new file mode 100644 index 0000000000..0d4b865f33 --- /dev/null +++ b/library/std/src/f32/tests.rs @@ -0,0 +1,759 @@ +use crate::f32::consts; +use crate::num::FpCategory as Fp; +use crate::num::*; + +#[test] +fn test_num_f32() { + test_num(10f32, 2f32); +} + +#[test] +fn test_min_nan() { + assert_eq!(f32::NAN.min(2.0), 2.0); + assert_eq!(2.0f32.min(f32::NAN), 2.0); +} + +#[test] +fn test_max_nan() { + assert_eq!(f32::NAN.max(2.0), 2.0); + assert_eq!(2.0f32.max(f32::NAN), 2.0); +} + +#[test] +fn test_nan() { + let nan: f32 = f32::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); +} + +#[test] +fn test_infinity() { + let inf: f32 = f32::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f32 = 0.0f32; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f32 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[test] +fn test_one() { + let one: f32 = 1.0f32; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f32.is_nan()); + assert!(!5.3f32.is_nan()); + assert!(!(-10.732f32).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f32.is_infinite()); + assert!(!42.8f32.is_infinite()); + assert!(!(-109.2f32).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f32.is_finite()); + assert!(42.8f32.is_finite()); + assert!((-109.2f32).is_finite()); +} + +#[test] +fn test_is_normal() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f32.is_normal()); + assert!(1e-37f32.is_normal()); + assert!(!1e-38f32.is_normal()); +} + +#[test] +fn test_classify() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let zero: f32 = 0.0f32; + let neg_zero: f32 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1f32.classify(), Fp::Normal); + assert_eq!(1e-37f32.classify(), Fp::Normal); + assert_eq!(1e-38f32.classify(), Fp::Subnormal); +} + +#[test] +fn test_floor() { + assert_approx_eq!(1.0f32.floor(), 1.0f32); + assert_approx_eq!(1.3f32.floor(), 1.0f32); + assert_approx_eq!(1.5f32.floor(), 1.0f32); + assert_approx_eq!(1.7f32.floor(), 1.0f32); + assert_approx_eq!(0.0f32.floor(), 0.0f32); + assert_approx_eq!((-0.0f32).floor(), -0.0f32); + assert_approx_eq!((-1.0f32).floor(), -1.0f32); + assert_approx_eq!((-1.3f32).floor(), -2.0f32); + assert_approx_eq!((-1.5f32).floor(), -2.0f32); + assert_approx_eq!((-1.7f32).floor(), -2.0f32); +} + +#[test] +fn test_ceil() { + assert_approx_eq!(1.0f32.ceil(), 1.0f32); + assert_approx_eq!(1.3f32.ceil(), 2.0f32); + assert_approx_eq!(1.5f32.ceil(), 2.0f32); + assert_approx_eq!(1.7f32.ceil(), 2.0f32); + assert_approx_eq!(0.0f32.ceil(), 0.0f32); + assert_approx_eq!((-0.0f32).ceil(), -0.0f32); + assert_approx_eq!((-1.0f32).ceil(), -1.0f32); + assert_approx_eq!((-1.3f32).ceil(), -1.0f32); + assert_approx_eq!((-1.5f32).ceil(), -1.0f32); + assert_approx_eq!((-1.7f32).ceil(), -1.0f32); +} + +#[test] +fn test_round() { + assert_approx_eq!(1.0f32.round(), 1.0f32); + assert_approx_eq!(1.3f32.round(), 1.0f32); + assert_approx_eq!(1.5f32.round(), 2.0f32); + assert_approx_eq!(1.7f32.round(), 2.0f32); + assert_approx_eq!(0.0f32.round(), 0.0f32); + assert_approx_eq!((-0.0f32).round(), -0.0f32); + assert_approx_eq!((-1.0f32).round(), -1.0f32); + assert_approx_eq!((-1.3f32).round(), -1.0f32); + assert_approx_eq!((-1.5f32).round(), -2.0f32); + assert_approx_eq!((-1.7f32).round(), -2.0f32); +} + +#[test] +fn test_trunc() { + assert_approx_eq!(1.0f32.trunc(), 1.0f32); + assert_approx_eq!(1.3f32.trunc(), 1.0f32); + assert_approx_eq!(1.5f32.trunc(), 1.0f32); + assert_approx_eq!(1.7f32.trunc(), 1.0f32); + assert_approx_eq!(0.0f32.trunc(), 0.0f32); + assert_approx_eq!((-0.0f32).trunc(), -0.0f32); + assert_approx_eq!((-1.0f32).trunc(), -1.0f32); + assert_approx_eq!((-1.3f32).trunc(), -1.0f32); + assert_approx_eq!((-1.5f32).trunc(), -1.0f32); + assert_approx_eq!((-1.7f32).trunc(), -1.0f32); +} + +#[test] +fn test_fract() { + assert_approx_eq!(1.0f32.fract(), 0.0f32); + assert_approx_eq!(1.3f32.fract(), 0.3f32); + assert_approx_eq!(1.5f32.fract(), 0.5f32); + assert_approx_eq!(1.7f32.fract(), 0.7f32); + assert_approx_eq!(0.0f32.fract(), 0.0f32); + assert_approx_eq!((-0.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.0f32).fract(), -0.0f32); + assert_approx_eq!((-1.3f32).fract(), -0.3f32); + assert_approx_eq!((-1.5f32).fract(), -0.5f32); + assert_approx_eq!((-1.7f32).fract(), -0.7f32); +} + +#[test] +fn test_abs() { + assert_eq!(f32::INFINITY.abs(), f32::INFINITY); + assert_eq!(1f32.abs(), 1f32); + assert_eq!(0f32.abs(), 0f32); + assert_eq!((-0f32).abs(), 0f32); + assert_eq!((-1f32).abs(), 1f32); + assert_eq!(f32::NEG_INFINITY.abs(), f32::INFINITY); + assert_eq!((1f32 / f32::NEG_INFINITY).abs(), 0f32); + assert!(f32::NAN.abs().is_nan()); +} + +#[test] +fn test_signum() { + assert_eq!(f32::INFINITY.signum(), 1f32); + assert_eq!(1f32.signum(), 1f32); + assert_eq!(0f32.signum(), 1f32); + assert_eq!((-0f32).signum(), -1f32); + assert_eq!((-1f32).signum(), -1f32); + assert_eq!(f32::NEG_INFINITY.signum(), -1f32); + assert_eq!((1f32 / f32::NEG_INFINITY).signum(), -1f32); + assert!(f32::NAN.signum().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f32::INFINITY.is_sign_positive()); + assert!(1f32.is_sign_positive()); + assert!(0f32.is_sign_positive()); + assert!(!(-0f32).is_sign_positive()); + assert!(!(-1f32).is_sign_positive()); + assert!(!f32::NEG_INFINITY.is_sign_positive()); + assert!(!(1f32 / f32::NEG_INFINITY).is_sign_positive()); + assert!(f32::NAN.is_sign_positive()); + assert!(!(-f32::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f32::INFINITY.is_sign_negative()); + assert!(!1f32.is_sign_negative()); + assert!(!0f32.is_sign_negative()); + assert!((-0f32).is_sign_negative()); + assert!((-1f32).is_sign_negative()); + assert!(f32::NEG_INFINITY.is_sign_negative()); + assert!((1f32 / f32::NEG_INFINITY).is_sign_negative()); + assert!(!f32::NAN.is_sign_negative()); + assert!((-f32::NAN).is_sign_negative()); +} + +#[test] +fn test_mul_add() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(12.3f32.mul_add(4.5, 6.7), 62.05); + assert_approx_eq!((-12.3f32).mul_add(-4.5, -6.7), 48.65); + assert_approx_eq!(0.0f32.mul_add(8.9, 1.2), 1.2); + assert_approx_eq!(3.4f32.mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f32.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f32).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +fn test_recip() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.recip(), 1.0); + assert_eq!(2.0f32.recip(), 0.5); + assert_eq!((-0.4f32).recip(), -2.5); + assert_eq!(0.0f32.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +fn test_powi() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powi(1), 1.0); + assert_approx_eq!((-3.1f32).powi(2), 9.61); + assert_approx_eq!(5.9f32.powi(-2), 0.028727); + assert_eq!(8.3f32.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +fn test_powf() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.powf(1.0), 1.0); + assert_approx_eq!(3.4f32.powf(4.5), 246.408218); + assert_approx_eq!(2.7f32.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f32).powf(2.0), 9.61); + assert_approx_eq!(5.9f32.powf(-2.0), 0.028727); + assert_eq!(8.3f32.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +fn test_sqrt_domain() { + assert!(f32::NAN.sqrt().is_nan()); + assert!(f32::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f32).sqrt().is_nan()); + assert_eq!((-0.0f32).sqrt(), -0.0); + assert_eq!(0.0f32.sqrt(), 0.0); + assert_eq!(1.0f32.sqrt(), 1.0); + assert_eq!(f32::INFINITY.sqrt(), f32::INFINITY); +} + +#[test] +fn test_exp() { + assert_eq!(1.0, 0.0f32.exp()); + assert_approx_eq!(2.718282, 1.0f32.exp()); + assert_approx_eq!(148.413162, 5.0f32.exp()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +fn test_exp2() { + assert_eq!(32.0, 5.0f32.exp2()); + assert_eq!(1.0, 0.0f32.exp2()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +fn test_ln() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(1.0f32.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f32).ln().is_nan()); + assert_eq!((-0.0f32).ln(), neg_inf); + assert_eq!(0.0f32.ln(), neg_inf); + assert_approx_eq!(4.0f32.ln(), 1.386294); +} + +#[test] +fn test_log() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log(10.0), 1.0); + assert_approx_eq!(2.3f32.log(3.5), 0.664858); + assert_eq!(1.0f32.exp().log(1.0f32.exp()), 1.0); + assert!(1.0f32.log(1.0).is_nan()); + assert!(1.0f32.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f32).log(0.1).is_nan()); + assert_eq!((-0.0f32).log(2.0), neg_inf); + assert_eq!(0.0f32.log(7.0), neg_inf); +} + +#[test] +fn test_log2() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_approx_eq!(10.0f32.log2(), 3.321928); + assert_approx_eq!(2.3f32.log2(), 1.201634); + assert_approx_eq!(1.0f32.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f32).log2().is_nan()); + assert_eq!((-0.0f32).log2(), neg_inf); + assert_eq!(0.0f32.log2(), neg_inf); +} + +#[test] +fn test_log10() { + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(10.0f32.log10(), 1.0); + assert_approx_eq!(2.3f32.log10(), 0.361728); + assert_approx_eq!(1.0f32.exp().log10(), 0.434294); + assert_eq!(1.0f32.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f32).log10().is_nan()); + assert_eq!((-0.0f32).log10(), neg_inf); + assert_eq!(0.0f32.log10(), neg_inf); +} + +#[test] +fn test_to_degrees() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_degrees(), 0.0); + assert_approx_eq!((-5.8f32).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); + assert_eq!(1_f32.to_degrees(), 57.2957795130823208767981548141051703); +} + +#[test] +fn test_to_radians() { + let pi: f32 = consts::PI; + let nan: f32 = f32::NAN; + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + assert_eq!(0.0f32.to_radians(), 0.0); + assert_approx_eq!(154.6f32.to_radians(), 2.698279); + assert_approx_eq!((-332.31f32).to_radians(), -5.799903); + assert_eq!(180.0f32.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_asinh() { + assert_eq!(0.0f32.asinh(), 0.0f32); + assert_eq!((-0.0f32).asinh(), -0.0f32); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f32).asinh().is_sign_negative()); // issue 63271 + assert_approx_eq!(2.0f32.asinh(), 1.443635475178810342493276740273105f32); + assert_approx_eq!((-2.0f32).asinh(), -1.443635475178810342493276740273105f32); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-3000.0f32).asinh(), -8.699514775987968673236893537700647f32); +} + +#[test] +fn test_acosh() { + assert_eq!(1.0f32.acosh(), 0.0f32); + assert!(0.999f32.acosh().is_nan()); + + let inf: f32 = f32::INFINITY; + let neg_inf: f32 = f32::NEG_INFINITY; + let nan: f32 = f32::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f32.acosh(), 1.31695789692481670862504634730796844f32); + assert_approx_eq!(3.0f32.acosh(), 1.76274717403908605046521864995958461f32); +} + +#[test] +fn test_atanh() { + assert_eq!(0.0f32.atanh(), 0.0f32); + assert_eq!((-0.0f32).atanh(), -0.0f32); + + let inf32: f32 = f32::INFINITY; + let neg_inf32: f32 = f32::NEG_INFINITY; + assert_eq!(1.0f32.atanh(), inf32); + assert_eq!((-1.0f32).atanh(), neg_inf32); + + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + + let inf64: f32 = f32::INFINITY; + let neg_inf64: f32 = f32::NEG_INFINITY; + let nan32: f32 = f32::NAN; + assert!(inf64.atanh().is_nan()); + assert!(neg_inf64.atanh().is_nan()); + assert!(nan32.atanh().is_nan()); + + assert_approx_eq!(0.5f32.atanh(), 0.54930614433405484569762261846126285f32); + assert_approx_eq!((-0.5f32).atanh(), -0.54930614433405484569762261846126285f32); +} + +#[test] +fn test_real_consts() { + use super::consts; + + let pi: f32 = consts::PI; + let frac_pi_2: f32 = consts::FRAC_PI_2; + let frac_pi_3: f32 = consts::FRAC_PI_3; + let frac_pi_4: f32 = consts::FRAC_PI_4; + let frac_pi_6: f32 = consts::FRAC_PI_6; + let frac_pi_8: f32 = consts::FRAC_PI_8; + let frac_1_pi: f32 = consts::FRAC_1_PI; + let frac_2_pi: f32 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f32 = consts::FRAC_2_SQRT_PI; + let sqrt2: f32 = consts::SQRT_2; + let frac_1_sqrt2: f32 = consts::FRAC_1_SQRT_2; + let e: f32 = consts::E; + let log2_e: f32 = consts::LOG2_E; + let log10_e: f32 = consts::LOG10_E; + let ln_2: f32 = consts::LN_2; + let ln_10: f32 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f32); + assert_approx_eq!(frac_pi_3, pi / 3f32); + assert_approx_eq!(frac_pi_4, pi / 4f32); + assert_approx_eq!(frac_pi_6, pi / 6f32); + assert_approx_eq!(frac_pi_8, pi / 8f32); + assert_approx_eq!(frac_1_pi, 1f32 / pi); + assert_approx_eq!(frac_2_pi, 2f32 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f32 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f32.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f32 / 2f32.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f32.ln()); + assert_approx_eq!(ln_10, 10f32.ln()); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f32).to_bits(), 0x3f800000); + assert_eq!((12.5f32).to_bits(), 0x41480000); + assert_eq!((1337f32).to_bits(), 0x44a72000); + assert_eq!((-14.25f32).to_bits(), 0xc1640000); + assert_approx_eq!(f32::from_bits(0x3f800000), 1.0); + assert_approx_eq!(f32::from_bits(0x41480000), 12.5); + assert_approx_eq!(f32::from_bits(0x44a72000), 1337.0); + assert_approx_eq!(f32::from_bits(0xc1640000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + let masked_nan1 = f32::NAN.to_bits() ^ 0x002A_AAAA; + let masked_nan2 = f32::NAN.to_bits() ^ 0x0055_5555; + assert!(f32::from_bits(masked_nan1).is_nan()); + assert!(f32::from_bits(masked_nan2).is_nan()); + + assert_eq!(f32::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f32::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f32.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f32.clamp(f32::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f32.clamp(3.0, f32::NAN); +} + +#[test] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u32 { + 1 << (f32::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f32 { + f32::MIN_POSITIVE / f32::powf(2.0, f32::MANTISSA_DIGITS as f32 - 1.0) + } + + fn max_subnorm() -> f32 { + f32::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f32 { + f32::from_bits(f32::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f32 { + f32::from_bits((f32::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f32::INFINITY).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Equal, (-f32::MAX).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f32::MIN_POSITIVE).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f32).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f32.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f32::MIN_POSITIVE.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f32::MAX.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Equal, f32::INFINITY.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-f32::INFINITY).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-f32::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f32).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f32).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f32::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f32).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f32.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f32::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f32.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f32.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, f32::MAX.total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, f32::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f32::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f32::MAX).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f32).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f32).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f32).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f32).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f32::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f32).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f32.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f32::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f32.total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f32.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f32.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f32.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f32::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f32::INFINITY.total_cmp(&f32::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f32::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} diff --git a/library/std/src/f64.rs b/library/std/src/f64.rs index f09fc8d790..bd094bdb55 100644 --- a/library/std/src/f64.rs +++ b/library/std/src/f64.rs @@ -11,6 +11,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#[cfg(test)] +mod tests; + #[cfg(not(test))] use crate::intrinsics; #[cfg(not(test))] @@ -936,762 +939,3 @@ impl f64 { } } } - -#[cfg(test)] -mod tests { - use crate::f64::consts; - use crate::num::FpCategory as Fp; - use crate::num::*; - - #[test] - fn test_num_f64() { - test_num(10f64, 2f64); - } - - #[test] - fn test_min_nan() { - assert_eq!(f64::NAN.min(2.0), 2.0); - assert_eq!(2.0f64.min(f64::NAN), 2.0); - } - - #[test] - fn test_max_nan() { - assert_eq!(f64::NAN.max(2.0), 2.0); - assert_eq!(2.0f64.max(f64::NAN), 2.0); - } - - #[test] - fn test_nan() { - let nan: f64 = f64::NAN; - assert!(nan.is_nan()); - assert!(!nan.is_infinite()); - assert!(!nan.is_finite()); - assert!(!nan.is_normal()); - assert!(nan.is_sign_positive()); - assert!(!nan.is_sign_negative()); - assert_eq!(Fp::Nan, nan.classify()); - } - - #[test] - fn test_infinity() { - let inf: f64 = f64::INFINITY; - assert!(inf.is_infinite()); - assert!(!inf.is_finite()); - assert!(inf.is_sign_positive()); - assert!(!inf.is_sign_negative()); - assert!(!inf.is_nan()); - assert!(!inf.is_normal()); - assert_eq!(Fp::Infinite, inf.classify()); - } - - #[test] - fn test_neg_infinity() { - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(neg_inf.is_infinite()); - assert!(!neg_inf.is_finite()); - assert!(!neg_inf.is_sign_positive()); - assert!(neg_inf.is_sign_negative()); - assert!(!neg_inf.is_nan()); - assert!(!neg_inf.is_normal()); - assert_eq!(Fp::Infinite, neg_inf.classify()); - } - - #[test] - fn test_zero() { - let zero: f64 = 0.0f64; - assert_eq!(0.0, zero); - assert!(!zero.is_infinite()); - assert!(zero.is_finite()); - assert!(zero.is_sign_positive()); - assert!(!zero.is_sign_negative()); - assert!(!zero.is_nan()); - assert!(!zero.is_normal()); - assert_eq!(Fp::Zero, zero.classify()); - } - - #[test] - fn test_neg_zero() { - let neg_zero: f64 = -0.0; - assert_eq!(0.0, neg_zero); - assert!(!neg_zero.is_infinite()); - assert!(neg_zero.is_finite()); - assert!(!neg_zero.is_sign_positive()); - assert!(neg_zero.is_sign_negative()); - assert!(!neg_zero.is_nan()); - assert!(!neg_zero.is_normal()); - assert_eq!(Fp::Zero, neg_zero.classify()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_one() { - let one: f64 = 1.0f64; - assert_eq!(1.0, one); - assert!(!one.is_infinite()); - assert!(one.is_finite()); - assert!(one.is_sign_positive()); - assert!(!one.is_sign_negative()); - assert!(!one.is_nan()); - assert!(one.is_normal()); - assert_eq!(Fp::Normal, one.classify()); - } - - #[test] - fn test_is_nan() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(nan.is_nan()); - assert!(!0.0f64.is_nan()); - assert!(!5.3f64.is_nan()); - assert!(!(-10.732f64).is_nan()); - assert!(!inf.is_nan()); - assert!(!neg_inf.is_nan()); - } - - #[test] - fn test_is_infinite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_infinite()); - assert!(inf.is_infinite()); - assert!(neg_inf.is_infinite()); - assert!(!0.0f64.is_infinite()); - assert!(!42.8f64.is_infinite()); - assert!(!(-109.2f64).is_infinite()); - } - - #[test] - fn test_is_finite() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert!(!nan.is_finite()); - assert!(!inf.is_finite()); - assert!(!neg_inf.is_finite()); - assert!(0.0f64.is_finite()); - assert!(42.8f64.is_finite()); - assert!((-109.2f64).is_finite()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_is_normal() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert!(!nan.is_normal()); - assert!(!inf.is_normal()); - assert!(!neg_inf.is_normal()); - assert!(!zero.is_normal()); - assert!(!neg_zero.is_normal()); - assert!(1f64.is_normal()); - assert!(1e-307f64.is_normal()); - assert!(!1e-308f64.is_normal()); - } - - #[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 - #[test] - fn test_classify() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let zero: f64 = 0.0f64; - let neg_zero: f64 = -0.0; - assert_eq!(nan.classify(), Fp::Nan); - assert_eq!(inf.classify(), Fp::Infinite); - assert_eq!(neg_inf.classify(), Fp::Infinite); - assert_eq!(zero.classify(), Fp::Zero); - assert_eq!(neg_zero.classify(), Fp::Zero); - assert_eq!(1e-307f64.classify(), Fp::Normal); - assert_eq!(1e-308f64.classify(), Fp::Subnormal); - } - - #[test] - fn test_floor() { - assert_approx_eq!(1.0f64.floor(), 1.0f64); - assert_approx_eq!(1.3f64.floor(), 1.0f64); - assert_approx_eq!(1.5f64.floor(), 1.0f64); - assert_approx_eq!(1.7f64.floor(), 1.0f64); - assert_approx_eq!(0.0f64.floor(), 0.0f64); - assert_approx_eq!((-0.0f64).floor(), -0.0f64); - assert_approx_eq!((-1.0f64).floor(), -1.0f64); - assert_approx_eq!((-1.3f64).floor(), -2.0f64); - assert_approx_eq!((-1.5f64).floor(), -2.0f64); - assert_approx_eq!((-1.7f64).floor(), -2.0f64); - } - - #[test] - fn test_ceil() { - assert_approx_eq!(1.0f64.ceil(), 1.0f64); - assert_approx_eq!(1.3f64.ceil(), 2.0f64); - assert_approx_eq!(1.5f64.ceil(), 2.0f64); - assert_approx_eq!(1.7f64.ceil(), 2.0f64); - assert_approx_eq!(0.0f64.ceil(), 0.0f64); - assert_approx_eq!((-0.0f64).ceil(), -0.0f64); - assert_approx_eq!((-1.0f64).ceil(), -1.0f64); - assert_approx_eq!((-1.3f64).ceil(), -1.0f64); - assert_approx_eq!((-1.5f64).ceil(), -1.0f64); - assert_approx_eq!((-1.7f64).ceil(), -1.0f64); - } - - #[test] - fn test_round() { - assert_approx_eq!(1.0f64.round(), 1.0f64); - assert_approx_eq!(1.3f64.round(), 1.0f64); - assert_approx_eq!(1.5f64.round(), 2.0f64); - assert_approx_eq!(1.7f64.round(), 2.0f64); - assert_approx_eq!(0.0f64.round(), 0.0f64); - assert_approx_eq!((-0.0f64).round(), -0.0f64); - assert_approx_eq!((-1.0f64).round(), -1.0f64); - assert_approx_eq!((-1.3f64).round(), -1.0f64); - assert_approx_eq!((-1.5f64).round(), -2.0f64); - assert_approx_eq!((-1.7f64).round(), -2.0f64); - } - - #[test] - fn test_trunc() { - assert_approx_eq!(1.0f64.trunc(), 1.0f64); - assert_approx_eq!(1.3f64.trunc(), 1.0f64); - assert_approx_eq!(1.5f64.trunc(), 1.0f64); - assert_approx_eq!(1.7f64.trunc(), 1.0f64); - assert_approx_eq!(0.0f64.trunc(), 0.0f64); - assert_approx_eq!((-0.0f64).trunc(), -0.0f64); - assert_approx_eq!((-1.0f64).trunc(), -1.0f64); - assert_approx_eq!((-1.3f64).trunc(), -1.0f64); - assert_approx_eq!((-1.5f64).trunc(), -1.0f64); - assert_approx_eq!((-1.7f64).trunc(), -1.0f64); - } - - #[test] - fn test_fract() { - assert_approx_eq!(1.0f64.fract(), 0.0f64); - assert_approx_eq!(1.3f64.fract(), 0.3f64); - assert_approx_eq!(1.5f64.fract(), 0.5f64); - assert_approx_eq!(1.7f64.fract(), 0.7f64); - assert_approx_eq!(0.0f64.fract(), 0.0f64); - assert_approx_eq!((-0.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.0f64).fract(), -0.0f64); - assert_approx_eq!((-1.3f64).fract(), -0.3f64); - assert_approx_eq!((-1.5f64).fract(), -0.5f64); - assert_approx_eq!((-1.7f64).fract(), -0.7f64); - } - - #[test] - fn test_abs() { - assert_eq!(f64::INFINITY.abs(), f64::INFINITY); - assert_eq!(1f64.abs(), 1f64); - assert_eq!(0f64.abs(), 0f64); - assert_eq!((-0f64).abs(), 0f64); - assert_eq!((-1f64).abs(), 1f64); - assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY); - assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64); - assert!(f64::NAN.abs().is_nan()); - } - - #[test] - fn test_signum() { - assert_eq!(f64::INFINITY.signum(), 1f64); - assert_eq!(1f64.signum(), 1f64); - assert_eq!(0f64.signum(), 1f64); - assert_eq!((-0f64).signum(), -1f64); - assert_eq!((-1f64).signum(), -1f64); - assert_eq!(f64::NEG_INFINITY.signum(), -1f64); - assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64); - assert!(f64::NAN.signum().is_nan()); - } - - #[test] - fn test_is_sign_positive() { - assert!(f64::INFINITY.is_sign_positive()); - assert!(1f64.is_sign_positive()); - assert!(0f64.is_sign_positive()); - assert!(!(-0f64).is_sign_positive()); - assert!(!(-1f64).is_sign_positive()); - assert!(!f64::NEG_INFINITY.is_sign_positive()); - assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive()); - assert!(f64::NAN.is_sign_positive()); - assert!(!(-f64::NAN).is_sign_positive()); - } - - #[test] - fn test_is_sign_negative() { - assert!(!f64::INFINITY.is_sign_negative()); - assert!(!1f64.is_sign_negative()); - assert!(!0f64.is_sign_negative()); - assert!((-0f64).is_sign_negative()); - assert!((-1f64).is_sign_negative()); - assert!(f64::NEG_INFINITY.is_sign_negative()); - assert!((1f64 / f64::NEG_INFINITY).is_sign_negative()); - assert!(!f64::NAN.is_sign_negative()); - assert!((-f64::NAN).is_sign_negative()); - } - - #[test] - fn test_mul_add() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); - assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); - assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); - assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); - assert!(nan.mul_add(7.8, 9.0).is_nan()); - assert_eq!(inf.mul_add(7.8, 9.0), inf); - assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); - assert_eq!(8.9f64.mul_add(inf, 3.2), inf); - assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); - } - - #[test] - fn test_recip() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.recip(), 1.0); - assert_eq!(2.0f64.recip(), 0.5); - assert_eq!((-0.4f64).recip(), -2.5); - assert_eq!(0.0f64.recip(), inf); - assert!(nan.recip().is_nan()); - assert_eq!(inf.recip(), 0.0); - assert_eq!(neg_inf.recip(), 0.0); - } - - #[test] - fn test_powi() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.powi(1), 1.0); - assert_approx_eq!((-3.1f64).powi(2), 9.61); - assert_approx_eq!(5.9f64.powi(-2), 0.028727); - assert_eq!(8.3f64.powi(0), 1.0); - assert!(nan.powi(2).is_nan()); - assert_eq!(inf.powi(3), inf); - assert_eq!(neg_inf.powi(2), inf); - } - - #[test] - fn test_powf() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(1.0f64.powf(1.0), 1.0); - assert_approx_eq!(3.4f64.powf(4.5), 246.408183); - assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); - assert_approx_eq!((-3.1f64).powf(2.0), 9.61); - assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); - assert_eq!(8.3f64.powf(0.0), 1.0); - assert!(nan.powf(2.0).is_nan()); - assert_eq!(inf.powf(2.0), inf); - assert_eq!(neg_inf.powf(3.0), neg_inf); - } - - #[test] - fn test_sqrt_domain() { - assert!(f64::NAN.sqrt().is_nan()); - assert!(f64::NEG_INFINITY.sqrt().is_nan()); - assert!((-1.0f64).sqrt().is_nan()); - assert_eq!((-0.0f64).sqrt(), -0.0); - assert_eq!(0.0f64.sqrt(), 0.0); - assert_eq!(1.0f64.sqrt(), 1.0); - assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); - } - - #[test] - fn test_exp() { - assert_eq!(1.0, 0.0f64.exp()); - assert_approx_eq!(2.718282, 1.0f64.exp()); - assert_approx_eq!(148.413159, 5.0f64.exp()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf, inf.exp()); - assert_eq!(0.0, neg_inf.exp()); - assert!(nan.exp().is_nan()); - } - - #[test] - fn test_exp2() { - assert_eq!(32.0, 5.0f64.exp2()); - assert_eq!(1.0, 0.0f64.exp2()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf, inf.exp2()); - assert_eq!(0.0, neg_inf.exp2()); - assert!(nan.exp2().is_nan()); - } - - #[test] - fn test_ln() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(1.0f64.exp().ln(), 1.0); - assert!(nan.ln().is_nan()); - assert_eq!(inf.ln(), inf); - assert!(neg_inf.ln().is_nan()); - assert!((-2.3f64).ln().is_nan()); - assert_eq!((-0.0f64).ln(), neg_inf); - assert_eq!(0.0f64.ln(), neg_inf); - assert_approx_eq!(4.0f64.ln(), 1.386294); - } - - #[test] - fn test_log() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log(10.0), 1.0); - assert_approx_eq!(2.3f64.log(3.5), 0.664858); - assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); - assert!(1.0f64.log(1.0).is_nan()); - assert!(1.0f64.log(-13.9).is_nan()); - assert!(nan.log(2.3).is_nan()); - assert_eq!(inf.log(10.0), inf); - assert!(neg_inf.log(8.8).is_nan()); - assert!((-2.3f64).log(0.1).is_nan()); - assert_eq!((-0.0f64).log(2.0), neg_inf); - assert_eq!(0.0f64.log(7.0), neg_inf); - } - - #[test] - fn test_log2() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_approx_eq!(10.0f64.log2(), 3.321928); - assert_approx_eq!(2.3f64.log2(), 1.201634); - assert_approx_eq!(1.0f64.exp().log2(), 1.442695); - assert!(nan.log2().is_nan()); - assert_eq!(inf.log2(), inf); - assert!(neg_inf.log2().is_nan()); - assert!((-2.3f64).log2().is_nan()); - assert_eq!((-0.0f64).log2(), neg_inf); - assert_eq!(0.0f64.log2(), neg_inf); - } - - #[test] - fn test_log10() { - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(10.0f64.log10(), 1.0); - assert_approx_eq!(2.3f64.log10(), 0.361728); - assert_approx_eq!(1.0f64.exp().log10(), 0.434294); - assert_eq!(1.0f64.log10(), 0.0); - assert!(nan.log10().is_nan()); - assert_eq!(inf.log10(), inf); - assert!(neg_inf.log10().is_nan()); - assert!((-2.3f64).log10().is_nan()); - assert_eq!((-0.0f64).log10(), neg_inf); - assert_eq!(0.0f64.log10(), neg_inf); - } - - #[test] - fn test_to_degrees() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(0.0f64.to_degrees(), 0.0); - assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); - assert_eq!(pi.to_degrees(), 180.0); - assert!(nan.to_degrees().is_nan()); - assert_eq!(inf.to_degrees(), inf); - assert_eq!(neg_inf.to_degrees(), neg_inf); - } - - #[test] - fn test_to_radians() { - let pi: f64 = consts::PI; - let nan: f64 = f64::NAN; - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - assert_eq!(0.0f64.to_radians(), 0.0); - assert_approx_eq!(154.6f64.to_radians(), 2.698279); - assert_approx_eq!((-332.31f64).to_radians(), -5.799903); - assert_eq!(180.0f64.to_radians(), pi); - assert!(nan.to_radians().is_nan()); - assert_eq!(inf.to_radians(), inf); - assert_eq!(neg_inf.to_radians(), neg_inf); - } - - #[test] - fn test_asinh() { - assert_eq!(0.0f64.asinh(), 0.0f64); - assert_eq!((-0.0f64).asinh(), -0.0f64); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf.asinh(), inf); - assert_eq!(neg_inf.asinh(), neg_inf); - assert!(nan.asinh().is_nan()); - assert!((-0.0f64).asinh().is_sign_negative()); - // issue 63271 - assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); - assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); - // regression test for the catastrophic cancellation fixed in 72486 - assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); - } - - #[test] - fn test_acosh() { - assert_eq!(1.0f64.acosh(), 0.0f64); - assert!(0.999f64.acosh().is_nan()); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(inf.acosh(), inf); - assert!(neg_inf.acosh().is_nan()); - assert!(nan.acosh().is_nan()); - assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); - assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); - } - - #[test] - fn test_atanh() { - assert_eq!(0.0f64.atanh(), 0.0f64); - assert_eq!((-0.0f64).atanh(), -0.0f64); - - let inf: f64 = f64::INFINITY; - let neg_inf: f64 = f64::NEG_INFINITY; - let nan: f64 = f64::NAN; - assert_eq!(1.0f64.atanh(), inf); - assert_eq!((-1.0f64).atanh(), neg_inf); - assert!(2f64.atanh().atanh().is_nan()); - assert!((-2f64).atanh().atanh().is_nan()); - assert!(inf.atanh().is_nan()); - assert!(neg_inf.atanh().is_nan()); - assert!(nan.atanh().is_nan()); - assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); - assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); - } - - #[test] - fn test_real_consts() { - use super::consts; - let pi: f64 = consts::PI; - let frac_pi_2: f64 = consts::FRAC_PI_2; - let frac_pi_3: f64 = consts::FRAC_PI_3; - let frac_pi_4: f64 = consts::FRAC_PI_4; - let frac_pi_6: f64 = consts::FRAC_PI_6; - let frac_pi_8: f64 = consts::FRAC_PI_8; - let frac_1_pi: f64 = consts::FRAC_1_PI; - let frac_2_pi: f64 = consts::FRAC_2_PI; - let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; - let sqrt2: f64 = consts::SQRT_2; - let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; - let e: f64 = consts::E; - let log2_e: f64 = consts::LOG2_E; - let log10_e: f64 = consts::LOG10_E; - let ln_2: f64 = consts::LN_2; - let ln_10: f64 = consts::LN_10; - - assert_approx_eq!(frac_pi_2, pi / 2f64); - assert_approx_eq!(frac_pi_3, pi / 3f64); - assert_approx_eq!(frac_pi_4, pi / 4f64); - assert_approx_eq!(frac_pi_6, pi / 6f64); - assert_approx_eq!(frac_pi_8, pi / 8f64); - assert_approx_eq!(frac_1_pi, 1f64 / pi); - assert_approx_eq!(frac_2_pi, 2f64 / pi); - assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); - assert_approx_eq!(sqrt2, 2f64.sqrt()); - assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); - assert_approx_eq!(log2_e, e.log2()); - assert_approx_eq!(log10_e, e.log10()); - assert_approx_eq!(ln_2, 2f64.ln()); - assert_approx_eq!(ln_10, 10f64.ln()); - } - - #[test] - fn test_float_bits_conv() { - assert_eq!((1f64).to_bits(), 0x3ff0000000000000); - assert_eq!((12.5f64).to_bits(), 0x4029000000000000); - assert_eq!((1337f64).to_bits(), 0x4094e40000000000); - assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); - assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); - assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); - assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); - assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); - - // Check that NaNs roundtrip their bits regardless of signaling-ness - // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits - let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; - let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; - assert!(f64::from_bits(masked_nan1).is_nan()); - assert!(f64::from_bits(masked_nan2).is_nan()); - - assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); - assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); - } - - #[test] - #[should_panic] - fn test_clamp_min_greater_than_max() { - let _ = 1.0f64.clamp(3.0, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_min_is_nan() { - let _ = 1.0f64.clamp(f64::NAN, 1.0); - } - - #[test] - #[should_panic] - fn test_clamp_max_is_nan() { - let _ = 1.0f64.clamp(3.0, f64::NAN); - } - - #[test] - fn test_total_cmp() { - use core::cmp::Ordering; - - fn quiet_bit_mask() -> u64 { - 1 << (f64::MANTISSA_DIGITS - 2) - } - - fn min_subnorm() -> f64 { - f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0) - } - - fn max_subnorm() -> f64 { - f64::MIN_POSITIVE - min_subnorm() - } - - fn q_nan() -> f64 { - f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask()) - } - - fn s_nan() -> f64 { - f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42) - } - - assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5)); - assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5)); - assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0)); - assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0)); - assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5)); - assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5)); - assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); - assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0)); - assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5)); - assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5)); - assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan())); - assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); - - assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); - assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan())); - assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5)); - assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5)); - assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0)); - assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5)); - assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0)); - assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); - assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); - assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm())); - assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5)); - assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0)); - assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5)); - assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5)); - assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX)); - assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); - - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); - assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); - } -} diff --git a/library/std/src/f64/tests.rs b/library/std/src/f64/tests.rs new file mode 100644 index 0000000000..5c163cfe90 --- /dev/null +++ b/library/std/src/f64/tests.rs @@ -0,0 +1,755 @@ +use crate::f64::consts; +use crate::num::FpCategory as Fp; +use crate::num::*; + +#[test] +fn test_num_f64() { + test_num(10f64, 2f64); +} + +#[test] +fn test_min_nan() { + assert_eq!(f64::NAN.min(2.0), 2.0); + assert_eq!(2.0f64.min(f64::NAN), 2.0); +} + +#[test] +fn test_max_nan() { + assert_eq!(f64::NAN.max(2.0), 2.0); + assert_eq!(2.0f64.max(f64::NAN), 2.0); +} + +#[test] +fn test_nan() { + let nan: f64 = f64::NAN; + assert!(nan.is_nan()); + assert!(!nan.is_infinite()); + assert!(!nan.is_finite()); + assert!(!nan.is_normal()); + assert!(nan.is_sign_positive()); + assert!(!nan.is_sign_negative()); + assert_eq!(Fp::Nan, nan.classify()); +} + +#[test] +fn test_infinity() { + let inf: f64 = f64::INFINITY; + assert!(inf.is_infinite()); + assert!(!inf.is_finite()); + assert!(inf.is_sign_positive()); + assert!(!inf.is_sign_negative()); + assert!(!inf.is_nan()); + assert!(!inf.is_normal()); + assert_eq!(Fp::Infinite, inf.classify()); +} + +#[test] +fn test_neg_infinity() { + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(neg_inf.is_infinite()); + assert!(!neg_inf.is_finite()); + assert!(!neg_inf.is_sign_positive()); + assert!(neg_inf.is_sign_negative()); + assert!(!neg_inf.is_nan()); + assert!(!neg_inf.is_normal()); + assert_eq!(Fp::Infinite, neg_inf.classify()); +} + +#[test] +fn test_zero() { + let zero: f64 = 0.0f64; + assert_eq!(0.0, zero); + assert!(!zero.is_infinite()); + assert!(zero.is_finite()); + assert!(zero.is_sign_positive()); + assert!(!zero.is_sign_negative()); + assert!(!zero.is_nan()); + assert!(!zero.is_normal()); + assert_eq!(Fp::Zero, zero.classify()); +} + +#[test] +fn test_neg_zero() { + let neg_zero: f64 = -0.0; + assert_eq!(0.0, neg_zero); + assert!(!neg_zero.is_infinite()); + assert!(neg_zero.is_finite()); + assert!(!neg_zero.is_sign_positive()); + assert!(neg_zero.is_sign_negative()); + assert!(!neg_zero.is_nan()); + assert!(!neg_zero.is_normal()); + assert_eq!(Fp::Zero, neg_zero.classify()); +} + +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 +#[test] +fn test_one() { + let one: f64 = 1.0f64; + assert_eq!(1.0, one); + assert!(!one.is_infinite()); + assert!(one.is_finite()); + assert!(one.is_sign_positive()); + assert!(!one.is_sign_negative()); + assert!(!one.is_nan()); + assert!(one.is_normal()); + assert_eq!(Fp::Normal, one.classify()); +} + +#[test] +fn test_is_nan() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(nan.is_nan()); + assert!(!0.0f64.is_nan()); + assert!(!5.3f64.is_nan()); + assert!(!(-10.732f64).is_nan()); + assert!(!inf.is_nan()); + assert!(!neg_inf.is_nan()); +} + +#[test] +fn test_is_infinite() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(!nan.is_infinite()); + assert!(inf.is_infinite()); + assert!(neg_inf.is_infinite()); + assert!(!0.0f64.is_infinite()); + assert!(!42.8f64.is_infinite()); + assert!(!(-109.2f64).is_infinite()); +} + +#[test] +fn test_is_finite() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert!(!nan.is_finite()); + assert!(!inf.is_finite()); + assert!(!neg_inf.is_finite()); + assert!(0.0f64.is_finite()); + assert!(42.8f64.is_finite()); + assert!((-109.2f64).is_finite()); +} + +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 +#[test] +fn test_is_normal() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert!(!nan.is_normal()); + assert!(!inf.is_normal()); + assert!(!neg_inf.is_normal()); + assert!(!zero.is_normal()); + assert!(!neg_zero.is_normal()); + assert!(1f64.is_normal()); + assert!(1e-307f64.is_normal()); + assert!(!1e-308f64.is_normal()); +} + +#[cfg_attr(all(target_arch = "wasm32", target_os = "emscripten"), ignore)] // issue 42630 +#[test] +fn test_classify() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let zero: f64 = 0.0f64; + let neg_zero: f64 = -0.0; + assert_eq!(nan.classify(), Fp::Nan); + assert_eq!(inf.classify(), Fp::Infinite); + assert_eq!(neg_inf.classify(), Fp::Infinite); + assert_eq!(zero.classify(), Fp::Zero); + assert_eq!(neg_zero.classify(), Fp::Zero); + assert_eq!(1e-307f64.classify(), Fp::Normal); + assert_eq!(1e-308f64.classify(), Fp::Subnormal); +} + +#[test] +fn test_floor() { + assert_approx_eq!(1.0f64.floor(), 1.0f64); + assert_approx_eq!(1.3f64.floor(), 1.0f64); + assert_approx_eq!(1.5f64.floor(), 1.0f64); + assert_approx_eq!(1.7f64.floor(), 1.0f64); + assert_approx_eq!(0.0f64.floor(), 0.0f64); + assert_approx_eq!((-0.0f64).floor(), -0.0f64); + assert_approx_eq!((-1.0f64).floor(), -1.0f64); + assert_approx_eq!((-1.3f64).floor(), -2.0f64); + assert_approx_eq!((-1.5f64).floor(), -2.0f64); + assert_approx_eq!((-1.7f64).floor(), -2.0f64); +} + +#[test] +fn test_ceil() { + assert_approx_eq!(1.0f64.ceil(), 1.0f64); + assert_approx_eq!(1.3f64.ceil(), 2.0f64); + assert_approx_eq!(1.5f64.ceil(), 2.0f64); + assert_approx_eq!(1.7f64.ceil(), 2.0f64); + assert_approx_eq!(0.0f64.ceil(), 0.0f64); + assert_approx_eq!((-0.0f64).ceil(), -0.0f64); + assert_approx_eq!((-1.0f64).ceil(), -1.0f64); + assert_approx_eq!((-1.3f64).ceil(), -1.0f64); + assert_approx_eq!((-1.5f64).ceil(), -1.0f64); + assert_approx_eq!((-1.7f64).ceil(), -1.0f64); +} + +#[test] +fn test_round() { + assert_approx_eq!(1.0f64.round(), 1.0f64); + assert_approx_eq!(1.3f64.round(), 1.0f64); + assert_approx_eq!(1.5f64.round(), 2.0f64); + assert_approx_eq!(1.7f64.round(), 2.0f64); + assert_approx_eq!(0.0f64.round(), 0.0f64); + assert_approx_eq!((-0.0f64).round(), -0.0f64); + assert_approx_eq!((-1.0f64).round(), -1.0f64); + assert_approx_eq!((-1.3f64).round(), -1.0f64); + assert_approx_eq!((-1.5f64).round(), -2.0f64); + assert_approx_eq!((-1.7f64).round(), -2.0f64); +} + +#[test] +fn test_trunc() { + assert_approx_eq!(1.0f64.trunc(), 1.0f64); + assert_approx_eq!(1.3f64.trunc(), 1.0f64); + assert_approx_eq!(1.5f64.trunc(), 1.0f64); + assert_approx_eq!(1.7f64.trunc(), 1.0f64); + assert_approx_eq!(0.0f64.trunc(), 0.0f64); + assert_approx_eq!((-0.0f64).trunc(), -0.0f64); + assert_approx_eq!((-1.0f64).trunc(), -1.0f64); + assert_approx_eq!((-1.3f64).trunc(), -1.0f64); + assert_approx_eq!((-1.5f64).trunc(), -1.0f64); + assert_approx_eq!((-1.7f64).trunc(), -1.0f64); +} + +#[test] +fn test_fract() { + assert_approx_eq!(1.0f64.fract(), 0.0f64); + assert_approx_eq!(1.3f64.fract(), 0.3f64); + assert_approx_eq!(1.5f64.fract(), 0.5f64); + assert_approx_eq!(1.7f64.fract(), 0.7f64); + assert_approx_eq!(0.0f64.fract(), 0.0f64); + assert_approx_eq!((-0.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.0f64).fract(), -0.0f64); + assert_approx_eq!((-1.3f64).fract(), -0.3f64); + assert_approx_eq!((-1.5f64).fract(), -0.5f64); + assert_approx_eq!((-1.7f64).fract(), -0.7f64); +} + +#[test] +fn test_abs() { + assert_eq!(f64::INFINITY.abs(), f64::INFINITY); + assert_eq!(1f64.abs(), 1f64); + assert_eq!(0f64.abs(), 0f64); + assert_eq!((-0f64).abs(), 0f64); + assert_eq!((-1f64).abs(), 1f64); + assert_eq!(f64::NEG_INFINITY.abs(), f64::INFINITY); + assert_eq!((1f64 / f64::NEG_INFINITY).abs(), 0f64); + assert!(f64::NAN.abs().is_nan()); +} + +#[test] +fn test_signum() { + assert_eq!(f64::INFINITY.signum(), 1f64); + assert_eq!(1f64.signum(), 1f64); + assert_eq!(0f64.signum(), 1f64); + assert_eq!((-0f64).signum(), -1f64); + assert_eq!((-1f64).signum(), -1f64); + assert_eq!(f64::NEG_INFINITY.signum(), -1f64); + assert_eq!((1f64 / f64::NEG_INFINITY).signum(), -1f64); + assert!(f64::NAN.signum().is_nan()); +} + +#[test] +fn test_is_sign_positive() { + assert!(f64::INFINITY.is_sign_positive()); + assert!(1f64.is_sign_positive()); + assert!(0f64.is_sign_positive()); + assert!(!(-0f64).is_sign_positive()); + assert!(!(-1f64).is_sign_positive()); + assert!(!f64::NEG_INFINITY.is_sign_positive()); + assert!(!(1f64 / f64::NEG_INFINITY).is_sign_positive()); + assert!(f64::NAN.is_sign_positive()); + assert!(!(-f64::NAN).is_sign_positive()); +} + +#[test] +fn test_is_sign_negative() { + assert!(!f64::INFINITY.is_sign_negative()); + assert!(!1f64.is_sign_negative()); + assert!(!0f64.is_sign_negative()); + assert!((-0f64).is_sign_negative()); + assert!((-1f64).is_sign_negative()); + assert!(f64::NEG_INFINITY.is_sign_negative()); + assert!((1f64 / f64::NEG_INFINITY).is_sign_negative()); + assert!(!f64::NAN.is_sign_negative()); + assert!((-f64::NAN).is_sign_negative()); +} + +#[test] +fn test_mul_add() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(12.3f64.mul_add(4.5, 6.7), 62.05); + assert_approx_eq!((-12.3f64).mul_add(-4.5, -6.7), 48.65); + assert_approx_eq!(0.0f64.mul_add(8.9, 1.2), 1.2); + assert_approx_eq!(3.4f64.mul_add(-0.0, 5.6), 5.6); + assert!(nan.mul_add(7.8, 9.0).is_nan()); + assert_eq!(inf.mul_add(7.8, 9.0), inf); + assert_eq!(neg_inf.mul_add(7.8, 9.0), neg_inf); + assert_eq!(8.9f64.mul_add(inf, 3.2), inf); + assert_eq!((-3.2f64).mul_add(2.4, neg_inf), neg_inf); +} + +#[test] +fn test_recip() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.recip(), 1.0); + assert_eq!(2.0f64.recip(), 0.5); + assert_eq!((-0.4f64).recip(), -2.5); + assert_eq!(0.0f64.recip(), inf); + assert!(nan.recip().is_nan()); + assert_eq!(inf.recip(), 0.0); + assert_eq!(neg_inf.recip(), 0.0); +} + +#[test] +fn test_powi() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.powi(1), 1.0); + assert_approx_eq!((-3.1f64).powi(2), 9.61); + assert_approx_eq!(5.9f64.powi(-2), 0.028727); + assert_eq!(8.3f64.powi(0), 1.0); + assert!(nan.powi(2).is_nan()); + assert_eq!(inf.powi(3), inf); + assert_eq!(neg_inf.powi(2), inf); +} + +#[test] +fn test_powf() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(1.0f64.powf(1.0), 1.0); + assert_approx_eq!(3.4f64.powf(4.5), 246.408183); + assert_approx_eq!(2.7f64.powf(-3.2), 0.041652); + assert_approx_eq!((-3.1f64).powf(2.0), 9.61); + assert_approx_eq!(5.9f64.powf(-2.0), 0.028727); + assert_eq!(8.3f64.powf(0.0), 1.0); + assert!(nan.powf(2.0).is_nan()); + assert_eq!(inf.powf(2.0), inf); + assert_eq!(neg_inf.powf(3.0), neg_inf); +} + +#[test] +fn test_sqrt_domain() { + assert!(f64::NAN.sqrt().is_nan()); + assert!(f64::NEG_INFINITY.sqrt().is_nan()); + assert!((-1.0f64).sqrt().is_nan()); + assert_eq!((-0.0f64).sqrt(), -0.0); + assert_eq!(0.0f64.sqrt(), 0.0); + assert_eq!(1.0f64.sqrt(), 1.0); + assert_eq!(f64::INFINITY.sqrt(), f64::INFINITY); +} + +#[test] +fn test_exp() { + assert_eq!(1.0, 0.0f64.exp()); + assert_approx_eq!(2.718282, 1.0f64.exp()); + assert_approx_eq!(148.413159, 5.0f64.exp()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf, inf.exp()); + assert_eq!(0.0, neg_inf.exp()); + assert!(nan.exp().is_nan()); +} + +#[test] +fn test_exp2() { + assert_eq!(32.0, 5.0f64.exp2()); + assert_eq!(1.0, 0.0f64.exp2()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf, inf.exp2()); + assert_eq!(0.0, neg_inf.exp2()); + assert!(nan.exp2().is_nan()); +} + +#[test] +fn test_ln() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(1.0f64.exp().ln(), 1.0); + assert!(nan.ln().is_nan()); + assert_eq!(inf.ln(), inf); + assert!(neg_inf.ln().is_nan()); + assert!((-2.3f64).ln().is_nan()); + assert_eq!((-0.0f64).ln(), neg_inf); + assert_eq!(0.0f64.ln(), neg_inf); + assert_approx_eq!(4.0f64.ln(), 1.386294); +} + +#[test] +fn test_log() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(10.0f64.log(10.0), 1.0); + assert_approx_eq!(2.3f64.log(3.5), 0.664858); + assert_eq!(1.0f64.exp().log(1.0f64.exp()), 1.0); + assert!(1.0f64.log(1.0).is_nan()); + assert!(1.0f64.log(-13.9).is_nan()); + assert!(nan.log(2.3).is_nan()); + assert_eq!(inf.log(10.0), inf); + assert!(neg_inf.log(8.8).is_nan()); + assert!((-2.3f64).log(0.1).is_nan()); + assert_eq!((-0.0f64).log(2.0), neg_inf); + assert_eq!(0.0f64.log(7.0), neg_inf); +} + +#[test] +fn test_log2() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_approx_eq!(10.0f64.log2(), 3.321928); + assert_approx_eq!(2.3f64.log2(), 1.201634); + assert_approx_eq!(1.0f64.exp().log2(), 1.442695); + assert!(nan.log2().is_nan()); + assert_eq!(inf.log2(), inf); + assert!(neg_inf.log2().is_nan()); + assert!((-2.3f64).log2().is_nan()); + assert_eq!((-0.0f64).log2(), neg_inf); + assert_eq!(0.0f64.log2(), neg_inf); +} + +#[test] +fn test_log10() { + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(10.0f64.log10(), 1.0); + assert_approx_eq!(2.3f64.log10(), 0.361728); + assert_approx_eq!(1.0f64.exp().log10(), 0.434294); + assert_eq!(1.0f64.log10(), 0.0); + assert!(nan.log10().is_nan()); + assert_eq!(inf.log10(), inf); + assert!(neg_inf.log10().is_nan()); + assert!((-2.3f64).log10().is_nan()); + assert_eq!((-0.0f64).log10(), neg_inf); + assert_eq!(0.0f64.log10(), neg_inf); +} + +#[test] +fn test_to_degrees() { + let pi: f64 = consts::PI; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(0.0f64.to_degrees(), 0.0); + assert_approx_eq!((-5.8f64).to_degrees(), -332.315521); + assert_eq!(pi.to_degrees(), 180.0); + assert!(nan.to_degrees().is_nan()); + assert_eq!(inf.to_degrees(), inf); + assert_eq!(neg_inf.to_degrees(), neg_inf); +} + +#[test] +fn test_to_radians() { + let pi: f64 = consts::PI; + let nan: f64 = f64::NAN; + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + assert_eq!(0.0f64.to_radians(), 0.0); + assert_approx_eq!(154.6f64.to_radians(), 2.698279); + assert_approx_eq!((-332.31f64).to_radians(), -5.799903); + assert_eq!(180.0f64.to_radians(), pi); + assert!(nan.to_radians().is_nan()); + assert_eq!(inf.to_radians(), inf); + assert_eq!(neg_inf.to_radians(), neg_inf); +} + +#[test] +fn test_asinh() { + assert_eq!(0.0f64.asinh(), 0.0f64); + assert_eq!((-0.0f64).asinh(), -0.0f64); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf.asinh(), inf); + assert_eq!(neg_inf.asinh(), neg_inf); + assert!(nan.asinh().is_nan()); + assert!((-0.0f64).asinh().is_sign_negative()); + // issue 63271 + assert_approx_eq!(2.0f64.asinh(), 1.443635475178810342493276740273105f64); + assert_approx_eq!((-2.0f64).asinh(), -1.443635475178810342493276740273105f64); + // regression test for the catastrophic cancellation fixed in 72486 + assert_approx_eq!((-67452098.07139316f64).asinh(), -18.72007542627454439398548429400083); +} + +#[test] +fn test_acosh() { + assert_eq!(1.0f64.acosh(), 0.0f64); + assert!(0.999f64.acosh().is_nan()); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(inf.acosh(), inf); + assert!(neg_inf.acosh().is_nan()); + assert!(nan.acosh().is_nan()); + assert_approx_eq!(2.0f64.acosh(), 1.31695789692481670862504634730796844f64); + assert_approx_eq!(3.0f64.acosh(), 1.76274717403908605046521864995958461f64); +} + +#[test] +fn test_atanh() { + assert_eq!(0.0f64.atanh(), 0.0f64); + assert_eq!((-0.0f64).atanh(), -0.0f64); + + let inf: f64 = f64::INFINITY; + let neg_inf: f64 = f64::NEG_INFINITY; + let nan: f64 = f64::NAN; + assert_eq!(1.0f64.atanh(), inf); + assert_eq!((-1.0f64).atanh(), neg_inf); + assert!(2f64.atanh().atanh().is_nan()); + assert!((-2f64).atanh().atanh().is_nan()); + assert!(inf.atanh().is_nan()); + assert!(neg_inf.atanh().is_nan()); + assert!(nan.atanh().is_nan()); + assert_approx_eq!(0.5f64.atanh(), 0.54930614433405484569762261846126285f64); + assert_approx_eq!((-0.5f64).atanh(), -0.54930614433405484569762261846126285f64); +} + +#[test] +fn test_real_consts() { + use super::consts; + let pi: f64 = consts::PI; + let frac_pi_2: f64 = consts::FRAC_PI_2; + let frac_pi_3: f64 = consts::FRAC_PI_3; + let frac_pi_4: f64 = consts::FRAC_PI_4; + let frac_pi_6: f64 = consts::FRAC_PI_6; + let frac_pi_8: f64 = consts::FRAC_PI_8; + let frac_1_pi: f64 = consts::FRAC_1_PI; + let frac_2_pi: f64 = consts::FRAC_2_PI; + let frac_2_sqrtpi: f64 = consts::FRAC_2_SQRT_PI; + let sqrt2: f64 = consts::SQRT_2; + let frac_1_sqrt2: f64 = consts::FRAC_1_SQRT_2; + let e: f64 = consts::E; + let log2_e: f64 = consts::LOG2_E; + let log10_e: f64 = consts::LOG10_E; + let ln_2: f64 = consts::LN_2; + let ln_10: f64 = consts::LN_10; + + assert_approx_eq!(frac_pi_2, pi / 2f64); + assert_approx_eq!(frac_pi_3, pi / 3f64); + assert_approx_eq!(frac_pi_4, pi / 4f64); + assert_approx_eq!(frac_pi_6, pi / 6f64); + assert_approx_eq!(frac_pi_8, pi / 8f64); + assert_approx_eq!(frac_1_pi, 1f64 / pi); + assert_approx_eq!(frac_2_pi, 2f64 / pi); + assert_approx_eq!(frac_2_sqrtpi, 2f64 / pi.sqrt()); + assert_approx_eq!(sqrt2, 2f64.sqrt()); + assert_approx_eq!(frac_1_sqrt2, 1f64 / 2f64.sqrt()); + assert_approx_eq!(log2_e, e.log2()); + assert_approx_eq!(log10_e, e.log10()); + assert_approx_eq!(ln_2, 2f64.ln()); + assert_approx_eq!(ln_10, 10f64.ln()); +} + +#[test] +fn test_float_bits_conv() { + assert_eq!((1f64).to_bits(), 0x3ff0000000000000); + assert_eq!((12.5f64).to_bits(), 0x4029000000000000); + assert_eq!((1337f64).to_bits(), 0x4094e40000000000); + assert_eq!((-14.25f64).to_bits(), 0xc02c800000000000); + assert_approx_eq!(f64::from_bits(0x3ff0000000000000), 1.0); + assert_approx_eq!(f64::from_bits(0x4029000000000000), 12.5); + assert_approx_eq!(f64::from_bits(0x4094e40000000000), 1337.0); + assert_approx_eq!(f64::from_bits(0xc02c800000000000), -14.25); + + // Check that NaNs roundtrip their bits regardless of signaling-ness + // 0xA is 0b1010; 0x5 is 0b0101 -- so these two together clobbers all the mantissa bits + let masked_nan1 = f64::NAN.to_bits() ^ 0x000A_AAAA_AAAA_AAAA; + let masked_nan2 = f64::NAN.to_bits() ^ 0x0005_5555_5555_5555; + assert!(f64::from_bits(masked_nan1).is_nan()); + assert!(f64::from_bits(masked_nan2).is_nan()); + + assert_eq!(f64::from_bits(masked_nan1).to_bits(), masked_nan1); + assert_eq!(f64::from_bits(masked_nan2).to_bits(), masked_nan2); +} + +#[test] +#[should_panic] +fn test_clamp_min_greater_than_max() { + let _ = 1.0f64.clamp(3.0, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_min_is_nan() { + let _ = 1.0f64.clamp(f64::NAN, 1.0); +} + +#[test] +#[should_panic] +fn test_clamp_max_is_nan() { + let _ = 1.0f64.clamp(3.0, f64::NAN); +} + +#[test] +fn test_total_cmp() { + use core::cmp::Ordering; + + fn quiet_bit_mask() -> u64 { + 1 << (f64::MANTISSA_DIGITS - 2) + } + + fn min_subnorm() -> f64 { + f64::MIN_POSITIVE / f64::powf(2.0, f64::MANTISSA_DIGITS as f64 - 1.0) + } + + fn max_subnorm() -> f64 { + f64::MIN_POSITIVE - min_subnorm() + } + + fn q_nan() -> f64 { + f64::from_bits(f64::NAN.to_bits() | quiet_bit_mask()) + } + + fn s_nan() -> f64 { + f64::from_bits((f64::NAN.to_bits() & !quiet_bit_mask()) + 42) + } + + assert_eq!(Ordering::Equal, (-q_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Equal, (-s_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Equal, (-f64::INFINITY).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Equal, (-f64::MAX).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Equal, (-2.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Equal, (-1.0_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Equal, (-1.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Equal, (-0.5_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Equal, (-f64::MIN_POSITIVE).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, (-max_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Equal, (-min_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Equal, (-0.0_f64).total_cmp(&-0.0)); + assert_eq!(Ordering::Equal, 0.0_f64.total_cmp(&0.0)); + assert_eq!(Ordering::Equal, min_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Equal, max_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Equal, f64::MIN_POSITIVE.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Equal, 0.5_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Equal, 1.0_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Equal, 1.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Equal, 2.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Equal, f64::MAX.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Equal, f64::INFINITY.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Equal, s_nan().total_cmp(&s_nan())); + assert_eq!(Ordering::Equal, q_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-f64::INFINITY).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-f64::MAX).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-2.5_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-1.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-1.0_f64).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-0.5_f64).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-f64::MIN_POSITIVE).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-max_subnorm()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-min_subnorm()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-0.0_f64).total_cmp(&0.0)); + assert_eq!(Ordering::Less, 0.0_f64.total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, min_subnorm().total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, max_subnorm().total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, f64::MIN_POSITIVE.total_cmp(&0.5)); + assert_eq!(Ordering::Less, 0.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Less, 1.0_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Less, 1.5_f64.total_cmp(&2.5)); + assert_eq!(Ordering::Less, 2.5_f64.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, f64::MAX.total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, f64::INFINITY.total_cmp(&s_nan())); + assert_eq!(Ordering::Less, s_nan().total_cmp(&q_nan())); + + assert_eq!(Ordering::Greater, (-s_nan()).total_cmp(&-q_nan())); + assert_eq!(Ordering::Greater, (-f64::INFINITY).total_cmp(&-s_nan())); + assert_eq!(Ordering::Greater, (-f64::MAX).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Greater, (-2.5_f64).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Greater, (-1.5_f64).total_cmp(&-2.5)); + assert_eq!(Ordering::Greater, (-1.0_f64).total_cmp(&-1.5)); + assert_eq!(Ordering::Greater, (-0.5_f64).total_cmp(&-1.0)); + assert_eq!(Ordering::Greater, (-f64::MIN_POSITIVE).total_cmp(&-0.5)); + assert_eq!(Ordering::Greater, (-max_subnorm()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, (-min_subnorm()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Greater, (-0.0_f64).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Greater, 0.0_f64.total_cmp(&-0.0)); + assert_eq!(Ordering::Greater, min_subnorm().total_cmp(&0.0)); + assert_eq!(Ordering::Greater, max_subnorm().total_cmp(&min_subnorm())); + assert_eq!(Ordering::Greater, f64::MIN_POSITIVE.total_cmp(&max_subnorm())); + assert_eq!(Ordering::Greater, 0.5_f64.total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Greater, 1.0_f64.total_cmp(&0.5)); + assert_eq!(Ordering::Greater, 1.5_f64.total_cmp(&1.0)); + assert_eq!(Ordering::Greater, 2.5_f64.total_cmp(&1.5)); + assert_eq!(Ordering::Greater, f64::MAX.total_cmp(&2.5)); + assert_eq!(Ordering::Greater, f64::INFINITY.total_cmp(&f64::MAX)); + assert_eq!(Ordering::Greater, s_nan().total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Greater, q_nan().total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-s_nan())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-q_nan()).total_cmp(&s_nan())); + + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&-0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&min_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&max_subnorm())); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MIN_POSITIVE)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&0.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.0)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&1.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&2.5)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::MAX)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&f64::INFINITY)); + assert_eq!(Ordering::Less, (-s_nan()).total_cmp(&s_nan())); +} diff --git a/library/std/src/ffi/c_str.rs b/library/std/src/ffi/c_str.rs index 717967fb76..13021738af 100644 --- a/library/std/src/ffi/c_str.rs +++ b/library/std/src/ffi/c_str.rs @@ -1,4 +1,8 @@ #![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(test)] +mod tests; + use crate::ascii; use crate::borrow::{Borrow, Cow}; use crate::cmp::Ordering; @@ -877,13 +881,13 @@ impl From> for CString { unsafe { // Transmute `Vec` to `Vec`. let v: Vec = { - // Safety: + // SAFETY: // - transmuting between `NonZeroU8` and `u8` is sound; // - `alloc::Layout == alloc::Layout`. let (ptr, len, cap): (*mut NonZeroU8, _, _) = Vec::into_raw_parts(v); Vec::from_raw_parts(ptr.cast::(), len, cap) }; - // Safety: `v` cannot contain null bytes, given the type-level + // SAFETY: `v` cannot contain null bytes, given the type-level // invariant of `NonZeroU8`. CString::from_vec_unchecked(v) } @@ -1522,202 +1526,3 @@ impl AsRef for CString { self } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::borrow::Cow::{Borrowed, Owned}; - use crate::collections::hash_map::DefaultHasher; - use crate::hash::{Hash, Hasher}; - use crate::os::raw::c_char; - use crate::rc::Rc; - use crate::sync::Arc; - - #[test] - fn c_to_rust() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); - assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); - } - } - - #[test] - fn simple() { - let s = CString::new("1234").unwrap(); - assert_eq!(s.as_bytes(), b"1234"); - assert_eq!(s.as_bytes_with_nul(), b"1234\0"); - } - - #[test] - fn build_with_zero1() { - assert!(CString::new(&b"\0"[..]).is_err()); - } - #[test] - fn build_with_zero2() { - assert!(CString::new(vec![0]).is_err()); - } - - #[test] - fn build_with_zero3() { - unsafe { - let s = CString::from_vec_unchecked(vec![0]); - assert_eq!(s.as_bytes(), b"\0"); - } - } - - #[test] - fn formatted() { - let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); - assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); - } - - #[test] - fn borrowed() { - unsafe { - let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); - assert_eq!(s.to_bytes(), b"12"); - assert_eq!(s.to_bytes_with_nul(), b"12\0"); - } - } - - #[test] - fn to_str() { - let data = b"123\xE2\x80\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); - } - let data = b"123\xE2\0"; - let ptr = data.as_ptr() as *const c_char; - unsafe { - assert!(CStr::from_ptr(ptr).to_str().is_err()); - assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); - } - } - - #[test] - fn to_owned() { - let data = b"123\0"; - let ptr = data.as_ptr() as *const c_char; - - let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; - assert_eq!(owned.as_bytes_with_nul(), data); - } - - #[test] - fn equal_hash() { - let data = b"123\xE2\xFA\xA6\0"; - let ptr = data.as_ptr() as *const c_char; - let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; - - let mut s = DefaultHasher::new(); - cstr.hash(&mut s); - let cstr_hash = s.finish(); - let mut s = DefaultHasher::new(); - CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); - let cstring_hash = s.finish(); - - assert_eq!(cstr_hash, cstring_hash); - } - - #[test] - fn from_bytes_with_nul() { - let data = b"123\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); - let cstr = CStr::from_bytes_with_nul(data); - assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); - - unsafe { - let cstr = CStr::from_bytes_with_nul(data); - let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); - assert_eq!(cstr, Ok(cstr_unchecked)); - } - } - - #[test] - fn from_bytes_with_nul_unterminated() { - let data = b"123"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); - } - - #[test] - fn from_bytes_with_nul_interior() { - let data = b"1\023\0"; - let cstr = CStr::from_bytes_with_nul(data); - assert!(cstr.is_err()); - } - - #[test] - fn into_boxed() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let boxed: Box = Box::from(cstr); - let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); - assert_eq!(cstr, &*boxed); - assert_eq!(&*boxed, &*cstring); - assert_eq!(&*cstring, cstr); - } - - #[test] - fn boxed_default() { - let boxed = >::default(); - assert_eq!(boxed.to_bytes_with_nul(), &[0]); - } - - #[test] - fn test_c_str_clone_into() { - let mut c_string = CString::new("lorem").unwrap(); - let c_ptr = c_string.as_ptr(); - let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap(); - c_str.clone_into(&mut c_string); - assert_eq!(c_str, c_string.as_c_str()); - // The exact same size shouldn't have needed to move its allocation - assert_eq!(c_ptr, c_string.as_ptr()); - } - - #[test] - fn into_rc() { - let orig: &[u8] = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(orig).unwrap(); - let rc: Rc = Rc::from(cstr); - let arc: Arc = Arc::from(cstr); - - assert_eq!(&*rc, cstr); - assert_eq!(&*arc, cstr); - - let rc2: Rc = Rc::from(cstr.to_owned()); - let arc2: Arc = Arc::from(cstr.to_owned()); - - assert_eq!(&*rc2, cstr); - assert_eq!(&*arc2, cstr); - } - - #[test] - fn cstr_const_constructor() { - const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") }; - - assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); - } - - #[test] - fn cstr_index_from() { - let original = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(original).unwrap(); - let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); - - assert_eq!(&cstr[7..], result); - } - - #[test] - #[should_panic] - fn cstr_index_from_empty() { - let original = b"Hello, world!\0"; - let cstr = CStr::from_bytes_with_nul(original).unwrap(); - let _ = &cstr[original.len()..]; - } -} diff --git a/library/std/src/ffi/c_str/tests.rs b/library/std/src/ffi/c_str/tests.rs new file mode 100644 index 0000000000..4dff3df63a --- /dev/null +++ b/library/std/src/ffi/c_str/tests.rs @@ -0,0 +1,195 @@ +use super::*; +use crate::borrow::Cow::{Borrowed, Owned}; +use crate::collections::hash_map::DefaultHasher; +use crate::hash::{Hash, Hasher}; +use crate::os::raw::c_char; +use crate::rc::Rc; +use crate::sync::Arc; + +#[test] +fn c_to_rust() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_bytes(), b"123"); + assert_eq!(CStr::from_ptr(ptr).to_bytes_with_nul(), b"123\0"); + } +} + +#[test] +fn simple() { + let s = CString::new("1234").unwrap(); + assert_eq!(s.as_bytes(), b"1234"); + assert_eq!(s.as_bytes_with_nul(), b"1234\0"); +} + +#[test] +fn build_with_zero1() { + assert!(CString::new(&b"\0"[..]).is_err()); +} +#[test] +fn build_with_zero2() { + assert!(CString::new(vec![0]).is_err()); +} + +#[test] +fn build_with_zero3() { + unsafe { + let s = CString::from_vec_unchecked(vec![0]); + assert_eq!(s.as_bytes(), b"\0"); + } +} + +#[test] +fn formatted() { + let s = CString::new(&b"abc\x01\x02\n\xE2\x80\xA6\xFF"[..]).unwrap(); + assert_eq!(format!("{:?}", s), r#""abc\x01\x02\n\xe2\x80\xa6\xff""#); +} + +#[test] +fn borrowed() { + unsafe { + let s = CStr::from_ptr(b"12\0".as_ptr() as *const _); + assert_eq!(s.to_bytes(), b"12"); + assert_eq!(s.to_bytes_with_nul(), b"12\0"); + } +} + +#[test] +fn to_str() { + let data = b"123\xE2\x80\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert_eq!(CStr::from_ptr(ptr).to_str(), Ok("123…")); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Borrowed("123…")); + } + let data = b"123\xE2\0"; + let ptr = data.as_ptr() as *const c_char; + unsafe { + assert!(CStr::from_ptr(ptr).to_str().is_err()); + assert_eq!(CStr::from_ptr(ptr).to_string_lossy(), Owned::(format!("123\u{FFFD}"))); + } +} + +#[test] +fn to_owned() { + let data = b"123\0"; + let ptr = data.as_ptr() as *const c_char; + + let owned = unsafe { CStr::from_ptr(ptr).to_owned() }; + assert_eq!(owned.as_bytes_with_nul(), data); +} + +#[test] +fn equal_hash() { + let data = b"123\xE2\xFA\xA6\0"; + let ptr = data.as_ptr() as *const c_char; + let cstr: &'static CStr = unsafe { CStr::from_ptr(ptr) }; + + let mut s = DefaultHasher::new(); + cstr.hash(&mut s); + let cstr_hash = s.finish(); + let mut s = DefaultHasher::new(); + CString::new(&data[..data.len() - 1]).unwrap().hash(&mut s); + let cstring_hash = s.finish(); + + assert_eq!(cstr_hash, cstring_hash); +} + +#[test] +fn from_bytes_with_nul() { + let data = b"123\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes), Ok(&b"123"[..])); + let cstr = CStr::from_bytes_with_nul(data); + assert_eq!(cstr.map(CStr::to_bytes_with_nul), Ok(&b"123\0"[..])); + + unsafe { + let cstr = CStr::from_bytes_with_nul(data); + let cstr_unchecked = CStr::from_bytes_with_nul_unchecked(data); + assert_eq!(cstr, Ok(cstr_unchecked)); + } +} + +#[test] +fn from_bytes_with_nul_unterminated() { + let data = b"123"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); +} + +#[test] +fn from_bytes_with_nul_interior() { + let data = b"1\023\0"; + let cstr = CStr::from_bytes_with_nul(data); + assert!(cstr.is_err()); +} + +#[test] +fn into_boxed() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let boxed: Box = Box::from(cstr); + let cstring = cstr.to_owned().into_boxed_c_str().into_c_string(); + assert_eq!(cstr, &*boxed); + assert_eq!(&*boxed, &*cstring); + assert_eq!(&*cstring, cstr); +} + +#[test] +fn boxed_default() { + let boxed = >::default(); + assert_eq!(boxed.to_bytes_with_nul(), &[0]); +} + +#[test] +fn test_c_str_clone_into() { + let mut c_string = CString::new("lorem").unwrap(); + let c_ptr = c_string.as_ptr(); + let c_str = CStr::from_bytes_with_nul(b"ipsum\0").unwrap(); + c_str.clone_into(&mut c_string); + assert_eq!(c_str, c_string.as_c_str()); + // The exact same size shouldn't have needed to move its allocation + assert_eq!(c_ptr, c_string.as_ptr()); +} + +#[test] +fn into_rc() { + let orig: &[u8] = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(orig).unwrap(); + let rc: Rc = Rc::from(cstr); + let arc: Arc = Arc::from(cstr); + + assert_eq!(&*rc, cstr); + assert_eq!(&*arc, cstr); + + let rc2: Rc = Rc::from(cstr.to_owned()); + let arc2: Arc = Arc::from(cstr.to_owned()); + + assert_eq!(&*rc2, cstr); + assert_eq!(&*arc2, cstr); +} + +#[test] +fn cstr_const_constructor() { + const CSTR: &CStr = unsafe { CStr::from_bytes_with_nul_unchecked(b"Hello, world!\0") }; + + assert_eq!(CSTR.to_str().unwrap(), "Hello, world!"); +} + +#[test] +fn cstr_index_from() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let result = CStr::from_bytes_with_nul(&original[7..]).unwrap(); + + assert_eq!(&cstr[7..], result); +} + +#[test] +#[should_panic] +fn cstr_index_from_empty() { + let original = b"Hello, world!\0"; + let cstr = CStr::from_bytes_with_nul(original).unwrap(); + let _ = &cstr[original.len()..]; +} diff --git a/library/std/src/ffi/os_str.rs b/library/std/src/ffi/os_str.rs index 262d39d98e..2663f682a1 100644 --- a/library/std/src/ffi/os_str.rs +++ b/library/std/src/ffi/os_str.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::borrow::{Borrow, Cow}; use crate::cmp; use crate::fmt; @@ -91,7 +94,7 @@ pub struct OsString { // `OsStr::from_inner` current implementation relies // on `OsStr` being layout-compatible with `Slice`. // When attribute privacy is implemented, `OsStr` should be annotated as `#[repr(transparent)]`. -// Anyway, `OsStr` representation and layout are considered implementation detail, are +// Anyway, `OsStr` representation and layout are considered implementation details, are // not documented and must not be relied upon. pub struct OsStr { inner: Slice, @@ -507,14 +510,14 @@ impl OsStr { #[inline] fn from_inner(inner: &Slice) -> &OsStr { - // Safety: OsStr is just a wrapper of Slice, + // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &Slice to &OsStr is safe. unsafe { &*(inner as *const Slice as *const OsStr) } } #[inline] fn from_inner_mut(inner: &mut Slice) -> &mut OsStr { - // Safety: OsStr is just a wrapper of Slice, + // SAFETY: OsStr is just a wrapper of Slice, // therefore converting &mut Slice to &mut OsStr is safe. // Any method that mutates OsStr must be careful not to // break platform-specific encoding, in particular Wtf8 on Windows. @@ -1145,172 +1148,3 @@ impl FromStr for OsString { Ok(OsString::from(s)) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::sys_common::{AsInner, IntoInner}; - - use crate::rc::Rc; - use crate::sync::Arc; - - #[test] - fn test_os_string_with_capacity() { - let os_string = OsString::with_capacity(0); - assert_eq!(0, os_string.inner.into_inner().capacity()); - - let os_string = OsString::with_capacity(10); - assert_eq!(10, os_string.inner.into_inner().capacity()); - - let mut os_string = OsString::with_capacity(0); - os_string.push("abc"); - assert!(os_string.inner.into_inner().capacity() >= 3); - } - - #[test] - fn test_os_string_clear() { - let mut os_string = OsString::from("abc"); - assert_eq!(3, os_string.inner.as_inner().len()); - - os_string.clear(); - assert_eq!(&os_string, ""); - assert_eq!(0, os_string.inner.as_inner().len()); - } - - #[test] - fn test_os_string_capacity() { - let os_string = OsString::with_capacity(0); - assert_eq!(0, os_string.capacity()); - - let os_string = OsString::with_capacity(10); - assert_eq!(10, os_string.capacity()); - - let mut os_string = OsString::with_capacity(0); - os_string.push("abc"); - assert!(os_string.capacity() >= 3); - } - - #[test] - fn test_os_string_reserve() { - let mut os_string = OsString::new(); - assert_eq!(os_string.capacity(), 0); - - os_string.reserve(2); - assert!(os_string.capacity() >= 2); - - for _ in 0..16 { - os_string.push("a"); - } - - assert!(os_string.capacity() >= 16); - os_string.reserve(16); - assert!(os_string.capacity() >= 32); - - os_string.push("a"); - - os_string.reserve(16); - assert!(os_string.capacity() >= 33) - } - - #[test] - fn test_os_string_reserve_exact() { - let mut os_string = OsString::new(); - assert_eq!(os_string.capacity(), 0); - - os_string.reserve_exact(2); - assert!(os_string.capacity() >= 2); - - for _ in 0..16 { - os_string.push("a"); - } - - assert!(os_string.capacity() >= 16); - os_string.reserve_exact(16); - assert!(os_string.capacity() >= 32); - - os_string.push("a"); - - os_string.reserve_exact(16); - assert!(os_string.capacity() >= 33) - } - - #[test] - fn test_os_string_default() { - let os_string: OsString = Default::default(); - assert_eq!("", &os_string); - } - - #[test] - fn test_os_str_is_empty() { - let mut os_string = OsString::new(); - assert!(os_string.is_empty()); - - os_string.push("abc"); - assert!(!os_string.is_empty()); - - os_string.clear(); - assert!(os_string.is_empty()); - } - - #[test] - fn test_os_str_len() { - let mut os_string = OsString::new(); - assert_eq!(0, os_string.len()); - - os_string.push("abc"); - assert_eq!(3, os_string.len()); - - os_string.clear(); - assert_eq!(0, os_string.len()); - } - - #[test] - fn test_os_str_default() { - let os_str: &OsStr = Default::default(); - assert_eq!("", os_str); - } - - #[test] - fn into_boxed() { - let orig = "Hello, world!"; - let os_str = OsStr::new(orig); - let boxed: Box = Box::from(os_str); - let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); - assert_eq!(os_str, &*boxed); - assert_eq!(&*boxed, &*os_string); - assert_eq!(&*os_string, os_str); - } - - #[test] - fn boxed_default() { - let boxed = >::default(); - assert!(boxed.is_empty()); - } - - #[test] - fn test_os_str_clone_into() { - let mut os_string = OsString::with_capacity(123); - os_string.push("hello"); - let os_str = OsStr::new("bonjour"); - os_str.clone_into(&mut os_string); - assert_eq!(os_str, os_string); - assert!(os_string.capacity() >= 123); - } - - #[test] - fn into_rc() { - let orig = "Hello, world!"; - let os_str = OsStr::new(orig); - let rc: Rc = Rc::from(os_str); - let arc: Arc = Arc::from(os_str); - - assert_eq!(&*rc, os_str); - assert_eq!(&*arc, os_str); - - let rc2: Rc = Rc::from(os_str.to_owned()); - let arc2: Arc = Arc::from(os_str.to_owned()); - - assert_eq!(&*rc2, os_str); - assert_eq!(&*arc2, os_str); - } -} diff --git a/library/std/src/ffi/os_str/tests.rs b/library/std/src/ffi/os_str/tests.rs new file mode 100644 index 0000000000..283f2b577e --- /dev/null +++ b/library/std/src/ffi/os_str/tests.rs @@ -0,0 +1,165 @@ +use super::*; +use crate::sys_common::{AsInner, IntoInner}; + +use crate::rc::Rc; +use crate::sync::Arc; + +#[test] +fn test_os_string_with_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.inner.into_inner().capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.inner.into_inner().capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.inner.into_inner().capacity() >= 3); +} + +#[test] +fn test_os_string_clear() { + let mut os_string = OsString::from("abc"); + assert_eq!(3, os_string.inner.as_inner().len()); + + os_string.clear(); + assert_eq!(&os_string, ""); + assert_eq!(0, os_string.inner.as_inner().len()); +} + +#[test] +fn test_os_string_capacity() { + let os_string = OsString::with_capacity(0); + assert_eq!(0, os_string.capacity()); + + let os_string = OsString::with_capacity(10); + assert_eq!(10, os_string.capacity()); + + let mut os_string = OsString::with_capacity(0); + os_string.push("abc"); + assert!(os_string.capacity() >= 3); +} + +#[test] +fn test_os_string_reserve() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve(16); + assert!(os_string.capacity() >= 33) +} + +#[test] +fn test_os_string_reserve_exact() { + let mut os_string = OsString::new(); + assert_eq!(os_string.capacity(), 0); + + os_string.reserve_exact(2); + assert!(os_string.capacity() >= 2); + + for _ in 0..16 { + os_string.push("a"); + } + + assert!(os_string.capacity() >= 16); + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 32); + + os_string.push("a"); + + os_string.reserve_exact(16); + assert!(os_string.capacity() >= 33) +} + +#[test] +fn test_os_string_default() { + let os_string: OsString = Default::default(); + assert_eq!("", &os_string); +} + +#[test] +fn test_os_str_is_empty() { + let mut os_string = OsString::new(); + assert!(os_string.is_empty()); + + os_string.push("abc"); + assert!(!os_string.is_empty()); + + os_string.clear(); + assert!(os_string.is_empty()); +} + +#[test] +fn test_os_str_len() { + let mut os_string = OsString::new(); + assert_eq!(0, os_string.len()); + + os_string.push("abc"); + assert_eq!(3, os_string.len()); + + os_string.clear(); + assert_eq!(0, os_string.len()); +} + +#[test] +fn test_os_str_default() { + let os_str: &OsStr = Default::default(); + assert_eq!("", os_str); +} + +#[test] +fn into_boxed() { + let orig = "Hello, world!"; + let os_str = OsStr::new(orig); + let boxed: Box = Box::from(os_str); + let os_string = os_str.to_owned().into_boxed_os_str().into_os_string(); + assert_eq!(os_str, &*boxed); + assert_eq!(&*boxed, &*os_string); + assert_eq!(&*os_string, os_str); +} + +#[test] +fn boxed_default() { + let boxed = >::default(); + assert!(boxed.is_empty()); +} + +#[test] +fn test_os_str_clone_into() { + let mut os_string = OsString::with_capacity(123); + os_string.push("hello"); + let os_str = OsStr::new("bonjour"); + os_str.clone_into(&mut os_string); + assert_eq!(os_str, os_string); + assert!(os_string.capacity() >= 123); +} + +#[test] +fn into_rc() { + let orig = "Hello, world!"; + let os_str = OsStr::new(orig); + let rc: Rc = Rc::from(os_str); + let arc: Arc = Arc::from(os_str); + + assert_eq!(&*rc, os_str); + assert_eq!(&*arc, os_str); + + let rc2: Rc = Rc::from(os_str.to_owned()); + let arc2: Arc = Arc::from(os_str.to_owned()); + + assert_eq!(&*rc2, os_str); + assert_eq!(&*arc2, os_str); +} diff --git a/library/std/src/fs.rs b/library/std/src/fs.rs index b1630f8f54..161bfe3795 100644 --- a/library/std/src/fs.rs +++ b/library/std/src/fs.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Filesystem manipulation operations. //! //! This module contains basic methods to manipulate the contents of the local @@ -10,6 +8,9 @@ #![stable(feature = "rust1", since = "1.0.0")] #![deny(unsafe_op_in_unsafe_fn)] +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +mod tests; + use crate::ffi::OsString; use crate::fmt; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read, Seek, SeekFrom, Write}; @@ -552,7 +553,7 @@ impl File { /// the `SetFileInformationByHandle` function on Windows. Note that, this /// [may change in the future][changes]. /// - /// [changes]: ../io/index.html#platform-specific-behavior + /// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1502,7 +1503,7 @@ impl AsInner for DirEntry { /// and the `DeleteFile` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1540,7 +1541,7 @@ pub fn remove_file>(path: P) -> io::Result<()> { /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1574,7 +1575,7 @@ pub fn metadata>(path: P) -> io::Result { /// and the `GetFileAttributesEx` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1617,7 +1618,7 @@ pub fn symlink_metadata>(path: P) -> io::Result { /// /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1668,7 +1669,7 @@ pub fn rename, Q: AsRef>(from: P, to: Q) -> io::Result<()> /// `fcopyfile`. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1706,7 +1707,7 @@ pub fn copy, Q: AsRef>(from: P, to: Q) -> io::Result { /// and the `CreateHardLink` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1771,7 +1772,7 @@ pub fn soft_link, Q: AsRef>(src: P, dst: Q) -> io::Result<( /// `FILE_FLAG_BACKUP_SEMANTICS` flags on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1811,7 +1812,7 @@ pub fn read_link>(path: P) -> io::Result { /// with other applications (if passed to the application on the command-line, /// or written to a file another application may read). /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// [path]: https://docs.microsoft.com/en-us/windows/win32/fileio/naming-a-file /// /// # Errors @@ -1845,7 +1846,7 @@ pub fn canonicalize>(path: P) -> io::Result { /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// **NOTE**: If a parent of the given path doesn't exist, this function will /// return an error. To create a directory and all its missing parents at the @@ -1886,7 +1887,7 @@ pub fn create_dir>(path: P) -> io::Result<()> { /// and the `CreateDirectory` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1929,7 +1930,7 @@ pub fn create_dir_all>(path: P) -> io::Result<()> { /// and the `RemoveDirectory` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -1969,7 +1970,7 @@ pub fn remove_dir>(path: P) -> io::Result<()> { /// on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -2005,7 +2006,7 @@ pub fn remove_dir_all>(path: P) -> io::Result<()> { /// currently corresponds to `readdir` on Unix and `FindNextFile` on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// The order in which this iterator returns entries is platform and filesystem /// dependent. @@ -2074,7 +2075,7 @@ pub fn read_dir>(path: P) -> io::Result { /// and the `SetFileAttributes` function on Windows. /// Note that, this [may change in the future][changes]. /// -/// [changes]: ../io/index.html#platform-specific-behavior +/// [changes]: io#platform-specific-behavior /// /// # Errors /// @@ -2194,1349 +2195,3 @@ impl AsInnerMut for DirBuilder { &mut self.inner } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] -mod tests { - use crate::io::prelude::*; - - use crate::fs::{self, File, OpenOptions}; - use crate::io::{ErrorKind, SeekFrom}; - use crate::path::Path; - use crate::str; - use crate::sys_common::io::test::{tmpdir, TempDir}; - use crate::thread; - - use rand::{rngs::StdRng, RngCore, SeedableRng}; - - #[cfg(unix)] - use crate::os::unix::fs::symlink as symlink_dir; - #[cfg(unix)] - use crate::os::unix::fs::symlink as symlink_file; - #[cfg(unix)] - use crate::os::unix::fs::symlink as symlink_junction; - #[cfg(windows)] - use crate::os::windows::fs::{symlink_dir, symlink_file}; - #[cfg(windows)] - use crate::sys::fs::symlink_junction; - - macro_rules! check { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("{} failed with: {}", stringify!($e), e), - } - }; - } - - #[cfg(windows)] - macro_rules! error { - ($e:expr, $s:expr) => { - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!( - err.raw_os_error() == Some($s), - format!("`{}` did not have a code of `{}`", err, $s) - ), - } - }; - } - - #[cfg(unix)] - macro_rules! error { - ($e:expr, $s:expr) => { - error_contains!($e, $s) - }; - } - - macro_rules! error_contains { - ($e:expr, $s:expr) => { - match $e { - Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), - Err(ref err) => assert!( - err.to_string().contains($s), - format!("`{}` did not contain `{}`", err, $s) - ), - } - }; - } - - // Several test fail on windows if the user does not have permission to - // create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of - // disabling these test on Windows, use this function to test whether we - // have permission, and return otherwise. This way, we still don't run these - // tests most of the time, but at least we do if the user has the right - // permissions. - pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { - if cfg!(unix) { - return true; - } - let link = tmpdir.join("some_hopefully_unique_link_name"); - - match symlink_file(r"nonexisting_target", link) { - Ok(_) => true, - // ERROR_PRIVILEGE_NOT_HELD = 1314 - Err(ref err) if err.raw_os_error() == Some(1314) => false, - Err(_) => true, - } - } - - #[test] - fn file_test_io_smoke_test() { - let message = "it's alright. have a good time"; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test.txt"); - { - let mut write_stream = check!(File::create(filename)); - check!(write_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - let mut read_buf = [0; 1028]; - let read_str = match check!(read_stream.read(&mut read_buf)) { - 0 => panic!("shouldn't happen"), - n => str::from_utf8(&read_buf[..n]).unwrap().to_string(), - }; - assert_eq!(read_str, message); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn invalid_path_raises() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_that_does_not_exist.txt"); - let result = File::open(filename); - - #[cfg(all(unix, not(target_os = "vxworks")))] - error!(result, "No such file or directory"); - #[cfg(target_os = "vxworks")] - error!(result, "no such file or directory"); - #[cfg(windows)] - error!(result, 2); // ERROR_FILE_NOT_FOUND - } - - #[test] - fn file_test_iounlinking_invalid_path_should_raise_condition() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); - - let result = fs::remove_file(filename); - - #[cfg(all(unix, not(target_os = "vxworks")))] - error!(result, "No such file or directory"); - #[cfg(target_os = "vxworks")] - error!(result, "no such file or directory"); - #[cfg(windows)] - error!(result, 2); // ERROR_FILE_NOT_FOUND - } - - #[test] - fn file_test_io_non_positional_read() { - let message: &str = "ten-four"; - let mut read_mem = [0; 8]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - { - let read_buf = &mut read_mem[0..4]; - check!(read_stream.read(read_buf)); - } - { - let read_buf = &mut read_mem[4..8]; - check!(read_stream.read(read_buf)); - } - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, message); - } - - #[test] - fn file_test_io_seek_and_tell_smoke_test() { - let message = "ten-four"; - let mut read_mem = [0; 4]; - let set_cursor = 4 as u64; - let tell_pos_pre_read; - let tell_pos_post_read; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(message.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.seek(SeekFrom::Start(set_cursor))); - tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); - check!(read_stream.read(&mut read_mem)); - tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert_eq!(read_str, &message[4..8]); - assert_eq!(tell_pos_pre_read, set_cursor); - assert_eq!(tell_pos_post_read, message.len() as u64); - } - - #[test] - fn file_test_io_seek_and_write() { - let initial_msg = "food-is-yummy"; - let overwrite_msg = "-the-bar!!"; - let final_msg = "foo-the-bar!!"; - let seek_idx = 3; - let mut read_mem = [0; 13]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - check!(rw_stream.seek(SeekFrom::Start(seek_idx))); - check!(rw_stream.write(overwrite_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - check!(read_stream.read(&mut read_mem)); - } - check!(fs::remove_file(filename)); - let read_str = str::from_utf8(&read_mem).unwrap(); - assert!(read_str == final_msg); - } - - #[test] - fn file_test_io_seek_shakedown() { - // 01234567890123 - let initial_msg = "qwer-asdf-zxcv"; - let chunk_one: &str = "qwer"; - let chunk_two: &str = "asdf"; - let chunk_three: &str = "zxcv"; - let mut read_mem = [0; 4]; - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); - { - let mut rw_stream = check!(File::create(filename)); - check!(rw_stream.write(initial_msg.as_bytes())); - } - { - let mut read_stream = check!(File::open(filename)); - - check!(read_stream.seek(SeekFrom::End(-4))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); - - check!(read_stream.seek(SeekFrom::Current(-9))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); - - check!(read_stream.seek(SeekFrom::Start(0))); - check!(read_stream.read(&mut read_mem)); - assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); - } - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_io_eof() { - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_eof.txt"); - let mut buf = [0; 256]; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.read(&mut buf)), 0); - assert_eq!(check!(rw.read(&mut buf)), 0); - } - check!(fs::remove_file(&filename)); - } - - #[test] - #[cfg(unix)] - fn file_test_io_read_write_at() { - use crate::os::unix::fs::FileExt; - - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt"); - let mut buf = [0; 256]; - let write1 = "asdf"; - let write2 = "qwer-"; - let write3 = "-zxcv"; - let content = "qwer-asdf-zxcv"; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0")); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.read(&mut buf)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - } - { - let mut read = check!(File::open(&filename)); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(read.read(&mut buf)), write3.len()); - assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.read_at(&mut buf, 14)), 0); - assert_eq!(check!(read.read_at(&mut buf, 15)), 0); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - } - check!(fs::remove_file(&filename)); - } - - #[test] - #[cfg(unix)] - fn set_get_unix_permissions() { - use crate::os::unix::fs::PermissionsExt; - - let tmpdir = tmpdir(); - let filename = &tmpdir.join("set_get_unix_permissions"); - check!(fs::create_dir(filename)); - let mask = 0o7777; - - check!(fs::set_permissions(filename, fs::Permissions::from_mode(0))); - let metadata0 = check!(fs::metadata(filename)); - assert_eq!(mask & metadata0.permissions().mode(), 0); - - check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777))); - let metadata1 = check!(fs::metadata(filename)); - #[cfg(all(unix, not(target_os = "vxworks")))] - assert_eq!(mask & metadata1.permissions().mode(), 0o1777); - #[cfg(target_os = "vxworks")] - assert_eq!(mask & metadata1.permissions().mode(), 0o0777); - } - - #[test] - #[cfg(windows)] - fn file_test_io_seek_read_write() { - use crate::os::windows::fs::FileExt; - - let tmpdir = tmpdir(); - let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt"); - let mut buf = [0; 256]; - let write1 = "asdf"; - let write2 = "qwer-"; - let write3 = "-zxcv"; - let content = "qwer-asdf-zxcv"; - { - let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); - let mut rw = check!(oo.open(&filename)); - assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); - assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.read(&mut buf)), write1.len()); - assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); - assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len()); - assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); - assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len()); - assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14); - } - { - let mut read = check!(File::open(&filename)); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); - assert_eq!(check!(read.read(&mut buf)), write3.len()); - assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); - assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); - assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); - assert_eq!(check!(read.seek_read(&mut buf, 14)), 0); - assert_eq!(check!(read.seek_read(&mut buf, 15)), 0); - } - check!(fs::remove_file(&filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_file() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); - { - let mut opts = OpenOptions::new(); - let mut fs = check!(opts.read(true).write(true).create(true).open(filename)); - let msg = "hw"; - fs.write(msg.as_bytes()).unwrap(); - - let fstat_res = check!(fs.metadata()); - assert!(fstat_res.is_file()); - } - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_file()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_file()); - check!(fs::remove_file(filename)); - } - - #[test] - fn file_test_stat_is_correct_on_is_dir() { - let tmpdir = tmpdir(); - let filename = &tmpdir.join("file_stat_correct_on_is_dir"); - check!(fs::create_dir(filename)); - let stat_res_fn = check!(fs::metadata(filename)); - assert!(stat_res_fn.is_dir()); - let stat_res_meth = check!(filename.metadata()); - assert!(stat_res_meth.is_dir()); - check!(fs::remove_dir(filename)); - } - - #[test] - fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("fileinfo_false_on_dir"); - check!(fs::create_dir(dir)); - assert!(!dir.is_file()); - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_test_fileinfo_check_exists_before_and_after_file_creation() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); - check!(check!(File::create(file)).write(b"foo")); - assert!(file.exists()); - check!(fs::remove_file(file)); - assert!(!file.exists()); - } - - #[test] - fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("before_and_after_dir"); - assert!(!dir.exists()); - check!(fs::create_dir(dir)); - assert!(dir.exists()); - assert!(dir.is_dir()); - check!(fs::remove_dir(dir)); - assert!(!dir.exists()); - } - - #[test] - fn file_test_directoryinfo_readdir() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("di_readdir"); - check!(fs::create_dir(dir)); - let prefix = "foo"; - for n in 0..3 { - let f = dir.join(&format!("{}.txt", n)); - let mut w = check!(File::create(&f)); - let msg_str = format!("{}{}", prefix, n.to_string()); - let msg = msg_str.as_bytes(); - check!(w.write(msg)); - } - let files = check!(fs::read_dir(dir)); - let mut mem = [0; 4]; - for f in files { - let f = f.unwrap().path(); - { - let n = f.file_stem().unwrap(); - check!(check!(File::open(&f)).read(&mut mem)); - let read_str = str::from_utf8(&mem).unwrap(); - let expected = format!("{}{}", prefix, n.to_str().unwrap()); - assert_eq!(expected, read_str); - } - check!(fs::remove_file(&f)); - } - check!(fs::remove_dir(dir)); - } - - #[test] - fn file_create_new_already_exists_error() { - let tmpdir = tmpdir(); - let file = &tmpdir.join("file_create_new_error_exists"); - check!(fs::File::create(file)); - let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err(); - assert_eq!(e.kind(), ErrorKind::AlreadyExists); - } - - #[test] - fn mkdir_path_already_exists_error() { - let tmpdir = tmpdir(); - let dir = &tmpdir.join("mkdir_error_twice"); - check!(fs::create_dir(dir)); - let e = fs::create_dir(dir).unwrap_err(); - assert_eq!(e.kind(), ErrorKind::AlreadyExists); - } - - #[test] - fn recursive_mkdir() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1/d2"); - check!(fs::create_dir_all(&dir)); - assert!(dir.is_dir()) - } - - #[test] - fn recursive_mkdir_failure() { - let tmpdir = tmpdir(); - let dir = tmpdir.join("d1"); - let file = dir.join("f1"); - - check!(fs::create_dir_all(&dir)); - check!(File::create(&file)); - - let result = fs::create_dir_all(&file); - - assert!(result.is_err()); - } - - #[test] - fn concurrent_recursive_mkdir() { - for _ in 0..100 { - let dir = tmpdir(); - let mut dir = dir.join("a"); - for _ in 0..40 { - dir = dir.join("a"); - } - let mut join = vec![]; - for _ in 0..8 { - let dir = dir.clone(); - join.push(thread::spawn(move || { - check!(fs::create_dir_all(&dir)); - })) - } - - // No `Display` on result of `join()` - join.drain(..).map(|join| join.join().unwrap()).count(); - } - } - - #[test] - fn recursive_mkdir_slash() { - check!(fs::create_dir_all(Path::new("/"))); - } - - #[test] - fn recursive_mkdir_dot() { - check!(fs::create_dir_all(Path::new("."))); - } - - #[test] - fn recursive_mkdir_empty() { - check!(fs::create_dir_all(Path::new(""))); - } - - #[test] - fn recursive_rmdir() { - let tmpdir = tmpdir(); - let d1 = tmpdir.join("d1"); - let dt = d1.join("t"); - let dtt = dt.join("t"); - let d2 = tmpdir.join("d2"); - let canary = d2.join("do_not_delete"); - check!(fs::create_dir_all(&dtt)); - check!(fs::create_dir_all(&d2)); - check!(check!(File::create(&canary)).write(b"foo")); - check!(symlink_junction(&d2, &dt.join("d2"))); - let _ = symlink_file(&canary, &d1.join("canary")); - check!(fs::remove_dir_all(&d1)); - - assert!(!d1.is_dir()); - assert!(canary.exists()); - } - - #[test] - fn recursive_rmdir_of_symlink() { - // test we do not recursively delete a symlink but only dirs. - let tmpdir = tmpdir(); - let link = tmpdir.join("d1"); - let dir = tmpdir.join("d2"); - let canary = dir.join("do_not_delete"); - check!(fs::create_dir_all(&dir)); - check!(check!(File::create(&canary)).write(b"foo")); - check!(symlink_junction(&dir, &link)); - check!(fs::remove_dir_all(&link)); - - assert!(!link.is_dir()); - assert!(canary.exists()); - } - - #[test] - // only Windows makes a distinction between file and directory symlinks. - #[cfg(windows)] - fn recursive_rmdir_of_file_symlink() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let f1 = tmpdir.join("f1"); - let f2 = tmpdir.join("f2"); - check!(check!(File::create(&f1)).write(b"foo")); - check!(symlink_file(&f1, &f2)); - match fs::remove_dir_all(&f2) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn unicode_path_is_dir() { - assert!(Path::new(".").is_dir()); - assert!(!Path::new("test/stdtest/fs.rs").is_dir()); - - let tmpdir = tmpdir(); - - let mut dirpath = tmpdir.path().to_path_buf(); - dirpath.push("test-가一ー你好"); - check!(fs::create_dir(&dirpath)); - assert!(dirpath.is_dir()); - - let mut filepath = dirpath; - filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); - check!(File::create(&filepath)); // ignore return; touch only - assert!(!filepath.is_dir()); - assert!(filepath.exists()); - } - - #[test] - fn unicode_path_exists() { - assert!(Path::new(".").exists()); - assert!(!Path::new("test/nonexistent-bogus-path").exists()); - - let tmpdir = tmpdir(); - let unicode = tmpdir.path(); - let unicode = unicode.join("test-각丁ー再见"); - check!(fs::create_dir(&unicode)); - assert!(unicode.exists()); - assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); - } - - #[test] - fn copy_file_does_not_exist() { - let from = Path::new("test/nonexistent-bogus-path"); - let to = Path::new("test/other-bogus-path"); - - match fs::copy(&from, &to) { - Ok(..) => panic!(), - Err(..) => { - assert!(!from.exists()); - assert!(!to.exists()); - } - } - } - - #[test] - fn copy_src_does_not_exist() { - let tmpdir = tmpdir(); - let from = Path::new("test/nonexistent-bogus-path"); - let to = tmpdir.join("out.txt"); - check!(check!(File::create(&to)).write(b"hello")); - assert!(fs::copy(&from, &to).is_err()); - assert!(!from.exists()); - let mut v = Vec::new(); - check!(check!(File::open(&to)).read_to_end(&mut v)); - assert_eq!(v, b"hello"); - } - - #[test] - fn copy_file_ok() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write(b"hello")); - check!(fs::copy(&input, &out)); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"hello"); - - assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions()); - } - - #[test] - fn copy_file_dst_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - check!(File::create(&out)); - match fs::copy(&*out, tmpdir.path()) { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - fn copy_file_dst_exists() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in"); - let output = tmpdir.join("out"); - - check!(check!(File::create(&input)).write("foo".as_bytes())); - check!(check!(File::create(&output)).write("bar".as_bytes())); - check!(fs::copy(&input, &output)); - - let mut v = Vec::new(); - check!(check!(File::open(&output)).read_to_end(&mut v)); - assert_eq!(v, b"foo".to_vec()); - } - - #[test] - fn copy_file_src_dir() { - let tmpdir = tmpdir(); - let out = tmpdir.join("out"); - - match fs::copy(tmpdir.path(), &out) { - Ok(..) => panic!(), - Err(..) => {} - } - assert!(!out.exists()); - } - - #[test] - fn copy_file_preserves_perm_bits() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - let attr = check!(check!(File::create(&input)).metadata()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&input, p)); - check!(fs::copy(&input, &out)); - assert!(check!(out.metadata()).permissions().readonly()); - check!(fs::set_permissions(&input, attr.permissions())); - check!(fs::set_permissions(&out, attr.permissions())); - } - - #[test] - #[cfg(windows)] - fn copy_file_preserves_streams() { - let tmp = tmpdir(); - check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); - assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0); - assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0); - let mut v = Vec::new(); - check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v)); - assert_eq!(v, b"carrot".to_vec()); - } - - #[test] - fn copy_file_returns_metadata_len() { - let tmp = tmpdir(); - let in_path = tmp.join("in.txt"); - let out_path = tmp.join("out.txt"); - check!(check!(File::create(&in_path)).write(b"lettuce")); - #[cfg(windows)] - check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot")); - let copied_len = check!(fs::copy(&in_path, &out_path)); - assert_eq!(check!(out_path.metadata()).len(), copied_len); - } - - #[test] - fn copy_file_follows_dst_symlink() { - let tmp = tmpdir(); - if !got_symlink_permission(&tmp) { - return; - }; - - let in_path = tmp.join("in.txt"); - let out_path = tmp.join("out.txt"); - let out_path_symlink = tmp.join("out_symlink.txt"); - - check!(fs::write(&in_path, "foo")); - check!(fs::write(&out_path, "bar")); - check!(symlink_file(&out_path, &out_path_symlink)); - - check!(fs::copy(&in_path, &out_path_symlink)); - - assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink()); - assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec()); - assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec()); - } - - #[test] - fn symlinks_work() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(symlink_file(&input, &out)); - assert!(check!(out.symlink_metadata()).file_type().is_symlink()); - assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - } - - #[test] - fn symlink_noexist() { - // Symlinks can point to things that don't exist - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - // Use a relative path for testing. Symlinks get normalized by Windows, - // so we may not get the same path back for absolute paths - check!(symlink_file(&"foo", &tmpdir.join("bar"))); - assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo"); - } - - #[test] - fn read_link() { - if cfg!(windows) { - // directory symlink - assert_eq!( - check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(), - r"C:\ProgramData" - ); - // junction - assert_eq!( - check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(), - r"C:\Users\Default" - ); - // junction with special permissions - assert_eq!( - check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(), - r"C:\Users" - ); - } - let tmpdir = tmpdir(); - let link = tmpdir.join("link"); - if !got_symlink_permission(&tmpdir) { - return; - }; - check!(symlink_file(&"foo", &link)); - assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo"); - } - - #[test] - fn readlink_not_symlink() { - let tmpdir = tmpdir(); - match fs::read_link(tmpdir.path()) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn links_work() { - let tmpdir = tmpdir(); - let input = tmpdir.join("in.txt"); - let out = tmpdir.join("out.txt"); - - check!(check!(File::create(&input)).write("foobar".as_bytes())); - check!(fs::hard_link(&input, &out)); - assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); - assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len()); - let mut v = Vec::new(); - check!(check!(File::open(&out)).read_to_end(&mut v)); - assert_eq!(v, b"foobar".to_vec()); - - // can't link to yourself - match fs::hard_link(&input, &input) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - // can't link to something that doesn't exist - match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) { - Ok(..) => panic!("wanted a failure"), - Err(..) => {} - } - } - - #[test] - fn chmod_works() { - let tmpdir = tmpdir(); - let file = tmpdir.join("in.txt"); - - check!(File::create(&file)); - let attr = check!(fs::metadata(&file)); - assert!(!attr.permissions().readonly()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(fs::set_permissions(&file, p.clone())); - let attr = check!(fs::metadata(&file)); - assert!(attr.permissions().readonly()); - - match fs::set_permissions(&tmpdir.join("foo"), p.clone()) { - Ok(..) => panic!("wanted an error"), - Err(..) => {} - } - - p.set_readonly(false); - check!(fs::set_permissions(&file, p)); - } - - #[test] - fn fchmod_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let file = check!(File::create(&path)); - let attr = check!(fs::metadata(&path)); - assert!(!attr.permissions().readonly()); - let mut p = attr.permissions(); - p.set_readonly(true); - check!(file.set_permissions(p.clone())); - let attr = check!(fs::metadata(&path)); - assert!(attr.permissions().readonly()); - - p.set_readonly(false); - check!(file.set_permissions(p)); - } - - #[test] - fn sync_doesnt_kill_anything() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.sync_all()); - check!(file.sync_data()); - check!(file.write(b"foo")); - check!(file.sync_all()); - check!(file.sync_data()); - } - - #[test] - fn truncate_works() { - let tmpdir = tmpdir(); - let path = tmpdir.join("in.txt"); - - let mut file = check!(File::create(&path)); - check!(file.write(b"foo")); - check!(file.sync_all()); - - // Do some simple things with truncation - assert_eq!(check!(file.metadata()).len(), 3); - check!(file.set_len(10)); - assert_eq!(check!(file.metadata()).len(), 10); - check!(file.write(b"bar")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 10); - - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"foobar\0\0\0\0".to_vec()); - - // Truncate to a smaller length, don't seek, and then write something. - // Ensure that the intermediate zeroes are all filled in (we have `seek`ed - // past the end of the file). - check!(file.set_len(2)); - assert_eq!(check!(file.metadata()).len(), 2); - check!(file.write(b"wut")); - check!(file.sync_all()); - assert_eq!(check!(file.metadata()).len(), 9); - let mut v = Vec::new(); - check!(check!(File::open(&path)).read_to_end(&mut v)); - assert_eq!(v, b"fo\0\0\0\0wut".to_vec()); - } - - #[test] - fn open_flavors() { - use crate::fs::OpenOptions as OO; - fn c(t: &T) -> T { - t.clone() - } - - let tmpdir = tmpdir(); - - let mut r = OO::new(); - r.read(true); - let mut w = OO::new(); - w.write(true); - let mut rw = OO::new(); - rw.read(true).write(true); - let mut a = OO::new(); - a.append(true); - let mut ra = OO::new(); - ra.read(true).append(true); - - #[cfg(windows)] - let invalid_options = 87; // ERROR_INVALID_PARAMETER - #[cfg(all(unix, not(target_os = "vxworks")))] - let invalid_options = "Invalid argument"; - #[cfg(target_os = "vxworks")] - let invalid_options = "invalid argument"; - - // Test various combinations of creation modes and access modes. - // - // Allowed: - // creation mode | read | write | read-write | append | read-append | - // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:| - // not set (open existing) | X | X | X | X | X | - // create | | X | X | X | X | - // truncate | | X | X | | | - // create and truncate | | X | X | | | - // create_new | | X | X | X | X | - // - // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it. - - // write-only - check!(c(&w).create_new(true).open(&tmpdir.join("a"))); - check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a"))); - check!(c(&w).truncate(true).open(&tmpdir.join("a"))); - check!(c(&w).create(true).open(&tmpdir.join("a"))); - check!(c(&w).open(&tmpdir.join("a"))); - - // read-only - error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options); - error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options); - check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only - - // read-write - check!(c(&rw).create_new(true).open(&tmpdir.join("c"))); - check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c"))); - check!(c(&rw).truncate(true).open(&tmpdir.join("c"))); - check!(c(&rw).create(true).open(&tmpdir.join("c"))); - check!(c(&rw).open(&tmpdir.join("c"))); - - // append - check!(c(&a).create_new(true).open(&tmpdir.join("d"))); - error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options); - error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options); - check!(c(&a).create(true).open(&tmpdir.join("d"))); - check!(c(&a).open(&tmpdir.join("d"))); - - // read-append - check!(c(&ra).create_new(true).open(&tmpdir.join("e"))); - error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options); - error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options); - check!(c(&ra).create(true).open(&tmpdir.join("e"))); - check!(c(&ra).open(&tmpdir.join("e"))); - - // Test opening a file without setting an access mode - let mut blank = OO::new(); - error!(blank.create(true).open(&tmpdir.join("f")), invalid_options); - - // Test write works - check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes())); - - // Test write fails for read-only - check!(r.open(&tmpdir.join("h"))); - { - let mut f = check!(r.open(&tmpdir.join("h"))); - assert!(f.write("wut".as_bytes()).is_err()); - } - - // Test write overwrites - { - let mut f = check!(c(&w).open(&tmpdir.join("h"))); - check!(f.write("baz".as_bytes())); - } - { - let mut f = check!(c(&r).open(&tmpdir.join("h"))); - let mut b = vec![0; 6]; - check!(f.read(&mut b)); - assert_eq!(b, "bazbar".as_bytes()); - } - - // Test truncate works - { - let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h"))); - check!(f.write("foo".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - - // Test append works - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); - { - let mut f = check!(c(&a).open(&tmpdir.join("h"))); - check!(f.write("bar".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6); - - // Test .append(true) equals .write(true).append(true) - { - let mut f = check!(c(&w).append(true).open(&tmpdir.join("h"))); - check!(f.write("baz".as_bytes())); - } - assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9); - } - - #[test] - fn _assert_send_sync() { - fn _assert_send_sync() {} - _assert_send_sync::(); - } - - #[test] - fn binary_file() { - let mut bytes = [0; 1024]; - StdRng::from_entropy().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(check!(File::create(&tmpdir.join("test"))).write(&bytes)); - let mut v = Vec::new(); - check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v)); - assert!(v == &bytes[..]); - } - - #[test] - fn write_then_read() { - let mut bytes = [0; 1024]; - StdRng::from_entropy().fill_bytes(&mut bytes); - - let tmpdir = tmpdir(); - - check!(fs::write(&tmpdir.join("test"), &bytes[..])); - let v = check!(fs::read(&tmpdir.join("test"))); - assert!(v == &bytes[..]); - - check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF])); - error_contains!( - fs::read_to_string(&tmpdir.join("not-utf8")), - "stream did not contain valid UTF-8" - ); - - let s = "𐁁𐀓𐀠𐀴𐀍"; - check!(fs::write(&tmpdir.join("utf8"), s.as_bytes())); - let string = check!(fs::read_to_string(&tmpdir.join("utf8"))); - assert_eq!(string, s); - } - - #[test] - fn file_try_clone() { - let tmpdir = tmpdir(); - - let mut f1 = check!( - OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test")) - ); - let mut f2 = check!(f1.try_clone()); - - check!(f1.write_all(b"hello world")); - check!(f1.seek(SeekFrom::Start(2))); - - let mut buf = vec![]; - check!(f2.read_to_end(&mut buf)); - assert_eq!(buf, b"llo world"); - drop(f2); - - check!(f1.write_all(b"!")); - } - - #[test] - #[cfg(not(windows))] - fn unlink_readonly() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(File::create(&path)); - let mut perm = check!(fs::metadata(&path)).permissions(); - perm.set_readonly(true); - check!(fs::set_permissions(&path, perm)); - check!(fs::remove_file(&path)); - } - - #[test] - fn mkdir_trailing_slash() { - let tmpdir = tmpdir(); - let path = tmpdir.join("file"); - check!(fs::create_dir_all(&path.join("a/"))); - } - - #[test] - fn canonicalize_works_simple() { - let tmpdir = tmpdir(); - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let file = tmpdir.join("test"); - File::create(&file).unwrap(); - assert_eq!(fs::canonicalize(&file).unwrap(), file); - } - - #[test] - fn realpath_works() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let file = tmpdir.join("test"); - let dir = tmpdir.join("test2"); - let link = dir.join("link"); - let linkdir = tmpdir.join("test3"); - - File::create(&file).unwrap(); - fs::create_dir(&dir).unwrap(); - symlink_file(&file, &link).unwrap(); - symlink_dir(&dir, &linkdir).unwrap(); - - assert!(link.symlink_metadata().unwrap().file_type().is_symlink()); - - assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir); - assert_eq!(fs::canonicalize(&file).unwrap(), file); - assert_eq!(fs::canonicalize(&link).unwrap(), file); - assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir); - assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file); - } - - #[test] - fn realpath_works_tricky() { - let tmpdir = tmpdir(); - if !got_symlink_permission(&tmpdir) { - return; - }; - - let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); - let a = tmpdir.join("a"); - let b = a.join("b"); - let c = b.join("c"); - let d = a.join("d"); - let e = d.join("e"); - let f = a.join("f"); - - fs::create_dir_all(&b).unwrap(); - fs::create_dir_all(&d).unwrap(); - File::create(&f).unwrap(); - if cfg!(not(windows)) { - symlink_file("../d/e", &c).unwrap(); - symlink_file("../f", &e).unwrap(); - } - if cfg!(windows) { - symlink_file(r"..\d\e", &c).unwrap(); - symlink_file(r"..\f", &e).unwrap(); - } - - assert_eq!(fs::canonicalize(&c).unwrap(), f); - assert_eq!(fs::canonicalize(&e).unwrap(), f); - } - - #[test] - fn dir_entry_methods() { - let tmpdir = tmpdir(); - - fs::create_dir_all(&tmpdir.join("a")).unwrap(); - File::create(&tmpdir.join("b")).unwrap(); - - for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) { - let fname = file.file_name(); - match fname.to_str() { - Some("a") => { - assert!(file.file_type().unwrap().is_dir()); - assert!(file.metadata().unwrap().is_dir()); - } - Some("b") => { - assert!(file.file_type().unwrap().is_file()); - assert!(file.metadata().unwrap().is_file()); - } - f => panic!("unknown file name: {:?}", f), - } - } - } - - #[test] - fn dir_entry_debug() { - let tmpdir = tmpdir(); - File::create(&tmpdir.join("b")).unwrap(); - let mut read_dir = tmpdir.path().read_dir().unwrap(); - let dir_entry = read_dir.next().unwrap().unwrap(); - let actual = format!("{:?}", dir_entry); - let expected = format!("DirEntry({:?})", dir_entry.0.path()); - assert_eq!(actual, expected); - } - - #[test] - fn read_dir_not_found() { - let res = fs::read_dir("/path/that/does/not/exist"); - assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound); - } - - #[test] - fn create_dir_all_with_junctions() { - let tmpdir = tmpdir(); - let target = tmpdir.join("target"); - - let junction = tmpdir.join("junction"); - let b = junction.join("a/b"); - - let link = tmpdir.join("link"); - let d = link.join("c/d"); - - fs::create_dir(&target).unwrap(); - - check!(symlink_junction(&target, &junction)); - check!(fs::create_dir_all(&b)); - // the junction itself is not a directory, but `is_dir()` on a Path - // follows links - assert!(junction.is_dir()); - assert!(b.exists()); - - if !got_symlink_permission(&tmpdir) { - return; - }; - check!(symlink_dir(&target, &link)); - check!(fs::create_dir_all(&d)); - assert!(link.is_dir()); - assert!(d.exists()); - } - - #[test] - fn metadata_access_times() { - let tmpdir = tmpdir(); - - let b = tmpdir.join("b"); - File::create(&b).unwrap(); - - let a = check!(fs::metadata(&tmpdir.path())); - let b = check!(fs::metadata(&b)); - - assert_eq!(check!(a.accessed()), check!(a.accessed())); - assert_eq!(check!(a.modified()), check!(a.modified())); - assert_eq!(check!(b.accessed()), check!(b.modified())); - - if cfg!(target_os = "macos") || cfg!(target_os = "windows") { - check!(a.created()); - check!(b.created()); - } - - if cfg!(target_os = "linux") { - // Not always available - match (a.created(), b.created()) { - (Ok(t1), Ok(t2)) => assert!(t1 <= t2), - (Err(e1), Err(e2)) - if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {} - (a, b) => panic!( - "creation time must be always supported or not supported: {:?} {:?}", - a, b, - ), - } - } - } -} diff --git a/library/std/src/fs/tests.rs b/library/std/src/fs/tests.rs new file mode 100644 index 0000000000..65a29076fe --- /dev/null +++ b/library/std/src/fs/tests.rs @@ -0,0 +1,1339 @@ +use crate::io::prelude::*; + +use crate::fs::{self, File, OpenOptions}; +use crate::io::{ErrorKind, SeekFrom}; +use crate::path::Path; +use crate::str; +use crate::sys_common::io::test::{tmpdir, TempDir}; +use crate::thread; + +use rand::{rngs::StdRng, RngCore, SeedableRng}; + +#[cfg(unix)] +use crate::os::unix::fs::symlink as symlink_dir; +#[cfg(unix)] +use crate::os::unix::fs::symlink as symlink_file; +#[cfg(unix)] +use crate::os::unix::fs::symlink as symlink_junction; +#[cfg(windows)] +use crate::os::windows::fs::{symlink_dir, symlink_file}; +#[cfg(windows)] +use crate::sys::fs::symlink_junction; + +macro_rules! check { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("{} failed with: {}", stringify!($e), e), + } + }; +} + +#[cfg(windows)] +macro_rules! error { + ($e:expr, $s:expr) => { + match $e { + Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), + Err(ref err) => assert!( + err.raw_os_error() == Some($s), + format!("`{}` did not have a code of `{}`", err, $s) + ), + } + }; +} + +#[cfg(unix)] +macro_rules! error { + ($e:expr, $s:expr) => { + error_contains!($e, $s) + }; +} + +macro_rules! error_contains { + ($e:expr, $s:expr) => { + match $e { + Ok(_) => panic!("Unexpected success. Should've been: {:?}", $s), + Err(ref err) => { + assert!(err.to_string().contains($s), format!("`{}` did not contain `{}`", err, $s)) + } + } + }; +} + +// Several test fail on windows if the user does not have permission to +// create symlinks (the `SeCreateSymbolicLinkPrivilege`). Instead of +// disabling these test on Windows, use this function to test whether we +// have permission, and return otherwise. This way, we still don't run these +// tests most of the time, but at least we do if the user has the right +// permissions. +pub fn got_symlink_permission(tmpdir: &TempDir) -> bool { + if cfg!(unix) { + return true; + } + let link = tmpdir.join("some_hopefully_unique_link_name"); + + match symlink_file(r"nonexisting_target", link) { + Ok(_) => true, + // ERROR_PRIVILEGE_NOT_HELD = 1314 + Err(ref err) if err.raw_os_error() == Some(1314) => false, + Err(_) => true, + } +} + +#[test] +fn file_test_io_smoke_test() { + let message = "it's alright. have a good time"; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test.txt"); + { + let mut write_stream = check!(File::create(filename)); + check!(write_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + let mut read_buf = [0; 1028]; + let read_str = match check!(read_stream.read(&mut read_buf)) { + 0 => panic!("shouldn't happen"), + n => str::from_utf8(&read_buf[..n]).unwrap().to_string(), + }; + assert_eq!(read_str, message); + } + check!(fs::remove_file(filename)); +} + +#[test] +fn invalid_path_raises() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_that_does_not_exist.txt"); + let result = File::open(filename); + + #[cfg(all(unix, not(target_os = "vxworks")))] + error!(result, "No such file or directory"); + #[cfg(target_os = "vxworks")] + error!(result, "no such file or directory"); + #[cfg(windows)] + error!(result, 2); // ERROR_FILE_NOT_FOUND +} + +#[test] +fn file_test_iounlinking_invalid_path_should_raise_condition() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_another_file_that_does_not_exist.txt"); + + let result = fs::remove_file(filename); + + #[cfg(all(unix, not(target_os = "vxworks")))] + error!(result, "No such file or directory"); + #[cfg(target_os = "vxworks")] + error!(result, "no such file or directory"); + #[cfg(windows)] + error!(result, 2); // ERROR_FILE_NOT_FOUND +} + +#[test] +fn file_test_io_non_positional_read() { + let message: &str = "ten-four"; + let mut read_mem = [0; 8]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_positional.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + { + let read_buf = &mut read_mem[0..4]; + check!(read_stream.read(read_buf)); + } + { + let read_buf = &mut read_mem[4..8]; + check!(read_stream.read(read_buf)); + } + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert_eq!(read_str, message); +} + +#[test] +fn file_test_io_seek_and_tell_smoke_test() { + let message = "ten-four"; + let mut read_mem = [0; 4]; + let set_cursor = 4 as u64; + let tell_pos_pre_read; + let tell_pos_post_read; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seeking.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(message.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + check!(read_stream.seek(SeekFrom::Start(set_cursor))); + tell_pos_pre_read = check!(read_stream.seek(SeekFrom::Current(0))); + check!(read_stream.read(&mut read_mem)); + tell_pos_post_read = check!(read_stream.seek(SeekFrom::Current(0))); + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert_eq!(read_str, &message[4..8]); + assert_eq!(tell_pos_pre_read, set_cursor); + assert_eq!(tell_pos_post_read, message.len() as u64); +} + +#[test] +fn file_test_io_seek_and_write() { + let initial_msg = "food-is-yummy"; + let overwrite_msg = "-the-bar!!"; + let final_msg = "foo-the-bar!!"; + let seek_idx = 3; + let mut read_mem = [0; 13]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seek_and_write.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(initial_msg.as_bytes())); + check!(rw_stream.seek(SeekFrom::Start(seek_idx))); + check!(rw_stream.write(overwrite_msg.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + check!(read_stream.read(&mut read_mem)); + } + check!(fs::remove_file(filename)); + let read_str = str::from_utf8(&read_mem).unwrap(); + assert!(read_str == final_msg); +} + +#[test] +fn file_test_io_seek_shakedown() { + // 01234567890123 + let initial_msg = "qwer-asdf-zxcv"; + let chunk_one: &str = "qwer"; + let chunk_two: &str = "asdf"; + let chunk_three: &str = "zxcv"; + let mut read_mem = [0; 4]; + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_rt_io_file_test_seek_shakedown.txt"); + { + let mut rw_stream = check!(File::create(filename)); + check!(rw_stream.write(initial_msg.as_bytes())); + } + { + let mut read_stream = check!(File::open(filename)); + + check!(read_stream.seek(SeekFrom::End(-4))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_three); + + check!(read_stream.seek(SeekFrom::Current(-9))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_two); + + check!(read_stream.seek(SeekFrom::Start(0))); + check!(read_stream.read(&mut read_mem)); + assert_eq!(str::from_utf8(&read_mem).unwrap(), chunk_one); + } + check!(fs::remove_file(filename)); +} + +#[test] +fn file_test_io_eof() { + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_eof.txt"); + let mut buf = [0; 256]; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.read(&mut buf)), 0); + assert_eq!(check!(rw.read(&mut buf)), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] +fn file_test_io_read_write_at() { + use crate::os::unix::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_read_write_at.txt"); + let mut buf = [0; 256]; + let write1 = "asdf"; + let write2 = "qwer-"; + let write3 = "-zxcv"; + let content = "qwer-asdf-zxcv"; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.write_at(write1.as_bytes(), 5)), write1.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.read_at(&mut buf, 5)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok("\0\0\0\0\0")); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.read(&mut buf)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.read_at(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.write_at(write3.as_bytes(), 9)), write3.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + } + { + let mut read = check!(File::open(&filename)); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 0); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(read.read(&mut buf)), write3.len()); + assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.read_at(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.read_at(&mut buf, 14)), 0); + assert_eq!(check!(read.read_at(&mut buf, 15)), 0); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + } + check!(fs::remove_file(&filename)); +} + +#[test] +#[cfg(unix)] +fn set_get_unix_permissions() { + use crate::os::unix::fs::PermissionsExt; + + let tmpdir = tmpdir(); + let filename = &tmpdir.join("set_get_unix_permissions"); + check!(fs::create_dir(filename)); + let mask = 0o7777; + + check!(fs::set_permissions(filename, fs::Permissions::from_mode(0))); + let metadata0 = check!(fs::metadata(filename)); + assert_eq!(mask & metadata0.permissions().mode(), 0); + + check!(fs::set_permissions(filename, fs::Permissions::from_mode(0o1777))); + let metadata1 = check!(fs::metadata(filename)); + #[cfg(all(unix, not(target_os = "vxworks")))] + assert_eq!(mask & metadata1.permissions().mode(), 0o1777); + #[cfg(target_os = "vxworks")] + assert_eq!(mask & metadata1.permissions().mode(), 0o0777); +} + +#[test] +#[cfg(windows)] +fn file_test_io_seek_read_write() { + use crate::os::windows::fs::FileExt; + + let tmpdir = tmpdir(); + let filename = tmpdir.join("file_rt_io_file_test_seek_read_write.txt"); + let mut buf = [0; 256]; + let write1 = "asdf"; + let write2 = "qwer-"; + let write3 = "-zxcv"; + let content = "qwer-asdf-zxcv"; + { + let oo = OpenOptions::new().create_new(true).write(true).read(true).clone(); + let mut rw = check!(oo.open(&filename)); + assert_eq!(check!(rw.seek_write(write1.as_bytes(), 5)), write1.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek_read(&mut buf, 5)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek(SeekFrom::Start(0))), 0); + assert_eq!(check!(rw.write(write2.as_bytes())), write2.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.read(&mut buf)), write1.len()); + assert_eq!(str::from_utf8(&buf[..write1.len()]), Ok(write1)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 9); + assert_eq!(check!(rw.seek_read(&mut buf[..write2.len()], 0)), write2.len()); + assert_eq!(str::from_utf8(&buf[..write2.len()]), Ok(write2)); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 5); + assert_eq!(check!(rw.seek_write(write3.as_bytes(), 9)), write3.len()); + assert_eq!(check!(rw.seek(SeekFrom::Current(0))), 14); + } + { + let mut read = check!(File::open(&filename)); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek(SeekFrom::End(-5))), 9); + assert_eq!(check!(read.read(&mut buf)), write3.len()); + assert_eq!(str::from_utf8(&buf[..write3.len()]), Ok(write3)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek_read(&mut buf, 0)), content.len()); + assert_eq!(str::from_utf8(&buf[..content.len()]), Ok(content)); + assert_eq!(check!(read.seek(SeekFrom::Current(0))), 14); + assert_eq!(check!(read.seek_read(&mut buf, 14)), 0); + assert_eq!(check!(read.seek_read(&mut buf, 15)), 0); + } + check!(fs::remove_file(&filename)); +} + +#[test] +fn file_test_stat_is_correct_on_is_file() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_stat_correct_on_is_file.txt"); + { + let mut opts = OpenOptions::new(); + let mut fs = check!(opts.read(true).write(true).create(true).open(filename)); + let msg = "hw"; + fs.write(msg.as_bytes()).unwrap(); + + let fstat_res = check!(fs.metadata()); + assert!(fstat_res.is_file()); + } + let stat_res_fn = check!(fs::metadata(filename)); + assert!(stat_res_fn.is_file()); + let stat_res_meth = check!(filename.metadata()); + assert!(stat_res_meth.is_file()); + check!(fs::remove_file(filename)); +} + +#[test] +fn file_test_stat_is_correct_on_is_dir() { + let tmpdir = tmpdir(); + let filename = &tmpdir.join("file_stat_correct_on_is_dir"); + check!(fs::create_dir(filename)); + let stat_res_fn = check!(fs::metadata(filename)); + assert!(stat_res_fn.is_dir()); + let stat_res_meth = check!(filename.metadata()); + assert!(stat_res_meth.is_dir()); + check!(fs::remove_dir(filename)); +} + +#[test] +fn file_test_fileinfo_false_when_checking_is_file_on_a_directory() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("fileinfo_false_on_dir"); + check!(fs::create_dir(dir)); + assert!(!dir.is_file()); + check!(fs::remove_dir(dir)); +} + +#[test] +fn file_test_fileinfo_check_exists_before_and_after_file_creation() { + let tmpdir = tmpdir(); + let file = &tmpdir.join("fileinfo_check_exists_b_and_a.txt"); + check!(check!(File::create(file)).write(b"foo")); + assert!(file.exists()); + check!(fs::remove_file(file)); + assert!(!file.exists()); +} + +#[test] +fn file_test_directoryinfo_check_exists_before_and_after_mkdir() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("before_and_after_dir"); + assert!(!dir.exists()); + check!(fs::create_dir(dir)); + assert!(dir.exists()); + assert!(dir.is_dir()); + check!(fs::remove_dir(dir)); + assert!(!dir.exists()); +} + +#[test] +fn file_test_directoryinfo_readdir() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("di_readdir"); + check!(fs::create_dir(dir)); + let prefix = "foo"; + for n in 0..3 { + let f = dir.join(&format!("{}.txt", n)); + let mut w = check!(File::create(&f)); + let msg_str = format!("{}{}", prefix, n.to_string()); + let msg = msg_str.as_bytes(); + check!(w.write(msg)); + } + let files = check!(fs::read_dir(dir)); + let mut mem = [0; 4]; + for f in files { + let f = f.unwrap().path(); + { + let n = f.file_stem().unwrap(); + check!(check!(File::open(&f)).read(&mut mem)); + let read_str = str::from_utf8(&mem).unwrap(); + let expected = format!("{}{}", prefix, n.to_str().unwrap()); + assert_eq!(expected, read_str); + } + check!(fs::remove_file(&f)); + } + check!(fs::remove_dir(dir)); +} + +#[test] +fn file_create_new_already_exists_error() { + let tmpdir = tmpdir(); + let file = &tmpdir.join("file_create_new_error_exists"); + check!(fs::File::create(file)); + let e = fs::OpenOptions::new().write(true).create_new(true).open(file).unwrap_err(); + assert_eq!(e.kind(), ErrorKind::AlreadyExists); +} + +#[test] +fn mkdir_path_already_exists_error() { + let tmpdir = tmpdir(); + let dir = &tmpdir.join("mkdir_error_twice"); + check!(fs::create_dir(dir)); + let e = fs::create_dir(dir).unwrap_err(); + assert_eq!(e.kind(), ErrorKind::AlreadyExists); +} + +#[test] +fn recursive_mkdir() { + let tmpdir = tmpdir(); + let dir = tmpdir.join("d1/d2"); + check!(fs::create_dir_all(&dir)); + assert!(dir.is_dir()) +} + +#[test] +fn recursive_mkdir_failure() { + let tmpdir = tmpdir(); + let dir = tmpdir.join("d1"); + let file = dir.join("f1"); + + check!(fs::create_dir_all(&dir)); + check!(File::create(&file)); + + let result = fs::create_dir_all(&file); + + assert!(result.is_err()); +} + +#[test] +fn concurrent_recursive_mkdir() { + for _ in 0..100 { + let dir = tmpdir(); + let mut dir = dir.join("a"); + for _ in 0..40 { + dir = dir.join("a"); + } + let mut join = vec![]; + for _ in 0..8 { + let dir = dir.clone(); + join.push(thread::spawn(move || { + check!(fs::create_dir_all(&dir)); + })) + } + + // No `Display` on result of `join()` + join.drain(..).map(|join| join.join().unwrap()).count(); + } +} + +#[test] +fn recursive_mkdir_slash() { + check!(fs::create_dir_all(Path::new("/"))); +} + +#[test] +fn recursive_mkdir_dot() { + check!(fs::create_dir_all(Path::new("."))); +} + +#[test] +fn recursive_mkdir_empty() { + check!(fs::create_dir_all(Path::new(""))); +} + +#[test] +fn recursive_rmdir() { + let tmpdir = tmpdir(); + let d1 = tmpdir.join("d1"); + let dt = d1.join("t"); + let dtt = dt.join("t"); + let d2 = tmpdir.join("d2"); + let canary = d2.join("do_not_delete"); + check!(fs::create_dir_all(&dtt)); + check!(fs::create_dir_all(&d2)); + check!(check!(File::create(&canary)).write(b"foo")); + check!(symlink_junction(&d2, &dt.join("d2"))); + let _ = symlink_file(&canary, &d1.join("canary")); + check!(fs::remove_dir_all(&d1)); + + assert!(!d1.is_dir()); + assert!(canary.exists()); +} + +#[test] +fn recursive_rmdir_of_symlink() { + // test we do not recursively delete a symlink but only dirs. + let tmpdir = tmpdir(); + let link = tmpdir.join("d1"); + let dir = tmpdir.join("d2"); + let canary = dir.join("do_not_delete"); + check!(fs::create_dir_all(&dir)); + check!(check!(File::create(&canary)).write(b"foo")); + check!(symlink_junction(&dir, &link)); + check!(fs::remove_dir_all(&link)); + + assert!(!link.is_dir()); + assert!(canary.exists()); +} + +#[test] +// only Windows makes a distinction between file and directory symlinks. +#[cfg(windows)] +fn recursive_rmdir_of_file_symlink() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let f1 = tmpdir.join("f1"); + let f2 = tmpdir.join("f2"); + check!(check!(File::create(&f1)).write(b"foo")); + check!(symlink_file(&f1, &f2)); + match fs::remove_dir_all(&f2) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } +} + +#[test] +fn unicode_path_is_dir() { + assert!(Path::new(".").is_dir()); + assert!(!Path::new("test/stdtest/fs.rs").is_dir()); + + let tmpdir = tmpdir(); + + let mut dirpath = tmpdir.path().to_path_buf(); + dirpath.push("test-가一ー你好"); + check!(fs::create_dir(&dirpath)); + assert!(dirpath.is_dir()); + + let mut filepath = dirpath; + filepath.push("unicode-file-\u{ac00}\u{4e00}\u{30fc}\u{4f60}\u{597d}.rs"); + check!(File::create(&filepath)); // ignore return; touch only + assert!(!filepath.is_dir()); + assert!(filepath.exists()); +} + +#[test] +fn unicode_path_exists() { + assert!(Path::new(".").exists()); + assert!(!Path::new("test/nonexistent-bogus-path").exists()); + + let tmpdir = tmpdir(); + let unicode = tmpdir.path(); + let unicode = unicode.join("test-각丁ー再见"); + check!(fs::create_dir(&unicode)); + assert!(unicode.exists()); + assert!(!Path::new("test/unicode-bogus-path-각丁ー再见").exists()); +} + +#[test] +fn copy_file_does_not_exist() { + let from = Path::new("test/nonexistent-bogus-path"); + let to = Path::new("test/other-bogus-path"); + + match fs::copy(&from, &to) { + Ok(..) => panic!(), + Err(..) => { + assert!(!from.exists()); + assert!(!to.exists()); + } + } +} + +#[test] +fn copy_src_does_not_exist() { + let tmpdir = tmpdir(); + let from = Path::new("test/nonexistent-bogus-path"); + let to = tmpdir.join("out.txt"); + check!(check!(File::create(&to)).write(b"hello")); + assert!(fs::copy(&from, &to).is_err()); + assert!(!from.exists()); + let mut v = Vec::new(); + check!(check!(File::open(&to)).read_to_end(&mut v)); + assert_eq!(v, b"hello"); +} + +#[test] +fn copy_file_ok() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write(b"hello")); + check!(fs::copy(&input, &out)); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"hello"); + + assert_eq!(check!(input.metadata()).permissions(), check!(out.metadata()).permissions()); +} + +#[test] +fn copy_file_dst_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + check!(File::create(&out)); + match fs::copy(&*out, tmpdir.path()) { + Ok(..) => panic!(), + Err(..) => {} + } +} + +#[test] +fn copy_file_dst_exists() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in"); + let output = tmpdir.join("out"); + + check!(check!(File::create(&input)).write("foo".as_bytes())); + check!(check!(File::create(&output)).write("bar".as_bytes())); + check!(fs::copy(&input, &output)); + + let mut v = Vec::new(); + check!(check!(File::open(&output)).read_to_end(&mut v)); + assert_eq!(v, b"foo".to_vec()); +} + +#[test] +fn copy_file_src_dir() { + let tmpdir = tmpdir(); + let out = tmpdir.join("out"); + + match fs::copy(tmpdir.path(), &out) { + Ok(..) => panic!(), + Err(..) => {} + } + assert!(!out.exists()); +} + +#[test] +fn copy_file_preserves_perm_bits() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + let attr = check!(check!(File::create(&input)).metadata()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(fs::set_permissions(&input, p)); + check!(fs::copy(&input, &out)); + assert!(check!(out.metadata()).permissions().readonly()); + check!(fs::set_permissions(&input, attr.permissions())); + check!(fs::set_permissions(&out, attr.permissions())); +} + +#[test] +#[cfg(windows)] +fn copy_file_preserves_streams() { + let tmp = tmpdir(); + check!(check!(File::create(tmp.join("in.txt:bunny"))).write("carrot".as_bytes())); + assert_eq!(check!(fs::copy(tmp.join("in.txt"), tmp.join("out.txt"))), 0); + assert_eq!(check!(tmp.join("out.txt").metadata()).len(), 0); + let mut v = Vec::new(); + check!(check!(File::open(tmp.join("out.txt:bunny"))).read_to_end(&mut v)); + assert_eq!(v, b"carrot".to_vec()); +} + +#[test] +fn copy_file_returns_metadata_len() { + let tmp = tmpdir(); + let in_path = tmp.join("in.txt"); + let out_path = tmp.join("out.txt"); + check!(check!(File::create(&in_path)).write(b"lettuce")); + #[cfg(windows)] + check!(check!(File::create(tmp.join("in.txt:bunny"))).write(b"carrot")); + let copied_len = check!(fs::copy(&in_path, &out_path)); + assert_eq!(check!(out_path.metadata()).len(), copied_len); +} + +#[test] +fn copy_file_follows_dst_symlink() { + let tmp = tmpdir(); + if !got_symlink_permission(&tmp) { + return; + }; + + let in_path = tmp.join("in.txt"); + let out_path = tmp.join("out.txt"); + let out_path_symlink = tmp.join("out_symlink.txt"); + + check!(fs::write(&in_path, "foo")); + check!(fs::write(&out_path, "bar")); + check!(symlink_file(&out_path, &out_path_symlink)); + + check!(fs::copy(&in_path, &out_path_symlink)); + + assert!(check!(out_path_symlink.symlink_metadata()).file_type().is_symlink()); + assert_eq!(check!(fs::read(&out_path_symlink)), b"foo".to_vec()); + assert_eq!(check!(fs::read(&out_path)), b"foo".to_vec()); +} + +#[test] +fn symlinks_work() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write("foobar".as_bytes())); + check!(symlink_file(&input, &out)); + assert!(check!(out.symlink_metadata()).file_type().is_symlink()); + assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"foobar".to_vec()); +} + +#[test] +fn symlink_noexist() { + // Symlinks can point to things that don't exist + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + // Use a relative path for testing. Symlinks get normalized by Windows, + // so we may not get the same path back for absolute paths + check!(symlink_file(&"foo", &tmpdir.join("bar"))); + assert_eq!(check!(fs::read_link(&tmpdir.join("bar"))).to_str().unwrap(), "foo"); +} + +#[test] +fn read_link() { + if cfg!(windows) { + // directory symlink + assert_eq!( + check!(fs::read_link(r"C:\Users\All Users")).to_str().unwrap(), + r"C:\ProgramData" + ); + // junction + assert_eq!( + check!(fs::read_link(r"C:\Users\Default User")).to_str().unwrap(), + r"C:\Users\Default" + ); + // junction with special permissions + assert_eq!( + check!(fs::read_link(r"C:\Documents and Settings\")).to_str().unwrap(), + r"C:\Users" + ); + } + let tmpdir = tmpdir(); + let link = tmpdir.join("link"); + if !got_symlink_permission(&tmpdir) { + return; + }; + check!(symlink_file(&"foo", &link)); + assert_eq!(check!(fs::read_link(&link)).to_str().unwrap(), "foo"); +} + +#[test] +fn readlink_not_symlink() { + let tmpdir = tmpdir(); + match fs::read_link(tmpdir.path()) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } +} + +#[test] +fn links_work() { + let tmpdir = tmpdir(); + let input = tmpdir.join("in.txt"); + let out = tmpdir.join("out.txt"); + + check!(check!(File::create(&input)).write("foobar".as_bytes())); + check!(fs::hard_link(&input, &out)); + assert_eq!(check!(fs::metadata(&out)).len(), check!(fs::metadata(&input)).len()); + assert_eq!(check!(fs::metadata(&out)).len(), check!(input.metadata()).len()); + let mut v = Vec::new(); + check!(check!(File::open(&out)).read_to_end(&mut v)); + assert_eq!(v, b"foobar".to_vec()); + + // can't link to yourself + match fs::hard_link(&input, &input) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } + // can't link to something that doesn't exist + match fs::hard_link(&tmpdir.join("foo"), &tmpdir.join("bar")) { + Ok(..) => panic!("wanted a failure"), + Err(..) => {} + } +} + +#[test] +fn chmod_works() { + let tmpdir = tmpdir(); + let file = tmpdir.join("in.txt"); + + check!(File::create(&file)); + let attr = check!(fs::metadata(&file)); + assert!(!attr.permissions().readonly()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(fs::set_permissions(&file, p.clone())); + let attr = check!(fs::metadata(&file)); + assert!(attr.permissions().readonly()); + + match fs::set_permissions(&tmpdir.join("foo"), p.clone()) { + Ok(..) => panic!("wanted an error"), + Err(..) => {} + } + + p.set_readonly(false); + check!(fs::set_permissions(&file, p)); +} + +#[test] +fn fchmod_works() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let file = check!(File::create(&path)); + let attr = check!(fs::metadata(&path)); + assert!(!attr.permissions().readonly()); + let mut p = attr.permissions(); + p.set_readonly(true); + check!(file.set_permissions(p.clone())); + let attr = check!(fs::metadata(&path)); + assert!(attr.permissions().readonly()); + + p.set_readonly(false); + check!(file.set_permissions(p)); +} + +#[test] +fn sync_doesnt_kill_anything() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = check!(File::create(&path)); + check!(file.sync_all()); + check!(file.sync_data()); + check!(file.write(b"foo")); + check!(file.sync_all()); + check!(file.sync_data()); +} + +#[test] +fn truncate_works() { + let tmpdir = tmpdir(); + let path = tmpdir.join("in.txt"); + + let mut file = check!(File::create(&path)); + check!(file.write(b"foo")); + check!(file.sync_all()); + + // Do some simple things with truncation + assert_eq!(check!(file.metadata()).len(), 3); + check!(file.set_len(10)); + assert_eq!(check!(file.metadata()).len(), 10); + check!(file.write(b"bar")); + check!(file.sync_all()); + assert_eq!(check!(file.metadata()).len(), 10); + + let mut v = Vec::new(); + check!(check!(File::open(&path)).read_to_end(&mut v)); + assert_eq!(v, b"foobar\0\0\0\0".to_vec()); + + // Truncate to a smaller length, don't seek, and then write something. + // Ensure that the intermediate zeroes are all filled in (we have `seek`ed + // past the end of the file). + check!(file.set_len(2)); + assert_eq!(check!(file.metadata()).len(), 2); + check!(file.write(b"wut")); + check!(file.sync_all()); + assert_eq!(check!(file.metadata()).len(), 9); + let mut v = Vec::new(); + check!(check!(File::open(&path)).read_to_end(&mut v)); + assert_eq!(v, b"fo\0\0\0\0wut".to_vec()); +} + +#[test] +fn open_flavors() { + use crate::fs::OpenOptions as OO; + fn c(t: &T) -> T { + t.clone() + } + + let tmpdir = tmpdir(); + + let mut r = OO::new(); + r.read(true); + let mut w = OO::new(); + w.write(true); + let mut rw = OO::new(); + rw.read(true).write(true); + let mut a = OO::new(); + a.append(true); + let mut ra = OO::new(); + ra.read(true).append(true); + + #[cfg(windows)] + let invalid_options = 87; // ERROR_INVALID_PARAMETER + #[cfg(all(unix, not(target_os = "vxworks")))] + let invalid_options = "Invalid argument"; + #[cfg(target_os = "vxworks")] + let invalid_options = "invalid argument"; + + // Test various combinations of creation modes and access modes. + // + // Allowed: + // creation mode | read | write | read-write | append | read-append | + // :-----------------------|:-----:|:-----:|:----------:|:------:|:-----------:| + // not set (open existing) | X | X | X | X | X | + // create | | X | X | X | X | + // truncate | | X | X | | | + // create and truncate | | X | X | | | + // create_new | | X | X | X | X | + // + // tested in reverse order, so 'create_new' creates the file, and 'open existing' opens it. + + // write-only + check!(c(&w).create_new(true).open(&tmpdir.join("a"))); + check!(c(&w).create(true).truncate(true).open(&tmpdir.join("a"))); + check!(c(&w).truncate(true).open(&tmpdir.join("a"))); + check!(c(&w).create(true).open(&tmpdir.join("a"))); + check!(c(&w).open(&tmpdir.join("a"))); + + // read-only + error!(c(&r).create_new(true).open(&tmpdir.join("b")), invalid_options); + error!(c(&r).create(true).truncate(true).open(&tmpdir.join("b")), invalid_options); + error!(c(&r).truncate(true).open(&tmpdir.join("b")), invalid_options); + error!(c(&r).create(true).open(&tmpdir.join("b")), invalid_options); + check!(c(&r).open(&tmpdir.join("a"))); // try opening the file created with write_only + + // read-write + check!(c(&rw).create_new(true).open(&tmpdir.join("c"))); + check!(c(&rw).create(true).truncate(true).open(&tmpdir.join("c"))); + check!(c(&rw).truncate(true).open(&tmpdir.join("c"))); + check!(c(&rw).create(true).open(&tmpdir.join("c"))); + check!(c(&rw).open(&tmpdir.join("c"))); + + // append + check!(c(&a).create_new(true).open(&tmpdir.join("d"))); + error!(c(&a).create(true).truncate(true).open(&tmpdir.join("d")), invalid_options); + error!(c(&a).truncate(true).open(&tmpdir.join("d")), invalid_options); + check!(c(&a).create(true).open(&tmpdir.join("d"))); + check!(c(&a).open(&tmpdir.join("d"))); + + // read-append + check!(c(&ra).create_new(true).open(&tmpdir.join("e"))); + error!(c(&ra).create(true).truncate(true).open(&tmpdir.join("e")), invalid_options); + error!(c(&ra).truncate(true).open(&tmpdir.join("e")), invalid_options); + check!(c(&ra).create(true).open(&tmpdir.join("e"))); + check!(c(&ra).open(&tmpdir.join("e"))); + + // Test opening a file without setting an access mode + let mut blank = OO::new(); + error!(blank.create(true).open(&tmpdir.join("f")), invalid_options); + + // Test write works + check!(check!(File::create(&tmpdir.join("h"))).write("foobar".as_bytes())); + + // Test write fails for read-only + check!(r.open(&tmpdir.join("h"))); + { + let mut f = check!(r.open(&tmpdir.join("h"))); + assert!(f.write("wut".as_bytes()).is_err()); + } + + // Test write overwrites + { + let mut f = check!(c(&w).open(&tmpdir.join("h"))); + check!(f.write("baz".as_bytes())); + } + { + let mut f = check!(c(&r).open(&tmpdir.join("h"))); + let mut b = vec![0; 6]; + check!(f.read(&mut b)); + assert_eq!(b, "bazbar".as_bytes()); + } + + // Test truncate works + { + let mut f = check!(c(&w).truncate(true).open(&tmpdir.join("h"))); + check!(f.write("foo".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); + + // Test append works + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 3); + { + let mut f = check!(c(&a).open(&tmpdir.join("h"))); + check!(f.write("bar".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 6); + + // Test .append(true) equals .write(true).append(true) + { + let mut f = check!(c(&w).append(true).open(&tmpdir.join("h"))); + check!(f.write("baz".as_bytes())); + } + assert_eq!(check!(fs::metadata(&tmpdir.join("h"))).len(), 9); +} + +#[test] +fn _assert_send_sync() { + fn _assert_send_sync() {} + _assert_send_sync::(); +} + +#[test] +fn binary_file() { + let mut bytes = [0; 1024]; + StdRng::from_entropy().fill_bytes(&mut bytes); + + let tmpdir = tmpdir(); + + check!(check!(File::create(&tmpdir.join("test"))).write(&bytes)); + let mut v = Vec::new(); + check!(check!(File::open(&tmpdir.join("test"))).read_to_end(&mut v)); + assert!(v == &bytes[..]); +} + +#[test] +fn write_then_read() { + let mut bytes = [0; 1024]; + StdRng::from_entropy().fill_bytes(&mut bytes); + + let tmpdir = tmpdir(); + + check!(fs::write(&tmpdir.join("test"), &bytes[..])); + let v = check!(fs::read(&tmpdir.join("test"))); + assert!(v == &bytes[..]); + + check!(fs::write(&tmpdir.join("not-utf8"), &[0xFF])); + error_contains!( + fs::read_to_string(&tmpdir.join("not-utf8")), + "stream did not contain valid UTF-8" + ); + + let s = "𐁁𐀓𐀠𐀴𐀍"; + check!(fs::write(&tmpdir.join("utf8"), s.as_bytes())); + let string = check!(fs::read_to_string(&tmpdir.join("utf8"))); + assert_eq!(string, s); +} + +#[test] +fn file_try_clone() { + let tmpdir = tmpdir(); + + let mut f1 = + check!(OpenOptions::new().read(true).write(true).create(true).open(&tmpdir.join("test"))); + let mut f2 = check!(f1.try_clone()); + + check!(f1.write_all(b"hello world")); + check!(f1.seek(SeekFrom::Start(2))); + + let mut buf = vec![]; + check!(f2.read_to_end(&mut buf)); + assert_eq!(buf, b"llo world"); + drop(f2); + + check!(f1.write_all(b"!")); +} + +#[test] +#[cfg(not(windows))] +fn unlink_readonly() { + let tmpdir = tmpdir(); + let path = tmpdir.join("file"); + check!(File::create(&path)); + let mut perm = check!(fs::metadata(&path)).permissions(); + perm.set_readonly(true); + check!(fs::set_permissions(&path, perm)); + check!(fs::remove_file(&path)); +} + +#[test] +fn mkdir_trailing_slash() { + let tmpdir = tmpdir(); + let path = tmpdir.join("file"); + check!(fs::create_dir_all(&path.join("a/"))); +} + +#[test] +fn canonicalize_works_simple() { + let tmpdir = tmpdir(); + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let file = tmpdir.join("test"); + File::create(&file).unwrap(); + assert_eq!(fs::canonicalize(&file).unwrap(), file); +} + +#[test] +fn realpath_works() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let file = tmpdir.join("test"); + let dir = tmpdir.join("test2"); + let link = dir.join("link"); + let linkdir = tmpdir.join("test3"); + + File::create(&file).unwrap(); + fs::create_dir(&dir).unwrap(); + symlink_file(&file, &link).unwrap(); + symlink_dir(&dir, &linkdir).unwrap(); + + assert!(link.symlink_metadata().unwrap().file_type().is_symlink()); + + assert_eq!(fs::canonicalize(&tmpdir).unwrap(), tmpdir); + assert_eq!(fs::canonicalize(&file).unwrap(), file); + assert_eq!(fs::canonicalize(&link).unwrap(), file); + assert_eq!(fs::canonicalize(&linkdir).unwrap(), dir); + assert_eq!(fs::canonicalize(&linkdir.join("link")).unwrap(), file); +} + +#[test] +fn realpath_works_tricky() { + let tmpdir = tmpdir(); + if !got_symlink_permission(&tmpdir) { + return; + }; + + let tmpdir = fs::canonicalize(tmpdir.path()).unwrap(); + let a = tmpdir.join("a"); + let b = a.join("b"); + let c = b.join("c"); + let d = a.join("d"); + let e = d.join("e"); + let f = a.join("f"); + + fs::create_dir_all(&b).unwrap(); + fs::create_dir_all(&d).unwrap(); + File::create(&f).unwrap(); + if cfg!(not(windows)) { + symlink_file("../d/e", &c).unwrap(); + symlink_file("../f", &e).unwrap(); + } + if cfg!(windows) { + symlink_file(r"..\d\e", &c).unwrap(); + symlink_file(r"..\f", &e).unwrap(); + } + + assert_eq!(fs::canonicalize(&c).unwrap(), f); + assert_eq!(fs::canonicalize(&e).unwrap(), f); +} + +#[test] +fn dir_entry_methods() { + let tmpdir = tmpdir(); + + fs::create_dir_all(&tmpdir.join("a")).unwrap(); + File::create(&tmpdir.join("b")).unwrap(); + + for file in tmpdir.path().read_dir().unwrap().map(|f| f.unwrap()) { + let fname = file.file_name(); + match fname.to_str() { + Some("a") => { + assert!(file.file_type().unwrap().is_dir()); + assert!(file.metadata().unwrap().is_dir()); + } + Some("b") => { + assert!(file.file_type().unwrap().is_file()); + assert!(file.metadata().unwrap().is_file()); + } + f => panic!("unknown file name: {:?}", f), + } + } +} + +#[test] +fn dir_entry_debug() { + let tmpdir = tmpdir(); + File::create(&tmpdir.join("b")).unwrap(); + let mut read_dir = tmpdir.path().read_dir().unwrap(); + let dir_entry = read_dir.next().unwrap().unwrap(); + let actual = format!("{:?}", dir_entry); + let expected = format!("DirEntry({:?})", dir_entry.0.path()); + assert_eq!(actual, expected); +} + +#[test] +fn read_dir_not_found() { + let res = fs::read_dir("/path/that/does/not/exist"); + assert_eq!(res.err().unwrap().kind(), ErrorKind::NotFound); +} + +#[test] +fn create_dir_all_with_junctions() { + let tmpdir = tmpdir(); + let target = tmpdir.join("target"); + + let junction = tmpdir.join("junction"); + let b = junction.join("a/b"); + + let link = tmpdir.join("link"); + let d = link.join("c/d"); + + fs::create_dir(&target).unwrap(); + + check!(symlink_junction(&target, &junction)); + check!(fs::create_dir_all(&b)); + // the junction itself is not a directory, but `is_dir()` on a Path + // follows links + assert!(junction.is_dir()); + assert!(b.exists()); + + if !got_symlink_permission(&tmpdir) { + return; + }; + check!(symlink_dir(&target, &link)); + check!(fs::create_dir_all(&d)); + assert!(link.is_dir()); + assert!(d.exists()); +} + +#[test] +fn metadata_access_times() { + let tmpdir = tmpdir(); + + let b = tmpdir.join("b"); + File::create(&b).unwrap(); + + let a = check!(fs::metadata(&tmpdir.path())); + let b = check!(fs::metadata(&b)); + + assert_eq!(check!(a.accessed()), check!(a.accessed())); + assert_eq!(check!(a.modified()), check!(a.modified())); + assert_eq!(check!(b.accessed()), check!(b.modified())); + + if cfg!(target_os = "macos") || cfg!(target_os = "windows") { + check!(a.created()); + check!(b.created()); + } + + if cfg!(target_os = "linux") { + // Not always available + match (a.created(), b.created()) { + (Ok(t1), Ok(t2)) => assert!(t1 <= t2), + (Err(e1), Err(e2)) + if e1.kind() == ErrorKind::Other && e2.kind() == ErrorKind::Other => {} + (a, b) => { + panic!("creation time must be always supported or not supported: {:?} {:?}", a, b,) + } + } + } +} diff --git a/library/std/src/future.rs b/library/std/src/future.rs index 89dd9fb9b2..9d9c36e9af 100644 --- a/library/std/src/future.rs +++ b/library/std/src/future.rs @@ -9,7 +9,7 @@ pub use core::future::Future; pub use core::future::{from_generator, get_context, ResumeTy}; #[doc(inline)] -#[unstable(feature = "future_readiness_fns", issue = "70921")] +#[stable(feature = "future_readiness_fns", since = "1.48.0")] pub use core::future::{pending, ready, Pending, Ready}; #[doc(inline)] diff --git a/library/std/src/io/buffered.rs b/library/std/src/io/buffered.rs index f3aadf29b2..97c4b87979 100644 --- a/library/std/src/io/buffered.rs +++ b/library/std/src/io/buffered.rs @@ -1,5 +1,8 @@ //! Buffering wrappers for I/O traits +#[cfg(test)] +mod tests; + use crate::io::prelude::*; use crate::cmp; @@ -383,6 +386,51 @@ impl Seek for BufReader { self.discard_buffer(); Ok(result) } + + /// Returns the current seek position from the start of the stream. + /// + /// The value returned is equivalent to `self.seek(SeekFrom::Current(0))` + /// but does not flush the internal buffer. Due to this optimization the + /// function does not guarantee that calling `.into_inner()` immediately + /// afterwards will yield the underlying reader at the same position. Use + /// [`BufReader::seek`] instead if you require that guarantee. + /// + /// # Panics + /// + /// This function will panic if the position of the inner reader is smaller + /// than the amount of buffered data. That can happen if the inner reader + /// has an incorrect implementation of [`Seek::stream_position`], or if the + /// position has gone out of sync due to calling [`Seek::seek`] directly on + /// the underlying reader. + /// + /// # Example + /// + /// ```no_run + /// #![feature(seek_convenience)] + /// use std::{ + /// io::{self, BufRead, BufReader, Seek}, + /// fs::File, + /// }; + /// + /// fn main() -> io::Result<()> { + /// let mut f = BufReader::new(File::open("foo.txt")?); + /// + /// let before = f.stream_position()?; + /// f.read_line(&mut String::new())?; + /// let after = f.stream_position()?; + /// + /// println!("The first line was {} bytes long", after - before); + /// Ok(()) + /// } + /// ``` + fn stream_position(&mut self) -> io::Result { + let remainder = (self.cap - self.pos) as u64; + self.inner.stream_position().map(|pos| { + pos.checked_sub(remainder).expect( + "overflow when subtracting remaining buffer size from inner stream position", + ) + }) + } } /// Wraps a writer and buffers its output. @@ -517,33 +565,81 @@ impl BufWriter { BufWriter { inner: Some(inner), buf: Vec::with_capacity(capacity), panicked: false } } + /// Send data in our local buffer into the inner writer, looping as + /// necessary until either it's all been sent or an error occurs. + /// + /// Because all the data in the buffer has been reported to our owner as + /// "successfully written" (by returning nonzero success values from + /// `write`), any 0-length writes from `inner` must be reported as i/o + /// errors from this method. fn flush_buf(&mut self) -> io::Result<()> { - let mut written = 0; - let len = self.buf.len(); - let mut ret = Ok(()); - while written < len { + /// Helper struct to ensure the buffer is updated after all the writes + /// are complete. It tracks the number of written bytes and drains them + /// all from the front of the buffer when dropped. + struct BufGuard<'a> { + buffer: &'a mut Vec, + written: usize, + } + + impl<'a> BufGuard<'a> { + fn new(buffer: &'a mut Vec) -> Self { + Self { buffer, written: 0 } + } + + /// The unwritten part of the buffer + fn remaining(&self) -> &[u8] { + &self.buffer[self.written..] + } + + /// Flag some bytes as removed from the front of the buffer + fn consume(&mut self, amt: usize) { + self.written += amt; + } + + /// true if all of the bytes have been written + fn done(&self) -> bool { + self.written >= self.buffer.len() + } + } + + impl Drop for BufGuard<'_> { + fn drop(&mut self) { + if self.written > 0 { + self.buffer.drain(..self.written); + } + } + } + + let mut guard = BufGuard::new(&mut self.buf); + let inner = self.inner.as_mut().unwrap(); + while !guard.done() { self.panicked = true; - let r = self.inner.as_mut().unwrap().write(&self.buf[written..]); + let r = inner.write(guard.remaining()); self.panicked = false; match r { Ok(0) => { - ret = - Err(Error::new(ErrorKind::WriteZero, "failed to write the buffered data")); - break; + return Err(Error::new( + ErrorKind::WriteZero, + "failed to write the buffered data", + )); } - Ok(n) => written += n, + Ok(n) => guard.consume(n), Err(ref e) if e.kind() == io::ErrorKind::Interrupted => {} - Err(e) => { - ret = Err(e); - break; - } + Err(e) => return Err(e), } } - if written > 0 { - self.buf.drain(..written); - } - ret + Ok(()) + } + + /// Buffer some data without flushing it, regardless of the size of the + /// data. Writes as much as possible without exceeding capacity. Returns + /// the number of bytes written. + fn write_to_buf(&mut self, buf: &[u8]) -> usize { + let available = self.buf.capacity() - self.buf.len(); + let amt_to_buffer = available.min(buf.len()); + self.buf.extend_from_slice(&buf[..amt_to_buffer]); + amt_to_buffer } /// Gets a reference to the underlying writer. @@ -656,13 +752,35 @@ impl Write for BufWriter { if self.buf.len() + buf.len() > self.buf.capacity() { self.flush_buf()?; } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 if buf.len() >= self.buf.capacity() { self.panicked = true; let r = self.get_mut().write(buf); self.panicked = false; r } else { - self.buf.write(buf) + self.buf.extend_from_slice(buf); + Ok(buf.len()) + } + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + // Normally, `write_all` just calls `write` in a loop. We can do better + // by calling `self.get_mut().write_all()` directly, which avoids + // round trips through the buffer in the event of a series of partial + // writes in some circumstances. + if self.buf.len() + buf.len() > self.buf.capacity() { + self.flush_buf()?; + } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 + if buf.len() >= self.buf.capacity() { + self.panicked = true; + let r = self.get_mut().write_all(buf); + self.panicked = false; + r + } else { + self.buf.extend_from_slice(buf); + Ok(()) } } @@ -671,13 +789,15 @@ impl Write for BufWriter { if self.buf.len() + total_len > self.buf.capacity() { self.flush_buf()?; } + // FIXME: Why no len > capacity? Why not buffer len == capacity? #72919 if total_len >= self.buf.capacity() { self.panicked = true; let r = self.get_mut().write_vectored(bufs); self.panicked = false; r } else { - self.buf.write_vectored(bufs) + bufs.iter().for_each(|b| self.buf.extend_from_slice(b)); + Ok(total_len) } } @@ -709,7 +829,8 @@ impl Seek for BufWriter { /// /// Seeking always writes out the internal buffer before seeking. fn seek(&mut self, pos: SeekFrom) -> io::Result { - self.flush_buf().and_then(|_| self.get_mut().seek(pos)) + self.flush_buf()?; + self.get_mut().seek(pos) } } @@ -816,6 +937,274 @@ impl fmt::Display for IntoInnerError { } } +/// Private helper struct for implementing the line-buffered writing logic. +/// This shim temporarily wraps a BufWriter, and uses its internals to +/// implement a line-buffered writer (specifically by using the internal +/// methods like write_to_buf and flush_buf). In this way, a more +/// efficient abstraction can be created than one that only had access to +/// `write` and `flush`, without needlessly duplicating a lot of the +/// implementation details of BufWriter. This also allows existing +/// `BufWriters` to be temporarily given line-buffering logic; this is what +/// enables Stdout to be alternately in line-buffered or block-buffered mode. +#[derive(Debug)] +pub(super) struct LineWriterShim<'a, W: Write> { + buffer: &'a mut BufWriter, +} + +impl<'a, W: Write> LineWriterShim<'a, W> { + pub fn new(buffer: &'a mut BufWriter) -> Self { + Self { buffer } + } + + /// Get a mutable reference to the inner writer (that is, the writer + /// wrapped by the BufWriter). Be careful with this writer, as writes to + /// it will bypass the buffer. + fn inner_mut(&mut self) -> &mut W { + self.buffer.get_mut() + } + + /// Get the content currently buffered in self.buffer + fn buffered(&self) -> &[u8] { + self.buffer.buffer() + } + + /// Flush the buffer iff the last byte is a newline (indicating that an + /// earlier write only succeeded partially, and we want to retry flushing + /// the buffered line before continuing with a subsequent write) + fn flush_if_completed_line(&mut self) -> io::Result<()> { + match self.buffered().last().copied() { + Some(b'\n') => self.buffer.flush_buf(), + _ => Ok(()), + } + } +} + +impl<'a, W: Write> Write for LineWriterShim<'a, W> { + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. Returns the number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. If that write only reports a partial + /// success, the remaining data will be buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it ends with a + /// newline, even if the incoming data does not contain any newlines. + fn write(&mut self, buf: &[u8]) -> io::Result { + let newline_idx = match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + return self.buffer.write(buf); + } + // Otherwise, arrange for the lines to be written directly to the + // inner writer. + Some(newline_idx) => newline_idx + 1, + }; + + // Flush existing content to prepare for our write. We have to do this + // before attempting to write `buf` in order to maintain consistency; + // if we add `buf` to the buffer then try to flush it all at once, + // we're obligated to return Ok(), which would mean suppressing any + // errors that occur during flush. + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let lines = &buf[..newline_idx]; + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.buffer.panicked here. + let flushed = self.inner_mut().write(lines)?; + + // If buffer returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Now that the write has succeeded, buffer the rest (or as much of + // the rest as possible). If there were any unwritten newlines, we + // only buffer out to the last unwritten newline that fits in the + // buffer; this helps prevent flushing partial lines on subsequent + // calls to LineWriterShim::write. + + // Handle the cases in order of most-common to least-common, under + // the presumption that most writes succeed in totality, and that most + // writes are smaller than the buffer. + // - Is this a partial line (ie, no newlines left in the unwritten tail) + // - If not, does the data out to the last unwritten newline fit in + // the buffer? + // - If not, scan for the last newline that *does* fit in the buffer + let tail = if flushed >= newline_idx { + &buf[flushed..] + } else if newline_idx - flushed <= self.buffer.capacity() { + &buf[flushed..newline_idx] + } else { + let scan_area = &buf[flushed..]; + let scan_area = &scan_area[..self.buffer.capacity()]; + match memchr::memrchr(b'\n', scan_area) { + Some(newline_idx) => &scan_area[..newline_idx + 1], + None => scan_area, + } + }; + + let buffered = self.buffer.write_to_buf(tail); + Ok(flushed + buffered) + } + + fn flush(&mut self) -> io::Result<()> { + self.buffer.flush() + } + + /// Write some vectored data into this BufReader with line buffering. This + /// means that, if any newlines are present in the data, the data up to + /// and including the buffer containing the last newline is sent directly + /// to the inner writer, and the data after it is buffered. Returns the + /// number of bytes written. + /// + /// This function operates on a "best effort basis"; in keeping with the + /// convention of `Write::write`, it makes at most one attempt to write + /// new data to the underlying writer. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines. + /// + /// Because sorting through an array of `IoSlice` can be a bit convoluted, + /// This method differs from write in the following ways: + /// + /// - It attempts to write the full content of all the buffers up to and + /// including the one containing the last newline. This means that it + /// may attempt to write a partial line, that buffer has data past the + /// newline. + /// - If the write only reports partial success, it does not attempt to + /// find the precise location of the written bytes and buffer the rest. + /// + /// If the underlying vector doesn't support vectored writing, we instead + /// simply write the first non-empty buffer with `write`. This way, we + /// get the benefits of more granular partial-line handling without losing + /// anything in efficiency + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + // If there's no specialized behavior for write_vectored, just use + // write. This has the benefit of more granular partial-line handling. + if !self.is_write_vectored() { + return match bufs.iter().find(|buf| !buf.is_empty()) { + Some(buf) => self.write(buf), + None => Ok(0), + }; + } + + // Find the buffer containing the last newline + let last_newline_buf_idx = bufs + .iter() + .enumerate() + .rev() + .find_map(|(i, buf)| memchr::memchr(b'\n', buf).map(|_| i)); + + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write + let last_newline_buf_idx = match last_newline_buf_idx { + // No newlines; just do a normal buffered write + None => { + self.flush_if_completed_line()?; + return self.buffer.write_vectored(bufs); + } + Some(i) => i, + }; + + // Flush existing content to prepare for our write + self.buffer.flush_buf()?; + + // This is what we're going to try to write directly to the inner + // writer. The rest will be buffered, if nothing goes wrong. + let (lines, tail) = bufs.split_at(last_newline_buf_idx + 1); + + // Write `lines` directly to the inner writer. In keeping with the + // `write` convention, make at most one attempt to add new (unbuffered) + // data. Because this write doesn't touch the BufWriter state directly, + // and the buffer is known to be empty, we don't need to worry about + // self.panicked here. + let flushed = self.inner_mut().write_vectored(lines)?; + + // If inner returns Ok(0), propagate that to the caller without + // doing additional buffering; otherwise we're just guaranteeing + // an "ErrorKind::WriteZero" later. + if flushed == 0 { + return Ok(0); + } + + // Don't try to reconstruct the exact amount written; just bail + // in the event of a partial write + let lines_len = lines.iter().map(|buf| buf.len()).sum(); + if flushed < lines_len { + return Ok(flushed); + } + + // Now that the write has succeeded, buffer the rest (or as much of the + // rest as possible) + let buffered: usize = tail + .iter() + .filter(|buf| !buf.is_empty()) + .map(|buf| self.buffer.write_to_buf(buf)) + .take_while(|&n| n > 0) + .sum(); + + Ok(flushed + buffered) + } + + fn is_write_vectored(&self) -> bool { + self.buffer.is_write_vectored() + } + + /// Write some data into this BufReader with line buffering. This means + /// that, if any newlines are present in the data, the data up to the last + /// newline is sent directly to the underlying writer, and data after it + /// is buffered. + /// + /// Because this function attempts to send completed lines to the underlying + /// writer, it will also flush the existing buffer if it contains any + /// newlines, even if the incoming data does not contain any newlines. + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + match memchr::memrchr(b'\n', buf) { + // If there are no new newlines (that is, if this write is less than + // one line), just do a regular buffered write (which may flush if + // we exceed the inner buffer's size) + None => { + self.flush_if_completed_line()?; + self.buffer.write_all(buf) + } + Some(newline_idx) => { + let (lines, tail) = buf.split_at(newline_idx + 1); + + if self.buffered().is_empty() { + self.inner_mut().write_all(lines)?; + } else { + // If there is any buffered data, we add the incoming lines + // to that buffer before flushing, which saves us at least + // one write call. We can't really do this with `write`, + // since we can't do this *and* not suppress errors *and* + // report a consistent state to the caller in a return + // value, but here in write_all it's fine. + self.buffer.write_all(lines)?; + self.buffer.flush_buf()?; + } + + self.buffer.write_all(tail) + } + } + } +} + /// Wraps a writer and buffers output to it, flushing whenever a newline /// (`0x0a`, `'\n'`) is detected. /// @@ -881,7 +1270,6 @@ impl fmt::Display for IntoInnerError { #[stable(feature = "rust1", since = "1.0.0")] pub struct LineWriter { inner: BufWriter, - need_flush: bool, } impl LineWriter { @@ -922,7 +1310,7 @@ impl LineWriter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn with_capacity(capacity: usize, inner: W) -> LineWriter { - LineWriter { inner: BufWriter::with_capacity(capacity, inner), need_flush: false } + LineWriter { inner: BufWriter::with_capacity(capacity, inner) } } /// Gets a reference to the underlying writer. @@ -996,110 +1384,40 @@ impl LineWriter { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn into_inner(self) -> Result>> { - self.inner.into_inner().map_err(|IntoInnerError(buf, e)| { - IntoInnerError(LineWriter { inner: buf, need_flush: false }, e) - }) + self.inner + .into_inner() + .map_err(|IntoInnerError(buf, e)| IntoInnerError(LineWriter { inner: buf }, e)) } } #[stable(feature = "rust1", since = "1.0.0")] impl Write for LineWriter { fn write(&mut self, buf: &[u8]) -> io::Result { - if self.need_flush { - self.flush()?; - } - - // Find the last newline character in the buffer provided. If found then - // we're going to write all the data up to that point and then flush, - // otherwise we just write the whole block to the underlying writer. - let i = match memchr::memrchr(b'\n', buf) { - Some(i) => i, - None => return self.inner.write(buf), - }; - - // Ok, we're going to write a partial amount of the data given first - // followed by flushing the newline. After we've successfully written - // some data then we *must* report that we wrote that data, so future - // errors are ignored. We set our internal `need_flush` flag, though, in - // case flushing fails and we need to try it first next time. - let n = self.inner.write(&buf[..=i])?; - self.need_flush = true; - if self.flush().is_err() || n != i + 1 { - return Ok(n); - } - - // At this point we successfully wrote `i + 1` bytes and flushed it out, - // meaning that the entire line is now flushed out on the screen. While - // we can attempt to finish writing the rest of the data provided. - // Remember though that we ignore errors here as we've successfully - // written data, so we need to report that. - match self.inner.write(&buf[i + 1..]) { - Ok(i) => Ok(n + i), - Err(_) => Ok(n), - } - } - - // Vectored writes are very similar to the writes above, but adjusted for - // the list of buffers that we have to write. - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - if self.need_flush { - self.flush()?; - } - - // Find the last newline, and failing that write the whole buffer - let last_newline = bufs.iter().enumerate().rev().find_map(|(i, buf)| { - let pos = memchr::memrchr(b'\n', buf)?; - Some((i, pos)) - }); - let (i, j) = match last_newline { - Some(pair) => pair, - None => return self.inner.write_vectored(bufs), - }; - let (prefix, suffix) = bufs.split_at(i); - let (buf, suffix) = suffix.split_at(1); - let buf = &buf[0]; - - // Write everything up to the last newline, flushing afterwards. Note - // that only if we finished our entire `write_vectored` do we try the - // subsequent - // `write` - let mut n = 0; - let prefix_amt = prefix.iter().map(|i| i.len()).sum(); - if prefix_amt > 0 { - n += self.inner.write_vectored(prefix)?; - self.need_flush = true; - } - if n == prefix_amt { - match self.inner.write(&buf[..=j]) { - Ok(m) => n += m, - Err(e) if n == 0 => return Err(e), - Err(_) => return Ok(n), - } - self.need_flush = true; - } - if self.flush().is_err() || n != j + 1 + prefix_amt { - return Ok(n); - } - - // ... and now write out everything remaining - match self.inner.write(&buf[j + 1..]) { - Ok(i) => n += i, - Err(_) => return Ok(n), - } - - if suffix.iter().map(|s| s.len()).sum::() == 0 { - return Ok(n); - } - match self.inner.write_vectored(suffix) { - Ok(i) => Ok(n + i), - Err(_) => Ok(n), - } + LineWriterShim::new(&mut self.inner).write(buf) } fn flush(&mut self) -> io::Result<()> { - self.inner.flush()?; - self.need_flush = false; - Ok(()) + self.inner.flush() + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + LineWriterShim::new(&mut self.inner).write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + self.inner.is_write_vectored() + } + + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all(buf) + } + + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_all_vectored(bufs) + } + + fn write_fmt(&mut self, fmt: fmt::Arguments<'_>) -> io::Result<()> { + LineWriterShim::new(&mut self.inner).write_fmt(fmt) } } @@ -1118,584 +1436,3 @@ where .finish() } } - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - use crate::io::{self, BufReader, BufWriter, IoSlice, LineWriter, SeekFrom}; - use crate::sync::atomic::{AtomicUsize, Ordering}; - use crate::thread; - - /// A dummy reader intended at testing short-reads propagation. - pub struct ShortReader { - lengths: Vec, - } - - impl Read for ShortReader { - fn read(&mut self, _: &mut [u8]) -> io::Result { - if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) } - } - } - - #[test] - fn test_buffered_reader() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, inner); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 3); - assert_eq!(buf, [5, 6, 7]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 2); - assert_eq!(buf, [0, 1]); - assert_eq!(reader.buffer(), []); - - let mut buf = [0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [2]); - assert_eq!(reader.buffer(), [3]); - - let mut buf = [0, 0, 0]; - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [3, 0, 0]); - assert_eq!(reader.buffer(), []); - - let nread = reader.read(&mut buf); - assert_eq!(nread.unwrap(), 1); - assert_eq!(buf, [4, 0, 0]); - assert_eq!(reader.buffer(), []); - - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_buffered_reader_seek() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); - - assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); - assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); - reader.consume(1); - assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); - } - - #[test] - fn test_buffered_reader_seek_relative() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); - - assert!(reader.seek_relative(3).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(0).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(1).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[1][..])); - assert!(reader.seek_relative(-1).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); - assert!(reader.seek_relative(2).is_ok()); - assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); - } - - #[test] - fn test_buffered_reader_invalidated_after_read() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); - - assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); - reader.consume(3); - - let mut buffer = [0, 0, 0, 0, 0]; - assert_eq!(reader.read(&mut buffer).ok(), Some(5)); - assert_eq!(buffer, [0, 1, 2, 3, 4]); - - assert!(reader.seek_relative(-2).is_ok()); - let mut buffer = [0, 0]; - assert_eq!(reader.read(&mut buffer).ok(), Some(2)); - assert_eq!(buffer, [3, 4]); - } - - #[test] - fn test_buffered_reader_invalidated_after_seek() { - let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; - let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); - - assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); - reader.consume(3); - - assert!(reader.seek(SeekFrom::Current(5)).is_ok()); - - assert!(reader.seek_relative(-2).is_ok()); - let mut buffer = [0, 0]; - assert_eq!(reader.read(&mut buffer).ok(), Some(2)); - assert_eq!(buffer, [3, 4]); - } - - #[test] - fn test_buffered_reader_seek_underflow() { - // gimmick reader that yields its position modulo 256 for each byte - struct PositionReader { - pos: u64, - } - impl Read for PositionReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = buf.len(); - for x in buf { - *x = self.pos as u8; - self.pos = self.pos.wrapping_add(1); - } - Ok(len) - } - } - impl Seek for PositionReader { - fn seek(&mut self, pos: SeekFrom) -> io::Result { - match pos { - SeekFrom::Start(n) => { - self.pos = n; - } - SeekFrom::Current(n) => { - self.pos = self.pos.wrapping_add(n as u64); - } - SeekFrom::End(n) => { - self.pos = u64::MAX.wrapping_add(n as u64); - } - } - Ok(self.pos) - } - } - - let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); - assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // the following seek will require two underlying seeks - let expected = 9223372036854775802; - assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected)); - assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); - // seeking to 0 should empty the buffer. - assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); - assert_eq!(reader.get_ref().pos, expected); - } - - #[test] - fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() { - // gimmick reader that returns Err after first seek - struct ErrAfterFirstSeekReader { - first_seek: bool, - } - impl Read for ErrAfterFirstSeekReader { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - for x in &mut *buf { - *x = 0; - } - Ok(buf.len()) - } - } - impl Seek for ErrAfterFirstSeekReader { - fn seek(&mut self, _: SeekFrom) -> io::Result { - if self.first_seek { - self.first_seek = false; - Ok(0) - } else { - Err(io::Error::new(io::ErrorKind::Other, "oh no!")) - } - } - } - - let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true }); - assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..])); - - // The following seek will require two underlying seeks. The first will - // succeed but the second will fail. This should still invalidate the - // buffer. - assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err()); - assert_eq!(reader.buffer().len(), 0); - } - - #[test] - fn test_buffered_writer() { - let inner = Vec::new(); - let mut writer = BufWriter::with_capacity(2, inner); - - writer.write(&[0, 1]).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[2]).unwrap(); - assert_eq!(writer.buffer(), [2]); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.write(&[3]).unwrap(); - assert_eq!(writer.buffer(), [2, 3]); - assert_eq!(*writer.get_ref(), [0, 1]); - - writer.flush().unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[4]).unwrap(); - writer.write(&[5]).unwrap(); - assert_eq!(writer.buffer(), [4, 5]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); - - writer.write(&[6]).unwrap(); - assert_eq!(writer.buffer(), [6]); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); - - writer.write(&[7, 8]).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); - - writer.write(&[9, 10, 11]).unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - - writer.flush().unwrap(); - assert_eq!(writer.buffer(), []); - assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); - } - - #[test] - fn test_buffered_writer_inner_flushes() { - let mut w = BufWriter::with_capacity(3, Vec::new()); - w.write(&[0, 1]).unwrap(); - assert_eq!(*w.get_ref(), []); - let w = w.into_inner().unwrap(); - assert_eq!(w, [0, 1]); - } - - #[test] - fn test_buffered_writer_seek() { - let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); - w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); - w.write_all(&[6, 7]).unwrap(); - assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); - assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); - assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); - w.write_all(&[8, 9]).unwrap(); - assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); - } - - #[test] - fn test_read_until() { - let inner: &[u8] = &[0, 1, 2, 1, 0]; - let mut reader = BufReader::with_capacity(2, inner); - let mut v = Vec::new(); - reader.read_until(0, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(2, &mut v).unwrap(); - assert_eq!(v, [1, 2]); - v.truncate(0); - reader.read_until(1, &mut v).unwrap(); - assert_eq!(v, [1]); - v.truncate(0); - reader.read_until(8, &mut v).unwrap(); - assert_eq!(v, [0]); - v.truncate(0); - reader.read_until(9, &mut v).unwrap(); - assert_eq!(v, []); - } - - #[test] - fn test_line_buffer_fail_flush() { - // Issue #32085 - struct FailFlushWriter<'a>(&'a mut Vec); - - impl Write for FailFlushWriter<'_> { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.0.extend_from_slice(buf); - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::new(io::ErrorKind::Other, "flush failed")) - } - } - - let mut buf = Vec::new(); - { - let mut writer = LineWriter::new(FailFlushWriter(&mut buf)); - let to_write = b"abc\ndef"; - if let Ok(written) = writer.write(to_write) { - assert!(written < to_write.len(), "didn't flush on new line"); - // PASS - return; - } - } - assert!(buf.is_empty(), "write returned an error but wrote data"); - } - - #[test] - fn test_line_buffer() { - let mut writer = LineWriter::new(Vec::new()); - writer.write(&[0]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.write(&[1]).unwrap(); - assert_eq!(*writer.get_ref(), []); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1]); - writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); - writer.flush().unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); - writer.write(&[3, b'\n']).unwrap(); - assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); - } - - #[test] - fn test_read_line() { - let in_buf: &[u8] = b"a\nb\nc"; - let mut reader = BufReader::with_capacity(2, in_buf); - let mut s = String::new(); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "a\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "b\n"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, "c"); - s.truncate(0); - reader.read_line(&mut s).unwrap(); - assert_eq!(s, ""); - } - - #[test] - fn test_lines() { - let in_buf: &[u8] = b"a\nb\nc"; - let reader = BufReader::with_capacity(2, in_buf); - let mut it = reader.lines(); - assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); - assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); - assert!(it.next().is_none()); - } - - #[test] - fn test_short_reads() { - let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] }; - let mut reader = BufReader::new(inner); - let mut buf = [0, 0]; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - #[should_panic] - fn dont_panic_in_drop_on_panicked_flush() { - struct FailFlushWriter; - - impl Write for FailFlushWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - Ok(buf.len()) - } - fn flush(&mut self) -> io::Result<()> { - Err(io::Error::last_os_error()) - } - } - - let writer = FailFlushWriter; - let _writer = BufWriter::new(writer); - - // If writer panics *again* due to the flush error then the process will - // abort. - panic!(); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn panic_in_write_doesnt_flush_in_drop() { - static WRITES: AtomicUsize = AtomicUsize::new(0); - - struct PanicWriter; - - impl Write for PanicWriter { - fn write(&mut self, _: &[u8]) -> io::Result { - WRITES.fetch_add(1, Ordering::SeqCst); - panic!(); - } - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - } - - thread::spawn(|| { - let mut writer = BufWriter::new(PanicWriter); - let _ = writer.write(b"hello world"); - let _ = writer.flush(); - }) - .join() - .unwrap_err(); - - assert_eq!(WRITES.load(Ordering::SeqCst), 1); - } - - #[bench] - fn bench_buffered_reader(b: &mut test::Bencher) { - b.iter(|| BufReader::new(io::empty())); - } - - #[bench] - fn bench_buffered_writer(b: &mut test::Bencher) { - b.iter(|| BufWriter::new(io::sink())); - } - - struct AcceptOneThenFail { - written: bool, - flushed: bool, - } - - impl Write for AcceptOneThenFail { - fn write(&mut self, data: &[u8]) -> io::Result { - if !self.written { - assert_eq!(data, b"a\nb\n"); - self.written = true; - Ok(data.len()) - } else { - Err(io::Error::new(io::ErrorKind::NotFound, "test")) - } - } - - fn flush(&mut self) -> io::Result<()> { - assert!(self.written); - assert!(!self.flushed); - self.flushed = true; - Err(io::Error::new(io::ErrorKind::Other, "test")) - } - } - - #[test] - fn erroneous_flush_retried() { - let a = AcceptOneThenFail { written: false, flushed: false }; - - let mut l = LineWriter::new(a); - assert_eq!(l.write(b"a\nb\na").unwrap(), 4); - assert!(l.get_ref().written); - assert!(l.get_ref().flushed); - l.get_mut().flushed = false; - - assert_eq!(l.write(b"a").unwrap_err().kind(), io::ErrorKind::Other) - } - - #[test] - fn line_vectored() { - let mut a = LineWriter::new(Vec::new()); - assert_eq!( - a.write_vectored(&[ - IoSlice::new(&[]), - IoSlice::new(b"\n"), - IoSlice::new(&[]), - IoSlice::new(b"a"), - ]) - .unwrap(), - 2, - ); - assert_eq!(a.get_ref(), b"\n"); - - assert_eq!( - a.write_vectored(&[ - IoSlice::new(&[]), - IoSlice::new(b"b"), - IoSlice::new(&[]), - IoSlice::new(b"a"), - IoSlice::new(&[]), - IoSlice::new(b"c"), - ]) - .unwrap(), - 3, - ); - assert_eq!(a.get_ref(), b"\n"); - a.flush().unwrap(); - assert_eq!(a.get_ref(), b"\nabac"); - assert_eq!(a.write_vectored(&[]).unwrap(), 0); - assert_eq!( - a.write_vectored(&[ - IoSlice::new(&[]), - IoSlice::new(&[]), - IoSlice::new(&[]), - IoSlice::new(&[]), - ]) - .unwrap(), - 0, - ); - assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3); - assert_eq!(a.get_ref(), b"\nabaca\n"); - } - - #[test] - fn line_vectored_partial_and_errors() { - enum Call { - Write { inputs: Vec<&'static [u8]>, output: io::Result }, - Flush { output: io::Result<()> }, - } - struct Writer { - calls: Vec, - } - - impl Write for Writer { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.write_vectored(&[IoSlice::new(buf)]) - } - - fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result { - match self.calls.pop().unwrap() { - Call::Write { inputs, output } => { - assert_eq!(inputs, buf.iter().map(|b| &**b).collect::>()); - output - } - _ => panic!("unexpected call to write"), - } - } - - fn flush(&mut self) -> io::Result<()> { - match self.calls.pop().unwrap() { - Call::Flush { output } => output, - _ => panic!("unexpected call to flush"), - } - } - } - - impl Drop for Writer { - fn drop(&mut self) { - if !thread::panicking() { - assert_eq!(self.calls.len(), 0); - } - } - } - - // partial writes keep going - let mut a = LineWriter::new(Writer { calls: Vec::new() }); - a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap(); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"bcx\n"], output: Ok(4) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"abcx\n"], output: Ok(1) }); - a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap(); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.flush().unwrap(); - - // erroneous writes stop and don't write more - a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Err(err()) }); - assert_eq!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).unwrap(), 2); - a.get_mut().calls.push(Call::Flush { output: Ok(()) }); - a.get_mut().calls.push(Call::Write { inputs: vec![b"x\n"], output: Ok(2) }); - a.flush().unwrap(); - - fn err() -> io::Error { - io::Error::new(io::ErrorKind::Other, "x") - } - } -} diff --git a/library/std/src/io/buffered/tests.rs b/library/std/src/io/buffered/tests.rs new file mode 100644 index 0000000000..66a64f667b --- /dev/null +++ b/library/std/src/io/buffered/tests.rs @@ -0,0 +1,958 @@ +use crate::io::prelude::*; +use crate::io::{self, BufReader, BufWriter, ErrorKind, IoSlice, LineWriter, SeekFrom}; +use crate::panic; +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::thread; + +/// A dummy reader intended at testing short-reads propagation. +pub struct ShortReader { + lengths: Vec, +} + +// FIXME: rustfmt and tidy disagree about the correct formatting of this +// function. This leads to issues for users with editors configured to +// rustfmt-on-save. +impl Read for ShortReader { + fn read(&mut self, _: &mut [u8]) -> io::Result { + if self.lengths.is_empty() { Ok(0) } else { Ok(self.lengths.remove(0)) } + } +} + +#[test] +fn test_buffered_reader() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, inner); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 3); + assert_eq!(buf, [5, 6, 7]); + assert_eq!(reader.buffer(), []); + + let mut buf = [0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 2); + assert_eq!(buf, [0, 1]); + assert_eq!(reader.buffer(), []); + + let mut buf = [0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + assert_eq!(buf, [2]); + assert_eq!(reader.buffer(), [3]); + + let mut buf = [0, 0, 0]; + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + assert_eq!(buf, [3, 0, 0]); + assert_eq!(reader.buffer(), []); + + let nread = reader.read(&mut buf); + assert_eq!(nread.unwrap(), 1); + assert_eq!(buf, [4, 0, 0]); + assert_eq!(reader.buffer(), []); + + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_buffered_reader_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(3)); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert_eq!(reader.seek(SeekFrom::Current(1)).ok(), Some(4)); + assert_eq!(reader.fill_buf().ok(), Some(&[1, 2][..])); + reader.consume(1); + assert_eq!(reader.seek(SeekFrom::Current(-2)).ok(), Some(3)); +} + +#[test] +fn test_buffered_reader_seek_relative() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert!(reader.seek_relative(3).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(0).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(1).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[1][..])); + assert!(reader.seek_relative(-1).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(2).is_ok()); + assert_eq!(reader.fill_buf().ok(), Some(&[2, 3][..])); +} + +#[test] +fn test_buffered_reader_stream_position() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(2, io::Cursor::new(inner)); + + assert_eq!(reader.stream_position().ok(), Some(0)); + assert_eq!(reader.seek(SeekFrom::Start(3)).ok(), Some(3)); + assert_eq!(reader.stream_position().ok(), Some(3)); + // relative seeking within the buffer and reading position should keep the buffer + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1][..])); + assert!(reader.seek_relative(0).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(3)); + assert_eq!(reader.buffer(), &[0, 1][..]); + assert!(reader.seek_relative(1).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(4)); + assert_eq!(reader.buffer(), &[1][..]); + assert!(reader.seek_relative(-1).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(3)); + assert_eq!(reader.buffer(), &[0, 1][..]); + // relative seeking outside the buffer will discard it + assert!(reader.seek_relative(2).is_ok()); + assert_eq!(reader.stream_position().ok(), Some(5)); + assert_eq!(reader.buffer(), &[][..]); +} + +#[test] +fn test_buffered_reader_stream_position_panic() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(4, io::Cursor::new(inner)); + + // cause internal buffer to be filled but read only partially + let mut buffer = [0, 0]; + assert!(reader.read_exact(&mut buffer).is_ok()); + // rewinding the internal reader will cause buffer to loose sync + let inner = reader.get_mut(); + assert!(inner.seek(SeekFrom::Start(0)).is_ok()); + // overflow when subtracting the remaining buffer size from current position + let result = panic::catch_unwind(panic::AssertUnwindSafe(|| reader.stream_position().ok())); + assert!(result.is_err()); +} + +#[test] +fn test_buffered_reader_invalidated_after_read() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + let mut buffer = [0, 0, 0, 0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(5)); + assert_eq!(buffer, [0, 1, 2, 3, 4]); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); +} + +#[test] +fn test_buffered_reader_invalidated_after_seek() { + let inner: &[u8] = &[5, 6, 7, 0, 1, 2, 3, 4]; + let mut reader = BufReader::with_capacity(3, io::Cursor::new(inner)); + + assert_eq!(reader.fill_buf().ok(), Some(&[5, 6, 7][..])); + reader.consume(3); + + assert!(reader.seek(SeekFrom::Current(5)).is_ok()); + + assert!(reader.seek_relative(-2).is_ok()); + let mut buffer = [0, 0]; + assert_eq!(reader.read(&mut buffer).ok(), Some(2)); + assert_eq!(buffer, [3, 4]); +} + +#[test] +fn test_buffered_reader_seek_underflow() { + // gimmick reader that yields its position modulo 256 for each byte + struct PositionReader { + pos: u64, + } + impl Read for PositionReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = buf.len(); + for x in buf { + *x = self.pos as u8; + self.pos = self.pos.wrapping_add(1); + } + Ok(len) + } + } + impl Seek for PositionReader { + fn seek(&mut self, pos: SeekFrom) -> io::Result { + match pos { + SeekFrom::Start(n) => { + self.pos = n; + } + SeekFrom::Current(n) => { + self.pos = self.pos.wrapping_add(n as u64); + } + SeekFrom::End(n) => { + self.pos = u64::MAX.wrapping_add(n as u64); + } + } + Ok(self.pos) + } + } + + let mut reader = BufReader::with_capacity(5, PositionReader { pos: 0 }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 1, 2, 3, 4][..])); + assert_eq!(reader.seek(SeekFrom::End(-5)).ok(), Some(u64::MAX - 5)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // the following seek will require two underlying seeks + let expected = 9223372036854775802; + assert_eq!(reader.seek(SeekFrom::Current(i64::MIN)).ok(), Some(expected)); + assert_eq!(reader.fill_buf().ok().map(|s| s.len()), Some(5)); + // seeking to 0 should empty the buffer. + assert_eq!(reader.seek(SeekFrom::Current(0)).ok(), Some(expected)); + assert_eq!(reader.get_ref().pos, expected); +} + +#[test] +fn test_buffered_reader_seek_underflow_discard_buffer_between_seeks() { + // gimmick reader that returns Err after first seek + struct ErrAfterFirstSeekReader { + first_seek: bool, + } + impl Read for ErrAfterFirstSeekReader { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + for x in &mut *buf { + *x = 0; + } + Ok(buf.len()) + } + } + impl Seek for ErrAfterFirstSeekReader { + fn seek(&mut self, _: SeekFrom) -> io::Result { + if self.first_seek { + self.first_seek = false; + Ok(0) + } else { + Err(io::Error::new(io::ErrorKind::Other, "oh no!")) + } + } + } + + let mut reader = BufReader::with_capacity(5, ErrAfterFirstSeekReader { first_seek: true }); + assert_eq!(reader.fill_buf().ok(), Some(&[0, 0, 0, 0, 0][..])); + + // The following seek will require two underlying seeks. The first will + // succeed but the second will fail. This should still invalidate the + // buffer. + assert!(reader.seek(SeekFrom::Current(i64::MIN)).is_err()); + assert_eq!(reader.buffer().len(), 0); +} + +#[test] +fn test_buffered_writer() { + let inner = Vec::new(); + let mut writer = BufWriter::with_capacity(2, inner); + + writer.write(&[0, 1]).unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[2]).unwrap(); + assert_eq!(writer.buffer(), [2]); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.write(&[3]).unwrap(); + assert_eq!(writer.buffer(), [2, 3]); + assert_eq!(*writer.get_ref(), [0, 1]); + + writer.flush().unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[4]).unwrap(); + writer.write(&[5]).unwrap(); + assert_eq!(writer.buffer(), [4, 5]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3]); + + writer.write(&[6]).unwrap(); + assert_eq!(writer.buffer(), [6]); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5]); + + writer.write(&[7, 8]).unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8]); + + writer.write(&[9, 10, 11]).unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); + + writer.flush().unwrap(); + assert_eq!(writer.buffer(), []); + assert_eq!(*writer.get_ref(), [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]); +} + +#[test] +fn test_buffered_writer_inner_flushes() { + let mut w = BufWriter::with_capacity(3, Vec::new()); + w.write(&[0, 1]).unwrap(); + assert_eq!(*w.get_ref(), []); + let w = w.into_inner().unwrap(); + assert_eq!(w, [0, 1]); +} + +#[test] +fn test_buffered_writer_seek() { + let mut w = BufWriter::with_capacity(3, io::Cursor::new(Vec::new())); + w.write_all(&[0, 1, 2, 3, 4, 5]).unwrap(); + w.write_all(&[6, 7]).unwrap(); + assert_eq!(w.seek(SeekFrom::Current(0)).ok(), Some(8)); + assert_eq!(&w.get_ref().get_ref()[..], &[0, 1, 2, 3, 4, 5, 6, 7][..]); + assert_eq!(w.seek(SeekFrom::Start(2)).ok(), Some(2)); + w.write_all(&[8, 9]).unwrap(); + assert_eq!(&w.into_inner().unwrap().into_inner()[..], &[0, 1, 8, 9, 4, 5, 6, 7]); +} + +#[test] +fn test_read_until() { + let inner: &[u8] = &[0, 1, 2, 1, 0]; + let mut reader = BufReader::with_capacity(2, inner); + let mut v = Vec::new(); + reader.read_until(0, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(2, &mut v).unwrap(); + assert_eq!(v, [1, 2]); + v.truncate(0); + reader.read_until(1, &mut v).unwrap(); + assert_eq!(v, [1]); + v.truncate(0); + reader.read_until(8, &mut v).unwrap(); + assert_eq!(v, [0]); + v.truncate(0); + reader.read_until(9, &mut v).unwrap(); + assert_eq!(v, []); +} + +#[test] +fn test_line_buffer() { + let mut writer = LineWriter::new(Vec::new()); + writer.write(&[0]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.write(&[1]).unwrap(); + assert_eq!(*writer.get_ref(), []); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1]); + writer.write(&[0, b'\n', 1, b'\n', 2]).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n']); + writer.flush().unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2]); + writer.write(&[3, b'\n']).unwrap(); + assert_eq!(*writer.get_ref(), [0, 1, 0, b'\n', 1, b'\n', 2, 3, b'\n']); +} + +#[test] +fn test_read_line() { + let in_buf: &[u8] = b"a\nb\nc"; + let mut reader = BufReader::with_capacity(2, in_buf); + let mut s = String::new(); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "a\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "b\n"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, "c"); + s.truncate(0); + reader.read_line(&mut s).unwrap(); + assert_eq!(s, ""); +} + +#[test] +fn test_lines() { + let in_buf: &[u8] = b"a\nb\nc"; + let reader = BufReader::with_capacity(2, in_buf); + let mut it = reader.lines(); + assert_eq!(it.next().unwrap().unwrap(), "a".to_string()); + assert_eq!(it.next().unwrap().unwrap(), "b".to_string()); + assert_eq!(it.next().unwrap().unwrap(), "c".to_string()); + assert!(it.next().is_none()); +} + +#[test] +fn test_short_reads() { + let inner = ShortReader { lengths: vec![0, 1, 2, 0, 1, 0] }; + let mut reader = BufReader::new(inner); + let mut buf = [0, 0]; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +#[should_panic] +fn dont_panic_in_drop_on_panicked_flush() { + struct FailFlushWriter; + + impl Write for FailFlushWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + fn flush(&mut self) -> io::Result<()> { + Err(io::Error::last_os_error()) + } + } + + let writer = FailFlushWriter; + let _writer = BufWriter::new(writer); + + // If writer panics *again* due to the flush error then the process will + // abort. + panic!(); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn panic_in_write_doesnt_flush_in_drop() { + static WRITES: AtomicUsize = AtomicUsize::new(0); + + struct PanicWriter; + + impl Write for PanicWriter { + fn write(&mut self, _: &[u8]) -> io::Result { + WRITES.fetch_add(1, Ordering::SeqCst); + panic!(); + } + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } + } + + thread::spawn(|| { + let mut writer = BufWriter::new(PanicWriter); + let _ = writer.write(b"hello world"); + let _ = writer.flush(); + }) + .join() + .unwrap_err(); + + assert_eq!(WRITES.load(Ordering::SeqCst), 1); +} + +#[bench] +fn bench_buffered_reader(b: &mut test::Bencher) { + b.iter(|| BufReader::new(io::empty())); +} + +#[bench] +fn bench_buffered_writer(b: &mut test::Bencher) { + b.iter(|| BufWriter::new(io::sink())); +} + +/// A simple `Write` target, designed to be wrapped by `LineWriter` / +/// `BufWriter` / etc, that can have its `write` & `flush` behavior +/// configured +#[derive(Default, Clone)] +struct ProgrammableSink { + // 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, + + // If true, flushes will always be an error + pub always_flush_error: bool, + + // If set, only up to this number of bytes will be written in a single + // call to `write` + pub accept_prefix: Option, + + // If set, counts down with each write, and writes return an error + // when it hits 0 + pub max_writes: Option, + + // If set, attempting to write when max_writes == Some(0) will be an + // error; otherwise, it will return Ok(0). + pub error_after_max_writes: bool, +} + +impl Write for ProgrammableSink { + fn write(&mut self, data: &[u8]) -> io::Result { + if self.always_write_error { + return Err(io::Error::new(io::ErrorKind::Other, "test - always_write_error")); + } + + match self.max_writes { + Some(0) if self.error_after_max_writes => { + return Err(io::Error::new(io::ErrorKind::Other, "test - max_writes")); + } + Some(0) => return Ok(0), + Some(ref mut count) => *count -= 1, + None => {} + } + + let len = match self.accept_prefix { + None => data.len(), + Some(prefix) => data.len().min(prefix), + }; + + let data = &data[..len]; + self.buffer.extend_from_slice(data); + + Ok(len) + } + + fn flush(&mut self) -> io::Result<()> { + if self.always_flush_error { + Err(io::Error::new(io::ErrorKind::Other, "test - always_flush_error")) + } else { + self.flushed = true; + Ok(()) + } + } +} + +/// Previously the `LineWriter` could successfully write some bytes but +/// then fail to report that it has done so. Additionally, an erroneous +/// flush after a successful write was permanently ignored. +/// +/// Test that a line writer correctly reports the number of written bytes, +/// and that it attempts to flush buffered lines from previous writes +/// before processing new data +/// +/// Regression test for #37807 +#[test] +fn erroneous_flush_retried() { + let writer = ProgrammableSink { + // Only write up to 4 bytes at a time + accept_prefix: Some(4), + + // Accept the first two writes, then error the others + max_writes: Some(2), + error_after_max_writes: true, + + ..Default::default() + }; + + // This should write the first 4 bytes. The rest will be buffered, out + // to the last newline. + let mut writer = LineWriter::new(writer); + assert_eq!(writer.write(b"a\nb\nc\nd\ne").unwrap(), 8); + + // This write should attempt to flush "c\nd\n", then buffer "e". No + // errors should happen here because no further writes should be + // attempted against `writer`. + assert_eq!(writer.write(b"e").unwrap(), 1); + assert_eq!(&writer.get_ref().buffer, b"a\nb\nc\nd\n"); +} + +#[test] +fn line_vectored() { + let mut a = LineWriter::new(Vec::new()); + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(b"\n"), + IoSlice::new(&[]), + IoSlice::new(b"a"), + ]) + .unwrap(), + 2, + ); + assert_eq!(a.get_ref(), b"\n"); + + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(b"b"), + IoSlice::new(&[]), + IoSlice::new(b"a"), + IoSlice::new(&[]), + IoSlice::new(b"c"), + ]) + .unwrap(), + 3, + ); + assert_eq!(a.get_ref(), b"\n"); + a.flush().unwrap(); + assert_eq!(a.get_ref(), b"\nabac"); + assert_eq!(a.write_vectored(&[]).unwrap(), 0); + assert_eq!( + a.write_vectored(&[ + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(&[]), + ]) + .unwrap(), + 0, + ); + assert_eq!(a.write_vectored(&[IoSlice::new(b"a\nb"),]).unwrap(), 3); + assert_eq!(a.get_ref(), b"\nabaca\nb"); +} + +#[test] +fn line_vectored_partial_and_errors() { + use crate::collections::VecDeque; + + enum Call { + Write { inputs: Vec<&'static [u8]>, output: io::Result }, + Flush { output: io::Result<()> }, + } + + #[derive(Default)] + struct Writer { + calls: VecDeque, + } + + impl Write for Writer { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(buf)]) + } + + fn write_vectored(&mut self, buf: &[IoSlice<'_>]) -> io::Result { + match self.calls.pop_front().expect("unexpected call to write") { + Call::Write { inputs, output } => { + assert_eq!(inputs, buf.iter().map(|b| &**b).collect::>()); + output + } + Call::Flush { .. } => panic!("unexpected call to write; expected a flush"), + } + } + + fn is_write_vectored(&self) -> bool { + true + } + + fn flush(&mut self) -> io::Result<()> { + match self.calls.pop_front().expect("Unexpected call to flush") { + Call::Flush { output } => output, + Call::Write { .. } => panic!("unexpected call to flush; expected a write"), + } + } + } + + impl Drop for Writer { + fn drop(&mut self) { + if !thread::panicking() { + assert_eq!(self.calls.len(), 0); + } + } + } + + // partial writes keep going + let mut a = LineWriter::new(Writer::default()); + a.write_vectored(&[IoSlice::new(&[]), IoSlice::new(b"abc")]).unwrap(); + + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"abc"], output: Ok(1) }); + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"bc"], output: Ok(2) }); + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\n"], output: Ok(2) }); + + a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\n")]).unwrap(); + + a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); + a.flush().unwrap(); + + // erroneous writes stop and don't write more + a.get_mut().calls.push_back(Call::Write { inputs: vec![b"x", b"\na"], output: Err(err()) }); + a.get_mut().calls.push_back(Call::Flush { output: Ok(()) }); + assert!(a.write_vectored(&[IoSlice::new(b"x"), IoSlice::new(b"\na")]).is_err()); + a.flush().unwrap(); + + fn err() -> io::Error { + io::Error::new(io::ErrorKind::Other, "x") + } +} + +/// Test that, in cases where vectored writing is not enabled, the +/// LineWriter uses the normal `write` call, which more-correctly handles +/// partial lines +#[test] +fn line_vectored_ignored() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::new(writer); + + let content = [ + IoSlice::new(&[]), + IoSlice::new(b"Line 1\nLine"), + IoSlice::new(b" 2\nLine 3\nL"), + IoSlice::new(&[]), + IoSlice::new(&[]), + IoSlice::new(b"ine 4"), + IoSlice::new(b"\nLine 5\n"), + ]; + + let count = writer.write_vectored(&content).unwrap(); + assert_eq!(count, 11); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + let count = writer.write_vectored(&content[2..]).unwrap(); + assert_eq!(count, 11); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); + + let count = writer.write_vectored(&content[5..]).unwrap(); + assert_eq!(count, 5); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); + + let count = writer.write_vectored(&content[6..]).unwrap(); + assert_eq!(count, 8); + assert_eq!( + writer.get_ref().buffer.as_slice(), + b"Line 1\nLine 2\nLine 3\nLine 4\nLine 5\n".as_ref() + ); +} + +/// Test that, given this input: +/// +/// Line 1\n +/// Line 2\n +/// Line 3\n +/// Line 4 +/// +/// And given a result that only writes to midway through Line 2 +/// +/// That only up to the end of Line 3 is buffered +/// +/// This behavior is desirable because it prevents flushing partial lines +#[test] +fn partial_write_buffers_line() { + let writer = ProgrammableSink { accept_prefix: Some(13), ..Default::default() }; + let mut writer = LineWriter::new(writer); + + assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3\nLine4").unwrap(), 21); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2"); + + assert_eq!(writer.write(b"Line 4").unwrap(), 6); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\n"); +} + +/// Test that, given this input: +/// +/// Line 1\n +/// Line 2\n +/// Line 3 +/// +/// And given that the full write of lines 1 and 2 was successful +/// That data up to Line 3 is buffered +#[test] +fn partial_line_buffered_after_line_write() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::new(writer); + + assert_eq!(writer.write(b"Line 1\nLine 2\nLine 3").unwrap(), 20); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\n"); + + assert!(writer.flush().is_ok()); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3"); +} + +/// Test that, given a partial line that exceeds the length of +/// LineBuffer's buffer (that is, without a trailing newline), that that +/// line is written to the inner writer +#[test] +fn long_line_flushed() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::with_capacity(5, writer); + + assert_eq!(writer.write(b"0123456789").unwrap(), 10); + assert_eq!(&writer.get_ref().buffer, b"0123456789"); +} + +/// Test that, given a very long partial line *after* successfully +/// flushing a complete line, that that line is buffered unconditionally, +/// and no additional writes take place. This assures the property that +/// `write` should make at-most-one attempt to write new data. +#[test] +fn line_long_tail_not_flushed() { + let writer = ProgrammableSink::default(); + let mut writer = LineWriter::with_capacity(5, writer); + + // Assert that Line 1\n is flushed, and 01234 is buffered + assert_eq!(writer.write(b"Line 1\n0123456789").unwrap(), 12); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // Because the buffer is full, this subsequent write will flush it + assert_eq!(writer.write(b"5").unwrap(), 1); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n01234"); +} + +/// Test that, if an attempt to pre-flush buffered data returns Ok(0), +/// this is propagated as an error. +#[test] +fn line_buffer_write0_error() { + let writer = ProgrammableSink { + // Accept one write, then return Ok(0) on subsequent ones + max_writes: Some(1), + + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + // This should write "Line 1\n" and buffer "Partial" + assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // This will attempt to flush "partial", which will return Ok(0), which + // needs to be an error, because we've already informed the client + // that we accepted the write. + let err = writer.write(b" Line End\n").unwrap_err(); + assert_eq!(err.kind(), ErrorKind::WriteZero); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); +} + +/// Test that, if a write returns Ok(0) after a successful pre-flush, this +/// is propagated as Ok(0) +#[test] +fn line_buffer_write0_normal() { + let writer = ProgrammableSink { + // Accept two writes, then return Ok(0) on subsequent ones + max_writes: Some(2), + + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + // This should write "Line 1\n" and buffer "Partial" + assert_eq!(writer.write(b"Line 1\nPartial").unwrap(), 14); + assert_eq!(&writer.get_ref().buffer, b"Line 1\n"); + + // This will flush partial, which will succeed, but then return Ok(0) + // when flushing " Line End\n" + assert_eq!(writer.write(b" Line End\n").unwrap(), 0); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nPartial"); +} + +/// LineWriter has a custom `write_all`; make sure it works correctly +#[test] +fn line_write_all() { + let writer = ProgrammableSink { + // Only write 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + let mut writer = LineWriter::new(writer); + + writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial").unwrap(); + assert_eq!(&writer.get_ref().buffer, b"Line 1\nLine 2\nLine 3\nLine 4\n"); + writer.write_all(b" Line 5\n").unwrap(); + assert_eq!( + writer.get_ref().buffer.as_slice(), + b"Line 1\nLine 2\nLine 3\nLine 4\nPartial Line 5\n".as_ref(), + ); +} + +#[test] +fn line_write_all_error() { + let writer = ProgrammableSink { + // Only accept up to 3 writes of up to 5 bytes each + accept_prefix: Some(5), + max_writes: Some(3), + ..Default::default() + }; + + let mut writer = LineWriter::new(writer); + let res = writer.write_all(b"Line 1\nLine 2\nLine 3\nLine 4\nPartial"); + assert!(res.is_err()); + // An error from write_all leaves everything in an indeterminate state, + // so there's nothing else to test here +} + +/// Under certain circumstances, the old implementation of LineWriter +/// would try to buffer "to the last newline" but be forced to buffer +/// less than that, leading to inappropriate partial line writes. +/// Regression test for that issue. +#[test] +fn partial_multiline_buffering() { + let writer = ProgrammableSink { + // Write only up to 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + + let mut writer = LineWriter::with_capacity(10, writer); + + let content = b"AAAAABBBBB\nCCCCDDDDDD\nEEE"; + + // When content is written, LineWriter will try to write blocks A, B, + // C, and D. Only block A will succeed. Under the old behavior, LineWriter + // would then try to buffer B, C and D, but because its capacity is 10, + // it will only be able to buffer B and C. We don't want to buffer + // partial lines concurrent with whole lines, so the correct behavior + // is to buffer only block B (out to the newline) + assert_eq!(writer.write(content).unwrap(), 11); + assert_eq!(writer.get_ref().buffer, *b"AAAAA"); + + writer.flush().unwrap(); + assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB\n"); +} + +/// Same as test_partial_multiline_buffering, but in the event NO full lines +/// fit in the buffer, just buffer as much as possible +#[test] +fn partial_multiline_buffering_without_full_line() { + let writer = ProgrammableSink { + // Write only up to 5 bytes at a time + accept_prefix: Some(5), + ..Default::default() + }; + + let mut writer = LineWriter::with_capacity(5, writer); + + let content = b"AAAAABBBBBBBBBB\nCCCCC\nDDDDD"; + + // When content is written, LineWriter will try to write blocks A, B, + // and C. Only block A will succeed. Under the old behavior, LineWriter + // would then try to buffer B and C, but because its capacity is 5, + // it will only be able to buffer part of B. Because it's not possible + // for it to buffer any complete lines, it should buffer as much of B as + // possible + assert_eq!(writer.write(content).unwrap(), 10); + assert_eq!(writer.get_ref().buffer, *b"AAAAA"); + + writer.flush().unwrap(); + assert_eq!(writer.get_ref().buffer, *b"AAAAABBBBB"); +} + +#[derive(Debug, Clone, PartialEq, Eq)] +enum RecordedEvent { + Write(String), + Flush, +} + +#[derive(Debug, Clone, Default)] +struct WriteRecorder { + pub events: Vec, +} + +impl Write for WriteRecorder { + fn write(&mut self, buf: &[u8]) -> io::Result { + use crate::str::from_utf8; + + self.events.push(RecordedEvent::Write(from_utf8(buf).unwrap().to_string())); + Ok(buf.len()) + } + + fn flush(&mut self) -> io::Result<()> { + self.events.push(RecordedEvent::Flush); + Ok(()) + } +} + +/// Test that a normal, formatted writeln only results in a single write +/// call to the underlying writer. A naive implementation of +/// LineWriter::write_all results in two writes: one of the buffered data, +/// and another of the final substring in the formatted set +#[test] +fn single_formatted_write() { + let writer = WriteRecorder::default(); + let mut writer = LineWriter::new(writer); + + // Under a naive implementation of LineWriter, this will result in two + // writes: "hello, world" and "!\n", because write() has to flush the + // buffer before attempting to write the last "!\n". write_all shouldn't + // have this limitation. + writeln!(&mut writer, "{}, {}!", "hello", "world").unwrap(); + assert_eq!(writer.get_ref().events, [RecordedEvent::Write("hello, world!\n".to_string())]); +} diff --git a/library/std/src/io/cursor.rs b/library/std/src/io/cursor.rs index 58343f66f3..5733735dc4 100644 --- a/library/std/src/io/cursor.rs +++ b/library/std/src/io/cursor.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::io::prelude::*; use crate::cmp; @@ -447,531 +450,3 @@ impl Write for Cursor> { Ok(()) } } - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; - - #[test] - fn test_vec_writer() { - let mut writer = Vec::new(); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) - .unwrap(), - 3 - ); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(writer, b); - } - - #[test] - fn test_mem_writer() { - let mut writer = Cursor::new(Vec::new()); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) - .unwrap(), - 3 - ); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_mem_mut_writer() { - let mut vec = Vec::new(); - let mut writer = Cursor::new(&mut vec); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) - .unwrap(), - 3 - ); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn test_box_slice_writer() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); - } - - #[test] - fn test_box_slice_writer_vectored() { - let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),]) - .unwrap(), - 7, - ); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write_vectored(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(&**writer.get_ref(), b); - } - - #[test] - fn test_buf_writer() { - let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write(&[8, 9]).unwrap(), 1); - assert_eq!(writer.write(&[10]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_vectored() { - let mut buf = [0 as u8; 9]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!( - writer - .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],) - .unwrap(), - 7, - ); - assert_eq!(writer.position(), 8); - assert_eq!(writer.write_vectored(&[]).unwrap(), 0); - assert_eq!(writer.position(), 8); - - assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); - assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); - } - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_seek() { - let mut buf = [0 as u8; 8]; - { - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[1]).unwrap(), 1); - assert_eq!(writer.position(), 1); - - assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2); - assert_eq!(writer.position(), 2); - assert_eq!(writer.write(&[2]).unwrap(), 1); - assert_eq!(writer.position(), 3); - - assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[3]).unwrap(), 1); - assert_eq!(writer.position(), 2); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.position(), 7); - assert_eq!(writer.write(&[4]).unwrap(), 1); - assert_eq!(writer.position(), 8); - } - let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; - assert_eq!(buf, b); - } - - #[test] - fn test_buf_writer_error() { - let mut buf = [0 as u8; 2]; - let mut writer = Cursor::new(&mut buf[..]); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 1); - assert_eq!(writer.write(&[0, 0]).unwrap(), 0); - } - - #[test] - fn test_mem_reader() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_mem_reader_vectored() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]) - .unwrap(), - 1, - ); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf1 = [0; 4]; - let mut buf2 = [0; 4]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),]) - .unwrap(), - 7, - ); - let b1: &[_] = &[1, 2, 3, 4]; - let b2: &[_] = &[5, 6, 7]; - assert_eq!(buf1, b1); - assert_eq!(&buf2[..3], b2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_boxed_slice_reader() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_boxed_slice_reader_vectored() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); - let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]) - .unwrap(), - 1, - ); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf1 = [0; 4]; - let mut buf2 = [0; 4]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) - .unwrap(), - 7, - ); - let b1: &[_] = &[1, 2, 3, 4]; - let b2: &[_] = &[5, 6, 7]; - assert_eq!(buf1, b1); - assert_eq!(&buf2[..3], b2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn read_to_end() { - let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); - let mut v = Vec::new(); - reader.read_to_end(&mut v).unwrap(); - assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); - } - - #[test] - fn test_slice_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.len(), 7); - let b: &[_] = &[0]; - assert_eq!(&buf[..], b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.len(), 3); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(&buf[..], b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_slice_reader_vectored() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); - let mut buf = [0]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]) - .unwrap(), - 1, - ); - assert_eq!(reader.len(), 7); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf1 = [0; 4]; - let mut buf2 = [0; 4]; - assert_eq!( - reader - .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) - .unwrap(), - 7, - ); - let b1: &[_] = &[1, 2, 3, 4]; - let b2: &[_] = &[5, 6, 7]; - assert_eq!(buf1, b1); - assert_eq!(&buf2[..3], b2); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn test_read_exact() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let reader = &mut &in_buf[..]; - let mut buf = []; - assert!(reader.read_exact(&mut buf).is_ok()); - let mut buf = [8]; - assert!(reader.read_exact(&mut buf).is_ok()); - assert_eq!(buf[0], 0); - assert_eq!(reader.len(), 7); - let mut buf = [0, 0, 0, 0, 0, 0, 0]; - assert!(reader.read_exact(&mut buf).is_ok()); - assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]); - assert_eq!(reader.len(), 0); - let mut buf = [0]; - assert!(reader.read_exact(&mut buf).is_err()); - } - - #[test] - fn test_buf_reader() { - let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; - let mut reader = Cursor::new(&in_buf[..]); - let mut buf = []; - assert_eq!(reader.read(&mut buf).unwrap(), 0); - assert_eq!(reader.position(), 0); - let mut buf = [0]; - assert_eq!(reader.read(&mut buf).unwrap(), 1); - assert_eq!(reader.position(), 1); - let b: &[_] = &[0]; - assert_eq!(buf, b); - let mut buf = [0; 4]; - assert_eq!(reader.read(&mut buf).unwrap(), 4); - assert_eq!(reader.position(), 5); - let b: &[_] = &[1, 2, 3, 4]; - assert_eq!(buf, b); - assert_eq!(reader.read(&mut buf).unwrap(), 3); - let b: &[_] = &[5, 6, 7]; - assert_eq!(&buf[..3], b); - assert_eq!(reader.read(&mut buf).unwrap(), 0); - } - - #[test] - fn seek_past_end() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut r = Cursor::new(vec![10]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.read(&mut [0]).unwrap(), 0); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 0); - } - - #[test] - fn seek_past_i64() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut r = Cursor::new(vec![10]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); - assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); - assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); - assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); - assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); - assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); - } - - #[test] - fn seek_before_0() { - let buf = [0xff]; - let mut r = Cursor::new(&buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec![10]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut buf = [0]; - let mut r = Cursor::new(&mut buf[..]); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - - let mut r = Cursor::new(vec![10].into_boxed_slice()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } - - #[test] - fn test_seekable_mem_writer() { - let mut writer = Cursor::new(Vec::::new()); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[0]).unwrap(), 1); - assert_eq!(writer.position(), 1); - assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); - assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); - assert_eq!(writer.position(), 8); - let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0); - assert_eq!(writer.position(), 0); - assert_eq!(writer.write(&[3, 4]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3); - assert_eq!(writer.write(&[0, 1]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); - assert_eq!(writer.write(&[1, 2]).unwrap(), 2); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; - assert_eq!(&writer.get_ref()[..], b); - - assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10); - assert_eq!(writer.write(&[1]).unwrap(), 1); - let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; - assert_eq!(&writer.get_ref()[..], b); - } - - #[test] - fn vec_seek_past_end() { - let mut r = Cursor::new(Vec::new()); - assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); - assert_eq!(r.write(&[3]).unwrap(), 1); - } - - #[test] - fn vec_seek_before_0() { - let mut r = Cursor::new(Vec::new()); - assert!(r.seek(SeekFrom::End(-2)).is_err()); - } - - #[test] - #[cfg(target_pointer_width = "32")] - fn vec_seek_and_write_past_usize_max() { - let mut c = Cursor::new(Vec::new()); - c.set_position(usize::MAX as u64 + 1); - assert!(c.write_all(&[1, 2, 3]).is_err()); - } - - #[test] - fn test_partial_eq() { - assert_eq!(Cursor::new(Vec::::new()), Cursor::new(Vec::::new())); - } - - #[test] - fn test_eq() { - struct AssertEq(pub T); - - let _: AssertEq>> = AssertEq(Cursor::new(Vec::new())); - } -} diff --git a/library/std/src/io/cursor/tests.rs b/library/std/src/io/cursor/tests.rs new file mode 100644 index 0000000000..80d88ca66f --- /dev/null +++ b/library/std/src/io/cursor/tests.rs @@ -0,0 +1,516 @@ +use crate::io::prelude::*; +use crate::io::{Cursor, IoSlice, IoSliceMut, SeekFrom}; + +#[test] +fn test_vec_writer() { + let mut writer = Vec::new(); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) + .unwrap(), + 3 + ); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(writer, b); +} + +#[test] +fn test_mem_writer() { + let mut writer = Cursor::new(Vec::new()); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) + .unwrap(), + 3 + ); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(&writer.get_ref()[..], b); +} + +#[test] +fn test_mem_mut_writer() { + let mut vec = Vec::new(); + let mut writer = Cursor::new(&mut vec); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[]), IoSlice::new(&[8, 9]), IoSlice::new(&[10])],) + .unwrap(), + 3 + ); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; + assert_eq!(&writer.get_ref()[..], b); +} + +#[test] +fn test_box_slice_writer() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]).unwrap(), 1); + assert_eq!(writer.write(&[10]).unwrap(), 0); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(&**writer.get_ref(), b); +} + +#[test] +fn test_box_slice_writer_vectored() { + let mut writer = Cursor::new(vec![0u8; 9].into_boxed_slice()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!( + writer.write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7]),]).unwrap(), + 7, + ); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(&**writer.get_ref(), b); +} + +#[test] +fn test_buf_writer() { + let mut buf = [0 as u8; 9]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write(&[8, 9]).unwrap(), 1); + assert_eq!(writer.write(&[10]).unwrap(), 0); + } + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(buf, b); +} + +#[test] +fn test_buf_writer_vectored() { + let mut buf = [0 as u8; 9]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[0])]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!( + writer + .write_vectored(&[IoSlice::new(&[1, 2, 3]), IoSlice::new(&[4, 5, 6, 7])],) + .unwrap(), + 7, + ); + assert_eq!(writer.position(), 8); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + assert_eq!(writer.position(), 8); + + assert_eq!(writer.write_vectored(&[IoSlice::new(&[8, 9])]).unwrap(), 1); + assert_eq!(writer.write_vectored(&[IoSlice::new(&[10])]).unwrap(), 0); + } + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8]; + assert_eq!(buf, b); +} + +#[test] +fn test_buf_writer_seek() { + let mut buf = [0 as u8; 8]; + { + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[1]).unwrap(), 1); + assert_eq!(writer.position(), 1); + + assert_eq!(writer.seek(SeekFrom::Start(2)).unwrap(), 2); + assert_eq!(writer.position(), 2); + assert_eq!(writer.write(&[2]).unwrap(), 1); + assert_eq!(writer.position(), 3); + + assert_eq!(writer.seek(SeekFrom::Current(-2)).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[3]).unwrap(), 1); + assert_eq!(writer.position(), 2); + + assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); + assert_eq!(writer.position(), 7); + assert_eq!(writer.write(&[4]).unwrap(), 1); + assert_eq!(writer.position(), 8); + } + let b: &[_] = &[1, 3, 2, 0, 0, 0, 0, 4]; + assert_eq!(buf, b); +} + +#[test] +fn test_buf_writer_error() { + let mut buf = [0 as u8; 2]; + let mut writer = Cursor::new(&mut buf[..]); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.write(&[0, 0]).unwrap(), 1); + assert_eq!(writer.write(&[0, 0]).unwrap(), 0); +} + +#[test] +fn test_mem_reader() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_mem_reader_vectored() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(), + 1, + ); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader + .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2),]) + .unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_boxed_slice_reader() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_boxed_slice_reader_vectored() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7].into_boxed_slice()); + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(), + 1, + ); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader + .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) + .unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn read_to_end() { + let mut reader = Cursor::new(vec![0, 1, 2, 3, 4, 5, 6, 7]); + let mut v = Vec::new(); + reader.read_to_end(&mut v).unwrap(); + assert_eq!(v, [0, 1, 2, 3, 4, 5, 6, 7]); +} + +#[test] +fn test_slice_reader() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let reader = &mut &in_buf[..]; + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.len(), 7); + let b: &[_] = &[0]; + assert_eq!(&buf[..], b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.len(), 3); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(&buf[..], b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_slice_reader_vectored() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let reader = &mut &in_buf[..]; + let mut buf = []; + assert_eq!(reader.read_vectored(&mut [IoSliceMut::new(&mut buf)]).unwrap(), 0); + let mut buf = [0]; + assert_eq!( + reader.read_vectored(&mut [IoSliceMut::new(&mut []), IoSliceMut::new(&mut buf),]).unwrap(), + 1, + ); + assert_eq!(reader.len(), 7); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf1 = [0; 4]; + let mut buf2 = [0; 4]; + assert_eq!( + reader + .read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) + .unwrap(), + 7, + ); + let b1: &[_] = &[1, 2, 3, 4]; + let b2: &[_] = &[5, 6, 7]; + assert_eq!(buf1, b1); + assert_eq!(&buf2[..3], b2); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn test_read_exact() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let reader = &mut &in_buf[..]; + let mut buf = []; + assert!(reader.read_exact(&mut buf).is_ok()); + let mut buf = [8]; + assert!(reader.read_exact(&mut buf).is_ok()); + assert_eq!(buf[0], 0); + assert_eq!(reader.len(), 7); + let mut buf = [0, 0, 0, 0, 0, 0, 0]; + assert!(reader.read_exact(&mut buf).is_ok()); + assert_eq!(buf, [1, 2, 3, 4, 5, 6, 7]); + assert_eq!(reader.len(), 0); + let mut buf = [0]; + assert!(reader.read_exact(&mut buf).is_err()); +} + +#[test] +fn test_buf_reader() { + let in_buf = vec![0, 1, 2, 3, 4, 5, 6, 7]; + let mut reader = Cursor::new(&in_buf[..]); + let mut buf = []; + assert_eq!(reader.read(&mut buf).unwrap(), 0); + assert_eq!(reader.position(), 0); + let mut buf = [0]; + assert_eq!(reader.read(&mut buf).unwrap(), 1); + assert_eq!(reader.position(), 1); + let b: &[_] = &[0]; + assert_eq!(buf, b); + let mut buf = [0; 4]; + assert_eq!(reader.read(&mut buf).unwrap(), 4); + assert_eq!(reader.position(), 5); + let b: &[_] = &[1, 2, 3, 4]; + assert_eq!(buf, b); + assert_eq!(reader.read(&mut buf).unwrap(), 3); + let b: &[_] = &[5, 6, 7]; + assert_eq!(&buf[..3], b); + assert_eq!(reader.read(&mut buf).unwrap(), 0); +} + +#[test] +fn seek_past_end() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.read(&mut [0]).unwrap(), 0); + + let mut r = Cursor::new(vec![10]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.read(&mut [0]).unwrap(), 0); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 0); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 0); +} + +#[test] +fn seek_past_i64() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut r = Cursor::new(vec![10]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert_eq!(r.seek(SeekFrom::Start(6)).unwrap(), 6); + assert_eq!(r.seek(SeekFrom::Current(0x7ffffffffffffff0)).unwrap(), 0x7ffffffffffffff6); + assert_eq!(r.seek(SeekFrom::Current(0x10)).unwrap(), 0x8000000000000006); + assert_eq!(r.seek(SeekFrom::Current(0)).unwrap(), 0x8000000000000006); + assert!(r.seek(SeekFrom::Current(0x7ffffffffffffffd)).is_err()); + assert_eq!(r.seek(SeekFrom::Current(-0x8000000000000000)).unwrap(), 6); +} + +#[test] +fn seek_before_0() { + let buf = [0xff]; + let mut r = Cursor::new(&buf[..]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut r = Cursor::new(vec![10]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut buf = [0]; + let mut r = Cursor::new(&mut buf[..]); + assert!(r.seek(SeekFrom::End(-2)).is_err()); + + let mut r = Cursor::new(vec![10].into_boxed_slice()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); +} + +#[test] +fn test_seekable_mem_writer() { + let mut writer = Cursor::new(Vec::::new()); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[0]).unwrap(), 1); + assert_eq!(writer.position(), 1); + assert_eq!(writer.write(&[1, 2, 3]).unwrap(), 3); + assert_eq!(writer.write(&[4, 5, 6, 7]).unwrap(), 4); + assert_eq!(writer.position(), 8); + let b: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::Start(0)).unwrap(), 0); + assert_eq!(writer.position(), 0); + assert_eq!(writer.write(&[3, 4]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 3, 4, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::Current(1)).unwrap(), 3); + assert_eq!(writer.write(&[0, 1]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 7]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::End(-1)).unwrap(), 7); + assert_eq!(writer.write(&[1, 2]).unwrap(), 2); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2]; + assert_eq!(&writer.get_ref()[..], b); + + assert_eq!(writer.seek(SeekFrom::End(1)).unwrap(), 10); + assert_eq!(writer.write(&[1]).unwrap(), 1); + let b: &[_] = &[3, 4, 2, 0, 1, 5, 6, 1, 2, 0, 1]; + assert_eq!(&writer.get_ref()[..], b); +} + +#[test] +fn vec_seek_past_end() { + let mut r = Cursor::new(Vec::new()); + assert_eq!(r.seek(SeekFrom::Start(10)).unwrap(), 10); + assert_eq!(r.write(&[3]).unwrap(), 1); +} + +#[test] +fn vec_seek_before_0() { + let mut r = Cursor::new(Vec::new()); + assert!(r.seek(SeekFrom::End(-2)).is_err()); +} + +#[test] +#[cfg(target_pointer_width = "32")] +fn vec_seek_and_write_past_usize_max() { + let mut c = Cursor::new(Vec::new()); + c.set_position(usize::MAX as u64 + 1); + assert!(c.write_all(&[1, 2, 3]).is_err()); +} + +#[test] +fn test_partial_eq() { + assert_eq!(Cursor::new(Vec::::new()), Cursor::new(Vec::::new())); +} + +#[test] +fn test_eq() { + struct AssertEq(pub T); + + let _: AssertEq>> = AssertEq(Cursor::new(Vec::new())); +} diff --git a/library/std/src/io/error.rs b/library/std/src/io/error.rs index e6eda2caf7..ba0f0a0cd7 100644 --- a/library/std/src/io/error.rs +++ b/library/std/src/io/error.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::convert::From; use crate::error; use crate::fmt; @@ -574,60 +577,3 @@ fn _assert_error_is_sync_send() { fn _is_sync_send() {} _is_sync_send::(); } - -#[cfg(test)] -mod test { - use super::{Custom, Error, ErrorKind, Repr}; - use crate::error; - use crate::fmt; - use crate::sys::decode_error_kind; - use crate::sys::os::error_string; - - #[test] - fn test_debug_error() { - let code = 6; - let msg = error_string(code); - let kind = decode_error_kind(code); - let err = Error { - repr: Repr::Custom(box Custom { - kind: ErrorKind::InvalidInput, - error: box Error { repr: super::Repr::Os(code) }, - }), - }; - let expected = format!( - "Custom {{ \ - kind: InvalidInput, \ - error: Os {{ \ - code: {:?}, \ - kind: {:?}, \ - message: {:?} \ - }} \ - }}", - code, kind, msg - ); - assert_eq!(format!("{:?}", err), expected); - } - - #[test] - fn test_downcasting() { - #[derive(Debug)] - struct TestError; - - impl fmt::Display for TestError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.write_str("asdf") - } - } - - impl error::Error for TestError {} - - // we have to call all of these UFCS style right now since method - // resolution won't implicitly drop the Send+Sync bounds - let mut err = Error::new(ErrorKind::Other, TestError); - assert!(err.get_ref().unwrap().is::()); - assert_eq!("asdf", err.get_ref().unwrap().to_string()); - assert!(err.get_mut().unwrap().is::()); - let extracted = err.into_inner().unwrap(); - extracted.downcast::().unwrap(); - } -} diff --git a/library/std/src/io/error/tests.rs b/library/std/src/io/error/tests.rs new file mode 100644 index 0000000000..0cce9368c8 --- /dev/null +++ b/library/std/src/io/error/tests.rs @@ -0,0 +1,53 @@ +use super::{Custom, Error, ErrorKind, Repr}; +use crate::error; +use crate::fmt; +use crate::sys::decode_error_kind; +use crate::sys::os::error_string; + +#[test] +fn test_debug_error() { + let code = 6; + let msg = error_string(code); + let kind = decode_error_kind(code); + let err = Error { + repr: Repr::Custom(box Custom { + kind: ErrorKind::InvalidInput, + error: box Error { repr: super::Repr::Os(code) }, + }), + }; + let expected = format!( + "Custom {{ \ + kind: InvalidInput, \ + error: Os {{ \ + code: {:?}, \ + kind: {:?}, \ + message: {:?} \ + }} \ + }}", + code, kind, msg + ); + assert_eq!(format!("{:?}", err), expected); +} + +#[test] +fn test_downcasting() { + #[derive(Debug)] + struct TestError; + + impl fmt::Display for TestError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.write_str("asdf") + } + } + + impl error::Error for TestError {} + + // we have to call all of these UFCS style right now since method + // resolution won't implicitly drop the Send+Sync bounds + let mut err = Error::new(ErrorKind::Other, TestError); + assert!(err.get_ref().unwrap().is::()); + assert_eq!("asdf", err.get_ref().unwrap().to_string()); + assert!(err.get_mut().unwrap().is::()); + let extracted = err.into_inner().unwrap(); + extracted.downcast::().unwrap(); +} diff --git a/library/std/src/io/impls.rs b/library/std/src/io/impls.rs index 01dff0b3eb..e09e7ba978 100644 --- a/library/std/src/io/impls.rs +++ b/library/std/src/io/impls.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::cmp; use crate::fmt; use crate::io::{ @@ -397,64 +400,3 @@ impl Write for Vec { Ok(()) } } - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - - #[bench] - fn bench_read_slice(b: &mut test::Bencher) { - let buf = [5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_slice(b: &mut test::Bencher) { - let mut buf = [0; 1024]; - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } - - #[bench] - fn bench_read_vec(b: &mut test::Bencher) { - let buf = vec![5; 1024]; - let mut dst = [0; 128]; - - b.iter(|| { - let mut rd = &buf[..]; - for _ in 0..8 { - let _ = rd.read(&mut dst); - test::black_box(&dst); - } - }) - } - - #[bench] - fn bench_write_vec(b: &mut test::Bencher) { - let mut buf = Vec::with_capacity(1024); - let src = [5; 128]; - - b.iter(|| { - let mut wr = &mut buf[..]; - for _ in 0..8 { - let _ = wr.write_all(&src); - test::black_box(&wr); - } - }) - } -} diff --git a/library/std/src/io/impls/tests.rs b/library/std/src/io/impls/tests.rs new file mode 100644 index 0000000000..d1cd84a67a --- /dev/null +++ b/library/std/src/io/impls/tests.rs @@ -0,0 +1,57 @@ +use crate::io::prelude::*; + +#[bench] +fn bench_read_slice(b: &mut test::Bencher) { + let buf = [5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) +} + +#[bench] +fn bench_write_slice(b: &mut test::Bencher) { + let mut buf = [0; 1024]; + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) +} + +#[bench] +fn bench_read_vec(b: &mut test::Bencher) { + let buf = vec![5; 1024]; + let mut dst = [0; 128]; + + b.iter(|| { + let mut rd = &buf[..]; + for _ in 0..8 { + let _ = rd.read(&mut dst); + test::black_box(&dst); + } + }) +} + +#[bench] +fn bench_write_vec(b: &mut test::Bencher) { + let mut buf = Vec::with_capacity(1024); + let src = [5; 128]; + + b.iter(|| { + let mut wr = &mut buf[..]; + for _ in 0..8 { + let _ = wr.write_all(&src); + test::black_box(&wr); + } + }) +} diff --git a/library/std/src/io/lazy.rs b/library/std/src/io/lazy.rs deleted file mode 100644 index 1968d498bb..0000000000 --- a/library/std/src/io/lazy.rs +++ /dev/null @@ -1,63 +0,0 @@ -use crate::cell::Cell; -use crate::ptr; -use crate::sync::Arc; -use crate::sys_common; -use crate::sys_common::mutex::Mutex; - -pub struct Lazy { - // We never call `lock.init()`, so it is UB to attempt to acquire this mutex reentrantly! - lock: Mutex, - ptr: Cell<*mut Arc>, -} - -#[inline] -const fn done() -> *mut Arc { - 1_usize as *mut _ -} - -unsafe impl Sync for Lazy {} - -impl Lazy { - pub const fn new() -> Lazy { - Lazy { lock: Mutex::new(), ptr: Cell::new(ptr::null_mut()) } - } -} - -impl Lazy { - /// Safety: `init` must not call `get` on the variable that is being - /// initialized. - pub unsafe fn get(&'static self, init: fn() -> Arc) -> Option> { - let _guard = self.lock.lock(); - let ptr = self.ptr.get(); - if ptr.is_null() { - Some(self.init(init)) - } else if ptr == done() { - None - } else { - Some((*ptr).clone()) - } - } - - // Must only be called with `lock` held - unsafe fn init(&'static self, init: fn() -> Arc) -> Arc { - // If we successfully register an at exit handler, then we cache the - // `Arc` allocation in our own internal box (it will get deallocated by - // the at exit handler). Otherwise we just return the freshly allocated - // `Arc`. - let registered = sys_common::at_exit(move || { - let ptr = { - let _guard = self.lock.lock(); - self.ptr.replace(done()) - }; - drop(Box::from_raw(ptr)) - }); - // This could reentrantly call `init` again, which is a problem - // because our `lock` allows reentrancy! - // That's why `get` is unsafe and requires the caller to ensure no reentrancy happens. - let ret = init(); - if registered.is_ok() { - self.ptr.set(Box::into_raw(Box::new(ret.clone()))); - } - ret - } -} diff --git a/library/std/src/io/mod.rs b/library/std/src/io/mod.rs index 462b696db4..d9d0380781 100644 --- a/library/std/src/io/mod.rs +++ b/library/std/src/io/mod.rs @@ -249,6 +249,9 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::fmt; use crate::memchr; @@ -282,7 +285,6 @@ mod buffered; mod cursor; mod error; mod impls; -mod lazy; pub mod prelude; mod stdio; mod util; @@ -2481,501 +2483,3 @@ impl Iterator for Lines { } } } - -#[cfg(test)] -mod tests { - use super::{repeat, Cursor, SeekFrom}; - use crate::cmp::{self, min}; - use crate::io::prelude::*; - use crate::io::{self, IoSlice, IoSliceMut}; - use crate::ops::Deref; - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn read_until() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2); - assert_eq!(v, b"12"); - - let mut buf = Cursor::new(&b"1233"[..]); - let mut v = Vec::new(); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); - assert_eq!(v, b"123"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); - assert_eq!(v, b"3"); - v.truncate(0); - assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); - assert_eq!(v, []); - } - - #[test] - fn split() { - let buf = Cursor::new(&b"12"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"1233"[..]); - let mut s = buf.split(b'3'); - assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); - assert_eq!(s.next().unwrap().unwrap(), vec![]); - assert!(s.next().is_none()); - } - - #[test] - fn read_line() { - let mut buf = Cursor::new(&b"12"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 2); - assert_eq!(v, "12"); - - let mut buf = Cursor::new(&b"12\n\n"[..]); - let mut v = String::new(); - assert_eq!(buf.read_line(&mut v).unwrap(), 3); - assert_eq!(v, "12\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 1); - assert_eq!(v, "\n"); - v.truncate(0); - assert_eq!(buf.read_line(&mut v).unwrap(), 0); - assert_eq!(v, ""); - } - - #[test] - fn lines() { - let buf = Cursor::new(&b"12\r"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string()); - assert!(s.next().is_none()); - - let buf = Cursor::new(&b"12\r\n\n"[..]); - let mut s = buf.lines(); - assert_eq!(s.next().unwrap().unwrap(), "12".to_string()); - assert_eq!(s.next().unwrap().unwrap(), "".to_string()); - assert!(s.next().is_none()); - } - - #[test] - fn read_to_end() { - let mut c = Cursor::new(&b""[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 0); - assert_eq!(v, []); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = Vec::new(); - assert_eq!(c.read_to_end(&mut v).unwrap(), 1); - assert_eq!(v, b"1"); - - let cap = 1024 * 1024; - let data = (0..cap).map(|i| (i / 3) as u8).collect::>(); - let mut v = Vec::new(); - let (a, b) = data.split_at(data.len() / 2); - assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); - assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); - assert_eq!(v, data); - } - - #[test] - fn read_to_string() { - let mut c = Cursor::new(&b""[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 0); - assert_eq!(v, ""); - - let mut c = Cursor::new(&b"1"[..]); - let mut v = String::new(); - assert_eq!(c.read_to_string(&mut v).unwrap(), 1); - assert_eq!(v, "1"); - - let mut c = Cursor::new(&b"\xff"[..]); - let mut v = String::new(); - assert!(c.read_to_string(&mut v).is_err()); - } - - #[test] - fn read_exact() { - let mut buf = [0; 4]; - - let mut c = Cursor::new(&b""[..]); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - - let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..])); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - } - - #[test] - fn read_exact_slice() { - let mut buf = [0; 4]; - - let mut c = &b""[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - - let mut c = &b"123"[..]; - assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); - // make sure the optimized (early returning) method is being used - assert_eq!(&buf, &[0; 4]); - - let mut c = &b"1234"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"1234"); - - let mut c = &b"56789"[..]; - c.read_exact(&mut buf).unwrap(); - assert_eq!(&buf, b"5678"); - assert_eq!(c, b"9"); - } - - #[test] - fn take_eof() { - struct R; - - impl Read for R { - fn read(&mut self, _: &mut [u8]) -> io::Result { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - } - impl BufRead for R { - fn fill_buf(&mut self) -> io::Result<&[u8]> { - Err(io::Error::new(io::ErrorKind::Other, "")) - } - fn consume(&mut self, _amt: usize) {} - } - - let mut buf = [0; 1]; - assert_eq!(0, R.take(0).read(&mut buf).unwrap()); - assert_eq!(b"", R.take(0).fill_buf().unwrap()); - } - - fn cmp_bufread(mut br1: Br1, mut br2: Br2, exp: &[u8]) { - let mut cat = Vec::new(); - loop { - let consume = { - let buf1 = br1.fill_buf().unwrap(); - let buf2 = br2.fill_buf().unwrap(); - let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() }; - assert_eq!(buf1[..minlen], buf2[..minlen]); - cat.extend_from_slice(&buf1[..minlen]); - minlen - }; - if consume == 0 { - break; - } - br1.consume(consume); - br2.consume(consume); - } - assert_eq!(br1.fill_buf().unwrap().len(), 0); - assert_eq!(br2.fill_buf().unwrap().len(), 0); - assert_eq!(&cat[..], &exp[..]) - } - - #[test] - fn chain_bufread() { - let testdata = b"ABCDEFGHIJKL"; - let chain1 = - (&testdata[..3]).chain(&testdata[3..6]).chain(&testdata[6..9]).chain(&testdata[9..]); - let chain2 = (&testdata[..4]).chain(&testdata[4..8]).chain(&testdata[8..]); - cmp_bufread(chain1, chain2, &testdata[..]); - } - - #[test] - fn chain_zero_length_read_is_not_eof() { - let a = b"A"; - let b = b"B"; - let mut s = String::new(); - let mut chain = (&a[..]).chain(&b[..]); - chain.read(&mut []).unwrap(); - chain.read_to_string(&mut s).unwrap(); - assert_eq!("AB", s); - } - - #[bench] - #[cfg_attr(target_os = "emscripten", ignore)] - fn bench_read_to_end(b: &mut test::Bencher) { - b.iter(|| { - let mut lr = repeat(1).take(10000000); - let mut vec = Vec::with_capacity(1024); - super::read_to_end(&mut lr, &mut vec) - }); - } - - #[test] - fn seek_len() -> io::Result<()> { - let mut c = Cursor::new(vec![0; 15]); - assert_eq!(c.stream_len()?, 15); - - c.seek(SeekFrom::End(0))?; - let old_pos = c.stream_position()?; - assert_eq!(c.stream_len()?, 15); - assert_eq!(c.stream_position()?, old_pos); - - c.seek(SeekFrom::Start(7))?; - c.seek(SeekFrom::Current(2))?; - let old_pos = c.stream_position()?; - assert_eq!(c.stream_len()?, 15); - assert_eq!(c.stream_position()?, old_pos); - - Ok(()) - } - - #[test] - fn seek_position() -> io::Result<()> { - // All `asserts` are duplicated here to make sure the method does not - // change anything about the seek state. - let mut c = Cursor::new(vec![0; 15]); - assert_eq!(c.stream_position()?, 0); - assert_eq!(c.stream_position()?, 0); - - c.seek(SeekFrom::End(0))?; - assert_eq!(c.stream_position()?, 15); - assert_eq!(c.stream_position()?, 15); - - c.seek(SeekFrom::Start(7))?; - c.seek(SeekFrom::Current(2))?; - assert_eq!(c.stream_position()?, 9); - assert_eq!(c.stream_position()?, 9); - - c.seek(SeekFrom::End(-3))?; - c.seek(SeekFrom::Current(1))?; - c.seek(SeekFrom::Current(-5))?; - assert_eq!(c.stream_position()?, 8); - assert_eq!(c.stream_position()?, 8); - - Ok(()) - } - - // A simple example reader which uses the default implementation of - // read_to_end. - struct ExampleSliceReader<'a> { - slice: &'a [u8], - } - - impl<'a> Read for ExampleSliceReader<'a> { - fn read(&mut self, buf: &mut [u8]) -> io::Result { - let len = cmp::min(self.slice.len(), buf.len()); - buf[..len].copy_from_slice(&self.slice[..len]); - self.slice = &self.slice[len..]; - Ok(len) - } - } - - #[test] - 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. - 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"); - - Ok(()) - } - - #[test] - fn io_slice_mut_advance() { - let mut buf1 = [1; 8]; - let mut buf2 = [2; 16]; - let mut buf3 = [3; 8]; - let mut bufs = &mut [ - IoSliceMut::new(&mut buf1), - IoSliceMut::new(&mut buf2), - IoSliceMut::new(&mut buf3), - ][..]; - - // Only in a single buffer.. - bufs = IoSliceMut::advance(bufs, 1); - assert_eq!(bufs[0].deref(), [1; 7].as_ref()); - assert_eq!(bufs[1].deref(), [2; 16].as_ref()); - assert_eq!(bufs[2].deref(), [3; 8].as_ref()); - - // Removing a buffer, leaving others as is. - bufs = IoSliceMut::advance(bufs, 7); - assert_eq!(bufs[0].deref(), [2; 16].as_ref()); - assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - - // Removing a buffer and removing from the next buffer. - bufs = IoSliceMut::advance(bufs, 18); - assert_eq!(bufs[0].deref(), [3; 6].as_ref()); - } - - #[test] - fn io_slice_mut_advance_empty_slice() { - let empty_bufs = &mut [][..]; - // Shouldn't panic. - IoSliceMut::advance(empty_bufs, 1); - } - - #[test] - fn io_slice_mut_advance_beyond_total_length() { - let mut buf1 = [1; 8]; - let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..]; - - // Going beyond the total length should be ok. - bufs = IoSliceMut::advance(bufs, 9); - assert!(bufs.is_empty()); - } - - #[test] - fn io_slice_advance() { - let buf1 = [1; 8]; - let buf2 = [2; 16]; - let buf3 = [3; 8]; - let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..]; - - // Only in a single buffer.. - bufs = IoSlice::advance(bufs, 1); - assert_eq!(bufs[0].deref(), [1; 7].as_ref()); - assert_eq!(bufs[1].deref(), [2; 16].as_ref()); - assert_eq!(bufs[2].deref(), [3; 8].as_ref()); - - // Removing a buffer, leaving others as is. - bufs = IoSlice::advance(bufs, 7); - assert_eq!(bufs[0].deref(), [2; 16].as_ref()); - assert_eq!(bufs[1].deref(), [3; 8].as_ref()); - - // Removing a buffer and removing from the next buffer. - bufs = IoSlice::advance(bufs, 18); - assert_eq!(bufs[0].deref(), [3; 6].as_ref()); - } - - #[test] - fn io_slice_advance_empty_slice() { - let empty_bufs = &mut [][..]; - // Shouldn't panic. - IoSlice::advance(empty_bufs, 1); - } - - #[test] - fn io_slice_advance_beyond_total_length() { - let buf1 = [1; 8]; - let mut bufs = &mut [IoSlice::new(&buf1)][..]; - - // Going beyond the total length should be ok. - bufs = IoSlice::advance(bufs, 9); - assert!(bufs.is_empty()); - } - - /// Create a new writer that reads from at most `n_bufs` and reads - /// `per_call` bytes (in total) per call to write. - fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { - TestWriter { n_bufs, per_call, written: Vec::new() } - } - - struct TestWriter { - n_bufs: usize, - per_call: usize, - written: Vec, - } - - impl Write for TestWriter { - fn write(&mut self, buf: &[u8]) -> io::Result { - self.write_vectored(&[IoSlice::new(buf)]) - } - - fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { - let mut left = self.per_call; - let mut written = 0; - for buf in bufs.iter().take(self.n_bufs) { - let n = min(left, buf.len()); - self.written.extend_from_slice(&buf[0..n]); - left -= n; - written += n; - } - Ok(written) - } - - fn flush(&mut self) -> io::Result<()> { - Ok(()) - } - } - - #[test] - fn test_writer_read_from_one_buf() { - let mut writer = test_writer(1, 2); - - assert_eq!(writer.write(&[]).unwrap(), 0); - assert_eq!(writer.write_vectored(&[]).unwrap(), 0); - - // Read at most 2 bytes. - assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2); - let bufs = &[IoSlice::new(&[2, 2, 2])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 2); - - // Only read from first buf. - let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 1); - - assert_eq!(writer.written, &[1, 1, 2, 2, 3]); - } - - #[test] - fn test_writer_read_from_multiple_bufs() { - let mut writer = test_writer(3, 3); - - // Read at most 3 bytes from two buffers. - let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 3); - - // Read at most 3 bytes from three buffers. - let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])]; - assert_eq!(writer.write_vectored(bufs).unwrap(), 3); - - assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]); - } - - #[test] - fn test_write_all_vectored() { - #[rustfmt::skip] // Becomes unreadable otherwise. - let tests: Vec<(_, &'static [u8])> = vec![ - (vec![], &[]), - (vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]), - (vec![IoSlice::new(&[1])], &[1]), - (vec![IoSlice::new(&[1, 2])], &[1, 2]), - (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]), - (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]), - (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]), - (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]), - (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]), - (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]), - (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]), - ]; - - let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]; - - for (n_bufs, per_call) in writer_configs.iter().copied() { - for (mut input, wanted) in tests.clone().into_iter() { - let mut writer = test_writer(n_bufs, per_call); - assert!(writer.write_all_vectored(&mut *input).is_ok()); - assert_eq!(&*writer.written, &*wanted); - } - } - } -} diff --git a/library/std/src/io/stdio.rs b/library/std/src/io/stdio.rs index 3943c66aad..36b4940159 100644 --- a/library/std/src/io/stdio.rs +++ b/library/std/src/io/stdio.rs @@ -1,30 +1,49 @@ #![cfg_attr(test, allow(unused))] +#[cfg(test)] +mod tests; + use crate::io::prelude::*; use crate::cell::RefCell; use crate::fmt; -use crate::io::lazy::Lazy; use crate::io::{self, BufReader, Initializer, IoSlice, IoSliceMut, LineWriter}; -use crate::sync::{Arc, Mutex, MutexGuard, Once}; +use crate::lazy::SyncOnceCell; +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sync::{Mutex, MutexGuard}; use crate::sys::stdio; +use crate::sys_common; use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; use crate::thread::LocalKey; thread_local! { - /// Stdout used by print! and println! macros + /// Used by the test crate to capture the output of the print! and println! macros. static LOCAL_STDOUT: RefCell>> = { RefCell::new(None) } } thread_local! { - /// Stderr used by eprint! and eprintln! macros, and panics + /// Used by the test crate to capture the output of the eprint! and eprintln! macros, and panics. static LOCAL_STDERR: RefCell>> = { RefCell::new(None) } } +/// Flag to indicate LOCAL_STDOUT and/or LOCAL_STDERR is used. +/// +/// If both are None and were never set on any thread, this flag is set to +/// false, and both LOCAL_STDOUT and LOCAL_STDOUT can be safely ignored on all +/// threads, saving some time and memory registering an unused thread local. +/// +/// Note about memory ordering: This contains information about whether two +/// thread local variables might be in use. Although this is a global flag, the +/// memory ordering between threads does not matter: we only want this flag to +/// have a consistent order between set_print/set_panic and print_to *within +/// the same thread*. Within the same thread, things always have a perfectly +/// consistent order. So Ordering::Relaxed is fine. +static LOCAL_STREAMS: AtomicBool = AtomicBool::new(false); + /// A handle to a raw instance of the standard input stream of this process. /// /// This handle is not synchronized or buffered in any fashion. Constructed via @@ -214,7 +233,7 @@ fn handle_ebadf(r: io::Result, default: T) -> io::Result { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub struct Stdin { - inner: Arc>>, + inner: &'static Mutex>, } /// A locked reference to the `Stdin` handle. @@ -289,15 +308,11 @@ pub struct StdinLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdin() -> Stdin { - static INSTANCE: Lazy>> = Lazy::new(); - return Stdin { - inner: unsafe { INSTANCE.get(stdin_init).expect("cannot access stdin during shutdown") }, - }; - - fn stdin_init() -> Arc>> { - // This must not reentrantly access `INSTANCE` - let stdin = stdin_raw(); - Arc::new(Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin))) + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); + Stdin { + inner: INSTANCE.get_or_init(|| { + Mutex::new(BufReader::with_capacity(stdio::STDIN_BUF_SIZE, stdin_raw())) + }), } } @@ -473,7 +488,7 @@ pub struct Stdout { // FIXME: this should be LineWriter or BufWriter depending on the state of // stdout (tty or not). Note that if this is not line buffered it // should also flush-on-panic or some form of flush-on-abort. - inner: Arc>>>, + inner: &'static ReentrantMutex>>, } /// A locked reference to the `Stdout` handle. @@ -531,19 +546,27 @@ pub struct StdoutLock<'a> { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn stdout() -> Stdout { - static INSTANCE: Lazy>>> = Lazy::new(); - return Stdout { - inner: unsafe { INSTANCE.get(stdout_init).expect("cannot access stdout during shutdown") }, - }; - - fn stdout_init() -> Arc>>> { - // This must not reentrantly access `INSTANCE` - let stdout = stdout_raw(); - unsafe { - let ret = Arc::new(ReentrantMutex::new(RefCell::new(LineWriter::new(stdout)))); - ret.init(); - ret - } + static INSTANCE: SyncOnceCell>>> = + SyncOnceCell::new(); + Stdout { + inner: INSTANCE.get_or_init(|| unsafe { + let _ = sys_common::at_exit(|| { + if let Some(instance) = INSTANCE.get() { + // Flush the data and disable buffering during shutdown + // by replacing the line writer by one with zero + // buffering capacity. + // We use try_lock() instead of lock(), because someone + // might have leaked a StdoutLock, which would + // otherwise cause a deadlock here. + if let Some(lock) = instance.try_lock() { + *lock.borrow_mut() = LineWriter::with_capacity(0, stdout_raw()); + } + } + }); + let r = ReentrantMutex::new(RefCell::new(LineWriter::new(stdout_raw()))); + r.init(); + r + }), } } @@ -583,6 +606,32 @@ impl fmt::Debug for Stdout { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stdout { + fn write(&mut self, buf: &[u8]) -> io::Result { + (&*self).write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&*self).write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (&*self).write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (&*self).write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + (&*self).write_fmt(args) + } +} + +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &Stdout { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) } @@ -606,6 +655,7 @@ impl Write for Stdout { self.lock().write_fmt(args) } } + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StdoutLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -711,16 +761,15 @@ pub fn stderr() -> Stderr { // // This has the added benefit of allowing `stderr` to be usable during // process shutdown as well! - static INSTANCE: ReentrantMutex> = - unsafe { ReentrantMutex::new(RefCell::new(stderr_raw())) }; + static INSTANCE: SyncOnceCell>> = SyncOnceCell::new(); - // When accessing stderr we need one-time initialization of the reentrant - // mutex. Afterwards we can just always use the now-filled-in `INSTANCE` value. - static INIT: Once = Once::new(); - INIT.call_once(|| unsafe { - INSTANCE.init(); - }); - Stderr { inner: &INSTANCE } + Stderr { + inner: INSTANCE.get_or_init(|| unsafe { + let r = ReentrantMutex::new(RefCell::new(stderr_raw())); + r.init(); + r + }), + } } impl Stderr { @@ -759,6 +808,32 @@ impl fmt::Debug for Stderr { #[stable(feature = "rust1", since = "1.0.0")] impl Write for Stderr { + fn write(&mut self, buf: &[u8]) -> io::Result { + (&*self).write(buf) + } + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&*self).write_vectored(bufs) + } + #[inline] + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } + fn write_all(&mut self, buf: &[u8]) -> io::Result<()> { + (&*self).write_all(buf) + } + fn write_all_vectored(&mut self, bufs: &mut [IoSlice<'_>]) -> io::Result<()> { + (&*self).write_all_vectored(bufs) + } + fn write_fmt(&mut self, args: fmt::Arguments<'_>) -> io::Result<()> { + (&*self).write_fmt(args) + } +} + +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &Stderr { fn write(&mut self, buf: &[u8]) -> io::Result { self.lock().write(buf) } @@ -782,6 +857,7 @@ impl Write for Stderr { self.lock().write_fmt(args) } } + #[stable(feature = "rust1", since = "1.0.0")] impl Write for StderrLock<'_> { fn write(&mut self, buf: &[u8]) -> io::Result { @@ -829,10 +905,18 @@ impl fmt::Debug for StderrLock<'_> { #[doc(hidden)] pub fn set_panic(sink: Option>) -> Option> { use crate::mem; - LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) + if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { + // LOCAL_STDERR is definitely None since LOCAL_STREAMS is false. + return None; + } + let s = LOCAL_STDERR.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( + |mut s| { + let _ = s.flush(); + Some(s) + }, + ); + LOCAL_STREAMS.store(true, Ordering::Relaxed); + s } /// Resets the thread-local stdout handle to the specified writer @@ -852,10 +936,18 @@ pub fn set_panic(sink: Option>) -> Option>) -> Option> { use crate::mem; - LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then(|mut s| { - let _ = s.flush(); - Some(s) - }) + if sink.is_none() && !LOCAL_STREAMS.load(Ordering::Relaxed) { + // LOCAL_STDOUT is definitely None since LOCAL_STREAMS is false. + return None; + } + let s = LOCAL_STDOUT.with(move |slot| mem::replace(&mut *slot.borrow_mut(), sink)).and_then( + |mut s| { + let _ = s.flush(); + Some(s) + }, + ); + LOCAL_STREAMS.store(true, Ordering::Relaxed); + s } /// Write `args` to output stream `local_s` if possible, `global_s` @@ -876,20 +968,26 @@ fn print_to( ) where T: Write, { - let result = local_s - .try_with(|s| { - // Note that we completely remove a local sink to write to in case - // our printing recursively panics/prints, so the recursive - // panic/print goes to the global sink instead of our local sink. - let prev = s.borrow_mut().take(); - if let Some(mut w) = prev { - let result = w.write_fmt(args); - *s.borrow_mut() = Some(w); - return result; - } - global_s().write_fmt(args) + let result = LOCAL_STREAMS + .load(Ordering::Relaxed) + .then(|| { + local_s + .try_with(|s| { + // Note that we completely remove a local sink to write to in case + // our printing recursively panics/prints, so the recursive + // panic/print goes to the global sink instead of our local sink. + let prev = s.borrow_mut().take(); + if let Some(mut w) = prev { + let result = w.write_fmt(args); + *s.borrow_mut() = Some(w); + return result; + } + global_s().write_fmt(args) + }) + .ok() }) - .unwrap_or_else(|_| global_s().write_fmt(args)); + .flatten() + .unwrap_or_else(|| global_s().write_fmt(args)); if let Err(e) = result { panic!("failed printing to {}: {}", label, e); @@ -920,54 +1018,3 @@ pub fn _eprint(args: fmt::Arguments<'_>) { #[cfg(test)] pub use realstd::io::{_eprint, _print}; - -#[cfg(test)] -mod tests { - use super::*; - use crate::panic::{RefUnwindSafe, UnwindSafe}; - use crate::thread; - - #[test] - fn stdout_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stdoutlock_unwind_safe() { - assert_unwind_safe::>(); - assert_unwind_safe::>(); - } - #[test] - fn stderr_unwind_safe() { - assert_unwind_safe::(); - } - #[test] - fn stderrlock_unwind_safe() { - assert_unwind_safe::>(); - assert_unwind_safe::>(); - } - - fn assert_unwind_safe() {} - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn panic_doesnt_poison() { - thread::spawn(|| { - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - panic!(); - }) - .join() - .unwrap_err(); - - let _a = stdin(); - let _a = _a.lock(); - let _a = stdout(); - let _a = _a.lock(); - let _a = stderr(); - let _a = _a.lock(); - } -} diff --git a/library/std/src/io/stdio/tests.rs b/library/std/src/io/stdio/tests.rs new file mode 100644 index 0000000000..04af500268 --- /dev/null +++ b/library/std/src/io/stdio/tests.rs @@ -0,0 +1,47 @@ +use super::*; +use crate::panic::{RefUnwindSafe, UnwindSafe}; +use crate::thread; + +#[test] +fn stdout_unwind_safe() { + assert_unwind_safe::(); +} +#[test] +fn stdoutlock_unwind_safe() { + assert_unwind_safe::>(); + assert_unwind_safe::>(); +} +#[test] +fn stderr_unwind_safe() { + assert_unwind_safe::(); +} +#[test] +fn stderrlock_unwind_safe() { + assert_unwind_safe::>(); + assert_unwind_safe::>(); +} + +fn assert_unwind_safe() {} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn panic_doesnt_poison() { + thread::spawn(|| { + let _a = stdin(); + let _a = _a.lock(); + let _a = stdout(); + let _a = _a.lock(); + let _a = stderr(); + let _a = _a.lock(); + panic!(); + }) + .join() + .unwrap_err(); + + let _a = stdin(); + let _a = _a.lock(); + let _a = stdout(); + let _a = _a.lock(); + let _a = stderr(); + let _a = _a.lock(); +} diff --git a/library/std/src/io/tests.rs b/library/std/src/io/tests.rs new file mode 100644 index 0000000000..913b28538b --- /dev/null +++ b/library/std/src/io/tests.rs @@ -0,0 +1,494 @@ +use super::{repeat, Cursor, SeekFrom}; +use crate::cmp::{self, min}; +use crate::io::prelude::*; +use crate::io::{self, IoSlice, IoSliceMut}; +use crate::ops::Deref; + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn read_until() { + let mut buf = Cursor::new(&b"12"[..]); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 2); + assert_eq!(v, b"12"); + + let mut buf = Cursor::new(&b"1233"[..]); + let mut v = Vec::new(); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 3); + assert_eq!(v, b"123"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 1); + assert_eq!(v, b"3"); + v.truncate(0); + assert_eq!(buf.read_until(b'3', &mut v).unwrap(), 0); + assert_eq!(v, []); +} + +#[test] +fn split() { + let buf = Cursor::new(&b"12"[..]); + let mut s = buf.split(b'3'); + assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); + assert!(s.next().is_none()); + + let buf = Cursor::new(&b"1233"[..]); + let mut s = buf.split(b'3'); + assert_eq!(s.next().unwrap().unwrap(), vec![b'1', b'2']); + assert_eq!(s.next().unwrap().unwrap(), vec![]); + assert!(s.next().is_none()); +} + +#[test] +fn read_line() { + let mut buf = Cursor::new(&b"12"[..]); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v).unwrap(), 2); + assert_eq!(v, "12"); + + let mut buf = Cursor::new(&b"12\n\n"[..]); + let mut v = String::new(); + assert_eq!(buf.read_line(&mut v).unwrap(), 3); + assert_eq!(v, "12\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v).unwrap(), 1); + assert_eq!(v, "\n"); + v.truncate(0); + assert_eq!(buf.read_line(&mut v).unwrap(), 0); + assert_eq!(v, ""); +} + +#[test] +fn lines() { + let buf = Cursor::new(&b"12\r"[..]); + let mut s = buf.lines(); + assert_eq!(s.next().unwrap().unwrap(), "12\r".to_string()); + assert!(s.next().is_none()); + + let buf = Cursor::new(&b"12\r\n\n"[..]); + let mut s = buf.lines(); + assert_eq!(s.next().unwrap().unwrap(), "12".to_string()); + assert_eq!(s.next().unwrap().unwrap(), "".to_string()); + assert!(s.next().is_none()); +} + +#[test] +fn read_to_end() { + let mut c = Cursor::new(&b""[..]); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v).unwrap(), 0); + assert_eq!(v, []); + + let mut c = Cursor::new(&b"1"[..]); + let mut v = Vec::new(); + assert_eq!(c.read_to_end(&mut v).unwrap(), 1); + assert_eq!(v, b"1"); + + let cap = 1024 * 1024; + let data = (0..cap).map(|i| (i / 3) as u8).collect::>(); + let mut v = Vec::new(); + let (a, b) = data.split_at(data.len() / 2); + assert_eq!(Cursor::new(a).read_to_end(&mut v).unwrap(), a.len()); + assert_eq!(Cursor::new(b).read_to_end(&mut v).unwrap(), b.len()); + assert_eq!(v, data); +} + +#[test] +fn read_to_string() { + let mut c = Cursor::new(&b""[..]); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v).unwrap(), 0); + assert_eq!(v, ""); + + let mut c = Cursor::new(&b"1"[..]); + let mut v = String::new(); + assert_eq!(c.read_to_string(&mut v).unwrap(), 1); + assert_eq!(v, "1"); + + let mut c = Cursor::new(&b"\xff"[..]); + let mut v = String::new(); + assert!(c.read_to_string(&mut v).is_err()); +} + +#[test] +fn read_exact() { + let mut buf = [0; 4]; + + let mut c = Cursor::new(&b""[..]); + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + + let mut c = Cursor::new(&b"123"[..]).chain(Cursor::new(&b"456789"[..])); + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"1234"); + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"5678"); + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); +} + +#[test] +fn read_exact_slice() { + let mut buf = [0; 4]; + + let mut c = &b""[..]; + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + + let mut c = &b"123"[..]; + assert_eq!(c.read_exact(&mut buf).unwrap_err().kind(), io::ErrorKind::UnexpectedEof); + // make sure the optimized (early returning) method is being used + assert_eq!(&buf, &[0; 4]); + + let mut c = &b"1234"[..]; + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"1234"); + + let mut c = &b"56789"[..]; + c.read_exact(&mut buf).unwrap(); + assert_eq!(&buf, b"5678"); + assert_eq!(c, b"9"); +} + +#[test] +fn take_eof() { + struct R; + + impl Read for R { + fn read(&mut self, _: &mut [u8]) -> io::Result { + Err(io::Error::new(io::ErrorKind::Other, "")) + } + } + impl BufRead for R { + fn fill_buf(&mut self) -> io::Result<&[u8]> { + Err(io::Error::new(io::ErrorKind::Other, "")) + } + fn consume(&mut self, _amt: usize) {} + } + + let mut buf = [0; 1]; + assert_eq!(0, R.take(0).read(&mut buf).unwrap()); + assert_eq!(b"", R.take(0).fill_buf().unwrap()); +} + +fn cmp_bufread(mut br1: Br1, mut br2: Br2, exp: &[u8]) { + let mut cat = Vec::new(); + loop { + let consume = { + let buf1 = br1.fill_buf().unwrap(); + let buf2 = br2.fill_buf().unwrap(); + let minlen = if buf1.len() < buf2.len() { buf1.len() } else { buf2.len() }; + assert_eq!(buf1[..minlen], buf2[..minlen]); + cat.extend_from_slice(&buf1[..minlen]); + minlen + }; + if consume == 0 { + break; + } + br1.consume(consume); + br2.consume(consume); + } + assert_eq!(br1.fill_buf().unwrap().len(), 0); + assert_eq!(br2.fill_buf().unwrap().len(), 0); + assert_eq!(&cat[..], &exp[..]) +} + +#[test] +fn chain_bufread() { + let testdata = b"ABCDEFGHIJKL"; + let chain1 = + (&testdata[..3]).chain(&testdata[3..6]).chain(&testdata[6..9]).chain(&testdata[9..]); + let chain2 = (&testdata[..4]).chain(&testdata[4..8]).chain(&testdata[8..]); + cmp_bufread(chain1, chain2, &testdata[..]); +} + +#[test] +fn chain_zero_length_read_is_not_eof() { + let a = b"A"; + let b = b"B"; + let mut s = String::new(); + let mut chain = (&a[..]).chain(&b[..]); + chain.read(&mut []).unwrap(); + chain.read_to_string(&mut s).unwrap(); + assert_eq!("AB", s); +} + +#[bench] +#[cfg_attr(target_os = "emscripten", ignore)] +fn bench_read_to_end(b: &mut test::Bencher) { + b.iter(|| { + let mut lr = repeat(1).take(10000000); + let mut vec = Vec::with_capacity(1024); + super::read_to_end(&mut lr, &mut vec) + }); +} + +#[test] +fn seek_len() -> io::Result<()> { + let mut c = Cursor::new(vec![0; 15]); + assert_eq!(c.stream_len()?, 15); + + c.seek(SeekFrom::End(0))?; + let old_pos = c.stream_position()?; + assert_eq!(c.stream_len()?, 15); + assert_eq!(c.stream_position()?, old_pos); + + c.seek(SeekFrom::Start(7))?; + c.seek(SeekFrom::Current(2))?; + let old_pos = c.stream_position()?; + assert_eq!(c.stream_len()?, 15); + assert_eq!(c.stream_position()?, old_pos); + + Ok(()) +} + +#[test] +fn seek_position() -> io::Result<()> { + // All `asserts` are duplicated here to make sure the method does not + // change anything about the seek state. + let mut c = Cursor::new(vec![0; 15]); + assert_eq!(c.stream_position()?, 0); + assert_eq!(c.stream_position()?, 0); + + c.seek(SeekFrom::End(0))?; + assert_eq!(c.stream_position()?, 15); + assert_eq!(c.stream_position()?, 15); + + c.seek(SeekFrom::Start(7))?; + c.seek(SeekFrom::Current(2))?; + assert_eq!(c.stream_position()?, 9); + assert_eq!(c.stream_position()?, 9); + + c.seek(SeekFrom::End(-3))?; + c.seek(SeekFrom::Current(1))?; + c.seek(SeekFrom::Current(-5))?; + assert_eq!(c.stream_position()?, 8); + assert_eq!(c.stream_position()?, 8); + + Ok(()) +} + +// A simple example reader which uses the default implementation of +// read_to_end. +struct ExampleSliceReader<'a> { + slice: &'a [u8], +} + +impl<'a> Read for ExampleSliceReader<'a> { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + let len = cmp::min(self.slice.len(), buf.len()); + buf[..len].copy_from_slice(&self.slice[..len]); + self.slice = &self.slice[len..]; + Ok(len) + } +} + +#[test] +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. + 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"); + + Ok(()) +} + +#[test] +fn io_slice_mut_advance() { + let mut buf1 = [1; 8]; + let mut buf2 = [2; 16]; + let mut buf3 = [3; 8]; + let mut bufs = &mut [ + IoSliceMut::new(&mut buf1), + IoSliceMut::new(&mut buf2), + IoSliceMut::new(&mut buf3), + ][..]; + + // Only in a single buffer.. + bufs = IoSliceMut::advance(bufs, 1); + assert_eq!(bufs[0].deref(), [1; 7].as_ref()); + assert_eq!(bufs[1].deref(), [2; 16].as_ref()); + assert_eq!(bufs[2].deref(), [3; 8].as_ref()); + + // Removing a buffer, leaving others as is. + bufs = IoSliceMut::advance(bufs, 7); + assert_eq!(bufs[0].deref(), [2; 16].as_ref()); + assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + + // Removing a buffer and removing from the next buffer. + bufs = IoSliceMut::advance(bufs, 18); + assert_eq!(bufs[0].deref(), [3; 6].as_ref()); +} + +#[test] +fn io_slice_mut_advance_empty_slice() { + let empty_bufs = &mut [][..]; + // Shouldn't panic. + IoSliceMut::advance(empty_bufs, 1); +} + +#[test] +fn io_slice_mut_advance_beyond_total_length() { + let mut buf1 = [1; 8]; + let mut bufs = &mut [IoSliceMut::new(&mut buf1)][..]; + + // Going beyond the total length should be ok. + bufs = IoSliceMut::advance(bufs, 9); + assert!(bufs.is_empty()); +} + +#[test] +fn io_slice_advance() { + let buf1 = [1; 8]; + let buf2 = [2; 16]; + let buf3 = [3; 8]; + let mut bufs = &mut [IoSlice::new(&buf1), IoSlice::new(&buf2), IoSlice::new(&buf3)][..]; + + // Only in a single buffer.. + bufs = IoSlice::advance(bufs, 1); + assert_eq!(bufs[0].deref(), [1; 7].as_ref()); + assert_eq!(bufs[1].deref(), [2; 16].as_ref()); + assert_eq!(bufs[2].deref(), [3; 8].as_ref()); + + // Removing a buffer, leaving others as is. + bufs = IoSlice::advance(bufs, 7); + assert_eq!(bufs[0].deref(), [2; 16].as_ref()); + assert_eq!(bufs[1].deref(), [3; 8].as_ref()); + + // Removing a buffer and removing from the next buffer. + bufs = IoSlice::advance(bufs, 18); + assert_eq!(bufs[0].deref(), [3; 6].as_ref()); +} + +#[test] +fn io_slice_advance_empty_slice() { + let empty_bufs = &mut [][..]; + // Shouldn't panic. + IoSlice::advance(empty_bufs, 1); +} + +#[test] +fn io_slice_advance_beyond_total_length() { + let buf1 = [1; 8]; + let mut bufs = &mut [IoSlice::new(&buf1)][..]; + + // Going beyond the total length should be ok. + bufs = IoSlice::advance(bufs, 9); + assert!(bufs.is_empty()); +} + +/// Create a new writer that reads from at most `n_bufs` and reads +/// `per_call` bytes (in total) per call to write. +fn test_writer(n_bufs: usize, per_call: usize) -> TestWriter { + TestWriter { n_bufs, per_call, written: Vec::new() } +} + +struct TestWriter { + n_bufs: usize, + per_call: usize, + written: Vec, +} + +impl Write for TestWriter { + fn write(&mut self, buf: &[u8]) -> io::Result { + self.write_vectored(&[IoSlice::new(buf)]) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let mut left = self.per_call; + let mut written = 0; + for buf in bufs.iter().take(self.n_bufs) { + let n = min(left, buf.len()); + self.written.extend_from_slice(&buf[0..n]); + left -= n; + written += n; + } + Ok(written) + } + + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + +#[test] +fn test_writer_read_from_one_buf() { + let mut writer = test_writer(1, 2); + + assert_eq!(writer.write(&[]).unwrap(), 0); + assert_eq!(writer.write_vectored(&[]).unwrap(), 0); + + // Read at most 2 bytes. + assert_eq!(writer.write(&[1, 1, 1]).unwrap(), 2); + let bufs = &[IoSlice::new(&[2, 2, 2])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 2); + + // Only read from first buf. + let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4, 4])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 1); + + assert_eq!(writer.written, &[1, 1, 2, 2, 3]); +} + +#[test] +fn test_writer_read_from_multiple_bufs() { + let mut writer = test_writer(3, 3); + + // Read at most 3 bytes from two buffers. + let bufs = &[IoSlice::new(&[1]), IoSlice::new(&[2, 2, 2])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 3); + + // Read at most 3 bytes from three buffers. + let bufs = &[IoSlice::new(&[3]), IoSlice::new(&[4]), IoSlice::new(&[5, 5])]; + assert_eq!(writer.write_vectored(bufs).unwrap(), 3); + + assert_eq!(writer.written, &[1, 2, 2, 3, 4, 5]); +} + +#[test] +fn test_write_all_vectored() { + #[rustfmt::skip] // Becomes unreadable otherwise. + let tests: Vec<(_, &'static [u8])> = vec![ + (vec![], &[]), + (vec![IoSlice::new(&[]), IoSlice::new(&[])], &[]), + (vec![IoSlice::new(&[1])], &[1]), + (vec![IoSlice::new(&[1, 2])], &[1, 2]), + (vec![IoSlice::new(&[1, 2, 3])], &[1, 2, 3]), + (vec![IoSlice::new(&[1, 2, 3, 4])], &[1, 2, 3, 4]), + (vec![IoSlice::new(&[1, 2, 3, 4, 5])], &[1, 2, 3, 4, 5]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2])], &[1, 2]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2])], &[1, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2])], &[1, 1, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2])], &[1, 1, 1, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 2, 2, 2, 2]), + (vec![IoSlice::new(&[1, 1, 1, 1]), IoSlice::new(&[2, 2, 2, 2])], &[1, 1, 1, 1, 2, 2, 2, 2]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2]), IoSlice::new(&[3])], &[1, 2, 3]), + (vec![IoSlice::new(&[1, 1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3])], &[1, 1, 2, 2, 3, 3]), + (vec![IoSlice::new(&[1]), IoSlice::new(&[2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 2, 2, 3, 3, 3]), + (vec![IoSlice::new(&[1, 1, 1]), IoSlice::new(&[2, 2, 2]), IoSlice::new(&[3, 3, 3])], &[1, 1, 1, 2, 2, 2, 3, 3, 3]), + ]; + + let writer_configs = &[(1, 1), (1, 2), (1, 3), (2, 2), (2, 3), (3, 3)]; + + for (n_bufs, per_call) in writer_configs.iter().copied() { + for (mut input, wanted) in tests.clone().into_iter() { + let mut writer = test_writer(n_bufs, per_call); + assert!(writer.write_all_vectored(&mut *input).is_ok()); + assert_eq!(&*writer.written, &*wanted); + } + } +} diff --git a/library/std/src/io/util.rs b/library/std/src/io/util.rs index a093b745b0..dc05b9648f 100644 --- a/library/std/src/io/util.rs +++ b/library/std/src/io/util.rs @@ -1,5 +1,8 @@ #![allow(missing_copy_implementations)] +#[cfg(test)] +mod tests; + use crate::fmt; use crate::io::{self, BufRead, ErrorKind, Initializer, IoSlice, IoSliceMut, Read, Write}; use crate::mem::MaybeUninit; @@ -49,24 +52,27 @@ where W: Write, { let mut buf = MaybeUninit::<[u8; super::DEFAULT_BUF_SIZE]>::uninit(); - // FIXME(#53491): This is calling `get_mut` and `get_ref` on an uninitialized - // `MaybeUninit`. Revisit this once we decided whether that is valid or not. - // This is still technically undefined behavior due to creating a reference - // to uninitialized data, but within libstd we can rely on more guarantees - // than if this code were in an external lib. + // FIXME: #42788 + // + // - This creates a (mut) reference to a slice of + // _uninitialized_ integers, which is **undefined behavior** + // + // - Only the standard library gets to soundly "ignore" this, + // based on its privileged knowledge of unstable rustc + // internals; unsafe { - reader.initializer().initialize(buf.get_mut()); + reader.initializer().initialize(buf.assume_init_mut()); } let mut written = 0; loop { - let len = match reader.read(unsafe { buf.get_mut() }) { + let len = match reader.read(unsafe { buf.assume_init_mut() }) { Ok(0) => return Ok(written), Ok(len) => len, Err(ref e) if e.kind() == ErrorKind::Interrupted => continue, Err(e) => return Err(e), }; - writer.write_all(unsafe { &buf.get_ref()[..len] })?; + writer.write_all(unsafe { &buf.assume_init_ref()[..len] })?; written += len as u64; } } @@ -248,58 +254,33 @@ impl Write for Sink { } } +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &Sink { + #[inline] + fn write(&mut self, buf: &[u8]) -> io::Result { + Ok(buf.len()) + } + + #[inline] + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + let total_len = bufs.iter().map(|b| b.len()).sum(); + Ok(total_len) + } + + #[inline] + fn is_write_vectored(&self) -> bool { + true + } + + #[inline] + fn flush(&mut self) -> io::Result<()> { + Ok(()) + } +} + #[stable(feature = "std_debug", since = "1.16.0")] impl fmt::Debug for Sink { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.pad("Sink { .. }") } } - -#[cfg(test)] -mod tests { - use crate::io::prelude::*; - use crate::io::{copy, empty, repeat, sink}; - - #[test] - fn copy_copies() { - let mut r = repeat(0).take(4); - let mut w = sink(); - assert_eq!(copy(&mut r, &mut w).unwrap(), 4); - - let mut r = repeat(0).take(1 << 17); - assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); - } - - #[test] - fn sink_sinks() { - let mut s = sink(); - assert_eq!(s.write(&[]).unwrap(), 0); - assert_eq!(s.write(&[0]).unwrap(), 1); - assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); - assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); - } - - #[test] - fn empty_reads() { - let mut e = empty(); - assert_eq!(e.read(&mut []).unwrap(), 0); - assert_eq!(e.read(&mut [0]).unwrap(), 0); - assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); - assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); - } - - #[test] - fn repeat_repeats() { - let mut r = repeat(4); - let mut b = [0; 1024]; - assert_eq!(r.read(&mut b).unwrap(), 1024); - assert!(b.iter().all(|b| *b == 4)); - } - - #[test] - fn take_some_bytes() { - assert_eq!(repeat(4).take(100).bytes().count(), 100); - assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); - assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); - } -} diff --git a/library/std/src/io/util/tests.rs b/library/std/src/io/util/tests.rs new file mode 100644 index 0000000000..e5e32ecb40 --- /dev/null +++ b/library/std/src/io/util/tests.rs @@ -0,0 +1,45 @@ +use crate::io::prelude::*; +use crate::io::{copy, empty, repeat, sink}; + +#[test] +fn copy_copies() { + let mut r = repeat(0).take(4); + let mut w = sink(); + assert_eq!(copy(&mut r, &mut w).unwrap(), 4); + + let mut r = repeat(0).take(1 << 17); + assert_eq!(copy(&mut r as &mut dyn Read, &mut w as &mut dyn Write).unwrap(), 1 << 17); +} + +#[test] +fn sink_sinks() { + let mut s = sink(); + assert_eq!(s.write(&[]).unwrap(), 0); + assert_eq!(s.write(&[0]).unwrap(), 1); + assert_eq!(s.write(&[0; 1024]).unwrap(), 1024); + assert_eq!(s.by_ref().write(&[0; 1024]).unwrap(), 1024); +} + +#[test] +fn empty_reads() { + let mut e = empty(); + assert_eq!(e.read(&mut []).unwrap(), 0); + assert_eq!(e.read(&mut [0]).unwrap(), 0); + assert_eq!(e.read(&mut [0; 1024]).unwrap(), 0); + assert_eq!(e.by_ref().read(&mut [0; 1024]).unwrap(), 0); +} + +#[test] +fn repeat_repeats() { + let mut r = repeat(4); + let mut b = [0; 1024]; + assert_eq!(r.read(&mut b).unwrap(), 1024); + assert!(b.iter().all(|b| *b == 4)); +} + +#[test] +fn take_some_bytes() { + assert_eq!(repeat(4).take(100).bytes().count(), 100); + assert_eq!(repeat(4).take(100).bytes().next().unwrap().unwrap(), 4); + assert_eq!(repeat(1).take(10).chain(repeat(2).take(10)).bytes().count(), 20); +} diff --git a/library/std/src/keyword_docs.rs b/library/std/src/keyword_docs.rs index af25c39fcc..54ce0e7b83 100644 --- a/library/std/src/keyword_docs.rs +++ b/library/std/src/keyword_docs.rs @@ -107,7 +107,7 @@ mod break_keyword {} /// Sometimes a certain value is used many times throughout a program, and it can become /// inconvenient to copy it over and over. What's more, it's not always possible or desirable to /// make it a variable that gets carried around to each function that needs it. In these cases, the -/// `const` keyword provides a convenient alternative to code duplication. +/// `const` keyword provides a convenient alternative to code duplication: /// /// ```rust /// const THING: u32 = 0xABAD1DEA; @@ -115,10 +115,12 @@ mod break_keyword {} /// let foo = 123 + THING; /// ``` /// -/// Constants must be explicitly typed, unlike with `let` you can't ignore its type and let the -/// compiler figure it out. Any constant value can be defined in a const, which in practice happens -/// to be most things that would be reasonable to have a constant (barring `const fn`s). For -/// example, you can't have a File as a `const`. +/// Constants must be explicitly typed; unlike with `let`, you can't ignore their type and let the +/// compiler figure it out. Any constant value can be defined in a `const`, which in practice happens +/// to be most things that would be reasonable to have in a constant (barring `const fn`s). For +/// example, you can't have a [`File`] as a `const`. +/// +/// [`File`]: crate::fs::File /// /// The only lifetime allowed in a constant is `'static`, which is the lifetime that encompasses /// all others in a Rust program. For example, if you wanted to define a constant string, it would @@ -128,7 +130,7 @@ mod break_keyword {} /// const WORDS: &'static str = "hello rust!"; /// ``` /// -/// Thanks to static lifetime elision, you usually don't have to explicitly use 'static: +/// Thanks to static lifetime elision, you usually don't have to explicitly use `'static`: /// /// ```rust /// const WORDS: &str = "hello convenience!"; @@ -136,19 +138,19 @@ mod break_keyword {} /// /// `const` items looks remarkably similar to `static` items, which introduces some confusion as /// to which one should be used at which times. To put it simply, constants are inlined wherever -/// they're used, making using them identical to simply replacing the name of the const with its -/// value. Static variables on the other hand point to a single location in memory, which all +/// they're used, making using them identical to simply replacing the name of the `const` with its +/// value. Static variables, on the other hand, point to a single location in memory, which all /// accesses share. This means that, unlike with constants, they can't have destructors, and act as /// a single value across the entire codebase. /// -/// Constants, as with statics, should always be in SCREAMING_SNAKE_CASE. +/// Constants, like statics, should always be in `SCREAMING_SNAKE_CASE`. /// /// The `const` keyword is also used in raw pointers in combination with `mut`, as seen in `*const -/// T` and `*mut T`. More about that can be read at the [pointer] primitive part of the Rust docs. +/// T` and `*mut T`. More about `const` as used in raw pointers can be read at the Rust docs for the [pointer primitive]. /// -/// For more detail on `const`, see the [Rust Book] or the [Reference] +/// For more detail on `const`, see the [Rust Book] or the [Reference]. /// -/// [pointer]: primitive.pointer.html +/// [pointer primitive]: primitive.pointer.html /// [Rust Book]: /// ../book/ch03-01-variables-and-mutability.html#differences-between-variables-and-constants /// [Reference]: ../reference/items/constant-items.html diff --git a/library/std/src/lazy.rs b/library/std/src/lazy.rs index f0548582d2..e0095e64fa 100644 --- a/library/std/src/lazy.rs +++ b/library/std/src/lazy.rs @@ -1,9 +1,13 @@ //! Lazy values and one-time initialization of static data. +#[cfg(test)] +mod tests; + use crate::{ cell::{Cell, UnsafeCell}, fmt, - mem::{self, MaybeUninit}, + marker::PhantomData, + mem::MaybeUninit, ops::{Deref, Drop}, panic::{RefUnwindSafe, UnwindSafe}, sync::Once, @@ -43,6 +47,26 @@ pub struct SyncOnceCell { once: Once, // Whether or not the value is initialized is tracked by `state_and_queue`. value: UnsafeCell>, + /// `PhantomData` to make sure dropck understands we're dropping T in our Drop impl. + /// + /// ```compile_fail,E0597 + /// #![feature(once_cell)] + /// + /// use std::lazy::SyncOnceCell; + /// + /// struct A<'a>(&'a str); + /// + /// impl<'a> Drop for A<'a> { + /// fn drop(&mut self) {} + /// } + /// + /// let cell = SyncOnceCell::new(); + /// { + /// let s = String::new(); + /// let _ = cell.set(A(&s)); + /// } + /// ``` + _marker: PhantomData, } // Why do we need `T: Send`? @@ -116,7 +140,11 @@ impl SyncOnceCell { /// Creates a new empty cell. #[unstable(feature = "once_cell", issue = "74465")] pub const fn new() -> SyncOnceCell { - SyncOnceCell { once: Once::new(), value: UnsafeCell::new(MaybeUninit::uninit()) } + SyncOnceCell { + once: Once::new(), + value: UnsafeCell::new(MaybeUninit::uninit()), + _marker: PhantomData, + } } /// Gets the reference to the underlying value. @@ -265,7 +293,7 @@ impl SyncOnceCell { debug_assert!(self.is_initialized()); - // Safety: The inner value has been initialized + // SAFETY: The inner value has been initialized Ok(unsafe { self.get_unchecked() }) } @@ -288,13 +316,7 @@ impl SyncOnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn into_inner(mut self) -> Option { - // Safety: Safe because we immediately free `self` without dropping - let inner = unsafe { self.take_inner() }; - - // Don't drop this `SyncOnceCell`. We just moved out one of the fields, but didn't set - // the state to uninitialized. - mem::ManuallyDrop::new(self); - inner + self.take() } /// Takes the value out of this `SyncOnceCell`, moving it back to an uninitialized state. @@ -320,22 +342,12 @@ impl SyncOnceCell { /// ``` #[unstable(feature = "once_cell", issue = "74465")] pub fn take(&mut self) -> Option { - mem::take(self).into_inner() - } - - /// Takes the wrapped value out of a `SyncOnceCell`. - /// Afterwards the cell is no longer initialized. - /// - /// Safety: The cell must now be free'd WITHOUT dropping. No other usages of the cell - /// are valid. Only used by `into_inner` and `drop`. - unsafe fn take_inner(&mut self) -> Option { - // The mutable reference guarantees there are no other threads that can observe us - // taking out the wrapped value. - // Right after this function `self` is supposed to be freed, so it makes little sense - // to atomically set the state to uninitialized. if self.is_initialized() { - let value = mem::replace(&mut self.value, UnsafeCell::new(MaybeUninit::uninit())); - Some(value.into_inner().assume_init()) + self.once = Once::new(); + // SAFETY: `self.value` is initialized and contains a valid `T`. + // `self.once` is reset, so `is_initialized()` will be false again + // which prevents the value from being read twice. + unsafe { Some((&mut *self.value.get()).assume_init_read()) } } else { None } @@ -376,21 +388,24 @@ impl SyncOnceCell { /// Safety: The value must be initialized unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); - (&*self.value.get()).get_ref() + (&*self.value.get()).assume_init_ref() } /// Safety: The value must be initialized unsafe fn get_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is_initialized()); - (&mut *self.value.get()).get_mut() + (&mut *self.value.get()).assume_init_mut() } } unsafe impl<#[may_dangle] T> Drop for SyncOnceCell { fn drop(&mut self) { - // Safety: The cell is being dropped, so it can't be accessed again. - // We also don't touch the `T`, which validates our usage of #[may_dangle]. - unsafe { self.take_inner() }; + if self.is_initialized() { + // Safety: The cell is initialized and being dropped, so it can't + // be accessed again. We also don't touch the `T` other than + // dropping it, which validates our usage of #[may_dangle]. + unsafe { (&mut *self.value.get()).assume_init_drop() }; + } } } @@ -506,333 +521,3 @@ impl Default for SyncLazy { SyncLazy::new(T::default) } } - -#[cfg(test)] -mod tests { - use crate::{ - lazy::{Lazy, SyncLazy, SyncOnceCell}, - panic, - sync::{ - atomic::{AtomicUsize, Ordering::SeqCst}, - mpsc::channel, - Mutex, - }, - thread, - }; - - #[test] - fn lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: Lazy> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn lazy_poisoning() { - let x: Lazy = Lazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); - assert!(res.is_err()); - } - } - - fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { - thread::spawn(f).join().unwrap() - } - - #[test] - fn sync_once_cell() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); - - assert!(ONCE_CELL.get().is_none()); - - spawn_and_wait(|| { - ONCE_CELL.get_or_init(|| 92); - assert_eq!(ONCE_CELL.get(), Some(&92)); - }); - - ONCE_CELL.get_or_init(|| panic!("Kabom!")); - assert_eq!(ONCE_CELL.get(), Some(&92)); - } - - #[test] - fn sync_once_cell_get_mut() { - let mut c = SyncOnceCell::new(); - assert!(c.get_mut().is_none()); - c.set(90).unwrap(); - *c.get_mut().unwrap() += 2; - assert_eq!(c.get_mut(), Some(&mut 92)); - } - - #[test] - fn sync_once_cell_get_unchecked() { - let c = SyncOnceCell::new(); - c.set(92).unwrap(); - unsafe { - assert_eq!(c.get_unchecked(), &92); - } - } - - #[test] - fn sync_once_cell_drop() { - static DROP_CNT: AtomicUsize = AtomicUsize::new(0); - struct Dropper; - impl Drop for Dropper { - fn drop(&mut self) { - DROP_CNT.fetch_add(1, SeqCst); - } - } - - let x = SyncOnceCell::new(); - spawn_and_wait(move || { - x.get_or_init(|| Dropper); - assert_eq!(DROP_CNT.load(SeqCst), 0); - drop(x); - }); - - assert_eq!(DROP_CNT.load(SeqCst), 1); - } - - #[test] - fn sync_once_cell_drop_empty() { - let x = SyncOnceCell::::new(); - drop(x); - } - - #[test] - fn clone() { - let s = SyncOnceCell::new(); - let c = s.clone(); - assert!(c.get().is_none()); - - s.set("hello".to_string()).unwrap(); - let c = s.clone(); - assert_eq!(c.get().map(String::as_str), Some("hello")); - } - - #[test] - fn get_or_try_init() { - let cell: SyncOnceCell = SyncOnceCell::new(); - assert!(cell.get().is_none()); - - let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); - assert!(res.is_err()); - assert!(!cell.is_initialized()); - assert!(cell.get().is_none()); - - assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); - - assert_eq!( - cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), - Ok(&"hello".to_string()) - ); - assert_eq!(cell.get(), Some(&"hello".to_string())); - } - - #[test] - fn from_impl() { - assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); - assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); - } - - #[test] - fn partialeq_impl() { - assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); - assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); - - assert!(SyncOnceCell::::new() == SyncOnceCell::new()); - assert!(SyncOnceCell::::new() != SyncOnceCell::from("value".to_owned())); - } - - #[test] - fn into_inner() { - let cell: SyncOnceCell = SyncOnceCell::new(); - assert_eq!(cell.into_inner(), None); - let cell = SyncOnceCell::new(); - cell.set("hello".to_string()).unwrap(); - assert_eq!(cell.into_inner(), Some("hello".to_string())); - } - - #[test] - fn sync_lazy_new() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - static SYNC_LAZY: SyncLazy = SyncLazy::new(|| { - CALLED.fetch_add(1, SeqCst); - 92 - }); - - assert_eq!(CALLED.load(SeqCst), 0); - - spawn_and_wait(|| { - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); - }); - - let y = *SYNC_LAZY - 30; - assert_eq!(y, 62); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn sync_lazy_default() { - static CALLED: AtomicUsize = AtomicUsize::new(0); - - struct Foo(u8); - impl Default for Foo { - fn default() -> Self { - CALLED.fetch_add(1, SeqCst); - Foo(42) - } - } - - let lazy: SyncLazy> = <_>::default(); - - assert_eq!(CALLED.load(SeqCst), 0); - - assert_eq!(lazy.lock().unwrap().0, 42); - assert_eq!(CALLED.load(SeqCst), 1); - - lazy.lock().unwrap().0 = 21; - - assert_eq!(lazy.lock().unwrap().0, 21); - assert_eq!(CALLED.load(SeqCst), 1); - } - - #[test] - fn static_sync_lazy() { - static XS: SyncLazy> = SyncLazy::new(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }); - - spawn_and_wait(|| { - assert_eq!(&*XS, &vec![1, 2, 3]); - }); - - assert_eq!(&*XS, &vec![1, 2, 3]); - } - - #[test] - fn static_sync_lazy_via_fn() { - fn xs() -> &'static Vec { - static XS: SyncOnceCell> = SyncOnceCell::new(); - XS.get_or_init(|| { - let mut xs = Vec::new(); - xs.push(1); - xs.push(2); - xs.push(3); - xs - }) - } - assert_eq!(xs(), &vec![1, 2, 3]); - } - - #[test] - fn sync_lazy_poisoning() { - let x: SyncLazy = SyncLazy::new(|| panic!("kaboom")); - for _ in 0..2 { - let res = panic::catch_unwind(|| x.len()); - assert!(res.is_err()); - } - } - - #[test] - fn is_sync_send() { - fn assert_traits() {} - assert_traits::>(); - assert_traits::>(); - } - - #[test] - fn eval_once_macro() { - macro_rules! eval_once { - (|| -> $ty:ty { - $($body:tt)* - }) => {{ - static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); - fn init() -> $ty { - $($body)* - } - ONCE_CELL.get_or_init(init) - }}; - } - - let fib: &'static Vec = eval_once! { - || -> Vec { - let mut res = vec![1, 1]; - for i in 0..10 { - let next = res[i] + res[i + 1]; - res.push(next); - } - res - } - }; - assert_eq!(fib[5], 8) - } - - #[test] - fn sync_once_cell_does_not_leak_partially_constructed_boxes() { - static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); - - let n_readers = 10; - let n_writers = 3; - const MSG: &str = "Hello, World"; - - let (tx, rx) = channel(); - - for _ in 0..n_readers { - let tx = tx.clone(); - thread::spawn(move || { - loop { - if let Some(msg) = ONCE_CELL.get() { - tx.send(msg).unwrap(); - break; - } - #[cfg(target_env = "sgx")] - crate::thread::yield_now(); - } - }); - } - for _ in 0..n_writers { - thread::spawn(move || { - let _ = ONCE_CELL.set(MSG.to_owned()); - }); - } - - for _ in 0..n_readers { - let msg = rx.recv().unwrap(); - assert_eq!(msg, MSG); - } - } - - #[test] - fn dropck() { - let cell = SyncOnceCell::new(); - { - let s = String::new(); - cell.set(&s).unwrap(); - } - } -} diff --git a/library/std/src/lazy/tests.rs b/library/std/src/lazy/tests.rs new file mode 100644 index 0000000000..a170edbd99 --- /dev/null +++ b/library/std/src/lazy/tests.rs @@ -0,0 +1,323 @@ +use crate::{ + lazy::{Lazy, SyncLazy, SyncOnceCell}, + panic, + sync::{ + atomic::{AtomicUsize, Ordering::SeqCst}, + mpsc::channel, + Mutex, + }, + thread, +}; + +#[test] +fn lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: Lazy> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn lazy_poisoning() { + let x: Lazy = Lazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(panic::AssertUnwindSafe(|| x.len())); + assert!(res.is_err()); + } +} + +fn spawn_and_wait(f: impl FnOnce() -> R + Send + 'static) -> R { + thread::spawn(f).join().unwrap() +} + +#[test] +fn sync_once_cell() { + static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); + + assert!(ONCE_CELL.get().is_none()); + + spawn_and_wait(|| { + ONCE_CELL.get_or_init(|| 92); + assert_eq!(ONCE_CELL.get(), Some(&92)); + }); + + ONCE_CELL.get_or_init(|| panic!("Kabom!")); + assert_eq!(ONCE_CELL.get(), Some(&92)); +} + +#[test] +fn sync_once_cell_get_mut() { + let mut c = SyncOnceCell::new(); + assert!(c.get_mut().is_none()); + c.set(90).unwrap(); + *c.get_mut().unwrap() += 2; + assert_eq!(c.get_mut(), Some(&mut 92)); +} + +#[test] +fn sync_once_cell_get_unchecked() { + let c = SyncOnceCell::new(); + c.set(92).unwrap(); + unsafe { + assert_eq!(c.get_unchecked(), &92); + } +} + +#[test] +fn sync_once_cell_drop() { + static DROP_CNT: AtomicUsize = AtomicUsize::new(0); + struct Dropper; + impl Drop for Dropper { + fn drop(&mut self) { + DROP_CNT.fetch_add(1, SeqCst); + } + } + + let x = SyncOnceCell::new(); + spawn_and_wait(move || { + x.get_or_init(|| Dropper); + assert_eq!(DROP_CNT.load(SeqCst), 0); + drop(x); + }); + + assert_eq!(DROP_CNT.load(SeqCst), 1); +} + +#[test] +fn sync_once_cell_drop_empty() { + let x = SyncOnceCell::::new(); + drop(x); +} + +#[test] +fn clone() { + let s = SyncOnceCell::new(); + let c = s.clone(); + assert!(c.get().is_none()); + + s.set("hello".to_string()).unwrap(); + let c = s.clone(); + assert_eq!(c.get().map(String::as_str), Some("hello")); +} + +#[test] +fn get_or_try_init() { + let cell: SyncOnceCell = SyncOnceCell::new(); + assert!(cell.get().is_none()); + + let res = panic::catch_unwind(|| cell.get_or_try_init(|| -> Result<_, ()> { panic!() })); + assert!(res.is_err()); + assert!(!cell.is_initialized()); + assert!(cell.get().is_none()); + + assert_eq!(cell.get_or_try_init(|| Err(())), Err(())); + + assert_eq!(cell.get_or_try_init(|| Ok::<_, ()>("hello".to_string())), Ok(&"hello".to_string())); + assert_eq!(cell.get(), Some(&"hello".to_string())); +} + +#[test] +fn from_impl() { + assert_eq!(SyncOnceCell::from("value").get(), Some(&"value")); + assert_ne!(SyncOnceCell::from("foo").get(), Some(&"bar")); +} + +#[test] +fn partialeq_impl() { + assert!(SyncOnceCell::from("value") == SyncOnceCell::from("value")); + assert!(SyncOnceCell::from("foo") != SyncOnceCell::from("bar")); + + assert!(SyncOnceCell::::new() == SyncOnceCell::new()); + assert!(SyncOnceCell::::new() != SyncOnceCell::from("value".to_owned())); +} + +#[test] +fn into_inner() { + let cell: SyncOnceCell = SyncOnceCell::new(); + assert_eq!(cell.into_inner(), None); + let cell = SyncOnceCell::new(); + cell.set("hello".to_string()).unwrap(); + assert_eq!(cell.into_inner(), Some("hello".to_string())); +} + +#[test] +fn sync_lazy_new() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + static SYNC_LAZY: SyncLazy = SyncLazy::new(|| { + CALLED.fetch_add(1, SeqCst); + 92 + }); + + assert_eq!(CALLED.load(SeqCst), 0); + + spawn_and_wait(|| { + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); + }); + + let y = *SYNC_LAZY - 30; + assert_eq!(y, 62); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn sync_lazy_default() { + static CALLED: AtomicUsize = AtomicUsize::new(0); + + struct Foo(u8); + impl Default for Foo { + fn default() -> Self { + CALLED.fetch_add(1, SeqCst); + Foo(42) + } + } + + let lazy: SyncLazy> = <_>::default(); + + assert_eq!(CALLED.load(SeqCst), 0); + + assert_eq!(lazy.lock().unwrap().0, 42); + assert_eq!(CALLED.load(SeqCst), 1); + + lazy.lock().unwrap().0 = 21; + + assert_eq!(lazy.lock().unwrap().0, 21); + assert_eq!(CALLED.load(SeqCst), 1); +} + +#[test] +fn static_sync_lazy() { + static XS: SyncLazy> = SyncLazy::new(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }); + + spawn_and_wait(|| { + assert_eq!(&*XS, &vec![1, 2, 3]); + }); + + assert_eq!(&*XS, &vec![1, 2, 3]); +} + +#[test] +fn static_sync_lazy_via_fn() { + fn xs() -> &'static Vec { + static XS: SyncOnceCell> = SyncOnceCell::new(); + XS.get_or_init(|| { + let mut xs = Vec::new(); + xs.push(1); + xs.push(2); + xs.push(3); + xs + }) + } + assert_eq!(xs(), &vec![1, 2, 3]); +} + +#[test] +fn sync_lazy_poisoning() { + let x: SyncLazy = SyncLazy::new(|| panic!("kaboom")); + for _ in 0..2 { + let res = panic::catch_unwind(|| x.len()); + assert!(res.is_err()); + } +} + +#[test] +fn is_sync_send() { + fn assert_traits() {} + assert_traits::>(); + assert_traits::>(); +} + +#[test] +fn eval_once_macro() { + macro_rules! eval_once { + (|| -> $ty:ty { + $($body:tt)* + }) => {{ + static ONCE_CELL: SyncOnceCell<$ty> = SyncOnceCell::new(); + fn init() -> $ty { + $($body)* + } + ONCE_CELL.get_or_init(init) + }}; + } + + let fib: &'static Vec = eval_once! { + || -> Vec { + let mut res = vec![1, 1]; + for i in 0..10 { + let next = res[i] + res[i + 1]; + res.push(next); + } + res + } + }; + assert_eq!(fib[5], 8) +} + +#[test] +fn sync_once_cell_does_not_leak_partially_constructed_boxes() { + static ONCE_CELL: SyncOnceCell = SyncOnceCell::new(); + + let n_readers = 10; + let n_writers = 3; + const MSG: &str = "Hello, World"; + + let (tx, rx) = channel(); + + for _ in 0..n_readers { + let tx = tx.clone(); + thread::spawn(move || { + loop { + if let Some(msg) = ONCE_CELL.get() { + tx.send(msg).unwrap(); + break; + } + #[cfg(target_env = "sgx")] + crate::thread::yield_now(); + } + }); + } + for _ in 0..n_writers { + thread::spawn(move || { + let _ = ONCE_CELL.set(MSG.to_owned()); + }); + } + + for _ in 0..n_readers { + let msg = rx.recv().unwrap(); + assert_eq!(msg, MSG); + } +} + +#[test] +fn dropck() { + let cell = SyncOnceCell::new(); + { + let s = String::new(); + cell.set(&s).unwrap(); + } +} diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 1142b74ff0..b2bd5f4da5 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -226,9 +226,9 @@ #![feature(asm)] #![feature(associated_type_bounds)] #![feature(atomic_mut_ptr)] +#![feature(bool_to_option)] #![feature(box_syntax)] #![feature(c_variadic)] -#![feature(can_vector)] #![feature(cfg_accessible)] #![feature(cfg_target_has_atomic)] #![feature(cfg_target_thread_local)] @@ -237,17 +237,23 @@ #![feature(clamp)] #![feature(concat_idents)] #![feature(const_cstr_unchecked)] +#![cfg_attr(not(bootstrap), feature(const_fn_floating_point_arithmetic))] #![feature(const_fn_transmute)] +#![feature(const_fn)] +#![cfg_attr(not(bootstrap), feature(const_fn_fn_ptr_basics))] +#![feature(const_ip)] +#![feature(const_ipv6)] #![feature(const_raw_ptr_deref)] +#![feature(const_ipv4)] #![feature(container_error_extra)] #![feature(core_intrinsics)] #![feature(custom_test_frameworks)] #![feature(decl_macro)] -#![feature(doc_alias)] +#![cfg_attr(bootstrap, feature(doc_alias))] #![feature(doc_cfg)] #![feature(doc_keyword)] #![feature(doc_masked)] -#![cfg_attr(not(bootstrap), feature(doc_spotlight))] +#![feature(doc_spotlight)] #![feature(dropck_eyepatch)] #![feature(duration_constants)] #![feature(exact_size_is_empty)] @@ -256,18 +262,15 @@ #![feature(external_doc)] #![feature(fn_traits)] #![feature(format_args_nl)] -#![feature(future_readiness_fns)] #![feature(gen_future)] #![feature(generator_trait)] #![feature(global_asm)] -#![feature(hash_raw_entry)] #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(int_error_matching)] #![feature(integer_atomics)] #![feature(into_future)] #![feature(lang_items)] -#![feature(libc)] #![feature(link_args)] #![feature(linkage)] #![feature(llvm_asm)] @@ -308,12 +311,15 @@ #![feature(str_internals)] #![feature(test)] #![feature(thread_local)] +#![feature(thread_local_internals)] #![feature(toowned_clone_into)] #![feature(total_cmp)] #![feature(trace_macros)] #![feature(try_reserve)] #![feature(unboxed_closures)] #![feature(unsafe_block_in_unsafe_fn)] +#![feature(unsafe_cell_get_mut)] +#![feature(unsafe_cell_raw_get)] #![feature(untagged_unions)] #![feature(unwind_attributes)] #![feature(vec_into_raw_parts)] diff --git a/library/std/src/memchr.rs b/library/std/src/memchr.rs index d69294b2d2..86a08f75a8 100644 --- a/library/std/src/memchr.rs +++ b/library/std/src/memchr.rs @@ -1,6 +1,9 @@ // Original implementation taken from rust-memchr. // Copyright 2015 Andrew Gallant, bluss and Nicolas Koch +#[cfg(test)] +mod tests; + /// A safe interface to `memchr`. /// /// Returns the index corresponding to the first occurrence of `needle` in @@ -44,90 +47,3 @@ pub fn memchr(needle: u8, haystack: &[u8]) -> Option { pub fn memrchr(needle: u8, haystack: &[u8]) -> Option { crate::sys::memchr::memrchr(needle, haystack) } - -#[cfg(test)] -mod tests { - // test the implementations for the current platform - use super::{memchr, memrchr}; - - #[test] - fn matches_one() { - assert_eq!(Some(0), memchr(b'a', b"a")); - } - - #[test] - fn matches_begin() { - assert_eq!(Some(0), memchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end() { - assert_eq!(Some(4), memchr(b'z', b"aaaaz")); - } - - #[test] - fn matches_nul() { - assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul() { - assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); - } - - #[test] - fn no_match_empty() { - assert_eq!(None, memchr(b'a', b"")); - } - - #[test] - fn no_match() { - assert_eq!(None, memchr(b'a', b"xyz")); - } - - #[test] - fn matches_one_reversed() { - assert_eq!(Some(0), memrchr(b'a', b"a")); - } - - #[test] - fn matches_begin_reversed() { - assert_eq!(Some(3), memrchr(b'a', b"aaaa")); - } - - #[test] - fn matches_end_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); - } - - #[test] - fn matches_nul_reversed() { - assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); - } - - #[test] - fn matches_past_nul_reversed() { - assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); - } - - #[test] - fn no_match_empty_reversed() { - assert_eq!(None, memrchr(b'a', b"")); - } - - #[test] - fn no_match_reversed() { - assert_eq!(None, memrchr(b'a', b"xyz")); - } - - #[test] - fn each_alignment() { - let mut data = [1u8; 64]; - let needle = 2; - let pos = 40; - data[pos] = needle; - for start in 0..16 { - assert_eq!(Some(pos - start), memchr(needle, &data[start..])); - } - } -} diff --git a/library/std/src/memchr/tests.rs b/library/std/src/memchr/tests.rs new file mode 100644 index 0000000000..557d749c7f --- /dev/null +++ b/library/std/src/memchr/tests.rs @@ -0,0 +1,86 @@ +// Original implementation taken from rust-memchr. +// Copyright 2015 Andrew Gallant, bluss and Nicolas Koch + +// test the implementations for the current platform +use super::{memchr, memrchr}; + +#[test] +fn matches_one() { + assert_eq!(Some(0), memchr(b'a', b"a")); +} + +#[test] +fn matches_begin() { + assert_eq!(Some(0), memchr(b'a', b"aaaa")); +} + +#[test] +fn matches_end() { + assert_eq!(Some(4), memchr(b'z', b"aaaaz")); +} + +#[test] +fn matches_nul() { + assert_eq!(Some(4), memchr(b'\x00', b"aaaa\x00")); +} + +#[test] +fn matches_past_nul() { + assert_eq!(Some(5), memchr(b'z', b"aaaa\x00z")); +} + +#[test] +fn no_match_empty() { + assert_eq!(None, memchr(b'a', b"")); +} + +#[test] +fn no_match() { + assert_eq!(None, memchr(b'a', b"xyz")); +} + +#[test] +fn matches_one_reversed() { + assert_eq!(Some(0), memrchr(b'a', b"a")); +} + +#[test] +fn matches_begin_reversed() { + assert_eq!(Some(3), memrchr(b'a', b"aaaa")); +} + +#[test] +fn matches_end_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"zaaaa")); +} + +#[test] +fn matches_nul_reversed() { + assert_eq!(Some(4), memrchr(b'\x00', b"aaaa\x00")); +} + +#[test] +fn matches_past_nul_reversed() { + assert_eq!(Some(0), memrchr(b'z', b"z\x00aaaa")); +} + +#[test] +fn no_match_empty_reversed() { + assert_eq!(None, memrchr(b'a', b"")); +} + +#[test] +fn no_match_reversed() { + assert_eq!(None, memrchr(b'a', b"xyz")); +} + +#[test] +fn each_alignment() { + let mut data = [1u8; 64]; + let needle = 2; + let pos = 40; + data[pos] = needle; + for start in 0..16 { + assert_eq!(Some(pos - start), memchr(needle, &data[start..])); + } +} diff --git a/library/std/src/net/addr.rs b/library/std/src/net/addr.rs index d7d96862b2..e213963d25 100644 --- a/library/std/src/net/addr.rs +++ b/library/std/src/net/addr.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cmp::Ordering; use crate::convert::TryInto; use crate::fmt; @@ -210,8 +213,6 @@ impl SocketAddr { /// /// [IP address]: IpAddr /// [`IPv4` address]: IpAddr::V4 - /// [`false`]: ../../std/primitive.bool.html - /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -232,8 +233,6 @@ impl SocketAddr { /// /// [IP address]: IpAddr /// [`IPv6` address]: IpAddr::V6 - /// [`false`]: ../../std/primitive.bool.html - /// [`true`]: ../../std/primitive.bool.html /// /// # Examples /// @@ -746,9 +745,9 @@ impl hash::Hash for SocketAddrV6 { /// `(`[`Ipv4Addr`]`, `[`u16`]`)`, `(`[`Ipv6Addr`]`, `[`u16`]`)`: /// [`to_socket_addrs`] constructs a [`SocketAddr`] trivially. /// -/// * `(`[`&str`]`, `[`u16`]`)`: the string 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. +/// name. [`u16`] is the port number. /// /// * [`&str`]: the string should be either a string representation of a /// [`SocketAddr`] as expected by its [`FromStr`] implementation or a string like @@ -991,236 +990,3 @@ impl ToSocketAddrs for String { (&**self).to_socket_addrs() } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::net::test::{sa4, sa6, tsa}; - use crate::net::*; - - #[test] - fn to_socket_addr_ipaddr_u16() { - let a = Ipv4Addr::new(77, 88, 21, 11); - let p = 12345; - let e = SocketAddr::V4(SocketAddrV4::new(a, p)); - assert_eq!(Ok(vec![e]), tsa((a, p))); - } - - #[test] - fn to_socket_addr_str_u16() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352))); - - let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); - assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); - - let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); - #[cfg(not(target_env = "sgx"))] - assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); - #[cfg(target_env = "sgx")] - let _ = a; - } - - #[test] - fn to_socket_addr_str() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352")); - - let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); - assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); - - let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); - #[cfg(not(target_env = "sgx"))] - assert!(tsa("localhost:23924").unwrap().contains(&a)); - #[cfg(target_env = "sgx")] - let _ = a; - } - - #[test] - fn to_socket_addr_string() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); - assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352"))); - assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352"))); - assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352"))); - - let s = format!("{}:{}", "77.88.21.11", "24352"); - assert_eq!(Ok(vec![a]), tsa(s)); - // s has been moved into the tsa call - } - - #[test] - fn bind_udp_socket_bad() { - // rust-lang/rust#53957: This is a regression test for a parsing problem - // discovered as part of issue rust-lang/rust#23076, where we were - // incorrectly parsing invalid input and then that would result in a - // successful `UdpSocket` binding when we would expect failure. - // - // At one time, this test was written as a call to `tsa` with - // INPUT_23076. However, that structure yields an unreliable test, - // because it ends up passing junk input to the DNS server, and some DNS - // servers will respond with `Ok` to such input, with the ip address of - // the DNS server itself. - // - // This form of the test is more robust: even when the DNS server - // returns its own address, it is still an error to bind a UDP socket to - // a non-local address, and so we still get an error here in that case. - - const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300"; - - assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err()) - } - - #[test] - fn set_ip() { - fn ip4(low: u8) -> Ipv4Addr { - Ipv4Addr::new(77, 88, 21, low) - } - fn ip6(low: u16) -> Ipv6Addr { - Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) - } - - let mut v4 = SocketAddrV4::new(ip4(11), 80); - assert_eq!(v4.ip(), &ip4(11)); - v4.set_ip(ip4(12)); - assert_eq!(v4.ip(), &ip4(12)); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); - addr.set_ip(IpAddr::V4(ip4(13))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); - addr.set_ip(IpAddr::V6(ip6(14))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); - - let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); - assert_eq!(v6.ip(), &ip6(1)); - v6.set_ip(ip6(2)); - assert_eq!(v6.ip(), &ip6(2)); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); - addr.set_ip(IpAddr::V6(ip6(3))); - assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); - addr.set_ip(IpAddr::V4(ip4(4))); - assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); - } - - #[test] - fn set_port() { - let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); - assert_eq!(v4.port(), 80); - v4.set_port(443); - assert_eq!(v4.port(), 443); - - let mut addr = SocketAddr::V4(v4); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); - - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); - assert_eq!(v6.port(), 80); - v6.set_port(443); - assert_eq!(v6.port(), 443); - - let mut addr = SocketAddr::V6(v6); - assert_eq!(addr.port(), 443); - addr.set_port(8080); - assert_eq!(addr.port(), 8080); - } - - #[test] - fn set_flowinfo() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); - assert_eq!(v6.flowinfo(), 10); - v6.set_flowinfo(20); - assert_eq!(v6.flowinfo(), 20); - } - - #[test] - fn set_scope_id() { - let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); - assert_eq!(v6.scope_id(), 10); - v6.set_scope_id(20); - assert_eq!(v6.scope_id(), 20); - } - - #[test] - fn is_v4() { - let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); - assert!(v4.is_ipv4()); - assert!(!v4.is_ipv6()); - } - - #[test] - fn is_v6() { - let v6 = SocketAddr::V6(SocketAddrV6::new( - Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), - 80, - 10, - 0, - )); - assert!(!v6.is_ipv4()); - assert!(v6.is_ipv6()); - } - - #[test] - fn socket_v4_to_str() { - let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); - - assert_eq!(format!("{}", socket), "192.168.0.1:8080"); - assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 "); - assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080"); - assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 "); - assert_eq!(format!("{:.10}", socket), "192.168.0."); - } - - #[test] - fn socket_v6_to_str() { - let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap(); - - assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53"); - assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 "); - assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::"); - } - - #[test] - fn compare() { - let v4_1 = "224.120.45.1:23456".parse::().unwrap(); - let v4_2 = "224.210.103.5:12345".parse::().unwrap(); - let v4_3 = "224.210.103.5:23456".parse::().unwrap(); - let v6_1 = "[2001:db8:f00::1002]:23456".parse::().unwrap(); - let v6_2 = "[2001:db8:f00::2001]:12345".parse::().unwrap(); - let v6_3 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); - - // equality - assert_eq!(v4_1, v4_1); - assert_eq!(v6_1, v6_1); - assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); - assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); - assert!(v4_1 != v4_2); - assert!(v6_1 != v6_2); - - // compare different addresses - assert!(v4_1 < v4_2); - assert!(v6_1 < v6_2); - assert!(v4_2 > v4_1); - assert!(v6_2 > v6_1); - - // compare the same address with different ports - assert!(v4_2 < v4_3); - assert!(v6_2 < v6_3); - assert!(v4_3 > v4_2); - assert!(v6_3 > v6_2); - - // compare different addresses with the same port - assert!(v4_1 < v4_3); - assert!(v6_1 < v6_3); - assert!(v4_3 > v4_1); - assert!(v6_3 > v6_1); - - // compare with an inferred right-hand side - assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); - assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); - assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap()); - } -} diff --git a/library/std/src/net/addr/tests.rs b/library/std/src/net/addr/tests.rs new file mode 100644 index 0000000000..cee9087e13 --- /dev/null +++ b/library/std/src/net/addr/tests.rs @@ -0,0 +1,229 @@ +use crate::net::test::{sa4, sa6, tsa}; +use crate::net::*; + +#[test] +fn to_socket_addr_ipaddr_u16() { + let a = Ipv4Addr::new(77, 88, 21, 11); + let p = 12345; + let e = SocketAddr::V4(SocketAddrV4::new(a, p)); + assert_eq!(Ok(vec![e]), tsa((a, p))); +} + +#[test] +fn to_socket_addr_str_u16() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa(("77.88.21.11", 24352))); + + let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa(("2a02:6b8:0:1::1", 53))); + + let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] + assert!(tsa(("localhost", 23924)).unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; +} + +#[test] +fn to_socket_addr_str() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa("77.88.21.11:24352")); + + let a = sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53); + assert_eq!(Ok(vec![a]), tsa("[2a02:6b8:0:1::1]:53")); + + let a = sa4(Ipv4Addr::new(127, 0, 0, 1), 23924); + #[cfg(not(target_env = "sgx"))] + assert!(tsa("localhost:23924").unwrap().contains(&a)); + #[cfg(target_env = "sgx")] + let _ = a; +} + +#[test] +fn to_socket_addr_string() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 24352); + assert_eq!(Ok(vec![a]), tsa(&*format!("{}:{}", "77.88.21.11", "24352"))); + assert_eq!(Ok(vec![a]), tsa(&format!("{}:{}", "77.88.21.11", "24352"))); + assert_eq!(Ok(vec![a]), tsa(format!("{}:{}", "77.88.21.11", "24352"))); + + let s = format!("{}:{}", "77.88.21.11", "24352"); + assert_eq!(Ok(vec![a]), tsa(s)); + // s has been moved into the tsa call +} + +#[test] +fn bind_udp_socket_bad() { + // rust-lang/rust#53957: This is a regression test for a parsing problem + // discovered as part of issue rust-lang/rust#23076, where we were + // incorrectly parsing invalid input and then that would result in a + // successful `UdpSocket` binding when we would expect failure. + // + // At one time, this test was written as a call to `tsa` with + // INPUT_23076. However, that structure yields an unreliable test, + // because it ends up passing junk input to the DNS server, and some DNS + // servers will respond with `Ok` to such input, with the ip address of + // the DNS server itself. + // + // This form of the test is more robust: even when the DNS server + // returns its own address, it is still an error to bind a UDP socket to + // a non-local address, and so we still get an error here in that case. + + const INPUT_23076: &'static str = "1200::AB00:1234::2552:7777:1313:34300"; + + assert!(crate::net::UdpSocket::bind(INPUT_23076).is_err()) +} + +#[test] +fn set_ip() { + fn ip4(low: u8) -> Ipv4Addr { + Ipv4Addr::new(77, 88, 21, low) + } + fn ip6(low: u16) -> Ipv6Addr { + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, low) + } + + let mut v4 = SocketAddrV4::new(ip4(11), 80); + assert_eq!(v4.ip(), &ip4(11)); + v4.set_ip(ip4(12)); + assert_eq!(v4.ip(), &ip4(12)); + + let mut addr = SocketAddr::V4(v4); + assert_eq!(addr.ip(), IpAddr::V4(ip4(12))); + addr.set_ip(IpAddr::V4(ip4(13))); + assert_eq!(addr.ip(), IpAddr::V4(ip4(13))); + addr.set_ip(IpAddr::V6(ip6(14))); + assert_eq!(addr.ip(), IpAddr::V6(ip6(14))); + + let mut v6 = SocketAddrV6::new(ip6(1), 80, 0, 0); + assert_eq!(v6.ip(), &ip6(1)); + v6.set_ip(ip6(2)); + assert_eq!(v6.ip(), &ip6(2)); + + let mut addr = SocketAddr::V6(v6); + assert_eq!(addr.ip(), IpAddr::V6(ip6(2))); + addr.set_ip(IpAddr::V6(ip6(3))); + assert_eq!(addr.ip(), IpAddr::V6(ip6(3))); + addr.set_ip(IpAddr::V4(ip4(4))); + assert_eq!(addr.ip(), IpAddr::V4(ip4(4))); +} + +#[test] +fn set_port() { + let mut v4 = SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80); + assert_eq!(v4.port(), 80); + v4.set_port(443); + assert_eq!(v4.port(), 443); + + let mut addr = SocketAddr::V4(v4); + assert_eq!(addr.port(), 443); + addr.set_port(8080); + assert_eq!(addr.port(), 8080); + + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 0); + assert_eq!(v6.port(), 80); + v6.set_port(443); + assert_eq!(v6.port(), 443); + + let mut addr = SocketAddr::V6(v6); + assert_eq!(addr.port(), 443); + addr.set_port(8080); + assert_eq!(addr.port(), 8080); +} + +#[test] +fn set_flowinfo() { + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 10, 0); + assert_eq!(v6.flowinfo(), 10); + v6.set_flowinfo(20); + assert_eq!(v6.flowinfo(), 20); +} + +#[test] +fn set_scope_id() { + let mut v6 = SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 80, 0, 10); + assert_eq!(v6.scope_id(), 10); + v6.set_scope_id(20); + assert_eq!(v6.scope_id(), 20); +} + +#[test] +fn is_v4() { + let v4 = SocketAddr::V4(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)); + assert!(v4.is_ipv4()); + assert!(!v4.is_ipv6()); +} + +#[test] +fn is_v6() { + let v6 = SocketAddr::V6(SocketAddrV6::new( + Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), + 80, + 10, + 0, + )); + assert!(!v6.is_ipv4()); + assert!(v6.is_ipv6()); +} + +#[test] +fn socket_v4_to_str() { + let socket = SocketAddrV4::new(Ipv4Addr::new(192, 168, 0, 1), 8080); + + assert_eq!(format!("{}", socket), "192.168.0.1:8080"); + assert_eq!(format!("{:<20}", socket), "192.168.0.1:8080 "); + assert_eq!(format!("{:>20}", socket), " 192.168.0.1:8080"); + assert_eq!(format!("{:^20}", socket), " 192.168.0.1:8080 "); + assert_eq!(format!("{:.10}", socket), "192.168.0."); +} + +#[test] +fn socket_v6_to_str() { + let socket: SocketAddrV6 = "[2a02:6b8:0:1::1]:53".parse().unwrap(); + + assert_eq!(format!("{}", socket), "[2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{:<24}", socket), "[2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{:>24}", socket), " [2a02:6b8:0:1::1]:53"); + assert_eq!(format!("{:^24}", socket), " [2a02:6b8:0:1::1]:53 "); + assert_eq!(format!("{:.15}", socket), "[2a02:6b8:0:1::"); +} + +#[test] +fn compare() { + let v4_1 = "224.120.45.1:23456".parse::().unwrap(); + let v4_2 = "224.210.103.5:12345".parse::().unwrap(); + let v4_3 = "224.210.103.5:23456".parse::().unwrap(); + let v6_1 = "[2001:db8:f00::1002]:23456".parse::().unwrap(); + let v6_2 = "[2001:db8:f00::2001]:12345".parse::().unwrap(); + let v6_3 = "[2001:db8:f00::2001]:23456".parse::().unwrap(); + + // equality + assert_eq!(v4_1, v4_1); + assert_eq!(v6_1, v6_1); + assert_eq!(SocketAddr::V4(v4_1), SocketAddr::V4(v4_1)); + assert_eq!(SocketAddr::V6(v6_1), SocketAddr::V6(v6_1)); + assert!(v4_1 != v4_2); + assert!(v6_1 != v6_2); + + // compare different addresses + assert!(v4_1 < v4_2); + assert!(v6_1 < v6_2); + assert!(v4_2 > v4_1); + assert!(v6_2 > v6_1); + + // compare the same address with different ports + assert!(v4_2 < v4_3); + assert!(v6_2 < v6_3); + assert!(v4_3 > v4_2); + assert!(v6_3 > v6_2); + + // compare different addresses with the same port + assert!(v4_1 < v4_3); + assert!(v6_1 < v6_3); + assert!(v4_3 > v4_1); + assert!(v6_3 > v6_1); + + // compare with an inferred right-hand side + assert_eq!(v4_1, "224.120.45.1:23456".parse().unwrap()); + assert_eq!(v6_1, "[2001:db8:f00::1002]:23456".parse().unwrap()); + assert_eq!(SocketAddr::V4(v4_1), "224.120.45.1:23456".parse().unwrap()); +} diff --git a/library/std/src/net/ip.rs b/library/std/src/net/ip.rs index 85bb6b60e6..f01a7b72a6 100644 --- a/library/std/src/net/ip.rs +++ b/library/std/src/net/ip.rs @@ -6,6 +6,10 @@ issue = "27709" )] +// Tests for this module +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cmp::Ordering; use crate::fmt::{self, Write as FmtWrite}; use crate::hash; @@ -136,8 +140,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_unspecified()`] and /// [`Ipv6Addr::is_unspecified()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -146,8 +148,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)).is_unspecified(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)).is_unspecified(), true); /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_unspecified(&self) -> bool { + pub const fn is_unspecified(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_unspecified(), IpAddr::V6(ip) => ip.is_unspecified(), @@ -159,8 +162,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_loopback()`] and /// [`Ipv6Addr::is_loopback()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -169,8 +170,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(127, 0, 0, 1)).is_loopback(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1)).is_loopback(), true); /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_loopback(&self) -> bool { + pub const fn is_loopback(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_loopback(), IpAddr::V6(ip) => ip.is_loopback(), @@ -182,8 +184,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_global()`] and /// [`Ipv6Addr::is_global()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -194,7 +194,8 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(80, 9, 12, 3)).is_global(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1)).is_global(), true); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_global(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_global(), IpAddr::V6(ip) => ip.is_global(), @@ -206,8 +207,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_multicast()`] and /// [`Ipv6Addr::is_multicast()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -216,8 +215,9 @@ impl IpAddr { /// assert_eq!(IpAddr::V4(Ipv4Addr::new(224, 254, 0, 0)).is_multicast(), true); /// assert_eq!(IpAddr::V6(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0)).is_multicast(), true); /// ``` + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] #[stable(feature = "ip_shared", since = "1.12.0")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_multicast(), IpAddr::V6(ip) => ip.is_multicast(), @@ -229,8 +229,6 @@ impl IpAddr { /// See the documentation for [`Ipv4Addr::is_documentation()`] and /// [`Ipv6Addr::is_documentation()`] for more details. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -244,7 +242,8 @@ impl IpAddr { /// true /// ); /// ``` - pub fn is_documentation(&self) -> bool { + #[rustc_const_unstable(feature = "const_ip", issue = "76205")] + pub const fn is_documentation(&self) -> bool { match self { IpAddr::V4(ip) => ip.is_documentation(), IpAddr::V6(ip) => ip.is_documentation(), @@ -254,8 +253,6 @@ impl IpAddr { /// Returns [`true`] if this address is an [`IPv4` address], and [`false`] /// otherwise. /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html /// [`IPv4` address]: IpAddr::V4 /// /// # Examples @@ -274,8 +271,6 @@ impl IpAddr { /// Returns [`true`] if this address is an [`IPv6` address], and [`false`] /// otherwise. /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html /// [`IPv6` address]: IpAddr::V6 /// /// # Examples @@ -361,8 +356,9 @@ impl Ipv4Addr { /// let addr = Ipv4Addr::new(127, 0, 0, 1); /// assert_eq!(addr.octets(), [127, 0, 0, 1]); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn octets(&self) -> [u8; 4] { + pub const fn octets(&self) -> [u8; 4] { // This returns the order we want because s_addr is stored in big-endian. self.inner.s_addr.to_ne_bytes() } @@ -372,7 +368,6 @@ impl Ipv4Addr { /// This property is defined in _UNIX Network Programming, Second Edition_, /// W. Richard Stevens, p. 891; see also [ip7]. /// - /// [`true`]: ../../std/primitive.bool.html /// [ip7]: http://man7.org/linux/man-pages/man7/ip.7.html /// /// # Examples @@ -393,7 +388,6 @@ impl Ipv4Addr { /// /// This property is defined by [IETF RFC 1122]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 1122]: https://tools.ietf.org/html/rfc1122 /// /// # Examples @@ -404,8 +398,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(127, 0, 0, 1).is_loopback(), true); /// assert_eq!(Ipv4Addr::new(45, 22, 13, 197).is_loopback(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { + pub const fn is_loopback(&self) -> bool { self.octets()[0] == 127 } @@ -417,7 +412,6 @@ impl Ipv4Addr { /// - 172.16.0.0/12 /// - 192.168.0.0/16 /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 1918]: https://tools.ietf.org/html/rfc1918 /// /// # Examples @@ -433,8 +427,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 168, 0, 2).is_private(), true); /// assert_eq!(Ipv4Addr::new(192, 169, 0, 2).is_private(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_private(&self) -> bool { + pub const fn is_private(&self) -> bool { match self.octets() { [10, ..] => true, [172, b, ..] if b >= 16 && b <= 31 => true, @@ -447,7 +442,6 @@ impl Ipv4Addr { /// /// This property is defined by [IETF RFC 3927]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 3927]: https://tools.ietf.org/html/rfc3927 /// /// # Examples @@ -459,8 +453,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(169, 254, 10, 65).is_link_local(), true); /// assert_eq!(Ipv4Addr::new(16, 89, 10, 65).is_link_local(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_link_local(&self) -> bool { + pub const fn is_link_local(&self) -> bool { match self.octets() { [169, 254, ..] => true, _ => false, @@ -486,8 +481,6 @@ impl Ipv4Addr { /// - addresses reserved for networking devices benchmarking (see /// [`Ipv4Addr::is_benchmarking()`]) /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html /// [ipv4-sr]: https://www.iana.org/assignments/iana-ipv4-special-registry/iana-ipv4-special-registry.xhtml /// /// # Examples @@ -538,10 +531,13 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(1, 1, 1, 1).is_global(), true); /// assert_eq!(Ipv4Addr::new(80, 9, 12, 3).is_global(), true); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + 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 // globally routable addresses in the 192.0.0.0/24 range. - if u32::from(*self) == 0xc0000009 || u32::from(*self) == 0xc000000a { + if u32::from_be_bytes(self.octets()) == 0xc0000009 + || u32::from_be_bytes(self.octets()) == 0xc000000a + { return true; } !self.is_private() @@ -560,7 +556,6 @@ impl Ipv4Addr { /// Returns [`true`] if this address is part of the Shared Address Space defined in /// [IETF RFC 6598] (`100.64.0.0/10`). /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 6598]: https://tools.ietf.org/html/rfc6598 /// /// # Examples @@ -573,7 +568,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(100, 127, 255, 255).is_shared(), true); /// assert_eq!(Ipv4Addr::new(100, 128, 0, 0).is_shared(), false); /// ``` - pub fn is_shared(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_shared(&self) -> bool { self.octets()[0] == 100 && (self.octets()[1] & 0b1100_0000 == 0b0100_0000) } @@ -586,7 +582,6 @@ impl Ipv4Addr { /// - `192.0.0.9/32` is the "Port Control Protocol Anycast" (see [IETF RFC 7723]) /// - `192.0.0.10/32` is used for NAT traversal (see [IETF RFC 8155]) /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 6890]: https://tools.ietf.org/html/rfc6890 /// [IETF RFC 7600]: https://tools.ietf.org/html/rfc7600 /// [IETF RFC 7723]: https://tools.ietf.org/html/rfc7723 @@ -605,7 +600,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 1, 0).is_ietf_protocol_assignment(), false); /// assert_eq!(Ipv4Addr::new(191, 255, 255, 255).is_ietf_protocol_assignment(), false); /// ``` - pub fn is_ietf_protocol_assignment(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_ietf_protocol_assignment(&self) -> bool { self.octets()[0] == 192 && self.octets()[1] == 0 && self.octets()[2] == 0 } @@ -613,7 +609,6 @@ impl Ipv4Addr { /// network devices benchmarking. This range is defined in [IETF RFC 2544] as `192.18.0.0` /// through `198.19.255.255` but [errata 423] corrects it to `198.18.0.0/15`. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 2544]: https://tools.ietf.org/html/rfc2544 /// [errata 423]: https://www.rfc-editor.org/errata/eid423 /// @@ -628,7 +623,8 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(198, 19, 255, 255).is_benchmarking(), true); /// assert_eq!(Ipv4Addr::new(198, 20, 0, 0).is_benchmarking(), false); /// ``` - pub fn is_benchmarking(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_benchmarking(&self) -> bool { self.octets()[0] == 198 && (self.octets()[1] & 0xfe) == 18 } @@ -637,7 +633,6 @@ impl Ipv4Addr { /// broadcast address `255.255.255.255`, but this implementation explicitly excludes it, since /// it is obviously not reserved for future use. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 1112]: https://tools.ietf.org/html/rfc1112 /// /// # Warning @@ -660,7 +655,8 @@ impl Ipv4Addr { /// // The broadcast address is not considered as reserved for future use by this implementation /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_reserved(), false); /// ``` - pub fn is_reserved(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] + pub const fn is_reserved(&self) -> bool { self.octets()[0] & 240 == 240 && !self.is_broadcast() } @@ -669,7 +665,6 @@ impl Ipv4Addr { /// Multicast addresses have a most significant octet between 224 and 239, /// and is defined by [IETF RFC 5771]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 5771]: https://tools.ietf.org/html/rfc5771 /// /// # Examples @@ -681,8 +676,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_multicast(), true); /// assert_eq!(Ipv4Addr::new(172, 16, 10, 65).is_multicast(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { self.octets()[0] >= 224 && self.octets()[0] <= 239 } @@ -690,7 +686,6 @@ impl Ipv4Addr { /// /// A broadcast address has all octets set to 255 as defined in [IETF RFC 919]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 919]: https://tools.ietf.org/html/rfc919 /// /// # Examples @@ -701,9 +696,10 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(255, 255, 255, 255).is_broadcast(), true); /// assert_eq!(Ipv4Addr::new(236, 168, 10, 65).is_broadcast(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_broadcast(&self) -> bool { - self == &Self::BROADCAST + pub const fn is_broadcast(&self) -> bool { + u32::from_be_bytes(self.octets()) == u32::from_be_bytes(Self::BROADCAST.octets()) } /// Returns [`true`] if this address is in a range designated for documentation. @@ -714,7 +710,6 @@ impl Ipv4Addr { /// - 198.51.100.0/24 (TEST-NET-2) /// - 203.0.113.0/24 (TEST-NET-3) /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 5737]: https://tools.ietf.org/html/rfc5737 /// /// # Examples @@ -727,8 +722,9 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(203, 0, 113, 6).is_documentation(), true); /// assert_eq!(Ipv4Addr::new(193, 34, 17, 19).is_documentation(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_documentation(&self) -> bool { + pub const fn is_documentation(&self) -> bool { match self.octets() { [192, 0, 2, _] => true, [198, 51, 100, _] => true, @@ -741,6 +737,9 @@ impl Ipv4Addr { /// /// a.b.c.d becomes ::a.b.c.d /// + /// This isn't typically the method you want; these addresses don't typically + /// function on modern systems. Use `to_ipv6_mapped` instead. + /// /// [`IPv6` address]: Ipv6Addr /// /// # Examples @@ -753,10 +752,13 @@ impl Ipv4Addr { /// Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 767) /// ); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_compatible(&self) -> Ipv6Addr { + pub const fn to_ipv6_compatible(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d]) + Ipv6Addr { + inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, a, b, c, d] }, + } } /// Converts this address to an IPv4-mapped [`IPv6` address]. @@ -773,10 +775,13 @@ impl Ipv4Addr { /// assert_eq!(Ipv4Addr::new(192, 0, 2, 255).to_ipv6_mapped(), /// Ipv6Addr::new(0, 0, 0, 0, 0, 65535, 49152, 767)); /// ``` + #[rustc_const_unstable(feature = "const_ipv4", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv6_mapped(&self) -> Ipv6Addr { + pub const fn to_ipv6_mapped(&self) -> Ipv6Addr { let [a, b, c, d] = self.octets(); - Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d]) + Ipv6Addr { + inner: c::in6_addr { s6_addr: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xFF, 0xFF, a, b, c, d] }, + } } } @@ -1098,8 +1103,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).segments(), /// [0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff]); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn segments(&self) -> [u16; 8] { + pub const fn segments(&self) -> [u16; 8] { // All elements in `s6_addr` must be big endian. // SAFETY: `[u8; 16]` is always safe to transmute to `[u16; 8]`. let [a, b, c, d, e, f, g, h] = unsafe { transmute::<_, [u16; 8]>(self.inner.s6_addr) }; @@ -1120,7 +1126,6 @@ impl Ipv6Addr { /// /// This property is defined in [IETF RFC 4291]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples @@ -1131,16 +1136,16 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unspecified(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).is_unspecified(), true); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_unspecified(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 0] + pub const fn is_unspecified(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::UNSPECIFIED.octets()) } /// Returns [`true`] if this is a loopback address (::1). /// /// This property is defined in [IETF RFC 4291]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples @@ -1151,9 +1156,10 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_loopback(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_loopback(), true); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_loopback(&self) -> bool { - self.segments() == [0, 0, 0, 0, 0, 0, 0, 1] + pub const fn is_loopback(&self) -> bool { + u128::from_be_bytes(self.octets()) == u128::from_be_bytes(Ipv6Addr::LOCALHOST.octets()) } /// Returns [`true`] if the address appears to be globally routable. @@ -1164,9 +1170,6 @@ impl Ipv6Addr { /// - link-local and unique local unicast addresses /// - interface-, link-, realm-, admin- and site-local multicast addresses /// - /// [`true`]: ../../std/primitive.bool.html - /// [`false`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1178,7 +1181,8 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0x1).is_global(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0x1c9, 0, 0, 0xafc8, 0, 0x1).is_global(), true); /// ``` - pub fn is_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_global(&self) -> bool { match self.multicast_scope() { Some(Ipv6MulticastScope::Global) => true, None => self.is_unicast_global(), @@ -1192,8 +1196,6 @@ impl Ipv6Addr { /// /// [IETF RFC 4193]: https://tools.ietf.org/html/rfc4193 /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1204,7 +1206,8 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unique_local(), false); /// assert_eq!(Ipv6Addr::new(0xfc02, 0, 0, 0, 0, 0, 0, 0).is_unique_local(), true); /// ``` - pub fn is_unique_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unique_local(&self) -> bool { (self.segments()[0] & 0xfe00) == 0xfc00 } @@ -1225,8 +1228,6 @@ impl Ipv6Addr { /// addresses such as `fe80:0:0:1::` or `fe81::` as unicast link-local addresses for example. /// If you need a less strict validation use [`Ipv6Addr::is_unicast_link_local()`] instead. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1259,7 +1260,8 @@ impl Ipv6Addr { /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// [IETF RFC 4291 section 2.5.6]: https://tools.ietf.org/html/rfc4291#section-2.5.6 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - pub fn is_unicast_link_local_strict(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local_strict(&self) -> bool { (self.segments()[0] & 0xffff) == 0xfe80 && (self.segments()[1] & 0xffff) == 0 && (self.segments()[2] & 0xffff) == 0 @@ -1284,8 +1286,6 @@ impl Ipv6Addr { /// If you need a strict validation fully compliant with the RFC, use /// [`Ipv6Addr::is_unicast_link_local_strict()`] instead. /// - /// [`true`]: ../../std/primitive.bool.html - /// /// # Examples /// /// ``` @@ -1316,7 +1316,8 @@ impl Ipv6Addr { /// /// [IETF RFC 4291 section 2.4]: https://tools.ietf.org/html/rfc4291#section-2.4 /// [RFC 4291 errata 4406]: https://www.rfc-editor.org/errata/eid4406 - pub fn is_unicast_link_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_link_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfe80 } @@ -1331,7 +1332,6 @@ impl Ipv6Addr { /// +----------+-------------------------+----------------------------+ /// ``` /// - /// [`true`]: ../../std/primitive.bool.html /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples @@ -1355,7 +1355,8 @@ impl Ipv6Addr { /// addresses. /// /// [RFC 3879]: https://tools.ietf.org/html/rfc3879 - pub fn is_unicast_site_local(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_site_local(&self) -> bool { (self.segments()[0] & 0xffc0) == 0xfec0 } @@ -1364,7 +1365,6 @@ impl Ipv6Addr { /// /// This property is defined in [IETF RFC 3849]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 3849]: https://tools.ietf.org/html/rfc3849 /// /// # Examples @@ -1377,7 +1377,8 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_documentation(), false); /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_documentation(), true); /// ``` - pub fn is_documentation(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_documentation(&self) -> bool { (self.segments()[0] == 0x2001) && (self.segments()[1] == 0xdb8) } @@ -1399,7 +1400,6 @@ impl Ipv6Addr { /// Global Unicast). /// ``` /// - /// [`true`]: ../../std/primitive.bool.html /// [RFC 4291 section 2.5.7]: https://tools.ietf.org/html/rfc4291#section-2.5.7 /// /// # Examples @@ -1412,7 +1412,8 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0, 0).is_unicast_global(), false); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_unicast_global(), true); /// ``` - pub fn is_unicast_global(&self) -> bool { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn is_unicast_global(&self) -> bool { !self.is_multicast() && !self.is_loopback() && !self.is_unicast_link_local() @@ -1436,7 +1437,8 @@ impl Ipv6Addr { /// ); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).multicast_scope(), None); /// ``` - pub fn multicast_scope(&self) -> Option { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn multicast_scope(&self) -> Option { if self.is_multicast() { match self.segments()[0] & 0x000f { 1 => Some(Ipv6MulticastScope::InterfaceLocal), @@ -1457,7 +1459,6 @@ impl Ipv6Addr { /// /// This property is defined by [IETF RFC 4291]. /// - /// [`true`]: ../../std/primitive.bool.html /// [IETF RFC 4291]: https://tools.ietf.org/html/rfc4291 /// /// # Examples @@ -1468,8 +1469,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0xff00, 0, 0, 0, 0, 0, 0, 0).is_multicast(), true); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc00a, 0x2ff).is_multicast(), false); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(since = "1.7.0", feature = "ip_17")] - pub fn is_multicast(&self) -> bool { + pub const fn is_multicast(&self) -> bool { (self.segments()[0] & 0xff00) == 0xff00 } @@ -1494,7 +1496,8 @@ impl Ipv6Addr { /// Some(Ipv4Addr::new(192, 10, 2, 255))); /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4_mapped(), None); /// ``` - pub fn to_ipv4_mapped(&self) -> Option { + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] + pub const fn to_ipv4_mapped(&self) -> Option { match self.octets() { [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0xff, 0xff, a, b, c, d] => { Some(Ipv4Addr::new(a, b, c, d)) @@ -1521,8 +1524,9 @@ impl Ipv6Addr { /// assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_ipv4(), /// Some(Ipv4Addr::new(0, 0, 0, 1))); /// ``` + #[rustc_const_unstable(feature = "const_ipv6", issue = "76205")] #[stable(feature = "rust1", since = "1.0.0")] - pub fn to_ipv4(&self) -> Option { + pub const fn to_ipv4(&self) -> Option { if let [0, 0, 0, 0, 0, 0 | 0xffff, ab, cd] = self.segments() { let [a, b] = ab.to_be_bytes(); let [c, d] = cd.to_be_bytes(); @@ -1895,862 +1899,3 @@ impl From<[u16; 8]> for IpAddr { IpAddr::V6(Ipv6Addr::from(segments)) } } - -// Tests for this module -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::net::test::{sa4, sa6, tsa}; - use crate::net::*; - use crate::str::FromStr; - - #[test] - fn test_from_str_ipv4() { - assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); - assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); - assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); - - // out of range - let none: Option = "256.0.0.1".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "255.0.0".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "255.0.0.1.2".parse().ok(); - assert_eq!(None, none); - // no number between dots - let none: Option = "255.0..1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); - - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); - - assert_eq!( - Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), - "2a02:6b8::11:11".parse() - ); - - // too long group - let none: Option = "::00000".parse().ok(); - assert_eq!(None, none); - // too short - let none: Option = "1:2:3:4:5:6:7".parse().ok(); - assert_eq!(None, none); - // too long - let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); - assert_eq!(None, none); - // triple colon - let none: Option = "1:2:::6:7:8".parse().ok(); - assert_eq!(None, none); - // two double colons - let none: Option = "1:2::6::8".parse().ok(); - assert_eq!(None, none); - // `::` indicating zero groups of zeros - let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_ipv4_in_ipv6() { - assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); - assert_eq!( - Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), - "::FFFF:192.0.2.33".parse() - ); - assert_eq!( - Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), - "64:ff9b::192.0.2.33".parse() - ); - assert_eq!( - Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), - "2001:db8:122:c000:2:2100:192.0.2.33".parse() - ); - - // colon after v4 - let none: Option = "::127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // not enough groups - let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); - assert_eq!(None, none); - // too many groups - let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn test_from_str_socket_addr() { - assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); - assert_eq!( - Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), - "77.88.21.11:80".parse() - ); - assert_eq!( - Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), - "[2a02:6b8:0:1::1]:53".parse() - ); - assert_eq!( - Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), - "[::127.0.0.1]:22".parse() - ); - assert_eq!( - Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), - "[::127.0.0.1]:22".parse() - ); - - // without port - let none: Option = "127.0.0.1".parse().ok(); - assert_eq!(None, none); - // without port - let none: Option = "127.0.0.1:".parse().ok(); - assert_eq!(None, none); - // wrong brackets around v4 - let none: Option = "[127.0.0.1]:22".parse().ok(); - assert_eq!(None, none); - // port out of range - let none: Option = "127.0.0.1:123456".parse().ok(); - assert_eq!(None, none); - } - - #[test] - fn ipv4_addr_to_string() { - assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); - // Short address - assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); - // Long address - assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); - - // Test padding - assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); - assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); - } - - #[test] - fn ipv6_addr_to_string() { - // ipv4-mapped address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); - - // ipv4-compatible address - let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); - assert_eq!(a1.to_string(), "::192.0.2.128"); - - // v6 address with no zero segments - assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); - - // longest possible IPv6 length - assert_eq!( - Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888) - .to_string(), - "1111:2222:3333:4444:5555:6666:7777:8888" - ); - // padding - assert_eq!( - &format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), - "1:2:3:4:5:6:7:8 " - ); - assert_eq!( - &format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), - " 1:2:3:4:5:6:7:8" - ); - - // reduce a single run of zeros - assert_eq!( - "ae::ffff:102:304", - Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() - ); - - // don't reduce just a single zero segment - assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); - - // 'any' address - assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // loopback address - assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); - - // ends in zeros - assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); - - // two runs of zeros, second one is longer - assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); - - // two runs of zeros, equal length - assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); - } - - #[test] - fn ipv4_to_ipv6() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), - Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() - ); - } - - #[test] - fn ipv6_to_ipv4_mapped() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); - } - - #[test] - fn ipv6_to_ipv4() { - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!( - Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), - Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) - ); - assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); - } - - #[test] - fn ip_properties() { - macro_rules! ip { - ($s:expr) => { - IpAddr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & doc) == doc { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - }}; - } - - let unspec: u8 = 1 << 0; - let loopback: u8 = 1 << 1; - let global: u8 = 1 << 2; - let multicast: u8 = 1 << 3; - let doc: u8 = 1 << 4; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7"); - check!("127.1.2.3", loopback); - check!("172.31.254.253"); - check!("169.254.253.242"); - check!("192.0.2.183", doc); - check!("192.1.2.183", global); - check!("192.168.254.253"); - check!("198.51.100.0", doc); - check!("203.0.113.0", doc); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - 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"); - // make sure addresses reserved for protocol assignment are not global - check!("192.0.0.0"); - check!("192.0.0.255"); - check!("192.0.0.100"); - // make sure reserved addresses are not global - check!("240.0.0.0"); - check!("251.54.1.76"); - check!("254.255.255.255"); - // make sure shared addresses are not global - check!("100.64.0.0"); - check!("100.127.255.255"); - check!("100.100.100.0"); - - check!("::", unspec); - check!("::1", loopback); - check!("::0.0.0.2", global); - check!("1::", global); - check!("fc00::"); - check!("fdff:ffff::"); - check!("fe80:ffff::"); - check!("febf:ffff::"); - check!("fec0::", global); - check!("ff01::", multicast); - check!("ff02::", multicast); - check!("ff03::", multicast); - check!("ff04::", multicast); - check!("ff05::", multicast); - check!("ff08::", multicast); - check!("ff0e::", global | multicast); - check!("2001:db8:85a3::8a2e:370:7334", doc); - check!("102:304:506:708:90a:b0c:d0e:f10", global); - } - - #[test] - fn ipv4_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv4Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr) => { - check!($s, 0); - }; - - ($s:expr, $mask:expr) => {{ - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let ietf_protocol_assignment: u16 = 1 << 9; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - if ($mask & unspec) == unspec { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - - if ($mask & private) == private { - assert!(ip!($s).is_private()); - } else { - assert!(!ip!($s).is_private()); - } - - if ($mask & link_local) == link_local { - assert!(ip!($s).is_link_local()); - } else { - assert!(!ip!($s).is_link_local()); - } - - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - - if ($mask & multicast) == multicast { - assert!(ip!($s).is_multicast()); - } else { - assert!(!ip!($s).is_multicast()); - } - - if ($mask & broadcast) == broadcast { - assert!(ip!($s).is_broadcast()); - } else { - assert!(!ip!($s).is_broadcast()); - } - - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - - if ($mask & benchmarking) == benchmarking { - assert!(ip!($s).is_benchmarking()); - } else { - assert!(!ip!($s).is_benchmarking()); - } - - if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { - assert!(ip!($s).is_ietf_protocol_assignment()); - } else { - assert!(!ip!($s).is_ietf_protocol_assignment()); - } - - if ($mask & reserved) == reserved { - assert!(ip!($s).is_reserved()); - } else { - assert!(!ip!($s).is_reserved()); - } - - if ($mask & shared) == shared { - assert!(ip!($s).is_shared()); - } else { - assert!(!ip!($s).is_shared()); - } - }}; - } - - let unspec: u16 = 1 << 0; - let loopback: u16 = 1 << 1; - let private: u16 = 1 << 2; - let link_local: u16 = 1 << 3; - let global: u16 = 1 << 4; - let multicast: u16 = 1 << 5; - let broadcast: u16 = 1 << 6; - let documentation: u16 = 1 << 7; - let benchmarking: u16 = 1 << 8; - let ietf_protocol_assignment: u16 = 1 << 9; - let reserved: u16 = 1 << 10; - let shared: u16 = 1 << 11; - - check!("0.0.0.0", unspec); - check!("0.0.0.1"); - check!("0.1.0.0"); - check!("10.9.8.7", private); - check!("127.1.2.3", loopback); - check!("172.31.254.253", private); - check!("169.254.253.242", link_local); - check!("192.0.2.183", documentation); - check!("192.1.2.183", global); - check!("192.168.254.253", private); - check!("198.51.100.0", documentation); - check!("203.0.113.0", documentation); - check!("203.2.113.0", global); - check!("224.0.0.0", global | multicast); - check!("239.255.255.255", global | multicast); - check!("255.255.255.255", broadcast); - check!("198.18.0.0", benchmarking); - check!("198.18.54.2", benchmarking); - check!("198.19.255.255", benchmarking); - check!("192.0.0.0", ietf_protocol_assignment); - check!("192.0.0.255", ietf_protocol_assignment); - check!("192.0.0.100", ietf_protocol_assignment); - check!("240.0.0.0", reserved); - check!("251.54.1.76", reserved); - check!("254.255.255.255", reserved); - check!("100.64.0.0", shared); - check!("100.127.255.255", shared); - check!("100.100.100.0", shared); - } - - #[test] - fn ipv6_properties() { - macro_rules! ip { - ($s:expr) => { - Ipv6Addr::from_str($s).unwrap() - }; - } - - macro_rules! check { - ($s:expr, &[$($octet:expr),*], $mask:expr) => { - assert_eq!($s, ip!($s).to_string()); - let octets = &[$($octet),*]; - 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_link_local_strict: u16 = 1 << 5; - let unicast_site_local: u16 = 1 << 6; - 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 - | multicast_admin_local - | multicast_global - | multicast_link_local - | multicast_realm_local - | multicast_site_local - | multicast_organization_local; - - if ($mask & unspecified) == unspecified { - assert!(ip!($s).is_unspecified()); - } else { - assert!(!ip!($s).is_unspecified()); - } - if ($mask & loopback) == loopback { - assert!(ip!($s).is_loopback()); - } else { - assert!(!ip!($s).is_loopback()); - } - if ($mask & unique_local) == unique_local { - assert!(ip!($s).is_unique_local()); - } else { - assert!(!ip!($s).is_unique_local()); - } - if ($mask & global) == global { - assert!(ip!($s).is_global()); - } else { - assert!(!ip!($s).is_global()); - } - if ($mask & unicast_link_local) == unicast_link_local { - assert!(ip!($s).is_unicast_link_local()); - } else { - assert!(!ip!($s).is_unicast_link_local()); - } - if ($mask & unicast_link_local_strict) == unicast_link_local_strict { - assert!(ip!($s).is_unicast_link_local_strict()); - } else { - assert!(!ip!($s).is_unicast_link_local_strict()); - } - if ($mask & unicast_site_local) == unicast_site_local { - assert!(ip!($s).is_unicast_site_local()); - } else { - assert!(!ip!($s).is_unicast_site_local()); - } - if ($mask & unicast_global) == unicast_global { - assert!(ip!($s).is_unicast_global()); - } else { - assert!(!ip!($s).is_unicast_global()); - } - if ($mask & documentation) == documentation { - assert!(ip!($s).is_documentation()); - } else { - assert!(!ip!($s).is_documentation()); - } - if ($mask & multicast) != 0 { - assert!(ip!($s).multicast_scope().is_some()); - assert!(ip!($s).is_multicast()); - } else { - assert!(ip!($s).multicast_scope().is_none()); - assert!(!ip!($s).is_multicast()); - } - if ($mask & multicast_interface_local) == multicast_interface_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::InterfaceLocal); - } - if ($mask & multicast_link_local) == multicast_link_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::LinkLocal); - } - if ($mask & multicast_realm_local) == multicast_realm_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::RealmLocal); - } - if ($mask & multicast_admin_local) == multicast_admin_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::AdminLocal); - } - if ($mask & multicast_site_local) == multicast_site_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::SiteLocal); - } - if ($mask & multicast_organization_local) == multicast_organization_local { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::OrganizationLocal); - } - if ($mask & multicast_global) == multicast_global { - assert_eq!(ip!($s).multicast_scope().unwrap(), - Ipv6MulticastScope::Global); - } - } - } - - 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_link_local_strict: u16 = 1 << 5; - let unicast_site_local: u16 = 1 << 6; - 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; - - check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); - - check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); - - check!( - "::0.0.0.2", - &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], - global | unicast_global - ); - - check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); - - check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); - - check!( - "fdff:ffff::", - &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unique_local - ); - - check!( - "fe80:ffff::", - &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "fe80::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local | unicast_link_local_strict - ); - - check!( - "febf:ffff::", - &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "febf::", - &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", - &[ - 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local - ); - - check!( - "fe80::ffff:ffff:ffff:ffff", - &[ - 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, - 0xff, 0xff - ], - unicast_link_local | unicast_link_local_strict - ); - - check!( - "fe80:0:0:1::", - &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_link_local - ); - - check!( - "fec0::", - &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - unicast_site_local | unicast_global | global - ); - - check!( - "ff01::", - &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_interface_local - ); - - check!( - "ff02::", - &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_link_local - ); - - check!( - "ff03::", - &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_realm_local - ); - - check!( - "ff04::", - &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_admin_local - ); - - check!( - "ff05::", - &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_site_local - ); - - check!( - "ff08::", - &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_organization_local - ); - - check!( - "ff0e::", - &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], - multicast_global | global - ); - - check!( - "2001:db8:85a3::8a2e:370:7334", - &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], - documentation - ); - - 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 - ); - } - - #[test] - fn to_socket_addr_socketaddr() { - let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); - assert_eq!(Ok(vec![a]), tsa(a)); - } - - #[test] - fn test_ipv4_to_int() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(u32::from(a), 0x11223344); - } - - #[test] - fn test_int_to_ipv4() { - let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); - assert_eq!(Ipv4Addr::from(0x11223344), a); - } - - #[test] - fn test_ipv6_to_int() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); - } - - #[test] - fn test_int_to_ipv6() { - let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); - assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); - } - - #[test] - fn ipv4_from_constructors() { - assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); - assert!(Ipv4Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); - assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); - assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); - assert!(Ipv4Addr::BROADCAST.is_broadcast()); - } - - #[test] - fn ipv6_from_contructors() { - assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - assert!(Ipv6Addr::LOCALHOST.is_loopback()); - assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); - } - - #[test] - fn ipv4_from_octets() { - assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) - } - - #[test] - fn ipv6_from_segments() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); - assert_eq!(new, from_u16s); - } - - #[test] - fn ipv6_from_octets() { - let from_u16s = - Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); - let from_u8s = Ipv6Addr::from([ - 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, - 0xee, 0xff, - ]); - assert_eq!(from_u16s, from_u8s); - } - - #[test] - fn cmp() { - let v41 = Ipv4Addr::new(100, 64, 3, 3); - let v42 = Ipv4Addr::new(192, 0, 2, 2); - let v61 = "2001:db8:f00::1002".parse::().unwrap(); - let v62 = "2001:db8:f00::2001".parse::().unwrap(); - assert!(v41 < v42); - assert!(v61 < v62); - - assert_eq!(v41, IpAddr::V4(v41)); - assert_eq!(v61, IpAddr::V6(v61)); - assert!(v41 != IpAddr::V4(v42)); - assert!(v61 != IpAddr::V6(v62)); - - assert!(v41 < IpAddr::V4(v42)); - assert!(v61 < IpAddr::V6(v62)); - assert!(IpAddr::V4(v41) < v42); - assert!(IpAddr::V6(v61) < v62); - - assert!(v41 < IpAddr::V6(v61)); - assert!(IpAddr::V4(v41) < v61); - } - - #[test] - fn is_v4() { - let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); - assert!(ip.is_ipv4()); - assert!(!ip.is_ipv6()); - } - - #[test] - fn is_v6() { - let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); - assert!(!ip.is_ipv4()); - assert!(ip.is_ipv6()); - } -} diff --git a/library/std/src/net/ip/tests.rs b/library/std/src/net/ip/tests.rs new file mode 100644 index 0000000000..d9fbdd1b5e --- /dev/null +++ b/library/std/src/net/ip/tests.rs @@ -0,0 +1,939 @@ +use crate::net::test::{sa4, sa6, tsa}; +use crate::net::*; +use crate::str::FromStr; + +#[test] +fn test_from_str_ipv4() { + assert_eq!(Ok(Ipv4Addr::new(127, 0, 0, 1)), "127.0.0.1".parse()); + assert_eq!(Ok(Ipv4Addr::new(255, 255, 255, 255)), "255.255.255.255".parse()); + assert_eq!(Ok(Ipv4Addr::new(0, 0, 0, 0)), "0.0.0.0".parse()); + + // out of range + let none: Option = "256.0.0.1".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "255.0.0".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "255.0.0.1.2".parse().ok(); + assert_eq!(None, none); + // no number between dots + let none: Option = "255.0..1".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "0:0:0:0:0:0:0:0".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "0:0:0:0:0:0:0:1".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)), "::1".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)), "::".parse()); + + assert_eq!(Ok(Ipv6Addr::new(0x2a02, 0x6b8, 0, 0, 0, 0, 0x11, 0x11)), "2a02:6b8::11:11".parse()); + + // too long group + let none: Option = "::00000".parse().ok(); + assert_eq!(None, none); + // too short + let none: Option = "1:2:3:4:5:6:7".parse().ok(); + assert_eq!(None, none); + // too long + let none: Option = "1:2:3:4:5:6:7:8:9".parse().ok(); + assert_eq!(None, none); + // triple colon + let none: Option = "1:2:::6:7:8".parse().ok(); + assert_eq!(None, none); + // two double colons + let none: Option = "1:2::6::8".parse().ok(); + assert_eq!(None, none); + // `::` indicating zero groups of zeros + let none: Option = "1:2:3:4::5:6:7:8".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_ipv4_in_ipv6() { + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 49152, 545)), "::192.0.2.33".parse()); + assert_eq!(Ok(Ipv6Addr::new(0, 0, 0, 0, 0, 0xFFFF, 49152, 545)), "::FFFF:192.0.2.33".parse()); + assert_eq!( + Ok(Ipv6Addr::new(0x64, 0xff9b, 0, 0, 0, 0, 49152, 545)), + "64:ff9b::192.0.2.33".parse() + ); + assert_eq!( + Ok(Ipv6Addr::new(0x2001, 0xdb8, 0x122, 0xc000, 0x2, 0x2100, 49152, 545)), + "2001:db8:122:c000:2:2100:192.0.2.33".parse() + ); + + // colon after v4 + let none: Option = "::127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // not enough groups + let none: Option = "1.2.3.4.5:127.0.0.1".parse().ok(); + assert_eq!(None, none); + // too many groups + let none: Option = "1.2.3.4.5:6:7:127.0.0.1".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn test_from_str_socket_addr() { + assert_eq!(Ok(sa4(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!(Ok(SocketAddrV4::new(Ipv4Addr::new(77, 88, 21, 11), 80)), "77.88.21.11:80".parse()); + assert_eq!( + Ok(sa6(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0x2a02, 0x6b8, 0, 1, 0, 0, 0, 1), 53, 0, 0)), + "[2a02:6b8:0:1::1]:53".parse() + ); + assert_eq!(Ok(sa6(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22)), "[::127.0.0.1]:22".parse()); + assert_eq!( + Ok(SocketAddrV6::new(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x7F00, 1), 22, 0, 0)), + "[::127.0.0.1]:22".parse() + ); + + // without port + let none: Option = "127.0.0.1".parse().ok(); + assert_eq!(None, none); + // without port + let none: Option = "127.0.0.1:".parse().ok(); + assert_eq!(None, none); + // wrong brackets around v4 + let none: Option = "[127.0.0.1]:22".parse().ok(); + assert_eq!(None, none); + // port out of range + let none: Option = "127.0.0.1:123456".parse().ok(); + assert_eq!(None, none); +} + +#[test] +fn ipv4_addr_to_string() { + assert_eq!(Ipv4Addr::new(127, 0, 0, 1).to_string(), "127.0.0.1"); + // Short address + assert_eq!(Ipv4Addr::new(1, 1, 1, 1).to_string(), "1.1.1.1"); + // Long address + assert_eq!(Ipv4Addr::new(127, 127, 127, 127).to_string(), "127.127.127.127"); + + // Test padding + assert_eq!(&format!("{:16}", Ipv4Addr::new(1, 1, 1, 1)), "1.1.1.1 "); + assert_eq!(&format!("{:>16}", Ipv4Addr::new(1, 1, 1, 1)), " 1.1.1.1"); +} + +#[test] +fn ipv6_addr_to_string() { + // ipv4-mapped address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::ffff:192.0.2.128"); + + // ipv4-compatible address + let a1 = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc000, 0x280); + assert_eq!(a1.to_string(), "::192.0.2.128"); + + // v6 address with no zero segments + assert_eq!(Ipv6Addr::new(8, 9, 10, 11, 12, 13, 14, 15).to_string(), "8:9:a:b:c:d:e:f"); + + // longest possible IPv6 length + assert_eq!( + Ipv6Addr::new(0x1111, 0x2222, 0x3333, 0x4444, 0x5555, 0x6666, 0x7777, 0x8888).to_string(), + "1111:2222:3333:4444:5555:6666:7777:8888" + ); + // padding + assert_eq!(&format!("{:20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), "1:2:3:4:5:6:7:8 "); + assert_eq!(&format!("{:>20}", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 7, 8)), " 1:2:3:4:5:6:7:8"); + + // reduce a single run of zeros + assert_eq!( + "ae::ffff:102:304", + Ipv6Addr::new(0xae, 0, 0, 0, 0, 0xffff, 0x0102, 0x0304).to_string() + ); + + // don't reduce just a single zero segment + assert_eq!("1:2:3:4:5:6:0:8", Ipv6Addr::new(1, 2, 3, 4, 5, 6, 0, 8).to_string()); + + // 'any' address + assert_eq!("::", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // loopback address + assert_eq!("::1", Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1).to_string()); + + // ends in zeros + assert_eq!("1::", Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0).to_string()); + + // two runs of zeros, second one is longer + assert_eq!("1:0:0:4::8", Ipv6Addr::new(1, 0, 0, 4, 0, 0, 0, 8).to_string()); + + // two runs of zeros, equal length + assert_eq!("1::4:5:0:0:8", Ipv6Addr::new(1, 0, 0, 4, 5, 0, 0, 8).to_string()); +} + +#[test] +fn ipv4_to_ipv6() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_mapped() + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678), + Ipv4Addr::new(0x12, 0x34, 0x56, 0x78).to_ipv6_compatible() + ); +} + +#[test] +fn ipv6_to_ipv4_mapped() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4_mapped(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4_mapped(), None); +} + +#[test] +fn ipv6_to_ipv4() { + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!( + Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), + Some(Ipv4Addr::new(0x12, 0x34, 0x56, 0x78)) + ); + assert_eq!(Ipv6Addr::new(0, 0, 1, 0, 0, 0, 0x1234, 0x5678).to_ipv4(), None); +} + +#[test] +fn ip_properties() { + macro_rules! ip { + ($s:expr) => { + IpAddr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & doc) == doc { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + }}; + } + + let unspec: u8 = 1 << 0; + let loopback: u8 = 1 << 1; + let global: u8 = 1 << 2; + let multicast: u8 = 1 << 3; + let doc: u8 = 1 << 4; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7"); + check!("127.1.2.3", loopback); + check!("172.31.254.253"); + check!("169.254.253.242"); + check!("192.0.2.183", doc); + check!("192.1.2.183", global); + check!("192.168.254.253"); + check!("198.51.100.0", doc); + check!("203.0.113.0", doc); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + 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"); + // make sure addresses reserved for protocol assignment are not global + check!("192.0.0.0"); + check!("192.0.0.255"); + check!("192.0.0.100"); + // make sure reserved addresses are not global + check!("240.0.0.0"); + check!("251.54.1.76"); + check!("254.255.255.255"); + // make sure shared addresses are not global + check!("100.64.0.0"); + check!("100.127.255.255"); + check!("100.100.100.0"); + + check!("::", unspec); + check!("::1", loopback); + check!("::0.0.0.2", global); + check!("1::", global); + check!("fc00::"); + check!("fdff:ffff::"); + check!("fe80:ffff::"); + check!("febf:ffff::"); + check!("fec0::", global); + check!("ff01::", multicast); + check!("ff02::", multicast); + check!("ff03::", multicast); + check!("ff04::", multicast); + check!("ff05::", multicast); + check!("ff08::", multicast); + check!("ff0e::", global | multicast); + check!("2001:db8:85a3::8a2e:370:7334", doc); + check!("102:304:506:708:90a:b0c:d0e:f10", global); +} + +#[test] +fn ipv4_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv4Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr) => { + check!($s, 0); + }; + + ($s:expr, $mask:expr) => {{ + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + if ($mask & unspec) == unspec { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + + if ($mask & private) == private { + assert!(ip!($s).is_private()); + } else { + assert!(!ip!($s).is_private()); + } + + if ($mask & link_local) == link_local { + assert!(ip!($s).is_link_local()); + } else { + assert!(!ip!($s).is_link_local()); + } + + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + + if ($mask & multicast) == multicast { + assert!(ip!($s).is_multicast()); + } else { + assert!(!ip!($s).is_multicast()); + } + + if ($mask & broadcast) == broadcast { + assert!(ip!($s).is_broadcast()); + } else { + assert!(!ip!($s).is_broadcast()); + } + + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + + if ($mask & benchmarking) == benchmarking { + assert!(ip!($s).is_benchmarking()); + } else { + assert!(!ip!($s).is_benchmarking()); + } + + if ($mask & ietf_protocol_assignment) == ietf_protocol_assignment { + assert!(ip!($s).is_ietf_protocol_assignment()); + } else { + assert!(!ip!($s).is_ietf_protocol_assignment()); + } + + if ($mask & reserved) == reserved { + assert!(ip!($s).is_reserved()); + } else { + assert!(!ip!($s).is_reserved()); + } + + if ($mask & shared) == shared { + assert!(ip!($s).is_shared()); + } else { + assert!(!ip!($s).is_shared()); + } + }}; + } + + let unspec: u16 = 1 << 0; + let loopback: u16 = 1 << 1; + let private: u16 = 1 << 2; + let link_local: u16 = 1 << 3; + let global: u16 = 1 << 4; + let multicast: u16 = 1 << 5; + let broadcast: u16 = 1 << 6; + let documentation: u16 = 1 << 7; + let benchmarking: u16 = 1 << 8; + let ietf_protocol_assignment: u16 = 1 << 9; + let reserved: u16 = 1 << 10; + let shared: u16 = 1 << 11; + + check!("0.0.0.0", unspec); + check!("0.0.0.1"); + check!("0.1.0.0"); + check!("10.9.8.7", private); + check!("127.1.2.3", loopback); + check!("172.31.254.253", private); + check!("169.254.253.242", link_local); + check!("192.0.2.183", documentation); + check!("192.1.2.183", global); + check!("192.168.254.253", private); + check!("198.51.100.0", documentation); + check!("203.0.113.0", documentation); + check!("203.2.113.0", global); + check!("224.0.0.0", global | multicast); + check!("239.255.255.255", global | multicast); + check!("255.255.255.255", broadcast); + check!("198.18.0.0", benchmarking); + check!("198.18.54.2", benchmarking); + check!("198.19.255.255", benchmarking); + check!("192.0.0.0", ietf_protocol_assignment); + check!("192.0.0.255", ietf_protocol_assignment); + check!("192.0.0.100", ietf_protocol_assignment); + check!("240.0.0.0", reserved); + check!("251.54.1.76", reserved); + check!("254.255.255.255", reserved); + check!("100.64.0.0", shared); + check!("100.127.255.255", shared); + check!("100.100.100.0", shared); +} + +#[test] +fn ipv6_properties() { + macro_rules! ip { + ($s:expr) => { + Ipv6Addr::from_str($s).unwrap() + }; + } + + macro_rules! check { + ($s:expr, &[$($octet:expr),*], $mask:expr) => { + assert_eq!($s, ip!($s).to_string()); + let octets = &[$($octet),*]; + 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_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + 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 + | multicast_admin_local + | multicast_global + | multicast_link_local + | multicast_realm_local + | multicast_site_local + | multicast_organization_local; + + if ($mask & unspecified) == unspecified { + assert!(ip!($s).is_unspecified()); + } else { + assert!(!ip!($s).is_unspecified()); + } + if ($mask & loopback) == loopback { + assert!(ip!($s).is_loopback()); + } else { + assert!(!ip!($s).is_loopback()); + } + if ($mask & unique_local) == unique_local { + assert!(ip!($s).is_unique_local()); + } else { + assert!(!ip!($s).is_unique_local()); + } + if ($mask & global) == global { + assert!(ip!($s).is_global()); + } else { + assert!(!ip!($s).is_global()); + } + if ($mask & unicast_link_local) == unicast_link_local { + assert!(ip!($s).is_unicast_link_local()); + } else { + assert!(!ip!($s).is_unicast_link_local()); + } + if ($mask & unicast_link_local_strict) == unicast_link_local_strict { + assert!(ip!($s).is_unicast_link_local_strict()); + } else { + assert!(!ip!($s).is_unicast_link_local_strict()); + } + if ($mask & unicast_site_local) == unicast_site_local { + assert!(ip!($s).is_unicast_site_local()); + } else { + assert!(!ip!($s).is_unicast_site_local()); + } + if ($mask & unicast_global) == unicast_global { + assert!(ip!($s).is_unicast_global()); + } else { + assert!(!ip!($s).is_unicast_global()); + } + if ($mask & documentation) == documentation { + assert!(ip!($s).is_documentation()); + } else { + assert!(!ip!($s).is_documentation()); + } + if ($mask & multicast) != 0 { + assert!(ip!($s).multicast_scope().is_some()); + assert!(ip!($s).is_multicast()); + } else { + assert!(ip!($s).multicast_scope().is_none()); + assert!(!ip!($s).is_multicast()); + } + if ($mask & multicast_interface_local) == multicast_interface_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::InterfaceLocal); + } + if ($mask & multicast_link_local) == multicast_link_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::LinkLocal); + } + if ($mask & multicast_realm_local) == multicast_realm_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::RealmLocal); + } + if ($mask & multicast_admin_local) == multicast_admin_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::AdminLocal); + } + if ($mask & multicast_site_local) == multicast_site_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::SiteLocal); + } + if ($mask & multicast_organization_local) == multicast_organization_local { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::OrganizationLocal); + } + if ($mask & multicast_global) == multicast_global { + assert_eq!(ip!($s).multicast_scope().unwrap(), + Ipv6MulticastScope::Global); + } + } + } + + 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_link_local_strict: u16 = 1 << 5; + let unicast_site_local: u16 = 1 << 6; + 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; + + check!("::", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unspecified); + + check!("::1", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1], loopback); + + check!("::0.0.0.2", &[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2], global | unicast_global); + + check!("1::", &[0, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], global | unicast_global); + + check!("fc00::", &[0xfc, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unique_local); + + check!( + "fdff:ffff::", + &[0xfd, 0xff, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unique_local + ); + + check!( + "fe80:ffff::", + &[0xfe, 0x80, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fe80::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local | unicast_link_local_strict + ); + + check!( + "febf:ffff::", + &[0xfe, 0xbf, 0xff, 0xff, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!("febf::", &[0xfe, 0xbf, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], unicast_link_local); + + check!( + "febf:ffff:ffff:ffff:ffff:ffff:ffff:ffff", + &[ + 0xfe, 0xbf, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local + ); + + check!( + "fe80::ffff:ffff:ffff:ffff", + &[ + 0xfe, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, + 0xff, 0xff + ], + unicast_link_local | unicast_link_local_strict + ); + + check!( + "fe80:0:0:1::", + &[0xfe, 0x80, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_link_local + ); + + check!( + "fec0::", + &[0xfe, 0xc0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + unicast_site_local | unicast_global | global + ); + + check!( + "ff01::", + &[0xff, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_interface_local + ); + + check!("ff02::", &[0xff, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_link_local); + + check!("ff03::", &[0xff, 3, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_realm_local); + + check!("ff04::", &[0xff, 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_admin_local); + + check!("ff05::", &[0xff, 5, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], multicast_site_local); + + check!( + "ff08::", + &[0xff, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_organization_local + ); + + check!( + "ff0e::", + &[0xff, 0xe, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + multicast_global | global + ); + + check!( + "2001:db8:85a3::8a2e:370:7334", + &[0x20, 1, 0xd, 0xb8, 0x85, 0xa3, 0, 0, 0, 0, 0x8a, 0x2e, 3, 0x70, 0x73, 0x34], + documentation + ); + + 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 + ); +} + +#[test] +fn to_socket_addr_socketaddr() { + let a = sa4(Ipv4Addr::new(77, 88, 21, 11), 12345); + assert_eq!(Ok(vec![a]), tsa(a)); +} + +#[test] +fn test_ipv4_to_int() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(u32::from(a), 0x11223344); +} + +#[test] +fn test_int_to_ipv4() { + let a = Ipv4Addr::new(0x11, 0x22, 0x33, 0x44); + assert_eq!(Ipv4Addr::from(0x11223344), a); +} + +#[test] +fn test_ipv6_to_int() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(u128::from(a), 0x112233445566778899aabbccddeeff11u128); +} + +#[test] +fn test_int_to_ipv6() { + let a = Ipv6Addr::new(0x1122, 0x3344, 0x5566, 0x7788, 0x99aa, 0xbbcc, 0xddee, 0xff11); + assert_eq!(Ipv6Addr::from(0x112233445566778899aabbccddeeff11u128), a); +} + +#[test] +fn ipv4_from_constructors() { + assert_eq!(Ipv4Addr::LOCALHOST, Ipv4Addr::new(127, 0, 0, 1)); + assert!(Ipv4Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv4Addr::UNSPECIFIED, Ipv4Addr::new(0, 0, 0, 0)); + assert!(Ipv4Addr::UNSPECIFIED.is_unspecified()); + assert_eq!(Ipv4Addr::BROADCAST, Ipv4Addr::new(255, 255, 255, 255)); + assert!(Ipv4Addr::BROADCAST.is_broadcast()); +} + +#[test] +fn ipv6_from_contructors() { + assert_eq!(Ipv6Addr::LOCALHOST, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + assert!(Ipv6Addr::LOCALHOST.is_loopback()); + assert_eq!(Ipv6Addr::UNSPECIFIED, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + assert!(Ipv6Addr::UNSPECIFIED.is_unspecified()); +} + +#[test] +fn ipv4_from_octets() { + assert_eq!(Ipv4Addr::from([127, 0, 0, 1]), Ipv4Addr::new(127, 0, 0, 1)) +} + +#[test] +fn ipv6_from_segments() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let new = Ipv6Addr::new(0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff); + assert_eq!(new, from_u16s); +} + +#[test] +fn ipv6_from_octets() { + let from_u16s = + Ipv6Addr::from([0x0011, 0x2233, 0x4455, 0x6677, 0x8899, 0xaabb, 0xccdd, 0xeeff]); + let from_u8s = Ipv6Addr::from([ + 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, + 0xff, + ]); + assert_eq!(from_u16s, from_u8s); +} + +#[test] +fn cmp() { + let v41 = Ipv4Addr::new(100, 64, 3, 3); + let v42 = Ipv4Addr::new(192, 0, 2, 2); + let v61 = "2001:db8:f00::1002".parse::().unwrap(); + let v62 = "2001:db8:f00::2001".parse::().unwrap(); + assert!(v41 < v42); + assert!(v61 < v62); + + assert_eq!(v41, IpAddr::V4(v41)); + assert_eq!(v61, IpAddr::V6(v61)); + assert!(v41 != IpAddr::V4(v42)); + assert!(v61 != IpAddr::V6(v62)); + + assert!(v41 < IpAddr::V4(v42)); + assert!(v61 < IpAddr::V6(v62)); + assert!(IpAddr::V4(v41) < v42); + assert!(IpAddr::V6(v61) < v62); + + assert!(v41 < IpAddr::V6(v61)); + assert!(IpAddr::V4(v41) < v61); +} + +#[test] +fn is_v4() { + let ip = IpAddr::V4(Ipv4Addr::new(100, 64, 3, 3)); + assert!(ip.is_ipv4()); + assert!(!ip.is_ipv6()); +} + +#[test] +fn is_v6() { + let ip = IpAddr::V6(Ipv6Addr::new(0, 0, 0, 0, 0, 0xffff, 0x1234, 0x5678)); + assert!(!ip.is_ipv4()); + assert!(ip.is_ipv6()); +} + +#[test] +fn ipv4_const() { + // test that the methods of `Ipv4Addr` are usable in a const context + + const IP_ADDRESS: Ipv4Addr = Ipv4Addr::new(127, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv4Addr::LOCALHOST); + + const OCTETS: [u8; 4] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [127, 0, 0, 1]); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_PRIVATE: bool = IP_ADDRESS.is_private(); + assert!(!IS_PRIVATE); + + const IS_LINK_LOCAL: bool = IP_ADDRESS.is_link_local(); + assert!(!IS_LINK_LOCAL); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_SHARED: bool = IP_ADDRESS.is_shared(); + assert!(!IS_SHARED); + + const IS_IETF_PROTOCOL_ASSIGNMENT: bool = IP_ADDRESS.is_ietf_protocol_assignment(); + assert!(!IS_IETF_PROTOCOL_ASSIGNMENT); + + const IS_BENCHMARKING: bool = IP_ADDRESS.is_benchmarking(); + assert!(!IS_BENCHMARKING); + + const IS_RESERVED: bool = IP_ADDRESS.is_reserved(); + assert!(!IS_RESERVED); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IS_BROADCAST: bool = IP_ADDRESS.is_broadcast(); + assert!(!IS_BROADCAST); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IP_V6_COMPATIBLE: Ipv6Addr = IP_ADDRESS.to_ipv6_compatible(); + assert_eq!( + IP_V6_COMPATIBLE, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 127, 0, 0, 1]) + ); + + const IP_V6_MAPPED: Ipv6Addr = IP_ADDRESS.to_ipv6_mapped(); + assert_eq!( + IP_V6_MAPPED, + Ipv6Addr::from([0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 255, 255, 127, 0, 0, 1]) + ); +} + +#[test] +fn ipv6_const() { + // test that the methods of `Ipv6Addr` are usable in a const context + + const IP_ADDRESS: Ipv6Addr = Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1); + assert_eq!(IP_ADDRESS, Ipv6Addr::LOCALHOST); + + const SEGMENTS: [u16; 8] = IP_ADDRESS.segments(); + assert_eq!(SEGMENTS, [0, 0, 0, 0, 0, 0, 0, 1]); + + const OCTETS: [u8; 16] = IP_ADDRESS.octets(); + assert_eq!(OCTETS, [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1]); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_UNIQUE_LOCAL: bool = IP_ADDRESS.is_unique_local(); + assert!(!IS_UNIQUE_LOCAL); + + const IS_UNICAST_LINK_LOCAL_STRICT: bool = IP_ADDRESS.is_unicast_link_local_strict(); + assert!(!IS_UNICAST_LINK_LOCAL_STRICT); + + const IS_UNICAST_LINK_LOCAL: bool = IP_ADDRESS.is_unicast_link_local(); + assert!(!IS_UNICAST_LINK_LOCAL); + + const IS_UNICAST_SITE_LOCAL: bool = IP_ADDRESS.is_unicast_site_local(); + assert!(!IS_UNICAST_SITE_LOCAL); + + const IS_DOCUMENTATION: bool = IP_ADDRESS.is_documentation(); + assert!(!IS_DOCUMENTATION); + + const IS_UNICAST_GLOBAL: bool = IP_ADDRESS.is_unicast_global(); + assert!(!IS_UNICAST_GLOBAL); + + const MULTICAST_SCOPE: Option = IP_ADDRESS.multicast_scope(); + assert_eq!(MULTICAST_SCOPE, None); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); + + const IP_V4: Option = IP_ADDRESS.to_ipv4(); + assert_eq!(IP_V4.unwrap(), Ipv4Addr::new(0, 0, 0, 1)); +} + +#[test] +fn ip_const() { + // test that the methods of `IpAddr` are usable in a const context + + const IP_ADDRESS: IpAddr = IpAddr::V4(Ipv4Addr::LOCALHOST); + + const IS_UNSPECIFIED: bool = IP_ADDRESS.is_unspecified(); + assert!(!IS_UNSPECIFIED); + + const IS_LOOPBACK: bool = IP_ADDRESS.is_loopback(); + assert!(IS_LOOPBACK); + + const IS_GLOBAL: bool = IP_ADDRESS.is_global(); + assert!(!IS_GLOBAL); + + const IS_MULTICAST: bool = IP_ADDRESS.is_multicast(); + assert!(!IS_MULTICAST); +} diff --git a/library/std/src/net/parser.rs b/library/std/src/net/parser.rs index a425aca5a6..0570a7c41b 100644 --- a/library/std/src/net/parser.rs +++ b/library/std/src/net/parser.rs @@ -3,6 +3,9 @@ //! This module is "publicly exported" through the `FromStr` implementations //! below. +#[cfg(test)] +mod tests; + use crate::error::Error; use crate::fmt; use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; @@ -321,146 +324,3 @@ impl Error for AddrParseError { "invalid IP address syntax" } } - -#[cfg(test)] -mod tests { - // FIXME: These tests are all excellent candidates for AFL fuzz testing - use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; - use crate::str::FromStr; - - const PORT: u16 = 8080; - - const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); - const IPV4_STR: &str = "192.168.0.1"; - const IPV4_STR_PORT: &str = "192.168.0.1:8080"; - - const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); - const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; - const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; - const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; - const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; - - #[test] - fn parse_ipv4() { - let result: Ipv4Addr = IPV4_STR.parse().unwrap(); - assert_eq!(result, IPV4); - - assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); - assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_ipv6() { - let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); - assert_eq!(result, IPV6); - - let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); - assert_eq!(result, IPV6); - - let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); - assert_eq!(result, IPV6); - - assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); - assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); - assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_ip() { - let result: IpAddr = IPV4_STR.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV4)); - - let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - let result: IpAddr = IPV6_STR_V4.parse().unwrap(); - assert_eq!(result, IpAddr::from(IPV6)); - - assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); - assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_socket_v4() { - let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); - - assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); - assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); - } - - #[test] - fn parse_socket_v6() { - let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0)); - - assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); - assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); - } - - #[test] - fn parse_socket() { - let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddr::from((IPV4, PORT))); - - let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); - assert_eq!(result, SocketAddr::from((IPV6, PORT))); - - assert!(SocketAddr::from_str(IPV4_STR).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); - assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); - } - - #[test] - fn ipv6_corner_cases() { - let result: Ipv6Addr = "1::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "1:1::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "::1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); - - let result: Ipv6Addr = "::1:1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); - - let result: Ipv6Addr = "::".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); - - let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); - - let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); - - let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); - assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); - } - - // Things that might not seem like failures but are - #[test] - fn ipv6_corner_failures() { - // No IP address before the :: - assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); - - // :: must have at least 1 set of zeroes - assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); - - // Need brackets for a port - assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); - } -} diff --git a/library/std/src/net/parser/tests.rs b/library/std/src/net/parser/tests.rs new file mode 100644 index 0000000000..ecf5a782c0 --- /dev/null +++ b/library/std/src/net/parser/tests.rs @@ -0,0 +1,139 @@ +// FIXME: These tests are all excellent candidates for AFL fuzz testing +use crate::net::{IpAddr, Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +use crate::str::FromStr; + +const PORT: u16 = 8080; + +const IPV4: Ipv4Addr = Ipv4Addr::new(192, 168, 0, 1); +const IPV4_STR: &str = "192.168.0.1"; +const IPV4_STR_PORT: &str = "192.168.0.1:8080"; + +const IPV6: Ipv6Addr = Ipv6Addr::new(0x2001, 0xdb8, 0, 0, 0, 0, 0xc0a8, 0x1); +const IPV6_STR_FULL: &str = "2001:db8:0:0:0:0:c0a8:1"; +const IPV6_STR_COMPRESS: &str = "2001:db8::c0a8:1"; +const IPV6_STR_V4: &str = "2001:db8::192.168.0.1"; +const IPV6_STR_PORT: &str = "[2001:db8::c0a8:1]:8080"; + +#[test] +fn parse_ipv4() { + let result: Ipv4Addr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IPV4); + + assert!(Ipv4Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_FULL).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_V4).is_err()); + assert!(Ipv4Addr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_ipv6() { + let result: Ipv6Addr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IPV6); + + let result: Ipv6Addr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IPV6); + + assert!(Ipv6Addr::from_str(IPV4_STR).is_err()); + assert!(Ipv6Addr::from_str(IPV4_STR_PORT).is_err()); + assert!(Ipv6Addr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_ip() { + let result: IpAddr = IPV4_STR.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV4)); + + let result: IpAddr = IPV6_STR_FULL.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_COMPRESS.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + let result: IpAddr = IPV6_STR_V4.parse().unwrap(); + assert_eq!(result, IpAddr::from(IPV6)); + + assert!(IpAddr::from_str(IPV4_STR_PORT).is_err()); + assert!(IpAddr::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_socket_v4() { + let result: SocketAddrV4 = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddrV4::new(IPV4, PORT)); + + assert!(SocketAddrV4::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_V4).is_err()); + assert!(SocketAddrV4::from_str(IPV6_STR_PORT).is_err()); +} + +#[test] +fn parse_socket_v6() { + let result: SocketAddrV6 = IPV6_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddrV6::new(IPV6, PORT, 0, 0)); + + assert!(SocketAddrV6::from_str(IPV4_STR).is_err()); + assert!(SocketAddrV6::from_str(IPV4_STR_PORT).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddrV6::from_str(IPV6_STR_V4).is_err()); +} + +#[test] +fn parse_socket() { + let result: SocketAddr = IPV4_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV4, PORT))); + + let result: SocketAddr = IPV6_STR_PORT.parse().unwrap(); + assert_eq!(result, SocketAddr::from((IPV6, PORT))); + + assert!(SocketAddr::from_str(IPV4_STR).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_FULL).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_COMPRESS).is_err()); + assert!(SocketAddr::from_str(IPV6_STR_V4).is_err()); +} + +#[test] +fn ipv6_corner_cases() { + let result: Ipv6Addr = "1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "1:1::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 1)); + + let result: Ipv6Addr = "::1:1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 1, 1)); + + let result: Ipv6Addr = "::".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0, 0)); + + let result: Ipv6Addr = "::192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 0, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "::1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(0, 0, 0, 0, 0, 1, 0xc0a8, 0x1)); + + let result: Ipv6Addr = "1:1:1:1:1:1:192.168.0.1".parse().unwrap(); + assert_eq!(result, Ipv6Addr::new(1, 1, 1, 1, 1, 1, 0xc0a8, 0x1)); +} + +// Things that might not seem like failures but are +#[test] +fn ipv6_corner_failures() { + // No IP address before the :: + assert!(Ipv6Addr::from_str("1:192.168.0.1::").is_err()); + + // :: must have at least 1 set of zeroes + assert!(Ipv6Addr::from_str("1:1:1:1::1:1:1:1").is_err()); + + // Need brackets for a port + assert!(SocketAddrV6::from_str("1:1:1:1:1:1:1:1:8080").is_err()); +} diff --git a/library/std/src/net/tcp.rs b/library/std/src/net/tcp.rs index a76c9c46c0..58c6343ea3 100644 --- a/library/std/src/net/tcp.rs +++ b/library/std/src/net/tcp.rs @@ -1,4 +1,8 @@ #![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] +mod tests; + use crate::io::prelude::*; use crate::fmt; @@ -936,869 +940,3 @@ impl fmt::Debug for TcpListener { self.0.fmt(f) } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten"))))] -mod tests { - use crate::fmt; - use crate::io::prelude::*; - use crate::io::{ErrorKind, IoSlice, IoSliceMut}; - use crate::net::test::{next_test_ip4, next_test_ip6}; - use crate::net::*; - use crate::sync::mpsc::channel; - use crate::thread; - use crate::time::{Duration, Instant}; - - fn each_ip(f: &mut dyn FnMut(SocketAddr)) { - f(next_test_ip4()); - f(next_test_ip6()); - } - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - }; - } - - #[test] - fn bind_error() { - match TcpListener::bind("1.1.1.1:9999") { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), - } - } - - #[test] - fn connect_error() { - match TcpStream::connect("0.0.0.0:1") { - Ok(..) => panic!(), - Err(e) => assert!( - e.kind() == ErrorKind::ConnectionRefused - || e.kind() == ErrorKind::InvalidInput - || e.kind() == ErrorKind::AddrInUse - || e.kind() == ErrorKind::AddrNotAvailable, - "bad error: {} {:?}", - e, - e.kind() - ), - } - } - - #[test] - fn listen_localhost() { - let socket_addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&socket_addr)); - - let _t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); - t!(stream.write(&[144])); - }); - - let mut stream = t!(listener.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 144); - } - - #[test] - fn connect_loopback() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let host = match addr { - SocketAddr::V4(..) => "127.0.0.1", - SocketAddr::V6(..) => "::1", - }; - let mut stream = t!(TcpStream::connect(&(host, addr.port()))); - t!(stream.write(&[66])); - }); - - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 66); - }) - } - - #[test] - fn smoke_test() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&addr)); - t!(stream.write(&[99])); - tx.send(t!(stream.local_addr())).unwrap(); - }); - - let (mut stream, addr) = t!(acceptor.accept()); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 99); - assert_eq!(addr, t!(rx.recv())); - }) - } - - #[test] - fn read_eof() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let _stream = t!(TcpStream::connect(&addr)); - // Close - }); - - let mut stream = t!(acceptor.accept()).0; - let mut buf = [0]; - let nread = t!(stream.read(&mut buf)); - assert_eq!(nread, 0); - let nread = t!(stream.read(&mut buf)); - assert_eq!(nread, 0); - }) - } - - #[test] - fn write_close() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - drop(t!(TcpStream::connect(&addr))); - tx.send(()).unwrap(); - }); - - let mut stream = t!(acceptor.accept()).0; - rx.recv().unwrap(); - let buf = [0]; - match stream.write(&buf) { - Ok(..) => {} - Err(e) => { - assert!( - e.kind() == ErrorKind::ConnectionReset - || e.kind() == ErrorKind::BrokenPipe - || e.kind() == ErrorKind::ConnectionAborted, - "unknown error: {}", - e - ); - } - } - }) - } - - #[test] - fn multiple_connect_serial() { - each_ip(&mut |addr| { - let max = 10; - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - for _ in 0..max { - let mut stream = t!(TcpStream::connect(&addr)); - t!(stream.write(&[99])); - } - }); - - for stream in acceptor.incoming().take(max) { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert_eq!(buf[0], 99); - } - }) - } - - #[test] - fn multiple_connect_interleaved_greedy_schedule() { - const MAX: usize = 10; - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let acceptor = acceptor; - for (i, stream) in acceptor.incoming().enumerate().take(MAX) { - // Start another thread to handle the connection - let _t = thread::spawn(move || { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == i as u8); - }); - } - }); - - connect(0, addr); - }); - - fn connect(i: usize, addr: SocketAddr) { - if i == MAX { - return; - } - - let t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&addr)); - // Connect again before writing - connect(i + 1, addr); - t!(stream.write(&[i as u8])); - }); - t.join().ok().expect("thread panicked"); - } - } - - #[test] - fn multiple_connect_interleaved_lazy_schedule() { - const MAX: usize = 10; - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - for stream in acceptor.incoming().take(MAX) { - // Start another thread to handle the connection - let _t = thread::spawn(move || { - let mut stream = t!(stream); - let mut buf = [0]; - t!(stream.read(&mut buf)); - assert!(buf[0] == 99); - }); - } - }); - - connect(0, addr); - }); - - fn connect(i: usize, addr: SocketAddr) { - if i == MAX { - return; - } - - let t = thread::spawn(move || { - let mut stream = t!(TcpStream::connect(&addr)); - connect(i + 1, addr); - t!(stream.write(&[99])); - }); - t.join().ok().expect("thread panicked"); - } - } - - #[test] - fn socket_and_peer_name() { - each_ip(&mut |addr| { - let listener = t!(TcpListener::bind(&addr)); - let so_name = t!(listener.local_addr()); - assert_eq!(addr, so_name); - let _t = thread::spawn(move || { - t!(listener.accept()); - }); - - let stream = t!(TcpStream::connect(&addr)); - assert_eq!(addr, t!(stream.peer_addr())); - }) - } - - #[test] - fn partial_read() { - each_ip(&mut |addr| { - let (tx, rx) = channel(); - let srv = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move || { - let mut cl = t!(srv.accept()).0; - cl.write(&[10]).unwrap(); - let mut b = [0]; - t!(cl.read(&mut b)); - tx.send(()).unwrap(); - }); - - let mut c = t!(TcpStream::connect(&addr)); - let mut b = [0; 10]; - assert_eq!(c.read(&mut b).unwrap(), 1); - t!(c.write(&[1])); - rx.recv().unwrap(); - }) - } - - #[test] - fn read_vectored() { - each_ip(&mut |addr| { - let srv = t!(TcpListener::bind(&addr)); - let mut s1 = t!(TcpStream::connect(&addr)); - let mut s2 = t!(srv.accept()).0; - - let len = s1.write(&[10, 11, 12]).unwrap(); - assert_eq!(len, 3); - - let mut a = []; - let mut b = [0]; - let mut c = [0; 3]; - let len = t!(s2.read_vectored(&mut [ - IoSliceMut::new(&mut a), - IoSliceMut::new(&mut b), - IoSliceMut::new(&mut c) - ],)); - assert!(len > 0); - assert_eq!(b, [10]); - // some implementations don't support readv, so we may only fill the first buffer - assert!(len == 1 || c == [11, 12, 0]); - }) - } - - #[test] - fn write_vectored() { - each_ip(&mut |addr| { - let srv = t!(TcpListener::bind(&addr)); - let mut s1 = t!(TcpStream::connect(&addr)); - let mut s2 = t!(srv.accept()).0; - - let a = []; - let b = [10]; - let c = [11, 12]; - t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); - - let mut buf = [0; 4]; - let len = t!(s2.read(&mut buf)); - // some implementations don't support writev, so we may only write the first buffer - if len == 1 { - assert_eq!(buf, [10, 0, 0, 0]); - } else { - assert_eq!(len, 3); - assert_eq!(buf, [10, 11, 12, 0]); - } - }) - } - - #[test] - fn double_bind() { - each_ip(&mut |addr| { - let listener1 = t!(TcpListener::bind(&addr)); - match TcpListener::bind(&addr) { - Ok(listener2) => panic!( - "This system (perhaps due to options set by TcpListener::bind) \ - permits double binding: {:?} and {:?}", - listener1, listener2 - ), - Err(e) => { - assert!( - e.kind() == ErrorKind::ConnectionRefused - || e.kind() == ErrorKind::Other - || e.kind() == ErrorKind::AddrInUse, - "unknown error: {} {:?}", - e, - e.kind() - ); - } - } - }) - } - - #[test] - fn tcp_clone_smoke() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let mut s = t!(TcpStream::connect(&addr)); - let mut buf = [0, 0]; - assert_eq!(s.read(&mut buf).unwrap(), 1); - assert_eq!(buf[0], 1); - t!(s.write(&[2])); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - rx1.recv().unwrap(); - t!(s2.write(&[1])); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(s1.read(&mut buf).unwrap(), 1); - rx2.recv().unwrap(); - }) - } - - #[test] - fn tcp_clone_two_read() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move || { - let mut s = t!(TcpStream::connect(&addr)); - t!(s.write(&[1])); - rx.recv().unwrap(); - t!(s.write(&[2])); - rx.recv().unwrap(); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - let mut buf = [0, 0]; - t!(s2.read(&mut buf)); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - t!(s1.read(&mut buf)); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - }) - } - - #[test] - fn tcp_clone_two_write() { - each_ip(&mut |addr| { - let acceptor = t!(TcpListener::bind(&addr)); - - let _t = thread::spawn(move || { - let mut s = t!(TcpStream::connect(&addr)); - let mut buf = [0, 1]; - t!(s.read(&mut buf)); - t!(s.read(&mut buf)); - }); - - let mut s1 = t!(acceptor.accept()).0; - let s2 = t!(s1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - t!(s2.write(&[1])); - done.send(()).unwrap(); - }); - t!(s1.write(&[2])); - - rx.recv().unwrap(); - }) - } - - #[test] - // FIXME: https://github.com/fortanix/rust-sgx/issues/110 - #[cfg_attr(target_env = "sgx", ignore)] - fn shutdown_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move || { - let mut c = t!(a.accept()).0; - let mut b = [0]; - assert_eq!(c.read(&mut b).unwrap(), 0); - t!(c.write(&[1])); - }); - - let mut s = t!(TcpStream::connect(&addr)); - t!(s.shutdown(Shutdown::Write)); - assert!(s.write(&[1]).is_err()); - let mut b = [0, 0]; - assert_eq!(t!(s.read(&mut b)), 1); - assert_eq!(b[0], 1); - }) - } - - #[test] - // FIXME: https://github.com/fortanix/rust-sgx/issues/110 - #[cfg_attr(target_env = "sgx", ignore)] - fn close_readwrite_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let (tx, rx) = channel::<()>(); - let _t = thread::spawn(move || { - let _s = t!(a.accept()); - let _ = rx.recv(); - }); - - let mut b = [0]; - let mut s = t!(TcpStream::connect(&addr)); - let mut s2 = t!(s.try_clone()); - - // closing should prevent reads/writes - t!(s.shutdown(Shutdown::Write)); - assert!(s.write(&[0]).is_err()); - t!(s.shutdown(Shutdown::Read)); - assert_eq!(s.read(&mut b).unwrap(), 0); - - // closing should affect previous handles - assert!(s2.write(&[0]).is_err()); - assert_eq!(s2.read(&mut b).unwrap(), 0); - - // closing should affect new handles - let mut s3 = t!(s.try_clone()); - assert!(s3.write(&[0]).is_err()); - assert_eq!(s3.read(&mut b).unwrap(), 0); - - // make sure these don't die - let _ = s2.shutdown(Shutdown::Read); - let _ = s2.shutdown(Shutdown::Write); - let _ = s3.shutdown(Shutdown::Read); - let _ = s3.shutdown(Shutdown::Write); - drop(tx); - }) - } - - #[test] - #[cfg(unix)] // test doesn't work on Windows, see #31657 - fn close_read_wakes_up() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let (tx1, rx) = channel::<()>(); - let _t = thread::spawn(move || { - let _s = t!(a.accept()); - let _ = rx.recv(); - }); - - let s = t!(TcpStream::connect(&addr)); - let s2 = t!(s.try_clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let mut s2 = s2; - assert_eq!(t!(s2.read(&mut [0])), 0); - tx.send(()).unwrap(); - }); - // this should wake up the child thread - t!(s.shutdown(Shutdown::Read)); - - // this test will never finish if the child doesn't wake up - rx.recv().unwrap(); - drop(tx1); - }) - } - - #[test] - fn clone_while_reading() { - each_ip(&mut |addr| { - let accept = t!(TcpListener::bind(&addr)); - - // Enqueue a thread to write to a socket - let (tx, rx) = channel(); - let (txdone, rxdone) = channel(); - let txdone2 = txdone.clone(); - let _t = thread::spawn(move || { - let mut tcp = t!(TcpStream::connect(&addr)); - rx.recv().unwrap(); - t!(tcp.write(&[0])); - txdone2.send(()).unwrap(); - }); - - // Spawn off a reading clone - let tcp = t!(accept.accept()).0; - let tcp2 = t!(tcp.try_clone()); - let txdone3 = txdone.clone(); - let _t = thread::spawn(move || { - let mut tcp2 = tcp2; - t!(tcp2.read(&mut [0])); - txdone3.send(()).unwrap(); - }); - - // Try to ensure that the reading clone is indeed reading - for _ in 0..50 { - thread::yield_now(); - } - - // clone the handle again while it's reading, then let it finish the - // read. - let _ = t!(tcp.try_clone()); - tx.send(()).unwrap(); - rxdone.recv().unwrap(); - rxdone.recv().unwrap(); - }) - } - - #[test] - fn clone_accept_smoke() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let a2 = t!(a.try_clone()); - - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - - t!(a.accept()); - t!(a2.accept()); - }) - } - - #[test] - fn clone_accept_concurrent() { - each_ip(&mut |addr| { - let a = t!(TcpListener::bind(&addr)); - let a2 = t!(a.try_clone()); - - let (tx, rx) = channel(); - let tx2 = tx.clone(); - - let _t = thread::spawn(move || { - tx.send(t!(a.accept())).unwrap(); - }); - let _t = thread::spawn(move || { - tx2.send(t!(a2.accept())).unwrap(); - }); - - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - let _t = thread::spawn(move || { - let _ = TcpStream::connect(&addr); - }); - - rx.recv().unwrap(); - rx.recv().unwrap(); - }) - } - - #[test] - fn debug() { - #[cfg(not(target_env = "sgx"))] - fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { - addr - } - #[cfg(target_env = "sgx")] - fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { - addr.to_string() - } - - #[cfg(target_env = "sgx")] - use crate::os::fortanix_sgx::io::AsRawFd; - #[cfg(unix)] - use crate::os::unix::io::AsRawFd; - #[cfg(not(windows))] - fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { - addr.as_raw_fd() - } - #[cfg(windows)] - fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { - addr.as_raw_socket() - } - - let inner_name = if cfg!(windows) { "socket" } else { "fd" }; - let socket_addr = next_test_ip4(); - - let listener = t!(TcpListener::bind(&socket_addr)); - let compare = format!( - "TcpListener {{ addr: {:?}, {}: {:?} }}", - render_socket_addr(&socket_addr), - inner_name, - render_inner(&listener) - ); - assert_eq!(format!("{:?}", listener), compare); - - let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); - let compare = format!( - "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", - render_socket_addr(&stream.local_addr().unwrap()), - render_socket_addr(&stream.peer_addr().unwrap()), - inner_name, - render_inner(&stream) - ); - assert_eq!(format!("{:?}", stream), compare); - } - - // FIXME: re-enabled openbsd tests once their socket timeout code - // no longer has rounding errors. - // VxWorks ignores SO_SNDTIMEO. - #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - #[test] - fn timeouts() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - let dur = Duration::new(15410, 0); - - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.read_timeout())); - - assert_eq!(None, t!(stream.write_timeout())); - - t!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.write_timeout())); - - t!(stream.set_read_timeout(None)); - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_write_timeout(None)); - assert_eq!(None, t!(stream.write_timeout())); - drop(listener); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn test_read_timeout() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let start = Instant::now(); - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - assert!(start.elapsed() > Duration::from_millis(400)); - drop(listener); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn test_read_with_timeout() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = t!(listener.accept()).0; - t!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - t!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let start = Instant::now(); - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - assert!(start.elapsed() > Duration::from_millis(400)); - drop(listener); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_timeout_zero_duration() { - let addr = next_test_ip4(); - - let listener = t!(TcpListener::bind(&addr)); - let stream = t!(TcpStream::connect(&addr)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] - fn nodelay() { - let addr = next_test_ip4(); - let _listener = t!(TcpListener::bind(&addr)); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - assert_eq!(false, t!(stream.nodelay())); - t!(stream.set_nodelay(true)); - assert_eq!(true, t!(stream.nodelay())); - t!(stream.set_nodelay(false)); - assert_eq!(false, t!(stream.nodelay())); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] - fn ttl() { - let ttl = 100; - - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - t!(listener.set_ttl(ttl)); - assert_eq!(ttl, t!(listener.ttl())); - - let stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - t!(stream.set_ttl(ttl)); - assert_eq!(ttl, t!(stream.ttl())); - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] - fn set_nonblocking() { - let addr = next_test_ip4(); - let listener = t!(TcpListener::bind(&addr)); - - t!(listener.set_nonblocking(true)); - t!(listener.set_nonblocking(false)); - - let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); - - t!(stream.set_nonblocking(false)); - t!(stream.set_nonblocking(true)); - - let mut buf = [0]; - match stream.read(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn peek() { - each_ip(&mut |addr| { - let (txdone, rxdone) = channel(); - - let srv = t!(TcpListener::bind(&addr)); - let _t = thread::spawn(move || { - let mut cl = t!(srv.accept()).0; - cl.write(&[1, 3, 3, 7]).unwrap(); - t!(rxdone.recv()); - }); - - let mut c = t!(TcpStream::connect(&addr)); - let mut b = [0; 10]; - for _ in 1..3 { - let len = c.peek(&mut b).unwrap(); - assert_eq!(len, 4); - } - let len = c.read(&mut b).unwrap(); - assert_eq!(len, 4); - - t!(c.set_nonblocking(true)); - match c.peek(&mut b) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - t!(txdone.send(())); - }) - } - - #[test] - #[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - fn connect_timeout_valid() { - let listener = TcpListener::bind("127.0.0.1:0").unwrap(); - let addr = listener.local_addr().unwrap(); - TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); - } -} diff --git a/library/std/src/net/tcp/tests.rs b/library/std/src/net/tcp/tests.rs new file mode 100644 index 0000000000..abe9bc24ce --- /dev/null +++ b/library/std/src/net/tcp/tests.rs @@ -0,0 +1,862 @@ +use crate::fmt; +use crate::io::prelude::*; +use crate::io::{ErrorKind, IoSlice, IoSliceMut}; +use crate::net::test::{next_test_ip4, next_test_ip6}; +use crate::net::*; +use crate::sync::mpsc::channel; +use crate::thread; +use crate::time::{Duration, Instant}; + +fn each_ip(f: &mut dyn FnMut(SocketAddr)) { + f(next_test_ip4()); + f(next_test_ip6()); +} + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; +} + +#[test] +fn bind_error() { + match TcpListener::bind("1.1.1.1:9999") { + Ok(..) => panic!(), + Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), + } +} + +#[test] +fn connect_error() { + match TcpStream::connect("0.0.0.0:1") { + Ok(..) => panic!(), + Err(e) => assert!( + e.kind() == ErrorKind::ConnectionRefused + || e.kind() == ErrorKind::InvalidInput + || e.kind() == ErrorKind::AddrInUse + || e.kind() == ErrorKind::AddrNotAvailable, + "bad error: {} {:?}", + e, + e.kind() + ), + } +} + +#[test] +fn listen_localhost() { + let socket_addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&socket_addr)); + + let _t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); + t!(stream.write(&[144])); + }); + + let mut stream = t!(listener.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 144); +} + +#[test] +fn connect_loopback() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let host = match addr { + SocketAddr::V4(..) => "127.0.0.1", + SocketAddr::V6(..) => "::1", + }; + let mut stream = t!(TcpStream::connect(&(host, addr.port()))); + t!(stream.write(&[66])); + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 66); + }) +} + +#[test] +fn smoke_test() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + tx.send(t!(stream.local_addr())).unwrap(); + }); + + let (mut stream, addr) = t!(acceptor.accept()); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + assert_eq!(addr, t!(rx.recv())); + }) +} + +#[test] +fn read_eof() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let _stream = t!(TcpStream::connect(&addr)); + // Close + }); + + let mut stream = t!(acceptor.accept()).0; + let mut buf = [0]; + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + let nread = t!(stream.read(&mut buf)); + assert_eq!(nread, 0); + }) +} + +#[test] +fn write_close() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + drop(t!(TcpStream::connect(&addr))); + tx.send(()).unwrap(); + }); + + let mut stream = t!(acceptor.accept()).0; + rx.recv().unwrap(); + let buf = [0]; + match stream.write(&buf) { + Ok(..) => {} + Err(e) => { + assert!( + e.kind() == ErrorKind::ConnectionReset + || e.kind() == ErrorKind::BrokenPipe + || e.kind() == ErrorKind::ConnectionAborted, + "unknown error: {}", + e + ); + } + } + }) +} + +#[test] +fn multiple_connect_serial() { + each_ip(&mut |addr| { + let max = 10; + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + for _ in 0..max { + let mut stream = t!(TcpStream::connect(&addr)); + t!(stream.write(&[99])); + } + }); + + for stream in acceptor.incoming().take(max) { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert_eq!(buf[0], 99); + } + }) +} + +#[test] +fn multiple_connect_interleaved_greedy_schedule() { + const MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let acceptor = acceptor; + for (i, stream) in acceptor.incoming().enumerate().take(MAX) { + // Start another thread to handle the connection + let _t = thread::spawn(move || { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == i as u8); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { + return; + } + + let t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&addr)); + // Connect again before writing + connect(i + 1, addr); + t!(stream.write(&[i as u8])); + }); + t.join().ok().expect("thread panicked"); + } +} + +#[test] +fn multiple_connect_interleaved_lazy_schedule() { + const MAX: usize = 10; + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + for stream in acceptor.incoming().take(MAX) { + // Start another thread to handle the connection + let _t = thread::spawn(move || { + let mut stream = t!(stream); + let mut buf = [0]; + t!(stream.read(&mut buf)); + assert!(buf[0] == 99); + }); + } + }); + + connect(0, addr); + }); + + fn connect(i: usize, addr: SocketAddr) { + if i == MAX { + return; + } + + let t = thread::spawn(move || { + let mut stream = t!(TcpStream::connect(&addr)); + connect(i + 1, addr); + t!(stream.write(&[99])); + }); + t.join().ok().expect("thread panicked"); + } +} + +#[test] +fn socket_and_peer_name() { + each_ip(&mut |addr| { + let listener = t!(TcpListener::bind(&addr)); + let so_name = t!(listener.local_addr()); + assert_eq!(addr, so_name); + let _t = thread::spawn(move || { + t!(listener.accept()); + }); + + let stream = t!(TcpStream::connect(&addr)); + assert_eq!(addr, t!(stream.peer_addr())); + }) +} + +#[test] +fn partial_read() { + each_ip(&mut |addr| { + let (tx, rx) = channel(); + let srv = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move || { + let mut cl = t!(srv.accept()).0; + cl.write(&[10]).unwrap(); + let mut b = [0]; + t!(cl.read(&mut b)); + tx.send(()).unwrap(); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + assert_eq!(c.read(&mut b).unwrap(), 1); + t!(c.write(&[1])); + rx.recv().unwrap(); + }) +} + +#[test] +fn read_vectored() { + each_ip(&mut |addr| { + let srv = t!(TcpListener::bind(&addr)); + let mut s1 = t!(TcpStream::connect(&addr)); + let mut s2 = t!(srv.accept()).0; + + let len = s1.write(&[10, 11, 12]).unwrap(); + assert_eq!(len, 3); + + let mut a = []; + let mut b = [0]; + let mut c = [0; 3]; + let len = t!(s2.read_vectored(&mut [ + IoSliceMut::new(&mut a), + IoSliceMut::new(&mut b), + IoSliceMut::new(&mut c) + ],)); + assert!(len > 0); + assert_eq!(b, [10]); + // some implementations don't support readv, so we may only fill the first buffer + assert!(len == 1 || c == [11, 12, 0]); + }) +} + +#[test] +fn write_vectored() { + each_ip(&mut |addr| { + let srv = t!(TcpListener::bind(&addr)); + let mut s1 = t!(TcpStream::connect(&addr)); + let mut s2 = t!(srv.accept()).0; + + let a = []; + let b = [10]; + let c = [11, 12]; + t!(s1.write_vectored(&[IoSlice::new(&a), IoSlice::new(&b), IoSlice::new(&c)])); + + let mut buf = [0; 4]; + let len = t!(s2.read(&mut buf)); + // some implementations don't support writev, so we may only write the first buffer + if len == 1 { + assert_eq!(buf, [10, 0, 0, 0]); + } else { + assert_eq!(len, 3); + assert_eq!(buf, [10, 11, 12, 0]); + } + }) +} + +#[test] +fn double_bind() { + each_ip(&mut |addr| { + let listener1 = t!(TcpListener::bind(&addr)); + match TcpListener::bind(&addr) { + Ok(listener2) => panic!( + "This system (perhaps due to options set by TcpListener::bind) \ + permits double binding: {:?} and {:?}", + listener1, listener2 + ), + Err(e) => { + assert!( + e.kind() == ErrorKind::ConnectionRefused + || e.kind() == ErrorKind::Other + || e.kind() == ErrorKind::AddrInUse, + "unknown error: {} {:?}", + e, + e.kind() + ); + } + } + }) +} + +#[test] +fn tcp_clone_smoke() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 0]; + assert_eq!(s.read(&mut buf).unwrap(), 1); + assert_eq!(buf[0], 1); + t!(s.write(&[2])); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + rx1.recv().unwrap(); + t!(s2.write(&[1])); + tx2.send(()).unwrap(); + }); + tx1.send(()).unwrap(); + let mut buf = [0, 0]; + assert_eq!(s1.read(&mut buf).unwrap(), 1); + rx2.recv().unwrap(); + }) +} + +#[test] +fn tcp_clone_two_read() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + t!(s.write(&[1])); + rx.recv().unwrap(); + t!(s.write(&[2])); + rx.recv().unwrap(); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + let mut buf = [0, 0]; + t!(s2.read(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(s1.read(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) +} + +#[test] +fn tcp_clone_two_write() { + each_ip(&mut |addr| { + let acceptor = t!(TcpListener::bind(&addr)); + + let _t = thread::spawn(move || { + let mut s = t!(TcpStream::connect(&addr)); + let mut buf = [0, 1]; + t!(s.read(&mut buf)); + t!(s.read(&mut buf)); + }); + + let mut s1 = t!(acceptor.accept()).0; + let s2 = t!(s1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + t!(s2.write(&[1])); + done.send(()).unwrap(); + }); + t!(s1.write(&[2])); + + rx.recv().unwrap(); + }) +} + +#[test] +// FIXME: https://github.com/fortanix/rust-sgx/issues/110 +#[cfg_attr(target_env = "sgx", ignore)] +fn shutdown_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move || { + let mut c = t!(a.accept()).0; + let mut b = [0]; + assert_eq!(c.read(&mut b).unwrap(), 0); + t!(c.write(&[1])); + }); + + let mut s = t!(TcpStream::connect(&addr)); + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[1]).is_err()); + let mut b = [0, 0]; + assert_eq!(t!(s.read(&mut b)), 1); + assert_eq!(b[0], 1); + }) +} + +#[test] +// FIXME: https://github.com/fortanix/rust-sgx/issues/110 +#[cfg_attr(target_env = "sgx", ignore)] +fn close_readwrite_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx, rx) = channel::<()>(); + let _t = thread::spawn(move || { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let mut b = [0]; + let mut s = t!(TcpStream::connect(&addr)); + let mut s2 = t!(s.try_clone()); + + // closing should prevent reads/writes + t!(s.shutdown(Shutdown::Write)); + assert!(s.write(&[0]).is_err()); + t!(s.shutdown(Shutdown::Read)); + assert_eq!(s.read(&mut b).unwrap(), 0); + + // closing should affect previous handles + assert!(s2.write(&[0]).is_err()); + assert_eq!(s2.read(&mut b).unwrap(), 0); + + // closing should affect new handles + let mut s3 = t!(s.try_clone()); + assert!(s3.write(&[0]).is_err()); + assert_eq!(s3.read(&mut b).unwrap(), 0); + + // make sure these don't die + let _ = s2.shutdown(Shutdown::Read); + let _ = s2.shutdown(Shutdown::Write); + let _ = s3.shutdown(Shutdown::Read); + let _ = s3.shutdown(Shutdown::Write); + drop(tx); + }) +} + +#[test] +#[cfg(unix)] // test doesn't work on Windows, see #31657 +fn close_read_wakes_up() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let (tx1, rx) = channel::<()>(); + let _t = thread::spawn(move || { + let _s = t!(a.accept()); + let _ = rx.recv(); + }); + + let s = t!(TcpStream::connect(&addr)); + let s2 = t!(s.try_clone()); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + let mut s2 = s2; + assert_eq!(t!(s2.read(&mut [0])), 0); + tx.send(()).unwrap(); + }); + // this should wake up the child thread + t!(s.shutdown(Shutdown::Read)); + + // this test will never finish if the child doesn't wake up + rx.recv().unwrap(); + drop(tx1); + }) +} + +#[test] +fn clone_while_reading() { + each_ip(&mut |addr| { + let accept = t!(TcpListener::bind(&addr)); + + // Enqueue a thread to write to a socket + let (tx, rx) = channel(); + let (txdone, rxdone) = channel(); + let txdone2 = txdone.clone(); + let _t = thread::spawn(move || { + let mut tcp = t!(TcpStream::connect(&addr)); + rx.recv().unwrap(); + t!(tcp.write(&[0])); + txdone2.send(()).unwrap(); + }); + + // Spawn off a reading clone + let tcp = t!(accept.accept()).0; + let tcp2 = t!(tcp.try_clone()); + let txdone3 = txdone.clone(); + let _t = thread::spawn(move || { + let mut tcp2 = tcp2; + t!(tcp2.read(&mut [0])); + txdone3.send(()).unwrap(); + }); + + // Try to ensure that the reading clone is indeed reading + for _ in 0..50 { + thread::yield_now(); + } + + // clone the handle again while it's reading, then let it finish the + // read. + let _ = t!(tcp.try_clone()); + tx.send(()).unwrap(); + rxdone.recv().unwrap(); + rxdone.recv().unwrap(); + }) +} + +#[test] +fn clone_accept_smoke() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + + t!(a.accept()); + t!(a2.accept()); + }) +} + +#[test] +fn clone_accept_concurrent() { + each_ip(&mut |addr| { + let a = t!(TcpListener::bind(&addr)); + let a2 = t!(a.try_clone()); + + let (tx, rx) = channel(); + let tx2 = tx.clone(); + + let _t = thread::spawn(move || { + tx.send(t!(a.accept())).unwrap(); + }); + let _t = thread::spawn(move || { + tx2.send(t!(a2.accept())).unwrap(); + }); + + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + let _t = thread::spawn(move || { + let _ = TcpStream::connect(&addr); + }); + + rx.recv().unwrap(); + rx.recv().unwrap(); + }) +} + +#[test] +fn debug() { + #[cfg(not(target_env = "sgx"))] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr + } + #[cfg(target_env = "sgx")] + fn render_socket_addr<'a>(addr: &'a SocketAddr) -> impl fmt::Debug + 'a { + addr.to_string() + } + + #[cfg(target_env = "sgx")] + use crate::os::fortanix_sgx::io::AsRawFd; + #[cfg(unix)] + use crate::os::unix::io::AsRawFd; + #[cfg(not(windows))] + fn render_inner(addr: &dyn AsRawFd) -> impl fmt::Debug { + addr.as_raw_fd() + } + #[cfg(windows)] + fn render_inner(addr: &dyn crate::os::windows::io::AsRawSocket) -> impl fmt::Debug { + addr.as_raw_socket() + } + + let inner_name = if cfg!(windows) { "socket" } else { "fd" }; + let socket_addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&socket_addr)); + let compare = format!( + "TcpListener {{ addr: {:?}, {}: {:?} }}", + render_socket_addr(&socket_addr), + inner_name, + render_inner(&listener) + ); + assert_eq!(format!("{:?}", listener), compare); + + let stream = t!(TcpStream::connect(&("localhost", socket_addr.port()))); + let compare = format!( + "TcpStream {{ addr: {:?}, peer: {:?}, {}: {:?} }}", + render_socket_addr(&stream.local_addr().unwrap()), + render_socket_addr(&stream.peer_addr().unwrap()), + inner_name, + render_inner(&stream) + ); + assert_eq!(format!("{:?}", stream), compare); +} + +// FIXME: re-enabled openbsd tests once their socket timeout code +// no longer has rounding errors. +// VxWorks ignores SO_SNDTIMEO. +#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +#[test] +fn timeouts() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + let dur = Duration::new(15410, 0); + + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.read_timeout())); + + assert_eq!(None, t!(stream.write_timeout())); + + t!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.write_timeout())); + + t!(stream.set_read_timeout(None)); + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_write_timeout(None)); + assert_eq!(None, t!(stream.write_timeout())); + drop(listener); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn test_read_timeout() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let start = Instant::now(); + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + assert!(start.elapsed() > Duration::from_millis(400)); + drop(listener); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn test_read_with_timeout() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = t!(listener.accept()).0; + t!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + t!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let start = Instant::now(); + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + assert!(start.elapsed() > Duration::from_millis(400)); + drop(listener); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let listener = t!(TcpListener::bind(&addr)); + let stream = t!(TcpStream::connect(&addr)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn nodelay() { + let addr = next_test_ip4(); + let _listener = t!(TcpListener::bind(&addr)); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + assert_eq!(false, t!(stream.nodelay())); + t!(stream.set_nodelay(true)); + assert_eq!(true, t!(stream.nodelay())); + t!(stream.set_nodelay(false)); + assert_eq!(false, t!(stream.nodelay())); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn ttl() { + let ttl = 100; + + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + t!(listener.set_ttl(ttl)); + assert_eq!(ttl, t!(listener.ttl())); + + let stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + t!(stream.set_ttl(ttl)); + assert_eq!(ttl, t!(stream.ttl())); +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] +fn set_nonblocking() { + let addr = next_test_ip4(); + let listener = t!(TcpListener::bind(&addr)); + + t!(listener.set_nonblocking(true)); + t!(listener.set_nonblocking(false)); + + let mut stream = t!(TcpStream::connect(&("localhost", addr.port()))); + + t!(stream.set_nonblocking(false)); + t!(stream.set_nonblocking(true)); + + let mut buf = [0]; + match stream.read(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn peek() { + each_ip(&mut |addr| { + let (txdone, rxdone) = channel(); + + let srv = t!(TcpListener::bind(&addr)); + let _t = thread::spawn(move || { + let mut cl = t!(srv.accept()).0; + cl.write(&[1, 3, 3, 7]).unwrap(); + t!(rxdone.recv()); + }); + + let mut c = t!(TcpStream::connect(&addr)); + let mut b = [0; 10]; + for _ in 1..3 { + let len = c.peek(&mut b).unwrap(); + assert_eq!(len, 4); + } + let len = c.read(&mut b).unwrap(); + assert_eq!(len, 4); + + t!(c.set_nonblocking(true)); + match c.peek(&mut b) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + t!(txdone.send(())); + }) +} + +#[test] +#[cfg_attr(target_env = "sgx", ignore)] // FIXME: https://github.com/fortanix/rust-sgx/issues/31 +fn connect_timeout_valid() { + let listener = TcpListener::bind("127.0.0.1:0").unwrap(); + let addr = listener.local_addr().unwrap(); + TcpStream::connect_timeout(&addr, Duration::from_secs(2)).unwrap(); +} diff --git a/library/std/src/net/udp.rs b/library/std/src/net/udp.rs index d730b2b87a..17e3e4497c 100644 --- a/library/std/src/net/udp.rs +++ b/library/std/src/net/udp.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +mod tests; + use crate::fmt; use crate::io::{self, Error, ErrorKind}; use crate::net::{Ipv4Addr, Ipv6Addr, SocketAddr, ToSocketAddrs}; @@ -798,380 +801,3 @@ impl fmt::Debug for UdpSocket { self.0.fmt(f) } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] -mod tests { - use crate::io::ErrorKind; - use crate::net::test::{next_test_ip4, next_test_ip6}; - use crate::net::*; - use crate::sync::mpsc::channel; - use crate::sys_common::AsInner; - use crate::thread; - use crate::time::{Duration, Instant}; - - fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { - f(next_test_ip4(), next_test_ip4()); - f(next_test_ip6(), next_test_ip6()); - } - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - }; - } - - #[test] - fn bind_error() { - match UdpSocket::bind("1.1.1.1:9999") { - Ok(..) => panic!(), - Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), - } - } - - #[test] - fn socket_smoke_test_ip4() { - each_ip(&mut |server_ip, client_ip| { - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - - let _t = thread::spawn(move || { - let client = t!(UdpSocket::bind(&client_ip)); - rx1.recv().unwrap(); - t!(client.send_to(&[99], &server_ip)); - tx2.send(()).unwrap(); - }); - - let server = t!(UdpSocket::bind(&server_ip)); - tx1.send(()).unwrap(); - let mut buf = [0]; - let (nread, src) = t!(server.recv_from(&mut buf)); - assert_eq!(nread, 1); - assert_eq!(buf[0], 99); - assert_eq!(src, client_ip); - rx2.recv().unwrap(); - }) - } - - #[test] - fn socket_name() { - each_ip(&mut |addr, _| { - let server = t!(UdpSocket::bind(&addr)); - assert_eq!(addr, t!(server.local_addr())); - }) - } - - #[test] - fn socket_peer() { - each_ip(&mut |addr1, addr2| { - let server = t!(UdpSocket::bind(&addr1)); - assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); - t!(server.connect(&addr2)); - assert_eq!(addr2, t!(server.peer_addr())); - }) - } - - #[test] - fn udp_clone_smoke() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - - let _t = thread::spawn(move || { - let mut buf = [0, 0]; - assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); - assert_eq!(buf[0], 1); - t!(sock2.send_to(&[2], &addr1)); - }); - - let sock3 = t!(sock1.try_clone()); - - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move || { - rx1.recv().unwrap(); - t!(sock3.send_to(&[1], &addr2)); - tx2.send(()).unwrap(); - }); - tx1.send(()).unwrap(); - let mut buf = [0, 0]; - assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); - rx2.recv().unwrap(); - }) - } - - #[test] - fn udp_clone_two_read() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - let (tx1, rx) = channel(); - let tx2 = tx1.clone(); - - let _t = thread::spawn(move || { - t!(sock2.send_to(&[1], &addr1)); - rx.recv().unwrap(); - t!(sock2.send_to(&[2], &addr1)); - rx.recv().unwrap(); - }); - - let sock3 = t!(sock1.try_clone()); - - let (done, rx) = channel(); - let _t = thread::spawn(move || { - let mut buf = [0, 0]; - t!(sock3.recv_from(&mut buf)); - tx2.send(()).unwrap(); - done.send(()).unwrap(); - }); - let mut buf = [0, 0]; - t!(sock1.recv_from(&mut buf)); - tx1.send(()).unwrap(); - - rx.recv().unwrap(); - }) - } - - #[test] - fn udp_clone_two_write() { - each_ip(&mut |addr1, addr2| { - let sock1 = t!(UdpSocket::bind(&addr1)); - let sock2 = t!(UdpSocket::bind(&addr2)); - - let (tx, rx) = channel(); - let (serv_tx, serv_rx) = channel(); - - let _t = thread::spawn(move || { - let mut buf = [0, 1]; - rx.recv().unwrap(); - t!(sock2.recv_from(&mut buf)); - serv_tx.send(()).unwrap(); - }); - - let sock3 = t!(sock1.try_clone()); - - let (done, rx) = channel(); - let tx2 = tx.clone(); - let _t = thread::spawn(move || { - match sock3.send_to(&[1], &addr2) { - Ok(..) => { - let _ = tx2.send(()); - } - Err(..) => {} - } - done.send(()).unwrap(); - }); - match sock1.send_to(&[2], &addr2) { - Ok(..) => { - let _ = tx.send(()); - } - Err(..) => {} - } - drop(tx); - - rx.recv().unwrap(); - serv_rx.recv().unwrap(); - }) - } - - #[test] - fn debug() { - let name = if cfg!(windows) { "socket" } else { "fd" }; - let socket_addr = next_test_ip4(); - - let udpsock = t!(UdpSocket::bind(&socket_addr)); - let udpsock_inner = udpsock.0.socket().as_inner(); - let compare = - format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); - assert_eq!(format!("{:?}", udpsock), compare); - } - - // FIXME: re-enabled openbsd/netbsd tests once their socket timeout code - // no longer has rounding errors. - // VxWorks ignores SO_SNDTIMEO. - #[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] - #[test] - fn timeouts() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.read_timeout())); - - assert_eq!(None, t!(stream.write_timeout())); - - t!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), t!(stream.write_timeout())); - - t!(stream.set_read_timeout(None)); - assert_eq!(None, t!(stream.read_timeout())); - - t!(stream.set_write_timeout(None)); - assert_eq!(None, t!(stream.write_timeout())); - } - - #[test] - fn test_read_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - - let start = Instant::now(); - loop { - let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); - if kind != ErrorKind::Interrupted { - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - break; - } - } - assert!(start.elapsed() > Duration::from_millis(400)); - } - - #[test] - fn test_read_with_timeout() { - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - t!(stream.send_to(b"hello world", &addr)); - - let mut buf = [0; 11]; - t!(stream.recv_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let start = Instant::now(); - loop { - let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); - if kind != ErrorKind::Interrupted { - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - break; - } - } - assert!(start.elapsed() > Duration::from_millis(400)); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_timeout_zero_duration() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); - - let result = socket.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = socket.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - } - - #[test] - fn connect_send_recv() { - let addr = next_test_ip4(); - - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.connect(addr)); - - t!(socket.send(b"hello world")); - - let mut buf = [0; 11]; - t!(socket.recv(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - } - - #[test] - fn connect_send_peek_recv() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.connect(addr)); - - t!(socket.send(b"hello world")); - - for _ in 1..3 { - let mut buf = [0; 11]; - let size = t!(socket.peek(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - } - - let mut buf = [0; 11]; - let size = t!(socket.recv(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - }) - } - - #[test] - fn peek_from() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - t!(socket.send_to(b"hello world", &addr)); - - for _ in 1..3 { - let mut buf = [0; 11]; - let (size, _) = t!(socket.peek_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - } - - let mut buf = [0; 11]; - let (size, _) = t!(socket.recv_from(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - assert_eq!(size, 11); - }) - } - - #[test] - fn ttl() { - let ttl = 100; - - let addr = next_test_ip4(); - - let stream = t!(UdpSocket::bind(&addr)); - - t!(stream.set_ttl(ttl)); - assert_eq!(ttl, t!(stream.ttl())); - } - - #[test] - fn set_nonblocking() { - each_ip(&mut |addr, _| { - let socket = t!(UdpSocket::bind(&addr)); - - t!(socket.set_nonblocking(true)); - t!(socket.set_nonblocking(false)); - - t!(socket.connect(addr)); - - t!(socket.set_nonblocking(false)); - t!(socket.set_nonblocking(true)); - - let mut buf = [0]; - match socket.recv(&mut buf) { - Ok(_) => panic!("expected error"), - Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} - Err(e) => panic!("unexpected error {}", e), - } - }) - } -} diff --git a/library/std/src/net/udp/tests.rs b/library/std/src/net/udp/tests.rs new file mode 100644 index 0000000000..658369f79a --- /dev/null +++ b/library/std/src/net/udp/tests.rs @@ -0,0 +1,372 @@ +use crate::io::ErrorKind; +use crate::net::test::{next_test_ip4, next_test_ip6}; +use crate::net::*; +use crate::sync::mpsc::channel; +use crate::sys_common::AsInner; +use crate::thread; +use crate::time::{Duration, Instant}; + +fn each_ip(f: &mut dyn FnMut(SocketAddr, SocketAddr)) { + f(next_test_ip4(), next_test_ip4()); + f(next_test_ip6(), next_test_ip6()); +} + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; +} + +#[test] +fn bind_error() { + match UdpSocket::bind("1.1.1.1:9999") { + Ok(..) => panic!(), + Err(e) => assert_eq!(e.kind(), ErrorKind::AddrNotAvailable), + } +} + +#[test] +fn socket_smoke_test_ip4() { + each_ip(&mut |server_ip, client_ip| { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + + let _t = thread::spawn(move || { + let client = t!(UdpSocket::bind(&client_ip)); + rx1.recv().unwrap(); + t!(client.send_to(&[99], &server_ip)); + tx2.send(()).unwrap(); + }); + + let server = t!(UdpSocket::bind(&server_ip)); + tx1.send(()).unwrap(); + let mut buf = [0]; + let (nread, src) = t!(server.recv_from(&mut buf)); + assert_eq!(nread, 1); + assert_eq!(buf[0], 99); + assert_eq!(src, client_ip); + rx2.recv().unwrap(); + }) +} + +#[test] +fn socket_name() { + each_ip(&mut |addr, _| { + let server = t!(UdpSocket::bind(&addr)); + assert_eq!(addr, t!(server.local_addr())); + }) +} + +#[test] +fn socket_peer() { + each_ip(&mut |addr1, addr2| { + let server = t!(UdpSocket::bind(&addr1)); + assert_eq!(server.peer_addr().unwrap_err().kind(), ErrorKind::NotConnected); + t!(server.connect(&addr2)); + assert_eq!(addr2, t!(server.peer_addr())); + }) +} + +#[test] +fn udp_clone_smoke() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let _t = thread::spawn(move || { + let mut buf = [0, 0]; + assert_eq!(sock2.recv_from(&mut buf).unwrap(), (1, addr1)); + assert_eq!(buf[0], 1); + t!(sock2.send_to(&[2], &addr1)); + }); + + let sock3 = t!(sock1.try_clone()); + + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + rx1.recv().unwrap(); + t!(sock3.send_to(&[1], &addr2)); + tx2.send(()).unwrap(); + }); + tx1.send(()).unwrap(); + let mut buf = [0, 0]; + assert_eq!(sock1.recv_from(&mut buf).unwrap(), (1, addr2)); + rx2.recv().unwrap(); + }) +} + +#[test] +fn udp_clone_two_read() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + let (tx1, rx) = channel(); + let tx2 = tx1.clone(); + + let _t = thread::spawn(move || { + t!(sock2.send_to(&[1], &addr1)); + rx.recv().unwrap(); + t!(sock2.send_to(&[2], &addr1)); + rx.recv().unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let _t = thread::spawn(move || { + let mut buf = [0, 0]; + t!(sock3.recv_from(&mut buf)); + tx2.send(()).unwrap(); + done.send(()).unwrap(); + }); + let mut buf = [0, 0]; + t!(sock1.recv_from(&mut buf)); + tx1.send(()).unwrap(); + + rx.recv().unwrap(); + }) +} + +#[test] +fn udp_clone_two_write() { + each_ip(&mut |addr1, addr2| { + let sock1 = t!(UdpSocket::bind(&addr1)); + let sock2 = t!(UdpSocket::bind(&addr2)); + + let (tx, rx) = channel(); + let (serv_tx, serv_rx) = channel(); + + let _t = thread::spawn(move || { + let mut buf = [0, 1]; + rx.recv().unwrap(); + t!(sock2.recv_from(&mut buf)); + serv_tx.send(()).unwrap(); + }); + + let sock3 = t!(sock1.try_clone()); + + let (done, rx) = channel(); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + match sock3.send_to(&[1], &addr2) { + Ok(..) => { + let _ = tx2.send(()); + } + Err(..) => {} + } + done.send(()).unwrap(); + }); + match sock1.send_to(&[2], &addr2) { + Ok(..) => { + let _ = tx.send(()); + } + Err(..) => {} + } + drop(tx); + + rx.recv().unwrap(); + serv_rx.recv().unwrap(); + }) +} + +#[test] +fn debug() { + let name = if cfg!(windows) { "socket" } else { "fd" }; + let socket_addr = next_test_ip4(); + + let udpsock = t!(UdpSocket::bind(&socket_addr)); + let udpsock_inner = udpsock.0.socket().as_inner(); + let compare = format!("UdpSocket {{ addr: {:?}, {}: {:?} }}", socket_addr, name, udpsock_inner); + assert_eq!(format!("{:?}", udpsock), compare); +} + +// FIXME: re-enabled openbsd/netbsd tests once their socket timeout code +// no longer has rounding errors. +// VxWorks ignores SO_SNDTIMEO. +#[cfg_attr(any(target_os = "netbsd", target_os = "openbsd", target_os = "vxworks"), ignore)] +#[test] +fn timeouts() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.read_timeout())); + + assert_eq!(None, t!(stream.write_timeout())); + + t!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), t!(stream.write_timeout())); + + t!(stream.set_read_timeout(None)); + assert_eq!(None, t!(stream.read_timeout())); + + t!(stream.set_write_timeout(None)); + assert_eq!(None, t!(stream.write_timeout())); +} + +#[test] +fn test_read_timeout() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + + let start = Instant::now(); + loop { + let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); + if kind != ErrorKind::Interrupted { + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + break; + } + } + assert!(start.elapsed() > Duration::from_millis(400)); +} + +#[test] +fn test_read_with_timeout() { + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + t!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + t!(stream.send_to(b"hello world", &addr)); + + let mut buf = [0; 11]; + t!(stream.recv_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let start = Instant::now(); + loop { + let kind = stream.recv_from(&mut buf).err().expect("expected error").kind(); + if kind != ErrorKind::Interrupted { + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); + break; + } + } + assert!(start.elapsed() > Duration::from_millis(400)); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_timeout_zero_duration() { + let addr = next_test_ip4(); + + let socket = t!(UdpSocket::bind(&addr)); + + let result = socket.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = socket.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); +} + +#[test] +fn connect_send_recv() { + let addr = next_test_ip4(); + + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.connect(addr)); + + t!(socket.send(b"hello world")); + + let mut buf = [0; 11]; + t!(socket.recv(&mut buf)); + assert_eq!(b"hello world", &buf[..]); +} + +#[test] +fn connect_send_peek_recv() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.connect(addr)); + + t!(socket.send(b"hello world")); + + for _ in 1..3 { + let mut buf = [0; 11]; + let size = t!(socket.peek(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let size = t!(socket.recv(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) +} + +#[test] +fn peek_from() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + t!(socket.send_to(b"hello world", &addr)); + + for _ in 1..3 { + let mut buf = [0; 11]; + let (size, _) = t!(socket.peek_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + } + + let mut buf = [0; 11]; + let (size, _) = t!(socket.recv_from(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + assert_eq!(size, 11); + }) +} + +#[test] +fn ttl() { + let ttl = 100; + + let addr = next_test_ip4(); + + let stream = t!(UdpSocket::bind(&addr)); + + t!(stream.set_ttl(ttl)); + assert_eq!(ttl, t!(stream.ttl())); +} + +#[test] +fn set_nonblocking() { + each_ip(&mut |addr, _| { + let socket = t!(UdpSocket::bind(&addr)); + + t!(socket.set_nonblocking(true)); + t!(socket.set_nonblocking(false)); + + t!(socket.connect(addr)); + + t!(socket.set_nonblocking(false)); + t!(socket.set_nonblocking(true)); + + let mut buf = [0]; + match socket.recv(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error {}", e), + } + }) +} diff --git a/library/std/src/num.rs b/library/std/src/num.rs index b496c16a74..0f1c596268 100644 --- a/library/std/src/num.rs +++ b/library/std/src/num.rs @@ -6,6 +6,12 @@ #![stable(feature = "rust1", since = "1.0.0")] #![allow(missing_docs)] +#[cfg(test)] +mod tests; + +#[cfg(test)] +mod benches; + #[stable(feature = "rust1", since = "1.0.0")] pub use core::num::Wrapping; #[stable(feature = "rust1", since = "1.0.0")] @@ -48,250 +54,3 @@ where assert_eq!(ten.div(two), ten / two); assert_eq!(ten.rem(two), ten % two); } - -#[cfg(test)] -mod tests { - use crate::ops::Mul; - - #[test] - fn test_saturating_add_uint() { - assert_eq!(3_usize.saturating_add(5_usize), 8_usize); - assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX); - assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX); - assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1); - } - - #[test] - fn test_saturating_sub_uint() { - assert_eq!(5_usize.saturating_sub(3_usize), 2_usize); - assert_eq!(3_usize.saturating_sub(5_usize), 0_usize); - assert_eq!(0_usize.saturating_sub(1_usize), 0_usize); - assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0); - } - - #[test] - fn test_saturating_add_int() { - assert_eq!(3i32.saturating_add(5), 8); - assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX); - assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX); - assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1); - assert_eq!(3i32.saturating_add(-5), -2); - assert_eq!(isize::MIN.saturating_add(-1), isize::MIN); - assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN); - } - - #[test] - fn test_saturating_sub_int() { - assert_eq!(3i32.saturating_sub(5), -2); - assert_eq!(isize::MIN.saturating_sub(1), isize::MIN); - assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN); - assert_eq!(3i32.saturating_sub(-5), 8); - assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX); - assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX); - assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1); - } - - #[test] - fn test_checked_add() { - let five_less = usize::MAX - 5; - assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5)); - assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4)); - assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3)); - assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2)); - assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1)); - assert_eq!(five_less.checked_add(5), Some(usize::MAX)); - assert_eq!(five_less.checked_add(6), None); - assert_eq!(five_less.checked_add(7), None); - } - - #[test] - fn test_checked_sub() { - assert_eq!(5_usize.checked_sub(0), Some(5)); - assert_eq!(5_usize.checked_sub(1), Some(4)); - assert_eq!(5_usize.checked_sub(2), Some(3)); - assert_eq!(5_usize.checked_sub(3), Some(2)); - assert_eq!(5_usize.checked_sub(4), Some(1)); - assert_eq!(5_usize.checked_sub(5), Some(0)); - assert_eq!(5_usize.checked_sub(6), None); - assert_eq!(5_usize.checked_sub(7), None); - } - - #[test] - fn test_checked_mul() { - let third = usize::MAX / 3; - assert_eq!(third.checked_mul(0), Some(0)); - assert_eq!(third.checked_mul(1), Some(third)); - assert_eq!(third.checked_mul(2), Some(third * 2)); - assert_eq!(third.checked_mul(3), Some(third * 3)); - assert_eq!(third.checked_mul(4), None); - } - - macro_rules! test_is_power_of_two { - ($test_name:ident, $T:ident) => { - fn $test_name() { - #![test] - assert_eq!((0 as $T).is_power_of_two(), false); - assert_eq!((1 as $T).is_power_of_two(), true); - assert_eq!((2 as $T).is_power_of_two(), true); - assert_eq!((3 as $T).is_power_of_two(), false); - assert_eq!((4 as $T).is_power_of_two(), true); - assert_eq!((5 as $T).is_power_of_two(), false); - assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true); - } - }; - } - - test_is_power_of_two! { test_is_power_of_two_u8, u8 } - test_is_power_of_two! { test_is_power_of_two_u16, u16 } - test_is_power_of_two! { test_is_power_of_two_u32, u32 } - test_is_power_of_two! { test_is_power_of_two_u64, u64 } - test_is_power_of_two! { test_is_power_of_two_uint, usize } - - macro_rules! test_next_power_of_two { - ($test_name:ident, $T:ident) => { - fn $test_name() { - #![test] - assert_eq!((0 as $T).next_power_of_two(), 1); - let mut next_power = 1; - for i in 1 as $T..40 { - assert_eq!(i.next_power_of_two(), next_power); - if i == next_power { - next_power *= 2 - } - } - } - }; - } - - test_next_power_of_two! { test_next_power_of_two_u8, u8 } - test_next_power_of_two! { test_next_power_of_two_u16, u16 } - test_next_power_of_two! { test_next_power_of_two_u32, u32 } - test_next_power_of_two! { test_next_power_of_two_u64, u64 } - test_next_power_of_two! { test_next_power_of_two_uint, usize } - - macro_rules! test_checked_next_power_of_two { - ($test_name:ident, $T:ident) => { - fn $test_name() { - #![test] - assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); - let smax = $T::MAX >> 1; - assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1)); - assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1)); - assert_eq!((smax + 2).checked_next_power_of_two(), None); - assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None); - assert_eq!($T::MAX.checked_next_power_of_two(), None); - let mut next_power = 1; - for i in 1 as $T..40 { - assert_eq!(i.checked_next_power_of_two(), Some(next_power)); - if i == next_power { - next_power *= 2 - } - } - } - }; - } - - test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 } - test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize } - - #[test] - fn test_pow() { - fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { - (0..exp).fold(one, |acc, _| acc * base) - } - macro_rules! assert_pow { - (($num:expr, $exp:expr) => $expected:expr) => {{ - let result = $num.pow($exp); - assert_eq!(result, $expected); - assert_eq!(result, naive_pow(1, $num, $exp)); - }}; - } - assert_pow!((3u32, 0 ) => 1); - assert_pow!((5u32, 1 ) => 5); - assert_pow!((-4i32, 2 ) => 16); - assert_pow!((8u32, 3 ) => 512); - assert_pow!((2u64, 50) => 1125899906842624); - } - - #[test] - fn test_uint_to_str_overflow() { - let mut u8_val: u8 = 255; - assert_eq!(u8_val.to_string(), "255"); - - u8_val = u8_val.wrapping_add(1); - assert_eq!(u8_val.to_string(), "0"); - - let mut u16_val: u16 = 65_535; - assert_eq!(u16_val.to_string(), "65535"); - - u16_val = u16_val.wrapping_add(1); - assert_eq!(u16_val.to_string(), "0"); - - let mut u32_val: u32 = 4_294_967_295; - assert_eq!(u32_val.to_string(), "4294967295"); - - u32_val = u32_val.wrapping_add(1); - assert_eq!(u32_val.to_string(), "0"); - - let mut u64_val: u64 = 18_446_744_073_709_551_615; - assert_eq!(u64_val.to_string(), "18446744073709551615"); - - u64_val = u64_val.wrapping_add(1); - assert_eq!(u64_val.to_string(), "0"); - } - - fn from_str(t: &str) -> Option { - crate::str::FromStr::from_str(t).ok() - } - - #[test] - fn test_uint_from_str_overflow() { - let mut u8_val: u8 = 255; - assert_eq!(from_str::("255"), Some(u8_val)); - assert_eq!(from_str::("256"), None); - - u8_val = u8_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u8_val)); - assert_eq!(from_str::("-1"), None); - - let mut u16_val: u16 = 65_535; - assert_eq!(from_str::("65535"), Some(u16_val)); - assert_eq!(from_str::("65536"), None); - - u16_val = u16_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u16_val)); - assert_eq!(from_str::("-1"), None); - - let mut u32_val: u32 = 4_294_967_295; - assert_eq!(from_str::("4294967295"), Some(u32_val)); - assert_eq!(from_str::("4294967296"), None); - - u32_val = u32_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u32_val)); - assert_eq!(from_str::("-1"), None); - - let mut u64_val: u64 = 18_446_744_073_709_551_615; - assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); - assert_eq!(from_str::("18446744073709551616"), None); - - u64_val = u64_val.wrapping_add(1); - assert_eq!(from_str::("0"), Some(u64_val)); - assert_eq!(from_str::("-1"), None); - } -} - -#[cfg(test)] -mod bench { - use test::Bencher; - - #[bench] - fn bench_pow_function(b: &mut Bencher) { - let v = (0..1024).collect::>(); - b.iter(|| { - v.iter().fold(0u32, |old, new| old.pow(*new as u32)); - }); - } -} diff --git a/library/std/src/num/benches.rs b/library/std/src/num/benches.rs new file mode 100644 index 0000000000..233ea0506c --- /dev/null +++ b/library/std/src/num/benches.rs @@ -0,0 +1,9 @@ +use test::Bencher; + +#[bench] +fn bench_pow_function(b: &mut Bencher) { + let v = (0..1024).collect::>(); + b.iter(|| { + v.iter().fold(0u32, |old, new| old.pow(*new as u32)); + }); +} diff --git a/library/std/src/num/tests.rs b/library/std/src/num/tests.rs new file mode 100644 index 0000000000..2f50b73f49 --- /dev/null +++ b/library/std/src/num/tests.rs @@ -0,0 +1,230 @@ +use crate::ops::Mul; + +#[test] +fn test_saturating_add_uint() { + assert_eq!(3_usize.saturating_add(5_usize), 8_usize); + assert_eq!(3_usize.saturating_add(usize::MAX - 1), usize::MAX); + assert_eq!(usize::MAX.saturating_add(usize::MAX), usize::MAX); + assert_eq!((usize::MAX - 2).saturating_add(1), usize::MAX - 1); +} + +#[test] +fn test_saturating_sub_uint() { + assert_eq!(5_usize.saturating_sub(3_usize), 2_usize); + assert_eq!(3_usize.saturating_sub(5_usize), 0_usize); + assert_eq!(0_usize.saturating_sub(1_usize), 0_usize); + assert_eq!((usize::MAX - 1).saturating_sub(usize::MAX), 0); +} + +#[test] +fn test_saturating_add_int() { + assert_eq!(3i32.saturating_add(5), 8); + assert_eq!(3isize.saturating_add(isize::MAX - 1), isize::MAX); + assert_eq!(isize::MAX.saturating_add(isize::MAX), isize::MAX); + assert_eq!((isize::MAX - 2).saturating_add(1), isize::MAX - 1); + assert_eq!(3i32.saturating_add(-5), -2); + assert_eq!(isize::MIN.saturating_add(-1), isize::MIN); + assert_eq!((-2isize).saturating_add(-isize::MAX), isize::MIN); +} + +#[test] +fn test_saturating_sub_int() { + assert_eq!(3i32.saturating_sub(5), -2); + assert_eq!(isize::MIN.saturating_sub(1), isize::MIN); + assert_eq!((-2isize).saturating_sub(isize::MAX), isize::MIN); + assert_eq!(3i32.saturating_sub(-5), 8); + assert_eq!(3isize.saturating_sub(-(isize::MAX - 1)), isize::MAX); + assert_eq!(isize::MAX.saturating_sub(-isize::MAX), isize::MAX); + assert_eq!((isize::MAX - 2).saturating_sub(-1), isize::MAX - 1); +} + +#[test] +fn test_checked_add() { + let five_less = usize::MAX - 5; + assert_eq!(five_less.checked_add(0), Some(usize::MAX - 5)); + assert_eq!(five_less.checked_add(1), Some(usize::MAX - 4)); + assert_eq!(five_less.checked_add(2), Some(usize::MAX - 3)); + assert_eq!(five_less.checked_add(3), Some(usize::MAX - 2)); + assert_eq!(five_less.checked_add(4), Some(usize::MAX - 1)); + assert_eq!(five_less.checked_add(5), Some(usize::MAX)); + assert_eq!(five_less.checked_add(6), None); + assert_eq!(five_less.checked_add(7), None); +} + +#[test] +fn test_checked_sub() { + assert_eq!(5_usize.checked_sub(0), Some(5)); + assert_eq!(5_usize.checked_sub(1), Some(4)); + assert_eq!(5_usize.checked_sub(2), Some(3)); + assert_eq!(5_usize.checked_sub(3), Some(2)); + assert_eq!(5_usize.checked_sub(4), Some(1)); + assert_eq!(5_usize.checked_sub(5), Some(0)); + assert_eq!(5_usize.checked_sub(6), None); + assert_eq!(5_usize.checked_sub(7), None); +} + +#[test] +fn test_checked_mul() { + let third = usize::MAX / 3; + assert_eq!(third.checked_mul(0), Some(0)); + assert_eq!(third.checked_mul(1), Some(third)); + assert_eq!(third.checked_mul(2), Some(third * 2)); + assert_eq!(third.checked_mul(3), Some(third * 3)); + assert_eq!(third.checked_mul(4), None); +} + +macro_rules! test_is_power_of_two { + ($test_name:ident, $T:ident) => { + fn $test_name() { + #![test] + assert_eq!((0 as $T).is_power_of_two(), false); + assert_eq!((1 as $T).is_power_of_two(), true); + assert_eq!((2 as $T).is_power_of_two(), true); + assert_eq!((3 as $T).is_power_of_two(), false); + assert_eq!((4 as $T).is_power_of_two(), true); + assert_eq!((5 as $T).is_power_of_two(), false); + assert_eq!(($T::MAX / 2 + 1).is_power_of_two(), true); + } + }; +} + +test_is_power_of_two! { test_is_power_of_two_u8, u8 } +test_is_power_of_two! { test_is_power_of_two_u16, u16 } +test_is_power_of_two! { test_is_power_of_two_u32, u32 } +test_is_power_of_two! { test_is_power_of_two_u64, u64 } +test_is_power_of_two! { test_is_power_of_two_uint, usize } + +macro_rules! test_next_power_of_two { + ($test_name:ident, $T:ident) => { + fn $test_name() { + #![test] + assert_eq!((0 as $T).next_power_of_two(), 1); + let mut next_power = 1; + for i in 1 as $T..40 { + assert_eq!(i.next_power_of_two(), next_power); + if i == next_power { + next_power *= 2 + } + } + } + }; +} + +test_next_power_of_two! { test_next_power_of_two_u8, u8 } +test_next_power_of_two! { test_next_power_of_two_u16, u16 } +test_next_power_of_two! { test_next_power_of_two_u32, u32 } +test_next_power_of_two! { test_next_power_of_two_u64, u64 } +test_next_power_of_two! { test_next_power_of_two_uint, usize } + +macro_rules! test_checked_next_power_of_two { + ($test_name:ident, $T:ident) => { + fn $test_name() { + #![test] + assert_eq!((0 as $T).checked_next_power_of_two(), Some(1)); + let smax = $T::MAX >> 1; + assert_eq!(smax.checked_next_power_of_two(), Some(smax + 1)); + assert_eq!((smax + 1).checked_next_power_of_two(), Some(smax + 1)); + assert_eq!((smax + 2).checked_next_power_of_two(), None); + assert_eq!(($T::MAX - 1).checked_next_power_of_two(), None); + assert_eq!($T::MAX.checked_next_power_of_two(), None); + let mut next_power = 1; + for i in 1 as $T..40 { + assert_eq!(i.checked_next_power_of_two(), Some(next_power)); + if i == next_power { + next_power *= 2 + } + } + } + }; +} + +test_checked_next_power_of_two! { test_checked_next_power_of_two_u8, u8 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_u16, u16 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_u32, u32 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_u64, u64 } +test_checked_next_power_of_two! { test_checked_next_power_of_two_uint, usize } + +#[test] +fn test_pow() { + fn naive_pow + Copy>(one: T, base: T, exp: usize) -> T { + (0..exp).fold(one, |acc, _| acc * base) + } + macro_rules! assert_pow { + (($num:expr, $exp:expr) => $expected:expr) => {{ + let result = $num.pow($exp); + assert_eq!(result, $expected); + assert_eq!(result, naive_pow(1, $num, $exp)); + }}; + } + assert_pow!((3u32, 0 ) => 1); + assert_pow!((5u32, 1 ) => 5); + assert_pow!((-4i32, 2 ) => 16); + assert_pow!((8u32, 3 ) => 512); + assert_pow!((2u64, 50) => 1125899906842624); +} + +#[test] +fn test_uint_to_str_overflow() { + let mut u8_val: u8 = 255; + assert_eq!(u8_val.to_string(), "255"); + + u8_val = u8_val.wrapping_add(1); + assert_eq!(u8_val.to_string(), "0"); + + let mut u16_val: u16 = 65_535; + assert_eq!(u16_val.to_string(), "65535"); + + u16_val = u16_val.wrapping_add(1); + assert_eq!(u16_val.to_string(), "0"); + + let mut u32_val: u32 = 4_294_967_295; + assert_eq!(u32_val.to_string(), "4294967295"); + + u32_val = u32_val.wrapping_add(1); + assert_eq!(u32_val.to_string(), "0"); + + let mut u64_val: u64 = 18_446_744_073_709_551_615; + assert_eq!(u64_val.to_string(), "18446744073709551615"); + + u64_val = u64_val.wrapping_add(1); + assert_eq!(u64_val.to_string(), "0"); +} + +fn from_str(t: &str) -> Option { + crate::str::FromStr::from_str(t).ok() +} + +#[test] +fn test_uint_from_str_overflow() { + let mut u8_val: u8 = 255; + assert_eq!(from_str::("255"), Some(u8_val)); + assert_eq!(from_str::("256"), None); + + u8_val = u8_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u8_val)); + assert_eq!(from_str::("-1"), None); + + let mut u16_val: u16 = 65_535; + assert_eq!(from_str::("65535"), Some(u16_val)); + assert_eq!(from_str::("65536"), None); + + u16_val = u16_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u16_val)); + assert_eq!(from_str::("-1"), None); + + let mut u32_val: u32 = 4_294_967_295; + assert_eq!(from_str::("4294967295"), Some(u32_val)); + assert_eq!(from_str::("4294967296"), None); + + u32_val = u32_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u32_val)); + assert_eq!(from_str::("-1"), None); + + let mut u64_val: u64 = 18_446_744_073_709_551_615; + assert_eq!(from_str::("18446744073709551615"), Some(u64_val)); + assert_eq!(from_str::("18446744073709551616"), None); + + u64_val = u64_val.wrapping_add(1); + assert_eq!(from_str::("0"), Some(u64_val)); + assert_eq!(from_str::("-1"), None); +} diff --git a/library/std/src/os/linux/fs.rs b/library/std/src/os/linux/fs.rs index cae65f1218..ff23c3d67e 100644 --- a/library/std/src/os/linux/fs.rs +++ b/library/std/src/os/linux/fs.rs @@ -1,3 +1,5 @@ +//! Linux-specific extensions to primitives in the `std::fs` module. + #![stable(feature = "metadata_ext", since = "1.1.0")] use crate::fs::Metadata; @@ -196,7 +198,7 @@ pub trait MetadataExt { fn st_atime(&self) -> i64; /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. /// - /// [`st_atime`]: #tymethod.st_atime + /// [`st_atime`]: Self::st_atime /// /// # Examples /// @@ -232,7 +234,7 @@ pub trait MetadataExt { fn st_mtime(&self) -> i64; /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. /// - /// [`st_mtime`]: #tymethod.st_mtime + /// [`st_mtime`]: Self::st_mtime /// /// # Examples /// @@ -268,7 +270,7 @@ pub trait MetadataExt { fn st_ctime(&self) -> i64; /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. /// - /// [`st_ctime`]: #tymethod.st_ctime + /// [`st_ctime`]: Self::st_ctime /// /// # Examples /// diff --git a/library/std/src/os/linux/mod.rs b/library/std/src/os/linux/mod.rs index d35307162c..f179a52433 100644 --- a/library/std/src/os/linux/mod.rs +++ b/library/std/src/os/linux/mod.rs @@ -1,4 +1,4 @@ -//! Linux-specific definitions +//! Linux-specific definitions. #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/library/std/src/os/linux/raw.rs b/library/std/src/os/linux/raw.rs index eb8589eb58..617c4098aa 100644 --- a/library/std/src/os/linux/raw.rs +++ b/library/std/src/os/linux/raw.rs @@ -1,4 +1,4 @@ -//! Linux-specific raw type definitions +//! Linux-specific raw type definitions. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( @@ -29,6 +29,7 @@ pub use self::arch::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; target_arch = "x86", target_arch = "le32", target_arch = "powerpc", + target_arch = "sparc", target_arch = "arm", target_arch = "asmjs", target_arch = "wasm32" @@ -170,63 +171,63 @@ mod arch { #[cfg(target_arch = "hexagon")] mod arch { - use crate::os::raw::{c_int, c_long, c_longlong, c_ulonglong}; + use crate::os::raw::{c_int, c_long, c_uint}; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type blkcnt_t = c_longlong; + pub type blkcnt_t = i64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type blksize_t = c_long; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type ino_t = c_ulonglong; + pub type ino_t = u64; #[stable(feature = "raw_ext", since = "1.1.0")] pub type nlink_t = c_uint; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type off_t = c_longlong; + pub type off_t = i64; #[stable(feature = "raw_ext", since = "1.1.0")] - pub type time_t = c_long; + pub type time_t = i64; #[repr(C)] #[derive(Clone)] #[stable(feature = "raw_ext", since = "1.1.0")] pub struct stat { #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_dev: ::dev_t, + pub st_dev: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ino: ::c_ulonglong, + pub st_ino: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mode: ::c_uint, + pub st_mode: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_nlink: ::c_uint, + pub st_nlink: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_uid: ::c_uint, + pub st_uid: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_gid: ::c_uint, + pub st_gid: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_rdev: ::c_ulonglong, + pub st_rdev: u64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad1: ::c_ulong, + pub __pad1: u32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_size: ::c_longlong, + pub st_size: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blksize: ::blksize_t, + pub st_blksize: i32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad2: ::c_int, + pub __pad2: i32, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_blocks: ::blkcnt_t, + pub st_blocks: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime: ::time_t, + pub st_atime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_atime_nsec: ::c_long, + pub st_atime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime: ::time_t, + pub st_mtime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_mtime_nsec: ::c_long, + pub st_mtime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime: ::time_t, + pub st_ctime: i64, #[stable(feature = "raw_ext", since = "1.1.0")] - pub st_ctime_nsec: ::c_long, + pub st_ctime_nsec: c_long, #[stable(feature = "raw_ext", since = "1.1.0")] - pub __pad3: [::c_int; 2], + pub __pad3: [c_int; 2], } } @@ -234,7 +235,8 @@ mod arch { target_arch = "mips64", target_arch = "s390x", target_arch = "sparc64", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ))] mod arch { pub use libc::{blkcnt_t, blksize_t, ino_t, nlink_t, off_t, stat, time_t}; diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index 47daf0cce1..16272aa057 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -8,6 +8,9 @@ #![stable(feature = "raw_os", since = "1.1.0")] +#[cfg(test)] +mod tests; + #[doc(include = "char.md")] #[cfg(any( all( @@ -19,7 +22,8 @@ target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ) ), all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), @@ -62,7 +66,8 @@ pub type c_char = u8; target_arch = "powerpc", target_arch = "powerpc64", target_arch = "s390x", - target_arch = "riscv64" + target_arch = "riscv64", + target_arch = "riscv32" ) ), all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), @@ -144,24 +149,3 @@ pub type c_double = f64; #[stable(feature = "raw_os", since = "1.1.0")] #[doc(no_inline)] pub use core::ffi::c_void; - -#[cfg(test)] -#[allow(unused_imports)] -mod tests { - use crate::any::TypeId; - use crate::mem; - - macro_rules! ok { - ($($t:ident)*) => {$( - assert!(TypeId::of::() == TypeId::of::(), - "{} is wrong", stringify!($t)); - )*} - } - - #[test] - fn same() { - use crate::os::raw; - ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong - c_longlong c_ulonglong c_float c_double); - } -} diff --git a/library/std/src/os/raw/tests.rs b/library/std/src/os/raw/tests.rs new file mode 100644 index 0000000000..e7bb7d7e73 --- /dev/null +++ b/library/std/src/os/raw/tests.rs @@ -0,0 +1,15 @@ +use crate::any::TypeId; + +macro_rules! ok { + ($($t:ident)*) => {$( + assert!(TypeId::of::() == TypeId::of::(), + "{} is wrong", stringify!($t)); + )*} +} + +#[test] +fn same() { + use crate::os::raw; + ok!(c_char c_schar c_uchar c_short c_ushort c_int c_uint c_long c_ulong + c_longlong c_ulonglong c_float c_double); +} diff --git a/library/std/src/os/redox/fs.rs b/library/std/src/os/redox/fs.rs index 94d65651da..0f179c8b83 100644 --- a/library/std/src/os/redox/fs.rs +++ b/library/std/src/os/redox/fs.rs @@ -200,7 +200,7 @@ pub trait MetadataExt { fn st_atime(&self) -> i64; /// Returns the last access time of the file, in nanoseconds since [`st_atime`]. /// - /// [`st_atime`]: #tymethod.st_atime + /// [`st_atime`]: Self::st_atime /// /// # Examples /// @@ -236,7 +236,7 @@ pub trait MetadataExt { fn st_mtime(&self) -> i64; /// Returns the last modification time of the file, in nanoseconds since [`st_mtime`]. /// - /// [`st_mtime`]: #tymethod.st_mtime + /// [`st_mtime`]: Self::st_mtime /// /// # Examples /// @@ -272,7 +272,7 @@ pub trait MetadataExt { fn st_ctime(&self) -> i64; /// Returns the last status change time of the file, in nanoseconds since [`st_ctime`]. /// - /// [`st_ctime`]: #tymethod.st_ctime + /// [`st_ctime`]: Self::st_ctime /// /// # Examples /// diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index 8fcb24033b..4281867314 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -232,16 +232,16 @@ impl RefUnwindSafe for RwLock {} #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicIsize {} #[cfg(target_has_atomic_load_store = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI8 {} #[cfg(target_has_atomic_load_store = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI16 {} #[cfg(target_has_atomic_load_store = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI32 {} #[cfg(target_has_atomic_load_store = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicI64 {} #[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] @@ -251,16 +251,16 @@ impl RefUnwindSafe for atomic::AtomicI128 {} #[stable(feature = "unwind_safe_atomic_refs", since = "1.14.0")] impl RefUnwindSafe for atomic::AtomicUsize {} #[cfg(target_has_atomic_load_store = "8")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU8 {} #[cfg(target_has_atomic_load_store = "16")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU16 {} #[cfg(target_has_atomic_load_store = "32")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU32 {} #[cfg(target_has_atomic_load_store = "64")] -#[unstable(feature = "integer_atomics", issue = "32976")] +#[stable(feature = "integer_atomics_stable", since = "1.34.0")] impl RefUnwindSafe for atomic::AtomicU64 {} #[cfg(target_has_atomic_load_store = "128")] #[unstable(feature = "integer_atomics", issue = "32976")] @@ -359,6 +359,9 @@ impl Future for AssertUnwindSafe { /// aborting the process as well. This function *only* catches unwinding panics, /// not those that abort the process. /// +/// Also note that unwinding into Rust code with a foreign exception (e.g. a +/// an exception thrown from C++ code) is undefined behavior. +/// /// # Examples /// /// ``` @@ -408,3 +411,6 @@ pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { pub fn resume_unwind(payload: Box) -> ! { panicking::rust_panic_without_hook(payload) } + +#[cfg(test)] +mod tests; diff --git a/src/test/ui/panics/panic-safe.rs b/library/std/src/panic/tests.rs similarity index 77% rename from src/test/ui/panics/panic-safe.rs rename to library/std/src/panic/tests.rs index 9867cc5640..b37d74011c 100644 --- a/src/test/ui/panics/panic-safe.rs +++ b/library/std/src/panic/tests.rs @@ -1,16 +1,18 @@ -// run-pass #![allow(dead_code)] -use std::panic::{UnwindSafe, AssertUnwindSafe}; -use std::cell::RefCell; -use std::sync::{Mutex, RwLock, Arc}; -use std::rc::Rc; +use crate::cell::RefCell; +use crate::panic::{AssertUnwindSafe, UnwindSafe}; +use crate::rc::Rc; +use crate::sync::{Arc, Mutex, RwLock}; -struct Foo { a: i32 } +struct Foo { + a: i32, +} fn assert() {} -fn main() { +#[test] +fn panic_safety_traits() { assert::(); assert::<&i32>(); assert::<*mut i32>(); @@ -32,13 +34,16 @@ fn main() { assert::>(); assert::>(); - trait Trait: UnwindSafe {} - assert::>(); + { + trait Trait: UnwindSafe {} + assert::>(); + } fn bar() { assert::>(); assert::>(); } + fn baz() { assert::>(); assert::>(); diff --git a/library/std/src/panicking.rs b/library/std/src/panicking.rs index 08d363a9a2..8dceb12de8 100644 --- a/library/std/src/panicking.rs +++ b/library/std/src/panicking.rs @@ -60,6 +60,14 @@ extern "C" fn __rust_drop_panic() -> ! { rtabort!("Rust panics must be rethrown"); } +/// This function is called by the panic runtime if it catches an exception +/// object which does not correspond to a Rust panic. +#[cfg(not(test))] +#[rustc_std_internal_symbol] +extern "C" fn __rust_foreign_exception() -> ! { + rtabort!("Rust cannot catch foreign exceptions"); +} + #[derive(Copy, Clone)] enum Hook { Default, diff --git a/library/std/src/path.rs b/library/std/src/path.rs index afdbdbeac3..6fa73042a3 100644 --- a/library/std/src/path.rs +++ b/library/std/src/path.rs @@ -1,5 +1,3 @@ -// ignore-tidy-filelength - //! Cross-platform path manipulation. //! //! This module provides two types, [`PathBuf`] and [`Path`] (akin to [`String`] @@ -60,6 +58,10 @@ //! [`push`]: PathBuf::push #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(test)] +mod tests; use crate::borrow::{Borrow, Cow}; use crate::cmp; @@ -293,7 +295,8 @@ fn os_str_as_u8_slice(s: &OsStr) -> &[u8] { unsafe { &*(s as *const OsStr as *const [u8]) } } unsafe fn u8_slice_as_os_str(s: &[u8]) -> &OsStr { - &*(s as *const [u8] as *const OsStr) + // SAFETY: see the comment of `os_str_as_u8_slice` + unsafe { &*(s as *const [u8] as *const OsStr) } } // Detect scheme on Redox @@ -313,24 +316,21 @@ fn has_physical_root(s: &[u8], prefix: Option>) -> bool { // basic workhorse for splitting stem and extension fn split_file_at_dot(file: &OsStr) -> (Option<&OsStr>, Option<&OsStr>) { - unsafe { - if os_str_as_u8_slice(file) == b".." { - return (Some(file), None); - } + if os_str_as_u8_slice(file) == b".." { + return (Some(file), None); + } - // The unsafety here stems from converting between &OsStr and &[u8] - // and back. This is safe to do because (1) we only look at ASCII - // contents of the encoding and (2) new &OsStr values are produced - // only from ASCII-bounded slices of existing &OsStr values. - - let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); - let after = iter.next(); - let before = iter.next(); - if before == Some(b"") { - (Some(file), None) - } else { - (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) - } + // The unsafety here stems from converting between &OsStr and &[u8] + // and back. This is safe to do because (1) we only look at ASCII + // contents of the encoding and (2) new &OsStr values are produced + // only from ASCII-bounded slices of existing &OsStr values. + let mut iter = os_str_as_u8_slice(file).rsplitn(2, |b| *b == b'.'); + let after = iter.next(); + let before = iter.next(); + if before == Some(b"") { + (Some(file), None) + } else { + unsafe { (before.map(|s| u8_slice_as_os_str(s)), after.map(|s| u8_slice_as_os_str(s))) } } } @@ -1701,7 +1701,7 @@ impl Path { // The following (private!) function allows construction of a path from a u8 // slice, which is only safe when it is known to follow the OsStr encoding. unsafe fn from_u8_slice(s: &[u8]) -> &Path { - Path::new(u8_slice_as_os_str(s)) + unsafe { Path::new(u8_slice_as_os_str(s)) } } // The following (private!) function reveals the byte encoding used for OsStr. fn as_u8_slice(&self) -> &[u8] { @@ -1838,7 +1838,7 @@ impl Path { // FIXME: Allow Redox prefixes self.has_root() || has_redox_scheme(self.as_u8_slice()) } else { - self.has_root() && (cfg!(unix) || self.prefix().is_some()) + self.has_root() && (cfg!(any(unix, target_os = "wasi")) || self.prefix().is_some()) } } @@ -2741,1401 +2741,3 @@ impl Error for StripPrefixError { "prefix not found" } } - -#[cfg(test)] -mod tests { - use super::*; - - use crate::rc::Rc; - use crate::sync::Arc; - - macro_rules! t( - ($path:expr, iter: $iter:expr) => ( - { - let path = Path::new($path); - - // Forward iteration - let comps = path.iter() - .map(|p| p.to_string_lossy().into_owned()) - .collect::>(); - let exp: &[&str] = &$iter; - let exps = exp.iter().map(|s| s.to_string()).collect::>(); - assert!(comps == exps, "iter: Expected {:?}, found {:?}", - exps, comps); - - // Reverse iteration - let comps = Path::new($path).iter().rev() - .map(|p| p.to_string_lossy().into_owned()) - .collect::>(); - let exps = exps.into_iter().rev().collect::>(); - assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}", - exps, comps); - } - ); - - ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => ( - { - let path = Path::new($path); - - let act_root = path.has_root(); - assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}", - $has_root, act_root); - - let act_abs = path.is_absolute(); - assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}", - $is_absolute, act_abs); - } - ); - - ($path:expr, parent: $parent:expr, file_name: $file:expr) => ( - { - let path = Path::new($path); - - let parent = path.parent().map(|p| p.to_str().unwrap()); - let exp_parent: Option<&str> = $parent; - assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}", - exp_parent, parent); - - let file = path.file_name().map(|p| p.to_str().unwrap()); - let exp_file: Option<&str> = $file; - assert!(file == exp_file, "file_name: Expected {:?}, found {:?}", - exp_file, file); - } - ); - - ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => ( - { - let path = Path::new($path); - - let stem = path.file_stem().map(|p| p.to_str().unwrap()); - let exp_stem: Option<&str> = $file_stem; - assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}", - exp_stem, stem); - - let ext = path.extension().map(|p| p.to_str().unwrap()); - let exp_ext: Option<&str> = $extension; - assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}", - exp_ext, ext); - } - ); - - ($path:expr, iter: $iter:expr, - has_root: $has_root:expr, is_absolute: $is_absolute:expr, - parent: $parent:expr, file_name: $file:expr, - file_stem: $file_stem:expr, extension: $extension:expr) => ( - { - t!($path, iter: $iter); - t!($path, has_root: $has_root, is_absolute: $is_absolute); - t!($path, parent: $parent, file_name: $file); - t!($path, file_stem: $file_stem, extension: $extension); - } - ); - ); - - #[test] - fn into() { - use crate::borrow::Cow; - - let static_path = Path::new("/home/foo"); - let static_cow_path: Cow<'static, Path> = static_path.into(); - let pathbuf = PathBuf::from("/home/foo"); - - { - let path: &Path = &pathbuf; - let borrowed_cow_path: Cow<'_, Path> = path.into(); - - assert_eq!(static_cow_path, borrowed_cow_path); - } - - let owned_cow_path: Cow<'static, Path> = pathbuf.into(); - - assert_eq!(static_cow_path, owned_cow_path); - } - - #[test] - #[cfg(unix)] - pub fn test_decompositions_unix() { - t!("", - iter: [], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/", - iter: ["/"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("/foo", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/foo/", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("/foo/bar", - iter: ["/", "foo", "bar"], - has_root: true, - is_absolute: true, - parent: Some("/foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("///foo///", - iter: ["/", "foo"], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("///foo///bar", - iter: ["/", "foo", "bar"], - has_root: true, - is_absolute: true, - parent: Some("///foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("/..", - iter: ["/", ".."], - has_root: true, - is_absolute: true, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/./bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/../bar", - iter: ["foo", "..", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo/.."), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("a/b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a//b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/./b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/b/c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a/b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None - ); - - t!(".foo", - iter: [".foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some(".foo"), - file_stem: Some(".foo"), - extension: None - ); - } - - #[test] - #[cfg(windows)] - pub fn test_decompositions_windows() { - t!("", - iter: [], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\", - iter: ["\\"], - has_root: true, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:", - iter: ["c:"], - has_root: false, - is_absolute: false, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:\\", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("c:/", - iter: ["c:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("/foo", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("/foo/", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("/foo/bar", - iter: ["\\", "foo", "bar"], - has_root: true, - is_absolute: false, - parent: Some("/foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("///foo///", - iter: ["\\", "foo"], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("///foo///bar", - iter: ["\\", "foo", "bar"], - has_root: true, - is_absolute: false, - parent: Some("///foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./.", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("/..", - iter: ["\\", ".."], - has_root: true, - is_absolute: false, - parent: Some("/"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("../", - iter: [".."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/.", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/..", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/./", - iter: ["foo"], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: Some("foo"), - file_stem: Some("foo"), - extension: None - ); - - t!("foo/./bar", - iter: ["foo", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("foo/../", - iter: ["foo", ".."], - has_root: false, - is_absolute: false, - parent: Some("foo"), - file_name: None, - file_stem: None, - extension: None - ); - - t!("foo/../bar", - iter: ["foo", "..", "bar"], - has_root: false, - is_absolute: false, - parent: Some("foo/.."), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("./a", - iter: [".", "a"], - has_root: false, - is_absolute: false, - parent: Some("."), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!(".", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("./", - iter: ["."], - has_root: false, - is_absolute: false, - parent: Some(""), - file_name: None, - file_stem: None, - extension: None - ); - - t!("a/b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a//b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/./b", - iter: ["a", "b"], - has_root: false, - is_absolute: false, - parent: Some("a"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - - t!("a/b/c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a/b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None); - - t!("a\\b\\c", - iter: ["a", "b", "c"], - has_root: false, - is_absolute: false, - parent: Some("a\\b"), - file_name: Some("c"), - file_stem: Some("c"), - extension: None - ); - - t!("\\a", - iter: ["\\", "a"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("a"), - file_stem: Some("a"), - extension: None - ); - - t!("c:\\foo.txt", - iter: ["c:", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("c:\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\server\\share\\foo.txt", - iter: ["\\\\server\\share", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\server\\share\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\server\\share", - iter: ["\\\\server\\share", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\server", - iter: ["\\", "server"], - has_root: true, - is_absolute: false, - parent: Some("\\"), - file_name: Some("server"), - file_stem: Some("server"), - extension: None - ); - - t!("\\\\?\\bar\\foo.txt", - iter: ["\\\\?\\bar", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\bar\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\bar", - iter: ["\\\\?\\bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\", - iter: ["\\\\?\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\UNC\\server\\share\\foo.txt", - iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\UNC\\server\\share\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\UNC\\server", - iter: ["\\\\?\\UNC\\server"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\UNC\\", - iter: ["\\\\?\\UNC\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\C:\\foo.txt", - iter: ["\\\\?\\C:", "\\", "foo.txt"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\C:\\"), - file_name: Some("foo.txt"), - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("\\\\?\\C:\\", - iter: ["\\\\?\\C:", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\C:", - iter: ["\\\\?\\C:"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\foo/bar", - iter: ["\\\\?\\foo/bar"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\C:/foo", - iter: ["\\\\?\\C:/foo"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\.\\foo\\bar", - iter: ["\\\\.\\foo", "\\", "bar"], - has_root: true, - is_absolute: true, - parent: Some("\\\\.\\foo\\"), - file_name: Some("bar"), - file_stem: Some("bar"), - extension: None - ); - - t!("\\\\.\\foo", - iter: ["\\\\.\\foo", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\.\\foo/bar", - iter: ["\\\\.\\foo/bar", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\.\\foo\\bar/baz", - iter: ["\\\\.\\foo", "\\", "bar", "baz"], - has_root: true, - is_absolute: true, - parent: Some("\\\\.\\foo\\bar"), - file_name: Some("baz"), - file_stem: Some("baz"), - extension: None - ); - - t!("\\\\.\\", - iter: ["\\\\.\\", "\\"], - has_root: true, - is_absolute: true, - parent: None, - file_name: None, - file_stem: None, - extension: None - ); - - t!("\\\\?\\a\\b\\", - iter: ["\\\\?\\a", "\\", "b"], - has_root: true, - is_absolute: true, - parent: Some("\\\\?\\a\\"), - file_name: Some("b"), - file_stem: Some("b"), - extension: None - ); - } - - #[test] - pub fn test_stem_ext() { - t!("foo", - file_stem: Some("foo"), - extension: None - ); - - t!("foo.", - file_stem: Some("foo"), - extension: Some("") - ); - - t!(".foo", - file_stem: Some(".foo"), - extension: None - ); - - t!("foo.txt", - file_stem: Some("foo"), - extension: Some("txt") - ); - - t!("foo.bar.txt", - file_stem: Some("foo.bar"), - extension: Some("txt") - ); - - t!("foo.bar.", - file_stem: Some("foo.bar"), - extension: Some("") - ); - - t!(".", file_stem: None, extension: None); - - t!("..", file_stem: None, extension: None); - - t!("", file_stem: None, extension: None); - } - - #[test] - pub fn test_push() { - macro_rules! tp( - ($path:expr, $push:expr, $expected:expr) => ( { - let mut actual = PathBuf::from($path); - actual.push($push); - assert!(actual.to_str() == Some($expected), - "pushing {:?} onto {:?}: Expected {:?}, got {:?}", - $push, $path, $expected, actual.to_str().unwrap()); - }); - ); - - if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { - tp!("", "foo", "foo"); - tp!("foo", "bar", "foo/bar"); - tp!("foo/", "bar", "foo/bar"); - tp!("foo//", "bar", "foo//bar"); - tp!("foo/.", "bar", "foo/./bar"); - tp!("foo./.", "bar", "foo././bar"); - tp!("foo", "", "foo/"); - tp!("foo", ".", "foo/."); - tp!("foo", "..", "foo/.."); - tp!("foo", "/", "/"); - tp!("/foo/bar", "/", "/"); - tp!("/foo/bar", "/baz", "/baz"); - tp!("/foo/bar", "./baz", "/foo/bar/./baz"); - } else { - tp!("", "foo", "foo"); - tp!("foo", "bar", r"foo\bar"); - tp!("foo/", "bar", r"foo/bar"); - tp!(r"foo\", "bar", r"foo\bar"); - tp!("foo//", "bar", r"foo//bar"); - tp!(r"foo\\", "bar", r"foo\\bar"); - tp!("foo/.", "bar", r"foo/.\bar"); - tp!("foo./.", "bar", r"foo./.\bar"); - tp!(r"foo\.", "bar", r"foo\.\bar"); - tp!(r"foo.\.", "bar", r"foo.\.\bar"); - tp!("foo", "", "foo\\"); - tp!("foo", ".", r"foo\."); - tp!("foo", "..", r"foo\.."); - tp!("foo", "/", "/"); - tp!("foo", r"\", r"\"); - tp!("/foo/bar", "/", "/"); - tp!(r"\foo\bar", r"\", r"\"); - tp!("/foo/bar", "/baz", "/baz"); - tp!("/foo/bar", r"\baz", r"\baz"); - tp!("/foo/bar", "./baz", r"/foo/bar\./baz"); - tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz"); - - tp!("c:\\", "windows", "c:\\windows"); - tp!("c:", "windows", "c:windows"); - - tp!("a\\b\\c", "d", "a\\b\\c\\d"); - tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d"); - tp!("a\\b", "c\\d", "a\\b\\c\\d"); - tp!("a\\b", "\\c\\d", "\\c\\d"); - tp!("a\\b", ".", "a\\b\\."); - tp!("a\\b", "..\\c", "a\\b\\..\\c"); - tp!("a\\b", "C:a.txt", "C:a.txt"); - tp!("a\\b", "C:\\a.txt", "C:\\a.txt"); - tp!("C:\\a", "C:\\b.txt", "C:\\b.txt"); - tp!("C:\\a\\b\\c", "C:d", "C:d"); - tp!("C:a\\b\\c", "C:d", "C:d"); - tp!("C:", r"a\b\c", r"C:a\b\c"); - tp!("C:", r"..\a", r"C:..\a"); - tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar"); - tp!("\\\\server\\share\\foo", "C:baz", "C:baz"); - tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d"); - tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); - tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); - tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); - tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar"); - tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); - tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a"); - - // Note: modified from old path API - tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo"); - - tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share"); - tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); - tp!("\\\\.\\foo\\bar", "C:a", "C:a"); - // again, not sure about the following, but I'm assuming \\.\ should be verbatim - tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); - - tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one - } - } - - #[test] - pub fn test_pop() { - macro_rules! tp( - ($path:expr, $expected:expr, $output:expr) => ( { - let mut actual = PathBuf::from($path); - let output = actual.pop(); - assert!(actual.to_str() == Some($expected) && output == $output, - "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}", - $path, $expected, $output, - actual.to_str().unwrap(), output); - }); - ); - - tp!("", "", false); - tp!("/", "/", false); - tp!("foo", "", true); - tp!(".", "", true); - tp!("/foo", "/", true); - tp!("/foo/bar", "/foo", true); - tp!("foo/bar", "foo", true); - tp!("foo/.", "", true); - tp!("foo//bar", "foo", true); - - if cfg!(windows) { - tp!("a\\b\\c", "a\\b", true); - tp!("\\a", "\\", true); - tp!("\\", "\\", false); - - tp!("C:\\a\\b", "C:\\a", true); - tp!("C:\\a", "C:\\", true); - tp!("C:\\", "C:\\", false); - tp!("C:a\\b", "C:a", true); - tp!("C:a", "C:", true); - tp!("C:", "C:", false); - tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true); - tp!("\\\\server\\share\\a", "\\\\server\\share\\", true); - tp!("\\\\server\\share", "\\\\server\\share", false); - tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true); - tp!("\\\\?\\a\\b", "\\\\?\\a\\", true); - tp!("\\\\?\\a", "\\\\?\\a", false); - tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); - tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true); - tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false); - tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true); - tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true); - tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false); - tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); - tp!("\\\\.\\a\\b", "\\\\.\\a\\", true); - tp!("\\\\.\\a", "\\\\.\\a", false); - - tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true); - } - } - - #[test] - pub fn test_set_file_name() { - macro_rules! tfn( - ($path:expr, $file:expr, $expected:expr) => ( { - let mut p = PathBuf::from($path); - p.set_file_name($file); - assert!(p.to_str() == Some($expected), - "setting file name of {:?} to {:?}: Expected {:?}, got {:?}", - $path, $file, $expected, - p.to_str().unwrap()); - }); - ); - - tfn!("foo", "foo", "foo"); - tfn!("foo", "bar", "bar"); - tfn!("foo", "", ""); - tfn!("", "foo", "foo"); - if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { - tfn!(".", "foo", "./foo"); - tfn!("foo/", "bar", "bar"); - tfn!("foo/.", "bar", "bar"); - tfn!("..", "foo", "../foo"); - tfn!("foo/..", "bar", "foo/../bar"); - tfn!("/", "foo", "/foo"); - } else { - tfn!(".", "foo", r".\foo"); - tfn!(r"foo\", "bar", r"bar"); - tfn!(r"foo\.", "bar", r"bar"); - tfn!("..", "foo", r"..\foo"); - tfn!(r"foo\..", "bar", r"foo\..\bar"); - tfn!(r"\", "foo", r"\foo"); - } - } - - #[test] - pub fn test_set_extension() { - macro_rules! tfe( - ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( { - let mut p = PathBuf::from($path); - let output = p.set_extension($ext); - assert!(p.to_str() == Some($expected) && output == $output, - "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}", - $path, $ext, $expected, $output, - p.to_str().unwrap(), output); - }); - ); - - tfe!("foo", "txt", "foo.txt", true); - tfe!("foo.bar", "txt", "foo.txt", true); - tfe!("foo.bar.baz", "txt", "foo.bar.txt", true); - tfe!(".test", "txt", ".test.txt", true); - tfe!("foo.txt", "", "foo", true); - tfe!("foo", "", "foo", true); - tfe!("", "foo", "", false); - tfe!(".", "foo", ".", false); - tfe!("foo/", "bar", "foo.bar", true); - tfe!("foo/.", "bar", "foo.bar", true); - tfe!("..", "foo", "..", false); - tfe!("foo/..", "bar", "foo/..", false); - tfe!("/", "foo", "/", false); - } - - #[test] - fn test_eq_receivers() { - use crate::borrow::Cow; - - let borrowed: &Path = Path::new("foo/bar"); - let mut owned: PathBuf = PathBuf::new(); - owned.push("foo"); - owned.push("bar"); - let borrowed_cow: Cow<'_, Path> = borrowed.into(); - let owned_cow: Cow<'_, Path> = owned.clone().into(); - - macro_rules! t { - ($($current:expr),+) => { - $( - assert_eq!($current, borrowed); - assert_eq!($current, owned); - assert_eq!($current, borrowed_cow); - assert_eq!($current, owned_cow); - )+ - } - } - - t!(borrowed, owned, borrowed_cow, owned_cow); - } - - #[test] - pub fn test_compare() { - use crate::collections::hash_map::DefaultHasher; - use crate::hash::{Hash, Hasher}; - - fn hash(t: T) -> u64 { - let mut s = DefaultHasher::new(); - t.hash(&mut s); - s.finish() - } - - macro_rules! tc( - ($path1:expr, $path2:expr, eq: $eq:expr, - starts_with: $starts_with:expr, ends_with: $ends_with:expr, - relative_from: $relative_from:expr) => ({ - let path1 = Path::new($path1); - let path2 = Path::new($path2); - - let eq = path1 == path2; - assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}", - $path1, $path2, $eq, eq); - assert!($eq == (hash(path1) == hash(path2)), - "{:?} == {:?}, expected {:?}, got {} and {}", - $path1, $path2, $eq, hash(path1), hash(path2)); - - let starts_with = path1.starts_with(path2); - assert!(starts_with == $starts_with, - "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2, - $starts_with, starts_with); - - let ends_with = path1.ends_with(path2); - assert!(ends_with == $ends_with, - "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2, - $ends_with, ends_with); - - let relative_from = path1.strip_prefix(path2) - .map(|p| p.to_str().unwrap()) - .ok(); - let exp: Option<&str> = $relative_from; - assert!(relative_from == exp, - "{:?}.strip_prefix({:?}), expected {:?}, got {:?}", - $path1, $path2, exp, relative_from); - }); - ); - - tc!("", "", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo", "", - eq: false, - starts_with: true, - ends_with: true, - relative_from: Some("foo") - ); - - tc!("", "foo", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - - tc!("foo", "foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/", "foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - - tc!("foo/bar", "foo", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("bar") - ); - - tc!("foo/bar/baz", "foo/bar", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("baz") - ); - - tc!("foo/bar", "foo/bar/baz", - eq: false, - starts_with: false, - ends_with: false, - relative_from: None - ); - - tc!("./foo/bar/", ".", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("foo/bar") - ); - - if cfg!(windows) { - tc!(r"C:\src\rust\cargo-test\test\Cargo.toml", - r"c:\src\rust\cargo-test\test", - eq: false, - starts_with: true, - ends_with: false, - relative_from: Some("Cargo.toml") - ); - - tc!(r"c:\foo", r"C:\foo", - eq: true, - starts_with: true, - ends_with: true, - relative_from: Some("") - ); - } - } - - #[test] - fn test_components_debug() { - let path = Path::new("/tmp"); - - let mut components = path.components(); - - let expected = "Components([RootDir, Normal(\"tmp\")])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - - let _ = components.next().unwrap(); - let expected = "Components([Normal(\"tmp\")])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - - let _ = components.next().unwrap(); - let expected = "Components([])"; - let actual = format!("{:?}", components); - assert_eq!(expected, actual); - } - - #[cfg(unix)] - #[test] - fn test_iter_debug() { - let path = Path::new("/tmp"); - - let mut iter = path.iter(); - - let expected = "Iter([\"/\", \"tmp\"])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - - let _ = iter.next().unwrap(); - let expected = "Iter([\"tmp\"])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - - let _ = iter.next().unwrap(); - let expected = "Iter([])"; - let actual = format!("{:?}", iter); - assert_eq!(expected, actual); - } - - #[test] - fn into_boxed() { - let orig: &str = "some/sort/of/path"; - let path = Path::new(orig); - let boxed: Box = Box::from(path); - let path_buf = path.to_owned().into_boxed_path().into_path_buf(); - assert_eq!(path, &*boxed); - assert_eq!(&*boxed, &*path_buf); - assert_eq!(&*path_buf, path); - } - - #[test] - fn test_clone_into() { - let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); - let path = Path::new("short"); - path.clone_into(&mut path_buf); - assert_eq!(path, path_buf); - assert!(path_buf.into_os_string().capacity() >= 15); - } - - #[test] - fn display_format_flags() { - assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b"); - assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b"); - } - - #[test] - fn into_rc() { - let orig = "hello/world"; - let path = Path::new(orig); - let rc: Rc = Rc::from(path); - let arc: Arc = Arc::from(path); - - assert_eq!(&*rc, path); - assert_eq!(&*arc, path); - - let rc2: Rc = Rc::from(path.to_owned()); - let arc2: Arc = Arc::from(path.to_owned()); - - assert_eq!(&*rc2, path); - assert_eq!(&*arc2, path); - } -} diff --git a/library/std/src/path/tests.rs b/library/std/src/path/tests.rs new file mode 100644 index 0000000000..ff94fda5a2 --- /dev/null +++ b/library/std/src/path/tests.rs @@ -0,0 +1,1394 @@ +use super::*; + +use crate::rc::Rc; +use crate::sync::Arc; + +macro_rules! t( + ($path:expr, iter: $iter:expr) => ( + { + let path = Path::new($path); + + // Forward iteration + let comps = path.iter() + .map(|p| p.to_string_lossy().into_owned()) + .collect::>(); + let exp: &[&str] = &$iter; + let exps = exp.iter().map(|s| s.to_string()).collect::>(); + assert!(comps == exps, "iter: Expected {:?}, found {:?}", + exps, comps); + + // Reverse iteration + let comps = Path::new($path).iter().rev() + .map(|p| p.to_string_lossy().into_owned()) + .collect::>(); + let exps = exps.into_iter().rev().collect::>(); + assert!(comps == exps, "iter().rev(): Expected {:?}, found {:?}", + exps, comps); + } + ); + + ($path:expr, has_root: $has_root:expr, is_absolute: $is_absolute:expr) => ( + { + let path = Path::new($path); + + let act_root = path.has_root(); + assert!(act_root == $has_root, "has_root: Expected {:?}, found {:?}", + $has_root, act_root); + + let act_abs = path.is_absolute(); + assert!(act_abs == $is_absolute, "is_absolute: Expected {:?}, found {:?}", + $is_absolute, act_abs); + } + ); + + ($path:expr, parent: $parent:expr, file_name: $file:expr) => ( + { + let path = Path::new($path); + + let parent = path.parent().map(|p| p.to_str().unwrap()); + let exp_parent: Option<&str> = $parent; + assert!(parent == exp_parent, "parent: Expected {:?}, found {:?}", + exp_parent, parent); + + let file = path.file_name().map(|p| p.to_str().unwrap()); + let exp_file: Option<&str> = $file; + assert!(file == exp_file, "file_name: Expected {:?}, found {:?}", + exp_file, file); + } + ); + + ($path:expr, file_stem: $file_stem:expr, extension: $extension:expr) => ( + { + let path = Path::new($path); + + let stem = path.file_stem().map(|p| p.to_str().unwrap()); + let exp_stem: Option<&str> = $file_stem; + assert!(stem == exp_stem, "file_stem: Expected {:?}, found {:?}", + exp_stem, stem); + + let ext = path.extension().map(|p| p.to_str().unwrap()); + let exp_ext: Option<&str> = $extension; + assert!(ext == exp_ext, "extension: Expected {:?}, found {:?}", + exp_ext, ext); + } + ); + + ($path:expr, iter: $iter:expr, + has_root: $has_root:expr, is_absolute: $is_absolute:expr, + parent: $parent:expr, file_name: $file:expr, + file_stem: $file_stem:expr, extension: $extension:expr) => ( + { + t!($path, iter: $iter); + t!($path, has_root: $has_root, is_absolute: $is_absolute); + t!($path, parent: $parent, file_name: $file); + t!($path, file_stem: $file_stem, extension: $extension); + } + ); +); + +#[test] +fn into() { + use crate::borrow::Cow; + + let static_path = Path::new("/home/foo"); + let static_cow_path: Cow<'static, Path> = static_path.into(); + let pathbuf = PathBuf::from("/home/foo"); + + { + let path: &Path = &pathbuf; + let borrowed_cow_path: Cow<'_, Path> = path.into(); + + assert_eq!(static_cow_path, borrowed_cow_path); + } + + let owned_cow_path: Cow<'static, Path> = pathbuf.into(); + + assert_eq!(static_cow_path, owned_cow_path); +} + +#[test] +#[cfg(unix)] +pub fn test_decompositions_unix() { + t!("", + iter: [], + has_root: false, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/", + iter: ["/"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("/foo", + iter: ["/", "foo"], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/foo/", + iter: ["/", "foo"], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("/foo/bar", + iter: ["/", "foo", "bar"], + has_root: true, + is_absolute: true, + parent: Some("/foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("///foo///", + iter: ["/", "foo"], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("///foo///bar", + iter: ["/", "foo", "bar"], + has_root: true, + is_absolute: true, + parent: Some("///foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./.", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("/..", + iter: ["/", ".."], + has_root: true, + is_absolute: true, + parent: Some("/"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("../", + iter: [".."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/.", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/..", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/./", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/./bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("foo/../", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/../bar", + iter: ["foo", "..", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo/.."), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./a", + iter: [".", "a"], + has_root: false, + is_absolute: false, + parent: Some("."), + file_name: Some("a"), + file_stem: Some("a"), + extension: None + ); + + t!(".", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("./", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("a/b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a//b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/./b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/b/c", + iter: ["a", "b", "c"], + has_root: false, + is_absolute: false, + parent: Some("a/b"), + file_name: Some("c"), + file_stem: Some("c"), + extension: None + ); + + t!(".foo", + iter: [".foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some(".foo"), + file_stem: Some(".foo"), + extension: None + ); +} + +#[test] +#[cfg(windows)] +pub fn test_decompositions_windows() { + t!("", + iter: [], + has_root: false, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/", + iter: ["\\"], + has_root: true, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\", + iter: ["\\"], + has_root: true, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("c:", + iter: ["c:"], + has_root: false, + is_absolute: false, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("c:\\", + iter: ["c:", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("c:/", + iter: ["c:", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("/foo", + iter: ["\\", "foo"], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("/foo/", + iter: ["\\", "foo"], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("/foo/bar", + iter: ["\\", "foo", "bar"], + has_root: true, + is_absolute: false, + parent: Some("/foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("///foo///", + iter: ["\\", "foo"], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("///foo///bar", + iter: ["\\", "foo", "bar"], + has_root: true, + is_absolute: false, + parent: Some("///foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./.", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("/..", + iter: ["\\", ".."], + has_root: true, + is_absolute: false, + parent: Some("/"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("../", + iter: [".."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/.", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/..", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/./", + iter: ["foo"], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: Some("foo"), + file_stem: Some("foo"), + extension: None + ); + + t!("foo/./bar", + iter: ["foo", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("foo/../", + iter: ["foo", ".."], + has_root: false, + is_absolute: false, + parent: Some("foo"), + file_name: None, + file_stem: None, + extension: None + ); + + t!("foo/../bar", + iter: ["foo", "..", "bar"], + has_root: false, + is_absolute: false, + parent: Some("foo/.."), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("./a", + iter: [".", "a"], + has_root: false, + is_absolute: false, + parent: Some("."), + file_name: Some("a"), + file_stem: Some("a"), + extension: None + ); + + t!(".", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("./", + iter: ["."], + has_root: false, + is_absolute: false, + parent: Some(""), + file_name: None, + file_stem: None, + extension: None + ); + + t!("a/b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a//b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/./b", + iter: ["a", "b"], + has_root: false, + is_absolute: false, + parent: Some("a"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); + + t!("a/b/c", + iter: ["a", "b", "c"], + has_root: false, + is_absolute: false, + parent: Some("a/b"), + file_name: Some("c"), + file_stem: Some("c"), + extension: None); + + t!("a\\b\\c", + iter: ["a", "b", "c"], + has_root: false, + is_absolute: false, + parent: Some("a\\b"), + file_name: Some("c"), + file_stem: Some("c"), + extension: None + ); + + t!("\\a", + iter: ["\\", "a"], + has_root: true, + is_absolute: false, + parent: Some("\\"), + file_name: Some("a"), + file_stem: Some("a"), + extension: None + ); + + t!("c:\\foo.txt", + iter: ["c:", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("c:\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\server\\share\\foo.txt", + iter: ["\\\\server\\share", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\server\\share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\server\\share", + iter: ["\\\\server\\share", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\server", + iter: ["\\", "server"], + has_root: true, + is_absolute: false, + parent: Some("\\"), + file_name: Some("server"), + file_stem: Some("server"), + extension: None + ); + + t!("\\\\?\\bar\\foo.txt", + iter: ["\\\\?\\bar", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\bar\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\?\\bar", + iter: ["\\\\?\\bar"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\", + iter: ["\\\\?\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\UNC\\server\\share\\foo.txt", + iter: ["\\\\?\\UNC\\server\\share", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\UNC\\server\\share\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\?\\UNC\\server", + iter: ["\\\\?\\UNC\\server"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\UNC\\", + iter: ["\\\\?\\UNC\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\C:\\foo.txt", + iter: ["\\\\?\\C:", "\\", "foo.txt"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\C:\\"), + file_name: Some("foo.txt"), + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("\\\\?\\C:\\", + iter: ["\\\\?\\C:", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\C:", + iter: ["\\\\?\\C:"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\foo/bar", + iter: ["\\\\?\\foo/bar"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\C:/foo", + iter: ["\\\\?\\C:/foo"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\.\\foo\\bar", + iter: ["\\\\.\\foo", "\\", "bar"], + has_root: true, + is_absolute: true, + parent: Some("\\\\.\\foo\\"), + file_name: Some("bar"), + file_stem: Some("bar"), + extension: None + ); + + t!("\\\\.\\foo", + iter: ["\\\\.\\foo", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\.\\foo/bar", + iter: ["\\\\.\\foo/bar", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\.\\foo\\bar/baz", + iter: ["\\\\.\\foo", "\\", "bar", "baz"], + has_root: true, + is_absolute: true, + parent: Some("\\\\.\\foo\\bar"), + file_name: Some("baz"), + file_stem: Some("baz"), + extension: None + ); + + t!("\\\\.\\", + iter: ["\\\\.\\", "\\"], + has_root: true, + is_absolute: true, + parent: None, + file_name: None, + file_stem: None, + extension: None + ); + + t!("\\\\?\\a\\b\\", + iter: ["\\\\?\\a", "\\", "b"], + has_root: true, + is_absolute: true, + parent: Some("\\\\?\\a\\"), + file_name: Some("b"), + file_stem: Some("b"), + extension: None + ); +} + +#[test] +pub fn test_stem_ext() { + t!("foo", + file_stem: Some("foo"), + extension: None + ); + + t!("foo.", + file_stem: Some("foo"), + extension: Some("") + ); + + t!(".foo", + file_stem: Some(".foo"), + extension: None + ); + + t!("foo.txt", + file_stem: Some("foo"), + extension: Some("txt") + ); + + t!("foo.bar.txt", + file_stem: Some("foo.bar"), + extension: Some("txt") + ); + + t!("foo.bar.", + file_stem: Some("foo.bar"), + extension: Some("") + ); + + t!(".", file_stem: None, extension: None); + + t!("..", file_stem: None, extension: None); + + t!("", file_stem: None, extension: None); +} + +#[test] +pub fn test_push() { + macro_rules! tp( + ($path:expr, $push:expr, $expected:expr) => ( { + let mut actual = PathBuf::from($path); + actual.push($push); + assert!(actual.to_str() == Some($expected), + "pushing {:?} onto {:?}: Expected {:?}, got {:?}", + $push, $path, $expected, actual.to_str().unwrap()); + }); + ); + + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { + tp!("", "foo", "foo"); + tp!("foo", "bar", "foo/bar"); + tp!("foo/", "bar", "foo/bar"); + tp!("foo//", "bar", "foo//bar"); + tp!("foo/.", "bar", "foo/./bar"); + tp!("foo./.", "bar", "foo././bar"); + tp!("foo", "", "foo/"); + tp!("foo", ".", "foo/."); + tp!("foo", "..", "foo/.."); + tp!("foo", "/", "/"); + tp!("/foo/bar", "/", "/"); + tp!("/foo/bar", "/baz", "/baz"); + tp!("/foo/bar", "./baz", "/foo/bar/./baz"); + } else { + tp!("", "foo", "foo"); + tp!("foo", "bar", r"foo\bar"); + tp!("foo/", "bar", r"foo/bar"); + tp!(r"foo\", "bar", r"foo\bar"); + tp!("foo//", "bar", r"foo//bar"); + tp!(r"foo\\", "bar", r"foo\\bar"); + tp!("foo/.", "bar", r"foo/.\bar"); + tp!("foo./.", "bar", r"foo./.\bar"); + tp!(r"foo\.", "bar", r"foo\.\bar"); + tp!(r"foo.\.", "bar", r"foo.\.\bar"); + tp!("foo", "", "foo\\"); + tp!("foo", ".", r"foo\."); + tp!("foo", "..", r"foo\.."); + tp!("foo", "/", "/"); + tp!("foo", r"\", r"\"); + tp!("/foo/bar", "/", "/"); + tp!(r"\foo\bar", r"\", r"\"); + tp!("/foo/bar", "/baz", "/baz"); + tp!("/foo/bar", r"\baz", r"\baz"); + tp!("/foo/bar", "./baz", r"/foo/bar\./baz"); + tp!("/foo/bar", r".\baz", r"/foo/bar\.\baz"); + + tp!("c:\\", "windows", "c:\\windows"); + tp!("c:", "windows", "c:windows"); + + tp!("a\\b\\c", "d", "a\\b\\c\\d"); + tp!("\\a\\b\\c", "d", "\\a\\b\\c\\d"); + tp!("a\\b", "c\\d", "a\\b\\c\\d"); + tp!("a\\b", "\\c\\d", "\\c\\d"); + tp!("a\\b", ".", "a\\b\\."); + tp!("a\\b", "..\\c", "a\\b\\..\\c"); + tp!("a\\b", "C:a.txt", "C:a.txt"); + tp!("a\\b", "C:\\a.txt", "C:\\a.txt"); + tp!("C:\\a", "C:\\b.txt", "C:\\b.txt"); + tp!("C:\\a\\b\\c", "C:d", "C:d"); + tp!("C:a\\b\\c", "C:d", "C:d"); + tp!("C:", r"a\b\c", r"C:a\b\c"); + tp!("C:", r"..\a", r"C:..\a"); + tp!("\\\\server\\share\\foo", "bar", "\\\\server\\share\\foo\\bar"); + tp!("\\\\server\\share\\foo", "C:baz", "C:baz"); + tp!("\\\\?\\C:\\a\\b", "C:c\\d", "C:c\\d"); + tp!("\\\\?\\C:a\\b", "C:c\\d", "C:c\\d"); + tp!("\\\\?\\C:\\a\\b", "C:\\c\\d", "C:\\c\\d"); + tp!("\\\\?\\foo\\bar", "baz", "\\\\?\\foo\\bar\\baz"); + tp!("\\\\?\\UNC\\server\\share\\foo", "bar", "\\\\?\\UNC\\server\\share\\foo\\bar"); + tp!("\\\\?\\UNC\\server\\share", "C:\\a", "C:\\a"); + tp!("\\\\?\\UNC\\server\\share", "C:a", "C:a"); + + // Note: modified from old path API + tp!("\\\\?\\UNC\\server", "foo", "\\\\?\\UNC\\server\\foo"); + + tp!("C:\\a", "\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share"); + tp!("\\\\.\\foo\\bar", "baz", "\\\\.\\foo\\bar\\baz"); + tp!("\\\\.\\foo\\bar", "C:a", "C:a"); + // again, not sure about the following, but I'm assuming \\.\ should be verbatim + tp!("\\\\.\\foo", "..\\bar", "\\\\.\\foo\\..\\bar"); + + tp!("\\\\?\\C:", "foo", "\\\\?\\C:\\foo"); // this is a weird one + } +} + +#[test] +pub fn test_pop() { + macro_rules! tp( + ($path:expr, $expected:expr, $output:expr) => ( { + let mut actual = PathBuf::from($path); + let output = actual.pop(); + assert!(actual.to_str() == Some($expected) && output == $output, + "popping from {:?}: Expected {:?}/{:?}, got {:?}/{:?}", + $path, $expected, $output, + actual.to_str().unwrap(), output); + }); + ); + + tp!("", "", false); + tp!("/", "/", false); + tp!("foo", "", true); + tp!(".", "", true); + tp!("/foo", "/", true); + tp!("/foo/bar", "/foo", true); + tp!("foo/bar", "foo", true); + tp!("foo/.", "", true); + tp!("foo//bar", "foo", true); + + if cfg!(windows) { + tp!("a\\b\\c", "a\\b", true); + tp!("\\a", "\\", true); + tp!("\\", "\\", false); + + tp!("C:\\a\\b", "C:\\a", true); + tp!("C:\\a", "C:\\", true); + tp!("C:\\", "C:\\", false); + tp!("C:a\\b", "C:a", true); + tp!("C:a", "C:", true); + tp!("C:", "C:", false); + tp!("\\\\server\\share\\a\\b", "\\\\server\\share\\a", true); + tp!("\\\\server\\share\\a", "\\\\server\\share\\", true); + tp!("\\\\server\\share", "\\\\server\\share", false); + tp!("\\\\?\\a\\b\\c", "\\\\?\\a\\b", true); + tp!("\\\\?\\a\\b", "\\\\?\\a\\", true); + tp!("\\\\?\\a", "\\\\?\\a", false); + tp!("\\\\?\\C:\\a\\b", "\\\\?\\C:\\a", true); + tp!("\\\\?\\C:\\a", "\\\\?\\C:\\", true); + tp!("\\\\?\\C:\\", "\\\\?\\C:\\", false); + tp!("\\\\?\\UNC\\server\\share\\a\\b", "\\\\?\\UNC\\server\\share\\a", true); + tp!("\\\\?\\UNC\\server\\share\\a", "\\\\?\\UNC\\server\\share\\", true); + tp!("\\\\?\\UNC\\server\\share", "\\\\?\\UNC\\server\\share", false); + tp!("\\\\.\\a\\b\\c", "\\\\.\\a\\b", true); + tp!("\\\\.\\a\\b", "\\\\.\\a\\", true); + tp!("\\\\.\\a", "\\\\.\\a", false); + + tp!("\\\\?\\a\\b\\", "\\\\?\\a\\", true); + } +} + +#[test] +pub fn test_set_file_name() { + macro_rules! tfn( + ($path:expr, $file:expr, $expected:expr) => ( { + let mut p = PathBuf::from($path); + p.set_file_name($file); + assert!(p.to_str() == Some($expected), + "setting file name of {:?} to {:?}: Expected {:?}, got {:?}", + $path, $file, $expected, + p.to_str().unwrap()); + }); + ); + + tfn!("foo", "foo", "foo"); + tfn!("foo", "bar", "bar"); + tfn!("foo", "", ""); + tfn!("", "foo", "foo"); + if cfg!(unix) || cfg!(all(target_env = "sgx", target_vendor = "fortanix")) { + tfn!(".", "foo", "./foo"); + tfn!("foo/", "bar", "bar"); + tfn!("foo/.", "bar", "bar"); + tfn!("..", "foo", "../foo"); + tfn!("foo/..", "bar", "foo/../bar"); + tfn!("/", "foo", "/foo"); + } else { + tfn!(".", "foo", r".\foo"); + tfn!(r"foo\", "bar", r"bar"); + tfn!(r"foo\.", "bar", r"bar"); + tfn!("..", "foo", r"..\foo"); + tfn!(r"foo\..", "bar", r"foo\..\bar"); + tfn!(r"\", "foo", r"\foo"); + } +} + +#[test] +pub fn test_set_extension() { + macro_rules! tfe( + ($path:expr, $ext:expr, $expected:expr, $output:expr) => ( { + let mut p = PathBuf::from($path); + let output = p.set_extension($ext); + assert!(p.to_str() == Some($expected) && output == $output, + "setting extension of {:?} to {:?}: Expected {:?}/{:?}, got {:?}/{:?}", + $path, $ext, $expected, $output, + p.to_str().unwrap(), output); + }); + ); + + tfe!("foo", "txt", "foo.txt", true); + tfe!("foo.bar", "txt", "foo.txt", true); + tfe!("foo.bar.baz", "txt", "foo.bar.txt", true); + tfe!(".test", "txt", ".test.txt", true); + tfe!("foo.txt", "", "foo", true); + tfe!("foo", "", "foo", true); + tfe!("", "foo", "", false); + tfe!(".", "foo", ".", false); + tfe!("foo/", "bar", "foo.bar", true); + tfe!("foo/.", "bar", "foo.bar", true); + tfe!("..", "foo", "..", false); + tfe!("foo/..", "bar", "foo/..", false); + tfe!("/", "foo", "/", false); +} + +#[test] +fn test_eq_receivers() { + use crate::borrow::Cow; + + let borrowed: &Path = Path::new("foo/bar"); + let mut owned: PathBuf = PathBuf::new(); + owned.push("foo"); + owned.push("bar"); + let borrowed_cow: Cow<'_, Path> = borrowed.into(); + let owned_cow: Cow<'_, Path> = owned.clone().into(); + + macro_rules! t { + ($($current:expr),+) => { + $( + assert_eq!($current, borrowed); + assert_eq!($current, owned); + assert_eq!($current, borrowed_cow); + assert_eq!($current, owned_cow); + )+ + } + } + + t!(borrowed, owned, borrowed_cow, owned_cow); +} + +#[test] +pub fn test_compare() { + use crate::collections::hash_map::DefaultHasher; + use crate::hash::{Hash, Hasher}; + + fn hash(t: T) -> u64 { + let mut s = DefaultHasher::new(); + t.hash(&mut s); + s.finish() + } + + macro_rules! tc( + ($path1:expr, $path2:expr, eq: $eq:expr, + starts_with: $starts_with:expr, ends_with: $ends_with:expr, + relative_from: $relative_from:expr) => ({ + let path1 = Path::new($path1); + let path2 = Path::new($path2); + + let eq = path1 == path2; + assert!(eq == $eq, "{:?} == {:?}, expected {:?}, got {:?}", + $path1, $path2, $eq, eq); + assert!($eq == (hash(path1) == hash(path2)), + "{:?} == {:?}, expected {:?}, got {} and {}", + $path1, $path2, $eq, hash(path1), hash(path2)); + + let starts_with = path1.starts_with(path2); + assert!(starts_with == $starts_with, + "{:?}.starts_with({:?}), expected {:?}, got {:?}", $path1, $path2, + $starts_with, starts_with); + + let ends_with = path1.ends_with(path2); + assert!(ends_with == $ends_with, + "{:?}.ends_with({:?}), expected {:?}, got {:?}", $path1, $path2, + $ends_with, ends_with); + + let relative_from = path1.strip_prefix(path2) + .map(|p| p.to_str().unwrap()) + .ok(); + let exp: Option<&str> = $relative_from; + assert!(relative_from == exp, + "{:?}.strip_prefix({:?}), expected {:?}, got {:?}", + $path1, $path2, exp, relative_from); + }); + ); + + tc!("", "", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo", "", + eq: false, + starts_with: true, + ends_with: true, + relative_from: Some("foo") + ); + + tc!("", "foo", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + + tc!("foo", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo/", "foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + + tc!("foo/bar", "foo", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("bar") + ); + + tc!("foo/bar/baz", "foo/bar", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("baz") + ); + + tc!("foo/bar", "foo/bar/baz", + eq: false, + starts_with: false, + ends_with: false, + relative_from: None + ); + + tc!("./foo/bar/", ".", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("foo/bar") + ); + + if cfg!(windows) { + tc!(r"C:\src\rust\cargo-test\test\Cargo.toml", + r"c:\src\rust\cargo-test\test", + eq: false, + starts_with: true, + ends_with: false, + relative_from: Some("Cargo.toml") + ); + + tc!(r"c:\foo", r"C:\foo", + eq: true, + starts_with: true, + ends_with: true, + relative_from: Some("") + ); + } +} + +#[test] +fn test_components_debug() { + let path = Path::new("/tmp"); + + let mut components = path.components(); + + let expected = "Components([RootDir, Normal(\"tmp\")])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); + + let _ = components.next().unwrap(); + let expected = "Components([Normal(\"tmp\")])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); + + let _ = components.next().unwrap(); + let expected = "Components([])"; + let actual = format!("{:?}", components); + assert_eq!(expected, actual); +} + +#[cfg(unix)] +#[test] +fn test_iter_debug() { + let path = Path::new("/tmp"); + + let mut iter = path.iter(); + + let expected = "Iter([\"/\", \"tmp\"])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); + + let _ = iter.next().unwrap(); + let expected = "Iter([\"tmp\"])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); + + let _ = iter.next().unwrap(); + let expected = "Iter([])"; + let actual = format!("{:?}", iter); + assert_eq!(expected, actual); +} + +#[test] +fn into_boxed() { + let orig: &str = "some/sort/of/path"; + let path = Path::new(orig); + let boxed: Box = Box::from(path); + let path_buf = path.to_owned().into_boxed_path().into_path_buf(); + assert_eq!(path, &*boxed); + assert_eq!(&*boxed, &*path_buf); + assert_eq!(&*path_buf, path); +} + +#[test] +fn test_clone_into() { + let mut path_buf = PathBuf::from("supercalifragilisticexpialidocious"); + let path = Path::new("short"); + path.clone_into(&mut path_buf); + assert_eq!(path, path_buf); + assert!(path_buf.into_os_string().capacity() >= 15); +} + +#[test] +fn display_format_flags() { + assert_eq!(format!("a{:#<5}b", Path::new("").display()), "a#####b"); + assert_eq!(format!("a{:#<5}b", Path::new("a").display()), "aa####b"); +} + +#[test] +fn into_rc() { + let orig = "hello/world"; + let path = Path::new(orig); + let rc: Rc = Rc::from(path); + let arc: Arc = Arc::from(path); + + assert_eq!(&*rc, path); + assert_eq!(&*arc, path); + + let rc2: Rc = Rc::from(path.to_owned()); + let arc2: Arc = Arc::from(path.to_owned()); + + assert_eq!(&*rc2, path); + assert_eq!(&*arc2, path); +} diff --git a/library/std/src/prelude/mod.rs b/library/std/src/prelude/mod.rs index 710c616be7..c7a7c779d3 100644 --- a/library/std/src/prelude/mod.rs +++ b/library/std/src/prelude/mod.rs @@ -75,7 +75,7 @@ //! [`std::result`]: crate::result //! [`std::slice`]: crate::slice //! [`std::string`]: crate::string -//! [`std::vec`]: ../vec/index.html +//! [`std::vec`]: mod@crate::vec //! [`to_owned`]: crate::borrow::ToOwned::to_owned //! [book-closures]: ../../book/ch13-01-closures.html //! [book-dtor]: ../../book/ch15-03-drop.html diff --git a/library/std/src/primitive_docs.rs b/library/std/src/primitive_docs.rs index be7fd0dd6c..81bbf37637 100644 --- a/library/std/src/primitive_docs.rs +++ b/library/std/src/primitive_docs.rs @@ -1,7 +1,6 @@ #[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 @@ -12,18 +11,17 @@ /// `bool` implements various traits, such as [`BitAnd`], [`BitOr`], [`Not`], etc., /// which allow us to perform boolean operations using `&`, `|` and `!`. /// -/// `if` always demands a `bool` value. [`assert!`], being an important macro in testing, -/// checks whether an expression returns `true`. +/// `if` always demands a `bool` value. [`assert!`], which is an important macro in testing, +/// checks whether an expression returns `true` and panics if it isn't. /// /// ``` /// let bool_val = true & false | false; /// assert!(!bool_val); /// ``` /// -/// [`assert!`]: macro.assert.html -/// [`BitAnd`]: ops/trait.BitAnd.html -/// [`BitOr`]: ops/trait.BitOr.html -/// [`Not`]: ops/trait.Not.html +/// [`BitAnd`]: ops::BitAnd +/// [`BitOr`]: ops::BitOr +/// [`Not`]: ops::Not /// /// # Examples /// @@ -46,7 +44,7 @@ /// } /// ``` /// -/// Also, since `bool` implements the [`Copy`](marker/trait.Copy.html) trait, we don't +/// 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: @@ -100,8 +98,8 @@ mod prim_bool {} /// 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`]: primitive.str.html -/// [`exit`]: process/fn.exit.html +/// [`u32`]: prim@u32 +/// [`exit`]: process::exit /// /// # `!` and generics /// @@ -185,26 +183,58 @@ mod prim_bool {} /// 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/trait.FromStr.html#tymethod.from_str -/// [`Result`]: result/enum.Result.html -/// [`Result`]: result/enum.Result.html -/// [`Result`]: result/enum.Result.html -/// [`Ok`]: result/enum.Result.html#variant.Ok -/// [`String`]: string/struct.String.html -/// [`Err`]: result/enum.Result.html#variant.Err -/// [`FromStr`]: str/trait.FromStr.html +/// [`String::from_str`]: str::FromStr::from_str +/// [`Result`]: Result +/// [`Result`]: Result +/// [`Result`]: Result +/// [`String`]: string::String +/// [`FromStr`]: str::FromStr /// /// # `!` and traits /// /// When writing your own traits, `!` should have an `impl` whenever there is an obvious `impl` -/// which doesn't `panic!`. As it turns out, most traits can have an `impl` for `!`. Take [`Debug`] +/// 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 core::ops::Add; +/// +/// fn foo() -> impl Add { +/// unimplemented!() +/// } +/// ``` +/// +/// But this code does: +/// +/// ``` +/// use core::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; +/// # fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result; /// # } /// impl Debug for ! { /// fn fmt(&self, formatter: &mut fmt::Formatter<'_>) -> fmt::Result { @@ -233,11 +263,9 @@ mod prim_bool {} /// `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.) /// -/// [`fmt::Result`]: fmt/type.Result.html -/// [`File`]: fs/struct.File.html -/// [`Debug`]: fmt/trait.Debug.html -/// [`Default`]: default/trait.Default.html -/// [`default()`]: default/trait.Default.html#tymethod.default +/// [`File`]: fs::File +/// [`Debug`]: fmt::Debug +/// [`default()`]: Default::default /// #[unstable(feature = "never_type", issue = "35121")] mod prim_never {} @@ -356,11 +384,12 @@ mod prim_char {} #[stable(feature = "rust1", since = "1.0.0")] mod prim_unit {} +#[doc(alias = "ptr")] #[doc(primitive = "pointer")] // /// Raw, unsafe pointers, `*const T`, and `*mut T`. /// -/// *[See also the `std::ptr` module](ptr/index.html).* +/// *[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 @@ -439,13 +468,13 @@ mod prim_unit {} /// but C APIs hand out a lot of pointers generally, so are a common source /// of raw pointers in Rust. /// -/// [`null`]: ../std/ptr/fn.null.html -/// [`null_mut`]: ../std/ptr/fn.null_mut.html +/// [`null`]: ptr::null +/// [`null_mut`]: ptr::null_mut /// [`is_null`]: ../std/primitive.pointer.html#method.is_null /// [`offset`]: ../std/primitive.pointer.html#method.offset -/// [`into_raw`]: ../std/boxed/struct.Box.html#method.into_raw -/// [`drop`]: ../std/mem/fn.drop.html -/// [`write`]: ../std/ptr/fn.write.html +/// [`into_raw`]: Box::into_raw +/// [`drop`]: mem::drop +/// [`write`]: ptr::write #[stable(feature = "rust1", since = "1.0.0")] mod prim_pointer {} @@ -458,32 +487,32 @@ mod prim_pointer {} /// /// * 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`][copy]. +/// The type of `x` must be [`Copy`]. /// /// Arrays of *any* size implement the following traits if the element type allows it: /// -/// - [`Debug`][debug] -/// - [`IntoIterator`][intoiterator] (implemented for `&[T; N]` and `&mut [T; N]`) -/// - [`PartialEq`][partialeq], [`PartialOrd`][partialord], [`Eq`][eq], [`Ord`][ord] -/// - [`Hash`][hash] -/// - [`AsRef`][asref], [`AsMut`][asmut] -/// - [`Borrow`][borrow], [`BorrowMut`][borrowmut] +/// - [`Debug`] +/// - [`IntoIterator`] (implemented for `&[T; N]` and `&mut [T; N]`) +/// - [`PartialEq`], [`PartialOrd`], [`Eq`], [`Ord`] +/// - [`Hash`] +/// - [`AsRef`], [`AsMut`] +/// - [`Borrow`], [`BorrowMut`] /// -/// Arrays of sizes from 0 to 32 (inclusive) implement [`Default`][default] trait +/// Arrays of sizes from 0 to 32 (inclusive) implement [`Default`] trait /// if the element type allows it. As a stopgap, trait implementations are /// statically generated up to size 32. /// -/// Arrays of *any* size are [`Copy`][copy] if the element type is [`Copy`][copy] -/// and [`Clone`][clone] if the element type is [`Clone`][clone]. This works -/// because [`Copy`][copy] and [`Clone`][clone] traits are specially known +/// Arrays of *any* size are [`Copy`] if the element type is [`Copy`] +/// and [`Clone`] if the element type is [`Clone`]. This works +/// because [`Copy`] and [`Clone`] traits are specially known /// to the compiler. /// /// 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`][replace]. +/// You can move elements out of an array with a [slice pattern]. If you want +/// one element, see [`mem::replace`]. /// /// # Examples /// @@ -524,7 +553,7 @@ mod prim_pointer {} /// for x in &array { } /// ``` /// -/// You can use a slice pattern to move elements out of an array: +/// You can use a [slice pattern] to move elements out of an array: /// /// ``` /// fn move_away(_: String) { /* Do interesting things. */ } @@ -535,23 +564,11 @@ mod prim_pointer {} /// ``` /// /// [slice]: primitive.slice.html -/// [copy]: marker/trait.Copy.html -/// [clone]: clone/trait.Clone.html -/// [debug]: fmt/trait.Debug.html -/// [intoiterator]: iter/trait.IntoIterator.html -/// [partialeq]: cmp/trait.PartialEq.html -/// [partialord]: cmp/trait.PartialOrd.html -/// [eq]: cmp/trait.Eq.html -/// [ord]: cmp/trait.Ord.html -/// [hash]: hash/trait.Hash.html -/// [asref]: convert/trait.AsRef.html -/// [asmut]: convert/trait.AsMut.html -/// [borrow]: borrow/trait.Borrow.html -/// [borrowmut]: borrow/trait.BorrowMut.html -/// [default]: default/trait.Default.html -/// [replace]: mem/fn.replace.html -/// [`IntoIterator`]: iter/trait.IntoIterator.html -/// +/// [`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 {} @@ -563,7 +580,7 @@ mod prim_array {} /// means that elements are laid out so that every element is the same /// distance from its neighbors. /// -/// *[See also the `std::slice` module](slice/index.html).* +/// *[See also the `std::slice` module][`crate::slice`].* /// /// Slices are a view into a block of memory represented as a pointer and a /// length. @@ -608,7 +625,7 @@ mod prim_slice {} // /// String slices. /// -/// *[See also the `std::str` module](str/index.html).* +/// *[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 @@ -660,8 +677,8 @@ mod prim_slice {} /// assert_eq!(s, Ok(story)); /// ``` /// -/// [`as_ptr`]: #method.as_ptr -/// [`len`]: #method.len +/// [`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` @@ -729,15 +746,8 @@ mod prim_str {} /// * [`Default`] /// * [`Hash`] /// -/// [`Clone`]: clone/trait.Clone.html -/// [`Copy`]: marker/trait.Copy.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`Debug`]: fmt/trait.Debug.html -/// [`Default`]: default/trait.Default.html -/// [`Hash`]: hash/trait.Hash.html +/// [`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. @@ -810,7 +820,7 @@ mod prim_tuple {} /// /// For more information on floating point numbers, see [Wikipedia][wikipedia]. /// -/// *[See also the `std::f32::consts` module](f32/consts/index.html).* +/// *[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")] @@ -819,13 +829,14 @@ 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`](primitive.f32.html), but has increased +/// This type is very similar to [`f32`], but has increased /// precision by using twice as many bits. Please see [the documentation for -/// `f32`](primitive.f32.html) or [Wikipedia on double precision +/// `f32`][`f32`] or [Wikipedia on double precision /// values][wikipedia] for more information. /// -/// *[See also the `std::f64::consts` module](f64/consts/index.html).* +/// *[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 {} @@ -945,9 +956,6 @@ mod prim_usize {} /// implicit reference-pointer coercion and raw pointer equality via [`ptr::eq`], while /// [`PartialEq`] compares values. /// -/// [`ptr::eq`]: ptr/fn.eq.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// /// ``` /// use std::ptr; /// @@ -979,11 +987,9 @@ mod prim_usize {} /// * [`Borrow`] /// * [`Pointer`] /// -/// [`Copy`]: marker/trait.Copy.html -/// [`Clone`]: clone/trait.Clone.html -/// [`Deref`]: ops/trait.Deref.html -/// [`Borrow`]: borrow/trait.Borrow.html -/// [`Pointer`]: fmt/trait.Pointer.html +/// [`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 @@ -992,8 +998,8 @@ mod prim_usize {} /// * [`DerefMut`] /// * [`BorrowMut`] /// -/// [`DerefMut`]: ops/trait.DerefMut.html -/// [`BorrowMut`]: borrow/trait.BorrowMut.html +/// [`DerefMut`]: ops::DerefMut +/// [`BorrowMut`]: borrow::BorrowMut /// /// The following traits are implemented on `&T` references if the underlying `T` also implements /// that trait: @@ -1008,18 +1014,10 @@ mod prim_usize {} /// * [`Hash`] /// * [`ToSocketAddrs`] /// -/// [`std::fmt`]: fmt/index.html -/// [`fmt::Write`]: fmt/trait.Write.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`AsRef`]: convert/trait.AsRef.html -/// [`Fn`]: ops/trait.Fn.html -/// [`FnMut`]: ops/trait.FnMut.html -/// [`FnOnce`]: ops/trait.FnOnce.html -/// [`Hash`]: hash/trait.Hash.html -/// [`ToSocketAddrs`]: net/trait.ToSocketAddrs.html +/// [`std::fmt`]: fmt +/// ['Pointer`]: fmt::Pointer +/// [`Hash`]: hash::Hash +/// [`ToSocketAddrs`]: net::ToSocketAddrs /// /// `&mut T` references get all of the above except `ToSocketAddrs`, plus the following, if `T` /// implements that trait: @@ -1038,17 +1036,11 @@ mod prim_usize {} /// * [`Seek`] /// * [`BufRead`] /// -/// [`AsMut`]: convert/trait.AsMut.html -/// [`Iterator`]: iter/trait.Iterator.html -/// [`DoubleEndedIterator`]: iter/trait.DoubleEndedIterator.html -/// [`ExactSizeIterator`]: iter/trait.ExactSizeIterator.html -/// [`FusedIterator`]: iter/trait.FusedIterator.html -/// [`TrustedLen`]: iter/trait.TrustedLen.html -/// [`Send`]: marker/trait.Send.html -/// [`io::Write`]: io/trait.Write.html -/// [`Read`]: io/trait.Read.html -/// [`Seek`]: io/trait.Seek.html -/// [`BufRead`]: io/trait.BufRead.html +/// [`FusedIterator`]: iter::FusedIterator +/// [`TrustedLen`]: iter::TrustedLen +/// [`Seek`]: io::Seek +/// [`BufRead`]: io::BufRead +/// [`Read`]: io::Read /// /// 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 @@ -1063,9 +1055,9 @@ mod prim_ref {} /// /// *See also the traits [`Fn`], [`FnMut`], and [`FnOnce`].* /// -/// [`Fn`]: ops/trait.Fn.html -/// [`FnMut`]: ops/trait.FnMut.html -/// [`FnOnce`]: ops/trait.FnOnce.html +/// [`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 @@ -1177,14 +1169,8 @@ mod prim_ref {} /// * [`Pointer`] /// * [`Debug`] /// -/// [`Clone`]: clone/trait.Clone.html -/// [`PartialEq`]: cmp/trait.PartialEq.html -/// [`Eq`]: cmp/trait.Eq.html -/// [`PartialOrd`]: cmp/trait.PartialOrd.html -/// [`Ord`]: cmp/trait.Ord.html -/// [`Hash`]: hash/trait.Hash.html -/// [`Pointer`]: fmt/trait.Pointer.html -/// [`Debug`]: fmt/trait.Debug.html +/// [`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 @@ -1193,7 +1179,5 @@ mod prim_ref {} /// 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. -/// -/// [`Copy`]: marker/trait.Copy.html #[stable(feature = "rust1", since = "1.0.0")] mod prim_fn {} diff --git a/library/std/src/process.rs b/library/std/src/process.rs index c42bc10965..3d238b7f76 100644 --- a/library/std/src/process.rs +++ b/library/std/src/process.rs @@ -95,6 +95,10 @@ //! [`Read`]: io::Read #![stable(feature = "process", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] +mod tests; use crate::io::prelude::*; @@ -106,6 +110,8 @@ use crate::path::Path; use crate::str; use crate::sys::pipe::{read2, AnonPipe}; use crate::sys::process as imp; +#[unstable(feature = "command_access", issue = "44434")] +pub use crate::sys_common::process::CommandEnvs; use crate::sys_common::{AsInner, AsInnerMut, FromInner, IntoInner}; /// Representation of a running or exited child process. @@ -245,6 +251,25 @@ pub struct ChildStdin { #[stable(feature = "process", since = "1.0.0")] impl Write for ChildStdin { + fn write(&mut self, buf: &[u8]) -> io::Result { + (&*self).write(buf) + } + + fn write_vectored(&mut self, bufs: &[IoSlice<'_>]) -> io::Result { + (&*self).write_vectored(bufs) + } + + fn is_write_vectored(&self) -> bool { + io::Write::is_write_vectored(&&*self) + } + + fn flush(&mut self) -> io::Result<()> { + (&*self).flush() + } +} + +#[stable(feature = "write_mt", since = "1.48.0")] +impl Write for &ChildStdin { fn write(&mut self, buf: &[u8]) -> io::Result { self.inner.write(buf) } @@ -318,7 +343,8 @@ impl Read for ChildStdout { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } @@ -378,7 +404,8 @@ impl Read for ChildStderr { #[inline] unsafe fn initializer(&self) -> Initializer { - Initializer::nop() + // SAFETY: Read is guaranteed to work on uninitialized memory + unsafe { Initializer::nop() } } } @@ -869,6 +896,98 @@ impl Command { .map(Child::from_inner) .and_then(|mut p| p.wait()) } + + /// Returns the path to the program that was given to [`Command::new`]. + /// + /// # 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")] + pub fn get_program(&self) -> &OsStr { + self.inner.get_program() + } + + /// Returns an iterator of the arguments that will be passed to the program. + /// + /// This does not include the path to the program as the first argument; + /// it only includes the arguments specified with [`Command::arg`] and + /// [`Command::args`]. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("echo"); + /// cmd.arg("first").arg("second"); + /// let args: Vec<&OsStr> = cmd.get_args().collect(); + /// assert_eq!(args, &["first", "second"]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { inner: self.inner.get_args() } + } + + /// Returns an iterator of the environment variables that will be set when + /// the process is spawned. + /// + /// Each element is a tuple `(&OsStr, Option<&OsStr>)`, where the first + /// value is the key, and the second is the value, which is [`None`] if + /// the environment variable is to be explicitly removed. + /// + /// This only includes environment variables explicitly set with + /// [`Command::env`], [`Command::envs`], and [`Command::env_remove`]. It + /// does not include environment variables that will be inherited by the + /// child process. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::ffi::OsStr; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// cmd.env("TERM", "dumb").env_remove("TZ"); + /// let envs: Vec<(&OsStr, Option<&OsStr>)> = cmd.get_envs().collect(); + /// assert_eq!(envs, &[ + /// (OsStr::new("TERM"), Some(OsStr::new("dumb"))), + /// (OsStr::new("TZ"), None) + /// ]); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.inner.get_envs() + } + + /// Returns the working directory for the child process. + /// + /// This returns [`None`] if the working directory will not be changed. + /// + /// # Examples + /// + /// ``` + /// # #![feature(command_access)] + /// use std::path::Path; + /// use std::process::Command; + /// + /// let mut cmd = Command::new("ls"); + /// assert_eq!(cmd.get_current_dir(), None); + /// cmd.current_dir("/bin"); + /// assert_eq!(cmd.get_current_dir(), Some(Path::new("/bin"))); + /// ``` + #[unstable(feature = "command_access", issue = "44434")] + pub fn get_current_dir(&self) -> Option<&Path> { + self.inner.get_current_dir() + } } #[stable(feature = "rust1", since = "1.0.0")] @@ -893,6 +1012,37 @@ impl AsInnerMut for Command { } } +/// An iterator over the command arguments. +/// +/// This struct is created by [`Command::get_args`]. See its documentation for +/// more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandArgs<'a> { + inner: imp::CommandArgs<'a>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.inner.next() + } + fn size_hint(&self) -> (usize, Option) { + self.inner.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.inner.len() + } + fn is_empty(&self) -> bool { + self.inner.is_empty() + } +} + /// The output of a finished process. /// /// This is returned in a Result by either the [`output`] method of a @@ -1702,411 +1852,3 @@ impl Termination for ExitCode { self.0.as_i32() } } - -#[cfg(all(test, not(any(target_os = "cloudabi", target_os = "emscripten", target_env = "sgx"))))] -mod tests { - use crate::io::prelude::*; - - use super::{Command, Output, Stdio}; - use crate::io::ErrorKind; - use crate::str; - - // FIXME(#10380) these tests should not all be ignored on android. - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn smoke() { - let p = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 0"]).spawn() - } else { - Command::new("true").spawn() - }; - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().success()); - } - - #[test] - #[cfg_attr(target_os = "android", ignore)] - fn smoke_failure() { - match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { - Ok(..) => panic!(), - Err(..) => {} - } - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn exit_reported_right() { - let p = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn() - } else { - Command::new("false").spawn() - }; - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.wait().unwrap().code() == Some(1)); - drop(p.wait()); - } - - #[test] - #[cfg(unix)] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn signal_reported_right() { - use crate::os::unix::process::ExitStatusExt; - - let mut p = - Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap(); - p.kill().unwrap(); - match p.wait().unwrap().signal() { - Some(9) => {} - result => panic!("not terminated by signal 9 (instead, {:?})", result), - } - } - - pub fn run_output(mut cmd: Command) -> String { - let p = cmd.spawn(); - assert!(p.is_ok()); - let mut p = p.unwrap(); - assert!(p.stdout.is_some()); - let mut ret = String::new(); - p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap(); - assert!(p.wait().unwrap().success()); - return ret; - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn stdout_works() { - if cfg!(target_os = "windows") { - let mut cmd = Command::new("cmd"); - cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "foobar\r\n"); - } else { - let mut cmd = Command::new("echo"); - cmd.arg("foobar").stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "foobar\n"); - } - } - - #[test] - #[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] - fn set_current_dir_works() { - let mut cmd = Command::new("/bin/sh"); - cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped()); - assert_eq!(run_output(cmd), "/\n"); - } - - #[test] - #[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] - fn stdin_works() { - let mut p = Command::new("/bin/sh") - .arg("-c") - .arg("read line; echo $line") - .stdin(Stdio::piped()) - .stdout(Stdio::piped()) - .spawn() - .unwrap(); - p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); - drop(p.stdin.take()); - let mut out = String::new(); - p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap(); - assert!(p.wait().unwrap().success()); - assert_eq!(out, "foobar\n"); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_process_status() { - let mut status = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() - } else { - Command::new("false").status().unwrap() - }; - assert!(status.code() == Some(1)); - - status = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap() - } else { - Command::new("true").status().unwrap() - }; - assert!(status.success()); - } - - #[test] - fn test_process_output_fail_to_start() { - match Command::new("/no-binary-by-this-name-should-exist").output() { - Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), - Ok(..) => panic!(), - } - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_process_output_output() { - let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() - } else { - Command::new("echo").arg("hello").output().unwrap() - }; - let output_str = str::from_utf8(&stdout).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - assert_eq!(stderr, Vec::new()); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_process_output_error() { - let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() - } else { - Command::new("mkdir").arg("./").output().unwrap() - }; - - assert!(status.code() == Some(1)); - assert_eq!(stdout, Vec::new()); - assert!(!stderr.is_empty()); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_finish_once() { - let mut prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() - } else { - Command::new("false").spawn().unwrap() - }; - assert!(prog.wait().unwrap().code() == Some(1)); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_finish_twice() { - let mut prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() - } else { - Command::new("false").spawn().unwrap() - }; - assert!(prog.wait().unwrap().code() == Some(1)); - assert!(prog.wait().unwrap().code() == Some(1)); - } - - #[test] - #[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] - fn test_wait_with_output_once() { - let prog = if cfg!(target_os = "windows") { - Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() - } else { - Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap() - }; - - let Output { status, stdout, stderr } = prog.wait_with_output().unwrap(); - let output_str = str::from_utf8(&stdout).unwrap(); - - assert!(status.success()); - assert_eq!(output_str.trim().to_string(), "hello"); - assert_eq!(stderr, Vec::new()); - } - - #[cfg(all(unix, not(target_os = "android")))] - pub fn env_cmd() -> Command { - Command::new("env") - } - #[cfg(target_os = "android")] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("/system/bin/sh"); - cmd.arg("-c").arg("set"); - cmd - } - - #[cfg(windows)] - pub fn env_cmd() -> Command { - let mut cmd = Command::new("cmd"); - cmd.arg("/c").arg("set"); - cmd - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_override_env() { - use crate::env; - - // In some build environments (such as chrooted Nix builds), `env` can - // only be found in the explicitly-provided PATH env variable, not in - // default places such as /bin or /usr/bin. So we need to pass through - // PATH to our sub-process. - let mut cmd = env_cmd(); - cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); - if let Some(p) = env::var_os("PATH") { - cmd.env("PATH", &p); - } - let result = cmd.output().unwrap(); - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!( - output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", - output - ); - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_add_to_env() { - let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!( - output.contains("RUN_TEST_NEW_ENV=123"), - "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", - output - ); - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_capture_env_at_spawn() { - use crate::env; - - let mut cmd = env_cmd(); - cmd.env("RUN_TEST_NEW_ENV1", "123"); - - // This variable will not be present if the environment has already - // been captured above. - env::set_var("RUN_TEST_NEW_ENV2", "456"); - let result = cmd.output().unwrap(); - env::remove_var("RUN_TEST_NEW_ENV2"); - - let output = String::from_utf8_lossy(&result.stdout).to_string(); - - assert!( - output.contains("RUN_TEST_NEW_ENV1=123"), - "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", - output - ); - assert!( - output.contains("RUN_TEST_NEW_ENV2=456"), - "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", - output - ); - } - - // Regression tests for #30858. - #[test] - fn test_interior_nul_in_progname_is_error() { - match Command::new("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_arg_is_error() { - match Command::new("echo").arg("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_args_is_error() { - match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - fn test_interior_nul_in_current_dir_is_error() { - match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - // Regression tests for #30862. - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_interior_nul_in_env_key_is_error() { - match env_cmd().env("has-some-\0\0s-inside", "value").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - #[test] - #[cfg_attr(target_os = "vxworks", ignore)] - fn test_interior_nul_in_env_value_is_error() { - match env_cmd().env("key", "has-some-\0\0s-inside").spawn() { - Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), - Ok(_) => panic!(), - } - } - - /// Tests that process creation flags work by debugging a process. - /// Other creation flags make it hard or impossible to detect - /// behavioral changes in the process. - #[test] - #[cfg(windows)] - fn test_creation_flags() { - use crate::os::windows::process::CommandExt; - use crate::sys::c::{BOOL, DWORD, INFINITE}; - #[repr(C, packed)] - struct DEBUG_EVENT { - pub event_code: DWORD, - pub process_id: DWORD, - pub thread_id: DWORD, - // This is a union in the real struct, but we don't - // need this data for the purposes of this test. - pub _junk: [u8; 164], - } - - extern "system" { - fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; - fn ContinueDebugEvent( - dwProcessId: DWORD, - dwThreadId: DWORD, - dwContinueStatus: DWORD, - ) -> BOOL; - } - - const DEBUG_PROCESS: DWORD = 1; - const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; - const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; - - let mut child = Command::new("cmd") - .creation_flags(DEBUG_PROCESS) - .stdin(Stdio::piped()) - .spawn() - .unwrap(); - child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); - let mut events = 0; - let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] }; - loop { - if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { - panic!("WaitForDebugEvent failed!"); - } - events += 1; - - if event.event_code == EXIT_PROCESS_DEBUG_EVENT { - break; - } - - if unsafe { - ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED) - } == 0 - { - panic!("ContinueDebugEvent failed!"); - } - } - assert!(events > 0); - } - - #[test] - fn test_command_implements_send_sync() { - fn take_send_sync_type(_: T) {} - take_send_sync_type(Command::new("")) - } -} diff --git a/library/std/src/process/tests.rs b/library/std/src/process/tests.rs new file mode 100644 index 0000000000..05e093434b --- /dev/null +++ b/library/std/src/process/tests.rs @@ -0,0 +1,401 @@ +use crate::io::prelude::*; + +use super::{Command, Output, Stdio}; +use crate::io::ErrorKind; +use crate::str; + +// FIXME(#10380) these tests should not all be ignored on android. + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn smoke() { + let p = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 0"]).spawn() + } else { + Command::new("true").spawn() + }; + assert!(p.is_ok()); + let mut p = p.unwrap(); + assert!(p.wait().unwrap().success()); +} + +#[test] +#[cfg_attr(target_os = "android", ignore)] +fn smoke_failure() { + match Command::new("if-this-is-a-binary-then-the-world-has-ended").spawn() { + Ok(..) => panic!(), + Err(..) => {} + } +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn exit_reported_right() { + let p = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn() + } else { + Command::new("false").spawn() + }; + assert!(p.is_ok()); + let mut p = p.unwrap(); + assert!(p.wait().unwrap().code() == Some(1)); + drop(p.wait()); +} + +#[test] +#[cfg(unix)] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn signal_reported_right() { + use crate::os::unix::process::ExitStatusExt; + + let mut p = + Command::new("/bin/sh").arg("-c").arg("read a").stdin(Stdio::piped()).spawn().unwrap(); + p.kill().unwrap(); + match p.wait().unwrap().signal() { + Some(9) => {} + result => panic!("not terminated by signal 9 (instead, {:?})", result), + } +} + +pub fn run_output(mut cmd: Command) -> String { + let p = cmd.spawn(); + assert!(p.is_ok()); + let mut p = p.unwrap(); + assert!(p.stdout.is_some()); + let mut ret = String::new(); + p.stdout.as_mut().unwrap().read_to_string(&mut ret).unwrap(); + assert!(p.wait().unwrap().success()); + return ret; +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn stdout_works() { + if cfg!(target_os = "windows") { + let mut cmd = Command::new("cmd"); + cmd.args(&["/C", "echo foobar"]).stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "foobar\r\n"); + } else { + let mut cmd = Command::new("echo"); + cmd.arg("foobar").stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "foobar\n"); + } +} + +#[test] +#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] +fn set_current_dir_works() { + let mut cmd = Command::new("/bin/sh"); + cmd.arg("-c").arg("pwd").current_dir("/").stdout(Stdio::piped()); + assert_eq!(run_output(cmd), "/\n"); +} + +#[test] +#[cfg_attr(any(windows, target_os = "android", target_os = "vxworks"), ignore)] +fn stdin_works() { + let mut p = Command::new("/bin/sh") + .arg("-c") + .arg("read line; echo $line") + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .unwrap(); + p.stdin.as_mut().unwrap().write("foobar".as_bytes()).unwrap(); + drop(p.stdin.take()); + let mut out = String::new(); + p.stdout.as_mut().unwrap().read_to_string(&mut out).unwrap(); + assert!(p.wait().unwrap().success()); + assert_eq!(out, "foobar\n"); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_process_status() { + let mut status = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).status().unwrap() + } else { + Command::new("false").status().unwrap() + }; + assert!(status.code() == Some(1)); + + status = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 0"]).status().unwrap() + } else { + Command::new("true").status().unwrap() + }; + assert!(status.success()); +} + +#[test] +fn test_process_output_fail_to_start() { + match Command::new("/no-binary-by-this-name-should-exist").output() { + Err(e) => assert_eq!(e.kind(), ErrorKind::NotFound), + Ok(..) => panic!(), + } +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_process_output_output() { + let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "echo hello"]).output().unwrap() + } else { + Command::new("echo").arg("hello").output().unwrap() + }; + let output_str = str::from_utf8(&stdout).unwrap(); + + assert!(status.success()); + assert_eq!(output_str.trim().to_string(), "hello"); + assert_eq!(stderr, Vec::new()); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_process_output_error() { + let Output { status, stdout, stderr } = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "mkdir ."]).output().unwrap() + } else { + Command::new("mkdir").arg("./").output().unwrap() + }; + + assert!(status.code() == Some(1)); + assert_eq!(stdout, Vec::new()); + assert!(!stderr.is_empty()); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_finish_once() { + let mut prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() + } else { + Command::new("false").spawn().unwrap() + }; + assert!(prog.wait().unwrap().code() == Some(1)); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_finish_twice() { + let mut prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "exit 1"]).spawn().unwrap() + } else { + Command::new("false").spawn().unwrap() + }; + assert!(prog.wait().unwrap().code() == Some(1)); + assert!(prog.wait().unwrap().code() == Some(1)); +} + +#[test] +#[cfg_attr(any(target_os = "vxworks", target_os = "android"), ignore)] +fn test_wait_with_output_once() { + let prog = if cfg!(target_os = "windows") { + Command::new("cmd").args(&["/C", "echo hello"]).stdout(Stdio::piped()).spawn().unwrap() + } else { + Command::new("echo").arg("hello").stdout(Stdio::piped()).spawn().unwrap() + }; + + let Output { status, stdout, stderr } = prog.wait_with_output().unwrap(); + let output_str = str::from_utf8(&stdout).unwrap(); + + assert!(status.success()); + assert_eq!(output_str.trim().to_string(), "hello"); + assert_eq!(stderr, Vec::new()); +} + +#[cfg(all(unix, not(target_os = "android")))] +pub fn env_cmd() -> Command { + Command::new("env") +} +#[cfg(target_os = "android")] +pub fn env_cmd() -> Command { + let mut cmd = Command::new("/system/bin/sh"); + cmd.arg("-c").arg("set"); + cmd +} + +#[cfg(windows)] +pub fn env_cmd() -> Command { + let mut cmd = Command::new("cmd"); + cmd.arg("/c").arg("set"); + cmd +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_override_env() { + use crate::env; + + // In some build environments (such as chrooted Nix builds), `env` can + // only be found in the explicitly-provided PATH env variable, not in + // default places such as /bin or /usr/bin. So we need to pass through + // PATH to our sub-process. + let mut cmd = env_cmd(); + cmd.env_clear().env("RUN_TEST_NEW_ENV", "123"); + if let Some(p) = env::var_os("PATH") { + cmd.env("PATH", &p); + } + let result = cmd.output().unwrap(); + let output = String::from_utf8_lossy(&result.stdout).to_string(); + + assert!( + output.contains("RUN_TEST_NEW_ENV=123"), + "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", + output + ); +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_add_to_env() { + let result = env_cmd().env("RUN_TEST_NEW_ENV", "123").output().unwrap(); + let output = String::from_utf8_lossy(&result.stdout).to_string(); + + assert!( + output.contains("RUN_TEST_NEW_ENV=123"), + "didn't find RUN_TEST_NEW_ENV inside of:\n\n{}", + output + ); +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_capture_env_at_spawn() { + use crate::env; + + let mut cmd = env_cmd(); + cmd.env("RUN_TEST_NEW_ENV1", "123"); + + // This variable will not be present if the environment has already + // been captured above. + env::set_var("RUN_TEST_NEW_ENV2", "456"); + let result = cmd.output().unwrap(); + env::remove_var("RUN_TEST_NEW_ENV2"); + + let output = String::from_utf8_lossy(&result.stdout).to_string(); + + assert!( + output.contains("RUN_TEST_NEW_ENV1=123"), + "didn't find RUN_TEST_NEW_ENV1 inside of:\n\n{}", + output + ); + assert!( + output.contains("RUN_TEST_NEW_ENV2=456"), + "didn't find RUN_TEST_NEW_ENV2 inside of:\n\n{}", + output + ); +} + +// Regression tests for #30858. +#[test] +fn test_interior_nul_in_progname_is_error() { + match Command::new("has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +fn test_interior_nul_in_arg_is_error() { + match Command::new("echo").arg("has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +fn test_interior_nul_in_args_is_error() { + match Command::new("echo").args(&["has-some-\0\0s-inside"]).spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +fn test_interior_nul_in_current_dir_is_error() { + match Command::new("echo").current_dir("has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +// Regression tests for #30862. +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_interior_nul_in_env_key_is_error() { + match env_cmd().env("has-some-\0\0s-inside", "value").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +#[test] +#[cfg_attr(target_os = "vxworks", ignore)] +fn test_interior_nul_in_env_value_is_error() { + match env_cmd().env("key", "has-some-\0\0s-inside").spawn() { + Err(e) => assert_eq!(e.kind(), ErrorKind::InvalidInput), + Ok(_) => panic!(), + } +} + +/// Tests that process creation flags work by debugging a process. +/// Other creation flags make it hard or impossible to detect +/// behavioral changes in the process. +#[test] +#[cfg(windows)] +fn test_creation_flags() { + use crate::os::windows::process::CommandExt; + use crate::sys::c::{BOOL, DWORD, INFINITE}; + #[repr(C, packed)] + struct DEBUG_EVENT { + pub event_code: DWORD, + pub process_id: DWORD, + pub thread_id: DWORD, + // This is a union in the real struct, but we don't + // need this data for the purposes of this test. + pub _junk: [u8; 164], + } + + extern "system" { + fn WaitForDebugEvent(lpDebugEvent: *mut DEBUG_EVENT, dwMilliseconds: DWORD) -> BOOL; + fn ContinueDebugEvent( + dwProcessId: DWORD, + dwThreadId: DWORD, + dwContinueStatus: DWORD, + ) -> BOOL; + } + + const DEBUG_PROCESS: DWORD = 1; + const EXIT_PROCESS_DEBUG_EVENT: DWORD = 5; + const DBG_EXCEPTION_NOT_HANDLED: DWORD = 0x80010001; + + let mut child = + Command::new("cmd").creation_flags(DEBUG_PROCESS).stdin(Stdio::piped()).spawn().unwrap(); + child.stdin.take().unwrap().write_all(b"exit\r\n").unwrap(); + let mut events = 0; + let mut event = DEBUG_EVENT { event_code: 0, process_id: 0, thread_id: 0, _junk: [0; 164] }; + loop { + if unsafe { WaitForDebugEvent(&mut event as *mut DEBUG_EVENT, INFINITE) } == 0 { + panic!("WaitForDebugEvent failed!"); + } + events += 1; + + if event.event_code == EXIT_PROCESS_DEBUG_EVENT { + break; + } + + if unsafe { + ContinueDebugEvent(event.process_id, event.thread_id, DBG_EXCEPTION_NOT_HANDLED) + } == 0 + { + panic!("ContinueDebugEvent failed!"); + } + } + assert!(events > 0); +} + +#[test] +fn test_command_implements_send_sync() { + fn take_send_sync_type(_: T) {} + take_send_sync_type(Command::new("")) +} diff --git a/library/std/src/sync/barrier.rs b/library/std/src/sync/barrier.rs index 23c989fd2f..eab26b6c71 100644 --- a/library/std/src/sync/barrier.rs +++ b/library/std/src/sync/barrier.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::fmt; use crate::sync::{Condvar, Mutex}; @@ -13,7 +16,7 @@ use crate::sync::{Condvar, Mutex}; /// let mut handles = Vec::with_capacity(10); /// let barrier = Arc::new(Barrier::new(10)); /// for _ in 0..10 { -/// let c = barrier.clone(); +/// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. /// handles.push(thread::spawn(move|| { @@ -40,11 +43,8 @@ struct BarrierState { generation_id: usize, } -/// A `BarrierWaitResult` is returned by [`wait`] when all threads in the [`Barrier`] -/// have rendezvoused. -/// -/// [`wait`]: struct.Barrier.html#method.wait -/// [`Barrier`]: struct.Barrier.html +/// A `BarrierWaitResult` is returned by [`Barrier::wait()`] when all threads +/// in the [`Barrier`] have rendezvoused. /// /// # Examples /// @@ -67,10 +67,10 @@ impl fmt::Debug for Barrier { impl Barrier { /// Creates a new barrier that can block a given number of threads. /// - /// A barrier will block `n`-1 threads which call [`wait`] and then wake up - /// all threads at once when the `n`th thread calls [`wait`]. + /// A barrier will block `n`-1 threads which call [`wait()`] and then wake + /// up all threads at once when the `n`th thread calls [`wait()`]. /// - /// [`wait`]: #method.wait + /// [`wait()`]: Barrier::wait /// /// # Examples /// @@ -94,12 +94,9 @@ impl Barrier { /// be used continuously. /// /// A single (arbitrary) thread will receive a [`BarrierWaitResult`] that - /// returns `true` from [`is_leader`] when returning from this function, and - /// all other threads will receive a result that will return `false` from - /// [`is_leader`]. - /// - /// [`BarrierWaitResult`]: struct.BarrierWaitResult.html - /// [`is_leader`]: struct.BarrierWaitResult.html#method.is_leader + /// returns `true` from [`BarrierWaitResult::is_leader()`] when returning + /// from this function, and all other threads will receive a result that + /// will return `false` from [`BarrierWaitResult::is_leader()`]. /// /// # Examples /// @@ -110,7 +107,7 @@ impl Barrier { /// let mut handles = Vec::with_capacity(10); /// let barrier = Arc::new(Barrier::new(10)); /// for _ in 0..10 { - /// let c = barrier.clone(); + /// let c = Arc::clone(&barrier); /// // The same messages will be printed together. /// // You will NOT see any interleaving. /// handles.push(thread::spawn(move|| { @@ -153,13 +150,12 @@ impl fmt::Debug for BarrierWaitResult { } impl BarrierWaitResult { - /// Returns `true` if this thread from [`wait`] is the "leader thread". + /// Returns `true` if this thread is the "leader thread" for the call to + /// [`Barrier::wait()`]. /// /// Only one thread will have `true` returned from their result, all other /// threads will have `false` returned. /// - /// [`wait`]: struct.Barrier.html#method.wait - /// /// # Examples /// /// ``` @@ -174,42 +170,3 @@ impl BarrierWaitResult { self.0 } } - -#[cfg(test)] -mod tests { - use crate::sync::mpsc::{channel, TryRecvError}; - use crate::sync::{Arc, Barrier}; - use crate::thread; - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn test_barrier() { - const N: usize = 10; - - let barrier = Arc::new(Barrier::new(N)); - let (tx, rx) = channel(); - - for _ in 0..N - 1 { - let c = barrier.clone(); - let tx = tx.clone(); - thread::spawn(move || { - tx.send(c.wait().is_leader()).unwrap(); - }); - } - - // At this point, all spawned threads should be blocked, - // so we shouldn't get anything from the port - assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty))); - - let mut leader_found = barrier.wait().is_leader(); - - // Now, the barrier is cleared and we should get data. - for _ in 0..N - 1 { - if rx.recv().unwrap() { - assert!(!leader_found); - leader_found = true; - } - } - assert!(leader_found); - } -} diff --git a/library/std/src/sync/barrier/tests.rs b/library/std/src/sync/barrier/tests.rs new file mode 100644 index 0000000000..834a3e7515 --- /dev/null +++ b/library/std/src/sync/barrier/tests.rs @@ -0,0 +1,35 @@ +use crate::sync::mpsc::{channel, TryRecvError}; +use crate::sync::{Arc, Barrier}; +use crate::thread; + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn test_barrier() { + const N: usize = 10; + + let barrier = Arc::new(Barrier::new(N)); + let (tx, rx) = channel(); + + for _ in 0..N - 1 { + let c = barrier.clone(); + let tx = tx.clone(); + thread::spawn(move || { + tx.send(c.wait().is_leader()).unwrap(); + }); + } + + // At this point, all spawned threads should be blocked, + // so we shouldn't get anything from the port + assert!(matches!(rx.try_recv(), Err(TryRecvError::Empty))); + + let mut leader_found = barrier.wait().is_leader(); + + // Now, the barrier is cleared and we should get data. + for _ in 0..N - 1 { + if rx.recv().unwrap() { + assert!(!leader_found); + leader_found = true; + } + } + assert!(leader_found); +} diff --git a/library/std/src/sync/condvar.rs b/library/std/src/sync/condvar.rs index 4efd86aa3e..1376d8ebe8 100644 --- a/library/std/src/sync/condvar.rs +++ b/library/std/src/sync/condvar.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::fmt; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sync::{mutex, MutexGuard, PoisonError}; @@ -33,7 +36,7 @@ impl WaitTimeoutResult { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move || { /// let (lock, cvar) = &*pair2; @@ -75,13 +78,9 @@ impl WaitTimeoutResult { /// and a mutex. The predicate is always verified inside of the mutex before /// determining that a thread must block. /// -/// Functions in this module will block the current **thread** of execution and -/// are bindings to system-provided condition variables where possible. Note -/// that this module places one additional restriction over the system condition -/// variables: each condvar can be used with precisely one mutex at runtime. Any -/// attempt to use multiple mutexes on the same condition variable will result -/// in a runtime panic. If this is not desired, then the unsafe primitives in -/// `sys` do not have this restriction but may result in undefined behavior. +/// Functions in this module will block the current **thread** of execution. +/// Note that any attempt to use multiple mutexes on the same condition +/// variable may result in a runtime panic. /// /// # Examples /// @@ -90,7 +89,7 @@ impl WaitTimeoutResult { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); -/// let pair2 = pair.clone(); +/// let pair2 = Arc::clone(&pair); /// /// // Inside of our lock, spawn a new thread, and then wait for it to start. /// thread::spawn(move|| { @@ -156,10 +155,8 @@ impl Condvar { /// /// # Panics /// - /// This function will [`panic!`] if it is used with more than one mutex - /// over time. Each condition variable is dynamically bound to exactly one - /// mutex to ensure defined behavior across platforms. If this functionality - /// is not desired, then unsafe primitives in `sys` are provided. + /// This function may [`panic!`] if it is used with more than one mutex + /// over time. /// /// [`notify_one`]: Self::notify_one /// [`notify_all`]: Self::notify_all @@ -173,7 +170,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -229,7 +226,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(true), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -288,7 +285,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -360,7 +357,7 @@ impl Condvar { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -429,7 +426,7 @@ impl Condvar { /// use std::time::Duration; /// /// let pair = Arc::new((Mutex::new(true), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -493,7 +490,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -533,7 +530,7 @@ impl Condvar { /// use std::thread; /// /// let pair = Arc::new((Mutex::new(false), Condvar::new())); - /// let pair2 = pair.clone(); + /// let pair2 = Arc::clone(&pair); /// /// thread::spawn(move|| { /// let (lock, cvar) = &*pair2; @@ -556,8 +553,8 @@ impl Condvar { unsafe { self.inner.notify_all() } } - fn verify(&self, mutex: &sys_mutex::Mutex) { - let addr = mutex as *const _ as usize; + fn verify(&self, mutex: &sys_mutex::MovableMutex) { + let addr = mutex.raw() as *const _ as usize; match self.mutex.compare_and_swap(0, addr, Ordering::SeqCst) { // If we got out 0, then we have successfully bound the mutex to // this cvar. @@ -598,218 +595,3 @@ impl Drop for Condvar { unsafe { self.inner.destroy() } } } - -#[cfg(test)] -mod tests { - use crate::sync::atomic::{AtomicBool, Ordering}; - use crate::sync::mpsc::channel; - use crate::sync::{Arc, Condvar, Mutex}; - use crate::thread; - use crate::time::Duration; - - #[test] - fn smoke() { - let c = Condvar::new(); - c.notify_one(); - c.notify_all(); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn notify_one() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let g = m.lock().unwrap(); - let _t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - let g = c.wait(g).unwrap(); - drop(g); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn notify_all() { - const N: usize = 10; - - let data = Arc::new((Mutex::new(0), Condvar::new())); - let (tx, rx) = channel(); - for _ in 0..N { - let data = data.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock().unwrap(); - *cnt += 1; - if *cnt == N { - tx.send(()).unwrap(); - } - while *cnt != 0 { - cnt = cond.wait(cnt).unwrap(); - } - tx.send(()).unwrap(); - }); - } - drop(tx); - - let &(ref lock, ref cond) = &*data; - rx.recv().unwrap(); - let mut cnt = lock.lock().unwrap(); - *cnt = 0; - cond.notify_all(); - drop(cnt); - - for _ in 0..N { - rx.recv().unwrap(); - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_while() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair2 = pair.clone(); - - // Inside of our lock, spawn a new thread, and then wait for it to start. - thread::spawn(move || { - let &(ref lock, ref cvar) = &*pair2; - let mut started = lock.lock().unwrap(); - *started = true; - // We notify the condvar that the value has changed. - cvar.notify_one(); - }); - - // Wait for the thread to start up. - let &(ref lock, ref cvar) = &*pair; - let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started); - assert!(*guard.unwrap()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_wait() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - loop { - let g = m.lock().unwrap(); - let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); - // spurious wakeups mean this isn't necessarily true - // so execute test again, if not timeout - if !no_timeout.timed_out() { - continue; - } - - break; - } - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_while_wait() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap(); - // no spurious wakeups. ensure it timed-out - assert!(wait.timed_out()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_while_instant_satisfy() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let g = m.lock().unwrap(); - let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap(); - // ensure it didn't time-out even if we were not given any time. - assert!(!wait.timed_out()); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_while_wake() { - let pair = Arc::new((Mutex::new(false), Condvar::new())); - let pair_copy = pair.clone(); - - let &(ref m, ref c) = &*pair; - let g = m.lock().unwrap(); - let _t = thread::spawn(move || { - let &(ref lock, ref cvar) = &*pair_copy; - let mut started = lock.lock().unwrap(); - thread::sleep(Duration::from_millis(1)); - *started = true; - cvar.notify_one(); - }); - let (g2, wait) = c - .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified) - .unwrap(); - // ensure it didn't time-out even if we were not given any time. - assert!(!wait.timed_out()); - assert!(*g2); - } - - #[test] - #[cfg_attr(target_os = "emscripten", ignore)] - fn wait_timeout_wake() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - loop { - let g = m.lock().unwrap(); - - let c2 = c.clone(); - let m2 = m.clone(); - - let notified = Arc::new(AtomicBool::new(false)); - let notified_copy = notified.clone(); - - let t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - thread::sleep(Duration::from_millis(1)); - notified_copy.store(true, Ordering::SeqCst); - c2.notify_one(); - }); - let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap(); - assert!(!timeout_res.timed_out()); - // spurious wakeups mean this isn't necessarily true - // so execute test again, if not notified - if !notified.load(Ordering::SeqCst) { - t.join().unwrap(); - continue; - } - drop(g); - - t.join().unwrap(); - - break; - } - } - - #[test] - #[should_panic] - #[cfg_attr(target_os = "emscripten", ignore)] - fn two_mutexes() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock().unwrap(); - let _t = thread::spawn(move || { - let _g = m2.lock().unwrap(); - c2.notify_one(); - }); - g = c.wait(g).unwrap(); - drop(g); - - let m = Mutex::new(()); - let _ = c.wait(m.lock().unwrap()).unwrap(); - } -} diff --git a/library/std/src/sync/condvar/tests.rs b/library/std/src/sync/condvar/tests.rs new file mode 100644 index 0000000000..86d099ee3a --- /dev/null +++ b/library/std/src/sync/condvar/tests.rs @@ -0,0 +1,211 @@ +use crate::sync::atomic::{AtomicBool, Ordering}; +use crate::sync::mpsc::channel; +use crate::sync::{Arc, Condvar, Mutex}; +use crate::thread; +use crate::time::Duration; + +#[test] +fn smoke() { + let c = Condvar::new(); + c.notify_one(); + c.notify_all(); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn notify_one() { + let m = Arc::new(Mutex::new(())); + let m2 = m.clone(); + let c = Arc::new(Condvar::new()); + let c2 = c.clone(); + + let g = m.lock().unwrap(); + let _t = thread::spawn(move || { + let _g = m2.lock().unwrap(); + c2.notify_one(); + }); + let g = c.wait(g).unwrap(); + drop(g); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn notify_all() { + const N: usize = 10; + + let data = Arc::new((Mutex::new(0), Condvar::new())); + let (tx, rx) = channel(); + for _ in 0..N { + let data = data.clone(); + let tx = tx.clone(); + thread::spawn(move || { + let &(ref lock, ref cond) = &*data; + let mut cnt = lock.lock().unwrap(); + *cnt += 1; + if *cnt == N { + tx.send(()).unwrap(); + } + while *cnt != 0 { + cnt = cond.wait(cnt).unwrap(); + } + tx.send(()).unwrap(); + }); + } + drop(tx); + + let &(ref lock, ref cond) = &*data; + rx.recv().unwrap(); + let mut cnt = lock.lock().unwrap(); + *cnt = 0; + cond.notify_all(); + drop(cnt); + + for _ in 0..N { + rx.recv().unwrap(); + } +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_while() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair2 = pair.clone(); + + // Inside of our lock, spawn a new thread, and then wait for it to start. + thread::spawn(move || { + let &(ref lock, ref cvar) = &*pair2; + let mut started = lock.lock().unwrap(); + *started = true; + // We notify the condvar that the value has changed. + cvar.notify_one(); + }); + + // Wait for the thread to start up. + let &(ref lock, ref cvar) = &*pair; + let guard = cvar.wait_while(lock.lock().unwrap(), |started| !*started); + assert!(*guard.unwrap()); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_wait() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + loop { + let g = m.lock().unwrap(); + let (_g, no_timeout) = c.wait_timeout(g, Duration::from_millis(1)).unwrap(); + // spurious wakeups mean this isn't necessarily true + // so execute test again, if not timeout + if !no_timeout.timed_out() { + continue; + } + + break; + } +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_while_wait() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(1), |_| true).unwrap(); + // no spurious wakeups. ensure it timed-out + assert!(wait.timed_out()); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_while_instant_satisfy() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + let g = m.lock().unwrap(); + let (_g, wait) = c.wait_timeout_while(g, Duration::from_millis(0), |_| false).unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_while_wake() { + let pair = Arc::new((Mutex::new(false), Condvar::new())); + let pair_copy = pair.clone(); + + let &(ref m, ref c) = &*pair; + let g = m.lock().unwrap(); + let _t = thread::spawn(move || { + let &(ref lock, ref cvar) = &*pair_copy; + let mut started = lock.lock().unwrap(); + thread::sleep(Duration::from_millis(1)); + *started = true; + cvar.notify_one(); + }); + let (g2, wait) = c + .wait_timeout_while(g, Duration::from_millis(u64::MAX), |&mut notified| !notified) + .unwrap(); + // ensure it didn't time-out even if we were not given any time. + assert!(!wait.timed_out()); + assert!(*g2); +} + +#[test] +#[cfg_attr(target_os = "emscripten", ignore)] +fn wait_timeout_wake() { + let m = Arc::new(Mutex::new(())); + let c = Arc::new(Condvar::new()); + + loop { + let g = m.lock().unwrap(); + + let c2 = c.clone(); + let m2 = m.clone(); + + let notified = Arc::new(AtomicBool::new(false)); + let notified_copy = notified.clone(); + + let t = thread::spawn(move || { + let _g = m2.lock().unwrap(); + thread::sleep(Duration::from_millis(1)); + notified_copy.store(true, Ordering::SeqCst); + c2.notify_one(); + }); + let (g, timeout_res) = c.wait_timeout(g, Duration::from_millis(u64::MAX)).unwrap(); + assert!(!timeout_res.timed_out()); + // spurious wakeups mean this isn't necessarily true + // so execute test again, if not notified + if !notified.load(Ordering::SeqCst) { + t.join().unwrap(); + continue; + } + drop(g); + + t.join().unwrap(); + + break; + } +} + +#[test] +#[should_panic] +#[cfg_attr(target_os = "emscripten", ignore)] +fn two_mutexes() { + let m = Arc::new(Mutex::new(())); + let m2 = m.clone(); + let c = Arc::new(Condvar::new()); + let c2 = c.clone(); + + let mut g = m.lock().unwrap(); + let _t = thread::spawn(move || { + let _g = m2.lock().unwrap(); + c2.notify_one(); + }); + g = c.wait(g).unwrap(); + drop(g); + + let m = Mutex::new(()); + let _ = c.wait(m.lock().unwrap()).unwrap(); +} diff --git a/library/std/src/sync/mpsc/mod.rs b/library/std/src/sync/mpsc/mod.rs index ac83017d9e..dc13c9433f 100644 --- a/library/std/src/sync/mpsc/mod.rs +++ b/library/std/src/sync/mpsc/mod.rs @@ -108,6 +108,12 @@ #![stable(feature = "rust1", since = "1.0.0")] +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +#[cfg(all(test, not(target_os = "emscripten")))] +mod sync_tests; + // A description of how Rust's channel implementation works // // Channels are supposed to be the basic building block for all other @@ -1525,6 +1531,11 @@ impl error::Error for TrySendError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From> for TrySendError { + /// Converts a `SendError` into a `TrySendError`. + /// + /// This conversion always returns a `TrySendError::Disconnected` containing the data in the `SendError`. + /// + /// No data is allocated on the heap. fn from(err: SendError) -> TrySendError { match err { SendError(t) => TrySendError::Disconnected(t), @@ -1570,6 +1581,11 @@ impl error::Error for TryRecvError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for TryRecvError { + /// Converts a `RecvError` into a `TryRecvError`. + /// + /// This conversion always returns `TryRecvError::Disconnected`. + /// + /// No data is allocated on the heap. fn from(err: RecvError) -> TryRecvError { match err { RecvError => TryRecvError::Disconnected, @@ -1600,1370 +1616,14 @@ impl error::Error for RecvTimeoutError { #[stable(feature = "mpsc_error_conversions", since = "1.24.0")] impl From for RecvTimeoutError { + /// Converts a `RecvError` into a `RecvTimeoutError`. + /// + /// This conversion always returns `RecvTimeoutError::Disconnected`. + /// + /// No data is allocated on the heap. fn from(err: RecvError) -> RecvTimeoutError { match err { RecvError => RecvTimeoutError::Disconnected, } } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::*; - use crate::env; - use crate::thread; - use crate::time::{Duration, Instant}; - - pub fn stress_factor() -> usize { - match env::var("RUST_TEST_STRESS") { - Ok(val) => val.parse().unwrap(), - Err(..) => 1, - } - } - - #[test] - fn smoke() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn drop_full() { - let (tx, _rx) = channel::>(); - tx.send(box 1).unwrap(); - } - - #[test] - fn drop_full_shared() { - let (tx, _rx) = channel::>(); - drop(tx.clone()); - drop(tx.clone()); - tx.send(box 1).unwrap(); - } - - #[test] - fn smoke_shared() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_threads() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - tx.send(1).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_port_gone() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(1).is_err()); - } - - #[test] - fn smoke_shared_port_gone() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(1).is_err()) - } - - #[test] - fn smoke_shared_port_gone2() { - let (tx, rx) = channel::(); - drop(rx); - let tx2 = tx.clone(); - drop(tx); - assert!(tx2.send(1).is_err()); - } - - #[test] - fn port_gone_concurrent() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() {} - } - - #[test] - fn port_gone_concurrent_shared() { - let (tx, rx) = channel::(); - let tx2 = tx.clone(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } - - #[test] - fn smoke_chan_gone() { - let (tx, rx) = channel::(); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn smoke_chan_gone_shared() { - let (tx, rx) = channel::<()>(); - let tx2 = tx.clone(); - drop(tx); - drop(tx2); - assert!(rx.recv().is_err()); - } - - #[test] - fn chan_gone_concurrent() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - tx.send(1).unwrap(); - tx.send(1).unwrap(); - }); - while rx.recv().is_ok() {} - } - - #[test] - fn stress() { - let (tx, rx) = channel::(); - let t = thread::spawn(move || { - for _ in 0..10000 { - tx.send(1).unwrap(); - } - }); - for _ in 0..10000 { - assert_eq!(rx.recv().unwrap(), 1); - } - t.join().ok().expect("thread panicked"); - } - - #[test] - fn stress_shared() { - const AMT: u32 = 10000; - const NTHREADS: u32 = 8; - let (tx, rx) = channel::(); - - let t = thread::spawn(move || { - for _ in 0..AMT * NTHREADS { - assert_eq!(rx.recv().unwrap(), 1); - } - match rx.try_recv() { - Ok(..) => panic!(), - _ => {} - } - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..AMT { - tx.send(1).unwrap(); - } - }); - } - drop(tx); - t.join().ok().expect("thread panicked"); - } - - #[test] - fn send_from_outside_runtime() { - let (tx1, rx1) = channel::<()>(); - let (tx2, rx2) = channel::(); - let t1 = thread::spawn(move || { - tx1.send(()).unwrap(); - for _ in 0..40 { - assert_eq!(rx2.recv().unwrap(), 1); - } - }); - rx1.recv().unwrap(); - let t2 = thread::spawn(move || { - for _ in 0..40 { - tx2.send(1).unwrap(); - } - }); - t1.join().ok().expect("thread panicked"); - t2.join().ok().expect("thread panicked"); - } - - #[test] - fn recv_from_outside_runtime() { - let (tx, rx) = channel::(); - let t = thread::spawn(move || { - for _ in 0..40 { - assert_eq!(rx.recv().unwrap(), 1); - } - }); - for _ in 0..40 { - tx.send(1).unwrap(); - } - t.join().ok().expect("thread panicked"); - } - - #[test] - fn no_runtime() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::(); - let t1 = thread::spawn(move || { - assert_eq!(rx1.recv().unwrap(), 1); - tx2.send(2).unwrap(); - }); - let t2 = thread::spawn(move || { - tx1.send(1).unwrap(); - assert_eq!(rx2.recv().unwrap(), 2); - }); - t1.join().ok().expect("thread panicked"); - t2.join().ok().expect("thread panicked"); - } - - #[test] - fn oneshot_single_thread_close_port_first() { - // Simple test of closing without sending - let (_tx, rx) = channel::(); - drop(rx); - } - - #[test] - fn oneshot_single_thread_close_chan_first() { - // Simple test of closing without sending - let (tx, _rx) = channel::(); - drop(tx); - } - - #[test] - fn oneshot_single_thread_send_port_close() { - // Testing that the sender cleans up the payload if receiver is closed - let (tx, rx) = channel::>(); - drop(rx); - assert!(tx.send(box 0).is_err()); - } - - #[test] - fn oneshot_single_thread_recv_chan_close() { - // Receiving on a closed chan will panic - let res = thread::spawn(move || { - let (tx, rx) = channel::(); - drop(tx); - rx.recv().unwrap(); - }) - .join(); - // What is our res? - assert!(res.is_err()); - } - - #[test] - fn oneshot_single_thread_send_then_recv() { - let (tx, rx) = channel::>(); - tx.send(box 10).unwrap(); - assert!(*rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_open() { - let (tx, rx) = channel::(); - assert!(tx.send(10).is_ok()); - assert!(rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_closed() { - let (tx, rx) = channel::(); - drop(rx); - assert!(tx.send(10).is_err()); - } - - #[test] - fn oneshot_single_thread_try_recv_open() { - let (tx, rx) = channel::(); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } - - #[test] - fn oneshot_single_thread_try_recv_closed() { - let (tx, rx) = channel::(); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn oneshot_single_thread_peek_data() { - let (tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); - assert_eq!(rx.try_recv(), Ok(10)); - } - - #[test] - fn oneshot_single_thread_peek_close() { - let (tx, rx) = channel::(); - drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_open() { - let (_tx, rx) = channel::(); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } - - #[test] - fn oneshot_multi_task_recv_then_send() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }); - - tx.send(box 10).unwrap(); - } - - #[test] - fn oneshot_multi_task_recv_then_close() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move || { - drop(tx); - }); - let res = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }) - .join(); - assert!(res.is_err()); - } - - #[test] - fn oneshot_multi_thread_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - drop(rx); - }); - drop(tx); - } - } - - #[test] - fn oneshot_multi_thread_send_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - let _t = thread::spawn(move || { - drop(rx); - }); - let _ = thread::spawn(move || { - tx.send(1).unwrap(); - }) - .join(); - } - } - - #[test] - fn oneshot_multi_thread_recv_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::(); - thread::spawn(move || { - let res = thread::spawn(move || { - rx.recv().unwrap(); - }) - .join(); - assert!(res.is_err()); - }); - let _t = thread::spawn(move || { - thread::spawn(move || { - drop(tx); - }); - }); - } - } - - #[test] - fn oneshot_multi_thread_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel::>(); - let _t = thread::spawn(move || { - tx.send(box 10).unwrap(); - }); - assert!(*rx.recv().unwrap() == 10); - } - } - - #[test] - fn stream_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = channel(); - - send(tx, 0); - recv(rx, 0); - - fn send(tx: Sender>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - tx.send(box i).unwrap(); - send(tx, i + 1); - }); - } - - fn recv(rx: Receiver>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - assert!(*rx.recv().unwrap() == i); - recv(rx, i + 1); - }); - } - } - } - - #[test] - fn oneshot_single_thread_recv_timeout() { - let (tx, rx) = channel(); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - } - - #[test] - fn stress_recv_timeout_two_threads() { - let (tx, rx) = channel(); - let stress = stress_factor() + 100; - let timeout = Duration::from_millis(100); - - thread::spawn(move || { - for i in 0..stress { - if i % 2 == 0 { - thread::sleep(timeout * 2); - } - tx.send(1usize).unwrap(); - } - }); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(timeout) { - Ok(n) => { - assert_eq!(n, 1usize); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, stress); - } - - #[test] - fn recv_timeout_upgrade() { - let (tx, rx) = channel::<()>(); - let timeout = Duration::from_millis(1); - let _tx_clone = tx.clone(); - - let start = Instant::now(); - assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); - assert!(Instant::now() >= start + timeout); - } - - #[test] - fn stress_recv_timeout_shared() { - let (tx, rx) = channel(); - let stress = stress_factor() + 100; - - for i in 0..stress { - let tx = tx.clone(); - thread::spawn(move || { - thread::sleep(Duration::from_millis(i as u64 * 10)); - tx.send(1usize).unwrap(); - }); - } - - drop(tx); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(10)) { - Ok(n) => { - assert_eq!(n, 1usize); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, stress); - } - - #[test] - fn very_long_recv_timeout_wont_panic() { - let (tx, rx) = channel::<()>(); - let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX))); - thread::sleep(Duration::from_secs(1)); - assert!(tx.send(()).is_ok()); - assert_eq!(join_handle.join().unwrap(), Ok(())); - } - - #[test] - fn recv_a_lot() { - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = channel(); - for _ in 0..10000 { - tx.send(()).unwrap(); - } - for _ in 0..10000 { - rx.recv().unwrap(); - } - } - - #[test] - fn shared_recv_timeout() { - let (tx, rx) = channel(); - let total = 5; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(()).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); - } - - #[test] - fn shared_chan_stress() { - let (tx, rx) = channel(); - let total = stress_factor() + 100; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - } - - #[test] - fn test_nested_recv_iter() { - let (tx, rx) = channel::(); - let (total_tx, total_rx) = channel::(); - - let _t = thread::spawn(move || { - let mut acc = 0; - for x in rx.iter() { - acc += x; - } - total_tx.send(acc).unwrap(); - }); - - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } - - #[test] - fn test_recv_iter_break() { - let (tx, rx) = channel::(); - let (count_tx, count_rx) = channel(); - - let _t = thread::spawn(move || { - let mut count = 0; - for x in rx.iter() { - if count >= 3 { - break; - } else { - count += x; - } - } - count_tx.send(count).unwrap(); - }); - - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - let _ = tx.send(2); - drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } - - #[test] - fn test_recv_try_iter() { - let (request_tx, request_rx) = channel(); - let (response_tx, response_rx) = channel(); - - // Request `x`s until we have `6`. - let t = thread::spawn(move || { - let mut count = 0; - loop { - for x in response_rx.try_iter() { - count += x; - if count == 6 { - return count; - } - } - request_tx.send(()).unwrap(); - } - }); - - for _ in request_rx.iter() { - if response_tx.send(2).is_err() { - break; - } - } - - assert_eq!(t.join().unwrap(), 6); - } - - #[test] - fn test_recv_into_iter_owned() { - let mut iter = { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - - rx.into_iter() - }; - assert_eq!(iter.next().unwrap(), 1); - assert_eq!(iter.next().unwrap(), 2); - assert_eq!(iter.next().is_none(), true); - } - - #[test] - fn test_recv_into_iter_borrowed() { - let (tx, rx) = channel::(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - let mut iter = (&rx).into_iter(); - assert_eq!(iter.next().unwrap(), 1); - assert_eq!(iter.next().unwrap(), 2); - assert_eq!(iter.next().is_none(), true); - } - - #[test] - fn try_recv_states() { - let (tx1, rx1) = channel::(); - let (tx2, rx2) = channel::<()>(); - let (tx3, rx3) = channel::<()>(); - let _t = thread::spawn(move || { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); - drop(tx1); - tx3.send(()).unwrap(); - }); - - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } - - // This bug used to end up in a livelock inside of the Receiver destructor - // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { - let (tx, rx) = channel(); - let (tx2, rx2) = channel(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); // wait on a oneshot - drop(rx); // destroy a shared - tx2.send(()).unwrap(); - }); - // make sure the other thread has gone to sleep - for _ in 0..5000 { - thread::yield_now(); - } - - // upgrade to a shared chan and send a message - let t = tx.clone(); - drop(tx); - t.send(()).unwrap(); - - // wait for the child thread to exit before we exit - rx2.recv().unwrap(); - } - - #[test] - fn issue_32114() { - let (tx, _) = channel(); - let _ = tx.send(123); - assert_eq!(tx.send(123), Err(SendError(123))); - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod sync_tests { - use super::*; - use crate::env; - use crate::thread; - use crate::time::Duration; - - pub fn stress_factor() -> usize { - match env::var("RUST_TEST_STRESS") { - Ok(val) => val.parse().unwrap(), - Err(..) => 1, - } - } - - #[test] - fn smoke() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn drop_full() { - let (tx, _rx) = sync_channel::>(1); - tx.send(box 1).unwrap(); - } - - #[test] - fn smoke_shared() { - let (tx, rx) = sync_channel::(1); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - let tx = tx.clone(); - tx.send(1).unwrap(); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn recv_timeout() { - let (tx, rx) = sync_channel::(1); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); - tx.send(1).unwrap(); - assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); - } - - #[test] - fn smoke_threads() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - tx.send(1).unwrap(); - }); - assert_eq!(rx.recv().unwrap(), 1); - } - - #[test] - fn smoke_port_gone() { - let (tx, rx) = sync_channel::(0); - drop(rx); - assert!(tx.send(1).is_err()); - } - - #[test] - fn smoke_shared_port_gone2() { - let (tx, rx) = sync_channel::(0); - drop(rx); - let tx2 = tx.clone(); - drop(tx); - assert!(tx2.send(1).is_err()); - } - - #[test] - fn port_gone_concurrent() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() {} - } - - #[test] - fn port_gone_concurrent_shared() { - let (tx, rx) = sync_channel::(0); - let tx2 = tx.clone(); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - while tx.send(1).is_ok() && tx2.send(1).is_ok() {} - } - - #[test] - fn smoke_chan_gone() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn smoke_chan_gone_shared() { - let (tx, rx) = sync_channel::<()>(0); - let tx2 = tx.clone(); - drop(tx); - drop(tx2); - assert!(rx.recv().is_err()); - } - - #[test] - fn chan_gone_concurrent() { - let (tx, rx) = sync_channel::(0); - thread::spawn(move || { - tx.send(1).unwrap(); - tx.send(1).unwrap(); - }); - while rx.recv().is_ok() {} - } - - #[test] - fn stress() { - let (tx, rx) = sync_channel::(0); - thread::spawn(move || { - for _ in 0..10000 { - tx.send(1).unwrap(); - } - }); - for _ in 0..10000 { - assert_eq!(rx.recv().unwrap(), 1); - } - } - - #[test] - fn stress_recv_timeout_two_threads() { - let (tx, rx) = sync_channel::(0); - - thread::spawn(move || { - for _ in 0..10000 { - tx.send(1).unwrap(); - } - }); - - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(1)) { - Ok(v) => { - assert_eq!(v, 1); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, 10000); - } - - #[test] - fn stress_recv_timeout_shared() { - const AMT: u32 = 1000; - const NTHREADS: u32 = 8; - let (tx, rx) = sync_channel::(0); - let (dtx, drx) = sync_channel::<()>(0); - - thread::spawn(move || { - let mut recv_count = 0; - loop { - match rx.recv_timeout(Duration::from_millis(10)) { - Ok(v) => { - assert_eq!(v, 1); - recv_count += 1; - } - Err(RecvTimeoutError::Timeout) => continue, - Err(RecvTimeoutError::Disconnected) => break, - } - } - - assert_eq!(recv_count, AMT * NTHREADS); - assert!(rx.try_recv().is_err()); - - dtx.send(()).unwrap(); - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..AMT { - tx.send(1).unwrap(); - } - }); - } - - drop(tx); - - drx.recv().unwrap(); - } - - #[test] - fn stress_shared() { - const AMT: u32 = 1000; - const NTHREADS: u32 = 8; - let (tx, rx) = sync_channel::(0); - let (dtx, drx) = sync_channel::<()>(0); - - thread::spawn(move || { - for _ in 0..AMT * NTHREADS { - assert_eq!(rx.recv().unwrap(), 1); - } - match rx.try_recv() { - Ok(..) => panic!(), - _ => {} - } - dtx.send(()).unwrap(); - }); - - for _ in 0..NTHREADS { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..AMT { - tx.send(1).unwrap(); - } - }); - } - drop(tx); - drx.recv().unwrap(); - } - - #[test] - fn oneshot_single_thread_close_port_first() { - // Simple test of closing without sending - let (_tx, rx) = sync_channel::(0); - drop(rx); - } - - #[test] - fn oneshot_single_thread_close_chan_first() { - // Simple test of closing without sending - let (tx, _rx) = sync_channel::(0); - drop(tx); - } - - #[test] - fn oneshot_single_thread_send_port_close() { - // Testing that the sender cleans up the payload if receiver is closed - let (tx, rx) = sync_channel::>(0); - drop(rx); - assert!(tx.send(box 0).is_err()); - } - - #[test] - fn oneshot_single_thread_recv_chan_close() { - // Receiving on a closed chan will panic - let res = thread::spawn(move || { - let (tx, rx) = sync_channel::(0); - drop(tx); - rx.recv().unwrap(); - }) - .join(); - // What is our res? - assert!(res.is_err()); - } - - #[test] - fn oneshot_single_thread_send_then_recv() { - let (tx, rx) = sync_channel::>(1); - tx.send(box 10).unwrap(); - assert!(*rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_open() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.try_send(10), Ok(())); - assert!(rx.recv().unwrap() == 10); - } - - #[test] - fn oneshot_single_thread_try_send_closed() { - let (tx, rx) = sync_channel::(0); - drop(rx); - assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); - } - - #[test] - fn oneshot_single_thread_try_send_closed2() { - let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); - } - - #[test] - fn oneshot_single_thread_try_recv_open() { - let (tx, rx) = sync_channel::(1); - tx.send(10).unwrap(); - assert!(rx.recv() == Ok(10)); - } - - #[test] - fn oneshot_single_thread_try_recv_closed() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert!(rx.recv().is_err()); - } - - #[test] - fn oneshot_single_thread_try_recv_closed_with_data() { - let (tx, rx) = sync_channel::(1); - tx.send(10).unwrap(); - drop(tx); - assert_eq!(rx.try_recv(), Ok(10)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_data() { - let (tx, rx) = sync_channel::(1); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - tx.send(10).unwrap(); - assert_eq!(rx.try_recv(), Ok(10)); - } - - #[test] - fn oneshot_single_thread_peek_close() { - let (tx, rx) = sync_channel::(0); - drop(tx); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); - } - - #[test] - fn oneshot_single_thread_peek_open() { - let (_tx, rx) = sync_channel::(0); - assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); - } - - #[test] - fn oneshot_multi_task_recv_then_send() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }); - - tx.send(box 10).unwrap(); - } - - #[test] - fn oneshot_multi_task_recv_then_close() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move || { - drop(tx); - }); - let res = thread::spawn(move || { - assert!(*rx.recv().unwrap() == 10); - }) - .join(); - assert!(res.is_err()); - } - - #[test] - fn oneshot_multi_thread_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - drop(rx); - }); - drop(tx); - } - } - - #[test] - fn oneshot_multi_thread_send_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - drop(rx); - }); - let _ = thread::spawn(move || { - tx.send(1).unwrap(); - }) - .join(); - } - } - - #[test] - fn oneshot_multi_thread_recv_close_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - let res = thread::spawn(move || { - rx.recv().unwrap(); - }) - .join(); - assert!(res.is_err()); - }); - let _t = thread::spawn(move || { - thread::spawn(move || { - drop(tx); - }); - }); - } - } - - #[test] - fn oneshot_multi_thread_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::>(0); - let _t = thread::spawn(move || { - tx.send(box 10).unwrap(); - }); - assert!(*rx.recv().unwrap() == 10); - } - } - - #[test] - fn stream_send_recv_stress() { - for _ in 0..stress_factor() { - let (tx, rx) = sync_channel::>(0); - - send(tx, 0); - recv(rx, 0); - - fn send(tx: SyncSender>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - tx.send(box i).unwrap(); - send(tx, i + 1); - }); - } - - fn recv(rx: Receiver>, i: i32) { - if i == 10 { - return; - } - - thread::spawn(move || { - assert!(*rx.recv().unwrap() == i); - recv(rx, i + 1); - }); - } - } - } - - #[test] - fn recv_a_lot() { - // Regression test that we don't run out of stack in scheduler context - let (tx, rx) = sync_channel(10000); - for _ in 0..10000 { - tx.send(()).unwrap(); - } - for _ in 0..10000 { - rx.recv().unwrap(); - } - } - - #[test] - fn shared_chan_stress() { - let (tx, rx) = sync_channel(0); - let total = stress_factor() + 100; - for _ in 0..total { - let tx = tx.clone(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - } - - for _ in 0..total { - rx.recv().unwrap(); - } - } - - #[test] - fn test_nested_recv_iter() { - let (tx, rx) = sync_channel::(0); - let (total_tx, total_rx) = sync_channel::(0); - - let _t = thread::spawn(move || { - let mut acc = 0; - for x in rx.iter() { - acc += x; - } - total_tx.send(acc).unwrap(); - }); - - tx.send(3).unwrap(); - tx.send(1).unwrap(); - tx.send(2).unwrap(); - drop(tx); - assert_eq!(total_rx.recv().unwrap(), 6); - } - - #[test] - fn test_recv_iter_break() { - let (tx, rx) = sync_channel::(0); - let (count_tx, count_rx) = sync_channel(0); - - let _t = thread::spawn(move || { - let mut count = 0; - for x in rx.iter() { - if count >= 3 { - break; - } else { - count += x; - } - } - count_tx.send(count).unwrap(); - }); - - tx.send(2).unwrap(); - tx.send(2).unwrap(); - tx.send(2).unwrap(); - let _ = tx.try_send(2); - drop(tx); - assert_eq!(count_rx.recv().unwrap(), 4); - } - - #[test] - fn try_recv_states() { - let (tx1, rx1) = sync_channel::(1); - let (tx2, rx2) = sync_channel::<()>(1); - let (tx3, rx3) = sync_channel::<()>(1); - let _t = thread::spawn(move || { - rx2.recv().unwrap(); - tx1.send(1).unwrap(); - tx3.send(()).unwrap(); - rx2.recv().unwrap(); - drop(tx1); - tx3.send(()).unwrap(); - }); - - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Ok(1)); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); - tx2.send(()).unwrap(); - rx3.recv().unwrap(); - assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); - } - - // This bug used to end up in a livelock inside of the Receiver destructor - // because the internal state of the Shared packet was corrupted - #[test] - fn destroy_upgraded_shared_port_when_sender_still_active() { - let (tx, rx) = sync_channel::<()>(0); - let (tx2, rx2) = sync_channel::<()>(0); - let _t = thread::spawn(move || { - rx.recv().unwrap(); // wait on a oneshot - drop(rx); // destroy a shared - tx2.send(()).unwrap(); - }); - // make sure the other thread has gone to sleep - for _ in 0..5000 { - thread::yield_now(); - } - - // upgrade to a shared chan and send a message - let t = tx.clone(); - drop(tx); - t.send(()).unwrap(); - - // wait for the child thread to exit before we exit - rx2.recv().unwrap(); - } - - #[test] - fn send1() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - rx.recv().unwrap(); - }); - assert_eq!(tx.send(1), Ok(())); - } - - #[test] - fn send2() { - let (tx, rx) = sync_channel::(0); - let _t = thread::spawn(move || { - drop(rx); - }); - assert!(tx.send(1).is_err()); - } - - #[test] - fn send3() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.send(1), Ok(())); - let _t = thread::spawn(move || { - drop(rx); - }); - assert!(tx.send(1).is_err()); - } - - #[test] - fn send4() { - let (tx, rx) = sync_channel::(0); - let tx2 = tx.clone(); - let (done, donerx) = channel(); - let done2 = done.clone(); - let _t = thread::spawn(move || { - assert!(tx.send(1).is_err()); - done.send(()).unwrap(); - }); - let _t = thread::spawn(move || { - assert!(tx2.send(2).is_err()); - done2.send(()).unwrap(); - }); - drop(rx); - donerx.recv().unwrap(); - donerx.recv().unwrap(); - } - - #[test] - fn try_send1() { - let (tx, _rx) = sync_channel::(0); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } - - #[test] - fn try_send2() { - let (tx, _rx) = sync_channel::(1); - assert_eq!(tx.try_send(1), Ok(())); - assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); - } - - #[test] - fn try_send3() { - let (tx, rx) = sync_channel::(1); - assert_eq!(tx.try_send(1), Ok(())); - drop(rx); - assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); - } - - #[test] - fn issue_15761() { - fn repro() { - let (tx1, rx1) = sync_channel::<()>(3); - let (tx2, rx2) = sync_channel::<()>(3); - - let _t = thread::spawn(move || { - rx1.recv().unwrap(); - tx2.try_send(()).unwrap(); - }); - - tx1.try_send(()).unwrap(); - rx2.recv().unwrap(); - } - - for _ in 0..100 { - repro() - } - } -} diff --git a/library/std/src/sync/mpsc/mpsc_queue.rs b/library/std/src/sync/mpsc/mpsc_queue.rs index 6e7a7be443..42bc639dc2 100644 --- a/library/std/src/sync/mpsc/mpsc_queue.rs +++ b/library/std/src/sync/mpsc/mpsc_queue.rs @@ -11,6 +11,9 @@ // http://www.1024cores.net/home/lock-free-algorithms // /queues/non-intrusive-mpsc-node-based-queue +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + pub use self::PopResult::*; use core::cell::UnsafeCell; @@ -112,54 +115,3 @@ impl Drop for Queue { } } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::{Data, Empty, Inconsistent, Queue}; - use crate::sync::mpsc::channel; - use crate::sync::Arc; - use crate::thread; - - #[test] - fn test_full() { - let q: Queue> = Queue::new(); - q.push(box 1); - q.push(box 2); - } - - #[test] - fn test() { - let nthreads = 8; - let nmsgs = 1000; - let q = Queue::new(); - match q.pop() { - Empty => {} - Inconsistent | Data(..) => panic!(), - } - let (tx, rx) = channel(); - let q = Arc::new(q); - - for _ in 0..nthreads { - let tx = tx.clone(); - let q = q.clone(); - thread::spawn(move || { - for i in 0..nmsgs { - q.push(i); - } - tx.send(()).unwrap(); - }); - } - - let mut i = 0; - while i < nthreads * nmsgs { - match q.pop() { - Empty | Inconsistent => {} - Data(_) => i += 1, - } - } - drop(tx); - for _ in 0..nthreads { - rx.recv().unwrap(); - } - } -} diff --git a/library/std/src/sync/mpsc/mpsc_queue/tests.rs b/library/std/src/sync/mpsc/mpsc_queue/tests.rs new file mode 100644 index 0000000000..348b83424b --- /dev/null +++ b/library/std/src/sync/mpsc/mpsc_queue/tests.rs @@ -0,0 +1,47 @@ +use super::{Data, Empty, Inconsistent, Queue}; +use crate::sync::mpsc::channel; +use crate::sync::Arc; +use crate::thread; + +#[test] +fn test_full() { + let q: Queue> = Queue::new(); + q.push(box 1); + q.push(box 2); +} + +#[test] +fn test() { + let nthreads = 8; + let nmsgs = 1000; + let q = Queue::new(); + match q.pop() { + Empty => {} + Inconsistent | Data(..) => panic!(), + } + let (tx, rx) = channel(); + let q = Arc::new(q); + + for _ in 0..nthreads { + let tx = tx.clone(); + let q = q.clone(); + thread::spawn(move || { + for i in 0..nmsgs { + q.push(i); + } + tx.send(()).unwrap(); + }); + } + + let mut i = 0; + while i < nthreads * nmsgs { + match q.pop() { + Empty | Inconsistent => {} + Data(_) => i += 1, + } + } + drop(tx); + for _ in 0..nthreads { + rx.recv().unwrap(); + } +} diff --git a/library/std/src/sync/mpsc/spsc_queue.rs b/library/std/src/sync/mpsc/spsc_queue.rs index 0274268f69..9bf99f193c 100644 --- a/library/std/src/sync/mpsc/spsc_queue.rs +++ b/library/std/src/sync/mpsc/spsc_queue.rs @@ -6,6 +6,9 @@ // http://www.1024cores.net/home/lock-free-algorithms/queues/unbounded-spsc-queue +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use core::cell::UnsafeCell; use core::ptr; @@ -231,108 +234,3 @@ impl Drop for Queue { - assert_eq!(&*vec, &[1]); - } - None => unreachable!(), - } - - match queue.pop() { - Some(vec) => { - assert_eq!(&*vec, &[1]); - } - None => unreachable!(), - } - } - } - - #[test] - fn drop_full() { - unsafe { - let q: Queue> = Queue::with_additions(0, (), ()); - q.push(box 1); - q.push(box 2); - } - } - - #[test] - fn smoke_bound() { - unsafe { - let q = Queue::with_additions(0, (), ()); - q.push(1); - q.push(2); - assert_eq!(q.pop(), Some(1)); - assert_eq!(q.pop(), Some(2)); - assert_eq!(q.pop(), None); - q.push(3); - q.push(4); - assert_eq!(q.pop(), Some(3)); - assert_eq!(q.pop(), Some(4)); - assert_eq!(q.pop(), None); - } - } - - #[test] - fn stress() { - unsafe { - stress_bound(0); - stress_bound(1); - } - - unsafe fn stress_bound(bound: usize) { - let q = Arc::new(Queue::with_additions(bound, (), ())); - - let (tx, rx) = channel(); - let q2 = q.clone(); - let _t = thread::spawn(move || { - for _ in 0..100000 { - loop { - match q2.pop() { - Some(1) => break, - Some(_) => panic!(), - None => {} - } - } - } - tx.send(()).unwrap(); - }); - for _ in 0..100000 { - q.push(1); - } - rx.recv().unwrap(); - } - } -} diff --git a/library/std/src/sync/mpsc/spsc_queue/tests.rs b/library/std/src/sync/mpsc/spsc_queue/tests.rs new file mode 100644 index 0000000000..e4fd15cbbd --- /dev/null +++ b/library/std/src/sync/mpsc/spsc_queue/tests.rs @@ -0,0 +1,101 @@ +use super::Queue; +use crate::sync::mpsc::channel; +use crate::sync::Arc; +use crate::thread; + +#[test] +fn smoke() { + unsafe { + let queue = Queue::with_additions(0, (), ()); + queue.push(1); + queue.push(2); + assert_eq!(queue.pop(), Some(1)); + assert_eq!(queue.pop(), Some(2)); + assert_eq!(queue.pop(), None); + queue.push(3); + queue.push(4); + assert_eq!(queue.pop(), Some(3)); + assert_eq!(queue.pop(), Some(4)); + assert_eq!(queue.pop(), None); + } +} + +#[test] +fn peek() { + unsafe { + let queue = Queue::with_additions(0, (), ()); + queue.push(vec![1]); + + // Ensure the borrowchecker works + match queue.peek() { + Some(vec) => { + assert_eq!(&*vec, &[1]); + } + None => unreachable!(), + } + + match queue.pop() { + Some(vec) => { + assert_eq!(&*vec, &[1]); + } + None => unreachable!(), + } + } +} + +#[test] +fn drop_full() { + unsafe { + let q: Queue> = Queue::with_additions(0, (), ()); + q.push(box 1); + q.push(box 2); + } +} + +#[test] +fn smoke_bound() { + unsafe { + let q = Queue::with_additions(0, (), ()); + q.push(1); + q.push(2); + assert_eq!(q.pop(), Some(1)); + assert_eq!(q.pop(), Some(2)); + assert_eq!(q.pop(), None); + q.push(3); + q.push(4); + assert_eq!(q.pop(), Some(3)); + assert_eq!(q.pop(), Some(4)); + assert_eq!(q.pop(), None); + } +} + +#[test] +fn stress() { + unsafe { + stress_bound(0); + stress_bound(1); + } + + unsafe fn stress_bound(bound: usize) { + let q = Arc::new(Queue::with_additions(bound, (), ())); + + let (tx, rx) = channel(); + let q2 = q.clone(); + let _t = thread::spawn(move || { + for _ in 0..100000 { + loop { + match q2.pop() { + Some(1) => break, + Some(_) => panic!(), + None => {} + } + } + } + tx.send(()).unwrap(); + }); + for _ in 0..100000 { + q.push(1); + } + rx.recv().unwrap(); + } +} diff --git a/library/std/src/sync/mpsc/sync_tests.rs b/library/std/src/sync/mpsc/sync_tests.rs new file mode 100644 index 0000000000..0052a38f7b --- /dev/null +++ b/library/std/src/sync/mpsc/sync_tests.rs @@ -0,0 +1,647 @@ +use super::*; +use crate::env; +use crate::thread; +use crate::time::Duration; + +pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } +} + +#[test] +fn smoke() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn drop_full() { + let (tx, _rx) = sync_channel::>(1); + tx.send(box 1).unwrap(); +} + +#[test] +fn smoke_shared() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn recv_timeout() { + let (tx, rx) = sync_channel::(1); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(1).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); +} + +#[test] +fn smoke_threads() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_port_gone() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert!(tx.send(1).is_err()); +} + +#[test] +fn smoke_shared_port_gone2() { + let (tx, rx) = sync_channel::(0); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); +} + +#[test] +fn port_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} +} + +#[test] +fn port_gone_concurrent_shared() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} +} + +#[test] +fn smoke_chan_gone() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn smoke_chan_gone_shared() { + let (tx, rx) = sync_channel::<()>(0); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); +} + +#[test] +fn chan_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} +} + +#[test] +fn stress() { + let (tx, rx) = sync_channel::(0); + thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } +} + +#[test] +fn stress_recv_timeout_two_threads() { + let (tx, rx) = sync_channel::(0); + + thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(1)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, 10000); +} + +#[test] +fn stress_recv_timeout_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + thread::spawn(move || { + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, AMT * NTHREADS); + assert!(rx.try_recv().is_err()); + + dtx.send(()).unwrap(); + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + + drop(tx); + + drx.recv().unwrap(); +} + +#[test] +fn stress_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + dtx.send(()).unwrap(); + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + drop(tx); + drx.recv().unwrap(); +} + +#[test] +fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = sync_channel::(0); + drop(rx); +} + +#[test] +fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = sync_channel::(0); + drop(tx); +} + +#[test] +fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = sync_channel::>(0); + drop(rx); + assert!(tx.send(box 0).is_err()); +} + +#[test] +fn oneshot_single_thread_recv_chan_close() { + // Receiving on a closed chan will panic + let res = thread::spawn(move || { + let (tx, rx) = sync_channel::(0); + drop(tx); + rx.recv().unwrap(); + }) + .join(); + // What is our res? + assert!(res.is_err()); +} + +#[test] +fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = sync_channel::>(1); + tx.send(box 10).unwrap(); + assert!(*rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_open() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(10), Ok(())); + assert!(rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); +} + +#[test] +fn oneshot_single_thread_try_send_closed2() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); +} + +#[test] +fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); +} + +#[test] +fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn oneshot_single_thread_try_recv_closed_with_data() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + drop(tx); + assert_eq!(rx.try_recv(), Ok(10)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_data() { + let (tx, rx) = sync_channel::(1); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); +} + +#[test] +fn oneshot_single_thread_peek_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_open() { + let (_tx, rx) = sync_channel::(0); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = sync_channel::>(0); + let _t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(box 10).unwrap(); +} + +#[test] +fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = sync_channel::>(0); + let _t = thread::spawn(move || { + drop(tx); + }); + let res = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }) + .join(); + assert!(res.is_err()); +} + +#[test] +fn oneshot_multi_thread_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + drop(rx); + }); + drop(tx); + } +} + +#[test] +fn oneshot_multi_thread_send_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + drop(rx); + }); + let _ = thread::spawn(move || { + tx.send(1).unwrap(); + }) + .join(); + } +} + +#[test] +fn oneshot_multi_thread_recv_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + let res = thread::spawn(move || { + rx.recv().unwrap(); + }) + .join(); + assert!(res.is_err()); + }); + let _t = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + } +} + +#[test] +fn oneshot_multi_thread_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::>(0); + let _t = thread::spawn(move || { + tx.send(box 10).unwrap(); + }); + assert!(*rx.recv().unwrap() == 10); + } +} + +#[test] +fn stream_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = sync_channel::>(0); + + send(tx, 0); + recv(rx, 0); + + fn send(tx: SyncSender>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + tx.send(box i).unwrap(); + send(tx, i + 1); + }); + } + + fn recv(rx: Receiver>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + }); + } + } +} + +#[test] +fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = sync_channel(10000); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } +} + +#[test] +fn shared_chan_stress() { + let (tx, rx) = sync_channel(0); + let total = stress_factor() + 100; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } +} + +#[test] +fn test_nested_recv_iter() { + let (tx, rx) = sync_channel::(0); + let (total_tx, total_rx) = sync_channel::(0); + + let _t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); +} + +#[test] +fn test_recv_iter_break() { + let (tx, rx) = sync_channel::(0); + let (count_tx, count_rx) = sync_channel(0); + + let _t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.try_send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); +} + +#[test] +fn try_recv_states() { + let (tx1, rx1) = sync_channel::(1); + let (tx2, rx2) = sync_channel::<()>(1); + let (tx3, rx3) = sync_channel::<()>(1); + let _t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); +} + +// This bug used to end up in a livelock inside of the Receiver destructor +// because the internal state of the Shared packet was corrupted +#[test] +fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = sync_channel::<()>(0); + let (tx2, rx2) = sync_channel::<()>(0); + let _t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let t = tx.clone(); + drop(tx); + t.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); +} + +#[test] +fn send1() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + assert_eq!(tx.send(1), Ok(())); +} + +#[test] +fn send2() { + let (tx, rx) = sync_channel::(0); + let _t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); +} + +#[test] +fn send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.send(1), Ok(())); + let _t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); +} + +#[test] +fn send4() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let (done, donerx) = channel(); + let done2 = done.clone(); + let _t = thread::spawn(move || { + assert!(tx.send(1).is_err()); + done.send(()).unwrap(); + }); + let _t = thread::spawn(move || { + assert!(tx2.send(2).is_err()); + done2.send(()).unwrap(); + }); + drop(rx); + donerx.recv().unwrap(); + donerx.recv().unwrap(); +} + +#[test] +fn try_send1() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); +} + +#[test] +fn try_send2() { + let (tx, _rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); +} + +#[test] +fn try_send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + drop(rx); + assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); +} + +#[test] +fn issue_15761() { + fn repro() { + let (tx1, rx1) = sync_channel::<()>(3); + let (tx2, rx2) = sync_channel::<()>(3); + + let _t = thread::spawn(move || { + rx1.recv().unwrap(); + tx2.try_send(()).unwrap(); + }); + + tx1.try_send(()).unwrap(); + rx2.recv().unwrap(); + } + + for _ in 0..100 { + repro() + } +} diff --git a/library/std/src/sync/mpsc/tests.rs b/library/std/src/sync/mpsc/tests.rs new file mode 100644 index 0000000000..184ce193cb --- /dev/null +++ b/library/std/src/sync/mpsc/tests.rs @@ -0,0 +1,706 @@ +use super::*; +use crate::env; +use crate::thread; +use crate::time::{Duration, Instant}; + +pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } +} + +#[test] +fn smoke() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn drop_full() { + let (tx, _rx) = channel::>(); + tx.send(box 1).unwrap(); +} + +#[test] +fn drop_full_shared() { + let (tx, _rx) = channel::>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(box 1).unwrap(); +} + +#[test] +fn smoke_shared() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_threads() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); +} + +#[test] +fn smoke_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()); +} + +#[test] +fn smoke_shared_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()) +} + +#[test] +fn smoke_shared_port_gone2() { + let (tx, rx) = channel::(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); +} + +#[test] +fn port_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} +} + +#[test] +fn port_gone_concurrent_shared() { + let (tx, rx) = channel::(); + let tx2 = tx.clone(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} +} + +#[test] +fn smoke_chan_gone() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn smoke_chan_gone_shared() { + let (tx, rx) = channel::<()>(); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); +} + +#[test] +fn chan_gone_concurrent() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} +} + +#[test] +fn stress() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn stress_shared() { + const AMT: u32 = 10000; + const NTHREADS: u32 = 8; + let (tx, rx) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + }); + + for _ in 0..NTHREADS { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + } + drop(tx); + t.join().ok().expect("thread panicked"); +} + +#[test] +fn send_from_outside_runtime() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + tx1.send(()).unwrap(); + for _ in 0..40 { + assert_eq!(rx2.recv().unwrap(), 1); + } + }); + rx1.recv().unwrap(); + let t2 = thread::spawn(move || { + for _ in 0..40 { + tx2.send(1).unwrap(); + } + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn recv_from_outside_runtime() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..40 { + assert_eq!(rx.recv().unwrap(), 1); + } + }); + for _ in 0..40 { + tx.send(1).unwrap(); + } + t.join().ok().expect("thread panicked"); +} + +#[test] +fn no_runtime() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); + }); + let t2 = thread::spawn(move || { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); + }); + t1.join().ok().expect("thread panicked"); + t2.join().ok().expect("thread panicked"); +} + +#[test] +fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = channel::(); + drop(rx); +} + +#[test] +fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::(); + drop(tx); +} + +#[test] +fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = channel::>(); + drop(rx); + assert!(tx.send(box 0).is_err()); +} + +#[test] +fn oneshot_single_thread_recv_chan_close() { + // Receiving on a closed chan will panic + let res = thread::spawn(move || { + let (tx, rx) = channel::(); + drop(tx); + rx.recv().unwrap(); + }) + .join(); + // What is our res? + assert!(res.is_err()); +} + +#[test] +fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::>(); + tx.send(box 10).unwrap(); + assert!(*rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); +} + +#[test] +fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(10).is_err()); +} + +#[test] +fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); +} + +#[test] +fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); +} + +#[test] +fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); +} + +#[test] +fn oneshot_single_thread_peek_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn oneshot_single_thread_peek_open() { + let (_tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(box 10).unwrap(); +} + +#[test] +fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + drop(tx); + }); + let res = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }) + .join(); + assert!(res.is_err()); +} + +#[test] +fn oneshot_multi_thread_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + drop(tx); + } +} + +#[test] +fn oneshot_multi_thread_send_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + let _t = thread::spawn(move || { + drop(rx); + }); + let _ = thread::spawn(move || { + tx.send(1).unwrap(); + }) + .join(); + } +} + +#[test] +fn oneshot_multi_thread_recv_close_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::(); + thread::spawn(move || { + let res = thread::spawn(move || { + rx.recv().unwrap(); + }) + .join(); + assert!(res.is_err()); + }); + let _t = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + } +} + +#[test] +fn oneshot_multi_thread_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel::>(); + let _t = thread::spawn(move || { + tx.send(box 10).unwrap(); + }); + assert!(*rx.recv().unwrap() == 10); + } +} + +#[test] +fn stream_send_recv_stress() { + for _ in 0..stress_factor() { + let (tx, rx) = channel(); + + send(tx, 0); + recv(rx, 0); + + fn send(tx: Sender>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + tx.send(box i).unwrap(); + send(tx, i + 1); + }); + } + + fn recv(rx: Receiver>, i: i32) { + if i == 10 { + return; + } + + thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + }); + } + } +} + +#[test] +fn oneshot_single_thread_recv_timeout() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn stress_recv_timeout_two_threads() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + let timeout = Duration::from_millis(100); + + thread::spawn(move || { + for i in 0..stress { + if i % 2 == 0 { + thread::sleep(timeout * 2); + } + tx.send(1usize).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(timeout) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn recv_timeout_upgrade() { + let (tx, rx) = channel::<()>(); + let timeout = Duration::from_millis(1); + let _tx_clone = tx.clone(); + + let start = Instant::now(); + assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); + assert!(Instant::now() >= start + timeout); +} + +#[test] +fn stress_recv_timeout_shared() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + + for i in 0..stress { + let tx = tx.clone(); + thread::spawn(move || { + thread::sleep(Duration::from_millis(i as u64 * 10)); + tx.send(1usize).unwrap(); + }); + } + + drop(tx); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); +} + +#[test] +fn very_long_recv_timeout_wont_panic() { + let (tx, rx) = channel::<()>(); + let join_handle = thread::spawn(move || rx.recv_timeout(Duration::from_secs(u64::MAX))); + thread::sleep(Duration::from_secs(1)); + assert!(tx.send(()).is_ok()); + assert_eq!(join_handle.join().unwrap(), Ok(())); +} + +#[test] +fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = channel(); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } +} + +#[test] +fn shared_recv_timeout() { + let (tx, rx) = channel(); + let total = 5; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Err(RecvTimeoutError::Timeout)); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); +} + +#[test] +fn shared_chan_stress() { + let (tx, rx) = channel(); + let total = stress_factor() + 100; + for _ in 0..total { + let tx = tx.clone(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + } + + for _ in 0..total { + rx.recv().unwrap(); + } +} + +#[test] +fn test_nested_recv_iter() { + let (tx, rx) = channel::(); + let (total_tx, total_rx) = channel::(); + + let _t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); +} + +#[test] +fn test_recv_iter_break() { + let (tx, rx) = channel::(); + let (count_tx, count_rx) = channel(); + + let _t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); +} + +#[test] +fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move || { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); +} + +#[test] +fn test_recv_into_iter_owned() { + let mut iter = { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + rx.into_iter() + }; + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn test_recv_into_iter_borrowed() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + let mut iter = (&rx).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn try_recv_states() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let _t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); +} + +// This bug used to end up in a livelock inside of the Receiver destructor +// because the internal state of the Shared packet was corrupted +#[test] +fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); + let _t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let t = tx.clone(); + drop(tx); + t.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); +} + +#[test] +fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); +} diff --git a/library/std/src/sync/mutex.rs b/library/std/src/sync/mutex.rs index d7a4f00305..e8f5a6f429 100644 --- a/library/std/src/sync/mutex.rs +++ b/library/std/src/sync/mutex.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cell::UnsafeCell; use crate::fmt; use crate::mem; @@ -85,7 +88,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; /// use std::thread; /// /// let lock = Arc::new(Mutex::new(0_u32)); -/// let lock2 = lock.clone(); +/// let lock2 = Arc::clone(&lock); /// /// let _ = thread::spawn(move || -> () { /// // This thread will acquire the mutex first, unwrapping the result of @@ -163,12 +166,7 @@ use crate::sys_common::poison::{self, LockResult, TryLockError, TryLockResult}; #[stable(feature = "rust1", since = "1.0.0")] #[cfg_attr(not(test), rustc_diagnostic_item = "mutex_type")] pub struct Mutex { - // Note that this mutex is in a *box*, not inlined into the struct itself. - // Once a native mutex has been used once, its address can never change (it - // can't be moved). This mutex type can be safely moved at any time, so to - // ensure that the native mutex is used correctly we box the inner mutex to - // give it a constant address. - inner: Box, + inner: sys::MovableMutex, poison: poison::Flag, data: UnsafeCell, } @@ -215,15 +213,11 @@ impl Mutex { /// ``` #[stable(feature = "rust1", since = "1.0.0")] pub fn new(t: T) -> Mutex { - let mut m = Mutex { - inner: box sys::Mutex::new(), + Mutex { + inner: sys::MovableMutex::new(), poison: poison::Flag::new(), data: UnsafeCell::new(t), - }; - unsafe { - m.inner.init(); } - m } } @@ -256,7 +250,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// thread::spawn(move || { /// *c_mutex.lock().unwrap() = 10; @@ -292,7 +286,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// thread::spawn(move || { /// let mut lock = c_mutex.try_lock(); @@ -328,7 +322,7 @@ impl Mutex { /// use std::thread; /// /// let mutex = Arc::new(Mutex::new(0)); - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// /// let _ = thread::spawn(move || { /// let _lock = c_mutex.lock().unwrap(); @@ -375,7 +369,6 @@ impl Mutex { (ptr::read(inner), ptr::read(poison), ptr::read(data)) }; mem::forget(self); - inner.destroy(); // Keep in sync with the `Drop` impl. drop(inner); poison::map_result(poison.borrow(), |_| data.into_inner()) @@ -403,25 +396,11 @@ impl Mutex { /// ``` #[stable(feature = "mutex_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner mutex. - let data = unsafe { &mut *self.data.get() }; + let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |_| data) } } -#[stable(feature = "rust1", since = "1.0.0")] -unsafe impl<#[may_dangle] T: ?Sized> Drop for Mutex { - fn drop(&mut self) { - // This is actually safe b/c we know that there is no further usage of - // this mutex (it's up to the user to arrange for a mutex to get - // dropped, that's not our job) - // - // IMPORTANT: This code must be kept in sync with `Mutex::into_inner`. - unsafe { self.inner.destroy() } - } -} - #[stable(feature = "mutex_from", since = "1.24.0")] impl From for Mutex { /// Creates a new mutex in an unlocked state ready for use. @@ -508,252 +487,10 @@ impl fmt::Display for MutexGuard<'_, T> { } } -pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::Mutex { +pub fn guard_lock<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a sys::MovableMutex { &guard.lock.inner } pub fn guard_poison<'a, T: ?Sized>(guard: &MutexGuard<'a, T>) -> &'a poison::Flag { &guard.lock.poison } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::sync::atomic::{AtomicUsize, Ordering}; - use crate::sync::mpsc::channel; - use crate::sync::{Arc, Condvar, Mutex}; - use crate::thread; - - struct Packet(Arc<(Mutex, Condvar)>); - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let m = Mutex::new(()); - drop(m.lock().unwrap()); - drop(m.lock().unwrap()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(Mutex::new(0)); - - fn inc(m: &Mutex) { - for _ in 0..J { - *m.lock().unwrap() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock().unwrap(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = Mutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = Mutex::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = Mutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_into_inner_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_get_mut() { - let mut m = Mutex::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); - } - - #[test] - fn test_get_mut_poison() { - let m = Arc::new(Mutex::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.lock().unwrap(); - panic!("test panic in inner thread to poison mutex"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), - } - } - - #[test] - fn test_mutex_arc_condvar() { - let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - // wait until parent gets in - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock().unwrap(); - *lock = true; - cvar.notify_one(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - assert!(!*lock); - while !*lock { - lock = cvar.wait(lock).unwrap(); - } - } - - #[test] - fn test_arc_condvar_poison() { - let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - - let _t = thread::spawn(move || -> () { - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let _g = lock.lock().unwrap(); - cvar.notify_one(); - // Parent should fail when it wakes up. - panic!(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock().unwrap(); - tx.send(()).unwrap(); - while *lock == 1 { - match cvar.wait(lock) { - Ok(l) => { - lock = l; - assert_eq!(*lock, 1); - } - Err(..) => break, - } - } - } - - #[test] - fn test_mutex_arc_poison() { - let arc = Arc::new(Mutex::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - let lock = arc2.lock().unwrap(); - assert_eq!(*lock, 2); - }) - .join(); - assert!(arc.lock().is_err()); - assert!(arc.is_poisoned()); - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(Mutex::new(1)); - let arc2 = Arc::new(Mutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let lock = arc2.lock().unwrap(); - let lock2 = lock.lock().unwrap(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(Mutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || -> () { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock().unwrap() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.lock().unwrap(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock().unwrap(), comp); - } -} diff --git a/library/std/src/sync/mutex/tests.rs b/library/std/src/sync/mutex/tests.rs new file mode 100644 index 0000000000..a1b5aeddcb --- /dev/null +++ b/library/std/src/sync/mutex/tests.rs @@ -0,0 +1,238 @@ +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::mpsc::channel; +use crate::sync::{Arc, Condvar, Mutex}; +use crate::thread; + +struct Packet(Arc<(Mutex, Condvar)>); + +#[derive(Eq, PartialEq, Debug)] +struct NonCopy(i32); + +#[test] +fn smoke() { + let m = Mutex::new(()); + drop(m.lock().unwrap()); + drop(m.lock().unwrap()); +} + +#[test] +fn lots_and_lots() { + const J: u32 = 1000; + const K: u32 = 3; + + let m = Arc::new(Mutex::new(0)); + + fn inc(m: &Mutex) { + for _ in 0..J { + *m.lock().unwrap() += 1; + } + } + + let (tx, rx) = channel(); + for _ in 0..K { + let tx2 = tx.clone(); + let m2 = m.clone(); + thread::spawn(move || { + inc(&m2); + tx2.send(()).unwrap(); + }); + let tx2 = tx.clone(); + let m2 = m.clone(); + thread::spawn(move || { + inc(&m2); + tx2.send(()).unwrap(); + }); + } + + drop(tx); + for _ in 0..2 * K { + rx.recv().unwrap(); + } + assert_eq!(*m.lock().unwrap(), J * K * 2); +} + +#[test] +fn try_lock() { + let m = Mutex::new(()); + *m.try_lock().unwrap() = (); +} + +#[test] +fn test_into_inner() { + let m = Mutex::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); +} + +#[test] +fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = Mutex::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); +} + +#[test] +fn test_into_inner_poison() { + let m = Arc::new(Mutex::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.lock().unwrap(); + panic!("test panic in inner thread to poison mutex"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned Mutex is Ok: {:?}", x), + } +} + +#[test] +fn test_get_mut() { + let mut m = Mutex::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); +} + +#[test] +fn test_get_mut_poison() { + let m = Arc::new(Mutex::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.lock().unwrap(); + panic!("test panic in inner thread to poison mutex"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned Mutex is Ok: {:?}", x), + } +} + +#[test] +fn test_mutex_arc_condvar() { + let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + // wait until parent gets in + rx.recv().unwrap(); + let &(ref lock, ref cvar) = &*packet2.0; + let mut lock = lock.lock().unwrap(); + *lock = true; + cvar.notify_one(); + }); + + let &(ref lock, ref cvar) = &*packet.0; + let mut lock = lock.lock().unwrap(); + tx.send(()).unwrap(); + assert!(!*lock); + while !*lock { + lock = cvar.wait(lock).unwrap(); + } +} + +#[test] +fn test_arc_condvar_poison() { + let packet = Packet(Arc::new((Mutex::new(1), Condvar::new()))); + let packet2 = Packet(packet.0.clone()); + let (tx, rx) = channel(); + + let _t = thread::spawn(move || -> () { + rx.recv().unwrap(); + let &(ref lock, ref cvar) = &*packet2.0; + let _g = lock.lock().unwrap(); + cvar.notify_one(); + // Parent should fail when it wakes up. + panic!(); + }); + + let &(ref lock, ref cvar) = &*packet.0; + let mut lock = lock.lock().unwrap(); + tx.send(()).unwrap(); + while *lock == 1 { + match cvar.wait(lock) { + Ok(l) => { + lock = l; + assert_eq!(*lock, 1); + } + Err(..) => break, + } + } +} + +#[test] +fn test_mutex_arc_poison() { + let arc = Arc::new(Mutex::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _ = thread::spawn(move || { + let lock = arc2.lock().unwrap(); + assert_eq!(*lock, 2); + }) + .join(); + assert!(arc.lock().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +fn test_mutex_arc_nested() { + // Tests nested mutexes and access + // to underlying data. + let arc = Arc::new(Mutex::new(1)); + let arc2 = Arc::new(Mutex::new(arc)); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + let lock = arc2.lock().unwrap(); + let lock2 = lock.lock().unwrap(); + assert_eq!(*lock2, 1); + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); +} + +#[test] +fn test_mutex_arc_access_in_unwind() { + let arc = Arc::new(Mutex::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + *self.i.lock().unwrap() += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }) + .join(); + let lock = arc.lock().unwrap(); + assert_eq!(*lock, 2); +} + +#[test] +fn test_mutex_unsized() { + let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); + { + let b = &mut *mutex.lock().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*mutex.lock().unwrap(), comp); +} diff --git a/library/std/src/sync/once.rs b/library/std/src/sync/once.rs index 714ec3e878..de5ddf1daf 100644 --- a/library/std/src/sync/once.rs +++ b/library/std/src/sync/once.rs @@ -84,6 +84,9 @@ // processor. Because both use Acquire ordering such a reordering is not // allowed, so no need for SeqCst. +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cell::Cell; use crate::fmt; use crate::marker; @@ -92,10 +95,7 @@ use crate::thread::{self, Thread}; /// A synchronization primitive which can be used to run a one-time global /// initialization. Useful for one-time initialization for FFI or related -/// functionality. This type can only be constructed with the [`Once::new`] -/// constructor. -/// -/// [`Once::new`]: struct.Once.html#method.new +/// functionality. This type can only be constructed with [`Once::new()`]. /// /// # Examples /// @@ -123,11 +123,8 @@ unsafe impl Sync for Once {} #[stable(feature = "rust1", since = "1.0.0")] unsafe impl Send for Once {} -/// State yielded to [`call_once_force`]’s closure parameter. The state can be -/// used to query the poison status of the [`Once`]. -/// -/// [`call_once_force`]: struct.Once.html#method.call_once_force -/// [`Once`]: struct.Once.html +/// State yielded to [`Once::call_once_force()`]’s closure parameter. The state +/// can be used to query the poison status of the [`Once`]. #[unstable(feature = "once_poison", issue = "33577")] #[derive(Debug)] pub struct OnceState { @@ -137,8 +134,6 @@ pub struct OnceState { /// Initialization value for static [`Once`] values. /// -/// [`Once`]: struct.Once.html -/// /// # Examples /// /// ``` @@ -188,6 +183,7 @@ struct WaiterQueue<'a> { impl Once { /// Creates a new `Once` value. + #[inline] #[stable(feature = "once_new", since = "1.2.0")] #[rustc_const_stable(feature = "const_once_new", since = "1.32.0")] pub const fn new() -> Once { @@ -208,7 +204,7 @@ impl Once { /// happens-before relation between the closure and code executing after the /// return). /// - /// If the given closure recursively invokes `call_once` on the same `Once` + /// If the given closure recursively invokes `call_once` on the same [`Once`] /// instance the exact behavior is not specified, allowed outcomes are /// a panic or a deadlock. /// @@ -245,7 +241,7 @@ impl Once { /// /// The closure `f` will only be executed once if this is called /// concurrently amongst many threads. If that closure panics, however, then - /// it will *poison* this `Once` instance, causing all future invocations of + /// it will *poison* this [`Once`] instance, causing all future invocations of /// `call_once` to also panic. /// /// This is similar to [poisoning with mutexes][poison]. @@ -265,21 +261,21 @@ impl Once { self.call_inner(false, &mut |_| f.take().unwrap()()); } - /// Performs the same function as [`call_once`] except ignores poisoning. + /// Performs the same function as [`call_once()`] except ignores poisoning. /// - /// Unlike [`call_once`], if this `Once` has been poisoned (i.e., a previous - /// call to `call_once` or `call_once_force` caused a panic), calling - /// `call_once_force` will still invoke the closure `f` and will _not_ - /// result in an immediate panic. If `f` panics, the `Once` will remain - /// in a poison state. If `f` does _not_ panic, the `Once` will no - /// longer be in a poison state and all future calls to `call_once` or - /// `call_once_force` will be no-ops. + /// Unlike [`call_once()`], if this [`Once`] has been poisoned (i.e., a previous + /// call to [`call_once()`] or [`call_once_force()`] caused a panic), calling + /// [`call_once_force()`] will still invoke the closure `f` and will _not_ + /// result in an immediate panic. If `f` panics, the [`Once`] will remain + /// in a poison state. If `f` does _not_ panic, the [`Once`] will no + /// longer be in a poison state and all future calls to [`call_once()`] or + /// [`call_once_force()`] will be no-ops. /// /// The closure `f` is yielded a [`OnceState`] structure which can be used - /// to query the poison status of the `Once`. + /// to query the poison status of the [`Once`]. /// - /// [`call_once`]: struct.Once.html#method.call_once - /// [`OnceState`]: struct.OnceState.html + /// [`call_once()`]: Once::call_once + /// [`call_once_force()`]: Once::call_once_force /// /// # Examples /// @@ -325,18 +321,20 @@ impl Once { self.call_inner(true, &mut |p| f.take().unwrap()(p)); } - /// Returns `true` if some `call_once` call has completed + /// Returns `true` if some [`call_once()`] call has completed /// successfully. Specifically, `is_completed` will return false in /// the following situations: - /// * `call_once` was not called at all, - /// * `call_once` was called, but has not yet completed, - /// * the `Once` instance is poisoned + /// * [`call_once()`] was not called at all, + /// * [`call_once()`] was called, but has not yet completed, + /// * the [`Once`] instance is poisoned /// - /// This function returning `false` does not mean that `Once` has not been + /// This function returning `false` does not mean that [`Once`] has not been /// executed. For example, it may have been executed in the time between /// when `is_completed` starts executing and when it returns, in which case /// the `false` return value would be stale (but still permissible). /// + /// [`call_once()`]: Once::call_once + /// /// # Examples /// /// ``` @@ -515,14 +513,11 @@ impl Drop for WaiterQueue<'_> { impl OnceState { /// Returns `true` if the associated [`Once`] was poisoned prior to the - /// invocation of the closure passed to [`call_once_force`]. - /// - /// [`call_once_force`]: struct.Once.html#method.call_once_force - /// [`Once`]: struct.Once.html + /// invocation of the closure passed to [`Once::call_once_force()`]. /// /// # Examples /// - /// A poisoned `Once`: + /// A poisoned [`Once`]: /// /// ``` /// #![feature(once_poison)] @@ -543,7 +538,7 @@ impl OnceState { /// }); /// ``` /// - /// An unpoisoned `Once`: + /// An unpoisoned [`Once`]: /// /// ``` /// #![feature(once_poison)] @@ -561,130 +556,8 @@ impl OnceState { } /// Poison the associated [`Once`] without explicitly panicking. - /// - /// [`Once`]: struct.Once.html // NOTE: This is currently only exposed for the `lazy` module pub(crate) fn poison(&self) { self.set_state_on_drop_to.set(POISONED); } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::Once; - use crate::panic; - use crate::sync::mpsc::channel; - use crate::thread; - - #[test] - fn smoke_once() { - static O: Once = Once::new(); - let mut a = 0; - O.call_once(|| a += 1); - assert_eq!(a, 1); - O.call_once(|| a += 1); - assert_eq!(a, 1); - } - - #[test] - fn stampede_once() { - static O: Once = Once::new(); - static mut RUN: bool = false; - - let (tx, rx) = channel(); - for _ in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..4 { - thread::yield_now() - } - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - tx.send(()).unwrap(); - }); - } - - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - - for _ in 0..10 { - rx.recv().unwrap(); - } - } - - #[test] - fn poison_bad() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // poisoning propagates - let t = panic::catch_unwind(|| { - O.call_once(|| {}); - }); - assert!(t.is_err()); - - // we can subvert poisoning, however - let mut called = false; - O.call_once_force(|p| { - called = true; - assert!(p.poisoned()) - }); - assert!(called); - - // once any success happens, we stop propagating the poison - O.call_once(|| {}); - } - - #[test] - fn wait_for_force_to_finish() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // make sure someone's waiting inside the once via a force - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let t1 = thread::spawn(move || { - O.call_once_force(|p| { - assert!(p.poisoned()); - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - }); - }); - - rx1.recv().unwrap(); - - // put another waiter on the once - let t2 = thread::spawn(|| { - let mut called = false; - O.call_once(|| { - called = true; - }); - assert!(!called); - }); - - tx2.send(()).unwrap(); - - assert!(t1.join().is_ok()); - assert!(t2.join().is_ok()); - } -} diff --git a/library/std/src/sync/once/tests.rs b/library/std/src/sync/once/tests.rs new file mode 100644 index 0000000000..fae2752526 --- /dev/null +++ b/library/std/src/sync/once/tests.rs @@ -0,0 +1,116 @@ +use super::Once; +use crate::panic; +use crate::sync::mpsc::channel; +use crate::thread; + +#[test] +fn smoke_once() { + static O: Once = Once::new(); + let mut a = 0; + O.call_once(|| a += 1); + assert_eq!(a, 1); + O.call_once(|| a += 1); + assert_eq!(a, 1); +} + +#[test] +fn stampede_once() { + static O: Once = Once::new(); + static mut RUN: bool = false; + + let (tx, rx) = channel(); + for _ in 0..10 { + let tx = tx.clone(); + thread::spawn(move || { + for _ in 0..4 { + thread::yield_now() + } + unsafe { + O.call_once(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + tx.send(()).unwrap(); + }); + } + + unsafe { + O.call_once(|| { + assert!(!RUN); + RUN = true; + }); + assert!(RUN); + } + + for _ in 0..10 { + rx.recv().unwrap(); + } +} + +#[test] +fn poison_bad() { + static O: Once = Once::new(); + + // poison the once + let t = panic::catch_unwind(|| { + O.call_once(|| panic!()); + }); + assert!(t.is_err()); + + // poisoning propagates + let t = panic::catch_unwind(|| { + O.call_once(|| {}); + }); + assert!(t.is_err()); + + // we can subvert poisoning, however + let mut called = false; + O.call_once_force(|p| { + called = true; + assert!(p.poisoned()) + }); + assert!(called); + + // once any success happens, we stop propagating the poison + O.call_once(|| {}); +} + +#[test] +fn wait_for_force_to_finish() { + static O: Once = Once::new(); + + // poison the once + let t = panic::catch_unwind(|| { + O.call_once(|| panic!()); + }); + assert!(t.is_err()); + + // make sure someone's waiting inside the once via a force + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let t1 = thread::spawn(move || { + O.call_once_force(|p| { + assert!(p.poisoned()); + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + }); + }); + + rx1.recv().unwrap(); + + // put another waiter on the once + let t2 = thread::spawn(|| { + let mut called = false; + O.call_once(|| { + called = true; + }); + assert!(!called); + }); + + tx2.send(()).unwrap(); + + assert!(t1.join().is_ok()); + assert!(t2.join().is_ok()); +} diff --git a/library/std/src/sync/rwlock.rs b/library/std/src/sync/rwlock.rs index 586093c916..d967779ce3 100644 --- a/library/std/src/sync/rwlock.rs +++ b/library/std/src/sync/rwlock.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::cell::UnsafeCell; use crate::fmt; use crate::mem; @@ -162,7 +165,7 @@ impl RwLock { /// use std::thread; /// /// let lock = Arc::new(RwLock::new(1)); - /// let c_lock = lock.clone(); + /// let c_lock = Arc::clone(&lock); /// /// let n = lock.read().unwrap(); /// assert_eq!(*n, 1); @@ -318,7 +321,7 @@ impl RwLock { /// use std::thread; /// /// let lock = Arc::new(RwLock::new(0)); - /// let c_lock = lock.clone(); + /// let c_lock = Arc::clone(&lock); /// /// let _ = thread::spawn(move || { /// let _lock = c_lock.write().unwrap(); @@ -401,9 +404,7 @@ impl RwLock { /// ``` #[stable(feature = "rwlock_get_mut", since = "1.6.0")] pub fn get_mut(&mut self) -> LockResult<&mut T> { - // We know statically that there are no other references to `self`, so - // there's no need to lock the inner lock. - let data = unsafe { &mut *self.data.get() }; + let data = self.data.get_mut(); poison::map_result(self.poison.borrow(), |_| data) } } @@ -538,254 +539,3 @@ impl Drop for RwLockWriteGuard<'_, T> { } } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::sync::atomic::{AtomicUsize, Ordering}; - use crate::sync::mpsc::channel; - use crate::sync::{Arc, RwLock, TryLockError}; - use crate::thread; - use rand::{self, Rng}; - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let l = RwLock::new(()); - drop(l.read().unwrap()); - drop(l.write().unwrap()); - drop((l.read().unwrap(), l.read().unwrap())); - drop(l.write().unwrap()); - } - - #[test] - fn frob() { - const N: u32 = 10; - const M: usize = 1000; - - let r = Arc::new(RwLock::new(())); - - let (tx, rx) = channel::<()>(); - for _ in 0..N { - let tx = tx.clone(); - let r = r.clone(); - thread::spawn(move || { - let mut rng = rand::thread_rng(); - for _ in 0..M { - if rng.gen_bool(1.0 / (N as f64)) { - drop(r.write().unwrap()); - } else { - drop(r.read().unwrap()); - } - } - drop(tx); - }); - } - drop(tx); - let _ = rx.recv(); - } - - #[test] - fn test_rw_arc_poison_wr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.read().is_err()); - } - - #[test] - fn test_rw_arc_poison_ww() { - let arc = Arc::new(RwLock::new(1)); - assert!(!arc.is_poisoned()); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write().unwrap(); - panic!(); - }) - .join(); - assert!(arc.write().is_err()); - assert!(arc.is_poisoned()); - } - - #[test] - fn test_rw_arc_no_poison_rr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 1); - } - #[test] - fn test_rw_arc_no_poison_rw() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read().unwrap(); - panic!() - }) - .join(); - let lock = arc.write().unwrap(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - let mut lock = arc2.write().unwrap(); - for _ in 0..10 { - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.read().unwrap(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 10); - } - - #[test] - fn test_rw_arc_access_in_unwind() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || -> () { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write().unwrap(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.read().unwrap(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write().unwrap(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read().unwrap(), comp); - } - - #[test] - fn test_rwlock_try_write() { - let lock = RwLock::new(0isize); - let read_guard = lock.read().unwrap(); - - let write_result = lock.try_write(); - match write_result { - Err(TryLockError::WouldBlock) => (), - Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), - Err(_) => assert!(false, "unexpected error"), - } - - drop(read_guard); - } - - #[test] - fn test_into_inner() { - let m = RwLock::new(NonCopy(10)); - assert_eq!(m.into_inner().unwrap(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = RwLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner().unwrap(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_into_inner_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().into_inner() { - Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), - Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x), - } - } - - #[test] - fn test_get_mut() { - let mut m = RwLock::new(NonCopy(10)); - *m.get_mut().unwrap() = NonCopy(20); - assert_eq!(m.into_inner().unwrap(), NonCopy(20)); - } - - #[test] - fn test_get_mut_poison() { - let m = Arc::new(RwLock::new(NonCopy(10))); - let m2 = m.clone(); - let _ = thread::spawn(move || { - let _lock = m2.write().unwrap(); - panic!("test panic in inner thread to poison RwLock"); - }) - .join(); - - assert!(m.is_poisoned()); - match Arc::try_unwrap(m).unwrap().get_mut() { - Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), - Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), - } - } -} diff --git a/library/std/src/sync/rwlock/tests.rs b/library/std/src/sync/rwlock/tests.rs new file mode 100644 index 0000000000..e9b74fb3ec --- /dev/null +++ b/library/std/src/sync/rwlock/tests.rs @@ -0,0 +1,247 @@ +use crate::sync::atomic::{AtomicUsize, Ordering}; +use crate::sync::mpsc::channel; +use crate::sync::{Arc, RwLock, TryLockError}; +use crate::thread; +use rand::{self, Rng}; + +#[derive(Eq, PartialEq, Debug)] +struct NonCopy(i32); + +#[test] +fn smoke() { + let l = RwLock::new(()); + drop(l.read().unwrap()); + drop(l.write().unwrap()); + drop((l.read().unwrap(), l.read().unwrap())); + drop(l.write().unwrap()); +} + +#[test] +fn frob() { + const N: u32 = 10; + const M: usize = 1000; + + let r = Arc::new(RwLock::new(())); + + let (tx, rx) = channel::<()>(); + for _ in 0..N { + let tx = tx.clone(); + let r = r.clone(); + thread::spawn(move || { + let mut rng = rand::thread_rng(); + for _ in 0..M { + if rng.gen_bool(1.0 / (N as f64)) { + drop(r.write().unwrap()); + } else { + drop(r.read().unwrap()); + } + } + drop(tx); + }); + } + drop(tx); + let _ = rx.recv(); +} + +#[test] +fn test_rw_arc_poison_wr() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.read().is_err()); +} + +#[test] +fn test_rw_arc_poison_ww() { + let arc = Arc::new(RwLock::new(1)); + assert!(!arc.is_poisoned()); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.write().unwrap(); + panic!(); + }) + .join(); + assert!(arc.write().is_err()); + assert!(arc.is_poisoned()); +} + +#[test] +fn test_rw_arc_no_poison_rr() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 1); +} +#[test] +fn test_rw_arc_no_poison_rw() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _: Result<(), _> = thread::spawn(move || { + let _lock = arc2.read().unwrap(); + panic!() + }) + .join(); + let lock = arc.write().unwrap(); + assert_eq!(*lock, 1); +} + +#[test] +fn test_rw_arc() { + let arc = Arc::new(RwLock::new(0)); + let arc2 = arc.clone(); + let (tx, rx) = channel(); + + thread::spawn(move || { + let mut lock = arc2.write().unwrap(); + for _ in 0..10 { + let tmp = *lock; + *lock = -1; + thread::yield_now(); + *lock = tmp + 1; + } + tx.send(()).unwrap(); + }); + + // Readers try to catch the writer in the act + let mut children = Vec::new(); + for _ in 0..5 { + let arc3 = arc.clone(); + children.push(thread::spawn(move || { + let lock = arc3.read().unwrap(); + assert!(*lock >= 0); + })); + } + + // Wait for children to pass their asserts + for r in children { + assert!(r.join().is_ok()); + } + + // Wait for writer to finish + rx.recv().unwrap(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 10); +} + +#[test] +fn test_rw_arc_access_in_unwind() { + let arc = Arc::new(RwLock::new(1)); + let arc2 = arc.clone(); + let _ = thread::spawn(move || -> () { + struct Unwinder { + i: Arc>, + } + impl Drop for Unwinder { + fn drop(&mut self) { + let mut lock = self.i.write().unwrap(); + *lock += 1; + } + } + let _u = Unwinder { i: arc2 }; + panic!(); + }) + .join(); + let lock = arc.read().unwrap(); + assert_eq!(*lock, 2); +} + +#[test] +fn test_rwlock_unsized() { + let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); + { + let b = &mut *rw.write().unwrap(); + b[0] = 4; + b[2] = 5; + } + let comp: &[i32] = &[4, 2, 5]; + assert_eq!(&*rw.read().unwrap(), comp); +} + +#[test] +fn test_rwlock_try_write() { + let lock = RwLock::new(0isize); + let read_guard = lock.read().unwrap(); + + let write_result = lock.try_write(); + match write_result { + Err(TryLockError::WouldBlock) => (), + Ok(_) => assert!(false, "try_write should not succeed while read_guard is in scope"), + Err(_) => assert!(false, "unexpected error"), + } + + drop(read_guard); +} + +#[test] +fn test_into_inner() { + let m = RwLock::new(NonCopy(10)); + assert_eq!(m.into_inner().unwrap(), NonCopy(10)); +} + +#[test] +fn test_into_inner_drop() { + struct Foo(Arc); + impl Drop for Foo { + fn drop(&mut self) { + self.0.fetch_add(1, Ordering::SeqCst); + } + } + let num_drops = Arc::new(AtomicUsize::new(0)); + let m = RwLock::new(Foo(num_drops.clone())); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + { + let _inner = m.into_inner().unwrap(); + assert_eq!(num_drops.load(Ordering::SeqCst), 0); + } + assert_eq!(num_drops.load(Ordering::SeqCst), 1); +} + +#[test] +fn test_into_inner_poison() { + let m = Arc::new(RwLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison RwLock"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().into_inner() { + Err(e) => assert_eq!(e.into_inner(), NonCopy(10)), + Ok(x) => panic!("into_inner of poisoned RwLock is Ok: {:?}", x), + } +} + +#[test] +fn test_get_mut() { + let mut m = RwLock::new(NonCopy(10)); + *m.get_mut().unwrap() = NonCopy(20); + assert_eq!(m.into_inner().unwrap(), NonCopy(20)); +} + +#[test] +fn test_get_mut_poison() { + let m = Arc::new(RwLock::new(NonCopy(10))); + let m2 = m.clone(); + let _ = thread::spawn(move || { + let _lock = m2.write().unwrap(); + panic!("test panic in inner thread to poison RwLock"); + }) + .join(); + + assert!(m.is_poisoned()); + match Arc::try_unwrap(m).unwrap().get_mut() { + Err(e) => assert_eq!(*e.into_inner(), NonCopy(10)), + Ok(x) => panic!("get_mut of poisoned RwLock is Ok: {:?}", x), + } +} diff --git a/library/std/src/sys/hermit/args.rs b/library/std/src/sys/hermit/args.rs index 72c1b8511c..7727293927 100644 --- a/library/std/src/sys/hermit/args.rs +++ b/library/std/src/sys/hermit/args.rs @@ -57,11 +57,11 @@ mod imp { use crate::ptr; use crate::sys_common::os_str_bytes::*; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/sgx/abi/mem.rs b/library/std/src/sys/sgx/abi/mem.rs index 57fd7efdd4..ffa234fccf 100644 --- a/library/std/src/sys/sgx/abi/mem.rs +++ b/library/std/src/sys/sgx/abi/mem.rs @@ -21,8 +21,15 @@ extern "C" { #[inline(always)] #[unstable(feature = "sgx_platform", issue = "56975")] pub fn image_base() -> u64 { - let base; - unsafe { llvm_asm!("lea IMAGE_BASE(%rip),$0":"=r"(base)) }; + let base: u64; + unsafe { + asm!( + "lea IMAGE_BASE(%rip), {}", + lateout(reg) base, + // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9. + options(att_syntax, nostack, preserves_flags, nomem, pure), + ) + }; base } diff --git a/library/std/src/sys/sgx/abi/tls.rs b/library/std/src/sys/sgx/abi/tls.rs index 2b0485c4f0..0d8952b2f2 100644 --- a/library/std/src/sys/sgx/abi/tls.rs +++ b/library/std/src/sys/sgx/abi/tls.rs @@ -1,3 +1,5 @@ +mod sync_bitset; + use self::sync_bitset::*; use crate::cell::Cell; use crate::mem; @@ -125,117 +127,3 @@ impl Tls { TLS_KEY_IN_USE.clear(key.to_index()); } } - -mod sync_bitset { - use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS}; - use crate::iter::{Enumerate, Peekable}; - use crate::slice::Iter; - use crate::sync::atomic::{AtomicUsize, Ordering}; - - /// A bitset that can be used synchronously. - pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]); - - pub(super) const SYNC_BITSET_INIT: SyncBitset = - SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]); - - impl SyncBitset { - pub fn get(&self, index: usize) -> bool { - let (hi, lo) = Self::split(index); - (self.0[hi].load(Ordering::Relaxed) & lo) != 0 - } - - /// Not atomic. - pub fn iter(&self) -> SyncBitsetIter<'_> { - SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0 } - } - - pub fn clear(&self, index: usize) { - let (hi, lo) = Self::split(index); - self.0[hi].fetch_and(!lo, Ordering::Relaxed); - } - - /// Sets any unset bit. Not atomic. Returns `None` if all bits were - /// observed to be set. - pub fn set(&self) -> Option { - 'elems: for (idx, elem) in self.0.iter().enumerate() { - let mut current = elem.load(Ordering::Relaxed); - loop { - if 0 == !current { - continue 'elems; - } - let trailing_ones = (!current).trailing_zeros() as usize; - match elem.compare_exchange( - current, - current | (1 << trailing_ones), - Ordering::AcqRel, - Ordering::Relaxed, - ) { - Ok(_) => return Some(idx * USIZE_BITS + trailing_ones), - Err(previous) => current = previous, - } - } - } - None - } - - fn split(index: usize) -> (usize, usize) { - (index / USIZE_BITS, 1 << (index % USIZE_BITS)) - } - } - - pub(super) struct SyncBitsetIter<'a> { - iter: Peekable>>, - elem_idx: usize, - } - - impl<'a> Iterator for SyncBitsetIter<'a> { - type Item = usize; - - fn next(&mut self) -> Option { - self.iter.peek().cloned().and_then(|(idx, elem)| { - let elem = elem.load(Ordering::Relaxed); - let low_mask = (1 << self.elem_idx) - 1; - let next = elem & !low_mask; - let next_idx = next.trailing_zeros() as usize; - self.elem_idx = next_idx + 1; - if self.elem_idx >= 64 { - self.elem_idx = 0; - self.iter.next(); - } - match next_idx { - 64 => self.next(), - _ => Some(idx * USIZE_BITS + next_idx), - } - }) - } - } - - #[cfg(test)] - mod tests { - use super::*; - - fn test_data(bitset: [usize; 2], bit_indices: &[usize]) { - let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]); - assert_eq!(set.iter().collect::>(), bit_indices); - for &i in bit_indices { - assert!(set.get(i)); - } - } - - #[test] - fn iter() { - test_data([0b0110_1001, 0], &[0, 3, 5, 6]); - test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]); - test_data([0, 0], &[]); - } - - #[test] - fn set_get_clear() { - let set = SYNC_BITSET_INIT; - let key = set.set().unwrap(); - assert!(set.get(key)); - set.clear(key); - assert!(!set.get(key)); - } - } -} diff --git a/library/std/src/sys/sgx/abi/tls/sync_bitset.rs b/library/std/src/sys/sgx/abi/tls/sync_bitset.rs new file mode 100644 index 0000000000..4eeff8f6ef --- /dev/null +++ b/library/std/src/sys/sgx/abi/tls/sync_bitset.rs @@ -0,0 +1,85 @@ +#[cfg(test)] +mod tests; + +use super::{TLS_KEYS_BITSET_SIZE, USIZE_BITS}; +use crate::iter::{Enumerate, Peekable}; +use crate::slice::Iter; +use crate::sync::atomic::{AtomicUsize, Ordering}; + +/// A bitset that can be used synchronously. +pub(super) struct SyncBitset([AtomicUsize; TLS_KEYS_BITSET_SIZE]); + +pub(super) const SYNC_BITSET_INIT: SyncBitset = + SyncBitset([AtomicUsize::new(0), AtomicUsize::new(0)]); + +impl SyncBitset { + pub fn get(&self, index: usize) -> bool { + let (hi, lo) = Self::split(index); + (self.0[hi].load(Ordering::Relaxed) & lo) != 0 + } + + /// Not atomic. + pub fn iter(&self) -> SyncBitsetIter<'_> { + SyncBitsetIter { iter: self.0.iter().enumerate().peekable(), elem_idx: 0 } + } + + pub fn clear(&self, index: usize) { + let (hi, lo) = Self::split(index); + self.0[hi].fetch_and(!lo, Ordering::Relaxed); + } + + /// Sets any unset bit. Not atomic. Returns `None` if all bits were + /// observed to be set. + pub fn set(&self) -> Option { + 'elems: for (idx, elem) in self.0.iter().enumerate() { + let mut current = elem.load(Ordering::Relaxed); + loop { + if 0 == !current { + continue 'elems; + } + let trailing_ones = (!current).trailing_zeros() as usize; + match elem.compare_exchange( + current, + current | (1 << trailing_ones), + Ordering::AcqRel, + Ordering::Relaxed, + ) { + Ok(_) => return Some(idx * USIZE_BITS + trailing_ones), + Err(previous) => current = previous, + } + } + } + None + } + + fn split(index: usize) -> (usize, usize) { + (index / USIZE_BITS, 1 << (index % USIZE_BITS)) + } +} + +pub(super) struct SyncBitsetIter<'a> { + iter: Peekable>>, + elem_idx: usize, +} + +impl<'a> Iterator for SyncBitsetIter<'a> { + type Item = usize; + + fn next(&mut self) -> Option { + self.iter.peek().cloned().and_then(|(idx, elem)| { + let elem = elem.load(Ordering::Relaxed); + let low_mask = (1 << self.elem_idx) - 1; + let next = elem & !low_mask; + let next_idx = next.trailing_zeros() as usize; + self.elem_idx = next_idx + 1; + if self.elem_idx >= 64 { + self.elem_idx = 0; + self.iter.next(); + } + match next_idx { + 64 => self.next(), + _ => Some(idx * USIZE_BITS + next_idx), + } + }) + } +} diff --git a/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs b/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs new file mode 100644 index 0000000000..d7eb2e139d --- /dev/null +++ b/library/std/src/sys/sgx/abi/tls/sync_bitset/tests.rs @@ -0,0 +1,25 @@ +use super::*; + +fn test_data(bitset: [usize; 2], bit_indices: &[usize]) { + let set = SyncBitset([AtomicUsize::new(bitset[0]), AtomicUsize::new(bitset[1])]); + assert_eq!(set.iter().collect::>(), bit_indices); + for &i in bit_indices { + assert!(set.get(i)); + } +} + +#[test] +fn iter() { + test_data([0b0110_1001, 0], &[0, 3, 5, 6]); + test_data([0x8000_0000_0000_0000, 0x8000_0000_0000_0001], &[63, 64, 127]); + test_data([0, 0], &[]); +} + +#[test] +fn set_get_clear() { + let set = SYNC_BITSET_INIT; + let key = set.set().unwrap(); + assert!(set.get(key)); + set.clear(key); + assert!(!set.get(key)); +} diff --git a/library/std/src/sys/sgx/ext/arch.rs b/library/std/src/sys/sgx/ext/arch.rs index 0c97a87e2e..7488e7e5dc 100644 --- a/library/std/src/sys/sgx/ext/arch.rs +++ b/library/std/src/sys/sgx/ext/arch.rs @@ -31,13 +31,13 @@ pub fn egetkey(request: &Align512<[u8; 512]>) -> Result, u32> let mut out = MaybeUninit::uninit(); let error; - llvm_asm!( - "enclu" - : "={eax}"(error) - : "{eax}"(ENCLU_EGETKEY), - "{rbx}"(request), - "{rcx}"(out.as_mut_ptr()) - : "flags" + asm!( + "enclu", + inlateout("eax") ENCLU_EGETKEY => error, + in("rbx") request, + in("rcx") out.as_mut_ptr(), + // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9. + options(att_syntax, nostack), ); match error { @@ -60,13 +60,14 @@ pub fn ereport( unsafe { let mut report = MaybeUninit::uninit(); - llvm_asm!( - "enclu" - : /* no output registers */ - : "{eax}"(ENCLU_EREPORT), - "{rbx}"(targetinfo), - "{rcx}"(reportdata), - "{rdx}"(report.as_mut_ptr()) + asm!( + "enclu", + in("eax") ENCLU_EREPORT, + in("rbx") targetinfo, + in("rcx") reportdata, + in("rdx") report.as_mut_ptr(), + // NOTE(#76738): ATT syntax is used to support LLVM 8 and 9. + options(att_syntax, preserves_flags, nostack), ); report.assume_init() diff --git a/library/std/src/sys/sgx/fs.rs b/library/std/src/sys/sgx/fs.rs deleted file mode 100644 index ecb5b51ccc..0000000000 --- a/library/std/src/sys/sgx/fs.rs +++ /dev/null @@ -1,308 +0,0 @@ -use crate::ffi::OsString; -use crate::fmt; -use crate::hash::{Hash, Hasher}; -use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; -use crate::path::{Path, PathBuf}; -use crate::sys::time::SystemTime; -use crate::sys::{unsupported, Void}; - -pub struct File(Void); - -pub struct FileAttr(Void); - -pub struct ReadDir(Void); - -pub struct DirEntry(Void); - -#[derive(Clone, Debug)] -pub struct OpenOptions {} - -pub struct FilePermissions(Void); - -pub struct FileType(Void); - -#[derive(Debug)] -pub struct DirBuilder {} - -impl FileAttr { - pub fn size(&self) -> u64 { - match self.0 {} - } - - pub fn perm(&self) -> FilePermissions { - match self.0 {} - } - - pub fn file_type(&self) -> FileType { - match self.0 {} - } - - pub fn modified(&self) -> io::Result { - match self.0 {} - } - - pub fn accessed(&self) -> io::Result { - match self.0 {} - } - - pub fn created(&self) -> io::Result { - match self.0 {} - } -} - -impl Clone for FileAttr { - fn clone(&self) -> FileAttr { - match self.0 {} - } -} - -impl FilePermissions { - pub fn readonly(&self) -> bool { - match self.0 {} - } - - pub fn set_readonly(&mut self, _readonly: bool) { - match self.0 {} - } -} - -impl Clone for FilePermissions { - fn clone(&self) -> FilePermissions { - match self.0 {} - } -} - -impl PartialEq for FilePermissions { - fn eq(&self, _other: &FilePermissions) -> bool { - match self.0 {} - } -} - -impl Eq for FilePermissions {} - -impl fmt::Debug for FilePermissions { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl FileType { - pub fn is_dir(&self) -> bool { - match self.0 {} - } - - pub fn is_file(&self) -> bool { - match self.0 {} - } - - pub fn is_symlink(&self) -> bool { - match self.0 {} - } -} - -impl Clone for FileType { - fn clone(&self) -> FileType { - match self.0 {} - } -} - -impl Copy for FileType {} - -impl PartialEq for FileType { - fn eq(&self, _other: &FileType) -> bool { - match self.0 {} - } -} - -impl Eq for FileType {} - -impl Hash for FileType { - fn hash(&self, _h: &mut H) { - match self.0 {} - } -} - -impl fmt::Debug for FileType { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Debug for ReadDir { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl Iterator for ReadDir { - type Item = io::Result; - - fn next(&mut self) -> Option> { - match self.0 {} - } -} - -impl DirEntry { - pub fn path(&self) -> PathBuf { - match self.0 {} - } - - pub fn file_name(&self) -> OsString { - match self.0 {} - } - - pub fn metadata(&self) -> io::Result { - match self.0 {} - } - - pub fn file_type(&self) -> io::Result { - match self.0 {} - } -} - -impl OpenOptions { - pub fn new() -> OpenOptions { - OpenOptions {} - } - - pub fn read(&mut self, _read: bool) {} - pub fn write(&mut self, _write: bool) {} - pub fn append(&mut self, _append: bool) {} - pub fn truncate(&mut self, _truncate: bool) {} - pub fn create(&mut self, _create: bool) {} - pub fn create_new(&mut self, _create_new: bool) {} -} - -impl File { - pub fn open(_path: &Path, _opts: &OpenOptions) -> io::Result { - unsupported() - } - - pub fn file_attr(&self) -> io::Result { - match self.0 {} - } - - pub fn fsync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn datasync(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn truncate(&self, _size: u64) -> io::Result<()> { - match self.0 {} - } - - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn flush(&self) -> io::Result<()> { - match self.0 {} - } - - pub fn seek(&self, _pos: SeekFrom) -> io::Result { - match self.0 {} - } - - pub fn duplicate(&self) -> io::Result { - match self.0 {} - } - - pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -impl DirBuilder { - pub fn new() -> DirBuilder { - DirBuilder {} - } - - pub fn mkdir(&self, _p: &Path) -> io::Result<()> { - unsupported() - } -} - -impl fmt::Debug for File { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -pub fn readdir(_p: &Path) -> io::Result { - unsupported() -} - -pub fn unlink(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn rename(_old: &Path, _new: &Path) -> io::Result<()> { - unsupported() -} - -pub fn set_perm(_p: &Path, perm: FilePermissions) -> io::Result<()> { - match perm.0 {} -} - -pub fn rmdir(_p: &Path) -> io::Result<()> { - unsupported() -} - -pub fn remove_dir_all(_path: &Path) -> io::Result<()> { - unsupported() -} - -pub fn readlink(_p: &Path) -> io::Result { - unsupported() -} - -pub fn symlink(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn link(_src: &Path, _dst: &Path) -> io::Result<()> { - unsupported() -} - -pub fn stat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn lstat(_p: &Path) -> io::Result { - unsupported() -} - -pub fn canonicalize(_p: &Path) -> io::Result { - unsupported() -} - -pub fn copy(_from: &Path, _to: &Path) -> io::Result { - unsupported() -} diff --git a/library/std/src/sys/sgx/io.rs b/library/std/src/sys/sgx/io.rs deleted file mode 100644 index d5f475b431..0000000000 --- a/library/std/src/sys/sgx/io.rs +++ /dev/null @@ -1,47 +0,0 @@ -use crate::mem; - -#[derive(Copy, Clone)] -pub struct IoSlice<'a>(&'a [u8]); - -impl<'a> IoSlice<'a> { - #[inline] - pub fn new(buf: &'a [u8]) -> IoSlice<'a> { - IoSlice(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - self.0 = &self.0[n..] - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } -} - -pub struct IoSliceMut<'a>(&'a mut [u8]); - -impl<'a> IoSliceMut<'a> { - #[inline] - pub fn new(buf: &'a mut [u8]) -> IoSliceMut<'a> { - IoSliceMut(buf) - } - - #[inline] - pub fn advance(&mut self, n: usize) { - let slice = mem::replace(&mut self.0, &mut []); - let (_, remaining) = slice.split_at_mut(n); - self.0 = remaining; - } - - #[inline] - pub fn as_slice(&self) -> &[u8] { - self.0 - } - - #[inline] - pub fn as_mut_slice(&mut self) -> &mut [u8] { - self.0 - } -} diff --git a/library/std/src/sys/sgx/mod.rs b/library/std/src/sys/sgx/mod.rs index 1d32eb2542..1abd91e75e 100644 --- a/library/std/src/sys/sgx/mod.rs +++ b/library/std/src/sys/sgx/mod.rs @@ -17,14 +17,18 @@ pub mod condvar; pub mod env; pub mod ext; pub mod fd; +#[path = "../unsupported/fs.rs"] pub mod fs; +#[path = "../unsupported/io.rs"] pub mod io; pub mod memchr; pub mod mutex; pub mod net; pub mod os; pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; pub mod rwlock; pub mod stack_overflow; diff --git a/library/std/src/sys/sgx/pipe.rs b/library/std/src/sys/sgx/pipe.rs deleted file mode 100644 index 10d0925823..0000000000 --- a/library/std/src/sys/sgx/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/sgx/process.rs b/library/std/src/sys/sgx/process.rs deleted file mode 100644 index 4702e5c549..0000000000 --- a/library/std/src/sys/sgx/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/sgx/rwlock.rs b/library/std/src/sys/sgx/rwlock.rs index 722b4f5e0b..3bf2a7d8fb 100644 --- a/library/std/src/sys/sgx/rwlock.rs +++ b/library/std/src/sys/sgx/rwlock.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::num::NonZeroUsize; use super::waitqueue::{ @@ -198,50 +201,3 @@ pub unsafe extern "C" fn __rust_rwlock_unlock(p: *mut RWLock) -> i32 { (*p).unlock(); return 0; } - -#[cfg(test)] -mod tests { - use super::*; - use crate::mem::{self, MaybeUninit}; - use core::array::FixedSizeArray; - - // Verify that the bytes of initialized RWLock are the same as in - // libunwind. If they change, `src/UnwindRustSgx.h` in libunwind needs to - // be changed too. - #[test] - fn test_c_rwlock_initializer() { - #[rustfmt::skip] - const RWLOCK_INIT: &[u8] = &[ - /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, - ]; - - #[inline(never)] - fn zero_stack() { - test::black_box(MaybeUninit::<[RWLock; 16]>::zeroed()); - } - - #[inline(never)] - unsafe fn rwlock_new(init: &mut MaybeUninit) { - init.write(RWLock::new()); - } - - unsafe { - // try hard to make sure that the padding/unused bytes in RWLock - // get initialized as 0. If the assertion below fails, that might - // just be an issue with the test code and not with the value of - // RWLOCK_INIT. - zero_stack(); - let mut init = MaybeUninit::::zeroed(); - rwlock_new(&mut init); - assert_eq!(mem::transmute::<_, [u8; 144]>(init.assume_init()).as_slice(), RWLOCK_INIT) - }; - } -} diff --git a/library/std/src/sys/sgx/rwlock/tests.rs b/library/std/src/sys/sgx/rwlock/tests.rs new file mode 100644 index 0000000000..17c9e72ee3 --- /dev/null +++ b/library/std/src/sys/sgx/rwlock/tests.rs @@ -0,0 +1,31 @@ +use super::*; + +// Verify that the byte pattern libunwind uses to initialize an RWLock is +// equivalent to the value of RWLock::new(). If the value changes, +// `src/UnwindRustSgx.h` in libunwind needs to be changed too. +#[test] +fn test_c_rwlock_initializer() { + #[rustfmt::skip] + const C_RWLOCK_INIT: &[u8] = &[ + /* 0x00 */ 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x10 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x20 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x30 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x40 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x1, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x50 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x60 */ 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x70 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + /* 0x80 */ 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + ]; + + // For the test to work, we need the padding/unused bytes in RWLock to be + // initialized as 0. In practice, this is the case with statics. + static RUST_RWLOCK_INIT: RWLock = RWLock::new(); + + unsafe { + // If the assertion fails, that not necessarily an issue with the value + // of C_RWLOCK_INIT. It might just be an issue with the way padding + // bytes are initialized in the test code. + assert_eq!(&crate::mem::transmute_copy::<_, [u8; 144]>(&RUST_RWLOCK_INIT), C_RWLOCK_INIT); + }; +} diff --git a/library/std/src/sys/sgx/waitqueue.rs b/library/std/src/sys/sgx/waitqueue.rs index 070afa55f3..e464dc3ee9 100644 --- a/library/std/src/sys/sgx/waitqueue.rs +++ b/library/std/src/sys/sgx/waitqueue.rs @@ -9,6 +9,18 @@ //! Since userspace may send spurious wake-ups, the wakeup event state is //! recorded in the enclave. The wakeup event state is protected by a spinlock. //! The queue and associated wait state are stored in a `WaitVariable`. + +#[cfg(test)] +mod tests; + +/// A doubly-linked list where callers are in charge of memory allocation +/// of the nodes in the list. +mod unsafe_list; + +/// Trivial spinlock-based implementation of `sync::Mutex`. +// FIXME: Perhaps use Intel TSX to avoid locking? +mod spin_mutex; + use crate::num::NonZeroUsize; use crate::ops::{Deref, DerefMut}; use crate::time::Duration; @@ -231,389 +243,3 @@ impl WaitQueue { } } } - -/// A doubly-linked list where callers are in charge of memory allocation -/// of the nodes in the list. -mod unsafe_list { - use crate::mem; - use crate::ptr::NonNull; - - pub struct UnsafeListEntry { - next: NonNull>, - prev: NonNull>, - value: Option, - } - - impl UnsafeListEntry { - fn dummy() -> Self { - UnsafeListEntry { next: NonNull::dangling(), prev: NonNull::dangling(), value: None } - } - - pub fn new(value: T) -> Self { - UnsafeListEntry { value: Some(value), ..Self::dummy() } - } - } - - pub struct UnsafeList { - head_tail: NonNull>, - head_tail_entry: Option>, - } - - impl UnsafeList { - pub const fn new() -> Self { - unsafe { - UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } - } - } - - unsafe fn init(&mut self) { - if self.head_tail_entry.is_none() { - self.head_tail_entry = Some(UnsafeListEntry::dummy()); - self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()); - self.head_tail.as_mut().next = self.head_tail; - self.head_tail.as_mut().prev = self.head_tail; - } - } - - pub fn is_empty(&self) -> bool { - unsafe { - if self.head_tail_entry.is_some() { - let first = self.head_tail.as_ref().next; - if first == self.head_tail { - // ,-------> /---------\ next ---, - // | |head_tail| | - // `--- prev \---------/ <-------` - rtassert!(self.head_tail.as_ref().prev == first); - true - } else { - false - } - } else { - true - } - } - } - - /// Pushes an entry onto the back of the list. - /// - /// # Safety - /// - /// The entry must remain allocated until the entry is removed from the - /// list AND the caller who popped is done using the entry. Special - /// care must be taken in the caller of `push` to ensure unwinding does - /// not destroy the stack frame containing the entry. - pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry) -> &'a T { - self.init(); - - // BEFORE: - // /---------\ next ---> /---------\ - // ... |prev_tail| |head_tail| ... - // \---------/ <--- prev \---------/ - // - // AFTER: - // /---------\ next ---> /-----\ next ---> /---------\ - // ... |prev_tail| |entry| |head_tail| ... - // \---------/ <--- prev \-----/ <--- prev \---------/ - let mut entry = NonNull::new_unchecked(entry); - let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry); - entry.as_mut().prev = prev_tail; - entry.as_mut().next = self.head_tail; - prev_tail.as_mut().next = entry; - // unwrap ok: always `Some` on non-dummy entries - (*entry.as_ptr()).value.as_ref().unwrap() - } - - /// Pops an entry from the front of the list. - /// - /// # Safety - /// - /// The caller must make sure to synchronize ending the borrow of the - /// return value and deallocation of the containing entry. - pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> { - self.init(); - - if self.is_empty() { - None - } else { - // BEFORE: - // /---------\ next ---> /-----\ next ---> /------\ - // ... |head_tail| |first| |second| ... - // \---------/ <--- prev \-----/ <--- prev \------/ - // - // AFTER: - // /---------\ next ---> /------\ - // ... |head_tail| |second| ... - // \---------/ <--- prev \------/ - let mut first = self.head_tail.as_mut().next; - let mut second = first.as_mut().next; - self.head_tail.as_mut().next = second; - second.as_mut().prev = self.head_tail; - first.as_mut().next = NonNull::dangling(); - first.as_mut().prev = NonNull::dangling(); - // unwrap ok: always `Some` on non-dummy entries - Some((*first.as_ptr()).value.as_ref().unwrap()) - } - } - - /// Removes an entry from the list. - /// - /// # Safety - /// - /// The caller must ensure that `entry` has been pushed onto `self` - /// prior to this call and has not moved since then. - pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry) { - rtassert!(!self.is_empty()); - // BEFORE: - // /----\ next ---> /-----\ next ---> /----\ - // ... |prev| |entry| |next| ... - // \----/ <--- prev \-----/ <--- prev \----/ - // - // AFTER: - // /----\ next ---> /----\ - // ... |prev| |next| ... - // \----/ <--- prev \----/ - let mut prev = entry.prev; - let mut next = entry.next; - prev.as_mut().next = next; - next.as_mut().prev = prev; - entry.next = NonNull::dangling(); - entry.prev = NonNull::dangling(); - } - } - - #[cfg(test)] - mod tests { - use super::*; - use crate::cell::Cell; - - unsafe fn assert_empty(list: &mut UnsafeList) { - assert!(list.pop().is_none(), "assertion failed: list is not empty"); - } - - #[test] - fn init_empty() { - unsafe { - assert_empty(&mut UnsafeList::::new()); - } - } - - #[test] - fn push_pop() { - unsafe { - let mut node = UnsafeListEntry::new(1234); - let mut list = UnsafeList::new(); - assert_eq!(list.push(&mut node), &1234); - assert_eq!(list.pop().unwrap(), &1234); - assert_empty(&mut list); - } - } - - #[test] - fn push_remove() { - unsafe { - let mut node = UnsafeListEntry::new(1234); - let mut list = UnsafeList::new(); - assert_eq!(list.push(&mut node), &1234); - list.remove(&mut node); - assert_empty(&mut list); - } - } - - #[test] - fn push_remove_pop() { - unsafe { - let mut node1 = UnsafeListEntry::new(11); - let mut node2 = UnsafeListEntry::new(12); - let mut node3 = UnsafeListEntry::new(13); - let mut node4 = UnsafeListEntry::new(14); - let mut node5 = UnsafeListEntry::new(15); - let mut list = UnsafeList::new(); - assert_eq!(list.push(&mut node1), &11); - assert_eq!(list.push(&mut node2), &12); - assert_eq!(list.push(&mut node3), &13); - assert_eq!(list.push(&mut node4), &14); - assert_eq!(list.push(&mut node5), &15); - - list.remove(&mut node1); - assert_eq!(list.pop().unwrap(), &12); - list.remove(&mut node3); - assert_eq!(list.pop().unwrap(), &14); - list.remove(&mut node5); - assert_empty(&mut list); - - assert_eq!(list.push(&mut node1), &11); - assert_eq!(list.pop().unwrap(), &11); - assert_empty(&mut list); - - assert_eq!(list.push(&mut node3), &13); - assert_eq!(list.push(&mut node4), &14); - list.remove(&mut node3); - list.remove(&mut node4); - assert_empty(&mut list); - } - } - - #[test] - fn complex_pushes_pops() { - unsafe { - let mut node1 = UnsafeListEntry::new(1234); - let mut node2 = UnsafeListEntry::new(4567); - let mut node3 = UnsafeListEntry::new(9999); - let mut node4 = UnsafeListEntry::new(8642); - let mut list = UnsafeList::new(); - list.push(&mut node1); - list.push(&mut node2); - assert_eq!(list.pop().unwrap(), &1234); - list.push(&mut node3); - assert_eq!(list.pop().unwrap(), &4567); - assert_eq!(list.pop().unwrap(), &9999); - assert_empty(&mut list); - list.push(&mut node4); - assert_eq!(list.pop().unwrap(), &8642); - assert_empty(&mut list); - } - } - - #[test] - fn cell() { - unsafe { - let mut node = UnsafeListEntry::new(Cell::new(0)); - let mut list = UnsafeList::new(); - let noderef = list.push(&mut node); - assert_eq!(noderef.get(), 0); - list.pop().unwrap().set(1); - assert_empty(&mut list); - assert_eq!(noderef.get(), 1); - } - } - } -} - -/// Trivial spinlock-based implementation of `sync::Mutex`. -// FIXME: Perhaps use Intel TSX to avoid locking? -mod spin_mutex { - use crate::cell::UnsafeCell; - use crate::ops::{Deref, DerefMut}; - use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; - - #[derive(Default)] - pub struct SpinMutex { - value: UnsafeCell, - lock: AtomicBool, - } - - unsafe impl Send for SpinMutex {} - unsafe impl Sync for SpinMutex {} - - pub struct SpinMutexGuard<'a, T: 'a> { - mutex: &'a SpinMutex, - } - - impl<'a, T> !Send for SpinMutexGuard<'a, T> {} - unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {} - - impl SpinMutex { - pub const fn new(value: T) -> Self { - SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) } - } - - #[inline(always)] - pub fn lock(&self) -> SpinMutexGuard<'_, T> { - loop { - match self.try_lock() { - None => { - while self.lock.load(Ordering::Relaxed) { - spin_loop_hint() - } - } - Some(guard) => return guard, - } - } - } - - #[inline(always)] - pub fn try_lock(&self) -> Option> { - if !self.lock.compare_and_swap(false, true, Ordering::Acquire) { - Some(SpinMutexGuard { mutex: self }) - } else { - None - } - } - } - - /// Lock the Mutex or return false. - pub macro try_lock_or_false($e:expr) { - if let Some(v) = $e.try_lock() { v } else { return false } - } - - impl<'a, T> Deref for SpinMutexGuard<'a, T> { - type Target = T; - - fn deref(&self) -> &T { - unsafe { &*self.mutex.value.get() } - } - } - - impl<'a, T> DerefMut for SpinMutexGuard<'a, T> { - fn deref_mut(&mut self) -> &mut T { - unsafe { &mut *self.mutex.value.get() } - } - } - - impl<'a, T> Drop for SpinMutexGuard<'a, T> { - fn drop(&mut self) { - self.mutex.lock.store(false, Ordering::Release) - } - } - - #[cfg(test)] - mod tests { - #![allow(deprecated)] - - use super::*; - use crate::sync::Arc; - use crate::thread; - use crate::time::Duration; - - #[test] - fn sleep() { - let mutex = Arc::new(SpinMutex::::default()); - let mutex2 = mutex.clone(); - let guard = mutex.lock(); - let t1 = thread::spawn(move || { - *mutex2.lock() = 1; - }); - - thread::sleep(Duration::from_millis(50)); - - assert_eq!(*guard, 0); - drop(guard); - t1.join().unwrap(); - assert_eq!(*mutex.lock(), 1); - } - } -} - -#[cfg(test)] -mod tests { - use super::*; - use crate::sync::Arc; - use crate::thread; - - #[test] - fn queue() { - let wq = Arc::new(SpinMutex::>::default()); - let wq2 = wq.clone(); - - let locked = wq.lock(); - - let t1 = thread::spawn(move || { - // if we obtain the lock, the main thread should be waiting - assert!(WaitQueue::notify_one(wq2.lock()).is_ok()); - }); - - WaitQueue::wait(locked, || {}); - - t1.join().unwrap(); - } -} diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs new file mode 100644 index 0000000000..d99ce895da --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex.rs @@ -0,0 +1,76 @@ +#[cfg(test)] +mod tests; + +use crate::cell::UnsafeCell; +use crate::ops::{Deref, DerefMut}; +use crate::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; + +#[derive(Default)] +pub struct SpinMutex { + value: UnsafeCell, + lock: AtomicBool, +} + +unsafe impl Send for SpinMutex {} +unsafe impl Sync for SpinMutex {} + +pub struct SpinMutexGuard<'a, T: 'a> { + mutex: &'a SpinMutex, +} + +impl<'a, T> !Send for SpinMutexGuard<'a, T> {} +unsafe impl<'a, T: Sync> Sync for SpinMutexGuard<'a, T> {} + +impl SpinMutex { + pub const fn new(value: T) -> Self { + SpinMutex { value: UnsafeCell::new(value), lock: AtomicBool::new(false) } + } + + #[inline(always)] + pub fn lock(&self) -> SpinMutexGuard<'_, T> { + loop { + match self.try_lock() { + None => { + while self.lock.load(Ordering::Relaxed) { + spin_loop_hint() + } + } + Some(guard) => return guard, + } + } + } + + #[inline(always)] + pub fn try_lock(&self) -> Option> { + if !self.lock.compare_and_swap(false, true, Ordering::Acquire) { + Some(SpinMutexGuard { mutex: self }) + } else { + None + } + } +} + +/// Lock the Mutex or return false. +pub macro try_lock_or_false($e:expr) { + if let Some(v) = $e.try_lock() { v } else { return false } +} + +impl<'a, T> Deref for SpinMutexGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.mutex.value.get() } + } +} + +impl<'a, T> DerefMut for SpinMutexGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.mutex.value.get() } + } +} + +impl<'a, T> Drop for SpinMutexGuard<'a, T> { + fn drop(&mut self) { + self.mutex.lock.store(false, Ordering::Release) + } +} diff --git a/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs b/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs new file mode 100644 index 0000000000..4c5994bea6 --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/spin_mutex/tests.rs @@ -0,0 +1,23 @@ +#![allow(deprecated)] + +use super::*; +use crate::sync::Arc; +use crate::thread; +use crate::time::Duration; + +#[test] +fn sleep() { + let mutex = Arc::new(SpinMutex::::default()); + let mutex2 = mutex.clone(); + let guard = mutex.lock(); + let t1 = thread::spawn(move || { + *mutex2.lock() = 1; + }); + + thread::sleep(Duration::from_millis(50)); + + assert_eq!(*guard, 0); + drop(guard); + t1.join().unwrap(); + assert_eq!(*mutex.lock(), 1); +} diff --git a/library/std/src/sys/sgx/waitqueue/tests.rs b/library/std/src/sys/sgx/waitqueue/tests.rs new file mode 100644 index 0000000000..bf91fdd08e --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/tests.rs @@ -0,0 +1,20 @@ +use super::*; +use crate::sync::Arc; +use crate::thread; + +#[test] +fn queue() { + let wq = Arc::new(SpinMutex::>::default()); + let wq2 = wq.clone(); + + let locked = wq.lock(); + + let t1 = thread::spawn(move || { + // if we obtain the lock, the main thread should be waiting + assert!(WaitQueue::notify_one(wq2.lock()).is_ok()); + }); + + WaitQueue::wait(locked, || {}); + + t1.join().unwrap(); +} diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs new file mode 100644 index 0000000000..7a24654273 --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/unsafe_list.rs @@ -0,0 +1,146 @@ +#[cfg(test)] +mod tests; + +use crate::mem; +use crate::ptr::NonNull; + +pub struct UnsafeListEntry { + next: NonNull>, + prev: NonNull>, + value: Option, +} + +impl UnsafeListEntry { + fn dummy() -> Self { + UnsafeListEntry { next: NonNull::dangling(), prev: NonNull::dangling(), value: None } + } + + pub fn new(value: T) -> Self { + UnsafeListEntry { value: Some(value), ..Self::dummy() } + } +} + +pub struct UnsafeList { + head_tail: NonNull>, + head_tail_entry: Option>, +} + +impl UnsafeList { + pub const fn new() -> Self { + unsafe { UnsafeList { head_tail: NonNull::new_unchecked(1 as _), head_tail_entry: None } } + } + + unsafe fn init(&mut self) { + if self.head_tail_entry.is_none() { + self.head_tail_entry = Some(UnsafeListEntry::dummy()); + self.head_tail = NonNull::new_unchecked(self.head_tail_entry.as_mut().unwrap()); + self.head_tail.as_mut().next = self.head_tail; + self.head_tail.as_mut().prev = self.head_tail; + } + } + + pub fn is_empty(&self) -> bool { + unsafe { + if self.head_tail_entry.is_some() { + let first = self.head_tail.as_ref().next; + if first == self.head_tail { + // ,-------> /---------\ next ---, + // | |head_tail| | + // `--- prev \---------/ <-------` + rtassert!(self.head_tail.as_ref().prev == first); + true + } else { + false + } + } else { + true + } + } + } + + /// Pushes an entry onto the back of the list. + /// + /// # Safety + /// + /// The entry must remain allocated until the entry is removed from the + /// list AND the caller who popped is done using the entry. Special + /// care must be taken in the caller of `push` to ensure unwinding does + /// not destroy the stack frame containing the entry. + pub unsafe fn push<'a>(&mut self, entry: &'a mut UnsafeListEntry) -> &'a T { + self.init(); + + // BEFORE: + // /---------\ next ---> /---------\ + // ... |prev_tail| |head_tail| ... + // \---------/ <--- prev \---------/ + // + // AFTER: + // /---------\ next ---> /-----\ next ---> /---------\ + // ... |prev_tail| |entry| |head_tail| ... + // \---------/ <--- prev \-----/ <--- prev \---------/ + let mut entry = NonNull::new_unchecked(entry); + let mut prev_tail = mem::replace(&mut self.head_tail.as_mut().prev, entry); + entry.as_mut().prev = prev_tail; + entry.as_mut().next = self.head_tail; + prev_tail.as_mut().next = entry; + // unwrap ok: always `Some` on non-dummy entries + (*entry.as_ptr()).value.as_ref().unwrap() + } + + /// Pops an entry from the front of the list. + /// + /// # Safety + /// + /// The caller must make sure to synchronize ending the borrow of the + /// return value and deallocation of the containing entry. + pub unsafe fn pop<'a>(&mut self) -> Option<&'a T> { + self.init(); + + if self.is_empty() { + None + } else { + // BEFORE: + // /---------\ next ---> /-----\ next ---> /------\ + // ... |head_tail| |first| |second| ... + // \---------/ <--- prev \-----/ <--- prev \------/ + // + // AFTER: + // /---------\ next ---> /------\ + // ... |head_tail| |second| ... + // \---------/ <--- prev \------/ + let mut first = self.head_tail.as_mut().next; + let mut second = first.as_mut().next; + self.head_tail.as_mut().next = second; + second.as_mut().prev = self.head_tail; + first.as_mut().next = NonNull::dangling(); + first.as_mut().prev = NonNull::dangling(); + // unwrap ok: always `Some` on non-dummy entries + Some((*first.as_ptr()).value.as_ref().unwrap()) + } + } + + /// Removes an entry from the list. + /// + /// # Safety + /// + /// The caller must ensure that `entry` has been pushed onto `self` + /// prior to this call and has not moved since then. + pub unsafe fn remove(&mut self, entry: &mut UnsafeListEntry) { + rtassert!(!self.is_empty()); + // BEFORE: + // /----\ next ---> /-----\ next ---> /----\ + // ... |prev| |entry| |next| ... + // \----/ <--- prev \-----/ <--- prev \----/ + // + // AFTER: + // /----\ next ---> /----\ + // ... |prev| |next| ... + // \----/ <--- prev \----/ + let mut prev = entry.prev; + let mut next = entry.next; + prev.as_mut().next = next; + next.as_mut().prev = prev; + entry.next = NonNull::dangling(); + entry.prev = NonNull::dangling(); + } +} diff --git a/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs new file mode 100644 index 0000000000..1f031ed195 --- /dev/null +++ b/library/std/src/sys/sgx/waitqueue/unsafe_list/tests.rs @@ -0,0 +1,103 @@ +use super::*; +use crate::cell::Cell; + +unsafe fn assert_empty(list: &mut UnsafeList) { + assert!(list.pop().is_none(), "assertion failed: list is not empty"); +} + +#[test] +fn init_empty() { + unsafe { + assert_empty(&mut UnsafeList::::new()); + } +} + +#[test] +fn push_pop() { + unsafe { + let mut node = UnsafeListEntry::new(1234); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node), &1234); + assert_eq!(list.pop().unwrap(), &1234); + assert_empty(&mut list); + } +} + +#[test] +fn push_remove() { + unsafe { + let mut node = UnsafeListEntry::new(1234); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node), &1234); + list.remove(&mut node); + assert_empty(&mut list); + } +} + +#[test] +fn push_remove_pop() { + unsafe { + let mut node1 = UnsafeListEntry::new(11); + let mut node2 = UnsafeListEntry::new(12); + let mut node3 = UnsafeListEntry::new(13); + let mut node4 = UnsafeListEntry::new(14); + let mut node5 = UnsafeListEntry::new(15); + let mut list = UnsafeList::new(); + assert_eq!(list.push(&mut node1), &11); + assert_eq!(list.push(&mut node2), &12); + assert_eq!(list.push(&mut node3), &13); + assert_eq!(list.push(&mut node4), &14); + assert_eq!(list.push(&mut node5), &15); + + list.remove(&mut node1); + assert_eq!(list.pop().unwrap(), &12); + list.remove(&mut node3); + assert_eq!(list.pop().unwrap(), &14); + list.remove(&mut node5); + assert_empty(&mut list); + + assert_eq!(list.push(&mut node1), &11); + assert_eq!(list.pop().unwrap(), &11); + assert_empty(&mut list); + + assert_eq!(list.push(&mut node3), &13); + assert_eq!(list.push(&mut node4), &14); + list.remove(&mut node3); + list.remove(&mut node4); + assert_empty(&mut list); + } +} + +#[test] +fn complex_pushes_pops() { + unsafe { + let mut node1 = UnsafeListEntry::new(1234); + let mut node2 = UnsafeListEntry::new(4567); + let mut node3 = UnsafeListEntry::new(9999); + let mut node4 = UnsafeListEntry::new(8642); + let mut list = UnsafeList::new(); + list.push(&mut node1); + list.push(&mut node2); + assert_eq!(list.pop().unwrap(), &1234); + list.push(&mut node3); + assert_eq!(list.pop().unwrap(), &4567); + assert_eq!(list.pop().unwrap(), &9999); + assert_empty(&mut list); + list.push(&mut node4); + assert_eq!(list.pop().unwrap(), &8642); + assert_empty(&mut list); + } +} + +#[test] +fn cell() { + unsafe { + let mut node = UnsafeListEntry::new(Cell::new(0)); + let mut list = UnsafeList::new(); + let noderef = list.push(&mut node); + assert_eq!(noderef.get(), 0); + list.pop().unwrap().set(1); + assert_empty(&mut list); + assert_eq!(noderef.get(), 1); + } +} diff --git a/library/std/src/sys/unix/alloc.rs b/library/std/src/sys/unix/alloc.rs index 8e19393546..964abe8b8c 100644 --- a/library/std/src/sys/unix/alloc.rs +++ b/library/std/src/sys/unix/alloc.rs @@ -52,46 +52,48 @@ unsafe impl GlobalAlloc for System { } } -#[cfg(any( - target_os = "android", - target_os = "illumos", - 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 = "illumos", - target_os = "redox", - target_os = "solaris" -)))] -#[inline] -unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { - let mut out = ptr::null_mut(); - // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. - // Since these are all powers of 2, we can just use max. - let align = layout.align().max(crate::mem::size_of::()); - let ret = libc::posix_memalign(&mut out, align, layout.size()); - if ret != 0 { ptr::null_mut() } else { out as *mut u8 } +cfg_if::cfg_if! { + if #[cfg(any( + target_os = "android", + target_os = "illumos", + 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 + } + } else if #[cfg(target_os = "wasi")] { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 + } + } else { + #[inline] + unsafe fn aligned_malloc(layout: &Layout) -> *mut u8 { + let mut out = ptr::null_mut(); + // posix_memalign requires that the alignment be a multiple of `sizeof(void*)`. + // Since these are all powers of 2, we can just use max. + let align = layout.align().max(crate::mem::size_of::()); + let ret = libc::posix_memalign(&mut out, align, layout.size()); + if ret != 0 { ptr::null_mut() } else { out as *mut u8 } + } + } } diff --git a/library/std/src/sys/unix/args.rs b/library/std/src/sys/unix/args.rs index 9bc44a5948..f7c3f16371 100644 --- a/library/std/src/sys/unix/args.rs +++ b/library/std/src/sys/unix/args.rs @@ -80,13 +80,13 @@ mod imp { use crate::ptr; use crate::sync::atomic::{AtomicIsize, AtomicPtr, Ordering}; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static ARGC: AtomicIsize = AtomicIsize::new(0); static ARGV: AtomicPtr<*const u8> = AtomicPtr::new(ptr::null_mut()); // We never call `ENV_LOCK.init()`, so it is UB to attempt to // acquire this mutex reentrantly! - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); unsafe fn really_init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/unix/ext/ffi.rs b/library/std/src/sys/unix/ext/ffi.rs index 76b34a6b5d..123f85deaf 100644 --- a/library/std/src/sys/unix/ext/ffi.rs +++ b/library/std/src/sys/unix/ext/ffi.rs @@ -1,4 +1,4 @@ -//! Unix-specific extension to the primitives in the `std::ffi` module +//! Unix-specific extension to the primitives in the `std::ffi` module. //! //! # Examples //! diff --git a/library/std/src/sys/unix/ext/fs.rs b/library/std/src/sys/unix/ext/fs.rs index b590a0280d..4b9f4ceb29 100644 --- a/library/std/src/sys/unix/ext/fs.rs +++ b/library/std/src/sys/unix/ext/fs.rs @@ -8,6 +8,9 @@ use crate::path::Path; use crate::sys; use crate::sys::platform::fs::MetadataExt as UnixMetadataExt; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; +// Used for `File::read` on intra-doc links +#[allow(unused_imports)] +use io::{Read, Write}; /// Unix-specific extensions to [`fs::File`]. #[stable(feature = "file_offset", since = "1.15.0")] @@ -24,7 +27,7 @@ pub trait FileExt { /// Note that similar to [`File::read`], it is not an error to return with a /// short read. /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read + /// [`File::read`]: fs::File::read /// /// # Examples /// @@ -127,7 +130,7 @@ pub trait FileExt { /// Note that similar to [`File::write`], it is not an error to return a /// short write. /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write + /// [`File::write`]: fs::File::write /// /// # Examples /// @@ -425,7 +428,7 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; - /// use std::io; + /// use std::io; /// /// fn main() -> io::Result<()> { /// let meta = fs::metadata("some_file")?; @@ -833,15 +836,6 @@ impl DirEntryExt for fs::DirEntry { /// /// The `dst` path will be a symbolic link pointing to the `src` path. /// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// /// # Examples /// /// ```no_run diff --git a/library/std/src/sys/unix/ext/io.rs b/library/std/src/sys/unix/ext/io.rs index 5077e2e28d..ef3c689bd3 100644 --- a/library/std/src/sys/unix/ext/io.rs +++ b/library/std/src/sys/unix/ext/io.rs @@ -1,4 +1,4 @@ -//! Unix-specific extensions to general I/O primitives +//! Unix-specific extensions to general I/O primitives. #![stable(feature = "rust1", since = "1.0.0")] @@ -25,6 +25,19 @@ pub trait AsRawFd { /// 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. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::unix::io::{AsRawFd, RawFd}; + /// + /// let mut f = File::open("foo.txt")?; + /// // Note that `raw_fd` is only valid as long as `f` exists. + /// let raw_fd: RawFd = f.as_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` #[stable(feature = "rust1", since = "1.0.0")] fn as_raw_fd(&self) -> RawFd; } @@ -45,6 +58,21 @@ pub trait FromRawFd { /// 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. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::unix::io::{FromRawFd, IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// // SAFETY: no other functions should call `from_raw_fd`, so there + /// // is only one owner for the file descriptor. + /// let f = unsafe { File::from_raw_fd(raw_fd) }; + /// # Ok::<(), io::Error>(()) + /// ``` #[stable(feature = "from_raw_os", since = "1.1.0")] unsafe fn from_raw_fd(fd: RawFd) -> Self; } @@ -58,10 +86,41 @@ pub trait IntoRawFd { /// 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. + /// + /// # Example + /// + /// ```no_run + /// use std::fs::File; + /// # use std::io; + /// use std::os::unix::io::{IntoRawFd, RawFd}; + /// + /// let f = File::open("foo.txt")?; + /// let raw_fd: RawFd = f.into_raw_fd(); + /// # Ok::<(), io::Error>(()) + /// ``` #[stable(feature = "into_raw_os", since = "1.4.0")] fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/sys/unix/ext/mod.rs b/library/std/src/sys/unix/ext/mod.rs index cbdb1c1004..f435468809 100644 --- a/library/std/src/sys/unix/ext/mod.rs +++ b/library/std/src/sys/unix/ext/mod.rs @@ -37,6 +37,18 @@ pub mod process; pub mod raw; pub mod thread; +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub mod ucred; + /// A prelude for conveniently writing platform-specific code. /// /// Includes all extension traits, and some important type definitions. diff --git a/library/std/src/sys/unix/ext/net.rs b/library/std/src/sys/unix/ext/net.rs index 55803ddfc4..3d2366554b 100644 --- a/library/std/src/sys/unix/ext/net.rs +++ b/library/std/src/sys/unix/ext/net.rs @@ -1,6 +1,9 @@ +//! Unix-specific networking functionality. + #![stable(feature = "unix_socket", since = "1.10.0")] -//! Unix-specific networking functionality +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; // FIXME(#43348): Make libc adapt #[doc(cfg(...))] so we don't need these fake definitions here? #[cfg(not(unix))] @@ -27,6 +30,29 @@ use crate::sys::{self, cvt}; use crate::sys_common::{self, AsInner, FromInner, IntoInner}; use crate::time::Duration; +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +use crate::os::unix::ucred; + +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use ucred::UCred; + #[cfg(any( target_os = "linux", target_os = "android", @@ -402,6 +428,34 @@ impl UnixStream { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } + /// Gets the peer credentials for this Unix domain socket. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(peer_credentials_unix_socket)] + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let peer_cred = socket.peer_cred().expect("Couldn't get peer credentials"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] + #[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" + ))] + pub fn peer_cred(&self) -> io::Result { + ucred::peer_cred(self) + } + /// Sets the read timeout for the socket. /// /// If the provided value is [`None`], then [`read`] calls will block @@ -591,6 +645,32 @@ impl UnixStream { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixStream; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixStream::connect("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } } #[stable(feature = "unix_socket", since = "1.10.0")] @@ -1288,6 +1368,33 @@ impl UnixDatagram { SocketAddr::new(|addr, len| unsafe { libc::getpeername(*self.0.as_inner(), addr, len) }) } + fn recv_from_flags( + &self, + buf: &mut [u8], + flags: libc::c_int, + ) -> io::Result<(usize, SocketAddr)> { + let mut count = 0; + let addr = SocketAddr::new(|addr, len| unsafe { + count = libc::recvfrom( + *self.0.as_inner(), + buf.as_mut_ptr() as *mut _, + buf.len(), + flags, + addr, + len, + ); + if count > 0 { + 1 + } else if count == 0 { + 0 + } else { + -1 + } + })?; + + Ok((count as usize, addr)) + } + /// Receives data from the socket. /// /// On success, returns the number of bytes read and the address from @@ -1308,26 +1415,7 @@ impl UnixDatagram { /// ``` #[stable(feature = "unix_socket", since = "1.10.0")] pub fn recv_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { - let mut count = 0; - let addr = SocketAddr::new(|addr, len| unsafe { - count = libc::recvfrom( - *self.0.as_inner(), - buf.as_mut_ptr() as *mut _, - buf.len(), - 0, - addr, - len, - ); - if count > 0 { - 1 - } else if count == 0 { - 0 - } else { - -1 - } - })?; - - Ok((count as usize, addr)) + self.recv_from_flags(buf, 0) } /// Receives data from the socket. @@ -1598,6 +1686,64 @@ impl UnixDatagram { pub fn shutdown(&self, how: Shutdown) -> io::Result<()> { self.0.shutdown(how) } + + /// Receives data on the socket from the remote address to which it is + /// connected, without removing that data from the queue. On success, + /// returns the number of bytes peeked. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recv` system call. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let len = socket.peek(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek(&self, buf: &mut [u8]) -> io::Result { + self.0.peek(buf) + } + + /// Receives a single datagram message on the socket, without removing it from the + /// queue. On success, returns the number of bytes read and the origin. + /// + /// The function must be called with valid byte array `buf` of sufficient size to + /// hold the message bytes. If a message is too long to fit in the supplied buffer, + /// excess bytes may be discarded. + /// + /// Successive calls return the same data. This is accomplished by passing + /// `MSG_PEEK` as a flag to the underlying `recvfrom` system call. + /// + /// Do not use this function to implement busy waiting, instead use `libc::poll` to + /// synchronize IO events on one or more sockets. + /// + /// # Examples + /// + /// ```no_run + /// #![feature(unix_socket_peek)] + /// + /// use std::os::unix::net::UnixDatagram; + /// + /// fn main() -> std::io::Result<()> { + /// let socket = UnixDatagram::bind("/tmp/sock")?; + /// let mut buf = [0; 10]; + /// let (len, addr) = socket.peek_from(&mut buf).expect("peek failed"); + /// Ok(()) + /// } + /// ``` + #[unstable(feature = "unix_socket_peek", issue = "76923")] + pub fn peek_from(&self, buf: &mut [u8]) -> io::Result<(usize, SocketAddr)> { + self.recv_from_flags(buf, libc::MSG_PEEK) + } } #[stable(feature = "unix_socket", since = "1.10.0")] @@ -1620,382 +1766,3 @@ impl IntoRawFd for UnixDatagram { self.0.into_inner() } } - -#[cfg(all(test, not(target_os = "emscripten")))] -mod test { - use crate::io::prelude::*; - use crate::io::{self, ErrorKind}; - use crate::sys_common::io::test::tmpdir; - use crate::thread; - use crate::time::Duration; - - use super::*; - - macro_rules! or_panic { - ($e:expr) => { - match $e { - Ok(e) => e, - Err(e) => panic!("{}", e), - } - }; - } - - #[test] - fn basic() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world!"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - 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(&socket_path)); - assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); - 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(); - } - - #[test] - fn vectored() { - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - - let len = or_panic!(s1.write_vectored(&[ - IoSlice::new(b"hello"), - IoSlice::new(b" "), - IoSlice::new(b"world!") - ],)); - assert_eq!(len, 12); - - let mut buf1 = [0; 6]; - let mut buf2 = [0; 7]; - let len = or_panic!( - s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],) - ); - assert_eq!(len, 12); - assert_eq!(&buf1, b"hello "); - assert_eq!(&buf2, b"world!\0"); - } - - #[test] - fn pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (mut s1, mut s2) = or_panic!(UnixStream::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.write_all(msg2)); - }); - - or_panic!(s2.write_all(msg1)); - let mut buf = vec![]; - or_panic!(s2.read_to_end(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); - } - - #[test] - fn try_clone() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - let msg1 = b"hello"; - let msg2 = b"world"; - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let thread = thread::spawn(move || { - let mut stream = or_panic!(listener.accept()).0; - or_panic!(stream.write_all(msg1)); - or_panic!(stream.write_all(msg2)); - }); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - let mut stream2 = or_panic!(stream.try_clone()); - - let mut buf = [0; 5]; - or_panic!(stream.read(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(stream2.read(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - - thread.join().unwrap(); - } - - #[test] - fn iter() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - 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(&socket_path)); - or_panic!(stream.write_all(&[0])); - } - - thread.join().unwrap(); - } - - #[test] - fn long_path() { - let dir = tmpdir(); - let socket_path = dir.path().join( - "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ - sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", - ); - match UnixStream::connect(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixListener::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - - match UnixDatagram::bind(&socket_path) { - Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} - Err(e) => panic!("unexpected error {}", e), - Ok(_) => panic!("unexpected success"), - } - } - - #[test] - fn timeouts() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let stream = or_panic!(UnixStream::connect(&socket_path)); - let dur = Duration::new(15410, 0); - - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_read_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.read_timeout())); - - assert_eq!(None, or_panic!(stream.write_timeout())); - - or_panic!(stream.set_write_timeout(Some(dur))); - assert_eq!(Some(dur), or_panic!(stream.write_timeout())); - - or_panic!(stream.set_read_timeout(None)); - assert_eq!(None, or_panic!(stream.read_timeout())); - - or_panic!(stream.set_write_timeout(None)); - assert_eq!(None, or_panic!(stream.write_timeout())); - } - - #[test] - fn test_read_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let _listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut buf = [0; 10]; - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - } - - #[test] - fn test_read_with_timeout() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - - let mut stream = or_panic!(UnixStream::connect(&socket_path)); - or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); - - let mut other_end = or_panic!(listener.accept()).0; - or_panic!(other_end.write_all(b"hello world")); - - let mut buf = [0; 11]; - or_panic!(stream.read(&mut buf)); - assert_eq!(b"hello world", &buf[..]); - - let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); - assert!( - kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, - "unexpected_error: {:?}", - kind - ); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_unix_stream_timeout_zero_duration() { - let dir = tmpdir(); - let socket_path = dir.path().join("sock"); - - let listener = or_panic!(UnixListener::bind(&socket_path)); - let stream = or_panic!(UnixStream::connect(&socket_path)); - - let result = stream.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = stream.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - drop(listener); - } - - #[test] - fn test_unix_datagram() { - 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"; - or_panic!(sock1.send_to(msg, &path2)); - let mut buf = [0; 11]; - or_panic!(sock2.recv_from(&mut buf)); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn test_unnamed_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - - let msg = b"hello world"; - or_panic!(sock2.send_to(msg, &path1)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn test_connect_unix_datagram() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - let path2 = dir.path().join("sock2"); - - let bsock1 = or_panic!(UnixDatagram::bind(&path1)); - let bsock2 = or_panic!(UnixDatagram::bind(&path2)); - let sock = or_panic!(UnixDatagram::unbound()); - or_panic!(sock.connect(&path1)); - - // Check send() - let msg = b"hello there"; - or_panic!(sock.send(msg)); - let mut buf = [0; 11]; - let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); - assert_eq!(usize, 11); - assert!(addr.is_unnamed()); - assert_eq!(msg, &buf[..]); - - // Changing default socket works too - or_panic!(sock.connect(&path2)); - or_panic!(sock.send(msg)); - or_panic!(bsock2.recv_from(&mut buf)); - } - - #[test] - fn test_unix_datagram_recv() { - let dir = tmpdir(); - let path1 = dir.path().join("sock1"); - - let sock1 = or_panic!(UnixDatagram::bind(&path1)); - let sock2 = or_panic!(UnixDatagram::unbound()); - or_panic!(sock2.connect(&path1)); - - let msg = b"hello world"; - or_panic!(sock2.send(msg)); - let mut buf = [0; 11]; - let size = or_panic!(sock1.recv(&mut buf)); - assert_eq!(size, 11); - assert_eq!(msg, &buf[..]); - } - - #[test] - fn datagram_pair() { - let msg1 = b"hello"; - let msg2 = b"world!"; - - let (s1, s2) = or_panic!(UnixDatagram::pair()); - let thread = thread::spawn(move || { - // s1 must be moved in or the test will hang! - let mut buf = [0; 5]; - or_panic!(s1.recv(&mut buf)); - assert_eq!(&msg1[..], &buf[..]); - or_panic!(s1.send(msg2)); - }); - - or_panic!(s2.send(msg1)); - let mut buf = [0; 6]; - or_panic!(s2.recv(&mut buf)); - assert_eq!(&msg2[..], &buf[..]); - drop(s2); - - thread.join().unwrap(); - } - - // Ensure the `set_read_timeout` and `set_write_timeout` calls return errors - // when passed zero Durations - #[test] - fn test_unix_datagram_timeout_zero_duration() { - let dir = tmpdir(); - let path = dir.path().join("sock"); - - let datagram = or_panic!(UnixDatagram::bind(&path)); - - let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - - let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); - let err = result.unwrap_err(); - assert_eq!(err.kind(), ErrorKind::InvalidInput); - } - - #[test] - fn abstract_namespace_not_allowed() { - assert!(UnixStream::connect("\0asdf").is_err()); - } -} diff --git a/library/std/src/sys/unix/ext/net/tests.rs b/library/std/src/sys/unix/ext/net/tests.rs new file mode 100644 index 0000000000..ee73a6ed53 --- /dev/null +++ b/library/std/src/sys/unix/ext/net/tests.rs @@ -0,0 +1,454 @@ +use crate::io::prelude::*; +use crate::io::{self, ErrorKind}; +use crate::sys_common::io::test::tmpdir; +use crate::thread; +use crate::time::Duration; + +use super::*; + +macro_rules! or_panic { + ($e:expr) => { + match $e { + Ok(e) => e, + Err(e) => panic!("{}", e), + } + }; +} + +#[test] +fn basic() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world!"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + 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(&socket_path)); + assert_eq!(Some(&*socket_path), stream.peer_addr().unwrap().as_pathname()); + 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(); +} + +#[test] +fn vectored() { + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + + let len = or_panic!(s1.write_vectored(&[ + IoSlice::new(b"hello"), + IoSlice::new(b" "), + IoSlice::new(b"world!") + ],)); + assert_eq!(len, 12); + + let mut buf1 = [0; 6]; + let mut buf2 = [0; 7]; + let len = + or_panic!(s2.read_vectored(&mut [IoSliceMut::new(&mut buf1), IoSliceMut::new(&mut buf2)],)); + assert_eq!(len, 12); + assert_eq!(&buf1, b"hello "); + assert_eq!(&buf2, b"world!\0"); +} + +#[test] +fn pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (mut s1, mut s2) = or_panic!(UnixStream::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.write_all(msg2)); + }); + + or_panic!(s2.write_all(msg1)); + let mut buf = vec![]; + or_panic!(s2.read_to_end(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +#[test] +fn try_clone() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + let msg1 = b"hello"; + let msg2 = b"world"; + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(msg1)); + or_panic!(stream.write_all(msg2)); + }); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + let mut stream2 = or_panic!(stream.try_clone()); + + let mut buf = [0; 5]; + or_panic!(stream.read(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(stream2.read(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + + thread.join().unwrap(); +} + +#[test] +fn iter() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + 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(&socket_path)); + or_panic!(stream.write_all(&[0])); + } + + thread.join().unwrap(); +} + +#[test] +fn long_path() { + let dir = tmpdir(); + let socket_path = dir.path().join( + "asdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfasdfa\ + sasdfasdfasdasdfasdfasdfadfasdfasdfasdfasdfasdf", + ); + match UnixStream::connect(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixListener::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } + + match UnixDatagram::bind(&socket_path) { + Err(ref e) if e.kind() == io::ErrorKind::InvalidInput => {} + Err(e) => panic!("unexpected error {}", e), + Ok(_) => panic!("unexpected success"), + } +} + +#[test] +fn timeouts() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let stream = or_panic!(UnixStream::connect(&socket_path)); + let dur = Duration::new(15410, 0); + + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_read_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.read_timeout())); + + assert_eq!(None, or_panic!(stream.write_timeout())); + + or_panic!(stream.set_write_timeout(Some(dur))); + assert_eq!(Some(dur), or_panic!(stream.write_timeout())); + + or_panic!(stream.set_read_timeout(None)); + assert_eq!(None, or_panic!(stream.read_timeout())); + + or_panic!(stream.set_write_timeout(None)); + assert_eq!(None, or_panic!(stream.write_timeout())); +} + +#[test] +fn test_read_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let _listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut buf = [0; 10]; + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +#[test] +fn test_read_with_timeout() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + + let mut stream = or_panic!(UnixStream::connect(&socket_path)); + or_panic!(stream.set_read_timeout(Some(Duration::from_millis(1000)))); + + let mut other_end = or_panic!(listener.accept()).0; + or_panic!(other_end.write_all(b"hello world")); + + let mut buf = [0; 11]; + or_panic!(stream.read(&mut buf)); + assert_eq!(b"hello world", &buf[..]); + + let kind = stream.read_exact(&mut buf).err().expect("expected error").kind(); + assert!( + kind == ErrorKind::WouldBlock || kind == ErrorKind::TimedOut, + "unexpected_error: {:?}", + kind + ); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_stream_timeout_zero_duration() { + let dir = tmpdir(); + let socket_path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&socket_path)); + let stream = or_panic!(UnixStream::connect(&socket_path)); + + let result = stream.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = stream.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + drop(listener); +} + +#[test] +fn test_unix_datagram() { + 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"; + or_panic!(sock1.send_to(msg, &path2)); + let mut buf = [0; 11]; + or_panic!(sock2.recv_from(&mut buf)); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unnamed_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + + let msg = b"hello world"; + or_panic!(sock2.send_to(msg, &path1)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(sock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_connect_unix_datagram() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + let path2 = dir.path().join("sock2"); + + let bsock1 = or_panic!(UnixDatagram::bind(&path1)); + let bsock2 = or_panic!(UnixDatagram::bind(&path2)); + let sock = or_panic!(UnixDatagram::unbound()); + or_panic!(sock.connect(&path1)); + + // Check send() + let msg = b"hello there"; + or_panic!(sock.send(msg)); + let mut buf = [0; 11]; + let (usize, addr) = or_panic!(bsock1.recv_from(&mut buf)); + assert_eq!(usize, 11); + assert!(addr.is_unnamed()); + assert_eq!(msg, &buf[..]); + + // Changing default socket works too + or_panic!(sock.connect(&path2)); + or_panic!(sock.send(msg)); + or_panic!(bsock2.recv_from(&mut buf)); +} + +#[test] +fn test_unix_datagram_recv() { + let dir = tmpdir(); + let path1 = dir.path().join("sock1"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn datagram_pair() { + let msg1 = b"hello"; + let msg2 = b"world!"; + + let (s1, s2) = or_panic!(UnixDatagram::pair()); + let thread = thread::spawn(move || { + // s1 must be moved in or the test will hang! + let mut buf = [0; 5]; + or_panic!(s1.recv(&mut buf)); + assert_eq!(&msg1[..], &buf[..]); + or_panic!(s1.send(msg2)); + }); + + or_panic!(s2.send(msg1)); + let mut buf = [0; 6]; + or_panic!(s2.recv(&mut buf)); + assert_eq!(&msg2[..], &buf[..]); + drop(s2); + + thread.join().unwrap(); +} + +// Ensure the `set_read_timeout` and `set_write_timeout` calls return errors +// when passed zero Durations +#[test] +fn test_unix_datagram_timeout_zero_duration() { + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let datagram = or_panic!(UnixDatagram::bind(&path)); + + let result = datagram.set_write_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); + + let result = datagram.set_read_timeout(Some(Duration::new(0, 0))); + let err = result.unwrap_err(); + assert_eq!(err.kind(), ErrorKind::InvalidInput); +} + +#[test] +fn abstract_namespace_not_allowed() { + assert!(UnixStream::connect("\0asdf").is_err()); +} + +#[test] +fn test_unix_stream_peek() { + let (txdone, rxdone) = crate::sync::mpsc::channel(); + + let dir = tmpdir(); + let path = dir.path().join("sock"); + + let listener = or_panic!(UnixListener::bind(&path)); + let thread = thread::spawn(move || { + let mut stream = or_panic!(listener.accept()).0; + or_panic!(stream.write_all(&[1, 3, 3, 7])); + or_panic!(rxdone.recv()); + }); + + let mut stream = or_panic!(UnixStream::connect(&path)); + let mut buf = [0; 10]; + for _ in 0..2 { + assert_eq!(or_panic!(stream.peek(&mut buf)), 4); + } + assert_eq!(or_panic!(stream.read(&mut buf)), 4); + + or_panic!(stream.set_nonblocking(true)); + match stream.peek(&mut buf) { + Ok(_) => panic!("expected error"), + Err(ref e) if e.kind() == ErrorKind::WouldBlock => {} + Err(e) => panic!("unexpected error: {}", e), + } + + or_panic!(txdone.send(())); + thread.join().unwrap(); +} + +#[test] +fn test_unix_datagram_peek() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let size = or_panic!(sock1.peek(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} + +#[test] +fn test_unix_datagram_peek_from() { + let dir = tmpdir(); + let path1 = dir.path().join("sock"); + + let sock1 = or_panic!(UnixDatagram::bind(&path1)); + let sock2 = or_panic!(UnixDatagram::unbound()); + or_panic!(sock2.connect(&path1)); + + let msg = b"hello world"; + or_panic!(sock2.send(msg)); + for _ in 0..2 { + let mut buf = [0; 11]; + let (size, _) = or_panic!(sock1.peek_from(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); + } + + let mut buf = [0; 11]; + let size = or_panic!(sock1.recv(&mut buf)); + assert_eq!(size, 11); + assert_eq!(msg, &buf[..]); +} diff --git a/library/std/src/sys/unix/ext/raw.rs b/library/std/src/sys/unix/ext/raw.rs index 40fa53d484..3199a0bff0 100644 --- a/library/std/src/sys/unix/ext/raw.rs +++ b/library/std/src/sys/unix/ext/raw.rs @@ -1,4 +1,4 @@ -//! Unix-specific primitives available on all unix platforms +//! Unix-specific primitives available on all unix platforms. #![stable(feature = "raw_ext", since = "1.1.0")] #![rustc_deprecated( diff --git a/library/std/src/sys/unix/ext/ucred.rs b/library/std/src/sys/unix/ext/ucred.rs new file mode 100644 index 0000000000..ed7516c7f2 --- /dev/null +++ b/library/std/src/sys/unix/ext/ucred.rs @@ -0,0 +1,97 @@ +//! Unix peer credentials. + +// NOTE: Code in this file is heavily based on work done in PR 13 from the tokio-uds repository on +// GitHub. +// +// For reference, the link is here: https://github.com/tokio-rs/tokio-uds/pull/13 +// Credit to Martin Habovštiak (GitHub username Kixunil) and contributors for this work. + +use libc::{gid_t, pid_t, uid_t}; + +/// Credentials for a UNIX process for credentials passing. +#[unstable(feature = "peer_credentials_unix_socket", issue = "42839", reason = "unstable")] +#[derive(Clone, Copy, Debug, Eq, Hash, PartialEq)] +pub struct UCred { + /// The UID part of the peer credential. This is the effective UID of the process at the domain + /// socket's endpoint. + pub uid: uid_t, + /// The GID part of the peer credential. This is the effective GID of the process at the domain + /// socket's endpoint. + pub gid: gid_t, + /// The PID part of the peer credential. This field is optional because the PID part of the + /// peer credentials is not supported on every platform. On platforms where the mechanism to + /// discover the PID exists, this field will be populated to the PID of the process at the + /// domain socket's endpoint. Otherwise, it will be set to None. + pub pid: Option, +} + +#[cfg(any(target_os = "android", target_os = "linux"))] +pub use self::impl_linux::peer_cred; + +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +pub use self::impl_bsd::peer_cred; + +#[cfg(any(target_os = "linux", target_os = "android"))] +pub mod impl_linux { + use super::UCred; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + use crate::{io, mem}; + use libc::{c_void, getsockopt, socklen_t, ucred, SOL_SOCKET, SO_PEERCRED}; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + let ucred_size = mem::size_of::(); + + // Trivial sanity checks. + assert!(mem::size_of::() <= mem::size_of::()); + assert!(ucred_size <= u32::MAX as usize); + + let mut ucred_size = ucred_size as socklen_t; + let mut ucred: ucred = ucred { pid: 1, uid: 1, gid: 1 }; + + unsafe { + let ret = getsockopt( + socket.as_raw_fd(), + SOL_SOCKET, + SO_PEERCRED, + &mut ucred as *mut ucred as *mut c_void, + &mut ucred_size, + ); + + if ret == 0 && ucred_size as usize == mem::size_of::() { + Ok(UCred { uid: ucred.uid, gid: ucred.gid, pid: Some(ucred.pid) }) + } else { + Err(io::Error::last_os_error()) + } + } + } +} + +#[cfg(any( + target_os = "dragonfly", + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "openbsd" +))] +pub mod impl_bsd { + use super::UCred; + use crate::io; + use crate::os::unix::io::AsRawFd; + use crate::os::unix::net::UnixStream; + + pub fn peer_cred(socket: &UnixStream) -> io::Result { + let mut cred = UCred { uid: 1, gid: 1, pid: None }; + unsafe { + let ret = libc::getpeereid(socket.as_raw_fd(), &mut cred.uid, &mut cred.gid); + + if ret == 0 { Ok(cred) } else { Err(io::Error::last_os_error()) } + } + } +} diff --git a/library/std/src/sys/unix/ext/ucred/tests.rs b/library/std/src/sys/unix/ext/ucred/tests.rs new file mode 100644 index 0000000000..451b534b26 --- /dev/null +++ b/library/std/src/sys/unix/ext/ucred/tests.rs @@ -0,0 +1,25 @@ +use crate::os::unix::net::UnixStream; +use libc::{getegid, geteuid}; + +#[test] +#[cfg(any( + target_os = "android", + target_os = "linux", + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "openbsd" +))] +fn test_socket_pair() { + // Create two connected sockets and get their peer credentials. They should be equal. + let (sock_a, sock_b) = UnixStream::pair().unwrap(); + let (cred_a, cred_b) = (sock_a.peer_cred().unwrap(), sock_b.peer_cred().unwrap()); + assert_eq!(cred_a, cred_b); + + // Check that the UID and GIDs match up. + let uid = unsafe { geteuid() }; + let gid = unsafe { getegid() }; + assert_eq!(cred_a.uid, uid); + assert_eq!(cred_a.gid, gid); +} diff --git a/library/std/src/sys/unix/fd.rs b/library/std/src/sys/unix/fd.rs index ba169b251b..2224a055d6 100644 --- a/library/std/src/sys/unix/fd.rs +++ b/library/std/src/sys/unix/fd.rs @@ -1,10 +1,11 @@ #![unstable(reason = "not public", issue = "none", feature = "fd")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::io::{self, Initializer, IoSlice, IoSliceMut, Read}; use crate::mem; -#[cfg(not(any(target_os = "redox", target_env = "newlib")))] -use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::cvt; use crate::sys_common::AsInner; @@ -28,24 +29,35 @@ const READ_LIMIT: usize = c_int::MAX as usize - 1; #[cfg(not(target_os = "macos"))] const READ_LIMIT: usize = libc::ssize_t::MAX as usize; -#[cfg(not(any(target_os = "redox", target_env = "newlib")))] -fn max_iov() -> usize { - static LIM: AtomicUsize = AtomicUsize::new(0); - - let mut lim = LIM.load(Ordering::Relaxed); - if lim == 0 { - let ret = unsafe { libc::sysconf(libc::_SC_IOV_MAX) }; - - // 16 is the minimum value required by POSIX. - lim = if ret > 0 { ret as usize } else { 16 }; - LIM.store(lim, Ordering::Relaxed); - } - - lim +#[cfg(any( + target_os = "dragonfly", + target_os = "freebsd", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +))] +const fn max_iov() -> usize { + libc::IOV_MAX as usize } -#[cfg(any(target_os = "redox", target_env = "newlib"))] -fn max_iov() -> usize { +#[cfg(any(target_os = "android", target_os = "emscripten", target_os = "linux"))] +const fn max_iov() -> usize { + libc::UIO_MAXIOV as usize +} + +#[cfg(not(any( + target_os = "android", + target_os = "dragonfly", + target_os = "emscripten", + target_os = "freebsd", + target_os = "ios", + target_os = "linux", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", +)))] +const fn max_iov() -> usize { 16 // The minimum value required by POSIX. } @@ -279,16 +291,3 @@ impl Drop for FileDesc { let _ = unsafe { libc::close(self.fd) }; } } - -#[cfg(test)] -mod tests { - use super::{FileDesc, IoSlice}; - use core::mem::ManuallyDrop; - - #[test] - fn limit_vector_count() { - let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); - let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); - assert!(stdout.write_vectored(&bufs).is_ok()); - } -} diff --git a/library/std/src/sys/unix/fd/tests.rs b/library/std/src/sys/unix/fd/tests.rs new file mode 100644 index 0000000000..a932043cbc --- /dev/null +++ b/library/std/src/sys/unix/fd/tests.rs @@ -0,0 +1,9 @@ +use super::{FileDesc, IoSlice}; +use core::mem::ManuallyDrop; + +#[test] +fn limit_vector_count() { + let stdout = ManuallyDrop::new(FileDesc { fd: 1 }); + let bufs = (0..1500).map(|_| IoSlice::new(&[])).collect::>(); + assert!(stdout.write_vectored(&bufs).is_ok()); +} diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index acb18e6d06..566ac0920d 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1140,14 +1140,14 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { } let (mut reader, reader_metadata) = open_from(from)?; - let len = reader_metadata.len(); + let max_len = u64::MAX; let (mut writer, _) = open_to_and_set_permissions(to, reader_metadata)?; let has_copy_file_range = HAS_COPY_FILE_RANGE.load(Ordering::Relaxed); let mut written = 0u64; - while written < len { + while written < max_len { let copy_result = if has_copy_file_range { - let bytes_to_copy = cmp::min(len - written, usize::MAX as u64) as usize; + let bytes_to_copy = cmp::min(max_len - written, usize::MAX as u64) as usize; let copy_result = unsafe { // We actually don't have to adjust the offsets, // because copy_file_range adjusts the file offset automatically @@ -1162,7 +1162,7 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { }; if let Err(ref copy_err) = copy_result { match copy_err.raw_os_error() { - Some(libc::ENOSYS) | Some(libc::EPERM) => { + Some(libc::ENOSYS | libc::EPERM | libc::EOPNOTSUPP) => { HAS_COPY_FILE_RANGE.store(false, Ordering::Relaxed); } _ => {} @@ -1173,18 +1173,25 @@ pub fn copy(from: &Path, to: &Path) -> io::Result { Err(io::Error::from_raw_os_error(libc::ENOSYS)) }; match copy_result { + Ok(0) if written == 0 => { + // fallback to work around several kernel bugs where copy_file_range will fail to + // copy any bytes and return 0 instead of an error if + // - reading virtual files from the proc filesystem which appear to have 0 size + // but are not empty. noted in coreutils to affect kernels at least up to 5.6.19. + // - copying from an overlay filesystem in docker. reported to occur on fedora 32. + return io::copy(&mut reader, &mut writer); + } + Ok(0) => return Ok(written), // reached EOF Ok(ret) => written += ret as u64, Err(err) => { match err.raw_os_error() { - Some(os_err) - if os_err == libc::ENOSYS - || os_err == libc::EXDEV - || os_err == libc::EINVAL - || os_err == libc::EPERM => - { + Some( + libc::ENOSYS | libc::EXDEV | libc::EINVAL | libc::EPERM | libc::EOPNOTSUPP, + ) => { // Try fallback io::copy if either: // - Kernel version is < 4.5 (ENOSYS) // - Files are mounted on different fs (EXDEV) + // - copy_file_range is broken in various ways on RHEL/CentOS 7 (EOPNOTSUPP) // - copy_file_range is disallowed, for example by seccomp (EPERM) // - copy_file_range cannot be used with pipes or device nodes (EINVAL) assert_eq!(written, 0); diff --git a/library/std/src/sys/unix/futex.rs b/library/std/src/sys/unix/futex.rs new file mode 100644 index 0000000000..e6f0c48c59 --- /dev/null +++ b/library/std/src/sys/unix/futex.rs @@ -0,0 +1,37 @@ +#![cfg(any(target_os = "linux", target_os = "android"))] + +use crate::convert::TryInto; +use crate::ptr::null; +use crate::sync::atomic::AtomicI32; +use crate::time::Duration; + +pub fn futex_wait(futex: &AtomicI32, expected: i32, timeout: Option) { + let timespec = timeout.and_then(|d| { + Some(libc::timespec { + // Sleep forever if the timeout is longer than fits in a timespec. + tv_sec: d.as_secs().try_into().ok()?, + // This conversion never truncates, as subsec_nanos is always <1e9. + tv_nsec: d.subsec_nanos() as _, + }) + }); + unsafe { + libc::syscall( + libc::SYS_futex, + futex as *const AtomicI32, + libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG, + expected, + timespec.as_ref().map_or(null(), |d| d as *const libc::timespec), + ); + } +} + +pub fn futex_wake(futex: &AtomicI32) { + unsafe { + libc::syscall( + libc::SYS_futex, + futex as *const AtomicI32, + libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG, + 1, + ); + } +} diff --git a/library/std/src/sys/unix/mod.rs b/library/std/src/sys/unix/mod.rs index eddf00d397..776f4f18ec 100644 --- a/library/std/src/sys/unix/mod.rs +++ b/library/std/src/sys/unix/mod.rs @@ -49,6 +49,7 @@ pub mod env; pub mod ext; pub mod fd; pub mod fs; +pub mod futex; pub mod io; #[cfg(target_os = "l4re")] mod l4re; @@ -75,6 +76,13 @@ pub use crate::sys_common::os_str_bytes as os_str; #[cfg(not(test))] pub fn init() { + // The standard streams might be closed on application startup. To prevent + // std::io::{stdin, stdout,stderr} objects from using other unrelated file + // resources opened later, we reopen standards streams when they are closed. + unsafe { + sanitize_standard_fds(); + } + // By default, some platforms will send a *signal* when an EPIPE error // would otherwise be delivered. This runtime doesn't install a SIGPIPE // handler, causing it to kill the program, which isn't exactly what we @@ -86,6 +94,62 @@ pub fn init() { reset_sigpipe(); } + cfg_if::cfg_if! { + if #[cfg(miri)] { + // The standard fds are always available in Miri. + unsafe fn sanitize_standard_fds() {} + } else if #[cfg(not(any( + target_os = "emscripten", + target_os = "fuchsia", + // The poll on Darwin doesn't set POLLNVAL for closed fds. + target_os = "macos", + target_os = "ios", + target_os = "redox", + )))] { + // In the case when all file descriptors are open, the poll has been + // observed to perform better than fcntl (on GNU/Linux). + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + let pfds: &mut [_] = &mut [ + libc::pollfd { fd: 0, events: 0, revents: 0 }, + libc::pollfd { fd: 1, events: 0, revents: 0 }, + libc::pollfd { fd: 2, events: 0, revents: 0 }, + ]; + while libc::poll(pfds.as_mut_ptr(), 3, 0) == -1 { + if errno() == libc::EINTR { + continue; + } + libc::abort(); + } + for pfd in pfds { + if pfd.revents & libc::POLLNVAL == 0 { + continue; + } + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + // If the stream is closed but we failed to reopen it, abort the + // process. Otherwise we wouldn't preserve the safety of + // operations on the corresponding Rust object Stdin, Stdout, or + // Stderr. + libc::abort(); + } + } + } + } else if #[cfg(any(target_os = "macos", target_os = "ios", target_os = "redox"))] { + unsafe fn sanitize_standard_fds() { + use crate::sys::os::errno; + for fd in 0..3 { + if libc::fcntl(fd, libc::F_GETFD) == -1 && errno() == libc::EBADF { + if libc::open("/dev/null\0".as_ptr().cast(), libc::O_RDWR, 0) == -1 { + libc::abort(); + } + } + } + } + } else { + unsafe fn sanitize_standard_fds() {} + } + } + #[cfg(not(any(target_os = "emscripten", target_os = "fuchsia")))] unsafe fn reset_sigpipe() { assert!(signal(libc::SIGPIPE, libc::SIG_IGN) != libc::SIG_ERR); diff --git a/library/std/src/sys/unix/os.rs b/library/std/src/sys/unix/os.rs index 2fcb5b9c4e..c9f9ed01e1 100644 --- a/library/std/src/sys/unix/os.rs +++ b/library/std/src/sys/unix/os.rs @@ -2,6 +2,9 @@ #![allow(unused_imports)] // lots of cfg code here +#[cfg(all(test, target_env = "gnu"))] +mod tests; + use crate::os::unix::prelude::*; use crate::error::Error as StdError; @@ -18,7 +21,7 @@ use crate::slice; use crate::str; use crate::sys::cvt; use crate::sys::fd; -use crate::sys_common::mutex::{Mutex, MutexGuard}; +use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; use crate::vec; use libc::{c_char, c_int, c_void}; @@ -467,10 +470,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> MutexGuard<'static> { - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static ENV_LOCK: Mutex = Mutex::new(); +pub unsafe fn env_lock() -> StaticMutexGuard<'static> { + // It is UB to attempt to acquire this mutex reentrantly! + static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() } @@ -645,30 +647,3 @@ fn parse_glibc_version(version: &str) -> Option<(usize, usize)> { _ => None, } } - -#[cfg(all(test, target_env = "gnu"))] -mod test { - use super::*; - - #[test] - fn test_glibc_version() { - // This mostly just tests that the weak linkage doesn't panic wildly... - glibc_version(); - } - - #[test] - fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } - } -} diff --git a/library/std/src/sys/unix/os/tests.rs b/library/std/src/sys/unix/os/tests.rs new file mode 100644 index 0000000000..0e1dcb390a --- /dev/null +++ b/library/std/src/sys/unix/os/tests.rs @@ -0,0 +1,23 @@ +use super::*; + +#[test] +fn test_glibc_version() { + // This mostly just tests that the weak linkage doesn't panic wildly... + glibc_version(); +} + +#[test] +fn test_parse_glibc_version() { + let cases = [ + ("0.0", Some((0, 0))), + ("01.+2", Some((1, 2))), + ("3.4.5.six", Some((3, 4))), + ("1", None), + ("1.-2", None), + ("1.foo", None), + ("foo.1", None), + ]; + for &(version_str, parsed) in cases.iter() { + assert_eq!(parsed, parse_glibc_version(version_str)); + } +} diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 553e980f08..1b7b93f9d4 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -1,6 +1,7 @@ -pub use self::process_common::{Command, ExitCode, Stdio, StdioPipes}; +pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::{ExitStatus, Process}; pub use crate::ffi::OsString as EnvKey; +pub use crate::sys_common::process::CommandEnvs; mod process_common; #[cfg(not(target_os = "fuchsia"))] diff --git a/library/std/src/sys/unix/process/process_common.rs b/library/std/src/sys/unix/process/process_common.rs index 6e33cdd3c4..9ddd4ad400 100644 --- a/library/std/src/sys/unix/process/process_common.rs +++ b/library/std/src/sys/unix/process/process_common.rs @@ -1,14 +1,18 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::os::unix::prelude::*; use crate::collections::BTreeMap; use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io; +use crate::path::Path; use crate::ptr; use crate::sys::fd::FileDesc; use crate::sys::fs::File; use crate::sys::pipe::{self, AnonPipe}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; #[cfg(not(target_os = "fuchsia"))] use crate::sys::fs::OpenOptions; @@ -181,11 +185,30 @@ impl Command { pub fn saw_nul(&self) -> bool { self.saw_nul } + + pub fn get_program(&self) -> &OsStr { + OsStr::from_bytes(self.program.as_bytes()) + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let mut iter = self.args.iter(); + iter.next(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cs| Path::new(OsStr::from_bytes(cs.as_bytes()))) + } + pub fn get_argv(&self) -> &Vec<*const c_char> { &self.argv.0 } - pub fn get_program(&self) -> &CStr { + pub fn get_program_cstr(&self) -> &CStr { &*self.program } @@ -400,70 +423,31 @@ impl ExitCode { } } -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::*; +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, CString>, +} - use crate::ffi::OsStr; - use crate::mem; - use crate::ptr; - use crate::sys::cvt; - - macro_rules! t { - ($e:expr) => { - match $e { - Ok(t) => t, - Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), - } - }; +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|cs| OsStr::from_bytes(cs.as_bytes())) } - - // See #14232 for more information, but it appears that signal delivery to a - // newly spawned process may just be raced in the macOS, so to prevent this - // test from being flaky we ignore it on macOS. - #[test] - #[cfg_attr(target_os = "macos", ignore)] - // When run under our current QEMU emulation test suite this test fails, - // although the reason isn't very clear as to why. For now this test is - // ignored there. - #[cfg_attr(target_arch = "arm", ignore)] - #[cfg_attr(target_arch = "aarch64", ignore)] - #[cfg_attr(target_arch = "riscv64", ignore)] - fn test_process_mask() { - unsafe { - // Test to make sure that a signal mask does not get inherited. - let mut cmd = Command::new(OsStr::new("cat")); - - let mut set = mem::MaybeUninit::::uninit(); - let mut old_set = mem::MaybeUninit::::uninit(); - t!(cvt(sigemptyset(set.as_mut_ptr()))); - t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT))); - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr()))); - - cmd.stdin(Stdio::MakePipe); - cmd.stdout(Stdio::MakePipe); - - let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); - let stdin_write = pipes.stdin.take().unwrap(); - let stdout_read = pipes.stdout.take().unwrap(); - - t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut()))); - - t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); - // We need to wait until SIGINT is definitely delivered. The - // easiest way is to write something to cat, and try to read it - // back: if SIGINT is unmasked, it'll get delivered when cat is - // next scheduled. - let _ = stdin_write.write(b"Hello"); - drop(stdin_write); - - // Either EOF or failure (EPIPE) is okay. - let mut buf = [0; 5]; - if let Ok(ret) = stdout_read.read(&mut buf) { - assert_eq!(ret, 0); - } - - t!(cat.wait()); - } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() } } diff --git a/library/std/src/sys/unix/process/process_common/tests.rs b/library/std/src/sys/unix/process/process_common/tests.rs new file mode 100644 index 0000000000..e72fbf0beb --- /dev/null +++ b/library/std/src/sys/unix/process/process_common/tests.rs @@ -0,0 +1,64 @@ +use super::*; + +use crate::ffi::OsStr; +use crate::mem; +use crate::ptr; +use crate::sys::cvt; + +macro_rules! t { + ($e:expr) => { + match $e { + Ok(t) => t, + Err(e) => panic!("received error for `{}`: {}", stringify!($e), e), + } + }; +} + +// See #14232 for more information, but it appears that signal delivery to a +// newly spawned process may just be raced in the macOS, so to prevent this +// test from being flaky we ignore it on macOS. +#[test] +#[cfg_attr(target_os = "macos", ignore)] +// When run under our current QEMU emulation test suite this test fails, +// although the reason isn't very clear as to why. For now this test is +// ignored there. +#[cfg_attr(target_arch = "arm", ignore)] +#[cfg_attr(target_arch = "aarch64", ignore)] +#[cfg_attr(target_arch = "riscv64", ignore)] +fn test_process_mask() { + unsafe { + // Test to make sure that a signal mask does not get inherited. + let mut cmd = Command::new(OsStr::new("cat")); + + let mut set = mem::MaybeUninit::::uninit(); + let mut old_set = mem::MaybeUninit::::uninit(); + t!(cvt(sigemptyset(set.as_mut_ptr()))); + t!(cvt(sigaddset(set.as_mut_ptr(), libc::SIGINT))); + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, set.as_ptr(), old_set.as_mut_ptr()))); + + cmd.stdin(Stdio::MakePipe); + cmd.stdout(Stdio::MakePipe); + + let (mut cat, mut pipes) = t!(cmd.spawn(Stdio::Null, true)); + let stdin_write = pipes.stdin.take().unwrap(); + let stdout_read = pipes.stdout.take().unwrap(); + + t!(cvt(libc::pthread_sigmask(libc::SIG_SETMASK, old_set.as_ptr(), ptr::null_mut()))); + + t!(cvt(libc::kill(cat.id() as libc::pid_t, libc::SIGINT))); + // We need to wait until SIGINT is definitely delivered. The + // easiest way is to write something to cat, and try to read it + // back: if SIGINT is unmasked, it'll get delivered when cat is + // next scheduled. + let _ = stdin_write.write(b"Hello"); + drop(stdin_write); + + // Either EOF or failure (EPIPE) is okay. + let mut buf = [0; 5]; + if let Ok(ret) = stdout_read.read(&mut buf) { + assert_eq!(ret, 0); + } + + t!(cat.wait()); + } +} diff --git a/library/std/src/sys/unix/process/process_fuchsia.rs b/library/std/src/sys/unix/process/process_fuchsia.rs index 6daf2885ba..b64636c3f3 100644 --- a/library/std/src/sys/unix/process/process_fuchsia.rs +++ b/library/std/src/sys/unix/process/process_fuchsia.rs @@ -118,8 +118,9 @@ impl Command { FDIO_SPAWN_CLONE_JOB | FDIO_SPAWN_CLONE_LDSVC | FDIO_SPAWN_CLONE_NAMESPACE - | FDIO_SPAWN_CLONE_ENVIRON, // this is ignored when envp is non-null - self.get_program().as_ptr(), + | FDIO_SPAWN_CLONE_ENVIRON // this is ignored when envp is non-null + | FDIO_SPAWN_CLONE_UTC_CLOCK, + self.get_program_cstr().as_ptr(), self.get_argv().as_ptr(), envp, actions.len() as size_t, diff --git a/library/std/src/sys/unix/process/process_unix.rs b/library/std/src/sys/unix/process/process_unix.rs index 0f349dfa30..32f456266c 100644 --- a/library/std/src/sys/unix/process/process_unix.rs +++ b/library/std/src/sys/unix/process/process_unix.rs @@ -67,7 +67,7 @@ impl Command { // pipe I/O up to PIPE_BUF bytes should be atomic, and then // we want to be sure we *don't* run at_exit destructors as // we're being torn down regardless - assert!(output.write(&bytes).is_ok()); + rtassert!(output.write(&bytes).is_ok()); libc::_exit(1) } n => n, @@ -245,14 +245,15 @@ impl Command { *sys::os::environ() = envp.as_ptr(); } - libc::execvp(self.get_program().as_ptr(), self.get_argv().as_ptr()); + libc::execvp(self.get_program_cstr().as_ptr(), self.get_argv().as_ptr()); Err(io::Error::last_os_error()) } #[cfg(not(any( target_os = "macos", target_os = "freebsd", - all(target_os = "linux", target_env = "gnu") + all(target_os = "linux", target_env = "gnu"), + all(target_os = "linux", target_env = "musl"), )))] fn posix_spawn( &mut self, @@ -267,7 +268,8 @@ impl Command { #[cfg(any( target_os = "macos", target_os = "freebsd", - all(target_os = "linux", target_env = "gnu") + all(target_os = "linux", target_env = "gnu"), + all(target_os = "linux", target_env = "musl"), ))] fn posix_spawn( &mut self, @@ -297,10 +299,10 @@ impl Command { } } - // Solaris and glibc 2.29+ can set a new working directory, and maybe - // others will gain this non-POSIX function too. We'll check for this - // weak symbol as soon as it's needed, so we can return early otherwise - // to do a manual chdir before exec. + // Solaris, glibc 2.29+, and musl 1.24+ can set a new working directory, + // and maybe others will gain this non-POSIX function too. We'll check + // for this weak symbol as soon as it's needed, so we can return early + // otherwise to do a manual chdir before exec. weak! { fn posix_spawn_file_actions_addchdir_np( *mut libc::posix_spawn_file_actions_t, @@ -383,7 +385,7 @@ impl Command { let envp = envp.map(|c| c.as_ptr()).unwrap_or_else(|| *sys::os::environ() as *const _); let ret = libc::posix_spawnp( &mut p.pid, - self.get_program().as_ptr(), + self.get_program_cstr().as_ptr(), file_actions.0.as_ptr(), attrs.0.as_ptr(), self.get_argv().as_ptr() as *const _, @@ -459,7 +461,15 @@ impl ExitStatus { } fn exited(&self) -> bool { - unsafe { libc::WIFEXITED(self.0) } + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] + unsafe { + libc::WIFEXITED(self.0) + } } pub fn success(&self) -> bool { @@ -467,10 +477,22 @@ impl ExitStatus { } pub fn code(&self) -> Option { + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] if self.exited() { Some(unsafe { libc::WEXITSTATUS(self.0) }) } else { None } } pub fn signal(&self) -> Option { + // On Linux-like OSes this function is safe, on others it is not. See + // libc issue: https://github.com/rust-lang/libc/issues/1888. + #[cfg_attr( + any(target_os = "linux", target_os = "android", target_os = "emscripten"), + allow(unused_unsafe) + )] if !self.exited() { Some(unsafe { libc::WTERMSIG(self.0) }) } else { None } } } diff --git a/library/std/src/sys/unix/process/zircon.rs b/library/std/src/sys/unix/process/zircon.rs index 750b8f0762..69ec275c2b 100644 --- a/library/std/src/sys/unix/process/zircon.rs +++ b/library/std/src/sys/unix/process/zircon.rs @@ -138,6 +138,7 @@ pub const FDIO_SPAWN_CLONE_LDSVC: u32 = 0x0002; pub const FDIO_SPAWN_CLONE_NAMESPACE: u32 = 0x0004; pub const FDIO_SPAWN_CLONE_STDIO: u32 = 0x0008; pub const FDIO_SPAWN_CLONE_ENVIRON: u32 = 0x0010; +pub const FDIO_SPAWN_CLONE_UTC_CLOCK: u32 = 0x0020; pub const FDIO_SPAWN_CLONE_ALL: u32 = 0xFFFF; // fdio_spawn_etc actions diff --git a/library/std/src/sys/unix/thread.rs b/library/std/src/sys/unix/thread.rs index 04da9812dd..652219e28f 100644 --- a/library/std/src/sys/unix/thread.rs +++ b/library/std/src/sys/unix/thread.rs @@ -294,6 +294,7 @@ pub mod guard { unsafe fn get_stack_start() -> Option<*mut libc::c_void> { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -305,7 +306,9 @@ pub mod guard { assert_eq!(libc::pthread_attr_getstack(&attr, &mut stackaddr, &mut stacksize), 0); ret = Some(stackaddr); } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(target_os = "freebsd") { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } @@ -403,6 +406,7 @@ pub mod guard { pub unsafe fn current() -> Option { let mut ret = None; let mut attr: libc::pthread_attr_t = crate::mem::zeroed(); + #[cfg(target_os = "freebsd")] assert_eq!(libc::pthread_attr_init(&mut attr), 0); #[cfg(target_os = "freebsd")] let e = libc::pthread_attr_get_np(libc::pthread_self(), &mut attr); @@ -446,7 +450,9 @@ pub mod guard { Some(stackaddr..stackaddr + guardsize) }; } - assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + if e == 0 || cfg!(target_os = "freebsd") { + assert_eq!(libc::pthread_attr_destroy(&mut attr), 0); + } ret } } diff --git a/library/std/src/sys/unsupported/fs.rs b/library/std/src/sys/unsupported/fs.rs index ecb5b51ccc..faa53b6a74 100644 --- a/library/std/src/sys/unsupported/fs.rs +++ b/library/std/src/sys/unsupported/fs.rs @@ -233,10 +233,6 @@ impl File { pub fn set_permissions(&self, _perm: FilePermissions) -> io::Result<()> { match self.0 {} } - - pub fn diverge(&self) -> ! { - match self.0 {} - } } impl DirBuilder { diff --git a/library/std/src/sys/unsupported/mod.rs b/library/std/src/sys/unsupported/mod.rs index 87f655eecd..8ba870c5db 100644 --- a/library/std/src/sys/unsupported/mod.rs +++ b/library/std/src/sys/unsupported/mod.rs @@ -8,6 +8,7 @@ pub mod io; pub mod mutex; pub mod net; pub mod os; +#[path = "../unix/path.rs"] pub mod path; pub mod pipe; pub mod process; diff --git a/library/std/src/sys/unsupported/path.rs b/library/std/src/sys/unsupported/path.rs deleted file mode 100644 index 840a7ae042..0000000000 --- a/library/std/src/sys/unsupported/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -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 --git a/library/std/src/sys/unsupported/process.rs b/library/std/src/sys/unsupported/process.rs index 4702e5c549..3ede2291d5 100644 --- a/library/std/src/sys/unsupported/process.rs +++ b/library/std/src/sys/unsupported/process.rs @@ -1,10 +1,12 @@ use crate::ffi::OsStr; use crate::fmt; use crate::io; +use crate::marker::PhantomData; +use crate::path::Path; use crate::sys::fs::File; use crate::sys::pipe::AnonPipe; use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; pub use crate::ffi::OsString as EnvKey; @@ -49,6 +51,22 @@ impl Command { pub fn stderr(&mut self, _stderr: Stdio) {} + pub fn get_program(&self) -> &OsStr { + panic!("unsupported") + } + + pub fn get_args(&self) -> CommandArgs<'_> { + CommandArgs { _p: PhantomData } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + None + } + pub fn spawn( &mut self, _default: Stdio, @@ -65,8 +83,8 @@ impl From for Stdio { } impl From for Stdio { - fn from(file: File) -> Stdio { - file.diverge() + fn from(_file: File) -> Stdio { + panic!("unsupported") } } @@ -147,3 +165,22 @@ impl Process { match self.0 {} } } + +pub struct CommandArgs<'a> { + _p: PhantomData<&'a ()>, +} + +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + None + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> {} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().finish() + } +} diff --git a/library/std/src/sys/vxworks/args.rs b/library/std/src/sys/vxworks/args.rs index adff6c489b..30cf7a707c 100644 --- a/library/std/src/sys/vxworks/args.rs +++ b/library/std/src/sys/vxworks/args.rs @@ -57,11 +57,11 @@ mod imp { use crate::marker::PhantomData; use crate::ptr; - use crate::sys_common::mutex::Mutex; + use crate::sys_common::mutex::StaticMutex; static mut ARGC: isize = 0; static mut ARGV: *const *const u8 = ptr::null(); - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); pub unsafe fn init(argc: isize, argv: *const *const u8) { let _guard = LOCK.lock(); diff --git a/library/std/src/sys/vxworks/ext/fs.rs b/library/std/src/sys/vxworks/ext/fs.rs index 4ff86daf0d..68dc21b806 100644 --- a/library/std/src/sys/vxworks/ext/fs.rs +++ b/library/std/src/sys/vxworks/ext/fs.rs @@ -427,7 +427,7 @@ pub trait MetadataExt { /// ```no_run /// use std::fs; /// use std::os::unix::fs::MetadataExt; - /// use std::io; + /// use std::io; /// /// fn main() -> io::Result<()> { /// let meta = fs::metadata("some_file")?; @@ -774,15 +774,6 @@ impl DirEntryExt for fs::DirEntry { /// /// The `dst` path will be a symbolic link pointing to the `src` path. /// -/// # Note -/// -/// On Windows, you must specify whether a symbolic link points to a file -/// or directory. Use `os::windows::fs::symlink_file` to create a -/// symbolic link to a file, or `os::windows::fs::symlink_dir` to create a -/// symbolic link to a directory. Additionally, the process must have -/// `SeCreateSymbolicLinkPrivilege` in order to be able to create a -/// symbolic link. -/// /// # Examples /// /// ```no_run diff --git a/library/std/src/sys/vxworks/ext/io.rs b/library/std/src/sys/vxworks/ext/io.rs index 25c6e26d96..8b5a2d12af 100644 --- a/library/std/src/sys/vxworks/ext/io.rs +++ b/library/std/src/sys/vxworks/ext/io.rs @@ -63,6 +63,25 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + #[stable(feature = "rust1", since = "1.0.0")] impl AsRawFd for fs::File { fn as_raw_fd(&self) -> RawFd { diff --git a/library/std/src/sys/vxworks/fd.rs b/library/std/src/sys/vxworks/fd.rs index ea18684692..d58468ad53 100644 --- a/library/std/src/sys/vxworks/fd.rs +++ b/library/std/src/sys/vxworks/fd.rs @@ -53,7 +53,7 @@ impl FileDesc { } #[inline] - fn is_read_vectored(&self) -> bool { + pub fn is_read_vectored(&self) -> bool { true } diff --git a/library/std/src/sys/vxworks/net.rs b/library/std/src/sys/vxworks/net.rs index 32c27ab6e9..7613fbec46 100644 --- a/library/std/src/sys/vxworks/net.rs +++ b/library/std/src/sys/vxworks/net.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, taget_env = "gnu"))] +mod tests; + use crate::cmp; use crate::ffi::CStr; use crate::io; @@ -330,30 +333,3 @@ fn on_resolver_failure() { #[cfg(not(target_env = "gnu"))] fn on_resolver_failure() {} - -#[cfg(all(test, taget_env = "gnu"))] -mod test { - use super::*; - - #[test] - fn test_res_init() { - // This mostly just tests that the weak linkage doesn't panic wildly... - res_init_if_glibc_before_2_26().unwrap(); - } - - #[test] - fn test_parse_glibc_version() { - let cases = [ - ("0.0", Some((0, 0))), - ("01.+2", Some((1, 2))), - ("3.4.5.six", Some((3, 4))), - ("1", None), - ("1.-2", None), - ("1.foo", None), - ("foo.1", None), - ]; - for &(version_str, parsed) in cases.iter() { - assert_eq!(parsed, parse_glibc_version(version_str)); - } - } -} diff --git a/library/std/src/sys/vxworks/net/tests.rs b/library/std/src/sys/vxworks/net/tests.rs new file mode 100644 index 0000000000..e7c6e348f8 --- /dev/null +++ b/library/std/src/sys/vxworks/net/tests.rs @@ -0,0 +1,23 @@ +use super::*; + +#[test] +fn test_res_init() { + // This mostly just tests that the weak linkage doesn't panic wildly... + res_init_if_glibc_before_2_26().unwrap(); +} + +#[test] +fn test_parse_glibc_version() { + let cases = [ + ("0.0", Some((0, 0))), + ("01.+2", Some((1, 2))), + ("3.4.5.six", Some((3, 4))), + ("1", None), + ("1.-2", None), + ("1.foo", None), + ("foo.1", None), + ]; + for &(version_str, parsed) in cases.iter() { + assert_eq!(parsed, parse_glibc_version(version_str)); + } +} diff --git a/library/std/src/sys/vxworks/os.rs b/library/std/src/sys/vxworks/os.rs index 1fadf71613..08394a8d29 100644 --- a/library/std/src/sys/vxworks/os.rs +++ b/library/std/src/sys/vxworks/os.rs @@ -10,7 +10,7 @@ use crate::path::{self, Path, PathBuf}; use crate::slice; use crate::str; use crate::sys::cvt; -use crate::sys_common::mutex::{Mutex, MutexGuard}; +use crate::sys_common::mutex::{StaticMutex, StaticMutexGuard}; use libc::{self, c_char /*,c_void */, c_int}; /*use sys::fd; this one is probably important */ use crate::vec; @@ -212,10 +212,9 @@ pub unsafe fn environ() -> *mut *const *const c_char { &mut environ } -pub unsafe fn env_lock() -> MutexGuard<'static> { - // We never call `ENV_LOCK.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static ENV_LOCK: Mutex = Mutex::new(); +pub unsafe fn env_lock() -> StaticMutexGuard<'static> { + // It is UB to attempt to acquire this mutex reentrantly! + static ENV_LOCK: StaticMutex = StaticMutex::new(); ENV_LOCK.lock() } diff --git a/library/std/src/sys/vxworks/process/process_common.rs b/library/std/src/sys/vxworks/process/process_common.rs index bbbd5eda77..6473a0c3ce 100644 --- a/library/std/src/sys/vxworks/process/process_common.rs +++ b/library/std/src/sys/vxworks/process/process_common.rs @@ -351,8 +351,7 @@ impl ExitStatus { } fn exited(&self) -> bool { - /*unsafe*/ - { libc::WIFEXITED(self.0) } + libc::WIFEXITED(self.0) } pub fn success(&self) -> bool { @@ -360,19 +359,11 @@ impl ExitStatus { } pub fn code(&self) -> Option { - if self.exited() { - Some(/*unsafe*/ { libc::WEXITSTATUS(self.0) }) - } else { - None - } + if self.exited() { Some(libc::WEXITSTATUS(self.0)) } else { None } } pub fn signal(&self) -> Option { - if !self.exited() { - Some(/*unsafe*/ { libc::WTERMSIG(self.0) }) - } else { - None - } + if !self.exited() { Some(libc::WTERMSIG(self.0)) } else { None } } } diff --git a/library/std/src/sys/vxworks/thread_local_dtor.rs b/library/std/src/sys/vxworks/thread_local_dtor.rs index 3f73f6c490..5391ed83eb 100644 --- a/library/std/src/sys/vxworks/thread_local_dtor.rs +++ b/library/std/src/sys/vxworks/thread_local_dtor.rs @@ -2,6 +2,6 @@ #![unstable(feature = "thread_local_internals", issue = "none")] pub unsafe fn register_dtor(t: *mut u8, dtor: unsafe extern "C" fn(*mut u8)) { - use crate::sys_common::thread_local::register_dtor_fallback; + use crate::sys_common::thread_local_dtor::register_dtor_fallback; register_dtor_fallback(t, dtor); } diff --git a/library/std/src/sys/wasi/alloc.rs b/library/std/src/sys/wasi/alloc.rs deleted file mode 100644 index 57187851a1..0000000000 --- a/library/std/src/sys/wasi/alloc.rs +++ /dev/null @@ -1,42 +0,0 @@ -use crate::alloc::{GlobalAlloc, Layout, System}; -use crate::ptr; -use crate::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() { - libc::malloc(layout.size()) as *mut u8 - } else { - libc::aligned_alloc(layout.align(), layout.size()) as *mut u8 - } - } - - #[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 { - realloc_fallback(self, ptr, layout, new_size) - } - } -} diff --git a/library/std/src/sys/wasi/args.rs b/library/std/src/sys/wasi/args.rs index 02aa68d6f3..9a27218e1f 100644 --- a/library/std/src/sys/wasi/args.rs +++ b/library/std/src/sys/wasi/args.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::ffi::{CStr, OsStr, OsString}; use crate::marker::PhantomData; use crate::os::wasi::ffi::OsStrExt; diff --git a/library/std/src/sys/wasi/ext/fs.rs b/library/std/src/sys/wasi/ext/fs.rs index f41c6626cc..4f7cf6018d 100644 --- a/library/std/src/sys/wasi/ext/fs.rs +++ b/library/std/src/sys/wasi/ext/fs.rs @@ -1,5 +1,6 @@ //! WASI-specific extensions to primitives in the `std::fs` module. +#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "none")] use crate::fs::{self, File, Metadata, OpenOptions}; @@ -9,8 +10,6 @@ use crate::sys::fs::osstr2str; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; /// WASI-specific extensions to [`File`]. -/// -/// [`File`]: ../../../../std/fs/struct.File.html pub trait FileExt { /// Reads a number of bytes starting from a given offset. /// @@ -23,8 +22,6 @@ pub trait FileExt { /// /// Note that similar to [`File::read`], it is not an error to return with a /// short read. - /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read fn read_at(&self, buf: &mut [u8], offset: u64) -> io::Result { let bufs = &mut [IoSliceMut::new(buf)]; self.read_vectored_at(bufs, offset) @@ -41,8 +38,6 @@ pub trait FileExt { /// /// Note that similar to [`File::read_vectored`], it is not an error to /// return with a short read. - /// - /// [`File::read`]: ../../../../std/fs/struct.File.html#method.read_vectored fn read_vectored_at(&self, bufs: &mut [IoSliceMut<'_>], offset: u64) -> io::Result; /// Reads the exact number of byte required to fill `buf` from the given offset. @@ -54,8 +49,7 @@ pub trait FileExt { /// /// Similar to [`Read::read_exact`] but uses [`read_at`] instead of `read`. /// - /// [`Read::read_exact`]: ../../../../std/io/trait.Read.html#method.read_exact - /// [`read_at`]: #tymethod.read_at + /// [`read_at`]: FileExt::read_at /// /// # Errors /// @@ -73,9 +67,6 @@ pub trait FileExt { /// If this function returns an error, it is unspecified how many bytes it /// has read, but it will never read more than would be necessary to /// completely fill the buffer. - /// - /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`ErrorKind::UnexpectedEof`]: ../../../../std/io/enum.ErrorKind.html#variant.UnexpectedEof #[stable(feature = "rw_exact_all_at", since = "1.33.0")] fn read_exact_at(&self, mut buf: &mut [u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { @@ -111,8 +102,6 @@ pub trait FileExt { /// /// Note that similar to [`File::write`], it is not an error to return a /// short write. - /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#write.v fn write_at(&self, buf: &[u8], offset: u64) -> io::Result { let bufs = &[IoSlice::new(buf)]; self.write_vectored_at(bufs, offset) @@ -132,8 +121,6 @@ pub trait FileExt { /// /// Note that similar to [`File::write_vectored`], it is not an error to return a /// short write. - /// - /// [`File::write`]: ../../../../std/fs/struct.File.html#method.write_vectored fn write_vectored_at(&self, bufs: &[IoSlice<'_>], offset: u64) -> io::Result; /// Attempts to write an entire buffer starting from a given offset. @@ -155,8 +142,7 @@ pub trait FileExt { /// This function will return the first error of /// non-[`ErrorKind::Interrupted`] kind that [`write_at`] returns. /// - /// [`ErrorKind::Interrupted`]: ../../../../std/io/enum.ErrorKind.html#variant.Interrupted - /// [`write_at`]: #tymethod.write_at + /// [`write_at`]: FileExt::write_at #[stable(feature = "rw_exact_all_at", since = "1.33.0")] fn write_all_at(&self, mut buf: &[u8], mut offset: u64) -> io::Result<()> { while !buf.is_empty() { @@ -289,8 +275,6 @@ impl FileExt for fs::File { } /// WASI-specific extensions to [`fs::OpenOptions`]. -/// -/// [`fs::OpenOptions`]: ../../../../std/fs/struct.OpenOptions.html pub trait OpenOptionsExt { /// Pass custom `dirflags` argument to `path_open`. /// @@ -406,8 +390,6 @@ impl OpenOptionsExt for OpenOptions { } /// WASI-specific extensions to [`fs::Metadata`]. -/// -/// [`fs::Metadata`]: ../../../../std/fs/struct.Metadata.html pub trait MetadataExt { /// Returns the `st_dev` field of the internal `filestat_t` fn dev(&self) -> u64; @@ -448,8 +430,6 @@ impl MetadataExt for fs::Metadata { /// /// Adds support for special WASI file types such as block/character devices, /// pipes, and sockets. -/// -/// [`FileType`]: ../../../../std/fs/struct.FileType.html pub trait FileTypeExt { /// Returns `true` if this file type is a block device. fn is_block_device(&self) -> bool; @@ -477,8 +457,6 @@ impl FileTypeExt for fs::FileType { } /// WASI-specific extension methods for [`fs::DirEntry`]. -/// -/// [`fs::DirEntry`]: ../../../../std/fs/struct.DirEntry.html pub trait DirEntryExt { /// Returns the underlying `d_ino` field of the `dirent_t` fn ino(&self) -> u64; diff --git a/library/std/src/sys/wasi/ext/io.rs b/library/std/src/sys/wasi/ext/io.rs index e849400d67..661214e8f4 100644 --- a/library/std/src/sys/wasi/ext/io.rs +++ b/library/std/src/sys/wasi/ext/io.rs @@ -1,5 +1,6 @@ //! WASI-specific extensions to general I/O primitives +#![deny(unsafe_op_in_unsafe_fn)] #![unstable(feature = "wasi_ext", issue = "none")] use crate::fs; @@ -51,6 +52,25 @@ pub trait IntoRawFd { fn into_raw_fd(self) -> RawFd; } +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl AsRawFd for RawFd { + fn as_raw_fd(&self) -> RawFd { + *self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl IntoRawFd for RawFd { + fn into_raw_fd(self) -> RawFd { + self + } +} +#[stable(feature = "raw_fd_reflexive_traits", since = "1.48.0")] +impl FromRawFd for RawFd { + unsafe fn from_raw_fd(fd: RawFd) -> RawFd { + fd + } +} + impl AsRawFd for net::TcpStream { fn as_raw_fd(&self) -> RawFd { self.as_inner().fd().as_raw() diff --git a/library/std/src/sys/wasi/ext/mod.rs b/library/std/src/sys/wasi/ext/mod.rs index 58c8c46c96..1cda30edca 100644 --- a/library/std/src/sys/wasi/ext/mod.rs +++ b/library/std/src/sys/wasi/ext/mod.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + pub mod ffi; pub mod fs; pub mod io; diff --git a/library/std/src/sys/wasi/fd.rs b/library/std/src/sys/wasi/fd.rs index 8458ded5db..ba66eba2ad 100644 --- a/library/std/src/sys/wasi/fd.rs +++ b/library/std/src/sys/wasi/fd.rs @@ -1,3 +1,4 @@ +#![deny(unsafe_op_in_unsafe_fn)] #![allow(dead_code)] use super::err2io; diff --git a/library/std/src/sys/wasi/fs.rs b/library/std/src/sys/wasi/fs.rs index 8408756f1b..93a92b49cf 100644 --- a/library/std/src/sys/wasi/fs.rs +++ b/library/std/src/sys/wasi/fs.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::ffi::{CStr, CString, OsStr, OsString}; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut, SeekFrom}; diff --git a/library/std/src/sys/wasi/io.rs b/library/std/src/sys/wasi/io.rs index 0ad2e15285..ee017d13a4 100644 --- a/library/std/src/sys/wasi/io.rs +++ b/library/std/src/sys/wasi/io.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::marker::PhantomData; use crate::slice; diff --git a/library/std/src/sys/wasi/mod.rs b/library/std/src/sys/wasi/mod.rs index 2704ff484f..a7a4407ac3 100644 --- a/library/std/src/sys/wasi/mod.rs +++ b/library/std/src/sys/wasi/mod.rs @@ -17,6 +17,7 @@ use crate::io as std_io; use crate::mem; +#[path = "../unix/alloc.rs"] pub mod alloc; pub mod args; #[path = "../unsupported/cmath.rs"] @@ -33,8 +34,11 @@ pub mod net; pub mod os; pub use crate::sys_common::os_str_bytes as os_str; pub mod ext; +#[path = "../unix/path.rs"] pub mod path; +#[path = "../unsupported/pipe.rs"] pub mod pipe; +#[path = "../unsupported/process.rs"] pub mod process; #[path = "../unsupported/rwlock.rs"] pub mod rwlock; diff --git a/library/std/src/sys/wasi/net.rs b/library/std/src/sys/wasi/net.rs index e186453588..8fd4bb76d8 100644 --- a/library/std/src/sys/wasi/net.rs +++ b/library/std/src/sys/wasi/net.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::convert::TryFrom; use crate::fmt; use crate::io::{self, IoSlice, IoSliceMut}; diff --git a/library/std/src/sys/wasi/os.rs b/library/std/src/sys/wasi/os.rs index 8052c0aa8a..33c796ae94 100644 --- a/library/std/src/sys/wasi/os.rs +++ b/library/std/src/sys/wasi/os.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::any::Any; use crate::error::Error as StdError; use crate::ffi::{CStr, CString, OsStr, OsString}; diff --git a/library/std/src/sys/wasi/path.rs b/library/std/src/sys/wasi/path.rs deleted file mode 100644 index 840a7ae042..0000000000 --- a/library/std/src/sys/wasi/path.rs +++ /dev/null @@ -1,19 +0,0 @@ -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 --git a/library/std/src/sys/wasi/pipe.rs b/library/std/src/sys/wasi/pipe.rs deleted file mode 100644 index 10d0925823..0000000000 --- a/library/std/src/sys/wasi/pipe.rs +++ /dev/null @@ -1,38 +0,0 @@ -use crate::io::{self, IoSlice, IoSliceMut}; -use crate::sys::Void; - -pub struct AnonPipe(Void); - -impl AnonPipe { - pub fn read(&self, _buf: &mut [u8]) -> io::Result { - match self.0 {} - } - - pub fn read_vectored(&self, _bufs: &mut [IoSliceMut<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_read_vectored(&self) -> bool { - match self.0 {} - } - - pub fn write(&self, _buf: &[u8]) -> io::Result { - match self.0 {} - } - - pub fn write_vectored(&self, _bufs: &[IoSlice<'_>]) -> io::Result { - match self.0 {} - } - - pub fn is_write_vectored(&self) -> bool { - match self.0 {} - } - - pub fn diverge(&self) -> ! { - match self.0 {} - } -} - -pub fn read2(p1: AnonPipe, _v1: &mut Vec, _p2: AnonPipe, _v2: &mut Vec) -> io::Result<()> { - match p1.0 {} -} diff --git a/library/std/src/sys/wasi/process.rs b/library/std/src/sys/wasi/process.rs deleted file mode 100644 index 7156c9ab92..0000000000 --- a/library/std/src/sys/wasi/process.rs +++ /dev/null @@ -1,149 +0,0 @@ -use crate::ffi::OsStr; -use crate::fmt; -use crate::io; -use crate::sys::fs::File; -use crate::sys::pipe::AnonPipe; -use crate::sys::{unsupported, Void}; -use crate::sys_common::process::CommandEnv; - -pub use crate::ffi::OsString as EnvKey; - -//////////////////////////////////////////////////////////////////////////////// -// Command -//////////////////////////////////////////////////////////////////////////////// - -pub struct Command { - env: CommandEnv, -} - -// passed back to std::process with the pipes connected to the child, if any -// were requested -pub struct StdioPipes { - pub stdin: Option, - pub stdout: Option, - pub stderr: Option, -} - -pub enum Stdio { - Inherit, - Null, - MakePipe, -} - -impl Command { - pub fn new(_program: &OsStr) -> Command { - Command { env: Default::default() } - } - - pub fn arg(&mut self, _arg: &OsStr) {} - - pub fn env_mut(&mut self) -> &mut CommandEnv { - &mut self.env - } - - pub fn cwd(&mut self, _dir: &OsStr) {} - - pub fn stdin(&mut self, _stdin: Stdio) {} - - pub fn stdout(&mut self, _stdout: Stdio) {} - - pub fn stderr(&mut self, _stderr: Stdio) {} - - pub fn spawn( - &mut self, - _default: Stdio, - _needs_stdin: bool, - ) -> io::Result<(Process, StdioPipes)> { - unsupported() - } -} - -impl From for Stdio { - fn from(pipe: AnonPipe) -> Stdio { - pipe.diverge() - } -} - -impl From for Stdio { - fn from(_file: File) -> Stdio { - panic!("unsupported") - } -} - -impl fmt::Debug for Command { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - Ok(()) - } -} - -pub struct ExitStatus(Void); - -impl ExitStatus { - pub fn success(&self) -> bool { - match self.0 {} - } - - pub fn code(&self) -> Option { - match self.0 {} - } -} - -impl Clone for ExitStatus { - fn clone(&self) -> ExitStatus { - match self.0 {} - } -} - -impl Copy for ExitStatus {} - -impl PartialEq for ExitStatus { - fn eq(&self, _other: &ExitStatus) -> bool { - match self.0 {} - } -} - -impl Eq for ExitStatus {} - -impl fmt::Debug for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -impl fmt::Display for ExitStatus { - fn fmt(&self, _f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.0 {} - } -} - -#[derive(PartialEq, Eq, Clone, Copy, Debug)] -pub struct ExitCode(bool); - -impl ExitCode { - pub const SUCCESS: ExitCode = ExitCode(false); - pub const FAILURE: ExitCode = ExitCode(true); - - pub fn as_i32(&self) -> i32 { - self.0 as i32 - } -} - -pub struct Process(Void); - -impl Process { - pub fn id(&self) -> u32 { - match self.0 {} - } - - pub fn kill(&mut self) -> io::Result<()> { - match self.0 {} - } - - pub fn wait(&mut self) -> io::Result { - match self.0 {} - } - - pub fn try_wait(&mut self) -> io::Result> { - match self.0 {} - } -} diff --git a/library/std/src/sys/wasi/stdio.rs b/library/std/src/sys/wasi/stdio.rs index 23baafabf7..d82f6f4118 100644 --- a/library/std/src/sys/wasi/stdio.rs +++ b/library/std/src/sys/wasi/stdio.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::io::{self, IoSlice, IoSliceMut}; use crate::mem::ManuallyDrop; use crate::sys::fd::WasiFd; diff --git a/library/std/src/sys/wasi/thread.rs b/library/std/src/sys/wasi/thread.rs index 0d39b1cec3..8eaa5f09cb 100644 --- a/library/std/src/sys/wasi/thread.rs +++ b/library/std/src/sys/wasi/thread.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::ffi::CStr; use crate::io; use crate::mem; diff --git a/library/std/src/sys/wasi/time.rs b/library/std/src/sys/wasi/time.rs index 80ec317b5a..2e720d1160 100644 --- a/library/std/src/sys/wasi/time.rs +++ b/library/std/src/sys/wasi/time.rs @@ -1,3 +1,5 @@ +#![deny(unsafe_op_in_unsafe_fn)] + use crate::time::Duration; #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] diff --git a/library/std/src/sys/wasm/mod.rs b/library/std/src/sys/wasm/mod.rs index 3de5890404..2934ea59ab 100644 --- a/library/std/src/sys/wasm/mod.rs +++ b/library/std/src/sys/wasm/mod.rs @@ -27,7 +27,7 @@ pub mod io; pub mod net; #[path = "../unsupported/os.rs"] pub mod os; -#[path = "../unsupported/path.rs"] +#[path = "../unix/path.rs"] pub mod path; #[path = "../unsupported/pipe.rs"] pub mod pipe; diff --git a/library/std/src/sys/windows/args.rs b/library/std/src/sys/windows/args.rs index 5fbea2a291..bcc2ea9ae0 100644 --- a/library/std/src/sys/windows/args.rs +++ b/library/std/src/sys/windows/args.rs @@ -1,5 +1,8 @@ #![allow(dead_code)] // runtime init functions not used during testing +#[cfg(test)] +mod tests; + use crate::ffi::OsString; use crate::fmt; use crate::os::windows::prelude::*; @@ -198,69 +201,3 @@ impl ExactSizeIterator for Args { self.parsed_args_list.len() } } - -#[cfg(test)] -mod tests { - use crate::ffi::OsString; - use crate::sys::windows::args::*; - - fn chk(string: &str, parts: &[&str]) { - let mut wide: Vec = OsString::from(string).encode_wide().collect(); - wide.push(0); - let parsed = unsafe { - parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) - }; - let expected: Vec = parts.iter().map(|k| OsString::from(k)).collect(); - assert_eq!(parsed.as_slice(), expected.as_slice()); - } - - #[test] - fn empty() { - chk("", &["TEST.EXE"]); - chk("\0", &["TEST.EXE"]); - } - - #[test] - fn single_words() { - chk("EXE one_word", &["EXE", "one_word"]); - chk("EXE a", &["EXE", "a"]); - chk("EXE 😅", &["EXE", "😅"]); - chk("EXE 😅🤦", &["EXE", "😅🤦"]); - } - - #[test] - fn official_examples() { - chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]); - chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]); - chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]); - chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]); - } - - #[test] - fn whitespace_behavior() { - chk(r#" test"#, &["", "test"]); - chk(r#" test"#, &["", "test"]); - chk(r#" test test2"#, &["", "test", "test2"]); - chk(r#" test test2"#, &["", "test", "test2"]); - chk(r#"test test2 "#, &["test", "test2"]); - chk(r#"test test2 "#, &["test", "test2"]); - chk(r#"test "#, &["test"]); - } - - #[test] - fn genius_quotes() { - chk(r#"EXE "" """#, &["EXE", "", ""]); - chk(r#"EXE "" """"#, &["EXE", "", "\""]); - chk( - r#"EXE "this is """all""" in the same argument""#, - &["EXE", "this is \"all\" in the same argument"], - ); - chk(r#"EXE "a"""#, &["EXE", "a\""]); - chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]); - // quotes cannot be escaped in command names - chk(r#""EXE" check"#, &["EXE", "check"]); - chk(r#""EXE check""#, &["EXE check"]); - chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]); - chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]); - } -} diff --git a/library/std/src/sys/windows/args/tests.rs b/library/std/src/sys/windows/args/tests.rs new file mode 100644 index 0000000000..756a4361ea --- /dev/null +++ b/library/std/src/sys/windows/args/tests.rs @@ -0,0 +1,61 @@ +use crate::ffi::OsString; +use crate::sys::windows::args::*; + +fn chk(string: &str, parts: &[&str]) { + let mut wide: Vec = OsString::from(string).encode_wide().collect(); + wide.push(0); + let parsed = + unsafe { parse_lp_cmd_line(wide.as_ptr() as *const u16, || OsString::from("TEST.EXE")) }; + let expected: Vec = parts.iter().map(|k| OsString::from(k)).collect(); + assert_eq!(parsed.as_slice(), expected.as_slice()); +} + +#[test] +fn empty() { + chk("", &["TEST.EXE"]); + chk("\0", &["TEST.EXE"]); +} + +#[test] +fn single_words() { + chk("EXE one_word", &["EXE", "one_word"]); + chk("EXE a", &["EXE", "a"]); + chk("EXE 😅", &["EXE", "😅"]); + chk("EXE 😅🤦", &["EXE", "😅🤦"]); +} + +#[test] +fn official_examples() { + chk(r#"EXE "abc" d e"#, &["EXE", "abc", "d", "e"]); + chk(r#"EXE a\\\b d"e f"g h"#, &["EXE", r#"a\\\b"#, "de fg", "h"]); + chk(r#"EXE a\\\"b c d"#, &["EXE", r#"a\"b"#, "c", "d"]); + chk(r#"EXE a\\\\"b c" d e"#, &["EXE", r#"a\\b c"#, "d", "e"]); +} + +#[test] +fn whitespace_behavior() { + chk(r#" test"#, &["", "test"]); + chk(r#" test"#, &["", "test"]); + chk(r#" test test2"#, &["", "test", "test2"]); + chk(r#" test test2"#, &["", "test", "test2"]); + chk(r#"test test2 "#, &["test", "test2"]); + chk(r#"test test2 "#, &["test", "test2"]); + chk(r#"test "#, &["test"]); +} + +#[test] +fn genius_quotes() { + chk(r#"EXE "" """#, &["EXE", "", ""]); + chk(r#"EXE "" """"#, &["EXE", "", "\""]); + chk( + r#"EXE "this is """all""" in the same argument""#, + &["EXE", "this is \"all\" in the same argument"], + ); + chk(r#"EXE "a"""#, &["EXE", "a\""]); + chk(r#"EXE "a"" a"#, &["EXE", "a\"", "a"]); + // quotes cannot be escaped in command names + chk(r#""EXE" check"#, &["EXE", "check"]); + chk(r#""EXE check""#, &["EXE check"]); + chk(r#""EXE """for""" check"#, &["EXE ", r#"for""#, "check"]); + chk(r#""EXE \"for\" check"#, &[r#"EXE \"#, r#"for""#, "check"]); +} diff --git a/library/std/src/sys/windows/c.rs b/library/std/src/sys/windows/c.rs index f440442ca3..559c4dc9c7 100644 --- a/library/std/src/sys/windows/c.rs +++ b/library/std/src/sys/windows/c.rs @@ -1032,7 +1032,7 @@ extern "system" { // 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! { - kernel32: + "kernel32": pub fn CreateSymbolicLinkW(_lpSymlinkFileName: LPCWSTR, _lpTargetFileName: LPCWSTR, diff --git a/library/std/src/sys/windows/compat.rs b/library/std/src/sys/windows/compat.rs index d6d433f9d0..3f25f05e1b 100644 --- a/library/std/src/sys/windows/compat.rs +++ b/library/std/src/sys/windows/compat.rs @@ -12,7 +12,6 @@ //! function is available but afterwards it's just a load and a jump. use crate::ffi::CString; -use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; pub fn lookup(module: &str, symbol: &str) -> Option { @@ -28,45 +27,69 @@ pub fn lookup(module: &str, symbol: &str) -> Option { } } -pub fn store_func(ptr: &AtomicUsize, module: &str, symbol: &str, fallback: usize) -> usize { - let value = lookup(module, symbol).unwrap_or(fallback); - ptr.store(value, Ordering::SeqCst); - value -} - macro_rules! compat_fn { - ($module:ident: $( + ($module:literal: $( $(#[$meta:meta])* - pub fn $symbol:ident($($argname:ident: $argtype:ty),*) - -> $rettype:ty { - $($body:expr);* - } + pub fn $symbol:ident($($argname:ident: $argtype:ty),*) -> $rettype:ty $body:block )*) => ($( - #[allow(unused_variables)] $(#[$meta])* - pub unsafe fn $symbol($($argname: $argtype),*) -> $rettype { + pub mod $symbol { + use super::*; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::mem; + type F = unsafe extern "system" fn($($argtype),*) -> $rettype; static PTR: AtomicUsize = AtomicUsize::new(0); + #[allow(unused_variables)] + unsafe extern "system" fn fallback($($argname: $argtype),*) -> $rettype $body + + /// This address is stored in `PTR` to incidate an unavailable API. + /// + /// This way, call() will end up calling fallback() if it is unavailable. + /// + /// This is a `static` to avoid rustc duplicating `fn fallback()` + /// into both load() and is_available(), which would break + /// is_available()'s comparison. By using the same static variable + /// in both places, they'll refer to the same (copy of the) + /// function. + /// + /// LLVM merging the address of fallback with other functions + /// (because of unnamed_addr) is fine, since it's only compared to + /// an address from GetProcAddress from an external dll. + static FALLBACK: F = fallback; + + #[cold] fn load() -> usize { - crate::sys::compat::store_func(&PTR, - stringify!($module), - stringify!($symbol), - fallback as usize) - } - unsafe extern "system" fn fallback($($argname: $argtype),*) - -> $rettype { - $($body);* + // There is no locking here. It's okay if this is executed by multiple threads in + // parallel. `lookup` will result in the same value, and it's okay if they overwrite + // eachothers result as long as they do so atomically. We don't need any guarantees + // about memory ordering, as this involves just a single atomic variable which is + // not used to protect or order anything else. + let addr = crate::sys::compat::lookup($module, stringify!($symbol)) + .unwrap_or(FALLBACK as usize); + PTR.store(addr, Ordering::Relaxed); + addr } - let addr = match PTR.load(Ordering::SeqCst) { - 0 => load(), - n => n, - }; - mem::transmute::(addr)($($argname),*) + fn addr() -> usize { + match PTR.load(Ordering::Relaxed) { + 0 => load(), + addr => addr, + } + } + + #[allow(dead_code)] + pub fn is_available() -> bool { + addr() != FALLBACK as usize + } + + pub unsafe fn call($($argname: $argtype),*) -> $rettype { + mem::transmute::(addr())($($argname),*) + } } + + pub use $symbol::call as $symbol; )*) } diff --git a/library/std/src/sys/windows/ext/io.rs b/library/std/src/sys/windows/ext/io.rs index 4573ee5893..e75f9a4bfd 100644 --- a/library/std/src/sys/windows/ext/io.rs +++ b/library/std/src/sys/windows/ext/io.rs @@ -1,3 +1,5 @@ +//! Windows-specific extensions to general I/O primitives. + #![stable(feature = "rust1", since = "1.0.0")] use crate::fs; diff --git a/library/std/src/sys/windows/ext/raw.rs b/library/std/src/sys/windows/ext/raw.rs index 7f2a287782..5014e008eb 100644 --- a/library/std/src/sys/windows/ext/raw.rs +++ b/library/std/src/sys/windows/ext/raw.rs @@ -1,4 +1,4 @@ -//! Windows-specific primitives +//! Windows-specific primitives. #![stable(feature = "raw_ext", since = "1.1.0")] diff --git a/library/std/src/sys/windows/mod.rs b/library/std/src/sys/windows/mod.rs index a0d5a7471d..8178e6806b 100644 --- a/library/std/src/sys/windows/mod.rs +++ b/library/std/src/sys/windows/mod.rs @@ -306,10 +306,20 @@ pub fn dur2timeout(dur: Duration) -> c::DWORD { /// that function for more information on `__fastfail` #[allow(unreachable_code)] pub fn abort_internal() -> ! { - #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] + const FAST_FAIL_FATAL_APP_EXIT: usize = 7; unsafe { - llvm_asm!("int $$0x29" :: "{ecx}"(7) ::: volatile); // 7 is FAST_FAIL_FATAL_APP_EXIT - crate::intrinsics::unreachable(); + cfg_if::cfg_if! { + if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + asm!("int $$0x29", in("ecx") FAST_FAIL_FATAL_APP_EXIT); + crate::intrinsics::unreachable(); + } else if #[cfg(all(target_arch = "arm", target_feature = "thumb-mode"))] { + asm!(".inst 0xDEFB", in("r0") FAST_FAIL_FATAL_APP_EXIT); + crate::intrinsics::unreachable(); + } else if #[cfg(target_arch = "aarch64")] { + asm!("brk 0xF003", in("x0") FAST_FAIL_FATAL_APP_EXIT); + crate::intrinsics::unreachable(); + } + } } crate::intrinsics::abort(); } diff --git a/library/std/src/sys/windows/mutex.rs b/library/std/src/sys/windows/mutex.rs index 63dfc64090..e2aaca59fe 100644 --- a/library/std/src/sys/windows/mutex.rs +++ b/library/std/src/sys/windows/mutex.rs @@ -19,24 +19,28 @@ //! CriticalSection is used and we keep track of who's holding the mutex to //! detect recursive locks. -use crate::cell::UnsafeCell; +use crate::cell::{Cell, UnsafeCell}; use crate::mem::{self, MaybeUninit}; use crate::sync::atomic::{AtomicUsize, Ordering}; use crate::sys::c; -use crate::sys::compat; pub struct Mutex { + // This is either directly an SRWLOCK (if supported), or a Box otherwise. lock: AtomicUsize, - held: UnsafeCell, } unsafe impl Send for Mutex {} unsafe impl Sync for Mutex {} +struct Inner { + remutex: ReentrantMutex, + held: Cell, +} + #[derive(Clone, Copy)] enum Kind { - SRWLock = 1, - CriticalSection = 2, + SRWLock, + CriticalSection, } #[inline] @@ -51,7 +55,6 @@ impl Mutex { // This works because SRWLOCK_INIT is 0 (wrapped in a struct), so we are also properly // initializing an SRWLOCK here. lock: AtomicUsize::new(0), - held: UnsafeCell::new(false), } } #[inline] @@ -60,10 +63,11 @@ impl Mutex { match kind() { Kind::SRWLock => c::AcquireSRWLockExclusive(raw(self)), Kind::CriticalSection => { - let re = self.remutex(); - (*re).lock(); - if !self.flag_locked() { - (*re).unlock(); + let inner = &*self.inner(); + inner.remutex.lock(); + if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); panic!("cannot recursively lock a mutex"); } } @@ -73,23 +77,27 @@ impl Mutex { match kind() { Kind::SRWLock => c::TryAcquireSRWLockExclusive(raw(self)) != 0, Kind::CriticalSection => { - let re = self.remutex(); - if !(*re).try_lock() { + let inner = &*self.inner(); + if !inner.remutex.try_lock() { + false + } else if inner.held.replace(true) { + // It was already locked, so we got a recursive lock which we do not want. + inner.remutex.unlock(); false - } else if self.flag_locked() { - true } else { - (*re).unlock(); - false + true } } } } pub unsafe fn unlock(&self) { - *self.held.get() = false; match kind() { Kind::SRWLock => c::ReleaseSRWLockExclusive(raw(self)), - Kind::CriticalSection => (*self.remutex()).unlock(), + Kind::CriticalSection => { + let inner = &*(self.lock.load(Ordering::SeqCst) as *const Inner); + inner.held.set(false); + inner.remutex.unlock(); + } } } pub unsafe fn destroy(&self) { @@ -97,60 +105,35 @@ impl Mutex { Kind::SRWLock => {} Kind::CriticalSection => match self.lock.load(Ordering::SeqCst) { 0 => {} - n => { - Box::from_raw(n as *mut ReentrantMutex).destroy(); - } + n => Box::from_raw(n as *mut Inner).remutex.destroy(), }, } } - unsafe fn remutex(&self) -> *mut ReentrantMutex { + unsafe fn inner(&self) -> *const Inner { match self.lock.load(Ordering::SeqCst) { 0 => {} - n => return n as *mut _, + n => return n as *const _, } - let re = box ReentrantMutex::uninitialized(); - re.init(); - let re = Box::into_raw(re); - match self.lock.compare_and_swap(0, re as usize, Ordering::SeqCst) { - 0 => re, + let inner = box Inner { remutex: ReentrantMutex::uninitialized(), held: Cell::new(false) }; + inner.remutex.init(); + let inner = Box::into_raw(inner); + match self.lock.compare_and_swap(0, inner as usize, Ordering::SeqCst) { + 0 => inner, n => { - Box::from_raw(re).destroy(); - n as *mut _ + Box::from_raw(inner).remutex.destroy(); + n as *const _ } } } - - unsafe fn flag_locked(&self) -> bool { - if *self.held.get() { - false - } else { - *self.held.get() = true; - true - } - } } fn kind() -> Kind { - static KIND: AtomicUsize = AtomicUsize::new(0); - - let val = KIND.load(Ordering::SeqCst); - if val == Kind::SRWLock as usize { - return Kind::SRWLock; - } else if val == Kind::CriticalSection as usize { - return Kind::CriticalSection; - } - - let ret = match compat::lookup("kernel32", "AcquireSRWLockExclusive") { - None => Kind::CriticalSection, - Some(..) => Kind::SRWLock, - }; - KIND.store(ret as usize, Ordering::SeqCst); - ret + if c::AcquireSRWLockExclusive::is_available() { Kind::SRWLock } else { Kind::CriticalSection } } pub struct ReentrantMutex { - inner: UnsafeCell>, + inner: MaybeUninit>, } unsafe impl Send for ReentrantMutex {} @@ -158,27 +141,27 @@ unsafe impl Sync for ReentrantMutex {} impl ReentrantMutex { pub const fn uninitialized() -> ReentrantMutex { - ReentrantMutex { inner: UnsafeCell::new(MaybeUninit::uninit()) } + ReentrantMutex { inner: MaybeUninit::uninit() } } pub unsafe fn init(&self) { - c::InitializeCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::InitializeCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } pub unsafe fn lock(&self) { - c::EnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::EnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } #[inline] pub unsafe fn try_lock(&self) -> bool { - c::TryEnterCriticalSection((&mut *self.inner.get()).as_mut_ptr()) != 0 + c::TryEnterCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())) != 0 } pub unsafe fn unlock(&self) { - c::LeaveCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::LeaveCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } pub unsafe fn destroy(&self) { - c::DeleteCriticalSection((&mut *self.inner.get()).as_mut_ptr()); + c::DeleteCriticalSection(UnsafeCell::raw_get(self.inner.as_ptr())); } } diff --git a/library/std/src/sys/windows/os.rs b/library/std/src/sys/windows/os.rs index a0da2498bb..77c378a66a 100644 --- a/library/std/src/sys/windows/os.rs +++ b/library/std/src/sys/windows/os.rs @@ -2,6 +2,9 @@ #![allow(nonstandard_style)] +#[cfg(test)] +mod tests; + use crate::os::windows::prelude::*; use crate::error::Error as StdError; @@ -328,20 +331,3 @@ pub fn exit(code: i32) -> ! { pub fn getpid() -> u32 { unsafe { c::GetCurrentProcessId() as u32 } } - -#[cfg(test)] -mod tests { - use crate::io::Error; - use crate::sys::c; - - // tests `error_string` above - #[test] - fn ntstatus_error() { - const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; - assert!( - !Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) - .to_string() - .contains("FormatMessageW() returned error") - ); - } -} diff --git a/library/std/src/sys/windows/os/tests.rs b/library/std/src/sys/windows/os/tests.rs new file mode 100644 index 0000000000..458d6e11c2 --- /dev/null +++ b/library/std/src/sys/windows/os/tests.rs @@ -0,0 +1,13 @@ +use crate::io::Error; +use crate::sys::c; + +// tests `error_string` above +#[test] +fn ntstatus_error() { + const STATUS_UNSUCCESSFUL: u32 = 0xc000_0001; + assert!( + !Error::from_raw_os_error((STATUS_UNSUCCESSFUL | c::FACILITY_NT_BIT) as _) + .to_string() + .contains("FormatMessageW() returned error") + ); +} diff --git a/library/std/src/sys/windows/os_str.rs b/library/std/src/sys/windows/os_str.rs index 2f5fc72ab4..7e09a4fd56 100644 --- a/library/std/src/sys/windows/os_str.rs +++ b/library/std/src/sys/windows/os_str.rs @@ -77,14 +77,14 @@ impl Buf { } pub fn as_slice(&self) -> &Slice { - // Safety: Slice is just a wrapper for Wtf8, + // SAFETY: Slice is just a wrapper for Wtf8, // and self.inner.as_slice() returns &Wtf8. // Therefore, transmuting &Wtf8 to &Slice is safe. unsafe { mem::transmute(self.inner.as_slice()) } } pub fn as_mut_slice(&mut self) -> &mut Slice { - // Safety: Slice is just a wrapper for Wtf8, + // SAFETY: Slice is just a wrapper for Wtf8, // and self.inner.as_mut_slice() returns &mut Wtf8. // Therefore, transmuting &mut Wtf8 to &mut Slice is safe. // Additionally, care should be taken to ensure the slice diff --git a/library/std/src/sys/windows/process.rs b/library/std/src/sys/windows/process.rs index 7d6d4775ee..243065b94b 100644 --- a/library/std/src/sys/windows/process.rs +++ b/library/std/src/sys/windows/process.rs @@ -1,5 +1,8 @@ #![unstable(feature = "process_internals", issue = "none")] +#[cfg(test)] +mod tests; + use crate::borrow::Borrow; use crate::collections::BTreeMap; use crate::env; @@ -19,7 +22,7 @@ use crate::sys::handle::Handle; use crate::sys::mutex::Mutex; use crate::sys::pipe::{self, AnonPipe}; use crate::sys::stdio; -use crate::sys_common::process::CommandEnv; +use crate::sys_common::process::{CommandEnv, CommandEnvs}; use crate::sys_common::AsInner; use libc::{c_void, EXIT_FAILURE, EXIT_SUCCESS}; @@ -131,6 +134,23 @@ impl Command { self.flags = flags; } + pub fn get_program(&self) -> &OsStr { + &self.program + } + + pub fn get_args(&self) -> CommandArgs<'_> { + let iter = self.args.iter(); + CommandArgs { iter } + } + + pub fn get_envs(&self) -> CommandEnvs<'_> { + self.env.iter() + } + + pub fn get_current_dir(&self) -> Option<&Path> { + self.cwd.as_ref().map(|cwd| Path::new(cwd)) + } + pub fn spawn( &mut self, default: Stdio, @@ -527,40 +547,31 @@ fn make_dirp(d: Option<&OsString>) -> io::Result<(*const u16, Vec)> { } } -#[cfg(test)] -mod tests { - use super::make_command_line; - use crate::ffi::{OsStr, OsString}; +pub struct CommandArgs<'a> { + iter: crate::slice::Iter<'a, OsString>, +} - #[test] - fn test_make_command_line() { - fn test_wrapper(prog: &str, args: &[&str]) -> String { - let command_line = &make_command_line( - OsStr::new(prog), - &args.iter().map(|a| OsString::from(a)).collect::>(), - ) - .unwrap(); - String::from_utf16(command_line).unwrap() - } - - assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc"); - - assert_eq!( - test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), - "\"C:\\Program Files\\blah\\blah.exe\" aaa" - ); - assert_eq!( - test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), - "\"C:\\Program Files\\test\" aa\\\"bb" - ); - assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\""); - assert_eq!( - test_wrapper("echo", &["\" \\\" \\", "\\"]), - "\"echo\" \"\\\" \\\\\\\" \\\\\" \\" - ); - assert_eq!( - test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), - "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\"" - ); +impl<'a> Iterator for CommandArgs<'a> { + type Item = &'a OsStr; + fn next(&mut self) -> Option<&'a OsStr> { + self.iter.next().map(|s| s.as_ref()) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +impl<'a> ExactSizeIterator for CommandArgs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } +} + +impl<'a> fmt::Debug for CommandArgs<'a> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_list().entries(self.iter.clone()).finish() } } diff --git a/library/std/src/sys/windows/process/tests.rs b/library/std/src/sys/windows/process/tests.rs new file mode 100644 index 0000000000..81627ad139 --- /dev/null +++ b/library/std/src/sys/windows/process/tests.rs @@ -0,0 +1,31 @@ +use super::make_command_line; +use crate::ffi::{OsStr, OsString}; + +#[test] +fn test_make_command_line() { + fn test_wrapper(prog: &str, args: &[&str]) -> String { + let command_line = &make_command_line( + OsStr::new(prog), + &args.iter().map(|a| OsString::from(a)).collect::>(), + ) + .unwrap(); + String::from_utf16(command_line).unwrap() + } + + assert_eq!(test_wrapper("prog", &["aaa", "bbb", "ccc"]), "\"prog\" aaa bbb ccc"); + + assert_eq!( + test_wrapper("C:\\Program Files\\blah\\blah.exe", &["aaa"]), + "\"C:\\Program Files\\blah\\blah.exe\" aaa" + ); + assert_eq!( + test_wrapper("C:\\Program Files\\test", &["aa\"bb"]), + "\"C:\\Program Files\\test\" aa\\\"bb" + ); + assert_eq!(test_wrapper("echo", &["a b c"]), "\"echo\" \"a b c\""); + assert_eq!(test_wrapper("echo", &["\" \\\" \\", "\\"]), "\"echo\" \"\\\" \\\\\\\" \\\\\" \\"); + assert_eq!( + test_wrapper("\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}", &[]), + "\"\u{03c0}\u{042f}\u{97f3}\u{00e6}\u{221e}\"" + ); +} diff --git a/library/std/src/sys_common/alloc.rs b/library/std/src/sys_common/alloc.rs index c669410078..6c1bc0d839 100644 --- a/library/std/src/sys_common/alloc.rs +++ b/library/std/src/sys_common/alloc.rs @@ -12,9 +12,11 @@ use crate::ptr; target_arch = "mips", target_arch = "powerpc", target_arch = "powerpc64", + target_arch = "sparc", target_arch = "asmjs", target_arch = "wasm32", - target_arch = "hexagon" + target_arch = "hexagon", + target_arch = "riscv32" )))] pub const MIN_ALIGN: usize = 8; #[cfg(all(any( diff --git a/library/std/src/sys_common/at_exit_imp.rs b/library/std/src/sys_common/at_exit_imp.rs index 6b799db856..90d5d3a789 100644 --- a/library/std/src/sys_common/at_exit_imp.rs +++ b/library/std/src/sys_common/at_exit_imp.rs @@ -4,7 +4,7 @@ use crate::mem; use crate::ptr; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; type Queue = Vec>; @@ -12,9 +12,8 @@ type Queue = Vec>; // on poisoning and this module needs to operate at a lower level than requiring // the thread infrastructure to be in place (useful on the borders of // initialization/destruction). -// We never call `LOCK.init()`, so it is UB to attempt to -// acquire this mutex reentrantly! -static LOCK: Mutex = Mutex::new(); +// It is UB to attempt to acquire this mutex reentrantly! +static LOCK: StaticMutex = StaticMutex::new(); static mut QUEUE: *mut Queue = ptr::null_mut(); const DONE: *mut Queue = 1_usize as *mut _; diff --git a/library/std/src/sys_common/bytestring.rs b/library/std/src/sys_common/bytestring.rs index dccc3bc4a1..97fba60c27 100644 --- a/library/std/src/sys_common/bytestring.rs +++ b/library/std/src/sys_common/bytestring.rs @@ -1,5 +1,8 @@ #![allow(dead_code)] +#[cfg(test)] +mod tests; + use crate::fmt::{Formatter, Result, Write}; use core::str::lossy::{Utf8Lossy, Utf8LossyChunk}; @@ -21,26 +24,3 @@ pub fn debug_fmt_bytestring(slice: &[u8], f: &mut Formatter<'_>) -> Result { } f.write_str("\"") } - -#[cfg(test)] -mod tests { - use super::*; - use crate::fmt::{Debug, Formatter, Result}; - - #[test] - fn smoke() { - struct Helper<'a>(&'a [u8]); - - impl Debug for Helper<'_> { - fn fmt(&self, f: &mut Formatter<'_>) -> Result { - debug_fmt_bytestring(self.0, f) - } - } - - let input = b"\xF0hello,\tworld"; - let expected = r#""\xF0hello,\tworld""#; - let output = format!("{:?}", Helper(input)); - - assert!(output == expected); - } -} diff --git a/library/std/src/sys_common/bytestring/tests.rs b/library/std/src/sys_common/bytestring/tests.rs new file mode 100644 index 0000000000..1685f087d1 --- /dev/null +++ b/library/std/src/sys_common/bytestring/tests.rs @@ -0,0 +1,19 @@ +use super::*; +use crate::fmt::{Debug, Formatter, Result}; + +#[test] +fn smoke() { + struct Helper<'a>(&'a [u8]); + + impl Debug for Helper<'_> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + debug_fmt_bytestring(self.0, f) + } + } + + let input = b"\xF0hello,\tworld"; + let expected = r#""\xF0hello,\tworld""#; + let output = format!("{:?}", Helper(input)); + + assert!(output == expected); +} diff --git a/library/std/src/sys_common/condvar.rs b/library/std/src/sys_common/condvar.rs index f9611bc6f7..a48d301f81 100644 --- a/library/std/src/sys_common/condvar.rs +++ b/library/std/src/sys_common/condvar.rs @@ -1,5 +1,5 @@ use crate::sys::condvar as imp; -use crate::sys_common::mutex::{self, Mutex}; +use crate::sys_common::mutex::MovableMutex; use crate::time::Duration; /// An OS-based condition variable. @@ -46,8 +46,8 @@ impl Condvar { /// Behavior is also undefined if more than one mutex is used concurrently /// on this condition variable. #[inline] - pub unsafe fn wait(&self, mutex: &Mutex) { - self.0.wait(mutex::raw(mutex)) + pub unsafe fn wait(&self, mutex: &MovableMutex) { + self.0.wait(mutex.raw()) } /// Waits for a signal on the specified mutex with a timeout duration @@ -57,8 +57,8 @@ impl Condvar { /// Behavior is also undefined if more than one mutex is used concurrently /// on this condition variable. #[inline] - pub unsafe fn wait_timeout(&self, mutex: &Mutex, dur: Duration) -> bool { - self.0.wait_timeout(mutex::raw(mutex), dur) + pub unsafe fn wait_timeout(&self, mutex: &MovableMutex, dur: Duration) -> bool { + self.0.wait_timeout(mutex.raw(), dur) } /// Deallocates all resources associated with this condition variable. diff --git a/library/std/src/sys_common/mod.rs b/library/std/src/sys_common/mod.rs index 840f9093e0..234b257aa9 100644 --- a/library/std/src/sys_common/mod.rs +++ b/library/std/src/sys_common/mod.rs @@ -15,6 +15,9 @@ #![allow(missing_docs)] #![allow(missing_debug_implementations)] +#[cfg(test)] +mod tests; + use crate::sync::Once; use crate::sys; @@ -63,6 +66,7 @@ pub mod thread; pub mod thread_info; pub mod thread_local_dtor; pub mod thread_local_key; +pub mod thread_parker; pub mod util; pub mod wtf8; @@ -141,8 +145,3 @@ pub fn mul_div_u64(value: u64, numer: u64, denom: u64) -> u64 { // r < denom, so (denom*numer) is the upper bound of (r*numer) q * numer + r * numer / denom } - -#[test] -fn test_muldiv() { - assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); -} diff --git a/library/std/src/sys_common/mutex.rs b/library/std/src/sys_common/mutex.rs index e66d899414..93ec7d89bc 100644 --- a/library/std/src/sys_common/mutex.rs +++ b/library/std/src/sys_common/mutex.rs @@ -1,97 +1,47 @@ use crate::sys::mutex as imp; -/// An OS-based mutual exclusion lock. +/// An OS-based mutual exclusion lock, meant for use in static variables. /// -/// This is the thinnest cross-platform wrapper around OS mutexes. All usage of -/// this mutex is unsafe and it is recommended to instead use the safe wrapper -/// at the top level of the crate instead of this type. -pub struct Mutex(imp::Mutex); +/// This mutex has a const constructor ([`StaticMutex::new`]), does not +/// implement `Drop` to cleanup resources, and causes UB when moved or used +/// reentrantly. +/// +/// This mutex does not implement poisoning. +/// +/// This is a wrapper around `imp::Mutex` that does *not* call `init()` and +/// `destroy()`. +pub struct StaticMutex(imp::Mutex); -unsafe impl Sync for Mutex {} +unsafe impl Sync for StaticMutex {} -impl Mutex { +impl StaticMutex { /// Creates a new mutex for use. /// /// Behavior is undefined if the mutex is moved after it is /// first used with any of the functions below. - /// Also, until `init` is called, behavior is undefined if this - /// mutex is ever used reentrantly, i.e., `raw_lock` or `try_lock` - /// are called by the thread currently holding the lock. + /// Also, the behavior is undefined if this mutex is ever used reentrantly, + /// i.e., `lock` is called by the thread currently holding the lock. #[rustc_const_stable(feature = "const_sys_mutex_new", since = "1.0.0")] - pub const fn new() -> Mutex { - Mutex(imp::Mutex::new()) - } - - /// Prepare the mutex for use. - /// - /// This should be called once the mutex is at a stable memory address. - /// If called, this must be the very first thing that happens to the mutex. - /// Calling it in parallel with or after any operation (including another - /// `init()`) is undefined behavior. - #[inline] - pub unsafe fn init(&mut self) { - self.0.init() - } - - /// Locks the mutex blocking the current thread until it is available. - /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. - #[inline] - pub unsafe fn raw_lock(&self) { - self.0.lock() + pub const fn new() -> Self { + Self(imp::Mutex::new()) } /// Calls raw_lock() and then returns an RAII guard to guarantee the mutex /// will be unlocked. - #[inline] - pub unsafe fn lock(&self) -> MutexGuard<'_> { - self.raw_lock(); - MutexGuard(&self.0) - } - - /// Attempts to lock the mutex without blocking, returning whether it was - /// successfully acquired or not. /// - /// Behavior is undefined if the mutex has been moved between this and any - /// previous function call. + /// It is undefined behaviour to call this function while locked, or if the + /// mutex has been moved since the last time this was called. #[inline] - pub unsafe fn try_lock(&self) -> bool { - self.0.try_lock() + pub unsafe fn lock(&self) -> StaticMutexGuard<'_> { + self.0.lock(); + StaticMutexGuard(&self.0) } - - /// Unlocks the mutex. - /// - /// Behavior is undefined if the current thread does not actually hold the - /// mutex. - /// - /// Consider switching from the pair of raw_lock() and raw_unlock() to - /// lock() whenever possible. - #[inline] - pub unsafe fn raw_unlock(&self) { - self.0.unlock() - } - - /// Deallocates all resources associated with this mutex. - /// - /// Behavior is undefined if there are current or will be future users of - /// this mutex. - #[inline] - pub unsafe fn destroy(&self) { - self.0.destroy() - } -} - -// not meant to be exported to the outside world, just the containing module -pub fn raw(mutex: &Mutex) -> &imp::Mutex { - &mutex.0 } #[must_use] -/// A simple RAII utility for the above Mutex without the poisoning semantics. -pub struct MutexGuard<'a>(&'a imp::Mutex); +pub struct StaticMutexGuard<'a>(&'a imp::Mutex); -impl Drop for MutexGuard<'_> { +impl Drop for StaticMutexGuard<'_> { #[inline] fn drop(&mut self) { unsafe { @@ -99,3 +49,58 @@ impl Drop for MutexGuard<'_> { } } } + +/// An OS-based mutual exclusion lock. +/// +/// This mutex does *not* have a const constructor, cleans up its resources in +/// its `Drop` implementation, may safely be moved (when not borrowed), and +/// does not cause UB when used reentrantly. +/// +/// This mutex does not implement poisoning. +/// +/// This is a wrapper around `Box`, to allow the object to be moved +/// without moving the raw mutex. +pub struct MovableMutex(Box); + +unsafe impl Sync for MovableMutex {} + +impl MovableMutex { + /// Creates a new mutex. + pub fn new() -> Self { + let mut mutex = box imp::Mutex::new(); + unsafe { mutex.init() }; + Self(mutex) + } + + pub(crate) fn raw(&self) -> &imp::Mutex { + &self.0 + } + + /// Locks the mutex blocking the current thread until it is available. + #[inline] + pub fn raw_lock(&self) { + unsafe { self.0.lock() } + } + + /// Attempts to lock the mutex without blocking, returning whether it was + /// successfully acquired or not. + #[inline] + pub fn try_lock(&self) -> bool { + unsafe { self.0.try_lock() } + } + + /// Unlocks the mutex. + /// + /// Behavior is undefined if the current thread does not actually hold the + /// mutex. + #[inline] + pub unsafe fn raw_unlock(&self) { + self.0.unlock() + } +} + +impl Drop for MovableMutex { + fn drop(&mut self) { + unsafe { self.0.destroy() }; + } +} diff --git a/library/std/src/sys_common/net.rs b/library/std/src/sys_common/net.rs index 0bb136078b..48ba4ddfc0 100644 --- a/library/std/src/sys_common/net.rs +++ b/library/std/src/sys_common/net.rs @@ -1,3 +1,6 @@ +#[cfg(test)] +mod tests; + use crate::cmp; use crate::convert::{TryFrom, TryInto}; use crate::ffi::CString; @@ -672,26 +675,3 @@ impl fmt::Debug for UdpSocket { res.field(name, &self.inner.as_inner()).finish() } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::collections::HashMap; - - #[test] - fn no_lookup_host_duplicates() { - let mut addrs = HashMap::new(); - let lh = match LookupHost::try_from(("localhost", 0)) { - Ok(lh) => lh, - Err(e) => panic!("couldn't resolve `localhost': {}", e), - }; - for sa in lh { - *addrs.entry(sa).or_insert(0) += 1; - } - assert_eq!( - addrs.iter().filter(|&(_, &v)| v > 1).collect::>(), - vec![], - "There should be no duplicate localhost entries" - ); - } -} diff --git a/library/std/src/sys_common/net/tests.rs b/library/std/src/sys_common/net/tests.rs new file mode 100644 index 0000000000..7d45621e09 --- /dev/null +++ b/library/std/src/sys_common/net/tests.rs @@ -0,0 +1,19 @@ +use super::*; +use crate::collections::HashMap; + +#[test] +fn no_lookup_host_duplicates() { + let mut addrs = HashMap::new(); + let lh = match LookupHost::try_from(("localhost", 0)) { + Ok(lh) => lh, + Err(e) => panic!("couldn't resolve `localhost': {}", e), + }; + for sa in lh { + *addrs.entry(sa).or_insert(0) += 1; + } + assert_eq!( + addrs.iter().filter(|&(_, &v)| v > 1).collect::>(), + vec![], + "There should be no duplicate localhost entries" + ); +} diff --git a/library/std/src/sys_common/os_str_bytes.rs b/library/std/src/sys_common/os_str_bytes.rs index 984c032e2a..497e5fc7bd 100644 --- a/library/std/src/sys_common/os_str_bytes.rs +++ b/library/std/src/sys_common/os_str_bytes.rs @@ -106,7 +106,7 @@ impl Buf { #[inline] pub fn as_slice(&self) -> &Slice { - // Safety: Slice just wraps [u8], + // SAFETY: Slice just wraps [u8], // and &*self.inner is &[u8], therefore // transmuting &[u8] to &Slice is safe. unsafe { mem::transmute(&*self.inner) } @@ -114,7 +114,7 @@ impl Buf { #[inline] pub fn as_mut_slice(&mut self) -> &mut Slice { - // Safety: Slice just wraps [u8], + // SAFETY: Slice just wraps [u8], // and &mut *self.inner is &mut [u8], therefore // transmuting &mut [u8] to &mut Slice is safe. unsafe { mem::transmute(&mut *self.inner) } @@ -232,23 +232,17 @@ impl Slice { } /// Platform-specific extensions to [`OsString`]. -/// -/// [`OsString`]: ../../../../std/ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStringExt { /// Creates an [`OsString`] from a byte vector. /// /// See the module documentation for an example. - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] fn from_vec(vec: Vec) -> Self; /// Yields the underlying byte vector of this [`OsString`]. /// /// See the module documentation for an example. - /// - /// [`OsString`]: ../../../ffi/struct.OsString.html #[stable(feature = "rust1", since = "1.0.0")] fn into_vec(self) -> Vec; } @@ -264,23 +258,17 @@ impl OsStringExt for OsString { } /// Platform-specific extensions to [`OsStr`]. -/// -/// [`OsStr`]: ../../../../std/ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] pub trait OsStrExt { #[stable(feature = "rust1", since = "1.0.0")] /// Creates an [`OsStr`] from a byte slice. /// /// See the module documentation for an example. - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html fn from_bytes(slice: &[u8]) -> &Self; /// Gets the underlying byte view of the [`OsStr`] slice. /// /// See the module documentation for an example. - /// - /// [`OsStr`]: ../../../ffi/struct.OsStr.html #[stable(feature = "rust1", since = "1.0.0")] fn as_bytes(&self) -> &[u8]; } diff --git a/library/std/src/sys_common/poison.rs b/library/std/src/sys_common/poison.rs index 285851d631..2ab2c700a1 100644 --- a/library/std/src/sys_common/poison.rs +++ b/library/std/src/sys_common/poison.rs @@ -3,6 +3,9 @@ use crate::fmt; use crate::sync::atomic::{AtomicBool, Ordering}; use crate::thread; +#[allow(unused_imports)] // for intra-doc links +use crate::sync::{Mutex, RwLock}; + pub struct Flag { failed: AtomicBool, } @@ -62,7 +65,7 @@ pub struct Guard { /// let mutex = Arc::new(Mutex::new(1)); /// /// // poison the mutex -/// let c_mutex = mutex.clone(); +/// let c_mutex = Arc::clone(&mutex); /// let _ = thread::spawn(move || { /// let mut data = c_mutex.lock().unwrap(); /// *data = 2; @@ -77,9 +80,6 @@ pub struct Guard { /// } /// }; /// ``` -/// -/// [`Mutex`]: ../../std/sync/struct.Mutex.html -/// [`RwLock`]: ../../std/sync/struct.RwLock.html #[stable(feature = "rust1", since = "1.0.0")] pub struct PoisonError { guard: T, @@ -89,12 +89,9 @@ pub struct PoisonError { /// can occur while trying to acquire a lock, from the [`try_lock`] method on a /// [`Mutex`] or the [`try_read`] and [`try_write`] methods on an [`RwLock`]. /// -/// [`Mutex`]: struct.Mutex.html -/// [`RwLock`]: struct.RwLock.html -/// [`TryLockResult`]: type.TryLockResult.html -/// [`try_lock`]: struct.Mutex.html#method.try_lock -/// [`try_read`]: struct.RwLock.html#method.try_read -/// [`try_write`]: struct.RwLock.html#method.try_write +/// [`try_lock`]: Mutex::try_lock +/// [`try_read`]: RwLock::try_read +/// [`try_write`]: RwLock::try_write #[stable(feature = "rust1", since = "1.0.0")] pub enum TryLockError { /// The lock could not be acquired because another thread failed while holding @@ -115,9 +112,7 @@ pub enum TryLockError { /// the associated guard, and it can be acquired through the [`into_inner`] /// method. /// -/// [`Ok`]: ../../std/result/enum.Result.html#variant.Ok -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err -/// [`into_inner`]: ../../std/sync/struct.PoisonError.html#method.into_inner +/// [`into_inner`]: PoisonError::into_inner #[stable(feature = "rust1", since = "1.0.0")] pub type LockResult = Result>; @@ -126,9 +121,6 @@ pub type LockResult = Result>; /// For more information, see [`LockResult`]. A `TryLockResult` doesn't /// necessarily hold the associated guard in the [`Err`] type as the lock may not /// have been acquired for other reasons. -/// -/// [`LockResult`]: ../../std/sync/type.LockResult.html -/// [`Err`]: ../../std/result/enum.Result.html#variant.Err #[stable(feature = "rust1", since = "1.0.0")] pub type TryLockResult = Result>; @@ -158,9 +150,6 @@ impl PoisonError { /// Creates a `PoisonError`. /// /// This is generally created by methods like [`Mutex::lock`] or [`RwLock::read`]. - /// - /// [`Mutex::lock`]: ../../std/sync/struct.Mutex.html#method.lock - /// [`RwLock::read`]: ../../std/sync/struct.RwLock.html#method.read #[stable(feature = "sync_poison", since = "1.2.0")] pub fn new(guard: T) -> PoisonError { PoisonError { guard } @@ -179,7 +168,7 @@ impl PoisonError { /// let mutex = Arc::new(Mutex::new(HashSet::new())); /// /// // poison the mutex - /// let c_mutex = mutex.clone(); + /// let c_mutex = Arc::clone(&mutex); /// let _ = thread::spawn(move || { /// let mut data = c_mutex.lock().unwrap(); /// data.insert(10); diff --git a/library/std/src/sys_common/process.rs b/library/std/src/sys_common/process.rs index f3a2962098..fe89b11043 100644 --- a/library/std/src/sys_common/process.rs +++ b/library/std/src/sys_common/process.rs @@ -92,4 +92,41 @@ impl CommandEnv { self.saw_path = true; } } + + pub fn iter(&self) -> CommandEnvs<'_> { + let iter = self.vars.iter(); + CommandEnvs { iter } + } +} + +/// An iterator over the command environment variables. +/// +/// This struct is created by +/// [`Command::get_envs`][crate::process::Command::get_envs]. See its +/// documentation for more. +#[unstable(feature = "command_access", issue = "44434")] +#[derive(Debug)] +pub struct CommandEnvs<'a> { + iter: crate::collections::btree_map::Iter<'a, EnvKey, Option>, +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> Iterator for CommandEnvs<'a> { + type Item = (&'a OsStr, Option<&'a OsStr>); + fn next(&mut self) -> Option { + self.iter.next().map(|(key, value)| (key.as_ref(), value.as_deref())) + } + fn size_hint(&self) -> (usize, Option) { + self.iter.size_hint() + } +} + +#[unstable(feature = "command_access", issue = "44434")] +impl<'a> ExactSizeIterator for CommandEnvs<'a> { + fn len(&self) -> usize { + self.iter.len() + } + fn is_empty(&self) -> bool { + self.iter.is_empty() + } } diff --git a/library/std/src/sys_common/remutex.rs b/library/std/src/sys_common/remutex.rs index 4f19bbc467..162eab2388 100644 --- a/library/std/src/sys_common/remutex.rs +++ b/library/std/src/sys_common/remutex.rs @@ -1,3 +1,6 @@ +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + use crate::fmt; use crate::marker; use crate::ops::Deref; @@ -34,9 +37,7 @@ impl RefUnwindSafe for ReentrantMutex {} /// guarded data. #[must_use = "if unused the ReentrantMutex will immediately unlock"] pub struct ReentrantMutexGuard<'a, T: 'a> { - // funny underscores due to how Deref currently works (it disregards field - // privacy). - __lock: &'a ReentrantMutex, + lock: &'a ReentrantMutex, } impl !marker::Send for ReentrantMutexGuard<'_, T> {} @@ -126,7 +127,7 @@ impl fmt::Debug for ReentrantMutex { impl<'mutex, T> ReentrantMutexGuard<'mutex, T> { fn new(lock: &'mutex ReentrantMutex) -> ReentrantMutexGuard<'mutex, T> { - ReentrantMutexGuard { __lock: lock } + ReentrantMutexGuard { lock } } } @@ -134,7 +135,7 @@ impl Deref for ReentrantMutexGuard<'_, T> { type Target = T; fn deref(&self) -> &T { - &self.__lock.data + &self.lock.data } } @@ -142,83 +143,7 @@ impl Drop for ReentrantMutexGuard<'_, T> { #[inline] fn drop(&mut self) { unsafe { - self.__lock.inner.unlock(); - } - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::cell::RefCell; - use crate::sync::Arc; - use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; - use crate::thread; - - #[test] - fn smoke() { - let m = unsafe { - let m = ReentrantMutex::new(()); - m.init(); - m - }; - { - let a = m.lock(); - { - let b = m.lock(); - { - let c = m.lock(); - assert_eq!(*c, ()); - } - assert_eq!(*b, ()); - } - assert_eq!(*a, ()); - } - } - - #[test] - fn is_mutex() { - let m = unsafe { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - m.init(); - m - }; - let m2 = m.clone(); - let lock = m.lock(); - let child = thread::spawn(move || { - let lock = m2.lock(); - assert_eq!(*lock.borrow(), 4950); - }); - for i in 0..100 { - let lock = m.lock(); - *lock.borrow_mut() += i; - } - drop(lock); - child.join().unwrap(); - } - - #[test] - fn trylock_works() { - let m = unsafe { - let m = Arc::new(ReentrantMutex::new(())); - m.init(); - m - }; - let m2 = m.clone(); - let _lock = m.try_lock(); - let _lock2 = m.try_lock(); - thread::spawn(move || { - let lock = m2.try_lock(); - assert!(lock.is_none()); - }) - .join() - .unwrap(); - let _lock3 = m.try_lock(); - } - - pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); - impl Drop for Answer<'_> { - fn drop(&mut self) { - *self.0.borrow_mut() = 42; + self.lock.inner.unlock(); } } } diff --git a/library/std/src/sys_common/remutex/tests.rs b/library/std/src/sys_common/remutex/tests.rs new file mode 100644 index 0000000000..9c686e579d --- /dev/null +++ b/library/std/src/sys_common/remutex/tests.rs @@ -0,0 +1,72 @@ +use crate::cell::RefCell; +use crate::sync::Arc; +use crate::sys_common::remutex::{ReentrantMutex, ReentrantMutexGuard}; +use crate::thread; + +#[test] +fn smoke() { + let m = unsafe { + let m = ReentrantMutex::new(()); + m.init(); + m + }; + { + let a = m.lock(); + { + let b = m.lock(); + { + let c = m.lock(); + assert_eq!(*c, ()); + } + assert_eq!(*b, ()); + } + assert_eq!(*a, ()); + } +} + +#[test] +fn is_mutex() { + let m = unsafe { + let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); + m.init(); + m + }; + let m2 = m.clone(); + let lock = m.lock(); + let child = thread::spawn(move || { + let lock = m2.lock(); + assert_eq!(*lock.borrow(), 4950); + }); + for i in 0..100 { + let lock = m.lock(); + *lock.borrow_mut() += i; + } + drop(lock); + child.join().unwrap(); +} + +#[test] +fn trylock_works() { + let m = unsafe { + let m = Arc::new(ReentrantMutex::new(())); + m.init(); + m + }; + let m2 = m.clone(); + let _lock = m.try_lock(); + let _lock2 = m.try_lock(); + thread::spawn(move || { + let lock = m2.try_lock(); + assert!(lock.is_none()); + }) + .join() + .unwrap(); + let _lock3 = m.try_lock(); +} + +pub struct Answer<'a>(pub ReentrantMutexGuard<'a, RefCell>); +impl Drop for Answer<'_> { + fn drop(&mut self) { + *self.0.borrow_mut() = 42; + } +} diff --git a/library/std/src/sys_common/tests.rs b/library/std/src/sys_common/tests.rs new file mode 100644 index 0000000000..1b6446db52 --- /dev/null +++ b/library/std/src/sys_common/tests.rs @@ -0,0 +1,6 @@ +use super::mul_div_u64; + +#[test] +fn test_muldiv() { + assert_eq!(mul_div_u64(1_000_000_000_001, 1_000_000_000, 1_000_000), 1_000_000_000_001_000); +} diff --git a/library/std/src/sys_common/thread_local_key.rs b/library/std/src/sys_common/thread_local_key.rs index ac5b128298..dbcb7b3626 100644 --- a/library/std/src/sys_common/thread_local_key.rs +++ b/library/std/src/sys_common/thread_local_key.rs @@ -48,9 +48,12 @@ #![unstable(feature = "thread_local_internals", issue = "none")] #![allow(dead_code)] // sys isn't exported yet +#[cfg(test)] +mod tests; + use crate::sync::atomic::{self, AtomicUsize, Ordering}; use crate::sys::thread_local_key as imp; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; /// A type for TLS keys that are statically allocated. /// @@ -114,6 +117,7 @@ pub struct Key { pub const INIT: StaticKey = StaticKey::new(None); impl StaticKey { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new(dtor: Option) -> StaticKey { StaticKey { key: atomic::AtomicUsize::new(0), dtor } } @@ -153,7 +157,7 @@ impl StaticKey { if imp::requires_synchronized_create() { // We never call `INIT_LOCK.init()`, so it is UB to attempt to // acquire this mutex reentrantly! - static INIT_LOCK: Mutex = Mutex::new(); + static INIT_LOCK: StaticMutex = StaticMutex::new(); let _guard = INIT_LOCK.lock(); let mut key = self.key.load(Ordering::SeqCst); if key == 0 { @@ -231,41 +235,3 @@ impl Drop for Key { // unsafe { imp::destroy(self.key) } } } - -#[cfg(test)] -mod tests { - use super::{Key, StaticKey}; - - fn assert_sync() {} - fn assert_send() {} - - #[test] - fn smoke() { - assert_sync::(); - assert_send::(); - - let k1 = Key::new(None); - let k2 = Key::new(None); - assert!(k1.get().is_null()); - assert!(k2.get().is_null()); - k1.set(1 as *mut _); - k2.set(2 as *mut _); - assert_eq!(k1.get() as usize, 1); - assert_eq!(k2.get() as usize, 2); - } - - #[test] - fn statik() { - static K1: StaticKey = StaticKey::new(None); - static K2: StaticKey = StaticKey::new(None); - - unsafe { - assert!(K1.get().is_null()); - assert!(K2.get().is_null()); - K1.set(1 as *mut _); - K2.set(2 as *mut _); - assert_eq!(K1.get() as usize, 1); - assert_eq!(K2.get() as usize, 2); - } - } -} diff --git a/library/std/src/sys_common/thread_local_key/tests.rs b/library/std/src/sys_common/thread_local_key/tests.rs new file mode 100644 index 0000000000..968738a418 --- /dev/null +++ b/library/std/src/sys_common/thread_local_key/tests.rs @@ -0,0 +1,34 @@ +use super::{Key, StaticKey}; + +fn assert_sync() {} +fn assert_send() {} + +#[test] +fn smoke() { + assert_sync::(); + assert_send::(); + + let k1 = Key::new(None); + let k2 = Key::new(None); + assert!(k1.get().is_null()); + assert!(k2.get().is_null()); + k1.set(1 as *mut _); + k2.set(2 as *mut _); + assert_eq!(k1.get() as usize, 1); + assert_eq!(k2.get() as usize, 2); +} + +#[test] +fn statik() { + static K1: StaticKey = StaticKey::new(None); + static K2: StaticKey = StaticKey::new(None); + + unsafe { + assert!(K1.get().is_null()); + assert!(K2.get().is_null()); + K1.set(1 as *mut _); + K2.set(2 as *mut _); + assert_eq!(K1.get() as usize, 1); + assert_eq!(K2.get() as usize, 2); + } +} diff --git a/library/std/src/sys_common/thread_parker/futex.rs b/library/std/src/sys_common/thread_parker/futex.rs new file mode 100644 index 0000000000..a5d4927dcc --- /dev/null +++ b/library/std/src/sys_common/thread_parker/futex.rs @@ -0,0 +1,93 @@ +use crate::sync::atomic::AtomicI32; +use crate::sync::atomic::Ordering::{Acquire, Release}; +use crate::sys::futex::{futex_wait, futex_wake}; +use crate::time::Duration; + +const PARKED: i32 = -1; +const EMPTY: i32 = 0; +const NOTIFIED: i32 = 1; + +pub struct Parker { + state: AtomicI32, +} + +// Notes about memory ordering: +// +// Memory ordering is only relevant for the relative ordering of operations +// between different variables. Even Ordering::Relaxed guarantees a +// monotonic/consistent order when looking at just a single atomic variable. +// +// So, since this parker is just a single atomic variable, we only need to look +// at the ordering guarantees we need to provide to the 'outside world'. +// +// The only memory ordering guarantee that parking and unparking provide, is +// that things which happened before unpark() are visible on the thread +// returning from park() afterwards. Otherwise, it was effectively unparked +// before unpark() was called while still consuming the 'token'. +// +// In other words, unpark() needs to synchronize with the part of park() that +// consumes the token and returns. +// +// This is done with a release-acquire synchronization, by using +// Ordering::Release when writing NOTIFIED (the 'token') in unpark(), and using +// Ordering::Acquire when checking for this state in park(). +impl Parker { + #[inline] + pub const fn new() -> Self { + Parker { state: AtomicI32::new(EMPTY) } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park(&self) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + loop { + // Wait for something to happen, assuming it's still set to PARKED. + futex_wait(&self.state, PARKED, None); + // Change NOTIFIED=>EMPTY and return in that case. + if self.state.compare_and_swap(NOTIFIED, EMPTY, Acquire) == NOTIFIED { + return; + } else { + // Spurious wake up. We loop to try again. + } + } + } + + // Assumes this is only called by the thread that owns the Parker, + // which means that `self.state != PARKED`. + pub unsafe fn park_timeout(&self, timeout: Duration) { + // Change NOTIFIED=>EMPTY or EMPTY=>PARKED, and directly return in the + // first case. + if self.state.fetch_sub(1, Acquire) == NOTIFIED { + return; + } + // Wait for something to happen, assuming it's still set to PARKED. + futex_wait(&self.state, PARKED, Some(timeout)); + // This is not just a store, because we need to establish a + // release-acquire ordering with unpark(). + if self.state.swap(EMPTY, Acquire) == NOTIFIED { + // Woke up because of unpark(). + } else { + // Timeout or spurious wake up. + // We return either way, because we can't easily tell if it was the + // timeout or not. + } + } + + #[inline] + pub fn unpark(&self) { + // Change PARKED=>NOTIFIED, EMPTY=>NOTIFIED, or NOTIFIED=>NOTIFIED, and + // wake the thread in the first case. + // + // Note that even NOTIFIED=>NOTIFIED results in a write. This is on + // purpose, to make sure every unpark() has a release-acquire ordering + // with park(). + if self.state.swap(NOTIFIED, Release) == PARKED { + futex_wake(&self.state); + } + } +} diff --git a/library/std/src/sys_common/thread_parker/generic.rs b/library/std/src/sys_common/thread_parker/generic.rs new file mode 100644 index 0000000000..14cfa958e5 --- /dev/null +++ b/library/std/src/sys_common/thread_parker/generic.rs @@ -0,0 +1,119 @@ +//! Parker implementaiton based on a Mutex and Condvar. + +use crate::sync::atomic::AtomicUsize; +use crate::sync::atomic::Ordering::SeqCst; +use crate::sync::{Condvar, Mutex}; +use crate::time::Duration; + +const EMPTY: usize = 0; +const PARKED: usize = 1; +const NOTIFIED: usize = 2; + +pub struct Parker { + state: AtomicUsize, + lock: Mutex<()>, + cvar: Condvar, +} + +impl Parker { + pub fn new() -> Self { + Parker { state: AtomicUsize::new(EMPTY), lock: Mutex::new(()), cvar: Condvar::new() } + } + + // This implementaiton doesn't require `unsafe`, but other implementations + // may assume this is only called by the thread that owns the Parker. + pub unsafe fn park(&self) { + // If we were previously notified then we consume this notification and + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + + // Otherwise we need to coordinate going to sleep + let mut m = self.lock.lock().unwrap(); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read here, even though we know it will be `NOTIFIED`. + // This is because `unpark` may have been called again since we read + // `NOTIFIED` in the `compare_exchange` above. We must perform an + // acquire operation that synchronizes with that `unpark` to observe + // any writes it made before the call to unpark. To do that we must + // read from the write it made to `state`. + let old = self.state.swap(EMPTY, SeqCst); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => panic!("inconsistent park state"), + } + loop { + m = self.cvar.wait(m).unwrap(); + match self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { + Ok(_) => return, // got a notification + Err(_) => {} // spurious wakeup, go back to sleep + } + } + } + + // This implementaiton doesn't require `unsafe`, but other implementations + // may assume this is only called by the thread that owns the Parker. + pub unsafe fn park_timeout(&self, dur: Duration) { + // Like `park` above we have a fast path for an already-notified thread, and + // afterwards we start coordinating for a sleep. + // return quickly. + if self.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { + return; + } + let m = self.lock.lock().unwrap(); + match self.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { + Ok(_) => {} + Err(NOTIFIED) => { + // We must read again here, see `park`. + let old = self.state.swap(EMPTY, SeqCst); + assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); + return; + } // should consume this notification, so prohibit spurious wakeups in next park. + Err(_) => panic!("inconsistent park_timeout state"), + } + + // Wait with a timeout, and if we spuriously wake up or otherwise wake up + // from a notification we just want to unconditionally set the state back to + // empty, either consuming a notification or un-flagging ourselves as + // parked. + let (_m, _result) = self.cvar.wait_timeout(m, dur).unwrap(); + match self.state.swap(EMPTY, SeqCst) { + NOTIFIED => {} // got a notification, hurray! + PARKED => {} // no notification, alas + n => panic!("inconsistent park_timeout state: {}", n), + } + } + + pub fn unpark(&self) { + // To ensure the unparked thread will observe any writes we made + // before this call, we must perform a release operation that `park` + // can synchronize with. To do that we must write `NOTIFIED` even if + // `state` is already `NOTIFIED`. That is why this must be a swap + // rather than a compare-and-swap that returns if it reads `NOTIFIED` + // on failure. + match self.state.swap(NOTIFIED, SeqCst) { + EMPTY => return, // no one was waiting + NOTIFIED => return, // already unparked + PARKED => {} // gotta go wake someone up + _ => panic!("inconsistent state in unpark"), + } + + // There is a period between when the parked thread sets `state` to + // `PARKED` (or last checked `state` in the case of a spurious wake + // up) and when it actually waits on `cvar`. If we were to notify + // during this period it would be ignored and then when the parked + // thread went to sleep it would never wake up. Fortunately, it has + // `lock` locked at this stage so we can acquire `lock` to wait until + // it is ready to receive the notification. + // + // Releasing `lock` before the call to `notify_one` means that when the + // parked thread wakes it doesn't get woken only to have to wait for us + // to release `lock`. + drop(self.lock.lock().unwrap()); + self.cvar.notify_one() + } +} diff --git a/library/std/src/sys_common/thread_parker/mod.rs b/library/std/src/sys_common/thread_parker/mod.rs new file mode 100644 index 0000000000..23c17c8e2c --- /dev/null +++ b/library/std/src/sys_common/thread_parker/mod.rs @@ -0,0 +1,9 @@ +cfg_if::cfg_if! { + if #[cfg(any(target_os = "linux", target_os = "android"))] { + mod futex; + pub use futex::Parker; + } else { + mod generic; + pub use generic::Parker; + } +} diff --git a/library/std/src/sys_common/wtf8.rs b/library/std/src/sys_common/wtf8.rs index bdb6a05464..7d4b0d5283 100644 --- a/library/std/src/sys_common/wtf8.rs +++ b/library/std/src/sys_common/wtf8.rs @@ -15,6 +15,9 @@ // unix (it's mostly used on windows), so don't worry about dead code here. #![allow(dead_code)] +#[cfg(test)] +mod tests; + use core::str::next_code_point; use crate::borrow::Cow; @@ -879,407 +882,3 @@ impl Hash for Wtf8 { 0xfeu8.hash(state) } } - -#[cfg(test)] -mod tests { - use super::*; - use crate::borrow::Cow; - - #[test] - fn code_point_from_u32() { - assert!(CodePoint::from_u32(0).is_some()); - assert!(CodePoint::from_u32(0xD800).is_some()); - assert!(CodePoint::from_u32(0x10FFFF).is_some()); - assert!(CodePoint::from_u32(0x110000).is_none()); - } - - #[test] - fn code_point_to_u32() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0).to_u32(), 0); - assert_eq!(c(0xD800).to_u32(), 0xD800); - assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); - } - - #[test] - fn code_point_from_char() { - assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); - assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9); - } - - #[test] - fn code_point_to_string() { - assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061"); - assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9"); - } - - #[test] - fn code_point_to_char() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0x61).to_char(), Some('a')); - assert_eq!(c(0x1F4A9).to_char(), Some('💩')); - assert_eq!(c(0xD800).to_char(), None); - } - - #[test] - fn code_point_to_char_lossy() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - assert_eq!(c(0x61).to_char_lossy(), 'a'); - assert_eq!(c(0x1F4A9).to_char_lossy(), '💩'); - assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}'); - } - - #[test] - fn wtf8buf_new() { - assert_eq!(Wtf8Buf::new().bytes, b""); - } - - #[test] - fn wtf8buf_from_str() { - assert_eq!(Wtf8Buf::from_str("").bytes, b""); - assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_from_string() { - assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); - assert_eq!( - Wtf8Buf::from_string(String::from("aé 💩")).bytes, - b"a\xC3\xA9 \xF0\x9F\x92\xA9" - ); - } - - #[test] - fn wtf8buf_from_wide() { - assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b""); - assert_eq!( - Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes, - b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9" - ); - } - - #[test] - fn wtf8buf_push_str() { - let mut string = Wtf8Buf::new(); - assert_eq!(string.bytes, b""); - string.push_str("aé 💩"); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_push_char() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - string.push_char('💩'); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8buf_push() { - let mut string = Wtf8Buf::from_str("aé "); - assert_eq!(string.bytes, b"a\xC3\xA9 "); - string.push(CodePoint::from_char('💩')); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - - let mut string = Wtf8Buf::new(); - string.push(c(0xD83D)); // lead - string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! - - let mut string = Wtf8Buf::new(); - string.push(c(0xD83D)); // lead - string.push(c(0x20)); // not surrogate - string.push(c(0xDCA9)); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD800)); // lead - string.push(c(0xDBFF)); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD800)); // lead - string.push(c(0xE000)); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xD7FF)); // not surrogate - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0x61)); // not surrogate, < 3 bytes - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push(c(0xDC00)); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_push_wtf8() { - let mut string = Wtf8Buf::from_str("aé"); - assert_eq!(string.bytes, b"a\xC3\xA9"); - string.push_wtf8(Wtf8::from_str(" 💩")); - assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - fn w(v: &[u8]) -> &Wtf8 { - unsafe { Wtf8::from_bytes_unchecked(v) } - } - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\xBD")); // lead - string.push_wtf8(w(b" ")); // not surrogate - string.push_wtf8(w(b"\xED\xB2\xA9")); // trail - assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\x80")); // lead - string.push_wtf8(w(b"\xED\xAF\xBF")); // lead - assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xA0\x80")); // lead - string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate - assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); - - let mut string = Wtf8Buf::new(); - string.push_wtf8(w(b"\xED\xB0\x80")); // trail - assert_eq!(string.bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_truncate() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(1); - assert_eq!(string.bytes, b"a"); - } - - #[test] - #[should_panic] - fn wtf8buf_truncate_fail_code_point_boundary() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(2); - } - - #[test] - #[should_panic] - fn wtf8buf_truncate_fail_longer() { - let mut string = Wtf8Buf::from_str("aé"); - string.truncate(4); - } - - #[test] - fn wtf8buf_into_string() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.clone().into_string(), Err(string)); - } - - #[test] - fn wtf8buf_into_string_lossy() { - let mut string = Wtf8Buf::from_str("aé 💩"); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩")); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�")); - } - - #[test] - fn wtf8buf_from_iterator() { - fn f(values: &[u32]) -> Wtf8Buf { - values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() - } - assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); - assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80"); - assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_extend() { - fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf { - fn c(value: &u32) -> CodePoint { - CodePoint::from_u32(*value).unwrap() - } - let mut string = initial.iter().map(c).collect::(); - string.extend(extended.iter().map(c)); - string - } - - assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - - assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! - assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); - assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); - assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); - assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); - assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80"); - assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80"); - } - - #[test] - fn wtf8buf_show() { - let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); - } - - #[test] - fn wtf8buf_as_slice() { - assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé")); - } - - #[test] - fn wtf8buf_show_str() { - let text = "a\té 💩\r"; - let string = Wtf8Buf::from_str(text); - assert_eq!(format!("{:?}", text), format!("{:?}", string)); - } - - #[test] - fn wtf8_from_str() { - assert_eq!(&Wtf8::from_str("").bytes, b""); - assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - fn wtf8_len() { - assert_eq!(Wtf8::from_str("").len(), 0); - assert_eq!(Wtf8::from_str("aé 💩").len(), 8); - } - - #[test] - fn wtf8_slice() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 "); - } - - #[test] - #[should_panic] - fn wtf8_slice_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2..4]; - } - - #[test] - fn wtf8_slice_from() { - assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); - } - - #[test] - #[should_panic] - fn wtf8_slice_from_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[2..]; - } - - #[test] - fn wtf8_slice_to() { - assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); - } - - #[test] - #[should_panic] - fn wtf8_slice_to_not_code_point_boundary() { - &Wtf8::from_str("aé 💩")[5..]; - } - - #[test] - fn wtf8_ascii_byte_at() { - let slice = Wtf8::from_str("aé 💩"); - assert_eq!(slice.ascii_byte_at(0), b'a'); - assert_eq!(slice.ascii_byte_at(1), b'\xFF'); - assert_eq!(slice.ascii_byte_at(2), b'\xFF'); - assert_eq!(slice.ascii_byte_at(3), b' '); - assert_eq!(slice.ascii_byte_at(4), b'\xFF'); - } - - #[test] - fn wtf8_code_points() { - fn c(value: u32) -> CodePoint { - CodePoint::from_u32(value).unwrap() - } - fn cp(string: &Wtf8Buf) -> Vec> { - string.code_points().map(|c| c.to_char()).collect::>() - } - let mut string = Wtf8Buf::from_str("é "); - assert_eq!(cp(&string), [Some('é'), Some(' ')]); - string.push(c(0xD83D)); - assert_eq!(cp(&string), [Some('é'), Some(' '), None]); - string.push(c(0xDCA9)); - assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]); - } - - #[test] - fn wtf8_as_str() { - assert_eq!(Wtf8::from_str("").as_str(), Some("")); - assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩")); - let mut string = Wtf8Buf::new(); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!(string.as_str(), None); - } - - #[test] - fn wtf8_to_string_lossy() { - assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); - assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); - assert_eq!(string.to_string_lossy(), expected); - } - - #[test] - fn wtf8_display() { - fn d(b: &[u8]) -> String { - (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() - } - - assert_eq!("", d("".as_bytes())); - assert_eq!("aé 💩", d("aé 💩".as_bytes())); - - let mut string = Wtf8Buf::from_str("aé 💩"); - string.push(CodePoint::from_u32(0xD800).unwrap()); - assert_eq!("aé 💩�", d(string.as_inner())); - } - - #[test] - fn wtf8_encode_wide() { - let mut string = Wtf8Buf::from_str("aé "); - string.push(CodePoint::from_u32(0xD83D).unwrap()); - string.push_char('💩'); - assert_eq!( - string.encode_wide().collect::>(), - vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] - ); - } -} diff --git a/library/std/src/sys_common/wtf8/tests.rs b/library/std/src/sys_common/wtf8/tests.rs new file mode 100644 index 0000000000..385e01f92f --- /dev/null +++ b/library/std/src/sys_common/wtf8/tests.rs @@ -0,0 +1,397 @@ +use super::*; +use crate::borrow::Cow; + +#[test] +fn code_point_from_u32() { + assert!(CodePoint::from_u32(0).is_some()); + assert!(CodePoint::from_u32(0xD800).is_some()); + assert!(CodePoint::from_u32(0x10FFFF).is_some()); + assert!(CodePoint::from_u32(0x110000).is_none()); +} + +#[test] +fn code_point_to_u32() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0).to_u32(), 0); + assert_eq!(c(0xD800).to_u32(), 0xD800); + assert_eq!(c(0x10FFFF).to_u32(), 0x10FFFF); +} + +#[test] +fn code_point_from_char() { + assert_eq!(CodePoint::from_char('a').to_u32(), 0x61); + assert_eq!(CodePoint::from_char('💩').to_u32(), 0x1F4A9); +} + +#[test] +fn code_point_to_string() { + assert_eq!(format!("{:?}", CodePoint::from_char('a')), "U+0061"); + assert_eq!(format!("{:?}", CodePoint::from_char('💩')), "U+1F4A9"); +} + +#[test] +fn code_point_to_char() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0x61).to_char(), Some('a')); + assert_eq!(c(0x1F4A9).to_char(), Some('💩')); + assert_eq!(c(0xD800).to_char(), None); +} + +#[test] +fn code_point_to_char_lossy() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + assert_eq!(c(0x61).to_char_lossy(), 'a'); + assert_eq!(c(0x1F4A9).to_char_lossy(), '💩'); + assert_eq!(c(0xD800).to_char_lossy(), '\u{FFFD}'); +} + +#[test] +fn wtf8buf_new() { + assert_eq!(Wtf8Buf::new().bytes, b""); +} + +#[test] +fn wtf8buf_from_str() { + assert_eq!(Wtf8Buf::from_str("").bytes, b""); + assert_eq!(Wtf8Buf::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_from_string() { + assert_eq!(Wtf8Buf::from_string(String::from("")).bytes, b""); + assert_eq!(Wtf8Buf::from_string(String::from("aé 💩")).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_from_wide() { + assert_eq!(Wtf8Buf::from_wide(&[]).bytes, b""); + assert_eq!( + Wtf8Buf::from_wide(&[0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9]).bytes, + b"a\xC3\xA9 \xED\xA0\xBD\xF0\x9F\x92\xA9" + ); +} + +#[test] +fn wtf8buf_push_str() { + let mut string = Wtf8Buf::new(); + assert_eq!(string.bytes, b""); + string.push_str("aé 💩"); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_push_char() { + let mut string = Wtf8Buf::from_str("aé "); + assert_eq!(string.bytes, b"a\xC3\xA9 "); + string.push_char('💩'); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8buf_push() { + let mut string = Wtf8Buf::from_str("aé "); + assert_eq!(string.bytes, b"a\xC3\xA9 "); + string.push(CodePoint::from_char('💩')); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + + let mut string = Wtf8Buf::new(); + string.push(c(0xD83D)); // lead + string.push(c(0xDCA9)); // trail + assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! + + let mut string = Wtf8Buf::new(); + string.push(c(0xD83D)); // lead + string.push(c(0x20)); // not surrogate + string.push(c(0xDCA9)); // trail + assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xD800)); // lead + string.push(c(0xDBFF)); // lead + assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xD800)); // lead + string.push(c(0xE000)); // not surrogate + assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xD7FF)); // not surrogate + string.push(c(0xDC00)); // trail + assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0x61)); // not surrogate, < 3 bytes + string.push(c(0xDC00)); // trail + assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push(c(0xDC00)); // trail + assert_eq!(string.bytes, b"\xED\xB0\x80"); +} + +#[test] +fn wtf8buf_push_wtf8() { + let mut string = Wtf8Buf::from_str("aé"); + assert_eq!(string.bytes, b"a\xC3\xA9"); + string.push_wtf8(Wtf8::from_str(" 💩")); + assert_eq!(string.bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + + fn w(v: &[u8]) -> &Wtf8 { + unsafe { Wtf8::from_bytes_unchecked(v) } + } + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\xBD")); // lead + string.push_wtf8(w(b"\xED\xB2\xA9")); // trail + assert_eq!(string.bytes, b"\xF0\x9F\x92\xA9"); // Magic! + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\xBD")); // lead + string.push_wtf8(w(b" ")); // not surrogate + string.push_wtf8(w(b"\xED\xB2\xA9")); // trail + assert_eq!(string.bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\x80")); // lead + string.push_wtf8(w(b"\xED\xAF\xBF")); // lead + assert_eq!(string.bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xA0\x80")); // lead + string.push_wtf8(w(b"\xEE\x80\x80")); // not surrogate + assert_eq!(string.bytes, b"\xED\xA0\x80\xEE\x80\x80"); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\x9F\xBF")); // not surrogate + string.push_wtf8(w(b"\xED\xB0\x80")); // trail + assert_eq!(string.bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"a")); // not surrogate, < 3 bytes + string.push_wtf8(w(b"\xED\xB0\x80")); // trail + assert_eq!(string.bytes, b"\x61\xED\xB0\x80"); + + let mut string = Wtf8Buf::new(); + string.push_wtf8(w(b"\xED\xB0\x80")); // trail + assert_eq!(string.bytes, b"\xED\xB0\x80"); +} + +#[test] +fn wtf8buf_truncate() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(1); + assert_eq!(string.bytes, b"a"); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_fail_code_point_boundary() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(2); +} + +#[test] +#[should_panic] +fn wtf8buf_truncate_fail_longer() { + let mut string = Wtf8Buf::from_str("aé"); + string.truncate(4); +} + +#[test] +fn wtf8buf_into_string() { + let mut string = Wtf8Buf::from_str("aé 💩"); + assert_eq!(string.clone().into_string(), Ok(String::from("aé 💩"))); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(string.clone().into_string(), Err(string)); +} + +#[test] +fn wtf8buf_into_string_lossy() { + let mut string = Wtf8Buf::from_str("aé 💩"); + assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩")); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(string.clone().into_string_lossy(), String::from("aé 💩�")); +} + +#[test] +fn wtf8buf_from_iterator() { + fn f(values: &[u32]) -> Wtf8Buf { + values.iter().map(|&c| CodePoint::from_u32(c).unwrap()).collect::() + } + assert_eq!(f(&[0x61, 0xE9, 0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + + assert_eq!(f(&[0xD83D, 0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!(f(&[0xD83D, 0x20, 0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + assert_eq!(f(&[0xD800, 0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + assert_eq!(f(&[0xD800, 0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); + assert_eq!(f(&[0xD7FF, 0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + assert_eq!(f(&[0x61, 0xDC00]).bytes, b"\x61\xED\xB0\x80"); + assert_eq!(f(&[0xDC00]).bytes, b"\xED\xB0\x80"); +} + +#[test] +fn wtf8buf_extend() { + fn e(initial: &[u32], extended: &[u32]) -> Wtf8Buf { + fn c(value: &u32) -> CodePoint { + CodePoint::from_u32(*value).unwrap() + } + let mut string = initial.iter().map(c).collect::(); + string.extend(extended.iter().map(c)); + string + } + + assert_eq!(e(&[0x61, 0xE9], &[0x20, 0x1F4A9]).bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); + + assert_eq!(e(&[0xD83D], &[0xDCA9]).bytes, b"\xF0\x9F\x92\xA9"); // Magic! + assert_eq!(e(&[0xD83D, 0x20], &[0xDCA9]).bytes, b"\xED\xA0\xBD \xED\xB2\xA9"); + assert_eq!(e(&[0xD800], &[0xDBFF]).bytes, b"\xED\xA0\x80\xED\xAF\xBF"); + assert_eq!(e(&[0xD800], &[0xE000]).bytes, b"\xED\xA0\x80\xEE\x80\x80"); + assert_eq!(e(&[0xD7FF], &[0xDC00]).bytes, b"\xED\x9F\xBF\xED\xB0\x80"); + assert_eq!(e(&[0x61], &[0xDC00]).bytes, b"\x61\xED\xB0\x80"); + assert_eq!(e(&[], &[0xDC00]).bytes, b"\xED\xB0\x80"); +} + +#[test] +fn wtf8buf_show() { + let mut string = Wtf8Buf::from_str("a\té \u{7f}💩\r"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(format!("{:?}", string), "\"a\\té \\u{7f}\u{1f4a9}\\r\\u{d800}\""); +} + +#[test] +fn wtf8buf_as_slice() { + assert_eq!(Wtf8Buf::from_str("aé").as_slice(), Wtf8::from_str("aé")); +} + +#[test] +fn wtf8buf_show_str() { + let text = "a\té 💩\r"; + let string = Wtf8Buf::from_str(text); + assert_eq!(format!("{:?}", text), format!("{:?}", string)); +} + +#[test] +fn wtf8_from_str() { + assert_eq!(&Wtf8::from_str("").bytes, b""); + assert_eq!(&Wtf8::from_str("aé 💩").bytes, b"a\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +fn wtf8_len() { + assert_eq!(Wtf8::from_str("").len(), 0); + assert_eq!(Wtf8::from_str("aé 💩").len(), 8); +} + +#[test] +fn wtf8_slice() { + assert_eq!(&Wtf8::from_str("aé 💩")[1..4].bytes, b"\xC3\xA9 "); +} + +#[test] +#[should_panic] +fn wtf8_slice_not_code_point_boundary() { + &Wtf8::from_str("aé 💩")[2..4]; +} + +#[test] +fn wtf8_slice_from() { + assert_eq!(&Wtf8::from_str("aé 💩")[1..].bytes, b"\xC3\xA9 \xF0\x9F\x92\xA9"); +} + +#[test] +#[should_panic] +fn wtf8_slice_from_not_code_point_boundary() { + &Wtf8::from_str("aé 💩")[2..]; +} + +#[test] +fn wtf8_slice_to() { + assert_eq!(&Wtf8::from_str("aé 💩")[..4].bytes, b"a\xC3\xA9 "); +} + +#[test] +#[should_panic] +fn wtf8_slice_to_not_code_point_boundary() { + &Wtf8::from_str("aé 💩")[5..]; +} + +#[test] +fn wtf8_ascii_byte_at() { + let slice = Wtf8::from_str("aé 💩"); + assert_eq!(slice.ascii_byte_at(0), b'a'); + assert_eq!(slice.ascii_byte_at(1), b'\xFF'); + assert_eq!(slice.ascii_byte_at(2), b'\xFF'); + assert_eq!(slice.ascii_byte_at(3), b' '); + assert_eq!(slice.ascii_byte_at(4), b'\xFF'); +} + +#[test] +fn wtf8_code_points() { + fn c(value: u32) -> CodePoint { + CodePoint::from_u32(value).unwrap() + } + fn cp(string: &Wtf8Buf) -> Vec> { + string.code_points().map(|c| c.to_char()).collect::>() + } + let mut string = Wtf8Buf::from_str("é "); + assert_eq!(cp(&string), [Some('é'), Some(' ')]); + string.push(c(0xD83D)); + assert_eq!(cp(&string), [Some('é'), Some(' '), None]); + string.push(c(0xDCA9)); + assert_eq!(cp(&string), [Some('é'), Some(' '), Some('💩')]); +} + +#[test] +fn wtf8_as_str() { + assert_eq!(Wtf8::from_str("").as_str(), Some("")); + assert_eq!(Wtf8::from_str("aé 💩").as_str(), Some("aé 💩")); + let mut string = Wtf8Buf::new(); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!(string.as_str(), None); +} + +#[test] +fn wtf8_to_string_lossy() { + assert_eq!(Wtf8::from_str("").to_string_lossy(), Cow::Borrowed("")); + assert_eq!(Wtf8::from_str("aé 💩").to_string_lossy(), Cow::Borrowed("aé 💩")); + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + let expected: Cow<'_, str> = Cow::Owned(String::from("aé 💩�")); + assert_eq!(string.to_string_lossy(), expected); +} + +#[test] +fn wtf8_display() { + fn d(b: &[u8]) -> String { + (&unsafe { Wtf8::from_bytes_unchecked(b) }).to_string() + } + + assert_eq!("", d("".as_bytes())); + assert_eq!("aé 💩", d("aé 💩".as_bytes())); + + let mut string = Wtf8Buf::from_str("aé 💩"); + string.push(CodePoint::from_u32(0xD800).unwrap()); + assert_eq!("aé 💩�", d(string.as_inner())); +} + +#[test] +fn wtf8_encode_wide() { + let mut string = Wtf8Buf::from_str("aé "); + string.push(CodePoint::from_u32(0xD83D).unwrap()); + string.push_char('💩'); + assert_eq!( + string.encode_wide().collect::>(), + vec![0x61, 0xE9, 0x20, 0xD83D, 0xD83D, 0xDCA9] + ); +} diff --git a/library/std/src/thread/local.rs b/library/std/src/thread/local.rs index a4562967f0..d8db5d1aa6 100644 --- a/library/std/src/thread/local.rs +++ b/library/std/src/thread/local.rs @@ -2,6 +2,12 @@ #![unstable(feature = "thread_local_internals", issue = "none")] +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; + +#[cfg(test)] +mod dynamic_tests; + use crate::error::Error; use crate::fmt; @@ -219,6 +225,7 @@ impl LocalKey { reason = "recently added to create a key", issue = "none" )] + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const unsafe fn new(inner: unsafe fn() -> Option<&'static T>) -> LocalKey { LocalKey { inner } } @@ -282,15 +289,23 @@ mod lazy { } pub unsafe fn get(&self) -> Option<&'static T> { - (*self.inner.get()).as_ref() + // SAFETY: The caller must ensure no reference is ever handed out to + // the inner cell nor mutable reference to the Option inside said + // cell. This make it safe to hand a reference, though the lifetime + // of 'static is itself unsafe, making the get method unsafe. + unsafe { (*self.inner.get()).as_ref() } } + /// The caller must ensure that no reference is active: this method + /// needs unique access. pub unsafe fn initialize T>(&self, init: F) -> &'static T { // Execute the initialization up front, *then* move it into our slot, // just in case initialization fails. let value = init(); let ptr = self.inner.get(); + // SAFETY: + // // note that this can in theory just be `*ptr = Some(value)`, but due to // the compiler will currently codegen that pattern with something like: // @@ -303,22 +318,36 @@ mod lazy { // value (an aliasing violation). To avoid setting the "I'm running a // destructor" flag we just use `mem::replace` which should sequence the // operations a little differently and make this safe to call. - let _ = mem::replace(&mut *ptr, Some(value)); + // + // The precondition also ensures that we are the only one accessing + // `self` at the moment so replacing is fine. + unsafe { + let _ = mem::replace(&mut *ptr, Some(value)); + } - // After storing `Some` we want to get a reference to the contents of - // what we just stored. While we could use `unwrap` here and it should - // always work it empirically doesn't seem to always get optimized away, - // which means that using something like `try_with` can pull in - // panicking code and cause a large size bloat. - match *ptr { - Some(ref x) => x, - None => hint::unreachable_unchecked(), + // SAFETY: With the call to `mem::replace` it is guaranteed there is + // a `Some` behind `ptr`, not a `None` so `unreachable_unchecked` + // will never be reached. + unsafe { + // After storing `Some` we want to get a reference to the contents of + // what we just stored. While we could use `unwrap` here and it should + // always work it empirically doesn't seem to always get optimized away, + // which means that using something like `try_with` can pull in + // panicking code and cause a large size bloat. + match *ptr { + Some(ref x) => x, + None => hint::unreachable_unchecked(), + } } } + /// The other methods hand out references while taking &self. + /// As such, callers of this method must ensure no `&` and `&mut` are + /// available and used at the same time. #[allow(unused)] pub unsafe fn take(&mut self) -> Option { - (*self.inner.get()).take() + // SAFETY: See doc comment for this method. + unsafe { (*self.inner.get()).take() } } } } @@ -349,10 +378,17 @@ pub mod statik { } pub unsafe fn get(&self, init: fn() -> T) -> Option<&'static T> { - let value = match self.inner.get() { - Some(ref value) => value, - None => self.inner.initialize(init), + // SAFETY: The caller must ensure no reference is ever handed out to + // the inner cell nor mutable reference to the Option inside said + // cell. This make it safe to hand a reference, though the lifetime + // of 'static is itself unsafe, making the get method unsafe. + let value = unsafe { + match self.inner.get() { + Some(ref value) => value, + None => self.inner.initialize(init), + } }; + Some(value) } } @@ -407,9 +443,18 @@ pub mod fast { } pub unsafe fn get T>(&self, init: F) -> Option<&'static T> { - match self.inner.get() { - Some(val) => Some(val), - None => self.try_initialize(init), + // SAFETY: See the definitions of `LazyKeyInner::get` and + // `try_initialize` for more informations. + // + // The caller must ensure no mutable references are ever active to + // the inner cell or the inner T when this is called. + // The `try_initialize` is dependant on the passed `init` function + // for this. + unsafe { + match self.inner.get() { + Some(val) => Some(val), + None => self.try_initialize(init), + } } } @@ -418,13 +463,14 @@ pub mod fast { // thread_local's, or it is being recursively initialized. // // Macos: Inlining this function can cause two `tlv_get_addr` calls to - // be performed for every call to `Key::get`. The #[cold] hint makes - // that less likely. + // be performed for every call to `Key::get`. // LLVM issue: https://bugs.llvm.org/show_bug.cgi?id=41722 - #[cold] + #[inline(never)] unsafe fn try_initialize T>(&self, init: F) -> Option<&'static T> { - if !mem::needs_drop::() || self.try_register_dtor() { - Some(self.inner.initialize(init)) + // SAFETY: See comment above (this function doc). + if !mem::needs_drop::() || unsafe { self.try_register_dtor() } { + // SAFETY: See comment above (his function doc). + Some(unsafe { self.inner.initialize(init) }) } else { None } @@ -436,8 +482,12 @@ pub mod fast { unsafe fn try_register_dtor(&self) -> bool { match self.dtor_state.get() { DtorState::Unregistered => { - // dtor registration happens before initialization. - register_dtor(self as *const _ as *mut u8, destroy_value::); + // SAFETY: dtor registration happens before initialization. + // Passing `self` as a pointer while using `destroy_value` + // is safe because the function will build a pointer to a + // Key, which is the type of self and so find the correct + // size. + unsafe { register_dtor(self as *const _ as *mut u8, destroy_value::) }; self.dtor_state.set(DtorState::Registered); true } @@ -453,13 +503,21 @@ pub mod fast { unsafe extern "C" fn destroy_value(ptr: *mut u8) { let ptr = ptr as *mut Key; + // SAFETY: + // + // The pointer `ptr` has been built just above and comes from + // `try_register_dtor` where it is originally a Key coming from `self`, + // making it non-NUL and of the correct type. + // // Right before we run the user destructor be sure to set the // `Option` to `None`, and `dtor_state` to `RunningOrHasRun`. This // causes future calls to `get` to run `try_initialize_drop` again, // which will now fail, and return `None`. - let value = (*ptr).inner.take(); - (*ptr).dtor_state.set(DtorState::RunningOrHasRun); - drop(value); + unsafe { + let value = (*ptr).inner.take(); + (*ptr).dtor_state.set(DtorState::RunningOrHasRun); + drop(value); + } } } @@ -492,25 +550,35 @@ pub mod os { } impl Key { + #[rustc_const_unstable(feature = "thread_local_internals", issue = "none")] pub const fn new() -> Key { Key { os: OsStaticKey::new(Some(destroy_value::)), marker: marker::PhantomData } } + /// It is a requirement for the caller to ensure that no mutable + /// reference is active when this method is called. pub unsafe fn get(&'static self, init: fn() -> T) -> Option<&'static T> { - let ptr = self.os.get() as *mut Value; + // SAFETY: See the documentation for this method. + let ptr = unsafe { self.os.get() as *mut Value }; if ptr as usize > 1 { - if let Some(ref value) = (*ptr).inner.get() { + // SAFETY: the check ensured the pointer is safe (its destructor + // is not running) + it is coming from a trusted source (self). + if let Some(ref value) = unsafe { (*ptr).inner.get() } { return Some(value); } } - self.try_initialize(init) + // SAFETY: At this point we are sure we have no value and so + // initializing (or trying to) is safe. + unsafe { self.try_initialize(init) } } // `try_initialize` is only called once per os thread local variable, // except in corner cases where thread_local dtors reference other // thread_local's, or it is being recursively initialized. unsafe fn try_initialize(&'static self, init: fn() -> T) -> Option<&'static T> { - let ptr = self.os.get() as *mut Value; + // SAFETY: No mutable references are ever handed out meaning getting + // the value is ok. + let ptr = unsafe { self.os.get() as *mut Value }; if ptr as usize == 1 { // destructor is running return None; @@ -521,18 +589,26 @@ pub mod os { // local copy, so do that now. let ptr: Box> = box Value { inner: LazyKeyInner::new(), key: self }; let ptr = Box::into_raw(ptr); - self.os.set(ptr as *mut u8); + // SAFETY: At this point we are sure there is no value inside + // ptr so setting it will not affect anyone else. + unsafe { + self.os.set(ptr as *mut u8); + } ptr } else { // recursive initialization ptr }; - Some((*ptr).inner.initialize(init)) + // SAFETY: ptr has been ensured as non-NUL just above an so can be + // dereferenced safely. + unsafe { Some((*ptr).inner.initialize(init)) } } } unsafe extern "C" fn destroy_value(ptr: *mut u8) { + // SAFETY: + // // The OS TLS ensures that this key contains a NULL value when this // destructor starts to run. We set it back to a sentinel value of 1 to // ensure that any future calls to `get` for this thread will return @@ -540,210 +616,12 @@ pub mod os { // // Note that to prevent an infinite loop we reset it back to null right // before we return from the destructor ourselves. - let ptr = Box::from_raw(ptr as *mut Value); - let key = ptr.key; - key.os.set(1 as *mut u8); - drop(ptr); - key.os.set(ptr::null_mut()); - } -} - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use crate::cell::{Cell, UnsafeCell}; - use crate::sync::mpsc::{channel, Sender}; - use crate::thread; - - struct Foo(Sender<()>); - - impl Drop for Foo { - fn drop(&mut self) { - let Foo(ref s) = *self; - s.send(()).unwrap(); - } - } - - #[test] - fn smoke_no_dtor() { - thread_local!(static FOO: Cell = Cell::new(1)); - - FOO.with(|f| { - assert_eq!(f.get(), 1); - f.set(2); - }); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - FOO.with(|f| { - assert_eq!(f.get(), 1); - }); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - - FOO.with(|f| { - assert_eq!(f.get(), 2); - }); - } - - #[test] - fn states() { - struct Foo; - impl Drop for Foo { - fn drop(&mut self) { - assert!(FOO.try_with(|_| ()).is_err()); - } - } - thread_local!(static FOO: Foo = Foo); - - thread::spawn(|| { - assert!(FOO.try_with(|_| ()).is_ok()); - }) - .join() - .ok() - .expect("thread panicked"); - } - - #[test] - fn smoke_dtor() { - thread_local!(static FOO: UnsafeCell> = UnsafeCell::new(None)); - - let (tx, rx) = channel(); - let _t = thread::spawn(move || unsafe { - let mut tx = Some(tx); - FOO.with(|f| { - *f.get() = Some(Foo(tx.take().unwrap())); - }); - }); - rx.recv().unwrap(); - } - - #[test] - fn circular() { - struct S1; - struct S2; - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); - static mut HITS: u32 = 0; - - impl Drop for S1 { - fn drop(&mut self) { - unsafe { - HITS += 1; - if K2.try_with(|_| ()).is_err() { - assert_eq!(HITS, 3); - } else { - if HITS == 1 { - K2.with(|s| *s.get() = Some(S2)); - } else { - assert_eq!(HITS, 3); - } - } - } - } - } - impl Drop for S2 { - fn drop(&mut self) { - unsafe { - HITS += 1; - assert!(K1.try_with(|_| ()).is_ok()); - assert_eq!(HITS, 2); - K1.with(|s| *s.get() = Some(S1)); - } - } - } - - thread::spawn(move || { - drop(S1); - }) - .join() - .ok() - .expect("thread panicked"); - } - - #[test] - fn self_referential() { - struct S1; - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - - impl Drop for S1 { - fn drop(&mut self) { - assert!(K1.try_with(|_| ()).is_err()); - } - } - - thread::spawn(move || unsafe { - K1.with(|s| *s.get() = Some(S1)); - }) - .join() - .ok() - .expect("thread panicked"); - } - - // Note that this test will deadlock if TLS destructors aren't run (this - // requires the destructor to be run to pass the test). - #[test] - fn dtors_in_dtors_in_dtors() { - struct S1(Sender<()>); - thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); - thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); - - impl Drop for S1 { - fn drop(&mut self) { - let S1(ref tx) = *self; - unsafe { - let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone()))); - } - } - } - - let (tx, rx) = channel(); - let _t = thread::spawn(move || unsafe { - let mut tx = Some(tx); - K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); - }); - rx.recv().unwrap(); - } -} - -#[cfg(test)] -mod dynamic_tests { - use crate::cell::RefCell; - use crate::collections::HashMap; - - #[test] - fn smoke() { - fn square(i: i32) -> i32 { - i * i - } - thread_local!(static FOO: i32 = square(3)); - - FOO.with(|f| { - assert_eq!(*f, 9); - }); - } - - #[test] - fn hashmap() { - fn map() -> RefCell> { - let mut m = HashMap::new(); - m.insert(1, 2); - RefCell::new(m) - } - thread_local!(static FOO: RefCell> = map()); - - FOO.with(|map| { - assert_eq!(map.borrow()[&1], 2); - }); - } - - #[test] - fn refcell_vec() { - thread_local!(static FOO: RefCell> = RefCell::new(vec![1, 2, 3])); - - FOO.with(|vec| { - assert_eq!(vec.borrow().len(), 3); - vec.borrow_mut().push(4); - assert_eq!(vec.borrow()[3], 4); - }); + unsafe { + let ptr = Box::from_raw(ptr as *mut Value); + let key = ptr.key; + key.os.set(1 as *mut u8); + drop(ptr); + key.os.set(ptr::null_mut()); + } } } diff --git a/library/std/src/thread/local/dynamic_tests.rs b/library/std/src/thread/local/dynamic_tests.rs new file mode 100644 index 0000000000..dd18004164 --- /dev/null +++ b/library/std/src/thread/local/dynamic_tests.rs @@ -0,0 +1,40 @@ +use crate::cell::RefCell; +use crate::collections::HashMap; +use crate::thread_local; + +#[test] +fn smoke() { + fn square(i: i32) -> i32 { + i * i + } + thread_local!(static FOO: i32 = square(3)); + + FOO.with(|f| { + assert_eq!(*f, 9); + }); +} + +#[test] +fn hashmap() { + fn map() -> RefCell> { + let mut m = HashMap::new(); + m.insert(1, 2); + RefCell::new(m) + } + thread_local!(static FOO: RefCell> = map()); + + FOO.with(|map| { + assert_eq!(map.borrow()[&1], 2); + }); +} + +#[test] +fn refcell_vec() { + thread_local!(static FOO: RefCell> = RefCell::new(vec![1, 2, 3])); + + FOO.with(|vec| { + assert_eq!(vec.borrow().len(), 3); + vec.borrow_mut().push(4); + assert_eq!(vec.borrow()[3], 4); + }); +} diff --git a/library/std/src/thread/local/tests.rs b/library/std/src/thread/local/tests.rs new file mode 100644 index 0000000000..4fb0a08908 --- /dev/null +++ b/library/std/src/thread/local/tests.rs @@ -0,0 +1,154 @@ +use crate::cell::{Cell, UnsafeCell}; +use crate::sync::mpsc::{channel, Sender}; +use crate::thread; +use crate::thread_local; + +struct Foo(Sender<()>); + +impl Drop for Foo { + fn drop(&mut self) { + let Foo(ref s) = *self; + s.send(()).unwrap(); + } +} + +#[test] +fn smoke_no_dtor() { + thread_local!(static FOO: Cell = Cell::new(1)); + + FOO.with(|f| { + assert_eq!(f.get(), 1); + f.set(2); + }); + let (tx, rx) = channel(); + let _t = thread::spawn(move || { + FOO.with(|f| { + assert_eq!(f.get(), 1); + }); + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); + + FOO.with(|f| { + assert_eq!(f.get(), 2); + }); +} + +#[test] +fn states() { + struct Foo; + impl Drop for Foo { + fn drop(&mut self) { + assert!(FOO.try_with(|_| ()).is_err()); + } + } + thread_local!(static FOO: Foo = Foo); + + thread::spawn(|| { + assert!(FOO.try_with(|_| ()).is_ok()); + }) + .join() + .ok() + .expect("thread panicked"); +} + +#[test] +fn smoke_dtor() { + thread_local!(static FOO: UnsafeCell> = UnsafeCell::new(None)); + + let (tx, rx) = channel(); + let _t = thread::spawn(move || unsafe { + let mut tx = Some(tx); + FOO.with(|f| { + *f.get() = Some(Foo(tx.take().unwrap())); + }); + }); + rx.recv().unwrap(); +} + +#[test] +fn circular() { + struct S1; + struct S2; + thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); + thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); + static mut HITS: u32 = 0; + + impl Drop for S1 { + fn drop(&mut self) { + unsafe { + HITS += 1; + if K2.try_with(|_| ()).is_err() { + assert_eq!(HITS, 3); + } else { + if HITS == 1 { + K2.with(|s| *s.get() = Some(S2)); + } else { + assert_eq!(HITS, 3); + } + } + } + } + } + impl Drop for S2 { + fn drop(&mut self) { + unsafe { + HITS += 1; + assert!(K1.try_with(|_| ()).is_ok()); + assert_eq!(HITS, 2); + K1.with(|s| *s.get() = Some(S1)); + } + } + } + + thread::spawn(move || { + drop(S1); + }) + .join() + .ok() + .expect("thread panicked"); +} + +#[test] +fn self_referential() { + struct S1; + thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); + + impl Drop for S1 { + fn drop(&mut self) { + assert!(K1.try_with(|_| ()).is_err()); + } + } + + thread::spawn(move || unsafe { + K1.with(|s| *s.get() = Some(S1)); + }) + .join() + .ok() + .expect("thread panicked"); +} + +// Note that this test will deadlock if TLS destructors aren't run (this +// requires the destructor to be run to pass the test). +#[test] +fn dtors_in_dtors_in_dtors() { + struct S1(Sender<()>); + thread_local!(static K1: UnsafeCell> = UnsafeCell::new(None)); + thread_local!(static K2: UnsafeCell> = UnsafeCell::new(None)); + + impl Drop for S1 { + fn drop(&mut self) { + let S1(ref tx) = *self; + unsafe { + let _ = K2.try_with(|s| *s.get() = Some(Foo(tx.clone()))); + } + } + } + + let (tx, rx) = channel(); + let _t = thread::spawn(move || unsafe { + let mut tx = Some(tx); + K1.with(|s| *s.get() = Some(S1(tx.take().unwrap()))); + }); + rx.recv().unwrap(); +} diff --git a/library/std/src/thread/mod.rs b/library/std/src/thread/mod.rs index 0b9849517c..087175bb92 100644 --- a/library/std/src/thread/mod.rs +++ b/library/std/src/thread/mod.rs @@ -144,6 +144,10 @@ //! [`with`]: LocalKey::with #![stable(feature = "rust1", since = "1.0.0")] +#![deny(unsafe_op_in_unsafe_fn)] + +#[cfg(all(test, not(target_os = "emscripten")))] +mod tests; use crate::any::Any; use crate::cell::UnsafeCell; @@ -155,13 +159,12 @@ use crate::num::NonZeroU64; use crate::panic; use crate::panicking; use crate::str; -use crate::sync::atomic::AtomicUsize; -use crate::sync::atomic::Ordering::SeqCst; -use crate::sync::{Arc, Condvar, Mutex}; +use crate::sync::Arc; use crate::sys::thread as imp; use crate::sys_common::mutex; use crate::sys_common::thread; use crate::sys_common::thread_info; +use crate::sys_common::thread_parker::Parker; use crate::sys_common::{AsInner, IntoInner}; use crate::time::Duration; @@ -453,14 +456,23 @@ impl Builder { imp::Thread::set_name(name); } - thread_info::set(imp::guard::current(), their_thread); + // SAFETY: the stack guard passed is the one for the current thread. + // This means the current thread's stack and the new thread's stack + // are properly set and protected from each other. + thread_info::set(unsafe { imp::guard::current() }, their_thread); let try_result = panic::catch_unwind(panic::AssertUnwindSafe(|| { crate::sys_common::backtrace::__rust_begin_short_backtrace(f) })); - *their_packet.get() = Some(try_result); + // SAFETY: `their_packet` as been built just above and moved by the + // closure (it is an Arc<...>) and `my_packet` will be stored in the + // same `JoinInner` as this closure meaning the mutation will be + // safe (not modify it and affect a value far away). + unsafe { *their_packet.get() = Some(try_result) }; }; Ok(JoinHandle(JoinInner { + // SAFETY: + // // `imp::Thread::new` takes a closure with a `'static` lifetime, since it's passed // through FFI or otherwise used with low-level threading primitives that have no // notion of or way to enforce lifetimes. @@ -472,12 +484,14 @@ impl Builder { // Similarly, the `sys` implementation must guarantee that no references to the closure // exist after the thread has terminated, which is signaled by `Thread::join` // returning. - native: Some(imp::Thread::new( - stack_size, - mem::transmute::, Box>(Box::new( - main, - )), - )?), + native: unsafe { + Some(imp::Thread::new( + stack_size, + mem::transmute::, Box>( + Box::new(main), + ), + )?) + }, thread: my_thread, packet: Packet(my_packet), })) @@ -652,6 +666,8 @@ pub fn current() -> Thread { /// /// [`channel`]: crate::sync::mpsc /// [`join`]: JoinHandle::join +/// [`Condvar`]: crate::sync::Condvar +/// [`Mutex`]: crate::sync::Mutex #[stable(feature = "rust1", since = "1.0.0")] pub fn yield_now() { imp::Thread::yield_now() @@ -697,6 +713,8 @@ pub fn yield_now() { /// panic!() /// } /// ``` +/// +/// [Mutex]: crate::sync::Mutex #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn panicking() -> bool { @@ -764,11 +782,6 @@ pub fn sleep(dur: Duration) { imp::Thread::sleep(dur) } -// constants for park/unpark -const EMPTY: usize = 0; -const PARKED: usize = 1; -const NOTIFIED: usize = 2; - /// Blocks unless or until the current thread's token is made available. /// /// A call to `park` does not guarantee that the thread will remain parked @@ -855,45 +868,11 @@ const NOTIFIED: usize = 2; /// /// [`unpark`]: Thread::unpark /// [`thread::park_timeout`]: park_timeout -// -// The implementation currently uses the trivial strategy of a Mutex+Condvar -// with wakeup flag, which does not actually allow spurious wakeups. In the -// future, this will be implemented in a more efficient way, perhaps along the lines of -// http://cr.openjdk.java.net/~stefank/6989984.1/raw_files/new/src/os/linux/vm/os_linux.cpp -// or futuxes, and in either case may allow spurious wakeups. #[stable(feature = "rust1", since = "1.0.0")] pub fn park() { - let thread = current(); - - // If we were previously notified then we consume this notification and - // return quickly. - if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return; - } - - // Otherwise we need to coordinate going to sleep - let mut m = thread.inner.lock.lock().unwrap(); - match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - Err(NOTIFIED) => { - // We must read here, even though we know it will be `NOTIFIED`. - // This is because `unpark` may have been called again since we read - // `NOTIFIED` in the `compare_exchange` above. We must perform an - // acquire operation that synchronizes with that `unpark` to observe - // any writes it made before the call to unpark. To do that we must - // read from the write it made to `state`. - let old = thread.inner.state.swap(EMPTY, SeqCst); - assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => panic!("inconsistent park state"), - } - loop { - m = thread.inner.cvar.wait(m).unwrap(); - match thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst) { - Ok(_) => return, // got a notification - Err(_) => {} // spurious wakeup, go back to sleep - } + // SAFETY: park_timeout is called on the parker owned by this thread. + unsafe { + current().inner.parker.park(); } } @@ -955,35 +934,9 @@ pub fn park_timeout_ms(ms: u32) { /// ``` #[stable(feature = "park_timeout", since = "1.4.0")] pub fn park_timeout(dur: Duration) { - let thread = current(); - - // Like `park` above we have a fast path for an already-notified thread, and - // afterwards we start coordinating for a sleep. - // return quickly. - if thread.inner.state.compare_exchange(NOTIFIED, EMPTY, SeqCst, SeqCst).is_ok() { - return; - } - let m = thread.inner.lock.lock().unwrap(); - match thread.inner.state.compare_exchange(EMPTY, PARKED, SeqCst, SeqCst) { - Ok(_) => {} - Err(NOTIFIED) => { - // We must read again here, see `park`. - let old = thread.inner.state.swap(EMPTY, SeqCst); - assert_eq!(old, NOTIFIED, "park state changed unexpectedly"); - return; - } // should consume this notification, so prohibit spurious wakeups in next park. - Err(_) => panic!("inconsistent park_timeout state"), - } - - // Wait with a timeout, and if we spuriously wake up or otherwise wake up - // from a notification we just want to unconditionally set the state back to - // empty, either consuming a notification or un-flagging ourselves as - // parked. - let (_m, _result) = thread.inner.cvar.wait_timeout(m, dur).unwrap(); - match thread.inner.state.swap(EMPTY, SeqCst) { - NOTIFIED => {} // got a notification, hurray! - PARKED => {} // no notification, alas - n => panic!("inconsistent park_timeout state: {}", n), + // SAFETY: park_timeout is called on the parker owned by this thread. + unsafe { + current().inner.parker.park_timeout(dur); } } @@ -1019,9 +972,8 @@ pub struct ThreadId(NonZeroU64); impl ThreadId { // Generate a new unique thread ID. fn new() -> ThreadId { - // We never call `GUARD.init()`, so it is UB to attempt to - // acquire this mutex reentrantly! - static GUARD: mutex::Mutex = mutex::Mutex::new(); + // It is UB to attempt to acquire this mutex reentrantly! + static GUARD: mutex::StaticMutex = mutex::StaticMutex::new(); static mut COUNTER: u64 = 1; unsafe { @@ -1062,11 +1014,7 @@ impl ThreadId { struct Inner { name: Option, // Guaranteed to be UTF-8 id: ThreadId, - - // state for thread park/unpark - state: AtomicUsize, - lock: Mutex<()>, - cvar: Condvar, + parker: Parker, } #[derive(Clone)] @@ -1100,13 +1048,7 @@ impl 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(), - state: AtomicUsize::new(EMPTY), - lock: Mutex::new(()), - cvar: Condvar::new(), - }), + inner: Arc::new(Inner { name: cname, id: ThreadId::new(), parker: Parker::new() }), } } @@ -1141,33 +1083,9 @@ impl Thread { /// parked_thread.join().unwrap(); /// ``` #[stable(feature = "rust1", since = "1.0.0")] + #[inline] pub fn unpark(&self) { - // To ensure the unparked thread will observe any writes we made - // before this call, we must perform a release operation that `park` - // can synchronize with. To do that we must write `NOTIFIED` even if - // `state` is already `NOTIFIED`. That is why this must be a swap - // rather than a compare-and-swap that returns if it reads `NOTIFIED` - // on failure. - match self.inner.state.swap(NOTIFIED, SeqCst) { - EMPTY => return, // no one was waiting - NOTIFIED => return, // already unparked - PARKED => {} // gotta go wake someone up - _ => panic!("inconsistent state in unpark"), - } - - // There is a period between when the parked thread sets `state` to - // `PARKED` (or last checked `state` in the case of a spurious wake - // up) and when it actually waits on `cvar`. If we were to notify - // during this period it would be ignored and then when the parked - // thread went to sleep it would never wake up. Fortunately, it has - // `lock` locked at this stage so we can acquire `lock` to wait until - // it is ready to receive the notification. - // - // Releasing `lock` before the call to `notify_one` means that when the - // parked thread wakes it doesn't get woken only to have to wait for us - // to release `lock`. - drop(self.inner.lock.lock().unwrap()); - self.inner.cvar.notify_one() + self.inner.parker.unpark(); } /// Gets the thread's unique identifier. @@ -1470,273 +1388,3 @@ fn _assert_sync_and_send() { _assert_both::>(); _assert_both::(); } - -//////////////////////////////////////////////////////////////////////////////// -// Tests -//////////////////////////////////////////////////////////////////////////////// - -#[cfg(all(test, not(target_os = "emscripten")))] -mod tests { - use super::Builder; - use crate::any::Any; - use crate::mem; - use crate::result; - use crate::sync::mpsc::{channel, Sender}; - use crate::thread::{self, ThreadId}; - use crate::time::Duration; - - // !!! These tests are dangerous. If something is buggy, they will hang, !!! - // !!! instead of exiting cleanly. This might wedge the buildbots. !!! - - #[test] - fn test_unnamed_thread() { - thread::spawn(move || { - assert!(thread::current().name().is_none()); - }) - .join() - .ok() - .expect("thread panicked"); - } - - #[test] - fn test_named_thread() { - Builder::new() - .name("ada lovelace".to_string()) - .spawn(move || { - assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); - }) - .unwrap() - .join() - .unwrap(); - } - - #[test] - #[should_panic] - fn test_invalid_named_thread() { - let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {}); - } - - #[test] - fn test_run_basic() { - let (tx, rx) = channel(); - thread::spawn(move || { - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_join_panic() { - match thread::spawn(move || panic!()).join() { - result::Result::Err(_) => (), - result::Result::Ok(()) => panic!(), - } - } - - #[test] - fn test_spawn_sched() { - let (tx, rx) = channel(); - - fn f(i: i32, tx: Sender<()>) { - let tx = tx.clone(); - thread::spawn(move || { - if i == 0 { - tx.send(()).unwrap(); - } else { - f(i - 1, tx); - } - }); - } - f(10, tx); - rx.recv().unwrap(); - } - - #[test] - fn test_spawn_sched_childs_on_default_sched() { - let (tx, rx) = channel(); - - thread::spawn(move || { - thread::spawn(move || { - tx.send(()).unwrap(); - }); - }); - - rx.recv().unwrap(); - } - - fn avoid_copying_the_body(spawnfn: F) - where - F: FnOnce(Box), - { - let (tx, rx) = channel(); - - let x: Box<_> = box 1; - let x_in_parent = (&*x) as *const i32 as usize; - - spawnfn(Box::new(move || { - let x_in_child = (&*x) as *const i32 as usize; - tx.send(x_in_child).unwrap(); - })); - - let x_in_child = rx.recv().unwrap(); - assert_eq!(x_in_parent, x_in_child); - } - - #[test] - fn test_avoid_copying_the_body_spawn() { - avoid_copying_the_body(|v| { - thread::spawn(move || v()); - }); - } - - #[test] - fn test_avoid_copying_the_body_thread_spawn() { - avoid_copying_the_body(|f| { - thread::spawn(move || { - f(); - }); - }) - } - - #[test] - fn test_avoid_copying_the_body_join() { - avoid_copying_the_body(|f| { - let _ = thread::spawn(move || f()).join(); - }) - } - - #[test] - fn test_child_doesnt_ref_parent() { - // If the child refcounts the parent thread, this will stack overflow when - // climbing the thread tree to dereference each ancestor. (See #1789) - // (well, it would if the constant were 8000+ - I lowered it to be more - // valgrind-friendly. try this at home, instead..!) - const GENERATIONS: u32 = 16; - fn child_no(x: u32) -> Box { - return Box::new(move || { - if x < GENERATIONS { - thread::spawn(move || child_no(x + 1)()); - } - }); - } - thread::spawn(|| child_no(0)()); - } - - #[test] - fn test_simple_newsched_spawn() { - thread::spawn(move || {}); - } - - #[test] - fn test_try_panic_message_static_str() { - match thread::spawn(move || { - panic!("static string"); - }) - .join() - { - Err(e) => { - type T = &'static str; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "static string"); - } - Ok(()) => panic!(), - } - } - - #[test] - fn test_try_panic_message_owned_str() { - match thread::spawn(move || { - panic!("owned string".to_string()); - }) - .join() - { - Err(e) => { - type T = String; - assert!(e.is::()); - assert_eq!(*e.downcast::().unwrap(), "owned string".to_string()); - } - Ok(()) => panic!(), - } - } - - #[test] - fn test_try_panic_message_any() { - match thread::spawn(move || { - panic!(box 413u16 as Box); - }) - .join() - { - Err(e) => { - type T = Box; - assert!(e.is::()); - let any = e.downcast::().unwrap(); - assert!(any.is::()); - assert_eq!(*any.downcast::().unwrap(), 413); - } - Ok(()) => panic!(), - } - } - - #[test] - fn test_try_panic_message_unit_struct() { - struct Juju; - - match thread::spawn(move || panic!(Juju)).join() { - Err(ref e) if e.is::() => {} - Err(_) | Ok(()) => panic!(), - } - } - - #[test] - fn test_park_timeout_unpark_before() { - for _ in 0..10 { - thread::current().unpark(); - thread::park_timeout(Duration::from_millis(u32::MAX as u64)); - } - } - - #[test] - fn test_park_timeout_unpark_not_called() { - for _ in 0..10 { - thread::park_timeout(Duration::from_millis(10)); - } - } - - #[test] - fn test_park_timeout_unpark_called_other_thread() { - for _ in 0..10 { - let th = thread::current(); - - let _guard = thread::spawn(move || { - super::sleep(Duration::from_millis(50)); - th.unpark(); - }); - - thread::park_timeout(Duration::from_millis(u32::MAX as u64)); - } - } - - #[test] - fn sleep_ms_smoke() { - thread::sleep(Duration::from_millis(2)); - } - - #[test] - fn test_size_of_option_thread_id() { - assert_eq!(mem::size_of::>(), mem::size_of::()); - } - - #[test] - fn test_thread_id_equal() { - assert!(thread::current().id() == thread::current().id()); - } - - #[test] - fn test_thread_id_not_equal() { - let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); - assert!(thread::current().id() != spawned_id); - } - - // NOTE: the corresponding test for stderr is in ui/thread-stderr, due - // to the test harness apparently interfering with stderr configuration. -} diff --git a/library/std/src/thread/tests.rs b/library/std/src/thread/tests.rs new file mode 100644 index 0000000000..16ad366fc1 --- /dev/null +++ b/library/std/src/thread/tests.rs @@ -0,0 +1,262 @@ +use super::Builder; +use crate::any::Any; +use crate::mem; +use crate::result; +use crate::sync::mpsc::{channel, Sender}; +use crate::thread::{self, ThreadId}; +use crate::time::Duration; + +// !!! These tests are dangerous. If something is buggy, they will hang, !!! +// !!! instead of exiting cleanly. This might wedge the buildbots. !!! + +#[test] +fn test_unnamed_thread() { + thread::spawn(move || { + assert!(thread::current().name().is_none()); + }) + .join() + .ok() + .expect("thread panicked"); +} + +#[test] +fn test_named_thread() { + Builder::new() + .name("ada lovelace".to_string()) + .spawn(move || { + assert!(thread::current().name().unwrap() == "ada lovelace".to_string()); + }) + .unwrap() + .join() + .unwrap(); +} + +#[test] +#[should_panic] +fn test_invalid_named_thread() { + let _ = Builder::new().name("ada l\0velace".to_string()).spawn(|| {}); +} + +#[test] +fn test_run_basic() { + let (tx, rx) = channel(); + thread::spawn(move || { + tx.send(()).unwrap(); + }); + rx.recv().unwrap(); +} + +#[test] +fn test_join_panic() { + match thread::spawn(move || panic!()).join() { + result::Result::Err(_) => (), + result::Result::Ok(()) => panic!(), + } +} + +#[test] +fn test_spawn_sched() { + let (tx, rx) = channel(); + + fn f(i: i32, tx: Sender<()>) { + let tx = tx.clone(); + thread::spawn(move || { + if i == 0 { + tx.send(()).unwrap(); + } else { + f(i - 1, tx); + } + }); + } + f(10, tx); + rx.recv().unwrap(); +} + +#[test] +fn test_spawn_sched_childs_on_default_sched() { + let (tx, rx) = channel(); + + thread::spawn(move || { + thread::spawn(move || { + tx.send(()).unwrap(); + }); + }); + + rx.recv().unwrap(); +} + +fn avoid_copying_the_body(spawnfn: F) +where + F: FnOnce(Box), +{ + let (tx, rx) = channel(); + + let x: Box<_> = box 1; + let x_in_parent = (&*x) as *const i32 as usize; + + spawnfn(Box::new(move || { + let x_in_child = (&*x) as *const i32 as usize; + tx.send(x_in_child).unwrap(); + })); + + let x_in_child = rx.recv().unwrap(); + assert_eq!(x_in_parent, x_in_child); +} + +#[test] +fn test_avoid_copying_the_body_spawn() { + avoid_copying_the_body(|v| { + thread::spawn(move || v()); + }); +} + +#[test] +fn test_avoid_copying_the_body_thread_spawn() { + avoid_copying_the_body(|f| { + thread::spawn(move || { + f(); + }); + }) +} + +#[test] +fn test_avoid_copying_the_body_join() { + avoid_copying_the_body(|f| { + let _ = thread::spawn(move || f()).join(); + }) +} + +#[test] +fn test_child_doesnt_ref_parent() { + // If the child refcounts the parent thread, this will stack overflow when + // climbing the thread tree to dereference each ancestor. (See #1789) + // (well, it would if the constant were 8000+ - I lowered it to be more + // valgrind-friendly. try this at home, instead..!) + const GENERATIONS: u32 = 16; + fn child_no(x: u32) -> Box { + return Box::new(move || { + if x < GENERATIONS { + thread::spawn(move || child_no(x + 1)()); + } + }); + } + thread::spawn(|| child_no(0)()); +} + +#[test] +fn test_simple_newsched_spawn() { + thread::spawn(move || {}); +} + +#[test] +fn test_try_panic_message_static_str() { + match thread::spawn(move || { + panic!("static string"); + }) + .join() + { + Err(e) => { + type T = &'static str; + assert!(e.is::()); + assert_eq!(*e.downcast::().unwrap(), "static string"); + } + Ok(()) => panic!(), + } +} + +#[test] +fn test_try_panic_message_owned_str() { + match thread::spawn(move || { + panic!("owned string".to_string()); + }) + .join() + { + Err(e) => { + type T = String; + assert!(e.is::()); + assert_eq!(*e.downcast::().unwrap(), "owned string".to_string()); + } + Ok(()) => panic!(), + } +} + +#[test] +fn test_try_panic_message_any() { + match thread::spawn(move || { + panic!(box 413u16 as Box); + }) + .join() + { + Err(e) => { + type T = Box; + assert!(e.is::()); + let any = e.downcast::().unwrap(); + assert!(any.is::()); + assert_eq!(*any.downcast::().unwrap(), 413); + } + Ok(()) => panic!(), + } +} + +#[test] +fn test_try_panic_message_unit_struct() { + struct Juju; + + match thread::spawn(move || panic!(Juju)).join() { + Err(ref e) if e.is::() => {} + Err(_) | Ok(()) => panic!(), + } +} + +#[test] +fn test_park_timeout_unpark_before() { + for _ in 0..10 { + thread::current().unpark(); + thread::park_timeout(Duration::from_millis(u32::MAX as u64)); + } +} + +#[test] +fn test_park_timeout_unpark_not_called() { + for _ in 0..10 { + thread::park_timeout(Duration::from_millis(10)); + } +} + +#[test] +fn test_park_timeout_unpark_called_other_thread() { + for _ in 0..10 { + let th = thread::current(); + + let _guard = thread::spawn(move || { + super::sleep(Duration::from_millis(50)); + th.unpark(); + }); + + thread::park_timeout(Duration::from_millis(u32::MAX as u64)); + } +} + +#[test] +fn sleep_ms_smoke() { + thread::sleep(Duration::from_millis(2)); +} + +#[test] +fn test_size_of_option_thread_id() { + assert_eq!(mem::size_of::>(), mem::size_of::()); +} + +#[test] +fn test_thread_id_equal() { + assert!(thread::current().id() == thread::current().id()); +} + +#[test] +fn test_thread_id_not_equal() { + let spawned_id = thread::spawn(|| thread::current().id()).join().unwrap(); + assert!(thread::current().id() != spawned_id); +} + +// NOTE: the corresponding test for stderr is in ui/thread-stderr, due +// to the test harness apparently interfering with stderr configuration. diff --git a/library/std/src/time.rs b/library/std/src/time.rs index 02161ecb4c..e7df384114 100644 --- a/library/std/src/time.rs +++ b/library/std/src/time.rs @@ -12,12 +12,15 @@ #![stable(feature = "time", since = "1.3.0")] +#[cfg(test)] +mod tests; + use crate::cmp; use crate::error::Error; use crate::fmt; use crate::ops::{Add, AddAssign, Sub, SubAssign}; use crate::sys::time; -use crate::sys_common::mutex::Mutex; +use crate::sys_common::mutex::StaticMutex; use crate::sys_common::FromInner; #[stable(feature = "time", since = "1.3.0")] @@ -156,10 +159,10 @@ pub struct Instant(time::Instant); /// | CloudABI | [clock_time_get (Realtime Clock)] | /// | SGX | [`insecure_time` usercall]. More information on [timekeeping in SGX] | /// | UNIX | [clock_gettime (Realtime Clock)] | -/// | DARWIN | [gettimeofday] | +/// | Darwin | [gettimeofday] | /// | VXWorks | [clock_gettime (Realtime Clock)] | /// | WASI | [__wasi_clock_time_get (Realtime Clock)] | -/// | Windows | [GetSystemTimeAsFileTime] | +/// | Windows | [GetSystemTimePreciseAsFileTime] / [GetSystemTimeAsFileTime] | /// /// [clock_time_get (Realtime Clock)]: https://nuxi.nl/cloudabi/#clock_time_get /// [`insecure_time` usercall]: https://edp.fortanix.com/docs/api/fortanix_sgx_abi/struct.Usercalls.html#method.insecure_time @@ -167,6 +170,7 @@ pub struct Instant(time::Instant); /// [gettimeofday]: http://man7.org/linux/man-pages/man2/gettimeofday.2.html /// [clock_gettime (Realtime Clock)]: https://linux.die.net/man/3/clock_gettime /// [__wasi_clock_time_get (Realtime Clock)]: https://github.com/WebAssembly/WASI/blob/master/phases/snapshot/docs.md#clock_time_get +/// [GetSystemTimePreciseAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimepreciseasfiletime /// [GetSystemTimeAsFileTime]: https://docs.microsoft.com/en-us/windows/win32/api/sysinfoapi/nf-sysinfoapi-getsystemtimeasfiletime /// /// **Disclaimer:** These system calls might change over time. @@ -239,7 +243,7 @@ impl Instant { return Instant(os_now); } - static LOCK: Mutex = Mutex::new(); + static LOCK: StaticMutex = StaticMutex::new(); static mut LAST_NOW: time::Instant = time::Instant::zero(); unsafe { let _lock = LOCK.lock(); @@ -456,12 +460,13 @@ impl SystemTime { /// /// # Examples /// - /// ``` + /// ```no_run /// use std::time::SystemTime; /// /// let sys_time = SystemTime::now(); - /// let difference = sys_time.duration_since(sys_time) - /// .expect("Clock may have gone backwards"); + /// let new_sys_time = SystemTime::now(); + /// let difference = new_sys_time.duration_since(sys_time) + /// .expect("Clock may have gone backwards"); /// println!("{:?}", difference); /// ``` #[stable(feature = "time2", since = "1.8.0")] @@ -629,172 +634,3 @@ impl FromInner for SystemTime { SystemTime(time) } } - -#[cfg(test)] -mod tests { - use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; - - macro_rules! assert_almost_eq { - ($a:expr, $b:expr) => {{ - let (a, b) = ($a, $b); - if a != b { - let (a, b) = if a > b { (a, b) } else { (b, a) }; - assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b); - } - }}; - } - - #[test] - fn instant_monotonic() { - let a = Instant::now(); - let b = Instant::now(); - assert!(b >= a); - } - - #[test] - fn instant_elapsed() { - let a = Instant::now(); - a.elapsed(); - } - - #[test] - fn instant_math() { - let a = Instant::now(); - let b = Instant::now(); - println!("a: {:?}", a); - println!("b: {:?}", b); - let dur = b.duration_since(a); - println!("dur: {:?}", dur); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - - let second = Duration::new(1, 0); - assert_almost_eq!(a - second + second, a); - assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); - - // checked_add_duration will not panic on overflow - let mut maybe_t = Some(Instant::now()); - let max_duration = Duration::from_secs(u64::MAX); - // in case `Instant` can store `>= now + max_duration`. - for _ in 0..2 { - maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); - } - assert_eq!(maybe_t, None); - - // checked_add_duration calculates the right time and will work for another year - let year = Duration::from_secs(60 * 60 * 24 * 365); - assert_eq!(a + year, a.checked_add(year).unwrap()); - } - - #[test] - fn instant_math_is_associative() { - let now = Instant::now(); - let offset = Duration::from_millis(5); - // Changing the order of instant math shouldn't change the results, - // especially when the expression reduces to X + identity. - assert_eq!((now + offset) - now, (now - now) + offset); - } - - #[test] - #[should_panic] - fn instant_duration_since_panic() { - let a = Instant::now(); - (a - Duration::new(1, 0)).duration_since(a); - } - - #[test] - fn instant_checked_duration_since_nopanic() { - let now = Instant::now(); - let earlier = now - Duration::new(1, 0); - let later = now + Duration::new(1, 0); - assert_eq!(earlier.checked_duration_since(now), None); - assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0))); - assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0))); - } - - #[test] - fn instant_saturating_duration_since_nopanic() { - let a = Instant::now(); - let ret = (a - Duration::new(1, 0)).saturating_duration_since(a); - assert_eq!(ret, Duration::new(0, 0)); - } - - #[test] - fn system_time_math() { - let a = SystemTime::now(); - let b = SystemTime::now(); - match b.duration_since(a) { - Ok(dur) if dur == Duration::new(0, 0) => { - assert_almost_eq!(a, b); - } - Ok(dur) => { - assert!(b > a); - assert_almost_eq!(b - dur, a); - assert_almost_eq!(a + dur, b); - } - Err(dur) => { - let dur = dur.duration(); - assert!(a > b); - assert_almost_eq!(b + dur, a); - assert_almost_eq!(a - dur, b); - } - } - - let second = Duration::new(1, 0); - assert_almost_eq!(a.duration_since(a - second).unwrap(), second); - assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second); - - assert_almost_eq!(a - second + second, a); - assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); - - let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); - let one_second_from_epoch2 = - UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); - assert_eq!(one_second_from_epoch, one_second_from_epoch2); - - // checked_add_duration will not panic on overflow - let mut maybe_t = Some(SystemTime::UNIX_EPOCH); - let max_duration = Duration::from_secs(u64::MAX); - // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. - for _ in 0..2 { - maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); - } - assert_eq!(maybe_t, None); - - // checked_add_duration calculates the right time and will work for another year - let year = Duration::from_secs(60 * 60 * 24 * 365); - assert_eq!(a + year, a.checked_add(year).unwrap()); - } - - #[test] - fn system_time_elapsed() { - let a = SystemTime::now(); - drop(a.elapsed()); - } - - #[test] - fn since_epoch() { - let ts = SystemTime::now(); - let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap(); - let b = ts.duration_since(UNIX_EPOCH).unwrap(); - assert!(b > a); - assert_eq!(b - a, Duration::new(1, 0)); - - let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; - - // Right now for CI this test is run in an emulator, and apparently the - // aarch64 emulator's sense of time is that we're still living in the - // 70s. This is also true for riscv (also qemu) - // - // Otherwise let's assume that we're all running computers later than - // 2000. - if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") { - assert!(a > thirty_years); - } - - // let's assume that we're all running computers earlier than 2090. - // Should give us ~70 years to fix this! - let hundred_twenty_years = thirty_years * 4; - assert!(a < hundred_twenty_years); - } -} diff --git a/library/std/src/time/tests.rs b/library/std/src/time/tests.rs new file mode 100644 index 0000000000..783bf49f31 --- /dev/null +++ b/library/std/src/time/tests.rs @@ -0,0 +1,165 @@ +use super::{Duration, Instant, SystemTime, UNIX_EPOCH}; + +macro_rules! assert_almost_eq { + ($a:expr, $b:expr) => {{ + let (a, b) = ($a, $b); + if a != b { + let (a, b) = if a > b { (a, b) } else { (b, a) }; + assert!(a - Duration::new(0, 1000) <= b, "{:?} is not almost equal to {:?}", a, b); + } + }}; +} + +#[test] +fn instant_monotonic() { + let a = Instant::now(); + let b = Instant::now(); + assert!(b >= a); +} + +#[test] +fn instant_elapsed() { + let a = Instant::now(); + a.elapsed(); +} + +#[test] +fn instant_math() { + let a = Instant::now(); + let b = Instant::now(); + println!("a: {:?}", a); + println!("b: {:?}", b); + let dur = b.duration_since(a); + println!("dur: {:?}", dur); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + + let second = Duration::new(1, 0); + assert_almost_eq!(a - second + second, a); + assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); + + // checked_add_duration will not panic on overflow + let mut maybe_t = Some(Instant::now()); + let max_duration = Duration::from_secs(u64::MAX); + // in case `Instant` can store `>= now + max_duration`. + for _ in 0..2 { + maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); + } + assert_eq!(maybe_t, None); + + // checked_add_duration calculates the right time and will work for another year + let year = Duration::from_secs(60 * 60 * 24 * 365); + assert_eq!(a + year, a.checked_add(year).unwrap()); +} + +#[test] +fn instant_math_is_associative() { + let now = Instant::now(); + let offset = Duration::from_millis(5); + // Changing the order of instant math shouldn't change the results, + // especially when the expression reduces to X + identity. + assert_eq!((now + offset) - now, (now - now) + offset); +} + +#[test] +#[should_panic] +fn instant_duration_since_panic() { + let a = Instant::now(); + (a - Duration::new(1, 0)).duration_since(a); +} + +#[test] +fn instant_checked_duration_since_nopanic() { + let now = Instant::now(); + let earlier = now - Duration::new(1, 0); + let later = now + Duration::new(1, 0); + assert_eq!(earlier.checked_duration_since(now), None); + assert_eq!(later.checked_duration_since(now), Some(Duration::new(1, 0))); + assert_eq!(now.checked_duration_since(now), Some(Duration::new(0, 0))); +} + +#[test] +fn instant_saturating_duration_since_nopanic() { + let a = Instant::now(); + let ret = (a - Duration::new(1, 0)).saturating_duration_since(a); + assert_eq!(ret, Duration::new(0, 0)); +} + +#[test] +fn system_time_math() { + let a = SystemTime::now(); + let b = SystemTime::now(); + match b.duration_since(a) { + Ok(dur) if dur == Duration::new(0, 0) => { + assert_almost_eq!(a, b); + } + Ok(dur) => { + assert!(b > a); + assert_almost_eq!(b - dur, a); + assert_almost_eq!(a + dur, b); + } + Err(dur) => { + let dur = dur.duration(); + assert!(a > b); + assert_almost_eq!(b + dur, a); + assert_almost_eq!(a - dur, b); + } + } + + let second = Duration::new(1, 0); + assert_almost_eq!(a.duration_since(a - second).unwrap(), second); + assert_almost_eq!(a.duration_since(a + second).unwrap_err().duration(), second); + + assert_almost_eq!(a - second + second, a); + assert_almost_eq!(a.checked_sub(second).unwrap().checked_add(second).unwrap(), a); + + let one_second_from_epoch = UNIX_EPOCH + Duration::new(1, 0); + let one_second_from_epoch2 = + UNIX_EPOCH + Duration::new(0, 500_000_000) + Duration::new(0, 500_000_000); + assert_eq!(one_second_from_epoch, one_second_from_epoch2); + + // checked_add_duration will not panic on overflow + let mut maybe_t = Some(SystemTime::UNIX_EPOCH); + let max_duration = Duration::from_secs(u64::MAX); + // in case `SystemTime` can store `>= UNIX_EPOCH + max_duration`. + for _ in 0..2 { + maybe_t = maybe_t.and_then(|t| t.checked_add(max_duration)); + } + assert_eq!(maybe_t, None); + + // checked_add_duration calculates the right time and will work for another year + let year = Duration::from_secs(60 * 60 * 24 * 365); + assert_eq!(a + year, a.checked_add(year).unwrap()); +} + +#[test] +fn system_time_elapsed() { + let a = SystemTime::now(); + drop(a.elapsed()); +} + +#[test] +fn since_epoch() { + let ts = SystemTime::now(); + let a = ts.duration_since(UNIX_EPOCH + Duration::new(1, 0)).unwrap(); + let b = ts.duration_since(UNIX_EPOCH).unwrap(); + assert!(b > a); + assert_eq!(b - a, Duration::new(1, 0)); + + let thirty_years = Duration::new(1, 0) * 60 * 60 * 24 * 365 * 30; + + // Right now for CI this test is run in an emulator, and apparently the + // aarch64 emulator's sense of time is that we're still living in the + // 70s. This is also true for riscv (also qemu) + // + // Otherwise let's assume that we're all running computers later than + // 2000. + if !cfg!(target_arch = "aarch64") && !cfg!(target_arch = "riscv64") { + assert!(a > thirty_years); + } + + // let's assume that we're all running computers earlier than 2090. + // Should give us ~70 years to fix this! + let hundred_twenty_years = thirty_years * 4; + assert!(a < hundred_twenty_years); +} diff --git a/library/stdarch/crates/core_arch/avx512f.md b/library/stdarch/crates/core_arch/avx512f.md new file mode 100644 index 0000000000..c978a63461 --- /dev/null +++ b/library/stdarch/crates/core_arch/avx512f.md @@ -0,0 +1,1418 @@ +

["AVX512F"]

+ + * [x] [`_mm512_abs_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_epi32&expand=5236) + * [x] [`_mm512_abs_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_epi64&expand=5236) + * [x] [`_mm512_abs_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_pd&expand=5236) + * [x] [`_mm512_abs_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_abs_ps&expand=5236) + * [x] [`_mm512_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_epi32&expand=5236) + * [x] [`_mm512_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_epi64&expand=5236) + * [x] [`_mm512_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_pd&expand=5236) + * [x] [`_mm512_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_ps&expand=5236) + * [x] [`_mm512_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_round_pd&expand=5236) + * [x] [`_mm512_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_add_round_ps&expand=5236) + * [ ] [`_mm512_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi32&expand=5236) + * [ ] [`_mm512_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_alignr_epi64&expand=5236) + * [x] [`_mm512_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_epi32&expand=5236) + * [x] [`_mm512_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_epi64&expand=5236) + * [x] [`_mm512_and_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_and_si512&expand=5236) + * [ ] [`_mm512_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_andnot_epi32&expand=5236) + * [ ] [`_mm512_andnot_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_andnot_epi64&expand=5236) + * [ ] [`_mm512_andnot_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_andnot_si512&expand=5236) + * [ ] [`_mm512_broadcast_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_f32x4&expand=5236) + * [ ] [`_mm512_broadcast_f64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_f64x4&expand=5236) + * [ ] [`_mm512_broadcast_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_i32x4&expand=5236) + * [ ] [`_mm512_broadcast_i64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcast_i64x4&expand=5236) + * [ ] [`_mm512_broadcastd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastd_epi32&expand=5236) + * [ ] [`_mm512_broadcastq_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastq_epi64&expand=5236) + * [ ] [`_mm512_broadcastsd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastsd_pd&expand=5236) + * [ ] [`_mm512_broadcastss_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_broadcastss_ps&expand=5236) + * [ ] [`_mm512_castpd128_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd128_pd512&expand=5236) + * [ ] [`_mm512_castpd256_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd256_pd512&expand=5236) + * [ ] [`_mm512_castpd512_pd128`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd512_pd128&expand=5236) + * [ ] [`_mm512_castpd512_pd256`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd512_pd256&expand=5236) + * [ ] [`_mm512_castpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd_ps&expand=5236) + * [ ] [`_mm512_castpd_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castpd_si512&expand=5236) + * [ ] [`_mm512_castps128_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps128_ps512&expand=5236) + * [ ] [`_mm512_castps256_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps256_ps512&expand=5236) + * [ ] [`_mm512_castps512_ps128`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps512_ps128&expand=5236) + * [ ] [`_mm512_castps512_ps256`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps512_ps256&expand=5236) + * [ ] [`_mm512_castps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps_pd&expand=5236) + * [ ] [`_mm512_castps_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castps_si512&expand=5236) + * [ ] [`_mm512_castsi128_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi128_si512&expand=5236) + * [ ] [`_mm512_castsi256_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi256_si512&expand=5236) + * [ ] [`_mm512_castsi512_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_pd&expand=5236) + * [ ] [`_mm512_castsi512_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_ps&expand=5236) + * [ ] [`_mm512_castsi512_si128`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_si128&expand=5236) + * [ ] [`_mm512_castsi512_si256`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_castsi512_si256&expand=5236) + * [x] [`_mm512_cmp_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi32_mask&expand=5236) + * [x] [`_mm512_cmp_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epi64_mask&expand=5236) + * [x] [`_mm512_cmp_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu32_mask&expand=5236) + * [x] [`_mm512_cmp_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_epu64_mask&expand=5236) + * [x] [`_mm512_cmp_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_pd_mask&expand=5236) + * [x] [`_mm512_cmp_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_ps_mask&expand=5236) + * [x] [`_mm512_cmp_round_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_round_pd_mask&expand=5236) + * [x] [`_mm512_cmp_round_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmp_round_ps_mask&expand=5236) + * [x] [`_mm512_cmpeq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi32_mask&expand=5236) + * [x] [`_mm512_cmpeq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epi64_mask&expand=5236) + * [x] [`_mm512_cmpeq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu32_mask&expand=5236) + * [x] [`_mm512_cmpeq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_epu64_mask&expand=5236) + * [x] [`_mm512_cmpeq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_pd_mask&expand=5236) + * [x] [`_mm512_cmpeq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpeq_ps_mask&expand=5236) + * [x] [`_mm512_cmpge_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi32_mask&expand=5236) + * [x] [`_mm512_cmpge_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epi64_mask&expand=5236) + * [x] [`_mm512_cmpge_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu32_mask&expand=5236) + * [x] [`_mm512_cmpge_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpge_epu64_mask&expand=5236) + * [x] [`_mm512_cmpgt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi32_mask&expand=5236) + * [x] [`_mm512_cmpgt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epi64_mask&expand=5236) + * [x] [`_mm512_cmpgt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu32_mask&expand=5236) + * [x] [`_mm512_cmpgt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpgt_epu64_mask&expand=5236) + * [x] [`_mm512_cmple_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi32_mask&expand=5236) + * [x] [`_mm512_cmple_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epi64_mask&expand=5236) + * [x] [`_mm512_cmple_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu32_mask&expand=5236) + * [x] [`_mm512_cmple_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_epu64_mask&expand=5236) + * [x] [`_mm512_cmple_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_pd_mask&expand=5236) + * [x] [`_mm512_cmple_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmple_ps_mask&expand=5236) + * [x] [`_mm512_cmplt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi32_mask&expand=5236) + * [x] [`_mm512_cmplt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epi64_mask&expand=5236) + * [x] [`_mm512_cmplt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epu32_mask&expand=5236) + * [x] [`_mm512_cmplt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_epu64_mask&expand=5236) + * [x] [`_mm512_cmplt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_pd_mask&expand=5236) + * [x] [`_mm512_cmplt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmplt_ps_mask&expand=5236) + * [x] [`_mm512_cmpneq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi32_mask&expand=5236) + * [x] [`_mm512_cmpneq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epi64_mask&expand=5236) + * [x] [`_mm512_cmpneq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu32_mask&expand=5236) + * [x] [`_mm512_cmpneq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_epu64_mask&expand=5236) + * [x] [`_mm512_cmpneq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_pd_mask&expand=5236) + * [x] [`_mm512_cmpneq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpneq_ps_mask&expand=5236) + * [x] [`_mm512_cmpnle_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnle_pd_mask&expand=5236) + * [x] [`_mm512_cmpnle_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnle_ps_mask&expand=5236) + * [x] [`_mm512_cmpnlt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnlt_pd_mask&expand=5236) + * [x] [`_mm512_cmpnlt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpnlt_ps_mask&expand=5236) + * [x] [`_mm512_cmpord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpord_pd_mask&expand=5236) + * [x] [`_mm512_cmpord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpord_ps_mask&expand=5236) + * [x] [`_mm512_cmpunord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_pd_mask&expand=5236) + * [x] [`_mm512_cmpunord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cmpunord_ps_mask&expand=5236) + * [ ] [`_mm512_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepi32_ps&expand=5236) + * [ ] [`_mm512_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundepu32_ps&expand=5236) + * [ ] [`_mm512_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epi32&expand=5236) + * [ ] [`_mm512_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_epu32&expand=5236) + * [ ] [`_mm512_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundpd_ps&expand=5236) + * [ ] [`_mm512_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_epi32&expand=5236) + * [x] [`_mm512_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_epu32&expand=5236) + * [x] [`_mm512_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_pd&expand=5236) + * [ ] [`_mm512_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvt_roundps_ph&expand=5236) + * [ ] [`_mm512_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi32&expand=5236) + * [ ] [`_mm512_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi16_epi64&expand=5236) + * [ ] [`_mm512_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi16&expand=5236) + * [ ] [`_mm512_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi64&expand=5236) + * [ ] [`_mm512_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_epi8&expand=5236) + * [ ] [`_mm512_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_pd&expand=5236) + * [ ] [`_mm512_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32_ps&expand=5236) + * [ ] [`_mm512_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi32lo_pd&expand=5236) + * [ ] [`_mm512_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi16&expand=5236) + * [ ] [`_mm512_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi32&expand=5236) + * [ ] [`_mm512_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi64_epi8&expand=5236) + * [ ] [`_mm512_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi32&expand=5236) + * [ ] [`_mm512_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepi8_epi64&expand=5236) + * [ ] [`_mm512_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi32&expand=5236) + * [ ] [`_mm512_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu16_epi64&expand=5236) + * [ ] [`_mm512_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_epi64&expand=5236) + * [ ] [`_mm512_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_pd&expand=5236) + * [ ] [`_mm512_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32_ps&expand=5236) + * [ ] [`_mm512_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu32lo_pd&expand=5236) + * [ ] [`_mm512_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi32&expand=5236) + * [ ] [`_mm512_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_epi32&expand=5236) + * [x] [`_mm512_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_epu32&expand=5236) + * [ ] [`_mm512_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_ps&expand=5236) + * [ ] [`_mm512_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpd_pslo&expand=5236) + * [ ] [`_mm512_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtph_ps&expand=5236) + * [x] [`_mm512_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_epi32&expand=5236) + * [x] [`_mm512_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_epu32&expand=5236) + * [ ] [`_mm512_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_pd&expand=5236) + * [ ] [`_mm512_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtps_ph&expand=5236) + * [ ] [`_mm512_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtpslo_pd&expand=5236) + * [ ] [`_mm512_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi16&expand=5236) + * [ ] [`_mm512_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi32_epi8&expand=5236) + * [ ] [`_mm512_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi16&expand=5236) + * [ ] [`_mm512_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi32&expand=5236) + * [ ] [`_mm512_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtsepi64_epi8&expand=5236) + * [x] [`_mm512_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundpd_epi32&expand=5236) + * [x] [`_mm512_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundpd_epu32&expand=5236) + * [x] [`_mm512_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundps_epi32&expand=5236) + * [x] [`_mm512_cvtt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtt_roundps_epu32&expand=5236) + * [x] [`_mm512_cvttpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttpd_epi32&expand=5236) + * [x] [`_mm512_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttpd_epu32&expand=5236) + * [x] [`_mm512_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttps_epi32&expand=5236) + * [x] [`_mm512_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvttps_epu32&expand=5236) + * [ ] [`_mm512_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi16&expand=5236) + * [ ] [`_mm512_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi32_epi8&expand=5236) + * [ ] [`_mm512_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi16&expand=5236) + * [ ] [`_mm512_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi32&expand=5236) + * [ ] [`_mm512_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_cvtusepi64_epi8&expand=5236) + * [x] [`_mm512_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_pd&expand=5236) + * [x] [`_mm512_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_ps&expand=5236) + * [x] [`_mm512_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_round_pd&expand=5236) + * [x] [`_mm512_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_div_round_ps&expand=5236) + * [x] [`_mm512_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extractf32x4_ps&expand=5236) + * [ ] [`_mm512_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extractf64x4_pd&expand=5236) + * [ ] [`_mm512_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti32x4_epi32&expand=5236) + * [ ] [`_mm512_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_extracti64x4_epi64&expand=5236) + * [ ] [`_mm512_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_pd&expand=5236) + * [ ] [`_mm512_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_ps&expand=5236) + * [ ] [`_mm512_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_pd&expand=5236) + * [ ] [`_mm512_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_pd&expand=5236) + * [x] [`_mm512_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_ps&expand=5236) + * [x] [`_mm512_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_round_pd&expand=5236) + * [x] [`_mm512_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmadd_round_ps&expand=5236) + * [x] [`_mm512_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_pd&expand=5236) + * [x] [`_mm512_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_ps&expand=5236) + * [x] [`_mm512_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_pd&expand=5236) + * [x] [`_mm512_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_ps&expand=5236) + * [x] [`_mm512_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_round_pd&expand=5236) + * [x] [`_mm512_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsub_round_ps&expand=5236) + * [x] [`_mm512_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_pd&expand=5236) + * [x] [`_mm512_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_ps&expand=5236) + * [x] [`_mm512_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_pd&expand=5236) + * [x] [`_mm512_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_ps&expand=5236) + * [x] [`_mm512_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_pd&expand=5236) + * [x] [`_mm512_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_ps&expand=5236) + * [x] [`_mm512_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_getexp_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_pd&expand=5236) + * [x] [`_mm512_getexp_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_ps&expand=5236) + * [x] [`_mm512_getexp_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_round_pd&expand=5236) + * [x] [`_mm512_getexp_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getexp_round_ps&expand=5236) + * [x] [`_mm512_getmant_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_pd&expand=5236) + * [x] [`_mm512_getmant_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_ps&expand=5236) + * [x] [`_mm512_getmant_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_round_pd&expand=5236) + * [x] [`_mm512_getmant_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_getmant_round_ps&expand=5236) + * [ ] [`_mm512_i32extgather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extgather_epi32&expand=5236) + * [ ] [`_mm512_i32extgather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extgather_ps&expand=5236) + * [ ] [`_mm512_i32extscatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extscatter_epi32&expand=5236) + * [ ] [`_mm512_i32extscatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32extscatter_ps&expand=5236) + * [x] [`_mm512_i32gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi32&expand=5236) + * [x] [`_mm512_i32gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_epi64&expand=5236) + * [x] [`_mm512_i32gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_pd&expand=5236) + * [x] [`_mm512_i32gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32gather_ps&expand=5236) + * [ ] [`_mm512_i32loextgather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextgather_epi64&expand=5236) + * [ ] [`_mm512_i32loextgather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextgather_pd&expand=5236) + * [ ] [`_mm512_i32loextscatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextscatter_epi64&expand=5236) + * [ ] [`_mm512_i32loextscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loextscatter_pd&expand=5236) + * [ ] [`_mm512_i32logather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32logather_epi64&expand=5236) + * [ ] [`_mm512_i32logather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32logather_pd&expand=5236) + * [ ] [`_mm512_i32loscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32loscatter_pd&expand=5236) + * [x] [`_mm512_i32scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_epi32&expand=5236) + * [x] [`_mm512_i32scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_epi64&expand=5236) + * [x] [`_mm512_i32scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_pd&expand=5236) + * [x] [`_mm512_i32scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i32scatter_ps&expand=5236) + * [x] [`_mm512_i64gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi32&expand=5236) + * [x] [`_mm512_i64gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_epi64&expand=5236) + * [x] [`_mm512_i64gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_pd&expand=5236) + * [x] [`_mm512_i64gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64gather_ps&expand=5236) + * [x] [`_mm512_i64scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi32&expand=5236) + * [x] [`_mm512_i64scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_epi64&expand=5236) + * [x] [`_mm512_i64scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_pd&expand=5236) + * [x] [`_mm512_i64scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_i64scatter_ps&expand=5236) + * [ ] [`_mm512_insertf32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_insertf32x4&expand=5236) + * [ ] [`_mm512_insertf64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_insertf64x4&expand=5236) + * [ ] [`_mm512_inserti32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_inserti32x4&expand=5236) + * [ ] [`_mm512_inserti64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_inserti64x4&expand=5236) + * [ ] [`_mm512_int2mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_int2mask&expand=5236) + * [x] [`_mm512_kand`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kand&expand=5236) + * [x] [`_mm512_kandn`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kandn&expand=5236) + * [x] [`_mm512_kmov`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kmov&expand=5236) + * [x] [`_mm512_knot`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_knot&expand=5236) + * [x] [`_mm512_kor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kor&expand=5236) + * [ ] [`_mm512_kortestc`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kortestc&expand=5236) + * [ ] [`_mm512_kortestz`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kortestz&expand=5236) + * [ ] [`_mm512_kunpackb`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kunpackb&expand=5236) + * [x] [`_mm512_kxnor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kxnor&expand=5236) + * [x] [`_mm512_kxor`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_kxor&expand=5236) + * [ ] [`_mm512_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi32&expand=5236) + * [ ] [`_mm512_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_epi64&expand=5236) + * [ ] [`_mm512_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_pd&expand=5236) + * [ ] [`_mm512_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_ps&expand=5236) + * [ ] [`_mm512_load_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_load_si512&expand=5236) + * [x] [`_mm512_loadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_pd&expand=5236) + * [x] [`_mm512_loadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_ps&expand=5236) + * [ ] [`_mm512_loadu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_loadu_si512&expand=5236) + * [x] [`_mm512_mask2_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_epi32&expand=5236) + * [x] [`_mm512_mask2_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_epi64&expand=5236) + * [x] [`_mm512_mask2_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_pd&expand=5236) + * [x] [`_mm512_mask2_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2_permutex2var_ps&expand=5236) + * [ ] [`_mm512_mask2int`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask2int&expand=5236) + * [x] [`_mm512_mask3_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_pd&expand=5236) + * [x] [`_mm512_mask3_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_ps&expand=5236) + * [x] [`_mm512_mask3_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmadd_round_ps&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_pd&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_ps&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_mask3_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_pd&expand=5236) + * [x] [`_mm512_mask3_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_ps&expand=5236) + * [x] [`_mm512_mask3_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsub_round_ps&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_pd&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_ps&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_mask3_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_mask3_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_pd&expand=5236) + * [x] [`_mm512_mask3_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_ps&expand=5236) + * [x] [`_mm512_mask3_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_mask3_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_mask3_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_pd&expand=5236) + * [x] [`_mm512_mask3_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_ps&expand=5236) + * [x] [`_mm512_mask3_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_mask3_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask3_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_mask_abs_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_epi32&expand=5236) + * [x] [`_mm512_mask_abs_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_epi64&expand=5236) + * [x] [`_mm512_mask_abs_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_pd&expand=5236) + * [x] [`_mm512_mask_abs_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_abs_ps&expand=5236) + * [x] [`_mm512_mask_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_epi32&expand=5236) + * [x] [`_mm512_mask_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_epi64&expand=5236) + * [x] [`_mm512_mask_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_pd&expand=5236) + * [x] [`_mm512_mask_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_ps&expand=5236) + * [x] [`_mm512_mask_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_round_pd&expand=5236) + * [x] [`_mm512_mask_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_add_round_ps&expand=5236) + * [ ] [`_mm512_mask_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi32&expand=5236) + * [ ] [`_mm512_mask_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_alignr_epi64&expand=5236) + * [x] [`_mm512_mask_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_and_epi32&expand=5236) + * [x] [`_mm512_mask_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_and_epi64&expand=5236) + * [ ] [`_mm512_mask_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_andnot_epi32&expand=5236) + * [ ] [`_mm512_mask_andnot_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_andnot_epi64&expand=5236) + * [ ] [`_mm512_mask_blend_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_epi32&expand=5236) + * [ ] [`_mm512_mask_blend_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_epi64&expand=5236) + * [ ] [`_mm512_mask_blend_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_pd&expand=5236) + * [ ] [`_mm512_mask_blend_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_blend_ps&expand=5236) + * [ ] [`_mm512_mask_broadcast_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_f32x4&expand=5236) + * [ ] [`_mm512_mask_broadcast_f64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_f64x4&expand=5236) + * [ ] [`_mm512_mask_broadcast_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_i32x4&expand=5236) + * [ ] [`_mm512_mask_broadcast_i64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcast_i64x4&expand=5236) + * [ ] [`_mm512_mask_broadcastd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastd_epi32&expand=5236) + * [ ] [`_mm512_mask_broadcastq_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastq_epi64&expand=5236) + * [ ] [`_mm512_mask_broadcastsd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastsd_pd&expand=5236) + * [ ] [`_mm512_mask_broadcastss_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_broadcastss_ps&expand=5236) + * [x] [`_mm512_mask_cmp_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmp_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmp_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmp_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmp_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmp_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmp_round_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_round_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmp_round_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmp_round_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpeq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpeq_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpge_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpge_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpgt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpgt_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmple_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmple_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmple_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmple_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmplt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmplt_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi32_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epi64_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epu32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu32_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_epu64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_epu64_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpneq_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpneq_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpnle_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnle_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpnle_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnle_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpnlt_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnlt_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpnlt_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpnlt_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpord_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpord_ps_mask&expand=5236) + * [x] [`_mm512_mask_cmpunord_pd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_pd_mask&expand=5236) + * [x] [`_mm512_mask_cmpunord_ps_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cmpunord_ps_mask&expand=5236) + * [ ] [`_mm512_mask_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi32&expand=5236) + * [ ] [`_mm512_mask_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_epi64&expand=5236) + * [ ] [`_mm512_mask_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_pd&expand=5236) + * [ ] [`_mm512_mask_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compress_ps&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi32&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_epi64&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_pd&expand=5236) + * [ ] [`_mm512_mask_compressstoreu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_compressstoreu_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepi32_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundepu32_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epi32&expand=5236) + * [ ] [`_mm512_mask_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_epu32&expand=5236) + * [ ] [`_mm512_mask_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundpd_ps&expand=5236) + * [ ] [`_mm512_mask_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_mask_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_epi32&expand=5236) + * [x] [`_mm512_mask_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_epu32&expand=5236) + * [ ] [`_mm512_mask_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_pd&expand=5236) + * [ ] [`_mm512_mask_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvt_roundps_ph&expand=5236) + * [ ] [`_mm512_mask_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi16_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_ps&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi32lo_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi64_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepi8_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu16_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_epi64&expand=5236) + * [ ] [`_mm512_mask_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32_ps&expand=5236) + * [ ] [`_mm512_mask_cvtepu32lo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu32lo_pd&expand=5236) + * [ ] [`_mm512_mask_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_mask_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_epi32&expand=5236) + * [x] [`_mm512_mask_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_epu32&expand=5236) + * [ ] [`_mm512_mask_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_ps&expand=5236) + * [ ] [`_mm512_mask_cvtpd_pslo`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpd_pslo&expand=5236) + * [ ] [`_mm512_mask_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtph_ps&expand=5236) + * [x] [`_mm512_mask_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_epi32&expand=5236) + * [x] [`_mm512_mask_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_epu32&expand=5236) + * [x] [`_mm512_mask_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_pd&expand=5236) + * [ ] [`_mm512_mask_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtps_ph&expand=5236) + * [ ] [`_mm512_mask_cvtpslo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtpslo_pd&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi32_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtsepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtsepi64_storeu_epi8&expand=5236) + * [x] [`_mm512_mask_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundpd_epi32&expand=5236) + * [x] [`_mm512_mask_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundpd_epu32&expand=5236) + * [x] [`_mm512_mask_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundps_epi32&expand=5236) + * [x] [`_mm512_mask_cvtt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtt_roundps_epu32&expand=5236) + * [x] [`_mm512_mask_cvttpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttpd_epi32&expand=5236) + * [x] [`_mm512_mask_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttpd_epu32&expand=5236) + * [x] [`_mm512_mask_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttps_epi32&expand=5236) + * [x] [`_mm512_mask_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvttps_epu32&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi32_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi32_storeu_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_epi8&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_storeu_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi16&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_cvtusepi64_storeu_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_cvtusepi64_storeu_epi8&expand=5236) + * [x] [`_mm512_mask_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_pd&expand=5236) + * [x] [`_mm512_mask_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_ps&expand=5236) + * [x] [`_mm512_mask_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_round_pd&expand=5236) + * [x] [`_mm512_mask_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_div_round_ps&expand=5236) + * [ ] [`_mm512_mask_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi32&expand=5236) + * [ ] [`_mm512_mask_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_epi64&expand=5236) + * [ ] [`_mm512_mask_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_pd&expand=5236) + * [ ] [`_mm512_mask_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expand_ps&expand=5236) + * [ ] [`_mm512_mask_expandloadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi32&expand=5236) + * [ ] [`_mm512_mask_expandloadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_epi64&expand=5236) + * [ ] [`_mm512_mask_expandloadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_pd&expand=5236) + * [ ] [`_mm512_mask_expandloadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_expandloadu_ps&expand=5236) + * [ ] [`_mm512_mask_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf32x4_ps&expand=5236) + * [ ] [`_mm512_mask_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extractf64x4_pd&expand=5236) + * [ ] [`_mm512_mask_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti32x4_epi32&expand=5236) + * [ ] [`_mm512_mask_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_extracti64x4_epi64&expand=5236) + * [ ] [`_mm512_mask_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_pd&expand=5236) + * [ ] [`_mm512_mask_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_ps&expand=5236) + * [ ] [`_mm512_mask_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_pd&expand=5236) + * [ ] [`_mm512_mask_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_mask_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_pd&expand=5236) + * [x] [`_mm512_mask_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_ps&expand=5236) + * [x] [`_mm512_mask_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_round_pd&expand=5236) + * [x] [`_mm512_mask_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmadd_round_ps&expand=5236) + * [x] [`_mm512_mask_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_pd&expand=5236) + * [x] [`_mm512_mask_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_ps&expand=5236) + * [x] [`_mm512_mask_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_mask_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_mask_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_pd&expand=5236) + * [x] [`_mm512_mask_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_ps&expand=5236) + * [x] [`_mm512_mask_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_round_pd&expand=5236) + * [x] [`_mm512_mask_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsub_round_ps&expand=5236) + * [x] [`_mm512_mask_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_pd&expand=5236) + * [x] [`_mm512_mask_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_ps&expand=5236) + * [x] [`_mm512_mask_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_mask_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_mask_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_pd&expand=5236) + * [x] [`_mm512_mask_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_ps&expand=5236) + * [x] [`_mm512_mask_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_mask_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_mask_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_pd&expand=5236) + * [x] [`_mm512_mask_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_ps&expand=5236) + * [x] [`_mm512_mask_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_mask_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_mask_getexp_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_pd&expand=5236) + * [x] [`_mm512_mask_getexp_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_ps&expand=5236) + * [x] [`_mm512_mask_getexp_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_round_pd&expand=5236) + * [x] [`_mm512_mask_getexp_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getexp_round_ps&expand=5236) + * [x] [`_mm512_mask_getmant_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_pd&expand=5236) + * [x] [`_mm512_mask_getmant_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_ps&expand=5236) + * [x] [`_mm512_mask_getmant_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_round_pd&expand=5236) + * [x] [`_mm512_mask_getmant_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_getmant_round_ps&expand=5236) + * [ ] [`_mm512_mask_i32extgather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extgather_epi32&expand=5236) + * [ ] [`_mm512_mask_i32extgather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extgather_ps&expand=5236) + * [ ] [`_mm512_mask_i32extscatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extscatter_epi32&expand=5236) + * [ ] [`_mm512_mask_i32extscatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32extscatter_ps&expand=5236) + * [x] [`_mm512_mask_i32gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi32&expand=5236) + * [x] [`_mm512_mask_i32gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_epi64&expand=5236) + * [x] [`_mm512_mask_i32gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_pd&expand=5236) + * [x] [`_mm512_mask_i32gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32gather_ps&expand=5236) + * [ ] [`_mm512_mask_i32loextgather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextgather_epi64&expand=5236) + * [ ] [`_mm512_mask_i32loextgather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextgather_pd&expand=5236) + * [ ] [`_mm512_mask_i32loextscatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextscatter_epi64&expand=5236) + * [ ] [`_mm512_mask_i32loextscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loextscatter_pd&expand=5236) + * [ ] [`_mm512_mask_i32logather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32logather_epi64&expand=5236) + * [ ] [`_mm512_mask_i32logather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32logather_pd&expand=5236) + * [ ] [`_mm512_mask_i32loscatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32loscatter_pd&expand=5236) + * [x] [`_mm512_mask_i32scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi32&expand=5236) + * [x] [`_mm512_mask_i32scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_epi64&expand=5236) + * [x] [`_mm512_mask_i32scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_pd&expand=5236) + * [x] [`_mm512_mask_i32scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i32scatter_ps&expand=5236) + * [x] [`_mm512_mask_i64gather_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi32&expand=5236) + * [x] [`_mm512_mask_i64gather_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_epi64&expand=5236) + * [x] [`_mm512_mask_i64gather_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_pd&expand=5236) + * [x] [`_mm512_mask_i64gather_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64gather_ps&expand=5236) + * [x] [`_mm512_mask_i64scatter_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi32&expand=5236) + * [x] [`_mm512_mask_i64scatter_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_epi64&expand=5236) + * [x] [`_mm512_mask_i64scatter_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_pd&expand=5236) + * [x] [`_mm512_mask_i64scatter_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_i64scatter_ps&expand=5236) + * [ ] [`_mm512_mask_insertf32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_insertf32x4&expand=5236) + * [ ] [`_mm512_mask_insertf64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_insertf64x4&expand=5236) + * [ ] [`_mm512_mask_inserti32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_inserti32x4&expand=5236) + * [ ] [`_mm512_mask_inserti64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_inserti64x4&expand=5236) + * [ ] [`_mm512_mask_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_epi32&expand=5236) + * [ ] [`_mm512_mask_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_epi64&expand=5236) + * [ ] [`_mm512_mask_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_pd&expand=5236) + * [ ] [`_mm512_mask_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_load_ps&expand=5236) + * [ ] [`_mm512_mask_loadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_epi32&expand=5236) + * [ ] [`_mm512_mask_loadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_epi64&expand=5236) + * [ ] [`_mm512_mask_loadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_pd&expand=5236) + * [ ] [`_mm512_mask_loadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_loadu_ps&expand=5236) + * [x] [`_mm512_mask_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epi32&expand=5236) + * [x] [`_mm512_mask_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epi64&expand=5236) + * [x] [`_mm512_mask_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epu32&expand=5236) + * [x] [`_mm512_mask_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_epu64&expand=5236) + * [x] [`_mm512_mask_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_pd&expand=5236) + * [x] [`_mm512_mask_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_ps&expand=5236) + * [x] [`_mm512_mask_max_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_round_pd&expand=5236) + * [x] [`_mm512_mask_max_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_max_round_ps&expand=5236) + * [x] [`_mm512_mask_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epi32&expand=5236) + * [x] [`_mm512_mask_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epi64&expand=5236) + * [x] [`_mm512_mask_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epu32&expand=5236) + * [x] [`_mm512_mask_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_epu64&expand=5236) + * [x] [`_mm512_mask_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_pd&expand=5236) + * [x] [`_mm512_mask_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_ps&expand=5236) + * [x] [`_mm512_mask_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_round_pd&expand=5236) + * [x] [`_mm512_mask_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_min_round_ps&expand=5236) + * [ ] [`_mm512_mask_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi32&expand=5236) + * [ ] [`_mm512_mask_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_epi64&expand=5236) + * [ ] [`_mm512_mask_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_pd&expand=5236) + * [ ] [`_mm512_mask_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mov_ps&expand=5236) + * [x] [`_mm512_mask_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_movedup_pd&expand=5236) + * [x] [`_mm512_mask_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_movehdup_ps&expand=5236) + * [x] [`_mm512_mask_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_moveldup_ps&expand=5236) + * [x] [`_mm512_mask_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_epi32&expand=5236) + * [x] [`_mm512_mask_mul_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_epu32&expand=5236) + * [x] [`_mm512_mask_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_pd&expand=5236) + * [x] [`_mm512_mask_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_ps&expand=5236) + * [x] [`_mm512_mask_mul_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_round_pd&expand=5236) + * [x] [`_mm512_mask_mul_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mul_round_ps&expand=5236) + * [x] [`_mm512_mask_mullo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mullo_epi32&expand=5236) + * [x] [`_mm512_mask_mullox_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_mullox_epi64&expand=5236) + * [x] [`_mm512_mask_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_or_epi32&expand=5236) + * [x] [`_mm512_mask_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_or_epi64&expand=5236) + * [x] [`_mm512_mask_permute_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permute_pd&expand=5236) + * [x] [`_mm512_mask_permute_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permute_ps&expand=5236) + * [x] [`_mm512_mask_permutevar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutevar_epi32&expand=5236) + * [x] [`_mm512_mask_permutevar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutevar_pd&expand=5236) + * [x] [`_mm512_mask_permutevar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutevar_ps&expand=5236) + * [x] [`_mm512_mask_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_epi32&expand=5236) + * [x] [`_mm512_mask_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_epi64&expand=5236) + * [x] [`_mm512_mask_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_pd&expand=5236) + * [x] [`_mm512_mask_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex2var_ps&expand=5236) + * [x] [`_mm512_mask_permutex_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex_epi64&expand=5236) + * [x] [`_mm512_mask_permutex_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutex_pd&expand=5236) + * [x] [`_mm512_mask_permutexvar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_epi32&expand=5236) + * [x] [`_mm512_mask_permutexvar_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_epi64&expand=5236) + * [x] [`_mm512_mask_permutexvar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_pd&expand=5236) + * [x] [`_mm512_mask_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_permutexvar_ps&expand=5236) + * [x] [`_mm512_mask_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rcp14_pd&expand=5236) + * [x] [`_mm512_mask_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rcp14_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_add_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_and_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu32&expand=5236) + * [ ] [`_mm512_mask_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_epu64&expand=5236) + * [ ] [`_mm512_mask_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_max_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu32&expand=5236) + * [ ] [`_mm512_mask_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_epu64&expand=5236) + * [ ] [`_mm512_mask_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_min_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_epi64&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_pd&expand=5236) + * [ ] [`_mm512_mask_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_mul_ps&expand=5236) + * [ ] [`_mm512_mask_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi32&expand=5236) + * [ ] [`_mm512_mask_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_reduce_or_epi64&expand=5236) + * [x] [`_mm512_mask_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rol_epi32&expand=5236) + * [x] [`_mm512_mask_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rol_epi64&expand=5236) + * [x] [`_mm512_mask_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rolv_epi32&expand=5236) + * [x] [`_mm512_mask_rolv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rolv_epi64&expand=5236) + * [x] [`_mm512_mask_ror_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ror_epi32&expand=5236) + * [x] [`_mm512_mask_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ror_epi64&expand=5236) + * [x] [`_mm512_mask_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rorv_epi32&expand=5236) + * [x] [`_mm512_mask_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rorv_epi64&expand=5236) + * [ ] [`_mm512_mask_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_pd&expand=5236) + * [ ] [`_mm512_mask_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_ps&expand=5236) + * [ ] [`_mm512_mask_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_pd&expand=5236) + * [ ] [`_mm512_mask_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_roundscale_round_ps&expand=5236) + * [x] [`_mm512_mask_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rsqrt14_pd&expand=5236) + * [x] [`_mm512_mask_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_rsqrt14_ps&expand=5236) + * [ ] [`_mm512_mask_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_pd&expand=5236) + * [ ] [`_mm512_mask_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_ps&expand=5236) + * [ ] [`_mm512_mask_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_pd&expand=5236) + * [ ] [`_mm512_mask_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_scalef_round_ps&expand=5236) + * [x] [`_mm512_mask_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi32&expand=5236) + * [x] [`_mm512_mask_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_set1_epi64&expand=5236) + * [x] [`_mm512_mask_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_epi32&expand=5236) + * [x] [`_mm512_mask_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_f32x4&expand=5236) + * [x] [`_mm512_mask_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_f64x2&expand=5236) + * [x] [`_mm512_mask_shuffle_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_i32x4&expand=5236) + * [x] [`_mm512_mask_shuffle_i64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_i64x2&expand=5236) + * [x] [`_mm512_mask_shuffle_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_pd&expand=5236) + * [x] [`_mm512_mask_shuffle_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_shuffle_ps&expand=5236) + * [x] [`_mm512_mask_sll_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sll_epi32&expand=5236) + * [x] [`_mm512_mask_sll_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sll_epi64&expand=5236) + * [x] [`_mm512_mask_slli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_slli_epi32&expand=5236) + * [x] [`_mm512_mask_slli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_slli_epi64&expand=5236) + * [x] [`_mm512_mask_sllv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sllv_epi32&expand=5236) + * [x] [`_mm512_mask_sllv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sllv_epi64&expand=5236) + * [x] [`_mm512_mask_sqrt_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_pd&expand=5236) + * [x] [`_mm512_mask_sqrt_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_ps&expand=5236) + * [x] [`_mm512_mask_sqrt_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_round_pd&expand=5236) + * [x] [`_mm512_mask_sqrt_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sqrt_round_ps&expand=5236) + * [x] [`_mm512_mask_sra_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sra_epi32&expand=5236) + * [x] [`_mm512_mask_sra_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sra_epi64&expand=5236) + * [x] [`_mm512_mask_srai_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srai_epi32&expand=5236) + * [x] [`_mm512_mask_srai_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srai_epi64&expand=5236) + * [x] [`_mm512_mask_srav_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srav_epi32&expand=5236) + * [x] [`_mm512_mask_srav_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srav_epi64&expand=5236) + * [x] [`_mm512_mask_srl_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srl_epi32&expand=5236) + * [x] [`_mm512_mask_srl_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srl_epi64&expand=5236) + * [x] [`_mm512_mask_srli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srli_epi32&expand=5236) + * [x] [`_mm512_mask_srli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srli_epi64&expand=5236) + * [x] [`_mm512_mask_srlv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srlv_epi32&expand=5236) + * [x] [`_mm512_mask_srlv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_srlv_epi64&expand=5236) + * [ ] [`_mm512_mask_store_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_epi32&expand=5236) + * [ ] [`_mm512_mask_store_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_epi64&expand=5236) + * [ ] [`_mm512_mask_store_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_pd&expand=5236) + * [ ] [`_mm512_mask_store_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_store_ps&expand=5236) + * [ ] [`_mm512_mask_storeu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_epi32&expand=5236) + * [ ] [`_mm512_mask_storeu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_epi64&expand=5236) + * [ ] [`_mm512_mask_storeu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_pd&expand=5236) + * [ ] [`_mm512_mask_storeu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_storeu_ps&expand=5236) + * [x] [`_mm512_mask_sub_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_epi32&expand=5236) + * [x] [`_mm512_mask_sub_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_epi64&expand=5236) + * [x] [`_mm512_mask_sub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_pd&expand=5236) + * [x] [`_mm512_mask_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_ps&expand=5236) + * [x] [`_mm512_mask_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_round_pd&expand=5236) + * [x] [`_mm512_mask_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_sub_round_ps&expand=5236) + * [ ] [`_mm512_mask_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi32&expand=5236) + * [ ] [`_mm512_mask_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_ternarylogic_epi64&expand=5236) + * [ ] [`_mm512_mask_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi32_mask&expand=5236) + * [ ] [`_mm512_mask_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_test_epi64_mask&expand=5236) + * [ ] [`_mm512_mask_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi32_mask&expand=5236) + * [ ] [`_mm512_mask_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_testn_epi64_mask&expand=5236) + * [ ] [`_mm512_mask_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi32&expand=5236) + * [ ] [`_mm512_mask_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_epi64&expand=5236) + * [ ] [`_mm512_mask_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_pd&expand=5236) + * [ ] [`_mm512_mask_unpackhi_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpackhi_ps&expand=5236) + * [ ] [`_mm512_mask_unpacklo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_epi32&expand=5236) + * [ ] [`_mm512_mask_unpacklo_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_epi64&expand=5236) + * [ ] [`_mm512_mask_unpacklo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_pd&expand=5236) + * [ ] [`_mm512_mask_unpacklo_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_unpacklo_ps&expand=5236) + * [x] [`_mm512_mask_xor_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_xor_epi32&expand=5236) + * [x] [`_mm512_mask_xor_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mask_xor_epi64&expand=5236) + * [x] [`_mm512_maskz_abs_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_abs_epi32&expand=5236) + * [x] [`_mm512_maskz_abs_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_abs_epi64&expand=5236) + * [x] [`_mm512_maskz_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_epi32&expand=5236) + * [x] [`_mm512_maskz_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_epi64&expand=5236) + * [x] [`_mm512_maskz_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_pd&expand=5236) + * [x] [`_mm512_maskz_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_ps&expand=5236) + * [x] [`_mm512_maskz_add_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_round_pd&expand=5236) + * [x] [`_mm512_maskz_add_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_add_round_ps&expand=5236) + * [ ] [`_mm512_maskz_alignr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi32&expand=5236) + * [ ] [`_mm512_maskz_alignr_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_alignr_epi64&expand=5236) + * [x] [`_mm512_maskz_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_and_epi32&expand=5236) + * [x] [`_mm512_maskz_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_and_epi64&expand=5236) + * [ ] [`_mm512_maskz_andnot_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_andnot_epi32&expand=5236) + * [ ] [`_mm512_maskz_andnot_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_andnot_epi64&expand=5236) + * [ ] [`_mm512_maskz_broadcast_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_f32x4&expand=5236) + * [ ] [`_mm512_maskz_broadcast_f64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_f64x4&expand=5236) + * [ ] [`_mm512_maskz_broadcast_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_i32x4&expand=5236) + * [ ] [`_mm512_maskz_broadcast_i64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcast_i64x4&expand=5236) + * [ ] [`_mm512_maskz_broadcastd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastd_epi32&expand=5236) + * [ ] [`_mm512_maskz_broadcastq_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastq_epi64&expand=5236) + * [ ] [`_mm512_maskz_broadcastsd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastsd_pd&expand=5236) + * [ ] [`_mm512_maskz_broadcastss_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_broadcastss_ps&expand=5236) + * [ ] [`_mm512_maskz_compress_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi32&expand=5236) + * [ ] [`_mm512_maskz_compress_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_epi64&expand=5236) + * [ ] [`_mm512_maskz_compress_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_pd&expand=5236) + * [ ] [`_mm512_maskz_compress_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_compress_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepi32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundepu32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundpd_ps&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundph_ps&expand=5236) + * [x] [`_mm512_maskz_cvt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_pd&expand=5236) + * [ ] [`_mm512_maskz_cvt_roundps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvt_roundps_ph&expand=5236) + * [ ] [`_mm512_maskz_cvtepi16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepi16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi16_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_pd&expand=5236) + * [ ] [`_mm512_maskz_cvtepi32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvtepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi64_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtepi8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepi8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepi8_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepu16_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepu16_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu16_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepu32_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_epi64&expand=5236) + * [ ] [`_mm512_maskz_cvtepu32_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_pd&expand=5236) + * [ ] [`_mm512_maskz_cvtepu32_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu32_ps&expand=5236) + * [ ] [`_mm512_maskz_cvtepu8_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtepu8_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtepu8_epi64&expand=5236) + * [x] [`_mm512_maskz_cvtpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvtpd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtpd_ps&expand=5236) + * [ ] [`_mm512_maskz_cvtph_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtph_ps&expand=5236) + * [x] [`_mm512_maskz_cvtps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvtps_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_pd&expand=5236) + * [ ] [`_mm512_maskz_cvtps_ph`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtps_ph&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi32_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtsepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtsepi64_epi8&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundpd_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundpd_epu32&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvtt_roundps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtt_roundps_epu32&expand=5236) + * [x] [`_mm512_maskz_cvttpd_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttpd_epi32&expand=5236) + * [x] [`_mm512_maskz_cvttpd_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttpd_epu32&expand=5236) + * [x] [`_mm512_maskz_cvttps_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttps_epi32&expand=5236) + * [x] [`_mm512_maskz_cvttps_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvttps_epu32&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi32_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi32_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi32_epi8&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi64_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi16&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi64_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi32&expand=5236) + * [ ] [`_mm512_maskz_cvtusepi64_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_cvtusepi64_epi8&expand=5236) + * [x] [`_mm512_maskz_div_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_pd&expand=5236) + * [x] [`_mm512_maskz_div_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_ps&expand=5236) + * [x] [`_mm512_maskz_div_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_round_pd&expand=5236) + * [x] [`_mm512_maskz_div_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_div_round_ps&expand=5236) + * [ ] [`_mm512_maskz_expand_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi32&expand=5236) + * [ ] [`_mm512_maskz_expand_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_epi64&expand=5236) + * [ ] [`_mm512_maskz_expand_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_pd&expand=5236) + * [ ] [`_mm512_maskz_expand_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expand_ps&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi32&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_epi64&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_pd&expand=5236) + * [ ] [`_mm512_maskz_expandloadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_expandloadu_ps&expand=5236) + * [ ] [`_mm512_maskz_extractf32x4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf32x4_ps&expand=5236) + * [ ] [`_mm512_maskz_extractf64x4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extractf64x4_pd&expand=5236) + * [ ] [`_mm512_maskz_extracti32x4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti32x4_epi32&expand=5236) + * [ ] [`_mm512_maskz_extracti64x4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_extracti64x4_epi64&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_pd&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_ps&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_pd&expand=5236) + * [ ] [`_mm512_maskz_fixupimm_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fixupimm_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_pd&expand=5236) + * [x] [`_mm512_maskz_fmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_ps&expand=5236) + * [x] [`_mm512_maskz_fmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmadd_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_pd&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_ps&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmaddsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmaddsub_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_pd&expand=5236) + * [x] [`_mm512_maskz_fmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_ps&expand=5236) + * [x] [`_mm512_maskz_fmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsub_round_ps&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_pd&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_ps&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_round_pd&expand=5236) + * [x] [`_mm512_maskz_fmsubadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fmsubadd_round_ps&expand=5236) + * [x] [`_mm512_maskz_fnmadd_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_pd&expand=5236) + * [x] [`_mm512_maskz_fnmadd_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_ps&expand=5236) + * [x] [`_mm512_maskz_fnmadd_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_round_pd&expand=5236) + * [x] [`_mm512_maskz_fnmadd_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmadd_round_ps&expand=5236) + * [x] [`_mm512_maskz_fnmsub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_pd&expand=5236) + * [x] [`_mm512_maskz_fnmsub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_ps&expand=5236) + * [x] [`_mm512_maskz_fnmsub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_round_pd&expand=5236) + * [x] [`_mm512_maskz_fnmsub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_fnmsub_round_ps&expand=5236) + * [x] [`_mm512_maskz_getexp_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_pd&expand=5236) + * [x] [`_mm512_maskz_getexp_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_ps&expand=5236) + * [x] [`_mm512_maskz_getexp_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_round_pd&expand=5236) + * [x] [`_mm512_maskz_getexp_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getexp_round_ps&expand=5236) + * [x] [`_mm512_maskz_getmant_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_pd&expand=5236) + * [x] [`_mm512_maskz_getmant_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_ps&expand=5236) + * [x] [`_mm512_maskz_getmant_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_round_pd&expand=5236) + * [x] [`_mm512_maskz_getmant_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_getmant_round_ps&expand=5236) + * [ ] [`_mm512_maskz_insertf32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_insertf32x4&expand=5236) + * [ ] [`_mm512_maskz_insertf64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_insertf64x4&expand=5236) + * [ ] [`_mm512_maskz_inserti32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_inserti32x4&expand=5236) + * [ ] [`_mm512_maskz_inserti64x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_inserti64x4&expand=5236) + * [ ] [`_mm512_maskz_load_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_epi32&expand=5236) + * [ ] [`_mm512_maskz_load_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_epi64&expand=5236) + * [ ] [`_mm512_maskz_load_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_pd&expand=5236) + * [ ] [`_mm512_maskz_load_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_load_ps&expand=5236) + * [ ] [`_mm512_maskz_loadu_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_epi32&expand=5236) + * [ ] [`_mm512_maskz_loadu_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_epi64&expand=5236) + * [ ] [`_mm512_maskz_loadu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_pd&expand=5236) + * [ ] [`_mm512_maskz_loadu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_loadu_ps&expand=5236) + * [x] [`_mm512_maskz_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epi32&expand=5236) + * [x] [`_mm512_maskz_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epi64&expand=5236) + * [x] [`_mm512_maskz_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epu32&expand=5236) + * [x] [`_mm512_maskz_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_epu64&expand=5236) + * [x] [`_mm512_maskz_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_pd&expand=5236) + * [x] [`_mm512_maskz_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_ps&expand=5236) + * [x] [`_mm512_maskz_max_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_round_pd&expand=5236) + * [x] [`_mm512_maskz_max_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_max_round_ps&expand=5236) + * [x] [`_mm512_maskz_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epi32&expand=5236) + * [x] [`_mm512_maskz_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epi64&expand=5236) + * [x] [`_mm512_maskz_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epu32&expand=5236) + * [x] [`_mm512_maskz_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_epu64&expand=5236) + * [x] [`_mm512_maskz_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_pd&expand=5236) + * [x] [`_mm512_maskz_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_ps&expand=5236) + * [x] [`_mm512_maskz_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_round_pd&expand=5236) + * [x] [`_mm512_maskz_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_min_round_ps&expand=5236) + * [ ] [`_mm512_maskz_mov_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi32&expand=5236) + * [ ] [`_mm512_maskz_mov_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_epi64&expand=5236) + * [ ] [`_mm512_maskz_mov_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_pd&expand=5236) + * [ ] [`_mm512_maskz_mov_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mov_ps&expand=5236) + * [x] [`_mm512_maskz_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_movedup_pd&expand=5236) + * [x] [`_mm512_maskz_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_movehdup_ps&expand=5236) + * [x] [`_mm512_maskz_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_moveldup_ps&expand=5236) + * [x] [`_mm512_maskz_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_epi32&expand=5236) + * [x] [`_mm512_maskz_mul_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_epu32&expand=5236) + * [x] [`_mm512_maskz_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_pd&expand=5236) + * [x] [`_mm512_maskz_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_ps&expand=5236) + * [x] [`_mm512_maskz_mul_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_round_pd&expand=5236) + * [x] [`_mm512_maskz_mul_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mul_round_ps&expand=5236) + * [x] [`_mm512_maskz_mullo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_mullo_epi32&expand=5236) + * [x] [`_mm512_maskz_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_or_epi32&expand=5236) + * [x] [`_mm512_maskz_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_or_epi64&expand=5236) + * [x] [`_mm512_maskz_permute_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permute_pd&expand=5236) + * [x] [`_mm512_maskz_permute_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permute_ps&expand=5236) + * [x] [`_mm512_maskz_permutevar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutevar_pd&expand=5236) + * [x] [`_mm512_maskz_permutevar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutevar_ps&expand=5236) + * [x] [`_mm512_maskz_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_epi32&expand=5236) + * [x] [`_mm512_maskz_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_epi64&expand=5236) + * [x] [`_mm512_maskz_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_pd&expand=5236) + * [x] [`_mm512_maskz_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex2var_ps&expand=5236) + * [x] [`_mm512_maskz_permutex_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex_epi64&expand=5236) + * [x] [`_mm512_maskz_permutex_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutex_pd&expand=5236) + * [x] [`_mm512_maskz_permutexvar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_epi32&expand=5236) + * [x] [`_mm512_maskz_permutexvar_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_epi64&expand=5236) + * [x] [`_mm512_maskz_permutexvar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_pd&expand=5236) + * [x] [`_mm512_maskz_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_permutexvar_ps&expand=5236) + * [x] [`_mm512_maskz_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rcp14_pd&expand=5236) + * [x] [`_mm512_maskz_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rcp14_ps&expand=5236) + * [x] [`_mm512_maskz_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rol_epi32&expand=5236) + * [x] [`_mm512_maskz_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rol_epi64&expand=5236) + * [x] [`_mm512_maskz_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rolv_epi32&expand=5236) + * [x] [`_mm512_maskz_rolv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rolv_epi64&expand=5236) + * [x] [`_mm512_maskz_ror_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ror_epi32&expand=5236) + * [x] [`_mm512_maskz_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ror_epi64&expand=5236) + * [x] [`_mm512_maskz_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rorv_epi32&expand=5236) + * [x] [`_mm512_maskz_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rorv_epi64&expand=5236) + * [ ] [`_mm512_maskz_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_pd&expand=5236) + * [ ] [`_mm512_maskz_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_ps&expand=5236) + * [ ] [`_mm512_maskz_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_pd&expand=5236) + * [ ] [`_mm512_maskz_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_roundscale_round_ps&expand=5236) + * [x] [`_mm512_maskz_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rsqrt14_pd&expand=5236) + * [x] [`_mm512_maskz_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_rsqrt14_ps&expand=5236) + * [ ] [`_mm512_maskz_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_pd&expand=5236) + * [ ] [`_mm512_maskz_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_ps&expand=5236) + * [ ] [`_mm512_maskz_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_pd&expand=5236) + * [ ] [`_mm512_maskz_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_scalef_round_ps&expand=5236) + * [ ] [`_mm512_maskz_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi32&expand=5236) + * [ ] [`_mm512_maskz_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_set1_epi64&expand=5236) + * [x] [`_mm512_maskz_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_epi32&expand=5236) + * [x] [`_mm512_maskz_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_f32x4&expand=5236) + * [x] [`_mm512_maskz_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_f64x2&expand=5236) + * [x] [`_mm512_maskz_shuffle_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_i32x4&expand=5236) + * [x] [`_mm512_maskz_shuffle_i64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_i64x2&expand=5236) + * [x] [`_mm512_maskz_shuffle_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_pd&expand=5236) + * [x] [`_mm512_maskz_shuffle_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_shuffle_ps&expand=5236) + * [x] [`_mm512_maskz_sll_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sll_epi32&expand=5236) + * [x] [`_mm512_maskz_sll_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sll_epi64&expand=5236) + * [x] [`_mm512_maskz_slli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_slli_epi32&expand=5236) + * [x] [`_mm512_maskz_slli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_slli_epi64&expand=5236) + * [x] [`_mm512_maskz_sllv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sllv_epi32&expand=5236) + * [x] [`_mm512_maskz_sllv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sllv_epi64&expand=5236) + * [x] [`_mm512_maskz_sqrt_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_pd&expand=5236) + * [x] [`_mm512_maskz_sqrt_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_ps&expand=5236) + * [x] [`_mm512_maskz_sqrt_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_round_pd&expand=5236) + * [x] [`_mm512_maskz_sqrt_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sqrt_round_ps&expand=5236) + * [x] [`_mm512_maskz_sra_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sra_epi32&expand=5236) + * [x] [`_mm512_maskz_sra_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sra_epi64&expand=5236) + * [x] [`_mm512_maskz_srai_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srai_epi32&expand=5236) + * [x] [`_mm512_maskz_srai_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srai_epi64&expand=5236) + * [x] [`_mm512_maskz_srav_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srav_epi32&expand=5236) + * [x] [`_mm512_maskz_srav_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srav_epi64&expand=5236) + * [x] [`_mm512_maskz_srl_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srl_epi32&expand=5236) + * [x] [`_mm512_maskz_srl_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srl_epi64&expand=5236) + * [x] [`_mm512_maskz_srli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srli_epi32&expand=5236) + * [x] [`_mm512_maskz_srli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srli_epi64&expand=5236) + * [x] [`_mm512_maskz_srlv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srlv_epi32&expand=5236) + * [x] [`_mm512_maskz_srlv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_srlv_epi64&expand=5236) + * [x] [`_mm512_maskz_sub_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_epi32&expand=5236) + * [x] [`_mm512_maskz_sub_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_epi64&expand=5236) + * [x] [`_mm512_maskz_sub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_pd&expand=5236) + * [x] [`_mm512_maskz_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_ps&expand=5236) + * [x] [`_mm512_maskz_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_round_pd&expand=5236) + * [x] [`_mm512_maskz_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_sub_round_ps&expand=5236) + * [ ] [`_mm512_maskz_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi32&expand=5236) + * [ ] [`_mm512_maskz_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_ternarylogic_epi64&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi32&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_epi64&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_pd&expand=5236) + * [ ] [`_mm512_maskz_unpackhi_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpackhi_ps&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_epi32&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_epi64&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_pd&expand=5236) + * [ ] [`_mm512_maskz_unpacklo_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_unpacklo_ps&expand=5236) + * [x] [`_mm512_maskz_xor_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_xor_epi32&expand=5236) + * [x] [`_mm512_maskz_xor_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_maskz_xor_epi64&expand=5236) + * [x] [`_mm512_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epi32&expand=5236) + * [x] [`_mm512_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epi64&expand=5236) + * [x] [`_mm512_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epu32&expand=5236) + * [x] [`_mm512_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_epu64&expand=5236) + * [x] [`_mm512_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_pd&expand=5236) + * [x] [`_mm512_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_ps&expand=5236) + * [x] [`_mm512_max_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_round_pd&expand=5236) + * [x] [`_mm512_max_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_max_round_ps&expand=5236) + * [x] [`_mm512_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epi32&expand=5236) + * [x] [`_mm512_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epi64&expand=5236) + * [x] [`_mm512_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epu32&expand=5236) + * [x] [`_mm512_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_epu64&expand=5236) + * [x] [`_mm512_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_pd&expand=5236) + * [x] [`_mm512_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_ps&expand=5236) + * [x] [`_mm512_min_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_round_pd&expand=5236) + * [x] [`_mm512_min_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_min_round_ps&expand=5236) + * [x] [`_mm512_movedup_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movedup_pd&expand=5236) + * [x] [`_mm512_movehdup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_movehdup_ps&expand=5236) + * [x] [`_mm512_moveldup_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_moveldup_ps&expand=5236) + * [x] [`_mm512_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_epi32&expand=5236) + * [x] [`_mm512_mul_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_epu32&expand=5236) + * [x] [`_mm512_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_pd&expand=5236) + * [x] [`_mm512_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_ps&expand=5236) + * [x] [`_mm512_mul_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_round_pd&expand=5236) + * [x] [`_mm512_mul_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mul_round_ps&expand=5236) + * [x] [`_mm512_mullo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mullo_epi32&expand=5236) + * [x] [`_mm512_mullox_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_mullox_epi64&expand=5236) + * [x] [`_mm512_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_or_epi32&expand=5236) + * [x] [`_mm512_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_or_epi64&expand=5236) + * [x] [`_mm512_or_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_or_si512&expand=5236) + * [x] [`_mm512_permute_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permute_pd&expand=5236) + * [x] [`_mm512_permute_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permute_ps&expand=5236) + * [x] [`_mm512_permutevar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutevar_epi32&expand=5236) + * [x] [`_mm512_permutevar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutevar_pd&expand=5236) + * [x] [`_mm512_permutevar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutevar_ps&expand=5236) + * [x] [`_mm512_permutex2var_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_epi32&expand=5236) + * [x] [`_mm512_permutex2var_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_epi64&expand=5236) + * [x] [`_mm512_permutex2var_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_pd&expand=5236) + * [x] [`_mm512_permutex2var_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex2var_ps&expand=5236) + * [x] [`_mm512_permutex_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex_epi64&expand=5236) + * [x] [`_mm512_permutex_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutex_pd&expand=5236) + * [x] [`_mm512_permutexvar_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_epi32&expand=5236) + * [x] [`_mm512_permutexvar_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_epi64&expand=5236) + * [x] [`_mm512_permutexvar_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_pd&expand=5236) + * [x] [`_mm512_permutexvar_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_permutexvar_ps&expand=5236) + * [x] [`_mm512_rcp14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rcp14_pd&expand=5236) + * [x] [`_mm512_rcp14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rcp14_ps&expand=5236) + * [ ] [`_mm512_reduce_add_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi32&expand=5236) + * [ ] [`_mm512_reduce_add_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_epi64&expand=5236) + * [ ] [`_mm512_reduce_add_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_pd&expand=5236) + * [ ] [`_mm512_reduce_add_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_add_ps&expand=5236) + * [ ] [`_mm512_reduce_and_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi32&expand=5236) + * [ ] [`_mm512_reduce_and_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_and_epi64&expand=5236) + * [ ] [`_mm512_reduce_max_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi32&expand=5236) + * [ ] [`_mm512_reduce_max_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epi64&expand=5236) + * [ ] [`_mm512_reduce_max_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu32&expand=5236) + * [ ] [`_mm512_reduce_max_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_epu64&expand=5236) + * [ ] [`_mm512_reduce_max_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_pd&expand=5236) + * [ ] [`_mm512_reduce_max_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_max_ps&expand=5236) + * [ ] [`_mm512_reduce_min_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi32&expand=5236) + * [ ] [`_mm512_reduce_min_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epi64&expand=5236) + * [ ] [`_mm512_reduce_min_epu32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu32&expand=5236) + * [ ] [`_mm512_reduce_min_epu64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_epu64&expand=5236) + * [ ] [`_mm512_reduce_min_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_pd&expand=5236) + * [ ] [`_mm512_reduce_min_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_min_ps&expand=5236) + * [ ] [`_mm512_reduce_mul_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi32&expand=5236) + * [ ] [`_mm512_reduce_mul_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_epi64&expand=5236) + * [ ] [`_mm512_reduce_mul_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_pd&expand=5236) + * [ ] [`_mm512_reduce_mul_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_mul_ps&expand=5236) + * [ ] [`_mm512_reduce_or_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi32&expand=5236) + * [ ] [`_mm512_reduce_or_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_reduce_or_epi64&expand=5236) + * [x] [`_mm512_rol_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rol_epi32&expand=5236) + * [x] [`_mm512_rol_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rol_epi64&expand=5236) + * [x] [`_mm512_rolv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rolv_epi32&expand=5236) + * [x] [`_mm512_rolv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rolv_epi64&expand=5236) + * [x] [`_mm512_ror_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ror_epi32&expand=5236) + * [x] [`_mm512_ror_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ror_epi64&expand=5236) + * [x] [`_mm512_rorv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rorv_epi32&expand=5236) + * [x] [`_mm512_rorv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rorv_epi64&expand=5236) + * [ ] [`_mm512_roundscale_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_pd&expand=5236) + * [ ] [`_mm512_roundscale_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_ps&expand=5236) + * [ ] [`_mm512_roundscale_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_pd&expand=5236) + * [ ] [`_mm512_roundscale_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_roundscale_round_ps&expand=5236) + * [x] [`_mm512_rsqrt14_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rsqrt14_pd&expand=5236) + * [x] [`_mm512_rsqrt14_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_rsqrt14_ps&expand=5236) + * [ ] [`_mm512_scalef_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_pd&expand=5236) + * [ ] [`_mm512_scalef_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_ps&expand=5236) + * [ ] [`_mm512_scalef_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_pd&expand=5236) + * [ ] [`_mm512_scalef_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_scalef_round_ps&expand=5236) + * [ ] [`_mm512_set1_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi16&expand=5236) + * [ ] [`_mm512_set1_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi32&expand=5236) + * [ ] [`_mm512_set1_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi64&expand=5236) + * [ ] [`_mm512_set1_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_epi8&expand=5236) + * [ ] [`_mm512_set1_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_pd&expand=5236) + * [ ] [`_mm512_set1_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set1_ps&expand=5236) + * [ ] [`_mm512_set4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi32&expand=5236) + * [ ] [`_mm512_set4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_epi64&expand=5236) + * [ ] [`_mm512_set4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_pd&expand=5236) + * [ ] [`_mm512_set4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set4_ps&expand=5236) + * [ ] [`_mm512_set_epi16`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi16&expand=5236) + * [ ] [`_mm512_set_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi32&expand=5236) + * [x] [`_mm512_set_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi64&expand=5236) + * [ ] [`_mm512_set_epi8`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_epi8&expand=5236) + * [x] [`_mm512_set_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_pd&expand=5236) + * [x] [`_mm512_set_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_set_ps&expand=5236) + * [ ] [`_mm512_setr4_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi32&expand=5236) + * [ ] [`_mm512_setr4_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_epi64&expand=5236) + * [ ] [`_mm512_setr4_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_pd&expand=5236) + * [ ] [`_mm512_setr4_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr4_ps&expand=5236) + * [x] [`_mm512_setr_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_epi32&expand=5236) + * [x] [`_mm512_setr_epi64`](https:/software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_epi64&expand=5236) + * [x] [`_mm512_setr_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_pd&expand=5236) + * [x] [`_mm512_setr_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setr_ps&expand=5236) + * [ ] [`_mm512_setzero_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_epi32&expand=5236) + * [x] [`_mm512_setzero_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_pd&expand=5236) + * [x] [`_mm512_setzero_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_ps&expand=5236) + * [x] [`_mm512_setzero_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero_si512&expand=5236) + * [ ] [`_mm512_setzero`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_setzero&expand=5236) + * [x] [`_mm512_shuffle_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_epi32&expand=5236) + * [x] [`_mm512_shuffle_f32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_f32x4&expand=5236) + * [x] [`_mm512_shuffle_f64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_f64x2&expand=5236) + * [x] [`_mm512_shuffle_i32x4`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_i32x4&expand=5236) + * [x] [`_mm512_shuffle_i64x2`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_i64x2&expand=5236) + * [x] [`_mm512_shuffle_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_pd&expand=5236) + * [x] [`_mm512_shuffle_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_shuffle_ps&expand=5236) + * [x] [`_mm512_sll_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sll_epi32&expand=5236) + * [x] [`_mm512_sll_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sll_epi64&expand=5236) + * [x] [`_mm512_slli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_slli_epi32&expand=5236) + * [x] [`_mm512_slli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_slli_epi64&expand=5236) + * [x] [`_mm512_sllv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sllv_epi32&expand=5236) + * [x] [`_mm512_sllv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sllv_epi64&expand=5236) + * [x] [`_mm512_sqrt_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_pd&expand=5236) + * [x] [`_mm512_sqrt_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_ps&expand=5236) + * [x] [`_mm512_sqrt_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_round_pd&expand=5236) + * [x] [`_mm512_sqrt_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sqrt_round_ps&expand=5236) + * [x] [`_mm512_sra_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sra_epi32&expand=5236) + * [x] [`_mm512_sra_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sra_epi64&expand=5236) + * [x] [`_mm512_srai_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srai_epi32&expand=5236) + * [x] [`_mm512_srai_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srai_epi64&expand=5236) + * [x] [`_mm512_srav_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srav_epi32&expand=5236) + * [x] [`_mm512_srav_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srav_epi64&expand=5236) + * [x] [`_mm512_srl_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srl_epi32&expand=5236) + * [x] [`_mm512_srl_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srl_epi64&expand=5236) + * [x] [`_mm512_srli_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srli_epi32&expand=5236) + * [x] [`_mm512_srli_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srli_epi64&expand=5236) + * [x] [`_mm512_srlv_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srlv_epi32&expand=5236) + * [x] [`_mm512_srlv_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_srlv_epi64&expand=5236) + * [ ] [`_mm512_store_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi32&expand=5236) + * [ ] [`_mm512_store_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_epi64&expand=5236) + * [ ] [`_mm512_store_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_pd&expand=5236) + * [ ] [`_mm512_store_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_ps&expand=5236) + * [ ] [`_mm512_store_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_store_si512&expand=5236) + * [x] [`_mm512_storeu_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_pd&expand=5236) + * [x] [`_mm512_storeu_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_ps&expand=5236) + * [ ] [`_mm512_storeu_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_storeu_si512&expand=5236) + * [ ] [`_mm512_stream_load_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_load_si512&expand=5236) + * [ ] [`_mm512_stream_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_pd&expand=5236) + * [ ] [`_mm512_stream_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_ps&expand=5236) + * [ ] [`_mm512_stream_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_stream_si512&expand=5236) + * [x] [`_mm512_sub_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi32&expand=5236) + * [x] [`_mm512_sub_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_epi64&expand=5236) + * [x] [`_mm512_sub_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_pd&expand=5236) + * [x] [`_mm512_sub_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_ps&expand=5236) + * [x] [`_mm512_sub_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_round_pd&expand=5236) + * [x] [`_mm512_sub_round_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_sub_round_ps&expand=5236) + * [ ] [`_mm512_svml_round_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_svml_round_pd&expand=5236) + * [ ] [`_mm512_ternarylogic_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi32&expand=5236) + * [ ] [`_mm512_ternarylogic_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_ternarylogic_epi64&expand=5236) + * [ ] [`_mm512_test_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi32_mask&expand=5236) + * [ ] [`_mm512_test_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_test_epi64_mask&expand=5236) + * [ ] [`_mm512_testn_epi32_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi32_mask&expand=5236) + * [ ] [`_mm512_testn_epi64_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_testn_epi64_mask&expand=5236) + * [ ] [`_mm512_undefined_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_epi32&expand=5236) + * [x] [`_mm512_undefined_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_pd&expand=5236) + * [x] [`_mm512_undefined_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined_ps&expand=5236) + * [ ] [`_mm512_undefined`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_undefined&expand=5236) + * [ ] [`_mm512_unpackhi_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi32&expand=5236) + * [ ] [`_mm512_unpackhi_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_epi64&expand=5236) + * [ ] [`_mm512_unpackhi_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_pd&expand=5236) + * [ ] [`_mm512_unpackhi_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpackhi_ps&expand=5236) + * [ ] [`_mm512_unpacklo_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_epi32&expand=5236) + * [ ] [`_mm512_unpacklo_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_epi64&expand=5236) + * [ ] [`_mm512_unpacklo_pd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_pd&expand=5236) + * [ ] [`_mm512_unpacklo_ps`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_unpacklo_ps&expand=5236) + * [x] [`_mm512_xor_epi32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_epi32&expand=5236) + * [x] [`_mm512_xor_epi64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_epi64&expand=5236) + * [x] [`_mm512_xor_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_xor_si512&expand=5236) + * [ ] [`_mm512_zextpd128_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd128_pd512&expand=5236) + * [ ] [`_mm512_zextpd256_pd512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextpd256_pd512&expand=5236) + * [ ] [`_mm512_zextps128_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps128_ps512&expand=5236) + * [ ] [`_mm512_zextps256_ps512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextps256_ps512&expand=5236) + * [ ] [`_mm512_zextsi128_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi128_si512&expand=5236) + * [ ] [`_mm512_zextsi256_si512`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm512_zextsi256_si512&expand=5236) + * [ ] [`_mm_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_sd&expand=5236) + * [ ] [`_mm_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_add_round_ss&expand=5236) + * [x] [`_mm_cmp_round_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_sd_mask&expand=5236) + * [x] [`_mm_cmp_round_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_round_ss_mask&expand=5236) + * [x] [`_mm_cmp_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_sd_mask&expand=5236) + * [x] [`_mm_cmp_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmp_ss_mask&expand=5236) + * [ ] [`_mm_comi_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_sd&expand=5236) + * [ ] [`_mm_comi_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_comi_round_ss&expand=5236) + * [ ] [`_mm_cvt_roundi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi32_ss&expand=5236) + * [ ] [`_mm_cvt_roundi64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi64_sd&expand=5236) + * [ ] [`_mm_cvt_roundi64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundi64_ss&expand=5236) + * [ ] [`_mm_cvt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_i32&expand=5236) + * [ ] [`_mm_cvt_roundsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_i64&expand=5236) + * [ ] [`_mm_cvt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_si32&expand=5236) + * [ ] [`_mm_cvt_roundsd_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_si64&expand=5236) + * [ ] [`_mm_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_ss&expand=5236) + * [ ] [`_mm_cvt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_u32&expand=5236) + * [ ] [`_mm_cvt_roundsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsd_u64&expand=5236) + * [ ] [`_mm_cvt_roundsi32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi32_ss&expand=5236) + * [ ] [`_mm_cvt_roundsi64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi64_sd&expand=5236) + * [ ] [`_mm_cvt_roundsi64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundsi64_ss&expand=5236) + * [ ] [`_mm_cvt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_i32&expand=5236) + * [ ] [`_mm_cvt_roundss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_i64&expand=5236) + * [ ] [`_mm_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_sd&expand=5236) + * [ ] [`_mm_cvt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_si32&expand=5236) + * [ ] [`_mm_cvt_roundss_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_si64&expand=5236) + * [ ] [`_mm_cvt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_u32&expand=5236) + * [ ] [`_mm_cvt_roundss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundss_u64&expand=5236) + * [ ] [`_mm_cvt_roundu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu32_ss&expand=5236) + * [ ] [`_mm_cvt_roundu64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu64_sd&expand=5236) + * [ ] [`_mm_cvt_roundu64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvt_roundu64_ss&expand=5236) + * [ ] [`_mm_cvti32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_sd&expand=5236) + * [ ] [`_mm_cvti32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti32_ss&expand=5236) + * [ ] [`_mm_cvti64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti64_sd&expand=5236) + * [ ] [`_mm_cvti64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvti64_ss&expand=5236) + * [ ] [`_mm_cvtsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_i32&expand=5236) + * [ ] [`_mm_cvtsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_i64&expand=5236) + * [ ] [`_mm_cvtsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_u32&expand=5236) + * [ ] [`_mm_cvtsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtsd_u64&expand=5236) + * [ ] [`_mm_cvtss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_i32&expand=5236) + * [ ] [`_mm_cvtss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_i64&expand=5236) + * [ ] [`_mm_cvtss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_u32&expand=5236) + * [ ] [`_mm_cvtss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtss_u64&expand=5236) + * [ ] [`_mm_cvtt_roundsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i32&expand=5236) + * [ ] [`_mm_cvtt_roundsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_i64&expand=5236) + * [ ] [`_mm_cvtt_roundsd_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_si32&expand=5236) + * [ ] [`_mm_cvtt_roundsd_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_si64&expand=5236) + * [ ] [`_mm_cvtt_roundsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_u32&expand=5236) + * [ ] [`_mm_cvtt_roundsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundsd_u64&expand=5236) + * [ ] [`_mm_cvtt_roundss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_i32&expand=5236) + * [ ] [`_mm_cvtt_roundss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_i64&expand=5236) + * [ ] [`_mm_cvtt_roundss_si32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_si32&expand=5236) + * [ ] [`_mm_cvtt_roundss_si64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_si64&expand=5236) + * [ ] [`_mm_cvtt_roundss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_u32&expand=5236) + * [ ] [`_mm_cvtt_roundss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtt_roundss_u64&expand=5236) + * [ ] [`_mm_cvttsd_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_i32&expand=5236) + * [ ] [`_mm_cvttsd_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_i64&expand=5236) + * [ ] [`_mm_cvttsd_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_u32&expand=5236) + * [ ] [`_mm_cvttsd_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttsd_u64&expand=5236) + * [ ] [`_mm_cvttss_i32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_i32&expand=5236) + * [ ] [`_mm_cvttss_i64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_i64&expand=5236) + * [ ] [`_mm_cvttss_u32`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_u32&expand=5236) + * [ ] [`_mm_cvttss_u64`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvttss_u64&expand=5236) + * [ ] [`_mm_cvtu32_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_sd&expand=5236) + * [ ] [`_mm_cvtu32_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu32_ss&expand=5236) + * [ ] [`_mm_cvtu64_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_sd&expand=5236) + * [ ] [`_mm_cvtu64_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cvtu64_ss&expand=5236) + * [ ] [`_mm_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_sd&expand=5236) + * [ ] [`_mm_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_div_round_ss&expand=5236) + * [ ] [`_mm_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_sd&expand=5236) + * [ ] [`_mm_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_round_ss&expand=5236) + * [ ] [`_mm_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_sd&expand=5236) + * [ ] [`_mm_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fixupimm_ss&expand=5236) + * [ ] [`_mm_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_sd&expand=5236) + * [ ] [`_mm_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmadd_round_ss&expand=5236) + * [ ] [`_mm_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_sd&expand=5236) + * [ ] [`_mm_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fmsub_round_ss&expand=5236) + * [ ] [`_mm_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_sd&expand=5236) + * [ ] [`_mm_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_round_ss&expand=5236) + * [ ] [`_mm_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_sd&expand=5236) + * [ ] [`_mm_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getexp_ss&expand=5236) + * [ ] [`_mm_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_sd&expand=5236) + * [ ] [`_mm_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_round_ss&expand=5236) + * [ ] [`_mm_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_sd&expand=5236) + * [ ] [`_mm_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_getmant_ss&expand=5236) + * [ ] [`_mm_mask3_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_sd&expand=5236) + * [ ] [`_mm_mask3_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_round_ss&expand=5236) + * [ ] [`_mm_mask3_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_sd&expand=5236) + * [ ] [`_mm_mask3_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmadd_ss&expand=5236) + * [ ] [`_mm_mask3_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_sd&expand=5236) + * [ ] [`_mm_mask3_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_round_ss&expand=5236) + * [ ] [`_mm_mask3_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_sd&expand=5236) + * [ ] [`_mm_mask3_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fmsub_ss&expand=5236) + * [ ] [`_mm_mask3_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_mask3_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_mask3_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_sd&expand=5236) + * [ ] [`_mm_mask3_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmadd_ss&expand=5236) + * [ ] [`_mm_mask3_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_mask3_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_mask3_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_sd&expand=5236) + * [ ] [`_mm_mask3_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask3_fnmsub_ss&expand=5236) + * [ ] [`_mm_mask_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_sd&expand=5236) + * [ ] [`_mm_mask_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_round_ss&expand=5236) + * [ ] [`_mm_mask_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_sd&expand=5236) + * [ ] [`_mm_mask_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_add_ss&expand=5236) + * [x] [`_mm_mask_cmp_round_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_sd_mask&expand=5236) + * [x] [`_mm_mask_cmp_round_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_round_ss_mask&expand=5236) + * [x] [`_mm_mask_cmp_sd_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_sd_mask&expand=5236) + * [x] [`_mm_mask_cmp_ss_mask`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cmp_ss_mask&expand=5236) + * [ ] [`_mm_mask_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundsd_ss&expand=5236) + * [ ] [`_mm_mask_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvt_roundss_sd&expand=5236) + * [ ] [`_mm_mask_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtsd_ss&expand=5236) + * [ ] [`_mm_mask_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_cvtss_sd&expand=5236) + * [ ] [`_mm_mask_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_sd&expand=5236) + * [ ] [`_mm_mask_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_round_ss&expand=5236) + * [ ] [`_mm_mask_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_sd&expand=5236) + * [ ] [`_mm_mask_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_div_ss&expand=5236) + * [ ] [`_mm_mask_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_sd&expand=5236) + * [ ] [`_mm_mask_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_round_ss&expand=5236) + * [ ] [`_mm_mask_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_sd&expand=5236) + * [ ] [`_mm_mask_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fixupimm_ss&expand=5236) + * [ ] [`_mm_mask_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_sd&expand=5236) + * [ ] [`_mm_mask_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_round_ss&expand=5236) + * [ ] [`_mm_mask_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_sd&expand=5236) + * [ ] [`_mm_mask_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmadd_ss&expand=5236) + * [ ] [`_mm_mask_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_sd&expand=5236) + * [ ] [`_mm_mask_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_round_ss&expand=5236) + * [ ] [`_mm_mask_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_sd&expand=5236) + * [ ] [`_mm_mask_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fmsub_ss&expand=5236) + * [ ] [`_mm_mask_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_mask_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_mask_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_sd&expand=5236) + * [ ] [`_mm_mask_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmadd_ss&expand=5236) + * [ ] [`_mm_mask_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_mask_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_mask_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_sd&expand=5236) + * [ ] [`_mm_mask_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_fnmsub_ss&expand=5236) + * [ ] [`_mm_mask_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_sd&expand=5236) + * [ ] [`_mm_mask_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_round_ss&expand=5236) + * [ ] [`_mm_mask_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_sd&expand=5236) + * [ ] [`_mm_mask_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getexp_ss&expand=5236) + * [ ] [`_mm_mask_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_sd&expand=5236) + * [ ] [`_mm_mask_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_round_ss&expand=5236) + * [ ] [`_mm_mask_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_sd&expand=5236) + * [ ] [`_mm_mask_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_getmant_ss&expand=5236) + * [ ] [`_mm_mask_load_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_load_sd&expand=5236) + * [ ] [`_mm_mask_load_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_load_ss&expand=5236) + * [ ] [`_mm_mask_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_sd&expand=5236) + * [ ] [`_mm_mask_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_round_ss&expand=5236) + * [ ] [`_mm_mask_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_sd&expand=5236) + * [ ] [`_mm_mask_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_max_ss&expand=5236) + * [ ] [`_mm_mask_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_sd&expand=5236) + * [ ] [`_mm_mask_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_round_ss&expand=5236) + * [ ] [`_mm_mask_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_sd&expand=5236) + * [ ] [`_mm_mask_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_min_ss&expand=5236) + * [ ] [`_mm_mask_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_sd&expand=5236) + * [ ] [`_mm_mask_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_move_ss&expand=5236) + * [ ] [`_mm_mask_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_sd&expand=5236) + * [ ] [`_mm_mask_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_round_ss&expand=5236) + * [ ] [`_mm_mask_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_sd&expand=5236) + * [ ] [`_mm_mask_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_mul_ss&expand=5236) + * [ ] [`_mm_mask_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_sd&expand=5236) + * [ ] [`_mm_mask_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rcp14_ss&expand=5236) + * [ ] [`_mm_mask_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_sd&expand=5236) + * [ ] [`_mm_mask_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_round_ss&expand=5236) + * [ ] [`_mm_mask_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_sd&expand=5236) + * [ ] [`_mm_mask_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_roundscale_ss&expand=5236) + * [ ] [`_mm_mask_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_sd&expand=5236) + * [ ] [`_mm_mask_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_rsqrt14_ss&expand=5236) + * [ ] [`_mm_mask_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_sd&expand=5236) + * [ ] [`_mm_mask_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_round_ss&expand=5236) + * [ ] [`_mm_mask_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_sd&expand=5236) + * [ ] [`_mm_mask_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_scalef_ss&expand=5236) + * [ ] [`_mm_mask_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_sd&expand=5236) + * [ ] [`_mm_mask_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_round_ss&expand=5236) + * [ ] [`_mm_mask_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_sd&expand=5236) + * [ ] [`_mm_mask_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sqrt_ss&expand=5236) + * [ ] [`_mm_mask_store_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_store_sd&expand=5236) + * [ ] [`_mm_mask_store_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_store_ss&expand=5236) + * [ ] [`_mm_mask_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_sd&expand=5236) + * [ ] [`_mm_mask_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_round_ss&expand=5236) + * [ ] [`_mm_mask_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_sd&expand=5236) + * [ ] [`_mm_mask_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mask_sub_ss&expand=5236) + * [ ] [`_mm_maskz_add_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_sd&expand=5236) + * [ ] [`_mm_maskz_add_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_round_ss&expand=5236) + * [ ] [`_mm_maskz_add_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_sd&expand=5236) + * [ ] [`_mm_maskz_add_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_add_ss&expand=5236) + * [ ] [`_mm_maskz_cvt_roundsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundsd_ss&expand=5236) + * [ ] [`_mm_maskz_cvt_roundss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvt_roundss_sd&expand=5236) + * [ ] [`_mm_maskz_cvtsd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtsd_ss&expand=5236) + * [ ] [`_mm_maskz_cvtss_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_cvtss_sd&expand=5236) + * [ ] [`_mm_maskz_div_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_sd&expand=5236) + * [ ] [`_mm_maskz_div_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_round_ss&expand=5236) + * [ ] [`_mm_maskz_div_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_sd&expand=5236) + * [ ] [`_mm_maskz_div_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_div_ss&expand=5236) + * [ ] [`_mm_maskz_fixupimm_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_sd&expand=5236) + * [ ] [`_mm_maskz_fixupimm_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_round_ss&expand=5236) + * [ ] [`_mm_maskz_fixupimm_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_sd&expand=5236) + * [ ] [`_mm_maskz_fixupimm_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fixupimm_ss&expand=5236) + * [ ] [`_mm_maskz_fmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_sd&expand=5236) + * [ ] [`_mm_maskz_fmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_round_ss&expand=5236) + * [ ] [`_mm_maskz_fmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_sd&expand=5236) + * [ ] [`_mm_maskz_fmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmadd_ss&expand=5236) + * [ ] [`_mm_maskz_fmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_sd&expand=5236) + * [ ] [`_mm_maskz_fmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_round_ss&expand=5236) + * [ ] [`_mm_maskz_fmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_sd&expand=5236) + * [ ] [`_mm_maskz_fmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fmsub_ss&expand=5236) + * [ ] [`_mm_maskz_fnmadd_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_sd&expand=5236) + * [ ] [`_mm_maskz_fnmadd_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_round_ss&expand=5236) + * [ ] [`_mm_maskz_fnmadd_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_sd&expand=5236) + * [ ] [`_mm_maskz_fnmadd_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmadd_ss&expand=5236) + * [ ] [`_mm_maskz_fnmsub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_sd&expand=5236) + * [ ] [`_mm_maskz_fnmsub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_round_ss&expand=5236) + * [ ] [`_mm_maskz_fnmsub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_sd&expand=5236) + * [ ] [`_mm_maskz_fnmsub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_fnmsub_ss&expand=5236) + * [ ] [`_mm_maskz_getexp_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_sd&expand=5236) + * [ ] [`_mm_maskz_getexp_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_round_ss&expand=5236) + * [ ] [`_mm_maskz_getexp_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_sd&expand=5236) + * [ ] [`_mm_maskz_getexp_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getexp_ss&expand=5236) + * [ ] [`_mm_maskz_getmant_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_sd&expand=5236) + * [ ] [`_mm_maskz_getmant_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_round_ss&expand=5236) + * [ ] [`_mm_maskz_getmant_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_sd&expand=5236) + * [ ] [`_mm_maskz_getmant_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_getmant_ss&expand=5236) + * [ ] [`_mm_maskz_load_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_load_sd&expand=5236) + * [ ] [`_mm_maskz_load_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_load_ss&expand=5236) + * [ ] [`_mm_maskz_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_sd&expand=5236) + * [ ] [`_mm_maskz_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_round_ss&expand=5236) + * [ ] [`_mm_maskz_max_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_sd&expand=5236) + * [ ] [`_mm_maskz_max_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_max_ss&expand=5236) + * [ ] [`_mm_maskz_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_sd&expand=5236) + * [ ] [`_mm_maskz_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_round_ss&expand=5236) + * [ ] [`_mm_maskz_min_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_sd&expand=5236) + * [ ] [`_mm_maskz_min_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_min_ss&expand=5236) + * [ ] [`_mm_maskz_move_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_sd&expand=5236) + * [ ] [`_mm_maskz_move_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_move_ss&expand=5236) + * [ ] [`_mm_maskz_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_sd&expand=5236) + * [ ] [`_mm_maskz_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_round_ss&expand=5236) + * [ ] [`_mm_maskz_mul_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_sd&expand=5236) + * [ ] [`_mm_maskz_mul_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_mul_ss&expand=5236) + * [ ] [`_mm_maskz_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_sd&expand=5236) + * [ ] [`_mm_maskz_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rcp14_ss&expand=5236) + * [ ] [`_mm_maskz_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_sd&expand=5236) + * [ ] [`_mm_maskz_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_round_ss&expand=5236) + * [ ] [`_mm_maskz_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_sd&expand=5236) + * [ ] [`_mm_maskz_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_roundscale_ss&expand=5236) + * [ ] [`_mm_maskz_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_sd&expand=5236) + * [ ] [`_mm_maskz_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_rsqrt14_ss&expand=5236) + * [ ] [`_mm_maskz_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_sd&expand=5236) + * [ ] [`_mm_maskz_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_round_ss&expand=5236) + * [ ] [`_mm_maskz_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_sd&expand=5236) + * [ ] [`_mm_maskz_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_scalef_ss&expand=5236) + * [ ] [`_mm_maskz_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_sd&expand=5236) + * [ ] [`_mm_maskz_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_round_ss&expand=5236) + * [ ] [`_mm_maskz_sqrt_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_sd&expand=5236) + * [ ] [`_mm_maskz_sqrt_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sqrt_ss&expand=5236) + * [ ] [`_mm_maskz_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_sd&expand=5236) + * [ ] [`_mm_maskz_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_round_ss&expand=5236) + * [ ] [`_mm_maskz_sub_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_sd&expand=5236) + * [ ] [`_mm_maskz_sub_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_maskz_sub_ss&expand=5236) + * [ ] [`_mm_max_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_sd&expand=5236) + * [ ] [`_mm_max_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_max_round_ss&expand=5236) + * [ ] [`_mm_min_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_sd&expand=5236) + * [ ] [`_mm_min_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_min_round_ss&expand=5236) + * [ ] [`_mm_mul_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_sd&expand=5236) + * [ ] [`_mm_mul_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_mul_round_ss&expand=5236) + * [ ] [`_mm_rcp14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_sd&expand=5236) + * [ ] [`_mm_rcp14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rcp14_ss&expand=5236) + * [ ] [`_mm_roundscale_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_sd&expand=5236) + * [ ] [`_mm_roundscale_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_round_ss&expand=5236) + * [ ] [`_mm_roundscale_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_sd&expand=5236) + * [ ] [`_mm_roundscale_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_roundscale_ss&expand=5236) + * [ ] [`_mm_rsqrt14_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_sd&expand=5236) + * [ ] [`_mm_rsqrt14_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_rsqrt14_ss&expand=5236) + * [ ] [`_mm_scalef_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_sd&expand=5236) + * [ ] [`_mm_scalef_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_round_ss&expand=5236) + * [ ] [`_mm_scalef_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_sd&expand=5236) + * [ ] [`_mm_scalef_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_scalef_ss&expand=5236) + * [ ] [`_mm_sqrt_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_sd&expand=5236) + * [ ] [`_mm_sqrt_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sqrt_round_ss&expand=5236) + * [ ] [`_mm_sub_round_sd`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_sd&expand=5236) + * [ ] [`_mm_sub_round_ss`](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_sub_round_ss&expand=5236) + +

diff --git a/library/stdarch/crates/core_arch/src/aarch64/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/mod.rs index eefdae6738..ec2c6924b9 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/mod.rs @@ -15,14 +15,15 @@ pub use self::neon::*; mod crypto; pub use self::crypto::*; -#[cfg(not(bootstrap))] mod tme; -#[cfg(not(bootstrap))] pub use self::tme::*; mod crc; pub use self::crc::*; +mod prefetch; +pub use self::prefetch::*; + pub use super::acle::*; #[cfg(test)] diff --git a/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs b/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs index 66da36463a..438b1ac771 100644 --- a/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/aarch64/neon/mod.rs @@ -82,8 +82,41 @@ extern "C" { #[link_name = "llvm.aarch64.neon.pmull64"] fn vmull_p64_(a: i64, b: i64) -> int8x16_t; + #[link_name = "llvm.aarch64.neon.addp.v8i16"] + fn vpaddq_s16_(a: int16x8_t, b: int16x8_t) -> int16x8_t; + #[link_name = "llvm.aarch64.neon.addp.v4i32"] + fn vpaddq_s32_(a: int32x4_t, b: int32x4_t) -> int32x4_t; #[link_name = "llvm.aarch64.neon.addp.v16i8"] - fn vpaddq_u8_(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t; + fn vpaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + + #[link_name = "llvm.aarch64.neon.saddv.i32.v4i16"] + fn vaddv_s16_(a: int16x4_t) -> i16; + #[link_name = "llvm.aarch64.neon.saddv.i32.v2i32"] + fn vaddv_s32_(a: int32x2_t) -> i32; + #[link_name = "llvm.aarch64.neon.saddv.i32.v8i8"] + fn vaddv_s8_(a: int8x8_t) -> i8; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v4i16"] + fn vaddv_u16_(a: uint16x4_t) -> u16; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v2i32"] + fn vaddv_u32_(a: uint32x2_t) -> u32; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v8i8"] + fn vaddv_u8_(a: uint8x8_t) -> u8; + #[link_name = "llvm.aarch64.neon.saddv.i32.v8i16"] + fn vaddvq_s16_(a: int16x8_t) -> i16; + #[link_name = "llvm.aarch64.neon.saddv.i32.v4i32"] + fn vaddvq_s32_(a: int32x4_t) -> i32; + #[link_name = "llvm.aarch64.neon.saddv.i32.v16i8"] + fn vaddvq_s8_(a: int8x16_t) -> i8; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v8i16"] + fn vaddvq_u16_(a: uint16x8_t) -> u16; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v4i32"] + fn vaddvq_u32_(a: uint32x4_t) -> u32; + #[link_name = "llvm.aarch64.neon.uaddv.i32.v16i8"] + fn vaddvq_u8_(a: uint8x16_t) -> u8; + #[link_name = "llvm.aarch64.neon.saddv.i64.v2i64"] + fn vaddvq_s64_(a: int64x2_t) -> i64; + #[link_name = "llvm.aarch64.neon.uaddv.i64.v2i64"] + fn vaddvq_u64_(a: uint64x2_t) -> u64; #[link_name = "llvm.aarch64.neon.smaxv.i8.v8i8"] fn vmaxv_s8_(a: int8x8_t) -> i8; @@ -252,6 +285,11 @@ extern "C" { b3: int8x16_t, c: uint8x16_t, ) -> int8x16_t; + + #[link_name = "llvm.aarch64.neon.fcvtzu.v4i32.v4f32"] + fn vcvtq_u32_f32_(a: float32x4_t) -> uint32x4_t; + #[link_name = "llvm.aarch64.neon.fcvtzs.v4i32.v4f32"] + fn vcvtq_s32_f32_(a: float32x4_t) -> int32x4_t; } /// Absolute Value (wrapping). @@ -276,12 +314,160 @@ pub unsafe fn vabsq_s64(a: int64x2_t) -> int64x2_t { vabsq_s64_(a) } +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_s16(a: int16x8_t, b: int16x8_t) -> int16x8_t { + vpaddq_s16_(a, b) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_u16(a: uint16x8_t, b: uint16x8_t) -> uint16x8_t { + transmute(vpaddq_s16_(transmute(a), transmute(b))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_s32(a: int32x4_t, b: int32x4_t) -> int32x4_t { + vpaddq_s32_(a, b) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_u32(a: uint32x4_t, b: uint32x4_t) -> uint32x4_t { + transmute(vpaddq_s32_(transmute(a), transmute(b))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddq_s8(a: int8x16_t, b: int8x16_t) -> int8x16_t { + vpaddq_s8_(a, b) +} /// Add pairwise #[inline] #[target_feature(enable = "neon")] #[cfg_attr(test, assert_instr(addp))] pub unsafe fn vpaddq_u8(a: uint8x16_t, b: uint8x16_t) -> uint8x16_t { - vpaddq_u8_(a, b) + transmute(vpaddq_s8_(transmute(a), transmute(b))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddd_s64(a: int64x2_t) -> i64 { + transmute(vaddvq_u64_(transmute(a))) +} +/// Add pairwise +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vpaddd_u64(a: uint64x2_t) -> u64 { + transmute(vaddvq_u64_(transmute(a))) +} + +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_s16(a: int16x4_t) -> i16 { + vaddv_s16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddv_s32(a: int32x2_t) -> i32 { + vaddv_s32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_s8(a: int8x8_t) -> i8 { + vaddv_s8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_u16(a: uint16x4_t) -> u16 { + vaddv_u16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddv_u32(a: uint32x2_t) -> u32 { + vaddv_u32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddv_u8(a: uint8x8_t) -> u8 { + vaddv_u8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_s16(a: int16x8_t) -> i16 { + vaddvq_s16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_s32(a: int32x4_t) -> i32 { + vaddvq_s32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_s8(a: int8x16_t) -> i8 { + vaddvq_s8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_u16(a: uint16x8_t) -> u16 { + vaddvq_u16_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_u32(a: uint32x4_t) -> u32 { + vaddvq_u32_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addv))] +pub unsafe fn vaddvq_u8(a: uint8x16_t) -> u8 { + vaddvq_u8_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddvq_s64(a: int64x2_t) -> i64 { + vaddvq_s64_(a) +} +/// Add across vector +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(addp))] +pub unsafe fn vaddvq_u64(a: uint64x2_t) -> u64 { + vaddvq_u64_(a) } /// Polynomial multiply long @@ -308,6 +494,22 @@ pub unsafe fn vaddq_f64(a: float64x2_t, b: float64x2_t) -> float64x2_t { simd_add(a, b) } +/// Vector add. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(add))] +pub unsafe fn vadd_s64(a: int64x1_t, b: int64x1_t) -> int64x1_t { + simd_add(a, b) +} + +/// Vector add. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(add))] +pub unsafe fn vadd_u64(a: uint64x1_t, b: uint64x1_t) -> uint64x1_t { + simd_add(a, b) +} + /// Vector add. #[inline] #[target_feature(enable = "neon")] @@ -1602,6 +1804,60 @@ pub unsafe fn vqtbx4q_p8(a: poly8x16_t, t: poly8x16x4_t, idx: uint8x16_t) -> pol )) } +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_f32(addr: *const f32) -> float32x4_t { + use crate::core_arch::simd::f32x4; + transmute(f32x4::new( + *addr, + *addr.offset(1), + *addr.offset(2), + *addr.offset(3), + )) +} + +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_s32(addr: *const i32) -> int32x4_t { + use crate::core_arch::simd::i32x4; + transmute(i32x4::new( + *addr, + *addr.offset(1), + *addr.offset(2), + *addr.offset(3), + )) +} + +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(ldr))] +pub unsafe fn vld1q_u32(addr: *const u32) -> uint32x4_t { + use crate::core_arch::simd::u32x4; + transmute(u32x4::new( + *addr, + *addr.offset(1), + *addr.offset(2), + *addr.offset(3), + )) +} + +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fcvtzs))] +pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { + vcvtq_s32_f32_(a) +} + +/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(test, assert_instr(fcvtzu))] +pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { + vcvtq_u32_f32_(a) +} + #[cfg(test)] mod tests { use crate::core_arch::aarch64::test_support::*; @@ -1610,6 +1866,116 @@ mod tests { use std::mem::transmute; use stdarch_test::simd_test; + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_s32_f32() { + let f = f32x4::new(-1., 2., 3., 4.); + let e = i32x4::new(-1, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(10e37, 2., 3., 4.); + let e = i32x4::new(0x7fffffff, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(-10e37, 2., 3., 4.); + let e = i32x4::new(-0x80000000, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_u32_f32() { + let f = f32x4::new(1., 2., 3., 4.); + let e = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(-1., 2., 3., 4.); + let e = u32x4::new(0, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + + let f = f32x4::new(10e37, 2., 3., 4.); + let e = u32x4::new(0xffffffff, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f32() { + let e = f32x4::new(1., 2., 3., 4.); + let f = [0., 1., 2., 3., 4.]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: f32x4 = transmute(vld1q_f32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_s32() { + let e = i32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: i32x4 = transmute(vld1q_s32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_u32() { + let e = u32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: u32x4 = transmute(vld1q_u32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_s16() { + let a = i16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b = i16x8::new(0, -1, -2, -3, -4, -5, -6, -7); + let r: i16x8 = transmute(vpaddq_s16(transmute(a), transmute(b))); + let e = i16x8::new(3, 7, 11, 15, -1, -5, -9, -13); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_s32() { + let a = i32x4::new(1, 2, 3, 4); + let b = i32x4::new(0, -1, -2, -3); + let r: i32x4 = transmute(vpaddq_s32(transmute(a), transmute(b))); + let e = i32x4::new(3, 7, -1, -5); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_s8() { + let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let b = i8x16::new( + 0, -1, -2, -3, -4, -5, -6, -7, -8, -8, -10, -11, -12, -13, -14, -15, + ); + let r: i8x16 = transmute(vpaddq_s8(transmute(a), transmute(b))); + let e = i8x16::new( + 3, 7, 11, 15, 19, 23, 27, 31, -1, -5, -9, -13, -16, -21, -25, -29, + ); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_u16() { + let a = u16x8::new(0, 1, 2, 3, 4, 5, 6, 7); + let b = u16x8::new(17, 18, 19, 20, 20, 21, 22, 23); + let r: u16x8 = transmute(vpaddq_u16(transmute(a), transmute(b))); + let e = u16x8::new(1, 5, 9, 13, 35, 39, 41, 45); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddq_u32() { + let a = u32x4::new(0, 1, 2, 3); + let b = u32x4::new(17, 18, 19, 20); + let r: u32x4 = transmute(vpaddq_u32(transmute(a), transmute(b))); + let e = u32x4::new(1, 5, 35, 39); + assert_eq!(r, e); + } #[simd_test(enable = "neon")] unsafe fn test_vpaddq_u8() { let a = i8x16::new(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); @@ -1620,6 +1986,20 @@ mod tests { let e: i8x16 = transmute(vpaddq_u8(transmute(a), transmute(b))); assert_eq!(r, e); } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddd_s64() { + let a = i64x2::new(2, -3); + let r: i64 = transmute(vpaddd_s64(transmute(a))); + let e = -1_i64; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpaddd_u64() { + let a = i64x2::new(2, 3); + let r: u64 = transmute(vpaddd_u64(transmute(a))); + let e = 5_u64; + assert_eq!(r, e); + } #[simd_test(enable = "neon")] unsafe fn test_vmull_p64() { @@ -1669,6 +2049,24 @@ mod tests { assert_eq!(r, e); } + #[simd_test(enable = "neon")] + unsafe fn test_vadd_s64() { + let a = 1_i64; + let b = 8_i64; + let e = 9_i64; + let r: i64 = transmute(vadd_s64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vadd_u64() { + let a = 1_u64; + let b = 8_u64; + let e = 9_u64; + let r: u64 = transmute(vadd_u64(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] unsafe fn test_vaddd_s64() { let a = 1_i64; @@ -2560,6 +2958,105 @@ mod tests { let e = i64x2::new(i64::MIN, i64::MAX); assert_eq!(r, e); } + + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_s16() { + let a = i16x4::new(1, 2, 3, -4); + let r: i16 = transmute(vaddv_s16(transmute(a))); + let e = 2_i16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_u16() { + let a = u16x4::new(1, 2, 3, 4); + let r: u16 = transmute(vaddv_u16(transmute(a))); + let e = 10_u16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_s32() { + let a = i32x2::new(1, -2); + let r: i32 = transmute(vaddv_s32(transmute(a))); + let e = -1_i32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_u32() { + let a = u32x2::new(1, 2); + let r: u32 = transmute(vaddv_u32(transmute(a))); + let e = 3_u32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_s8() { + let a = i8x8::new(1, 2, 3, 4, 5, 6, 7, -8); + let r: i8 = transmute(vaddv_s8(transmute(a))); + let e = 20_i8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddv_u8() { + let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u8 = transmute(vaddv_u8(transmute(a))); + let e = 36_u8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s16() { + let a = i16x8::new(1, 2, 3, 4, 5, 6, 7, -8); + let r: i16 = transmute(vaddvq_s16(transmute(a))); + let e = 20_i16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u16() { + let a = u16x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let r: u16 = transmute(vaddvq_u16(transmute(a))); + let e = 36_u16; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s32() { + let a = i32x4::new(1, 2, 3, -4); + let r: i32 = transmute(vaddvq_s32(transmute(a))); + let e = 2_i32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u32() { + let a = u32x4::new(1, 2, 3, 4); + let r: u32 = transmute(vaddvq_u32(transmute(a))); + let e = 10_u32; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s8() { + let a = i8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, -16); + let r: i8 = transmute(vaddvq_s8(transmute(a))); + let e = 104_i8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u8() { + let a = u8x16::new(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r: u8 = transmute(vaddvq_u8(transmute(a))); + let e = 136_u8; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_s64() { + let a = i64x2::new(1, -2); + let r: i64 = transmute(vaddvq_s64(transmute(a))); + let e = -1_i64; + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vaddvq_u64() { + let a = u64x2::new(1, 2); + let r: u64 = transmute(vaddvq_u64(transmute(a))); + let e = 3_u64; + assert_eq!(r, e); + } } #[cfg(test)] diff --git a/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs b/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs new file mode 100644 index 0000000000..0c50be5ec0 --- /dev/null +++ b/library/stdarch/crates/core_arch/src/aarch64/prefetch.rs @@ -0,0 +1,89 @@ +#[cfg(test)] +use stdarch_test::assert_instr; + +extern "C" { + #[link_name = "llvm.prefetch"] + fn prefetch(p: *const i8, rw: i32, loc: i32, ty: i32); +} + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_READ: i32 = 0; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_WRITE: i32 = 1; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY0: i32 = 0; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY1: i32 = 1; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY2: i32 = 2; + +/// See [`prefetch`](fn._prefetch.html). +pub const _PREFETCH_LOCALITY3: i32 = 3; + +/// Fetch the cache line that contains address `p` using the given `rw` and `locality`. +/// +/// The `rw` must be one of: +/// +/// * [`_PREFETCH_READ`](constant._PREFETCH_READ.html): the prefetch is preparing +/// for a read. +/// +/// * [`_PREFETCH_WRITE`](constant._PREFETCH_WRITE.html): the prefetch is preparing +/// for a write. +/// +/// The `locality` must be one of: +/// +/// * [`_PREFETCH_LOCALITY0`](constant._PREFETCH_LOCALITY0.html): Streaming or +/// non-temporal prefetch, for data that is used only once. +/// +/// * [`_PREFETCH_LOCALITY1`](constant._PREFETCH_LOCALITY1.html): Fetch into level 3 cache. +/// +/// * [`_PREFETCH_LOCALITY2`](constant._PREFETCH_LOCALITY2.html): Fetch into level 2 cache. +/// +/// * [`_PREFETCH_LOCALITY3`](constant._PREFETCH_LOCALITY3.html): Fetch into level 1 cache. +/// +/// The prefetch memory instructions signal to the memory system that memory accesses +/// from a specified address are likely to occur in the near future. The memory system +/// can respond by taking actions that are expected to speed up the memory access when +/// they do occur, such as preloading the specified address into one or more caches. +/// Because these signals are only hints, it is valid for a particular CPU to treat +/// any or all prefetch instructions as a NOP. +/// +/// +/// [Arm's documentation](https://developer.arm.com/documentation/den0024/a/the-a64-instruction-set/memory-access-instructions/prefetching-memory?lang=en) +#[inline(always)] +#[cfg_attr(test, assert_instr("prfm pldl1strm", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY0))] +#[cfg_attr(test, assert_instr("prfm pldl3keep", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY1))] +#[cfg_attr(test, assert_instr("prfm pldl2keep", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY2))] +#[cfg_attr(test, assert_instr("prfm pldl1keep", rw = _PREFETCH_READ, locality = _PREFETCH_LOCALITY3))] +#[cfg_attr(test, assert_instr("prfm pstl1strm", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY0))] +#[cfg_attr(test, assert_instr("prfm pstl3keep", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY1))] +#[cfg_attr(test, assert_instr("prfm pstl2keep", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY2))] +#[cfg_attr(test, assert_instr("prfm pstl1keep", rw = _PREFETCH_WRITE, locality = _PREFETCH_LOCALITY3))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _prefetch(p: *const i8, rw: i32, locality: i32) { + // We use the `llvm.prefetch` instrinsic with `cache type` = 1 (data cache). + // `rw` and `strategy` are based on the function parameters. + macro_rules! pref { + ($rdwr:expr, $local:expr) => { + match ($rdwr, $local) { + (0, 0) => prefetch(p, 0, 0, 1), + (0, 1) => prefetch(p, 0, 1, 1), + (0, 2) => prefetch(p, 0, 2, 1), + (0, 3) => prefetch(p, 0, 3, 1), + (1, 0) => prefetch(p, 1, 0, 1), + (1, 1) => prefetch(p, 1, 1, 1), + (1, 2) => prefetch(p, 1, 2, 1), + (1, 3) => prefetch(p, 1, 3, 1), + (_, _) => panic!( + "Illegal (rw, locality) pair in prefetch, value ({}, {}).", + $rdwr, $local + ), + } + }; + } + pref!(rw, locality); +} diff --git a/library/stdarch/crates/core_arch/src/arm/mod.rs b/library/stdarch/crates/core_arch/src/arm/mod.rs index bd902dc607..ff983b34b8 100644 --- a/library/stdarch/crates/core_arch/src/arm/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm/mod.rs @@ -19,19 +19,9 @@ mod v7; #[cfg(any(target_arch = "aarch64", target_feature = "v7"))] pub use self::v7::*; -// NEON is supported on AArch64, and on ARM when built with the v7 and neon -// features. Building ARM without neon produces incorrect codegen. -#[cfg(any( - target_arch = "aarch64", - all(target_feature = "v7", target_feature = "neon"), - dox -))] +#[cfg(any(target_arch = "aarch64", target_feature = "v7", dox))] mod neon; -#[cfg(any( - target_arch = "aarch64", - all(target_feature = "v7", target_feature = "neon"), - dox -))] +#[cfg(any(target_arch = "aarch64", target_feature = "v7", dox))] pub use self::neon::*; #[cfg(any(target_arch = "aarch64", target_feature = "v7"))] diff --git a/library/stdarch/crates/core_arch/src/arm/neon/mod.rs b/library/stdarch/crates/core_arch/src/arm/neon/mod.rs index b39b1191e3..03fa069c11 100644 --- a/library/stdarch/crates/core_arch/src/arm/neon/mod.rs +++ b/library/stdarch/crates/core_arch/src/arm/neon/mod.rs @@ -175,6 +175,26 @@ extern "C" { #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpmaxs.v2f32")] #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.fmaxp.v2f32")] fn vpmaxf_v2f32(a: float32x2_t, b: float32x2_t) -> float32x2_t; + + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v4i16")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v4i16")] + fn vpadd_s16_(a: int16x4_t, b: int16x4_t) -> int16x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v2i32")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v2i32")] + fn vpadd_s32_(a: int32x2_t, b: int32x2_t) -> int32x2_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v8i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v8i8")] + fn vpadd_s8_(a: int8x8_t, b: int8x8_t) -> int8x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vpadd.v16i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.addp.v16i8")] + fn vpaddq_s8_(a: int8x16_t, b: int8x16_t) -> int8x16_t; + + #[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; + #[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; } #[cfg(target_arch = "arm")] @@ -204,6 +224,10 @@ extern "C" { d: int8x8_t, e: int8x8_t, ) -> int8x8_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v4f32.p0i8")] + fn vld1q_v4f32(addr: *const u8, align: u32) -> float32x4_t; + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1.v4i32.p0i8")] + fn vld1q_v4i32(addr: *const u8, align: u32) -> int32x4_t; } /// Absolute value (wrapping). @@ -261,6 +285,61 @@ pub unsafe fn vabsq_s32(a: int32x4_t) -> int32x4_t { vabsq_s32_(a) } +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s16(a: int16x4_t, b: int16x4_t) -> int16x4_t { + vpadd_s16_(a, b) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s32(a: int32x2_t, b: int32x2_t) -> int32x2_t { + vpadd_s32_(a, b) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_s8(a: int8x8_t, b: int8x8_t) -> int8x8_t { + vpadd_s8_(a, b) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u16(a: uint16x4_t, b: uint16x4_t) -> uint16x4_t { + transmute(vpadd_s16_(transmute(a), transmute(b))) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u32(a: uint32x2_t, b: uint32x2_t) -> uint32x2_t { + transmute(vpadd_s32_(transmute(a), transmute(b))) +} +/// Add pairwise. +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr(vpadd))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(addp))] +pub unsafe fn vpadd_u8(a: uint8x8_t, b: uint8x8_t) -> uint8x8_t { + transmute(vpadd_s8_(transmute(a), transmute(b))) +} + /// Unsigned saturating extract narrow. #[inline] #[target_feature(enable = "neon")] @@ -1243,11 +1322,8 @@ pub unsafe fn vtbx4_p8(a: poly8x8_t, b: poly8x8x4_t, c: uint8x8_t) -> poly8x8_t // `mov` seems to be an acceptable intrinsic to compile to // #[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(vmov, imm5 = 1))] pub unsafe fn vgetq_lane_u64(v: uint64x2_t, imm5: i32) -> u64 { - if (imm5) < 0 || (imm5) > 1 { - unreachable_unchecked() - } - let imm5 = (imm5 & 0b1) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 1); + simd_extract(v, imm5 as u32) } /// Move vector element to general-purpose register @@ -1260,9 +1336,7 @@ pub unsafe fn vgetq_lane_u64(v: uint64x2_t, imm5: i32) -> u64 { // FIXME: no 32bit this seems to be turned into two vmov.32 instructions // validate correctness pub unsafe fn vget_lane_u64(v: uint64x1_t, imm5: i32) -> u64 { - if imm5 != 0 { - unreachable_unchecked() - } + assert!(imm5 == 0); simd_extract(v, 0) } @@ -1274,11 +1348,8 @@ pub unsafe fn vget_lane_u64(v: uint64x1_t, imm5: i32) -> u64 { #[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))] pub unsafe fn vgetq_lane_u16(v: uint16x8_t, imm5: i32) -> u16 { - if (imm5) < 0 || (imm5) > 7 { - unreachable_unchecked() - } - let imm5 = (imm5 & 0b111) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 7); + simd_extract(v, imm5 as u32) } /// Move vector element to general-purpose register @@ -1289,11 +1360,20 @@ pub unsafe fn vgetq_lane_u16(v: uint16x8_t, imm5: i32) -> u16 { #[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))] pub unsafe fn vgetq_lane_u32(v: uint32x4_t, imm5: i32) -> u32 { - if (imm5) < 0 || (imm5) > 3 { - unreachable_unchecked() - } - let imm5 = (imm5 & 0b11) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 3); + simd_extract(v, imm5 as u32) +} + +/// Move vector element to general-purpose register +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[rustc_args_required_const(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))] +pub unsafe fn vgetq_lane_s32(v: int32x4_t, imm5: i32) -> i32 { + assert!(imm5 >= 0 && imm5 <= 3); + simd_extract(v, imm5 as u32) } /// Move vector element to general-purpose register @@ -1304,11 +1384,8 @@ pub unsafe fn vgetq_lane_u32(v: uint32x4_t, imm5: i32) -> u32 { #[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))] pub unsafe fn vget_lane_u8(v: uint8x8_t, imm5: i32) -> u8 { - if (imm5) < 0 || (imm5) > 7 { - unreachable_unchecked() - } - let imm5 = (imm5 & 7) as u32; - simd_extract(v, imm5) + assert!(imm5 >= 0 && imm5 <= 7); + simd_extract(v, imm5 as u32) } /// Duplicate vector element to vector or scalar @@ -1699,6 +1776,93 @@ pub unsafe fn vld1q_u8(addr: *const u8) -> uint8x16_t { ptr::read(addr as *const uint8x16_t) } +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_s32(addr: *const i32) -> int32x4_t { + vld1q_v4i32(addr as *const u8, 4) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_u32(addr: *const u32) -> uint32x4_t { + transmute(vld1q_v4i32(addr as *const u8, 4)) +} + +/// Load multiple single-element structures to one, two, three, or four registers +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vld1.32"))] +pub unsafe fn vld1q_f32(addr: *const f32) -> float32x4_t { + vld1q_v4f32(addr as *const u8, 4) +} + +/// 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"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(ld1r))] +pub unsafe fn vld1q_dup_f32(addr: *const f32) -> float32x4_t { + use crate::core_arch::simd::f32x4; + let v = *addr; + transmute(f32x4::new(v, v, v, v)) +} + +// These float-to-int implementations have undefined behaviour when `a` overflows +// the destination type. Clang has the same problem: https://llvm.org/PR47510 + +/// Floating-point Convert to Signed fixed-point, rounding toward Zero (vector) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vcvt.s32.f32"))] +pub unsafe fn vcvtq_s32_f32(a: float32x4_t) -> int32x4_t { + use crate::core_arch::simd::{f32x4, i32x4}; + transmute(simd_cast::<_, i32x4>(transmute::<_, f32x4>(a))) +} + +/// Floating-point Convert to Unsigned fixed-point, rounding toward Zero (vector) +#[inline] +#[cfg(target_arch = "arm")] +#[target_feature(enable = "neon")] +#[target_feature(enable = "v7")] +#[cfg_attr(test, assert_instr("vcvt.u32.f32"))] +pub unsafe fn vcvtq_u32_f32(a: float32x4_t) -> uint32x4_t { + use crate::core_arch::simd::{f32x4, u32x4}; + transmute(simd_cast::<_, u32x4>(transmute::<_, f32x4>(a))) +} + +/// Floating-point 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("vmin.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmin))] +pub unsafe fn vminq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + vminq_f32_(a, b) +} + +/// Floating-point maxmimum (vector). +#[inline] +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +#[cfg_attr(all(test, target_arch = "arm"), assert_instr("vmax.f32"))] +#[cfg_attr(all(test, target_arch = "aarch64"), assert_instr(fmax))] +pub unsafe fn vmaxq_f32(a: float32x4_t, b: float32x4_t) -> float32x4_t { + vmaxq_f32_(a, b) +} + #[cfg(test)] mod tests { use super::*; @@ -1723,6 +1887,65 @@ mod tests { assert_eq!(r, e); } + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_f32() { + let e = f32x4::new(1., 2., 3., 4.); + let f = [0., 1., 2., 3., 4.]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: f32x4 = transmute(vld1q_f32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_s32() { + let e = i32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: i32x4 = transmute(vld1q_s32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_u32() { + let e = u32x4::new(1, 2, 3, 4); + let f = [0, 1, 2, 3, 4]; + // do a load that has 4 byte alignment to make sure we're not + // over aligning it + let r: u32x4 = transmute(vld1q_u32(f[1..].as_ptr())); + assert_eq!(r, e); + } + + #[simd_test(enable = "neon")] + unsafe fn test_vld1q_dup_f32() { + let e = f32x4::new(1., 1., 1., 1.); + let f = [1., 2., 3., 4.]; + let r: f32x4 = transmute(vld1q_dup_f32(f.as_ptr())); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_s32_f32() { + let f = f32x4::new(-1., 2., 3., 4.); + let e = i32x4::new(-1, 2, 3, 4); + let r: i32x4 = transmute(vcvtq_s32_f32(transmute(f))); + assert_eq!(r, e); + } + + #[cfg(target_arch = "arm")] + #[simd_test(enable = "neon")] + unsafe fn test_vcvtq_u32_f32() { + let f = f32x4::new(1., 2., 3., 4.); + let e = u32x4::new(1, 2, 3, 4); + let r: u32x4 = transmute(vcvtq_u32_f32(transmute(f))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] unsafe fn test_vget_lane_u8() { let v = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); @@ -1737,6 +1960,13 @@ mod tests { assert_eq!(r, 2); } + #[simd_test(enable = "neon")] + unsafe fn test_vgetq_lane_s32() { + let v = i32x4::new(1, 2, 3, 4); + let r = vgetq_lane_s32(transmute(v), 1); + assert_eq!(r, 2); + } + #[simd_test(enable = "neon")] unsafe fn test_vget_lane_u64() { let v: u64 = 1; @@ -4063,6 +4293,70 @@ mod tests { let e = i32x4::new(i32::MIN, i32::MAX, 0, 1); assert_eq!(r, e); } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_s16() { + let a = i16x4::new(1, 2, 3, 4); + let b = i16x4::new(0, -1, -2, -3); + let r: i16x4 = transmute(vpadd_s16(transmute(a), transmute(b))); + let e = i16x4::new(3, 7, -1, -5); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_s32() { + let a = i32x2::new(1, 2); + let b = i32x2::new(0, -1); + let r: i32x2 = transmute(vpadd_s32(transmute(a), transmute(b))); + let e = i32x2::new(3, -1); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_s8() { + let a = i8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b = i8x8::new(0, -1, -2, -3, -4, -5, -6, -7); + let r: i8x8 = transmute(vpadd_s8(transmute(a), transmute(b))); + let e = i8x8::new(3, 7, 11, 15, -1, -5, -9, -13); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_u16() { + let a = u16x4::new(1, 2, 3, 4); + let b = u16x4::new(30, 31, 32, 33); + let r: u16x4 = transmute(vpadd_u16(transmute(a), transmute(b))); + let e = u16x4::new(3, 7, 61, 65); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_u32() { + let a = u32x2::new(1, 2); + let b = u32x2::new(30, 31); + let r: u32x2 = transmute(vpadd_u32(transmute(a), transmute(b))); + let e = u32x2::new(3, 61); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vpadd_u8() { + let a = u8x8::new(1, 2, 3, 4, 5, 6, 7, 8); + let b = u8x8::new(30, 31, 32, 33, 34, 35, 36, 37); + let r: u8x8 = transmute(vpadd_u8(transmute(a), transmute(b))); + let e = u8x8::new(3, 7, 11, 15, 61, 65, 69, 73); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vminq_f32() { + let a = f32x4::new(1., -2., 3., -4.); + let b = f32x4::new(0., 3., 2., 8.); + let e = f32x4::new(0., -2., 2., -4.); + let r: f32x4 = transmute(vminq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } + #[simd_test(enable = "neon")] + unsafe fn test_vmaxq_f32() { + let a = f32x4::new(1., -2., 3., -4.); + let b = f32x4::new(0., 3., 2., 8.); + let e = f32x4::new(1., 3., 3., 8.); + let r: f32x4 = transmute(vmaxq_f32(transmute(a), transmute(b))); + assert_eq!(r, e); + } } #[cfg(test)] diff --git a/library/stdarch/crates/core_arch/src/lib.rs b/library/stdarch/crates/core_arch/src/lib.rs index aa8d4c9820..5638ccc11e 100644 --- a/library/stdarch/crates/core_arch/src/lib.rs +++ b/library/stdarch/crates/core_arch/src/lib.rs @@ -6,6 +6,7 @@ #![feature( const_fn, const_fn_union, + const_fn_transmute, const_generics, custom_inner_attributes, link_llvm_intrinsics, @@ -21,7 +22,6 @@ stdsimd, staged_api, doc_cfg, - mmx_target_feature, tbm_target_feature, sse4a_target_feature, arm_target_feature, diff --git a/library/stdarch/crates/core_arch/src/simd.rs b/library/stdarch/crates/core_arch/src/simd.rs index 202df0143c..4b71d6c2bf 100644 --- a/library/stdarch/crates/core_arch/src/simd.rs +++ b/library/stdarch/crates/core_arch/src/simd.rs @@ -90,16 +90,44 @@ simd_ty!(i16x2[i16]: i16, i16 | x0, x1); // 64-bit wide types: -simd_ty!(u8x8[u8]: - u8, u8, u8, u8, u8, u8, u8, u8 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + u8x8[u8]: u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); simd_ty!(u16x4[u16]: u16, u16, u16, u16 | x0, x1, x2, x3); simd_ty!(u32x2[u32]: u32, u32 | x0, x1); simd_ty!(u64x1[u64]: u64 | x1); -simd_ty!(i8x8[i8]: - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + i8x8[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); simd_ty!(i16x4[i16]: i16, i16, i16, i16 | x0, x1, x2, x3); simd_ty!(i32x2[i32]: i32, i32 | x0, x1); simd_ty!(i64x1[i64]: i64 | x1); @@ -108,116 +136,576 @@ simd_ty!(f32x2[f32]: f32, f32 | x0, x1); // 128-bit wide types: -simd_ty!(u8x16[u8]: - u8, u8, u8, u8, u8, u8, u8, u8, - u8, u8, u8, u8, u8, u8, u8, u8 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_ty!( + u8x16[u8]: u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8, + u8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + u16x8[u16]: u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_ty!(u16x8[u16]: - u16, u16, u16, u16, u16, u16, u16, u16 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_ty!(u32x4[u32]: u32, u32, u32, u32 | x0, x1, x2, x3); simd_ty!(u64x2[u64]: u64, u64 | x0, x1); -simd_ty!(i8x16[i8]: - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_ty!( + i8x16[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + i16x8[i16]: i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_ty!(i16x8[i16]: - i16, i16, i16, i16, i16, i16, i16, i16 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_ty!(i32x4[i32]: i32, i32, i32, i32 | x0, x1, x2, x3); simd_ty!(i64x2[i64]: i64, i64 | x0, x1); simd_ty!(f32x4[f32]: f32, f32, f32, f32 | x0, x1, x2, x3); simd_ty!(f64x2[f64]: f64, f64 | x0, x1); -simd_m_ty!(m8x16[i8]: - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_m_ty!( + m8x16[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_m_ty!( + m16x8[i16]: i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_m_ty!(m16x8[i16]: - i16, i16, i16, i16, i16, i16, i16, i16 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_m_ty!(m32x4[i32]: i32, i32, i32, i32 | x0, x1, x2, x3); simd_m_ty!(m64x2[i64]: i64, i64 | x0, x1); // 256-bit wide types: -simd_ty!(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, u8 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, - x24, x25, x26, x27, x28, x29, x30, x31 +simd_ty!( + 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, + u8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31 ); -simd_ty!(u16x16[u16]: - u16, u16, u16, u16, u16, u16, u16, u16, - u16, u16, u16, u16, u16, u16, u16, u16 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_ty!( + u16x16[u16]: u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16, + u16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + u32x8[u32]: u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_ty!(u32x8[u32]: - u32, u32, u32, u32, u32, u32, u32, u32 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_ty!(u64x4[u64]: u64, u64, u64, u64 | x0, x1, x2, x3); -simd_ty!(i8x32[i8]: - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8, - i8, i8, i8, i8, i8, i8, i8, i8 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15, - x16, x17, x18, x19, x20, x21, x22, x23, - x24, x25, x26, x27, x28, x29, x30, x31 +simd_ty!( + i8x32[i8]: i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8, + i8 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15, + x16, + x17, + x18, + x19, + x20, + x21, + x22, + x23, + x24, + x25, + x26, + x27, + x28, + x29, + x30, + x31 ); -simd_ty!(i16x16[i16]: - i16, i16, i16, i16, i16, i16, i16, i16, - i16, i16, i16, i16, i16, i16, i16, i16 - | x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, x10, x11, x12, x13, x14, x15 +simd_ty!( + i16x16[i16]: i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16, + i16 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); +simd_ty!( + i32x8[i32]: i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 ); -simd_ty!(i32x8[i32]: - i32, i32, i32, i32, i32, i32, i32, i32 - | x0, x1, x2, x3, x4, x5, x6, x7); simd_ty!(i64x4[i64]: i64, i64, i64, i64 | x0, x1, x2, x3); -simd_ty!(f32x8[f32]: - f32, f32, f32, f32, f32, f32, f32, f32 | - x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + f32x8[f32]: f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); // 512-bit wide types: -simd_ty!(i32x16[i32]: - i32, i32, i32, i32, i32, i32, i32, i32, - i32, i32, i32, i32, i32, i32, i32, i32 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15); +simd_ty!( + i32x16[i32]: i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32, + i32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); -simd_ty!(u32x16[u32]: - u32, u32, u32, u32, u32, u32, u32, u32, - u32, u32, u32, u32, u32, u32, u32, u32 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15); +simd_ty!( + u32x16[u32]: u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32, + u32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); -simd_ty!(f32x16[f32]: - f32, f32, f32, f32, f32, f32, f32, f32, - f32, f32, f32, f32, f32, f32, f32, f32 - | x0, x1, x2, x3, x4, x5, x6, x7, - x8, x9, x10, x11, x12, x13, x14, x15); +simd_ty!( + f32x16[f32]: f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32, + f32 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7, + x8, + x9, + x10, + x11, + x12, + x13, + x14, + x15 +); -simd_ty!(i64x8[i64]: - i64, i64, i64, i64, i64, i64, i64, i64 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + i64x8[i64]: i64, + i64, + i64, + i64, + i64, + i64, + i64, + i64 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); -simd_ty!(u64x8[u64]: - u64, u64, u64, u64, u64, u64, u64, u64 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + u64x8[u64]: u64, + u64, + u64, + u64, + u64, + u64, + u64, + u64 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); -simd_ty!(f64x8[f64]: - f64, f64, f64, f64, f64, f64, f64, f64 - | x0, x1, x2, x3, x4, x5, x6, x7); +simd_ty!( + f64x8[f64]: f64, + f64, + f64, + f64, + f64, + f64, + f64, + f64 | x0, + x1, + x2, + x3, + x4, + x5, + x6, + x7 +); diff --git a/library/stdarch/crates/core_arch/src/simd_llvm.rs b/library/stdarch/crates/core_arch/src/simd_llvm.rs index 02934f7cb8..f472b86f8b 100644 --- a/library/stdarch/crates/core_arch/src/simd_llvm.rs +++ b/library/stdarch/crates/core_arch/src/simd_llvm.rs @@ -1,6 +1,4 @@ -//! LLVM's simd platform intrinsics -//! -//! TODO: should use `link_llvm_intrinsic` instead: issue #112 +//! LLVM's SIMD platform intrinsics extern "platform-intrinsic" { //pub fn simd_select_bitmask diff --git a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs index 798035d76a..bb8e238a91 100644 --- a/library/stdarch/crates/core_arch/src/wasm32/simd128.rs +++ b/library/stdarch/crates/core_arch/src/wasm32/simd128.rs @@ -24,7 +24,7 @@ types! { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait v128Ext: Sized { unsafe fn as_v128(self) -> v128; diff --git a/library/stdarch/crates/core_arch/src/x86/avx.rs b/library/stdarch/crates/core_arch/src/x86/avx.rs index e3f80733f5..0b6f13fe82 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx.rs @@ -1423,7 +1423,7 @@ pub unsafe fn _mm256_permute2f128_pd(a: __m256d, b: __m256d, imm8: i32) -> __m25 constify_imm8!(imm8, call) } -/// Shuffles 258-bits (composed of integer data) selected by `imm8` +/// Shuffles 128-bits (composed of integer data) selected by `imm8` /// from `a` and `b`. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_permute2f128_si256) diff --git a/library/stdarch/crates/core_arch/src/x86/avx2.rs b/library/stdarch/crates/core_arch/src/x86/avx2.rs index 15060a5e38..87af536cc9 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx2.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx2.rs @@ -3289,7 +3289,7 @@ pub unsafe fn _mm256_sub_epi16(a: __m256i, b: __m256i) -> __m256i { transmute(simd_sub(a.as_i16x16(), b.as_i16x16())) } -/// Subtract packed 32-bit integers in `b` from packed 16-bit integers in `a` +/// Subtract packed 32-bit integers in `b` from packed 32-bit integers in `a` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_sub_epi32) #[inline] @@ -3300,7 +3300,7 @@ pub unsafe fn _mm256_sub_epi32(a: __m256i, b: __m256i) -> __m256i { transmute(simd_sub(a.as_i32x8(), b.as_i32x8())) } -/// Subtract packed 64-bit integers in `b` from packed 16-bit integers in `a` +/// Subtract packed 64-bit integers in `b` from packed 64-bit integers in `a` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_sub_epi64) #[inline] @@ -3311,7 +3311,7 @@ pub unsafe fn _mm256_sub_epi64(a: __m256i, b: __m256i) -> __m256i { transmute(simd_sub(a.as_i64x4(), b.as_i64x4())) } -/// Subtract packed 8-bit integers in `b` from packed 16-bit integers in `a` +/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a` /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm256_sub_epi8) #[inline] @@ -3743,9 +3743,14 @@ pub unsafe fn _mm256_xor_si256(a: __m256i, b: __m256i) -> __m256i { // This intrinsic has no corresponding instruction. #[rustc_args_required_const(1)] #[stable(feature = "simd_x86", since = "1.27.0")] -pub unsafe fn _mm256_extract_epi8(a: __m256i, imm8: i32) -> i8 { - let imm8 = (imm8 & 31) as u32; - simd_extract(a.as_i8x32(), imm8 as u32) +pub unsafe fn _mm256_extract_epi8(a: __m256i, imm8: i32) -> i32 { + let a = a.as_u8x32(); + macro_rules! call { + ($imm5:expr) => { + simd_extract::<_, u8>(a, $imm5) as i32 + }; + } + constify_imm5!(imm8, call) } /// Extracts a 16-bit integer from `a`, selected with `imm8`. Returns a 32-bit @@ -3759,9 +3764,14 @@ pub unsafe fn _mm256_extract_epi8(a: __m256i, imm8: i32) -> i8 { // This intrinsic has no corresponding instruction. #[rustc_args_required_const(1)] #[stable(feature = "simd_x86", since = "1.27.0")] -pub unsafe fn _mm256_extract_epi16(a: __m256i, imm8: i32) -> i16 { - let imm8 = (imm8 & 15) as u32; - simd_extract(a.as_i16x16(), imm8) +pub unsafe fn _mm256_extract_epi16(a: __m256i, imm8: i32) -> i32 { + let a = a.as_u16x16(); + macro_rules! call { + ($imm4:expr) => { + simd_extract::<_, u16>(a, $imm4) as i32 + }; + } + constify_imm4!((imm8 & 15), call) } /// Extracts a 32-bit integer from `a`, selected with `imm8`. @@ -6120,7 +6130,7 @@ mod tests { ); let r1 = _mm256_extract_epi8(a, 0); let r2 = _mm256_extract_epi8(a, 35); - assert_eq!(r1, -1); + assert_eq!(r1, 0xFF); assert_eq!(r2, 3); } @@ -6133,7 +6143,7 @@ mod tests { ); let r1 = _mm256_extract_epi16(a, 0); let r2 = _mm256_extract_epi16(a, 19); - assert_eq!(r1, -1); + assert_eq!(r1, 0xFFFF); assert_eq!(r2, 3); } diff --git a/library/stdarch/crates/core_arch/src/x86/avx512f.rs b/library/stdarch/crates/core_arch/src/x86/avx512f.rs index 4744b435dd..3f9bbfb3e1 100644 --- a/library/stdarch/crates/core_arch/src/x86/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86/avx512f.rs @@ -49,6 +49,5835 @@ pub unsafe fn _mm512_maskz_abs_epi32(k: __mmask16, a: __m512i) -> __m512i { transmute(simd_select_bitmask(k, abs, zero)) } +/// Compute the absolute value of packed signed 64-bit integers in a, and store the unsigned results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_abs_epi64&expand=48) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpabsq))] +pub unsafe fn _mm512_abs_epi64(a: __m512i) -> __m512i { + let a = a.as_i64x8(); + // all-0 is a properly initialized i64x8 + let zero: i64x8 = mem::zeroed(); + let sub = simd_sub(zero, a); + let cmp: i64x8 = simd_gt(a, zero); + transmute(simd_select(cmp, a, sub)) +} + +/// Compute the absolute value of packed signed 64-bit integers in a, and store the unsigned results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_abs_epi64&expand=49) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpabsq))] +pub unsafe fn _mm512_mask_abs_epi64(src: __m512i, k: __mmask8, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi64(a).as_i64x8(); + transmute(simd_select_bitmask(k, abs, src.as_i64x8())) +} + +/// Compute the absolute value of packed signed 64-bit integers in a, and store the unsigned results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_abs_epi64&expand=50) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpabsq))] +pub unsafe fn _mm512_maskz_abs_epi64(k: __mmask8, a: __m512i) -> __m512i { + let abs = _mm512_abs_epi64(a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, abs, zero)) +} + +/// Finds the absolute value of each packed single-precision (32-bit) floating-point element in v2, storing the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_abs_ps&expand=65) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_abs_ps(v2: __m512) -> __m512 { + let a = _mm512_set1_epi32(0x7FFFFFFF); // from LLVM code + let b = transmute::(v2.as_f32x16()); + let abs = _mm512_and_epi32(a, b); + transmute(abs) +} + +/// Finds the absolute value of each packed single-precision (32-bit) floating-point element in v2, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_abs_ps&expand=66) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_mask_abs_ps(src: __m512, k: __mmask16, v2: __m512) -> __m512 { + let abs = _mm512_abs_ps(v2).as_f32x16(); + transmute(simd_select_bitmask(k, abs, src.as_f32x16())) +} + +/// Finds the absolute value of each packed double-precision (64-bit) floating-point element in v2, storing the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_abs_pd&expand=60) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_abs_pd(v2: __m512d) -> __m512d { + let a = _mm512_set1_epi64(0x7FFFFFFFFFFFFFFF); // from LLVM code + let b = transmute::(v2.as_f64x8()); + let abs = _mm512_and_epi64(a, b); + transmute(abs) +} + +/// Finds the absolute value of each packed double-precision (64-bit) floating-point element in v2, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_abs_pd&expand=61) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_mask_abs_pd(src: __m512d, k: __mmask8, v2: __m512d) -> __m512d { + let abs = _mm512_abs_pd(v2).as_f64x8(); + transmute(simd_select_bitmask(k, abs, src.as_f64x8())) +} + +/// Add packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_epi32&expand=100) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpaddd))] +pub unsafe fn _mm512_add_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_add(a.as_i32x16(), b.as_i32x16())) +} + +/// Add packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_epi32&expand=101) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpaddd))] +pub unsafe fn _mm512_mask_add_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, add, src.as_i32x16())) +} + +/// Add packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_epi32&expand=102) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpaddd))] +pub unsafe fn _mm512_maskz_add_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed 64-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_epi64&expand=109) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpaddq))] +pub unsafe fn _mm512_add_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_add(a.as_i64x8(), b.as_i64x8())) +} + +/// Add packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_epi64&expand=110) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpaddq))] +pub unsafe fn _mm512_mask_add_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, add, src.as_i64x8())) +} + +/// Add packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_epi64&expand=111) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpaddq))] +pub unsafe fn _mm512_maskz_add_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_add_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_ps&expand=139) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps))] +pub unsafe fn _mm512_add_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_add(a.as_f32x16(), b.as_f32x16())) +} + +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_ps&expand=140) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps))] +pub unsafe fn _mm512_mask_add_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let add = _mm512_add_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, add, src.as_f32x16())) +} + +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_ps&expand=141) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps))] +pub unsafe fn _mm512_maskz_add_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let add = _mm512_add_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_pd&expand=127) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd))] +pub unsafe fn _mm512_add_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_add(a.as_f64x8(), b.as_f64x8())) +} + +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_pd&expand=128) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd))] +pub unsafe fn _mm512_mask_add_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let add = _mm512_add_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, add, src.as_f64x8())) +} + +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_pd&expand=129) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd))] +pub unsafe fn _mm512_maskz_add_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let add = _mm512_add_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Subtract packed 32-bit integers in b from packed 32-bit integers in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_epi32&expand=5694) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsubd))] +pub unsafe fn _mm512_sub_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_sub(a.as_i32x16(), b.as_i32x16())) +} + +/// Subtract packed 32-bit integers in b from packed 32-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_epi32&expand=5692) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsubd))] +pub unsafe fn _mm512_mask_sub_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, sub, src.as_i32x16())) +} + +/// Subtract packed 32-bit integers in b from packed 32-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_epi32&expand=5693) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsubd))] +pub unsafe fn _mm512_maskz_sub_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed 64-bit integers in b from packed 64-bit integers in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_epi64&expand=5703) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsubq))] +pub unsafe fn _mm512_sub_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_sub(a.as_i64x8(), b.as_i64x8())) +} + +/// Subtract packed 64-bit integers in b from packed 64-bit integers in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_epi64&expand=5701) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsubq))] +pub unsafe fn _mm512_mask_sub_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let sub = _mm512_sub_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, sub, src.as_i64x8())) +} + +/// Subtract packed 64-bit integers in b from packed 64-bit integers in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_epi64&expand=5702) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsubq))] +pub unsafe fn _mm512_maskz_sub_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let add = _mm512_sub_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, add, zero)) +} + +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_ps&expand=5733) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps))] +pub unsafe fn _mm512_sub_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_sub(a.as_f32x16(), b.as_f32x16())) +} + +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_ps&expand=5731) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps))] +pub unsafe fn _mm512_mask_sub_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let sub = _mm512_sub_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, sub, src.as_f32x16())) +} + +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_ps&expand=5732) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps))] +pub unsafe fn _mm512_maskz_sub_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let sub = _mm512_sub_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_pd&expand=5721) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd))] +pub unsafe fn _mm512_sub_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_sub(a.as_f64x8(), b.as_f64x8())) +} + +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_pd&expand=5719) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd))] +pub unsafe fn _mm512_mask_sub_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let sub = _mm512_sub_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, sub, src.as_f64x8())) +} + +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_pd&expand=5720) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd))] +pub unsafe fn _mm512_maskz_sub_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let sub = _mm512_sub_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, sub, zero)) +} + +/// Multiply the low signed 32-bit integers from each packed 64-bit element in a and b, and store the signed 64-bit results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_epi32&expand=3907) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmuldq))] +pub unsafe fn _mm512_mul_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmuldq(a.as_i32x16(), b.as_i32x16())) +} + +/// Multiply the low signed 32-bit integers from each packed 64-bit element in a and b, and store the signed 64-bit results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_epi32&expand=3905) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmuldq))] +pub unsafe fn _mm512_mask_mul_epi32(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epi32(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, mul, src.as_i64x8())) +} + +/// Multiply the low signed 32-bit integers from each packed 64-bit element in a and b, and store the signed 64-bit results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_epi32&expand=3906) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmuldq))] +pub unsafe fn _mm512_maskz_mul_epi32(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epi32(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply the packed 32-bit integers in a and b, producing intermediate 64-bit integers, and store the low 32 bits of the intermediate integers in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mullo_epi&expand=4005) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmulld))] +pub unsafe fn _mm512_mullo_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_mul(a.as_i32x16(), b.as_i32x16())) +} + +/// Multiply the packed 32-bit integers in a and b, producing intermediate 64-bit integers, and store the low 32 bits of the intermediate integers in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mullo_epi32&expand=4003) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmulld))] +pub unsafe fn _mm512_mask_mullo_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mullo_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, mul, src.as_i32x16())) +} + +/// Multiply the packed 32-bit integers in a and b, producing intermediate 64-bit integers, and store the low 32 bits of the intermediate integers in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mullo_epi32&expand=4004) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmulld))] +pub unsafe fn _mm512_maskz_mullo_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mullo_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiplies elements in packed 64-bit integer vectors a and b together, storing the lower 64 bits of the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mullox_epi64&expand=4017) +/// +/// This intrinsic generates a sequence of instructions, which may perform worse than a native instruction. Consider the performance impact of this intrinsic. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mullox_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_mul(a.as_i64x8(), b.as_i64x8())) +} + +/// Multiplies elements in packed 64-bit integer vectors a and b together, storing the lower 64 bits of the result in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mullox&expand=4016) +/// +/// This intrinsic generates a sequence of instructions, which may perform worse than a native instruction. Consider the performance impact of this intrinsic. +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_mask_mullox_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, +) -> __m512i { + let mul = _mm512_mullox_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, mul, src.as_i64x8())) +} + +/// Multiply the low unsigned 32-bit integers from each packed 64-bit element in a and b, and store the unsigned 64-bit results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_epu32&expand=3916) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmuludq))] +pub unsafe fn _mm512_mul_epu32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmuludq(a.as_u32x16(), b.as_u32x16())) +} + +/// Multiply the low unsigned 32-bit integers from each packed 64-bit element in a and b, and store the unsigned 64-bit results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_epu32&expand=3914) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmuludq))] +pub unsafe fn _mm512_mask_mul_epu32(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epu32(a, b).as_u64x8(); + transmute(simd_select_bitmask(k, mul, src.as_u64x8())) +} + +/// Multiply the low unsigned 32-bit integers from each packed 64-bit element in a and b, and store the unsigned 64-bit results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_epu32&expand=3915) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmuludq))] +pub unsafe fn _mm512_maskz_mul_epu32(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let mul = _mm512_mul_epu32(a, b).as_u64x8(); + let zero = _mm512_setzero_si512().as_u64x8(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm512_mul_ps&expand=3934) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps))] +pub unsafe fn _mm512_mul_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_mul(a.as_f32x16(), b.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). RM. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_ps&expand=3932) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps))] +pub unsafe fn _mm512_mask_mul_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let mul = _mm512_mul_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, mul, src.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_ps&expand=3933) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps))] +pub unsafe fn _mm512_maskz_mul_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let mul = _mm512_mul_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_pd&expand=3925) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd))] +pub unsafe fn _mm512_mul_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_mul(a.as_f64x8(), b.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). RM. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_pd&expand=3923) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd))] +pub unsafe fn _mm512_mask_mul_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let mul = _mm512_mul_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, mul, src.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_pd&expand=3924) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd))] +pub unsafe fn _mm512_maskz_mul_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let mul = _mm512_mul_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mul, zero)) +} + +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_ps&expand=2162) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps))] +pub unsafe fn _mm512_div_ps(a: __m512, b: __m512) -> __m512 { + transmute(simd_div(a.as_f32x16(), b.as_f32x16())) +} + +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_ps&expand=2163) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps))] +pub unsafe fn _mm512_mask_div_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let div = _mm512_div_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, div, src.as_f32x16())) +} + +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_ps&expand=2164) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps))] +pub unsafe fn _mm512_maskz_div_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let div = _mm512_div_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, div, zero)) +} + +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_pd&expand=2153) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd))] +pub unsafe fn _mm512_div_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(simd_div(a.as_f64x8(), b.as_f64x8())) +} + +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_pd&expand=2154) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd))] +pub unsafe fn _mm512_mask_div_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let div = _mm512_div_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, div, src.as_f64x8())) +} + +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_pd&expand=2155) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd))] +pub unsafe fn _mm512_maskz_div_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let div = _mm512_div_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, div, zero)) +} + +/// Compare packed signed 32-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_epi32&expand=3582) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxsd))] +pub unsafe fn _mm512_max_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxsd(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epi32&expand=3580) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxsd))] +pub unsafe fn _mm512_mask_max_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, max, src.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epi32&expand=3581) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxsd))] +pub unsafe fn _mm512_maskz_max_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 64-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_epi64&expand=3591) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxsq))] +pub unsafe fn _mm512_max_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxsq(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epi64&expand=3589) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxsq))] +pub unsafe fn _mm512_mask_max_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, max, src.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epi64&expand=3590) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxsq))] +pub unsafe fn _mm512_maskz_max_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_ps&expand=3655) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps))] +pub unsafe fn _mm512_max_ps(a: __m512, b: __m512) -> __m512 { + transmute(vmaxps( + a.as_f32x16(), + b.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_ps&expand=3653) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps))] +pub unsafe fn _mm512_mask_max_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_max_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_ps&expand=3654) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps))] +pub unsafe fn _mm512_maskz_max_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_max_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_pd&expand=3645) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd))] +pub unsafe fn _mm512_max_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(vmaxpd(a.as_f64x8(), b.as_f64x8(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_pd&expand=3643) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd))] +pub unsafe fn _mm512_mask_max_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_max_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_pd&expand=3644) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd))] +pub unsafe fn _mm512_maskz_max_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_max_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 32-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_epu32&expand=3618) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxud))] +pub unsafe fn _mm512_max_epu32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxud(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epu32&expand=3616) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxud))] +pub unsafe fn _mm512_mask_max_epu32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu32(a, b).as_u32x16(); + transmute(simd_select_bitmask(k, max, src.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epu32&expand=3617) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxud))] +pub unsafe fn _mm512_maskz_max_epu32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu32(a, b).as_u32x16(); + let zero = _mm512_setzero_si512().as_u32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 64-bit integers in a and b, and store packed maximum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=max_epu64&expand=3627) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxuq))] +pub unsafe fn _mm512_max_epu64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpmaxuq(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_epu64&expand=3625) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxuq))] +pub unsafe fn _mm512_mask_max_epu64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu64(a, b).as_u64x8(); + transmute(simd_select_bitmask(k, max, src.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_epu&expand=3626) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpmaxuq))] +pub unsafe fn _mm512_maskz_max_epu64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_max_epu64(a, b).as_u64x8(); + let zero = _mm512_setzero_si512().as_u64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 32-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epi32&expand=3696) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminsd))] +pub unsafe fn _mm512_min_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminsd(a.as_i32x16(), b.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epi32&expand=3694) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminsd))] +pub unsafe fn _mm512_mask_min_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, max, src.as_i32x16())) +} + +/// Compare packed signed 32-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epi32&expand=3695) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminsd))] +pub unsafe fn _mm512_maskz_min_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed signed 64-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epi64&expand=3705) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminsq))] +pub unsafe fn _mm512_min_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminsq(a.as_i64x8(), b.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epi64&expand=3703) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminsq))] +pub unsafe fn _mm512_mask_min_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, max, src.as_i64x8())) +} + +/// Compare packed signed 64-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epi64&expand=3704) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminsq))] +pub unsafe fn _mm512_maskz_min_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_ps&expand=3769) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps))] +pub unsafe fn _mm512_min_ps(a: __m512, b: __m512) -> __m512 { + transmute(vminps( + a.as_f32x16(), + b.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_ps&expand=3767) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps))] +pub unsafe fn _mm512_mask_min_ps(src: __m512, k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_min_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_ps&expand=3768) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps))] +pub unsafe fn _mm512_maskz_min_ps(k: __mmask16, a: __m512, b: __m512) -> __m512 { + let max = _mm512_min_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_pd&expand=3759) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd))] +pub unsafe fn _mm512_min_pd(a: __m512d, b: __m512d) -> __m512d { + transmute(vminpd(a.as_f64x8(), b.as_f64x8(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_pd&expand=3757) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd))] +pub unsafe fn _mm512_mask_min_pd(src: __m512d, k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_min_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_pd&expand=3758) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd))] +pub unsafe fn _mm512_maskz_min_pd(k: __mmask8, a: __m512d, b: __m512d) -> __m512d { + let max = _mm512_min_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 32-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epu32&expand=3732) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminud))] +pub unsafe fn _mm512_min_epu32(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminud(a.as_u32x16(), b.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epu32&expand=3730) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminud))] +pub unsafe fn _mm512_mask_min_epu32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu32(a, b).as_u32x16(); + transmute(simd_select_bitmask(k, max, src.as_u32x16())) +} + +/// Compare packed unsigned 32-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epu32&expand=3731) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminud))] +pub unsafe fn _mm512_maskz_min_epu32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu32(a, b).as_u32x16(); + let zero = _mm512_setzero_si512().as_u32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed unsigned 64-bit integers in a and b, and store packed minimum values in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_epu64&expand=3741) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminuq))] +pub unsafe fn _mm512_min_epu64(a: __m512i, b: __m512i) -> __m512i { + transmute(vpminuq(a.as_u64x8(), b.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_epu64&expand=3739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminuq))] +pub unsafe fn _mm512_mask_min_epu64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu64(a, b).as_u64x8(); + transmute(simd_select_bitmask(k, max, src.as_u64x8())) +} + +/// Compare packed unsigned 64-bit integers in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_epu64&expand=3740) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpminuq))] +pub unsafe fn _mm512_maskz_min_epu64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let max = _mm512_min_epu64(a, b).as_u64x8(); + let zero = _mm512_setzero_si512().as_u64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_ps&expand=5371) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps))] +pub unsafe fn _mm512_sqrt_ps(a: __m512) -> __m512 { + transmute(vsqrtps(a.as_f32x16(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_ps&expand=5369) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps))] +pub unsafe fn _mm512_mask_sqrt_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let sqrt = _mm512_sqrt_ps(a).as_f32x16(); + transmute(simd_select_bitmask(k, sqrt, src.as_f32x16())) +} + +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_ps&expand=5370) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps))] +pub unsafe fn _mm512_maskz_sqrt_ps(k: __mmask16, a: __m512) -> __m512 { + let sqrt = _mm512_sqrt_ps(a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, sqrt, zero)) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_pd&expand=5362) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd))] +pub unsafe fn _mm512_sqrt_pd(a: __m512d) -> __m512d { + transmute(vsqrtpd(a.as_f64x8(), _MM_FROUND_CUR_DIRECTION)) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_pd&expand=5360) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd))] +pub unsafe fn _mm512_mask_sqrt_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + let sqrt = _mm512_sqrt_pd(a).as_f64x8(); + transmute(simd_select_bitmask(k, sqrt, src.as_f64x8())) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_pd&expand=5361) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd))] +pub unsafe fn _mm512_maskz_sqrt_pd(k: __mmask8, a: __m512d) -> __m512d { + let sqrt = _mm512_sqrt_pd(a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, sqrt, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=fmadd_ps&expand=2557) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_fmadd_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + transmute(vfmadd132ps( + a.as_f32x16(), + b.as_f32x16(), + c.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_ps&expand=2558) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_mask_fmadd_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmadd = _mm512_fmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_ps&expand=2560) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_maskz_fmadd_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmadd = _mm512_fmadd_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_ps&expand=2559) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +pub unsafe fn _mm512_mask3_fmadd_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmadd = _mm512_fmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_pd&expand=2545) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_fmadd_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + transmute(vfmadd132pd( + a.as_f64x8(), + b.as_f64x8(), + c.as_f64x8(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_pd&expand=2546) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_mask_fmadd_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmadd = _mm512_fmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_pd&expand=2548) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_maskz_fmadd_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmadd = _mm512_fmadd_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_pd&expand=2547) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +pub unsafe fn _mm512_mask3_fmadd_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmadd = _mm512_fmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_ps&expand=2643) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_fmsub_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + transmute(vfmadd132ps( + a.as_f32x16(), + b.as_f32x16(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_ps&expand=2644) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_mask_fmsub_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmsub = _mm512_fmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsub, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_ps&expand=2646) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_maskz_fmsub_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmsub = _mm512_fmsub_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_ps&expand=2645) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generate vfmadd, gcc generate vfmsub +pub unsafe fn _mm512_mask3_fmsub_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmsub = _mm512_fmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_pd&expand=2631) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_fmsub_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + transmute(vfmadd132pd( + a.as_f64x8(), + b.as_f64x8(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_pd&expand=2632) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_mask_fmsub_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmsub = _mm512_fmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsub, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_pd&expand=2634) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_maskz_fmsub_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmsub = _mm512_fmsub_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmsub, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_pd&expand=2633) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang fmadd, gcc fmsub +pub unsafe fn _mm512_mask3_fmsub_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmsub = _mm512_fmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsub, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_ps&expand=2611) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_fmaddsub_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + transmute(vfmaddsub213ps( + a.as_f32x16(), + b.as_f32x16(), + c.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_ps&expand=2612) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_mask_fmaddsub_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmaddsub = _mm512_fmaddsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_ps&expand=2614) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_maskz_fmaddsub_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmaddsub = _mm512_fmaddsub_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_ps&expand=2613) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +pub unsafe fn _mm512_mask3_fmaddsub_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmaddsub = _mm512_fmaddsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_pd&expand=2599) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_fmaddsub_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + transmute(vfmaddsub213pd( + a.as_f64x8(), + b.as_f64x8(), + c.as_f64x8(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_pd&expand=2600) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_mask_fmaddsub_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmaddsub = _mm512_fmaddsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_pd&expand=2602) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_maskz_fmaddsub_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmaddsub = _mm512_fmaddsub_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_ps&expand=2613) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +pub unsafe fn _mm512_mask3_fmaddsub_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmaddsub = _mm512_fmaddsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_ps&expand=2691) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_fmsubadd_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + transmute(vfmaddsub213ps( + a.as_f32x16(), + b.as_f32x16(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_ps&expand=2692) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_mask_fmsubadd_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fmsubadd = _mm512_fmsubadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_ps&expand=2694) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_maskz_fmsubadd_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fmsubadd = _mm512_fmsubadd_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmsubadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_ps&expand=2693) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +pub unsafe fn _mm512_mask3_fmsubadd_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fmsubadd = _mm512_fmsubadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_pd&expand=2679) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_fmsubadd_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + transmute(vfmaddsub213pd( + a.as_f64x8(), + b.as_f64x8(), + sub, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_pd&expand=2680) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_mask_fmsubadd_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fmsubadd = _mm512_fmsubadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_pd&expand=2682) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_maskz_fmsubadd_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fmsubadd = _mm512_fmsubadd_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmsubadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_pd&expand=2681) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +pub unsafe fn _mm512_mask3_fmsubadd_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fmsubadd = _mm512_fmsubadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_ps&expand=2723) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_fnmadd_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + transmute(vfmadd132ps( + sub, + b.as_f32x16(), + c.as_f32x16(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_ps&expand=2724) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_mask_fnmadd_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fnmadd = _mm512_fnmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_ps&expand=2726) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_maskz_fnmadd_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fnmadd = _mm512_fnmadd_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fnmadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_ps&expand=2725) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +pub unsafe fn _mm512_mask3_fnmadd_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fnmadd = _mm512_fnmadd_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_pd&expand=2711) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_fnmadd_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + transmute(vfmadd132pd( + sub, + b.as_f64x8(), + c.as_f64x8(), + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_pd&expand=2712) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_mask_fnmadd_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fnmadd = _mm512_fnmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_pd&expand=2714) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_maskz_fnmadd_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fnmadd = _mm512_fnmadd_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fnmadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_pd&expand=2713) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +pub unsafe fn _mm512_mask3_fnmadd_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fnmadd = _mm512_fnmadd_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_ps&expand=2771) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_fnmsub_ps(a: __m512, b: __m512, c: __m512) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + transmute(vfmadd132ps( + suba, + b.as_f32x16(), + subc, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_ps&expand=2772) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_mask_fnmsub_ps(a: __m512, k: __mmask16, b: __m512, c: __m512) -> __m512 { + let fnmsub = _mm512_fnmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmsub, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_ps&expand=2774) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_maskz_fnmsub_ps(k: __mmask16, a: __m512, b: __m512, c: __m512) -> __m512 { + let fnmsub = _mm512_fnmsub_ps(a, b, c).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fnmsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_ps&expand=2773) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +pub unsafe fn _mm512_mask3_fnmsub_ps(a: __m512, b: __m512, c: __m512, k: __mmask16) -> __m512 { + let fnmsub = _mm512_fnmsub_ps(a, b, c).as_f32x16(); + transmute(simd_select_bitmask(k, fnmsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_pd&expand=2759) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_fnmsub_pd(a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + transmute(vfmadd132pd( + suba, + b.as_f64x8(), + subc, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_pd&expand=2760) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_mask_fnmsub_pd(a: __m512d, k: __mmask8, b: __m512d, c: __m512d) -> __m512d { + let fnmsub = _mm512_fnmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmsub, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_pd&expand=2762) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_maskz_fnmsub_pd(k: __mmask8, a: __m512d, b: __m512d, c: __m512d) -> __m512d { + let fnmsub = _mm512_fnmsub_pd(a, b, c).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fnmsub, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_pd&expand=2761) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +pub unsafe fn _mm512_mask3_fnmsub_pd(a: __m512d, b: __m512d, c: __m512d, k: __mmask8) -> __m512d { + let fnmsub = _mm512_fnmsub_pd(a, b, c).as_f64x8(); + transmute(simd_select_bitmask(k, fnmsub, c.as_f64x8())) +} + +/// Compute the approximate reciprocal of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rcp14_ps&expand=4502) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14ps))] +pub unsafe fn _mm512_rcp14_ps(a: __m512) -> __m512 { + transmute(vrcp14ps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + )) +} + +/// Compute the approximate reciprocal of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rcp14_ps&expand=4500) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14ps))] +pub unsafe fn _mm512_mask_rcp14_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vrcp14ps(a.as_f32x16(), src.as_f32x16(), k)) +} + +/// Compute the approximate reciprocal of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rcp14_ps&expand=4501) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14ps))] +pub unsafe fn _mm512_maskz_rcp14_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vrcp14ps(a.as_f32x16(), _mm512_setzero_ps().as_f32x16(), k)) +} + +/// Compute the approximate reciprocal of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rcp14_pd&expand=4493) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14pd))] +pub unsafe fn _mm512_rcp14_pd(a: __m512d) -> __m512d { + transmute(vrcp14pd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + )) +} + +/// Compute the approximate reciprocal of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rcp14_pd&expand=4491) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14pd))] +pub unsafe fn _mm512_mask_rcp14_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vrcp14pd(a.as_f64x8(), src.as_f64x8(), k)) +} + +/// Compute the approximate reciprocal of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rcp14_pd&expand=4492) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrcp14pd))] +pub unsafe fn _mm512_maskz_rcp14_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vrcp14pd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k)) +} + +/// Compute the approximate reciprocal square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rsqrt14_ps&expand=4819) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14ps))] +pub unsafe fn _mm512_rsqrt14_ps(a: __m512) -> __m512 { + transmute(vrsqrt14ps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + )) +} + +/// Compute the approximate reciprocal square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rsqrt14_ps&expand=4817) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14ps))] +pub unsafe fn _mm512_mask_rsqrt14_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vrsqrt14ps(a.as_f32x16(), src.as_f32x16(), k)) +} + +/// Compute the approximate reciprocal square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rsqrt14_ps&expand=4818) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14ps))] +pub unsafe fn _mm512_maskz_rsqrt14_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vrsqrt14ps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + k, + )) +} + +/// Compute the approximate reciprocal square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rsqrt14_pd&expand=4812) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14pd))] +pub unsafe fn _mm512_rsqrt14_pd(a: __m512d) -> __m512d { + transmute(vrsqrt14pd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + )) +} + +/// Compute the approximate reciprocal square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rsqrt14_pd&expand=4810) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14pd))] +pub unsafe fn _mm512_mask_rsqrt14_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vrsqrt14pd(a.as_f64x8(), src.as_f64x8(), k)) +} + +/// Compute the approximate reciprocal square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). The maximum relative error for this approximation is less than 2^-14. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rsqrt14_pd&expand=4811) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vrsqrt14pd))] +pub unsafe fn _mm512_maskz_rsqrt14_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vrsqrt14pd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k)) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_ps&expand=2844) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps))] +pub unsafe fn _mm512_getexp_ps(a: __m512) -> __m512 { + transmute(vgetexpps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_ps&expand=2845) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps))] +pub unsafe fn _mm512_mask_getexp_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + transmute(vgetexpps( + a.as_f32x16(), + src.as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_ps&expand=2846) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps))] +pub unsafe fn _mm512_maskz_getexp_ps(k: __mmask16, a: __m512) -> __m512 { + transmute(vgetexpps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_pd&expand=2835) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd))] +pub unsafe fn _mm512_getexp_pd(a: __m512d) -> __m512d { + transmute(vgetexppd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_pd&expand=2836) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd))] +pub unsafe fn _mm512_mask_getexp_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + transmute(vgetexppd( + a.as_f64x8(), + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_pd&expand=2837) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd))] +pub unsafe fn _mm512_maskz_getexp_pd(k: __mmask8, a: __m512d) -> __m512d { + transmute(vgetexppd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_ps&expand=2880) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_getmant_ps( + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512 { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_ps&expand=2881) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_getmant_ps( + src: __m512, + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512 { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + src.as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_ps&expand=2882) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_getmant_ps( + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512 { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4, + _mm512_setzero_ps().as_f32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_pd&expand=2871) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(1, 2)] +pub unsafe fn _mm512_getmant_pd( + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512d { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_pd&expand=2872) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(3, 4)] +pub unsafe fn _mm512_mask_getmant_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512d { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_pd&expand=2873) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0))] +#[rustc_args_required_const(2, 3)] +pub unsafe fn _mm512_maskz_getmant_pd( + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, +) -> __m512d { + macro_rules! call { + ($imm4:expr, $imm2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4, + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + ) + }; + } + let r = constify_imm4_mantissas!(norm, sign, call); + transmute(r) +} + +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_ps&expand=145) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_add_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_ps&expand=146) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_add_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let addround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, addround, src.as_f32x16())) +} + +/// Add packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_ps&expand=147) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_add_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vaddps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let addround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, addround, zero)) +} + +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_add_round_pd&expand=142) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_add_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_add_round_pd&expand=143) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_add_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let addround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, addround, src.as_f64x8())) +} + +/// Add packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_add_round_pd&expand=144) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vaddpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_add_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vaddpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let addround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, addround, zero)) +} + +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_ps&expand=5739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_sub_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_ps&expand=5737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_sub_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let subround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, subround, src.as_f32x16())) +} + +/// Subtract packed single-precision (32-bit) floating-point elements in b from packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_ps&expand=5738) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_sub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsubps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let subround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, subround, zero)) +} + +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sub_round_pd&expand=5736) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_sub_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sub_round_pd&expand=5734) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_sub_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let subround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, subround, src.as_f64x8())) +} + +/// Subtract packed double-precision (64-bit) floating-point elements in b from packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sub_round_pd&expand=5735) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsubpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_sub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsubpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let subround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, subround, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_ps&expand=3940) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_mul_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_ps&expand=3938) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_mul_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let mulround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, mulround, src.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_mul_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmulps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let mulround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mulround, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mul_round_pd&expand=3937) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_mul_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_mul_round_pd&expand=3935) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_mul_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let mulround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, mulround, src.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_mul_round_ps&expand=3939) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmulpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_mul_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmulpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let mulround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mulround, zero)) +} + +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_ps&expand=2168) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_div_round_ps(a: __m512, b: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_ps&expand=2169) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_div_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let divround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, divround, src.as_f32x16())) +} + +/// Divide packed single-precision (32-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_ps&expand=2170) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_div_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vdivps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let divround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, divround, zero)) +} + +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, =and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_div_round_pd&expand=2165) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_div_round_pd(a: __m512d, b: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_div_round_pd&expand=2166) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_div_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let divround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, divround, src.as_f64x8())) +} + +/// Divide packed double-precision (64-bit) floating-point elements in a by packed elements in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_div_round_pd&expand=2167) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vdivpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_div_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vdivpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let divround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, divround, zero)) +} + +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_ps&expand=5377) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_sqrt_round_ps(a: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_ps&expand=5375) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_sqrt_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a.as_f32x16(), $imm4) + }; + } + let sqrtround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, sqrtround, src.as_f32x16())) +} + +/// Compute the square root of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_ps&expand=5376) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtps, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_sqrt_round_ps(k: __mmask16, a: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vsqrtps(a.as_f32x16(), $imm4) + }; + } + let sqrtround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, sqrtround, zero)) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sqrt_round_pd&expand=5374) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_sqrt_round_pd(a: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sqrt_round_pd&expand=5372) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_sqrt_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a.as_f64x8(), $imm4) + }; + } + let sqrtround = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, sqrtround, src.as_f64x8())) +} + +/// Compute the square root of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sqrt_round_pd&expand=5373) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vsqrtpd, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_sqrt_round_pd(k: __mmask8, a: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vsqrtpd(a.as_f64x8(), $imm4) + }; + } + let sqrtround = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, sqrtround, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_ps&expand=2565) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_ps&expand=2566) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmadd_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in a using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_ps&expand=2568) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmadd_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_ps&expand=2567) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132ps or vfmadd213ps or vfmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmadd_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmadd_round_pd&expand=2561) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmadd_round_pd&expand=2562) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmadd_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmadd_round_pd&expand=2564) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmadd_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmadd_round_pd&expand=2563) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmadd132pd or vfmadd213pd or vfmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_ps&expand=2651) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_ps&expand=2652) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsub_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_ps&expand=2654) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_ps&expand=2653) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132ps or vfmsub213ps or vfmsub231ps, clang generates vfmadd, gcc generates vfmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsub_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsub_round_pd&expand=2647) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsub_round_pd&expand=2648) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsub_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsub_round_pd&expand=2650) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsub_round_pd&expand=2649) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfmsub132pd or vfmsub213pd or vfmsub231pd. clang generates fmadd, gcc generates fmsub +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsub, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_ps&expand=2619) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmaddsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_ps&expand=2620) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmaddsub_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_ps&expand=2622) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmaddsub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fmaddsub = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_ps&expand=2621) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132ps or vfmaddsub213ps or vfmaddsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmaddsub_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmaddsub_round_pd&expand=2615) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmaddsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmaddsub_round_pd&expand=2616) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmaddsub_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmaddsub_round_pd&expand=2618) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmaddsub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fmaddsub = constify_imm4_round!(rounding, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, fmaddsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmaddsub_round_pd&expand=2617) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmaddsub132pd or vfmaddsub213pd or vfmaddsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmaddsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fmaddsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmaddsub, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_ps&expand=2699) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsubadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_ps&expand=2700) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsubadd_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_ps&expand=2702) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsubadd_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_ps&expand=2701) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132ps or vfmsubadd213ps or vfmsubadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsubadd_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213ps(a.as_f32x16(), b.as_f32x16(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fmsubadd_round_pd&expand=2695) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fmsubadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fmsubadd_round_pd&expand=2696) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fmsubadd_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively add and subtract packed elements in c to/from the intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fmsubadd_round_pd&expand=2698) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fmsubadd_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, alternatively subtract and add packed elements in c from/to the intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fmsubadd_round_pd&expand=2697) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmaddsub, rounding = 8))] //vfmsubadd132pd or vfmsubadd213pd or vfmsubadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fmsubadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmaddsub213pd(a.as_f64x8(), b.as_f64x8(), sub, $imm4) + }; + } + let fmsubadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fmsubadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_round_ps&expand=2731) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmadd_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_ps&expand=2732) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmadd_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_ps&expand=2734) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmadd_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_ps&expand=2733) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132ps or vfnmadd213ps or vfnmadd231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmadd_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(sub, b.as_f32x16(), c.as_f32x16(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmadd_pd&expand=2711) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmadd_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmadd_round_pd&expand=2728) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmadd_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmadd_round_pd&expand=2730) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmadd_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, add the negated intermediate result to packed elements in c, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmadd_round_pd&expand=2729) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmadd132pd or vfnmadd213pd or vfnmadd231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmadd_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let sub = simd_sub(zero, a.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(sub, b.as_f64x8(), c.as_f64x8(), $imm4) + }; + } + let fnmadd = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmadd, c.as_f64x8())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_ps&expand=2779) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmsub_round_ps(a: __m512, b: __m512, c: __m512, rounding: i32) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_ps&expand=2780) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmsub_round_ps( + a: __m512, + k: __mmask16, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, a.as_f32x16())) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_ps&expand=2782) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmsub_round_ps( + k: __mmask16, + a: __m512, + b: __m512, + c: __m512, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, zero)) +} + +/// Multiply packed single-precision (32-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_ps&expand=2781) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132ps or vfnmsub213ps or vfnmsub231ps +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmsub_round_ps( + a: __m512, + b: __m512, + c: __m512, + k: __mmask16, + rounding: i32, +) -> __m512 { + let zero: f32x16 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f32x16()); + let subc = simd_sub(zero, c.as_f32x16()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132ps(suba, b.as_f32x16(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, c.as_f32x16())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_fnmsub_round_pd&expand=2775) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_fnmsub_round_pd(a: __m512d, b: __m512d, c: __m512d, rounding: i32) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_fnmsub_round_pd&expand=2776) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_fnmsub_round_pd( + a: __m512d, + k: __mmask8, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, a.as_f64x8())) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_fnmsub_round_pd&expand=2778) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_maskz_fnmsub_round_pd( + k: __mmask8, + a: __m512d, + b: __m512d, + c: __m512d, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, zero)) +} + +/// Multiply packed double-precision (64-bit) floating-point elements in a and b, subtract packed elements in c from the negated intermediate result, and store the results in dst using writemask k (elements are copied from c when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask3_fnmsub_round_pd&expand=2777) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vfmadd, rounding = 8))] //vfnmsub132pd or vfnmsub213pd or vfnmsub231pd +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask3_fnmsub_round_pd( + a: __m512d, + b: __m512d, + c: __m512d, + k: __mmask8, + rounding: i32, +) -> __m512d { + let zero: f64x8 = mem::zeroed(); + let suba = simd_sub(zero, a.as_f64x8()); + let subc = simd_sub(zero, c.as_f64x8()); + macro_rules! call { + ($imm4:expr) => { + vfmadd132pd(suba, b.as_f64x8(), subc, $imm4) + }; + } + let fnmsub = constify_imm4_round!(rounding, call); + transmute(simd_select_bitmask(k, fnmsub, c.as_f64x8())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=max_round_ps&expand=3662) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_max_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_ps&expand=3660) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_max_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_ps&expand=3661) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_max_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vmaxps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_max_round_pd&expand=3659) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_max_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_max_round_pd&expand=3657) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_max_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed maximum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_max_round_pd&expand=3658) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmaxpd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_max_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vmaxpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_ps&expand=3776) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_min_round_ps(a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_ps&expand=3774) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_min_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f32x16())) +} + +/// Compare packed single-precision (32-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_ps&expand=3775) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_min_round_ps(k: __mmask16, a: __m512, b: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vminps(a.as_f32x16(), b.as_f32x16(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_min_round_pd&expand=3773) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_min_round_pd(a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_min_round_pd&expand=3771) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_min_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + transmute(simd_select_bitmask(k, max, src.as_f64x8())) +} + +/// Compare packed double-precision (64-bit) floating-point elements in a and b, and store packed minimum values in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_min_round_pd&expand=3772) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vminpd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_min_round_pd(k: __mmask8, a: __m512d, b: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vminpd(a.as_f64x8(), b.as_f64x8(), $imm4) + }; + } + let max = constify_imm4_sae!(sae, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, max, zero)) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_ps&expand=2850) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_getexp_round_ps(a: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps( + a.as_f32x16(), + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_ps&expand=2851) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_getexp_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps(a.as_f32x16(), src.as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed single-precision (32-bit) floating-point element in a to a single-precision (32-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_ps&expand=2852) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexpps, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_getexp_round_ps(k: __mmask16, a: __m512, sae: i32) -> __m512 { + macro_rules! call { + ($imm4:expr) => { + vgetexpps(a.as_f32x16(), _mm512_setzero_ps().as_f32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst. This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getexp_round_pd&expand=2847) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_getexp_round_pd(a: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd( + a.as_f64x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getexp_round_pd&expand=2848) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_getexp_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd(a.as_f64x8(), src.as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert the exponent of each packed double-precision (64-bit) floating-point element in a to a double-precision (64-bit) floating-point number representing the integer exponent, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates floor(log2(x)) for each element. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getexp_round_pd&expand=2849) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetexppd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_getexp_round_pd(k: __mmask8, a: __m512d, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vgetexppd(a.as_f64x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_ps&expand=2886) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(1, 2, 3)] +pub unsafe fn _mm512_getmant_round_ps( + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_ps().as_f32x16(), + 0b11111111_11111111, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_ps&expand=2887) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm512_mask_getmant_round_ps( + src: __m512, + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + src.as_f32x16(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed single-precision (32-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_ps&expand=2888) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantps, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm512_maskz_getmant_round_ps( + k: __mmask16, + a: __m512, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512 { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantps( + a.as_f32x16(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_ps().as_f32x16(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst. This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_getmant_round_pd&expand=2883) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(1, 2, 3)] +pub unsafe fn _mm512_getmant_round_pd( + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_getmant_round_pd&expand=2884) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(3, 4, 5)] +pub unsafe fn _mm512_mask_getmant_round_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + src.as_f64x8(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Normalize the mantissas of packed double-precision (64-bit) floating-point elements in a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). This intrinsic essentially calculates ±(2^k)*|x.significand|, where k depends on the interval range defined by interv and the sign depends on sc and the source sign. +/// The mantissa is normalized to the interval specified by interv, which can take the following values: +/// _MM_MANT_NORM_1_2 // interval [1, 2) +/// _MM_MANT_NORM_p5_2 // interval [0.5, 2) +/// _MM_MANT_NORM_p5_1 // interval [0.5, 1) +/// _MM_MANT_NORM_p75_1p5 // interval [0.75, 1.5) +/// The sign is determined by sc which can take the following values: +/// _MM_MANT_SIGN_src // sign = sign(src) +/// _MM_MANT_SIGN_zero // sign = 0 +/// _MM_MANT_SIGN_nan // dst = NaN if sign(src) = 1 +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_getmant_round_pd&expand=2885) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vgetmantpd, norm = 0, sign = 0, sae = 4))] +#[rustc_args_required_const(2, 3, 4)] +pub unsafe fn _mm512_maskz_getmant_round_pd( + k: __mmask8, + a: __m512d, + norm: _MM_MANTISSA_NORM_ENUM, + sign: _MM_MANTISSA_SIGN_ENUM, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr) => { + vgetmantpd( + a.as_f64x8(), + $imm2 << 2 | $imm4_1, + _mm512_setzero_pd().as_f64x8(), + k, + $imm4_2, + ) + }; + } + let r = constify_imm4_mantissas_sae!(norm, sign, sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvtps_epi32&expand=1737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_cvtps_epi32(a: __m512) -> __m512i { + transmute(vcvtps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epi32&expand=1738) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_mask_cvtps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2dq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_epi32&expand=1739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq))] +pub unsafe fn _mm512_maskz_cvtps_epi32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_epu32&expand=1755) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_cvtps_epu32(a: __m512) -> __m512i { + transmute(vcvtps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_u32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_epu32&expand=1756) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_mask_cvtps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2udq( + a.as_f32x16(), + src.as_u32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq))] +pub unsafe fn _mm512_maskz_cvtps_epu32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvtps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_u32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtps_pd&expand=1769) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_cvtps_pd(a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtps_pd&expand=1770) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_mask_cvtps_pd(src: __m512d, k: __mmask8, a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + src.as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtps_pd&expand=1771) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd))] +pub unsafe fn _mm512_maskz_cvtps_pd(k: __mmask8, a: __m256) -> __m512d { + transmute(vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epi32&expand=1335) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_epi32(a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_epi32( + src: __m512i, + k: __mmask16, + a: __m512, + rounding: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2dq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_epi32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst. +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvt_roundps_epu32&expand=1341) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_epu32(a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_u32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epu32&expand=1342) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_epu32( + src: __m512i, + k: __mmask16, + a: __m512, + rounding: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq(a.as_f32x16(), src.as_u32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// Rounding is done according to the rounding\[3:0\] parameter, which can be one of: +/// (_MM_FROUND_TO_NEAREST_INT |_MM_FROUND_NO_EXC) // round to nearest, and suppress exceptions +/// (_MM_FROUND_TO_NEG_INF |_MM_FROUND_NO_EXC) // round down, and suppress exceptions +/// (_MM_FROUND_TO_POS_INF |_MM_FROUND_NO_EXC) // round up, and suppress exceptions +/// (_MM_FROUND_TO_ZERO |_MM_FROUND_NO_EXC) // truncate, and suppress exceptions +/// _MM_FROUND_CUR_DIRECTION // use MXCSR.RC; see _MM_SET_ROUNDING_MODE +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=maskz_cvt_roundps_epu32&expand=1343) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2udq, rounding = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_epu32(k: __mmask16, a: __m512, rounding: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvtps2udq(a.as_f32x16(), _mm512_setzero_si512().as_u32x16(), k, $imm4) + }; + } + let r = constify_imm4_round!(rounding, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=cvt_roundps_pd&expand=1347) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvt_roundps_pd(a: __m256, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd( + a.as_f32x8(), + _mm512_setzero_pd().as_f64x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvt_roundps_epi32&expand=1336) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvt_roundps_pd( + src: __m512d, + k: __mmask8, + a: __m256, + sae: i32, +) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd(a.as_f32x8(), src.as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed double-precision (64-bit) floating-point elements, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvt_roundps_epi32&expand=1337) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvtps2pd, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvt_roundps_pd(k: __mmask8, a: __m256, sae: i32) -> __m512d { + macro_rules! call { + ($imm4:expr) => { + vcvtps2pd(a.as_f32x8(), _mm512_setzero_pd().as_f64x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epi32&expand=1916) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundps_epi32(a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epi32&expand=1917) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundps_epi32( + src: __m512i, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundps_epi32(k: __mmask16, a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2dq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundps_epu32&expand=1922) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundps_epu32(a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundps_epu32&expand=1923) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundps_epu32( + src: __m512i, + k: __mmask16, + a: __m512, + sae: i32, +) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq(a.as_f32x16(), src.as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epu32&expand=1924) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundps_epu32(k: __mmask16, a: __m512, sae: i32) -> __m512i { + macro_rules! call { + ($imm4:expr) => { + vcvttps2udq(a.as_f32x16(), _mm512_setzero_si512().as_i32x16(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epi32&expand=1904) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundpd_epi32(a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epi32&expand=1905) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundpd_epi32( + src: __m256i, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundps_epi32&expand=1918) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundpd_epi32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2dq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvtt_roundpd_epu32&expand=1910) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_cvtt_roundpd_epu32(a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + $imm4, + ) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvtt_roundpd_epu32&expand=1911) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_cvtt_roundpd_epu32( + src: __m256i, + k: __mmask8, + a: __m512d, + sae: i32, +) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq(a.as_f64x8(), src.as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epi32&expand=1984) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_cvttps_epi32(a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epi32&expand=1985) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_mask_cvttps_epi32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epi32&expand=1986) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2dq))] +pub unsafe fn _mm512_maskz_cvttps_epi32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2dq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed single-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttps_epu32&expand=2002) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_cvttps_epu32(a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + 0b11111111_11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttps_epu32&expand=2003) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_mask_cvttps_epu32(src: __m512i, k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + src.as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (32-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttps_epu32&expand=2004) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttps2udq))] +pub unsafe fn _mm512_maskz_cvttps_epu32(k: __mmask16, a: __m512) -> __m512i { + transmute(vcvttps2udq( + a.as_f32x16(), + _mm512_setzero_si512().as_i32x16(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// Exceptions can be suppressed by passing _MM_FROUND_NO_EXC in the sae parameter. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvtt_roundpd_epu32&expand=1912) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq, sae = 8))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_cvtt_roundpd_epu32(k: __mmask8, a: __m512d, sae: i32) -> __m256i { + macro_rules! call { + ($imm4:expr) => { + vcvttpd2udq(a.as_f64x8(), _mm256_setzero_si256().as_i32x8(), k, $imm4) + }; + } + let r = constify_imm4_sae!(sae, call); + transmute(r) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epi32&expand=1947) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_cvttpd_epi32(a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epi32&expand=1948) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_mask_cvttpd_epi32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + src.as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epi32&expand=1949) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2dq))] +pub unsafe fn _mm512_maskz_cvttpd_epi32(k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2dq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_cvttpd_epu32&expand=1965) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_cvttpd_epu32(a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + 0b11111111, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_cvttpd_epu32&expand=1966) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_mask_cvttpd_epu32(src: __m256i, k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + src.as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + +/// Convert packed double-precision (64-bit) floating-point elements in a to packed unsigned 32-bit integers with truncation, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_cvttpd_epu32&expand=1967) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vcvttpd2udq))] +pub unsafe fn _mm512_maskz_cvttpd_epu32(k: __mmask8, a: __m512d) -> __m256i { + transmute(vcvttpd2udq( + a.as_f64x8(), + _mm256_setzero_si256().as_i32x8(), + k, + _MM_FROUND_CUR_DIRECTION, + )) +} + /// Returns vector of type `__m512d` with all elements set to zero. /// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#avx512techs=AVX512F&expand=33,34,4990&text=_mm512_setzero_pd) @@ -854,6 +6683,3911 @@ pub unsafe fn _mm512_mask_i64scatter_epi32( constify_imm8_gather!(scale, call); } +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi32&expand=4685) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_rol_epi32(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprold(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi32&expand=4683) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_rol_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprold(a.as_i32x16(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, rol, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi32&expand=4684) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_rol_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprold(a.as_i32x16(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi32&expand=4721) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_ror_epi32(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprord(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi32&expand=4719) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_ror_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprord(a.as_i32x16(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ror, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi32&expand=4720) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprold, imm8 = 123))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_ror_epi32(k: __mmask16, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprord(a.as_i32x16(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rol_epi64&expand=4694) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_rol_epi64(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprolq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rol_epi64&expand=4692) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_rol_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprolq(a.as_i64x8(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, rol, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rol_epi64&expand=4693) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_rol_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprolq(a.as_i64x8(), $imm8) + }; + } + let rol = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_ror_epi64&expand=4730) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_ror_epi64(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprorq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_ror_epi64&expand=4728) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_ror_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprorq(a.as_i64x8(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, ror, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_ror_epi64&expand=4729) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolq, imm8 = 15))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_ror_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vprorq(a.as_i64x8(), $imm8) + }; + } + let ror = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi32&expand=5310) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_slli_epi32(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsllid(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi32&expand=5308) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_slli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsllid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi32&expand=5309) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_slli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsllid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi32&expand=5522) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srli_epi32(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi32&expand=5520) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srli_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi32&expand=5521) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srli_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrlid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_slli_epi64&expand=5319) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_slli_epi64(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpslliq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_slli_epi64&expand=5317) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_slli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpslliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_slli_epi64&expand=5318) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq, imm8 = 5))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_slli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpslliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srli_epi64&expand=5531) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srli_epi64(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srli_epi64&expand=5529) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srli_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srli_epi64&expand=5530) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srli_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsrliq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi32&expand=5280) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_sll_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpslld(a.as_i32x16(), count.as_i32x4())) +} + +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi32&expand=5278) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_mask_sll_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sll_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi32&expand=5279) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpslld))] +pub unsafe fn _mm512_maskz_sll_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sll_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi32&expand=5492) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_srl_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrld(a.as_i32x16(), count.as_i32x4())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi32&expand=5490) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_mask_srl_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_srl_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srl_epi32&expand=5491) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrld))] +pub unsafe fn _mm512_maskz_srl_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_srl_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sll_epi64&expand=5289) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_sll_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsllq(a.as_i64x8(), count.as_i64x2())) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sll_epi64&expand=5287) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_mask_sll_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sll_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllq))] +pub unsafe fn _mm512_maskz_sll_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sll_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srl_epi64&expand=5501) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_srl_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrlq(a.as_i64x8(), count.as_i64x2())) +} + +/// Shift packed 64-bit integers in a right by count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srl_epi64&expand=5499) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_mask_srl_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_srl_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sll_epi64&expand=5288) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlq))] +pub unsafe fn _mm512_maskz_srl_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_srl_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi32&expand=5407) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_sra_epi32(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsrad(a.as_i32x16(), count.as_i32x4())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi32&expand=5405) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_mask_sra_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sra_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi32&expand=5406) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad))] +pub unsafe fn _mm512_maskz_sra_epi32(k: __mmask16, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sra_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sra_epi64&expand=5416) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_sra_epi64(a: __m512i, count: __m128i) -> __m512i { + transmute(vpsraq(a.as_i64x8(), count.as_i64x2())) +} + +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sra_epi64&expand=5414) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_mask_sra_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m128i, +) -> __m512i { + let shf = _mm512_sra_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sra_epi64&expand=5415) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq))] +pub unsafe fn _mm512_maskz_sra_epi64(k: __mmask8, a: __m512i, count: __m128i) -> __m512i { + let shf = _mm512_sra_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi32&expand=5436) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srai_epi32(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraid(a.as_i32x16(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi32&expand=5434) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srai_epi32(src: __m512i, k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi32&expand=5435) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrad, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srai_epi32(k: __mmask16, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraid(a.as_i32x16(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srai_epi64&expand=5445) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_srai_epi64(a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a.as_i64x8(), $imm8) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srai_epi64&expand=5443) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_srai_epi64(src: __m512i, k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by imm8 while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srai_epi64&expand=5444) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsraq, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_srai_epi64(k: __mmask8, a: __m512i, imm8: u32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpsraiq(a.as_i64x8(), $imm8) + }; + } + let shf = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi32&expand=5465) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_srav_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsravd(a.as_i32x16(), count.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi32&expand=5463) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_mask_srav_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srav_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi32&expand=5464) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravd))] +pub unsafe fn _mm512_maskz_srav_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srav_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srav_epi64&expand=5474) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_srav_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsravq(a.as_i64x8(), count.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srav_epi64&expand=5472) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_mask_srav_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srav_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in sign bits, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srav_epi64&expand=5473) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsravq))] +pub unsafe fn _mm512_maskz_srav_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srav_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi32&expand=4703) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_rolv_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vprolvd(a.as_i32x16(), b.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi32&expand=4701) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_mask_rolv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let rol = _mm512_rolv_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, rol, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi32&expand=4702) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvd))] +pub unsafe fn _mm512_maskz_rolv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi32&expand=4739) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_rorv_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(vprorvd(a.as_i32x16(), b.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi32&expand=4737) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_mask_rorv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, +) -> __m512i { + let ror = _mm512_rorv_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, ror, src.as_i32x16())) +} + +/// Rotate the bits in each packed 32-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi32&expand=4738) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvd))] +pub unsafe fn _mm512_maskz_rorv_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rolv_epi64&expand=4712) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_rolv_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vprolvq(a.as_i64x8(), b.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rolv_epi64&expand=4710) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_mask_rolv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, rol, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the left by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rolv_epi64&expand=4711) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprolvq))] +pub unsafe fn _mm512_maskz_rolv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let rol = _mm512_rolv_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, rol, zero)) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_rorv_epi64&expand=4748) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_rorv_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(vprorvq(a.as_i64x8(), b.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_rorv_epi64&expand=4746) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_mask_rorv_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, ror, src.as_i64x8())) +} + +/// Rotate the bits in each packed 64-bit integer in a to the right by the number of bits specified in the corresponding element of b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_rorv_epi64&expand=4747) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vprorvq))] +pub unsafe fn _mm512_maskz_rorv_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let ror = _mm512_rorv_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, ror, zero)) +} + +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi32&expand=5342) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_sllv_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsllvd(a.as_i32x16(), count.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi32&expand=5340) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_mask_sllv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_sllv_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi32&expand=5341) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvd))] +pub unsafe fn _mm512_maskz_sllv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_sllv_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi32&expand=5554) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_srlv_epi32(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsrlvd(a.as_i32x16(), count.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_srlv_epi32&expand=5552) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_mask_srlv_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srlv_epi32(a, count).as_i32x16(); + transmute(simd_select_bitmask(k, shf, src.as_i32x16())) +} + +/// Shift packed 32-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi32&expand=5553) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvd))] +pub unsafe fn _mm512_maskz_srlv_epi32(k: __mmask16, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srlv_epi32(a, count).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_sllv_epi64&expand=5351) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_sllv_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsllvq(a.as_i64x8(), count.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_sllv_epi64&expand=5349) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_mask_sllv_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_sllv_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a left by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_sllv_epi64&expand=5350) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsllvq))] +pub unsafe fn _mm512_maskz_sllv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_sllv_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_srlv_epi64&expand=5563) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_srlv_epi64(a: __m512i, count: __m512i) -> __m512i { + transmute(vpsrlvq(a.as_i64x8(), count.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mask_srlv_epi64&expand=5561) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_mask_srlv_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + count: __m512i, +) -> __m512i { + let shf = _mm512_srlv_epi64(a, count).as_i64x8(); + transmute(simd_select_bitmask(k, shf, src.as_i64x8())) +} + +/// Shift packed 64-bit integers in a right by the amount specified by the corresponding element in count while shifting in zeros, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_srlv_epi64&expand=5562) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpsrlvq))] +pub unsafe fn _mm512_maskz_srlv_epi64(k: __mmask8, a: __m512i, count: __m512i) -> __m512i { + let shf = _mm512_srlv_epi64(a, count).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shf, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_ps&expand=4170) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permute_ps(a: __m512, imm8: i32) -> __m512 { + macro_rules! call { + ($imm8:expr) => { + vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_ps&expand=4168) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permute_ps(src: __m512, k: __mmask16, a: __m512, imm8: i32) -> __m512 { + macro_rules! call { + ($imm8:expr) => { + vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_ps&expand=4169) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 1))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permute_ps(k: __mmask16, a: __m512, imm8: i32) -> __m512 { + macro_rules! call { + ($imm8:expr) => { + vpermilps(a.as_f32x16(), _mm512_set1_epi32($imm8).as_i32x16()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permute_pd&expand=4161) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permute_pd(a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permute_pd&expand=4159) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permute_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permute_pd&expand=4160) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd, imm8 = 2))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permute_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermilpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_epi64&expand=4208) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] +//shoud be vpermq, but generate vpermpd. It generates vpermq with mask. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permutex_epi64(a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_epi64&expand=4206) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permutex_epi64( + src: __m512i, + k: __mmask8, + a: __m512i, + imm8: i32, +) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_i64x8())) +} + +/// Shuffle 64-bit integers in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_epi64&expand=4207) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpbroadcast, imm8 = 0b11111111))] //shoud be vpermq. change to vpbroadcast becaise CI Windows +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permutex_epi64(k: __mmask8, a: __m512i, imm8: i32) -> __m512i { + macro_rules! call { + ($imm8:expr) => { + vpermq(a.as_i64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex_pd&expand=4214) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_permutex_pd(a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let r = constify_imm8_sae!(imm8, call); + transmute(r) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex_pd&expand=4212) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_permutex_pd(src: __m512d, k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 256-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex_pd&expand=4213) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vbroadcast, imm8 = 0b11111111))] //shoud be vpermpd. change to vbroadcast becaise CI Windows +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_permutex_pd(k: __mmask8, a: __m512d, imm8: i32) -> __m512d { + macro_rules! call { + ($imm8:expr) => { + vpermpd(a.as_f64x8(), _mm512_set1_epi64($imm8).as_i64x8()) + }; + } + let permute = constify_imm8_sae!(imm8, call); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_permutexvar_epi32, and it is recommended that you use that intrinsic name. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_epi32&expand=4182) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask +pub unsafe fn _mm512_permutevar_epi32(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). Note that this intrinsic shuffles across 128-bit lanes, unlike past intrinsics that use the permutevar name. This intrinsic is identical to _mm512_mask_permutexvar_epi32, and it is recommended that you use that intrinsic name. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_epi32&expand=4181) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_mask_permutevar_epi32( + src: __m512i, + k: __mmask16, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutevar_epi32(idx, a).as_i32x16(); + transmute(simd_select_bitmask(k, permute, src.as_i32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_permutevar_ps(a: __m512, b: __m512i) -> __m512 { + transmute(vpermilps(a.as_f32x16(), b.as_i32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_ps&expand=4198) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_mask_permutevar_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512i, +) -> __m512 { + let permute = _mm512_permutevar_ps(a, b).as_f32x16(); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_ps&expand=4199) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps))] +pub unsafe fn _mm512_maskz_permutevar_ps(k: __mmask16, a: __m512, b: __m512i) -> __m512 { + let permute = _mm512_permutevar_ps(a, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_pd&expand=4191) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_permutevar_pd(a: __m512d, b: __m512i) -> __m512d { + transmute(vpermilpd(a.as_f64x8(), b.as_i64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutevar_pd&expand=4189) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_mask_permutevar_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512i, +) -> __m512d { + let permute = _mm512_permutevar_pd(a, b).as_f64x8(); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a within 128-bit lanes using the control in b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutevar_pd&expand=4190) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilpd))] +pub unsafe fn _mm512_maskz_permutevar_pd(k: __mmask8, a: __m512d, b: __m512i) -> __m512d { + let permute = _mm512_permutevar_pd(a, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi32&expand=4301) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermd, but generate vpermps. It generates vpermd with mask +pub unsafe fn _mm512_permutexvar_epi32(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermd(a.as_i32x16(), idx.as_i32x16())) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi32&expand=4299) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_mask_permutexvar_epi32( + src: __m512i, + k: __mmask16, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); + transmute(simd_select_bitmask(k, permute, src.as_i32x16())) +} + +/// Shuffle 32-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi32&expand=4300) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermd))] +pub unsafe fn _mm512_maskz_permutexvar_epi32(k: __mmask16, idx: __m512i, a: __m512i) -> __m512i { + let permute = _mm512_permutexvar_epi32(idx, a).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_epi64&expand=4307) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermq, but generate vpermpd. It generates vpermd with mask +pub unsafe fn _mm512_permutexvar_epi64(idx: __m512i, a: __m512i) -> __m512i { + transmute(vpermq(a.as_i64x8(), idx.as_i64x8())) +} + +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_epi64&expand=4305) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermq))] +pub unsafe fn _mm512_mask_permutexvar_epi64( + src: __m512i, + k: __mmask8, + idx: __m512i, + a: __m512i, +) -> __m512i { + let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); + transmute(simd_select_bitmask(k, permute, src.as_i64x8())) +} + +/// Shuffle 64-bit integers in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_epi64&expand=4306) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermq))] +pub unsafe fn _mm512_maskz_permutexvar_epi64(k: __mmask8, idx: __m512i, a: __m512i) -> __m512i { + let permute = _mm512_permutexvar_epi64(idx, a).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutevar_ps&expand=4200) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_permutexvar_ps(idx: __m512i, a: __m512) -> __m512 { + transmute(vpermps(a.as_f32x16(), idx.as_i32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_ps&expand=4326) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_mask_permutexvar_ps( + src: __m512, + k: __mmask16, + idx: __m512i, + a: __m512, +) -> __m512 { + let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); + transmute(simd_select_bitmask(k, permute, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_ps&expand=4327) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermps))] +pub unsafe fn _mm512_maskz_permutexvar_ps(k: __mmask16, idx: __m512i, a: __m512) -> __m512 { + let permute = _mm512_permutexvar_ps(idx, a).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutexvar_pd&expand=4322) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_permutexvar_pd(idx: __m512i, a: __m512d) -> __m512d { + transmute(vpermpd(a.as_f64x8(), idx.as_i64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutexvar_pd&expand=4320) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_mask_permutexvar_pd( + src: __m512d, + k: __mmask8, + idx: __m512i, + a: __m512d, +) -> __m512d { + let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); + transmute(simd_select_bitmask(k, permute, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a across lanes using the corresponding index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutexvar_pd&expand=4321) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermpd))] +pub unsafe fn _mm512_maskz_permutexvar_pd(k: __mmask8, idx: __m512i, a: __m512d) -> __m512d { + let permute = _mm512_permutexvar_pd(idx, a).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi32&expand=4238) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d +pub unsafe fn _mm512_permutex2var_epi32(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { + transmute(vpermi2d(a.as_i32x16(), idx.as_i32x16(), b.as_i32x16())) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi32&expand=4235) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2d))] +pub unsafe fn _mm512_mask_permutex2var_epi32( + a: __m512i, + k: __mmask16, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + transmute(simd_select_bitmask(k, permute, a.as_i32x16())) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi32&expand=4237) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2d or vpermt2d +pub unsafe fn _mm512_maskz_permutex2var_epi32( + k: __mmask16, + a: __m512i, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 32-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi32&expand=4236) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermi2d))] +pub unsafe fn _mm512_mask2_permutex2var_epi32( + a: __m512i, + idx: __m512i, + k: __mmask16, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi32(a, idx, b).as_i32x16(); + transmute(simd_select_bitmask(k, permute, idx.as_i32x16())) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_epi64&expand=4250) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q +pub unsafe fn _mm512_permutex2var_epi64(a: __m512i, idx: __m512i, b: __m512i) -> __m512i { + transmute(vpermi2q(a.as_i64x8(), idx.as_i64x8(), b.as_i64x8())) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_epi64&expand=4247) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2q))] +pub unsafe fn _mm512_mask_permutex2var_epi64( + a: __m512i, + k: __mmask8, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + transmute(simd_select_bitmask(k, permute, a.as_i64x8())) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_epi64&expand=4249) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2q or vpermt2q +pub unsafe fn _mm512_maskz_permutex2var_epi64( + k: __mmask8, + a: __m512i, + idx: __m512i, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle 64-bit integers in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_epi64&expand=4248) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermi2q))] +pub unsafe fn _mm512_mask2_permutex2var_epi64( + a: __m512i, + idx: __m512i, + k: __mmask8, + b: __m512i, +) -> __m512i { + let permute = _mm512_permutex2var_epi64(a, idx, b).as_i64x8(); + transmute(simd_select_bitmask(k, permute, idx.as_i64x8())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_ps&expand=4286) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps +pub unsafe fn _mm512_permutex2var_ps(a: __m512, idx: __m512i, b: __m512) -> __m512 { + transmute(vpermi2ps(a.as_f32x16(), idx.as_i32x16(), b.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_ps&expand=4283) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2ps))] +pub unsafe fn _mm512_mask_permutex2var_ps( + a: __m512, + k: __mmask16, + idx: __m512i, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + transmute(simd_select_bitmask(k, permute, a.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_ps&expand=4285) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2ps or vpermt2ps +pub unsafe fn _mm512_maskz_permutex2var_ps( + k: __mmask16, + a: __m512, + idx: __m512i, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_ps&expand=4284) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2ps, but it shows vpermt2ps +pub unsafe fn _mm512_mask2_permutex2var_ps( + a: __m512, + idx: __m512i, + k: __mmask16, + b: __m512, +) -> __m512 { + let permute = _mm512_permutex2var_ps(a, idx, b).as_f32x16(); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_permutex2var_pd&expand=4274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd +pub unsafe fn _mm512_permutex2var_pd(a: __m512d, idx: __m512i, b: __m512d) -> __m512d { + transmute(vpermi2pd(a.as_f64x8(), idx.as_i64x8(), b.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from a when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_permutex2var_pd&expand=4271) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermt2pd))] +pub unsafe fn _mm512_mask_permutex2var_pd( + a: __m512d, + k: __mmask8, + idx: __m512i, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + transmute(simd_select_bitmask(k, permute, a.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_permutex2var_pd&expand=4273) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //vpermi2pd or vpermt2pd +pub unsafe fn _mm512_maskz_permutex2var_pd( + k: __mmask8, + a: __m512d, + idx: __m512i, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements in a and b across lanes using the corresponding selector and index in idx, and store the results in dst using writemask k (elements are copied from idx when the corresponding mask bit is not set) +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask2_permutex2var_pd&expand=4272) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vperm))] //should be vpermi2pd, but it shows vpermt2pd +pub unsafe fn _mm512_mask2_permutex2var_pd( + a: __m512d, + idx: __m512i, + k: __mmask8, + b: __m512d, +) -> __m512d { + let permute = _mm512_permutex2var_pd(a, idx, b).as_f64x8(); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, permute, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_epi32&expand=5150) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpermilps, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_shuffle_epi32(a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let r: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + transmute(r) +} + +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_epi32&expand=5148) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_mask_shuffle_epi32( + src: __m512i, + k: __mmask16, + a: __m512i, + imm8: _MM_PERM_ENUM, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) +} + +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_epi32&expand=5149) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpshufd, imm8 = 9))] //should be vpshufd, but generate vpermilps +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_maskz_shuffle_epi32(k: __mmask16, a: __m512i, imm8: _MM_PERM_ENUM) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + a, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_ps&expand=5203) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_ps(a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + } +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_ps&expand=5201) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_ps( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + imm8: i32, +) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) +} + +/// Shuffle single-precision (32-bit) floating-point elements in a within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_ps&expand=5202) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufps, imm8 = 0))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_ps(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, 16, $e, $f, $g, 20, $i, $j, $k, 24, $m, $n, $o, 28), + 1 => shuffle4!($a, $b, $c, 17, $e, $f, $g, 21, $i, $j, $k, 25, $m, $n, $o, 29), + 2 => shuffle4!($a, $b, $c, 18, $e, $f, $g, 22, $i, $j, $k, 26, $m, $n, $o, 30), + _ => shuffle4!($a, $b, $c, 19, $e, $f, $g, 23, $i, $j, $k, 27, $m, $n, $o, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, 16, $e, $f, 20, $i, $j, 24, $m, $n, 28), + 1 => shuffle3!($a, $b, 17, $e, $f, 21, $i, $j, 25, $m, $n, 29), + 2 => shuffle3!($a, $b, 18, $e, $f, 22, $i, $j, 26, $m, $n, 30), + _ => shuffle3!($a, $b, 19, $e, $f, 23, $i, $j, 27, $m, $n, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, 0, $e, 4, $i, 8, $m, 12), + 1 => shuffle2!($a, 1, $e, 5, $i, 9, $m, 13), + 2 => shuffle2!($a, 2, $e, 6, $i, 10, $m, 14), + _ => shuffle2!($a, 3, $e, 7, $i, 11, $m, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 4, 8, 12), + 1 => shuffle1!(1, 5, 9, 13), + 2 => shuffle1!(2, 6, 10, 14), + _ => shuffle1!(3, 7, 11, 15), + }; + + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_pd&expand=5192) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_pd(a: __m512d, b: __m512d, imm8: i32) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + } +} + +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_pd&expand=5190) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_pd( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + let shuffle = match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) +} + +/// Shuffle double-precision (64-bit) floating-point elements within 128-bit lanes using the control in imm8, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_pd&expand=5191) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufpd, imm8 = 3))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_pd(k: __mmask8, a: __m512d, b: __m512d, imm8: i32) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle8 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr, $h:expr) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle7 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 7) & 0x1 { + 0 => shuffle8!($a, $b, $c, $d, $e, $f, $g, 14), + _ => shuffle8!($a, $b, $c, $d, $e, $f, $g, 15), + } + }; + } + macro_rules! shuffle6 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr, $f:expr) => { + match (imm8 >> 6) & 0x1 { + 0 => shuffle7!($a, $b, $c, $d, $e, $f, 6), + _ => shuffle7!($a, $b, $c, $d, $e, $f, 7), + } + }; + } + macro_rules! shuffle5 { + ($a:expr, $b:expr, $c:expr, $d:expr, $e:expr) => { + match (imm8 >> 5) & 0x1 { + 0 => shuffle6!($a, $b, $c, $d, $e, 12), + _ => shuffle6!($a, $b, $c, $d, $e, 13), + } + }; + } + macro_rules! shuffle4 { + ($a:expr, $b:expr, $c:expr, $d:expr) => { + match (imm8 >> 4) & 0x1 { + 0 => shuffle5!($a, $b, $c, $d, 4), + _ => shuffle5!($a, $b, $c, $d, 5), + } + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr) => { + match (imm8 >> 3) & 0x1 { + 0 => shuffle4!($a, $b, $c, 10), + _ => shuffle4!($a, $b, $c, 11), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr) => { + match (imm8 >> 2) & 0x1 { + 0 => shuffle3!($a, $b, 2), + _ => shuffle3!($a, $b, 3), + } + }; + } + macro_rules! shuffle1 { + ($a:expr) => { + match (imm8 >> 1) & 0x1 { + 0 => shuffle2!($a, 8), + _ => shuffle2!($a, 9), + } + }; + } + let shuffle = match imm8 & 0x1 { + 0 => shuffle1!(0), + _ => shuffle1!(1), + }; + + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i32&expand=5177) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] //should be vshufi32x4, but generate vshufi64x2 +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_i32x4(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let r: i32x16 = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(r) +} + +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i32x&expand=5175) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_i32x4( + src: __m512i, + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_i32x16())) +} + +/// Shuffle 128-bits (composed of 4 32-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i32&expand=5176) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_i32x4( + k: __mmask16, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + + let a = a.as_i32x16(); + let b = b.as_i32x16(); + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_i64x2&expand=5183) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_i64x2(a: __m512i, b: __m512i, imm8: i32) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + } +} + +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_i64x&expand=5181) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_i64x2( + src: __m512i, + k: __mmask8, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_i64x8())) +} + +/// Shuffle 128-bits (composed of 2 64-bit integers) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_i64&expand=5182) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshufi64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_i64x2( + k: __mmask8, + a: __m512i, + b: __m512i, + imm8: i32, +) -> __m512i { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f32x4&expand=5165) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] //should be vshuff32x4, but generate vshuff64x2 +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_f32x4(a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + } +} + +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f32&expand=5163) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_f32x4( + src: __m512, + k: __mmask16, + a: __m512, + b: __m512, + imm8: i32, +) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f32x16())) +} + +/// Shuffle 128-bits (composed of 4 single-precision (32-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f32&expand=5164) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff32x4, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_f32x4(k: __mmask16, a: __m512, b: __m512, imm8: i32) -> __m512 { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr, + $i:expr, + $j:expr, + $k:expr, + $l:expr, + $m:expr, + $n:expr, + $o:expr, + $p:expr + ) => { + simd_shuffle16( + a, + b, + [ + $a, $b, $c, $d, $e, $f, $g, $h, $i, $j, $k, $l, $m, $n, $o, $p, + ], + ); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr, $i:expr, $j:expr, $k:expr, $m:expr, $n:expr, $o:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 16, 17, 18, 19), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 20, 21, 22, 23), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 24, 25, 26, 27), + _ => shuffle4!($a, $b, $c, $e, $f, $g, $i, $j, $k, $m, $n, $o, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr, $i:expr, $j:expr, $m:expr, $n:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 16, 17, 18, 19), + 1 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 20, 21, 22, 23), + 2 => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 24, 25, 26, 27), + _ => shuffle3!($a, $b, $e, $f, $i, $j, $m, $n, 28, 29, 30, 31), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr, $i: expr, $m: expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, $i, $m, 0, 1, 2, 3), + 1 => shuffle2!($a, $e, $i, $m, 4, 5, 6, 7), + 2 => shuffle2!($a, $e, $i, $m, 8, 9, 10, 11), + _ => shuffle2!($a, $e, $i, $m, 12, 13, 14, 15), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1, 2, 3), + 1 => shuffle1!(4, 5, 6, 7), + 2 => shuffle1!(8, 9, 10, 11), + _ => shuffle1!(12, 13, 14, 15), + }; + + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_shuffle_f64x2&expand=5171) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(2)] +pub unsafe fn _mm512_shuffle_f64x2(a: __m512d, b: __m512d, imm8: i32) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + } +} + +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_shuffle_f64x2&expand=5169) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(4)] +pub unsafe fn _mm512_mask_shuffle_f64x2( + src: __m512d, + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + transmute(simd_select_bitmask(k, shuffle, src.as_f64x8())) +} + +/// Shuffle 128-bits (composed of 2 double-precision (64-bit) floating-point elements) selected by imm8 from a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_shuffle_f64x2&expand=5170) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vshuff64x2, imm8 = 0b10111111))] +#[rustc_args_required_const(3)] +pub unsafe fn _mm512_maskz_shuffle_f64x2( + k: __mmask8, + a: __m512d, + b: __m512d, + imm8: i32, +) -> __m512d { + let imm8 = (imm8 & 0xFF) as u8; + macro_rules! shuffle4 { + ( + $a:expr, + $b:expr, + $c:expr, + $d:expr, + $e:expr, + $f:expr, + $g:expr, + $h:expr + ) => { + simd_shuffle8(a, b, [$a, $b, $c, $d, $e, $f, $g, $h]); + }; + } + macro_rules! shuffle3 { + ($a:expr, $b:expr, $c:expr, $e:expr, $f:expr, $g:expr) => { + match (imm8 >> 6) & 0x3 { + 0 => shuffle4!($a, $b, $c, $e, $f, $g, 8, 9), + 1 => shuffle4!($a, $b, $c, $e, $f, $g, 10, 11), + 2 => shuffle4!($a, $b, $c, $e, $f, $g, 12, 13), + _ => shuffle4!($a, $b, $c, $e, $f, $g, 14, 15), + } + }; + } + macro_rules! shuffle2 { + ($a:expr, $b:expr, $e:expr, $f:expr) => { + match (imm8 >> 4) & 0x3 { + 0 => shuffle3!($a, $b, $e, $f, 8, 9), + 1 => shuffle3!($a, $b, $e, $f, 10, 11), + 2 => shuffle3!($a, $b, $e, $f, 12, 13), + _ => shuffle3!($a, $b, $e, $f, 14, 15), + } + }; + } + macro_rules! shuffle1 { + ($a:expr, $e:expr) => { + match (imm8 >> 2) & 0x3 { + 0 => shuffle2!($a, $e, 0, 1), + 1 => shuffle2!($a, $e, 2, 3), + 2 => shuffle2!($a, $e, 4, 5), + _ => shuffle2!($a, $e, 6, 7), + } + }; + } + let shuffle = match imm8 & 0x3 { + 0 => shuffle1!(0, 1), + 1 => shuffle1!(2, 3), + 2 => shuffle1!(4, 5), + _ => shuffle1!(6, 7), + }; + + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, shuffle, zero)) +} + +/// Extract 128 bits (composed of 4 packed single-precision (32-bit) floating-point elements) from a, selected with imm8, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_extractf32x4_ps&expand=2442) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr( + all(test, not(target_os = "windows")), + assert_instr(vextractf32x4, imm8 = 3) +)] +#[rustc_args_required_const(1)] +pub unsafe fn _mm512_extractf32x4_ps(a: __m512, imm8: i32) -> __m128 { + match imm8 & 0x3 { + 0 => simd_shuffle4(a, _mm512_undefined_ps(), [0, 1, 2, 3]), + 1 => simd_shuffle4(a, _mm512_undefined_ps(), [4, 5, 6, 7]), + 2 => simd_shuffle4(a, _mm512_undefined_ps(), [8, 9, 10, 11]), + _ => simd_shuffle4(a, _mm512_undefined_ps(), [12, 13, 14, 15]), + } +} + +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_moveldup_ps&expand=3862) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_moveldup_ps(a: __m512) -> __m512 { + let r: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + transmute(r) +} + +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_moveldup_ps&expand=3860) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_mask_moveldup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + transmute(simd_select_bitmask(k, mov, src.as_f32x16())) +} + +/// Duplicate even-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveldup_ps&expand=3861) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovsldup))] +pub unsafe fn _mm512_maskz_moveldup_ps(k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14]); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movehdup_ps&expand=3852) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_movehdup_ps(a: __m512) -> __m512 { + let r: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + transmute(r) +} + +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movehdup&expand=3850) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_mask_movehdup_ps(src: __m512, k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + transmute(simd_select_bitmask(k, mov, src.as_f32x16())) +} + +/// Duplicate odd-indexed single-precision (32-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_moveh&expand=3851) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovshdup))] +pub unsafe fn _mm512_maskz_movehdup_ps(k: __mmask16, a: __m512) -> __m512 { + let mov: f32x16 = simd_shuffle16(a, a, [1, 1, 3, 3, 5, 5, 7, 7, 9, 9, 11, 11, 13, 13, 15, 15]); + let zero = _mm512_setzero_ps().as_f32x16(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_movedup_pd&expand=3843) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_movedup_pd(a: __m512d) -> __m512d { + let r: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + transmute(r) +} + +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_movedup_pd&expand=3841) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_mask_movedup_pd(src: __m512d, k: __mmask8, a: __m512d) -> __m512d { + let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + transmute(simd_select_bitmask(k, mov, src.as_f64x8())) +} + +/// Duplicate even-indexed double-precision (64-bit) floating-point elements from a, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_movedup_pd&expand=3842) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vmovddup))] +pub unsafe fn _mm512_maskz_movedup_pd(k: __mmask8, a: __m512d) -> __m512d { + let mov: f64x8 = simd_shuffle8(a, a, [0, 0, 2, 2, 4, 4, 6, 6]); + let zero = _mm512_setzero_pd().as_f64x8(); + transmute(simd_select_bitmask(k, mov, zero)) +} + +/// Shuffle 32-bit integers in a within 128-bit lanes using the control in imm8, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi32&expand=272) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] //should be vpandd, but generate vpandq +pub unsafe fn _mm512_and_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i32x16(), b.as_i32x16())) +} + +/// Performs element-by-element bitwise AND between packed 32-bit integer elements of v2 and v3, storing the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi32&expand=273) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_mask_and_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, and, src.as_i32x16())) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_epi32&expand=274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandd))] +pub unsafe fn _mm512_maskz_and_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, and, zero)) +} + +/// Compute the bitwise AND of 512 bits (composed of packed 64-bit integers) in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_epi64&expand=279) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_and_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise AND of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_and_epi64&expand=280) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_mask_and_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, and, src.as_i64x8())) +} + +/// Compute the bitwise AND of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_and_Epi32&expand=274) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_maskz_and_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let and = _mm512_and_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, and, zero)) +} + +/// Compute the bitwise AND of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_and_si512&expand=302) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpandq))] +pub unsafe fn _mm512_and_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_and(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi32&expand=4042) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi32&expand=4040) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpord))] +pub unsafe fn _mm512_mask_or_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, or, src.as_i32x16())) +} + +/// Compute the bitwise OR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi32&expand=4041) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpord))] +pub unsafe fn _mm512_maskz_or_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, or, zero)) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the resut in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_epi64&expand=4051) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_or_epi64&expand=4049) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_mask_or_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, or, src.as_i64x8())) +} + +/// Compute the bitwise OR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_or_epi64&expand=4050) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_maskz_or_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let or = _mm512_or_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, or, zero)) +} + +/// Compute the bitwise OR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_or_si512&expand=4072) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vporq))] +pub unsafe fn _mm512_or_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_or(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi32&expand=6142) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_epi32(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi32&expand=6140) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxord))] +pub unsafe fn _mm512_mask_xor_epi32(src: __m512i, k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi32(a, b).as_i32x16(); + transmute(simd_select_bitmask(k, xor, src.as_i32x16())) +} + +/// Compute the bitwise XOR of packed 32-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi32&expand=6141) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxord))] +pub unsafe fn _mm512_maskz_xor_epi32(k: __mmask16, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi32(a, b).as_i32x16(); + let zero = _mm512_setzero_si512().as_i32x16(); + transmute(simd_select_bitmask(k, xor, zero)) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_epi64&expand=6151) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_epi64(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i64x8(), b.as_i64x8())) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using writemask k (elements are copied from src when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_mask_xor_epi64&expand=6149) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_mask_xor_epi64(src: __m512i, k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi64(a, b).as_i64x8(); + transmute(simd_select_bitmask(k, xor, src.as_i64x8())) +} + +/// Compute the bitwise XOR of packed 64-bit integers in a and b, and store the results in dst using zeromask k (elements are zeroed out when the corresponding mask bit is not set). +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_maskz_xor_epi64&expand=6150) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_maskz_xor_epi64(k: __mmask8, a: __m512i, b: __m512i) -> __m512i { + let xor = _mm512_xor_epi64(a, b).as_i64x8(); + let zero = _mm512_setzero_si512().as_i64x8(); + transmute(simd_select_bitmask(k, xor, zero)) +} + +/// Compute the bitwise XOR of 512 bits (representing integer data) in a and b, and store the result in dst. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_xor_si512&expand=6172) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(vpxorq))] +pub unsafe fn _mm512_xor_si512(a: __m512i, b: __m512i) -> __m512i { + transmute(simd_xor(a.as_i32x16(), b.as_i32x16())) +} + +/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kand_mask16&expand=3212) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw +pub unsafe fn _kand_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a & b) +} + +/// Compute the bitwise AND of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kand&expand=3210) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(and))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kand(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a & b) +} + +/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kor_mask16&expand=3239) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw +pub unsafe fn _kor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a | b) +} + +/// Compute the bitwise OR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kor&expand=3237) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(or))] // generate normal or code instead of korw +pub unsafe fn _mm512_kor(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a | b) +} + +/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxor_mask16&expand=3291) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw +pub unsafe fn _kxor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a ^ b) +} + +/// Compute the bitwise XOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxor&expand=3289) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor code instead of kxorw +pub unsafe fn _mm512_kxor(a: __mmask16, b: __mmask16) -> __mmask16 { + transmute(a ^ b) +} + +/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=knot_mask16&expand=3233) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _knot_mask16(a: __mmask16) -> __mmask16 { + transmute(a ^ 0b11111111_11111111) +} + +/// Compute the bitwise NOT of 16-bit mask a, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_knot&expand=3231) +#[inline] +#[target_feature(enable = "avx512f")] +pub unsafe fn _mm512_knot(a: __mmask16) -> __mmask16 { + transmute(a ^ 0b11111111_11111111) +} + +/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kandn_mask16&expand=3218) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(not))] // generate normal and, not code instead of kandnw +pub unsafe fn _kandn_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_kand(_mm512_knot(a), b) +} + +/// Compute the bitwise NOT of 16-bit masks a and then AND with b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kandn&expand=3216) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(not))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kandn(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_kand(_mm512_knot(a), b) +} + +/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=kxnor_mask16&expand=3285) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal xor, not code instead of kxnorw +pub unsafe fn _kxnor_mask16(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_knot(_mm512_kxor(a, b)) +} + +/// Compute the bitwise XNOR of 16-bit masks a and b, and store the result in k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=512_kxnor&expand=3283) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(xor))] // generate normal and code instead of kandw +pub unsafe fn _mm512_kxnor(a: __mmask16, b: __mmask16) -> __mmask16 { + _mm512_knot(_mm512_kxor(a, b)) +} + +/// Copy 16-bit mask a to k. +/// +/// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=mm512_kmov&expand=3228) +#[inline] +#[target_feature(enable = "avx512f")] +#[cfg_attr(test, assert_instr(mov))] // generate normal and code instead of kmovw +pub unsafe fn _mm512_kmov(a: __mmask16) -> __mmask16 { + let r: u16 = a; + transmute(r) +} + /// Sets packed 32-bit integers in `dst` with the supplied values. /// /// [Intel's documentation]( https://software.intel.com/sites/landingpage/IntrinsicsGuide/#expand=727,1063,4909,1062,1062,4909&text=_mm512_set_ps) @@ -2422,8 +12156,380 @@ pub const _MM_CMPINT_NLE: _MM_CMPINT_ENUM = 0x06; /// True pub const _MM_CMPINT_TRUE: _MM_CMPINT_ENUM = 0x07; +/// interval [1, 2) +pub const _MM_MANT_NORM_1_2: _MM_MANTISSA_NORM_ENUM = 0x00; +/// interval [0.5, 2) +pub const _MM_MANT_NORM_P5_2: _MM_MANTISSA_NORM_ENUM = 0x01; +/// interval [0.5, 1) +pub const _MM_MANT_NORM_P5_1: _MM_MANTISSA_NORM_ENUM = 0x02; +/// interval [0.75, 1.5) +pub const _MM_MANT_NORM_P75_1P5: _MM_MANTISSA_NORM_ENUM = 0x03; + +/// sign = sign(SRC) +pub const _MM_MANT_SIGN_SRC: _MM_MANTISSA_SIGN_ENUM = 0x00; +/// sign = 0 +pub const _MM_MANT_SIGN_ZERO: _MM_MANTISSA_SIGN_ENUM = 0x01; +/// DEST = NaN if sign(SRC) = 1 +pub const _MM_MANT_SIGN_NAN: _MM_MANTISSA_SIGN_ENUM = 0x02; + +pub const _MM_PERM_AAAA: _MM_PERM_ENUM = 0x00; +pub const _MM_PERM_AAAB: _MM_PERM_ENUM = 0x01; +pub const _MM_PERM_AAAC: _MM_PERM_ENUM = 0x02; +pub const _MM_PERM_AAAD: _MM_PERM_ENUM = 0x03; +pub const _MM_PERM_AABA: _MM_PERM_ENUM = 0x04; +pub const _MM_PERM_AABB: _MM_PERM_ENUM = 0x05; +pub const _MM_PERM_AABC: _MM_PERM_ENUM = 0x06; +pub const _MM_PERM_AABD: _MM_PERM_ENUM = 0x07; +pub const _MM_PERM_AACA: _MM_PERM_ENUM = 0x08; +pub const _MM_PERM_AACB: _MM_PERM_ENUM = 0x09; +pub const _MM_PERM_AACC: _MM_PERM_ENUM = 0x0A; +pub const _MM_PERM_AACD: _MM_PERM_ENUM = 0x0B; +pub const _MM_PERM_AADA: _MM_PERM_ENUM = 0x0C; +pub const _MM_PERM_AADB: _MM_PERM_ENUM = 0x0D; +pub const _MM_PERM_AADC: _MM_PERM_ENUM = 0x0E; +pub const _MM_PERM_AADD: _MM_PERM_ENUM = 0x0F; +pub const _MM_PERM_ABAA: _MM_PERM_ENUM = 0x10; +pub const _MM_PERM_ABAB: _MM_PERM_ENUM = 0x11; +pub const _MM_PERM_ABAC: _MM_PERM_ENUM = 0x12; +pub const _MM_PERM_ABAD: _MM_PERM_ENUM = 0x13; +pub const _MM_PERM_ABBA: _MM_PERM_ENUM = 0x14; +pub const _MM_PERM_ABBB: _MM_PERM_ENUM = 0x15; +pub const _MM_PERM_ABBC: _MM_PERM_ENUM = 0x16; +pub const _MM_PERM_ABBD: _MM_PERM_ENUM = 0x17; +pub const _MM_PERM_ABCA: _MM_PERM_ENUM = 0x18; +pub const _MM_PERM_ABCB: _MM_PERM_ENUM = 0x19; +pub const _MM_PERM_ABCC: _MM_PERM_ENUM = 0x1A; +pub const _MM_PERM_ABCD: _MM_PERM_ENUM = 0x1B; +pub const _MM_PERM_ABDA: _MM_PERM_ENUM = 0x1C; +pub const _MM_PERM_ABDB: _MM_PERM_ENUM = 0x1D; +pub const _MM_PERM_ABDC: _MM_PERM_ENUM = 0x1E; +pub const _MM_PERM_ABDD: _MM_PERM_ENUM = 0x1F; +pub const _MM_PERM_ACAA: _MM_PERM_ENUM = 0x20; +pub const _MM_PERM_ACAB: _MM_PERM_ENUM = 0x21; +pub const _MM_PERM_ACAC: _MM_PERM_ENUM = 0x22; +pub const _MM_PERM_ACAD: _MM_PERM_ENUM = 0x23; +pub const _MM_PERM_ACBA: _MM_PERM_ENUM = 0x24; +pub const _MM_PERM_ACBB: _MM_PERM_ENUM = 0x25; +pub const _MM_PERM_ACBC: _MM_PERM_ENUM = 0x26; +pub const _MM_PERM_ACBD: _MM_PERM_ENUM = 0x27; +pub const _MM_PERM_ACCA: _MM_PERM_ENUM = 0x28; +pub const _MM_PERM_ACCB: _MM_PERM_ENUM = 0x29; +pub const _MM_PERM_ACCC: _MM_PERM_ENUM = 0x2A; +pub const _MM_PERM_ACCD: _MM_PERM_ENUM = 0x2B; +pub const _MM_PERM_ACDA: _MM_PERM_ENUM = 0x2C; +pub const _MM_PERM_ACDB: _MM_PERM_ENUM = 0x2D; +pub const _MM_PERM_ACDC: _MM_PERM_ENUM = 0x2E; +pub const _MM_PERM_ACDD: _MM_PERM_ENUM = 0x2F; +pub const _MM_PERM_ADAA: _MM_PERM_ENUM = 0x30; +pub const _MM_PERM_ADAB: _MM_PERM_ENUM = 0x31; +pub const _MM_PERM_ADAC: _MM_PERM_ENUM = 0x32; +pub const _MM_PERM_ADAD: _MM_PERM_ENUM = 0x33; +pub const _MM_PERM_ADBA: _MM_PERM_ENUM = 0x34; +pub const _MM_PERM_ADBB: _MM_PERM_ENUM = 0x35; +pub const _MM_PERM_ADBC: _MM_PERM_ENUM = 0x36; +pub const _MM_PERM_ADBD: _MM_PERM_ENUM = 0x37; +pub const _MM_PERM_ADCA: _MM_PERM_ENUM = 0x38; +pub const _MM_PERM_ADCB: _MM_PERM_ENUM = 0x39; +pub const _MM_PERM_ADCC: _MM_PERM_ENUM = 0x3A; +pub const _MM_PERM_ADCD: _MM_PERM_ENUM = 0x3B; +pub const _MM_PERM_ADDA: _MM_PERM_ENUM = 0x3C; +pub const _MM_PERM_ADDB: _MM_PERM_ENUM = 0x3D; +pub const _MM_PERM_ADDC: _MM_PERM_ENUM = 0x3E; +pub const _MM_PERM_ADDD: _MM_PERM_ENUM = 0x3F; +pub const _MM_PERM_BAAA: _MM_PERM_ENUM = 0x40; +pub const _MM_PERM_BAAB: _MM_PERM_ENUM = 0x41; +pub const _MM_PERM_BAAC: _MM_PERM_ENUM = 0x42; +pub const _MM_PERM_BAAD: _MM_PERM_ENUM = 0x43; +pub const _MM_PERM_BABA: _MM_PERM_ENUM = 0x44; +pub const _MM_PERM_BABB: _MM_PERM_ENUM = 0x45; +pub const _MM_PERM_BABC: _MM_PERM_ENUM = 0x46; +pub const _MM_PERM_BABD: _MM_PERM_ENUM = 0x47; +pub const _MM_PERM_BACA: _MM_PERM_ENUM = 0x48; +pub const _MM_PERM_BACB: _MM_PERM_ENUM = 0x49; +pub const _MM_PERM_BACC: _MM_PERM_ENUM = 0x4A; +pub const _MM_PERM_BACD: _MM_PERM_ENUM = 0x4B; +pub const _MM_PERM_BADA: _MM_PERM_ENUM = 0x4C; +pub const _MM_PERM_BADB: _MM_PERM_ENUM = 0x4D; +pub const _MM_PERM_BADC: _MM_PERM_ENUM = 0x4E; +pub const _MM_PERM_BADD: _MM_PERM_ENUM = 0x4F; +pub const _MM_PERM_BBAA: _MM_PERM_ENUM = 0x50; +pub const _MM_PERM_BBAB: _MM_PERM_ENUM = 0x51; +pub const _MM_PERM_BBAC: _MM_PERM_ENUM = 0x52; +pub const _MM_PERM_BBAD: _MM_PERM_ENUM = 0x53; +pub const _MM_PERM_BBBA: _MM_PERM_ENUM = 0x54; +pub const _MM_PERM_BBBB: _MM_PERM_ENUM = 0x55; +pub const _MM_PERM_BBBC: _MM_PERM_ENUM = 0x56; +pub const _MM_PERM_BBBD: _MM_PERM_ENUM = 0x57; +pub const _MM_PERM_BBCA: _MM_PERM_ENUM = 0x58; +pub const _MM_PERM_BBCB: _MM_PERM_ENUM = 0x59; +pub const _MM_PERM_BBCC: _MM_PERM_ENUM = 0x5A; +pub const _MM_PERM_BBCD: _MM_PERM_ENUM = 0x5B; +pub const _MM_PERM_BBDA: _MM_PERM_ENUM = 0x5C; +pub const _MM_PERM_BBDB: _MM_PERM_ENUM = 0x5D; +pub const _MM_PERM_BBDC: _MM_PERM_ENUM = 0x5E; +pub const _MM_PERM_BBDD: _MM_PERM_ENUM = 0x5F; +pub const _MM_PERM_BCAA: _MM_PERM_ENUM = 0x60; +pub const _MM_PERM_BCAB: _MM_PERM_ENUM = 0x61; +pub const _MM_PERM_BCAC: _MM_PERM_ENUM = 0x62; +pub const _MM_PERM_BCAD: _MM_PERM_ENUM = 0x63; +pub const _MM_PERM_BCBA: _MM_PERM_ENUM = 0x64; +pub const _MM_PERM_BCBB: _MM_PERM_ENUM = 0x65; +pub const _MM_PERM_BCBC: _MM_PERM_ENUM = 0x66; +pub const _MM_PERM_BCBD: _MM_PERM_ENUM = 0x67; +pub const _MM_PERM_BCCA: _MM_PERM_ENUM = 0x68; +pub const _MM_PERM_BCCB: _MM_PERM_ENUM = 0x69; +pub const _MM_PERM_BCCC: _MM_PERM_ENUM = 0x6A; +pub const _MM_PERM_BCCD: _MM_PERM_ENUM = 0x6B; +pub const _MM_PERM_BCDA: _MM_PERM_ENUM = 0x6C; +pub const _MM_PERM_BCDB: _MM_PERM_ENUM = 0x6D; +pub const _MM_PERM_BCDC: _MM_PERM_ENUM = 0x6E; +pub const _MM_PERM_BCDD: _MM_PERM_ENUM = 0x6F; +pub const _MM_PERM_BDAA: _MM_PERM_ENUM = 0x70; +pub const _MM_PERM_BDAB: _MM_PERM_ENUM = 0x71; +pub const _MM_PERM_BDAC: _MM_PERM_ENUM = 0x72; +pub const _MM_PERM_BDAD: _MM_PERM_ENUM = 0x73; +pub const _MM_PERM_BDBA: _MM_PERM_ENUM = 0x74; +pub const _MM_PERM_BDBB: _MM_PERM_ENUM = 0x75; +pub const _MM_PERM_BDBC: _MM_PERM_ENUM = 0x76; +pub const _MM_PERM_BDBD: _MM_PERM_ENUM = 0x77; +pub const _MM_PERM_BDCA: _MM_PERM_ENUM = 0x78; +pub const _MM_PERM_BDCB: _MM_PERM_ENUM = 0x79; +pub const _MM_PERM_BDCC: _MM_PERM_ENUM = 0x7A; +pub const _MM_PERM_BDCD: _MM_PERM_ENUM = 0x7B; +pub const _MM_PERM_BDDA: _MM_PERM_ENUM = 0x7C; +pub const _MM_PERM_BDDB: _MM_PERM_ENUM = 0x7D; +pub const _MM_PERM_BDDC: _MM_PERM_ENUM = 0x7E; +pub const _MM_PERM_BDDD: _MM_PERM_ENUM = 0x7F; +pub const _MM_PERM_CAAA: _MM_PERM_ENUM = 0x80; +pub const _MM_PERM_CAAB: _MM_PERM_ENUM = 0x81; +pub const _MM_PERM_CAAC: _MM_PERM_ENUM = 0x82; +pub const _MM_PERM_CAAD: _MM_PERM_ENUM = 0x83; +pub const _MM_PERM_CABA: _MM_PERM_ENUM = 0x84; +pub const _MM_PERM_CABB: _MM_PERM_ENUM = 0x85; +pub const _MM_PERM_CABC: _MM_PERM_ENUM = 0x86; +pub const _MM_PERM_CABD: _MM_PERM_ENUM = 0x87; +pub const _MM_PERM_CACA: _MM_PERM_ENUM = 0x88; +pub const _MM_PERM_CACB: _MM_PERM_ENUM = 0x89; +pub const _MM_PERM_CACC: _MM_PERM_ENUM = 0x8A; +pub const _MM_PERM_CACD: _MM_PERM_ENUM = 0x8B; +pub const _MM_PERM_CADA: _MM_PERM_ENUM = 0x8C; +pub const _MM_PERM_CADB: _MM_PERM_ENUM = 0x8D; +pub const _MM_PERM_CADC: _MM_PERM_ENUM = 0x8E; +pub const _MM_PERM_CADD: _MM_PERM_ENUM = 0x8F; +pub const _MM_PERM_CBAA: _MM_PERM_ENUM = 0x90; +pub const _MM_PERM_CBAB: _MM_PERM_ENUM = 0x91; +pub const _MM_PERM_CBAC: _MM_PERM_ENUM = 0x92; +pub const _MM_PERM_CBAD: _MM_PERM_ENUM = 0x93; +pub const _MM_PERM_CBBA: _MM_PERM_ENUM = 0x94; +pub const _MM_PERM_CBBB: _MM_PERM_ENUM = 0x95; +pub const _MM_PERM_CBBC: _MM_PERM_ENUM = 0x96; +pub const _MM_PERM_CBBD: _MM_PERM_ENUM = 0x97; +pub const _MM_PERM_CBCA: _MM_PERM_ENUM = 0x98; +pub const _MM_PERM_CBCB: _MM_PERM_ENUM = 0x99; +pub const _MM_PERM_CBCC: _MM_PERM_ENUM = 0x9A; +pub const _MM_PERM_CBCD: _MM_PERM_ENUM = 0x9B; +pub const _MM_PERM_CBDA: _MM_PERM_ENUM = 0x9C; +pub const _MM_PERM_CBDB: _MM_PERM_ENUM = 0x9D; +pub const _MM_PERM_CBDC: _MM_PERM_ENUM = 0x9E; +pub const _MM_PERM_CBDD: _MM_PERM_ENUM = 0x9F; +pub const _MM_PERM_CCAA: _MM_PERM_ENUM = 0xA0; +pub const _MM_PERM_CCAB: _MM_PERM_ENUM = 0xA1; +pub const _MM_PERM_CCAC: _MM_PERM_ENUM = 0xA2; +pub const _MM_PERM_CCAD: _MM_PERM_ENUM = 0xA3; +pub const _MM_PERM_CCBA: _MM_PERM_ENUM = 0xA4; +pub const _MM_PERM_CCBB: _MM_PERM_ENUM = 0xA5; +pub const _MM_PERM_CCBC: _MM_PERM_ENUM = 0xA6; +pub const _MM_PERM_CCBD: _MM_PERM_ENUM = 0xA7; +pub const _MM_PERM_CCCA: _MM_PERM_ENUM = 0xA8; +pub const _MM_PERM_CCCB: _MM_PERM_ENUM = 0xA9; +pub const _MM_PERM_CCCC: _MM_PERM_ENUM = 0xAA; +pub const _MM_PERM_CCCD: _MM_PERM_ENUM = 0xAB; +pub const _MM_PERM_CCDA: _MM_PERM_ENUM = 0xAC; +pub const _MM_PERM_CCDB: _MM_PERM_ENUM = 0xAD; +pub const _MM_PERM_CCDC: _MM_PERM_ENUM = 0xAE; +pub const _MM_PERM_CCDD: _MM_PERM_ENUM = 0xAF; +pub const _MM_PERM_CDAA: _MM_PERM_ENUM = 0xB0; +pub const _MM_PERM_CDAB: _MM_PERM_ENUM = 0xB1; +pub const _MM_PERM_CDAC: _MM_PERM_ENUM = 0xB2; +pub const _MM_PERM_CDAD: _MM_PERM_ENUM = 0xB3; +pub const _MM_PERM_CDBA: _MM_PERM_ENUM = 0xB4; +pub const _MM_PERM_CDBB: _MM_PERM_ENUM = 0xB5; +pub const _MM_PERM_CDBC: _MM_PERM_ENUM = 0xB6; +pub const _MM_PERM_CDBD: _MM_PERM_ENUM = 0xB7; +pub const _MM_PERM_CDCA: _MM_PERM_ENUM = 0xB8; +pub const _MM_PERM_CDCB: _MM_PERM_ENUM = 0xB9; +pub const _MM_PERM_CDCC: _MM_PERM_ENUM = 0xBA; +pub const _MM_PERM_CDCD: _MM_PERM_ENUM = 0xBB; +pub const _MM_PERM_CDDA: _MM_PERM_ENUM = 0xBC; +pub const _MM_PERM_CDDB: _MM_PERM_ENUM = 0xBD; +pub const _MM_PERM_CDDC: _MM_PERM_ENUM = 0xBE; +pub const _MM_PERM_CDDD: _MM_PERM_ENUM = 0xBF; +pub const _MM_PERM_DAAA: _MM_PERM_ENUM = 0xC0; +pub const _MM_PERM_DAAB: _MM_PERM_ENUM = 0xC1; +pub const _MM_PERM_DAAC: _MM_PERM_ENUM = 0xC2; +pub const _MM_PERM_DAAD: _MM_PERM_ENUM = 0xC3; +pub const _MM_PERM_DABA: _MM_PERM_ENUM = 0xC4; +pub const _MM_PERM_DABB: _MM_PERM_ENUM = 0xC5; +pub const _MM_PERM_DABC: _MM_PERM_ENUM = 0xC6; +pub const _MM_PERM_DABD: _MM_PERM_ENUM = 0xC7; +pub const _MM_PERM_DACA: _MM_PERM_ENUM = 0xC8; +pub const _MM_PERM_DACB: _MM_PERM_ENUM = 0xC9; +pub const _MM_PERM_DACC: _MM_PERM_ENUM = 0xCA; +pub const _MM_PERM_DACD: _MM_PERM_ENUM = 0xCB; +pub const _MM_PERM_DADA: _MM_PERM_ENUM = 0xCC; +pub const _MM_PERM_DADB: _MM_PERM_ENUM = 0xCD; +pub const _MM_PERM_DADC: _MM_PERM_ENUM = 0xCE; +pub const _MM_PERM_DADD: _MM_PERM_ENUM = 0xCF; +pub const _MM_PERM_DBAA: _MM_PERM_ENUM = 0xD0; +pub const _MM_PERM_DBAB: _MM_PERM_ENUM = 0xD1; +pub const _MM_PERM_DBAC: _MM_PERM_ENUM = 0xD2; +pub const _MM_PERM_DBAD: _MM_PERM_ENUM = 0xD3; +pub const _MM_PERM_DBBA: _MM_PERM_ENUM = 0xD4; +pub const _MM_PERM_DBBB: _MM_PERM_ENUM = 0xD5; +pub const _MM_PERM_DBBC: _MM_PERM_ENUM = 0xD6; +pub const _MM_PERM_DBBD: _MM_PERM_ENUM = 0xD7; +pub const _MM_PERM_DBCA: _MM_PERM_ENUM = 0xD8; +pub const _MM_PERM_DBCB: _MM_PERM_ENUM = 0xD9; +pub const _MM_PERM_DBCC: _MM_PERM_ENUM = 0xDA; +pub const _MM_PERM_DBCD: _MM_PERM_ENUM = 0xDB; +pub const _MM_PERM_DBDA: _MM_PERM_ENUM = 0xDC; +pub const _MM_PERM_DBDB: _MM_PERM_ENUM = 0xDD; +pub const _MM_PERM_DBDC: _MM_PERM_ENUM = 0xDE; +pub const _MM_PERM_DBDD: _MM_PERM_ENUM = 0xDF; +pub const _MM_PERM_DCAA: _MM_PERM_ENUM = 0xE0; +pub const _MM_PERM_DCAB: _MM_PERM_ENUM = 0xE1; +pub const _MM_PERM_DCAC: _MM_PERM_ENUM = 0xE2; +pub const _MM_PERM_DCAD: _MM_PERM_ENUM = 0xE3; +pub const _MM_PERM_DCBA: _MM_PERM_ENUM = 0xE4; +pub const _MM_PERM_DCBB: _MM_PERM_ENUM = 0xE5; +pub const _MM_PERM_DCBC: _MM_PERM_ENUM = 0xE6; +pub const _MM_PERM_DCBD: _MM_PERM_ENUM = 0xE7; +pub const _MM_PERM_DCCA: _MM_PERM_ENUM = 0xE8; +pub const _MM_PERM_DCCB: _MM_PERM_ENUM = 0xE9; +pub const _MM_PERM_DCCC: _MM_PERM_ENUM = 0xEA; +pub const _MM_PERM_DCCD: _MM_PERM_ENUM = 0xEB; +pub const _MM_PERM_DCDA: _MM_PERM_ENUM = 0xEC; +pub const _MM_PERM_DCDB: _MM_PERM_ENUM = 0xED; +pub const _MM_PERM_DCDC: _MM_PERM_ENUM = 0xEE; +pub const _MM_PERM_DCDD: _MM_PERM_ENUM = 0xEF; +pub const _MM_PERM_DDAA: _MM_PERM_ENUM = 0xF0; +pub const _MM_PERM_DDAB: _MM_PERM_ENUM = 0xF1; +pub const _MM_PERM_DDAC: _MM_PERM_ENUM = 0xF2; +pub const _MM_PERM_DDAD: _MM_PERM_ENUM = 0xF3; +pub const _MM_PERM_DDBA: _MM_PERM_ENUM = 0xF4; +pub const _MM_PERM_DDBB: _MM_PERM_ENUM = 0xF5; +pub const _MM_PERM_DDBC: _MM_PERM_ENUM = 0xF6; +pub const _MM_PERM_DDBD: _MM_PERM_ENUM = 0xF7; +pub const _MM_PERM_DDCA: _MM_PERM_ENUM = 0xF8; +pub const _MM_PERM_DDCB: _MM_PERM_ENUM = 0xF9; +pub const _MM_PERM_DDCC: _MM_PERM_ENUM = 0xFA; +pub const _MM_PERM_DDCD: _MM_PERM_ENUM = 0xFB; +pub const _MM_PERM_DDDA: _MM_PERM_ENUM = 0xFC; +pub const _MM_PERM_DDDB: _MM_PERM_ENUM = 0xFD; +pub const _MM_PERM_DDDC: _MM_PERM_ENUM = 0xFE; +pub const _MM_PERM_DDDD: _MM_PERM_ENUM = 0xFF; + #[allow(improper_ctypes)] extern "C" { + #[link_name = "llvm.x86.avx512.pmul.dq.512"] + fn vpmuldq(a: i32x16, b: i32x16) -> i64x8; + #[link_name = "llvm.x86.avx512.pmulu.dq.512"] + fn vpmuludq(a: u32x16, b: u32x16) -> u64x8; + + #[link_name = "llvm.x86.avx512.mask.pmaxs.d.512"] + fn vpmaxsd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pmaxs.q.512"] + fn vpmaxsq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pmins.d.512"] + fn vpminsd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pmins.q.512"] + fn vpminsq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.mask.pmaxu.d.512"] + fn vpmaxud(a: u32x16, b: u32x16) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.pmaxu.q.512"] + fn vpmaxuq(a: u64x8, b: u64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pminu.d.512"] + fn vpminud(a: u32x16, b: u32x16) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.pminu.q.512"] + fn vpminuq(a: u64x8, b: u64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.sqrt.ps.512"] + fn vsqrtps(a: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.sqrt.pd.512"] + fn vsqrtpd(a: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.vfmadd.ps.512"] + fn vfmadd132ps(a: f32x16, b: f32x16, c: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.vfmadd.pd.512"] + fn vfmadd132pd(a: f64x8, b: f64x8, c: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.vfmaddsub.ps.512"] + fn vfmaddsub213ps(a: f32x16, b: f32x16, c: f32x16, d: i32) -> f32x16; //from clang + #[link_name = "llvm.x86.avx512.vfmaddsub.pd.512"] + fn vfmaddsub213pd(a: f64x8, b: f64x8, c: f64x8, d: i32) -> f64x8; //from clang + + #[link_name = "llvm.x86.avx512.add.ps.512"] + fn vaddps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.add.pd.512"] + fn vaddpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.sub.ps.512"] + fn vsubps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.sub.pd.512"] + fn vsubpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.mul.ps.512"] + fn vmulps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mul.pd.512"] + fn vmulpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.div.ps.512"] + fn vdivps(a: f32x16, b: f32x16, rounding: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.div.pd.512"] + fn vdivpd(a: f64x8, b: f64x8, rounding: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.max.ps.512"] + fn vmaxps(a: f32x16, b: f32x16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.max.pd.512"] + fn vmaxpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; + #[link_name = "llvm.x86.avx512.min.ps.512"] + fn vminps(a: f32x16, b: f32x16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.min.pd.512"] + fn vminpd(a: f64x8, b: f64x8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.getexp.ps.512"] + fn vgetexpps(a: f32x16, src: f32x16, m: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.getexp.pd.512"] + fn vgetexppd(a: f64x8, src: f64x8, m: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.getmant.ps.512"] + fn vgetmantps(a: f32x16, mantissas: i32, src: f32x16, m: u16, sae: i32) -> f32x16; + #[link_name = "llvm.x86.avx512.mask.getmant.pd.512"] + fn vgetmantpd(a: f64x8, mantissas: i32, src: f64x8, m: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.rcp14.ps.512"] + fn vrcp14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.rcp14.pd.512"] + fn vrcp14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; + #[link_name = "llvm.x86.avx512.rsqrt14.ps.512"] + fn vrsqrt14ps(a: f32x16, src: f32x16, m: u16) -> f32x16; + #[link_name = "llvm.x86.avx512.rsqrt14.pd.512"] + fn vrsqrt14pd(a: f64x8, src: f64x8, m: u8) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.cvtps2dq.512"] + fn vcvtps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.cvtps2udq.512"] + fn vcvtps2udq(a: f32x16, src: u32x16, mask: u16, rounding: i32) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.cvtps2pd.512"] + fn vcvtps2pd(a: f32x8, src: f64x8, mask: u8, sae: i32) -> f64x8; + + #[link_name = "llvm.x86.avx512.mask.cvttps2dq.512"] + fn vcvttps2dq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.cvttps2udq.512"] + fn vcvttps2udq(a: f32x16, src: i32x16, mask: u16, rounding: i32) -> u32x16; + #[link_name = "llvm.x86.avx512.mask.cvttpd2dq.512"] + fn vcvttpd2dq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> i32x8; + #[link_name = "llvm.x86.avx512.mask.cvttpd2udq.512"] + fn vcvttpd2udq(a: f64x8, src: i32x8, mask: u8, rounding: i32) -> u32x8; + #[link_name = "llvm.x86.avx512.gather.dpd.512"] fn vgatherdpd(src: f64x8, slice: *const i8, offsets: i32x8, mask: i8, scale: i32) -> f64x8; #[link_name = "llvm.x86.avx512.gather.dps.512"] @@ -2474,6 +12580,89 @@ extern "C" { fn vpcmpud(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; #[link_name = "llvm.x86.avx512.mask.cmp.d.512"] fn vpcmpd(a: i32x16, b: i32x16, op: i32, m: i16) -> i16; + + #[link_name = "llvm.x86.avx512.mask.prol.d.512"] + fn vprold(a: i32x16, i8: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.pror.d.512"] + fn vprord(a: i32x16, i8: i32) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prol.q.512"] + fn vprolq(a: i64x8, i8: i32) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.pror.q.512"] + fn vprorq(a: i64x8, i8: i32) -> i64x8; + + #[link_name = "llvm.x86.avx512.mask.prolv.d.512"] + fn vprolvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prorv.d.512"] + fn vprorvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.mask.prolv.q.512"] + fn vprolvq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.mask.prorv.q.512"] + fn vprorvq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.psllv.d.512"] + fn vpsllvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psrlv.d.512"] + fn vpsrlvd(a: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psllv.q.512"] + fn vpsllvq(a: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.psrlv.q.512"] + fn vpsrlvq(a: i64x8, b: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.pslli.d.512"] + fn vpsllid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.psrli.d.512"] + fn vpsrlid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.pslli.q.512"] + fn vpslliq(a: i64x8, imm8: u32) -> i64x8; + #[link_name = "llvm.x86.avx512.psrli.q.512"] + fn vpsrliq(a: i64x8, imm8: u32) -> i64x8; + + #[link_name = "llvm.x86.avx512.psll.d.512"] + fn vpslld(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psrl.d.512"] + fn vpsrld(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psll.q.512"] + fn vpsllq(a: i64x8, count: i64x2) -> i64x8; + #[link_name = "llvm.x86.avx512.psrl.q.512"] + fn vpsrlq(a: i64x8, count: i64x2) -> i64x8; + + #[link_name = "llvm.x86.avx512.psra.d.512"] + fn vpsrad(a: i32x16, count: i32x4) -> i32x16; + #[link_name = "llvm.x86.avx512.psra.q.512"] + fn vpsraq(a: i64x8, count: i64x2) -> i64x8; + + #[link_name = "llvm.x86.avx512.psrai.d.512"] + fn vpsraid(a: i32x16, imm8: u32) -> i32x16; + #[link_name = "llvm.x86.avx512.psrai.q.512"] + fn vpsraiq(a: i64x8, imm8: u32) -> i64x8; + + #[link_name = "llvm.x86.avx512.psrav.d.512"] + fn vpsravd(a: i32x16, count: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.psrav.q.512"] + fn vpsravq(a: i64x8, count: i64x8) -> i64x8; + + #[link_name = "llvm.x86.avx512.vpermilvar.ps.512"] + fn vpermilps(a: f32x16, b: i32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.vpermilvar.pd.512"] + fn vpermilpd(a: f64x8, b: i64x8) -> f64x8; + + #[link_name = "llvm.x86.avx512.permvar.si.512"] + fn vpermd(a: i32x16, idx: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.permvar.di.512"] + fn vpermq(a: i64x8, idx: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.permvar.sf.512"] + fn vpermps(a: f32x16, idx: i32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.permvar.df.512"] + fn vpermpd(a: f64x8, idx: i64x8) -> f64x8; + + #[link_name = "llvm.x86.avx512.vpermi2var.d.512"] + fn vpermi2d(a: i32x16, idx: i32x16, b: i32x16) -> i32x16; + #[link_name = "llvm.x86.avx512.vpermi2var.q.512"] + fn vpermi2q(a: i64x8, idx: i64x8, b: i64x8) -> i64x8; + #[link_name = "llvm.x86.avx512.vpermi2var.ps.512"] + fn vpermi2ps(a: f32x16, idx: i32x16, b: f32x16) -> f32x16; + #[link_name = "llvm.x86.avx512.vpermi2var.pd.512"] + fn vpermi2pd(a: f64x8, idx: i64x8, b: f64x8) -> f64x8; } #[cfg(test)] @@ -2526,7 +12715,7 @@ mod tests { ); let r = _mm512_mask_abs_epi32(a, 0, a); assert_eq_m512i(r, a); - let r = _mm512_mask_abs_epi32(a, 0b11111111, a); + let r = _mm512_mask_abs_epi32(a, 0b00000000_11111111, a); let e = _mm512_setr_epi32( 0, 1, @@ -2559,7 +12748,7 @@ mod tests { ); let r = _mm512_maskz_abs_epi32(0, a); assert_eq_m512i(r, _mm512_setzero_si512()); - let r = _mm512_maskz_abs_epi32(0b11111111, a); + let r = _mm512_maskz_abs_epi32(0b00000000_11111111, a); let e = _mm512_setr_epi32( 0, 1, @@ -2581,6 +12770,3473 @@ mod tests { assert_eq_m512i(r, e); } + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_abs_ps() { + #[rustfmt::skip] + let a = _mm512_setr_ps( + 0., 1., -1., f32::MAX, + f32::MIN, 100., -100., -32., + 0., 1., -1., f32::MAX, + f32::MIN, 100., -100., -32., + ); + let r = _mm512_abs_ps(a); + let e = _mm512_setr_ps( + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_abs_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let r = _mm512_mask_abs_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_abs_ps(a, 0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., + 1., + 1., + f32::MAX, + f32::MAX, + 100., + 100., + 32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_add_epi32(a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_add_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_add_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_epi32() { + #[rustfmt::skip] + let a = _mm512_setr_epi32( + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + 0, 1, -1, i32::MAX, + i32::MIN, 100, -100, -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_add_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_add_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 1, + 2, + 0, + i32::MIN, + i32::MIN + 1, + 101, + -99, + -31, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_add_ps(a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_add_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_add_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_add_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_add_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 1., + 2., + 0., + f32::MAX, + f32::MIN + 1., + 101., + -99., + -31., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_sub_epi32(a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_sub_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_sub_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_sub_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sub_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + -1, + 0, + -2, + i32::MAX - 1, + i32::MAX, + 99, + -101, + -33, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_sub_ps(a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_sub_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_sub_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_sub_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sub_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + -1., + 0., + -2., + f32::MAX - 1., + f32::MIN, + 99., + -101., + -33., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_mullo_epi32(a, b); + let e = _mm512_setr_epi32( + 0, 2, -2, -2, 0, 200, -200, -64, 0, 2, -2, -2, 0, 200, -200, -64, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_mask_mullo_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mullo_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32( + 0, + 2, + -2, + -2, + 0, + 200, + -200, + -64, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mullo_epi32() { + let a = _mm512_setr_epi32( + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + 0, + 1, + -1, + i32::MAX, + i32::MIN, + 100, + -100, + -32, + ); + let b = _mm512_set1_epi32(2); + let r = _mm512_maskz_mullo_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mullo_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 2, -2, -2, 0, 200, -200, -64, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_mul_ps(a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_mask_mul_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_mul_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_ps() { + let a = _mm512_setr_ps( + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + 0., + 1., + -1., + f32::MAX, + f32::MIN, + 100., + -100., + -32., + ); + let b = _mm512_set1_ps(2.); + let r = _mm512_maskz_mul_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_mul_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 2., + -2., + f32::INFINITY, + f32::NEG_INFINITY, + 200., + -200., + -64., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_div_ps(a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 0.5, + -0.5, + 500., + f32::NEG_INFINITY, + 50., + -50., + -16., + ); + assert_eq_m512(r, e); // 0/0 = NAN + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_mask_div_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_div_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 1., + -1., + 1000., + -131., + 100., + -100., + -32., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_ps() { + let a = _mm512_setr_ps( + 0., 1., -1., -2., 100., 100., -100., -32., 0., 1., -1., 1000., -131., 100., -100., -32., + ); + let b = _mm512_setr_ps( + 2., 2., 2., 2., 2., 0., 2., 2., 2., 2., 2., 2., 0., 2., 2., 2., + ); + let r = _mm512_maskz_div_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_div_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., + 0.5, + -0.5, + -1., + 50., + f32::INFINITY, + -50., + -16., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epi32(a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_max_ps(a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_max_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_max_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_max_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_max_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epu32(a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epu32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epu32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epi32(a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epi32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epi32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epi32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_min_ps(a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_min_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_min_ps(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_min_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_min_ps(0b00000000_11111111, a, b); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epu32(a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 7, 6, 5, 4, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epu32(a, 0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epu32() { + let a = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let b = _mm512_setr_epi32(15, 14, 13, 12, 11, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epu32(0b00000000_11111111, a, b); + let e = _mm512_setr_epi32(0, 1, 2, 3, 4, 5, 6, 7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_sqrt_ps(a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_mask_sqrt_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_sqrt_ps(a, 0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 64., 81., 100., 121., 144., 169., 196., 225., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_ps() { + let a = _mm512_setr_ps( + 0., 1., 4., 9., 16., 25., 36., 49., 64., 81., 100., 121., 144., 169., 196., 225., + ); + let r = _mm512_maskz_sqrt_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sqrt_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., 0., 1., 2., 3., 4., 5., 6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmaddsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 7., 10., 9., 12., 11., 14., 13., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmaddsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmaddsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmaddsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmaddsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmaddsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., 2., 1., 4., 3., 6., 5., 8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fmsubadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 9., 8., 11., 10., 13., 12., 15., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fmsubadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsubadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fmsubadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsubadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsubadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 0., 3., 2., 5., 4., 7., 6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fnmadd_ps(a, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fnmadd_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmadd_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fnmadd_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmadd_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fnmadd_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmadd_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + 1., 0., -1., -2., -3., -4., -5., -6., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_fnmsub_ps(a, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., -9., -10., -11., -12., -13., -14., -15., -16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_mask_fnmsub_ps(a, 0, b, c); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmsub_ps(a, 0b00000000_11111111, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let r = _mm512_maskz_fnmsub_ps(0, a, b, c); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmsub_ps(0b00000000_11111111, a, b, c); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_ps() { + let a = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., 1., + ); + let b = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let c = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 2., 2., 2., 2., 2., 2., 2., 2., + ); + let r = _mm512_mask3_fnmsub_ps(a, b, c, 0); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmsub_ps(a, b, c, 0b00000000_11111111); + let e = _mm512_setr_ps( + -1., -2., -3., -4., -5., -6., -7., -8., 2., 2., 2., 2., 2., 2., 2., 2., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_rcp14_ps(a); + let e = _mm512_set1_ps(0.33333206); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_rcp14_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_rcp14_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 0.33333206, 0.33333206, 0.33333206, 0.33333206, + 0.33333206, 0.33333206, 0.33333206, 0.33333206, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rcp14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_rcp14_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_rcp14_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.33333206, 0.33333206, 0.33333206, 0.33333206, + 0.33333206, 0.33333206, 0.33333206, 0.33333206, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_rsqrt14_ps(a); + let e = _mm512_set1_ps(0.5773392); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_rsqrt14_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_rsqrt14_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, + 0.5773392, 0.5773392, 0.5773392, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rsqrt14_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_rsqrt14_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_rsqrt14_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.5773392, 0.5773392, 0.5773392, 0.5773392, 0.5773392, + 0.5773392, 0.5773392, 0.5773392, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_getexp_ps(a); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_getexp_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_getexp_ps(a, 0b11111111_00000000, a); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_getexp_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getexp_ps(0b11111111_00000000, a); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_getmant_ps(a, _MM_MANT_NORM_P75_1P5, _MM_MANT_SIGN_NAN); + let e = _mm512_set1_ps(1.25); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_mask_getmant_ps(a, 0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512(r, a); + let r = _mm512_mask_getmant_ps( + a, + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + ); + let e = _mm512_setr_ps( + 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_maskz_getmant_ps(0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = + _mm512_maskz_getmant_ps(0b11111111_00000000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., + 0.5, + 1., + 2.5, + 3., + 4.5, + 5., + 6.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_add_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_mask_add_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_add_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(-1.); + let r = _mm512_maskz_add_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_add_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., + 0.5, + 1., + 2.5, + 3., + 4.5, + 5., + 6.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_sub_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -1., 0.5, 1., 2.5, 3., 4.5, 5., 6.5, 7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_mask_sub_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_sub_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_round_ps() { + let a = _mm512_setr_ps( + 0., 1.5, 2., 3.5, 4., 5.5, 6., 7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 0.00000007, + ); + let b = _mm512_set1_ps(1.); + let r = _mm512_maskz_sub_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sub_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 7., + 8.5, + 9., + 10.5, + 11., + 12.5, + 13., + -0.99999994, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., + 0.15, + 0.2, + 0.35, + 0.4, + 0.55, + 0.6, + 0.75, + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + let r = _mm512_mul_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 0., + 0.14999999, + 0.2, + 0.35, + 0.4, + 0.54999995, + 0.59999996, + 0.75, + 0.8, + 0.95, + 1.0, + 1.15, + 1.1999999, + 1.3499999, + 1.4, + 0.000000000000000000000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_mask_mul_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_mul_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_round_ps() { + let a = _mm512_setr_ps( + 0., + 1.5, + 2., + 3.5, + 4., + 5.5, + 6., + 7.5, + 8., + 9.5, + 10., + 11.5, + 12., + 13.5, + 14., + 0.00000000000000000000007, + ); + let b = _mm512_set1_ps(0.1); + let r = _mm512_maskz_mul_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_mul_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0.8, + 0.95, + 1.0, + 1.15, + 1.2, + 1.35, + 1.4, + 0.000000000000000000000007000001, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.33333334); + assert_eq_m512(r, e); + let r = _mm512_div_round_ps(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.3333333); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_mask_div_round_ps(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_div_round_ps( + a, + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1., 1., 1., 1., 1., 1., 1., 1., 0.33333334, 0.33333334, 0.33333334, 0.33333334, + 0.33333334, 0.33333334, 0.33333334, 0.33333334, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_round_ps() { + let a = _mm512_set1_ps(1.); + let b = _mm512_set1_ps(3.); + let r = _mm512_maskz_div_round_ps(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_div_round_ps( + 0b11111111_00000000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 0.33333334, 0.33333334, 0.33333334, 0.33333334, + 0.33333334, 0.33333334, 0.33333334, 0.33333334, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.7320508); + assert_eq_m512(r, e); + let r = _mm512_sqrt_round_ps(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.7320509); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_sqrt_round_ps(a, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_sqrt_round_ps( + a, + 0b11111111_00000000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, + 1.7320508, 1.7320508, 1.7320508, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_sqrt_round_ps(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_sqrt_round_ps( + 0b11111111_00000000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.7320508, 1.7320508, 1.7320508, 1.7320508, 1.7320508, + 1.7320508, 1.7320508, 1.7320508, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask_fmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fmadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_maskz_fmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask3_fmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(-0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask_fmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_maskz_fmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask3_fmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + -0.99999994, + 1., + 1., + 1., + 1., + 1., + 1., + 1., + 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + ); + assert_eq_m512(r, e); + let r = _mm512_fmaddsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + -0.9999999, 1., -0.9999999, 1., -0.9999999, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask_fmaddsub_round_ps( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_fmaddsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_maskz_fmaddsub_round_ps( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmaddsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask3_fmaddsub_round_ps( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmaddsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + ); + assert_eq_m512(r, e); + let r = _mm512_fmsubadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_ps( + -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + -0.9999999, 1., -0.9999999, 1., -0.9999999, 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask_fmsubadd_round_ps( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_fmsubadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_maskz_fmsubadd_round_ps( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fmsubadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + 0., + 0., + 0., + 0., + 0., + 0., + 0., + 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_mask3_fmsubadd_round_ps( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512(r, c); + let r = _mm512_mask3_fmsubadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -0.99999994, + 1.0000001, + -1., + -1., + -1., + -1., + -1., + -1., + -1., + -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fnmadd_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask_fnmadd_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmadd_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, + 0.00000007, 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_maskz_fnmadd_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmadd_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(1.); + let r = + _mm512_mask3_fnmadd_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmadd_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.99999994); + assert_eq_m512(r, e); + let r = _mm512_fnmsub_round_ps(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(0.9999999); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask_fnmsub_round_ps(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, a); + let r = _mm512_mask_fnmsub_round_ps( + a, + 0b00000000_11111111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, 0.00000007, + 0.00000007, 0.00000007, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_maskz_fnmsub_round_ps(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_fnmsub_round_ps( + 0b00000000_11111111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_round_ps() { + let a = _mm512_set1_ps(0.00000007); + let b = _mm512_set1_ps(1.); + let c = _mm512_set1_ps(-1.); + let r = + _mm512_mask3_fnmsub_round_ps(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512(r, c); + let r = _mm512_mask3_fnmsub_round_ps( + a, + b, + c, + 0b00000000_11111111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_ps( + 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, 0.99999994, + 0.99999994, -1., -1., -1., -1., -1., -1., -1., -1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_max_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_max_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_max_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_max_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_max_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_min_round_ps(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 7., 6., 5., 4., 3., 2., 1., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_mask_min_round_ps(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_min_round_ps(a, 0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_round_ps() { + let a = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_setr_ps( + 15., 14., 13., 12., 11., 10., 9., 8., 7., 6., 5., 4., 3., 2., 1., 0., + ); + let r = _mm512_maskz_min_round_ps(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_min_round_ps(0b00000000_11111111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_getexp_round_ps(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + let r = _mm512_getexp_round_ps(a, _MM_FROUND_NO_EXC); + let e = _mm512_set1_ps(1.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_mask_getexp_round_ps(a, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, a); + let r = _mm512_mask_getexp_round_ps(a, 0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 3., 3., 3., 3., 3., 3., 3., 3., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_round_ps() { + let a = _mm512_set1_ps(3.); + let r = _mm512_maskz_getexp_round_ps(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getexp_round_ps(0b11111111_00000000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1., 1., 1., 1., 1., 1., 1., 1., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_getmant_round_ps( + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_set1_ps(1.25); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_mask_getmant_round_ps( + a, + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512(r, a); + let r = _mm512_mask_getmant_round_ps( + a, + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_ps( + 10., 10., 10., 10., 10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_round_ps() { + let a = _mm512_set1_ps(10.); + let r = _mm512_maskz_getmant_round_ps( + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_getmant_round_ps( + 0b11111111_00000000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, 1.25, + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtps_epi32(a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtps_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtps_epi32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_epi32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtps_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtps_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtps_epu32(a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtps_epu32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtps_epu32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_epu32() { + let a = _mm512_setr_ps( + 0., -1.4, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtps_epu32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtps_epu32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + let r = _mm512_cvt_roundps_epi32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = + _mm512_mask_cvt_roundps_epi32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvt_roundps_epi32( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvt_roundps_epi32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvt_roundps_epi32( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -2, 2, -4, 4, -6, 6, -8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 10, 10, 12, 12, 14, 14, 16); + assert_eq_m512i(r, e); + let r = _mm512_cvt_roundps_epu32(a, _MM_FROUND_TO_NEG_INF | _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = + _mm512_mask_cvt_roundps_epu32(src, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvt_roundps_epu32( + src, + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvt_roundps_epu32(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvt_roundps_epu32( + 0b00000000_11111111, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtt_roundps_epi32(a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtt_roundps_epi32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtt_roundps_epi32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtt_roundps_epi32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtt_roundps_epi32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvtt_roundps_epu32(a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvtt_roundps_epu32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvtt_roundps_epu32(src, 0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvtt_roundps_epu32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvtt_roundps_epu32(0b00000000_11111111, a, _MM_FROUND_NO_EXC); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvttps_epi32(a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvttps_epi32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvttps_epi32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttps_epi32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvttps_epi32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvttps_epi32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_cvttps_epu32(a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 8, 9, 10, 11, 12, 13, 14, 15); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let src = _mm512_set1_epi32(0); + let r = _mm512_mask_cvttps_epu32(src, 0, a); + assert_eq_m512i(r, src); + let r = _mm512_mask_cvttps_epu32(src, 0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttps_epu32() { + let a = _mm512_setr_ps( + 0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5, 8., 9.5, 10., 11.5, 12., 13.5, 14., 15.5, + ); + let r = _mm512_maskz_cvttps_epu32(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_cvttps_epu32(0b00000000_11111111, a); + let e = _mm512_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_i32gather_ps() { let mut arr = [0f32; 256]; @@ -3452,4 +17108,2047 @@ mod tests { let r = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); assert_eq_m512d(r, _mm512_set_pd(7., 6., 5., 4., 3., 2., 1., 0.)); } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rol_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_rol_epi32(a, 1); + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rol_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_mask_rol_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rol_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rol_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let r = _mm512_maskz_rol_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rol_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_ror_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_ror_epi32(a, 1); + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_ror_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_mask_ror_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_ror_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_ror_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + let r = _mm512_maskz_ror_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_ror_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_slli_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_slli_epi32(a, 1); + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_slli_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let r = _mm512_mask_slli_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_slli_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_slli_epi32() { + let a = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let r = _mm512_maskz_slli_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_slli_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srli_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_srli_epi32(a, 1); + let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srli_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let r = _mm512_mask_srli_epi32(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srli_epi32(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_epi32(0 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srli_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); + let r = _mm512_maskz_srli_epi32(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srli_epi32(0b00000000_11111111, a, 1); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0 << 31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_rolv_epi32(a, b); + + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_rolv_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rolv_epi32(a, 0b11111111_11111111, a, b); + + let e = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rolv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_rolv_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rolv_epi32(0b00000000_11111111, a, b); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rorv_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_rorv_epi32(a, b); + + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rorv_epi32() { + let a = _mm512_set_epi32(1 << 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let b = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_rorv_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rorv_epi32(a, 0b11111111_11111111, a, b); + + let e = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rorv_epi32() { + let a = _mm512_set_epi32(3, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 1 << 0); + let b = _mm512_set_epi32(2, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_rorv_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rorv_epi32(0b00000000_11111111, a, b); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_sllv_epi32(a, count); + + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_sllv_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sllv_epi32(a, 0b11111111_11111111, a, count); + + let e = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sllv_epi32() { + let a = _mm512_set_epi32(1 << 31, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 << 31); + let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_sllv_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sllv_epi32(0b00000000_11111111, a, count); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2, 2, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srlv_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_srlv_epi32(a, count); + + let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srlv_epi32() { + let a = _mm512_set_epi32(0, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2); + let count = _mm512_set_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_mask_srlv_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srlv_epi32(a, 0b11111111_11111111, a, count); + + let e = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srlv_epi32() { + let a = _mm512_set_epi32(2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0); + let count = _mm512_set_epi32(0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + + let r = _mm512_maskz_srlv_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srlv_epi32(0b00000000_11111111, a, count); + + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_sll_epi32(a, count); + let e = _mm512_set_epi32( + 0, + 1 << 2, + 1 << 3, + 1 << 4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_sll_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sll_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32( + 0, + 1 << 2, + 1 << 3, + 1 << 4, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sll_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 31, + ); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_sll_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sll_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_srl_epi32(a, count); + let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + ); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_srl_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srl_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(1 << 29, 0, 0, 1 << 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srl_epi32() { + let a = _mm512_set_epi32( + 1 << 31, + 1 << 0, + 1 << 1, + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 31, + ); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_srl_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srl_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 29); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let count = _mm_set_epi32(1, 0, 0, 2); + let r = _mm512_sra_epi32(a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); + let count = _mm_set_epi32(0, 0, 0, 2); + let r = _mm512_mask_sra_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sra_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sra_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); + let count = _mm_set_epi32(2, 0, 0, 2); + let r = _mm512_maskz_sra_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sra_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0); + let r = _mm512_srav_epi32(a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1); + let r = _mm512_mask_srav_epi32(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srav_epi32(a, 0b11111111_11111111, a, count); + let e = _mm512_set_epi32(2, -2, 4, -4, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srav_epi32() { + let a = _mm512_set_epi32(8, -8, 16, -15, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -15, -14); + let count = _mm512_set_epi32(2, 2, 2, 2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2); + let r = _mm512_maskz_srav_epi32(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srav_epi32(0b00000000_11111111, a, count); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, -4, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16, -15); + let r = _mm512_srai_epi32(a, 2); + let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); + let r = _mm512_mask_srai_epi32(a, 0, a, 2); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srai_epi32(a, 0b11111111_11111111, a, 2); + let e = _mm512_set_epi32(2, -2, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srai_epi32() { + let a = _mm512_set_epi32(8, -8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, -15); + let r = _mm512_maskz_srai_epi32(0, a, 2); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srai_epi32(0b00000000_11111111, a, 2); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_permute_ps(a, 1); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_mask_permute_ps(a, 0b00000000_00000000, a, 1); + assert_eq_m512(r, a); + let r = _mm512_mask_permute_ps(a, 0b11111111_11111111, a, 1); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permute_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_maskz_permute_ps(0, a, 1); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permute_ps(0b00000000_11111111, a, 1); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutevar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_permutevar_epi32(idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutevar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_permutevar_epi32(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutevar_epi32(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_permutevar_ps(a, b); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_mask_permutevar_ps(a, 0, a, b); + assert_eq_m512(r, a); + let r = _mm512_mask_permutevar_ps(a, 0b11111111_11111111, a, b); + let e = _mm512_set_ps( + 2., 2., 2., 2., 6., 6., 6., 6., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutevar_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let b = _mm512_set1_epi32(1); + let r = _mm512_maskz_permutevar_ps(0, a, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutevar_ps(0b00000000_11111111, a, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 10., 10., 10., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_permutexvar_epi32(idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_mask_permutexvar_epi32(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutexvar_epi32(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_epi32(14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_epi32() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let r = _mm512_maskz_permutexvar_epi32(0, idx, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutexvar_epi32(0b00000000_11111111, idx, a); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 14, 14, 14, 14, 14, 14, 14, 14); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_permutexvar_ps(idx, a); + let e = _mm512_set1_ps(14.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_mask_permutexvar_ps(a, 0, idx, a); + assert_eq_m512(r, a); + let r = _mm512_mask_permutexvar_ps(a, 0b11111111_11111111, idx, a); + let e = _mm512_set1_ps(14.); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_ps() { + let idx = _mm512_set1_epi32(1); + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let r = _mm512_maskz_permutexvar_ps(0, idx, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutexvar_ps(0b00000000_11111111, idx, a); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 14., 14., 14., 14., 14., 14., 14., 14., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_permutex2var_epi32(a, idx, b); + let e = _mm512_set_epi32( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_mask_permutex2var_epi32(a, 0, idx, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex2var_epi32(a, 0b11111111_11111111, idx, b); + let e = _mm512_set_epi32( + 14, 100, 13, 100, 12, 100, 11, 100, 10, 100, 9, 100, 8, 100, 7, 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_maskz_permutex2var_epi32(0, a, idx, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex2var_epi32(0b00000000_11111111, a, idx, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 10, 100, 9, 100, 8, 100, 7, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_epi32() { + let a = _mm512_set_epi32(0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); + let idx = _mm512_set_epi32( + 1000, + 1 << 4, + 2000, + 1 << 4, + 3000, + 1 << 4, + 4000, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_epi32(100); + let r = _mm512_mask2_permutex2var_epi32(a, idx, 0, b); + assert_eq_m512i(r, idx); + let r = _mm512_mask2_permutex2var_epi32(a, idx, 0b00000000_11111111, b); + let e = _mm512_set_epi32( + 1000, + 1 << 4, + 2000, + 1 << 4, + 3000, + 1 << 4, + 4000, + 1 << 4, + 10, + 100, + 9, + 100, + 8, + 100, + 7, + 100, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_permutex2var_ps(a, idx, b); + let e = _mm512_set_ps( + 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_mask_permutex2var_ps(a, 0, idx, b); + assert_eq_m512(r, a); + let r = _mm512_mask_permutex2var_ps(a, 0b11111111_11111111, idx, b); + let e = _mm512_set_ps( + 14., 100., 13., 100., 12., 100., 11., 100., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_maskz_permutex2var_ps(0, a, idx, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_permutex2var_ps(0b00000000_11111111, a, idx, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_ps() { + let a = _mm512_set_ps( + 0., 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., + ); + let idx = _mm512_set_epi32( + 1, + 1 << 4, + 2, + 1 << 4, + 3, + 1 << 4, + 4, + 1 << 4, + 5, + 1 << 4, + 6, + 1 << 4, + 7, + 1 << 4, + 8, + 1 << 4, + ); + let b = _mm512_set1_ps(100.); + let r = _mm512_mask2_permutex2var_ps(a, idx, 0, b); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_mask2_permutex2var_ps(a, idx, 0b00000000_11111111, b); + let e = _mm512_set_ps( + 0., 0., 0., 0., 0., 0., 0., 0., 10., 100., 9., 100., 8., 100., 7., 100., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_shuffle_epi32(a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_mask_shuffle_epi32(a, 0, a, _MM_PERM_AADD); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_epi32(a, 0b11111111_11111111, a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 8, 8, 1, 1, 16, 16, 9, 9); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_epi32() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let r = _mm512_maskz_shuffle_epi32(0, a, _MM_PERM_AADD); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_epi32(0b00000000_11111111, a, _MM_PERM_AADD); + let e = _mm512_setr_epi32(8, 8, 1, 1, 16, 16, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_shuffle_ps(a, b, 0x0F); + let e = _mm512_setr_ps( + 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_mask_shuffle_ps(a, 0, a, b, 0x0F); + assert_eq_m512(r, a); + let r = _mm512_mask_shuffle_ps(a, 0b11111111_11111111, a, b, 0x0F); + let e = _mm512_setr_ps( + 8., 8., 2., 2., 16., 16., 10., 10., 8., 8., 2., 2., 16., 16., 10., 10., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_ps() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_maskz_shuffle_ps(0, a, b, 0x0F); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_shuffle_ps(0b00000000_11111111, a, b, 0x0F); + let e = _mm512_setr_ps( + 8., 8., 2., 2., 16., 16., 10., 10., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_shuffle_i32x4(a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_mask_shuffle_i32x4(a, 0, a, b, 0b00000000); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_i32x4(a, 0b11111111_11111111, a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 2, 3, 6, 7, 2, 3, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_i32x4() { + let a = _mm512_setr_epi32(1, 4, 5, 8, 9, 12, 13, 16, 1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi32(2, 3, 6, 7, 10, 11, 14, 15, 2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_maskz_shuffle_i32x4(0, a, b, 0b00000000); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_i32x4(0b00000000_11111111, a, b, 0b00000000); + let e = _mm512_setr_epi32(1, 4, 5, 8, 1, 4, 5, 8, 0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_f32x4() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_shuffle_f32x4(a, b, 0b00000000); + let e = _mm512_setr_ps( + 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_f32x4() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_mask_shuffle_f32x4(a, 0, a, b, 0b00000000); + assert_eq_m512(r, a); + let r = _mm512_mask_shuffle_f32x4(a, 0b11111111_11111111, a, b, 0b00000000); + let e = _mm512_setr_ps( + 1., 4., 5., 8., 1., 4., 5., 8., 2., 3., 6., 7., 2., 3., 6., 7., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_f32x4() { + let a = _mm512_setr_ps( + 1., 4., 5., 8., 9., 12., 13., 16., 1., 4., 5., 8., 9., 12., 13., 16., + ); + let b = _mm512_setr_ps( + 2., 3., 6., 7., 10., 11., 14., 15., 2., 3., 6., 7., 10., 11., 14., 15., + ); + let r = _mm512_maskz_shuffle_f32x4(0, a, b, 0b00000000); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_shuffle_f32x4(0b00000000_11111111, a, b, 0b00000000); + let e = _mm512_setr_ps( + 1., 4., 5., 8., 1., 4., 5., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_extractf32x4_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_extractf32x4_ps(a, 0x1); + let e = _mm_setr_ps(5., 6., 7., 8.); + assert_eq_m128(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_moveldup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_moveldup_ps(a); + let e = _mm512_setr_ps( + 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_moveldup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_mask_moveldup_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_moveldup_ps(a, 0b11111111_11111111, a); + let e = _mm512_setr_ps( + 1., 1., 3., 3., 5., 5., 7., 7., 9., 9., 11., 11., 13., 13., 15., 15., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_moveldup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_maskz_moveldup_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_moveldup_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 1., 1., 3., 3., 5., 5., 7., 7., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_movehdup_ps(a); + let e = _mm512_setr_ps( + 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_mask_movehdup_ps(a, 0, a); + assert_eq_m512(r, a); + let r = _mm512_mask_movehdup_ps(a, 0b11111111_11111111, a); + let e = _mm512_setr_ps( + 2., 2., 4., 4., 6., 6., 8., 8., 10., 10., 12., 12., 14., 14., 16., 16., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_movehdup_ps() { + let a = _mm512_setr_ps( + 1., 2., 3., 4., 5., 6., 7., 8., 9., 10., 11., 12., 13., 14., 15., 16., + ); + let r = _mm512_maskz_movehdup_ps(0, a); + assert_eq_m512(r, _mm512_setzero_ps()); + let r = _mm512_maskz_movehdup_ps(0b00000000_11111111, a); + let e = _mm512_setr_ps( + 2., 2., 4., 4., 6., 6., 8., 8., 0., 0., 0., 0., 0., 0., 0., 0., + ); + assert_eq_m512(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_and_epi32(a, b); + let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_and_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_and_epi32(a, 0b01111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_and_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_and_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_and_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_and_epi32(a, b); + let e = _mm512_set_epi32(1 << 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_or_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_or_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_or_epi32(a, 0b11111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_or_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_or_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_or_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32( + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_or_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_xor_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_mask_xor_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_xor_epi32(a, 0b01111111_11111111, a, b); + let e = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_xor_epi32() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_maskz_xor_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_xor_epi32(0b00000000_11111111, a, b); + let e = _mm512_set_epi32(0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_xor_si512() { + let a = _mm512_set_epi32( + 1 << 1 | 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 3, + ); + let b = _mm512_set_epi32( + 1 << 1, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 3 | 1 << 4, + ); + let r = _mm512_xor_epi32(a, b); + let e = _mm512_set_epi32( + 1 << 2, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 4, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_kand() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b11001100_00110011; + let r = _mm512_kand(a, b); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_kand_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b11001100_00110011; + let r = _kand_mask16(a, b); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_kor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kor(a, b); + let e: u16 = 0b11101110_00111011; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_kor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kor_mask16(a, b); + let e: u16 = 0b11101110_00111011; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_kxor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kxor(a, b); + let e: u16 = 0b11100010_00111000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_kxor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kxor_mask16(a, b); + let e: u16 = 0b11100010_00111000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_knot() { + let a: u16 = 0b11001100_00110011; + let r = _mm512_knot(a); + let e: u16 = 0b00110011_11001100; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_knot_mask16() { + let a: u16 = 0b11001100_00110011; + let r = _knot_mask16(a); + let e: u16 = 0b00110011_11001100; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_kandn() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kandn(a, b); + let e: u16 = 0b00100010_00001000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_kandn_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kandn_mask16(a, b); + let e: u16 = 0b00100010_00001000; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_kxnor() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _mm512_kxnor(a, b); + let e: u16 = 0b00011101_11000111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_kxnor_mask16() { + let a: u16 = 0b11001100_00110011; + let b: u16 = 0b00101110_00001011; + let r = _kxnor_mask16(a, b); + let e: u16 = 0b00011101_11000111; + assert_eq!(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_kmov() { + let a: u16 = 0b11001100_00110011; + let r = _mm512_kmov(a); + let e: u16 = 0b11001100_00110011; + assert_eq!(r, e); + } } diff --git a/library/stdarch/crates/core_arch/src/x86/macros.rs b/library/stdarch/crates/core_arch/src/x86/macros.rs index b1b7697623..891286df4e 100644 --- a/library/stdarch/crates/core_arch/src/x86/macros.rs +++ b/library/stdarch/crates/core_arch/src/x86/macros.rs @@ -216,6 +216,523 @@ macro_rules! constify_imm8_gather { }; } +// For round instructions, the only valid values for rounding are 4, 8, 9, 10 and 11. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_round { + ($imm8:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm8) & 0b1111 { + 4 => $expand!(4), + 8 => $expand!(8), + 9 => $expand!(9), + 10 => $expand!(10), + 11 => $expand!(11), + _ => panic!("Invalid round value"), + } + }; +} + +// For sae instructions, the only valid values for sae are 4 and 8. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_sae { + ($imm8:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm8) & 0b1111 { + 4 => $expand!(4), + 8 => $expand!(8), + _ => panic!("Invalid sae value"), + } + }; +} + +// Two mantissas parameters. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_mantissas { + ($imm4:expr, $imm2:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm4, $imm2) { + (0, 0) => $expand!(0, 0), + (0, 1) => $expand!(0, 1), + (0, 2) => $expand!(0, 2), + (0, 3) => $expand!(0, 3), + (1, 0) => $expand!(1, 0), + (1, 1) => $expand!(1, 1), + (1, 2) => $expand!(1, 2), + (1, 3) => $expand!(1, 3), + (2, 0) => $expand!(2, 0), + (2, 1) => $expand!(2, 1), + (2, 2) => $expand!(2, 2), + (2, 3) => $expand!(2, 3), + (3, 0) => $expand!(3, 0), + (3, 1) => $expand!(3, 1), + (3, 2) => $expand!(3, 2), + (3, 3) => $expand!(3, 3), + (4, 0) => $expand!(4, 0), + (4, 1) => $expand!(4, 1), + (4, 2) => $expand!(4, 2), + (4, 3) => $expand!(4, 3), + (5, 0) => $expand!(5, 0), + (5, 1) => $expand!(5, 1), + (5, 2) => $expand!(5, 2), + (5, 3) => $expand!(5, 3), + (6, 0) => $expand!(6, 0), + (6, 1) => $expand!(6, 1), + (6, 2) => $expand!(6, 2), + (6, 3) => $expand!(6, 3), + (7, 0) => $expand!(7, 0), + (7, 1) => $expand!(7, 1), + (7, 2) => $expand!(7, 2), + (7, 3) => $expand!(7, 3), + (8, 0) => $expand!(8, 0), + (8, 1) => $expand!(8, 1), + (8, 2) => $expand!(8, 2), + (8, 3) => $expand!(8, 3), + (9, 0) => $expand!(9, 0), + (9, 1) => $expand!(9, 1), + (9, 2) => $expand!(9, 2), + (9, 3) => $expand!(9, 3), + (10, 0) => $expand!(10, 0), + (10, 1) => $expand!(10, 1), + (10, 2) => $expand!(10, 2), + (10, 3) => $expand!(10, 3), + (11, 0) => $expand!(11, 0), + (11, 1) => $expand!(11, 1), + (11, 2) => $expand!(11, 2), + (11, 3) => $expand!(11, 3), + (12, 0) => $expand!(12, 0), + (12, 1) => $expand!(12, 1), + (12, 2) => $expand!(12, 2), + (12, 3) => $expand!(12, 3), + (13, 0) => $expand!(13, 0), + (13, 1) => $expand!(13, 1), + (13, 2) => $expand!(13, 2), + (13, 3) => $expand!(13, 3), + (14, 0) => $expand!(14, 0), + (14, 1) => $expand!(14, 1), + (14, 2) => $expand!(14, 2), + (14, 3) => $expand!(14, 3), + (15, 0) => $expand!(15, 0), + (15, 1) => $expand!(15, 1), + (15, 2) => $expand!(15, 2), + (15, 3) => $expand!(15, 3), + (_, _) => panic!("Invalid sae value"), + } + }; +} + +// Include mantissas parameters. +// For sae instructions, the only valid values for sae are 4 and 8. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm4_mantissas_sae { + ($imm4_1:expr, $imm2:expr, $imm4_2:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm4_1, $imm2, $imm4_2) { + (0, 0, 4) => $expand!(0, 0, 4), + (0, 0, 8) => $expand!(0, 0, 8), + (0, 1, 4) => $expand!(0, 1, 4), + (0, 1, 8) => $expand!(0, 1, 8), + (0, 2, 4) => $expand!(0, 2, 4), + (0, 2, 8) => $expand!(0, 2, 8), + (0, 3, 4) => $expand!(0, 3, 4), + (0, 3, 8) => $expand!(0, 3, 8), + (1, 0, 4) => $expand!(1, 0, 4), + (1, 0, 8) => $expand!(1, 0, 8), + (1, 1, 4) => $expand!(1, 1, 4), + (1, 1, 8) => $expand!(1, 1, 8), + (1, 2, 4) => $expand!(1, 2, 4), + (1, 2, 8) => $expand!(1, 2, 8), + (1, 3, 4) => $expand!(1, 3, 4), + (1, 3, 8) => $expand!(1, 3, 8), + (2, 0, 4) => $expand!(2, 0, 4), + (2, 0, 8) => $expand!(2, 0, 8), + (2, 1, 4) => $expand!(2, 1, 4), + (2, 1, 8) => $expand!(2, 1, 8), + (2, 2, 4) => $expand!(2, 2, 4), + (2, 2, 8) => $expand!(2, 2, 8), + (2, 3, 4) => $expand!(2, 3, 4), + (2, 3, 8) => $expand!(2, 3, 8), + (3, 0, 4) => $expand!(3, 0, 4), + (3, 0, 8) => $expand!(3, 0, 8), + (3, 1, 4) => $expand!(3, 1, 4), + (3, 1, 8) => $expand!(3, 1, 8), + (3, 2, 4) => $expand!(3, 2, 4), + (3, 2, 8) => $expand!(3, 2, 8), + (3, 3, 4) => $expand!(3, 3, 4), + (3, 3, 8) => $expand!(3, 3, 8), + (4, 0, 4) => $expand!(4, 0, 4), + (4, 0, 8) => $expand!(4, 0, 8), + (4, 1, 4) => $expand!(4, 1, 4), + (4, 1, 8) => $expand!(4, 1, 8), + (4, 2, 4) => $expand!(4, 2, 4), + (4, 2, 8) => $expand!(4, 2, 8), + (4, 3, 4) => $expand!(4, 3, 4), + (4, 3, 8) => $expand!(4, 3, 8), + (5, 0, 4) => $expand!(5, 0, 4), + (5, 0, 8) => $expand!(5, 0, 8), + (5, 1, 4) => $expand!(5, 1, 4), + (5, 1, 8) => $expand!(5, 1, 8), + (5, 2, 4) => $expand!(5, 2, 4), + (5, 2, 8) => $expand!(5, 2, 8), + (5, 3, 4) => $expand!(5, 3, 4), + (5, 3, 8) => $expand!(5, 3, 8), + (6, 0, 4) => $expand!(6, 0, 4), + (6, 0, 8) => $expand!(6, 0, 8), + (6, 1, 4) => $expand!(6, 1, 4), + (6, 1, 8) => $expand!(6, 1, 8), + (6, 2, 4) => $expand!(6, 2, 4), + (6, 2, 8) => $expand!(6, 2, 8), + (6, 3, 4) => $expand!(6, 3, 4), + (6, 3, 8) => $expand!(6, 3, 8), + (7, 0, 4) => $expand!(7, 0, 4), + (7, 0, 8) => $expand!(7, 0, 8), + (7, 1, 4) => $expand!(7, 1, 4), + (7, 1, 8) => $expand!(7, 1, 8), + (7, 2, 4) => $expand!(7, 2, 4), + (7, 2, 8) => $expand!(7, 2, 8), + (7, 3, 4) => $expand!(7, 3, 4), + (7, 3, 8) => $expand!(7, 3, 8), + (8, 0, 4) => $expand!(8, 0, 4), + (8, 0, 8) => $expand!(8, 0, 8), + (8, 1, 4) => $expand!(8, 1, 4), + (8, 1, 8) => $expand!(8, 1, 8), + (8, 2, 4) => $expand!(8, 2, 4), + (8, 2, 8) => $expand!(8, 2, 8), + (8, 3, 4) => $expand!(8, 3, 4), + (8, 3, 8) => $expand!(8, 3, 8), + (9, 0, 4) => $expand!(9, 0, 4), + (9, 0, 8) => $expand!(9, 0, 8), + (9, 1, 4) => $expand!(9, 1, 4), + (9, 1, 8) => $expand!(9, 1, 8), + (9, 2, 4) => $expand!(9, 2, 4), + (9, 2, 8) => $expand!(9, 2, 8), + (9, 3, 4) => $expand!(9, 3, 4), + (9, 3, 8) => $expand!(9, 3, 8), + (10, 0, 4) => $expand!(10, 0, 4), + (10, 0, 8) => $expand!(10, 0, 8), + (10, 1, 4) => $expand!(10, 1, 4), + (10, 1, 8) => $expand!(10, 1, 8), + (10, 2, 4) => $expand!(10, 2, 4), + (10, 2, 8) => $expand!(10, 2, 8), + (10, 3, 4) => $expand!(10, 3, 4), + (10, 3, 8) => $expand!(10, 3, 8), + (11, 0, 4) => $expand!(11, 0, 4), + (11, 0, 8) => $expand!(11, 0, 8), + (11, 1, 4) => $expand!(11, 1, 4), + (11, 1, 8) => $expand!(11, 1, 8), + (11, 2, 4) => $expand!(11, 2, 4), + (11, 2, 8) => $expand!(11, 2, 8), + (11, 3, 4) => $expand!(11, 3, 4), + (11, 3, 8) => $expand!(11, 3, 8), + (12, 0, 4) => $expand!(12, 0, 4), + (12, 0, 8) => $expand!(12, 0, 8), + (12, 1, 4) => $expand!(12, 1, 4), + (12, 1, 8) => $expand!(12, 1, 8), + (12, 2, 4) => $expand!(12, 2, 4), + (12, 2, 8) => $expand!(12, 2, 8), + (12, 3, 4) => $expand!(12, 3, 4), + (12, 3, 8) => $expand!(12, 3, 8), + (13, 0, 4) => $expand!(13, 0, 4), + (13, 0, 8) => $expand!(13, 0, 8), + (13, 1, 4) => $expand!(13, 1, 4), + (13, 1, 8) => $expand!(13, 1, 8), + (13, 2, 4) => $expand!(13, 2, 4), + (13, 2, 8) => $expand!(13, 2, 8), + (13, 3, 4) => $expand!(13, 3, 4), + (13, 3, 8) => $expand!(13, 3, 8), + (14, 0, 4) => $expand!(14, 0, 4), + (14, 0, 8) => $expand!(14, 0, 8), + (14, 1, 4) => $expand!(14, 1, 4), + (14, 1, 8) => $expand!(14, 1, 8), + (14, 2, 4) => $expand!(14, 2, 4), + (14, 2, 8) => $expand!(14, 2, 8), + (14, 3, 4) => $expand!(14, 3, 4), + (14, 3, 8) => $expand!(14, 3, 8), + (15, 0, 4) => $expand!(15, 0, 4), + (15, 0, 8) => $expand!(15, 0, 8), + (15, 1, 4) => $expand!(15, 1, 4), + (15, 1, 8) => $expand!(15, 1, 8), + (15, 2, 4) => $expand!(15, 2, 4), + (15, 2, 8) => $expand!(15, 2, 8), + (15, 3, 4) => $expand!(15, 3, 4), + (15, 3, 8) => $expand!(15, 3, 8), + (_, _, _) => panic!("Invalid sae value"), + } + }; +} + +// Constifies 8 bits along with an sae option without rounding control. +// The only valid values are 0 to 255. +// This macro enforces that. +#[allow(unused)] +macro_rules! constify_imm8_sae { + ($imm8:expr, $expand:ident) => { + #[allow(overflowing_literals)] + match ($imm8) & 0b1111_1111 { + 0 => $expand!(0), + 1 => $expand!(1), + 2 => $expand!(2), + 3 => $expand!(3), + 4 => $expand!(4), + 5 => $expand!(5), + 6 => $expand!(6), + 7 => $expand!(7), + 8 => $expand!(8), + 9 => $expand!(9), + 10 => $expand!(10), + 11 => $expand!(11), + 12 => $expand!(12), + 13 => $expand!(13), + 14 => $expand!(14), + 15 => $expand!(15), + 16 => $expand!(16), + 17 => $expand!(17), + 18 => $expand!(18), + 19 => $expand!(19), + 20 => $expand!(20), + 21 => $expand!(21), + 22 => $expand!(22), + 23 => $expand!(23), + 24 => $expand!(24), + 25 => $expand!(25), + 26 => $expand!(26), + 27 => $expand!(27), + 28 => $expand!(28), + 29 => $expand!(29), + 30 => $expand!(30), + 31 => $expand!(31), + 32 => $expand!(32), + 33 => $expand!(33), + 34 => $expand!(34), + 35 => $expand!(35), + 36 => $expand!(36), + 37 => $expand!(37), + 38 => $expand!(38), + 39 => $expand!(39), + 40 => $expand!(40), + 41 => $expand!(41), + 42 => $expand!(42), + 43 => $expand!(43), + 44 => $expand!(44), + 45 => $expand!(45), + 46 => $expand!(46), + 47 => $expand!(47), + 48 => $expand!(48), + 49 => $expand!(49), + 50 => $expand!(50), + 51 => $expand!(51), + 52 => $expand!(52), + 53 => $expand!(53), + 54 => $expand!(54), + 55 => $expand!(55), + 56 => $expand!(56), + 57 => $expand!(57), + 58 => $expand!(58), + 59 => $expand!(59), + 60 => $expand!(60), + 61 => $expand!(61), + 62 => $expand!(62), + 63 => $expand!(63), + 64 => $expand!(64), + 65 => $expand!(65), + 66 => $expand!(66), + 67 => $expand!(67), + 68 => $expand!(68), + 69 => $expand!(69), + 70 => $expand!(70), + 71 => $expand!(71), + 72 => $expand!(72), + 73 => $expand!(73), + 74 => $expand!(74), + 75 => $expand!(75), + 76 => $expand!(76), + 77 => $expand!(77), + 78 => $expand!(78), + 79 => $expand!(79), + 80 => $expand!(80), + 81 => $expand!(81), + 82 => $expand!(82), + 83 => $expand!(83), + 84 => $expand!(84), + 85 => $expand!(85), + 86 => $expand!(86), + 87 => $expand!(87), + 88 => $expand!(88), + 89 => $expand!(89), + 90 => $expand!(90), + 91 => $expand!(91), + 92 => $expand!(92), + 93 => $expand!(93), + 94 => $expand!(94), + 95 => $expand!(95), + 96 => $expand!(96), + 97 => $expand!(97), + 98 => $expand!(98), + 99 => $expand!(99), + 100 => $expand!(100), + 101 => $expand!(101), + 102 => $expand!(102), + 103 => $expand!(103), + 104 => $expand!(104), + 105 => $expand!(105), + 106 => $expand!(106), + 107 => $expand!(107), + 108 => $expand!(108), + 109 => $expand!(109), + 110 => $expand!(110), + 111 => $expand!(111), + 112 => $expand!(112), + 113 => $expand!(113), + 114 => $expand!(114), + 115 => $expand!(115), + 116 => $expand!(116), + 117 => $expand!(117), + 118 => $expand!(118), + 119 => $expand!(119), + 120 => $expand!(120), + 121 => $expand!(121), + 122 => $expand!(122), + 123 => $expand!(123), + 124 => $expand!(124), + 125 => $expand!(125), + 126 => $expand!(126), + 127 => $expand!(127), + 128 => $expand!(128), + 129 => $expand!(129), + 130 => $expand!(130), + 131 => $expand!(131), + 132 => $expand!(132), + 133 => $expand!(133), + 134 => $expand!(134), + 135 => $expand!(135), + 136 => $expand!(136), + 137 => $expand!(137), + 138 => $expand!(138), + 139 => $expand!(139), + 140 => $expand!(140), + 141 => $expand!(141), + 142 => $expand!(142), + 143 => $expand!(143), + 144 => $expand!(144), + 145 => $expand!(145), + 146 => $expand!(146), + 147 => $expand!(147), + 148 => $expand!(148), + 149 => $expand!(149), + 150 => $expand!(150), + 151 => $expand!(151), + 152 => $expand!(152), + 153 => $expand!(153), + 154 => $expand!(154), + 155 => $expand!(155), + 156 => $expand!(156), + 157 => $expand!(157), + 158 => $expand!(158), + 159 => $expand!(159), + 160 => $expand!(160), + 161 => $expand!(161), + 162 => $expand!(162), + 163 => $expand!(163), + 164 => $expand!(164), + 165 => $expand!(165), + 166 => $expand!(166), + 167 => $expand!(167), + 168 => $expand!(168), + 169 => $expand!(169), + 170 => $expand!(170), + 171 => $expand!(171), + 172 => $expand!(172), + 173 => $expand!(173), + 174 => $expand!(174), + 175 => $expand!(175), + 176 => $expand!(176), + 177 => $expand!(177), + 178 => $expand!(178), + 179 => $expand!(179), + 180 => $expand!(180), + 181 => $expand!(181), + 182 => $expand!(182), + 183 => $expand!(183), + 184 => $expand!(184), + 185 => $expand!(185), + 186 => $expand!(186), + 187 => $expand!(187), + 188 => $expand!(188), + 189 => $expand!(189), + 190 => $expand!(190), + 191 => $expand!(191), + 192 => $expand!(192), + 193 => $expand!(193), + 194 => $expand!(194), + 195 => $expand!(195), + 196 => $expand!(196), + 197 => $expand!(197), + 198 => $expand!(198), + 199 => $expand!(199), + 200 => $expand!(200), + 201 => $expand!(201), + 202 => $expand!(202), + 203 => $expand!(203), + 204 => $expand!(204), + 205 => $expand!(205), + 206 => $expand!(206), + 207 => $expand!(207), + 208 => $expand!(208), + 209 => $expand!(209), + 210 => $expand!(210), + 211 => $expand!(211), + 212 => $expand!(212), + 213 => $expand!(213), + 214 => $expand!(214), + 215 => $expand!(215), + 216 => $expand!(216), + 217 => $expand!(217), + 218 => $expand!(218), + 219 => $expand!(219), + 220 => $expand!(220), + 221 => $expand!(221), + 222 => $expand!(222), + 223 => $expand!(223), + 224 => $expand!(224), + 225 => $expand!(225), + 226 => $expand!(226), + 227 => $expand!(227), + 228 => $expand!(228), + 229 => $expand!(229), + 230 => $expand!(230), + 231 => $expand!(231), + 232 => $expand!(232), + 233 => $expand!(233), + 234 => $expand!(234), + 235 => $expand!(235), + 236 => $expand!(236), + 237 => $expand!(237), + 238 => $expand!(238), + 239 => $expand!(239), + 240 => $expand!(240), + 241 => $expand!(241), + 242 => $expand!(242), + 243 => $expand!(243), + 244 => $expand!(244), + 245 => $expand!(245), + 246 => $expand!(246), + 247 => $expand!(247), + 248 => $expand!(248), + 249 => $expand!(249), + 250 => $expand!(250), + 251 => $expand!(251), + 252 => $expand!(252), + 253 => $expand!(253), + 254 => $expand!(254), + 255 => $expand!(255), + _ => panic!("Invalid sae value"), + } + }; +} + #[cfg(test)] macro_rules! assert_approx_eq { ($a:expr, $b:expr, $eps:expr) => {{ diff --git a/library/stdarch/crates/core_arch/src/x86/mmx.rs b/library/stdarch/crates/core_arch/src/x86/mmx.rs deleted file mode 100644 index 3947f2bea6..0000000000 --- a/library/stdarch/crates/core_arch/src/x86/mmx.rs +++ /dev/null @@ -1,786 +0,0 @@ -//! `i586` MMX instruction set. -//! -//! The intrinsics here roughly correspond to those in the `mmintrin.h` C -//! header. -//! -//! The reference is [Intel 64 and IA-32 Architectures Software Developer's -//! Manual Volume 2: Instruction Set Reference, A-Z][intel64_ref]. -//! -//! [intel64_ref]: http://www.intel.de/content/dam/www/public/us/en/documents/manuals/64-ia-32-architectures-software-developer-instruction-set-reference-manual-325383.pdf - -use crate::{ - core_arch::{simd::*, x86::*}, - mem::transmute, -}; - -#[cfg(test)] -use stdarch_test::assert_instr; - -/// Constructs a 64-bit integer vector initialized to zero. -#[inline] -#[target_feature(enable = "mmx")] -// FIXME: this produces a movl instead of xorps on x86 -// FIXME: this produces a xor intrinsic instead of xorps on x86_64 -#[cfg_attr(all(test, target_arch = "x86_64"), assert_instr(xor))] -pub unsafe fn _mm_setzero_si64() -> __m64 { - transmute(0_i64) -} - -/// Adds packed 8-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddb))] -pub unsafe fn _mm_add_pi8(a: __m64, b: __m64) -> __m64 { - paddb(a, b) -} - -/// Adds packed 8-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddb))] -pub unsafe fn _m_paddb(a: __m64, b: __m64) -> __m64 { - _mm_add_pi8(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddw))] -pub unsafe fn _mm_add_pi16(a: __m64, b: __m64) -> __m64 { - paddw(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddw))] -pub unsafe fn _m_paddw(a: __m64, b: __m64) -> __m64 { - _mm_add_pi16(a, b) -} - -/// Adds packed 32-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddd))] -pub unsafe fn _mm_add_pi32(a: __m64, b: __m64) -> __m64 { - paddd(a, b) -} - -/// Adds packed 32-bit integers in `a` and `b`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddd))] -pub unsafe fn _m_paddd(a: __m64, b: __m64) -> __m64 { - _mm_add_pi32(a, b) -} - -/// Adds packed 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsb))] -pub unsafe fn _mm_adds_pi8(a: __m64, b: __m64) -> __m64 { - paddsb(a, b) -} - -/// Adds packed 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsb))] -pub unsafe fn _m_paddsb(a: __m64, b: __m64) -> __m64 { - _mm_adds_pi8(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsw))] -pub unsafe fn _mm_adds_pi16(a: __m64, b: __m64) -> __m64 { - paddsw(a, b) -} - -/// Adds packed 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddsw))] -pub unsafe fn _m_paddsw(a: __m64, b: __m64) -> __m64 { - _mm_adds_pi16(a, b) -} - -/// Adds packed unsigned 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusb))] -pub unsafe fn _mm_adds_pu8(a: __m64, b: __m64) -> __m64 { - paddusb(a, b) -} - -/// Adds packed unsigned 8-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusb))] -pub unsafe fn _m_paddusb(a: __m64, b: __m64) -> __m64 { - _mm_adds_pu8(a, b) -} - -/// Adds packed unsigned 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusw))] -pub unsafe fn _mm_adds_pu16(a: __m64, b: __m64) -> __m64 { - paddusw(a, b) -} - -/// Adds packed unsigned 16-bit integers in `a` and `b` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(paddusw))] -pub unsafe fn _m_paddusw(a: __m64, b: __m64) -> __m64 { - _mm_adds_pu16(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubb))] -pub unsafe fn _mm_sub_pi8(a: __m64, b: __m64) -> __m64 { - psubb(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubb))] -pub unsafe fn _m_psubb(a: __m64, b: __m64) -> __m64 { - _mm_sub_pi8(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubw))] -pub unsafe fn _mm_sub_pi16(a: __m64, b: __m64) -> __m64 { - psubw(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubw))] -pub unsafe fn _m_psubw(a: __m64, b: __m64) -> __m64 { - _mm_sub_pi16(a, b) -} - -/// Subtract packed 32-bit integers in `b` from packed 32-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubd))] -pub unsafe fn _mm_sub_pi32(a: __m64, b: __m64) -> __m64 { - psubd(a, b) -} - -/// Subtract packed 32-bit integers in `b` from packed 32-bit integers in `a`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubd))] -pub unsafe fn _m_psubd(a: __m64, b: __m64) -> __m64 { - _mm_sub_pi32(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsb))] -pub unsafe fn _mm_subs_pi8(a: __m64, b: __m64) -> __m64 { - psubsb(a, b) -} - -/// Subtract packed 8-bit integers in `b` from packed 8-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsb))] -pub unsafe fn _m_psubsb(a: __m64, b: __m64) -> __m64 { - _mm_subs_pi8(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsw))] -pub unsafe fn _mm_subs_pi16(a: __m64, b: __m64) -> __m64 { - psubsw(a, b) -} - -/// Subtract packed 16-bit integers in `b` from packed 16-bit integers in `a` -/// using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubsw))] -pub unsafe fn _m_psubsw(a: __m64, b: __m64) -> __m64 { - _mm_subs_pi16(a, b) -} - -/// Subtract packed unsigned 8-bit integers in `b` from packed unsigned 8-bit -/// integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusb))] -pub unsafe fn _mm_subs_pu8(a: __m64, b: __m64) -> __m64 { - psubusb(a, b) -} - -/// Subtract packed unsigned 8-bit integers in `b` from packed unsigned 8-bit -/// integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusb))] -pub unsafe fn _m_psubusb(a: __m64, b: __m64) -> __m64 { - _mm_subs_pu8(a, b) -} - -/// Subtract packed unsigned 16-bit integers in `b` from packed unsigned -/// 16-bit integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusw))] -pub unsafe fn _mm_subs_pu16(a: __m64, b: __m64) -> __m64 { - psubusw(a, b) -} - -/// Subtract packed unsigned 16-bit integers in `b` from packed unsigned -/// 16-bit integers in `a` using saturation. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(psubusw))] -pub unsafe fn _m_psubusw(a: __m64, b: __m64) -> __m64 { - _mm_subs_pu16(a, b) -} - -/// Converts packed 16-bit integers from `a` and `b` to packed 8-bit integers -/// using signed saturation. -/// -/// Positive values greater than 0x7F are saturated to 0x7F. Negative values -/// less than 0x80 are saturated to 0x80. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(packsswb))] -pub unsafe fn _mm_packs_pi16(a: __m64, b: __m64) -> __m64 { - packsswb(a, b) -} - -/// Converts packed 32-bit integers from `a` and `b` to packed 16-bit integers -/// using signed saturation. -/// -/// Positive values greater than 0x7F are saturated to 0x7F. Negative values -/// less than 0x80 are saturated to 0x80. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(packssdw))] -pub unsafe fn _mm_packs_pi32(a: __m64, b: __m64) -> __m64 { - packssdw(a, b) -} - -/// Compares whether each element of `a` is greater than the corresponding -/// element of `b` returning `0` for `false` and `-1` for `true`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(pcmpgtb))] -pub unsafe fn _mm_cmpgt_pi8(a: __m64, b: __m64) -> __m64 { - pcmpgtb(a, b) -} - -/// Compares whether each element of `a` is greater than the corresponding -/// element of `b` returning `0` for `false` and `-1` for `true`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(pcmpgtw))] -pub unsafe fn _mm_cmpgt_pi16(a: __m64, b: __m64) -> __m64 { - pcmpgtw(a, b) -} - -/// Compares whether each element of `a` is greater than the corresponding -/// element of `b` returning `0` for `false` and `-1` for `true`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(pcmpgtd))] -pub unsafe fn _mm_cmpgt_pi32(a: __m64, b: __m64) -> __m64 { - pcmpgtd(a, b) -} - -/// Unpacks the upper two elements from two `i16x4` vectors and interleaves -/// them into the result: `[a.2, b.2, a.3, b.3]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckhwd))] // FIXME punpcklbw expected -pub unsafe fn _mm_unpackhi_pi16(a: __m64, b: __m64) -> __m64 { - punpckhwd(a, b) -} - -/// Unpacks the upper four elements from two `i8x8` vectors and interleaves -/// them into the result: `[a.4, b.4, a.5, b.5, a.6, b.6, a.7, b.7]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckhbw))] -pub unsafe fn _mm_unpackhi_pi8(a: __m64, b: __m64) -> __m64 { - punpckhbw(a, b) -} - -/// Unpacks the lower four elements from two `i8x8` vectors and interleaves -/// them into the result: `[a.0, b.0, a.1, b.1, a.2, b.2, a.3, b.3]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpcklbw))] -pub unsafe fn _mm_unpacklo_pi8(a: __m64, b: __m64) -> __m64 { - punpcklbw(a, b) -} - -/// Unpacks the lower two elements from two `i16x4` vectors and interleaves -/// them into the result: `[a.0 b.0 a.1 b.1]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpcklwd))] -pub unsafe fn _mm_unpacklo_pi16(a: __m64, b: __m64) -> __m64 { - punpcklwd(a, b) -} - -/// Unpacks the upper element from two `i32x2` vectors and interleaves them -/// into the result: `[a.1, b.1]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckhdq))] -pub unsafe fn _mm_unpackhi_pi32(a: __m64, b: __m64) -> __m64 { - punpckhdq(a, b) -} - -/// Unpacks the lower element from two `i32x2` vectors and interleaves them -/// into the result: `[a.0, b.0]`. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(punpckldq))] -pub unsafe fn _mm_unpacklo_pi32(a: __m64, b: __m64) -> __m64 { - punpckldq(a, b) -} - -/// Sets packed 16-bit integers in dst with the supplied values. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set_pi16(e3: i16, e2: i16, e1: i16, e0: i16) -> __m64 { - _mm_setr_pi16(e0, e1, e2, e3) -} - -/// Sets packed 32-bit integers in dst with the supplied values. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set_pi32(e1: i32, e0: i32) -> __m64 { - _mm_setr_pi32(e0, e1) -} - -/// Sets packed 8-bit integers in dst with the supplied values. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set_pi8(e7: i8, e6: i8, e5: i8, e4: i8, e3: i8, e2: i8, e1: i8, e0: i8) -> __m64 { - _mm_setr_pi8(e0, e1, e2, e3, e4, e5, e6, e7) -} - -/// Broadcasts 16-bit integer a to all all elements of dst. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set1_pi16(a: i16) -> __m64 { - _mm_setr_pi16(a, a, a, a) -} - -/// Broadcasts 32-bit integer a to all all elements of dst. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set1_pi32(a: i32) -> __m64 { - _mm_setr_pi32(a, a) -} - -/// Broadcasts 8-bit integer a to all all elements of dst. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_set1_pi8(a: i8) -> __m64 { - _mm_setr_pi8(a, a, a, a, a, a, a, a) -} - -/// Sets packed 16-bit integers in dst with the supplied values in reverse -/// order. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_setr_pi16(e0: i16, e1: i16, e2: i16, e3: i16) -> __m64 { - transmute(i16x4::new(e0, e1, e2, e3)) -} - -/// Sets packed 32-bit integers in dst with the supplied values in reverse -/// order. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_setr_pi32(e0: i32, e1: i32) -> __m64 { - transmute(i32x2::new(e0, e1)) -} - -/// Sets packed 8-bit integers in dst with the supplied values in reverse order. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_setr_pi8( - e0: i8, - e1: i8, - e2: i8, - e3: i8, - e4: i8, - e5: i8, - e6: i8, - e7: i8, -) -> __m64 { - transmute(i8x8::new(e0, e1, e2, e3, e4, e5, e6, e7)) -} - -/// Empty the MMX state, which marks the x87 FPU registers as available for use -/// by x87 instructions. This instruction must be used at the end of all MMX -/// technology procedures. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(emms))] -pub unsafe fn _mm_empty() { - emms() -} - -/// Empty the MMX state, which marks the x87 FPU registers as available for use -/// by x87 instructions. This instruction must be used at the end of all MMX -/// technology procedures. -#[inline] -#[target_feature(enable = "mmx")] -#[cfg_attr(test, assert_instr(emms))] -pub unsafe fn _m_empty() { - emms() -} - -/// Copies 32-bit integer `a` to the lower elements of the return value, and zero -/// the upper element of the return value. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_cvtsi32_si64(a: i32) -> __m64 { - transmute(i32x2::new(a, 0)) -} - -/// Return the lower 32-bit integer in `a`. -#[inline] -#[target_feature(enable = "mmx")] -pub unsafe fn _mm_cvtsi64_si32(a: __m64) -> i32 { - let r: i32x2 = transmute(a); - r.0 -} - -#[allow(improper_ctypes)] -extern "C" { - #[link_name = "llvm.x86.mmx.padd.b"] - fn paddb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padd.w"] - fn paddw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padd.d"] - fn paddd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padds.b"] - fn paddsb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.padds.w"] - fn paddsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.paddus.b"] - fn paddusb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.paddus.w"] - fn paddusw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.b"] - fn psubb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.w"] - fn psubw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.d"] - fn psubd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubs.b"] - fn psubsb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubs.w"] - fn psubsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubus.b"] - fn psubusb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psubus.w"] - fn psubusw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.packsswb"] - fn packsswb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.packssdw"] - fn packssdw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pcmpgt.b"] - fn pcmpgtb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pcmpgt.w"] - fn pcmpgtw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pcmpgt.d"] - fn pcmpgtd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckhwd"] - fn punpckhwd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpcklwd"] - fn punpcklwd(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckhbw"] - fn punpckhbw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpcklbw"] - fn punpcklbw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckhdq"] - fn punpckhdq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.punpckldq"] - fn punpckldq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.emms"] - fn emms(); -} - -#[cfg(test)] -mod tests { - use crate::core_arch::x86::*; - use stdarch_test::simd_test; - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_setzero_si64() { - let r: __m64 = transmute(0_i64); - assert_eq_m64(r, _mm_setzero_si64()); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_add_pi8() { - let a = _mm_setr_pi8(-1, -1, 1, 1, -1, 0, 1, 0); - let b = _mm_setr_pi8(-127, 101, 99, 126, 0, -1, 0, 1); - let e = _mm_setr_pi8(-128, 100, 100, 127, -1, -1, 1, 1); - assert_eq_m64(e, _mm_add_pi8(a, b)); - assert_eq_m64(e, _m_paddb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_add_pi16() { - let a = _mm_setr_pi16(-1, -1, 1, 1); - let b = _mm_setr_pi16(i16::MIN + 1, 30001, -30001, i16::MAX - 1); - let e = _mm_setr_pi16(i16::MIN, 30000, -30000, i16::MAX); - assert_eq_m64(e, _mm_add_pi16(a, b)); - assert_eq_m64(e, _m_paddw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_add_pi32() { - let a = _mm_setr_pi32(1, -1); - let b = _mm_setr_pi32(i32::MAX - 1, i32::MIN + 1); - let e = _mm_setr_pi32(i32::MAX, i32::MIN); - assert_eq_m64(e, _mm_add_pi32(a, b)); - assert_eq_m64(e, _m_paddd(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pi8() { - let a = _mm_setr_pi8(-100, -1, 1, 100, -1, 0, 1, 0); - let b = _mm_setr_pi8(-100, 1, -1, 100, 0, -1, 0, 1); - let e = _mm_setr_pi8(i8::MIN, 0, 0, i8::MAX, -1, -1, 1, 1); - assert_eq_m64(e, _mm_adds_pi8(a, b)); - assert_eq_m64(e, _m_paddsb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pi16() { - let a = _mm_setr_pi16(-32000, 32000, 4, 0); - let b = _mm_setr_pi16(-32000, 32000, -5, 1); - let e = _mm_setr_pi16(i16::MIN, i16::MAX, -1, 1); - assert_eq_m64(e, _mm_adds_pi16(a, b)); - assert_eq_m64(e, _m_paddsw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pu8() { - let a = _mm_setr_pi8(0, 1, 2, 3, 4, 5, 6, 200u8 as i8); - let b = _mm_setr_pi8(0, 10, 20, 30, 40, 50, 60, 200u8 as i8); - let e = _mm_setr_pi8(0, 11, 22, 33, 44, 55, 66, u8::MAX as i8); - assert_eq_m64(e, _mm_adds_pu8(a, b)); - assert_eq_m64(e, _m_paddusb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_adds_pu16() { - let a = _mm_setr_pi16(0, 1, 2, 60000u16 as i16); - let b = _mm_setr_pi16(0, 10, 20, 60000u16 as i16); - let e = _mm_setr_pi16(0, 11, 22, u16::MAX as i16); - assert_eq_m64(e, _mm_adds_pu16(a, b)); - assert_eq_m64(e, _m_paddusw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_sub_pi8() { - let a = _mm_setr_pi8(0, 0, 1, 1, -1, -1, 0, 0); - let b = _mm_setr_pi8(-1, 1, -2, 2, 100, -100, -127, 127); - let e = _mm_setr_pi8(1, -1, 3, -1, -101, 99, 127, -127); - assert_eq_m64(e, _mm_sub_pi8(a, b)); - assert_eq_m64(e, _m_psubb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_sub_pi16() { - let a = _mm_setr_pi16(-20000, -20000, 20000, 30000); - let b = _mm_setr_pi16(-10000, 10000, -10000, 30000); - let e = _mm_setr_pi16(-10000, -30000, 30000, 0); - assert_eq_m64(e, _mm_sub_pi16(a, b)); - assert_eq_m64(e, _m_psubw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_sub_pi32() { - let a = _mm_setr_pi32(500_000, -500_000); - let b = _mm_setr_pi32(500_000, 500_000); - let e = _mm_setr_pi32(0, -1_000_000); - assert_eq_m64(e, _mm_sub_pi32(a, b)); - assert_eq_m64(e, _m_psubd(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pi8() { - let a = _mm_setr_pi8(-100, 100, 0, 0, 0, 0, -5, 5); - let b = _mm_setr_pi8(100, -100, i8::MIN, 127, -1, 1, 3, -3); - let e = _mm_setr_pi8(i8::MIN, i8::MAX, i8::MAX, -127, 1, -1, -8, 8); - assert_eq_m64(e, _mm_subs_pi8(a, b)); - assert_eq_m64(e, _m_psubsb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pi16() { - let a = _mm_setr_pi16(-20000, 20000, 0, 0); - let b = _mm_setr_pi16(20000, -20000, -1, 1); - let e = _mm_setr_pi16(i16::MIN, i16::MAX, 1, -1); - assert_eq_m64(e, _mm_subs_pi16(a, b)); - assert_eq_m64(e, _m_psubsw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pu8() { - let a = _mm_setr_pi8(50, 10, 20, 30, 40, 60, 70, 80); - let b = _mm_setr_pi8(60, 20, 30, 40, 30, 20, 10, 0); - let e = _mm_setr_pi8(0, 0, 0, 0, 10, 40, 60, 80); - assert_eq_m64(e, _mm_subs_pu8(a, b)); - assert_eq_m64(e, _m_psubusb(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_subs_pu16() { - let a = _mm_setr_pi16(10000, 200, 0, 44444u16 as i16); - let b = _mm_setr_pi16(20000, 300, 1, 11111); - let e = _mm_setr_pi16(0, 0, 0, 33333u16 as i16); - assert_eq_m64(e, _mm_subs_pu16(a, b)); - assert_eq_m64(e, _m_psubusw(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_packs_pi16() { - let a = _mm_setr_pi16(-1, 2, -3, 4); - let b = _mm_setr_pi16(-5, 6, -7, 8); - let r = _mm_setr_pi8(-1, 2, -3, 4, -5, 6, -7, 8); - assert_eq_m64(r, _mm_packs_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_packs_pi32() { - let a = _mm_setr_pi32(-1, 2); - let b = _mm_setr_pi32(-5, 6); - let r = _mm_setr_pi16(-1, 2, -5, 6); - assert_eq_m64(r, _mm_packs_pi32(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cmpgt_pi8() { - let a = _mm_setr_pi8(0, 1, 2, 3, 4, 5, 6, 7); - let b = _mm_setr_pi8(8, 7, 6, 5, 4, 3, 2, 1); - let r = _mm_setr_pi8(0, 0, 0, 0, 0, -1, -1, -1); - assert_eq_m64(r, _mm_cmpgt_pi8(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cmpgt_pi16() { - let a = _mm_setr_pi16(0, 1, 2, 3); - let b = _mm_setr_pi16(4, 3, 2, 1); - let r = _mm_setr_pi16(0, 0, 0, -1); - assert_eq_m64(r, _mm_cmpgt_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cmpgt_pi32() { - let a = _mm_setr_pi32(0, 3); - let b = _mm_setr_pi32(1, 2); - let r0 = _mm_setr_pi32(0, -1); - let r1 = _mm_setr_pi32(-1, 0); - - assert_eq_m64(r0, _mm_cmpgt_pi32(a, b)); - assert_eq_m64(r1, _mm_cmpgt_pi32(b, a)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpackhi_pi8() { - let a = _mm_setr_pi8(0, 3, 4, 7, 8, 11, 12, 15); - let b = _mm_setr_pi8(1, 2, 5, 6, 9, 10, 13, 14); - let r = _mm_setr_pi8(8, 9, 11, 10, 12, 13, 15, 14); - - assert_eq_m64(r, _mm_unpackhi_pi8(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpacklo_pi8() { - let a = _mm_setr_pi8(0, 1, 2, 3, 4, 5, 6, 7); - let b = _mm_setr_pi8(8, 9, 10, 11, 12, 13, 14, 15); - let r = _mm_setr_pi8(0, 8, 1, 9, 2, 10, 3, 11); - assert_eq_m64(r, _mm_unpacklo_pi8(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpackhi_pi16() { - let a = _mm_setr_pi16(0, 1, 2, 3); - let b = _mm_setr_pi16(4, 5, 6, 7); - let r = _mm_setr_pi16(2, 6, 3, 7); - assert_eq_m64(r, _mm_unpackhi_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpacklo_pi16() { - let a = _mm_setr_pi16(0, 1, 2, 3); - let b = _mm_setr_pi16(4, 5, 6, 7); - let r = _mm_setr_pi16(0, 4, 1, 5); - assert_eq_m64(r, _mm_unpacklo_pi16(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpackhi_pi32() { - let a = _mm_setr_pi32(0, 3); - let b = _mm_setr_pi32(1, 2); - let r = _mm_setr_pi32(3, 2); - - assert_eq_m64(r, _mm_unpackhi_pi32(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_unpacklo_pi32() { - let a = _mm_setr_pi32(0, 3); - let b = _mm_setr_pi32(1, 2); - let r = _mm_setr_pi32(0, 1); - - assert_eq_m64(r, _mm_unpacklo_pi32(a, b)); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_empty() { - _mm_empty(); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_m_empty() { - _m_empty(); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cvtsi32_si64() { - let a = _mm_cvtsi32_si64(42); - let b = _mm_setr_pi32(42, 0); - assert_eq_m64(a, b); - } - - #[simd_test(enable = "mmx")] - unsafe fn test_mm_cvtsi64_si32() { - let a = _mm_setr_pi32(42, 666); - let b = _mm_cvtsi64_si32(a); - assert_eq!(b, 42); - } -} diff --git a/library/stdarch/crates/core_arch/src/x86/mod.rs b/library/stdarch/crates/core_arch/src/x86/mod.rs index 60eb890c2f..abe99f23a2 100644 --- a/library/stdarch/crates/core_arch/src/x86/mod.rs +++ b/library/stdarch/crates/core_arch/src/x86/mod.rs @@ -6,50 +6,6 @@ use crate::{intrinsics, marker::Sized, mem::transmute}; mod macros; types! { - /// 64-bit wide integer vector type, x86-specific - /// - /// This type is the same as the `__m64` type defined by Intel, - /// representing a 64-bit SIMD register. Usage of this type typically - /// corresponds to the `mmx` target feature. - /// - /// Internally this type may be viewed as: - /// - /// * `i8x8` - eight `i8` variables packed together - /// * `i16x4` - four `i16` variables packed together - /// * `i32x2` - two `i32` variables packed together - /// - /// (as well as unsigned versions). Each intrinsic may interpret the - /// internal bits differently, check the documentation of the intrinsic - /// to see how it's being used. - /// - /// Note that this means that an instance of `__m64` typically just means - /// a "bag of bits" which is left up to interpretation at the point of use. - /// - /// Most intrinsics using `__m64` are prefixed with `_mm_` and the - /// integer types tend to correspond to suffixes like "pi8" or "pi32" (not - /// to be confused with "epiXX", used for `__m128i`). - /// - /// # Examples - /// - /// ``` - /// # #![feature(stdsimd, mmx_target_feature)] - /// #[cfg(target_arch = "x86")] - /// use std::arch::x86::*; - /// #[cfg(target_arch = "x86_64")] - /// use std::arch::x86_64::*; - /// - /// # fn main() { - /// # #[target_feature(enable = "mmx")] - /// # unsafe fn foo() { - /// let all_bytes_zero = _mm_setzero_si64(); - /// let all_bytes_one = _mm_set1_pi8(1); - /// let two_i32 = _mm_set_pi32(1, 2); - /// # } - /// # if is_x86_feature_detected!("mmx") { unsafe { foo() } } - /// # } - /// ``` - pub struct __m64(i64); - /// 128-bit wide integer vector type, x86-specific /// /// This type is the same as the `__m128i` type defined by Intel, @@ -354,56 +310,25 @@ pub type __mmask8 = u8; #[allow(non_camel_case_types)] pub type _MM_CMPINT_ENUM = i32; +/// The `MM_MANTISSA_NORM_ENUM` type used to specify mantissa normalized operations in AVX-512 intrinsics. +#[allow(non_camel_case_types)] +pub type _MM_MANTISSA_NORM_ENUM = i32; + +/// The `MM_MANTISSA_SIGN_ENUM` type used to specify mantissa signed operations in AVX-512 intrinsics. +#[allow(non_camel_case_types)] +pub type _MM_MANTISSA_SIGN_ENUM = i32; + +/// The `MM_PERM_ENUM` type used to specify shuffle operations in AVX-512 intrinsics. +#[allow(non_camel_case_types)] +pub type _MM_PERM_ENUM = i32; + #[cfg(test)] mod test; #[cfg(test)] pub use self::test::*; #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] -pub(crate) trait m64Ext: Sized { - fn as_m64(self) -> __m64; - - #[inline] - fn as_u8x8(self) -> crate::core_arch::simd::u8x8 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_u16x4(self) -> crate::core_arch::simd::u16x4 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_u32x2(self) -> crate::core_arch::simd::u32x2 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_i8x8(self) -> crate::core_arch::simd::i8x8 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_i16x4(self) -> crate::core_arch::simd::i16x4 { - unsafe { transmute(self.as_m64()) } - } - - #[inline] - fn as_i32x2(self) -> crate::core_arch::simd::i32x2 { - unsafe { transmute(self.as_m64()) } - } -} - -impl m64Ext for __m64 { - #[inline] - fn as_m64(self) -> Self { - self - } -} - -#[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m128iExt: Sized { fn as_m128i(self) -> __m128i; @@ -456,7 +381,7 @@ impl m128iExt for __m128i { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m256iExt: Sized { fn as_m256i(self) -> __m256i; @@ -509,7 +434,7 @@ impl m256iExt for __m256i { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m256Ext: Sized { fn as_m256(self) -> __m256; @@ -527,7 +452,7 @@ impl m256Ext for __m256 { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m512iExt: Sized { fn as_m512i(self) -> __m512i; @@ -560,7 +485,7 @@ impl m512iExt for __m512i { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m512Ext: Sized { fn as_m512(self) -> __m512; @@ -578,7 +503,7 @@ impl m512Ext for __m512 { } #[allow(non_camel_case_types)] -#[unstable(feature = "stdimd_internal", issue = "none")] +#[unstable(feature = "stdsimd_internal", issue = "none")] pub(crate) trait m512dExt: Sized { fn as_m512d(self) -> __m512d; @@ -649,9 +574,6 @@ mod tbm; #[cfg(not(stdarch_intel_sde))] pub use self::tbm::*; -mod mmx; -pub use self::mmx::*; - mod pclmulqdq; pub use self::pclmulqdq::*; diff --git a/library/stdarch/crates/core_arch/src/x86/sse.rs b/library/stdarch/crates/core_arch/src/x86/sse.rs index c01aa1bc9f..ba3efae3c9 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse.rs @@ -1115,33 +1115,6 @@ pub unsafe fn _mm_movemask_ps(a: __m128) -> i32 { movmskps(a) } -/// Sets the upper two single-precision floating-point values with 64 bits of -/// data loaded from the address `p`; the lower two values are passed through -/// from `a`. -#[inline] -#[target_feature(enable = "sse")] -#[cfg_attr(test, assert_instr(movhps))] -// TODO: this function is actually not limited to floats, but that's what -// what matches the C type most closely: `(__m128, *const __m64) -> __m128`. -pub unsafe fn _mm_loadh_pi(a: __m128, p: *const __m64) -> __m128 { - let q = p as *const f32x2; - let b: f32x2 = *q; - let bb = simd_shuffle4(b, b, [0, 1, 0, 1]); - simd_shuffle4(a, bb, [0, 1, 4, 5]) -} - -/// Loads two floats from `p` into the lower half of a `__m128`. The upper half -/// is copied from the upper half of `a`. -#[inline] -#[target_feature(enable = "sse")] -#[cfg_attr(test, assert_instr(movlps))] -pub unsafe fn _mm_loadl_pi(a: __m128, p: *const __m64) -> __m128 { - let q = p as *const f32x2; - let b: f32x2 = *q; - let bb = simd_shuffle4(b, b, [0, 1, 0, 1]); - simd_shuffle4(a, bb, [4, 5, 2, 3]) -} - /// Construct a `__m128` with the lowest element read from `p` and the other /// elements set to zero. /// @@ -1270,72 +1243,6 @@ pub unsafe fn _mm_loadu_si64(mem_addr: *const u8) -> __m128i { transmute(i64x2(0, ptr::read_unaligned(mem_addr as *const i64))) } -/// Stores the upper half of `a` (64 bits) into memory. -/// -/// This intrinsic corresponds to the `MOVHPS` instruction. The compiler may -/// choose to generate an equivalent sequence of other instructions. -#[inline] -#[target_feature(enable = "sse")] -// On i686 and up LLVM actually generates MOVHPD instead of MOVHPS, that's -// fine. -// On i586 (no SSE2) it just generates plain MOV instructions. -#[cfg_attr( - all(test, any(target_arch = "x86_64", target_feature = "sse2"), - not(target_os = "windows")), - // assert_instr(movhpd) - assert_instr(movhps) // LLVM7 prefers single-precision instructions -)] -pub unsafe fn _mm_storeh_pi(p: *mut __m64, a: __m128) { - #[cfg(target_arch = "x86")] - { - // If this is a `f64x2` then on i586, LLVM generates fldl & fstpl which - // is just silly - let a64: u64x2 = mem::transmute(a); - let a_hi = a64.extract(1); - *(p as *mut u64) = a_hi; - } - #[cfg(target_arch = "x86_64")] - { - // If this is a `u64x2` LLVM generates a pshufd + movq, but we really - // want a a MOVHPD or MOVHPS here. - let a64: f64x2 = mem::transmute(a); - let a_hi = a64.extract(1); - *p = mem::transmute(a_hi); - } -} - -/// Stores the lower half of `a` (64 bits) into memory. -/// -/// This intrinsic corresponds to the `MOVQ` instruction. The compiler may -/// choose to generate an equivalent sequence of other instructions. -#[inline] -#[target_feature(enable = "sse")] -// On i586 the codegen just generates plane MOVs. No need to test for that. -#[cfg_attr( - all( - test, - any(target_arch = "x86_64", target_feature = "sse2"), - not(target_os = "windows") - ), - assert_instr(movlps) -)] -pub unsafe fn _mm_storel_pi(p: *mut __m64, a: __m128) { - #[cfg(target_arch = "x86")] - { - // Same as for _mm_storeh_pi: i586 code gen would use floating point - // stack. - let a64: u64x2 = mem::transmute(a); - let a_hi = a64.extract(0); - *(p as *mut u64) = a_hi; - } - #[cfg(target_arch = "x86_64")] - { - let a64: f64x2 = mem::transmute(a); - let a_hi = a64.extract(0); - *p = mem::transmute(a_hi); - } -} - /// Stores the lowest 32 bit float of `a` into memory. /// /// This intrinsic corresponds to the `MOVSS` instruction. @@ -1985,42 +1892,6 @@ extern "C" { fn prefetch(p: *const i8, rw: i32, loc: i32, ty: i32); #[link_name = "llvm.x86.sse.cmp.ss"] fn cmpss(a: __m128, b: __m128, imm8: i8) -> __m128; - #[link_name = "llvm.x86.mmx.movnt.dq"] - fn movntdq(a: *mut __m64, b: __m64); - #[link_name = "llvm.x86.sse.cvtpi2ps"] - fn cvtpi2ps(a: __m128, b: __m64) -> __m128; - #[link_name = "llvm.x86.mmx.maskmovq"] - fn maskmovq(a: __m64, mask: __m64, mem_addr: *mut i8); - #[link_name = "llvm.x86.mmx.pextr.w"] - fn pextrw(a: __m64, imm8: i32) -> i32; - #[link_name = "llvm.x86.mmx.pinsr.w"] - fn pinsrw(a: __m64, d: i32, imm8: i32) -> __m64; - #[link_name = "llvm.x86.mmx.pmovmskb"] - fn pmovmskb(a: __m64) -> i32; - #[link_name = "llvm.x86.sse.pshuf.w"] - fn pshufw(a: __m64, imm8: i8) -> __m64; - #[link_name = "llvm.x86.mmx.pmaxs.w"] - fn pmaxsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmaxu.b"] - fn pmaxub(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmins.w"] - fn pminsw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pminu.b"] - fn pminub(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmulhu.w"] - fn pmulhuw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmull.w"] - fn pmullw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pavg.b"] - fn pavgb(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pavg.w"] - fn pavgw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psad.bw"] - fn psadbw(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.sse.cvtps2pi"] - fn cvtps2pi(a: __m128) -> __m64; - #[link_name = "llvm.x86.sse.cvttps2pi"] - fn cvttps2pi(a: __m128) -> __m64; } /// Stores `a` into the memory at `mem_addr` using a non-temporal memory hint. @@ -2038,463 +1909,6 @@ pub unsafe fn _mm_stream_ps(mem_addr: *mut f32, a: __m128) { intrinsics::nontemporal_store(mem_addr as *mut __m128, a); } -/// Stores 64-bits of integer data from a into memory using a non-temporal -/// memory hint. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(movntq))] -pub unsafe fn _mm_stream_pi(mem_addr: *mut __m64, a: __m64) { - movntdq(mem_addr, a) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxsw))] -pub unsafe fn _mm_max_pi16(a: __m64, b: __m64) -> __m64 { - pmaxsw(a, b) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxsw))] -pub unsafe fn _m_pmaxsw(a: __m64, b: __m64) -> __m64 { - _mm_max_pi16(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxub))] -pub unsafe fn _mm_max_pu8(a: __m64, b: __m64) -> __m64 { - pmaxub(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// greatest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmaxub))] -pub unsafe fn _m_pmaxub(a: __m64, b: __m64) -> __m64 { - _mm_max_pu8(a, b) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminsw))] -pub unsafe fn _mm_min_pi16(a: __m64, b: __m64) -> __m64 { - pminsw(a, b) -} - -/// Compares the packed 16-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminsw))] -pub unsafe fn _m_pminsw(a: __m64, b: __m64) -> __m64 { - _mm_min_pi16(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminub))] -pub unsafe fn _mm_min_pu8(a: __m64, b: __m64) -> __m64 { - pminub(a, b) -} - -/// Compares the packed 8-bit signed integers of `a` and `b` writing the -/// smallest value into the result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pminub))] -pub unsafe fn _m_pminub(a: __m64, b: __m64) -> __m64 { - _mm_min_pu8(a, b) -} - -/// Multiplies packed 16-bit unsigned integer values and writes the -/// high-order 16 bits of each 32-bit product to the corresponding bits in -/// the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmulhuw))] -pub unsafe fn _mm_mulhi_pu16(a: __m64, b: __m64) -> __m64 { - pmulhuw(a, b) -} - -/// Multiplies packed 16-bit integer values and writes the -/// low-order 16 bits of each 32-bit product to the corresponding bits in -/// the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmullw))] -pub unsafe fn _mm_mullo_pi16(a: __m64, b: __m64) -> __m64 { - pmullw(a, b) -} - -/// Multiplies packed 16-bit unsigned integer values and writes the -/// high-order 16 bits of each 32-bit product to the corresponding bits in -/// the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmulhuw))] -pub unsafe fn _m_pmulhuw(a: __m64, b: __m64) -> __m64 { - _mm_mulhi_pu16(a, b) -} - -/// Computes the rounded averages of the packed unsigned 8-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgb))] -pub unsafe fn _mm_avg_pu8(a: __m64, b: __m64) -> __m64 { - pavgb(a, b) -} - -/// Computes the rounded averages of the packed unsigned 8-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgb))] -pub unsafe fn _m_pavgb(a: __m64, b: __m64) -> __m64 { - _mm_avg_pu8(a, b) -} - -/// Computes the rounded averages of the packed unsigned 16-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgw))] -pub unsafe fn _mm_avg_pu16(a: __m64, b: __m64) -> __m64 { - pavgw(a, b) -} - -/// Computes the rounded averages of the packed unsigned 16-bit integer -/// values and writes the averages to the corresponding bits in the -/// destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pavgw))] -pub unsafe fn _m_pavgw(a: __m64, b: __m64) -> __m64 { - _mm_avg_pu16(a, b) -} - -/// Subtracts the corresponding 8-bit unsigned integer values of the two -/// 64-bit vector operands and computes the absolute value for each of the -/// difference. Then sum of the 8 absolute differences is written to the -/// bits `[15:0]` of the destination; the remaining bits `[63:16]` are cleared. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(psadbw))] -pub unsafe fn _mm_sad_pu8(a: __m64, b: __m64) -> __m64 { - psadbw(a, b) -} - -/// Subtracts the corresponding 8-bit unsigned integer values of the two -/// 64-bit vector operands and computes the absolute value for each of the -/// difference. Then sum of the 8 absolute differences is written to the -/// bits `[15:0]` of the destination; the remaining bits `[63:16]` are cleared. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(psadbw))] -pub unsafe fn _m_psadbw(a: __m64, b: __m64) -> __m64 { - _mm_sad_pu8(a, b) -} - -/// Converts two elements of a 64-bit vector of `[2 x i32]` into two -/// floating point values and writes them to the lower 64-bits of the -/// destination. The remaining higher order elements of the destination are -/// copied from the corresponding elements in the first operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi32_ps(a: __m128, b: __m64) -> __m128 { - cvtpi2ps(a, b) -} - -/// Converts two elements of a 64-bit vector of `[2 x i32]` into two -/// floating point values and writes them to the lower 64-bits of the -/// destination. The remaining higher order elements of the destination are -/// copied from the corresponding elements in the first operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvt_pi2ps(a: __m128, b: __m64) -> __m128 { - _mm_cvtpi32_ps(a, b) -} - -/// Converts the lower 4 8-bit values of `a` into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi8_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let b = _mm_cmpgt_pi8(b, a); - let b = _mm_unpacklo_pi8(a, b); - _mm_cvtpi16_ps(b) -} - -/// Converts the lower 4 8-bit values of `a` into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpu8_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let b = _mm_unpacklo_pi8(a, b); - _mm_cvtpi16_ps(b) -} - -/// Converts a 64-bit vector of `i16`s into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi16_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let b = _mm_cmpgt_pi16(b, a); - let c = _mm_unpackhi_pi16(a, b); - let r = _mm_setzero_ps(); - let r = cvtpi2ps(r, c); - let r = _mm_movelh_ps(r, r); - let c = _mm_unpacklo_pi16(a, b); - cvtpi2ps(r, c) -} - -/// Converts a 64-bit vector of `i16`s into a 128-bit vector of 4 `f32`s. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpu16_ps(a: __m64) -> __m128 { - let b = _mm_setzero_si64(); - let c = _mm_unpackhi_pi16(a, b); - let r = _mm_setzero_ps(); - let r = cvtpi2ps(r, c); - let r = _mm_movelh_ps(r, r); - let c = _mm_unpacklo_pi16(a, b); - cvtpi2ps(r, c) -} - -/// Converts the two 32-bit signed integer values from each 64-bit vector -/// operand of `[2 x i32]` into a 128-bit vector of `[4 x float]`. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2ps))] -pub unsafe fn _mm_cvtpi32x2_ps(a: __m64, b: __m64) -> __m128 { - let c = _mm_setzero_ps(); - let c = _mm_cvtpi32_ps(c, b); - let c = _mm_movelh_ps(c, c); - _mm_cvtpi32_ps(c, a) -} - -/// Conditionally copies the values from each 8-bit element in the first -/// 64-bit integer vector operand to the specified memory location, as -/// specified by the most significant bit in the corresponding element in the -/// second 64-bit integer vector operand. -/// -/// To minimize caching, the data is flagged as non-temporal -/// (unlikely to be used again soon). -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(maskmovq))] -pub unsafe fn _mm_maskmove_si64(a: __m64, mask: __m64, mem_addr: *mut i8) { - maskmovq(a, mask, mem_addr) -} - -/// Conditionally copies the values from each 8-bit element in the first -/// 64-bit integer vector operand to the specified memory location, as -/// specified by the most significant bit in the corresponding element in the -/// second 64-bit integer vector operand. -/// -/// To minimize caching, the data is flagged as non-temporal -/// (unlikely to be used again soon). -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(maskmovq))] -pub unsafe fn _m_maskmovq(a: __m64, mask: __m64, mem_addr: *mut i8) { - _mm_maskmove_si64(a, mask, mem_addr) -} - -/// Extracts 16-bit element from a 64-bit vector of `[4 x i16]` and -/// returns it, as specified by the immediate integer operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pextrw, imm2 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm_extract_pi16(a: __m64, imm2: i32) -> i32 { - macro_rules! call { - ($imm2:expr) => { - pextrw(a, $imm2) as i32 - }; - } - constify_imm2!(imm2, call) -} - -/// Extracts 16-bit element from a 64-bit vector of `[4 x i16]` and -/// returns it, as specified by the immediate integer operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pextrw, imm2 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _m_pextrw(a: __m64, imm2: i32) -> i32 { - macro_rules! call { - ($imm2:expr) => { - pextrw(a, $imm2) as i32 - }; - } - constify_imm2!(imm2, call) -} - -/// Copies data from the 64-bit vector of `[4 x i16]` to the destination, -/// and inserts the lower 16-bits of an integer operand at the 16-bit offset -/// specified by the immediate operand `n`. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pinsrw, imm2 = 0))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm_insert_pi16(a: __m64, d: i32, imm2: i32) -> __m64 { - macro_rules! call { - ($imm2:expr) => { - pinsrw(a, d, $imm2) - }; - } - constify_imm2!(imm2, call) -} - -/// Copies data from the 64-bit vector of `[4 x i16]` to the destination, -/// and inserts the lower 16-bits of an integer operand at the 16-bit offset -/// specified by the immediate operand `n`. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pinsrw, imm2 = 0))] -#[rustc_args_required_const(2)] -pub unsafe fn _m_pinsrw(a: __m64, d: i32, imm2: i32) -> __m64 { - macro_rules! call { - ($imm2:expr) => { - pinsrw(a, d, $imm2) - }; - } - constify_imm2!(imm2, call) -} - -/// Takes the most significant bit from each 8-bit element in a 64-bit -/// integer vector to create a 16-bit mask value. Zero-extends the value to -/// 32-bit integer and writes it to the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmovmskb))] -pub unsafe fn _mm_movemask_pi8(a: __m64) -> i32 { - pmovmskb(a) -} - -/// Takes the most significant bit from each 8-bit element in a 64-bit -/// integer vector to create a 16-bit mask value. Zero-extends the value to -/// 32-bit integer and writes it to the destination. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pmovmskb))] -pub unsafe fn _m_pmovmskb(a: __m64) -> i32 { - _mm_movemask_pi8(a) -} - -/// Shuffles the 4 16-bit integers from a 64-bit integer vector to the -/// destination, as specified by the immediate value operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pshufw, imm8 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _mm_shuffle_pi16(a: __m64, imm8: i32) -> __m64 { - macro_rules! call { - ($imm8:expr) => { - pshufw(a, $imm8) - }; - } - constify_imm8!(imm8, call) -} - -/// Shuffles the 4 16-bit integers from a 64-bit integer vector to the -/// destination, as specified by the immediate value operand. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(pshufw, imm8 = 0))] -#[rustc_args_required_const(1)] -pub unsafe fn _m_pshufw(a: __m64, imm8: i32) -> __m64 { - macro_rules! call { - ($imm8:expr) => { - pshufw(a, $imm8) - }; - } - constify_imm8!(imm8, call) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers with truncation. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvttps2pi))] -pub unsafe fn _mm_cvttps_pi32(a: __m128) -> __m64 { - cvttps2pi(a) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers with truncation. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvttps2pi))] -pub unsafe fn _mm_cvtt_ps2pi(a: __m128) -> __m64 { - _mm_cvttps_pi32(a) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvtps_pi32(a: __m128) -> __m64 { - cvtps2pi(a) -} - -/// Converts the two lower packed single-precision (32-bit) floating-point -/// elements in `a` to packed 32-bit integers. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvt_ps2pi(a: __m128) -> __m64 { - _mm_cvtps_pi32(a) -} - -/// Converts packed single-precision (32-bit) floating-point elements in `a` to -/// packed 16-bit integers. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvtps_pi16(a: __m128) -> __m64 { - let b = _mm_cvtps_pi32(a); - let a = _mm_movehl_ps(a, a); - let c = _mm_cvtps_pi32(a); - _mm_packs_pi32(b, c) -} - -/// Converts packed single-precision (32-bit) floating-point elements in `a` to -/// packed 8-bit integers, and returns theem in the lower 4 elements of the -/// result. -#[inline] -#[target_feature(enable = "sse,mmx")] -#[cfg_attr(test, assert_instr(cvtps2pi))] -pub unsafe fn _mm_cvtps_pi8(a: __m128) -> __m64 { - let b = _mm_cvtps_pi16(a); - let c = _mm_setzero_si64(); - _mm_packs_pi16(b, c) -} - #[cfg(test)] mod tests { use crate::{hint::black_box, mem::transmute}; @@ -3593,24 +3007,6 @@ mod tests { assert_eq_m128(r, _mm_setr_ps(1.0, 2.0, 5.0, 6.0)); } - #[simd_test(enable = "sse")] - unsafe fn test_mm_loadh_pi() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let x: [f32; 4] = [5.0, 6.0, 7.0, 8.0]; - let p = x[..].as_ptr(); - let r = _mm_loadh_pi(a, p as *const _); - assert_eq_m128(r, _mm_setr_ps(1.0, 2.0, 5.0, 6.0)); - } - - #[simd_test(enable = "sse")] - unsafe fn test_mm_loadl_pi() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let x: [f32; 4] = [5.0, 6.0, 7.0, 8.0]; - let p = x[..].as_ptr(); - let r = _mm_loadl_pi(a, p as *const _); - assert_eq_m128(r, _mm_setr_ps(5.0, 6.0, 3.0, 4.0)); - } - #[simd_test(enable = "sse")] unsafe fn test_mm_load_ss() { let a = 42.0f32; @@ -3684,28 +3080,6 @@ mod tests { assert_eq_m128i(r, _mm_set_epi64x(5, 0)); } - #[simd_test(enable = "sse")] - unsafe fn test_mm_storeh_pi() { - let mut vals = [0.0f32; 8]; - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - _mm_storeh_pi(vals.as_mut_ptr() as *mut _, a); - - assert_eq!(vals[0], 3.0); - assert_eq!(vals[1], 4.0); - assert_eq!(vals[2], 0.0); - } - - #[simd_test(enable = "sse")] - unsafe fn test_mm_storel_pi() { - let mut vals = [0.0f32; 8]; - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - _mm_storel_pi(vals.as_mut_ptr() as *mut _, a); - - assert_eq!(vals[0], 1.0); - assert_eq!(vals[1], 2.0); - assert_eq!(vals[2], 0.0); - } - #[simd_test(enable = "sse")] unsafe fn test_mm_store_ss() { let mut vals = [0.0f32; 8]; @@ -3926,254 +3300,4 @@ mod tests { assert_eq!(mem.data[i], get_m128(a, i)); } } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_stream_pi() { - let a = transmute(i8x8::new(0, 0, 0, 0, 0, 0, 0, 7)); - let mut mem = boxed::Box::<__m64>::new(transmute(i8x8::splat(1))); - _mm_stream_pi(&mut *mem as *mut _ as *mut _, a); - assert_eq_m64(a, *mem); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_max_pi16() { - let a = _mm_setr_pi16(-1, 6, -3, 8); - let b = _mm_setr_pi16(5, -2, 7, -4); - let r = _mm_setr_pi16(5, 6, 7, 8); - - assert_eq_m64(r, _mm_max_pi16(a, b)); - assert_eq_m64(r, _m_pmaxsw(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_max_pu8() { - let a = _mm_setr_pi8(2, 6, 3, 8, 2, 6, 3, 8); - let b = _mm_setr_pi8(5, 2, 7, 4, 5, 2, 7, 4); - let r = _mm_setr_pi8(5, 6, 7, 8, 5, 6, 7, 8); - - assert_eq_m64(r, _mm_max_pu8(a, b)); - assert_eq_m64(r, _m_pmaxub(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_min_pi16() { - let a = _mm_setr_pi16(-1, 6, -3, 8); - let b = _mm_setr_pi16(5, -2, 7, -4); - let r = _mm_setr_pi16(-1, -2, -3, -4); - - assert_eq_m64(r, _mm_min_pi16(a, b)); - assert_eq_m64(r, _m_pminsw(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_min_pu8() { - let a = _mm_setr_pi8(2, 6, 3, 8, 2, 6, 3, 8); - let b = _mm_setr_pi8(5, 2, 7, 4, 5, 2, 7, 4); - let r = _mm_setr_pi8(2, 2, 3, 4, 2, 2, 3, 4); - - assert_eq_m64(r, _mm_min_pu8(a, b)); - assert_eq_m64(r, _m_pminub(a, b)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_mulhi_pu16() { - let (a, b) = (_mm_set1_pi16(1000), _mm_set1_pi16(1001)); - let r = _mm_mulhi_pu16(a, b); - assert_eq_m64(r, _mm_set1_pi16(15)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_mullo_pi16() { - let (a, b) = (_mm_set1_pi16(1000), _mm_set1_pi16(1001)); - let r = _mm_mullo_pi16(a, b); - assert_eq_m64(r, _mm_set1_pi16(17960)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_m_pmulhuw() { - let (a, b) = (_mm_set1_pi16(1000), _mm_set1_pi16(1001)); - let r = _m_pmulhuw(a, b); - assert_eq_m64(r, _mm_set1_pi16(15)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_avg_pu8() { - let (a, b) = (_mm_set1_pi8(3), _mm_set1_pi8(9)); - let r = _mm_avg_pu8(a, b); - assert_eq_m64(r, _mm_set1_pi8(6)); - - let r = _m_pavgb(a, b); - assert_eq_m64(r, _mm_set1_pi8(6)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_avg_pu16() { - let (a, b) = (_mm_set1_pi16(3), _mm_set1_pi16(9)); - let r = _mm_avg_pu16(a, b); - assert_eq_m64(r, _mm_set1_pi16(6)); - - let r = _m_pavgw(a, b); - assert_eq_m64(r, _mm_set1_pi16(6)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_sad_pu8() { - #[rustfmt::skip] - let a = _mm_setr_pi8( - 255u8 as i8, 254u8 as i8, 253u8 as i8, 252u8 as i8, - 1, 2, 3, 4, - ); - let b = _mm_setr_pi8(0, 0, 0, 0, 2, 1, 2, 1); - let r = _mm_sad_pu8(a, b); - assert_eq_m64(r, _mm_setr_pi16(1020, 0, 0, 0)); - - let r = _m_psadbw(a, b); - assert_eq_m64(r, _mm_setr_pi16(1020, 0, 0, 0)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi32_ps() { - let a = _mm_setr_ps(0., 0., 3., 4.); - let b = _mm_setr_pi32(1, 2); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi32_ps(a, b); - assert_eq_m128(r, expected); - - let r = _mm_cvt_pi2ps(a, b); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi16_ps() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi16_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpu16_ps() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpu16_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi8_ps() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi8_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpu8_ps() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpu8_ps(a); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtpi32x2_ps() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(3, 4); - let expected = _mm_setr_ps(1., 2., 3., 4.); - let r = _mm_cvtpi32x2_ps(a, b); - assert_eq_m128(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_maskmove_si64() { - let a = _mm_set1_pi8(9); - let mask = _mm_setr_pi8(0, 0, 0x80u8 as i8, 0, 0, 0, 0, 0); - let mut r = _mm_set1_pi8(0); - _mm_maskmove_si64(a, mask, &mut r as *mut _ as *mut i8); - let e = _mm_setr_pi8(0, 0, 9, 0, 0, 0, 0, 0); - assert_eq_m64(r, e); - - let mut r = _mm_set1_pi8(0); - _m_maskmovq(a, mask, &mut r as *mut _ as *mut i8); - assert_eq_m64(r, e); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_extract_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let r = _mm_extract_pi16(a, 0); - assert_eq!(r, 1); - let r = _mm_extract_pi16(a, 1); - assert_eq!(r, 2); - - let r = _m_pextrw(a, 1); - assert_eq!(r, 2); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_insert_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let r = _mm_insert_pi16(a, 0, 0b0); - let expected = _mm_setr_pi16(0, 2, 3, 4); - assert_eq_m64(r, expected); - let r = _mm_insert_pi16(a, 0, 0b10); - let expected = _mm_setr_pi16(1, 2, 0, 4); - assert_eq_m64(r, expected); - - let r = _m_pinsrw(a, 0, 0b10); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_movemask_pi8() { - let a = _mm_setr_pi16(0b1000_0000, 0b0100_0000, 0b1000_0000, 0b0100_0000); - let r = _mm_movemask_pi8(a); - assert_eq!(r, 0b10001); - - let r = _m_pmovmskb(a); - assert_eq!(r, 0b10001); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_shuffle_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let r = _mm_shuffle_pi16(a, 0b00_01_01_11); - let expected = _mm_setr_pi16(4, 2, 2, 1); - assert_eq_m64(r, expected); - - let r = _m_pshufw(a, 0b00_01_01_11); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtps_pi32() { - let a = _mm_setr_ps(1.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi32(1, 2); - - assert_eq_m64(r, _mm_cvtps_pi32(a)); - assert_eq_m64(r, _mm_cvt_ps2pi(a)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvttps_pi32() { - let a = _mm_setr_ps(7.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi32(7, 2); - - assert_eq_m64(r, _mm_cvttps_pi32(a)); - assert_eq_m64(r, _mm_cvtt_ps2pi(a)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtps_pi16() { - let a = _mm_setr_ps(7.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi16(7, 2, 3, 4); - assert_eq_m64(r, _mm_cvtps_pi16(a)); - } - - #[simd_test(enable = "sse,mmx")] - unsafe fn test_mm_cvtps_pi8() { - let a = _mm_setr_ps(7.0, 2.0, 3.0, 4.0); - let r = _mm_setr_pi8(7, 2, 3, 4, 0, 0, 0, 0); - assert_eq_m64(r, _mm_cvtps_pi8(a)); - } } diff --git a/library/stdarch/crates/core_arch/src/x86/sse2.rs b/library/stdarch/crates/core_arch/src/x86/sse2.rs index 90a2cf7a70..b6c19cdef4 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse2.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse2.rs @@ -2958,113 +2958,6 @@ pub unsafe fn _mm_unpacklo_pd(a: __m128d, b: __m128d) -> __m128d { simd_shuffle2(a, b, [0, 2]) } -/// Adds two signed or unsigned 64-bit integer values, returning the -/// lower 64 bits of the sum. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(paddq))] -pub unsafe fn _mm_add_si64(a: __m64, b: __m64) -> __m64 { - paddq(a, b) -} - -/// Multiplies 32-bit unsigned integer values contained in the lower bits -/// of the two 64-bit integer vectors and returns the 64-bit unsigned -/// product. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(pmuludq))] -pub unsafe fn _mm_mul_su32(a: __m64, b: __m64) -> __m64 { - pmuludq2(a, b) -} - -/// Subtracts signed or unsigned 64-bit integer values and writes the -/// difference to the corresponding bits in the destination. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(psubq))] -pub unsafe fn _mm_sub_si64(a: __m64, b: __m64) -> __m64 { - psubq(a, b) -} - -/// Converts the two signed 32-bit integer elements of a 64-bit vector of -/// `[2 x i32]` into two double-precision floating-point values, returned in a -/// 128-bit vector of `[2 x double]`. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(cvtpi2pd))] -pub unsafe fn _mm_cvtpi32_pd(a: __m64) -> __m128d { - cvtpi2pd(a) -} - -/// Initializes both 64-bit values in a 128-bit vector of `[2 x i64]` with -/// the specified 64-bit integer values. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// no particular instruction to test -pub unsafe fn _mm_set_epi64(e1: __m64, e0: __m64) -> __m128i { - _mm_set_epi64x(transmute(e1), transmute(e0)) -} - -/// Initializes both values in a 128-bit vector of `[2 x i64]` with the -/// specified 64-bit value. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// no particular instruction to test -pub unsafe fn _mm_set1_epi64(a: __m64) -> __m128i { - _mm_set_epi64x(transmute(a), transmute(a)) -} - -/// Constructs a 128-bit integer vector, initialized in reverse order -/// with the specified 64-bit integral values. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// no particular instruction to test -pub unsafe fn _mm_setr_epi64(e1: __m64, e0: __m64) -> __m128i { - _mm_set_epi64x(transmute(e0), transmute(e1)) -} - -/// Returns the lower 64 bits of a 128-bit integer vector as a 64-bit -/// integer. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// #[cfg_attr(test, assert_instr(movdq2q))] // FIXME: llvm codegens wrong -// instr? -pub unsafe fn _mm_movepi64_pi64(a: __m128i) -> __m64 { - transmute(simd_extract::<_, i64>(a.as_i64x2(), 0)) -} - -/// Moves the 64-bit operand to a 128-bit integer vector, zeroing the -/// upper bits. -#[inline] -#[target_feature(enable = "sse2,mmx")] -// #[cfg_attr(test, assert_instr(movq2dq))] // FIXME: llvm codegens wrong -// instr? -pub unsafe fn _mm_movpi64_epi64(a: __m64) -> __m128i { - _mm_set_epi64x(0, transmute(a)) -} - -/// Converts the two double-precision floating-point elements of a -/// 128-bit vector of `[2 x double]` into two signed 32-bit integer values, -/// returned in a 64-bit vector of `[2 x i32]`. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(cvtpd2pi))] -pub unsafe fn _mm_cvtpd_pi32(a: __m128d) -> __m64 { - cvtpd2pi(a) -} - -/// Converts the two double-precision floating-point elements of a -/// 128-bit vector of `[2 x double]` into two signed 32-bit integer values, -/// returned in a 64-bit vector of `[2 x i32]`. -/// If the result of either conversion is inexact, the result is truncated -/// (rounded towards zero) regardless of the current MXCSR setting. -#[inline] -#[target_feature(enable = "sse2,mmx")] -#[cfg_attr(test, assert_instr(cvttpd2pi))] -pub unsafe fn _mm_cvttpd_pi32(a: __m128d) -> __m64 { - cvttpd2pi(a) -} - #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.sse2.pause"] @@ -3207,18 +3100,6 @@ extern "C" { fn storeudq(mem_addr: *mut i8, a: __m128i); #[link_name = "llvm.x86.sse2.storeu.pd"] fn storeupd(mem_addr: *mut i8, a: __m128d); - #[link_name = "llvm.x86.mmx.padd.q"] - fn paddq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.pmulu.dq"] - fn pmuludq2(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.mmx.psub.q"] - fn psubq(a: __m64, b: __m64) -> __m64; - #[link_name = "llvm.x86.sse.cvtpi2pd"] - fn cvtpi2pd(a: __m64) -> __m128d; - #[link_name = "llvm.x86.sse.cvtpd2pi"] - fn cvtpd2pi(a: __m128d) -> __m64; - #[link_name = "llvm.x86.sse.cvttpd2pi"] - fn cvttpd2pi(a: __m128d) -> __m64; } #[cfg(test)] @@ -5208,87 +5089,4 @@ mod tests { let r = _mm_castsi128_ps(a); assert_eq_m128(r, expected); } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_add_si64() { - let a = 1i64; - let b = 2i64; - let expected = 3i64; - let r = _mm_add_si64(transmute(a), transmute(b)); - assert_eq!(transmute::<__m64, i64>(r), expected); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_mul_su32() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(3, 4); - let expected = 3u64; - let r = _mm_mul_su32(a, b); - assert_eq_m64(r, transmute(expected)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_sub_si64() { - let a = 1i64; - let b = 2i64; - let expected = -1i64; - let r = _mm_sub_si64(transmute(a), transmute(b)); - assert_eq!(transmute::<__m64, i64>(r), expected); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_cvtpi32_pd() { - let a = _mm_setr_pi32(1, 2); - let expected = _mm_setr_pd(1., 2.); - let r = _mm_cvtpi32_pd(a); - assert_eq_m128d(r, expected); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_set_epi64() { - let r = _mm_set_epi64(transmute(1i64), transmute(2i64)); - assert_eq_m128i(r, _mm_setr_epi64x(2, 1)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_set1_epi64() { - let r = _mm_set1_epi64(transmute(1i64)); - assert_eq_m128i(r, _mm_setr_epi64x(1, 1)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_setr_epi64() { - let r = _mm_setr_epi64(transmute(1i64), transmute(2i64)); - assert_eq_m128i(r, _mm_setr_epi64x(1, 2)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_movepi64_pi64() { - let r = _mm_movepi64_pi64(_mm_setr_epi64x(5, 0)); - assert_eq_m64(r, _mm_setr_pi8(5, 0, 0, 0, 0, 0, 0, 0)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_movpi64_epi64() { - let r = _mm_movpi64_epi64(_mm_setr_pi8(5, 0, 0, 0, 0, 0, 0, 0)); - assert_eq_m128i(r, _mm_setr_epi64x(5, 0)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_cvtpd_pi32() { - let a = _mm_setr_pd(5., 0.); - let r = _mm_cvtpd_pi32(a); - assert_eq_m64(r, _mm_setr_pi32(5, 0)); - } - - #[simd_test(enable = "sse2,mmx")] - unsafe fn test_mm_cvttpd_pi32() { - let a = _mm_setr_pd(5., 0.); - let r = _mm_cvttpd_pi32(a); - assert_eq_m64(r, _mm_setr_pi32(5, 0)); - - let a = _mm_setr_pd(f64::NEG_INFINITY, f64::NAN); - let r = _mm_cvttpd_pi32(a); - assert_eq_m64(r, _mm_setr_pi32(i32::MIN, i32::MIN)); - } } diff --git a/library/stdarch/crates/core_arch/src/x86/sse42.rs b/library/stdarch/crates/core_arch/src/x86/sse42.rs index d4d8aa644e..cce05e864c 100644 --- a/library/stdarch/crates/core_arch/src/x86/sse42.rs +++ b/library/stdarch/crates/core_arch/src/x86/sse42.rs @@ -261,20 +261,6 @@ pub unsafe fn _mm_cmpistrm(a: __m128i, b: __m128i, imm8: i32) -> __m128i { /// # } /// ``` /// -/// [`_SIDD_UBYTE_OPS`]: constant._SIDD_UBYTE_OPS.html -/// [`_SIDD_UWORD_OPS`]: constant._SIDD_UWORD_OPS.html -/// [`_SIDD_SBYTE_OPS`]: constant._SIDD_SBYTE_OPS.html -/// [`_SIDD_SWORD_OPS`]: constant._SIDD_SWORD_OPS.html -/// [`_SIDD_CMP_EQUAL_ANY`]: constant._SIDD_CMP_EQUAL_ANY.html -/// [`_SIDD_CMP_RANGES`]: constant._SIDD_CMP_RANGES.html -/// [`_SIDD_CMP_EQUAL_EACH`]: constant._SIDD_CMP_EQUAL_EACH.html -/// [`_SIDD_CMP_EQUAL_ORDERED`]: constant._SIDD_CMP_EQUAL_ORDERED.html -/// [`_SIDD_POSITIVE_POLARITY`]: constant._SIDD_POSITIVE_POLARITY.html -/// [`_SIDD_NEGATIVE_POLARITY`]: constant._SIDD_NEGATIVE_POLARITY.html -/// [`_SIDD_LEAST_SIGNIFICANT`]: constant._SIDD_LEAST_SIGNIFICANT.html -/// [`_SIDD_MOST_SIGNIFICANT`]: constant._SIDD_MOST_SIGNIFICANT.html -/// [`_mm_cmpestri`]: fn._mm_cmpestri.html -/// /// [Intel's documentation](https://software.intel.com/sites/landingpage/IntrinsicsGuide/#text=_mm_cmpistri) #[inline] #[target_feature(enable = "sse4.2")] diff --git a/library/stdarch/crates/core_arch/src/x86/ssse3.rs b/library/stdarch/crates/core_arch/src/x86/ssse3.rs index 6a45603e44..669f51ce7b 100644 --- a/library/stdarch/crates/core_arch/src/x86/ssse3.rs +++ b/library/stdarch/crates/core_arch/src/x86/ssse3.rs @@ -299,169 +299,6 @@ pub unsafe fn _mm_sign_epi32(a: __m128i, b: __m128i) -> __m128i { transmute(psignd128(a.as_i32x4(), b.as_i32x4())) } -/// Computes the absolute value of packed 8-bit integers in `a` and -/// return the unsigned results. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pabsb))] -pub unsafe fn _mm_abs_pi8(a: __m64) -> __m64 { - pabsb(a) -} - -/// Computes the absolute value of packed 8-bit integers in `a`, and returns the -/// unsigned results. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pabsw))] -pub unsafe fn _mm_abs_pi16(a: __m64) -> __m64 { - pabsw(a) -} - -/// Computes the absolute value of packed 32-bit integers in `a`, and returns the -/// unsigned results. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pabsd))] -pub unsafe fn _mm_abs_pi32(a: __m64) -> __m64 { - pabsd(a) -} - -/// Shuffles packed 8-bit integers in `a` according to shuffle control mask in -/// the corresponding 8-bit element of `b`, and returns the results -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pshufb))] -pub unsafe fn _mm_shuffle_pi8(a: __m64, b: __m64) -> __m64 { - pshufb(a, b) -} - -/// Concatenates the two 64-bit integer vector operands, and right-shifts -/// the result by the number of bytes specified in the immediate operand. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(palignr, n = 15))] -#[rustc_args_required_const(2)] -pub unsafe fn _mm_alignr_pi8(a: __m64, b: __m64, n: i32) -> __m64 { - macro_rules! call { - ($imm8:expr) => { - palignrb(a, b, $imm8) - }; - } - constify_imm8!(n, call) -} - -/// Horizontally adds the adjacent pairs of values contained in 2 packed -/// 64-bit vectors of `[4 x i16]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phaddw))] -pub unsafe fn _mm_hadd_pi16(a: __m64, b: __m64) -> __m64 { - phaddw(a, b) -} - -/// Horizontally adds the adjacent pairs of values contained in 2 packed -/// 64-bit vectors of `[2 x i32]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phaddd))] -pub unsafe fn _mm_hadd_pi32(a: __m64, b: __m64) -> __m64 { - phaddd(a, b) -} - -/// Horizontally adds the adjacent pairs of values contained in 2 packed -/// 64-bit vectors of `[4 x i16]`. Positive sums greater than 7FFFh are -/// saturated to 7FFFh. Negative sums less than 8000h are saturated to 8000h. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phaddsw))] -pub unsafe fn _mm_hadds_pi16(a: __m64, b: __m64) -> __m64 { - phaddsw(a, b) -} - -/// Horizontally subtracts the adjacent pairs of values contained in 2 -/// packed 64-bit vectors of `[4 x i16]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phsubw))] -pub unsafe fn _mm_hsub_pi16(a: __m64, b: __m64) -> __m64 { - phsubw(a, b) -} - -/// Horizontally subtracts the adjacent pairs of values contained in 2 -/// packed 64-bit vectors of `[2 x i32]`. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phsubd))] -pub unsafe fn _mm_hsub_pi32(a: __m64, b: __m64) -> __m64 { - phsubd(a, b) -} - -/// Horizontally subtracts the adjacent pairs of values contained in 2 -/// packed 64-bit vectors of `[4 x i16]`. Positive differences greater than -/// 7FFFh are saturated to 7FFFh. Negative differences less than 8000h are -/// saturated to 8000h. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(phsubsw))] -pub unsafe fn _mm_hsubs_pi16(a: __m64, b: __m64) -> __m64 { - phsubsw(a, b) -} - -/// Multiplies corresponding pairs of packed 8-bit unsigned integer -/// values contained in the first source operand and packed 8-bit signed -/// integer values contained in the second source operand, adds pairs of -/// contiguous products with signed saturation, and writes the 16-bit sums to -/// the corresponding bits in the destination. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pmaddubsw))] -pub unsafe fn _mm_maddubs_pi16(a: __m64, b: __m64) -> __m64 { - pmaddubsw(a, b) -} - -/// Multiplies packed 16-bit signed integer values, truncates the 32-bit -/// products to the 18 most significant bits by right-shifting, rounds the -/// truncated value by adding 1, and writes bits `[16:1]` to the destination. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(pmulhrsw))] -pub unsafe fn _mm_mulhrs_pi16(a: __m64, b: __m64) -> __m64 { - pmulhrsw(a, b) -} - -/// Negates packed 8-bit integers in `a` when the corresponding signed 8-bit -/// integer in `b` is negative, and returns the results. -/// Element in result are zeroed out when the corresponding element in `b` is -/// zero. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(psignb))] -pub unsafe fn _mm_sign_pi8(a: __m64, b: __m64) -> __m64 { - psignb(a, b) -} - -/// Negates packed 16-bit integers in `a` when the corresponding signed 16-bit -/// integer in `b` is negative, and returns the results. -/// Element in result are zeroed out when the corresponding element in `b` is -/// zero. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(psignw))] -pub unsafe fn _mm_sign_pi16(a: __m64, b: __m64) -> __m64 { - psignw(a, b) -} - -/// Negates packed 32-bit integers in `a` when the corresponding signed 32-bit -/// integer in `b` is negative, and returns the results. -/// Element in result are zeroed out when the corresponding element in `b` is -/// zero. -#[inline] -#[target_feature(enable = "ssse3,mmx")] -#[cfg_attr(test, assert_instr(psignd))] -pub unsafe fn _mm_sign_pi32(a: __m64, b: __m64) -> __m64 { - psignd(a, b) -} - #[allow(improper_ctypes)] extern "C" { #[link_name = "llvm.x86.ssse3.pabs.b.128"] @@ -508,54 +345,6 @@ extern "C" { #[link_name = "llvm.x86.ssse3.psign.d.128"] fn psignd128(a: i32x4, b: i32x4) -> i32x4; - - #[link_name = "llvm.x86.ssse3.pabs.b"] - fn pabsb(a: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pabs.w"] - fn pabsw(a: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pabs.d"] - fn pabsd(a: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pshuf.b"] - fn pshufb(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.mmx.palignr.b"] - fn palignrb(a: __m64, b: __m64, n: u8) -> __m64; - - #[link_name = "llvm.x86.ssse3.phadd.w"] - fn phaddw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phadd.d"] - fn phaddd(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phadd.sw"] - fn phaddsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phsub.w"] - fn phsubw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phsub.d"] - fn phsubd(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.phsub.sw"] - fn phsubsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pmadd.ub.sw"] - fn pmaddubsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.pmul.hr.sw"] - fn pmulhrsw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.psign.b"] - fn psignb(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.psign.w"] - fn psignw(a: __m64, b: __m64) -> __m64; - - #[link_name = "llvm.x86.ssse3.psign.d"] - fn psignd(a: __m64, b: __m64) -> __m64; } #[cfg(test)] @@ -761,138 +550,4 @@ mod tests { let r = _mm_sign_epi32(a, b); assert_eq_m128i(r, expected); } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_abs_pi8() { - let r = _mm_abs_pi8(_mm_set1_pi8(-5)); - assert_eq_m64(r, _mm_set1_pi8(5)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_abs_pi16() { - let r = _mm_abs_pi16(_mm_set1_pi16(-5)); - assert_eq_m64(r, _mm_set1_pi16(5)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_abs_pi32() { - let r = _mm_abs_pi32(_mm_set1_pi32(-5)); - assert_eq_m64(r, _mm_set1_pi32(5)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_shuffle_pi8() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let b = _mm_setr_pi8(4, 128u8 as i8, 4, 3, 24, 12, 6, 19); - let expected = _mm_setr_pi8(5, 0, 5, 4, 1, 5, 7, 4); - let r = _mm_shuffle_pi8(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_alignr_pi8() { - let a = _mm_setr_pi32(0x89ABCDEF_u32 as i32, 0x01234567_u32 as i32); - let b = _mm_setr_pi32(0xBBAA9988_u32 as i32, 0xFFDDEECC_u32 as i32); - let r = _mm_alignr_pi8(a, b, 4); - assert_eq_m64(r, transmute(0x89abcdefffddeecc_u64)); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hadd_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 128, 4, 3); - let expected = _mm_setr_pi16(3, 7, 132, 7); - let r = _mm_hadd_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hadd_pi32() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(4, 128); - let expected = _mm_setr_pi32(3, 132); - let r = _mm_hadd_pi32(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hadds_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(32767, 1, -32768, -1); - let expected = _mm_setr_pi16(3, 7, 32767, -32768); - let r = _mm_hadds_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hsub_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 128, 4, 3); - let expected = _mm_setr_pi16(-1, -1, -124, 1); - let r = _mm_hsub_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hsub_pi32() { - let a = _mm_setr_pi32(1, 2); - let b = _mm_setr_pi32(4, 128); - let expected = _mm_setr_pi32(-1, -124); - let r = _mm_hsub_pi32(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_hsubs_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 128, 4, 3); - let expected = _mm_setr_pi16(-1, -1, -124, 1); - let r = _mm_hsubs_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_maddubs_pi16() { - let a = _mm_setr_pi8(1, 2, 3, 4, 5, 6, 7, 8); - let b = _mm_setr_pi8(4, 63, 4, 3, 24, 12, 6, 19); - let expected = _mm_setr_pi16(130, 24, 192, 194); - let r = _mm_maddubs_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_mulhrs_pi16() { - let a = _mm_setr_pi16(1, 2, 3, 4); - let b = _mm_setr_pi16(4, 32767, -1, -32768); - let expected = _mm_setr_pi16(0, 2, 0, -4); - let r = _mm_mulhrs_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_sign_pi8() { - let a = _mm_setr_pi8(1, 2, 3, 4, -5, -6, 7, 8); - let b = _mm_setr_pi8(4, 64, 0, 3, 1, -1, -2, 1); - let expected = _mm_setr_pi8(1, 2, 0, 4, -5, 6, -7, 8); - let r = _mm_sign_pi8(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_sign_pi16() { - let a = _mm_setr_pi16(-1, 2, 3, 4); - let b = _mm_setr_pi16(1, -1, 1, 0); - let expected = _mm_setr_pi16(-1, -2, 3, 0); - let r = _mm_sign_pi16(a, b); - assert_eq_m64(r, expected); - } - - #[simd_test(enable = "ssse3,mmx")] - unsafe fn test_mm_sign_pi32() { - let a = _mm_setr_pi32(-1, 2); - let b = _mm_setr_pi32(1, 0); - let expected = _mm_setr_pi32(-1, 0); - let r = _mm_sign_pi32(a, b); - assert_eq_m64(r, expected); - } } diff --git a/library/stdarch/crates/core_arch/src/x86/test.rs b/library/stdarch/crates/core_arch/src/x86/test.rs index b9c4537da5..a3ca0e0820 100644 --- a/library/stdarch/crates/core_arch/src/x86/test.rs +++ b/library/stdarch/crates/core_arch/src/x86/test.rs @@ -2,15 +2,6 @@ use crate::core_arch::x86::*; -#[target_feature(enable = "mmx")] -pub unsafe fn assert_eq_m64(a: __m64, b: __m64) { - union A { - a: __m64, - b: u64, - } - assert_eq!(A { a }.b, A { a: b }.b) -} - #[target_feature(enable = "sse2")] pub unsafe fn assert_eq_m128i(a: __m128i, b: __m128i) { union A { diff --git a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs index ce2970ee51..036cf36c74 100644 --- a/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs +++ b/library/stdarch/crates/core_arch/src/x86_64/avx512f.rs @@ -49,6 +49,2145 @@ mod tests { use crate::core_arch::x86::*; use crate::core_arch::x86_64::*; + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_abs_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let r = _mm512_abs_epi64(a); + let e = _mm512_setr_epi64(0, 1, 1, i64::MAX, i64::MAX.wrapping_add(1), 100, 100, 32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_abs_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let r = _mm512_mask_abs_epi64(a, 0, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_abs_epi64(a, 0b00001111, a); + let e = _mm512_setr_epi64(0, 1, 1, i64::MAX, i64::MIN, 100, -100, -32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_abs_epi64() { + #[rustfmt::skip] + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let r = _mm512_maskz_abs_epi64(0, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_abs_epi64(0b00001111, a); + let e = _mm512_setr_epi64(0, 1, 1, i64::MAX, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_abs_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let r = _mm512_abs_pd(a); + let e = _mm512_setr_pd(0., 1., 1., f64::MAX, f64::MAX, 100., 100., 32.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_abs_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let r = _mm512_mask_abs_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_abs_pd(a, 0b00001111, a); + let e = _mm512_setr_pd(0., 1., 1., f64::MAX, f64::MIN, 100., -100., -32.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_add_epi64(a, b); + let e = _mm512_setr_epi64(1, 2, 0, i64::MIN, i64::MIN + 1, 101, -99, -31); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_mask_add_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_add_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(1, 2, 0, i64::MIN, i64::MIN, 100, -100, -32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_epi64() { + #[rustfmt::skip] + let a = _mm512_setr_epi64( + 0, 1, -1, i64::MAX, + i64::MIN, 100, -100, -32 + ); + let b = _mm512_set1_epi64(1); + let r = _mm512_maskz_add_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_add_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(1, 2, 0, i64::MIN, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_add_pd(a, b); + let e = _mm512_setr_pd(1., 2., 0., f64::MAX, f64::MIN + 1., 101., -99., -31.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_mask_add_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_add_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(1., 2., 0., f64::MAX, f64::MIN, 100., -100., -32.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_maskz_add_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_add_pd(0b00001111, a, b); + let e = _mm512_setr_pd(1., 2., 0., f64::MAX, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_sub_epi64(a, b); + let e = _mm512_setr_epi64(-1, 0, -2, i64::MAX - 1, i64::MAX, 99, -101, -33); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_mask_sub_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_sub_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(-1, 0, -2, i64::MAX - 1, i64::MIN, 100, -100, -32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_epi64() { + let a = _mm512_setr_epi64(0, 1, -1, i64::MAX, i64::MIN, 100, -100, -32); + let b = _mm512_set1_epi64(1); + let r = _mm512_maskz_sub_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_sub_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(-1, 0, -2, i64::MAX - 1, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_sub_pd(a, b); + let e = _mm512_setr_pd(-1., 0., -2., f64::MAX - 1., f64::MIN, 99., -101., -33.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_mask_sub_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_sub_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(-1., 0., -2., f64::MAX - 1., f64::MIN, 100., -100., -32.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_pd() { + let a = _mm512_setr_pd(0., 1., -1., f64::MAX, f64::MIN, 100., -100., -32.); + let b = _mm512_set1_pd(1.); + let r = _mm512_maskz_sub_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sub_pd(0b00001111, a, b); + let e = _mm512_setr_pd(-1., 0., -2., f64::MAX - 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_epi32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mul_epi32(a, b); + let e = _mm512_set_epi64(15, 13, 11, 9, 7, 5, 3, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_epi32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mask_mul_epi32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mul_epi32(a, 0b00001111, a, b); + let e = _mm512_set_epi64( + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 7, + 5, + 3, + 1, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_epi32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_maskz_mul_epi32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mul_epi32(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 7, 5, 3, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_epu32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mul_epu32(a, b); + let e = _mm512_set_epi64(15, 13, 11, 9, 7, 5, 3, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_epu32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_mask_mul_epu32(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mul_epu32(a, 0b00001111, a, b); + let e = _mm512_set_epi64( + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 1 | 1 << 32, + 7, + 5, + 3, + 1, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_epu32() { + let a = _mm512_setr_epi32(1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1); + let b = _mm512_setr_epi32(1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16); + let r = _mm512_maskz_mul_epu32(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_mul_epu32(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 7, 5, 3, 1); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mullox_epi64() { + let a = _mm512_setr_epi64(0, 1, i64::MAX, i64::MIN, i64::MAX, 100, -100, -32); + let b = _mm512_set1_epi64(2); + let r = _mm512_mullox_epi64(a, b); + let e = _mm512_setr_epi64(0, 2, -2, 0, -2, 200, -200, -64); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mullox_epi64() { + let a = _mm512_setr_epi64(0, 1, i64::MAX, i64::MIN, i64::MAX, 100, -100, -32); + let b = _mm512_set1_epi64(2); + let r = _mm512_mask_mullox_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_mullox_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(0, 2, -2, 0, i64::MAX, 100, -100, -32); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_set1_pd(2.); + let r = _mm512_mul_pd(a, b); + let e = _mm512_setr_pd( + 0., + 2., + f64::INFINITY, + f64::NEG_INFINITY, + f64::INFINITY, + f64::NEG_INFINITY, + -200., + -64., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_set1_pd(2.); + let r = _mm512_mask_mul_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_mul_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd( + 0., + 2., + f64::INFINITY, + f64::NEG_INFINITY, + f64::MAX, + f64::MIN, + -100., + -32., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_set1_pd(2.); + let r = _mm512_maskz_mul_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_mul_pd(0b00001111, a, b); + let e = _mm512_setr_pd(0., 2., f64::INFINITY, f64::NEG_INFINITY, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_setr_pd(2., 2., 0., 0., 0., 0., 2., 2.); + let r = _mm512_div_pd(a, b); + let e = _mm512_setr_pd( + 0., + 0.5, + f64::INFINITY, + f64::NEG_INFINITY, + f64::INFINITY, + f64::NEG_INFINITY, + -50., + -16., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_setr_pd(2., 2., 0., 0., 0., 0., 2., 2.); + let r = _mm512_mask_div_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_div_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd( + 0., + 0.5, + f64::INFINITY, + f64::NEG_INFINITY, + f64::MAX, + f64::MIN, + -100., + -32., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_pd() { + let a = _mm512_setr_pd(0., 1., f64::MAX, f64::MIN, f64::MAX, f64::MIN, -100., -32.); + let b = _mm512_setr_pd(2., 2., 0., 0., 0., 0., 2., 2.); + let r = _mm512_maskz_div_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_div_pd(0b00001111, a, b); + let e = _mm512_setr_pd(0., 0.5, f64::INFINITY, f64::NEG_INFINITY, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epi64(a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_max_pd(a, b); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_max_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_max_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_max_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_max_pd(0b00001111, a, b); + let e = _mm512_setr_pd(7., 6., 5., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_max_epu64(a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_max_epu64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_max_epu64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 4, 5, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_max_epu64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_max_epu64(0b00001111, a, b); + let e = _mm512_setr_epi64(7, 6, 5, 4, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epi64(a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epi64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epi64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epi64(0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_min_pd(a, b); + let e = _mm512_setr_pd(0., 1., 2., 3., 3., 2., 1., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_min_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_min_pd(a, 0b00001111, a, b); + let e = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_min_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_min_pd(0b00001111, a, b); + let e = _mm512_setr_pd(0., 1., 2., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_min_epu64(a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 3, 2, 1, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_mask_min_epu64(a, 0, a, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_min_epu64(a, 0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_epu64() { + let a = _mm512_setr_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let b = _mm512_setr_epi64(7, 6, 5, 4, 3, 2, 1, 0); + let r = _mm512_maskz_min_epu64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_min_epu64(0b00001111, a, b); + let e = _mm512_setr_epi64(0, 1, 2, 3, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_pd() { + let a = _mm512_setr_pd(0., 1., 4., 9., 16., 25., 36., 49.); + let r = _mm512_sqrt_pd(a); + let e = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_pd() { + let a = _mm512_setr_pd(0., 1., 4., 9., 16., 25., 36., 49.); + let r = _mm512_mask_sqrt_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_sqrt_pd(a, 0b00001111, a); + let e = _mm512_setr_pd(0., 1., 2., 3., 16., 25., 36., 49.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_pd() { + let a = _mm512_setr_pd(0., 1., 4., 9., 16., 25., 36., 49.); + let r = _mm512_maskz_sqrt_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sqrt_pd(0b00001111, a); + let e = _mm512_setr_pd(0., 1., 2., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmadd_pd(a, b, c); + let e = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmadd_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmadd_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(1., 2., 3., 4., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmadd_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmadd_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(1., 2., 3., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmadd_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmadd_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(1., 2., 3., 4., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmsub_pd(a, b, c); + let e = _mm512_setr_pd(-1., 0., 1., 2., 3., 4., 5., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmsub_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsub_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(-1., 0., 1., 2., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmsub_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsub_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(-1., 0., 1., 2., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmsub_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsub_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(-1., 0., 1., 2., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmaddsub_pd(a, b, c); + let e = _mm512_setr_pd(-1., 2., 1., 4., 3., 6., 5., 8.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmaddsub_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmaddsub_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(-1., 2., 1., 4., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmaddsub_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmaddsub_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(-1., 2., 1., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmaddsub_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmaddsub_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(-1., 2., 1., 4., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fmsubadd_pd(a, b, c); + let e = _mm512_setr_pd(1., 0., 3., 2., 5., 4., 7., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fmsubadd_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsubadd_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(1., 0., 3., 2., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fmsubadd_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsubadd_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(1., 0., 3., 2., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fmsubadd_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsubadd_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(1., 0., 3., 2., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fnmadd_pd(a, b, c); + let e = _mm512_setr_pd(1., 0., -1., -2., -3., -4., -5., -6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fnmadd_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmadd_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(1., 0., -1., -2., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fnmadd_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmadd_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(1., 0., -1., -2., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fnmadd_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmadd_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(1., 0., -1., -2., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_fnmsub_pd(a, b, c); + let e = _mm512_setr_pd(-1., -2., -3., -4., -5., -6., -7., -8.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_mask_fnmsub_pd(a, 0, b, c); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmsub_pd(a, 0b00001111, b, c); + let e = _mm512_setr_pd(-1., -2., -3., -4., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let r = _mm512_maskz_fnmsub_pd(0, a, b, c); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmsub_pd(0b00001111, a, b, c); + let e = _mm512_setr_pd(-1., -2., -3., -4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_pd() { + let a = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + let b = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let c = _mm512_setr_pd(1., 1., 1., 1., 2., 2., 2., 2.); + let r = _mm512_mask3_fnmsub_pd(a, b, c, 0); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmsub_pd(a, b, c, 0b00001111); + let e = _mm512_setr_pd(-1., -2., -3., -4., 2., 2., 2., 2.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rcp14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_rcp14_pd(a); + let e = _mm512_set1_pd(0.3333320617675781); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rcp14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_rcp14_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_rcp14_pd(a, 0b11110000, a); + let e = _mm512_setr_pd( + 3., + 3., + 3., + 3., + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rcp14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_rcp14_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_rcp14_pd(0b11110000, a); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + 0.3333320617675781, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rsqrt14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_rsqrt14_pd(a); + let e = _mm512_set1_pd(0.5773391723632813); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rsqrt14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_rsqrt14_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_rsqrt14_pd(a, 0b11110000, a); + let e = _mm512_setr_pd( + 3., + 3., + 3., + 3., + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rsqrt14_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_rsqrt14_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_rsqrt14_pd(0b11110000, a); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + 0.5773391723632813, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_getexp_pd(a); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_getexp_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_getexp_pd(a, 0b11110000, a); + let e = _mm512_setr_pd(3., 3., 3., 3., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_getexp_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getexp_pd(0b11110000, a); + let e = _mm512_setr_pd(0., 0., 0., 0., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_getmant_pd(a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_set1_pd(1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_mask_getmant_pd(a, 0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512d(r, a); + let r = _mm512_mask_getmant_pd(a, 0b11110000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_setr_pd(10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_maskz_getmant_pd(0, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getmant_pd(0b11110000, a, _MM_MANT_NORM_1_2, _MM_MANT_SIGN_SRC); + let e = _mm512_setr_pd(0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtps_pd(a); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm512_set1_pd(0.); + let r = _mm512_mask_cvtps_pd(src, 0, a); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvtps_pd(src, 0b00001111, a); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtps_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_cvtps_pd(0b00001111, a); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtt_roundpd_epi32(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvtt_roundpd_epi32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtt_roundpd_epi32(src, 0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtt_roundpd_epi32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtt_roundpd_epi32(0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvtt_roundpd_epu32(a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvtt_roundpd_epu32(src, 0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvtt_roundpd_epu32(src, 0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvtt_roundpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvtt_roundpd_epu32(0, a, _MM_FROUND_NO_EXC); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvtt_roundpd_epu32(0b00001111, a, _MM_FROUND_NO_EXC); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvttpd_epi32(a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 4, -5, 6, -7); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvttpd_epi32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvttpd_epi32(src, 0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttpd_epi32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvttpd_epi32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvttpd_epi32(0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -3, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvttpd_epu32(a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 4, -1, 6, -1); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm256_set1_epi32(0); + let r = _mm512_mask_cvttpd_epu32(src, 0, a); + assert_eq_m256i(r, src); + let r = _mm512_mask_cvttpd_epu32(src, 0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvttpd_epu32() { + let a = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvttpd_epu32(0, a); + assert_eq_m256i(r, _mm256_setzero_si256()); + let r = _mm512_maskz_cvttpd_epu32(0b00001111, a); + let e = _mm256_setr_epi32(0, -1, 2, -1, 0, 0, 0, 0); + assert_eq_m256i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + let r = _mm512_add_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_mask_add_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_add_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_add_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(-1.); + let r = _mm512_maskz_add_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_add_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(0., 0., 0., 0., 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + let r = _mm512_sub_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(7., 8.5, 9., 10.5, 11., 12.5, 13., -0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_mask_sub_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_sub_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(8., 9.5, 10., 11.5, 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sub_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.000000000000000007); + let b = _mm512_set1_pd(1.); + let r = _mm512_maskz_sub_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sub_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(0., 0., 0., 0., 11., 12.5, 13., -1.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mul_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.); + let b = _mm512_set1_pd(0.1); + let r = _mm512_mul_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd( + 0.8, + 0.9500000000000001, + 1., + 1.1500000000000001, + 1.2000000000000002, + 1.35, + 1.4000000000000001, + 0., + ); + assert_eq_m512d(r, e); + let r = _mm512_mul_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(0.8, 0.95, 1.0, 1.15, 1.2, 1.3499999999999999, 1.4, 0.0); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_mul_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.); + let b = _mm512_set1_pd(0.1); + let r = _mm512_mask_mul_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_mul_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 8., + 9.5, + 10., + 11.5, + 1.2000000000000002, + 1.35, + 1.4000000000000001, + 0., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_mul_round_pd() { + let a = _mm512_setr_pd(8., 9.5, 10., 11.5, 12., 13.5, 14., 0.); + let b = _mm512_set1_pd(0.1); + let r = _mm512_maskz_mul_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_mul_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 1.2000000000000002, + 1.35, + 1.4000000000000001, + 0., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_div_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_div_round_pd(a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.3333333333333333); + assert_eq_m512d(r, e); + let r = _mm512_div_round_pd(a, b, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.33333333333333334); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_div_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_mask_div_round_pd(a, 0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_div_round_pd( + a, + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + 1., + 1., + 1., + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_div_round_pd() { + let a = _mm512_set1_pd(1.); + let b = _mm512_set1_pd(3.); + let r = _mm512_maskz_div_round_pd(0, a, b, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_div_round_pd( + 0b11110000, + a, + b, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + 0.3333333333333333, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sqrt_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_sqrt_round_pd(a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.7320508075688772); + assert_eq_m512d(r, e); + let r = _mm512_sqrt_round_pd(a, _MM_FROUND_TO_POS_INF | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.7320508075688774); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sqrt_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_sqrt_round_pd(a, 0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_sqrt_round_pd( + a, + 0b11110000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 3., + 3., + 3., + 3., + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sqrt_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_sqrt_round_pd(0, a, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_sqrt_round_pd( + 0b11110000, + a, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 0., + 0., + 0., + 0., + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + 1.7320508075688772, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fmadd_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-1.); + assert_eq_m512d(r, e); + let r = _mm512_fmadd_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask_fmadd_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmadd_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + -1., + -1., + -1., + -1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_maskz_fmadd_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmadd_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask3_fmadd_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmadd_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = _mm512_fmsub_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-1.); + assert_eq_m512d(r, e); + let r = _mm512_fmsub_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(-0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask_fmsub_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsub_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + -1., + -1., + -1., + -1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_maskz_fmsub_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsub_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask3_fmsub_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsub_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., -1., -1., -1., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fmaddsub_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(1., -1., 1., -1., 1., -1., 1., -1.); + assert_eq_m512d(r, e); + let r = _mm512_fmaddsub_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd( + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask_fmaddsub_round_pd( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmaddsub_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + -1., + 1., + -1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_maskz_fmaddsub_round_pd( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmaddsub_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., -1., 1., -1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmaddsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask3_fmaddsub_round_pd( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmaddsub_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., -1., 1., -1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fmsubadd_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd(-1., 1., -1., 1., -1., 1., -1., 1.); + assert_eq_m512d(r, e); + let r = _mm512_fmsubadd_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_setr_pd( + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + -0.9999999999999999, + 1., + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask_fmsubadd_round_pd( + a, + 0, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_fmsubadd_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + -1., + 1., + -1., + 1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_maskz_fmsubadd_round_pd( + 0, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fmsubadd_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., 1., -1., 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fmsubadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_mask3_fmsubadd_round_pd( + a, + b, + c, + 0, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fmsubadd_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(-1., 1., -1., 1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = _mm512_fnmadd_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + let r = _mm512_fnmadd_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask_fnmadd_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmadd_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + 1., + 1., + 1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_maskz_fnmadd_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmadd_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmadd_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(1.); + let r = + _mm512_mask3_fnmadd_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmadd_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = _mm512_fnmsub_round_pd(a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + let r = _mm512_fnmsub_round_pd(a, b, c, _MM_FROUND_TO_ZERO | _MM_FROUND_NO_EXC); + let e = _mm512_set1_pd(0.9999999999999999); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask_fnmsub_round_pd(a, 0, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, a); + let r = _mm512_mask_fnmsub_round_pd( + a, + 0b00001111, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd( + 1., + 1., + 1., + 1., + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + 0.000000000000000007, + ); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_maskz_fnmsub_round_pd(0, a, b, c, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_fnmsub_round_pd( + 0b00001111, + a, + b, + c, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask3_fnmsub_round_pd() { + let a = _mm512_set1_pd(0.000000000000000007); + let b = _mm512_set1_pd(1.); + let c = _mm512_set1_pd(-1.); + let r = + _mm512_mask3_fnmsub_round_pd(a, b, c, 0, _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC); + assert_eq_m512d(r, c); + let r = _mm512_mask3_fnmsub_round_pd( + a, + b, + c, + 0b00001111, + _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC, + ); + let e = _mm512_setr_pd(1., 1., 1., 1., -1., -1., -1., -1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_max_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_max_round_pd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_max_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_max_round_pd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, a); + let r = _mm512_mask_max_round_pd(a, 0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(7., 6., 5., 4., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_max_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_max_round_pd(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_max_round_pd(0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(7., 6., 5., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_min_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_min_round_pd(a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 1., 2., 3., 3., 2., 1., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_min_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_mask_min_round_pd(a, 0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, a); + let r = _mm512_mask_min_round_pd(a, 0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_min_round_pd() { + let a = _mm512_setr_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_setr_pd(7., 6., 5., 4., 3., 2., 1., 0.); + let r = _mm512_maskz_min_round_pd(0, a, b, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_min_round_pd(0b00001111, a, b, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 1., 2., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getexp_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_getexp_round_pd(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_set1_pd(1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getexp_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_mask_getexp_round_pd(a, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, a); + let r = _mm512_mask_getexp_round_pd(a, 0b11110000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(3., 3., 3., 3., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getexp_round_pd() { + let a = _mm512_set1_pd(3.); + let r = _mm512_maskz_getexp_round_pd(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getexp_round_pd(0b11110000, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., 0., 0., 0., 1., 1., 1., 1.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_getmant_round_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_getmant_round_pd( + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_set1_pd(1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_getmant_round_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_mask_getmant_round_pd( + a, + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_getmant_round_pd( + a, + 0b11110000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_pd(10., 10., 10., 10., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_getmant_round_pd() { + let a = _mm512_set1_pd(10.); + let r = _mm512_maskz_getmant_round_pd( + 0, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_getmant_round_pd( + 0b11110000, + a, + _MM_MANT_NORM_1_2, + _MM_MANT_SIGN_SRC, + _MM_FROUND_CUR_DIRECTION, + ); + let e = _mm512_setr_pd(0., 0., 0., 0., 1.25, 1.25, 1.25, 1.25); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_cvt_roundps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_cvt_roundps_pd(a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_cvt_roundps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let src = _mm512_set1_pd(0.); + let r = _mm512_mask_cvt_roundps_pd(src, 0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, src); + let r = _mm512_mask_cvt_roundps_pd(src, 0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_cvt_roundps_pd() { + let a = _mm256_setr_ps(0., -1.5, 2., -3.5, 4., -5.5, 6., -7.5); + let r = _mm512_maskz_cvt_roundps_pd(0, a, _MM_FROUND_CUR_DIRECTION); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_cvt_roundps_pd(0b00001111, a, _MM_FROUND_CUR_DIRECTION); + let e = _mm512_setr_pd(0., -1.5, 2., -3.5, 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + #[simd_test(enable = "avx512f")] unsafe fn test_mm512_setzero_pd() { assert_eq_m512d(_mm512_setzero_pd(), _mm512_set1_pd(0.)); @@ -854,4 +2993,1447 @@ mod tests { } assert_eq!(&arr[..], &expected[..],); } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rol_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_rol_epi64(a, 1); + let e = _mm512_set_epi64( + 1 << 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rol_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_rol_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rol_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 1 << 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rol_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let r = _mm512_maskz_rol_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rol_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 33, 1 << 33, 1 << 33, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_ror_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_ror_epi64(a, 1); + let e = _mm512_set_epi64( + 1 << 63, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_ror_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_ror_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_ror_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 1 << 63, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_ror_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let r = _mm512_maskz_ror_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_ror_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 31, 1 << 31, 1 << 31, 1 << 63); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_slli_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_slli_epi64(a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_slli_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_slli_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_slli_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_slli_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let r = _mm512_maskz_slli_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_slli_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 33, 1 << 33, 1 << 33, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srli_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_srli_epi64(a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srli_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let r = _mm512_mask_srli_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srli_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srli_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let r = _mm512_maskz_srli_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srli_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 31, 1 << 31, 1 << 31, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rolv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_rolv_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 34, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rolv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_rolv_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rolv_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 34, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rolv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 62, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 2); + let r = _mm512_maskz_rolv_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rolv_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 36, 1 << 37, 1 << 38, 1 << 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_rorv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_rorv_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_rorv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_rorv_epi64(a, 0, a, b); + assert_eq_m512i(r, a); + + let r = _mm512_mask_rorv_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_rorv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let b = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 2); + let r = _mm512_maskz_rorv_epi64(0, a, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_rorv_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 28, 1 << 27, 1 << 26, 1 << 62); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sllv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 2, 2, 3, 4, 5, 6, 7); + let r = _mm512_sllv_epi64(a, count); + let e = _mm512_set_epi64( + 1 << 32, + 0, + 1 << 34, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sllv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_sllv_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sllv_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 1 << 32, + 1 << 33, + 0, + 1 << 35, + 1 << 36, + 1 << 37, + 1 << 38, + 1 << 39, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sllv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 1); + let r = _mm512_maskz_sllv_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sllv_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 36, 1 << 37, 1 << 38, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srlv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_srlv_epi64(a, count); + let e = _mm512_set_epi64( + 1 << 32, + 0, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srlv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_srlv_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srlv_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 1 << 32, + 0, + 1 << 30, + 1 << 29, + 1 << 28, + 1 << 27, + 1 << 26, + 1 << 25, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srlv_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let count = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_srlv_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srlv_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 28, 1 << 27, 1 << 26, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sll_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_sll_epi64(a, count); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + + let count = _mm_set_epi64x(1, 0); + let r = _mm512_sll_epi64(a, count); + assert_eq_m512i(r, a); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sll_epi64() { + let a = _mm512_set_epi64( + 1 << 63, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_mask_sll_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sll_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 0, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + 1 << 33, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sll_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 63, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_maskz_sll_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sll_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 33, 1 << 33, 1 << 33, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srl_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_srl_epi64(a, count); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srl_epi64() { + let a = _mm512_set_epi64( + 1 << 0, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_mask_srl_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srl_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64( + 0, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + 1 << 31, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srl_epi64() { + let a = _mm512_set_epi64( + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 32, + 1 << 0, + ); + let count = _mm_set_epi64x(0, 1); + let r = _mm512_maskz_srl_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srl_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 1 << 31, 1 << 31, 1 << 31, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_sra_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm_set_epi64x(0, 2); + let r = _mm512_sra_epi64(a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_sra_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm_set_epi64x(0, 2); + let r = _mm512_mask_sra_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_sra_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_sra_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm_set_epi64x(0, 2); + let r = _mm512_maskz_sra_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_sra_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 3, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srav_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm512_set_epi64(2, 2, 0, 0, 0, 0, 2, 1); + let r = _mm512_srav_epi64(a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srav_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm512_set_epi64(2, 2, 0, 0, 0, 0, 2, 1); + let r = _mm512_mask_srav_epi64(a, 0, a, count); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srav_epi64(a, 0b11111111, a, count); + let e = _mm512_set_epi64(0, -2, 0, 0, 0, 0, 3, -8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srav_epi64() { + let a = _mm512_set_epi64(1, -8, 0, 0, 0, 0, 15, -16); + let count = _mm512_set_epi64(2, 2, 0, 0, 0, 0, 2, 1); + let r = _mm512_maskz_srav_epi64(0, a, count); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srav_epi64(0b00001111, a, count); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 3, -8); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_srai_epi64() { + let a = _mm512_set_epi64(1, -4, 15, 0, 0, 0, 0, -16); + let r = _mm512_srai_epi64(a, 2); + let e = _mm512_set_epi64(0, -1, 3, 0, 0, 0, 0, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_srai_epi64() { + let a = _mm512_set_epi64(1, -4, 15, 0, 0, 0, 0, -16); + let r = _mm512_mask_srai_epi64(a, 0, a, 2); + assert_eq_m512i(r, a); + + let r = _mm512_mask_srai_epi64(a, 0b11111111, a, 2); + let e = _mm512_set_epi64(0, -1, 3, 0, 0, 0, 0, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_srai_epi64() { + let a = _mm512_set_epi64(1, -4, 15, 0, 0, 0, 0, -16); + let r = _mm512_maskz_srai_epi64(0, a, 2); + assert_eq_m512i(r, _mm512_setzero_si512()); + + let r = _mm512_maskz_srai_epi64(0b00001111, a, 2); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, -4); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permute_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_permute_pd(a, 1); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permute_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_permute_pd(a, 0, a, 1); + assert_eq_m512d(r, a); + let r = _mm512_mask_permute_pd(a, 0b11111111, a, 1); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permute_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_permute_pd(0, a, 1); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permute_pd(0b00001111, a, 1); + let e = _mm512_set_pd(0., 0., 0., 0., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_permutex_epi64(a, 1); + let e = _mm512_set_epi64(6, 6, 6, 6, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_permutex_epi64(a, 0, a, 1); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex_epi64(a, 0b11111111, a, 1); + let e = _mm512_set_epi64(6, 6, 6, 6, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_permutex_epi64(0, a, 1); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex_epi64(0b00001111, a, 1); + let e = _mm512_set_epi64(0, 0, 0, 0, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_permutex_pd(a, 1); + let e = _mm512_set_pd(6., 6., 6., 6., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_permutex_pd(a, 0, a, 1); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutex_pd(a, 0b11111111, a, 1); + let e = _mm512_set_pd(6., 6., 6., 6., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_permutex_pd(0, a, 1); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutex_pd(0b00001111, a, 1); + let e = _mm512_set_pd(0., 0., 0., 0., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutevar_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_set1_epi64(1); + let r = _mm512_permutevar_pd(a, b); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutevar_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_set1_epi64(1); + let r = _mm512_mask_permutevar_pd(a, 0, a, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutevar_pd(a, 0b11111111, a, b); + let e = _mm512_set_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutevar_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let b = _mm512_set1_epi64(1); + let r = _mm512_maskz_permutevar_pd(0, a, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutevar_pd(0b00001111, a, b); + let e = _mm512_set_pd(0., 0., 0., 0., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_epi64() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_permutexvar_epi64(idx, a); + let e = _mm512_set1_epi64(6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_epi64() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_mask_permutexvar_epi64(a, 0, idx, a); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutexvar_epi64(a, 0b11111111, idx, a); + let e = _mm512_set1_epi64(6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_epi64() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let r = _mm512_maskz_permutexvar_epi64(0, idx, a); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutexvar_epi64(0b00001111, idx, a); + let e = _mm512_set_epi64(0, 0, 0, 0, 6, 6, 6, 6); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutexvar_pd() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_permutexvar_pd(idx, a); + let e = _mm512_set1_pd(6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutexvar_pd() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_mask_permutexvar_pd(a, 0, idx, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutexvar_pd(a, 0b11111111, idx, a); + let e = _mm512_set1_pd(6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutexvar_pd() { + let idx = _mm512_set1_epi64(1); + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let r = _mm512_maskz_permutexvar_pd(0, idx, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutexvar_pd(0b00001111, idx, a); + let e = _mm512_set_pd(0., 0., 0., 0., 6., 6., 6., 6.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_permutex2var_epi64(a, idx, b); + let e = _mm512_set_epi64(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_mask_permutex2var_epi64(a, 0, idx, b); + assert_eq_m512i(r, a); + let r = _mm512_mask_permutex2var_epi64(a, 0b11111111, idx, b); + let e = _mm512_set_epi64(6, 100, 5, 100, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_maskz_permutex2var_epi64(0, a, idx, b); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_permutex2var_epi64(0b00001111, a, idx, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_epi64() { + let a = _mm512_set_epi64(0, 1, 2, 3, 4, 5, 6, 7); + let idx = _mm512_set_epi64(1000, 1 << 3, 2000, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_epi64(100); + let r = _mm512_mask2_permutex2var_epi64(a, idx, 0, b); + assert_eq_m512i(r, idx); + let r = _mm512_mask2_permutex2var_epi64(a, idx, 0b00001111, b); + let e = _mm512_set_epi64(1000, 1 << 3, 2000, 1 << 3, 4, 100, 3, 100); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_permutex2var_pd(a, idx, b); + let e = _mm512_set_pd(6., 100., 5., 100., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_mask_permutex2var_pd(a, 0, idx, b); + assert_eq_m512d(r, a); + let r = _mm512_mask_permutex2var_pd(a, 0b11111111, idx, b); + let e = _mm512_set_pd(6., 100., 5., 100., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_maskz_permutex2var_pd(0, a, idx, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_permutex2var_pd(0b00001111, a, idx, b); + let e = _mm512_set_pd(0., 0., 0., 0., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask2_permutex2var_pd() { + let a = _mm512_set_pd(0., 1., 2., 3., 4., 5., 6., 7.); + let idx = _mm512_set_epi64(1, 1 << 3, 2, 1 << 3, 3, 1 << 3, 4, 1 << 3); + let b = _mm512_set1_pd(100.); + let r = _mm512_mask2_permutex2var_pd(a, idx, 0, b); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_mask2_permutex2var_pd(a, idx, 0b00001111, b); + let e = _mm512_set_pd(0., 0., 0., 0., 4., 100., 3., 100.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_pd() { + let a = _mm512_setr_pd(1., 4., 5., 8., 1., 4., 5., 8.); + let b = _mm512_setr_pd(2., 3., 6., 7., 2., 3., 6., 7.); + let r = _mm512_shuffle_pd( + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + let e = _mm512_setr_pd(4., 3., 8., 7., 4., 3., 8., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_pd() { + let a = _mm512_setr_pd(1., 4., 5., 8., 1., 4., 5., 8.); + let b = _mm512_setr_pd(2., 3., 6., 7., 2., 3., 6., 7.); + let r = _mm512_mask_shuffle_pd( + a, + 0, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + assert_eq_m512d(r, a); + let r = _mm512_mask_shuffle_pd( + a, + 0b11111111, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + let e = _mm512_setr_pd(4., 3., 8., 7., 4., 3., 8., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_pd() { + let a = _mm512_setr_pd(1., 4., 5., 8., 1., 4., 5., 8.); + let b = _mm512_setr_pd(2., 3., 6., 7., 2., 3., 6., 7.); + let r = _mm512_maskz_shuffle_pd( + 0, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_shuffle_pd( + 0b00001111, + a, + b, + 1 << 0 | 1 << 1 | 1 << 2 | 1 << 3 | 1 << 4 | 1 << 5 | 1 << 6 | 1 << 7, + ); + let e = _mm512_setr_pd(4., 3., 8., 7., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_i64x2() { + let a = _mm512_setr_epi64(1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi64(2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_shuffle_i64x2(a, b, 0b00000000); + let e = _mm512_setr_epi64(1, 4, 1, 4, 2, 3, 2, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_i64x2() { + let a = _mm512_setr_epi64(1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi64(2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_mask_shuffle_i64x2(a, 0, a, b, 0b00000000); + assert_eq_m512i(r, a); + let r = _mm512_mask_shuffle_i64x2(a, 0b11111111, a, b, 0b00000000); + let e = _mm512_setr_epi64(1, 4, 1, 4, 2, 3, 2, 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_i64x2() { + let a = _mm512_setr_epi64(1, 4, 5, 8, 9, 12, 13, 16); + let b = _mm512_setr_epi64(2, 3, 6, 7, 10, 11, 14, 15); + let r = _mm512_maskz_shuffle_i64x2(0, a, b, 0b00000000); + assert_eq_m512i(r, _mm512_setzero_si512()); + let r = _mm512_maskz_shuffle_i64x2(0b00001111, a, b, 0b00000000); + let e = _mm512_setr_epi64(1, 4, 1, 4, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_shuffle_f64x2() { + let a = _mm512_setr_pd(1., 4., 5., 8., 9., 12., 13., 16.); + let b = _mm512_setr_pd(2., 3., 6., 7., 10., 11., 14., 15.); + let r = _mm512_shuffle_f64x2(a, b, 0b00000000); + let e = _mm512_setr_pd(1., 4., 1., 4., 2., 3., 2., 3.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_shuffle_f64x2() { + let a = _mm512_setr_pd(1., 4., 5., 8., 9., 12., 13., 16.); + let b = _mm512_setr_pd(2., 3., 6., 7., 10., 11., 14., 15.); + let r = _mm512_mask_shuffle_f64x2(a, 0, a, b, 0b00000000); + assert_eq_m512d(r, a); + let r = _mm512_mask_shuffle_f64x2(a, 0b11111111, a, b, 0b00000000); + let e = _mm512_setr_pd(1., 4., 1., 4., 2., 3., 2., 3.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_shuffle_f64x2() { + let a = _mm512_setr_pd(1., 4., 5., 8., 9., 12., 13., 16.); + let b = _mm512_setr_pd(2., 3., 6., 7., 10., 11., 14., 15.); + let r = _mm512_maskz_shuffle_f64x2(0, a, b, 0b00000000); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_shuffle_f64x2(0b00001111, a, b, 0b00000000); + let e = _mm512_setr_pd(1., 4., 1., 4., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_movedup_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_movedup_pd(a); + let e = _mm512_setr_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_movedup_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_mask_movedup_pd(a, 0, a); + assert_eq_m512d(r, a); + let r = _mm512_mask_movedup_pd(a, 0b11111111, a); + let e = _mm512_setr_pd(1., 1., 3., 3., 5., 5., 7., 7.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_movedup_pd() { + let a = _mm512_setr_pd(1., 2., 3., 4., 5., 6., 7., 8.); + let r = _mm512_maskz_movedup_pd(0, a); + assert_eq_m512d(r, _mm512_setzero_pd()); + let r = _mm512_maskz_movedup_pd(0b00001111, a); + let e = _mm512_setr_pd(1., 1., 3., 3., 0., 0., 0., 0.); + assert_eq_m512d(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_and_epi64(a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_and_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_mask_and_epi64(a, 0, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + + let r = _mm512_mask_and_epi64(a, 0b01111111, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_and_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_maskz_and_epi64(0, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + + let r = _mm512_maskz_and_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_and_si512() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_and_epi64(a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_or_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 0 | 1 << 13 | 1 << 15, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 2 | 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_or_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_mask_or_epi64(a, 0, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + + let r = _mm512_mask_or_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64( + 1 << 0 | 1 << 13 | 1 << 15, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 2 | 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_or_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_maskz_or_epi64(0, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + + let r = _mm512_maskz_or_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_or_si512() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_or_epi64(a, b); + let e = _mm512_set_epi64( + 1 << 0 | 1 << 13 | 1 << 15, + 0, + 0, + 0, + 0, + 0, + 0, + 1 << 1 | 1 << 2 | 1 << 3, + ); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_xor_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_xor_epi64(a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 13 | 1 << 15, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_mask_xor_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_mask_xor_epi64(a, 0, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + assert_eq_m512i(r, e); + + let r = _mm512_mask_xor_epi64(a, 0b11111111, a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 13 | 1 << 15, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_maskz_xor_epi64() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_maskz_xor_epi64(0, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + + let r = _mm512_maskz_xor_epi64(0b00001111, a, b); + let e = _mm512_set_epi64(0, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } + + #[simd_test(enable = "avx512f")] + unsafe fn test_mm512_xor_si512() { + let a = _mm512_set_epi64(1 << 0 | 1 << 15, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let b = _mm512_set_epi64(1 << 13, 0, 0, 0, 0, 0, 0, 1 << 1 | 1 << 2 | 1 << 3); + let r = _mm512_xor_epi64(a, b); + let e = _mm512_set_epi64(1 << 0 | 1 << 13 | 1 << 15, 0, 0, 0, 0, 0, 0, 0); + assert_eq_m512i(r, e); + } } diff --git a/library/stdarch/crates/simd-test-macro/src/lib.rs b/library/stdarch/crates/simd-test-macro/src/lib.rs index 6df48b1e6a..8e65c43992 100644 --- a/library/stdarch/crates/simd-test-macro/src/lib.rs +++ b/library/stdarch/crates/simd-test-macro/src/lib.rs @@ -44,8 +44,6 @@ pub fn simd_test( .map(String::from) .collect(); - let mmx = target_features.iter().any(|s| s.starts_with("mmx")); - let enable_feature = string(enable_feature); let item = TokenStream::from(item); let name = find_name(item.clone()); @@ -106,15 +104,6 @@ pub fn simd_test( TokenStream::new() }; - let emms = if mmx { - // note: if the test requires MMX we need to clear the FPU - // registers once the test finishes before interfacing with - // other x87 code: - quote! { unsafe { super::_mm_empty() }; } - } else { - TokenStream::new() - }; - let ret: TokenStream = quote_spanned! { proc_macro2::Span::call_site() => #[allow(non_snake_case)] @@ -123,7 +112,6 @@ pub fn simd_test( fn #name() { if #force_test | (#cfg_target_features) { let v = unsafe { #name() }; - #emms return v; } else { ::stdarch_test::assert_skip_test_ok(stringify!(#name)); diff --git a/library/stdarch/crates/std_detect/src/detect/cache.rs b/library/stdarch/crates/std_detect/src/detect/cache.rs index 6bcbace4bb..e79c96dafa 100644 --- a/library/stdarch/crates/std_detect/src/detect/cache.rs +++ b/library/stdarch/crates/std_detect/src/detect/cache.rs @@ -43,7 +43,6 @@ impl Default for Initializer { // the one fitting our cache. impl Initializer { /// Tests the `bit` of the cache. - #[allow(dead_code)] #[inline] pub(crate) fn test(self, bit: u32) -> bool { debug_assert!( @@ -80,60 +79,65 @@ impl Initializer { // Note: on x64, we only use the first slot static CACHE: [Cache; 2] = [Cache::uninitialized(), Cache::uninitialized()]; -/// Feature cache with capacity for `usize::MAX - 1` features. +/// Feature cache with capacity for `size_of::() * 8 - 1` features. /// -/// Note: the last feature bit is used to represent an -/// uninitialized cache. +/// Note: 0 is used to represent an uninitialized cache, and (at least) the most +/// significant bit is set on any cache which has been initialized. /// -/// Note: we can use `Relaxed` atomic operations, because we are only interested -/// in the effects of operations on a single memory location. That is, we only -/// need "modification order", and not the full-blown "happens before". However, -/// we use `SeqCst` just to be on the safe side. +/// Note: we use `Relaxed` atomic operations, because we are only interested in +/// the effects of operations on a single memory location. That is, we only need +/// "modification order", and not the full-blown "happens before". struct Cache(AtomicUsize); impl Cache { const CAPACITY: u32 = (core::mem::size_of::() * 8 - 1) as u32; const MASK: usize = (1 << Cache::CAPACITY) - 1; + const INITIALIZED_BIT: usize = 1usize << Cache::CAPACITY; /// Creates an uninitialized cache. #[allow(clippy::declare_interior_mutable_const)] const fn uninitialized() -> Self { - Cache(AtomicUsize::new(usize::MAX)) - } - /// Is the cache uninitialized? - #[inline] - pub(crate) fn is_uninitialized(&self) -> bool { - self.0.load(Ordering::SeqCst) == usize::MAX + Cache(AtomicUsize::new(0)) } - /// Is the `bit` in the cache set? + /// Is the `bit` in the cache set? Returns `None` if the cache has not been initialized. #[inline] - pub(crate) fn test(&self, bit: u32) -> bool { - test_bit(self.0.load(Ordering::SeqCst) as u64, bit) + pub(crate) fn test(&self, bit: u32) -> Option { + let cached = self.0.load(Ordering::Relaxed); + if cached == 0 { + None + } else { + Some(test_bit(cached as u64, bit)) + } } /// Initializes the cache. #[inline] - fn initialize(&self, value: usize) { - self.0.store(value, Ordering::SeqCst); + fn initialize(&self, value: usize) -> usize { + debug_assert_eq!((value & !Cache::MASK), 0); + self.0 + .store(value | Cache::INITIALIZED_BIT, Ordering::Relaxed); + value } } cfg_if::cfg_if! { if #[cfg(feature = "std_detect_env_override")] { - #[inline(never)] - fn initialize(mut value: Initializer) { + #[inline] + fn initialize(mut value: Initializer) -> Initializer { if let Ok(disable) = crate::env::var("RUST_STD_DETECT_UNSTABLE") { for v in disable.split(" ") { let _ = super::Feature::from_str(v).map(|v| value.unset(v as u32)); } } do_initialize(value); + value } } else { #[inline] - fn initialize(value: Initializer) { + fn initialize(value: Initializer) -> Initializer { do_initialize(value); + value } } } @@ -144,8 +148,22 @@ fn do_initialize(value: Initializer) { CACHE[1].initialize((value.0 >> Cache::CAPACITY) as usize & Cache::MASK); } +// We only have to detect features once, and it's fairly costly, so hint to LLVM +// that it should assume that cache hits are more common than misses (which is +// the point of caching). It's possibly unfortunate that this function needs to +// reach across modules like this to call `os::detect_features`, but it produces +// the best code out of several attempted variants. +// +// The `Initializer` that the cache was initialized with is returned, so that +// the caller can call `test()` on it without having to load the value from the +// cache again. +#[cold] +fn detect_and_initialize() -> Initializer { + initialize(super::os::detect_features()) +} + /// Tests the `bit` of the storage. If the storage has not been initialized, -/// initializes it with the result of `f()`. +/// initializes it with the result of `os::detect_features()`. /// /// On its first invocation, it detects the CPU features and caches them in the /// `CACHE` global variable as an `AtomicU64`. @@ -157,18 +175,13 @@ fn do_initialize(value: Initializer) { /// variable `RUST_STD_DETECT_UNSTABLE` and uses its its content to disable /// Features that would had been otherwise detected. #[inline] -pub(crate) fn test(bit: u32, f: F) -> bool -where - F: FnOnce() -> Initializer, -{ - let (bit, idx) = if bit < Cache::CAPACITY { +pub(crate) fn test(bit: u32) -> bool { + let (relative_bit, idx) = if bit < Cache::CAPACITY { (bit, 0) } else { (bit - Cache::CAPACITY, 1) }; - - if CACHE[idx].is_uninitialized() { - initialize(f()) - } - CACHE[idx].test(bit) + CACHE[idx] + .test(relative_bit) + .unwrap_or_else(|| detect_and_initialize().test(bit)) } diff --git a/library/stdarch/crates/std_detect/src/detect/mod.rs b/library/stdarch/crates/std_detect/src/detect/mod.rs index c44f44c1b3..7aedef47d6 100644 --- a/library/stdarch/crates/std_detect/src/detect/mod.rs +++ b/library/stdarch/crates/std_detect/src/detect/mod.rs @@ -120,7 +120,7 @@ cfg_if! { #[inline] #[allow(dead_code)] fn check_for(x: Feature) -> bool { - cache::test(x as u32, self::os::detect_features) + cache::test(x as u32) } /// Returns an `Iterator` where diff --git a/library/stdarch/crates/stdarch-test/src/lib.rs b/library/stdarch/crates/stdarch-test/src/lib.rs index c66b6a8d9d..03711e911e 100644 --- a/library/stdarch/crates/stdarch-test/src/lib.rs +++ b/library/stdarch/crates/stdarch-test/src/lib.rs @@ -3,7 +3,6 @@ //! This basically just disassembles the current executable and then parses the //! output once globally and then provides the `assert` function which makes //! assertions about the disassembly of a function. -#![feature(vec_leak)] #![allow(clippy::missing_docs_in_private_items, clippy::print_stdout)] extern crate assert_instr_macro; diff --git a/library/stdarch/crates/stdarch-verify/src/lib.rs b/library/stdarch/crates/stdarch-verify/src/lib.rs index 37224013f0..6d9dfe6229 100644 --- a/library/stdarch/crates/stdarch-verify/src/lib.rs +++ b/library/stdarch/crates/stdarch-verify/src/lib.rs @@ -148,6 +148,9 @@ fn to_type(t: &syn::Type) -> proc_macro2::TokenStream { "__mmask8" => quote! { &MMASK8 }, "__mmask16" => quote! { &MMASK16 }, "_MM_CMPINT_ENUM" => quote! { &MM_CMPINT_ENUM }, + "_MM_MANTISSA_NORM_ENUM" => quote! { &MM_MANTISSA_NORM_ENUM }, + "_MM_MANTISSA_SIGN_ENUM" => quote! { &MM_MANTISSA_SIGN_ENUM }, + "_MM_PERM_ENUM" => quote! { &MM_PERM_ENUM }, "__m64" => quote! { &M64 }, "bool" => quote! { &BOOL }, "f32" => quote! { &F32 }, diff --git a/library/stdarch/crates/stdarch-verify/tests/arm.rs b/library/stdarch/crates/stdarch-verify/tests/arm.rs index b877b1e869..26239a43aa 100644 --- a/library/stdarch/crates/stdarch-verify/tests/arm.rs +++ b/library/stdarch/crates/stdarch-verify/tests/arm.rs @@ -330,6 +330,7 @@ fn verify_all_signatures() { "_rbit_u64", "_cls_u32", "_cls_u64", + "_prefetch", ]; if !skip.contains(&rust.name) { println!( @@ -350,7 +351,7 @@ fn verify_all_signatures() { // Skip some intrinsics that aren't NEON and are located in different // places than the whitelists below. match rust.name { - "brk" | "__breakpoint" | "udf" => continue, + "brk" | "__breakpoint" | "udf" | "_prefetch" => continue, _ => {} } let arm = match map.get(rust.name) { diff --git a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs index b6f3b01f56..d9adf91999 100644 --- a/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs +++ b/library/stdarch/crates/stdarch-verify/tests/x86-intel.rs @@ -56,6 +56,9 @@ static M512D: Type = Type::M512D; static MMASK8: Type = Type::MMASK8; static MMASK16: Type = Type::MMASK16; static MM_CMPINT_ENUM: Type = Type::MM_CMPINT_ENUM; +static MM_MANTISSA_NORM_ENUM: Type = Type::MM_MANTISSA_NORM_ENUM; +static MM_MANTISSA_SIGN_ENUM: Type = Type::MM_MANTISSA_SIGN_ENUM; +static MM_PERM_ENUM: Type = Type::MM_PERM_ENUM; static TUPLE: Type = Type::Tuple; static CPUID: Type = Type::CpuidResult; @@ -81,6 +84,9 @@ enum Type { MMASK8, MMASK16, MM_CMPINT_ENUM, + MM_MANTISSA_NORM_ENUM, + MM_MANTISSA_SIGN_ENUM, + MM_PERM_ENUM, Tuple, CpuidResult, Never, @@ -323,8 +329,6 @@ fn verify_all_signatures() { // take a signed-integer. This breaks `_MM_SHUFFLE` for // `_mm_shuffle_ps`: "_mm_shuffle_ps" => continue, - // FIXME(#867) - "_mm256_extract_epi8" | "_mm256_extract_epi16" => continue, _ => {} } @@ -676,6 +680,9 @@ fn equate(t: &Type, intel: &str, intrinsic: &str, is_const: bool) -> Result<(), (&Type::MMASK8, "__mmask8") => {} (&Type::MMASK16, "__mmask16") => {} (&Type::MM_CMPINT_ENUM, "_MM_CMPINT_ENUM") => {} + (&Type::MM_MANTISSA_NORM_ENUM, "_MM_MANTISSA_NORM_ENUM") => {} + (&Type::MM_MANTISSA_SIGN_ENUM, "_MM_MANTISSA_SIGN_ENUM") => {} + (&Type::MM_PERM_ENUM, "_MM_PERM_ENUM") => {} // This is a macro (?) in C which seems to mutate its arguments, but // that means that we're taking pointers to arguments in rust diff --git a/library/test/Cargo.toml b/library/test/Cargo.toml index 7b76dc83aa..e44c781113 100644 --- a/library/test/Cargo.toml +++ b/library/test/Cargo.toml @@ -25,6 +25,7 @@ proc_macro = { path = "../proc_macro" } default = ["std_detect_file_io", "std_detect_dlsym_getauxval", "panic-unwind"] backtrace = ["std/backtrace"] compiler-builtins-c = ["std/compiler-builtins-c"] +compiler-builtins-mem = ["std/compiler-builtins-mem"] llvm-libunwind = ["std/llvm-libunwind"] panic-unwind = ["std/panic_unwind"] panic_immediate_abort = ["std/panic_immediate_abort"] diff --git a/library/test/src/bench.rs b/library/test/src/bench.rs index e92e5b9829..10546de176 100644 --- a/library/test/src/bench.rs +++ b/library/test/src/bench.rs @@ -61,15 +61,15 @@ pub fn fmt_bench_samples(bs: &BenchSamples) -> String { let median = bs.ns_iter_summ.median as usize; let deviation = (bs.ns_iter_summ.max - bs.ns_iter_summ.min) as usize; - output - .write_fmt(format_args!( - "{:>11} ns/iter (+/- {})", - fmt_thousands_sep(median, ','), - fmt_thousands_sep(deviation, ',') - )) - .unwrap(); + write!( + output, + "{:>11} ns/iter (+/- {})", + fmt_thousands_sep(median, ','), + fmt_thousands_sep(deviation, ',') + ) + .unwrap(); if bs.mb_s != 0 { - output.write_fmt(format_args!(" = {} MB/s", bs.mb_s)).unwrap(); + write!(output, " = {} MB/s", bs.mb_s).unwrap(); } output } @@ -83,9 +83,9 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String { let base = 10_usize.pow(pow); if pow == 0 || trailing || n / base != 0 { if !trailing { - output.write_fmt(format_args!("{}", n / base)).unwrap(); + write!(output, "{}", n / base).unwrap(); } else { - output.write_fmt(format_args!("{:03}", n / base)).unwrap(); + write!(output, "{:03}", n / base).unwrap(); } if pow != 0 { output.push(sep); @@ -98,10 +98,6 @@ fn fmt_thousands_sep(mut n: usize, sep: char) -> String { output } -fn ns_from_dur(dur: Duration) -> u64 { - dur.as_secs() * 1_000_000_000 + (dur.subsec_nanos() as u64) -} - fn ns_iter_inner(inner: &mut F, k: u64) -> u64 where F: FnMut() -> T, @@ -110,7 +106,7 @@ where for _ in 0..k { black_box(inner()); } - ns_from_dur(start.elapsed()) + start.elapsed().as_nanos() as u64 } pub fn iter(inner: &mut F) -> stats::Summary @@ -163,7 +159,7 @@ where return summ5; } - total_run = total_run + loop_run; + total_run += loop_run; // Longest we ever run for is 3s. if total_run > Duration::from_secs(3) { return summ5; diff --git a/library/test/src/formatters/pretty.rs b/library/test/src/formatters/pretty.rs index 4a93e084df..8c90b57b3b 100644 --- a/library/test/src/formatters/pretty.rs +++ b/library/test/src/formatters/pretty.rs @@ -139,7 +139,7 @@ impl PrettyFormatter { stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); stdouts.push_str(&output); - stdouts.push_str("\n"); + stdouts.push('\n'); } } if !stdouts.is_empty() { diff --git a/library/test/src/formatters/terse.rs b/library/test/src/formatters/terse.rs index 5a264d2005..1ae7846a99 100644 --- a/library/test/src/formatters/terse.rs +++ b/library/test/src/formatters/terse.rs @@ -114,7 +114,7 @@ impl TerseFormatter { stdouts.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); stdouts.push_str(&output); - stdouts.push_str("\n"); + stdouts.push('\n'); } } if !stdouts.is_empty() { @@ -140,7 +140,7 @@ impl TerseFormatter { fail_out.push_str(&format!("---- {} stdout ----\n", f.name)); let output = String::from_utf8_lossy(stdout); fail_out.push_str(&output); - fail_out.push_str("\n"); + fail_out.push('\n'); } } if !fail_out.is_empty() { diff --git a/library/test/src/lib.rs b/library/test/src/lib.rs index 6bd708ef48..b0b81f85fe 100644 --- a/library/test/src/lib.rs +++ b/library/test/src/lib.rs @@ -29,6 +29,7 @@ #![feature(staged_api)] #![feature(termination_trait_lib)] #![feature(test)] +#![feature(total_cmp)] // Public reexports pub use self::bench::{black_box, Bencher}; @@ -236,11 +237,9 @@ where let event = TestEvent::TeFiltered(filtered_descs); notify_about_test_event(event)?; - let (filtered_tests, filtered_benchs): (Vec<_>, _) = - filtered_tests.into_iter().partition(|e| match e.testfn { - StaticTestFn(_) | DynTestFn(_) => true, - _ => false, - }); + let (filtered_tests, filtered_benchs): (Vec<_>, _) = filtered_tests + .into_iter() + .partition(|e| matches!(e.testfn, StaticTestFn(_) | DynTestFn(_))); let concurrency = opts.test_threads.unwrap_or_else(get_concurrency); diff --git a/library/test/src/stats.rs b/library/test/src/stats.rs index c02f93bf9d..53f3889447 100644 --- a/library/test/src/stats.rs +++ b/library/test/src/stats.rs @@ -1,29 +1,13 @@ #![allow(missing_docs)] #![allow(deprecated)] // Float -use std::cmp::Ordering::{self, Equal, Greater, Less}; use std::mem; #[cfg(test)] mod tests; -fn local_cmp(x: f64, y: f64) -> Ordering { - // arbitrarily decide that NaNs are larger than everything. - if y.is_nan() { - Less - } else if x.is_nan() { - Greater - } else if x < y { - Less - } else if x == y { - Equal - } else { - Greater - } -} - fn local_sort(v: &mut [f64]) { - v.sort_by(|x: &f64, y: &f64| local_cmp(*x, *y)); + v.sort_by(|x: &f64, y: &f64| x.total_cmp(y)); } /// Trait that provides simple descriptive statistics on a univariate set of numeric samples. @@ -215,7 +199,7 @@ impl Stats for [f64] { let mut v: f64 = 0.0; for s in self { let x = *s - mean; - v = v + x * x; + v += x * x; } // N.B., this is _supposed to be_ len-1, not len. If you // change it back to len, you will be calculating a diff --git a/library/unwind/src/libunwind.rs b/library/unwind/src/libunwind.rs index 0c57861f70..806df572cf 100644 --- a/library/unwind/src/libunwind.rs +++ b/library/unwind/src/libunwind.rs @@ -51,10 +51,10 @@ pub const unwinder_private_data_size: usize = 2; #[cfg(target_arch = "s390x")] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_arch = "sparc64")] +#[cfg(any(target_arch = "sparc", target_arch = "sparc64"))] pub const unwinder_private_data_size: usize = 2; -#[cfg(target_arch = "riscv64")] +#[cfg(any(target_arch = "riscv64", target_arch = "riscv32"))] pub const unwinder_private_data_size: usize = 2; #[cfg(target_os = "emscripten")] diff --git a/src/README.md b/src/README.md index 2f8e9da179..ef0dec1c45 100644 --- a/src/README.md +++ b/src/README.md @@ -1,5 +1,5 @@ This directory contains the source code of the rust project, including: -- `rustc` and its tests +- The test suite - The bootstrapping build system - Various submodules for tools, like rustdoc, rls, etc. diff --git a/src/bootstrap/CHANGELOG.md b/src/bootstrap/CHANGELOG.md new file mode 100644 index 0000000000..fe426c4cec --- /dev/null +++ b/src/bootstrap/CHANGELOG.md @@ -0,0 +1,47 @@ +# Changelog + +All notable changes to bootstrap will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/). + +## [Non-breaking changes since the last major version] + +None. + +## [Version 2] - 2020-09-25 + +- `host` now defaults to the value of `build` in all cases + + Previously `host` defaulted to an empty list when `target` was overridden, and to `build` otherwise + +### Non-breaking changes + +- Add `x.py setup` [#76631](https://github.com/rust-lang/rust/pull/76631) +- Add a changelog for x.py [#76626](https://github.com/rust-lang/rust/pull/76626) +- Optionally, download LLVM from CI on Linux and NixOS + + [#76439](https://github.com/rust-lang/rust/pull/76349) + + [#76667](https://github.com/rust-lang/rust/pull/76667) + + [#76708](https://github.com/rust-lang/rust/pull/76708) +- Distribute rustc sources as part of `rustc-dev` [#76856](https://github.com/rust-lang/rust/pull/76856) +- Make the default stage for x.py configurable [#76625](https://github.com/rust-lang/rust/pull/76625) +- Add a dedicated debug-logging option [#76588](https://github.com/rust-lang/rust/pull/76588) +- Add sample defaults for x.py [#76628](https://github.com/rust-lang/rust/pull/76628) +- Add `--keep-stage-std`, which behaves like `keep-stage` but allows the stage + 0 compiler artifacts (i.e., stage1/bin/rustc) to be rebuilt if changed + [#77120](https://github.com/rust-lang/rust/pull/77120). + + +## [Version 1] - 2020-09-11 + +This is the first changelog entry, and it does not attempt to be an exhaustive list of features in x.py. +Instead, this documents the changes to bootstrap in the past 2 months. + +- Improve defaults in `x.py` [#73964](https://github.com/rust-lang/rust/pull/73964) + (see [blog post] for details) +- Set `ninja = true` by default [#74922](https://github.com/rust-lang/rust/pull/74922) +- Avoid trying to inversely cross-compile for build triple from host triples [#76415](https://github.com/rust-lang/rust/pull/76415) +- Allow blessing expect-tests in tools [#75975](https://github.com/rust-lang/rust/pull/75975) +- `x.py check` checks tests/examples/benches [#76258](https://github.com/rust-lang/rust/pull/76258) +- Fix `rust.use-lld` when linker is not set [#76326](https://github.com/rust-lang/rust/pull/76326) +- Build tests with LLD if `use-lld = true` was passed [#76378](https://github.com/rust-lang/rust/pull/76378) + +[blog post]: https://blog.rust-lang.org/inside-rust/2020/08/30/changes-to-x-py-defaults.html diff --git a/src/bootstrap/Cargo.toml b/src/bootstrap/Cargo.toml index c4918d7f2e..e04128d1b0 100644 --- a/src/bootstrap/Cargo.toml +++ b/src/bootstrap/Cargo.toml @@ -3,9 +3,9 @@ authors = ["The Rust Project Developers"] name = "bootstrap" version = "0.0.0" edition = "2018" +build = "build.rs" [lib] -name = "bootstrap" path = "lib.rs" doctest = false @@ -49,6 +49,7 @@ lazy_static = "1.3.0" time = "0.1" ignore = "0.4.10" opener = "0.4" +merge = "0.1.0" [target.'cfg(windows)'.dependencies.winapi] version = "0.3" diff --git a/src/bootstrap/README.md b/src/bootstrap/README.md index 86de3d5c6d..bc8bae14b2 100644 --- a/src/bootstrap/README.md +++ b/src/bootstrap/README.md @@ -26,10 +26,10 @@ The script accepts commands, flags, and arguments to determine what to do: ``` # build the whole compiler - ./x.py build + ./x.py build --stage 2 # build the stage1 compiler - ./x.py build --stage 1 + ./x.py build # build stage0 libstd ./x.py build --stage 0 library/std @@ -43,8 +43,8 @@ The script accepts commands, flags, and arguments to determine what to do: that belong to stage n or earlier: ``` - # keep old build products for stage 0 and build stage 1 - ./x.py build --keep-stage 0 --stage 1 + # build stage 1, keeping old build products for stage 0 + ./x.py build --keep-stage 0 ``` * `test` - a command for executing unit tests. Like the `build` command this @@ -123,24 +123,8 @@ that (b) leverage Rust as much as possible! ## Incremental builds -You can configure rustbuild to use incremental compilation. Because -incremental is new and evolving rapidly, if you want to use it, it is -recommended that you replace the snapshot with a locally installed -nightly build of rustc. You will want to keep this up to date. - -To follow this course of action, first thing you will want to do is to -install a nightly, presumably using `rustup`. You will then want to -configure your directory to use this build, like so: - -```sh -# configure to use local rust instead of downloading a beta. -# `--local-rust-root` is optional here. If elided, we will -# use whatever rustc we find on your PATH. -$ ./configure --local-rust-root=~/.cargo/ --enable-local-rebuild -``` - -After that, you can use the `--incremental` flag to actually do -incremental builds: +You can configure rustbuild to use incremental compilation with the +`--incremental` flag: ```sh $ ./x.py build --incremental @@ -150,9 +134,7 @@ The `--incremental` flag will store incremental compilation artifacts in `build//stage0-incremental`. Note that we only use incremental compilation for the stage0 -> stage1 compilation -- this is because the stage1 compiler is changing, and we don't try to cache and reuse -incremental artifacts across different versions of the compiler. For -this reason, `--incremental` defaults to `--stage 1` (though you can -manually select a higher stage, if you prefer). +incremental artifacts across different versions of the compiler. You can always drop the `--incremental` to build as normal (but you will still be using the local nightly as your bootstrap). @@ -274,7 +256,7 @@ directory, but rather the compiler is split into three different Cargo projects: * `library/std` - the standard library * `library/test` - testing support, depends on libstd -* `src/rustc` - the actual compiler itself +* `compiler/rustc` - the actual compiler itself Each "project" has a corresponding Cargo.lock file with all dependencies, and this means that building the compiler involves running Cargo three times. The @@ -331,8 +313,22 @@ are: `Config` struct. * Adding a sanity check? Take a look at `bootstrap/sanity.rs`. -If you have any questions feel free to reach out on `#infra` channel in the -[Rust Discord server][rust-discord] or ask on internals.rust-lang.org. When +If you make a major change, please remember to: + ++ Update `VERSION` in `src/bootstrap/main.rs`. +* Update `changelog-seen = N` in `config.toml.example`. +* Add an entry in `src/bootstrap/CHANGELOG.md`. + +A 'major change' includes + +* A new option or +* A change in the default options. + +Changes that do not affect contributors to the compiler or users +building rustc from source don't need an update to `VERSION`. + +If you have any questions feel free to reach out on the `#t-infra` channel in +the [Rust Zulip server][rust-zulip] or ask on internals.rust-lang.org. When you encounter bugs, please file issues on the rust-lang/rust issue tracker. -[rust-discord]: https://discord.gg/rust-lang +[rust-zulip]: https://rust-lang.zulipchat.com/#narrow/stream/242791-t-infra diff --git a/src/bootstrap/bin/main.rs b/src/bootstrap/bin/main.rs index b67486c962..d31f95ee5e 100644 --- a/src/bootstrap/bin/main.rs +++ b/src/bootstrap/bin/main.rs @@ -7,10 +7,58 @@ use std::env; -use bootstrap::{Build, Config}; +use bootstrap::{Build, Config, Subcommand}; fn main() { let args = env::args().skip(1).collect::>(); let config = Config::parse(&args); + + let changelog_suggestion = check_version(&config); + + // NOTE: Since `./configure` generates a `config.toml`, distro maintainers will see the + // changelog warning, not the `x.py setup` message. + let suggest_setup = !config.config.exists() && !matches!(config.cmd, Subcommand::Setup { .. }); + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { + println!("{}", suggestion); + } + Build::new(config).build(); + + if suggest_setup { + println!("warning: you have not made a `config.toml`"); + println!("help: consider running `x.py setup` or copying `config.toml.example`"); + } else if let Some(suggestion) = &changelog_suggestion { + println!("{}", suggestion); + } + + if suggest_setup || changelog_suggestion.is_some() { + println!("note: this message was printed twice to make it more likely to be seen"); + } +} + +fn check_version(config: &Config) -> Option { + const VERSION: usize = 2; + + let mut msg = String::new(); + + let suggestion = if let Some(seen) = config.changelog_seen { + if seen != VERSION { + msg.push_str("warning: there have been changes to x.py since you last updated.\n"); + format!("update `config.toml` to use `changelog-seen = {}` instead", VERSION) + } else { + return None; + } + } else { + msg.push_str("warning: x.py has made several changes recently you may want to look at\n"); + format!("add `changelog-seen = {}` at the top of `config.toml`", VERSION) + }; + + msg.push_str("help: consider looking at the changes in `src/bootstrap/CHANGELOG.md`\n"); + msg.push_str("note: to silence this warning, "); + msg.push_str(&suggestion); + + Some(msg) } diff --git a/src/bootstrap/bin/rustc.rs b/src/bootstrap/bin/rustc.rs index 4dd71ebade..3694bdbf67 100644 --- a/src/bootstrap/bin/rustc.rs +++ b/src/bootstrap/bin/rustc.rs @@ -112,6 +112,9 @@ fn main() { if let Ok(host_linker) = env::var("RUSTC_HOST_LINKER") { cmd.arg(format!("-Clinker={}", host_linker)); } + if env::var_os("RUSTC_HOST_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } if let Ok(s) = env::var("RUSTC_HOST_CRT_STATIC") { if s == "true" { diff --git a/src/bootstrap/bin/rustdoc.rs b/src/bootstrap/bin/rustdoc.rs index ab846adf94..cb58eb89ad 100644 --- a/src/bootstrap/bin/rustdoc.rs +++ b/src/bootstrap/bin/rustdoc.rs @@ -42,11 +42,14 @@ fn main() { if env::var_os("RUSTC_FORCE_UNSTABLE").is_some() { cmd.arg("-Z").arg("force-unstable-if-unmarked"); } - if let Some(linker) = env::var_os("RUSTC_TARGET_LINKER") { + if let Some(linker) = env::var_os("RUSTDOC_LINKER") { let mut arg = OsString::from("-Clinker="); arg.push(&linker); cmd.arg(arg); } + if env::var_os("RUSTDOC_FUSE_LD_LLD").is_some() { + cmd.arg("-Clink-args=-fuse-ld=lld"); + } // Needed to be able to run all rustdoc tests. if let Some(ref x) = env::var_os("RUSTDOC_RESOURCE_SUFFIX") { diff --git a/src/bootstrap/bootstrap.py b/src/bootstrap/bootstrap.py index c3f1bac177..5c9184f450 100644 --- a/src/bootstrap/bootstrap.py +++ b/src/bootstrap/bootstrap.py @@ -14,8 +14,17 @@ import tempfile from time import time +def support_xz(): + try: + with tempfile.NamedTemporaryFile(delete=False) as temp_file: + temp_path = temp_file.name + with tarfile.open(temp_path, "w:xz"): + pass + return True + except tarfile.CompressionError: + return False -def get(url, path, verbose=False): +def get(url, path, verbose=False, do_verify=True): suffix = '.sha256' sha_url = url + suffix with tempfile.NamedTemporaryFile(delete=False) as temp_file: @@ -24,19 +33,20 @@ def get(url, path, verbose=False): sha_path = sha_file.name try: - download(sha_path, sha_url, False, verbose) - if os.path.exists(path): - if verify(path, sha_path, False): - if verbose: - print("using already-download file", path) - return - else: - if verbose: - print("ignoring already-download file", - path, "due to failed verification") - os.unlink(path) + if do_verify: + download(sha_path, sha_url, False, verbose) + if os.path.exists(path): + if verify(path, sha_path, False): + if verbose: + print("using already-download file", path) + return + else: + if verbose: + print("ignoring already-download file", + path, "due to failed verification") + os.unlink(path) download(temp_path, url, True, verbose) - if not verify(temp_path, sha_path, verbose): + if do_verify and not verify(temp_path, sha_path, verbose): raise RuntimeError("failed verification") if verbose: print("moving {} to {}".format(temp_path, path)) @@ -365,16 +375,6 @@ class RustBuild(object): cargo_channel = self.cargo_channel rustfmt_channel = self.rustfmt_channel - def support_xz(): - try: - with tempfile.NamedTemporaryFile(delete=False) as temp_file: - temp_path = temp_file.name - with tarfile.open(temp_path, "w:xz"): - pass - return True - except tarfile.CompressionError: - return False - if self.rustc().startswith(self.bin_root()) and \ (not os.path.exists(self.rustc()) or self.program_out_of_date(self.rustc_stamp())): @@ -398,14 +398,6 @@ class RustBuild(object): with output(self.rustc_stamp()) as rust_stamp: rust_stamp.write(self.date) - # This is required so that we don't mix incompatible MinGW - # libraries/binaries that are included in rust-std with - # the system MinGW ones. - if "pc-windows-gnu" in self.build: - filename = "rust-mingw-{}-{}{}".format( - rustc_channel, self.build, tarball_suffix) - self._download_stage0_helper(filename, "rust-mingw", tarball_suffix) - if self.cargo().startswith(self.bin_root()) and \ (not os.path.exists(self.cargo()) or self.program_out_of_date(self.cargo_stamp())): @@ -431,6 +423,32 @@ class RustBuild(object): with output(self.rustfmt_stamp()) as rustfmt_stamp: rustfmt_stamp.write(self.date + self.rustfmt_channel) + if self.downloading_llvm(): + # We want the most recent LLVM submodule update to avoid downloading + # LLVM more often than necessary. + # + # This git command finds that commit SHA, looking for bors-authored + # merges that modified src/llvm-project. + # + # This works even in a repository that has not yet initialized + # submodules. + llvm_sha = subprocess.check_output([ + "git", "log", "--author=bors", "--format=%H", "-n1", + "-m", "--first-parent", + "--", "src/llvm-project" + ]).decode(sys.getdefaultencoding()).strip() + llvm_assertions = self.get_toml('assertions', 'llvm') == 'true' + if self.program_out_of_date(self.llvm_stamp(), llvm_sha + str(llvm_assertions)): + self._download_ci_llvm(llvm_sha, llvm_assertions) + for binary in ["llvm-config", "FileCheck"]: + self.fix_bin_or_dylib("{}/bin/{}".format(self.llvm_root(), binary)) + with output(self.llvm_stamp()) as llvm_stamp: + llvm_stamp.write(self.date + llvm_sha + str(llvm_assertions)) + + def downloading_llvm(self): + opt = self.get_toml('download-ci-llvm', 'llvm') + return opt == "true" + def _download_stage0_helper(self, filename, pattern, tarball_suffix, date=None): if date is None: date = self.date @@ -445,6 +463,25 @@ class RustBuild(object): get("{}/{}".format(url, filename), tarball, verbose=self.verbose) unpack(tarball, tarball_suffix, self.bin_root(), match=pattern, verbose=self.verbose) + def _download_ci_llvm(self, llvm_sha, llvm_assertions): + 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) + if llvm_assertions: + url = url.replace('rustc-builds', 'rustc-builds-alt') + tarball_suffix = '.tar.xz' if support_xz() else '.tar.gz' + 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) + unpack(tarball, tarball_suffix, self.llvm_root(), + match="rust-dev", + verbose=self.verbose) + def fix_bin_or_dylib(self, fname): """Modifies the interpreter section of 'fname' to fix the dynamic linker, or the RPATH section, to fix the dynamic library search path @@ -566,6 +603,17 @@ class RustBuild(object): """ return os.path.join(self.bin_root(), '.rustfmt-stamp') + def llvm_stamp(self): + """Return the path for .rustfmt-stamp + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_stamp() == os.path.join("build", "ci-llvm", ".llvm-stamp") + True + """ + return os.path.join(self.llvm_root(), '.llvm-stamp') + + def program_out_of_date(self, stamp_path, extra=""): """Check if the given program stamp is out of date""" if not os.path.exists(stamp_path) or self.clean: @@ -589,6 +637,22 @@ class RustBuild(object): """ return os.path.join(self.build_dir, self.build, "stage0") + def llvm_root(self): + """Return the CI LLVM root directory + + >>> rb = RustBuild() + >>> rb.build_dir = "build" + >>> rb.llvm_root() == os.path.join("build", "ci-llvm") + True + + When the 'build' property is given should be a nested directory: + + >>> rb.build = "devel" + >>> rb.llvm_root() == os.path.join("build", "devel", "ci-llvm") + True + """ + return os.path.join(self.build_dir, self.build, "ci-llvm") + def get_toml(self, key, section=None): """Returns the value of the given key in config.toml, otherwise returns None @@ -714,7 +778,6 @@ class RustBuild(object): # See also: . if "CARGO_BUILD_TARGET" in env: del env["CARGO_BUILD_TARGET"] - env["RUSTC_BOOTSTRAP"] = '1' env["CARGO_TARGET_DIR"] = build_dir env["RUSTC"] = self.rustc() env["LD_LIBRARY_PATH"] = os.path.join(self.bin_root(), "lib") + \ @@ -829,8 +892,9 @@ class RustBuild(object): submodules_names = [] for module in submodules: if module.endswith("llvm-project"): - if self.get_toml('llvm-config') and self.get_toml('lld') != 'true': - continue + if self.get_toml('llvm-config') or self.get_toml('download-ci-llvm') == 'true': + if self.get_toml('lld') != 'true': + continue check = self.check_submodule(module, slow_submodules) filtered_submodules.append((module, check)) submodules_names.append(module) @@ -914,7 +978,6 @@ def bootstrap(help_triggered): parser = argparse.ArgumentParser(description='Build rust') parser.add_argument('--config') parser.add_argument('--build') - parser.add_argument('--src') parser.add_argument('--clean', action='store_true') parser.add_argument('-v', '--verbose', action='count', default=0) @@ -923,7 +986,7 @@ def bootstrap(help_triggered): # Configure initial bootstrap build = RustBuild() - build.rust_root = args.src or os.path.abspath(os.path.join(__file__, '../../..')) + build.rust_root = os.path.abspath(os.path.join(__file__, '../../..')) build.verbose = args.verbose build.clean = args.clean @@ -980,18 +1043,12 @@ def bootstrap(help_triggered): args = [build.bootstrap_binary()] args.extend(sys.argv[1:]) env = os.environ.copy() - env["BUILD"] = build.build - env["SRC"] = build.rust_root env["BOOTSTRAP_PARENT_ID"] = str(os.getpid()) env["BOOTSTRAP_PYTHON"] = sys.executable env["BUILD_DIR"] = build.build_dir env["RUSTC_BOOTSTRAP"] = '1' - env["CARGO"] = build.cargo() - env["RUSTC"] = build.rustc() if toml_path: env["BOOTSTRAP_CONFIG"] = toml_path - if build.rustfmt(): - env["RUSTFMT"] = build.rustfmt() run(args, env=env, verbose=build.verbose) diff --git a/src/bootstrap/build.rs b/src/bootstrap/build.rs new file mode 100644 index 0000000000..d40b924e0f --- /dev/null +++ b/src/bootstrap/build.rs @@ -0,0 +1,26 @@ +use std::env; +use std::path::PathBuf; + +fn main() { + println!("cargo:rerun-if-changed=build.rs"); + println!("cargo:rustc-env=BUILD_TRIPLE={}", env::var("HOST").unwrap()); + + // This may not be a canonicalized path. + let mut rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); + + if rustc.is_relative() { + for dir in env::split_paths(&env::var_os("PATH").unwrap_or_default()) { + let absolute = dir.join(&rustc); + if absolute.exists() { + rustc = absolute; + break; + } + } + } + assert!(rustc.is_absolute()); + + // FIXME: if the path is not utf-8, this is going to break. Unfortunately + // Cargo doesn't have a way for us to specify non-utf-8 paths easily, so + // we'll need to invent some encoding scheme if this becomes a problem. + println!("cargo:rustc-env=RUSTC={}", rustc.to_str().unwrap()); +} diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index 6446fa7550..3fa77982a9 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -87,11 +87,16 @@ pub trait Step: 'static + Clone + Debug + PartialEq + Eq + Hash { pub struct RunConfig<'a> { pub builder: &'a Builder<'a>, - pub host: TargetSelection, pub target: TargetSelection, pub path: PathBuf, } +impl RunConfig<'_> { + pub fn build_triple(&self) -> TargetSelection { + self.builder.build.build + } +} + struct StepDescription { default: bool, only_hosts: bool, @@ -165,29 +170,13 @@ impl StepDescription { pathset, self.name, builder.config.exclude ); } - let hosts = &builder.hosts; // Determine the targets participating in this rule. - let targets = if self.only_hosts { - if builder.config.skip_only_host_steps { - return; // don't run anything - } else { - &builder.hosts - } - } else { - &builder.targets - }; + let targets = if self.only_hosts { &builder.hosts } else { &builder.targets }; - for host in hosts { - for target in targets { - let run = RunConfig { - builder, - path: pathset.path(builder), - host: *host, - target: *target, - }; - (self.make_run)(run); - } + for target in targets { + let run = RunConfig { builder, path: pathset.path(builder), target: *target }; + (self.make_run)(run); } } @@ -204,37 +193,37 @@ impl StepDescription { ); } - if paths.is_empty() { - for (desc, should_run) in v.iter().zip(should_runs) { + if paths.is_empty() || builder.config.include_default_paths { + for (desc, should_run) in v.iter().zip(&should_runs) { if desc.default && should_run.is_really_default { for pathset in &should_run.paths { desc.maybe_run(builder, pathset); } } } - } else { - for path in paths { - // strip CurDir prefix if present - let path = match path.strip_prefix(".") { - Ok(p) => p, - Err(_) => path, - }; + } - let mut attempted_run = false; - for (desc, should_run) in v.iter().zip(&should_runs) { - if let Some(suite) = should_run.is_suite_path(path) { - attempted_run = true; - desc.maybe_run(builder, suite); - } else if let Some(pathset) = should_run.pathset_for_path(path) { - attempted_run = true; - desc.maybe_run(builder, pathset); - } - } + for path in paths { + // strip CurDir prefix if present + let path = match path.strip_prefix(".") { + Ok(p) => p, + Err(_) => path, + }; - if !attempted_run { - panic!("error: no rules matched {}", path.display()); + let mut attempted_run = false; + for (desc, should_run) in v.iter().zip(&should_runs) { + if let Some(suite) = should_run.is_suite_path(path) { + attempted_run = true; + desc.maybe_run(builder, suite); + } else if let Some(pathset) = should_run.pathset_for_path(path) { + attempted_run = true; + desc.maybe_run(builder, pathset); } } + + if !attempted_run { + panic!("error: no rules matched {}", path.display()); + } } } } @@ -382,7 +371,7 @@ impl<'a> Builder<'a> { native::Lld ), Kind::Check | Kind::Clippy | Kind::Fix | Kind::Format => { - describe!(check::Std, check::Rustc, check::Rustdoc, check::Clippy) + describe!(check::Std, check::Rustc, check::Rustdoc, check::Clippy, check::Bootstrap) } Kind::Test => describe!( crate::toolstate::ToolStateCheck, @@ -471,7 +460,9 @@ impl<'a> Builder<'a> { dist::Clippy, dist::Miri, dist::LlvmTools, + dist::RustDev, dist::Extended, + dist::BuildManifest, dist::HashSign ), Kind::Install => describe!( @@ -487,7 +478,7 @@ impl<'a> Builder<'a> { install::Src, install::Rustc ), - Kind::Run => describe!(run::ExpandYamlAnchors,), + Kind::Run => describe!(run::ExpandYamlAnchors, run::BuildManifest,), } } @@ -528,23 +519,9 @@ impl<'a> Builder<'a> { } fn new_internal(build: &Build, kind: Kind, paths: Vec) -> Builder<'_> { - let top_stage = if let Some(explicit_stage) = build.config.stage { - explicit_stage - } else { - // See https://github.com/rust-lang/compiler-team/issues/326 - match kind { - Kind::Doc => 0, - Kind::Build | Kind::Test => 1, - Kind::Bench | Kind::Dist | Kind::Install => 2, - // These are all bootstrap tools, which don't depend on the compiler. - // The stage we pass shouldn't matter, but use 0 just in case. - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => 0, - } - }; - Builder { build, - top_stage, + top_stage: build.config.stage, kind, cache: Cache::new(), stack: RefCell::new(Vec::new()), @@ -565,23 +542,12 @@ impl<'a> Builder<'a> { Subcommand::Dist { ref paths } => (Kind::Dist, &paths[..]), Subcommand::Install { ref paths } => (Kind::Install, &paths[..]), Subcommand::Run { ref paths } => (Kind::Run, &paths[..]), - Subcommand::Format { .. } | Subcommand::Clean { .. } => panic!(), + Subcommand::Format { .. } | Subcommand::Clean { .. } | Subcommand::Setup { .. } => { + panic!() + } }; - let this = Self::new_internal(build, kind, paths.to_owned()); - - // CI should always run stage 2 builds, unless it specifically states otherwise - #[cfg(not(test))] - if build.config.stage.is_none() && build.ci_env != crate::CiEnv::None { - match kind { - Kind::Test | Kind::Doc | Kind::Build | Kind::Bench | Kind::Dist | Kind::Install => { - assert_eq!(this.top_stage, 2) - } - Kind::Check | Kind::Clippy | Kind::Fix | Kind::Run | Kind::Format => {} - } - } - - this + Self::new_internal(build, kind, paths.to_owned()) } pub fn execute_cli(&self) { @@ -712,7 +678,7 @@ impl<'a> Builder<'a> { /// Adds the compiler's directory of dynamic libraries to `cmd`'s dynamic /// library lookup path. - pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Cargo) { + pub fn add_rustc_lib_path(&self, compiler: Compiler, cmd: &mut Command) { // Windows doesn't need dylib path munging because the dlls for the // compiler live next to the compiler and the system will find them // automatically. @@ -720,7 +686,7 @@ impl<'a> Builder<'a> { return; } - add_dylib_path(vec![self.rustc_libdir(compiler)], &mut cmd.command); + add_dylib_path(vec![self.rustc_libdir(compiler)], cmd); } /// Gets a path to the compiler specified. @@ -755,8 +721,11 @@ impl<'a> Builder<'a> { cmd.env_remove("MAKEFLAGS"); cmd.env_remove("MFLAGS"); - if let Some(linker) = self.linker(compiler.host, true) { - cmd.env("RUSTC_TARGET_LINKER", linker); + if let Some(linker) = self.linker(compiler.host) { + cmd.env("RUSTDOC_LINKER", linker); + } + if self.is_fuse_ld_lld(compiler.host) { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } cmd } @@ -796,7 +765,7 @@ impl<'a> Builder<'a> { if cmd == "doc" || cmd == "rustdoc" { let my_out = match mode { // This is the intended out directory for compiler documentation. - Mode::Rustc | Mode::ToolRustc | Mode::Codegen => self.compiler_doc_out(target), + Mode::Rustc | Mode::ToolRustc => self.compiler_doc_out(target), Mode::Std => out_dir.join(target.triple).join("doc"), _ => panic!("doc mode {:?} not expected", mode), }; @@ -811,7 +780,7 @@ impl<'a> Builder<'a> { format!("CARGO_PROFILE_{}_{}", profile, name) }; - // See comment in librustc_llvm/build.rs for why this is necessary, largely llvm-config + // See comment in rustc_llvm/build.rs for why this is necessary, largely llvm-config // needs to not accidentally link to libLLVM in stage0/lib. cargo.env("REAL_LIBRARY_PATH_VAR", &util::dylib_path_var()); if let Some(e) = env::var_os(util::dylib_path_var()) { @@ -828,9 +797,9 @@ impl<'a> Builder<'a> { // scripts can do less work (i.e. not building/requiring LLVM). if cmd == "check" || cmd == "clippy" || cmd == "fix" { // If we've not yet built LLVM, or it's stale, then bust - // the librustc_llvm cache. That will always work, even though it + // the rustc_llvm cache. That will always work, even though it // may mean that on the next non-check build we'll need to rebuild - // librustc_llvm. But if LLVM is stale, that'll be a tiny amount + // rustc_llvm. But if LLVM is stale, that'll be a tiny amount // of work comparitively, and we'd likely need to rebuild it anyway, // so that's okay. if crate::native::prebuilt_llvm_config(self, target).is_err() { @@ -874,7 +843,7 @@ impl<'a> Builder<'a> { match mode { Mode::Std | Mode::ToolBootstrap | Mode::ToolStd => {} - Mode::Rustc | Mode::Codegen | Mode::ToolRustc => { + Mode::Rustc | Mode::ToolRustc => { // Build proc macros both for the host and the target if target != compiler.host && cmd != "check" { cargo.arg("-Zdual-proc-macros"); @@ -1041,20 +1010,18 @@ impl<'a> Builder<'a> { } } - // FIXME: Don't use LLD with MSVC if we're compiling libtest, since it fails to link it. - // See https://github.com/rust-lang/rust/issues/68647. - let can_use_lld = mode != Mode::Std; - - if let Some(host_linker) = self.linker(compiler.host, can_use_lld) { + if let Some(host_linker) = self.linker(compiler.host) { cargo.env("RUSTC_HOST_LINKER", host_linker); } + if self.is_fuse_ld_lld(compiler.host) { + cargo.env("RUSTC_HOST_FUSE_LD_LLD", "1"); + } - if let Some(target_linker) = self.linker(target, can_use_lld) { + if let Some(target_linker) = self.linker(target) { let target = crate::envify(&target.triple); cargo.env(&format!("CARGO_TARGET_{}_LINKER", target), target_linker); } - - if self.config.use_lld && !target.contains("msvc") { + if self.is_fuse_ld_lld(target) { rustflags.arg("-Clink-args=-fuse-ld=lld"); } @@ -1063,7 +1030,7 @@ impl<'a> Builder<'a> { } let debuginfo_level = match mode { - Mode::Rustc | Mode::Codegen => self.config.rust_debuginfo_level_rustc, + Mode::Rustc => self.config.rust_debuginfo_level_rustc, Mode::Std => self.config.rust_debuginfo_level_std, Mode::ToolBootstrap | Mode::ToolStd | Mode::ToolRustc => { self.config.rust_debuginfo_level_tools @@ -1079,6 +1046,11 @@ impl<'a> Builder<'a> { }, ); + if self.config.cmd.bless() { + // Bless `expect!` tests. + cargo.env("UPDATE_EXPECT", "1"); + } + if !mode.is_tool() { cargo.env("RUSTC_FORCE_UNSTABLE", "1"); } @@ -1195,7 +1167,7 @@ impl<'a> Builder<'a> { rustdocflags.arg("-Winvalid_codeblock_attributes"); } - if let Mode::Rustc | Mode::Codegen = mode { + if mode == Mode::Rustc { rustflags.arg("-Zunstable-options"); rustflags.arg("-Wrustc::internal"); } @@ -1232,7 +1204,7 @@ impl<'a> Builder<'a> { cargo.env(format!("CC_{}", target.triple), &cc); let cflags = self.cflags(target, GitRepo::Rustc).join(" "); - cargo.env(format!("CFLAGS_{}", target.triple), cflags.clone()); + cargo.env(format!("CFLAGS_{}", target.triple), &cflags); if let Some(ar) = self.ar(target) { let ranlib = format!("{} s", ar.display()); @@ -1358,7 +1330,7 @@ impl<'a> Builder<'a> { // When we build Rust dylibs they're all intended for intermediate // usage, so make sure we pass the -Cprefer-dynamic flag instead of // linking all deps statically into the dylib. - if let Mode::Std | Mode::Rustc | Mode::Codegen = mode { + if matches!(mode, Mode::Std | Mode::Rustc) { rustflags.arg("-Cprefer-dynamic"); } @@ -1417,7 +1389,7 @@ impl<'a> Builder<'a> { (out, dur - deps) }; - if self.config.print_step_timings && dur > Duration::from_millis(100) { + if self.config.print_step_timings && !self.config.dry_run { println!("[TIMING] {:?} -- {}.{:03}", step, dur.as_secs(), dur.subsec_millis()); } @@ -1511,6 +1483,10 @@ impl Cargo { self.command.env(key.as_ref(), value.as_ref()); self } + + pub fn add_rustc_lib_path(&mut self, builder: &Builder<'_>, compiler: Compiler) { + builder.add_rustc_lib_path(compiler, &mut self.command); + } } impl From for Command { diff --git a/src/bootstrap/builder/tests.rs b/src/bootstrap/builder/tests.rs index 111971534b..a367aa5349 100644 --- a/src/bootstrap/builder/tests.rs +++ b/src/bootstrap/builder/tests.rs @@ -2,13 +2,16 @@ use super::*; use crate::config::{Config, TargetSelection}; use std::thread; -fn configure(host: &[&str], target: &[&str]) -> Config { - let mut config = Config::default_opts(); +fn configure(cmd: &str, host: &[&str], target: &[&str]) -> Config { + let mut config = Config::parse(&[cmd.to_owned()]); // don't save toolstates config.save_toolstates = None; - config.skip_only_host_steps = false; config.dry_run = true; + config.ninja_in_file = false; // try to avoid spurious failures in dist where we create/delete each others file + config.out = PathBuf::from(env::var_os("BOOTSTRAP_OUTPUT_DIRECTORY").unwrap()); + config.initial_rustc = PathBuf::from(env::var_os("RUSTC").unwrap()); + config.initial_cargo = PathBuf::from(env::var_os("BOOTSTRAP_INITIAL_CARGO").unwrap()); let dir = config .out .join("tmp-rustbuild-tests") @@ -16,16 +19,8 @@ fn configure(host: &[&str], target: &[&str]) -> Config { t!(fs::create_dir_all(&dir)); config.out = dir; config.build = TargetSelection::from_user("A"); - config.hosts = vec![config.build] - .into_iter() - .chain(host.iter().map(|s| TargetSelection::from_user(s))) - .collect::>(); - config.targets = config - .hosts - .clone() - .into_iter() - .chain(target.iter().map(|s| TargetSelection::from_user(s))) - .collect::>(); + config.hosts = host.iter().map(|s| TargetSelection::from_user(s)).collect(); + config.targets = target.iter().map(|s| TargetSelection::from_user(s)).collect(); config } @@ -41,7 +36,7 @@ mod defaults { #[test] fn build_default() { - let build = Build::new(configure(&[], &[])); + let build = Build::new(configure("build", &["A"], &["A"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -69,7 +64,7 @@ mod defaults { #[test] fn build_stage_0() { - let config = Config { stage: Some(0), ..configure(&[], &[]) }; + let config = Config { stage: 0, ..configure("build", &["A"], &["A"]) }; let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); @@ -89,9 +84,57 @@ mod defaults { assert!(builder.cache.all::().is_empty()); } + #[test] + fn build_cross_compile() { + let config = Config { stage: 1, ..configure("build", &["A", "B"], &["A", "B"]) }; + let build = Build::new(config); + let mut builder = Builder::new(&build); + builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); + + let a = TargetSelection::from_user("A"); + let b = TargetSelection::from_user("B"); + + // Ideally, this build wouldn't actually have `target: a` + // rustdoc/rustcc/std here (the user only requested a host=B build, so + // there's not really a need for us to build for target A in this case + // (since we're producing stage 1 libraries/binaries). But currently + // rustbuild is just a bit buggy here; this should be fixed though. + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, + compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, + compile::Assemble { target_compiler: Compiler { host: b, stage: 1 } }, + ] + ); + assert_eq!( + first(builder.cache.all::()), + &[ + tool::Rustdoc { compiler: Compiler { host: a, stage: 1 } }, + tool::Rustdoc { compiler: Compiler { host: b, stage: 1 } }, + ], + ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: b }, + ] + ); + } + #[test] fn doc_default() { - let mut config = configure(&[], &[]); + let mut config = configure("doc", &["A"], &["A"]); config.compiler_docs = true; config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; let build = Build::new(config); @@ -125,12 +168,12 @@ mod dist { use pretty_assertions::assert_eq; fn configure(host: &[&str], target: &[&str]) -> Config { - Config { stage: Some(2), ..super::configure(host, target) } + Config { stage: 2, ..super::configure("dist", host, target) } } #[test] fn dist_baseline() { - let build = Build::new(configure(&[], &[])); + let build = Build::new(configure(&["A"], &["A"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -156,7 +199,7 @@ mod dist { #[test] fn dist_with_targets() { - let build = Build::new(configure(&[], &["B"])); + let build = Build::new(configure(&["A"], &["A", "B"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -187,7 +230,7 @@ mod dist { #[test] fn dist_with_hosts() { - let build = Build::new(configure(&["B"], &[])); + let build = Build::new(configure(&["A", "B"], &["A", "B"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -216,6 +259,16 @@ mod dist { dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); + assert_eq!( + first(builder.cache.all::()), + &[ + compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, + compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, + compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, + ], + ); assert_eq!(first(builder.cache.all::()), &[dist::Src]); } @@ -223,7 +276,7 @@ mod dist { fn dist_only_cross_host() { let a = TargetSelection::from_user("A"); let b = TargetSelection::from_user("B"); - let mut build = Build::new(configure(&["B"], &[])); + let mut build = Build::new(configure(&["A", "B"], &["A", "B"])); build.config.docs = false; build.config.extended = true; build.hosts = vec![b]; @@ -245,7 +298,7 @@ mod dist { #[test] fn dist_with_targets_and_hosts() { - let build = Build::new(configure(&["B"], &["C"])); + let build = Build::new(configure(&["A", "B"], &["A", "B", "C"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -280,40 +333,26 @@ mod dist { } #[test] - fn dist_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.skip_only_host_steps = true; // as-if --target=C was passed + fn dist_with_empty_host() { + let config = configure(&[], &["C"]); let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); let c = TargetSelection::from_user("C"); - assert_eq!( - first(builder.cache.all::()), - &[dist::Docs { host: a }, dist::Docs { host: b }, dist::Docs { host: c },] - ); - assert_eq!( - first(builder.cache.all::()), - &[dist::Mingw { host: a }, dist::Mingw { host: b }, dist::Mingw { host: c },] - ); - assert_eq!(first(builder.cache.all::()), &[]); + assert_eq!(first(builder.cache.all::()), &[dist::Docs { host: c },]); + assert_eq!(first(builder.cache.all::()), &[dist::Mingw { host: c },]); assert_eq!( first(builder.cache.all::()), - &[ - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - dist::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - ] + &[dist::Std { compiler: Compiler { host: a, stage: 2 }, target: c },] ); - assert_eq!(first(builder.cache.all::()), &[]); } #[test] fn dist_with_same_targets_and_hosts() { - let build = Build::new(configure(&["B"], &["B"])); + let build = Build::new(configure(&["A", "B"], &["A", "B"])); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Dist), &[]); @@ -366,11 +405,11 @@ mod dist { #[test] fn build_all() { - let build = Build::new(configure(&["B"], &["C"])); + let build = Build::new(configure(&["A", "B"], &["A", "B", "C"])); let mut builder = Builder::new(&build); builder.run_step_descriptions( &Builder::get_step_descriptions(Kind::Build), - &["src/rustc".into(), "library/std".into()], + &["compiler/rustc".into(), "library/std".into()], ); let a = TargetSelection::from_user("A"); @@ -383,12 +422,9 @@ mod dist { compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert!(!builder.cache.all::().is_empty()); @@ -398,24 +434,20 @@ mod dist { compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, compile::Rustc { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Rustc { compiler: Compiler { host: b, stage: 2 }, target: b }, ] ); } #[test] - fn build_with_target_flag() { - let mut config = configure(&["B"], &["C"]); - config.skip_only_host_steps = true; + fn build_with_empty_host() { + let config = configure(&[], &["C"]); let build = Build::new(config); let mut builder = Builder::new(&build); builder.run_step_descriptions(&Builder::get_step_descriptions(Kind::Build), &[]); let a = TargetSelection::from_user("A"); - let b = TargetSelection::from_user("B"); let c = TargetSelection::from_user("C"); assert_eq!( @@ -423,13 +455,7 @@ mod dist { &[ compile::Std { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Std { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: a }, - compile::Std { compiler: Compiler { host: a, stage: 1 }, target: b }, - compile::Std { compiler: Compiler { host: a, stage: 2 }, target: b }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: b }, compile::Std { compiler: Compiler { host: a, stage: 2 }, target: c }, - compile::Std { compiler: Compiler { host: b, stage: 2 }, target: c }, ] ); assert_eq!( @@ -438,7 +464,6 @@ mod dist { compile::Assemble { target_compiler: Compiler { host: a, stage: 0 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 1 } }, compile::Assemble { target_compiler: Compiler { host: a, stage: 2 } }, - compile::Assemble { target_compiler: Compiler { host: b, stage: 2 } }, ] ); assert_eq!( @@ -446,15 +471,14 @@ mod dist { &[ compile::Rustc { compiler: Compiler { host: a, stage: 0 }, target: a }, compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: a }, - compile::Rustc { compiler: Compiler { host: a, stage: 1 }, target: b }, ] ); } #[test] fn test_with_no_doc_stage0() { - let mut config = configure(&[], &[]); - config.stage = Some(0); + let mut config = configure(&["A"], &["A"]); + config.stage = 0; config.cmd = Subcommand::Test { paths: vec!["library/std".into()], test_args: vec![], @@ -493,7 +517,7 @@ mod dist { #[test] fn test_exclude() { - let mut config = configure(&[], &[]); + let mut config = configure(&["A"], &["A"]); config.exclude = vec!["src/tools/tidy".into()]; config.cmd = Subcommand::Test { paths: Vec::new(), @@ -520,7 +544,7 @@ mod dist { #[test] fn doc_ci() { - let mut config = configure(&[], &[]); + let mut config = configure(&["A"], &["A"]); config.compiler_docs = true; config.cmd = Subcommand::Doc { paths: Vec::new(), open: false }; let build = Build::new(config); @@ -549,7 +573,7 @@ mod dist { #[test] fn test_docs() { // Behavior of `x.py test` doing various documentation tests. - let mut config = configure(&[], &[]); + let mut config = configure(&["A"], &["A"]); config.cmd = Subcommand::Test { paths: vec![], test_args: vec![], diff --git a/src/bootstrap/cc_detect.rs b/src/bootstrap/cc_detect.rs index 7ff00d85dd..d50e4cf526 100644 --- a/src/bootstrap/cc_detect.rs +++ b/src/bootstrap/cc_detect.rs @@ -132,7 +132,8 @@ pub fn find(build: &mut Build) { false }; - if cxx_configured { + // for VxWorks, record CXX compiler which will be used in lib.rs:linker() + if cxx_configured || target.contains("vxworks") { let compiler = cfg.get_compiler(); build.cxx.insert(target, compiler); } diff --git a/src/bootstrap/channel.rs b/src/bootstrap/channel.rs index 51a9b0e0a5..2b82f6c30b 100644 --- a/src/bootstrap/channel.rs +++ b/src/bootstrap/channel.rs @@ -12,9 +12,6 @@ use build_helper::output; use crate::Build; -// The version number -pub const CFG_RELEASE_NUM: &str = "1.47.0"; - pub struct GitInfo { inner: Option, } diff --git a/src/bootstrap/check.rs b/src/bootstrap/check.rs index 9f34bb4e6c..ead0bd0413 100644 --- a/src/bootstrap/check.rs +++ b/src/bootstrap/check.rs @@ -66,6 +66,43 @@ impl Step for Std { let libdir = builder.sysroot_libdir(compiler, target); let hostdir = builder.sysroot_libdir(compiler, compiler.host); add_to_sysroot(&builder, &libdir, &hostdir, &libstd_stamp(builder, compiler, target)); + + // 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 + // since we initialize with an empty sysroot. + // + // Currently only the "libtest" tree of crates does this. + + let mut cargo = builder.cargo( + compiler, + Mode::Std, + SourceType::InTree, + target, + cargo_subcommand(builder.kind), + ); + std_cargo(builder, target, compiler.stage, &mut cargo); + cargo.arg("--all-targets"); + + // Explicitly pass -p for all dependencies krates -- this will force cargo + // to also check the tests/benches/examples for these crates, rather + // than just the leaf crate. + for krate in builder.in_tree_crates("test") { + cargo.arg("-p").arg(krate.name); + } + + builder.info(&format!( + "Checking std test/bench/example targets ({} -> {})", + &compiler.host, target + )); + run_cargo( + builder, + cargo, + args(builder.kind), + &libstd_test_stamp(builder, compiler, target), + vec![], + true, + ); } } @@ -106,6 +143,14 @@ impl Step for Rustc { cargo_subcommand(builder.kind), ); rustc_cargo(builder, &mut cargo, target); + 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 + // than just the leaf crate. + for krate in builder.in_tree_crates("rustc-main") { + cargo.arg("-p").arg(krate.name); + } builder.info(&format!("Checking compiler artifacts ({} -> {})", &compiler.host, target)); run_cargo( @@ -149,7 +194,7 @@ macro_rules! tool_check_step { builder.ensure(Rustc { target }); - let cargo = prepare_tool_cargo( + let mut cargo = prepare_tool_cargo( builder, compiler, Mode::ToolRustc, @@ -160,12 +205,14 @@ macro_rules! tool_check_step { &[], ); - println!( + cargo.arg("--all-targets"); + + builder.info(&format!( "Checking {} artifacts ({} -> {})", stringify!($name).to_lowercase(), &compiler.host.triple, target.triple - ); + )); run_cargo( builder, cargo, @@ -202,12 +249,24 @@ tool_check_step!(Rustdoc, "src/tools/rustdoc", SourceType::InTree); // rejected. tool_check_step!(Clippy, "src/tools/clippy", SourceType::InTree); +tool_check_step!(Bootstrap, "src/bootstrap", SourceType::InTree); + /// Cargo's output path for the standard library in a given stage, compiled /// by a particular compiler for the specified target. fn libstd_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check.stamp") } +/// Cargo's output path for the standard library in a given stage, compiled +/// by a particular compiler for the specified target. +fn libstd_test_stamp( + builder: &Builder<'_>, + compiler: Compiler, + target: TargetSelection, +) -> PathBuf { + builder.cargo_out(compiler, Mode::Std, target).join(".libstd-check-test.stamp") +} + /// Cargo's output path for librustc in a given stage, compiled by a particular /// compiler for the specified target. fn librustc_stamp(builder: &Builder<'_>, compiler: Compiler, target: TargetSelection) -> PathBuf { diff --git a/src/bootstrap/compile.rs b/src/bootstrap/compile.rs index 373e240cb8..40bf6c4829 100644 --- a/src/bootstrap/compile.rs +++ b/src/bootstrap/compile.rs @@ -45,7 +45,7 @@ impl Step for Std { fn make_run(run: RunConfig<'_>) { run.builder.ensure(Std { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -59,7 +59,9 @@ impl Step for Std { let target = self.target; let compiler = self.compiler; - if builder.config.keep_stage.contains(&compiler.stage) { + if builder.config.keep_stage.contains(&compiler.stage) + || builder.config.keep_stage_std.contains(&compiler.stage) + { builder.info("Warning: Using a potentially old libstd. This may not behave well."); builder.ensure(StdLink { compiler, target_compiler: compiler, target }); return; @@ -385,7 +387,7 @@ impl Step for StartupObjects { fn make_run(run: RunConfig<'_>) { run.builder.ensure(StartupObjects { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -449,12 +451,12 @@ impl Step for Rustc { const DEFAULT: bool = false; fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { - run.path("src/rustc") + run.path("compiler/rustc") } fn make_run(run: RunConfig<'_>) { run.builder.ensure(Rustc { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.build_triple()), target: run.target, }); } @@ -472,6 +474,7 @@ impl Step for Rustc { if builder.config.keep_stage.contains(&compiler.stage) { builder.info("Warning: Using a potentially old librustc. This may not behave well."); + builder.info("Warning: Use `--keep-stage-std` if you want to rebuild the compiler when it changes"); builder.ensure(RustcLink { compiler, target_compiler: compiler, target }); return; } @@ -524,7 +527,7 @@ pub fn rustc_cargo(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetSelec .arg("--features") .arg(builder.rustc_features()) .arg("--manifest-path") - .arg(builder.src.join("src/rustc/Cargo.toml")); + .arg(builder.src.join("compiler/rustc/Cargo.toml")); rustc_cargo_env(builder, cargo, target); } @@ -560,7 +563,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS } // Pass down configuration from the LLVM build into the build of - // librustc_llvm and librustc_codegen_llvm. + // rustc_llvm and rustc_codegen_llvm. // // Note that this is disabled if LLVM itself is disabled or we're in a check // build. If we are in a check build we still go ahead here presuming we've @@ -579,7 +582,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS if let Some(s) = target_config.and_then(|c| c.llvm_config.as_ref()) { cargo.env("CFG_LLVM_ROOT", s); } - // Some LLVM linker flags (-L and -l) may be needed to link librustc_llvm. + // Some LLVM linker flags (-L and -l) may be needed to link rustc_llvm. if let Some(ref s) = builder.config.llvm_ldflags { cargo.env("LLVM_LINKER_FLAGS", s); } @@ -593,7 +596,7 @@ pub fn rustc_cargo_env(builder: &Builder<'_>, cargo: &mut Cargo, target: TargetS let file = compiler_file(builder, builder.cxx(target).unwrap(), target, "libstdc++.a"); cargo.env("LLVM_STATIC_STDCPP", file); } - if builder.config.llvm_link_shared || builder.config.llvm_thin_lto { + if builder.config.llvm_link_shared { cargo.env("LLVM_LINK_SHARED", "1"); } if builder.config.llvm_use_libcxx { @@ -819,7 +822,7 @@ impl Step for Assemble { // Link the compiler binary itself into place let out_dir = builder.cargo_out(build_compiler, Mode::Rustc, host); - let rustc = out_dir.join(exe("rustc_binary", host)); + let rustc = out_dir.join(exe("rustc-main", host)); let bindir = sysroot.join("bin"); t!(fs::create_dir_all(&bindir)); let compiler = builder.rustc(target_compiler); diff --git a/src/bootstrap/config.rs b/src/bootstrap/config.rs index 8b8b01b115..8985d1fbd0 100644 --- a/src/bootstrap/config.rs +++ b/src/bootstrap/config.rs @@ -10,14 +10,25 @@ use std::ffi::OsString; use std::fmt; use std::fs; use std::path::{Path, PathBuf}; -use std::process; use crate::cache::{Interned, INTERNER}; use crate::flags::Flags; pub use crate::flags::Subcommand; +use crate::util::exe; use build_helper::t; +use merge::Merge; use serde::Deserialize; +macro_rules! check_ci_llvm { + ($name:expr) => { + assert!( + $name.is_none(), + "setting {} is incompatible with download-ci-llvm.", + stringify!($name) + ); + }; +} + /// Global configuration for the entire build and/or bootstrap. /// /// This structure is derived from a combination of both `config.toml` and @@ -31,8 +42,10 @@ use serde::Deserialize; /// `config.toml.example`. #[derive(Default)] pub struct Config { + pub changelog_seen: Option, pub ccache: Option, - pub ninja: bool, + /// Call Build::ninja() instead of this. + pub ninja_in_file: bool, pub verbose: usize, pub submodules: bool, pub fast_submodules: bool, @@ -48,17 +61,19 @@ pub struct Config { pub profiler: bool, pub ignore_git: bool, pub exclude: Vec, + pub include_default_paths: bool, pub rustc_error_format: Option, pub json_output: bool, pub test_compare_mode: bool, pub llvm_libunwind: bool, - pub skip_only_host_steps: bool, - pub on_fail: Option, - pub stage: Option, + pub stage: u32, pub keep_stage: Vec, + pub keep_stage_std: Vec, pub src: PathBuf, + // defaults to `config.toml` + pub config: PathBuf, pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, @@ -83,6 +98,7 @@ pub struct Config { pub llvm_version_suffix: Option, pub llvm_use_linker: Option, pub llvm_allow_old_toolchain: Option, + pub llvm_from_ci: bool, pub use_lld: bool, pub lld_enabled: bool, @@ -99,6 +115,7 @@ pub struct Config { pub rust_codegen_units_std: Option, pub rust_debug_assertions: bool, pub rust_debug_assertions_std: bool, + pub rust_debug_logging: bool, pub rust_debuginfo_level_rustc: u32, pub rust_debuginfo_level_std: u32, pub rust_debuginfo_level_tools: u32, @@ -259,28 +276,51 @@ impl Target { #[derive(Deserialize, Default)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlConfig { + changelog_seen: Option, build: Option, install: Option, llvm: Option, rust: Option, target: Option>, dist: Option, + profile: Option, +} + +impl Merge for TomlConfig { + fn merge( + &mut self, + TomlConfig { build, install, llvm, rust, dist, target, profile: _, changelog_seen: _ }: Self, + ) { + fn do_merge(x: &mut Option, y: Option) { + if let Some(new) = y { + if let Some(original) = x { + original.merge(new); + } else { + *x = Some(new); + } + } + }; + do_merge(&mut self.build, build); + do_merge(&mut self.install, install); + do_merge(&mut self.llvm, llvm); + do_merge(&mut self.rust, rust); + do_merge(&mut self.dist, dist); + assert!(target.is_none(), "merging target-specific config is not currently supported"); + } } /// TOML representation of various global build decisions. -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Build { build: Option, - #[serde(default)] - host: Vec, - #[serde(default)] - target: Vec, + host: Option>, + target: Option>, // This is ignored, the rust code always gets the build directory from the `BUILD_DIR` env variable build_dir: Option, cargo: Option, rustc: Option, - rustfmt: Option, /* allow bootstrap.py to use rustfmt key */ + rustfmt: Option, docs: Option, compiler_docs: Option, submodules: Option, @@ -301,10 +341,16 @@ struct Build { configure_args: Option>, local_rebuild: Option, print_step_timings: Option, + doc_stage: Option, + build_stage: Option, + test_stage: Option, + install_stage: Option, + dist_stage: Option, + bench_stage: Option, } /// TOML representation of various global install decisions. -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Install { prefix: Option, @@ -321,7 +367,7 @@ struct Install { } /// TOML representation of how the LLVM build is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Llvm { skip_rebuild: Option, @@ -345,9 +391,10 @@ struct Llvm { use_libcxx: Option, use_linker: Option, allow_old_toolchain: Option, + download_ci_llvm: Option, } -#[derive(Deserialize, Default, Clone)] +#[derive(Deserialize, Default, Clone, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Dist { sign_folder: Option, @@ -371,7 +418,7 @@ impl Default for StringOrBool { } /// TOML representation of how the Rust build is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct Rust { optimize: Option, @@ -380,6 +427,7 @@ struct Rust { codegen_units_std: Option, debug_assertions: Option, debug_assertions_std: Option, + debug_logging: Option, debuginfo_level: Option, debuginfo_level_rustc: Option, debuginfo_level_std: Option, @@ -415,7 +463,7 @@ struct Rust { } /// TOML representation of how each build target is configured. -#[derive(Deserialize, Default)] +#[derive(Deserialize, Default, Merge)] #[serde(deny_unknown_fields, rename_all = "kebab-case")] struct TomlTarget { cc: Option, @@ -450,6 +498,7 @@ impl Config { pub fn default_opts() -> Config { let mut config = Config::default(); config.llvm_optimize = true; + config.ninja_in_file = true; config.llvm_version_check = true; config.backtrace = true; config.rust_optimize = true; @@ -467,31 +516,33 @@ impl Config { config.missing_tools = false; // set by bootstrap.py - config.build = TargetSelection::from_user(&env::var("BUILD").expect("'BUILD' to be set")); - config.src = Config::path_from_python("SRC"); + config.build = TargetSelection::from_user(&env!("BUILD_TRIPLE")); + let manifest_dir = PathBuf::from(env!("CARGO_MANIFEST_DIR")); + // Undo `src/bootstrap` + config.src = manifest_dir.parent().unwrap().parent().unwrap().to_owned(); config.out = Config::path_from_python("BUILD_DIR"); - config.initial_rustc = Config::path_from_python("RUSTC"); - config.initial_cargo = Config::path_from_python("CARGO"); - config.initial_rustfmt = env::var_os("RUSTFMT").map(Config::normalize_python_path); + config.initial_cargo = PathBuf::from(env!("CARGO")); + config.initial_rustc = PathBuf::from(env!("RUSTC")); config } pub fn parse(args: &[String]) -> Config { let flags = Flags::parse(&args); - let file = flags.config.clone(); + let mut config = Config::default_opts(); config.exclude = flags.exclude; + config.include_default_paths = flags.include_default_paths; config.rustc_error_format = flags.rustc_error_format; config.json_output = flags.json_output; config.on_fail = flags.on_fail; - config.stage = flags.stage; config.jobs = flags.jobs.map(threads_from_config); config.cmd = flags.cmd; config.incremental = flags.incremental; config.dry_run = flags.dry_run; config.keep_stage = flags.keep_stage; + config.keep_stage_std = flags.keep_stage_std; config.bindir = "bin".into(); // default if let Some(value) = flags.deny_warnings { config.deny_warnings = value; @@ -503,48 +554,56 @@ impl Config { config.out = dir; } - // If --target was specified but --host wasn't specified, don't run any host-only tests. - let has_hosts = !flags.host.is_empty(); - let has_targets = !flags.target.is_empty(); - config.skip_only_host_steps = !has_hosts && has_targets; + #[cfg(test)] + let get_toml = |_| TomlConfig::default(); + #[cfg(not(test))] + let get_toml = |file: &Path| { + use std::process; - let toml = file - .map(|file| { - let contents = t!(fs::read_to_string(&file)); - match toml::from_str(&contents) { - Ok(table) => table, - Err(err) => { - println!( - "failed to parse TOML configuration '{}': {}", - file.display(), - err - ); - process::exit(2); - } + let contents = t!(fs::read_to_string(file), "`include` config not found"); + match toml::from_str(&contents) { + Ok(table) => table, + Err(err) => { + println!("failed to parse TOML configuration '{}': {}", file.display(), err); + process::exit(2); } - }) - .unwrap_or_else(TomlConfig::default); + } + }; - let build = toml.build.clone().unwrap_or_default(); - // set by bootstrap.py - config.hosts.push(config.build); - for host in build.host.iter().map(|h| TargetSelection::from_user(h)) { - if !config.hosts.contains(&host) { - config.hosts.push(host); - } + let mut toml = flags.config.as_deref().map(get_toml).unwrap_or_else(TomlConfig::default); + if let Some(include) = &toml.profile { + let mut include_path = config.src.clone(); + include_path.push("src"); + include_path.push("bootstrap"); + include_path.push("defaults"); + include_path.push(format!("config.toml.{}", include)); + let included_toml = get_toml(&include_path); + toml.merge(included_toml); } - for target in config - .hosts - .iter() - .copied() - .chain(build.target.iter().map(|h| TargetSelection::from_user(h))) - { - if !config.targets.contains(&target) { - config.targets.push(target); - } + + config.changelog_seen = toml.changelog_seen; + if let Some(cfg) = flags.config { + config.config = cfg; } - config.hosts = if !flags.host.is_empty() { flags.host } else { config.hosts }; - config.targets = if !flags.target.is_empty() { flags.target } else { config.targets }; + + let build = toml.build.unwrap_or_default(); + + config.hosts = if let Some(arg_host) = flags.host { + arg_host + } else if let Some(file_host) = build.host { + file_host.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + vec![config.build] + }; + config.targets = if let Some(arg_target) = flags.target { + arg_target + } else if let Some(file_target) = build.target { + file_target.iter().map(|h| TargetSelection::from_user(h)).collect() + } else { + // If target is *not* configured, then default to the host + // toolchains. + config.hosts.clone() + }; config.nodejs = build.nodejs.map(PathBuf::from); config.gdb = build.gdb.map(PathBuf::from); @@ -559,6 +618,9 @@ impl Config { set(&mut config.full_bootstrap, build.full_bootstrap); set(&mut config.extended, build.extended); config.tools = build.tools; + if build.rustfmt.is_some() { + config.initial_rustfmt = build.rustfmt; + } set(&mut config.verbose, build.verbose); set(&mut config.sanitizers, build.sanitizers); set(&mut config.profiler, build.profiler); @@ -566,16 +628,62 @@ impl Config { set(&mut config.configure_args, build.configure_args); set(&mut config.local_rebuild, build.local_rebuild); set(&mut config.print_step_timings, build.print_step_timings); + + // See https://github.com/rust-lang/compiler-team/issues/326 + config.stage = match config.cmd { + Subcommand::Doc { .. } => flags.stage.or(build.doc_stage).unwrap_or(0), + Subcommand::Build { .. } => flags.stage.or(build.build_stage).unwrap_or(1), + Subcommand::Test { .. } => flags.stage.or(build.test_stage).unwrap_or(1), + Subcommand::Bench { .. } => flags.stage.or(build.bench_stage).unwrap_or(2), + Subcommand::Dist { .. } => flags.stage.or(build.dist_stage).unwrap_or(2), + Subcommand::Install { .. } => flags.stage.or(build.install_stage).unwrap_or(2), + // These are all bootstrap tools, which don't depend on the compiler. + // The stage we pass shouldn't matter, but use 0 just in case. + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Setup { .. } + | Subcommand::Format { .. } => flags.stage.unwrap_or(0), + }; + + // CI should always run stage 2 builds, unless it specifically states otherwise + #[cfg(not(test))] + if flags.stage.is_none() && crate::CiEnv::current() != crate::CiEnv::None { + match config.cmd { + Subcommand::Test { .. } + | Subcommand::Doc { .. } + | Subcommand::Build { .. } + | Subcommand::Bench { .. } + | Subcommand::Dist { .. } + | Subcommand::Install { .. } => { + assert_eq!( + config.stage, 2, + "x.py should be run with `--stage 2` on CI, but was run with `--stage {}`", + config.stage, + ); + } + Subcommand::Clean { .. } + | Subcommand::Check { .. } + | Subcommand::Clippy { .. } + | Subcommand::Fix { .. } + | Subcommand::Run { .. } + | Subcommand::Setup { .. } + | Subcommand::Format { .. } => {} + } + } + config.verbose = cmp::max(config.verbose, flags.verbose); - if let Some(ref install) = toml.install { - config.prefix = install.prefix.clone().map(PathBuf::from); - config.sysconfdir = install.sysconfdir.clone().map(PathBuf::from); - config.datadir = install.datadir.clone().map(PathBuf::from); - config.docdir = install.docdir.clone().map(PathBuf::from); - set(&mut config.bindir, install.bindir.clone().map(PathBuf::from)); - config.libdir = install.libdir.clone().map(PathBuf::from); - config.mandir = install.mandir.clone().map(PathBuf::from); + if let Some(install) = toml.install { + config.prefix = install.prefix.map(PathBuf::from); + config.sysconfdir = install.sysconfdir.map(PathBuf::from); + config.datadir = install.datadir.map(PathBuf::from); + config.docdir = install.docdir.map(PathBuf::from); + set(&mut config.bindir, install.bindir.map(PathBuf::from)); + config.libdir = install.libdir.map(PathBuf::from); + config.mandir = install.mandir.map(PathBuf::from); } // We want the llvm-skip-rebuild flag to take precedence over the @@ -589,6 +697,7 @@ impl Config { let mut debug = None; let mut debug_assertions = None; let mut debug_assertions_std = None; + let mut debug_logging = None; let mut debuginfo_level = None; let mut debuginfo_level_rustc = None; let mut debuginfo_level_std = None; @@ -597,7 +706,7 @@ impl Config { let mut optimize = None; let mut ignore_git = None; - if let Some(ref llvm) = toml.llvm { + if let Some(llvm) = toml.llvm { match llvm.ccache { Some(StringOrBool::String(ref s)) => config.ccache = Some(s.to_string()), Some(StringOrBool::Bool(true)) => { @@ -605,7 +714,7 @@ impl Config { } Some(StringOrBool::Bool(false)) | None => {} } - set(&mut config.ninja, llvm.ninja); + set(&mut config.ninja_in_file, llvm.ninja); llvm_assertions = llvm.assertions; llvm_skip_rebuild = llvm_skip_rebuild.or(llvm.skip_rebuild); set(&mut config.llvm_optimize, llvm.optimize); @@ -626,12 +735,50 @@ impl Config { set(&mut config.llvm_use_libcxx, llvm.use_libcxx); config.llvm_use_linker = llvm.use_linker.clone(); config.llvm_allow_old_toolchain = llvm.allow_old_toolchain; + config.llvm_from_ci = llvm.download_ci_llvm.unwrap_or(false); + + if config.llvm_from_ci { + // None of the LLVM options, except assertions, are supported + // when using downloaded LLVM. We could just ignore these but + // that's potentially confusing, so force them to not be + // explicitly set. The defaults and CI defaults don't + // necessarily match but forcing people to match (somewhat + // arbitrary) CI configuration locally seems bad/hard. + check_ci_llvm!(llvm.optimize); + check_ci_llvm!(llvm.thin_lto); + check_ci_llvm!(llvm.release_debuginfo); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.static_libstdcpp); + check_ci_llvm!(llvm.targets); + check_ci_llvm!(llvm.experimental_targets); + check_ci_llvm!(llvm.link_jobs); + check_ci_llvm!(llvm.link_shared); + check_ci_llvm!(llvm.clang_cl); + check_ci_llvm!(llvm.version_suffix); + check_ci_llvm!(llvm.cflags); + check_ci_llvm!(llvm.cxxflags); + check_ci_llvm!(llvm.ldflags); + check_ci_llvm!(llvm.use_libcxx); + check_ci_llvm!(llvm.use_linker); + check_ci_llvm!(llvm.allow_old_toolchain); + + // CI-built LLVM is shared + config.llvm_link_shared = true; + } + + 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. + config.llvm_link_shared = true; + } } - if let Some(ref rust) = toml.rust { + if let Some(rust) = toml.rust { debug = rust.debug; debug_assertions = rust.debug_assertions; debug_assertions_std = rust.debug_assertions_std; + debug_logging = rust.debug_logging; debuginfo_level = rust.debuginfo_level; debuginfo_level_rustc = rust.debuginfo_level_rustc; debuginfo_level_std = rust.debuginfo_level_std; @@ -647,7 +794,7 @@ impl Config { set(&mut config.test_compare_mode, rust.test_compare_mode); set(&mut config.llvm_libunwind, rust.llvm_libunwind); set(&mut config.backtrace, rust.backtrace); - set(&mut config.channel, rust.channel.clone()); + set(&mut config.channel, rust.channel); set(&mut config.rust_dist_src, rust.dist_src); set(&mut config.verbose_tests, rust.verbose_tests); // in the case "false" is set explicitly, do not overwrite the command line args @@ -658,9 +805,9 @@ impl Config { set(&mut config.lld_enabled, rust.lld); set(&mut config.llvm_tools_enabled, rust.llvm_tools); config.rustc_parallel = rust.parallel_compiler.unwrap_or(false); - config.rustc_default_linker = rust.default_linker.clone(); - config.musl_root = rust.musl_root.clone().map(PathBuf::from); - config.save_toolstates = rust.save_toolstates.clone().map(PathBuf::from); + config.rustc_default_linker = rust.default_linker; + config.musl_root = rust.musl_root.map(PathBuf::from); + config.save_toolstates = rust.save_toolstates.map(PathBuf::from); set(&mut config.deny_warnings, flags.deny_warnings.or(rust.deny_warnings)); set(&mut config.backtrace_on_ice, rust.backtrace_on_ice); set(&mut config.rust_verify_llvm_ir, rust.verify_llvm_ir); @@ -677,9 +824,9 @@ impl Config { config.rust_codegen_units_std = rust.codegen_units_std.map(threads_from_config); } - if let Some(ref t) = toml.target { + if let Some(t) = toml.target { for (triple, cfg) in t { - let mut target = Target::from_triple(triple); + let mut target = Target::from_triple(&triple); if let Some(ref s) = cfg.llvm_config { target.llvm_config = Some(config.src.join(s)); @@ -693,35 +840,52 @@ impl Config { if let Some(s) = cfg.no_std { target.no_std = s; } - target.cc = cfg.cc.clone().map(PathBuf::from); - target.cxx = cfg.cxx.clone().map(PathBuf::from); - target.ar = cfg.ar.clone().map(PathBuf::from); - target.ranlib = cfg.ranlib.clone().map(PathBuf::from); - target.linker = cfg.linker.clone().map(PathBuf::from); + target.cc = cfg.cc.map(PathBuf::from); + target.cxx = cfg.cxx.map(PathBuf::from); + target.ar = cfg.ar.map(PathBuf::from); + target.ranlib = cfg.ranlib.map(PathBuf::from); + target.linker = cfg.linker.map(PathBuf::from); target.crt_static = cfg.crt_static; - target.musl_root = cfg.musl_root.clone().map(PathBuf::from); - target.musl_libdir = cfg.musl_libdir.clone().map(PathBuf::from); - target.wasi_root = cfg.wasi_root.clone().map(PathBuf::from); - target.qemu_rootfs = cfg.qemu_rootfs.clone().map(PathBuf::from); + target.musl_root = cfg.musl_root.map(PathBuf::from); + target.musl_libdir = cfg.musl_libdir.map(PathBuf::from); + target.wasi_root = cfg.wasi_root.map(PathBuf::from); + target.qemu_rootfs = cfg.qemu_rootfs.map(PathBuf::from); - config.target_config.insert(TargetSelection::from_user(triple), target); + config.target_config.insert(TargetSelection::from_user(&triple), target); } } - if let Some(ref t) = toml.dist { - config.dist_sign_folder = t.sign_folder.clone().map(PathBuf::from); - config.dist_gpg_password_file = t.gpg_password_file.clone().map(PathBuf::from); - config.dist_upload_addr = t.upload_addr.clone(); + if config.llvm_from_ci { + let triple = &config.build.triple; + let mut build_target = config + .target_config + .entry(config.build) + .or_insert_with(|| Target::from_triple(&triple)); + + check_ci_llvm!(build_target.llvm_config); + check_ci_llvm!(build_target.llvm_filecheck); + let ci_llvm_bin = config.out.join(&*config.build.triple).join("ci-llvm/bin"); + build_target.llvm_config = Some(ci_llvm_bin.join(exe("llvm-config", config.build))); + build_target.llvm_filecheck = Some(ci_llvm_bin.join(exe("FileCheck", config.build))); + } + + if let Some(t) = toml.dist { + config.dist_sign_folder = t.sign_folder.map(PathBuf::from); + config.dist_gpg_password_file = t.gpg_password_file.map(PathBuf::from); + config.dist_upload_addr = t.upload_addr; set(&mut config.rust_dist_src, t.src_tarball); set(&mut config.missing_tools, t.missing_tools); } + // Cargo does not provide a RUSTFMT environment variable, so we + // synthesize it manually. Note that we also later check the config.toml + // and set this to that path if necessary. + let rustfmt = config.initial_rustc.with_file_name(exe("rustfmt", config.build)); + config.initial_rustfmt = if rustfmt.exists() { Some(rustfmt) } else { None }; + // Now that we've reached the end of our configuration, infer the // default values for all options that we haven't otherwise stored yet. - set(&mut config.initial_rustc, build.rustc.map(PathBuf::from)); - set(&mut config.initial_cargo, build.cargo.map(PathBuf::from)); - config.llvm_skip_rebuild = llvm_skip_rebuild.unwrap_or(false); let default = false; @@ -735,6 +899,8 @@ impl Config { config.rust_debug_assertions_std = debug_assertions_std.unwrap_or(config.rust_debug_assertions); + config.rust_debug_logging = debug_logging.unwrap_or(config.rust_debug_assertions); + let with_defaults = |debuginfo_level_specific: Option| { debuginfo_level_specific.or(debuginfo_level).unwrap_or(if debug == Some(true) { 1 diff --git a/src/bootstrap/defaults/README.md b/src/bootstrap/defaults/README.md new file mode 100644 index 0000000000..f5b96db1b0 --- /dev/null +++ b/src/bootstrap/defaults/README.md @@ -0,0 +1,12 @@ +# About bootstrap defaults + +These defaults are intended to be a good starting point for working with x.py, +with the understanding that no one set of defaults make sense for everyone. + +They are still experimental, and we'd appreciate your help improving them! +If you use a setting that's not in these defaults that you think +others would benefit from, please [file an issue] or make a PR with the changes. +Similarly, if one of these defaults doesn't match what you use personally, +please open an issue to get it changed. + +[file an issue]: https://github.com/rust-lang/rust/issues/new/choose diff --git a/src/bootstrap/defaults/config.toml.codegen b/src/bootstrap/defaults/config.toml.codegen new file mode 100644 index 0000000000..a9505922ca --- /dev/null +++ b/src/bootstrap/defaults/config.toml.codegen @@ -0,0 +1,13 @@ +# These defaults are meant for contributors to the compiler who modify codegen or LLVM +[llvm] +# This enables debug-assertions in LLVM, +# catching logic errors in codegen much earlier in the process. +assertions = true + +[rust] +# This enables `RUSTC_LOG=debug`, avoiding confusing situations +# where adding `debug!()` appears to do nothing. +# However, it makes running the compiler slightly slower. +debug-logging = true +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.compiler b/src/bootstrap/defaults/config.toml.compiler new file mode 100644 index 0000000000..4772de8a2c --- /dev/null +++ b/src/bootstrap/defaults/config.toml.compiler @@ -0,0 +1,8 @@ +# These defaults are meant for contributors to the compiler who do not modify codegen or LLVM +[rust] +# This enables `RUSTC_LOG=debug`, avoiding confusing situations +# where adding `debug!()` appears to do nothing. +# However, it makes running the compiler slightly slower. +debug-logging = true +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.library b/src/bootstrap/defaults/config.toml.library new file mode 100644 index 0000000000..e4316f4d86 --- /dev/null +++ b/src/bootstrap/defaults/config.toml.library @@ -0,0 +1,10 @@ +# These defaults are meant for contributors to the standard library and documentation. +[build] +# When building the standard library, you almost never want to build the compiler itself. +build-stage = 0 +test-stage = 0 +bench-stage = 0 + +[rust] +# This greatly increases the speed of rebuilds, especially when there are only minor changes. However, it makes the initial build slightly slower. +incremental = true diff --git a/src/bootstrap/defaults/config.toml.user b/src/bootstrap/defaults/config.toml.user new file mode 100644 index 0000000000..6647061d88 --- /dev/null +++ b/src/bootstrap/defaults/config.toml.user @@ -0,0 +1,9 @@ +# These defaults are meant for users and distro maintainers building from source, without intending to make multiple changes. +[build] +# When compiling from source, you almost always want a full stage 2 build, +# which has all the latest optimizations from nightly. +build-stage = 2 +test-stage = 2 +doc-stage = 2 +# When compiling from source, you usually want all tools. +extended = true diff --git a/src/bootstrap/dist.rs b/src/bootstrap/dist.rs index d021feafbe..1887b805da 100644 --- a/src/bootstrap/dist.rs +++ b/src/bootstrap/dist.rs @@ -18,7 +18,6 @@ use build_helper::{output, t}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; use crate::cache::{Interned, INTERNER}; -use crate::channel; use crate::compile; use crate::config::TargetSelection; use crate::tool::{self, Tool}; @@ -27,27 +26,10 @@ use crate::{Compiler, DependencyType, Mode, LLVM_TOOLS}; use time::{self, Timespec}; pub fn pkgname(builder: &Builder<'_>, component: &str) -> String { - if component == "cargo" { - format!("{}-{}", component, builder.cargo_package_vers()) - } else if component == "rls" { - format!("{}-{}", component, builder.rls_package_vers()) - } else if component == "rust-analyzer" { - format!("{}-{}", component, builder.rust_analyzer_package_vers()) - } else if component == "clippy" { - format!("{}-{}", component, builder.clippy_package_vers()) - } else if component == "miri" { - format!("{}-{}", component, builder.miri_package_vers()) - } else if component == "rustfmt" { - format!("{}-{}", component, builder.rustfmt_package_vers()) - } else if component == "llvm-tools" { - format!("{}-{}", component, builder.llvm_tools_package_vers()) - } else { - assert!(component.starts_with("rust")); - format!("{}-{}", component, builder.rust_package_vers()) - } + format!("{}-{}", component, builder.rust_package_vers()) } -fn distdir(builder: &Builder<'_>) -> PathBuf { +pub(crate) fn distdir(builder: &Builder<'_>) -> PathBuf { builder.out.join("dist") } @@ -323,8 +305,8 @@ fn make_win_dist( // Warn windows-gnu users that the bundled GCC cannot compile C files builder.create( &target_bin_dir.join("GCC-WARNING.txt"), - "gcc.exe contained in this folder cannot be used for compiling C files - it is only\ - used as a linker. In order to be able to compile projects containing C code use\ + "gcc.exe contained in this folder cannot be used for compiling C files - it is only \ + used as a linker. In order to be able to compile projects containing C code use \ the GCC provided by MinGW or Cygwin.", ); @@ -569,7 +551,7 @@ impl Step for Rustc { &page_dst, &[ ("", &month_year), - ("", channel::CFG_RELEASE_NUM), + ("", &builder.version), ], ); } @@ -605,7 +587,9 @@ impl Step for DebuggerScripts { fn make_run(run: RunConfig<'_>) { run.builder.ensure(DebuggerScripts { - sysroot: run.builder.sysroot(run.builder.compiler(run.builder.top_stage, run.host)), + sysroot: run + .builder + .sysroot(run.builder.compiler(run.builder.top_stage, run.build_triple())), host: run.target, }); } @@ -791,6 +775,18 @@ impl Step for RustcDev { let stamp = compile::librustc_stamp(builder, compiler_to_use, target); copy_target_libs(builder, target, &image, &stamp); + // Copy compiler sources. + let dst_src = image.join("lib/rustlib/rustc-src/rust"); + t!(fs::create_dir_all(&dst_src)); + + let src_files = ["Cargo.lock"]; + // This is the reduced set of paths which will become the rustc-dev component + // (essentially the compiler crates and all of their path dependencies). + copy_src_dirs(builder, &builder.src, &["compiler"], &[], &dst_src); + for file in src_files.iter() { + builder.copy(&builder.src.join(file), &dst_src.join(file)); + } + let mut cmd = rust_installer(builder); cmd.arg("generate") .arg("--product-name=Rust") @@ -1020,7 +1016,7 @@ impl Step for Src { copy_src_dirs( builder, &builder.src, - &["library"], + &["library", "src/llvm-project/libunwind"], &[ // not needed and contains symlinks which rustup currently // chokes on when unpacking. @@ -1097,7 +1093,7 @@ impl Step for PlainSourceTarball { "Cargo.toml", "Cargo.lock", ]; - let src_dirs = ["src", "library"]; + let src_dirs = ["src", "compiler", "library"]; copy_src_dirs(builder, &builder.src, &src_dirs, &[], &plain_dst_src); @@ -2287,9 +2283,9 @@ impl Step for Extended { } fn add_env(builder: &Builder<'_>, cmd: &mut Command, target: TargetSelection) { - let mut parts = channel::CFG_RELEASE_NUM.split('.'); + let mut parts = builder.version.split('.'); cmd.env("CFG_RELEASE_INFO", builder.rust_version()) - .env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM) + .env("CFG_RELEASE_NUM", &builder.version) .env("CFG_RELEASE", builder.rust_release()) .env("CFG_VER_MAJOR", parts.next().unwrap()) .env("CFG_VER_MINOR", parts.next().unwrap()) @@ -2355,15 +2351,9 @@ impl Step for HashSign { cmd.arg(sign); cmd.arg(distdir(builder)); cmd.arg(today.trim()); - cmd.arg(builder.rust_package_vers()); cmd.arg(addr); - cmd.arg(builder.package_vers(&builder.release_num("cargo"))); - cmd.arg(builder.package_vers(&builder.release_num("rls"))); - cmd.arg(builder.package_vers(&builder.release_num("rust-analyzer/crates/rust-analyzer"))); - cmd.arg(builder.package_vers(&builder.release_num("clippy"))); - cmd.arg(builder.package_vers(&builder.release_num("miri"))); - cmd.arg(builder.package_vers(&builder.release_num("rustfmt"))); - cmd.arg(builder.llvm_tools_package_vers()); + cmd.arg(&builder.config.channel); + cmd.env("BUILD_MANIFEST_LEGACY", "1"); builder.create_dir(&distdir(builder)); @@ -2380,26 +2370,29 @@ impl Step for HashSign { /// Note: This function does not yet support Windows, but we also don't support /// linking LLVM tools dynamically on Windows yet. fn maybe_install_llvm(builder: &Builder<'_>, target: TargetSelection, dst_libdir: &Path) { - let src_libdir = builder.llvm_out(target).join("lib"); + if !builder.config.llvm_link_shared { + // We do not need to copy LLVM files into the sysroot if it is not + // dynamically linked; it is already included into librustc_llvm + // statically. + return; + } + // On macOS, rustc (and LLVM tools) link to an unversioned libLLVM.dylib + // instead of libLLVM-11-rust-....dylib, as on linux. It's not entirely + // clear why this is the case, though. llvm-config will emit the versioned + // paths and we don't want those in the sysroot (as we're expecting + // unversioned paths). if target.contains("apple-darwin") { + let src_libdir = builder.llvm_out(target).join("lib"); let llvm_dylib_path = src_libdir.join("libLLVM.dylib"); if llvm_dylib_path.exists() { builder.install(&llvm_dylib_path, dst_libdir, 0o644); } - return; - } - - // Usually libLLVM.so is a symlink to something like libLLVM-6.0.so. - // Since tools link to the latter rather than the former, we have to - // follow the symlink to find out what to distribute. - let llvm_dylib_path = src_libdir.join("libLLVM.so"); - if llvm_dylib_path.exists() { - let llvm_dylib_path = llvm_dylib_path.canonicalize().unwrap_or_else(|e| { - panic!("dist: Error calling canonicalize path `{}`: {}", llvm_dylib_path.display(), e); - }); - - builder.install(&llvm_dylib_path, dst_libdir, 0o644); + } else if let Ok(llvm_config) = crate::native::prebuilt_llvm_config(builder, target) { + let files = output(Command::new(llvm_config).arg("--libfiles")); + for file in files.lines() { + builder.install(Path::new(file), dst_libdir, 0o644); + } } } @@ -2499,3 +2492,161 @@ impl Step for LlvmTools { Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) } } + +// Tarball intended for internal consumption to ease rustc/std development. +// +// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct RustDev { + pub target: TargetSelection, +} + +impl Step for RustDev { + type Output = Option; + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("rust-dev") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustDev { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> Option { + let target = self.target; + + /* run only if llvm-config isn't used */ + if let Some(config) = builder.config.target_config.get(&target) { + if let Some(ref _s) = config.llvm_config { + builder.info(&format!("Skipping RustDev ({}): external LLVM", target)); + return None; + } + } + + builder.info(&format!("Dist RustDev ({})", target)); + let _time = timeit(builder); + let src = builder.src.join("src/llvm-project/llvm"); + let name = pkgname(builder, "rust-dev"); + + let tmp = tmpdir(builder); + let image = tmp.join("rust-dev-image"); + drop(fs::remove_dir_all(&image)); + + // Prepare the image directory + let dst_bindir = image.join("bin"); + t!(fs::create_dir_all(&dst_bindir)); + + let exe = builder.llvm_out(target).join("bin").join(exe("llvm-config", target)); + builder.install(&exe, &dst_bindir, 0o755); + builder.install(&builder.llvm_filecheck(target), &dst_bindir, 0o755); + + // Copy the include directory as well; needed mostly to build + // librustc_llvm properly (e.g., llvm-config.h is in here). But also + // just broadly useful to be able to link against the bundled LLVM. + builder.cp_r(&builder.llvm_out(target).join("include"), &image.join("include")); + + // Copy libLLVM.so to the target lib dir as well, so the RPATH like + // `$ORIGIN/../lib` can find it. It may also be used as a dependency + // of `rustc-dev` to support the inherited `-lLLVM` when using the + // compiler libraries. + maybe_install_llvm(builder, target, &image.join("lib")); + + // Prepare the overlay + let overlay = tmp.join("rust-dev-overlay"); + drop(fs::remove_dir_all(&overlay)); + builder.create_dir(&overlay); + builder.install(&src.join("README.txt"), &overlay, 0o644); + builder.install(&src.join("LICENSE.TXT"), &overlay, 0o644); + builder.create(&overlay.join("version"), &builder.rust_version()); + + // Generate the installer tarball + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=rust-dev-installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=rust-dev"); + + builder.run(&mut cmd); + Some(distdir(builder).join(format!("{}-{}.tar.gz", name, target.triple))) + } +} + +/// Tarball containing a prebuilt version of the build-manifest tool, intented to be used by the +/// release process to avoid cloning the monorepo and building stuff. +/// +/// Should not be considered stable by end users. +#[derive(Clone, Debug, Eq, Hash, PartialEq)] +pub struct BuildManifest { + pub target: TargetSelection, +} + +impl Step for BuildManifest { + type Output = PathBuf; + const DEFAULT: bool = false; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build-manifest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(BuildManifest { target: run.target }); + } + + fn run(self, builder: &Builder<'_>) -> PathBuf { + let build_manifest = builder.tool_exe(Tool::BuildManifest); + + let name = pkgname(builder, "build-manifest"); + let tmp = tmpdir(builder); + + // Prepare the image. + let image = tmp.join("build-manifest-image"); + let image_bin = image.join("bin"); + let _ = fs::remove_dir_all(&image); + t!(fs::create_dir_all(&image_bin)); + builder.install(&build_manifest, &image_bin, 0o755); + + // Prepare the overlay. + let overlay = tmp.join("build-manifest-overlay"); + let _ = fs::remove_dir_all(&overlay); + builder.create_dir(&overlay); + builder.create(&overlay.join("version"), &builder.rust_version()); + for file in &["COPYRIGHT", "LICENSE-APACHE", "LICENSE-MIT", "README.md"] { + builder.install(&builder.src.join(file), &overlay, 0o644); + } + + // Create the final tarball. + let mut cmd = rust_installer(builder); + cmd.arg("generate") + .arg("--product-name=Rust") + .arg("--rel-manifest-dir=rustlib") + .arg("--success-message=build-manifest installed.") + .arg("--image-dir") + .arg(&image) + .arg("--work-dir") + .arg(&tmpdir(builder)) + .arg("--output-dir") + .arg(&distdir(builder)) + .arg("--non-installed-overlay") + .arg(&overlay) + .arg(format!("--package-name={}-{}", name, self.target.triple)) + .arg("--legacy-manifest-dirs=rustlib,cargo") + .arg("--component-name=build-manifest"); + + builder.run(&mut cmd); + distdir(builder).join(format!("{}-{}.tar.gz", name, self.target.triple)) + } +} diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 2a8f43950d..aa670bd9a2 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -66,7 +66,6 @@ book!( Nomicon, "src/doc/nomicon", "nomicon"; Reference, "src/doc/reference", "reference"; RustByExample, "src/doc/rust-by-example", "rust-by-example"; - RustcBook, "src/doc/rustc", "rustc"; RustdocBook, "src/doc/rustdoc", "rustdoc"; ); @@ -434,7 +433,7 @@ impl Step for Std { .arg("-Z") .arg("unstable-options") .arg("--resource-suffix") - .arg(crate::channel::CFG_RELEASE_NUM) + .arg(&builder.version) .arg("--index-page") .arg(&builder.src.join("src/doc/index.md")); @@ -660,7 +659,7 @@ impl Step for ErrorIndex { let mut index = tool::ErrorIndex::command(builder, self.compiler); index.arg("html"); index.arg(out.join("error-index.html")); - index.arg(crate::channel::CFG_RELEASE_NUM); + index.arg(&builder.version); builder.run(&mut index); } @@ -694,6 +693,7 @@ impl Step for UnstableBookGen { builder.remove_dir(&out); let mut cmd = builder.tool_cmd(Tool::UnstableBookGen); cmd.arg(builder.src.join("library")); + cmd.arg(builder.src.join("compiler")); cmd.arg(builder.src.join("src")); cmd.arg(out); @@ -717,3 +717,72 @@ fn symlink_dir_force(config: &Config, src: &Path, dst: &Path) -> io::Result<()> symlink_dir(config, src, dst) } + +#[derive(Ord, PartialOrd, Debug, Copy, Clone, Hash, PartialEq, Eq)] +pub struct RustcBook { + pub compiler: Compiler, + pub target: TargetSelection, +} + +impl Step for RustcBook { + type Output = (); + const DEFAULT: bool = true; + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + let builder = run.builder; + run.path("src/doc/rustc").default_condition(builder.config.docs) + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(RustcBook { + compiler: run.builder.compiler(run.builder.top_stage, run.builder.config.build), + target: run.target, + }); + } + + /// Builds the rustc book. + /// + /// The lints are auto-generated by a tool, and then merged into the book + /// in the "md-doc" directory in the build output directory. Then + /// "rustbook" is used to convert it to HTML. + fn run(self, builder: &Builder<'_>) { + let out_base = builder.md_doc_out(self.target).join("rustc"); + t!(fs::create_dir_all(&out_base)); + let out_listing = out_base.join("src/lints"); + builder.cp_r(&builder.src.join("src/doc/rustc"), &out_base); + builder.info(&format!("Generating lint docs ({})", self.target)); + + let rustc = builder.rustc(self.compiler); + // The tool runs `rustc` for extracting output examples, so it needs a + // functional sysroot. + builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + let mut cmd = builder.tool_cmd(Tool::LintDocs); + cmd.arg("--src"); + cmd.arg(builder.src.join("compiler")); + cmd.arg("--out"); + cmd.arg(&out_listing); + cmd.arg("--rustc"); + cmd.arg(&rustc); + cmd.arg("--rustc-target").arg(&self.target.rustc_target_arg()); + if builder.config.verbose() { + cmd.arg("--verbose"); + } + // If the lib directories are in an unusual location (changed in + // config.toml), then this needs to explicitly update the dylib search + // path. + builder.add_rustc_lib_path(self.compiler, &mut cmd); + builder.run(&mut cmd); + // Run rustbook/mdbook to generate the HTML pages. + builder.ensure(RustbookSrc { + target: self.target, + name: INTERNER.intern_str("rustc"), + src: INTERNER.intern_path(out_base), + }); + if is_explicit_request(builder, "src/doc/rustc") { + let out = builder.doc_out(self.target); + let index = out.join("rustc").join("index.html"); + open(builder, &index); + } + } +} diff --git a/src/bootstrap/flags.rs b/src/bootstrap/flags.rs index 38b3a32e3b..4bf4a19363 100644 --- a/src/bootstrap/flags.rs +++ b/src/bootstrap/flags.rs @@ -7,6 +7,7 @@ use std::env; use std::path::PathBuf; use std::process; +use build_helper::t; use getopts::Options; use crate::builder::Builder; @@ -19,14 +20,16 @@ pub struct Flags { pub on_fail: Option, pub stage: Option, pub keep_stage: Vec, + pub keep_stage_std: Vec, - pub host: Vec, - pub target: Vec, + pub host: Option>, + pub target: Option>, pub config: Option, pub jobs: Option, pub cmd: Subcommand, pub incremental: bool, pub exclude: Vec, + pub include_default_paths: bool, pub rustc_error_format: Option, pub json_output: bool, pub dry_run: bool, @@ -88,6 +91,9 @@ pub enum Subcommand { Run { paths: Vec, }, + Setup { + path: String, + }, } impl Default for Subcommand { @@ -98,7 +104,6 @@ impl Default for Subcommand { impl Flags { pub fn parse(args: &[String]) -> Flags { - let mut extra_help = String::new(); let mut subcommand_help = String::from( "\ Usage: x.py [options] [...] @@ -129,6 +134,11 @@ To learn more about a subcommand, run `./x.py -h`", opts.optmulti("", "host", "host targets to build", "HOST"); opts.optmulti("", "target", "target targets to build", "TARGET"); opts.optmulti("", "exclude", "build paths to exclude", "PATH"); + opts.optflag( + "", + "include-default-paths", + "include default paths in addition to the provided ones", + ); opts.optopt("", "on-fail", "command to run on failure", "CMD"); opts.optflag("", "dry-run", "dry run; don't build anything"); opts.optopt( @@ -145,6 +155,13 @@ To learn more about a subcommand, run `./x.py -h`", (pass multiple times to keep e.g., both stages 0 and 1)", "N", ); + opts.optmulti( + "", + "keep-stage-std", + "stage(s) of the standard library to keep without recompiling \ + (pass multiple times to keep e.g., both stages 0 and 1)", + "N", + ); opts.optopt("", "src", "path to the root of the rust checkout", "DIR"); let j_msg = format!( "number of jobs to run in parallel; \ @@ -170,16 +187,6 @@ To learn more about a subcommand, run `./x.py -h`", "VALUE", ); - // fn usage() - let usage = - |exit_code: i32, opts: &Options, subcommand_help: &str, extra_help: &str| -> ! { - println!("{}", opts.usage(subcommand_help)); - if !extra_help.is_empty() { - println!("{}", extra_help); - } - process::exit(exit_code); - }; - // We can't use getopt to parse the options until we have completed specifying which // options are valid, but under the current implementation, some options are conditional on // the subcommand. Therefore we must manually identify the subcommand first, so that we can @@ -202,6 +209,7 @@ To learn more about a subcommand, run `./x.py -h`", || (s == "install") || (s == "run") || (s == "r") + || (s == "setup") }); let subcommand = match subcommand { Some(s) => s, @@ -263,12 +271,38 @@ To learn more about a subcommand, run `./x.py -h`", _ => {} }; + // fn usage() + let usage = |exit_code: i32, opts: &Options, verbose: bool, subcommand_help: &str| -> ! { + let mut extra_help = String::new(); + + // All subcommands except `clean` can have an optional "Available paths" section + if verbose { + let config = Config::parse(&["build".to_string()]); + let build = Build::new(config); + + let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); + extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); + } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") { + extra_help.push_str( + format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand) + .as_str(), + ); + } + + println!("{}", opts.usage(subcommand_help)); + if !extra_help.is_empty() { + println!("{}", extra_help); + } + process::exit(exit_code); + }; + // Done specifying what options are possible, so do the getopts parsing let matches = opts.parse(&args[..]).unwrap_or_else(|e| { // Invalid argument/option format println!("\n{}\n", e); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, false, &subcommand_help); }); + // Extra sanity check to make sure we didn't hit this crazy corner case: // // ./x.py --frobulate clean build @@ -385,7 +419,7 @@ Arguments: ./x.py test src/test/ui --bless ./x.py test src/test/ui --compare-mode nll - Note that `test src/test/* --stage N` does NOT depend on `build src/rustc --stage N`; + Note that `test src/test/* --stage N` does NOT depend on `build compiler/rustc --stage N`; just like `build library/std --stage N` it tests the compiler produced by the previous stage. @@ -430,30 +464,28 @@ Arguments: At least a tool needs to be called.", ); } + "setup" => { + subcommand_help.push_str( + "\n +Arguments: + This subcommand accepts a 'profile' to use for builds. For example: + + ./x.py setup library + + The profile is optional and you will be prompted interactively if it is not given.", + ); + } _ => {} }; // Get any optional paths which occur after the subcommand - let paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); + let mut paths = matches.free[1..].iter().map(|p| p.into()).collect::>(); let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); - - // All subcommands except `clean` can have an optional "Available paths" section - if matches.opt_present("verbose") { - let config = Config::parse(&["build".to_string()]); - let build = Build::new(config); - - let maybe_rules_help = Builder::get_help(&build, subcommand.as_str()); - extra_help.push_str(maybe_rules_help.unwrap_or_default().as_str()); - } else if !(subcommand.as_str() == "clean" || subcommand.as_str() == "fmt") { - extra_help.push_str( - format!("Run `./x.py {} -h -v` to see a list of available paths.", subcommand) - .as_str(), - ); - } + let verbose = matches.opt_present("verbose"); // User passed in -h/--help? if matches.opt_present("help") { - usage(0, &opts, &subcommand_help, &extra_help); + usage(0, &opts, verbose, &subcommand_help); } let cmd = match subcommand.as_str() { @@ -483,7 +515,7 @@ Arguments: "clean" => { if !paths.is_empty() { println!("\nclean does not take a path argument\n"); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } Subcommand::Clean { all: matches.opt_present("all") } @@ -494,12 +526,26 @@ Arguments: "run" | "r" => { if paths.is_empty() { println!("\nrun requires at least a path!\n"); - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } Subcommand::Run { paths } } + "setup" => { + let path = if paths.len() > 1 { + println!("\nat most one profile can be passed to setup\n"); + usage(1, &opts, verbose, &subcommand_help) + } else if let Some(path) = paths.pop() { + t!(path.into_os_string().into_string().map_err(|path| format!( + "{} is not a valid UTF8 string", + path.to_string_lossy() + ))) + } else { + t!(crate::setup::interactive_path()) + }; + Subcommand::Setup { path } + } _ => { - usage(1, &opts, &subcommand_help, &extra_help); + usage(1, &opts, verbose, &subcommand_help); } }; @@ -508,7 +554,9 @@ Arguments: println!("--stage not supported for x.py check, always treated as stage 0"); process::exit(1); } - if matches.opt_str("keep-stage").is_some() { + if matches.opt_str("keep-stage").is_some() + || matches.opt_str("keep-stage-std").is_some() + { println!("--keep-stage not supported for x.py check, only one stage available"); process::exit(1); } @@ -526,14 +574,31 @@ Arguments: .into_iter() .map(|j| j.parse().expect("`keep-stage` should be a number")) .collect(), - host: split(&matches.opt_strs("host")) + keep_stage_std: matches + .opt_strs("keep-stage-std") .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::>(), - target: split(&matches.opt_strs("target")) - .into_iter() - .map(|x| TargetSelection::from_user(&x)) - .collect::>(), + .map(|j| j.parse().expect("`keep-stage-std` should be a number")) + .collect(), + host: if matches.opt_present("host") { + Some( + split(&matches.opt_strs("host")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::>(), + ) + } else { + None + }, + target: if matches.opt_present("target") { + Some( + split(&matches.opt_strs("target")) + .into_iter() + .map(|x| TargetSelection::from_user(&x)) + .collect::>(), + ) + } else { + None + }, config: cfg_file, jobs: matches.opt_str("jobs").map(|j| j.parse().expect("`jobs` should be a number")), cmd, @@ -542,6 +607,7 @@ Arguments: .into_iter() .map(|p| p.into()) .collect::>(), + include_default_paths: matches.opt_present("include-default-paths"), deny_warnings: parse_deny_warnings(&matches), llvm_skip_rebuild: matches.opt_str("llvm-skip-rebuild").map(|s| s.to_lowercase()).map( |s| s.parse::().expect("`llvm-skip-rebuild` should be either true or false"), @@ -620,7 +686,7 @@ impl Subcommand { } fn split(s: &[String]) -> Vec { - s.iter().flat_map(|s| s.split(',')).map(|s| s.to_string()).collect() + s.iter().flat_map(|s| s.split(',')).filter(|s| !s.is_empty()).map(|s| s.to_string()).collect() } fn parse_deny_warnings(matches: &getopts::Matches) -> Option { diff --git a/src/bootstrap/format.rs b/src/bootstrap/format.rs index 6f93082e67..0ae9f9712d 100644 --- a/src/bootstrap/format.rs +++ b/src/bootstrap/format.rs @@ -105,15 +105,13 @@ pub fn format(build: &Build, check: bool) { eprintln!("./x.py fmt is not supported on this channel"); std::process::exit(1); }); - let src = build.src.clone(); - let walker = WalkBuilder::new(&build.src).types(matcher).overrides(ignore_fmt).build_parallel(); + let src = &build.src; + let walker = WalkBuilder::new(src).types(matcher).overrides(ignore_fmt).build_parallel(); walker.run(|| { - let src = src.clone(); - let rustfmt_path = rustfmt_path.clone(); Box::new(move |entry| { let entry = t!(entry); if entry.file_type().map_or(false, |t| t.is_file()) { - rustfmt(&src, &rustfmt_path, &entry.path(), check); + rustfmt(src, &rustfmt_path, &entry.path(), check); } ignore::WalkState::Continue }) diff --git a/src/bootstrap/install.rs b/src/bootstrap/install.rs index d9ee3bc90f..074f5cd73f 100644 --- a/src/bootstrap/install.rs +++ b/src/bootstrap/install.rs @@ -192,7 +192,7 @@ install!((self, builder, _config), builder.ensure(dist::Docs { host: self.target }); install_docs(builder, self.compiler.stage, self.target); }; - Std, "library/std", true, only_hosts: true, { + Std, "library/std", true, only_hosts: false, { for target in &builder.targets { builder.ensure(dist::Std { compiler: self.compiler, diff --git a/src/bootstrap/lib.rs b/src/bootstrap/lib.rs index a42ee11bd6..852316a8d8 100644 --- a/src/bootstrap/lib.rs +++ b/src/bootstrap/lib.rs @@ -103,8 +103,6 @@ //! More documentation can be found in each respective module below, and you can //! also check out the `src/bootstrap/README.md` file for more information. -#![feature(drain_filter)] - use std::cell::{Cell, RefCell}; use std::collections::{HashMap, HashSet}; use std::env; @@ -143,6 +141,7 @@ mod metadata; mod native; mod run; mod sanity; +mod setup; mod test; mod tool; mod toolstate; @@ -167,7 +166,7 @@ mod job { use crate::cache::{Interned, INTERNER}; pub use crate::config::Config; -use crate::flags::Subcommand; +pub use crate::flags::Subcommand; const LLVM_TOOLS: &[&str] = &[ "llvm-nm", // used to inspect binaries; it shows symbol names, their sizes and visibility @@ -220,6 +219,9 @@ pub struct Build { /// User-specified configuration from `config.toml`. config: Config, + // Version information + version: String, + // Properties derived from the above configuration src: PathBuf, out: PathBuf, @@ -300,9 +302,6 @@ pub enum Mode { /// Build librustc, and compiler libraries, placing output in the "stageN-rustc" directory. Rustc, - /// Build codegen libraries, placing output in the "stageN-codegen" directory - Codegen, - /// Build a tool, placing output in the "stage0-bootstrap-tools" /// directory. This is for miscellaneous sets of tools that are built /// using the bootstrap stage0 compiler in its entirety (target libraries @@ -385,6 +384,10 @@ impl Build { .unwrap() .to_path_buf(); + let version = std::fs::read_to_string(src.join("src").join("version")) + .expect("failed to read src/version"); + let version = version.trim(); + let mut build = Build { initial_rustc: config.initial_rustc.clone(), initial_cargo: config.initial_cargo.clone(), @@ -400,6 +403,7 @@ impl Build { targets: config.targets.clone(), config, + version: version.to_string(), src, out, @@ -438,8 +442,7 @@ impl Build { .next() .unwrap() .trim(); - let my_version = channel::CFG_RELEASE_NUM; - if local_release.split('.').take(2).eq(my_version.split('.').take(2)) { + if local_release.split('.').take(2).eq(version.split('.').take(2)) { build.verbose(&format!("auto-detected local-rebuild {}", local_release)); build.local_rebuild = true; } @@ -468,6 +471,10 @@ impl Build { return clean::clean(self, all); } + if let Subcommand::Setup { path: include_name } = &self.config.cmd { + return setup::setup(&self.config.src, include_name); + } + { let builder = builder::Builder::new(&self); if let Some(path) = builder.paths.get(0) { @@ -546,6 +553,16 @@ impl Build { if self.config.llvm_enabled() { features.push_str(" llvm"); } + + // If debug logging is on, then we want the default for tracing: + // https://github.com/tokio-rs/tracing/blob/3dd5c03d907afdf2c39444a29931833335171554/tracing/src/level_filters.rs#L26 + // which is everything (including debug/trace/etc.) + // if its unset, if debug_assertions is on, then debug_logging will also be on + // as well as tracing *ignoring* this feature when debug_assertions is on + if !self.config.rust_debug_logging { + features.push_str(" max_level_info"); + } + features } @@ -572,7 +589,6 @@ impl Build { let suffix = match mode { Mode::Std => "-std", Mode::Rustc => "-rustc", - Mode::Codegen => "-codegen", Mode::ToolBootstrap => "-bootstrap-tools", Mode::ToolStd | Mode::ToolRustc => "-tools", }; @@ -617,6 +633,10 @@ impl Build { /// /// If no custom `llvm-config` was specified then Rust's llvm will be used. fn is_rust_llvm(&self, target: TargetSelection) -> bool { + if self.config.llvm_from_ci && target == self.config.build { + return true; + } + match self.config.target_config.get(&target) { Some(ref c) => c.llvm_config.is_none(), None => true, @@ -650,7 +670,7 @@ impl Build { } } else { let base = self.llvm_out(self.config.build).join("build"); - let base = if !self.config.ninja && self.config.build.contains("msvc") { + let base = if !self.ninja() && self.config.build.contains("msvc") { if self.config.llvm_optimize { if self.config.llvm_release_debuginfo { base.join("RelWithDebInfo") @@ -777,7 +797,7 @@ impl Build { match which { GitRepo::Rustc => { - let sha = self.rust_sha().unwrap_or(channel::CFG_RELEASE_NUM); + let sha = self.rust_sha().unwrap_or(&self.version); Some(format!("/rustc/{}", sha)) } GitRepo::Llvm => Some(String::from("/rustc/llvm")), @@ -850,22 +870,32 @@ impl Build { } /// Returns the path to the linker for the given target if it needs to be overridden. - fn linker(&self, target: TargetSelection, can_use_lld: bool) -> Option<&Path> { + fn linker(&self, target: TargetSelection) -> Option<&Path> { if let Some(linker) = self.config.target_config.get(&target).and_then(|c| c.linker.as_ref()) { Some(linker) + } else if target.contains("vxworks") { + // need to use CXX compiler as linker to resolve the exception functions + // that are only existed in CXX libraries + Some(self.cxx[&target].path()) } else if target != self.config.build && util::use_host_linker(target) && !target.contains("msvc") { Some(self.cc(target)) - } else if can_use_lld && self.config.use_lld && self.build == target { + } else if self.config.use_lld && !self.is_fuse_ld_lld(target) && self.build == target { Some(&self.initial_lld) } else { None } } + // LLD is used through `-fuse-ld=lld` rather than directly. + // Only MSVC targets use LLD directly at the moment. + fn is_fuse_ld_lld(&self, target: TargetSelection) -> bool { + self.config.use_lld && !target.contains("msvc") + } + /// Returns if this target should statically link the C runtime, if specified fn crt_static(&self, target: TargetSelection) -> Option { if target.contains("pc-windows-msvc") { @@ -998,7 +1028,7 @@ impl Build { /// Returns the value of `release` above for Rust itself. fn rust_release(&self) -> String { - self.release(channel::CFG_RELEASE_NUM) + self.release(&self.version) } /// Returns the "package version" for a component given the `num` release @@ -1018,41 +1048,7 @@ impl Build { /// Returns the value of `package_vers` above for Rust itself. fn rust_package_vers(&self) -> String { - self.package_vers(channel::CFG_RELEASE_NUM) - } - - /// Returns the value of `package_vers` above for Cargo - fn cargo_package_vers(&self) -> String { - self.package_vers(&self.release_num("cargo")) - } - - /// Returns the value of `package_vers` above for rls - fn rls_package_vers(&self) -> String { - self.package_vers(&self.release_num("rls")) - } - - /// Returns the value of `package_vers` above for rust-analyzer - fn rust_analyzer_package_vers(&self) -> String { - self.package_vers(&self.release_num("rust-analyzer/crates/rust-analyzer")) - } - - /// Returns the value of `package_vers` above for clippy - fn clippy_package_vers(&self) -> String { - self.package_vers(&self.release_num("clippy")) - } - - /// Returns the value of `package_vers` above for miri - fn miri_package_vers(&self) -> String { - self.package_vers(&self.release_num("miri")) - } - - /// Returns the value of `package_vers` above for rustfmt - fn rustfmt_package_vers(&self) -> String { - self.package_vers(&self.release_num("rustfmt")) - } - - fn llvm_tools_package_vers(&self) -> String { - self.package_vers(channel::CFG_RELEASE_NUM) + self.package_vers(&self.version) } fn llvm_tools_vers(&self) -> String { @@ -1069,7 +1065,7 @@ impl Build { /// Note that this is a descriptive string which includes the commit date, /// sha, version, etc. fn rust_version(&self) -> String { - self.rust_info.version(self, channel::CFG_RELEASE_NUM) + self.rust_info.version(self, &self.version) } /// Returns the full commit hash. @@ -1324,6 +1320,43 @@ impl Build { } fs::remove_file(f).unwrap_or_else(|_| panic!("failed to remove {:?}", f)); } + + /// Returns if config.ninja is enabled, and checks for ninja existence, + /// exiting with a nicer error message if not. + fn ninja(&self) -> bool { + let mut cmd_finder = crate::sanity::Finder::new(); + + if self.config.ninja_in_file { + // Some Linux distros rename `ninja` to `ninja-build`. + // CMake can work with either binary name. + if cmd_finder.maybe_have("ninja-build").is_none() + && cmd_finder.maybe_have("ninja").is_none() + { + eprintln!( + " +Couldn't find required command: ninja +You should install ninja, or set ninja=false in config.toml +" + ); + std::process::exit(1); + } + } + + // If ninja isn't enabled but we're building for MSVC then we try + // doubly hard to enable it. It was realized in #43767 that the msbuild + // CMake generator for MSVC doesn't respect configuration options like + // disabling LLVM assertions, which can often be quite important! + // + // In these cases we automatically enable Ninja if we find it in the + // environment. + if !self.config.ninja_in_file && self.config.build.contains("msvc") { + if cmd_finder.maybe_have("ninja").is_some() { + return true; + } + } + + self.config.ninja_in_file + } } #[cfg(unix)] diff --git a/src/bootstrap/native.rs b/src/bootstrap/native.rs index 97d9dbdd63..6bba00ee85 100644 --- a/src/bootstrap/native.rs +++ b/src/bootstrap/native.rs @@ -19,7 +19,6 @@ use std::process::Command; use build_helper::{output, t}; use crate::builder::{Builder, RunConfig, ShouldRun, Step}; -use crate::channel; use crate::config::TargetSelection; use crate::util::{self, exe}; use crate::GitRepo; @@ -56,7 +55,7 @@ pub fn prebuilt_llvm_config( let out_dir = builder.llvm_out(target); let mut llvm_config_ret_dir = builder.llvm_out(builder.config.build); - if !builder.config.build.contains("msvc") || builder.config.ninja { + if !builder.config.build.contains("msvc") || builder.ninja() { llvm_config_ret_dir.push("build"); } llvm_config_ret_dir.push("bin"); @@ -129,6 +128,12 @@ impl Step for Llvm { Err(m) => m, }; + if builder.config.llvm_link_shared + && (target.contains("windows") || target.contains("apple-darwin")) + { + panic!("shared linking to LLVM is not currently supported on {}", target.triple); + } + builder.info(&format!("Building LLVM for {}", target)); t!(stamp.remove()); let _time = util::timeit(&builder); @@ -169,7 +174,6 @@ impl Step for Llvm { .define("LLVM_INCLUDE_TESTS", "OFF") .define("LLVM_INCLUDE_DOCS", "OFF") .define("LLVM_INCLUDE_BENCHMARKS", "OFF") - .define("WITH_POLLY", "OFF") .define("LLVM_ENABLE_TERMINFO", "OFF") .define("LLVM_ENABLE_LIBEDIT", "OFF") .define("LLVM_ENABLE_BINDINGS", "OFF") @@ -178,11 +182,9 @@ impl Step for Llvm { .define("LLVM_TARGET_ARCH", target_native.split('-').next().unwrap()) .define("LLVM_DEFAULT_TARGET_TRIPLE", target_native); - if !target.contains("netbsd") && target != "aarch64-apple-darwin" { + if target != "aarch64-apple-darwin" { cfg.define("LLVM_ENABLE_ZLIB", "ON"); } else { - // FIXME: Enable zlib on NetBSD too - // https://github.com/rust-lang/rust/pull/72696#issuecomment-641517185 cfg.define("LLVM_ENABLE_ZLIB", "OFF"); } @@ -208,7 +210,10 @@ impl Step for Llvm { // which saves both memory during parallel links and overall disk space // for the tools. We don't do this on every platform as it doesn't work // equally well everywhere. - if builder.llvm_link_tools_dynamically(target) { + // + // If we're not linking rustc to a dynamic LLVM, though, then don't link + // tools to it. + if builder.llvm_link_tools_dynamically(target) && builder.config.llvm_link_shared { cfg.define("LLVM_LINK_LLVM_DYLIB", "ON"); } @@ -295,7 +300,7 @@ impl Step for Llvm { // release number on the dev channel. cfg.define("LLVM_VERSION_SUFFIX", "-rust-dev"); } else { - let suffix = format!("-rust-{}-{}", channel::CFG_RELEASE_NUM, builder.config.channel); + let suffix = format!("-rust-{}-{}", builder.version, builder.config.channel); cfg.define("LLVM_VERSION_SUFFIX", suffix); } @@ -307,10 +312,6 @@ impl Step for Llvm { cfg.define("LLVM_TEMPORARILY_ALLOW_OLD_TOOLCHAIN", "YES"); } - if let Some(ref python) = builder.config.python { - cfg.define("PYTHON_EXECUTABLE", python); - } - configure_cmake(builder, target, &mut cfg, true); // FIXME: we don't actually need to build all LLVM tools and all LLVM @@ -365,7 +366,7 @@ fn configure_cmake( // own build directories. cfg.env("DESTDIR", ""); - if builder.config.ninja { + if builder.ninja() { cfg.generator("Ninja"); } cfg.target(&target.triple).host(&builder.config.build.triple); @@ -397,7 +398,7 @@ fn configure_cmake( // MSVC with CMake uses msbuild by default which doesn't respect these // vars that we'd otherwise configure. In that case we just skip this // entirely. - if target.contains("msvc") && !builder.config.ninja { + if target.contains("msvc") && !builder.ninja() { return; } @@ -407,7 +408,7 @@ fn configure_cmake( }; // Handle msvc + ninja + ccache specially (this is what the bots use) - if target.contains("msvc") && builder.config.ninja && builder.config.ccache.is_some() { + if target.contains("msvc") && builder.ninja() && builder.config.ccache.is_some() { let mut wrap_cc = env::current_exe().expect("failed to get cwd"); wrap_cc.set_file_name("sccache-plus-cl.exe"); @@ -629,7 +630,14 @@ impl Step for TestHelpers { if builder.config.dry_run { return; } - let target = self.target; + // The x86_64-fortanix-unknown-sgx target doesn't have a working C + // toolchain. However, some x86_64 ELF objects can be linked + // without issues. Use this hack to compile the test helpers. + let target = if self.target == "x86_64-fortanix-unknown-sgx" { + TargetSelection::from_user("x86_64-unknown-linux-gnu") + } else { + self.target + }; let dst = builder.test_helpers_out(target); let src = builder.src.join("src/test/auxiliary/rust_test_helpers.c"); if up_to_date(&src, &dst.join("librust_test_helpers.a")) { @@ -653,7 +661,6 @@ impl Step for TestHelpers { } cfg.compiler(builder.cc(target)); } - cfg.cargo_metadata(false) .out_dir(&dst) .target(&target.triple) diff --git a/src/bootstrap/run.rs b/src/bootstrap/run.rs index 9005347142..7c64e5a0aa 100644 --- a/src/bootstrap/run.rs +++ b/src/bootstrap/run.rs @@ -1,5 +1,7 @@ use crate::builder::{Builder, RunConfig, ShouldRun, Step}; +use crate::dist::distdir; use crate::tool::Tool; +use build_helper::output; use std::process::Command; #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] @@ -10,7 +12,7 @@ impl Step for ExpandYamlAnchors { /// Runs the `expand-yaml_anchors` tool. /// - /// This tool in `src/tools` read the CI configuration files written in YAML and expands the + /// This tool in `src/tools` reads the CI configuration files written in YAML and expands the /// anchors in them, since GitHub Actions doesn't support them. fn run(self, builder: &Builder<'_>) { builder.info("Expanding YAML anchors in the GitHub Actions configuration"); @@ -41,3 +43,42 @@ fn try_run(builder: &Builder<'_>, cmd: &mut Command) -> bool { } true } + +#[derive(Debug, PartialOrd, Ord, Copy, Clone, Hash, PartialEq, Eq)] +pub struct BuildManifest; + +impl Step for BuildManifest { + type Output = (); + const ONLY_HOSTS: bool = true; + + fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { + run.path("src/tools/build-manifest") + } + + fn make_run(run: RunConfig<'_>) { + run.builder.ensure(BuildManifest); + } + + fn run(self, builder: &Builder<'_>) { + // This gets called by `promote-release` + // (https://github.com/rust-lang/promote-release). + let mut cmd = builder.tool_cmd(Tool::BuildManifest); + let sign = builder.config.dist_sign_folder.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.sign-folder` in `config.toml`\n\n") + }); + let addr = builder.config.dist_upload_addr.as_ref().unwrap_or_else(|| { + panic!("\n\nfailed to specify `dist.upload-addr` in `config.toml`\n\n") + }); + + let today = output(Command::new("date").arg("+%Y-%m-%d")); + + cmd.arg(sign); + cmd.arg(distdir(builder)); + cmd.arg(today.trim()); + cmd.arg(addr); + cmd.arg(&builder.config.channel); + + builder.create_dir(&distdir(builder)); + builder.run(&mut cmd); + } +} diff --git a/src/bootstrap/sanity.rs b/src/bootstrap/sanity.rs index f89bef50de..6826d177a4 100644 --- a/src/bootstrap/sanity.rs +++ b/src/bootstrap/sanity.rs @@ -20,18 +20,18 @@ use build_helper::{output, t}; use crate::config::Target; use crate::Build; -struct Finder { +pub struct Finder { cache: HashMap>, path: OsString, } impl Finder { - fn new() -> Self { + pub fn new() -> Self { Self { cache: HashMap::new(), path: env::var_os("PATH").unwrap_or_default() } } - fn maybe_have>(&mut self, cmd: S) -> Option { - let cmd: OsString = cmd.as_ref().into(); + pub fn maybe_have>(&mut self, cmd: S) -> Option { + let cmd: OsString = cmd.into(); let path = &self.path; self.cache .entry(cmd.clone()) @@ -54,7 +54,7 @@ impl Finder { .clone() } - fn must_have>(&mut self, cmd: S) -> PathBuf { + pub fn must_have>(&mut self, cmd: S) -> PathBuf { self.maybe_have(&cmd).unwrap_or_else(|| { panic!("\n\ncouldn't find required command: {:?}\n\n", cmd.as_ref()); }) @@ -95,30 +95,6 @@ pub fn check(build: &mut Build) { cmd_finder.must_have("cmake"); } - // Ninja is currently only used for LLVM itself. - if building_llvm { - if build.config.ninja { - // Some Linux distros rename `ninja` to `ninja-build`. - // CMake can work with either binary name. - if cmd_finder.maybe_have("ninja-build").is_none() { - cmd_finder.must_have("ninja"); - } - } - - // If ninja isn't enabled but we're building for MSVC then we try - // doubly hard to enable it. It was realized in #43767 that the msbuild - // CMake generator for MSVC doesn't respect configuration options like - // disabling LLVM assertions, which can often be quite important! - // - // In these cases we automatically enable Ninja if we find it in the - // environment. - if !build.config.ninja && build.config.build.contains("msvc") { - if cmd_finder.maybe_have("ninja").is_some() { - build.config.ninja = true; - } - } - } - build.config.python = build .config .python diff --git a/src/bootstrap/setup.rs b/src/bootstrap/setup.rs new file mode 100644 index 0000000000..9d3a889aa0 --- /dev/null +++ b/src/bootstrap/setup.rs @@ -0,0 +1,88 @@ +use crate::t; +use std::path::{Path, PathBuf}; +use std::{ + env, fs, + io::{self, Write}, +}; + +pub fn setup(src_path: &Path, include_name: &str) { + let cfg_file = env::var_os("BOOTSTRAP_CONFIG").map(PathBuf::from); + + if cfg_file.as_ref().map_or(false, |f| f.exists()) { + let file = cfg_file.unwrap(); + println!( + "error: you asked `x.py` to setup a new config file, but one already exists at `{}`", + file.display() + ); + println!( + "help: try adding `profile = \"{}\"` at the top of {}", + include_name, + file.display() + ); + println!( + "note: this will use the configuration in {}/src/bootstrap/defaults/config.toml.{}", + src_path.display(), + include_name + ); + std::process::exit(1); + } + + let path = cfg_file.unwrap_or_else(|| src_path.join("config.toml")); + let settings = format!( + "# Includes one of the default files in src/bootstrap/defaults\n\ + profile = \"{}\"\n", + include_name + ); + t!(fs::write(path, settings)); + + let include_path = + format!("{}/src/bootstrap/defaults/config.toml.{}", src_path.display(), include_name); + println!("`x.py` will now use the configuration at {}", include_path); + + let suggestions = match include_name { + "codegen" | "compiler" => &["check", "build", "test"][..], + "library" => &["check", "build", "test library/std", "doc"], + "user" => &["dist", "build"], + _ => return, + }; + + println!("To get started, try one of the following commands:"); + for cmd in suggestions { + println!("- `x.py {}`", cmd); + } + + if include_name != "user" { + println!( + "For more suggestions, see https://rustc-dev-guide.rust-lang.org/building/suggested.html" + ); + } +} + +// Used to get the path for `Subcommand::Setup` +pub fn interactive_path() -> io::Result { + let mut input = String::new(); + println!( + "Welcome to the Rust project! What do you want to do with x.py? +a) Contribute to the standard library +b) Contribute to the compiler +c) Contribute to the compiler, and also modify LLVM or codegen +d) Install Rust from source" + ); + let template = loop { + print!("Please choose one (a/b/c/d): "); + io::stdout().flush()?; + io::stdin().read_line(&mut input)?; + break match input.trim().to_lowercase().as_str() { + "a" | "lib" | "library" => "library", + "b" | "compiler" => "compiler", + "c" | "llvm" => "llvm", + "d" | "user" | "maintainer" => "maintainer", + _ => { + println!("error: unrecognized option '{}'", input.trim()); + println!("note: press Ctrl+C to exit"); + continue; + } + }; + }; + Ok(template.to_owned()) +} diff --git a/src/bootstrap/test.rs b/src/bootstrap/test.rs index afa72b5d58..00522ee6b6 100644 --- a/src/bootstrap/test.rs +++ b/src/bootstrap/test.rs @@ -270,7 +270,7 @@ impl Step for Rls { &[], ); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); cargo.arg("--").args(builder.config.cmd.test_args()); if try_run(builder, &mut cargo.into()) { @@ -328,7 +328,7 @@ impl Step for Rustfmt { t!(fs::create_dir_all(&dir)); cargo.env("RUSTFMT_TEST_DIR", dir); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if try_run(builder, &mut cargo.into()) { builder.save_toolstate("rustfmt", ToolState::TestPass); @@ -449,7 +449,7 @@ impl Step for Miri { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); if !try_run(builder, &mut cargo.into()) { return; @@ -554,7 +554,7 @@ impl Step for Clippy { cargo.arg("--").args(builder.config.cmd.test_args()); - builder.add_rustc_lib_path(compiler, &mut cargo); + cargo.add_rustc_lib_path(builder, compiler); builder.run(&mut cargo.into()); } @@ -584,7 +584,7 @@ impl Step for RustdocTheme { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.target); run.builder.ensure(RustdocTheme { compiler }); } @@ -600,8 +600,11 @@ impl Step for RustdocTheme { .env("CFG_RELEASE_CHANNEL", &builder.config.channel) .env("RUSTDOC_REAL", builder.rustdoc(self.compiler)) .env("RUSTC_BOOTSTRAP", "1"); - if let Some(linker) = builder.linker(self.compiler.host, true) { - cmd.env("RUSTC_TARGET_LINKER", linker); + if let Some(linker) = builder.linker(self.compiler.host) { + cmd.env("RUSTDOC_LINKER", linker); + } + if builder.is_fuse_ld_lld(self.compiler.host) { + cmd.env("RUSTDOC_FUSE_LD_LLD", "1"); } try_run(builder, &mut cmd); } @@ -633,7 +636,7 @@ impl Step for RustdocJSStd { .arg("--crate-name") .arg("std") .arg("--resource-suffix") - .arg(crate::channel::CFG_RELEASE_NUM) + .arg(&builder.version) .arg("--doc-folder") .arg(builder.doc_out(self.target)) .arg("--test-folder") @@ -648,7 +651,6 @@ impl Step for RustdocJSStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocJSNotStd { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -663,8 +665,8 @@ impl Step for RustdocJSNotStd { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocJSNotStd { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocJSNotStd { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -685,7 +687,6 @@ impl Step for RustdocJSNotStd { #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq)] pub struct RustdocUi { - pub host: TargetSelection, pub target: TargetSelection, pub compiler: Compiler, } @@ -700,8 +701,8 @@ impl Step for RustdocUi { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); - run.builder.ensure(RustdocUi { host: run.host, target: run.target, compiler }); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); + run.builder.ensure(RustdocUi { target: run.target, compiler }); } fn run(self, builder: &Builder<'_>) { @@ -734,7 +735,7 @@ impl Step for Tidy { /// for the `dev` or `nightly` channels. fn run(self, builder: &Builder<'_>) { let mut cmd = builder.tool_cmd(Tool::Tidy); - cmd.arg(builder.src.join("src")); + cmd.arg(&builder.src); cmd.arg(&builder.initial_cargo); if builder.is_verbose() { cmd.arg("--verbose"); @@ -870,7 +871,7 @@ macro_rules! test_definitions { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler(run.builder.top_stage, run.host); + let compiler = run.builder.compiler(run.builder.top_stage, run.build_triple()); run.builder.ensure($name { compiler, target: run.target }); } @@ -1061,17 +1062,22 @@ impl Step for Compiletest { flags.push("-Zunstable-options".to_string()); flags.push(builder.config.cmd.rustc_args().join(" ")); - // Don't use LLD here since we want to test that rustc finds and uses a linker by itself. - if let Some(linker) = builder.linker(target, false) { + if let Some(linker) = builder.linker(target) { cmd.arg("--linker").arg(linker); } let mut hostflags = flags.clone(); hostflags.push(format!("-Lnative={}", builder.test_helpers_out(compiler.host).display())); + if builder.is_fuse_ld_lld(compiler.host) { + hostflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--host-rustcflags").arg(hostflags.join(" ")); let mut targetflags = flags; targetflags.push(format!("-Lnative={}", builder.test_helpers_out(target).display())); + if builder.is_fuse_ld_lld(target) { + targetflags.push("-Clink-args=-fuse-ld=lld".to_string()); + } cmd.arg("--target-rustcflags").arg(targetflags.join(" ")); cmd.arg("--docck-python").arg(builder.python()); @@ -1275,6 +1281,8 @@ impl Step for Compiletest { cmd.arg("--rustfix-coverage"); } + cmd.env("BOOTSTRAP_CARGO", &builder.initial_cargo); + builder.ci_env.force_coloring_in_ci(&mut cmd); builder.info(&format!( @@ -1414,7 +1422,7 @@ macro_rules! test_book { fn make_run(run: RunConfig<'_>) { run.builder.ensure($name { - compiler: run.builder.compiler(run.builder.top_stage, run.host), + compiler: run.builder.compiler(run.builder.top_stage, run.target), }); } @@ -1461,7 +1469,7 @@ impl Step for ErrorIndex { // error_index_generator depends on librustdoc. Use the compiler that // is normally used to build rustdoc for other tests (like compiletest // tests in src/test/rustdoc) so that it shares the same artifacts. - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); + let compiler = run.builder.compiler_for(run.builder.top_stage, run.target, run.target); run.builder.ensure(ErrorIndex { compiler }); } @@ -1565,7 +1573,7 @@ impl Step for CrateLibrustc { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); for krate in builder.in_tree_crates("rustc-main") { if krate.path.ends_with(&run.path) { @@ -1612,7 +1620,7 @@ impl Step for CrateNotDefault { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let test_kind = builder.kind.into(); @@ -1660,7 +1668,7 @@ impl Step for Crate { fn make_run(run: RunConfig<'_>) { let builder = run.builder; - let compiler = builder.compiler(builder.top_stage, run.host); + let compiler = builder.compiler(builder.top_stage, run.build_triple()); let make = |mode: Mode, krate: &CargoCrate| { let test_kind = builder.kind.into(); @@ -1754,11 +1762,6 @@ impl Step for Crate { cargo.arg("--quiet"); } - if builder.config.cmd.bless() { - // Bless `expect!` tests. - cargo.env("UPDATE_EXPECT", "1"); - } - if target.contains("emscripten") { cargo.env( format!("CARGO_TARGET_{}_RUNNER", envify(&target.triple)), @@ -1805,7 +1808,7 @@ impl Step for CrateRustdoc { let test_kind = builder.kind.into(); - builder.ensure(CrateRustdoc { host: run.host, test_kind }); + builder.ensure(CrateRustdoc { host: run.target, test_kind }); } fn run(self, builder: &Builder<'_>) { @@ -2021,6 +2024,8 @@ impl Step for Bootstrap { .current_dir(builder.src.join("src/bootstrap")) .env("RUSTFLAGS", "-Cdebuginfo=2") .env("CARGO_TARGET_DIR", builder.out.join("bootstrap")) + .env("BOOTSTRAP_OUTPUT_DIRECTORY", &builder.config.out) + .env("BOOTSTRAP_INITIAL_CARGO", &builder.config.initial_cargo) .env("RUSTC_BOOTSTRAP", "1") .env("RUSTC", &builder.initial_rustc); if let Some(flags) = option_env!("RUSTFLAGS") { @@ -2051,7 +2056,6 @@ impl Step for Bootstrap { #[derive(Debug, Copy, Clone, PartialEq, Eq, Hash)] pub struct TierCheck { pub compiler: Compiler, - target: TargetSelection, } impl Step for TierCheck { @@ -2064,18 +2068,19 @@ impl Step for TierCheck { } fn make_run(run: RunConfig<'_>) { - let compiler = run.builder.compiler_for(run.builder.top_stage, run.host, run.host); - run.builder.ensure(TierCheck { compiler, target: run.host }); + let compiler = + run.builder.compiler_for(run.builder.top_stage, run.builder.build.build, run.target); + run.builder.ensure(TierCheck { compiler }); } /// Tests the Platform Support page in the rustc book. fn run(self, builder: &Builder<'_>) { - builder.ensure(compile::Std { compiler: self.compiler, target: self.target }); + builder.ensure(compile::Std { compiler: self.compiler, target: self.compiler.host }); let mut cargo = tool::prepare_tool_cargo( builder, self.compiler, - Mode::ToolRustc, - self.target, + Mode::ToolStd, + self.compiler.host, "run", "src/tools/tier-check", SourceType::InTree, diff --git a/src/bootstrap/tool.rs b/src/bootstrap/tool.rs index fe3f1e7802..290e374485 100644 --- a/src/bootstrap/tool.rs +++ b/src/bootstrap/tool.rs @@ -7,7 +7,6 @@ use std::process::{exit, Command}; use build_helper::t; use crate::builder::{Builder, Cargo as CargoCommand, RunConfig, ShouldRun, Step}; -use crate::channel; use crate::channel::GitInfo; use crate::compile; use crate::config::TargetSelection; @@ -162,13 +161,15 @@ impl Step for ToolBuild { "the following dependencies are duplicated although they \ have the same features enabled:" ); - for (id, cur, prev) in duplicates.drain_filter(|(_, cur, prev)| cur.2 == prev.2) { + let (same, different): (Vec<_>, Vec<_>) = + duplicates.into_iter().partition(|(_, cur, prev)| cur.2 == prev.2); + for (id, cur, prev) in same { println!(" {}", id); // same features println!(" `{}` ({:?})\n `{}` ({:?})", cur.0, cur.1, prev.0, prev.1); } println!("the following dependencies have different features:"); - for (id, cur, prev) in duplicates { + for (id, cur, prev) in different { println!(" {}", id); let cur_features: HashSet<_> = cur.2.into_iter().collect(); let prev_features: HashSet<_> = prev.2.into_iter().collect(); @@ -253,7 +254,7 @@ pub fn prepare_tool_cargo( cargo.env("CFG_RELEASE", builder.rust_release()); cargo.env("CFG_RELEASE_CHANNEL", &builder.config.channel); cargo.env("CFG_VERSION", builder.rust_version()); - cargo.env("CFG_RELEASE_NUM", channel::CFG_RELEASE_NUM); + cargo.env("CFG_RELEASE_NUM", &builder.version); let info = GitInfo::new(builder.config.ignore_git, &dir); if let Some(sha) = info.sha() { @@ -365,6 +366,7 @@ bootstrap_tool!( RustInstaller, "src/tools/rust-installer", "fabricate", is_external_tool = true; RustdocTheme, "src/tools/rustdoc-themes", "rustdoc-themes"; ExpandYamlAnchors, "src/tools/expand-yaml-anchors", "expand-yaml-anchors"; + LintDocs, "src/tools/lint-docs", "lint-docs"; ); #[derive(Debug, Copy, Clone, Hash, PartialEq, Eq, Ord, PartialOrd)] @@ -467,8 +469,13 @@ impl Step for Rustdoc { } fn make_run(run: RunConfig<'_>) { - run.builder - .ensure(Rustdoc { compiler: run.builder.compiler(run.builder.top_stage, run.host) }); + run.builder.ensure(Rustdoc { + // Note: this is somewhat unique in that we actually want a *target* + // compiler here, because rustdoc *is* a compiler. We won't be using + // this as the compiler to build with, but rather this is "what + // compiler are we producing"? + compiler: run.builder.compiler(run.builder.top_stage, run.target), + }); } fn run(self, builder: &Builder<'_>) -> PathBuf { @@ -697,6 +704,10 @@ impl<'a> Builder<'a> { } add_dylib_path(lib_paths, &mut cmd); + + // Provide a RUSTC for this command to use. + cmd.env("RUSTC", &self.initial_rustc); + cmd } } diff --git a/src/build_helper/Cargo.toml b/src/build_helper/Cargo.toml index 04c7820b45..2420f1b7f1 100644 --- a/src/build_helper/Cargo.toml +++ b/src/build_helper/Cargo.toml @@ -5,5 +5,4 @@ authors = ["The Rust Project Developers"] edition = "2018" [lib] -name = "build_helper" path = "lib.rs" diff --git a/src/ci/azure-pipelines/auto.yml b/src/ci/azure-pipelines/auto.yml index 2185b0d30d..37c2e9bc35 100644 --- a/src/ci/azure-pipelines/auto.yml +++ b/src/ci/azure-pipelines/auto.yml @@ -18,45 +18,9 @@ trigger: - auto jobs: -- job: macOS +- job: Dummy timeoutInMinutes: 600 pool: - vmImage: macos-10.15 + vmImage: ubuntu-16.04 steps: - - template: steps/run.yml - variables: - # We're still uploading macOS builds from Azure Pipelines. - - group: prod-credentials - strategy: - matrix: - # OSX builders running tests, these run the full test suite. - # NO_DEBUG_ASSERTIONS=1 to make them go faster, but also do have some - # runners that run `//ignore-debug` tests. - # - # Note that the compiler is compiled to target 10.8 here because the Xcode - # version that we're using, 8.2, cannot compile LLVM for OSX 10.7. - x86_64-apple: - SCRIPT: ./x.py --stage 2 test - INITIAL_RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - - dist-x86_64-apple: - SCRIPT: ./x.py dist - INITIAL_RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - - dist-x86_64-apple-alt: - SCRIPT: ./x.py dist - INITIAL_RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 + - bash: echo "We're running this job since bors is still gating on Azure" diff --git a/src/ci/azure-pipelines/steps/run.yml b/src/ci/azure-pipelines/steps/run.yml deleted file mode 100644 index 34fc4d76fa..0000000000 --- a/src/ci/azure-pipelines/steps/run.yml +++ /dev/null @@ -1,142 +0,0 @@ -##################################### -## READ BEFORE CHANGING THIS ## -##################################### - -# We're in the process of evaluating GitHub Actions as a possible replacement -# for Azure Pipelines, and at the moment the configuration is duplicated -# between the two CI providers. Be sure to also change the configuration in -# src/ci/github-actions when changing this file. - -##################################### - -# FIXME(linux): need to configure core dumps, enable them, and then dump -# backtraces on failure from all core dumps: -# -# - bash: sudo apt install gdb -# - bash: sudo sh -c 'echo "/checkout/obj/cores/core.%p.%E" > /proc/sys/kernel/core_pattern' -# -# Check travis config for `gdb --batch` command to print all crash logs - -steps: - -# Configure our CI_JOB_NAME variable which log analyzers can use for the main -# step to see what's going on. -- bash: | - builder=$(echo $AGENT_JOBNAME | cut -d ' ' -f 2) - echo "##vso[task.setvariable variable=CI_JOB_NAME]$builder" - displayName: Configure Job Name - -# Disable automatic line ending conversion, which is enabled by default on -# Azure's Windows image. Having the conversion enabled caused regressions both -# in our test suite (it broke miri tests) and in the ecosystem, since we -# started shipping install scripts with CRLF endings instead of the old LF. -# -# Note that we do this a couple times during the build as the PATH and current -# user/directory change, e.g. when mingw is enabled. -- bash: git config --global core.autocrlf false - displayName: "Disable git automatic line ending conversion" - -- checkout: self - fetchDepth: 2 - -- bash: src/ci/scripts/setup-environment.sh - displayName: Setup environment - -- bash: src/ci/scripts/clean-disk.sh - displayName: Clean disk - -- bash: src/ci/scripts/should-skip-this.sh - displayName: Decide whether to run this job - -- bash: src/ci/scripts/collect-cpu-stats.sh - displayName: Collect CPU-usage statistics in the background - -- bash: src/ci/scripts/dump-environment.sh - displayName: Show the current environment - -- bash: src/ci/scripts/install-sccache.sh - displayName: Install sccache - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-clang.sh - displayName: Install clang - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-wix.sh - displayName: Install wix - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/symlink-build-dir.sh - displayName: Ensure the build happens on a partition with enough space - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/disable-git-crlf-conversion.sh - displayName: "Disable git automatic line ending conversion (on C:/)" - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-msys2.sh - displayName: Install msys2 - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-mingw.sh - displayName: Install MinGW - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/install-ninja.sh - displayName: Install ninja - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/enable-docker-ipv6.sh - displayName: Enable IPv6 on Docker - condition: and(succeeded(), not(variables.SKIP_JOB)) - -# Disable automatic line ending conversion (again). On Windows, when we're -# installing dependencies, something switches the git configuration directory or -# re-enables autocrlf. We've not tracked down the exact cause -- and there may -# be multiple -- but this should ensure submodules are checked out with the -# appropriate line endings. -- bash: src/ci/scripts/disable-git-crlf-conversion.sh - displayName: Disable git automatic line ending conversion - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/checkout-submodules.sh - displayName: Checkout submodules - condition: and(succeeded(), not(variables.SKIP_JOB)) - -- bash: src/ci/scripts/verify-line-endings.sh - displayName: Verify line endings - condition: and(succeeded(), not(variables.SKIP_JOB)) - -# Ensure the `aws` CLI is installed so we can deploy later on, cache docker -# images, etc. -- bash: src/ci/scripts/install-awscli.sh - condition: and(succeeded(), not(variables.SKIP_JOB)) - displayName: Install awscli - -- bash: src/ci/scripts/run-build-from-ci.sh - timeoutInMinutes: 600 - env: - AWS_ACCESS_KEY_ID: $(SCCACHE_AWS_ACCESS_KEY_ID) - AWS_SECRET_ACCESS_KEY: $(SCCACHE_AWS_SECRET_ACCESS_KEY) - TOOLSTATE_REPO_ACCESS_TOKEN: $(TOOLSTATE_REPO_ACCESS_TOKEN) - condition: and(succeeded(), not(variables.SKIP_JOB)) - displayName: Run build - -- bash: src/ci/scripts/upload-artifacts.sh - env: - AWS_ACCESS_KEY_ID: $(UPLOAD_AWS_ACCESS_KEY_ID) - AWS_SECRET_ACCESS_KEY: $(UPLOAD_AWS_SECRET_ACCESS_KEY) - displayName: Upload artifacts - # Adding a condition on DEPLOY=1 or DEPLOY_ALT=1 is not needed as all deploy - # builders *should* have the AWS credentials available. Still, explicitly - # adding the condition is helpful as this way CI will not silently skip - # deploying artifacts from a dist builder if the variables are misconfigured, - # erroring about invalid credentials instead. - condition: | - and( - succeeded(), not(variables.SKIP_JOB), - or( - variables.UPLOAD_AWS_SECRET_ACCESS_KEY, - eq(variables.DEPLOY, '1'), eq(variables.DEPLOY_ALT, '1') - ) - ) diff --git a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile index b6cf60a5e1..e54d0eafb4 100644 --- a/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile +++ b/src/ci/docker/host-aarch64/aarch64-gnu/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:20.04 RUN apt-get update && DEBIAN_FRONTEND=noninteractive apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/arm-android/Dockerfile b/src/ci/docker/host-x86_64/arm-android/Dockerfile index add2647fa1..f675252fb1 100644 --- a/src/ci/docker/host-x86_64/arm-android/Dockerfile +++ b/src/ci/docker/host-x86_64/arm-android/Dockerfile @@ -31,7 +31,7 @@ ENV TARGETS=arm-linux-androideabi ENV RUST_CONFIGURE_ARGS --arm-linux-androideabi-ndk=/android/ndk/arm-14 -ENV SCRIPT python3 ../x.py --stage 2 test --target $TARGETS +ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile index 1f3092c551..9370f5debb 100644 --- a/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/armhf-gnu/Dockerfile @@ -14,6 +14,7 @@ RUN apt-get update -y && apt-get install -y --no-install-recommends \ libc6-dev \ libc6-dev-armhf-cross \ make \ + ninja-build \ python3 \ qemu-system-arm \ xz-utils @@ -57,7 +58,7 @@ RUN curl https://www.busybox.net/downloads/busybox-1.21.1.tar.bz2 | tar xjf - && # Download the ubuntu rootfs, which we'll use as a chroot for all our tests. WORKDIR /tmp RUN mkdir rootfs/ubuntu -RUN curl http://cdimage.ubuntu.com/ubuntu-base/releases/16.04/release/ubuntu-base-16.04-core-armhf.tar.gz | \ +RUN curl http://cdimage.ubuntu.com/ubuntu-base/releases/16.04/release/ubuntu-base-16.04.6-base-armhf.tar.gz | \ tar xzf - -C rootfs/ubuntu && \ cd rootfs && mkdir proc sys dev etc etc/init.d @@ -78,6 +79,6 @@ COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh ENV RUST_CONFIGURE_ARGS --qemu-armhf-rootfs=/tmp/rootfs -ENV SCRIPT python3 ../x.py --stage 2 test --target arm-unknown-linux-gnueabihf +ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target arm-unknown-linux-gnueabihf ENV NO_CHANGE_USER=1 diff --git a/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile b/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile index a4d9f53eba..e04f6409f5 100644 --- a/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/asmjs/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -33,7 +34,7 @@ ENV EMCC_CFLAGS=-O1 # Emscripten installation is user-specific ENV NO_CHANGE_USER=1 -ENV SCRIPT python3 ../x.py --stage 2 test --target $TARGETS +ENV SCRIPT python3 ../x.py --stage 2 test --host='' --target $TARGETS # This is almost identical to the wasm32-unknown-emscripten target, so # running with assertions again is not useful diff --git a/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile index 19df9d6cf6..34c4874121 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-powerpcspe-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile index 62d0bfc71b..a8e7583ccb 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-sparc64-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile index 5e743f0818..5d594a8058 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-dragonfly/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile index 61b3179d55..5ddd3f1803 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-haiku/Dockerfile @@ -16,6 +16,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libcurl4-openssl-dev \ libssl-dev \ make \ + ninja-build \ nasm \ pkg-config \ python3 \ diff --git a/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile b/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile index b32c498c74..e9188b42f5 100644 --- a/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/dist-x86_64-redox/Dockerfile @@ -19,4 +19,4 @@ ENV \ CXX_x86_64_unknown_redox=x86_64-unknown-redox-g++ ENV RUST_CONFIGURE_ARGS --enable-extended -ENV SCRIPT python3 ../x.py dist --target x86_64-unknown-redox +ENV SCRIPT python3 ../x.py dist --host='' --target x86_64-unknown-redox diff --git a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile index e3c35000eb..3c39a63849 100644 --- a/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/disabled/riscv64gc-linux/Dockerfile @@ -20,6 +20,7 @@ RUN apt-get update -y && apt-get install -y --no-install-recommends \ libc6-dev \ libc6-dev-riscv64-cross \ make \ + ninja-build \ patch \ python3 \ qemu-system-misc \ diff --git a/src/ci/docker/host-x86_64/dist-android/Dockerfile b/src/ci/docker/host-x86_64/dist-android/Dockerfile index 6d38e19956..258dcea06e 100644 --- a/src/ci/docker/host-x86_64/dist-android/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-android/Dockerfile @@ -32,7 +32,7 @@ ENV RUST_CONFIGURE_ARGS \ --x86_64-linux-android-ndk=/android/ndk/x86_64-21 \ --disable-docs -ENV SCRIPT python3 ../x.py dist --target $TARGETS +ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS COPY scripts/sccache.sh /scripts/ RUN sh /scripts/sccache.sh diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile index ba93f6ad82..88b13eab2d 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-arm-linux/Dockerfile @@ -6,6 +6,14 @@ RUN sh /scripts/cross-apt-packages.sh COPY scripts/crosstool-ng-1.24.sh /scripts/ RUN sh /scripts/crosstool-ng-1.24.sh +WORKDIR /build + +COPY scripts/musl-toolchain.sh /build/ +# We need to mitigate rust-lang/rust#34978 when compiling musl itself as well +RUN CFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + CXXFLAGS="-Wa,--compress-debug-sections=none -Wl,--compress-debug-sections=none" \ + bash musl-toolchain.sh aarch64 && rm -rf build + COPY scripts/rustbuild-setup.sh /scripts/ RUN sh /scripts/rustbuild-setup.sh USER rustbuild @@ -25,7 +33,8 @@ ENV CC_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-gcc \ AR_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-ar \ CXX_arm_unknown_linux_gnueabi=arm-unknown-linux-gnueabi-g++ -ENV HOSTS=arm-unknown-linux-gnueabi +ENV HOSTS=arm-unknown-linux-gnueabi,aarch64-unknown-linux-musl -ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs +ENV RUST_CONFIGURE_ARGS --enable-full-tools --disable-docs --musl-root-aarch64=/usr/local/aarch64-linux-musl \ + --set target.aarch64-unknown-linux-musl.crt-static=false ENV SCRIPT python3 ../x.py dist --host $HOSTS --target $HOSTS diff --git a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config index 1dcdbd1a90..66709a4004 100644 --- a/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config +++ b/src/ci/docker/host-x86_64/dist-arm-linux/arm-linux-gnueabi.config @@ -14,6 +14,7 @@ CT_CONFIGURE_has_autoconf_2_65_or_newer=y CT_CONFIGURE_has_autoreconf_2_65_or_newer=y CT_CONFIGURE_has_automake_1_15_or_newer=y CT_CONFIGURE_has_gnu_m4_1_4_12_or_newer=y +CT_CONFIGURE_has_python_3_4_or_newer=y CT_CONFIGURE_has_bison_2_7_or_newer=y CT_CONFIGURE_has_python=y CT_CONFIGURE_has_git=y @@ -132,12 +133,6 @@ CT_ARCH_ARM=y # CT_ARCH_XTENSA is not set CT_ARCH="arm" CT_ARCH_CHOICE_KSYM="ARM" -# CT_ARCH_ALPHA_EV4 is not set -# CT_ARCH_ALPHA_EV45 is not set -# CT_ARCH_ALPHA_EV5 is not set -# CT_ARCH_ALPHA_EV56 is not set -# CT_ARCH_ALPHA_EV6 is not set -# CT_ARCH_ALPHA_EV67 is not set CT_ARCH_CPU="" CT_ARCH_TUNE="" CT_ARCH_ARM_SHOW=y @@ -371,8 +366,6 @@ CT_ALL_BINUTILS_CHOICES="BINUTILS" # C-library # CT_LIBC_GLIBC=y -# CT_LIBC_NEWLIB is not set -# CT_LIBC_NONE is not set # CT_LIBC_UCLIBC is not set CT_LIBC="glibc" CT_LIBC_CHOICE_KSYM="GLIBC" @@ -389,6 +382,7 @@ CT_GLIBC_USE="GLIBC" CT_GLIBC_PKG_NAME="glibc" CT_GLIBC_SRC_RELEASE=y CT_GLIBC_PATCH_ORDER="global" +# CT_GLIBC_V_2_29 is not set # CT_GLIBC_V_2_28 is not set # CT_GLIBC_V_2_27 is not set # CT_GLIBC_V_2_26 is not set @@ -407,7 +401,6 @@ CT_GLIBC_ARCHIVE_FORMATS=".tar.xz .tar.bz2 .tar.gz" CT_GLIBC_SIGNATURE_FORMAT="packed/.sig" CT_GLIBC_2_29_or_older=y CT_GLIBC_older_than_2_29=y -CT_GLIBC_REQUIRE_older_than_2_29=y CT_GLIBC_2_27_or_older=y CT_GLIBC_older_than_2_27=y CT_GLIBC_2_26_or_older=y @@ -447,12 +440,6 @@ CT_GLIBC_FORCE_UNWIND=y CT_GLIBC_KERNEL_VERSION_AS_HEADERS=y # CT_GLIBC_KERNEL_VERSION_CHOSEN is not set CT_GLIBC_MIN_KERNEL="3.2.101" -# CT_GLIBC_SSP_DEFAULT is not set -# CT_GLIBC_SSP_NO is not set -# CT_GLIBC_SSP_YES is not set -# CT_GLIBC_SSP_ALL is not set -# CT_GLIBC_SSP_STRONG is not set -# CT_NEWLIB_USE_REDHAT is not set CT_ALL_LIBC_CHOICES="AVR_LIBC BIONIC GLIBC MINGW_W64 MOXIEBOX MUSL NEWLIB NONE UCLIBC" CT_LIBC_SUPPORT_THREADS_ANY=y CT_LIBC_SUPPORT_THREADS_NATIVE=y diff --git a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile index 162d7a1345..c734202eef 100644 --- a/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i586-gnu-i586-i686-musl/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -46,5 +47,5 @@ ENV CFLAGS_i586_unknown_linux_musl=-Wa,-mrelax-relocations=no ENV TARGETS=i586-unknown-linux-gnu,i686-unknown-linux-musl ENV SCRIPT \ - python3 ../x.py --stage 2 test --target $TARGETS && \ - python3 ../x.py dist --target $TARGETS,i586-unknown-linux-musl + python3 ../x.py --stage 2 test --host='' --target $TARGETS && \ + python3 ../x.py dist --host='' --target $TARGETS,i586-unknown-linux-musl diff --git a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile index bbbd632c6b..7db6e58c4d 100644 --- a/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-freebsd/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile index 9a051caa06..22d7cbb0d1 100644 --- a/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-i686-linux/Dockerfile @@ -93,6 +93,7 @@ ENV RUST_CONFIGURE_ARGS \ --enable-profiler \ --set target.i686-unknown-linux-gnu.linker=clang \ --build=i686-unknown-linux-gnu \ + --set llvm.ninja=false \ --set rust.jemalloc ENV SCRIPT python2.7 ../x.py dist --build $HOSTS --host $HOSTS --target $HOSTS ENV CARGO_TARGET_I686_UNKNOWN_LINUX_GNU_LINKER=clang diff --git a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile index 57a7fc25b5..cb5c17c25a 100644 --- a/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile index 63f1028e2b..31146e3ead 100644 --- a/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile index a51edbc9c7..dadd50a7e6 100644 --- a/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mips64el-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile index 908cef90ce..d2d65565b1 100644 --- a/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-mipsel-linux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile index fdd777e824..104b608529 100644 --- a/src/ci/docker/host-x86_64/dist-various-1/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-1/Dockerfile @@ -15,6 +15,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ libncurses-dev \ gawk \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -83,10 +84,6 @@ RUN env \ CXX=arm-linux-gnueabihf-g++ CXXFLAGS="-march=armv7-a" \ bash musl.sh armv7hf && \ env \ - CC=aarch64-linux-gnu-gcc \ - CXX=aarch64-linux-gnu-g++ \ - bash musl.sh aarch64 && \ - env \ CC=mips-openwrt-linux-gcc \ CXX=mips-openwrt-linux-g++ \ bash musl.sh mips && \ @@ -129,7 +126,6 @@ ENV TARGETS=$TARGETS,arm-unknown-linux-musleabihf ENV TARGETS=$TARGETS,armv5te-unknown-linux-gnueabi ENV TARGETS=$TARGETS,armv5te-unknown-linux-musleabi ENV TARGETS=$TARGETS,armv7-unknown-linux-musleabihf -ENV TARGETS=$TARGETS,aarch64-unknown-linux-musl ENV TARGETS=$TARGETS,aarch64-unknown-none ENV TARGETS=$TARGETS,aarch64-unknown-none-softfloat ENV TARGETS=$TARGETS,sparc64-unknown-linux-gnu @@ -184,7 +180,6 @@ ENV RUST_CONFIGURE_ARGS \ --musl-root-arm=/musl-arm \ --musl-root-armhf=/musl-armhf \ --musl-root-armv7hf=/musl-armv7hf \ - --musl-root-aarch64=/musl-aarch64 \ --musl-root-mips=/musl-mips \ --musl-root-mipsel=/musl-mipsel \ --musl-root-mips64=/musl-mips64 \ @@ -192,8 +187,8 @@ ENV RUST_CONFIGURE_ARGS \ --disable-docs ENV SCRIPT \ - python3 ../x.py --stage 2 test --target $RUN_MAKE_TARGETS src/test/run-make && \ - python3 ../x.py dist --target $TARGETS + python3 ../x.py --stage 2 test --host='' --target $RUN_MAKE_TARGETS src/test/run-make && \ + python3 ../x.py dist --host='' --target $TARGETS # sccache COPY scripts/sccache.sh /scripts/ diff --git a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile index 3081f29aef..47a66f7480 100644 --- a/src/ci/docker/host-x86_64/dist-various-2/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-various-2/Dockerfile @@ -110,4 +110,4 @@ ENV RUST_CONFIGURE_ARGS --enable-extended --enable-lld --disable-docs \ --set target.wasm32-wasi.wasi-root=/wasm32-wasi \ --musl-root-armv7=/musl-armv7 -ENV SCRIPT python3 ../x.py dist --target $TARGETS +ENV SCRIPT python3 ../x.py dist --host='' --target $TARGETS diff --git a/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh b/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh index 3354a796c3..b7ff6cd4e4 100755 --- a/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh +++ b/src/ci/docker/host-x86_64/dist-various-2/build-cloudabi-toolchain.sh @@ -16,6 +16,7 @@ apt-get install -y --no-install-recommends \ git \ lld-5.0 \ make \ + ninja-build \ python \ sudo \ xz-utils diff --git a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile index bfc768f993..1075947c9c 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-freebsd/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ clang \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile index 7681eaef60..f5c4d638c1 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-linux/Dockerfile @@ -96,8 +96,11 @@ ENV RUST_CONFIGURE_ARGS \ --set target.x86_64-unknown-linux-gnu.ar=/rustroot/bin/llvm-ar \ --set target.x86_64-unknown-linux-gnu.ranlib=/rustroot/bin/llvm-ranlib \ --set llvm.thin-lto=false \ + --set llvm.ninja=false \ --set rust.jemalloc -ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS +ENV SCRIPT python2.7 ../x.py dist --host $HOSTS --target $HOSTS \ + --include-default-paths \ + src/tools/build-manifest ENV CARGO_TARGET_X86_64_UNKNOWN_LINUX_GNU_LINKER=clang # This is the only builder which will create source tarballs diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh deleted file mode 100755 index 38fea2a809..0000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-git.sh +++ /dev/null @@ -1,15 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl -L https://www.kernel.org/pub/software/scm/git/git-2.10.0.tar.gz | tar xzf - - -cd git-2.10.0 -make configure -hide_output ./configure --prefix=/rustroot -hide_output make -j10 -hide_output make install - -cd .. -rm -rf git-2.10.0 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh deleted file mode 100755 index b623e53583..0000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-headers.sh +++ /dev/null @@ -1,16 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://cdn.kernel.org/pub/linux/kernel/v3.x/linux-3.2.84.tar.xz | unxz | tar x - -cd linux-3.2.84 -hide_output make mrproper -hide_output make INSTALL_HDR_PATH=dest headers_install - -find dest/include \( -name .install -o -name ..install.cmd \) -delete -yes | cp -fr dest/include/* /usr/include - -cd .. -rm -rf linux-3.2.84 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh b/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh deleted file mode 100755 index a678d353d5..0000000000 --- a/src/ci/docker/host-x86_64/dist-x86_64-linux/build-perl.sh +++ /dev/null @@ -1,21 +0,0 @@ -#!/usr/bin/env bash - -set -ex -source shared.sh - -curl https://www.cpan.org/src/5.0/perl-5.28.0.tar.gz | \ - tar xzf - - -cd perl-5.28.0 - -# Gotta do some hackery to tell python about our custom OpenSSL build, but other -# than that fairly normal. -CC=gcc \ -CFLAGS='-I /rustroot/include -fgnu89-inline' \ -LDFLAGS='-L /rustroot/lib -L /rustroot/lib64' \ - hide_output ./configure.gnu -hide_output make -j10 -hide_output make install - -cd .. -rm -rf perl-5.28.0 diff --git a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile index ab6515cd1f..904ee64db3 100644 --- a/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile +++ b/src/ci/docker/host-x86_64/dist-x86_64-musl/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ wget \ curl \ @@ -33,6 +34,7 @@ ENV HOSTS=x86_64-unknown-linux-musl ENV RUST_CONFIGURE_ARGS \ --musl-root-x86_64=/usr/local/x86_64-linux-musl \ --enable-extended \ + --enable-profiler \ --enable-lld \ --set target.x86_64-unknown-linux-musl.crt-static=false \ --build $HOSTS diff --git a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile index cb507dced4..930061fca6 100644 --- a/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu-nopt/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile index 9d319017d7..ea178bcf4f 100644 --- a/src/ci/docker/host-x86_64/i686-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/i686-gnu/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++-multilib \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/mingw-check/Dockerfile b/src/ci/docker/host-x86_64/mingw-check/Dockerfile index b902eda87b..8fc9a009dc 100644 --- a/src/ci/docker/host-x86_64/mingw-check/Dockerfile +++ b/src/ci/docker/host-x86_64/mingw-check/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/test-various/Dockerfile b/src/ci/docker/host-x86_64/test-various/Dockerfile index c55a284e13..8653aecc12 100644 --- a/src/ci/docker/host-x86_64/test-various/Dockerfile +++ b/src/ci/docker/host-x86_64/test-various/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:18.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -40,7 +41,7 @@ ENV RUST_CONFIGURE_ARGS \ ENV NO_DEBUG_ASSERTIONS=1 ENV WASM_TARGETS=wasm32-unknown-unknown -ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --target $WASM_TARGETS \ +ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $WASM_TARGETS \ src/test/run-make \ src/test/ui \ src/test/compile-fail \ @@ -49,13 +50,13 @@ ENV WASM_SCRIPT python3 /checkout/x.py --stage 2 test --target $WASM_TARGETS \ library/core ENV NVPTX_TARGETS=nvptx64-nvidia-cuda -ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --target $NVPTX_TARGETS \ +ENV NVPTX_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $NVPTX_TARGETS \ src/test/run-make \ src/test/assembly ENV MUSL_TARGETS=x86_64-unknown-linux-musl \ CC_x86_64_unknown_linux_musl=x86_64-linux-musl-gcc \ CXX_x86_64_unknown_linux_musl=x86_64-linux-musl-g++ -ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --target $MUSL_TARGETS +ENV MUSL_SCRIPT python3 /checkout/x.py --stage 2 test --host='' --target $MUSL_TARGETS ENV SCRIPT $WASM_SCRIPT && $NVPTX_SCRIPT && $MUSL_SCRIPT diff --git a/src/ci/docker/host-x86_64/wasm32/Dockerfile b/src/ci/docker/host-x86_64/wasm32/Dockerfile index e00177b4a6..096b664534 100644 --- a/src/ci/docker/host-x86_64/wasm32/Dockerfile +++ b/src/ci/docker/host-x86_64/wasm32/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -52,7 +53,7 @@ ENV NO_CHANGE_USER=1 # FIXME: Re-enable these tests once https://github.com/rust-lang/cargo/pull/7476 # is picked up by CI -ENV SCRIPT python3 ../x.py test --stage 2 --target $TARGETS \ +ENV SCRIPT python3 ../x.py test --stage 2 --host='' --target $TARGETS \ --exclude library/core \ --exclude library/alloc \ --exclude library/proc_macro \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile index 86ac0256d2..a109b36066 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-aux/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile index c1cb20b631..fe956b9c7b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-debug/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:19.10 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile index 68e89a7bad..5f98edf617 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-distcheck/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile index 5c971c73c9..34c6396b7b 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-llvm-8/Dockerfile @@ -4,6 +4,7 @@ RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ g++-arm-linux-gnueabi \ make \ + ninja-build \ file \ curl \ ca-certificates \ @@ -44,7 +45,7 @@ ENV SCRIPT python2.7 ../x.py --stage 2 test --exclude src/tools/tidy && \ # on the `x86_64` host when they're built as `armv5te` binaries. # (we're only interested in the MIR output, so this doesn't matter) python2.7 ../x.py --stage 2 test src/test/mir-opt --pass=build \ - --target=armv5te-unknown-linux-gnueabi && \ + --host='' --target=armv5te-unknown-linux-gnueabi && \ # Run the UI test suite again, but in `--pass=check` mode # # This is intended to make sure that both `--pass=check` continues to diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile index 41e83c69e5..f4071961f8 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-nopt/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile index ef17f0507a..89171a6f21 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu-tools/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:16.04 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile index f8bacf79ac..527b539f68 100644 --- a/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile +++ b/src/ci/docker/host-x86_64/x86_64-gnu/Dockerfile @@ -3,6 +3,7 @@ FROM ubuntu:19.10 RUN apt-get update && apt-get install -y --no-install-recommends \ g++ \ make \ + ninja-build \ file \ curl \ ca-certificates \ diff --git a/src/ci/docker/scripts/android-base-apt-get.sh b/src/ci/docker/scripts/android-base-apt-get.sh index 391b68ea63..1795b1696d 100644 --- a/src/ci/docker/scripts/android-base-apt-get.sh +++ b/src/ci/docker/scripts/android-base-apt-get.sh @@ -10,6 +10,7 @@ apt-get install -y --no-install-recommends \ git \ libssl-dev \ make \ + ninja-build \ pkg-config \ python3 \ sudo \ diff --git a/src/ci/docker/scripts/cross-apt-packages.sh b/src/ci/docker/scripts/cross-apt-packages.sh index 7030cd74ca..2de376443a 100644 --- a/src/ci/docker/scripts/cross-apt-packages.sh +++ b/src/ci/docker/scripts/cross-apt-packages.sh @@ -17,6 +17,7 @@ apt-get update && apt-get install -y --no-install-recommends \ libssl-dev \ libtool-bin \ make \ + ninja-build \ patch \ pkg-config \ python3 \ diff --git a/src/ci/github-actions/ci.yml b/src/ci/github-actions/ci.yml index db2def483a..101716d160 100644 --- a/src/ci/github-actions/ci.yml +++ b/src/ci/github-actions/ci.yml @@ -103,13 +103,6 @@ x--expand-yaml-anchors--remove: with: fetch-depth: 2 - - name: configure GitHub Actions to kill the build when outdated - uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master - with: - github_token: "${{ secrets.github_token }}" - if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' - <<: *step - # Rust Log Analyzer can't currently detect the PR number of a GitHub # Actions build on its own, so a hint in the log message is needed to # point it in the right direction. @@ -133,6 +126,13 @@ x--expand-yaml-anchors--remove: run: src/ci/scripts/should-skip-this.sh <<: *step + - name: configure GitHub Actions to kill the build when outdated + uses: rust-lang/simpleinfra/github-actions/cancel-outdated-builds@master + with: + github_token: "${{ secrets.github_token }}" + if: success() && !env.SKIP_JOB && github.ref != 'refs/heads/try' + <<: *step + - name: collect CPU statistics run: src/ci/scripts/collect-cpu-stats.sh <<: *step @@ -284,18 +284,6 @@ jobs: CI_ONLY_WHEN_SUBMODULES_CHANGED: 1 <<: *job-linux-xl - try: - <<: *base-ci-job - name: try - env: - <<: [*shared-ci-variables, *prod-variables] - if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust' - strategy: - matrix: - include: - - name: dist-x86_64-linux - <<: *job-linux-xl - auto: <<: *base-ci-job name: auto @@ -378,7 +366,8 @@ jobs: - name: dist-x86_64-illumos <<: *job-linux-xl - - name: dist-x86_64-linux + - &dist-x86_64-linux + name: dist-x86_64-linux <<: *job-linux-xl - name: dist-x86_64-linux-alt @@ -432,6 +421,42 @@ jobs: DEPLOY_TOOLSTATES_JSON: toolstates-linux.json <<: *job-linux-xl + #################### + # macOS Builders # + #################### + + - name: dist-x86_64-apple + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --host=x86_64-apple-darwin --target=x86_64-apple-darwin,aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + DIST_REQUIRE_ALL_TOOLS: 1 + <<: *job-macos-xl + + - name: dist-x86_64-apple-alt + env: + SCRIPT: ./x.py dist + RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + + - name: x86_64-apple + env: + SCRIPT: ./x.py --stage 2 test + RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc --set llvm.ninja=false + RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 + MACOSX_DEPLOYMENT_TARGET: 10.8 + MACOSX_STD_DEPLOYMENT_TARGET: 10.7 + NO_LLVM_ASSERTIONS: 1 + NO_DEBUG_ASSERTIONS: 1 + <<: *job-macos-xl + ###################### # Windows Builders # ###################### @@ -489,7 +514,7 @@ jobs: # # We are using MinGW with POSIX threads since LLVM requires # C++'s std::thread which is disabled in libstdc++ with win32 threads. - # FIXME: Libc++ doesn't have this limitation so we can avoid + # FIXME: Libc++ doesn't have this limitation so we can avoid # winpthreads if we switch to it. # # Instead of relying on the MinGW version installed on CI we download @@ -521,7 +546,7 @@ jobs: - name: x86_64-mingw-1 env: SCRIPT: make ci-mingw-subset-1 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 # FIXME(#59637) NO_DEBUG_ASSERTIONS: 1 @@ -531,7 +556,7 @@ jobs: - name: x86_64-mingw-2 env: SCRIPT: make ci-mingw-subset-2 - RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu + RUST_CONFIGURE_ARGS: --build=x86_64-pc-windows-gnu --enable-profiler CUSTOM_MINGW: 1 <<: *job-windows-xl @@ -539,6 +564,7 @@ jobs: env: RUST_CONFIGURE_ARGS: >- --build=x86_64-pc-windows-msvc + --host=x86_64-pc-windows-msvc --target=x86_64-pc-windows-msvc,aarch64-pc-windows-msvc --enable-full-tools --enable-profiler @@ -550,7 +576,8 @@ jobs: env: RUST_CONFIGURE_ARGS: >- --build=i686-pc-windows-msvc - --target=i586-pc-windows-msvc + --host=i686-pc-windows-msvc + --target=i686-pc-windows-msvc,i586-pc-windows-msvc --enable-full-tools --enable-profiler SCRIPT: python x.py dist @@ -596,41 +623,16 @@ jobs: - name: aarch64-gnu <<: *job-aarch64-linux - #################### - # macOS Builders # - #################### - - - name: dist-x86_64-apple - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --target=aarch64-apple-ios,x86_64-apple-ios --enable-full-tools --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - DIST_REQUIRE_ALL_TOOLS: 1 - <<: *job-macos-xl - - - name: dist-x86_64-apple-alt - env: - SCRIPT: ./x.py dist - RUST_CONFIGURE_ARGS: --enable-extended --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl - - - name: x86_64-apple - env: - SCRIPT: ./x.py --stage 2 test - RUST_CONFIGURE_ARGS: --build=x86_64-apple-darwin --enable-sanitizers --enable-profiler --set rust.jemalloc - RUSTC_RETRY_LINKER_ON_SEGFAULT: 1 - MACOSX_DEPLOYMENT_TARGET: 10.8 - MACOSX_STD_DEPLOYMENT_TARGET: 10.7 - NO_LLVM_ASSERTIONS: 1 - NO_DEBUG_ASSERTIONS: 1 - <<: *job-macos-xl + try: + <<: *base-ci-job + name: try + env: + <<: [*shared-ci-variables, *prod-variables] + if: github.event_name == 'push' && (github.ref == 'refs/heads/try' || github.ref == 'refs/heads/try-perf') && github.repository == 'rust-lang-ci/rust' + strategy: + matrix: + include: + - *dist-x86_64-linux master: name: master diff --git a/src/ci/run.sh b/src/ci/run.sh index 59510f5945..8681f84f6a 100755 --- a/src/ci/run.sh +++ b/src/ci/run.sh @@ -63,7 +63,7 @@ fi # # FIXME: need a scheme for changing this `nightly` value to `beta` and `stable` # either automatically or manually. -export RUST_RELEASE_CHANNEL=stable +export RUST_RELEASE_CHANNEL=beta # Always set the release channel for bootstrap; this is normally not important (i.e., only dist # builds would seem to matter) but in practice bootstrap wants to know whether we're targeting @@ -104,6 +104,8 @@ if [ "$RUST_RELEASE_CHANNEL" = "nightly" ] || [ "$DIST_REQUIRE_ALL_TOOLS" = "" ] RUST_CONFIGURE_ARGS="$RUST_CONFIGURE_ARGS --enable-missing-tools" fi +export COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS=1 + # Print the date from the local machine and the date from an external source to # check for clock drifts. An HTTP URL is used instead of HTTPS since on Azure # Pipelines it happened that the certificates were marked as expired. diff --git a/src/ci/scripts/symlink-build-dir.sh b/src/ci/scripts/symlink-build-dir.sh index 28d8aa3b6e..23849f7047 100755 --- a/src/ci/scripts/symlink-build-dir.sh +++ b/src/ci/scripts/symlink-build-dir.sh @@ -12,22 +12,4 @@ source "$(cd "$(dirname "$0")" && pwd)/../shared.sh" if isWindows && isAzurePipelines; then cmd //c "mkdir c:\\MORE_SPACE" cmd //c "mklink /J build c:\\MORE_SPACE" -elif isLinux && isGitHubActions && ! isSelfHostedGitHubActions; then - sudo mkdir -p /mnt/more-space - sudo chown -R "$(whoami):" /mnt/more-space - - # Switch the whole workspace to the /mnt partition, which has more space. - # We don't just symlink the `obj` directory as doing that creates problems - # with the docker container. - current_dir="$(readlink -f "$(pwd)")" - cd /tmp - mv "${current_dir}" /mnt/more-space/workspace - ln -s /mnt/more-space/workspace "${current_dir}" - cd "${current_dir}" - - # Move the Docker data directory to /mnt - sudo systemctl stop docker.service - sudo mv /var/lib/docker /mnt/docker - sudo ln -s /mnt/docker /var/lib/docker - sudo systemctl start docker.service fi diff --git a/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt b/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt index be3ef310f8..273b34711a 100644 --- a/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt +++ b/src/doc/book/listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/output.txt @@ -1,6 +1,15 @@ $ cargo run Compiling arrays v0.1.0 (file:///projects/arrays) - Finished dev [unoptimized + debuginfo] target(s) in 0.31s - Running `target/debug/arrays` -thread 'main' panicked at 'index out of bounds: the len is 5 but the index is 10', src/main.rs:5:19 -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace. +error: this operation will panic at runtime + --> src/main.rs:5:19 + | +5 | let element = a[index]; + | ^^^^^^^^ index out of bounds: the len is 5 but the index is 10 + | + = note: `#[deny(unconditional_panic)]` on by default + +error: aborting due to previous error + +error: could not compile `arrays`. + +To learn more, run the command again with --verbose. diff --git a/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs b/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs index 814fddc509..df33743f78 100644 --- a/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs +++ b/src/doc/book/listings/ch10-generic-types-traits-and-lifetimes/listing-10-05/src/main.rs @@ -1,5 +1,5 @@ fn largest(list: &[T]) -> &T { - let mut largest = list[0]; + let mut largest = &list[0]; for item in list { if item > largest { diff --git a/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs b/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs index 6284f4f291..becae97e07 100644 --- a/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs +++ b/src/doc/book/listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs @@ -1,3 +1,7 @@ +#![allow(unused_variables)] +fn main() {} + +// ANCHOR: here #[cfg(test)] mod tests { #[test] @@ -9,3 +13,4 @@ mod tests { } } } +// ANCHOR_END: here diff --git a/src/doc/book/src/appendix-06-translation.md b/src/doc/book/src/appendix-06-translation.md index 035fbcaff6..cbd39743c9 100644 --- a/src/doc/book/src/appendix-06-translation.md +++ b/src/doc/book/src/appendix-06-translation.md @@ -24,3 +24,4 @@ For resources in languages other than English. Most are still in progress; see - [Svenska](https://github.com/sebras/book) - [Farsi](https://github.com/pomokhtari/rust-book-fa) - [Deutsch](https://github.com/rust-lang-de/rustbook-de) +- [Turkish](https://github.com/RustDili/dokuman/tree/master/ceviriler), [online](https://rustdili.github.io/) diff --git a/src/doc/book/src/ch03-02-data-types.md b/src/doc/book/src/ch03-02-data-types.md index f76d54bd59..62111c7241 100644 --- a/src/doc/book/src/ch03-02-data-types.md +++ b/src/doc/book/src/ch03-02-data-types.md @@ -320,7 +320,7 @@ compile but exit with an error when it runs: Filename: src/main.rs -```rust,ignore,panics +```rust,ignore,does_not_compile {{#rustdoc_include ../listings/ch03-common-programming-concepts/no-listing-15-invalid-array-access/src/main.rs}} ``` diff --git a/src/doc/book/src/ch11-01-writing-tests.md b/src/doc/book/src/ch11-01-writing-tests.md index 996816bce2..f486a5cdf8 100644 --- a/src/doc/book/src/ch11-01-writing-tests.md +++ b/src/doc/book/src/ch11-01-writing-tests.md @@ -507,7 +507,7 @@ that use `Result`! Here’s the test from Listing 11-1, rewritten to use `Result` and return an `Err` instead of panicking: ```rust -{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs}} +{{#rustdoc_include ../listings/ch11-writing-automated-tests/no-listing-10-result-in-tests/src/lib.rs:here}} ``` The `it_works` function now has a return type, `Result<(), String>`. In the diff --git a/src/doc/edition-guide/src/rust-next/const-fn.md b/src/doc/edition-guide/src/rust-next/const-fn.md index 2f504d1f3b..65f640f70b 100644 --- a/src/doc/edition-guide/src/rust-next/const-fn.md +++ b/src/doc/edition-guide/src/rust-next/const-fn.md @@ -230,7 +230,7 @@ const fn foo() { ![Minimum Rust version: 1.33](https://img.shields.io/badge/Minimum%20Rust%20Version-1.33-brightgreen.svg) -YOu can call an `unsafe fn` inside a `const fn`: +You can call an `unsafe fn` inside a `const fn`: ``` const unsafe fn foo() -> i32 { 5 } @@ -238,4 +238,4 @@ const unsafe fn foo() -> i32 { 5 } const fn bar() -> i32 { unsafe { foo() } } -``` \ No newline at end of file +``` diff --git a/src/doc/embedded-book/src/intro/install.md b/src/doc/embedded-book/src/intro/install.md index 6dd61f8286..343f762cab 100644 --- a/src/doc/embedded-book/src/intro/install.md +++ b/src/doc/embedded-book/src/intro/install.md @@ -17,7 +17,7 @@ rustc 1.31.1 (b6c32da9b 2018-12-18) For bandwidth and disk usage concerns the default installation only supports native compilation. To add cross compilation support for the ARM Cortex-M architectures choose one of the following compilation targets. For the STM32F3DISCOVERY -board used for the examples in this book, use the final `thumbv7em-none-eabihf` target. +board used for the examples in this book, use the `thumbv7em-none-eabihf` target. Cortex-M0, M0+, and M1 (ARMv6-M architecture): ``` console @@ -39,6 +39,22 @@ Cortex-M4F and M7F with hardware floating point (ARMv7E-M architecture): $ rustup target add thumbv7em-none-eabihf ``` +Cortex-M23 (ARMv8-M architecture): +``` console +$ rustup target add thumbv8m.base-none-eabi +``` + +Cortex-M33 and M35P (ARMv8-M architecture): +``` console +$ rustup target add thumbv8m.main-none-eabi +``` + +Cortex-M33F and M35PF with hardware floating point (ARMv8-M architecture): +``` console +$ rustup target add thumbv8m.main-none-eabihf +``` + + ### `cargo-binutils` ``` console diff --git a/src/doc/nomicon/src/vec-final.md b/src/doc/nomicon/src/vec-final.md index 8c86641bd5..eb749a4758 100644 --- a/src/doc/nomicon/src/vec-final.md +++ b/src/doc/nomicon/src/vec-final.md @@ -47,7 +47,7 @@ impl RawVec { let c: NonNull = self.ptr.into(); let ptr = Global.grow(c.cast(), Layout::array::(self.cap).unwrap(), - Layout::array::(new_cap).unwrap().size()); + Layout::array::(new_cap).unwrap()); (new_cap, ptr) }; diff --git a/src/doc/reference/src/behavior-considered-undefined.md b/src/doc/reference/src/behavior-considered-undefined.md index d2488591c7..f1ad30ada3 100644 --- a/src/doc/reference/src/behavior-considered-undefined.md +++ b/src/doc/reference/src/behavior-considered-undefined.md @@ -57,6 +57,11 @@ code. > **Note**: `rustc` achieves this with the unstable > `rustc_layout_scalar_valid_range_*` attributes. +**Note:** Uninitialized memory is also implicitly invalid for any type that has +a restricted set of valid values. In other words, the only cases in which +reading uninitialized memory is permitted are inside `union`s and in "padding" +(the gaps between the fields/elements of a type). + A reference/pointer is "dangling" if it is null or not all of the bytes it points to are part of the same allocation (so in particular they all have to be part of *some* allocation). The span of bytes it points to is determined by the diff --git a/src/doc/reference/src/const_eval.md b/src/doc/reference/src/const_eval.md index 2c4fbe9bad..b3d087f326 100644 --- a/src/doc/reference/src/const_eval.md +++ b/src/doc/reference/src/const_eval.md @@ -64,7 +64,24 @@ A _const context_ is one of the following: A _const fn_ is a function that one is permitted to call from a const context. Declaring a function `const` has no effect on any existing uses, it only restricts the types that arguments and the -return type may use, as well as prevent various expressions from being used within it. +return type may use, as well as prevent various expressions from being used within it. You can freely do anything with a const function that +you can do with a regular function. + +When called from a const context, the function is interpreted by the +compiler at compile time. The interpretation happens in the +environment of the compilation target and not the host. So `usize` is +`32` bits if you are compiling against a `32` bit system, irrelevant +of whether you are building on a `64` bit or a `32` bit system. + +Const functions have various restrictions to make sure that they can be +evaluated at compile-time. It is, for example, not possible to write a random +number generator as a const function. Calling a const function at compile-time +will always yield the same result as calling it at runtime, even when called +multiple times. There's one exception to this rule: if you are doing complex +floating point operations in extreme situations, then you might get (very +slightly) different results. It is advisable to not make array lengths and enum +discriminants depend on floating point computations. + Notable features that const contexts have, but const fn haven't are: diff --git a/src/doc/reference/src/expressions/match-expr.md b/src/doc/reference/src/expressions/match-expr.md index 9a0cb8d610..6d9f3f2afe 100644 --- a/src/doc/reference/src/expressions/match-expr.md +++ b/src/doc/reference/src/expressions/match-expr.md @@ -66,7 +66,7 @@ Multiple match patterns may be joined with the `|` operator. Each pattern will b tested in left-to-right sequence until a successful match is found. ```rust -# let x = 9; +let x = 9; let message = match x { 0 | 1 => "not many", 2 ..= 9 => "a few", diff --git a/src/doc/reference/src/items/functions.md b/src/doc/reference/src/items/functions.md index 138f1169e3..15b8cc10b4 100644 --- a/src/doc/reference/src/items/functions.md +++ b/src/doc/reference/src/items/functions.md @@ -183,58 +183,9 @@ aborts the process by executing an illegal instruction. ## Const functions -Functions qualified with the `const` keyword are const functions, as are +Functions qualified with the `const` keyword are [const functions], as are [tuple struct] and [tuple variant] constructors. _Const functions_ can be -called from within [const context]s. When called from a const context, the -function is interpreted by the compiler at compile time. The interpretation -happens in the environment of the compilation target and not the host. So -`usize` is `32` bits if you are compiling against a `32` bit system, irrelevant -of whether you are building on a `64` bit or a `32` bit system. - -If a const function is called outside a [const context], it is indistinguishable -from any other function. You can freely do anything with a const function that -you can do with a regular function. - -Const functions have various restrictions to make sure that they can be -evaluated at compile-time. It is, for example, not possible to write a random -number generator as a const function. Calling a const function at compile-time -will always yield the same result as calling it at runtime, even when called -multiple times. There's one exception to this rule: if you are doing complex -floating point operations in extreme situations, then you might get (very -slightly) different results. It is advisable to not make array lengths and enum -discriminants depend on floating point computations. - -Exhaustive list of permitted structures in const functions: - -> **Note**: this list is more restrictive than what you can write in -> regular constants - -* Type parameters where the parameters only have any [trait bounds] - of the following kind: - * lifetimes - * `Sized` or [`?Sized`] - - This means that ``, ``, and `` - are all permitted. - - This rule also applies to type parameters of impl blocks that - contain const methods. - - This does not apply to tuple struct and tuple variant constructors. - -* Arithmetic and comparison operators on integers -* All boolean operators except for `&&` and `||` which are banned since - they are short-circuiting. -* Any kind of aggregate constructor (array, `struct`, `enum`, tuple, ...) -* Calls to other *safe* const functions (whether by function call or method call) -* Index expressions on arrays and slices -* Field accesses on structs and tuples -* Reading from constants (but not statics, not even taking a reference to a static) -* `&` and `*` (only dereferencing of references, not raw pointers) -* Casts except for raw pointer to integer casts -* `unsafe` blocks and `const unsafe fn` are allowed, but the body/block may only do - the following unsafe operations: - * calls to const unsafe functions +called from within [const context]s. ## Async functions @@ -396,6 +347,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [_WhereClause_]: generics.md#where-clauses [_OuterAttribute_]: ../attributes.md [const context]: ../const_eval.md#const-context +[const functions]: ../const_eval.md#const-functions [tuple struct]: structs.md [tuple variant]: enumerations.md [external block]: external-blocks.md @@ -416,10 +368,7 @@ fn foo_oof(#[some_inert_attribute] arg: u8) { [`doc`]: ../../rustdoc/the-doc-attribute.html [`must_use`]: ../attributes/diagnostics.md#the-must_use-attribute [patterns]: ../patterns.md -[`?Sized`]: ../trait-bounds.md#sized -[trait bounds]: ../trait-bounds.md [`export_name`]: ../abi.md#the-export_name-attribute [`link_section`]: ../abi.md#the-link_section-attribute [`no_mangle`]: ../abi.md#the-no_mangle-attribute -[external_block_abi]: external-blocks.md#abi [built-in attributes]: ../attributes.html#built-in-attributes-index diff --git a/src/doc/reference/src/linkage.md b/src/doc/reference/src/linkage.md index 264d3f024a..4a8ed96a96 100644 --- a/src/doc/reference/src/linkage.md +++ b/src/doc/reference/src/linkage.md @@ -41,10 +41,10 @@ be ignored in favor of only building the artifacts specified by command line. the compiler will never attempt to link to `staticlib` outputs. The purpose of this output type is to create a static library containing all of the local crate's code along with all upstream dependencies. The static - library is actually a `*.a` archive on linux and osx and a `*.lib` file on - windows. This format is recommended for use in situations such as linking - Rust code into an existing non-Rust application because it will not have - dynamic dependencies on other Rust code. + library is actually a `*.a` archive on linux and osx and windows(MinGW), and + a `*.lib` file on windows(MSVC). This format is recommended for use in + situations such as linking Rust code into an existing non-Rust application + because it will not have dynamic dependencies on other Rust code. * `--crate-type=cdylib`, `#[crate_type = "cdylib"]` - A dynamic system library will be produced. This is used when compiling diff --git a/src/doc/reference/src/patterns.md b/src/doc/reference/src/patterns.md index 88940641c6..b9c1b9690b 100644 --- a/src/doc/reference/src/patterns.md +++ b/src/doc/reference/src/patterns.md @@ -2,10 +2,15 @@ > **Syntax**\ > _Pattern_ :\ +>       _PatternWithoutRange_\ +>    | [_RangePattern_] +> +> _PatternWithoutRange_ :\ >       [_LiteralPattern_]\ >    | [_IdentifierPattern_]\ >    | [_WildcardPattern_]\ ->    | [_RangePattern_]\ +>    | [_RestPattern_]\ +>    | [_ObsoleteRangePattern_]\ >    | [_ReferencePattern_]\ >    | [_StructPattern_]\ >    | [_TupleStructPattern_]\ @@ -248,6 +253,9 @@ copying or moving what was matched. [Path patterns](#path-patterns) take precedence over identifier patterns. It is an error if `ref` or `ref mut` is specified and the identifier shadows a constant. +Identifier patterns are irrefutable if the `@` subpattern is irrefutable or +the subpattern is not specified. + ### Binding modes To service better ergonomics, patterns operate in different *binding modes* in @@ -317,12 +325,67 @@ if let Some(_) = x {} The wildcard pattern is always irrefutable. +## Rest patterns + +> **Syntax**\ +> _RestPattern_ :\ +>    `..` + +The _rest pattern_ (the `..` token) acts as a variable-length pattern which +matches zero or more elements that haven't been matched already before and +after. It may only be used in [tuple](#tuple-patterns), [tuple +struct](#tuple-struct-patterns), and [slice](#slice-patterns) patterns, and +may only appear once as one of the elements in those patterns. It is also +allowed in an [identifier pattern](#identifier-patterns) for [slice +patterns](#slice-patterns) only. + +The rest pattern is always irrefutable. + +Examples: + +```rust +# let words = vec!["a", "b", "c"]; +# let slice = &words[..]; +match slice { + [] => println!("slice is empty"), + [one] => println!("single element {}", one), + [head, tail @ ..] => println!("head={} tail={:?}", head, tail), +} + +match slice { + // Ignore everything but the last element, which must be "!". + [.., "!"] => println!("!!!"), + + // `start` is a slice of everything except the last element, which must be "z". + [start @ .., "z"] => println!("starts with: {:?}", start), + + // `end` is a slice of everything but the first element, which must be "a". + ["a", end @ ..] => println!("ends with: {:?}", end), + + rest => println!("{:?}", rest), +} + +if let [.., penultimate, _] = slice { + println!("next to last is {}", penultimate); +} + +# let tuple = (1, 2, 3, 4, 5); +// Rest patterns may also be used in tuple and tuple struct patterns. +match tuple { + (1, .., y, z) => println!("y={} z={}", y, z), + (.., 5) => println!("tail must be 5"), + (..) => println!("matches everything else"), +} +``` + ## Range patterns > **Syntax**\ > _RangePattern_ :\ ->      _RangePatternBound_ `..=` _RangePatternBound_\ ->    | _RangePatternBound_ `...` _RangePatternBound_ +>    _RangePatternBound_ `..=` _RangePatternBound_ +> +> _ObsoleteRangePattern_ :\ +>    _RangePatternBound_ `...` _RangePatternBound_ > > _RangePatternBound_ :\ >       [CHAR_LITERAL]\ @@ -429,7 +492,7 @@ ranges containing all Unicode Scalar Values: `'\u{0000}'..='\u{D7FF}'` and > **Syntax**\ > _ReferencePattern_ :\ ->    (`&`|`&&`) `mut`? _Pattern_ +>    (`&`|`&&`) `mut`? [_PatternWithoutRange_] Reference patterns dereference the pointers that are being matched and, thus, borrow them. @@ -559,8 +622,7 @@ A struct pattern is refutable when one of its subpatterns is refutable. >    [_PathInExpression_] `(` _TupleStructItems_? `)` > > _TupleStructItems_ :\ ->       [_Pattern_] ( `,` [_Pattern_] )\* `,`?\ ->    | ([_Pattern_] `,`)\* `..` (`,` [_Pattern_])* `,`? +>    [_Pattern_] ( `,` [_Pattern_] )\* `,`? Tuple struct patterns match tuple struct and enum values that match all criteria defined by its subpatterns. They are also used to [destructure](#destructuring) a tuple struct or @@ -576,13 +638,16 @@ A tuple struct pattern is refutable when one of its subpatterns is refutable. > > _TuplePatternItems_ :\ >       [_Pattern_] `,`\ ->    | [_Pattern_] (`,` [_Pattern_])+ `,`?\ ->    | ([_Pattern_] `,`)\* `..` (`,` [_Pattern_])* `,`? +>    | [_RestPattern_]\ +>    | [_Pattern_] (`,` [_Pattern_])+ `,`? Tuple patterns match tuple values that match all criteria defined by its subpatterns. They are also used to [destructure](#destructuring) a tuple. -This pattern is refutable when one of its subpatterns is refutable. +The form `(..)` with a single [_RestPattern_] is a special form that does not +require a comma, and matches a tuple of any size. + +The tuple pattern is refutable when one of its subpatterns is refutable. ## Grouped patterns @@ -607,7 +672,10 @@ match int_reference { > **Syntax**\ > _SlicePattern_ :\ ->    `[` [_Pattern_] \(`,` [_Pattern_])\* `,`? `]` +>    `[` _SlicePatternItems_? `]` +> +> _SlicePatternItems_ :\ +>    [_Pattern_] \(`,` [_Pattern_])\* `,`? Slice patterns can match both arrays of fixed size and slices of dynamic size. ```rust @@ -628,6 +696,11 @@ match v[..] { }; ``` +Slice patterns are irrefutable when matching an array as long as each element +is irrefutable. When matching a slice, it is irrefutable only in the form with +a single `..` [rest pattern](#rest-patterns) or [identifier +pattern](#identifier-patterns) with the `..` rest pattern as a subpattern. + ## Path patterns > **Syntax**\ @@ -658,12 +731,15 @@ refer to refutable constants or enum variants for enums with multiple variants. [_IdentifierPattern_]: #identifier-patterns [_LiteralPattern_]: #literal-patterns [_MacroInvocation_]: macros.md#macro-invocation +[_ObsoleteRangePattern_]: #range-patterns [_PathInExpression_]: paths.md#paths-in-expressions [_PathPattern_]: #path-patterns [_Pattern_]: #patterns +[_PatternWithoutRange_]: #patterns [_QualifiedPathInExpression_]: paths.md#qualified-paths [_RangePattern_]: #range-patterns [_ReferencePattern_]: #reference-patterns +[_RestPattern_]: #rest-patterns [_SlicePattern_]: #slice-patterns [_StructPattern_]: #struct-patterns [_TuplePattern_]: #tuple-patterns diff --git a/src/doc/reference/src/type-coercions.md b/src/doc/reference/src/type-coercions.md index 377afe769b..d578e042a1 100644 --- a/src/doc/reference/src/type-coercions.md +++ b/src/doc/reference/src/type-coercions.md @@ -1,10 +1,13 @@ # Type coercions -Coercions are defined in [RFC 401]. [RFC 1558] then expanded on that. -A coercion is implicit and has no syntax. +**Type coercions** are implicit operations that change the type of a value. +They happen automatically at specific locations and are highly restricted in +what types actually coerce. -[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md -[RFC 1558]: https://github.com/rust-lang/rfcs/blob/master/text/1558-closure-to-fn-coercion.md +Any conversions allowed by coercion can also be explicitly performed by the +[type cast operator], `as`. + +Coercions are originally defined in [RFC 401] and expanded upon in [RFC 1558]. ## Coercion sites @@ -15,52 +18,53 @@ sites are: * `let` statements where an explicit type is given. - For example, `42` is coerced to have type `i8` in the following: + For example, `&mut 42` is coerced to have type `&i8` in the following: ```rust - let _: i8 = 42; + let _: &i8 = &mut 42; ``` -* `static` and `const` statements (similar to `let` statements). +* `static` and `const` item declarations (similar to `let` statements). * Arguments for function calls The value being coerced is the actual parameter, and it is coerced to the type of the formal parameter. - For example, `42` is coerced to have type `i8` in the following: + For example, `&mut 42` is coerced to have type `&i8` in the following: ```rust - fn bar(_: i8) { } + fn bar(_: &i8) { } fn main() { - bar(42); + bar(&mut 42); } ``` For method calls, the receiver (`self` parameter) can only take advantage of [unsized coercions](#unsized-coercions). -* Instantiations of struct or variant fields +* Instantiations of struct, union, or enum variant fields - For example, `42` is coerced to have type `i8` in the following: + For example, `&mut 42` is coerced to have type `&i8` in the following: ```rust - struct Foo { x: i8 } + struct Foo<'a> { x: &'a i8 } fn main() { - Foo { x: 42 }; + Foo { x: &mut 42 }; } ``` - -* Function results, either the final line of a block if it is not + +* Function results—either the final line of a block if it is not semicolon-terminated or any expression in a `return` statement - For example, `42` is coerced to have type `i8` in the following: + For example, `x` is coerced to have type `&dyn Display` in the following: ```rust - fn foo() -> i8 { - 42 + use std::fmt::Display; + fn foo(x: &u32) -> &dyn Display { + x } ``` @@ -91,7 +95,7 @@ the block has a known type. Coercion is allowed between the following types: -* `T` to `U` if `T` is a subtype of `U` (*reflexive case*) +* `T` to `U` if `T` is a [subtype] of `U` (*reflexive case*) * `T_1` to `T_3` where `T_1` coerces to `T_2` and `T_2` coerces to `T_3` (*transitive case*) @@ -164,8 +168,7 @@ an implementation of `Unsize` for `T` will be provided: * `[T; n]` to `[T]`. -* `T` to `U`, when `U` is a trait object type and either `T` implements `U` or - `T` is a trait object for a subtrait of `U`. +* `T` to `dyn U`, when `T` implements `U + Sized`, and `U` is [object safe]. * `Foo<..., T, ...>` to `Foo<..., U, ...>`, when: * `Foo` is a struct. @@ -182,5 +185,10 @@ unsized coercion to `Foo`. > has been stabilized, the traits themselves are not yet stable and therefore > can't be used directly in stable Rust. +[RFC 401]: https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md +[RFC 1558]: https://github.com/rust-lang/rfcs/blob/master/text/1558-closure-to-fn-coercion.md +[subtype]: subtyping.md +[object safe]: items/traits.md#object-safety +[type cast operator]: expressions/operator-expr.md#type-cast-expressions [`Unsize`]: ../std/marker/trait.Unsize.html [`CoerceUnsized`]: ../std/ops/trait.CoerceUnsized.html diff --git a/src/doc/reference/src/type-layout.md b/src/doc/reference/src/type-layout.md index 3adbdc95f1..c450195b47 100644 --- a/src/doc/reference/src/type-layout.md +++ b/src/doc/reference/src/type-layout.md @@ -174,7 +174,8 @@ layout such as reinterpreting values as a different type. Because of this dual purpose, it is possible to create types that are not useful for interfacing with the C programming language. -This representation can be applied to structs, unions, and enums. +This representation can be applied to structs, unions, and enums. The exception +is [zero-variant enums] for which the `C` representation is an error. #### \#[repr(C)] Structs @@ -273,9 +274,9 @@ assert_eq!(std::mem::size_of::(), 8); // Size of 6 from b, assert_eq!(std::mem::align_of::(), 4); // From a ``` -#### \#[repr(C)] Enums +#### \#[repr(C)] Field-less Enums -For [C-like enumerations], the `C` representation has the size and alignment of +For [field-less enums], the `C` representation has the size and alignment of the default `enum` size and alignment for the target platform's C ABI. > Note: The enum representation in C is implementation defined, so this is @@ -285,21 +286,80 @@ the default `enum` size and alignment for the target platform's C ABI.
Warning: There are crucial differences between an `enum` in the C language and -Rust's C-like enumerations with this representation. An `enum` in C is +Rust's [field-less enums] with this representation. An `enum` in C is mostly a `typedef` plus some named constants; in other words, an object of an `enum` type can hold any integer value. For example, this is often used for -bitflags in `C`. In contrast, Rust’s C-like enumerations can only legally hold -the discriminant values, everything else is undefined behaviour. Therefore, -using a C-like enumeration in FFI to model a C `enum` is often wrong. +bitflags in `C`. In contrast, Rust’s [field-less enums] can only legally hold +the discrimnant values, everything else is [undefined behavior]. Therefore, +using a field-less enum in FFI to model a C `enum` is often wrong.
-It is an error for [zero-variant enumerations] to have the `C` representation. +#### \#[repr(C)] Enums With Fields -For all other enumerations, the layout is unspecified. +The representation of a `repr(C)` enum with fields is a `repr(C)` struct with +two fields, also called a "tagged union" in C: -Likewise, combining the `C` representation with a primitive representation, the -layout is unspecified. +- a `repr(C)` version of the enum with all fields removed ("the tag") +- a `repr(C)` union of `repr(C)` structs for the fields of each variant that had + them ("the payload") + +> Note: Due to the representation of `repr(C)` structs and unions, if a variant +> has a single field there is no difference between putting that field directly +> in the union or wrapping it in a struct; any system which wishes to manipulate +> such an `enum`'s representation may therefore use whichever form is more +> convenient or consistent for them. + +```rust +// This Enum has the same representation as ... +#[repr(C)] +enum MyEnum { + A(u32), + B(f32, u64), + C { x: u32, y: u8 }, + D, + } + +// ... this struct. +#[repr(C)] +struct MyEnumRepr { + tag: MyEnumDiscriminant, + payload: MyEnumFields, +} + +// This is the discriminant enum. +#[repr(C)] +enum MyEnumDiscriminant { A, B, C, D } + +// This is the variant union. +#[repr(C)] +union MyEnumFields { + A: MyAFields, + B: MyBFields, + C: MyCFields, + D: MyDFields, +} + +#[repr(C)] +#[derive(Copy, Clone)] +struct MyAFields(u32); + +#[repr(C)] +#[derive(Copy, Clone)] +struct MyBFields(f32, u64); + +#[repr(C)] +#[derive(Copy, Clone)] +struct MyCFields { x: u32, y: u8 } + +// This struct could be omitted (it is a zero-sized type), and it must be in +// C/C++ headers. +#[repr(C)] +#[derive(Copy, Clone)] +struct MyDFields; +``` + +> Note: `union`s with non-`Copy` fields are unstable, see [55149]. ### Primitive representations @@ -307,18 +367,135 @@ The *primitive representations* are the representations with the same names as the primitive integer types. That is: `u8`, `u16`, `u32`, `u64`, `u128`, `usize`, `i8`, `i16`, `i32`, `i64`, `i128`, and `isize`. -Primitive representations can only be applied to enumerations. +Primitive representations can only be applied to enumerations and have +different behavior whether the enum has fields or no fields. It is an error +for [zero-variant enumerations] to have a primitive representation. Combining +two primitive representations together is an error. -For [C-like enumerations], they set the size and alignment to be the same as the -primitive type of the same name. For example, a C-like enumeration with a `u8` -representation can only have discriminants between 0 and 255 inclusive. +#### Primitive Representation of Field-less Enums -It is an error for [zero-variant enumerations] to have a primitive -representation. +For [field-less enums], primitive representations set the size and alignment to +be the same as the primitive type of the same name. For example, a field-less +enum with a `u8` representation can only have discriminants between 0 and 255 +inclusive. -For all other enumerations, the layout is unspecified. +#### Primitive Representation of Enums With Fields -Likewise, combining two primitive representations together is unspecified. +The representation of a primitive representation enum is a `repr(C)` union of +`repr(C)` structs for each variant with a field. The first field of each struct +in the union is the primitive representation version of the enum with all fields +removed ("the tag") and the remaining fields are the fields of that variant. + +> Note: This representation is unchanged if the tag is given its own member in +> the union, should that make manipulation more clear for you (although to +> follow the C++ standard the tag member should be wrapped in a `struct`). + +```rust +// This enum has the same representation as ... +#[repr(u8)] +enum MyEnum { + A(u32), + B(f32, u64), + C { x: u32, y: u8 }, + D, + } + +// ... this union. +#[repr(C)] +union MyEnumRepr { + A: MyVariantA, + B: MyVariantB, + C: MyVariantC, + D: MyVariantD, +} + +// This is the discriminant enum. +#[repr(u8)] +#[derive(Copy, Clone)] +enum MyEnumDiscriminant { A, B, C, D } + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantA(MyEnumDiscriminant, u32); + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantB(MyEnumDiscriminant, f32, u64); + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantC { tag: MyEnumDiscriminant, x: u32, y: u8 } + +#[repr(C)] +#[derive(Clone, Copy)] +struct MyVariantD(MyEnumDiscriminant); +``` + +> Note: `union`s with non-`Copy` fields are unstable, see [55149]. + +#### Combining primitive representations of enums with fields and \#[repr(C)] + +For enums with fields, it is also possible to combine `repr(C)` and a +primitive representation (e.g., `repr(C, u8)`). This modifies the [`repr(C)`] by +changing the representation of the discriminant enum to the chosen primitive +instead. So, if you chose the `u8` representation, then the discriminant enum +would have a size and alignment of 1 byte. + +The discriminant enum from the example [earlier][`repr(C)`] then becomes: + +```rust +#[repr(C, u8)] // `u8` was added +enum MyEnum { + A(u32), + B(f32, u64), + C { x: u32, y: u8 }, + D, + } + +// ... + +#[repr(u8)] // So `u8` is used here instead of `C` +enum MyEnumDiscriminant { A, B, C, D } + +// ... +``` + +For example, with a `repr(C, u8)` enum it is not possible to have 257 unique +discriminants ("tags") whereas the same enum with only a `repr(C)` attribute +will compile without any problems. + +Using a primitive representation in addition to `repr(C)` can change the size of +an enum from the `repr(C)` form: + +```rust +#[repr(C)] +enum EnumC { + Variant0(u8), + Variant1, +} + +#[repr(C, u8)] +enum Enum8 { + Variant0(u8), + Variant1, +} + +#[repr(C, u16)] +enum Enum16 { + Variant0(u8), + Variant1, +} + +// The size of the C representation is platform dependant +assert_eq!(std::mem::size_of::(), 8); +// One byte for the discriminant and one byte for the value in Enum8::Variant0 +assert_eq!(std::mem::size_of::(), 2); +// Two bytes for the discriminant and one byte for the value in Enum16::Variant0 +// plus one byte of padding. +assert_eq!(std::mem::size_of::(), 4); +``` + +[`repr(C)`]: #reprc-enums-with-fields ### The alignment modifiers @@ -379,12 +556,14 @@ used with any other representation. [`align_of`]: ../std/mem/fn.align_of.html [`size_of`]: ../std/mem/fn.size_of.html [`Sized`]: ../std/marker/trait.Sized.html +[`Copy`]: ../std/marker/trait.Copy.html [dynamically sized types]: dynamically-sized-types.md -[C-like enumerations]: items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations +[field-less enums]: items/enumerations.md#custom-discriminant-values-for-fieldless-enumerations [enumerations]: items/enumerations.md -[zero-variant enumerations]: items/enumerations.md#zero-variant-enums +[zero-variant enums]: items/enumerations.md#zero-variant-enums [undefined behavior]: behavior-considered-undefined.md [27060]: https://github.com/rust-lang/rust/issues/27060 +[55149]: https://github.com/rust-lang/rust/issues/55149 [`PhantomData`]: special-types-and-traits.md#phantomdatat [Default]: #the-default-representation [`C`]: #the-c-representation diff --git a/src/doc/rust-by-example/src/SUMMARY.md b/src/doc/rust-by-example/src/SUMMARY.md index 093d3af8ee..dfefcd5b90 100644 --- a/src/doc/rust-by-example/src/SUMMARY.md +++ b/src/doc/rust-by-example/src/SUMMARY.md @@ -82,8 +82,8 @@ - [File hierarchy](mod/split.md) - [Crates](crates.md) - - [Library](crates/lib.md) - - [`extern crate`](crates/link.md) + - [Creating a Library](crates/lib.md) + - [Using a Library](crates/using_lib.md) - [Cargo](cargo.md) - [Dependencies](cargo/deps.md) diff --git a/src/doc/rust-by-example/src/crates/lib.md b/src/doc/rust-by-example/src/crates/lib.md index 20b4cac59e..44593f3bb0 100644 --- a/src/doc/rust-by-example/src/crates/lib.md +++ b/src/doc/rust-by-example/src/crates/lib.md @@ -1,4 +1,4 @@ -# Library +# Creating a Library Let's create a library, and then see how to link it to another crate. diff --git a/src/doc/rust-by-example/src/crates/link.md b/src/doc/rust-by-example/src/crates/link.md deleted file mode 100644 index 828fbdbeba..0000000000 --- a/src/doc/rust-by-example/src/crates/link.md +++ /dev/null @@ -1,29 +0,0 @@ -# `extern crate` - -To link a crate to this new library, the `extern crate` declaration must be -used. This will not only link the library, but also import all its items under -a module named the same as the library. The visibility rules that apply to -modules also apply to libraries. - -```rust,ignore -// Link to `library`, import items under the `rary` module -extern crate rary; - -fn main() { - rary::public_function(); - - // Error! `private_function` is private - //rary::private_function(); - - rary::indirect_access(); -} -``` - -```txt -# Where library.rlib is the path to the compiled library, assumed that it's -# in the same directory here: -$ rustc executable.rs --extern rary=library.rlib && ./executable -called rary's `public_function()` -called rary's `indirect_access()`, that -> called rary's `private_function()` -``` diff --git a/src/doc/rust-by-example/src/crates/using_lib.md b/src/doc/rust-by-example/src/crates/using_lib.md new file mode 100644 index 0000000000..102080700f --- /dev/null +++ b/src/doc/rust-by-example/src/crates/using_lib.md @@ -0,0 +1,27 @@ +# Using a Library + +To link a crate to this new library you may use `rustc`'s `--extern` flag. All +of its items will then be imported under a module named the same as the library. +This module generally behaves the same way as any other module. + +```rust,ignore +// extern crate rary; // May be required for Rust 2015 edition or earlier + +fn main() { + rary::public_function(); + + // Error! `private_function` is private + //rary::private_function(); + + rary::indirect_access(); +} +``` + +```txt +# Where library.rlib is the path to the compiled library, assumed that it's +# in the same directory here: +$ rustc executable.rs --extern rary=library.rlib --edition=2018 && ./executable +called rary's `public_function()` +called rary's `indirect_access()`, that +> called rary's `private_function()` +``` diff --git a/src/doc/rust-by-example/src/custom_types/structs.md b/src/doc/rust-by-example/src/custom_types/structs.md index b7f84c2fa4..97bd46ba2a 100644 --- a/src/doc/rust-by-example/src/custom_types/structs.md +++ b/src/doc/rust-by-example/src/custom_types/structs.md @@ -9,9 +9,8 @@ There are three types of structures ("structs") that can be created using the ```rust,editable #[derive(Debug)] -struct Person<'a> { - // The 'a defines a lifetime - name: &'a str, +struct Person { + name: String, age: u8, } @@ -38,7 +37,7 @@ struct Rectangle { fn main() { // Create struct with field init shorthand - let name = "Peter"; + let name = String::from("Peter"); let age = 27; let peter = Person { name, age }; @@ -93,9 +92,8 @@ fn main() { ### See also: -[`attributes`][attributes], [lifetime][lifetime] and [destructuring][destructuring] +[`attributes`][attributes], and [destructuring][destructuring] [attributes]: ../attribute.md [c_struct]: https://en.wikipedia.org/wiki/Struct_(C_programming_language) [destructuring]: ../flow_control/match/destructuring.md -[lifetime]: ../scope/lifetime.md diff --git a/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md b/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md index e8acd25197..392b783aed 100644 --- a/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md +++ b/src/doc/rust-by-example/src/error/multiple_error_types/wrap_error.md @@ -4,6 +4,7 @@ An alternative to boxing errors is to wrap them in your own error type. ```rust,editable use std::error; +use std::error::Error as _; use std::num::ParseIntError; use std::fmt; @@ -22,8 +23,10 @@ impl fmt::Display for DoubleError { match *self { DoubleError::EmptyVec => write!(f, "please use a vector with at least one element"), - // This is a wrapper, so defer to the underlying types' implementation of `fmt`. - DoubleError::Parse(ref e) => e.fmt(f), + // The wrapped error contains additional information and is available + // via the source() method. + DoubleError::Parse(..) => + write!(f, "the provided string could not be parsed as int"), } } } @@ -51,6 +54,8 @@ impl From for DoubleError { fn double_first(vec: Vec<&str>) -> Result { let first = vec.first().ok_or(DoubleError::EmptyVec)?; + // Here we implicitly use the `ParseIntError` implementation of `From` (which + // we defined above) in order to create a `DoubleError`. let parsed = first.parse::()?; Ok(2 * parsed) @@ -59,7 +64,12 @@ fn double_first(vec: Vec<&str>) -> Result { fn print(result: Result) { match result { Ok(n) => println!("The first doubled is {}", n), - Err(e) => println!("Error: {}", e), + Err(e) => { + println!("Error: {}", e); + if let Some(source) = e.source() { + println!(" Caused by: {}", source); + } + }, } } diff --git a/src/doc/rust-by-example/src/error/panic.md b/src/doc/rust-by-example/src/error/panic.md index a690642539..5524dbf6f2 100644 --- a/src/doc/rust-by-example/src/error/panic.md +++ b/src/doc/rust-by-example/src/error/panic.md @@ -1,19 +1,19 @@ # `panic` -The simplest error handling mechanism we will see is `panic`. It prints an -error message, starts unwinding the stack, and usually exits the program. -Here, we explicitly call `panic` on our error condition: +The simplest error handling mechanism we will see is `panic`. It prints an +error message, starts unwinding the stack, and usually exits the program. +Here, we explicitly call `panic` on our error condition: ```rust,editable,ignore,mdbook-runnable -fn give_princess(gift: &str) { - // Princesses hate snakes, so we need to stop if she disapproves! - if gift == "snake" { panic!("AAAaaaaa!!!!"); } +fn drink(beverage: &str) { + // You shouldn't drink too much sugary beverages. + if beverage == "lemonade" { panic!("AAAaaaaa!!!!"); } - println!("I love {}s!!!!!", gift); + println!("Some refreshing {} is all I need.", beverage); } fn main() { - give_princess("teddy bear"); - give_princess("snake"); + drink("water"); + drink("lemonade"); } ``` diff --git a/src/doc/rust-by-example/src/mod/use.md b/src/doc/rust-by-example/src/mod/use.md index 8860bc20b4..7a57272b15 100644 --- a/src/doc/rust-by-example/src/mod/use.md +++ b/src/doc/rust-by-example/src/mod/use.md @@ -4,8 +4,6 @@ The `use` declaration can be used to bind a full path to a new name, for easier access. It is often used like this: ```rust,editable,ignore -// extern crate deeply; // normally, this would exist and not be commented out! - use crate::deeply::nested::{ my_first_function, my_second_function, diff --git a/src/doc/rust-by-example/src/primitives/array.md b/src/doc/rust-by-example/src/primitives/array.md index f612c1dbc2..50ea52fca4 100644 --- a/src/doc/rust-by-example/src/primitives/array.md +++ b/src/doc/rust-by-example/src/primitives/array.md @@ -1,10 +1,10 @@ # Arrays and Slices An array is a collection of objects of the same type `T`, stored in contiguous -memory. Arrays are created using brackets `[]`, and their size, which is known -at compile time, is part of their type signature `[T; size]`. +memory. Arrays are created using brackets `[]`, and their length, which is known +at compile time, is part of their type signature `[T; length]`. -Slices are similar to arrays, but their size is not known at compile time. +Slices are similar to arrays, but their length is not known at compile time. Instead, a slice is a two-word object, the first word is a pointer to the data, and the second word is the length of the slice. The word size is the same as usize, determined by the processor architecture eg 64 bits on an x86-64. @@ -31,8 +31,8 @@ fn main() { println!("first element of the array: {}", xs[0]); println!("second element of the array: {}", xs[1]); - // `len` returns the size of the array - println!("array size: {}", xs.len()); + // `len` returns the count of elements in the array + println!("number of elements in array: {}", xs.len()); // Arrays are stack allocated println!("array occupies {} bytes", mem::size_of_val(&xs)); diff --git a/src/doc/rust-by-example/src/std_misc/threads.md b/src/doc/rust-by-example/src/std_misc/threads.md index 7a9b2cf22d..2f37d1c4a3 100644 --- a/src/doc/rust-by-example/src/std_misc/threads.md +++ b/src/doc/rust-by-example/src/std_misc/threads.md @@ -6,7 +6,7 @@ function, the argument of this function is a moving closure. ```rust,editable use std::thread; -static NTHREADS: i32 = 10; +const NTHREADS: u32 = 10; // This is the `main` thread fn main() { diff --git a/src/doc/rust-by-example/src/testing/integration_testing.md b/src/doc/rust-by-example/src/testing/integration_testing.md index 2ab0d85a6e..a4345ae945 100644 --- a/src/doc/rust-by-example/src/testing/integration_testing.md +++ b/src/doc/rust-by-example/src/testing/integration_testing.md @@ -10,7 +10,7 @@ Cargo looks for integration tests in `tests` directory next to `src`. File `src/lib.rs`: ```rust,ignore -// Assume that crate is called adder, will have to extern it in integration test. +// Define this in a crate called `adder`. pub fn add(a: i32, b: i32) -> i32 { a + b } @@ -19,9 +19,6 @@ pub fn add(a: i32, b: i32) -> i32 { File with test: `tests/integration_test.rs`: ```rust,ignore -// extern crate we're testing, same as any other code would do. -extern crate adder; - #[test] fn test_add() { assert_eq!(adder::add(3, 2), 5); @@ -66,9 +63,6 @@ pub fn setup() { File with test: `tests/integration_test.rs` ```rust,ignore -// extern crate we're testing, same as any other code will do. -extern crate adder; - // importing common module. mod common; diff --git a/src/doc/rust-by-example/src/trait/clone.md b/src/doc/rust-by-example/src/trait/clone.md index 1b9d953b71..5d6747a47b 100644 --- a/src/doc/rust-by-example/src/trait/clone.md +++ b/src/doc/rust-by-example/src/trait/clone.md @@ -30,9 +30,9 @@ fn main() { let pair = Pair(Box::new(1), Box::new(2)); println!("original: {:?}", pair); - // Copy `pair` into `moved_pair`, moves resources + // Move `pair` into `moved_pair`, moves resources let moved_pair = pair; - println!("copy: {:?}", moved_pair); + println!("moved: {:?}", moved_pair); // Error! `pair` has lost its resources //println!("original: {:?}", pair); diff --git a/src/doc/rust-by-example/src/variable_bindings/scope.md b/src/doc/rust-by-example/src/variable_bindings/scope.md index d9639b42e3..9e3c79e3ee 100644 --- a/src/doc/rust-by-example/src/variable_bindings/scope.md +++ b/src/doc/rust-by-example/src/variable_bindings/scope.md @@ -1,9 +1,7 @@ # Scope and Shadowing Variable bindings have a scope, and are constrained to live in a *block*. A -block is a collection of statements enclosed by braces `{}`. Also, [variable -shadowing][variable-shadow] is allowed. - +block is a collection of statements enclosed by braces `{}`. ```rust,editable,ignore,mdbook-runnable fn main() { // This binding lives in the main function @@ -15,11 +13,6 @@ fn main() { let short_lived_binding = 2; println!("inner short: {}", short_lived_binding); - - // This binding *shadows* the outer one - let long_lived_binding = 5_f32; - - println!("inner long: {}", long_lived_binding); } // End of the block @@ -28,12 +21,26 @@ fn main() { // FIXME ^ Comment out this line println!("outer long: {}", long_lived_binding); - - // This binding also *shadows* the previous binding - let long_lived_binding = 'a'; - - println!("outer long: {}", long_lived_binding); } ``` +Also, [variable shadowing][variable-shadow] is allowed. +```rust,editable,ignore,mdbook-runnable +fn main() { + let shadowed_binding = 1; + { + println!("before being shadowed: {}", shadowed_binding); + + // This binding *shadows* the outer one + let shadowed_binding = "abc"; + + println!("shadowed in inner block: {}", shadowed_binding); + } + println!("outside inner block: {}", shadowed_binding); + + // This binding *shadows* the previous binding + let shadowed_binding = 2; + println!("shadowed in outer block: {}", shadowed_binding); +} +``` [variable-shadow]: https://en.wikipedia.org/wiki/Variable_shadowing diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 7b0280d5b7..bed10ca16d 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -44,13 +44,13 @@ incremental builds the default is 256 which allows caching to be more granular. ## control-flow-guard -This flag controls whether LLVM enables the Windows [Control Flow -Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) -platform security feature. This flag is currently ignored for non-Windows targets. +This flag controls whether LLVM enables the Windows [Control Flow +Guard](https://docs.microsoft.com/en-us/windows/win32/secbp/control-flow-guard) +platform security feature. This flag is currently ignored for non-Windows targets. It takes one of the following values: * `y`, `yes`, `on`, `checks`, or no value: enable Control Flow Guard. -* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this +* `nochecks`: emit Control Flow Guard metadata without runtime enforcement checks (this should only be used for testing purposes as it does not provide security enforcement). * `n`, `no`, `off`: do not enable Control Flow Guard (the default). @@ -200,6 +200,18 @@ the following values: An example of when this flag might be useful is when trying to construct code coverage metrics. +## link-self-contained + +On targets that support it this flag controls whether the linker will use libraries and objects +shipped with Rust instead or those in the system. +It takes one of the following values: + +* no value: rustc will use heuristic to disable self-contained mode if system has necessary tools. +* `y`, `yes`, `on`: use only libraries/objects shipped with Rust. +* `n`, `no`, or `off`: rely on the user or the linker to provide non-Rust libraries/objects. + +This allows overriding cases when detection fails or user wants to use shipped libraries. + ## linker This flag controls which linker `rustc` invokes to link your code. It takes a diff --git a/src/doc/rustc/src/linker-plugin-lto.md b/src/doc/rustc/src/linker-plugin-lto.md index c0b14352b7..18f1be6a1f 100644 --- a/src/doc/rustc/src/linker-plugin-lto.md +++ b/src/doc/rustc/src/linker-plugin-lto.md @@ -89,6 +89,28 @@ rustc -Clinker-plugin-lto="/path/to/LLVMgold.so" -L. -Copt-level=2 ./main.rs ## Toolchain Compatibility + + In order for this kind of LTO to work, the LLVM linker plugin must be able to handle the LLVM bitcode produced by both `rustc` and `clang`. @@ -100,17 +122,20 @@ LLVM. However, the approximation is usually reliable. The following table shows known good combinations of toolchain versions. -| | Clang 7 | Clang 8 | Clang 9 | -|-----------|-----------|-----------|-----------| -| Rust 1.34 | ✗ | ✓ | ✗ | -| Rust 1.35 | ✗ | ✓ | ✗ | -| Rust 1.36 | ✗ | ✓ | ✗ | -| Rust 1.37 | ✗ | ✓ | ✗ | -| Rust 1.38 | ✗ | ✗ | ✓ | -| Rust 1.39 | ✗ | ✗ | ✓ | -| Rust 1.40 | ✗ | ✗ | ✓ | -| Rust 1.41 | ✗ | ✗ | ✓ | -| Rust 1.42 | ✗ | ✗ | ✓ | -| Rust 1.43 | ✗ | ✗ | ✓ | +| Rust Version | Clang Version | +|--------------|---------------| +| Rust 1.34 | Clang 8 | +| Rust 1.35 | Clang 8 | +| Rust 1.36 | Clang 8 | +| Rust 1.37 | Clang 8 | +| Rust 1.38 | Clang 9 | +| Rust 1.39 | Clang 9 | +| Rust 1.40 | Clang 9 | +| Rust 1.41 | Clang 9 | +| Rust 1.42 | Clang 9 | +| Rust 1.43 | Clang 9 | +| Rust 1.44 | Clang 9 | +| Rust 1.45 | Clang 10 | +| Rust 1.46 | Clang 10 | Note that the compatibility policy for this feature might change in the future. diff --git a/src/doc/rustc/src/lints/groups.md b/src/doc/rustc/src/lints/groups.md index 049e59b651..44cf42ff0d 100644 --- a/src/doc/rustc/src/lints/groups.md +++ b/src/doc/rustc/src/lints/groups.md @@ -14,14 +14,7 @@ $ rustc -D non-camel-case-types -D non-snake-case -D non-upper-case-globals Here's a list of each lint group, and the lints that they are made up of: -| group | description | lints | -|---------------------|---------------------------------------------------------------|----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------| -| nonstandard-style | Violation of standard naming conventions | non-camel-case-types, non-snake-case, non-upper-case-globals | -| warnings | all lints that would be issuing warnings | all lints that would be issuing warnings | -| edition-2018 | Lints that will be turned into errors in Rust 2018 | tyvar-behind-raw-pointer | -| rust-2018-idioms | Lints to nudge you toward idiomatic features of Rust 2018 | bare-trait-object, unreachable-pub | -| unused | These lints detect things being declared but not used | unused-imports, unused-variables, unused-assignments, dead-code, unused-mut, unreachable-code, unreachable-patterns, unused-must-use, unused-unsafe, path-statements, unused-attributes, unused-macros, unused-allocation, unused-doc-comment, unused-extern-crates, unused-features, unused-parens | -| future-incompatible | Lints that detect code that has future-compatibility problems | private-in-public, pub-use-of-private-extern-crate, patterns-in-fns-without-body, safe-extern-statics, invalid-type-param-default, legacy-directory-ownership, legacy-imports, legacy-constructor-visibility, missing-fragment-specifier, illegal-floating-point-literal-pattern, anonymous-parameters, parenthesized-params-in-types-and-modules, late-bound-lifetime-arguments, safe-packed-borrows, tyvar-behind-raw-pointer, unstable-name-collision | +{{groups-table}} Additionally, there's a `bad-style` lint group that's a deprecated alias for `nonstandard-style`. diff --git a/src/doc/rustc/src/lints/index.md b/src/doc/rustc/src/lints/index.md index 9010d436eb..029c9edc1b 100644 --- a/src/doc/rustc/src/lints/index.md +++ b/src/doc/rustc/src/lints/index.md @@ -26,3 +26,35 @@ warning: unused variable: `x` This is the `unused_variables` lint, and it tells you that you've introduced a variable that you don't use in your code. That's not *wrong*, so it's not an error, but it might be a bug, so you get a warning. + +## Future-incompatible lints + +Sometimes the compiler needs to be changed to fix an issue that can cause +existing code to stop compiling. "Future-incompatible" lints are issued in +these cases to give users of Rust a smooth transition to the new behavior. +Initially, the compiler will continue to accept the problematic code and issue +a warning. The warning has a description of the problem, a notice that this +will become an error in the future, and a link to a tracking issue that +provides detailed information and an opportunity for feedback. This gives +users some time to fix the code to accommodate the change. After some time, +the warning may become an error. + +The following is an example of what a future-incompatible looks like: + +```text +warning: borrow of packed field is unsafe and requires unsafe function or block (error E0133) + --> lint_example.rs:11:13 + | +11 | let y = &x.data.0; + | ^^^^^^^^^ + | + = note: `#[warn(safe_packed_borrows)]` 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 #46043 + = note: fields of packed structs might be misaligned: dereferencing a misaligned pointer or even just creating a misaligned reference is undefined behavior +``` + +For more information about the process and policy of future-incompatible +changes, see [RFC 1589]. + +[RFC 1589]: https://github.com/rust-lang/rfcs/blob/master/text/1589-rustc-bug-fix-procedure.md diff --git a/src/doc/rustc/src/lints/listing/allowed-by-default.md b/src/doc/rustc/src/lints/listing/allowed-by-default.md index d3dfc3197e..95dd60bebf 100644 --- a/src/doc/rustc/src/lints/listing/allowed-by-default.md +++ b/src/doc/rustc/src/lints/listing/allowed-by-default.md @@ -1,453 +1,3 @@ # Allowed-by-default lints -These lints are all set to the 'allow' level by default. As such, they won't show up -unless you set them to a higher lint level with a flag or attribute. - -## anonymous-parameters - -This lint detects anonymous parameters. Some example code that triggers this lint: - -```rust -trait Foo { - fn foo(usize); -} -``` - -When set to 'deny', this will produce: - -```text -error: use of deprecated anonymous parameter - --> src/lib.rs:5:11 - | -5 | fn foo(usize); - | ^ - | - = 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 #41686 -``` - -This syntax is mostly a historical accident, and can be worked around quite -easily: - -```rust -trait Foo { - fn foo(_: usize); -} -``` - -## bare-trait-object - -This lint suggests using `dyn Trait` for trait objects. Some example code -that triggers this lint: - -```rust -#![feature(dyn_trait)] - -trait Trait { } - -fn takes_trait_object(_: Box) { -} -``` - -When set to 'deny', this will produce: - -```text -error: trait objects without an explicit `dyn` are deprecated - --> src/lib.rs:7:30 - | -7 | fn takes_trait_object(_: Box) { - | ^^^^^ help: use `dyn`: `dyn Trait` - | -``` - -To fix it, do as the help message suggests: - -```rust -#![feature(dyn_trait)] -#![deny(bare_trait_objects)] - -trait Trait { } - -fn takes_trait_object(_: Box) { -} -``` - -## box-pointers - -This lints use of the Box type. Some example code that triggers this lint: - -```rust -struct Foo { - x: Box, -} -``` - -When set to 'deny', this will produce: - -```text -error: type uses owned (Box type) pointers: std::boxed::Box - --> src/lib.rs:6:5 - | -6 | x: Box //~ ERROR type uses owned - | ^^^^^^^^^^^^^ - | -``` - -This lint is mostly historical, and not particularly useful. `Box` used to -be built into the language, and the only way to do heap allocation. Today's -Rust can call into other allocators, etc. - -## elided-lifetime-in-path - -This lint detects the use of hidden lifetime parameters. Some example code -that triggers this lint: - -```rust -struct Foo<'a> { - x: &'a u32 -} - -fn foo(x: &Foo) { -} -``` - -When set to 'deny', this will produce: - -```text -error: hidden lifetime parameters are deprecated, try `Foo<'_>` - --> src/lib.rs:5:12 - | -5 | fn foo(x: &Foo) { - | ^^^ - | -``` - -Lifetime elision elides this lifetime, but that is being deprecated. - -## missing-copy-implementations - -This lint detects potentially-forgotten implementations of `Copy`. Some -example code that triggers this lint: - -```rust -pub struct Foo { - pub field: i32 -} -``` - -When set to 'deny', this will produce: - -```text -error: type could implement `Copy`; consider adding `impl Copy` - --> src/main.rs:3:1 - | -3 | / pub struct Foo { //~ ERROR type could implement `Copy`; consider adding `impl Copy` -4 | | pub field: i32 -5 | | } - | |_^ - | -``` - -You can fix the lint by deriving `Copy`. - -This lint is set to 'allow' because this code isn't bad; it's common to write -newtypes like this specifically so that a `Copy` type is no longer `Copy`. - -## missing-debug-implementations - -This lint detects missing implementations of `fmt::Debug`. Some example code -that triggers this lint: - -```rust -pub struct Foo; -``` - -When set to 'deny', this will produce: - -```text -error: type does not implement `fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation - --> src/main.rs:3:1 - | -3 | pub struct Foo; - | ^^^^^^^^^^^^^^^ - | -``` - -You can fix the lint by deriving `Debug`. - -## missing-docs - -This lint detects missing documentation for public items. Some example code -that triggers this lint: - -```rust -pub fn foo() {} -``` - -When set to 'deny', this will produce: - -```text -error: missing documentation for crate - --> src/main.rs:1:1 - | -1 | / #![deny(missing_docs)] -2 | | -3 | | pub fn foo() {} -4 | | -5 | | fn main() {} - | |____________^ - | - -error: missing documentation for a function - --> src/main.rs:3:1 - | -3 | pub fn foo() {} - | ^^^^^^^^^^^^ - -``` - -To fix the lint, add documentation to all items. - -## single-use-lifetimes - -This lint detects lifetimes that are only used once. Some example code that -triggers this lint: - -```rust -struct Foo<'x> { - x: &'x u32 -} -``` - -When set to 'deny', this will produce: - -```text -error: lifetime name `'x` only used once - --> src/main.rs:3:12 - | -3 | struct Foo<'x> { - | ^^ - | -``` - -## trivial-casts - -This lint detects trivial casts which could be removed. Some example code -that triggers this lint: - -```rust -let x: &u32 = &42; -let _ = x as *const u32; -``` - -When set to 'deny', this will produce: - -```text -error: trivial cast: `&u32` as `*const u32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable - --> src/main.rs:5:13 - | -5 | let _ = x as *const u32; - | ^^^^^^^^^^^^^^^ - | -note: lint level defined here - --> src/main.rs:1:9 - | -1 | #![deny(trivial_casts)] - | ^^^^^^^^^^^^^ -``` - -## trivial-numeric-casts - -This lint detects trivial casts of numeric types which could be removed. Some -example code that triggers this lint: - -```rust -let x = 42i32 as i32; -``` - -When set to 'deny', this will produce: - -```text -error: trivial numeric cast: `i32` as `i32`. Cast can be replaced by coercion, this might require type ascription or a temporary variable - --> src/main.rs:4:13 - | -4 | let x = 42i32 as i32; - | ^^^^^^^^^^^^ - | -``` - -## unreachable-pub - -This lint triggers for `pub` items not reachable from the crate root. Some -example code that triggers this lint: - -```rust -mod foo { - pub mod bar { - - } -} -``` - -When set to 'deny', this will produce: - -```text -error: unreachable `pub` item - --> src/main.rs:4:5 - | -4 | pub mod bar { - | ---^^^^^^^^ - | | - | help: consider restricting its visibility: `pub(crate)` - | -``` - -## unsafe-code - -This lint catches usage of `unsafe` code. Some example code that triggers this lint: - -```rust -fn main() { - unsafe { - - } -} -``` - -When set to 'deny', this will produce: - -```text -error: usage of an `unsafe` block - --> src/main.rs:4:5 - | -4 | / unsafe { -5 | | -6 | | } - | |_____^ - | -``` - -## unstable-features - -This lint is deprecated and no longer used. - -## unused-extern-crates - -This lint guards against `extern crate` items that are never used. Some -example code that triggers this lint: - -```rust,ignore -extern crate semver; -``` - -When set to 'deny', this will produce: - -```text -error: unused extern crate - --> src/main.rs:3:1 - | -3 | extern crate semver; - | ^^^^^^^^^^^^^^^^^^^^ - | -``` - -## unused-import-braces - -This lint catches unnecessary braces around an imported item. Some example -code that triggers this lint: - -```rust -use test::{A}; - -pub mod test { - pub struct A; -} -# fn main() {} -``` - -When set to 'deny', this will produce: - -```text -error: braces around A is unnecessary - --> src/main.rs:3:1 - | -3 | use test::{A}; - | ^^^^^^^^^^^^^^ - | -``` - -To fix it, `use test::A;` - -## unused-qualifications - -This lint detects unnecessarily qualified names. Some example code that triggers this lint: - -```rust -mod foo { - pub fn bar() {} -} - -fn main() { - use foo::bar; - foo::bar(); -} -``` - -When set to 'deny', this will produce: - -```text -error: unnecessary qualification - --> src/main.rs:9:5 - | -9 | foo::bar(); - | ^^^^^^^^ - | -``` - -You can call `bar()` directly, without the `foo::`. - -## unused-results - -This lint checks for the unused result of an expression in a statement. Some -example code that triggers this lint: - -```rust,no_run -fn foo() -> T { panic!() } - -fn main() { - foo::(); -} -``` - -When set to 'deny', this will produce: - -```text -error: unused result - --> src/main.rs:6:5 - | -6 | foo::(); - | ^^^^^^^^^^^^^^^ - | -``` - -## variant-size-differences - -This lint detects enums with widely varying variant sizes. Some example code that triggers this lint: - -```rust -enum En { - V0(u8), - VBig([u8; 1024]), -} -``` - -When set to 'deny', this will produce: - -```text -error: enum variant is more than three times larger (1024 bytes) than the next largest - --> src/main.rs:5:5 - | -5 | VBig([u8; 1024]), //~ ERROR variant is more than three times larger - | ^^^^^^^^^^^^^^^^ - | -``` +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/lints/listing/deny-by-default.md b/src/doc/rustc/src/lints/listing/deny-by-default.md index dc5a9e44ac..3c1452d646 100644 --- a/src/doc/rustc/src/lints/listing/deny-by-default.md +++ b/src/doc/rustc/src/lints/listing/deny-by-default.md @@ -1,212 +1,3 @@ # Deny-by-default lints -These lints are all set to the 'deny' level by default. - -## exceeding-bitshifts - -This lint detects that a shift exceeds the type's number of bits. Some -example code that triggers this lint: - -```rust,ignore -1_i32 << 32; -``` - -This will produce: - -```text -error: bitshift exceeds the type's number of bits - --> src/main.rs:2:5 - | -2 | 1_i32 << 32; - | ^^^^^^^^^^^ - | -``` - -## invalid-type-param-default - -This lint detects type parameter default erroneously allowed in invalid location. Some -example code that triggers this lint: - -```rust,ignore -fn foo(t: T) {} -``` - -This will produce: - -```text -error: defaults for type parameters are only allowed in `struct`, `enum`, `type`, or `trait` definitions. - --> src/main.rs:4:8 - | -4 | fn foo(t: T) {} - | ^ - | - = note: `#[deny(invalid_type_param_default)]` 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 #36887 -``` - -## missing-fragment-specifier - -The missing_fragment_specifier warning is issued when an unused pattern in a -`macro_rules!` macro definition has a meta-variable (e.g. `$e`) that is not -followed by a fragment specifier (e.g. `:expr`). - -This warning can always be fixed by removing the unused pattern in the -`macro_rules!` macro definition. - -## mutable-transmutes - -This lint catches transmuting from `&T` to `&mut T` because it is undefined -behavior. Some example code that triggers this lint: - -```rust,ignore -unsafe { - let y = std::mem::transmute::<&i32, &mut i32>(&5); -} -``` - -This will produce: - -```text -error: mutating transmuted &mut T from &T may cause undefined behavior, consider instead using an UnsafeCell - --> src/main.rs:3:17 - | -3 | let y = std::mem::transmute::<&i32, &mut i32>(&5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | -``` - - -## no-mangle-const-items - -This lint detects any `const` items with the `#[no_mangle]` attribute. -Constants do not have their symbols exported, and therefore, this probably -means you meant to use a `static`, not a `const`. Some example code that -triggers this lint: - -```rust,ignore -#[no_mangle] -const FOO: i32 = 5; -``` - -This will produce: - -```text -error: const items should never be `#[no_mangle]` - --> src/main.rs:3:1 - | -3 | const FOO: i32 = 5; - | -----^^^^^^^^^^^^^^ - | | - | help: try a static value: `pub static` - | -``` - -## overflowing-literals - -This lint detects literal out of range for its type. Some -example code that triggers this lint: - -```rust,compile_fail -let x: u8 = 1000; -``` - -This will produce: - -```text -error: literal out of range for u8 - --> src/main.rs:2:17 - | -2 | let x: u8 = 1000; - | ^^^^ - | -``` - -## patterns-in-fns-without-body - -This lint detects patterns in functions without body were that were -previously erroneously allowed. Some example code that triggers this lint: - -```rust,compile_fail -trait Trait { - fn foo(mut arg: u8); -} -``` - -This will produce: - -```text -warning: patterns aren't allowed in methods without bodies - --> src/main.rs:2:12 - | -2 | fn foo(mut arg: u8); - | ^^^^^^^ - | - = note: `#[warn(patterns_in_fns_without_body)]` 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 #35203 -``` - -To fix this, remove the pattern; it can be used in the implementation without -being used in the definition. That is: - -```rust -trait Trait { - fn foo(arg: u8); -} - -impl Trait for i32 { - fn foo(mut arg: u8) { - - } -} -``` - -## pub-use-of-private-extern-crate - -This lint detects a specific situation of re-exporting a private `extern crate`; - -## unknown-crate-types - -This lint detects an unknown crate type found in a `#[crate_type]` directive. Some -example code that triggers this lint: - -```rust,ignore -#![crate_type="lol"] -``` - -This will produce: - -```text -error: invalid `crate_type` value - --> src/lib.rs:1:1 - | -1 | #![crate_type="lol"] - | ^^^^^^^^^^^^^^^^^^^^ - | -``` - -## const-err - -This lint detects expressions that will always panic at runtime and would be an -error in a `const` context. - -```rust,ignore -let _ = [0; 4][4]; -``` - -This will produce: - -```text -error: index out of bounds: the len is 4 but the index is 4 - --> src/lib.rs:1:9 - | -1 | let _ = [0; 4][4]; - | ^^^^^^^^^ - | -``` - -## order-dependent-trait-objects - -This lint detects a trait coherency violation that would allow creating two -trait impls for the same dynamic trait object involving marker traits. +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/lints/listing/warn-by-default.md b/src/doc/rustc/src/lints/listing/warn-by-default.md index 386f6008d0..eebc022a82 100644 --- a/src/doc/rustc/src/lints/listing/warn-by-default.md +++ b/src/doc/rustc/src/lints/listing/warn-by-default.md @@ -1,903 +1,3 @@ # Warn-by-default lints -These lints are all set to the 'warn' level by default. - -## const-err - -This lint detects an erroneous expression while doing constant evaluation. Some -example code that triggers this lint: - -```rust,ignore -let b = 200u8 + 200u8; -``` - -This will produce: - -```text -warning: attempt to add with overflow - --> src/main.rs:2:9 - | -2 | let b = 200u8 + 200u8; - | ^^^^^^^^^^^^^ - | -``` - -## dead-code - -This lint detects unused, unexported items. Some -example code that triggers this lint: - -```rust -fn foo() {} -``` - -This will produce: - -```text -warning: function is never used: `foo` - --> src/lib.rs:2:1 - | -2 | fn foo() {} - | ^^^^^^^^ - | -``` - -## deprecated - -This lint detects use of deprecated items. Some -example code that triggers this lint: - -```rust -#[deprecated] -fn foo() {} - -fn bar() { - foo(); -} -``` - -This will produce: - -```text -warning: use of deprecated item 'foo' - --> src/lib.rs:7:5 - | -7 | foo(); - | ^^^ - | -``` - -## illegal-floating-point-literal-pattern - -This lint detects floating-point literals used in patterns. Some example code -that triggers this lint: - -```rust -let x = 42.0; - -match x { - 5.0 => {}, - _ => {}, -} -``` - -This will produce: - -```text -warning: floating-point literals cannot be used in patterns - --> src/main.rs:4:9 - | -4 | 5.0 => {}, - | ^^^ - | - = note: `#[warn(illegal_floating_point_literal_pattern)]` 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 #41620 -``` - -## improper-ctypes - -This lint detects proper use of libc types in foreign modules. Some -example code that triggers this lint: - -```rust -extern "C" { - static STATIC: String; -} -``` - -This will produce: - -```text -warning: found struct without foreign-function-safe representation annotation in foreign module, consider adding a `#[repr(C)]` attribute to the type - --> src/main.rs:2:20 - | -2 | static STATIC: String; - | ^^^^^^ - | -``` - -## late-bound-lifetime-arguments - -This lint detects generic lifetime arguments in path segments with -late bound lifetime parameters. Some example code that triggers this lint: - -```rust -struct S; - -impl S { - fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} -} - -fn main() { - S.late::<'static>(&0, &0); -} -``` - -This will produce: - -```text -warning: cannot specify lifetime arguments explicitly if late bound lifetime parameters are present - --> src/main.rs:8:14 - | -4 | fn late<'a, 'b>(self, _: &'a u8, _: &'b u8) {} - | -- the late bound lifetime parameter is introduced here -... -8 | S.late::<'static>(&0, &0); - | ^^^^^^^ - | - = note: `#[warn(late_bound_lifetime_arguments)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! - = note: for more information, see issue #42868 -``` - -## non-camel-case-types - -This lint detects types, variants, traits and type parameters that don't have -camel case names. Some example code that triggers this lint: - -```rust -struct s; -``` - -This will produce: - -```text -warning: type `s` should have a camel case name such as `S` - --> src/main.rs:1:1 - | -1 | struct s; - | ^^^^^^^^^ - | -``` - -## non-shorthand-field-patterns - -This lint detects using `Struct { x: x }` instead of `Struct { x }` in a pattern. Some -example code that triggers this lint: - -```rust -struct Point { - x: i32, - y: i32, -} - - -fn main() { - let p = Point { - x: 5, - y: 5, - }; - - match p { - Point { x: x, y: y } => (), - } -} -``` - -This will produce: - -```text -warning: the `x:` in this pattern is redundant - --> src/main.rs:14:17 - | -14 | Point { x: x, y: y } => (), - | --^^ - | | - | help: remove this - | - -warning: the `y:` in this pattern is redundant - --> src/main.rs:14:23 - | -14 | Point { x: x, y: y } => (), - | --^^ - | | - | help: remove this - -``` - -## non-snake-case - -This lint detects variables, methods, functions, lifetime parameters and -modules that don't have snake case names. Some example code that triggers -this lint: - -```rust -let X = 5; -``` - -This will produce: - -```text -warning: variable `X` should have a snake case name such as `x` - --> src/main.rs:2:9 - | -2 | let X = 5; - | ^ - | -``` - -## non-upper-case-globals - -This lint detects static constants that don't have uppercase identifiers. -Some example code that triggers this lint: - -```rust -static x: i32 = 5; -``` - -This will produce: - -```text -warning: static variable `x` should have an upper case name such as `X` - --> src/main.rs:1:1 - | -1 | static x: i32 = 5; - | ^^^^^^^^^^^^^^^^^^ - | -``` - -## no-mangle-generic-items - -This lint detects generic items must be mangled. Some -example code that triggers this lint: - -```rust -#[no_mangle] -fn foo(t: T) { - -} -``` - -This will produce: - -```text -warning: functions generic over types must be mangled - --> src/main.rs:2:1 - | -1 | #[no_mangle] - | ------------ help: remove this attribute -2 | / fn foo(t: T) { -3 | | -4 | | } - | |_^ - | -``` - -## path-statements - -This lint detects path statements with no effect. Some example code that -triggers this lint: - -```rust -let x = 42; - -x; -``` - -This will produce: - -```text -warning: path statement with no effect - --> src/main.rs:3:5 - | -3 | x; - | ^^ - | -``` - -## private-in-public - -This lint detects private items in public interfaces not caught by the old implementation. Some -example code that triggers this lint: - -```rust,ignore -pub trait Trait { - type A; -} - -pub struct S; - -mod foo { - struct Z; - - impl ::Trait for ::S { - type A = Z; - } -} -# fn main() {} -``` - -This will produce: - -```text -error[E0446]: private type `foo::Z` in public interface - --> src/main.rs:11:9 - | -11 | type A = Z; - | ^^^^^^^^^^^ can't leak private type -``` - -## private-no-mangle-fns - -This lint detects functions marked `#[no_mangle]` that are also private. -Given that private functions aren't exposed publicly, and `#[no_mangle]` -controls the public symbol, this combination is erroneous. Some example code -that triggers this lint: - -```rust -#[no_mangle] -fn foo() {} -``` - -This will produce: - -```text -warning: function is marked `#[no_mangle]`, but not exported - --> src/main.rs:2:1 - | -2 | fn foo() {} - | -^^^^^^^^^^ - | | - | help: try making it public: `pub` - | -``` - -To fix this, either make it public or remove the `#[no_mangle]`. - -## private-no-mangle-statics - -This lint detects any statics marked `#[no_mangle]` that are private. -Given that private statics aren't exposed publicly, and `#[no_mangle]` -controls the public symbol, this combination is erroneous. Some example code -that triggers this lint: - -```rust -#[no_mangle] -static X: i32 = 4; -``` - -This will produce: - -```text -warning: static is marked `#[no_mangle]`, but not exported - --> src/main.rs:2:1 - | -2 | static X: i32 = 4; - | -^^^^^^^^^^^^^^^^^ - | | - | help: try making it public: `pub` - | -``` - -To fix this, either make it public or remove the `#[no_mangle]`. - -## renamed-and-removed-lints - -This lint detects lints that have been renamed or removed. Some -example code that triggers this lint: - -```rust -#![deny(raw_pointer_derive)] -``` - -This will produce: - -```text -warning: lint raw_pointer_derive has been removed: using derive with raw pointers is ok - --> src/main.rs:1:9 - | -1 | #![deny(raw_pointer_derive)] - | ^^^^^^^^^^^^^^^^^^ - | -``` - -To fix this, either remove the lint or use the new name. - -## safe-packed-borrows - -This lint detects borrowing a field in the interior of a packed structure -with alignment other than 1. Some example code that triggers this lint: - -```rust -#[repr(packed)] -pub struct Unaligned(pub T); - -pub struct Foo { - start: u8, - data: Unaligned, -} - -fn main() { - let x = Foo { start: 0, data: Unaligned(1) }; - let y = &x.data.0; -} -``` - -This will produce: - -```text -warning: borrow of packed field requires unsafe function or block (error E0133) - --> src/main.rs:11:13 - | -11 | let y = &x.data.0; - | ^^^^^^^^^ - | - = note: `#[warn(safe_packed_borrows)]` 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 #46043 -``` - -## stable-features - -This lint detects a `#[feature]` attribute that's since been made stable. Some -example code that triggers this lint: - -```rust -#![feature(test_accepted_feature)] -``` - -This will produce: - -```text -warning: this feature has been stable since 1.0.0. Attribute no longer needed - --> src/main.rs:1:12 - | -1 | #![feature(test_accepted_feature)] - | ^^^^^^^^^^^^^^^^^^^^^ - | -``` - -To fix, simply remove the `#![feature]` attribute, as it's no longer needed. - -## type-alias-bounds - -This lint detects bounds in type aliases. These are not currently enforced. -Some example code that triggers this lint: - -```rust -#[allow(dead_code)] -type SendVec = Vec; -``` - -This will produce: - -```text -warning: bounds on generic parameters are not enforced in type aliases - --> src/lib.rs:2:17 - | -2 | type SendVec = Vec; - | ^^^^ - | - = note: `#[warn(type_alias_bounds)]` on by default - = help: the bound will not be checked when the type alias is used, and should be removed -``` - -## tyvar-behind-raw-pointer - -This lint detects raw pointer to an inference variable. Some -example code that triggers this lint: - -```rust -let data = std::ptr::null(); -let _ = &data as *const *const (); - -if data.is_null() {} -``` - -This will produce: - -```text -warning: type annotations needed - --> src/main.rs:4:13 - | -4 | if data.is_null() {} - | ^^^^^^^ - | - = note: `#[warn(tyvar_behind_raw_pointer)]` on by default - = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in the 2018 edition! - = note: for more information, see issue #46906 -``` - -## unconditional-recursion - -This lint detects functions that cannot return without calling themselves. -Some example code that triggers this lint: - -```rust -fn foo() { - foo(); -} -``` - -This will produce: - -```text -warning: function cannot return without recursing - --> src/main.rs:1:1 - | -1 | fn foo() { - | ^^^^^^^^ cannot return without recursing -2 | foo(); - | ----- recursive call site - | -``` - -## unknown-lints - -This lint detects unrecognized lint attribute. Some -example code that triggers this lint: - -```rust,ignore -#[allow(not_a_real_lint)] -``` - -This will produce: - -```text -warning: unknown lint: `not_a_real_lint` - --> src/main.rs:1:10 - | -1 | #![allow(not_a_real_lint)] - | ^^^^^^^^^^^^^^^ - | -``` - -## unreachable-code - -This lint detects unreachable code paths. Some example code that -triggers this lint: - -```rust,no_run -panic!("we never go past here!"); - -let x = 5; -``` - -This will produce: - -```text -warning: unreachable statement - --> src/main.rs:4:5 - | -4 | let x = 5; - | ^^^^^^^^^^ - | -``` - -## unreachable-patterns - -This lint detects unreachable patterns. Some -example code that triggers this lint: - -```rust -let x = 5; -match x { - y => (), - 5 => (), -} -``` - -This will produce: - -```text -warning: unreachable pattern - --> src/main.rs:5:5 - | -5 | 5 => (), - | ^ - | -``` - -The `y` pattern will always match, so the five is impossible to reach. -Remember, match arms match in order, you probably wanted to put the `5` case -above the `y` case. - -## unstable-name-collision - -This lint detects that you've used a name that the standard library plans to -add in the future, which means that your code may fail to compile without -additional type annotations in the future. Either rename, or add those -annotations now. - -## unused-allocation - -This lint detects unnecessary allocations that can be eliminated. - -## unused-assignments - -This lint detects assignments that will never be read. Some -example code that triggers this lint: - -```rust -let mut x = 5; -x = 6; -``` - -This will produce: - -```text -warning: value assigned to `x` is never read - --> src/main.rs:4:5 - | -4 | x = 6; - | ^ - | -``` - -## unused-attributes - -This lint detects attributes that were not used by the compiler. Some -example code that triggers this lint: - -```rust -#![macro_export] -``` - -This will produce: - -```text -warning: unused attribute - --> src/main.rs:1:1 - | -1 | #![macro_export] - | ^^^^^^^^^^^^^^^^ - | -``` - -## unused-comparisons - -This lint detects comparisons made useless by limits of the types involved. Some -example code that triggers this lint: - -```rust -fn foo(x: u8) { - x >= 0; -} -``` - -This will produce: - -```text -warning: comparison is useless due to type limits - --> src/main.rs:6:5 - | -6 | x >= 0; - | ^^^^^^ - | -``` - -## unused-doc-comment - -This lint detects doc comments that aren't used by rustdoc. Some -example code that triggers this lint: - -```rust -/// docs for x -let x = 12; -``` - -This will produce: - -```text -warning: doc comment not used by rustdoc - --> src/main.rs:2:5 - | -2 | /// docs for x - | ^^^^^^^^^^^^^^ - | -``` - -## unused-features - -This lint detects unused or unknown features found in crate-level `#[feature]` directives. -To fix this, simply remove the feature flag. - -## unused-imports - -This lint detects imports that are never used. Some -example code that triggers this lint: - -```rust -use std::collections::HashMap; -``` - -This will produce: - -```text -warning: unused import: `std::collections::HashMap` - --> src/main.rs:1:5 - | -1 | use std::collections::HashMap; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | -``` - -## unused-macros - -This lint detects macros that were not used. Some example code that -triggers this lint: - -```rust -macro_rules! unused { - () => {}; -} - -fn main() { -} -``` - -This will produce: - -```text -warning: unused macro definition - --> src/main.rs:1:1 - | -1 | / macro_rules! unused { -2 | | () => {}; -3 | | } - | |_^ - | -``` - -## unused-must-use - -This lint detects unused result of a type flagged as `#[must_use]`. Some -example code that triggers this lint: - -```rust -fn returns_result() -> Result<(), ()> { - Ok(()) -} - -fn main() { - returns_result(); -} -``` - -This will produce: - -```text -warning: unused `std::result::Result` that must be used - --> src/main.rs:6:5 - | -6 | returns_result(); - | ^^^^^^^^^^^^^^^^^ - | -``` - -## unused-mut - -This lint detects mut variables which don't need to be mutable. Some -example code that triggers this lint: - -```rust -let mut x = 5; -``` - -This will produce: - -```text -warning: variable does not need to be mutable - --> src/main.rs:2:9 - | -2 | let mut x = 5; - | ----^ - | | - | help: remove this `mut` - | -``` - -## unused-parens - -This lint detects `if`, `match`, `while` and `return` with parentheses; they -do not need them. Some example code that triggers this lint: - -```rust -if(true) {} -``` - -This will produce: - -```text -warning: unnecessary parentheses around `if` condition - --> src/main.rs:2:7 - | -2 | if(true) {} - | ^^^^^^ help: remove these parentheses - | -``` - -## unused-unsafe - -This lint detects unnecessary use of an `unsafe` block. Some -example code that triggers this lint: - -```rust -unsafe {} -``` - -This will produce: - -```text -warning: unnecessary `unsafe` block - --> src/main.rs:2:5 - | -2 | unsafe {} - | ^^^^^^ unnecessary `unsafe` block - | -``` - -## unused-variables - -This lint detects variables which are not used in any way. Some -example code that triggers this lint: - -```rust -let x = 5; -``` - -This will produce: - -```text -warning: unused variable: `x` - --> src/main.rs:2:9 - | -2 | let x = 5; - | ^ help: consider using `_x` instead - | -``` - -## warnings - -This lint is a bit special; by changing its level, you change every other warning -that would produce a warning to whatever value you'd like: - -```rust -#![deny(warnings)] -``` - -As such, you won't ever trigger this lint in your code directly. - -## while-true - -This lint detects `while true { }`. Some example code that triggers this -lint: - -```rust,no_run -while true { - -} -``` - -This will produce: - -```text -warning: denote infinite loops with `loop { ... }` - --> src/main.rs:2:5 - | -2 | while true { - | ^^^^^^^^^^ help: use `loop` - | -``` +This file is auto-generated by the lint-docs script. diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 2187485383..6c605f045e 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -57,12 +57,12 @@ Specifically, these platforms are required to have each of the following: target | std | host | notes -------|-----|------|------- -`aarch64-apple-ios` | ✓[^apple] | | ARM64 iOS +`aarch64-apple-ios` | ✓ | | ARM64 iOS `aarch64-fuchsia` | ✓ | | ARM64 Fuchsia `aarch64-linux-android` | ✓ | | ARM64 Android `aarch64-pc-windows-msvc` | ✓ | | ARM64 Windows MSVC `aarch64-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (kernel 4.2, glibc 2.17) -`aarch64-unknown-linux-musl` | ✓ | | ARM64 Linux with MUSL +`aarch64-unknown-linux-musl` | ✓ | ✓ | ARM64 Linux with MUSL `aarch64-unknown-none` | * | | Bare ARM64, hardfloat `aarch64-unknown-none-softfloat` | * | | Bare ARM64, softfloat `arm-linux-androideabi` | ✓ | | ARMv7 Android @@ -118,11 +118,11 @@ target | std | host | notes `thumbv7neon-unknown-linux-gnueabihf` | ✓ | | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23) `thumbv8m.base-none-eabi` | * | | ARMv8-M Baseline `thumbv8m.main-none-eabi` | * | | ARMv8-M Mainline -`thumbv8m.main-none-eabihf` | * | | ARMv8-M Baseline, hardfloat +`thumbv8m.main-none-eabihf` | * | | ARMv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | | WebAssembly `wasm32-wasi` | ✓ | | WebAssembly with WASI -`x86_64-apple-ios` | ✓[^apple] | | 64-bit x86 iOS +`x86_64-apple-ios` | ✓ | | 64-bit x86 iOS `x86_64-fortanix-unknown-sgx` | ✓ | | [Fortanix ABI] for 64-bit Intel SGX `x86_64-fuchsia` | ✓ | | 64-bit Fuchsia `x86_64-linux-android` | ✓ | | 64-bit x86 Android @@ -146,7 +146,7 @@ not available. target | std | host | notes -------|-----|------|------- `aarch64-apple-darwin` | ? | | ARM64 macOS -`aarch64-apple-tvos` | *[^apple] | | ARM64 tvOS +`aarch64-apple-tvos` | * | | ARM64 tvOS `aarch64-unknown-cloudabi` | ✓ | | ARM64 CloudABI `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ? | | @@ -158,16 +158,16 @@ target | std | host | notes `armv4t-unknown-linux-gnueabi` | ? | | `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD `armv6-unknown-netbsd-eabihf` | ? | | -`armv7-apple-ios` | ✓[^apple] | | ARMv7 iOS, Cortex-a8 +`armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8 `armv7-unknown-cloudabi-eabihf` | ✓ | | ARMv7 CloudABI, hardfloat `armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD `armv7-unknown-netbsd-eabihf` | ? | | `armv7-wrs-vxworks-eabihf` | ? | | `armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat -`armv7s-apple-ios` | ✓[^apple] | | -`avr-unknown-unknown` | ? | | AVR +`armv7s-apple-ios` | ✓ | | +`avr-unknown-gnu-atmega328` | ✗ | | AVR. Requires `-Z build-std=core` `hexagon-unknown-linux-musl` | ? | | -`i386-apple-ios` | ✓[^apple] | | 32-bit x86 iOS +`i386-apple-ios` | ✓ | | 32-bit x86 iOS `i686-apple-darwin` | ✓ | ✓ | 32-bit OSX (10.7+, Lion+) `i686-pc-windows-msvc` | ✓ | | 32-bit Windows XP support `i686-unknown-cloudabi` | ✓ | | 32-bit CloudABI @@ -195,6 +195,7 @@ target | std | host | notes `powerpc64-unknown-linux-musl` | ? | | `powerpc64-wrs-vxworks` | ? | | `powerpc64le-unknown-linux-musl` | ? | | +`riscv32gc-unknown-linux-gnu` | | | RISC-V Linux (kernel 5.4, glibc 2.33) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux `sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 `sparc64-unknown-openbsd` | ? | | @@ -202,8 +203,8 @@ target | std | host | notes `thumbv7a-uwp-windows-msvc` | ✓ | | `thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL `thumbv4t-none-eabi` | * | | ARMv4T T32 -`x86_64-apple-ios-macabi` | ✓[^apple] | | Apple Catalyst -`x86_64-apple-tvos` | *[^apple] | | x86 64-bit tvOS +`x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst +`x86_64-apple-tvos` | * | | x86 64-bit tvOS `x86_64-linux-kernel` | * | | Linux kernel modules `x86_64-pc-solaris` | ? | | `x86_64-pc-windows-msvc` | ✓ | | 64-bit Windows XP support @@ -220,4 +221,3 @@ target | std | host | notes `x86_64-wrs-vxworks` | ? | | [runs on NVIDIA GPUs]: https://github.com/japaric-archived/nvptx#targets -[^apple]: These targets are only available on macOS. diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index f982863e67..93454b4f90 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -5,6 +5,7 @@ - [Command-line arguments](command-line-arguments.md) - [The `#[doc]` attribute](the-doc-attribute.md) - [Documentation tests](documentation-tests.md) +- [Linking to items by name](linking-to-items-by-name.md) - [Lints](lints.md) - [Passes](passes.md) - [Advanced Features](advanced-features.md) diff --git a/src/doc/rustdoc/src/advanced-features.md b/src/doc/rustdoc/src/advanced-features.md index 7c12d23e64..8c7926f116 100644 --- a/src/doc/rustdoc/src/advanced-features.md +++ b/src/doc/rustdoc/src/advanced-features.md @@ -32,3 +32,19 @@ pub struct UnixToken; Here, the respective tokens can only be used by dependent crates on their respective platforms, but they will both appear in documentation. + +## Add aliases for an item in documentation search + +This feature allows you to add alias(es) to an item when using the `rustdoc` search through the +`doc(alias)` attribute. Example: + +```rust,no_run +#[doc(alias = "x")] +#[doc(alias = "big")] +pub struct BigX; +``` + +Then, when looking for it through the `rustdoc` search, if you enter "x" or +"big", search will show the `BigX` struct first. + +There are some limitations on the doc alias names though: you can't use `"` or whitespace. diff --git a/src/doc/rustdoc/src/linking-to-items-by-name.md b/src/doc/rustdoc/src/linking-to-items-by-name.md new file mode 100644 index 0000000000..5e46ef583f --- /dev/null +++ b/src/doc/rustdoc/src/linking-to-items-by-name.md @@ -0,0 +1,65 @@ +# Linking to items by name + +Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link. + +For example, in the following code all of the links will link to the rustdoc page for `Bar`: + +```rust +/// This struct is not [Bar] +pub struct Foo1; + +/// This struct is also not [bar](Bar) +pub struct Foo2; + +/// This struct is also not [bar][b] +/// +/// [b]: Bar +pub struct Foo3; + +/// This struct is also not [`Bar`] +pub struct Foo4; + +pub struct Bar; +``` + +You can refer to anything in scope, and use paths, including `Self`, `self`, `super`, and `crate`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. Backticks around the link will be stripped. + +```rust,edition2018 +use std::sync::mpsc::Receiver; + +/// This is an version of [`Receiver`], with support for [`std::future`]. +/// +/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`]. +pub struct AsyncReceiver { + sender: Receiver +} + +impl AsyncReceiver { + pub async fn recv() -> T { + unimplemented!() + } +} +``` + +You can also link to sections using URL fragment specifiers: + +```rust +/// This is a special implementation of [positional parameters] +/// +/// [positional parameters]: std::fmt#formatting-parameters +struct MySpecialFormatter; +``` + +Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: + +```rust +/// See also: [`Foo`](struct@Foo) +struct Bar; + +/// This is different from [`Foo`](fn@Foo) +struct Foo {} + +fn Foo() {} +``` + +Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in. diff --git a/src/doc/rustdoc/src/lints.md b/src/doc/rustdoc/src/lints.md index d1d6bc1c1f..3e632a0644 100644 --- a/src/doc/rustdoc/src/lints.md +++ b/src/doc/rustdoc/src/lints.md @@ -13,20 +13,95 @@ Here is the list of the lints provided by `rustdoc`: ## broken_intra_doc_links -This lint **warns by default** and is **nightly-only**. This lint detects when -an intra-doc link fails to get resolved. For example: +This lint **warns by default**. This lint detects when an [intra-doc link] fails to get resolved. For example: + + [intra-doc link]: linking-to-items-by-name.html ```rust -/// I want to link to [`Inexistent`] but it doesn't exist! +/// I want to link to [`Nonexistent`] but it doesn't exist! pub fn foo() {} ``` You'll get a warning saying: ```text -error: `[`Inexistent`]` cannot be resolved, ignoring it... +warning: unresolved link to `Nonexistent` + --> test.rs:1:24 + | +1 | /// I want to link to [`Nonexistent`] but it doesn't exist! + | ^^^^^^^^^^^^^ no item named `Nonexistent` in `test` ``` +It will also warn when there is an ambiguity and suggest how to disambiguate: + +```rust +/// [`Foo`] +pub fn function() {} + +pub enum Foo {} + +pub fn Foo(){} +``` + +```text +warning: `Foo` is both an enum and a function + --> test.rs:1:6 + | +1 | /// [`Foo`] + | ^^^^^ ambiguous link + | + = note: `#[warn(broken_intra_doc_links)]` on by default +help: to link to the enum, prefix with the item type + | +1 | /// [`enum@Foo`] + | ^^^^^^^^^^ +help: to link to the function, add parentheses + | +1 | /// [`Foo()`] + | ^^^^^^^ + +``` + +## private_intra_doc_links + +This lint **warns by default**. This lint detects when [intra-doc links] from public to private items. +For example: + +```rust +/// [private] +pub fn public() {} +fn private() {} +``` + +This gives a warning that the link will be broken when it appears in your documentation: + +```text +warning: public documentation for `public` links to private item `private` + --> priv.rs:1:6 + | +1 | /// [private] + | ^^^^^^^ this item is private + | + = note: `#[warn(private_intra_doc_links)]` on by default + = note: this link will resolve properly if you pass `--document-private-items` +``` + +Note that this has different behavior depending on whether you pass `--document-private-items` or not! +If you document private items, then it will still generate a link, despite the warning: + +```text +warning: public documentation for `public` links to private item `private` + --> priv.rs:1:6 + | +1 | /// [private] + | ^^^^^^^ this item is private + | + = note: `#[warn(private_intra_doc_links)]` on by default + = note: this link resolves only because you passed `--document-private-items`, but will break without +``` + +[intra-doc links]: linking-to-items-by-name.html + ## missing_docs This lint is **allowed by default**. It detects items missing documentation. @@ -49,9 +124,33 @@ warning: missing documentation for a function | ^^^^^^^^^^^^^^^^^^^^^ ``` +## missing_crate_level_docs + +This lint is **allowed by default**. It detects if there is no documentation +at the crate root. For example: + +```rust +#![warn(missing_crate_level_docs)] +``` + +This will generate the following warning: + +```text +warning: no documentation found for this crate's top-level module + | + = help: The following guide may be of use: + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html +``` + +This is currently "allow" by default, but it is intended to make this a +warning in the future. This is intended as a means to introduce new users on +*how* to document their crate by pointing them to some instructions on how to +get started, without providing overwhelming warnings like `missing_docs` +might. + ## missing_doc_code_examples -This lint is **allowed by default**. It detects when a documentation block +This lint is **allowed by default** and is **nightly-only**. It detects when a documentation block is missing a code example. For example: ```rust @@ -117,3 +216,37 @@ warning: Documentation test in private item 8 | | /// ``` | |___________^ ``` + +## invalid_codeblock_attributes + +This lint **warns by default**. It detects code block attributes in +documentation examples that have potentially mis-typed values. For example: + +```rust +/// Example. +/// +/// ```should-panic +/// assert_eq!(1, 2); +/// ``` +pub fn foo() {} +``` + +Which will give: + +```text +warning: unknown attribute `should-panic`. Did you mean `should_panic`? + --> src/lib.rs:1:1 + | +1 | / /// Example. +2 | | /// +3 | | /// ```should-panic +4 | | /// assert_eq!(1, 2); +5 | | /// ``` + | |_______^ + | + = note: `#[warn(invalid_codeblock_attributes)]` on by default + = help: the code block will either not be tested if not marked as a rust one or won't fail if it doesn't panic when running +``` + +In the example above, the correct form is `should_panic`. This helps detect +typo mistakes for some common attributes. diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index 2f49fc8a41..e4d8818b56 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -38,63 +38,6 @@ future. Attempting to use these error numbers on stable will result in the code sample being interpreted as plain text. -### Linking to items by name - -Rustdoc is capable of directly linking to other rustdoc pages in Markdown documentation using the path of item as a link. - -For example, in the following code all of the links will link to the rustdoc page for `Bar`: - -```rust -/// This struct is not [Bar] -pub struct Foo1; - -/// This struct is also not [bar](Bar) -pub struct Foo2; - -/// This struct is also not [bar][b] -/// -/// [b]: Bar -pub struct Foo3; - -/// This struct is also not [`Bar`] -pub struct Foo4; - -pub struct Bar; -``` - -You can refer to anything in scope, and use paths, including `Self`. You may also use `foo()` and `foo!()` to refer to methods/functions and macros respectively. - -```rust,edition2018 -use std::sync::mpsc::Receiver; - -/// This is an version of [`Receiver`], with support for [`std::future`]. -/// -/// You can obtain a [`std::future::Future`] by calling [`Self::recv()`]. -pub struct AsyncReceiver { - sender: Receiver -} - -impl AsyncReceiver { - pub async fn recv() -> T { - unimplemented!() - } -} -``` - -Paths in Rust have three namespaces: type, value, and macro. Items from these namespaces are allowed to overlap. In case of ambiguity, rustdoc will warn about the ambiguity and ask you to disambiguate, which can be done by using a prefix like `struct@`, `enum@`, `type@`, `trait@`, `union@`, `const@`, `static@`, `value@`, `function@`, `mod@`, `fn@`, `module@`, `method@`, `prim@`, `primitive@`, `macro@`, or `derive@`: - -```rust -/// See also: [`Foo`](struct@Foo) -struct Bar; - -/// This is different from [`Foo`](fn@Foo) -struct Foo {} - -fn Foo() {} -``` - -Note: Because of how `macro_rules` macros are scoped in Rust, the intra-doc links of a `macro_rules` macro will be resolved relative to the crate root, as opposed to the module it is defined in. - ## Extensions to the `#[doc]` attribute These features operate by extending the `#[doc]` attribute, and thus can be caught by the compiler @@ -207,22 +150,6 @@ issue][issue-include]. [unstable-include]: ../unstable-book/language-features/external-doc.html [issue-include]: https://github.com/rust-lang/rust/issues/44732 -### Add aliases for an item in documentation search - -This feature allows you to add alias(es) to an item when using the `rustdoc` search through the -`doc(alias)` attribute. Example: - -```rust,no_run -#![feature(doc_alias)] - -#[doc(alias = "x")] -#[doc(alias = "big")] -pub struct BigX; -``` - -Then, when looking for it through the `rustdoc` search, if you enter "x" or -"big", search will show the `BigX` struct first. - ## Unstable command-line arguments These features are enabled by passing a command-line flag to Rustdoc, but the flags in question are diff --git a/src/doc/rustdoc/src/what-is-rustdoc.md b/src/doc/rustdoc/src/what-is-rustdoc.md index adcebc832b..7a38c96d71 100644 --- a/src/doc/rustdoc/src/what-is-rustdoc.md +++ b/src/doc/rustdoc/src/what-is-rustdoc.md @@ -93,6 +93,29 @@ passes `-L`, a flag that helps rustdoc find the dependencies your code relies on. If our project used dependencies, we'd get documentation for them as well! +## Outer and inner documentation + +The `///` syntax is used to document the item present after it. +That's why it is called an outer documentation. +There is another syntax: `//!`, which is used to document the +item it is present inside. It is called an inner documentation. +It is often used when documenting the entire crate, +because nothing comes before it: it is the root of the crate. +So in order to document an entire crate, you need to use `//!` syntax. +For example: + +``` rust +//! This is my first rust crate +``` + +When used in the crate root, it documents the item it is inside, +which is the crate itself. + +For more information about the `//!` syntax, see [the Book]. + +[the Book]: https://doc.rust-lang.org/book/ch14-02-publishing-to-crates-io.html#commenting-contained-items + + ## Using standalone Markdown files `rustdoc` can also generate HTML from standalone Markdown files. Let's diff --git a/src/doc/unstable-book/src/compiler-flags/tls-model.md b/src/doc/unstable-book/src/compiler-flags/tls-model.md index 0aefaa7fb0..cd625f3fd0 100644 --- a/src/doc/unstable-book/src/compiler-flags/tls-model.md +++ b/src/doc/unstable-book/src/compiler-flags/tls-model.md @@ -22,4 +22,4 @@ The TLS data must not be in a library loaded after startup (via `dlopen`). but not in a shared library, and is accessed only from that executable. `rustc` and LLVM may use a more optimized model than specified if they know that we are producing -and executable rather than a library, or that the `static` item is private enough. +an executable rather than a library, or that the `static` item is private enough. diff --git a/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md b/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md new file mode 100644 index 0000000000..8e46e227c2 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/unsound-mir-opts.md @@ -0,0 +1,8 @@ +# `unsound-mir-opts` + +-------------------- + +The `-Zunsound-mir-opts` compiler flag enables [MIR optimization passes] which can cause unsound behavior. +This flag should only be used by MIR optimization tests in the rustc test suite. + +[MIR optimization passes]: https://rustc-dev-guide.rust-lang.org/mir/optimizations.html diff --git a/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md new file mode 100644 index 0000000000..338fbc4b2b --- /dev/null +++ b/src/doc/unstable-book/src/language-features/cmse-nonsecure-entry.md @@ -0,0 +1,81 @@ +# `cmse_nonsecure_entry` + +The tracking issue for this feature is: [#75835] + +[#75835]: https://github.com/rust-lang/rust/issues/75835 + +------------------------ + +The [TrustZone-M +feature](https://developer.arm.com/documentation/100690/latest/) is available +for targets with the Armv8-M architecture profile (`thumbv8m` in their target +name). +LLVM, the Rust compiler and the linker are providing +[support](https://developer.arm.com/documentation/ecm0359818/latest/) for the +TrustZone-M feature. + +One of the things provided, with this unstable feature, is the +`cmse_nonsecure_entry` attribute. This attribute marks a Secure function as an +entry function (see [section +5.4](https://developer.arm.com/documentation/ecm0359818/latest/) for details). +With this attribute, the compiler will do the following: +* add a special symbol on the function which is the `__acle_se_` prefix and the + standard function name +* constrain the number of parameters to avoid using the Non-Secure stack +* before returning from the function, clear registers that might contain Secure + information +* use the `BXNS` instruction to return + +Because the stack can not be used to pass parameters, there will be compilation +errors if: +* the total size of all parameters is too big (for example more than four 32 + bits integers) +* the entry function is not using a C ABI + +The special symbol `__acle_se_` will be used by the linker to generate a secure +gateway veneer. + + + +``` rust,ignore +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} +``` + +``` text +$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs +$ arm-none-eabi-objdump -D function.o + +00000000 : + 0: b580 push {r7, lr} + 2: 466f mov r7, sp + 4: b082 sub sp, #8 + 6: 9001 str r0, [sp, #4] + 8: 1d81 adds r1, r0, #6 + a: 460a mov r2, r1 + c: 4281 cmp r1, r0 + e: 9200 str r2, [sp, #0] + 10: d30b bcc.n 2a + 12: e7ff b.n 14 + 14: 9800 ldr r0, [sp, #0] + 16: b002 add sp, #8 + 18: e8bd 4080 ldmia.w sp!, {r7, lr} + 1c: 4671 mov r1, lr + 1e: 4672 mov r2, lr + 20: 4673 mov r3, lr + 22: 46f4 mov ip, lr + 24: f38e 8800 msr CPSR_f, lr + 28: 4774 bxns lr + 2a: f240 0000 movw r0, #0 + 2e: f2c0 0000 movt r0, #0 + 32: f240 0200 movw r2, #0 + 36: f2c0 0200 movt r2, #0 + 3a: 211c movs r1, #28 + 3c: f7ff fffe bl 0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E> + 40: defe udf #254 ; 0xfe +``` diff --git a/src/doc/unstable-book/src/language-features/doc-alias.md b/src/doc/unstable-book/src/language-features/doc-alias.md deleted file mode 100644 index 647ac0cf66..0000000000 --- a/src/doc/unstable-book/src/language-features/doc-alias.md +++ /dev/null @@ -1,23 +0,0 @@ -# `doc_alias` - -The tracking issue for this feature is: [#50146] - -[#50146]: https://github.com/rust-lang/rust/issues/50146 - ------------------------- - -You can add alias(es) to an item when using the `rustdoc` search through the -`doc(alias)` attribute. Example: - -```rust,no_run -#![feature(doc_alias)] - -#[doc(alias = "x")] -#[doc(alias = "big")] -pub struct BigX; -``` - -Then, when looking for it through the `rustdoc` search, if you enter "x" or -"big", search will show the `BigX` struct first. - -Note that this feature is currently hidden behind the `feature(doc_alias)` gate. diff --git a/src/doc/unstable-book/src/language-features/ffi-const.md b/src/doc/unstable-book/src/language-features/ffi-const.md index 9a1ced4033..24a3044375 100644 --- a/src/doc/unstable-book/src/language-features/ffi-const.md +++ b/src/doc/unstable-book/src/language-features/ffi-const.md @@ -1,5 +1,9 @@ # `ffi_const` +The tracking issue for this feature is: [#58328] + +------ + The `#[ffi_const]` attribute applies clang's `const` attribute to foreign functions declarations. @@ -42,6 +46,7 @@ implemented in this way on all of them. It is therefore also worth verifying that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_const]`. +[#58328]: https://github.com/rust-lang/rust/issues/58328 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacgigch.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_const.htm diff --git a/src/doc/unstable-book/src/language-features/ffi-pure.md b/src/doc/unstable-book/src/language-features/ffi-pure.md index 7bfd7a378f..4aef4eeab5 100644 --- a/src/doc/unstable-book/src/language-features/ffi-pure.md +++ b/src/doc/unstable-book/src/language-features/ffi-pure.md @@ -1,5 +1,9 @@ # `ffi_pure` +The tracking issue for this feature is: [#58329] + +------ + The `#[ffi_pure]` attribute applies clang's `pure` attribute to foreign functions declarations. @@ -46,6 +50,7 @@ that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the `#[ffi_pure]`. +[#58329]: https://github.com/rust-lang/rust/issues/58329 [ARM C/C++ compiler]: http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.dui0491c/Cacigdac.html [GCC]: https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute [IBM ILE C/C++]: https://www.ibm.com/support/knowledgecenter/fr/ssw_ibm_i_71/rzarg/fn_attrib_pure.htm diff --git a/src/doc/unstable-book/src/language-features/rustc-attrs.md b/src/doc/unstable-book/src/language-features/rustc-attrs.md index 2967200faf..1d9409ee9e 100644 --- a/src/doc/unstable-book/src/language-features/rustc-attrs.md +++ b/src/doc/unstable-book/src/language-features/rustc-attrs.md @@ -13,8 +13,8 @@ The `rustc_attrs` feature allows debugging rustc type layouts by using with `cargo check`) as an alternative to `rustc -Z print-type-sizes` that is way more verbose. -Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `abi`. -Note that it only work best with sized type without generics. +Options provided by `#[rustc_layout(...)]` are `debug`, `size`, `align`, +`abi`. Note that it only works on sized types without generics. ## Examples diff --git a/src/doc/unstable-book/src/library-features/asm.md b/src/doc/unstable-book/src/library-features/asm.md index 28a5fe31fc..af39424ec6 100644 --- a/src/doc/unstable-book/src/library-features/asm.md +++ b/src/doc/unstable-book/src/library-features/asm.md @@ -27,6 +27,7 @@ Inline assembly is currently supported on the following architectures: - RISC-V - NVPTX - Hexagon +- MIPS32 ## Basic usage @@ -345,6 +346,25 @@ The `h` modifier will emit the register name for the high byte of that register If you use a smaller data type (e.g. `u16`) with an operand and forget the use template modifiers, the compiler will emit a warning and suggest the correct modifier to use. +## Memory address operands + +Sometimes assembly instructions require operands passed via memory addresses/memory locations. +You have to manually use the memory address syntax specified by the respectively architectures. +For example, in x86/x86_64 and intel assembly syntax, you should wrap inputs/outputs in `[]` +to indicate they are memory operands: + +```rust,allow_fail +# #![feature(asm, llvm_asm)] +# fn load_fpu_control_word(control: u16) { +unsafe { + asm!("fldcw [{}]", in(reg) &control, options(nostack)); + + // Previously this would have been written with the deprecated `llvm_asm!` like this + llvm_asm!("fldcw $0" :: "m" (control) :: "volatile"); +} +# } +``` + ## Options By default, an inline assembly block is treated the same way as an external FFI function call with a custom calling convention: it may read/write memory, have observable side effects, etc. However in many cases, it is desirable to give the compiler more information about what the assembly code is actually doing so that it can optimize better. @@ -390,7 +410,7 @@ reg_spec := / "" operand_expr := expr / "_" / expr "=>" expr / expr "=>" "_" reg_operand := dir_spec "(" reg_spec ")" operand_expr operand := reg_operand / "const" const_expr / "sym" path -option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "att_syntax" +option := "pure" / "nomem" / "readonly" / "preserves_flags" / "noreturn" / "nostack" / "att_syntax" options := "options(" option *["," option] [","] ")" asm := "asm!(" format_string *("," format_string) *("," [ident "="] operand) ["," options] [","] ")" ``` @@ -493,6 +513,8 @@ Here is the list of currently supported register classes: | ARM | `qreg` | `q[0-15]` | `w` | | ARM | `qreg_low8` | `q[0-7]` | `t` | | ARM | `qreg_low4` | `q[0-3]` | `x` | +| MIPS32 | `reg` | `$[2-25]` | `r` | +| MIPS32 | `freg` | `$f[0-31]` | `f` | | NVPTX | `reg16` | None\* | `h` | | NVPTX | `reg32` | None\* | `r` | | NVPTX | `reg64` | None\* | `l` | @@ -528,6 +550,8 @@ Each register class has constraints on which value types they can be used with. | ARM | `sreg` | `vfp2` | `i32`, `f32` | | ARM | `dreg` | `vfp2` | `i64`, `f64`, `i8x8`, `i16x4`, `i32x2`, `i64x1`, `f32x2` | | ARM | `qreg` | `neon` | `i8x16`, `i16x8`, `i32x4`, `i64x2`, `f32x4` | +| MIPS32 | `reg` | None | `i8`, `i16`, `i32`, `f32` | +| MIPS32 | `freg` | None | `f32` | | NVPTX | `reg16` | None | `i8`, `i16` | | NVPTX | `reg32` | None | `i8`, `i16`, `i32`, `f32` | | NVPTX | `reg64` | None | `i8`, `i16`, `i32`, `f32`, `i64`, `f64` | @@ -576,6 +600,7 @@ Some registers have multiple names. These are all treated by the compiler as ide | ARM | `r13` | `sp` | | ARM | `r14` | `lr` | | ARM | `r15` | `pc` | +| MIPS32 | `$[2-25]` | Please [see the Wikipedia page][mips-regs] | | RISC-V | `x0` | `zero` | | RISC-V | `x1` | `ra` | | RISC-V | `x2` | `sp` | @@ -596,12 +621,14 @@ Some registers have multiple names. These are all treated by the compiler as ide | Hexagon | `r30` | `fr` | | Hexagon | `r31` | `lr` | +[mips-regs]: https://en.wikibooks.org/wiki/MIPS_Assembly/Register_File#Registers + Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `fr` (Hexagon), `$fp` (MIPS) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | | ARM | `r6` | `r6` is used internally by LLVM as a base pointer and therefore cannot be used as an input or output. | | x86 | `k0` | This is a constant zero register which can't be modified. | @@ -610,6 +637,11 @@ Some registers cannot be used for input or output operands: | x86 | `st([0-7])` | x87 registers are not currently supported (but may be in the future). | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | ARM | `pc` | This is the program counter, not a real register. | +| MIPS32 | `$0` or `$zero` | This is a constant zero register which can't be modified. | +| MIPS32 | `$1` or `$at` | Reserved for assembler. | +| MIPS32 | `$26`/`$k0`, `$27`/`$k1` | OS-reserved registers. | +| MIPS32 | `$28`/`$gp` | Global pointer cannot be used as inputs or outputs. | +| MIPS32 | `$ra` | Return address cannot be used as inputs or outputs. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | | Hexagon | `lr` | This is the link register which cannot be used as an input or output. | @@ -657,6 +689,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `dreg` | None | `d0` | `P` | | ARM | `qreg` | None | `q0` | `q` | | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | +| MIPS32 | `reg` | None | `$2` | None | +| MIPS32 | `freg` | None | `$f0` | None | | NVPTX | `reg16` | None | `rs0` | None | | NVPTX | `reg32` | None | `r0` | None | | NVPTX | `reg64` | None | `rd0` | None | diff --git a/src/doc/unstable-book/src/library-features/llvm-asm.md b/src/doc/unstable-book/src/library-features/llvm-asm.md index da01d9228f..a2f029db29 100644 --- a/src/doc/unstable-book/src/library-features/llvm-asm.md +++ b/src/doc/unstable-book/src/library-features/llvm-asm.md @@ -159,12 +159,12 @@ specify some extra info about the inline assembly: Current valid options are: -1. *volatile* - specifying this is analogous to +1. `volatile` - specifying this is analogous to `__asm__ __volatile__ (...)` in gcc/clang. -2. *alignstack* - certain instructions expect the stack to be +2. `alignstack` - certain instructions expect the stack to be aligned a certain way (i.e. SSE) and specifying this indicates to the compiler to insert its usual stack alignment code -3. *intel* - use intel syntax instead of the default AT&T. +3. `intel` - use intel syntax instead of the default AT&T. ```rust # #![feature(llvm_asm)] diff --git a/src/doc/unstable-book/src/library-features/slice-check-range.md b/src/doc/unstable-book/src/library-features/slice-check-range.md new file mode 100644 index 0000000000..83e5738cf5 --- /dev/null +++ b/src/doc/unstable-book/src/library-features/slice-check-range.md @@ -0,0 +1,10 @@ +# `slice_check_range` + +The tracking issue for this feature is: [#76393] + +------------------------ + +This adds [`slice::check_range`]. + +[#76393]: https://github.com/rust-lang/rust/issues/76393 +[`slice::check_range`]: https://doc.rust-lang.org/nightly/std/primitive.slice.html#method.check_range diff --git a/src/etc/gdb_lookup.py b/src/etc/gdb_lookup.py index 2a46eaadad..a5a1824c84 100644 --- a/src/etc/gdb_lookup.py +++ b/src/etc/gdb_lookup.py @@ -69,9 +69,9 @@ def lookup(valobj): else: return StdOldHashMapProvider(valobj) if rust_type == RustType.STD_HASH_SET: - hash_map = valobj["map"] + hash_map = valobj[valobj.type.fields()[0]] if is_hashbrown_hashmap(hash_map): - return StdHashMapProvider(hash_map, show_values=False) + return StdHashMapProvider(valobj, show_values=False) else: return StdOldHashMapProvider(hash_map, show_values=False) diff --git a/src/etc/gdb_providers.py b/src/etc/gdb_providers.py index 67f99ec4e4..bae51e6f9e 100644 --- a/src/etc/gdb_providers.py +++ b/src/etc/gdb_providers.py @@ -347,7 +347,7 @@ class StdHashMapProvider: self.valobj = valobj self.show_values = show_values - table = self.valobj["base"]["table"] + table = self.table() capacity = int(table["bucket_mask"]) + 1 ctrl = table["ctrl"]["pointer"] @@ -368,6 +368,18 @@ class StdHashMapProvider: if is_presented: self.valid_indices.append(idx) + def table(self): + if self.show_values: + hashbrown_hashmap = self.valobj["base"] + elif self.valobj.type.fields()[0].name == "map": + # BACKCOMPAT: rust 1.47 + # HashSet wraps std::collections::HashMap, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["map"]["base"] + else: + # HashSet wraps hashbrown::HashSet, which wraps hashbrown::HashMap + hashbrown_hashmap = self.valobj["base"]["map"] + return hashbrown_hashmap["table"] + def to_string(self): if self.show_values: return "HashMap(size={})".format(self.size) diff --git a/src/etc/lldb_lookup.py b/src/etc/lldb_lookup.py index 13420fbaf0..3cee51982b 100644 --- a/src/etc/lldb_lookup.py +++ b/src/etc/lldb_lookup.py @@ -94,7 +94,7 @@ def synthetic_lookup(valobj, dict): if rust_type == RustType.STD_HASH_SET: hash_map = valobj.GetChildAtIndex(0) if is_hashbrown_hashmap(hash_map): - return StdHashMapSyntheticProvider(hash_map, dict, show_values=False) + return StdHashMapSyntheticProvider(valobj, dict, show_values=False) else: return StdOldHashMapSyntheticProvider(hash_map, dict, show_values=False) diff --git a/src/etc/lldb_providers.py b/src/etc/lldb_providers.py index 19da75c35b..64cb983794 100644 --- a/src/etc/lldb_providers.py +++ b/src/etc/lldb_providers.py @@ -526,7 +526,7 @@ class StdHashMapSyntheticProvider: def update(self): # type: () -> None - table = self.valobj.GetChildMemberWithName("base").GetChildMemberWithName("table") + table = self.table() capacity = table.GetChildMemberWithName("bucket_mask").GetValueAsUnsigned() + 1 ctrl = table.GetChildMemberWithName("ctrl").GetChildAtIndex(0) @@ -552,6 +552,17 @@ class StdHashMapSyntheticProvider: if is_present: self.valid_indices.append(idx) + def table(self): + # type: () -> SBValue + if self.show_values: + hashbrown_hashmap = self.valobj.GetChildMemberWithName("base") + else: + # BACKCOMPAT: rust 1.47 + # HashSet wraps either std HashMap or hashbrown::HashSet, which both + # wrap hashbrown::HashMap, so either way we "unwrap" twice. + hashbrown_hashmap = self.valobj.GetChildAtIndex(0).GetChildAtIndex(0) + return hashbrown_hashmap.GetChildMemberWithName("table") + def has_children(self): # type: () -> bool return True diff --git a/src/etc/natvis/libstd.natvis b/src/etc/natvis/libstd.natvis index f791979800..9550c25f2f 100644 --- a/src/etc/natvis/libstd.natvis +++ b/src/etc/natvis/libstd.natvis @@ -5,7 +5,7 @@ Current std impls: std::collections::hash::set::HashSet is implemented in terms of... - std::collections::hash::map::HashMap is implemented in terms of... + hashbrown::set::HashSet is implemented in terms of... hashbrown::map::HashMap is implemented in terms of... hashbrown::raw::RawTable<(K, V)> @@ -50,22 +50,22 @@ - {{ size={map.base.table.items} }} + {{ size={base.map.table.items} }} - map.base.table.items - map.base.table.items + map.base.table.growth_left - map.base.hash_builder + base.map.table.items + base.map.table.items + base.map.table.growth_left + base.map.hash_builder - - map.base.table.items + + base.map.table.items - + n-- - (($T1*)map.base.table.ctrl.pointer)[-(i + 1)] + (($T1*)base.map.table.ctrl.pointer)[-(i + 1)] i++ diff --git a/src/librustc_ast/Cargo.toml b/src/librustc_ast/Cargo.toml deleted file mode 100644 index 73c5e33753..0000000000 --- a/src/librustc_ast/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_serialize = { path = "../librustc_serialize" } -tracing = "0.1" -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -bitflags = "1.2.1" diff --git a/src/librustc_ast_lowering/Cargo.toml b/src/librustc_ast_lowering/Cargo.toml deleted file mode 100644 index bf7e69a31a..0000000000 --- a/src/librustc_ast_lowering/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast_lowering" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast_lowering" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_span = { path = "../librustc_span" } -rustc_errors = { path = "../librustc_errors" } -rustc_session = { path = "../librustc_session" } -rustc_ast = { path = "../librustc_ast" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_ast_passes/Cargo.toml b/src/librustc_ast_passes/Cargo.toml deleted file mode 100644 index 6db9bce316..0000000000 --- a/src/librustc_ast_passes/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast_passes" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast_passes" -path = "lib.rs" - -[dependencies] -itertools = "0.8" -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_parse = { path = "../librustc_parse" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_ast_pretty/Cargo.toml b/src/librustc_ast_pretty/Cargo.toml deleted file mode 100644 index d26205c791..0000000000 --- a/src/librustc_ast_pretty/Cargo.toml +++ /dev/null @@ -1,16 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ast_pretty" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ast_pretty" -path = "lib.rs" -doctest = false - -[dependencies] -tracing = "0.1" -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } -rustc_target = { path = "../librustc_target" } diff --git a/src/librustc_attr/Cargo.toml b/src/librustc_attr/Cargo.toml deleted file mode 100644 index 35bdf747f0..0000000000 --- a/src/librustc_attr/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_attr" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_attr" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_errors = { path = "../librustc_errors" } -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_feature = { path = "../librustc_feature" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } -rustc_session = { path = "../librustc_session" } -rustc_ast = { path = "../librustc_ast" } -version_check = "0.9" diff --git a/src/librustc_builtin_macros/Cargo.toml b/src/librustc_builtin_macros/Cargo.toml deleted file mode 100644 index dee6fed317..0000000000 --- a/src/librustc_builtin_macros/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_builtin_macros" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_builtin_macros" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_parse_format = { path = "../librustc_parse_format" } -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_parse = { path = "../librustc_parse" } -rustc_target = { path = "../librustc_target" } -rustc_session = { path = "../librustc_session" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_expand = { path = "../librustc_expand" } -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_codegen_llvm/Cargo.toml b/src/librustc_codegen_llvm/Cargo.toml deleted file mode 100644 index 2e4b9f22f8..0000000000 --- a/src/librustc_codegen_llvm/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_codegen_llvm" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_codegen_llvm" -path = "lib.rs" -test = false -doctest = false - -[dependencies] -bitflags = "1.0" -flate2 = "1.0" -libc = "0.2" -measureme = "0.7.1" -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc-demangle = "0.1" -rustc_attr = { path = "../librustc_attr" } -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_fs_util = { path = "../librustc_fs_util" } -rustc_hir = { path = "../librustc_hir" } -rustc_incremental = { path = "../librustc_incremental" } -rustc_index = { path = "../librustc_index" } -rustc_llvm = { path = "../librustc_llvm" } -rustc_session = { path = "../librustc_session" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_target = { path = "../librustc_target" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_codegen_ssa/Cargo.toml b/src/librustc_codegen_ssa/Cargo.toml deleted file mode 100644 index 5707d3cd0e..0000000000 --- a/src/librustc_codegen_ssa/Cargo.toml +++ /dev/null @@ -1,38 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_codegen_ssa" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_codegen_ssa" -path = "lib.rs" -test = false - -[dependencies] -bitflags = "1.2.1" -cc = "1.0.1" -num_cpus = "1.0" -memmap = "0.7" -tracing = "0.1" -libc = "0.2.50" -jobserver = "0.1.11" -tempfile = "3.1" -pathdiff = "0.2.0" - -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_middle = { path = "../librustc_middle" } -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_attr = { path = "../librustc_attr" } -rustc_symbol_mangling = { path = "../librustc_symbol_mangling" } -rustc_data_structures = { path = "../librustc_data_structures"} -rustc_errors = { path = "../librustc_errors" } -rustc_fs_util = { path = "../librustc_fs_util" } -rustc_hir = { path = "../librustc_hir" } -rustc_incremental = { path = "../librustc_incremental" } -rustc_index = { path = "../librustc_index" } -rustc_macros = { path = "../librustc_macros" } -rustc_target = { path = "../librustc_target" } -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_codegen_ssa/traits/declare.rs b/src/librustc_codegen_ssa/traits/declare.rs deleted file mode 100644 index 690aacd205..0000000000 --- a/src/librustc_codegen_ssa/traits/declare.rs +++ /dev/null @@ -1,65 +0,0 @@ -use super::BackendTypes; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::mono::{Linkage, Visibility}; -use rustc_middle::ty::{Instance, Ty}; -use rustc_target::abi::call::FnAbi; - -pub trait DeclareMethods<'tcx>: BackendTypes { - /// Declare a global value. - /// - /// If there’s a value with the same name already declared, the function will - /// return its Value instead. - fn declare_global(&self, name: &str, ty: Self::Type) -> Self::Value; - - /// Declare a C ABI function. - /// - /// Only use this for foreign function ABIs and glue. For Rust functions use - /// `declare_fn` instead. - /// - /// If there’s a value with the same name already declared, the function will - /// update the declaration and return existing Value instead. - fn declare_cfn(&self, name: &str, fn_type: Self::Type) -> Self::Function; - - /// Declare a Rust 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_fn(&self, name: &str, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) -> Self::Function; - - /// Declare a global with an intention to define it. - /// - /// Use this function when you intend to define a global. This function will - /// return `None` if the name already has a definition associated with it. In that - /// case an error should be reported to the user, because it usually happens due - /// to user’s fault (e.g., misuse of `#[no_mangle]` or `#[export_name]` attributes). - fn define_global(&self, name: &str, ty: Self::Type) -> Option; - - /// Declare a private global - /// - /// Use this function when you intend to define a global without a name. - fn define_private_global(&self, ty: Self::Type) -> Self::Value; - - /// Gets declared value by name. - fn get_declared_value(&self, name: &str) -> Option; - - /// Gets defined or externally defined (AvailableExternally linkage) value by - /// name. - fn get_defined_value(&self, name: &str) -> Option; -} - -pub trait PreDefineMethods<'tcx>: BackendTypes { - fn predefine_static( - &self, - def_id: DefId, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str, - ); - fn predefine_fn( - &self, - instance: Instance<'tcx>, - linkage: Linkage, - visibility: Visibility, - symbol_name: &str, - ); -} diff --git a/src/librustc_data_structures/jobserver.rs b/src/librustc_data_structures/jobserver.rs deleted file mode 100644 index a811c88839..0000000000 --- a/src/librustc_data_structures/jobserver.rs +++ /dev/null @@ -1,42 +0,0 @@ -pub use jobserver_crate::Client; -use lazy_static::lazy_static; - -lazy_static! { - // We can only call `from_env` once per process - - // Note that this is unsafe because it may misinterpret file descriptors - // on Unix as jobserver file descriptors. We hopefully execute this near - // the beginning of the process though to ensure we don't get false - // positives, or in other words we try to execute this before we open - // any file descriptors ourselves. - // - // Pick a "reasonable maximum" if we don't otherwise have - // a jobserver in our environment, capping out at 32 so we - // don't take everything down by hogging the process run queue. - // The fixed number is used to have deterministic compilation - // across machines. - // - // Also note that we stick this in a global because there could be - // multiple rustc instances in this process, and the jobserver is - // per-process. - static ref GLOBAL_CLIENT: Client = unsafe { - Client::from_env().unwrap_or_else(|| { - let client = Client::new(32).expect("failed to create jobserver"); - // Acquire a token for the main thread which we can release later - client.acquire_raw().ok(); - client - }) - }; -} - -pub fn client() -> Client { - GLOBAL_CLIENT.clone() -} - -pub fn acquire_thread() { - GLOBAL_CLIENT.acquire_raw().ok(); -} - -pub fn release_thread() { - GLOBAL_CLIENT.release_raw().ok(); -} diff --git a/src/librustc_driver/Cargo.toml b/src/librustc_driver/Cargo.toml deleted file mode 100644 index 46331c6311..0000000000 --- a/src/librustc_driver/Cargo.toml +++ /dev/null @@ -1,43 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_driver" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_driver" -path = "lib.rs" -crate-type = ["dylib"] - -[dependencies] -lazy_static = "1.0" -libc = "0.2" -tracing = { version = "0.1.18", features = ["release_max_level_info"] } -tracing-subscriber = { version = "0.2.10", default-features = false, features = ["fmt", "env-filter", "smallvec", "parking_lot", "ansi"] } -rustc_middle = { path = "../librustc_middle" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_target = { path = "../librustc_target" } -rustc_lint = { path = "../librustc_lint" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_mir = { path = "../librustc_mir" } -rustc_parse = { path = "../librustc_parse" } -rustc_plugin_impl = { path = "../librustc_plugin_impl" } -rustc_save_analysis = { path = "../librustc_save_analysis" } -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } -rustc_session = { path = "../librustc_session" } -rustc_error_codes = { path = "../librustc_error_codes" } -rustc_interface = { path = "../librustc_interface" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["consoleapi", "debugapi", "processenv"] } - -[features] -llvm = ['rustc_interface/llvm'] diff --git a/src/librustc_error_codes/error_codes/E0019.md b/src/librustc_error_codes/error_codes/E0019.md deleted file mode 100644 index 7832468a53..0000000000 --- a/src/librustc_error_codes/error_codes/E0019.md +++ /dev/null @@ -1,36 +0,0 @@ -A function call isn't allowed in the const's initialization expression -because the expression's value must be known at compile-time. - -Erroneous code example: - -```compile_fail,E0019 -#![feature(box_syntax)] - -fn main() { - struct MyOwned; - - static STATIC11: Box = box MyOwned; // error! -} -``` - -Remember: you can't use a function call inside a const's initialization -expression! However, you can totally use it anywhere else: - -``` -enum Test { - V1 -} - -impl Test { - fn func(&self) -> i32 { - 12 - } -} - -fn main() { - const FOO: Test = Test::V1; - - FOO.func(); // here is good - let x = FOO.func(); // or even here! -} -``` diff --git a/src/librustc_error_codes/error_codes/E0433.md b/src/librustc_error_codes/error_codes/E0433.md deleted file mode 100644 index f9e333e8cc..0000000000 --- a/src/librustc_error_codes/error_codes/E0433.md +++ /dev/null @@ -1,17 +0,0 @@ -An undeclared type or module was used. - -Erroneous code example: - -```compile_fail,E0433 -let map = HashMap::new(); -// error: failed to resolve: use of undeclared type or module `HashMap` -``` - -Please verify you didn't misspell the type/module's name or that you didn't -forget to import it: - - -``` -use std::collections::HashMap; // HashMap has been imported. -let map: HashMap = HashMap::new(); // So it can be used! -``` diff --git a/src/librustc_expand/Cargo.toml b/src/librustc_expand/Cargo.toml deleted file mode 100644 index 55a1862971..0000000000 --- a/src/librustc_expand/Cargo.toml +++ /dev/null @@ -1,28 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_expand" -version = "0.0.0" -edition = "2018" -build = false - -[lib] -name = "rustc_expand" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_serialize = { path = "../librustc_serialize" } -tracing = "0.1" -rustc_span = { path = "../librustc_span" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_ast_passes = { path = "../librustc_ast_passes" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_macros = { path = "../librustc_macros" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_parse = { path = "../librustc_parse" } -rustc_session = { path = "../librustc_session" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_expand/parse/lexer/tests.rs b/src/librustc_expand/parse/lexer/tests.rs deleted file mode 100644 index 8718444428..0000000000 --- a/src/librustc_expand/parse/lexer/tests.rs +++ /dev/null @@ -1,252 +0,0 @@ -use rustc_ast::ast::AttrStyle; -use rustc_ast::token::{self, CommentKind, Token, TokenKind}; -use rustc_data_structures::sync::Lrc; -use rustc_errors::{emitter::EmitterWriter, Handler}; -use rustc_parse::lexer::StringReader; -use rustc_session::parse::ParseSess; -use rustc_span::source_map::{FilePathMapping, SourceMap}; -use rustc_span::symbol::Symbol; -use rustc_span::with_default_session_globals; -use rustc_span::{BytePos, Span}; - -use std::io; -use std::path::PathBuf; - -fn mk_sess(sm: Lrc) -> ParseSess { - let emitter = EmitterWriter::new( - Box::new(io::sink()), - Some(sm.clone()), - false, - false, - false, - None, - false, - ); - ParseSess::with_span_handler(Handler::with_emitter(true, None, Box::new(emitter)), sm) -} - -// Creates a string reader for the given string. -fn setup<'a>(sm: &SourceMap, sess: &'a ParseSess, teststr: String) -> StringReader<'a> { - let sf = sm.new_source_file(PathBuf::from(teststr.clone()).into(), teststr); - StringReader::new(sess, sf, None) -} - -#[test] -fn t1() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut string_reader = setup( - &sm, - &sh, - "/* my source file */ fn main() { println!(\"zebra\"); }\n".to_string(), - ); - assert_eq!(string_reader.next_token(), token::Comment); - assert_eq!(string_reader.next_token(), token::Whitespace); - let tok1 = string_reader.next_token(); - let tok2 = Token::new(mk_ident("fn"), Span::with_root_ctxt(BytePos(21), BytePos(23))); - assert_eq!(tok1.kind, tok2.kind); - assert_eq!(tok1.span, tok2.span); - assert_eq!(string_reader.next_token(), token::Whitespace); - // Read another token. - let tok3 = string_reader.next_token(); - assert_eq!(string_reader.pos(), BytePos(28)); - let tok4 = Token::new(mk_ident("main"), Span::with_root_ctxt(BytePos(24), BytePos(28))); - assert_eq!(tok3.kind, tok4.kind); - assert_eq!(tok3.span, tok4.span); - - assert_eq!(string_reader.next_token(), token::OpenDelim(token::Paren)); - assert_eq!(string_reader.pos(), BytePos(29)) - }) -} - -// Checks that the given reader produces the desired stream -// of tokens (stop checking after exhausting `expected`). -fn check_tokenization(mut string_reader: StringReader<'_>, expected: Vec) { - for expected_tok in &expected { - assert_eq!(&string_reader.next_token(), expected_tok); - } -} - -// Makes the identifier by looking up the string in the interner. -fn mk_ident(id: &str) -> TokenKind { - token::Ident(Symbol::intern(id), false) -} - -fn mk_lit(kind: token::LitKind, symbol: &str, suffix: Option<&str>) -> TokenKind { - TokenKind::lit(kind, Symbol::intern(symbol), suffix.map(Symbol::intern)) -} - -#[test] -fn doublecolon_parsing() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a b".to_string()), - vec![mk_ident("a"), token::Whitespace, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_2() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a::b".to_string()), - vec![mk_ident("a"), token::Colon, token::Colon, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_3() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a ::b".to_string()), - vec![mk_ident("a"), token::Whitespace, token::Colon, token::Colon, mk_ident("b")], - ); - }) -} - -#[test] -fn doublecolon_parsing_4() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - check_tokenization( - setup(&sm, &sh, "a:: b".to_string()), - vec![mk_ident("a"), token::Colon, token::Colon, token::Whitespace, mk_ident("b")], - ); - }) -} - -#[test] -fn character_a() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "'a'".to_string()).next_token(), mk_lit(token::Char, "a", None),); - }) -} - -#[test] -fn character_space() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!(setup(&sm, &sh, "' '".to_string()).next_token(), mk_lit(token::Char, " ", None),); - }) -} - -#[test] -fn character_escaped() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "'\\n'".to_string()).next_token(), - mk_lit(token::Char, "\\n", None), - ); - }) -} - -#[test] -fn lifetime_name() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "'abc".to_string()).next_token(), - token::Lifetime(Symbol::intern("'abc")), - ); - }) -} - -#[test] -fn raw_string() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - assert_eq!( - setup(&sm, &sh, "r###\"\"#a\\b\x00c\"\"###".to_string()).next_token(), - mk_lit(token::StrRaw(3), "\"#a\\b\x00c\"", None), - ); - }) -} - -#[test] -fn literal_suffixes() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - macro_rules! test { - ($input: expr, $tok_type: ident, $tok_contents: expr) => {{ - assert_eq!( - setup(&sm, &sh, format!("{}suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, Some("suffix")), - ); - // with a whitespace separator - assert_eq!( - setup(&sm, &sh, format!("{} suffix", $input)).next_token(), - mk_lit(token::$tok_type, $tok_contents, None), - ); - }}; - } - - test!("'a'", Char, "a"); - test!("b'a'", Byte, "a"); - test!("\"a\"", Str, "a"); - test!("b\"a\"", ByteStr, "a"); - test!("1234", Integer, "1234"); - test!("0b101", Integer, "0b101"); - test!("0xABC", Integer, "0xABC"); - test!("1.0", Float, "1.0"); - test!("1.0e10", Float, "1.0e10"); - - assert_eq!( - setup(&sm, &sh, "2us".to_string()).next_token(), - mk_lit(token::Integer, "2", Some("us")), - ); - assert_eq!( - setup(&sm, &sh, "r###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::StrRaw(3), "raw", Some("suffix")), - ); - assert_eq!( - setup(&sm, &sh, "br###\"raw\"###suffix".to_string()).next_token(), - mk_lit(token::ByteStrRaw(3), "raw", Some("suffix")), - ); - }) -} - -#[test] -fn nested_block_comments() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut lexer = setup(&sm, &sh, "/* /* */ */'a'".to_string()); - assert_eq!(lexer.next_token(), token::Comment); - assert_eq!(lexer.next_token(), mk_lit(token::Char, "a", None)); - }) -} - -#[test] -fn crlf_comments() { - with_default_session_globals(|| { - let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); - let sh = mk_sess(sm.clone()); - let mut lexer = setup(&sm, &sh, "// test\r\n/// test\r\n".to_string()); - let comment = lexer.next_token(); - assert_eq!(comment.kind, token::Comment); - assert_eq!((comment.span.lo(), comment.span.hi()), (BytePos(0), BytePos(7))); - assert_eq!(lexer.next_token(), token::Whitespace); - assert_eq!( - lexer.next_token(), - token::DocComment(CommentKind::Line, AttrStyle::Outer, Symbol::intern(" test")) - ); - }) -} diff --git a/src/librustc_feature/Cargo.toml b/src/librustc_feature/Cargo.toml deleted file mode 100644 index 96fd15ef30..0000000000 --- a/src/librustc_feature/Cargo.toml +++ /dev/null @@ -1,15 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_feature" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_feature" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_data_structures = { path = "../librustc_data_structures" } -lazy_static = "1.0.0" -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_hir/Cargo.toml b/src/librustc_hir/Cargo.toml deleted file mode 100644 index a473a8edcd..0000000000 --- a/src/librustc_hir/Cargo.toml +++ /dev/null @@ -1,22 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_hir" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_hir" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_target = { path = "../librustc_target" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_span = { path = "../librustc_span" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -lazy_static = "1" -tracing = "0.1" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_hir_pretty/Cargo.toml b/src/librustc_hir_pretty/Cargo.toml deleted file mode 100644 index ccd3e9b6e4..0000000000 --- a/src/librustc_hir_pretty/Cargo.toml +++ /dev/null @@ -1,17 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_hir_pretty" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_hir_pretty" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_incremental/Cargo.toml b/src/librustc_incremental/Cargo.toml deleted file mode 100644 index 1f7e372541..0000000000 --- a/src/librustc_incremental/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_incremental" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_incremental" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_graphviz = { path = "../librustc_graphviz" } -tracing = "0.1" -rand = "0.7" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_hir = { path = "../librustc_hir" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_macros = { path = "../librustc_macros" } -rustc_span = { path = "../librustc_span" } -rustc_fs_util = { path = "../librustc_fs_util" } -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_infer/Cargo.toml b/src/librustc_infer/Cargo.toml deleted file mode 100644 index a0fcc881e4..0000000000 --- a/src/librustc_infer/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_infer" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_infer" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_graphviz = { path = "../librustc_graphviz" } -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_macros = { path = "../librustc_macros" } -rustc_session = { path = "../librustc_session" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -rustc_target = { path = "../librustc_target" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_interface/Cargo.toml b/src/librustc_interface/Cargo.toml deleted file mode 100644 index b9837c6ade..0000000000 --- a/src/librustc_interface/Cargo.toml +++ /dev/null @@ -1,57 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_interface" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_interface" -path = "lib.rs" -doctest = false - -[dependencies] -libc = "0.2" -tracing = "0.1" -rayon = { version = "0.3.0", package = "rustc-rayon" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_attr = { path = "../librustc_attr" } -rustc_builtin_macros = { path = "../librustc_builtin_macros" } -rustc_expand = { path = "../librustc_expand" } -rustc_parse = { path = "../librustc_parse" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_middle = { path = "../librustc_middle" } -rustc_ast_lowering = { path = "../librustc_ast_lowering" } -rustc_ast_passes = { path = "../librustc_ast_passes" } -rustc_incremental = { path = "../librustc_incremental" } -rustc_traits = { path = "../librustc_traits" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_codegen_ssa = { path = "../librustc_codegen_ssa" } -rustc_symbol_mangling = { path = "../librustc_symbol_mangling" } -rustc_codegen_llvm = { path = "../librustc_codegen_llvm", optional = true } -rustc_hir = { path = "../librustc_hir" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_mir = { path = "../librustc_mir" } -rustc_mir_build = { path = "../librustc_mir_build" } -rustc_passes = { path = "../librustc_passes" } -rustc_typeck = { path = "../librustc_typeck" } -rustc_lint = { path = "../librustc_lint" } -rustc_errors = { path = "../librustc_errors" } -rustc_plugin_impl = { path = "../librustc_plugin_impl" } -rustc_privacy = { path = "../librustc_privacy" } -rustc_resolve = { path = "../librustc_resolve" } -rustc_trait_selection = { path = "../librustc_trait_selection" } -rustc_ty = { path = "../librustc_ty" } -tempfile = "3.0.5" -once_cell = "1" - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["libloaderapi"] } - -[dev-dependencies] -rustc_target = { path = "../librustc_target" } - -[features] -llvm = ['rustc_codegen_llvm'] diff --git a/src/librustc_lexer/src/tests.rs b/src/librustc_lexer/src/tests.rs deleted file mode 100644 index a1ea5ceb1f..0000000000 --- a/src/librustc_lexer/src/tests.rs +++ /dev/null @@ -1,167 +0,0 @@ -use super::*; - -use expect_test::{expect, Expect}; - -fn check_raw_str(s: &str, expected_hashes: u16, expected_err: Option) { - let s = &format!("r{}", s); - let mut cursor = Cursor::new(s); - cursor.bump(); - let (n_hashes, err) = cursor.raw_double_quoted_string(0); - assert_eq!(n_hashes, expected_hashes); - assert_eq!(err, expected_err); -} - -#[test] -fn test_naked_raw_str() { - check_raw_str(r#""abc""#, 0, None); -} - -#[test] -fn test_raw_no_start() { - check_raw_str(r##""abc"#"##, 0, None); -} - -#[test] -fn test_too_many_terminators() { - // this error is handled in the parser later - check_raw_str(r###"#"abc"##"###, 1, None); -} - -#[test] -fn test_unterminated() { - check_raw_str( - r#"#"abc"#, - 1, - Some(RawStrError::NoTerminator { expected: 1, found: 0, possible_terminator_offset: None }), - ); - check_raw_str( - r###"##"abc"#"###, - 2, - Some(RawStrError::NoTerminator { - expected: 2, - found: 1, - possible_terminator_offset: Some(7), - }), - ); - // We're looking for "# not just any # - check_raw_str( - r###"##"abc#"###, - 2, - Some(RawStrError::NoTerminator { expected: 2, found: 0, possible_terminator_offset: None }), - ) -} - -#[test] -fn test_invalid_start() { - check_raw_str(r##"#~"abc"#"##, 1, Some(RawStrError::InvalidStarter { bad_char: '~' })); -} - -#[test] -fn test_unterminated_no_pound() { - // https://github.com/rust-lang/rust/issues/70677 - check_raw_str( - r#"""#, - 0, - Some(RawStrError::NoTerminator { expected: 0, found: 0, possible_terminator_offset: None }), - ); -} - -#[test] -fn test_valid_shebang() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#!/usr/bin/rustrun\nlet x = 5;"; - assert_eq!(strip_shebang(input), Some(18)); -} - -#[test] -fn test_invalid_shebang_valid_rust_syntax() { - // https://github.com/rust-lang/rust/issues/70528 - let input = "#! [bad_attribute]"; - assert_eq!(strip_shebang(input), None); -} - -#[test] -fn test_shebang_second_line() { - // Because shebangs are interpreted by the kernel, they must be on the first line - let input = "\n#!/bin/bash"; - assert_eq!(strip_shebang(input), None); -} - -#[test] -fn test_shebang_space() { - let input = "#! /bin/bash"; - assert_eq!(strip_shebang(input), Some(input.len())); -} - -#[test] -fn test_shebang_empty_shebang() { - let input = "#! \n[attribute(foo)]"; - assert_eq!(strip_shebang(input), None); -} - -#[test] -fn test_invalid_shebang_comment() { - let input = "#!//bin/ami/a/comment\n["; - assert_eq!(strip_shebang(input), None) -} - -#[test] -fn test_invalid_shebang_another_comment() { - let input = "#!/*bin/ami/a/comment*/\n[attribute"; - assert_eq!(strip_shebang(input), None) -} - -#[test] -fn test_shebang_valid_rust_after() { - let input = "#!/*bin/ami/a/comment*/\npub fn main() {}"; - assert_eq!(strip_shebang(input), Some(23)) -} - -#[test] -fn test_shebang_followed_by_attrib() { - let input = "#!/bin/rust-scripts\n#![allow_unused(true)]"; - assert_eq!(strip_shebang(input), Some(19)); -} - -fn check_lexing(src: &str, expect: Expect) { - let actual: String = tokenize(src).map(|token| format!("{:?}\n", token)).collect(); - expect.assert_eq(&actual) -} - -#[test] -fn comment_flavors() { - check_lexing( - r" -// line -//// line as well -/// outer doc line -//! inner doc line -/* block */ -/**/ -/*** also block */ -/** outer doc block */ -/*! inner doc block */ -", - expect![[r#" - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: None }, len: 7 } - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: None }, len: 17 } - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: Some(Outer) }, len: 18 } - Token { kind: Whitespace, len: 1 } - Token { kind: LineComment { doc_style: Some(Inner) }, len: 18 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: None, terminated: true }, len: 11 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: None, terminated: true }, len: 4 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: None, terminated: true }, len: 18 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: Some(Outer), terminated: true }, len: 22 } - Token { kind: Whitespace, len: 1 } - Token { kind: BlockComment { doc_style: Some(Inner), terminated: true }, len: 22 } - Token { kind: Whitespace, len: 1 } - "#]], - ) -} diff --git a/src/librustc_lint/Cargo.toml b/src/librustc_lint/Cargo.toml deleted file mode 100644 index d779f15f19..0000000000 --- a/src/librustc_lint/Cargo.toml +++ /dev/null @@ -1,26 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_lint" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_lint" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -unicode-security = "0.0.5" -rustc_middle = { path = "../librustc_middle" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_feature = { path = "../librustc_feature" } -rustc_index = { path = "../librustc_index" } -rustc_session = { path = "../librustc_session" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_metadata/Cargo.toml b/src/librustc_metadata/Cargo.toml deleted file mode 100644 index af6aacfd64..0000000000 --- a/src/librustc_metadata/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_metadata" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_metadata" -path = "lib.rs" -doctest = false - -[dependencies] -flate2 = "1.0" -libc = "0.2" -tracing = "0.1" -memmap = "0.7" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_target = { path = "../librustc_target" } -rustc_index = { path = "../librustc_index" } -rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../librustc_serialize" } -stable_deref_trait = "1.0.0" -rustc_ast = { path = "../librustc_ast" } -rustc_expand = { path = "../librustc_expand" } -rustc_span = { path = "../librustc_span" } -rustc_session = { path = "../librustc_session" } - -[target.'cfg(windows)'.dependencies] -winapi = { version = "0.3", features = ["errhandlingapi", "libloaderapi"] } diff --git a/src/librustc_middle/Cargo.toml b/src/librustc_middle/Cargo.toml deleted file mode 100644 index ae09420d4a..0000000000 --- a/src/librustc_middle/Cargo.toml +++ /dev/null @@ -1,36 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_middle" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_middle" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -bitflags = "1.2.1" -tracing = "0.1" -rustc-rayon-core = "0.3.0" -polonius-engine = "0.12.0" -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_attr = { path = "../librustc_attr" } -rustc_feature = { path = "../librustc_feature" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_query_system = { path = "../librustc_query_system" } -rustc_errors = { path = "../librustc_errors" } -rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -byteorder = { version = "1.3" } -chalk-ir = "0.14.0" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -arrayvec = { version = "0.5.1", default-features = false } -measureme = "0.7.1" -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_middle/ty/print/obsolete.rs b/src/librustc_middle/ty/print/obsolete.rs deleted file mode 100644 index 2ea7cd2a6d..0000000000 --- a/src/librustc_middle/ty/print/obsolete.rs +++ /dev/null @@ -1,251 +0,0 @@ -//! Allows for producing a unique string key for a mono item. -//! These keys are used by the handwritten auto-tests, so they need to be -//! predictable and human-readable. -//! -//! Note: A lot of this could looks very similar to what's already in `ty::print`. -//! FIXME(eddyb) implement a custom `PrettyPrinter` for this. - -use crate::bug; -use crate::ty::subst::SubstsRef; -use crate::ty::{self, Const, Instance, Ty, TyCtxt}; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use std::fmt::Write; -use std::iter; - -/// Same as `unique_type_name()` but with the result pushed onto the given -/// `output` parameter. -pub struct DefPathBasedNames<'tcx> { - tcx: TyCtxt<'tcx>, - omit_disambiguators: bool, - omit_local_crate_name: bool, -} - -impl DefPathBasedNames<'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, omit_disambiguators: bool, omit_local_crate_name: bool) -> Self { - DefPathBasedNames { tcx, omit_disambiguators, omit_local_crate_name } - } - - // Pushes the type name of the specified type to the provided string. - // If `debug` is true, printing normally unprintable types is allowed - // (e.g. `ty::GeneratorWitness`). This parameter should only be set when - // this method is being used for logging purposes (e.g. with `debug!` or `info!`) - // When being used for codegen purposes, `debug` should be set to `false` - // in order to catch unexpected types that should never end up in a type name. - pub fn push_type_name(&self, t: Ty<'tcx>, output: &mut String, debug: bool) { - match t.kind { - ty::Bool => output.push_str("bool"), - ty::Char => output.push_str("char"), - ty::Str => output.push_str("str"), - ty::Never => output.push_str("!"), - ty::Int(ty) => output.push_str(ty.name_str()), - ty::Uint(ty) => output.push_str(ty.name_str()), - ty::Float(ty) => output.push_str(ty.name_str()), - ty::Adt(adt_def, substs) => { - self.push_def_path(adt_def.did, output); - self.push_generic_params(substs, iter::empty(), output, debug); - } - ty::Tuple(component_types) => { - output.push('('); - for component_type in component_types { - self.push_type_name(component_type.expect_ty(), output, debug); - output.push_str(", "); - } - if !component_types.is_empty() { - output.pop(); - output.pop(); - } - output.push(')'); - } - ty::RawPtr(ty::TypeAndMut { ty: inner_type, mutbl }) => { - output.push('*'); - match mutbl { - hir::Mutability::Not => output.push_str("const "), - hir::Mutability::Mut => output.push_str("mut "), - } - - self.push_type_name(inner_type, output, debug); - } - ty::Ref(_, inner_type, mutbl) => { - output.push('&'); - output.push_str(mutbl.prefix_str()); - - self.push_type_name(inner_type, output, debug); - } - ty::Array(inner_type, len) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - let len = len.eval_usize(self.tcx, ty::ParamEnv::reveal_all()); - write!(output, "; {}", len).unwrap(); - output.push(']'); - } - ty::Slice(inner_type) => { - output.push('['); - self.push_type_name(inner_type, output, debug); - output.push(']'); - } - ty::Dynamic(ref trait_data, ..) => { - if let Some(principal) = trait_data.principal() { - self.push_def_path(principal.def_id(), output); - self.push_generic_params( - principal.skip_binder().substs, - trait_data.projection_bounds(), - output, - debug, - ); - } else { - output.push_str("dyn '_"); - } - } - ty::Foreign(did) => self.push_def_path(did, output), - ty::FnDef(..) | ty::FnPtr(_) => { - let sig = t.fn_sig(self.tcx); - output.push_str(sig.unsafety().prefix_str()); - - let abi = sig.abi(); - if abi != ::rustc_target::spec::abi::Abi::Rust { - output.push_str("extern \""); - output.push_str(abi.name()); - output.push_str("\" "); - } - - output.push_str("fn("); - - let sig = - self.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig); - - if !sig.inputs().is_empty() { - for ¶meter_type in sig.inputs() { - self.push_type_name(parameter_type, output, debug); - output.push_str(", "); - } - output.pop(); - output.pop(); - } - - if sig.c_variadic { - if !sig.inputs().is_empty() { - output.push_str(", ..."); - } else { - output.push_str("..."); - } - } - - output.push(')'); - - if !sig.output().is_unit() { - output.push_str(" -> "); - self.push_type_name(sig.output(), output, debug); - } - } - ty::Generator(def_id, substs, _) | ty::Closure(def_id, substs) => { - self.push_def_path(def_id, output); - let generics = self.tcx.generics_of(self.tcx.closure_base_def_id(def_id)); - let substs = substs.truncate_to(self.tcx, generics); - self.push_generic_params(substs, iter::empty(), output, debug); - } - ty::Param(_) => { - output.push_str(&t.to_string()); - } - ty::Error(_) - | ty::Bound(..) - | ty::Infer(_) - | ty::Placeholder(..) - | ty::Projection(..) - | ty::GeneratorWitness(_) - | ty::Opaque(..) => { - if debug { - output.push_str(&format!("`{:?}`", t)); - } else { - bug!( - "DefPathBasedNames: trying to create type name for unexpected type: {:?}", - t, - ); - } - } - } - } - - // Pushes the the name of the specified const to the provided string. - // If `debug` is true, the unprintable types of constants will be printed with `fmt::Debug` - // (see `push_type_name` for more details). - pub fn push_const_name(&self, ct: &Const<'tcx>, output: &mut String, debug: bool) { - write!(output, "{}", ct).unwrap(); - output.push_str(": "); - self.push_type_name(ct.ty, output, debug); - } - - pub fn push_def_path(&self, def_id: DefId, output: &mut String) { - let def_path = self.tcx.def_path(def_id); - - // some_crate:: - if !(self.omit_local_crate_name && def_id.is_local()) { - output.push_str(&self.tcx.crate_name(def_path.krate).as_str()); - output.push_str("::"); - } - - // foo::bar::ItemName:: - for part in self.tcx.def_path(def_id).data { - if self.omit_disambiguators { - write!(output, "{}::", part.data.as_symbol()).unwrap(); - } else { - write!(output, "{}[{}]::", part.data.as_symbol(), part.disambiguator).unwrap(); - } - } - - // remove final "::" - output.pop(); - output.pop(); - } - - fn push_generic_params( - &self, - substs: SubstsRef<'tcx>, - projections: I, - output: &mut String, - debug: bool, - ) where - I: Iterator>, - { - let mut projections = projections.peekable(); - if substs.non_erasable_generics().next().is_none() && projections.peek().is_none() { - return; - } - - output.push('<'); - - for type_parameter in substs.types() { - self.push_type_name(type_parameter, output, debug); - output.push_str(", "); - } - - for projection in projections { - let projection = projection.skip_binder(); - let name = &self.tcx.associated_item(projection.item_def_id).ident.as_str(); - output.push_str(name); - output.push_str("="); - self.push_type_name(projection.ty, output, debug); - output.push_str(", "); - } - - for const_parameter in substs.consts() { - self.push_const_name(const_parameter, output, debug); - output.push_str(", "); - } - - output.pop(); - output.pop(); - - output.push('>'); - } - - pub fn push_instance_as_string( - &self, - instance: Instance<'tcx>, - output: &mut String, - debug: bool, - ) { - self.push_def_path(instance.def_id(), output); - self.push_generic_params(instance.substs, iter::empty(), output, debug); - } -} diff --git a/src/librustc_mir/Cargo.toml b/src/librustc_mir/Cargo.toml deleted file mode 100644 index 2693d29e41..0000000000 --- a/src/librustc_mir/Cargo.toml +++ /dev/null @@ -1,35 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_mir" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_mir" -path = "lib.rs" -doctest = false - -[dependencies] -either = "1.5.0" -rustc_graphviz = { path = "../librustc_graphviz" } -itertools = "0.8" -tracing = "0.1" -log_settings = "0.1.1" -polonius-engine = "0.12.0" -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_infer = { path = "../librustc_infer" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_session = { path = "../librustc_session" } -rustc_target = { path = "../librustc_target" } -rustc_trait_selection = { path = "../librustc_trait_selection" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_apfloat = { path = "../librustc_apfloat" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir/transform/check_consts/mod.rs b/src/librustc_mir/transform/check_consts/mod.rs deleted file mode 100644 index 81c1b0b5bd..0000000000 --- a/src/librustc_mir/transform/check_consts/mod.rs +++ /dev/null @@ -1,57 +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_hir as hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_middle::mir; -use rustc_middle::ty::{self, TyCtxt}; - -pub use self::qualifs::Qualif; - -mod ops; -pub mod post_drop_elaboration; -pub mod qualifs; -mod resolver; -pub mod validation; - -/// 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 def_id: LocalDefId, - pub param_env: ty::ParamEnv<'tcx>, - pub const_kind: Option, -} - -impl ConstCx<'mir, 'tcx> { - pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId, body: &'mir mir::Body<'tcx>) -> Self { - let param_env = tcx.param_env(def_id); - Self::new_with_param_env(tcx, def_id, body, param_env) - } - - pub fn new_with_param_env( - tcx: TyCtxt<'tcx>, - def_id: LocalDefId, - body: &'mir mir::Body<'tcx>, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - let const_kind = tcx.hir().body_const_context(def_id); - ConstCx { body, tcx, def_id: def_id, param_env, const_kind } - } - - /// 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") - } -} - -/// 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().begin_panic_fn() -} diff --git a/src/librustc_mir/transform/check_consts/ops.rs b/src/librustc_mir/transform/check_consts/ops.rs deleted file mode 100644 index ea025f208e..0000000000 --- a/src/librustc_mir/transform/check_consts/ops.rs +++ /dev/null @@ -1,393 +0,0 @@ -//! Concrete error types for all operations which may be invalid in a certain const context. - -use rustc_errors::struct_span_err; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_session::config::nightly_options; -use rustc_session::parse::feature_err; -use rustc_span::symbol::sym; -use rustc_span::{Span, Symbol}; - -use super::ConstCx; - -/// Emits an error if `op` is not allowed in the given const context. -pub fn non_const(ccx: &ConstCx<'_, '_>, op: O, span: Span) { - debug!("illegal_op: op={:?}", op); - - if op.is_allowed_in_item(ccx) { - return; - } - - if ccx.tcx.sess.opts.debugging_opts.unleash_the_miri_inside_of_you { - ccx.tcx.sess.miri_unleashed_feature(span, O::feature_gate()); - return; - } - - op.emit_error(ccx, span); -} - -/// An operation that is not *always* allowed in a const context. -pub trait NonConstOp: std::fmt::Debug { - /// Returns the `Symbol` corresponding to the feature gate that would enable this operation, - /// or `None` if such a feature gate does not exist. - fn feature_gate() -> Option { - None - } - - /// Returns `true` if this operation is allowed in the given item. - /// - /// This check should assume that we are not in a non-const `fn`, where all operations are - /// legal. - /// - /// By default, it returns `true` if and only if this operation has a corresponding feature - /// gate and that gate is enabled. - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - Self::feature_gate().map_or(false, |gate| ccx.tcx.features().enabled(gate)) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0019, - "{} contains unimplemented expression type", - ccx.const_kind() - ); - if let Some(feat) = Self::feature_gate() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feat)); - } - if ccx.tcx.sess.teach(&err.get_code().unwrap()) { - err.note( - "A function call isn't allowed in the const's initialization expression \ - because the expression's value must be known at compile-time.", - ); - err.note( - "Remember: you can't use a function call inside a const's initialization \ - expression! However, you can use it anywhere else.", - ); - } - err.emit(); - } -} - -/// A function call where the callee is a pointer. -#[derive(Debug)] -pub struct FnCallIndirect; -impl NonConstOp for FnCallIndirect { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = - ccx.tcx.sess.struct_span_err(span, "function pointers are not allowed in const fn"); - err.emit(); - } -} - -/// A function call where the callee is not marked as `const`. -#[derive(Debug)] -pub struct FnCallNonConst(pub DefId); -impl NonConstOp for FnCallNonConst { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = struct_span_err!( - ccx.tcx.sess, - span, - E0015, - "calls in {}s are limited to constant functions, \ - tuple structs and tuple variants", - ccx.const_kind(), - ); - err.emit(); - } -} - -/// A call to a `#[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 Symbol); -impl NonConstOp for FnCallUnstable { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - 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 nightly_options::is_nightly_build() { - err.help(&format!("add `#![feature({})]` to the crate attributes to enable", feature)); - } - err.emit(); - } -} - -#[derive(Debug)] -pub struct HeapAllocation; -impl NonConstOp for HeapAllocation { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - 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.emit(); - } -} - -#[derive(Debug)] -pub struct InlineAsm; -impl NonConstOp for InlineAsm {} - -#[derive(Debug)] -pub struct LiveDrop(pub Option); -impl NonConstOp for LiveDrop { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut diagnostic = struct_span_err!( - ccx.tcx.sess, - span, - E0493, - "destructors cannot be evaluated at compile-time" - ); - diagnostic.span_label(span, format!("{}s cannot evaluate destructors", ccx.const_kind())); - if let Some(span) = self.0 { - diagnostic.span_label(span, "value is dropped here"); - } - diagnostic.emit(); - } -} - -#[derive(Debug)] -pub struct CellBorrow; -impl NonConstOp for CellBorrow { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - struct_span_err!( - ccx.tcx.sess, - span, - E0492, - "cannot borrow a constant which may contain \ - interior mutability, create a static instead" - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct MutBorrow; -impl NonConstOp for MutBorrow { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - // Forbid everywhere except in const fn - ccx.const_kind() == hir::ConstContext::ConstFn - && ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_mut_refs) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - let mut err = if ccx.const_kind() == hir::ConstContext::ConstFn { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("mutable references are not allowed in {}s", ccx.const_kind()), - ) - } else { - struct_span_err!( - ccx.tcx.sess, - span, - E0764, - "mutable references are not allowed in {}s", - ccx.const_kind(), - ) - }; - err.span_label(span, "`&mut` is only allowed in `const fn`".to_string()); - 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.emit(); - } -} - -#[derive(Debug)] -pub struct MutAddressOf; -impl NonConstOp for MutAddressOf { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_mut_refs, - span, - &format!("`&raw mut` is not allowed in {}s", ccx.const_kind()), - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct MutDeref; -impl NonConstOp for MutDeref { - fn feature_gate() -> Option { - Some(sym::const_mut_refs) - } -} - -#[derive(Debug)] -pub struct Panic; -impl NonConstOp for Panic { - fn feature_gate() -> Option { - Some(sym::const_panic) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_panic, - span, - &format!("panicking in {}s is unstable", ccx.const_kind()), - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct RawPtrComparison; -impl NonConstOp for RawPtrComparison { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - 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.emit(); - } -} - -#[derive(Debug)] -pub struct RawPtrDeref; -impl NonConstOp for RawPtrDeref { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_deref) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_raw_ptr_deref, - span, - &format!("dereferencing raw pointers in {}s is unstable", ccx.const_kind(),), - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct RawPtrToIntCast; -impl NonConstOp for RawPtrToIntCast { - fn feature_gate() -> Option { - Some(sym::const_raw_ptr_to_usize_cast) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_raw_ptr_to_usize_cast, - span, - &format!("casting pointers to integers in {}s is unstable", ccx.const_kind(),), - ) - .emit(); - } -} - -/// An access to a (non-thread-local) `static`. -#[derive(Debug)] -pub struct StaticAccess; -impl NonConstOp for StaticAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - matches!(ccx.const_kind(), hir::ConstContext::Static(_)) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - 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.emit(); - } -} - -/// An access to a thread-local `static`. -#[derive(Debug)] -pub struct ThreadLocalAccess; -impl NonConstOp for ThreadLocalAccess { - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - struct_span_err!( - ccx.tcx.sess, - span, - E0625, - "thread-local statics cannot be \ - accessed at compile-time" - ) - .emit(); - } -} - -#[derive(Debug)] -pub struct UnionAccess; -impl NonConstOp for UnionAccess { - fn is_allowed_in_item(&self, ccx: &ConstCx<'_, '_>) -> bool { - // Union accesses are stable in all contexts except `const fn`. - ccx.const_kind() != hir::ConstContext::ConstFn - || ccx.tcx.features().enabled(Self::feature_gate().unwrap()) - } - - fn feature_gate() -> Option { - Some(sym::const_fn_union) - } - - fn emit_error(&self, ccx: &ConstCx<'_, '_>, span: Span) { - feature_err( - &ccx.tcx.sess.parse_sess, - sym::const_fn_union, - span, - "unions in const fn are unstable", - ) - .emit(); - } -} diff --git a/src/librustc_mir/transform/instcombine.rs b/src/librustc_mir/transform/instcombine.rs deleted file mode 100644 index 7967137e01..0000000000 --- a/src/librustc_mir/transform/instcombine.rs +++ /dev/null @@ -1,117 +0,0 @@ -//! Performs various peephole optimizations. - -use crate::transform::{MirPass, MirSource}; -use rustc_data_structures::fx::{FxHashMap, FxHashSet}; -use rustc_hir::Mutability; -use rustc_index::vec::Idx; -use rustc_middle::mir::visit::{MutVisitor, Visitor}; -use rustc_middle::mir::{ - Body, Constant, Local, Location, Operand, Place, PlaceRef, ProjectionElem, Rvalue, -}; -use rustc_middle::ty::{self, TyCtxt}; -use std::mem; - -pub struct InstCombine; - -impl<'tcx> MirPass<'tcx> for InstCombine { - fn run_pass(&self, tcx: TyCtxt<'tcx>, _: MirSource<'tcx>, body: &mut Body<'tcx>) { - // First, find optimization opportunities. This is done in a pre-pass to keep the MIR - // read-only so that we can do global analyses on the MIR in the process (e.g. - // `Place::ty()`). - let optimizations = { - let mut optimization_finder = OptimizationFinder::new(body, tcx); - optimization_finder.visit_body(body); - optimization_finder.optimizations - }; - - // Then carry out those optimizations. - MutVisitor::visit_body(&mut InstCombineVisitor { optimizations, tcx }, body); - } -} - -pub struct InstCombineVisitor<'tcx> { - optimizations: OptimizationList<'tcx>, - tcx: TyCtxt<'tcx>, -} - -impl<'tcx> MutVisitor<'tcx> for InstCombineVisitor<'tcx> { - fn tcx(&self) -> TyCtxt<'tcx> { - self.tcx - } - - fn visit_rvalue(&mut self, rvalue: &mut Rvalue<'tcx>, location: Location) { - if self.optimizations.and_stars.remove(&location) { - debug!("replacing `&*`: {:?}", rvalue); - let new_place = match rvalue { - Rvalue::Ref(_, _, place) => { - if let &[ref proj_l @ .., proj_r] = place.projection.as_ref() { - place.projection = self.tcx().intern_place_elems(&[proj_r]); - - Place { - // Replace with dummy - local: mem::replace(&mut place.local, Local::new(0)), - projection: self.tcx().intern_place_elems(proj_l), - } - } else { - unreachable!(); - } - } - _ => bug!("Detected `&*` but didn't find `&*`!"), - }; - *rvalue = Rvalue::Use(Operand::Copy(new_place)) - } - - if let Some(constant) = self.optimizations.arrays_lengths.remove(&location) { - debug!("replacing `Len([_; N])`: {:?}", rvalue); - *rvalue = Rvalue::Use(Operand::Constant(box constant)); - } - - self.super_rvalue(rvalue, location) - } -} - -/// Finds optimization opportunities on the MIR. -struct OptimizationFinder<'b, 'tcx> { - body: &'b Body<'tcx>, - tcx: TyCtxt<'tcx>, - optimizations: OptimizationList<'tcx>, -} - -impl OptimizationFinder<'b, 'tcx> { - fn new(body: &'b Body<'tcx>, tcx: TyCtxt<'tcx>) -> OptimizationFinder<'b, 'tcx> { - OptimizationFinder { body, tcx, optimizations: OptimizationList::default() } - } -} - -impl Visitor<'tcx> for OptimizationFinder<'b, 'tcx> { - fn visit_rvalue(&mut self, rvalue: &Rvalue<'tcx>, location: Location) { - if let Rvalue::Ref(_, _, place) = rvalue { - if let PlaceRef { local, projection: &[ref proj_base @ .., ProjectionElem::Deref] } = - place.as_ref() - { - // The dereferenced place must have type `&_`. - let ty = Place::ty_from(local, proj_base, self.body, self.tcx).ty; - if let ty::Ref(_, _, Mutability::Not) = ty.kind { - self.optimizations.and_stars.insert(location); - } - } - } - - if let Rvalue::Len(ref place) = *rvalue { - let place_ty = place.ty(&self.body.local_decls, self.tcx).ty; - if let ty::Array(_, len) = place_ty.kind { - let span = self.body.source_info(location).span; - let constant = Constant { span, literal: len, user_ty: None }; - self.optimizations.arrays_lengths.insert(location, constant); - } - } - - self.super_rvalue(rvalue, location) - } -} - -#[derive(Default)] -struct OptimizationList<'tcx> { - and_stars: FxHashSet, - arrays_lengths: FxHashMap>, -} diff --git a/src/librustc_mir/transform/instrument_coverage.rs b/src/librustc_mir/transform/instrument_coverage.rs deleted file mode 100644 index f60e6da714..0000000000 --- a/src/librustc_mir/transform/instrument_coverage.rs +++ /dev/null @@ -1,247 +0,0 @@ -use crate::transform::{MirPass, MirSource}; -use rustc_data_structures::fingerprint::Fingerprint; -use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; -use rustc_middle::hir; -use rustc_middle::ich::StableHashingContext; -use rustc_middle::mir; -use rustc_middle::mir::coverage::*; -use rustc_middle::mir::visit::Visitor; -use rustc_middle::mir::{BasicBlock, Coverage, CoverageInfo, Location, Statement, StatementKind}; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::TyCtxt; -use rustc_span::def_id::DefId; -use rustc_span::{FileName, Pos, RealFileName, Span, Symbol}; - -/// Inserts call to count_code_region() as a placeholder to be replaced during code generation with -/// the intrinsic llvm.instrprof.increment. -pub struct InstrumentCoverage; - -/// The `query` provider for `CoverageInfo`, requested by `codegen_intrinsic_call()` when -/// constructing the arguments for `llvm.instrprof.increment`. -pub(crate) fn provide(providers: &mut Providers) { - providers.coverageinfo = |tcx, def_id| coverageinfo_from_mir(tcx, def_id); -} - -struct CoverageVisitor { - info: CoverageInfo, -} - -impl Visitor<'_> for CoverageVisitor { - fn visit_coverage(&mut self, coverage: &Coverage, _location: Location) { - match coverage.kind { - CoverageKind::Counter { id, .. } => { - let counter_id = u32::from(id); - self.info.num_counters = std::cmp::max(self.info.num_counters, counter_id + 1); - } - CoverageKind::Expression { id, .. } => { - let expression_index = u32::MAX - u32::from(id); - self.info.num_expressions = - std::cmp::max(self.info.num_expressions, expression_index + 1); - } - _ => {} - } - } -} - -fn coverageinfo_from_mir<'tcx>(tcx: TyCtxt<'tcx>, mir_def_id: DefId) -> CoverageInfo { - let mir_body = tcx.optimized_mir(mir_def_id); - - // The `num_counters` argument to `llvm.instrprof.increment` is the number of injected - // counters, with each counter having a counter ID from `0..num_counters-1`. MIR optimization - // may split and duplicate some BasicBlock sequences. Simply counting the calls may not - // work; but computing the num_counters by adding `1` to the highest counter_id (for a given - // instrumented function) is valid. - // - // `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. - let mut coverage_visitor = - CoverageVisitor { info: CoverageInfo { num_counters: 0, num_expressions: 0 } }; - - coverage_visitor.visit_body(mir_body); - coverage_visitor.info -} - -impl<'tcx> MirPass<'tcx> for InstrumentCoverage { - fn run_pass(&self, tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &mut mir::Body<'tcx>) { - // If the InstrumentCoverage pass is called on promoted MIRs, skip them. - // See: https://github.com/rust-lang/rust/pull/73011#discussion_r438317601 - if src.promoted.is_none() { - Instrumentor::new(tcx, src, mir_body).inject_counters(); - } - } -} - -struct Instrumentor<'a, 'tcx> { - tcx: TyCtxt<'tcx>, - mir_def_id: DefId, - mir_body: &'a mut mir::Body<'tcx>, - hir_body: &'tcx rustc_hir::Body<'tcx>, - function_source_hash: Option, - num_counters: u32, - num_expressions: u32, -} - -impl<'a, 'tcx> Instrumentor<'a, 'tcx> { - fn new(tcx: TyCtxt<'tcx>, src: MirSource<'tcx>, mir_body: &'a mut mir::Body<'tcx>) -> Self { - let mir_def_id = src.def_id(); - let hir_body = hir_body(tcx, mir_def_id); - Self { - tcx, - mir_def_id, - mir_body, - hir_body, - function_source_hash: None, - num_counters: 0, - num_expressions: 0, - } - } - - /// Counter IDs start from zero and go up. - fn next_counter(&mut self) -> CounterValueReference { - assert!(self.num_counters < u32::MAX - self.num_expressions); - let next = self.num_counters; - self.num_counters += 1; - CounterValueReference::from(next) - } - - /// Expression IDs start from u32::MAX and go down because a CounterExpression can reference - /// (add or subtract counts) of both Counter regions and CounterExpression regions. The counter - /// expression operand IDs must be unique across both types. - fn next_expression(&mut self) -> InjectedExpressionIndex { - assert!(self.num_counters < u32::MAX - self.num_expressions); - let next = u32::MAX - self.num_expressions; - self.num_expressions += 1; - InjectedExpressionIndex::from(next) - } - - fn function_source_hash(&mut self) -> u64 { - match self.function_source_hash { - Some(hash) => hash, - None => { - let hash = hash_mir_source(self.tcx, self.hir_body); - self.function_source_hash.replace(hash); - hash - } - } - } - - fn inject_counters(&mut self) { - let body_span = self.hir_body.value.span; - debug!("instrumenting {:?}, span: {:?}", self.mir_def_id, body_span); - - // FIXME(richkadel): As a first step, counters are only injected at the top of each - // function. The complete solution will inject counters at each conditional code branch. - let block = rustc_middle::mir::START_BLOCK; - let counter = self.make_counter(); - self.inject_statement(counter, body_span, block); - - // FIXME(richkadel): The next step to implement source based coverage analysis will be - // instrumenting branches within functions, and some regions will be counted by "counter - // expression". The function to inject counter expression is implemented. Replace this - // "fake use" with real use. - let fake_use = false; - if fake_use { - let add = false; - let fake_counter = CoverageKind::Counter { - function_source_hash: self.function_source_hash(), - id: CounterValueReference::from_u32(1), - }; - let fake_expression = CoverageKind::Expression { - id: InjectedExpressionIndex::from(u32::MAX - 1), - lhs: ExpressionOperandId::from_u32(1), - op: Op::Add, - rhs: ExpressionOperandId::from_u32(2), - }; - - let lhs = fake_counter.as_operand_id(); - let op = if add { Op::Add } else { Op::Subtract }; - let rhs = fake_expression.as_operand_id(); - - let block = rustc_middle::mir::START_BLOCK; - - let expression = self.make_expression(lhs, op, rhs); - self.inject_statement(expression, body_span, block); - } - } - - fn make_counter(&mut self) -> CoverageKind { - CoverageKind::Counter { - function_source_hash: self.function_source_hash(), - id: self.next_counter(), - } - } - - fn make_expression( - &mut self, - lhs: ExpressionOperandId, - op: Op, - rhs: ExpressionOperandId, - ) -> CoverageKind { - CoverageKind::Expression { id: self.next_expression(), lhs, op, rhs } - } - - fn inject_statement(&mut self, coverage_kind: CoverageKind, span: Span, block: BasicBlock) { - let code_region = make_code_region(self.tcx, &span); - debug!(" injecting statement {:?} covering {:?}", coverage_kind, code_region); - - let data = &mut self.mir_body[block]; - let source_info = data.terminator().source_info; - let statement = Statement { - source_info, - kind: StatementKind::Coverage(box Coverage { kind: coverage_kind, code_region }), - }; - data.statements.push(statement); - } -} - -/// Convert the Span into its file name, start line and column, and end line and column -fn make_code_region<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> CodeRegion { - let source_map = tcx.sess.source_map(); - let start = source_map.lookup_char_pos(span.lo()); - let end = if span.hi() == span.lo() { - start.clone() - } else { - let end = source_map.lookup_char_pos(span.hi()); - debug_assert_eq!( - start.file.name, - end.file.name, - "Region start ({:?} -> {:?}) and end ({:?} -> {:?}) don't come from the same source file!", - span.lo(), - start, - span.hi(), - end - ); - end - }; - match &start.file.name { - FileName::Real(RealFileName::Named(path)) => CodeRegion { - file_name: Symbol::intern(&path.to_string_lossy()), - 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, - }, - _ => bug!("start.file.name should be a RealFileName, but it was: {:?}", start.file.name), - } -} - -fn hir_body<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId) -> &'tcx rustc_hir::Body<'tcx> { - let hir_node = tcx.hir().get_if_local(def_id).expect("DefId is local"); - let fn_body_id = hir::map::associated_body(hir_node).expect("HIR node is a function with body"); - tcx.hir().body(fn_body_id) -} - -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 --git a/src/librustc_mir/transform/qualify_min_const_fn.rs b/src/librustc_mir/transform/qualify_min_const_fn.rs deleted file mode 100644 index 26db4600a2..0000000000 --- a/src/librustc_mir/transform/qualify_min_const_fn.rs +++ /dev/null @@ -1,464 +0,0 @@ -use rustc_attr as attr; -use rustc_hir as hir; -use rustc_hir::def_id::DefId; -use rustc_middle::mir::*; -use rustc_middle::ty::subst::GenericArgKind; -use rustc_middle::ty::{self, adjustment::PointerCast, Ty, TyCtxt}; -use rustc_span::symbol::{sym, Symbol}; -use rustc_span::Span; -use rustc_target::spec::abi::Abi::RustIntrinsic; -use std::borrow::Cow; - -type McfResult = Result<(), (Span, Cow<'static, str>)>; - -pub fn is_min_const_fn(tcx: TyCtxt<'tcx>, def_id: DefId, body: &'a Body<'tcx>) -> McfResult { - // Prevent const trait methods from being annotated as `stable`. - if tcx.features().staged_api { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - if crate::const_eval::is_parent_const_impl_raw(tcx, hir_id) { - return Err((body.span, "trait methods cannot be stable const fn".into())); - } - } - - let mut current = def_id; - loop { - let predicates = tcx.predicates_of(current); - for (predicate, _) in predicates.predicates { - match predicate.skip_binders() { - ty::PredicateAtom::RegionOutlives(_) - | ty::PredicateAtom::TypeOutlives(_) - | ty::PredicateAtom::WellFormed(_) - | ty::PredicateAtom::Projection(_) - | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => continue, - ty::PredicateAtom::ObjectSafe(_) => { - bug!("object safe predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::ClosureKind(..) => { - bug!("closure kind predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::Subtype(_) => { - bug!("subtype predicate on function: {:#?}", predicate) - } - ty::PredicateAtom::Trait(pred, constness) => { - if Some(pred.def_id()) == tcx.lang_items().sized_trait() { - continue; - } - match pred.self_ty().kind { - ty::Param(ref p) => { - // Allow `T: ?const Trait` - if constness == hir::Constness::NotConst - && feature_allowed(tcx, def_id, sym::const_trait_bound_opt_out) - { - continue; - } - - let generics = tcx.generics_of(current); - let def = generics.type_param(p, tcx); - let span = tcx.def_span(def.def_id); - return Err(( - span, - "trait bounds other than `Sized` \ - on const fn parameters are unstable" - .into(), - )); - } - // other kinds of bounds are either tautologies - // or cause errors in other passes - _ => continue, - } - } - } - } - match predicates.parent { - Some(parent) => current = parent, - None => break, - } - } - - for local in &body.local_decls { - check_ty(tcx, local.ty, local.source_info.span, def_id)?; - } - // impl trait is gone in MIR, so check the return type manually - check_ty( - tcx, - tcx.fn_sig(def_id).output().skip_binder(), - body.local_decls.iter().next().unwrap().source_info.span, - def_id, - )?; - - for bb in body.basic_blocks() { - check_terminator(tcx, body, def_id, bb.terminator())?; - for stmt in &bb.statements { - check_statement(tcx, body, def_id, stmt)?; - } - } - Ok(()) -} - -fn check_ty(tcx: TyCtxt<'tcx>, ty: Ty<'tcx>, span: Span, fn_def_id: DefId) -> McfResult { - for arg in ty.walk() { - let ty = match arg.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) => { - if !feature_allowed(tcx, fn_def_id, sym::const_mut_refs) { - return Err((span, "mutable references in const fn are unstable".into())); - } - } - ty::Opaque(..) => return Err((span, "`impl Trait` in const fn is unstable".into())), - ty::FnPtr(..) => { - if !tcx.const_fn_is_allowed_fn_ptr(fn_def_id) { - return Err((span, "function pointers in const fn are unstable".into())); - } - } - ty::Dynamic(preds, _) => { - for pred in preds.iter() { - match pred.skip_binder() { - ty::ExistentialPredicate::AutoTrait(_) - | ty::ExistentialPredicate::Projection(_) => { - return Err(( - span, - "trait bounds other than `Sized` \ - on const fn parameters are unstable" - .into(), - )); - } - ty::ExistentialPredicate::Trait(trait_ref) => { - if Some(trait_ref.def_id) != tcx.lang_items().sized_trait() { - return Err(( - span, - "trait bounds other than `Sized` \ - on const fn parameters are unstable" - .into(), - )); - } - } - } - } - } - _ => {} - } - } - Ok(()) -} - -fn check_rvalue( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - def_id: DefId, - rvalue: &Rvalue<'tcx>, - span: Span, -) -> McfResult { - match rvalue { - Rvalue::ThreadLocalRef(_) => { - Err((span, "cannot access thread local storage in const fn".into())) - } - Rvalue::Repeat(operand, _) | Rvalue::Use(operand) => { - check_operand(tcx, operand, span, def_id, body) - } - Rvalue::Len(place) - | Rvalue::Discriminant(place) - | Rvalue::Ref(_, _, place) - | Rvalue::AddressOf(_, place) => check_place(tcx, *place, span, def_id, body), - Rvalue::Cast(CastKind::Misc, operand, cast_ty) => { - use rustc_middle::ty::cast::CastTy; - let cast_in = CastTy::from_ty(operand.ty(body, tcx)).expect("bad input type for cast"); - let cast_out = CastTy::from_ty(cast_ty).expect("bad output type for cast"); - match (cast_in, cast_out) { - (CastTy::Ptr(_) | CastTy::FnPtr, CastTy::Int(_)) => { - Err((span, "casting pointers to ints is unstable in const fn".into())) - } - _ => check_operand(tcx, operand, span, def_id, body), - } - } - Rvalue::Cast( - CastKind::Pointer(PointerCast::MutToConstPointer | PointerCast::ArrayToPointer), - operand, - _, - ) => check_operand(tcx, operand, span, def_id, body), - Rvalue::Cast( - CastKind::Pointer( - PointerCast::UnsafeFnPointer - | PointerCast::ClosureFnPointer(_) - | PointerCast::ReifyFnPointer, - ), - _, - _, - ) => Err((span, "function pointer casts are not allowed in const fn".into())), - Rvalue::Cast(CastKind::Pointer(PointerCast::Unsize), op, cast_ty) => { - let pointee_ty = if let Some(deref_ty) = cast_ty.builtin_deref(true) { - deref_ty.ty - } else { - // We cannot allow this for now. - return Err(( - span, - "unsizing casts are only allowed for references right now".into(), - )); - }; - let unsized_ty = tcx.struct_tail_erasing_lifetimes(pointee_ty, tcx.param_env(def_id)); - if let ty::Slice(_) | ty::Str = unsized_ty.kind { - check_operand(tcx, op, span, def_id, body)?; - // Casting/coercing things to slices is fine. - Ok(()) - } else { - // We just can't allow trait objects until we have figured out trait method calls. - Err((span, "unsizing casts are not allowed in const fn".into())) - } - } - // binops are fine on integers - Rvalue::BinaryOp(_, lhs, rhs) | Rvalue::CheckedBinaryOp(_, lhs, rhs) => { - check_operand(tcx, lhs, span, def_id, body)?; - check_operand(tcx, rhs, span, def_id, body)?; - let ty = lhs.ty(body, tcx); - if ty.is_integral() || ty.is_bool() || ty.is_char() { - Ok(()) - } else { - Err((span, "only int, `bool` and `char` operations are stable in const fn".into())) - } - } - Rvalue::NullaryOp(NullOp::SizeOf, _) => Ok(()), - Rvalue::NullaryOp(NullOp::Box, _) => { - Err((span, "heap allocations are not allowed in const fn".into())) - } - Rvalue::UnaryOp(_, operand) => { - let ty = operand.ty(body, tcx); - if ty.is_integral() || ty.is_bool() { - check_operand(tcx, operand, span, def_id, body) - } else { - Err((span, "only int and `bool` operations are stable in const fn".into())) - } - } - Rvalue::Aggregate(_, operands) => { - for operand in operands { - check_operand(tcx, operand, span, def_id, body)?; - } - Ok(()) - } - } -} - -fn check_statement( - tcx: TyCtxt<'tcx>, - body: &Body<'tcx>, - def_id: DefId, - statement: &Statement<'tcx>, -) -> McfResult { - let span = statement.source_info.span; - match &statement.kind { - StatementKind::Assign(box (place, rval)) => { - check_place(tcx, *place, span, def_id, body)?; - check_rvalue(tcx, body, def_id, rval, span) - } - - StatementKind::FakeRead(_, place) => check_place(tcx, **place, span, def_id, body), - - // just an assignment - StatementKind::SetDiscriminant { place, .. } => { - check_place(tcx, **place, span, def_id, body) - } - - StatementKind::LlvmInlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } - - // These are all NOPs - StatementKind::StorageLive(_) - | StatementKind::StorageDead(_) - | StatementKind::Retag { .. } - | StatementKind::AscribeUserType(..) - | StatementKind::Coverage(..) - | StatementKind::Nop => Ok(()), - } -} - -fn check_operand( - tcx: TyCtxt<'tcx>, - operand: &Operand<'tcx>, - span: Span, - def_id: DefId, - body: &Body<'tcx>, -) -> McfResult { - match operand { - Operand::Move(place) | Operand::Copy(place) => check_place(tcx, *place, span, def_id, body), - Operand::Constant(c) => match c.check_static_ptr(tcx) { - Some(_) => Err((span, "cannot access `static` items in const fn".into())), - None => Ok(()), - }, - } -} - -fn check_place( - tcx: TyCtxt<'tcx>, - place: Place<'tcx>, - span: Span, - def_id: DefId, - body: &Body<'tcx>, -) -> McfResult { - let mut cursor = place.projection.as_ref(); - while let &[ref proj_base @ .., elem] = cursor { - cursor = proj_base; - match elem { - ProjectionElem::Field(..) => { - let base_ty = Place::ty_from(place.local, &proj_base, body, tcx).ty; - if let Some(def) = base_ty.ty_adt_def() { - // No union field accesses in `const fn` - if def.is_union() { - if !feature_allowed(tcx, def_id, sym::const_fn_union) { - return Err((span, "accessing union fields is unstable".into())); - } - } - } - } - ProjectionElem::ConstantIndex { .. } - | ProjectionElem::Downcast(..) - | ProjectionElem::Subslice { .. } - | ProjectionElem::Deref - | ProjectionElem::Index(_) => {} - } - } - - Ok(()) -} - -/// Returns `true` if the given feature gate is allowed within the function with the given `DefId`. -fn feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { - // All features require that the corresponding gate be enabled, - // even if the function has `#[allow_internal_unstable(the_gate)]`. - if !tcx.features().enabled(feature_gate) { - return false; - } - - // If this crate is not using stability attributes, or this function is not claiming to be a - // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { - return true; - } - - // However, we cannot allow stable `const fn`s to use unstable features without an explicit - // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) -} - -/// Returns `true` if the given library feature gate is allowed within the function with the given `DefId`. -pub fn lib_feature_allowed(tcx: TyCtxt<'tcx>, def_id: DefId, feature_gate: Symbol) -> bool { - // All features require that the corresponding gate be enabled, - // even if the function has `#[allow_internal_unstable(the_gate)]`. - if !tcx.features().declared_lib_features.iter().any(|&(sym, _)| sym == feature_gate) { - return false; - } - - // If this crate is not using stability attributes, or this function is not claiming to be a - // stable `const fn`, that is all that is required. - if !tcx.features().staged_api || tcx.has_attr(def_id, sym::rustc_const_unstable) { - return true; - } - - // However, we cannot allow stable `const fn`s to use unstable features without an explicit - // opt-in via `allow_internal_unstable`. - attr::allow_internal_unstable(&tcx.sess, &tcx.get_attrs(def_id)) - .map_or(false, |mut features| features.any(|name| name == feature_gate)) -} - -fn check_terminator( - tcx: TyCtxt<'tcx>, - body: &'a Body<'tcx>, - def_id: DefId, - terminator: &Terminator<'tcx>, -) -> McfResult { - let span = terminator.source_info.span; - match &terminator.kind { - TerminatorKind::FalseEdge { .. } - | TerminatorKind::FalseUnwind { .. } - | TerminatorKind::Goto { .. } - | TerminatorKind::Return - | TerminatorKind::Resume - | TerminatorKind::Unreachable => Ok(()), - - TerminatorKind::Drop { place, .. } => check_place(tcx, *place, span, def_id, body), - TerminatorKind::DropAndReplace { place, value, .. } => { - check_place(tcx, *place, span, def_id, body)?; - check_operand(tcx, value, span, def_id, body) - } - - TerminatorKind::SwitchInt { discr, switch_ty: _, values: _, targets: _ } => { - check_operand(tcx, discr, span, def_id, body) - } - - TerminatorKind::Abort => Err((span, "abort is not stable in const fn".into())), - TerminatorKind::GeneratorDrop | TerminatorKind::Yield { .. } => { - Err((span, "const fn generators are unstable".into())) - } - - TerminatorKind::Call { - func, - args, - from_hir_call: _, - destination: _, - cleanup: _, - fn_span: _, - } => { - let fn_ty = func.ty(body, tcx); - if let ty::FnDef(fn_def_id, _) = fn_ty.kind { - // Allow unstable const if we opt in by using #[allow_internal_unstable] - // on function or macro declaration. - if !crate::const_eval::is_min_const_fn(tcx, fn_def_id) - && !crate::const_eval::is_unstable_const_fn(tcx, fn_def_id) - .map(|feature| { - span.allows_unstable(feature) - || lib_feature_allowed(tcx, def_id, feature) - }) - .unwrap_or(false) - { - return Err(( - span, - format!( - "can only call other `const fn` within a `const fn`, \ - but `{:?}` is not stable as `const fn`", - func, - ) - .into(), - )); - } - - // HACK: This is to "unstabilize" the `transmute` intrinsic - // within const fns. `transmute` is allowed in all other const contexts. - // This won't really scale to more intrinsics or functions. Let's allow const - // transmutes in const fn before we add more hacks to this. - if tcx.fn_sig(fn_def_id).abi() == RustIntrinsic - && tcx.item_name(fn_def_id) == sym::transmute - && !feature_allowed(tcx, def_id, sym::const_fn_transmute) - { - return Err(( - span, - "can only call `transmute` from const items, not `const fn`".into(), - )); - } - - check_operand(tcx, func, span, fn_def_id, body)?; - - for arg in args { - check_operand(tcx, arg, span, fn_def_id, body)?; - } - Ok(()) - } else { - Err((span, "can only call other const fns within const fn".into())) - } - } - - TerminatorKind::Assert { cond, expected: _, msg: _, target: _, cleanup: _ } => { - check_operand(tcx, cond, span, def_id, body) - } - - TerminatorKind::InlineAsm { .. } => { - Err((span, "cannot use inline assembly in const fn".into())) - } - } -} diff --git a/src/librustc_mir_build/Cargo.toml b/src/librustc_mir_build/Cargo.toml deleted file mode 100644 index 97621f205f..0000000000 --- a/src/librustc_mir_build/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_mir_build" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_mir_build" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_apfloat = { path = "../librustc_apfloat" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_infer = { path = "../librustc_infer" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_target = { path = "../librustc_target" } -rustc_trait_selection = { path = "../librustc_trait_selection" } -rustc_ast = { path = "../librustc_ast" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_mir_build/thir/pattern/const_to_pat.rs b/src/librustc_mir_build/thir/pattern/const_to_pat.rs deleted file mode 100644 index f6d3ccc1ae..0000000000 --- a/src/librustc_mir_build/thir/pattern/const_to_pat.rs +++ /dev/null @@ -1,306 +0,0 @@ -use rustc_hir as hir; -use rustc_index::vec::Idx; -use rustc_infer::infer::{InferCtxt, TyCtxtInferExt}; -use rustc_middle::mir::Field; -use rustc_middle::ty::{self, Ty, TyCtxt}; -use rustc_session::lint; -use rustc_span::Span; -use rustc_trait_selection::traits::predicate_for_trait_def; -use rustc_trait_selection::traits::query::evaluate_obligation::InferCtxtExt; -use rustc_trait_selection::traits::{self, ObligationCause, PredicateObligation}; - -use std::cell::Cell; - -use super::{FieldPat, Pat, PatCtxt, PatKind}; - -impl<'a, 'tcx> PatCtxt<'a, 'tcx> { - /// Converts an evaluated constant to a pattern (if possible). - /// This means aggregate values (like structs and enums) are converted - /// to a pattern that matches the value (as if you'd compared via structural equality). - pub(super) fn const_to_pat( - &self, - cv: &'tcx ty::Const<'tcx>, - id: hir::HirId, - span: Span, - mir_structural_match_violation: bool, - ) -> Pat<'tcx> { - debug!("const_to_pat: cv={:#?} id={:?}", cv, id); - debug!("const_to_pat: cv.ty={:?} span={:?}", cv.ty, span); - - self.tcx.infer_ctxt().enter(|infcx| { - let mut convert = ConstToPat::new(self, id, span, infcx); - convert.to_pat(cv, mir_structural_match_violation) - }) - } -} - -struct ConstToPat<'a, 'tcx> { - id: hir::HirId, - span: Span, - param_env: ty::ParamEnv<'tcx>, - - // This tracks if we signal some hard error for a given const value, so that - // we will not subsequently issue an irrelevant lint for the same const - // value. - saw_const_match_error: Cell, - - // inference context used for checking `T: Structural` bounds. - infcx: InferCtxt<'a, 'tcx>, - - include_lint_checks: bool, -} - -impl<'a, 'tcx> ConstToPat<'a, 'tcx> { - fn new( - pat_ctxt: &PatCtxt<'_, 'tcx>, - id: hir::HirId, - span: Span, - infcx: InferCtxt<'a, 'tcx>, - ) -> Self { - ConstToPat { - id, - span, - infcx, - param_env: pat_ctxt.param_env, - include_lint_checks: pat_ctxt.include_lint_checks, - saw_const_match_error: Cell::new(false), - } - } - - fn tcx(&self) -> TyCtxt<'tcx> { - self.infcx.tcx - } - - fn search_for_structural_match_violation( - &self, - ty: Ty<'tcx>, - ) -> Option> { - traits::search_for_structural_match_violation(self.id, self.span, self.tcx(), ty) - } - - fn type_marked_structural(&self, ty: Ty<'tcx>) -> bool { - ty.is_structural_eq_shallow(self.infcx.tcx) - } - - fn to_pat( - &mut self, - cv: &'tcx ty::Const<'tcx>, - mir_structural_match_violation: bool, - ) -> Pat<'tcx> { - // This method is just a wrapper handling a validity check; the heavy lifting is - // performed by the recursive `recur` method, which is not meant to be - // invoked except by this method. - // - // once indirect_structural_match is a full fledged error, this - // level of indirection can be eliminated - - let inlined_const_as_pat = self.recur(cv); - - if self.include_lint_checks && !self.saw_const_match_error.get() { - // If we were able to successfully convert the const to some pat, - // double-check that all types in the const implement `Structural`. - - let structural = self.search_for_structural_match_violation(cv.ty); - debug!( - "search_for_structural_match_violation cv.ty: {:?} returned: {:?}", - cv.ty, structural - ); - - // This can occur because const qualification treats all associated constants as - // opaque, whereas `search_for_structural_match_violation` tries to monomorphize them - // before it runs. - // - // FIXME(#73448): Find a way to bring const qualification into parity with - // `search_for_structural_match_violation`. - if structural.is_none() && mir_structural_match_violation { - warn!("MIR const-checker found novel structural match violation. See #73448."); - return inlined_const_as_pat; - } - - if let Some(non_sm_ty) = structural { - let msg = match non_sm_ty { - traits::NonStructuralMatchTy::Adt(adt_def) => { - let path = self.tcx().def_path_str(adt_def.did); - format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ) - } - traits::NonStructuralMatchTy::Dynamic => { - "trait objects cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Opaque => { - "opaque types cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Generator => { - "generators cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Closure => { - "closures cannot be used in patterns".to_string() - } - traits::NonStructuralMatchTy::Param => { - bug!("use of a constant whose type is a parameter inside a pattern") - } - traits::NonStructuralMatchTy::Projection => { - bug!("use of a constant whose type is a projection inside a pattern") - } - traits::NonStructuralMatchTy::Foreign => { - bug!("use of a value of a foreign type inside a pattern") - } - }; - - // double-check there even *is* a semantic `PartialEq` to dispatch to. - // - // (If there isn't, then we can safely issue a hard - // error, because that's never worked, due to compiler - // using `PartialEq::eq` in this scenario in the past.) - // - // Note: To fix rust-lang/rust#65466, one could lift this check - // *before* any structural-match checking, and unconditionally error - // if `PartialEq` is not implemented. However, that breaks stable - // code at the moment, because types like `for <'a> fn(&'a ())` do - // not *yet* implement `PartialEq`. So for now we leave this here. - let ty_is_partial_eq: bool = { - let partial_eq_trait_id = - self.tcx().require_lang_item(hir::LangItem::PartialEq, Some(self.span)); - let obligation: PredicateObligation<'_> = predicate_for_trait_def( - self.tcx(), - self.param_env, - ObligationCause::misc(self.span, self.id), - partial_eq_trait_id, - 0, - cv.ty, - &[], - ); - // FIXME: should this call a `predicate_must_hold` variant instead? - self.infcx.predicate_may_hold(&obligation) - }; - - if !ty_is_partial_eq { - // span_fatal avoids ICE from resolution of non-existent method (rare case). - self.tcx().sess.span_fatal(self.span, &msg); - } else if mir_structural_match_violation { - self.tcx().struct_span_lint_hir( - lint::builtin::INDIRECT_STRUCTURAL_MATCH, - self.id, - self.span, - |lint| lint.build(&msg).emit(), - ); - } else { - debug!( - "`search_for_structural_match_violation` found one, but `CustomEq` was \ - not in the qualifs for that `const`" - ); - } - } - } - - inlined_const_as_pat - } - - // Recursive helper for `to_pat`; invoke that (instead of calling this directly). - fn recur(&self, cv: &'tcx ty::Const<'tcx>) -> Pat<'tcx> { - let id = self.id; - let span = self.span; - let tcx = self.tcx(); - let param_env = self.param_env; - - let field_pats = |vals: &[&'tcx ty::Const<'tcx>]| { - vals.iter() - .enumerate() - .map(|(idx, val)| { - let field = Field::new(idx); - FieldPat { field, pattern: self.recur(val) } - }) - .collect() - }; - - let kind = match cv.ty.kind { - ty::Float(_) => { - tcx.struct_span_lint_hir( - lint::builtin::ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - id, - span, - |lint| lint.build("floating-point types cannot be used in patterns").emit(), - ); - PatKind::Constant { value: cv } - } - ty::Adt(adt_def, _) if adt_def.is_union() => { - // Matching on union fields is unsafe, we can't hide it in constants - self.saw_const_match_error.set(true); - tcx.sess.span_err(span, "cannot use unions in constant patterns"); - PatKind::Wild - } - // keep old code until future-compat upgraded to errors. - ty::Adt(adt_def, _) if !self.type_marked_structural(cv.ty) => { - debug!("adt_def {:?} has !type_marked_structural for cv.ty: {:?}", adt_def, cv.ty); - let path = tcx.def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); - self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &msg); - PatKind::Wild - } - // keep old code until future-compat upgraded to errors. - ty::Ref(_, adt_ty @ ty::TyS { kind: ty::Adt(_, _), .. }, _) - if !self.type_marked_structural(adt_ty) => - { - let adt_def = - if let ty::Adt(adt_def, _) = adt_ty.kind { adt_def } else { unreachable!() }; - - debug!( - "adt_def {:?} has !type_marked_structural for adt_ty: {:?}", - adt_def, adt_ty - ); - - // HACK(estebank): Side-step ICE #53708, but anything other than erroring here - // would be wrong. Returnging `PatKind::Wild` is not technically correct. - let path = tcx.def_path_str(adt_def.did); - let msg = format!( - "to use a constant of type `{}` in a pattern, \ - `{}` must be annotated with `#[derive(PartialEq, Eq)]`", - path, path, - ); - self.saw_const_match_error.set(true); - tcx.sess.span_err(span, &msg); - PatKind::Wild - } - ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Variant { - adt_def, - substs, - variant_index: destructured - .variant - .expect("destructed const of adt without variant id"), - subpatterns: field_pats(destructured.fields), - } - } - ty::Adt(_, _) => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } - } - ty::Tuple(_) => { - let destructured = tcx.destructure_const(param_env.and(cv)); - PatKind::Leaf { subpatterns: field_pats(destructured.fields) } - } - ty::Array(..) => PatKind::Array { - prefix: tcx - .destructure_const(param_env.and(cv)) - .fields - .iter() - .map(|val| self.recur(val)) - .collect(), - slice: None, - suffix: Vec::new(), - }, - _ => PatKind::Constant { value: cv }, - }; - - Pat { span, ty: cv.ty, kind: Box::new(kind) } - } -} diff --git a/src/librustc_parse/Cargo.toml b/src/librustc_parse/Cargo.toml deleted file mode 100644 index 31d858849a..0000000000 --- a/src/librustc_parse/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_parse" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_parse" -path = "lib.rs" -doctest = false - -[dependencies] -bitflags = "1.0" -tracing = "0.1" -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_feature = { path = "../librustc_feature" } -rustc_lexer = { path = "../librustc_lexer" } -rustc_errors = { path = "../librustc_errors" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_ast = { path = "../librustc_ast" } -unicode-normalization = "0.1.11" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_parse_format/Cargo.toml b/src/librustc_parse_format/Cargo.toml deleted file mode 100644 index 646509569f..0000000000 --- a/src/librustc_parse_format/Cargo.toml +++ /dev/null @@ -1,13 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_parse_format" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_parse_format" -path = "lib.rs" - -[dependencies] -rustc_span = { path = "../librustc_span" } -rustc_lexer = { path = "../librustc_lexer" } diff --git a/src/librustc_passes/Cargo.toml b/src/librustc_passes/Cargo.toml deleted file mode 100644 index db481c0d0d..0000000000 --- a/src/librustc_passes/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_passes" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_passes" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_session = { path = "../librustc_session" } -rustc_target = { path = "../librustc_target" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_plugin_impl/Cargo.toml b/src/librustc_plugin_impl/Cargo.toml deleted file mode 100644 index 38cfbd48de..0000000000 --- a/src/librustc_plugin_impl/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_plugin_impl" -version = "0.0.0" -build = false -edition = "2018" - -[lib] -name = "rustc_plugin_impl" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_middle = { path = "../librustc_middle" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_lint = { path = "../librustc_lint" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_ast = { path = "../librustc_ast" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } diff --git a/src/librustc_privacy/Cargo.toml b/src/librustc_privacy/Cargo.toml deleted file mode 100644 index 3641f0f8a3..0000000000 --- a/src/librustc_privacy/Cargo.toml +++ /dev/null @@ -1,20 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_privacy" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_privacy" -path = "lib.rs" - -[dependencies] -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_typeck = { path = "../librustc_typeck" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_data_structures = { path = "../librustc_data_structures" } -tracing = "0.1" diff --git a/src/librustc_query_system/Cargo.toml b/src/librustc_query_system/Cargo.toml deleted file mode 100644 index 1e89d379cb..0000000000 --- a/src/librustc_query_system/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_query_system" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_query_system" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc-rayon-core = "0.3.0" -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_macros = { path = "../librustc_macros" } -rustc_index = { path = "../librustc_index" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -parking_lot = "0.10" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_resolve/Cargo.toml b/src/librustc_resolve/Cargo.toml deleted file mode 100644 index e5260866f2..0000000000 --- a/src/librustc_resolve/Cargo.toml +++ /dev/null @@ -1,31 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_resolve" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_resolve" -path = "lib.rs" -test = false -doctest = false - -[dependencies] -bitflags = "1.2.1" -tracing = "0.1" -rustc_ast = { path = "../librustc_ast" } -rustc_arena = { path = "../librustc_arena" } -rustc_middle = { path = "../librustc_middle" } -rustc_ast_lowering = { path = "../librustc_ast_lowering" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_expand = { path = "../librustc_expand" } -rustc_feature = { path = "../librustc_feature" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_metadata = { path = "../librustc_metadata" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_save_analysis/Cargo.toml b/src/librustc_save_analysis/Cargo.toml deleted file mode 100644 index 3c2edc1fa5..0000000000 --- a/src/librustc_save_analysis/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_save_analysis" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_save_analysis" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_ast = { path = "../librustc_ast" } -rustc_ast_pretty = { path = "../librustc_ast_pretty" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_parse = { path = "../librustc_parse" } -serde_json = "1" -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rls-data = "0.19" -rls-span = "0.5" diff --git a/src/librustc_session/Cargo.toml b/src/librustc_session/Cargo.toml deleted file mode 100644 index 208bba1d96..0000000000 --- a/src/librustc_session/Cargo.toml +++ /dev/null @@ -1,24 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_session" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_session" -path = "lib.rs" - -[dependencies] -bitflags = "1.2.1" -getopts = "0.2" -rustc_macros = { path = "../librustc_macros" } -tracing = "0.1" -rustc_errors = { path = "../librustc_errors" } -rustc_feature = { path = "../librustc_feature" } -rustc_target = { path = "../librustc_target" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_span = { path = "../librustc_span" } -rustc_fs_util = { path = "../librustc_fs_util" } -num_cpus = "1.0" -rustc_ast = { path = "../librustc_ast" } diff --git a/src/librustc_session/lint/builtin.rs b/src/librustc_session/lint/builtin.rs deleted file mode 100644 index 144a06a491..0000000000 --- a/src/librustc_session/lint/builtin.rs +++ /dev/null @@ -1,635 +0,0 @@ -//! Some lints that are built in to the compiler. -//! -//! These are the built-in lints that are emitted direct in the main -//! compiler code, rather than using their own custom pass. Those -//! lints are all available in `rustc_lint::builtin`. - -use crate::lint::FutureIncompatibleInfo; -use crate::{declare_lint, declare_lint_pass}; -use rustc_span::edition::Edition; -use rustc_span::symbol::sym; - -declare_lint! { - pub ILL_FORMED_ATTRIBUTE_INPUT, - Deny, - "ill-formed attribute inputs that were previously accepted and used in practice", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #57571 ", - edition: None, - }; - crate_level_only -} - -declare_lint! { - pub CONFLICTING_REPR_HINTS, - Deny, - "conflicts between `#[repr(..)]` hints that were previously accepted and used in practice", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #68585 ", - edition: None, - }; -} - -declare_lint! { - pub META_VARIABLE_MISUSE, - Allow, - "possible meta-variable misuse at macro definition" -} - -declare_lint! { - pub INCOMPLETE_INCLUDE, - Deny, - "trailing content in included file" -} - -declare_lint! { - pub ARITHMETIC_OVERFLOW, - Deny, - "arithmetic operation overflows" -} - -declare_lint! { - pub UNCONDITIONAL_PANIC, - Deny, - "operation will cause a panic at runtime" -} - -declare_lint! { - pub CONST_ERR, - Deny, - "constant evaluation detected erroneous expression", - report_in_external_macro -} - -declare_lint! { - pub UNUSED_IMPORTS, - Warn, - "imports that are never used" -} - -declare_lint! { - pub UNUSED_EXTERN_CRATES, - Allow, - "extern crates that are never used" -} - -declare_lint! { - pub UNUSED_CRATE_DEPENDENCIES, - Allow, - "crate dependencies that are never used", - crate_level_only -} - -declare_lint! { - pub UNUSED_QUALIFICATIONS, - Allow, - "detects unnecessarily qualified names" -} - -declare_lint! { - pub UNKNOWN_LINTS, - Warn, - "unrecognized lint attribute" -} - -declare_lint! { - pub UNUSED_VARIABLES, - Warn, - "detect variables which are not used in any way" -} - -declare_lint! { - pub UNUSED_ASSIGNMENTS, - Warn, - "detect assignments that will never be read" -} - -declare_lint! { - pub DEAD_CODE, - Warn, - "detect unused, unexported items" -} - -declare_lint! { - pub UNUSED_ATTRIBUTES, - Warn, - "detects attributes that were not used by the compiler" -} - -declare_lint! { - pub UNREACHABLE_CODE, - Warn, - "detects unreachable code paths", - report_in_external_macro -} - -declare_lint! { - pub UNREACHABLE_PATTERNS, - Warn, - "detects unreachable patterns" -} - -declare_lint! { - pub OVERLAPPING_PATTERNS, - Warn, - "detects overlapping patterns" -} - -declare_lint! { - pub BINDINGS_WITH_VARIANT_NAME, - Warn, - "detects pattern bindings with the same name as one of the matched variants" -} - -declare_lint! { - pub UNUSED_MACROS, - Warn, - "detects macros that were not used" -} - -declare_lint! { - pub WARNINGS, - Warn, - "mass-change the level for lints which produce warnings" -} - -declare_lint! { - pub UNUSED_FEATURES, - Warn, - "unused features found in crate-level `#[feature]` directives" -} - -declare_lint! { - pub STABLE_FEATURES, - Warn, - "stable features found in `#[feature]` directive" -} - -declare_lint! { - pub UNKNOWN_CRATE_TYPES, - Deny, - "unknown crate type found in `#[crate_type]` directive", - crate_level_only -} - -declare_lint! { - pub TRIVIAL_CASTS, - Allow, - "detects trivial casts which could be removed" -} - -declare_lint! { - pub TRIVIAL_NUMERIC_CASTS, - Allow, - "detects trivial casts of numeric types which could be removed" -} - -declare_lint! { - pub PRIVATE_IN_PUBLIC, - Warn, - "detect private items in public interfaces not caught by the old implementation", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #34537 ", - edition: None, - }; -} - -declare_lint! { - pub EXPORTED_PRIVATE_DEPENDENCIES, - Warn, - "public interface leaks type from a private dependency" -} - -declare_lint! { - pub PUB_USE_OF_PRIVATE_EXTERN_CRATE, - Deny, - "detect public re-exports of private extern crates", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #34537 ", - edition: None, - }; -} - -declare_lint! { - pub INVALID_TYPE_PARAM_DEFAULT, - Deny, - "type parameter default erroneously allowed in invalid location", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #36887 ", - edition: None, - }; -} - -declare_lint! { - pub RENAMED_AND_REMOVED_LINTS, - Warn, - "lints that have been renamed or removed" -} - -declare_lint! { - pub UNALIGNED_REFERENCES, - Allow, - "detects unaligned references to fields of packed structs", -} - -declare_lint! { - pub SAFE_PACKED_BORROWS, - Warn, - "safe borrows of fields of packed structs were erroneously allowed", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #46043 ", - edition: None, - }; -} - -declare_lint! { - pub PATTERNS_IN_FNS_WITHOUT_BODY, - Deny, - "patterns in functions without body were erroneously allowed", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #35203 ", - edition: None, - }; -} - -declare_lint! { - pub MISSING_FRAGMENT_SPECIFIER, - Deny, - "detects missing fragment specifiers in unused `macro_rules!` patterns", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #40107 ", - edition: None, - }; -} - -declare_lint! { - pub LATE_BOUND_LIFETIME_ARGUMENTS, - Warn, - "detects generic lifetime arguments in path segments with late bound lifetime parameters", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #42868 ", - edition: None, - }; -} - -declare_lint! { - pub ORDER_DEPENDENT_TRAIT_OBJECTS, - Deny, - "trait-object types were treated as different depending on marker-trait order", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #56484 ", - edition: None, - }; -} - -declare_lint! { - pub COHERENCE_LEAK_CHECK, - Warn, - "distinct impls distinguished only by the leak-check code", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #56105 ", - edition: None, - }; -} - -declare_lint! { - pub DEPRECATED, - Warn, - "detects use of deprecated items", - report_in_external_macro -} - -declare_lint! { - pub UNUSED_UNSAFE, - Warn, - "unnecessary use of an `unsafe` block" -} - -declare_lint! { - pub UNUSED_MUT, - Warn, - "detect mut variables which don't need to be mutable" -} - -declare_lint! { - pub UNCONDITIONAL_RECURSION, - Warn, - "functions that cannot return without calling themselves" -} - -declare_lint! { - pub SINGLE_USE_LIFETIMES, - Allow, - "detects lifetime parameters that are only used once" -} - -declare_lint! { - pub UNUSED_LIFETIMES, - Allow, - "detects lifetime parameters that are never used" -} - -declare_lint! { - pub TYVAR_BEHIND_RAW_POINTER, - Warn, - "raw pointer to an inference variable", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #46906 ", - edition: Some(Edition::Edition2018), - }; -} - -declare_lint! { - pub ELIDED_LIFETIMES_IN_PATHS, - Allow, - "hidden lifetime parameters in types are deprecated", - crate_level_only -} - -declare_lint! { - pub BARE_TRAIT_OBJECTS, - Warn, - "suggest using `dyn Trait` for trait objects" -} - -declare_lint! { - pub ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - Allow, - "fully qualified paths that start with a module name \ - instead of `crate`, `self`, or an extern crate name", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #53130 ", - edition: Some(Edition::Edition2018), - }; -} - -declare_lint! { - pub ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - Warn, - "floating-point literals cannot be used in patterns", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #41620 ", - edition: None, - }; -} - -declare_lint! { - pub UNSTABLE_NAME_COLLISIONS, - Warn, - "detects name collision with an existing but unstable method", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #48919 ", - edition: None, - // Note: this item represents future incompatibility of all unstable functions in the - // standard library, and thus should never be removed or changed to an error. - }; -} - -declare_lint! { - pub IRREFUTABLE_LET_PATTERNS, - Warn, - "detects irrefutable patterns in if-let and while-let statements" -} - -declare_lint! { - pub UNUSED_LABELS, - Warn, - "detects labels that are never used" -} - -declare_lint! { - pub BROKEN_INTRA_DOC_LINKS, - Warn, - "failures in resolving intra-doc link targets" -} - -declare_lint! { - pub INVALID_CODEBLOCK_ATTRIBUTES, - Warn, - "codeblock attribute looks a lot like a known one" -} - -declare_lint! { - pub MISSING_CRATE_LEVEL_DOCS, - Allow, - "detects crates with no crate-level documentation" -} - -declare_lint! { - pub MISSING_DOC_CODE_EXAMPLES, - Allow, - "detects publicly-exported items without code samples in their documentation" -} - -declare_lint! { - pub PRIVATE_DOC_TESTS, - Allow, - "detects code samples in docs of private items not documented by rustdoc" -} - -declare_lint! { - pub WHERE_CLAUSES_OBJECT_SAFETY, - Warn, - "checks the object safety of where clauses", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #51443 ", - edition: None, - }; -} - -declare_lint! { - pub PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - Warn, - "detects proc macro derives using inaccessible names from parent modules", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #50504 ", - edition: None, - }; -} - -declare_lint! { - pub MACRO_USE_EXTERN_CRATE, - Allow, - "the `#[macro_use]` attribute is now deprecated in favor of using macros \ - via the module system" -} - -declare_lint! { - pub MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - Deny, - "macro-expanded `macro_export` macros from the current crate \ - cannot be referred to by absolute paths", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #52234 ", - edition: None, - }; - crate_level_only -} - -declare_lint! { - pub EXPLICIT_OUTLIVES_REQUIREMENTS, - Allow, - "outlives requirements can be inferred" -} - -declare_lint! { - pub INDIRECT_STRUCTURAL_MATCH, - // defaulting to allow until rust-lang/rust#62614 is fixed. - Allow, - "pattern with const indirectly referencing non-structural-match type", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #62411 ", - edition: None, - }; -} - -declare_lint! { - pub DEPRECATED_IN_FUTURE, - Allow, - "detects use of items that will be deprecated in a future version", - report_in_external_macro -} - -declare_lint! { - pub AMBIGUOUS_ASSOCIATED_ITEMS, - Deny, - "ambiguous associated items", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #57644 ", - edition: None, - }; -} - -declare_lint! { - pub MUTABLE_BORROW_RESERVATION_CONFLICT, - Warn, - "reservation of a two-phased borrow conflicts with other shared borrows", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #59159 ", - edition: None, - }; -} - -declare_lint! { - pub SOFT_UNSTABLE, - Deny, - "a feature gate that doesn't break dependent crates", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #64266 ", - edition: None, - }; -} - -declare_lint! { - pub INLINE_NO_SANITIZE, - Warn, - "detects incompatible use of `#[inline(always)]` and `#[no_sanitize(...)]`", -} - -declare_lint! { - pub ASM_SUB_REGISTER, - Warn, - "using only a subset of a register for inline asm inputs", -} - -declare_lint! { - pub UNSAFE_OP_IN_UNSAFE_FN, - Allow, - "unsafe operations in unsafe functions without an explicit unsafe block are deprecated", - @feature_gate = sym::unsafe_block_in_unsafe_fn; -} - -declare_lint! { - pub CENUM_IMPL_DROP_CAST, - Warn, - "a C-like enum implementing Drop is cast", - @future_incompatible = FutureIncompatibleInfo { - reference: "issue #73333 ", - edition: None, - }; -} - -declare_lint_pass! { - /// Does nothing as a lint pass, but registers some `Lint`s - /// that are used by other parts of the compiler. - HardwiredLints => [ - ILLEGAL_FLOATING_POINT_LITERAL_PATTERN, - ARITHMETIC_OVERFLOW, - UNCONDITIONAL_PANIC, - UNUSED_IMPORTS, - UNUSED_EXTERN_CRATES, - UNUSED_CRATE_DEPENDENCIES, - UNUSED_QUALIFICATIONS, - UNKNOWN_LINTS, - UNUSED_VARIABLES, - UNUSED_ASSIGNMENTS, - DEAD_CODE, - UNREACHABLE_CODE, - UNREACHABLE_PATTERNS, - OVERLAPPING_PATTERNS, - BINDINGS_WITH_VARIANT_NAME, - UNUSED_MACROS, - WARNINGS, - UNUSED_FEATURES, - STABLE_FEATURES, - UNKNOWN_CRATE_TYPES, - TRIVIAL_CASTS, - TRIVIAL_NUMERIC_CASTS, - PRIVATE_IN_PUBLIC, - EXPORTED_PRIVATE_DEPENDENCIES, - PUB_USE_OF_PRIVATE_EXTERN_CRATE, - INVALID_TYPE_PARAM_DEFAULT, - CONST_ERR, - RENAMED_AND_REMOVED_LINTS, - UNALIGNED_REFERENCES, - SAFE_PACKED_BORROWS, - PATTERNS_IN_FNS_WITHOUT_BODY, - MISSING_FRAGMENT_SPECIFIER, - LATE_BOUND_LIFETIME_ARGUMENTS, - ORDER_DEPENDENT_TRAIT_OBJECTS, - COHERENCE_LEAK_CHECK, - DEPRECATED, - UNUSED_UNSAFE, - UNUSED_MUT, - UNCONDITIONAL_RECURSION, - SINGLE_USE_LIFETIMES, - UNUSED_LIFETIMES, - UNUSED_LABELS, - TYVAR_BEHIND_RAW_POINTER, - ELIDED_LIFETIMES_IN_PATHS, - BARE_TRAIT_OBJECTS, - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - UNSTABLE_NAME_COLLISIONS, - IRREFUTABLE_LET_PATTERNS, - BROKEN_INTRA_DOC_LINKS, - INVALID_CODEBLOCK_ATTRIBUTES, - MISSING_CRATE_LEVEL_DOCS, - MISSING_DOC_CODE_EXAMPLES, - PRIVATE_DOC_TESTS, - WHERE_CLAUSES_OBJECT_SAFETY, - PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, - MACRO_USE_EXTERN_CRATE, - MACRO_EXPANDED_MACRO_EXPORTS_ACCESSED_BY_ABSOLUTE_PATHS, - ILL_FORMED_ATTRIBUTE_INPUT, - CONFLICTING_REPR_HINTS, - META_VARIABLE_MISUSE, - DEPRECATED_IN_FUTURE, - AMBIGUOUS_ASSOCIATED_ITEMS, - MUTABLE_BORROW_RESERVATION_CONFLICT, - INDIRECT_STRUCTURAL_MATCH, - SOFT_UNSTABLE, - INLINE_NO_SANITIZE, - ASM_SUB_REGISTER, - UNSAFE_OP_IN_UNSAFE_FN, - INCOMPLETE_INCLUDE, - CENUM_IMPL_DROP_CAST, - ] -} - -declare_lint! { - pub UNUSED_DOC_COMMENTS, - Warn, - "detects doc comments that aren't used by rustdoc" -} - -declare_lint_pass!(UnusedDocComment => [UNUSED_DOC_COMMENTS]); diff --git a/src/librustc_span/Cargo.toml b/src/librustc_span/Cargo.toml deleted file mode 100644 index dd4928d4e3..0000000000 --- a/src/librustc_span/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_span" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_span" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_serialize = { path = "../librustc_serialize" } -rustc_macros = { path = "../librustc_macros" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_index = { path = "../librustc_index" } -rustc_arena = { path = "../librustc_arena" } -scoped-tls = "1.0" -unicode-width = "0.1.4" -cfg-if = "0.1.2" -tracing = "0.1" -sha-1 = "0.8" -md-5 = "0.8" diff --git a/src/librustc_symbol_mangling/Cargo.toml b/src/librustc_symbol_mangling/Cargo.toml deleted file mode 100644 index b44c0e4e02..0000000000 --- a/src/librustc_symbol_mangling/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_symbol_mangling" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_symbol_mangling" -path = "lib.rs" -doctest = false - -[dependencies] -tracing = "0.1" -punycode = "0.4.0" -rustc-demangle = "0.1.16" - -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_middle = { path = "../librustc_middle" } -rustc_hir = { path = "../librustc_hir" } -rustc_target = { path = "../librustc_target" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_session = { path = "../librustc_session" } diff --git a/src/librustc_target/Cargo.toml b/src/librustc_target/Cargo.toml deleted file mode 100644 index d2b50f44e4..0000000000 --- a/src/librustc_target/Cargo.toml +++ /dev/null @@ -1,18 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_target" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_target" -path = "lib.rs" - -[dependencies] -bitflags = "1.2.1" -tracing = "0.1" -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_macros = { path = "../librustc_macros" } -rustc_serialize = { path = "../librustc_serialize" } -rustc_span = { path = "../librustc_span" } -rustc_index = { path = "../librustc_index" } diff --git a/src/librustc_target/spec/apple_sdk_base.rs b/src/librustc_target/spec/apple_sdk_base.rs deleted file mode 100644 index 0d0a0da9d1..0000000000 --- a/src/librustc_target/spec/apple_sdk_base.rs +++ /dev/null @@ -1,151 +0,0 @@ -use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; -use std::env; -use std::io; -use std::path::Path; -use std::process::Command; - -use Arch::*; -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -pub enum Arch { - Armv7, - Armv7s, - Arm64, - I386, - X86_64, - X86_64_macabi, -} - -#[allow(non_camel_case_types)] -#[derive(Copy, Clone)] -pub enum AppleOS { - tvOS, - iOS, -} - -impl Arch { - pub fn to_string(self) -> &'static str { - match self { - Armv7 => "armv7", - Armv7s => "armv7s", - Arm64 => "arm64", - I386 => "i386", - X86_64 => "x86_64", - X86_64_macabi => "x86_64", - } - } -} - -pub fn get_sdk_root(sdk_name: &str) -> Result { - // Following what clang does - // (https://github.com/llvm/llvm-project/blob/ - // 296a80102a9b72c3eda80558fb78a3ed8849b341/clang/lib/Driver/ToolChains/Darwin.cpp#L1661-L1678) - // to allow the SDK path to be set. (For clang, xcrun sets - // SDKROOT; for rustc, the user or build system can set it, or we - // can fall back to checking for xcrun on PATH.) - if let Ok(sdkroot) = env::var("SDKROOT") { - let p = Path::new(&sdkroot); - match sdk_name { - // Ignore `SDKROOT` if it's clearly set for the wrong platform. - "appletvos" - if sdkroot.contains("TVSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "appletvsimulator" - if sdkroot.contains("TVOS.platform") || sdkroot.contains("MacOSX.platform") => {} - "iphoneos" - if sdkroot.contains("iPhoneSimulator.platform") - || sdkroot.contains("MacOSX.platform") => {} - "iphonesimulator" - if sdkroot.contains("iPhoneOS.platform") || sdkroot.contains("MacOSX.platform") => { - } - "macosx10.15" - if sdkroot.contains("iPhoneOS.platform") - || sdkroot.contains("iPhoneSimulator.platform") => {} - // Ignore `SDKROOT` if it's not a valid path. - _ if !p.is_absolute() || p == Path::new("/") || !p.exists() => {} - _ => return Ok(sdkroot), - } - } - let res = - Command::new("xcrun").arg("--show-sdk-path").arg("-sdk").arg(sdk_name).output().and_then( - |output| { - if output.status.success() { - Ok(String::from_utf8(output.stdout).unwrap()) - } else { - let error = String::from_utf8(output.stderr); - let error = format!("process exit with error: {}", error.unwrap()); - Err(io::Error::new(io::ErrorKind::Other, &error[..])) - } - }, - ); - - match res { - Ok(output) => Ok(output.trim().to_string()), - Err(e) => Err(format!("failed to get {} SDK path: {}", sdk_name, e)), - } -} - -fn build_pre_link_args(arch: Arch, os: AppleOS) -> Result { - let sdk_name = match (arch, os) { - (Arm64, AppleOS::tvOS) => "appletvos", - (X86_64, AppleOS::tvOS) => "appletvsimulator", - (Armv7, AppleOS::iOS) => "iphoneos", - (Armv7s, AppleOS::iOS) => "iphoneos", - (Arm64, AppleOS::iOS) => "iphoneos", - (I386, AppleOS::iOS) => "iphonesimulator", - (X86_64, AppleOS::iOS) => "iphonesimulator", - (X86_64_macabi, AppleOS::iOS) => "macosx10.15", - _ => unreachable!(), - }; - - let arch_name = arch.to_string(); - - let sdk_root = get_sdk_root(sdk_name)?; - - let mut args = LinkArgs::new(); - args.insert( - LinkerFlavor::Gcc, - vec![ - "-arch".to_string(), - arch_name.to_string(), - "-isysroot".to_string(), - sdk_root.clone(), - "-Wl,-syslibroot".to_string(), - sdk_root, - ], - ); - - Ok(args) -} - -fn target_cpu(arch: Arch) -> String { - match arch { - Armv7 => "cortex-a8", // iOS7 is supported on iPhone 4 and higher - Armv7s => "cortex-a9", - Arm64 => "apple-a7", - I386 => "yonah", - X86_64 => "core2", - X86_64_macabi => "core2", - } - .to_string() -} - -fn link_env_remove(arch: Arch) -> Vec { - match arch { - Armv7 | Armv7s | Arm64 | I386 | X86_64 => vec!["MACOSX_DEPLOYMENT_TARGET".to_string()], - X86_64_macabi => vec!["IPHONEOS_DEPLOYMENT_TARGET".to_string()], - } -} - -pub fn opts(arch: Arch, os: AppleOS) -> Result { - let pre_link_args = build_pre_link_args(arch, os)?; - Ok(TargetOptions { - cpu: target_cpu(arch), - executables: true, - pre_link_args, - link_env_remove: link_env_remove(arch), - has_elf_tls: false, - eliminate_frame_pointer: false, - ..super::apple_base::opts() - }) -} diff --git a/src/librustc_target/spec/avr_unknown_unknown.rs b/src/librustc_target/spec/avr_unknown_unknown.rs deleted file mode 100644 index f90a8def0a..0000000000 --- a/src/librustc_target/spec/avr_unknown_unknown.rs +++ /dev/null @@ -1,17 +0,0 @@ -use crate::spec::{LinkerFlavor, Target, TargetResult}; - -pub fn target() -> TargetResult { - Ok(Target { - llvm_target: "avr-unknown-unknown".to_string(), - target_endian: "little".to_string(), - target_pointer_width: "16".to_string(), - data_layout: "e-P1-p:16:8-i8:8-i16:8-i32:8-i64:8-f32:8-f64:8-n8-a:8".to_string(), - arch: "avr".to_string(), - linker_flavor: LinkerFlavor::Gcc, - target_os: "unknown".to_string(), - target_env: "".to_string(), - target_vendor: "unknown".to_string(), - target_c_int_width: 16.to_string(), - options: super::freestanding_base::opts(), - }) -} diff --git a/src/librustc_target/spec/freestanding_base.rs b/src/librustc_target/spec/freestanding_base.rs deleted file mode 100644 index c338856228..0000000000 --- a/src/librustc_target/spec/freestanding_base.rs +++ /dev/null @@ -1,31 +0,0 @@ -use crate::spec::{LinkArgs, LinkerFlavor, TargetOptions}; -use std::default::Default; - -pub fn opts() -> TargetOptions { - let mut args = LinkArgs::new(); - - args.insert( - LinkerFlavor::Gcc, - vec![ - // We want to be able to strip as much executable code as possible - // from the linker command line, and this flag indicates to the - // linker that it can avoid linking in dynamic libraries that don't - // actually satisfy any symbols up to that point (as with many other - // resolutions the linker does). This option only applies to all - // following libraries so we're sure to pass it as one of the first - // arguments. - "-Wl,--as-needed".to_string(), - ], - ); - - TargetOptions { - dynamic_linking: false, - executables: true, - linker_is_gnu: true, - has_rpath: false, - pre_link_args: args, - position_independent_executables: false, - eh_frame_header: false, - ..Default::default() - } -} diff --git a/src/librustc_trait_selection/Cargo.toml b/src/librustc_trait_selection/Cargo.toml deleted file mode 100644 index 444023baa6..0000000000 --- a/src/librustc_trait_selection/Cargo.toml +++ /dev/null @@ -1,27 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_trait_selection" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_trait_selection" -path = "lib.rs" -doctest = false - -[dependencies] -rustc_parse_format = { path = "../librustc_parse_format" } -tracing = "0.1" -rustc_attr = { path = "../librustc_attr" } -rustc_middle = { path = "../librustc_middle" } -rustc_ast = { path = "../librustc_ast" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_infer = { path = "../librustc_infer" } -rustc_macros = { path = "../librustc_macros" } -rustc_session = { path = "../librustc_session" } -rustc_span = { path = "../librustc_span" } -rustc_target = { path = "../librustc_target" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } diff --git a/src/librustc_trait_selection/traits/chalk_fulfill.rs b/src/librustc_trait_selection/traits/chalk_fulfill.rs deleted file mode 100644 index 0097097707..0000000000 --- a/src/librustc_trait_selection/traits/chalk_fulfill.rs +++ /dev/null @@ -1,267 +0,0 @@ -//! Defines a Chalk-based `TraitEngine` - -use crate::infer::canonical::OriginalQueryValues; -use crate::infer::InferCtxt; -use crate::traits::query::NoSolution; -use crate::traits::{ - ChalkEnvironmentAndGoal, ChalkEnvironmentClause, FulfillmentError, FulfillmentErrorCode, - ObligationCause, PredicateObligation, SelectionError, TraitEngine, -}; -use rustc_data_structures::fx::FxIndexSet; -use rustc_hir::def_id::DefId; -use rustc_middle::ty::{self, Ty, TyCtxt}; - -pub struct FulfillmentContext<'tcx> { - obligations: FxIndexSet>, -} - -impl FulfillmentContext<'tcx> { - crate fn new() -> Self { - FulfillmentContext { obligations: FxIndexSet::default() } - } -} - -fn environment<'tcx>( - tcx: TyCtxt<'tcx>, - def_id: DefId, -) -> &'tcx ty::List> { - use rustc_hir::{ForeignItemKind, ImplItemKind, ItemKind, Node, TraitItemKind}; - use rustc_middle::ty::subst::GenericArgKind; - - debug!("environment(def_id = {:?})", def_id); - - // The environment of an impl Trait type is its defining function's environment. - if let Some(parent) = ty::is_impl_trait_defn(tcx, def_id) { - return environment(tcx, parent); - } - - // Compute the bounds on `Self` and the type parameters. - let ty::InstantiatedPredicates { predicates, .. } = - tcx.predicates_of(def_id).instantiate_identity(tcx); - - let clauses = predicates.into_iter().map(ChalkEnvironmentClause::Predicate); - - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); - let node = tcx.hir().get(hir_id); - - enum NodeKind { - TraitImpl, - InherentImpl, - Fn, - Other, - }; - - let node_kind = match node { - Node::TraitItem(item) => match item.kind { - TraitItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::ImplItem(item) => match item.kind { - ImplItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::Item(item) => match item.kind { - ItemKind::Impl { of_trait: Some(_), .. } => NodeKind::TraitImpl, - ItemKind::Impl { of_trait: None, .. } => NodeKind::InherentImpl, - ItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - Node::ForeignItem(item) => match item.kind { - ForeignItemKind::Fn(..) => NodeKind::Fn, - _ => NodeKind::Other, - }, - - // FIXME: closures? - _ => NodeKind::Other, - }; - - // FIXME(eddyb) isn't the unordered nature of this a hazard? - let mut inputs = FxIndexSet::default(); - - match node_kind { - // In a trait impl, we assume that the header trait ref and all its - // constituents are well-formed. - NodeKind::TraitImpl => { - let trait_ref = tcx.impl_trait_ref(def_id).expect("not an impl"); - - // FIXME(chalk): this has problems because of late-bound regions - //inputs.extend(trait_ref.substs.iter().flat_map(|arg| arg.walk())); - inputs.extend(trait_ref.substs.iter()); - } - - // In an inherent impl, we assume that the receiver type and all its - // constituents are well-formed. - NodeKind::InherentImpl => { - let self_ty = tcx.type_of(def_id); - inputs.extend(self_ty.walk()); - } - - // In an fn, we assume that the arguments and all their constituents are - // well-formed. - NodeKind::Fn => { - let fn_sig = tcx.fn_sig(def_id); - let fn_sig = tcx.liberate_late_bound_regions(def_id, &fn_sig); - - inputs.extend(fn_sig.inputs().iter().flat_map(|ty| ty.walk())); - } - - NodeKind::Other => (), - } - let input_clauses = inputs.into_iter().filter_map(|arg| { - match arg.unpack() { - GenericArgKind::Type(ty) => Some(ChalkEnvironmentClause::TypeFromEnv(ty)), - - // FIXME(eddyb) no WF conditions from lifetimes? - GenericArgKind::Lifetime(_) => None, - - // FIXME(eddyb) support const generics in Chalk - GenericArgKind::Const(_) => None, - } - }); - - tcx.mk_chalk_environment_clause_list(clauses.chain(input_clauses)) -} - -/// We need to wrap a `ty::Predicate` in an elaborated environment *before* we -/// canonicalize. This is due to the fact that we insert extra clauses into the -/// environment for all input types (`FromEnv`). -fn in_environment( - infcx: &InferCtxt<'_, 'tcx>, - obligation: &PredicateObligation<'tcx>, -) -> ChalkEnvironmentAndGoal<'tcx> { - assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(obligation); - - let environment = match obligation.param_env.def_id { - Some(def_id) => environment(infcx.tcx, def_id), - None if obligation.param_env.caller_bounds().is_empty() => ty::List::empty(), - // FIXME(chalk): this is hit in ui/where-clauses/where-clause-constraints-are-local-for-trait-impl - // and ui/generics/generic-static-methods - //_ => bug!("non-empty `ParamEnv` with no def-id"), - _ => ty::List::empty(), - }; - - ChalkEnvironmentAndGoal { environment, goal: obligation.predicate } -} - -impl TraitEngine<'tcx> for FulfillmentContext<'tcx> { - fn normalize_projection_type( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - _param_env: ty::ParamEnv<'tcx>, - projection_ty: ty::ProjectionTy<'tcx>, - _cause: ObligationCause<'tcx>, - ) -> Ty<'tcx> { - infcx.tcx.mk_ty(ty::Projection(projection_ty)) - } - - fn register_predicate_obligation( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - obligation: PredicateObligation<'tcx>, - ) { - assert!(!infcx.is_in_snapshot()); - let obligation = infcx.resolve_vars_if_possible(&obligation); - - self.obligations.insert(obligation); - } - - fn select_all_or_error( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec>> { - self.select_where_possible(infcx)?; - - if self.obligations.is_empty() { - Ok(()) - } else { - let errors = self - .obligations - .iter() - .map(|obligation| FulfillmentError { - obligation: obligation.clone(), - code: FulfillmentErrorCode::CodeAmbiguity, - points_at_arg_span: false, - }) - .collect(); - Err(errors) - } - } - - fn select_where_possible( - &mut self, - infcx: &InferCtxt<'_, 'tcx>, - ) -> Result<(), Vec>> { - let mut errors = Vec::new(); - let mut next_round = FxIndexSet::default(); - let mut making_progress; - - loop { - making_progress = false; - - // We iterate over all obligations, and record if we are able - // to unambiguously prove at least one obligation. - for obligation in self.obligations.drain(..) { - let goal_in_environment = in_environment(infcx, &obligation); - let mut orig_values = OriginalQueryValues::default(); - let canonical_goal = - infcx.canonicalize_query(&goal_in_environment, &mut orig_values); - - match infcx.tcx.evaluate_goal(canonical_goal) { - Ok(response) => { - if response.is_proven() { - making_progress = true; - - match infcx.instantiate_query_response_and_region_obligations( - &obligation.cause, - obligation.param_env, - &orig_values, - &response, - ) { - Ok(infer_ok) => next_round.extend( - infer_ok.obligations.into_iter().map(|obligation| { - assert!(!infcx.is_in_snapshot()); - infcx.resolve_vars_if_possible(&obligation) - }), - ), - - Err(_err) => errors.push(FulfillmentError { - obligation, - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - points_at_arg_span: false, - }), - } - } else { - // Ambiguous: retry at next round. - next_round.insert(obligation); - } - } - - Err(NoSolution) => errors.push(FulfillmentError { - obligation, - code: FulfillmentErrorCode::CodeSelectionError( - SelectionError::Unimplemented, - ), - points_at_arg_span: false, - }), - } - } - next_round = std::mem::replace(&mut self.obligations, next_round); - - if !making_progress { - break; - } - } - - if errors.is_empty() { Ok(()) } else { Err(errors) } - } - - fn pending_obligations(&self) -> Vec> { - self.obligations.iter().cloned().collect() - } -} diff --git a/src/librustc_traits/Cargo.toml b/src/librustc_traits/Cargo.toml deleted file mode 100644 index f5545f5629..0000000000 --- a/src/librustc_traits/Cargo.toml +++ /dev/null @@ -1,23 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_traits" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_traits" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_hir = { path = "../librustc_hir" } -rustc_index = { path = "../librustc_index" } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -chalk-ir = "0.14.0" -chalk-solve = "0.14.0" -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_infer = { path = "../librustc_infer" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_traits/chalk/mod.rs b/src/librustc_traits/chalk/mod.rs deleted file mode 100644 index f18b4ca65f..0000000000 --- a/src/librustc_traits/chalk/mod.rs +++ /dev/null @@ -1,229 +0,0 @@ -//! Calls `chalk-solve` to solve a `ty::Predicate` -//! -//! In order to call `chalk-solve`, this file must convert a -//! `ChalkCanonicalGoal` into a Chalk ucanonical goal. It then calls Chalk, and -//! converts the answer back into rustc solution. - -crate mod db; -crate mod lowering; - -use rustc_data_structures::fx::FxHashMap; - -use rustc_index::vec::IndexVec; - -use rustc_middle::infer::canonical::{CanonicalTyVarKind, CanonicalVarKind}; -use rustc_middle::traits::ChalkRustInterner; -use rustc_middle::ty::query::Providers; -use rustc_middle::ty::subst::GenericArg; -use rustc_middle::ty::{ - self, Bound, BoundVar, ParamTy, Region, RegionKind, Ty, TyCtxt, TypeFoldable, -}; - -use rustc_infer::infer::canonical::{ - Canonical, CanonicalVarValues, Certainty, QueryRegionConstraints, QueryResponse, -}; -use rustc_infer::traits::{self, ChalkCanonicalGoal}; - -use crate::chalk::db::RustIrDatabase as ChalkRustIrDatabase; -use crate::chalk::lowering::{LowerInto, ParamsSubstitutor}; - -use chalk_solve::Solution; - -crate fn provide(p: &mut Providers) { - *p = Providers { evaluate_goal, ..*p }; -} - -crate fn evaluate_goal<'tcx>( - tcx: TyCtxt<'tcx>, - obligation: ChalkCanonicalGoal<'tcx>, -) -> Result<&'tcx Canonical<'tcx, QueryResponse<'tcx, ()>>, traits::query::NoSolution> { - let interner = ChalkRustInterner { tcx }; - - // Chalk doesn't have a notion of `Params`, so instead we use placeholders. - let mut params_substitutor = ParamsSubstitutor::new(tcx); - let obligation = obligation.fold_with(&mut params_substitutor); - let _params: FxHashMap = params_substitutor.params; - let max_universe = obligation.max_universe.index(); - - let _lowered_goal: chalk_ir::UCanonical< - chalk_ir::InEnvironment>>, - > = chalk_ir::UCanonical { - canonical: chalk_ir::Canonical { - binders: chalk_ir::CanonicalVarKinds::from( - &interner, - obligation.variables.iter().map(|v| match v.kind { - CanonicalVarKind::PlaceholderTy(_ty) => unimplemented!(), - CanonicalVarKind::PlaceholderRegion(_ui) => unimplemented!(), - CanonicalVarKind::Ty(ty) => match ty { - CanonicalTyVarKind::General(ui) => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyKind::General), - chalk_ir::UniverseIndex { counter: ui.index() }, - ), - CanonicalTyVarKind::Int => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Integer), - chalk_ir::UniverseIndex::root(), - ), - CanonicalTyVarKind::Float => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Ty(chalk_ir::TyKind::Float), - chalk_ir::UniverseIndex::root(), - ), - }, - CanonicalVarKind::Region(ui) => chalk_ir::WithKind::new( - chalk_ir::VariableKind::Lifetime, - chalk_ir::UniverseIndex { counter: ui.index() }, - ), - CanonicalVarKind::Const(_ui) => unimplemented!(), - CanonicalVarKind::PlaceholderConst(_pc) => unimplemented!(), - }), - ), - value: obligation.value.lower_into(&interner), - }, - universes: max_universe + 1, - }; - - let solver_choice = chalk_solve::SolverChoice::SLG { max_size: 32, expected_answers: None }; - let mut solver = solver_choice.into_solver::>(); - - let db = ChalkRustIrDatabase { tcx, interner }; - let solution = solver.solve(&db, &_lowered_goal); - - // Ideally, the code to convert *back* to rustc types would live close to - // the code to convert *from* rustc types. Right now though, we don't - // really need this and so it's really minimal. - // Right now, we also treat a `Unique` solution the same as - // `Ambig(Definite)`. This really isn't right. - let make_solution = |_subst: chalk_ir::Substitution<_>| { - let mut var_values: IndexVec> = IndexVec::new(); - _subst.parameters(&interner).iter().for_each(|p| { - // FIXME(chalk): we should move this elsewhere, since this is - // essentially inverse of lowering a `GenericArg`. - let _data = p.data(&interner); - match _data { - chalk_ir::GenericArgData::Ty(_t) => { - use chalk_ir::TyData; - use rustc_ast as ast; - - let _data = _t.data(&interner); - let kind = match _data { - TyData::Apply(_application_ty) => match _application_ty.name { - chalk_ir::TypeName::Adt(_struct_id) => unimplemented!(), - chalk_ir::TypeName::Scalar(scalar) => match scalar { - chalk_ir::Scalar::Bool => ty::Bool, - chalk_ir::Scalar::Char => ty::Char, - chalk_ir::Scalar::Int(int_ty) => match int_ty { - chalk_ir::IntTy::Isize => ty::Int(ast::IntTy::Isize), - chalk_ir::IntTy::I8 => ty::Int(ast::IntTy::I8), - chalk_ir::IntTy::I16 => ty::Int(ast::IntTy::I16), - chalk_ir::IntTy::I32 => ty::Int(ast::IntTy::I32), - chalk_ir::IntTy::I64 => ty::Int(ast::IntTy::I64), - chalk_ir::IntTy::I128 => ty::Int(ast::IntTy::I128), - }, - chalk_ir::Scalar::Uint(int_ty) => match int_ty { - chalk_ir::UintTy::Usize => ty::Uint(ast::UintTy::Usize), - chalk_ir::UintTy::U8 => ty::Uint(ast::UintTy::U8), - chalk_ir::UintTy::U16 => ty::Uint(ast::UintTy::U16), - chalk_ir::UintTy::U32 => ty::Uint(ast::UintTy::U32), - chalk_ir::UintTy::U64 => ty::Uint(ast::UintTy::U64), - chalk_ir::UintTy::U128 => ty::Uint(ast::UintTy::U128), - }, - chalk_ir::Scalar::Float(float_ty) => match float_ty { - chalk_ir::FloatTy::F32 => ty::Float(ast::FloatTy::F32), - chalk_ir::FloatTy::F64 => ty::Float(ast::FloatTy::F64), - }, - }, - chalk_ir::TypeName::Array => unimplemented!(), - chalk_ir::TypeName::FnDef(_) => unimplemented!(), - chalk_ir::TypeName::Closure(_) => unimplemented!(), - chalk_ir::TypeName::Never => unimplemented!(), - chalk_ir::TypeName::Tuple(_size) => unimplemented!(), - chalk_ir::TypeName::Slice => unimplemented!(), - chalk_ir::TypeName::Raw(_) => unimplemented!(), - chalk_ir::TypeName::Ref(_) => unimplemented!(), - chalk_ir::TypeName::Str => unimplemented!(), - chalk_ir::TypeName::OpaqueType(_ty) => unimplemented!(), - chalk_ir::TypeName::AssociatedType(_assoc_ty) => unimplemented!(), - chalk_ir::TypeName::Error => unimplemented!(), - }, - TyData::Placeholder(_placeholder) => { - unimplemented!(); - } - TyData::Alias(_alias_ty) => unimplemented!(), - TyData::Function(_quantified_ty) => unimplemented!(), - TyData::BoundVar(_bound) => Bound( - ty::DebruijnIndex::from_usize(_bound.debruijn.depth() as usize), - ty::BoundTy { - var: ty::BoundVar::from_usize(_bound.index), - kind: ty::BoundTyKind::Anon, - }, - ), - TyData::InferenceVar(_, _) => unimplemented!(), - TyData::Dyn(_) => unimplemented!(), - }; - let _ty: Ty<'_> = tcx.mk_ty(kind); - let _arg: GenericArg<'_> = _ty.into(); - var_values.push(_arg); - } - chalk_ir::GenericArgData::Lifetime(_l) => { - let _data = _l.data(&interner); - let _lifetime: Region<'_> = match _data { - chalk_ir::LifetimeData::BoundVar(_var) => { - tcx.mk_region(RegionKind::ReLateBound( - rustc_middle::ty::DebruijnIndex::from_usize( - _var.debruijn.depth() as usize - ), - rustc_middle::ty::BoundRegion::BrAnon(_var.index as u32), - )) - } - chalk_ir::LifetimeData::InferenceVar(_var) => unimplemented!(), - chalk_ir::LifetimeData::Placeholder(_index) => unimplemented!(), - chalk_ir::LifetimeData::Phantom(_, _) => unimplemented!(), - }; - let _arg: GenericArg<'_> = _lifetime.into(); - var_values.push(_arg); - } - chalk_ir::GenericArgData::Const(_) => unimplemented!(), - } - }); - let sol = Canonical { - max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables.clone(), - value: QueryResponse { - var_values: CanonicalVarValues { var_values }, - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Proven, - value: (), - }, - }; - &*tcx.arena.alloc(sol) - }; - solution - .map(|s| match s { - Solution::Unique(_subst) => { - // FIXME(chalk): handle constraints - make_solution(_subst.value.subst) - } - Solution::Ambig(_guidance) => { - match _guidance { - chalk_solve::Guidance::Definite(_subst) => make_solution(_subst.value), - chalk_solve::Guidance::Suggested(_) => unimplemented!(), - chalk_solve::Guidance::Unknown => { - // chalk_fulfill doesn't use the var_values here, so - // let's just ignore that - let sol = Canonical { - max_universe: ty::UniverseIndex::from_usize(0), - variables: obligation.variables.clone(), - value: QueryResponse { - var_values: CanonicalVarValues { var_values: IndexVec::new() } - .make_identity(tcx), - region_constraints: QueryRegionConstraints::default(), - certainty: Certainty::Ambiguous, - value: (), - }, - }; - &*tcx.arena.alloc(sol) - } - } - } - }) - .ok_or(traits::query::NoSolution) -} diff --git a/src/librustc_ty/Cargo.toml b/src/librustc_ty/Cargo.toml deleted file mode 100644 index adc9740c2c..0000000000 --- a/src/librustc_ty/Cargo.toml +++ /dev/null @@ -1,21 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_ty" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_ty" -path = "lib.rs" - -[dependencies] -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_infer = { path = "../librustc_infer" } -rustc_span = { path = "../librustc_span" } -rustc_session = { path = "../librustc_session" } -rustc_target = { path = "../librustc_target" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustc_typeck/Cargo.toml b/src/librustc_typeck/Cargo.toml deleted file mode 100644 index 82c6ac7a0c..0000000000 --- a/src/librustc_typeck/Cargo.toml +++ /dev/null @@ -1,29 +0,0 @@ -[package] -authors = ["The Rust Project Developers"] -name = "rustc_typeck" -version = "0.0.0" -edition = "2018" - -[lib] -name = "rustc_typeck" -path = "lib.rs" -test = false -doctest = false - -[dependencies] -rustc_arena = { path = "../librustc_arena" } -tracing = "0.1" -rustc_middle = { path = "../librustc_middle" } -rustc_attr = { path = "../librustc_attr" } -rustc_data_structures = { path = "../librustc_data_structures" } -rustc_errors = { path = "../librustc_errors" } -rustc_hir = { path = "../librustc_hir" } -rustc_hir_pretty = { path = "../librustc_hir_pretty" } -rustc_target = { path = "../librustc_target" } -rustc_session = { path = "../librustc_session" } -smallvec = { version = "1.0", features = ["union", "may_dangle"] } -rustc_ast = { path = "../librustc_ast" } -rustc_span = { path = "../librustc_span" } -rustc_index = { path = "../librustc_index" } -rustc_infer = { path = "../librustc_infer" } -rustc_trait_selection = { path = "../librustc_trait_selection" } diff --git a/src/librustdoc/Cargo.toml b/src/librustdoc/Cargo.toml index 1354ef5cbd..a40a44fe27 100644 --- a/src/librustdoc/Cargo.toml +++ b/src/librustdoc/Cargo.toml @@ -5,15 +5,17 @@ version = "0.0.0" edition = "2018" [lib] -name = "rustdoc" path = "lib.rs" [dependencies] -pulldown-cmark = { version = "0.7", default-features = false } +pulldown-cmark = { version = "0.8", default-features = false } minifier = "0.0.33" rayon = { version = "0.3.0", package = "rustc-rayon" } serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" smallvec = "1.0" tempfile = "3" -itertools = "0.8" +itertools = "0.9" + +[dev-dependencies] +expect-test = "1.0" diff --git a/src/librustdoc/clean/blanket_impl.rs b/src/librustdoc/clean/blanket_impl.rs index 3d2785541b..de5a9a6155 100644 --- a/src/librustdoc/clean/blanket_impl.rs +++ b/src/librustdoc/clean/blanket_impl.rs @@ -38,7 +38,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { ); let trait_ref = self.cx.tcx.impl_trait_ref(impl_def_id).unwrap(); let may_apply = self.cx.tcx.infer_ctxt().enter(|infcx| { - match trait_ref.self_ty().kind { + match trait_ref.self_ty().kind() { ty::Param(_) => {} _ => return false, } @@ -75,8 +75,7 @@ impl<'a, 'tcx> BlanketImplFinder<'a, 'tcx> { } }); debug!( - "get_blanket_impls: found applicable impl: {}\ - for trait_ref={:?}, ty={:?}", + "get_blanket_impls: found applicable impl: {} for trait_ref={:?}, ty={:?}", may_apply, trait_ref, ty ); if !may_apply { diff --git a/src/librustdoc/clean/cfg.rs b/src/librustdoc/clean/cfg.rs index ab0b332ee1..c039b18117 100644 --- a/src/librustdoc/clean/cfg.rs +++ b/src/librustdoc/clean/cfg.rs @@ -135,7 +135,7 @@ impl Cfg { /// Renders the configuration for human display, as a short HTML description. pub(crate) fn render_short_html(&self) -> String { - let mut msg = Html(self, true).to_string(); + let mut msg = Display(self, Format::ShortHtml).to_string(); if self.should_capitalize_first_letter() { if let Some(i) = msg.find(|c: char| c.is_ascii_alphanumeric()) { msg[i..i + 1].make_ascii_uppercase(); @@ -148,7 +148,11 @@ impl Cfg { pub(crate) fn render_long_html(&self) -> String { let on = if self.should_use_with_in_description() { "with" } else { "on" }; - let mut msg = format!("This is supported {} {}", on, Html(self, false)); + let mut msg = format!( + "This is supported {} {}", + on, + Display(self, Format::LongHtml) + ); if self.should_append_only_to_description() { msg.push_str(" only"); } @@ -156,6 +160,17 @@ impl Cfg { msg } + /// Renders the configuration for long display, as a long plain text description. + pub(crate) fn render_long_plain(&self) -> String { + let on = if self.should_use_with_in_description() { "with" } else { "on" }; + + let mut msg = format!("This is supported {} {}", on, Display(self, Format::LongPlain)); + if self.should_append_only_to_description() { + msg.push_str(" only"); + } + msg + } + fn should_capitalize_first_letter(&self) -> bool { match *self { Cfg::False | Cfg::True | Cfg::Not(..) => true, @@ -286,9 +301,31 @@ impl ops::BitOr for Cfg { } } -/// Pretty-print wrapper for a `Cfg`. Also indicates whether the "short-form" rendering should be -/// used. -struct Html<'a>(&'a Cfg, bool); +#[derive(Clone, Copy)] +enum Format { + LongHtml, + LongPlain, + ShortHtml, +} + +impl Format { + fn is_long(self) -> bool { + match self { + Format::LongHtml | Format::LongPlain => true, + Format::ShortHtml => false, + } + } + + fn is_html(self) -> bool { + match self { + Format::LongHtml | Format::ShortHtml => true, + Format::LongPlain => false, + } + } +} + +/// Pretty-print wrapper for a `Cfg`. Also indicates what form of rendering should be used. +struct Display<'a>(&'a Cfg, Format); fn write_with_opt_paren( fmt: &mut fmt::Formatter<'_>, @@ -305,7 +342,7 @@ fn write_with_opt_paren( Ok(()) } -impl<'a> fmt::Display for Html<'a> { +impl<'a> fmt::Display for Display<'a> { fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { match *self.0 { Cfg::Not(ref child) => match **child { @@ -314,31 +351,86 @@ impl<'a> fmt::Display for Html<'a> { if sub_cfgs.iter().all(Cfg::is_simple) { " nor " } else { ", nor " }; for (i, sub_cfg) in sub_cfgs.iter().enumerate() { fmt.write_str(if i == 0 { "neither " } else { separator })?; - write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?; + write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; } Ok(()) } - ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Html(simple, self.1)), - ref c => write!(fmt, "not ({})", Html(c, self.1)), + ref simple @ Cfg::Cfg(..) => write!(fmt, "non-{}", Display(simple, self.1)), + ref c => write!(fmt, "not ({})", Display(c, self.1)), }, Cfg::Any(ref sub_cfgs) => { let separator = if sub_cfgs.iter().all(Cfg::is_simple) { " or " } else { ", or " }; + + let short_longhand = self.1.is_long() && { + let all_crate_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); + let all_target_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); + + if all_crate_features { + fmt.write_str("crate features ")?; + true + } else if all_target_features { + fmt.write_str("target features ")?; + true + } else { + false + } + }; + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { if i != 0 { fmt.write_str(separator)?; } - write_with_opt_paren(fmt, !sub_cfg.is_all(), Html(sub_cfg, self.1))?; + if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { + if self.1.is_html() { + write!(fmt, "{}", feat)?; + } else { + write!(fmt, "`{}`", feat)?; + } + } else { + write_with_opt_paren(fmt, !sub_cfg.is_all(), Display(sub_cfg, self.1))?; + } } Ok(()) } Cfg::All(ref sub_cfgs) => { + let short_longhand = self.1.is_long() && { + let all_crate_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::feature, Some(_)))); + let all_target_features = sub_cfgs + .iter() + .all(|sub_cfg| matches!(sub_cfg, Cfg::Cfg(sym::target_feature, Some(_)))); + + if all_crate_features { + fmt.write_str("crate features ")?; + true + } else if all_target_features { + fmt.write_str("target features ")?; + true + } else { + false + } + }; + for (i, sub_cfg) in sub_cfgs.iter().enumerate() { if i != 0 { fmt.write_str(" and ")?; } - write_with_opt_paren(fmt, !sub_cfg.is_simple(), Html(sub_cfg, self.1))?; + if let (true, Cfg::Cfg(_, Some(feat))) = (short_longhand, sub_cfg) { + if self.1.is_html() { + write!(fmt, "{}", feat)?; + } else { + write!(fmt, "`{}`", feat)?; + } + } else { + write_with_opt_paren(fmt, !sub_cfg.is_simple(), Display(sub_cfg, self.1))?; + } } Ok(()) } @@ -406,26 +498,39 @@ impl<'a> fmt::Display for Html<'a> { }, (sym::target_endian, Some(endian)) => return write!(fmt, "{}-endian", endian), (sym::target_pointer_width, Some(bits)) => return write!(fmt, "{}-bit", bits), - (sym::target_feature, Some(feat)) => { - if self.1 { - return write!(fmt, "{}", feat); - } else { + (sym::target_feature, Some(feat)) => match self.1 { + Format::LongHtml => { return write!(fmt, "target feature {}", feat); } - } + Format::LongPlain => return write!(fmt, "target feature `{}`", feat), + Format::ShortHtml => return write!(fmt, "{}", feat), + }, + (sym::feature, Some(feat)) => match self.1 { + Format::LongHtml => { + return write!(fmt, "crate feature {}", feat); + } + Format::LongPlain => return write!(fmt, "crate feature `{}`", feat), + Format::ShortHtml => return write!(fmt, "{}", feat), + }, _ => "", }; if !human_readable.is_empty() { fmt.write_str(human_readable) } else if let Some(v) = value { - write!( - fmt, - "{}=\"{}\"", - Escape(&name.as_str()), - Escape(&v.as_str()) - ) - } else { + if self.1.is_html() { + write!( + fmt, + r#"{}="{}""#, + Escape(&name.as_str()), + Escape(&v.as_str()) + ) + } else { + write!(fmt, r#"`{}="{}"`"#, name, v) + } + } else if self.1.is_html() { write!(fmt, "{}", Escape(&name.as_str())) + } else { + write!(fmt, "`{}`", name) } } } diff --git a/src/librustdoc/clean/cfg/tests.rs b/src/librustdoc/clean/cfg/tests.rs index 96f0a1b7a7..794a7bcaf1 100644 --- a/src/librustdoc/clean/cfg/tests.rs +++ b/src/librustdoc/clean/cfg/tests.rs @@ -391,26 +391,25 @@ fn test_render_long_html() { (word_cfg("unix") & word_cfg("windows") & word_cfg("debug_assertions")) .render_long_html(), "This is supported on Unix and Windows and debug-assertions enabled\ - only." + only." ); assert_eq!( (word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions")) .render_long_html(), "This is supported on Unix or Windows or debug-assertions enabled\ - only." + only." ); assert_eq!( (!(word_cfg("unix") | word_cfg("windows") | word_cfg("debug_assertions"))) .render_long_html(), "This is supported on neither Unix nor Windows nor debug-assertions \ - enabled." + enabled." ); assert_eq!( ((word_cfg("unix") & name_value_cfg("target_arch", "x86_64")) | (word_cfg("windows") & name_value_cfg("target_pointer_width", "64"))) .render_long_html(), - "This is supported on Unix and x86-64, or Windows and 64-bit \ - only." + "This is supported on Unix and x86-64, or Windows and 64-bit only." ); assert_eq!( (!(word_cfg("unix") & word_cfg("windows"))).render_long_html(), @@ -420,7 +419,7 @@ fn test_render_long_html() { ((word_cfg("debug_assertions") | word_cfg("windows")) & word_cfg("unix")) .render_long_html(), "This is supported on (debug-assertions enabled or Windows) and Unix\ - only." + only." ); assert_eq!( name_value_cfg("target_feature", "sse2").render_long_html(), @@ -430,7 +429,7 @@ fn test_render_long_html() { (name_value_cfg("target_arch", "x86_64") & name_value_cfg("target_feature", "sse2")) .render_long_html(), "This is supported on x86-64 and target feature \ - sse2 only." + sse2 only." ); }) } diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f67b689bb0..31e8c32f06 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -306,15 +306,17 @@ fn merge_attrs( attrs: Attrs<'_>, other_attrs: Option>, ) -> clean::Attributes { - let mut merged_attrs: Vec = Vec::with_capacity(attrs.len()); - // If we have additional attributes (from a re-export), + // NOTE: If we have additional attributes (from a re-export), // always insert them first. This ensure that re-export // doc comments show up before the original doc comments // when we render them. - if let Some(a) = other_attrs { - merged_attrs.extend(a.iter().cloned()); - } - merged_attrs.extend(attrs.to_vec()); + let merged_attrs = if let Some(inner) = other_attrs { + let mut both = inner.to_vec(); + both.extend_from_slice(attrs); + both + } else { + attrs.to_vec() + }; merged_attrs.clean(cx) } @@ -350,14 +352,22 @@ pub fn build_impl( } } - let for_ = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { self_ty, .. } => self_ty.clean(cx), - _ => panic!("did given to build_impl was not an impl"), + let impl_item = match did.as_local() { + Some(did) => { + let hir_id = tcx.hir().local_def_id_to_hir_id(did); + match tcx.hir().expect_item(hir_id).kind { + hir::ItemKind::Impl { self_ty, ref generics, ref items, .. } => { + Some((self_ty, generics, items)) + } + _ => panic!("`DefID` passed to `build_impl` is not an `impl"), + } } - } else { - tcx.type_of(did).clean(cx) + None => None, + }; + + let for_ = match impl_item { + Some((self_ty, _, _)) => self_ty.clean(cx), + None => tcx.type_of(did).clean(cx), }; // Only inline impl if the implementing type is @@ -377,17 +387,12 @@ pub fn build_impl( } let predicates = tcx.explicit_predicates_of(did); - let (trait_items, generics) = if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); - match tcx.hir().expect_item(hir_id).kind { - hir::ItemKind::Impl { ref generics, ref items, .. } => ( - items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), - generics.clean(cx), - ), - _ => panic!("did given to build_impl was not an impl"), - } - } else { - ( + let (trait_items, generics) = match impl_item { + Some((_, generics, items)) => ( + items.iter().map(|item| tcx.hir().impl_item(item.id).clean(cx)).collect::>(), + generics.clean(cx), + ), + None => ( tcx.associated_items(did) .in_definition_order() .filter_map(|item| { @@ -399,7 +404,7 @@ pub fn build_impl( }) .collect::>(), clean::enter_impl_trait(cx, || (tcx.generics_of(did), predicates).clean(cx)), - ) + ), }; let polarity = tcx.impl_polarity(did); let trait_ = associated_trait.clean(cx).map(|bound| match bound { @@ -629,7 +634,9 @@ pub fn record_extern_trait(cx: &DocContext<'_>, did: DefId) { } } - cx.active_extern_traits.borrow_mut().insert(did); + { + cx.active_extern_traits.borrow_mut().insert(did); + } debug!("record_extern_trait: {:?}", did); let trait_ = build_external_trait(cx, did); diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 14e0fa7eab..788bb5e787 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -23,7 +23,7 @@ use rustc_middle::middle::stability; use rustc_middle::ty::fold::TypeFolder; use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::{self, AdtKind, Lift, Ty, TyCtxt}; -use rustc_mir::const_eval::is_min_const_fn; +use rustc_mir::const_eval::{is_const_fn, is_min_const_fn, is_unstable_const_fn}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::{kw, sym, Ident, Symbol}; use rustc_span::{self, Pos}; @@ -256,7 +256,7 @@ impl Clean for doctree::Module<'_> { // determine if we should display the inner contents or // the outer `mod` item for the source code. - let whence = { + let span = { let sm = cx.sess().source_map(); let outer = sm.lookup_char_pos(self.where_outer.lo()); let inner = sm.lookup_char_pos(self.where_inner.lo()); @@ -272,7 +272,7 @@ impl Clean for doctree::Module<'_> { Item { name: Some(name), attrs, - source: whence.clean(cx), + source: span.clean(cx), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -508,7 +508,8 @@ impl<'a> Clean> for ty::Predicate<'a> { | ty::PredicateAtom::ObjectSafe(..) | ty::PredicateAtom::ClosureKind(..) | ty::PredicateAtom::ConstEvaluatable(..) - | ty::PredicateAtom::ConstEquate(..) => panic!("not user writable"), + | ty::PredicateAtom::ConstEquate(..) + | ty::PredicateAtom::TypeWellFormedFromEnv(..) => panic!("not user writable"), } } } @@ -764,17 +765,17 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx let param_idx = (|| { match p.skip_binders() { ty::PredicateAtom::Trait(pred, _constness) => { - if let ty::Param(param) = pred.self_ty().kind { + if let ty::Param(param) = pred.self_ty().kind() { return Some(param.index); } } ty::PredicateAtom::TypeOutlives(ty::OutlivesPredicate(ty, _reg)) => { - if let ty::Param(param) = ty.kind { + if let ty::Param(param) = ty.kind() { return Some(param.index); } } ty::PredicateAtom::Projection(p) => { - if let ty::Param(param) = p.projection_ty.self_ty().kind { + if let ty::Param(param) = p.projection_ty.self_ty().kind() { projection = Some(ty::Binder::bind(p)); return Some(param.index); } @@ -839,7 +840,7 @@ impl<'a, 'tcx> Clean for (&'a ty::Generics, ty::GenericPredicates<'tcx let mut where_predicates = where_predicates.into_iter().flat_map(|p| p.clean(cx)).collect::>(); - // Type parameters and have a Sized bound by default unless removed with + // Type parameters have a Sized bound by default unless removed with // ?Sized. Scan through the predicates and mark any type parameter with // a Sized bound, removing the bounds as we find them. // @@ -900,7 +901,9 @@ impl Clean for doctree::Function<'_> { enter_impl_trait(cx, || (self.generics.clean(cx), (self.decl, self.body).clean(cx))); let did = cx.tcx.hir().local_def_id(self.id); - let constness = if is_min_const_fn(cx.tcx, did.to_def_id()) { + let constness = if is_const_fn(cx.tcx, did.to_def_id()) + && !is_unstable_const_fn(cx.tcx, did.to_def_id()).is_some() + { hir::Constness::Const } else { hir::Constness::NotConst @@ -909,7 +912,7 @@ impl Clean for doctree::Function<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -1017,7 +1020,7 @@ impl Clean for doctree::Trait<'_> { Item { name: Some(self.name.clean(cx)), attrs, - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1041,7 +1044,7 @@ impl Clean for doctree::TraitAlias<'_> { Item { name: Some(self.name.clean(cx)), attrs, - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1108,7 +1111,7 @@ impl Clean for hir::TraitItem<'_> { hir::TraitItemKind::Fn(ref sig, hir::TraitFn::Provided(body)) => { let mut m = (sig, &self.generics, body, None).clean(cx); if m.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } @@ -1121,7 +1124,7 @@ impl Clean for hir::TraitItem<'_> { let (all_types, ret_types) = get_all_types(&generics, &decl, cx); let mut t = TyMethod { header: sig.header, decl, generics, all_types, ret_types }; if t.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { t.header.constness = hir::Constness::NotConst; } @@ -1154,7 +1157,7 @@ impl Clean for hir::ImplItem<'_> { hir::ImplItemKind::Fn(ref sig, body) => { let mut m = (sig, &self.generics, body, Some(self.defaultness)).clean(cx); if m.header.constness == hir::Constness::Const - && !is_min_const_fn(cx.tcx, local_did.to_def_id()) + && is_unstable_const_fn(cx.tcx, local_did.to_def_id()).is_some() { m.header.constness = hir::Constness::NotConst; } @@ -1206,7 +1209,7 @@ impl Clean for ty::AssocItem { let self_arg_ty = sig.input(0).skip_binder(); if self_arg_ty == self_ty { decl.inputs.values[0].type_ = Generic(String::from("Self")); - } else if let ty::Ref(_, ty, _) = self_arg_ty.kind { + } else if let ty::Ref(_, ty, _) = *self_arg_ty.kind() { if ty == self_ty { match decl.inputs.values[0].type_ { BorrowedRef { ref mut type_, .. } => { @@ -1364,16 +1367,16 @@ impl Clean for hir::Ty<'_> { 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); - let length = match cx.tcx.const_eval_poly(def_id.to_def_id()) { - Ok(length) => { - print_const(cx, ty::Const::from_value(cx.tcx, length, cx.tcx.types.usize)) - } - Err(_) => cx - .sess() - .source_map() - .span_to_snippet(cx.tcx.def_span(def_id)) - .unwrap_or_else(|_| "_".to_string()), - }; + // NOTE(min_const_generics): We can't use `const_eval_poly` for constants + // as we currently do not supply the parent generics to anonymous constants + // but do allow `ConstKind::Param`. + // + // `const_eval_poly` tries to to first substitute generic parameters which + // results in an ICE while manually constructing the constant and using `eval` + // does nothing for `ConstKind::Param`. + 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 ty.clean(cx), length) } TyKind::Tup(ref tys) => Tuple(tys.clean(cx)), @@ -1511,7 +1514,7 @@ impl Clean for hir::Ty<'_> { TyKind::Path(hir::QPath::TypeRelative(ref qself, ref segment)) => { let mut res = Res::Err; let ty = hir_ty_to_ty(cx.tcx, self); - if let ty::Projection(proj) = ty.kind { + if let ty::Projection(proj) = ty.kind() { res = Res::Def(DefKind::Trait, proj.trait_ref(cx.tcx).def_id); } let trait_path = hir::Path { span: self.span, res, segments: &[] }; @@ -1554,7 +1557,7 @@ impl Clean for hir::Ty<'_> { impl<'tcx> Clean for Ty<'tcx> { fn clean(&self, cx: &DocContext<'_>) -> Type { debug!("cleaning type: {:?}", self); - match self.kind { + match *self.kind() { ty::Never => Never, ty::Bool => Primitive(PrimitiveType::Bool), ty::Char => Primitive(PrimitiveType::Char), @@ -1827,7 +1830,7 @@ impl Clean for doctree::Struct<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1847,7 +1850,7 @@ impl Clean for doctree::Union<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1877,7 +1880,7 @@ impl Clean for doctree::Enum<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -1896,7 +1899,7 @@ impl Clean for doctree::Variant<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Inherited, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), @@ -2044,7 +2047,7 @@ impl Clean for doctree::Typedef<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2059,7 +2062,7 @@ impl Clean for doctree::OpaqueTy<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2090,7 +2093,7 @@ impl Clean for doctree::Static<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2111,7 +2114,7 @@ impl Clean for doctree::Constant<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2165,7 +2168,7 @@ impl Clean> for doctree::Impl<'_> { let make_item = |trait_: Option, for_: Type, items: Vec| Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: def_id.to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2216,7 +2219,7 @@ impl Clean> for doctree::ExternCrate<'_> { vec![Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: DefId { krate: self.cnum, index: CRATE_DEF_INDEX }, visibility: self.vis.clean(cx), stability: None, @@ -2281,7 +2284,7 @@ impl Clean> for doctree::Import<'_> { vec![Item { name: None, attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: DefId::local(CRATE_DEF_INDEX), visibility: self.vis.clean(cx), stability: None, @@ -2323,7 +2326,7 @@ impl Clean for doctree::ForeignItem<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), def_id: cx.tcx.hir().local_def_id(self.id).to_def_id(), visibility: self.vis.clean(cx), stability: cx.stability(self.id).clean(cx), @@ -2339,7 +2342,7 @@ impl Clean for doctree::Macro<'_> { Item { name: Some(name.clone()), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Public, stability: cx.stability(self.hid).clean(cx), deprecation: cx.deprecation(self.hid).clean(cx), @@ -2364,7 +2367,7 @@ impl Clean for doctree::ProcMacro<'_> { Item { name: Some(self.name.clean(cx)), attrs: self.attrs.clean(cx), - source: self.whence.clean(cx), + source: self.span.clean(cx), visibility: Public, stability: cx.stability(self.id).clean(cx), deprecation: cx.deprecation(self.id).clean(cx), diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index a458cdab30..8fbfb04bac 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -118,7 +118,7 @@ impl Item { self.attrs.collapsed_doc_value() } - pub fn links(&self) -> Vec<(String, String)> { + pub fn links(&self) -> Vec { self.attrs.links(&self.def_id.krate) } @@ -425,10 +425,38 @@ pub struct Attributes { pub cfg: Option>, pub span: Option, /// map from Rust paths to resolved defs and potential URL fragments - pub links: Vec<(String, Option, Option)>, + pub links: Vec, pub inner_docs: bool, } +#[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 [`Attributes::links`] +pub struct ItemLink { + /// The original link written in the markdown + pub(crate) link: String, + /// The link text displayed in the HTML. + /// + /// 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, + /// The url fragment to append to the link + pub(crate) fragment: Option, +} + +pub struct RenderedLink { + /// The text the link was original written as. + /// + /// This could potentially include disambiguators and backticks. + pub(crate) original_text: String, + /// The text to display in the HTML + pub(crate) new_text: String, + /// The URL to put in the `href` + pub(crate) href: String, +} + impl Attributes { /// Extracts the content from an attribute `#[doc(cfg(content))]`. pub fn extract_cfg(mi: &ast::MetaItem) -> Option<&ast::MetaItem> { @@ -605,21 +633,25 @@ impl Attributes { /// Gets links as a vector /// /// Cache must be populated before call - pub fn links(&self, krate: &CrateNum) -> Vec<(String, String)> { + pub fn links(&self, krate: &CrateNum) -> Vec { use crate::html::format::href; use crate::html::render::CURRENT_DEPTH; self.links .iter() - .filter_map(|&(ref s, did, ref fragment)| { - match did { + .filter_map(|ItemLink { link: s, link_text, did, fragment }| { + match *did { Some(did) => { if let Some((mut href, ..)) = href(did) { if let Some(ref fragment) = *fragment { href.push_str("#"); href.push_str(fragment); } - Some((s.clone(), href)) + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href, + }) } else { None } @@ -639,16 +671,17 @@ impl Attributes { }; // This is a primitive so the url is done "by hand". let tail = fragment.find('#').unwrap_or_else(|| fragment.len()); - Some(( - s.clone(), - format!( + Some(RenderedLink { + original_text: s.clone(), + new_text: link_text.clone(), + href: format!( "{}{}std/primitive.{}.html{}", url, if !url.ends_with('/') { "/" } else { "" }, &fragment[..tail], &fragment[tail..] ), - )) + }) } else { panic!("This isn't a primitive?!"); } @@ -662,7 +695,7 @@ impl Attributes { self.other_attrs .lists(sym::doc) .filter(|a| a.has_name(sym::alias)) - .filter_map(|a| a.value_str().map(|s| s.to_string().replace("\"", ""))) + .filter_map(|a| a.value_str().map(|s| s.to_string())) .filter(|v| !v.is_empty()) .collect::>() } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index 75fdcd5ec1..58b76d24a5 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -130,7 +130,7 @@ pub fn external_generic_args( None } GenericArgKind::Type(ty) => { - ty_kind = Some(&ty.kind); + ty_kind = Some(ty.kind()); Some(GenericArg::Type(ty.clean(cx))) } GenericArgKind::Const(ct) => Some(GenericArg::Const(ct.clean(cx))), @@ -422,14 +422,13 @@ pub fn name_from_pat(p: &hir::Pat<'_>) -> String { PatKind::Ref(ref p, _) => name_from_pat(&**p), PatKind::Lit(..) => { warn!( - "tried to get argument name from PatKind::Lit, \ - which is silly in function arguments" + "tried to get argument name from PatKind::Lit, which is silly in function arguments" ); "()".to_string() } PatKind::Range(..) => panic!( "tried to get argument name from PatKind::Range, \ - which is not allowed in function arguments" + which is not allowed in function arguments" ), PatKind::Slice(ref begin, ref mid, ref end) => { let begin = begin.iter().map(|p| name_from_pat(&**p)); @@ -473,7 +472,7 @@ pub fn print_const(cx: &DocContext<'_>, n: &'tcx ty::Const<'_>) -> String { pub fn print_evaluated_const(cx: &DocContext<'_>, def_id: DefId) -> Option { cx.tcx.const_eval_poly(def_id).ok().and_then(|val| { let ty = cx.tcx.type_of(def_id); - match (val, &ty.kind) { + match (val, ty.kind()) { (_, &ty::Ref(..)) => None, (ConstValue::Scalar(_), &ty::Adt(_, _)) => None, (ConstValue::Scalar(_), _) => { @@ -498,7 +497,7 @@ fn format_integer_with_underscore_sep(num: &str) -> String { fn print_const_with_custom_print_scalar(cx: &DocContext<'_>, ct: &'tcx ty::Const<'tcx>) -> String { // Use a slightly different format for integer types which always shows the actual value. // For all other types, fallback to the original `pretty_print_const`. - match (ct.val, &ct.ty.kind) { + match (ct.val, ct.ty.kind()) { (ty::ConstKind::Value(ConstValue::Scalar(Scalar::Raw { data, .. })), ty::Uint(ui)) => { format!("{}{}", format_integer_with_underscore_sep(&data.to_string()), ui.name_str()) } @@ -602,7 +601,7 @@ pub fn register_res(cx: &DocContext<'_>, res: Res) -> DefId { }, Res::Def(DefKind::TraitAlias, i) => (i, TypeKind::TraitAlias), Res::SelfTy(Some(def_id), _) => (def_id, TypeKind::Trait), - Res::SelfTy(_, Some(impl_def_id)) => return impl_def_id, + Res::SelfTy(_, Some((impl_def_id, _))) => return impl_def_id, _ => return res.def_id(), }; if did.is_local() { diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 4f751decc8..a5fc075781 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -83,9 +83,9 @@ pub struct Options { /// Codegen options strings to hand to the compiler. pub codegen_options_strs: Vec, /// Debugging (`-Z`) options to pass to the compiler. - pub debugging_options: DebuggingOptions, + pub debugging_opts: DebuggingOptions, /// Debugging (`-Z`) options strings to pass to the compiler. - pub debugging_options_strs: Vec, + pub debugging_opts_strs: Vec, /// The target used to compile the crate against. pub target: TargetTriple, /// Edition used when reading the crate. Defaults to "2015". Also used by default when @@ -318,9 +318,9 @@ impl Options { let error_format = config::parse_error_format(&matches, color, json_rendered); let codegen_options = build_codegen_options(matches, error_format); - let debugging_options = build_debugging_options(matches, error_format); + let debugging_opts = build_debugging_options(matches, error_format); - let diag = new_handler(error_format, None, &debugging_options); + let diag = new_handler(error_format, None, &debugging_opts); // check for deprecated options check_deprecated_options(&matches, &diag); @@ -365,7 +365,7 @@ impl Options { .iter() .map(|s| SearchPath::from_cli_opt(s, error_format)) .collect(); - let externs = parse_externs(&matches, &debugging_options, error_format); + let externs = parse_externs(&matches, &debugging_opts, error_format); let extern_html_root_urls = match parse_extern_html_roots(&matches) { Ok(ex) => ex, Err(err) => { @@ -416,14 +416,12 @@ impl Options { return Err(1); } else if !ret.is_empty() { diag.struct_warn(&format!( - "theme file \"{}\" is missing CSS rules from the \ - default theme", + "theme file \"{}\" is missing CSS rules from the default theme", theme_s )) .warn("the theme may appear incorrect when loaded") .help(&format!( - "to see what rules are missing, call `rustdoc \ - --check-theme \"{}\"`", + "to see what rules are missing, call `rustdoc --check-theme \"{}\"`", theme_s )) .emit(); @@ -546,7 +544,7 @@ impl Options { let persist_doctests = matches.opt_str("persist-doctests").map(PathBuf::from); let test_builder = matches.opt_str("test-builder").map(PathBuf::from); let codegen_options_strs = matches.opt_strs("C"); - let debugging_options_strs = matches.opt_strs("Z"); + let debugging_opts_strs = matches.opt_strs("Z"); let lib_strs = matches.opt_strs("L"); let extern_strs = matches.opt_strs("extern"); let runtool = matches.opt_str("runtool"); @@ -569,8 +567,8 @@ impl Options { cfgs, codegen_options, codegen_options_strs, - debugging_options, - debugging_options_strs, + debugging_opts, + debugging_opts_strs, target, edition, maybe_sysroot, diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 7a0cf3717c..391859050e 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -234,7 +234,7 @@ pub fn new_handler( /// It returns a tuple containing: /// * Vector of tuples of lints' name and their associated "max" level /// * HashMap of lint id with their associated "max" level -pub fn init_lints( +pub(crate) fn init_lints( mut allowed_lints: Vec, lint_opts: Vec<(String, lint::Level)>, filter_call: F, @@ -257,7 +257,7 @@ where .filter_map(|lint| { // Permit feature-gated lints to avoid feature errors when trying to // allow all lints. - if lint.name == warnings_lint_name || lint.feature_gate.is_some() { + if lint.feature_gate.is_some() || allowed_lints.iter().any(|l| lint.name == l) { None } else { filter_call(lint) @@ -294,7 +294,7 @@ pub fn run_core( externs, mut cfgs, codegen_options, - debugging_options, + debugging_opts, target, edition, maybe_sysroot, @@ -328,19 +328,23 @@ pub fn run_core( let private_doc_tests = rustc_lint::builtin::PRIVATE_DOC_TESTS.name; let no_crate_level_docs = rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS.name; let invalid_codeblock_attributes_name = rustc_lint::builtin::INVALID_CODEBLOCK_ATTRIBUTES.name; + let renamed_and_removed_lints = rustc_lint::builtin::RENAMED_AND_REMOVED_LINTS.name; + let unknown_lints = rustc_lint::builtin::UNKNOWN_LINTS.name; // In addition to those specific lints, we also need to allow those given through // command line, otherwise they'll get ignored and we don't want that. - let allowed_lints = vec![ + let lints_to_show = vec![ intra_link_resolution_failure_name.to_owned(), missing_docs.to_owned(), missing_doc_example.to_owned(), private_doc_tests.to_owned(), no_crate_level_docs.to_owned(), invalid_codeblock_attributes_name.to_owned(), + renamed_and_removed_lints.to_owned(), + unknown_lints.to_owned(), ]; - let (lint_opts, lint_caps) = init_lints(allowed_lints, lint_opts, |lint| { + let (lint_opts, lint_caps) = init_lints(lints_to_show, lint_opts, |lint| { if lint.name == intra_link_resolution_failure_name || lint.name == invalid_codeblock_attributes_name { @@ -358,13 +362,13 @@ pub fn run_core( search_paths: libs, crate_types, lint_opts: if !display_warnings { lint_opts } else { vec![] }, - lint_cap: Some(lint_cap.unwrap_or_else(|| lint::Forbid)), + lint_cap, cg: codegen_options, externs, target_triple: target, unstable_features: UnstableFeatures::from_environment(), actually_rustdoc: true, - debugging_opts: debugging_options, + debugging_opts, error_format, edition, describe_lints, @@ -415,6 +419,7 @@ pub fn run_core( (rustc_interface::DEFAULT_QUERY_PROVIDERS.typeck)(tcx, def_id) }; }), + make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), }; @@ -435,6 +440,7 @@ pub fn run_core( resolver.borrow_mut().access(|resolver| { sess.time("load_extern_crates", || { for extern_name in &extern_names { + debug!("loading extern crate {}", extern_name); resolver .resolve_str_path_error( DUMMY_SP, @@ -556,8 +562,7 @@ fn run_global_ctxt( if let Some(ref m) = krate.module { if let None | Some("") = m.doc_value() { let help = "The following guide may be of use:\n\ - https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation\ - .html"; + https://doc.rust-lang.org/nightly/rustdoc/how-to-write-documentation.html"; tcx.struct_lint_node( rustc_lint::builtin::MISSING_CRATE_LEVEL_DOCS, ctxt.as_local_hir_id(m.def_id).unwrap(), @@ -576,7 +581,7 @@ fn run_global_ctxt( .struct_warn(&format!("the `#![doc({})]` attribute is considered deprecated", name)); msg.warn( "see issue #44136 \ - for more information", + for more information", ); if name == "no_default_passes" { @@ -609,7 +614,7 @@ fn run_global_ctxt( report_deprecated_attr("plugins = \"...\"", diag); eprintln!( "WARNING: `#![doc(plugins = \"...\")]` \ - no longer functions; see CVE-2018-1000622" + no longer functions; see CVE-2018-1000622" ); continue; } diff --git a/src/librustdoc/test.rs b/src/librustdoc/doctest.rs similarity index 99% rename from src/librustdoc/test.rs rename to src/librustdoc/doctest.rs index 693d5b9fb0..7a6c9eabb5 100644 --- a/src/librustdoc/test.rs +++ b/src/librustdoc/doctest.rs @@ -95,6 +95,7 @@ pub fn run(options: Options) -> Result<(), ErrorReported> { lint_caps, register_lints: None, override_queries: None, + make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), }; @@ -281,7 +282,7 @@ fn run_test( for codegen_options_str in &options.codegen_options_strs { compiler.arg("-C").arg(&codegen_options_str); } - for debugging_option_str in &options.debugging_options_strs { + for debugging_option_str in &options.debugging_opts_strs { compiler.arg("-Z").arg(&debugging_option_str); } if no_run && !compile_fail { diff --git a/src/librustdoc/test/tests.rs b/src/librustdoc/doctest/tests.rs similarity index 100% rename from src/librustdoc/test/tests.rs rename to src/librustdoc/doctest/tests.rs diff --git a/src/librustdoc/doctree.rs b/src/librustdoc/doctree.rs index 98125adbde..cfa51dcf4f 100644 --- a/src/librustdoc/doctree.rs +++ b/src/librustdoc/doctree.rs @@ -89,7 +89,7 @@ pub struct Struct<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField<'hir>], - pub whence: Span, + pub span: Span, } pub struct Union<'hir> { @@ -100,7 +100,7 @@ pub struct Union<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub fields: &'hir [hir::StructField<'hir>], - pub whence: Span, + pub span: Span, } pub struct Enum<'hir> { @@ -109,7 +109,7 @@ pub struct Enum<'hir> { pub generics: &'hir hir::Generics<'hir>, pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub name: Symbol, } @@ -118,7 +118,7 @@ pub struct Variant<'hir> { pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], pub def: &'hir hir::VariantData<'hir>, - pub whence: Span, + pub span: Span, } pub struct Function<'hir> { @@ -128,7 +128,7 @@ pub struct Function<'hir> { pub name: Symbol, pub vis: &'hir hir::Visibility<'hir>, pub header: hir::FnHeader, - pub whence: Span, + pub span: Span, pub generics: &'hir hir::Generics<'hir>, pub body: hir::BodyId, } @@ -139,7 +139,7 @@ pub struct Typedef<'hir> { pub name: Symbol, pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -148,7 +148,7 @@ pub struct OpaqueTy<'hir> { pub name: Symbol, pub id: hir::HirId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -161,7 +161,7 @@ pub struct Static<'hir> { pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, - pub whence: Span, + pub span: Span, } pub struct Constant<'hir> { @@ -171,7 +171,7 @@ pub struct Constant<'hir> { pub attrs: &'hir [ast::Attribute], pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, - pub whence: Span, + pub span: Span, } pub struct Trait<'hir> { @@ -183,7 +183,7 @@ pub struct Trait<'hir> { pub bounds: &'hir [hir::GenericBound<'hir>], pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -193,7 +193,7 @@ pub struct TraitAlias<'hir> { pub bounds: &'hir [hir::GenericBound<'hir>], pub attrs: &'hir [ast::Attribute], pub id: hir::HirId, - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, } @@ -208,7 +208,7 @@ pub struct Impl<'hir> { pub for_: &'hir hir::Ty<'hir>, pub items: Vec<&'hir hir::ImplItem<'hir>>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub vis: &'hir hir::Visibility<'hir>, pub id: hir::HirId, } @@ -219,7 +219,7 @@ pub struct ForeignItem<'hir> { pub name: Symbol, pub kind: &'hir hir::ForeignItemKind<'hir>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } // For Macro we store the DefId instead of the NodeId, since we also create @@ -229,7 +229,7 @@ pub struct Macro<'hir> { pub hid: hir::HirId, pub def_id: hir::def_id::DefId, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, pub matchers: Vec, pub imported_from: Option, } @@ -240,7 +240,7 @@ pub struct ExternCrate<'hir> { pub path: Option, pub vis: &'hir hir::Visibility<'hir>, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } pub struct Import<'hir> { @@ -250,7 +250,7 @@ pub struct Import<'hir> { pub attrs: &'hir [ast::Attribute], pub path: &'hir hir::Path<'hir>, pub glob: bool, - pub whence: Span, + pub span: Span, } pub struct ProcMacro<'hir> { @@ -259,7 +259,7 @@ pub struct ProcMacro<'hir> { pub kind: MacroKind, pub helpers: Vec, pub attrs: &'hir [ast::Attribute], - pub whence: Span, + pub span: Span, } pub fn struct_type_from_def(vdata: &hir::VariantData<'_>) -> StructType { diff --git a/src/librustdoc/fold.rs b/src/librustdoc/fold.rs index 0a85cb1d5a..d4ada3278e 100644 --- a/src/librustdoc/fold.rs +++ b/src/librustdoc/fold.rs @@ -93,15 +93,11 @@ pub trait DocFolder: Sized { c.module = c.module.take().and_then(|module| self.fold_item(module)); { - let mut guard = c.external_traits.borrow_mut(); - let external_traits = std::mem::replace(&mut *guard, Default::default()); - *guard = external_traits - .into_iter() - .map(|(k, mut v)| { - v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); - (k, v) - }) - .collect(); + let external_traits = { std::mem::take(&mut *c.external_traits.borrow_mut()) }; + for (k, mut v) in external_traits { + v.items = v.items.into_iter().filter_map(|i| self.fold_item(i)).collect(); + c.external_traits.borrow_mut().insert(k, v); + } } c } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 99b31473f8..b99321e848 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -16,7 +16,7 @@ use crate::formats::item_type::ItemType; use crate::formats::Impl; use crate::html::render::cache::{extern_location, get_index_search_type, ExternalLocation}; use crate::html::render::IndexItem; -use crate::html::render::{plain_summary_line, shorten}; +use crate::html::render::{plain_text_summary, shorten}; thread_local!(crate static CACHE_KEY: RefCell> = Default::default()); @@ -313,7 +313,7 @@ impl DocFolder for Cache { ty: item.type_(), name: s.to_string(), path: path.join("::"), - desc: shorten(plain_summary_line(item.doc_value())), + desc: shorten(plain_text_summary(item.doc_value())), parent, parent_idx: None, search_type: get_index_search_type(&item), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 699f8c36cb..2da9c68b19 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -833,7 +833,7 @@ fn fmt_type(t: &clean::Type, f: &mut fmt::Formatter<'_>, use_absolute: bool) -> write!( f, "
{name}", + title=\"type {path}::{name}\">{name}", url = url, shortty = ItemType::AssocType, name = name, diff --git a/src/librustdoc/html/highlight.rs b/src/librustdoc/html/highlight.rs index d4302d0cb5..4769edc50f 100644 --- a/src/librustdoc/html/highlight.rs +++ b/src/librustdoc/html/highlight.rs @@ -7,18 +7,12 @@ use crate::html::escape::Escape; -use std::fmt::Display; -use std::io; -use std::io::prelude::*; +use std::fmt::{Display, Write}; +use std::iter::Peekable; -use rustc_ast::token::{self, Token}; -use rustc_data_structures::sync::Lrc; -use rustc_parse::lexer; -use rustc_session::parse::ParseSess; -use rustc_span::hygiene::SyntaxContext; -use rustc_span::source_map::SourceMap; -use rustc_span::symbol::{kw, sym}; -use rustc_span::{BytePos, FileName, SourceFile, Span}; +use rustc_lexer::{LiteralKind, TokenKind}; +use rustc_span::symbol::Ident; +use rustc_span::with_default_session_globals; /// Highlights `src`, returning the HTML output. pub fn render_with_highlighting( @@ -28,71 +22,41 @@ pub fn render_with_highlighting( tooltip: Option<(&str, &str)>, ) -> String { debug!("highlighting: ================\n{}\n==============", src); - let mut out = Vec::new(); + let mut out = String::with_capacity(src.len()); if let Some((tooltip, class)) = tooltip { write!( out, "
{}
", + class='tooltiptext'>{}

`]: ../pin/struct.Pin.html -/// [`pin module`]: ../../std/pin/index.html +/// [`mem::replace`]: crate::mem::replace +/// [Pin]: crate::pin::Pin +/// [`pin` module]: crate::pin #[stable(feature = "pin", since = "1.33.0")] #[rustc_on_unimplemented( on(_Self = "std::future::Future", note = "consider using `Box::pin`",), diff --git a/library/core/src/mem/manually_drop.rs b/library/core/src/mem/manually_drop.rs index e45aa86c07..d86939454b 100644 --- a/library/core/src/mem/manually_drop.rs +++ b/library/core/src/mem/manually_drop.rs @@ -15,50 +15,33 @@ use crate::ptr; /// be exposed through a public safe API. /// Correspondingly, `ManuallyDrop::drop` is unsafe. /// -/// # Examples +/// # `ManuallyDrop` and drop order. /// -/// This wrapper can be used to enforce a particular drop order on fields, regardless -/// of how they are defined in the struct: +/// Rust has a well-defined [drop order] of values. To make sure that fields or +/// locals are dropped in a specific order, reorder the declarations such that +/// the implicit drop order is the correct one. /// -/// ```rust -/// use std::mem::ManuallyDrop; -/// struct Peach; -/// struct Banana; -/// struct Melon; -/// struct FruitBox { -/// // Immediately clear there’s something non-trivial going on with these fields. -/// peach: ManuallyDrop, -/// melon: Melon, // Field that’s independent of the other two. -/// banana: ManuallyDrop, -/// } +/// It is possible to use `ManuallyDrop` to control the drop order, but this +/// requires unsafe code and is hard to do correctly in the presence of +/// unwinding. /// -/// impl Drop for FruitBox { -/// fn drop(&mut self) { -/// unsafe { -/// // Explicit ordering in which field destructors are run specified in the intuitive -/// // location – the destructor of the structure containing the fields. -/// // Moreover, one can now reorder fields within the struct however much they want. -/// ManuallyDrop::drop(&mut self.peach); -/// ManuallyDrop::drop(&mut self.banana); -/// } -/// // After destructor for `FruitBox` runs (this function), the destructor for Melon gets -/// // invoked in the usual manner, as it is not wrapped in `ManuallyDrop`. -/// } +/// For example, if you want to make sure that a specific field is dropped after +/// the others, make it the last field of a struct: +/// +/// ``` +/// struct Context; +/// +/// struct Widget { +/// children: Vec, +/// // `context` will be dropped after `children`. +/// // Rust guarantees that fields are dropped in the order of declaration. +/// context: Context, /// } /// ``` /// -/// However, care should be taken when using this pattern as it can lead to *leak amplification*. -/// In this example, if the `Drop` implementation for `Peach` were to panic, the `banana` field -/// would also be leaked. -/// -/// In contrast, the automatically-generated compiler drop implementation would have ensured -/// that all fields are dropped even in the presence of panics. This is especially important when -/// working with [pinned] data, where reusing the memory without calling the destructor could lead -/// to Undefined Behaviour. -/// +/// [drop order]: https://doc.rust-lang.org/reference/destructors.html /// [`mem::zeroed`]: crate::mem::zeroed /// [`MaybeUninit`]: crate::mem::MaybeUninit -/// [pinned]: crate::pin #[stable(feature = "manually_drop", since = "1.20.0")] #[lang = "manually_drop"] #[derive(Copy, Clone, Debug, Default, PartialEq, Eq, PartialOrd, Ord, Hash)] @@ -74,8 +57,12 @@ impl ManuallyDrop { /// /// ```rust /// use std::mem::ManuallyDrop; - /// ManuallyDrop::new(Box::new(())); + /// let mut x = ManuallyDrop::new(String::from("Hello World!")); + /// x.truncate(5); // You can still safely operate on the value + /// assert_eq!(*x, "Hello"); + /// // But `Drop` will not be run here /// ``` + #[must_use = "if you don't need the wrapper, you can use `mem::forget` instead"] #[stable(feature = "manually_drop", since = "1.20.0")] #[rustc_const_stable(feature = "const_manually_drop", since = "1.36.0")] #[inline(always)] diff --git a/library/core/src/mem/maybe_uninit.rs b/library/core/src/mem/maybe_uninit.rs index d2d65fd2fa..e629d28eae 100644 --- a/library/core/src/mem/maybe_uninit.rs +++ b/library/core/src/mem/maybe_uninit.rs @@ -2,8 +2,7 @@ use crate::any::type_name; use crate::fmt; use crate::intrinsics; use crate::mem::ManuallyDrop; - -// ignore-tidy-undocumented-unsafe +use crate::ptr; /// A wrapper type to construct uninitialized instances of `T`. /// @@ -281,7 +280,7 @@ impl MaybeUninit { /// # Examples /// /// ```no_run - /// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice_assume_init)] + /// #![feature(maybe_uninit_uninit_array, maybe_uninit_extra, maybe_uninit_slice)] /// /// use std::mem::MaybeUninit; /// @@ -293,7 +292,7 @@ impl MaybeUninit { /// fn read(buf: &mut [MaybeUninit]) -> &[u8] { /// unsafe { /// let len = read_into_buffer(buf.as_mut_ptr() as *mut u8, buf.len()); - /// MaybeUninit::slice_get_ref(&buf[..len]) + /// MaybeUninit::slice_assume_init_ref(&buf[..len]) /// } /// } /// @@ -303,17 +302,10 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_uninit_array", issue = "none")] #[inline(always)] pub fn uninit_array() -> [Self; LEN] { + // SAFETY: An uninitialized `[MaybeUninit<_>; LEN]` is valid. unsafe { MaybeUninit::<[MaybeUninit; LEN]>::uninit().assume_init() } } - /// A promotable constant, equivalent to `uninit()`. - #[unstable( - feature = "internal_uninit_const", - issue = "none", - reason = "hack to work around promotability" - )] - pub const UNINIT: Self = Self::uninit(); - /// Creates a new `MaybeUninit` in an uninitialized state, with the memory being /// filled with `0` bytes. It depends on `T` whether that already makes for /// proper initialization. For example, `MaybeUninit::zeroed()` is initialized, @@ -354,6 +346,7 @@ impl MaybeUninit { #[rustc_diagnostic_item = "maybe_uninit_zeroed"] pub fn zeroed() -> MaybeUninit { let mut u = MaybeUninit::::uninit(); + // SAFETY: `u.as_mut_ptr()` points to allocated memory. unsafe { u.as_mut_ptr().write_bytes(0u8, 1); } @@ -367,10 +360,9 @@ impl MaybeUninit { #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] pub fn write(&mut self, val: T) -> &mut T { - unsafe { - self.value = ManuallyDrop::new(val); - self.get_mut() - } + *self = MaybeUninit::new(val); + // SAFETY: We just initialized this value. + unsafe { self.assume_init_mut() } } /// Gets a pointer to the contained value. Reading from this pointer or turning it @@ -472,6 +464,8 @@ impl MaybeUninit { /// *immediate* undefined behavior, but will cause undefined behavior with most /// safe operations (including dropping it). /// + /// [`Vec`]: ../../std/vec/struct.Vec.html + /// /// # Examples /// /// Correct usage of this method: @@ -520,8 +514,8 @@ impl MaybeUninit { /// this initialization invariant. /// /// Moreover, this leaves a copy of the same data behind in the `MaybeUninit`. When using - /// multiple copies of the data (by calling `read` multiple times, or first - /// calling `read` and then [`assume_init`]), it is your responsibility + /// multiple copies of the data (by calling `assume_init_read` multiple times, or first + /// calling `assume_init_read` and then [`assume_init`]), it is your responsibility /// to ensure that that data may indeed be duplicated. /// /// [inv]: #initialization-invariant @@ -537,16 +531,16 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::::uninit(); /// x.write(13); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // `u32` is `Copy`, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(None); - /// let x1 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; /// // Duplicating a `None` value is okay, so we may read multiple times. - /// let x2 = unsafe { x.read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// assert_eq!(x1, x2); /// ``` /// @@ -558,14 +552,14 @@ impl MaybeUninit { /// /// let mut x = MaybeUninit::>>::uninit(); /// x.write(Some(vec![0,1,2])); - /// let x1 = unsafe { x.read() }; - /// let x2 = unsafe { x.read() }; + /// let x1 = unsafe { x.assume_init_read() }; + /// let x2 = unsafe { x.assume_init_read() }; /// // We now created two copies of the same vector, leading to a double-free ⚠️ when /// // they both get dropped! /// ``` #[unstable(feature = "maybe_uninit_extra", issue = "63567")] #[inline(always)] - pub unsafe fn read(&self) -> T { + pub unsafe fn assume_init_read(&self) -> T { // SAFETY: the caller must guarantee that `self` is initialized. // Reading from `self.as_ptr()` is safe since `self` should be initialized. unsafe { @@ -574,6 +568,34 @@ impl MaybeUninit { } } + /// Drops the contained value in place. + /// + /// If you have ownership of the `MaybeUninit`, you can use [`assume_init`] instead. + /// + /// # Safety + /// + /// It is up to the caller to guarantee that the `MaybeUninit` really is + /// in an initialized state. Calling this when the content is not yet fully + /// initialized causes undefined behavior. + /// + /// On top of that, all additional invariants of the type `T` must be + /// satisfied, as the `Drop` implementation of `T` (or its members) may + /// rely on this. For example, a `1`-initialized [`Vec`] is considered + /// initialized (under the current implementation; this does not constitute + /// a stable guarantee) because the only requirement the compiler knows + /// about it is that the data pointer must be non-null. Dropping such a + /// `Vec` however will cause undefined behaviour. + /// + /// [`assume_init`]: MaybeUninit::assume_init + /// [`Vec`]: ../../std/vec/struct.Vec.html + #[unstable(feature = "maybe_uninit_extra", issue = "63567")] + pub unsafe fn assume_init_drop(&mut self) { + // SAFETY: the caller must guarantee that `self` is initialized and + // satisfies all invariants of `T`. + // Dropping the value in place is safe if that is the case. + unsafe { ptr::drop_in_place(self.as_mut_ptr()) } + } + /// Gets a shared reference to the contained value. /// /// This can be useful when we want to access a `MaybeUninit` that has been @@ -600,8 +622,8 @@ impl MaybeUninit { /// // Now that our `MaybeUninit<_>` is known to be initialized, it is okay to /// // create a shared reference to it: /// let x: &Vec = unsafe { - /// // Safety: `x` has been initialized. - /// x.get_ref() + /// // SAFETY: `x` has been initialized. + /// x.assume_init_ref() /// }; /// assert_eq!(x, &vec![1, 2, 3]); /// ``` @@ -613,7 +635,7 @@ impl MaybeUninit { /// use std::mem::MaybeUninit; /// /// let x = MaybeUninit::>::uninit(); - /// let x_vec: &Vec = unsafe { x.get_ref() }; + /// let x_vec: &Vec = unsafe { x.assume_init_ref() }; /// // We have created a reference to an uninitialized vector! This is undefined behavior. ⚠️ /// ``` /// @@ -624,14 +646,14 @@ impl MaybeUninit { /// let b = MaybeUninit::>::uninit(); /// // Initialize the `MaybeUninit` using `Cell::set`: /// unsafe { - /// b.get_ref().set(true); - /// // ^^^^^^^^^^^ - /// // Reference to an uninitialized `Cell`: UB! + /// b.assume_init_ref().set(true); + /// // ^^^^^^^^^^^^^^^ + /// // Reference to an uninitialized `Cell`: UB! /// } /// ``` #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] - pub unsafe fn get_ref(&self) -> &T { + pub unsafe fn assume_init_ref(&self) -> &T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { @@ -650,7 +672,7 @@ impl MaybeUninit { /// /// Calling this when the content is not yet fully initialized causes undefined /// behavior: it is up to the caller to guarantee that the `MaybeUninit` really - /// is in an initialized state. For instance, `.get_mut()` cannot be used to + /// is in an initialized state. For instance, `.assume_init_mut()` cannot be used to /// initialize a `MaybeUninit`. /// /// # Examples @@ -677,8 +699,8 @@ impl MaybeUninit { /// // To assert our buffer has been initialized without copying it, we upgrade /// // the `&mut MaybeUninit<[u8; 2048]>` to a `&mut [u8; 2048]`: /// let buf: &mut [u8; 2048] = unsafe { - /// // Safety: `buf` has been initialized. - /// buf.get_mut() + /// // SAFETY: `buf` has been initialized. + /// buf.assume_init_mut() /// }; /// /// // Now we can use `buf` as a normal slice: @@ -691,7 +713,7 @@ impl MaybeUninit { /// /// ### *Incorrect* usages of this method: /// - /// You cannot use `.get_mut()` to initialize a value: + /// You cannot use `.assume_init_mut()` to initialize a value: /// /// ```rust,no_run /// #![feature(maybe_uninit_ref)] @@ -699,7 +721,7 @@ impl MaybeUninit { /// /// let mut b = MaybeUninit::::uninit(); /// unsafe { - /// *b.get_mut() = true; + /// *b.assume_init_mut() = true; /// // We have created a (mutable) reference to an uninitialized `bool`! /// // This is undefined behavior. ⚠️ /// } @@ -716,8 +738,8 @@ impl MaybeUninit { /// fn read_chunk (reader: &'_ mut dyn io::Read) -> io::Result<[u8; 64]> /// { /// let mut buffer = MaybeUninit::<[u8; 64]>::uninit(); - /// reader.read_exact(unsafe { buffer.get_mut() })?; - /// // ^^^^^^^^^^^^^^^^ + /// reader.read_exact(unsafe { buffer.assume_init_mut() })?; + /// // ^^^^^^^^^^^^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! /// // This is undefined behavior. /// Ok(unsafe { buffer.assume_init() }) @@ -737,23 +759,23 @@ impl MaybeUninit { /// /// let foo: Foo = unsafe { /// let mut foo = MaybeUninit::::uninit(); - /// ptr::write(&mut foo.get_mut().a as *mut u32, 1337); - /// // ^^^^^^^^^^^^^ + /// ptr::write(&mut foo.assume_init_mut().a as *mut u32, 1337); + /// // ^^^^^^^^^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! /// // This is undefined behavior. - /// ptr::write(&mut foo.get_mut().b as *mut u8, 42); - /// // ^^^^^^^^^^^^^ + /// ptr::write(&mut foo.assume_init_mut().b as *mut u8, 42); + /// // ^^^^^^^^^^^^^^^^^^^^^ /// // (mutable) reference to uninitialized memory! /// // This is undefined behavior. /// foo.assume_init() /// }; /// ``` - // FIXME(#53491): We currently rely on the above being incorrect, i.e., we have references + // FIXME(#76092): We currently rely on the above being incorrect, i.e., we have references // to uninitialized data (e.g., in `libcore/fmt/float.rs`). We should make // a final decision about the rules before stabilization. #[unstable(feature = "maybe_uninit_ref", issue = "63568")] #[inline(always)] - pub unsafe fn get_mut(&mut self) -> &mut T { + pub unsafe fn assume_init_mut(&mut self) -> &mut T { // SAFETY: the caller must guarantee that `self` is initialized. // This also means that `self` must be a `value` variant. unsafe { @@ -769,9 +791,13 @@ impl MaybeUninit { /// It is up to the caller to guarantee that the `MaybeUninit` elements /// really are in an initialized state. /// Calling this when the content is not yet fully initialized causes undefined behavior. - #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")] + /// + /// See [`assume_init_ref`] for more details and examples. + /// + /// [`assume_init_ref`]: MaybeUninit::assume_init_ref + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub unsafe fn slice_get_ref(slice: &[Self]) -> &[T] { + pub unsafe fn slice_assume_init_ref(slice: &[Self]) -> &[T] { // SAFETY: casting slice to a `*const [T]` is safe since the caller guarantees that // `slice` is initialized, and`MaybeUninit` is guaranteed to have the same layout as `T`. // The pointer obtained is valid since it refers to memory owned by `slice` which is a @@ -786,9 +812,13 @@ impl MaybeUninit { /// It is up to the caller to guarantee that the `MaybeUninit` elements /// really are in an initialized state. /// Calling this when the content is not yet fully initialized causes undefined behavior. - #[unstable(feature = "maybe_uninit_slice_assume_init", issue = "none")] + /// + /// See [`assume_init_mut`] for more details and examples. + /// + /// [`assume_init_mut`]: MaybeUninit::assume_init_mut + #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub unsafe fn slice_get_mut(slice: &mut [Self]) -> &mut [T] { + pub unsafe fn slice_assume_init_mut(slice: &mut [Self]) -> &mut [T] { // SAFETY: similar to safety notes for `slice_get_ref`, but we have a // mutable reference which is also guaranteed to be valid for writes. unsafe { &mut *(slice as *mut [Self] as *mut [T]) } @@ -797,14 +827,14 @@ impl MaybeUninit { /// Gets a pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn first_ptr(this: &[MaybeUninit]) -> *const T { + pub fn slice_as_ptr(this: &[MaybeUninit]) -> *const T { this as *const [MaybeUninit] as *const T } /// Gets a mutable pointer to the first element of the array. #[unstable(feature = "maybe_uninit_slice", issue = "63569")] #[inline(always)] - pub fn first_ptr_mut(this: &mut [MaybeUninit]) -> *mut T { + pub fn slice_as_mut_ptr(this: &mut [MaybeUninit]) -> *mut T { this as *mut [MaybeUninit] as *mut T } } diff --git a/library/core/src/mem/mod.rs b/library/core/src/mem/mod.rs index 9107c570a8..aa1b5529df 100644 --- a/library/core/src/mem/mod.rs +++ b/library/core/src/mem/mod.rs @@ -31,10 +31,10 @@ pub use crate::intrinsics::transmute; /// forever in an unreachable state. However, it does not guarantee that pointers /// to this memory will remain valid. /// -/// * If you want to leak memory, see [`Box::leak`][leak]. -/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`][into_raw]. +/// * If you want to leak memory, see [`Box::leak`]. +/// * If you want to obtain a raw pointer to the memory, see [`Box::into_raw`]. /// * If you want to dispose of a value properly, running its destructor, see -/// [`mem::drop`][drop]. +/// [`mem::drop`]. /// /// # Safety /// @@ -132,28 +132,22 @@ pub use crate::intrinsics::transmute; /// ownership to `s` — the final step of interacting with `v` to dispose of it without /// running its destructor is entirely avoided. /// -/// [drop]: fn.drop.html -/// [uninit]: fn.uninitialized.html -/// [clone]: ../clone/trait.Clone.html -/// [swap]: fn.swap.html -/// [box]: ../../std/boxed/struct.Box.html -/// [leak]: ../../std/boxed/struct.Box.html#method.leak -/// [into_raw]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`Box`]: ../../std/boxed/struct.Box.html +/// [`Box::leak`]: ../../std/boxed/struct.Box.html#method.leak +/// [`Box::into_raw`]: ../../std/boxed/struct.Box.html#method.into_raw +/// [`mem::drop`]: drop /// [ub]: ../../reference/behavior-considered-undefined.html -/// [`ManuallyDrop`]: struct.ManuallyDrop.html #[inline] #[rustc_const_stable(feature = "const_forget", since = "1.46.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn forget(t: T) { - ManuallyDrop::new(t); + let _ = ManuallyDrop::new(t); } /// Like [`forget`], but also accepts unsized values. /// /// This function is just a shim intended to be removed when the `unsized_locals` feature gets /// stabilized. -/// -/// [`forget`]: fn.forget.html #[inline] #[unstable(feature = "forget_unsized", issue = "none")] pub fn forget_unsized(t: T) { @@ -301,7 +295,7 @@ pub fn forget_unsized(t: T) { /// assert_eq!(2, mem::size_of::()); /// ``` /// -/// [alignment]: ./fn.align_of.html +/// [alignment]: align_of #[inline(always)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_promotable] @@ -365,7 +359,6 @@ pub const fn size_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`size_of_val`]: ../../core/mem/fn.size_of_val.html /// /// # Examples /// @@ -501,7 +494,6 @@ pub const fn align_of_val(val: &T) -> usize { /// [slice]: ../../std/primitive.slice.html /// [trait object]: ../../book/ch17-02-trait-objects.html /// [extern type]: ../../unstable-book/language-features/extern-types.html -/// [`align_of_val`]: ../../core/mem/fn.align_of_val.html /// /// # Examples /// @@ -540,7 +532,7 @@ pub unsafe fn align_of_val_raw(val: *const T) -> usize { /// `needs_drop` explicitly. Types like [`HashMap`], on the other hand, have to drop /// values one at a time and should use this API. /// -/// [`drop_in_place`]: ../ptr/fn.drop_in_place.html +/// [`drop_in_place`]: crate::ptr::drop_in_place /// [`HashMap`]: ../../std/collections/struct.HashMap.html /// /// # Examples @@ -595,9 +587,9 @@ pub const fn needs_drop() -> bool { /// This has the same effect as [`MaybeUninit::zeroed().assume_init()`][zeroed]. /// It is useful for FFI sometimes, but should generally be avoided. /// -/// [zeroed]: union.MaybeUninit.html#method.zeroed +/// [zeroed]: MaybeUninit::zeroed /// [ub]: ../../reference/behavior-considered-undefined.html -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [inv]: MaybeUninit#initialization-invariant /// /// # Examples /// @@ -650,10 +642,10 @@ pub unsafe fn zeroed() -> T { /// (Notice that the rules around uninitialized integers are not finalized yet, but /// until they are, it is advisable to avoid them.) /// -/// [`MaybeUninit`]: union.MaybeUninit.html -/// [uninit]: union.MaybeUninit.html#method.uninit -/// [assume_init]: union.MaybeUninit.html#method.assume_init -/// [inv]: union.MaybeUninit.html#initialization-invariant +/// [`MaybeUninit`]: MaybeUninit +/// [uninit]: MaybeUninit::uninit +/// [assume_init]: MaybeUninit::assume_init +/// [inv]: MaybeUninit#initialization-invariant #[inline(always)] #[rustc_deprecated(since = "1.39.0", reason = "use `mem::MaybeUninit` instead")] #[stable(feature = "rust1", since = "1.0.0")] @@ -686,9 +678,6 @@ pub unsafe fn uninitialized() -> T { /// assert_eq!(42, x); /// assert_eq!(5, y); /// ``` -/// -/// [`replace`]: fn.replace.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn swap(x: &mut T, y: &mut T) { @@ -754,10 +743,6 @@ pub fn swap(x: &mut T, y: &mut T) { /// assert_eq!(buffer.get_and_reset(), vec![0, 1]); /// assert_eq!(buffer.buf.len(), 0); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`replace`]: fn.replace.html -/// [`swap`]: fn.swap.html #[inline] #[stable(feature = "mem_take", since = "1.40.0")] pub fn take(dest: &mut T) -> T { @@ -822,10 +807,6 @@ pub fn take(dest: &mut T) -> T { /// assert_eq!(buffer.replace_index(0, 2), 0); /// assert_eq!(buffer.buf[0], 2); /// ``` -/// -/// [`Clone`]: ../../std/clone/trait.Clone.html -/// [`swap`]: fn.swap.html -/// [`take`]: fn.take.html #[inline] #[stable(feature = "rust1", since = "1.0.0")] #[must_use = "if you don't need the old value, you can just assign the new value directly"] @@ -851,7 +832,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// Because `_x` is moved into the function, it is automatically dropped before /// the function returns. /// -/// [drop]: ../ops/trait.Drop.html +/// [drop]: Drop /// /// # Examples /// @@ -894,8 +875,7 @@ pub fn replace(dest: &mut T, mut src: T) -> T { /// println!("x: {}, y: {}", x, y.0); // still available /// ``` /// -/// [`RefCell`]: ../../std/cell/struct.RefCell.html -/// [`Copy`]: ../../std/marker/trait.Copy.html +/// [`RefCell`]: crate::cell::RefCell #[inline] #[stable(feature = "rust1", since = "1.0.0")] pub fn drop(_x: T) {} @@ -914,7 +894,6 @@ pub fn drop(_x: T) {} /// `T`. /// /// [ub]: ../../reference/behavior-considered-undefined.html -/// [size_of]: fn.size_of.html /// /// # Examples /// @@ -960,8 +939,6 @@ pub unsafe fn transmute_copy(src: &T) -> U { /// Opaque type representing the discriminant of an enum. /// /// See the [`discriminant`] function in this module for more information. -/// -/// [`discriminant`]: fn.discriminant.html #[stable(feature = "discriminant_value", since = "1.21.0")] pub struct Discriminant(::Discriminant); diff --git a/library/core/src/num/bignum.rs b/library/core/src/num/bignum.rs index 6f16b93d04..6a1a1e1976 100644 --- a/library/core/src/num/bignum.rs +++ b/library/core/src/num/bignum.rs @@ -20,7 +20,6 @@ #![macro_use] use crate::intrinsics; -use crate::mem; /// Arithmetic operations required by bignums. pub trait FullOps: Sized { @@ -58,25 +57,22 @@ macro_rules! impl_full_ops { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. // FIXME: will LLVM optimize this into ADC or similar? - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_mul_add(self, other: $ty, other2: $ty, carry: $ty) -> ($ty, $ty) { // This cannot overflow; // the output is between `0` and `2^nbits * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; let v = (self as $bigty) * (other as $bigty) + (other2 as $bigty) + (carry as $bigty); - ((v >> nbits) as $ty, v as $ty) + ((v >> <$ty>::BITS) as $ty, v as $ty) } fn full_div_rem(self, other: $ty, borrow: $ty) -> ($ty, $ty) { debug_assert!(borrow < other); // This cannot overflow; the output is between `0` and `other * (2^nbits - 1)`. - let nbits = mem::size_of::<$ty>() * 8; - let lhs = ((borrow as $bigty) << nbits) | (self as $bigty); + let lhs = ((borrow as $bigty) << <$ty>::BITS) | (self as $bigty); let rhs = other as $bigty; ((lhs / rhs) as $ty, (lhs % rhs) as $ty) } @@ -128,13 +124,11 @@ macro_rules! define_bignum { /// Makes a bignum from `u64` value. pub fn from_u64(mut v: u64) -> $name { - use crate::mem; - let mut base = [0; $n]; let mut sz = 0; while v > 0 { base[sz] = v as $ty; - v >>= mem::size_of::<$ty>() * 8; + v >>= <$ty>::BITS; sz += 1; } $name { size: sz, base: base } @@ -150,9 +144,7 @@ macro_rules! define_bignum { /// Returns the `i`-th bit where bit 0 is the least significant one. /// In other words, the bit with weight `2^i`. pub fn get_bit(&self, i: usize) -> u8 { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let d = i / digitbits; let b = i % digitbits; ((self.base[d] >> b) & 1) as u8 @@ -166,8 +158,6 @@ macro_rules! define_bignum { /// Returns the number of bits necessary to represent this value. Note that zero /// is considered to need 0 bits. pub fn bit_length(&self) -> usize { - use crate::mem; - // Skip over the most significant digits which are zero. let digits = self.digits(); let zeros = digits.iter().rev().take_while(|&&x| x == 0).count(); @@ -180,7 +170,7 @@ macro_rules! define_bignum { } // This could be optimized with leading_zeros() and bit shifts, but that's // probably not worth the hassle. - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let mut i = nonzero.len() * digitbits - 1; while self.get_bit(i) == 0 { i -= 1; @@ -265,9 +255,7 @@ macro_rules! define_bignum { /// Multiplies itself by `2^bits` and returns its own mutable reference. pub fn mul_pow2(&mut self, bits: usize) -> &mut $name { - use crate::mem; - - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; let digits = bits / digitbits; let bits = bits % digitbits; @@ -393,13 +381,11 @@ macro_rules! define_bignum { /// Divide self by another bignum, overwriting `q` with the quotient and `r` with the /// remainder. pub fn div_rem(&self, d: &$name, q: &mut $name, r: &mut $name) { - use crate::mem; - // Stupid slow base-2 long division taken from // https://en.wikipedia.org/wiki/Division_algorithm // FIXME use a greater base ($ty) for the long division. assert!(!d.is_zero()); - let digitbits = mem::size_of::<$ty>() * 8; + let digitbits = <$ty>::BITS as usize; for digit in &mut q.base[..] { *digit = 0; } @@ -462,10 +448,8 @@ macro_rules! define_bignum { impl crate::fmt::Debug for $name { fn fmt(&self, f: &mut crate::fmt::Formatter<'_>) -> crate::fmt::Result { - use crate::mem; - let sz = if self.size < 1 { 1 } else { self.size }; - let digitlen = mem::size_of::<$ty>() * 2; + let digitlen = <$ty>::BITS as usize / 4; write!(f, "{:#x}", self.base[sz - 1])?; for &v in self.base[..sz - 1].iter().rev() { diff --git a/library/core/src/num/dec2flt/algorithm.rs b/library/core/src/num/dec2flt/algorithm.rs index aaeb4d8a22..a5fbdc6ee2 100644 --- a/library/core/src/num/dec2flt/algorithm.rs +++ b/library/core/src/num/dec2flt/algorithm.rs @@ -60,12 +60,19 @@ mod fpu_precision { fn set_cw(cw: u16) { // SAFETY: the `fldcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fldcw $0" :: "m" (cw) :: "volatile") } + unsafe { + asm!( + "fldcw ({})", + in(reg) &cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } } /// Sets the precision field of the FPU to `T` and returns a `FPUControlWord`. pub fn set_precision() -> FPUControlWord { - let cw = 0u16; + let mut cw = 0_u16; // Compute the value for the Precision Control field that is appropriate for `T`. let cw_precision = match size_of::() { @@ -78,7 +85,14 @@ mod fpu_precision { // `FPUControlWord` structure is dropped // SAFETY: the `fnstcw` instruction has been audited to be able to work correctly with // any `u16` - unsafe { llvm_asm!("fnstcw $0" : "=*m" (&cw) ::: "volatile") } + unsafe { + asm!( + "fnstcw ({})", + in(reg) &mut cw, + // FIXME: We are using ATT syntax to support LLVM 8 and LLVM 9. + options(att_syntax, nostack), + ) + } // Set the control word to the desired precision. This is achieved by masking away the old // precision (bits 8 and 9, 0x300) and replacing it with the precision flag computed above. diff --git a/library/core/src/num/dec2flt/mod.rs b/library/core/src/num/dec2flt/mod.rs index c83c6b0ecc..6f3a3a8674 100644 --- a/library/core/src/num/dec2flt/mod.rs +++ b/library/core/src/num/dec2flt/mod.rs @@ -167,9 +167,15 @@ from_str_float_impl!(f64); /// This error is used as the error type for the [`FromStr`] implementation /// for [`f32`] and [`f64`]. /// -/// [`FromStr`]: ../str/trait.FromStr.html -/// [`f32`]: ../../std/primitive.f32.html -/// [`f64`]: ../../std/primitive.f64.html +/// # Example +/// +/// ``` +/// use std::str::FromStr; +/// +/// if let Err(e) = f64::from_str("a.12") { +/// println!("Failed conversion to f64: {}", e); +/// } +/// ``` #[derive(Debug, Clone, PartialEq, Eq)] #[stable(feature = "rust1", since = "1.0.0")] pub struct ParseFloatError { diff --git a/library/core/src/num/error.rs b/library/core/src/num/error.rs new file mode 100644 index 0000000000..aab1715518 --- /dev/null +++ b/library/core/src/num/error.rs @@ -0,0 +1,151 @@ +//! Error types for conversion to integral types. + +use crate::convert::Infallible; +use crate::fmt; + +/// The error type returned when a checked integral type conversion fails. +#[stable(feature = "try_from", since = "1.34.0")] +#[derive(Debug, Copy, Clone, PartialEq, Eq)] +pub struct TryFromIntError(pub(crate) ()); + +impl TryFromIntError { + #[unstable( + feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "none" + )] + #[doc(hidden)] + pub fn __description(&self) -> &str { + "out of range integral type conversion attempted" + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl fmt::Display for TryFromIntError { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + self.__description().fmt(fmt) + } +} + +#[stable(feature = "try_from", since = "1.34.0")] +impl From for TryFromIntError { + fn from(x: Infallible) -> TryFromIntError { + match x {} + } +} + +#[unstable(feature = "never_type", issue = "35121")] +impl From for TryFromIntError { + fn from(never: !) -> TryFromIntError { + // Match rather than coerce to make sure that code like + // `From for TryFromIntError` above will keep working + // when `Infallible` becomes an alias to `!`. + match never {} + } +} + +/// An error which can be returned when parsing an integer. +/// +/// This error is used as the error type for the `from_str_radix()` functions +/// on the primitive integer types, such as [`i8::from_str_radix`]. +/// +/// # Potential causes +/// +/// Among other causes, `ParseIntError` can be thrown because of leading or trailing whitespace +/// in the string e.g., when it is obtained from the standard input. +/// Using the [`str.trim()`] method ensures that no whitespace remains before parsing. +/// +/// [`str.trim()`]: ../../std/primitive.str.html#method.trim +/// [`i8::from_str_radix`]: ../../std/primitive.i8.html#method.from_str_radix +/// +/// # Example +/// +/// ``` +/// if let Err(e) = i32::from_str_radix("a12", 10) { +/// println!("Failed conversion to i32: {}", e); +/// } +/// ``` +#[derive(Debug, Clone, PartialEq, Eq)] +#[stable(feature = "rust1", since = "1.0.0")] +pub struct ParseIntError { + pub(super) kind: IntErrorKind, +} + +/// Enum to store the various types of errors that can cause parsing an integer to fail. +/// +/// # Example +/// +/// ``` +/// #![feature(int_error_matching)] +/// +/// # fn main() { +/// if let Err(e) = i32::from_str_radix("a12", 10) { +/// println!("Failed conversion to i32: {:?}", e.kind()); +/// } +/// # } +/// ``` +#[unstable( + feature = "int_error_matching", + reason = "it can be useful to match errors when making error messages \ + for integer parsing", + issue = "22639" +)] +#[derive(Debug, Clone, PartialEq, Eq)] +#[non_exhaustive] +pub enum IntErrorKind { + /// Value being parsed is empty. + /// + /// Among other causes, this variant will be constructed when parsing an empty string. + Empty, + /// Contains an invalid digit. + /// + /// Among other causes, this variant will be constructed when parsing a string that + /// contains a letter. + InvalidDigit, + /// Integer is too large to store in target integer type. + Overflow, + /// Integer is too small to store in target integer type. + Underflow, + /// Value was Zero + /// + /// This variant will be emitted when the parsing string has a value of zero, which + /// would be illegal for non-zero types. + Zero, +} + +impl ParseIntError { + /// Outputs the detailed cause of parsing an integer failing. + #[unstable( + feature = "int_error_matching", + reason = "it can be useful to match errors when making error messages \ + for integer parsing", + issue = "22639" + )] + pub fn kind(&self) -> &IntErrorKind { + &self.kind + } + #[unstable( + feature = "int_error_internals", + reason = "available through Error trait and this method should \ + not be exposed publicly", + issue = "none" + )] + #[doc(hidden)] + pub fn __description(&self) -> &str { + match self.kind { + IntErrorKind::Empty => "cannot parse integer from empty string", + IntErrorKind::InvalidDigit => "invalid digit found in string", + IntErrorKind::Overflow => "number too large to fit in target type", + IntErrorKind::Underflow => "number too small to fit in target type", + IntErrorKind::Zero => "number would be zero for non-zero type", + } + } +} + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Display for ParseIntError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.__description().fmt(f) + } +} diff --git a/library/core/src/num/flt2dec/mod.rs b/library/core/src/num/flt2dec/mod.rs index 9bf56e93d8..e8f9d6574e 100644 --- a/library/core/src/num/flt2dec/mod.rs +++ b/library/core/src/num/flt2dec/mod.rs @@ -124,6 +124,8 @@ functions. pub use self::decoder::{decode, DecodableFloat, Decoded, FullDecoded}; +use crate::mem::MaybeUninit; + pub mod decoder; pub mod estimator; @@ -140,23 +142,23 @@ pub mod strategy { /// The exact formula is `ceil(# bits in mantissa * log_10 2 + 1)`. pub const MAX_SIG_DIGITS: usize = 17; -/// When `d[..n]` contains decimal digits, increase the last digit and propagate carry. -/// Returns a next digit when it causes the length change. +/// When `d` contains decimal digits, increase the last digit and propagate carry. +/// Returns a next digit when it causes the length to change. #[doc(hidden)] -pub fn round_up(d: &mut [u8], n: usize) -> Option { - match d[..n].iter().rposition(|&c| c != b'9') { +pub fn round_up(d: &mut [u8]) -> Option { + match d.iter().rposition(|&c| c != b'9') { Some(i) => { // d[i+1..n] is all nines d[i] += 1; - for j in i + 1..n { + for j in i + 1..d.len() { d[j] = b'0'; } None } - None if n > 0 => { + None if d.len() > 0 => { // 999..999 rounds to 1000..000 with an increased exponent d[0] = b'1'; - for j in 1..n { + for j in 1..d.len() { d[j] = b'0'; } Some(b'0') @@ -281,7 +283,7 @@ fn digits_to_dec_str<'a>( buf: &'a [u8], exp: i16, frac_digits: usize, - parts: &'a mut [Part<'a>], + parts: &'a mut [MaybeUninit>], ) -> &'a [Part<'a>] { assert!(!buf.is_empty()); assert!(buf[0] > b'0'); @@ -303,38 +305,44 @@ fn digits_to_dec_str<'a>( if exp <= 0 { // the decimal point is before rendered digits: [0.][000...000][1234][____] let minus_exp = -(exp as i32) as usize; - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(minus_exp); - parts[2] = Part::Copy(buf); + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(minus_exp)); + parts[2] = MaybeUninit::new(Part::Copy(buf)); if frac_digits > buf.len() && frac_digits - buf.len() > minus_exp { - parts[3] = Part::Zero((frac_digits - buf.len()) - minus_exp); - &parts[..4] + parts[3] = MaybeUninit::new(Part::Zero((frac_digits - buf.len()) - minus_exp)); + // SAFETY: we just initialized the elements `..4`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } } else { - &parts[..3] + // SAFETY: we just initialized the elements `..3`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) } } } else { let exp = exp as usize; if exp < buf.len() { // the decimal point is inside rendered digits: [12][.][34][____] - parts[0] = Part::Copy(&buf[..exp]); - parts[1] = Part::Copy(b"."); - parts[2] = Part::Copy(&buf[exp..]); + parts[0] = MaybeUninit::new(Part::Copy(&buf[..exp])); + parts[1] = MaybeUninit::new(Part::Copy(b".")); + parts[2] = MaybeUninit::new(Part::Copy(&buf[exp..])); if frac_digits > buf.len() - exp { - parts[3] = Part::Zero(frac_digits - (buf.len() - exp)); - &parts[..4] + parts[3] = MaybeUninit::new(Part::Zero(frac_digits - (buf.len() - exp))); + // SAFETY: we just initialized the elements `..4`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } } else { - &parts[..3] + // SAFETY: we just initialized the elements `..3`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) } } } else { // the decimal point is after rendered digits: [1234][____0000] or [1234][__][.][__]. - parts[0] = Part::Copy(buf); - parts[1] = Part::Zero(exp - buf.len()); + parts[0] = MaybeUninit::new(Part::Copy(buf)); + parts[1] = MaybeUninit::new(Part::Zero(exp - buf.len())); if frac_digits > 0 { - parts[2] = Part::Copy(b"."); - parts[3] = Part::Zero(frac_digits); - &parts[..4] + parts[2] = MaybeUninit::new(Part::Copy(b".")); + parts[3] = MaybeUninit::new(Part::Zero(frac_digits)); + // SAFETY: we just initialized the elements `..4`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..4]) } } else { - &parts[..2] + // SAFETY: we just initialized the elements `..2`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) } } } } @@ -354,7 +362,7 @@ fn digits_to_exp_str<'a>( exp: i16, min_ndigits: usize, upper: bool, - parts: &'a mut [Part<'a>], + parts: &'a mut [MaybeUninit>], ) -> &'a [Part<'a>] { assert!(!buf.is_empty()); assert!(buf[0] > b'0'); @@ -362,15 +370,15 @@ fn digits_to_exp_str<'a>( let mut n = 0; - parts[n] = Part::Copy(&buf[..1]); + parts[n] = MaybeUninit::new(Part::Copy(&buf[..1])); n += 1; if buf.len() > 1 || min_ndigits > 1 { - parts[n] = Part::Copy(b"."); - parts[n + 1] = Part::Copy(&buf[1..]); + parts[n] = MaybeUninit::new(Part::Copy(b".")); + parts[n + 1] = MaybeUninit::new(Part::Copy(&buf[1..])); n += 2; if min_ndigits > buf.len() { - parts[n] = Part::Zero(min_ndigits - buf.len()); + parts[n] = MaybeUninit::new(Part::Zero(min_ndigits - buf.len())); n += 1; } } @@ -378,13 +386,14 @@ fn digits_to_exp_str<'a>( // 0.1234 x 10^exp = 1.234 x 10^(exp-1) let exp = exp as i32 - 1; // avoid underflow when exp is i16::MIN if exp < 0 { - parts[n] = Part::Copy(if upper { b"E-" } else { b"e-" }); - parts[n + 1] = Part::Num(-exp as u16); + parts[n] = MaybeUninit::new(Part::Copy(if upper { b"E-" } else { b"e-" })); + parts[n + 1] = MaybeUninit::new(Part::Num(-exp as u16)); } else { - parts[n] = Part::Copy(if upper { b"E" } else { b"e" }); - parts[n + 1] = Part::Num(exp as u16); + parts[n] = MaybeUninit::new(Part::Copy(if upper { b"E" } else { b"e" })); + parts[n + 1] = MaybeUninit::new(Part::Num(exp as u16)); } - &parts[..n + 2] + // SAFETY: we just initialized the elements `..n + 2`. + unsafe { MaybeUninit::slice_assume_init_ref(&parts[..n + 2]) } } /// Sign formatting options. @@ -446,6 +455,7 @@ fn determine_sign(sign: Sign, decoded: &FullDecoded, negative: bool) -> &'static /// (which can be an empty string if no sign is rendered). /// /// `format_shortest` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_shortest` for this. /// /// `frac_digits` can be less than the number of actual fractional digits in `v`; @@ -461,12 +471,12 @@ pub fn to_shortest_str<'a, T, F>( v: T, sign: Sign, frac_digits: usize, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { assert!(parts.len() >= 4); assert!(buf.len() >= MAX_SIG_DIGITS); @@ -475,27 +485,37 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { if frac_digits > 0 { // [0.][0000] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(frac_digits); - Formatted { sign, parts: &parts[..2] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(frac_digits)); + Formatted { + sign, + // SAFETY: we just initialized the elements `..2`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + } } else { - parts[0] = Part::Copy(b"0"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"0")); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } FullDecoded::Finite(ref decoded) => { - let (len, exp) = format_shortest(decoded, buf); - Formatted { sign, parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) } + let (buf, exp) = format_shortest(decoded, buf); + Formatted { sign, parts: digits_to_dec_str(buf, exp, frac_digits, parts) } } } } @@ -509,6 +529,7 @@ where /// an empty string if no sign is rendered). /// /// `format_shortest` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_shortest` for this. /// /// The `dec_bounds` is a tuple `(lo, hi)` such that the number is formatted @@ -525,12 +546,12 @@ pub fn to_shortest_exp_str<'a, T, F>( sign: Sign, dec_bounds: (i16, i16), upper: bool, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8]) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit]) -> (&'a [u8], i16), { assert!(parts.len() >= 6); assert!(buf.len() >= MAX_SIG_DIGITS); @@ -540,28 +561,31 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { parts[0] = if dec_bounds.0 <= 0 && 0 < dec_bounds.1 { - Part::Copy(b"0") + MaybeUninit::new(Part::Copy(b"0")) } else { - Part::Copy(if upper { b"0E0" } else { b"0e0" }) + MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" })) }; - Formatted { sign, parts: &parts[..1] } + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Finite(ref decoded) => { - let (len, exp) = format_shortest(decoded, buf); + let (buf, exp) = format_shortest(decoded, buf); let vis_exp = exp as i32 - 1; let parts = if dec_bounds.0 as i32 <= vis_exp && vis_exp < dec_bounds.1 as i32 { - digits_to_dec_str(&buf[..len], exp, 0, parts) + digits_to_dec_str(buf, exp, 0, parts) } else { - digits_to_exp_str(&buf[..len], exp, 0, upper, parts) + digits_to_exp_str(buf, exp, 0, upper, parts) }; Formatted { sign, parts } } @@ -600,6 +624,7 @@ fn estimate_max_buf_len(exp: i16) -> usize { /// an empty string if no sign is rendered). /// /// `format_exact` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_exact` for this. /// /// The byte buffer should be at least `ndigits` bytes long unless `ndigits` is @@ -613,12 +638,12 @@ pub fn to_exact_exp_str<'a, T, F>( sign: Sign, ndigits: usize, upper: bool, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { assert!(parts.len() >= 6); assert!(ndigits > 0); @@ -627,23 +652,33 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { if ndigits > 1 { // [0.][0000][e0] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(ndigits - 1); - parts[2] = Part::Copy(if upper { b"E0" } else { b"e0" }); - Formatted { sign, parts: &parts[..3] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(ndigits - 1)); + parts[2] = MaybeUninit::new(Part::Copy(if upper { b"E0" } else { b"e0" })); + Formatted { + sign, + // SAFETY: we just initialized the elements `..3`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..3]) }, + } } else { - parts[0] = Part::Copy(if upper { b"0E0" } else { b"0e0" }); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(if upper { b"0E0" } else { b"0e0" })); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } FullDecoded::Finite(ref decoded) => { @@ -651,8 +686,8 @@ where assert!(buf.len() >= ndigits || buf.len() >= maxlen); let trunc = if ndigits < maxlen { ndigits } else { maxlen }; - let (len, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN); - Formatted { sign, parts: digits_to_exp_str(&buf[..len], exp, ndigits, upper, parts) } + let (buf, exp) = format_exact(decoded, &mut buf[..trunc], i16::MIN); + Formatted { sign, parts: digits_to_exp_str(buf, exp, ndigits, upper, parts) } } } } @@ -665,6 +700,7 @@ where /// (which can be an empty string if no sign is rendered). /// /// `format_exact` should be the underlying digit-generation function. +/// It should return the part of the buffer that it initialized. /// You probably would want `strategy::grisu::format_exact` for this. /// /// The byte buffer should be enough for the output unless `frac_digits` is @@ -677,12 +713,12 @@ pub fn to_exact_fixed_str<'a, T, F>( v: T, sign: Sign, frac_digits: usize, - buf: &'a mut [u8], - parts: &'a mut [Part<'a>], + buf: &'a mut [MaybeUninit], + parts: &'a mut [MaybeUninit>], ) -> Formatted<'a> where T: DecodableFloat, - F: FnMut(&Decoded, &mut [u8], i16) -> (usize, i16), + F: FnMut(&Decoded, &'a mut [MaybeUninit], i16) -> (&'a [u8], i16), { assert!(parts.len() >= 4); @@ -690,22 +726,32 @@ where let sign = determine_sign(sign, &full_decoded, negative); match full_decoded { FullDecoded::Nan => { - parts[0] = Part::Copy(b"NaN"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"NaN")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Infinite => { - parts[0] = Part::Copy(b"inf"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"inf")); + // SAFETY: we just initialized the elements `..1`. + Formatted { sign, parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) } } } FullDecoded::Zero => { if frac_digits > 0 { // [0.][0000] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(frac_digits); - Formatted { sign, parts: &parts[..2] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(frac_digits)); + Formatted { + sign, + // SAFETY: we just initialized the elements `..2`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + } } else { - parts[0] = Part::Copy(b"0"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"0")); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } FullDecoded::Finite(ref decoded) => { @@ -716,23 +762,31 @@ where // `format_exact` will end rendering digits much earlier in this case, // because we are strictly limited by `maxlen`. let limit = if frac_digits < 0x8000 { -(frac_digits as i16) } else { i16::MIN }; - let (len, exp) = format_exact(decoded, &mut buf[..maxlen], limit); + let (buf, exp) = format_exact(decoded, &mut buf[..maxlen], limit); if exp <= limit { // the restriction couldn't been met, so this should render like zero no matter // `exp` was. this does not include the case that the restriction has been met // only after the final rounding-up; it's a regular case with `exp = limit + 1`. - debug_assert_eq!(len, 0); + debug_assert_eq!(buf.len(), 0); if frac_digits > 0 { // [0.][0000] - parts[0] = Part::Copy(b"0."); - parts[1] = Part::Zero(frac_digits); - Formatted { sign, parts: &parts[..2] } + parts[0] = MaybeUninit::new(Part::Copy(b"0.")); + parts[1] = MaybeUninit::new(Part::Zero(frac_digits)); + Formatted { + sign, + // SAFETY: we just initialized the elements `..2`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..2]) }, + } } else { - parts[0] = Part::Copy(b"0"); - Formatted { sign, parts: &parts[..1] } + parts[0] = MaybeUninit::new(Part::Copy(b"0")); + Formatted { + sign, + // SAFETY: we just initialized the elements `..1`. + parts: unsafe { MaybeUninit::slice_assume_init_ref(&parts[..1]) }, + } } } else { - Formatted { sign, parts: digits_to_dec_str(&buf[..len], exp, frac_digits, parts) } + Formatted { sign, parts: digits_to_dec_str(buf, exp, frac_digits, parts) } } } } diff --git a/library/core/src/num/flt2dec/strategy/dragon.rs b/library/core/src/num/flt2dec/strategy/dragon.rs index c8de000435..8ced5971ec 100644 --- a/library/core/src/num/flt2dec/strategy/dragon.rs +++ b/library/core/src/num/flt2dec/strategy/dragon.rs @@ -5,6 +5,7 @@ //! quickly and accurately. SIGPLAN Not. 31, 5 (May. 1996), 108-116. use crate::cmp::Ordering; +use crate::mem::MaybeUninit; use crate::num::bignum::Big32x40 as Big; use crate::num::bignum::Digit32 as Digit; @@ -97,7 +98,10 @@ fn div_rem_upto_16<'a>( } /// The shortest mode implementation for Dragon. -pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_shortest<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { // the number `v` to format is known to be: // - equal to `mant * 2^exp`; // - preceded by `(mant - 2 * minus) * 2^exp` in the original type; and @@ -186,7 +190,7 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp // generate one digit: `d[n] = floor(mant / scale) < 10`. let (d, _) = div_rem_upto_16(&mut mant, &scale, &scale2, &scale4, &scale8); debug_assert!(d < 10); - buf[i] = b'0' + d; + buf[i] = MaybeUninit::new(b'0' + d); i += 1; // this is a simplified description of the modified Dragon algorithm. @@ -241,18 +245,24 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp // if rounding up changes the length, the exponent should also change. // it seems that this condition is very hard to satisfy (possibly impossible), // but we are just being safe and consistent here. - if let Some(c) = round_up(buf, i) { - buf[i] = c; + // SAFETY: we initialized that memory above. + if let Some(c) = round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }) { + buf[i] = MaybeUninit::new(c); i += 1; k += 1; } } - (i, k) + // SAFETY: we initialized that memory above. + (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..i]) }, k) } /// The exact and fixed mode implementation for Dragon. -pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_exact<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], + limit: i16, +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { assert!(d.mant > 0); assert!(d.minus > 0); assert!(d.plus > 0); @@ -319,9 +329,10 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi // following digits are all zeroes, we stop here // do *not* try to perform rounding! rather, fill remaining digits. for c in &mut buf[i..len] { - *c = b'0'; + *c = MaybeUninit::new(b'0'); } - return (len, k); + // SAFETY: we initialized that memory above. + return (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, k); } let mut d = 0; @@ -343,7 +354,7 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi } debug_assert!(mant < scale); debug_assert!(d < 10); - buf[i] = b'0' + d; + buf[i] = MaybeUninit::new(b'0' + d); mant.mul_small(10); } } @@ -353,21 +364,25 @@ pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usi // round to even (i.e., avoid rounding up when the prior digit is even). let order = mant.cmp(scale.mul_small(5)); if order == Ordering::Greater - || (order == Ordering::Equal && (len == 0 || buf[len - 1] & 1 == 1)) + || (order == Ordering::Equal + // SAFETY: `buf[len-1]` is initialized. + && (len == 0 || unsafe { buf[len - 1].assume_init() } & 1 == 1)) { // if rounding up changes the length, the exponent should also change. // but we've been requested a fixed number of digits, so do not alter the buffer... - if let Some(c) = round_up(buf, len) { + // SAFETY: we initialized that memory above. + if let Some(c) = round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..len]) }) { // ...unless we've been requested the fixed precision instead. // we also need to check that, if the original buffer was empty, // the additional digit can only be added when `k == limit` (edge case). k += 1; if k > limit && len < buf.len() { - buf[len] = c; + buf[len] = MaybeUninit::new(c); len += 1; } } } - (len, k) + // SAFETY: we initialized that memory above. + (unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, k) } diff --git a/library/core/src/num/flt2dec/strategy/grisu.rs b/library/core/src/num/flt2dec/strategy/grisu.rs index 1e2db212dd..a4cb51c629 100644 --- a/library/core/src/num/flt2dec/strategy/grisu.rs +++ b/library/core/src/num/flt2dec/strategy/grisu.rs @@ -5,6 +5,7 @@ //! [^1]: Florian Loitsch. 2010. Printing floating-point numbers quickly and //! accurately with integers. SIGPLAN Not. 45, 6 (June 2010), 233-243. +use crate::mem::MaybeUninit; use crate::num::diy_float::Fp; use crate::num::flt2dec::{round_up, Decoded, MAX_SIG_DIGITS}; @@ -161,10 +162,10 @@ pub fn max_pow10_no_more_than(x: u32) -> (u8, u32) { /// The shortest mode implementation for Grisu. /// /// It returns `None` when it would return an inexact representation otherwise. -pub fn format_shortest_opt( +pub fn format_shortest_opt<'a>( d: &Decoded, - buf: &mut [u8], -) -> Option<(/*#digits*/ usize, /*exp*/ i16)> { + buf: &'a mut [MaybeUninit], +) -> Option<(/*digits*/ &'a [u8], /*exp*/ i16)> { assert!(d.mant > 0); assert!(d.minus > 0); assert!(d.plus > 0); @@ -266,14 +267,23 @@ pub fn format_shortest_opt( let q = remainder / ten_kappa; let r = remainder % ten_kappa; debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; let plus1rem = ((r as u64) << e) + plus1frac; // == (plus1 % 10^kappa) * 2^e if plus1rem < delta1 { // `plus1 % 10^kappa < delta1 = plus1 - minus1`; we've found the correct `kappa`. let ten_kappa = (ten_kappa as u64) << e; // scale 10^kappa back to the shared exponent - return round_and_weed(&mut buf[..i], exp, plus1rem, delta1, plus1 - v.f, ten_kappa, 1); + return round_and_weed( + // SAFETY: we initialized that memory above. + unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }, + exp, + plus1rem, + delta1, + plus1 - v.f, + ten_kappa, + 1, + ); } // break the loop when we have rendered all integral digits. @@ -310,13 +320,14 @@ pub fn format_shortest_opt( let q = remainder >> e; let r = remainder & ((1 << e) - 1); debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; if r < threshold { let ten_kappa = 1 << e; // implicit divisor return round_and_weed( - &mut buf[..i], + // SAFETY: we initialized that memory above. + unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..i]) }, exp, r, threshold, @@ -355,7 +366,7 @@ pub fn format_shortest_opt( plus1v: u64, ten_kappa: u64, ulp: u64, - ) -> Option<(usize, i16)> { + ) -> Option<(&[u8], i16)> { assert!(!buf.is_empty()); // produce two approximations to `v` (actually `plus1 - v`) within 1.5 ulps. @@ -437,20 +448,22 @@ pub fn format_shortest_opt( // this is too liberal, though, so we reject any `w(n)` not between `plus0` and `minus0`, // i.e., `plus1 - plus1w(n) <= minus0` or `plus1 - plus1w(n) >= plus0`. we utilize the facts // that `threshold = plus1 - minus1` and `plus1 - plus0 = minus0 - minus1 = 2 ulp`. - if 2 * ulp <= plus1w && plus1w <= threshold - 4 * ulp { - Some((buf.len(), exp)) - } else { - None - } + if 2 * ulp <= plus1w && plus1w <= threshold - 4 * ulp { Some((buf, exp)) } else { None } } } /// The shortest mode implementation for Grisu with Dragon fallback. /// /// This should be used for most cases. -pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_shortest<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { use crate::num::flt2dec::strategy::dragon::format_shortest as fallback; - match format_shortest_opt(d, buf) { + // SAFETY: The borrow checker is not smart enough to let us use `buf` + // in the second branch, so we launder the lifetime here. But we only re-use + // `buf` if `format_shortest_opt` returned `None` so this is okay. + match format_shortest_opt(d, unsafe { &mut *(buf as *mut _) }) { Some(ret) => ret, None => fallback(d, buf), } @@ -459,11 +472,11 @@ pub fn format_shortest(d: &Decoded, buf: &mut [u8]) -> (/*#digits*/ usize, /*exp /// The exact and fixed mode implementation for Grisu. /// /// It returns `None` when it would return an inexact representation otherwise. -pub fn format_exact_opt( +pub fn format_exact_opt<'a>( d: &Decoded, - buf: &mut [u8], + buf: &'a mut [MaybeUninit], limit: i16, -) -> Option<(/*#digits*/ usize, /*exp*/ i16)> { +) -> Option<(/*digits*/ &'a [u8], /*exp*/ i16)> { assert!(d.mant > 0); assert!(d.mant < (1 << 61)); // we need at least three bits of additional precision assert!(!buf.is_empty()); @@ -510,7 +523,11 @@ pub fn format_exact_opt( // thus we are being sloppy here and widen the error range by a factor of 10. // this will increase the false negative rate, but only very, *very* slightly; // it can only matter noticeably when the mantissa is bigger than 60 bits. - return possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e); + // + // SAFETY: `len=0`, so the obligation of having initialized this memory is trivial. + return unsafe { + possibly_round(buf, 0, exp, limit, v.f / 10, (max_ten_kappa as u64) << e, err << e) + }; } else if ((exp as i32 - limit as i32) as usize) < buf.len() { (exp - limit) as usize } else { @@ -534,13 +551,16 @@ pub fn format_exact_opt( let q = remainder / ten_kappa; let r = remainder % ten_kappa; debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; // is the buffer full? run the rounding pass with the remainder. if i == len { let vrem = ((r as u64) << e) + vfrac; // == (v % 10^kappa) * 2^e - return possibly_round(buf, len, exp, limit, vrem, (ten_kappa as u64) << e, err << e); + // SAFETY: we have initialized `len` many bytes. + return unsafe { + possibly_round(buf, len, exp, limit, vrem, (ten_kappa as u64) << e, err << e) + }; } // break the loop when we have rendered all integral digits. @@ -585,12 +605,13 @@ pub fn format_exact_opt( let q = remainder >> e; let r = remainder & ((1 << e) - 1); debug_assert!(q < 10); - buf[i] = b'0' + q as u8; + buf[i] = MaybeUninit::new(b'0' + q as u8); i += 1; // is the buffer full? run the rounding pass with the remainder. if i == len { - return possibly_round(buf, len, exp, limit, r, 1 << e, err); + // SAFETY: we have initialized `len` many bytes. + return unsafe { possibly_round(buf, len, exp, limit, r, 1 << e, err) }; } // restore invariants @@ -610,15 +631,17 @@ pub fn format_exact_opt( // - `remainder = (v % 10^kappa) * k` // - `ten_kappa = 10^kappa * k` // - `ulp = 2^-e * k` - fn possibly_round( - buf: &mut [u8], + // + // SAFETY: the first `len` bytes of `buf` must be initialized. + unsafe fn possibly_round( + buf: &mut [MaybeUninit], mut len: usize, mut exp: i16, limit: i16, remainder: u64, ten_kappa: u64, ulp: u64, - ) -> Option<(usize, i16)> { + ) -> Option<(&[u8], i16)> { debug_assert!(remainder < ten_kappa); // 10^kappa @@ -677,7 +700,8 @@ pub fn format_exact_opt( // we've already verified that `ulp < 10^kappa / 2`, so as long as // `10^kappa` did not overflow after all, the second check is fine. if ten_kappa - remainder > remainder && ten_kappa - 2 * remainder >= 2 * ulp { - return Some((len, exp)); + // SAFETY: our caller initialized that memory. + return Some((unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, exp)); } // :<------- remainder ------>| : @@ -698,17 +722,21 @@ pub fn format_exact_opt( // as `10^kappa` is never zero). also note that `remainder - ulp <= 10^kappa`, // so the second check does not overflow. if remainder > ulp && ten_kappa - (remainder - ulp) <= remainder - ulp { - if let Some(c) = round_up(buf, len) { + if let Some(c) = + // SAFETY: our caller must have initialized that memory. + round_up(unsafe { MaybeUninit::slice_assume_init_mut(&mut buf[..len]) }) + { // only add an additional digit when we've been requested the fixed precision. // we also need to check that, if the original buffer was empty, // the additional digit can only be added when `exp == limit` (edge case). exp += 1; if exp > limit && len < buf.len() { - buf[len] = c; + buf[len] = MaybeUninit::new(c); len += 1; } } - return Some((len, exp)); + // SAFETY: we and our caller initialized that memory. + return Some((unsafe { MaybeUninit::slice_assume_init_ref(&buf[..len]) }, exp)); } // otherwise we are doomed (i.e., some values between `v - 1 ulp` and `v + 1 ulp` are @@ -720,9 +748,16 @@ pub fn format_exact_opt( /// The exact and fixed mode implementation for Grisu with Dragon fallback. /// /// This should be used for most cases. -pub fn format_exact(d: &Decoded, buf: &mut [u8], limit: i16) -> (/*#digits*/ usize, /*exp*/ i16) { +pub fn format_exact<'a>( + d: &Decoded, + buf: &'a mut [MaybeUninit], + limit: i16, +) -> (/*digits*/ &'a [u8], /*exp*/ i16) { use crate::num::flt2dec::strategy::dragon::format_exact as fallback; - match format_exact_opt(d, buf, limit) { + // SAFETY: The borrow checker is not smart enough to let us use `buf` + // in the second branch, so we launder the lifetime here. But we only re-use + // `buf` if `format_exact_opt` returned `None` so this is okay. + match format_exact_opt(d, unsafe { &mut *(buf as *mut _) }, limit) { Some(ret) => ret, None => fallback(d, buf, limit), } diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index ffd30b03f2..369175fb6a 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -1,49 +1,2201 @@ -#![doc(hidden)] - -macro_rules! doc_comment { - ($x:expr, $($tt:tt)*) => { - #[doc = $x] - $($tt)* - }; -} - -macro_rules! int_module { - ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); - ($T:ident, #[$attr:meta]) => ( +macro_rules! int_impl { + ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, + $EndFeature: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) => { doc_comment! { concat!("The smallest value that can be represented by this integer type. -Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead. # Examples -```rust -// deprecated way -let min = std::", stringify!($T), "::MIN; +Basic usage: -// intended way -let min = ", stringify!($T), "::MIN; ``` -"), - #[$attr] - pub const MIN: $T = $T::MIN; +", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; } doc_comment! { concat!("The largest value that can be represented by this integer type. -Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead. # Examples -```rust -// deprecated way -let max = std::", stringify!($T), "::MAX; +Basic usage: -// intended way -let max = ", stringify!($T), "::MAX; +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MAX: Self = !Self::MIN; + } + + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "76904")] + pub const BITS: u32 = $BITS; + } + + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` or `-` sign followed by digits. +Leading and trailing whitespace represent an error. Digits are a subset of these characters, +depending on `radix`: + + * `0-9` + * `a-z` + * `A-Z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } + } + + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b100_0000", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 1);", +$EndFeature, " ``` "), - #[$attr] - pub const MAX: $T = $T::MAX; + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } } - ) + + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_zeros(), 0);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + (self as $UnsignedT).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -4", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 2);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + (self as $UnsignedT).trailing_zeros() + } + } + + doc_comment! { + concat!("Returns the number of leading ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = -1", stringify!($SelfT), "; + +assert_eq!(n.leading_ones(), ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn leading_ones(self) -> u32 { + (self as $UnsignedT).leading_ones() + } + } + + doc_comment! { + concat!("Returns the number of trailing ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 3", stringify!($SelfT), "; + +assert_eq!(n.trailing_ones(), 2);", +$EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn trailing_ones(self) -> u32 { + (self as $UnsignedT).trailing_ones() + } + } + + doc_comment! { + concat!("Shifts the bits to the left by a specified amount, `n`, +wrapping the truncated bits to the end of the resulting integer. + +Please note this isn't the same operation as the `<<` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_op, stringify!($SelfT), "; +let m = ", $rot_result, "; + +assert_eq!(n.rotate_left(", $rot, "), m); +```"), + #[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] + pub const fn rotate_left(self, n: u32) -> Self { + (self as $UnsignedT).rotate_left(n) as Self + } + } + + doc_comment! { + concat!("Shifts the bits to the right by a specified amount, `n`, +wrapping the truncated bits to the beginning of the resulting +integer. + +Please note this isn't the same operation as the `>>` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_result, stringify!($SelfT), "; +let m = ", $rot_op, "; + +assert_eq!(n.rotate_right(", $rot, "), m); +```"), + #[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] + pub const fn rotate_right(self, n: u32) -> Self { + (self as $UnsignedT).rotate_right(n) as Self + } + } + + doc_comment! { + concat!("Reverses the byte order of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; + +let m = n.swap_bytes(); + +assert_eq!(m, ", $swapped, "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn swap_bytes(self) -> Self { + (self as $UnsignedT).swap_bytes() as Self + } + } + + doc_comment! { + concat!("Reverses the bit pattern of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.reverse_bits(); + +assert_eq!(m, ", $reversed, "); +```"), + #[stable(feature = "reverse_bits", since = "1.37.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + #[must_use] + pub const fn reverse_bits(self) -> Self { + (self as $UnsignedT).reverse_bits() as Self + } + } + + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +}", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1)); +assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.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_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_add(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1)); +assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.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_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), +"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.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_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` +or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), +"::MIN + 1).checked_div(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + // SAFETY: div by zero and by INT_MIN have been checked above + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, +returning `None` if `rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!((", stringify!($SelfT), +"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); +assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None); +assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + Some(self.div_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if +`rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + // SAFETY: div by zero and by INT_MIN have been checked above + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` +if `rhs == 0` or the division results in overflow. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); +assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { + None + } else { + Some(self.rem_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger +than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", +$EndFeature, " +```"), + #[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_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is +larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", +$EndFeature, " +```"), + #[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_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked absolute value. Computes `self.abs()`, returning `None` if +`self == MIN`. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); +assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_abs(self) -> Option { + if self.is_negative() { + self.checked_neg() + } else { + Some(self) + } + } + } + + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", +$EndFeature, " +```"), + + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_pow(self, mut exp: u32) -> Option { + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.checked_mul(base)); + } + exp /= 2; + base = try_opt!(base.checked_mul(base)); + } + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + Some(try_opt!(acc.checked_mul(base))) + } + } + + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric +bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), +"::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), +"::MIN);", +$EndFeature, " +```"), + + #[stable(feature = "rust1", since = "1.0.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_add(self, rhs: Self) -> Self { + intrinsics::saturating_add(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), +"::MIN); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), +"::MAX);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.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_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` +instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); +assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), +"::MAX); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), +"::MIN + 1);", +$EndFeature, " +```"), + + #[stable(feature = "saturating_neg", since = "1.45.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_neg(self) -> Self { + intrinsics::saturating_sub(0, self) + } + } + + doc_comment! { + concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == +MIN` instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), +"::MAX); +assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), +"::MAX);", +$EndFeature, " +```"), + + #[stable(feature = "saturating_neg", since = "1.45.0")] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_abs(self) -> Self { + if self.is_negative() { + self.saturating_neg() + } else { + self + } + } + } + + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the +numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);", +$EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.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_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => if (self < 0) == (rhs < 0) { + Self::MAX + } else { + Self::MIN + } + } + } + } + + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX); +assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None if self < 0 && exp % 2 == 1 => Self::MIN, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); +assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), +"::MIN + 1);", +$EndFeature, " +```"), + #[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] + pub const fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the +boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); +assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", +stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + #[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] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + intrinsics::wrapping_sub(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at +the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); +assert_eq!(11i8.wrapping_mul(12), -124);", +$EndFeature, " +```"), + #[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] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + intrinsics::wrapping_mul(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the +boundary of the type. + +The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where +`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value +that is too large to represent in the type. In such a case, this function returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); +assert_eq!((-128i8).wrapping_div(-1), -128);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + self.overflowing_div(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, +wrapping around at the boundary of the type. + +Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value +for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the +type. In this case, this method returns `MIN` itself. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); +assert_eq!((-128i8).wrapping_div_euclid(-1), -128); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self.overflowing_div_euclid(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the +boundary of the type. + +Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` +invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, +this function returns `0`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); +assert_eq!((-128i8).wrapping_rem(-1), 0);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + self.overflowing_rem(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around +at the boundary of the type. + +Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value +for the type). In this case, this method returns 0. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); +assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self.overflowing_rem_euclid(rhs).0 + } + } + + doc_comment! { + concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary +of the type. + +The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` +is the negative minimal value for the type); this is a positive value that is too large to represent +in the type. In such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); +assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), +"::MIN);", +$EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes +any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to +the range of the type, rather than the bits shifted out of the LHS being returned to the other end. +The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); +assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", +$EndFeature, " +```"), + #[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] + pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` +removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted +to the range of the type, rather than the bits shifted out of the LHS being returned to the other +end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); +assert_eq!((-128i16).wrapping_shr(64), -128);", +$EndFeature, " +```"), + #[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] + pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at +the boundary of the type. + +The only case where such wrapping can occur is when one takes the absolute value of the negative +minimal value for the type; this is a positive value that is too large to represent in the type. In +such a case, this function returns `MIN` itself. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); +assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); +assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), +"::MIN); +assert_eq!((-128i8).wrapping_abs() as u8, 128);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + #[inline] + pub const fn wrapping_abs(self) -> Self { + if self.is_negative() { + self.wrapping_neg() + } else { + self + } + } + } + + doc_comment! { + concat!("Computes the absolute value of `self` without any wrapping +or panicking. + + +# Examples + +Basic usage: + +``` +", $Feature, "#![feature(unsigned_abs)] +assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), "); +assert_eq!((-128i8).unsigned_abs(), 128u8);", +$EndFeature, " +```"), + #[unstable(feature = "unsigned_abs", issue = "74913")] + #[inline] + pub const fn unsigned_abs(self) -> $UnsignedT { + self.wrapping_abs() as $UnsignedT + } + } + + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); +assert_eq!(3i8.wrapping_pow(5), -13); +assert_eq!(3i8.wrapping_pow(6), -39);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.wrapping_mul(base) + } + } + + doc_comment! { + concat!("Calculates `self` + `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, " +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates `self` - `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, " +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), +"::MAX, true));", $EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates the multiplication of `self` and `rhs`. + +Returns a tuple of the multiplication 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, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); +assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", +$EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then self is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[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) { + (self, true) + } else { + (self / rhs, false) + } + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would +occur. If an overflow would occur then `self` is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), +"::MIN, true)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[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) { + (self, true) + } else { + (self.div_euclid(rhs), false) + } + } + } + + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[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) + } else { + (self % rhs, false) + } + } + } + + + doc_comment! { + concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`. + +Returns a tuple of the remainder after dividing along with a boolean indicating whether an +arithmetic overflow would occur. If an overflow would occur then 0 is returned. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + 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) + } else { + (self.rem_euclid(rhs), false) + } + } + } + + + doc_comment! { + concat!("Negates self, overflowing if this is equal to the minimum value. + +Returns a tuple of the negated version of self along with a boolean indicating whether an overflow +happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the +minimum value will be returned again and `true` will be returned for an overflow happening. + +# Examples + +Basic usage: + +``` +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); +assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), +"::MIN, true));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + pub const fn overflowing_neg(self) -> (Self, bool) { + if unlikely!(self == Self::MIN) { + (Self::MIN, true) + } else { + (-self, false) + } + } + } + + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", +$EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean indicating whether the shift +value was larger than or equal to the number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then used to perform the shift. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", +$EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`. + +Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow +happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type + ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned +for an overflow happening. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); +assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); +assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), +"::MIN, true));", +$EndFeature, " +```"), + #[stable(feature = "no_panic_abs", since = "1.13.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn overflowing_abs(self) -> (Self, bool) { + (self.wrapping_abs(), self == Self::MIN) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); +assert_eq!(3i8.overflowing_pow(5), (-13, true));", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + if exp == 0 { + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + r = acc.overflowing_mul(base); + r.1 |= overflown; + r + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type + +assert_eq!(x.pow(5), 32);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. + +This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, +with `0 <= self.rem_euclid(rhs) < rhs`. + +In other words, the result is `self / rhs` rounded to the integer `n` +such that `self >= n * rhs`. +If `self > 0`, this is equal to round towards zero (the default in Rust); +if `self < 0`, this is equal to round towards +/- infinity. + +# Panics + +This function will panic if `rhs` is 0 or the division results in overflow. + +# Examples + +Basic usage: + +``` +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1 +assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 +assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 +assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_euclid(self, rhs: Self) -> Self { + let q = self / rhs; + if self % rhs < 0 { + return if rhs > 0 { q - 1 } else { q + 1 } + } + q + } + } + + + doc_comment! { + concat!("Calculates the least nonnegative remainder of `self (mod rhs)`. + +This is done as if by the Euclidean division algorithm -- given +`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and +`0 <= r < abs(rhs)`. + +# Panics + +This function will panic if `rhs` is 0 or the division results in overflow. + +# Examples + +Basic usage: + +``` +let a: ", stringify!($SelfT), " = 7; // or any other integer type +let b = 4; + +assert_eq!(a.rem_euclid(b), 3); +assert_eq!((-a).rem_euclid(b), 1); +assert_eq!(a.rem_euclid(-b), 3); +assert_eq!((-a).rem_euclid(-b), 1); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn rem_euclid(self, rhs: Self) -> Self { + let r = self % rhs; + if r < 0 { + if rhs < 0 { + r - rhs + } else { + r + rhs + } + } else { + r + } + } + } + + doc_comment! { + concat!("Computes the absolute value of `self`. + +# Overflow behavior + +The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an +`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that +code in debug mode will trigger a panic on this case and optimized code will return `", +stringify!($SelfT), "::MIN` without a panic. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10); +assert_eq!((-10", stringify!($SelfT), ").abs(), 10);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[allow(unused_attributes)] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn abs(self) -> Self { + // Note that the #[inline] above means that the overflow + // semantics of the subtraction depend on the crate we're being + // inlined into. + if self.is_negative() { + -self + } else { + self + } + } + } + + doc_comment! { + concat!("Returns a number representing sign of `self`. + + - `0` if the number is zero + - `1` if the number is positive + - `-1` if the number is negative + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1); +assert_eq!(0", stringify!($SelfT), ".signum(), 0); +assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] + #[inline] + pub const fn signum(self) -> Self { + match self { + n if n > 0 => 1, + 0 => 0, + _ => -1, + } + } + } + + doc_comment! { + concat!("Returns `true` if `self` is positive and `false` if the number is zero or +negative. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!(10", stringify!($SelfT), ".is_positive()); +assert!(!(-10", stringify!($SelfT), ").is_positive());", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn is_positive(self) -> bool { self > 0 } + } + + doc_comment! { + concat!("Returns `true` if `self` is negative and `false` if the number is zero or +positive. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative()); +assert!(!10", stringify!($SelfT), ".is_negative());", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] + #[inline] + pub const fn is_negative(self) -> bool { self < 0 } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +big-endian (network) byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); +assert_eq!(bytes, ", $be_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + self.to_be().to_ne_bytes() + } + } + +doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +little-endian byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); +assert_eq!(bytes, ", $le_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + self.to_le().to_ne_bytes() + } + } + + doc_comment! { + concat!(" +Return the memory representation of this integer as a byte array in +native byte order. + +As the target platform's native endianness is used, portable code +should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, +instead. +", +$to_xe_bytes_doc, +" +[`to_be_bytes`]: #method.to_be_bytes +[`to_le_bytes`]: #method.to_le_bytes + +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { + ", $be_bytes, " + } else { + ", $le_bytes, " + } +); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[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 + #[allow_internal_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 + // arrays of bytes + unsafe { mem::transmute(self) } + } + } + +doc_comment! { + concat!("Create an integer value from its representation as a byte array in +big endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + } + +doc_comment! { + concat!(" +Create an integer value from its representation as a byte array in +little endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!("Create an integer value from its memory representation as a byte +array in native endianness. + +As the target platform's native endianness is used, portable code +likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as +appropriate instead. + +[`from_be_bytes`]: #method.from_be_bytes +[`from_le_bytes`]: #method.from_le_bytes +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { + ", $be_bytes, " +} else { + ", $le_bytes, " +}); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[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 to them + #[allow_internal_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 + unsafe { mem::transmute(bytes) } + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause a compilation warning, +new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. + +Returns the smallest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + #[rustc_promotable] + #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")] + pub const fn min_value() -> Self { + Self::MIN + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause a compilation warning, +new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. + +Returns the largest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[inline(always)] + #[rustc_promotable] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn max_value() -> Self { + Self::MAX + } + } + } } diff --git a/library/core/src/num/mod.rs b/library/core/src/num/mod.rs index 7a88cfbb74..4f64e30ccf 100644 --- a/library/core/src/num/mod.rs +++ b/library/core/src/num/mod.rs @@ -1,14 +1,9 @@ -// ignore-tidy-filelength - //! Numeric traits and functions for the built-in numeric types. #![stable(feature = "rust1", since = "1.0.0")] -use crate::convert::Infallible; -use crate::fmt; use crate::intrinsics; use crate::mem; -use crate::ops::{BitOr, BitOrAssign}; use crate::str::FromStr; // Used because the `?` operator is not allowed in a const context. @@ -28,20 +23,6 @@ macro_rules! unlikely { }; } -macro_rules! impl_nonzero_fmt { - ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { - $( - #[$stability] - impl fmt::$Trait for $Ty { - #[inline] - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.get().fmt(f) - } - } - )+ - } -} - macro_rules! doc_comment { ($x:expr, $($tt:tt)*) => { #[doc = $x] @@ -49,248 +30,42 @@ macro_rules! doc_comment { }; } -macro_rules! nonzero_integers { - ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { - $( - doc_comment! { - concat!("An integer that is known not to equal zero. - -This enables some memory layout optimization. -For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`: - -```rust -use std::mem::size_of; -assert_eq!(size_of::>(), size_of::<", stringify!($Int), -">()); -```"), - #[$stability] - #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] - #[repr(transparent)] - #[rustc_layout_scalar_valid_range_start(1)] - #[rustc_nonnull_optimization_guaranteed] - pub struct $Ty($Int); - } - - impl $Ty { - /// Creates a non-zero without checking the value. - /// - /// # Safety - /// - /// The value must not be zero. - #[$stability] - #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] - #[inline] - pub const unsafe fn new_unchecked(n: $Int) -> Self { - // SAFETY: this is guaranteed to be safe by the caller. - unsafe { Self(n) } - } - - /// Creates a non-zero if the given value is not zero. - #[$stability] - #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] - #[inline] - pub const fn new(n: $Int) -> Option { - if n != 0 { - // SAFETY: we just checked that there's no `0` - Some(unsafe { Self(n) }) - } else { - None - } - } - - /// Returns the value as a primitive type. - #[$stability] - #[inline] - #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] - pub const fn get(self) -> $Int { - self.0 - } - - } - - #[stable(feature = "from_nonzero", since = "1.31.0")] - impl From<$Ty> for $Int { - doc_comment! { - concat!( -"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"), - fn from(nonzero: $Ty) -> Self { - nonzero.0 - } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr for $Ty { - type Output = Self; - #[inline] - fn bitor(self, rhs: Self) -> Self::Output { - // Safety: since `self` and `rhs` are both nonzero, the - // result of the bitwise-or will be nonzero. - unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Int> for $Ty { - type Output = Self; - #[inline] - fn bitor(self, rhs: $Int) -> Self::Output { - // Safety: since `self` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `rhs`. - unsafe { $Ty::new_unchecked(self.get() | rhs) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOr<$Ty> for $Int { - type Output = $Ty; - #[inline] - fn bitor(self, rhs: $Ty) -> Self::Output { - // Safety: since `rhs` is nonzero, the result of the - // bitwise-or will be nonzero regardless of the value of - // `self`. - unsafe { $Ty::new_unchecked(self | rhs.get()) } - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: Self) { - *self = *self | rhs; - } - } - - #[stable(feature = "nonzero_bitor", since = "1.45.0")] - impl BitOrAssign<$Int> for $Ty { - #[inline] - fn bitor_assign(&mut self, rhs: $Int) { - *self = *self | rhs; - } - } - - impl_nonzero_fmt! { - #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty - } - )+ - } -} - -nonzero_integers! { - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); - #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); - #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); -} - -macro_rules! from_str_radix_nzint_impl { - ($($t:ty)*) => {$( - #[stable(feature = "nonzero_parse", since = "1.35.0")] - impl FromStr for $t { - type Err = ParseIntError; - fn from_str(src: &str) -> Result { - Self::new(from_str_radix(src, 10)?) - .ok_or(ParseIntError { - kind: IntErrorKind::Zero - }) - } - } - )*} -} - -from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize -NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } - -/// Provides intentionally-wrapped arithmetic on `T`. -/// -/// Operations like `+` on `u32` values are intended to never overflow, -/// and in some debug configurations overflow is detected and results -/// in a panic. While most arithmetic falls into this category, some -/// code explicitly expects and relies upon modular arithmetic (e.g., -/// hashing). -/// -/// Wrapping arithmetic can be achieved either through methods like -/// `wrapping_add`, or through the `Wrapping` type, which says that -/// all standard arithmetic operations on the underlying value are -/// intended to have wrapping semantics. -/// -/// The underlying value can be retrieved through the `.0` index of the -/// `Wrapping` tuple. -/// -/// # Examples -/// -/// ``` -/// use std::num::Wrapping; -/// -/// let zero = Wrapping(0u32); -/// let one = Wrapping(1u32); -/// -/// assert_eq!(u32::MAX, (zero - one).0); -/// ``` -#[stable(feature = "rust1", since = "1.0.0")] -#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] -#[repr(transparent)] -pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Debug for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_display", since = "1.10.0")] -impl fmt::Display for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::Binary for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::Octal for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::LowerHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - -#[stable(feature = "wrapping_fmt", since = "1.11.0")] -impl fmt::UpperHex for Wrapping { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.0.fmt(f) - } -} - // All these modules are technically private and only exposed for coretests: pub mod bignum; pub mod dec2flt; pub mod diy_float; pub mod flt2dec; +#[macro_use] +mod int_macros; // import int_impl! +#[macro_use] +mod uint_macros; // import uint_impl! + +mod error; +mod nonzero; mod wrapping; +#[stable(feature = "rust1", since = "1.0.0")] +pub use wrapping::Wrapping; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use dec2flt::ParseFloatError; + +#[stable(feature = "rust1", since = "1.0.0")] +pub use error::ParseIntError; + +#[stable(feature = "nonzero", since = "1.28.0")] +pub use nonzero::{NonZeroU128, NonZeroU16, NonZeroU32, NonZeroU64, NonZeroU8, NonZeroUsize}; + +#[stable(feature = "signed_nonzero", since = "1.34.0")] +pub use nonzero::{NonZeroI128, NonZeroI16, NonZeroI32, NonZeroI64, NonZeroI8, NonZeroIsize}; + +#[stable(feature = "try_from", since = "1.34.0")] +pub use error::TryFromIntError; + +#[unstable(feature = "int_error_matching", issue = "22639")] +pub use error::IntErrorKind; + macro_rules! usize_isize_to_xe_bytes_doc { () => { " @@ -313,2194 +88,6 @@ depending on the target pointer size. }; } -macro_rules! int_impl { - ($SelfT:ty, $ActualT:ident, $UnsignedT:ty, $BITS:expr, $Min:expr, $Max:expr, $Feature:expr, - $EndFeature: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) => { - doc_comment! { - concat!("The smallest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, ", stringify!($Min), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: Self = !0 ^ ((!0 as $UnsignedT) >> 1) as Self; - } - - doc_comment! { - concat!("The largest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($Max), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: Self = !Self::MIN; - } - - doc_comment! { - concat!("Converts a string slice in a given base to an integer. - -The string is expected to be an optional `+` or `-` sign followed by digits. -Leading and trailing whitespace represent an error. Digits are a subset of these characters, -depending on `radix`: - - * `0-9` - * `a-z` - * `A-Z` - -# Panics - -This function panics if `radix` is not in the range from 2 to 36. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - } - - doc_comment! { - concat!("Returns the number of ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b100_0000", stringify!($SelfT), "; - -assert_eq!(n.count_ones(), 1);", -$EndFeature, " -``` -"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn count_ones(self) -> u32 { (self as $UnsignedT).count_ones() } - } - - doc_comment! { - concat!("Returns the number of zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 1);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - - doc_comment! { - concat!("Returns the number of leading zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -1", stringify!($SelfT), "; - -assert_eq!(n.leading_zeros(), 0);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn leading_zeros(self) -> u32 { - (self as $UnsignedT).leading_zeros() - } - } - - doc_comment! { - concat!("Returns the number of trailing zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -4", stringify!($SelfT), "; - -assert_eq!(n.trailing_zeros(), 2);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn trailing_zeros(self) -> u32 { - (self as $UnsignedT).trailing_zeros() - } - } - - doc_comment! { - concat!("Returns the number of leading ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = -1", stringify!($SelfT), "; - -assert_eq!(n.leading_ones(), ", stringify!($BITS), ");", -$EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn leading_ones(self) -> u32 { - (self as $UnsignedT).leading_ones() - } - } - - doc_comment! { - concat!("Returns the number of trailing ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 3", stringify!($SelfT), "; - -assert_eq!(n.trailing_ones(), 2);", -$EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn trailing_ones(self) -> u32 { - (self as $UnsignedT).trailing_ones() - } - } - - doc_comment! { - concat!("Shifts the bits to the left by a specified amount, `n`, -wrapping the truncated bits to the end of the resulting integer. - -Please note this isn't the same operation as the `<<` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_op, stringify!($SelfT), "; -let m = ", $rot_result, "; - -assert_eq!(n.rotate_left(", $rot, "), m); -```"), - #[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] - pub const fn rotate_left(self, n: u32) -> Self { - (self as $UnsignedT).rotate_left(n) as Self - } - } - - doc_comment! { - concat!("Shifts the bits to the right by a specified amount, `n`, -wrapping the truncated bits to the beginning of the resulting -integer. - -Please note this isn't the same operation as the `>>` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_result, stringify!($SelfT), "; -let m = ", $rot_op, "; - -assert_eq!(n.rotate_right(", $rot, "), m); -```"), - #[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] - pub const fn rotate_right(self, n: u32) -> Self { - (self as $UnsignedT).rotate_right(n) as Self - } - } - - doc_comment! { - concat!("Reverses the byte order of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; - -let m = n.swap_bytes(); - -assert_eq!(m, ", $swapped, "); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn swap_bytes(self) -> Self { - (self as $UnsignedT).swap_bytes() as Self - } - } - - doc_comment! { - concat!("Reverses the bit pattern of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.reverse_bits(); - -assert_eq!(m, ", $reversed, "); -```"), - #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - #[must_use] - pub const fn reverse_bits(self) -> Self { - (self as $UnsignedT).reverse_bits() as Self - } - } - - doc_comment! { - concat!("Converts an integer from big endian to the target's endianness. - -On big endian this is a no-op. On little endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(", stringify!($SelfT), "::from_be(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - { - x - } - #[cfg(not(target_endian = "big"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts an integer from little endian to the target's endianness. - -On little endian this is a no-op. On big endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(", stringify!($SelfT), "::from_le(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - { - x - } - #[cfg(not(target_endian = "little"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to big endian from the target's endianness. - -On big endian this is a no-op. On little endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(n.to_be(), n) -} else { - assert_eq!(n.to_be(), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn to_be(self) -> Self { // or not to be? - #[cfg(target_endian = "big")] - { - self - } - #[cfg(not(target_endian = "big"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to little endian from the target's endianness. - -On little endian this is a no-op. On big endian the bytes are swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(n.to_le(), n) -} else { - assert_eq!(n.to_le(), n.swap_bytes()) -}", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_conversions", since = "1.32.0")] - #[inline] - pub const fn to_le(self) -> Self { - #[cfg(target_endian = "little")] - { - self - } - #[cfg(not(target_endian = "little"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Checked integer addition. Computes `self + rhs`, returning `None` -if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MAX - 2).checked_add(1), Some(", stringify!($SelfT), "::MAX - 1)); -assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.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_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer subtraction. Computes `self - rhs`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MIN + 2).checked_sub(1), Some(", stringify!($SelfT), "::MIN + 1)); -assert_eq!((", stringify!($SelfT), "::MIN + 2).checked_sub(3), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.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_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer multiplication. Computes `self * rhs`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), -"::MAX.checked_mul(1), Some(", stringify!($SelfT), "::MAX)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.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_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer division. Computes `self / rhs`, returning `None` if `rhs == 0` -or the division results in overflow. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), -"::MIN + 1).checked_div(-1), Some(", stringify!($Max), ")); -assert_eq!(", stringify!($SelfT), "::MIN.checked_div(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div(0), None);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - // SAFETY: div by zero and by INT_MIN have been checked above - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, -returning `None` if `rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -assert_eq!((", stringify!($SelfT), -"::MIN + 1).checked_div_euclid(-1), Some(", stringify!($Max), ")); -assert_eq!(", stringify!($SelfT), "::MIN.checked_div_euclid(-1), None); -assert_eq!((1", stringify!($SelfT), ").checked_div_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - Some(self.div_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked integer remainder. Computes `self % rhs`, returning `None` if -`rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_rem(-1), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - // SAFETY: div by zero and by INT_MIN have been checked above - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean remainder. Computes `self.rem_euclid(rhs)`, returning `None` -if `rhs == 0` or the division results in overflow. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); -assert_eq!(", stringify!($SelfT), "::MIN.checked_rem_euclid(-1), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0 || (self == Self::MIN && rhs == -1)) { - None - } else { - Some(self.rem_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked negation. Computes `-self`, returning `None` if `self == MIN`. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".checked_neg(), Some(-5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_neg(), None);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift left. Computes `self << rhs`, returning `None` if `rhs` is larger -than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); -assert_eq!(0x1", stringify!($SelfT), ".checked_shl(129), None);", -$EndFeature, " -```"), - #[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_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift right. Computes `self >> rhs`, returning `None` if `rhs` is -larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(128), None);", -$EndFeature, " -```"), - #[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_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked absolute value. Computes `self.abs()`, returning `None` if -`self == MIN`. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!((-5", stringify!($SelfT), ").checked_abs(), Some(5)); -assert_eq!(", stringify!($SelfT), "::MIN.checked_abs(), None);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_abs(self) -> Option { - if self.is_negative() { - self.checked_neg() - } else { - Some(self) - } - } - } - - doc_comment! { - concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(8", stringify!($SelfT), ".checked_pow(2), Some(64)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", -$EndFeature, " -```"), - - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_pow(self, mut exp: u32) -> Option { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); - } - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - Some(try_opt!(acc.checked_mul(base))) - } - } - - doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at the numeric -bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(100), ", stringify!($SelfT), -"::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_add(-1), ", stringify!($SelfT), -"::MIN);", -$EndFeature, " -```"), - - #[stable(feature = "rust1", since = "1.0.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_add(self, rhs: Self) -> Self { - intrinsics::saturating_add(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating at the -numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(127), -27); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_sub(100), ", stringify!($SelfT), -"::MIN); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_sub(-1), ", stringify!($SelfT), -"::MAX);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.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_sub(self, rhs: Self) -> Self { - intrinsics::saturating_sub(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer negation. Computes `-self`, returning `MAX` if `self == MIN` -instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_neg(), -100); -assert_eq!((-100", stringify!($SelfT), ").saturating_neg(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_neg(), ", stringify!($SelfT), -"::MAX); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_neg(), ", stringify!($SelfT), -"::MIN + 1);", -$EndFeature, " -```"), - - #[stable(feature = "saturating_neg", since = "1.45.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_neg(self) -> Self { - intrinsics::saturating_sub(0, self) - } - } - - doc_comment! { - concat!("Saturating absolute value. Computes `self.abs()`, returning `MAX` if `self == -MIN` instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_abs(), 100); -assert_eq!((-100", stringify!($SelfT), ").saturating_abs(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_abs(), ", stringify!($SelfT), -"::MAX); -assert_eq!((", stringify!($SelfT), "::MIN + 1).saturating_abs(), ", stringify!($SelfT), -"::MAX);", -$EndFeature, " -```"), - - #[stable(feature = "saturating_neg", since = "1.45.0")] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_abs(self) -> Self { - if self.is_negative() { - self.saturating_neg() - } else { - self - } - } - } - - doc_comment! { - concat!("Saturating integer multiplication. Computes `self * rhs`, saturating at the -numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(10", stringify!($SelfT), ".saturating_mul(12), 120); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_mul(10), ", stringify!($SelfT), "::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_mul(10), ", stringify!($SelfT), "::MIN);", -$EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.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_mul(self, rhs: Self) -> Self { - match self.checked_mul(rhs) { - Some(x) => x, - None => if (self < 0) == (rhs < 0) { - Self::MAX - } else { - Self::MIN - } - } - } - } - - doc_comment! { - concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!((-4", stringify!($SelfT), ").saturating_pow(3), -64); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(2), ", stringify!($SelfT), "::MAX); -assert_eq!(", stringify!($SelfT), "::MIN.saturating_pow(3), ", stringify!($SelfT), "::MIN);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Some(x) => x, - None if self < 0 && exp % 2 == 1 => Self::MIN, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Wrapping (modular) addition. Computes `self + rhs`, wrapping around at the -boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_add(27), 127); -assert_eq!(", stringify!($SelfT), "::MAX.wrapping_add(2), ", stringify!($SelfT), -"::MIN + 1);", -$EndFeature, " -```"), - #[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] - pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::wrapping_add(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) subtraction. Computes `self - rhs`, wrapping around at the -boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".wrapping_sub(127), -127); -assert_eq!((-2", stringify!($SelfT), ").wrapping_sub(", stringify!($SelfT), "::MAX), ", -stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - #[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] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::wrapping_sub(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) multiplication. Computes `self * rhs`, wrapping around at -the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".wrapping_mul(12), 120); -assert_eq!(11i8.wrapping_mul(12), -124);", -$EndFeature, " -```"), - #[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] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::wrapping_mul(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) division. Computes `self / rhs`, wrapping around at the -boundary of the type. - -The only case where such wrapping can occur is when one divides `MIN / -1` on a signed type (where -`MIN` is the negative minimal value for the type); this is equivalent to `-MIN`, a positive value -that is too large to represent in the type. In such a case, this function returns `MIN` itself. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10); -assert_eq!((-128i8).wrapping_div(-1), -128);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - self.overflowing_div(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`, -wrapping around at the boundary of the type. - -Wrapping will only occur in `MIN / -1` on a signed type (where `MIN` is the negative minimal value -for the type). This is equivalent to `-MIN`, a positive value that is too large to represent in the -type. In this case, this method returns `MIN` itself. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); -assert_eq!((-128i8).wrapping_div_euclid(-1), -128); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self.overflowing_div_euclid(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping (modular) remainder. Computes `self % rhs`, wrapping around at the -boundary of the type. - -Such wrap-around never actually occurs mathematically; implementation artifacts make `x % y` -invalid for `MIN / -1` on a signed type (where `MIN` is the negative minimal value). In such a case, -this function returns `0`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0); -assert_eq!((-128i8).wrapping_rem(-1), 0);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - self.overflowing_rem(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping Euclidean remainder. Computes `self.rem_euclid(rhs)`, wrapping around -at the boundary of the type. - -Wrapping will only occur in `MIN % -1` on a signed type (where `MIN` is the negative minimal value -for the type). In this case, this method returns 0. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); -assert_eq!((-128i8).wrapping_rem_euclid(-1), 0); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { - self.overflowing_rem_euclid(rhs).0 - } - } - - doc_comment! { - concat!("Wrapping (modular) negation. Computes `-self`, wrapping around at the boundary -of the type. - -The only case where such wrapping can occur is when one negates `MIN` on a signed type (where `MIN` -is the negative minimal value for the type); this is a positive value that is too large to represent -in the type. In such a case, this function returns `MIN` itself. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_neg(), -100); -assert_eq!(", stringify!($SelfT), "::MIN.wrapping_neg(), ", stringify!($SelfT), -"::MIN);", -$EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, where `mask` removes -any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-left; the RHS of a wrapping shift-left is restricted to -the range of the type, rather than the bits shifted out of the LHS being returned to the other end. -The primitive integer types all implement a `[`rotate_left`](#method.rotate_left) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(7), -128); -assert_eq!((-1", stringify!($SelfT), ").wrapping_shl(128), -1);", -$EndFeature, " -```"), - #[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] - pub const fn wrapping_shl(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, where `mask` -removes any high-order bits of `rhs` that would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-right; the RHS of a wrapping shift-right is restricted -to the range of the type, rather than the bits shifted out of the LHS being returned to the other -end. The primitive integer types all implement a [`rotate_right`](#method.rotate_right) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((-128", stringify!($SelfT), ").wrapping_shr(7), -1); -assert_eq!((-128i16).wrapping_shr(64), -128);", -$EndFeature, " -```"), - #[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] - pub const fn wrapping_shr(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Wrapping (modular) absolute value. Computes `self.abs()`, wrapping around at -the boundary of the type. - -The only case where such wrapping can occur is when one takes the absolute value of the negative -minimal value for the type; this is a positive value that is too large to represent in the type. In -such a case, this function returns `MIN` itself. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_abs(), 100); -assert_eq!((-100", stringify!($SelfT), ").wrapping_abs(), 100); -assert_eq!(", stringify!($SelfT), "::MIN.wrapping_abs(), ", stringify!($SelfT), -"::MIN); -assert_eq!((-128i8).wrapping_abs() as u8, 128);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - #[inline] - pub const fn wrapping_abs(self) -> Self { - if self.is_negative() { - self.wrapping_neg() - } else { - self - } - } - } - - doc_comment! { - concat!("Computes the absolute value of `self` without any wrapping -or panicking. - - -# Examples - -Basic usage: - -``` -", $Feature, "#![feature(unsigned_abs)] -assert_eq!(100", stringify!($SelfT), ".unsigned_abs(), 100", stringify!($UnsignedT), "); -assert_eq!((-100", stringify!($SelfT), ").unsigned_abs(), 100", stringify!($UnsignedT), "); -assert_eq!((-128i8).unsigned_abs(), 128u8);", -$EndFeature, " -```"), - #[unstable(feature = "unsigned_abs", issue = "74913")] - #[inline] - pub const fn unsigned_abs(self) -> $UnsignedT { - self.wrapping_abs() as $UnsignedT - } - } - - doc_comment! { - concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(4), 81); -assert_eq!(3i8.wrapping_pow(5), -13); -assert_eq!(3i8.wrapping_pow(6), -39);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) - } - } - - doc_comment! { - concat!("Calculates `self` + `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, " -assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (", stringify!($SelfT), -"::MIN, true));", $EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates `self` - `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, " -assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_sub(1), (", stringify!($SelfT), -"::MAX, true));", $EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates the multiplication of `self` and `rhs`. - -Returns a tuple of the multiplication 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, "assert_eq!(5", stringify!($SelfT), ".overflowing_mul(2), (10, false)); -assert_eq!(1_000_000_000i32.overflowing_mul(10), (1410065408, true));", -$EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates the divisor when `self` is divided by `rhs`. - -Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would occur then self is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div(-1), (", stringify!($SelfT), -"::MIN, true));", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[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) { - (self, true) - } else { - (self / rhs, false) - } - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. - -Returns a tuple of the divisor along with a boolean indicating whether an arithmetic overflow would -occur. If an overflow would occur then `self` is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_div_euclid(-1), (", stringify!($SelfT), -"::MIN, true)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[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) { - (self, true) - } else { - (self.div_euclid(rhs), false) - } - } - } - - doc_comment! { - concat!("Calculates the remainder when `self` is divided by `rhs`. - -Returns a tuple of the remainder after dividing along with a boolean indicating whether an -arithmetic overflow would occur. If an overflow would occur then 0 is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem(-1), (0, true));", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[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) - } else { - (self % rhs, false) - } - } - } - - - doc_comment! { - concat!("Overflowing Euclidean remainder. Calculates `self.rem_euclid(rhs)`. - -Returns a tuple of the remainder after dividing along with a boolean indicating whether an -arithmetic overflow would occur. If an overflow would occur then 0 is returned. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_rem_euclid(-1), (0, true)); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - 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) - } else { - (self.rem_euclid(rhs), false) - } - } - } - - - doc_comment! { - concat!("Negates self, overflowing if this is equal to the minimum value. - -Returns a tuple of the negated version of self along with a boolean indicating whether an overflow -happened. If `self` is the minimum value (e.g., `i32::MIN` for values of type `i32`), then the -minimum value will be returned again and `true` will be returned for an overflow happening. - -# Examples - -Basic usage: - -``` -assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2, false)); -assert_eq!(", stringify!($SelfT), "::MIN.overflowing_neg(), (", stringify!($SelfT), -"::MIN, true));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - pub const fn overflowing_neg(self) -> (Self, bool) { - if unlikely!(self == Self::MIN) { - (Self::MIN, true) - } else { - (-self, false) - } - } - } - - doc_comment! { - concat!("Shifts self left by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean indicating whether the shift -value was larger than or equal to the number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then used to perform the shift. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT),".overflowing_shl(4), (0x10, false)); -assert_eq!(0x1i32.overflowing_shl(36), (0x10, true));", -$EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Shifts self right by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean indicating whether the shift -value was larger than or equal to the number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then used to perform the shift. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10i32.overflowing_shr(36), (0x1, true));", -$EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Computes the absolute value of `self`. - -Returns a tuple of the absolute version of self along with a boolean indicating whether an overflow -happened. If self is the minimum value (e.g., ", stringify!($SelfT), "::MIN for values of type - ", stringify!($SelfT), "), then the minimum value will be returned again and true will be returned -for an overflow happening. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".overflowing_abs(), (10, false)); -assert_eq!((-10", stringify!($SelfT), ").overflowing_abs(), (10, false)); -assert_eq!((", stringify!($SelfT), "::MIN).overflowing_abs(), (", stringify!($SelfT), -"::MIN, true));", -$EndFeature, " -```"), - #[stable(feature = "no_panic_abs", since = "1.13.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn overflowing_abs(self) -> (Self, bool) { - (self.wrapping_abs(), self == Self::MIN) - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -Returns a tuple of the exponentiation along with a bool indicating -whether an overflow happened. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(4), (81, false)); -assert_eq!(3i8.overflowing_pow(5), (-13, true));", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - if exp == 0 { - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; - overflown |= r.1; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - r - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -# Examples - -Basic usage: - -``` -", $Feature, "let x: ", stringify!($SelfT), " = 2; // or any other integer type - -assert_eq!(x.pow(5), 32);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division of `self` by `rhs`. - -This computes the integer `n` such that `self = n * rhs + self.rem_euclid(rhs)`, -with `0 <= self.rem_euclid(rhs) < rhs`. - -In other words, the result is `self / rhs` rounded to the integer `n` -such that `self >= n * rhs`. -If `self > 0`, this is equal to round towards zero (the default in Rust); -if `self < 0`, this is equal to round towards +/- infinity. - -# Panics - -This function will panic if `rhs` is 0 or the division results in overflow. - -# Examples - -Basic usage: - -``` -let a: ", stringify!($SelfT), " = 7; // or any other integer type -let b = 4; - -assert_eq!(a.div_euclid(b), 1); // 7 >= 4 * 1 -assert_eq!(a.div_euclid(-b), -1); // 7 >= -4 * -1 -assert_eq!((-a).div_euclid(b), -2); // -7 >= 4 * -2 -assert_eq!((-a).div_euclid(-b), 2); // -7 >= -4 * 2 -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn div_euclid(self, rhs: Self) -> Self { - let q = self / rhs; - if self % rhs < 0 { - return if rhs > 0 { q - 1 } else { q + 1 } - } - q - } - } - - - doc_comment! { - concat!("Calculates the least nonnegative remainder of `self (mod rhs)`. - -This is done as if by the Euclidean division algorithm -- given -`r = self.rem_euclid(rhs)`, `self = rhs * self.div_euclid(rhs) + r`, and -`0 <= r < abs(rhs)`. - -# Panics - -This function will panic if `rhs` is 0 or the division results in overflow. - -# Examples - -Basic usage: - -``` -let a: ", stringify!($SelfT), " = 7; // or any other integer type -let b = 4; - -assert_eq!(a.rem_euclid(b), 3); -assert_eq!((-a).rem_euclid(b), 1); -assert_eq!(a.rem_euclid(-b), 3); -assert_eq!((-a).rem_euclid(-b), 1); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn rem_euclid(self, rhs: Self) -> Self { - let r = self % rhs; - if r < 0 { - if rhs < 0 { - r - rhs - } else { - r + rhs - } - } else { - r - } - } - } - - doc_comment! { - concat!("Computes the absolute value of `self`. - -# Overflow behavior - -The absolute value of `", stringify!($SelfT), "::MIN` cannot be represented as an -`", stringify!($SelfT), "`, and attempting to calculate it will cause an overflow. This means that -code in debug mode will trigger a panic on this case and optimized code will return `", -stringify!($SelfT), "::MIN` without a panic. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".abs(), 10); -assert_eq!((-10", stringify!($SelfT), ").abs(), 10);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[allow(unused_attributes)] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn abs(self) -> Self { - // Note that the #[inline] above means that the overflow - // semantics of the subtraction depend on the crate we're being - // inlined into. - if self.is_negative() { - -self - } else { - self - } - } - } - - doc_comment! { - concat!("Returns a number representing sign of `self`. - - - `0` if the number is zero - - `1` if the number is positive - - `-1` if the number is negative - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(10", stringify!($SelfT), ".signum(), 1); -assert_eq!(0", stringify!($SelfT), ".signum(), 0); -assert_eq!((-10", stringify!($SelfT), ").signum(), -1);", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_sign", since = "1.47.0")] - #[inline] - pub const fn signum(self) -> Self { - match self { - n if n > 0 => 1, - 0 => 0, - _ => -1, - } - } - } - - doc_comment! { - concat!("Returns `true` if `self` is positive and `false` if the number is zero or -negative. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!(10", stringify!($SelfT), ".is_positive()); -assert!(!(-10", stringify!($SelfT), ").is_positive());", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn is_positive(self) -> bool { self > 0 } - } - - doc_comment! { - concat!("Returns `true` if `self` is negative and `false` if the number is zero or -positive. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!((-10", stringify!($SelfT), ").is_negative()); -assert!(!10", stringify!($SelfT), ".is_negative());", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_int_methods", since = "1.32.0")] - #[inline] - pub const fn is_negative(self) -> bool { self < 0 } - } - - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -big-endian (network) byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); -assert_eq!(bytes, ", $be_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { - self.to_be().to_ne_bytes() - } - } - -doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -little-endian byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); -assert_eq!(bytes, ", $le_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { - self.to_le().to_ne_bytes() - } - } - - doc_comment! { - concat!(" -Return the memory representation of this integer as a byte array in -native byte order. - -As the target platform's native endianness is used, portable code -should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, -instead. -", -$to_xe_bytes_doc, -" -[`to_be_bytes`]: #method.to_be_bytes -[`to_le_bytes`]: #method.to_le_bytes - -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!( - bytes, - if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - } -); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[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 - #[allow_internal_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 - // arrays of bytes - unsafe { mem::transmute(self) } - } - } - -doc_comment! { - concat!("Create an integer value from its representation as a byte array in -big endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_be(Self::from_ne_bytes(bytes)) - } - } - -doc_comment! { - concat!(" -Create an integer value from its representation as a byte array in -little endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_le(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!("Create an integer value from its memory representation as a byte -array in native endianness. - -As the target platform's native endianness is used, portable code -likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as -appropriate instead. - -[`from_be_bytes`]: #method.from_be_bytes -[`from_le_bytes`]: #method.from_le_bytes -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " -} else { - ", $le_bytes, " -}); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[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 to them - #[allow_internal_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 - unsafe { mem::transmute(bytes) } - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. - -Returns the smallest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - #[rustc_promotable] - #[rustc_const_stable(feature = "const_min_value", since = "1.32.0")] - pub const fn min_value() -> Self { - Self::MIN - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. - -Returns the largest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[inline(always)] - #[rustc_promotable] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn max_value() -> Self { - Self::MAX - } - } - } -} - #[lang = "i8"] impl i8 { int_impl! { i8, i8, u8, 8, -128, 127, "", "", 2, "-0x7e", "0xa", "0x12", "0x12", "0x48", @@ -2567,1948 +154,6 @@ impl isize { usize_isize_to_xe_bytes_doc!(), usize_isize_from_xe_bytes_doc!() } } -macro_rules! uint_impl { - ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature: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) => { - doc_comment! { - concat!("The smallest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MIN: Self = 0; - } - - doc_comment! { - concat!("The largest value that can be represented by this integer type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");", -$EndFeature, " -```"), - #[stable(feature = "assoc_int_consts", since = "1.43.0")] - pub const MAX: Self = !0; - } - - doc_comment! { - concat!("Converts a string slice in a given base to an integer. - -The string is expected to be an optional `+` sign -followed by digits. -Leading and trailing whitespace represent an error. -Digits are a subset of these characters, depending on `radix`: - -* `0-9` -* `a-z` -* `A-Z` - -# Panics - -This function panics if `radix` is not in the range from 2 to 36. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", -$EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - pub fn from_str_radix(src: &str, radix: u32) -> Result { - from_str_radix(src, radix) - } - } - - doc_comment! { - concat!("Returns the number of ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b01001100", stringify!($SelfT), "; - -assert_eq!(n.count_ones(), 3);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn count_ones(self) -> u32 { - intrinsics::ctpop(self as $ActualT) as u32 - } - } - - doc_comment! { - concat!("Returns the number of zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn count_zeros(self) -> u32 { - (!self).count_ones() - } - } - - doc_comment! { - concat!("Returns the number of leading zeros in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2; - -assert_eq!(n.leading_zeros(), 2);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn leading_zeros(self) -> u32 { - intrinsics::ctlz(self as $ActualT) as u32 - } - } - - doc_comment! { - concat!("Returns the number of trailing zeros in the binary representation -of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b0101000", stringify!($SelfT), "; - -assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn trailing_zeros(self) -> u32 { - intrinsics::cttz(self) as u32 - } - } - - doc_comment! { - concat!("Returns the number of leading ones in the binary representation of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2); - -assert_eq!(n.leading_ones(), 2);", $EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn leading_ones(self) -> u32 { - (!self).leading_zeros() - } - } - - doc_comment! { - concat!("Returns the number of trailing ones in the binary representation -of `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0b1010111", stringify!($SelfT), "; - -assert_eq!(n.trailing_ones(), 3);", $EndFeature, " -```"), - #[stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] - #[inline] - pub const fn trailing_ones(self) -> u32 { - (!self).trailing_zeros() - } - } - - doc_comment! { - concat!("Shifts the bits to the left by a specified amount, `n`, -wrapping the truncated bits to the end of the resulting integer. - -Please note this isn't the same operation as the `<<` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_op, stringify!($SelfT), "; -let m = ", $rot_result, "; - -assert_eq!(n.rotate_left(", $rot, "), m); -```"), - #[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] - pub const fn rotate_left(self, n: u32) -> Self { - intrinsics::rotate_left(self, n as $SelfT) - } - } - - doc_comment! { - concat!("Shifts the bits to the right by a specified amount, `n`, -wrapping the truncated bits to the beginning of the resulting -integer. - -Please note this isn't the same operation as the `>>` shifting operator! - -# Examples - -Basic usage: - -``` -let n = ", $rot_result, stringify!($SelfT), "; -let m = ", $rot_op, "; - -assert_eq!(n.rotate_right(", $rot, "), m); -```"), - #[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] - pub const fn rotate_right(self, n: u32) -> Self { - intrinsics::rotate_right(self, n as $SelfT) - } - } - - doc_comment! { - concat!(" -Reverses the byte order of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.swap_bytes(); - -assert_eq!(m, ", $swapped, "); -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn swap_bytes(self) -> Self { - intrinsics::bswap(self as $ActualT) as Self - } - } - - doc_comment! { - concat!("Reverses the bit pattern of the integer. - -# Examples - -Basic usage: - -``` -let n = ", $swap_op, stringify!($SelfT), "; -let m = n.reverse_bits(); - -assert_eq!(m, ", $reversed, "); -```"), - #[stable(feature = "reverse_bits", since = "1.37.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - #[must_use] - pub const fn reverse_bits(self) -> Self { - intrinsics::bitreverse(self as $ActualT) as Self - } - } - - doc_comment! { - concat!("Converts an integer from big endian to the target's endianness. - -On big endian this is a no-op. On little endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(", stringify!($SelfT), "::from_be(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn from_be(x: Self) -> Self { - #[cfg(target_endian = "big")] - { - x - } - #[cfg(not(target_endian = "big"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts an integer from little endian to the target's endianness. - -On little endian this is a no-op. On big endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(", stringify!($SelfT), "::from_le(n), n) -} else { - assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn from_le(x: Self) -> Self { - #[cfg(target_endian = "little")] - { - x - } - #[cfg(not(target_endian = "little"))] - { - x.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to big endian from the target's endianness. - -On big endian this is a no-op. On little endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"big\") { - assert_eq!(n.to_be(), n) -} else { - assert_eq!(n.to_be(), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn to_be(self) -> Self { // or not to be? - #[cfg(target_endian = "big")] - { - self - } - #[cfg(not(target_endian = "big"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Converts `self` to little endian from the target's endianness. - -On little endian this is a no-op. On big endian the bytes are -swapped. - -# Examples - -Basic usage: - -``` -", $Feature, "let n = 0x1A", stringify!($SelfT), "; - -if cfg!(target_endian = \"little\") { - assert_eq!(n.to_le(), n) -} else { - assert_eq!(n.to_le(), n.swap_bytes()) -}", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_math", since = "1.32.0")] - #[inline] - pub const fn to_le(self) -> Self { - #[cfg(target_endian = "little")] - { - self - } - #[cfg(not(target_endian = "little"))] - { - self.swap_bytes() - } - } - } - - doc_comment! { - concat!("Checked integer addition. Computes `self + rhs`, returning `None` -if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ", -"Some(", stringify!($SelfT), "::MAX - 1)); -assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.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_add(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_add(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), -"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_add(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_add`. - unsafe { intrinsics::unchecked_add(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer subtraction. Computes `self - rhs`, returning -`None` if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); -assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.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_sub(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_sub(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), -"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_sub`. - unsafe { intrinsics::unchecked_sub(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer multiplication. Computes `self * rhs`, returning -`None` if overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.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_mul(self, rhs: Self) -> Option { - let (a, b) = self.overflowing_mul(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow -cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), -"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), - #[unstable( - feature = "unchecked_math", - reason = "niche optimization path", - issue = "none", - )] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { - // SAFETY: the caller must uphold the safety contract for - // `unchecked_mul`. - unsafe { intrinsics::unchecked_mul(self, rhs) } - } - } - - doc_comment! { - concat!("Checked integer division. Computes `self / rhs`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - // SAFETY: div by zero has been checked above and unsigned types have no other - // failure modes for division - Some(unsafe { intrinsics::unchecked_div(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); -assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_div_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - Some(self.div_euclid(rhs)) - } - } - } - - - doc_comment! { - concat!("Checked integer remainder. Computes `self % rhs`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - // SAFETY: div by zero has been checked above and unsigned types have no other - // failure modes for division - Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) - } - } - } - - doc_comment! { - concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` -if `rhs == 0`. - -# Examples - -Basic usage: - -``` -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); -assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_rem_euclid(self, rhs: Self) -> Option { - if unlikely!(rhs == 0) { - None - } else { - Some(self.rem_euclid(rhs)) - } - } - } - - doc_comment! { - concat!("Checked negation. Computes `-self`, returning `None` unless `self == -0`. - -Note that negating any positive integer will overflow. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); -assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] - #[inline] - pub const fn checked_neg(self) -> Option { - let (a, b) = self.overflowing_neg(); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift left. Computes `self << rhs`, returning `None` -if `rhs` is larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " -```"), - #[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_shl(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shl(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked shift right. Computes `self >> rhs`, returning `None` -if `rhs` is larger than or equal to the number of bits in `self`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); -assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " -```"), - #[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_shr(self, rhs: u32) -> Option { - let (a, b) = self.overflowing_shr(rhs); - if unlikely!(b) {None} else {Some(a)} - } - } - - doc_comment! { - concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if -overflow occurred. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn checked_pow(self, mut exp: u32) -> Option { - if exp == 0 { - return Some(1); - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = try_opt!(acc.checked_mul(base)); - } - exp /= 2; - base = try_opt!(base.checked_mul(base)); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - - Some(try_opt!(acc.checked_mul(base))) - } - } - - doc_comment! { - concat!("Saturating integer addition. Computes `self + rhs`, saturating at -the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_add(self, rhs: Self) -> Self { - intrinsics::saturating_add(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer subtraction. Computes `self - rhs`, saturating -at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); -assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] - #[inline] - pub const fn saturating_sub(self, rhs: Self) -> Self { - intrinsics::saturating_sub(self, rhs) - } - } - - doc_comment! { - concat!("Saturating integer multiplication. Computes `self * rhs`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20); -assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT), -"::MAX);", $EndFeature, " -```"), - #[stable(feature = "wrapping", since = "1.7.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_mul(self, rhs: Self) -> Self { - match self.checked_mul(rhs) { - Some(x) => x, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, -saturating at the numeric bounds instead of overflowing. - -# Examples - -Basic usage: - -``` -", $Feature, " -assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); -assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", -$EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn saturating_pow(self, exp: u32) -> Self { - match self.checked_pow(exp) { - Some(x) => x, - None => Self::MAX, - } - } - } - - doc_comment! { - concat!("Wrapping (modular) addition. Computes `self + rhs`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); -assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);", -$EndFeature, " -```"), - #[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"] - #[inline] - pub const fn wrapping_add(self, rhs: Self) -> Self { - intrinsics::wrapping_add(self, rhs) - } - } - - doc_comment! { - concat!("Wrapping (modular) subtraction. Computes `self - rhs`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0); -assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);", -$EndFeature, " -```"), - #[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"] - #[inline] - pub const fn wrapping_sub(self, rhs: Self) -> Self { - intrinsics::wrapping_sub(self, rhs) - } - } - - /// Wrapping (modular) multiplication. Computes `self * - /// rhs`, wrapping around at the boundary of the type. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u8` is used here. - /// - /// ``` - /// assert_eq!(10u8.wrapping_mul(12), 120); - /// assert_eq!(25u8.wrapping_mul(12), 44); - /// ``` - #[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"] - #[inline] - pub const fn wrapping_mul(self, rhs: Self) -> Self { - intrinsics::wrapping_mul(self, rhs) - } - - doc_comment! { - concat!("Wrapping (modular) division. Computes `self / rhs`. -Wrapped division on unsigned types is just normal division. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div(self, rhs: Self) -> Self { - self / rhs - } - } - - doc_comment! { - concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. -Wrapped division on unsigned types is just normal division. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.wrapping_div(rhs)`. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { - self / rhs - } - } - - doc_comment! { - concat!("Wrapping (modular) remainder. Computes `self % rhs`. -Wrapped remainder calculation on unsigned types is -just the regular remainder calculation. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " -```"), - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem(self, rhs: Self) -> Self { - self % rhs - } - } - - doc_comment! { - concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. -Wrapped modulo calculation on unsigned types is -just the regular remainder calculation. -There's no way wrapping could ever happen. -This function exists, so that all operations -are accounted for in the wrapping operations. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.wrapping_rem(rhs)`. - -# Examples - -Basic usage: - -``` -assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { - self % rhs - } - } - - /// Wrapping (modular) negation. Computes `-self`, - /// wrapping around at the boundary of the type. - /// - /// Since unsigned types do not have negative equivalents - /// all applications of this function will wrap (except for `-0`). - /// For values smaller than the corresponding signed type's maximum - /// the result is the same as casting the corresponding signed value. - /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where - /// `MAX` is the corresponding signed type's maximum. - /// - /// # Examples - /// - /// Basic usage: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `i8` is used here. - /// - /// ``` - /// assert_eq!(100i8.wrapping_neg(), -100); - /// assert_eq!((-128i8).wrapping_neg(), -128); - /// ``` - #[stable(feature = "num_wrapping", since = "1.2.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - #[inline] - pub const fn wrapping_neg(self) -> Self { - self.overflowing_neg().0 - } - - doc_comment! { - concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, -where `mask` removes any high-order bits of `rhs` that -would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-left; the -RHS of a wrapping shift-left is restricted to the range -of the type, rather than the bits shifted out of the LHS -being returned to the other end. The primitive integer -types all implement a [`rotate_left`](#method.rotate_left) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); -assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " -```"), - #[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] - pub const fn wrapping_shl(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, -where `mask` removes any high-order bits of `rhs` that -would cause the shift to exceed the bitwidth of the type. - -Note that this is *not* the same as a rotate-right; the -RHS of a wrapping shift-right is restricted to the range -of the type, rather than the bits shifted out of the LHS -being returned to the other end. The primitive integer -types all implement a [`rotate_right`](#method.rotate_right) function, -which may be what you want instead. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); -assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " -```"), - #[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] - pub const fn wrapping_shr(self, rhs: u32) -> Self { - // SAFETY: the masking by the bitsize of the type ensures that we do not shift - // out of bounds - unsafe { - intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) - } - } - } - - doc_comment! { - concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, -wrapping around at the boundary of the type. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); -assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn wrapping_pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc: Self = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc.wrapping_mul(base); - } - exp /= 2; - base = base.wrapping_mul(base); - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc.wrapping_mul(base) - } - } - - doc_comment! { - concat!("Calculates `self` + `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, " -assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); -assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - doc_comment! { - concat!("Calculates `self` - `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, " -assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); -assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));", -$EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - } - - /// Calculates the multiplication of `self` and `rhs`. - /// - /// Returns a tuple of the multiplication 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: - /// - /// Please note that this example is shared between integer types. - /// Which explains why `u32` is used here. - /// - /// ``` - /// assert_eq!(5u32.overflowing_mul(2), (10, false)); - /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); - /// ``` - #[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"] - #[inline] - pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { - let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); - (a as Self, b) - } - - doc_comment! { - concat!("Calculates the divisor when `self` is divided by `rhs`. - -Returns a tuple of the divisor along with a boolean indicating -whether an arithmetic overflow would occur. Note that for unsigned -integers overflow never occurs, so the second value is always -`false`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { - (self / rhs, false) - } - } - - doc_comment! { - concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. - -Returns a tuple of the divisor along with a boolean indicating -whether an arithmetic overflow would occur. Note that for unsigned -integers overflow never occurs, so the second value is always -`false`. -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self.overflowing_div(rhs)`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { - (self / rhs, false) - } - } - - doc_comment! { - concat!("Calculates the remainder when `self` is divided by `rhs`. - -Returns a tuple of the remainder after dividing along with a boolean -indicating whether an arithmetic overflow would occur. Note that for -unsigned integers overflow never occurs, so the second value is -always `false`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { - (self % rhs, false) - } - } - - doc_comment! { - concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. - -Returns a tuple of the modulo after dividing along with a boolean -indicating whether an arithmetic overflow would occur. Note that for -unsigned integers overflow never occurs, so the second value is -always `false`. -Since, for the positive integers, all common -definitions of division are equal, this operation -is exactly equal to `self.overflowing_rem(rhs)`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage - -``` -assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); -```"), - #[inline] - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { - (self % rhs, false) - } - } - - doc_comment! { - concat!("Negates self in an overflowing fashion. - -Returns `!self + 1` using wrapping operations to return the value -that represents the negation of this unsigned value. Note that for -positive unsigned values overflow always occurs, but negating 0 does -not overflow. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); -assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), -", true));", $EndFeature, " -```"), - #[inline] - #[stable(feature = "wrapping", since = "1.7.0")] - #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] - pub const fn overflowing_neg(self) -> (Self, bool) { - ((!self).wrapping_add(1), self != 0) - } - } - - doc_comment! { - concat!("Shifts self left by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean -indicating whether the shift value was larger than or equal to the -number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then -used to perform the shift. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false)); -assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Shifts self right by `rhs` bits. - -Returns a tuple of the shifted version of self along with a boolean -indicating whether the shift value was larger than or equal to the -number of bits. If the shift value is too large, then value is -masked (N-1) where N is the number of bits, and this value is then -used to perform the shift. - -# Examples - -Basic usage - -``` -", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); -assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " -```"), - #[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"] - #[inline] - pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { - (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -Returns a tuple of the exponentiation along with a bool indicating -whether an overflow happened. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); -assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " -```"), - #[stable(feature = "no_panic_pow", since = "1.34.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { - if exp == 0{ - return (1,false); - } - let mut base = self; - let mut acc: Self = 1; - let mut overflown = false; - // Scratch space for storing results of overflowing_mul. - let mut r; - - while exp > 1 { - if (exp & 1) == 1 { - r = acc.overflowing_mul(base); - acc = r.0; - overflown |= r.1; - } - exp /= 2; - r = base.overflowing_mul(base); - base = r.0; - overflown |= r.1; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - r = acc.overflowing_mul(base); - r.1 |= overflown; - - r - } - } - - doc_comment! { - concat!("Raises self to the power of `exp`, using exponentiation by squaring. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn pow(self, mut exp: u32) -> Self { - if exp == 0 { - return 1; - } - let mut base = self; - let mut acc = 1; - - while exp > 1 { - if (exp & 1) == 1 { - acc = acc * base; - } - exp /= 2; - base = base * base; - } - - // since exp!=0, finally the exp must be 1. - // Deal with the final bit of the exponent separately, since - // squaring the base afterwards is not necessary and may cause a - // needless overflow. - acc * base - } - } - - doc_comment! { - concat!("Performs Euclidean division. - -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self / rhs`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn div_euclid(self, rhs: Self) -> Self { - self / rhs - } - } - - - doc_comment! { - concat!("Calculates the least remainder of `self (mod rhs)`. - -Since, for the positive integers, all common -definitions of division are equal, this -is exactly equal to `self % rhs`. - -# Panics - -This function will panic if `rhs` is 0. - -# Examples - -Basic usage: - -``` -assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type -```"), - #[stable(feature = "euclidean_division", since = "1.38.0")] - #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] - #[must_use = "this returns the result of the operation, \ - without modifying the original"] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn rem_euclid(self, rhs: Self) -> Self { - self % rhs - } - } - - doc_comment! { - concat!("Returns `true` if and only if `self == 2^k` for some `k`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two()); -assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] - #[inline] - pub const fn is_power_of_two(self) -> bool { - self.count_ones() == 1 - } - } - - // Returns one less than next power of two. - // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) - // - // 8u8.one_less_than_next_power_of_two() == 7 - // 6u8.one_less_than_next_power_of_two() == 7 - // - // This method cannot overflow, as in the `next_power_of_two` - // overflow cases it instead ends up returning the maximum value - // of the type, and can return 0 for 0. - #[inline] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - const fn one_less_than_next_power_of_two(self) -> Self { - if self <= 1 { return 0; } - - let p = self - 1; - // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros. - // That means the shift is always in-bounds, and some processors - // (such as intel pre-haswell) have more efficient ctlz - // intrinsics when the argument is non-zero. - let z = unsafe { intrinsics::ctlz_nonzero(p) }; - <$SelfT>::MAX >> z - } - - doc_comment! { - concat!("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 -release mode (the only situation in which method can return 0). - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); -assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " -```"), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - #[inline] - #[rustc_inherit_overflow_checks] - pub const fn next_power_of_two(self) -> Self { - self.one_less_than_next_power_of_two() + 1 - } - } - - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `n`. If -the next power of two is greater than the type's maximum value, -`None` is returned, otherwise the power of two is wrapped in `Some`. - -# Examples - -Basic usage: - -``` -", $Feature, "assert_eq!(2", stringify!($SelfT), -".checked_next_power_of_two(), Some(2)); -assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); -assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);", -$EndFeature, " -```"), - #[inline] - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - pub const fn checked_next_power_of_two(self) -> Option { - self.one_less_than_next_power_of_two().checked_add(1) - } - } - - doc_comment! { - concat!("Returns the smallest power of two greater than or equal to `n`. If -the next power of two is greater than the type's maximum value, -the return value is wrapped to `0`. - -# Examples - -Basic usage: - -``` -#![feature(wrapping_next_power_of_two)] -", $Feature, " -assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); -assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); -assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);", -$EndFeature, " -```"), - #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", - reason = "needs decision on wrapping behaviour")] - #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] - pub const fn wrapping_next_power_of_two(self) -> Self { - self.one_less_than_next_power_of_two().wrapping_add(1) - } - } - - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -big-endian (network) byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); -assert_eq!(bytes, ", $be_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { - self.to_be().to_ne_bytes() - } - } - - doc_comment! { - concat!("Return the memory representation of this integer as a byte array in -little-endian byte order. -", -$to_xe_bytes_doc, -" -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); -assert_eq!(bytes, ", $le_bytes, "); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { - self.to_le().to_ne_bytes() - } - } - - doc_comment! { - concat!(" -Return the memory representation of this integer as a byte array in -native byte order. - -As the target platform's native endianness is used, portable code -should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, -instead. -", -$to_xe_bytes_doc, -" -[`to_be_bytes`]: #method.to_be_bytes -[`to_le_bytes`]: #method.to_le_bytes - -# Examples - -``` -let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); -assert_eq!( - bytes, - if cfg!(target_endian = \"big\") { - ", $be_bytes, " - } else { - ", $le_bytes, " - } -); -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[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 - #[allow_internal_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 - // arrays of bytes - unsafe { mem::transmute(self) } - } - } - - doc_comment! { - concat!("Create a native endian integer value from its representation -as a byte array in big endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_be(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!(" -Create a native endian integer value from its representation -as a byte array in little endian. -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] - #[inline] - pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { - Self::from_le(Self::from_ne_bytes(bytes)) - } - } - - doc_comment! { - concat!("Create a native endian integer value from its memory representation -as a byte array in native endianness. - -As the target platform's native endianness is used, portable code -likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as -appropriate instead. - -[`from_be_bytes`]: #method.from_be_bytes -[`from_le_bytes`]: #method.from_le_bytes -", -$from_xe_bytes_doc, -" -# Examples - -``` -let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { - ", $be_bytes, " -} else { - ", $le_bytes, " -}); -assert_eq!(value, ", $swap_op, "); -``` - -When starting from a slice rather than an array, fallible conversion APIs can be used: - -``` -use std::convert::TryInto; - -fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { - let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); - *input = rest; - ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) -} -```"), - #[stable(feature = "int_to_from_bytes", since = "1.32.0")] - #[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 to them - #[allow_internal_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 - unsafe { mem::transmute(bytes) } - } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. - -Returns the smallest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_promotable] - #[inline(always)] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn min_value() -> Self { Self::MIN } - } - - doc_comment! { - concat!("**This method is soft-deprecated.** - -Although using it won’t cause compilation warning, -new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. - -Returns the largest value that can be represented by this integer type."), - #[stable(feature = "rust1", since = "1.0.0")] - #[rustc_promotable] - #[inline(always)] - #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] - pub const fn max_value() -> Self { Self::MAX } - } - } -} - #[lang = "u8"] impl u8 { uint_impl! { u8, u8, 8, 255, "", "", 2, "0x82", "0xa", "0x12", "0x12", "0x48", "[0x12]", @@ -5115,6 +760,16 @@ pub enum FpCategory { Normal, } +#[doc(hidden)] +trait FromStrRadixHelper: PartialOrd + Copy { + fn min_value() -> Self; + fn max_value() -> Self; + fn from_u32(u: u32) -> Self; + fn checked_mul(&self, other: u32) -> Option; + fn checked_sub(&self, other: u32) -> Option; + fn checked_add(&self, other: u32) -> Option; +} + macro_rules! from_str_radix_int_impl { ($($t:ty)*) => {$( #[stable(feature = "rust1", since = "1.0.0")] @@ -5128,58 +783,6 @@ macro_rules! from_str_radix_int_impl { } from_str_radix_int_impl! { isize i8 i16 i32 i64 i128 usize u8 u16 u32 u64 u128 } -/// The error type returned when a checked integral type conversion fails. -#[stable(feature = "try_from", since = "1.34.0")] -#[derive(Debug, Copy, Clone, PartialEq, Eq)] -pub struct TryFromIntError(pub(crate) ()); - -impl TryFromIntError { - #[unstable( - feature = "int_error_internals", - reason = "available through Error trait and this method should \ - not be exposed publicly", - issue = "none" - )] - #[doc(hidden)] - pub fn __description(&self) -> &str { - "out of range integral type conversion attempted" - } -} - -#[stable(feature = "try_from", since = "1.34.0")] -impl fmt::Display for TryFromIntError { - fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { - self.__description().fmt(fmt) - } -} - -#[stable(feature = "try_from", since = "1.34.0")] -impl From for TryFromIntError { - fn from(x: Infallible) -> TryFromIntError { - match x {} - } -} - -#[unstable(feature = "never_type", issue = "35121")] -impl From for TryFromIntError { - fn from(never: !) -> TryFromIntError { - // Match rather than coerce to make sure that code like - // `From for TryFromIntError` above will keep working - // when `Infallible` becomes an alias to `!`. - match never {} - } -} - -#[doc(hidden)] -trait FromStrRadixHelper: PartialOrd + Copy { - fn min_value() -> Self; - fn max_value() -> Self; - fn from_u32(u: u32) -> Self; - fn checked_mul(&self, other: u32) -> Option; - fn checked_sub(&self, other: u32) -> Option; - fn checked_add(&self, other: u32) -> Option; -} - macro_rules! doit { ($($t:ty)*) => ($(impl FromStrRadixHelper for $t { #[inline] @@ -5272,91 +875,3 @@ fn from_str_radix(src: &str, radix: u32) -> Result &IntErrorKind { - &self.kind - } - #[unstable( - feature = "int_error_internals", - reason = "available through Error trait and this method should \ - not be exposed publicly", - issue = "none" - )] - #[doc(hidden)] - pub fn __description(&self) -> &str { - match self.kind { - IntErrorKind::Empty => "cannot parse integer from empty string", - IntErrorKind::InvalidDigit => "invalid digit found in string", - IntErrorKind::Overflow => "number too large to fit in target type", - IntErrorKind::Underflow => "number too small to fit in target type", - IntErrorKind::Zero => "number would be zero for non-zero type", - } - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -impl fmt::Display for ParseIntError { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - self.__description().fmt(f) - } -} - -#[stable(feature = "rust1", since = "1.0.0")] -pub use crate::num::dec2flt::ParseFloatError; diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs new file mode 100644 index 0000000000..382f799bfe --- /dev/null +++ b/library/core/src/num/nonzero.rs @@ -0,0 +1,190 @@ +//! Definitions of integer that is known not to equal zero. + +use crate::fmt; +use crate::ops::{BitOr, BitOrAssign}; +use crate::str::FromStr; + +use super::from_str_radix; +use super::{IntErrorKind, ParseIntError}; + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + +macro_rules! impl_nonzero_fmt { + ( #[$stability: meta] ( $( $Trait: ident ),+ ) for $Ty: ident ) => { + $( + #[$stability] + impl fmt::$Trait for $Ty { + #[inline] + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.get().fmt(f) + } + } + )+ + } +} + +macro_rules! nonzero_integers { + ( $( #[$stability: meta] $Ty: ident($Int: ty); )+ ) => { + $( + doc_comment! { + concat!("An integer that is known not to equal zero. + +This enables some memory layout optimization. +For example, `Option<", stringify!($Ty), ">` is the same size as `", stringify!($Int), "`: + +```rust +use std::mem::size_of; +assert_eq!(size_of::>(), size_of::<", stringify!($Int), +">()); +```"), + #[$stability] + #[derive(Copy, Clone, Eq, PartialEq, Ord, PartialOrd, Hash)] + #[repr(transparent)] + #[rustc_layout_scalar_valid_range_start(1)] + #[rustc_nonnull_optimization_guaranteed] + pub struct $Ty($Int); + } + + impl $Ty { + /// Creates a non-zero without checking the value. + /// + /// # Safety + /// + /// The value must not be zero. + #[$stability] + #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] + #[inline] + pub const unsafe fn new_unchecked(n: $Int) -> Self { + // SAFETY: this is guaranteed to be safe by the caller. + unsafe { Self(n) } + } + + /// Creates a non-zero if the given value is not zero. + #[$stability] + #[rustc_const_stable(feature = "const_nonzero_int_methods", since = "1.47.0")] + #[inline] + pub const fn new(n: $Int) -> Option { + if n != 0 { + // SAFETY: we just checked that there's no `0` + Some(unsafe { Self(n) }) + } else { + None + } + } + + /// Returns the value as a primitive type. + #[$stability] + #[inline] + #[rustc_const_stable(feature = "nonzero", since = "1.34.0")] + pub const fn get(self) -> $Int { + self.0 + } + + } + + #[stable(feature = "from_nonzero", since = "1.31.0")] + impl From<$Ty> for $Int { + doc_comment! { + concat!( +"Converts a `", stringify!($Ty), "` into an `", stringify!($Int), "`"), + fn from(nonzero: $Ty) -> Self { + nonzero.0 + } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr for $Ty { + type Output = Self; + #[inline] + fn bitor(self, rhs: Self) -> Self::Output { + // SAFETY: since `self` and `rhs` are both nonzero, the + // result of the bitwise-or will be nonzero. + unsafe { $Ty::new_unchecked(self.get() | rhs.get()) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr<$Int> for $Ty { + type Output = Self; + #[inline] + fn bitor(self, rhs: $Int) -> Self::Output { + // SAFETY: since `self` is nonzero, the result of the + // bitwise-or will be nonzero regardless of the value of + // `rhs`. + unsafe { $Ty::new_unchecked(self.get() | rhs) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOr<$Ty> for $Int { + type Output = $Ty; + #[inline] + fn bitor(self, rhs: $Ty) -> Self::Output { + // SAFETY: since `rhs` is nonzero, the result of the + // bitwise-or will be nonzero regardless of the value of + // `self`. + unsafe { $Ty::new_unchecked(self | rhs.get()) } + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOrAssign for $Ty { + #[inline] + fn bitor_assign(&mut self, rhs: Self) { + *self = *self | rhs; + } + } + + #[stable(feature = "nonzero_bitor", since = "1.45.0")] + impl BitOrAssign<$Int> for $Ty { + #[inline] + fn bitor_assign(&mut self, rhs: $Int) { + *self = *self | rhs; + } + } + + impl_nonzero_fmt! { + #[$stability] (Debug, Display, Binary, Octal, LowerHex, UpperHex) for $Ty + } + )+ + } +} + +nonzero_integers! { + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU8(u8); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU16(u16); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU32(u32); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU64(u64); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroU128(u128); + #[stable(feature = "nonzero", since = "1.28.0")] NonZeroUsize(usize); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI8(i8); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI16(i16); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI32(i32); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI64(i64); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroI128(i128); + #[stable(feature = "signed_nonzero", since = "1.34.0")] NonZeroIsize(isize); +} + +macro_rules! from_str_radix_nzint_impl { + ($($t:ty)*) => {$( + #[stable(feature = "nonzero_parse", since = "1.35.0")] + impl FromStr for $t { + type Err = ParseIntError; + fn from_str(src: &str) -> Result { + Self::new(from_str_radix(src, 10)?) + .ok_or(ParseIntError { + kind: IntErrorKind::Zero + }) + } + } + )*} +} + +from_str_radix_nzint_impl! { NonZeroU8 NonZeroU16 NonZeroU32 NonZeroU64 NonZeroU128 NonZeroUsize +NonZeroI8 NonZeroI16 NonZeroI32 NonZeroI64 NonZeroI128 NonZeroIsize } diff --git a/library/core/src/num/i128.rs b/library/core/src/num/shells/i128.rs similarity index 100% rename from library/core/src/num/i128.rs rename to library/core/src/num/shells/i128.rs diff --git a/library/core/src/num/i16.rs b/library/core/src/num/shells/i16.rs similarity index 100% rename from library/core/src/num/i16.rs rename to library/core/src/num/shells/i16.rs diff --git a/library/core/src/num/i32.rs b/library/core/src/num/shells/i32.rs similarity index 100% rename from library/core/src/num/i32.rs rename to library/core/src/num/shells/i32.rs diff --git a/library/core/src/num/i64.rs b/library/core/src/num/shells/i64.rs similarity index 100% rename from library/core/src/num/i64.rs rename to library/core/src/num/shells/i64.rs diff --git a/library/core/src/num/i8.rs b/library/core/src/num/shells/i8.rs similarity index 100% rename from library/core/src/num/i8.rs rename to library/core/src/num/shells/i8.rs diff --git a/library/core/src/num/shells/int_macros.rs b/library/core/src/num/shells/int_macros.rs new file mode 100644 index 0000000000..ffd30b03f2 --- /dev/null +++ b/library/core/src/num/shells/int_macros.rs @@ -0,0 +1,49 @@ +#![doc(hidden)] + +macro_rules! doc_comment { + ($x:expr, $($tt:tt)*) => { + #[doc = $x] + $($tt)* + }; +} + +macro_rules! int_module { + ($T:ident) => (int_module!($T, #[stable(feature = "rust1", since = "1.0.0")]);); + ($T:ident, #[$attr:meta]) => ( + doc_comment! { + concat!("The smallest value that can be represented by this integer type. +Use [`", stringify!($T), "::MIN", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MIN) instead. + +# Examples + +```rust +// deprecated way +let min = std::", stringify!($T), "::MIN; + +// intended way +let min = ", stringify!($T), "::MIN; +``` +"), + #[$attr] + pub const MIN: $T = $T::MIN; + } + + doc_comment! { + concat!("The largest value that can be represented by this integer type. +Use [`", stringify!($T), "::MAX", "`](../../std/primitive.", stringify!($T), ".html#associatedconstant.MAX) instead. + +# Examples + +```rust +// deprecated way +let max = std::", stringify!($T), "::MAX; + +// intended way +let max = ", stringify!($T), "::MAX; +``` +"), + #[$attr] + pub const MAX: $T = $T::MAX; + } + ) +} diff --git a/library/core/src/num/isize.rs b/library/core/src/num/shells/isize.rs similarity index 100% rename from library/core/src/num/isize.rs rename to library/core/src/num/shells/isize.rs diff --git a/library/core/src/num/u128.rs b/library/core/src/num/shells/u128.rs similarity index 100% rename from library/core/src/num/u128.rs rename to library/core/src/num/shells/u128.rs diff --git a/library/core/src/num/u16.rs b/library/core/src/num/shells/u16.rs similarity index 100% rename from library/core/src/num/u16.rs rename to library/core/src/num/shells/u16.rs diff --git a/library/core/src/num/u32.rs b/library/core/src/num/shells/u32.rs similarity index 100% rename from library/core/src/num/u32.rs rename to library/core/src/num/shells/u32.rs diff --git a/library/core/src/num/u64.rs b/library/core/src/num/shells/u64.rs similarity index 100% rename from library/core/src/num/u64.rs rename to library/core/src/num/shells/u64.rs diff --git a/library/core/src/num/u8.rs b/library/core/src/num/shells/u8.rs similarity index 100% rename from library/core/src/num/u8.rs rename to library/core/src/num/shells/u8.rs diff --git a/library/core/src/num/usize.rs b/library/core/src/num/shells/usize.rs similarity index 100% rename from library/core/src/num/usize.rs rename to library/core/src/num/shells/usize.rs diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs new file mode 100644 index 0000000000..234c309961 --- /dev/null +++ b/library/core/src/num/uint_macros.rs @@ -0,0 +1,1955 @@ +macro_rules! uint_impl { + ($SelfT:ty, $ActualT:ty, $BITS:expr, $MaxV:expr, $Feature:expr, $EndFeature: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) => { + doc_comment! { + concat!("The smallest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MIN, 0);", $EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MIN: Self = 0; + } + + doc_comment! { + concat!("The largest value that can be represented by this integer type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX, ", stringify!($MaxV), ");", +$EndFeature, " +```"), + #[stable(feature = "assoc_int_consts", since = "1.43.0")] + pub const MAX: Self = !0; + } + + doc_comment! { + concat!("The size of this integer type in bits. + +# Examples + +``` +", $Feature, "#![feature(int_bits_const)] +assert_eq!(", stringify!($SelfT), "::BITS, ", stringify!($BITS), ");", +$EndFeature, " +```"), + #[unstable(feature = "int_bits_const", issue = "76904")] + pub const BITS: u32 = $BITS; + } + + doc_comment! { + concat!("Converts a string slice in a given base to an integer. + +The string is expected to be an optional `+` sign +followed by digits. +Leading and trailing whitespace represent an error. +Digits are a subset of these characters, depending on `radix`: + +* `0-9` +* `a-z` +* `A-Z` + +# Panics + +This function panics if `radix` is not in the range from 2 to 36. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::from_str_radix(\"A\", 16), Ok(10));", +$EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + pub fn from_str_radix(src: &str, radix: u32) -> Result { + from_str_radix(src, radix) + } + } + + doc_comment! { + concat!("Returns the number of ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b01001100", stringify!($SelfT), "; + +assert_eq!(n.count_ones(), 3);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn count_ones(self) -> u32 { + intrinsics::ctpop(self as $ActualT) as u32 + } + } + + doc_comment! { + concat!("Returns the number of zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(", stringify!($SelfT), "::MAX.count_zeros(), 0);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn count_zeros(self) -> u32 { + (!self).count_ones() + } + } + + doc_comment! { + concat!("Returns the number of leading zeros in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = ", stringify!($SelfT), "::MAX >> 2; + +assert_eq!(n.leading_zeros(), 2);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn leading_zeros(self) -> u32 { + intrinsics::ctlz(self as $ActualT) as u32 + } + } + + doc_comment! { + concat!("Returns the number of trailing zeros in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b0101000", stringify!($SelfT), "; + +assert_eq!(n.trailing_zeros(), 3);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn trailing_zeros(self) -> u32 { + intrinsics::cttz(self) as u32 + } + } + + doc_comment! { + concat!("Returns the number of leading ones in the binary representation of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = !(", stringify!($SelfT), "::MAX >> 2); + +assert_eq!(n.leading_ones(), 2);", $EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn leading_ones(self) -> u32 { + (!self).leading_zeros() + } + } + + doc_comment! { + concat!("Returns the number of trailing ones in the binary representation +of `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0b1010111", stringify!($SelfT), "; + +assert_eq!(n.trailing_ones(), 3);", $EndFeature, " +```"), + #[stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[rustc_const_stable(feature = "leading_trailing_ones", since = "1.46.0")] + #[inline] + pub const fn trailing_ones(self) -> u32 { + (!self).trailing_zeros() + } + } + + doc_comment! { + concat!("Shifts the bits to the left by a specified amount, `n`, +wrapping the truncated bits to the end of the resulting integer. + +Please note this isn't the same operation as the `<<` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_op, stringify!($SelfT), "; +let m = ", $rot_result, "; + +assert_eq!(n.rotate_left(", $rot, "), m); +```"), + #[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] + pub const fn rotate_left(self, n: u32) -> Self { + intrinsics::rotate_left(self, n as $SelfT) + } + } + + doc_comment! { + concat!("Shifts the bits to the right by a specified amount, `n`, +wrapping the truncated bits to the beginning of the resulting +integer. + +Please note this isn't the same operation as the `>>` shifting operator! + +# Examples + +Basic usage: + +``` +let n = ", $rot_result, stringify!($SelfT), "; +let m = ", $rot_op, "; + +assert_eq!(n.rotate_right(", $rot, "), m); +```"), + #[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] + pub const fn rotate_right(self, n: u32) -> Self { + intrinsics::rotate_right(self, n as $SelfT) + } + } + + doc_comment! { + concat!(" +Reverses the byte order of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.swap_bytes(); + +assert_eq!(m, ", $swapped, "); +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn swap_bytes(self) -> Self { + intrinsics::bswap(self as $ActualT) as Self + } + } + + doc_comment! { + concat!("Reverses the bit pattern of the integer. + +# Examples + +Basic usage: + +``` +let n = ", $swap_op, stringify!($SelfT), "; +let m = n.reverse_bits(); + +assert_eq!(m, ", $reversed, "); +```"), + #[stable(feature = "reverse_bits", since = "1.37.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + #[must_use] + pub const fn reverse_bits(self) -> Self { + intrinsics::bitreverse(self as $ActualT) as Self + } + } + + doc_comment! { + concat!("Converts an integer from big endian to the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(", stringify!($SelfT), "::from_be(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_be(n), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn from_be(x: Self) -> Self { + #[cfg(target_endian = "big")] + { + x + } + #[cfg(not(target_endian = "big"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts an integer from little endian to the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(", stringify!($SelfT), "::from_le(n), n) +} else { + assert_eq!(", stringify!($SelfT), "::from_le(n), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn from_le(x: Self) -> Self { + #[cfg(target_endian = "little")] + { + x + } + #[cfg(not(target_endian = "little"))] + { + x.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to big endian from the target's endianness. + +On big endian this is a no-op. On little endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"big\") { + assert_eq!(n.to_be(), n) +} else { + assert_eq!(n.to_be(), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn to_be(self) -> Self { // or not to be? + #[cfg(target_endian = "big")] + { + self + } + #[cfg(not(target_endian = "big"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Converts `self` to little endian from the target's endianness. + +On little endian this is a no-op. On big endian the bytes are +swapped. + +# Examples + +Basic usage: + +``` +", $Feature, "let n = 0x1A", stringify!($SelfT), "; + +if cfg!(target_endian = \"little\") { + assert_eq!(n.to_le(), n) +} else { + assert_eq!(n.to_le(), n.swap_bytes()) +}", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_math", since = "1.32.0")] + #[inline] + pub const fn to_le(self) -> Self { + #[cfg(target_endian = "little")] + { + self + } + #[cfg(not(target_endian = "little"))] + { + self.swap_bytes() + } + } + } + + doc_comment! { + concat!("Checked integer addition. Computes `self + rhs`, returning `None` +if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(1), ", +"Some(", stringify!($SelfT), "::MAX - 1)); +assert_eq!((", stringify!($SelfT), "::MAX - 2).checked_add(3), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.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_add(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_add(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer addition. Computes `self + rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self + rhs > ", stringify!($SelfT), +"::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_add(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_add`. + unsafe { intrinsics::unchecked_add(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer subtraction. Computes `self - rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(1", stringify!($SelfT), ".checked_sub(1), Some(0)); +assert_eq!(0", stringify!($SelfT), ".checked_sub(1), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.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_sub(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_sub(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer subtraction. Computes `self - rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self - rhs > ", stringify!($SelfT), +"::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_sub(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_sub`. + unsafe { intrinsics::unchecked_sub(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer multiplication. Computes `self * rhs`, returning +`None` if overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_mul(1), Some(5)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_mul(2), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.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_mul(self, rhs: Self) -> Option { + let (a, b) = self.overflowing_mul(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Unchecked integer multiplication. Computes `self * rhs`, assuming overflow +cannot occur. This results in undefined behavior when `self * rhs > ", stringify!($SelfT), +"::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`."), + #[unstable( + feature = "unchecked_math", + reason = "niche optimization path", + issue = "none", + )] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub unsafe fn unchecked_mul(self, rhs: Self) -> Self { + // SAFETY: the caller must uphold the safety contract for + // `unchecked_mul`. + unsafe { intrinsics::unchecked_mul(self, rhs) } + } + } + + doc_comment! { + concat!("Checked integer division. Computes `self / rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".checked_div(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div(0), None);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division + Some(unsafe { intrinsics::unchecked_div(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean division. Computes `self.div_euclid(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(128", stringify!($SelfT), ".checked_div_euclid(2), Some(64)); +assert_eq!(1", stringify!($SelfT), ".checked_div_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_div_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + Some(self.div_euclid(rhs)) + } + } + } + + + doc_comment! { + concat!("Checked integer remainder. Computes `self % rhs`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".checked_rem(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem(0), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_checked_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + // SAFETY: div by zero has been checked above and unsigned types have no other + // failure modes for division + Some(unsafe { intrinsics::unchecked_rem(self, rhs) }) + } + } + } + + doc_comment! { + concat!("Checked Euclidean modulo. Computes `self.rem_euclid(rhs)`, returning `None` +if `rhs == 0`. + +# Examples + +Basic usage: + +``` +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(2), Some(1)); +assert_eq!(5", stringify!($SelfT), ".checked_rem_euclid(0), None); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_rem_euclid(self, rhs: Self) -> Option { + if unlikely!(rhs == 0) { + None + } else { + Some(self.rem_euclid(rhs)) + } + } + } + + doc_comment! { + concat!("Checked negation. Computes `-self`, returning `None` unless `self == +0`. + +Note that negating any positive integer will overflow. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".checked_neg(), Some(0)); +assert_eq!(1", stringify!($SelfT), ".checked_neg(), None);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_checked_int_methods", since = "1.47.0")] + #[inline] + pub const fn checked_neg(self) -> Option { + let (a, b) = self.overflowing_neg(); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift left. Computes `self << rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".checked_shl(4), Some(0x10)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shl(129), None);", $EndFeature, " +```"), + #[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_shl(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shl(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked shift right. Computes `self >> rhs`, returning `None` +if `rhs` is larger than or equal to the number of bits in `self`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".checked_shr(4), Some(0x1)); +assert_eq!(0x10", stringify!($SelfT), ".checked_shr(129), None);", $EndFeature, " +```"), + #[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_shr(self, rhs: u32) -> Option { + let (a, b) = self.overflowing_shr(rhs); + if unlikely!(b) {None} else {Some(a)} + } + } + + doc_comment! { + concat!("Checked exponentiation. Computes `self.pow(exp)`, returning `None` if +overflow occurred. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".checked_pow(5), Some(32)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_pow(2), None);", $EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn checked_pow(self, mut exp: u32) -> Option { + if exp == 0 { + return Some(1); + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = try_opt!(acc.checked_mul(base)); + } + exp /= 2; + base = try_opt!(base.checked_mul(base)); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + + Some(try_opt!(acc.checked_mul(base))) + } + } + + doc_comment! { + concat!("Saturating integer addition. Computes `self + rhs`, saturating at +the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_add(1), 101); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_add(127), ", stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_add(self, rhs: Self) -> Self { + intrinsics::saturating_add(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer subtraction. Computes `self - rhs`, saturating +at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".saturating_sub(27), 73); +assert_eq!(13", stringify!($SelfT), ".saturating_sub(127), 0);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[rustc_const_stable(feature = "const_saturating_int_methods", since = "1.47.0")] + #[inline] + pub const fn saturating_sub(self, rhs: Self) -> Self { + intrinsics::saturating_sub(self, rhs) + } + } + + doc_comment! { + concat!("Saturating integer multiplication. Computes `self * rhs`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".saturating_mul(10), 20); +assert_eq!((", stringify!($SelfT), "::MAX).saturating_mul(10), ", stringify!($SelfT), +"::MAX);", $EndFeature, " +```"), + #[stable(feature = "wrapping", since = "1.7.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_mul(self, rhs: Self) -> Self { + match self.checked_mul(rhs) { + Some(x) => x, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Saturating integer exponentiation. Computes `self.pow(exp)`, +saturating at the numeric bounds instead of overflowing. + +# Examples + +Basic usage: + +``` +", $Feature, " +assert_eq!(4", stringify!($SelfT), ".saturating_pow(3), 64); +assert_eq!(", stringify!($SelfT), "::MAX.saturating_pow(2), ", stringify!($SelfT), "::MAX);", +$EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn saturating_pow(self, exp: u32) -> Self { + match self.checked_pow(exp) { + Some(x) => x, + None => Self::MAX, + } + } + } + + doc_comment! { + concat!("Wrapping (modular) addition. Computes `self + rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(200", stringify!($SelfT), ".wrapping_add(55), 255); +assert_eq!(200", stringify!($SelfT), ".wrapping_add(", stringify!($SelfT), "::MAX), 199);", +$EndFeature, " +```"), + #[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"] + #[inline] + pub const fn wrapping_add(self, rhs: Self) -> Self { + intrinsics::wrapping_add(self, rhs) + } + } + + doc_comment! { + concat!("Wrapping (modular) subtraction. Computes `self - rhs`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_sub(100), 0); +assert_eq!(100", stringify!($SelfT), ".wrapping_sub(", stringify!($SelfT), "::MAX), 101);", +$EndFeature, " +```"), + #[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"] + #[inline] + pub const fn wrapping_sub(self, rhs: Self) -> Self { + intrinsics::wrapping_sub(self, rhs) + } + } + + /// Wrapping (modular) multiplication. Computes `self * + /// rhs`, wrapping around at the boundary of the type. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u8` is used here. + /// + /// ``` + /// assert_eq!(10u8.wrapping_mul(12), 120); + /// assert_eq!(25u8.wrapping_mul(12), 44); + /// ``` + #[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"] + #[inline] + pub const fn wrapping_mul(self, rhs: Self) -> Self { + intrinsics::wrapping_mul(self, rhs) + } + + doc_comment! { + concat!("Wrapping (modular) division. Computes `self / rhs`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_div(10), 10);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div(self, rhs: Self) -> Self { + self / rhs + } + } + + doc_comment! { + concat!("Wrapping Euclidean division. Computes `self.div_euclid(rhs)`. +Wrapped division on unsigned types is just normal division. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_div(rhs)`. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_div_euclid(10), 10); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_div_euclid(self, rhs: Self) -> Self { + self / rhs + } + } + + doc_comment! { + concat!("Wrapping (modular) remainder. Computes `self % rhs`. +Wrapped remainder calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(100", stringify!($SelfT), ".wrapping_rem(10), 0);", $EndFeature, " +```"), + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_unstable(feature = "const_wrapping_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem(self, rhs: Self) -> Self { + self % rhs + } + } + + doc_comment! { + concat!("Wrapping Euclidean modulo. Computes `self.rem_euclid(rhs)`. +Wrapped modulo calculation on unsigned types is +just the regular remainder calculation. +There's no way wrapping could ever happen. +This function exists, so that all operations +are accounted for in the wrapping operations. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.wrapping_rem(rhs)`. + +# Examples + +Basic usage: + +``` +assert_eq!(100", stringify!($SelfT), ".wrapping_rem_euclid(10), 0); +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + } + + /// Wrapping (modular) negation. Computes `-self`, + /// wrapping around at the boundary of the type. + /// + /// Since unsigned types do not have negative equivalents + /// all applications of this function will wrap (except for `-0`). + /// For values smaller than the corresponding signed type's maximum + /// the result is the same as casting the corresponding signed value. + /// Any larger values are equivalent to `MAX + 1 - (val - MAX - 1)` where + /// `MAX` is the corresponding signed type's maximum. + /// + /// # Examples + /// + /// Basic usage: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `i8` is used here. + /// + /// ``` + /// assert_eq!(100i8.wrapping_neg(), -100); + /// assert_eq!((-128i8).wrapping_neg(), -128); + /// ``` + #[stable(feature = "num_wrapping", since = "1.2.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + #[inline] + pub const fn wrapping_neg(self) -> Self { + self.overflowing_neg().0 + } + + doc_comment! { + concat!("Panic-free bitwise shift-left; yields `self << mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-left; the +RHS of a wrapping shift-left is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a [`rotate_left`](#method.rotate_left) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(1", stringify!($SelfT), ".wrapping_shl(7), 128); +assert_eq!(1", stringify!($SelfT), ".wrapping_shl(128), 1);", $EndFeature, " +```"), + #[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] + pub const fn wrapping_shl(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shl(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Panic-free bitwise shift-right; yields `self >> mask(rhs)`, +where `mask` removes any high-order bits of `rhs` that +would cause the shift to exceed the bitwidth of the type. + +Note that this is *not* the same as a rotate-right; the +RHS of a wrapping shift-right is restricted to the range +of the type, rather than the bits shifted out of the LHS +being returned to the other end. The primitive integer +types all implement a [`rotate_right`](#method.rotate_right) function, +which may be what you want instead. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(128", stringify!($SelfT), ".wrapping_shr(7), 1); +assert_eq!(128", stringify!($SelfT), ".wrapping_shr(128), 128);", $EndFeature, " +```"), + #[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] + pub const fn wrapping_shr(self, rhs: u32) -> Self { + // SAFETY: the masking by the bitsize of the type ensures that we do not shift + // out of bounds + unsafe { + intrinsics::unchecked_shr(self, (rhs & ($BITS - 1)) as $SelfT) + } + } + } + + doc_comment! { + concat!("Wrapping (modular) exponentiation. Computes `self.pow(exp)`, +wrapping around at the boundary of the type. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".wrapping_pow(5), 243); +assert_eq!(3u8.wrapping_pow(6), 217);", $EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn wrapping_pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc: Self = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc.wrapping_mul(base); + } + exp /= 2; + base = base.wrapping_mul(base); + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc.wrapping_mul(base) + } + } + + doc_comment! { + concat!("Calculates `self` + `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, " +assert_eq!(5", stringify!($SelfT), ".overflowing_add(2), (7, false)); +assert_eq!(", stringify!($SelfT), "::MAX.overflowing_add(1), (0, true));", $EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_add(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::add_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + doc_comment! { + concat!("Calculates `self` - `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, " +assert_eq!(5", stringify!($SelfT), ".overflowing_sub(2), (3, false)); +assert_eq!(0", stringify!($SelfT), ".overflowing_sub(1), (", stringify!($SelfT), "::MAX, true));", +$EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_sub(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::sub_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + } + + /// Calculates the multiplication of `self` and `rhs`. + /// + /// Returns a tuple of the multiplication 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: + /// + /// Please note that this example is shared between integer types. + /// Which explains why `u32` is used here. + /// + /// ``` + /// assert_eq!(5u32.overflowing_mul(2), (10, false)); + /// assert_eq!(1_000_000_000u32.overflowing_mul(10), (1410065408, true)); + /// ``` + #[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"] + #[inline] + pub const fn overflowing_mul(self, rhs: Self) -> (Self, bool) { + let (a, b) = intrinsics::mul_with_overflow(self as $ActualT, rhs as $ActualT); + (a as Self, b) + } + + doc_comment! { + concat!("Calculates the divisor when `self` is divided by `rhs`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_div(2), (2, false));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + + doc_comment! { + concat!("Calculates the quotient of Euclidean division `self.div_euclid(rhs)`. + +Returns a tuple of the divisor along with a boolean indicating +whether an arithmetic overflow would occur. Note that for unsigned +integers overflow never occurs, so the second value is always +`false`. +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self.overflowing_div(rhs)`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_div_euclid(2), (2, false)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_div_euclid(self, rhs: Self) -> (Self, bool) { + (self / rhs, false) + } + } + + doc_comment! { + concat!("Calculates the remainder when `self` is divided by `rhs`. + +Returns a tuple of the remainder after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(5", stringify!($SelfT), ".overflowing_rem(2), (1, false));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_unstable(feature = "const_overflowing_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + + doc_comment! { + concat!("Calculates the remainder `self.rem_euclid(rhs)` as if by Euclidean division. + +Returns a tuple of the modulo after dividing along with a boolean +indicating whether an arithmetic overflow would occur. Note that for +unsigned integers overflow never occurs, so the second value is +always `false`. +Since, for the positive integers, all common +definitions of division are equal, this operation +is exactly equal to `self.overflowing_rem(rhs)`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage + +``` +assert_eq!(5", stringify!($SelfT), ".overflowing_rem_euclid(2), (1, false)); +```"), + #[inline] + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + pub const fn overflowing_rem_euclid(self, rhs: Self) -> (Self, bool) { + (self % rhs, false) + } + } + + doc_comment! { + concat!("Negates self in an overflowing fashion. + +Returns `!self + 1` using wrapping operations to return the value +that represents the negation of this unsigned value. Note that for +positive unsigned values overflow always occurs, but negating 0 does +not overflow. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0", stringify!($SelfT), ".overflowing_neg(), (0, false)); +assert_eq!(2", stringify!($SelfT), ".overflowing_neg(), (-2i32 as ", stringify!($SelfT), +", true));", $EndFeature, " +```"), + #[inline] + #[stable(feature = "wrapping", since = "1.7.0")] + #[rustc_const_stable(feature = "const_wrapping_math", since = "1.32.0")] + pub const fn overflowing_neg(self) -> (Self, bool) { + ((!self).wrapping_add(1), self != 0) + } + } + + doc_comment! { + concat!("Shifts self left by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(4), (0x10, false)); +assert_eq!(0x1", stringify!($SelfT), ".overflowing_shl(132), (0x10, true));", $EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_shl(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shl(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Shifts self right by `rhs` bits. + +Returns a tuple of the shifted version of self along with a boolean +indicating whether the shift value was larger than or equal to the +number of bits. If the shift value is too large, then value is +masked (N-1) where N is the number of bits, and this value is then +used to perform the shift. + +# Examples + +Basic usage + +``` +", $Feature, "assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(4), (0x1, false)); +assert_eq!(0x10", stringify!($SelfT), ".overflowing_shr(132), (0x1, true));", $EndFeature, " +```"), + #[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"] + #[inline] + pub const fn overflowing_shr(self, rhs: u32) -> (Self, bool) { + (self.wrapping_shr(rhs), (rhs > ($BITS - 1))) + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +Returns a tuple of the exponentiation along with a bool indicating +whether an overflow happened. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(3", stringify!($SelfT), ".overflowing_pow(5), (243, false)); +assert_eq!(3u8.overflowing_pow(6), (217, true));", $EndFeature, " +```"), + #[stable(feature = "no_panic_pow", since = "1.34.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + pub const fn overflowing_pow(self, mut exp: u32) -> (Self, bool) { + if exp == 0{ + return (1,false); + } + let mut base = self; + let mut acc: Self = 1; + let mut overflown = false; + // Scratch space for storing results of overflowing_mul. + let mut r; + + while exp > 1 { + if (exp & 1) == 1 { + r = acc.overflowing_mul(base); + acc = r.0; + overflown |= r.1; + } + exp /= 2; + r = base.overflowing_mul(base); + base = r.0; + overflown |= r.1; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + r = acc.overflowing_mul(base); + r.1 |= overflown; + + r + } + } + + doc_comment! { + concat!("Raises self to the power of `exp`, using exponentiation by squaring. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".pow(5), 32);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn pow(self, mut exp: u32) -> Self { + if exp == 0 { + return 1; + } + let mut base = self; + let mut acc = 1; + + while exp > 1 { + if (exp & 1) == 1 { + acc = acc * base; + } + exp /= 2; + base = base * base; + } + + // since exp!=0, finally the exp must be 1. + // Deal with the final bit of the exponent separately, since + // squaring the base afterwards is not necessary and may cause a + // needless overflow. + acc * base + } + } + + doc_comment! { + concat!("Performs Euclidean division. + +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self / rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(7", stringify!($SelfT), ".div_euclid(4), 1); // or any other integer type +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn div_euclid(self, rhs: Self) -> Self { + self / rhs + } + } + + + doc_comment! { + concat!("Calculates the least remainder of `self (mod rhs)`. + +Since, for the positive integers, all common +definitions of division are equal, this +is exactly equal to `self % rhs`. + +# Panics + +This function will panic if `rhs` is 0. + +# Examples + +Basic usage: + +``` +assert_eq!(7", stringify!($SelfT), ".rem_euclid(4), 3); // or any other integer type +```"), + #[stable(feature = "euclidean_division", since = "1.38.0")] + #[rustc_const_unstable(feature = "const_euclidean_int_methods", issue = "53718")] + #[must_use = "this returns the result of the operation, \ + without modifying the original"] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn rem_euclid(self, rhs: Self) -> Self { + self % rhs + } + } + + doc_comment! { + concat!("Returns `true` if and only if `self == 2^k` for some `k`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert!(16", stringify!($SelfT), ".is_power_of_two()); +assert!(!10", stringify!($SelfT), ".is_power_of_two());", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "const_is_power_of_two", since = "1.32.0")] + #[inline] + pub const fn is_power_of_two(self) -> bool { + self.count_ones() == 1 + } + } + + // Returns one less than next power of two. + // (For 8u8 next power of two is 8u8 and for 6u8 it is 8u8) + // + // 8u8.one_less_than_next_power_of_two() == 7 + // 6u8.one_less_than_next_power_of_two() == 7 + // + // This method cannot overflow, as in the `next_power_of_two` + // overflow cases it instead ends up returning the maximum value + // of the type, and can return 0 for 0. + #[inline] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + const fn one_less_than_next_power_of_two(self) -> Self { + if self <= 1 { return 0; } + + let p = self - 1; + // SAFETY: Because `p > 0`, it cannot consist entirely of leading zeros. + // That means the shift is always in-bounds, and some processors + // (such as intel pre-haswell) have more efficient ctlz + // intrinsics when the argument is non-zero. + let z = unsafe { intrinsics::ctlz_nonzero(p) }; + <$SelfT>::MAX >> z + } + + doc_comment! { + concat!("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 +release mode (the only situation in which method can return 0). + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), ".next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".next_power_of_two(), 4);", $EndFeature, " +```"), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + #[inline] + #[rustc_inherit_overflow_checks] + pub const fn next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two() + 1 + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +`None` is returned, otherwise the power of two is wrapped in `Some`. + +# Examples + +Basic usage: + +``` +", $Feature, "assert_eq!(2", stringify!($SelfT), +".checked_next_power_of_two(), Some(2)); +assert_eq!(3", stringify!($SelfT), ".checked_next_power_of_two(), Some(4)); +assert_eq!(", stringify!($SelfT), "::MAX.checked_next_power_of_two(), None);", +$EndFeature, " +```"), + #[inline] + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + pub const fn checked_next_power_of_two(self) -> Option { + self.one_less_than_next_power_of_two().checked_add(1) + } + } + + doc_comment! { + concat!("Returns the smallest power of two greater than or equal to `n`. If +the next power of two is greater than the type's maximum value, +the return value is wrapped to `0`. + +# Examples + +Basic usage: + +``` +#![feature(wrapping_next_power_of_two)] +", $Feature, " +assert_eq!(2", stringify!($SelfT), ".wrapping_next_power_of_two(), 2); +assert_eq!(3", stringify!($SelfT), ".wrapping_next_power_of_two(), 4); +assert_eq!(", stringify!($SelfT), "::MAX.wrapping_next_power_of_two(), 0);", +$EndFeature, " +```"), + #[unstable(feature = "wrapping_next_power_of_two", issue = "32463", + reason = "needs decision on wrapping behaviour")] + #[rustc_const_unstable(feature = "const_int_pow", issue = "53718")] + pub const fn wrapping_next_power_of_two(self) -> Self { + self.one_less_than_next_power_of_two().wrapping_add(1) + } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +big-endian (network) byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_be_bytes(); +assert_eq!(bytes, ", $be_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_be_bytes(self) -> [u8; mem::size_of::()] { + self.to_be().to_ne_bytes() + } + } + + doc_comment! { + concat!("Return the memory representation of this integer as a byte array in +little-endian byte order. +", +$to_xe_bytes_doc, +" +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_le_bytes(); +assert_eq!(bytes, ", $le_bytes, "); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn to_le_bytes(self) -> [u8; mem::size_of::()] { + self.to_le().to_ne_bytes() + } + } + + doc_comment! { + concat!(" +Return the memory representation of this integer as a byte array in +native byte order. + +As the target platform's native endianness is used, portable code +should use [`to_be_bytes`] or [`to_le_bytes`], as appropriate, +instead. +", +$to_xe_bytes_doc, +" +[`to_be_bytes`]: #method.to_be_bytes +[`to_le_bytes`]: #method.to_le_bytes + +# Examples + +``` +let bytes = ", $swap_op, stringify!($SelfT), ".to_ne_bytes(); +assert_eq!( + bytes, + if cfg!(target_endian = \"big\") { + ", $be_bytes, " + } else { + ", $le_bytes, " + } +); +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[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 + #[allow_internal_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 + // arrays of bytes + unsafe { mem::transmute(self) } + } + } + + doc_comment! { + concat!("Create a native endian integer value from its representation +as a byte array in big endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_be_bytes(", $be_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_be_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_be_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_be_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_be(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!(" +Create a native endian integer value from its representation +as a byte array in little endian. +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_le_bytes(", $le_bytes, "); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_le_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_le_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[rustc_const_stable(feature = "const_int_conversion", since = "1.44.0")] + #[inline] + pub const fn from_le_bytes(bytes: [u8; mem::size_of::()]) -> Self { + Self::from_le(Self::from_ne_bytes(bytes)) + } + } + + doc_comment! { + concat!("Create a native endian integer value from its memory representation +as a byte array in native endianness. + +As the target platform's native endianness is used, portable code +likely wants to use [`from_be_bytes`] or [`from_le_bytes`], as +appropriate instead. + +[`from_be_bytes`]: #method.from_be_bytes +[`from_le_bytes`]: #method.from_le_bytes +", +$from_xe_bytes_doc, +" +# Examples + +``` +let value = ", stringify!($SelfT), "::from_ne_bytes(if cfg!(target_endian = \"big\") { + ", $be_bytes, " +} else { + ", $le_bytes, " +}); +assert_eq!(value, ", $swap_op, "); +``` + +When starting from a slice rather than an array, fallible conversion APIs can be used: + +``` +use std::convert::TryInto; + +fn read_ne_", stringify!($SelfT), "(input: &mut &[u8]) -> ", stringify!($SelfT), " { + let (int_bytes, rest) = input.split_at(std::mem::size_of::<", stringify!($SelfT), ">()); + *input = rest; + ", stringify!($SelfT), "::from_ne_bytes(int_bytes.try_into().unwrap()) +} +```"), + #[stable(feature = "int_to_from_bytes", since = "1.32.0")] + #[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 to them + #[allow_internal_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 + unsafe { mem::transmute(bytes) } + } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause compilation warning, +new code should use [`", stringify!($SelfT), "::MIN", "`](#associatedconstant.MIN) instead. + +Returns the smallest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_promotable] + #[inline(always)] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn min_value() -> Self { Self::MIN } + } + + doc_comment! { + concat!("**This method is soft-deprecated.** + +Although using it won’t cause compilation warning, +new code should use [`", stringify!($SelfT), "::MAX", "`](#associatedconstant.MAX) instead. + +Returns the largest value that can be represented by this integer type."), + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_promotable] + #[inline(always)] + #[rustc_const_stable(feature = "const_max_value", since = "1.32.0")] + pub const fn max_value() -> Self { Self::MAX } + } + } +} diff --git a/library/core/src/num/wrapping.rs b/library/core/src/num/wrapping.rs index f6acb8f8b9..5324dfdedd 100644 --- a/library/core/src/num/wrapping.rs +++ b/library/core/src/num/wrapping.rs @@ -1,6 +1,83 @@ -use super::Wrapping; +//! Definitions of `Wrapping`. -use crate::ops::*; +use crate::fmt; +use crate::ops::{Add, AddAssign, BitAnd, BitAndAssign, BitOr, BitOrAssign}; +use crate::ops::{BitXor, BitXorAssign, Div, DivAssign}; +use crate::ops::{Mul, MulAssign, Neg, Not, Rem, RemAssign}; +use crate::ops::{Shl, ShlAssign, Shr, ShrAssign, Sub, SubAssign}; + +/// Provides intentionally-wrapped arithmetic on `T`. +/// +/// Operations like `+` on `u32` values are intended to never overflow, +/// and in some debug configurations overflow is detected and results +/// in a panic. While most arithmetic falls into this category, some +/// code explicitly expects and relies upon modular arithmetic (e.g., +/// hashing). +/// +/// Wrapping arithmetic can be achieved either through methods like +/// `wrapping_add`, or through the `Wrapping` type, which says that +/// all standard arithmetic operations on the underlying value are +/// intended to have wrapping semantics. +/// +/// The underlying value can be retrieved through the `.0` index of the +/// `Wrapping` tuple. +/// +/// # Examples +/// +/// ``` +/// use std::num::Wrapping; +/// +/// let zero = Wrapping(0u32); +/// let one = Wrapping(1u32); +/// +/// assert_eq!(u32::MAX, (zero - one).0); +/// ``` +#[stable(feature = "rust1", since = "1.0.0")] +#[derive(PartialEq, Eq, PartialOrd, Ord, Clone, Copy, Default, Hash)] +#[repr(transparent)] +pub struct Wrapping(#[stable(feature = "rust1", since = "1.0.0")] pub T); + +#[stable(feature = "rust1", since = "1.0.0")] +impl fmt::Debug for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_display", since = "1.10.0")] +impl fmt::Display for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::Binary for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::Octal for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::LowerHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} + +#[stable(feature = "wrapping_fmt", since = "1.11.0")] +impl fmt::UpperHex for Wrapping { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.0.fmt(f) + } +} #[allow(unused_macros)] macro_rules! sh_impl_signed { diff --git a/library/core/src/ops/arith.rs b/library/core/src/ops/arith.rs index 622a138abe..19f86ced50 100644 --- a/library/core/src/ops/arith.rs +++ b/library/core/src/ops/arith.rs @@ -78,6 +78,12 @@ pub trait Add { type Output; /// Performs the `+` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 + 1, 13); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn add(self, rhs: Rhs) -> Self::Output; @@ -122,10 +128,10 @@ add_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// } /// /// impl Sub for Point { -/// type Output = Point; +/// type Output = Self; /// -/// fn sub(self, other: Point) -> Point { -/// Point { +/// fn sub(self, other: Self) -> Self::Output { +/// Self { /// x: self.x - other.x, /// y: self.y - other.y, /// } @@ -178,6 +184,12 @@ pub trait Sub { type Output; /// Performs the `-` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 - 1, 11); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn sub(self, rhs: Rhs) -> Self::Output; @@ -229,7 +241,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. /// let gcd = gcd(numerator, denominator); -/// Rational { +/// Self { /// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } @@ -243,7 +255,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// fn mul(self, rhs: Self) -> Self { /// let numerator = self.numerator * rhs.numerator; /// let denominator = self.denominator * rhs.denominator; -/// Rational::new(numerator, denominator) +/// Self::new(numerator, denominator) /// } /// } /// @@ -279,7 +291,7 @@ sub_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn mul(self, rhs: Scalar) -> Self::Output { -/// Vector { value: self.value.iter().map(|v| v * rhs.value).collect() } +/// Self { value: self.value.iter().map(|v| v * rhs.value).collect() } /// } /// } /// @@ -300,6 +312,12 @@ pub trait Mul { type Output; /// Performs the `*` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 * 2, 24); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn mul(self, rhs: Rhs) -> Self::Output; @@ -351,7 +369,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// // Reduce to lowest terms by dividing by the greatest common /// // divisor. /// let gcd = gcd(numerator, denominator); -/// Rational { +/// Self { /// numerator: numerator / gcd, /// denominator: denominator / gcd, /// } @@ -369,7 +387,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// /// let numerator = self.numerator * rhs.denominator; /// let denominator = self.denominator * rhs.numerator; -/// Rational::new(numerator, denominator) +/// Self::new(numerator, denominator) /// } /// } /// @@ -405,7 +423,7 @@ mul_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } /// type Output = Self; /// /// fn div(self, rhs: Scalar) -> Self::Output { -/// Vector { value: self.value.iter().map(|v| v / rhs.value).collect() } +/// Self { value: self.value.iter().map(|v| v / rhs.value).collect() } /// } /// } /// @@ -426,6 +444,12 @@ pub trait Div { type Output; /// Performs the `/` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 / 2, 6); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn div(self, rhs: Rhs) -> Self::Output; @@ -491,7 +515,7 @@ div_impl_float! { f32 f64 } /// let len = self.slice.len(); /// let rem = len % modulus; /// let start = len - rem; -/// SplitSlice {slice: &self.slice[start..]} +/// Self {slice: &self.slice[start..]} /// } /// } /// @@ -513,6 +537,12 @@ pub trait Rem { type Output; /// Performs the `%` operation. + /// + /// # Example + /// + /// ``` + /// assert_eq!(12 % 10, 2); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn rem(self, rhs: Rhs) -> Self::Output; @@ -585,7 +615,7 @@ rem_impl_float! { f32 f64 } /// } /// /// impl Neg for Sign { -/// type Output = Sign; +/// type Output = Self; /// /// fn neg(self) -> Self::Output { /// match self { @@ -612,6 +642,13 @@ pub trait Neg { type Output; /// Performs the unary `-` operation. + /// + /// # Example + /// + /// ``` + /// let x: i32 = 12; + /// assert_eq!(-x, -12); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn neg(self) -> Self::Output; @@ -673,6 +710,14 @@ neg_impl! { isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "+=")] pub trait AddAssign { /// Performs the `+=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x += 1; + /// assert_eq!(x, 13); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn add_assign(&mut self, rhs: Rhs); } @@ -731,6 +776,14 @@ add_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "-=")] pub trait SubAssign { /// Performs the `-=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x -= 1; + /// assert_eq!(x, 11); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn sub_assign(&mut self, rhs: Rhs); } @@ -780,6 +833,14 @@ sub_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "*=")] pub trait MulAssign { /// Performs the `*=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x *= 2; + /// assert_eq!(x, 24); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn mul_assign(&mut self, rhs: Rhs); } @@ -829,6 +890,14 @@ mul_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "/=")] pub trait DivAssign { /// Performs the `/=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x /= 2; + /// assert_eq!(x, 6); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn div_assign(&mut self, rhs: Rhs); } @@ -881,6 +950,14 @@ div_assign_impl! { usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 f32 f64 } #[doc(alias = "%=")] pub trait RemAssign { /// Performs the `%=` operation. + /// + /// # Example + /// + /// ``` + /// let mut x: u32 = 12; + /// x %= 10; + /// assert_eq!(x, 2); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn rem_assign(&mut self, rhs: Rhs); } diff --git a/library/core/src/ops/bit.rs b/library/core/src/ops/bit.rs index bcfff4a223..6120da50c3 100644 --- a/library/core/src/ops/bit.rs +++ b/library/core/src/ops/bit.rs @@ -15,7 +15,7 @@ /// } /// /// impl Not for Answer { -/// type Output = Answer; +/// type Output = Self; /// /// fn not(self) -> Self::Output { /// match self { @@ -36,6 +36,15 @@ pub trait Not { type Output; /// Performs the unary `!` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(!true, false); + /// assert_eq!(!false, true); + /// assert_eq!(!1u8, 254); + /// assert_eq!(!0u8, 255); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn not(self) -> Self::Output; @@ -76,7 +85,7 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// // rhs is the "right-hand side" of the expression `a & b` /// fn bitand(self, rhs: Self) -> Self::Output { -/// Scalar(self.0 & rhs.0) +/// Self(self.0 & rhs.0) /// } /// } /// @@ -97,10 +106,13 @@ not_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitAnd for BooleanVector { /// type Output = Self; /// -/// fn bitand(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitand(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x && *y).collect()) +/// Self(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()) /// } /// } /// @@ -122,6 +134,15 @@ pub trait BitAnd { type Output; /// Performs the `&` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true & false, false); + /// assert_eq!(true & true, true); + /// assert_eq!(5u8 & 1u8, 1); + /// assert_eq!(5u8 & 2u8, 0); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitand(self, rhs: Rhs) -> Self::Output; @@ -161,8 +182,8 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// type Output = Self; /// /// // rhs is the "right-hand side" of the expression `a | b` -/// fn bitor(self, rhs: Self) -> Self { -/// Scalar(self.0 | rhs.0) +/// fn bitor(self, rhs: Self) -> Self::Output { +/// Self(self.0 | rhs.0) /// } /// } /// @@ -183,10 +204,10 @@ bitand_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitOr for BooleanVector { /// type Output = Self; /// -/// fn bitor(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitor(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) +/// Self(lhs.iter().zip(rhs.iter()).map(|(x, y)| *x || *y).collect()) /// } /// } /// @@ -208,6 +229,15 @@ pub trait BitOr { type Output; /// Performs the `|` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true | false, true); + /// assert_eq!(false | false, false); + /// assert_eq!(5u8 | 1u8, 5); + /// assert_eq!(5u8 | 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitor(self, rhs: Rhs) -> Self::Output; @@ -248,7 +278,7 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// /// // rhs is the "right-hand side" of the expression `a ^ b` /// fn bitxor(self, rhs: Self) -> Self::Output { -/// Scalar(self.0 ^ rhs.0) +/// Self(self.0 ^ rhs.0) /// } /// } /// @@ -269,13 +299,13 @@ bitor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl BitXor for BooleanVector { /// type Output = Self; /// -/// fn bitxor(self, BooleanVector(rhs): Self) -> Self::Output { -/// let BooleanVector(lhs) = self; +/// fn bitxor(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; /// assert_eq!(lhs.len(), rhs.len()); -/// BooleanVector(lhs.iter() -/// .zip(rhs.iter()) -/// .map(|(x, y)| (*x || *y) && !(*x && *y)) -/// .collect()) +/// Self(lhs.iter() +/// .zip(rhs.iter()) +/// .map(|(x, y)| (*x || *y) && !(*x && *y)) +/// .collect()) /// } /// } /// @@ -297,6 +327,15 @@ pub trait BitXor { type Output; /// Performs the `^` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(true ^ false, true); + /// assert_eq!(true ^ true, false); + /// assert_eq!(5u8 ^ 1u8, 4); + /// assert_eq!(5u8 ^ 2u8, 7); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn bitxor(self, rhs: Rhs) -> Self::Output; @@ -339,9 +378,9 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// impl Shl for Scalar { /// type Output = Self; /// -/// fn shl(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs << rhs) +/// fn shl(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; +/// Self(lhs << rhs) /// } /// } /// @@ -364,10 +403,10 @@ bitxor_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } /// fn shl(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(rhs); -/// let mut spun_vector: Vec = vec![]; +/// let mut spun_vector = vec![]; /// spun_vector.extend_from_slice(b); /// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } +/// Self { vec: spun_vector } /// } /// } /// @@ -387,6 +426,13 @@ pub trait Shl { type Output; /// Performs the `<<` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 << 1, 10); + /// assert_eq!(1u8 << 1, 2); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shl(self, rhs: Rhs) -> Self::Output; @@ -450,9 +496,9 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// impl Shr for Scalar { /// type Output = Self; /// -/// fn shr(self, Scalar(rhs): Self) -> Scalar { -/// let Scalar(lhs) = self; -/// Scalar(lhs >> rhs) +/// fn shr(self, Self(rhs): Self) -> Self::Output { +/// let Self(lhs) = self; +/// Self(lhs >> rhs) /// } /// } /// @@ -475,10 +521,10 @@ shl_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 isize i128 } /// fn shr(self, rhs: usize) -> Self::Output { /// // Rotate the vector by `rhs` places. /// let (a, b) = self.vec.split_at(self.vec.len() - rhs); -/// let mut spun_vector: Vec = vec![]; +/// let mut spun_vector = vec![]; /// spun_vector.extend_from_slice(b); /// spun_vector.extend_from_slice(a); -/// SpinVector { vec: spun_vector } +/// Self { vec: spun_vector } /// } /// } /// @@ -498,6 +544,13 @@ pub trait Shr { type Output; /// Performs the `>>` operation. + /// + /// # Examples + /// + /// ``` + /// assert_eq!(5u8 >> 1, 2); + /// assert_eq!(2u8 >> 1, 1); + /// ``` #[must_use] #[stable(feature = "rust1", since = "1.0.0")] fn shr(self, rhs: Rhs) -> Self::Output; @@ -556,7 +609,7 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// impl BitAndAssign for Scalar { /// // rhs is the "right-hand side" of the expression `a &= b` /// fn bitand_assign(&mut self, rhs: Self) { -/// *self = Scalar(self.0 & rhs.0) +/// *self = Self(self.0 & rhs.0) /// } /// } /// @@ -590,11 +643,11 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } /// // `rhs` is the "right-hand side" of the expression `a &= b`. /// fn bitand_assign(&mut self, rhs: Self) { /// assert_eq!(self.0.len(), rhs.0.len()); -/// *self = BooleanVector(self.0 -/// .iter() -/// .zip(rhs.0.iter()) -/// .map(|(x, y)| *x && *y) -/// .collect()); +/// *self = Self(self.0 +/// .iter() +/// .zip(rhs.0.iter()) +/// .map(|(x, y)| *x && *y) +/// .collect()); /// } /// } /// @@ -612,6 +665,26 @@ shr_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait BitAndAssign { /// Performs the `&=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x &= false; + /// assert_eq!(x, false); + /// + /// let mut x = true; + /// x &= true; + /// assert_eq!(x, true); + /// + /// let mut x: u8 = 5; + /// x &= 1; + /// assert_eq!(x, 1); + /// + /// let mut x: u8 = 5; + /// x &= 2; + /// assert_eq!(x, 0); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitand_assign(&mut self, rhs: Rhs); } @@ -663,6 +736,26 @@ bitand_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitOrAssign { /// Performs the `|=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x |= false; + /// assert_eq!(x, true); + /// + /// let mut x = false; + /// x |= false; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x |= 1; + /// assert_eq!(x, 5); + /// + /// let mut x: u8 = 5; + /// x |= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitor_assign(&mut self, rhs: Rhs); } @@ -714,6 +807,26 @@ bitor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait BitXorAssign { /// Performs the `^=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x = true; + /// x ^= false; + /// assert_eq!(x, true); + /// + /// let mut x = true; + /// x ^= true; + /// assert_eq!(x, false); + /// + /// let mut x: u8 = 5; + /// x ^= 1; + /// assert_eq!(x, 4); + /// + /// let mut x: u8 = 5; + /// x ^= 2; + /// assert_eq!(x, 7); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn bitxor_assign(&mut self, rhs: Rhs); } @@ -763,6 +876,18 @@ bitxor_assign_impl! { bool usize u8 u16 u32 u64 u128 isize i8 i16 i32 i64 i128 } )] pub trait ShlAssign { /// Performs the `<<=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x <<= 1; + /// assert_eq!(x, 10); + /// + /// let mut x: u8 = 1; + /// x <<= 1; + /// assert_eq!(x, 2); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shl_assign(&mut self, rhs: Rhs); } @@ -833,6 +958,18 @@ shl_assign_impl_all! { u8 u16 u32 u64 u128 usize i8 i16 i32 i64 i128 isize } )] pub trait ShrAssign { /// Performs the `>>=` operation. + /// + /// # Examples + /// + /// ``` + /// let mut x: u8 = 5; + /// x >>= 1; + /// assert_eq!(x, 2); + /// + /// let mut x: u8 = 2; + /// x >>= 1; + /// assert_eq!(x, 1); + /// ``` #[stable(feature = "op_assign_traits", since = "1.8.0")] fn shr_assign(&mut self, rhs: Rhs); } diff --git a/library/core/src/ops/control_flow.rs b/library/core/src/ops/control_flow.rs new file mode 100644 index 0000000000..b0c7dc1a51 --- /dev/null +++ b/library/core/src/ops/control_flow.rs @@ -0,0 +1,110 @@ +use crate::ops::Try; + +/// Used to make try_fold closures more like normal loops +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum ControlFlow { + /// Continue in the loop, using the given value for the next iteration + Continue(C), + /// Exit the loop, yielding the given value + Break(B), +} + +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +impl Try for ControlFlow { + type Ok = C; + type Error = B; + #[inline] + fn into_result(self) -> Result { + match self { + ControlFlow::Continue(y) => Ok(y), + ControlFlow::Break(x) => Err(x), + } + } + #[inline] + fn from_error(v: Self::Error) -> Self { + ControlFlow::Break(v) + } + #[inline] + fn from_ok(v: Self::Ok) -> Self { + ControlFlow::Continue(v) + } +} + +impl ControlFlow { + /// Converts the `ControlFlow` into an `Option` which is `Some` if the + /// `ControlFlow` was `Break` and `None` otherwise. + #[inline] + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub fn break_value(self) -> Option { + match self { + ControlFlow::Continue(..) => None, + ControlFlow::Break(x) => Some(x), + } + } +} + +impl ControlFlow { + /// Create a `ControlFlow` from any type implementing `Try`. + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn from_try(r: R) -> Self { + match Try::into_result(r) { + Ok(v) => ControlFlow::Continue(v), + Err(v) => ControlFlow::Break(Try::from_error(v)), + } + } + + /// Convert a `ControlFlow` into any type implementing `Try`; + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + #[inline] + pub fn into_try(self) -> R { + match self { + ControlFlow::Continue(v) => Try::from_ok(v), + ControlFlow::Break(v) => v, + } + } +} + +impl ControlFlow<(), B> { + /// It's frequently the case that there's no value needed with `Continue`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// let last_used = (1..10).chain(20..25).try_for_each(|x| { + /// partial_sum += x; + /// if partial_sum > 100 { ControlFlow::Break(x) } + /// else { ControlFlow::CONTINUE } + /// }); + /// assert_eq!(last_used.break_value(), Some(22)); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const CONTINUE: Self = ControlFlow::Continue(()); +} + +impl ControlFlow { + /// APIs like `try_for_each` don't need values with `Break`, + /// so this provides a way to avoid typing `(())`, if you prefer it. + /// + /// # Examples + /// + /// ``` + /// #![feature(control_flow_enum)] + /// use std::ops::ControlFlow; + /// + /// let mut partial_sum = 0; + /// (1..10).chain(20..25).try_for_each(|x| { + /// if partial_sum > 100 { ControlFlow::BREAK } + /// else { partial_sum += x; ControlFlow::CONTINUE } + /// }); + /// assert_eq!(partial_sum, 108); + /// ``` + #[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] + pub const BREAK: Self = ControlFlow::Break(()); +} diff --git a/library/core/src/ops/deref.rs b/library/core/src/ops/deref.rs index d6c097eee1..245152e549 100644 --- a/library/core/src/ops/deref.rs +++ b/library/core/src/ops/deref.rs @@ -63,11 +63,13 @@ pub trait Deref { /// The resulting type after dereferencing. #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_target"] type Target: ?Sized; /// Dereferences the value. #[must_use] #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_diagnostic_item = "deref_method"] fn deref(&self) -> &Self::Target; } diff --git a/library/core/src/ops/mod.rs b/library/core/src/ops/mod.rs index c19bd6e441..354ad6b7b7 100644 --- a/library/core/src/ops/mod.rs +++ b/library/core/src/ops/mod.rs @@ -49,18 +49,18 @@ //! } //! //! impl Add for Point { -//! type Output = Point; +//! type Output = Self; //! -//! fn add(self, other: Point) -> Point { -//! Point {x: self.x + other.x, y: self.y + other.y} +//! fn add(self, other: Self) -> Self { +//! Self {x: self.x + other.x, y: self.y + other.y} //! } //! } //! //! impl Sub for Point { -//! type Output = Point; +//! type Output = Self; //! -//! fn sub(self, other: Point) -> Point { -//! Point {x: self.x - other.x, y: self.y - other.y} +//! fn sub(self, other: Self) -> Self { +//! Self {x: self.x - other.x, y: self.y - other.y} //! } //! } //! @@ -140,6 +140,7 @@ mod arith; mod bit; +mod control_flow; mod deref; mod drop; mod function; @@ -191,3 +192,6 @@ pub use self::unsize::CoerceUnsized; #[unstable(feature = "dispatch_from_dyn", issue = "none")] pub use self::unsize::DispatchFromDyn; + +#[unstable(feature = "control_flow_enum", reason = "new API", issue = "75744")] +pub use self::control_flow::ControlFlow; diff --git a/library/core/src/ops/range.rs b/library/core/src/ops/range.rs index d10829832d..2eaf7601e5 100644 --- a/library/core/src/ops/range.rs +++ b/library/core/src/ops/range.rs @@ -36,7 +36,7 @@ use crate::hash::Hash; /// ``` /// /// [slicing index]: crate::slice::SliceIndex -#[cfg_attr(not(bootstrap), lang = "RangeFull")] +#[lang = "RangeFull"] #[doc(alias = "..")] #[derive(Copy, Clone, Default, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -69,7 +69,7 @@ impl fmt::Debug for RangeFull { /// assert_eq!(arr[1.. 3], [ 1,2 ]); // Range /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` -#[cfg_attr(not(bootstrap), lang = "Range")] +#[lang = "Range"] #[doc(alias = "..")] #[derive(Clone, Default, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -172,7 +172,7 @@ impl> Range { /// assert_eq!(arr[1.. 3], [ 1,2 ]); /// assert_eq!(arr[1..=3], [ 1,2,3 ]); /// ``` -#[cfg_attr(not(bootstrap), lang = "RangeFrom")] +#[lang = "RangeFrom"] #[doc(alias = "..")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "rust1", since = "1.0.0")] @@ -253,7 +253,7 @@ impl> RangeFrom { /// ``` /// /// [slicing index]: crate::slice::SliceIndex -#[cfg_attr(not(bootstrap), lang = "RangeTo")] +#[lang = "RangeTo"] #[doc(alias = "..")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "rust1", since = "1.0.0")] @@ -322,7 +322,7 @@ impl> RangeTo { /// assert_eq!(arr[1.. 3], [ 1,2 ]); /// assert_eq!(arr[1..=3], [ 1,2,3 ]); // RangeInclusive /// ``` -#[cfg_attr(not(bootstrap), lang = "RangeInclusive")] +#[lang = "RangeInclusive"] #[doc(alias = "..=")] #[derive(Clone, PartialEq, Eq, Hash)] // not Copy -- see #27186 #[stable(feature = "inclusive_range", since = "1.26.0")] @@ -354,7 +354,7 @@ impl RangeInclusive { /// /// assert_eq!(3..=5, RangeInclusive::new(3, 5)); /// ``` - #[cfg_attr(not(bootstrap), lang = "range_inclusive_new")] + #[lang = "range_inclusive_new"] #[stable(feature = "inclusive_range_methods", since = "1.27.0")] #[inline] #[rustc_promotable] @@ -543,7 +543,7 @@ impl> RangeInclusive { /// ``` /// /// [slicing index]: crate::slice::SliceIndex -#[cfg_attr(not(bootstrap), lang = "RangeToInclusive")] +#[lang = "RangeToInclusive"] #[doc(alias = "..=")] #[derive(Copy, Clone, PartialEq, Eq, Hash)] #[stable(feature = "inclusive_range", since = "1.26.0")] diff --git a/library/core/src/ops/try.rs b/library/core/src/ops/try.rs index e6b05cc641..3bede56997 100644 --- a/library/core/src/ops/try.rs +++ b/library/core/src/ops/try.rs @@ -43,19 +43,19 @@ pub trait Try { /// in the return type of the enclosing scope (which must itself implement /// `Try`). Specifically, the value `X::from_error(From::from(e))` /// is returned, where `X` is the return type of the enclosing function. - #[cfg_attr(not(bootstrap), lang = "into_result")] + #[lang = "into_result"] #[unstable(feature = "try_trait", issue = "42327")] fn into_result(self) -> Result; /// Wrap an error value to construct the composite result. For example, /// `Result::Err(x)` and `Result::from_error(x)` are equivalent. - #[cfg_attr(not(bootstrap), lang = "from_error")] + #[lang = "from_error"] #[unstable(feature = "try_trait", issue = "42327")] fn from_error(v: Self::Error) -> Self; /// Wrap an OK value to construct the composite result. For example, /// `Result::Ok(x)` and `Result::from_ok(x)` are equivalent. - #[cfg_attr(not(bootstrap), lang = "from_ok")] + #[lang = "from_ok"] #[unstable(feature = "try_trait", issue = "42327")] fn from_ok(v: Self::Ok) -> Self; } diff --git a/library/core/src/option.rs b/library/core/src/option.rs index b6aa2c6697..0cfb4af59b 100644 --- a/library/core/src/option.rs +++ b/library/core/src/option.rs @@ -70,10 +70,23 @@ //! } //! ``` //! -//! This usage of [`Option`] to create safe nullable pointers is so -//! common that Rust does special optimizations to make the -//! representation of [`Option`]`<`[`Box`]`>` a single pointer. Optional pointers -//! in Rust are stored as efficiently as any other pointer type. +//! # Representation +//! +//! Rust guarantees to optimize the following types `T` such that +//! [`Option`] has the same size as `T`: +//! +//! * [`Box`] +//! * `&U` +//! * `&mut U` +//! * `fn`, `extern "C" fn` +//! * [`num::NonZero*`] +//! * [`ptr::NonNull`] +//! * `#[repr(transparent)]` struct around one of the types in this list. +//! +//! It is further guaranteed that, for the cases above, one can +//! [`mem::transmute`] from all valid values of `T` to `Option` and +//! from `Some::(_)` to `T` (but transmuting `None::` to `T` +//! is undefined behaviour). //! //! # Examples //! @@ -144,11 +157,11 @@ use crate::{ #[stable(feature = "rust1", since = "1.0.0")] pub enum Option { /// No value - #[cfg_attr(not(bootstrap), lang = "None")] + #[lang = "None"] #[stable(feature = "rust1", since = "1.0.0")] None, /// Some value `T` - #[cfg_attr(not(bootstrap), lang = "Some")] + #[lang = "Some"] #[stable(feature = "rust1", since = "1.0.0")] Some(#[stable(feature = "rust1", since = "1.0.0")] T), } @@ -175,7 +188,7 @@ impl Option { /// ``` #[must_use = "if you intended to assert that this has a value, consider `.unwrap()` instead"] #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_some(&self) -> bool { matches!(*self, Some(_)) @@ -195,7 +208,7 @@ impl Option { #[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_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn is_none(&self) -> bool { !self.is_some() @@ -254,7 +267,7 @@ impl Option { /// println!("still can print text: {:?}", text); /// ``` #[inline] - #[rustc_const_unstable(feature = "const_option", issue = "67441")] + #[rustc_const_stable(feature = "const_option", since = "1.48.0")] #[stable(feature = "rust1", since = "1.0.0")] pub const fn as_ref(&self) -> Option<&T> { match *self { @@ -1502,8 +1515,6 @@ unsafe impl TrustedLen for IterMut<'_, A> {} /// The iterator yields one value if the [`Option`] is a [`Some`], otherwise none. /// /// This `struct` is created by the [`Option::into_iter`] function. -/// -/// [`Option::into_iter`]: enum.Option.html#method.into_iter #[derive(Clone, Debug)] #[stable(feature = "rust1", since = "1.0.0")] pub struct IntoIter { diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 316ecafe57..34a974b827 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -92,8 +92,6 @@ impl<'a> PanicInfo<'a> { /// If the `panic!` macro from the `core` crate (not from `std`) /// was used with a formatting string and some additional arguments, /// returns that message ready to be used for example with [`fmt::write`] - /// - /// [`fmt::write`]: ../fmt/fn.write.html #[unstable(feature = "panic_info_message", issue = "66745")] pub fn message(&self) -> Option<&fmt::Arguments<'_>> { self.message @@ -105,8 +103,6 @@ impl<'a> PanicInfo<'a> { /// This method will currently always return [`Some`], but this may change /// in future versions. /// - /// [`Some`]: ../../std/option/enum.Option.html#variant.Some - /// /// # Examples /// /// ```should_panic @@ -153,10 +149,7 @@ impl fmt::Display for PanicInfo<'_> { /// A struct containing information about the location of a panic. /// -/// This structure is created by the [`location`] method of [`PanicInfo`]. -/// -/// [`location`]: ../../std/panic/struct.PanicInfo.html#method.location -/// [`PanicInfo`]: ../../std/panic/struct.PanicInfo.html +/// This structure is created by [`PanicInfo::location()`]. /// /// # Examples /// @@ -232,7 +225,7 @@ impl<'a> Location<'a> { /// assert_ne!(this_location.column(), another_location.column()); /// ``` #[stable(feature = "track_caller", since = "1.46.0")] - #[rustc_const_unstable(feature = "const_caller_location", issue = "47809")] + #[rustc_const_unstable(feature = "const_caller_location", issue = "76156")] #[track_caller] pub const fn caller() -> &'static Location<'static> { crate::intrinsics::caller_location() diff --git a/library/core/src/pin.rs b/library/core/src/pin.rs index 290aa797fd..9f0284d5d9 100644 --- a/library/core/src/pin.rs +++ b/library/core/src/pin.rs @@ -471,10 +471,11 @@ impl> Pin

", class, tooltip ) .unwrap(); } - let sess = ParseSess::with_silent_emitter(); - let source_file = sess - .source_map() - .new_source_file(FileName::Custom(String::from("rustdoc-highlighting")), src); + write_header(&mut out, class); + write_code(&mut out, &src); + write_footer(&mut out, playground_button); - let classifier_source_file = Lrc::clone(&source_file); - let highlight_result = rustc_driver::catch_fatal_errors(|| { - let mut classifier = Classifier::new(&sess, classifier_source_file); - - let mut highlighted_source = vec![]; - if classifier.write_source(&mut highlighted_source).is_err() { - Err(()) - } else { - Ok(String::from_utf8_lossy(&highlighted_source).into_owned()) - } - }) - .unwrap_or(Err(())); - - match highlight_result { - Ok(highlighted_source) => { - write_header(class, &mut out).unwrap(); - write!(out, "{}", highlighted_source).unwrap(); - write_footer(&mut out, playground_button).unwrap(); - } - Err(()) => { - // Get the source back out of the source map to avoid a copy in the happy path. - let span = - Span::new(BytePos(0), BytePos(source_file.byte_length()), SyntaxContext::root()); - let src = sess - .source_map() - .span_to_snippet(span) - .expect("could not retrieve snippet from artificial source file"); - - // If errors are encountered while trying to highlight, just emit - // the unhighlighted source. - write!(out, "
{}
", Escape(&src)).unwrap(); - } - } - - String::from_utf8_lossy(&out[..]).into_owned() + out } -/// Processes a program (nested in the internal `lexer`), classifying strings of -/// text by highlighting category (`Class`). Calls out to a `Writer` to write -/// each span of text in sequence. -struct Classifier<'sess> { - lexer: lexer::StringReader<'sess>, - peek_token: Option, - source_map: &'sess SourceMap, +fn write_header(out: &mut String, class: Option<&str>) { + write!(out, "
\n", class.unwrap_or_default())
+        .unwrap()
+}
 
-    // State of the classifier.
-    in_attribute: bool,
-    in_macro: bool,
-    in_macro_nonterminal: bool,
+fn write_code(out: &mut String, src: &str) {
+    Classifier::new(src).highlight(&mut |highlight| {
+        match highlight {
+            Highlight::Token { text, class } => string(out, Escape(text), class),
+            Highlight::EnterSpan { class } => enter_span(out, class),
+            Highlight::ExitSpan => exit_span(out),
+        };
+    });
+}
+
+fn write_footer(out: &mut String, playground_button: Option<&str>) {
+    write!(out, "
{}
\n", playground_button.unwrap_or_default()).unwrap() } /// How a span of text is classified. Mostly corresponds to token kinds. @@ -119,306 +83,9 @@ enum Class { QuestionMark, } -/// Trait that controls writing the output of syntax highlighting. Users should -/// implement this trait to customize writing output. -/// -/// The classifier will call into the `Writer` implementation as it finds spans -/// of text to highlight. Exactly how that text should be highlighted is up to -/// the implementation. -trait Writer { - /// Called when we start processing a span of text that should be highlighted. - /// The `Class` argument specifies how it should be highlighted. - fn enter_span(&mut self, _: Class) -> io::Result<()>; - - /// Called at the end of a span of highlighted text. - fn exit_span(&mut self) -> io::Result<()>; - - /// Called for a span of text. If the text should be highlighted differently from the - /// surrounding text, then the `Class` argument will be a value other than `None`. - /// - /// The following sequences of callbacks are equivalent: - /// ```plain - /// enter_span(Foo), string("text", None), exit_span() - /// string("text", Foo) - /// ``` - /// The latter can be thought of as a shorthand for the former, which is - /// more flexible. - fn string(&mut self, text: T, klass: Class) -> io::Result<()>; -} - -// Implement `Writer` for anything that can be written to, this just implements -// the default rustdoc behaviour. -impl Writer for U { - fn string(&mut self, text: T, klass: Class) -> io::Result<()> { - match klass { - Class::None => write!(self, "{}", text), - klass => write!(self, "{}", klass.rustdoc_class(), text), - } - } - - fn enter_span(&mut self, klass: Class) -> io::Result<()> { - write!(self, "", klass.rustdoc_class()) - } - - fn exit_span(&mut self) -> io::Result<()> { - write!(self, "") - } -} - -#[derive(Debug)] -enum HighlightError { - LexError, - IoError(io::Error), -} - -impl From for HighlightError { - fn from(err: io::Error) -> Self { - HighlightError::IoError(err) - } -} - -impl<'sess> Classifier<'sess> { - fn new(sess: &ParseSess, source_file: Lrc) -> Classifier<'_> { - let lexer = lexer::StringReader::new(sess, source_file, None); - - Classifier { - lexer, - peek_token: None, - source_map: sess.source_map(), - in_attribute: false, - in_macro: false, - in_macro_nonterminal: false, - } - } - - /// Gets the next token out of the lexer. - fn try_next_token(&mut self) -> Result { - if let Some(token) = self.peek_token.take() { - return Ok(token); - } - let token = self.lexer.next_token(); - if let token::Unknown(..) = &token.kind { - return Err(HighlightError::LexError); - } - Ok(token) - } - - fn peek(&mut self) -> Result<&Token, HighlightError> { - if self.peek_token.is_none() { - let token = self.lexer.next_token(); - if let token::Unknown(..) = &token.kind { - return Err(HighlightError::LexError); - } - self.peek_token = Some(token); - } - Ok(self.peek_token.as_ref().unwrap()) - } - - /// Exhausts the `lexer` writing the output into `out`. - /// - /// The general structure for this method is to iterate over each token, - /// possibly giving it an HTML span with a class specifying what flavor of token - /// is used. All source code emission is done as slices from the source map, - /// not from the tokens themselves, in order to stay true to the original - /// source. - fn write_source(&mut self, out: &mut W) -> Result<(), HighlightError> { - loop { - let mut next = self.try_next_token()?; - if next == token::Eof { - break; - } - - // Glue any tokens that need to be glued. - if let Some(joint) = next.glue(self.peek()?) { - next = joint; - let _ = self.try_next_token()?; - } - - self.write_token(out, next)?; - } - - Ok(()) - } - - // Handles an individual token from the lexer. - fn write_token(&mut self, out: &mut W, token: Token) -> Result<(), HighlightError> { - let klass = match token.kind { - token::Shebang(s) => { - out.string(Escape(&s.as_str()), Class::None)?; - return Ok(()); - } - - token::Whitespace | token::Unknown(..) => Class::None, - token::Comment => Class::Comment, - token::DocComment(..) => Class::DocComment, - - // If this '&' or '*' token is followed by a non-whitespace token, assume that it's the - // reference or dereference operator or a reference or pointer type, instead of the - // bit-and or multiplication operator. - token::BinOp(token::And | token::Star) if self.peek()? != &token::Whitespace => { - Class::RefKeyWord - } - - // Consider this as part of a macro invocation if there was a - // leading identifier. - token::Not if self.in_macro => { - self.in_macro = false; - Class::Macro - } - - // Operators. - token::Eq - | token::Lt - | token::Le - | token::EqEq - | token::Ne - | token::Ge - | token::Gt - | token::AndAnd - | token::OrOr - | token::Not - | token::BinOp(..) - | token::RArrow - | token::BinOpEq(..) - | token::FatArrow => Class::Op, - - // Miscellaneous, no highlighting. - token::Dot - | token::DotDot - | token::DotDotDot - | token::DotDotEq - | token::Comma - | token::Semi - | token::Colon - | token::ModSep - | token::LArrow - | token::OpenDelim(_) - | token::CloseDelim(token::Brace | token::Paren | token::NoDelim) => Class::None, - - token::Question => Class::QuestionMark, - - token::Dollar => { - if self.peek()?.is_ident() { - self.in_macro_nonterminal = true; - Class::MacroNonTerminal - } else { - Class::None - } - } - - // This might be the start of an attribute. We're going to want to - // continue highlighting it as an attribute until the ending ']' is - // seen, so skip out early. Down below we terminate the attribute - // span when we see the ']'. - token::Pound => { - // We can't be sure that our # begins an attribute (it could - // just be appearing in a macro) until we read either `#![` or - // `#[` from the input stream. - // - // We don't want to start highlighting as an attribute until - // we're confident there is going to be a ] coming up, as - // otherwise # tokens in macros highlight the rest of the input - // as an attribute. - - // Case 1: #![inner_attribute] - if self.peek()? == &token::Not { - self.try_next_token()?; // NOTE: consumes `!` token! - if self.peek()? == &token::OpenDelim(token::Bracket) { - self.in_attribute = true; - out.enter_span(Class::Attribute)?; - } - out.string("#", Class::None)?; - out.string("!", Class::None)?; - return Ok(()); - } - - // Case 2: #[outer_attribute] - if self.peek()? == &token::OpenDelim(token::Bracket) { - self.in_attribute = true; - out.enter_span(Class::Attribute)?; - } - out.string("#", Class::None)?; - return Ok(()); - } - token::CloseDelim(token::Bracket) => { - if self.in_attribute { - self.in_attribute = false; - out.string("]", Class::None)?; - out.exit_span()?; - return Ok(()); - } else { - Class::None - } - } - - token::Literal(lit) => { - match lit.kind { - // Text literals. - token::Byte - | token::Char - | token::Err - | token::ByteStr - | token::ByteStrRaw(..) - | token::Str - | token::StrRaw(..) => Class::String, - - // Number literals. - token::Integer | token::Float => Class::Number, - - token::Bool => panic!("literal token contains `Lit::Bool`"), - } - } - - // Keywords are also included in the identifier set. - token::Ident(name, is_raw) => match name { - kw::Ref | kw::Mut if !is_raw => Class::RefKeyWord, - - kw::SelfLower | kw::SelfUpper => Class::Self_, - kw::False | kw::True if !is_raw => Class::Bool, - - sym::Option | sym::Result => Class::PreludeTy, - sym::Some | sym::None | sym::Ok | sym::Err => Class::PreludeVal, - - _ if token.is_reserved_ident() => Class::KeyWord, - - _ => { - if self.in_macro_nonterminal { - self.in_macro_nonterminal = false; - Class::MacroNonTerminal - } else if self.peek()? == &token::Not { - self.in_macro = true; - Class::Macro - } else { - Class::Ident - } - } - }, - - token::Lifetime(..) => Class::Lifetime, - - token::Eof - | token::Interpolated(..) - | token::Tilde - | token::At - | token::SingleQuote => Class::None, - }; - - // Anything that didn't return above is the simple case where we the - // class just spans a single token, so we can use the `string` method. - out.string(Escape(&self.snip(token.span)), klass)?; - - Ok(()) - } - - // Helper function to get a snippet from the source_map. - fn snip(&self, sp: Span) -> String { - self.source_map.span_to_snippet(sp).unwrap() - } -} - impl Class { /// Returns the css class expected by rustdoc for each `Class`. - fn rustdoc_class(self) -> &'static str { + fn as_html(self) -> &'static str { match self { Class::None => "", Class::Comment => "comment", @@ -442,12 +109,239 @@ impl Class { } } -fn write_header(class: Option<&str>, out: &mut dyn Write) -> io::Result<()> { - write!(out, "
\n", class.unwrap_or(""))
+enum Highlight<'a> {
+    Token { text: &'a str, class: Class },
+    EnterSpan { class: Class },
+    ExitSpan,
 }
 
-fn write_footer(out: &mut dyn Write, playground_button: Option<&str>) -> io::Result<()> {
-    write!(out, "
{}
\n", if let Some(button) = playground_button { button } else { "" }) +struct TokenIter<'a> { + src: &'a str, +} + +impl Iterator for TokenIter<'a> { + type Item = (TokenKind, &'a str); + fn next(&mut self) -> Option<(TokenKind, &'a str)> { + if self.src.is_empty() { + return None; + } + let token = rustc_lexer::first_token(self.src); + let (text, rest) = self.src.split_at(token.len); + self.src = rest; + Some((token.kind, text)) + } +} + +/// Processes program tokens, classifying strings of text by highlighting +/// category (`Class`). +struct Classifier<'a> { + tokens: Peekable>, + in_attribute: bool, + in_macro: bool, + in_macro_nonterminal: bool, +} + +impl<'a> Classifier<'a> { + fn new(src: &str) -> Classifier<'_> { + let tokens = TokenIter { src }.peekable(); + Classifier { tokens, in_attribute: false, in_macro: false, in_macro_nonterminal: false } + } + + /// Exhausts the `Classifier` writing the output into `sink`. + /// + /// The general structure for this method is to iterate over each token, + /// possibly giving it an HTML span with a class specifying what flavor of + /// token is used. + fn highlight(mut self, sink: &mut dyn FnMut(Highlight<'a>)) { + with_default_session_globals(|| { + while let Some((token, text)) = self.tokens.next() { + self.advance(token, text, sink); + } + }) + } + + /// Single step of highlighting. This will classify `token`, but maybe also + /// a couple of following ones as well. + fn advance(&mut self, token: TokenKind, text: &'a str, sink: &mut dyn FnMut(Highlight<'a>)) { + let lookahead = self.peek(); + let class = match token { + TokenKind::Whitespace => Class::None, + TokenKind::LineComment { doc_style } | TokenKind::BlockComment { doc_style, .. } => { + if doc_style.is_some() { + Class::DocComment + } else { + Class::Comment + } + } + // Consider this as part of a macro invocation if there was a + // leading identifier. + TokenKind::Bang if self.in_macro => { + self.in_macro = false; + Class::Macro + } + + // 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 { + Some(TokenKind::Whitespace) => Class::Op, + _ => Class::RefKeyWord, + }, + TokenKind::And => match lookahead { + Some(TokenKind::And) => { + let _and = self.tokens.next(); + sink(Highlight::Token { text: "&&", class: Class::Op }); + return; + } + Some(TokenKind::Eq) => { + let _eq = self.tokens.next(); + sink(Highlight::Token { text: "&=", class: Class::Op }); + return; + } + Some(TokenKind::Whitespace) => Class::Op, + _ => Class::RefKeyWord, + }, + + // Operators. + TokenKind::Minus + | TokenKind::Plus + | TokenKind::Or + | TokenKind::Slash + | TokenKind::Caret + | TokenKind::Percent + | TokenKind::Bang + | TokenKind::Eq + | TokenKind::Lt + | TokenKind::Gt => Class::Op, + + // Miscellaneous, no highlighting. + TokenKind::Dot + | TokenKind::Semi + | TokenKind::Comma + | TokenKind::OpenParen + | TokenKind::CloseParen + | TokenKind::OpenBrace + | TokenKind::CloseBrace + | TokenKind::OpenBracket + | TokenKind::At + | TokenKind::Tilde + | TokenKind::Colon + | TokenKind::Unknown => Class::None, + + TokenKind::Question => Class::QuestionMark, + + TokenKind::Dollar => match lookahead { + Some(TokenKind::Ident) => { + self.in_macro_nonterminal = true; + Class::MacroNonTerminal + } + _ => Class::None, + }, + + // This might be the start of an attribute. We're going to want to + // continue highlighting it as an attribute until the ending ']' is + // seen, so skip out early. Down below we terminate the attribute + // span when we see the ']'. + TokenKind::Pound => { + match lookahead { + // Case 1: #![inner_attribute] + Some(TokenKind::Bang) => { + let _not = self.tokens.next().unwrap(); + if let Some(TokenKind::OpenBracket) = self.peek() { + self.in_attribute = true; + sink(Highlight::EnterSpan { class: Class::Attribute }); + } + sink(Highlight::Token { text: "#", class: Class::None }); + sink(Highlight::Token { text: "!", class: Class::None }); + return; + } + // Case 2: #[outer_attribute] + Some(TokenKind::OpenBracket) => { + self.in_attribute = true; + sink(Highlight::EnterSpan { class: Class::Attribute }); + } + _ => (), + } + Class::None + } + TokenKind::CloseBracket => { + if self.in_attribute { + self.in_attribute = false; + sink(Highlight::Token { text: "]", class: Class::None }); + sink(Highlight::ExitSpan); + return; + } + Class::None + } + TokenKind::Literal { kind, .. } => match kind { + // Text literals. + LiteralKind::Byte { .. } + | LiteralKind::Char { .. } + | LiteralKind::Str { .. } + | LiteralKind::ByteStr { .. } + | LiteralKind::RawStr { .. } + | LiteralKind::RawByteStr { .. } => Class::String, + // Number literals. + LiteralKind::Float { .. } | LiteralKind::Int { .. } => Class::Number, + }, + TokenKind::Ident | TokenKind::RawIdent if lookahead == Some(TokenKind::Bang) => { + self.in_macro = true; + Class::Macro + } + TokenKind::Ident => match text { + "ref" | "mut" => Class::RefKeyWord, + "self" | "Self" => Class::Self_, + "false" | "true" => Class::Bool, + "Option" | "Result" => Class::PreludeTy, + "Some" | "None" | "Ok" | "Err" => Class::PreludeVal, + // Keywords are also included in the identifier set. + _ if Ident::from_str(text).is_reserved() => Class::KeyWord, + _ if self.in_macro_nonterminal => { + self.in_macro_nonterminal = false; + Class::MacroNonTerminal + } + _ => Class::Ident, + }, + TokenKind::RawIdent => Class::Ident, + TokenKind::Lifetime { .. } => Class::Lifetime, + }; + // Anything that didn't return above is the simple case where we the + // class just spans a single token, so we can use the `string` method. + sink(Highlight::Token { text, class }); + } + + fn peek(&mut self) -> Option { + self.tokens.peek().map(|(toke_kind, _text)| *toke_kind) + } +} + +/// Called when we start processing a span of text that should be highlighted. +/// The `Class` argument specifies how it should be highlighted. +fn enter_span(out: &mut String, klass: Class) { + write!(out, "", klass.as_html()).unwrap() +} + +/// Called at the end of a span of highlighted text. +fn exit_span(out: &mut String) { + write!(out, "").unwrap() +} + +/// Called for a span of text. If the text should be highlighted differently +/// from the surrounding text, then the `Class` argument will be a value other +/// than `None`. +/// +/// The following sequences of callbacks are equivalent: +/// ```plain +/// enter_span(Foo), string("text", None), exit_span() +/// string("text", Foo) +/// ``` +/// The latter can be thought of as a shorthand for the former, which is more +/// flexible. +fn string(out: &mut String, text: T, klass: Class) { + match klass { + Class::None => write!(out, "{}", text).unwrap(), + klass => write!(out, "{}", klass.as_html(), text).unwrap(), + } } #[cfg(test)] diff --git a/src/librustdoc/html/highlight/fixtures/sample.html b/src/librustdoc/html/highlight/fixtures/sample.html new file mode 100644 index 0000000000..d937246f46 --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/sample.html @@ -0,0 +1,27 @@ + + +
#![crate_type = "lib"]
+
+#[cfg(target_os = "linux")]
+fn main() {
+    let foo = true && false || true;
+    let _: *const () = 0;
+    let _ = &foo;
+    let _ = &&foo;
+    let _ = *foo;
+    mac!(foo, &mut bar);
+    assert!(self.length < N && index <= self.length);
+}
+
+macro_rules! bar {
+    ($foo:tt) => {};
+}
+
diff --git a/src/librustdoc/html/highlight/fixtures/sample.rs b/src/librustdoc/html/highlight/fixtures/sample.rs new file mode 100644 index 0000000000..956fdbe090 --- /dev/null +++ b/src/librustdoc/html/highlight/fixtures/sample.rs @@ -0,0 +1,16 @@ +#![crate_type = "lib"] + +#[cfg(target_os = "linux")] +fn main() { + let foo = true && false || true; + let _: *const () = 0; + let _ = &foo; + let _ = &&foo; + let _ = *foo; + mac!(foo, &mut bar); + assert!(self.length < N && index <= self.length); +} + +macro_rules! bar { + ($foo:tt) => {}; +} diff --git a/src/librustdoc/html/highlight/tests.rs b/src/librustdoc/html/highlight/tests.rs index 21e476cbe0..c79471b1fa 100644 --- a/src/librustdoc/html/highlight/tests.rs +++ b/src/librustdoc/html/highlight/tests.rs @@ -1,82 +1,25 @@ -use rustc_session::parse::ParseSess; -use rustc_span::edition::Edition; -use rustc_span::with_session_globals; -use rustc_span::FileName; - -use super::Classifier; - -fn highlight(src: &str) -> String { - let mut out = vec![]; - - with_session_globals(Edition::Edition2018, || { - let sess = ParseSess::with_silent_emitter(); - let source_file = sess.source_map().new_source_file( - FileName::Custom(String::from("rustdoc-highlighting")), - src.to_owned(), - ); - - let mut classifier = Classifier::new(&sess, source_file); - classifier.write_source(&mut out).unwrap(); - }); - - String::from_utf8(out).unwrap() -} +use super::write_code; +use expect_test::expect_file; #[test] -fn function() { - assert_eq!( - highlight("fn main() {}"), - r#"fn main() {}"#, - ); +fn test_html_highlighting() { + let src = include_str!("fixtures/sample.rs"); + let html = { + let mut out = String::new(); + write_code(&mut out, src); + format!("{}
{}
\n", STYLE, out) + }; + expect_file!["fixtures/sample.html"].assert_eq(&html); } -#[test] -fn statement() { - assert_eq!( - highlight("let foo = true;"), - concat!( - r#"let foo "#, - r#"= true;"#, - ), - ); -} - -#[test] -fn inner_attr() { - assert_eq!( - highlight(r##"#![crate_type = "lib"]"##), - concat!( - r##"#![crate_type "##, - r##"= "lib"]"##, - ), - ); -} - -#[test] -fn outer_attr() { - assert_eq!( - highlight(r##"#[cfg(target_os = "linux")]"##), - concat!( - r##"#[cfg("##, - r##"target_os = "##, - r##""linux")]"##, - ), - ); -} - -#[test] -fn mac() { - assert_eq!( - highlight("mac!(foo bar)"), - concat!( - r#"mac!("#, - r#"foo bar)"#, - ), - ); -} - -// Regression test for #72684 -#[test] -fn andand() { - assert_eq!(highlight("&&"), r#"&&"#); -} +const STYLE: &str = r#" + +"#; diff --git a/src/librustdoc/html/layout.rs b/src/librustdoc/html/layout.rs index fd67a66395..7239b3c5ba 100644 --- a/src/librustdoc/html/layout.rs +++ b/src/librustdoc/html/layout.rs @@ -158,7 +158,9 @@ pub fn render( keywords = page.keywords, favicon = if layout.favicon.is_empty() { format!( - r#""#, + r##" + +"##, static_root_path = static_root_path, suffix = page.resource_suffix ) @@ -210,8 +212,8 @@ pub fn render( .collect::(), filter_crates = if layout.generate_search_filter { "" + \ + " } else { "" }, diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index b2589e5b80..6c0f1c02ac 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -27,18 +27,18 @@ use rustc_session::lint; use rustc_span::edition::Edition; use rustc_span::Span; use std::borrow::Cow; -use std::cell::RefCell; use std::collections::VecDeque; use std::default::Default; use std::fmt::Write; use std::ops::Range; use std::str; +use crate::clean::RenderedLink; +use crate::doctest; use crate::html::highlight; use crate::html::toc::TocBuilder; -use crate::test; -use pulldown_cmark::{html, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; +use pulldown_cmark::{html, BrokenLink, CodeBlockKind, CowStr, Event, Options, Parser, Tag}; #[cfg(test)] mod tests; @@ -52,7 +52,7 @@ fn opts() -> Options { pub struct Markdown<'a>( pub &'a str, /// A list of link replacements. - pub &'a [(String, String)], + pub &'a [RenderedLink], /// The current list of used header IDs. pub &'a mut IdMap, /// Whether to allow the use of explicit error codes in doctest lang strings. @@ -78,7 +78,7 @@ pub struct MarkdownHtml<'a>( pub &'a Option, ); /// A tuple struct like `Markdown` that renders only the first paragraph. -pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [(String, String)]); +pub struct MarkdownSummaryLine<'a>(pub &'a str, pub &'a [RenderedLink]); #[derive(Copy, Clone, PartialEq, Debug)] pub enum ErrorCodes { @@ -243,7 +243,7 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { .collect::>>() .join("\n"); let krate = krate.as_ref().map(|s| &**s); - let (test, _) = test::make_test(&test, krate, false, &Default::default(), edition); + let (test, _) = doctest::make_test(&test, krate, false, &Default::default(), edition); let channel = if test.contains("#![feature(") { "&version=nightly" } else { "" }; let edition_string = format!("&edition={}", edition); @@ -337,31 +337,107 @@ impl<'a, I: Iterator>> Iterator for CodeBlocks<'_, 'a, I> { } /// Make headings links with anchor IDs and build up TOC. -struct LinkReplacer<'a, 'b, I: Iterator>> { +struct LinkReplacer<'a, I: Iterator>> { inner: I, - links: &'b [(String, String)], + links: &'a [RenderedLink], + shortcut_link: Option<&'a RenderedLink>, } -impl<'a, 'b, I: Iterator>> LinkReplacer<'a, 'b, I> { - fn new(iter: I, links: &'b [(String, String)]) -> Self { - LinkReplacer { inner: iter, links } +impl<'a, I: Iterator>> LinkReplacer<'a, I> { + fn new(iter: I, links: &'a [RenderedLink]) -> Self { + LinkReplacer { inner: iter, links, shortcut_link: None } } } -impl<'a, 'b, I: Iterator>> Iterator for LinkReplacer<'a, 'b, I> { +impl<'a, I: Iterator>> Iterator for LinkReplacer<'a, I> { type Item = Event<'a>; fn next(&mut self) -> Option { - let event = self.inner.next(); - if let Some(Event::Start(Tag::Link(kind, dest, text))) = event { - if let Some(&(_, ref replace)) = self.links.iter().find(|link| link.0 == *dest) { - Some(Event::Start(Tag::Link(kind, replace.to_owned().into(), text))) - } else { - Some(Event::Start(Tag::Link(kind, dest, text))) + use pulldown_cmark::LinkType; + + let mut event = self.inner.next(); + + // Replace intra-doc links and remove disambiguators from shortcut links (`[fn@f]`). + match &mut event { + // This is a shortcut link that was resolved by the broken_link_callback: `[fn@f]` + // Remove any disambiguator. + Some(Event::Start(Tag::Link( + // [fn@f] or [fn@f][] + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + title, + ))) => { + debug!("saw start of shortcut link to {} with title {}", dest, title); + // If this is a shortcut link, it was resolved by the broken_link_callback. + // So the URL will already be updated properly. + let link = self.links.iter().find(|&link| *link.href == **dest); + // Since this is an external iterator, we can't replace the inner text just yet. + // Store that we saw a link so we know to replace it later. + if let Some(link) = link { + trace!("it matched"); + assert!(self.shortcut_link.is_none(), "shortcut links cannot be nested"); + self.shortcut_link = Some(link); + } } - } else { - event + // Now that we're done with the shortcut link, don't replace any more text. + Some(Event::End(Tag::Link( + LinkType::ShortcutUnknown | LinkType::CollapsedUnknown, + dest, + _, + ))) => { + debug!("saw end of shortcut link to {}", dest); + if self.links.iter().find(|&link| *link.href == **dest).is_some() { + assert!(self.shortcut_link.is_some(), "saw closing link without opening tag"); + self.shortcut_link = None; + } + } + // Handle backticks in inline code blocks, but only if we're in the middle of a shortcut link. + // [`fn@f`] + Some(Event::Code(text)) => { + trace!("saw code {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: this only replaces if the code block is the *entire* text. + // If only part of the link has code highlighting, the disambiguator will not be removed. + // e.g. [fn@`f`] + // This is a limitation from `collect_intra_doc_links`: it passes a full link, + // and does not distinguish at all between code blocks. + // So we could never be sure we weren't replacing too much: + // [fn@my_`f`unc] is treated the same as [my_func()] in that pass. + // + // NOTE: &[1..len() - 1] is to strip the backticks + if **text == link.original_text[1..link.original_text.len() - 1] { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // Replace plain text in links, but only in the middle of a shortcut link. + // [fn@f] + Some(Event::Text(text)) => { + trace!("saw text {}", text); + if let Some(link) = self.shortcut_link { + trace!("original text was {}", link.original_text); + // NOTE: same limitations as `Event::Code` + if **text == *link.original_text { + debug!("replacing {} with {}", text, link.new_text); + *text = CowStr::Borrowed(&link.new_text); + } + } + } + // If this is a link, but not a shortcut link, + // replace the URL, since the broken_link_callback was not called. + Some(Event::Start(Tag::Link(_, dest, _))) => { + if let Some(link) = self.links.iter().find(|&link| *link.original_text == **dest) { + *dest = CowStr::Borrowed(link.href.as_ref()); + } + } + // Anything else couldn't have been a valid Rust path, so no need to replace the text. + _ => {} } + + // Yield the modified event + event } } @@ -519,8 +595,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { Some(Event::FootnoteReference(ref reference)) => { let entry = self.get_entry(&reference); let reference = format!( - "{0}\ - ", + "{0}", (*entry).1 ); return Some(Event::Html(reference.into())); @@ -568,7 +643,7 @@ impl<'a, I: Iterator>> Iterator for Footnotes<'a, I> { } } -pub fn find_testable_code( +pub fn find_testable_code( doc: &str, tests: &mut T, error_codes: ErrorCodes, @@ -855,15 +930,17 @@ impl Markdown<'_> { if md.is_empty() { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&replacer)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut replacer)); let mut s = String::with_capacity(md.len() * 3 / 2); @@ -933,9 +1010,11 @@ impl MarkdownSummaryLine<'_> { return String::new(); } - let replacer = |_: &str, s: &str| { - if let Some(&(_, ref replace)) = links.iter().find(|link| &*link.0 == s) { - Some((replace.clone(), s.to_owned())) + let mut replacer = |broken_link: BrokenLink<'_>| { + if let Some(link) = + links.iter().find(|link| &*link.original_text == broken_link.reference) + { + Some((link.href.as_str().into(), link.new_text.as_str().into())) } else { None } @@ -944,7 +1023,7 @@ impl MarkdownSummaryLine<'_> { let p = Parser::new_with_broken_link_callback( md, Options::ENABLE_STRIKETHROUGH, - Some(&replacer), + Some(&mut replacer), ); let mut s = String::new(); @@ -955,44 +1034,33 @@ impl MarkdownSummaryLine<'_> { } } -pub fn plain_summary_line(md: &str) -> String { - struct ParserWrapper<'a> { - inner: Parser<'a>, - is_in: isize, - is_first: bool, +/// Renders the first paragraph of the provided markdown as plain text. +/// +/// - Headings, links, and formatting are stripped. +/// - Inline code is rendered as-is, surrounded by backticks. +/// - HTML and code blocks are ignored. +pub fn plain_text_summary(md: &str) -> String { + if md.is_empty() { + return String::new(); } - impl<'a> Iterator for ParserWrapper<'a> { - type Item = String; + let mut s = String::with_capacity(md.len() * 3 / 2); - fn next(&mut self) -> Option { - let next_event = self.inner.next()?; - let (ret, is_in) = match next_event { - Event::Start(Tag::Paragraph) => (None, 1), - Event::Start(Tag::Heading(_)) => (None, 1), - Event::Code(code) => (Some(format!("`{}`", code)), 0), - Event::Text(ref s) if self.is_in > 0 => (Some(s.as_ref().to_owned()), 0), - Event::End(Tag::Paragraph | Tag::Heading(_)) => (None, -1), - _ => (None, 0), - }; - if is_in > 0 || (is_in < 0 && self.is_in > 0) { - self.is_in += is_in; - } - if ret.is_some() { - self.is_first = false; - ret - } else { - Some(String::new()) + for event in Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH) { + match &event { + Event::Text(text) => s.push_str(text), + Event::Code(code) => { + s.push('`'); + s.push_str(code); + s.push('`'); } + Event::HardBreak | Event::SoftBreak => s.push(' '), + Event::Start(Tag::CodeBlock(..)) => break, + Event::End(Tag::Paragraph) => break, + _ => (), } } - let mut s = String::with_capacity(md.len() * 3 / 2); - let p = ParserWrapper { - inner: Parser::new_ext(md, Options::ENABLE_STRIKETHROUGH), - is_in: 0, - is_first: true, - }; - p.filter(|t| !t.is_empty()).for_each(|i| s.push_str(&i)); + s } @@ -1002,7 +1070,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } let mut links = vec![]; - let shortcut_links = RefCell::new(vec![]); + let mut shortcut_links = vec![]; { let locate = |s: &str| unsafe { @@ -1019,11 +1087,13 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } }; - let push = |_: &str, s: &str| { - shortcut_links.borrow_mut().push((s.to_owned(), locate(s))); + let mut push = |link: BrokenLink<'_>| { + // FIXME: use `link.span` instead of `locate` + // (doing it now includes the `[]` as well as the text) + shortcut_links.push((link.reference.to_owned(), locate(link.reference))); None }; - let p = Parser::new_with_broken_link_callback(md, opts(), Some(&push)); + let p = Parser::new_with_broken_link_callback(md, opts(), Some(&mut push)); // There's no need to thread an IdMap through to here because // the IDs generated aren't going to be emitted anywhere. @@ -1041,8 +1111,7 @@ pub fn markdown_links(md: &str) -> Vec<(String, Option>)> { } } - let mut shortcut_links = shortcut_links.into_inner(); - links.extend(shortcut_links.drain(..)); + links.append(&mut shortcut_links); links } diff --git a/src/librustdoc/html/markdown/tests.rs b/src/librustdoc/html/markdown/tests.rs index 783977d285..8e618733f0 100644 --- a/src/librustdoc/html/markdown/tests.rs +++ b/src/librustdoc/html/markdown/tests.rs @@ -1,4 +1,4 @@ -use super::plain_summary_line; +use super::plain_text_summary; use super::{ErrorCodes, IdMap, Ignore, LangString, Markdown, MarkdownHtml}; use rustc_span::edition::{Edition, DEFAULT_EDITION}; use std::cell::RefCell; @@ -140,25 +140,26 @@ fn test_header() { 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-%

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

\ - Foo? & *bar?!* \ - baz ❤ #qux

", + Foo? & *bar?!* \ + baz ❤ #qux\ + ", ); } @@ -174,54 +175,55 @@ fn test_header_ids_multiple_blocks() { 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

", ); } #[test] -fn test_plain_summary_line() { +fn test_plain_text_summary() { fn t(input: &str, expect: &str) { - let output = plain_summary_line(input); + let output = plain_text_summary(input); assert_eq!(output, expect, "original: {}", input); } t("hello [Rust](https://www.rust-lang.org) :)", "hello Rust :)"); + t("**bold**", "bold"); + t("Multi-line\nsummary", "Multi-line summary"); + t("Hard-break \nsummary", "Hard-break summary"); + t("hello [Rust] :)\n\n[Rust]: https://www.rust-lang.org", "hello Rust :)"); t("hello [Rust](https://www.rust-lang.org \"Rust\") :)", "hello Rust :)"); t("code `let x = i32;` ...", "code `let x = i32;` ..."); t("type `Type<'static>` ...", "type `Type<'static>` ..."); t("# top header", "top header"); t("## header", "header"); + t("first paragraph\n\nsecond paragraph", "first paragraph"); + t("```\nfn main() {}\n```", ""); + t("
hello
", ""); } #[test] diff --git a/src/librustdoc/html/render/cache.rs b/src/librustdoc/html/render/cache.rs index ccc0764562..cf785d362c 100644 --- a/src/librustdoc/html/render/cache.rs +++ b/src/librustdoc/html/render/cache.rs @@ -9,7 +9,7 @@ use crate::clean::types::GetDefId; use crate::clean::{self, AttributesExt}; use crate::formats::cache::Cache; use crate::formats::item_type::ItemType; -use crate::html::render::{plain_summary_line, shorten}; +use crate::html::render::{plain_text_summary, shorten}; use crate::html::render::{Generic, IndexItem, IndexItemFunctionType, RenderType, TypeWithKind}; /// Indicates where an external crate can be found. @@ -78,7 +78,7 @@ pub fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { ty: item.type_(), name: item.name.clone().unwrap(), path: fqp[..fqp.len() - 1].join("::"), - desc: shorten(plain_summary_line(item.doc_value())), + desc: shorten(plain_text_summary(item.doc_value())), parent: Some(did), parent_idx: None, search_type: get_index_search_type(&item), @@ -127,7 +127,7 @@ pub fn build_index(krate: &clean::Crate, cache: &mut Cache) -> String { let crate_doc = krate .module .as_ref() - .map(|module| shorten(plain_summary_line(module.doc_value()))) + .map(|module| shorten(plain_text_summary(module.doc_value()))) .unwrap_or(String::new()); #[derive(Serialize)] diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index d17961521c..8b5ba7a239 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -63,9 +63,8 @@ use rustc_span::symbol::{sym, Symbol}; use serde::ser::SerializeSeq; use serde::{Serialize, Serializer}; -use crate::clean::{self, AttributesExt, Deprecation, GetDefId, SelfTy, TypeKind}; -use crate::config::RenderInfo; -use crate::config::RenderOptions; +use crate::clean::{self, AttributesExt, Deprecation, GetDefId, RenderedLink, SelfTy, TypeKind}; +use crate::config::{RenderInfo, RenderOptions}; use crate::docfs::{DocFS, PathError}; use crate::doctree; use crate::error::Error; @@ -755,7 +754,9 @@ fn write_shared( write(cx.path("rust-logo.png"), static_files::RUST_LOGO)?; } if (*cx.shared).layout.favicon.is_empty() { - write(cx.path("favicon.ico"), static_files::RUST_FAVICON)?; + write(cx.path("favicon.svg"), static_files::RUST_FAVICON_SVG)?; + write(cx.path("favicon-16x16.png"), static_files::RUST_FAVICON_PNG_16)?; + write(cx.path("favicon-32x32.png"), static_files::RUST_FAVICON_PNG_32)?; } write(cx.path("brush.svg"), static_files::BRUSH_SVG)?; write(cx.path("wheel.svg"), static_files::WHEEL_SVG)?; @@ -1061,12 +1062,17 @@ themePicker.onblur = handleThemeButtonsBlur; let content = format!( "

\ - List of all crates\ -

    {}
", + List of all crates\ + \ +
    {}
", krates .iter() .map(|s| { - format!("
  • {}
  • ", ensure_trailing_slash(s), s) + format!( + "
  • {}
  • ", + ensure_trailing_slash(s), + s + ) }) .collect::() ); @@ -1307,15 +1313,16 @@ impl AllTypes { write!( f, "

    \ - \ - \ - \ - []\ - \ - - - List of all items\ -

    " + \ + \ + \ + []\ + \ + + + List of all items\ + " ); print_entries(f, &self.structs, "Structs", "structs"); print_entries(f, &self.enums, "Enums", "enums"); @@ -1345,20 +1352,20 @@ impl Setting { match *self { Setting::Section { ref description, ref sub_settings } => format!( "
    \ -
    {}
    \ -
    {}
    -
    ", +
    {}
    \ +
    {}
    + ", description, sub_settings.iter().map(|s| s.display()).collect::() ), Setting::Entry { ref js_data_name, ref description, ref default_value } => format!( "
    \ - \ -
    {}
    \ -
    ", + \ +
    {}
    \ + ", js_data_name, if *default_value { " checked" } else { "" }, description, @@ -1502,6 +1509,7 @@ impl Context { } } + /// Construct a map of items shown in the sidebar to a plain-text summary of their docs. fn build_sidebar_items(&self, m: &clean::Module) -> BTreeMap> { // BTreeMap instead of HashMap to get a sorted output let mut map: BTreeMap<_, Vec<_>> = BTreeMap::new(); @@ -1518,7 +1526,7 @@ impl Context { let short = short.to_string(); map.entry(short) .or_default() - .push((myname, Some(plain_summary_line(item.doc_value())))); + .push((myname, Some(plain_text_summary(item.doc_value())))); } if self.shared.sort_modules_alphabetically { @@ -1724,22 +1732,15 @@ fn full_path(cx: &Context, item: &clean::Item) -> String { s } +/// Renders the first paragraph of the given markdown as plain text, making it suitable for +/// contexts like alt-text or the search index. +/// +/// If no markdown is supplied, the empty string is returned. +/// +/// See [`markdown::plain_text_summary`] for further details. #[inline] -crate fn plain_summary_line(s: Option<&str>) -> String { - let s = s.unwrap_or(""); - // This essentially gets the first paragraph of text in one line. - let mut line = s - .lines() - .skip_while(|line| line.chars().all(|c| c.is_whitespace())) - .take_while(|line| line.chars().any(|c| !c.is_whitespace())) - .fold(String::new(), |mut acc, line| { - acc.push_str(line); - acc.push(' '); - acc - }); - // remove final whitespace - line.pop(); - markdown::plain_summary_line(&line[..]) +crate fn plain_text_summary(s: Option<&str>) -> String { + s.map(markdown::plain_text_summary).unwrap_or_default() } crate fn shorten(s: String) -> String { @@ -1774,7 +1775,7 @@ fn render_markdown( w: &mut Buffer, cx: &Context, md_text: &str, - links: Vec<(String, String)>, + links: Vec, prefix: &str, is_hidden: bool, ) { @@ -1796,25 +1797,35 @@ fn render_markdown( ) } +/// Writes a documentation block containing only the first paragraph of the documentation. If the +/// docs are longer, a "Read more" link is appended to the end. fn document_short( w: &mut Buffer, - cx: &Context, item: &clean::Item, link: AssocItemLink<'_>, prefix: &str, is_hidden: bool, ) { if let Some(s) = item.doc_value() { - let markdown = if s.contains('\n') { - format!( - "{} [Read more]({})", - &plain_summary_line(Some(s)), - naive_assoc_href(item, link) - ) - } else { - plain_summary_line(Some(s)) - }; - render_markdown(w, cx, &markdown, item.links(), prefix, is_hidden); + let mut summary_html = MarkdownSummaryLine(s, &item.links()).into_string(); + + if s.contains('\n') { + let link = format!(r#" Read more"#, naive_assoc_href(item, link)); + + if let Some(idx) = summary_html.rfind("

    ") { + summary_html.insert_str(idx, &link); + } else { + summary_html.push_str(&link); + } + } + + write!( + w, + "
    {}{}
    ", + if is_hidden { " hidden" } else { "" }, + prefix, + summary_html, + ); } else if !prefix.is_empty() { write!( w, @@ -1872,30 +1883,29 @@ fn document_non_exhaustive(w: &mut Buffer, item: &clean::Item) { write!( w, "Non-exhaustive structs could have additional fields added in future. \ - Therefore, non-exhaustive structs cannot be constructed in external crates \ - using the traditional Struct {{ .. }} syntax; cannot be \ - matched against without a wildcard ..; and \ - struct update syntax will not work." + Therefore, non-exhaustive structs cannot be constructed in external crates \ + using the traditional Struct {{ .. }} syntax; cannot be \ + matched against without a wildcard ..; and \ + struct update syntax will not work." ); } else if item.is_enum() { write!( w, "Non-exhaustive enums could have additional variants added in future. \ - Therefore, when matching against variants of non-exhaustive enums, an \ - extra wildcard arm must be added to account for any future variants." + Therefore, when matching against variants of non-exhaustive enums, an \ + extra wildcard arm must be added to account for any future variants." ); } else if item.is_variant() { write!( w, "Non-exhaustive enum variants could have additional fields added in future. \ - Therefore, non-exhaustive enum variants cannot be constructed in external \ - crates and cannot be matched against." + Therefore, non-exhaustive enum variants cannot be constructed in external \ + crates and cannot be matched against." ); } else { write!( w, - "This type will require a wildcard arm in any match statements or \ - constructors." + "This type will require a wildcard arm in any match statements or constructors." ); } @@ -2092,12 +2102,11 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: let doc_value = myitem.doc_value().unwrap_or(""); write!( w, - "\ - \ - {name}{unsafety_flag}\ - {stab_tags}{docs}\ - ", + "\ + {name}{unsafety_flag}\ + {stab_tags}{docs}\ + ", name = *myitem.name.as_ref().unwrap(), stab_tags = stability_tags(myitem), docs = MarkdownSummaryLine(doc_value, &myitem.links()).into_string(), @@ -2126,8 +2135,8 @@ fn item_module(w: &mut Buffer, cx: &Context, item: &clean::Item, items: &[clean: fn stability_tags(item: &clean::Item) -> String { let mut tags = String::new(); - fn tag_html(class: &str, contents: &str) -> String { - format!(r#"{}"#, class, contents) + fn tag_html(class: &str, title: &str, contents: &str) -> String { + format!(r#"{}"#, class, Escape(title), contents) } // The trailing space after each tag is to space it properly against the rest of the docs. @@ -2136,7 +2145,7 @@ fn stability_tags(item: &clean::Item) -> String { if !stability::deprecation_in_effect(depr.is_since_rustc_version, depr.since.as_deref()) { message = "Deprecation planned"; } - tags += &tag_html("deprecated", message); + tags += &tag_html("deprecated", "", message); } // The "rustc_private" crates are permanently unstable so it makes no sense @@ -2147,11 +2156,11 @@ fn stability_tags(item: &clean::Item) -> String { .map(|s| s.level == stability::Unstable && s.feature != "rustc_private") == Some(true) { - tags += &tag_html("unstable", "Experimental"); + tags += &tag_html("unstable", "", "Experimental"); } if let Some(ref cfg) = item.attrs.cfg { - tags += &tag_html("portability", &cfg.render_short_html()); + tags += &tag_html("portability", &cfg.render_long_plain(), &cfg.render_short_html()); } tags @@ -2246,8 +2255,7 @@ fn item_constant(w: &mut Buffer, cx: &Context, it: &clean::Item, c: &clean::Cons write!( w, - "{vis}const \ - {name}: {typ}", + "{vis}const {name}: {typ}", vis = it.visibility.print_with_space(), name = it.name.as_ref().unwrap(), typ = c.type_.print(), @@ -2281,8 +2289,7 @@ fn item_static(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Static render_attributes(w, it, false); write!( w, - "{vis}static {mutability}\ - {name}: {typ}", + "{vis}static {mutability} {name}: {typ}", vis = it.visibility.print_with_space(), mutability = s.mutability.print_with_space(), name = it.name.as_ref().unwrap(), @@ -2308,7 +2315,7 @@ fn item_function(w: &mut Buffer, cx: &Context, it: &clean::Item, f: &clean::Func write!( w, "{vis}{constness}{asyncness}{unsafety}{abi}fn \ - {name}{generics}{decl}{spotlight}{where_clause}", + {name}{generics}{decl}{spotlight}{where_clause}", vis = it.visibility.print_with_space(), constness = f.header.constness.print_with_space(), asyncness = f.header.asyncness.print_with_space(), @@ -2499,10 +2506,9 @@ fn item_trait(w: &mut Buffer, cx: &Context, it: &clean::Item, t: &clean::Trait, fn write_small_section_header(w: &mut Buffer, id: &str, title: &str, extra_content: &str) { write!( w, - " -

    \ - {1}\ -

    {2}", + "

    \ + {1}\ +

    {2}", id, title, extra_content ) } @@ -2831,7 +2837,7 @@ fn render_assoc_item( write!( w, "{}{}{}{}{}{}{}fn {name}\ - {generics}{decl}{spotlight}{where_clause}", + {generics}{decl}{spotlight}{where_clause}", if parent == ItemType::Trait { " " } else { "" }, meth.visibility.print_with_space(), header.constness.print_with_space(), @@ -2906,9 +2912,9 @@ fn item_struct(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Struct write!( w, "\ - \ - {name}: {ty}\ - ", + \ + {name}: {ty}\ + ", item_type = ItemType::StructField, id = id, name = field.name.as_ref().unwrap(), @@ -2950,9 +2956,9 @@ fn item_union(w: &mut Buffer, cx: &Context, it: &clean::Item, s: &clean::Union, write!( w, "\ - \ - {name}: {ty}\ - ", + \ + {name}: {ty}\ + ", id = id, name = name, shortty = ItemType::StructField, @@ -3077,9 +3083,9 @@ fn item_enum(w: &mut Buffer, cx: &Context, it: &clean::Item, e: &clean::Enum, ca write!( w, "\ - \ - {f}: {t}\ - ", + \ + {f}: {t}\ + ", id = id, f = field.name.as_ref().unwrap(), t = ty.print() @@ -3292,23 +3298,19 @@ fn render_assoc_items( AssocItemRender::All => { write!( w, - "\ -

    \ - Implementations\ -

    \ - " + "

    \ + Implementations\ +

    " ); RenderMode::Normal } AssocItemRender::DerefFor { trait_, type_, deref_mut_ } => { write!( w, - "\ -

    \ - Methods from {}<Target = {}>\ - \ -

    \ - ", + "

    \ + Methods from {}<Target = {}>\ + \ +

    ", trait_.print(), type_.print() ); @@ -3355,11 +3357,10 @@ fn render_assoc_items( if !impls.is_empty() { write!( w, - "\ -

    \ - Trait Implementations\ -

    \ -
    {}
    ", + "

    \ + Trait Implementations\ +

    \ +
    {}
    ", impls ); } @@ -3367,13 +3368,11 @@ fn render_assoc_items( if !synthetic.is_empty() { write!( w, - "\ -

    \ - Auto Trait Implementations\ - \ -

    \ -
    \ - " + "

    \ + Auto Trait Implementations\ + \ +

    \ +
    " ); render_impls(cx, w, &synthetic, containing_item, cache); write!(w, "
    "); @@ -3382,13 +3381,11 @@ fn render_assoc_items( if !blanket_impl.is_empty() { write!( w, - "\ -

    \ - Blanket Implementations\ - \ -

    \ -
    \ - " + "

    \ + Blanket Implementations\ + \ +

    \ +
    " ); render_impls(cx, w, &blanket_impl, containing_item, cache); write!(w, "
    "); @@ -3469,7 +3466,7 @@ fn spotlight_decl(decl: &clean::FnDecl) -> String { if out.is_empty() { out.push_str(&format!( "

    Notable traits for {}

    \ - ", + ", impl_.for_.print() )); trait_.push_str(&impl_.for_.print().to_string()); @@ -3685,7 +3682,7 @@ fn render_impl( } else if show_def_docs { // In case the item isn't documented, // provide short documentation from the trait. - document_short(w, cx, it, link, "", is_hidden); + document_short(w, it, link, "", is_hidden); } } } else { @@ -3697,7 +3694,7 @@ fn render_impl( } else { document_stability(w, cx, item, is_hidden); if show_def_docs { - document_short(w, cx, item, link, "", is_hidden); + document_short(w, item, link, "", is_hidden); } } } @@ -3905,8 +3902,8 @@ fn print_sidebar(cx: &Context, it: &clean::Item, buffer: &mut Buffer, cache: &Ca write!( buffer, "
    \ -

    Version {}

    \ -
    ", +

    Version {}

    \ +
    ", Escape(version) ); } @@ -4181,7 +4178,7 @@ fn sidebar_struct(buf: &mut Buffer, it: &clean::Item, s: &clean::Struct) { if let doctree::Plain = s.struct_type { sidebar.push_str(&format!( "Fields\ -
    {}
    ", +
    {}
    ", fields )); } @@ -4308,8 +4305,8 @@ fn sidebar_trait(buf: &mut Buffer, it: &clean::Item, t: &clean::Trait) { res.sort(); sidebar.push_str(&format!( "\ - Implementations on Foreign Types
    {}
    ", + Implementations on Foreign Types\ +
    {}
    ", res.into_iter() .map(|(name, id)| format!("{}", id, Escape(&name))) .collect::>() diff --git a/src/librustdoc/html/sources.rs b/src/librustdoc/html/sources.rs index aaa73b100c..02a7362bb3 100644 --- a/src/librustdoc/html/sources.rs +++ b/src/librustdoc/html/sources.rs @@ -52,7 +52,7 @@ impl<'a> DocFolder for SourceCollector<'a> { Err(e) => { println!( "warning: source code was requested to be rendered, \ - but processing `{}` had an error: {}", + but processing `{}` had an error: {}", item.source.filename, e ); println!(" skipping rendering of source code"); diff --git a/src/librustdoc/html/static/favicon-16x16.png b/src/librustdoc/html/static/favicon-16x16.png new file mode 100644 index 0000000000..7cfe6c1355 Binary files /dev/null and b/src/librustdoc/html/static/favicon-16x16.png differ diff --git a/src/librustdoc/html/static/favicon-32x32.png b/src/librustdoc/html/static/favicon-32x32.png new file mode 100644 index 0000000000..5109c1de8b Binary files /dev/null and b/src/librustdoc/html/static/favicon-32x32.png differ diff --git a/src/librustdoc/html/static/favicon.ico b/src/librustdoc/html/static/favicon.ico deleted file mode 100644 index b8ad23769a..0000000000 Binary files a/src/librustdoc/html/static/favicon.ico and /dev/null differ diff --git a/src/librustdoc/html/static/favicon.svg b/src/librustdoc/html/static/favicon.svg new file mode 100644 index 0000000000..8b34b51198 --- /dev/null +++ b/src/librustdoc/html/static/favicon.svg @@ -0,0 +1,24 @@ + + + + + diff --git a/src/librustdoc/html/static/main.js b/src/librustdoc/html/static/main.js index 462a696dee..1b3eb2011a 100644 --- a/src/librustdoc/html/static/main.js +++ b/src/librustdoc/html/static/main.js @@ -92,6 +92,7 @@ function defocusSearchBar() { var disableShortcuts = getCurrentValue("rustdoc-disable-shortcuts") === "true"; var search_input = getSearchInput(); var searchTimeout = null; + var toggleAllDocsId = "toggle-all-docs"; // On the search screen, so you remain on the last tab you opened. // @@ -344,6 +345,7 @@ function defocusSearchBar() { } function getHelpElement() { + buildHelperPopup(); return document.getElementById("help"); } @@ -1396,8 +1398,8 @@ function defocusSearchBar() { // "current" is used to know which tab we're looking into. var current = 0; onEachLazy(document.getElementById("results").childNodes, function(e) { - onEachLazy(e.getElementsByClassName("highlighted"), function(e) { - actives[current].push(e); + onEachLazy(e.getElementsByClassName("highlighted"), function(h_e) { + actives[current].push(h_e); }); current += 1; }); @@ -1576,14 +1578,21 @@ function defocusSearchBar() { } function showResults(results) { - if (results.others.length === 1 && - getCurrentValue("rustdoc-go-to-only-result") === "true") { + var search = getSearchElement(); + if (results.others.length === 1 + && getCurrentValue("rustdoc-go-to-only-result") === "true" + // By default, the search DOM element is "empty" (meaning it has no children not + // text content). Once a search has been run, it won't be empty, even if you press + // ESC or empty the search input (which also "cancels" the search). + && (!search.firstChild || search.firstChild.innerText !== getSearchLoadingText())) + { var elem = document.createElement("a"); elem.href = results.others[0].href; elem.style.display = "none"; // For firefox, we need the element to be in the DOM so it can be clicked. document.body.appendChild(elem); elem.click(); + return; } var query = getQuery(search_input.value); @@ -1602,7 +1611,6 @@ function defocusSearchBar() { "
    " + ret_others[0] + ret_in_args[0] + ret_returned[0] + "
    "; - var search = getSearchElement(); search.innerHTML = output; showSearchResults(search); var tds = search.getElementsByTagName("td"); @@ -2114,7 +2122,7 @@ function defocusSearchBar() { } function toggleAllDocs(pageId, fromAutoCollapse) { - var innerToggle = document.getElementById("toggle-all-docs"); + var innerToggle = document.getElementById(toggleAllDocsId); if (!innerToggle) { return; } @@ -2307,11 +2315,6 @@ function defocusSearchBar() { } } - var toggles = document.getElementById("toggle-all-docs"); - if (toggles) { - toggles.onclick = toggleAllDocs; - } - function insertAfter(newNode, referenceNode) { referenceNode.parentNode.insertBefore(newNode, referenceNode.nextSibling); } @@ -2361,6 +2364,11 @@ function defocusSearchBar() { } (function() { + var toggles = document.getElementById(toggleAllDocsId); + if (toggles) { + toggles.onclick = toggleAllDocs; + } + var toggle = createSimpleToggle(false); var hideMethodDocs = getCurrentValue("rustdoc-auto-hide-method-docs") === "true"; var hideImplementors = getCurrentValue("rustdoc-auto-collapse-implementors") !== "false"; @@ -2679,6 +2687,10 @@ function defocusSearchBar() { } } + function getSearchLoadingText() { + return "Loading search results..."; + } + if (search_input) { search_input.onfocus = function() { putBackSearch(this); @@ -2688,7 +2700,7 @@ function defocusSearchBar() { var params = getQueryStringParams(); if (params && params.search) { var search = getSearchElement(); - search.innerHTML = "

    Loading search results...

    "; + search.innerHTML = "

    " + getSearchLoadingText() + "

    "; showSearchResults(search); } @@ -2728,10 +2740,17 @@ function defocusSearchBar() { }); } + function enableSearchInput() { + if (search_input) { + search_input.removeAttribute('disabled'); + } + } + window.addSearchOptions = function(crates) { var elem = document.getElementById("crate-search"); if (!elem) { + enableSearchInput(); return; } var crates_text = []; @@ -2769,10 +2788,7 @@ function defocusSearchBar() { elem.value = savedCrate; } } - - if (search_input) { - search_input.removeAttribute('disabled'); - } + enableSearchInput(); }; function buildHelperPopup() { @@ -2797,8 +2813,8 @@ function defocusSearchBar() { var infos = [ "Prefix searches with a type followed by a colon (e.g., fn:) to \ - restrict the search to a given type.", - "Accepted types are: fn, mod, struct, \ + restrict the search to a given item kind.", + "Accepted kinds are: fn, mod, struct, \ enum, trait, type, macro, \ and const.", "Search functions by type signature (e.g., vec -> usize or \ @@ -2818,12 +2834,12 @@ function defocusSearchBar() { popup.appendChild(container); insertAfter(popup, getSearchElement()); + // So that it's only built once and then it'll do nothing when called! + buildHelperPopup = function() {}; } onHashChange(null); window.onhashchange = onHashChange; - - buildHelperPopup(); }()); // This is required in firefox. Explanations: when going back in the history, firefox doesn't re-run diff --git a/src/librustdoc/html/static/rustdoc.css b/src/librustdoc/html/static/rustdoc.css index 346ceacc92..935b96e51f 100644 --- a/src/librustdoc/html/static/rustdoc.css +++ b/src/librustdoc/html/static/rustdoc.css @@ -126,6 +126,10 @@ h1, h2, h3, h4, font-family: "Fira Sans", sans-serif; } +.content ul.crate a.crate { + font: 16px/1.6 "Fira Sans"; +} + ol, ul { padding-left: 25px; } @@ -1290,7 +1294,7 @@ h4 > .notable-traits { #theme-choices > button { border: none; width: 100%; - padding: 4px; + padding: 4px 8px; text-align: center; background: rgba(0,0,0,0); } diff --git a/src/librustdoc/html/static/themes/ayu.css b/src/librustdoc/html/static/themes/ayu.css index 6e8db1e9eb..3b15b21889 100644 --- a/src/librustdoc/html/static/themes/ayu.css +++ b/src/librustdoc/html/static/themes/ayu.css @@ -129,9 +129,10 @@ pre { color: #ffb44c; } -.line-numbers span { color: #5c6773ab; } +.line-numbers span { color: #5c6773; } .line-numbers .line-highlighted { - background-color: rgba(255, 236, 164, 0.06) !important; + color: #708090; + background-color: rgba(255, 236, 164, 0.06); padding-right: 4px; border-right: 1px solid #ffb44c; } @@ -495,6 +496,7 @@ kbd { #theme-picker, #settings-menu, .help-button { border-color: #5c6773; background-color: #0f1419; + color: #fff; } #theme-picker > img, #settings-menu > img { @@ -513,11 +515,11 @@ kbd { } #theme-choices > button:not(:first-child) { - border-top-color: #c5c5c5; + border-top-color: #5c6773; } #theme-choices > button:hover, #theme-choices > button:focus { - background-color: rgba(70, 70, 70, 0.33); + background-color: rgba(110, 110, 110, 0.33); } @media (max-width: 700px) { diff --git a/src/librustdoc/html/static/themes/dark.css b/src/librustdoc/html/static/themes/dark.css index eeb1f0a3d4..f5a8533776 100644 --- a/src/librustdoc/html/static/themes/dark.css +++ b/src/librustdoc/html/static/themes/dark.css @@ -389,6 +389,7 @@ kbd { #theme-picker, #settings-menu, .help-button { border-color: #e0e0e0; background: #f0f0f0; + color: #000; } #theme-picker:hover, #theme-picker:focus, diff --git a/src/librustdoc/html/static_files.rs b/src/librustdoc/html/static_files.rs index 6bd7e53cdf..213c7f3aab 100644 --- a/src/librustdoc/html/static_files.rs +++ b/src/librustdoc/html/static_files.rs @@ -53,8 +53,10 @@ pub static LICENSE_MIT: &[u8] = include_bytes!("static/LICENSE-MIT.txt"); /// The contents of `rust-logo.png`, the default icon of the documentation. pub static RUST_LOGO: &[u8] = include_bytes!("static/rust-logo.png"); -/// The contents of `favicon.ico`, the default favicon of the documentation. -pub static RUST_FAVICON: &[u8] = include_bytes!("static/favicon.ico"); +/// The default documentation favicons (SVG and PNG fallbacks) +pub static RUST_FAVICON_SVG: &[u8] = include_bytes!("static/favicon.svg"); +pub static RUST_FAVICON_PNG_16: &[u8] = include_bytes!("static/favicon-16x16.png"); +pub static RUST_FAVICON_PNG_32: &[u8] = include_bytes!("static/favicon-32x32.png"); /// The built-in themes given to every documentation site. pub mod themes { diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs index 6d79924a06..7762e8f8d4 100644 --- a/src/librustdoc/lib.rs +++ b/src/librustdoc/lib.rs @@ -16,6 +16,16 @@ #[macro_use] extern crate lazy_static; +#[macro_use] +extern crate tracing; + +// N.B. these need `extern crate` even in 2018 edition +// because they're loaded implicitly from the sysroot. +// The reason they're loaded from the sysroot is because +// the rustdoc artifacts aren't stored in rustc's cargo target directory. +// So if `rustc` was specified in Cargo.toml, this would spuriously rebuild crates. +// +// Dependencies listed in Cargo.toml do not need `extern crate`. extern crate rustc_ast; extern crate rustc_ast_pretty; extern crate rustc_attr; @@ -42,8 +52,6 @@ extern crate rustc_target; extern crate rustc_trait_selection; extern crate rustc_typeck; extern crate test as testing; -#[macro_use] -extern crate tracing; use std::default::Default; use std::env; @@ -64,13 +72,13 @@ mod docfs; mod doctree; #[macro_use] mod error; +mod doctest; mod fold; crate mod formats; pub mod html; mod json; mod markdown; mod passes; -mod test; mod theme; mod visit_ast; mod visit_lib; @@ -153,7 +161,7 @@ fn opts() -> Vec { "", "passes", "list of passes to also run, you might want to pass it multiple times; a value of \ - `list` will print available passes", + `list` will print available passes", "PASSES", ) }), @@ -183,7 +191,7 @@ fn opts() -> Vec { "", "html-in-header", "files to include inline in the section of a rendered Markdown file \ - or generated documentation", + or generated documentation", "FILES", ) }), @@ -192,7 +200,7 @@ fn opts() -> Vec { "", "html-before-content", "files to include inline between and the content of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -201,7 +209,7 @@ fn opts() -> Vec { "", "html-after-content", "files to include inline between the content and of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -210,7 +218,7 @@ fn opts() -> Vec { "", "markdown-before-content", "files to include inline between and the content of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -219,7 +227,7 @@ fn opts() -> Vec { "", "markdown-after-content", "files to include inline between the content and of a rendered \ - Markdown file or generated documentation", + Markdown file or generated documentation", "FILES", ) }), @@ -234,8 +242,8 @@ fn opts() -> Vec { "e", "extend-css", "To add some CSS rules with a given file to generate doc with your \ - own theme. However, your theme might break if the rustdoc's generated HTML \ - changes, so be careful!", + own theme. However, your theme might break if the rustdoc's generated HTML \ + changes, so be careful!", "PATH", ) }), @@ -248,7 +256,7 @@ fn opts() -> Vec { "", "playground-url", "URL to send code snippets to, may be reset by --markdown-playground-url \ - or `#![doc(html_playground_url=...)]`", + or `#![doc(html_playground_url=...)]`", "URL", ) }), @@ -281,7 +289,7 @@ fn opts() -> Vec { "", "resource-suffix", "suffix to add to CSS and JavaScript files, e.g., \"light.css\" will become \ - \"light-suffix.css\"", + \"light-suffix.css\"", "PATH", ) }), @@ -343,7 +351,7 @@ fn opts() -> Vec { "", "static-root-path", "Path string to force loading static files from in output pages. \ - If not set, uses combinations of '../' to reach the documentation root.", + If not set, uses combinations of '../' to reach the documentation root.", "PATH", ) }), @@ -472,11 +480,11 @@ fn run_renderer( } fn main_options(options: config::Options) -> MainResult { - let diag = core::new_handler(options.error_format, None, &options.debugging_options); + let diag = core::new_handler(options.error_format, None, &options.debugging_opts); match (options.should_test, options.markdown_input()) { (true, true) => return wrap_return(&diag, markdown::test(options)), - (true, false) => return test::run(options), + (true, false) => return doctest::run(options), (false, true) => { return wrap_return( &diag, @@ -488,7 +496,7 @@ fn main_options(options: config::Options) -> MainResult { // need to move these items separately because we lose them by the time the closure is called, // but we can't crates the Handler ahead of time because it's not Send - let diag_opts = (options.error_format, options.edition, options.debugging_options.clone()); + let diag_opts = (options.error_format, options.edition, options.debugging_opts.clone()); let show_coverage = options.show_coverage; // First, parse the crate and extract all relevant information. diff --git a/src/librustdoc/markdown.rs b/src/librustdoc/markdown.rs index 89d184e35c..3a87e1c46a 100644 --- a/src/librustdoc/markdown.rs +++ b/src/librustdoc/markdown.rs @@ -7,10 +7,10 @@ use rustc_span::edition::Edition; use rustc_span::source_map::DUMMY_SP; use crate::config::{Options, RenderOptions}; +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::test::{Collector, TestOptions}; /// Separate any lines at the start of the file that begin with `# ` or `%`. fn extract_leading_metadata(s: &str) -> (Vec<&str>, &str) { diff --git a/src/librustdoc/passes/check_code_block_syntax.rs b/src/librustdoc/passes/check_code_block_syntax.rs index d1f2c12ccd..beb1f13ca6 100644 --- a/src/librustdoc/passes/check_code_block_syntax.rs +++ b/src/librustdoc/passes/check_code_block_syntax.rs @@ -1,7 +1,6 @@ -use rustc_ast::token; use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::Emitter, Applicability, Diagnostic, Handler}; -use rustc_parse::lexer::StringReader as Lexer; +use rustc_parse::parse_stream_from_source_str; use rustc_session::parse::ParseSess; use rustc_span::source_map::{FilePathMapping, SourceMap}; use rustc_span::{FileName, InnerSpan}; @@ -28,49 +27,34 @@ struct SyntaxChecker<'a, 'tcx> { impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { fn check_rust_syntax(&self, item: &clean::Item, dox: &str, code_block: RustCodeBlock) { - let buffered_messages = Lrc::new(Lock::new(vec![])); - - let emitter = BufferEmitter { messages: Lrc::clone(&buffered_messages) }; + let buffer = Lrc::new(Lock::new(Buffer::default())); + let emitter = BufferEmitter { buffer: Lrc::clone(&buffer) }; let sm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let handler = Handler::with_emitter(false, None, Box::new(emitter)); + let source = dox[code_block.code].to_owned(); let sess = ParseSess::with_span_handler(handler, sm); - let source_file = sess.source_map().new_source_file( - FileName::Custom(String::from("doctest")), - dox[code_block.code].to_owned(), - ); - let validation_status = rustc_driver::catch_fatal_errors(|| { - let mut has_syntax_errors = false; - let mut only_whitespace = true; - // even if there is a syntax error, we need to run the lexer over the whole file - let mut lexer = Lexer::new(&sess, source_file, None); - loop { - match lexer.next_token().kind { - token::Eof => break, - token::Whitespace => (), - token::Unknown(..) => has_syntax_errors = true, - _ => only_whitespace = false, - } - } - - if has_syntax_errors { - Some(CodeBlockInvalid::SyntaxError) - } else if only_whitespace { - Some(CodeBlockInvalid::Empty) - } else { - None - } + let is_empty = rustc_driver::catch_fatal_errors(|| { + parse_stream_from_source_str( + FileName::Custom(String::from("doctest")), + source, + &sess, + None, + ) + .is_empty() }) - .unwrap_or(Some(CodeBlockInvalid::SyntaxError)); + .unwrap_or(false); + let buffer = buffer.borrow(); - if let Some(code_block_invalid) = validation_status { + if buffer.has_errors || is_empty { let mut diag = if let Some(sp) = super::source_span_for_markdown_range(self.cx, &dox, &code_block.range, &item.attrs) { - let warning_message = match code_block_invalid { - CodeBlockInvalid::SyntaxError => "could not parse code block as Rust code", - CodeBlockInvalid::Empty => "Rust code block is empty", + let warning_message = if buffer.has_errors { + "could not parse code block as Rust code" + } else { + "Rust code block is empty" }; let mut diag = self.cx.sess().struct_span_warn(sp, warning_message); @@ -102,7 +86,7 @@ impl<'a, 'tcx> SyntaxChecker<'a, 'tcx> { }; // FIXME(#67563): Provide more context for these errors by displaying the spans inline. - for message in buffered_messages.borrow().iter() { + for message in buffer.messages.iter() { diag.note(&message); } @@ -125,21 +109,26 @@ impl<'a, 'tcx> DocFolder for SyntaxChecker<'a, 'tcx> { } } +#[derive(Default)] +struct Buffer { + messages: Vec, + has_errors: bool, +} + struct BufferEmitter { - messages: Lrc>>, + buffer: Lrc>, } impl Emitter for BufferEmitter { fn emit_diagnostic(&mut self, diag: &Diagnostic) { - self.messages.borrow_mut().push(format!("error from rustc: {}", diag.message[0].0)); + let mut buffer = self.buffer.borrow_mut(); + buffer.messages.push(format!("error from rustc: {}", diag.message[0].0)); + if diag.is_error() { + buffer.has_errors = true; + } } fn source_map(&self) -> Option<&Lrc> { None } } - -enum CodeBlockInvalid { - SyntaxError, - Empty, -} diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index bf091a0a62..cf94ea384f 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -2,7 +2,6 @@ use rustc_ast as ast; use rustc_data_structures::stable_set::FxHashSet; use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_expand::base::SyntaxExtensionKind; -use rustc_feature::UnstableFeatures; use rustc_hir as hir; use rustc_hir::def::{ DefKind, @@ -12,13 +11,17 @@ use rustc_hir::def::{ use rustc_hir::def_id::DefId; use rustc_middle::ty; use rustc_resolve::ParentScope; -use rustc_session::lint; +use rustc_session::lint::{ + builtin::{BROKEN_INTRA_DOC_LINKS, PRIVATE_INTRA_DOC_LINKS}, + Lint, +}; use rustc_span::hygiene::MacroKind; use rustc_span::symbol::Ident; use rustc_span::symbol::Symbol; use rustc_span::DUMMY_SP; -use smallvec::SmallVec; +use smallvec::{smallvec, SmallVec}; +use std::borrow::Cow; use std::cell::Cell; use std::ops::Range; @@ -37,28 +40,48 @@ pub const COLLECT_INTRA_DOC_LINKS: Pass = Pass { }; pub fn collect_intra_doc_links(krate: Crate, cx: &DocContext<'_>) -> Crate { - if !UnstableFeatures::from_environment().is_nightly_build() { - krate - } else { - let mut coll = LinkCollector::new(cx); + let mut coll = LinkCollector::new(cx); + coll.fold_crate(krate) +} - coll.fold_crate(krate) +enum ErrorKind<'a> { + Resolve(Box>), + AnchorFailure(AnchorFailure), +} + +impl<'a> From> for ErrorKind<'a> { + fn from(err: ResolutionFailure<'a>) -> Self { + ErrorKind::Resolve(box err) } } -enum ErrorKind { - ResolutionFailure, - AnchorFailure(AnchorFailure), +#[derive(Debug)] +enum ResolutionFailure<'a> { + /// This resolved, but with the wrong namespace. + /// `Namespace` is the expected namespace (as opposed to the actual). + WrongNamespace(Res, Namespace), + /// The link failed to resolve. `resolution_failure` should look to see if there's + /// a more helpful error that can be given. + NotResolved { module_id: DefId, partial_res: Option, unresolved: Cow<'a, str> }, + /// should not ever happen + NoParentItem, + /// used to communicate that this should be ignored, but shouldn't be reported to the user + Dummy, +} + +impl ResolutionFailure<'a> { + // This resolved fully (not just partially) but is erroneous for some other reason + fn full_res(&self) -> Option { + match self { + Self::WrongNamespace(res, _) => Some(*res), + _ => None, + } + } } enum AnchorFailure { MultipleAnchors, - Primitive, - Variant, - AssocConstant, - AssocType, - Field, - Method, + RustdocAnchorConflict(Res), } struct LinkCollector<'a, 'tcx> { @@ -68,7 +91,7 @@ struct LinkCollector<'a, 'tcx> { /// This is used to store the kind of associated items, /// because `clean` and the disambiguator code expect them to be different. /// See the code for associated items on inherent impls for details. - kind_side_channel: Cell>, + kind_side_channel: Cell>, } impl<'a, 'tcx> LinkCollector<'a, 'tcx> { @@ -78,17 +101,28 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { fn variant_field( &self, - path_str: &str, + path_str: &'path str, current_item: &Option, module_id: DefId, - ) -> Result<(Res, Option), ErrorKind> { + ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; + let no_res = || ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_str.into(), + }; + debug!("looking for enum variant {}", path_str); let mut split = path_str.rsplitn(3, "::"); - let variant_field_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; - let variant_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; + let (variant_field_str, variant_field_name) = split + .next() + .map(|f| (f, Symbol::intern(f))) + .expect("fold_item should ensure link is non-empty"); + let (variant_str, variant_name) = + // we're not sure this is a variant at all, so use the full string + // If there's no second component, the link looks like `[path]`. + // So there's no partial res and we should say the whole link failed to resolve. + split.next().map(|f| (f, Symbol::intern(f))).ok_or_else(no_res)?; let path = split .next() .map(|f| { @@ -99,14 +133,17 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { } f.to_owned() }) - .ok_or(ErrorKind::ResolutionFailure)?; - let (_, ty_res) = cx + // If there's no third component, we saw `[a::b]` before and it failed to resolve. + // So there's no partial res. + .ok_or_else(no_res)?; + let ty_res = cx .enter_resolver(|resolver| { resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) }) - .map_err(|_| ErrorKind::ResolutionFailure)?; + .map(|(_, res)| res) + .unwrap_or(Res::Err); if let Res::Err = ty_res { - return Err(ErrorKind::ResolutionFailure); + return Err(no_res().into()); } let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); match ty_res { @@ -118,31 +155,47 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { .flat_map(|imp| cx.tcx.associated_items(*imp).in_definition_order()) .any(|item| item.ident.name == variant_name) { - return Err(ErrorKind::ResolutionFailure); + // This is just to let `fold_item` know that this shouldn't be considered; + // it's a bug for the error to make it to the user + return Err(ResolutionFailure::Dummy.into()); } - match cx.tcx.type_of(did).kind { + match cx.tcx.type_of(did).kind() { ty::Adt(def, _) if def.is_enum() => { if def.all_fields().any(|item| item.ident.name == variant_field_name) { Ok(( ty_res, Some(format!( "variant.{}.field.{}", - variant_name, variant_field_name + variant_str, variant_field_name )), )) } else { - Err(ErrorKind::ResolutionFailure) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(Res::Def(DefKind::Enum, def.did)), + unresolved: variant_field_str.into(), + } + .into()) } } - _ => Err(ErrorKind::ResolutionFailure), + _ => unreachable!(), } } - _ => Err(ErrorKind::ResolutionFailure), + _ => Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: variant_str.into(), + } + .into()), } } /// Resolves a string as a macro. - fn macro_resolve(&self, path_str: &str, parent_id: Option) -> Option { + fn macro_resolve( + &self, + path_str: &'a str, + module_id: DefId, + ) -> Result> { let cx = self.cx; let path = ast::Path::from_ident(Ident::from_str(path_str)); cx.enter_resolver(|resolver| { @@ -154,275 +207,349 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> { false, ) { if let SyntaxExtensionKind::LegacyBang { .. } = ext.kind { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } } if let Some(res) = resolver.all_macros().get(&Symbol::intern(path_str)) { - return Some(res.map_id(|_| panic!("unexpected id"))); + return Ok(res.map_id(|_| panic!("unexpected id"))); } - if let Some(module_id) = parent_id { - if let Ok((_, res)) = - resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) - { - // don't resolve builtins like `#[derive]` - if let Res::Def(..) = res { - let res = res.map_id(|_| panic!("unexpected node_id")); - return Some(res); - } + debug!("resolving {} as a macro in the module {:?}", path_str, module_id); + if let Ok((_, res)) = + resolver.resolve_str_path_error(DUMMY_SP, path_str, MacroNS, module_id) + { + // don't resolve builtins like `#[derive]` + if let Res::Def(..) = res { + let res = res.map_id(|_| panic!("unexpected node_id")); + return Ok(res); } - } else { - debug!("attempting to resolve item without parent module: {}", path_str); } - None + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_str.into(), + }) }) } + /// Resolves a string as a path within a particular namespace. Also returns an optional /// URL fragment in the case of variants and methods. - fn resolve( + fn resolve<'path>( &self, - path_str: &str, + path_str: &'path str, ns: Namespace, current_item: &Option, - parent_id: Option, + module_id: DefId, extra_fragment: &Option, - ) -> Result<(Res, Option), ErrorKind> { + ) -> Result<(Res, Option), ErrorKind<'path>> { let cx = self.cx; - // In case we're in a module, try to resolve the relative path. - if let Some(module_id) = parent_id { - let result = cx.enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) - }); - debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); - let result = match result { - Ok((_, Res::Err)) => Err(ErrorKind::ResolutionFailure), - _ => result.map_err(|_| ErrorKind::ResolutionFailure), + let result = cx.enter_resolver(|resolver| { + resolver.resolve_str_path_error(DUMMY_SP, &path_str, ns, module_id) + }); + debug!("{} resolved to {:?} in namespace {:?}", path_str, result, ns); + let result = match result { + Ok((_, Res::Err)) => Err(()), + x => x, + }; + + if let Ok((_, res)) = result { + let res = res.map_id(|_| panic!("unexpected node_id")); + // In case this is a trait item, skip the + // early return and try looking for the trait. + let value = match res { + Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true, + Res::Def(DefKind::AssocTy, _) => false, + Res::Def(DefKind::Variant, _) => { + return handle_variant(cx, res, extra_fragment); + } + // Not a trait item; just return what we found. + Res::PrimTy(ty) => { + if extra_fragment.is_some() { + return Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )); + } + return Ok((res, Some(ty.name_str().to_owned()))); + } + Res::Def(DefKind::Mod, _) => { + return Ok((res, extra_fragment.clone())); + } + _ => { + return Ok((res, extra_fragment.clone())); + } }; - if let Ok((_, res)) = result { - let res = res.map_id(|_| panic!("unexpected node_id")); - // In case this is a trait item, skip the - // early return and try looking for the trait. - let value = match res { - Res::Def(DefKind::AssocFn | DefKind::AssocConst, _) => true, - Res::Def(DefKind::AssocTy, _) => false, - Res::Def(DefKind::Variant, _) => { - return handle_variant(cx, res, extra_fragment); - } - // Not a trait item; just return what we found. - Res::PrimTy(..) => { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); - } - return Ok((res, Some(path_str.to_owned()))); - } - Res::Def(DefKind::Mod, _) => { - return Ok((res, extra_fragment.clone())); - } - _ => { - return Ok((res, extra_fragment.clone())); - } - }; - - if value != (ns == ValueNS) { - return Err(ErrorKind::ResolutionFailure); - } - } else if let Some((path, prim)) = is_primitive(path_str, ns) { - if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Primitive)); - } - return Ok((prim, Some(path.to_owned()))); + if value != (ns == ValueNS) { + return Err(ResolutionFailure::WrongNamespace(res, ns).into()); } + // FIXME: why is this necessary? + } else if let Some((path, prim)) = is_primitive(path_str, ns) { + if extra_fragment.is_some() { + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(prim))); + } + return Ok((prim, Some(path.to_owned()))); + } - // Try looking for methods and associated items. - let mut split = path_str.rsplitn(2, "::"); - let item_name = - split.next().map(|f| Symbol::intern(f)).ok_or(ErrorKind::ResolutionFailure)?; - let path = split - .next() - .map(|f| { - if f == "self" || f == "Self" { - if let Some(name) = current_item.as_ref() { - return name.clone(); - } - } - f.to_owned() - }) - .ok_or(ErrorKind::ResolutionFailure)?; - - if let Some((path, prim)) = is_primitive(&path, TypeNS) { - for &impl_ in primitive_impl(cx, &path).ok_or(ErrorKind::ResolutionFailure)? { - let link = cx - .tcx - .associated_items(impl_) - .find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - impl_, - ) - .and_then(|item| match item.kind { - ty::AssocKind::Fn => Some("method"), - _ => None, - }) - .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_name)))); - if let Some(link) = link { - return Ok(link); + // Try looking for methods and associated items. + let mut split = path_str.rsplitn(2, "::"); + // this can be an `unwrap()` because we ensure the link is never empty + let (item_str, item_name) = split.next().map(|i| (i, Symbol::intern(i))).unwrap(); + let path_root = split + .next() + .map(|f| { + if f == "self" || f == "Self" { + if let Some(name) = current_item.as_ref() { + return name.clone(); } } - return Err(ErrorKind::ResolutionFailure); - } + f.to_owned() + }) + // If there's no `::`, it's not an associated item. + // So we can be sure that `rustc_resolve` was accurate when it said it wasn't resolved. + .ok_or_else(|| { + debug!("found no `::`, assumming {} was correctly not in scope", item_name); + ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: item_str.into(), + } + })?; - let (_, ty_res) = cx - .enter_resolver(|resolver| { - resolver.resolve_str_path_error(DUMMY_SP, &path, TypeNS, module_id) - }) - .map_err(|_| ErrorKind::ResolutionFailure)?; - if let Res::Err = ty_res { + if let Some((path, prim)) = is_primitive(&path_root, TypeNS) { + let impls = + primitive_impl(cx, &path).ok_or_else(|| ResolutionFailure::NotResolved { + module_id, + partial_res: Some(prim), + unresolved: item_str.into(), + })?; + for &impl_ in impls { + let link = cx + .tcx + .associated_items(impl_) + .find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + impl_, + ) + .map(|item| match item.kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + }) + .map(|out| (prim, Some(format!("{}#{}.{}", path, out, item_str)))); + if let Some(link) = link { + return Ok(link); + } + } + debug!( + "returning primitive error for {}::{} in {} namespace", + path, + item_name, + ns.descr() + ); + return Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(prim), + unresolved: item_str.into(), + } + .into()); + } + + let ty_res = cx + .enter_resolver(|resolver| { + // only types can have associated items + resolver.resolve_str_path_error(DUMMY_SP, &path_root, TypeNS, module_id) + }) + .map(|(_, res)| res); + let ty_res = match ty_res { + Err(()) | Ok(Res::Err) => { return if ns == Namespace::ValueNS { self.variant_field(path_str, current_item, module_id) } else { - Err(ErrorKind::ResolutionFailure) + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: None, + unresolved: path_root.into(), + } + .into()) }; } - let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); - let res = match ty_res { - Res::Def( - DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, - did, - ) => { - debug!("looking for associated item named {} for item {:?}", item_name, did); - // Checks if item_name belongs to `impl SomeItem` - let kind = cx - .tcx - .inherent_impls(did) - .iter() - .flat_map(|&imp| { - cx.tcx.associated_items(imp).find_by_name_and_namespace( - cx.tcx, - Ident::with_dummy_span(item_name), - ns, - imp, - ) - }) - .map(|item| item.kind) - // There should only ever be one associated item that matches from any inherent impl - .next() - // Check if item_name belongs to `impl SomeTrait for SomeItem` - // This gives precedence to `impl SomeItem`: - // Although having both would be ambiguous, use impl version for compat. sake. - // To handle that properly resolve() would have to support - // something like [`ambi_fn`](::ambi_fn) - .or_else(|| { - let kind = resolve_associated_trait_item( - did, module_id, item_name, ns, &self.cx, - ); - debug!("got associated item kind {:?}", kind); - kind - }); - - if let Some(kind) = kind { - let out = match kind { - ty::AssocKind::Fn => "method", - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - }; - Some(if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if kind == ty::AssocKind::Fn { - AnchorFailure::Method - } else { - AnchorFailure::AssocConstant - })) - } else { - // HACK(jynelson): `clean` expects the type, not the associated item. - // but the disambiguator logic expects the associated item. - // Store the kind in a side channel so that only the disambiguator logic looks at it. - self.kind_side_channel.set(Some(kind.as_def_kind())); - Ok((ty_res, Some(format!("{}.{}", out, item_name)))) - }) - } else if ns == Namespace::ValueNS { - match cx.tcx.type_of(did).kind { - ty::Adt(def, _) => { - let field = if def.is_enum() { - def.all_fields().find(|item| item.ident.name == item_name) - } else { - def.non_enum_variant() - .fields - .iter() - .find(|item| item.ident.name == item_name) - }; - field.map(|item| { - if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if def.is_enum() { - AnchorFailure::Variant - } else { - AnchorFailure::Field - })) - } else { - Ok(( - ty_res, - Some(format!( - "{}.{}", - if def.is_enum() { - "variant" - } else { - "structfield" - }, - item.ident - )), - )) - } - }) - } - _ => None, - } - } else { - // We already know this isn't in ValueNS, so no need to check variant_field - return Err(ErrorKind::ResolutionFailure); - } - } - Res::Def(DefKind::Trait, did) => cx + Ok(res) => res, + }; + let ty_res = ty_res.map_id(|_| panic!("unexpected node_id")); + let res = match ty_res { + Res::Def(DefKind::Struct | DefKind::Union | DefKind::Enum | DefKind::TyAlias, did) => { + debug!("looking for associated item named {} for item {:?}", item_name, did); + // Checks if item_name belongs to `impl SomeItem` + let assoc_item = cx .tcx - .associated_items(did) - .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did) - .map(|item| { - let kind = match item.kind { - ty::AssocKind::Const => "associatedconstant", - ty::AssocKind::Type => "associatedtype", - ty::AssocKind::Fn => { - if item.defaultness.has_value() { - "method" - } else { - "tymethod" - } - } - }; + .inherent_impls(did) + .iter() + .flat_map(|&imp| { + cx.tcx.associated_items(imp).find_by_name_and_namespace( + cx.tcx, + Ident::with_dummy_span(item_name), + ns, + imp, + ) + }) + .map(|item| (item.kind, item.def_id)) + // There should only ever be one associated item that matches from any inherent impl + .next() + // Check if item_name belongs to `impl SomeTrait for SomeItem` + // This gives precedence to `impl SomeItem`: + // Although having both would be ambiguous, use impl version for compat. sake. + // To handle that properly resolve() would have to support + // something like [`ambi_fn`](::ambi_fn) + .or_else(|| { + let kind = + resolve_associated_trait_item(did, module_id, item_name, ns, &self.cx); + debug!("got associated item kind {:?}", kind); + kind + }); - if extra_fragment.is_some() { - Err(ErrorKind::AnchorFailure(if item.kind == ty::AssocKind::Const { - AnchorFailure::AssocConstant - } else if item.kind == ty::AssocKind::Type { - AnchorFailure::AssocType + if let Some((kind, id)) = assoc_item { + let out = match kind { + ty::AssocKind::Fn => "method", + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + }; + Some(if extra_fragment.is_some() { + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) + } else { + // HACK(jynelson): `clean` expects the type, not the associated item. + // but the disambiguator logic expects the associated item. + // Store the kind in a side channel so that only the disambiguator logic looks at it. + self.kind_side_channel.set(Some((kind.as_def_kind(), id))); + Ok((ty_res, Some(format!("{}.{}", out, item_str)))) + }) + } else if ns == Namespace::ValueNS { + debug!("looking for variants or fields named {} for {:?}", item_name, did); + match cx.tcx.type_of(did).kind() { + ty::Adt(def, _) => { + let field = if def.is_enum() { + def.all_fields().find(|item| item.ident.name == item_name) } else { - AnchorFailure::Method - })) - } else { - let res = Res::Def(item.kind.as_def_kind(), item.def_id); - Ok((res, Some(format!("{}.{}", kind, item_name)))) + def.non_enum_variant() + .fields + .iter() + .find(|item| item.ident.name == item_name) + }; + field.map(|item| { + if extra_fragment.is_some() { + let res = Res::Def( + if def.is_enum() { + DefKind::Variant + } else { + DefKind::Field + }, + item.did, + ); + Err(ErrorKind::AnchorFailure( + AnchorFailure::RustdocAnchorConflict(res), + )) + } else { + Ok(( + ty_res, + Some(format!( + "{}.{}", + if def.is_enum() { "variant" } else { "structfield" }, + item.ident + )), + )) + } + }) } - }), - _ => None, - }; - res.unwrap_or_else(|| { - if ns == Namespace::ValueNS { - self.variant_field(path_str, current_item, module_id) + _ => None, + } } else { - Err(ErrorKind::ResolutionFailure) + // We already know this isn't in ValueNS, so no need to check variant_field + return Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: item_str.into(), + } + .into()); } - }) - } else { - debug!("attempting to resolve item without parent module: {}", path_str); - Err(ErrorKind::ResolutionFailure) + } + Res::Def(DefKind::Trait, did) => cx + .tcx + .associated_items(did) + .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, did) + .map(|item| { + let kind = match item.kind { + ty::AssocKind::Const => "associatedconstant", + ty::AssocKind::Type => "associatedtype", + ty::AssocKind::Fn => { + if item.defaultness.has_value() { + "method" + } else { + "tymethod" + } + } + }; + + if extra_fragment.is_some() { + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(ty_res))) + } else { + let res = Res::Def(item.kind.as_def_kind(), item.def_id); + Ok((res, Some(format!("{}.{}", kind, item_str)))) + } + }), + _ => None, + }; + res.unwrap_or_else(|| { + if ns == Namespace::ValueNS { + self.variant_field(path_str, current_item, module_id) + } else { + Err(ResolutionFailure::NotResolved { + module_id, + partial_res: Some(ty_res), + unresolved: item_str.into(), + } + .into()) + } + }) + } + + /// Used for reporting better errors. + /// + /// Returns whether the link resolved 'fully' in another namespace. + /// 'fully' here means that all parts of the link resolved, not just some path segments. + /// This returns the `Res` even if it was erroneous for some reason + /// (such as having invalid URL fragments or being in the wrong namespace). + fn check_full_res( + &self, + ns: Namespace, + path_str: &str, + module_id: DefId, + current_item: &Option, + extra_fragment: &Option, + ) -> Option { + let check_full_res_inner = |this: &Self, result: Result>| { + let res = match result { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(box kind)) => kind.full_res(), + Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))) => { + Some(res) + } + Err(ErrorKind::AnchorFailure(AnchorFailure::MultipleAnchors)) => None, + }; + this.kind_side_channel.take().map(|(kind, id)| Res::Def(kind, id)).or(res) + }; + // cannot be used for macro namespace + let check_full_res = |this: &Self, ns| { + let result = this.resolve(path_str, ns, current_item, module_id, extra_fragment); + check_full_res_inner(this, result.map(|(res, _)| res)) + }; + let check_full_res_macro = |this: &Self| { + let result = this.macro_resolve(path_str, module_id); + check_full_res_inner(this, result.map_err(ErrorKind::from)) + }; + match ns { + Namespace::MacroNS => check_full_res_macro(self), + Namespace::TypeNS | Namespace::ValueNS => check_full_res(self, ns), } } } @@ -433,7 +560,7 @@ fn resolve_associated_trait_item( item_name: Symbol, ns: Namespace, cx: &DocContext<'_>, -) -> Option { +) -> Option<(ty::AssocKind, DefId)> { let ty = cx.tcx.type_of(did); // First consider automatic impls: `impl From for T` let implicit_impls = crate::clean::get_auto_trait_and_blanket_impls(cx, ty, did); @@ -461,7 +588,7 @@ fn resolve_associated_trait_item( // but provided methods come directly from `tcx`. // Fortunately, we don't need the whole method, we just need to know // what kind of associated item it is. - Some((assoc.def_id, kind)) + Some((kind, assoc.def_id)) }); let assoc = items.next(); debug_assert_eq!(items.count(), 0); @@ -483,7 +610,7 @@ fn resolve_associated_trait_item( ns, trait_, ) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) } } _ => panic!("get_impls returned something that wasn't an impl"), @@ -500,12 +627,12 @@ fn resolve_associated_trait_item( cx.tcx .associated_items(trait_) .find_by_name_and_namespace(cx.tcx, Ident::with_dummy_span(item_name), ns, trait_) - .map(|assoc| (assoc.def_id, assoc.kind)) + .map(|assoc| (assoc.kind, assoc.def_id)) })); } // FIXME: warn about ambiguity debug!("the candidates were {:?}", candidates); - candidates.pop().map(|(_, kind)| kind) + candidates.pop() } /// Given a type, return all traits in scope in `module` implemented by that type. @@ -534,19 +661,21 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx let trait_ref = cx.tcx.impl_trait_ref(impl_).expect("this is not an inherent impl"); // Check if these are the same type. let impl_type = trait_ref.self_ty(); - debug!( + trace!( "comparing type {} with kind {:?} against type {:?}", - impl_type, impl_type.kind, type_ + impl_type, + impl_type.kind(), + type_ ); // Fast path: if this is a primitive simple `==` will work saw_impl = impl_type == ty - || match impl_type.kind { + || match impl_type.kind() { // Check if these are the same def_id ty::Adt(def, _) => { debug!("adt def_id: {:?}", def.did); def.did == type_ } - ty::Foreign(def_id) => def_id == type_, + ty::Foreign(def_id) => *def_id == type_, _ => false, }; }); @@ -558,10 +687,10 @@ fn traits_implemented_by(cx: &DocContext<'_>, type_: DefId, module: DefId) -> Fx /// Check for resolve collisions between a trait and its derive /// /// These are common and we should just resolve to the trait in that case -fn is_derive_trait_collision(ns: &PerNS>) -> bool { +fn is_derive_trait_collision(ns: &PerNS>>) -> bool { if let PerNS { - type_ns: Some((Res::Def(DefKind::Trait, _), _)), - macro_ns: Some((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), + type_ns: Ok((Res::Def(DefKind::Trait, _), _)), + macro_ns: Ok((Res::Def(DefKind::Macro(MacroKind::Derive), _), _)), .. } = *ns { @@ -578,6 +707,9 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { let parent_node = if item.is_fake() { // FIXME: is this correct? None + // If we're documenting the crate root itself, it has no parent. Use the root instead. + } else if item.def_id.is_top_level_module() { + Some(item.def_id) } else { let mut current = item.def_id; // The immediate parent might not always be a module. @@ -589,6 +721,12 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { } current = parent; } else { + debug!( + "{:?} has no parent (kind={:?}, original was {:?})", + current, + self.cx.tcx.def_kind(current), + item.def_id + ); break None; } } @@ -629,7 +767,6 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { self.mod_ids.push(item.def_id); } - let cx = self.cx; let dox = item.attrs.collapsed_doc_value().unwrap_or_else(String::new); trace!("got documentation '{}'", dox); @@ -671,305 +808,15 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { }); for (ori_link, link_range) in markdown_links(&dox) { - trace!("considering link '{}'", ori_link); - - // Bail early for real links. - if ori_link.contains('/') { - continue; - } - - // [] is mostly likely not supposed to be a link - if ori_link.is_empty() { - continue; - } - - let link = ori_link.replace("`", ""); - let parts = link.split('#').collect::>(); - let (link, extra_fragment) = if parts.len() > 2 { - anchor_failure(cx, &item, &link, &dox, link_range, AnchorFailure::MultipleAnchors); - continue; - } else if parts.len() == 2 { - if parts[0].trim().is_empty() { - // This is an anchor to an element of the current page, nothing to do in here! - continue; - } - (parts[0].to_owned(), Some(parts[1].to_owned())) - } else { - (parts[0].to_owned(), None) - }; - let resolved_self; - let mut path_str; - let disambiguator; - let (mut res, mut fragment) = { - path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { - disambiguator = Some(d); - path - } else { - disambiguator = None; - &link - } - .trim(); - - if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { - continue; - } - - // In order to correctly resolve intra-doc-links we need to - // pick a base AST node to work from. If the documentation for - // this module came from an inner comment (//!) then we anchor - // our name resolution *inside* the module. If, on the other - // hand it was an outer comment (///) then we anchor the name - // resolution in the parent module on the basis that the names - // used are more likely to be intended to be parent names. For - // this, we set base_node to None for inner comments since - // we've already pushed this node onto the resolution stack but - // for outer comments we explicitly try and resolve against the - // parent_node first. - let base_node = if item.is_mod() && item.attrs.inner_docs { - self.mod_ids.last().copied() - } else { - parent_node - }; - - // replace `Self` with suitable item's parent name - if path_str.starts_with("Self::") { - if let Some(ref name) = parent_name { - resolved_self = format!("{}::{}", name, &path_str[6..]); - path_str = &resolved_self; - } - } - - match disambiguator.map(Disambiguator::ns) { - Some(ns @ (ValueNS | TypeNS)) => { - match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) - { - Ok(res) => res, - Err(ErrorKind::ResolutionFailure) => { - resolution_failure(cx, &item, path_str, &dox, link_range); - // This could just be a normal link or a broken link - // we could potentially check if something is - // "intra-doc-link-like" and warn in that case. - continue; - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - } - } - None => { - // Try everything! - let mut candidates = PerNS { - macro_ns: self - .macro_resolve(path_str, base_node) - .map(|res| (res, extra_fragment.clone())), - type_ns: match self.resolve( - path_str, - TypeNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => { - debug!("got res in TypeNS: {:?}", res); - Some(res) - } - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - Err(ErrorKind::ResolutionFailure) => None, - }, - value_ns: match self.resolve( - path_str, - ValueNS, - ¤t_item, - base_node, - &extra_fragment, - ) { - Ok(res) => Some(res), - Err(ErrorKind::AnchorFailure(msg)) => { - anchor_failure(cx, &item, &ori_link, &dox, link_range, msg); - continue; - } - Err(ErrorKind::ResolutionFailure) => None, - } - .and_then(|(res, fragment)| { - // Constructors are picked up in the type namespace. - match res { - Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => None, - _ => match (fragment, extra_fragment) { - (Some(fragment), Some(_)) => { - // Shouldn't happen but who knows? - Some((res, Some(fragment))) - } - (fragment, None) | (None, fragment) => { - Some((res, fragment)) - } - }, - } - }), - }; - - if candidates.is_empty() { - resolution_failure(cx, &item, path_str, &dox, link_range); - // this could just be a normal link - continue; - } - - let len = candidates.clone().present_items().count(); - - if len == 1 { - candidates.present_items().next().unwrap() - } else if len == 2 && is_derive_trait_collision(&candidates) { - candidates.type_ns.unwrap() - } else { - if is_derive_trait_collision(&candidates) { - candidates.macro_ns = None; - } - let candidates = - candidates.map(|candidate| candidate.map(|(res, _)| res)); - let candidates = [TypeNS, ValueNS, MacroNS] - .iter() - .filter_map(|&ns| candidates[ns].map(|res| (res, ns))); - ambiguity_error( - cx, - &item, - path_str, - &dox, - link_range, - candidates.collect(), - ); - continue; - } - } - Some(MacroNS) => { - if let Some(res) = self.macro_resolve(path_str, base_node) { - (res, extra_fragment) - } else { - resolution_failure(cx, &item, path_str, &dox, link_range); - continue; - } - } - } - }; - - // Check for a primitive which might conflict with a module - // Report the ambiguity and require that the user specify which one they meant. - // FIXME: could there ever be a primitive not in the type namespace? - if matches!( - disambiguator, - None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) - ) && !matches!(res, Res::PrimTy(_)) - { - if let Some((path, prim)) = is_primitive(path_str, TypeNS) { - // `prim@char` - if matches!(disambiguator, Some(Disambiguator::Primitive)) { - if fragment.is_some() { - anchor_failure( - cx, - &item, - path_str, - &dox, - link_range, - AnchorFailure::Primitive, - ); - continue; - } - res = prim; - fragment = Some(path.to_owned()); - } else { - // `[char]` when a `char` module is in scope - let candidates = vec![(res, TypeNS), (prim, TypeNS)]; - ambiguity_error(cx, &item, path_str, &dox, link_range, candidates); - continue; - } - } - } - - let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { - // The resolved item did not match the disambiguator; give a better error than 'not found' - let msg = format!("incompatible link kind for `{}`", path_str); - report_diagnostic(cx, &msg, &item, &dox, link_range.clone(), |diag, sp| { - let note = format!( - "this link resolved to {} {}, which is not {} {}", - resolved.article(), - resolved.descr(), - specified.article(), - specified.descr() - ); - let suggestion = resolved.display_for(path_str); - let help_msg = - format!("to link to the {}, use its disambiguator", resolved.descr()); - diag.note(¬e); - if let Some(sp) = sp { - diag.span_suggestion( - sp, - &help_msg, - suggestion, - Applicability::MaybeIncorrect, - ); - } else { - diag.help(&format!("{}: {}", help_msg, suggestion)); - } - }); - }; - if let Res::PrimTy(_) = res { - match disambiguator { - Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { - item.attrs.links.push((ori_link, None, fragment)) - } - Some(other) => { - report_mismatch(other, Disambiguator::Primitive); - continue; - } - } - } else { - debug!("intra-doc link to {} resolved to {:?}", path_str, res); - - // Disallow e.g. linking to enums with `struct@` - if let Res::Def(kind, _) = res { - debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); - match (self.kind_side_channel.take().unwrap_or(kind), disambiguator) { - | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) - // NOTE: this allows 'method' to mean both normal functions and associated functions - // This can't cause ambiguity because both are in the same namespace. - | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) - // These are namespaces; allow anything in the namespace to match - | (_, Some(Disambiguator::Namespace(_))) - // If no disambiguator given, allow anything - | (_, None) - // All of these are valid, so do nothing - => {} - (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} - (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { - report_mismatch(specified, Disambiguator::Kind(kind)); - continue; - } - } - } - - // item can be non-local e.g. when using #[doc(primitive = "pointer")] - if let Some((src_id, dst_id)) = res - .opt_def_id() - .and_then(|def_id| def_id.as_local()) - .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) - { - use rustc_hir::def_id::LOCAL_CRATE; - - let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); - let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); - - if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) - && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) - { - privacy_error(cx, &item, &path_str, &dox, link_range); - continue; - } - } - let id = register_res(cx, res); - item.attrs.links.push((ori_link, Some(id), fragment)); - } + self.resolve_link( + &mut item, + &dox, + ¤t_item, + parent_node, + &parent_name, + ori_link, + link_range, + ); } if item.is_mod() && !item.attrs.inner_docs { @@ -986,14 +833,427 @@ impl<'a, 'tcx> DocFolder for LinkCollector<'a, 'tcx> { self.fold_item_recur(item) } } +} - // FIXME: if we can resolve intra-doc links from other crates, we can use the stock - // `fold_crate`, but until then we should avoid scanning `krate.external_traits` since those - // will never resolve properly - fn fold_crate(&mut self, mut c: Crate) -> Crate { - c.module = c.module.take().and_then(|module| self.fold_item(module)); +impl LinkCollector<'_, '_> { + fn resolve_link( + &self, + item: &mut Item, + dox: &str, + current_item: &Option, + parent_node: Option, + parent_name: &Option, + ori_link: String, + link_range: Option>, + ) { + trace!("considering link '{}'", ori_link); - c + // Bail early for real links. + if ori_link.contains('/') { + return; + } + + // [] is mostly likely not supposed to be a link + if ori_link.is_empty() { + return; + } + + let cx = self.cx; + let link = ori_link.replace("`", ""); + let parts = link.split('#').collect::>(); + let (link, extra_fragment) = if parts.len() > 2 { + anchor_failure(cx, &item, &link, dox, link_range, AnchorFailure::MultipleAnchors); + return; + } else if parts.len() == 2 { + if parts[0].trim().is_empty() { + // This is an anchor to an element of the current page, nothing to do in here! + return; + } + (parts[0], Some(parts[1].to_owned())) + } else { + (parts[0], None) + }; + let resolved_self; + let link_text; + let mut path_str; + let disambiguator; + let (mut res, mut fragment) = { + path_str = if let Ok((d, path)) = Disambiguator::from_str(&link) { + disambiguator = Some(d); + path + } else { + disambiguator = None; + &link + } + .trim(); + + if path_str.contains(|ch: char| !(ch.is_alphanumeric() || ch == ':' || ch == '_')) { + return; + } + + // We stripped `()` and `!` when parsing the disambiguator. + // Add them back to be displayed, but not prefix disambiguators. + link_text = disambiguator + .map(|d| d.display_for(path_str)) + .unwrap_or_else(|| path_str.to_owned()); + + // In order to correctly resolve intra-doc-links we need to + // pick a base AST node to work from. If the documentation for + // this module came from an inner comment (//!) then we anchor + // our name resolution *inside* the module. If, on the other + // hand it was an outer comment (///) then we anchor the name + // resolution in the parent module on the basis that the names + // used are more likely to be intended to be parent names. For + // this, we set base_node to None for inner comments since + // we've already pushed this node onto the resolution stack but + // for outer comments we explicitly try and resolve against the + // parent_node first. + let base_node = if item.is_mod() && item.attrs.inner_docs { + self.mod_ids.last().copied() + } else { + parent_node + }; + + let mut module_id = if let Some(id) = base_node { + id + } else { + debug!("attempting to resolve item without parent module: {}", path_str); + let err_kind = ResolutionFailure::NoParentItem.into(); + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![err_kind], + ); + return; + }; + + // replace `Self` with suitable item's parent name + if path_str.starts_with("Self::") { + if let Some(ref name) = parent_name { + resolved_self = format!("{}::{}", name, &path_str[6..]); + path_str = &resolved_self; + } + } else if path_str.starts_with("crate::") { + use rustc_span::def_id::CRATE_DEF_INDEX; + + // HACK(jynelson): rustc_resolve thinks that `crate` is the crate currently being documented. + // But rustdoc wants it to mean the crate this item was originally present in. + // To work around this, remove it and resolve relative to the crate root instead. + // HACK(jynelson)(2): If we just strip `crate::` then suddenly primitives become ambiguous + // (consider `crate::char`). Instead, change it to `self::`. This works because 'self' is now the crate root. + resolved_self = format!("self::{}", &path_str["crate::".len()..]); + path_str = &resolved_self; + module_id = DefId { krate: item.def_id.krate, index: CRATE_DEF_INDEX }; + } + + match self.resolve_with_disambiguator( + disambiguator, + item, + dox, + path_str, + current_item, + module_id, + extra_fragment, + &ori_link, + link_range.clone(), + ) { + Some(x) => x, + None => return, + } + }; + + // Check for a primitive which might conflict with a module + // Report the ambiguity and require that the user specify which one they meant. + // FIXME: could there ever be a primitive not in the type namespace? + if matches!( + disambiguator, + None | Some(Disambiguator::Namespace(Namespace::TypeNS) | Disambiguator::Primitive) + ) && !matches!(res, Res::PrimTy(_)) + { + if let Some((path, prim)) = is_primitive(path_str, TypeNS) { + // `prim@char` + if matches!(disambiguator, Some(Disambiguator::Primitive)) { + if fragment.is_some() { + anchor_failure( + cx, + &item, + path_str, + dox, + link_range, + AnchorFailure::RustdocAnchorConflict(prim), + ); + return; + } + res = prim; + fragment = Some(path.to_owned()); + } else { + // `[char]` when a `char` module is in scope + let candidates = vec![res, prim]; + ambiguity_error(cx, &item, path_str, dox, link_range, candidates); + return; + } + } + } + + let report_mismatch = |specified: Disambiguator, resolved: Disambiguator| { + // The resolved item did not match the disambiguator; give a better error than 'not found' + let msg = format!("incompatible link kind for `{}`", path_str); + let callback = |diag: &mut DiagnosticBuilder<'_>, sp| { + let note = format!( + "this link resolved to {} {}, which is not {} {}", + resolved.article(), + resolved.descr(), + specified.article(), + specified.descr() + ); + diag.note(¬e); + suggest_disambiguator(resolved, diag, path_str, dox, sp, &link_range); + }; + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, &item, dox, &link_range, callback); + }; + if let Res::PrimTy(..) = res { + match disambiguator { + Some(Disambiguator::Primitive | Disambiguator::Namespace(_)) | None => { + item.attrs.links.push(ItemLink { + link: ori_link, + link_text, + did: None, + fragment, + }); + } + Some(other) => { + report_mismatch(other, Disambiguator::Primitive); + return; + } + } + } else { + debug!("intra-doc link to {} resolved to {:?}", path_str, res); + + // Disallow e.g. linking to enums with `struct@` + if let Res::Def(kind, _) = res { + debug!("saw kind {:?} with disambiguator {:?}", kind, disambiguator); + match (self.kind_side_channel.take().map(|(kind, _)| kind).unwrap_or(kind), disambiguator) { + | (DefKind::Const | DefKind::ConstParam | DefKind::AssocConst | DefKind::AnonConst, Some(Disambiguator::Kind(DefKind::Const))) + // NOTE: this allows 'method' to mean both normal functions and associated functions + // This can't cause ambiguity because both are in the same namespace. + | (DefKind::Fn | DefKind::AssocFn, Some(Disambiguator::Kind(DefKind::Fn))) + // These are namespaces; allow anything in the namespace to match + | (_, Some(Disambiguator::Namespace(_))) + // If no disambiguator given, allow anything + | (_, None) + // All of these are valid, so do nothing + => {} + (actual, Some(Disambiguator::Kind(expected))) if actual == expected => {} + (_, Some(specified @ Disambiguator::Kind(_) | specified @ Disambiguator::Primitive)) => { + report_mismatch(specified, Disambiguator::Kind(kind)); + return; + } + } + } + + // item can be non-local e.g. when using #[doc(primitive = "pointer")] + if let Some((src_id, dst_id)) = res + .opt_def_id() + .and_then(|def_id| def_id.as_local()) + .and_then(|dst_id| item.def_id.as_local().map(|src_id| (src_id, dst_id))) + { + use rustc_hir::def_id::LOCAL_CRATE; + + let hir_src = self.cx.tcx.hir().local_def_id_to_hir_id(src_id); + let hir_dst = self.cx.tcx.hir().local_def_id_to_hir_id(dst_id); + + if self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_src) + && !self.cx.tcx.privacy_access_levels(LOCAL_CRATE).is_exported(hir_dst) + { + privacy_error(cx, &item, &path_str, dox, link_range); + } + } + let id = register_res(cx, res); + item.attrs.links.push(ItemLink { link: ori_link, link_text, did: Some(id), fragment }); + } + } + + fn resolve_with_disambiguator( + &self, + disambiguator: Option, + item: &mut Item, + dox: &str, + path_str: &str, + current_item: &Option, + base_node: DefId, + extra_fragment: Option, + ori_link: &str, + link_range: Option>, + ) -> Option<(Res, Option)> { + match disambiguator.map(Disambiguator::ns) { + Some(ns @ (ValueNS | TypeNS)) => { + match self.resolve(path_str, ns, ¤t_item, base_node, &extra_fragment) { + Ok(res) => Some(res), + Err(ErrorKind::Resolve(box mut kind)) => { + // We only looked in one namespace. Try to give a better error if possible. + if kind.full_res().is_none() { + let other_ns = if ns == ValueNS { TypeNS } else { ValueNS }; + // FIXME: really it should be `resolution_failure` that does this, not `resolve_with_disambiguator` + // See https://github.com/rust-lang/rust/pull/76955#discussion_r493953382 for a good approach + for &new_ns in &[other_ns, MacroNS] { + if let Some(res) = self.check_full_res( + new_ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, ns); + break; + } + } + } + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![kind], + ); + // This could just be a normal link or a broken link + // we could potentially check if something is + // "intra-doc-link-like" and warn in that case. + return None; + } + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, &ori_link, dox, link_range, msg); + return None; + } + } + } + None => { + // Try everything! + let mut candidates = PerNS { + macro_ns: self + .macro_resolve(path_str, base_node) + .map(|res| (res, extra_fragment.clone())), + type_ns: match self.resolve( + path_str, + TypeNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => { + debug!("got res in TypeNS: {:?}", res); + Ok(res) + } + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + return None; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), + }, + value_ns: match self.resolve( + path_str, + ValueNS, + ¤t_item, + base_node, + &extra_fragment, + ) { + Ok(res) => Ok(res), + Err(ErrorKind::AnchorFailure(msg)) => { + anchor_failure(self.cx, &item, ori_link, dox, link_range, msg); + return None; + } + Err(ErrorKind::Resolve(box kind)) => Err(kind), + } + .and_then(|(res, fragment)| { + // Constructors are picked up in the type namespace. + match res { + Res::Def(DefKind::Ctor(..), _) | Res::SelfCtor(..) => { + Err(ResolutionFailure::WrongNamespace(res, TypeNS)) + } + _ => match (fragment, extra_fragment) { + (Some(fragment), Some(_)) => { + // Shouldn't happen but who knows? + Ok((res, Some(fragment))) + } + (fragment, None) | (None, fragment) => Ok((res, fragment)), + }, + } + }), + }; + + let len = candidates.iter().filter(|res| res.is_ok()).count(); + + if len == 0 { + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + candidates.into_iter().filter_map(|res| res.err()).collect(), + ); + // this could just be a normal link + return None; + } + + if len == 1 { + Some(candidates.into_iter().filter_map(|res| res.ok()).next().unwrap()) + } else if len == 2 && is_derive_trait_collision(&candidates) { + Some(candidates.type_ns.unwrap()) + } else { + if is_derive_trait_collision(&candidates) { + candidates.macro_ns = Err(ResolutionFailure::Dummy); + } + // If we're reporting an ambiguity, don't mention the namespaces that failed + let candidates = candidates.map(|candidate| candidate.ok().map(|(res, _)| res)); + ambiguity_error( + self.cx, + &item, + path_str, + dox, + link_range, + candidates.present_items().collect(), + ); + return None; + } + } + Some(MacroNS) => { + match self.macro_resolve(path_str, base_node) { + Ok(res) => Some((res, extra_fragment)), + Err(mut kind) => { + // `macro_resolve` only looks in the macro namespace. Try to give a better error if possible. + for &ns in &[TypeNS, ValueNS] { + if let Some(res) = self.check_full_res( + ns, + path_str, + base_node, + ¤t_item, + &extra_fragment, + ) { + kind = ResolutionFailure::WrongNamespace(res, MacroNS); + break; + } + } + resolution_failure( + self, + &item, + path_str, + disambiguator, + dox, + link_range, + smallvec![kind], + ); + return None; + } + } + } + } } } @@ -1005,6 +1265,18 @@ enum Disambiguator { } impl Disambiguator { + /// The text that should be displayed when the path is rendered as HTML. + /// + /// NOTE: `path` is not the original link given by the user, but a name suitable for passing to `resolve`. + fn display_for(&self, path: &str) -> String { + match self { + // FIXME: this will have different output if the user had `m!()` originally. + Self::Kind(DefKind::Macro(MacroKind::Bang)) => format!("{}!", path), + Self::Kind(DefKind::Fn) => format!("{}()", path), + _ => path.to_owned(), + } + } + /// (disambiguator, path_str) fn from_str(link: &str) -> Result<(Self, &str), ()> { use Disambiguator::{Kind, Namespace as NS, Primitive}; @@ -1047,17 +1319,27 @@ impl Disambiguator { } } - fn display_for(self, path_str: &str) -> String { + /// WARNING: panics on `Res::Err` + fn from_res(res: Res) -> Self { + match res { + Res::Def(kind, _) => Disambiguator::Kind(kind), + Res::PrimTy(_) => Disambiguator::Primitive, + _ => Disambiguator::Namespace(res.ns().expect("can't call `from_res` on Res::err")), + } + } + + fn suggestion(self) -> Suggestion { let kind = match self { - Disambiguator::Primitive => return format!("prim@{}", path_str), + Disambiguator::Primitive => return Suggestion::Prefix("prim"), Disambiguator::Kind(kind) => kind, Disambiguator::Namespace(_) => panic!("display_for cannot be used on namespaces"), }; if kind == DefKind::Macro(MacroKind::Bang) { - return format!("{}!", path_str); + return Suggestion::Macro; } else if kind == DefKind::Fn || kind == DefKind::AssocFn { - return format!("{}()", path_str); + return Suggestion::Function; } + let prefix = match kind { DefKind::Struct => "struct", DefKind::Enum => "enum", @@ -1079,7 +1361,8 @@ impl Disambiguator { Namespace::MacroNS => "macro", }, }; - format!("{}@{}", prefix, path_str) + + Suggestion::Prefix(prefix) } fn ns(self) -> Namespace { @@ -1111,6 +1394,31 @@ impl Disambiguator { } } +enum Suggestion { + Prefix(&'static str), + Function, + Macro, +} + +impl Suggestion { + fn descr(&self) -> Cow<'static, str> { + match self { + Self::Prefix(x) => format!("prefix with `{}@`", x).into(), + Self::Function => "add parentheses".into(), + Self::Macro => "add an exclamation mark".into(), + } + } + + fn as_help(&self, path_str: &str) -> String { + // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` + match self { + Self::Prefix(prefix) => format!("{}@{}", prefix, path_str), + Self::Function => format!("{}()", path_str), + Self::Macro => format!("{}!", path_str), + } + } +} + /// Reports a diagnostic for an intra-doc link. /// /// If no link range is provided, or the source span of the link cannot be determined, the span of @@ -1123,10 +1431,11 @@ impl Disambiguator { /// to it. fn report_diagnostic( cx: &DocContext<'_>, + lint: &'static Lint, msg: &str, item: &Item, dox: &str, - link_range: Option>, + link_range: &Option>, decorate: impl FnOnce(&mut DiagnosticBuilder<'_>, Option), ) { let hir_id = match cx.as_local_hir_id(item.def_id) { @@ -1141,7 +1450,7 @@ fn report_diagnostic( let attrs = &item.attrs; let sp = span_of_attrs(attrs).unwrap_or(item.source.span()); - cx.tcx.struct_span_lint_hir(lint::builtin::BROKEN_INTRA_DOC_LINKS, hir_id, sp, |lint| { + cx.tcx.struct_span_lint_hir(lint, hir_id, sp, |lint| { let mut diag = lint.build(msg); let span = link_range @@ -1162,7 +1471,7 @@ fn report_diagnostic( // Print the line containing the `link_range` and manually mark it with '^'s. diag.note(&format!( "the link appears in this line:\n\n{line}\n\ - {indicator: , + collector: &LinkCollector<'_, '_>, item: &Item, path_str: &str, + disambiguator: Option, dox: &str, link_range: Option>, + kinds: SmallVec<[ResolutionFailure<'_>; 3]>, ) { report_diagnostic( - cx, + collector.cx, + BROKEN_INTRA_DOC_LINKS, &format!("unresolved link to `{}`", path_str), item, dox, - link_range, + &link_range, |diag, sp| { - if let Some(sp) = sp { - diag.span_label(sp, "unresolved link"); - } + let item = |res: Res| { + format!( + "the {} `{}`", + res.descr(), + collector.cx.tcx.item_name(res.def_id()).to_string() + ) + }; + let assoc_item_not_allowed = |res: Res| { + let def_id = res.def_id(); + let name = collector.cx.tcx.item_name(def_id); + format!( + "`{}` is {} {}, not a module or type, and cannot have associated items", + name, + res.article(), + res.descr() + ) + }; + // ignore duplicates + let mut variants_seen = SmallVec::<[_; 3]>::new(); + for mut failure in kinds { + let variant = std::mem::discriminant(&failure); + if variants_seen.contains(&variant) { + continue; + } + variants_seen.push(variant); - diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + if let ResolutionFailure::NotResolved { module_id, partial_res, unresolved } = + &mut failure + { + use DefKind::*; + + let module_id = *module_id; + // FIXME(jynelson): this might conflict with my `Self` fix in #76467 + // FIXME: maybe use itertools `collect_tuple` instead? + fn split(path: &str) -> Option<(&str, &str)> { + let mut splitter = path.rsplitn(2, "::"); + splitter.next().and_then(|right| splitter.next().map(|left| (left, right))) + } + + // Check if _any_ parent of the path gets resolved. + // If so, report it and say the first which failed; if not, say the first path segment didn't resolve. + let mut name = path_str; + 'outer: loop { + let (start, end) = if let Some(x) = split(name) { + x + } else { + // avoid bug that marked [Quux::Z] as missing Z, not Quux + if partial_res.is_none() { + *unresolved = name.into(); + } + break; + }; + name = start; + for &ns in &[TypeNS, ValueNS, MacroNS] { + if let Some(res) = + collector.check_full_res(ns, &start, module_id, &None, &None) + { + debug!("found partial_res={:?}", res); + *partial_res = Some(res); + *unresolved = end.into(); + break 'outer; + } + } + *unresolved = end.into(); + } + + let last_found_module = match *partial_res { + Some(Res::Def(DefKind::Mod, id)) => Some(id), + None => Some(module_id), + _ => None, + }; + // See if this was a module: `[path]` or `[std::io::nope]` + if let Some(module) = last_found_module { + let module_name = collector.cx.tcx.item_name(module); + let note = format!( + "the module `{}` contains no item named `{}`", + module_name, unresolved + ); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + // If the link has `::` in it, assume it was meant to be an intra-doc link. + // Otherwise, the `[]` might be unrelated. + // FIXME: don't show this for autolinks (`<>`), `()` style links, or reference links + if !path_str.contains("::") { + diag.help(r#"to escape `[` and `]` characters, add '\' before them like `\[` or `\]`"#); + } + continue; + } + + // Otherwise, it must be an associated item or variant + let res = partial_res.expect("None case was handled by `last_found_module`"); + let diagnostic_name; + let (kind, name) = match res { + Res::Def(kind, def_id) => { + diagnostic_name = collector.cx.tcx.item_name(def_id).as_str(); + (Some(kind), &*diagnostic_name) + } + Res::PrimTy(ty) => (None, ty.name_str()), + _ => unreachable!("only ADTs and primitives are in scope at module level"), + }; + let path_description = if let Some(kind) = kind { + match kind { + Mod | ForeignMod => "inner item", + Struct => "field or associated item", + Enum | Union => "variant or associated item", + Variant + | Field + | Closure + | Generator + | AssocTy + | AssocConst + | AssocFn + | Fn + | Macro(_) + | Const + | ConstParam + | ExternCrate + | Use + | LifetimeParam + | Ctor(_, _) + | AnonConst => { + let note = assoc_item_not_allowed(res); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + return; + } + Trait | TyAlias | ForeignTy | OpaqueTy | TraitAlias | TyParam + | Static => "associated item", + Impl | GlobalAsm => unreachable!("not a path"), + } + } else { + "associated item" + }; + let note = format!( + "the {} `{}` has no {} named `{}`", + res.descr(), + name, + disambiguator.map_or(path_description, |d| d.descr()), + unresolved, + ); + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + + continue; + } + let note = match failure { + ResolutionFailure::NotResolved { .. } => unreachable!("handled above"), + ResolutionFailure::Dummy => continue, + ResolutionFailure::WrongNamespace(res, expected_ns) => { + if let Res::Def(kind, _) = res { + let disambiguator = Disambiguator::Kind(kind); + suggest_disambiguator( + disambiguator, + diag, + path_str, + dox, + sp, + &link_range, + ) + } + + format!( + "this link resolves to {}, which is not in the {} namespace", + item(res), + expected_ns.descr() + ) + } + ResolutionFailure::NoParentItem => { + diag.level = rustc_errors::Level::Bug; + "all intra doc links should have a parent item".to_owned() + } + }; + if let Some(span) = sp { + diag.span_label(span, ¬e); + } else { + diag.note(¬e); + } + } }, ); } @@ -1210,31 +1704,14 @@ fn anchor_failure( ) { let msg = match failure { AnchorFailure::MultipleAnchors => format!("`{}` contains multiple anchors", path_str), - AnchorFailure::Primitive - | AnchorFailure::Variant - | AnchorFailure::AssocConstant - | AnchorFailure::AssocType - | AnchorFailure::Field - | AnchorFailure::Method => { - let kind = match failure { - AnchorFailure::Primitive => "primitive type", - AnchorFailure::Variant => "enum variant", - AnchorFailure::AssocConstant => "associated constant", - AnchorFailure::AssocType => "associated type", - AnchorFailure::Field => "struct field", - AnchorFailure::Method => "method", - AnchorFailure::MultipleAnchors => unreachable!("should be handled already"), - }; - - format!( - "`{}` contains an anchor, but links to {kind}s are already anchored", - path_str, - kind = kind - ) - } + AnchorFailure::RustdocAnchorConflict(res) => format!( + "`{}` contains an anchor, but links to {kind}s are already anchored", + path_str, + kind = res.descr(), + ), }; - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "contains invalid anchor"); } @@ -1247,12 +1724,12 @@ fn ambiguity_error( path_str: &str, dox: &str, link_range: Option>, - candidates: Vec<(Res, Namespace)>, + candidates: Vec, ) { let mut msg = format!("`{}` is ", path_str); match candidates.as_slice() { - [(first_def, _), (second_def, _)] => { + [first_def, second_def] => { msg += &format!( "both {} {} and {} {}", first_def.article(), @@ -1263,7 +1740,7 @@ fn ambiguity_error( } _ => { let mut candidates = candidates.iter().peekable(); - while let Some((res, _)) = candidates.next() { + while let Some(res) = candidates.next() { if candidates.peek().is_some() { msg += &format!("{} {}, ", res.article(), res.descr()); } else { @@ -1273,57 +1750,45 @@ fn ambiguity_error( } } - report_diagnostic(cx, &msg, item, dox, link_range.clone(), |diag, sp| { + report_diagnostic(cx, BROKEN_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "ambiguous link"); + } else { + diag.note("ambiguous link"); + } - let link_range = link_range.expect("must have a link range if we have a span"); - - for (res, ns) in candidates { - let (action, mut suggestion) = match res { - Res::Def(DefKind::AssocFn | DefKind::Fn, _) => { - ("add parentheses", format!("{}()", path_str)) - } - Res::Def(DefKind::Macro(MacroKind::Bang), _) => { - ("add an exclamation mark", format!("{}!", path_str)) - } - _ => { - let type_ = match (res, ns) { - (Res::PrimTy(_), _) => "prim", - (Res::Def(DefKind::Const, _), _) => "const", - (Res::Def(DefKind::Static, _), _) => "static", - (Res::Def(DefKind::Struct, _), _) => "struct", - (Res::Def(DefKind::Enum, _), _) => "enum", - (Res::Def(DefKind::Union, _), _) => "union", - (Res::Def(DefKind::Trait, _), _) => "trait", - (Res::Def(DefKind::Mod, _), _) => "module", - (_, TypeNS) => "type", - (_, ValueNS) => "value", - (Res::Def(DefKind::Macro(MacroKind::Derive), _), MacroNS) => "derive", - (_, MacroNS) => "macro", - }; - - // FIXME: if this is an implied shortcut link, it's bad style to suggest `@` - ("prefix with the item type", format!("{}@{}", type_, path_str)) - } - }; - - if dox.bytes().nth(link_range.start) == Some(b'`') { - suggestion = format!("`{}`", suggestion); - } - - // FIXME: Create a version of this suggestion for when we don't have the span. - diag.span_suggestion( - sp, - &format!("to link to the {}, {}", res.descr(), action), - suggestion, - Applicability::MaybeIncorrect, - ); - } + for res in candidates { + let disambiguator = Disambiguator::from_res(res); + suggest_disambiguator(disambiguator, diag, path_str, dox, sp, &link_range); } }); } +fn suggest_disambiguator( + disambiguator: Disambiguator, + diag: &mut DiagnosticBuilder<'_>, + path_str: &str, + dox: &str, + sp: Option, + link_range: &Option>, +) { + let suggestion = disambiguator.suggestion(); + let help = format!("to link to the {}, {}", disambiguator.descr(), suggestion.descr()); + + if let Some(sp) = sp { + let link_range = link_range.as_ref().expect("must have a link range if we have a span"); + let msg = if dox.bytes().nth(link_range.start) == Some(b'`') { + format!("`{}`", suggestion.as_help(path_str)) + } else { + suggestion.as_help(path_str) + }; + + diag.span_suggestion(sp, &help, msg, Applicability::MaybeIncorrect); + } else { + diag.help(&format!("{}: {}", help, suggestion.as_help(path_str))); + } +} + fn privacy_error( cx: &DocContext<'_>, item: &Item, @@ -1335,7 +1800,7 @@ fn privacy_error( let msg = format!("public documentation for `{}` links to private item `{}`", item_name, path_str); - report_diagnostic(cx, &msg, item, dox, link_range, |diag, sp| { + report_diagnostic(cx, PRIVATE_INTRA_DOC_LINKS, &msg, item, dox, &link_range, |diag, sp| { if let Some(sp) = sp { diag.span_label(sp, "this item is private"); } @@ -1354,16 +1819,16 @@ fn handle_variant( cx: &DocContext<'_>, res: Res, extra_fragment: &Option, -) -> Result<(Res, Option), ErrorKind> { +) -> Result<(Res, Option), ErrorKind<'static>> { use rustc_middle::ty::DefIdTree; if extra_fragment.is_some() { - return Err(ErrorKind::AnchorFailure(AnchorFailure::Variant)); + return Err(ErrorKind::AnchorFailure(AnchorFailure::RustdocAnchorConflict(res))); } let parent = if let Some(parent) = cx.tcx.parent(res.def_id()) { parent } else { - return Err(ErrorKind::ResolutionFailure); + return Err(ResolutionFailure::NoParentItem.into()); }; let parent_def = Res::Def(DefKind::Enum, parent); let variant = cx.tcx.expect_variant_res(res); diff --git a/src/librustdoc/passes/doc_test_lints.rs b/src/librustdoc/passes/doc_test_lints.rs index 367f93cfd3..78af9f9b85 100644 --- a/src/librustdoc/passes/doc_test_lints.rs +++ b/src/librustdoc/passes/doc_test_lints.rs @@ -8,7 +8,7 @@ use crate::clean; use crate::clean::*; use crate::core::DocContext; use crate::fold::DocFolder; -use crate::html::markdown::{find_testable_code, ErrorCodes, LangString}; +use crate::html::markdown::{find_testable_code, ErrorCodes, Ignore, LangString}; use rustc_session::lint; pub const CHECK_PRIVATE_ITEMS_DOC_TESTS: Pass = Pass { @@ -48,15 +48,11 @@ pub(crate) struct Tests { pub(crate) found_tests: usize, } -impl Tests { - pub(crate) fn new() -> Tests { - Tests { found_tests: 0 } - } -} - -impl crate::test::Tester for Tests { - fn add_test(&mut self, _: String, _: LangString, _: usize) { - self.found_tests += 1; +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; + } } } @@ -85,7 +81,7 @@ pub fn look_for_tests<'tcx>(cx: &DocContext<'tcx>, dox: &str, item: &Item) { } }; - let mut tests = Tests::new(); + let mut tests = Tests { found_tests: 0 }; find_testable_code(&dox, &mut tests, ErrorCodes::No, false, None); diff --git a/src/librustdoc/passes/mod.rs b/src/librustdoc/passes/mod.rs index 0eebdbd87e..75a6596666 100644 --- a/src/librustdoc/passes/mod.rs +++ b/src/librustdoc/passes/mod.rs @@ -284,8 +284,7 @@ impl<'a> DocFolder for ImplStripper<'a> { if let Some(did) = typaram.def_id() { if did.is_local() && !self.retained.contains(&did) { debug!( - "ImplStripper: stripped item in trait's generics; \ - removing impl" + "ImplStripper: stripped item in trait's generics; removing impl" ); return None; } diff --git a/src/librustdoc/passes/strip_private.rs b/src/librustdoc/passes/strip_private.rs index f244956e50..9173d8e960 100644 --- a/src/librustdoc/passes/strip_private.rs +++ b/src/librustdoc/passes/strip_private.rs @@ -9,7 +9,7 @@ pub const STRIP_PRIVATE: Pass = Pass { name: "strip-private", run: strip_private, description: "strips all private items from a crate which cannot be seen externally, \ - implies strip-priv-imports", + implies strip-priv-imports", }; /// Strip private items from the point of view of a crate or externally from a diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index ac9f839600..33578dc061 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -99,7 +99,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, generics, fields: sd.fields(), - whence: item.span, + span: item.span, } } @@ -120,7 +120,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, generics, fields: sd.fields(), - whence: item.span, + span: item.span, } } @@ -142,14 +142,14 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: v.id, attrs: &v.attrs, def: &v.data, - whence: v.span, + span: v.span, }) .collect(), vis: &it.vis, generics, attrs: &it.attrs, id: it.hir_id, - whence: it.span, + span: it.span, } } @@ -208,7 +208,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { kind, helpers, attrs: &item.attrs, - whence: item.span, + span: item.span, }); } None => { @@ -218,7 +218,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, decl, name, - whence: item.span, + span: item.span, generics, header, body, @@ -402,7 +402,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { path: orig_name.map(|x| x.to_string()), vis: &item.vis, attrs: &item.attrs, - whence: item.span, + span: item.span, }) } hir::ItemKind::Use(_, hir::UseKind::ListStem) => {} @@ -444,7 +444,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { attrs: &item.attrs, path, glob: is_glob, - whence: item.span, + span: item.span, }); } hir::ItemKind::Mod(ref m) => { @@ -476,7 +476,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: ident.name, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.typedefs.push(t); @@ -487,7 +487,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { name: ident.name, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.opaque_tys.push(t); @@ -500,7 +500,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: item.hir_id, name: ident.name, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.statics.push(s); @@ -515,7 +515,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { id: item.hir_id, name: ident.name, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.constants.push(s); @@ -532,7 +532,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { bounds, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.traits.push(t); @@ -544,7 +544,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { bounds, id: item.hir_id, attrs: &item.attrs, - whence: item.span, + span: item.span, vis: &item.vis, }; om.trait_aliases.push(t); @@ -577,7 +577,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { items, attrs: &item.attrs, id: item.hir_id, - whence: item.span, + span: item.span, vis: &item.vis, }; om.impls.push(i); @@ -603,7 +603,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { kind: &item.kind, vis: &item.vis, attrs: &item.attrs, - whence: item.span, + span: item.span, }); } @@ -623,7 +623,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { def_id: self.cx.tcx.hir().local_def_id(def.hir_id).to_def_id(), attrs: &def.attrs, name: renamed.unwrap_or(def.ident.name), - whence: def.span, + span: def.span, matchers, imported_from: None, } diff --git a/src/stage0.txt b/src/stage0.txt index 67c19a3380..2f34956479 100644 --- a/src/stage0.txt +++ b/src/stage0.txt @@ -12,15 +12,15 @@ # source tarball for a stable release you'll likely see `1.x.0` for rustc and # `0.(x+1).0` for Cargo where they were released on `date`. -date: 2020-08-27 -rustc: 1.46.0 -cargo: 0.47.0 +date: 2020-10-08 +rustc: 1.47.0 +cargo: 0.48.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-2020-07-12 +# rustfmt: nightly-2020-07-12 # When making a stable release the process currently looks like: # diff --git a/src/test/assembly/asm/aarch64-types.rs b/src/test/assembly/asm/aarch64-types.rs index e39f74c916..8dd1f3c873 100644 --- a/src/test/assembly/asm/aarch64-types.rs +++ b/src/test/assembly/asm/aarch64-types.rs @@ -96,6 +96,17 @@ pub unsafe fn sym_static() { asm!("adr x0, {}", sym extern_static); } +// Regression test for #75761 +// CHECK-LABEL: issue_75761: +// CHECK: str {{.*}}x30 +// CHECK: //APP +// CHECK: //NO_APP +// CHECK: ldr {{.*}}x30 +#[no_mangle] +pub unsafe fn issue_75761() { + asm!("", out("v0") _, out("x30") _); +} + macro_rules! check { ($func:ident $ty:ident $class:ident $mov:literal $modifier:literal) => { #[no_mangle] @@ -553,8 +564,3 @@ check_reg!(v0_f32x4 f32x4 "s0" "fmov"); // CHECK: fmov s0, s0 // CHECK: //NO_APP check_reg!(v0_f64x2 f64x2 "s0" "fmov"); - -// Regression test for #75761 -pub unsafe fn issue_75761() { - asm!("", out("v0") _, out("x30") _); -} diff --git a/src/test/assembly/asm/mips-types.rs b/src/test/assembly/asm/mips-types.rs new file mode 100644 index 0000000000..b195ed88c7 --- /dev/null +++ b/src/test/assembly/asm/mips-types.rs @@ -0,0 +1,191 @@ +// no-system-llvm +// assembly-output: emit-asm +// compile-flags: --target mips-unknown-linux-gnu +// needs-llvm-components: mips + +#![feature(no_core, lang_items, rustc_attrs, repr_simd)] +#![crate_type = "rlib"] +#![no_core] +#![allow(asm_sub_register, non_camel_case_types)] + +#[rustc_builtin_macro] +macro_rules! asm { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! concat { + () => {}; +} +#[rustc_builtin_macro] +macro_rules! stringify { + () => {}; +} + +#[lang = "sized"] +trait Sized {} +#[lang = "copy"] +trait Copy {} + +type ptr = *const i32; + +impl Copy for i8 {} +impl Copy for u8 {} +impl Copy for i16 {} +impl Copy for i32 {} +impl Copy for f32 {} +impl Copy for ptr {} +extern "C" { + fn extern_func(); + static extern_static: u8; +} + +// Hack to avoid function merging +extern "Rust" { + fn dont_merge(s: &str); +} + +macro_rules! check { ($func:ident, $ty:ty, $class:ident) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!("move {}, {}", out($class) y, in($class) x); + y + } +};} + +macro_rules! check_reg { ($func:ident, $ty:ty, $reg:tt) => { + #[no_mangle] + pub unsafe fn $func(x: $ty) -> $ty { + dont_merge(stringify!($func)); + + let y; + asm!(concat!("move ", $reg, ", ", $reg), lateout($reg) y, in($reg) x); + y + } +};} + +// CHECK-LABEL: sym_static: +// CHECK: #APP +// CHECK: lw $3, %got(extern_static) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_static() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_static); +} + +// CHECK-LABEL: sym_fn: +// CHECK: #APP +// CHECK: lw $3, %got(extern_func) +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn sym_fn() { + dont_merge(stringify!($func)); + + asm!("la $v1, {}", sym extern_func); +} + +// CHECK-LABEL: reg_f32: +// CHECK: #APP +// CHECK: mov.s $f{{[0-9]+}}, $f{{[0-9]+}} +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn reg_f32(x: f32) -> f32 { + dont_merge("reg_f32"); + let y; + asm!("mov.s {}, {}", out(freg) y, in(freg) x); + y +} + +// CHECK-LABEL: f0_f32: +// CHECK: #APP +// CHECK: mov.s $f0, $f0 +// CHECK: #NO_APP +#[no_mangle] +pub unsafe fn f0_f32(x: f32) -> f32 { + dont_merge("f0_f32"); + let y; + asm!("mov.s $f0, $f0", lateout("$f0") y, in("$f0") x); + y +} + +// CHECK-LABEL: reg_ptr: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_ptr, ptr, reg); + +// CHECK-LABEL: reg_i32: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i32, i32, reg); + +// CHECK-LABEL: reg_f32_soft: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_f32_soft, f32, reg); + +// CHECK-LABEL: reg_i8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i8, i8, reg); + +// CHECK-LABEL: reg_u8: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_u8, u8, reg); + +// CHECK-LABEL: reg_i16: +// CHECK: #APP +// CHECK: move ${{[0-9]+}}, ${{[0-9]+}} +// CHECK: #NO_APP +check!(reg_i16, i16, reg); + +// CHECK-LABEL: t0_ptr: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_ptr, ptr, "$t0"); + +// CHECK-LABEL: t0_i32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i32, i32, "$t0"); + +// CHECK-LABEL: t0_f32: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_f32, f32, "$t0"); + +// CHECK-LABEL: t0_i8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i8, i8, "$t0"); + +// CHECK-LABEL: t0_u8: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_u8, u8, "$t0"); + +// CHECK-LABEL: t0_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(t0_i16, i16, "$t0"); + +// CHECK-LABEL: r8_i16: +// CHECK: #APP +// CHECK: move $8, $8 +// CHECK: #NO_APP +check_reg!(r8_i16, i16, "$8"); diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs new file mode 100644 index 0000000000..79d82cf70d --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-load.rs @@ -0,0 +1,17 @@ +// Test LVI load hardening on SGX enclave code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn plus_one(r: &mut u64) { + *r = *r + 1; +} + +// CHECK: plus_one +// CHECK: lfence +// CHECK-NEXT: addq +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs new file mode 100644 index 0000000000..a21ef6b758 --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-generic-ret.rs @@ -0,0 +1,12 @@ +// Test LVI ret hardening on generic rust code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#[no_mangle] +pub extern fn myret() {} +// CHECK: myret: +// CHECK: popq [[REGISTER:%[a-z]+]] +// CHECK-NEXT: lfence +// CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs new file mode 100644 index 0000000000..7e440169ed --- /dev/null +++ b/src/test/assembly/x86_64-fortanix-unknown-sgx-lvi-inline-assembly.rs @@ -0,0 +1,41 @@ +// Test LVI load hardening on SGX inline assembly code + +// assembly-output: emit-asm +// compile-flags: --crate-type staticlib +// only-x86_64-fortanix-unknown-sgx + +#![feature(asm)] + +#[no_mangle] +pub extern fn get(ptr: *const u64) -> u64 { + let value : u64; + unsafe { + asm!(".start_inline_asm:", + "mov {}, [{}]", + ".end_inline_asm:", + out(reg) value, + in(reg) ptr); + } + value +} + +// CHECK: get +// CHECK: .start_inline_asm +// CHECK-NEXT: movq +// CHECK-NEXT: lfence +// CHECK-NEXT: .end_inline_asm + +#[no_mangle] +pub extern fn myret() { + unsafe { + asm!(".start_myret_inline_asm: + ret + .end_myret_inline_asm:"); + } +} + +// CHECK: myret +// CHECK: .start_myret_inline_asm +// CHECK-NEXT: shlq $0, (%rsp) +// CHECK-NEXT: lfence +// CHECK-NEXT: retq diff --git a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs index e1991046d4..7289ceee95 100644 --- a/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs +++ b/src/test/codegen-units/item-collection/cross-crate-generic-functions.rs @@ -6,15 +6,15 @@ // aux-build:cgu_generic_function.rs extern crate cgu_generic_function; -//~ MONO_ITEM fn cross_crate_generic_functions::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn cgu_generic_function::bar[0] - //~ MONO_ITEM fn cgu_generic_function::foo[0] + //~ MONO_ITEM fn cgu_generic_function::bar:: + //~ MONO_ITEM fn cgu_generic_function::foo:: let _ = cgu_generic_function::foo(1u32); - //~ MONO_ITEM fn cgu_generic_function::bar[0] - //~ MONO_ITEM fn cgu_generic_function::foo[0] + //~ MONO_ITEM fn cgu_generic_function::bar:: + //~ MONO_ITEM fn cgu_generic_function::foo:: let _ = cgu_generic_function::foo(2u64); // This should not introduce a codegen item diff --git a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs index 442438b64b..dc0984c8a9 100644 --- a/src/test/codegen-units/item-collection/cross-crate-trait-method.rs +++ b/src/test/codegen-units/item-collection/cross-crate-trait-method.rs @@ -8,7 +8,7 @@ extern crate cgu_export_trait_method; use cgu_export_trait_method::Trait; -//~ MONO_ITEM fn cross_crate_trait_method::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { // The object code of these methods is contained in the external crate, so @@ -19,31 +19,31 @@ fn start(_: isize, _: *const *const u8) -> isize { // Currently, no object code is generated for trait methods with default // implementations, unless they are actually called from somewhere. Therefore // we cannot import the implementations and have to create our own inline. - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] + //~ MONO_ITEM fn ::with_default_impl let _ = Trait::with_default_impl(0u32); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl[0] + //~ MONO_ITEM fn ::with_default_impl let _ = Trait::with_default_impl('c'); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic::<&str> let _ = Trait::with_default_impl_generic(0u32, "abc"); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic:: let _ = Trait::with_default_impl_generic(0u32, false); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic:: let _ = Trait::with_default_impl_generic('x', 1i16); - //~ MONO_ITEM fn cgu_export_trait_method::Trait[0]::with_default_impl_generic[0] + //~ MONO_ITEM fn ::with_default_impl_generic:: let _ = Trait::with_default_impl_generic('y', 0i32); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (u32, char) = Trait::without_default_impl_generic('c'); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[1]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (u32, bool) = Trait::without_default_impl_generic(false); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (char, char) = Trait::without_default_impl_generic('c'); - //~ MONO_ITEM fn cgu_export_trait_method::{{impl}}[0]::without_default_impl_generic[0] + //~ MONO_ITEM fn ::without_default_impl_generic:: let _: (char, bool) = Trait::without_default_impl_generic(false); 0 diff --git a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs index 27fb3cb138..adde5745fe 100644 --- a/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs +++ b/src/test/codegen-units/item-collection/drop_in_place_intrinsic.rs @@ -4,19 +4,19 @@ #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ drop_in_place_intrinsic-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(StructWithDtor)) @@ drop_in_place_intrinsic-cgu.0[Internal] struct StructWithDtor(u32); impl Drop for StructWithDtor { - //~ MONO_ITEM fn drop_in_place_intrinsic::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } -//~ MONO_ITEM fn drop_in_place_intrinsic::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]; 2]> @@ drop_in_place_intrinsic-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<[StructWithDtor; 2]> - shim(Some([StructWithDtor; 2])) @@ drop_in_place_intrinsic-cgu.0[Internal] let x = [StructWithDtor(0), StructWithDtor(1)]; drop_slice_in_place(&x); @@ -24,13 +24,13 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ MONO_ITEM fn drop_in_place_intrinsic::drop_slice_in_place[0] +//~ MONO_ITEM fn drop_slice_in_place fn drop_slice_in_place(x: &[StructWithDtor]) { unsafe { // This is the interesting thing in this test case: Normally we would // not have drop-glue for the unsized [StructWithDtor]. This has to be // generated though when the drop_in_place() intrinsic is used. - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<[drop_in_place_intrinsic::StructWithDtor[0]]> @@ drop_in_place_intrinsic-cgu.0[Internal] - ::std::ptr::drop_in_place(x as *const _ as *mut [StructWithDtor]); + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<[StructWithDtor]> - shim(Some([StructWithDtor])) @@ drop_in_place_intrinsic-cgu.0[Internal] + ::std::intrinsics::drop_in_place(x as *const _ as *mut [StructWithDtor]); } } diff --git a/src/test/codegen-units/item-collection/function-as-argument.rs b/src/test/codegen-units/item-collection/function-as-argument.rs index 3f61f124d2..2329dec385 100644 --- a/src/test/codegen-units/item-collection/function-as-argument.rs +++ b/src/test/codegen-units/item-collection/function-as-argument.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] @@ -13,26 +14,26 @@ fn take_fn_pointer(f: fn(T1, T2), x: T1, y: T2) { (f)(x, y) } -//~ MONO_ITEM fn function_as_argument::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn function_as_argument::take_fn_once[0] - //~ MONO_ITEM fn function_as_argument::function[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] + //~ MONO_ITEM fn take_fn_once::}> + //~ MONO_ITEM fn function:: + //~ MONO_ITEM fn } as std::ops::FnOnce<(u32, &str)>>::call_once - shim(fn(u32, &str) {function::}) take_fn_once(function, 0u32, "abc"); - //~ MONO_ITEM fn function_as_argument::take_fn_once[0] - //~ MONO_ITEM fn function_as_argument::function[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] + //~ MONO_ITEM fn take_fn_once::}> + //~ MONO_ITEM fn function:: + //~ MONO_ITEM fn } as std::ops::FnOnce<(char, f64)>>::call_once - shim(fn(char, f64) {function::}) take_fn_once(function, 'c', 0f64); - //~ MONO_ITEM fn function_as_argument::take_fn_pointer[0] - //~ MONO_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn take_fn_pointer:: + //~ MONO_ITEM fn function:: take_fn_pointer(function, 0i32, ()); - //~ MONO_ITEM fn function_as_argument::take_fn_pointer[0] - //~ MONO_ITEM fn function_as_argument::function[0] + //~ MONO_ITEM fn take_fn_pointer:: + //~ MONO_ITEM fn function:: take_fn_pointer(function, 0f32, 0i64); 0 diff --git a/src/test/codegen-units/item-collection/generic-drop-glue.rs b/src/test/codegen-units/item-collection/generic-drop-glue.rs index 675bdfdb4d..45e4a0d6d7 100644 --- a/src/test/codegen-units/item-collection/generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/generic-drop-glue.rs @@ -37,22 +37,22 @@ enum EnumNoDrop { struct NonGenericNoDrop(i32); struct NonGenericWithDrop(i32); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ generic_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(NonGenericWithDrop)) @@ generic_drop_glue-cgu.0[Internal] impl Drop for NonGenericWithDrop { - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[2]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } -//~ MONO_ITEM fn generic_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(StructWithDrop)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = StructWithDrop { x: 0i8, y: 'a' }.x; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[0]::drop[0]<&str, generic_drop_glue::NonGenericNoDrop[0]> + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(StructWithDrop<&str, NonGenericNoDrop>)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = StructWithDrop { x: "&str", y: NonGenericNoDrop(0) }.y; // Should produce no drop glue @@ -60,18 +60,18 @@ fn start(_: isize, _: *const *const u8) -> isize { // This is supposed to generate drop-glue because it contains a field that // needs to be dropped. - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(StructNoDrop)) @@ generic_drop_glue-cgu.0[Internal] let _ = StructNoDrop { x: NonGenericWithDrop(0), y: 0f64 }.y; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(EnumWithDrop)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = match EnumWithDrop::A::(0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as i32 }; - //~MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ generic_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(EnumWithDrop)) @@ generic_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = match EnumWithDrop::B::(1.0) { EnumWithDrop::A(x) => x, EnumWithDrop::B(x) => x as f64 diff --git a/src/test/codegen-units/item-collection/generic-functions.rs b/src/test/codegen-units/item-collection/generic-functions.rs index 8390970420..04383bb8ed 100644 --- a/src/test/codegen-units/item-collection/generic-functions.rs +++ b/src/test/codegen-units/item-collection/generic-functions.rs @@ -16,39 +16,39 @@ fn foo3(a: T1, b: T2, c: T3) -> (T1, T2, T3) { } // This function should be instantiated even if no used -//~ MONO_ITEM fn generic_functions::lifetime_only[0] +//~ MONO_ITEM fn lifetime_only pub fn lifetime_only<'a>(a: &'a u32) -> &'a u32 { a } -//~ MONO_ITEM fn generic_functions::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn foo1:: let _ = foo1(2i32); - //~ MONO_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn foo1:: let _ = foo1(2i64); - //~ MONO_ITEM fn generic_functions::foo1[0]<&str> + //~ MONO_ITEM fn foo1::<&str> let _ = foo1("abc"); - //~ MONO_ITEM fn generic_functions::foo1[0] + //~ MONO_ITEM fn foo1:: let _ = foo1('v'); - //~ MONO_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn foo2:: let _ = foo2(2i32, 2i32); - //~ MONO_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn foo2:: let _ = foo2(2i64, "abc"); - //~ MONO_ITEM fn generic_functions::foo2[0]<&str, usize> + //~ MONO_ITEM fn foo2::<&str, usize> let _ = foo2("a", 2usize); - //~ MONO_ITEM fn generic_functions::foo2[0] + //~ MONO_ITEM fn foo2:: let _ = foo2('v', ()); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3(2i32, 2i32, 2i32); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3(2i64, "abc", 'c'); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3(0i16, "a", 2usize); - //~ MONO_ITEM fn generic_functions::foo3[0] + //~ MONO_ITEM fn foo3:: let _ = foo3('v', (), ()); 0 diff --git a/src/test/codegen-units/item-collection/generic-impl.rs b/src/test/codegen-units/item-collection/generic-impl.rs index 571bb4fa86..dd5367ef03 100644 --- a/src/test/codegen-units/item-collection/generic-impl.rs +++ b/src/test/codegen-units/item-collection/generic-impl.rs @@ -30,41 +30,41 @@ pub struct LifeTimeOnly<'a> { impl<'a> LifeTimeOnly<'a> { - //~ MONO_ITEM fn generic_impl::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn LifeTimeOnly::foo pub fn foo(&self) {} - //~ MONO_ITEM fn generic_impl::{{impl}}[1]::bar[0] + //~ MONO_ITEM fn LifeTimeOnly::bar pub fn bar(&'a self) {} - //~ MONO_ITEM fn generic_impl::{{impl}}[1]::baz[0] + //~ MONO_ITEM fn LifeTimeOnly::baz pub fn baz<'b>(&'b self) {} pub fn non_instantiated(&self) {} } -//~ MONO_ITEM fn generic_impl::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ MONO_ITEM fn generic_impl::id[0] - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn Struct::::new + //~ MONO_ITEM fn id:: + //~ MONO_ITEM fn Struct::::get:: let _ = Struct::new(0i32).get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ MONO_ITEM fn generic_impl::id[0] - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn Struct::::new + //~ MONO_ITEM fn id:: + //~ MONO_ITEM fn Struct::::get:: let _ = Struct::new(0i64).get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0] - //~ MONO_ITEM fn generic_impl::id[0] - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0] + //~ MONO_ITEM fn Struct::::new + //~ MONO_ITEM fn id:: + //~ MONO_ITEM fn Struct::::get:: let _ = Struct::new('c').get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0]<&str> - //~ MONO_ITEM fn generic_impl::id[0]<&str> - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::get[0], i16> + //~ MONO_ITEM fn Struct::<&str>::new + //~ MONO_ITEM fn id::<&str> + //~ MONO_ITEM fn Struct::>::get:: let _ = Struct::new(Struct::new("str")).get(0i16); - //~ MONO_ITEM fn generic_impl::{{impl}}[0]::new[0]> - //~ MONO_ITEM fn generic_impl::id[0]> + //~ MONO_ITEM fn Struct::>::new + //~ MONO_ITEM fn id::> let _ = (Struct::new(Struct::new("str")).f)(Struct::new("str")); 0 diff --git a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs index e45644cd37..c01398eb23 100644 --- a/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs +++ b/src/test/codegen-units/item-collection/impl-in-non-instantiated-generic.rs @@ -11,14 +11,14 @@ trait SomeTrait { // discovered. pub fn generic_function(x: T) -> (T, i32) { impl SomeTrait for i64 { - //~ MONO_ITEM fn impl_in_non_instantiated_generic::generic_function[0]::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn generic_function::::foo fn foo(&self) {} } (x, 0) } -//~ MONO_ITEM fn impl_in_non_instantiated_generic::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { 0i64.foo(); diff --git a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs index db0390b58c..63966a7ec9 100644 --- a/src/test/codegen-units/item-collection/instantiation-through-vtable.rs +++ b/src/test/codegen-units/item-collection/instantiation-through-vtable.rs @@ -19,20 +19,20 @@ impl Trait for Struct { fn bar(&self) {} } -//~ MONO_ITEM fn instantiation_through_vtable::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { let s1 = Struct { _a: 0u32 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable-cgu.0[Internal] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] + //~ MONO_ITEM fn as Trait>::foo + //~ MONO_ITEM fn as Trait>::bar let _ = &s1 as &Trait; let s1 = Struct { _a: 0u64 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ instantiation_through_vtable-cgu.0[Internal] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::foo[0] - //~ MONO_ITEM fn instantiation_through_vtable::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(None) @@ instantiation_through_vtable-cgu.0[Internal] + //~ MONO_ITEM fn as Trait>::foo + //~ MONO_ITEM fn as Trait>::bar let _ = &s1 as &Trait; 0 diff --git a/src/test/codegen-units/item-collection/items-within-generic-items.rs b/src/test/codegen-units/item-collection/items-within-generic-items.rs index 10bc52f6a8..d37d7f7d9b 100644 --- a/src/test/codegen-units/item-collection/items-within-generic-items.rs +++ b/src/test/codegen-units/item-collection/items-within-generic-items.rs @@ -4,13 +4,13 @@ #![feature(start)] fn generic_fn(a: T) -> (T, i32) { - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[0] + //~ MONO_ITEM fn generic_fn::nested_fn fn nested_fn(a: i32) -> i32 { a + 1 } let x = { - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0]::nested_fn[1] + //~ MONO_ITEM fn generic_fn::nested_fn fn nested_fn(a: i32) -> i32 { a + 2 } @@ -21,14 +21,14 @@ fn generic_fn(a: T) -> (T, i32) { return (a, x + nested_fn(0)); } -//~ MONO_ITEM fn items_within_generic_items::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn generic_fn:: let _ = generic_fn(0i64); - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn generic_fn:: let _ = generic_fn(0u16); - //~ MONO_ITEM fn items_within_generic_items::generic_fn[0] + //~ MONO_ITEM fn generic_fn:: let _ = generic_fn(0i8); 0 diff --git a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs index a899b8b2c8..b583771681 100644 --- a/src/test/codegen-units/item-collection/non-generic-drop-glue.rs +++ b/src/test/codegen-units/item-collection/non-generic-drop-glue.rs @@ -5,13 +5,13 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(StructWithDrop)) @@ non_generic_drop_glue-cgu.0[Internal] struct StructWithDrop { x: i32 } impl Drop for StructWithDrop { - //~ MONO_ITEM fn non_generic_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } @@ -19,13 +19,13 @@ struct StructNoDrop { x: i32 } -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ non_generic_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(EnumWithDrop)) @@ non_generic_drop_glue-cgu.0[Internal] enum EnumWithDrop { A(i32) } impl Drop for EnumWithDrop { - //~ MONO_ITEM fn non_generic_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } @@ -33,7 +33,7 @@ enum EnumNoDrop { A(i32) } -//~ MONO_ITEM fn non_generic_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { let _ = StructWithDrop { x: 0 }.x; diff --git a/src/test/codegen-units/item-collection/non-generic-functions.rs b/src/test/codegen-units/item-collection/non-generic-functions.rs index 26d2fb1b42..092e64562c 100644 --- a/src/test/codegen-units/item-collection/non-generic-functions.rs +++ b/src/test/codegen-units/item-collection/non-generic-functions.rs @@ -3,24 +3,24 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn non_generic_functions::foo[0] +//~ MONO_ITEM fn foo fn foo() { { - //~ MONO_ITEM fn non_generic_functions::foo[0]::foo[0] + //~ MONO_ITEM fn foo::foo fn foo() {} foo(); } { - //~ MONO_ITEM fn non_generic_functions::foo[0]::foo[1] + //~ MONO_ITEM fn foo::foo fn foo() {} foo(); } } -//~ MONO_ITEM fn non_generic_functions::bar[0] +//~ MONO_ITEM fn bar fn bar() { - //~ MONO_ITEM fn non_generic_functions::bar[0]::baz[0] + //~ MONO_ITEM fn bar::baz fn baz() {} baz(); } @@ -28,38 +28,38 @@ fn bar() { struct Struct { _x: i32 } impl Struct { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn Struct::foo fn foo() { { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[0] + //~ MONO_ITEM fn Struct::foo::foo fn foo() {} foo(); } { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::foo[0]::foo[1] + //~ MONO_ITEM fn Struct::foo::foo fn foo() {} foo(); } } - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0] + //~ MONO_ITEM fn Struct::bar fn bar(&self) { { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[0] + //~ MONO_ITEM fn Struct::bar::foo fn foo() {} foo(); } { - //~ MONO_ITEM fn non_generic_functions::{{impl}}[0]::bar[0]::foo[1] + //~ MONO_ITEM fn Struct::bar::foo fn foo() {} foo(); } } } -//~ MONO_ITEM fn non_generic_functions::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { foo(); diff --git a/src/test/codegen-units/item-collection/overloaded-operators.rs b/src/test/codegen-units/item-collection/overloaded-operators.rs index 0b4c97723d..2be7eba1d8 100644 --- a/src/test/codegen-units/item-collection/overloaded-operators.rs +++ b/src/test/codegen-units/item-collection/overloaded-operators.rs @@ -12,7 +12,7 @@ pub struct Indexable { impl Index for Indexable { type Output = u8; - //~ MONO_ITEM fn overloaded_operators::{{impl}}[0]::index[0] + //~ MONO_ITEM fn >::index fn index(&self, index: usize) -> &Self::Output { if index >= 3 { &self.data[0] @@ -23,7 +23,7 @@ impl Index for Indexable { } impl IndexMut for Indexable { - //~ MONO_ITEM fn overloaded_operators::{{impl}}[1]::index_mut[0] + //~ MONO_ITEM fn >::index_mut fn index_mut(&mut self, index: usize) -> &mut Self::Output { if index >= 3 { &mut self.data[0] @@ -34,8 +34,8 @@ impl IndexMut for Indexable { } -//~ MONO_ITEM fn overloaded_operators::{{impl}}[5]::eq[0] -//~ MONO_ITEM fn overloaded_operators::{{impl}}[5]::ne[0] +//~ MONO_ITEM fn ::eq +//~ MONO_ITEM fn ::ne #[derive(PartialEq)] pub struct Equatable(u32); @@ -43,7 +43,7 @@ pub struct Equatable(u32); impl Add for Equatable { type Output = u32; - //~ MONO_ITEM fn overloaded_operators::{{impl}}[2]::add[0] + //~ MONO_ITEM fn >::add fn add(self, rhs: u32) -> u32 { self.0 + rhs } @@ -52,7 +52,7 @@ impl Add for Equatable { impl Deref for Equatable { type Target = u32; - //~ MONO_ITEM fn overloaded_operators::{{impl}}[3]::deref[0] + //~ MONO_ITEM fn ::deref fn deref(&self) -> &Self::Target { &self.0 } diff --git a/src/test/codegen-units/item-collection/static-init.rs b/src/test/codegen-units/item-collection/static-init.rs index 9d79171c4c..287ec8f24e 100644 --- a/src/test/codegen-units/item-collection/static-init.rs +++ b/src/test/codegen-units/item-collection/static-init.rs @@ -6,10 +6,10 @@ pub static FN : fn() = foo::; pub fn foo() { } -//~ MONO_ITEM fn static_init::foo[0] -//~ MONO_ITEM static static_init::FN[0] +//~ MONO_ITEM fn foo:: +//~ MONO_ITEM static FN -//~ MONO_ITEM fn static_init::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { 0 diff --git a/src/test/codegen-units/item-collection/statics-and-consts.rs b/src/test/codegen-units/item-collection/statics-and-consts.rs index 7e28ba58b6..49a8d3dff6 100644 --- a/src/test/codegen-units/item-collection/statics-and-consts.rs +++ b/src/test/codegen-units/item-collection/statics-and-consts.rs @@ -37,7 +37,7 @@ fn foo() { }; } -//~ MONO_ITEM fn statics_and_consts::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { foo(); @@ -46,9 +46,9 @@ fn start(_: isize, _: *const *const u8) -> isize { 0 } -//~ MONO_ITEM static statics_and_consts::STATIC1[0] +//~ MONO_ITEM static STATIC1 -//~ MONO_ITEM fn statics_and_consts::foo[0] -//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[0] -//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[1] -//~ MONO_ITEM static statics_and_consts::foo[0]::STATIC2[2] +//~ MONO_ITEM fn foo +//~ MONO_ITEM static foo::STATIC2 +//~ MONO_ITEM static foo::STATIC2 +//~ MONO_ITEM static foo::STATIC2 diff --git a/src/test/codegen-units/item-collection/trait-implementations.rs b/src/test/codegen-units/item-collection/trait-implementations.rs index f090c0c8d1..a816cb0324 100644 --- a/src/test/codegen-units/item-collection/trait-implementations.rs +++ b/src/test/codegen-units/item-collection/trait-implementations.rs @@ -10,7 +10,7 @@ pub trait SomeTrait { impl SomeTrait for i64 { - //~ MONO_ITEM fn trait_implementations::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn ::foo fn foo(&self) {} fn bar(&self, _: T) {} @@ -18,7 +18,7 @@ impl SomeTrait for i64 { impl SomeTrait for i32 { - //~ MONO_ITEM fn trait_implementations::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn ::foo fn foo(&self) {} fn bar(&self, _: T) {} @@ -32,7 +32,7 @@ pub trait SomeGenericTrait { // Concrete impl of generic trait impl SomeGenericTrait for f64 { - //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::foo[0] + //~ MONO_ITEM fn >::foo fn foo(&self, _: u32) {} fn bar(&self, _: u32, _: T2) {} @@ -45,28 +45,28 @@ impl SomeGenericTrait for f32 { fn bar(&self, _: T, _: T2) {} } -//~ MONO_ITEM fn trait_implementations::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn trait_implementations::{{impl}}[1]::bar[0] + //~ MONO_ITEM fn ::bar:: 0i32.bar('x'); - //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<&str> + //~ MONO_ITEM fn >::bar::<&str> 0f64.bar(0u32, "&str"); - //~ MONO_ITEM fn trait_implementations::{{impl}}[2]::bar[0]<()> + //~ MONO_ITEM fn >::bar::<()> 0f64.bar(0u32, ()); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn >::foo 0f32.foo('x'); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn >::foo 0f32.foo(-1i64); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::bar[0] + //~ MONO_ITEM fn >::bar::<()> 0f32.bar(0u32, ()); - //~ MONO_ITEM fn trait_implementations::{{impl}}[3]::bar[0]<&str, &str> + //~ MONO_ITEM fn >::bar::<&str> 0f32.bar("&str", "&str"); 0 diff --git a/src/test/codegen-units/item-collection/trait-method-as-argument.rs b/src/test/codegen-units/item-collection/trait-method-as-argument.rs index 27ace8e31a..6817b33c61 100644 --- a/src/test/codegen-units/item-collection/trait-method-as-argument.rs +++ b/src/test/codegen-units/item-collection/trait-method-as-argument.rs @@ -1,3 +1,4 @@ +// ignore-tidy-linelength // compile-flags:-Zprint-mono-items=eager #![deny(dead_code)] @@ -26,33 +27,33 @@ fn take_foo_mut T>(mut f: F, arg: T) -> T { (f)(arg) } -//~ MONO_ITEM fn trait_method_as_argument::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn trait_method_as_argument::take_foo_once[0] u32> - //~ MONO_ITEM fn trait_method_as_argument::{{impl}}[0]::foo[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] u32, (u32)> + //~ MONO_ITEM fn take_foo_once:: u32 {::foo}> + //~ MONO_ITEM fn ::foo + //~ MONO_ITEM fn u32 {::foo} as std::ops::FnOnce<(u32,)>>::call_once - shim(fn(u32) -> u32 {::foo}) take_foo_once(Trait::foo, 0u32); - //~ MONO_ITEM fn trait_method_as_argument::take_foo_once[0] char> - //~ MONO_ITEM fn trait_method_as_argument::Trait[0]::foo[0] - //~ MONO_ITEM fn core::ops[0]::function[0]::FnOnce[0]::call_once[0] char, (char)> + //~ MONO_ITEM fn take_foo_once:: char {::foo}> + //~ MONO_ITEM fn ::foo + //~ MONO_ITEM fn char {::foo} as std::ops::FnOnce<(char,)>>::call_once - shim(fn(char) -> char {::foo}) take_foo_once(Trait::foo, 'c'); - //~ MONO_ITEM fn trait_method_as_argument::take_foo[0] u32> - //~ MONO_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] u32, (u32)> + //~ MONO_ITEM fn take_foo:: u32 {::foo}> + //~ MONO_ITEM fn u32 {::foo} as std::ops::Fn<(u32,)>>::call - shim(fn(u32) -> u32 {::foo}) take_foo(Trait::foo, 0u32); - //~ MONO_ITEM fn trait_method_as_argument::take_foo[0] char> - //~ MONO_ITEM fn core::ops[0]::function[0]::Fn[0]::call[0] char, (char)> + //~ MONO_ITEM fn take_foo:: char {::foo}> + //~ MONO_ITEM fn char {::foo} as std::ops::Fn<(char,)>>::call - shim(fn(char) -> char {::foo}) take_foo(Trait::foo, 'c'); - //~ MONO_ITEM fn trait_method_as_argument::take_foo_mut[0] u32> - //~ MONO_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] char, (char)> + //~ MONO_ITEM fn take_foo_mut:: u32 {::foo}> + //~ MONO_ITEM fn u32 {::foo} as std::ops::FnMut<(u32,)>>::call_mut - shim(fn(u32) -> u32 {::foo}) take_foo_mut(Trait::foo, 0u32); - //~ MONO_ITEM fn trait_method_as_argument::take_foo_mut[0] char> - //~ MONO_ITEM fn core::ops[0]::function[0]::FnMut[0]::call_mut[0] u32, (u32)> + //~ MONO_ITEM fn take_foo_mut:: char {::foo}> + //~ MONO_ITEM fn char {::foo} as std::ops::FnMut<(char,)>>::call_mut - shim(fn(char) -> char {::foo}) take_foo_mut(Trait::foo, 'c'); 0 diff --git a/src/test/codegen-units/item-collection/trait-method-default-impl.rs b/src/test/codegen-units/item-collection/trait-method-default-impl.rs index 6cf59fdc39..bfcdb6fa14 100644 --- a/src/test/codegen-units/item-collection/trait-method-default-impl.rs +++ b/src/test/codegen-units/item-collection/trait-method-default-impl.rs @@ -13,7 +13,7 @@ impl SomeTrait for i8 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::foo[0] + //~ MONO_ITEM fn ::foo } trait SomeGenericTrait { @@ -27,7 +27,7 @@ impl SomeGenericTrait for i32 { // For the non-generic foo(), we should generate a codegen-item even if it // is not called anywhere - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::foo[0] + //~ MONO_ITEM fn >::foo } // Non-generic impl of generic trait @@ -36,25 +36,25 @@ impl SomeGenericTrait for u32 { // since nothing is monomorphic here, nothing should be generated unless used somewhere. } -//~ MONO_ITEM fn trait_method_default_impl::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] + //~ MONO_ITEM fn ::bar:: let _ = 1i8.bar('c'); - //~ MONO_ITEM fn trait_method_default_impl::SomeTrait[0]::bar[0] + //~ MONO_ITEM fn ::bar::<&str> let _ = 2i8.bar("&str"); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar:: 0i32.bar(0u64, 'c'); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar::<&str> 0i32.bar(0u64, "&str"); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar::<&[char; 1]> 0u32.bar(0i8, &['c']); - //~ MONO_ITEM fn trait_method_default_impl::SomeGenericTrait[0]::bar[0] + //~ MONO_ITEM fn >::bar::<()> 0u32.bar(0i16, ()); 0 diff --git a/src/test/codegen-units/item-collection/transitive-drop-glue.rs b/src/test/codegen-units/item-collection/transitive-drop-glue.rs index 7e29af4353..c0489a6a25 100644 --- a/src/test/codegen-units/item-collection/transitive-drop-glue.rs +++ b/src/test/codegen-units/item-collection/transitive-drop-glue.rs @@ -5,15 +5,15 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Root)) @@ transitive_drop_glue-cgu.0[Internal] struct Root(Intermediate); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Intermediate)) @@ transitive_drop_glue-cgu.0[Internal] struct Intermediate(Leaf); -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ transitive_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Leaf)) @@ transitive_drop_glue-cgu.0[Internal] struct Leaf; impl Drop for Leaf { - //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } @@ -25,21 +25,21 @@ impl Drop for LeafGen { fn drop(&mut self) {} } -//~ MONO_ITEM fn transitive_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { let _ = Root(Intermediate(Leaf)); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(RootGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(IntermediateGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(LeafGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = RootGen(IntermediateGen(LeafGen(0u32))); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]> @@ transitive_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn transitive_drop_glue::{{impl}}[1]::drop[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(RootGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(IntermediateGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::> - shim(Some(LeafGen)) @@ transitive_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn as std::ops::Drop>::drop let _ = RootGen(IntermediateGen(LeafGen(0i16))); 0 diff --git a/src/test/codegen-units/item-collection/tuple-drop-glue.rs b/src/test/codegen-units/item-collection/tuple-drop-glue.rs index d77de53ce0..d34835ae69 100644 --- a/src/test/codegen-units/item-collection/tuple-drop-glue.rs +++ b/src/test/codegen-units/item-collection/tuple-drop-glue.rs @@ -5,22 +5,22 @@ #![deny(dead_code)] #![feature(start)] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ tuple_drop_glue-cgu.0[Internal] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Dropped)) @@ tuple_drop_glue-cgu.0[Internal] struct Dropped; impl Drop for Dropped { - //~ MONO_ITEM fn tuple_drop_glue::{{impl}}[0]::drop[0] + //~ MONO_ITEM fn ::drop fn drop(&mut self) {} } -//~ MONO_ITEM fn tuple_drop_glue::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, tuple_drop_glue::Dropped[0])> @@ tuple_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(u32, Dropped)> - shim(Some((u32, Dropped))) @@ tuple_drop_glue-cgu.0[Internal] let x = (0u32, Dropped); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(i16, (tuple_drop_glue::Dropped[0], bool))> @@ tuple_drop_glue-cgu.0[Internal] - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(tuple_drop_glue::Dropped[0], bool)> @@ tuple_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(i16, (Dropped, bool))> - shim(Some((i16, (Dropped, bool)))) @@ tuple_drop_glue-cgu.0[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(Dropped, bool)> - shim(Some((Dropped, bool))) @@ tuple_drop_glue-cgu.0[Internal] let x = (0i16, (Dropped, true)); 0 diff --git a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs index ec6be0ecf4..17b92eae00 100644 --- a/src/test/codegen-units/item-collection/unreferenced-const-fn.rs +++ b/src/test/codegen-units/item-collection/unreferenced-const-fn.rs @@ -3,7 +3,7 @@ #![deny(dead_code)] #![crate_type = "rlib"] -//~ MONO_ITEM fn unreferenced_const_fn::foo[0] @@ unreferenced_const_fn-cgu.0[External] +//~ MONO_ITEM fn foo @@ unreferenced_const_fn-cgu.0[External] pub const fn foo(x: u32) -> u32 { x + 0xf00 } diff --git a/src/test/codegen-units/item-collection/unsizing.rs b/src/test/codegen-units/item-collection/unsizing.rs index 1ed60dcf26..9421bf106b 100644 --- a/src/test/codegen-units/item-collection/unsizing.rs +++ b/src/test/codegen-units/item-collection/unsizing.rs @@ -43,19 +43,19 @@ struct Wrapper(*const T); impl, U: ?Sized> CoerceUnsized> for Wrapper {} -//~ MONO_ITEM fn unsizing::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { // simple case let bool_sized = &true; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[0]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _bool_unsized = bool_sized as &Trait; let char_sized = &'a'; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[1]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _char_unsized = char_sized as &Trait; // struct field @@ -64,14 +64,14 @@ fn start(_: isize, _: *const *const u8) -> isize { _b: 2, _c: 3.0f64 }; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[2]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _struct_unsized = struct_sized as &Struct; // custom coercion let wrapper_sized = Wrapper(&0u32); - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ unsizing-cgu.0[Internal] - //~ MONO_ITEM fn unsizing::{{impl}}[3]::foo[0] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ unsizing-cgu.0[Internal] + //~ MONO_ITEM fn ::foo let _wrapper_sized = wrapper_sized as Wrapper; 0 diff --git a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs index 4a5e294ea0..561dc1a5c0 100644 --- a/src/test/codegen-units/item-collection/unused-traits-and-generics.rs +++ b/src/test/codegen-units/item-collection/unused-traits-and-generics.rs @@ -74,4 +74,4 @@ impl NonGeneric { } // Only the non-generic methods should be instantiated: -//~ MONO_ITEM fn unused_traits_and_generics::{{impl}}[3]::foo[0] +//~ MONO_ITEM fn NonGeneric::foo diff --git a/src/test/codegen-units/partitioning/extern-drop-glue.rs b/src/test/codegen-units/partitioning/extern-drop-glue.rs index 1cb8538223..3de1bdb86c 100644 --- a/src/test/codegen-units/partitioning/extern-drop-glue.rs +++ b/src/test/codegen-units/partitioning/extern-drop-glue.rs @@ -12,13 +12,13 @@ // aux-build:cgu_extern_drop_glue.rs extern crate cgu_extern_drop_glue; -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(cgu_extern_drop_glue::Struct)) @@ extern_drop_glue-fallback.cgu[External] struct LocalStruct(cgu_extern_drop_glue::Struct); -//~ MONO_ITEM fn extern_drop_glue::user[0] @@ extern_drop_glue[External] +//~ MONO_ITEM fn user @@ extern_drop_glue[External] pub fn user() { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(LocalStruct)) @@ extern_drop_glue-fallback.cgu[External] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } @@ -27,9 +27,9 @@ pub mod mod1 { struct LocalStruct(cgu_extern_drop_glue::Struct); - //~ MONO_ITEM fn extern_drop_glue::mod1[0]::user[0] @@ extern_drop_glue-mod1[External] + //~ MONO_ITEM fn mod1::user @@ extern_drop_glue-mod1[External] pub fn user() { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ extern_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(mod1::LocalStruct)) @@ extern_drop_glue-fallback.cgu[External] let _ = LocalStruct(cgu_extern_drop_glue::Struct(0)); } } diff --git a/src/test/codegen-units/partitioning/extern-generic.rs b/src/test/codegen-units/partitioning/extern-generic.rs index 88d6116a98..02930f96bd 100644 --- a/src/test/codegen-units/partitioning/extern-generic.rs +++ b/src/test/codegen-units/partitioning/extern-generic.rs @@ -9,7 +9,7 @@ // aux-build:cgu_generic_function.rs extern crate cgu_generic_function; -//~ MONO_ITEM fn extern_generic::user[0] @@ extern_generic[Internal] +//~ MONO_ITEM fn user @@ extern_generic[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -17,7 +17,7 @@ fn user() { mod mod1 { use cgu_generic_function; - //~ MONO_ITEM fn extern_generic::mod1[0]::user[0] @@ extern_generic-mod1[Internal] + //~ MONO_ITEM fn mod1::user @@ extern_generic-mod1[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -25,7 +25,7 @@ mod mod1 { mod mod1 { use cgu_generic_function; - //~ MONO_ITEM fn extern_generic::mod1[0]::mod1[0]::user[0] @@ extern_generic-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::user @@ extern_generic-mod1-mod1[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } @@ -35,18 +35,18 @@ mod mod1 { mod mod2 { use cgu_generic_function; - //~ MONO_ITEM fn extern_generic::mod2[0]::user[0] @@ extern_generic-mod2[Internal] + //~ MONO_ITEM fn mod2::user @@ extern_generic-mod2[Internal] fn user() { let _ = cgu_generic_function::foo("abc"); } } mod mod3 { - //~ MONO_ITEM fn extern_generic::mod3[0]::non_user[0] @@ extern_generic-mod3[Internal] + //~ MONO_ITEM fn mod3::non_user @@ extern_generic-mod3[Internal] fn non_user() {} } // Make sure the two generic functions from the extern crate get instantiated // once for the current crate -//~ MONO_ITEM fn cgu_generic_function::foo[0]<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] -//~ MONO_ITEM fn cgu_generic_function::bar[0]<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] +//~ MONO_ITEM fn cgu_generic_function::foo::<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] +//~ MONO_ITEM fn cgu_generic_function::bar::<&str> @@ cgu_generic_function-in-extern_generic.volatile[External] diff --git a/src/test/codegen-units/partitioning/incremental-merging.rs b/src/test/codegen-units/partitioning/incremental-merging.rs index ca2df19096..91ae602293 100644 --- a/src/test/codegen-units/partitioning/incremental-merging.rs +++ b/src/test/codegen-units/partitioning/incremental-merging.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // We specify -C incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-mono-items=lazy -Cincremental=tmp/partitioning-tests/incremental-merging @@ -14,28 +13,28 @@ // while `ccc` and `ddd` are supposed to stay untouched. pub mod aaa { - //~ MONO_ITEM fn incremental_merging::aaa[0]::foo[0] @@ incremental_merging-aaa--incremental_merging-bbb[External] + //~ MONO_ITEM fn aaa::foo @@ incremental_merging-aaa--incremental_merging-bbb[External] pub fn foo(a: u64) -> u64 { a + 1 } } pub mod bbb { - //~ MONO_ITEM fn incremental_merging::bbb[0]::foo[0] @@ incremental_merging-aaa--incremental_merging-bbb[External] + //~ MONO_ITEM fn bbb::foo @@ incremental_merging-aaa--incremental_merging-bbb[External] pub fn foo(a: u64, b: u64) -> u64 { a + b + 1 } } pub mod ccc { - //~ MONO_ITEM fn incremental_merging::ccc[0]::foo[0] @@ incremental_merging-ccc[External] + //~ MONO_ITEM fn ccc::foo @@ incremental_merging-ccc[External] pub fn foo(a: u64, b: u64, c: u64) -> u64 { a + b + c + 1 } } pub mod ddd { - //~ MONO_ITEM fn incremental_merging::ddd[0]::foo[0] @@ incremental_merging-ddd[External] + //~ MONO_ITEM fn ddd::foo @@ incremental_merging-ddd[External] pub fn foo(a: u64, b: u64, c: u64, d: u64) -> u64 { a + b + c + d + 1 } diff --git a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs index 7afeb0a0f3..410b77b005 100644 --- a/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs +++ b/src/test/codegen-units/partitioning/inlining-from-extern-crate.rs @@ -12,10 +12,10 @@ extern crate cgu_explicit_inlining; // This test makes sure that items inlined from external crates are privately // instantiated in every codegen unit they are used in. -//~ MONO_ITEM fn cgu_explicit_inlining::inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod1[Internal] -//~ MONO_ITEM fn cgu_explicit_inlining::always_inlined[0] @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod2[Internal] +//~ MONO_ITEM fn cgu_explicit_inlining::inlined @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod1[Internal] +//~ MONO_ITEM fn cgu_explicit_inlining::always_inlined @@ inlining_from_extern_crate[Internal] inlining_from_extern_crate-mod2[Internal] -//~ MONO_ITEM fn inlining_from_extern_crate::user[0] @@ inlining_from_extern_crate[External] +//~ MONO_ITEM fn user @@ inlining_from_extern_crate[External] pub fn user() { cgu_explicit_inlining::inlined(); @@ -28,7 +28,7 @@ pub fn user() pub mod mod1 { use cgu_explicit_inlining; - //~ MONO_ITEM fn inlining_from_extern_crate::mod1[0]::user[0] @@ inlining_from_extern_crate-mod1[External] + //~ MONO_ITEM fn mod1::user @@ inlining_from_extern_crate-mod1[External] pub fn user() { cgu_explicit_inlining::inlined(); @@ -41,7 +41,7 @@ pub mod mod1 { pub mod mod2 { use cgu_explicit_inlining; - //~ MONO_ITEM fn inlining_from_extern_crate::mod2[0]::user[0] @@ inlining_from_extern_crate-mod2[External] + //~ MONO_ITEM fn mod2::user @@ inlining_from_extern_crate-mod2[External] pub fn user() { cgu_explicit_inlining::always_inlined(); diff --git a/src/test/codegen-units/partitioning/local-drop-glue.rs b/src/test/codegen-units/partitioning/local-drop-glue.rs index c082b40827..98108615ce 100644 --- a/src/test/codegen-units/partitioning/local-drop-glue.rs +++ b/src/test/codegen-units/partitioning/local-drop-glue.rs @@ -8,22 +8,22 @@ #![allow(dead_code)] #![crate_type = "rlib"] -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Struct)) @@ local_drop_glue-fallback.cgu[External] struct Struct { _a: u32, } impl Drop for Struct { - //~ MONO_ITEM fn local_drop_glue::{{impl}}[0]::drop[0] @@ local_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn ::drop @@ local_drop_glue-fallback.cgu[External] fn drop(&mut self) {} } -//~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] +//~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(Outer)) @@ local_drop_glue-fallback.cgu[External] struct Outer { _a: Struct, } -//~ MONO_ITEM fn local_drop_glue::user[0] @@ local_drop_glue[External] +//~ MONO_ITEM fn user @@ local_drop_glue[External] pub fn user() { let _ = Outer { _a: Struct { _a: 0 } }; } @@ -31,14 +31,14 @@ pub fn user() { pub mod mod1 { use super::Struct; - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ local_drop_glue-fallback.cgu[External] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(Some(mod1::Struct2)) @@ local_drop_glue-fallback.cgu[External] struct Struct2 { _a: Struct, - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0]<(u32, local_drop_glue::Struct[0])> @@ local_drop_glue-fallback.cgu[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place::<(u32, Struct)> - shim(Some((u32, Struct))) @@ local_drop_glue-fallback.cgu[Internal] _b: (u32, Struct), } - //~ MONO_ITEM fn local_drop_glue::mod1[0]::user[0] @@ local_drop_glue-mod1[External] + //~ MONO_ITEM fn mod1::user @@ local_drop_glue-mod1[External] pub fn user() { let _ = Struct2 { _a: Struct { _a: 0 }, _b: (0, Struct { _a: 0 }) }; } diff --git a/src/test/codegen-units/partitioning/local-generic.rs b/src/test/codegen-units/partitioning/local-generic.rs index 4518166a1c..9a7743bbf4 100644 --- a/src/test/codegen-units/partitioning/local-generic.rs +++ b/src/test/codegen-units/partitioning/local-generic.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // We specify -C incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/local-generic @@ -6,13 +5,13 @@ #![allow(dead_code)] #![crate_type="lib"] -//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ MONO_ITEM fn local_generic::generic[0] @@ local_generic.volatile[External] -//~ MONO_ITEM fn local_generic::generic[0]<&str> @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic:: @@ local_generic.volatile[External] +//~ MONO_ITEM fn generic::<&str> @@ local_generic.volatile[External] pub fn generic(x: T) -> T { x } -//~ MONO_ITEM fn local_generic::user[0] @@ local_generic[Internal] +//~ MONO_ITEM fn user @@ local_generic[Internal] fn user() { let _ = generic(0u32); } @@ -20,7 +19,7 @@ fn user() { mod mod1 { pub use super::generic; - //~ MONO_ITEM fn local_generic::mod1[0]::user[0] @@ local_generic-mod1[Internal] + //~ MONO_ITEM fn mod1::user @@ local_generic-mod1[Internal] fn user() { let _ = generic(0u64); } @@ -28,7 +27,7 @@ mod mod1 { mod mod1 { use super::generic; - //~ MONO_ITEM fn local_generic::mod1[0]::mod1[0]::user[0] @@ local_generic-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::user @@ local_generic-mod1-mod1[Internal] fn user() { let _ = generic('c'); } @@ -38,7 +37,7 @@ mod mod1 { mod mod2 { use super::generic; - //~ MONO_ITEM fn local_generic::mod2[0]::user[0] @@ local_generic-mod2[Internal] + //~ MONO_ITEM fn mod2::user @@ local_generic-mod2[Internal] fn user() { let _ = generic("abc"); } diff --git a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs index 6322f55d2b..a24943348f 100644 --- a/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs +++ b/src/test/codegen-units/partitioning/local-inlining-but-not-all.rs @@ -9,7 +9,7 @@ mod inline { - //~ MONO_ITEM fn local_inlining_but_not_all::inline[0]::inlined_function[0] @@ local_inlining_but_not_all-inline[External] + //~ MONO_ITEM fn inline::inlined_function @@ local_inlining_but_not_all-inline[External] #[inline] pub fn inlined_function() { @@ -20,7 +20,7 @@ mod inline { pub mod user1 { use super::inline; - //~ MONO_ITEM fn local_inlining_but_not_all::user1[0]::foo[0] @@ local_inlining_but_not_all-user1[External] + //~ MONO_ITEM fn user1::foo @@ local_inlining_but_not_all-user1[External] pub fn foo() { inline::inlined_function(); } @@ -29,7 +29,7 @@ pub mod user1 { pub mod user2 { use super::inline; - //~ MONO_ITEM fn local_inlining_but_not_all::user2[0]::bar[0] @@ local_inlining_but_not_all-user2[External] + //~ MONO_ITEM fn user2::bar @@ local_inlining_but_not_all-user2[External] pub fn bar() { inline::inlined_function(); } @@ -37,7 +37,7 @@ pub mod user2 { pub mod non_user { - //~ MONO_ITEM fn local_inlining_but_not_all::non_user[0]::baz[0] @@ local_inlining_but_not_all-non_user[External] + //~ MONO_ITEM fn non_user::baz @@ local_inlining_but_not_all-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/local-inlining.rs b/src/test/codegen-units/partitioning/local-inlining.rs index d75dfc9126..0cc652eeb5 100644 --- a/src/test/codegen-units/partitioning/local-inlining.rs +++ b/src/test/codegen-units/partitioning/local-inlining.rs @@ -10,7 +10,7 @@ mod inline { // Important: This function should show up in all codegen units where it is inlined - //~ MONO_ITEM fn local_inlining::inline[0]::inlined_function[0] @@ local_inlining-user1[Internal] local_inlining-user2[Internal] + //~ MONO_ITEM fn inline::inlined_function @@ local_inlining-user1[Internal] local_inlining-user2[Internal] #[inline(always)] pub fn inlined_function() { @@ -21,7 +21,7 @@ mod inline { pub mod user1 { use super::inline; - //~ MONO_ITEM fn local_inlining::user1[0]::foo[0] @@ local_inlining-user1[External] + //~ MONO_ITEM fn user1::foo @@ local_inlining-user1[External] pub fn foo() { inline::inlined_function(); } @@ -30,7 +30,7 @@ pub mod user1 { pub mod user2 { use super::inline; - //~ MONO_ITEM fn local_inlining::user2[0]::bar[0] @@ local_inlining-user2[External] + //~ MONO_ITEM fn user2::bar @@ local_inlining-user2[External] pub fn bar() { inline::inlined_function(); } @@ -38,7 +38,7 @@ pub mod user2 { pub mod non_user { - //~ MONO_ITEM fn local_inlining::non_user[0]::baz[0] @@ local_inlining-non_user[External] + //~ MONO_ITEM fn non_user::baz @@ local_inlining-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/local-transitive-inlining.rs b/src/test/codegen-units/partitioning/local-transitive-inlining.rs index 3cf0396686..0c8a67aeb3 100644 --- a/src/test/codegen-units/partitioning/local-transitive-inlining.rs +++ b/src/test/codegen-units/partitioning/local-transitive-inlining.rs @@ -9,7 +9,7 @@ mod inline { - //~ MONO_ITEM fn local_transitive_inlining::inline[0]::inlined_function[0] @@ local_transitive_inlining-indirect_user[Internal] + //~ MONO_ITEM fn inline::inlined_function @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn inlined_function() { @@ -20,7 +20,7 @@ mod inline { mod direct_user { use super::inline; - //~ MONO_ITEM fn local_transitive_inlining::direct_user[0]::foo[0] @@ local_transitive_inlining-indirect_user[Internal] + //~ MONO_ITEM fn direct_user::foo @@ local_transitive_inlining-indirect_user[Internal] #[inline(always)] pub fn foo() { inline::inlined_function(); @@ -30,7 +30,7 @@ mod direct_user { pub mod indirect_user { use super::direct_user; - //~ MONO_ITEM fn local_transitive_inlining::indirect_user[0]::bar[0] @@ local_transitive_inlining-indirect_user[External] + //~ MONO_ITEM fn indirect_user::bar @@ local_transitive_inlining-indirect_user[External] pub fn bar() { direct_user::foo(); } @@ -38,7 +38,7 @@ pub mod indirect_user { pub mod non_user { - //~ MONO_ITEM fn local_transitive_inlining::non_user[0]::baz[0] @@ local_transitive_inlining-non_user[External] + //~ MONO_ITEM fn non_user::baz @@ local_transitive_inlining-non_user[External] pub fn baz() { } diff --git a/src/test/codegen-units/partitioning/regular-modules.rs b/src/test/codegen-units/partitioning/regular-modules.rs index c8ceeafd0b..f9b8f52b0b 100644 --- a/src/test/codegen-units/partitioning/regular-modules.rs +++ b/src/test/codegen-units/partitioning/regular-modules.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // We specify -C incremental here because we want to test the partitioning for // incremental compilation // compile-flags:-Zprint-mono-items=eager -Cincremental=tmp/partitioning-tests/regular-modules @@ -6,67 +5,67 @@ #![allow(dead_code)] #![crate_type="lib"] -//~ MONO_ITEM fn regular_modules::foo[0] @@ regular_modules[Internal] +//~ MONO_ITEM fn foo @@ regular_modules[Internal] fn foo() {} -//~ MONO_ITEM fn regular_modules::bar[0] @@ regular_modules[Internal] +//~ MONO_ITEM fn bar @@ regular_modules[Internal] fn bar() {} -//~ MONO_ITEM static regular_modules::BAZ[0] @@ regular_modules[Internal] +//~ MONO_ITEM static BAZ @@ regular_modules[Internal] static BAZ: u64 = 0; mod mod1 { - //~ MONO_ITEM fn regular_modules::mod1[0]::foo[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM fn mod1::foo @@ regular_modules-mod1[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod1[0]::bar[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM fn mod1::bar @@ regular_modules-mod1[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod1[0]::BAZ[0] @@ regular_modules-mod1[Internal] + //~ MONO_ITEM static mod1::BAZ @@ regular_modules-mod1[Internal] static BAZ: u64 = 0; mod mod1 { - //~ MONO_ITEM fn regular_modules::mod1[0]::mod1[0]::foo[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::foo @@ regular_modules-mod1-mod1[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod1[0]::mod1[0]::bar[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM fn mod1::mod1::bar @@ regular_modules-mod1-mod1[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod1[0]::mod1[0]::BAZ[0] @@ regular_modules-mod1-mod1[Internal] + //~ MONO_ITEM static mod1::mod1::BAZ @@ regular_modules-mod1-mod1[Internal] static BAZ: u64 = 0; } mod mod2 { - //~ MONO_ITEM fn regular_modules::mod1[0]::mod2[0]::foo[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM fn mod1::mod2::foo @@ regular_modules-mod1-mod2[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod1[0]::mod2[0]::bar[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM fn mod1::mod2::bar @@ regular_modules-mod1-mod2[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod1[0]::mod2[0]::BAZ[0] @@ regular_modules-mod1-mod2[Internal] + //~ MONO_ITEM static mod1::mod2::BAZ @@ regular_modules-mod1-mod2[Internal] static BAZ: u64 = 0; } } mod mod2 { - //~ MONO_ITEM fn regular_modules::mod2[0]::foo[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM fn mod2::foo @@ regular_modules-mod2[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod2[0]::bar[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM fn mod2::bar @@ regular_modules-mod2[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod2[0]::BAZ[0] @@ regular_modules-mod2[Internal] + //~ MONO_ITEM static mod2::BAZ @@ regular_modules-mod2[Internal] static BAZ: u64 = 0; mod mod1 { - //~ MONO_ITEM fn regular_modules::mod2[0]::mod1[0]::foo[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM fn mod2::mod1::foo @@ regular_modules-mod2-mod1[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod2[0]::mod1[0]::bar[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM fn mod2::mod1::bar @@ regular_modules-mod2-mod1[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod2[0]::mod1[0]::BAZ[0] @@ regular_modules-mod2-mod1[Internal] + //~ MONO_ITEM static mod2::mod1::BAZ @@ regular_modules-mod2-mod1[Internal] static BAZ: u64 = 0; } mod mod2 { - //~ MONO_ITEM fn regular_modules::mod2[0]::mod2[0]::foo[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM fn mod2::mod2::foo @@ regular_modules-mod2-mod2[Internal] fn foo() {} - //~ MONO_ITEM fn regular_modules::mod2[0]::mod2[0]::bar[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM fn mod2::mod2::bar @@ regular_modules-mod2-mod2[Internal] fn bar() {} - //~ MONO_ITEM static regular_modules::mod2[0]::mod2[0]::BAZ[0] @@ regular_modules-mod2-mod2[Internal] + //~ MONO_ITEM static mod2::mod2::BAZ @@ regular_modules-mod2-mod2[Internal] static BAZ: u64 = 0; } } diff --git a/src/test/codegen-units/partitioning/shared-generics.rs b/src/test/codegen-units/partitioning/shared-generics.rs index 99142dd6b7..eb3196439b 100644 --- a/src/test/codegen-units/partitioning/shared-generics.rs +++ b/src/test/codegen-units/partitioning/shared-generics.rs @@ -9,10 +9,10 @@ // aux-build:shared_generics_aux.rs extern crate shared_generics_aux; -//~ MONO_ITEM fn shared_generics::foo[0] +//~ MONO_ITEM fn foo pub fn foo() { - //~ MONO_ITEM fn shared_generics_aux::generic_fn[0] @@ shared_generics_aux-in-shared_generics.volatile[External] + //~ MONO_ITEM fn shared_generics_aux::generic_fn:: @@ shared_generics_aux-in-shared_generics.volatile[External] let _ = shared_generics_aux::generic_fn(0u16, 1u16); // This should not generate a monomorphization because it's already diff --git a/src/test/codegen-units/partitioning/statics.rs b/src/test/codegen-units/partitioning/statics.rs index 5eac046b81..02d6467577 100644 --- a/src/test/codegen-units/partitioning/statics.rs +++ b/src/test/codegen-units/partitioning/statics.rs @@ -4,34 +4,34 @@ #![crate_type="rlib"] -//~ MONO_ITEM static statics::FOO[0] @@ statics[Internal] +//~ MONO_ITEM static FOO @@ statics[Internal] static FOO: u32 = 0; -//~ MONO_ITEM static statics::BAR[0] @@ statics[Internal] +//~ MONO_ITEM static BAR @@ statics[Internal] static BAR: u32 = 0; -//~ MONO_ITEM fn statics::function[0] @@ statics[External] +//~ MONO_ITEM fn function @@ statics[External] pub fn function() { - //~ MONO_ITEM static statics::function[0]::FOO[0] @@ statics[Internal] + //~ MONO_ITEM static function::FOO @@ statics[Internal] static FOO: u32 = 0; - //~ MONO_ITEM static statics::function[0]::BAR[0] @@ statics[Internal] + //~ MONO_ITEM static function::BAR @@ statics[Internal] static BAR: u32 = 0; } pub mod mod1 { - //~ MONO_ITEM static statics::mod1[0]::FOO[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::FOO @@ statics-mod1[Internal] static FOO: u32 = 0; - //~ MONO_ITEM static statics::mod1[0]::BAR[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::BAR @@ statics-mod1[Internal] static BAR: u32 = 0; - //~ MONO_ITEM fn statics::mod1[0]::function[0] @@ statics-mod1[External] + //~ MONO_ITEM fn mod1::function @@ statics-mod1[External] pub fn function() { - //~ MONO_ITEM static statics::mod1[0]::function[0]::FOO[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::function::FOO @@ statics-mod1[Internal] static FOO: u32 = 0; - //~ MONO_ITEM static statics::mod1[0]::function[0]::BAR[0] @@ statics-mod1[Internal] + //~ MONO_ITEM static mod1::function::BAR @@ statics-mod1[Internal] static BAR: u32 = 0; } } diff --git a/src/test/codegen-units/partitioning/vtable-through-const.rs b/src/test/codegen-units/partitioning/vtable-through-const.rs index 5a1d95d266..03dbac6179 100644 --- a/src/test/codegen-units/partitioning/vtable-through-const.rs +++ b/src/test/codegen-units/partitioning/vtable-through-const.rs @@ -28,7 +28,7 @@ mod mod1 { fn do_something_else(&self, x: T) -> T { x } } - //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn mod1::id:: @@ vtable_through_const-mod1.volatile[Internal] fn id(x: T) -> T { x } // These are referenced, so they produce mono-items (see start()) @@ -43,8 +43,8 @@ mod mod1 { fn do_something_else(&self) {} } - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait2[0]::do_something[0] @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait2[0]::do_something_else[0] @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[Internal] impl Trait2 for u32 {} pub trait Trait2Gen { @@ -63,30 +63,30 @@ mod mod1 { pub const ID_I64: fn(i64) -> i64 = id::; } -//~ MONO_ITEM fn vtable_through_const::start[0] +//~ MONO_ITEM fn start #[start] fn start(_: isize, _: *const *const u8) -> isize { - //~ MONO_ITEM fn core::ptr[0]::drop_in_place[0] @@ vtable_through_const[Internal] + //~ MONO_ITEM fn std::intrinsics::drop_in_place:: - shim(None) @@ vtable_through_const[Internal] // Since Trait1::do_something() is instantiated via its default implementation, // it is considered a generic and is instantiated here only because it is // referenced in this module. - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn ::do_something_else @@ vtable_through_const-mod1.volatile[External] // Although it is never used, Trait1::do_something_else() has to be // instantiated locally here too, otherwise the <&u32 as &Trait1> vtable // could not be fully constructed. - //~ MONO_ITEM fn vtable_through_const::mod1[0]::Trait1[0]::do_something[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn ::do_something @@ vtable_through_const-mod1.volatile[External] mod1::TRAIT1_REF.do_something(); // Same as above - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something[0] @@ vtable_through_const-mod1.volatile[External] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[1]::do_something_else[0] @@ vtable_through_const-mod1.volatile[External] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[3]::do_something[0] @@ vtable_through_const-mod1.volatile[Internal] - //~ MONO_ITEM fn vtable_through_const::mod1[0]::{{impl}}[3]::do_something_else[0] @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn >::do_something @@ vtable_through_const-mod1.volatile[Internal] + //~ MONO_ITEM fn >::do_something_else @@ vtable_through_const-mod1.volatile[Internal] mod1::TRAIT1_GEN_REF.do_something(0u8); - //~ MONO_ITEM fn vtable_through_const::mod1[0]::id[0] @@ vtable_through_const-mod1.volatile[External] + //~ MONO_ITEM fn mod1::id:: @@ vtable_through_const-mod1.volatile[External] mod1::ID_CHAR('x'); 0 diff --git a/src/test/codegen-units/polymorphization/unused_type_parameters.rs b/src/test/codegen-units/polymorphization/unused_type_parameters.rs index 403f68bb17..c2e06d067d 100644 --- a/src/test/codegen-units/polymorphization/unused_type_parameters.rs +++ b/src/test/codegen-units/polymorphization/unused_type_parameters.rs @@ -1,5 +1,4 @@ // compile-flags:-Zpolymorphize=on -Zprint-mono-items=lazy -Copt-level=1 -// ignore-tidy-linelength #![crate_type = "rlib"] @@ -10,44 +9,44 @@ mod functions { // Function doesn't have any type parameters to be unused. pub fn no_parameters() {} -//~ MONO_ITEM fn unused_type_parameters::functions[0]::no_parameters[0] +//~ MONO_ITEM fn functions::no_parameters // Function has an unused type parameter. pub fn unused() { } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::unused[0] +//~ MONO_ITEM fn functions::unused:: // Function uses type parameter in value of a binding. pub fn used_binding_value() { let _: T = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_value[0] +//~ MONO_ITEM fn functions::used_binding_value:: +//~ MONO_ITEM fn functions::used_binding_value:: // Function uses type parameter in type of a binding. pub fn used_binding_type() { let _: Option = None; } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_binding_type[0] +//~ MONO_ITEM fn functions::used_binding_type:: +//~ MONO_ITEM fn functions::used_binding_type:: // Function uses type parameter in argument. pub fn used_argument(_: T) { } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_argument[0] +//~ MONO_ITEM fn functions::used_argument:: +//~ MONO_ITEM fn functions::used_argument:: // // Function uses type parameter in substitutions to another function. pub fn used_substs() { unused::() } -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::functions[0]::used_substs[0] +//~ MONO_ITEM fn functions::used_substs:: +//~ MONO_ITEM fn functions::used_substs:: } @@ -57,7 +56,7 @@ mod closures { let _ = || {}; } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::no_parameters[0] +//~ MONO_ITEM fn closures::no_parameters // Function has an unused type parameter in parent and closure. pub fn unused() -> u32 { @@ -65,8 +64,8 @@ mod closures { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::unused[0] +//~ MONO_ITEM fn closures::unused::::{closure#0} +//~ MONO_ITEM fn closures::unused:: // Function has an unused type parameter in closure, but not in parent. pub fn used_parent() -> u32 { @@ -75,9 +74,9 @@ mod closures { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_parent[0] +//~ MONO_ITEM fn closures::used_parent::::{closure#0} +//~ MONO_ITEM fn closures::used_parent:: +//~ MONO_ITEM fn closures::used_parent:: // Function uses type parameter in value of a binding in closure. pub fn used_binding_value() -> T { @@ -89,10 +88,10 @@ mod closures { x() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0]::{{closure}}[0] u64, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_value[0] +//~ MONO_ITEM fn closures::used_binding_value::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_value::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_value:: +//~ MONO_ITEM fn closures::used_binding_value:: // Function uses type parameter in type of a binding in closure. pub fn used_binding_type() -> Option { @@ -104,10 +103,10 @@ mod closures { x() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0] core::option[0]::Option[0], ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0]::{{closure}}[0] core::option[0]::Option[0], ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_binding_type[0] +//~ MONO_ITEM fn closures::used_binding_type::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_type::::{closure#0} +//~ MONO_ITEM fn closures::used_binding_type:: +//~ MONO_ITEM fn closures::used_binding_type:: // Function and closure uses type parameter in argument. pub fn used_argument(t: T) -> u32 { @@ -115,10 +114,10 @@ mod closures { x(t) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument[0] +//~ MONO_ITEM fn closures::used_argument::::{closure#0} +//~ MONO_ITEM fn closures::used_argument::::{closure#0} +//~ MONO_ITEM fn closures::used_argument:: +//~ MONO_ITEM fn closures::used_argument:: // Closure uses type parameter in argument. pub fn used_argument_closure() -> u32 { @@ -127,10 +126,10 @@ mod closures { x(t) } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_argument_closure[0] +//~ MONO_ITEM fn closures::used_argument_closure::::{closure#0} +//~ MONO_ITEM fn closures::used_argument_closure::::{closure#0} +//~ MONO_ITEM fn closures::used_argument_closure:: +//~ MONO_ITEM fn closures::used_argument_closure:: // Closure uses type parameter as upvar. pub fn used_upvar() -> T { @@ -139,10 +138,10 @@ mod closures { y() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0] u32, (u32)> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0]::{{closure}}[0] u64, (u64)> -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_upvar[0] +//~ MONO_ITEM fn closures::used_upvar::::{closure#0} +//~ MONO_ITEM fn closures::used_upvar::::{closure#0} +//~ MONO_ITEM fn closures::used_upvar:: +//~ MONO_ITEM fn closures::used_upvar:: // Closure uses type parameter in substitutions to another function. pub fn used_substs() { @@ -150,10 +149,10 @@ mod closures { x() } -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::closures[0]::used_substs[0] +//~ MONO_ITEM fn closures::used_substs::::{closure#0} +//~ MONO_ITEM fn closures::used_substs::::{closure#0} +//~ MONO_ITEM fn closures::used_substs:: +//~ MONO_ITEM fn closures::used_substs:: } mod methods { @@ -164,29 +163,29 @@ mod methods { pub fn unused_impl() { } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_impl[0] +//~ MONO_ITEM fn methods::Foo::::unused_impl // Function has an unused type parameter from impl and fn. pub fn unused_both() { } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::unused_both[0] +//~ MONO_ITEM fn methods::Foo::::unused_both:: // Function uses type parameter from impl. pub fn used_impl() { let _: F = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_impl[0] +//~ MONO_ITEM fn methods::Foo::::used_impl +//~ MONO_ITEM fn methods::Foo::::used_impl // Function uses type parameter from impl. pub fn used_fn() { let _: G = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_fn[0] +//~ MONO_ITEM fn methods::Foo::::used_fn:: +//~ MONO_ITEM fn methods::Foo::::used_fn:: // Function uses type parameter from impl. pub fn used_both() { @@ -194,16 +193,16 @@ mod methods { let _: G = Default::default(); } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_both[0] +//~ MONO_ITEM fn methods::Foo::::used_both:: +//~ MONO_ITEM fn methods::Foo::::used_both:: // Function uses type parameter in substitutions to another function. pub fn used_substs() { super::functions::unused::() } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::used_substs[0] +//~ MONO_ITEM fn methods::Foo::::used_substs +//~ MONO_ITEM fn methods::Foo::::used_substs // Function has an unused type parameter from impl and fn. pub fn closure_unused_all() -> u32 { @@ -211,8 +210,8 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_unused_all[0] +//~ MONO_ITEM fn methods::Foo::::closure_unused_all::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_unused_all:: // Function uses type parameter from impl and fn in closure. pub fn closure_used_both() -> u32 { @@ -225,10 +224,10 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_both[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_both::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_both:: +//~ MONO_ITEM fn methods::Foo::::closure_used_both:: // Function uses type parameter from fn in closure. pub fn closure_used_fn() -> u32 { @@ -240,10 +239,10 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_fn[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_fn::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_fn:: +//~ MONO_ITEM fn methods::Foo::::closure_used_fn:: // Function uses type parameter from impl in closure. pub fn closure_used_impl() -> u32 { @@ -255,10 +254,10 @@ mod methods { add_one(3) } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0]::{{closure}}[0] u32, ()> -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_impl[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_impl::::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_impl:: +//~ MONO_ITEM fn methods::Foo::::closure_used_impl:: // Closure uses type parameter in substitutions to another function. pub fn closure_used_substs() { @@ -266,10 +265,10 @@ mod methods { x() } -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0]::{{closure}}[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0] -//~ MONO_ITEM fn unused_type_parameters::methods[0]::{{impl}}[0]::closure_used_substs[0] +//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_substs::{closure#0} +//~ MONO_ITEM fn methods::Foo::::closure_used_substs +//~ MONO_ITEM fn methods::Foo::::closure_used_substs } } @@ -306,8 +305,8 @@ fn dispatch() { let _ = methods::Foo::::closure_used_substs(); } -//~ MONO_ITEM fn unused_type_parameters::dispatch[0] -//~ MONO_ITEM fn unused_type_parameters::dispatch[0] +//~ MONO_ITEM fn dispatch:: +//~ MONO_ITEM fn dispatch:: pub fn foo() { // Generate two copies of each function to check that where the type parameter is unused, @@ -316,8 +315,8 @@ pub fn foo() { dispatch::(); } -//~ MONO_ITEM fn unused_type_parameters::foo[0] @@ unused_type_parameters-cgu.0[External] +//~ MONO_ITEM fn foo @@ unused_type_parameters-cgu.0[External] // These are all the items that aren't relevant to the test. -//~ MONO_ITEM fn core::default[0]::{{impl}}[6]::default[0] -//~ MONO_ITEM fn core::default[0]::{{impl}}[7]::default[0] +//~ MONO_ITEM fn ::default +//~ MONO_ITEM fn ::default diff --git a/src/test/codegen/avr/avr-func-addrspace.rs b/src/test/codegen/avr/avr-func-addrspace.rs index 6d25ca56f1..0f15729158 100644 --- a/src/test/codegen/avr/avr-func-addrspace.rs +++ b/src/test/codegen/avr/avr-func-addrspace.rs @@ -1,4 +1,4 @@ -// compile-flags: -O --target=avr-unknown-unknown --crate-type=rlib +// compile-flags: -O --target=avr-unknown-gnu-atmega328 --crate-type=rlib // needs-llvm-components: avr // This test validates that function pointers can be stored in global variables diff --git a/src/test/codegen/consts.rs b/src/test/codegen/consts.rs index 318f9b0eec..fcb9002986 100644 --- a/src/test/codegen/consts.rs +++ b/src/test/codegen/consts.rs @@ -14,7 +14,7 @@ // This checks the constants from {low,high}_align_const, they share the same // constant, but the alignment differs, so the higher one should be used -// CHECK: [[LOW_HIGH:@[0-9]+]] = {{.*}} getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* @alloc20, i32 0, i32 0, i32 0), {{.*}} +// CHECK: [[LOW_HIGH:@alloc[0-9]+]] = {{.*}}, align 4 #[derive(Copy, Clone)] // repr(i16) is required for the {low,high}_align_const test @@ -43,7 +43,7 @@ pub fn inline_enum_const() -> E { #[no_mangle] pub fn low_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), + // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 2 %1, i8* align 2 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false) *&E::A(0) } @@ -51,6 +51,6 @@ pub fn low_align_const() -> E { #[no_mangle] pub fn high_align_const() -> E { // Check that low_align_const and high_align_const use the same constant - // CHECK: load %"E"*, %"E"** bitcast (<{ i8*, [0 x i8] }>* [[LOW_HIGH]] to %"E"**), + // CHECK: memcpy.p0i8.p0i8.i{{(32|64)}}(i8* align 4 %1, i8* align 4 getelementptr inbounds (<{ [8 x i8] }>, <{ [8 x i8] }>* [[LOW_HIGH]], i32 0, i32 0, i32 0), i{{(32|64)}} 8, i1 false) *&E::A(0) } diff --git a/src/test/codegen/enum-bounds-check-derived-idx.rs b/src/test/codegen/enum-bounds-check-derived-idx.rs new file mode 100644 index 0000000000..7e3773b6a3 --- /dev/null +++ b/src/test/codegen/enum-bounds-check-derived-idx.rs @@ -0,0 +1,25 @@ +// This test checks an optimization that is not guaranteed to work. This test case should not block +// a future LLVM update. +// compile-flags: -O +// min-llvm-version: 11.0 + +#![crate_type = "lib"] + +pub enum Bar { + A = 1, + B = 3, +} + +// CHECK-LABEL: @lookup_inc +#[no_mangle] +pub fn lookup_inc(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize + 1] +} + +// CHECK-LABEL: @lookup_dec +#[no_mangle] +pub fn lookup_dec(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize - 1] +} diff --git a/src/test/codegen/enum-bounds-check-issue-13926.rs b/src/test/codegen/enum-bounds-check-issue-13926.rs new file mode 100644 index 0000000000..ad029f0fa7 --- /dev/null +++ b/src/test/codegen/enum-bounds-check-issue-13926.rs @@ -0,0 +1,19 @@ +// This test checks an optimization that is not guaranteed to work. This test case should not block +// a future LLVM update. +// compile-flags: -O +// min-llvm-version: 11.0 + +#![crate_type = "lib"] + +#[repr(u8)] +pub enum Exception { + Low = 5, + High = 10, +} + +// CHECK-LABEL: @access +#[no_mangle] +pub fn access(array: &[usize; 12], exc: Exception) -> usize { + // CHECK-NOT: panic_bounds_check + array[(exc as u8 - 4) as usize] +} diff --git a/src/test/codegen/enum-bounds-check.rs b/src/test/codegen/enum-bounds-check.rs index 21a27c9f35..17322d5911 100644 --- a/src/test/codegen/enum-bounds-check.rs +++ b/src/test/codegen/enum-bounds-check.rs @@ -12,3 +12,15 @@ pub fn lookup(buf: &[u8; 2], f: Foo) -> u8 { // CHECK-NOT: panic_bounds_check buf[f as usize] } + +pub enum Bar { + A = 2, + B = 3 +} + +// CHECK-LABEL: @lookup_unmodified +#[no_mangle] +pub fn lookup_unmodified(buf: &[u8; 5], f: Bar) -> u8 { + // CHECK-NOT: panic_bounds_check + buf[f as usize] +} diff --git a/src/test/codegen/issue-27130.rs b/src/test/codegen/issue-27130.rs new file mode 100644 index 0000000000..7ae78782ff --- /dev/null +++ b/src/test/codegen/issue-27130.rs @@ -0,0 +1,22 @@ +// compile-flags: -O +// min-llvm-version: 11.0 + +#![crate_type = "lib"] + +// CHECK-LABEL: @trim_in_place +#[no_mangle] +pub fn trim_in_place(a: &mut &[u8]) { + while a.first() == Some(&42) { + // CHECK-NOT: slice_index_order_fail + *a = &a[1..]; + } +} + +// CHECK-LABEL: @trim_in_place2 +#[no_mangle] +pub fn trim_in_place2(a: &mut &[u8]) { + while let Some(&42) = a.first() { + // CHECK-NOT: slice_index_order_fail + *a = &a[2..]; + } +} diff --git a/src/test/codegen/issue-34634.rs b/src/test/codegen/issue-34634.rs new file mode 100644 index 0000000000..6c18adbcb3 --- /dev/null +++ b/src/test/codegen/issue-34634.rs @@ -0,0 +1,16 @@ +// Test that `wrapping_div` only checks divisor once. +// This test checks that there is only a single compare agains -1 and -1 is not present as a +// switch case (the second check present until rustc 1.12). +// This test also verifies that a single panic call is generated (for the division by zero case). + +// compile-flags: -O +#![crate_type = "lib"] + +// CHECK-LABEL: @f +#[no_mangle] +pub fn f(x: i32, y: i32) -> i32 { + // CHECK-COUNT-1: icmp eq i32 %y, -1 + // CHECK-COUNT-1: panic + // CHECK-NOT: i32 -1, label + x.wrapping_div(y) +} diff --git a/src/test/codegen/issue-73396-bounds-check-after-position.rs b/src/test/codegen/issue-73396-bounds-check-after-position.rs new file mode 100644 index 0000000000..e5f3ae45c0 --- /dev/null +++ b/src/test/codegen/issue-73396-bounds-check-after-position.rs @@ -0,0 +1,78 @@ +// min-llvm-version: 11.0.0 +// compile-flags: -O +// ignore-debug: the debug assertions get in the way +#![crate_type = "lib"] + +// Make sure no bounds checks are emitted when slicing or indexing +// with an index from `position()` or `rposition()`. + +// CHECK-LABEL: @position_slice_to_no_bounds_check +#[no_mangle] +pub fn position_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @position_slice_from_no_bounds_check +#[no_mangle] +pub fn position_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @position_index_no_bounds_check +#[no_mangle] +pub fn position_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().position(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} +// CHECK-LABEL: @rposition_slice_to_no_bounds_check +#[no_mangle] +pub fn rposition_slice_to_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[..idx] + } else { + s + } +} + +// CHECK-LABEL: @rposition_slice_from_no_bounds_check +#[no_mangle] +pub fn rposition_slice_from_no_bounds_check(s: &[u8]) -> &[u8] { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + &s[idx..] + } else { + s + } +} + +// CHECK-LABEL: @rposition_index_no_bounds_check +#[no_mangle] +pub fn rposition_index_no_bounds_check(s: &[u8]) -> u8 { + // CHECK-NOT: panic + // CHECK-NOT: slice_index_len_fail + if let Some(idx) = s.iter().rposition(|b| *b == b'\\') { + s[idx] + } else { + 42 + } +} diff --git a/src/test/codegen/issue-75659.rs b/src/test/codegen/issue-75659.rs new file mode 100644 index 0000000000..d093c841d6 --- /dev/null +++ b/src/test/codegen/issue-75659.rs @@ -0,0 +1,63 @@ +// This test checks that the call to memchr/slice_contains is optimized away +// when searching in small slices. + +// compile-flags: -O +// only-x86_64 + +#![crate_type = "lib"] + +// CHECK-LABEL: @foo1 +#[no_mangle] +pub fn foo1(x: u8, data: &[u8; 1]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo2 +#[no_mangle] +pub fn foo2(x: u8, data: &[u8; 2]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo3 +#[no_mangle] +pub fn foo3(x: u8, data: &[u8; 3]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo4 +#[no_mangle] +pub fn foo4(x: u8, data: &[u8; 4]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8 +#[no_mangle] +pub fn foo8(x: u8, data: &[u8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + data.contains(&x) +} + +// CHECK-LABEL: @foo8_i8 +#[no_mangle] +pub fn foo8_i8(x: i8, data: &[i8; 8]) -> bool { + // CHECK-NOT: memchr + // CHECK-NOT: slice_contains + !data.contains(&x) +} + +// Check that the general case isn't inlined +// CHECK-LABEL: @foo80 +#[no_mangle] +pub fn foo80(x: u8, data: &[u8; 80]) -> bool { + // CHECK: call core::slice::memchr + data.contains(&x) +} diff --git a/src/test/codegen/return-value-in-reg.rs b/src/test/codegen/return-value-in-reg.rs new file mode 100644 index 0000000000..4bc0136c5e --- /dev/null +++ b/src/test/codegen/return-value-in-reg.rs @@ -0,0 +1,32 @@ +//! This test checks that types of up to 128 bits are returned by-value instead of via out-pointer. + +// compile-flags: -C no-prepopulate-passes -O +// only-x86_64 + +#![crate_type = "lib"] + +pub struct S { + a: u64, + b: u32, + c: u32, +} + +// CHECK: define i128 @modify(%S* noalias nocapture dereferenceable(16) %s) +#[no_mangle] +pub fn modify(s: S) -> S { + S { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c } +} + +#[repr(packed)] +pub struct TooBig { + a: u64, + b: u32, + c: u32, + d: u8, +} + +// CHECK: define void @m_big(%TooBig* [[ATTRS:.*sret.*]], %TooBig* [[ATTRS2:.*]] %s) +#[no_mangle] +pub fn m_big(s: TooBig) -> TooBig { + TooBig { a: s.a + s.a, b: s.b + s.b, c: s.c + s.c, d: s.d + s.d } +} diff --git a/src/test/codegen/try_identity.rs b/src/test/codegen/try_identity.rs index 30e7adfddf..d30b706eaf 100644 --- a/src/test/codegen/try_identity.rs +++ b/src/test/codegen/try_identity.rs @@ -1,4 +1,4 @@ -// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=2 +// compile-flags: -C no-prepopulate-passes -Z mir-opt-level=2 -Zunsound-mir-opts // Ensure that `x?` has no overhead on `Result` due to identity `match`es in lowering. // This requires inlining to trigger the MIR optimizations in `SimplifyArmIdentity`. diff --git a/src/test/codegen/tuple-layout-opt.rs b/src/test/codegen/tuple-layout-opt.rs new file mode 100644 index 0000000000..e86c75f3f4 --- /dev/null +++ b/src/test/codegen/tuple-layout-opt.rs @@ -0,0 +1,36 @@ +// ignore-emscripten +// compile-flags: -C no-prepopulate-passes + +// Test that tuples get optimized layout, in particular with a ZST in the last field (#63244) + +#![crate_type="lib"] + +type ScalarZstLast = (u128, ()); +// CHECK: define i128 @test_ScalarZstLast(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstLast(_: ScalarZstLast) -> ScalarZstLast { loop {} } + +type ScalarZstFirst = ((), u128); +// CHECK: define i128 @test_ScalarZstFirst(i128 %_1) +#[no_mangle] +pub fn test_ScalarZstFirst(_: ScalarZstFirst) -> ScalarZstFirst { loop {} } + +type ScalarPairZstLast = (u8, u128, ()); +// CHECK: define { i128, i8 } @test_ScalarPairZstLast(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstLast(_: ScalarPairZstLast) -> ScalarPairZstLast { loop {} } + +type ScalarPairZstFirst = ((), u8, u128); +// CHECK: define { i8, i128 } @test_ScalarPairZstFirst(i8 %_1.0, i128 %_1.1) +#[no_mangle] +pub fn test_ScalarPairZstFirst(_: ScalarPairZstFirst) -> ScalarPairZstFirst { loop {} } + +type ScalarPairLotsOfZsts = ((), u8, (), u128, ()); +// CHECK: define { i128, i8 } @test_ScalarPairLotsOfZsts(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLotsOfZsts(_: ScalarPairLotsOfZsts) -> ScalarPairLotsOfZsts { loop {} } + +type ScalarPairLottaNesting = (((), ((), u8, (), u128, ())), ()); +// CHECK: define { i128, i8 } @test_ScalarPairLottaNesting(i128 %_1.0, i8 %_1.1) +#[no_mangle] +pub fn test_ScalarPairLottaNesting(_: ScalarPairLottaNesting) -> ScalarPairLottaNesting { loop {} } diff --git a/src/test/codegen/x86_mmx.rs b/src/test/codegen/x86_mmx.rs deleted file mode 100644 index 9a58ef1c37..0000000000 --- a/src/test/codegen/x86_mmx.rs +++ /dev/null @@ -1,27 +0,0 @@ -// ignore-arm -// ignore-aarch64 -// ignore-emscripten -// ignore-mips -// ignore-mips64 -// ignore-powerpc -// ignore-powerpc64 -// ignore-powerpc64le -// ignore-riscv64 -// ignore-sparc -// ignore-sparc64 -// ignore-s390x -// compile-flags: -O - -#![feature(repr_simd)] -#![crate_type="lib"] - -#[repr(simd)] -#[derive(Clone, Copy)] -pub struct i8x8(u64); - -#[no_mangle] -pub fn a(a: &mut i8x8, b: i8x8) -> i8x8 { - // CHECK-LABEL: define void @a(x86_mmx*{{.*}}, x86_mmx*{{.*}}, x86_mmx*{{.*}}) - *a = b; - return b -} diff --git a/src/test/codegen/zst-offset.rs b/src/test/codegen/zst-offset.rs new file mode 100644 index 0000000000..0c015fca32 --- /dev/null +++ b/src/test/codegen/zst-offset.rs @@ -0,0 +1,43 @@ +// compile-flags: -C no-prepopulate-passes + +#![crate_type = "lib"] +#![feature(repr_simd)] + +// Hack to get the correct size for the length part in slices +// CHECK: @helper([[USIZE:i[0-9]+]] %_1) +#[no_mangle] +pub fn helper(_: usize) { +} + +// Check that we correctly generate a GEP for a ZST that is not included in Scalar layout +// CHECK-LABEL: @scalar_layout +#[no_mangle] +pub fn scalar_layout(s: &(u64, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast i64* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 8 + let x = &s.1; + &x; // keep variable in an alloca +} + +// Check that we correctly generate a GEP for a ZST that is not included in ScalarPair layout +// CHECK-LABEL: @scalarpair_layout +#[no_mangle] +pub fn scalarpair_layout(s: &(u64, u32, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast { i64, i32 }* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 12 + let x = &s.2; + &x; // keep variable in an alloca +} + +#[repr(simd)] +pub struct U64x4(u64, u64, u64, u64); + +// Check that we correctly generate a GEP for a ZST that is not included in Vector layout +// CHECK-LABEL: @vector_layout +#[no_mangle] +pub fn vector_layout(s: &(U64x4, ())) { +// CHECK: [[X0:%[0-9]+]] = bitcast <4 x i64>* %s to i8* +// CHECK-NEXT: [[X1:%[0-9]+]] = getelementptr i8, i8* [[X0]], [[USIZE]] 32 + let x = &s.1; + &x; // keep variable in an alloca +} diff --git a/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs b/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs index 3e5cdad7ab..b9ef2f3294 100644 --- a/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/compile-fail/auxiliary/panic-runtime-lang-items.rs @@ -11,3 +11,5 @@ use core::panic::PanicInfo; fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; diff --git a/src/test/compile-fail/consts/const-fn-error.rs b/src/test/compile-fail/consts/const-fn-error.rs index 7dbf7d1a38..68a4d414ff 100644 --- a/src/test/compile-fail/consts/const-fn-error.rs +++ b/src/test/compile-fail/consts/const-fn-error.rs @@ -5,9 +5,9 @@ const X : usize = 2; const fn f(x: usize) -> usize { let mut sum = 0; for i in 0..x { - //~^ ERROR E0015 - //~| ERROR E0015 - //~| ERROR E0658 + //~^ ERROR mutable references + //~| ERROR calls in constant functions + //~| ERROR calls in constant functions //~| ERROR E0080 //~| ERROR E0744 sum += i; diff --git a/src/test/compile-fail/issue-43733-2.rs b/src/test/compile-fail/issue-43733-2.rs index dae27c4785..61dd3a923f 100644 --- a/src/test/compile-fail/issue-43733-2.rs +++ b/src/test/compile-fail/issue-43733-2.rs @@ -22,7 +22,7 @@ impl Key { use std::thread::__FastLocalKeyInner as Key; static __KEY: Key<()> = Key::new(); -//~^ ERROR `std::cell::UnsafeCell>` cannot be shared between threads +//~^ ERROR `UnsafeCell>` cannot be shared between threads //~| ERROR cannot be shared between threads safely [E0277] fn main() {} diff --git a/src/test/compile-fail/issue-44415.rs b/src/test/compile-fail/issue-44415.rs index 763f857487..71e764620d 100644 --- a/src/test/compile-fail/issue-44415.rs +++ b/src/test/compile-fail/issue-44415.rs @@ -4,7 +4,7 @@ use std::intrinsics; struct Foo { bytes: [u8; unsafe { intrinsics::size_of::() }], - //~^ ERROR cycle detected when const-evaluating + checking + //~^ ERROR cycle detected when simplifying constant for the type system x: usize, } diff --git a/src/test/compile-fail/must_use-in-stdlib-traits.rs b/src/test/compile-fail/must_use-in-stdlib-traits.rs index 39472ae11f..70dddf61fb 100644 --- a/src/test/compile-fail/must_use-in-stdlib-traits.rs +++ b/src/test/compile-fail/must_use-in-stdlib-traits.rs @@ -39,9 +39,9 @@ fn square_fn() -> impl Fn(u32) -> u32 { } fn main() { - iterator(); //~ ERROR unused implementer of `std::iter::Iterator` that must be used - future(); //~ ERROR unused implementer of `std::future::Future` that must be used - square_fn_once(); //~ ERROR unused implementer of `std::ops::FnOnce` that must be used - square_fn_mut(); //~ ERROR unused implementer of `std::ops::FnMut` that must be used - square_fn(); //~ ERROR unused implementer of `std::ops::Fn` that must be used + iterator(); //~ ERROR unused implementer of `Iterator` that must be used + future(); //~ ERROR unused implementer of `Future` that must be used + square_fn_once(); //~ ERROR unused implementer of `FnOnce` that must be used + square_fn_mut(); //~ ERROR unused implementer of `FnMut` that must be used + square_fn(); //~ ERROR unused implementer of `Fn` that must be used } diff --git a/src/test/debuginfo/pretty-std-collections-hash.rs b/src/test/debuginfo/pretty-std-collections-hash.rs index e8f52deabd..9f59936a92 100644 --- a/src/test/debuginfo/pretty-std-collections-hash.rs +++ b/src/test/debuginfo/pretty-std-collections-hash.rs @@ -1,3 +1,7 @@ +// CDB doesn't like how libstd.natvis casts to tuples before this version. +// https://github.com/rust-lang/rust/issues/76352#issuecomment-687640746 +// min-cdb-version: 10.0.18362.1 + // cdb-only // compile-flags:-g diff --git a/src/test/incremental/dirty_clean.rs b/src/test/incremental/dirty_clean.rs index 2a1056df4c..02c9a0c579 100644 --- a/src/test/incremental/dirty_clean.rs +++ b/src/test/incremental/dirty_clean.rs @@ -27,7 +27,7 @@ mod y { #[rustc_clean(label="typeck", cfg="cfail2")] pub fn y() { - //[cfail2]~^ ERROR `typeck(y::y)` should be clean but is not + //[cfail2]~^ ERROR `typeck(y)` should be clean but is not x::x(); } } @@ -35,6 +35,6 @@ mod y { mod z { #[rustc_dirty(label="typeck", cfg="cfail2")] pub fn z() { - //[cfail2]~^ ERROR `typeck(z::z)` should be dirty but is not + //[cfail2]~^ ERROR `typeck(z)` should be dirty but is not } } diff --git a/src/test/incremental/issue-54242.rs b/src/test/incremental/issue-54242.rs index 1c700d44dd..25dc7cdf12 100644 --- a/src/test/incremental/issue-54242.rs +++ b/src/test/incremental/issue-54242.rs @@ -11,7 +11,7 @@ impl Tr for str { type Arr = [u8; 8]; #[cfg(cfail)] type Arr = [u8; Self::C]; - //[cfail]~^ ERROR cycle detected when const-evaluating + //[cfail]~^ ERROR cycle detected when simplifying constant } fn main() {} diff --git a/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff new file mode 100644 index 0000000000..28b8329606 --- /dev/null +++ b/src/test/mir-opt/76803_regression.encode.SimplifyBranchSame.diff @@ -0,0 +1,28 @@ +- // MIR for `encode` before SimplifyBranchSame ++ // MIR for `encode` after SimplifyBranchSame + + fn encode(_1: Type) -> Type { + debug v => _1; // in scope 0 at $DIR/76803_regression.rs:10:15: 10:16 + let mut _0: Type; // return place in scope 0 at $DIR/76803_regression.rs:10:27: 10:31 + let mut _2: isize; // in scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + + bb0: { + _2 = discriminant(_1); // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + switchInt(move _2) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/76803_regression.rs:12:9: 12:16 + } + + bb1: { + _0 = move _1; // scope 0 at $DIR/76803_regression.rs:13:14: 13:15 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 + } + + bb2: { + discriminant(_0) = 1; // scope 0 at $DIR/76803_regression.rs:12:20: 12:27 + goto -> bb3; // scope 0 at $DIR/76803_regression.rs:11:5: 14:6 + } + + bb3: { + return; // scope 0 at $DIR/76803_regression.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/76803_regression.rs b/src/test/mir-opt/76803_regression.rs new file mode 100644 index 0000000000..05dc3c9784 --- /dev/null +++ b/src/test/mir-opt/76803_regression.rs @@ -0,0 +1,19 @@ +// compile-flags: -Z mir-opt-level=1 +// EMIT_MIR 76803_regression.encode.SimplifyBranchSame.diff + +#[derive(Debug, Eq, PartialEq)] +pub enum Type { + A, + B, +} + +pub fn encode(v: Type) -> Type { + match v { + Type::A => Type::B, + _ => v, + } +} + +fn main() { + assert_eq!(Type::B, encode(Type::A)); +} diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir similarity index 96% rename from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit rename to src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir index 2216c2bc92..deb5dbad7d 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.32bit +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.32bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { diff --git a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir similarity index 96% rename from src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit rename to src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir index 2216c2bc92..deb5dbad7d 100644 --- a/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.mir.64bit +++ b/src/test/mir-opt/array_index_is_temporary.main.SimplifyCfg-elaborate-drops.after.64bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _7 = _2; // scope 3 at $DIR/array-index-is-temporary.rs:16:7: 16:8 _8 = Len(_1); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 _9 = Lt(_7, _8); // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 3 at $DIR/array-index-is-temporary.rs:16:5: 16:9 } bb2: { diff --git a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir index 06869735f1..50326253ce 100644 --- a/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/basic_assignment.main.SimplifyCfg-initial.after.mir @@ -35,7 +35,7 @@ fn main() -> () { _2 = move _3; // scope 2 at $DIR/basic_assignment.rs:16:5: 16:24 StorageDead(_3); // scope 2 at $DIR/basic_assignment.rs:16:23: 16:24 StorageLive(_4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 - _4 = std::option::Option::>::None; // scope 2 at $DIR/basic_assignment.rs:18:36: 18:40 + _4 = Option::>::None; // scope 2 at $DIR/basic_assignment.rs:18:36: 18:40 FakeRead(ForLet, _4); // scope 2 at $DIR/basic_assignment.rs:18:9: 18:15 AscribeUserType(_4, o, UserTypeProjection { base: UserType(1), projs: [] }); // scope 2 at $DIR/basic_assignment.rs:18:17: 18:33 StorageLive(_5); // scope 3 at $DIR/basic_assignment.rs:19:9: 19:15 diff --git a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir index 46dbb997ef..408efb4cad 100644 --- a/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/box_expr.main.ElaborateDrops.before.mir @@ -38,7 +38,7 @@ fn main() -> () { 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: bb5, unwind: bb7]; // scope 1 at $DIR/box_expr.rs:8:5: 8:12 + _3 = std::mem::drop::>(move _4) -> [return: bb5, unwind: bb7]; // 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()) } diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff similarity index 94% rename from src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit rename to src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff index 61e987cc68..979e5bc4d2 100644 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.64bit +++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.32bit.diff @@ -32,7 +32,7 @@ - _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { @@ -44,7 +44,7 @@ - _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { diff --git a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff similarity index 94% rename from src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit rename to src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff index 61e987cc68..979e5bc4d2 100644 --- a/src/test/mir-opt/combine_array_len.norm2.InstCombine.diff.32bit +++ b/src/test/mir-opt/combine_array_len.norm2.InstCombine.64bit.diff @@ -32,7 +32,7 @@ - _4 = Len(_1); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + _4 = const 2_usize; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 _5 = Lt(_3, _4); // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/combine_array_len.rs:5:13: 5:17 } bb1: { @@ -44,7 +44,7 @@ - _8 = Len(_1); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + _8 = const 2_usize; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 _9 = Lt(_7, _8); // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 - assert(move _9, "index out of bounds: the len is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 + assert(move _9, "index out of bounds: the length is {} but the index is {}", move _8, _7) -> bb2; // scope 1 at $DIR/combine_array_len.rs:6:13: 6:17 } bb2: { diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir similarity index 76% rename from src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir index 09a4eca938..8b09eade06 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.32bit +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.32bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 - _2 = const {alloc0: &&[(std::option::Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + _2 = const {alloc0: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 // ty::Const // + ty: &&[(std::option::Option, &[&str])] // + val: Value(Scalar(alloc0)) @@ -24,42 +24,42 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc17─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc14─╼ 03 00 00 00 │ ╾──╼.... } -alloc17 (size: 48, align: 4) { +alloc14 (size: 48, align: 4) { 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc4──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc13─╼ 03 00 00 00 │ ....*...╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc7──╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc11─╼ 03 00 00 00 │ ....*...╾──╼.... } alloc4 (size: 0, align: 4) {} -alloc8 (size: 16, align: 4) { - ╾─alloc7──╼ 03 00 00 00 ╾─alloc9──╼ 03 00 00 00 │ ╾──╼....╾──╼.... +alloc7 (size: 16, align: 4) { + ╾─alloc6──╼ 03 00 00 00 ╾─alloc8──╼ 03 00 00 00 │ ╾──╼....╾──╼.... } -alloc7 (size: 3, align: 1) { +alloc6 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc9 (size: 3, align: 1) { +alloc8 (size: 3, align: 1) { 62 61 72 │ bar } -alloc13 (size: 24, align: 4) { - 0x00 │ ╾─alloc12─╼ 03 00 00 00 ╾─alloc14─╼ 03 00 00 00 │ ╾──╼....╾──╼.... - 0x10 │ ╾─alloc15─╼ 04 00 00 00 │ ╾──╼.... +alloc11 (size: 24, align: 4) { + 0x00 │ ╾─alloc10─╼ 03 00 00 00 ╾─alloc12─╼ 03 00 00 00 │ ╾──╼....╾──╼.... + 0x10 │ ╾─alloc13─╼ 04 00 00 00 │ ╾──╼.... } -alloc12 (size: 3, align: 1) { +alloc10 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc14 (size: 3, align: 1) { +alloc12 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc15 (size: 4, align: 1) { +alloc13 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir similarity index 76% rename from src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir index b10cc3e098..2853a0ac18 100644 --- a/src/test/mir-opt/const_allocation.main.ConstProp.after.mir.64bit +++ b/src/test/mir-opt/const_allocation.main.ConstProp.after.64bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 StorageLive(_2); // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 - _2 = const {alloc0: &&[(std::option::Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 + _2 = const {alloc0: &&[(Option, &[&str])]}; // scope 0 at $DIR/const_allocation.rs:8:5: 8:8 // ty::Const // + ty: &&[(std::option::Option, &[&str])] // + val: Value(Scalar(alloc0)) @@ -24,46 +24,46 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc17───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc17 (size: 72, align: 8) { +alloc14 (size: 72, align: 8) { 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc4────────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc8────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc13───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc7────────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc11───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } alloc4 (size: 0, align: 8) {} -alloc8 (size: 32, align: 8) { - 0x00 │ ╾───────alloc7────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc9────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ +alloc7 (size: 32, align: 8) { + 0x00 │ ╾───────alloc6────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾───────alloc8────────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc7 (size: 3, align: 1) { +alloc6 (size: 3, align: 1) { 66 6f 6f │ foo } -alloc9 (size: 3, align: 1) { +alloc8 (size: 3, align: 1) { 62 61 72 │ bar } -alloc13 (size: 48, align: 8) { - 0x00 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x10 │ ╾───────alloc14───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x20 │ ╾───────alloc15───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ +alloc11 (size: 48, align: 8) { + 0x00 │ ╾───────alloc10───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x10 │ ╾───────alloc12───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x20 │ ╾───────alloc13───────╼ 04 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc12 (size: 3, align: 1) { +alloc10 (size: 3, align: 1) { 6d 65 68 │ meh } -alloc14 (size: 3, align: 1) { +alloc12 (size: 3, align: 1) { 6d 6f 70 │ mop } -alloc15 (size: 4, align: 1) { +alloc13 (size: 4, align: 1) { 6d c3 b6 70 │ m..p } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir similarity index 77% rename from src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir index 19cbab74ab..710ffeeda0 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.32bit +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.32bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 - _2 = const {alloc0: &&[(std::option::Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + _2 = const {alloc0: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 // ty::Const // + ty: &&[(std::option::Option, &[&u8])] // + val: Value(Scalar(alloc0)) @@ -24,41 +24,41 @@ fn main() -> () { } alloc0 (static: FOO, size: 8, align: 4) { - ╾─alloc23─╼ 03 00 00 00 │ ╾──╼.... + ╾─alloc20─╼ 03 00 00 00 │ ╾──╼.... } -alloc23 (size: 48, align: 4) { +alloc20 (size: 48, align: 4) { 0x00 │ 00 00 00 00 __ __ __ __ ╾─alloc8──╼ 00 00 00 00 │ ....░░░░╾──╼.... - 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc13─╼ 02 00 00 00 │ ....░░░░╾──╼.... - 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc21─╼ 03 00 00 00 │ ....*...╾──╼.... + 0x10 │ 00 00 00 00 __ __ __ __ ╾─alloc12─╼ 02 00 00 00 │ ....░░░░╾──╼.... + 0x20 │ 01 00 00 00 2a 00 00 00 ╾─alloc19─╼ 03 00 00 00 │ ....*...╾──╼.... } alloc8 (size: 0, align: 4) {} -alloc13 (size: 8, align: 4) { - ╾─alloc11─╼ ╾─alloc12─╼ │ ╾──╼╾──╼ +alloc12 (size: 8, align: 4) { + ╾─alloc10─╼ ╾─alloc11─╼ │ ╾──╼╾──╼ } -alloc11 (size: 1, align: 1) { +alloc10 (size: 1, align: 1) { 05 │ . } -alloc12 (size: 1, align: 1) { +alloc11 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 12, align: 4) { - ╾─a17+0x3─╼ ╾─alloc18─╼ ╾─a20+0x2─╼ │ ╾──╼╾──╼╾──╼ +alloc19 (size: 12, align: 4) { + ╾─a15+0x3─╼ ╾─alloc16─╼ ╾─a18+0x2─╼ │ ╾──╼╾──╼╾──╼ } -alloc17 (size: 4, align: 1) { +alloc15 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc18 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +alloc18 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir similarity index 75% rename from src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir index 4dd960c8dd..97a7f76f6b 100644 --- a/src/test/mir-opt/const_allocation2.main.ConstProp.after.mir.64bit +++ b/src/test/mir-opt/const_allocation2.main.ConstProp.after.64bit.mir @@ -8,7 +8,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 StorageLive(_2); // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 - _2 = const {alloc0: &&[(std::option::Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 + _2 = const {alloc0: &&[(Option, &[&u8])]}; // scope 0 at $DIR/const_allocation2.rs:5:5: 5:8 // ty::Const // + ty: &&[(std::option::Option, &[&u8])] // + val: Value(Scalar(alloc0)) @@ -24,44 +24,44 @@ fn main() -> () { } alloc0 (static: FOO, size: 16, align: 8) { - ╾───────alloc23───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ + ╾───────alloc20───────╼ 03 00 00 00 00 00 00 00 │ ╾──────╼........ } -alloc23 (size: 72, align: 8) { +alloc20 (size: 72, align: 8) { 0x00 │ 00 00 00 00 __ __ __ __ ╾───────alloc8────────╼ │ ....░░░░╾──────╼ 0x10 │ 00 00 00 00 00 00 00 00 00 00 00 00 __ __ __ __ │ ............░░░░ - 0x20 │ ╾───────alloc13───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ - 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc21───────╼ │ ....*...╾──────╼ + 0x20 │ ╾───────alloc12───────╼ 02 00 00 00 00 00 00 00 │ ╾──────╼........ + 0x30 │ 01 00 00 00 2a 00 00 00 ╾───────alloc19───────╼ │ ....*...╾──────╼ 0x40 │ 03 00 00 00 00 00 00 00 │ ........ } alloc8 (size: 0, align: 8) {} -alloc13 (size: 16, align: 8) { - ╾───────alloc11───────╼ ╾───────alloc12───────╼ │ ╾──────╼╾──────╼ +alloc12 (size: 16, align: 8) { + ╾───────alloc10───────╼ ╾───────alloc11───────╼ │ ╾──────╼╾──────╼ } -alloc11 (size: 1, align: 1) { +alloc10 (size: 1, align: 1) { 05 │ . } -alloc12 (size: 1, align: 1) { +alloc11 (size: 1, align: 1) { 06 │ . } -alloc21 (size: 24, align: 8) { - 0x00 │ ╾─────alloc17+0x3─────╼ ╾───────alloc18───────╼ │ ╾──────╼╾──────╼ - 0x10 │ ╾─────alloc20+0x2─────╼ │ ╾──────╼ +alloc19 (size: 24, align: 8) { + 0x00 │ ╾─────alloc15+0x3─────╼ ╾───────alloc16───────╼ │ ╾──────╼╾──────╼ + 0x10 │ ╾─────alloc18+0x2─────╼ │ ╾──────╼ } -alloc17 (size: 4, align: 1) { +alloc15 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } -alloc18 (size: 1, align: 1) { +alloc16 (size: 1, align: 1) { 2a │ * } -alloc20 (size: 4, align: 1) { +alloc18 (size: 4, align: 1) { 2a 45 15 6f │ *E.o } diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.32bit rename to src/test/mir-opt/const_allocation3.main.ConstProp.after.32bit.mir diff --git a/src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit b/src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_allocation3.main.ConstProp.after.mir.64bit rename to src/test/mir-opt/const_allocation3.main.ConstProp.after.64bit.mir diff --git a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff index 6acb8e46e7..c8c15792a2 100644 --- a/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.BAR.PromoteTemps.diff @@ -22,7 +22,7 @@ - // + ty: &i32 - // + val: Value(Scalar(alloc0)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:9:33: 9:34 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc0)) } @@ -30,7 +30,7 @@ - _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 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:6 ~ const_promotion_extern_static[317d]::BAR), const_param_did: None }, [], 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 _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:9:31: 9:44 diff --git a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff index 2f7a2d7288..ddf79fca9f 100644 --- a/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff +++ b/src/test/mir-opt/const_promotion_extern_static.FOO.PromoteTemps.diff @@ -24,7 +24,7 @@ - // + ty: &i32 - // + val: Value(Scalar(alloc2)) + // + ty: &[&i32; 1] -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], Some(promoted[0])) // mir::Constant - // + span: $DIR/const-promotion-extern-static.rs:13:42: 13:43 - // + literal: Const { ty: &i32, val: Value(Scalar(alloc2)) } @@ -32,7 +32,7 @@ - _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 -+ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &[&i32; 1], val: Unevaluated(WithOptConstParam { did: DefId(0:7 ~ const_promotion_extern_static[317d]::FOO), const_param_did: None }, [], 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 _0 = core::slice::::as_ptr(move _1) -> [return: bb2, unwind: bb1]; // scope 0 at $DIR/const-promotion-extern-static.rs:13:31: 13:55 diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff index 1ccda1c500..4664934690 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.32bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32 _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33 - _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:5:18: 5:33 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 + _5 = const true; // scope 0 at $DIR/array_index.rs:5:18: 5:33 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 } bb1: { diff --git a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff index 1ccda1c500..4664934690 100644 --- a/src/test/mir-opt/const_prop/array_index.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/array_index.main.ConstProp.64bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/array_index.rs:5:31: 5:32 _4 = const 4_usize; // scope 0 at $DIR/array_index.rs:5:18: 5:33 - _5 = Lt(_3, _4); // scope 0 at $DIR/array_index.rs:5:18: 5:33 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 + _5 = const true; // scope 0 at $DIR/array_index.rs:5:18: 5:33 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 4_usize, const 2_usize) -> bb1; // scope 0 at $DIR/array_index.rs:5:18: 5:33 } bb1: { diff --git a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff index 30ff6ec860..ba081f95fa 100644 --- a/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_div_by_zero.main.ConstProp.diff @@ -24,21 +24,21 @@ StorageLive(_3); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 - _3 = _1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 - _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -- assert(!move _4, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- assert(!move _4, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _3 = const 0_i32; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:18: 5:19 + _4 = const true; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -+ assert(!const true, "attempt to divide {} by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ assert(!const true, "attempt to divide `{}` by zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 } bb1: { - _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 - _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 - _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -- assert(!move _7, "attempt to compute `{} / {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 +- assert(!move _7, "attempt to compute `{} / {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _5 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _6 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 + _7 = const false; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 -+ assert(!const false, "attempt to compute `{} / {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 ++ assert(!const false, "attempt to compute `{} / {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_div_by_zero.rs:5:14: 5:19 } bb2: { diff --git a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff index 6e6ce0a613..a843cacf4d 100644 --- a/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/bad_op_mod_by_zero.main.ConstProp.diff @@ -24,21 +24,21 @@ StorageLive(_3); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 - _3 = _1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 - _4 = Eq(_3, const 0_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -- assert(!move _4, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- assert(!move _4, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _3 = const 0_i32; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:18: 5:19 + _4 = const true; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -+ assert(!const true, "attempt to calculate the remainder of {} with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ assert(!const true, "attempt to calculate the remainder of `{}` with a divisor of zero", const 1_i32) -> bb1; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 } bb1: { - _5 = Eq(_3, const -1_i32); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 - _6 = Eq(const 1_i32, const i32::MIN); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 - _7 = BitAnd(move _5, move _6); // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -- assert(!move _7, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 +- assert(!move _7, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, _3) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _5 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _6 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 + _7 = const false; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 -+ assert(!const false, "attempt to compute the remainder of `{} % {}` which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 ++ assert(!const false, "attempt to compute the remainder of `{} % {}`, which would overflow", const 1_i32, const 0_i32) -> bb2; // scope 1 at $DIR/bad_op_mod_by_zero.rs:5:14: 5:19 } bb2: { diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff index 245a7de5e9..8c10b3518d 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.32bit.diff @@ -28,10 +28,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 @@ -42,9 +42,9 @@ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 - _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -+ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 } bb1: { diff --git a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff index 245a7de5e9..8c10b3518d 100644 --- a/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/bad_op_unsafe_oob_for_slices.main.ConstProp.64bit.diff @@ -28,10 +28,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 // ty::Const // + ty: &[i32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 - // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[i32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ bad_op_unsafe_oob_for_slices[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _3 = _9; // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _2 = &raw const (*_3); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 _1 = move _2 as *const [i32] (Pointer(Unsize)); // scope 0 at $DIR/bad_op_unsafe_oob_for_slices.rs:5:25: 5:35 @@ -42,9 +42,9 @@ _6 = const 3_usize; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:23: 7:24 _7 = Len((*_1)); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 - _8 = Lt(_6, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 +- assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 + _8 = Lt(const 3_usize, _7); // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 -+ assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 ++ assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, const 3_usize) -> bb1; // scope 2 at $DIR/bad_op_unsafe_oob_for_slices.rs:7:18: 7:25 } bb1: { diff --git a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff index 125d150d3d..f01676b6da 100644 --- a/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/checked_add.main.ConstProp.diff @@ -12,7 +12,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/checked_add.rs:5:9: 5:10 - _2 = CheckedAdd(const 1_u32, const 1_u32); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + _2 = const (2_u32, false); // scope 0 at $DIR/checked_add.rs:5:18: 5:23 + // ty::Const + // + ty: (u32, bool) @@ -20,7 +20,7 @@ + // mir::Constant + // + span: $DIR/checked_add.rs:5:18: 5:23 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [2, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 1_u32, const 1_u32) -> bb1; // scope 0 at $DIR/checked_add.rs:5:18: 5:23 } bb1: { diff --git a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff index bfc848bbfc..6034645864 100644 --- a/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/const_prop_fails_gracefully.main.ConstProp.diff @@ -16,13 +16,13 @@ StorageLive(_1); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:9: 7:10 StorageLive(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:30 StorageLive(_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - _3 = const main::FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 + _3 = const FOO; // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, [], None) // mir::Constant // + span: $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main[0]::FOO[0]), const_param_did: None }, [], None) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ const_prop_fails_gracefully[317d]::main::FOO), const_param_did: None }, [], None) } _2 = &raw const (*_3); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:16 _1 = move _2 as usize (Misc); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:13: 7:39 StorageDead(_2); // scope 0 at $DIR/const_prop_fails_gracefully.rs:7:38: 7:39 diff --git a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff index b55e3a6353..80b7e7ecdd 100644 --- a/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff +++ b/src/test/mir-opt/const_prop/control_flow_simplification.hello.ConstProp.diff @@ -22,7 +22,7 @@ bb2: { StorageLive(_2); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "explicit panic"); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/discriminant.main.ConstProp.32bit.diff diff --git a/src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/const_prop/discriminant.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/discriminant.main.ConstProp.64bit.diff diff --git a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff index e37d0a3ed9..8c7b35887c 100644 --- a/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/indirect.main.ConstProp.diff @@ -15,7 +15,7 @@ StorageLive(_2); // scope 0 at $DIR/indirect.rs:5:13: 5:25 - _2 = const 2_u32 as u8 (Misc); // scope 0 at $DIR/indirect.rs:5:13: 5:25 - _3 = CheckedAdd(_2, const 1_u8); // scope 0 at $DIR/indirect.rs:5:13: 5:29 -- assert(!move (_3.1: bool), "attempt to compute `{} + {}` which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 +- assert(!move (_3.1: bool), "attempt to compute `{} + {}`, which would overflow", move _2, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 + _2 = const 2_u8; // scope 0 at $DIR/indirect.rs:5:13: 5:25 + _3 = const (3_u8, false); // scope 0 at $DIR/indirect.rs:5:13: 5:29 + // ty::Const @@ -24,7 +24,7 @@ + // mir::Constant + // + span: $DIR/indirect.rs:5:13: 5:29 + // + literal: Const { ty: (u8, bool), val: Value(ByRef { alloc: Allocation { bytes: [3, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [3], len: Size { raw: 2 } }, size: Size { raw: 2 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u8, const 1_u8) -> bb1; // scope 0 at $DIR/indirect.rs:5:13: 5:29 } bb1: { diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff index b1a9e1cb5d..fa790822b6 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.32bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 - _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 } bb1: { diff --git a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff similarity index 86% rename from src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff index b1a9e1cb5d..fa790822b6 100644 --- a/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/large_array_index.main.ConstProp.64bit.diff @@ -20,9 +20,9 @@ _3 = const 2_usize; // scope 0 at $DIR/large_array_index.rs:6:30: 6:31 _4 = const 5000_usize; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 - _5 = Lt(_3, _4); // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -- assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 +- assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 + _5 = const true; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 5000_usize, const 2_usize) -> bb1; // scope 0 at $DIR/large_array_index.rs:6:17: 6:32 } bb1: { diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff index 2c8e7ada39..53ffc01cca 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.32bit.diff @@ -25,7 +25,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + // ty::Const + // + ty: (i32, bool) @@ -33,7 +33,7 @@ + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } bb1: { @@ -46,9 +46,9 @@ _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 - _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -- assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 } bb2: { diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff similarity index 89% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff index 2c8e7ada39..53ffc01cca 100644 --- a/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/optimizes_into_variable.main.ConstProp.64bit.diff @@ -25,7 +25,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/optimizes_into_variable.rs:12:9: 12:10 - _2 = CheckedAdd(const 2_i32, const 2_i32); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 -- assert(!move (_2.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 +- assert(!move (_2.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + _2 = const (4_i32, false); // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 + // ty::Const + // + ty: (i32, bool) @@ -33,7 +33,7 @@ + // mir::Constant + // + span: $DIR/optimizes_into_variable.rs:12:13: 12:18 + // + literal: Const { ty: (i32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_i32, const 2_i32) -> bb1; // scope 0 at $DIR/optimizes_into_variable.rs:12:13: 12:18 } bb1: { @@ -46,9 +46,9 @@ _5 = const 3_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:32: 13:33 _6 = const 6_usize; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 - _7 = Lt(_5, _6); // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -- assert(move _7, "index out of bounds: the len is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 +- assert(move _7, "index out of bounds: the length is {} but the index is {}", move _6, _5) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 + _7 = const true; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 6_usize, const 3_usize) -> bb2; // scope 1 at $DIR/optimizes_into_variable.rs:13:13: 13:34 } bb2: { diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.32bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.32bit.mir diff --git a/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit b/src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir similarity index 100% rename from src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.mir.64bit rename to src/test/mir-opt/const_prop/optimizes_into_variable.main.SimplifyLocals.after.64bit.mir diff --git a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff index 31061233ee..4fd1b8b227 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.ConstProp.diff @@ -14,10 +14,10 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref.rs:5:6: 5:10 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _2 = _4; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 - _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 + _1 = const 4_i32; // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 diff --git a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff index c9caf07a73..e7ebfee7f3 100644 --- a/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref.main.PromoteTemps.diff @@ -17,10 +17,10 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 + // ty::Const + // + ty: &i32 -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref.rs:5:6: 5:10 -+ // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _2 = &(*_4); // scope 0 at $DIR/ref_deref.rs:5:6: 5:10 _1 = (*_2); // scope 0 at $DIR/ref_deref.rs:5:5: 5:10 - StorageDead(_3); // scope 0 at $DIR/ref_deref.rs:5:10: 5:11 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff index e9398df132..812c7c9771 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.ConstProp.diff @@ -14,10 +14,10 @@ _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 // ty::Const // + ty: &(i32, i32) - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/ref_deref_project.rs:5:6: 5:17 - // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 StorageDead(_2); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff index 43e4b32a6c..588c291bcc 100644 --- a/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff +++ b/src/test/mir-opt/const_prop/ref_deref_project.main.PromoteTemps.diff @@ -17,10 +17,10 @@ + _4 = const main::promoted[0]; // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 + // ty::Const + // + ty: &(i32, i32) -+ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) ++ // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) + // mir::Constant + // + span: $DIR/ref_deref_project.rs:5:6: 5:17 -+ // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } ++ // + literal: Const { ty: &(i32, i32), val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ ref_deref_project[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _2 = &((*_4).1: i32); // scope 0 at $DIR/ref_deref_project.rs:5:6: 5:17 _1 = (*_2); // scope 0 at $DIR/ref_deref_project.rs:5:5: 5:17 - StorageDead(_3); // scope 0 at $DIR/ref_deref_project.rs:5:17: 5:18 diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff similarity index 88% rename from src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff index f14004fc25..98f409f326 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.32bit.diff @@ -22,9 +22,9 @@ _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27 _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28 - _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:6:18: 6:28 -- assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 + _6 = const true; // scope 0 at $DIR/repeat.rs:6:18: 6:28 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 } bb1: { diff --git a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff similarity index 88% rename from src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff index f14004fc25..98f409f326 100644 --- a/src/test/mir-opt/const_prop/repeat.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/repeat.main.ConstProp.64bit.diff @@ -22,9 +22,9 @@ _4 = const 2_usize; // scope 0 at $DIR/repeat.rs:6:26: 6:27 _5 = const 8_usize; // scope 0 at $DIR/repeat.rs:6:18: 6:28 - _6 = Lt(_4, _5); // scope 0 at $DIR/repeat.rs:6:18: 6:28 -- assert(move _6, "index out of bounds: the len is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 +- assert(move _6, "index out of bounds: the length is {} but the index is {}", move _5, _4) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 + _6 = const true; // scope 0 at $DIR/repeat.rs:6:18: 6:28 -+ assert(const true, "index out of bounds: the len is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 ++ assert(const true, "index out of bounds: the length is {} but the index is {}", const 8_usize, const 2_usize) -> bb1; // scope 0 at $DIR/repeat.rs:6:18: 6:28 } bb1: { diff --git a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff index d61a04d1e0..fc8a543723 100644 --- a/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff +++ b/src/test/mir-opt/const_prop/return_place.add.ConstProp.diff @@ -7,7 +7,7 @@ bb0: { - _1 = CheckedAdd(const 2_u32, const 2_u32); // scope 0 at $DIR/return_place.rs:6:5: 6:10 -- assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 +- assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 + _1 = const (4_u32, false); // scope 0 at $DIR/return_place.rs:6:5: 6:10 + // ty::Const + // + ty: (u32, bool) @@ -15,7 +15,7 @@ + // mir::Constant + // + span: $DIR/return_place.rs:6:5: 6:10 + // + literal: Const { ty: (u32, bool), val: Value(ByRef { alloc: Allocation { bytes: [4, 0, 0, 0, 0, 0, 0, 0], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [31], len: Size { raw: 8 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) } -+ assert(!const false, "attempt to compute `{} + {}` which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 ++ assert(!const false, "attempt to compute `{} + {}`, which would overflow", const 2_u32, const 2_u32) -> bb1; // scope 0 at $DIR/return_place.rs:6:5: 6:10 } bb1: { diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff similarity index 87% rename from src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit rename to src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff index 02c4391baf..240cc8e231 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.32bit +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.32bit.diff @@ -21,10 +21,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], 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 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 @@ -33,10 +33,10 @@ _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 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // 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 len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // 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 } bb1: { diff --git a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff similarity index 87% rename from src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit rename to src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff index 02c4391baf..240cc8e231 100644 --- a/src/test/mir-opt/const_prop/slice_len.main.ConstProp.diff.64bit +++ b/src/test/mir-opt/const_prop/slice_len.main.ConstProp.64bit.diff @@ -21,10 +21,10 @@ _9 = const main::promoted[0]; // scope 0 at $DIR/slice_len.rs:5:6: 5:19 // ty::Const // + ty: &[u32; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/slice_len.rs:5:6: 5:19 - // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[u32; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ slice_len[317d]::main), const_param_did: None }, [], 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 _2 = move _3 as &[u32] (Pointer(Unsize)); // scope 0 at $DIR/slice_len.rs:5:6: 5:19 @@ -33,10 +33,10 @@ _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 - _8 = Lt(_6, _7); // scope 0 at $DIR/slice_len.rs:5:5: 5:33 -- assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> bb1; // 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 len is {} but the index is {}", const 3_usize, const 1_usize) -> bb1; // 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 } bb1: { diff --git a/src/test/mir-opt/copy_propagation.rs b/src/test/mir-opt/copy_propagation.rs index ee460a488b..8283ec73d0 100644 --- a/src/test/mir-opt/copy_propagation.rs +++ b/src/test/mir-opt/copy_propagation.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR copy_propagation.test.CopyPropagation.diff fn test(x: u32) -> u32 { diff --git a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff index f2838638ac..152d159063 100644 --- a/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation.test.CopyPropagation.diff @@ -2,24 +2,19 @@ + // MIR for `test` after CopyPropagation fn test(_1: u32) -> u32 { - debug x => _1; // in scope 0 at $DIR/copy_propagation.rs:3:9: 3:10 - let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:3:20: 3:23 - let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 + debug x => _1; // in scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 + let mut _0: u32; // return place in scope 0 at $DIR/copy_propagation.rs:4:20: 4:23 + let _2: u32; // in scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 scope 1 { -- debug y => _2; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 -+ debug y => _1; // in scope 1 at $DIR/copy_propagation.rs:4:9: 4:10 + debug y => _0; // in scope 1 at $DIR/copy_propagation.rs:5:9: 5:10 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 -- _2 = _1; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 -- _0 = _2; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 -- StorageDead(_2); // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 -+ nop; // scope 0 at $DIR/copy_propagation.rs:4:9: 4:10 -+ nop; // scope 0 at $DIR/copy_propagation.rs:4:13: 4:14 -+ _0 = _1; // scope 1 at $DIR/copy_propagation.rs:5:5: 5:6 -+ nop; // scope 0 at $DIR/copy_propagation.rs:6:1: 6:2 - return; // scope 0 at $DIR/copy_propagation.rs:6:2: 6:2 + nop; // scope 0 at $DIR/copy_propagation.rs:5:9: 5:10 + _0 = _1; // scope 0 at $DIR/copy_propagation.rs:5:13: 5:14 + nop; // scope 1 at $DIR/copy_propagation.rs:6:5: 6:6 + nop; // scope 0 at $DIR/copy_propagation.rs:7:1: 7:2 + return; // scope 0 at $DIR/copy_propagation.rs:7:2: 7:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff index a4d60ae25d..8aab2299d2 100644 --- a/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.arg_src.CopyPropagation.diff @@ -6,15 +6,15 @@ let mut _0: i32; // return place in scope 0 at $DIR/copy_propagation_arg.rs:27:27: 27:30 let _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 scope 1 { - debug y => _2; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + debug y => _0; // in scope 1 at $DIR/copy_propagation_arg.rs:28:9: 28:10 } bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 - _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:28:9: 28:10 + _0 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:28:13: 28:14 _1 = const 123_i32; // scope 1 at $DIR/copy_propagation_arg.rs:29:5: 29:12 - _0 = _2; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 + nop; // scope 1 at $DIR/copy_propagation_arg.rs:30:5: 30:6 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:31:1: 31:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:31:2: 31:2 } } diff --git a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff index b20003bd7c..1ea51fec71 100644 --- a/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.baz.CopyPropagation.diff @@ -7,10 +7,10 @@ let mut _2: i32; // in scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - _2 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 - _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:5: 23:10 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:23:9: 23:10 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:21:20: 24:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:24:2: 24:2 } diff --git a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff index d07a4c0541..48ab37a239 100644 --- a/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff +++ b/src/test/mir-opt/copy_propagation_arg.foo.CopyPropagation.diff @@ -8,10 +8,10 @@ let mut _3: u8; // in scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 bb0: { - StorageLive(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 StorageLive(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 _3 = _1; // scope 0 at $DIR/copy_propagation_arg.rs:11:15: 11:16 - _2 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 + _1 = dummy(move _3) -> bb1; // scope 0 at $DIR/copy_propagation_arg.rs:11:9: 11:17 // mir::Constant // + span: $DIR/copy_propagation_arg.rs:11:9: 11:14 // + literal: Const { ty: fn(u8) -> u8 {dummy}, val: Value(Scalar()) } @@ -19,8 +19,8 @@ bb1: { StorageDead(_3); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 - _1 = move _2; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 - StorageDead(_2); // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:5: 11:17 + nop; // scope 0 at $DIR/copy_propagation_arg.rs:11:16: 11:17 _0 = const (); // scope 0 at $DIR/copy_propagation_arg.rs:9:19: 12:2 return; // scope 0 at $DIR/copy_propagation_arg.rs:12:2: 12:2 } diff --git a/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff new file mode 100644 index 0000000000..9c213eaed3 --- /dev/null +++ b/src/test/mir-opt/dest-prop/branch.main.DestinationPropagation.diff @@ -0,0 +1,73 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/branch.rs:12:11: 12:11 + let _1: i32; // in scope 0 at $DIR/branch.rs:13:9: 13:10 + let mut _3: bool; // in scope 0 at $DIR/branch.rs:15:16: 15:22 + let _4: i32; // in scope 0 at $DIR/branch.rs:18:9: 18:14 + scope 1 { +- debug x => _1; // in scope 1 at $DIR/branch.rs:13:9: 13:10 ++ debug x => _2; // in scope 1 at $DIR/branch.rs:13:9: 13:10 + let _2: i32; // in scope 1 at $DIR/branch.rs:15:9: 15:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/branch.rs:15:9: 15:10 + } + } + + bb0: { +- StorageLive(_1); // scope 0 at $DIR/branch.rs:13:9: 13:10 +- _1 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 ++ nop; // scope 0 at $DIR/branch.rs:13:9: 13:10 ++ _2 = val() -> bb1; // scope 0 at $DIR/branch.rs:13:13: 13:18 + // mir::Constant + // + span: $DIR/branch.rs:13:13: 13:16 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb1: { +- StorageLive(_2); // scope 1 at $DIR/branch.rs:15:9: 15:10 ++ nop; // scope 1 at $DIR/branch.rs:15:9: 15:10 + StorageLive(_3); // scope 1 at $DIR/branch.rs:15:16: 15:22 + _3 = cond() -> bb2; // scope 1 at $DIR/branch.rs:15:16: 15:22 + // mir::Constant + // + span: $DIR/branch.rs:15:16: 15:20 + // + literal: Const { ty: fn() -> bool {cond}, val: Value(Scalar()) } + } + + bb2: { + switchInt(_3) -> [false: bb3, otherwise: bb4]; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb3: { + StorageLive(_4); // scope 1 at $DIR/branch.rs:18:9: 18:14 + _4 = val() -> bb5; // scope 1 at $DIR/branch.rs:18:9: 18:14 + // mir::Constant + // + span: $DIR/branch.rs:18:9: 18:12 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb4: { +- _2 = _1; // scope 1 at $DIR/branch.rs:16:9: 16:10 ++ nop; // scope 1 at $DIR/branch.rs:16:9: 16:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb5: { + StorageDead(_4); // scope 1 at $DIR/branch.rs:18:14: 18:15 +- _2 = _1; // scope 1 at $DIR/branch.rs:19:9: 19:10 ++ nop; // scope 1 at $DIR/branch.rs:19:9: 19:10 + goto -> bb6; // scope 1 at $DIR/branch.rs:15:13: 20:6 + } + + bb6: { + StorageDead(_3); // scope 1 at $DIR/branch.rs:20:6: 20:7 + _0 = const (); // scope 0 at $DIR/branch.rs:12:11: 21:2 +- StorageDead(_2); // scope 1 at $DIR/branch.rs:21:1: 21:2 +- StorageDead(_1); // scope 0 at $DIR/branch.rs:21:1: 21:2 ++ nop; // scope 1 at $DIR/branch.rs:21:1: 21:2 ++ nop; // scope 0 at $DIR/branch.rs:21:1: 21:2 + return; // scope 0 at $DIR/branch.rs:21:2: 21:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/branch.rs b/src/test/mir-opt/dest-prop/branch.rs new file mode 100644 index 0000000000..7e0e40671d --- /dev/null +++ b/src/test/mir-opt/dest-prop/branch.rs @@ -0,0 +1,21 @@ +//! Tests that assignment in both branches of an `if` are eliminated. + +fn val() -> i32 { + 1 +} + +fn cond() -> bool { + true +} + +// EMIT_MIR branch.main.DestinationPropagation.diff +fn main() { + let x = val(); + + let y = if cond() { + x + } else { + val(); + x + }; +} diff --git a/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff new file mode 100644 index 0000000000..881c296cee --- /dev/null +++ b/src/test/mir-opt/dest-prop/cycle.main.DestinationPropagation.diff @@ -0,0 +1,72 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/cycle.rs:8:11: 8:11 + let mut _1: i32; // in scope 0 at $DIR/cycle.rs:9:9: 9:14 + let mut _4: i32; // in scope 0 at $DIR/cycle.rs:12:9: 12:10 + let _5: (); // in scope 0 at $DIR/cycle.rs:14:5: 14:12 + let mut _6: i32; // in scope 0 at $DIR/cycle.rs:14:10: 14:11 + scope 1 { +- debug x => _1; // in scope 1 at $DIR/cycle.rs:9:9: 9:14 ++ debug x => _4; // in scope 1 at $DIR/cycle.rs:9:9: 9:14 + let _2: i32; // in scope 1 at $DIR/cycle.rs:10:9: 10:10 + scope 2 { +- debug y => _2; // in scope 2 at $DIR/cycle.rs:10:9: 10:10 ++ debug y => _4; // in scope 2 at $DIR/cycle.rs:10:9: 10:10 + let _3: i32; // in scope 2 at $DIR/cycle.rs:11:9: 11:10 + scope 3 { +- debug z => _3; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 ++ debug z => _4; // in scope 3 at $DIR/cycle.rs:11:9: 11:10 + scope 4 { + debug _x => _6; // in scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + } + } + } + + bb0: { +- StorageLive(_1); // scope 0 at $DIR/cycle.rs:9:9: 9:14 +- _1 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 ++ nop; // scope 0 at $DIR/cycle.rs:9:9: 9:14 ++ _4 = val() -> bb1; // scope 0 at $DIR/cycle.rs:9:17: 9:22 + // mir::Constant + // + span: $DIR/cycle.rs:9:17: 9:20 + // + literal: Const { ty: fn() -> i32 {val}, val: Value(Scalar()) } + } + + bb1: { +- StorageLive(_2); // scope 1 at $DIR/cycle.rs:10:9: 10:10 +- _2 = _1; // scope 1 at $DIR/cycle.rs:10:13: 10:14 +- StorageLive(_3); // scope 2 at $DIR/cycle.rs:11:9: 11:10 +- _3 = _2; // scope 2 at $DIR/cycle.rs:11:13: 11:14 +- StorageLive(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 +- _4 = _3; // scope 3 at $DIR/cycle.rs:12:9: 12:10 +- _1 = move _4; // scope 3 at $DIR/cycle.rs:12:5: 12:10 +- StorageDead(_4); // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 1 at $DIR/cycle.rs:10:9: 10:10 ++ nop; // scope 1 at $DIR/cycle.rs:10:13: 10:14 ++ nop; // scope 2 at $DIR/cycle.rs:11:9: 11:10 ++ nop; // scope 2 at $DIR/cycle.rs:11:13: 11:14 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:5: 12:10 ++ nop; // scope 3 at $DIR/cycle.rs:12:9: 12:10 + StorageLive(_5); // scope 3 at $DIR/cycle.rs:14:5: 14:12 + StorageLive(_6); // scope 3 at $DIR/cycle.rs:14:10: 14:11 +- _6 = _1; // scope 3 at $DIR/cycle.rs:14:10: 14:11 ++ _6 = _4; // scope 3 at $DIR/cycle.rs:14:10: 14:11 + _5 = const (); // scope 4 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageDead(_6); // scope 3 at $DIR/cycle.rs:14:11: 14:12 + StorageDead(_5); // scope 3 at $DIR/cycle.rs:14:12: 14:13 + _0 = const (); // scope 0 at $DIR/cycle.rs:8:11: 15:2 +- StorageDead(_3); // scope 2 at $DIR/cycle.rs:15:1: 15:2 +- StorageDead(_2); // scope 1 at $DIR/cycle.rs:15:1: 15:2 +- StorageDead(_1); // scope 0 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 2 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 1 at $DIR/cycle.rs:15:1: 15:2 ++ nop; // scope 0 at $DIR/cycle.rs:15:1: 15:2 + return; // scope 0 at $DIR/cycle.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/cycle.rs b/src/test/mir-opt/dest-prop/cycle.rs new file mode 100644 index 0000000000..7fbffb1335 --- /dev/null +++ b/src/test/mir-opt/dest-prop/cycle.rs @@ -0,0 +1,15 @@ +//! Tests that cyclic assignments don't hang DestinationPropagation, and result in reasonable code. + +fn val() -> i32 { + 1 +} + +// EMIT_MIR cycle.main.DestinationPropagation.diff +fn main() { + let mut x = val(); + let y = x; + let z = y; + x = z; + + drop(x); +} diff --git a/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff new file mode 100644 index 0000000000..3475d41b50 --- /dev/null +++ b/src/test/mir-opt/dest-prop/simple.nrvo.DestinationPropagation.diff @@ -0,0 +1,39 @@ +- // MIR for `nrvo` before DestinationPropagation ++ // MIR for `nrvo` after DestinationPropagation + + fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { + debug init => _1; // in scope 0 at $DIR/simple.rs:4:9: 4:13 + let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/simple.rs:4:39: 4:49 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/simple.rs:6:10: 6:18 + scope 1 { + debug buf => _2; // in scope 1 at $DIR/simple.rs:5:9: 5:16 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simple.rs:5:9: 5:16 + _2 = [const 0_u8; 1024]; // scope 0 at $DIR/simple.rs:5:19: 5:28 + StorageLive(_3); // scope 1 at $DIR/simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/simple.rs:6:5: 6:9 + StorageLive(_5); // scope 1 at $DIR/simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 + _6 = &mut _2; // scope 1 at $DIR/simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/simple.rs:6:5: 6:19 + } + + bb1: { + StorageDead(_5); // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/simple.rs:6:18: 6:19 + StorageDead(_6); // scope 1 at $DIR/simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/simple.rs:6:19: 6:20 + _0 = _2; // scope 1 at $DIR/simple.rs:7:5: 7:8 + StorageDead(_2); // scope 0 at $DIR/simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/simple.rs:8:2: 8:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/simple.rs b/src/test/mir-opt/dest-prop/simple.rs new file mode 100644 index 0000000000..4655f96699 --- /dev/null +++ b/src/test/mir-opt/dest-prop/simple.rs @@ -0,0 +1,14 @@ +//! Copy of `nrvo-simple.rs`, to ensure that full dest-prop handles it too. + +// EMIT_MIR simple.nrvo.DestinationPropagation.diff +fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { + let mut buf = [0; 1024]; + init(&mut buf); + buf +} + +fn main() { + let _ = nrvo(|buf| { + buf[4] = 4; + }); +} diff --git a/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff new file mode 100644 index 0000000000..f15e7bcb2f --- /dev/null +++ b/src/test/mir-opt/dest-prop/union.main.DestinationPropagation.diff @@ -0,0 +1,42 @@ +- // MIR for `main` before DestinationPropagation ++ // MIR for `main` after DestinationPropagation + + fn main() -> () { + let mut _0: (); // return place in scope 0 at $DIR/union.rs:8:11: 8:11 + let _1: main::Un; // in scope 0 at $DIR/union.rs:13:9: 13:11 + let mut _2: u32; // in scope 0 at $DIR/union.rs:13:23: 13:28 + let _3: (); // in scope 0 at $DIR/union.rs:15:5: 15:27 + let mut _4: u32; // in scope 0 at $DIR/union.rs:15:10: 15:26 + scope 1 { + debug un => _1; // in scope 1 at $DIR/union.rs:13:9: 13:11 + scope 2 { + } + scope 3 { + debug _x => _4; // in scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/union.rs:13:9: 13:11 + StorageLive(_2); // scope 0 at $DIR/union.rs:13:23: 13:28 + _2 = val() -> bb1; // scope 0 at $DIR/union.rs:13:23: 13:28 + // mir::Constant + // + span: $DIR/union.rs:13:23: 13:26 + // + literal: Const { ty: fn() -> u32 {val}, val: Value(Scalar()) } + } + + bb1: { + (_1.0: u32) = move _2; // scope 0 at $DIR/union.rs:13:14: 13:30 + StorageDead(_2); // scope 0 at $DIR/union.rs:13:29: 13:30 + StorageLive(_3); // scope 1 at $DIR/union.rs:15:5: 15:27 + StorageLive(_4); // scope 1 at $DIR/union.rs:15:10: 15:26 + _4 = (_1.0: u32); // scope 2 at $DIR/union.rs:15:19: 15:24 + _3 = const (); // scope 3 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + StorageDead(_4); // scope 1 at $DIR/union.rs:15:26: 15:27 + StorageDead(_3); // scope 1 at $DIR/union.rs:15:27: 15:28 + _0 = const (); // scope 0 at $DIR/union.rs:8:11: 16:2 + StorageDead(_1); // scope 0 at $DIR/union.rs:16:1: 16:2 + return; // scope 0 at $DIR/union.rs:16:2: 16:2 + } + } + diff --git a/src/test/mir-opt/dest-prop/union.rs b/src/test/mir-opt/dest-prop/union.rs new file mode 100644 index 0000000000..b9d831389e --- /dev/null +++ b/src/test/mir-opt/dest-prop/union.rs @@ -0,0 +1,16 @@ +//! Tests that projections through unions cancel `DestinationPropagation`. + +fn val() -> u32 { + 1 +} + +// EMIT_MIR union.main.DestinationPropagation.diff +fn main() { + union Un { + us: u32, + } + + let un = Un { us: val() }; + + drop(unsafe { un.us }); +} diff --git a/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..386726bfdd --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,77 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:3:9: 3:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:3:25: 3:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:3:44: 3:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 ++ let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ let mut _11: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:4:12: 4:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:4:15: 4:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:4:11: 4:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:4:16: 4:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 +- switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ _10 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ _11 = Ne(_10, _7); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 ++ switchInt(move _11) -> [false: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:10: 5:17 + } + + bb1: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:6:14: 6:15 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 + } + + bb2: { +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 +- switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 +- } +- +- bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:15: 5:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _9 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:5:24: 5:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch.rs:5:31: 5:32 +- goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 ++ goto -> bb3; // scope 0 at $DIR/early_otherwise_branch.rs:4:5: 7:6 + } + +- bb4: { ++ bb3: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:8:1: 8:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:8:2: 8:2 ++ } ++ ++ bb4: { ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 ++ switchInt(_7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:5:19: 5:26 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..bc5934dec8 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,91 @@ +- // MIR for `opt2` before EarlyOtherwiseBranch ++ // MIR for `opt2` after EarlyOtherwiseBranch + + fn opt2(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch.rs:11:9: 11:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch.rs:11:25: 11:26 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch.rs:11:44: 11:47 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 ++ let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ let mut _12: bool; // in scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch.rs:12:12: 12:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch.rs:12:15: 12:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch.rs:12:11: 12:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch.rs:12:16: 12:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 +- switchInt(move _8) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ _11 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ _12 = Ne(_11, _8); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 ++ switchInt(move _12) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:13:10: 13:17 + } + + bb1: { +- _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 +- switchInt(move _6) -> [0_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 +- } +- +- bb2: { ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch.rs:15:14: 15:15 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 + } + +- bb3: { +- _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 +- switchInt(move _7) -> [1_isize: bb4, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch.rs:13:19: 13:26 +- } +- +- bb4: { ++ bb2: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:15: 13:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch.rs:13:24: 13:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch.rs:13:31: 13:32 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 + } + +- bb5: { ++ bb3: { + _0 = const 0_u32; // scope 0 at $DIR/early_otherwise_branch.rs:14:25: 14:26 +- goto -> bb6; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch.rs:12:5: 16:6 + } + +- bb6: { ++ bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch.rs:17:1: 17:2 + return; // scope 0 at $DIR/early_otherwise_branch.rs:17:2: 17:2 ++ } ++ ++ bb5: { ++ StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 ++ switchInt(_8) -> [0_isize: bb3, 1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch.rs:14:16: 14:20 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch.rs b/src/test/mir-opt/early_otherwise_branch.rs new file mode 100644 index 0000000000..7700344208 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch.rs @@ -0,0 +1,22 @@ +// compile-flags: -Z mir-opt-level=3 +// EMIT_MIR early_otherwise_branch.opt1.EarlyOtherwiseBranch.diff +fn opt1(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + _ => 1, + } +} + +// EMIT_MIR early_otherwise_branch.opt2.EarlyOtherwiseBranch.diff +fn opt2(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + (None, None) => 0, + _ => 1, + } +} + +fn main() { + opt1(None, Some(0)); + opt2(None, Some(0)); +} diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..b0357f1aec --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,99 @@ +- // MIR for `opt1` before EarlyOtherwiseBranch ++ // MIR for `opt1` after EarlyOtherwiseBranch + + fn opt1(_1: Option, _2: Option, _3: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:9: 4:10 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:25: 4:26 + debug z => _3; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:41: 4:42 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:4:60: 4:63 + let mut _4: (std::option::Option, std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + let mut _6: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + let mut _7: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + let _13: u32; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 ++ let mut _14: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _15: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ let mut _16: isize; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ let mut _17: bool; // in scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + scope 1 { + debug a => _11; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + debug b => _12; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + debug c => _13; // in scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + } + + bb0: { + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:12: 5:13 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:15: 5:16 + StorageLive(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + _7 = _3; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:18: 5:19 + (_4.0: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.1: std::option::Option) = move _6; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + (_4.2: std::option::Option) = move _7; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:11: 5:20 + StorageDead(_7); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:19: 5:20 + _10 = discriminant((_4.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 +- switchInt(move _10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageLive(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ _14 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageLive(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ _15 = Ne(_14, _10); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ StorageDead(_14); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 ++ switchInt(move _15) -> [false: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:10: 6:17 + } + + bb1: { ++ StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:7:14: 7:15 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 + } + + bb2: { +- _9 = discriminant((_4.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 +- switchInt(move _9) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 +- } +- +- bb3: { + _8 = discriminant((_4.2: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 +- switchInt(move _8) -> [1_isize: bb4, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 ++ switchInt(move _8) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:28: 6:35 + } + +- bb4: { ++ bb3: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + _11 = (((_4.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:15: 6:16 + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + _12 = (((_4.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:24: 6:25 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _13 = (((_4.2: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:33: 6:34 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:40: 6:41 +- goto -> bb5; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 ++ goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:5:5: 8:6 + } + +- bb5: { ++ bb4: { + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:1: 9:2 + return; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:9:2: 9:2 ++ } ++ ++ bb5: { ++ StorageDead(_15); // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 ++ switchInt(_10) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_3_element_tuple.rs:6:19: 6:26 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs new file mode 100644 index 0000000000..1d6877d67d --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_3_element_tuple.rs @@ -0,0 +1,13 @@ +// compile-flags: -Z mir-opt-level=3 + +// EMIT_MIR early_otherwise_branch_3_element_tuple.opt1.EarlyOtherwiseBranch.diff +fn opt1(x: Option, y: Option, z: Option) -> u32 { + match (x, y, z) { + (Some(a), Some(b), Some(c)) => 0, + _ => 1, + } +} + +fn main() { + opt1(None, Some(0), None); +} diff --git a/src/test/mir-opt/early_otherwise_branch_68867.rs b/src/test/mir-opt/early_otherwise_branch_68867.rs new file mode 100644 index 0000000000..98a275c18a --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.rs @@ -0,0 +1,33 @@ +// ignore-tidy-linelength +// compile-flags: -Z mir-opt-level=3 -Zunsound-mir-opts + +// example from #68867 +type CSSFloat = f32; + +pub enum ViewportPercentageLength { + Vw(CSSFloat), + Vh(CSSFloat), + Vmin(CSSFloat), + Vmax(CSSFloat), +} + +// EMIT_MIR early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff +// EMIT_MIR early_otherwise_branch_68867.try_sum EarlyOtherwiseBranch.before SimplifyBranches-after-copy-prop.after +#[no_mangle] +pub extern "C" fn try_sum( + x: &ViewportPercentageLength, + other: &ViewportPercentageLength, +) -> Result { + use self::ViewportPercentageLength::*; + Ok(match (x, other) { + (&Vw(one), &Vw(other)) => Vw(one + other), + (&Vh(one), &Vh(other)) => Vh(one + other), + (&Vmin(one), &Vmin(other)) => Vmin(one + other), + (&Vmax(one), &Vmax(other)) => Vmax(one + other), + _ => return Err(()), + }) +} + +fn main() { + try_sum(&ViewportPercentageLength::Vw(1.0), &ViewportPercentageLength::Vw(2.0)); +} diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff new file mode 100644 index 0000000000..2cf5dd49d6 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.before-SimplifyBranches-after-copy-prop.after.diff @@ -0,0 +1,304 @@ +- // MIR for `try_sum` before EarlyOtherwiseBranch ++ // MIR for `try_sum` after SimplifyBranches-after-copy-prop + + fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + scope 1 { +- debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ debug one => _15; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ debug other => _16; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + } + scope 2 { +- debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ debug one => _20; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ debug other => _21; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + } + scope 3 { +- debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ debug one => _25; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ debug other => _26; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + } + scope 4 { +- debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ debug one => _30; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ debug other => _31; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + } + + bb0: { +- StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 +- _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 +- StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 +- _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 +- (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 +- StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 +- StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 ++ (_4.0: &ViewportPercentageLength) = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ (_4.1: &ViewportPercentageLength) = move _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 +- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + } + + bb1: { +- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- } +- +- bb2: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + } + ++ bb2: { ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ _15 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ _16 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vw).0: f32) = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 ++ nop; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ } ++ + bb3: { +- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ _20 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ _21 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vh).0: f32) = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 ++ nop; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb4: { +- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ _25 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ _26 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmin).0: f32) = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 ++ nop; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb5: { +- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ _30 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ _31 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 ++ ((((_0 as Ok).0: ViewportPercentageLength) as Vmax).0: f32) = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 ++ discriminant(((_0 as Ok).0: ViewportPercentageLength)) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 ++ nop; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + + bb6: { +- StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 +- StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 +- StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 +- StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 +- _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 +- StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 +- ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 +- StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 ++ discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 ++ nop; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 ++ return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 + } + + bb7: { +- StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 +- StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 +- _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 +- StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 +- StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 +- _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 +- StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 +- _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 +- _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 +- StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 +- StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 +- ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 +- discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 +- StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb8: { +- StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 +- StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 +- StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 +- StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 +- _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 +- StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 +- ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 +- StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb9: { +- StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 +- StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 +- _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 +- StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 +- StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 +- _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 +- StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 +- _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 +- _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 +- StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 +- StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 +- ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 +- discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 +- StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 +- } +- +- bb10: { +- ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 +- discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 +- StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 +- StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 +- return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..a80bf2ac01 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_68867.try_sum.EarlyOtherwiseBranch.diff @@ -0,0 +1,216 @@ +- // MIR for `try_sum` before EarlyOtherwiseBranch ++ // MIR for `try_sum` after EarlyOtherwiseBranch + + fn try_sum(_1: &ViewportPercentageLength, _2: &ViewportPercentageLength) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:18:5: 18:6 + debug other => _2; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:19:5: 19:10 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/early_otherwise_branch_68867.rs:20:6: 20:42 + let mut _3: ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + let mut _4: (&ViewportPercentageLength, &ViewportPercentageLength); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + let mut _5: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + let mut _6: &ViewportPercentageLength; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 + let mut _9: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 + let mut _10: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 + let mut _11: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + let _12: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + let _13: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + let mut _14: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + let mut _15: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + let mut _16: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + let _17: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + let _18: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + let mut _19: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + let mut _20: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + let mut _21: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + let _22: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + let _23: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + let mut _24: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + let mut _25: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + let mut _26: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + let _27: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + let _28: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + let mut _29: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + let mut _30: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + let mut _31: f32; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + let mut _32: !; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + let mut _33: (); // in scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 ++ let mut _34: isize; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ let mut _35: bool; // in scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + scope 1 { + debug one => _12; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + debug other => _13; // in scope 1 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + } + scope 2 { + debug one => _17; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + debug other => _18; // in scope 2 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + } + scope 3 { + debug one => _22; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + debug other => _23; // in scope 3 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + } + scope 4 { + debug one => _27; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + debug other => _28; // in scope 4 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + _5 = _1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:15: 22:16 + StorageLive(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + _6 = _2; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:18: 22:23 + (_4.0: &ViewportPercentageLength) = move _5; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + (_4.1: &ViewportPercentageLength) = move _6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:14: 22:24 + StorageDead(_6); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:23: 22:24 + _11 = discriminant((*(_4.0: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 +- switchInt(move _11) -> [0_isize: bb1, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _34 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageLive(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ _35 = Ne(_34, _11); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ StorageDead(_34); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 ++ switchInt(move _35) -> [false: bb7, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:11: 23:18 + } + + bb1: { +- _7 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- switchInt(move _7) -> [0_isize: bb6, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 +- } +- +- bb2: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + StorageLive(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:25: 27:27 + ((_0 as Err).0: ()) = const (); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + discriminant(_0) = 1; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:21: 27:28 + StorageDead(_33); // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:27: 27:28 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:27:14: 27:28 + } + +- bb3: { +- _8 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- switchInt(move _8) -> [1_isize: bb7, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:21: 24:30 +- } +- +- bb4: { +- _9 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- switchInt(move _9) -> [2_isize: bb8, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:23: 25:34 +- } +- +- bb5: { +- _10 = discriminant((*(_4.1: &ViewportPercentageLength))); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- switchInt(move _10) -> [3_isize: bb9, otherwise: bb2]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:23: 26:34 +- } +- +- bb6: { ++ bb2: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + _12 = (((*(_4.0: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:14: 23:17 + StorageLive(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + _13 = (((*(_4.1: &ViewportPercentageLength)) as Vw).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:24: 23:29 + StorageLive(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageLive(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + _15 = _12; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:41 + StorageLive(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _16 = _13; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:44: 23:49 + _14 = Add(move _15, move _16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:38: 23:49 + StorageDead(_16); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + StorageDead(_15); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:48: 23:49 + ((_3 as Vw).0: f32) = move _14; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + discriminant(_3) = 0; // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:35: 23:50 + StorageDead(_14); // scope 1 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_13); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:49: 23:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb7: { ++ bb3: { + StorageLive(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + _17 = (((*(_4.0: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:14: 24:17 + StorageLive(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + _18 = (((*(_4.1: &ViewportPercentageLength)) as Vh).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:24: 24:29 + StorageLive(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + StorageLive(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + _20 = _17; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:41 + StorageLive(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + _21 = _18; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:44: 24:49 + _19 = Add(move _20, move _21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:38: 24:49 + StorageDead(_21); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 + StorageDead(_20); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:48: 24:49 + ((_3 as Vh).0: f32) = move _19; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 + discriminant(_3) = 1; // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:35: 24:50 + StorageDead(_19); // scope 2 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 + StorageDead(_18); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 + StorageDead(_17); // scope 0 at $DIR/early_otherwise_branch_68867.rs:24:49: 24:50 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb8: { ++ bb4: { + StorageLive(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + _22 = (((*(_4.0: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:16: 25:19 + StorageLive(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + _23 = (((*(_4.1: &ViewportPercentageLength)) as Vmin).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:28: 25:33 + StorageLive(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageLive(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + _25 = _22; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:47 + StorageLive(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _26 = _23; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:50: 25:55 + _24 = Add(move _25, move _26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:44: 25:55 + StorageDead(_26); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + StorageDead(_25); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:54: 25:55 + ((_3 as Vmin).0: f32) = move _24; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + discriminant(_3) = 2; // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:39: 25:56 + StorageDead(_24); // scope 3 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_23); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 + StorageDead(_22); // scope 0 at $DIR/early_otherwise_branch_68867.rs:25:55: 25:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb9: { ++ bb5: { + StorageLive(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + _27 = (((*(_4.0: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:16: 26:19 + StorageLive(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + _28 = (((*(_4.1: &ViewportPercentageLength)) as Vmax).0: f32); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:28: 26:33 + StorageLive(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + StorageLive(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + _30 = _27; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:47 + StorageLive(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + _31 = _28; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:50: 26:55 + _29 = Add(move _30, move _31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:44: 26:55 + StorageDead(_31); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 + StorageDead(_30); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:54: 26:55 + ((_3 as Vmax).0: f32) = move _29; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 + discriminant(_3) = 3; // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:39: 26:56 + StorageDead(_29); // scope 4 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 + StorageDead(_28); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 + StorageDead(_27); // scope 0 at $DIR/early_otherwise_branch_68867.rs:26:55: 26:56 +- goto -> bb10; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 ++ goto -> bb6; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:8: 28:6 + } + +- bb10: { ++ bb6: { + ((_0 as Ok).0: ViewportPercentageLength) = move _3; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 + discriminant(_0) = 0; // scope 0 at $DIR/early_otherwise_branch_68867.rs:22:5: 28:7 + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_68867.rs:28:6: 28:7 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:1: 29:2 + return; // scope 0 at $DIR/early_otherwise_branch_68867.rs:29:2: 29:2 ++ } ++ ++ bb7: { ++ StorageDead(_35); // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 ++ switchInt(_11) -> [0_isize: bb2, 1_isize: bb3, 2_isize: bb4, 3_isize: bb5, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_68867.rs:23:21: 23:30 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..9a6094f12d --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff @@ -0,0 +1,90 @@ +- // MIR for `noopt1` before EarlyOtherwiseBranch ++ // MIR for `noopt1` after EarlyOtherwiseBranch + + fn noopt1(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:11: 7:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:27: 7:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:7:46: 7:49 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + let mut _8: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + let _9: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + let _10: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + let _11: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + let _12: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + scope 1 { + debug a => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + debug b => _10; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + } + scope 2 { + debug a => _11; // in scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + } + scope 3 { + debug b => _12; // in scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:12: 8:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:15: 8:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:11: 8:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:16: 8:17 + _8 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + switchInt(move _8) -> [0_isize: bb1, otherwise: bb3]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:10: 9:17 + } + + bb1: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + switchInt(move _6) -> [0_isize: bb2, otherwise: bb6]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:16: 11:23 + } + + bb2: { + _0 = const 3_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:12:25: 12:26 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb3: { + _7 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + switchInt(move _7) -> [0_isize: bb5, otherwise: bb4]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:19: 9:26 + } + + bb4: { + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + _9 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:15: 9:16 + StorageLive(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _10 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:24: 9:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_10); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:9:31: 9:32 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb5: { + StorageLive(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _11 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:15: 10:16 + _0 = const 1_u32; // scope 2 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + StorageDead(_11); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:10:28: 10:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb6: { + StorageLive(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _12 = (((_3.1: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:21: 11:22 + _0 = const 2_u32; // scope 3 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + StorageDead(_12); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:11:28: 11:29 + goto -> bb7; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:8:5: 13:6 + } + + bb7: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:1: 14:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:14:2: 14:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff new file mode 100644 index 0000000000..c3aecb4529 --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff @@ -0,0 +1,60 @@ +- // MIR for `noopt2` before EarlyOtherwiseBranch ++ // MIR for `noopt2` after EarlyOtherwiseBranch + + fn noopt2(_1: Option, _2: Option) -> u32 { + debug x => _1; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:11: 18:12 + debug y => _2; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:27: 18:28 + let mut _0: u32; // return place in scope 0 at $DIR/early_otherwise_branch_noopt.rs:18:47: 18:50 + let mut _3: (std::option::Option, std::option::Option); // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + let mut _4: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + let mut _5: std::option::Option; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + let mut _6: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + let mut _7: isize; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + let _8: u32; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + let _9: bool; // in scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + scope 1 { + debug a => _8; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + debug b => _9; // in scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + } + + bb0: { + StorageLive(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageLive(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + _4 = _1; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:12: 19:13 + StorageLive(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + _5 = _2; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:15: 19:16 + (_3.0: std::option::Option) = move _4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + (_3.1: std::option::Option) = move _5; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:11: 19:17 + StorageDead(_5); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + StorageDead(_4); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:16: 19:17 + _7 = discriminant((_3.0: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + switchInt(move _7) -> [1_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:10: 20:17 + } + + bb1: { + _0 = const 1_u32; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:21:14: 21:15 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 22:6 + } + + bb2: { + _6 = discriminant((_3.1: std::option::Option)); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + switchInt(move _6) -> [1_isize: bb3, otherwise: bb1]; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:19: 20:26 + } + + bb3: { + StorageLive(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + _8 = (((_3.0: std::option::Option) as Some).0: u32); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:15: 20:16 + StorageLive(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _9 = (((_3.1: std::option::Option) as Some).0: bool); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:24: 20:25 + _0 = const 0_u32; // scope 1 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_9); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + StorageDead(_8); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:20:31: 20:32 + goto -> bb4; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:19:5: 22:6 + } + + bb4: { + StorageDead(_3); // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:1: 23:2 + return; // scope 0 at $DIR/early_otherwise_branch_noopt.rs:23:2: 23:2 + } + } + diff --git a/src/test/mir-opt/early_otherwise_branch_noopt.rs b/src/test/mir-opt/early_otherwise_branch_noopt.rs new file mode 100644 index 0000000000..bd15f520df --- /dev/null +++ b/src/test/mir-opt/early_otherwise_branch_noopt.rs @@ -0,0 +1,28 @@ +// compile-flags: -Z mir-opt-level=3 + +// must not optimize as it does not follow the pattern of +// left and right hand side being the same variant + +// EMIT_MIR early_otherwise_branch_noopt.noopt1.EarlyOtherwiseBranch.diff +fn noopt1(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + (Some(a), None) => 1, + (None, Some(b)) => 2, + (None, None) => 3, + } +} + +// must not optimize as the types being matched on are not identical +// EMIT_MIR early_otherwise_branch_noopt.noopt2.EarlyOtherwiseBranch.diff +fn noopt2(x: Option, y: Option) -> u32 { + match (x, y) { + (Some(a), Some(b)) => 0, + _ => 1, + } +} + +fn main() { + noopt1(None, Some(0)); + noopt2(None, Some(true)); +} diff --git a/src/test/mir-opt/equal_true.opt.InstCombine.diff b/src/test/mir-opt/equal_true.opt.InstCombine.diff new file mode 100644 index 0000000000..a26776e70d --- /dev/null +++ b/src/test/mir-opt/equal_true.opt.InstCombine.diff @@ -0,0 +1,35 @@ +- // MIR for `opt` before InstCombine ++ // MIR for `opt` after InstCombine + + fn opt(_1: bool) -> i32 { + debug x => _1; // in scope 0 at $DIR/equal_true.rs:3:8: 3:9 + let mut _0: i32; // return place in scope 0 at $DIR/equal_true.rs:3:20: 3:23 + let mut _2: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:17 + let mut _3: bool; // in scope 0 at $DIR/equal_true.rs:4:8: 4:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageLive(_3); // scope 0 at $DIR/equal_true.rs:4:8: 4:9 + _3 = _1; // scope 0 at $DIR/equal_true.rs:4:8: 4:9 +- _2 = Eq(move _3, const true); // scope 0 at $DIR/equal_true.rs:4:8: 4:17 ++ _2 = move _3; // scope 0 at $DIR/equal_true.rs:4:8: 4:17 + StorageDead(_3); // scope 0 at $DIR/equal_true.rs:4:16: 4:17 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb1: { + _0 = const 1_i32; // scope 0 at $DIR/equal_true.rs:4:31: 4:32 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb2: { + _0 = const 0_i32; // scope 0 at $DIR/equal_true.rs:4:20: 4:21 + goto -> bb3; // scope 0 at $DIR/equal_true.rs:4:5: 4:34 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/equal_true.rs:5:1: 5:2 + return; // scope 0 at $DIR/equal_true.rs:5:2: 5:2 + } + } + diff --git a/src/test/mir-opt/equal_true.rs b/src/test/mir-opt/equal_true.rs new file mode 100644 index 0000000000..994cd194a4 --- /dev/null +++ b/src/test/mir-opt/equal_true.rs @@ -0,0 +1,9 @@ +// EMIT_MIR equal_true.opt.InstCombine.diff + +fn opt(x: bool) -> i32 { + if x == true { 0 } else { 1 } +} + +fn main() { + opt(true); +} diff --git a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir index 28364d4fbf..0db0f8349b 100644 --- a/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir +++ b/src/test/mir-opt/exponential_or.match_tuple.SimplifyCfg-initial.after.mir @@ -1,6 +1,6 @@ // MIR for `match_tuple` after SimplifyCfg-initial -fn match_tuple(_1: (u32, bool, std::option::Option, u32)) -> u32 { +fn match_tuple(_1: (u32, bool, Option, u32)) -> u32 { debug x => _1; // in scope 0 at $DIR/exponential-or.rs:6:16: 6:17 let mut _0: u32; // return place in scope 0 at $DIR/exponential-or.rs:6:53: 6:56 let mut _2: isize; // in scope 0 at $DIR/exponential-or.rs:8:37: 8:48 diff --git a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir index 199cbcf837..bcc6042f2f 100644 --- a/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir +++ b/src/test/mir-opt/fn_ptr_shim.core.ops-function-Fn-call.AddMovesForPackedDrops.before.mir @@ -1,7 +1,7 @@ // MIR for `std::ops::Fn::call` before AddMovesForPackedDrops -fn std::ops::Fn::call(_1: *const fn(), _2: Args) -> >::Output { - let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL +fn std::ops::Fn::call(_1: *const fn(), _2: ()) -> >::Output { + let mut _0: >::Output; // return place in scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL bb0: { _0 = move (*_1)() -> bb1; // scope 0 at $SRC_DIR/core/src/ops/function.rs:LL:COL diff --git a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff index 9bf666bc76..bb79cd80e5 100644 --- a/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff +++ b/src/test/mir-opt/funky_arms.float_to_exponential_common.ConstProp.diff @@ -1,7 +1,7 @@ - // MIR for `float_to_exponential_common` before ConstProp + // MIR for `float_to_exponential_common` after ConstProp - fn float_to_exponential_common(_1: &mut std::fmt::Formatter, _2: &T, _3: bool) -> std::result::Result<(), std::fmt::Error> { + fn float_to_exponential_common(_1: &mut Formatter, _2: &T, _3: bool) -> std::result::Result<(), std::fmt::Error> { debug fmt => _1; // in scope 0 at $DIR/funky_arms.rs:11:35: 11:38 debug num => _2; // in scope 0 at $DIR/funky_arms.rs:11:60: 11:63 debug upper => _3; // in scope 0 at $DIR/funky_arms.rs:11:69: 11:74 @@ -38,7 +38,7 @@ 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 - _4 = std::fmt::Formatter::sign_plus(move _5) -> bb1; // 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 // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> bool {std::fmt::Formatter::sign_plus}, val: Value(Scalar()) } @@ -64,7 +64,7 @@ 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 - _7 = std::fmt::Formatter::precision(move _8) -> bb5; // 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 // + literal: Const { ty: for<'r> fn(&'r std::fmt::Formatter) -> std::option::Option {std::fmt::Formatter::precision}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/generator-drop-cleanup.rs b/src/test/mir-opt/generator-drop-cleanup.rs index f4fc2aec70..82c1292cbd 100644 --- a/src/test/mir-opt/generator-drop-cleanup.rs +++ b/src/test/mir-opt/generator-drop-cleanup.rs @@ -5,7 +5,7 @@ // Regression test for #58892, generator drop shims should not have blocks // spuriously marked as cleanup -// EMIT_MIR generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir +// EMIT_MIR generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir fn main() { let gen = || { let _s = String::new(); diff --git a/src/test/mir-opt/generator-storage-dead-unwind.rs b/src/test/mir-opt/generator-storage-dead-unwind.rs index ae9faaefdd..b72170adec 100644 --- a/src/test/mir-opt/generator-storage-dead-unwind.rs +++ b/src/test/mir-opt/generator-storage-dead-unwind.rs @@ -17,7 +17,7 @@ struct Bar(i32); fn take(_x: T) {} -// EMIT_MIR generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir +// EMIT_MIR generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir fn main() { let _gen = || { let a = Foo(5); diff --git a/src/test/mir-opt/generator-tiny.rs b/src/test/mir-opt/generator-tiny.rs index 0e79f16255..7dad63a61d 100644 --- a/src/test/mir-opt/generator-tiny.rs +++ b/src/test/mir-opt/generator-tiny.rs @@ -14,7 +14,7 @@ impl Drop for HasDrop { fn callee() {} -// EMIT_MIR generator_tiny.main-{{closure}}.generator_resume.0.mir +// EMIT_MIR generator_tiny.main-{closure#0}.generator_resume.0.mir fn main() { let _gen = |_x: u8| { let _d = HasDrop; diff --git a/src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir similarity index 95% rename from src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir rename to src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir index bd64a31663..31f85469c2 100644 --- a/src/test/mir-opt/generator_drop_cleanup.main-{{closure}}.generator_drop.0.mir +++ b/src/test/mir-opt/generator_drop_cleanup.main-{closure#0}.generator_drop.0.mir @@ -1,4 +1,4 @@ -// MIR for `main::{{closure}}#0` 0 generator_drop +// MIR for `main::{closure#0}` 0 generator_drop /* generator_layout = GeneratorLayout { field_tys: { _0: std::string::String, @@ -14,7 +14,7 @@ }, } */ -fn main::{{closure}}#0(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {std::string::String, ()}]) -> () { +fn main::{closure#0}(_1: *mut [generator@$DIR/generator-drop-cleanup.rs:10:15: 13:6 {String, ()}]) -> () { let mut _0: (); // return place in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let mut _2: (); // in scope 0 at $DIR/generator-drop-cleanup.rs:10:15: 13:6 let _3: std::string::String; // in scope 0 at $DIR/generator-drop-cleanup.rs:11:13: 11:15 diff --git a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir similarity index 97% rename from src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir rename to src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir index b6cda80683..b76e41230e 100644 --- a/src/test/mir-opt/generator_storage_dead_unwind.main-{{closure}}.StateTransform.before.mir +++ b/src/test/mir-opt/generator_storage_dead_unwind.main-{closure#0}.StateTransform.before.mir @@ -1,6 +1,6 @@ -// MIR for `main::{{closure}}#0` before StateTransform +// MIR for `main::{closure#0}` before StateTransform -fn main::{{closure}}#0(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> () +fn main::{closure#0}(_1: [generator@$DIR/generator-storage-dead-unwind.rs:22:16: 28:6 {Foo, Bar, ()}], _2: ()) -> () yields () { let mut _0: (); // return place in scope 0 at $DIR/generator-storage-dead-unwind.rs:22:19: 22:19 diff --git a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir similarity index 95% rename from src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir rename to src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir index 691f5eedad..990aa1ec08 100644 --- a/src/test/mir-opt/generator_tiny.main-{{closure}}.generator_resume.0.mir +++ b/src/test/mir-opt/generator_tiny.main-{closure#0}.generator_resume.0.mir @@ -1,4 +1,4 @@ -// MIR for `main::{{closure}}#0` 0 generator_resume +// MIR for `main::{closure#0}` 0 generator_resume /* generator_layout = GeneratorLayout { field_tys: {}, variant_fields: { @@ -10,7 +10,7 @@ storage_conflicts: BitMatrix(0x0) {}, } */ -fn main::{{closure}}#0(_1: std::pin::Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> std::ops::GeneratorState<(), ()> { +fn main::{closure#0}(_1: Pin<&mut [generator@$DIR/generator-tiny.rs:19:16: 25:6 {u8, HasDrop, ()}]>, _2: u8) -> GeneratorState<(), ()> { debug _x => _10; // in scope 0 at $DIR/generator-tiny.rs:19:17: 19:19 let mut _0: std::ops::GeneratorState<(), ()>; // return place in scope 0 at $DIR/generator-tiny.rs:19:16: 25:6 let _3: HasDrop; // in scope 0 at $DIR/generator-tiny.rs:20:13: 20:15 diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot b/src/test/mir-opt/graphviz.main.mir_map.0.dot index f5d8b84812..df4f11f0f2 100644 --- a/src/test/mir-opt/graphviz.main.mir_map.0.dot +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot @@ -1,7 +1,7 @@ digraph Mir_0_3 { - graph [fontname="monospace"]; - node [fontname="monospace"]; - edge [fontname="monospace"]; + graph [fontname="Courier, monospace"]; + node [fontname="Courier, monospace"]; + edge [fontname="Courier, monospace"]; label=>; bb0__0_3 [shape="none", label=<
    0
    _0 = const ()
    goto
    >]; bb1__0_3 [shape="none", label=<
    1
    resume
    >]; diff --git a/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir new file mode 100644 index 0000000000..df4f11f0f2 --- /dev/null +++ b/src/test/mir-opt/graphviz.main.mir_map.0.dot.mir @@ -0,0 +1,10 @@ +digraph Mir_0_3 { + graph [fontname="Courier, monospace"]; + node [fontname="Courier, monospace"]; + edge [fontname="Courier, monospace"]; + label=>; + bb0__0_3 [shape="none", label=<
    0
    _0 = const ()
    goto
    >]; + bb1__0_3 [shape="none", label=<
    1
    resume
    >]; + bb2__0_3 [shape="none", label=<
    2
    return
    >]; + bb0__0_3 -> bb2__0_3 [label=""]; +} diff --git a/src/test/mir-opt/if-condition-int.rs b/src/test/mir-opt/if-condition-int.rs new file mode 100644 index 0000000000..b34389a0ab --- /dev/null +++ b/src/test/mir-opt/if-condition-int.rs @@ -0,0 +1,65 @@ +// compile-flags: -O +// EMIT_MIR if_condition_int.opt_u32.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_negative.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_char.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_i8.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff +// EMIT_MIR if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff + +fn opt_u32(x: u32) -> u32 { + if x == 42 { 0 } else { 1 } +} + +// don't opt: it is already optimal to switch on the bool +fn dont_opt_bool(x: bool) -> u32 { + if x { 0 } else { 1 } +} + +fn opt_char(x: char) -> u32 { + if x == 'x' { 0 } else { 1 } +} + +fn opt_i8(x: i8) -> u32 { + if x == 42 { 0 } else { 1 } +} + +fn opt_negative(x: i32) -> u32 { + if x == -42 { 0 } else { 1 } +} + +fn opt_multiple_ifs(x: u32) -> u32 { + if x == 42 { + 0 + } else if x != 21 { + 1 + } else { + 2 + } +} + +// test that we optimize, but do not remove the b statement, as that is used later on +fn dont_remove_comparison(a: i8) -> i32 { + let b = a == 17; + match b { + false => 10 + b as i32, + true => 100 + b as i32, + } +} + +// test that we do not optimize on floats +fn dont_opt_floats(a: f32) -> i32 { + if a == -42.0 { 0 } else { 1 } +} + +fn main() { + opt_u32(0); + opt_char('0'); + opt_i8(22); + dont_opt_bool(false); + opt_negative(0); + opt_multiple_ifs(0); + dont_remove_comparison(11); + dont_opt_floats(1.0); +} diff --git a/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..993ff660ca --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_opt_bool.SimplifyComparisonIntegral.diff @@ -0,0 +1,30 @@ +- // MIR for `dont_opt_bool` before SimplifyComparisonIntegral ++ // MIR for `dont_opt_bool` after SimplifyComparisonIntegral + + fn dont_opt_bool(_1: bool) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:16:18: 16:19 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:16:30: 16:33 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + _2 = _1; // scope 0 at $DIR/if-condition-int.rs:17:8: 17:9 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 + } + + bb1: { + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:17:23: 17:24 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 + } + + bb2: { + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:17:12: 17:13 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:17:5: 17:26 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:18:1: 18:2 + return; // scope 0 at $DIR/if-condition-int.rs:18:2: 18:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..8ae9168c95 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_opt_floats.SimplifyComparisonIntegral.diff @@ -0,0 +1,37 @@ +- // MIR for `dont_opt_floats` before SimplifyComparisonIntegral ++ // MIR for `dont_opt_floats` after SimplifyComparisonIntegral + + fn dont_opt_floats(_1: f32) -> i32 { + debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:52:20: 52:21 + let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:52:31: 52:34 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + let mut _3: f32; // in scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:53:8: 53:9 + _2 = Eq(move _3, const -42f32); // scope 0 at $DIR/if-condition-int.rs:53:8: 53:18 + // mir::Constant + // + span: $DIR/if-condition-int.rs:53:13: 53:18 + // + literal: Const { ty: f32, val: Value(Scalar(0xc2280000)) } + StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:53:17: 53:18 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 + } + + bb1: { + _0 = const 1_i32; // scope 0 at $DIR/if-condition-int.rs:53:32: 53:33 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 + } + + bb2: { + _0 = const 0_i32; // scope 0 at $DIR/if-condition-int.rs:53:21: 53:22 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:53:5: 53:35 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:54:1: 54:2 + return; // scope 0 at $DIR/if-condition-int.rs:54:2: 54:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..b590be5370 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.dont_remove_comparison.SimplifyComparisonIntegral.diff @@ -0,0 +1,58 @@ +- // MIR for `dont_remove_comparison` before SimplifyComparisonIntegral ++ // MIR for `dont_remove_comparison` after SimplifyComparisonIntegral + + fn dont_remove_comparison(_1: i8) -> i32 { + debug a => _1; // in scope 0 at $DIR/if-condition-int.rs:43:27: 43:28 + let mut _0: i32; // return place in scope 0 at $DIR/if-condition-int.rs:43:37: 43:40 + let _2: bool; // in scope 0 at $DIR/if-condition-int.rs:44:9: 44:10 + let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 + let mut _4: i32; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:31 + let mut _5: bool; // in scope 0 at $DIR/if-condition-int.rs:46:23: 46:24 + let mut _6: i32; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:31 + let mut _7: bool; // in scope 0 at $DIR/if-condition-int.rs:47:23: 47:24 + scope 1 { + debug b => _2; // in scope 1 at $DIR/if-condition-int.rs:44:9: 44:10 + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:44:9: 44:10 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:44:13: 44:14 +- _2 = Eq(move _3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20 +- switchInt(_2) -> [false: bb2, otherwise: bb1]; // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 ++ _2 = Eq(_3, const 17_i8); // scope 0 at $DIR/if-condition-int.rs:44:13: 44:20 ++ nop; // scope 0 at $DIR/if-condition-int.rs:44:19: 44:20 ++ switchInt(move _3) -> [17_i8: bb1, otherwise: bb2]; // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 + } + + bb1: { ++ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 + StorageLive(_6); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31 + StorageLive(_7); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24 + _7 = _2; // scope 1 at $DIR/if-condition-int.rs:47:23: 47:24 + _6 = move _7 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:47:23: 47:31 + StorageDead(_7); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31 + _0 = Add(const 100_i32, move _6); // scope 1 at $DIR/if-condition-int.rs:47:17: 47:31 + StorageDead(_6); // scope 1 at $DIR/if-condition-int.rs:47:30: 47:31 + goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:45:5: 48:6 + } + + bb2: { ++ StorageDead(_3); // scope 1 at $DIR/if-condition-int.rs:46:9: 46:14 + StorageLive(_4); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31 + StorageLive(_5); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24 + _5 = _2; // scope 1 at $DIR/if-condition-int.rs:46:23: 46:24 + _4 = move _5 as i32 (Misc); // scope 1 at $DIR/if-condition-int.rs:46:23: 46:31 + StorageDead(_5); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31 + _0 = Add(const 10_i32, move _4); // scope 1 at $DIR/if-condition-int.rs:46:18: 46:31 + StorageDead(_4); // scope 1 at $DIR/if-condition-int.rs:46:30: 46:31 + goto -> bb3; // scope 1 at $DIR/if-condition-int.rs:45:5: 48:6 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:49:1: 49:2 + return; // scope 0 at $DIR/if-condition-int.rs:49:2: 49:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..ae0960028a --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_char.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_char` before SimplifyComparisonIntegral ++ // MIR for `opt_char` after SimplifyComparisonIntegral + + fn opt_char(_1: char) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:20:13: 20:14 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:20:25: 20:28 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + let mut _3: char; // in scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:21:8: 21:9 +- _2 = Eq(move _3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 ++ _2 = Eq(_3, const 'x'); // scope 0 at $DIR/if-condition-int.rs:21:8: 21:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:21:15: 21:16 ++ switchInt(move _3) -> ['x': bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:21:30: 21:31 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:21:19: 21:20 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:21:5: 21:33 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:22:1: 22:2 + return; // scope 0 at $DIR/if-condition-int.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..8d59e51ac2 --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_i8.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_i8` before SimplifyComparisonIntegral ++ // MIR for `opt_i8` after SimplifyComparisonIntegral + + fn opt_i8(_1: i8) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:24:11: 24:12 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:24:21: 24:24 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + let mut _3: i8; // in scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:25:8: 25:9 +- _2 = Eq(move _3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 ++ _2 = Eq(_3, const 42_i8); // scope 0 at $DIR/if-condition-int.rs:25:8: 25:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:25:14: 25:15 ++ switchInt(move _3) -> [42_i8: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:25:29: 25:30 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:25:18: 25:19 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:25:5: 25:32 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:26:1: 26:2 + return; // scope 0 at $DIR/if-condition-int.rs:26:2: 26:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..c4975661ef --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_multiple_ifs.SimplifyComparisonIntegral.diff @@ -0,0 +1,65 @@ +- // MIR for `opt_multiple_ifs` before SimplifyComparisonIntegral ++ // MIR for `opt_multiple_ifs` after SimplifyComparisonIntegral + + fn opt_multiple_ifs(_1: u32) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:32:21: 32:22 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:32:32: 32:35 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 + let mut _4: bool; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + let mut _5: u32; // in scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:33:8: 33:9 +- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 ++ _2 = Eq(_3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:33:8: 33:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:33:14: 33:15 ++ switchInt(move _3) -> [42_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + StorageLive(_4); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 + StorageLive(_5); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 + _5 = _1; // scope 0 at $DIR/if-condition-int.rs:35:15: 35:16 +- _4 = Ne(move _5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 +- StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22 +- switchInt(_4) -> [false: bb3, otherwise: bb4]; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 ++ _4 = Ne(_5, const 21_u32); // scope 0 at $DIR/if-condition-int.rs:35:15: 35:22 ++ nop; // scope 0 at $DIR/if-condition-int.rs:35:21: 35:22 ++ switchInt(move _5) -> [21_u32: bb3, otherwise: bb4]; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:34:9: 34:10 + goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + } + + bb3: { ++ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + _0 = const 2_u32; // scope 0 at $DIR/if-condition-int.rs:38:9: 38:10 + goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + } + + bb4: { ++ StorageDead(_5); // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:36:9: 36:10 + goto -> bb5; // scope 0 at $DIR/if-condition-int.rs:35:12: 39:6 + } + + bb5: { + StorageDead(_4); // scope 0 at $DIR/if-condition-int.rs:39:5: 39:6 + goto -> bb6; // scope 0 at $DIR/if-condition-int.rs:33:5: 39:6 + } + + bb6: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:40:1: 40:2 + return; // scope 0 at $DIR/if-condition-int.rs:40:2: 40:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..d7f544e44c --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_negative.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_negative` before SimplifyComparisonIntegral ++ // MIR for `opt_negative` after SimplifyComparisonIntegral + + fn opt_negative(_1: i32) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:28:17: 28:18 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:28:28: 28:31 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + let mut _3: i32; // in scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:29:8: 29:9 +- _2 = Eq(move _3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 ++ _2 = Eq(_3, const -42_i32); // scope 0 at $DIR/if-condition-int.rs:29:8: 29:16 ++ nop; // scope 0 at $DIR/if-condition-int.rs:29:15: 29:16 ++ switchInt(move _3) -> [-42_i32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:29:30: 29:31 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:29:19: 29:20 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:29:5: 29:33 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:30:1: 30:2 + return; // scope 0 at $DIR/if-condition-int.rs:30:2: 30:2 + } + } + diff --git a/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..51e00e680c --- /dev/null +++ b/src/test/mir-opt/if_condition_int.opt_u32.SimplifyComparisonIntegral.diff @@ -0,0 +1,39 @@ +- // MIR for `opt_u32` before SimplifyComparisonIntegral ++ // MIR for `opt_u32` after SimplifyComparisonIntegral + + fn opt_u32(_1: u32) -> u32 { + debug x => _1; // in scope 0 at $DIR/if-condition-int.rs:11:12: 11:13 + let mut _0: u32; // return place in scope 0 at $DIR/if-condition-int.rs:11:23: 11:26 + let mut _2: bool; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + let mut _3: u32; // in scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 + StorageLive(_3); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 + _3 = _1; // scope 0 at $DIR/if-condition-int.rs:12:8: 12:9 +- _2 = Eq(move _3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 +- StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15 +- switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 ++ _2 = Eq(_3, const 42_u32); // scope 0 at $DIR/if-condition-int.rs:12:8: 12:15 ++ nop; // scope 0 at $DIR/if-condition-int.rs:12:14: 12:15 ++ switchInt(move _3) -> [42_u32: bb2, otherwise: bb1]; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + } + + bb1: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + _0 = const 1_u32; // scope 0 at $DIR/if-condition-int.rs:12:29: 12:30 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + } + + bb2: { ++ StorageDead(_3); // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + _0 = const 0_u32; // scope 0 at $DIR/if-condition-int.rs:12:18: 12:19 + goto -> bb3; // scope 0 at $DIR/if-condition-int.rs:12:5: 12:32 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/if-condition-int.rs:13:1: 13:2 + return; // scope 0 at $DIR/if-condition-int.rs:13:2: 13:2 + } + } + diff --git a/src/test/mir-opt/inline/inline-async.rs b/src/test/mir-opt/inline/inline-async.rs new file mode 100644 index 0000000000..5c838159b9 --- /dev/null +++ b/src/test/mir-opt/inline/inline-async.rs @@ -0,0 +1,18 @@ +// Checks that inliner doesn't introduce cycles when optimizing generators. +// The outcome of optimization is not verfied, just the absence of the cycle. +// Regression test for #76181. +// +// edition:2018 + +#![crate_type = "lib"] + +pub struct S; + +impl S { + pub async fn g(&mut self) { + self.h(); + } + pub fn h(&mut self) { + let _ = self.g(); + } +} diff --git a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs index 218bc3553a..d76bc33f52 100644 --- a/src/test/mir-opt/inline/inline-closure-borrows-arg.rs +++ b/src/test/mir-opt/inline/inline-closure-borrows-arg.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z span_free_formats +// compile-flags: -Z span_free_formats -Zunsound-mir-opts // Tests that MIR inliner can handle closure arguments, // even when (#45894) diff --git a/src/test/mir-opt/inline/inline-compatibility.rs b/src/test/mir-opt/inline/inline-compatibility.rs new file mode 100644 index 0000000000..ff9049edb4 --- /dev/null +++ b/src/test/mir-opt/inline/inline-compatibility.rs @@ -0,0 +1,39 @@ +// Checks that only functions with compatible attributes are inlined. +// +// only-x86_64 +// needs-sanitizer-address +// compile-flags: -Zsanitizer=address + +#![crate_type = "lib"] +#![feature(no_sanitize)] +#![feature(target_feature_11)] + +// EMIT_MIR inline_compatibility.inlined_target_feature.Inline.diff +#[target_feature(enable = "sse2")] +pub unsafe fn inlined_target_feature() { + target_feature(); +} + +// EMIT_MIR inline_compatibility.not_inlined_target_feature.Inline.diff +pub unsafe fn not_inlined_target_feature() { + target_feature(); +} + +// EMIT_MIR inline_compatibility.inlined_no_sanitize.Inline.diff +#[no_sanitize(address)] +pub unsafe fn inlined_no_sanitize() { + no_sanitize(); +} + +// EMIT_MIR inline_compatibility.not_inlined_no_sanitize.Inline.diff +pub unsafe fn not_inlined_no_sanitize() { + no_sanitize(); +} + +#[inline] +#[target_feature(enable = "sse2")] +pub unsafe fn target_feature() {} + +#[inline] +#[no_sanitize(address, memory)] +pub unsafe fn no_sanitize() {} diff --git a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir index 9d490f047f..4d623297f8 100644 --- a/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_any_operand.bar.Inline.after.mir @@ -4,13 +4,15 @@ fn bar() -> bool { let mut _0: bool; // return place in scope 0 at $DIR/inline-any-operand.rs:10:13: 10:17 let _1: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:11:9: 11:10 let mut _2: fn(i32, i32) -> bool {foo}; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:6 - let mut _3: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 - let mut _4: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _5: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _6: i32; // in scope 0 at $DIR/inline-any-operand.rs:12:5: 12:13 scope 1 { debug f => _1; // in scope 1 at $DIR/inline-any-operand.rs:11:9: 11:10 scope 2 { - debug x => _3; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9 - debug y => _4; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17 + debug x => _5; // in scope 2 at $DIR/inline-any-operand.rs:16:8: 16:9 + debug y => _6; // in scope 2 at $DIR/inline-any-operand.rs:16:16: 16:17 + let mut _3: i32; // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13 + let mut _4: i32; // in scope 2 at $DIR/inline-any-operand.rs:12:5: 12:13 } } @@ -22,9 +24,19 @@ fn bar() -> bool { // + literal: Const { ty: fn(i32, i32) -> bool {foo}, val: Value(Scalar()) } StorageLive(_2); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 _2 = _1; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:6 - _3 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 - _4 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_5); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _5 = const 1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_6); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + _6 = const -1_i32; // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageLive(_3); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + _3 = _5; // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:6 + StorageLive(_4); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + _4 = _6; // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 _0 = Eq(move _3, move _4); // scope 2 at $DIR/inline-any-operand.rs:17:5: 17:11 + StorageDead(_4); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_3); // scope 2 at $DIR/inline-any-operand.rs:17:10: 17:11 + StorageDead(_6); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 + StorageDead(_5); // scope 1 at $DIR/inline-any-operand.rs:12:5: 12:13 StorageDead(_2); // scope 1 at $DIR/inline-any-operand.rs:12:12: 12:13 StorageDead(_1); // scope 0 at $DIR/inline-any-operand.rs:13:1: 13:2 return; // scope 0 at $DIR/inline-any-operand.rs:13:2: 13:2 diff --git a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir index b40a8047c4..c970b1bfac 100644 --- a/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure.foo.Inline.after.mir @@ -4,8 +4,8 @@ fn foo(_1: T, _2: i32) -> i32 { debug _t => _1; // in scope 0 at $DIR/inline-closure.rs:10:17: 10:19 debug q => _2; // in scope 0 at $DIR/inline-closure.rs:10:24: 10:25 let mut _0: i32; // return place in scope 0 at $DIR/inline-closure.rs:10:35: 10:38 - let _3: [closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure.rs:11:9: 11:10 - let mut _4: &[closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:6 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:11:9: 11:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure.rs:12:5: 12:6 let mut _5: (i32, i32); // in scope 0 at $DIR/inline-closure.rs:12:5: 12:12 let mut _6: i32; // in scope 0 at $DIR/inline-closure.rs:12:7: 12:8 let mut _7: i32; // in scope 0 at $DIR/inline-closure.rs:12:10: 12:11 @@ -30,9 +30,13 @@ fn foo(_1: T, _2: i32) -> i32 { _7 = _2; // scope 1 at $DIR/inline-closure.rs:12:10: 12:11 (_5.0: i32) = move _6; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 (_5.1: i32) = move _7; // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _8 = move (_5.0: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageLive(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _9 = move (_5.1: i32); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 _0 = _8; // scope 2 at $DIR/inline-closure.rs:11:22: 11:24 + StorageDead(_9); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 + StorageDead(_8); // scope 1 at $DIR/inline-closure.rs:12:5: 12:12 StorageDead(_7); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_6); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 StorageDead(_5); // scope 1 at $DIR/inline-closure.rs:12:11: 12:12 diff --git a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir index f6dd741364..2f2db51ec8 100644 --- a/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_borrows_arg.foo.Inline.after.mir @@ -4,18 +4,19 @@ fn foo(_1: T, _2: &i32) -> i32 { debug _t => _1; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:17: 11:19 debug q => _2; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:24: 11:25 let mut _0: i32; // return place in scope 0 at $DIR/inline-closure-borrows-arg.rs:11:36: 11:39 - let _3: [closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 - let mut _4: &[closure@foo::{{closure}}#0]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 + let mut _4: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:6 let mut _5: (&i32, &i32); // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 let mut _6: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:7: 16:8 let mut _7: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 - let mut _8: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 let mut _9: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + let mut _10: &i32; // in scope 0 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 scope 1 { debug x => _3; // in scope 1 at $DIR/inline-closure-borrows-arg.rs:12:9: 12:10 scope 2 { - debug r => _8; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:14: 12:15 - debug _s => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:23: 12:25 + debug r => _9; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:14: 12:15 + debug _s => _10; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:12:23: 12:25 + let _8: &i32; // in scope 2 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 } } scope 3 { @@ -33,9 +34,16 @@ fn foo(_1: T, _2: &i32) -> i32 { _7 = &(*_2); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:10: 16:11 (_5.0: &i32) = move _6; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 (_5.1: &i32) = move _7; // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _8 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _9 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 - _0 = (*_8); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + StorageLive(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _9 = move (_5.0: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_10); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + _10 = move (_5.1: &i32); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageLive(_8); // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:13: 13:21 + _8 = _9; // scope 2 at $DIR/inline-closure-borrows-arg.rs:13:24: 13:27 + _0 = (*_9); // scope 3 at $DIR/inline-closure-borrows-arg.rs:14:9: 14:18 + StorageDead(_8); // scope 2 at $DIR/inline-closure-borrows-arg.rs:15:5: 15:6 + StorageDead(_10); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 + StorageDead(_9); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:5: 16:12 StorageDead(_7); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_6); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 StorageDead(_5); // scope 1 at $DIR/inline-closure-borrows-arg.rs:16:11: 16:12 diff --git a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir index e2b5d6567c..5138b50c9f 100644 --- a/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_closure_captures.foo.Inline.after.mir @@ -4,21 +4,20 @@ fn foo(_1: T, _2: i32) -> (i32, T) { debug t => _1; // in scope 0 at $DIR/inline-closure-captures.rs:10:17: 10:18 debug q => _2; // in scope 0 at $DIR/inline-closure-captures.rs:10:23: 10:24 let mut _0: (i32, T); // return place in scope 0 at $DIR/inline-closure-captures.rs:10:34: 10:42 - let _3: [closure@foo::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 + let _3: [closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:11:9: 11:10 let mut _4: &i32; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 let mut _5: &T; // in scope 0 at $DIR/inline-closure-captures.rs:11:13: 11:24 - let mut _6: &[closure@foo::{{closure}}#0 q:&i32, t:&T]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 + let mut _6: &[closure@foo::{closure#0}]; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:6 let mut _7: (i32,); // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 let mut _8: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:7: 12:8 - let mut _11: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 + let mut _10: i32; // in scope 0 at $DIR/inline-closure-captures.rs:12:5: 12:9 scope 1 { debug x => _3; // in scope 1 at $DIR/inline-closure-captures.rs:11:9: 11:10 scope 2 { - debug _q => _11; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16 + debug _q => _10; // in scope 2 at $DIR/inline-closure-captures.rs:11:14: 11:16 debug q => (*((*_6).0: &i32)); // in scope 2 at $DIR/inline-closure-captures.rs:10:23: 10:24 debug t => (*((*_6).1: &T)); // in scope 2 at $DIR/inline-closure-captures.rs:10:17: 10:18 - let mut _9: i32; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 - let mut _10: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 + let mut _9: T; // in scope 2 at $DIR/inline-closure-captures.rs:12:5: 12:9 } } @@ -38,15 +37,14 @@ fn foo(_1: T, _2: i32) -> (i32, T) { StorageLive(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 _8 = _2; // scope 1 at $DIR/inline-closure-captures.rs:12:7: 12:8 (_7.0: i32) = move _8; // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 - _11 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 - StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - _9 = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 - StorageLive(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - _10 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 - (_0.0: i32) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 - (_0.1: T) = move _10; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 - StorageDead(_10); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageLive(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + _10 = move (_7.0: i32); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 + (_0.0: i32) = (*((*_6).0: &i32)); // scope 2 at $DIR/inline-closure-captures.rs:11:19: 11:20 + StorageLive(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + _9 = (*((*_6).1: &T)); // scope 2 at $DIR/inline-closure-captures.rs:11:22: 11:23 + (_0.1: T) = move _9; // scope 2 at $DIR/inline-closure-captures.rs:11:18: 11:24 StorageDead(_9); // scope 2 at $DIR/inline-closure-captures.rs:11:23: 11:24 + StorageDead(_10); // scope 1 at $DIR/inline-closure-captures.rs:12:5: 12:9 StorageDead(_8); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_7); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 StorageDead(_6); // scope 1 at $DIR/inline-closure-captures.rs:12:8: 12:9 diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff new file mode 100644 index 0000000000..7b0ecaffdd --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_no_sanitize.Inline.diff @@ -0,0 +1,25 @@ +- // MIR for `inlined_no_sanitize` before Inline ++ // MIR for `inlined_no_sanitize` after Inline + + fn inlined_no_sanitize() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:24:37: 24:37 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 ++ scope 1 { ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 +- _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:25:5: 25:18 +- // mir::Constant +- // + span: $DIR/inline-compatibility.rs:25:5: 25:16 +- // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar()) } +- } +- +- bb1: { ++ _1 = const (); // scope 1 at $DIR/inline-compatibility.rs:39:29: 39:31 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:25:18: 25:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:24:37: 26:2 + return; // scope 0 at $DIR/inline-compatibility.rs:26:2: 26:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff new file mode 100644 index 0000000000..f55eae6c50 --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.inlined_target_feature.Inline.diff @@ -0,0 +1,25 @@ +- // MIR for `inlined_target_feature` before Inline ++ // MIR for `inlined_target_feature` after Inline + + fn inlined_target_feature() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:13:40: 13:40 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 ++ scope 1 { ++ } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 +- _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:14:5: 14:21 +- // mir::Constant +- // + span: $DIR/inline-compatibility.rs:14:5: 14:19 +- // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar()) } +- } +- +- bb1: { ++ _1 = const (); // scope 1 at $DIR/inline-compatibility.rs:35:32: 35:34 + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:14:21: 14:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:13:40: 15:2 + return; // scope 0 at $DIR/inline-compatibility.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff new file mode 100644 index 0000000000..651eadc1e8 --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_no_sanitize.Inline.diff @@ -0,0 +1,22 @@ +- // MIR for `not_inlined_no_sanitize` before Inline ++ // MIR for `not_inlined_no_sanitize` after Inline + + fn not_inlined_no_sanitize() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:29:41: 29:41 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + _1 = no_sanitize() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:30:5: 30:18 + // mir::Constant + // + span: $DIR/inline-compatibility.rs:30:5: 30:16 + // + literal: Const { ty: unsafe fn() {no_sanitize}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:30:18: 30:19 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:29:41: 31:2 + return; // scope 0 at $DIR/inline-compatibility.rs:31:2: 31:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff new file mode 100644 index 0000000000..55b9edf3ad --- /dev/null +++ b/src/test/mir-opt/inline/inline_compatibility.not_inlined_target_feature.Inline.diff @@ -0,0 +1,22 @@ +- // MIR for `not_inlined_target_feature` before Inline ++ // MIR for `not_inlined_target_feature` after Inline + + fn not_inlined_target_feature() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inline-compatibility.rs:18:44: 18:44 + let _1: (); // in scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + _1 = target_feature() -> bb1; // scope 0 at $DIR/inline-compatibility.rs:19:5: 19:21 + // mir::Constant + // + span: $DIR/inline-compatibility.rs:19:5: 19:19 + // + literal: Const { ty: unsafe fn() {target_feature}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_1); // scope 0 at $DIR/inline-compatibility.rs:19:21: 19:22 + _0 = const (); // scope 0 at $DIR/inline-compatibility.rs:18:44: 20:2 + return; // scope 0 at $DIR/inline-compatibility.rs:20:2: 20:2 + } + } + diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff similarity index 89% rename from src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit rename to src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff index 0957698820..2d52f034e5 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.32bit +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.32bit.diff @@ -17,9 +17,9 @@ 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) = std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_2) = Vec::::new() -> [return: bb2, unwind: bb4]; // 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: std::ptr::Unique:: { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL ++ ((*_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 $SRC_DIR/alloc/src/vec.rs:LL:COL + // 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 } }, size: Size { raw: 8 }, align: Align { pow2: 2 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -54,7 +54,7 @@ - } - - bb4 (cleanup): { -- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // 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>) {alloc::alloc::box_free::>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff similarity index 89% rename from src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit rename to src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff index ab065fc3d2..d4e2df6fbf 100644 --- a/src/test/mir-opt/inline/inline_into_box_place.main.Inline.diff.64bit +++ b/src/test/mir-opt/inline/inline_into_box_place.main.Inline.64bit.diff @@ -17,9 +17,9 @@ 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) = std::vec::Vec::::new() -> [return: bb2, unwind: bb4]; // scope 0 at $DIR/inline-into-box-place.rs:8:33: 8:43 +- (*_2) = Vec::::new() -> [return: bb2, unwind: bb4]; // 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: std::ptr::Unique:: { pointer: {0x4 as *const u32}, _marker: std::marker::PhantomData:: }, cap: 0_usize, alloc: std::alloc::Global }; // scope 2 at $SRC_DIR/alloc/src/vec.rs:LL:COL ++ ((*_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 $SRC_DIR/alloc/src/vec.rs:LL:COL + // 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 } }, size: Size { raw: 16 }, align: Align { pow2: 3 }, mutability: Not, extra: () }, offset: Size { raw: 0 } }) @@ -54,7 +54,7 @@ - } - - bb4 (cleanup): { -- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // scope 0 at $DIR/inline-into-box-place.rs:8:42: 8:43 +- _3 = alloc::alloc::box_free::>(move (_2.0: std::ptr::Unique>)) -> bb1; // 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>) {alloc::alloc::box_free::>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir index 29327108f3..5258f67ebd 100644 --- a/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_retag.bar.Inline.after.mir @@ -35,10 +35,10 @@ fn bar() -> bool { _10 = const bar::promoted[1]; // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $DIR/inline-retag.rs:12:7: 12:9 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[1])) } Retag(_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 _4 = &(*_10); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 Retag(_4); // scope 1 at $DIR/inline-retag.rs:12:7: 12:9 @@ -49,10 +49,10 @@ fn bar() -> bool { _9 = const bar::promoted[0]; // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/inline-retag.rs:12:11: 12:14 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:4 ~ inline_retag[317d]::bar), const_param_did: None }, [], Some(promoted[0])) } Retag(_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 _7 = &(*_9); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 Retag(_7); // scope 1 at $DIR/inline-retag.rs:12:11: 12:14 diff --git a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff index e97191b53e..2ffc025235 100644 --- a/src/test/mir-opt/inline/inline_specialization.main.Inline.diff +++ b/src/test/mir-opt/inline/inline_specialization.main.Inline.diff @@ -12,7 +12,7 @@ bb0: { StorageLive(_1); // scope 0 at $DIR/inline-specialization.rs:5:9: 5:10 -- _1 = as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 +- _1 = as Foo>::bar() -> bb1; // scope 0 at $DIR/inline-specialization.rs:5:13: 5:38 - // mir::Constant - // + span: $DIR/inline-specialization.rs:5:13: 5:36 - // + literal: Const { ty: fn() -> u32 { as Foo>::bar}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir index 00e3ef06a4..0954620596 100644 --- a/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir +++ b/src/test/mir-opt/inline/inline_trait_method_2.test2.Inline.after.mir @@ -7,6 +7,7 @@ fn test2(_1: &dyn X) -> bool { let mut _3: &dyn X; // in scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 scope 1 { debug x => _2; // in scope 1 at $DIR/inline-trait-method_2.rs:9:9: 9:10 + let mut _4: &dyn X; // in scope 1 at $DIR/inline-trait-method_2.rs:5:5: 5:12 } bb0: { @@ -15,13 +16,16 @@ fn test2(_1: &dyn X) -> bool { _3 = &(*_1); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 _2 = move _3 as &dyn X (Pointer(Unsize)); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 StorageDead(_3); // scope 0 at $DIR/inline-trait-method_2.rs:5:10: 5:11 - _0 = ::y(move _2) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 + StorageLive(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6 + _4 = _2; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:6 + _0 = ::y(move _4) -> bb1; // scope 1 at $DIR/inline-trait-method_2.rs:10:5: 10:10 // mir::Constant // + span: $DIR/inline-trait-method_2.rs:10:7: 10:8 // + literal: Const { ty: for<'r> fn(&'r dyn X) -> bool {::y}, val: Value(Scalar()) } } bb1: { + StorageDead(_4); // scope 1 at $DIR/inline-trait-method_2.rs:10:9: 10:10 StorageDead(_2); // scope 0 at $DIR/inline-trait-method_2.rs:5:11: 5:12 return; // scope 0 at $DIR/inline-trait-method_2.rs:6:2: 6:2 } diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir index 6add8d9d75..c9a6aed3d4 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.b.Inline.after.mir @@ -1,6 +1,6 @@ // MIR for `b` after Inline -fn b(_1: &mut std::boxed::Box) -> &mut T { +fn b(_1: &mut Box) -> &mut T { debug x => _1; // in scope 0 at $DIR/issue-58867-inline-as-ref-as-mut.rs:7:13: 7:14 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 diff --git a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir index 51bda6d334..89f8aae73c 100644 --- a/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir +++ b/src/test/mir-opt/inline/issue_58867_inline_as_ref_as_mut.d.Inline.after.mir @@ -1,6 +1,6 @@ // MIR for `d` after Inline -fn d(_1: &std::boxed::Box) -> &T { +fn d(_1: &Box) -> &T { 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 diff --git a/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff new file mode 100644 index 0000000000..1d20e17a84 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.deep_opt.InstCombine.diff @@ -0,0 +1,92 @@ +- // MIR for `deep_opt` before InstCombine ++ // MIR for `deep_opt` after InstCombine + + fn deep_opt() -> (u64, u64, u64) { + let mut _0: (u64, u64, u64); // return place in scope 0 at $DIR/inst_combine_deref.rs:11:18: 11:33 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11 + let mut _10: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:6: 21:8 + let mut _11: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:10: 21:12 + let mut _12: u64; // in scope 0 at $DIR/inst_combine_deref.rs:21:14: 21:16 + scope 1 { + debug x1 => _1; // in scope 1 at $DIR/inst_combine_deref.rs:12:9: 12:11 + let _2: u64; // in scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11 + scope 2 { + debug x2 => _2; // in scope 2 at $DIR/inst_combine_deref.rs:13:9: 13:11 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11 + scope 3 { + debug x3 => _3; // in scope 3 at $DIR/inst_combine_deref.rs:14:9: 14:11 + let _4: &u64; // in scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11 + scope 4 { + debug y1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:15:9: 15:11 + let _5: &u64; // in scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11 + scope 5 { + debug y2 => _5; // in scope 5 at $DIR/inst_combine_deref.rs:16:9: 16:11 + let _6: &u64; // in scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11 + scope 6 { + debug y3 => _6; // in scope 6 at $DIR/inst_combine_deref.rs:17:9: 17:11 + let _7: u64; // in scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11 + scope 7 { + debug z1 => _7; // in scope 7 at $DIR/inst_combine_deref.rs:18:9: 18:11 + let _8: u64; // in scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11 + scope 8 { + debug z2 => _8; // in scope 8 at $DIR/inst_combine_deref.rs:19:9: 19:11 + let _9: u64; // in scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11 + scope 9 { + debug z3 => _9; // in scope 9 at $DIR/inst_combine_deref.rs:20:9: 20:11 + } + } + } + } + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:12:9: 12:11 + _1 = const 1_u64; // scope 0 at $DIR/inst_combine_deref.rs:12:14: 12:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:13:9: 13:11 + _2 = const 2_u64; // scope 1 at $DIR/inst_combine_deref.rs:13:14: 13:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:14:9: 14:11 + _3 = const 3_u64; // scope 2 at $DIR/inst_combine_deref.rs:14:14: 14:15 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:15:9: 15:11 + _4 = &_1; // scope 3 at $DIR/inst_combine_deref.rs:15:14: 15:17 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:16:9: 16:11 + _5 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:16:14: 16:17 + StorageLive(_6); // scope 5 at $DIR/inst_combine_deref.rs:17:9: 17:11 + _6 = &_3; // scope 5 at $DIR/inst_combine_deref.rs:17:14: 17:17 + StorageLive(_7); // scope 6 at $DIR/inst_combine_deref.rs:18:9: 18:11 +- _7 = (*_4); // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17 ++ _7 = _1; // scope 6 at $DIR/inst_combine_deref.rs:18:14: 18:17 + StorageLive(_8); // scope 7 at $DIR/inst_combine_deref.rs:19:9: 19:11 +- _8 = (*_5); // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17 ++ _8 = _2; // scope 7 at $DIR/inst_combine_deref.rs:19:14: 19:17 + StorageLive(_9); // scope 8 at $DIR/inst_combine_deref.rs:20:9: 20:11 +- _9 = (*_6); // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17 ++ _9 = _3; // scope 8 at $DIR/inst_combine_deref.rs:20:14: 20:17 + StorageLive(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8 + _10 = _7; // scope 9 at $DIR/inst_combine_deref.rs:21:6: 21:8 + StorageLive(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12 + _11 = _8; // scope 9 at $DIR/inst_combine_deref.rs:21:10: 21:12 + StorageLive(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16 + _12 = _9; // scope 9 at $DIR/inst_combine_deref.rs:21:14: 21:16 + (_0.0: u64) = move _10; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + (_0.1: u64) = move _11; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + (_0.2: u64) = move _12; // scope 9 at $DIR/inst_combine_deref.rs:21:5: 21:17 + StorageDead(_12); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_11); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_10); // scope 9 at $DIR/inst_combine_deref.rs:21:16: 21:17 + StorageDead(_9); // scope 8 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_8); // scope 7 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_7); // scope 6 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_6); // scope 5 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:22:1: 22:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:22:1: 22:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff new file mode 100644 index 0000000000..23c18bde22 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.do_not_miscompile.InstCombine.diff @@ -0,0 +1,85 @@ +- // MIR for `do_not_miscompile` before InstCombine ++ // MIR for `do_not_miscompile` after InstCombine + + fn do_not_miscompile() -> () { + let mut _0: (); // return place in scope 0 at $DIR/inst_combine_deref.rs:54:24: 54:24 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12 + let _6: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:59:10: 59:12 + let _7: (); // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23 + let mut _8: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:5: 60:23 + let mut _9: bool; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:21 + let mut _10: i32; // in scope 0 at $DIR/inst_combine_deref.rs:60:13: 60:15 + let mut _11: !; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + scope 1 { + debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:55:9: 55:10 + let _2: i32; // in scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10 + scope 2 { + debug a => _2; // in scope 2 at $DIR/inst_combine_deref.rs:56:9: 56:10 + let mut _3: &i32; // in scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14 + scope 3 { + debug y => _3; // in scope 3 at $DIR/inst_combine_deref.rs:57:9: 57:14 + let _4: &mut &i32; // in scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10 + scope 4 { + debug z => _4; // in scope 4 at $DIR/inst_combine_deref.rs:58:9: 58:10 + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:55:9: 55:10 + _1 = const 42_i32; // scope 0 at $DIR/inst_combine_deref.rs:55:13: 55:15 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:56:9: 56:10 + _2 = const 99_i32; // scope 1 at $DIR/inst_combine_deref.rs:56:13: 56:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:57:9: 57:14 + _3 = &_1; // scope 2 at $DIR/inst_combine_deref.rs:57:17: 57:19 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:58:9: 58:10 + _4 = &mut _3; // scope 3 at $DIR/inst_combine_deref.rs:58:13: 58:19 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + _6 = &_2; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 +- _5 = &(*_6); // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 ++ _5 = _6; // scope 4 at $DIR/inst_combine_deref.rs:59:10: 59:12 + (*_4) = move _5; // scope 4 at $DIR/inst_combine_deref.rs:59:5: 59:12 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:59:11: 59:12 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:59:12: 59:13 + StorageLive(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageLive(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageLive(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21 + StorageLive(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15 + _10 = (*_3); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:15 + _9 = Eq(move _10, const 99_i32); // scope 4 at $DIR/inst_combine_deref.rs:60:13: 60:21 + StorageDead(_10); // scope 4 at $DIR/inst_combine_deref.rs:60:20: 60:21 + _8 = Not(move _9); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageDead(_9); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + switchInt(_8) -> [false: bb1, otherwise: bb2]; // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + } + + bb1: { + _7 = const (); // scope 4 at $DIR/inst_combine_deref.rs:60:5: 60:23 + StorageDead(_8); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + StorageDead(_7); // scope 4 at $DIR/inst_combine_deref.rs:60:22: 60:23 + _0 = const (); // scope 0 at $DIR/inst_combine_deref.rs:54:24: 61:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:61:1: 61:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:61:1: 61:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:61:2: 61:2 + } + + bb2: { + StorageLive(_11); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "assertion failed: *y == 99"); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } + // ty::Const + // + ty: &str + // + val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 }) + // mir::Constant + // + span: $DIR/inst_combine_deref.rs:1:1: 1:1 + // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [97, 115, 115, 101, 114, 116, 105, 111, 110, 32, 102, 97, 105, 108, 101, 100, 58, 32, 42, 121, 32, 61, 61, 32, 57, 57], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [67108863], len: Size { raw: 26 } }, size: Size { raw: 26 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 26 }) } + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff new file mode 100644 index 0000000000..69036491a1 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.dont_opt.InstCombine.diff @@ -0,0 +1,53 @@ +- // MIR for `dont_opt` before InstCombine ++ // MIR for `dont_opt` after InstCombine + + fn dont_opt() -> u64 { + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:43:18: 43:21 + let _1: i32; // in scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10 + let mut _5: &i32; // in scope 0 at $DIR/inst_combine_deref.rs:48:10: 48:14 + scope 1 { + debug y => _1; // in scope 1 at $DIR/inst_combine_deref.rs:44:9: 44:10 + let _2: &i32; // in scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13 + scope 2 { + debug _ref => _2; // in scope 2 at $DIR/inst_combine_deref.rs:45:9: 45:13 + let _3: i32; // in scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10 + scope 3 { + debug x => _3; // in scope 3 at $DIR/inst_combine_deref.rs:46:9: 46:10 + let mut _4: &i32; // in scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15 + scope 4 { + debug _1 => _4; // in scope 4 at $DIR/inst_combine_deref.rs:47:9: 47:15 + let _6: i32; // in scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11 + scope 5 { + debug _4 => _6; // in scope 5 at $DIR/inst_combine_deref.rs:49:9: 49:11 + } + } + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:44:9: 44:10 + _1 = const 5_i32; // scope 0 at $DIR/inst_combine_deref.rs:44:13: 44:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:45:9: 45:13 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:45:16: 45:18 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:46:9: 46:10 + _3 = const 5_i32; // scope 2 at $DIR/inst_combine_deref.rs:46:13: 46:14 + StorageLive(_4); // scope 3 at $DIR/inst_combine_deref.rs:47:9: 47:15 + _4 = &_3; // scope 3 at $DIR/inst_combine_deref.rs:47:18: 47:20 + StorageLive(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 +- _5 = &(*_2); // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 ++ _5 = _2; // scope 4 at $DIR/inst_combine_deref.rs:48:10: 48:14 + _4 = move _5; // scope 4 at $DIR/inst_combine_deref.rs:48:5: 48:14 + StorageDead(_5); // scope 4 at $DIR/inst_combine_deref.rs:48:13: 48:14 + StorageLive(_6); // scope 4 at $DIR/inst_combine_deref.rs:49:9: 49:11 + _6 = (*_4); // scope 4 at $DIR/inst_combine_deref.rs:49:14: 49:17 + _0 = const 0_u64; // scope 5 at $DIR/inst_combine_deref.rs:50:5: 50:6 + StorageDead(_6); // scope 4 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_4); // scope 3 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:51:1: 51:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:51:1: 51:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:51:2: 51:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff new file mode 100644 index 0000000000..c867543d05 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.opt_struct.InstCombine.diff @@ -0,0 +1,44 @@ +- // MIR for `opt_struct` before InstCombine ++ // MIR for `opt_struct` after InstCombine + + fn opt_struct(_1: S) -> u64 { + debug s => _1; // in scope 0 at $DIR/inst_combine_deref.rs:30:15: 30:16 + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:30:24: 30:27 + let _2: &u64; // in scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10 + let mut _5: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:5: 34:7 + let mut _6: u64; // in scope 0 at $DIR/inst_combine_deref.rs:34:10: 34:11 + scope 1 { + debug a => _2; // in scope 1 at $DIR/inst_combine_deref.rs:31:9: 31:10 + let _3: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10 + scope 2 { + debug b => _3; // in scope 2 at $DIR/inst_combine_deref.rs:32:9: 32:10 + let _4: u64; // in scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10 + scope 3 { + debug x => _4; // in scope 3 at $DIR/inst_combine_deref.rs:33:9: 33:10 + } + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/inst_combine_deref.rs:31:9: 31:10 + _2 = &(_1.0: u64); // scope 0 at $DIR/inst_combine_deref.rs:31:13: 31:17 + StorageLive(_3); // scope 1 at $DIR/inst_combine_deref.rs:32:9: 32:10 + _3 = &(_1.1: u64); // scope 1 at $DIR/inst_combine_deref.rs:32:13: 32:17 + StorageLive(_4); // scope 2 at $DIR/inst_combine_deref.rs:33:9: 33:10 +- _4 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15 ++ _4 = (_1.0: u64); // scope 2 at $DIR/inst_combine_deref.rs:33:13: 33:15 + StorageLive(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 +- _5 = (*_3); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 ++ _5 = (_1.1: u64); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:7 + StorageLive(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + _6 = _4; // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + _0 = Add(move _5, move _6); // scope 3 at $DIR/inst_combine_deref.rs:34:5: 34:11 + StorageDead(_6); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + StorageDead(_5); // scope 3 at $DIR/inst_combine_deref.rs:34:10: 34:11 + StorageDead(_4); // scope 2 at $DIR/inst_combine_deref.rs:35:1: 35:2 + StorageDead(_3); // scope 1 at $DIR/inst_combine_deref.rs:35:1: 35:2 + StorageDead(_2); // scope 0 at $DIR/inst_combine_deref.rs:35:1: 35:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:35:2: 35:2 + } + } + diff --git a/src/test/mir-opt/inst_combine_deref.rs b/src/test/mir-opt/inst_combine_deref.rs new file mode 100644 index 0000000000..78361c3366 --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.rs @@ -0,0 +1,69 @@ +// compile-flags: -O -Zunsound-mir-opts +// EMIT_MIR inst_combine_deref.simple_opt.InstCombine.diff +fn simple_opt() -> u64 { + let x = 5; + let y = &x; + let z = *y; + z +} + +// EMIT_MIR inst_combine_deref.deep_opt.InstCombine.diff +fn deep_opt() -> (u64, u64, u64) { + let x1 = 1; + let x2 = 2; + let x3 = 3; + let y1 = &x1; + let y2 = &x2; + let y3 = &x3; + let z1 = *y1; + let z2 = *y2; + let z3 = *y3; + (z1, z2, z3) +} + +struct S { + a: u64, + b: u64, +} + +// EMIT_MIR inst_combine_deref.opt_struct.InstCombine.diff +fn opt_struct(s: S) -> u64 { + let a = &s.a; + let b = &s.b; + let x = *a; + *b + x +} + +// EMIT_MIR inst_combine_deref.dont_opt.InstCombine.diff +// do not optimize a sequence looking like this: +// _1 = &_2; +// _1 = _3; +// _4 = *_1; +// as the _1 = _3 assignment makes it not legal to replace the last statement with _4 = _2 +fn dont_opt() -> u64 { + let y = 5; + let _ref = &y; + let x = 5; + let mut _1 = &x; + _1 = _ref; + let _4 = *_1; + 0 +} + +// EMIT_MIR inst_combine_deref.do_not_miscompile.InstCombine.diff +fn do_not_miscompile() { + let x = 42; + let a = 99; + let mut y = &x; + let z = &mut y; + *z = &a; + assert!(*y == 99); +} + +fn main() { + simple_opt(); + deep_opt(); + opt_struct(S { a: 0, b: 1 }); + dont_opt(); + do_not_miscompile(); +} diff --git a/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff new file mode 100644 index 0000000000..f52dfe379c --- /dev/null +++ b/src/test/mir-opt/inst_combine_deref.simple_opt.InstCombine.diff @@ -0,0 +1,34 @@ +- // MIR for `simple_opt` before InstCombine ++ // MIR for `simple_opt` after InstCombine + + fn simple_opt() -> u64 { + let mut _0: u64; // return place in scope 0 at $DIR/inst_combine_deref.rs:3:20: 3:23 + let _1: u64; // in scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10 + scope 1 { + debug x => _1; // in scope 1 at $DIR/inst_combine_deref.rs:4:9: 4:10 + let _2: &u64; // in scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10 + scope 2 { + debug y => _2; // in scope 2 at $DIR/inst_combine_deref.rs:5:9: 5:10 + let _3: u64; // in scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10 + scope 3 { + debug z => _3; // in scope 3 at $DIR/inst_combine_deref.rs:6:9: 6:10 + } + } + } + + bb0: { + StorageLive(_1); // scope 0 at $DIR/inst_combine_deref.rs:4:9: 4:10 + _1 = const 5_u64; // scope 0 at $DIR/inst_combine_deref.rs:4:13: 4:14 + StorageLive(_2); // scope 1 at $DIR/inst_combine_deref.rs:5:9: 5:10 + _2 = &_1; // scope 1 at $DIR/inst_combine_deref.rs:5:13: 5:15 + StorageLive(_3); // scope 2 at $DIR/inst_combine_deref.rs:6:9: 6:10 +- _3 = (*_2); // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15 ++ _3 = _1; // scope 2 at $DIR/inst_combine_deref.rs:6:13: 6:15 + _0 = _3; // scope 3 at $DIR/inst_combine_deref.rs:7:5: 7:6 + StorageDead(_3); // scope 2 at $DIR/inst_combine_deref.rs:8:1: 8:2 + StorageDead(_2); // scope 1 at $DIR/inst_combine_deref.rs:8:1: 8:2 + StorageDead(_1); // scope 0 at $DIR/inst_combine_deref.rs:8:1: 8:2 + return; // scope 0 at $DIR/inst_combine_deref.rs:8:2: 8:2 + } + } + diff --git a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff index 01d837d155..5b2572655c 100644 --- a/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.bar.InstrumentCoverage.diff @@ -6,7 +6,7 @@ bb0: { _0 = const true; // scope 0 at /the/src/instrument_coverage.rs:20:5: 20:9 -+ Coverage { kind: Counter { function_source_hash: 10208505205182607101, id: CounterValueReference(0) }, code_region: /the/src/instrument_coverage.rs:19:18 - 21:2 }; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 ++ Coverage::Counter(0) for /the/src/instrument_coverage.rs:19:18 - 21:2; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 return; // scope 0 at /the/src/instrument_coverage.rs:21:2: 21:2 } } diff --git a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff index 43c8be8f45..03affed050 100644 --- a/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff +++ b/src/test/mir-opt/instrument_coverage.main.InstrumentCoverage.diff @@ -8,7 +8,7 @@ let mut _3: !; // in scope 0 at /the/src/instrument_coverage.rs:12:18: 14:10 bb0: { -+ Coverage { kind: Counter { function_source_hash: 16004455475339839479, id: CounterValueReference(0) }, code_region: /the/src/instrument_coverage.rs:10:11 - 16:2 }; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 ++ Coverage::Counter(0) for /the/src/instrument_coverage.rs:10:11 - 16:2; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 falseUnwind -> [real: bb1, cleanup: bb2]; // scope 0 at /the/src/instrument_coverage.rs:11:5: 15:6 } diff --git a/src/test/mir-opt/issue-41697.rs b/src/test/mir-opt/issue-41697.rs index 2c4f754484..5c34d8e68d 100644 --- a/src/test/mir-opt/issue-41697.rs +++ b/src/test/mir-opt/issue-41697.rs @@ -14,7 +14,7 @@ trait Foo { } // EMIT_MIR_FOR_EACH_BIT_WIDTH -// EMIT_MIR issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir +// EMIT_MIR issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.mir impl Foo for [u8; 1+1] { fn get(&self) -> [u8; 2] { *self diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir similarity index 69% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit rename to src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir index 1cef88fd10..f1f4b97035 100644 --- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.32bit +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.32bit.mir @@ -1,12 +1,12 @@ -// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts +// MIR for `::{constant#0}` after SimplifyCfg-promote-consts -::{{constant}}#0: usize = { +::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 bb0: { _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 - assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir similarity index 69% rename from src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit rename to src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir index 1cef88fd10..f1f4b97035 100644 --- a/src/test/mir-opt/issue_41697.{{impl}}-{{constant}}.SimplifyCfg-promote-consts.after.mir.64bit +++ b/src/test/mir-opt/issue_41697.{impl#0}-{constant#0}.SimplifyCfg-promote-consts.after.64bit.mir @@ -1,12 +1,12 @@ -// MIR for `::{{constant}}#0` after SimplifyCfg-promote-consts +// MIR for `::{constant#0}` after SimplifyCfg-promote-consts -::{{constant}}#0: usize = { +::{constant#0}: usize = { let mut _0: usize; // return place in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 let mut _1: (usize, bool); // in scope 0 at $DIR/issue-41697.rs:18:19: 18:22 bb0: { _1 = CheckedAdd(const 1_usize, const 1_usize); // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 - assert(!move (_1.1: bool), "attempt to compute `{} + {}` which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 + assert(!move (_1.1: bool), "attempt to compute `{} + {}`, which would overflow", const 1_usize, const 1_usize) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-41697.rs:18:19: 18:22 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir index c71ae93462..137d9a8247 100644 --- a/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir +++ b/src/test/mir-opt/issue_62289.test.ElaborateDrops.before.mir @@ -1,6 +1,6 @@ // MIR for `test` before ElaborateDrops -fn test() -> std::option::Option> { +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 @@ -29,8 +29,8 @@ fn test() -> std::option::Option> { _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 = std::option::Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 - _3 = as std::ops::Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/issue-62289.rs:9:15: 9:20 + _4 = Option::::None; // scope 0 at $DIR/issue-62289.rs:9:15: 9:19 + _3 = as Try>::into_result(move _4) -> [return: bb2, unwind: bb3]; // 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::result::Result< as std::ops::Try>::Ok, as std::ops::Try>::Error> { as std::ops::Try>::into_result}, val: Value(Scalar()) } @@ -69,7 +69,7 @@ fn test() -> std::option::Option> { StorageLive(_8); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 StorageLive(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 _9 = _6; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _8 = >::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _8 = >::from(move _9) -> [return: bb8, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:19: 9:20 // + literal: Const { ty: fn(std::option::NoneError) -> std::option::NoneError {>::from}, val: Value(Scalar()) } @@ -81,7 +81,7 @@ fn test() -> std::option::Option> { bb8: { StorageDead(_9); // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 - _0 = > as std::ops::Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 + _0 = > as Try>::from_error(move _8) -> [return: bb9, unwind: bb3]; // scope 2 at $DIR/issue-62289.rs:9:19: 9:20 // mir::Constant // + span: $DIR/issue-62289.rs:9:15: 9:20 // + literal: Const { ty: fn(> as std::ops::Try>::Error) -> std::option::Option> {> as std::ops::Try>::from_error}, val: Value(Scalar()) } @@ -106,7 +106,7 @@ fn test() -> std::option::Option> { bb12: { StorageDead(_2); // scope 0 at $DIR/issue-62289.rs:9:20: 9:21 - _0 = std::option::Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 + _0 = Option::>::Some(move _1); // scope 0 at $DIR/issue-62289.rs:9:5: 9:22 drop(_1) -> bb13; // scope 0 at $DIR/issue-62289.rs:9:21: 9:22 } diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.bar.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.bar.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/issue_72181.bar.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/issue_72181.bar.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.bar.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir similarity index 88% rename from src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir index 972a36a30a..c94f6c28cd 100644 --- a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.32bit +++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.32bit.mir @@ -12,7 +12,7 @@ fn foo(_1: [(Never, u32); 1]) -> u32 { _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 - assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir similarity index 88% rename from src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir index 972a36a30a..c94f6c28cd 100644 --- a/src/test/mir-opt/issue_72181.foo.mir_map.0.mir.64bit +++ b/src/test/mir-opt/issue_72181.foo.mir_map.0.64bit.mir @@ -12,7 +12,7 @@ fn foo(_1: [(Never, u32); 1]) -> u32 { _2 = const 0_usize; // scope 0 at $DIR/issue-72181.rs:16:43: 16:44 _3 = Len(_1); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 _4 = Lt(_2, _3); // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 - assert(move _4, "index out of bounds: the len is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 + assert(move _4, "index out of bounds: the length is {} but the index is {}", move _3, _2) -> [success: bb2, unwind: bb1]; // scope 0 at $DIR/issue-72181.rs:16:40: 16:45 } bb1 (cleanup): { diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir similarity index 95% rename from src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit rename to src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir index 89b6012149..e003dc2aad 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.32bit +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.32bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 - assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 } bb3: { diff --git a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir similarity index 95% rename from src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit rename to src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir index 89b6012149..e003dc2aad 100644 --- a/src/test/mir-opt/issue_72181.main.mir_map.0.mir.64bit +++ b/src/test/mir-opt/issue_72181.main.mir_map.0.64bit.mir @@ -48,7 +48,7 @@ fn main() -> () { _6 = const 0_usize; // scope 4 at $DIR/issue-72181.rs:27:24: 27:25 _7 = Len(_2); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 _8 = Lt(_6, _7); // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 - assert(move _8, "index out of bounds: the len is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 + assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb3, unwind: bb1]; // scope 4 at $DIR/issue-72181.rs:27:22: 27:26 } bb3: { diff --git a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir index b3aea29f13..d9e5d2c389 100644 --- a/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir +++ b/src/test/mir-opt/issue_72181_1.main.mir_map.0.mir @@ -21,7 +21,7 @@ fn main() -> () { StorageLive(_2); // scope 0 at $DIR/issue-72181-1.rs:16:9: 16:10 StorageLive(_3); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 _3 = (); // scope 2 at $DIR/issue-72181-1.rs:17:41: 17:43 - _2 = std::intrinsics::transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 + _2 = transmute::<(), Void>(move _3) -> [return: bb2, unwind: bb1]; // scope 2 at $DIR/issue-72181-1.rs:17:9: 17:44 // mir::Constant // + span: $DIR/issue-72181-1.rs:17:9: 17:40 // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(()) -> Void {std::intrinsics::transmute::<(), Void>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff similarity index 56% rename from src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit rename to src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff index b940f1a929..ef7c73068f 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.64bit +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.32bit.diff @@ -3,66 +3,65 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _14: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _14: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _16: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _17: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _21: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _26: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _22: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 - let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _25; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg1 => _28; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _24; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { - debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug x => _28; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _31; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -70,31 +69,29 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_4 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + discriminant(_4) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + (_5.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } + (_5.1: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -109,99 +106,88 @@ bb1: { StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _18 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_17.0: &&i32) = &_18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _20 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + (_17.1: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _25 = (_17.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _28 = (_17.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _24 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _23 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb3: { - StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb4: { - (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _26 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb5: { - StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb6: { - (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _16 = [move _21, move _22]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _15 = &_16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_30) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff similarity index 56% rename from src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit rename to src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff index b940f1a929..ef7c73068f 100644 --- a/src/test/mir-opt/issue_73223.main.PreCodegen.diff.32bit +++ b/src/test/mir-opt/issue_73223.main.PreCodegen.64bit.diff @@ -3,66 +3,65 @@ fn main() -> () { let mut _0: (); // return place in scope 0 at $DIR/issue-73223.rs:1:11: 1:11 - let mut _1: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - let _2: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - let mut _4: i32; // in scope 0 at $DIR/issue-73223.rs:7:22: 7:27 + let _1: i32; // in scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + let mut _2: std::option::Option; // in scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + let _3: i32; // in scope 0 at $DIR/issue-73223.rs:3:14: 3:15 let mut _5: (&i32, &i32); // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _6: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _9: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _10: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _11: i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _12: &std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL let _13: std::fmt::Arguments; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _14: &[&str]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _15: &[std::fmt::ArgumentV1]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _16: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let _17: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _18: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _14: &[&str; 3]; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _15: &[std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _16: [std::fmt::ArgumentV1; 2]; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _17: (&&i32, &&i32); // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let _18: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let mut _19: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _20: &i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _21: &&i32; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _24: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _25: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _26: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _21: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _22: std::fmt::ArgumentV1; // in scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL scope 1 { - debug split => _2; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 - let _3: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 + debug split => _1; // in scope 1 at $DIR/issue-73223.rs:2:9: 2:14 + let _4: std::option::Option; // in scope 1 at $DIR/issue-73223.rs:7:9: 7:14 scope 3 { - debug _prev => _3; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 + debug _prev => _4; // in scope 3 at $DIR/issue-73223.rs:7:9: 7:14 let _7: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL let _8: &i32; // in scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 4 { debug left_val => _7; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL debug right_val => _8; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _22: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let _23: &&i32; // in scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 5 { - debug arg0 => _22; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - debug arg1 => _23; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg0 => _25; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + debug arg1 => _28; // in scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL scope 6 { - debug x => _22; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug f => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _28: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _29: &core::fmt::Opaque; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + debug x => _25; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug f => _24; // in scope 6 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _23: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _24: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _25: &&i32; // in scope 6 at $SRC_DIR/std/src/macros.rs:LL:COL } scope 8 { - debug x => _23; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug x => _28; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL debug f => _27; // in scope 8 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _30: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL - let mut _31: &core::fmt::Opaque; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _26: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _27: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _28: &&i32; // in scope 8 at $SRC_DIR/std/src/macros.rs:LL:COL } } scope 10 { - debug pieces => _14; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - debug args => _15; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - let mut _32: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + debug pieces => _29; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + debug args => _31; // in scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + let mut _29: &[&str]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _30: std::option::Option<&[std::fmt::rt::v1::Argument]>; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL + let mut _31: &[std::fmt::ArgumentV1]; // in scope 10 at $SRC_DIR/std/src/macros.rs:LL:COL } } } } scope 2 { - debug v => _2; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 + debug v => _3; // in scope 2 at $DIR/issue-73223.rs:3:14: 3:15 } scope 7 { } @@ -70,31 +69,29 @@ } bb0: { - StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - ((_1 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - discriminant(_1) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 - _2 = ((_1 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 - StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 - StorageLive(_3); // scope 1 at $DIR/issue-73223.rs:7:9: 7:14 - StorageLive(_4); // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - _4 = _2; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 - ((_3 as Some).0: i32) = move _4; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - discriminant(_3) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 - StorageDead(_4); // scope 1 at $DIR/issue-73223.rs:7:27: 7:28 - StorageLive(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _6 = &_2; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.0: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_5.1: &i32) = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_1); // scope 0 at $DIR/issue-73223.rs:2:9: 2:14 + StorageLive(_2); // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + ((_2 as Some).0: i32) = const 1_i32; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + discriminant(_2) = 1; // scope 0 at $DIR/issue-73223.rs:2:23: 2:30 + StorageLive(_3); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _3 = ((_2 as Some).0: i32); // scope 0 at $DIR/issue-73223.rs:3:14: 3:15 + _1 = _3; // scope 2 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_3); // scope 0 at $DIR/issue-73223.rs:3:20: 3:21 + StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 + ((_4 as Some).0: i32) = _1; // scope 1 at $DIR/issue-73223.rs:7:22: 7:27 + discriminant(_4) = 1; // scope 1 at $DIR/issue-73223.rs:7:17: 7:28 + (_5.0: &i32) = &_1; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _6 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } - StorageDead(_6); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } + (_5.1: &i32) = move _6; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _7 = (_5.0: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _8 = (_5.1: &i32); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_10); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -109,99 +106,88 @@ bb1: { StorageDead(_9); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageDead(_8); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_7); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageDead(_5); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 - StorageDead(_3); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 + StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } bb2: { StorageLive(_13); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _14 = const main::promoted[0] as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _14 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } - StorageLive(_17); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_18); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } + _29 = move _14 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + StorageLive(_16); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_18); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _18 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_17.0: &&i32) = &_18; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_19); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _20 = _7; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _20 = _8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _19 = &_20; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_21); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _21 = &_8; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - (_18.0: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - (_18.1: &&i32) = move _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + (_17.1: &&i32) = move _19; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageDead(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _22 = (_18.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _23 = (_18.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - StorageLive(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _25 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _25 = (_17.0: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _28 = (_17.1: &&i32); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _24 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _28 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _25) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _23 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _24) -> bb3; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb3: { - StorageLive(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _29 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _22) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_21.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _25) -> bb4; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb4: { - (_24.0: &core::fmt::Opaque) = move _29; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_24.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _28; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_29); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_28); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageLive(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _27 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + (_21.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _23; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_23); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _27 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } - StorageLive(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _30 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageLive(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _26 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _27) -> bb5; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } bb5: { - StorageLive(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _31 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _23) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.0: &core::fmt::Opaque) = transmute::<&&i32, &core::fmt::Opaque>(move _28) -> bb6; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } bb6: { - (_26.0: &core::fmt::Opaque) = move _31; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_26.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _30; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_31); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_30); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _17 = [move _24, move _26]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_26); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageDead(_24); // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL - _16 = &_17; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - _15 = move _16 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - StorageLive(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - discriminant(_32) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.0: &[&str]) = move _14; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _32; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - (_13.2: &[std::fmt::ArgumentV1]) = move _15; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - StorageDead(_32); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_22.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _26; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_26); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _16 = [move _21, move _22]; // scope 5 at $SRC_DIR/std/src/macros.rs:LL:COL + _15 = &_16; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + _31 = move _15 as &[std::fmt::ArgumentV1] (Pointer(Unsize)); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + StorageLive(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + discriminant(_30) = 0; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.0: &[&str]) = move _29; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.1: std::option::Option<&[std::fmt::rt::v1::Argument]>) = move _30; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + (_13.2: &[std::fmt::ArgumentV1]) = move _31; // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + StorageDead(_30); // scope 10 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _12 = &_13; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _12); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff similarity index 92% rename from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit rename to src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff index 586a9f7624..1a6ee724cb 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.64bit +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.32bit.diff @@ -106,7 +106,7 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + return; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 } bb2: { @@ -129,10 +129,10 @@ _45 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } _11 = _45; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -153,14 +153,10 @@ StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_15) -> [false: bb4, otherwise: bb5]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_15) -> [false: bb3, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb3: { - return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 - } - - bb4: { _8 = const (); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -170,10 +166,10 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } - bb5: { + bb4: { StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL @@ -184,10 +180,10 @@ _44 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _25 = _44; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _24 = _25; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -217,31 +213,31 @@ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _40 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _40 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_46); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _47 = _40; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _46 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _46 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb6: { + bb5: { StorageDead(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_48); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _49 = _39; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _48 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb7: { + bb6: { StorageDead(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -253,31 +249,31 @@ StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _43 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _43 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_50); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _51 = _43; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _50 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _50 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb8: { + bb7: { StorageDead(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_52); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _53 = _42; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _52 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb9: { + bb8: { StorageDead(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -310,7 +306,7 @@ StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff similarity index 92% rename from src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit rename to src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff index 586a9f7624..1a6ee724cb 100644 --- a/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.diff.32bit +++ b/src/test/mir-opt/issue_73223.main.SimplifyArmIdentity.64bit.diff @@ -106,7 +106,7 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 StorageDead(_2); // scope 0 at $DIR/issue-73223.rs:5:6: 5:7 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 + return; // scope 0 at $DIR/issue-73223.rs:4:17: 4:23 } bb2: { @@ -129,10 +129,10 @@ _45 = const main::promoted[1]; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[1])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[1])) } _11 = _45; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.0: &i32) = move _10; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL (_9.1: &i32) = move _11; // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -153,14 +153,10 @@ StorageDead(_17); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _15 = Not(move _16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_16); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - switchInt(_15) -> [false: bb4, otherwise: bb5]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + switchInt(_15) -> [false: bb3, otherwise: bb4]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL } bb3: { - return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 - } - - bb4: { _8 = const (); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_15); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageDead(_14); // scope 3 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -170,10 +166,10 @@ _0 = const (); // scope 0 at $DIR/issue-73223.rs:1:11: 9:2 StorageDead(_6); // scope 1 at $DIR/issue-73223.rs:9:1: 9:2 StorageDead(_1); // scope 0 at $DIR/issue-73223.rs:9:1: 9:2 - goto -> bb3; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 + return; // scope 0 at $DIR/issue-73223.rs:9:2: 9:2 } - bb5: { + bb4: { StorageLive(_19); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL StorageLive(_21); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL @@ -184,10 +180,10 @@ _44 = const main::promoted[0]; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // ty::Const // + ty: &[&str; 3] - // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL - // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &[&str; 3], val: Unevaluated(WithOptConstParam { did: DefId(0:3 ~ issue_73223[317d]::main), const_param_did: None }, [], Some(promoted[0])) } _25 = _44; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _24 = _25; // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _23 = move _24 as &[&str] (Pointer(Unsize)); // scope 4 at $SRC_DIR/core/src/macros/mod.rs:LL:COL @@ -217,31 +213,31 @@ StorageLive(_39); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _39 = _36; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_40); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _40 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _40 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_46); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _47 = _40; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _46 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _46 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _47) -> bb5; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb6: { + bb5: { StorageDead(_47); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_48); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _49 = _39; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _48 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb7; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _48 = transmute::<&&i32, &core::fmt::Opaque>(move _49) -> bb6; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb7: { + bb6: { StorageDead(_49); // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.0: &core::fmt::Opaque) = move _48; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_38.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _46; // scope 7 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -253,31 +249,31 @@ StorageLive(_42); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL _42 = _37; // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL StorageLive(_43); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _43 = <&i32 as std::fmt::Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _43 = <&i32 as Debug>::fmt as for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> (Pointer(ReifyFnPointer)); // scope 5 at $SRC_DIR/core/src/macros/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL // + literal: Const { ty: for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {<&i32 as std::fmt::Debug>::fmt}, val: Value(Scalar()) } StorageLive(_50); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _51 = _43; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _50 = std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _50 = transmute:: fn(&'r &i32, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>(move _51) -> bb7; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(for<'r, 's, 't0> fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) -> for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error> {std::intrinsics::transmute:: fn(&'r &i32, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>, for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>>}, val: Value(Scalar()) } } - bb8: { + bb7: { StorageDead(_51); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_52); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL StorageLive(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL _53 = _42; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL - _52 = std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb9; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL + _52 = transmute::<&&i32, &core::fmt::Opaque>(move _53) -> bb8; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/fmt/mod.rs:LL:COL // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(&&i32) -> &core::fmt::Opaque {std::intrinsics::transmute::<&&i32, &core::fmt::Opaque>}, val: Value(Scalar()) } } - bb9: { + bb8: { StorageDead(_53); // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.0: &core::fmt::Opaque) = move _52; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL (_41.1: for<'r, 's, 't0> fn(&'r core::fmt::Opaque, &'s mut std::fmt::Formatter<'t0>) -> std::result::Result<(), std::fmt::Error>) = move _50; // scope 9 at $SRC_DIR/core/src/fmt/mod.rs:LL:COL @@ -310,7 +306,7 @@ StorageDead(_23); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _21 = &_22; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL _20 = _21; // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic_fmt(move _20); // scope 4 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: for<'r, 's> fn(&'r std::fmt::Arguments<'s>) -> ! {std::rt::begin_panic_fmt}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/issue_76432.rs b/src/test/mir-opt/issue_76432.rs new file mode 100644 index 0000000000..c8b405ca8e --- /dev/null +++ b/src/test/mir-opt/issue_76432.rs @@ -0,0 +1,16 @@ +// Check that we do not insert StorageDead at each target if StorageDead was never seen + +// EMIT_MIR issue_76432.test.SimplifyComparisonIntegral.diff +use std::fmt::Debug; + +fn test(x: T) { + let v: &[T] = &[x, x, x]; + match v { + [ref v1, ref v2, ref v3] => [v1 as *const _, v2 as *const _, v3 as *const _], + _ => unreachable!(), + }; +} + +fn main() { + test(0u32); +} diff --git a/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff new file mode 100644 index 0000000000..499134b699 --- /dev/null +++ b/src/test/mir-opt/issue_76432.test.SimplifyComparisonIntegral.diff @@ -0,0 +1,116 @@ +- // MIR for `test` before SimplifyComparisonIntegral ++ // MIR for `test` after SimplifyComparisonIntegral + + fn test(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/issue_76432.rs:6:38: 6:39 + let mut _0: (); // return place in scope 0 at $DIR/issue_76432.rs:6:44: 6:44 + let _2: &[T]; // in scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + let mut _3: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _4: &[T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + let _5: [T; 3]; // in scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + let mut _6: T; // in scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + let mut _7: T; // in scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + let mut _8: T; // in scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + let _9: [*const T; 3]; // in scope 0 at $DIR/issue_76432.rs:8:5: 11:6 + let mut _10: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _11: usize; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _12: bool; // in scope 0 at $DIR/issue_76432.rs:9:9: 9:33 + let mut _16: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _17: *const T; // in scope 0 at $DIR/issue_76432.rs:9:38: 9:52 + let mut _18: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + let mut _19: *const T; // in scope 0 at $DIR/issue_76432.rs:9:54: 9:68 + 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/std/src/macros.rs:LL:COL + 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 + let _14: &T; // in scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + let _15: &T; // in scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + scope 2 { + debug v1 => _13; // in scope 2 at $DIR/issue_76432.rs:9:10: 9:16 + debug v2 => _14; // in scope 2 at $DIR/issue_76432.rs:9:18: 9:24 + debug v3 => _15; // in scope 2 at $DIR/issue_76432.rs:9:26: 9:32 + } + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue_76432.rs:7:9: 7:10 + StorageLive(_3); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_4); // scope 0 at $DIR/issue_76432.rs:7:19: 7:29 + StorageLive(_5); // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageLive(_6); // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + _6 = _1; // scope 0 at $DIR/issue_76432.rs:7:21: 7:22 + StorageLive(_7); // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + _7 = _1; // scope 0 at $DIR/issue_76432.rs:7:24: 7:25 + StorageLive(_8); // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _8 = _1; // scope 0 at $DIR/issue_76432.rs:7:27: 7:28 + _5 = [move _6, move _7, move _8]; // scope 0 at $DIR/issue_76432.rs:7:20: 7:29 + StorageDead(_8); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + StorageDead(_7); // scope 0 at $DIR/issue_76432.rs:7:28: 7:29 + 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 + _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 + _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 + } + + bb1: { + StorageLive(_22); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "internal error: entered unreachable code"); // scope 1 at $SRC_DIR/std/src/macros.rs:LL:COL + // mir::Constant + // + span: $SRC_DIR/std/src/macros.rs:LL:COL + // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } + // ty::Const + // + ty: &str + // + val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) + // mir::Constant + // + span: $SRC_DIR/core/src/macros/mod.rs:LL:COL + // + literal: Const { ty: &str, val: Value(Slice { data: Allocation { bytes: [105, 110, 116, 101, 114, 110, 97, 108, 32, 101, 114, 114, 111, 114, 58, 32, 101, 110, 116, 101, 114, 101, 100, 32, 117, 110, 114, 101, 97, 99, 104, 97, 98, 108, 101, 32, 99, 111, 100, 101], relocations: Relocations(SortedMap { data: [] }), init_mask: InitMask { blocks: [1099511627775], len: Size { raw: 40 } }, size: Size { raw: 40 }, align: Align { pow2: 0 }, mutability: Not, extra: () }, start: 0, end: 40 }) } + } + + bb2: { + StorageLive(_13); // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + _13 = &(*_2)[0 of 3]; // scope 1 at $DIR/issue_76432.rs:9:10: 9:16 + StorageLive(_14); // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + _14 = &(*_2)[1 of 3]; // scope 1 at $DIR/issue_76432.rs:9:18: 9:24 + StorageLive(_15); // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + _15 = &(*_2)[2 of 3]; // scope 1 at $DIR/issue_76432.rs:9:26: 9:32 + StorageLive(_16); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_17); // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + _17 = &raw const (*_13); // scope 2 at $DIR/issue_76432.rs:9:38: 9:40 + _16 = _17; // scope 2 at $DIR/issue_76432.rs:9:38: 9:52 + StorageLive(_18); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_19); // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + _19 = &raw const (*_14); // scope 2 at $DIR/issue_76432.rs:9:54: 9:56 + _18 = _19; // scope 2 at $DIR/issue_76432.rs:9:54: 9:68 + StorageLive(_20); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + StorageLive(_21); // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _21 = &raw const (*_15); // scope 2 at $DIR/issue_76432.rs:9:70: 9:72 + _20 = _21; // scope 2 at $DIR/issue_76432.rs:9:70: 9:84 + _9 = [move _16, move _18, move _20]; // scope 2 at $DIR/issue_76432.rs:9:37: 9:85 + StorageDead(_21); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_20); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_19); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_18); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_17); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_16); // scope 2 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_15); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_14); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_13); // scope 1 at $DIR/issue_76432.rs:9:84: 9:85 + StorageDead(_9); // scope 1 at $DIR/issue_76432.rs:11:6: 11:7 + _0 = const (); // scope 0 at $DIR/issue_76432.rs:6:44: 12:2 + StorageDead(_5); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + StorageDead(_2); // scope 0 at $DIR/issue_76432.rs:12:1: 12:2 + return; // scope 0 at $DIR/issue_76432.rs:12:2: 12:2 + } + } + diff --git a/src/test/mir-opt/issues/issue-75439.rs b/src/test/mir-opt/issues/issue-75439.rs new file mode 100644 index 0000000000..44d6bc619d --- /dev/null +++ b/src/test/mir-opt/issues/issue-75439.rs @@ -0,0 +1,21 @@ +// EMIT_MIR issue_75439.foo.MatchBranchSimplification.diff + +#![feature(const_fn_transmute)] +#![feature(or_patterns)] + +use std::mem::transmute; + +pub fn foo(bytes: [u8; 16]) -> Option<[u8; 4]> { + // big endian `u32`s + let dwords: [u32; 4] = unsafe { transmute(bytes) }; + const FF: u32 = 0x0000_ffff_u32.to_be(); + if let [0, 0, 0 | FF, ip] = dwords { + Some(unsafe { transmute(ip) }) + } else { + None + } +} + +fn main() { + let _ = foo([0; 16]); +} diff --git a/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff new file mode 100644 index 0000000000..43422b36e1 --- /dev/null +++ b/src/test/mir-opt/issues/issue_75439.foo.MatchBranchSimplification.diff @@ -0,0 +1,87 @@ +- // MIR for `foo` before MatchBranchSimplification ++ // MIR for `foo` after MatchBranchSimplification + + fn foo(_1: [u8; 16]) -> Option<[u8; 4]> { + debug bytes => _1; // in scope 0 at $DIR/issue-75439.rs:8:12: 8:17 + let mut _0: std::option::Option<[u8; 4]>; // return place in scope 0 at $DIR/issue-75439.rs:8:32: 8:47 + let _2: [u32; 4]; // in scope 0 at $DIR/issue-75439.rs:10:9: 10:15 + let mut _3: [u8; 16]; // in scope 0 at $DIR/issue-75439.rs:10:47: 10:52 + let mut _5: [u8; 4]; // in scope 0 at $DIR/issue-75439.rs:13:14: 13:38 + let mut _6: u32; // in scope 0 at $DIR/issue-75439.rs:13:33: 13:35 + scope 1 { + debug dwords => _2; // in scope 1 at $DIR/issue-75439.rs:10:9: 10:15 + let _4: u32; // in scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + scope 3 { + debug ip => _4; // in scope 3 at $DIR/issue-75439.rs:12:27: 12:29 + scope 4 { + } + } + } + scope 2 { + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/issue-75439.rs:10:9: 10:15 + StorageLive(_3); // scope 2 at $DIR/issue-75439.rs:10:47: 10:52 + _3 = _1; // scope 2 at $DIR/issue-75439.rs:10:47: 10:52 + _2 = transmute::<[u8; 16], [u32; 4]>(move _3) -> bb1; // scope 2 at $DIR/issue-75439.rs:10:37: 10:53 + // mir::Constant + // + span: $DIR/issue-75439.rs:10:37: 10:46 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn([u8; 16]) -> [u32; 4] {std::intrinsics::transmute::<[u8; 16], [u32; 4]>}, val: Value(Scalar()) } + } + + bb1: { + StorageDead(_3); // scope 2 at $DIR/issue-75439.rs:10:52: 10:53 + switchInt(_2[0 of 4]) -> [0_u32: bb2, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:13: 12:14 + } + + bb2: { + switchInt(_2[1 of 4]) -> [0_u32: bb3, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:16: 12:17 + } + + bb3: { + switchInt(_2[2 of 4]) -> [0_u32: bb6, 4294901760_u32: bb7, otherwise: bb4]; // scope 1 at $DIR/issue-75439.rs:12:19: 12:20 + } + + bb4: { + discriminant(_0) = 0; // scope 1 at $DIR/issue-75439.rs:15:9: 15:13 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb5: { + StorageLive(_5); // scope 3 at $DIR/issue-75439.rs:13:14: 13:38 + StorageLive(_6); // scope 4 at $DIR/issue-75439.rs:13:33: 13:35 + _6 = _4; // scope 4 at $DIR/issue-75439.rs:13:33: 13:35 + _5 = transmute::(move _6) -> bb8; // scope 4 at $DIR/issue-75439.rs:13:23: 13:36 + // mir::Constant + // + span: $DIR/issue-75439.rs:13:23: 13:32 + // + literal: Const { ty: unsafe extern "rust-intrinsic" fn(u32) -> [u8; 4] {std::intrinsics::transmute::}, val: Value(Scalar()) } + } + + bb6: { + StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb7: { + StorageLive(_4); // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + _4 = _2[3 of 4]; // scope 1 at $DIR/issue-75439.rs:12:27: 12:29 + goto -> bb5; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb8: { + StorageDead(_6); // scope 4 at $DIR/issue-75439.rs:13:35: 13:36 + ((_0 as Some).0: [u8; 4]) = move _5; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39 + discriminant(_0) = 1; // scope 3 at $DIR/issue-75439.rs:13:9: 13:39 + StorageDead(_5); // scope 3 at $DIR/issue-75439.rs:13:38: 13:39 + StorageDead(_4); // scope 1 at $DIR/issue-75439.rs:14:5: 14:6 + goto -> bb9; // scope 1 at $DIR/issue-75439.rs:12:5: 16:6 + } + + bb9: { + StorageDead(_2); // scope 0 at $DIR/issue-75439.rs:17:1: 17:2 + return; // scope 0 at $DIR/issue-75439.rs:17:2: 17:2 + } + } + diff --git a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff index 7a7d86f98a..8062f33a86 100644 --- a/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff +++ b/src/test/mir-opt/match_arm_scopes.complicated_match.SimplifyCfg-initial.after-ElaborateDrops.after.diff @@ -1,7 +1,7 @@ - // MIR for `complicated_match` after SimplifyCfg-initial + // MIR for `complicated_match` after ElaborateDrops - fn complicated_match(_1: bool, _2: (bool, bool, std::string::String)) -> i32 { + fn complicated_match(_1: bool, _2: (bool, bool, String)) -> i32 { debug cond => _1; // in scope 0 at $DIR/match-arm-scopes.rs:13:22: 13:26 debug items => _2; // in scope 0 at $DIR/match-arm-scopes.rs:13:34: 13:39 let mut _0: i32; // return place in scope 0 at $DIR/match-arm-scopes.rs:13:66: 13:69 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir index c0249d134f..e09d32c729 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match.PromoteTemps.after.mir @@ -26,7 +26,7 @@ fn full_tested_match() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:15:13: 19:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 - _2 = std::option::Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 + _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16 switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:16:9: 16:16 @@ -58,10 +58,10 @@ fn full_tested_match() -> () { _11 = const full_tested_match::promoted[0]; // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 // ty::Const // + ty: &std::option::Option - // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/match_false_edges.rs:16:14: 16:15 - // + literal: Const { ty: &std::option::Option, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &std::option::Option, val: Unevaluated(WithOptConstParam { did: DefId(0:5 ~ match_false_edges[317d]::full_tested_match), const_param_did: None }, [], Some(promoted[0])) } _6 = &(((*_11) as Some).0: i32); // scope 0 at $DIR/match_false_edges.rs:16:14: 16:15 _4 = &shallow _2; // scope 0 at $DIR/match_false_edges.rs:15:19: 15:27 StorageLive(_7); // scope 0 at $DIR/match_false_edges.rs:16:20: 16:27 diff --git a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir index a2ad5be265..a6c492581f 100644 --- a/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.full_tested_match2.PromoteTemps.before.mir @@ -25,7 +25,7 @@ fn full_tested_match2() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:26:13: 30:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 - _2 = std::option::Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 + _2 = Option::::Some(const 42_i32); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:26:19: 26:27 _3 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16 switchInt(move _3) -> [0_isize: bb2, 1_isize: bb3, otherwise: bb5]; // scope 0 at $DIR/match_false_edges.rs:27:9: 27:16 diff --git a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir index b7322e7da0..1d451cef2a 100644 --- a/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir +++ b/src/test/mir-opt/match_false_edges.main.PromoteTemps.before.mir @@ -36,7 +36,7 @@ fn main() -> () { bb0: { StorageLive(_1); // scope 0 at $DIR/match_false_edges.rs:35:13: 40:6 StorageLive(_2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 - _2 = std::option::Option::::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 + _2 = Option::::Some(const 1_i32); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 FakeRead(ForMatchedPlace, _2); // scope 0 at $DIR/match_false_edges.rs:35:19: 35:26 _4 = discriminant(_2); // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17 switchInt(move _4) -> [1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/match_false_edges.rs:36:9: 36:17 diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff similarity index 70% rename from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff index 3f01719e01..648cf241cb 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.32bit +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.32bit.diff @@ -2,83 +2,83 @@ + // MIR for `bar` after MatchBranchSimplification fn bar(_1: i32) -> (bool, bool, bool, bool) { - debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9 - let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43 - let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6 - let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:12:8: 12:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:12:19: 12:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:18:5: 33:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16 scope 1 { - debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 scope 3 { - debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 scope 4 { - debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:16:9: 16:10 } } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 - StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 -- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 -+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 -+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 -+ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 -+ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 -+ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 ++ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 ++ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 ++ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 ++ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 } bb1: { - _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21 - _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21 + _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb2: { - _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 - _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 + _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb3: { - StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7 - StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2 + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:36:2: 36:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff similarity index 70% rename from src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff index 3f01719e01..648cf241cb 100644 --- a/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.diff.64bit +++ b/src/test/mir-opt/matches_reduce_branches.bar.MatchBranchSimplification.64bit.diff @@ -2,83 +2,83 @@ + // MIR for `bar` after MatchBranchSimplification fn bar(_1: i32) -> (bool, bool, bool, bool) { - debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:11:8: 11:9 - let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:11:19: 11:43 - let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:17:5: 32:6 - let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:34:15: 34:16 + debug i => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:12:8: 12:9 + let mut _0: (bool, bool, bool, bool); // return place in scope 0 at $DIR/matches_reduce_branches.rs:12:19: 12:43 + let _2: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _6: (); // in scope 0 at $DIR/matches_reduce_branches.rs:18:5: 33:6 + let mut _7: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + let mut _8: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + let mut _9: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + let mut _10: bool; // in scope 0 at $DIR/matches_reduce_branches.rs:35:15: 35:16 scope 1 { - debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + debug a => _2; // in scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + let _3: bool; // in scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 scope 2 { - debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + debug b => _3; // in scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + let _4: bool; // in scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 scope 3 { - debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug c => _4; // in scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + let _5: bool; // in scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 scope 4 { - debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + debug d => _5; // in scope 4 at $DIR/matches_reduce_branches.rs:16:9: 16:10 } } } } bb0: { - StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:12:9: 12:10 - StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:13:9: 13:10 - StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:14:9: 14:10 - StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:15:9: 15:10 - StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 -- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 -+ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 -+ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 -+ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 -+ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 -+ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:9: 18:10 + StorageLive(_2); // scope 0 at $DIR/matches_reduce_branches.rs:13:9: 13:10 + StorageLive(_3); // scope 1 at $DIR/matches_reduce_branches.rs:14:9: 14:10 + StorageLive(_4); // scope 2 at $DIR/matches_reduce_branches.rs:15:9: 15:10 + StorageLive(_5); // scope 3 at $DIR/matches_reduce_branches.rs:16:9: 16:10 + StorageLive(_6); // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 +- switchInt(_1) -> [7_i32: bb2, otherwise: bb1]; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 ++ _2 = Ne(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 ++ _3 = Eq(_1, const 7_i32); // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 ++ _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 ++ _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 ++ goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:19:9: 19:10 } bb1: { - _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:26:13: 26:21 - _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:22 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:27:13: 27:21 + _3 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:28:13: 28:22 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:29:13: 29:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:30:13: 30:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb2: { - _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:19:13: 19:22 - _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:21 - _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:22 - _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:21 - goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:17:5: 32:6 + _2 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:20:13: 20:22 + _3 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:21:13: 21:21 + _4 = const false; // scope 4 at $DIR/matches_reduce_branches.rs:22:13: 22:22 + _5 = const true; // scope 4 at $DIR/matches_reduce_branches.rs:23:13: 23:21 + goto -> bb3; // scope 4 at $DIR/matches_reduce_branches.rs:18:5: 33:6 } bb3: { - StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:32:6: 32:7 - StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:34:6: 34:7 - StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:34:9: 34:10 - StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:34:12: 34:13 - StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:34:15: 34:16 - (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:34:5: 34:17 - StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:34:16: 34:17 - StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:35:1: 35:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:35:2: 35:2 + StorageDead(_6); // scope 4 at $DIR/matches_reduce_branches.rs:33:6: 33:7 + StorageLive(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + _7 = _2; // scope 4 at $DIR/matches_reduce_branches.rs:35:6: 35:7 + StorageLive(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + _8 = _3; // scope 4 at $DIR/matches_reduce_branches.rs:35:9: 35:10 + StorageLive(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + _9 = _4; // scope 4 at $DIR/matches_reduce_branches.rs:35:12: 35:13 + StorageLive(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + _10 = _5; // scope 4 at $DIR/matches_reduce_branches.rs:35:15: 35:16 + (_0.0: bool) = move _7; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.1: bool) = move _8; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.2: bool) = move _9; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + (_0.3: bool) = move _10; // scope 4 at $DIR/matches_reduce_branches.rs:35:5: 35:17 + StorageDead(_10); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_9); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_8); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_7); // scope 4 at $DIR/matches_reduce_branches.rs:35:16: 35:17 + StorageDead(_5); // scope 3 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_4); // scope 2 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_3); // scope 1 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:36:1: 36:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:36:2: 36:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff similarity index 77% rename from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff index 883a4e1470..a52abfb1a7 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.32bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.32bit.diff @@ -1,18 +1,18 @@ - // MIR for `foo` before MatchBranchSimplification + // MIR for `foo` after MatchBranchSimplification - fn foo(_1: std::option::Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25 + fn foo(_1: Option<()>) -> () { + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } bb1: { @@ -26,17 +26,17 @@ } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff similarity index 77% rename from src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff index 883a4e1470..a52abfb1a7 100644 --- a/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.diff.64bit +++ b/src/test/mir-opt/matches_reduce_branches.foo.MatchBranchSimplification.64bit.diff @@ -1,18 +1,18 @@ - // MIR for `foo` before MatchBranchSimplification + // MIR for `foo` after MatchBranchSimplification - fn foo(_1: std::option::Option<()>) -> () { - debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:5:8: 5:11 - let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:5:25: 5:25 + fn foo(_1: Option<()>) -> () { + debug bar => _1; // in scope 0 at $DIR/matches_reduce_branches.rs:6:8: 6:11 + let mut _0: (); // return place in scope 0 at $DIR/matches_reduce_branches.rs:6:25: 6:25 let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + let mut _3: isize; // in scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 bb0: { StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL - _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 -- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 + _3 = discriminant(_1); // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 +- switchInt(move _3) -> [0_isize: bb2, otherwise: bb1]; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 + _2 = Eq(_3, const 0_isize); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL -+ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:6:22: 6:26 ++ goto -> bb3; // scope 0 at $DIR/matches_reduce_branches.rs:7:22: 7:26 } bb1: { @@ -26,17 +26,17 @@ } bb3: { - switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + switchInt(_2) -> [false: bb4, otherwise: bb5]; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb4: { - _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 - goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:6:5: 8:6 + _0 = const (); // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 + goto -> bb5; // scope 0 at $DIR/matches_reduce_branches.rs:7:5: 9:6 } bb5: { - StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:9:1: 9:2 - return; // scope 0 at $DIR/matches_reduce_branches.rs:9:2: 9:2 + StorageDead(_2); // scope 0 at $DIR/matches_reduce_branches.rs:10:1: 10:2 + return; // scope 0 at $DIR/matches_reduce_branches.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/matches_reduce_branches.rs b/src/test/mir-opt/matches_reduce_branches.rs index ebc88d2fbd..54b79a8426 100644 --- a/src/test/mir-opt/matches_reduce_branches.rs +++ b/src/test/mir-opt/matches_reduce_branches.rs @@ -1,3 +1,4 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR_FOR_EACH_BIT_WIDTH // EMIT_MIR matches_reduce_branches.foo.MatchBranchSimplification.diff // EMIT_MIR matches_reduce_branches.bar.MatchBranchSimplification.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_u8.exhaustive_match.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.32bit rename to src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.32bit.diff diff --git a/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit b/src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff similarity index 100% rename from src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.diff.64bit rename to src/test/mir-opt/matches_u8.exhaustive_match_i8.MatchBranchSimplification.64bit.diff diff --git a/src/test/mir-opt/multiple_return_terminators.rs b/src/test/mir-opt/multiple_return_terminators.rs new file mode 100644 index 0000000000..b73a51d483 --- /dev/null +++ b/src/test/mir-opt/multiple_return_terminators.rs @@ -0,0 +1,14 @@ +// compile-flags: -Z mir-opt-level=3 +// EMIT_MIR multiple_return_terminators.test.MultipleReturnTerminators.diff + +fn test(x: bool) { + if x { + // test + } else { + // test + } +} + +fn main() { + test(true) +} diff --git a/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff new file mode 100644 index 0000000000..997c021d2e --- /dev/null +++ b/src/test/mir-opt/multiple_return_terminators.test.MultipleReturnTerminators.diff @@ -0,0 +1,30 @@ +- // MIR for `test` before MultipleReturnTerminators ++ // MIR for `test` after MultipleReturnTerminators + + fn test(_1: bool) -> () { + debug x => _1; // in scope 0 at $DIR/multiple_return_terminators.rs:4:9: 4:10 + let mut _0: (); // return place in scope 0 at $DIR/multiple_return_terminators.rs:4:18: 4:18 + let mut _2: bool; // in scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9 + + bb0: { + StorageLive(_2); // scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9 + _2 = _1; // scope 0 at $DIR/multiple_return_terminators.rs:5:8: 5:9 + switchInt(_2) -> [false: bb1, otherwise: bb2]; // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6 + } + + bb1: { + _0 = const (); // scope 0 at $DIR/multiple_return_terminators.rs:7:12: 9:6 + goto -> bb3; // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6 + } + + bb2: { + _0 = const (); // scope 0 at $DIR/multiple_return_terminators.rs:5:10: 7:6 + goto -> bb3; // scope 0 at $DIR/multiple_return_terminators.rs:5:5: 9:6 + } + + bb3: { + StorageDead(_2); // scope 0 at $DIR/multiple_return_terminators.rs:10:1: 10:2 + return; // scope 0 at $DIR/multiple_return_terminators.rs:10:2: 10:2 + } + } + diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir similarity index 97% rename from src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit rename to src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir index 2885dd8eb7..91135fbf41 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.32bit +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.32bit.mir @@ -52,7 +52,7 @@ fn main() -> () { _3 = const Const(Value(Scalar(0x00000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1 (cleanup): { diff --git a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir similarity index 97% rename from src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit rename to src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir index 3820f70d51..23dcab656c 100644 --- a/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.mir.64bit +++ b/src/test/mir-opt/nll/region_subtyping_basic.main.nll.0.64bit.mir @@ -52,7 +52,7 @@ fn main() -> () { _3 = const Const(Value(Scalar(0x0000000000000000)): usize); // bb0[5]: scope 1 at $DIR/region-subtyping-basic.rs:18:16: 18:17 _4 = Len(_1); // bb0[6]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 _5 = Lt(_3, _4); // bb0[7]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 - assert(move _5, "index out of bounds: the len is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 + assert(move _5, "index out of bounds: the length is {} but the index is {}", move _4, _3) -> [success: bb2, unwind: bb1]; // bb0[8]: scope 1 at $DIR/region-subtyping-basic.rs:18:14: 18:18 } bb1 (cleanup): { diff --git a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir index e90364c1cc..5de8e98ced 100644 --- a/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/no_drop_for_inactive_variant.unwrap.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ // MIR for `unwrap` after SimplifyCfg-elaborate-drops -fn unwrap(_1: std::option::Option) -> T { +fn unwrap(_1: Option) -> T { debug opt => _1; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:14: 7:17 let mut _0: T; // return place in scope 0 at $DIR/no-drop-for-inactive-variant.rs:7:33: 7:34 let mut _2: isize; // in scope 0 at $DIR/no-drop-for-inactive-variant.rs:9:9: 9:16 @@ -20,7 +20,7 @@ fn unwrap(_1: std::option::Option) -> T { bb1: { StorageLive(_4); // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL - std::rt::begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL + begin_panic::<&str>(const "explicit panic") -> bb4; // scope 0 at $SRC_DIR/std/src/macros.rs:LL:COL // mir::Constant // + span: $SRC_DIR/std/src/macros.rs:LL:COL // + literal: Const { ty: fn(&str) -> ! {std::rt::begin_panic::<&str>}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir index 5e1866fbc5..495c7f24c8 100644 --- a/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir +++ b/src/test/mir-opt/no_spurious_drop_after_call.main.ElaborateDrops.before.mir @@ -20,7 +20,7 @@ fn main() -> () { // + 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 } }, size: 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 - _2 = ::to_string(move _3) -> bb2; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:20: 9:34 + _2 = ::to_string(move _3) -> bb2; // 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 // + literal: Const { ty: for<'r> fn(&'r str) -> std::string::String {::to_string}, val: Value(Scalar()) } @@ -32,7 +32,7 @@ fn main() -> () { bb2: { StorageDead(_3); // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:33: 9:34 - _1 = std::mem::drop::(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 + _1 = std::mem::drop::(move _2) -> [return: bb3, unwind: bb4]; // scope 0 at $DIR/no-spurious-drop-after-call.rs:9:5: 9:35 // mir::Constant // + span: $DIR/no-spurious-drop-after-call.rs:9:5: 9:19 // + literal: Const { ty: fn(std::string::String) {std::mem::drop::}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/not_equal_false.opt.InstCombine.diff b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff new file mode 100644 index 0000000000..39830946ae --- /dev/null +++ b/src/test/mir-opt/not_equal_false.opt.InstCombine.diff @@ -0,0 +1,68 @@ +- // MIR for `opt` before InstCombine ++ // MIR for `opt` after InstCombine + + fn opt(_1: Option<()>) -> bool { + debug x => _1; // in scope 0 at $DIR/not_equal_false.rs:3:8: 3:9 + let mut _0: bool; // return place in scope 0 at $DIR/not_equal_false.rs:3:26: 3:30 + let mut _2: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _3: isize; // in scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + let mut _4: bool; // in scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + let mut _5: isize; // in scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + + bb0: { + StorageLive(_2); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _3 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + switchInt(move _3) -> [0_isize: bb6, otherwise: bb5]; // scope 0 at $DIR/not_equal_false.rs:4:17: 4:21 + } + + bb1: { + _0 = const true; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb2: { + _0 = const false; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + goto -> bb4; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb3: { + StorageLive(_4); // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + _5 = discriminant(_1); // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + switchInt(move _5) -> [1_isize: bb9, otherwise: bb8]; // scope 0 at $DIR/not_equal_false.rs:4:38: 4:45 + } + + bb4: { + StorageDead(_4); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 + StorageDead(_2); // scope 0 at $DIR/not_equal_false.rs:4:45: 4:46 + return; // scope 0 at $DIR/not_equal_false.rs:5:2: 5:2 + } + + bb5: { + _2 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb6: { + _2 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb7; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb7: { + switchInt(move _2) -> [false: bb3, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + + bb8: { + _4 = const false; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb9: { + _4 = const true; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + goto -> bb10; // scope 0 at $SRC_DIR/core/src/macros/mod.rs:LL:COL + } + + bb10: { + switchInt(move _4) -> [false: bb2, otherwise: bb1]; // scope 0 at $DIR/not_equal_false.rs:4:5: 4:46 + } + } + diff --git a/src/test/mir-opt/not_equal_false.rs b/src/test/mir-opt/not_equal_false.rs new file mode 100644 index 0000000000..a98a2834e8 --- /dev/null +++ b/src/test/mir-opt/not_equal_false.rs @@ -0,0 +1,9 @@ +// EMIT_MIR not_equal_false.opt.InstCombine.diff + +fn opt(x: Option<()>) -> bool { + matches!(x, None) || matches!(x, Some(_)) +} + +fn main() { + opt(None); +} diff --git a/src/test/mir-opt/nrvo-simple.rs b/src/test/mir-opt/nrvo-simple.rs index f0eb711b3f..ab46d7b94c 100644 --- a/src/test/mir-opt/nrvo-simple.rs +++ b/src/test/mir-opt/nrvo-simple.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zmir-opt-level=1 + // EMIT_MIR nrvo_simple.nrvo.RenameReturnPlace.diff fn nrvo(init: fn(&mut [u8; 1024])) -> [u8; 1024] { let mut buf = [0; 1024]; diff --git a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff index 924e87ea8c..f438eaa002 100644 --- a/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff +++ b/src/test/mir-opt/nrvo_simple.nrvo.RenameReturnPlace.diff @@ -2,39 +2,42 @@ + // MIR for `nrvo` after RenameReturnPlace fn nrvo(_1: for<'r> fn(&'r mut [u8; 1024])) -> [u8; 1024] { - debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:2:9: 2:13 -- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:2:39: 2:49 -+ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 - let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 - let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:19 - let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:4:5: 4:9 - let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18 - let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:4:10: 4:18 + debug init => _1; // in scope 0 at $DIR/nrvo-simple.rs:4:9: 4:13 +- let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:4:39: 4:49 ++ let mut _0: [u8; 1024]; // return place in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let mut _2: [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 + let _3: (); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:19 + let mut _4: for<'r> fn(&'r mut [u8; 1024]); // in scope 0 at $DIR/nrvo-simple.rs:6:5: 6:9 + let mut _5: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 + let mut _6: &mut [u8; 1024]; // in scope 0 at $DIR/nrvo-simple.rs:6:10: 6:18 scope 1 { -- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16 -+ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:3:9: 3:16 +- debug buf => _2; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 ++ debug buf => _0; // in scope 1 at $DIR/nrvo-simple.rs:5:9: 5:16 } bb0: { -- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:3:9: 3:16 -- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28 -+ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:3:19: 3:28 - StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 - StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 -- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 -+ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:4:10: 4:18 - _3 = move _1(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:4:5: 4:19 +- StorageLive(_2); // scope 0 at $DIR/nrvo-simple.rs:5:9: 5:16 +- _2 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 ++ _0 = [const 0_u8; 1024]; // scope 0 at $DIR/nrvo-simple.rs:5:19: 5:28 + StorageLive(_3); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 + StorageLive(_4); // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + _4 = _1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:9 + StorageLive(_5); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + StorageLive(_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 +- _6 = &mut _2; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 ++ _6 = &mut _0; // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _5 = &mut (*_6); // scope 1 at $DIR/nrvo-simple.rs:6:10: 6:18 + _3 = move _4(move _5) -> bb1; // scope 1 at $DIR/nrvo-simple.rs:6:5: 6:19 } bb1: { - StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:4:18: 4:19 - StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 - StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:4:19: 4:20 -- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:5:5: 5:8 -- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:6:1: 6:2 - return; // scope 0 at $DIR/nrvo-simple.rs:6:2: 6:2 + StorageDead(_5); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_4); // scope 1 at $DIR/nrvo-simple.rs:6:18: 6:19 + StorageDead(_6); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 + StorageDead(_3); // scope 1 at $DIR/nrvo-simple.rs:6:19: 6:20 +- _0 = _2; // scope 1 at $DIR/nrvo-simple.rs:7:5: 7:8 +- StorageDead(_2); // scope 0 at $DIR/nrvo-simple.rs:8:1: 8:2 + return; // scope 0 at $DIR/nrvo-simple.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir similarity index 100% rename from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.32bit rename to src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.32bit.mir diff --git a/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit b/src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir similarity index 100% rename from src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.mir.64bit rename to src/test/mir-opt/packed_struct_drop_aligned.main.SimplifyCfg-elaborate-drops.after.64bit.mir diff --git a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff index 2b7e4bbffe..47027311b4 100644 --- a/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff +++ b/src/test/mir-opt/remove_fake_borrows.match_guard.CleanupNonCodegenStatements.diff @@ -1,7 +1,7 @@ - // MIR for `match_guard` before CleanupNonCodegenStatements + // MIR for `match_guard` after CleanupNonCodegenStatements - fn match_guard(_1: std::option::Option<&&i32>, _2: bool) -> i32 { + fn match_guard(_1: Option<&&i32>, _2: bool) -> i32 { debug x => _1; // in scope 0 at $DIR/remove_fake_borrows.rs:6:16: 6:17 debug c => _2; // in scope 0 at $DIR/remove_fake_borrows.rs:6:34: 6:35 let mut _0: i32; // return place in scope 0 at $DIR/remove_fake_borrows.rs:6:46: 6:49 diff --git a/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..787cf6f97c --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `cannot_opt_generic` before RemoveUnneededDrops ++ // MIR for `cannot_opt_generic` after RemoveUnneededDrops + + fn cannot_opt_generic(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:20:26: 20:27 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 20:32 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:5: 21:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:21:10: 21:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:20:1: 22:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:21:11: 21:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:21:12: 21:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:20:32: 22:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:22:2: 22:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..52e182eeb4 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff @@ -0,0 +1,32 @@ +- // MIR for `dont_opt` before RemoveUnneededDrops ++ // MIR for `dont_opt` after RemoveUnneededDrops + + fn dont_opt(_1: Vec) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:8:13: 8:14 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 8:27 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + let mut _3: std::vec::Vec; // in scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:5: 9:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + _3 = move _1; // scope 0 at $DIR/remove_unneeded_drops.rs:9:10: 9:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + drop(_3) -> [return: bb2, unwind: bb1]; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb1 (cleanup): { + resume; // scope 0 at $DIR/remove_unneeded_drops.rs:8:1: 10:2 + } + + bb2: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:9:11: 9:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:9:12: 9:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:8:27: 10:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:10:2: 10:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..bc9e1344f3 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt.RemoveUnneededDrops.diff @@ -0,0 +1,28 @@ +- // MIR for `opt` before RemoveUnneededDrops ++ // MIR for `opt` after RemoveUnneededDrops + + fn opt(_1: bool) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:3:8: 3:9 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 3:17 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + let mut _3: bool; // in scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:5: 4:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:4:10: 4:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- } +- +- bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:4:11: 4:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:4:12: 4:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:3:17: 5:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:5:2: 5:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff new file mode 100644 index 0000000000..5c8b1d1372 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff @@ -0,0 +1,28 @@ +- // MIR for `opt_generic_copy` before RemoveUnneededDrops ++ // MIR for `opt_generic_copy` after RemoveUnneededDrops + + fn opt_generic_copy(_1: T) -> () { + debug x => _1; // in scope 0 at $DIR/remove_unneeded_drops.rs:13:30: 13:31 + let mut _0: (); // return place in scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 13:36 + let _2: (); // in scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + let mut _3: T; // in scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + scope 1 { + debug _x => _3; // in scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:5: 14:12 + StorageLive(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + _3 = _1; // scope 0 at $DIR/remove_unneeded_drops.rs:14:10: 14:11 + _2 = const (); // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- drop(_3) -> bb1; // scope 1 at $SRC_DIR/core/src/mem/mod.rs:LL:COL +- } +- +- bb1: { + StorageDead(_3); // scope 0 at $DIR/remove_unneeded_drops.rs:14:11: 14:12 + StorageDead(_2); // scope 0 at $DIR/remove_unneeded_drops.rs:14:12: 14:13 + _0 = const (); // scope 0 at $DIR/remove_unneeded_drops.rs:13:36: 15:2 + return; // scope 0 at $DIR/remove_unneeded_drops.rs:15:2: 15:2 + } + } + diff --git a/src/test/mir-opt/remove_unneeded_drops.rs b/src/test/mir-opt/remove_unneeded_drops.rs new file mode 100644 index 0000000000..1052f28867 --- /dev/null +++ b/src/test/mir-opt/remove_unneeded_drops.rs @@ -0,0 +1,29 @@ +// ignore-wasm32-bare compiled with panic=abort by default +// EMIT_MIR remove_unneeded_drops.opt.RemoveUnneededDrops.diff +fn opt(x: bool) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.dont_opt.RemoveUnneededDrops.diff +fn dont_opt(x: Vec) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.opt_generic_copy.RemoveUnneededDrops.diff +fn opt_generic_copy(x: T) { + drop(x); +} + +// EMIT_MIR remove_unneeded_drops.cannot_opt_generic.RemoveUnneededDrops.diff +// since the pass is not running on monomorphisized code, +// we can't (but probably should) optimize this +fn cannot_opt_generic(x: T) { + drop(x); +} + +fn main() { + opt(true); + opt_generic_copy(42); + cannot_opt_generic(42); + dont_opt(vec![true]); +} diff --git a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir index b10ca21831..d0268cf207 100644 --- a/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir +++ b/src/test/mir-opt/retag.core.ptr-drop_in_place.Test.SimplifyCfg-make_shim.after.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` after SimplifyCfg-make_shim +// MIR for `drop_in_place` after SimplifyCfg-make_shim -fn std::intrinsics::drop_in_place(_1: *mut Test) -> () { +fn drop_in_place(_1: *mut Test) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: &mut Test; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -8,7 +8,7 @@ fn std::intrinsics::drop_in_place(_1: *mut Test) -> () { bb0: { Retag([raw] _1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = ::drop(move _2) -> bb1; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut Test) {::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir similarity index 88% rename from src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir index 01f5fbb7d2..0b8c4d25d2 100644 --- a/src/test/mir-opt/retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir @@ -1,6 +1,6 @@ -// MIR for `main::{{closure}}#0` after SimplifyCfg-elaborate-drops +// MIR for `main::{closure#0}` after SimplifyCfg-elaborate-drops -fn main::{{closure}}#0(_1: &[closure@main::{{closure}}#0], _2: &i32) -> &i32 { +fn main::{closure#0}(_1: &[closure@main::{closure#0}], _2: &i32) -> &i32 { debug x => _2; // in scope 0 at $DIR/retag.rs:40:32: 40:33 let mut _0: &i32; // return place in scope 0 at $DIR/retag.rs:40:44: 40:48 let _3: &i32; // in scope 0 at $DIR/retag.rs:41:13: 41:15 diff --git a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir index 5a79466ede..52f422d831 100644 --- a/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir +++ b/src/test/mir-opt/retag.main.SimplifyCfg-elaborate-drops.after.mir @@ -10,7 +10,7 @@ fn main() -> () { let mut _7: &mut i32; // in scope 0 at $DIR/retag.rs:32:29: 32:35 let mut _9: &mut i32; // in scope 0 at $DIR/retag.rs:33:19: 33:20 let mut _12: *mut i32; // in scope 0 at $DIR/retag.rs:36:18: 36:29 - let mut _14: [closure@main::{{closure}}#0]; // in scope 0 at $DIR/retag.rs:40:31: 43:6 + let mut _14: [closure@main::{closure#0}]; // in scope 0 at $DIR/retag.rs:40:31: 43:6 let mut _16: for<'r> fn(&'r i32) -> &'r i32; // in scope 0 at $DIR/retag.rs:44:14: 44:15 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 @@ -118,9 +118,9 @@ fn main() -> () { StorageDead(_2); // scope 1 at $DIR/retag.rs:37:5: 37:6 StorageLive(_13); // scope 1 at $DIR/retag.rs:40:9: 40:10 StorageLive(_14); // scope 1 at $DIR/retag.rs:40:31: 43:6 - _14 = [closure@main::{{closure}}#0]; // scope 1 at $DIR/retag.rs:40:31: 43:6 + _14 = [closure@main::{closure#0}]; // scope 1 at $DIR/retag.rs:40:31: 43:6 // closure - // + def_id: DefId(0:14 ~ retag[317d]::main[0]::{{closure}}[0]) + // + def_id: DefId(0:14 ~ retag[317d]::main::{closure#0}) // + substs: [ // i8, // for<'r> extern "rust-call" fn((&'r i32,)) -> &'r i32, @@ -157,10 +157,10 @@ fn main() -> () { _27 = const main::promoted[0]; // scope 7 at $DIR/retag.rs:47:21: 47:23 // ty::Const // + ty: &i32 - // + val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) + // + val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, [], Some(promoted[0])) // mir::Constant // + span: $DIR/retag.rs:47:21: 47:23 - // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main[0]), const_param_did: None }, [], Some(promoted[0])) } + // + literal: Const { ty: &i32, val: Unevaluated(WithOptConstParam { did: DefId(0:13 ~ retag[317d]::main), const_param_did: None }, [], Some(promoted[0])) } Retag(_27); // scope 7 at $DIR/retag.rs:47:21: 47:23 _23 = &(*_27); // scope 7 at $DIR/retag.rs:47:21: 47:23 Retag(_23); // scope 7 at $DIR/retag.rs:47:21: 47:23 diff --git a/src/test/mir-opt/retag.rs b/src/test/mir-opt/retag.rs index 12d7cb30d9..d0ea2cfb18 100644 --- a/src/test/mir-opt/retag.rs +++ b/src/test/mir-opt/retag.rs @@ -6,8 +6,8 @@ struct Test(i32); -// EMIT_MIR retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir -// EMIT_MIR retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir impl Test { // Make sure we run the pass on a method, not just on bare functions. fn foo<'x>(&self, x: &'x mut i32) -> &'x mut i32 { @@ -25,7 +25,7 @@ impl Drop for Test { } // EMIT_MIR retag.main.SimplifyCfg-elaborate-drops.after.mir -// EMIT_MIR retag.main-{{closure}}.SimplifyCfg-elaborate-drops.after.mir +// EMIT_MIR retag.main-{closure#0}.SimplifyCfg-elaborate-drops.after.mir fn main() { let mut x = 0; { diff --git a/src/test/mir-opt/retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/retag.{{impl}}-foo.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.{impl#0}-foo.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir b/src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir similarity index 100% rename from src/test/mir-opt/retag.{{impl}}-foo_shr.SimplifyCfg-elaborate-drops.after.mir rename to src/test/mir-opt/retag.{impl#0}-foo_shr.SimplifyCfg-elaborate-drops.after.mir diff --git a/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff new file mode 100644 index 0000000000..c3e503bf2c --- /dev/null +++ b/src/test/mir-opt/rustc.try_identity.DestinationPropagation.diff @@ -0,0 +1,72 @@ +- // MIR for `try_identity` before DestinationPropagation ++ // MIR for `try_identity` after DestinationPropagation + + fn try_identity(_1: std::result::Result) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:6:17: 6:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:6:41: 6:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:7:9: 7:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:7:13: 7:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:8:8: 8:9 + scope 1 { + debug y => _2; // in scope 1 at $DIR/simplify_try.rs:7:9: 7:10 + } + scope 2 { + debug err => _6; // in scope 2 at $DIR/simplify_try.rs:7:14: 7:15 + scope 3 { + scope 7 { + debug t => _9; // in scope 7 at $SRC_DIR/libcore/convert/mod.rs:LL:COL + } + scope 8 { + debug v => _8; // in scope 8 at $SRC_DIR/libcore/result.rs:LL:COL + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:7:14: 7:15 + } + } + } + scope 4 { + debug val => _10; // in scope 4 at $DIR/simplify_try.rs:7:13: 7:15 + scope 5 { + } + } + scope 6 { +- debug self => _4; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL ++ debug self => _0; // in scope 6 at $SRC_DIR/libcore/result.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:7:9: 7:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 +- _3 = move _4; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:7:13: 7:14 ++ nop; // scope 6 at $SRC_DIR/libcore/result.rs:LL:COL ++ nop; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:7:14: 7:15 + } + + bb1: { +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:8:5: 8:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:7:15: 7:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:9:1: 9:2 + goto -> bb2; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + } + + bb2: { + return; // scope 0 at $DIR/simplify_try.rs:9:2: 9:2 + } + } + diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.32bit b/src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.32bit rename to src/test/mir-opt/simple_match.match_bool.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.64bit b/src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/simple_match.match_bool.mir_map.0.mir.64bit rename to src/test/mir-opt/simple_match.match_bool.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/simplify-arm.rs b/src/test/mir-opt/simplify-arm.rs index 9d81b7f01c..a7df786357 100644 --- a/src/test/mir-opt/simplify-arm.rs +++ b/src/test/mir-opt/simplify-arm.rs @@ -1,4 +1,4 @@ -// compile-flags: -Z mir-opt-level=2 +// compile-flags: -Z mir-opt-level=2 -Zunsound-mir-opts // EMIT_MIR simplify_arm.id.SimplifyArmIdentity.diff // EMIT_MIR simplify_arm.id.SimplifyBranchSame.diff // EMIT_MIR simplify_arm.id_result.SimplifyArmIdentity.diff diff --git a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs index cf8940ec33..84f57deccf 100644 --- a/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs +++ b/src/test/mir-opt/simplify-locals-removes-unused-discriminant-reads.rs @@ -1,3 +1,5 @@ +// compile-flags: -Zunsound-mir-opts + fn map(x: Option>) -> Option> { match x { None => None, diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff index ecb4384fc6..e390662307 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyArmIdentity.diff @@ -1,7 +1,7 @@ - // MIR for `id` before SimplifyArmIdentity + // MIR for `id` after SimplifyArmIdentity - fn id(_1: std::option::Option) -> std::option::Option { + fn id(_1: Option) -> Option { debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8 let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35 let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 diff --git a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff index fb75eb5603..81a0e6ba0b 100644 --- a/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff +++ b/src/test/mir-opt/simplify_arm.id.SimplifyBranchSame.diff @@ -1,7 +1,7 @@ - // MIR for `id` before SimplifyBranchSame + // MIR for `id` after SimplifyBranchSame - fn id(_1: std::option::Option) -> std::option::Option { + fn id(_1: Option) -> Option { debug o => _1; // in scope 0 at $DIR/simplify-arm.rs:9:7: 9:8 let mut _0: std::option::Option; // return place in scope 0 at $DIR/simplify-arm.rs:9:25: 9:35 let mut _2: isize; // in scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 @@ -13,24 +13,27 @@ bb0: { _2 = discriminant(_1); // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 - switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 +- switchInt(move _2) -> [0_isize: bb1, 1_isize: bb3, otherwise: bb2]; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 ++ goto -> bb1; // scope 0 at $DIR/simplify-arm.rs:11:9: 11:16 } bb1: { - discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 - } - - bb2: { - unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 - } - - bb3: { +- discriminant(_0) = 0; // scope 0 at $DIR/simplify-arm.rs:12:17: 12:21 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 +- } +- +- bb2: { +- unreachable; // scope 0 at $DIR/simplify-arm.rs:10:11: 10:12 +- } +- +- bb3: { _0 = move _1; // scope 1 at $DIR/simplify-arm.rs:11:20: 11:27 - goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 +- goto -> bb4; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 ++ goto -> bb2; // scope 0 at $DIR/simplify-arm.rs:10:5: 13:6 } - bb4: { +- bb4: { ++ bb2: { return; // scope 0 at $DIR/simplify-arm.rs:14:2: 14:2 } } diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff similarity index 100% rename from src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.32bit rename to src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.32bit.diff diff --git a/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit b/src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff similarity index 100% rename from src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.diff.64bit rename to src/test/mir-opt/simplify_arm_identity.main.SimplifyArmIdentity.64bit.diff diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff similarity index 56% rename from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit rename to src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff index 4418c9f12b..760fb747f7 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.32bit +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.32bit.diff @@ -1,26 +1,26 @@ - // MIR for `map` before SimplifyLocals + // MIR for `map` after SimplifyLocals - fn map(_1: std::option::Option>) -> std::option::Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + fn map(_1: Option>) -> Option> { + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff similarity index 56% rename from src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit rename to src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff index 4418c9f12b..760fb747f7 100644 --- a/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.diff.64bit +++ b/src/test/mir-opt/simplify_locals_removes_unused_discriminant_reads.map.SimplifyLocals.64bit.diff @@ -1,26 +1,26 @@ - // MIR for `map` before SimplifyLocals + // MIR for `map` after SimplifyLocals - fn map(_1: std::option::Option>) -> std::option::Option> { - debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:8: 1:9 - let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:1:31: 1:46 -- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 -- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:25: 4:26 -- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 -- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 + fn map(_1: Option>) -> Option> { + debug x => _1; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:8: 3:9 + let mut _0: std::option::Option>; // return place in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:31: 3:46 +- let mut _2: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- let _3: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 +- let mut _4: std::boxed::Box<()>; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:25: 6:26 +- let mut _5: bool; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _6: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 +- let mut _7: isize; // in scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 scope 1 { - debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:14: 4:15 + debug x => ((_0 as Some).0: std::boxed::Box<()>); // in scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:14: 6:15 } bb0: { -- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 -- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:3:9: 3:13 - _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:4:20: 4:27 -- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:1: 6:2 - return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:2: 6:2 +- _5 = const false; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _5 = const true; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 +- _2 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:5:9: 5:13 + _0 = move _1; // scope 1 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:6:20: 6:27 +- _6 = discriminant(_1); // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:1: 8:2 + return; // scope 0 at $DIR/simplify-locals-removes-unused-discriminant-reads.rs:8:2: 8:2 } } diff --git a/src/test/mir-opt/simplify_try.rs b/src/test/mir-opt/simplify_try.rs index fa127de13d..eb307de207 100644 --- a/src/test/mir-opt/simplify_try.rs +++ b/src/test/mir-opt/simplify_try.rs @@ -1,6 +1,8 @@ +// compile-flags: -Zunsound-mir-opts // EMIT_MIR simplify_try.try_identity.SimplifyArmIdentity.diff // EMIT_MIR simplify_try.try_identity.SimplifyBranchSame.after.mir // EMIT_MIR simplify_try.try_identity.SimplifyLocals.after.mir +// EMIT_MIR simplify_try.try_identity.DestinationPropagation.diff fn try_identity(x: Result) -> Result { let y = x?; diff --git a/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff new file mode 100644 index 0000000000..2af387a73b --- /dev/null +++ b/src/test/mir-opt/simplify_try.try_identity.DestinationPropagation.diff @@ -0,0 +1,68 @@ +- // MIR for `try_identity` before DestinationPropagation ++ // MIR for `try_identity` after DestinationPropagation + + fn try_identity(_1: std::result::Result) -> std::result::Result { + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 + scope 1 { + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 + } + scope 2 { + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 + scope 3 { + scope 7 { + debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL + } + scope 8 { + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 + } + } + } + scope 4 { + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 + scope 5 { + } + } + scope 6 { +- debug self => _4; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL ++ debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL + } + + bb0: { + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 +- StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 +- _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 +- _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL +- StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 ++ _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 ++ nop; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL ++ nop; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ _5 = discriminant(_0); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + } + + bb1: { +- _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 ++ nop; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 ++ nop; // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 + } + } + diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff index 26ce290b54..284ebfab9a 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyArmIdentity.diff @@ -2,25 +2,25 @@ + // MIR for `try_identity` after SimplifyArmIdentity fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { -- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 -+ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 +- debug y => _2; // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 ++ debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { -- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 -+ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 +- debug err => _6; // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 ++ debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { - debug t => _9; // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -29,13 +29,13 @@ scope 8 { - debug v => _8; // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL + debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 } } } scope 4 { -- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 -+ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 +- debug val => _10; // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 ++ debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -44,55 +44,51 @@ } bb0: { - StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - _4 = _1; // scope 0 at $DIR/simplify_try.rs:6:13: 6:14 + StorageLive(_2); // scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + StorageLive(_3); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + StorageLive(_4); // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + _4 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 _3 = move _4; // scope 6 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + switchInt(move _5) -> [0_isize: bb1, otherwise: bb2]; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb1: { -- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:6:13: 6:15 -- _2 = _10; // scope 5 at $DIR/simplify_try.rs:6:13: 6:15 -- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -+ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 -- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:7:8: 7:9 -- _11 = _2; // scope 1 at $DIR/simplify_try.rs:7:8: 7:9 -- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 -- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:7:9: 7:10 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 +- StorageLive(_10); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _10 = ((_3 as Ok).0: u32); // scope 0 at $DIR/simplify_try.rs:8:13: 8:15 +- _2 = _10; // scope 5 at $DIR/simplify_try.rs:8:13: 8:15 +- StorageDead(_10); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 ++ _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 +- StorageLive(_11); // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- _11 = _2; // scope 1 at $DIR/simplify_try.rs:9:8: 9:9 +- ((_0 as Ok).0: u32) = move _11; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- discriminant(_0) = 0; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 +- StorageDead(_11); // scope 1 at $DIR/simplify_try.rs:9:9: 9:10 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } bb2: { -- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- _9 = _6; // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageLive(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- _6 = ((_3 as Err).0: i32); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageLive(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- _9 = _6; // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - _8 = move _9; // scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL -- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageDead(_9); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 - StorageLive(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - _12 = move _8; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - ((_0 as Err).0: i32) = move _12; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - discriminant(_0) = 1; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_12); // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL -- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:6:14: 6:15 -- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 +- StorageDead(_8); // scope 3 at $DIR/simplify_try.rs:8:14: 8:15 +- StorageDead(_6); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _0 = move _3; // scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb3; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - } - - bb3: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir index dc4aae176f..ceb5bfb19a 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyBranchSame.after.mir @@ -1,35 +1,35 @@ // MIR for `try_identity` after SimplifyBranchSame fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 - let _2: u32; // in scope 0 at $DIR/simplify_try.rs:6:9: 6:10 - let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:14 - let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _6: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:6:14: 6:15 - let _10: u32; // in scope 0 at $DIR/simplify_try.rs:6:13: 6:15 - let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:7:8: 7:9 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 + let _2: u32; // in scope 0 at $DIR/simplify_try.rs:8:9: 8:10 + let mut _3: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _4: std::result::Result; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + let mut _5: isize; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _6: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _7: !; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _8: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let mut _9: i32; // in scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + let _10: u32; // in scope 0 at $DIR/simplify_try.rs:8:13: 8:15 + let mut _11: u32; // in scope 0 at $DIR/simplify_try.rs:9:8: 9:9 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL } scope 8 { debug v => ((_0 as Err).0: i32); // in scope 8 at $SRC_DIR/core/src/result.rs:LL:COL - let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:6:14: 6:15 + let mut _12: i32; // in scope 8 at $DIR/simplify_try.rs:8:14: 8:15 } } } scope 4 { - debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } @@ -38,24 +38,20 @@ fn try_identity(_1: std::result::Result) -> std::result::Result bb1; // scope 0 at $DIR/simplify_try.rs:6:14: 6:15 + StorageDead(_4); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + _5 = discriminant(_3); // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 + goto -> bb1; // scope 0 at $DIR/simplify_try.rs:8:14: 8:15 } bb1: { - _0 = move _3; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:6:15: 6:16 - StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:8:1: 8:2 - goto -> bb2; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 - } - - bb2: { - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + _0 = move _3; // scope 1 at $DIR/simplify_try.rs:9:5: 9:10 + StorageDead(_3); // scope 0 at $DIR/simplify_try.rs:8:15: 8:16 + StorageDead(_2); // scope 0 at $DIR/simplify_try.rs:10:1: 10:2 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir index d65a2b12c0..508f2705d0 100644 --- a/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir +++ b/src/test/mir-opt/simplify_try.try_identity.SimplifyLocals.after.mir @@ -1,13 +1,13 @@ // MIR for `try_identity` after SimplifyLocals fn try_identity(_1: std::result::Result) -> std::result::Result { - debug x => _1; // in scope 0 at $DIR/simplify_try.rs:5:17: 5:18 - let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:5:41: 5:57 + debug x => _1; // in scope 0 at $DIR/simplify_try.rs:7:17: 7:18 + let mut _0: std::result::Result; // return place in scope 0 at $DIR/simplify_try.rs:7:41: 7:57 scope 1 { - debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:6:9: 6:10 + debug y => ((_0 as Ok).0: u32); // in scope 1 at $DIR/simplify_try.rs:8:9: 8:10 } scope 2 { - debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:6:14: 6:15 + debug err => ((_0 as Err).0: i32); // in scope 2 at $DIR/simplify_try.rs:8:14: 8:15 scope 3 { scope 7 { debug t => ((_0 as Err).0: i32); // in scope 7 at $SRC_DIR/core/src/convert/mod.rs:LL:COL @@ -18,16 +18,16 @@ fn try_identity(_1: std::result::Result) -> std::result::Result ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:6:13: 6:15 + debug val => ((_0 as Ok).0: u32); // in scope 4 at $DIR/simplify_try.rs:8:13: 8:15 scope 5 { } } scope 6 { - debug self => _1; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL + debug self => _0; // in scope 6 at $SRC_DIR/core/src/result.rs:LL:COL } bb0: { - _0 = move _1; // scope 1 at $DIR/simplify_try.rs:7:5: 7:10 - return; // scope 0 at $DIR/simplify_try.rs:8:2: 8:2 + _0 = _1; // scope 0 at $DIR/simplify_try.rs:8:13: 8:14 + return; // scope 0 at $DIR/simplify_try.rs:10:2: 10:2 } } diff --git a/src/test/mir-opt/simplify_try_if_let.rs b/src/test/mir-opt/simplify_try_if_let.rs index b37db73842..fba67de403 100644 --- a/src/test/mir-opt/simplify_try_if_let.rs +++ b/src/test/mir-opt/simplify_try_if_let.rs @@ -1,5 +1,8 @@ -// compile-flags: -Zmir-opt-level=1 -// EMIT_MIR simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff +// compile-flags: -Zmir-opt-level=1 -Zunsound-mir-opts +// ignore-test +// FIXME: the pass is unsound and causes ICEs in the MIR validator + +// EMIT_MIR simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff use std::ptr::NonNull; @@ -19,7 +22,7 @@ impl LinkedList { pub fn append(&mut self, other: &mut Self) { match self.tail { - None => { }, + None => {} Some(mut tail) => { // `as_mut` is okay here because we have exclusive access to the entirety // of both lists. diff --git a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff b/src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff similarity index 88% rename from src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff rename to src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff index 51a1e6ba4c..11f6b53374 100644 --- a/src/test/mir-opt/simplify_try_if_let.{{impl}}-append.SimplifyArmIdentity.diff +++ b/src/test/mir-opt/simplify_try_if_let.{impl#0}-append.SimplifyArmIdentity.diff @@ -18,7 +18,8 @@ debug tail => _4; // in scope 1 at $DIR/simplify_try_if_let.rs:23:18: 23:26 let _8: std::ptr::NonNull; // in scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 scope 2 { - debug other_head => _8; // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 +- debug other_head => _8; // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 ++ debug other_head => ((_9 as Some).0: std::ptr::NonNull); // in scope 2 at $DIR/simplify_try_if_let.rs:26:29: 26:39 scope 3 { } } @@ -35,7 +36,7 @@ StorageLive(_5); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 StorageLive(_6); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53 _6 = &mut ((*_2).0: std::option::Option>); // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:53 - _5 = std::option::Option::>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 + _5 = Option::>::take(move _6) -> bb4; // scope 1 at $DIR/simplify_try_if_let.rs:26:43: 26:60 // mir::Constant // + span: $DIR/simplify_try_if_let.rs:26:54: 26:58 // + literal: Const { ty: for<'r> fn(&'r mut std::option::Option>) -> std::option::Option> {std::option::Option::>::take}, val: Value(Scalar()) } @@ -65,15 +66,16 @@ StorageLive(_8); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 _8 = ((_5 as Some).0: std::ptr::NonNull); // scope 1 at $DIR/simplify_try_if_let.rs:26:29: 26:39 StorageLive(_9); // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 - _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 - ((_9 as Some).0: std::ptr::NonNull) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 - StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 +- StorageLive(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 +- _10 = _8; // scope 3 at $DIR/simplify_try_if_let.rs:28:51: 28:61 +- ((_9 as Some).0: std::ptr::NonNull) = move _10; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 +- discriminant(_9) = 1; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 +- StorageDead(_10); // scope 3 at $DIR/simplify_try_if_let.rs:28:61: 28:62 ++ _9 = move _5; // scope 3 at $DIR/simplify_try_if_let.rs:28:46: 28:62 StorageLive(_11); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 StorageLive(_12); // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 _12 = &mut _4; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:29 - _11 = std::ptr::NonNull::::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 + _11 = NonNull::::as_mut(move _12) -> bb7; // scope 3 at $DIR/simplify_try_if_let.rs:28:25: 28:38 // mir::Constant // + span: $DIR/simplify_try_if_let.rs:28:30: 28:36 // + literal: Const { ty: for<'r> unsafe fn(&'r mut std::ptr::NonNull) -> &'r mut Node {std::ptr::NonNull::::as_mut}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/slice-drop-shim.rs b/src/test/mir-opt/slice-drop-shim.rs index 3b98b8474e..0fd32906db 100644 --- a/src/test/mir-opt/slice-drop-shim.rs +++ b/src/test/mir-opt/slice-drop-shim.rs @@ -1,7 +1,7 @@ // compile-flags: -Zmir-opt-level=0 // EMIT_MIR_FOR_EACH_BIT_WIDTH -// EMIT_MIR core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir +// EMIT_MIR core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.mir fn main() { let _fn = std::ptr::drop_in_place::<[String]> as unsafe fn(_); } diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.64bit b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir similarity index 97% rename from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.64bit rename to src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir index 50cfe19974..8051c61bce 100644 --- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.64bit +++ b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () { +fn drop_in_place(_1: *mut [String]) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.32bit b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir similarity index 97% rename from src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.32bit rename to src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir index 50cfe19974..8051c61bce 100644 --- a/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[std__string__String].AddMovesForPackedDrops.before.mir.32bit +++ b/src/test/mir-opt/slice_drop_shim.core.ptr-drop_in_place.[String].AddMovesForPackedDrops.before.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut [std::string::String]) -> () { +fn drop_in_place(_1: *mut [String]) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: usize; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL diff --git a/src/test/mir-opt/spanview-block.rs b/src/test/mir-opt/spanview-block.rs new file mode 100644 index 0000000000..fc1d6e0ede --- /dev/null +++ b/src/test/mir-opt/spanview-block.rs @@ -0,0 +1,5 @@ +// Test spanview block output +// compile-flags: -Z dump-mir-spanview=block + +// EMIT_MIR spanview_block.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-statement.rs b/src/test/mir-opt/spanview-statement.rs new file mode 100644 index 0000000000..a43ad5e71a --- /dev/null +++ b/src/test/mir-opt/spanview-statement.rs @@ -0,0 +1,5 @@ +// Test spanview output (the default value for `-Z dump-mir-spanview` is "statement") +// compile-flags: -Z dump-mir-spanview + +// EMIT_MIR spanview_statement.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview-terminator.rs b/src/test/mir-opt/spanview-terminator.rs new file mode 100644 index 0000000000..92e1411ead --- /dev/null +++ b/src/test/mir-opt/spanview-terminator.rs @@ -0,0 +1,5 @@ +// Test spanview terminator output +// compile-flags: -Z dump-mir-spanview=terminator + +// EMIT_MIR spanview_terminator.main.mir_map.0.html +fn main() {} diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html b/src/test/mir-opt/spanview_block.main.mir_map.0.html new file mode 100644 index 0000000000..8f6b130797 --- /dev/null +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0⦊{}⦉02⦊⦉2
    + + diff --git a/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir new file mode 100644 index 0000000000..8f6b130797 --- /dev/null +++ b/src/test/mir-opt/spanview_block.main.mir_map.0.html.mir @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0⦊{}⦉02⦊⦉2
    + + diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html b/src/test/mir-opt/spanview_statement.main.mir_map.0.html new file mode 100644 index 0000000000..072d22473a --- /dev/null +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0[0]⦊{}⦉0[0]0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
    + + diff --git a/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir new file mode 100644 index 0000000000..072d22473a --- /dev/null +++ b/src/test/mir-opt/spanview_statement.main.mir_map.0.html.mir @@ -0,0 +1,67 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() 0[0]⦊{}⦉0[0]0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
    + + diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html new file mode 100644 index 0000000000..e023f0f8ae --- /dev/null +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html @@ -0,0 +1,66 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() {}0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
    + + diff --git a/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir new file mode 100644 index 0000000000..e023f0f8ae --- /dev/null +++ b/src/test/mir-opt/spanview_terminator.main.mir_map.0.html.mir @@ -0,0 +1,66 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() {}0:Goto⦊⦉0:Goto2:Return⦊⦉2:Return
    + + diff --git a/src/test/mir-opt/storage_ranges.main.nll.0.mir b/src/test/mir-opt/storage_ranges.main.nll.0.mir index 707caf57c6..6fa83d3de6 100644 --- a/src/test/mir-opt/storage_ranges.main.nll.0.mir +++ b/src/test/mir-opt/storage_ranges.main.nll.0.mir @@ -45,7 +45,7 @@ fn main() -> () { StorageLive(_4); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 StorageLive(_5); // scope 1 at $DIR/storage_ranges.rs:6:23: 6:24 _5 = _1; // scope 1 at $DIR/storage_ranges.rs:6:23: 6:24 - _4 = std::option::Option::::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 + _4 = Option::::Some(move _5); // scope 1 at $DIR/storage_ranges.rs:6:18: 6:25 StorageDead(_5); // scope 1 at $DIR/storage_ranges.rs:6:24: 6:25 _3 = &_4; // scope 1 at $DIR/storage_ranges.rs:6:17: 6:25 FakeRead(ForLet, _3); // scope 1 at $DIR/storage_ranges.rs:6:13: 6:14 diff --git a/src/test/mir-opt/unusual-item-types.rs b/src/test/mir-opt/unusual-item-types.rs index 249a851af2..c68ec21a03 100644 --- a/src/test/mir-opt/unusual-item-types.rs +++ b/src/test/mir-opt/unusual-item-types.rs @@ -5,25 +5,25 @@ struct A; -// EMIT_MIR unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir +// EMIT_MIR unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.mir impl A { const ASSOCIATED_CONSTANT: i32 = 2; } // See #59021 -// EMIT_MIR unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir +// EMIT_MIR unusual_item_types.Test-X-{constructor#0}.mir_map.0.mir enum Test { X(usize), Y { a: usize }, } -// EMIT_MIR unusual_item_types.E-V-{{constant}}.mir_map.0.mir +// EMIT_MIR unusual_item_types.E-V-{constant#0}.mir_map.0.mir enum E { V = 5, } fn main() { let f = Test::X as fn(usize) -> Test; -// EMIT_MIR core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir +// EMIT_MIR core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.mir let v = Vec::::new(); } diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir similarity index 85% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir index 315525e08c..f11fce891f 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.32bit +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `E::V::{{constant}}#0` 0 mir_map +// MIR for `E::V::{constant#0}` 0 mir_map -E::V::{{constant}}#0: isize = { +E::V::{constant#0}: isize = { let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { diff --git a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir similarity index 85% rename from src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir index 315525e08c..f11fce891f 100644 --- a/src/test/mir-opt/unusual_item_types.E-V-{{constant}}.mir_map.0.mir.64bit +++ b/src/test/mir-opt/unusual_item_types.E-V-{constant#0}.mir_map.0.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `E::V::{{constant}}#0` 0 mir_map +// MIR for `E::V::{constant#0}` 0 mir_map -E::V::{{constant}}#0: isize = { +E::V::{constant#0}: isize = { let mut _0: isize; // return place in scope 0 at $DIR/unusual-item-types.rs:22:9: 22:10 bb0: { diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.Test-X-{{constructor}}.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.Test-X-{constructor#0}.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir similarity index 84% rename from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit rename to src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir index 1f5804e0b2..2d96f64aeb 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.32bit +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.32bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { +fn drop_in_place(_1: *mut Vec) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -35,7 +35,7 @@ fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { bb7: { _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = as Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir similarity index 84% rename from src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit rename to src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir index 1f5804e0b2..2d96f64aeb 100644 --- a/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.std__vec__Vec_i32_.AddMovesForPackedDrops.before.mir.64bit +++ b/src/test/mir-opt/unusual_item_types.core.ptr-drop_in_place.Vec_i32_.AddMovesForPackedDrops.before.64bit.mir @@ -1,6 +1,6 @@ -// MIR for `std::intrinsics::drop_in_place` before AddMovesForPackedDrops +// MIR for `drop_in_place` before AddMovesForPackedDrops -fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { +fn drop_in_place(_1: *mut Vec) -> () { let mut _0: (); // return place in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _2: &mut std::vec::Vec; // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL let mut _3: (); // in scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL @@ -35,7 +35,7 @@ fn std::intrinsics::drop_in_place(_1: *mut std::vec::Vec) -> () { bb7: { _2 = &mut (*_1); // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL - _3 = as std::ops::Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL + _3 = as Drop>::drop(move _2) -> [return: bb6, unwind: bb5]; // scope 0 at $SRC_DIR/core/src/ptr/mod.rs:LL:COL // mir::Constant // + span: $SRC_DIR/core/src/ptr/mod.rs:LL:COL // + literal: Const { ty: for<'r> fn(&'r mut std::vec::Vec) { as std::ops::Drop>::drop}, val: Value(Scalar()) } diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.32bit rename to src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.32bit.mir diff --git a/src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit b/src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir similarity index 100% rename from src/test/mir-opt/unusual_item_types.{{impl}}-ASSOCIATED_CONSTANT.mir_map.0.mir.64bit rename to src/test/mir-opt/unusual_item_types.{impl#0}-ASSOCIATED_CONSTANT.mir_map.0.64bit.mir diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.32bit rename to src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.32bit.diff diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.diff.64bit rename to src/test/mir-opt/while_let_loops.change_loop_body.ConstProp.64bit.diff diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.32bit rename to src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.32bit.mir diff --git a/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit b/src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir similarity index 100% rename from src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.mir.64bit rename to src/test/mir-opt/while_let_loops.change_loop_body.PreCodegen.after.64bit.mir diff --git a/src/test/pretty/issue-4264.pp b/src/test/pretty/issue-4264.pp index 0e45b6f04a..7b0a00282f 100644 --- a/src/test/pretty/issue-4264.pp +++ b/src/test/pretty/issue-4264.pp @@ -32,34 +32,34 @@ pub fn bar() ({ ({ let res = ((::alloc::fmt::format as - for<'r> fn(std::fmt::Arguments<'r>) -> std::string::String {std::fmt::format})(((::core::fmt::Arguments::new_v1 - as - fn(&[&'static str], &[std::fmt::ArgumentV1]) -> std::fmt::Arguments {std::fmt::Arguments::new_v1})((&([("test" - as - &str)] - as - [&str; 1]) - as - &[&str; 1]), - (&(match (() - as - ()) - { - () - => - ([] - as - [std::fmt::ArgumentV1; 0]), - } - as - [std::fmt::ArgumentV1; 0]) - as - &[std::fmt::ArgumentV1; 0])) - as - std::fmt::Arguments)) - as std::string::String); - (res as std::string::String) - } as std::string::String); + 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); + (res as String) + } as String); } as ()) pub type Foo = [i32; (3 as usize)]; pub struct Bar { diff --git a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp index b0fd65f88e..8182021a2c 100644 --- a/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp +++ b/src/test/run-make-fulldeps/foreign-exceptions/foo.cpp @@ -23,15 +23,15 @@ struct drop_check { extern "C" { void rust_catch_callback(void (*cb)(), bool* rust_ok); - static void callback() { + void throw_cxx_exception() { println("throwing C++ exception"); throw exception(); } - void throw_cxx_exception() { + void test_cxx_exception() { bool rust_ok = false; try { - rust_catch_callback(callback, &rust_ok); + rust_catch_callback(throw_cxx_exception, &rust_ok); assert(false && "unreachable"); } catch (exception e) { println("caught C++ exception"); diff --git a/src/test/run-make-fulldeps/foreign-exceptions/foo.rs b/src/test/run-make-fulldeps/foreign-exceptions/foo.rs index 9c2045c8c8..b5c8c1962a 100644 --- a/src/test/run-make-fulldeps/foreign-exceptions/foo.rs +++ b/src/test/run-make-fulldeps/foreign-exceptions/foo.rs @@ -1,5 +1,5 @@ -// Tests that C++ exceptions can unwind through Rust code, run destructors and -// are ignored by catch_unwind. Also tests that Rust panics can unwind through +// Tests that C++ exceptions can unwind through Rust code run destructors and +// are caught by catch_unwind. Also tests that Rust panics can unwind through // C++ code. // For linking libstdc++ on MinGW @@ -17,7 +17,7 @@ impl<'a> Drop for DropCheck<'a> { } extern "C" { - fn throw_cxx_exception(); + fn test_cxx_exception(); #[unwind(allowed)] fn cxx_catch_callback(cb: extern "C" fn(), ok: *mut bool); @@ -26,15 +26,12 @@ extern "C" { #[no_mangle] #[unwind(allowed)] extern "C" fn rust_catch_callback(cb: extern "C" fn(), rust_ok: &mut bool) { - let _caught_unwind = catch_unwind(AssertUnwindSafe(|| { - let _drop = DropCheck(rust_ok); - cb(); - unreachable!("should have unwound instead of returned"); - })); - unreachable!("catch_unwind should not have caught foreign exception"); + let _drop = DropCheck(rust_ok); + cb(); + unreachable!("should have unwound instead of returned"); } -fn throw_rust_panic() { +fn test_rust_panic() { #[unwind(allowed)] extern "C" fn callback() { println!("throwing rust panic"); @@ -60,6 +57,6 @@ fn throw_rust_panic() { } fn main() { - unsafe { throw_cxx_exception() }; - throw_rust_panic(); + unsafe { test_cxx_exception() }; + test_rust_panic(); } diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile new file mode 100644 index 0000000000..cb081fb641 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/Makefile @@ -0,0 +1,81 @@ +# needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. + +-include ../instrument-coverage/coverage_tools.mk + +BASEDIR=../instrument-coverage-cov-reports-base +SOURCEDIR=../instrument-coverage + +all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) + +# Ensure there are no `expected` results for tests that may have been removed or renamed +.PHONY: clear_expected_if_blessed +clear_expected_if_blessed: +ifdef RUSTC_BLESS_TEST + rm -f expected_export_coverage.*.json + rm -f typical_show_coverage.*.txt +endif + +-include clear_expected_if_blessed + +%: $(SOURCEDIR)/%.rs + # Compile the test program with "experimental" coverage instrumentation and generate relevant MIR. + # + # FIXME(richkadel): `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are + # satisfied with the branch-level instrumentation. + $(RUSTC) $(SOURCEDIR)/$@.rs \ + -Zexperimental-coverage \ + -Clink-dead-code=$(LINK_DEAD_CODE) + + # Run it in order to generate some profiling data, + # with `LLVM_PROFILE_FILE=` environment variable set to + # output the coverage stats for this run. + LLVM_PROFILE_FILE="$(TMPDIR)"/$@.profraw \ + $(call RUN,$@) + + # Postprocess the profiling data so it can be used by the llvm-cov tool + "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ + "$(TMPDIR)"/$@.profraw \ + -o "$(TMPDIR)"/$@.profdata + + # Generate a coverage report using `llvm-cov show`. The output ordering + # can be non-deterministic, so ignore the return status. If the test fails + # when comparing the JSON `export`, the `show` output may be useful when + # debugging. + "$(LLVM_BIN_DIR)"/llvm-cov show \ + --Xdemangler="$(RUST_DEMANGLER)" \ + --show-line-counts-or-regions \ + --instr-profile="$(TMPDIR)"/$@.profdata \ + $(call BIN,"$(TMPDIR)"/$@) \ + > "$(TMPDIR)"/actual_show_coverage.$@.txt + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/actual_show_coverage.$@.txt typical_show_coverage.$@.txt +else + # Compare the show coverage output (`--bless` refreshes `typical` files) + $(DIFF) typical_show_coverage.$@.txt "$(TMPDIR)"/actual_show_coverage.$@.txt || \ + >&2 echo 'diff failed for `llvm-cov show` on $@ (might not be an error)' +endif + + # Generate a coverage report in JSON, using `llvm-cov export`, and fail if + # there are differences from the expected output. + "$(LLVM_BIN_DIR)"/llvm-cov export \ + --summary-only \ + --instr-profile="$(TMPDIR)"/$@.profdata \ + $(call BIN,"$(TMPDIR)"/$@) \ + | "$(PYTHON)" $(BASEDIR)/prettify_json.py \ + > "$(TMPDIR)"/actual_export_coverage.$@.json + +ifdef RUSTC_BLESS_TEST + cp "$(TMPDIR)"/actual_export_coverage.$@.json expected_export_coverage.$@.json +else + # Check that exported JSON coverage data matches what we expect (`--bless` refreshes `expected`) + $(DIFF) expected_export_coverage.$@.json "$(TMPDIR)"/actual_export_coverage.$@.json +endif diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json new file mode 100644 index 0000000000..b9041ebebe --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/expected_export_coverage.coverage_of_if_else.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/coverage_of_if_else.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/prettify_json.py b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/prettify_json.py similarity index 100% rename from src/test/run-make-fulldeps/instrument-coverage/prettify_json.py rename to src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/prettify_json.py diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt new file mode 100644 index 0000000000..0c71155960 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-base/typical_show_coverage.coverage_of_if_else.txt @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | let mut countdown = 0; + 5| 2| if true { + ^1 + 6| 2| countdown = 10; + 7| 2| } + 8| | + 9| 2| if countdown > 7 { + ^1 + 10| 2| countdown -= 4; + ^1 + 11| 2| } else if countdown > 2 { + ^0 ^0 + 12| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 13| 0| countdown = 0; + 14| 0| } + 15| 0| countdown -= 5; + 16| 0| } else { + 17| 0| return; + 18| 0| } + 19| 0| + 20| 0| let mut countdown = 0; + 21| 2| if true { + ^1 + 22| 2| countdown = 10; + 23| 2| } + 24| 0| + 25| 2| if countdown > 7 { + ^1 + 26| 2| countdown -= 4; + ^1 + 27| 2| } else if countdown > 2 { + ^0 ^0 + 28| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 29| 0| countdown = 0; + 30| 0| } + 31| 0| countdown -= 5; + 32| 0| } else { + 33| 0| return; + 34| 0| } + 35| 0| + 36| 0| let mut countdown = 0; + 37| 2| if true { + ^1 + 38| 2| countdown = 10; + 39| 2| } + 40| 0| + 41| 2| if countdown > 7 { + ^1 + 42| 2| countdown -= 4; + ^1 + 43| 2| } else if countdown > 2 { + ^0 ^0 + 44| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 45| 0| countdown = 0; + 46| 0| } + 47| 0| countdown -= 5; + 48| 0| } else { + 49| 0| return; + 50| 0| } + 51| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile new file mode 100644 index 0000000000..ab826d07e0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/Makefile @@ -0,0 +1,15 @@ +# needs-profiler-support +# ignore-msvc +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. + +# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 +LINK_DEAD_CODE=yes + +-include ../instrument-coverage-cov-reports-base/Makefile + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json new file mode 100644 index 0000000000..b9041ebebe --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/expected_export_coverage.coverage_of_if_else.json @@ -0,0 +1,59 @@ +{ + "data": [ + { + "files": [ + { + "filename": "../instrument-coverage/coverage_of_if_else.rs", + "summary": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "totals": { + "functions": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "instantiations": { + "count": 1, + "covered": 1, + "percent": 100 + }, + "lines": { + "count": 46, + "covered": 19, + "percent": 41.30434782608695 + }, + "regions": { + "count": 75, + "covered": 23, + "notcovered": 52, + "percent": 30.666666666666664 + } + } + } + ], + "type": "llvm.coverage.json.export", + "version": "2.0.1" +} diff --git a/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt new file mode 100644 index 0000000000..0c71155960 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-cov-reports-link-dead-code/typical_show_coverage.coverage_of_if_else.txt @@ -0,0 +1,64 @@ + 1| |#![allow(unused_assignments)] + 2| | + 3| |fn main() { + 4| | let mut countdown = 0; + 5| 2| if true { + ^1 + 6| 2| countdown = 10; + 7| 2| } + 8| | + 9| 2| if countdown > 7 { + ^1 + 10| 2| countdown -= 4; + ^1 + 11| 2| } else if countdown > 2 { + ^0 ^0 + 12| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 13| 0| countdown = 0; + 14| 0| } + 15| 0| countdown -= 5; + 16| 0| } else { + 17| 0| return; + 18| 0| } + 19| 0| + 20| 0| let mut countdown = 0; + 21| 2| if true { + ^1 + 22| 2| countdown = 10; + 23| 2| } + 24| 0| + 25| 2| if countdown > 7 { + ^1 + 26| 2| countdown -= 4; + ^1 + 27| 2| } else if countdown > 2 { + ^0 ^0 + 28| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 29| 0| countdown = 0; + 30| 0| } + 31| 0| countdown -= 5; + 32| 0| } else { + 33| 0| return; + 34| 0| } + 35| 0| + 36| 0| let mut countdown = 0; + 37| 2| if true { + ^1 + 38| 2| countdown = 10; + 39| 2| } + 40| 0| + 41| 2| if countdown > 7 { + ^1 + 42| 2| countdown -= 4; + ^1 + 43| 2| } else if countdown > 2 { + ^0 ^0 + 44| 0| if countdown < 1 || countdown > 5 || countdown != 9 { + 45| 0| countdown = 0; + 46| 0| } + 47| 0| countdown -= 5; + 48| 0| } else { + 49| 0| return; + 50| 0| } + 51| 1|} + diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile new file mode 100644 index 0000000000..f623248ab5 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/Makefile @@ -0,0 +1,65 @@ +# needs-profiler-support + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. + +-include ../instrument-coverage/coverage_tools.mk + +BASEDIR=../instrument-coverage-llvm-ir-base + +ifeq ($(UNAME),Darwin) + INSTR_PROF_DATA_SUFFIX=,regular,live_support + DATA_SECTION_PREFIX=__DATA, + LLVM_COV_SECTION_PREFIX=__LLVM_COV, +else + INSTR_PROF_DATA_SUFFIX= + DATA_SECTION_PREFIX= + LLVM_COV_SECTION_PREFIX= +endif + +ifeq ($(LINK_DEAD_CODE),yes) + DEFINE_INTERNAL=define hidden +else + DEFINE_INTERNAL=define internal +endif + +ifdef IS_WINDOWS + LLVM_FILECHECK_OPTIONS=\ + -check-prefixes=CHECK,WINDOWS \ + -DPRIVATE_GLOBAL='internal global' \ + -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ + -DINSTR_PROF_DATA='.lprfd$$M' \ + -DINSTR_PROF_NAME='.lprfn$$M' \ + -DINSTR_PROF_CNTS='.lprfc$$M' \ + -DINSTR_PROF_VALS='.lprfv$$M' \ + -DINSTR_PROF_VNODES='.lprfnd$$M' \ + -DINSTR_PROF_COVMAP='.lcovmap$$M' \ + -DINSTR_PROF_ORDERFILE='.lorderfile$$M' +else + LLVM_FILECHECK_OPTIONS=\ + -check-prefixes=CHECK \ + -DPRIVATE_GLOBAL='private global' \ + -DDEFINE_INTERNAL='$(DEFINE_INTERNAL)' \ + -DINSTR_PROF_DATA='$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)' \ + -DINSTR_PROF_NAME='$(DATA_SECTION_PREFIX)__llvm_prf_names' \ + -DINSTR_PROF_CNTS='$(DATA_SECTION_PREFIX)__llvm_prf_cnts' \ + -DINSTR_PROF_VALS='$(DATA_SECTION_PREFIX)__llvm_prf_vals' \ + -DINSTR_PROF_VNODES='$(DATA_SECTION_PREFIX)__llvm_prf_vnds' \ + -DINSTR_PROF_COVMAP='$(LLVM_COV_SECTION_PREFIX)__llvm_covmap' \ + -DINSTR_PROF_ORDERFILE='$(DATA_SECTION_PREFIX)__llvm_orderfile' +endif + +all: + # Compile the test program with non-experimental coverage instrumentation, and generate LLVM IR + # + # Note: `-Clink-dead-code=no` disables the option, needed because the option is automatically + # enabled for some platforms, but not for Windows MSVC (due to Issue #76038). The state of this + # option affects the generated MIR and coverage, so it is enabled for tests to ensure the + # tests results are the same across platforms. + $(RUSTC) $(BASEDIR)/testprog.rs \ + -Zinstrument-coverage \ + -Clink-dead-code=$(LINK_DEAD_CODE) \ + --emit=llvm-ir + + cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" $(BASEDIR)/filecheck.testprog.txt $(LLVM_FILECHECK_OPTIONS) diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt new file mode 100644 index 0000000000..0a3c4aedd5 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/filecheck.testprog.txt @@ -0,0 +1,49 @@ +# Check for metadata, variables, declarations, and function definitions injected +# into LLVM IR when compiling with -Zinstrument-coverage. + +WINDOWS: $__llvm_profile_runtime_user = comdat any + +CHECK: @__llvm_coverage_mapping = internal constant +CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 + +WINDOWS: @__llvm_profile_runtime = external global i32 + +CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] +CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 + +CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] +CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, +CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 + +CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] +CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 + +CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] +CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main, +CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 + +CHECK: @__llvm_prf_nm = private constant +CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 + +CHECK: @llvm.used = appending global +CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*) +WINDOWS-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*) +CHECK-SAME: i8* bitcast ({ {{.*}} }* @__profd__R{{[a-zA-Z0-9_]*}}testprog4main to i8*) +CHECK-SAME: i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0) +CHECK-SAME: section "llvm.metadata" + +CHECK: [[DEFINE_INTERNAL]] { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { +CHECK-NEXT: start: +CHECK-NOT: bb{{[0-9]+}}: +CHECK: %pgocount = load i64, i64* getelementptr inbounds +CHECK-SAME: * @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, + +CHECK: declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] + +WINDOWS: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { +WINDOWS-NEXT: %1 = load i32, i32* @__llvm_profile_runtime +WINDOWS-NEXT: ret i32 %1 +WINDOWS-NEXT: } + +CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } +WINDOWS: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } diff --git a/src/test/run-make-fulldeps/instrument-coverage/testprog.rs b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/testprog.rs similarity index 100% rename from src/test/run-make-fulldeps/instrument-coverage/testprog.rs rename to src/test/run-make-fulldeps/instrument-coverage-llvm-ir-base/testprog.rs diff --git a/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile new file mode 100644 index 0000000000..ba2126a6b3 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-llvm-ir-link-dead-code/Makefile @@ -0,0 +1,11 @@ +# needs-profiler-support +# ignore-msvc + +# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 +LINK_DEAD_CODE=yes + +-include ../instrument-coverage-llvm-ir-base/Makefile + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile new file mode 100644 index 0000000000..5cd425979e --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/Makefile @@ -0,0 +1,42 @@ +# needs-profiler-support + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. + +-include ../instrument-coverage/coverage_tools.mk + +SOURCEDIR=../instrument-coverage + +all: $(patsubst $(SOURCEDIR)/%.rs,%,$(wildcard $(SOURCEDIR)/*.rs)) + +# Ensure there are no `expected` results for tests that may have been removed or renamed +.PHONY: clear_expected_if_blessed +clear_expected_if_blessed: +ifdef RUSTC_BLESS_TEST + rm -rf expected_mir_dump.*/ +endif + +-include clear_expected_if_blessed + +%: $(SOURCEDIR)/%.rs + # Compile the test program with "experimental" coverage instrumentation and generate relevant MIR. + # + # FIXME(richkadel): `-Zexperimental-coverage` to `-Zinstrument-coverage` once we are + # satisfied with the branch-level instrumentation. + $(RUSTC) $(SOURCEDIR)/$@.rs \ + -Zexperimental-coverage \ + -Clink-dead-code=$(LINK_DEAD_CODE) \ + -Zdump-mir=InstrumentCoverage \ + -Zdump-mir-dir="$(TMPDIR)"/mir_dump.$@ + +ifdef RUSTC_BLESS_TEST + mkdir -p expected_mir_dump.$@ + cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html expected_mir_dump.$@/ +else + # Check that the selected `mir_dump` files match what we expect (`--bless` refreshes `expected`) + mkdir -p "$(TMPDIR)"/actual_mir_dump.$@ + rm -f "$(TMPDIR)"/actual_mir_dump.$@/* + cp "$(TMPDIR)"/mir_dump.$@/*InstrumentCoverage.0.html "$(TMPDIR)"/actual_mir_dump.$@/ + $(DIFF) -r expected_mir_dump.$@/ "$(TMPDIR)"/actual_mir_dump.$@/ +endif diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000..94abe11896 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-base/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,808 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() { + let mut countdown = 0; + 2⦊4⦊3⦊if 0⦊true⦉0 { + countdown = 10; + }⦉3⦉4⦉2 + + 6⦊9⦊25⦊if 5⦊countdown > 7⦉5 { + 8⦊countdown -= 4⦉8; + } else 10⦊if 7⦊countdown > 2⦉7 { + 22⦊23⦊21⦊if 14⦊15⦊16⦊13⦊20⦊12⦊18⦊19⦊17⦊countdown < 1 || countdown > 5⦉17⦉19⦉18 || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { + countdown = 0; + 24⦊}⦉22⦉23⦉21⦉21 + countdown -= 5⦉24; + } else { + 27⦊11⦊return; + }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11 + + let mut countdown = 0; + 30⦊31⦊29⦊if 28⦊true⦉28 { + countdown = 10; + }⦉29⦉31⦉30 + + 33⦊52⦊36⦊if 32⦊countdown > 7⦉32 { + 35⦊countdown -= 4⦉35; + } else 37⦊if 34⦊countdown > 2⦉34 { + 48⦊50⦊49⦊if 39⦊47⦊40⦊43⦊42⦊41⦊46⦊45⦊44⦊countdown < 1 || countdown > 5⦉44⦉45⦉46 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39 { + countdown = 0; + 51⦊}⦉48⦉50⦉49⦉49 + countdown -= 5⦉51; + } else { + 38⦊return; + }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 + + let mut countdown = 0; + 56⦊54⦊55⦊if 53⦊true⦉53 { + countdown = 10; + }⦉55⦉54⦉56 + + 61⦊58⦊77⦊if 57⦊countdown > 7⦉57 { + 60⦊countdown -= 4⦉60; + } else 62⦊if 59⦊countdown > 2⦉59 { + 75⦊74⦊73⦊if 67⦊68⦊65⦊72⦊64⦊66⦊69⦊71⦊70⦊countdown < 1 || countdown > 5⦉70⦉71⦉69 || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { + countdown = 0; + 76⦊}⦉75⦉74⦉73⦉73 + countdown -= 5⦉76; + } else { + 63⦊return; + }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +78⦊}⦉78⦉63⦉38⦉2726⦊⦉26
    + + diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile new file mode 100644 index 0000000000..0578949b3c --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/Makefile @@ -0,0 +1,11 @@ +# needs-profiler-support +# ignore-msvc + +# LINK_DEAD_CODE requires ignore-msvc due to Issue #76038 +LINK_DEAD_CODE=yes + +-include ../instrument-coverage-mir-cov-html-base/Makefile + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw`. +# See ../instrument-coverage/coverage_tools.mk for more information. \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html new file mode 100644 index 0000000000..94abe11896 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage-mir-cov-html-link-dead-code/expected_mir_dump.coverage_of_if_else/coverage_of_if_else.main.-------.InstrumentCoverage.0.html @@ -0,0 +1,808 @@ + + + + coverage_of_if_else - Code Regions + + + +
    fn main() { + let mut countdown = 0; + 2⦊4⦊3⦊if 0⦊true⦉0 { + countdown = 10; + }⦉3⦉4⦉2 + + 6⦊9⦊25⦊if 5⦊countdown > 7⦉5 { + 8⦊countdown -= 4⦉8; + } else 10⦊if 7⦊countdown > 2⦉7 { + 22⦊23⦊21⦊if 14⦊15⦊16⦊13⦊20⦊12⦊18⦊19⦊17⦊countdown < 1 || countdown > 5⦉17⦉19⦉18 || countdown != 9⦉12⦉20⦉13⦉16⦉15⦉14 { + countdown = 0; + 24⦊}⦉22⦉23⦉21⦉21 + countdown -= 5⦉24; + } else { + 27⦊11⦊return; + }⦉11⦉6⦉9⦉25⦉25⦉25⦉10⦉10⦉10⦉11 + + let mut countdown = 0; + 30⦊31⦊29⦊if 28⦊true⦉28 { + countdown = 10; + }⦉29⦉31⦉30 + + 33⦊52⦊36⦊if 32⦊countdown > 7⦉32 { + 35⦊countdown -= 4⦉35; + } else 37⦊if 34⦊countdown > 2⦉34 { + 48⦊50⦊49⦊if 39⦊47⦊40⦊43⦊42⦊41⦊46⦊45⦊44⦊countdown < 1 || countdown > 5⦉44⦉45⦉46 || countdown != 9⦉41⦉42⦉43⦉40⦉47⦉39 { + countdown = 0; + 51⦊}⦉48⦉50⦉49⦉49 + countdown -= 5⦉51; + } else { + 38⦊return; + }⦉33⦉52⦉36⦉36⦉36⦉37⦉37⦉37 + + let mut countdown = 0; + 56⦊54⦊55⦊if 53⦊true⦉53 { + countdown = 10; + }⦉55⦉54⦉56 + + 61⦊58⦊77⦊if 57⦊countdown > 7⦉57 { + 60⦊countdown -= 4⦉60; + } else 62⦊if 59⦊countdown > 2⦉59 { + 75⦊74⦊73⦊if 67⦊68⦊65⦊72⦊64⦊66⦊69⦊71⦊70⦊countdown < 1 || countdown > 5⦉70⦉71⦉69 || countdown != 9⦉66⦉64⦉72⦉65⦉68⦉67 { + countdown = 0; + 76⦊}⦉75⦉74⦉73⦉73 + countdown -= 5⦉76; + } else { + 63⦊return; + }⦉61⦉58⦉77⦉77⦉77⦉62⦉62⦉62 +78⦊}⦉78⦉63⦉38⦉2726⦊⦉26
    + + diff --git a/src/test/run-make-fulldeps/instrument-coverage/Makefile b/src/test/run-make-fulldeps/instrument-coverage/Makefile deleted file mode 100644 index 4392cfec08..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/Makefile +++ /dev/null @@ -1,103 +0,0 @@ -# needs-profiler-support -# ignore-msvc - -# FIXME(richkadel): Debug the following problem, and reenable on Windows (by -# removing the `# ignore-msvc` directive above). The current implementation -# generates a segfault when running the instrumented `testprog` executable, -# after the `main()` function completes, but before the process terminates. -# This most likely points to a problem generating the LLVM "testprog.profraw" -# file. - --include ../tools.mk - -UNAME = $(shell uname) - -ifeq ($(UNAME),Darwin) - INSTR_PROF_DATA_SUFFIX=,regular,live_support - DATA_SECTION_PREFIX=__DATA, - LLVM_COV_SECTION_PREFIX=__LLVM_COV, -else - INSTR_PROF_DATA_SUFFIX= - DATA_SECTION_PREFIX= - LLVM_COV_SECTION_PREFIX= -endif - -# This test makes sure that LLVM coverage maps are genereated in LLVM IR. - -COMMON_FLAGS=-Zinstrument-coverage - -all: - # Compile the test program with instrumentation, and also generate LLVM IR - $(RUSTC) $(COMMON_FLAGS) testprog.rs \ - --emit=link,llvm-ir - - # check the LLVM IR -ifdef IS_WIN32 - cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \ - -check-prefixes=CHECK,WIN32 \ - -DPRIVATE_GLOBAL="internal global" \ - -DINSTR_PROF_DATA=".lprfd$$M" \ - -DINSTR_PROF_NAME=".lprfn$$M" \ - -DINSTR_PROF_CNTS=".lprfc$$M" \ - -DINSTR_PROF_VALS=".lprfv$$M" \ - -DINSTR_PROF_VNODES=".lprfnd$$M" \ - -DINSTR_PROF_COVMAP=".lcovmap$$M" \ - -DINSTR_PROF_ORDERFILE=".lorderfile$$M" -else - cat "$(TMPDIR)"/testprog.ll | "$(LLVM_FILECHECK)" filecheck-patterns.txt \ - -check-prefixes=CHECK \ - -DPRIVATE_GLOBAL="private global" \ - -DINSTR_PROF_DATA="$(DATA_SECTION_PREFIX)__llvm_prf_data$(INSTR_PROF_DATA_SUFFIX)" \ - -DINSTR_PROF_NAME="$(DATA_SECTION_PREFIX)__llvm_prf_names" \ - -DINSTR_PROF_CNTS="$(DATA_SECTION_PREFIX)__llvm_prf_cnts" \ - -DINSTR_PROF_VALS="$(DATA_SECTION_PREFIX)__llvm_prf_vals" \ - -DINSTR_PROF_VNODES="$(DATA_SECTION_PREFIX)__llvm_prf_vnds" \ - -DINSTR_PROF_COVMAP="$(LLVM_COV_SECTION_PREFIX)__llvm_covmap" \ - -DINSTR_PROF_ORDERFILE="$(DATA_SECTION_PREFIX)__llvm_orderfile" -endif - - # Run it in order to generate some profiling data, - # with `LLVM_PROFILE_FILE=` environment variable set to - # output the coverage stats for this run. - LLVM_PROFILE_FILE="$(TMPDIR)"/testprog.profraw \ - $(call RUN,testprog) - - # Postprocess the profiling data so it can be used by the llvm-cov tool - "$(LLVM_BIN_DIR)"/llvm-profdata merge --sparse \ - "$(TMPDIR)"/testprog.profraw \ - -o "$(TMPDIR)"/testprog.profdata - - # Generate a coverage report using `llvm-cov show`. The output ordering - # can be non-deterministic, so ignore the return status. If the test fails - # when comparing the JSON `export`, the `show` output may be useful when - # debugging. - "$(LLVM_BIN_DIR)"/llvm-cov show \ - --Xdemangler="$(RUST_DEMANGLER)" \ - --show-line-counts-or-regions \ - --instr-profile="$(TMPDIR)"/testprog.profdata \ - $(call BIN,"$(TMPDIR)"/testprog) \ - > "$(TMPDIR)"/actual_show_coverage.txt - -ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/actual_show_coverage.txt typical_show_coverage.txt -else - # Compare the show coverage output - $(DIFF) typical_show_coverage.txt "$(TMPDIR)"/actual_show_coverage.txt || \ - >&2 echo 'diff failed for `llvm-cov show` (might not be an error)' -endif - - # Generate a coverage report in JSON, using `llvm-cov export`, and fail if - # there are differences from the expected output. - "$(LLVM_BIN_DIR)"/llvm-cov export \ - --summary-only \ - --instr-profile="$(TMPDIR)"/testprog.profdata \ - $(call BIN,"$(TMPDIR)"/testprog) \ - | "$(PYTHON)" prettify_json.py \ - > "$(TMPDIR)"/actual_export_coverage.json - -ifdef RUSTC_BLESS_TEST - cp "$(TMPDIR)"/actual_export_coverage.json expected_export_coverage.json -else - # Check that the exported JSON coverage data matches what we expect - $(DIFF) expected_export_coverage.json "$(TMPDIR)"/actual_export_coverage.json -endif diff --git a/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir b/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir new file mode 100644 index 0000000000..d57f66a448 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/compiletest-ignore-dir @@ -0,0 +1,3 @@ +# Directory "instrument-coverage" supports the tests at prefix ../instrument-coverage-* + +# Use ./x.py [options] test src/test/run-make-fulldeps/instrument-coverage to run all related tests. \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs b/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs new file mode 100644 index 0000000000..91741cf8f0 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/coverage_of_if_else.rs @@ -0,0 +1,51 @@ +#![allow(unused_assignments)] + +fn main() { + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } + + let mut countdown = 0; + if true { + countdown = 10; + } + + if countdown > 7 { + countdown -= 4; + } else if countdown > 2 { + if countdown < 1 || countdown > 5 || countdown != 9 { + countdown = 0; + } + countdown -= 5; + } else { + return; + } +} diff --git a/src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk b/src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk new file mode 100644 index 0000000000..ad5f465c54 --- /dev/null +++ b/src/test/run-make-fulldeps/instrument-coverage/coverage_tools.mk @@ -0,0 +1,39 @@ +# Common Makefile include for Rust `run-make-fulldeps/instrument-coverage-* tests. Include this +# file with the line: +# +# -include ../instrument-coverage/coverage_tools.mk +# +# To enable the Rust compiler option `-C link-dead-code`, also set the following variable +# *BEFORE* the `-include` line: +# +# LINK_DEAD_CODE=yes + +-include ../tools.mk + +ifndef LINK_DEAD_CODE + LINK_DEAD_CODE=no +endif + +# ISSUE(76038): When targeting MSVC, Rust binaries built with both `-Z instrument-coverage` and +# `-C link-dead-code` typically crash (with a seg-fault) or at best generate an empty `*.profraw` +# file, required for coverage reports. +# +# Enabling `-C link-dead-code` is preferred when compiling with `-Z instrument-coverage`, so +# `-C link-dead-code` is automatically enabled for all platform targets _except_ MSVC. +# +# Making the state of `-C link-dead-code` platform-dependent creates a problem for cross-platform +# tests because the injected counters, coverage reports, and some low-level output can be different, +# depending on the `-C link-dead-code` setting. For example, coverage reports will not report any +# coverage for a dead code region when the `-C link-dead-code` option is disabled, but with the +# option enabled, those same regions will show coverage counter values (of zero, of course). +# +# To ensure cross-platform `-Z instrument-coverage` generate consistent output, the +# `-C link-dead-code` option is always explicitly enabled or disabled. +# +# Since tests that execute binaries enabled with both `-Z instrument-coverage` and +# `-C link-dead-code` are known to fail, those tests will need the `# ignore-msvc` setting. +# +# If and when the above issue is resolved, the `# ignore-msvc` option can be removed, and the +# tests can be simplified to always test with `-C link-dead-code`. + +UNAME = $(shell uname) diff --git a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json b/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json deleted file mode 100644 index 75bec80bdf..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/expected_export_coverage.json +++ /dev/null @@ -1,59 +0,0 @@ -{ - "data": [ - { - "files": [ - { - "filename": "testprog.rs", - "summary": { - "functions": { - "count": 7, - "covered": 5, - "percent": 71.42857142857143 - }, - "instantiations": { - "count": 8, - "covered": 6, - "percent": 75 - }, - "lines": { - "count": 30, - "covered": 25, - "percent": 83.33333333333334 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "totals": { - "functions": { - "count": 7, - "covered": 5, - "percent": 71.42857142857143 - }, - "instantiations": { - "count": 8, - "covered": 6, - "percent": 75 - }, - "lines": { - "count": 30, - "covered": 25, - "percent": 83.33333333333334 - }, - "regions": { - "count": 7, - "covered": 5, - "notcovered": 2, - "percent": 71.42857142857143 - } - } - } - ], - "type": "llvm.coverage.json.export", - "version": "2.0.1" -} diff --git a/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt b/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt deleted file mode 100644 index 5a7cc9a188..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/filecheck-patterns.txt +++ /dev/null @@ -1,51 +0,0 @@ -# Check for metadata, variables, declarations, and function definitions injected -# into LLVM IR when compiling with -Zinstrument-coverage. - -WIN32: $__llvm_profile_runtime_user = comdat any - -CHECK: @__llvm_coverage_mapping = internal constant -CHECK-SAME: section "[[INSTR_PROF_COVMAP]]", align 8 - -WIN32: @__llvm_profile_runtime = external global i32 - -CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] -CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 - -CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog14will_be_called = [[PRIVATE_GLOBAL]] -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, -CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called to i8*), -CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 - -CHECK: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] -CHECK-SAME: section "[[INSTR_PROF_CNTS]]", align 8 - -CHECK: @__profd__R{{[a-zA-Z0-9_]+}}testprog4main = [[PRIVATE_GLOBAL]] -CHECK-SAME: @__profc__R{{[a-zA-Z0-9_]+}}testprog4main, -CHECK-SAME: ()* @_R{{[a-zA-Z0-9_]+}}testprog4main to i8*), -CHECK-SAME: section "[[INSTR_PROF_DATA]]", align 8 - -CHECK: @__llvm_prf_nm = private constant -CHECK-SAME: section "[[INSTR_PROF_NAME]]", align 1 - -CHECK: @llvm.used = appending global -CHECK-SAME: i8* bitcast ({ {{.*}} }* @__llvm_coverage_mapping to i8*) -WIN32-SAME: i8* bitcast (i32 ()* @__llvm_profile_runtime_user to i8*) -CHECK-SAME: i8* bitcast ({ {{.*}} }* @__profd__R{{[a-zA-Z0-9_]*}}testprog4main to i8*) -CHECK-SAME: i8* getelementptr inbounds ({{.*}}* @__llvm_prf_nm, i32 0, i32 0) -CHECK-SAME: section "llvm.metadata" - -CHECK: define hidden { {{.*}} } @_R{{[a-zA-Z0-9_]+}}testprog14will_be_called() unnamed_addr #{{[0-9]+}} { -CHECK-NEXT: start: -CHECK-NOT: bb{{[0-9]+}}: -CHECK: %pgocount = load i64, i64* getelementptr inbounds -CHECK-SAME: * @__profc__R{{[a-zA-Z0-9_]+}}testprog14will_be_called, - -CHECK: declare void @llvm.instrprof.increment(i8*, i64, i32, i32) #[[LLVM_INSTRPROF_INCREMENT_ATTR:[0-9]+]] - -WIN32: define linkonce_odr hidden i32 @__llvm_profile_runtime_user() #[[LLVM_PROFILE_RUNTIME_USER_ATTR:[0-9]+]] comdat { -WIN32-NEXT: %1 = load i32, i32* @__llvm_profile_runtime -WIN32-NEXT: ret i32 %1 -WIN32-NEXT: } - -CHECK: attributes #[[LLVM_INSTRPROF_INCREMENT_ATTR]] = { nounwind } -WIN32: attributes #[[LLVM_PROFILE_RUNTIME_USER_ATTR]] = { noinline } \ No newline at end of file diff --git a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt b/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt deleted file mode 100644 index ae123afff0..0000000000 --- a/src/test/run-make-fulldeps/instrument-coverage/typical_show_coverage.txt +++ /dev/null @@ -1,55 +0,0 @@ - 1| 2|pub fn will_be_called() -> &'static str { - 2| 2| let val = "called"; - 3| 2| println!("{}", val); - 4| 2| val - 5| 2|} - 6| | - 7| 0|pub fn will_not_be_called() -> bool { - 8| 0| println!("should not have been called"); - 9| 0| false - 10| 0|} - 11| | - 12| |pub fn print(left: &str, value: T, right: &str) - 13| |where - 14| | T: std::fmt::Display, - 15| 1|{ - 16| 1| println!("{}{}{}", left, value, right); - 17| 1|} - 18| | - 19| |pub fn wrap_with(inner: T, should_wrap: bool, wrapper: F) - 20| |where - 21| | F: FnOnce(&T) - 22| 2|{ - 23| 2| if should_wrap { - 24| 2| wrapper(&inner) - 25| 2| } - 26| 2|} - ------------------ - | testprog[317d481089b8c8fe]::wrap_with::: - | 22| 1|{ - | 23| 1| if should_wrap { - | 24| 1| wrapper(&inner) - | 25| 1| } - | 26| 1|} - ------------------ - | testprog[317d481089b8c8fe]::wrap_with::: - | 22| 1|{ - | 23| 1| if should_wrap { - | 24| 1| wrapper(&inner) - | 25| 1| } - | 26| 1|} - ------------------ - 27| | - 28| 1|fn main() { - 29| 1| let less = 1; - 30| 1| let more = 100; - 31| 1| - 32| 1| if less < more { - 33| 1| wrap_with(will_be_called(), less < more, |inner| print(" ***", inner, "*** ")); - 34| 1| wrap_with(will_be_called(), more < less, |inner| print(" ***", inner, "*** ")); - ^0 - 35| 1| } else { - 36| 1| wrap_with(will_not_be_called(), true, |inner| print("wrapped result is: ", inner, "")); - 37| 1| } - 38| 1|} - diff --git a/src/test/run-make-fulldeps/issue-19371/foo.rs b/src/test/run-make-fulldeps/issue-19371/foo.rs index af84faa751..2636423c1a 100644 --- a/src/test/run-make-fulldeps/issue-19371/foo.rs +++ b/src/test/run-make-fulldeps/issue-19371/foo.rs @@ -60,6 +60,7 @@ fn compile(code: String, output: PathBuf, sysroot: PathBuf) { lint_caps: Default::default(), register_lints: None, override_queries: None, + make_codegen_backend: None, registry: rustc_driver::diagnostics_registry(), }; diff --git a/src/test/run-make-fulldeps/issue-69368/a.rs b/src/test/run-make-fulldeps/issue-69368/a.rs index 726db87463..7d339c5a5d 100644 --- a/src/test/run-make-fulldeps/issue-69368/a.rs +++ b/src/test/run-make-fulldeps/issue-69368/a.rs @@ -14,3 +14,8 @@ pub fn panic_handler(_: &core::panic::PanicInfo) -> ! { extern "C" fn __rust_drop_panic() -> ! { loop {} } + +#[no_mangle] +extern "C" fn __rust_foreign_exception() -> ! { + loop {} +} diff --git a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile index c13297b3a6..18828b66ce 100644 --- a/src/test/run-make-fulldeps/pgo-branch-weights/Makefile +++ b/src/test/run-make-fulldeps/pgo-branch-weights/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile index 6c70d951c3..f1ac39aa0e 100644 --- a/src/test/run-make-fulldeps/pgo-gen-lto/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen-lto/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-gen/Makefile b/src/test/run-make-fulldeps/pgo-gen/Makefile index 3b66427c14..69b19801bf 100644 --- a/src/test/run-make-fulldeps/pgo-gen/Makefile +++ b/src/test/run-make-fulldeps/pgo-gen/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile index e61018752c..876a9b2c43 100644 --- a/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile +++ b/src/test/run-make-fulldeps/pgo-indirect-call-promotion/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/pgo-use/Makefile b/src/test/run-make-fulldeps/pgo-use/Makefile index 61a7358775..cb5e9e9a45 100644 --- a/src/test/run-make-fulldeps/pgo-use/Makefile +++ b/src/test/run-make-fulldeps/pgo-use/Makefile @@ -1,4 +1,8 @@ # needs-profiler-support +# ignore-windows-gnu + +# FIXME(mati865): MinGW GCC miscompiles compiler-rt profiling library but with Clang it works +# properly. Since we only have GCC on the CI ignore the test for now. -include ../tools.mk diff --git a/src/test/run-make-fulldeps/tools.mk b/src/test/run-make-fulldeps/tools.mk index f9b6d34229..634c9ece3f 100644 --- a/src/test/run-make-fulldeps/tools.mk +++ b/src/test/run-make-fulldeps/tools.mk @@ -11,8 +11,8 @@ BARE_RUSTDOC := $(HOST_RPATH_ENV) '$(RUSTDOC)' RUSTC := $(BARE_RUSTC) --out-dir $(TMPDIR) -L $(TMPDIR) $(RUSTFLAGS) RUSTDOC := $(BARE_RUSTDOC) -L $(TARGET_RPATH_DIR) ifdef RUSTC_LINKER -RUSTC := $(RUSTC) -Clinker=$(RUSTC_LINKER) -RUSTDOC := $(RUSTDOC) -Clinker=$(RUSTC_LINKER) +RUSTC := $(RUSTC) -Clinker='$(RUSTC_LINKER)' +RUSTDOC := $(RUSTDOC) -Clinker='$(RUSTC_LINKER)' endif #CC := $(CC) -L $(TMPDIR) HTMLDOCCK := '$(PYTHON)' '$(S)/src/etc/htmldocck.py' diff --git a/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile b/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile index 9fd1377322..802b3df460 100644 --- a/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile +++ b/src/test/run-make-fulldeps/type-mismatch-same-crate-name/Makefile @@ -11,9 +11,9 @@ all: tr -d '\r\n' | $(CGREP) -e \ "mismatched types.*\ crateB::try_foo\(foo2\);.*\ - expected struct \`crateA::foo::Foo\`, found struct \`crateA::Foo\`.*\ + expected struct \`crateA::foo::Foo\`, found struct \`Foo\`.*\ different versions of crate \`crateA\`.*\ mismatched types.*\ crateB::try_bar\(bar2\);.*\ - expected trait \`crateA::bar::Bar\`, found trait \`crateA::Bar\`.*\ + expected trait \`crateA::bar::Bar\`, found trait \`Bar\`.*\ different versions of crate \`crateA\`" diff --git a/src/test/run-make/thumb-none-cortex-m/Makefile b/src/test/run-make/thumb-none-cortex-m/Makefile index 36e51bcab6..13385369e4 100644 --- a/src/test/run-make/thumb-none-cortex-m/Makefile +++ b/src/test/run-make/thumb-none-cortex-m/Makefile @@ -35,4 +35,4 @@ all: # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. - cd $(WORK_DIR) && cd $(CRATE) && env RUSTC_BOOTSTRAP=1 $(CARGO) build --target $(TARGET) -v + cd $(WORK_DIR) && cd $(CRATE) && env RUSTC_BOOTSTRAP=1 $(BOOTSTRAP_CARGO) build --target $(TARGET) -v diff --git a/src/test/run-make/thumb-none-qemu/script.sh b/src/test/run-make/thumb-none-qemu/script.sh index c5cbff5c3c..045d02a8ed 100644 --- a/src/test/run-make/thumb-none-qemu/script.sh +++ b/src/test/run-make/thumb-none-qemu/script.sh @@ -12,8 +12,8 @@ pushd $WORK_DIR # These come from the top-level Rust workspace, that this crate is not a # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \ - $CARGO run --target $TARGET | grep "x = 42" + $BOOTSTRAP_CARGO run --target $TARGET | grep "x = 42" env RUSTC_BOOTSTRAP=1 RUSTFLAGS="-C linker=arm-none-eabi-ld -C link-arg=-Tlink.x" \ - $CARGO run --target $TARGET --release | grep "x = 42" + $BOOTSTRAP_CARGO run --target $TARGET --release | grep "x = 42" popd popd diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile new file mode 100644 index 0000000000..6a04d34391 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/Makefile @@ -0,0 +1,23 @@ +-include ../../run-make-fulldeps/tools.mk + +#only-x86_64-fortanix-unknown-sgx + +# For cargo setting +export RUSTC := $(RUSTC_ORIGINAL) +export LD_LIBRARY_PATH := $(HOST_RPATH_DIR) +# We need to be outside of 'src' dir in order to run cargo +export WORK_DIR := $(TMPDIR) +export TEST_DIR := $(shell pwd) + +## clean up unused env variables which might cause harm. +unexport RUSTC_LINKER +unexport RUSTC_BOOTSTRAP +unexport RUST_BUILD_STAGE +unexport RUST_TEST_THREADS +unexport RUST_TEST_TMPDIR +unexport AR +unexport CC +unexport CXX + +all: + bash script.sh diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks new file mode 100644 index 0000000000..e839c200bb --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_asm.checks @@ -0,0 +1,8 @@ +CHECK: cc_plus_one_asm +CHECK-NEXT: movl +CHECK-NEXT: lfence +CHECK-NEXT: inc +CHECK-NEXT: notq (%rsp) +CHECK-NEXT: notq (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks new file mode 100644 index 0000000000..b93b33afb3 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c.checks @@ -0,0 +1,6 @@ +CHECK: cc_plus_one_c +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks new file mode 100644 index 0000000000..d1fae3d495 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_c_asm.checks @@ -0,0 +1,15 @@ +CHECK: cc_plus_one_c_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks new file mode 100644 index 0000000000..f96f152c02 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx.checks @@ -0,0 +1,6 @@ +CHECK: cc_plus_one_cxx +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks new file mode 100644 index 0000000000..e704bf4172 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cc_plus_one_cxx_asm.checks @@ -0,0 +1,16 @@ +CHECK: cc_plus_one_cxx_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks new file mode 100644 index 0000000000..78b18ccbfc --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_asm.checks @@ -0,0 +1,7 @@ +CHECK: cmake_plus_one_asm +CHECK-NEXT: movl +CHECK-NEXT: lfence +CHECK-NEXT: incl +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks new file mode 100644 index 0000000000..f551356b2f --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c.checks @@ -0,0 +1,6 @@ +CHECK: cmake_plus_one_c +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks new file mode 100644 index 0000000000..87c806f137 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_asm.checks @@ -0,0 +1,16 @@ +CHECK: cmake_plus_one_c_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks new file mode 100644 index 0000000000..4b66cc5bc8 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_c_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: cmake_plus_one_c_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks new file mode 100644 index 0000000000..0f403e0203 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx.checks @@ -0,0 +1,6 @@ +CHECK: cmake_plus_one_cxx +CHECK: lfence +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks new file mode 100644 index 0000000000..9cac8711ea --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_asm.checks @@ -0,0 +1,16 @@ +CHECK: cmake_plus_one_cxx_asm +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: movl +CHECK: lfence +CHECK-NEXT: incl +CHECK-NEXT: jmp 0x{{[[:xdigit:]]+}} +CHECK-NEXT: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq +CHECK: popq +CHECK-NEXT: popq [[REGISTER:%[a-z]+]] +CHECK-NEXT: lfence +CHECK-NEXT: jmpq *[[REGISTER]] diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks new file mode 100644 index 0000000000..d4a3d44790 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/cmake_plus_one_cxx_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: cmake_plus_one_cxx_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml new file mode 100644 index 0000000000..8949068658 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "enclave" +version = "0.1.0" +authors = ["Raoul Strackx "] +edition = "2018" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] + +[build-dependencies] +cc = "1.0" +cmake = "0.1" diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs new file mode 100644 index 0000000000..3a7aa1be86 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/build.rs @@ -0,0 +1,30 @@ +fn main() { + cc::Build::new() + .file("foo.c") + .compile("foo_c"); + + cc::Build::new() + .file("foo_asm.s") + .compile("foo_asm"); + + cc::Build::new() + .cpp(true) + .cpp_set_stdlib(None) + .file("foo_cxx.cpp") + .compile("foo_cxx"); + + // When the cmake crate detects the clang compiler, it passes the + // "--target" argument to the linker which subsequently fails. The + // `CMAKE_C_COMPILER_FORCED` option makes sure that `cmake` does not + // tries to test the compiler. From version 3.6 the option + // `CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY` can be used + // https://cmake.org/cmake/help/v3.5/module/CMakeForceCompiler.html + let dst = cmake::Config::new("libcmake_foo") + .build_target("cmake_foo") + .define("CMAKE_C_COMPILER_FORCED", "1") + .define("CMAKE_CXX_COMPILER_FORCED", "1") + .define("CMAKE_TRY_COMPILE_TARGET_TYPE=STATIC_LIBRARY", "1") + .build(); + println!("cargo:rustc-link-search=native={}/build/", dst.display()); + println!("cargo:rustc-link-lib=static=cmake_foo"); +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c new file mode 100644 index 0000000000..dd76d4f303 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo.c @@ -0,0 +1,18 @@ +int cc_plus_one_c(int *arg) { + return *arg + 1; +} + +int cc_plus_one_c_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s new file mode 100644 index 0000000000..6d56214e87 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_asm.s @@ -0,0 +1,7 @@ + .text + .global cc_plus_one_asm + .type cc_plus_one_asm, @function +cc_plus_one_asm: + movl (%rdi), %eax + inc %eax + retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp new file mode 100644 index 0000000000..ac6f64ac41 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/foo_cxx.cpp @@ -0,0 +1,21 @@ +extern "C" int cc_plus_one_cxx(int *arg); +extern "C" int cc_plus_one_cxx_asm(int *arg); + +int cc_plus_one_cxx(int *arg) { + return *arg + 1; +} + +int cc_plus_one_cxx_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt new file mode 100644 index 0000000000..27cdf2ecf8 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/CMakeLists.txt @@ -0,0 +1,33 @@ +enable_language(C CXX ASM) + +set(C_SOURCES + src/foo.c + ) + +set_source_files_properties(${C_SOURCES} + PROPERTIES + LANGUAGE C) + +set(CXX_SOURCES + src/foo_cxx.cpp + ) + +set_source_files_properties(${CXX_SOURCES} + PROPERTIES + LANGUAGE CXX) + +set(ASM_SOURCES + src/foo_asm.s + ) + +set_source_files_properties(${ASM_SOURCES} + PROPERTIES + LANGUAGE ASM) + +set(SOURCES + ${C_SOURCES} + ${CXX_SOURCES} + ${ASM_SOURCES}) + +add_library(cmake_foo STATIC + ${SOURCES}) diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c new file mode 100644 index 0000000000..c3b731a2d5 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo.c @@ -0,0 +1,26 @@ +int cmake_plus_one_c(int *arg) { + return *arg + 1; +} + +int cmake_plus_one_c_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} + +asm(".text\n" +" .global cmake_plus_one_c_global_asm\n" +" .type cmake_plus_one_c_global_asm, @function\n" +"cmake_plus_one_c_global_asm:\n" +" movl (%rdi), %eax\n" +" inc %eax\n" +" retq\n" ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s new file mode 100644 index 0000000000..64b6b430ee --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_asm.s @@ -0,0 +1,7 @@ + .text + .global cmake_plus_one_asm + .type cmake_plus_one_asm, @function +cmake_plus_one_asm: + movl (%rdi), %eax + inc %eax + retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp new file mode 100644 index 0000000000..824e2afebc --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/libcmake_foo/src/foo_cxx.cpp @@ -0,0 +1,29 @@ +extern "C" int cmake_plus_one_cxx(int *arg); +extern "C" int cmake_plus_one_cxx_asm(int *arg); + +int cmake_plus_one_cxx(int *arg) { + return *arg + 1; +} + +int cmake_plus_one_cxx_asm(int *arg) { + int value = 0; + + asm volatile ( " movl (%1), %0\n" + " inc %0\n" + " jmp 1f\n" + " retq\n" // never executed, but a shortcut to determine how + // the assembler deals with `ret` instructions + "1:\n" + : "=r"(value) + : "r"(arg) ); + + return value; +} + +asm(".text\n" +" .global cmake_plus_one_cxx_global_asm\n" +" .type cmake_plus_one_cxx_global_asm, @function\n" +"cmake_plus_one_cxx_global_asm:\n" +" movl (%rdi), %eax\n" +" inc %eax\n" +" retq\n" ); diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs new file mode 100644 index 0000000000..8e91a8d842 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/enclave/src/main.rs @@ -0,0 +1,48 @@ +#![feature(global_asm)] + +global_asm!( r#" + .text + .global rust_plus_one_global_asm + .type rust_plus_one_global_asm, @function +rust_plus_one_global_asm: + movl (%rdi), %eax + inc %eax + retq +"# ); + +extern { + fn cc_plus_one_c(arg : &u32) -> u32; + fn cc_plus_one_c_asm(arg : &u32) -> u32; + fn cc_plus_one_cxx(arg : &u32) -> u32; + fn cc_plus_one_cxx_asm(arg : &u32) -> u32; + fn cc_plus_one_asm(arg : &u32) -> u32; + fn cmake_plus_one_c(arg : &u32) -> u32; + fn cmake_plus_one_c_asm(arg : &u32) -> u32; + fn cmake_plus_one_cxx(arg : &u32) -> u32; + fn cmake_plus_one_cxx_asm(arg : &u32) -> u32; + fn cmake_plus_one_c_global_asm(arg : &u32) -> u32; + fn cmake_plus_one_cxx_global_asm(arg : &u32) -> u32; + fn cmake_plus_one_asm(arg : &u32) -> u32; + fn rust_plus_one_global_asm(arg : &u32) -> u32; +} + +fn main() { + let value : u32 = 41; + let question = "Answer to the Ultimate Question of Life, the Universe, and Everything:"; + + unsafe{ + println!("{}: {}!", question,rust_plus_one_global_asm(&value)); + println!("{}: {}!", question,cc_plus_one_c(&value)); + println!("{}: {}!", question,cc_plus_one_c_asm(&value)); + println!("{}: {}!", question,cc_plus_one_cxx(&value)); + println!("{}: {}!", question,cc_plus_one_cxx_asm(&value)); + println!("{}: {}!", question,cc_plus_one_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_c(&value)); + println!("{}: {}!", question,cmake_plus_one_c_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_c_global_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_cxx_global_asm(&value)); + println!("{}: {}!", question,cmake_plus_one_asm(&value)); + } +} diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks new file mode 100644 index 0000000000..15211e3ade --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/jumpto.checks @@ -0,0 +1,8 @@ +CHECK: libunwind::Registers_x86_64::jumpto +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks new file mode 100644 index 0000000000..0fe88141b2 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/print.checks @@ -0,0 +1,7 @@ +CHECK: print +CHECK: lfence +CHECK: lfence +CHECK: lfence +CHECK: popq +CHECK: callq 0x{{[[:xdigit:]]*}} <_Unwind_Resume> +CHECK-NEXT: ud2 diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks new file mode 100644 index 0000000000..fe6777537f --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/rust_plus_one_global_asm.checks @@ -0,0 +1,2 @@ +CHECK: rust_plus_one_global_asm +CHECK: lfence diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh new file mode 100644 index 0000000000..ec93c98016 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/script.sh @@ -0,0 +1,57 @@ +set -exuo pipefail + +function build { + CRATE=enclave + + mkdir -p $WORK_DIR + pushd $WORK_DIR + rm -rf $CRATE + cp -a $TEST_DIR/enclave . + pushd $CRATE + echo ${WORK_DIR} + # HACK(eddyb) sets `RUSTC_BOOTSTRAP=1` so Cargo can accept nightly features. + # These come from the top-level Rust workspace, that this crate is not a + # member of, but Cargo tries to load the workspace `Cargo.toml` anyway. + env RUSTC_BOOTSTRAP=1 + cargo -v run --target $TARGET + popd + popd +} + +function check { + local func=$1 + local checks="${TEST_DIR}/$2" + local asm=$(mktemp) + local objdump="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/llvm-objdump" + local filecheck="${BUILD_DIR}/x86_64-unknown-linux-gnu/llvm/build/bin/FileCheck" + + ${objdump} --disassemble-symbols=${func} --demangle \ + ${WORK_DIR}/enclave/target/x86_64-fortanix-unknown-sgx/debug/enclave > ${asm} + ${filecheck} --input-file ${asm} ${checks} +} + +build + +check unw_getcontext unw_getcontext.checks +check "libunwind::Registers_x86_64::jumpto()" jumpto.checks +check "std::io::stdio::_print::h87f0c238421c45bc" print.checks +check rust_plus_one_global_asm rust_plus_one_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" + +check cc_plus_one_c cc_plus_one_c.checks +check cc_plus_one_c_asm cc_plus_one_c_asm.checks +check cc_plus_one_cxx cc_plus_one_cxx.checks +check cc_plus_one_cxx_asm cc_plus_one_cxx_asm.checks +check cc_plus_one_asm cc_plus_one_asm.checks \ + || echo "warning: the cc crate forwards assembly files to the CC compiler." \ + "Clang uses its own intergrated assembler, which does not include the LVI passes." + +check cmake_plus_one_c cmake_plus_one_c.checks +check cmake_plus_one_c_asm cmake_plus_one_c_asm.checks +check cmake_plus_one_c_global_asm cmake_plus_one_c_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_cxx cmake_plus_one_cxx.checks +check cmake_plus_one_cxx_asm cmake_plus_one_cxx_asm.checks +check cmake_plus_one_cxx_global_asm cmake_plus_one_cxx_global_asm.checks \ + || echo "warning: module level assembly currently not hardened" +check cmake_plus_one_asm cmake_plus_one_asm.checks diff --git a/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks new file mode 100644 index 0000000000..4b7615b115 --- /dev/null +++ b/src/test/run-make/x86_64-fortanix-unknown-sgx-lvi/unw_getcontext.checks @@ -0,0 +1,6 @@ +CHECK: unw_getcontext +CHECK: lfence +CHECK: lfence +CHECK: shlq $0, (%rsp) +CHECK-NEXT: lfence +CHECK-NEXT: retq diff --git a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr index 8827c9351a..92d27179e8 100644 --- a/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr +++ b/src/test/rustdoc-ui/assoc-item-not-in-scope.stderr @@ -2,14 +2,13 @@ error: unresolved link to `S::fmt` --> $DIR/assoc-item-not-in-scope.rs:4:14 | LL | /// Link to [`S::fmt`] - | ^^^^^^^^ unresolved link + | ^^^^^^^^ the struct `S` has no field or associated item named `fmt` | note: the lint level is defined here --> $DIR/assoc-item-not-in-scope.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.rs b/src/test/rustdoc-ui/check-doc-alias-attr.rs index b02cc1a454..c8bec39fad 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.rs +++ b/src/test/rustdoc-ui/check-doc-alias-attr.rs @@ -7,4 +7,10 @@ pub struct Bar; #[doc(alias)] //~ ERROR #[doc(alias = 0)] //~ ERROR #[doc(alias("bar"))] //~ ERROR +#[doc(alias = "\"")] //~ ERROR +#[doc(alias = "\n")] //~ ERROR +#[doc(alias = " +")] //~^ ERROR +#[doc(alias = " ")] //~ ERROR +#[doc(alias = "\t")] //~ ERROR pub struct Foo; diff --git a/src/test/rustdoc-ui/check-doc-alias-attr.stderr b/src/test/rustdoc-ui/check-doc-alias-attr.stderr index 268230ab44..be7d7b3dbe 100644 --- a/src/test/rustdoc-ui/check-doc-alias-attr.stderr +++ b/src/test/rustdoc-ui/check-doc-alias-attr.stderr @@ -16,5 +16,37 @@ error: doc alias attribute expects a string: #[doc(alias = "0")] LL | #[doc(alias("bar"))] | ^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: '\"' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:10:7 + | +LL | #[doc(alias = "\"")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:11:7 + | +LL | #[doc(alias = "\n")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:12:7 + | +LL | #[doc(alias = " + | _______^ +LL | | ")] + | |_^ + +error: ' ' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:14:7 + | +LL | #[doc(alias = " ")] + | ^^^^^^^^^^^ + +error: '\t' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:15:7 + | +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ + +error: aborting due to 8 previous errors diff --git a/src/test/rustdoc-ui/coverage/doc-examples.stdout b/src/test/rustdoc-ui/coverage/doc-examples.stdout index 10ed13c9ff..8188740f87 100644 --- a/src/test/rustdoc-ui/coverage/doc-examples.stdout +++ b/src/test/rustdoc-ui/coverage/doc-examples.stdout @@ -1,7 +1,7 @@ +-------------------------------------+------------+------------+------------+------------+ | File | Documented | Percentage | Examples | Percentage | +-------------------------------------+------------+------------+------------+------------+ -| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 2 | 50.0% | +| ...tdoc-ui/coverage/doc-examples.rs | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ -| Total | 4 | 100.0% | 2 | 50.0% | +| Total | 4 | 100.0% | 1 | 25.0% | +-------------------------------------+------------+------------+------------+------------+ diff --git a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr index 7530e3ad0f..33260fa0e1 100644 --- a/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr +++ b/src/test/rustdoc-ui/deny-intra-link-resolution-failure.stderr @@ -2,7 +2,7 @@ error: unresolved link to `v2` --> $DIR/deny-intra-link-resolution-failure.rs:3:6 | LL | /// [v2] - | ^^ unresolved link + | ^^ the module `deny_intra_link_resolution_failure` contains no item named `v2` | note: the lint level is defined here --> $DIR/deny-intra-link-resolution-failure.rs:1:9 diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.rs b/src/test/rustdoc-ui/doc-alias-assoc-const.rs new file mode 100644 index 0000000000..73e23c152f --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.rs @@ -0,0 +1,22 @@ +#![feature(doc_alias)] +#![feature(trait_alias)] + +pub struct Foo; + +pub trait Bar { + const BAZ: u8; +} + +impl Bar for Foo { + #[doc(alias = "CONST_BAZ")] //~ ERROR + const BAZ: u8 = 0; +} + +impl Foo { + #[doc(alias = "CONST_FOO")] // ok! + pub const FOO: u8 = 0; + + pub fn bar() -> u8 { + Self::FOO + } +} diff --git a/src/test/rustdoc-ui/doc-alias-assoc-const.stderr b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr new file mode 100644 index 0000000000..3c64548cc2 --- /dev/null +++ b/src/test/rustdoc-ui/doc-alias-assoc-const.stderr @@ -0,0 +1,8 @@ +error: `#[doc(alias = "...")]` isn't allowed on associated constant in trait implementation block + --> $DIR/doc-alias-assoc-const.rs:11:11 + | +LL | #[doc(alias = "CONST_BAZ")] + | ^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/rustdoc-ui/failed-doctest-output.rs b/src/test/rustdoc-ui/failed-doctest-output.rs index fcbd7cabc6..90cdb5127b 100644 --- a/src/test/rustdoc-ui/failed-doctest-output.rs +++ b/src/test/rustdoc-ui/failed-doctest-output.rs @@ -2,7 +2,7 @@ // FIXME: if/when the output of the test harness can be tested on its own, this test should be // adapted to use that, and that normalize line can go away -// compile-flags:--test +// compile-flags:--test --test-args --test-threads=1 // rustc-env:RUST_BACKTRACE=0 // normalize-stdout-test: "src/test/rustdoc-ui" -> "$$DIR" // failure-status: 101 diff --git a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs index acce0f77a2..2319de5568 100644 --- a/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs +++ b/src/test/rustdoc-ui/infinite-recursive-type-impl-trait-return.rs @@ -5,7 +5,7 @@ pub async fn f() -> impl std::fmt::Debug { #[derive(Debug)] enum E { - //~^ ERROR recursive type `f::{{closure}}#0::E` has infinite size + //~^ ERROR recursive type `f::{closure#0}::E` has infinite size This(E), Unit, } diff --git a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr index f1c07e31cd..771fc2204f 100644 --- a/src/test/rustdoc-ui/intra-doc-alias-ice.stderr +++ b/src/test/rustdoc-ui/intra-doc-alias-ice.stderr @@ -2,14 +2,13 @@ error: unresolved link to `TypeAlias::hoge` --> $DIR/intra-doc-alias-ice.rs:5:30 | LL | /// [broken cross-reference](TypeAlias::hoge) - | ^^^^^^^^^^^^^^^ unresolved link + | ^^^^^^^^^^^^^^^ the type alias `TypeAlias` has no associated item named `hoge` | note: the lint level is defined here --> $DIR/intra-doc-alias-ice.rs:1:9 | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` error: aborting due to previous error diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.rs b/src/test/rustdoc-ui/intra-link-double-anchor.rs new file mode 100644 index 0000000000..a01211c4f3 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.rs @@ -0,0 +1,7 @@ +// check-pass + +// regression test for #73264 +// should only give one error +/// docs [label][with#anchor#error] +//~^ WARNING multiple anchors +pub struct S; diff --git a/src/test/rustdoc-ui/intra-link-double-anchor.stderr b/src/test/rustdoc-ui/intra-link-double-anchor.stderr new file mode 100644 index 0000000000..3282ec8b79 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-double-anchor.stderr @@ -0,0 +1,10 @@ +warning: `with#anchor#error` contains multiple anchors + --> $DIR/intra-link-double-anchor.rs:5:18 + | +LL | /// docs [label][with#anchor#error] + | ^^^^^^^^^^^^^^^^^ contains invalid anchor + | + = note: `#[warn(broken_intra_doc_links)]` on by default + +warning: 1 warning emitted + diff --git a/src/test/rustdoc-ui/intra-link-errors.rs b/src/test/rustdoc-ui/intra-link-errors.rs new file mode 100644 index 0000000000..0278caf308 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.rs @@ -0,0 +1,105 @@ +#![deny(broken_intra_doc_links)] +//~^ NOTE lint level is defined + +// FIXME: this should say that it was skipped (maybe an allowed by default lint?) +/// [] + +/// [path::to::nonexistent::module] +//~^ ERROR unresolved link +//~| NOTE `intra_link_errors` contains no item named `path` + +/// [path::to::nonexistent::macro!] +//~^ ERROR unresolved link +//~| NOTE `intra_link_errors` contains no item named `path` + +/// [type@path::to::nonexistent::type] +//~^ ERROR unresolved link +//~| NOTE `intra_link_errors` contains no item named `path` + +/// [std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE `io` contains no item named `not` + +/// [type@std::io::not::here] +//~^ ERROR unresolved link +//~| NOTE `io` contains no item named `not` + +/// [std::io::Error::x] +//~^ ERROR unresolved link +//~| NOTE the struct `Error` has no field + +/// [std::io::ErrorKind::x] +//~^ ERROR unresolved link +//~| NOTE the enum `ErrorKind` has no variant + +/// [f::A] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + +/// [f::A!] +//~^ ERROR unresolved link +//~| NOTE `f` is a function, not a module + +/// [S::A] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [S::fmt] +//~^ ERROR unresolved link +//~| NOTE struct `S` has no field or associated item + +/// [E::D] +//~^ ERROR unresolved link +//~| NOTE enum `E` has no variant or associated item + +/// [u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [std::primitive::u8::not_found] +//~^ ERROR unresolved link +//~| NOTE the builtin type `u8` has no associated item named `not_found` + +/// [type@Vec::into_iter] +//~^ ERROR unresolved link +//~| HELP to link to the associated function, add parentheses +//~| NOTE this link resolves to the associated function `into_iter` + +/// [S!] +//~^ ERROR unresolved link +//~| HELP to link to the struct, prefix with `struct@` +//~| NOTE this link resolves to the struct `S` +pub fn f() {} +#[derive(Debug)] +pub struct S; + +pub enum E { A, B, C } + +/// [type@S::h] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace +impl S { + pub fn h() {} +} + +/// [type@T::g] +//~^ ERROR unresolved link +//~| HELP to link to the associated function +//~| NOTE not in the type namespace + +/// [T::h!] +//~^ ERROR unresolved link +//~| NOTE `T` has no macro named `h` +pub trait T { + fn g() {} +} + +/// [m()] +//~^ ERROR unresolved link +//~| HELP to link to the macro +//~| NOTE not in the value namespace +#[macro_export] +macro_rules! m { + () => {}; +} diff --git a/src/test/rustdoc-ui/intra-link-errors.stderr b/src/test/rustdoc-ui/intra-link-errors.stderr new file mode 100644 index 0000000000..b63f799535 --- /dev/null +++ b/src/test/rustdoc-ui/intra-link-errors.stderr @@ -0,0 +1,143 @@ +error: unresolved link to `path::to::nonexistent::module` + --> $DIR/intra-link-errors.rs:7:6 + | +LL | /// [path::to::nonexistent::module] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` + | +note: the lint level is defined here + --> $DIR/intra-link-errors.rs:1:9 + | +LL | #![deny(broken_intra_doc_links)] + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: unresolved link to `path::to::nonexistent::macro` + --> $DIR/intra-link-errors.rs:11:6 + | +LL | /// [path::to::nonexistent::macro!] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` + +error: unresolved link to `path::to::nonexistent::type` + --> $DIR/intra-link-errors.rs:15:6 + | +LL | /// [type@path::to::nonexistent::type] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the module `intra_link_errors` contains no item named `path` + +error: unresolved link to `std::io::not::here` + --> $DIR/intra-link-errors.rs:19:6 + | +LL | /// [std::io::not::here] + | ^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not` + +error: unresolved link to `std::io::not::here` + --> $DIR/intra-link-errors.rs:23:6 + | +LL | /// [type@std::io::not::here] + | ^^^^^^^^^^^^^^^^^^^^^^^ the module `io` contains no item named `not` + +error: unresolved link to `std::io::Error::x` + --> $DIR/intra-link-errors.rs:27:6 + | +LL | /// [std::io::Error::x] + | ^^^^^^^^^^^^^^^^^ the struct `Error` has no field or associated item named `x` + +error: unresolved link to `std::io::ErrorKind::x` + --> $DIR/intra-link-errors.rs:31:6 + | +LL | /// [std::io::ErrorKind::x] + | ^^^^^^^^^^^^^^^^^^^^^ the enum `ErrorKind` has no variant or associated item named `x` + +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:35:6 + | +LL | /// [f::A] + | ^^^^ `f` is a function, not a module or type, and cannot have associated items + +error: unresolved link to `f::A` + --> $DIR/intra-link-errors.rs:39:6 + | +LL | /// [f::A!] + | ^^^^^ `f` is a function, not a module or type, and cannot have associated items + +error: unresolved link to `S::A` + --> $DIR/intra-link-errors.rs:43:6 + | +LL | /// [S::A] + | ^^^^ the struct `S` has no field or associated item named `A` + +error: unresolved link to `S::fmt` + --> $DIR/intra-link-errors.rs:47:6 + | +LL | /// [S::fmt] + | ^^^^^^ the struct `S` has no field or associated item named `fmt` + +error: unresolved link to `E::D` + --> $DIR/intra-link-errors.rs:51:6 + | +LL | /// [E::D] + | ^^^^ the enum `E` has no variant or associated item named `D` + +error: unresolved link to `u8::not_found` + --> $DIR/intra-link-errors.rs:55:6 + | +LL | /// [u8::not_found] + | ^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` + +error: unresolved link to `std::primitive::u8::not_found` + --> $DIR/intra-link-errors.rs:59:6 + | +LL | /// [std::primitive::u8::not_found] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the builtin type `u8` has no associated item named `not_found` + +error: unresolved link to `Vec::into_iter` + --> $DIR/intra-link-errors.rs:63:6 + | +LL | /// [type@Vec::into_iter] + | ^^^^^^^^^^^^^^^^^^^ + | | + | this link resolves to the associated function `into_iter`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `Vec::into_iter()` + +error: unresolved link to `S` + --> $DIR/intra-link-errors.rs:68:6 + | +LL | /// [S!] + | ^^ + | | + | this link resolves to the struct `S`, which is not in the macro namespace + | help: to link to the struct, prefix with `struct@`: `struct@S` + +error: unresolved link to `T::g` + --> $DIR/intra-link-errors.rs:86:6 + | +LL | /// [type@T::g] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `g`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `T::g()` + +error: unresolved link to `T::h` + --> $DIR/intra-link-errors.rs:91:6 + | +LL | /// [T::h!] + | ^^^^^ the trait `T` has no macro named `h` + +error: unresolved link to `S::h` + --> $DIR/intra-link-errors.rs:78:6 + | +LL | /// [type@S::h] + | ^^^^^^^^^ + | | + | this link resolves to the associated function `h`, which is not in the type namespace + | help: to link to the associated function, add parentheses: `S::h()` + +error: unresolved link to `m` + --> $DIR/intra-link-errors.rs:98:6 + | +LL | /// [m()] + | ^^^ + | | + | this link resolves to the macro `m`, which is not in the value namespace + | help: to link to the macro, add an exclamation mark: `m!` + +error: aborting due to 20 previous errors + diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.rs b/src/test/rustdoc-ui/intra-link-prim-conflict.rs index 34276fbcf2..85738ceae8 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.rs +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.rs @@ -18,13 +18,13 @@ /// [struct@char] //~^ ERROR incompatible link -//~| HELP use its disambiguator +//~| HELP prefix with `mod@` //~| NOTE resolved to a module pub mod char {} pub mod inner { //! [struct@char] //~^ ERROR incompatible link - //~| HELP use its disambiguator + //~| HELP prefix with `prim@` //~| NOTE resolved to a builtin type } diff --git a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr index b28a442666..43587a8002 100644 --- a/src/test/rustdoc-ui/intra-link-prim-conflict.stderr +++ b/src/test/rustdoc-ui/intra-link-prim-conflict.stderr @@ -9,11 +9,11 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the module, prefix with the item type +help: to link to the module, prefix with `mod@` | -LL | /// [module@char] - | ^^^^^^^^^^^ -help: to link to the builtin type, prefix with the item type +LL | /// [mod@char] + | ^^^^^^^^ +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -24,11 +24,11 @@ error: `char` is both a module and a builtin type LL | /// [type@char] | ^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item type +help: to link to the module, prefix with `mod@` | -LL | /// [module@char] - | ^^^^^^^^^^^ -help: to link to the builtin type, prefix with the item type +LL | /// [mod@char] + | ^^^^^^^^ +help: to link to the builtin type, prefix with `prim@` | LL | /// [prim@char] | ^^^^^^^^^ @@ -37,7 +37,7 @@ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:19:6 | LL | /// [struct@char] - | ^^^^^^^^^^^ help: to link to the module, use its disambiguator: `mod@char` + | ^^^^^^^^^^^ help: to link to the module, prefix with `mod@`: `mod@char` | = note: this link resolved to a module, which is not a struct @@ -45,7 +45,7 @@ error: incompatible link kind for `char` --> $DIR/intra-link-prim-conflict.rs:26:10 | LL | //! [struct@char] - | ^^^^^^^^^^^ help: to link to the builtin type, use its disambiguator: `prim@char` + | ^^^^^^^^^^^ help: to link to the builtin type, prefix with `prim@`: `prim@char` | = note: this link resolved to a builtin type, which is not a struct diff --git a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr index 6b0ff8f116..d946aa9398 100644 --- a/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr +++ b/src/test/rustdoc-ui/intra-link-span-ice-55723.stderr @@ -2,7 +2,7 @@ error: unresolved link to `i` --> $DIR/intra-link-span-ice-55723.rs:9:10 | LL | /// (arr[i]) - | ^ unresolved link + | ^ the module `intra_link_span_ice_55723` contains no item named `i` | note: the lint level is defined here --> $DIR/intra-link-span-ice-55723.rs:1:9 diff --git a/src/test/rustdoc-ui/intra-links-ambiguity.stderr b/src/test/rustdoc-ui/intra-links-ambiguity.stderr index 35262c1b61..17891ca05e 100644 --- a/src/test/rustdoc-ui/intra-links-ambiguity.stderr +++ b/src/test/rustdoc-ui/intra-links-ambiguity.stderr @@ -9,7 +9,7 @@ note: the lint level is defined here | LL | #![deny(broken_intra_doc_links)] | ^^^^^^^^^^^^^^^^^^^^^^ -help: to link to the struct, prefix with the item type +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@ambiguous`] is ambiguous. | ^^^^^^^^^^^^^^^^^^ @@ -24,7 +24,7 @@ error: `ambiguous` is both a struct and a function LL | /// [ambiguous] is ambiguous. | ^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item type +help: to link to the struct, prefix with `struct@` | LL | /// [struct@ambiguous] is ambiguous. | ^^^^^^^^^^^^^^^^ @@ -39,7 +39,7 @@ error: `multi_conflict` is a struct, a function, and a macro LL | /// [`multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^ ambiguous link | -help: to link to the struct, prefix with the item type +help: to link to the struct, prefix with `struct@` | LL | /// [`struct@multi_conflict`] is a three-way conflict. | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -58,11 +58,11 @@ error: `type_and_value` is both a module and a constant LL | /// Ambiguous [type_and_value]. | ^^^^^^^^^^^^^^ ambiguous link | -help: to link to the module, prefix with the item type +help: to link to the module, prefix with `mod@` | -LL | /// Ambiguous [module@type_and_value]. - | ^^^^^^^^^^^^^^^^^^^^^ -help: to link to the constant, prefix with the item type +LL | /// Ambiguous [mod@type_and_value]. + | ^^^^^^^^^^^^^^^^^^ +help: to link to the constant, prefix with `const@` | LL | /// Ambiguous [const@type_and_value]. | ^^^^^^^^^^^^^^^^^^^^ @@ -73,7 +73,7 @@ error: `foo::bar` is both an enum and a function LL | /// Ambiguous non-implied shortcut link [`foo::bar`]. | ^^^^^^^^^^ ambiguous link | -help: to link to the enum, prefix with the item type +help: to link to the enum, prefix with `enum@` | LL | /// Ambiguous non-implied shortcut link [`enum@foo::bar`]. | ^^^^^^^^^^^^^^^ diff --git a/src/test/rustdoc-ui/intra-links-anchors.stderr b/src/test/rustdoc-ui/intra-links-anchors.stderr index e737b84320..1825a4ad1f 100644 --- a/src/test/rustdoc-ui/intra-links-anchors.stderr +++ b/src/test/rustdoc-ui/intra-links-anchors.stderr @@ -1,4 +1,4 @@ -error: `Foo::f#hola` contains an anchor, but links to struct fields are already anchored +error: `Foo::f#hola` contains an anchor, but links to fields are already anchored --> $DIR/intra-links-anchors.rs:25:15 | LL | /// Or maybe [Foo::f#hola]. @@ -16,13 +16,13 @@ error: `hello#people#!` contains multiple anchors LL | /// Another anchor error: [hello#people#!]. | ^^^^^^^^^^^^^^ contains invalid anchor -error: `Enum::A#whatever` contains an anchor, but links to enum variants are already anchored +error: `Enum::A#whatever` contains an anchor, but links to variants are already anchored --> $DIR/intra-links-anchors.rs:37:28 | LL | /// Damn enum's variants: [Enum::A#whatever]. | ^^^^^^^^^^^^^^^^ contains invalid anchor -error: `u32#hello` contains an anchor, but links to primitive types are already anchored +error: `u32#hello` contains an anchor, but links to builtin types are already anchored --> $DIR/intra-links-anchors.rs:43:6 | LL | /// [u32#hello] diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs index 1a7a2fce7a..b9c8e033b1 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.rs @@ -14,55 +14,55 @@ trait T {} /// Link to [struct@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [mod@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [union@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [trait@S] //~^ ERROR incompatible link kind for `S` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `enum@` /// Link to [struct@T] //~^ ERROR incompatible link kind for `T` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `trait@` /// Link to [derive@m] //~^ ERROR incompatible link kind for `m` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP add an exclamation mark /// Link to [const@s] //~^ ERROR incompatible link kind for `s` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `static@` /// Link to [static@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `const@` /// Link to [fn@c] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `const@` /// Link to [c()] //~^ ERROR incompatible link kind for `c` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP prefix with `const@` /// Link to [const@f] //~^ ERROR incompatible link kind for `f` //~| NOTE this link resolved -//~| HELP use its disambiguator +//~| HELP add parentheses pub fn f() {} diff --git a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr index 9edf838f9d..2e732baf6e 100644 --- a/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr +++ b/src/test/rustdoc-ui/intra-links-disambiguator-mismatch.stderr @@ -2,7 +2,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:14:14 | LL | /// Link to [struct@S] - | ^^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | note: the lint level is defined here --> $DIR/intra-links-disambiguator-mismatch.rs:1:9 @@ -15,7 +15,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:19:14 | LL | /// Link to [mod@S] - | ^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a module @@ -23,7 +23,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:24:14 | LL | /// Link to [union@S] - | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a union @@ -31,7 +31,7 @@ error: incompatible link kind for `S` --> $DIR/intra-links-disambiguator-mismatch.rs:29:14 | LL | /// Link to [trait@S] - | ^^^^^^^ help: to link to the enum, use its disambiguator: `enum@S` + | ^^^^^^^ help: to link to the enum, prefix with `enum@`: `enum@S` | = note: this link resolved to an enum, which is not a trait @@ -39,7 +39,7 @@ error: incompatible link kind for `T` --> $DIR/intra-links-disambiguator-mismatch.rs:34:14 | LL | /// Link to [struct@T] - | ^^^^^^^^ help: to link to the trait, use its disambiguator: `trait@T` + | ^^^^^^^^ help: to link to the trait, prefix with `trait@`: `trait@T` | = note: this link resolved to a trait, which is not a struct @@ -47,7 +47,7 @@ error: incompatible link kind for `m` --> $DIR/intra-links-disambiguator-mismatch.rs:39:14 | LL | /// Link to [derive@m] - | ^^^^^^^^ help: to link to the macro, use its disambiguator: `m!` + | ^^^^^^^^ help: to link to the macro, add an exclamation mark: `m!` | = note: this link resolved to a macro, which is not a derive macro @@ -55,7 +55,7 @@ error: incompatible link kind for `s` --> $DIR/intra-links-disambiguator-mismatch.rs:44:14 | LL | /// Link to [const@s] - | ^^^^^^^ help: to link to the static, use its disambiguator: `static@s` + | ^^^^^^^ help: to link to the static, prefix with `static@`: `static@s` | = note: this link resolved to a static, which is not a constant @@ -63,7 +63,7 @@ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:49:14 | LL | /// Link to [static@c] - | ^^^^^^^^ help: to link to the constant, use its disambiguator: `const@c` + | ^^^^^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a static @@ -71,7 +71,7 @@ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:54:14 | LL | /// Link to [fn@c] - | ^^^^ help: to link to the constant, use its disambiguator: `const@c` + | ^^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function @@ -79,7 +79,7 @@ error: incompatible link kind for `c` --> $DIR/intra-links-disambiguator-mismatch.rs:59:14 | LL | /// Link to [c()] - | ^^^ help: to link to the constant, use its disambiguator: `const@c` + | ^^^ help: to link to the constant, prefix with `const@`: `const@c` | = note: this link resolved to a constant, which is not a function @@ -87,7 +87,7 @@ error: incompatible link kind for `f` --> $DIR/intra-links-disambiguator-mismatch.rs:64:14 | LL | /// Link to [const@f] - | ^^^^^^^ help: to link to the function, use its disambiguator: `f()` + | ^^^^^^^ help: to link to the function, add parentheses: `f()` | = note: this link resolved to a function, which is not a constant diff --git a/src/test/rustdoc-ui/intra-links-private.private.stderr b/src/test/rustdoc-ui/intra-links-private.private.stderr index 77c4b67a65..eeef24b479 100644 --- a/src/test/rustdoc-ui/intra-links-private.private.stderr +++ b/src/test/rustdoc-ui/intra-links-private.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/intra-links-private.public.stderr b/src/test/rustdoc-ui/intra-links-private.public.stderr index 312a78e8c3..3f7b17586f 100644 --- a/src/test/rustdoc-ui/intra-links-private.public.stderr +++ b/src/test/rustdoc-ui/intra-links-private.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `DocMe` links to private item `DontDocMe` LL | /// docs [DontDocMe] | ^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr index 1e3a26fadf..76a2ac0c8c 100644 --- a/src/test/rustdoc-ui/intra-links-warning-crlf.stderr +++ b/src/test/rustdoc-ui/intra-links-warning-crlf.stderr @@ -2,7 +2,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:7:6 | LL | /// [error] - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error` | = note: `#[warn(broken_intra_doc_links)]` on by default = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -11,7 +11,7 @@ warning: unresolved link to `error1` --> $DIR/intra-links-warning-crlf.rs:12:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error1` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -19,7 +19,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning-crlf.rs:15:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning_crlf` contains no item named `error2` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -27,7 +27,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning-crlf.rs:23:20 | LL | * It also has an [error]. - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning_crlf` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` diff --git a/src/test/rustdoc-ui/intra-links-warning.stderr b/src/test/rustdoc-ui/intra-links-warning.stderr index 53f2476295..09db465df5 100644 --- a/src/test/rustdoc-ui/intra-links-warning.stderr +++ b/src/test/rustdoc-ui/intra-links-warning.stderr @@ -2,56 +2,45 @@ warning: unresolved link to `Foo::baz` --> $DIR/intra-links-warning.rs:3:23 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link + | ^^^^^^^^ the struct `Foo` has no field or associated item named `baz` | = note: `#[warn(broken_intra_doc_links)]` on by default - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `Bar::foo` --> $DIR/intra-links-warning.rs:3:35 | LL | //! Test with [Foo::baz], [Bar::foo], ... - | ^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^ the module `intra_links_warning` contains no item named `Bar` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:6:13 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:6:30 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^ the module `intra_links_warning` contains no item named `Qux` warning: unresolved link to `Uniooon::X` --> $DIR/intra-links-warning.rs:10:14 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^^^^^ the module `intra_links_warning` contains no item named `Uniooon` warning: unresolved link to `Qux::Z` --> $DIR/intra-links-warning.rs:10:31 | LL | //! , [Uniooon::X] and [Qux::Z]. - | ^^^^^^ unresolved link - | - = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` + | ^^^^^^ the module `intra_links_warning` contains no item named `Qux` warning: unresolved link to `Qux:Y` --> $DIR/intra-links-warning.rs:14:13 | LL | /// [Qux:Y] - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning` contains no item named `Qux:Y` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -59,7 +48,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:58:30 | LL | * time to introduce a link [error]*/ - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -67,7 +56,7 @@ warning: unresolved link to `error` --> $DIR/intra-links-warning.rs:64:30 | LL | * time to introduce a link [error] - | ^^^^^ unresolved link + | ^^^^^ the module `intra_links_warning` contains no item named `error` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -81,6 +70,7 @@ LL | #[doc = "single line [error]"] single line [error] ^^^^^ + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -93,6 +83,7 @@ LL | #[doc = "single line with \"escaping\" [error]"] single line with "escaping" [error] ^^^^^ + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error` @@ -107,13 +98,14 @@ LL | | /// [error] [error] ^^^^^ + = note: the module `intra_links_warning` contains no item named `error` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `error1` --> $DIR/intra-links-warning.rs:80:11 | LL | /// docs [error1] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning` contains no item named `error1` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -121,7 +113,7 @@ warning: unresolved link to `error2` --> $DIR/intra-links-warning.rs:82:11 | LL | /// docs [error2] - | ^^^^^^ unresolved link + | ^^^^^^ the module `intra_links_warning` contains no item named `error2` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -129,7 +121,7 @@ warning: unresolved link to `BarA` --> $DIR/intra-links-warning.rs:21:10 | LL | /// bar [BarA] bar - | ^^^^ unresolved link + | ^^^^ the module `intra_links_warning` contains no item named `BarA` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -137,7 +129,7 @@ warning: unresolved link to `BarB` --> $DIR/intra-links-warning.rs:27:9 | LL | * bar [BarB] bar - | ^^^^ unresolved link + | ^^^^ the module `intra_links_warning` contains no item named `BarB` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -145,7 +137,7 @@ warning: unresolved link to `BarC` --> $DIR/intra-links-warning.rs:34:6 | LL | bar [BarC] bar - | ^^^^ unresolved link + | ^^^^ the module `intra_links_warning` contains no item named `BarC` | = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` @@ -159,6 +151,7 @@ LL | #[doc = "Foo\nbar [BarD] bar\nbaz"] bar [BarD] bar ^^^^ + = note: the module `intra_links_warning` contains no item named `BarD` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` warning: unresolved link to `BarF` @@ -174,6 +167,7 @@ LL | f!("Foo\nbar [BarF] bar\nbaz"); bar [BarF] bar ^^^^ + = note: the module `intra_links_warning` contains no item named `BarF` = help: to escape `[` and `]` characters, add '\' before them like `\[` or `\]` = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/rustdoc-ui/issue-74134.private.stderr b/src/test/rustdoc-ui/issue-74134.private.stderr index 5877210914..b802d7e125 100644 --- a/src/test/rustdoc-ui/issue-74134.private.stderr +++ b/src/test/rustdoc-ui/issue-74134.private.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link resolves only because you passed `--document-private-items`, but will break without warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/issue-74134.public.stderr b/src/test/rustdoc-ui/issue-74134.public.stderr index b5bea19094..40aa2ece1a 100644 --- a/src/test/rustdoc-ui/issue-74134.public.stderr +++ b/src/test/rustdoc-ui/issue-74134.public.stderr @@ -4,7 +4,7 @@ warning: public documentation for `public_item` links to private item `PrivateTy LL | /// [`PrivateType`] | ^^^^^^^^^^^^^ this item is private | - = note: `#[warn(broken_intra_doc_links)]` on by default + = note: `#[warn(private_intra_doc_links)]` on by default = note: this link will resolve properly if you pass `--document-private-items` warning: 1 warning emitted diff --git a/src/test/rustdoc-ui/lint-group.stderr b/src/test/rustdoc-ui/lint-group.stderr index 04296d2e44..4e9134ea46 100644 --- a/src/test/rustdoc-ui/lint-group.stderr +++ b/src/test/rustdoc-ui/lint-group.stderr @@ -32,7 +32,7 @@ error: unresolved link to `error` --> $DIR/lint-group.rs:9:29 | LL | /// what up, let's make an [error] - | ^^^^^ unresolved link + | ^^^^^ the module `lint_group` contains no item named `error` | note: the lint level is defined here --> $DIR/lint-group.rs:7:9 diff --git a/src/test/rustdoc-ui/private-doc-test.rs b/src/test/rustdoc-ui/private-doc-test.rs new file mode 100644 index 0000000000..379fa45f9f --- /dev/null +++ b/src/test/rustdoc-ui/private-doc-test.rs @@ -0,0 +1,12 @@ +// check-pass + +#![deny(private_doc_tests)] + +mod foo { + /// private doc test + /// + /// ```ignore (used for testing ignored doc tests) + /// assert!(false); + /// ``` + fn bar() {} +} diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.rs b/src/test/rustdoc-ui/unknown-renamed-lints.rs new file mode 100644 index 0000000000..7faa82ea42 --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.rs @@ -0,0 +1,8 @@ +#![deny(unknown_lints)] +//~^ NOTE lint level is defined +#![deny(renamed_and_removed_lints)] +//~^ NOTE lint level is defined +#![deny(x)] +//~^ ERROR unknown lint +#![deny(intra_doc_link_resolution_failure)] +//~^ ERROR lint `intra_doc_link_resolution_failure` has been renamed diff --git a/src/test/rustdoc-ui/unknown-renamed-lints.stderr b/src/test/rustdoc-ui/unknown-renamed-lints.stderr new file mode 100644 index 0000000000..f0917f194b --- /dev/null +++ b/src/test/rustdoc-ui/unknown-renamed-lints.stderr @@ -0,0 +1,28 @@ +error: unknown lint: `x` + --> $DIR/unknown-renamed-lints.rs:5:9 + | +LL | #![deny(x)] + | ^ + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:1:9 + | +LL | #![deny(unknown_lints)] + | ^^^^^^^^^^^^^ + +error: lint `intra_doc_link_resolution_failure` has been renamed to `broken_intra_doc_links` + --> $DIR/unknown-renamed-lints.rs:7:9 + | +LL | #![deny(intra_doc_link_resolution_failure)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use the new name: `broken_intra_doc_links` + | +note: the lint level is defined here + --> $DIR/unknown-renamed-lints.rs:3:9 + | +LL | #![deny(renamed_and_removed_lints)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: Compilation failed, aborting rustdoc + +error: aborting due to 3 previous errors + diff --git a/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs b/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs new file mode 100644 index 0000000000..a37848e23d --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-cross-crate-crate.rs @@ -0,0 +1,5 @@ +#![crate_name = "inner"] + +/// Links to [crate::g] +pub fn f() {} +pub fn g() {} diff --git a/src/test/rustdoc/auxiliary/intra-link-pub-use.rs b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs new file mode 100644 index 0000000000..a4db2ffc44 --- /dev/null +++ b/src/test/rustdoc/auxiliary/intra-link-pub-use.rs @@ -0,0 +1,4 @@ +#![crate_name = "inner"] + +/// Documentation, including a link to [std::ptr] +pub fn f() {} diff --git a/src/test/rustdoc/bad-codeblock-syntax.rs b/src/test/rustdoc/bad-codeblock-syntax.rs index afef86ec9c..920877028d 100644 --- a/src/test/rustdoc/bad-codeblock-syntax.rs +++ b/src/test/rustdoc/bad-codeblock-syntax.rs @@ -1,33 +1,33 @@ // @has bad_codeblock_syntax/fn.foo.html -// @has - '//*[@class="docblock"]/pre/code' '\_' +// @has - '//*[@class="docblock"]' '\_' /// ``` /// \_ /// ``` pub fn foo() {} // @has bad_codeblock_syntax/fn.bar.html -// @has - '//*[@class="docblock"]/pre/code' '`baz::foobar`' +// @has - '//*[@class="docblock"]' '`baz::foobar`' /// ``` /// `baz::foobar` /// ``` pub fn bar() {} // @has bad_codeblock_syntax/fn.quux.html -// @has - '//*[@class="docblock"]/pre/code' '\_' +// @has - '//*[@class="docblock"]' '\_' /// ```rust /// \_ /// ``` pub fn quux() {} // @has bad_codeblock_syntax/fn.ok.html -// @has - '//*[@class="docblock"]/pre/code[@class="language-text"]' '\_' +// @has - '//*[@class="docblock"]' '\_' /// ```text /// \_ /// ``` pub fn ok() {} // @has bad_codeblock_syntax/fn.escape.html -// @has - '//*[@class="docblock"]/pre/code' '\_ ' +// @has - '//*[@class="docblock"]' '\_ ' /// ``` /// \_ /// @@ -35,7 +35,7 @@ pub fn ok() {} pub fn escape() {} // @has bad_codeblock_syntax/fn.unterminated.html -// @has - '//*[@class="docblock"]/pre/code' '"unterminated' +// @has - '//*[@class="docblock"]' '"unterminated' /// ``` /// "unterminated /// ``` diff --git a/src/test/rustdoc/const-display.rs b/src/test/rustdoc/const-display.rs index c5016c650e..b3fbe377f0 100644 --- a/src/test/rustdoc/const-display.rs +++ b/src/test/rustdoc/const-display.rs @@ -12,7 +12,7 @@ #[rustc_const_unstable(feature="foo", issue = "none")] pub const unsafe fn foo() -> u32 { 42 } -// @has 'foo/fn.foo2.html' '//pre' 'pub fn foo2() -> u32' +// @has 'foo/fn.foo2.html' '//pre' 'pub const fn foo2() -> u32' #[unstable(feature = "humans", issue = "none")] pub const fn foo2() -> u32 { 42 } @@ -21,7 +21,7 @@ pub const fn foo2() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn bar2() -> u32 { 42 } -// @has 'foo/fn.foo2_gated.html' '//pre' 'pub unsafe fn foo2_gated() -> u32' +// @has 'foo/fn.foo2_gated.html' '//pre' 'pub const unsafe fn foo2_gated() -> u32' #[unstable(feature = "foo2", issue = "none")] pub const unsafe fn foo2_gated() -> u32 { 42 } @@ -30,7 +30,7 @@ pub const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const unsafe fn bar2_gated() -> u32 { 42 } -// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub unsafe fn bar_not_gated() -> u32' +// @has 'foo/fn.bar_not_gated.html' '//pre' 'pub const unsafe fn bar_not_gated() -> u32' pub const unsafe fn bar_not_gated() -> u32 { 42 } pub struct Foo; diff --git a/src/test/rustdoc/const-generics/type-alias.rs b/src/test/rustdoc/const-generics/type-alias.rs new file mode 100644 index 0000000000..3064d0701e --- /dev/null +++ b/src/test/rustdoc/const-generics/type-alias.rs @@ -0,0 +1,6 @@ +// ignore-tidy-linelength +#![feature(min_const_generics)] +#![crate_name = "foo"] + +// @has foo/type.CellIndex.html '//pre[@class="rust typedef"]' 'type CellIndex = [i64; D];' +pub type CellIndex = [i64; D]; diff --git a/src/test/rustdoc/duplicate-cfg.rs b/src/test/rustdoc/duplicate-cfg.rs index 9ccc5d7882..47ba362c97 100644 --- a/src/test/rustdoc/duplicate-cfg.rs +++ b/src/test/rustdoc/duplicate-cfg.rs @@ -3,22 +3,34 @@ #![crate_name = "foo"] #![feature(doc_cfg)] +// @has 'foo/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only' + // @has 'foo/struct.Foo.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.' +// @has '-' '//*[@class="stab portability"]' 'sync' #[doc(cfg(feature = "sync"))] #[doc(cfg(feature = "sync"))] pub struct Foo; +// @has 'foo/bar/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` only' + // @has 'foo/bar/struct.Bar.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync only.' #[doc(cfg(feature = "sync"))] pub mod bar { #[doc(cfg(feature = "sync"))] pub struct Bar; } +// @has 'foo/baz/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate features `sync` and `send` only' + // @has 'foo/baz/struct.Baz.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(all(feature = "sync", feature = "send")))] pub mod baz { #[doc(cfg(feature = "sync"))] @@ -26,15 +38,19 @@ pub mod baz { } // @has 'foo/qux/struct.Qux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate features sync and send only.' #[doc(cfg(feature = "sync"))] pub mod qux { #[doc(cfg(all(feature = "sync", feature = "send")))] pub struct Qux; } +// @has 'foo/quux/index.html' +// @matches '-' '//*[@class="module-item"]//*[@class="stab portability"]' '^sync and send and foo and bar$' +// @has '-' '//*[@class="module-item"]//*[@class="stab portability"]/@title' 'This is supported on crate feature `sync` and crate feature `send` and `foo` and `bar` only' + // @has 'foo/quux/struct.Quux.html' -// @has '-' '//*[@class="stab portability"]' 'This is supported on feature="sync" and feature="send" and foo and bar only.' +// @has '-' '//*[@class="stab portability"]' 'This is supported on crate feature sync and crate feature send and foo and bar only.' #[doc(cfg(all(feature = "sync", feature = "send", foo)))] pub mod quux { #[doc(cfg(all(feature = "send", feature = "sync", bar)))] diff --git a/src/test/rustdoc/index-page.rs b/src/test/rustdoc/index-page.rs index f0476f083b..be668a1276 100644 --- a/src/test/rustdoc/index-page.rs +++ b/src/test/rustdoc/index-page.rs @@ -6,6 +6,6 @@ // @has foo/../index.html // @has - '//span[@class="in-band"]' 'List of all crates' -// @has - '//ul[@class="mod"]//a[@href="foo/index.html"]' 'foo' -// @has - '//ul[@class="mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' +// @has - '//ul[@class="crate mod"]//a[@href="foo/index.html"]' 'foo' +// @has - '//ul[@class="crate mod"]//a[@href="all_item_types/index.html"]' 'all_item_types' pub struct Foo; diff --git a/src/test/rustdoc/intra-doc-crate/traits.rs b/src/test/rustdoc/intra-doc-crate/traits.rs index 07f9fb6331..07decb4801 100644 --- a/src/test/rustdoc/intra-doc-crate/traits.rs +++ b/src/test/rustdoc/intra-doc-crate/traits.rs @@ -1,5 +1,3 @@ -// ignore-test -// ^ this is https://github.com/rust-lang/rust/issues/73829 // aux-build:traits.rs // build-aux-docs // ignore-tidy-line-length diff --git a/src/test/rustdoc/intra-doc-link-private.rs b/src/test/rustdoc/intra-doc-link-private.rs new file mode 100644 index 0000000000..f86ca44403 --- /dev/null +++ b/src/test/rustdoc/intra-doc-link-private.rs @@ -0,0 +1,6 @@ +#![crate_name = "private"] +// compile-flags: --document-private-items +/// docs [DontDocMe] +// @has private/struct.DocMe.html '//*a[@href="../private/struct.DontDocMe.html"]' 'DontDocMe' +pub struct DocMe; +struct DontDocMe; diff --git a/src/test/rustdoc/intra-link-associated-items.rs b/src/test/rustdoc/intra-link-associated-items.rs index 16a21e3374..daf7075a91 100644 --- a/src/test/rustdoc/intra-link-associated-items.rs +++ b/src/test/rustdoc/intra-link-associated-items.rs @@ -3,8 +3,10 @@ /// [`std::collections::BTreeMap::into_iter`] /// [`String::from`] is ambiguous as to which `From` impl +/// [Vec::into_iter()] uses a disambiguator // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/collections/btree/map/struct.BTreeMap.html#method.into_iter"]' 'std::collections::BTreeMap::into_iter' // @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/string/struct.String.html#method.from"]' 'String::from' +// @has 'intra_link_associated_items/fn.foo.html' '//a[@href="https://doc.rust-lang.org/nightly/alloc/vec/struct.Vec.html#method.into_iter"]' 'Vec::into_iter' pub fn foo() {} /// Link to [MyStruct], [link from struct][MyStruct::method], [MyStruct::clone], [MyStruct::Input] diff --git a/src/test/rustdoc/intra-link-cross-crate-crate.rs b/src/test/rustdoc/intra-link-cross-crate-crate.rs new file mode 100644 index 0000000000..edf544708b --- /dev/null +++ b/src/test/rustdoc/intra-link-cross-crate-crate.rs @@ -0,0 +1,6 @@ +// aux-build:intra-link-cross-crate-crate.rs +// build-aux-docs +#![crate_name = "outer"] +extern crate inner; +// @has outer/fn.f.html '//a[@href="../inner/fn.g.html"]' "crate::g" +pub use inner::f; diff --git a/src/test/rustdoc/intra-link-disambiguators-removed.rs b/src/test/rustdoc/intra-link-disambiguators-removed.rs new file mode 100644 index 0000000000..26d05b484b --- /dev/null +++ b/src/test/rustdoc/intra-link-disambiguators-removed.rs @@ -0,0 +1,51 @@ +// ignore-tidy-linelength +#![deny(intra_doc_link_resolution_failure)] +// first try backticks +/// Trait: [`trait@Name`], fn: [`fn@Name`], [`Name`][`macro@Name`] +// @has intra_link_disambiguators_removed/struct.AtDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name" +pub struct AtDisambiguator; + +/// fn: [`Name()`], macro: [`Name!`] +// @has intra_link_disambiguators_removed/struct.SymbolDisambiguator.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name()" +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"][code]' "Name!" +pub struct SymbolDisambiguator; + +// Now make sure that backticks aren't added if they weren't already there +/// [fn@Name] +// @has intra_link_disambiguators_removed/trait.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "Name" +// @!has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"][code]' "Name" + +// FIXME: this will turn !() into ! alone +/// [Name!()] +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name!" +pub trait Name {} + +#[allow(non_snake_case)] + +// Try collapsed reference links +/// [macro@Name][] +// @has intra_link_disambiguators_removed/fn.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/macro.Name.html"]' "Name" + +// Try links that have the same text as a generated URL +/// Weird URL aligned [../intra_link_disambiguators_removed/macro.Name.html][trait@Name] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "../intra_link_disambiguators_removed/macro.Name.html" +pub fn Name() {} + +#[macro_export] +// Rustdoc doesn't currently handle links that have weird interspersing of inline code blocks. +/// [fn@Na`m`e] +// @has intra_link_disambiguators_removed/macro.Name.html +// @has - '//a[@href="../intra_link_disambiguators_removed/fn.Name.html"]' "fn@Name" + +// It also doesn't handle any case where the code block isn't the whole link text: +/// [trait@`Name`] +// @has - '//a[@href="../intra_link_disambiguators_removed/trait.Name.html"]' "trait@Name" +macro_rules! Name { + () => () +} diff --git a/src/test/rustdoc/intra-link-prim-assoc.rs b/src/test/rustdoc/intra-link-prim-assoc.rs new file mode 100644 index 0000000000..c0066885e1 --- /dev/null +++ b/src/test/rustdoc/intra-link-prim-assoc.rs @@ -0,0 +1,5 @@ +// ignore-tidy-linelength +#![deny(broken_intra_doc_links)] + +//! [i32::MAX] +// @has intra_link_prim_assoc/index.html '//a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' "i32::MAX" diff --git a/src/test/rustdoc/intra-link-pub-use.rs b/src/test/rustdoc/intra-link-pub-use.rs new file mode 100644 index 0000000000..dd52249abc --- /dev/null +++ b/src/test/rustdoc/intra-link-pub-use.rs @@ -0,0 +1,27 @@ +// aux-build: intra-link-pub-use.rs +#![deny(broken_intra_doc_links)] +#![crate_name = "outer"] + +extern crate inner; + +/// [mod@std::env] [g] + +// FIXME: This can't be tested because rustdoc doesn't show documentation on pub re-exports. +// Until then, comment out the `htmldocck` test. +// This test still does something; namely check that no incorrect errors are emitted when +// documenting the re-export. + +// @has outer/index.html +// @ has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/fn.var.html"]' "std::env" +// @ has - '//a[@href="../outer/fn.f.html"]' "g" +pub use f as g; + +// FIXME: same as above +/// [std::env] +extern crate self as _; + +// Make sure the documentation is actually correct by documenting an inlined re-export +/// [mod@std::env] +// @has outer/fn.f.html +// @has - '//a[@href="https://doc.rust-lang.org/nightly/std/env/index.html"]' "std::env" +pub use inner::f; diff --git a/src/test/rustdoc/issue-76501.rs b/src/test/rustdoc/issue-76501.rs new file mode 100644 index 0000000000..605059fe0d --- /dev/null +++ b/src/test/rustdoc/issue-76501.rs @@ -0,0 +1,18 @@ +#![feature(const_fn)] + +// @has 'issue_76501/fn.bloop.html' '//pre' 'pub const fn bloop() -> i32' +/// A useless function that always returns 1. +pub const fn bloop() -> i32 { + 1 +} + +/// A struct. +pub struct Struct {} + +impl Struct { + // @has 'issue_76501/struct.Struct.html' '//*[@class="method"]' 'pub const fn blurp() -> i32' + /// A useless function that always returns 1. + pub const fn blurp() -> i32 { + 1 + } +} diff --git a/src/test/rustdoc/plain-text-summaries.rs b/src/test/rustdoc/plain-text-summaries.rs new file mode 100644 index 0000000000..c995ccbf0a --- /dev/null +++ b/src/test/rustdoc/plain-text-summaries.rs @@ -0,0 +1,26 @@ +#![crate_type = "lib"] +#![crate_name = "summaries"] + +//! This summary has a [link] and `code`. +//! +//! This is the second paragraph. +//! +//! [link]: https://example.com + +// @has search-index.js 'This summary has a link and `code`.' +// @!has - 'second paragraph' + +/// This `code` should be in backticks. +/// +/// This text should not be rendered. +pub struct Sidebar; + +// @has summaries/sidebar-items.js 'This `code` should be in backticks.' +// @!has - 'text should not be rendered' + +/// ```text +/// this block should not be rendered +/// ``` +pub struct Sidebar2; + +// @!has summaries/sidebar-items.js 'block should not be rendered' diff --git a/src/test/rustdoc/primitive-link.rs b/src/test/rustdoc/primitive-link.rs index 819ef05174..8f69b894a2 100644 --- a/src/test/rustdoc/primitive-link.rs +++ b/src/test/rustdoc/primitive-link.rs @@ -4,6 +4,13 @@ // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.u32.html"]' 'u32' // @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i64.html"]' 'i64' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html"]' 'std::primitive::i32' +// @has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.str.html"]' 'std::primitive::str' + +// FIXME: this doesn't resolve +// @ has foo/struct.Foo.html '//*[@class="docblock"]/p/a[@href="https://doc.rust-lang.org/nightly/std/primitive.i32.html#associatedconstant.MAX"]' 'std::primitive::i32::MAX' /// It contains [`u32`] and [i64]. +/// It also links to [std::primitive::i32], [std::primitive::str], +/// and [`std::primitive::i32::MAX`]. pub struct Foo; diff --git a/src/test/rustdoc/trait-impl.rs b/src/test/rustdoc/trait-impl.rs new file mode 100644 index 0000000000..3bcaa3bb67 --- /dev/null +++ b/src/test/rustdoc/trait-impl.rs @@ -0,0 +1,46 @@ +pub trait Trait { + /// Some long docs here. + /// + /// These docs are long enough that a link will be added to the end. + fn a(); + + /// These docs contain a [reference link]. + /// + /// [reference link]: https://example.com + fn b(); + + /// ``` + /// This code block should not be in the output, but a Read more link should be generated + /// ``` + fn c(); + + /// Escaped formatting a\*b\*c\* works + fn d(); +} + +pub struct Struct; + +impl Trait for Struct { + // @has trait_impl/struct.Struct.html '//*[@id="method.a"]/../div/p' 'Some long docs' + // @!has - '//*[@id="method.a"]/../div/p' 'link will be added' + // @has - '//*[@id="method.a"]/../div/p/a' 'Read more' + // @has - '//*[@id="method.a"]/../div/p/a/@href' 'trait.Trait.html' + fn a() {} + + // @has trait_impl/struct.Struct.html '//*[@id="method.b"]/../div/p' 'These docs contain' + // @has - '//*[@id="method.b"]/../div/p/a' 'reference link' + // @has - '//*[@id="method.b"]/../div/p/a/@href' 'https://example.com' + // @has - '//*[@id="method.b"]/../div/p/a' 'Read more' + // @has - '//*[@id="method.b"]/../div/p/a/@href' 'trait.Trait.html' + fn b() {} + + // @!has trait_impl/struct.Struct.html '//*[@id="method.c"]/../div/p' 'code block' + // @has - '//*[@id="method.c"]/../div/p/a' 'Read more' + // @has - '//*[@id="method.c"]/../div/p/a/@href' 'trait.Trait.html' + fn c() {} + + // @has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p' \ + // 'Escaped formatting a*b*c* works' + // @!has trait_impl/struct.Struct.html '//*[@id="method.d"]/../div/p/em' + fn d() {} +} diff --git a/src/test/ui-fulldeps/auxiliary/proc-macro-panic.rs b/src/test/ui-fulldeps/auxiliary/proc-macro-panic.rs new file mode 100644 index 0000000000..fc15bb9c59 --- /dev/null +++ b/src/test/ui-fulldeps/auxiliary/proc-macro-panic.rs @@ -0,0 +1,13 @@ +// force-host +// no-prefer-dynamic + +#![crate_type = "proc-macro"] + +extern crate proc_macro; +use proc_macro::{TokenStream, Ident, Span}; + +#[proc_macro] +pub fn panic_in_libproc_macro(_: TokenStream) -> TokenStream { + Ident::new("", Span::call_site()); + TokenStream::new() +} diff --git a/src/test/ui-fulldeps/compiler-calls.rs b/src/test/ui-fulldeps/compiler-calls.rs index e97dcab6ae..0025b47403 100644 --- a/src/test/ui-fulldeps/compiler-calls.rs +++ b/src/test/ui-fulldeps/compiler-calls.rs @@ -26,7 +26,13 @@ fn main() { let mut count = 1; let args = vec!["compiler-calls".to_string(), "foo.rs".to_string()]; rustc_driver::catch_fatal_errors(|| { - rustc_driver::run_compiler(&args, &mut TestCalls { count: &mut count }, None, None).ok(); + rustc_driver::run_compiler( + &args, + &mut TestCalls { count: &mut count }, + None, + None, + None, + ).ok(); }).ok(); assert_eq!(count, 2); } diff --git a/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr index 98c1a22bd1..4299688221 100644 --- a/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr +++ b/src/test/ui-fulldeps/dropck-tarena-cycle-checked.stderr @@ -7,7 +7,7 @@ LL | } | - | | | `arena` dropped here while still borrowed - | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `rustc_arena::TypedArena` + | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `TypedArena` error: aborting due to previous error diff --git a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr index 22c7487e8f..ccffee9cdb 100644 --- a/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr +++ b/src/test/ui-fulldeps/dropck-tarena-unsound-drop.stderr @@ -7,7 +7,7 @@ LL | } | - | | | `arena` dropped here while still borrowed - | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `rustc_arena::TypedArena` + | borrow might be used here, when `arena` is dropped and runs the `Drop` code for type `TypedArena` error: aborting due to previous error diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs new file mode 100644 index 0000000000..f58446d559 --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.rs @@ -0,0 +1,33 @@ +// NOTE: This test doesn't actually require `fulldeps` +// so we could instead use it as an `ui` test. +// +// Considering that all other `internal-lints` are tested here +// this seems like the cleaner solution though. +#![feature(rustc_attrs)] +#![deny(rustc::ty_pass_by_reference)] +#![allow(unused)] + +#[rustc_diagnostic_item = "TyCtxt"] +struct TyCtxt<'tcx> { + inner: &'tcx (), +} + +impl<'tcx> TyCtxt<'tcx> { + fn by_value(self) {} // OK + fn by_ref(&self) {} //~ ERROR passing `TyCtxt<'tcx>` by reference +} + + +struct TyS<'tcx> { + inner: &'tcx (), +} + +#[rustc_diagnostic_item = "Ty"] +type Ty<'tcx> = &'tcx TyS<'tcx>; + +impl<'tcx> TyS<'tcx> { + fn by_value(self: Ty<'tcx>) {} + fn by_ref(self: &Ty<'tcx>) {} //~ ERROR passing `Ty<'tcx>` by reference +} + +fn main() {} diff --git a/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr new file mode 100644 index 0000000000..b846b30f4e --- /dev/null +++ b/src/test/ui-fulldeps/internal-lints/pass_ty_by_ref_self.stderr @@ -0,0 +1,20 @@ +error: passing `TyCtxt<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:17:15 + | +LL | fn by_ref(&self) {} + | ^^^^^ help: try passing by value: `TyCtxt<'tcx>` + | +note: the lint level is defined here + --> $DIR/pass_ty_by_ref_self.rs:7:9 + | +LL | #![deny(rustc::ty_pass_by_reference)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: passing `Ty<'tcx>` by reference + --> $DIR/pass_ty_by_ref_self.rs:30:21 + | +LL | fn by_ref(self: &Ty<'tcx>) {} + | ^^^^^^^^^ help: try passing by value: `Ty<'tcx>` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.rs b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.rs new file mode 100644 index 0000000000..981abb4e2c --- /dev/null +++ b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.rs @@ -0,0 +1,17 @@ +// aux-build:proc-macro-panic.rs +// edition:2018 +// ignore-stage1 +// only-linux +// +// FIXME: This should be a normal (stage1, all platforms) test in +// src/test/ui/proc-macro once issue #59998 is fixed. + +// Regression test for issue #76270 +// Tests that we don't print an ICE message when a panic +// occurs in libproc-macro (when `-Z proc-macro-backtrace` is not specified) + +extern crate proc_macro_panic; + +proc_macro_panic::panic_in_libproc_macro!(); //~ ERROR proc macro panicked + +fn main() {} diff --git a/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr new file mode 100644 index 0000000000..e472242ce4 --- /dev/null +++ b/src/test/ui-fulldeps/issue-76270-panic-in-libproc-macro.stderr @@ -0,0 +1,10 @@ +error: proc macro panicked + --> $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 + +error: aborting due to previous error + diff --git a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs index 633d153e39..caf55bec53 100644 --- a/src/test/ui-fulldeps/pprust-expr-roundtrip.rs +++ b/src/test/ui-fulldeps/pprust-expr-roundtrip.rs @@ -62,7 +62,7 @@ fn expr(kind: ExprKind) -> P { fn make_x() -> P { let seg = PathSegment::from_ident(Ident::from_str("x")); - let path = Path { segments: vec![seg], span: DUMMY_SP }; + let path = Path { segments: vec![seg], span: DUMMY_SP, tokens: None }; expr(ExprKind::Path(None, path)) } @@ -113,6 +113,7 @@ fn iter_exprs(depth: usize, f: &mut dyn FnMut(P)) { id: DUMMY_NODE_ID, rules: BlockCheckMode::Default, span: DUMMY_SP, + tokens: None, }); iter_exprs(depth - 1, &mut |e| g(ExprKind::If(e, block.clone(), None))); }, diff --git a/src/test/ui-fulldeps/session-derive-errors.rs b/src/test/ui-fulldeps/session-derive-errors.rs new file mode 100644 index 0000000000..7967b32a4a --- /dev/null +++ b/src/test/ui-fulldeps/session-derive-errors.rs @@ -0,0 +1,260 @@ +// check-fail +// Tests error conditions for specifying diagnostics using #[derive(SessionDiagnostic)] + +#![feature(rustc_private)] +#![crate_type = "lib"] + +extern crate rustc_span; +use rustc_span::Span; +use rustc_span::symbol::Ident; + +extern crate rustc_macros; +use rustc_macros::SessionDiagnostic; + +extern crate rustc_middle; +use rustc_middle::ty::Ty; + +extern crate rustc_errors; +use rustc_errors::Applicability; + +extern crate rustc_session; + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +struct Hello {} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +//~^ ERROR `#[derive(SessionDiagnostic)]` can only be used on structs +enum SessionDiagnosticOnEnum { + Foo, + Bar, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[label = "This is in the wrong place"] +//~^ ERROR `#[label = ...]` is not a valid SessionDiagnostic struct attribute +struct WrongPlace {} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct WrongPlaceField { + #[suggestion = "this is the wrong kind of attribute"] +//~^ ERROR `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute + sp: Span, +} + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +#[error = "E0456"] //~ ERROR `error` specified multiple times +struct ErrorSpecifiedTwice {} + +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[error = "E0123"] +#[lint = "some_useful_lint"] //~ ERROR `lint` specified when `error` was already specified +struct LintSpecifiedAfterError {} + +#[derive(SessionDiagnostic)] +#[message = "Some lint message"] +#[error = "E0123"] +struct LintButHasErrorCode {} + +#[derive(SessionDiagnostic)] +struct ErrorCodeNotProvided {} //~ ERROR `code` not specified + +// FIXME: Uncomment when emitting lints is supported. +/* +#[derive(SessionDiagnostic)] +#[message = "Hello, world!"] +#[lint = "clashing_extern_declarations"] +#[lint = "improper_ctypes"] // FIXME: ERROR `lint` specified multiple times +struct LintSpecifiedTwice {} + +#[derive(SessionDiagnostic)] +#[lint = "Some lint message"] +#[message = "Some error message"] +#[error = "E0123"] // ERROR `error` specified when `lint` was already specified +struct ErrorSpecifiedAfterLint {} +*/ + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithField { + name: String, + #[message = "This error has a field, and references {name}"] + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithMessageAppliedToField { + #[message = "this message is applied to a String field"] + //~^ ERROR the `#[message = "..."]` attribute can only be applied to fields of type Span + name: String, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This error has a field, and references {name}"] +//~^ ERROR `name` doesn't refer to a field on this type +struct ErrorWithNonexistentField { + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This is missing a closing brace: {name"] +//~^ ERROR invalid format string: expected `'}'` +struct ErrorMissingClosingBrace { + name: String, + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "This is missing an opening brace: name}"] +//~^ ERROR invalid format string: unmatched `}` +struct ErrorMissingOpeningBrace { + name: String, + span: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something"] +struct LabelOnSpan { + #[label = "See here"] + sp: Span +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something"] +struct LabelOnNonSpan { + #[label = "See here"] + //~^ ERROR The `#[label = ...]` attribute can only be applied to fields of type Span + id: u32, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct Suggest { + #[suggestion(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_short(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_hidden(message = "This is a suggestion", code = "This is the suggested code")] + #[suggestion_verbose(message = "This is a suggestion", code = "This is the suggested code")] + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithoutCode { + #[suggestion(message = "This is a suggestion")] + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithBadKey { + #[suggestion(nonsense = "This is nonsense")] + //~^ ERROR `nonsense` is not a valid key for `#[suggestion(...)]` + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithShorthandMsg { + #[suggestion(msg = "This is a suggestion")] + //~^ ERROR `msg` is not a valid key for `#[suggestion(...)]` + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithoutMsg { + #[suggestion(code = "This is suggested code")] + //~^ ERROR missing suggestion message + suggestion: (Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithTypesSwapped { + #[suggestion(message = "This is a message", code = "This is suggested code")] + suggestion: (Applicability, Span), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithWrongTypeApplicabilityOnly { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR wrong field type for suggestion + suggestion: Applicability, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithSpanOnly{ + #[suggestion(message = "This is a message", code = "This is suggested code")] + suggestion: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithDuplicateSpanAndApplicability { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one Span + suggestion: (Span, Span, Applicability), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct SuggestWithDuplicateApplicabilityAndSpan { + #[suggestion(message = "This is a message", code = "This is suggested code")] + //~^ ERROR type of field annotated with `#[suggestion(...)]` contains more than one + suggestion: (Applicability, Applicability, Span), +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct WrongKindOfAnnotation { + #[label("wrong kind of annotation for label")] + //~^ ERROR invalid annotation list `#[label(...)]` + z: Span, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +#[message = "Something something else"] +struct OptionsInErrors { + #[label = "Label message"] + label: Option, + #[suggestion(message = "suggestion message")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(SessionDiagnostic)] +#[error = "E0456"] +struct MoveOutOfBorrowError<'tcx> { + name: Ident, + ty: Ty<'tcx>, + #[message = "cannot move {ty} out of borrow"] + #[label = "cannot move out of borrow"] + span: Span, + #[label = "`{ty}` first borrowed here"] + other_span: Span, + #[suggestion(message = "consider cloning here", code = "{name}.clone()")] + opt_sugg: Option<(Span, Applicability)>, +} + +#[derive(SessionDiagnostic)] +#[error = "E0123"] +struct ErrorWithLifetime<'a> { + #[message = "Some message that references {name}"] + span: Span, + name: &'a str, +} diff --git a/src/test/ui-fulldeps/session-derive-errors.stderr b/src/test/ui-fulldeps/session-derive-errors.stderr new file mode 100644 index 0000000000..b4830743e3 --- /dev/null +++ b/src/test/ui-fulldeps/session-derive-errors.stderr @@ -0,0 +1,124 @@ +error: `#[derive(SessionDiagnostic)]` can only be used on structs + --> $DIR/session-derive-errors.rs:28:1 + | +LL | #[error = "E0123"] + | ^^^^^^^^^^^^^^^^^^ + +error: `#[label = ...]` is not a valid SessionDiagnostic struct attribute + --> $DIR/session-derive-errors.rs:37:1 + | +LL | #[label = "This is in the wrong place"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: `#[suggestion = ...]` is not a valid SessionDiagnostic field attribute + --> $DIR/session-derive-errors.rs:44:5 + | +LL | #[suggestion = "this is the wrong kind of attribute"] + | ^ + +error: `error` specified multiple times + --> $DIR/session-derive-errors.rs:52:11 + | +LL | #[error = "E0456"] + | ^^^^^^^ + +error: `lint` specified when `error` was already specified + --> $DIR/session-derive-errors.rs:58:10 + | +LL | #[lint = "some_useful_lint"] + | ^^^^^^^^^^^^^^^^^^ + +error: `code` not specified + --> $DIR/session-derive-errors.rs:67:1 + | +LL | struct ErrorCodeNotProvided {} + | ^^^^^^ + | + = help: use the [code = "..."] attribute to set this diagnostic's error code + +error: the `#[message = "..."]` attribute can only be applied to fields of type Span + --> $DIR/session-derive-errors.rs:95:5 + | +LL | #[message = "this message is applied to a String field"] + | ^ + +error: `name` doesn't refer to a field on this type + --> $DIR/session-derive-errors.rs:102:1 + | +LL | #[message = "This error has a field, and references {name}"] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: invalid format string: expected `'}'` but string was terminated + --> $DIR/session-derive-errors.rs:110:1 + | +LL | #[error = "E0123"] + | - because of this opening brace +LL | #[message = "This is missing a closing brace: {name"] + | ^ expected `'}'` in format string + | + = note: if you intended to print `{`, you can escape it using `{{` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: invalid format string: unmatched `}` found + --> $DIR/session-derive-errors.rs:119:1 + | +LL | #[message = "This is missing an opening brace: name}"] + | ^ unmatched `}` in format string + | + = note: if you intended to print `}`, you can escape it using `}}` + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: The `#[label = ...]` attribute can only be applied to fields of type Span + --> $DIR/session-derive-errors.rs:138:5 + | +LL | #[label = "See here"] + | ^ + +error: `nonsense` is not a valid key for `#[suggestion(...)]` + --> $DIR/session-derive-errors.rs:163:18 + | +LL | #[suggestion(nonsense = "This is nonsense")] + | ^^^^^^^^ + +error: `msg` is not a valid key for `#[suggestion(...)]` + --> $DIR/session-derive-errors.rs:171:18 + | +LL | #[suggestion(msg = "This is a suggestion")] + | ^^^ + +error: missing suggestion message + --> $DIR/session-derive-errors.rs:179:7 + | +LL | #[suggestion(code = "This is suggested code")] + | ^^^^^^^^^^ + | + = help: provide a suggestion message using #[suggestion(message = "...")] + +error: wrong field type for suggestion + --> $DIR/session-derive-errors.rs:194:5 + | +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ + | + = help: #[suggestion(...)] should be applied to fields of type Span or (Span, Applicability) + +error: type of field annotated with `#[suggestion(...)]` contains more than one Span + --> $DIR/session-derive-errors.rs:209:5 + | +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ + +error: type of field annotated with `#[suggestion(...)]` contains more than one Applicability + --> $DIR/session-derive-errors.rs:217:5 + | +LL | #[suggestion(message = "This is a message", code = "This is suggested code")] + | ^ + +error: invalid annotation list `#[label(...)]` + --> $DIR/session-derive-errors.rs:225:7 + | +LL | #[label("wrong kind of annotation for label")] + | ^^^^^ + +error: aborting due to 18 previous errors + diff --git a/src/test/ui/access-mode-in-closures.stderr b/src/test/ui/access-mode-in-closures.stderr index 349e3f4a83..c32e944afe 100644 --- a/src/test/ui/access-mode-in-closures.stderr +++ b/src/test/ui/access-mode-in-closures.stderr @@ -5,7 +5,7 @@ LL | match *s { S(v) => v } | ^^ - | | | | | data moved here - | | move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | | move occurs because `v` has type `Vec`, which does not implement the `Copy` trait | help: consider borrowing here: `&*s` error: aborting due to previous error diff --git a/src/test/ui/allocator/custom.rs b/src/test/ui/allocator/custom.rs index a6c2317c73..dfb5d3e9e3 100644 --- a/src/test/ui/allocator/custom.rs +++ b/src/test/ui/allocator/custom.rs @@ -10,6 +10,7 @@ extern crate helper; use std::alloc::{self, AllocRef, Global, Layout, System}; use std::sync::atomic::{AtomicUsize, Ordering}; +use std::ptr::NonNull; static HITS: AtomicUsize = AtomicUsize::new(0); @@ -18,12 +19,12 @@ struct A; unsafe impl alloc::GlobalAlloc for A { unsafe fn alloc(&self, layout: Layout) -> *mut u8 { HITS.fetch_add(1, Ordering::SeqCst); - System.alloc(layout) + alloc::GlobalAlloc::alloc(&System, layout) } unsafe fn dealloc(&self, ptr: *mut u8, layout: Layout) { HITS.fetch_add(1, Ordering::SeqCst); - System.dealloc(ptr, layout) + AllocRef::dealloc(&System, NonNull::new(ptr).unwrap(), layout) } } diff --git a/src/test/ui/allocator/not-an-allocator.stderr b/src/test/ui/allocator/not-an-allocator.stderr index 0d52a23c1f..c0ea8ff47e 100644 --- a/src/test/ui/allocator/not-an-allocator.stderr +++ b/src/test/ui/allocator/not-an-allocator.stderr @@ -1,35 +1,35 @@ -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::alloc` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::dealloc` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::realloc` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `usize: std::alloc::GlobalAlloc` is not satisfied +error[E0277]: the trait bound `usize: GlobalAlloc` is not satisfied --> $DIR/not-an-allocator.rs:2:1 | LL | static A: usize = 0; - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::alloc::GlobalAlloc` is not implemented for `usize` + | ^^^^^^^^^^^^^^^^^^^^ the trait `GlobalAlloc` is not implemented for `usize` | = note: required by `std::alloc::GlobalAlloc::alloc_zeroed` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/anonymous-higher-ranked-lifetime.stderr b/src/test/ui/anonymous-higher-ranked-lifetime.stderr index de478417d0..576fcc6fad 100644 --- a/src/test/ui/anonymous-higher-ranked-lifetime.stderr +++ b/src/test/ui/anonymous-higher-ranked-lifetime.stderr @@ -59,7 +59,7 @@ error[E0631]: type mismatch in closure arguments LL | g1(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | - | expected signature of `for<'r> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>) -> _` + | expected signature of `for<'r> fn(&'r (), Box<(dyn for<'s> Fn(&'s ()) + 'static)>) -> _` ... LL | fn g1(_: F) where F: Fn(&(), Box) {} | ------------------------- required by this bound in `g1` @@ -81,7 +81,7 @@ error[E0631]: type mismatch in closure arguments LL | g3(|_: (), _: ()| {}); | ^^ -------------- found signature of `fn((), ()) -> _` | | - | expected signature of `for<'s> fn(&'s (), std::boxed::Box<(dyn for<'r> std::ops::Fn(&'r ()) + 'static)>) -> _` + | expected signature of `for<'s> fn(&'s (), Box<(dyn for<'r> Fn(&'r ()) + 'static)>) -> _` ... LL | fn g3(_: F) where F: for<'s> Fn(&'s (), Box) {} | ------------------------------------ required by this bound in `g3` @@ -103,7 +103,7 @@ error[E0631]: type mismatch in closure arguments LL | h1(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | - | expected signature of `for<'r, 's> fn(&'r (), std::boxed::Box<(dyn for<'t0> std::ops::Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` + | expected signature of `for<'r, 's> fn(&'r (), Box<(dyn for<'t0> Fn(&'t0 ()) + 'static)>, &'s (), for<'t0, 't1> fn(&'t0 (), &'t1 ())) -> _` ... LL | fn h1(_: F) where F: Fn(&(), Box, &(), fn(&(), &())) {} | -------------------------------------------- required by this bound in `h1` @@ -114,7 +114,7 @@ error[E0631]: type mismatch in closure arguments LL | h2(|_: (), _: (), _: (), _: ()| {}); | ^^ ---------------------------- found signature of `fn((), (), (), ()) -> _` | | - | expected signature of `for<'r, 't0> fn(&'r (), std::boxed::Box<(dyn for<'s> std::ops::Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` + | expected signature of `for<'r, 't0> fn(&'r (), Box<(dyn for<'s> Fn(&'s ()) + 'static)>, &'t0 (), for<'s, 't1> fn(&'s (), &'t1 ())) -> _` ... LL | fn h2(_: F) where F: for<'t0> Fn(&(), Box, &'t0 (), fn(&(), &())) {} | --------------------------------------------------------- required by this bound in `h2` diff --git a/src/test/ui/array-slice-vec/arr_cycle.rs b/src/test/ui/array-slice-vec/arr_cycle.rs deleted file mode 100644 index c262b5a1ff..0000000000 --- a/src/test/ui/array-slice-vec/arr_cycle.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -use std::cell::Cell; - -#[derive(Debug)] -struct B<'a> { - a: [Cell>>; 2] -} - -impl<'a> B<'a> { - fn new() -> B<'a> { - B { a: [Cell::new(None), Cell::new(None)] } - } -} - -fn f() { - let (b1, b2, b3); - b1 = B::new(); - b2 = B::new(); - b3 = B::new(); - b1.a[0].set(Some(&b2)); - b1.a[1].set(Some(&b3)); - b2.a[0].set(Some(&b2)); - b2.a[1].set(Some(&b3)); - b3.a[0].set(Some(&b1)); - b3.a[1].set(Some(&b2)); -} - -fn main() { - f(); -} diff --git a/src/test/ui/array-slice-vec/slice-2.rs b/src/test/ui/array-slice-vec/slice-2.rs deleted file mode 100644 index 01733f4823..0000000000 --- a/src/test/ui/array-slice-vec/slice-2.rs +++ /dev/null @@ -1,62 +0,0 @@ -// run-pass - -// Test slicing expressions on slices and Vecs. - - -fn main() { - let x: &[isize] = &[1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: Vec = vec![1, 2, 3, 4, 5]; - let cmp: &[isize] = &[1, 2, 3, 4, 5]; - assert_eq!(&x[..], cmp); - let cmp: &[isize] = &[3, 4, 5]; - assert_eq!(&x[2..], cmp); - let cmp: &[isize] = &[1, 2, 3]; - assert_eq!(&x[..3], cmp); - let cmp: &[isize] = &[2, 3, 4]; - assert_eq!(&x[1..4], cmp); - - let x: &mut [isize] = &mut [1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } - - let mut x: Vec = vec![1, 2, 3, 4, 5]; - { - let cmp: &mut [isize] = &mut [1, 2, 3, 4, 5]; - assert_eq!(&mut x[..], cmp); - } - { - let cmp: &mut [isize] = &mut [3, 4, 5]; - assert_eq!(&mut x[2..], cmp); - } - { - let cmp: &mut [isize] = &mut [1, 2, 3]; - assert_eq!(&mut x[..3], cmp); - } - { - let cmp: &mut [isize] = &mut [2, 3, 4]; - assert_eq!(&mut x[1..4], cmp); - } -} diff --git a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs index 34adb42a32..521b898e7f 100644 --- a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs +++ b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.rs @@ -1,7 +1,7 @@ fn main() { match "foo".to_string() { ['f', 'o', ..] => {} - //~^ ERROR expected an array or slice, found `std::string::String` + //~^ ERROR expected an array or slice, found `String` _ => { } }; diff --git a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr index c4548142c1..20a5b99845 100644 --- a/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr +++ b/src/test/ui/array-slice-vec/slice-pat-type-mismatches.stderr @@ -4,11 +4,11 @@ error[E0425]: cannot find value `does_not_exist` in this scope LL | match does_not_exist { | ^^^^^^^^^^^^^^ not found in this scope -error[E0529]: expected an array or slice, found `std::string::String` +error[E0529]: expected an array or slice, found `String` --> $DIR/slice-pat-type-mismatches.rs:3:9 | LL | ['f', 'o', ..] => {} - | ^^^^^^^^^^^^^^ pattern cannot match with input type `std::string::String` + | ^^^^^^^^^^^^^^ pattern cannot match with input type `String` error[E0527]: pattern requires 1 element but array has 3 --> $DIR/slice-pat-type-mismatches.rs:18:9 diff --git a/src/test/ui/array-slice-vec/vec-concat.rs b/src/test/ui/array-slice-vec/vec-concat.rs deleted file mode 100644 index 1f493679b7..0000000000 --- a/src/test/ui/array-slice-vec/vec-concat.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass - -use std::vec; - -pub fn main() { - let a: Vec = vec![1, 2, 3, 4, 5]; - let b: Vec = vec![6, 7, 8, 9, 0]; - let mut v: Vec = a; - v.extend_from_slice(&b); - println!("{}", v[9]); - assert_eq!(v[0], 1); - assert_eq!(v[7], 8); - assert_eq!(v[9], 0); -} diff --git a/src/test/ui/array-slice-vec/vec-growth.rs b/src/test/ui/array-slice-vec/vec-growth.rs deleted file mode 100644 index b09f08bb85..0000000000 --- a/src/test/ui/array-slice-vec/vec-growth.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - - - -pub fn main() { - let mut v = vec![1]; - v.push(2); - v.push(3); - v.push(4); - v.push(5); - assert_eq!(v[0], 1); - assert_eq!(v[1], 2); - assert_eq!(v[2], 3); - assert_eq!(v[3], 4); - assert_eq!(v[4], 5); -} diff --git a/src/test/ui/array-slice-vec/vec-push.rs b/src/test/ui/array-slice-vec/vec-push.rs deleted file mode 100644 index 466ab3fab1..0000000000 --- a/src/test/ui/array-slice-vec/vec-push.rs +++ /dev/null @@ -1,3 +0,0 @@ -// run-pass - -pub fn main() { let mut v = vec![1, 2, 3]; v.push(1); } diff --git a/src/test/ui/array-slice-vec/vec-slice-drop.rs b/src/test/ui/array-slice-vec/vec-slice-drop.rs deleted file mode 100644 index 3a9ea86af3..0000000000 --- a/src/test/ui/array-slice-vec/vec-slice-drop.rs +++ /dev/null @@ -1,31 +0,0 @@ -// run-pass - -#![allow(non_camel_case_types)] - -use std::cell::Cell; - -// Make sure that destructors get run on slice literals -struct foo<'a> { - x: &'a Cell, -} - -impl<'a> Drop for foo<'a> { - fn drop(&mut self) { - self.x.set(self.x.get() + 1); - } -} - -fn foo(x: &Cell) -> foo { - foo { - x: x - } -} - -pub fn main() { - let x = &Cell::new(0); - { - let l = &[foo(x)]; - assert_eq!(l[0].x.get(), 0); - } - assert_eq!(x.get(), 1); -} diff --git a/src/test/ui/array-slice-vec/vec-slice.rs b/src/test/ui/array-slice-vec/vec-slice.rs deleted file mode 100644 index 1f090ddd9c..0000000000 --- a/src/test/ui/array-slice-vec/vec-slice.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - -pub fn main() { - let v = vec![1,2,3,4,5]; - let v2 = &v[1..3]; - assert_eq!(v2[0], 2); - assert_eq!(v2[1], 3); -} diff --git a/src/test/ui/array-slice-vec/vec-to_str.rs b/src/test/ui/array-slice-vec/vec-to_str.rs deleted file mode 100644 index a11cfc8e9b..0000000000 --- a/src/test/ui/array-slice-vec/vec-to_str.rs +++ /dev/null @@ -1,12 +0,0 @@ -// run-pass - - -pub fn main() { - assert_eq!(format!("{:?}", vec![0, 1]), "[0, 1]".to_string()); - - let foo = vec![3, 4]; - let bar: &[isize] = &[4, 5]; - - assert_eq!(format!("{:?}", foo), "[3, 4]"); - assert_eq!(format!("{:?}", bar), "[4, 5]"); -} diff --git a/src/test/ui/array-slice-vec/vec.rs b/src/test/ui/array-slice-vec/vec.rs deleted file mode 100644 index e76c1ab440..0000000000 --- a/src/test/ui/array-slice-vec/vec.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - - - -pub fn main() { - let v: Vec = vec![10, 20]; - assert_eq!(v[0], 10); - assert_eq!(v[1], 20); - let mut x: usize = 0; - assert_eq!(v[x], 10); - assert_eq!(v[x + 1], 20); - x = x + 1; - assert_eq!(v[x], 20); - assert_eq!(v[x - 1], 10); -} diff --git a/src/test/ui/array-slice-vec/vec_cycle.rs b/src/test/ui/array-slice-vec/vec_cycle.rs deleted file mode 100644 index 82bce43728..0000000000 --- a/src/test/ui/array-slice-vec/vec_cycle.rs +++ /dev/null @@ -1,39 +0,0 @@ -// run-pass - -use std::cell::Cell; - -#[derive(Debug)] -struct C<'a> { - v: Vec>>>, -} - -impl<'a> C<'a> { - fn new() -> C<'a> { - C { v: Vec::new() } - } -} - -fn f() { - let (mut c1, mut c2, mut c3); - c1 = C::new(); - c2 = C::new(); - c3 = C::new(); - - c1.v.push(Cell::new(None)); - c1.v.push(Cell::new(None)); - c2.v.push(Cell::new(None)); - c2.v.push(Cell::new(None)); - c3.v.push(Cell::new(None)); - c3.v.push(Cell::new(None)); - - c1.v[0].set(Some(&c2)); - c1.v[1].set(Some(&c3)); - c2.v[0].set(Some(&c2)); - c2.v[1].set(Some(&c3)); - c3.v[0].set(Some(&c1)); - c3.v[1].set(Some(&c2)); -} - -fn main() { - f(); -} diff --git a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs b/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs deleted file mode 100644 index 1a3606d5e8..0000000000 --- a/src/test/ui/array-slice-vec/vec_cycle_wrapped.rs +++ /dev/null @@ -1,50 +0,0 @@ -// run-pass - -use std::cell::Cell; - -#[derive(Debug)] -struct Refs<'a> { - v: Vec>>>, -} - -#[derive(Debug)] -struct C<'a> { - refs: Refs<'a>, -} - -impl<'a> Refs<'a> { - fn new() -> Refs<'a> { - Refs { v: Vec::new() } - } -} - -impl<'a> C<'a> { - fn new() -> C<'a> { - C { refs: Refs::new() } - } -} - -fn f() { - let (mut c1, mut c2, mut c3); - c1 = C::new(); - c2 = C::new(); - c3 = C::new(); - - c1.refs.v.push(Cell::new(None)); - c1.refs.v.push(Cell::new(None)); - c2.refs.v.push(Cell::new(None)); - c2.refs.v.push(Cell::new(None)); - c3.refs.v.push(Cell::new(None)); - c3.refs.v.push(Cell::new(None)); - - c1.refs.v[0].set(Some(&c2)); - c1.refs.v[1].set(Some(&c3)); - c2.refs.v[0].set(Some(&c2)); - c2.refs.v[1].set(Some(&c3)); - c3.refs.v[0].set(Some(&c1)); - c3.refs.v[1].set(Some(&c2)); -} - -fn main() { - f(); -} diff --git a/src/test/ui/array_const_index-0.rs b/src/test/ui/array_const_index-0.rs index 3422aeae8c..4021dfcc6e 100644 --- a/src/test/ui/array_const_index-0.rs +++ b/src/test/ui/array_const_index-0.rs @@ -1,6 +1,6 @@ const A: &'static [i32] = &[]; const B: i32 = (&A)[1]; -//~^ index out of bounds: the len is 0 but the index is 1 +//~^ index out of bounds: the length is 0 but the index is 1 //~| ERROR any use of this value will cause an error fn main() { diff --git a/src/test/ui/array_const_index-0.stderr b/src/test/ui/array_const_index-0.stderr index 16ebc4a577..7ccc3aa087 100644 --- a/src/test/ui/array_const_index-0.stderr +++ b/src/test/ui/array_const_index-0.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const B: i32 = (&A)[1]; | ---------------^^^^^^^- | | - | index out of bounds: the len is 0 but the index is 1 + | index out of bounds: the length is 0 but the index is 1 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/array_const_index-1.rs b/src/test/ui/array_const_index-1.rs index 1f77cb6a39..d0ee1796c0 100644 --- a/src/test/ui/array_const_index-1.rs +++ b/src/test/ui/array_const_index-1.rs @@ -1,6 +1,6 @@ const A: [i32; 0] = []; const B: i32 = A[1]; -//~^ index out of bounds: the len is 0 but the index is 1 +//~^ index out of bounds: the length is 0 but the index is 1 //~| ERROR any use of this value will cause an error fn main() { diff --git a/src/test/ui/array_const_index-1.stderr b/src/test/ui/array_const_index-1.stderr index 98a64eaadc..37de61b9df 100644 --- a/src/test/ui/array_const_index-1.stderr +++ b/src/test/ui/array_const_index-1.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const B: i32 = A[1]; | ---------------^^^^- | | - | index out of bounds: the len is 0 but the index is 1 + | index out of bounds: the length is 0 but the index is 1 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/asm/type-check-1.stderr b/src/test/ui/asm/type-check-1.stderr index 1f11d19c70..556e83fdb0 100644 --- a/src/test/ui/asm/type-check-1.stderr +++ b/src/test/ui/asm/type-check-1.stderr @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `[u64]` cannot be known at compilation LL | asm!("{}", in(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = help: the trait `Sized` is not implemented for `[u64]` = 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 @@ -25,7 +25,7 @@ error[E0277]: the size for values of type `[u64]` cannot be known at compilation LL | asm!("{}", out(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = help: the trait `Sized` is not implemented for `[u64]` = 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 @@ -34,7 +34,7 @@ error[E0277]: the size for values of type `[u64]` cannot be known at compilation LL | asm!("{}", inout(reg) v[..]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u64]` + = help: the trait `Sized` is not implemented for `[u64]` = note: all inline asm arguments must have a statically known size error: aborting due to 5 previous errors diff --git a/src/test/ui/asm/type-check-2.rs b/src/test/ui/asm/type-check-2.rs index 1652e9e4c9..01c8b4eb65 100644 --- a/src/test/ui/asm/type-check-2.rs +++ b/src/test/ui/asm/type-check-2.rs @@ -78,7 +78,7 @@ fn main() { asm!("{}", in(reg) |x: i32| x); //~^ ERROR cannot use value of type asm!("{}", in(reg) vec![0]); - //~^ ERROR cannot use value of type `std::vec::Vec` for inline assembly + //~^ 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]); diff --git a/src/test/ui/asm/type-check-2.stderr b/src/test/ui/asm/type-check-2.stderr index dc7949534f..a520bea8f1 100644 --- a/src/test/ui/asm/type-check-2.stderr +++ b/src/test/ui/asm/type-check-2.stderr @@ -26,7 +26,7 @@ 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 `std::vec::Vec` for inline assembly +error: cannot use value of type `Vec` for inline assembly --> $DIR/type-check-2.rs:80:28 | LL | asm!("{}", in(reg) vec![0]); diff --git a/src/test/ui/asm/type-check-3.rs b/src/test/ui/asm/type-check-3.rs index 0f803eff17..6890baead8 100644 --- a/src/test/ui/asm/type-check-3.rs +++ b/src/test/ui/asm/type-check-3.rs @@ -12,9 +12,9 @@ fn main() { asm!("{}", in(reg) 0i128); //~^ ERROR type `i128` cannot be used with this register class asm!("{}", in(reg) _mm_setzero_ps()); - //~^ ERROR type `std::arch::x86_64::__m128` cannot be used with this register class + //~^ ERROR type `__m128` cannot be used with this register class asm!("{}", in(reg) _mm256_setzero_ps()); - //~^ ERROR type `std::arch::x86_64::__m256` cannot be used with this register class + //~^ 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); diff --git a/src/test/ui/asm/type-check-3.stderr b/src/test/ui/asm/type-check-3.stderr index 01dbe78db8..42497456ac 100644 --- a/src/test/ui/asm/type-check-3.stderr +++ b/src/test/ui/asm/type-check-3.stderr @@ -6,7 +6,7 @@ LL | asm!("{}", in(reg) 0i128); | = note: register class `reg` supports these types: i16, i32, i64, f32, f64 -error: type `std::arch::x86_64::__m128` cannot be used with this register class +error: type `__m128` cannot be used with this register class --> $DIR/type-check-3.rs:14:28 | LL | asm!("{}", in(reg) _mm_setzero_ps()); @@ -14,7 +14,7 @@ LL | asm!("{}", in(reg) _mm_setzero_ps()); | = note: register class `reg` supports these types: i16, i32, i64, f32, f64 -error: type `std::arch::x86_64::__m256` cannot be used with this register class +error: type `__m256` cannot be used with this register class --> $DIR/type-check-3.rs:16:28 | LL | asm!("{}", in(reg) _mm256_setzero_ps()); diff --git a/src/test/ui/associated-const/defaults-cyclic-fail.stderr b/src/test/ui/associated-const/defaults-cyclic-fail.stderr index e6075f7457..616ac9053f 100644 --- a/src/test/ui/associated-const/defaults-cyclic-fail.stderr +++ b/src/test/ui/associated-const/defaults-cyclic-fail.stderr @@ -1,6 +1,11 @@ error[E0391]: cycle detected when normalizing `<() as Tr>::A` | -note: ...which requires const-evaluating + checking `Tr::A`... +note: ...which requires simplifying constant for the type system `Tr::A`... + --> $DIR/defaults-cyclic-fail.rs:6:5 + | +LL | const A: u8 = Self::B; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | LL | const A: u8 = Self::B; @@ -8,15 +13,15 @@ LL | const A: u8 = Self::B; note: ...which requires const-evaluating + checking `Tr::A`... --> $DIR/defaults-cyclic-fail.rs:6:5 | -LL | const A: u8 = Self::B; - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Tr::A`... - --> $DIR/defaults-cyclic-fail.rs:6:5 - | LL | const A: u8 = Self::B; | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `<() as Tr>::B`... -note: ...which requires const-evaluating + checking `Tr::B`... +note: ...which requires simplifying constant for the type system `Tr::B`... + --> $DIR/defaults-cyclic-fail.rs:8:5 + | +LL | const B: u8 = Self::A; + | ^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | LL | const B: u8 = Self::A; @@ -24,15 +29,10 @@ LL | const B: u8 = Self::A; note: ...which requires const-evaluating + checking `Tr::B`... --> $DIR/defaults-cyclic-fail.rs:8:5 | -LL | const B: u8 = Self::A; - | ^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Tr::B`... - --> $DIR/defaults-cyclic-fail.rs:8:5 - | LL | const B: u8 = Self::A; | ^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `<() as Tr>::A`, completing the cycle -note: cycle used when const-evaluating `main::promoted[2]` +note: cycle used when const-evaluating + checking `main::promoted[2]` --> $DIR/defaults-cyclic-fail.rs:14:1 | LL | fn main() { diff --git a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr b/src/test/ui/associated-const/defaults-not-assumed-fail.stderr index c1b08010cd..1497633c26 100644 --- a/src/test/ui/associated-const/defaults-not-assumed-fail.stderr +++ b/src/test/ui/associated-const/defaults-not-assumed-fail.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const B: u8 = Self::A + 1; | --------------^^^^^^^^^^^- | | - | attempt to compute `u8::MAX + 1_u8` which would overflow + | attempt to compute `u8::MAX + 1_u8`, which would overflow | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr index 724823e364..f59287bce7 100644 --- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr +++ b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.noopt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22 | LL | const NEG: i32 = -i32::MIN + T::NEG; - | ^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,25 +10,25 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35 | LL | const NEG_REV: i32 = T::NEG + (-i32::MIN); - | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36 | LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1); - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22 | LL | const DIV: i32 = (1/0) + T::DIV; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -36,19 +36,19 @@ error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35 | LL | const DIV_REV: i32 = T::DIV + (1/0); - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22 | LL | const OOB: i32 = [1][1] + T::OOB; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35 | LL | const OOB_REV: i32 = T::OOB + [1][1]; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr index 724823e364..f59287bce7 100644 --- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr +++ b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22 | LL | const NEG: i32 = -i32::MIN + T::NEG; - | ^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,25 +10,25 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35 | LL | const NEG_REV: i32 = T::NEG + (-i32::MIN); - | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36 | LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1); - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22 | LL | const DIV: i32 = (1/0) + T::DIV; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -36,19 +36,19 @@ error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35 | LL | const DIV_REV: i32 = T::DIV + (1/0); - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22 | LL | const OOB: i32 = [1][1] + T::OOB; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35 | LL | const OOB_REV: i32 = T::OOB + [1][1]; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr index 724823e364..f59287bce7 100644 --- a/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr +++ b/src/test/ui/associated-const/issue-69020-assoc-const-arith-overflow.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:29:22 | LL | const NEG: i32 = -i32::MIN + T::NEG; - | ^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,25 +10,25 @@ error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:31:35 | LL | const NEG_REV: i32 = T::NEG + (-i32::MIN); - | ^^^^^^^^^^^ attempt to negate i32::MIN which would overflow + | ^^^^^^^^^^^ attempt to negate `i32::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:34:22 | LL | const ADD: i32 = (i32::MAX+1) + T::ADD; - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-69020-assoc-const-arith-overflow.rs:36:36 | LL | const ADD_REV: i32 = T::ADD + (i32::MAX+1); - | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:39:22 | LL | const DIV: i32 = (1/0) + T::DIV; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -36,19 +36,19 @@ error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:41:35 | LL | const DIV_REV: i32 = T::DIV + (1/0); - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:44:22 | LL | const OOB: i32 = [1][1] + T::OOB; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: this operation will panic at runtime --> $DIR/issue-69020-assoc-const-arith-overflow.rs:46:35 | LL | const OOB_REV: i32 = T::OOB + [1][1]; - | ^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr index 1b4326ea56..d9bb738656 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-impl.stderr @@ -1,21 +1,26 @@ -error[E0391]: cycle detected when const-evaluating + checking `IMPL_REF_BAR` +error[E0391]: cycle detected when simplifying constant for the type system `IMPL_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: ...which requires simplifying constant for the type system `IMPL_REF_BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 + | +LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `IMPL_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 | -LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `IMPL_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:7:1 - | LL | const IMPL_REF_BAR: u32 = GlobalImplRef::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 + | +LL | const BAR: u32 = IMPL_REF_BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; @@ -25,18 +30,13 @@ note: ...which requires const-evaluating + checking `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 - | -LL | const BAR: u32 = IMPL_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires optimizing MIR for `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-impl.rs:12:5 | LL | const BAR: u32 = IMPL_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `IMPL_REF_BAR`... - = note: ...which again requires const-evaluating + checking `IMPL_REF_BAR`, completing the cycle + = note: ...which again requires simplifying constant for the type system `IMPL_REF_BAR`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr index 8efa56a9a2..d000d8ac09 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait-default.stderr @@ -1,21 +1,26 @@ -error[E0391]: cycle detected when const-evaluating + checking `DEFAULT_REF_BAR` +error[E0391]: cycle detected when simplifying constant for the type system `DEFAULT_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: ...which requires simplifying constant for the type system `DEFAULT_REF_BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 + | +LL | const DEFAULT_REF_BAR: u32 = ::BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `DEFAULT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 | -LL | const DEFAULT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `DEFAULT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:11:1 - | LL | const DEFAULT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `FooDefault::BAR`... +note: ...which requires simplifying constant for the type system `FooDefault::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 + | +LL | const BAR: u32 = DEFAULT_REF_BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; @@ -25,18 +30,13 @@ note: ...which requires const-evaluating + checking `FooDefault::BAR`... | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `FooDefault::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 - | -LL | const BAR: u32 = DEFAULT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires optimizing MIR for `FooDefault::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait-default.rs:8:5 | LL | const BAR: u32 = DEFAULT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `DEFAULT_REF_BAR`... - = note: ...which again requires const-evaluating + checking `DEFAULT_REF_BAR`, completing the cycle + = note: ...which again requires simplifying constant for the type system `DEFAULT_REF_BAR`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr index 78ce1a28a3..62d2051b6c 100644 --- a/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr +++ b/src/test/ui/associated-consts/issue-24949-assoc-const-static-recursion-trait.stderr @@ -1,21 +1,26 @@ -error[E0391]: cycle detected when const-evaluating + checking `TRAIT_REF_BAR` +error[E0391]: cycle detected when simplifying constant for the type system `TRAIT_REF_BAR` --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | +note: ...which requires simplifying constant for the type system `TRAIT_REF_BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 + | +LL | const TRAIT_REF_BAR: u32 = ::BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `TRAIT_REF_BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 | -LL | const TRAIT_REF_BAR: u32 = ::BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `TRAIT_REF_BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:7:1 - | LL | const TRAIT_REF_BAR: u32 = ::BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `::BAR`... -note: ...which requires const-evaluating + checking `::BAR`... +note: ...which requires simplifying constant for the type system `::BAR`... + --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 + | +LL | const BAR: u32 = TRAIT_REF_BAR; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; @@ -25,18 +30,13 @@ note: ...which requires const-evaluating + checking `::BAR`... - --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 - | -LL | const BAR: u32 = TRAIT_REF_BAR; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ note: ...which requires optimizing MIR for `::BAR`... --> $DIR/issue-24949-assoc-const-static-recursion-trait.rs:12:5 | LL | const BAR: u32 = TRAIT_REF_BAR; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `TRAIT_REF_BAR`... - = note: ...which again requires const-evaluating + checking `TRAIT_REF_BAR`, completing the cycle + = note: ...which again requires simplifying constant for the type system `TRAIT_REF_BAR`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs index a58cec5342..498a555c44 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.rs @@ -24,7 +24,7 @@ impl Bar for AssocNoCopy { type Assoc = String; } impl Thing for AssocNoCopy { type Out = Box>; - //~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `String: Copy` is not satisfied fn func() -> Self::Out { Box::new(AssocNoCopy) diff --git a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr index b6b49c2e90..5236f0efa8 100644 --- a/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr +++ b/src/test/ui/associated-type-bounds/assoc-type-eq-with-dyn-atb-fail.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/assoc-type-eq-with-dyn-atb-fail.rs:26:28 | LL | type Out = Box>; - | ^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^^^^^^^^^^^ the trait `Copy` is not implemented for `String` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs index 3db5e468b3..556d8900d1 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - // NOTE: rustc cannot currently handle bounds of the form `for<'a> >::Assoc: Baz`. // This should hopefully be fixed with Chalk. @@ -29,15 +27,15 @@ trait Case1 { pub struct S1; impl Case1 for S1 { -//~^ ERROR `>::App` doesn't implement `std::fmt::Debug` [E0277] +//~^ ERROR `>::App` doesn't implement `Debug` [E0277] type C = Once>; } fn assume_case1() { -//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` [E0277] -//~| ERROR `<::C as std::iter::Iterator>::Item` is not an iterator [E0277] -//~| ERROR `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely [E0277] -//~| ERROR `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely [E0277] +//~^ ERROR `<_ as Lam<&'a u8>>::App` doesn't implement `Debug` [E0277] +//~| ERROR `<::C as Iterator>::Item` is not an iterator [E0277] +//~| ERROR `<::C as Iterator>::Item` cannot be sent between threads safely [E0277] +//~| ERROR `<::C as Iterator>::Item` cannot be shared between threads safely [E0277] fn assert_a<_0, A>() where A: Iterator, _0: Debug {} assert_a::<_, T::A>(); diff --git a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr index cbacc3610d..49b5e7fbb8 100644 --- a/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr +++ b/src/test/ui/associated-type-bounds/bad-bounds-on-assoc-in-trait.stderr @@ -1,5 +1,5 @@ -error[E0277]: `>::App` doesn't implement `std::fmt::Debug` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:31:6 +error[E0277]: `>::App` doesn't implement `Debug` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:29:6 | LL | trait Case1 { | ----- required by a bound in this @@ -8,24 +8,24 @@ LL | Debug | ----- required by this bound in `Case1` ... LL | impl Case1 for S1 { - | ^^^^^ `>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^ `>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `for<'a> std::fmt::Debug` is not implemented for `>::App` + = help: the trait `for<'a> Debug` is not implemented for `>::App` -error[E0277]: `<::C as std::iter::Iterator>::Item` is not an iterator - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<::C as Iterator>::Item` is not an iterator + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | fn assume_case1() { - | ^^^^^ `<::C as std::iter::Iterator>::Item` is not an iterator + | ^^^^^ `<::C as Iterator>::Item` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: the trait `Iterator` is not implemented for `<::C as Iterator>::Item` help: consider further restricting the associated type | -LL | fn assume_case1() where <::C as std::iter::Iterator>::Item: std::iter::Iterator { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn assume_case1() where <::C as Iterator>::Item: Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<::C as Iterator>::Item` cannot be sent between threads safely + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | trait Case1 { | ----- required by a bound in this @@ -34,16 +34,16 @@ LL | Send + Iterator() { - | ^^^^^ `<::C as std::iter::Iterator>::Item` cannot be sent between threads safely + | ^^^^^ `<::C as Iterator>::Item` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: the trait `Send` is not implemented for `<::C as Iterator>::Item` help: consider further restricting the associated type | -LL | fn assume_case1() where <::C as std::iter::Iterator>::Item: std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn assume_case1() where <::C as Iterator>::Item: Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<::C as Iterator>::Item` cannot be shared between threads safely + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | trait Case1 { | ----- required by a bound in this @@ -52,16 +52,16 @@ LL | > + Sync>; | ---- required by this bound in `Case1` ... LL | fn assume_case1() { - | ^^^^^ `<::C as std::iter::Iterator>::Item` cannot be shared between threads safely + | ^^^^^ `<::C as Iterator>::Item` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `<::C as std::iter::Iterator>::Item` + = help: the trait `Sync` is not implemented for `<::C as Iterator>::Item` help: consider further restricting the associated type | -LL | fn assume_case1() where <::C as std::iter::Iterator>::Item: std::marker::Sync { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn assume_case1() where <::C as Iterator>::Item: Sync { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `std::fmt::Debug` - --> $DIR/bad-bounds-on-assoc-in-trait.rs:36:20 +error[E0277]: `<_ as Lam<&'a u8>>::App` doesn't implement `Debug` + --> $DIR/bad-bounds-on-assoc-in-trait.rs:34:20 | LL | trait Case1 { | ----- required by a bound in this @@ -70,9 +70,9 @@ LL | Debug | ----- required by this bound in `Case1` ... LL | fn assume_case1() { - | ^^^^^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^ `<_ as Lam<&'a u8>>::App` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `for<'a> std::fmt::Debug` is not implemented for `<_ as Lam<&'a u8>>::App` + = help: the trait `for<'a> Debug` is not implemented for `<_ as Lam<&'a u8>>::App` error: aborting due to 5 previous errors diff --git a/src/test/ui/associated-type-bounds/duplicate.rs b/src/test/ui/associated-type-bounds/duplicate.rs index 8b5c521943..39df9ba02f 100644 --- a/src/test/ui/associated-type-bounds/duplicate.rs +++ b/src/test/ui/associated-type-bounds/duplicate.rs @@ -8,173 +8,152 @@ use std::iter; struct SI1> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SI2> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SI3> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SW1 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SW2 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] struct SW3 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EI1> { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EI2> { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EI3> { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EW1 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EW2 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] enum EW3 where T: Iterator { V(T) } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UI1> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UI2> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UI3> { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UW1 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UW2 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] union UW3 where T: Iterator { f: T } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FI1>() {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FI2>() {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FI3>() {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FW1() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FW2() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FW3() where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FRPIT1() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT2() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FRPIT3() -> impl Iterator { iter::empty() } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] fn FAPIT1(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FAPIT2(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn FAPIT3(_: impl Iterator) {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] const CIT1: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] const CIT2: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] const CIT3: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] static SIT1: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] static SIT2: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] static SIT3: impl Iterator = iter::empty(); -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn lit1() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn lit2() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn lit3() { let _: impl Iterator = iter::empty(); } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAI1> = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAI2> = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAI3> = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAW1 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAW2 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TAW3 where T: Iterator = T; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI1> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI2> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI3> = impl Copy; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI4 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI5 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type ETAI6 = impl Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRI1> {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRI2> {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRI3> {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRS1: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRS2: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRS3: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRW1 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRW2 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRW3 where T: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRSW1 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] +//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRSW2 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] +//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRSW3 where Self: Iterator {} -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] +//~| ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRA1 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRA2 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] trait TRA3 { type A: Iterator; } -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TADyn1 = dyn Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TADyn2 = Box>; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] type TADyn3 = dyn Iterator; -//~^ ERROR the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified [E0719] -//~| ERROR could not find defining uses -//~| ERROR could not find defining uses +//~^ ERROR the value of the associated type `Item` (from trait `Iterator`) is already specified [E0719] fn main() {} diff --git a/src/test/ui/associated-type-bounds/duplicate.stderr b/src/test/ui/associated-type-bounds/duplicate.stderr index 712211e60c..77cd88e524 100644 --- a/src/test/ui/associated-type-bounds/duplicate.stderr +++ b/src/test/ui/associated-type-bounds/duplicate.stderr @@ -7,7 +7,7 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #63065 for more information -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:10:36 | LL | struct SI1> { f: T } @@ -15,7 +15,7 @@ LL | struct SI1> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:12:36 | LL | struct SI2> { f: T } @@ -23,7 +23,7 @@ LL | struct SI2> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:14:39 | LL | struct SI3> { f: T } @@ -31,7 +31,7 @@ LL | struct SI3> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:16:45 | LL | struct SW1 where T: Iterator { f: T } @@ -39,7 +39,7 @@ LL | struct SW1 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:18:45 | LL | struct SW2 where T: Iterator { f: T } @@ -47,7 +47,7 @@ LL | struct SW2 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:20:48 | LL | struct SW3 where T: Iterator { f: T } @@ -55,7 +55,7 @@ LL | struct SW3 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:23:34 | LL | enum EI1> { V(T) } @@ -63,7 +63,7 @@ LL | enum EI1> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:25:34 | LL | enum EI2> { V(T) } @@ -71,7 +71,7 @@ LL | enum EI2> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:27:37 | LL | enum EI3> { V(T) } @@ -79,7 +79,7 @@ LL | enum EI3> { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:29:43 | LL | enum EW1 where T: Iterator { V(T) } @@ -87,7 +87,7 @@ LL | enum EW1 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:31:43 | LL | enum EW2 where T: Iterator { V(T) } @@ -95,7 +95,7 @@ LL | enum EW2 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:33:46 | LL | enum EW3 where T: Iterator { V(T) } @@ -103,7 +103,7 @@ LL | enum EW3 where T: Iterator { V(T) } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:36:35 | LL | union UI1> { f: T } @@ -111,7 +111,7 @@ LL | union UI1> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:38:35 | LL | union UI2> { f: T } @@ -119,7 +119,7 @@ LL | union UI2> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:40:38 | LL | union UI3> { f: T } @@ -127,7 +127,7 @@ LL | union UI3> { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:42:44 | LL | union UW1 where T: Iterator { f: T } @@ -135,7 +135,7 @@ LL | union UW1 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:44:44 | LL | union UW2 where T: Iterator { f: T } @@ -143,7 +143,7 @@ LL | union UW2 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:46:47 | LL | union UW3 where T: Iterator { f: T } @@ -151,7 +151,7 @@ LL | union UW3 where T: Iterator { f: T } | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:49:32 | LL | fn FI1>() {} @@ -159,7 +159,7 @@ LL | fn FI1>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:51:32 | LL | fn FI2>() {} @@ -167,7 +167,7 @@ LL | fn FI2>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:53:35 | LL | fn FI3>() {} @@ -175,7 +175,7 @@ LL | fn FI3>() {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:55:43 | LL | fn FW1() where T: Iterator {} @@ -183,7 +183,7 @@ LL | fn FW1() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:57:43 | LL | fn FW2() where T: Iterator {} @@ -191,7 +191,7 @@ LL | fn FW2() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/duplicate.rs:59:46 | LL | fn FW3() where T: Iterator {} @@ -199,498 +199,366 @@ LL | fn FW3() where T: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:68:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:65:40 | LL | fn FAPIT1(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:70:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:67:40 | LL | fn FAPIT2(_: impl Iterator) {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:72:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:69:43 | LL | fn FAPIT3(_: impl Iterator) {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:75:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:72:39 | LL | const CIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:77:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:74:39 | LL | const CIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:79:42 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:76:42 | LL | const CIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:81:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:78:40 | LL | static SIT1: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:83:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:80:40 | LL | static SIT2: impl Iterator = iter::empty(); | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:85:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:82:43 | LL | static SIT3: impl Iterator = iter::empty(); | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:88:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:85:46 | LL | fn lit1() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:90:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:87:46 | LL | fn lit2() { let _: impl Iterator = iter::empty(); } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:92:49 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:89:49 | LL | fn lit3() { let _: impl Iterator = iter::empty(); } | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:95:35 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:92:35 | LL | type TAI1> = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:97:35 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:94:35 | LL | type TAI2> = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:99:38 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:96:38 | LL | type TAI3> = T; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:101:44 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:98:44 | LL | type TAW1 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:103:44 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:100:44 | LL | type TAW2 where T: Iterator = T; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:105:47 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:102:47 | LL | type TAW3 where T: Iterator = T; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:108:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:105:36 | LL | type ETAI1> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:62:42 - | -LL | fn FRPIT1() -> impl Iterator { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:64:42 - | -LL | fn FRPIT2() -> impl Iterator { iter::empty() } - | ---------- ^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:66:45 - | -LL | fn FRPIT3() -> impl Iterator { iter::empty() } - | ------------- ^^^^^^^^^^^^^ re-bound here - | | - | `Item` bound here first - -error: could not find defining uses - --> $DIR/duplicate.rs:108:51 - | -LL | type ETAI1> = impl Copy; - | ^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:111:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:107:36 | LL | type ETAI2> = impl Copy; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:111:51 - | -LL | type ETAI2> = impl Copy; - | ^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:114:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:109:39 | LL | type ETAI3> = impl Copy; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:114:57 - | -LL | type ETAI3> = impl Copy; - | ^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:117:14 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:117:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:111:40 | LL | type ETAI4 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:122:14 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:122:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:113:40 | LL | type ETAI5 = impl Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:127:14 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:127:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:115:43 | LL | type ETAI6 = impl Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:133:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:118:36 | LL | trait TRI1> {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:135:36 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:120:36 | LL | trait TRI2> {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:137:39 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:122:39 | LL | trait TRI3> {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:139:34 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:124:34 | LL | trait TRS1: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:141:34 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:126:34 | LL | trait TRS2: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:143:37 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:128:37 | LL | trait TRS3: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:145:45 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:130:45 | LL | trait TRW1 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:147:45 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:132:45 | LL | trait TRW2 where T: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:149:48 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:134:48 | LL | trait TRW3 where T: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:151:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:136:46 | LL | trait TRSW1 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:151:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:136:46 | LL | trait TRSW1 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:154:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:139:46 | LL | trait TRSW2 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:154:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:139:46 | LL | trait TRSW2 where Self: Iterator {} | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:157:49 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:142:49 | LL | trait TRSW3 where Self: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:157:49 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:142:49 | LL | trait TRSW3 where Self: Iterator {} | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:160:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:145:43 | LL | trait TRA1 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:162:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:147:43 | LL | trait TRA2 { type A: Iterator; } | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:164:46 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:149:46 | LL | trait TRA3 { type A: Iterator; } | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:167:40 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:152:40 | LL | type TADyn1 = dyn Iterator; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:171:44 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:154:44 | LL | type TADyn2 = Box>; | ---------- ^^^^^^^^^^ re-bound here | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified - --> $DIR/duplicate.rs:175:43 +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified + --> $DIR/duplicate.rs:156:43 | LL | type TADyn3 = dyn Iterator; | ------------- ^^^^^^^^^^^^^ re-bound here | | | `Item` bound here first -error: could not find defining uses - --> $DIR/duplicate.rs:117:28 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:117:40 - | -LL | type ETAI4 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:122:28 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:122:40 - | -LL | type ETAI5 = impl Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:127:28 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:127:43 - | -LL | type ETAI6 = impl Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:167:28 - | -LL | type TADyn1 = dyn Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:167:40 - | -LL | type TADyn1 = dyn Iterator; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:171:32 - | -LL | type TADyn2 = Box>; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:171:44 - | -LL | type TADyn2 = Box>; - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:175:28 - | -LL | type TADyn3 = dyn Iterator; - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/duplicate.rs:175:43 - | -LL | type TADyn3 = dyn Iterator; - | ^^^^^^^^^^^^^ - -error: aborting due to 90 previous errors; 1 warning emitted +error: aborting due to 69 previous errors; 1 warning emitted For more information about this error, try `rustc --explain E0719`. diff --git a/src/test/ui/associated-type-bounds/inside-adt.rs b/src/test/ui/associated-type-bounds/inside-adt.rs index b74c03829b..5af0573875 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.rs +++ b/src/test/ui/associated-type-bounds/inside-adt.rs @@ -3,32 +3,27 @@ struct S1 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses struct S2 { f: Box> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses struct S3 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses enum E1 { V(dyn Iterator) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` enum E2 { V(Box>) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses enum E3 { V(dyn Iterator) } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` union U1 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` union U2 { f: Box> } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses union U3 { f: dyn Iterator } //~^ ERROR associated type bounds are not allowed within structs, enums, or unions -//~| ERROR could not find defining uses +//~| ERROR the size for values of type `(dyn Iterator + 'static)` fn main() {} diff --git a/src/test/ui/associated-type-bounds/inside-adt.stderr b/src/test/ui/associated-type-bounds/inside-adt.stderr index a532bb0c76..74e858ca86 100644 --- a/src/test/ui/associated-type-bounds/inside-adt.stderr +++ b/src/test/ui/associated-type-bounds/inside-adt.stderr @@ -5,106 +5,125 @@ LL | struct S1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:7:33 + --> $DIR/inside-adt.rs:6:33 | LL | struct S2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:10:29 + --> $DIR/inside-adt.rs:8:29 | LL | struct S3 { f: dyn Iterator } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:14:26 + --> $DIR/inside-adt.rs:11:26 | LL | enum E1 { V(dyn Iterator) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:17:30 + --> $DIR/inside-adt.rs:14:30 | LL | enum E2 { V(Box>) } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:20:26 + --> $DIR/inside-adt.rs:16:26 | LL | enum E3 { V(dyn Iterator) } | ^^^^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:24:28 + --> $DIR/inside-adt.rs:20:28 | LL | union U1 { f: dyn Iterator } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:27:32 + --> $DIR/inside-adt.rs:23:32 | LL | union U2 { f: Box> } | ^^^^^^^^^^ error: associated type bounds are not allowed within structs, enums, or unions - --> $DIR/inside-adt.rs:30:28 + --> $DIR/inside-adt.rs:25:28 | LL | union U3 { f: dyn Iterator } | ^^^^^^^^^^^^^ -error: could not find defining uses - --> $DIR/inside-adt.rs:4:29 - | -LL | struct S1 { f: dyn Iterator } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:7:33 - | -LL | struct S2 { f: Box> } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:10:29 - | -LL | struct S3 { f: dyn Iterator } - | ^^^^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:14:26 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:11:13 | LL | enum E1 { V(dyn Iterator) } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:17:30 + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -LL | enum E2 { V(Box>) } - | ^^^^^^^^^^ + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | enum E1 { V(&dyn Iterator) } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | enum E1 { V(Box>) } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:20:26 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:16:13 | LL | enum E3 { V(dyn Iterator) } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of an enum variant may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | enum E3 { V(&dyn Iterator) } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | enum E3 { V(Box>) } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:24:28 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:20:15 | LL | union U1 { f: dyn Iterator } - | ^^^^^^^^^^ - -error: could not find defining uses - --> $DIR/inside-adt.rs:27:32 + | ^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | -LL | union U2 { f: Box> } - | ^^^^^^^^^^ + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | union U1 { f: &dyn Iterator } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | union U1 { f: Box> } + | ^^^^ ^ -error: could not find defining uses - --> $DIR/inside-adt.rs:30:28 +error[E0277]: the size for values of type `(dyn Iterator + 'static)` cannot be known at compilation time + --> $DIR/inside-adt.rs:25:15 | LL | union U3 { f: dyn Iterator } - | ^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = help: the trait `Sized` is not implemented for `(dyn Iterator + 'static)` + = note: no field of a union may have a dynamically sized type + = help: change the field's type to have a statically known size +help: borrowed types always have a statically known size + | +LL | union U3 { f: &dyn Iterator } + | ^ +help: the `Box` type always has a statically known size and allocates its contents in the heap + | +LL | union U3 { f: Box> } + | ^^^^ ^ -error: aborting due to 18 previous errors +error: aborting due to 13 previous errors +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr index 77835c5f67..289911779f 100644 --- a/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr +++ b/src/test/ui/associated-types/associated-types-in-ambiguous-context.stderr @@ -14,7 +14,7 @@ error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:25:10 | LL | type X = std::ops::Deref::Target; - | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Target` + | ^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Target` error[E0223]: ambiguous associated type --> $DIR/associated-types-in-ambiguous-context.rs:11:23 diff --git a/src/test/ui/associated-types/associated-types-issue-20346.stderr b/src/test/ui/associated-types/associated-types-issue-20346.stderr index db35c1af17..7193d4163b 100644 --- a/src/test/ui/associated-types/associated-types-issue-20346.stderr +++ b/src/test/ui/associated-types/associated-types-issue-20346.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as Iterator>::Item == std::option::Option` +error[E0271]: type mismatch resolving ` as Iterator>::Item == Option` --> $DIR/associated-types-issue-20346.rs:34:5 | LL | fn is_iterator_of>(_: &I) {} @@ -8,9 +8,9 @@ LL | fn test_adapter>>(it: I) { | - this type parameter ... LL | is_iterator_of::, _>(&adapter); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found type parameter `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found type parameter `T` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `T` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr index 82c0eba87e..9f1abf2a6c 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding-2.stderr @@ -1,10 +1,10 @@ -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == i32` +error[E0271]: type mismatch resolving ` as Iterator>::Item == i32` --> $DIR/associated-types-overridden-binding-2.rs:6:43 | LL | let _: &dyn I32Iterator = &vec![42].into_iter(); | ^^^^^^^^^^^^^^^^^^^^^ expected `i32`, found `u32` | - = note: required for the cast to the object type `dyn std::iter::Iterator` + = note: required for the cast to the object type `dyn Iterator` error: aborting due to previous error diff --git a/src/test/ui/associated-types/associated-types-overridden-binding.stderr b/src/test/ui/associated-types/associated-types-overridden-binding.stderr index b8321ce5b2..87612679af 100644 --- a/src/test/ui/associated-types/associated-types-overridden-binding.stderr +++ b/src/test/ui/associated-types/associated-types-overridden-binding.stderr @@ -1,18 +1,18 @@ -error[E0284]: type annotations needed: cannot satisfy `::Item == i32` +error[E0284]: type annotations needed: cannot satisfy `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:4:12 | LL | trait Foo: Iterator {} | ---------- required by this bound in `Foo` LL | trait Bar: Foo {} - | ^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` + | ^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` -error[E0284]: type annotations needed: cannot satisfy `::Item == i32` +error[E0284]: type annotations needed: cannot satisfy `::Item == i32` --> $DIR/associated-types-overridden-binding.rs:7:21 | LL | trait I32Iterator = Iterator; | ---------- required by this bound in `I32Iterator` LL | trait U32Iterator = I32Iterator; - | ^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` + | ^^^^^^^^^^^^^^^^^^^^^^^ cannot satisfy `::Item == i32` error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/associated-types-unsized.fixed b/src/test/ui/associated-types/associated-types-unsized.fixed index 9837796e30..328c8f944e 100644 --- a/src/test/ui/associated-types/associated-types-unsized.fixed +++ b/src/test/ui/associated-types/associated-types-unsized.fixed @@ -6,7 +6,7 @@ trait Get { fn get(&self) -> ::Value; } -fn foo(t: T) where ::Value: std::marker::Sized { +fn foo(t: T) where ::Value: Sized { let x = t.get(); //~ ERROR the size for values of type } diff --git a/src/test/ui/associated-types/associated-types-unsized.stderr b/src/test/ui/associated-types/associated-types-unsized.stderr index e96d0e0eff..c2af548300 100644 --- a/src/test/ui/associated-types/associated-types-unsized.stderr +++ b/src/test/ui/associated-types/associated-types-unsized.stderr @@ -4,13 +4,13 @@ error[E0277]: the size for values of type `::Value` cannot be known at LL | let x = t.get(); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `::Value` + = help: the trait `Sized` is not implemented for `::Value` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type | -LL | fn foo(t: T) where ::Value: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(t: T) where ::Value: Sized { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/defaults-suitability.rs b/src/test/ui/associated-types/defaults-suitability.rs index 2be01cba10..30c2555df8 100644 --- a/src/test/ui/associated-types/defaults-suitability.rs +++ b/src/test/ui/associated-types/defaults-suitability.rs @@ -13,12 +13,12 @@ struct NotClone; // Assoc. type bounds must hold for the default type trait Tr { type Ty: Clone = NotClone; - //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NotClone: Clone` is not satisfied } // Where-clauses defined on the trait must also be considered trait Tr2 where Self::Ty: Clone { - //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NotClone: Clone` is not satisfied type Ty = NotClone; } @@ -31,7 +31,7 @@ trait Tr3 { // Involved type parameters must fulfill all bounds required by defaults that mention them trait Foo { type Bar: Clone = Vec; - //~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `T: Clone` is not satisfied } trait Bar: Sized { @@ -55,7 +55,7 @@ trait C where // Test that we get all expected errors if that default is unsuitable trait D where Vec: Clone, - //~^ ERROR the trait bound `NotClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NotClone: Clone` is not satisfied Self::Assoc: IsU8, //~^ ERROR the trait bound `NotClone: IsU8` is not satisfied bool: IsU8, @@ -70,7 +70,7 @@ trait D where // `Clone`. trait Foo2 { type Bar: Clone = Vec; - //~^ ERROR the trait bound `>::Baz: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `>::Baz: Clone` is not satisfied type Baz = T; } @@ -79,7 +79,7 @@ trait Foo2 { // this would be accepted. trait Foo25 { type Bar: Clone = Vec; - //~^ ERROR the trait bound `>::Baz: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `>::Baz: Clone` is not satisfied type Baz = T; } @@ -88,7 +88,7 @@ trait Foo25 { trait Foo3 where Self::Bar: Clone, Self::Baz: Clone, - //~^ ERROR the trait bound `T: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `T: Clone` is not satisfied { type Bar = Vec; type Baz = T; diff --git a/src/test/ui/associated-types/defaults-suitability.stderr b/src/test/ui/associated-types/defaults-suitability.stderr index 4ff4ee542b..c2ad4c5824 100644 --- a/src/test/ui/associated-types/defaults-suitability.stderr +++ b/src/test/ui/associated-types/defaults-suitability.stderr @@ -1,33 +1,33 @@ -error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NotClone: Clone` is not satisfied --> $DIR/defaults-suitability.rs:15:14 | LL | trait Tr { | -------- required by `Tr` LL | type Ty: Clone = NotClone; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone` + | ^^^^^ the trait `Clone` is not implemented for `NotClone` -error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NotClone: Clone` is not satisfied --> $DIR/defaults-suitability.rs:20:27 | LL | trait Tr2 where Self::Ty: Clone { | --------------------------^^^^^ | | | - | | the trait `std::clone::Clone` is not implemented for `NotClone` + | | the trait `Clone` is not implemented for `NotClone` | required by `Tr2` -error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/defaults-suitability.rs:33:15 | LL | trait Foo { | ------------ required by `Foo` LL | type Bar: Clone = Vec; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `T` + | ^^^^^ the trait `Clone` is not implemented for `T` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` + = note: required because of the requirements on the impl of `Clone` for `Vec` help: consider restricting type parameter `T` | -LL | trait Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait Foo { + | ^^^^^^^ error[E0277]: the trait bound `(): Foo` is not satisfied --> $DIR/defaults-suitability.rs:39:17 @@ -66,12 +66,12 @@ LL | | type Assoc = NotClone; LL | | } | |_- required by `D` -error[E0277]: the trait bound `NotClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NotClone: Clone` is not satisfied --> $DIR/defaults-suitability.rs:57:23 | LL | / trait D where LL | | Vec: Clone, - | | ^^^^^ the trait `std::clone::Clone` is not implemented for `NotClone` + | | ^^^^^ the trait `Clone` is not implemented for `NotClone` LL | | LL | | Self::Assoc: IsU8, ... | @@ -79,43 +79,43 @@ LL | | type Assoc = NotClone; LL | | } | |_- required by `D` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` + = note: required because of the requirements on the impl of `Clone` for `Vec` -error[E0277]: the trait bound `>::Baz: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:72:15 | LL | trait Foo2 { | ------------- required by `Foo2` LL | type Bar: Clone = Vec; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `>::Baz` + | ^^^^^ the trait `Clone` is not implemented for `>::Baz` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<>::Baz>` + = note: required because of the requirements on the impl of `Clone` for `Vec<>::Baz>` help: consider further restricting the associated type | -LL | trait Foo2 where >::Baz: std::clone::Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Foo2 where >::Baz: Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `>::Baz: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `>::Baz: Clone` is not satisfied --> $DIR/defaults-suitability.rs:81:15 | LL | trait Foo25 { | --------------------- required by `Foo25` LL | type Bar: Clone = Vec; - | ^^^^^ the trait `std::clone::Clone` is not implemented for `>::Baz` + | ^^^^^ the trait `Clone` is not implemented for `>::Baz` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec<>::Baz>` + = note: required because of the requirements on the impl of `Clone` for `Vec<>::Baz>` help: consider further restricting the associated type | -LL | trait Foo25 where >::Baz: std::clone::Clone { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Foo25 where >::Baz: Clone { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `T: Clone` is not satisfied --> $DIR/defaults-suitability.rs:90:16 | LL | / trait Foo3 where LL | | Self::Bar: Clone, LL | | Self::Baz: Clone, - | | ^^^^^ the trait `std::clone::Clone` is not implemented for `T` + | | ^^^^^ the trait `Clone` is not implemented for `T` LL | | ... | LL | | type Baz = T; @@ -124,8 +124,8 @@ LL | | } | help: consider further restricting type parameter `T` | -LL | Self::Baz: Clone, T: std::clone::Clone - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | Self::Baz: Clone, T: Clone + | ^^^^^^^^^^ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time --> $DIR/defaults-suitability.rs:27:5 @@ -136,9 +136,9 @@ LL | type Ty = Vec<[u8]>; ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | LL | pub struct Vec { - | - required by this bound in `std::vec::Vec` + | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` error: aborting due to 11 previous errors diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.rs b/src/test/ui/associated-types/defaults-unsound-62211-1.rs index c8b4734d6e..f283d22b3c 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-1.rs +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.rs @@ -19,9 +19,9 @@ trait UncheckedCopy: Sized { // This Output is said to be Copy. Yet we default to Self // and it's accepted, not knowing if Self ineed is Copy type Output: Copy - //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Self: Copy` is not satisfied + Deref - //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + //~^ ERROR the trait bound `Self: Deref` is not satisfied + AddAssign<&'static str> //~^ ERROR cannot add-assign `&'static str` to `Self` + From @@ -40,9 +40,9 @@ trait UncheckedCopy: Sized { impl UncheckedCopy for T {} //~^ ERROR `T` doesn't implement `std::fmt::Display` -//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR the trait bound `T: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `T` -//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied +//~| ERROR the trait bound `T: Copy` is not satisfied fn bug(origin: T) { let origin = T::make_origin(origin); diff --git a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr index 2ba854eac4..29a7c2eab4 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-1.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-1.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Self: Copy` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:21:18 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | type Output: Copy - | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + | ^^^^ the trait `Copy` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::marker::Copy { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Copy { + | ^^^^^^ error[E0277]: cannot add-assign `&'static str` to `Self` --> $DIR/defaults-unsound-62211-1.rs:25:7 @@ -23,22 +23,22 @@ LL | + AddAssign<&'static str> | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:23:7 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | + Deref - | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::Deref { - | ^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Deref { + | ^^^^^^^ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-1.rs:28:7 @@ -73,7 +73,7 @@ help: consider restricting type parameter `T` LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `T: Deref` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -83,12 +83,12 @@ LL | + Deref | ------------------- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^^ error[E0277]: cannot add-assign `&'static str` to `T` --> $DIR/defaults-unsound-62211-1.rs:41:9 @@ -104,10 +104,10 @@ LL | impl UncheckedCopy for T {} | help: consider restricting type parameter `T` | -LL | impl> UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> UncheckedCopy for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/defaults-unsound-62211-1.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -117,12 +117,12 @@ LL | type Output: Copy | ---- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.rs b/src/test/ui/associated-types/defaults-unsound-62211-2.rs index aa343e759a..5518cda370 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-2.rs +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.rs @@ -19,9 +19,9 @@ trait UncheckedCopy: Sized { // This Output is said to be Copy. Yet we default to Self // and it's accepted, not knowing if Self ineed is Copy type Output: Copy - //~^ ERROR the trait bound `Self: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Self: Copy` is not satisfied + Deref - //~^ ERROR the trait bound `Self: std::ops::Deref` is not satisfied + //~^ ERROR the trait bound `Self: Deref` is not satisfied + AddAssign<&'static str> //~^ ERROR cannot add-assign `&'static str` to `Self` + From @@ -40,9 +40,9 @@ trait UncheckedCopy: Sized { impl UncheckedCopy for T {} //~^ ERROR `T` doesn't implement `std::fmt::Display` -//~| ERROR the trait bound `T: std::ops::Deref` is not satisfied +//~| ERROR the trait bound `T: Deref` is not satisfied //~| ERROR cannot add-assign `&'static str` to `T` -//~| ERROR the trait bound `T: std::marker::Copy` is not satisfied +//~| ERROR the trait bound `T: Copy` is not satisfied fn bug(origin: T) { let origin = T::make_origin(origin); diff --git a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr index d4fd0ca98e..49c66093bf 100644 --- a/src/test/ui/associated-types/defaults-unsound-62211-2.stderr +++ b/src/test/ui/associated-types/defaults-unsound-62211-2.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Self: Copy` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:21:18 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | type Output: Copy - | ^^^^ the trait `std::marker::Copy` is not implemented for `Self` + | ^^^^ the trait `Copy` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::marker::Copy { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Copy { + | ^^^^^^ error[E0277]: cannot add-assign `&'static str` to `Self` --> $DIR/defaults-unsound-62211-2.rs:25:7 @@ -23,22 +23,22 @@ LL | + AddAssign<&'static str> | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::AddAssign<&'static str> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + AddAssign<&'static str> { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `Self: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `Self: Deref` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:23:7 | LL | trait UncheckedCopy: Sized { | -------------------------- required by `UncheckedCopy` ... LL | + Deref - | ^^^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `Self` + | ^^^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `Self` | help: consider further restricting `Self` | -LL | trait UncheckedCopy: Sized + std::ops::Deref { - | ^^^^^^^^^^^^^^^^^ +LL | trait UncheckedCopy: Sized + Deref { + | ^^^^^^^ error[E0277]: `Self` doesn't implement `std::fmt::Display` --> $DIR/defaults-unsound-62211-2.rs:28:7 @@ -73,7 +73,7 @@ help: consider restricting type parameter `T` LL | impl UncheckedCopy for T {} | ^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `T: Deref` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -83,12 +83,12 @@ LL | + Deref | ------------------- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Deref` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^^ error[E0277]: cannot add-assign `&'static str` to `T` --> $DIR/defaults-unsound-62211-2.rs:41:9 @@ -104,10 +104,10 @@ LL | impl UncheckedCopy for T {} | help: consider restricting type parameter `T` | -LL | impl> UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> UncheckedCopy for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/defaults-unsound-62211-2.rs:41:9 | LL | trait UncheckedCopy: Sized { @@ -117,12 +117,12 @@ LL | type Output: Copy | ---- required by this bound in `UncheckedCopy` ... LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UncheckedCopy for T {} - | ^^^^^^^^^^^^^^^^^^^ +LL | impl UncheckedCopy for T {} + | ^^^^^^ error: aborting due to 8 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-1.rs index 497b86eeab..cdf32dd82a 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-1.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.rs @@ -10,7 +10,7 @@ where impl X<'_> for i32 { type U = str; - //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` + //~^ ERROR the trait bound `for<'b> >::U: Clone` } fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr index 7ef2faef9c..c9255c91d2 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-1.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-1.rs:12:14 | LL | trait X<'a> @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr index 2a364d349d..20b6659bbc 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-2.stderr @@ -5,7 +5,7 @@ LL | 1u32.f("abc"); | ^ method not found in `u32` | = note: the method `f` exists but the following trait bounds were not satisfied: - `>::U: std::clone::Clone` + `>::U: Clone` which is required by `u32: X` error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.rs b/src/test/ui/associated-types/hr-associated-type-bound-object.rs index 7c64ae38ca..e19c918c3d 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-object.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.rs @@ -5,7 +5,7 @@ where type U: ?Sized; } fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { - //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> >::U: Clone` is not satisfied <>::U>::clone(x); } diff --git a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr index db966875c7..225b18a3b0 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-object.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-object.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-object.rs:7:13 | LL | trait X<'a> @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | fn f<'a, T: X<'a> + ?Sized>(x: &>::U) { - | ^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | ^^^^^ the trait `for<'b> Clone` is not implemented for `>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs index a65f8a8c49..0a81f373ad 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.rs @@ -12,7 +12,7 @@ where impl<'a> Y<'a, u8> for u8 { type V = str; - //~^ ERROR the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> >::V: Clone` is not satisfied } fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr index 347a5818dc..7af261e4b3 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-1.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::V: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::V: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-1.rs:14:14 | LL | trait Y<'a, T: ?Sized> @@ -8,11 +8,11 @@ LL | for<'b> >::V: Clone, | ----- required by this bound in `Y` ... LL | type V = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::V` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::V` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs index 9f849b0327..5db619dc98 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.rs @@ -1,8 +1,8 @@ trait Z<'a, T: ?Sized> where T: Z<'a, u16>, - //~^ the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied - //~| the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied + //~^ the trait bound `for<'b> >::W: Clone` is not satisfied + //~| the trait bound `for<'b> >::W: Clone` is not satisfied for<'b> >::W: Clone, { type W: ?Sized; @@ -13,7 +13,7 @@ where impl<'a> Z<'a, u16> for u16 { type W = str; - //~^ ERROR the trait bound `for<'b> >::W: std::clone::Clone + //~^ ERROR the trait bound `for<'b> >::W: Clone } fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr index e06777e36a..9a70194379 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-2.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:3:8 | LL | trait Z<'a, T: ?Sized> | - required by a bound in this LL | where LL | T: Z<'a, u16>, - | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | ^^^^^^^^^^ the trait `for<'b> Clone` is not implemented for `>::W` ... LL | for<'b> >::W: Clone, | ----- required by this bound in `Z` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:15:14 | LL | trait Z<'a, T: ?Sized> @@ -24,27 +24,27 @@ LL | for<'b> >::W: Clone, | ----- required by this bound in `Z` ... LL | type W = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::W` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> >::W: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::W: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-2.rs:3:8 | LL | trait Z<'a, T: ?Sized> | - required by a bound in this LL | where LL | T: Z<'a, u16>, - | ^^^^^^^^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::W` + | ^^^^^^^^^^ the trait `for<'b> Clone` is not implemented for `>::W` ... LL | for<'b> >::W: Clone, | ----- required by this bound in `Z` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs index 9aca59f8ce..1af63bf907 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - trait X<'a, T> where for<'b> T: X<'b, T>, @@ -13,7 +11,7 @@ where impl X<'_, (T,)> for (S,) { type U = str; - //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr index ff56f60e4c..48c4d77dcc 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-3.stderr @@ -1,5 +1,5 @@ -error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-3.rs:15:14 +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, (T,)>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-3.rs:13:14 | LL | trait X<'a, T> | - required by a bound in this @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `<(T,) as X<'b, (T,)>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs index ffe43c674c..6f06b925bd 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.rs @@ -11,7 +11,7 @@ where impl X<'_, T> for (S,) { type U = str; - //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> <(T,) as X<'b, T>>::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr index c41efb8b6e..111ca8566b 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-4.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> <(T,) as X<'b, T>>::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-4.rs:13:14 | LL | trait X<'a, T> @@ -8,11 +8,11 @@ LL | for<'b> <(T,) as X<'b, T>>::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `<(T,) as X<'b, T>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `<(T,) as X<'b, T>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to previous error diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs index dcca0b3ce9..ec627c7f7e 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.rs @@ -1,5 +1,3 @@ -// ignore-tidy-linelength - trait Cycle: Sized { type Next: Cycle; } @@ -26,14 +24,14 @@ where impl X<'_, Vec> for S { type U = str; - //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied } impl X<'_, Box> for S { type U = str; - //~^ ERROR the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - //~| ERROR the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + //~| ERROR the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr index 39c191e974..81eceb4666 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-5.stderr @@ -1,5 +1,5 @@ -error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:28:14 +error[E0277]: the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:26:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -8,14 +8,14 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Box>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:28:14 +error[E0277]: the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:26:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -24,14 +24,14 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Vec>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> as X<'b, std::vec::Vec>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:34:14 +error[E0277]: the trait bound `for<'b> as X<'b, Vec>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:32:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -40,14 +40,14 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::vec::Vec>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Vec>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> -error[E0277]: the trait bound `for<'b> as X<'b, std::boxed::Box>>::U: std::clone::Clone` is not satisfied - --> $DIR/hr-associated-type-bound-param-5.rs:34:14 +error[E0277]: the trait bound `for<'b> as X<'b, Box>>::U: Clone` is not satisfied + --> $DIR/hr-associated-type-bound-param-5.rs:32:14 | LL | trait X<'a, T: Cycle + for<'b> X<'b, T>> | - required by a bound in this @@ -56,11 +56,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for ` as X<'b, std::boxed::Box>>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for ` as X<'b, Box>>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error: aborting due to 4 previous errors diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs index 4b8018cb43..04b88c7f4f 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.rs @@ -12,7 +12,7 @@ where impl X<'_, T> for (S,) { //~^ ERROR the trait bound `for<'b> T: X<'b, T>` is not satisfied type U = str; - //~^ ERROR the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `for<'b> >::U: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr index 83845d3a94..2efdb2445a 100644 --- a/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr +++ b/src/test/ui/associated-types/hr-associated-type-bound-param-6.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::U: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `for<'b> >::U: Clone` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:14:14 | LL | trait X<'a, T> @@ -8,11 +8,11 @@ LL | for<'b> >::U: Clone, | ----- required by this bound in `X` ... LL | type U = str; - | ^^^ the trait `for<'b> std::clone::Clone` is not implemented for `>::U` + | ^^^ the trait `for<'b> Clone` is not implemented for `>::U` | = help: the following implementations were found: - <&T as std::clone::Clone> - <&mut T as std::clone::Clone> + <&T as Clone> + <&mut T as Clone> error[E0277]: the trait bound `for<'b> T: X<'b, T>` is not satisfied --> $DIR/hr-associated-type-bound-param-6.rs:12:12 diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.rs b/src/test/ui/associated-types/hr-associated-type-projection-1.rs index 0d4567a55f..1270cd6706 100644 --- a/src/test/ui/associated-types/hr-associated-type-projection-1.rs +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.rs @@ -11,9 +11,9 @@ where } impl UnsafeCopy<'_, T> for T { - //~^ ERROR the trait bound `>::Item: std::ops::Deref` is not satisfied + //~^ ERROR the trait bound `>::Item: Deref` is not satisfied type Item = T; - //~^ ERROR the trait bound `for<'b> >::Item: std::ops::Deref + //~^ ERROR the trait bound `for<'b> >::Item: Deref } pub fn main() { diff --git a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr index 5ab57410c4..cf4ec0babf 100644 --- a/src/test/ui/associated-types/hr-associated-type-projection-1.stderr +++ b/src/test/ui/associated-types/hr-associated-type-projection-1.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'b> >::Item: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `for<'b> >::Item: Deref` is not satisfied --> $DIR/hr-associated-type-projection-1.rs:15:17 | LL | trait UnsafeCopy<'a, T: Copy> @@ -8,22 +8,22 @@ LL | for<'b> >::Item: std::ops::Deref, | --------------------------- required by this bound in `UnsafeCopy` ... LL | type Item = T; - | ^ the trait `for<'b> std::ops::Deref` is not implemented for `>::Item` + | ^ the trait `for<'b> Deref` is not implemented for `>::Item` | = help: the following implementations were found: - <&T as std::ops::Deref> - <&mut T as std::ops::Deref> + <&T as Deref> + <&mut T as Deref> -error[E0277]: the trait bound `>::Item: std::ops::Deref` is not satisfied +error[E0277]: the trait bound `>::Item: Deref` is not satisfied --> $DIR/hr-associated-type-projection-1.rs:13:33 | LL | impl UnsafeCopy<'_, T> for T { - | ^^^^^^^^^^^^^^^^^ the trait `std::ops::Deref` is not implemented for `>::Item` + | ^^^^^^^^^^^^^^^^^ the trait `Deref` is not implemented for `>::Item` | help: consider further restricting the associated type | -LL | impl UnsafeCopy<'_, T> for T where >::Item: std::ops::Deref { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl UnsafeCopy<'_, T> for T where >::Item: Deref { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/associated-types/issue-43924.stderr b/src/test/ui/associated-types/issue-43924.stderr index f21846fd82..661730bcd7 100644 --- a/src/test/ui/associated-types/issue-43924.stderr +++ b/src/test/ui/associated-types/issue-43924.stderr @@ -1,12 +1,12 @@ -error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied +error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied --> $DIR/issue-43924.rs:7:15 | LL | trait Foo { | -------------------------------- required by `Foo` LL | type Out: Default + ToString + ?Sized = dyn ToString; - | ^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + | ^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)` -error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied +error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied --> $DIR/issue-43924.rs:10:6 | LL | trait Foo { @@ -15,9 +15,9 @@ LL | type Out: Default + ToString + ?Sized = dyn ToString; | ------- required by this bound in `Foo` ... LL | impl Foo for () {} - | ^^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + | ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)` -error[E0277]: the trait bound `(dyn std::string::ToString + 'static): std::default::Default` is not satisfied +error[E0277]: the trait bound `(dyn ToString + 'static): Default` is not satisfied --> $DIR/issue-43924.rs:11:6 | LL | trait Foo { @@ -26,7 +26,7 @@ LL | type Out: Default + ToString + ?Sized = dyn ToString; | ------- required by this bound in `Foo` ... LL | impl Foo for () {} - | ^^^^^^^^ the trait `std::default::Default` is not implemented for `(dyn std::string::ToString + 'static)` + | ^^^^^^^^ the trait `Default` is not implemented for `(dyn ToString + 'static)` error: aborting due to 3 previous errors diff --git a/src/test/ui/associated-types/issue-63593.stderr b/src/test/ui/associated-types/issue-63593.stderr index be3b61665b..ddc0bf436f 100644 --- a/src/test/ui/associated-types/issue-63593.stderr +++ b/src/test/ui/associated-types/issue-63593.stderr @@ -8,8 +8,8 @@ LL | type This = Self; | help: consider further restricting `Self` | -LL | trait MyTrait: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^ +LL | trait MyTrait: Sized { + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/associated-types/missing-associated-types.stderr b/src/test/ui/associated-types/missing-associated-types.stderr index 49003c7445..63164480a0 100644 --- a/src/test/ui/associated-types/missing-associated-types.stderr +++ b/src/test/ui/associated-types/missing-associated-types.stderr @@ -6,10 +6,10 @@ LL | type Foo = dyn Add + Sub + X + Y; | | | 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::ops::Add + std::ops::Sub + X + Y {}` + = 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 {}` = 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 `std::ops::Add`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Sub`) must be specified +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 --> $DIR/missing-associated-types.rs:12:21 | LL | type A; @@ -35,10 +35,10 @@ LL | type Bar = dyn Add + Sub + X + Z; | | | 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::ops::Add + std::ops::Sub + X + Z {}` + = 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 {}` = 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 `std::ops::Add`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Sub`) must be specified +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 --> $DIR/missing-associated-types.rs:15:21 | LL | type A; @@ -49,7 +49,7 @@ LL | type B; LL | type Bar = dyn Add + Sub + X + Z; | ^^^^^^^^ ^^^^^^^^ ^^^^^^ ^^^^^^ associated types `A`, `B`, `Output` must be specified | | | | - | | | associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | | | associated types `Output` (from trait `Mul`), `Output` (from trait `Div`) must be specified | | associated type `Output` must be specified | associated type `Output` must be specified | @@ -71,10 +71,10 @@ LL | type Baz = dyn Add + Sub + Y; | | | 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::ops::Add + std::ops::Sub + Y {}` + = help: consider creating a new trait with all of these as super-traits 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 `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified +error[E0191]: the value of the associated types `A` (from trait `Y`), `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified --> $DIR/missing-associated-types.rs:18:21 | LL | type A; @@ -99,10 +99,10 @@ LL | type Bat = dyn Add + Sub + Fine; | | | 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::ops::Add + std::ops::Sub + Fine {}` + = help: consider creating a new trait with all of these as super-traits 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 `std::ops::Add`), `Output` (from trait `std::ops::Sub`) must be specified +error[E0191]: the value of the associated types `Output` (from trait `Add`), `Output` (from trait `Sub`) must be specified --> $DIR/missing-associated-types.rs:21:21 | LL | type Bat = dyn Add + Sub + Fine; @@ -115,11 +115,11 @@ help: specify the associated types LL | type Bat = dyn Add + Sub + Fine; | ^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^^^^ -error[E0191]: the value of the associated types `Output` (from trait `std::ops::Div`), `Output` (from trait `std::ops::Mul`) must be specified +error[E0191]: the value of the associated types `Output` (from trait `Div`), `Output` (from trait `Mul`) must be specified --> $DIR/missing-associated-types.rs:24:21 | LL | type Bal = dyn X; - | ^^^^^^ associated types `Output` (from trait `std::ops::Mul`), `Output` (from trait `std::ops::Div`) must be specified + | ^^^^^^ associated types `Output` (from trait `Mul`), `Output` (from trait `Div`) must be specified | = help: consider introducing a new type parameter, adding `where` constraints using the fully-qualified path to the associated types diff --git a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr index cfdf5bd53e..8fdca54d2d 100644 --- a/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr +++ b/src/test/ui/associated-types/trait-with-supertraits-needing-sized-self.stderr @@ -7,12 +7,12 @@ LL | trait ArithmeticOps: Add + Sub + Mul ::: $SRC_DIR/core/src/ops/arith.rs:LL:COL | LL | pub trait Add { - | --- required by this bound in `std::ops::Add` + | --- required by this bound in `Add` | help: consider further restricting `Self` | -LL | trait ArithmeticOps: Add + Sub + Mul + Div + std::marker::Sized {} - | ^^^^^^^^^^^^^^^^^^^^ +LL | trait ArithmeticOps: Add + Sub + Mul + Div + Sized {} + | ^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/ast-json/ast-json-noexpand-output.stdout b/src/test/ui/ast-json/ast-json-noexpand-output.stdout index d0942f78bb..3d7d476cf6 100644 --- a/src/test/ui/ast-json/ast-json-noexpand-output.stdout +++ b/src/test/ui/ast-json/ast-json-noexpand-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/ast-json/ast-json-output.stdout b/src/test/ui/ast-json/ast-json-output.stdout index dc06fd74a4..a4ce6061b4 100644 --- a/src/test/ui/ast-json/ast-json-output.stdout +++ b/src/test/ui/ast-json/ast-json-output.stdout @@ -1 +1 @@ -{"module":{"inner":{"lo":0,"hi":0},"items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":"Empty"}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"node":"Inherited","span":{"lo":0,"hi":0}},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}]},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"NonJoint"]]}]}}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} +{"module":{"inner":{"lo":0,"hi":0},"unsafety":"No","items":[{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"prelude_import","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"","span":{"lo":0,"hi":0}},"kind":{"variant":"Use","fields":[{"prefix":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"{{root}}","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"std","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"prelude","span":{"lo":0,"hi":0}},"id":0,"args":null},{"ident":{"name":"v1","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"kind":"Glob","span":{"lo":0,"hi":0}}]},"tokens":null},{"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"macro_use","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":"Empty","tokens":null}]},"id":null,"style":"Outer","span":{"lo":0,"hi":0}}],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"std","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null},{"attrs":[],"id":0,"span":{"lo":0,"hi":0},"vis":{"kind":"Inherited","span":{"lo":0,"hi":0},"tokens":null},"ident":{"name":"core","span":{"lo":0,"hi":0}},"kind":{"variant":"ExternCrate","fields":[null]},"tokens":null}],"inline":true},"attrs":[{"kind":{"variant":"Normal","fields":[{"path":{"span":{"lo":0,"hi":0},"segments":[{"ident":{"name":"crate_type","span":{"lo":0,"hi":0}},"id":0,"args":null}],"tokens":null},"args":{"variant":"Eq","fields":[{"lo":0,"hi":0},{"0":[[{"variant":"Token","fields":[{"kind":{"variant":"Literal","fields":[{"kind":"Str","symbol":"lib","suffix":null}]},"span":{"lo":0,"hi":0}}]},"Alone"]]}]},"tokens":null}]},"id":null,"style":"Inner","span":{"lo":0,"hi":0}}],"span":{"lo":0,"hi":0},"proc_macros":[]} diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs index 971d447633..5bc7069ff8 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.rs +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.rs @@ -4,7 +4,6 @@ // 3. get targeted by `?` and not the parent function. // // edition:2018 -// ignore-tidy-linelength fn main() {} @@ -16,7 +15,7 @@ fn return_targets_async_block_not_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR type mismatch resolving `::Output == ()` + //~^ ERROR type mismatch resolving `::Output == ()` } async fn return_targets_async_block_not_async_fn() -> u8 { @@ -25,7 +24,7 @@ async fn return_targets_async_block_not_async_fn() -> u8 { return 0u8; }; let _: &dyn Future = █ - //~^ ERROR type mismatch resolving `::Output == ()` + //~^ ERROR type mismatch resolving `::Output == ()` } fn no_break_in_async_block() { diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index 46a132da30..dbdfb2e71e 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,5 +1,5 @@ error[E0267]: `break` inside of an `async` block - --> $DIR/async-block-control-flow-static-semantics.rs:33:9 + --> $DIR/async-block-control-flow-static-semantics.rs:32:9 | LL | async { | ___________- @@ -9,7 +9,7 @@ LL | | }; | |_____- enclosing `async` block error[E0267]: `break` inside of an `async` block - --> $DIR/async-block-control-flow-static-semantics.rs:40:13 + --> $DIR/async-block-control-flow-static-semantics.rs:39:13 | LL | async { | _______________- @@ -19,7 +19,7 @@ LL | | }; | |_________- enclosing `async` block error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:22:58 + --> $DIR/async-block-control-flow-static-semantics.rs:21:58 | LL | async fn return_targets_async_block_not_async_fn() -> u8 { | __________________________________________________________^ @@ -31,32 +31,32 @@ LL | | LL | | } | |_^ expected `u8`, found `()` -error[E0271]: type mismatch resolving `::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:27:39 +error[E0271]: type mismatch resolving `::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:26:39 | LL | let _: &dyn Future = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast to the object type `dyn std::future::Future` + = note: required for the cast to the object type `dyn Future` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:13:43 + --> $DIR/async-block-control-flow-static-semantics.rs:12:43 | LL | fn return_targets_async_block_not_fn() -> u8 { | --------------------------------- ^^ expected `u8`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression -error[E0271]: type mismatch resolving `::Output == ()` - --> $DIR/async-block-control-flow-static-semantics.rs:18:39 +error[E0271]: type mismatch resolving `::Output == ()` + --> $DIR/async-block-control-flow-static-semantics.rs:17:39 | LL | let _: &dyn Future = █ | ^^^^^^ expected `()`, found `u8` | - = note: required for the cast to the object type `dyn std::future::Future` + = note: required for the cast to the object type `dyn Future` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:48:44 + --> $DIR/async-block-control-flow-static-semantics.rs:47:44 | LL | fn rethrow_targets_async_block_not_fn() -> Result { | ---------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `()` @@ -67,7 +67,7 @@ LL | fn rethrow_targets_async_block_not_fn() -> Result { found unit type `()` error[E0308]: mismatched types - --> $DIR/async-block-control-flow-static-semantics.rs:57:50 + --> $DIR/async-block-control-flow-static-semantics.rs:56:50 | LL | fn rethrow_targets_async_block_not_async_fn() -> Result { | ---------------------------------------- ^^^^^^^^^^^^^^^^^ expected enum `std::result::Result`, found `()` diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index 9523f040aa..d808a5939b 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -7,7 +7,7 @@ LL | LL | panic!() | -------- this returned value is of type `!` | - = help: the trait `std::future::Future` is not implemented for `()` + = help: the trait `Future` is not implemented for `()` = note: the return type of a function must have a statically known size error[E0698]: type inside `async fn` body must be known in this context diff --git a/src/test/ui/async-await/async-fn-nonsend.stderr b/src/test/ui/async-await/async-fn-nonsend.stderr index d36d59f1f6..cd0db4cc01 100644 --- a/src/test/ui/async-await/async-fn-nonsend.stderr +++ b/src/test/ui/async-await/async-fn-nonsend.stderr @@ -7,12 +7,12 @@ LL | fn assert_send(_: impl Send) {} LL | assert_send(local_dropped_before_await()); | ^^^^^^^^^^^ future returned by `local_dropped_before_await` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:24:5 | LL | let x = non_send(); - | - has type `impl std::fmt::Debug` which is not `Send` + | - has type `impl Debug` which is not `Send` LL | drop(x); LL | fut().await; | ^^^^^^^^^^^ await occurs here, with `x` maybe used later @@ -28,12 +28,12 @@ LL | fn assert_send(_: impl Send) {} LL | assert_send(non_send_temporary_in_match()); | ^^^^^^^^^^^ future returned by `non_send_temporary_in_match` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = help: within `impl Future`, the trait `Send` is not implemented for `Rc<()>` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:33:20 | LL | match Some(non_send()) { - | ---------- has type `impl std::fmt::Debug` which is not `Send` + | ---------- has type `impl Debug` which is not `Send` LL | Some(_) => fut().await, | ^^^^^^^^^^^ await occurs here, with `non_send()` maybe used later ... @@ -49,12 +49,12 @@ LL | fn assert_send(_: impl Send) {} LL | assert_send(non_sync_with_method_call()); | ^^^^^^^^^^^ future returned by `non_sync_with_method_call` is not `Send` | - = help: the trait `std::marker::Send` is not implemented for `dyn std::fmt::Write` + = help: the trait `Send` is not implemented for `dyn std::fmt::Write` note: future is not `Send` as this value is used across an await --> $DIR/async-fn-nonsend.rs:42:9 | LL | let f: &mut std::fmt::Formatter = panic!(); - | - has type `&mut std::fmt::Formatter<'_>` which is not `Send` + | - has type `&mut Formatter<'_>` which is not `Send` LL | if non_sync().fmt(f).unwrap() == () { LL | fut().await; | ^^^^^^^^^^^ await occurs here, with `f` maybe used later diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs index cebff3be6b..337487fc80 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.rs @@ -14,7 +14,7 @@ async fn foo2() -> Result<(), ()> { } async fn foo3() -> Result<(), ()> { let _ = await bar()?; //~ ERROR incorrect use of `await` - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } async fn foo21() -> Result<(), ()> { @@ -62,7 +62,7 @@ fn foo10() -> Result<(), ()> { fn foo11() -> Result<(), ()> { let _ = await bar()?; //~ ERROR `await` is only allowed inside `async` functions and blocks //~^ ERROR incorrect use of `await` - //~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~| ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } fn foo12() -> Result<(), ()> { diff --git a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr index 96158fc0e0..6a653fc060 100644 --- a/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr +++ b/src/test/ui/async-await/await-keyword/incorrect-syntax-suggestions.stderr @@ -233,26 +233,26 @@ LL | let foo = || { LL | let _ = await!(bar())?; | ^^^^^^^^^^^^^ only allowed inside `async` functions and blocks -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/incorrect-syntax-suggestions.rs:16:19 | LL | let _ = await bar()?; | ^^^^^^ | | - | the `?` operator cannot be applied to type `impl std::future::Future` + | the `?` operator cannot be applied to type `impl Future` | help: consider using `.await` here: `bar().await?` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/incorrect-syntax-suggestions.rs:63:19 | LL | let _ = await bar()?; - | ^^^^^^ the `?` operator cannot be applied to type `impl std::future::Future` + | ^^^^^^ the `?` operator cannot be applied to type `impl Future` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` error: aborting due to 36 previous errors diff --git a/src/test/ui/async-await/dont-suggest-missing-await.stderr b/src/test/ui/async-await/dont-suggest-missing-await.stderr index dc3a4752fb..e70ed9badb 100644 --- a/src/test/ui/async-await/dont-suggest-missing-await.stderr +++ b/src/test/ui/async-await/dont-suggest-missing-await.stderr @@ -8,7 +8,7 @@ LL | take_u32(x) | ^ expected `u32`, found opaque type | = note: expected type `u32` - found opaque type `impl std::future::Future` + found opaque type `impl Future` error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-61076.rs b/src/test/ui/async-await/issue-61076.rs index 13b45df64e..b1216ff4c4 100644 --- a/src/test/ui/async-await/issue-61076.rs +++ b/src/test/ui/async-await/issue-61076.rs @@ -6,6 +6,26 @@ use core::task::{Context, Poll}; struct T; +struct Tuple(i32); + +struct Struct { + a: i32 +} + +impl Struct { + fn method(&self) {} +} + +impl Future for Struct { + type Output = Struct; + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { Poll::Pending } +} + +impl Future for Tuple { + type Output = Tuple; + fn poll(self: Pin<&mut Self>, _: &mut Context<'_>) -> Poll { Poll::Pending } +} + impl Future for T { type Output = Result<(), ()>; @@ -19,14 +39,35 @@ async fn foo() -> Result<(), ()> { } async fn bar() -> Result<(), ()> { - foo()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + foo()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } +async fn struct_() -> Struct { + Struct { a: 1 } +} + +async fn tuple() -> Tuple { + Tuple(1i32) +} + async fn baz() -> Result<(), ()> { let t = T; - t?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + t?; //~ ERROR the `?` operator can only be applied to values that implement `Try` + + let _: i32 = tuple().0; //~ ERROR no field `0` + + let _: i32 = struct_().a; //~ ERROR no field `a` + + struct_().method(); //~ ERROR no method named + Ok(()) } +async fn match_() { + match tuple() { + Tuple(_) => {} //~ ERROR mismatched types + } +} + fn main() {} diff --git a/src/test/ui/async-await/issue-61076.stderr b/src/test/ui/async-await/issue-61076.stderr index e71f4e7136..f1f1b2d443 100644 --- a/src/test/ui/async-await/issue-61076.stderr +++ b/src/test/ui/async-await/issue-61076.stderr @@ -1,17 +1,17 @@ -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` - --> $DIR/issue-61076.rs:22:5 +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-61076.rs:42:5 | LL | foo()?; | ^^^^^^ | | - | the `?` operator cannot be applied to type `impl std::future::Future` + | the `?` operator cannot be applied to type `impl Future` | help: consider using `.await` here: `foo().await?` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` - --> $DIR/issue-61076.rs:28:5 +error[E0277]: the `?` operator can only be applied to values that implement `Try` + --> $DIR/issue-61076.rs:56:5 | LL | t?; | ^^ @@ -19,9 +19,59 @@ LL | t?; | the `?` operator cannot be applied to type `T` | help: consider using `.await` here: `t.await?` | - = help: the trait `std::ops::Try` is not implemented for `T` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `T` + = note: required by `into_result` -error: aborting due to 2 previous errors +error[E0609]: no field `0` on type `impl Future` + --> $DIR/issue-61076.rs:58:26 + | +LL | let _: i32 = tuple().0; + | ^ + | +help: consider awaiting before field access + | +LL | let _: i32 = tuple().await.0; + | ^^^^^^ -For more information about this error, try `rustc --explain E0277`. +error[E0609]: no field `a` on type `impl Future` + --> $DIR/issue-61076.rs:60:28 + | +LL | let _: i32 = struct_().a; + | ^ + | +help: consider awaiting before field access + | +LL | let _: i32 = struct_().await.a; + | ^^^^^^ + +error[E0599]: no method named `method` found for opaque type `impl Future` in the current scope + --> $DIR/issue-61076.rs:62:15 + | +LL | struct_().method(); + | ^^^^^^ method not found in `impl Future` + | +help: consider awaiting before this method call + | +LL | struct_().await.method(); + | ^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-61076.rs:69:9 + | +LL | async fn tuple() -> Tuple { + | ----- the `Output` of this `async fn`'s expected opaque type +... +LL | Tuple(_) => {} + | ^^^^^^^^ expected opaque type, found struct `Tuple` + | + = note: expected opaque type `impl Future` + found struct `Tuple` +help: consider awaiting on the future + | +LL | match tuple().await { + | ^^^^^^ + +error: aborting due to 6 previous errors + +Some errors have detailed explanations: E0277, E0308, E0599, E0609. +For more information about an error, try `rustc --explain E0277`. diff --git a/src/test/ui/async-await/issue-64130-1-sync.stderr b/src/test/ui/async-await/issue-64130-1-sync.stderr index 42e9e4642c..ab73236800 100644 --- a/src/test/ui/async-await/issue-64130-1-sync.stderr +++ b/src/test/ui/async-await/issue-64130-1-sync.stderr @@ -7,7 +7,7 @@ LL | fn is_sync(t: T) { } LL | is_sync(bar()); | ^^^^^^^ future returned by `bar` is not `Sync` | - = help: within `impl std::future::Future`, the trait `std::marker::Sync` is not implemented for `Foo` + = help: within `impl Future`, the trait `Sync` is not implemented for `Foo` note: future is not `Sync` as this value is used across an await --> $DIR/issue-64130-1-sync.rs:15:5 | diff --git a/src/test/ui/async-await/issue-64130-2-send.stderr b/src/test/ui/async-await/issue-64130-2-send.stderr index f6f834618d..5f7440a72d 100644 --- a/src/test/ui/async-await/issue-64130-2-send.stderr +++ b/src/test/ui/async-await/issue-64130-2-send.stderr @@ -7,7 +7,7 @@ LL | fn is_send(t: T) { } LL | is_send(bar()); | ^^^^^^^ future returned by `bar` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `Foo` + = help: within `impl Future`, the trait `Send` is not implemented for `Foo` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-2-send.rs:15:5 | diff --git a/src/test/ui/async-await/issue-64130-3-other.rs b/src/test/ui/async-await/issue-64130-3-other.rs index b819970d59..133152c309 100644 --- a/src/test/ui/async-await/issue-64130-3-other.rs +++ b/src/test/ui/async-await/issue-64130-3-other.rs @@ -22,5 +22,5 @@ async fn baz() { } fn main() { is_qux(bar()); - //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future` + //~^ ERROR the trait bound `Foo: Qux` is not satisfied in `impl Future` } diff --git a/src/test/ui/async-await/issue-64130-3-other.stderr b/src/test/ui/async-await/issue-64130-3-other.stderr index 3475b66b37..4bf43f14cc 100644 --- a/src/test/ui/async-await/issue-64130-3-other.stderr +++ b/src/test/ui/async-await/issue-64130-3-other.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl std::future::Future` +error[E0277]: the trait bound `Foo: Qux` is not satisfied in `impl Future` --> $DIR/issue-64130-3-other.rs:24:5 | LL | fn is_qux(t: T) { } | --- required by this bound in `is_qux` LL | LL | async fn bar() { - | - within this `impl std::future::Future` + | - within this `impl Future` ... LL | is_qux(bar()); - | ^^^^^^ within `impl std::future::Future`, the trait `Qux` is not implemented for `Foo` + | ^^^^^^ within `impl Future`, the trait `Qux` is not implemented for `Foo` | = help: the following implementations were found: diff --git a/src/test/ui/async-await/issue-64130-4-async-move.stderr b/src/test/ui/async-await/issue-64130-4-async-move.stderr index fc231d394c..440ea0a38e 100644 --- a/src/test/ui/async-await/issue-64130-4-async-move.stderr +++ b/src/test/ui/async-await/issue-64130-4-async-move.stderr @@ -11,9 +11,9 @@ LL | | let _x = get().await; ... | LL | | } LL | | } - | |_____- this returned value is of type `impl std::future::Future` + | |_____- this returned value is of type `impl Future` | - = help: the trait `std::marker::Sync` is not implemented for `(dyn std::any::Any + std::marker::Send + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Any + Send + 'static)` note: future is not `Send` as this value is used across an await --> $DIR/issue-64130-4-async-move.rs:21:26 | diff --git a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr index f72757339c..2d6615cd5d 100644 --- a/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr +++ b/src/test/ui/async-await/issue-64130-non-send-future-diags.stderr @@ -7,12 +7,12 @@ LL | fn is_send(t: T) { } LL | is_send(foo()); | ^^^^^^^ future returned by `foo` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, u32>` + = 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 | LL | let g = x.lock().unwrap(); - | - has type `std::sync::MutexGuard<'_, u32>` which is not `Send` + | - has type `MutexGuard<'_, u32>` which is not `Send` LL | baz().await; | ^^^^^^^^^^^ await occurs here, with `g` maybe used later LL | } diff --git a/src/test/ui/async-await/issue-67252-unnamed-future.stderr b/src/test/ui/async-await/issue-67252-unnamed-future.stderr index b43478ee20..741623040c 100644 --- a/src/test/ui/async-await/issue-67252-unnamed-future.stderr +++ b/src/test/ui/async-await/issue-67252-unnamed-future.stderr @@ -7,7 +7,7 @@ LL | fn spawn(_: T) {} LL | spawn(async { | ^^^^^ future created by async block is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*mut ()` + = help: within `impl Future`, the trait `Send` is not implemented for `*mut ()` note: future is not `Send` as this value is used across an await --> $DIR/issue-67252-unnamed-future.rs:20:9 | diff --git a/src/test/ui/async-await/issue-68112.rs b/src/test/ui/async-await/issue-68112.rs index 11b1783680..bfabf81d1f 100644 --- a/src/test/ui/async-await/issue-68112.rs +++ b/src/test/ui/async-await/issue-68112.rs @@ -58,7 +58,7 @@ fn test2() { ready(0).await; }; require_send(send_fut); - //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely + //~^ ERROR `RefCell` cannot be shared between threads safely } fn main() {} diff --git a/src/test/ui/async-await/issue-68112.stderr b/src/test/ui/async-await/issue-68112.stderr index 6ded3e475b..e97d088cf3 100644 --- a/src/test/ui/async-await/issue-68112.stderr +++ b/src/test/ui/async-await/issue-68112.stderr @@ -7,12 +7,12 @@ LL | fn require_send(_: impl Send) {} LL | require_send(send_fut); | ^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:31:17 | LL | let _ = non_send_fut.await; - | ^^^^^^^^^^^^ await occurs here on type `impl std::future::Future`, which is not `Send` + | ^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` error: future cannot be sent between threads safely --> $DIR/issue-68112.rs:43:5 @@ -23,33 +23,33 @@ LL | fn require_send(_: impl Send) {} LL | require_send(send_fut); | ^^^^^^^^^^^^ future created by async block is not `Send` | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` note: future is not `Send` as it awaits another future which is not `Send` --> $DIR/issue-68112.rs:40:17 | LL | let _ = make_non_send_future1().await; - | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl std::future::Future`, which is not `Send` + | ^^^^^^^^^^^^^^^^^^^^^^^ await occurs here on type `impl Future`, which is not `Send` -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-68112.rs:60:5 | LL | fn require_send(_: impl Send) {} | ---- required by this bound in `require_send` ... LL | require_send(send_fut); - | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc>` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:std::sync::Arc> {}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 t:std::sync::Arc> {}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `{std::future::ResumeTy, impl std::future::Future, (), i32, Ready}` - = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {std::future::ResumeTy, impl std::future::Future, (), i32, Ready}]>` - = note: required because it appears within the type `impl std::future::Future` + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Send` for `Arc>` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:47:31: 47:36 {}]>` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `{ResumeTy, impl Future, (), i32, Ready}` + = note: required because it appears within the type `[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@$DIR/issue-68112.rs:55:26: 59:6 {ResumeTy, impl Future, (), i32, Ready}]>` + = note: required because it appears within the type `impl Future` error: aborting due to 3 previous errors diff --git a/src/test/ui/async-await/issue-68523.rs b/src/test/ui/async-await/issue-68523.rs index e6250c40c7..718c597e71 100644 --- a/src/test/ui/async-await/issue-68523.rs +++ b/src/test/ui/async-await/issue-68523.rs @@ -2,6 +2,6 @@ async fn main() -> Result { //~^ ERROR `main` function is not allowed to be `async` -//~^^ ERROR `main` has invalid return type `impl std::future::Future` +//~^^ ERROR `main` has invalid return type `impl Future` Ok(1) } diff --git a/src/test/ui/async-await/issue-68523.stderr b/src/test/ui/async-await/issue-68523.stderr index 62e37cf262..6f67af04cd 100644 --- a/src/test/ui/async-await/issue-68523.stderr +++ b/src/test/ui/async-await/issue-68523.stderr @@ -1,8 +1,8 @@ -error[E0277]: `main` has invalid return type `impl std::future::Future` +error[E0277]: `main` has invalid return type `impl Future` --> $DIR/issue-68523.rs:3:20 | LL | async fn main() -> Result { - | ^^^^^^^^^^^^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^^^^^^^^^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index badb7ae9f6..fb1f8e4ffd 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -24,8 +24,8 @@ error[E0277]: `()` is not a future LL | [1; ().await]; | ^^^^^^^^ `()` is not a future | - = help: the trait `std::future::Future` is not implemented for `()` - = note: required by `std::future::Future::poll` + = help: the trait `Future` is not implemented for `()` + = note: required by `poll` error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/issue-70818.stderr b/src/test/ui/async-await/issue-70818.stderr index 2166420070..364194bea1 100644 --- a/src/test/ui/async-await/issue-70818.stderr +++ b/src/test/ui/async-await/issue-70818.stderr @@ -5,7 +5,7 @@ LL | fn foo(ty: T, ty1: U) -> impl Future + Send { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ future created by async block is not `Send` LL | LL | async { (ty, ty1) } - | ------------------- this returned value is of type `impl std::future::Future` + | ------------------- this returned value is of type `impl Future` | note: captured value is not `Send` --> $DIR/issue-70818.rs:6:18 @@ -15,8 +15,8 @@ LL | async { (ty, ty1) } = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | -LL | fn foo(ty: T, ty1: U) -> impl Future + Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo(ty: T, ty1: U) -> impl Future + Send { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-71137.stderr b/src/test/ui/async-await/issue-71137.stderr index 788a9bc2c7..85cc7069b6 100644 --- a/src/test/ui/async-await/issue-71137.stderr +++ b/src/test/ui/async-await/issue-71137.stderr @@ -7,12 +7,12 @@ LL | fn fake_spawn(f: F) { } LL | fake_spawn(wrong_mutex()); | ^^^^^^^^^^ future returned by `wrong_mutex` is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, i32>` + = 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 | LL | let mut guard = m.lock().unwrap(); - | --------- has type `std::sync::MutexGuard<'_, i32>` which is not `Send` + | --------- has type `MutexGuard<'_, i32>` which is not `Send` LL | (async { "right"; }).await; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ await occurs here, with `mut guard` maybe used later LL | *guard += 1; diff --git a/src/test/ui/async-await/issue-72442.stderr b/src/test/ui/async-await/issue-72442.stderr index 3b909689b5..52245b6312 100644 --- a/src/test/ui/async-await/issue-72442.stderr +++ b/src/test/ui/async-await/issue-72442.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::option::Option<&str>: std::convert::AsRef` is not satisfied +error[E0277]: the trait bound `Option<&str>: AsRef` is not satisfied --> $DIR/issue-72442.rs:12:36 | LL | let mut f = File::open(path.to_str())?; - | ^^^^^^^^^^^^^ the trait `std::convert::AsRef` is not implemented for `std::option::Option<&str>` + | ^^^^^^^^^^^^^ the trait `AsRef` is not implemented for `Option<&str>` | ::: $SRC_DIR/std/src/fs.rs:LL:COL | LL | pub fn open>(path: P) -> io::Result { - | ----------- required by this bound in `std::fs::File::open` + | ----------- required by this bound in `File::open` error: aborting due to previous error diff --git a/src/test/ui/async-await/issue-72590-type-error-sized.stderr b/src/test/ui/async-await/issue-72590-type-error-sized.stderr index 762afa6450..785fe21dd3 100644 --- a/src/test/ui/async-await/issue-72590-type-error-sized.stderr +++ b/src/test/ui/async-await/issue-72590-type-error-sized.stderr @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | async fn frob(self) {} | ^^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `str` + = help: within `Foo`, the trait `Sized` is not implemented for `str` = note: required because it appears within the type `Foo` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index e3ba74a03c..c879a65bc7 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -33,8 +33,8 @@ error[E0277]: `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future LL | (|_| 2333).await; | ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future | - = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` - = note: required by `std::future::Future::poll` + = help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` + = note: required by `poll` error: aborting due to 4 previous errors diff --git a/src/test/ui/async-await/issues/issue-65159.rs b/src/test/ui/async-await/issues/issue-65159.rs index 2f80435046..4f160fccc0 100644 --- a/src/test/ui/async-await/issues/issue-65159.rs +++ b/src/test/ui/async-await/issues/issue-65159.rs @@ -5,7 +5,7 @@ async fn copy() -> Result<()> //~ ERROR wrong number of type arguments { Ok(()) - //~^ type annotations needed + //~^ ERROR type annotations needed } fn main() { } diff --git a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr index 49cd30e11a..e4b2725686 100644 --- a/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr +++ b/src/test/ui/async-await/issues/issue-65436-raw-ptr-not-send.stderr @@ -7,7 +7,7 @@ LL | fn assert_send(_: T) {} LL | assert_send(async { | ^^^^^^^^^^^ future created by async block is not `Send` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `*const u8` + = help: within `impl Future`, the trait `Send` is not implemented for `*const u8` note: future is not `Send` as this value is used across an await --> $DIR/issue-65436-raw-ptr-not-send.rs:14:9 | diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs index c8c2702ec4..b7a976a0af 100644 --- a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.rs @@ -8,7 +8,7 @@ impl Ia { async fn crash(self) { Self::partial(self.0); - Self::full(self); //~ ERROR use of moved value: `self` + Self::full(self); //~ ERROR use of partially moved value: `self` } } diff --git a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr index 9177b83dd4..e2a7353987 100644 --- a/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr +++ b/src/test/ui/async-await/issues/issue-66958-non-copy-infered-type-arg.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `self` +error[E0382]: use of partially moved value: `self` --> $DIR/issue-66958-non-copy-infered-type-arg.rs:11:20 | LL | Self::partial(self.0); - | ------ value moved here + | ------ value partially moved here LL | Self::full(self); | ^^^^ value used here after partial move | - = note: move occurs because `self.0` has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because `self.0` has type `S`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/async-await/issues/issue-67893.rs b/src/test/ui/async-await/issues/issue-67893.rs index 9679e3807b..f34ce8081c 100644 --- a/src/test/ui/async-await/issues/issue-67893.rs +++ b/src/test/ui/async-await/issues/issue-67893.rs @@ -7,5 +7,5 @@ fn g(_: impl Send) {} fn main() { g(issue_67893::run()) - //~^ ERROR: `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely + //~^ ERROR: `MutexGuard<'_, ()>` cannot be sent between threads safely } diff --git a/src/test/ui/async-await/issues/issue-67893.stderr b/src/test/ui/async-await/issues/issue-67893.stderr index 343a35a166..af09f0a27b 100644 --- a/src/test/ui/async-await/issues/issue-67893.stderr +++ b/src/test/ui/async-await/issues/issue-67893.stderr @@ -1,23 +1,23 @@ -error[E0277]: `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely +error[E0277]: `MutexGuard<'_, ()>` cannot be sent between threads safely --> $DIR/issue-67893.rs:9:5 | LL | fn g(_: impl Send) {} | ---- required by this bound in `g` ... LL | g(issue_67893::run()) - | ^ `std::sync::MutexGuard<'_, ()>` cannot be sent between threads safely + | ^ `MutexGuard<'_, ()>` cannot be sent between threads safely | ::: $DIR/auxiliary/issue_67893.rs:7:20 | LL | pub async fn run() { - | - within this `impl std::future::Future` + | - within this `impl Future` | - = help: within `impl std::future::Future`, the trait `std::marker::Send` is not implemented for `std::sync::MutexGuard<'_, ()>` - = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {std::future::ResumeTy, std::sync::Arc>, &'r std::sync::Mutex<()>, std::result::Result, std::sync::PoisonError>>, &'t1 std::sync::MutexGuard<'t2, ()>, std::sync::MutexGuard<'t3, ()>, (), impl std::future::Future}` - = note: required because it appears within the type `[static generator@issue_67893::run::{{closure}}#0 for<'r, 's, 't0, 't1, 't2, 't3> {std::future::ResumeTy, std::sync::Arc>, &'r std::sync::Mutex<()>, std::result::Result, std::sync::PoisonError>>, &'t1 std::sync::MutexGuard<'t2, ()>, std::sync::MutexGuard<'t3, ()>, (), impl std::future::Future}]` - = note: required because it appears within the type `std::future::from_generator::GenFuture<[static generator@issue_67893::run::{{closure}}#0 for<'r, 's, 't0, 't1, 't2, 't3> {std::future::ResumeTy, std::sync::Arc>, &'r std::sync::Mutex<()>, std::result::Result, std::sync::PoisonError>>, &'t1 std::sync::MutexGuard<'t2, ()>, std::sync::MutexGuard<'t3, ()>, (), impl std::future::Future}]>` - = note: required because it appears within the type `impl std::future::Future` - = note: required because it appears within the type `impl std::future::Future` + = help: within `impl Future`, the trait `Send` is not implemented for `MutexGuard<'_, ()>` + = note: required because it appears within the type `for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}` + = note: required because it appears within the type `[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]` + = note: required because it appears within the type `from_generator::GenFuture<[static generator@run::{closure#0} for<'r, 's, 't0, 't1, 't2, 't3> {ResumeTy, Arc>, &'r Mutex<()>, std::result::Result, PoisonError>>, &'t1 MutexGuard<'t2, ()>, MutexGuard<'t3, ()>, (), impl Future}]>` + = note: required because it appears within the type `impl Future` + = note: required because it appears within the type `impl Future` error: aborting due to previous error diff --git a/src/test/ui/async-await/no-const-async.rs b/src/test/ui/async-await/no-const-async.rs index 57a9f175ca..b3c59734e0 100644 --- a/src/test/ui/async-await/no-const-async.rs +++ b/src/test/ui/async-await/no-const-async.rs @@ -3,4 +3,3 @@ pub const async fn x() {} //~^ ERROR functions cannot be both `const` and `async` -//~| ERROR `impl Trait` in const fn is unstable diff --git a/src/test/ui/async-await/no-const-async.stderr b/src/test/ui/async-await/no-const-async.stderr index 4e59bb5076..90ec646c8c 100644 --- a/src/test/ui/async-await/no-const-async.stderr +++ b/src/test/ui/async-await/no-const-async.stderr @@ -7,15 +7,5 @@ LL | pub const async fn x() {} | | `async` because of this | `const` because of this -error[E0723]: `impl Trait` in const fn is unstable - --> $DIR/no-const-async.rs:4:24 - | -LL | pub const async fn x() {} - | ^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable +error: aborting due to previous error -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/async-await/no-move-across-await-struct.stderr b/src/test/ui/async-await/no-move-across-await-struct.stderr index adfae09925..4eaed1cf15 100644 --- a/src/test/ui/async-await/no-move-across-await-struct.stderr +++ b/src/test/ui/async-await/no-move-across-await-struct.stderr @@ -6,7 +6,7 @@ LL | needs_vec(s.x).await; LL | s.x | ^^^ value used here after move | - = note: move occurs because `s.x` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `s.x` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/async-await/no-move-across-await-tuple.stderr b/src/test/ui/async-await/no-move-across-await-tuple.stderr index a60fd9361a..d750df9918 100644 --- a/src/test/ui/async-await/no-move-across-await-tuple.stderr +++ b/src/test/ui/async-await/no-move-across-await-tuple.stderr @@ -7,7 +7,7 @@ LL | nothing().await; LL | x.1 | ^^^ value used here after move | - = note: move occurs because `x.1` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `x.1` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/async-await/suggest-missing-await-closure.stderr b/src/test/ui/async-await/suggest-missing-await-closure.stderr index 2703cec581..ed2c4cbfcc 100644 --- a/src/test/ui/async-await/suggest-missing-await-closure.stderr +++ b/src/test/ui/async-await/suggest-missing-await-closure.stderr @@ -11,7 +11,7 @@ LL | take_u32(x) | help: consider using `.await` here: `x.await` | = note: expected type `u32` - found opaque type `impl std::future::Future` + found opaque type `impl Future` error: aborting due to previous error diff --git a/src/test/ui/async-await/suggest-missing-await.stderr b/src/test/ui/async-await/suggest-missing-await.stderr index 6ac05a87aa..c6355680e2 100644 --- a/src/test/ui/async-await/suggest-missing-await.stderr +++ b/src/test/ui/async-await/suggest-missing-await.stderr @@ -11,7 +11,7 @@ LL | take_u32(x) | help: consider using `.await` here: `x.await` | = note: expected type `u32` - found opaque type `impl std::future::Future` + found opaque type `impl Future` error[E0308]: mismatched types --> $DIR/suggest-missing-await.rs:23:5 @@ -23,7 +23,7 @@ LL | dummy() | ^^^^^^^ expected `()`, found opaque type | = note: expected unit type `()` - found opaque type `impl std::future::Future` + found opaque type `impl Future` help: try adding a semicolon | LL | dummy(); diff --git a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr index f623511c0e..695d7dd59f 100644 --- a/src/test/ui/async-await/suggest-switching-edition-on-await.stderr +++ b/src/test/ui/async-await/suggest-switching-edition-on-await.stderr @@ -18,7 +18,7 @@ LL | x.await; = help: set `edition = "2018"` in `Cargo.toml` = note: for more on editions, read https://doc.rust-lang.org/edition-guide -error[E0609]: no field `await` on type `std::pin::Pin<&mut dyn std::future::Future>` +error[E0609]: no field `await` on type `Pin<&mut dyn Future>` --> $DIR/suggest-switching-edition-on-await.rs:31:7 | LL | x.await; diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index 700296d674..8e7823f357 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-in-async.rs:8:9 | LL | async { @@ -10,10 +10,10 @@ LL | | 22 LL | | } | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in an async closure that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-in-async.rs:17:9 | LL | let async_closure = async || { @@ -25,10 +25,10 @@ LL | | 22_u32 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in an async function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-in-async.rs:26:5 | LL | async fn an_async_function() -> u32 { @@ -40,8 +40,8 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` error: aborting due to 3 previous errors diff --git a/src/test/ui/atomic-from-mut-not-available.rs b/src/test/ui/atomic-from-mut-not-available.rs new file mode 100644 index 0000000000..bf94616007 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.rs @@ -0,0 +1,7 @@ +// only-x86 +// only-linux + +fn main() { + core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + //~^ ERROR: no function or associated item named `from_mut` found for struct `AtomicU64` +} diff --git a/src/test/ui/atomic-from-mut-not-available.stderr b/src/test/ui/atomic-from-mut-not-available.stderr new file mode 100644 index 0000000000..d1ebca8a29 --- /dev/null +++ b/src/test/ui/atomic-from-mut-not-available.stderr @@ -0,0 +1,9 @@ +error[E0599]: no function or associated item named `from_mut` found for struct `AtomicU64` in the current scope + --> $DIR/atomic-from-mut-not-available.rs:5:36 + | +LL | core::sync::atomic::AtomicU64::from_mut(&mut 0u64); + | ^^^^^^^^ function or associated item not found in `AtomicU64` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0599`. diff --git a/src/test/ui/attributes/register-attr-tool-prelude.rs b/src/test/ui/attributes/register-attr-tool-prelude.rs index a491773f5e..d217a8146d 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.rs +++ b/src/test/ui/attributes/register-attr-tool-prelude.rs @@ -7,7 +7,7 @@ #[no_implicit_prelude] mod m { #[attr] //~ ERROR cannot find attribute `attr` in this scope - #[tool::attr] //~ ERROR failed to resolve: use of undeclared type or module `tool` + #[tool::attr] //~ ERROR failed to resolve: use of undeclared crate or module `tool` fn check() {} } diff --git a/src/test/ui/attributes/register-attr-tool-prelude.stderr b/src/test/ui/attributes/register-attr-tool-prelude.stderr index 66a4eeb6aa..905b661206 100644 --- a/src/test/ui/attributes/register-attr-tool-prelude.stderr +++ b/src/test/ui/attributes/register-attr-tool-prelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `tool` +error[E0433]: failed to resolve: use of undeclared crate or module `tool` --> $DIR/register-attr-tool-prelude.rs:10:7 | LL | #[tool::attr] - | ^^^^ use of undeclared type or module `tool` + | ^^^^ use of undeclared crate or module `tool` error: cannot find attribute `attr` in this scope --> $DIR/register-attr-tool-prelude.rs:9:7 diff --git a/src/test/ui/auto-ref-slice-plus-ref.stderr b/src/test/ui/auto-ref-slice-plus-ref.stderr index dc7deb8a7c..eb8447ff0f 100644 --- a/src/test/ui/auto-ref-slice-plus-ref.stderr +++ b/src/test/ui/auto-ref-slice-plus-ref.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `test_mut` found for struct `std::vec::Vec<{integer}>` in the current scope +error[E0599]: no method named `test_mut` found for struct `Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:7:7 | LL | a.test_mut(); @@ -11,11 +11,11 @@ note: `MyIter` defines an item `test_mut`, perhaps you need to implement it LL | trait MyIter { | ^^^^^^^^^^^^ -error[E0599]: no method named `test` found for struct `std::vec::Vec<{integer}>` in the current scope +error[E0599]: no method named `test` found for struct `Vec<{integer}>` in the current scope --> $DIR/auto-ref-slice-plus-ref.rs:8:7 | LL | a.test(); - | ^^^^ method not found in `std::vec::Vec<{integer}>` + | ^^^^ method not found in `Vec<{integer}>` | = help: items from traits can only be used if the trait is implemented and in scope note: `MyIter` defines an item `test`, perhaps you need to implement it diff --git a/src/test/ui/autoderef-full-lval.rs b/src/test/ui/autoderef-full-lval.rs index 4bef1012e3..f07a2c107b 100644 --- a/src/test/ui/autoderef-full-lval.rs +++ b/src/test/ui/autoderef-full-lval.rs @@ -13,13 +13,13 @@ fn main() { let a: Clam = Clam{x: box 1, y: box 2}; let b: Clam = Clam{x: box 10, y: box 20}; let z: isize = a.x + b.y; - //~^ ERROR cannot add `std::boxed::Box` to `std::boxed::Box` + //~^ 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 answer: isize = forty.a + two.a; - //~^ ERROR cannot add `std::boxed::Box` to `std::boxed::Box` + //~^ ERROR cannot add `Box` to `Box` println!("{}", answer); assert_eq!(answer, 42); } diff --git a/src/test/ui/autoderef-full-lval.stderr b/src/test/ui/autoderef-full-lval.stderr index f094388794..9921ce7c15 100644 --- a/src/test/ui/autoderef-full-lval.stderr +++ b/src/test/ui/autoderef-full-lval.stderr @@ -1,18 +1,18 @@ -error[E0369]: cannot add `std::boxed::Box` to `std::boxed::Box` +error[E0369]: cannot add `Box` to `Box` --> $DIR/autoderef-full-lval.rs:15:24 | LL | let z: isize = a.x + b.y; - | --- ^ --- std::boxed::Box + | --- ^ --- Box | | - | std::boxed::Box + | Box -error[E0369]: cannot add `std::boxed::Box` to `std::boxed::Box` +error[E0369]: cannot add `Box` to `Box` --> $DIR/autoderef-full-lval.rs:21:33 | LL | let answer: isize = forty.a + two.a; - | ------- ^ ----- std::boxed::Box + | ------- ^ ----- Box | | - | std::boxed::Box + | Box error: aborting due to 2 previous errors diff --git a/src/test/ui/auxiliary/using-target-feature-unstable.rs b/src/test/ui/auxiliary/using-target-feature-unstable.rs index 78645c284f..2682028936 100644 --- a/src/test/ui/auxiliary/using-target-feature-unstable.rs +++ b/src/test/ui/auxiliary/using-target-feature-unstable.rs @@ -1,5 +1,5 @@ -#![feature(mmx_target_feature)] +#![feature(avx512_target_feature)] #[inline] -#[target_feature(enable = "mmx")] +#[target_feature(enable = "avx512ifma")] pub unsafe fn foo() {} diff --git a/src/test/ui/bad/bad-const-type.rs b/src/test/ui/bad/bad-const-type.rs index ce9ea7bc9e..934ee353da 100644 --- a/src/test/ui/bad/bad-const-type.rs +++ b/src/test/ui/bad/bad-const-type.rs @@ -1,4 +1,4 @@ static i: String = 10; //~^ ERROR mismatched types -//~| expected struct `std::string::String`, found integer +//~| expected struct `String`, found integer fn main() { println!("{}", i); } diff --git a/src/test/ui/bad/bad-const-type.stderr b/src/test/ui/bad/bad-const-type.stderr index f667779fab..a9c84b4b41 100644 --- a/src/test/ui/bad/bad-const-type.stderr +++ b/src/test/ui/bad/bad-const-type.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | static i: String = 10; | ^^ | | - | expected struct `std::string::String`, found integer + | expected struct `String`, found integer | help: try using a conversion method: `10.to_string()` error: aborting due to previous error diff --git a/src/test/ui/bad/bad-expr-path.stderr b/src/test/ui/bad/bad-expr-path.stderr index 56bb6e2be8..77c48c951a 100644 --- a/src/test/ui/bad/bad-expr-path.stderr +++ b/src/test/ui/bad/bad-expr-path.stderr @@ -23,7 +23,7 @@ LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | = note: expected fn pointer `fn()` - found fn pointer `fn(std::vec::Vec)` + found fn pointer `fn(Vec)` error: aborting due to 4 previous errors diff --git a/src/test/ui/bad/bad-expr-path2.stderr b/src/test/ui/bad/bad-expr-path2.stderr index e217c45b26..d06e102717 100644 --- a/src/test/ui/bad/bad-expr-path2.stderr +++ b/src/test/ui/bad/bad-expr-path2.stderr @@ -23,7 +23,7 @@ LL | fn main(arguments: Vec) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ incorrect number of function parameters | = note: expected fn pointer `fn()` - found fn pointer `fn(std::vec::Vec)` + found fn pointer `fn(Vec)` error: aborting due to 4 previous errors diff --git a/src/test/ui/bad/bad-method-typaram-kind.stderr b/src/test/ui/bad/bad-method-typaram-kind.stderr index fd3999ae6f..5b68d97a9e 100644 --- a/src/test/ui/bad/bad-method-typaram-kind.stderr +++ b/src/test/ui/bad/bad-method-typaram-kind.stderr @@ -6,8 +6,8 @@ LL | 1.bar::(); | help: consider further restricting this bound | -LL | fn foo() { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo() { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/bad/bad-module.rs b/src/test/ui/bad/bad-module.rs index a496c816e9..b23e97c2cf 100644 --- a/src/test/ui/bad/bad-module.rs +++ b/src/test/ui/bad/bad-module.rs @@ -1,7 +1,7 @@ fn main() { let foo = thing::len(Vec::new()); - //~^ ERROR failed to resolve: use of undeclared type or module `thing` + //~^ ERROR failed to resolve: use of undeclared crate or module `thing` let foo = foo::bar::baz(); - //~^ ERROR failed to resolve: use of undeclared type or module `foo` + //~^ ERROR failed to resolve: use of undeclared crate or module `foo` } diff --git a/src/test/ui/bad/bad-module.stderr b/src/test/ui/bad/bad-module.stderr index 45d4c5abd9..581a661981 100644 --- a/src/test/ui/bad/bad-module.stderr +++ b/src/test/ui/bad/bad-module.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `thing` +error[E0433]: failed to resolve: use of undeclared crate or module `thing` --> $DIR/bad-module.rs:2:15 | LL | let foo = thing::len(Vec::new()); - | ^^^^^ use of undeclared type or module `thing` + | ^^^^^ use of undeclared crate or module `thing` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/bad-module.rs:5:15 | LL | let foo = foo::bar::baz(); - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/bad/bad-sized.stderr b/src/test/ui/bad/bad-sized.stderr index 93984f1c37..b9bce7fb5f 100644 --- a/src/test/ui/bad/bad-sized.stderr +++ b/src/test/ui/bad/bad-sized.stderr @@ -6,7 +6,7 @@ LL | let x: Vec = Vec::new(); | | | 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 + std::marker::Sized {}` + = help: consider creating a new trait with all of these as super-traits 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 @@ -18,9 +18,9 @@ LL | let x: Vec = Vec::new(); ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | LL | pub struct Vec { - | - required by this bound in `std::vec::Vec` + | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` + = help: the trait `Sized` is not implemented for `dyn Trait` error[E0277]: the size for values of type `dyn Trait` cannot be known at compilation time --> $DIR/bad-sized.rs:4:37 @@ -28,8 +28,8 @@ error[E0277]: the size for values of type `dyn Trait` cannot be known at compila LL | let x: Vec = Vec::new(); | ^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn Trait` - = note: required by `std::vec::Vec::::new` + = help: the trait `Sized` is not implemented for `dyn Trait` + = note: required by `Vec::::new` error: aborting due to 3 previous errors diff --git a/src/test/ui/binding/issue-53114-borrow-checks.stderr b/src/test/ui/binding/issue-53114-borrow-checks.stderr index 2a7a721324..489bf70d92 100644 --- a/src/test/ui/binding/issue-53114-borrow-checks.stderr +++ b/src/test/ui/binding/issue-53114-borrow-checks.stderr @@ -8,26 +8,26 @@ LL | drop(m); LL | match m { _ => { } } // #53114: should eventually be accepted too | ^ value used here after move -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:27:11 | LL | match mm { (_x, _) => { } } - | -- value moved here + | -- value partially moved here LL | match mm { (_, _y) => { } } | ^^ value used here after partial move | - = note: move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:29:11 | LL | match mm { (_, _y) => { } } - | -- value moved here + | -- value partially moved here LL | LL | match mm { (_, _) => { } } | ^^ value used here after partial move | - = note: move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait error[E0382]: use of moved value: `m` --> $DIR/issue-53114-borrow-checks.rs:36:16 @@ -39,26 +39,26 @@ LL | drop(m); LL | if let _ = m { } // #53114: should eventually be accepted too | ^ value used here after move -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:41:22 | LL | if let (_x, _) = mm { } - | -- value moved here + | -- value partially moved here LL | if let (_, _y) = mm { } | ^^ value used here after partial move | - = note: move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.0` has type `M`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `mm` +error[E0382]: use of partially moved value: `mm` --> $DIR/issue-53114-borrow-checks.rs:43:21 | LL | if let (_, _y) = mm { } - | -- value moved here + | -- value partially moved here LL | LL | if let (_, _) = mm { } | ^^ value used here after partial move | - = note: move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait + = note: partial move occurs because `mm.1` has type `M`, which does not implement the `Copy` trait error: aborting due to 6 previous errors diff --git a/src/test/ui/binop/binop-bitxor-str.rs b/src/test/ui/binop/binop-bitxor-str.rs index e98ea4df97..3085cce3f3 100644 --- a/src/test/ui/binop/binop-bitxor-str.rs +++ b/src/test/ui/binop/binop-bitxor-str.rs @@ -1,3 +1,3 @@ -// error-pattern:no implementation for `std::string::String ^ std::string::String` +// error-pattern:no implementation for `String ^ String` fn main() { let x = "a".to_string() ^ "b".to_string(); } diff --git a/src/test/ui/binop/binop-bitxor-str.stderr b/src/test/ui/binop/binop-bitxor-str.stderr index 18c1ce0ff0..f236cd61ef 100644 --- a/src/test/ui/binop/binop-bitxor-str.stderr +++ b/src/test/ui/binop/binop-bitxor-str.stderr @@ -1,10 +1,10 @@ -error[E0369]: no implementation for `std::string::String ^ std::string::String` +error[E0369]: no implementation for `String ^ String` --> $DIR/binop-bitxor-str.rs:3:37 | LL | fn main() { let x = "a".to_string() ^ "b".to_string(); } - | --------------- ^ --------------- std::string::String + | --------------- ^ --------------- String | | - | std::string::String + | String error: aborting due to previous error diff --git a/src/test/ui/blind/blind-item-block-middle.stderr b/src/test/ui/blind/blind-item-block-middle.stderr index d8d15615d7..9db11cf159 100644 --- a/src/test/ui/blind/blind-item-block-middle.stderr +++ b/src/test/ui/blind/blind-item-block-middle.stderr @@ -7,7 +7,7 @@ LL | mod foo { pub struct bar; } LL | let bar = 5; | ^^^ | | - | expected integer, found struct `foo::bar` + | expected integer, found struct `bar` | `bar` is interpreted as a unit struct, not a new binding | help: introduce a new binding instead: `other_bar` diff --git a/src/test/ui/block-result/consider-removing-last-semi.stderr b/src/test/ui/block-result/consider-removing-last-semi.stderr index 15ca831670..7c3d0165c6 100644 --- a/src/test/ui/block-result/consider-removing-last-semi.stderr +++ b/src/test/ui/block-result/consider-removing-last-semi.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:3:15 | LL | pub fn f() -> String { - | - ^^^^^^ expected struct `std::string::String`, found `()` + | - ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression LL | 0u8; @@ -13,7 +13,7 @@ error[E0308]: mismatched types --> $DIR/consider-removing-last-semi.rs:8:15 | LL | pub fn g() -> String { - | - ^^^^^^ expected struct `std::string::String`, found `()` + | - ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression LL | "this won't work".to_string(); diff --git a/src/test/ui/block-result/issue-13428.stderr b/src/test/ui/block-result/issue-13428.stderr index 707d24cd6a..60aa2c5a6b 100644 --- a/src/test/ui/block-result/issue-13428.stderr +++ b/src/test/ui/block-result/issue-13428.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-13428.rs:3:13 | LL | fn foo() -> String { - | --- ^^^^^^ expected struct `std::string::String`, found `()` + | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression ... @@ -13,7 +13,7 @@ error[E0308]: mismatched types --> $DIR/issue-13428.rs:11:13 | LL | fn bar() -> String { - | --- ^^^^^^ expected struct `std::string::String`, found `()` + | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression LL | "foobar".to_string() diff --git a/src/test/ui/block-result/issue-13624.rs b/src/test/ui/block-result/issue-13624.rs index bd1d0de320..4d2844cc5a 100644 --- a/src/test/ui/block-result/issue-13624.rs +++ b/src/test/ui/block-result/issue-13624.rs @@ -6,7 +6,7 @@ mod a { pub fn get_enum_struct_variant() -> () { Enum::EnumStructVariant { x: 1, y: 2, z: 3 } //~^ ERROR mismatched types - //~| expected `()`, found enum `a::Enum` + //~| expected `()`, found enum `Enum` } } @@ -19,7 +19,7 @@ mod b { match enum_struct_variant { a::Enum::EnumStructVariant { x, y, z } => { //~^ ERROR mismatched types - //~| expected `()`, found enum `a::Enum` + //~| expected `()`, found enum `Enum` } } } diff --git a/src/test/ui/block-result/issue-13624.stderr b/src/test/ui/block-result/issue-13624.stderr index 416f055251..13070b4e82 100644 --- a/src/test/ui/block-result/issue-13624.stderr +++ b/src/test/ui/block-result/issue-13624.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | pub fn get_enum_struct_variant() -> () { | -- expected `()` because of return type LL | Enum::EnumStructVariant { x: 1, y: 2, z: 3 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `a::Enum` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `Enum` error[E0308]: mismatched types --> $DIR/issue-13624.rs:20:9 @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | match enum_struct_variant { | ------------------- this expression has type `()` LL | a::Enum::EnumStructVariant { x, y, z } => { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `a::Enum` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found enum `Enum` error: aborting due to 2 previous errors diff --git a/src/test/ui/block-result/issue-20862.stderr b/src/test/ui/block-result/issue-20862.stderr index 560c9c2fbe..09c06e8428 100644 --- a/src/test/ui/block-result/issue-20862.stderr +++ b/src/test/ui/block-result/issue-20862.stderr @@ -7,7 +7,7 @@ LL | |y| x + y | ^^^^^^^^^ expected `()`, found closure | = note: expected unit type `()` - found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14 x:_]` + found closure `[closure@$DIR/issue-20862.rs:2:5: 2:14]` error[E0618]: expected function, found `()` --> $DIR/issue-20862.rs:7:13 diff --git a/src/test/ui/block-result/issue-22645.stderr b/src/test/ui/block-result/issue-22645.stderr index 79eb1d4b89..6649e67a50 100644 --- a/src/test/ui/block-result/issue-22645.stderr +++ b/src/test/ui/block-result/issue-22645.stderr @@ -6,7 +6,7 @@ LL | b + 3 | = help: the following implementations were found: - = note: required because of the requirements on the impl of `std::ops::Add<{integer}>` for `Bob` + = note: required because of the requirements on the impl of `Add<{integer}>` for `Bob` error[E0308]: mismatched types --> $DIR/issue-22645.rs:15:3 diff --git a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr index 35ed2763c2..1bf8158927 100644 --- a/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr +++ b/src/test/ui/borrowck/bindings-after-at-or-patterns-slice-patterns-box-patterns.stderr @@ -20,7 +20,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:22:5 | LL | fn bindings_after_at_slice_patterns_move_binding(x: [String; 4]) { - | - move occurs because `x` has type `[std::string::String; 4]`, which does not implement the `Copy` trait + | - move occurs because `x` has type `[String; 4]`, which does not implement the `Copy` trait LL | match x { LL | a @ [.., _] => (), | ----------- value moved here @@ -68,7 +68,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:80:5 | LL | fn bindings_after_at_or_patterns_move(x: Option) { - | - move occurs because `x` has type `std::option::Option`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Option`, which does not implement the `Copy` trait LL | match x { LL | foo @ Some(Test::Foo | Test::Bar) => (), | --------------------------------- @@ -119,7 +119,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/bindings-after-at-or-patterns-slice-patterns-box-patterns.rs:138:5 | LL | fn bindings_after_at_slice_patterns_or_patterns_moves(x: [Option; 4]) { - | - move occurs because `x` has type `[std::option::Option; 4]`, which does not implement the `Copy` trait + | - move occurs because `x` has type `[Option; 4]`, which does not implement the `Copy` trait LL | match x { LL | a @ [.., Some(Test::Foo | Test::Bar)] => (), | ------------------------------------- diff --git a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs index 75bf320dd5..7a88c3df2e 100644 --- a/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs +++ b/src/test/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.rs @@ -1,7 +1,7 @@ // Test that attempt to reborrow an `&mut` pointer in an aliasable // location yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md fn foo(t0: & &mut isize) { let t1 = t0; diff --git a/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs b/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs index 2839a9195a..5ef282c0ca 100644 --- a/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs +++ b/src/test/ui/borrowck/borrowck-borrow-of-mut-base-ptr-safe.rs @@ -5,7 +5,7 @@ // Test that freezing an `&mut` pointer while referent is // frozen is legal. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md // pretty-expanded FIXME #23616 diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr index 6f2b20285b..426d5bc472 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-auto-deref.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut x.y; | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:40:19 @@ -12,7 +12,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut x.y; | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:48:5 @@ -20,7 +20,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut x.y | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:52:5 @@ -28,7 +28,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut x.y | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:56:5 @@ -36,7 +36,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | x.y = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:60:5 @@ -44,7 +44,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | x.y = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:64:5 @@ -52,7 +52,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | x.y = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:72:5 @@ -60,7 +60,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.set(0, 0); | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:76:5 @@ -68,7 +68,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.set(0, 0); | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:84:5 @@ -76,7 +76,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.y_mut() | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:88:5 @@ -84,7 +84,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | x.y_mut() | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:92:6 @@ -92,7 +92,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | *x.y_mut() = 3; | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:96:6 @@ -100,7 +100,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | *x.y_mut() = 3; | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-auto-deref.rs:100:6 @@ -108,7 +108,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | *x.y_mut() = 3; | ^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr index 246a7981ae..9ed9d29249 100644 --- a/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-borrow-overloaded-deref.stderr @@ -4,7 +4,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut *x; | ^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-deref.rs:16:19 @@ -12,7 +12,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | let __isize = &mut *x; | ^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-deref.rs:24:5 @@ -20,7 +20,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut **x | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0596]: cannot borrow data in an `Rc` as mutable --> $DIR/borrowck-borrow-overloaded-deref.rs:28:5 @@ -28,7 +28,7 @@ error[E0596]: cannot borrow data in an `Rc` as mutable LL | &mut **x | ^^^^^^^^ cannot borrow as mutable | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-deref.rs:32:5 @@ -36,7 +36,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | *x = 3; | ^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-deref.rs:36:5 @@ -44,7 +44,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | **x = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error[E0594]: cannot assign to data in an `Rc` --> $DIR/borrowck-borrow-overloaded-deref.rs:40:5 @@ -52,7 +52,7 @@ error[E0594]: cannot assign to data in an `Rc` LL | **x = 3; | ^^^^^^^ cannot assign | - = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `std::rc::Rc` + = help: trait `DerefMut` is required to modify through a dereference, but it is not implemented for `Rc` error: aborting due to 7 previous errors diff --git a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr index 483975e577..7f6c764ec2 100644 --- a/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr +++ b/src/test/ui/borrowck/borrowck-closures-slice-patterns.stderr @@ -30,7 +30,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrowck-closures-slice-patterns.rs:25:5 | LL | fn arr_by_move(x: [String; 3]) { - | - move occurs because `x` has type `[std::string::String; 3]`, which does not implement the `Copy` trait + | - move occurs because `x` has type `[String; 3]`, which does not implement the `Copy` trait LL | let f = || { | -- value moved into closure here LL | let [y, z @ ..] = x; @@ -71,7 +71,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrowck-closures-slice-patterns.rs:51:5 | LL | fn arr_box_by_move(x: Box<[String; 3]>) { - | - move occurs because `x` has type `std::boxed::Box<[std::string::String; 3]>`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box<[String; 3]>`, which does not implement the `Copy` trait LL | let f = || { | -- value moved into closure here LL | let [y, z @ ..] = *x; diff --git a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr index c69237fa95..17b9310661 100644 --- a/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr +++ b/src/test/ui/borrowck/borrowck-consume-unsize-vec.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `b` --> $DIR/borrowck-consume-unsize-vec.rs:8:13 | LL | fn foo(b: Box<[i32;5]>) { - | - move occurs because `b` has type `std::boxed::Box<[i32; 5]>`, which does not implement the `Copy` trait + | - move occurs because `b` has type `Box<[i32; 5]>`, which does not implement the `Copy` trait LL | consume(b); | - value moved here LL | consume(b); diff --git a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr index 356cda01e2..4e20bbf175 100644 --- a/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr +++ b/src/test/ui/borrowck/borrowck-consume-upcast-box.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `b` --> $DIR/borrowck-consume-upcast-box.rs:10:13 | LL | fn foo(b: Box) { - | - move occurs because `b` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `b` has type `Box`, which does not implement the `Copy` trait LL | consume(b); | - value moved here LL | consume(b); diff --git a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr index 4144d70cc1..e386aa1f1f 100644 --- a/src/test/ui/borrowck/borrowck-describe-lvalue.stderr +++ b/src/test/ui/borrowck/borrowck-describe-lvalue.stderr @@ -361,7 +361,7 @@ LL | drop(x); LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Vec`, which does not implement the `Copy` trait error: aborting due to 32 previous errors diff --git a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr index a2b42fa495..77dda0a32b 100644 --- a/src/test/ui/borrowck/borrowck-drop-from-guard.stderr +++ b/src/test/ui/borrowck/borrowck-drop-from-guard.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `my_str` --> $DIR/borrowck-drop-from-guard.rs:11:23 | LL | let my_str = "hello".to_owned(); - | ------ move occurs because `my_str` has type `std::string::String`, which does not implement the `Copy` trait + | ------ move occurs because `my_str` has type `String`, which does not implement the `Copy` trait LL | match Some(42) { LL | Some(_) if { drop(my_str); false } => {} | ------ value moved here diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr index ebdacee7f6..e2c8073241 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.edition.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr index ebdacee7f6..e2c8073241 100644 --- a/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr +++ b/src/test/ui/borrowck/borrowck-feature-nll-overrides-migrate.zflag.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr index 158b2e42f2..f1601336fc 100644 --- a/src/test/ui/borrowck/borrowck-field-sensitivity.stderr +++ b/src/test/ui/borrowck/borrowck-field-sensitivity.stderr @@ -6,7 +6,7 @@ LL | drop(x.b); LL | drop(*x.b); | ^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:14:10 @@ -16,7 +16,7 @@ LL | let y = A { a: 3, .. x }; LL | drop(*x.b); | ^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:20:13 @@ -26,7 +26,7 @@ LL | drop(x.b); LL | let p = &x.b; | ^^^^ value borrowed here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:27:13 @@ -36,7 +36,7 @@ LL | let _y = A { a: 3, .. x }; LL | let p = &x.b; | ^^^^ value borrowed here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0505]: cannot move out of `x.b` because it is borrowed --> $DIR/borrowck-field-sensitivity.rs:34:10 @@ -76,7 +76,7 @@ LL | drop(x.b); LL | drop(x.b); | ^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:62:10 @@ -86,7 +86,7 @@ LL | let _y = A { a: 3, .. x }; LL | drop(x.b); | ^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:68:14 @@ -96,7 +96,7 @@ LL | drop(x.b); LL | let _z = A { a: 3, .. x }; | ^^^^^^^^^^^^^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.b` --> $DIR/borrowck-field-sensitivity.rs:74:14 @@ -106,7 +106,7 @@ LL | let _y = A { a: 3, .. x }; LL | let _z = A { a: 4, .. x }; | ^^^^^^^^^^^^^^^^ value used here after move | - = note: move occurs because `x.b` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.b` has type `Box`, which does not implement the `Copy` trait error[E0381]: assign to part of possibly-uninitialized variable: `x` --> $DIR/borrowck-field-sensitivity.rs:81:5 diff --git a/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr b/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr index 4c9cfa60ad..e7491afdad 100644 --- a/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr +++ b/src/test/ui/borrowck/borrowck-fn-in-const-a.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `*x` which is behind a shared reference --> $DIR/borrowck-fn-in-const-a.rs:6:16 | LL | return *x - | ^^ move occurs because `*x` has type `std::string::String`, which does not implement the `Copy` trait + | ^^ move occurs because `*x` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr index 38e41f315f..2eabc1f1d9 100644 --- a/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr +++ b/src/test/ui/borrowck/borrowck-for-loop-correct-cmt-for-pattern.stderr @@ -15,7 +15,7 @@ LL | for &a in &f.a { | -- ^^^^ | || | |data moved here - | |move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | |move occurs because `a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&`: `a` error[E0507]: cannot move out of a shared reference @@ -25,7 +25,7 @@ LL | for &a in x.iter() { | -- ^^^^^^^^ | || | |data moved here - | |move occurs because `a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | |move occurs because `a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&`: `a` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr index 77d6d7c231..f73c787346 100644 --- a/src/test/ui/borrowck/borrowck-in-static.stderr +++ b/src/test/ui/borrowck/borrowck-in-static.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | Box::new(|| x) - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr index 5880a1abb8..f9ba2ca416 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr +++ b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*y` which is behind a shared reference LL | let _b = *y; | ^^ | | - | move occurs because `*y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `*y` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&*y` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 0eceaf561b..837bd08253 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -7,7 +7,7 @@ LL | let _g = to_fn_mut(|| { LL | let _h = to_fn_once(move || -> isize { *bar }); | ^^^^^^^^^^^^^^^^ --- | | | - | | move occurs because `bar` has type `std::boxed::Box`, which does not implement the `Copy` trait + | | 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 diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr index 26de39101f..ead02414a6 100644 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr @@ -34,7 +34,7 @@ LL | n => { | - | | | data moved here - | move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `n` has type `Box`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr index 7dfae33920..7ac095e808 100644 --- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*x` which is behind a raw pointer LL | let y = *x; | ^^ | | - | move occurs because `*x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `*x` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&*x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr index f0a490d359..6b19f9d977 100644 --- a/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr +++ b/src/test/ui/borrowck/borrowck-move-in-irrefut-pat.stderr @@ -5,7 +5,7 @@ LL | fn arg_item(&_x: &String) {} | ^-- | || | |data moved here - | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `_x` error[E0507]: cannot move out of a shared reference @@ -15,7 +15,7 @@ LL | with(|&_x| ()) | ^-- | || | |data moved here - | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `_x` error[E0507]: cannot move out of a shared reference @@ -25,7 +25,7 @@ LL | let &_x = &"hi".to_string(); | --- ^^^^^^^^^^^^^^^^^ | || | |data moved here - | |move occurs because `_x` has type `std::string::String`, which does not implement the `Copy` trait + | |move occurs because `_x` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `_x` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr index 557e27aae5..44f423c2bd 100644 --- a/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr +++ b/src/test/ui/borrowck/borrowck-move-moved-value-into-closure.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `t` --> $DIR/borrowck-move-moved-value-into-closure.rs:11:12 | LL | let t: Box<_> = box 3; - | - move occurs because `t` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `t` has type `Box`, which does not implement the `Copy` trait LL | LL | call_f(move|| { *t + 1 }); | ------ - variable moved due to use in closure diff --git a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs index 10fc143725..fa2d5531b1 100644 --- a/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs +++ b/src/test/ui/borrowck/borrowck-move-mut-base-ptr.rs @@ -1,7 +1,7 @@ // Test that attempt to move `&mut` pointer while pointee is borrowed // yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs index c1513fcba8..ced4d002b3 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.rs @@ -20,7 +20,7 @@ fn move_out_from_begin_field_and_end() { [_, _, (_x, _)] => {} } match a { - [.., _y] => {} //~ ERROR use of moved value + [.., _y] => {} //~ ERROR use of partially moved value } } @@ -42,7 +42,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _, _] => {} } } @@ -53,7 +53,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} } } @@ -64,7 +64,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _, _] => {} } } @@ -75,7 +75,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _, _y @ ..] => {} } } @@ -108,7 +108,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr index 84930b000c..3249aae8f4 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-match.stderr @@ -7,18 +7,18 @@ LL | [_, _, _x] => {} LL | [.., _y] => {} | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a[..]` +error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-match.rs:23:14 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here ... LL | [.., _y] => {} | ^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:33:15 @@ -29,51 +29,51 @@ LL | [_, _, (_x, _)] => {} LL | [.., (_y, _)] => {} | ^^ value used here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:44:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:55:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:66:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:77:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:89:11 @@ -84,7 +84,7 @@ LL | [_y @ .., _, _] => {} LL | [(_x, _), _, _] => {} | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-match.rs:99:15 @@ -95,18 +95,18 @@ LL | [_, _, _y @ ..] => {} LL | [.., (_x, _)] => {} | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs index 056b8e672b..97db70f34c 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.rs @@ -15,7 +15,7 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., _y, _] => {} } } @@ -26,7 +26,7 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_, _y)] => {} } } @@ -39,7 +39,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -50,7 +50,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -61,7 +61,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } @@ -72,7 +72,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_y @ .., _] => {} } } @@ -83,7 +83,7 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [(_x, _), _, _] => {} } } @@ -94,7 +94,7 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_x, _)] => {} } } @@ -107,7 +107,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr index ff5eab2442..c198002265 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-no-overlap-match.stderr @@ -1,101 +1,101 @@ -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:17:11 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:28:11 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:41:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:52:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:63:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:74:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr index 0ef63105cf..8f2da9d203 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-match.stderr @@ -7,18 +7,18 @@ LL | [_, _, _x] => {} LL | [.., ref _y] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a[..]` +error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:23:14 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here ... LL | [.., ref _y] => {} | ^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use-match.rs:33:15 @@ -29,51 +29,51 @@ LL | [_, _, (_x, _)] => {} LL | [.., (ref _y, _)] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:44:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:55:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:66:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:77:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:89:11 @@ -84,7 +84,7 @@ LL | [_y @ .., _, _] => {} LL | [(ref _x, _), _, _] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use-match.rs:99:15 @@ -95,62 +95,62 @@ LL | [_, _, _y @ ..] => {} LL | [.., (ref _x, _)] => {} | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:110:11 | LL | [x @ .., _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:123:5 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | a[2] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:131:5 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:139:5 | LL | [_, _, _x @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | a[0] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-match.rs:147:5 | LL | [_, _, _x @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs index 5afd6835dc..017ca90b81 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.rs @@ -15,7 +15,7 @@ fn move_out_from_begin_and_one_from_end() { [_, _, _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., ref _y, _] => {} } } @@ -26,7 +26,7 @@ fn move_out_from_begin_field_and_end_field() { [_, _, (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (_, ref _y)] => {} } } @@ -39,7 +39,7 @@ fn move_out_by_const_index_and_subslice() { [_x, _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -50,7 +50,7 @@ fn move_out_by_const_index_end_and_subslice() { [.., _x] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -61,7 +61,7 @@ fn move_out_by_const_index_field_and_subslice() { [(_x, _), _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } @@ -72,7 +72,7 @@ fn move_out_by_const_index_end_field_and_subslice() { [.., (_x, _)] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [ref _y @ .., _] => {} } } @@ -83,7 +83,7 @@ fn move_out_by_const_subslice_and_index_field() { [_, _y @ ..] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [(ref _x, _), _, _] => {} } } @@ -94,7 +94,7 @@ fn move_out_by_const_subslice_and_end_index_field() { [_y @ .., _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [.., (ref _x, _)] => {} } } @@ -107,7 +107,7 @@ fn move_out_by_subslice_and_subslice() { [x @ .., _, _] => {} } match a { - //~^ ERROR use of moved value + //~^ ERROR use of partially moved value [_, ref _y @ ..] => {} } } diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr index a4042ce7db..4b27f03dc4 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use-no-overlap-match.stderr @@ -1,101 +1,101 @@ -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:17:11 | LL | [_, _, _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:28:11 | LL | [_, _, (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:41:11 | LL | [_x, _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:52:11 | LL | [.., _x] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:63:11 | LL | [(_x, _), _, _] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:74:11 | LL | [.., (_x, _)] => {} - | -- value moved here + | -- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:85:11 | LL | [_, _y @ ..] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:96:11 | LL | [_y @ .., _] => {} - | ------- value moved here + | ------- value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use-no-overlap-match.rs:109:11 | LL | [x @ .., _, _] => {} - | ------ value moved here + | ------ value partially moved here LL | } LL | match a { | ^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 9 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr index 7ad4116645..b0bad6e997 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array-use.stderr @@ -6,17 +6,17 @@ LL | let [_, _, _x] = a; LL | let [.., ref _y] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a[..]` +error[E0382]: borrow of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:16:14 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [.., ref _y] = a; | ^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array-use.rs:22:15 @@ -26,47 +26,47 @@ LL | let [_, _, (_x, _)] = a; LL | let [.., (ref _y, _)] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:30:10 | LL | let [_x, _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [ref _y @ .., _, _] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:36:16 | LL | let [.., _x] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:42:10 | LL | let [(_x, _), _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [ref _y @ .., _, _] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:48:16 | LL | let [.., (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:54:11 @@ -76,7 +76,7 @@ LL | let [_y @ .., _, _] = a; LL | let [(ref _x, _), _, _] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `a[..]` --> $DIR/borrowck-move-out-from-array-use.rs:60:15 @@ -86,57 +86,57 @@ LL | let [_, _, _y @ ..] = a; LL | let [.., (ref _x, _)] = a; | ^^^^^^ value borrowed here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: borrow of moved value: `a` +error[E0382]: borrow of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value moved here + | ------ value partially moved here LL | let [_, ref _y @ ..] = a; | ^^^^^^^^^^^ value borrowed here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:76:5 | LL | let [_, _, _x] = a; - | -- value moved here + | -- value partially moved here LL | a[2] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:82:5 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | a[2].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:88:5 | LL | let [_, _, _x @ ..] = a; - | ------- value moved here + | ------- value partially moved here LL | a[0] = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array-use.rs:94:5 | LL | let [_, _, _x @ ..] = a; - | ------- value moved here + | ------- value partially moved here LL | a[0].1 = Default::default(); | ^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr index b7babd93ed..1fc2b292b8 100644 --- a/src/test/ui/borrowck/borrowck-move-out-from-array.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-from-array.stderr @@ -6,17 +6,17 @@ LL | let [_, _, _x] = a; LL | let [.., _y] = a; | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a[..]` +error[E0382]: use of partially moved value: `a[..]` --> $DIR/borrowck-move-out-from-array.rs:16:14 | LL | let [_, _, (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [.., _y] = a; | ^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:22:15 @@ -26,47 +26,47 @@ LL | let [_, _, (_x, _)] = a; LL | let [.., (_y, _)] = a; | ^^ value used here after move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:30:10 | LL | let [_x, _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [_y @ .., _, _] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:36:16 | LL | let [.., _x] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:42:10 | LL | let [(_x, _), _, _] = a; - | -- value moved here + | -- value partially moved here LL | let [_y @ .., _, _] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:48:16 | LL | let [.., (_x, _)] = a; - | -- value moved here + | -- value partially moved here LL | let [_, _, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..].0` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..].0` has type `String`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:54:11 @@ -76,7 +76,7 @@ LL | let [_y @ .., _, _] = a; LL | let [(_x, _), _, _] = a; | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error[E0382]: use of moved value: `a[..].0` --> $DIR/borrowck-move-out-from-array.rs:60:15 @@ -86,17 +86,17 @@ LL | let [_, _, _y @ ..] = a; LL | let [.., (_x, _)] = a; | ^^ value used here after move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `a` +error[E0382]: use of partially moved value: `a` --> $DIR/borrowck-move-out-from-array.rs:68:13 | LL | let [x @ .., _] = a; - | ------ value moved here + | ------ value partially moved here LL | let [_, _y @ ..] = a; | ^^^^^^^ value used here after partial move | - = note: move occurs because `a[..]` has type `(std::string::String, std::string::String)`, which does not implement the `Copy` trait + = note: partial move occurs because `a[..]` has type `(String, String)`, which does not implement the `Copy` trait error: aborting due to 10 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr index 8a94c85ef2..0a29d2bb1d 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-auto-deref.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of an `Rc` --> $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 `std::vec::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 --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr index 1501644fac..68994c2071 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of an `Rc` LL | let _x = *Rc::new("hi".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | move occurs because value has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because value has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*Rc::new("hi".to_string())` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr index a2f66f3ec4..7b00ac9f1c 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-struct-with-dtor.stderr @@ -8,7 +8,7 @@ LL | S {f:_s} => {} | -- | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:14:20 @@ -17,7 +17,7 @@ LL | let S {f:_s} = S {f:"foo".to_string()}; | -- ^^^^^^^^^^^^^^^^^^^^^^^ cannot move out of here | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-struct-with-dtor.rs:18:19 @@ -26,7 +26,7 @@ LL | fn move_in_fn_arg(S {f:_s}: S) { | ^^^^^--^ | | | | | data moved here - | | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait | cannot move out of here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr index f9a539c1c9..f00181b746 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-tuple-struct-with-dtor.stderr @@ -8,7 +8,7 @@ LL | S(_s) => {} | -- | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:14:17 @@ -17,7 +17,7 @@ LL | let S(_s) = S("foo".to_string()); | -- ^^^^^^^^^^^^^^^^^^^^ cannot move out of here | | | data moved here - | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `_s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `S`, which implements the `Drop` trait --> $DIR/borrowck-move-out-of-tuple-struct-with-dtor.rs:18:19 @@ -26,7 +26,7 @@ LL | fn move_in_fn_arg(S(_s): S) { | ^^--^ | | | | | data moved here - | | move occurs because `_s` has type `std::string::String`, which does not implement the `Copy` trait + | | move occurs because `_s` has type `String`, which does not implement the `Copy` trait | cannot move out of here error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-multiple-captures.stderr b/src/test/ui/borrowck/borrowck-multiple-captures.stderr index 298482b3c5..e159878619 100644 --- a/src/test/ui/borrowck/borrowck-multiple-captures.stderr +++ b/src/test/ui/borrowck/borrowck-multiple-captures.stderr @@ -31,7 +31,7 @@ error[E0382]: use of moved value: `x1` --> $DIR/borrowck-multiple-captures.rs:27:19 | LL | let x1: Box<_> = box 1; - | -- move occurs because `x1` has type `std::boxed::Box`, which does not implement the `Copy` trait + | -- move occurs because `x1` has type `Box`, which does not implement the `Copy` trait LL | drop(x1); | -- value moved here ... @@ -45,7 +45,7 @@ error[E0382]: use of moved value: `x2` --> $DIR/borrowck-multiple-captures.rs:27:19 | LL | let x2: Box<_> = box 2; - | -- move occurs because `x2` has type `std::boxed::Box`, which does not implement the `Copy` trait + | -- move occurs because `x2` has type `Box`, which does not implement the `Copy` trait LL | drop(x2); | -- value moved here LL | thread::spawn(move|| { @@ -62,7 +62,7 @@ LL | drop(x); LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0505]: cannot move out of `x` because it is borrowed --> $DIR/borrowck-multiple-captures.rs:38:19 @@ -86,13 +86,13 @@ LL | drop(x); LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x` --> $DIR/borrowck-multiple-captures.rs:49:19 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | drop(x); | - value moved here LL | thread::spawn(move|| { diff --git a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs index 32caa46647..6174893bae 100644 --- a/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs +++ b/src/test/ui/borrowck/borrowck-mut-borrow-of-mut-base-ptr.rs @@ -1,7 +1,7 @@ // Test that attempt to mutably borrow `&mut` pointer while pointee is // borrowed yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs index ddc210f9aa..ddf6354c97 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.rs @@ -18,5 +18,5 @@ fn main() { let v = MyVec::> { data: vec![box 1, box 2, box 3] }; let good = &v[0]; // Shouldn't fail here let bad = v[0]; - //~^ ERROR cannot move out of index of `MyVec>` + //~^ ERROR cannot move out of index of `MyVec>` } diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr index 57f42ede21..2b4293b433 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-from-vec.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of index of `MyVec>` +error[E0507]: cannot move out of index of `MyVec>` --> $DIR/borrowck-overloaded-index-move-from-vec.rs:20:15 | LL | let bad = v[0]; | ^^^^ | | - | move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because value has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&v[0]` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr index 5414b01cb0..bacad399eb 100644 --- a/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr +++ b/src/test/ui/borrowck/borrowck-overloaded-index-move-index.stderr @@ -26,7 +26,7 @@ error[E0382]: use of moved value: `s` --> $DIR/borrowck-overloaded-index-move-index.rs:53:7 | LL | let mut s = "hello".to_string(); - | ----- move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `s` has type `String`, which does not implement the `Copy` trait ... LL | println!("{}", f[s]); | - value moved here diff --git a/src/test/ui/borrowck/borrowck-reinit.stderr b/src/test/ui/borrowck/borrowck-reinit.stderr index f8f14b6435..22253cd96f 100644 --- a/src/test/ui/borrowck/borrowck-reinit.stderr +++ b/src/test/ui/borrowck/borrowck-reinit.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/borrowck-reinit.rs:6:16 | LL | let mut x = Box::new(0); - | ----- move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | drop(x); | - value moved here diff --git a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr index c92c65ba73..af32f27910 100644 --- a/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr +++ b/src/test/ui/borrowck/borrowck-struct-update-with-dtor.stderr @@ -14,7 +14,7 @@ LL | let _s2 = T{a: 2, ..s0}; | ^^^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `s0.mv` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `s0.mv` has type `Box`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs index 3d40d31922..8170323efc 100644 --- a/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs +++ b/src/test/ui/borrowck/borrowck-swap-mut-base-ptr.rs @@ -1,7 +1,7 @@ // Test that attempt to swap `&mut` pointer while pointee is borrowed // yields an error. // -// Example from src/librustc_borrowck/borrowck/README.md +// Example from compiler/rustc_borrowck/borrowck/README.md use std::mem::swap; diff --git a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr index 9f35a4a8d8..7951a5b1b5 100644 --- a/src/test/ui/borrowck/borrowck-uninit-field-access.stderr +++ b/src/test/ui/borrowck/borrowck-uninit-field-access.stderr @@ -14,15 +14,15 @@ LL | let _ = line1.origin.x + 1; | = note: move occurs because `line1.origin` has type `Point`, which does not implement the `Copy` trait -error[E0382]: use of moved value: `line2` +error[E0382]: use of partially moved value: `line2` --> $DIR/borrowck-uninit-field-access.rs:29:5 | LL | let _moved = (line2.origin, line2.middle); - | ------------ value moved here + | ------------ value partially moved here LL | line2.consume(); | ^^^^^ value used here after partial move | - = note: move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait + = note: partial move occurs because `line2.middle` has type `Point`, which does not implement the `Copy` trait error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr index e2c0852dd8..b4b3bc1ba2 100644 --- a/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr +++ b/src/test/ui/borrowck/borrowck-vec-pattern-nesting.stderr @@ -22,7 +22,7 @@ LL | LL | _b.use_ref(); | -- borrow later used here -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:34:11 | LL | match vec { @@ -32,7 +32,7 @@ LL | &mut [_a, | -- | | | data moved here - | move occurs because `_a` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `_a` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&mut` | @@ -44,17 +44,17 @@ LL | .. LL | ] => { | -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:46:13 | LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `vec[_]` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&vec[0]` -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:55:11 | LL | match vec { @@ -64,7 +64,7 @@ LL | _b] => {} | -- | | | data moved here - | move occurs because `_b` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `_b` has type `Box`, which does not implement the `Copy` trait | help: consider removing the `&mut` | @@ -73,17 +73,17 @@ LL | LL | _b] => {} | -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:65:13 | LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `vec[_]` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&vec[0]` -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:74:11 | LL | match vec { @@ -99,14 +99,14 @@ LL | &mut [_a, _b, _c] => {} | = note: move occurs because these variables have types that don't implement the `Copy` trait -error[E0508]: cannot move out of type `[std::boxed::Box]`, a non-copy slice +error[E0508]: cannot move out of type `[Box]`, a non-copy slice --> $DIR/borrowck-vec-pattern-nesting.rs:85:13 | LL | let a = vec[0]; | ^^^^^^ | | | cannot move out of here - | move occurs because `vec[_]` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `vec[_]` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&vec[0]` error: aborting due to 8 previous errors diff --git a/src/test/ui/borrowck/index-mut-help.stderr b/src/test/ui/borrowck/index-mut-help.stderr index baf649f912..52b9ad496e 100644 --- a/src/test/ui/borrowck/index-mut-help.stderr +++ b/src/test/ui/borrowck/index-mut-help.stderr @@ -1,26 +1,26 @@ -error[E0596]: cannot borrow data in an index of `std::collections::HashMap<&str, std::string::String>` as mutable +error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable --> $DIR/index-mut-help.rs:11:5 | LL | map["peter"].clear(); | ^^^^^^^^^^^^ cannot borrow as mutable | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` -error[E0594]: cannot assign to data in an index of `std::collections::HashMap<&str, std::string::String>` +error[E0594]: cannot assign to data in an index of `HashMap<&str, String>` --> $DIR/index-mut-help.rs:12:5 | LL | map["peter"] = "0".to_string(); | ^^^^^^^^^^^^ cannot assign | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` -error[E0596]: cannot borrow data in an index of `std::collections::HashMap<&str, std::string::String>` as mutable +error[E0596]: cannot borrow data in an index of `HashMap<&str, String>` as mutable --> $DIR/index-mut-help.rs:13:13 | LL | let _ = &mut map["peter"]; | ^^^^^^^^^^^^^^^^^ cannot borrow as mutable | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap<&str, std::string::String>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap<&str, String>` error: aborting due to 3 previous errors diff --git a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr index ea7df7d5a7..540f7f8a48 100644 --- a/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr +++ b/src/test/ui/borrowck/issue-27282-mutation-in-guard.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr index 85c83ec4d7..d33115988a 100644 --- a/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr +++ b/src/test/ui/borrowck/issue-31287-drop-in-guard.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `a` --> $DIR/issue-31287-drop-in-guard.rs:5:9 | LL | let a = Some("...".to_owned()); - | - move occurs because `a` has type `std::option::Option`, which does not implement the `Copy` trait + | - move occurs because `a` has type `Option`, which does not implement the `Copy` trait LL | let b = match a { LL | Some(_) if { drop(a); false } => None, | - value moved here diff --git a/src/test/ui/borrowck/issue-41962.stderr b/src/test/ui/borrowck/issue-41962.stderr index 604143b4e7..dd3090b30f 100644 --- a/src/test/ui/borrowck/issue-41962.stderr +++ b/src/test/ui/borrowck/issue-41962.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because value has type `Vec`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `maybe.0` | LL | if let Some(ref thing) = maybe { diff --git a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr index 249a05192b..eb41af1cea 100644 --- a/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr +++ b/src/test/ui/borrowck/issue-47215-ice-from-drop-elab.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of static item `X` LL | let mut x = X; | ^ | | - | move occurs because `X` has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait + | move occurs because `X` has type `AtomicUsize`, which does not implement the `Copy` trait | help: consider borrowing here: `&X` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-51415.stderr b/src/test/ui/borrowck/issue-51415.stderr index 96175b1496..a88819efcf 100644 --- a/src/test/ui/borrowck/issue-51415.stderr +++ b/src/test/ui/borrowck/issue-51415.stderr @@ -5,7 +5,7 @@ LL | let opt = a.iter().enumerate().find(|(_, &s)| { | ^^^^^-^ | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr index 3781691ff4..e8a026cfab 100644 --- a/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr +++ b/src/test/ui/borrowck/issue-53432-nested-closure-outlives-borrowed-value.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | let _action = move || { | ------- | | | - | | return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15 f:&'2 [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:2:13: 2:23]] + | | return type of closure is [closure@$DIR/issue-53432-nested-closure-outlives-borrowed-value.rs:4:9: 4:15] | lifetime `'1` represents this closure's body LL | || f() // The `nested` closure | ^^^^^^ returning this value requires that `'1` must outlive `'2` diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr index 78d44f3206..1f9cbdb734 100644 --- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr +++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*array` which is behind a shared reference LL | *array | ^^^^^^ | | - | move occurs because `*array` has type `std::vec::Vec`, which does not implement the `Copy` trait + | move occurs because `*array` has type `Vec`, which does not implement the `Copy` trait | help: consider borrowing here: `&*array` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-64453.stderr b/src/test/ui/borrowck/issue-64453.stderr index 081ccd3786..fba801983c 100644 --- a/src/test/ui/borrowck/issue-64453.stderr +++ b/src/test/ui/borrowck/issue-64453.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of static item `settings_dir` --> $DIR/issue-64453.rs:14:37 | LL | let settings_data = from_string(settings_dir); - | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^^^^^^^^^ move occurs because `settings_dir` has type `String`, which does not implement the `Copy` trait error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants --> $DIR/issue-64453.rs:4:31 diff --git a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr index a7cb1c9e22..82c3fe3b12 100644 --- a/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr +++ b/src/test/ui/borrowck/move-from-union-field-issue-66500.stderr @@ -2,25 +2,25 @@ error[E0507]: cannot move out of `*u.a` which is behind a shared reference --> $DIR/move-from-union-field-issue-66500.rs:14:5 | LL | *u.a - | ^^^^ move occurs because `*u.a` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.a` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.b` which is behind a mutable reference --> $DIR/move-from-union-field-issue-66500.rs:18:5 | LL | *u.b - | ^^^^ move occurs because `*u.b` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.b` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.c` which is behind a raw pointer --> $DIR/move-from-union-field-issue-66500.rs:22:5 | LL | *u.c - | ^^^^ move occurs because `*u.c` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.c` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*u.d` which is behind a raw pointer --> $DIR/move-from-union-field-issue-66500.rs:26:5 | LL | *u.d - | ^^^^ move occurs because `*u.d` has type `std::string::String`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*u.d` has type `String`, which does not implement the `Copy` trait error: aborting due to 4 previous errors diff --git a/src/test/ui/borrowck/move-in-pattern-mut.rs b/src/test/ui/borrowck/move-in-pattern-mut.rs index 175eb3b7a0..b5c275bf28 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut.rs +++ b/src/test/ui/borrowck/move-in-pattern-mut.rs @@ -15,9 +15,9 @@ fn main() { if let Some(mut x) = s { x = S; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let mut e = E::V { s: S }; let E::V { s: mut x } = e; x = S; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern-mut.stderr b/src/test/ui/borrowck/move-in-pattern-mut.stderr index 391638444c..17bc549275 100644 --- a/src/test/ui/borrowck/move-in-pattern-mut.stderr +++ b/src/test/ui/borrowck/move-in-pattern-mut.stderr @@ -1,28 +1,28 @@ -error[E0382]: use of moved value: `s` +error[E0382]: use of partially moved value: `s` --> $DIR/move-in-pattern-mut.rs:18:9 | LL | if let Some(mut x) = s { - | ----- value moved here + | ----- value partially moved here ... LL | foo(s); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `s.0` | LL | if let Some(ref mut x) = s { | ^^^ -error[E0382]: use of moved value: `e` +error[E0382]: use of partially moved value: `e` --> $DIR/move-in-pattern-mut.rs:22:9 | LL | let E::V { s: mut x } = e; - | ----- value moved here + | ----- value partially moved here LL | x = S; LL | bar(e); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `e.s` | LL | let E::V { s: ref mut x } = e; diff --git a/src/test/ui/borrowck/move-in-pattern.fixed b/src/test/ui/borrowck/move-in-pattern.fixed index f55fdcc5f9..145893d334 100644 --- a/src/test/ui/borrowck/move-in-pattern.fixed +++ b/src/test/ui/borrowck/move-in-pattern.fixed @@ -16,9 +16,9 @@ fn main() { if let Some(ref x) = s { let _ = x; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let e = E::V { s: S }; let E::V { s: ref x } = e; let _ = x; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern.rs b/src/test/ui/borrowck/move-in-pattern.rs index 7ad04b9490..14851d0f6f 100644 --- a/src/test/ui/borrowck/move-in-pattern.rs +++ b/src/test/ui/borrowck/move-in-pattern.rs @@ -16,9 +16,9 @@ fn main() { if let Some(x) = s { let _ = x; } - foo(s); //~ ERROR use of moved value: `s` + foo(s); //~ ERROR use of partially moved value: `s` let e = E::V { s: S }; let E::V { s: x } = e; let _ = x; - bar(e); //~ ERROR use of moved value: `e` + bar(e); //~ ERROR use of partially moved value: `e` } diff --git a/src/test/ui/borrowck/move-in-pattern.stderr b/src/test/ui/borrowck/move-in-pattern.stderr index c5cb24455e..21ba92f1fc 100644 --- a/src/test/ui/borrowck/move-in-pattern.stderr +++ b/src/test/ui/borrowck/move-in-pattern.stderr @@ -1,28 +1,28 @@ -error[E0382]: use of moved value: `s` +error[E0382]: use of partially moved value: `s` --> $DIR/move-in-pattern.rs:19:9 | LL | if let Some(x) = s { - | - value moved here + | - value partially moved here ... LL | foo(s); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `s.0` | LL | if let Some(ref x) = s { | ^^^ -error[E0382]: use of moved value: `e` +error[E0382]: use of partially moved value: `e` --> $DIR/move-in-pattern.rs:23:9 | LL | let E::V { s: x } = e; - | - value moved here + | - value partially moved here LL | let _ = x; LL | bar(e); | ^ value used here after partial move | - = note: move occurs because value has type `S`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `S`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `e.s` | LL | let E::V { s: ref x } = e; diff --git a/src/test/ui/borrowck/or-patterns.stderr b/src/test/ui/borrowck/or-patterns.stderr index d3f3544426..9593b94537 100644 --- a/src/test/ui/borrowck/or-patterns.stderr +++ b/src/test/ui/borrowck/or-patterns.stderr @@ -7,7 +7,7 @@ LL | } LL | &x.0 .0; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.0.1` --> $DIR/or-patterns.rs:12:5 @@ -18,7 +18,7 @@ LL | ((y, _) | (_, y),) => (), LL | &x.0 .1; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable --> $DIR/or-patterns.rs:20:5 @@ -76,7 +76,7 @@ LL | let ((y, _) | (_, y),) = x; LL | &x.0 .0; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.0` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.0` has type `String`, which does not implement the `Copy` trait error[E0382]: borrow of moved value: `x.0.1` --> $DIR/or-patterns.rs:42:5 @@ -87,7 +87,7 @@ LL | let ((y, _) | (_, y),) = x; LL | &x.0 .1; | ^^^^^^^ value borrowed here after move | - = note: move occurs because `x.0.1` has type `std::string::String`, which does not implement the `Copy` trait + = note: move occurs because `x.0.1` has type `String`, which does not implement the `Copy` trait error[E0502]: cannot borrow `x.0.0` as mutable because it is also borrowed as immutable --> $DIR/or-patterns.rs:48:5 diff --git a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr index 21ae25c16b..50d277a12f 100644 --- a/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr +++ b/src/test/ui/borrowck/two-phase-nonrecv-autoref.nll.stderr @@ -11,7 +11,7 @@ error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:59:11 | LL | fn twice_ten_so i32>(f: Box) { - | - move occurs because `f` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `f` has type `Box`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | @@ -30,7 +30,7 @@ error[E0382]: use of moved value: `f` --> $DIR/two-phase-nonrecv-autoref.rs:73:11 | LL | fn twice_ten_oo(f: Box i32>) { - | - move occurs because `f` has type `std::boxed::Box i32>`, which does not implement the `Copy` trait + | - move occurs because `f` has type `Box i32>`, which does not implement the `Copy` trait LL | f(f(10)); | - ^ value used here after move | | diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index 73cea6fc36..dbba33f018 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -5,7 +5,7 @@ LL | let y = vec![format!("World")]; | - captured outer variable LL | call(|| { LL | y.into_iter(); - | ^ move occurs because `y` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^ move occurs because `y` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/bound-suggestions.fixed b/src/test/ui/bound-suggestions.fixed index 9c98200db5..a3fe67a959 100644 --- a/src/test/ui/bound-suggestions.fixed +++ b/src/test/ui/bound-suggestions.fixed @@ -1,37 +1,41 @@ // run-rustfix +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + #[allow(dead_code)] -fn test_impl(t: impl Sized + std::fmt::Debug) { +fn test_impl(t: impl Sized + Debug) { println!("{:?}", t); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_no_bounds(t: T) { +fn test_no_bounds(t: T) { println!("{:?}", t); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_one_bound(t: T) { +fn test_one_bound(t: T) { println!("{:?}", t); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: std::fmt::Debug { +fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: Debug { println!("{:?} {:?}", x, y); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_one_bound_where(x: X) where X: Sized + std::fmt::Debug { +fn test_one_bound_where(x: X) where X: Sized + Debug { println!("{:?}", x); //~^ ERROR doesn't implement } #[allow(dead_code)] -fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: std::fmt::Debug { +fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: Debug { println!("{:?}", x); //~^ ERROR doesn't implement } diff --git a/src/test/ui/bound-suggestions.rs b/src/test/ui/bound-suggestions.rs index 562dec9f08..de6133d7f5 100644 --- a/src/test/ui/bound-suggestions.rs +++ b/src/test/ui/bound-suggestions.rs @@ -1,5 +1,9 @@ // run-rustfix +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + #[allow(dead_code)] fn test_impl(t: impl Sized) { println!("{:?}", t); diff --git a/src/test/ui/bound-suggestions.stderr b/src/test/ui/bound-suggestions.stderr index 623252a8c1..010f95d8ad 100644 --- a/src/test/ui/bound-suggestions.stderr +++ b/src/test/ui/bound-suggestions.stderr @@ -1,80 +1,80 @@ -error[E0277]: `impl Sized` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:5:22 +error[E0277]: `impl Sized` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:9:22 | LL | println!("{:?}", t); - | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `impl Sized` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -LL | fn test_impl(t: impl Sized + std::fmt::Debug) { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_impl(t: impl Sized + Debug) { + | ^^^^^^^ -error[E0277]: `T` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:11:22 +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:15:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider restricting type parameter `T` | -LL | fn test_no_bounds(t: T) { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_no_bounds(t: T) { + | ^^^^^^^ -error[E0277]: `T` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:17:22 +error[E0277]: `T` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:21:22 | LL | println!("{:?}", t); - | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `T` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -LL | fn test_one_bound(t: T) { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_one_bound(t: T) { + | ^^^^^^^ -error[E0277]: `Y` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:23:30 +error[E0277]: `Y` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:27:30 | LL | println!("{:?} {:?}", x, y); - | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `Y` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `Y` | -LL | fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn test_no_bounds_where(x: X, y: Y) where X: std::fmt::Debug, Y: Debug { + | ^^^^^^^^^^ -error[E0277]: `X` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:29:22 +error[E0277]: `X` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:33:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting this bound | -LL | fn test_one_bound_where(x: X) where X: Sized + std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^ +LL | fn test_one_bound_where(x: X) where X: Sized + Debug { + | ^^^^^^^ -error[E0277]: `X` doesn't implement `std::fmt::Debug` - --> $DIR/bound-suggestions.rs:35:22 +error[E0277]: `X` doesn't implement `Debug` + --> $DIR/bound-suggestions.rs:39:22 | LL | println!("{:?}", x); - | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^ `X` cannot be formatted using `{:?}` because it doesn't implement `Debug` | = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) help: consider further restricting type parameter `X` | -LL | fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn test_many_bounds_where(x: X) where X: Sized, X: Sized, X: Debug { + | ^^^^^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/box-into-boxed-slice-fail.rs b/src/test/ui/box-into-boxed-slice-fail.rs index 5f8a3fd9d6..49dbb170f8 100644 --- a/src/test/ui/box-into-boxed-slice-fail.rs +++ b/src/test/ui/box-into-boxed-slice-fail.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![feature(box_into_boxed_slice)] use std::boxed::Box; @@ -10,6 +9,6 @@ fn main() { //~^^ ERROR the size for values of type `[u8]` cannot be known at compilation time let boxed_trait: Box = Box::new(5u8); let _ = Box::into_boxed_slice(boxed_trait); - //~^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time - //~^^ ERROR the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time + //~^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time + //~^^ ERROR the size for values of type `dyn Debug` cannot be known at compilation time } diff --git a/src/test/ui/box-into-boxed-slice-fail.stderr b/src/test/ui/box-into-boxed-slice-fail.stderr index b3e7b5b4fe..8cfa3668d9 100644 --- a/src/test/ui/box-into-boxed-slice-fail.stderr +++ b/src/test/ui/box-into-boxed-slice-fail.stderr @@ -1,37 +1,37 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:8:35 + --> $DIR/box-into-boxed-slice-fail.rs:7:35 | LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` - = note: required by `std::boxed::Box::::into_boxed_slice` + = help: the trait `Sized` is not implemented for `[u8]` + = note: required by `Box::::into_boxed_slice` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:8:13 + --> $DIR/box-into-boxed-slice-fail.rs:7:13 | LL | let _ = Box::into_boxed_slice(boxed_slice); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: slice and array elements must have `Sized` type -error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:12:35 +error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time + --> $DIR/box-into-boxed-slice-fail.rs:11:35 | LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` - = note: required by `std::boxed::Box::::into_boxed_slice` + = help: the trait `Sized` is not implemented for `dyn Debug` + = note: required by `Box::::into_boxed_slice` -error[E0277]: the size for values of type `dyn std::fmt::Debug` cannot be known at compilation time - --> $DIR/box-into-boxed-slice-fail.rs:12:13 +error[E0277]: the size for values of type `dyn Debug` cannot be known at compilation time + --> $DIR/box-into-boxed-slice-fail.rs:11:13 | LL | let _ = Box::into_boxed_slice(boxed_trait); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::fmt::Debug` + = help: the trait `Sized` is not implemented for `dyn Debug` = note: slice and array elements must have `Sized` type error: aborting due to 4 previous errors diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr index 7ff986ec38..7e8ac113b4 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-double-superkind.stderr @@ -10,8 +10,8 @@ LL | impl Foo for (T,) { } = note: required because it appears within the type `(T,)` help: consider further restricting this bound | -LL | impl Foo for (T,) { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for (T,) { } + | ^^^^^^ error[E0277]: `T` cannot be shared between threads safely --> $DIR/builtin-superkinds-double-superkind.rs:9:16 @@ -25,8 +25,8 @@ LL | impl Foo for (T,T) { } = note: required because it appears within the type `(T, T)` help: consider further restricting this bound | -LL | impl Foo for (T,T) { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for (T,T) { } + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr index 9ee045edfe..2b4b6e548b 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-in-metadata.stderr @@ -7,13 +7,13 @@ LL | impl RequiresRequiresShareAndSend for X { } ::: $DIR/auxiliary/trait_superkinds_in_metadata.rs:7:58 | LL | pub trait RequiresRequiresShareAndSend : RequiresShare + Send { } - | ---- required by this bound in `trait_superkinds_in_metadata::RequiresRequiresShareAndSend` + | ---- required by this bound in `RequiresRequiresShareAndSend` | = note: required because it appears within the type `X` help: consider further restricting this bound | -LL | impl RequiresRequiresShareAndSend for X { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl RequiresRequiresShareAndSend for X { } + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs index afafc09438..1620f8d5cf 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.rs @@ -4,6 +4,6 @@ trait Foo : Send { } impl Foo for std::rc::Rc { } -//~^ ERROR `std::rc::Rc` cannot be sent between threads safely +//~^ ERROR `Rc` cannot be sent between threads safely fn main() { } diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr index 592cc3b1c4..0abe2052b2 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-simple.stderr @@ -1,13 +1,13 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/builtin-superkinds-simple.rs:6:6 | LL | trait Foo : Send { } | ---- required by this bound in `Foo` LL | LL | impl Foo for std::rc::Rc { } - | ^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^ `Rc` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = help: the trait `Send` is not implemented for `Rc` error: aborting due to previous error diff --git a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr index ad80b3fa8d..ff2cd1c4c8 100644 --- a/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr +++ b/src/test/ui/builtin-superkinds/builtin-superkinds-typaram-not-send.stderr @@ -9,8 +9,8 @@ LL | impl Foo for T { } | help: consider further restricting this bound | -LL | impl Foo for T { } - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for T { } + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/by-move-pattern-binding.stderr b/src/test/ui/by-move-pattern-binding.stderr index 1db4e2a66d..0012f67cfa 100644 --- a/src/test/ui/by-move-pattern-binding.stderr +++ b/src/test/ui/by-move-pattern-binding.stderr @@ -8,7 +8,7 @@ LL | &E::Bar(identifier) => f(identifier.clone()) | ------------------- | | | | | data moved here - | | move occurs because `identifier` has type `std::string::String`, which does not implement the `Copy` trait + | | move occurs because `identifier` has type `String`, which does not implement the `Copy` trait | help: consider removing the `&`: `E::Bar(identifier)` error: aborting due to previous error diff --git a/src/test/ui/c-variadic/variadic-ffi-4.stderr b/src/test/ui/c-variadic/variadic-ffi-4.stderr index 6562350156..dd67514d02 100644 --- a/src/test/ui/c-variadic/variadic-ffi-4.stderr +++ b/src/test/ui/c-variadic/variadic-ffi-4.stderr @@ -2,7 +2,7 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `core::ffi::VaListImpl<'1>` + | -- -- has type `VaListImpl<'1>` | | | lifetime `'f` defined here LL | ap @@ -12,7 +12,7 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:8:5 | LL | pub unsafe extern "C" fn no_escape0<'f>(_: usize, ap: ...) -> VaListImpl<'f> { - | -- -- has type `core::ffi::VaListImpl<'1>` + | -- -- has type `VaListImpl<'1>` | | | lifetime `'f` defined here LL | ap @@ -22,7 +22,7 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:14:5 | LL | pub unsafe extern "C" fn no_escape1(_: usize, ap: ...) -> VaListImpl<'static> { - | -- has type `core::ffi::VaListImpl<'1>` + | -- has type `VaListImpl<'1>` LL | ap | ^^ returning this value requires that `'1` must outlive `'static` @@ -32,16 +32,16 @@ error: lifetime may not live long enough LL | let _ = ap.with_copy(|ap| ap); | --- ^^ returning this value requires that `'1` must outlive `'2` | | | - | | return type of closure is core::ffi::VaList<'2, '_> - | has type `core::ffi::VaList<'1, '_>` + | | return type of closure is VaList<'2, '_> + | has type `VaList<'1, '_>` error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'1` must outlive `'2` @@ -49,9 +49,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:22:5 | LL | pub unsafe extern "C" fn no_escape3(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1; | ^^^^ assignment requires that `'2` must outlive `'1` @@ -59,9 +59,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'1` must outlive `'2` @@ -69,9 +69,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:28:5 | LL | pub unsafe extern "C" fn no_escape4(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | ap0 = &mut ap1; | ^^^^^^^^^^^^^^ assignment requires that `'2` must outlive `'1` @@ -93,9 +93,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:35:12 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ argument requires that `'1` must outlive `'2` @@ -103,9 +103,9 @@ error: lifetime may not live long enough --> $DIR/variadic-ffi-4.rs:35:12 | LL | pub unsafe extern "C" fn no_escape5(_: usize, mut ap0: &mut VaListImpl, mut ap1: ...) { - | ------- ------- has type `core::ffi::VaListImpl<'2>` + | ------- ------- has type `VaListImpl<'2>` | | - | has type `&mut core::ffi::VaListImpl<'1>` + | has type `&mut VaListImpl<'1>` LL | *ap0 = ap1.clone(); | ^^^^^^^^^^^ argument requires that `'2` must outlive `'1` diff --git a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr index 9b86f8d4de..3b5b8ea69c 100644 --- a/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr +++ b/src/test/ui/cast/cast-to-unsized-trait-object-suggestion.stderr @@ -1,4 +1,4 @@ -error[E0620]: cast to unsized type: `&{integer}` as `dyn std::marker::Send` +error[E0620]: cast to unsized type: `&{integer}` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:2:5 | LL | &1 as dyn Send; @@ -6,7 +6,7 @@ LL | &1 as dyn Send; | | | help: try casting to a reference instead: `&dyn Send` -error[E0620]: cast to unsized type: `std::boxed::Box<{integer}>` as `dyn std::marker::Send` +error[E0620]: cast to unsized type: `Box<{integer}>` as `dyn Send` --> $DIR/cast-to-unsized-trait-object-suggestion.rs:3:5 | LL | Box::new(1) as dyn Send; diff --git a/src/test/ui/casts-differing-anon.stderr b/src/test/ui/casts-differing-anon.stderr index fbbb8e3bb3..a30e9b35f5 100644 --- a/src/test/ui/casts-differing-anon.stderr +++ b/src/test/ui/casts-differing-anon.stderr @@ -1,4 +1,4 @@ -error[E0606]: casting `*mut impl std::fmt::Debug+?Sized` as `*mut impl std::fmt::Debug+?Sized` is invalid +error[E0606]: casting `*mut impl Debug+?Sized` as `*mut impl Debug+?Sized` is invalid --> $DIR/casts-differing-anon.rs:21:13 | LL | b_raw = f_raw as *mut _; diff --git a/src/test/ui/cell-does-not-clone.rs b/src/test/ui/cell-does-not-clone.rs deleted file mode 100644 index 587447b54b..0000000000 --- a/src/test/ui/cell-does-not-clone.rs +++ /dev/null @@ -1,26 +0,0 @@ -// run-pass - -#![allow(dead_code)] - -use std::cell::Cell; - -#[derive(Copy)] -struct Foo { - x: isize -} - -impl Clone for Foo { - fn clone(&self) -> Foo { - // Using Cell in any way should never cause clone() to be - // invoked -- after all, that would permit evil user code to - // abuse `Cell` and trigger crashes. - - panic!(); - } -} - -pub fn main() { - let x = Cell::new(Foo { x: 22 }); - let _y = x.get(); - let _z = x.clone(); -} diff --git a/src/test/ui/chalkify/generic_impls.stderr b/src/test/ui/chalkify/generic_impls.stderr index 4ac57a2f13..a6f5d1a608 100644 --- a/src/test/ui/chalkify/generic_impls.stderr +++ b/src/test/ui/chalkify/generic_impls.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `(std::option::Option, f32): Foo` is not satisfied +error[E0277]: the trait bound `(Option, f32): Foo` is not satisfied --> $DIR/generic_impls.rs:12:13 | LL | fn gimme() { } | --- required by this bound in `gimme` ... LL | gimme::<(Option, f32)>(); - | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(std::option::Option, f32)` + | ^^^^^^^^^^^^^^^^ the trait `Foo` is not implemented for `(Option, f32)` | = help: the following implementations were found: <(T, u32) as Foo> diff --git a/src/test/ui/chalkify/impl_wf.stderr b/src/test/ui/chalkify/impl_wf.stderr index fb2e0fc1a6..4ca5ae472f 100644 --- a/src/test/ui/chalkify/impl_wf.stderr +++ b/src/test/ui/chalkify/impl_wf.stderr @@ -7,7 +7,7 @@ LL | trait Foo: Sized { } LL | impl Foo for str { } | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` error[E0277]: the trait bound `f32: Foo` is not satisfied --> $DIR/impl_wf.rs:27:17 diff --git a/src/test/ui/chalkify/type_inference.rs b/src/test/ui/chalkify/type_inference.rs index 2b62bf18a7..369777a790 100644 --- a/src/test/ui/chalkify/type_inference.rs +++ b/src/test/ui/chalkify/type_inference.rs @@ -24,5 +24,5 @@ fn main() { // Here we have two solutions so we get back the behavior of the old-style // trait solver. - only_bar(x); //~ ERROR the trait bound `f64: Bar` is not satisfied + only_bar(x); //~ ERROR the trait bound `{float}: Bar` is not satisfied } diff --git a/src/test/ui/chalkify/type_inference.stderr b/src/test/ui/chalkify/type_inference.stderr index 5cfb968404..91c46b9531 100644 --- a/src/test/ui/chalkify/type_inference.stderr +++ b/src/test/ui/chalkify/type_inference.stderr @@ -1,11 +1,15 @@ -error[E0277]: the trait bound `f64: Bar` is not satisfied - --> $DIR/type_inference.rs:27:5 +error[E0277]: the trait bound `{float}: Bar` is not satisfied + --> $DIR/type_inference.rs:27:14 | LL | fn only_bar(_x: T) { } | --- required by this bound in `only_bar` ... LL | only_bar(x); - | ^^^^^^^^ the trait `Bar` is not implemented for `f64` + | ^ the trait `Bar` is not implemented for `{float}` + | + = help: the following implementations were found: + + error: aborting due to previous error diff --git a/src/test/ui/chalkify/type_wf.rs b/src/test/ui/chalkify/type_wf.rs index 7c469d99c5..dd83a03fdf 100644 --- a/src/test/ui/chalkify/type_wf.rs +++ b/src/test/ui/chalkify/type_wf.rs @@ -15,7 +15,7 @@ fn main() { x: 5, }; - let s = S { //~ ERROR the trait bound `f64: Foo` is not satisfied + let s = S { //~ ERROR the trait bound `{float}: Foo` is not satisfied x: 5.0, }; diff --git a/src/test/ui/chalkify/type_wf.stderr b/src/test/ui/chalkify/type_wf.stderr index ab585a6ed2..3cd6036945 100644 --- a/src/test/ui/chalkify/type_wf.stderr +++ b/src/test/ui/chalkify/type_wf.stderr @@ -1,11 +1,15 @@ -error[E0277]: the trait bound `f64: Foo` is not satisfied +error[E0277]: the trait bound `{float}: Foo` is not satisfied --> $DIR/type_wf.rs:18:13 | LL | struct S { | ---------------- required by `S` ... LL | let s = S { - | ^ the trait `Foo` is not implemented for `f64` + | ^ the trait `Foo` is not implemented for `{float}` + | + = help: the following implementations were found: + as Foo> + error: aborting due to previous error diff --git a/src/test/ui/check-doc-alias-attr.rs b/src/test/ui/check-doc-alias-attr.rs index b02cc1a454..c8bec39fad 100644 --- a/src/test/ui/check-doc-alias-attr.rs +++ b/src/test/ui/check-doc-alias-attr.rs @@ -7,4 +7,10 @@ pub struct Bar; #[doc(alias)] //~ ERROR #[doc(alias = 0)] //~ ERROR #[doc(alias("bar"))] //~ ERROR +#[doc(alias = "\"")] //~ ERROR +#[doc(alias = "\n")] //~ ERROR +#[doc(alias = " +")] //~^ ERROR +#[doc(alias = " ")] //~ ERROR +#[doc(alias = "\t")] //~ ERROR pub struct Foo; diff --git a/src/test/ui/check-doc-alias-attr.stderr b/src/test/ui/check-doc-alias-attr.stderr index 268230ab44..be7d7b3dbe 100644 --- a/src/test/ui/check-doc-alias-attr.stderr +++ b/src/test/ui/check-doc-alias-attr.stderr @@ -16,5 +16,37 @@ error: doc alias attribute expects a string: #[doc(alias = "0")] LL | #[doc(alias("bar"))] | ^^^^^^^^^^^^ -error: aborting due to 3 previous errors +error: '\"' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:10:7 + | +LL | #[doc(alias = "\"")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:11:7 + | +LL | #[doc(alias = "\n")] + | ^^^^^^^^^^^^ + +error: '\n' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:12:7 + | +LL | #[doc(alias = " + | _______^ +LL | | ")] + | |_^ + +error: ' ' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:14:7 + | +LL | #[doc(alias = " ")] + | ^^^^^^^^^^^ + +error: '\t' character isn't allowed in `#[doc(alias = "...")]` + --> $DIR/check-doc-alias-attr.rs:15:7 + | +LL | #[doc(alias = "\t")] + | ^^^^^^^^^^^^ + +error: aborting due to 8 previous errors diff --git a/src/test/ui/check-static-recursion-foreign.rs b/src/test/ui/check-static-recursion-foreign.rs index 8ca0af8e47..3072deb6c5 100644 --- a/src/test/ui/check-static-recursion-foreign.rs +++ b/src/test/ui/check-static-recursion-foreign.rs @@ -1,6 +1,5 @@ // run-pass -#![allow(dead_code)] // Static recursion check shouldn't fail when given a foreign item (#18279) // aux-build:check_static_recursion_foreign_helper.rs @@ -15,12 +14,10 @@ extern crate libc; use libc::c_int; -#[link_name = "check_static_recursion_foreign_helper"] extern "C" { - #[allow(dead_code)] static test_static: c_int; } -static B: &'static c_int = unsafe { &test_static }; +pub static B: &'static c_int = unsafe { &test_static }; pub fn main() {} diff --git a/src/test/ui/check-static-values-constraints.rs b/src/test/ui/check-static-values-constraints.rs index acfb3b5e44..3d1b5a0822 100644 --- a/src/test/ui/check-static-values-constraints.rs +++ b/src/test/ui/check-static-values-constraints.rs @@ -78,7 +78,6 @@ struct MyOwned; static STATIC11: Box = box MyOwned; //~^ ERROR allocations are not allowed in statics -//~| ERROR static contains unimplemented expression type static mut STATIC12: UnsafeStruct = UnsafeStruct; @@ -93,16 +92,12 @@ static mut STATIC14: SafeStruct = SafeStruct { static STATIC15: &'static [Box] = &[ box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression ]; static STATIC16: (&'static Box, &'static Box) = ( &box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression &box MyOwned, //~ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression ); static mut STATIC17: SafeEnum = SafeEnum::Variant1; @@ -110,11 +105,9 @@ static mut STATIC17: SafeEnum = SafeEnum::Variant1; static STATIC19: Box = box 3; //~^ ERROR allocations are not allowed in statics - //~| ERROR contains unimplemented expression pub fn main() { let y = { static x: Box = box 3; x }; //~^ ERROR allocations are not allowed in statics //~| ERROR cannot move out of static item - //~| ERROR contains unimplemented expression } diff --git a/src/test/ui/check-static-values-constraints.stderr b/src/test/ui/check-static-values-constraints.stderr index b00affdca8..eb640c88e0 100644 --- a/src/test/ui/check-static-values-constraints.stderr +++ b/src/test/ui/check-static-values-constraints.stderr @@ -15,114 +15,58 @@ error[E0010]: allocations are not allowed in statics LL | static STATIC11: Box = box MyOwned; | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:79:37 - | -LL | static STATIC11: Box = box MyOwned; - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/check-static-values-constraints.rs:90:32 + --> $DIR/check-static-values-constraints.rs:89:32 | LL | field2: SafeEnum::Variant4("str".to_string()) | ^^^^^^^^^^^^^^^^^ +error[E0010]: allocations are not allowed in statics + --> $DIR/check-static-values-constraints.rs:94:5 + | +LL | box MyOwned, + | ^^^^^^^^^^^ allocation not allowed in statics + error[E0010]: allocations are not allowed in statics --> $DIR/check-static-values-constraints.rs:95:5 | LL | box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:95:9 - | -LL | box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:97:5 - | -LL | box MyOwned, - | ^^^^^^^^^^^ allocation not allowed in statics - -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:97:9 - | -LL | box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:102:6 + --> $DIR/check-static-values-constraints.rs:99:6 | LL | &box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:102:10 - | -LL | &box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:104:6 + --> $DIR/check-static-values-constraints.rs:100:6 | LL | &box MyOwned, | ^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:104:10 - | -LL | &box MyOwned, - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:111:5 + --> $DIR/check-static-values-constraints.rs:106:5 | LL | box 3; | ^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:111:9 - | -LL | box 3; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0507]: cannot move out of static item `x` - --> $DIR/check-static-values-constraints.rs:116:45 + --> $DIR/check-static-values-constraints.rs:110:45 | LL | let y = { static x: Box = box 3; x }; | ^ | | - | move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `x` has type `Box`, which does not implement the `Copy` trait | help: consider borrowing here: `&x` error[E0010]: allocations are not allowed in statics - --> $DIR/check-static-values-constraints.rs:116:38 + --> $DIR/check-static-values-constraints.rs:110:38 | LL | let y = { static x: Box = box 3; x }; | ^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/check-static-values-constraints.rs:116:42 - | -LL | let y = { static x: Box = box 3; x }; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error: aborting due to 10 previous errors -error: aborting due to 17 previous errors - -Some errors have detailed explanations: E0010, E0015, E0019, E0493, E0507. +Some errors have detailed explanations: E0010, E0015, E0493, E0507. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/class-cast-to-trait.stderr b/src/test/ui/class-cast-to-trait.stderr index 0f932cda07..56d10d88d8 100644 --- a/src/test/ui/class-cast-to-trait.stderr +++ b/src/test/ui/class-cast-to-trait.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `eat` found for struct `std::boxed::Box` in the current scope +error[E0599]: no method named `eat` found for struct `Box` in the current scope --> $DIR/class-cast-to-trait.rs:53:8 | LL | nyan.eat(); - | ^^^ method not found in `std::boxed::Box` + | ^^^ method not found in `Box` error: aborting due to previous error diff --git a/src/test/ui/closure-expected.rs b/src/test/ui/closure-expected.rs index 9b15a63da2..68cac3dd85 100644 --- a/src/test/ui/closure-expected.rs +++ b/src/test/ui/closure-expected.rs @@ -1,5 +1,5 @@ fn main() { let x = Some(1); let y = x.or_else(4); - //~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `{integer}` + //~^ ERROR expected a `FnOnce<()>` closure, found `{integer}` } diff --git a/src/test/ui/closure-expected.stderr b/src/test/ui/closure-expected.stderr index 687dd97ca6..6c77d08096 100644 --- a/src/test/ui/closure-expected.stderr +++ b/src/test/ui/closure-expected.stderr @@ -1,10 +1,10 @@ -error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `{integer}` +error[E0277]: expected a `FnOnce<()>` closure, found `{integer}` --> $DIR/closure-expected.rs:3:23 | LL | let y = x.or_else(4); | ^ expected an `FnOnce<()>` closure, found `{integer}` | - = help: the trait `std::ops::FnOnce<()>` is not implemented for `{integer}` + = help: the trait `FnOnce<()>` is not implemented for `{integer}` = note: wrap the `{integer}` in a closure with no arguments: `|| { /* code */ }` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr index 273eae9955..48f18b1ebe 100644 --- a/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr +++ b/src/test/ui/closures/closure-bounds-cant-promote-superkind-in-struct.stderr @@ -9,8 +9,8 @@ LL | fn foo(blk: F) -> X where F: FnOnce() + 'static { | help: consider further restricting this bound | -LL | fn foo(blk: F) -> X where F: FnOnce() + 'static + std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo(blk: F) -> X where F: FnOnce() + 'static + Send { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-bounds-subtype.stderr b/src/test/ui/closures/closure-bounds-subtype.stderr index 7df29d5a09..d649eeccb8 100644 --- a/src/test/ui/closures/closure-bounds-subtype.stderr +++ b/src/test/ui/closures/closure-bounds-subtype.stderr @@ -9,8 +9,8 @@ LL | take_const_owned(f); | help: consider further restricting this bound | -LL | fn give_owned(f: F) where F: FnOnce() + Send + std::marker::Sync { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn give_owned(f: F) where F: FnOnce() + Send + Sync { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/closures/closure-move-sync.rs b/src/test/ui/closures/closure-move-sync.rs index 580cd1af4f..ea2d1434c4 100644 --- a/src/test/ui/closures/closure-move-sync.rs +++ b/src/test/ui/closures/closure-move-sync.rs @@ -16,7 +16,7 @@ fn bar() { fn foo() { let (tx, _rx) = channel(); thread::spawn(|| tx.send(()).unwrap()); - //~^ ERROR `std::sync::mpsc::Sender<()>` cannot be shared between threads safely + //~^ ERROR `Sender<()>` cannot be shared between threads safely } fn main() {} diff --git a/src/test/ui/closures/closure-move-sync.stderr b/src/test/ui/closures/closure-move-sync.stderr index f4d08ea5b8..da5e25c0d1 100644 --- a/src/test/ui/closures/closure-move-sync.stderr +++ b/src/test/ui/closures/closure-move-sync.stderr @@ -7,26 +7,26 @@ LL | let t = thread::spawn(|| { ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL | LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` + | ---- required by this bound in `spawn` | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver<()>` - = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Receiver<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6 recv:&std::sync::mpsc::Receiver<()>]` + = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver<()>` + = note: required because of the requirements on the impl of `Send` for `&std::sync::mpsc::Receiver<()>` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:6:27: 9:6]` -error[E0277]: `std::sync::mpsc::Sender<()>` cannot be shared between threads safely +error[E0277]: `Sender<()>` cannot be shared between threads safely --> $DIR/closure-move-sync.rs:18:5 | LL | thread::spawn(|| tx.send(()).unwrap()); - | ^^^^^^^^^^^^^ `std::sync::mpsc::Sender<()>` cannot be shared between threads safely + | ^^^^^^^^^^^^^ `Sender<()>` cannot be shared between threads safely | ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL | LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` + | ---- required by this bound in `spawn` | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender<()>` - = note: required because of the requirements on the impl of `std::marker::Send` for `&std::sync::mpsc::Sender<()>` - = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42 tx:&std::sync::mpsc::Sender<()>]` + = help: the trait `Sync` is not implemented for `Sender<()>` + = note: required because of the requirements on the impl of `Send` for `&Sender<()>` + = note: required because it appears within the type `[closure@$DIR/closure-move-sync.rs:18:19: 18:42]` error: aborting due to 2 previous errors diff --git a/src/test/ui/closures/closure-no-fn-1.stderr b/src/test/ui/closures/closure-no-fn-1.stderr index 5e76ee5a9a..76136315a1 100644 --- a/src/test/ui/closures/closure-no-fn-1.stderr +++ b/src/test/ui/closures/closure-no-fn-1.stderr @@ -7,7 +7,7 @@ LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; | expected due to this | = note: expected fn pointer `fn(u8) -> u8` - found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50 a:_]` + found closure `[closure@$DIR/closure-no-fn-1.rs:6:29: 6:50]` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-no-fn-2.stderr b/src/test/ui/closures/closure-no-fn-2.stderr index 07ffd6e5c9..85cbdbe7c1 100644 --- a/src/test/ui/closures/closure-no-fn-2.stderr +++ b/src/test/ui/closures/closure-no-fn-2.stderr @@ -7,7 +7,7 @@ LL | let bar: fn() -> u8 = || { b }; | expected due to this | = note: expected fn pointer `fn() -> u8` - found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35 b:_]` + found closure `[closure@$DIR/closure-no-fn-2.rs:6:27: 6:35]` error: aborting due to previous error diff --git a/src/test/ui/closures/closure-no-fn-3.stderr b/src/test/ui/closures/closure-no-fn-3.stderr index 4b3b4be798..95683a786b 100644 --- a/src/test/ui/closures/closure-no-fn-3.stderr +++ b/src/test/ui/closures/closure-no-fn-3.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37 b:_]` as `fn() -> u8` +error[E0605]: non-primitive cast: `[closure@$DIR/closure-no-fn-3.rs:6:27: 6:37]` as `fn() -> u8` --> $DIR/closure-no-fn-3.rs:6:27 | LL | let baz: fn() -> u8 = (|| { b }) as fn() -> u8; diff --git a/src/test/ui/closures/closure-reform-bad.stderr b/src/test/ui/closures/closure-reform-bad.stderr index 3c4ae45076..77c8c7ab79 100644 --- a/src/test/ui/closures/closure-reform-bad.stderr +++ b/src/test/ui/closures/closure-reform-bad.stderr @@ -7,7 +7,7 @@ LL | call_bare(f) | ^ expected fn pointer, found closure | = note: expected fn pointer `for<'r> fn(&'r str)` - found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50 string:_]` + found closure `[closure@$DIR/closure-reform-bad.rs:10:13: 10:50]` error: aborting due to previous error diff --git a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr index 63eb0bd8fa..bd2e31648c 100644 --- a/src/test/ui/closures/closure_cap_coerce_many_fail.stderr +++ b/src/test/ui/closures/closure_cap_coerce_many_fail.stderr @@ -12,7 +12,7 @@ LL | | }; | |_____- `match` arms have incompatible types | = note: expected type `fn(i32, i32) -> i32 {add}` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:9:16: 9:43]` error[E0308]: `match` arms have incompatible types --> $DIR/closure_cap_coerce_many_fail.rs:18:16 @@ -28,7 +28,7 @@ LL | | }; | |_____- `match` arms have incompatible types | = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:17:16: 17:37]` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43 cap:_]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:18:16: 18:43]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object @@ -38,14 +38,14 @@ error[E0308]: `match` arms have incompatible types LL | let _ = match "+" { | _____________- LL | | "+" => |a, b| (a + b + cap) as i32, - | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]` LL | | "-" => |a, b| (a - b) as i32, | | ^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure LL | | _ => unimplemented!(), LL | | }; | |_____- `match` arms have incompatible types | - = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43 cap:_]` + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:26:16: 26:43]` found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:27:16: 27:37]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object @@ -56,15 +56,15 @@ error[E0308]: `match` arms have incompatible types LL | let _ = match "+" { | _____________- LL | | "+" => |a, b| (a + b + cap) as i32, - | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` + | | --------------------------- this is found to be of type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]` LL | | "-" => |a, b| (a - b + cap) as i32, | | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected closure, found a different closure LL | | _ => unimplemented!(), LL | | }; | |_____- `match` arms have incompatible types | - = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43 cap:_]` - found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43 cap:_]` + = note: expected type `[closure@$DIR/closure_cap_coerce_many_fail.rs:34:16: 34:43]` + found closure `[closure@$DIR/closure_cap_coerce_many_fail.rs:35:16: 35:43]` = note: no two closures, even if identical, have the same type = help: consider boxing your closure and/or using it as a trait object diff --git a/src/test/ui/closures/issue-41366.stderr b/src/test/ui/closures/issue-41366.stderr index 9c4b7d529e..df0495cdc4 100644 --- a/src/test/ui/closures/issue-41366.stderr +++ b/src/test/ui/closures/issue-41366.stderr @@ -7,7 +7,7 @@ LL | (&|_| ()) as &dyn for<'x> Fn(>::V); | | found signature of `fn(u16) -> _` | expected signature of `fn(>::V) -> _` | - = note: required for the cast to the object type `dyn for<'x> std::ops::Fn(>::V)` + = note: required for the cast to the object type `dyn for<'x> Fn(>::V)` error: aborting due to previous error diff --git a/src/test/ui/closures/print/closure-print-generic-1.rs b/src/test/ui/closures/print/closure-print-generic-1.rs new file mode 100644 index 0000000000..504b4adbeb --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-1.rs @@ -0,0 +1,23 @@ +fn to_fn_once(f: F) -> F { + f +} + +fn f(y: T) { + struct Foo { + x: U, + }; + + let foo = Foo { x: "x" }; + + let c = to_fn_once(move || { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + +fn main() { + f("S"); +} diff --git a/src/test/ui/closures/print/closure-print-generic-1.stderr b/src/test/ui/closures/print/closure-print-generic-1.stderr new file mode 100644 index 0000000000..43a12f675f --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-1.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/closure-print-generic-1.rs:17:5 + | +LL | let c = to_fn_once(move || { + | - move occurs because `c` has type `[closure@$DIR/closure-print-generic-1.rs:12:24: 14:6]`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/closure-print-generic-1.rs:16:5 + | +LL | c(); + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/print/closure-print-generic-2.rs b/src/test/ui/closures/print/closure-print-generic-2.rs new file mode 100644 index 0000000000..3f77fd26b1 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-2.rs @@ -0,0 +1,13 @@ +mod mod1 { + pub fn f(t: T) { + let x = 20; + + let c = || println!("{} {}", t, x); + let c1: () = c; + //~^ ERROR mismatched types + } +} + +fn main() { + mod1::f(5i32); +} diff --git a/src/test/ui/closures/print/closure-print-generic-2.stderr b/src/test/ui/closures/print/closure-print-generic-2.stderr new file mode 100644 index 0000000000..f7cfbd251b --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-2.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-generic-2.rs:6:22 + | +LL | let c = || println!("{} {}", t, x); + | -------------------------- the found closure +LL | let c1: () = c; + | -- ^ expected `()`, found closure + | | + | expected due to this + | + = note: expected unit type `()` + found closure `[closure@$DIR/closure-print-generic-2.rs:5:17: 5:43]` +help: use parentheses to call this closure + | +LL | let c1: () = c(); + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs new file mode 100644 index 0000000000..07bf8fe4c0 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.rs @@ -0,0 +1,16 @@ +// compile-flags: -Ztrim-diagnostic-paths=off -Zverbose + +mod mod1 { + pub fn f(t: T) + { + let x = 20; + + let c = || println!("{} {}", t, x); + let c1 : () = c; + //~^ ERROR mismatched types + } +} + +fn main() { + mod1::f(5i32); +} diff --git a/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr new file mode 100644 index 0000000000..7fd929221d --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-trim-off-verbose-2.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-generic-trim-off-verbose-2.rs:9:23 + | +LL | let c = || println!("{} {}", t, x); + | -------------------------- the found closure +LL | let c1 : () = c; + | -- ^ expected `()`, found closure + | | + | expected due to this + | + = note: expected unit type `()` + found closure `[mod1::f::{closure#0} closure_substs=(unavailable)]` +help: use parentheses to call this closure + | +LL | let c1 : () = c(); + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-1.rs b/src/test/ui/closures/print/closure-print-generic-verbose-1.rs new file mode 100644 index 0000000000..67d37f1c59 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-1.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zverbose + +fn to_fn_once(f: F) -> F { f } + +fn f(y: T) { + struct Foo { + x: U + }; + + let foo = Foo{ x: "x" }; + + let c = to_fn_once(move|| { + println!("{} {}", foo.x, y); + }); + + c(); + c(); + //~^ ERROR use of moved value +} + + +fn main() { + f("S"); +} diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr new file mode 100644 index 0000000000..fdaf353fe3 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-1.stderr @@ -0,0 +1,20 @@ +error[E0382]: use of moved value: `c` + --> $DIR/closure-print-generic-verbose-1.rs:17:5 + | +LL | let c = to_fn_once(move|| { + | - move occurs because `c` has type `[f::{closure#0} closure_kind_ty=i32 closure_sig_as_fn_ptr_ty=extern "rust-call" fn(()) upvar_tys=(Foo<&'_#10r str>, T)]`, which does not implement the `Copy` trait +... +LL | c(); + | --- `c` moved due to this call +LL | c(); + | ^ value used here after move + | +note: this value implements `FnOnce`, which causes it to be moved when called + --> $DIR/closure-print-generic-verbose-1.rs:16:5 + | +LL | c(); + | ^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.rs b/src/test/ui/closures/print/closure-print-generic-verbose-2.rs new file mode 100644 index 0000000000..f460fedffb --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.rs @@ -0,0 +1,16 @@ +// compile-flags: -Zverbose + +mod mod1 { + pub fn f(t: T) + { + let x = 20; + + let c = || println!("{} {}", t, x); + let c1 : () = c; + //~^ ERROR mismatched types + } +} + +fn main() { + mod1::f(5i32); +} diff --git a/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr new file mode 100644 index 0000000000..680f6ff679 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-generic-verbose-2.stderr @@ -0,0 +1,20 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-generic-verbose-2.rs:9:23 + | +LL | let c = || println!("{} {}", t, x); + | -------------------------- the found closure +LL | let c1 : () = c; + | -- ^ expected `()`, found closure + | | + | expected due to this + | + = note: expected unit type `()` + found closure `[f::{closure#0} closure_substs=(unavailable)]` +help: use parentheses to call this closure + | +LL | let c1 : () = c(); + | ^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/closures/print/closure-print-verbose.rs b/src/test/ui/closures/print/closure-print-verbose.rs new file mode 100644 index 0000000000..4b0438a91e --- /dev/null +++ b/src/test/ui/closures/print/closure-print-verbose.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zverbose + +// Same as closure-coerce-fn-1.rs + +// Ensure that capturing closures are never coerced to fns +// Especially interesting as non-capturing closures can be. + +fn main() { + let mut a = 0u8; + let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/closures/print/closure-print-verbose.stderr b/src/test/ui/closures/print/closure-print-verbose.stderr new file mode 100644 index 0000000000..9e07137a24 --- /dev/null +++ b/src/test/ui/closures/print/closure-print-verbose.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/closure-print-verbose.rs:10:29 + | +LL | let foo: fn(u8) -> u8 = |v: u8| { a += v; a }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^ expected fn pointer, found closure + | | + | expected due to this + | + = note: expected fn pointer `fn(u8) -> u8` + found closure `[main::{closure#0} closure_substs=(unavailable)]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/cmse-nonsecure-entry/gate_test.rs b/src/test/ui/cmse-nonsecure-entry/gate_test.rs new file mode 100644 index 0000000000..02d5f20feb --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/gate_test.rs @@ -0,0 +1,11 @@ +// gate-test-cmse_nonsecure_entry + +#[no_mangle] +#[cmse_nonsecure_entry] +//~^ ERROR [E0775] +//~| ERROR [E0658] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} + +fn main() {} diff --git a/src/test/ui/cmse-nonsecure-entry/gate_test.stderr b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr new file mode 100644 index 0000000000..75a29b317d --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/gate_test.stderr @@ -0,0 +1,19 @@ +error[E0658]: the `#[cmse_nonsecure_entry]` attribute is an experimental feature + --> $DIR/gate_test.rs:4:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #75835 for more information + = help: add `#![feature(cmse_nonsecure_entry)]` to the crate attributes to enable + +error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension + --> $DIR/gate_test.rs:4:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +Some errors have detailed explanations: E0658, E0775. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs new file mode 100644 index 0000000000..a723eb7347 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-registers.rs @@ -0,0 +1,11 @@ +// build-pass +// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +// only-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] +#![no_std] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 { + a + b + c + d +} diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs new file mode 100644 index 0000000000..553d3a8cb0 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.rs @@ -0,0 +1,10 @@ +// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +// only-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] +#![no_std] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub extern "C" fn entry_function(a: u32, b: u32, c: u32, d: u32, e: u32) -> u32 { //~ ERROR + a + b + c + d + e +} diff --git a/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr new file mode 100644 index 0000000000..d9956acbe7 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/params-on-stack.stderr @@ -0,0 +1,5 @@ +error: :0:0: in function entry_function i32 (i32, i32, i32, i32, i32): secure entry function requires arguments on stack + + +error: aborting due to previous error + diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs new file mode 100644 index 0000000000..3783e27940 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.rs @@ -0,0 +1,10 @@ +// ignore-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] + +#[no_mangle] +#[cmse_nonsecure_entry] //~ ERROR [E0775] +pub extern "C" fn entry_function(input: u32) -> u32 { + input + 6 +} + +fn main() {} diff --git a/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr new file mode 100644 index 0000000000..7e8862f9ab --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/trustzone-only.stderr @@ -0,0 +1,9 @@ +error[E0775]: `#[cmse_nonsecure_entry]` is only valid for targets with the TrustZone-M extension + --> $DIR/trustzone-only.rs:5:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0775`. diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs new file mode 100644 index 0000000000..611c8643dc --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.rs @@ -0,0 +1,10 @@ +// compile-flags: --target thumbv8m.main-none-eabi --crate-type lib +// only-thumbv8m.main-none-eabi +#![feature(cmse_nonsecure_entry)] +#![no_std] + +#[no_mangle] +#[cmse_nonsecure_entry] +pub fn entry_function(a: u32, b: u32, c: u32, d: u32) -> u32 { //~ ERROR [E0776] + a + b + c + d +} diff --git a/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr new file mode 100644 index 0000000000..d6967a11e6 --- /dev/null +++ b/src/test/ui/cmse-nonsecure-entry/wrong-abi.stderr @@ -0,0 +1,9 @@ +error[E0776]: `#[cmse_nonsecure_entry]` functions require C ABI + --> $DIR/wrong-abi.rs:7:1 + | +LL | #[cmse_nonsecure_entry] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0776`. diff --git a/src/test/ui/codemap_tests/bad-format-args.rs b/src/test/ui/codemap_tests/bad-format-args.rs index dff248344a..e89a45a84f 100644 --- a/src/test/ui/codemap_tests/bad-format-args.rs +++ b/src/test/ui/codemap_tests/bad-format-args.rs @@ -1,5 +1,5 @@ fn main() { format!(); //~ ERROR requires at least a format string argument - format!("" 1); //~ ERROR expected token: `,` + format!("" 1); //~ ERROR expected `,`, found `1` format!("", 1 1); //~ ERROR expected one of } diff --git a/src/test/ui/codemap_tests/bad-format-args.stderr b/src/test/ui/codemap_tests/bad-format-args.stderr index 96d7b07b0e..5ed023e1f2 100644 --- a/src/test/ui/codemap_tests/bad-format-args.stderr +++ b/src/test/ui/codemap_tests/bad-format-args.stderr @@ -6,7 +6,7 @@ LL | format!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: expected token: `,` +error: expected `,`, found `1` --> $DIR/bad-format-args.rs:3:16 | LL | format!("" 1); diff --git a/src/test/ui/codemap_tests/empty_span.stderr b/src/test/ui/codemap_tests/empty_span.stderr index 1dd99cfd64..e36f59ee54 100644 --- a/src/test/ui/codemap_tests/empty_span.stderr +++ b/src/test/ui/codemap_tests/empty_span.stderr @@ -1,4 +1,4 @@ -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static main::Foo` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `&'static Foo` --> $DIR/empty_span.rs:7:5 | LL | unsafe impl Send for &'static Foo { } diff --git a/src/test/ui/codemap_tests/tab_3.stderr b/src/test/ui/codemap_tests/tab_3.stderr index f07959cdd8..958d54bbb1 100644 --- a/src/test/ui/codemap_tests/tab_3.stderr +++ b/src/test/ui/codemap_tests/tab_3.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `some_vec` --> $DIR/tab_3.rs:7:20 | LL | let some_vec = vec!["hi"]; - | -------- move occurs because `some_vec` has type `std::vec::Vec<&str>`, which does not implement the `Copy` trait + | -------- move occurs because `some_vec` has type `Vec<&str>`, which does not implement the `Copy` trait LL | some_vec.into_iter(); | ----------- `some_vec` moved due to this method call LL | { diff --git a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr index 93e16bac13..f0109f22a2 100644 --- a/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr +++ b/src/test/ui/coercion/coerce-expect-unsized-ascribed.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | let _ = box { [1, 2, 3] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:10:13 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | let _ = box if true { [1, 2, 3] } else { [1, 3, 4] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:11:13 @@ -22,35 +22,35 @@ error[E0308]: mismatched types LL | let _ = box match true { true => [1, 2, 3], false => [1, 3, 4] }: Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:13:13 | LL | let _ = box { |x| (x as u8) }: Box _>; - | ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure + | ^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | - = note: expected struct `std::boxed::Box u8>` - found struct `std::boxed::Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:32]>` + = note: expected struct `Box u8>` + found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:13:19: 13:32]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:14:13 | LL | let _ = box if true { false } else { true }: Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool` | - = note: expected struct `std::boxed::Box` - found struct `std::boxed::Box` + = note: expected struct `Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:15:13 | LL | let _ = box match true { true => 'a', false => 'b' }: Box; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `char` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char` | - = note: expected struct `std::boxed::Box` - found struct `std::boxed::Box` + = note: expected struct `Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:17:13 @@ -83,27 +83,27 @@ error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:21:13 | LL | let _ = &{ |x| (x as u8) }: &dyn Fn(i32) -> _; - | ^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure + | ^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | - = note: expected reference `&dyn std::ops::Fn(i32) -> u8` + = note: expected reference `&dyn Fn(i32) -> u8` found reference `&[closure@$DIR/coerce-expect-unsized-ascribed.rs:21:16: 21:29]` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:22:13 | LL | let _ = &if true { false } else { true }: &dyn Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `bool` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `bool` | - = note: expected reference `&dyn std::fmt::Debug` + = note: expected reference `&dyn Debug` found reference `&bool` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:23:13 | LL | let _ = &match true { true => 'a', false => 'b' }: &dyn Debug; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::fmt::Debug`, found `char` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Debug`, found `char` | - = note: expected reference `&dyn std::fmt::Debug` + = note: expected reference `&dyn Debug` found reference `&char` error[E0308]: mismatched types @@ -112,17 +112,17 @@ error[E0308]: mismatched types LL | let _ = Box::new([1, 2, 3]): Box<[i32]>; | ^^^^^^^^^^^^^^^^^^^ expected slice `[i32]`, found array `[i32; 3]` | - = note: expected struct `std::boxed::Box<[i32]>` - found struct `std::boxed::Box<[i32; 3]>` + = note: expected struct `Box<[i32]>` + found struct `Box<[i32; 3]>` error[E0308]: mismatched types --> $DIR/coerce-expect-unsized-ascribed.rs:26:13 | LL | let _ = Box::new(|x| (x as u8)): Box _>; - | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn std::ops::Fn`, found closure + | ^^^^^^^^^^^^^^^^^^^^^^^ expected trait object `dyn Fn`, found closure | - = note: expected struct `std::boxed::Box u8>` - found struct `std::boxed::Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>` + = note: expected struct `Box u8>` + found struct `Box<[closure@$DIR/coerce-expect-unsized-ascribed.rs:26:22: 26:35]>` error: aborting due to 14 previous errors diff --git a/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr b/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr index 91cf925e68..a2008f0426 100644 --- a/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr +++ b/src/test/ui/coherence/coherence-blanket-conflicts-with-specific-cross-crate.stderr @@ -5,8 +5,8 @@ LL | impl GoMut for MyThingy { | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `go_trait`: - - impl go_trait::GoMut for G - where G: go_trait::Go; + - impl GoMut for G + where G: Go; error: aborting due to previous error diff --git a/src/test/ui/coherence/coherence-cow.re_a.stderr b/src/test/ui/coherence/coherence-cow.re_a.stderr index 06e77b2797..0cf2a406da 100644 --- a/src/test/ui/coherence/coherence-cow.re_a.stderr +++ b/src/test/ui/coherence/coherence-cow.re_a.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-cow.re_b.stderr b/src/test/ui/coherence/coherence-cow.re_b.stderr index 39f211eff3..b523db4da2 100644 --- a/src/test/ui/coherence/coherence-cow.re_b.stderr +++ b/src/test/ui/coherence/coherence-cow.re_b.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair,T> { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-cow.re_c.stderr b/src/test/ui/coherence/coherence-cow.re_c.stderr index 94bb0d2166..bd635fc2e8 100644 --- a/src/test/ui/coherence/coherence-cow.re_c.stderr +++ b/src/test/ui/coherence/coherence-cow.re_c.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair,U> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr index c00751a0f2..5381053979 100644 --- a/src/test/ui/coherence/coherence-cross-crate-conflict.stderr +++ b/src/test/ui/coherence/coherence-cross-crate-conflict.stderr @@ -5,7 +5,7 @@ LL | impl Foo for A { | ^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `trait_impl_conflict`: - - impl trait_impl_conflict::Foo for isize; + - impl Foo for isize; error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/coherence-cross-crate-conflict.rs:9:6 diff --git a/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr b/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr index 06cfdeb390..a35a95ef4b 100644 --- a/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr +++ b/src/test/ui/coherence/coherence-fundamental-trait-objects.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Misc for dyn Fundamental {} | ^^^^^^^^^^^^^^---------------------- | | | - | | `dyn coherence_fundamental_trait_lib::Fundamental` is not defined in the current crate + | | `dyn Fundamental` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr index 23db5328a7..c364c707ff 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-negative.stderr @@ -21,13 +21,13 @@ LL | impl !Send for dyn Marker2 {} | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:27:1 | LL | impl !Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-negative.rs:28:1 | LL | impl !Send for dyn Object + Marker2 {} diff --git a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr index 141ab7771f..b80429794f 100644 --- a/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr +++ b/src/test/ui/coherence/coherence-impl-trait-for-marker-trait-positive.stderr @@ -21,13 +21,13 @@ LL | unsafe impl Send for dyn Marker2 {} | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:27:1 | LL | unsafe impl Send for dyn Object {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't implement cross-crate trait with a default impl for non-struct/enum type -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `(dyn Object + Marker2 + 'static)` --> $DIR/coherence-impl-trait-for-marker-trait-positive.rs:28:1 | LL | unsafe impl Send for dyn Object + Marker2 {} diff --git a/src/test/ui/coherence/coherence-impls-copy.stderr b/src/test/ui/coherence/coherence-impls-copy.stderr index be040b38d6..8cc24f099e 100644 --- a/src/test/ui/coherence/coherence-impls-copy.stderr +++ b/src/test/ui/coherence/coherence-impls-copy.stderr @@ -5,7 +5,7 @@ LL | impl Copy for i32 {} | ^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Copy for i32; + - impl Copy for i32; error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&NotSync`: --> $DIR/coherence-impls-copy.rs:29:1 @@ -14,7 +14,7 @@ LL | impl Copy for &'static NotSync {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Copy for &T + - impl Copy for &T where T: ?Sized; error[E0119]: conflicting implementations of trait `std::marker::Copy` for type `&[NotSync]`: @@ -24,7 +24,7 @@ LL | impl Copy for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Copy for &T + - impl Copy for &T where T: ?Sized; error[E0206]: the trait `Copy` may not be implemented for this type diff --git a/src/test/ui/coherence/coherence-impls-send.stderr b/src/test/ui/coherence/coherence-impls-send.stderr index dbfc968332..edca31b5da 100644 --- a/src/test/ui/coherence/coherence-impls-send.stderr +++ b/src/test/ui/coherence/coherence-impls-send.stderr @@ -5,8 +5,8 @@ LL | unsafe impl Send for &'static [NotSync] {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::marker::Send for &T - where T: std::marker::Sync, T: ?Sized; + - impl Send for &T + where T: Sync, T: ?Sized; = note: upstream crates may add a new impl of trait `std::marker::Sync` for type `[NotSync]` in future versions error[E0117]: only traits defined in the current crate can be implemented for arbitrary types @@ -20,7 +20,7 @@ LL | unsafe impl Send for (MyType, MyType) {} | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `std::marker::Send`, can only be implemented for a struct/enum type, not `&'static NotSync` +error[E0321]: cross-crate traits with a default impl, like `Send`, can only be implemented for a struct/enum type, not `&'static NotSync` --> $DIR/coherence-impls-send.rs:19:1 | LL | unsafe impl Send for &'static NotSync {} diff --git a/src/test/ui/coherence/coherence-orphan.stderr b/src/test/ui/coherence/coherence-orphan.stderr index fb518f8ecb..52d2cc88cb 100644 --- a/src/test/ui/coherence/coherence-orphan.stderr +++ b/src/test/ui/coherence/coherence-orphan.stderr @@ -16,7 +16,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl !Send for Vec { } | ^^^^^^^^^^^^^^^---------- | | | - | | `std::vec::Vec` is not defined in the current crate + | | `Vec` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-overlapping-pairs.stderr b/src/test/ui/coherence/coherence-overlapping-pairs.stderr index 69a4627a7b..c1a02681c1 100644 --- a/src/test/ui/coherence/coherence-overlapping-pairs.stderr +++ b/src/test/ui/coherence/coherence-overlapping-pairs.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for lib::Pair { } | ^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr b/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr index f6b9869e17..b18bf44dbd 100644 --- a/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr +++ b/src/test/ui/coherence/coherence-pair-covered-uncovered-1.stderr @@ -5,7 +5,7 @@ LL | impl Remote1>> for i32 { } | ^^^^^^^^^^^--------------------------^^^^^--- | | | | | | | `i32` is not defined in the current crate - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr b/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr index d1a4993e0f..34fdf64ea1 100644 --- a/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr +++ b/src/test/ui/coherence/coherence-pair-covered-uncovered.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Pair> { } | ^^^^^^^^^^^^^^^^^^^^^---------------- | | | - | | `lib::Pair` is not defined in the current crate + | | `Pair` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-vec-local-2.stderr b/src/test/ui/coherence/coherence-vec-local-2.stderr index 198314d5ce..567b6a6c17 100644 --- a/src/test/ui/coherence/coherence-vec-local-2.stderr +++ b/src/test/ui/coherence/coherence-vec-local-2.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Vec> { } | ^^^^^^^^^^^^^^^^^^^------------- | | | - | | `std::vec::Vec` is not defined in the current crate + | | `Vec` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence-vec-local.stderr b/src/test/ui/coherence/coherence-vec-local.stderr index dc5a0a6895..38464f12a2 100644 --- a/src/test/ui/coherence/coherence-vec-local.stderr +++ b/src/test/ui/coherence/coherence-vec-local.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Vec { } | ^^^^^^^^^^^^^^^^---------- | | | - | | `std::vec::Vec` is not defined in the current crate + | | `Vec` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/coherence_inherent.stderr b/src/test/ui/coherence/coherence_inherent.stderr index 3d37d8af31..6f36f2a751 100644 --- a/src/test/ui/coherence/coherence_inherent.stderr +++ b/src/test/ui/coherence/coherence_inherent.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `the_fn` found for reference `&Lib::TheStruct` in the current scope +error[E0599]: no method named `the_fn` found for reference `&TheStruct` in the current scope --> $DIR/coherence_inherent.rs:31:11 | LL | s.the_fn(); - | ^^^^^^ method not found in `&Lib::TheStruct` + | ^^^^^^ 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: diff --git a/src/test/ui/coherence/coherence_inherent_cc.stderr b/src/test/ui/coherence/coherence_inherent_cc.stderr index d968c8b468..edfe6348d1 100644 --- a/src/test/ui/coherence/coherence_inherent_cc.stderr +++ b/src/test/ui/coherence/coherence_inherent_cc.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `the_fn` found for reference `&coherence_inherent_cc_lib::TheStruct` in the current scope +error[E0599]: no method named `the_fn` found for reference `&TheStruct` in the current scope --> $DIR/coherence_inherent_cc.rs:23:11 | LL | s.the_fn(); - | ^^^^^^ method not found in `&coherence_inherent_cc_lib::TheStruct` + | ^^^^^^ 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: diff --git a/src/test/ui/coherence/coherence_local_err_struct.stderr b/src/test/ui/coherence/coherence_local_err_struct.stderr index 0a1aee9b5c..8c310b318a 100644 --- a/src/test/ui/coherence/coherence_local_err_struct.stderr +++ b/src/test/ui/coherence/coherence_local_err_struct.stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl lib::MyCopy for lib::MyStruct { } | ^^^^^^^^^^^^^^^^^^^^^--------------------- | | | - | | `lib::MyStruct` is not defined in the current crate + | | `MyStruct` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/conflicting-impl-with-err.stderr b/src/test/ui/coherence/conflicting-impl-with-err.stderr index a8a5730acc..3009b452dc 100644 --- a/src/test/ui/coherence/conflicting-impl-with-err.stderr +++ b/src/test/ui/coherence/conflicting-impl-with-err.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:4:11 | LL | impl From for Error { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` -error[E0433]: failed to resolve: use of undeclared type or module `nope` +error[E0433]: failed to resolve: use of undeclared crate or module `nope` --> $DIR/conflicting-impl-with-err.rs:5:16 | LL | fn from(_: nope::Thing) -> Self { - | ^^^^ use of undeclared type or module `nope` + | ^^^^ use of undeclared crate or module `nope` error: aborting due to 2 previous errors diff --git a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr index a33cff2a4d..bdf19cf00a 100644 --- a/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr +++ b/src/test/ui/coherence/impl-foreign-for-foreign[foreign].stderr @@ -5,7 +5,7 @@ LL | impl Remote1> for i32 { | ^^^^^----------------^^^^^--- | | | | | | | `i32` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -17,7 +17,7 @@ LL | impl Remote1> for f64 { | ^^^^^------------------^^^^^--- | | | | | | | `f64` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -29,7 +29,7 @@ LL | impl Remote1> for f32 { | ^^^^^^^^--------------^^^^^--- | | | | | | | `f32` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr index bd1a933b76..0959e155c5 100644 --- a/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr +++ b/src/test/ui/coherence/impl-foreign-for-fundamental[foreign].stderr @@ -15,7 +15,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Box> { | ^^^^^^^^^^^^^^^^^^^---------- | | | - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr index 3ca40e0072..b4d559eb1f 100644 --- a/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr +++ b/src/test/ui/coherence/impl-foreign[fundemental[foreign]]-for-foreign.stderr @@ -5,7 +5,7 @@ LL | impl Remote1> for i32 { | ^^^^^--------------------^^^^^--- | | | | | | | `i32` is not defined in the current crate - | | `std::string::String` is not defined in the current crate + | | `String` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -17,7 +17,7 @@ LL | impl Remote1>> for f64 { | ^^^^^---------------------^^^^^--- | | | | | | | `f64` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -29,7 +29,7 @@ LL | impl Remote1>> for f32 { | ^^^^^^^^-------------------^^^^^--- | | | | | | | `f32` is not defined in the current crate - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr index 95889022bd..7f8ec83b24 100644 --- a/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr +++ b/src/test/ui/coherence/impl[t]-foreign-for-foreign[t].stderr @@ -4,7 +4,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Rc { | ^^^^^^^^^^^^^^^^--------- | | | - | | `std::rc::Rc` is not defined in the current crate + | | `Rc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead @@ -15,7 +15,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl Remote for Arc { | ^^^^^^^^^^^^^^^^^^^------ | | | - | | `std::sync::Arc` is not defined in the current crate + | | `Arc` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr index 5d09038076..83a2ae6068 100644 --- a/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr +++ b/src/test/ui/compare-method/trait-bound-on-type-parameter.stderr @@ -5,7 +5,7 @@ LL | fn b(&self, x: C) -> C; | ---------------------------- definition of `b` from trait ... LL | fn b(&self, _x: F) -> F { panic!() } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: std::marker::Sync` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `F: Sync` error: aborting due to previous error diff --git a/src/test/ui/compare-method/traits-misc-mismatch-1.stderr b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr index 717c0d2315..da94fc6584 100644 --- a/src/test/ui/compare-method/traits-misc-mismatch-1.stderr +++ b/src/test/ui/compare-method/traits-misc-mismatch-1.stderr @@ -5,7 +5,7 @@ LL | fn test_error1_fn(&self); | -------------------------------- definition of `test_error1_fn` from trait ... LL | fn test_error1_fn(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Ord` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Ord` error[E0276]: impl has stricter requirements than trait --> $DIR/traits-misc-mismatch-1.rs:31:5 @@ -41,7 +41,7 @@ LL | fn test_error7_fn(&self); | ------------------------------- definition of `test_error7_fn` from trait ... LL | fn test_error7_fn(&self) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::cmp::Eq` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Eq` error[E0276]: impl has stricter requirements than trait --> $DIR/traits-misc-mismatch-1.rs:54:5 diff --git a/src/test/ui/confuse-field-and-method/issue-2392.stderr b/src/test/ui/confuse-field-and-method/issue-2392.stderr index f9dfdddad9..051940bbe9 100644 --- a/src/test/ui/confuse-field-and-method/issue-2392.stderr +++ b/src/test/ui/confuse-field-and-method/issue-2392.stderr @@ -90,7 +90,7 @@ LL | w.wrap.not_closure(); | | | field, not a method -error[E0599]: no method named `closure` found for struct `Obj u32 + 'static)>>` in the current scope +error[E0599]: no method named `closure` found for struct `Obj u32 + 'static)>>` in the current scope --> $DIR/issue-2392.rs:58:24 | LL | struct Obj where F: FnOnce() -> u32 { diff --git a/src/test/ui/confuse-field-and-method/private-field.stderr b/src/test/ui/confuse-field-and-method/private-field.stderr index 82cb235d47..fd98a86474 100644 --- a/src/test/ui/confuse-field-and-method/private-field.stderr +++ b/src/test/ui/confuse-field-and-method/private-field.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `dog_age` found for struct `animal::Dog` in the current scope +error[E0599]: no method named `dog_age` found for struct `Dog` in the current scope --> $DIR/private-field.rs:16:23 | LL | pub struct Dog { diff --git a/src/test/ui/conservative_impl_trait.stderr b/src/test/ui/conservative_impl_trait.stderr index 58223d9d3b..87058c3c29 100644 --- a/src/test/ui/conservative_impl_trait.stderr +++ b/src/test/ui/conservative_impl_trait.stderr @@ -4,7 +4,7 @@ error[E0277]: `()` is not an iterator LL | fn will_ice(something: &u32) -> impl Iterator { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/const-generics/argument_order.stderr b/src/test/ui/const-generics/argument_order.full.stderr similarity index 91% rename from src/test/ui/const-generics/argument_order.stderr rename to src/test/ui/const-generics/argument_order.full.stderr index d6546a768d..b52e505070 100644 --- a/src/test/ui/const-generics/argument_order.stderr +++ b/src/test/ui/const-generics/argument_order.full.stderr @@ -1,11 +1,11 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/argument_order.rs:9:32 + --> $DIR/argument_order.rs:12:32 | LL | struct AlsoBad { | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then consts and types: `<'a, 'b, const N: usize, T, const M: usize, U>` error[E0747]: lifetime provided when a type was expected - --> $DIR/argument_order.rs:16:23 + --> $DIR/argument_order.rs:20:23 | LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>; | ^^^^^^^ diff --git a/src/test/ui/const-generics/argument_order.min.stderr b/src/test/ui/const-generics/argument_order.min.stderr new file mode 100644 index 0000000000..728ae69b41 --- /dev/null +++ b/src/test/ui/const-generics/argument_order.min.stderr @@ -0,0 +1,30 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/argument_order.rs:6:28 + | +LL | struct Bad { + | -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `` + +error: lifetime parameters must be declared prior to const parameters + --> $DIR/argument_order.rs:12:32 + | +LL | struct AlsoBad { + | -----------------^^-----^^-------------------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/argument_order.rs:12:36 + | +LL | struct AlsoBad { + | ---------------------^----------------------^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, 'b, T, U, const N: usize, const M: usize>` + +error[E0747]: lifetime provided when a type was expected + --> $DIR/argument_order.rs:20:23 + | +LL | let _: AlsoBad<7, 'static, u32, 'static, 17, u16>; + | ^^^^^^^ + | + = note: lifetime arguments must be provided before type arguments + = help: reorder the arguments: lifetimes, then types, then consts: `<'a, 'b, T, U, N, M>` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/argument_order.rs b/src/test/ui/const-generics/argument_order.rs index 9e071e674e..507baf5fd7 100644 --- a/src/test/ui/const-generics/argument_order.rs +++ b/src/test/ui/const-generics/argument_order.rs @@ -1,13 +1,17 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Bad { + //[min]~^ ERROR type parameters must be declared prior to const parameters arr: [u8; { N }], another: T, } struct AlsoBad { //~^ ERROR lifetime parameters must be declared prior + //[min]~^^ ERROR type parameters must be declared prior to const parameters a: &'a T, b: &'b U, } diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs index 49fc53b32b..390b6cc204 100644 --- a/src/test/ui/const-generics/array-wrapper-struct-ctor.rs +++ b/src/test/ui/const-generics/array-wrapper-struct-ctor.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] diff --git a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr b/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr deleted file mode 100644 index e6eb2a0a78..0000000000 --- a/src/test/ui/const-generics/array-wrapper-struct-ctor.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/array-wrapper-struct-ctor.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs index 901fb5dd05..899a5a1836 100644 --- a/src/test/ui/const-generics/auxiliary/const_generic_lib.rs +++ b/src/test/ui/const-generics/auxiliary/const_generic_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct(pub [u8; N]); diff --git a/src/test/ui/const-generics/auxiliary/impl-const.rs b/src/test/ui/const-generics/auxiliary/impl-const.rs index fc993d6392..2e25dadf11 100644 --- a/src/test/ui/const-generics/auxiliary/impl-const.rs +++ b/src/test/ui/const-generics/auxiliary/impl-const.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Num; diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs index aac5d195f7..931f6ade7f 100644 --- a/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs +++ b/src/test/ui/const-generics/cannot-infer-type-for-const-param.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // This test confirms that the types can be inferred correctly for this example with const // generics. Previously this would ICE, and more recently error. diff --git a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr b/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr deleted file mode 100644 index c5c48d7be4..0000000000 --- a/src/test/ui/const-generics/cannot-infer-type-for-const-param.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/cannot-infer-type-for-const-param.rs:2:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.full.stderr similarity index 84% rename from src/test/ui/const-generics/const-arg-type-arg-misordered.stderr rename to src/test/ui/const-generics/const-arg-type-arg-misordered.full.stderr index 2e2bfed51f..3827002ff4 100644 --- a/src/test/ui/const-generics/const-arg-type-arg-misordered.stderr +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.full.stderr @@ -1,5 +1,5 @@ error[E0747]: constant provided when a type was expected - --> $DIR/const-arg-type-arg-misordered.rs:6:35 + --> $DIR/const-arg-type-arg-misordered.rs:8:35 | LL | fn foo() -> Array { | ^ diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr b/src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr new file mode 100644 index 0000000000..2c5fc8dcc0 --- /dev/null +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.min.stderr @@ -0,0 +1,12 @@ +error[E0747]: constant provided when a type was expected + --> $DIR/const-arg-type-arg-misordered.rs:8:35 + | +LL | fn foo() -> Array { + | ^ + | + = note: type arguments must be provided before constant arguments + = help: reorder the arguments: types, then consts: `` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0747`. diff --git a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs index 13ca56ad3e..6680f772fa 100644 --- a/src/test/ui/const-generics/const-arg-type-arg-misordered.rs +++ b/src/test/ui/const-generics/const-arg-type-arg-misordered.rs @@ -1,9 +1,12 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] type Array = [T; N]; -fn foo() -> Array { //~ ERROR constant provided when a type was expected +fn foo() -> Array { + //~^ ERROR constant provided when a type was expected unimplemented!() } diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr similarity index 86% rename from src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr rename to src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr index aefd514f7a..a35c3abc11 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.stderr +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.full.stderr @@ -1,11 +1,11 @@ error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:6:67 + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 | LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements error[E0308]: mismatched types - --> $DIR/const-argument-cross-crate-mismatch.rs:8:65 + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 | LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr new file mode 100644 index 0000000000..a35c3abc11 --- /dev/null +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.min.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:7:67 + | +LL | let _ = const_generic_lib::function(const_generic_lib::Struct([0u8, 1u8])); + | ^^^^^^^^^^ expected an array with a fixed size of 3 elements, found one with 2 elements + +error[E0308]: mismatched types + --> $DIR/const-argument-cross-crate-mismatch.rs:9:65 + | +LL | let _: const_generic_lib::Alias = const_generic_lib::Struct([0u8, 1u8, 2u8]); + | ^^^^^^^^^^^^^^^ expected an array with a fixed size of 2 elements, found one with 3 elements + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs index d863d097d5..9ae2ae50ba 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate-mismatch.rs @@ -1,4 +1,5 @@ // aux-build:const_generic_lib.rs +// revisions: full min extern crate const_generic_lib; diff --git a/src/test/ui/const-generics/const-argument-cross-crate.rs b/src/test/ui/const-generics/const-argument-cross-crate.rs index 98cf39a7ee..fda3ec3eef 100644 --- a/src/test/ui/const-generics/const-argument-cross-crate.rs +++ b/src/test/ui/const-generics/const-argument-cross-crate.rs @@ -1,4 +1,5 @@ // run-pass +// revisions: full min // aux-build:const_generic_lib.rs extern crate const_generic_lib; diff --git a/src/test/ui/const-generics/const-param-before-other-params.stderr b/src/test/ui/const-generics/const-param-before-other-params.full.stderr similarity index 84% rename from src/test/ui/const-generics/const-param-before-other-params.stderr rename to src/test/ui/const-generics/const-param-before-other-params.full.stderr index 1194dd30f6..c2acaabbd8 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.stderr +++ b/src/test/ui/const-generics/const-param-before-other-params.full.stderr @@ -1,5 +1,5 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/const-param-before-other-params.rs:4:21 + --> $DIR/const-param-before-other-params.rs:6:21 | LL | fn bar(_: &'a ()) { | --------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const X: ()>` diff --git a/src/test/ui/const-generics/const-param-before-other-params.min.stderr b/src/test/ui/const-generics/const-param-before-other-params.min.stderr new file mode 100644 index 0000000000..c7e6d1be42 --- /dev/null +++ b/src/test/ui/const-generics/const-param-before-other-params.min.stderr @@ -0,0 +1,32 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/const-param-before-other-params.rs:6:21 + | +LL | fn bar(_: &'a ()) { + | --------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, const X: ()>` + +error: type parameters must be declared prior to const parameters + --> $DIR/const-param-before-other-params.rs:11:21 + | +LL | fn foo(_: &T) {} + | --------------^- help: reorder the parameters: lifetimes, then types, then consts: `` + +error: `()` is forbidden as the type of a const generic parameter + --> $DIR/const-param-before-other-params.rs:6:17 + | +LL | fn bar(_: &'a ()) { + | ^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `()` is forbidden as the type of a const generic parameter + --> $DIR/const-param-before-other-params.rs:11:17 + | +LL | fn foo(_: &T) {} + | ^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/const-param-before-other-params.rs b/src/test/ui/const-generics/const-param-before-other-params.rs index 0d787d9a67..f1be90cf2e 100644 --- a/src/test/ui/const-generics/const-param-before-other-params.rs +++ b/src/test/ui/const-generics/const-param-before-other-params.rs @@ -1,10 +1,15 @@ -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn bar(_: &'a ()) { //~^ ERROR lifetime parameters must be declared prior to const parameters + //[min]~^^ ERROR `()` is forbidden as the type of a const generic parameter } fn foo(_: &T) {} +//[min]~^ ERROR type parameters must be declared prior to const parameters +//[min]~^^ ERROR `()` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr index ba99c87722..f860788e77 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.full.stderr @@ -10,7 +10,7 @@ error[E0392]: parameter `T` is never used LL | pub struct Dependent([(); X]); | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr index ba99c87722..f860788e77 100644 --- a/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr +++ b/src/test/ui/const-generics/const-param-type-depends-on-type-param.min.stderr @@ -10,7 +10,7 @@ error[E0392]: parameter `T` is never used LL | pub struct Dependent([(); X]); | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs new file mode 100644 index 0000000000..9745dfed46 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/auxiliary/const_evaluatable_lib.rs @@ -0,0 +1,9 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +pub fn test1() -> [u8; std::mem::size_of::() - 1] +where + [u8; std::mem::size_of::() - 1]: Sized, +{ + [0; std::mem::size_of::() - 1] +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/closures.rs b/src/test/ui/const-generics/const_evaluatable_checked/closures.rs new file mode 100644 index 0000000000..32f43591e3 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/closures.rs @@ -0,0 +1,6 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +fn test() -> [u8; N + (|| 42)()] {} +//~^ ERROR overly complex generic constant + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr new file mode 100644 index 0000000000..9f0b7252e8 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/closures.stderr @@ -0,0 +1,12 @@ +error: overly complex generic constant + --> $DIR/closures.rs:3:35 + | +LL | fn test() -> [u8; N + (|| 42)()] {} + | ^^^^-------^^ + | | + | unsupported rvalue + | + = help: consider moving this anonymous constant into a `const` function + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs new file mode 100644 index 0000000000..53b2378438 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate.rs @@ -0,0 +1,15 @@ +// aux-build:const_evaluatable_lib.rs +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +extern crate const_evaluatable_lib; + +fn user() where [u8; std::mem::size_of::() - 1]: Sized { + assert_eq!(const_evaluatable_lib::test1::(), [0; std::mem::size_of::() - 1]); +} + +fn main() { + assert_eq!(const_evaluatable_lib::test1::(), [0; 3]); + user::(); + user::(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs new file mode 100644 index 0000000000..e3a4d9a96a --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.rs @@ -0,0 +1,14 @@ +// aux-build:const_evaluatable_lib.rs +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] +extern crate const_evaluatable_lib; + +fn user() { + let _ = const_evaluatable_lib::test1::(); + //~^ ERROR unconstrained generic constant + //~| ERROR unconstrained generic constant + //~| ERROR unconstrained generic constant + //~| ERROR unconstrained generic constant +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr new file mode 100644 index 0000000000..8a298b47ff --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/cross_crate_predicate.stderr @@ -0,0 +1,50 @@ +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27 + | +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:6:10 + | +LL | [u8; std::mem::size_of::() - 1]: Sized, + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: unconstrained generic constant + --> $DIR/cross_crate_predicate.rs:7:13 + | +LL | let _ = const_evaluatable_lib::test1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | +help: consider adding a `where` bound for this expression + --> $DIR/auxiliary/const_evaluatable_lib.rs:4:27 + | +LL | pub fn test1() -> [u8; std::mem::size_of::() - 1] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr new file mode 100644 index 0000000000..b2816367ea --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/feature-gate-const_evaluatable_checked.rs:9:30 + | +LL | fn test() -> Arr where Arr: Default { + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr new file mode 100644 index 0000000000..269710db16 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/feature-gate-const_evaluatable_checked.rs:6:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs new file mode 100644 index 0000000000..af3090115f --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/feature-gate-const_evaluatable_checked.rs @@ -0,0 +1,17 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +type Arr = [u8; N - 1]; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn test() -> Arr where Arr: Default { + //[full]~^ ERROR constant expression depends + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs b/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs new file mode 100644 index 0000000000..1b9ec0108b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/fn_call.rs @@ -0,0 +1,30 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +const fn test_me(a: usize, b: usize) -> usize { + if a < b { + std::mem::size_of::() + } else { + std::usize::MAX + } +} + +fn test_simple() -> [u8; std::mem::size_of::()] +where + [u8; std::mem::size_of::()]: Sized, +{ + [0; std::mem::size_of::()] +} + +fn test_with_args() -> [u8; test_me::(N, N + 1) + N] +where + [u8; test_me::(N, N + 1) + N]: Sized, +{ + [0; test_me::(N, N + 1) + N] +} + +fn main() { + assert_eq!([0; 8], test_simple::()); + assert_eq!([0; 12], test_with_args::()); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs new file mode 100644 index 0000000000..3da4688702 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.rs @@ -0,0 +1,11 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn test() -> [u8; N - 1] { + //~^ ERROR evaluation of constant + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr new file mode 100644 index 0000000000..25af18eb16 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig-fail.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/from-sig-fail.rs:4:35 + | +LL | fn test() -> [u8; N - 1] { + | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs new file mode 100644 index 0000000000..5c05a5acfe --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/from-sig.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ N > 10 }> { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs new file mode 100644 index 0000000000..193a365f9b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/impl-bounds.rs @@ -0,0 +1,25 @@ +// check-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +use std::mem::size_of; + +struct Foo(T); + +impl Foo() }> { + fn test() { + let _: [u8; std::mem::size_of::()]; + } +} + +trait Bar { + fn test_me(); +} + +impl Bar<{ size_of::() }> for Foo { + fn test_me() { + let _: [u8; std::mem::size_of::()]; + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs b/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs new file mode 100644 index 0000000000..cad06ea400 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/infer-too-generic.rs @@ -0,0 +1,24 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +use std::{mem, ptr}; + +fn split_first(arr: [T; N]) -> (T, [T; N - 1]) +where + [T; N - 1]: Sized, +{ + let arr = mem::ManuallyDrop::new(arr); + unsafe { + let head = ptr::read(&arr[0]); + let tail = ptr::read(&arr[1..] as *const [T] as *const [T; N - 1]); + (head, tail) + } +} + +fn main() { + let arr = [0, 1, 2, 3, 4]; + let (head, tail) = split_first(arr); + assert_eq!(head, 0); + assert_eq!(tail, [1, 2, 3, 4]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs b/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs new file mode 100644 index 0000000000..907ea255ab --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/less_than.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ N > 10 }> where Foo<{ N > 10 }>: Sized { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs new file mode 100644 index 0000000000..a6bb39208a --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.rs @@ -0,0 +1,15 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +// We do not yet want to support let-bindings in abstract consts, +// so this test should keep failing for now. +fn test() -> [u8; { let x = N; N + 1 }] where [u8; { let x = N; N + 1 }]: Default { + //~^ ERROR overly complex generic constant + //~| ERROR overly complex generic constant + Default::default() +} + +fn main() { + let x = test::<31>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr new file mode 100644 index 0000000000..5749defb3e --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/let-bindings.stderr @@ -0,0 +1,22 @@ +error: overly complex generic constant + --> $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 + | + = help: consider moving this anonymous constant into a `const` function + +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 + | + = help: consider moving this anonymous constant into a `const` function + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr new file mode 100644 index 0000000000..3cac604a7b --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.min.stderr @@ -0,0 +1,18 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:53 + | +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple.rs:8:35 + | +LL | fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs new file mode 100644 index 0000000000..dcf0071cb2 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple.rs @@ -0,0 +1,17 @@ +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +fn test() -> [u8; N - 1] where [u8; N - 1]: Default { + //[min]~^ ERROR generic parameters + //[min]~| ERROR generic parameters + Default::default() +} + +fn main() { + let x = test::<33>(); + assert_eq!(x, [0; 32]); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr new file mode 100644 index 0000000000..f95d6d2d57 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.full.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of constant value failed + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr = [u8; N - 1]; + | ^^^^^ attempt to compute `0_usize - 1_usize`, which would overflow + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr new file mode 100644 index 0000000000..042710f132 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/simple_fail.rs:7:33 + | +LL | type Arr = [u8; N - 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs new file mode 100644 index 0000000000..b15e0ff183 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/simple_fail.rs @@ -0,0 +1,16 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(min, feature(min_const_generics))] +#![feature(const_evaluatable_checked)] +#![allow(incomplete_features)] + +type Arr = [u8; N - 1]; //[full]~ ERROR evaluation of constant +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + +fn test() -> Arr where Arr: Sized { + todo!() +} + +fn main() { + test::<0>(); +} diff --git a/src/test/ui/const-generics/const_evaluatable_checked/unop.rs b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs new file mode 100644 index 0000000000..8e0768b1c9 --- /dev/null +++ b/src/test/ui/const-generics/const_evaluatable_checked/unop.rs @@ -0,0 +1,14 @@ +// run-pass +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Foo; + +fn test() -> Foo<{ !(N > 10) }> where Foo<{ !(N > 10) }>: Sized { + Foo +} + +fn main() { + let _: Foo = test::<12>(); + let _: Foo = test::<9>(); +} diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr new file mode 100644 index 0000000000..0574ddfb25 --- /dev/null +++ b/src/test/ui/const-generics/defaults/complex-unord-param.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/complex-unord-param.rs:9:41 + | +LL | struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + | ---------------------^----------------------^--------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, A: 'a, T: 'a, const N: usize, const M: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/complex-unord-param.rs b/src/test/ui/const-generics/defaults/complex-unord-param.rs index 72967640a8..e83a96388c 100644 --- a/src/test/ui/const-generics/defaults/complex-unord-param.rs +++ b/src/test/ui/const-generics/defaults/complex-unord-param.rs @@ -1,11 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: full min // Checks a complicated usage of unordered params - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct NestedArrays<'a, const N: usize, A: 'a, const M: usize, T:'a =u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters args: &'a [&'a [T; M]; N], specifier: A, } diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr similarity index 87% rename from src/test/ui/const-generics/defaults/intermixed-lifetime.stderr rename to src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr index 0f6d7f1065..9cc3e9c0da 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.stderr +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.full.stderr @@ -1,11 +1,11 @@ error: lifetime parameters must be declared prior to const parameters - --> $DIR/intermixed-lifetime.rs:6:28 + --> $DIR/intermixed-lifetime.rs:7:28 | LL | struct Foo(&'a (), T); | -----------------^^---------- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` error: lifetime parameters must be declared prior to type parameters - --> $DIR/intermixed-lifetime.rs:9:37 + --> $DIR/intermixed-lifetime.rs:11:37 | LL | struct Bar(&'a (), T); | --------------------------^^- help: reorder the parameters: lifetimes, then consts and types: `<'a, const N: usize, T>` diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr new file mode 100644 index 0000000000..4d80fdb5bc --- /dev/null +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.min.stderr @@ -0,0 +1,26 @@ +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:28 + | +LL | struct Foo(&'a (), T); + | -----------------^^---------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:7:32 + | +LL | struct Foo(&'a (), T); + | ---------------------^------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: lifetime parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:37 + | +LL | struct Bar(&'a (), T); + | --------------------------^^- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: type parameters must be declared prior to const parameters + --> $DIR/intermixed-lifetime.rs:11:28 + | +LL | struct Bar(&'a (), T); + | -----------------^----------- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to 4 previous errors + diff --git a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs index ea3a8c14b9..cc0d1c6c0c 100644 --- a/src/test/ui/const-generics/defaults/intermixed-lifetime.rs +++ b/src/test/ui/const-generics/defaults/intermixed-lifetime.rs @@ -1,12 +1,16 @@ +// revisions: full min // Checks that lifetimes cannot be interspersed between consts and types. - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo(&'a (), T); //~^ Error lifetime parameters must be declared prior to const parameters +//[min]~^^ Error type parameters must be declared prior to const parameters struct Bar(&'a (), T); -//~^ Error lifetime parameters must be declared prior to type parameters +//[full]~^ Error lifetime parameters must be declared prior to type parameters +//[min]~^^ Error type parameters must be declared prior to const parameters +//[min]~| Error lifetime parameters must be declared prior to const parameters fn main() {} diff --git a/src/test/ui/const-generics/defaults/simple-defaults.min.stderr b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr new file mode 100644 index 0000000000..59cc6f28af --- /dev/null +++ b/src/test/ui/const-generics/defaults/simple-defaults.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/simple-defaults.rs:9:40 + | +LL | struct FixedOutput<'a, const N: usize, T=u32> { + | ---------------------^----- help: reorder the parameters: lifetimes, then types, then consts: `<'a, T, const N: usize>` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/defaults/simple-defaults.rs b/src/test/ui/const-generics/defaults/simple-defaults.rs index b282dfd37c..78abe35199 100644 --- a/src/test/ui/const-generics/defaults/simple-defaults.rs +++ b/src/test/ui/const-generics/defaults/simple-defaults.rs @@ -1,10 +1,13 @@ -// run-pass +// [full] run-pass +// revisions: min full // Checks some basic test cases for defaults. -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code)] struct FixedOutput<'a, const N: usize, T=u32> { + //[min]~^ ERROR type parameters must be declared prior to const parameters out: &'a [T; N], } diff --git a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr similarity index 70% rename from src/test/ui/const-generics/cannot-infer-const-args.full.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr index 053139787e..b438ed3ad6 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.full.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.full.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr similarity index 70% rename from src/test/ui/const-generics/cannot-infer-const-args.min.stderr rename to src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr index 053139787e..b438ed3ad6 100644 --- a/src/test/ui/const-generics/cannot-infer-const-args.min.stderr +++ b/src/test/ui/const-generics/infer/cannot-infer-const-args.min.stderr @@ -2,9 +2,7 @@ error[E0282]: type annotations needed --> $DIR/cannot-infer-const-args.rs:12:5 | LL | foo(); - | ^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `X` declared on the function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/cannot-infer-const-args.rs b/src/test/ui/const-generics/infer/cannot-infer-const-args.rs similarity index 100% rename from src/test/ui/const-generics/cannot-infer-const-args.rs rename to src/test/ui/const-generics/infer/cannot-infer-const-args.rs diff --git a/src/test/ui/const-generics/infer/issue-77092.rs b/src/test/ui/const-generics/infer/issue-77092.rs new file mode 100644 index 0000000000..9a1dd1a825 --- /dev/null +++ b/src/test/ui/const-generics/infer/issue-77092.rs @@ -0,0 +1,16 @@ +#![feature(min_const_generics)] + +use std::convert::TryInto; + +fn take_array_from_mut(data: &mut [T], start: usize) -> &mut [T; N] { + (&mut data[start .. start + N]).try_into().unwrap() +} + +fn main() { + let mut arr = [0, 1, 2, 3, 4, 5, 6, 7, 8]; + + for i in 1 .. 4 { + println!("{:?}", take_array_from_mut(&mut arr, i)); + //~^ ERROR type annotations needed + } +} diff --git a/src/test/ui/const-generics/infer/issue-77092.stderr b/src/test/ui/const-generics/infer/issue-77092.stderr new file mode 100644 index 0000000000..e84ff8baee --- /dev/null +++ b/src/test/ui/const-generics/infer/issue-77092.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/issue-77092.rs:13:26 + | +LL | println!("{:?}", take_array_from_mut(&mut arr, i)); + | ^^^^^^^^^^^^^^^^^^^ cannot infer the value of the constant `{_: usize}` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.full.stderr b/src/test/ui/const-generics/infer/method-chain.full.stderr new file mode 100644 index 0000000000..1fb0b23cf1 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.full.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.min.stderr b/src/test/ui/const-generics/infer/method-chain.min.stderr new file mode 100644 index 0000000000..1fb0b23cf1 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.min.stderr @@ -0,0 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/method-chain.rs:21:33 + | +LL | Foo.bar().bar().bar().bar().baz(); + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `baz` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0282`. diff --git a/src/test/ui/const-generics/infer/method-chain.rs b/src/test/ui/const-generics/infer/method-chain.rs new file mode 100644 index 0000000000..9389ca20d1 --- /dev/null +++ b/src/test/ui/const-generics/infer/method-chain.rs @@ -0,0 +1,22 @@ +// revisions: full min + +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +struct Foo; + +impl Foo { + fn bar(self) -> Foo { + Foo + } + + fn baz(self) -> Foo { + println!("baz: {}", N); + Foo + } +} + +fn main() { + Foo.bar().bar().bar().bar().baz(); //~ ERROR type annotations needed +} diff --git a/src/test/ui/const-generics/uninferred-consts.full.stderr b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr similarity index 54% rename from src/test/ui/const-generics/uninferred-consts.full.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.full.stderr index 2c5af9e65f..7a451903e9 100644 --- a/src/test/ui/const-generics/uninferred-consts.full.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.full.stderr @@ -1,10 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/uninferred-consts.min.stderr b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr similarity index 54% rename from src/test/ui/const-generics/uninferred-consts.min.stderr rename to src/test/ui/const-generics/infer/uninferred-consts.min.stderr index 2c5af9e65f..7a451903e9 100644 --- a/src/test/ui/const-generics/uninferred-consts.min.stderr +++ b/src/test/ui/const-generics/infer/uninferred-consts.min.stderr @@ -1,10 +1,8 @@ error[E0282]: type annotations needed - --> $DIR/uninferred-consts.rs:14:5 + --> $DIR/uninferred-consts.rs:14:9 | LL | Foo.foo(); - | ^^^^^^^^^ - | - = note: unable to infer the value of a const parameter + | ^^^ cannot infer the value of const parameter `N` declared on the associated function `foo` error: aborting due to previous error diff --git a/src/test/ui/const-generics/uninferred-consts.rs b/src/test/ui/const-generics/infer/uninferred-consts.rs similarity index 100% rename from src/test/ui/const-generics/uninferred-consts.rs rename to src/test/ui/const-generics/infer/uninferred-consts.rs diff --git a/src/test/ui/const-generics/invalid-enum.rs b/src/test/ui/const-generics/invalid-enum.rs new file mode 100644 index 0000000000..ceb188a0d3 --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.rs @@ -0,0 +1,39 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +#[derive(PartialEq, Eq)] +enum CompileFlag { + A, + B, +} + +pub fn test_1() {} +pub fn test_2(x: T) {} +pub struct Example{ + x: T, +} + +impl Example { + const ASSOC_FLAG: CompileFlag = CompileFlag::A; +} + +pub fn main() { + test_1::(); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + test_2::<_, CompileFlag::A>(0); + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + let _: Example = Example { x: 0 }; + //~^ ERROR: expected type, found variant + //~| ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments + + let _: Example = Example { x: 0 }; + //~^ ERROR: wrong number of const arguments + //~| ERROR: wrong number of type arguments +} diff --git a/src/test/ui/const-generics/invalid-enum.stderr b/src/test/ui/const-generics/invalid-enum.stderr new file mode 100644 index 0000000000..965abbc9cb --- /dev/null +++ b/src/test/ui/const-generics/invalid-enum.stderr @@ -0,0 +1,99 @@ +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:21:12 + | +LL | test_1::(); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:26:15 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0573]: expected type, found variant `CompileFlag::A` + --> $DIR/invalid-enum.rs:31:18 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^ + | | + | not a type + | help: try using the variant's enum: `CompileFlag` + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:31:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ CompileFlag::A }, _> = Example { x: 0 }; + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected at most 1, found 2 + --> $DIR/invalid-enum.rs:36:10 + | +LL | let _: Example = Example { x: 0 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected at most 1 type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | let _: Example<{ Example::ASSOC_FLAG }, _> = Example { x: 0 }; + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:21:3 + | +LL | test_1::(); + | ^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 0, found 1 + --> $DIR/invalid-enum.rs:21:12 + | +LL | test_1::(); + | ^^^^^^^^^^^^^^ unexpected type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test_1::<{ CompileFlag::A }>(); + | ^ ^ + +error[E0107]: wrong number of const arguments: expected 1, found 0 + --> $DIR/invalid-enum.rs:26:3 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected 1 const argument + +error[E0107]: wrong number of type arguments: expected 1, found 2 + --> $DIR/invalid-enum.rs:26:15 + | +LL | test_2::<_, CompileFlag::A>(0); + | ^^^^^^^^^^^^^^ unexpected type argument + | +help: If this generic argument was intended as a const parameter, try surrounding it with braces: + | +LL | test_2::<_, { CompileFlag::A }>(0); + | ^ ^ + +error: aborting due to 11 previous errors + +Some errors have detailed explanations: E0107, E0573. +For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issue-74906.rs b/src/test/ui/const-generics/issue-74906.rs new file mode 100644 index 0000000000..9162d1142b --- /dev/null +++ b/src/test/ui/const-generics/issue-74906.rs @@ -0,0 +1,25 @@ +// edition:2018 +// check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +const SIZE: usize = 16; + +struct Bar {} + +struct Foo {} + +impl Foo { + async fn biz(_: &[[u8; SIZE]]) -> Vec<()> { + vec![] + } + + pub async fn baz(&self) -> Bar { + Self::biz(&vec![]).await; + Bar {} + } +} + +fn main() { } diff --git a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs index 59a4d345cb..7ea8d936d6 100644 --- a/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs +++ b/src/test/ui/const-generics/issues/auxiliary/const_generic_issues_lib.rs @@ -1,4 +1,6 @@ -#![feature(const_generics)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // All of these three items must be in `lib2` to reproduce the error diff --git a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr index d21cd9df05..ef6e60084a 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.full.stderr @@ -7,17 +7,17 @@ LL | #![cfg_attr(full, feature(const_generics))] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336-2.rs:10:5 | LL | [x; { N }] - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336-2.min.stderr b/src/test/ui/const-generics/issues/issue-61336-2.min.stderr index 29ab7b1305..40863a4f71 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61336-2.min.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336-2.rs:10:5 | LL | [x; { N }] - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61336-2.rs b/src/test/ui/const-generics/issues/issue-61336-2.rs index 25b9271105..44995157cc 100644 --- a/src/test/ui/const-generics/issues/issue-61336-2.rs +++ b/src/test/ui/const-generics/issues/issue-61336-2.rs @@ -8,7 +8,7 @@ fn f(x: T) -> [T; N] { fn g(x: T) -> [T; N] { [x; { N }] - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-61336.full.stderr b/src/test/ui/const-generics/issues/issue-61336.full.stderr index d1b5d5eb94..bdfdffd941 100644 --- a/src/test/ui/const-generics/issues/issue-61336.full.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.full.stderr @@ -7,17 +7,17 @@ LL | #![cfg_attr(full, feature(const_generics))] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:10:5 | LL | [x; N] - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61336.min.stderr b/src/test/ui/const-generics/issues/issue-61336.min.stderr index bced8bbd82..6c57f9ccbf 100644 --- a/src/test/ui/const-generics/issues/issue-61336.min.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.min.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:10:5 | LL | [x; N] - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/const-generics/issues/issue-61336.rs b/src/test/ui/const-generics/issues/issue-61336.rs index fb55542a1c..7c34250e6b 100644 --- a/src/test/ui/const-generics/issues/issue-61336.rs +++ b/src/test/ui/const-generics/issues/issue-61336.rs @@ -8,7 +8,7 @@ fn f(x: T) -> [T; N] { fn g(x: T) -> [T; N] { [x; N] - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-61336.stderr b/src/test/ui/const-generics/issues/issue-61336.stderr index 0eee37df3d..1be907b98a 100644 --- a/src/test/ui/const-generics/issues/issue-61336.stderr +++ b/src/test/ui/const-generics/issues/issue-61336.stderr @@ -7,17 +7,17 @@ LL | #![feature(const_generics)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44580 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-61336.rs:9:5 | LL | [x; N] - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | = note: the `Copy` trait is required because the repeated element will be copied help: consider restricting type parameter `T` | -LL | fn g(x: T) -> [T; N] { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(x: T) -> [T; N] { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/const-generics/issues/issue-61935.full.stderr b/src/test/ui/const-generics/issues/issue-61935.full.stderr new file mode 100644 index 0000000000..b805bc0db7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-61935.rs:10:14 + | +LL | Self:FooImpl<{N==0}> + | ^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.min.stderr b/src/test/ui/const-generics/issues/issue-61935.min.stderr new file mode 100644 index 0000000000..e5715ec658 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-61935.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-61935.rs:10:23 + | +LL | Self:FooImpl<{N==0}> + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-61935.rs b/src/test/ui/const-generics/issues/issue-61935.rs index 0d42ff1895..64257da030 100644 --- a/src/test/ui/const-generics/issues/issue-61935.rs +++ b/src/test/ui/const-generics/issues/issue-61935.rs @@ -1,12 +1,15 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo {} impl Foo for [(); N] where Self:FooImpl<{N==0}> -//~^ERROR constant expression depends on a generic parameter +//[full]~^ERROR constant expression depends on a generic parameter +//[min]~^^ERROR generic parameters must not be used inside of non trivial constant values {} trait FooImpl{} diff --git a/src/test/ui/const-generics/issues/issue-61935.stderr b/src/test/ui/const-generics/issues/issue-61935.stderr deleted file mode 100644 index a785af5f00..0000000000 --- a/src/test/ui/const-generics/issues/issue-61935.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-61935.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-61935.rs:8:14 - | -LL | Self:FooImpl<{N==0}> - | ^^^^^^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs index 2f3b5c5dc5..a8fa378035 100644 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs +++ b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.rs @@ -1,7 +1,9 @@ // run-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub trait BitLen: Sized { const BIT_LEN: usize; @@ -12,5 +14,5 @@ impl BitLen for [u8; L] { } fn main() { - let foo = <[u8; 2]>::BIT_LEN; //~ WARN unused variable + let _foo = <[u8; 2]>::BIT_LEN; } diff --git a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr b/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr deleted file mode 100644 index a9abb877c0..0000000000 --- a/src/test/ui/const-generics/issues/issue-62187-encountered-polymorphic-const.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62187-encountered-polymorphic-const.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: unused variable: `foo` - --> $DIR/issue-62187-encountered-polymorphic-const.rs:15:9 - | -LL | let foo = <[u8; 2]>::BIT_LEN; - | ^^^ help: if this is intentional, prefix it with an underscore: `_foo` - | - = note: `#[warn(unused_variables)]` on by default - -warning: 2 warnings emitted - diff --git a/src/test/ui/const-generics/issues/issue-62220.stderr b/src/test/ui/const-generics/issues/issue-62220.full.stderr similarity index 90% rename from src/test/ui/const-generics/issues/issue-62220.stderr rename to src/test/ui/const-generics/issues/issue-62220.full.stderr index d91d2bb326..120aa8e4af 100644 --- a/src/test/ui/const-generics/issues/issue-62220.stderr +++ b/src/test/ui/const-generics/issues/issue-62220.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62220.rs:10:27 + --> $DIR/issue-62220.rs:13:27 | LL | pub fn trunc(self) -> (TruncatedVector, T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62220.min.stderr b/src/test/ui/const-generics/issues/issue-62220.min.stderr new file mode 100644 index 0000000000..943b689bf6 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62220.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62220.rs:8:59 + | +LL | pub type TruncatedVector = Vector; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62220.rs b/src/test/ui/const-generics/issues/issue-62220.rs index 5c4a0d31a8..acb13ad117 100644 --- a/src/test/ui/const-generics/issues/issue-62220.rs +++ b/src/test/ui/const-generics/issues/issue-62220.rs @@ -1,14 +1,17 @@ -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Vector([T; N]); pub type TruncatedVector = Vector; +//[min]~^ ERROR generic parameters must not be used inside of non trivial constant values impl Vector { /// Drop the last component and return the vector with one fewer dimension. pub fn trunc(self) -> (TruncatedVector, T) { - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter unimplemented!() } } diff --git a/src/test/ui/const-generics/issues/issue-62456.full.stderr b/src/test/ui/const-generics/issues/issue-62456.full.stderr new file mode 100644 index 0000000000..a8d44074db --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.min.stderr b/src/test/ui/const-generics/issues/issue-62456.min.stderr new file mode 100644 index 0000000000..335f0ead27 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62456.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-62456.rs:7:20 + | +LL | let _ = [0u64; N + 1]; + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62456.rs b/src/test/ui/const-generics/issues/issue-62456.rs index 37947ad1b3..c96868c00a 100644 --- a/src/test/ui/const-generics/issues/issue-62456.rs +++ b/src/test/ui/const-generics/issues/issue-62456.rs @@ -1,9 +1,12 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() { let _ = [0u64; N + 1]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-62456.stderr b/src/test/ui/const-generics/issues/issue-62456.stderr deleted file mode 100644 index 0454fed670..0000000000 --- a/src/test/ui/const-generics/issues/issue-62456.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62456.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-62456.rs:5:20 - | -LL | let _ = [0u64; N + 1]; - | ^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62504.stderr b/src/test/ui/const-generics/issues/issue-62504.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-62504.stderr rename to src/test/ui/const-generics/issues/issue-62504.full.stderr index f09af76325..9c84f06ce9 100644 --- a/src/test/ui/const-generics/issues/issue-62504.stderr +++ b/src/test/ui/const-generics/issues/issue-62504.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-62504.rs:18:25 + --> $DIR/issue-62504.rs:19:25 | LL | ArrayHolder([0; Self::SIZE]) | ^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-62504.min.stderr b/src/test/ui/const-generics/issues/issue-62504.min.stderr new file mode 100644 index 0000000000..8f79431283 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62504.min.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/issue-62504.rs:19:25 + | +LL | ArrayHolder([0; Self::SIZE]) + | ^^^^^^^^^^ + | +note: not a concrete type + --> $DIR/issue-62504.rs:17:22 + | +LL | impl ArrayHolder { + | ^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62504.rs b/src/test/ui/const-generics/issues/issue-62504.rs index 4e05aadd39..015f170f00 100644 --- a/src/test/ui/const-generics/issues/issue-62504.rs +++ b/src/test/ui/const-generics/issues/issue-62504.rs @@ -1,7 +1,8 @@ -// Regression test for #62504 - -#![feature(const_generics)] +// revisions: full min #![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait HasSize { const SIZE: usize; @@ -16,7 +17,8 @@ struct ArrayHolder([u32; X]); impl ArrayHolder { pub const fn new() -> Self { ArrayHolder([0; Self::SIZE]) - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic `Self` types are currently } } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr new file mode 100644 index 0000000000..6903b20fad --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.min.stderr @@ -0,0 +1,11 @@ +error: `NoMatch` is forbidden as the type of a const generic parameter + --> $DIR/issue-62579-no-match.rs:10:17 + | +LL | fn foo() -> bool { + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.rs b/src/test/ui/const-generics/issues/issue-62579-no-match.rs index 7eaf5eea07..c9853aa916 100644 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.rs +++ b/src/test/ui/const-generics/issues/issue-62579-no-match.rs @@ -1,12 +1,14 @@ -// run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[derive(PartialEq, Eq)] struct NoMatch; fn foo() -> bool { + //[min]~^ ERROR `NoMatch` is forbidden as the type of a const generic parameter true } diff --git a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr b/src/test/ui/const-generics/issues/issue-62579-no-match.stderr deleted file mode 100644 index 9fb9b5b13d..0000000000 --- a/src/test/ui/const-generics/issues/issue-62579-no-match.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62579-no-match.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-62878.stderr b/src/test/ui/const-generics/issues/issue-62878.full.stderr similarity index 58% rename from src/test/ui/const-generics/issues/issue-62878.stderr rename to src/test/ui/const-generics/issues/issue-62878.full.stderr index fe0990d824..c8b9db8941 100644 --- a/src/test/ui/const-generics/issues/issue-62878.stderr +++ b/src/test/ui/const-generics/issues/issue-62878.full.stderr @@ -1,37 +1,28 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-62878.rs:3:38 + --> $DIR/issue-62878.rs:6:38 | LL | fn foo() {} | ^ the type must not depend on the parameter `N` -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-62878.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - error[E0107]: wrong number of const arguments: expected 2, found 1 - --> $DIR/issue-62878.rs:7:5 + --> $DIR/issue-62878.rs:11:5 | LL | foo::<_, {[1]}>(); | ^^^^^^^^^^^^^^^ expected 2 const arguments error[E0107]: wrong number of type arguments: expected 0, found 1 - --> $DIR/issue-62878.rs:7:11 + --> $DIR/issue-62878.rs:11:11 | LL | foo::<_, {[1]}>(); | ^ unexpected type argument error[E0308]: mismatched types - --> $DIR/issue-62878.rs:7:15 + --> $DIR/issue-62878.rs:11:15 | LL | foo::<_, {[1]}>(); | ^^^ expected `usize`, found array `[{integer}; 1]` -error: aborting due to 4 previous errors; 1 warning emitted +error: aborting due to 4 previous errors Some errors have detailed explanations: E0107, E0308, E0770. For more information about an error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-62878.min.stderr b/src/test/ui/const-generics/issues/issue-62878.min.stderr new file mode 100644 index 0000000000..34edd09b51 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-62878.min.stderr @@ -0,0 +1,18 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-62878.rs:6:38 + | +LL | fn foo() {} + | ^ the type must not depend on the parameter `N` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-62878.rs:6:33 + | +LL | fn foo() {} + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-62878.rs b/src/test/ui/const-generics/issues/issue-62878.rs index ccc05fdf10..0487dda2fe 100644 --- a/src/test/ui/const-generics/issues/issue-62878.rs +++ b/src/test/ui/const-generics/issues/issue-62878.rs @@ -1,11 +1,15 @@ -#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() {} //~^ ERROR the type of const parameters must not +//[min]~| ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() { foo::<_, {[1]}>(); - //~^ ERROR wrong number of const arguments - //~| ERROR wrong number of type arguments - //~| ERROR mismatched types + //[full]~^ ERROR wrong number of const arguments + //[full]~| ERROR wrong number of type arguments + //[full]~| ERROR mismatched types } diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr new file mode 100644 index 0000000000..a20c7264ac --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.full.stderr @@ -0,0 +1,9 @@ +error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-63322-forbid-dyn.rs:10:18 + | +LL | fn test() { + | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr new file mode 100644 index 0000000000..e6d9fb7a24 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.min.stderr @@ -0,0 +1,18 @@ +error: `&'static (dyn A + 'static)` is forbidden as the type of a const generic parameter + --> $DIR/issue-63322-forbid-dyn.rs:10:18 + | +LL | fn test() { + | ^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter + --> $DIR/issue-63322-forbid-dyn.rs:10:18 + | +LL | fn test() { + | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs index 2bcaa27b4d..2194eb97a4 100644 --- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs +++ b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait A {} struct B; @@ -7,6 +9,7 @@ impl A for B {} fn test() { //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` to be used + //[min]~^^ ERROR `&'static (dyn A + 'static)` is forbidden unimplemented!() } diff --git a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr b/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr deleted file mode 100644 index 32054e4371..0000000000 --- a/src/test/ui/const-generics/issues/issue-63322-forbid-dyn.stderr +++ /dev/null @@ -1,18 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-63322-forbid-dyn.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error[E0741]: `&'static (dyn A + 'static)` must be annotated with `#[derive(PartialEq, Eq)]` to be used as the type of a const parameter - --> $DIR/issue-63322-forbid-dyn.rs:8:18 - | -LL | fn test() { - | ^^^^^^^^^^^^^^ `&'static (dyn A + 'static)` doesn't derive both `PartialEq` and `Eq` - -error: aborting due to previous error; 1 warning emitted - -For more information about this error, try `rustc --explain E0741`. diff --git a/src/test/ui/const-generics/issues/issue-64494.stderr b/src/test/ui/const-generics/issues/issue-64494.full.stderr similarity index 94% rename from src/test/ui/const-generics/issues/issue-64494.stderr rename to src/test/ui/const-generics/issues/issue-64494.full.stderr index 30dca16964..a97ec9308f 100644 --- a/src/test/ui/const-generics/issues/issue-64494.stderr +++ b/src/test/ui/const-generics/issues/issue-64494.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-64494.rs:14:53 + --> $DIR/issue-64494.rs:16:53 | LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} | ^^^^ @@ -7,7 +7,7 @@ LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-64494.rs:16:53 + --> $DIR/issue-64494.rs:19:53 | LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-64494.min.stderr b/src/test/ui/const-generics/issues/issue-64494.min.stderr new file mode 100644 index 0000000000..07822f86f5 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-64494.min.stderr @@ -0,0 +1,28 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-64494.rs:16:38 + | +LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} + | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | + = note: type parameters are currently not permitted in anonymous constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-64494.rs:19:38 + | +LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} + | ^^^^^^ non-trivial anonymous constants must not depend on the parameter `T` + | + = note: type parameters are currently not permitted in anonymous constants + +error[E0119]: conflicting implementations of trait `MyTrait`: + --> $DIR/issue-64494.rs:19:1 + | +LL | impl MyTrait for T where Is<{T::VAL == 5}>: True {} + | ------------------------------------ first implementation here +... +LL | impl MyTrait for T where Is<{T::VAL == 6}>: True {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0119`. diff --git a/src/test/ui/const-generics/issues/issue-64494.rs b/src/test/ui/const-generics/issues/issue-64494.rs index 4c755530b9..3b598a4152 100644 --- a/src/test/ui/const-generics/issues/issue-64494.rs +++ b/src/test/ui/const-generics/issues/issue-64494.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo { const VAL: usize; @@ -12,8 +14,11 @@ struct Is; impl True for Is<{true}> {} impl MyTrait for T where Is<{T::VAL == 5}>: True {} -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values impl MyTrait for T where Is<{T::VAL == 6}>: True {} -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values +//[min]~| ERROR conflicting implementations of trait `MyTrait` fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-64519.rs b/src/test/ui/const-generics/issues/issue-64519.rs index e9391096b0..1ca709d097 100644 --- a/src/test/ui/const-generics/issues/issue-64519.rs +++ b/src/test/ui/const-generics/issues/issue-64519.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo { state: Option<[u8; D]>, diff --git a/src/test/ui/const-generics/issues/issue-66205.full.stderr b/src/test/ui/const-generics/issues/issue-66205.full.stderr new file mode 100644 index 0000000000..a1520912e4 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-66205.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-66205.rs:8:12 + | +LL | fact::<{ N - 1 }>(); + | ^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-66205.min.stderr b/src/test/ui/const-generics/issues/issue-66205.min.stderr new file mode 100644 index 0000000000..86709c389b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-66205.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-66205.rs:8:14 + | +LL | fact::<{ N - 1 }>(); + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-66205.rs b/src/test/ui/const-generics/issues/issue-66205.rs index 7cedf51ca0..e115eff356 100644 --- a/src/test/ui/const-generics/issues/issue-66205.rs +++ b/src/test/ui/const-generics/issues/issue-66205.rs @@ -1,10 +1,13 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #![allow(dead_code, unconditional_recursion)] -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete fn fact() { fact::<{ N - 1 }>(); - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values } fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-66205.stderr b/src/test/ui/const-generics/issues/issue-66205.stderr deleted file mode 100644 index 1e9c0f2f3d..0000000000 --- a/src/test/ui/const-generics/issues/issue-66205.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-66205.rs:2:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-66205.rs:6:12 - | -LL | fact::<{ N - 1 }>(); - | ^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-66906.rs b/src/test/ui/const-generics/issues/issue-66906.rs index 486c72d8a3..3e048593c9 100644 --- a/src/test/ui/const-generics/issues/issue-66906.rs +++ b/src/test/ui/const-generics/issues/issue-66906.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Tuple; diff --git a/src/test/ui/const-generics/issues/issue-66906.stderr b/src/test/ui/const-generics/issues/issue-66906.stderr deleted file mode 100644 index 8e8b552f90..0000000000 --- a/src/test/ui/const-generics/issues/issue-66906.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-66906.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-67185-1.rs b/src/test/ui/const-generics/issues/issue-67185-1.rs index b08057851a..09d88ef89a 100644 --- a/src/test/ui/const-generics/issues/issue-67185-1.rs +++ b/src/test/ui/const-generics/issues/issue-67185-1.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Baz { type Quaks; diff --git a/src/test/ui/const-generics/issues/issue-67185-1.stderr b/src/test/ui/const-generics/issues/issue-67185-1.stderr deleted file mode 100644 index 9cc797d6d8..0000000000 --- a/src/test/ui/const-generics/issues/issue-67185-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-67185-1.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-67185-2.stderr b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr similarity index 82% rename from src/test/ui/const-generics/issues/issue-67185-2.stderr rename to src/test/ui/const-generics/issues/issue-67185-2.full.stderr index 7d947a907a..78c7ebff05 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.stderr +++ b/src/test/ui/const-generics/issues/issue-67185-2.full.stderr @@ -1,14 +1,5 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-67185-2.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -26,7 +17,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:15:1 + --> $DIR/issue-67185-2.rs:17:1 | LL | / trait Foo LL | | @@ -44,7 +35,7 @@ LL | | } = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -60,7 +51,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:25:6 + --> $DIR/issue-67185-2.rs:27:6 | LL | trait Foo | --- required by a bound in this @@ -76,7 +67,7 @@ LL | impl Foo for FooImpl {} <[u16; 4] as Bar> error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -92,7 +83,7 @@ LL | fn f(_: impl Foo) {} <[u16; 4] as Bar> error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied - --> $DIR/issue-67185-2.rs:29:14 + --> $DIR/issue-67185-2.rs:31:14 | LL | trait Foo | --- required by a bound in this @@ -107,6 +98,6 @@ LL | fn f(_: impl Foo) {} <[[u16; 3]; 3] as Bar> <[u16; 4] as Bar> -error: aborting due to 6 previous errors; 1 warning emitted +error: aborting due to 6 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.min.stderr b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr new file mode 100644 index 0000000000..78c7ebff05 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67185-2.min.stderr @@ -0,0 +1,103 @@ +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:17:1 + | +LL | / trait Foo +LL | | +LL | | where +LL | | [::Quaks; 2]: Bar, +LL | | ::Quaks: Bar, +LL | | { +LL | | } + | |_^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + = help: see issue #48214 + = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:27:6 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | impl Foo for FooImpl {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[[u16; 3]; 2]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | [::Quaks; 2]: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[[u16; 3]; 2]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error[E0277]: the trait bound `[u16; 3]: Bar` is not satisfied + --> $DIR/issue-67185-2.rs:31:14 + | +LL | trait Foo + | --- required by a bound in this +... +LL | ::Quaks: Bar, + | --- required by this bound in `Foo` +... +LL | fn f(_: impl Foo) {} + | ^^^ the trait `Bar` is not implemented for `[u16; 3]` + | + = help: the following implementations were found: + <[[u16; 3]; 3] as Bar> + <[u16; 4] as Bar> + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/const-generics/issues/issue-67185-2.rs b/src/test/ui/const-generics/issues/issue-67185-2.rs index 111b718dd5..1176d0c690 100644 --- a/src/test/ui/const-generics/issues/issue-67185-2.rs +++ b/src/test/ui/const-generics/issues/issue-67185-2.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Baz { type Quaks; diff --git a/src/test/ui/const-generics/issues/issue-67739.stderr b/src/test/ui/const-generics/issues/issue-67739.full.stderr similarity index 100% rename from src/test/ui/const-generics/issues/issue-67739.stderr rename to src/test/ui/const-generics/issues/issue-67739.full.stderr diff --git a/src/test/ui/const-generics/issues/issue-67739.min.stderr b/src/test/ui/const-generics/issues/issue-67739.min.stderr new file mode 100644 index 0000000000..68f1733dec --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-67739.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-67739.rs:12:30 + | +LL | [0u8; mem::size_of::()]; + | ^^^^^^^^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = note: type parameters are currently not permitted in anonymous constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-67739.rs b/src/test/ui/const-generics/issues/issue-67739.rs index c8ee182123..72bf3ee960 100644 --- a/src/test/ui/const-generics/issues/issue-67739.rs +++ b/src/test/ui/const-generics/issues/issue-67739.rs @@ -1,7 +1,7 @@ -// Regression test for #67739 - -#![allow(incomplete_features)] -#![feature(const_generics)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::mem; @@ -10,7 +10,8 @@ pub trait Trait { fn associated_size(&self) -> usize { [0u8; mem::size_of::()]; - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values 0 } } diff --git a/src/test/ui/const-generics/issues/issue-68366.full.stderr b/src/test/ui/const-generics/issues/issue-68366.full.stderr new file mode 100644 index 0000000000..ac774f50c7 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.full.stderr @@ -0,0 +1,21 @@ +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:12:13 + | +LL | impl Collatz<{Some(N)}> {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:18:12 + | +LL | impl Foo {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/const-generics/issues/issue-68366.min.stderr b/src/test/ui/const-generics/issues/issue-68366.min.stderr new file mode 100644 index 0000000000..8d34bdc6ea --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.min.stderr @@ -0,0 +1,29 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68366.rs:12:37 + | +LL | impl Collatz<{Some(N)}> {} + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:12:13 + | +LL | impl Collatz<{Some(N)}> {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error[E0207]: the const parameter `N` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-68366.rs:18:12 + | +LL | impl Foo {} + | ^ unconstrained const parameter + | + = note: expressions using a const parameter must map each value to a distinct output value + = note: proving the result of expressions other than the parameter are unique is not supported + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/const-generics/issues/issue-68366.rs b/src/test/ui/const-generics/issues/issue-68366.rs new file mode 100644 index 0000000000..819fcaffea --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68366.rs @@ -0,0 +1,21 @@ +// Checks that const expressions have a useful note explaining why they can't be evaluated. +// The note should relate to the fact that it cannot be shown forall N that it maps 1-1 to a new +// type. + +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +struct Collatz>; + +impl Collatz<{Some(N)}> {} +//~^ ERROR the const parameter +//[min]~^^ generic parameters must not be used inside of non trivial constant values + +struct Foo; + +impl Foo {} +//~^ ERROR the const parameter + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-68596.rs b/src/test/ui/const-generics/issues/issue-68596.rs index 1f96e7d3b4..3b27d4d68c 100644 --- a/src/test/ui/const-generics/issues/issue-68596.rs +++ b/src/test/ui/const-generics/issues/issue-68596.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct S(u8); diff --git a/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr new file mode 100644 index 0000000000..81c8f4392c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-adt.min.stderr @@ -0,0 +1,11 @@ +error: `[usize; 0]` is forbidden as the type of a const generic parameter + --> $DIR/issue-68615-adt.rs:7:23 + | +LL | struct Const {} + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-68615-adt.rs b/src/test/ui/const-generics/issues/issue-68615-adt.rs index 140bb28ec5..d616f3ab95 100644 --- a/src/test/ui/const-generics/issues/issue-68615-adt.rs +++ b/src/test/ui/const-generics/issues/issue-68615-adt.rs @@ -1,8 +1,11 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Const {} +//[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter type MyConst = Const<{ [] }>; fn main() { diff --git a/src/test/ui/const-generics/issues/issue-68615-array.min.stderr b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr new file mode 100644 index 0000000000..8f55a92fce --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68615-array.min.stderr @@ -0,0 +1,11 @@ +error: `[usize; 0]` is forbidden as the type of a const generic parameter + --> $DIR/issue-68615-array.rs:7:21 + | +LL | struct Foo {} + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-68615-array.rs b/src/test/ui/const-generics/issues/issue-68615-array.rs index c384bc1e36..24c9a59a18 100644 --- a/src/test/ui/const-generics/issues/issue-68615-array.rs +++ b/src/test/ui/const-generics/issues/issue-68615-array.rs @@ -1,8 +1,11 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo {} +//[min]~^ ERROR `[usize; 0]` is forbidden as the type of a const generic parameter type MyFoo = Foo<{ [] }>; diff --git a/src/test/ui/const-generics/issues/issue-68977.full.stderr b/src/test/ui/const-generics/issues/issue-68977.full.stderr new file mode 100644 index 0000000000..3690bac3eb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.full.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-68977.rs:35:44 + | +LL | FxpStorageHelper: FxpStorage, + | ^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-68977.min.stderr b/src/test/ui/const-generics/issues/issue-68977.min.stderr new file mode 100644 index 0000000000..5b2137b244 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-68977.min.stderr @@ -0,0 +1,18 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68977.rs:29:17 + | +LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + | ^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `INT_BITS` + | + = help: it is currently only allowed to use either `INT_BITS` or `{ INT_BITS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-68977.rs:29:28 + | +LL | PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + | ^^^^^^^^^ non-trivial anonymous constants must not depend on the parameter `FRAC_BITS` + | + = help: it is currently only allowed to use either `FRAC_BITS` or `{ FRAC_BITS }` as generic constants + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-68977.rs b/src/test/ui/const-generics/issues/issue-68977.rs index 346ea3c204..02e634efec 100644 --- a/src/test/ui/const-generics/issues/issue-68977.rs +++ b/src/test/ui/const-generics/issues/issue-68977.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct PhantomU8; @@ -25,11 +27,13 @@ fxp_storage_impls! { type FxpStorageHelper = PhantomU8<{(INT_BITS + FRAC_BITS + 7) / 8}>; + //[min]~^ ERROR generic parameters must not be used inside of non trivial constant values + //[min]~| ERROR generic parameters must not be used inside of non trivial constant values struct Fxp where FxpStorageHelper: FxpStorage, - //~^ ERROR constant expression depends on a generic parameter + //[full]~^ ERROR constant expression depends on a generic parameter { storage: as FxpStorage>::SInt, } diff --git a/src/test/ui/const-generics/issues/issue-68977.stderr b/src/test/ui/const-generics/issues/issue-68977.stderr deleted file mode 100644 index e1190d9026..0000000000 --- a/src/test/ui/const-generics/issues/issue-68977.stderr +++ /dev/null @@ -1,19 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-68977.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: constant expression depends on a generic parameter - --> $DIR/issue-68977.rs:31:44 - | -LL | FxpStorageHelper: FxpStorage, - | ^^^^^^^^^^ - | - = note: this may fail depending on what value the parameter takes - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-69654-run-pass.rs b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs new file mode 100644 index 0000000000..bbfd2183b0 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654-run-pass.rs @@ -0,0 +1,18 @@ +// run-pass +#![feature(const_generics)] +#![allow(incomplete_features, unused_braces)] + +trait Bar {} +impl Bar for [u8; {7}] {} + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); +} diff --git a/src/test/ui/const-generics/issues/issue-69654.rs b/src/test/ui/const-generics/issues/issue-69654.rs new file mode 100644 index 0000000000..7e775999eb --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.rs @@ -0,0 +1,18 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar for [u8; T] {} +//~^ ERROR expected value, found type parameter `T` + +struct Foo {} +impl Foo +where + [u8; N]: Bar<[(); N]>, +{ + fn foo() {} +} + +fn main() { + Foo::foo(); +} diff --git a/src/test/ui/const-generics/issues/issue-69654.stderr b/src/test/ui/const-generics/issues/issue-69654.stderr new file mode 100644 index 0000000000..70af7bf25d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-69654.stderr @@ -0,0 +1,9 @@ +error[E0423]: expected value, found type parameter `T` + --> $DIR/issue-69654.rs:5:25 + | +LL | impl Bar for [u8; T] {} + | ^ not a value + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0423`. diff --git a/src/test/ui/const-generics/issues/issue-70125-1.rs b/src/test/ui/const-generics/issues/issue-70125-1.rs index 08a8309d43..04175089dc 100644 --- a/src/test/ui/const-generics/issues/issue-70125-1.rs +++ b/src/test/ui/const-generics/issues/issue-70125-1.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] const L: usize = 4; diff --git a/src/test/ui/const-generics/issues/issue-70125-1.stderr b/src/test/ui/const-generics/issues/issue-70125-1.stderr deleted file mode 100644 index 8ad4b25ae5..0000000000 --- a/src/test/ui/const-generics/issues/issue-70125-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70125-1.rs:2:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-70125-2.rs b/src/test/ui/const-generics/issues/issue-70125-2.rs index fb7d4886a7..ceefc2dcb3 100644 --- a/src/test/ui/const-generics/issues/issue-70125-2.rs +++ b/src/test/ui/const-generics/issues/issue-70125-2.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn main() { <()>::foo(); diff --git a/src/test/ui/const-generics/issues/issue-70125-2.stderr b/src/test/ui/const-generics/issues/issue-70125-2.stderr deleted file mode 100644 index c1f9634810..0000000000 --- a/src/test/ui/const-generics/issues/issue-70125-2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70125-2.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-70167.rs b/src/test/ui/const-generics/issues/issue-70167.rs index b53cec8007..04c76a4dca 100644 --- a/src/test/ui/const-generics/issues/issue-70167.rs +++ b/src/test/ui/const-generics/issues/issue-70167.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub trait Trait: From<>::Item> { type Item; diff --git a/src/test/ui/const-generics/issues/issue-70167.stderr b/src/test/ui/const-generics/issues/issue-70167.stderr deleted file mode 100644 index 5d647e933c..0000000000 --- a/src/test/ui/const-generics/issues/issue-70167.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-70167.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-70225.rs b/src/test/ui/const-generics/issues/issue-70225.rs new file mode 100644 index 0000000000..8f8d753d0a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-70225.rs @@ -0,0 +1,21 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] +#![deny(dead_code)] + +// We previously incorrectly linted `L` as unused here. +const L: usize = 3; + +fn main() { + let p = Printer {}; + p.print(); +} + +trait Print { + fn print(&self) -> usize { + 3 + } +} + +struct Printer {} +impl Print for Printer {} diff --git a/src/test/ui/const-generics/issues/issue-71169.stderr b/src/test/ui/const-generics/issues/issue-71169.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-71169.stderr rename to src/test/ui/const-generics/issues/issue-71169.full.stderr index 6d4cf4027c..b87825d20c 100644 --- a/src/test/ui/const-generics/issues/issue-71169.stderr +++ b/src/test/ui/const-generics/issues/issue-71169.full.stderr @@ -1,11 +1,11 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71169.rs:4:43 + --> $DIR/issue-71169.rs:6:43 | LL | fn foo() {} | ^^^ the type must not depend on the parameter `LEN` error: constant expression depends on a generic parameter - --> $DIR/issue-71169.rs:8:14 + --> $DIR/issue-71169.rs:11:14 | LL | foo::<4, DATA>(); | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71169.min.stderr b/src/test/ui/const-generics/issues/issue-71169.min.stderr new file mode 100644 index 0000000000..79d6344335 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71169.min.stderr @@ -0,0 +1,18 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71169.rs:6:43 + | +LL | fn foo() {} + | ^^^ the type must not depend on the parameter `LEN` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-71169.rs:6:38 + | +LL | fn foo() {} + | ^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71169.rs b/src/test/ui/const-generics/issues/issue-71169.rs index 943a16cfcd..7007ec222c 100644 --- a/src/test/ui/const-generics/issues/issue-71169.rs +++ b/src/test/ui/const-generics/issues/issue-71169.rs @@ -1,10 +1,13 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn foo() {} //~^ ERROR the type of const parameters must not +//[min]~^^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() { const DATA: [u8; 4] = *b"ABCD"; foo::<4, DATA>(); - //~^ ERROR constant expression depends on + //[full]~^ ERROR constant expression depends on } diff --git a/src/test/ui/const-generics/issues/issue-71381.stderr b/src/test/ui/const-generics/issues/issue-71381.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-71381.stderr rename to src/test/ui/const-generics/issues/issue-71381.full.stderr index fd4ebe3dea..453ef00e6d 100644 --- a/src/test/ui/const-generics/issues/issue-71381.stderr +++ b/src/test/ui/const-generics/issues/issue-71381.full.stderr @@ -1,23 +1,23 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71381.rs:13:82 + --> $DIR/issue-71381.rs:15:82 | LL | pub fn call_me(&self) { | ^^^^ the type must not depend on the parameter `Args` error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71381.rs:22:40 + --> $DIR/issue-71381.rs:24:40 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^ the type must not depend on the parameter `Args` error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71381.rs:13:61 + --> $DIR/issue-71381.rs:15:61 | LL | pub fn call_me(&self) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71381.rs:22:19 + --> $DIR/issue-71381.rs:24:19 | LL | const FN: unsafe extern "C" fn(Args), | ^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71381.min.stderr b/src/test/ui/const-generics/issues/issue-71381.min.stderr new file mode 100644 index 0000000000..453ef00e6d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71381.min.stderr @@ -0,0 +1,27 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:15:82 + | +LL | pub fn call_me(&self) { + | ^^^^ the type must not depend on the parameter `Args` + +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71381.rs:24:40 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^ the type must not depend on the parameter `Args` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:15:61 + | +LL | pub fn call_me(&self) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71381.rs:24:19 + | +LL | const FN: unsafe extern "C" fn(Args), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71381.rs b/src/test/ui/const-generics/issues/issue-71381.rs index 08f9482394..65d88e553b 100644 --- a/src/test/ui/const-generics/issues/issue-71381.rs +++ b/src/test/ui/const-generics/issues/issue-71381.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Test(*const usize); diff --git a/src/test/ui/const-generics/issues/issue-71382.stderr b/src/test/ui/const-generics/issues/issue-71382.full.stderr similarity index 85% rename from src/test/ui/const-generics/issues/issue-71382.stderr rename to src/test/ui/const-generics/issues/issue-71382.full.stderr index 1652b0bdfa..3da85ee040 100644 --- a/src/test/ui/const-generics/issues/issue-71382.stderr +++ b/src/test/ui/const-generics/issues/issue-71382.full.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71382.rs:15:23 + --> $DIR/issue-71382.rs:17:23 | LL | fn test(&self) { | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71382.min.stderr b/src/test/ui/const-generics/issues/issue-71382.min.stderr new file mode 100644 index 0000000000..3da85ee040 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71382.min.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71382.rs:17:23 + | +LL | fn test(&self) { + | ^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-71382.rs b/src/test/ui/const-generics/issues/issue-71382.rs index e0cf9812d9..12a7d08382 100644 --- a/src/test/ui/const-generics/issues/issue-71382.rs +++ b/src/test/ui/const-generics/issues/issue-71382.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Test(); diff --git a/src/test/ui/const-generics/issues/issue-71611.stderr b/src/test/ui/const-generics/issues/issue-71611.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-71611.stderr rename to src/test/ui/const-generics/issues/issue-71611.full.stderr index e2c9f22361..48d4bb361a 100644 --- a/src/test/ui/const-generics/issues/issue-71611.stderr +++ b/src/test/ui/const-generics/issues/issue-71611.full.stderr @@ -1,11 +1,11 @@ error[E0770]: the type of const parameters must not depend on other generic parameters - --> $DIR/issue-71611.rs:4:31 + --> $DIR/issue-71611.rs:6:31 | LL | fn func(outer: A) { | ^ the type must not depend on the parameter `A` error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71611.rs:4:21 + --> $DIR/issue-71611.rs:6:21 | LL | fn func(outer: A) { | ^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-71611.min.stderr b/src/test/ui/const-generics/issues/issue-71611.min.stderr new file mode 100644 index 0000000000..48d4bb361a --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-71611.min.stderr @@ -0,0 +1,15 @@ +error[E0770]: the type of const parameters must not depend on other generic parameters + --> $DIR/issue-71611.rs:6:31 + | +LL | fn func(outer: A) { + | ^ the type must not depend on the parameter `A` + +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71611.rs:6:21 + | +LL | fn func(outer: A) { + | ^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0770`. diff --git a/src/test/ui/const-generics/issues/issue-71611.rs b/src/test/ui/const-generics/issues/issue-71611.rs index 06ff38dec6..9b8e8be6bc 100644 --- a/src/test/ui/const-generics/issues/issue-71611.rs +++ b/src/test/ui/const-generics/issues/issue-71611.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn func(outer: A) { //~^ ERROR: using function pointers as const generic parameters is forbidden diff --git a/src/test/ui/const-generics/issues/issue-72352.stderr b/src/test/ui/const-generics/issues/issue-72352.full.stderr similarity index 89% rename from src/test/ui/const-generics/issues/issue-72352.stderr rename to src/test/ui/const-generics/issues/issue-72352.full.stderr index bc48da1039..51f9467846 100644 --- a/src/test/ui/const-generics/issues/issue-72352.stderr +++ b/src/test/ui/const-generics/issues/issue-72352.full.stderr @@ -1,5 +1,5 @@ error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-72352.rs:6:42 + --> $DIR/issue-72352.rs:8:42 | LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8) -> usize { | ^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72352.min.stderr b/src/test/ui/const-generics/issues/issue-72352.min.stderr new file mode 100644 index 0000000000..51f9467846 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72352.min.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-72352.rs:8:42 + | +LL | unsafe fn unsafely_do_the_thing usize>(ptr: *const i8) -> usize { + | ^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-72352.rs b/src/test/ui/const-generics/issues/issue-72352.rs index e977af8deb..1517f3dae4 100644 --- a/src/test/ui/const-generics/issues/issue-72352.rs +++ b/src/test/ui/const-generics/issues/issue-72352.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::ffi::{CStr, CString}; diff --git a/src/test/ui/const-generics/issues/issue-72787.stderr b/src/test/ui/const-generics/issues/issue-72787.full.stderr similarity index 88% rename from src/test/ui/const-generics/issues/issue-72787.stderr rename to src/test/ui/const-generics/issues/issue-72787.full.stderr index ed892e46bb..b4c79d4171 100644 --- a/src/test/ui/const-generics/issues/issue-72787.stderr +++ b/src/test/ui/const-generics/issues/issue-72787.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:9:32 + --> $DIR/issue-72787.rs:11:32 | LL | Condition<{ LHS <= RHS }>: True | ^^^^ @@ -7,7 +7,7 @@ LL | Condition<{ LHS <= RHS }>: True = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -15,7 +15,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -23,7 +23,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ @@ -31,7 +31,7 @@ LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, = note: this may fail depending on what value the parameter takes error: constant expression depends on a generic parameter - --> $DIR/issue-72787.rs:20:42 + --> $DIR/issue-72787.rs:26:42 | LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, | ^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72787.min.stderr b/src/test/ui/const-generics/issues/issue-72787.min.stderr new file mode 100644 index 0000000000..d3e9887fe2 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72787.min.stderr @@ -0,0 +1,57 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:17 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `LHS` + | + = help: it is currently only allowed to use either `LHS` or `{ LHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:11:24 + | +LL | Condition<{ LHS <= RHS }>: True + | ^^^ non-trivial anonymous constants must not depend on the parameter `RHS` + | + = help: it is currently only allowed to use either `RHS` or `{ RHS }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:26:25 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `I` + | + = help: it is currently only allowed to use either `I` or `{ I }` as generic constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72787.rs:26:36 + | +LL | IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, + | ^ non-trivial anonymous constants must not depend on the parameter `J` + | + = help: it is currently only allowed to use either `J` or `{ J }` as generic constants + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual` + | + = note: cannot satisfy `IsLessOrEqual: True` + +error[E0283]: type annotations needed + --> $DIR/issue-72787.rs:22:26 + | +LL | pub trait True {} + | -------------- required by this bound in `True` +... +LL | IsLessOrEqual: True, + | ^^^^ cannot infer type for struct `IsLessOrEqual` + | + = note: cannot satisfy `IsLessOrEqual: True` + +error: aborting due to 6 previous errors + +For more information about this error, try `rustc --explain E0283`. diff --git a/src/test/ui/const-generics/issues/issue-72787.rs b/src/test/ui/const-generics/issues/issue-72787.rs index a368c226ec..45c20191c8 100644 --- a/src/test/ui/const-generics/issues/issue-72787.rs +++ b/src/test/ui/const-generics/issues/issue-72787.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct IsLessOrEqual; pub struct Condition; @@ -7,7 +9,9 @@ pub trait True {} impl True for IsLessOrEqual where Condition<{ LHS <= RHS }>: True -//~^ Error constant expression depends on a generic parameter +//[full]~^ Error constant expression depends on a generic parameter +//[min]~^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values { } impl True for Condition {} @@ -16,12 +20,16 @@ struct S; impl S where IsLessOrEqual: True, +//[min]~^ Error type annotations needed [E0283] +//[min]~| Error type annotations needed [E0283] IsLessOrEqual: True, IsLessOrEqual<{ 8 - I }, { 8 - J }>: True, -//~^ Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter -//~| Error constant expression depends on a generic parameter +//[full]~^ constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[full]~| constant expression depends on a generic parameter +//[min]~^^^^^ Error generic parameters must not be used inside of non trivial constant values +//[min]~| Error generic parameters must not be used inside of non trivial constant values // Condition<{ 8 - I <= 8 - J }>: True, { fn print() { diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr similarity index 84% rename from src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr rename to src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr index a9f664d0ac..e4105a3df1 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.stderr +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.full.stderr @@ -1,5 +1,5 @@ error: constant expression depends on a generic parameter - --> $DIR/issue-72819-generic-in-const-eval.rs:7:47 + --> $DIR/issue-72819-generic-in-const-eval.rs:9:47 | LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, | ^^^^^^ diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr new file mode 100644 index 0000000000..48a1f0bd19 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.min.stderr @@ -0,0 +1,10 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-72819-generic-in-const-eval.rs:9:17 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs index 225593c317..b653b91d99 100644 --- a/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs +++ b/src/test/ui/const-generics/issues/issue-72819-generic-in-const-eval.rs @@ -1,11 +1,14 @@ // Regression test for #72819: ICE due to failure in resolving the const generic in `Arr`'s type // bounds. +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] -#![feature(const_generics)] -#![allow(incomplete_features)] struct Arr where Assert::<{N < usize::max_value() / 2}>: IsTrue, -//~^ ERROR constant expression depends on a generic parameter +//[full]~^ ERROR constant expression depends on a generic parameter +//[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values { } diff --git a/src/test/ui/const-generics/issues/issue-73120.rs b/src/test/ui/const-generics/issues/issue-73120.rs index aea4de39f7..c153a93cde 100644 --- a/src/test/ui/const-generics/issues/issue-73120.rs +++ b/src/test/ui/const-generics/issues/issue-73120.rs @@ -1,3 +1,4 @@ +// revisions: full min // check-pass // aux-build:const_generic_issues_lib.rs extern crate const_generic_issues_lib as lib2; diff --git a/src/test/ui/const-generics/issues/issue-73260.rs b/src/test/ui/const-generics/issues/issue-73260.rs new file mode 100644 index 0000000000..351d6849af --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.rs @@ -0,0 +1,20 @@ +// compile-flags: -Zsave-analysis + +#![feature(const_generics)] +#![allow(incomplete_features)] +struct Arr +where Assert::<{N < usize::max_value() / 2}>: IsTrue, //~ ERROR constant expression +{ +} + +enum Assert {} + +trait IsTrue {} + +impl IsTrue for Assert {} + +fn main() { + let x: Arr<{usize::max_value()}> = Arr {}; + //~^ ERROR mismatched types + //~| ERROR mismatched types +} diff --git a/src/test/ui/const-generics/issues/issue-73260.stderr b/src/test/ui/const-generics/issues/issue-73260.stderr new file mode 100644 index 0000000000..e22612ed5e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73260.stderr @@ -0,0 +1,29 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-73260.rs:6:47 + | +LL | where Assert::<{N < usize::max_value() / 2}>: IsTrue, + | ^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:12 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error[E0308]: mismatched types + --> $DIR/issue-73260.rs:17:40 + | +LL | let x: Arr<{usize::max_value()}> = Arr {}; + | ^^^ expected `false`, found `true` + | + = note: expected type `false` + found type `true` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/issues/issue-73491.min.stderr b/src/test/ui/const-generics/issues/issue-73491.min.stderr new file mode 100644 index 0000000000..5bf3671d38 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73491.min.stderr @@ -0,0 +1,11 @@ +error: `[u32; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-73491.rs:9:19 + | +LL | fn hoge() {} + | ^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-73491.rs b/src/test/ui/const-generics/issues/issue-73491.rs index 05e1513bb7..4f6c44ad2c 100644 --- a/src/test/ui/const-generics/issues/issue-73491.rs +++ b/src/test/ui/const-generics/issues/issue-73491.rs @@ -1,9 +1,12 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] const LEN: usize = 1024; fn hoge() {} +//[min]~^ ERROR `[u32; _]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-73508.full.stderr b/src/test/ui/const-generics/issues/issue-73508.full.stderr new file mode 100644 index 0000000000..0816bad35b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.full.stderr @@ -0,0 +1,8 @@ +error: using raw pointers as const generic parameters is forbidden + --> $DIR/issue-73508.rs:6:33 + | +LL | pub const fn func_name() {} + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-73508.min.stderr b/src/test/ui/const-generics/issues/issue-73508.min.stderr new file mode 100644 index 0000000000..0816bad35b --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-73508.min.stderr @@ -0,0 +1,8 @@ +error: using raw pointers as const generic parameters is forbidden + --> $DIR/issue-73508.rs:6:33 + | +LL | pub const fn func_name() {} + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-73508.rs b/src/test/ui/const-generics/issues/issue-73508.rs index ba2e2a38e7..21b87f7f90 100644 --- a/src/test/ui/const-generics/issues/issue-73508.rs +++ b/src/test/ui/const-generics/issues/issue-73508.rs @@ -1,4 +1,7 @@ -#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub const fn func_name() {} //~^ ERROR using raw pointers diff --git a/src/test/ui/const-generics/issues/issue-73508.stderr b/src/test/ui/const-generics/issues/issue-73508.stderr deleted file mode 100644 index 23ad1818b6..0000000000 --- a/src/test/ui/const-generics/issues/issue-73508.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-73508.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: using raw pointers as const generic parameters is forbidden - --> $DIR/issue-73508.rs:3:33 - | -LL | pub const fn func_name() {} - | ^^^^^^^^^^ - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/issues/issue-74101.min.stderr b/src/test/ui/const-generics/issues/issue-74101.min.stderr new file mode 100644 index 0000000000..8062faefbe --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74101.min.stderr @@ -0,0 +1,20 @@ +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-74101.rs:7:18 + | +LL | fn test() {} + | ^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-74101.rs:10:21 + | +LL | struct Foo; + | ^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-74101.rs b/src/test/ui/const-generics/issues/issue-74101.rs index 2f427ef3a2..2a7d31ac8d 100644 --- a/src/test/ui/const-generics/issues/issue-74101.rs +++ b/src/test/ui/const-generics/issues/issue-74101.rs @@ -1,9 +1,13 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] fn test() {} +//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter struct Foo; +//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74255.min.stderr b/src/test/ui/const-generics/issues/issue-74255.min.stderr new file mode 100644 index 0000000000..86937d715c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74255.min.stderr @@ -0,0 +1,11 @@ +error: `IceEnum` is forbidden as the type of a const generic parameter + --> $DIR/issue-74255.rs:15:31 + | +LL | fn ice_struct_fn() {} + | ^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-74255.rs b/src/test/ui/const-generics/issues/issue-74255.rs index 55ccf57dc9..b277c27346 100644 --- a/src/test/ui/const-generics/issues/issue-74255.rs +++ b/src/test/ui/const-generics/issues/issue-74255.rs @@ -1,6 +1,8 @@ -// check-pass -#![feature(const_generics)] -#![allow(dead_code, incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[derive(PartialEq, Eq)] enum IceEnum { @@ -11,6 +13,7 @@ struct IceStruct; impl IceStruct { fn ice_struct_fn() {} + //[min]~^ ERROR `IceEnum` is forbidden as the type of a const generic parameter } fn main() { diff --git a/src/test/ui/const-generics/issues/issue-74634.rs b/src/test/ui/const-generics/issues/issue-74634.rs new file mode 100644 index 0000000000..0f23fa92c3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.rs @@ -0,0 +1,27 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait If {} +impl If for () {} + +trait IsZero { + type Answer; +} + +struct True; +struct False; + +impl IsZero for () +where (): If<{N == 0}> { //~ERROR constant expression + type Answer = True; +} + +trait Foobar {} + +impl Foobar for () +where (): IsZero {} + +impl Foobar for () +where (): IsZero {} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-74634.stderr b/src/test/ui/const-generics/issues/issue-74634.stderr new file mode 100644 index 0000000000..091a1ac7b9 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-74634.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-74634.rs:15:11 + | +LL | where (): If<{N == 0}> { + | ^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-75047.min.stderr b/src/test/ui/const-generics/issues/issue-75047.min.stderr new file mode 100644 index 0000000000..edc54b082d --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-75047.min.stderr @@ -0,0 +1,11 @@ +error: `[u8; _]` is forbidden as the type of a const generic parameter + --> $DIR/issue-75047.rs:15:21 + | +LL | struct Foo::value()]>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/issues/issue-75047.rs b/src/test/ui/const-generics/issues/issue-75047.rs index 5d068d851c..7bab7cdd09 100644 --- a/src/test/ui/const-generics/issues/issue-75047.rs +++ b/src/test/ui/const-generics/issues/issue-75047.rs @@ -1,6 +1,8 @@ -// check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Bar(T); @@ -11,5 +13,6 @@ impl Bar { } struct Foo::value()]>; +//[min]~^ ERROR `[u8; _]` is forbidden as the type of a const generic parameter fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-76595.rs b/src/test/ui/const-generics/issues/issue-76595.rs new file mode 100644 index 0000000000..9fdbbff66e --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.rs @@ -0,0 +1,17 @@ +#![feature(const_generics, const_evaluatable_checked)] +#![allow(incomplete_features)] + +struct Bool; + +trait True {} + +impl True for Bool {} + +fn test() where Bool<{core::mem::size_of::() > 4}>: True { + todo!() +} + +fn main() { + test::<2>(); + //~^ ERROR wrong number of type +} diff --git a/src/test/ui/const-generics/issues/issue-76595.stderr b/src/test/ui/const-generics/issues/issue-76595.stderr new file mode 100644 index 0000000000..f258d29771 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76595.stderr @@ -0,0 +1,9 @@ +error[E0107]: wrong number of type arguments: expected 1, found 0 + --> $DIR/issue-76595.rs:15:5 + | +LL | test::<2>(); + | ^^^^^^^^^ expected 1 type argument + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0107`. diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr new file mode 100644 index 0000000000..089937e66c --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.full.stderr @@ -0,0 +1,18 @@ +error: constant expression depends on a generic parameter + --> $DIR/issue-76701-ty-param-in-const.rs:6:21 + | +LL | fn ty_param() -> [u8; std::mem::size_of::()] { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/issue-76701-ty-param-in-const.rs:12:37 + | +LL | fn const_param() -> [u8; N + 1] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr new file mode 100644 index 0000000000..a39495e0b2 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.min.stderr @@ -0,0 +1,18 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-76701-ty-param-in-const.rs:6:46 + | +LL | fn ty_param() -> [u8; std::mem::size_of::()] { + | ^ non-trivial anonymous constants must not depend on the parameter `T` + | + = note: type parameters are currently not permitted in anonymous constants + +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/issue-76701-ty-param-in-const.rs:12:42 + | +LL | fn const_param() -> [u8; N + 1] { + | ^ non-trivial anonymous constants must not depend on the parameter `N` + | + = help: it is currently only allowed to use either `N` or `{ N }` as generic constants + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs new file mode 100644 index 0000000000..9252b59236 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-76701-ty-param-in-const.rs @@ -0,0 +1,18 @@ +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] + +fn ty_param() -> [u8; std::mem::size_of::()] { + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + todo!() +} + +fn const_param() -> [u8; N + 1] { + //[full]~^ ERROR constant expression depends on a generic parameter + //[min]~^^ ERROR generic parameters must not be used inside of non trivial constant values + todo!() +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs b/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs index c22e61d0ce..28f80702dc 100644 --- a/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs +++ b/src/test/ui/const-generics/issues/issue70273-assoc-fn.rs @@ -1,7 +1,8 @@ // check-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait T { fn f(); diff --git a/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr b/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr deleted file mode 100644 index 931701b64b..0000000000 --- a/src/test/ui/const-generics/issues/issue70273-assoc-fn.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue70273-assoc-fn.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/min-and-full-same-time.rs b/src/test/ui/const-generics/min-and-full-same-time.rs new file mode 100644 index 0000000000..2365adc3a8 --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.rs @@ -0,0 +1,7 @@ +#![feature(const_generics)] +//~^ ERROR features `const_generics` and `min_const_generics` are incompatible +#![allow(incomplete_features)] +#![feature(min_const_generics)] + + +fn main() {} diff --git a/src/test/ui/const-generics/min-and-full-same-time.stderr b/src/test/ui/const-generics/min-and-full-same-time.stderr new file mode 100644 index 0000000000..907fec9bbe --- /dev/null +++ b/src/test/ui/const-generics/min-and-full-same-time.stderr @@ -0,0 +1,13 @@ +error: features `const_generics` and `min_const_generics` are incompatible, using them at the same time is not allowed + --> $DIR/min-and-full-same-time.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ +... +LL | #![feature(min_const_generics)] + | ^^^^^^^^^^^^^^^^^^ + | + = help: remove one of these features + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs new file mode 100644 index 0000000000..02944e2bff --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.rs @@ -0,0 +1,27 @@ +#![feature(min_const_generics)] + +// This test checks that non-static lifetimes are prohibited under `min_const_generics`. It +// currently emits an error with `min_const_generics`. This will ICE under `const_generics`. + +fn test() {} + +fn issue_75323_and_74447_1<'a>() -> &'a () { + test::<{ let _: &'a (); 3 },>(); + //~^ ERROR a non-static lifetime is not allowed in a `const` + &() +} + +fn issue_75323_and_74447_2() { + test::<{ let _: &(); 3 },>(); +} + +fn issue_75323_and_74447_3() { + test::<{ let _: &'static (); 3 },>(); +} + +fn issue_73375<'a>() { + [(); (|_: &'a u8| (), 0).1]; + //~^ ERROR a non-static lifetime is not allowed in a `const` +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr new file mode 100644 index 0000000000..cdfd491e39 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/forbid-non-static-lifetimes.stderr @@ -0,0 +1,21 @@ +error[E0658]: a non-static lifetime is not allowed in a `const` + --> $DIR/forbid-non-static-lifetimes.rs:9:22 + | +LL | test::<{ let _: &'a (); 3 },>(); + | ^^ + | + = note: see issue #44580 for more information + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error[E0658]: a non-static lifetime is not allowed in a `const` + --> $DIR/forbid-non-static-lifetimes.rs:23:16 + | +LL | [(); (|_: &'a u8| (), 0).1]; + | ^^ + | + = note: see issue #44580 for more information + = help: add `#![feature(const_generics)]` to the crate attributes to enable + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs new file mode 100644 index 0000000000..0973b373c1 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.rs @@ -0,0 +1,27 @@ +#![feature(min_const_generics)] + +trait Foo { + fn t1() -> [u8; std::mem::size_of::()]; //~ERROR generic parameters +} + +struct Bar(T); + +impl Bar { + fn t2() -> [u8; std::mem::size_of::()] { todo!() } // ok +} + +impl Bar { + fn t3() -> [u8; std::mem::size_of::()] {} //~ERROR generic `Self` +} + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr new file mode 100644 index 0000000000..edb77a8743 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-1.stderr @@ -0,0 +1,22 @@ +error: generic parameters must not be used inside of non trivial constant values + --> $DIR/self-ty-in-const-1.rs:4:41 + | +LL | fn t1() -> [u8; std::mem::size_of::()]; + | ^^^^ non-trivial anonymous constants must not depend on the parameter `Self` + | + = note: type parameters are currently not permitted in anonymous constants + +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-1.rs:14:41 + | +LL | fn t3() -> [u8; std::mem::size_of::()] {} + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-1.rs:13:9 + | +LL | impl Bar { + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs new file mode 100644 index 0000000000..e7f80d5008 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.rs @@ -0,0 +1,21 @@ +#![feature(min_const_generics)] + +struct Bar(T); + +trait Baz { + fn hey(); +} + +impl Baz for u16 { + fn hey() { + let _: [u8; std::mem::size_of::()]; // ok + } +} + +impl Baz for Bar { + fn hey() { + let _: [u8; std::mem::size_of::()]; //~ERROR generic `Self` + } +} + +fn main() {} diff --git a/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr new file mode 100644 index 0000000000..9ac6410a29 --- /dev/null +++ b/src/test/ui/const-generics/min_const_generics/self-ty-in-const-2.stderr @@ -0,0 +1,14 @@ +error: generic `Self` types are currently not permitted in anonymous constants + --> $DIR/self-ty-in-const-2.rs:17:41 + | +LL | let _: [u8; std::mem::size_of::()]; + | ^^^^ + | +note: not a concrete type + --> $DIR/self-ty-in-const-2.rs:15:17 + | +LL | impl Baz for Bar { + | ^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/nested-type.full.stderr b/src/test/ui/const-generics/nested-type.full.stderr index ded6f882ca..075bdceccf 100644 --- a/src/test/ui/const-generics/nested-type.full.stderr +++ b/src/test/ui/const-generics/nested-type.full.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` + | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` error: aborting due to 2 previous errors diff --git a/src/test/ui/const-generics/nested-type.min.stderr b/src/test/ui/const-generics/nested-type.min.stderr index 55f6fe7cc1..733b02fa85 100644 --- a/src/test/ui/const-generics/nested-type.min.stderr +++ b/src/test/ui/const-generics/nested-type.min.stderr @@ -24,7 +24,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/nested-type.rs:16:5 | LL | Foo::<17>::value() - | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{{constant}}#0::Foo::<17_usize>::value` + | ^^^^^^^^^^^^^^^^^^ calling non-const function `Foo::{constant#0}::Foo::<17_usize>::value` error: aborting due to 3 previous errors diff --git a/src/test/ui/const-generics/occurs-check/bind-param.rs b/src/test/ui/const-generics/occurs-check/bind-param.rs new file mode 100644 index 0000000000..68d1865000 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/bind-param.rs @@ -0,0 +1,17 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// This test does not use any "unevaluated" consts, so it should compile just fine. + +fn bind(value: [u8; N]) -> [u8; N] { + todo!() +} + +fn sink(_: [u8; 5]) {} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); + sink(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs b/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs new file mode 100644 index 0000000000..3cb9b7b9da --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.rs @@ -0,0 +1,18 @@ +#![feature(const_generics)] //~ WARN the feature `const_generics` is incomplete + +// It depends on how we normalize constants and how const equate works if this +// compiles. +// +// Please ping @lcnr if the output if this test changes. + + +fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + //~^ ERROR constant expression depends on a generic parameter + //~| ERROR constant expression depends on a generic parameter + todo!() +} + +fn main() { + let mut arr = Default::default(); + arr = bind::<2>(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr new file mode 100644 index 0000000000..671f1103dc --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-fixpoint.stderr @@ -0,0 +1,27 @@ +warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes + --> $DIR/unify-fixpoint.rs:1:12 + | +LL | #![feature(const_generics)] + | ^^^^^^^^^^^^^^ + | + = note: `#[warn(incomplete_features)]` on by default + = note: see issue #44580 for more information + +error: constant expression depends on a generic parameter + --> $DIR/unify-fixpoint.rs:9:32 + | +LL | fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: constant expression depends on a generic parameter + --> $DIR/unify-fixpoint.rs:9:48 + | +LL | fn bind(value: [u8; N + 2]) -> [u8; N * 2] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to 2 previous errors; 1 warning emitted + diff --git a/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs new file mode 100644 index 0000000000..552b1b2a66 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.rs @@ -0,0 +1,17 @@ +#![feature(const_generics)] +#![allow(incomplete_features)] + +// This test would try to unify `N` with `N + 1` which must fail the occurs check. + +fn bind(value: [u8; N]) -> [u8; N + 1] { + //~^ ERROR constant expression depends on a generic parameter + todo!() +} + +fn sink(_: [u8; 5]) {} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); + sink(arr); +} diff --git a/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr new file mode 100644 index 0000000000..c1ac7eec1e --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unify-n-nplusone.stderr @@ -0,0 +1,10 @@ +error: constant expression depends on a generic parameter + --> $DIR/unify-n-nplusone.rs:6:44 + | +LL | fn bind(value: [u8; N]) -> [u8; N + 1] { + | ^^^^^^^^^^^ + | + = note: this may fail depending on what value the parameter takes + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-1.rs b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs new file mode 100644 index 0000000000..f56687ecd9 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-1.rs @@ -0,0 +1,14 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +trait Bar {} +impl Bar for A<{ 6 + 1 }> {} + +struct A +where + A: Bar; + +fn main() { + let _ = A; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-2.rs b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs new file mode 100644 index 0000000000..12444ec531 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-2.rs @@ -0,0 +1,27 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +struct Foo; + +trait Bind { + fn bind() -> (T, Self); +} + +// `N` has to be `ConstKind::Unevaluated`. +impl Bind for Foo<{ 6 + 1 }> { + fn bind() -> (T, Self) { + (panic!(), Foo) + } +} + +fn main() { + let (mut t, foo) = Foo::bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-3.rs b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs new file mode 100644 index 0000000000..187e27382f --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-3.rs @@ -0,0 +1,18 @@ +// check-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +// The goal is is to get an unevaluated const `ct` with a `Ty::Infer(TyVar(_#1t)` subst. +// +// If we are then able to infer `ty::Infer(TyVar(_#1t) := Ty` we introduced an +// artificial inference cycle. +fn bind() -> (T, [u8; 6 + 1]) { + todo!() +} + +fn main() { + let (mut t, foo) = bind(); + // `t` is `ty::Infer(TyVar(_#1t))` + // `foo` contains `ty::Infer(TyVar(_#1t))` in its substs + t = foo; +} diff --git a/src/test/ui/const-generics/occurs-check/unused-substs-4.rs b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs new file mode 100644 index 0000000000..8e42ceb6d7 --- /dev/null +++ b/src/test/ui/const-generics/occurs-check/unused-substs-4.rs @@ -0,0 +1,12 @@ +// build-pass +#![feature(const_generics)] +#![allow(incomplete_features)] + +fn bind(value: [u8; N]) -> [u8; 3 + 4] { + todo!() +} + +fn main() { + let mut arr = Default::default(); + arr = bind(arr); +} diff --git a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr index 461822a960..e545ae8571 100644 --- a/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr +++ b/src/test/ui/const-generics/params-in-ct-in-ty-param-lazy-norm.min.stderr @@ -12,7 +12,7 @@ error: generic parameters must not be used inside of non trivial constant values LL | struct Foo()]>(T, U); | ^ non-trivial anonymous constants must not depend on the parameter `T` | - = help: it is currently only allowed to use either `T` or `{ T }` as generic constants + = note: type parameters are currently not permitted in anonymous constants error: constant values inside of type parameter defaults must not depend on generic parameters --> $DIR/params-in-ct-in-ty-param-lazy-norm.rs:12:21 diff --git a/src/test/ui/const-generics/std/const-generics-range.min.stderr b/src/test/ui/const-generics/std/const-generics-range.min.stderr new file mode 100644 index 0000000000..97be6ee644 --- /dev/null +++ b/src/test/ui/const-generics/std/const-generics-range.min.stderr @@ -0,0 +1,56 @@ +error: `std::ops::Range` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:8:24 + | +LL | struct _Range>; + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeFrom` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:13:28 + | +LL | struct _RangeFrom>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeFull` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:18:28 + | +LL | struct _RangeFull; + | ^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeInclusive` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:24:33 + | +LL | struct _RangeInclusive>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeTo` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:29:26 + | +LL | struct _RangeTo>; + | ^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `RangeToInclusive` is forbidden as the type of a const generic parameter + --> $DIR/const-generics-range.rs:34:35 + | +LL | struct _RangeToInclusive>; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/const-generics/std/const-generics-range.rs b/src/test/ui/const-generics/std/const-generics-range.rs index 6d56fe0d7b..136ac35289 100644 --- a/src/test/ui/const-generics/std/const-generics-range.rs +++ b/src/test/ui/const-generics/std/const-generics-range.rs @@ -1,30 +1,38 @@ -// check-pass -#![allow(incomplete_features)] -#![feature(const_generics)] +// [full] check-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // `Range` should be usable within const generics: struct _Range>; +//[min]~^ ERROR `std::ops::Range` is forbidden const RANGE : _Range<{ 0 .. 1000 }> = _Range; // `RangeFrom` should be usable within const generics: struct _RangeFrom>; +//[min]~^ ERROR `RangeFrom` is forbidden const RANGE_FROM : _RangeFrom<{ 0 .. }> = _RangeFrom; // `RangeFull` should be usable within const generics: struct _RangeFull; +//[min]~^ ERROR `RangeFull` is forbidden const RANGE_FULL : _RangeFull<{ .. }> = _RangeFull; // Regression test for #70155 // `RangeInclusive` should be usable within const generics: struct _RangeInclusive>; +//[min]~^ ERROR `RangeInclusive` is forbidden const RANGE_INCLUSIVE : _RangeInclusive<{ 0 ..= 999 }> = _RangeInclusive; // `RangeTo` should be usable within const generics: struct _RangeTo>; +//[min]~^ ERROR `RangeTo` is forbidden const RANGE_TO : _RangeTo<{ .. 1000 }> = _RangeTo; // `RangeToInclusive` should be usable within const generics: struct _RangeToInclusive>; +//[min]~^ ERROR `RangeToInclusive` is forbidden const RANGE_TO_INCLUSIVE : _RangeToInclusive<{ ..= 999 }> = _RangeToInclusive; pub fn main() {} diff --git a/src/test/ui/const-generics/type-after-const-ok.min.stderr b/src/test/ui/const-generics/type-after-const-ok.min.stderr new file mode 100644 index 0000000000..67a44d2c5b --- /dev/null +++ b/src/test/ui/const-generics/type-after-const-ok.min.stderr @@ -0,0 +1,8 @@ +error: type parameters must be declared prior to const parameters + --> $DIR/type-after-const-ok.rs:9:26 + | +LL | struct A(T); + | -----------------^- help: reorder the parameters: lifetimes, then types, then consts: `` + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/type-after-const-ok.rs b/src/test/ui/const-generics/type-after-const-ok.rs index fc977d6617..69227cdf19 100644 --- a/src/test/ui/const-generics/type-after-const-ok.rs +++ b/src/test/ui/const-generics/type-after-const-ok.rs @@ -1,10 +1,12 @@ -// run-pass +// [full] run-pass +// revisions: full min // Verifies that having generic parameters after constants is permitted - -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] #[allow(dead_code)] struct A(T); +//[min]~^ ERROR type parameters must be declared prior to const parameters fn main() {} diff --git a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs index c8db91b62b..aa85376bf0 100644 --- a/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs +++ b/src/test/ui/const-generics/type-dependent/auxiliary/type_dependent_lib.rs @@ -1,5 +1,6 @@ -#![feature(const_generics)] -#![allow(incomplete_features)] +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] pub struct Struct(()); diff --git a/src/test/ui/const-generics/type-dependent/issue-61936.rs b/src/test/ui/const-generics/type-dependent/issue-61936.rs index a7a923c6a5..f3b19109a7 100644 --- a/src/test/ui/const-generics/type-dependent/issue-61936.rs +++ b/src/test/ui/const-generics/type-dependent/issue-61936.rs @@ -1,23 +1,25 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait SliceExt { - fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N>; + fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N>; } impl SliceExt for [T] { - fn array_windows<'a, const N: usize>(&'a self) -> ArrayWindows<'a, T, N> { - ArrayWindows{ idx: 0, slice: &self } + fn array_windows_example<'a, const N: usize>(&'a self) -> ArrayWindowsExample<'a, T, N> { + ArrayWindowsExample{ idx: 0, slice: &self } } } -struct ArrayWindows<'a, T, const N: usize> { +struct ArrayWindowsExample<'a, T, const N: usize> { slice: &'a [T], idx: usize, } -impl <'a, T: Clone, const N: usize> Iterator for ArrayWindows<'a, T, N> { +impl <'a, T: Clone, const N: usize> Iterator for ArrayWindowsExample<'a, T, N> { type Item = [T; N]; fn next(&mut self) -> Option { // Note: this is unsound for some `T` and not meant as an example @@ -43,7 +45,7 @@ const FOUR: usize = 4; fn main() { let v: Vec = vec![0; 100]; - for array in v.as_slice().array_windows::() { + for array in v.as_slice().array_windows_example::() { assert_eq!(array, [0, 0, 0, 0]) } } diff --git a/src/test/ui/const-generics/type-dependent/issue-63695.rs b/src/test/ui/const-generics/type-dependent/issue-63695.rs index f3c2e17759..465b66b09c 100644 --- a/src/test/ui/const-generics/type-dependent/issue-63695.rs +++ b/src/test/ui/const-generics/type-dependent/issue-63695.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait T { fn test(&self) -> i32 { A } diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-1.rs b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs index a3d0595919..3d4910e9e4 100644 --- a/src/test/ui/const-generics/type-dependent/issue-67144-1.rs +++ b/src/test/ui/const-generics/type-dependent/issue-67144-1.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct X; diff --git a/src/test/ui/const-generics/type-dependent/issue-67144-2.rs b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs index c53a149fa8..0868d309b3 100644 --- a/src/test/ui/const-generics/type-dependent/issue-67144-2.rs +++ b/src/test/ui/const-generics/type-dependent/issue-67144-2.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct A; diff --git a/src/test/ui/const-generics/type-dependent/issue-69816.rs b/src/test/ui/const-generics/type-dependent/issue-69816.rs index cbe86cef32..4a374dc1db 100644 --- a/src/test/ui/const-generics/type-dependent/issue-69816.rs +++ b/src/test/ui/const-generics/type-dependent/issue-69816.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait IterExt: Sized + Iterator { fn default_for_size(self) -> [Self::Item; N] diff --git a/src/test/ui/const-generics/type-dependent/issue-70217.rs b/src/test/ui/const-generics/type-dependent/issue-70217.rs index caa611cbd7..ba5a42e47e 100644 --- a/src/test/ui/const-generics/type-dependent/issue-70217.rs +++ b/src/test/ui/const-generics/type-dependent/issue-70217.rs @@ -1,6 +1,9 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min + +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Struct; diff --git a/src/test/ui/const-generics/type-dependent/issue-70507.rs b/src/test/ui/const-generics/type-dependent/issue-70507.rs index 6fcf4116d4..234c09e04a 100644 --- a/src/test/ui/const-generics/type-dependent/issue-70507.rs +++ b/src/test/ui/const-generics/type-dependent/issue-70507.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait ConstChunksExactTrait { fn const_chunks_exact(&self) -> ConstChunksExact<'_, T, {N}>; diff --git a/src/test/ui/const-generics/type-dependent/issue-70586.rs b/src/test/ui/const-generics/type-dependent/issue-70586.rs index 5a0888506e..fd52373cee 100644 --- a/src/test/ui/const-generics/type-dependent/issue-70586.rs +++ b/src/test/ui/const-generics/type-dependent/issue-70586.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::marker::PhantomData; diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr new file mode 100644 index 0000000000..8656239605 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71348.min.stderr @@ -0,0 +1,20 @@ +error: `&'static str` is forbidden as the type of a const generic parameter + --> $DIR/issue-71348.rs:11:24 + | +LL | trait Get<'a, const N: &'static str> { + | ^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: `&'static str` is forbidden as the type of a const generic parameter + --> $DIR/issue-71348.rs:19:25 + | +LL | fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + | ^^^^^^^^^^^^ + | + = note: the only supported types are integers, `bool` and `char` + = note: more complex types are supported with `#[feature(const_generics)]` + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/const-generics/type-dependent/issue-71348.rs b/src/test/ui/const-generics/type-dependent/issue-71348.rs index ec22dcdf60..772e179746 100644 --- a/src/test/ui/const-generics/type-dependent/issue-71348.rs +++ b/src/test/ui/const-generics/type-dependent/issue-71348.rs @@ -1,12 +1,15 @@ -// run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// [full] run-pass +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Foo { i: i32, } trait Get<'a, const N: &'static str> { + //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter type Target: 'a; fn get(&'a self) -> &'a Self::Target; @@ -14,6 +17,7 @@ trait Get<'a, const N: &'static str> { impl Foo { fn ask<'a, const N: &'static str>(&'a self) -> &'a >::Target + //[min]~^ ERROR `&'static str` is forbidden as the type of a const generic parameter where Self: Get<'a, N>, { diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.full.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.full.stderr new file mode 100644 index 0000000000..da1d3270b7 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71382.full.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71382.rs:17:23 + | +LL | fn test u8>(&self) -> u8 { + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.min.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.min.stderr new file mode 100644 index 0000000000..da1d3270b7 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/issue-71382.min.stderr @@ -0,0 +1,8 @@ +error: using function pointers as const generic parameters is forbidden + --> $DIR/issue-71382.rs:17:23 + | +LL | fn test u8>(&self) -> u8 { + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.rs b/src/test/ui/const-generics/type-dependent/issue-71382.rs index 05abd48881..497fd1381d 100644 --- a/src/test/ui/const-generics/type-dependent/issue-71382.rs +++ b/src/test/ui/const-generics/type-dependent/issue-71382.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct Test; diff --git a/src/test/ui/const-generics/type-dependent/issue-71382.stderr b/src/test/ui/const-generics/type-dependent/issue-71382.stderr deleted file mode 100644 index f441b71031..0000000000 --- a/src/test/ui/const-generics/type-dependent/issue-71382.stderr +++ /dev/null @@ -1,17 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/issue-71382.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error: using function pointers as const generic parameters is forbidden - --> $DIR/issue-71382.rs:15:23 - | -LL | fn test u8>(&self) -> u8 { - | ^^^^^^^^^^ - -error: aborting due to previous error; 1 warning emitted - diff --git a/src/test/ui/const-generics/type-dependent/issue-71805.rs b/src/test/ui/const-generics/type-dependent/issue-71805.rs index 6823d780ae..2aaf12cea4 100644 --- a/src/test/ui/const-generics/type-dependent/issue-71805.rs +++ b/src/test/ui/const-generics/type-dependent/issue-71805.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::mem::MaybeUninit; diff --git a/src/test/ui/const-generics/type-dependent/issue-73730.rs b/src/test/ui/const-generics/type-dependent/issue-73730.rs index d90cc50ddc..3e53190ee4 100644 --- a/src/test/ui/const-generics/type-dependent/issue-73730.rs +++ b/src/test/ui/const-generics/type-dependent/issue-73730.rs @@ -1,6 +1,8 @@ // check-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] trait Foo<'a, A>: Iterator { fn bar(&mut self) -> *const [A; N]; diff --git a/src/test/ui/const-generics/type-dependent/non-local.rs b/src/test/ui/const-generics/type-dependent/non-local.rs index e6f3eb075f..747664a096 100644 --- a/src/test/ui/const-generics/type-dependent/non-local.rs +++ b/src/test/ui/const-generics/type-dependent/non-local.rs @@ -1,7 +1,9 @@ // aux-build:type_dependent_lib.rs // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] extern crate type_dependent_lib; diff --git a/src/test/ui/const-generics/type-dependent/qpath.rs b/src/test/ui/const-generics/type-dependent/qpath.rs index f3f98e5faf..ec23ff1d22 100644 --- a/src/test/ui/const-generics/type-dependent/qpath.rs +++ b/src/test/ui/const-generics/type-dependent/qpath.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct A; impl A { diff --git a/src/test/ui/const-generics/type-dependent/simple.rs b/src/test/ui/const-generics/type-dependent/simple.rs index cc7c50d8fd..70af655092 100644 --- a/src/test/ui/const-generics/type-dependent/simple.rs +++ b/src/test/ui/const-generics/type-dependent/simple.rs @@ -1,6 +1,8 @@ // run-pass -#![feature(const_generics)] -#![allow(incomplete_features)] +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct R; diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr new file mode 100644 index 0000000000..a530e63449 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/type-mismatch.full.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch.rs:12:27 + | +LL | assert_eq!(R.method::<1u16>(), 1); + | ^^^^ expected `u8`, found `u16` + | +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 + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr new file mode 100644 index 0000000000..a530e63449 --- /dev/null +++ b/src/test/ui/const-generics/type-dependent/type-mismatch.min.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/type-mismatch.rs:12:27 + | +LL | assert_eq!(R.method::<1u16>(), 1); + | ^^^^ expected `u8`, found `u16` + | +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 + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.rs b/src/test/ui/const-generics/type-dependent/type-mismatch.rs index 0c71f338bd..67d80973f0 100644 --- a/src/test/ui/const-generics/type-dependent/type-mismatch.rs +++ b/src/test/ui/const-generics/type-dependent/type-mismatch.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] struct R; diff --git a/src/test/ui/const-generics/type-dependent/type-mismatch.stderr b/src/test/ui/const-generics/type-dependent/type-mismatch.stderr deleted file mode 100644 index 5bb7c5b0ea..0000000000 --- a/src/test/ui/const-generics/type-dependent/type-mismatch.stderr +++ /dev/null @@ -1,23 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/type-mismatch.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -error[E0308]: mismatched types - --> $DIR/type-mismatch.rs:10:27 - | -LL | assert_eq!(R.method::<1u16>(), 1); - | ^^^^ expected `u8`, found `u16` - | -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; 1 warning emitted - -For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/types-mismatch-const-args.stderr b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr similarity index 64% rename from src/test/ui/const-generics/types-mismatch-const-args.stderr rename to src/test/ui/const-generics/types-mismatch-const-args.full.stderr index 49530c9d24..265e9ee618 100644 --- a/src/test/ui/const-generics/types-mismatch-const-args.stderr +++ b/src/test/ui/const-generics/types-mismatch-const-args.full.stderr @@ -1,14 +1,5 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/types-mismatch-const-args.rs:1:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - error[E0308]: mismatched types - --> $DIR/types-mismatch-const-args.rs:13:41 + --> $DIR/types-mismatch-const-args.rs:15:41 | LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32` @@ -17,7 +8,7 @@ LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data found type `4_u32` error[E0308]: mismatched types - --> $DIR/types-mismatch-const-args.rs:15:41 + --> $DIR/types-mismatch-const-args.rs:17:41 | LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData }; | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32` @@ -27,6 +18,6 @@ LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data = note: expected struct `A<'a, u16, {2u32}, {3u32}>` found struct `A<'b, u32, {2u32}, {3u32}>` -error: aborting due to 2 previous errors; 1 warning emitted +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/types-mismatch-const-args.min.stderr b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr new file mode 100644 index 0000000000..27277f0c0b --- /dev/null +++ b/src/test/ui/const-generics/types-mismatch-const-args.min.stderr @@ -0,0 +1,25 @@ +error[E0308]: mismatched types + --> $DIR/types-mismatch-const-args.rs:15:41 + | +LL | let _: A<'a, u32, {2u32}, {3u32}> = A::<'a, u32, {4u32}, {3u32}> { data: PhantomData }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `2_u32`, found `4_u32` + | | + | expected due to this + | + = note: expected struct `A<'_, _, 2_u32, _>` + found struct `A<'_, _, 4_u32, _>` + +error[E0308]: mismatched types + --> $DIR/types-mismatch-const-args.rs:17:41 + | +LL | let _: A<'a, u16, {2u32}, {3u32}> = A::<'b, u32, {2u32}, {3u32}> { data: PhantomData }; + | -------------------------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `u16`, found `u32` + | | + | expected due to this + | + = note: expected struct `A<'a, u16, _, _>` + found struct `A<'b, u32, _, _>` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/const-generics/types-mismatch-const-args.rs b/src/test/ui/const-generics/types-mismatch-const-args.rs index bf517c1126..34b85304cc 100644 --- a/src/test/ui/const-generics/types-mismatch-const-args.rs +++ b/src/test/ui/const-generics/types-mismatch-const-args.rs @@ -1,5 +1,7 @@ -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] // tests the diagnostic output of type mismatches for types that have const generics arguments. diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs index 7473718351..45afbdc9ab 100644 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::fmt; diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr deleted file mode 100644 index f41628d5d8..0000000000 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-1.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/uninferred-consts-during-codegen-1.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs index 8b95a01047..65ae05e119 100644 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs +++ b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.rs @@ -1,7 +1,8 @@ // run-pass - -#![feature(const_generics)] -//~^ WARN the feature `const_generics` is incomplete +// revisions: full min +#![cfg_attr(full, feature(const_generics))] +#![cfg_attr(full, allow(incomplete_features))] +#![cfg_attr(min, feature(min_const_generics))] use std::fmt; diff --git a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr b/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr deleted file mode 100644 index f1703bc3a2..0000000000 --- a/src/test/ui/const-generics/uninferred-consts-during-codegen-2.stderr +++ /dev/null @@ -1,11 +0,0 @@ -warning: the feature `const_generics` is incomplete and may not be safe to use and/or cause compiler crashes - --> $DIR/uninferred-consts-during-codegen-2.rs:3:12 - | -LL | #![feature(const_generics)] - | ^^^^^^^^^^^^^^ - | - = note: `#[warn(incomplete_features)]` on by default - = note: see issue #44580 for more information - -warning: 1 warning emitted - diff --git a/src/test/ui/const-suggest-feature.rs b/src/test/ui/const-suggest-feature.rs index 89fafbbe6f..d11b91edb8 100644 --- a/src/test/ui/const-suggest-feature.rs +++ b/src/test/ui/const-suggest-feature.rs @@ -2,8 +2,6 @@ const WRITE: () = unsafe { *std::ptr::null_mut() = 0; //~^ ERROR dereferencing raw pointers in constants is unstable //~| HELP add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable - //~| ERROR constant contains unimplemented expression type - //~| HELP add `#![feature(const_mut_refs)]` to the crate attributes to enable }; fn main() {} diff --git a/src/test/ui/const-suggest-feature.stderr b/src/test/ui/const-suggest-feature.stderr index 6b91df6b42..1ccc3d754f 100644 --- a/src/test/ui/const-suggest-feature.stderr +++ b/src/test/ui/const-suggest-feature.stderr @@ -7,15 +7,6 @@ LL | *std::ptr::null_mut() = 0; = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0019]: constant contains unimplemented expression type - --> $DIR/const-suggest-feature.rs:2:5 - | -LL | *std::ptr::null_mut() = 0; - | ^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0019, E0658. -For more information about an error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/const_evaluatable/associated-const.rs b/src/test/ui/const_evaluatable/associated-const.rs new file mode 100644 index 0000000000..a677763225 --- /dev/null +++ b/src/test/ui/const_evaluatable/associated-const.rs @@ -0,0 +1,11 @@ +// check-pass +struct Foo(T); +impl Foo { + const VALUE: usize = std::mem::size_of::(); +} + +fn test() { + let _ = [0; Foo::::VALUE]; +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/function-call.rs b/src/test/ui/const_evaluatable/function-call.rs new file mode 100644 index 0000000000..b5de66621c --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.rs @@ -0,0 +1,19 @@ +// check-pass + +const fn foo() -> usize { + // We might instead branch on `std::mem::size_of::<*mut T>() < 8` here, + // which would cause this function to fail on 32 bit systems. + if false { + std::mem::size_of::() + } else { + 8 + } +} + +fn test() { + let _ = [0; foo::()]; + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out +} + +fn main() {} diff --git a/src/test/ui/const_evaluatable/function-call.stderr b/src/test/ui/const_evaluatable/function-call.stderr new file mode 100644 index 0000000000..0d8463714e --- /dev/null +++ b/src/test/ui/const_evaluatable/function-call.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/function-call.rs:14:17 + | +LL | let _ = [0; foo::()]; + | ^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` 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 #76200 + +warning: 1 warning emitted + diff --git a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr index e2a3e4db8a..276fb716d4 100644 --- a/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr +++ b/src/test/ui/const_prop/ice-assert-fail-div-by-zero.stderr @@ -2,7 +2,7 @@ warning: this operation will panic at runtime --> $DIR/ice-assert-fail-div-by-zero.rs:11:5 | LL | f.0 / 0; - | ^^^^^^^ attempt to divide _ by zero + | ^^^^^^^ attempt to divide `_` by zero | note: the lint level is defined here --> $DIR/ice-assert-fail-div-by-zero.rs:5:9 diff --git a/src/test/ui/consts/array-literal-index-oob.stderr b/src/test/ui/consts/array-literal-index-oob.stderr index 08c0231536..5916ea6d32 100644 --- a/src/test/ui/consts/array-literal-index-oob.stderr +++ b/src/test/ui/consts/array-literal-index-oob.stderr @@ -2,7 +2,7 @@ warning: this operation will panic at runtime --> $DIR/array-literal-index-oob.rs:7:8 | LL | &{ [1, 2, 3][4] }; - | ^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 4 + | ^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 4 | note: the lint level is defined here --> $DIR/array-literal-index-oob.rs:4:20 diff --git a/src/test/ui/consts/assoc_const_generic_impl.stderr b/src/test/ui/consts/assoc_const_generic_impl.stderr index cd27331ad5..db64ebe0c4 100644 --- a/src/test/ui/consts/assoc_const_generic_impl.stderr +++ b/src/test/ui/consts/assoc_const_generic_impl.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const I_AM_ZERO_SIZED: () = [()][std::mem::size_of::()]; | -----------------------------^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 4 + | index out of bounds: the length is 1 but the index is 4 | note: the lint level is defined here --> $DIR/assoc_const_generic_impl.rs:3:9 diff --git a/src/test/ui/consts/async-block.rs b/src/test/ui/consts/async-block.rs new file mode 100644 index 0000000000..1fa2a61609 --- /dev/null +++ b/src/test/ui/consts/async-block.rs @@ -0,0 +1,8 @@ +// From + +// edition:2018 + +const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; +//~^ `async` block + +fn main() {} diff --git a/src/test/ui/consts/async-block.stderr b/src/test/ui/consts/async-block.stderr new file mode 100644 index 0000000000..99f470623a --- /dev/null +++ b/src/test/ui/consts/async-block.stderr @@ -0,0 +1,8 @@ +error: `async` blocks are not allowed in constants + --> $DIR/async-block.rs:5:47 + | +LL | const _: i32 = { core::mem::ManuallyDrop::new(async { 0 }); 4 }; + | ^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/auxiliary/const_fn_lib.rs b/src/test/ui/consts/auxiliary/const_fn_lib.rs index 85714efdbe..bf0b01a2ec 100644 --- a/src/test/ui/consts/auxiliary/const_fn_lib.rs +++ b/src/test/ui/consts/auxiliary/const_fn_lib.rs @@ -1,6 +1,6 @@ // Crate that exports a const fn. Used for testing cross-crate. -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] #![crate_type="rlib"] pub const fn foo() -> usize { 22 } diff --git a/src/test/ui/consts/cast-discriminant-zst-enum.rs b/src/test/ui/consts/cast-discriminant-zst-enum.rs index a772581201..9c02d232e1 100644 --- a/src/test/ui/consts/cast-discriminant-zst-enum.rs +++ b/src/test/ui/consts/cast-discriminant-zst-enum.rs @@ -1,5 +1,7 @@ // run-pass // Test a ZST enum whose dicriminant is ~0i128. This caused an ICE when casting to a i32. +#![feature(test)] +use std::hint::black_box; #[derive(Copy, Clone)] enum Nums { @@ -12,9 +14,6 @@ const NEG_ONE_I32: i32 = Nums::NegOne as i32; const NEG_ONE_I64: i64 = Nums::NegOne as i64; const NEG_ONE_I128: i128 = Nums::NegOne as i128; -#[inline(never)] -fn identity(t: T) -> T { t } - fn test_as_arg(n: Nums) { assert_eq!(-1i8, n as i8); assert_eq!(-1i16, n as i16); @@ -31,11 +30,11 @@ fn main() { assert_eq!(-1i64, kind as i64); assert_eq!(-1i128, kind as i128); - assert_eq!(-1i8, identity(kind) as i8); - assert_eq!(-1i16, identity(kind) as i16); - assert_eq!(-1i32, identity(kind) as i32); - assert_eq!(-1i64, identity(kind) as i64); - assert_eq!(-1i128, identity(kind) as i128); + assert_eq!(-1i8, black_box(kind) as i8); + assert_eq!(-1i16, black_box(kind) as i16); + assert_eq!(-1i32, black_box(kind) as i32); + assert_eq!(-1i64, black_box(kind) as i64); + assert_eq!(-1i128, black_box(kind) as i128); test_as_arg(Nums::NegOne); diff --git a/src/test/ui/consts/const-array-oob.rs b/src/test/ui/consts/const-array-oob.rs index 1174a76ada..eca2fe18ab 100644 --- a/src/test/ui/consts/const-array-oob.rs +++ b/src/test/ui/consts/const-array-oob.rs @@ -5,7 +5,7 @@ const BAR: usize = FOO[5]; // no error, because the error below occurs before re const BLUB: [u32; FOO[4]] = [5, 6]; //~^ ERROR evaluation of constant value failed [E0080] -//~| index out of bounds: the len is 3 but the index is 4 +//~| index out of bounds: the length is 3 but the index is 4 fn main() { let _ = BAR; diff --git a/src/test/ui/consts/const-array-oob.stderr b/src/test/ui/consts/const-array-oob.stderr index f25cac5cdd..1aa3e88e52 100644 --- a/src/test/ui/consts/const-array-oob.stderr +++ b/src/test/ui/consts/const-array-oob.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-array-oob.rs:6:19 | LL | const BLUB: [u32; FOO[4]] = [5, 6]; - | ^^^^^^ index out of bounds: the len is 3 but the index is 4 + | ^^^^^^ index out of bounds: the length is 3 but the index is 4 error: aborting due to previous error diff --git a/src/test/ui/consts/const-block-non-item-statement-3.rs b/src/test/ui/consts/const-block-non-item-statement-3.rs index 10a4c31f24..c513946d18 100644 --- a/src/test/ui/consts/const-block-non-item-statement-3.rs +++ b/src/test/ui/consts/const-block-non-item-statement-3.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(dead_code)] +#![allow(dead_code, unused)] type Array = [u32; { let x = 2; 5 }]; diff --git a/src/test/ui/consts/const-block-non-item-statement-rpass.rs b/src/test/ui/consts/const-block-non-item-statement-rpass.rs index a1b9b586ad..3e52eb50e7 100644 --- a/src/test/ui/consts/const-block-non-item-statement-rpass.rs +++ b/src/test/ui/consts/const-block-non-item-statement-rpass.rs @@ -1,5 +1,5 @@ // run-pass -#![allow(dead_code)] +#![allow(dead_code, unused)] #[repr(u8)] enum Foo { diff --git a/src/test/ui/consts/const-err-early.stderr b/src/test/ui/consts/const-err-early.stderr index 0cb7751819..36b36db7c1 100644 --- a/src/test/ui/consts/const-err-early.stderr +++ b/src/test/ui/consts/const-err-early.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | pub const A: i8 = -std::i8::MIN; | ------------------^^^^^^^^^^^^^- | | - | attempt to negate i8::MIN which would overflow + | attempt to negate `i8::MIN`, which would overflow | note: the lint level is defined here --> $DIR/const-err-early.rs:1:9 @@ -18,7 +18,7 @@ error: any use of this value will cause an error LL | pub const B: u8 = 200u8 + 200u8; | ------------------^^^^^^^^^^^^^- | | - | attempt to compute `200_u8 + 200_u8` which would overflow + | attempt to compute `200_u8 + 200_u8`, which would overflow error: any use of this value will cause an error --> $DIR/const-err-early.rs:5:19 @@ -26,7 +26,7 @@ error: any use of this value will cause an error LL | pub const C: u8 = 200u8 * 4; | ------------------^^^^^^^^^- | | - | attempt to compute `200_u8 * 4_u8` which would overflow + | attempt to compute `200_u8 * 4_u8`, which would overflow error: any use of this value will cause an error --> $DIR/const-err-early.rs:6:19 @@ -34,7 +34,7 @@ error: any use of this value will cause an error LL | pub const D: u8 = 42u8 - (42u8 + 1); | ------------------^^^^^^^^^^^^^^^^^- | | - | attempt to compute `42_u8 - 43_u8` which would overflow + | attempt to compute `42_u8 - 43_u8`, which would overflow error: any use of this value will cause an error --> $DIR/const-err-early.rs:7:19 @@ -42,7 +42,7 @@ error: any use of this value will cause an error LL | pub const E: u8 = [5u8][1]; | ------------------^^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 1 + | index out of bounds: the length is 1 but the index is 1 error: aborting due to 5 previous errors diff --git a/src/test/ui/consts/const-err-multi.stderr b/src/test/ui/consts/const-err-multi.stderr index a0c91ff6b5..5b688d4c6d 100644 --- a/src/test/ui/consts/const-err-multi.stderr +++ b/src/test/ui/consts/const-err-multi.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | pub const A: i8 = -std::i8::MIN; | ------------------^^^^^^^^^^^^^- | | - | attempt to negate i8::MIN which would overflow + | attempt to negate `i8::MIN`, which would overflow | note: the lint level is defined here --> $DIR/const-err-multi.rs:1:9 diff --git a/src/test/ui/consts/const-err.stderr b/src/test/ui/consts/const-err.stderr index ea27aa8fc8..693b74c2c2 100644 --- a/src/test/ui/consts/const-err.stderr +++ b/src/test/ui/consts/const-err.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const FOO: u8 = [5u8][1]; | ----------------^^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 1 + | index out of bounds: the length is 1 but the index is 1 | note: the lint level is defined here --> $DIR/const-err.rs:5:9 diff --git a/src/test/ui/consts/const-err2.noopt.stderr b/src/test/ui/consts/const-err2.noopt.stderr index 687ffc4c4b..2473632cbc 100644 --- a/src/test/ui/consts/const-err2.noopt.stderr +++ b/src/test/ui/consts/const-err2.noopt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow + | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow + | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 | LL | let b = 200u8 + 200u8 + 200u8; - | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 | LL | let c = 200u8 * 4; - | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:29:13 | LL | let d = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow error: this operation will panic at runtime --> $DIR/const-err2.rs:31:14 | LL | let _e = [5u8][1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-err2.opt.stderr b/src/test/ui/consts/const-err2.opt.stderr index 687ffc4c4b..2473632cbc 100644 --- a/src/test/ui/consts/const-err2.opt.stderr +++ b/src/test/ui/consts/const-err2.opt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow + | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow + | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 | LL | let b = 200u8 + 200u8 + 200u8; - | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 | LL | let c = 200u8 * 4; - | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:29:13 | LL | let d = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow error: this operation will panic at runtime --> $DIR/const-err2.rs:31:14 | LL | let _e = [5u8][1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr index 687ffc4c4b..2473632cbc 100644 --- a/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-err2.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:19:13 | LL | let a = -std::i8::MIN; - | ^^^^^^^^^^^^^ attempt to negate i8::MIN which would overflow + | ^^^^^^^^^^^^^ attempt to negate `i8::MIN`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/const-err2.rs:21:18 | LL | let a_i128 = -std::i128::MIN; - | ^^^^^^^^^^^^^^^ attempt to negate i128::MIN which would overflow + | ^^^^^^^^^^^^^^^ attempt to negate `i128::MIN`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:23:13 | LL | let b = 200u8 + 200u8 + 200u8; - | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `200_u8 + 200_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:25:18 | LL | let b_i128 = std::i128::MIN - std::i128::MAX; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i128::MIN - i128::MAX`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:27:13 | LL | let c = 200u8 * 4; - | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8` which would overflow + | ^^^^^^^^^ attempt to compute `200_u8 * 4_u8`, which would overflow error: this arithmetic operation will overflow --> $DIR/const-err2.rs:29:13 | LL | let d = 42u8 - (42u8 + 1); - | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8` which would overflow + | ^^^^^^^^^^^^^^^^^ attempt to compute `42_u8 - 43_u8`, which would overflow error: this operation will panic at runtime --> $DIR/const-err2.rs:31:14 | LL | let _e = [5u8][1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs index 4d3c714481..037c6f9f7e 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.rs @@ -1,7 +1,7 @@ // New test for #53818: modifying static memory at compile-time is not allowed. // The test should never compile successfully -#![feature(const_raw_ptr_deref)] +#![feature(const_raw_ptr_deref, const_mut_refs)] use std::cell::UnsafeCell; @@ -13,7 +13,7 @@ unsafe impl Sync for Foo {} static FOO: Foo = Foo(UnsafeCell::new(42)); static BAR: () = unsafe { - *FOO.0.get() = 5; //~ ERROR contains unimplemented expression type + *FOO.0.get() = 5; //~ ERROR }; fn main() {} diff --git a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr index 14dcc07463..296a6bf542 100644 --- a/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr +++ b/src/test/ui/consts/const-eval/assign-to-static-within-other-static-2.stderr @@ -1,11 +1,9 @@ -error[E0019]: static contains unimplemented expression type +error[E0080]: could not evaluate static initializer --> $DIR/assign-to-static-within-other-static-2.rs:16:5 | LL | *FOO.0.get() = 5; - | ^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + | ^^^^^^^^^^^^^^^^ modifying a static's initial value from another static's initializer error: aborting due to previous error -For more information about this error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/conditional_array_execution.stderr b/src/test/ui/consts/const-eval/conditional_array_execution.stderr index 62f339809e..65dfbd8097 100644 --- a/src/test/ui/consts/const-eval/conditional_array_execution.stderr +++ b/src/test/ui/consts/const-eval/conditional_array_execution.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const FOO: u32 = [X - Y, Y - X][(X < Y) as usize]; | ------------------^^^^^--------------------------- | | - | attempt to compute `5_u32 - 6_u32` which would overflow + | attempt to compute `5_u32 - 6_u32`, which would overflow | note: the lint level is defined here --> $DIR/conditional_array_execution.rs:3:9 diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr index dd79cbd7e5..0ae51786b3 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-eval-overflow-3.rs:20:11 | LL | = [0; (i8::MAX + 1) as usize]; - | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr index 3da34fe9af..2696d5a0b3 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-3b.stderr @@ -10,7 +10,7 @@ error[E0277]: cannot add `u8` to `i8` LL | = [0; (i8::MAX + 1u8) as usize]; | ^ no implementation for `i8 + u8` | - = help: the trait `std::ops::Add` is not implemented for `i8` + = help: the trait `Add` is not implemented for `i8` error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr index 30c52a82ea..e548fc266c 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-eval-overflow-4.rs:13:13 | LL | : [u32; (i8::MAX as i8 + 1i8) as usize] - | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow + | ^^^^^^^^^^^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr index e4d256c0ad..e695e9f75f 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow-4b.stderr @@ -10,7 +10,7 @@ error[E0277]: cannot add `u8` to `i8` LL | : [u32; (i8::MAX as i8 + 1u8) as usize] | ^ no implementation for `i8 + u8` | - = help: the trait `std::ops::Add` is not implemented for `i8` + = help: the trait `Add` is not implemented for `i8` error[E0604]: only `u8` can be cast as `char`, not `i8` --> $DIR/const-eval-overflow-4b.rs:25:13 diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr index 2ad557a711..51a810b8f3 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MIN - 1, - | | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `i8::MIN - 1_i8`, which would overflow LL | | ); | |_______- | @@ -20,7 +20,7 @@ error: any use of this value will cause an error LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i16::MIN - 1_i16`, which would overflow LL | | ); | |_______- @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i32::MIN - 1_i32`, which would overflow LL | | ); | |_______- @@ -40,7 +40,7 @@ error: any use of this value will cause an error LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i64::MIN - 1_i64`, which would overflow LL | | ); | |_______- @@ -50,7 +50,7 @@ error: any use of this value will cause an error LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MIN - 1, - | | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `0_u8 - 1_u8`, which would overflow LL | | ); | |_______- @@ -59,7 +59,7 @@ error: any use of this value will cause an error | LL | / const VALS_U16: (u16,) = ( LL | | u16::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `0_u16 - 1_u16`, which would overflow LL | | ); | |_______- @@ -68,7 +68,7 @@ error: any use of this value will cause an error | LL | / const VALS_U32: (u32,) = ( LL | | u32::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow LL | | ); | |_______- @@ -78,7 +78,7 @@ error: any use of this value will cause an error LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MIN - 1, - | | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `0_u64 - 1_u64`, which would overflow LL | | ); | |_______- diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr index fce616b296..eec440fcb7 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2b.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MAX + 1, - | | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `i8::MAX + 1_i8`, which would overflow LL | | ); | |_______- | @@ -20,7 +20,7 @@ error: any use of this value will cause an error LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i16::MAX + 1_i16`, which would overflow LL | | ); | |_______- @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i32::MAX + 1_i32`, which would overflow LL | | ); | |_______- @@ -40,7 +40,7 @@ error: any use of this value will cause an error LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i64::MAX + 1_i64`, which would overflow LL | | ); | |_______- @@ -50,7 +50,7 @@ error: any use of this value will cause an error LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MAX + 1, - | | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `u8::MAX + 1_u8`, which would overflow LL | | ); | |_______- @@ -59,7 +59,7 @@ error: any use of this value will cause an error | LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u16::MAX + 1_u16`, which would overflow LL | | ); | |_______- @@ -68,7 +68,7 @@ error: any use of this value will cause an error | LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u32::MAX + 1_u32`, which would overflow LL | | ); | |_______- @@ -78,7 +78,7 @@ error: any use of this value will cause an error LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MAX + 1, - | | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u64::MAX + 1_u64`, which would overflow LL | | ); | |_______- diff --git a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr index 76201524d3..e44f94c202 100644 --- a/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr +++ b/src/test/ui/consts/const-eval/const-eval-overflow2c.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | / const VALS_I8: (i8,) = LL | | ( LL | | i8::MIN * 2, - | | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `i8::MIN * 2_i8`, which would overflow LL | | ); | |_______- | @@ -20,7 +20,7 @@ error: any use of this value will cause an error LL | / const VALS_I16: (i16,) = LL | | ( LL | | i16::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i16::MIN * 2_i16`, which would overflow LL | | ); | |_______- @@ -30,7 +30,7 @@ error: any use of this value will cause an error LL | / const VALS_I32: (i32,) = LL | | ( LL | | i32::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i32::MIN * 2_i32`, which would overflow LL | | ); | |_______- @@ -40,7 +40,7 @@ error: any use of this value will cause an error LL | / const VALS_I64: (i64,) = LL | | ( LL | | i64::MIN * 2, - | | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `i64::MIN * 2_i64`, which would overflow LL | | ); | |_______- @@ -50,7 +50,7 @@ error: any use of this value will cause an error LL | / const VALS_U8: (u8,) = LL | | ( LL | | u8::MAX * 2, - | | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8` which would overflow + | | ^^^^^^^^^^^ attempt to compute `u8::MAX * 2_u8`, which would overflow LL | | ); | |_______- @@ -59,7 +59,7 @@ error: any use of this value will cause an error | LL | / const VALS_U16: (u16,) = ( LL | | u16::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u16::MAX * 2_u16`, which would overflow LL | | ); | |_______- @@ -68,7 +68,7 @@ error: any use of this value will cause an error | LL | / const VALS_U32: (u32,) = ( LL | | u32::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u32::MAX * 2_u32`, which would overflow LL | | ); | |_______- @@ -78,7 +78,7 @@ error: any use of this value will cause an error LL | / const VALS_U64: (u64,) = LL | | ( LL | | u64::MAX * 2, - | | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64` which would overflow + | | ^^^^^^^^^^^^ attempt to compute `u64::MAX * 2_u64`, which would overflow LL | | ); | |_______- diff --git a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr index dc2661ee79..8c57fd37e8 100644 --- a/src/test/ui/consts/const-eval/const-eval-query-stack.stderr +++ b/src/test/ui/consts/const-eval/const-eval-query-stack.stderr @@ -9,9 +9,9 @@ LL | let x: &'static i32 = &(1 / 0); = note: `#[deny(const_err)]` on by default query stack during panic: -#0 [const_eval_raw] const-evaluating `main::promoted[1]` -#1 [const_eval_validated] const-evaluating + checking `main::promoted[1]` -#2 [const_eval_validated] const-evaluating + checking `main::promoted[1]` +#0 [eval_to_allocation_raw] const-evaluating + checking `main::promoted[1]` +#1 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` +#2 [eval_to_const_value_raw] simplifying constant for the type system `main::promoted[1]` #3 [normalize_generic_arg_after_erasing_regions] normalizing `main::promoted[1]` #4 [optimized_mir] optimizing MIR for `main` #5 [collect_and_partition_mono_items] collect_and_partition_mono_items diff --git a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr index d24491e1bc..fb0ed1bd5a 100644 --- a/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr +++ b/src/test/ui/consts/const-eval/const-pointer-values-in-various-types.stderr @@ -36,7 +36,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:37:5 | LL | const I32_REF_U64_UNION: u64 = unsafe { Nonsense { int_32_ref: &3 }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -76,7 +76,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:52:5 | LL | const I32_REF_I64_UNION: i64 = unsafe { Nonsense { int_32_ref: &3 }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc47, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc38, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -100,7 +100,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:61:5 | LL | const I32_REF_F64_UNION: f64 = unsafe { Nonsense { int_32_ref: &3 }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc62, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc50, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -148,7 +148,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:79:5 | LL | const STR_U64_UNION: u64 = unsafe { Nonsense { stringy: "3" }.uint_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc71, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -188,7 +188,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:94:5 | LL | const STR_I64_UNION: i64 = unsafe { Nonsense { stringy: "3" }.int_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc101, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc86, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -212,7 +212,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/const-pointer-values-in-various-types.rs:103:5 | LL | const STR_F64_UNION: f64 = unsafe { Nonsense { stringy: "3" }.float_64 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc110, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc95, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/const_fn_ptr.stderr b/src/test/ui/consts/const-eval/const_fn_ptr.stderr index d0ae94079d..ab18020056 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr.stderr @@ -10,11 +10,23 @@ help: skipping check that does not even have a feature gate | LL | X_CONST(x) | ^^^^^^^^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr.rs:19:14 + | +LL | const fn foo(x: fn(usize) -> usize, y: usize) -> usize { + | ^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr.rs:20:5 + | +LL | x(y) + | ^ help: skipping check that does not even have a feature gate --> $DIR/const_fn_ptr.rs:20:5 | LL | x(y) | ^^^^ -warning: 1 warning emitted +error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr index 90ee2afa31..822d4af830 100644 --- a/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr +++ b/src/test/ui/consts/const-eval/const_fn_ptr_fail2.stderr @@ -20,6 +20,16 @@ LL | assert_eq!(Z, 4); warning: skipping const checks | +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr_fail2.rs:12:14 + | +LL | const fn bar(x: fn(usize) -> usize, y: usize) -> usize { + | ^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/const_fn_ptr_fail2.rs:13:5 + | +LL | x(y) + | ^ help: skipping check that does not even have a feature gate --> $DIR/const_fn_ptr_fail2.rs:13:5 | diff --git a/src/test/ui/consts/const-eval/const_panic_libcore_main.rs b/src/test/ui/consts/const-eval/const_panic_libcore_main.rs index 6b86feb592..6b03e847de 100644 --- a/src/test/ui/consts/const-eval/const_panic_libcore_main.rs +++ b/src/test/ui/consts/const-eval/const_panic_libcore_main.rs @@ -17,6 +17,8 @@ const X: () = unimplemented!(); #[lang = "eh_personality"] fn eh() {} +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; #[panic_handler] fn panic(_info: &PanicInfo) -> ! { diff --git a/src/test/ui/consts/const-eval/double_check2.rs b/src/test/ui/consts/const-eval/double_check2.rs index 8402d62885..81f5dde450 100644 --- a/src/test/ui/consts/const-eval/double_check2.rs +++ b/src/test/ui/consts/const-eval/double_check2.rs @@ -1,3 +1,9 @@ +// check-pass + +// This test exhibits undefined behavior, but it is very expensive and complex to check for such +// UB in constants. +// Thus, we do not detect it if you create references to statics in ways that are UB. + enum Foo { A = 5, B = 42, @@ -13,11 +19,14 @@ union Union { u8: &'static u8, } static BAR: u8 = 5; -static FOO: (&Foo, &Bar) = unsafe {( //~ undefined behavior - Union { u8: &BAR }.foo, - Union { u8: &BAR }.bar, -)}; -static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; -//~^ undefined behavior +static FOO: (&Foo, &Bar) = unsafe { + ( + // undefined behavior + Union { u8: &BAR }.foo, + Union { u8: &BAR }.bar, + ) +}; +static FOO2: (&Foo, &Bar) = unsafe { (std::mem::transmute(&BAR), std::mem::transmute(&BAR)) }; +//^ undefined behavior fn main() {} diff --git a/src/test/ui/consts/const-eval/double_check2.stderr b/src/test/ui/consts/const-eval/double_check2.stderr deleted file mode 100644 index 84f6080915..0000000000 --- a/src/test/ui/consts/const-eval/double_check2.stderr +++ /dev/null @@ -1,22 +0,0 @@ -error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:16:1 - | -LL | / static FOO: (&Foo, &Bar) = unsafe {( -LL | | Union { u8: &BAR }.foo, -LL | | Union { u8: &BAR }.bar, -LL | | )}; - | |___^ type validation failed: encountered 0x05 at .1.., but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -error[E0080]: it is undefined behavior to use this value - --> $DIR/double_check2.rs:20:1 - | -LL | static FOO2: (&Foo, &Bar) = unsafe {(std::mem::transmute(&BAR), std::mem::transmute(&BAR))}; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered 0x05 at .1.., but expected a valid enum tag - | - = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. - -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/erroneous-const.stderr b/src/test/ui/consts/const-eval/erroneous-const.stderr index f06e2c33fd..7087a6f668 100644 --- a/src/test/ui/consts/const-eval/erroneous-const.stderr +++ b/src/test/ui/consts/const-eval/erroneous-const.stderr @@ -2,7 +2,7 @@ warning: this operation will panic at runtime --> $DIR/erroneous-const.rs:6:22 | LL | const VOID: () = [()][2]; - | ^^^^^^^ index out of bounds: the len is 1 but the index is 2 + | ^^^^^^^ index out of bounds: the length is 1 but the index is 2 | note: the lint level is defined here --> $DIR/erroneous-const.rs:2:20 @@ -16,7 +16,7 @@ warning: any use of this value will cause an error LL | const VOID: () = [()][2]; | -----------------^^^^^^^- | | - | index out of bounds: the len is 1 but the index is 2 + | index out of bounds: the length is 1 but the index is 2 | note: the lint level is defined here --> $DIR/erroneous-const.rs:2:9 diff --git a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr index 33e60dd7c9..8647da90a3 100644 --- a/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr +++ b/src/test/ui/consts/const-eval/index-out-of-bounds-never-type.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const VOID: ! = { let x = 0 * std::mem::size_of::(); [][x] }; | --------------------------------------------------------^^^^^--- | | - | index out of bounds: the len is 0 but the index is 0 + | index out of bounds: the length is 0 but the index is 0 | note: the lint level is defined here --> $DIR/index-out-of-bounds-never-type.rs:4:9 diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds.stderr index 1b2974e4e3..8bb3a0c67d 100644 --- a/src/test/ui/consts/const-eval/index_out_of_bounds.stderr +++ b/src/test/ui/consts/const-eval/index_out_of_bounds.stderr @@ -2,7 +2,7 @@ error[E0080]: could not evaluate static initializer --> $DIR/index_out_of_bounds.rs:1:19 | LL | static FOO: i32 = [][0]; - | ^^^^^ index out of bounds: the len is 0 but the index is 0 + | ^^^^^ index out of bounds: the length is 0 but the index is 0 error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr index 4188efd021..d247d691db 100644 --- a/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr +++ b/src/test/ui/consts/const-eval/index_out_of_bounds_propagated.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/index_out_of_bounds_propagated.rs:5:5 | LL | array[1]; - | ^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-eval/issue-43197.stderr b/src/test/ui/consts/const-eval/issue-43197.stderr index b3e1f496ae..27e067cedb 100644 --- a/src/test/ui/consts/const-eval/issue-43197.stderr +++ b/src/test/ui/consts/const-eval/issue-43197.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | const X: u32 = 0 - 1; | ---------------^^^^^- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/issue-43197.rs:3:9 @@ -18,7 +18,7 @@ warning: any use of this value will cause an error LL | const Y: u32 = foo(0 - 1); | -------------------^^^^^-- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow error[E0080]: evaluation of constant expression failed --> $DIR/issue-43197.rs:14:23 diff --git a/src/test/ui/consts/const-eval/issue-50814-2.stderr b/src/test/ui/consts/const-eval/issue-50814-2.stderr index e04bf03a20..ca8885e935 100644 --- a/src/test/ui/consts/const-eval/issue-50814-2.stderr +++ b/src/test/ui/consts/const-eval/issue-50814-2.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const BAR: usize = [5, 6, 7][T::BOO]; | -------------------^^^^^^^^^^^^^^^^^- | | - | index out of bounds: the len is 3 but the index is 42 + | index out of bounds: the length is 3 but the index is 42 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-eval/issue-50814.stderr b/src/test/ui/consts/const-eval/issue-50814.stderr index 4be84f8d18..7327138627 100644 --- a/src/test/ui/consts/const-eval/issue-50814.stderr +++ b/src/test/ui/consts/const-eval/issue-50814.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const MAX: u8 = A::MAX + B::MAX; | ----------------^^^^^^^^^^^^^^^- | | - | attempt to compute `u8::MAX + u8::MAX` which would overflow + | attempt to compute `u8::MAX + u8::MAX`, which would overflow | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs index 59d46ea66c..bf8bae5ea2 100644 --- a/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs +++ b/src/test/ui/consts/const-eval/issue-70804-fn-subtyping.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] const fn nested(x: (for<'a> fn(&'a ()), String)) -> (fn(&'static ()), String) { x diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs index 32f0062168..481e046946 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.rs @@ -12,14 +12,9 @@ unsafe impl Sync for Foo {} static FOO: Foo = Foo(UnsafeCell::new(42)); -fn foo() {} - static BAR: () = unsafe { *FOO.0.get() = 5; - //~^ contains unimplemented expression - - foo(); - //~^ ERROR calls in statics are limited to constant functions, tuple structs and tuple variants + //~^ mutation through a reference }; fn main() { diff --git a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr index 44ae1ecf04..38282c0e30 100644 --- a/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr +++ b/src/test/ui/consts/const-eval/mod-static-with-const-fn.stderr @@ -1,18 +1,12 @@ -error[E0019]: static contains unimplemented expression type - --> $DIR/mod-static-with-const-fn.rs:18:5 +error[E0658]: mutation through a reference is not allowed in statics + --> $DIR/mod-static-with-const-fn.rs:16:5 | LL | *FOO.0.get() = 5; | ^^^^^^^^^^^^^^^^ | + = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0015]: calls in statics are limited to constant functions, tuple structs and tuple variants - --> $DIR/mod-static-with-const-fn.rs:21:5 - | -LL | foo(); - | ^^^^^ +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0015, E0019. -For more information about an error, try `rustc --explain E0015`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr index 52313205dc..ce83d8e9bb 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.noopt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:12:20 | LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -14,13 +14,13 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:14:14 | LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:41 @@ -50,13 +50,13 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:22:20 | LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:22:20 @@ -74,7 +74,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:26:14 | LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: 10 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr index b411bb2e7f..2c66b175cf 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:14:14 | LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -14,7 +14,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:41 @@ -44,13 +44,13 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:22:20 | LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:22:20 @@ -68,7 +68,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:26:14 | LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: 9 warnings emitted diff --git a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr index 52313205dc..ce83d8e9bb 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:12:20 | LL | println!("{}", 0u32 - 1); - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:20 @@ -14,13 +14,13 @@ warning: this arithmetic operation will overflow --> $DIR/promoted_errors.rs:14:14 | LL | let _x = 0u32 - 1; - | ^^^^^^^^ attempt to compute `0_u32 - 1_u32` which would overflow + | ^^^^^^^^ attempt to compute `0_u32 - 1_u32`, which would overflow warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:16:20 | LL | println!("{}", 1 / (1 - 1)); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero | note: the lint level is defined here --> $DIR/promoted_errors.rs:9:41 @@ -50,13 +50,13 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:20:14 | LL | let _x = 1 / (1 - 1); - | ^^^^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^^^^ attempt to divide `1_i32` by zero warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:22:20 | LL | println!("{}", 1 / (false as u32)); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: reaching this expression at runtime will panic or abort --> $DIR/promoted_errors.rs:22:20 @@ -74,7 +74,7 @@ warning: this operation will panic at runtime --> $DIR/promoted_errors.rs:26:14 | LL | let _x = 1 / (false as u32); - | ^^^^^^^^^^^^^^^^^^ attempt to divide 1_u32 by zero + | ^^^^^^^^^^^^^^^^^^ attempt to divide `1_u32` by zero warning: 10 warnings emitted diff --git a/src/test/ui/consts/const-eval/pub_const_err.stderr b/src/test/ui/consts/const-eval/pub_const_err.stderr index ecdba2f1c5..5be0fd9672 100644 --- a/src/test/ui/consts/const-eval/pub_const_err.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | pub const Z: u32 = 0 - 1; | -------------------^^^^^- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/pub_const_err.rs:2:9 diff --git a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr index b2b65767dc..55f8a58ea9 100644 --- a/src/test/ui/consts/const-eval/pub_const_err_bin.stderr +++ b/src/test/ui/consts/const-eval/pub_const_err_bin.stderr @@ -4,7 +4,7 @@ warning: any use of this value will cause an error LL | pub const Z: u32 = 0 - 1; | -------------------^^^^^- | | - | attempt to compute `0_u32 - 1_u32` which would overflow + | attempt to compute `0_u32 - 1_u32`, which would overflow | note: the lint level is defined here --> $DIR/pub_const_err_bin.rs:2:9 diff --git a/src/test/ui/consts/const-eval/shift_overflow.stderr b/src/test/ui/consts/const-eval/shift_overflow.stderr index 478769ca9f..e8d4076a61 100644 --- a/src/test/ui/consts/const-eval/shift_overflow.stderr +++ b/src/test/ui/consts/const-eval/shift_overflow.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/shift_overflow.rs:3:9 | LL | X = 1 << ((u32::MAX as u64) + 1), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by 4294967296_u64 which would overflow + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ attempt to shift left by `4294967296_u64`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-eval/ub-enum.stderr b/src/test/ui/consts/const-eval/ub-enum.stderr index 7b3ee535c8..db95b996c1 100644 --- a/src/test/ui/consts/const-eval/ub-enum.stderr +++ b/src/test/ui/consts/const-eval/ub-enum.stderr @@ -18,7 +18,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:30:1 | LL | const BAD_ENUM_WRAPPED: Wrap = unsafe { mem::transmute(&1) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc13 at .0., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc12 at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:44:1 | LL | const BAD_ENUM2_PTR: Enum2 = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc20 at ., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc18 at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -42,7 +42,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:47:1 | LL | const BAD_ENUM2_WRAPPED: Wrap = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc25 at .0., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc22 at .0., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. @@ -58,7 +58,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-enum.rs:60:1 | LL | const BAD_ENUM2_OPTION_PTR: Option = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc32 at ., but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc28 at ., but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/ub-nonnull.stderr b/src/test/ui/consts/const-eval/ub-nonnull.stderr index 38e9bdecdb..afd8a4b9e5 100644 --- a/src/test/ui/consts/const-eval/ub-nonnull.stderr +++ b/src/test/ui/consts/const-eval/ub-nonnull.stderr @@ -13,7 +13,7 @@ LL | / const OUT_OF_BOUNDS_PTR: NonNull = { unsafe { LL | | let ptr: &[u8; 256] = mem::transmute(&0u8); // &0 gets promoted so it does not dangle LL | | // Use address-of-element for pointer arithmetic. This could wrap around to NULL! LL | | let out_of_bounds_ptr = &ptr[255]; - | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc11 which has size 1 + | | ^^^^^^^^^ memory access failed: pointer must be in-bounds at offset 256, but is outside bounds of alloc10 which has size 1 LL | | mem::transmute(out_of_bounds_ptr) LL | | } }; | |____- diff --git a/src/test/ui/consts/const-eval/ub-ref.stderr b/src/test/ui/consts/const-eval/ub-ref.stderr index cd270f2a53..429ae69eab 100644 --- a/src/test/ui/consts/const-eval/ub-ref.stderr +++ b/src/test/ui/consts/const-eval/ub-ref.stderr @@ -34,7 +34,7 @@ error[E0080]: it is undefined behavior to use this value --> $DIR/ub-ref.rs:23:1 | LL | const REF_AS_USIZE: usize = unsafe { mem::transmute(&0) }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc16, but expected initialized plain (non-pointer) bytes + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type validation failed: encountered pointer to alloc14, but expected initialized plain (non-pointer) bytes | = note: The rules on what exactly is undefined behavior aren't clear, so this check might be overzealous. Please open an issue on the rustc repository if you believe it should not be considered undefined behavior. diff --git a/src/test/ui/consts/const-eval/unused-broken-const.stderr b/src/test/ui/consts/const-eval/unused-broken-const.stderr index a13cb87788..0cb13790f2 100644 --- a/src/test/ui/consts/const-eval/unused-broken-const.stderr +++ b/src/test/ui/consts/const-eval/unused-broken-const.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const FOO: i32 = [][0]; | -----------------^^^^^- | | - | index out of bounds: the len is 0 but the index is 0 + | index out of bounds: the length is 0 but the index is 0 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs index 6469a65700..e18e0a8357 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.rs @@ -7,7 +7,7 @@ extern "C" { const extern fn bar() { unsafe { regular_in_block(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } @@ -16,7 +16,7 @@ extern fn regular() {} const extern fn foo() { unsafe { regular(); - //~^ ERROR: can only call other `const fn` within a `const fn` + //~^ ERROR: calls in constant functions } } diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr index a9e2bcdbdd..348387ff5f 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-call-extern-fn.stderr @@ -1,21 +1,15 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `regular_in_block` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:9:9 | LL | regular_in_block(); | ^^^^^^^^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `regular` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-extern-fn-call-extern-fn.rs:18:9 | LL | regular(); | ^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs index 2854c08665..645a957949 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.rs @@ -2,11 +2,12 @@ const extern fn unsize(x: &[u8; 3]) -> &[u8] { x } const unsafe extern "C" fn closure() -> fn() { || {} } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast const unsafe extern fn use_float() { 1.0 + 1.0; } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn +//~^ ERROR floating point arithmetic const extern "C" fn ptr_cast(val: *const u8) { val as usize; } -//~^ ERROR casting pointers to ints is unstable in const fn +//~^ ERROR casting pointers to integers fn main() {} diff --git a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr index 146d119fc8..694e229080 100644 --- a/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr +++ b/src/test/ui/consts/const-extern-fn/const-extern-fn-min-const-fn.stderr @@ -1,30 +1,39 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/const-extern-fn-min-const-fn.rs:4:41 | LL | const unsafe extern "C" fn closure() -> fn() { || {} } | ^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/const-extern-fn-min-const-fn.rs:6:38 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/const-extern-fn-min-const-fn.rs:4:48 + | +LL | const unsafe extern "C" fn closure() -> fn() { || {} } + | ^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const-extern-fn-min-const-fn.rs:7:38 | LL | const unsafe extern fn use_float() { 1.0 + 1.0; } | ^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn - --> $DIR/const-extern-fn-min-const-fn.rs:8:48 +error[E0658]: casting pointers to integers in constant functions is unstable + --> $DIR/const-extern-fn-min-const-fn.rs:9:48 | LL | const extern "C" fn ptr_cast(val: *const u8) { val as usize; } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-external-macro-const-err.stderr b/src/test/ui/consts/const-external-macro-const-err.stderr index 06a630d82d..350e4b24de 100644 --- a/src/test/ui/consts/const-external-macro-const-err.stderr +++ b/src/test/ui/consts/const-external-macro-const-err.stderr @@ -2,7 +2,7 @@ error: any use of this value will cause an error --> $DIR/const-external-macro-const-err.rs:12:5 | LL | static_assert!(2 + 2 == 5); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len 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 = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/consts/const-fn-not-safe-for-const.rs b/src/test/ui/consts/const-fn-not-safe-for-const.rs index 085ff5c58e..0446ece421 100644 --- a/src/test/ui/consts/const-fn-not-safe-for-const.rs +++ b/src/test/ui/consts/const-fn-not-safe-for-const.rs @@ -1,6 +1,6 @@ // Test that we can't call random fns in a const fn or do other bad things. -#![feature(const_fn, const_transmute)] +#![feature(const_fn, const_fn_transmute)] use std::mem::transmute; diff --git a/src/test/ui/consts/const-len-underflow-separate-spans.stderr b/src/test/ui/consts/const-len-underflow-separate-spans.stderr index eff50587ca..2ab6d0ffde 100644 --- a/src/test/ui/consts/const-len-underflow-separate-spans.stderr +++ b/src/test/ui/consts/const-len-underflow-separate-spans.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const LEN: usize = ONE - TWO; | -------------------^^^^^^^^^- | | - | attempt to compute `1_usize - 2_usize` which would overflow + | attempt to compute `1_usize - 2_usize`, which would overflow | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-len-underflow-subspans.rs b/src/test/ui/consts/const-len-underflow-subspans.rs index 8ef8ef9625..ed77e90784 100644 --- a/src/test/ui/consts/const-len-underflow-subspans.rs +++ b/src/test/ui/consts/const-len-underflow-subspans.rs @@ -7,5 +7,5 @@ const TWO: usize = 2; fn main() { let a: [i8; ONE - TWO] = unimplemented!(); //~^ ERROR evaluation of constant value failed - //~| attempt to compute `1_usize - 2_usize` which would overflow + //~| attempt to compute `1_usize - 2_usize`, which would overflow } diff --git a/src/test/ui/consts/const-len-underflow-subspans.stderr b/src/test/ui/consts/const-len-underflow-subspans.stderr index e52e64b25b..68e958b378 100644 --- a/src/test/ui/consts/const-len-underflow-subspans.stderr +++ b/src/test/ui/consts/const-len-underflow-subspans.stderr @@ -2,7 +2,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/const-len-underflow-subspans.rs:8:17 | LL | let a: [i8; ONE - TWO] = unimplemented!(); - | ^^^^^^^^^ attempt to compute `1_usize - 2_usize` which would overflow + | ^^^^^^^^^ attempt to compute `1_usize - 2_usize`, which would overflow error: aborting due to previous error diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs index 2207599815..ce9be4ac5c 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.rs @@ -2,6 +2,7 @@ fn main() { foo(&mut 5); } -const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references in const fn are unstable +const fn foo(x: &mut i32) -> i32 { //~ ERROR mutable references *x + 1 + } diff --git a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr index 83e050c7a5..3f9bd37053 100644 --- a/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr +++ b/src/test/ui/consts/const-mut-refs/feature-gate-const_mut_refs.stderr @@ -1,12 +1,12 @@ -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/feature-gate-const_mut_refs.rs:5:14 | LL | const fn foo(x: &mut i32) -> i32 { | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const-nonzero.rs b/src/test/ui/consts/const-nonzero.rs deleted file mode 100644 index cf6f8c8d69..0000000000 --- a/src/test/ui/consts/const-nonzero.rs +++ /dev/null @@ -1,16 +0,0 @@ -// run-pass - -use std::num::NonZeroU8; - -const X: NonZeroU8 = unsafe { NonZeroU8::new_unchecked(5) }; -const Y: u8 = X.get(); - -const ZERO: Option = NonZeroU8::new(0); -const ONE: Option = NonZeroU8::new(1); - -fn main() { - assert_eq!(Y, 5); - - assert!(ZERO.is_none()); - assert_eq!(ONE.unwrap().get(), 1); -} diff --git a/src/test/ui/consts/const-option.rs b/src/test/ui/consts/const-option.rs deleted file mode 100644 index fbf20b9db6..0000000000 --- a/src/test/ui/consts/const-option.rs +++ /dev/null @@ -1,14 +0,0 @@ -// run-pass - -#![feature(const_option)] - -const X: Option = Some(32); -const Y: Option<&i32> = X.as_ref(); - -const IS_SOME: bool = X.is_some(); -const IS_NONE: bool = Y.is_none(); - -fn main() { - assert!(IS_SOME); - assert!(!IS_NONE) -} diff --git a/src/test/ui/consts/const-prop-ice.stderr b/src/test/ui/consts/const-prop-ice.stderr index 7bb4acb235..3bcf2b2de7 100644 --- a/src/test/ui/consts/const-prop-ice.stderr +++ b/src/test/ui/consts/const-prop-ice.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/const-prop-ice.rs:4:5 | LL | [0; 3][3u64 as usize]; - | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 3 but the index is 3 + | ^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 3 but the index is 3 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-prop-ice2.stderr b/src/test/ui/consts/const-prop-ice2.stderr index 73405eca34..2b65ffc2db 100644 --- a/src/test/ui/consts/const-prop-ice2.stderr +++ b/src/test/ui/consts/const-prop-ice2.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/const-prop-ice2.rs:6:20 | LL | println!("{}", xs[Enum::One as usize]); - | ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default diff --git a/src/test/ui/consts/const-size_of-cycle.stderr b/src/test/ui/consts/const-size_of-cycle.stderr index f4bff31c99..42e2749b20 100644 --- a/src/test/ui/consts/const-size_of-cycle.stderr +++ b/src/test/ui/consts/const-size_of-cycle.stderr @@ -1,32 +1,32 @@ -error[E0391]: cycle detected when const-evaluating + checking `Foo::bytes::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::bytes::{constant#0}` --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `Foo::bytes::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Foo::bytes::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::bytes::{constant#0}`... --> $DIR/const-size_of-cycle.rs:4:17 | LL | bytes: [u8; std::mem::size_of::()] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `std::mem::size_of`... +note: ...which requires const-evaluating + checking `std::mem::size_of`... --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | pub const fn size_of() -> usize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating + checking `std::intrinsics::size_of`... +note: ...which requires simplifying constant for the type system `std::intrinsics::size_of`... --> $SRC_DIR/core/src/intrinsics.rs:LL:COL | LL | pub fn size_of() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires computing layout of `Foo`... = note: ...which requires normalizing `[u8; _]`... - = note: ...which again requires const-evaluating + checking `Foo::bytes::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::bytes::{constant#0}`, completing the cycle note: cycle used when checking that `Foo` is well-formed --> $DIR/const-size_of-cycle.rs:3:1 | diff --git a/src/test/ui/consts/const-slice-oob.rs b/src/test/ui/consts/const-slice-oob.rs index 1775f35fac..70852f8f56 100644 --- a/src/test/ui/consts/const-slice-oob.rs +++ b/src/test/ui/consts/const-slice-oob.rs @@ -2,7 +2,7 @@ const FOO: &'static[u32] = &[1, 2, 3]; const BAR: u32 = FOO[5]; -//~^ index out of bounds: the len is 3 but the index is 5 +//~^ index out of bounds: the length is 3 but the index is 5 //~| ERROR any use of this value will cause an error fn main() { diff --git a/src/test/ui/consts/const-slice-oob.stderr b/src/test/ui/consts/const-slice-oob.stderr index 7e191a6336..0077bafe9e 100644 --- a/src/test/ui/consts/const-slice-oob.stderr +++ b/src/test/ui/consts/const-slice-oob.stderr @@ -4,7 +4,7 @@ error: any use of this value will cause an error LL | const BAR: u32 = FOO[5]; | -----------------^^^^^^- | | - | index out of bounds: the len is 3 but the index is 5 + | index out of bounds: the length is 3 but the index is 5 | = note: `#[deny(const_err)]` on by default diff --git a/src/test/ui/consts/const-unsized.stderr b/src/test/ui/consts/const-unsized.stderr index bf2844cfb7..27b200648e 100644 --- a/src/test/ui/consts/const-unsized.stderr +++ b/src/test/ui/consts/const-unsized.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:3:16 | LL | const CONST_0: dyn Debug + Sync = *(&0 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:6:18 @@ -12,15 +12,15 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | const CONST_FOO: str = *"foo"; | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` -error[E0277]: the size for values of type `(dyn std::fmt::Debug + std::marker::Sync + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Debug + Sync + 'static)` cannot be known at compilation time --> $DIR/const-unsized.rs:9:18 | LL | static STATIC_1: dyn Debug + Sync = *(&1 as &(dyn Debug + Sync)); | ^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::fmt::Debug + std::marker::Sync + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Debug + Sync + 'static)` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/const-unsized.rs:12:20 @@ -28,7 +28,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | static STATIC_BAR: str = *"bar"; | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` error: aborting due to 4 previous errors diff --git a/src/test/ui/consts/const-unwrap.stderr b/src/test/ui/consts/const-unwrap.stderr index 7f2c1f4151..6500baab07 100644 --- a/src/test/ui/consts/const-unwrap.stderr +++ b/src/test/ui/consts/const-unwrap.stderr @@ -5,7 +5,7 @@ LL | None => panic!("called `Option::unwrap()` on a `None` value"), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | the evaluated program panicked at 'called `Option::unwrap()` on a `None` value', $DIR/const-unwrap.rs:9:38 - | inside `std::option::Option::::unwrap` at $SRC_DIR/core/src/macros/mod.rs:LL:COL + | inside `Option::::unwrap` at $SRC_DIR/core/src/macros/mod.rs:LL:COL | inside `BAR` at $DIR/const-unwrap.rs:9:18 | ::: $DIR/const-unwrap.rs:9:1 diff --git a/src/test/ui/consts/const_discriminant.rs b/src/test/ui/consts/const_discriminant.rs index 1ad5134e71..d016d236db 100644 --- a/src/test/ui/consts/const_discriminant.rs +++ b/src/test/ui/consts/const_discriminant.rs @@ -1,14 +1,10 @@ // run-pass #![feature(const_discriminant)] +#![feature(test)] #![allow(dead_code)] use std::mem::{discriminant, Discriminant}; - -// `discriminant(const_expr)` may get const-propagated. -// As we want to check that const-eval is equal to ordinary exection, -// we wrap `const_expr` with a function which is not const to prevent this. -#[inline(never)] -fn identity(x: T) -> T { x } +use std::hint::black_box; enum Test { A(u8), @@ -31,10 +27,10 @@ const TEST_V: Discriminant = discriminant(&SingleVariant::V); fn main() { assert_eq!(TEST_A, TEST_A_OTHER); - assert_eq!(TEST_A, discriminant(identity(&Test::A(17)))); - assert_eq!(TEST_B, discriminant(identity(&Test::B))); + assert_eq!(TEST_A, discriminant(black_box(&Test::A(17)))); + assert_eq!(TEST_B, discriminant(black_box(&Test::B))); assert_ne!(TEST_A, TEST_B); - assert_ne!(TEST_B, discriminant(identity(&Test::C { a: 42, b: 7 }))); + assert_ne!(TEST_B, discriminant(black_box(&Test::C { a: 42, b: 7 }))); - assert_eq!(TEST_V, discriminant(identity(&SingleVariant::V))); + assert_eq!(TEST_V, discriminant(black_box(&SingleVariant::V))); } diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr new file mode 100644 index 0000000000..ae24f8f650 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.gated.stderr @@ -0,0 +1,8 @@ +error: fatal error triggered by #[rustc_error] + --> $DIR/const_fn_floating_point_arithmetic.rs:20:1 + | +LL | fn main() {} + | ^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.rs b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs new file mode 100644 index 0000000000..5e32482b21 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.rs @@ -0,0 +1,20 @@ +// gate-test-const_fn_floating_point_arithmetic + +// revisions: stock gated + +#![feature(rustc_attrs)] +#![cfg_attr(gated, feature(const_fn_floating_point_arithmetic))] + +const fn add(f: f32) -> f32 { f + 2.0 } +//[stock]~^ floating point arithmetic +const fn sub(f: f32) -> f32 { 2.0 - f } +//[stock]~^ floating point arithmetic +const fn mul(f: f32, g: f32) -> f32 { f * g } +//[stock]~^ floating point arithmetic +const fn div(f: f32, g: f32) -> f32 { f / g } +//[stock]~^ floating point arithmetic +const fn neg(f: f32) -> f32 { -f } +//[stock]~^ floating point arithmetic + +#[rustc_error] +fn main() {} //[gated]~ fatal error triggered by #[rustc_error] diff --git a/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr new file mode 100644 index 0000000000..ef7a60faf3 --- /dev/null +++ b/src/test/ui/consts/const_fn_floating_point_arithmetic.stock.stderr @@ -0,0 +1,48 @@ +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:8:31 + | +LL | const fn add(f: f32) -> f32 { f + 2.0 } + | ^^^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:10:31 + | +LL | const fn sub(f: f32) -> f32 { 2.0 - f } + | ^^^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:12:39 + | +LL | const fn mul(f: f32, g: f32) -> f32 { f * g } + | ^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:14:39 + | +LL | const fn div(f: f32, g: f32) -> f32 { f / g } + | ^^^^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error[E0658]: floating point arithmetic is not allowed in constant functions + --> $DIR/const_fn_floating_point_arithmetic.rs:16:31 + | +LL | const fn neg(f: f32) -> f32 { -f } + | ^^ + | + = note: see issue #57241 for more information + = help: add `#![feature(const_fn_floating_point_arithmetic)]` to the crate attributes to enable + +error: aborting due to 5 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs index 05c53e5edc..ab297f54df 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.rs @@ -12,7 +12,6 @@ fn main() { match None { consts::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } @@ -20,7 +19,6 @@ fn main() { match None { ::SOME => panic!(), //~^ must be annotated with `#[derive(PartialEq, Eq)]` - //~| must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } diff --git a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr index 5d147e32f5..a8066a88c3 100644 --- a/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/cross-crate-fail.stderr @@ -1,26 +1,14 @@ -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/cross-crate-fail.rs:13:9 | LL | consts::SOME => panic!(), | ^^^^^^^^^^^^ -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 +error: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/cross-crate-fail.rs:20:9 | LL | ::SOME => panic!(), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:13:9 - | -LL | consts::SOME => panic!(), - | ^^^^^^^^^^^^ - -error: to use a constant of type `consts::CustomEq` in a pattern, `consts::CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cross-crate-fail.rs:21:9 - | -LL | ::SOME => panic!(), - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - -error: aborting due to 4 previous errors +error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs index a1f9838ca0..856d204178 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.rs @@ -1,8 +1,5 @@ // check-pass -#![warn(indirect_structural_match)] -//~^ NOTE lint level is defined here - struct CustomEq; impl Eq for CustomEq {} @@ -32,7 +29,8 @@ fn main() { BAR_BAZ => panic!(), //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` //~| WARN this was previously accepted - //~| NOTE see issue #62411 + //~| NOTE see issue #73448 + //~| NOTE `#[warn(nontrivial_structural_match)]` on by default _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr index 0be1cca806..e51d6f9164 100644 --- a/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr +++ b/src/test/ui/consts/const_in_pattern/custom-eq-branch-warn.stderr @@ -1,16 +1,12 @@ -warning: to use a constant of type `CustomEq` in a pattern, `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/custom-eq-branch-warn.rs:32:9 +warning: to use a constant of type `CustomEq` in a pattern, the constant's initializer must be trivial or `CustomEq` must be annotated with `#[derive(PartialEq, Eq)]` + --> $DIR/custom-eq-branch-warn.rs:29:9 | LL | BAR_BAZ => panic!(), | ^^^^^^^ | -note: the lint level is defined here - --> $DIR/custom-eq-branch-warn.rs:3:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` 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 #62411 + = note: for more information, see issue #73448 warning: 1 warning emitted diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.rs b/src/test/ui/consts/const_in_pattern/issue-65466.rs index 0e3e0f6dd8..2b421f4c70 100644 --- a/src/test/ui/consts/const_in_pattern/issue-65466.rs +++ b/src/test/ui/consts/const_in_pattern/issue-65466.rs @@ -1,9 +1,7 @@ -// FIXME: This still ICEs. -// -// ignore-test - #![deny(indirect_structural_match)] +// check-pass + #[derive(PartialEq, Eq)] enum O { Some(*const T), // Can also use PhantomData diff --git a/src/test/ui/consts/const_in_pattern/issue-65466.stderr b/src/test/ui/consts/const_in_pattern/issue-65466.stderr deleted file mode 100644 index 9fe3049d1d..0000000000 --- a/src/test/ui/consts/const_in_pattern/issue-65466.stderr +++ /dev/null @@ -1,15 +0,0 @@ -error[E0601]: `main` function not found in crate `issue_65466` - --> $DIR/issue-65466.rs:1:1 - | -LL | / #![deny(indirect_structural_match)] -LL | | -LL | | #[derive(PartialEq, Eq)] -LL | | enum O { -... | -LL | | } -LL | | } - | |_^ consider adding a `main` function to `$DIR/issue-65466.rs` - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0601`. diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs index c7f02c615a..fc80d51c72 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.rs @@ -20,7 +20,6 @@ fn main() { match Foo::Qux(NoEq) { BAR_BAZ => panic!(), //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => {} } } diff --git a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr index ee78c6f5c3..e505dad69b 100644 --- a/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr +++ b/src/test/ui/consts/const_in_pattern/no-eq-branch-fail.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | BAR_BAZ => panic!(), | ^^^^^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/no-eq-branch-fail.rs:21:9 - | -LL | BAR_BAZ => panic!(), - | ^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs index bbeaeea1f8..7a8169bec4 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.rs +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.rs @@ -39,51 +39,41 @@ fn main() { const ENUM: Derive = Derive::Some(NoDerive); match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const FIELD: OND = TrivialEq(Some(NoDerive)).0; match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const NO_DERIVE_SOME: OND = Some(NoDerive); const INDIRECT: OND = NO_DERIVE_SOME; match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TUPLE: (OND, OND) = (None, Some(NoDerive)); match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const TYPE_ASCRIPTION: OND = Some(NoDerive): OND; match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ARRAY: [OND; 2] = [None, Some(NoDerive)]; match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const REPEAT: [OND; 2] = [Some(NoDerive); 2]; match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` trait Trait: Sized { const ASSOC: Option; } impl Trait for NoDerive { const ASSOC: Option = Some(NoDerive); } match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const BLOCK: OND = { NoDerive; Some(NoDerive) }; match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` const ADDR_OF: &OND = &Some(NoDerive); match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; diff --git a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr index b1310cf101..56405a55d6 100644 --- a/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr +++ b/src/test/ui/consts/const_in_pattern/reject_non_structural.stderr @@ -5,61 +5,61 @@ LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops" | ^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 + --> $DIR/reject_non_structural.rs:44:28 | LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 + --> $DIR/reject_non_structural.rs:49:27 | LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; | ^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 + --> $DIR/reject_non_structural.rs:53:36 | LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 + --> $DIR/reject_non_structural.rs:57:28 | LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 + --> $DIR/reject_non_structural.rs:61:36 | LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; | ^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 + --> $DIR/reject_non_structural.rs:65:33 | LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; | ^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 + --> $DIR/reject_non_structural.rs:71:28 | LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; | ^^^^^^^^^^^^^^^ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 + --> $DIR/reject_non_structural.rs:75:28 | LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; | ^^^^^ warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:89:29 + --> $DIR/reject_non_structural.rs:79:29 | LL | match &Some(NoDerive) { ADDR_OF => dbg!(ADDR_OF), _ => panic!("whoops"), }; | ^^^^^^^ @@ -72,65 +72,5 @@ LL | #![warn(indirect_structural_match)] = 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 #62411 -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:40:36 - | -LL | match Derive::Some(NoDerive) { ENUM => dbg!(ENUM), _ => panic!("whoops"), }; - | ^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:45:28 - | -LL | match Some(NoDerive) { FIELD => dbg!(FIELD), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:51:27 - | -LL | match Some(NoDerive) {INDIRECT => dbg!(INDIRECT), _ => panic!("whoops"), }; - | ^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:56:36 - | -LL | match (None, Some(NoDerive)) { TUPLE => dbg!(TUPLE), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:61:28 - | -LL | match Some(NoDerive) { TYPE_ASCRIPTION => dbg!(TYPE_ASCRIPTION), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:66:36 - | -LL | match [None, Some(NoDerive)] { ARRAY => dbg!(ARRAY), _ => panic!("whoops"), }; - | ^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:71:33 - | -LL | match [Some(NoDerive); 2] { REPEAT => dbg!(REPEAT), _ => panic!("whoops"), }; - | ^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:79:28 - | -LL | match Some(NoDerive) { NoDerive::ASSOC => dbg!(NoDerive::ASSOC), _ => panic!("whoops"), }; - | ^^^^^^^^^^^^^^^ - -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/reject_non_structural.rs:84:28 - | -LL | match Some(NoDerive) { BLOCK => dbg!(BLOCK), _ => panic!("whoops"), }; - | ^^^^^ - -error: aborting due to 20 previous errors; 1 warning emitted +error: aborting due to 10 previous errors; 1 warning emitted diff --git a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr index 3e7ed573c7..a24c8d1818 100644 --- a/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr +++ b/src/test/ui/consts/const_in_pattern/warn_corner_cases.stderr @@ -1,34 +1,30 @@ -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:26:47 | LL | match None { Some(_) => panic!("whoops"), INDEX => dbg!(INDEX), }; | ^^^^^ | -note: the lint level is defined here - --> $DIR/warn_corner_cases.rs:15:9 - | -LL | #![warn(indirect_structural_match)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: `#[warn(nontrivial_structural_match)]` 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 #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:32:47 | LL | match None { Some(_) => panic!("whoops"), CALL => dbg!(CALL), }; | ^^^^ | = 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 #62411 + = note: for more information, see issue #73448 -warning: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` +warning: to use a constant of type `NoDerive` in a pattern, the constant's initializer must be trivial or `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` --> $DIR/warn_corner_cases.rs:38:47 | LL | match None { Some(_) => panic!("whoops"), METHOD_CALL => dbg!(METHOD_CALL), }; | ^^^^^^^^^^^ | = 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 #62411 + = note: for more information, see issue #73448 warning: 3 warnings emitted diff --git a/src/test/ui/consts/const_let_assign3.rs b/src/test/ui/consts/const_let_assign3.rs index f993a427b4..2fd6e06067 100644 --- a/src/test/ui/consts/const_let_assign3.rs +++ b/src/test/ui/consts/const_let_assign3.rs @@ -6,23 +6,21 @@ struct S { impl S { const fn foo(&mut self, x: u32) { + //~^ ERROR mutable reference self.state = x; - //~^ contains unimplemented expression } } const FOO: S = { let mut s = S { state: 42 }; - s.foo(3); //~ ERROR mutable references are not allowed in constants + s.foo(3); //~ ERROR mutable reference s }; type Array = [u32; { let mut x = 2; - let y = &mut x; -//~^ ERROR mutable references are not allowed in constants + let y = &mut x; //~ ERROR mutable reference *y = 42; -//~^ ERROR constant contains unimplemented expression type *y }]; diff --git a/src/test/ui/consts/const_let_assign3.stderr b/src/test/ui/consts/const_let_assign3.stderr index dd05a4c0bb..dc86e178a4 100644 --- a/src/test/ui/consts/const_let_assign3.stderr +++ b/src/test/ui/consts/const_let_assign3.stderr @@ -1,9 +1,10 @@ -error[E0019]: constant function contains unimplemented expression type - --> $DIR/const_let_assign3.rs:9:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/const_let_assign3.rs:8:18 | -LL | self.state = x; - | ^^^^^^^^^^^^^^ +LL | const fn foo(&mut self, x: u32) { + | ^^^^^^^^^ | + = note: see issue #57349 for more information = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0764]: mutable references are not allowed in constants @@ -18,15 +19,7 @@ error[E0764]: mutable references are not allowed in constants LL | let y = &mut x; | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0019]: constant contains unimplemented expression type - --> $DIR/const_let_assign3.rs:24:5 - | -LL | *y = 42; - | ^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error: aborting due to 3 previous errors -error: aborting due to 4 previous errors - -Some errors have detailed explanations: E0019, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/const_let_eq_float.rs b/src/test/ui/consts/const_let_eq_float.rs index bc0ef26eb2..e15f4b804f 100644 --- a/src/test/ui/consts/const_let_eq_float.rs +++ b/src/test/ui/consts/const_let_eq_float.rs @@ -1,6 +1,6 @@ -// build-pass (FIXME(62277): could be check-pass?) +// run-pass -#![feature(const_fn)] +#![feature(const_fn_floating_point_arithmetic)] struct Foo(T); struct Bar { x: T } diff --git a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr index 85b38f41c5..31090be090 100644 --- a/src/test/ui/consts/const_unsafe_unreachable_ub.stderr +++ b/src/test/ui/consts/const_unsafe_unreachable_ub.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::unreachable() } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | | | entering unreachable code - | inside `std::hint::unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL + | inside `unreachable_unchecked` at $SRC_DIR/core/src/hint.rs:LL:COL | inside `foo` at $DIR/const_unsafe_unreachable_ub.rs:9:18 | inside `BAR` at $DIR/const_unsafe_unreachable_ub.rs:14:28 | diff --git a/src/test/ui/consts/consts-in-patterns.rs b/src/test/ui/consts/consts-in-patterns.rs index d51215447d..0295204c87 100644 --- a/src/test/ui/consts/consts-in-patterns.rs +++ b/src/test/ui/consts/consts-in-patterns.rs @@ -19,8 +19,6 @@ pub fn main() { assert_eq!(y, 2); let z = match &() { ZST => 9, - // FIXME: this should not be required - _ => 42, }; assert_eq!(z, 9); let z = match b"" { diff --git a/src/test/ui/consts/control-flow/drop-pass.rs b/src/test/ui/consts/control-flow/drop-pass.rs index 95f954a59a..2a6d12768c 100644 --- a/src/test/ui/consts/control-flow/drop-pass.rs +++ b/src/test/ui/consts/control-flow/drop-pass.rs @@ -1,6 +1,7 @@ // run-pass // revisions: stock precise +#![allow(unused)] #![cfg_attr(precise, feature(const_precise_live_drops))] // `x` is always moved into the final value and is not dropped inside the initializer. diff --git a/src/test/ui/consts/duration-consts-2.rs b/src/test/ui/consts/duration-consts-2.rs deleted file mode 100644 index c8b3939933..0000000000 --- a/src/test/ui/consts/duration-consts-2.rs +++ /dev/null @@ -1,57 +0,0 @@ -// run-pass - -#![feature(const_panic)] -#![feature(duration_consts_2)] -#![feature(div_duration)] - -use std::time::Duration; - -fn duration() { - const ZERO : Duration = Duration::new(0, 0); - assert_eq!(ZERO, Duration::from_secs(0)); - - const ONE : Duration = Duration::new(0, 1); - assert_eq!(ONE, Duration::from_nanos(1)); - - const MAX : Duration = Duration::new(u64::MAX, 1_000_000_000 - 1); - - const MAX_ADD_ZERO : Option = MAX.checked_add(ZERO); - assert_eq!(MAX_ADD_ZERO, Some(MAX)); - - const MAX_ADD_ONE : Option = MAX.checked_add(ONE); - assert_eq!(MAX_ADD_ONE, None); - - const ONE_SUB_ONE : Option = ONE.checked_sub(ONE); - assert_eq!(ONE_SUB_ONE, Some(ZERO)); - - const ZERO_SUB_ONE : Option = ZERO.checked_sub(ONE); - assert_eq!(ZERO_SUB_ONE, None); - - const ONE_MUL_ONE : Option = ONE.checked_mul(1); - assert_eq!(ONE_MUL_ONE, Some(ONE)); - - const MAX_MUL_TWO : Option = MAX.checked_mul(2); - assert_eq!(MAX_MUL_TWO, None); - - const ONE_DIV_ONE : Option = ONE.checked_div(1); - assert_eq!(ONE_DIV_ONE, Some(ONE)); - - const ONE_DIV_ZERO : Option = ONE.checked_div(0); - assert_eq!(ONE_DIV_ZERO, None); - - const MAX_AS_F32 : f32 = MAX.as_secs_f32(); - assert_eq!(MAX_AS_F32, 18446744000000000000.0_f32); - - const MAX_AS_F64 : f64 = MAX.as_secs_f64(); - assert_eq!(MAX_AS_F64, 18446744073709552000.0_f64); - - const ONE_AS_F32 : f32 = ONE.div_duration_f32(ONE); - assert_eq!(ONE_AS_F32, 1.0_f32); - - const ONE_AS_F64 : f64 = ONE.div_duration_f64(ONE); - assert_eq!(ONE_AS_F64, 1.0_f64); -} - -fn main() { - duration(); -} diff --git a/src/test/ui/consts/inline_asm.rs b/src/test/ui/consts/inline_asm.rs index c2ab97e54f..b8b755018e 100644 --- a/src/test/ui/consts/inline_asm.rs +++ b/src/test/ui/consts/inline_asm.rs @@ -1,6 +1,6 @@ #![feature(llvm_asm)] const _: () = unsafe { llvm_asm!("nop") }; -//~^ ERROR contains unimplemented expression type +//~^ ERROR inline assembly fn main() {} diff --git a/src/test/ui/consts/inline_asm.stderr b/src/test/ui/consts/inline_asm.stderr index 0a064c8136..6fb6b69d22 100644 --- a/src/test/ui/consts/inline_asm.stderr +++ b/src/test/ui/consts/inline_asm.stderr @@ -1,4 +1,4 @@ -error[E0019]: constant contains unimplemented expression type +error[E0015]: inline assembly is not allowed in constants --> $DIR/inline_asm.rs:3:24 | LL | const _: () = unsafe { llvm_asm!("nop") }; @@ -8,4 +8,4 @@ LL | const _: () = unsafe { llvm_asm!("nop") }; error: aborting due to previous error -For more information about this error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/consts/is_ascii.rs b/src/test/ui/consts/is_ascii.rs deleted file mode 100644 index d8424549f9..0000000000 --- a/src/test/ui/consts/is_ascii.rs +++ /dev/null @@ -1,15 +0,0 @@ -// run-pass - -static X: bool = 'a'.is_ascii(); -static Y: bool = 'ä'.is_ascii(); - -static BX: bool = b'a'.is_ascii(); -static BY: bool = 192u8.is_ascii(); - -fn main() { - assert!(X); - assert!(!Y); - - assert!(BX); - assert!(!BY); -} diff --git a/src/test/ui/consts/issue-37550.rs b/src/test/ui/consts/issue-37550.rs index 04865830df..15877c5374 100644 --- a/src/test/ui/consts/issue-37550.rs +++ b/src/test/ui/consts/issue-37550.rs @@ -2,7 +2,7 @@ #![allow(dead_code)] #![allow(unused_variables)] -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] const fn x() { let t = true; diff --git a/src/test/ui/consts/issue-56164.rs b/src/test/ui/consts/issue-56164.rs index 9d1a8b5946..90ea217698 100644 --- a/src/test/ui/consts/issue-56164.rs +++ b/src/test/ui/consts/issue-56164.rs @@ -1,12 +1,11 @@ -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] const fn foo() { (||{})() } -//~^ ERROR calls in constant functions are limited to constant functions, tuple structs and tuple -// variants +//~^ ERROR calls in constant functions const fn bad(input: fn()) { input() - //~^ ERROR function pointers are not allowed in const fn + //~^ ERROR function pointer } fn main() { diff --git a/src/test/ui/consts/issue-56164.stderr b/src/test/ui/consts/issue-56164.stderr index d3e9ce379a..500af0a400 100644 --- a/src/test/ui/consts/issue-56164.stderr +++ b/src/test/ui/consts/issue-56164.stderr @@ -5,7 +5,7 @@ LL | const fn foo() { (||{})() } | ^^^^^^^^ error: function pointers are not allowed in const fn - --> $DIR/issue-56164.rs:8:5 + --> $DIR/issue-56164.rs:7:5 | LL | input() | ^^^^^^^ diff --git a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr index 815cc9d836..8c839f94e3 100644 --- a/src/test/ui/consts/issue-68542-closure-in-array-len.stderr +++ b/src/test/ui/consts/issue-68542-closure-in-array-len.stderr @@ -8,7 +8,7 @@ error[E0080]: evaluation of constant value failed --> $DIR/issue-68542-closure-in-array-len.rs:6:13 | LL | a: [(); (|| { 0 })()] - | ^^^^^^^^^^^^ calling non-const function `Bug::a::{{constant}}#0::{{closure}}#0` + | ^^^^^^^^^^^^ calling non-const function `Bug::a::{constant#0}::{closure#0}` error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/match_ice.rs b/src/test/ui/consts/match_ice.rs index 1e495438e8..632335c841 100644 --- a/src/test/ui/consts/match_ice.rs +++ b/src/test/ui/consts/match_ice.rs @@ -9,11 +9,10 @@ fn main() { const C: &S = &S; match C { C => {} - //~^ ERROR to use a constant of type `S` in a pattern, `S` must be annotated with - //~| ERROR to use a constant of type `S` in a pattern, `S` must be annotated with + //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` } const K: &T = &T; - match K { //~ ERROR non-exhaustive patterns: `&T` not covered + match K { K => {} } } diff --git a/src/test/ui/consts/match_ice.stderr b/src/test/ui/consts/match_ice.stderr index 5477170fb1..699b4a5e20 100644 --- a/src/test/ui/consts/match_ice.stderr +++ b/src/test/ui/consts/match_ice.stderr @@ -4,24 +4,5 @@ error: to use a constant of type `S` in a pattern, `S` must be annotated with `# LL | C => {} | ^ -error[E0004]: non-exhaustive patterns: `&T` not covered - --> $DIR/match_ice.rs:16:11 - | -LL | struct T; - | --------- `T` defined here -... -LL | match K { - | ^ pattern `&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 `&T` +error: aborting due to previous error -error: to use a constant of type `S` in a pattern, `S` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match_ice.rs:11:9 - | -LL | C => {} - | ^ - -error: aborting due to 3 previous errors - -For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs index 937aae1a8e..dc10db177e 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.rs @@ -1,12 +1,14 @@ -#![feature(rustc_attrs, staged_api)] +#![feature(rustc_attrs, staged_api, allow_internal_unstable)] +#![feature(const_fn_fn_ptr_basics)] #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(since="1.0.0", feature = "mep")] -const fn error(_: fn()) {} //~ ERROR function pointers in const fn are unstable +const fn error(_: fn()) {} +//~^ ERROR const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]` #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allow_const_fn_ptr] #[rustc_const_stable(since="1.0.0", feature = "mep")] +#[allow_internal_unstable(const_fn_fn_ptr_basics)] const fn compiles(_: fn()) {} fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr index 9a14bcc2f7..a08d57b604 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr.stderr @@ -1,12 +1,17 @@ -error[E0723]: function pointers in const fn are unstable - --> $DIR/allow_const_fn_ptr.rs:5:16 +error: const-stable function cannot use `#[feature(const_fn_fn_ptr_basics)]` + --> $DIR/allow_const_fn_ptr.rs:6:16 | LL | const fn error(_: fn()) {} | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks + | +LL | #[allow_internal_unstable(const_fn_fn_ptr_basics)] + | error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs deleted file mode 100644 index 0f9d372929..0000000000 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.rs +++ /dev/null @@ -1,11 +0,0 @@ -#![feature(staged_api)] - -#[stable(feature = "rust1", since = "1.0.0")] -const fn error(_: fn()) {} - -#[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allow_const_fn_ptr] -//~^ ERROR internal implementation detail -const fn compiles(_: fn()) {} - -fn main() {} diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr deleted file mode 100644 index 7794cc7583..0000000000 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_feature_gate.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0658]: internal implementation detail - --> $DIR/allow_const_fn_ptr_feature_gate.rs:7:1 - | -LL | #[rustc_allow_const_fn_ptr] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(rustc_attrs)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs index 7aa9bd7e2d..b4e836bbc9 100644 --- a/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs +++ b/src/test/ui/consts/min_const_fn/allow_const_fn_ptr_run_pass.rs @@ -1,11 +1,13 @@ // run-pass +#![feature(allow_internal_unstable)] +#![feature(const_fn_fn_ptr_basics)] #![feature(rustc_attrs, staged_api)] #![stable(feature = "rust1", since = "1.0.0")] #[stable(feature = "rust1", since = "1.0.0")] -#[rustc_allow_const_fn_ptr] #[rustc_const_stable(since="1.0.0", feature = "mep")] +#[allow_internal_unstable(const_fn_fn_ptr_basics)] const fn takes_fn_ptr(_: fn()) {} const FN: fn() = || (); diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs index 3e42cb8c1b..4e1b7bf119 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.rs @@ -1,5 +1,7 @@ const fn foo(a: i32) -> Vec { - vec![1, 2, 3] //~ ERROR heap allocations are not allowed in const fn + vec![1, 2, 3] + //~^ ERROR allocations are not allowed + //~| ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr index 39b223062e..23697a8e11 100644 --- a/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr +++ b/src/test/ui/consts/min_const_fn/bad_const_fn_body_ice.stderr @@ -1,13 +1,20 @@ -error[E0723]: heap allocations are not allowed in const fn +error[E0010]: allocations are not allowed in constant functions + --> $DIR/bad_const_fn_body_ice.rs:2:5 + | +LL | vec![1, 2, 3] + | ^^^^^^^^^^^^^ allocation not allowed in constant functions + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/bad_const_fn_body_ice.rs:2:5 | LL | vec![1, 2, 3] | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +Some errors have detailed explanations: E0010, E0015. +For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/consts/min_const_fn/cast_errors.rs b/src/test/ui/consts/min_const_fn/cast_errors.rs index 8d730df16b..b68f47f5cb 100644 --- a/src/test/ui/consts/min_const_fn/cast_errors.rs +++ b/src/test/ui/consts/min_const_fn/cast_errors.rs @@ -2,12 +2,16 @@ fn main() {} const fn unsize(x: &[u8; 3]) -> &[u8] { x } const fn closure() -> fn() { || {} } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast const fn closure2() { (|| {}) as fn(); -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer } const fn reify(f: fn()) -> unsafe fn() { f } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer +//~| ERROR function pointer cast const fn reify2() { main as unsafe fn(); } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast diff --git a/src/test/ui/consts/min_const_fn/cast_errors.stderr b/src/test/ui/consts/min_const_fn/cast_errors.stderr index 583cb4e972..fb962bdf90 100644 --- a/src/test/ui/consts/min_const_fn/cast_errors.stderr +++ b/src/test/ui/consts/min_const_fn/cast_errors.stderr @@ -1,39 +1,75 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/cast_errors.rs:4:23 | LL | const fn closure() -> fn() { || {} } | ^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/cast_errors.rs:7:5 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:4:30 | -LL | (|| {}) as fn(); - | ^^^^^^^^^^^^^^^ +LL | const fn closure() -> fn() { || {} } + | ^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/cast_errors.rs:10:28 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:8:5 + | +LL | (|| {}) as fn(); + | ^^^^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/cast_errors.rs:11:16 + | +LL | const fn reify(f: fn()) -> unsafe fn() { f } + | ^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/cast_errors.rs:11:28 | LL | const fn reify(f: fn()) -> unsafe fn() { f } | ^^^^^^^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/cast_errors.rs:12:21 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:11:42 | -LL | const fn reify2() { main as unsafe fn(); } - | ^^^^^^^^^^^^^^^^^^^ +LL | const fn reify(f: fn()) -> unsafe fn() { f } + | ^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: aborting due to 4 previous errors +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:15:21 + | +LL | const fn reify2() { main as unsafe fn(); } + | ^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -For more information about this error, try `rustc --explain E0723`. +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/cast_errors.rs:15:21 + | +LL | const fn reify2() { main as unsafe fn(); } + | ^^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable + +error: aborting due to 8 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs index c2600f894d..638ff1d8b9 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.rs @@ -1,5 +1,8 @@ -const fn cmp(x: fn(), y: fn()) -> bool { //~ ERROR function pointers in const fn are unstable +const fn cmp(x: fn(), y: fn()) -> bool { + //~^ ERROR function pointer + //~| ERROR function pointer unsafe { x == y } + //~^ ERROR pointers cannot be reliably compared } fn main() {} diff --git a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr index 74e5228d0d..04c2febeb9 100644 --- a/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr +++ b/src/test/ui/consts/min_const_fn/cmp_fn_pointers.stderr @@ -1,12 +1,29 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/cmp_fn_pointers.rs:1:14 | LL | const fn cmp(x: fn(), y: fn()) -> bool { | ^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: aborting due to previous error +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/cmp_fn_pointers.rs:1:23 + | +LL | const fn cmp(x: fn(), y: fn()) -> bool { + | ^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -For more information about this error, try `rustc --explain E0723`. +error: pointers cannot be reliably compared during const eval. + --> $DIR/cmp_fn_pointers.rs:4:14 + | +LL | unsafe { x == y } + | ^^^^^^ + | + = note: see issue #53020 for more information + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.rs b/src/test/ui/consts/min_const_fn/min_const_fn.rs index 2ebd9dd10c..e46127c36b 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn.rs @@ -37,26 +37,34 @@ impl Foo { const fn into_inner(self) -> T { self.0 } //~ destructors cannot be evaluated const fn get(&self) -> &T { &self.0 } const fn get_mut(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } impl<'a, T> Foo { const fn new_lt(t: T) -> Self { Foo(t) } const fn into_inner_lt(self) -> T { self.0 } //~ destructors cannot be evaluated const fn get_lt(&'a self) -> &T { &self.0 } const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } impl Foo { const fn new_s(t: T) -> Self { Foo(t) } const fn into_inner_s(self) -> T { self.0 } //~ ERROR destructors const fn get_s(&self) -> &T { &self.0 } const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } impl Foo { const fn get_sq(&self) -> &T { &self.0 } const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } - //~^ mutable references in const fn are unstable + //~^ mutable references + //~| mutable references + //~| mutable references } @@ -77,29 +85,21 @@ const fn foo11(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable const fn foo11_2(t: T) -> T { t } //~^ ERROR trait bounds other than `Sized` on const fn parameters are unstable -const fn foo19(f: f32) -> f32 { f * 2.0 } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn -const fn foo19_2(f: f32) -> f32 { 2.0 - f } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn -const fn foo19_3(f: f32) -> f32 { -f } -//~^ ERROR only int and `bool` operations are stable in const fn -const fn foo19_4(f: f32, g: f32) -> f32 { f / g } -//~^ ERROR only int, `bool` and `char` operations are stable in const fn static BAR: u32 = 42; -const fn foo25() -> u32 { BAR } //~ ERROR cannot access `static` items in const fn -const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot access `static` items +const fn foo25() -> u32 { BAR } //~ ERROR cannot refer to statics +const fn foo26() -> &'static u32 { &BAR } //~ ERROR cannot refer to statics const fn foo30(x: *const u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2(x: *mut u32) -> usize { x as usize } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } -//~^ ERROR casting pointers to ints is unstable +//~^ ERROR casting pointers to integers const fn foo30_6() -> bool { let x = true; x } const fn inc(x: &mut i32) { *x += 1 } -//~^ ERROR mutable references in const fn are unstable +//~^ ERROR mutable references // ok const fn foo36(a: bool, b: bool) -> bool { a && b } @@ -125,17 +125,24 @@ impl Foo { struct AlanTuring(T); const fn no_apit2(_x: AlanTuring) {} //~^ ERROR trait bounds other than `Sized` -const fn no_apit(_x: impl std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` -const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} //~ ERROR trait bounds other than `Sized` +//~| ERROR destructor +const fn no_apit(_x: impl std::fmt::Debug) {} +//~^ ERROR trait bounds other than `Sized` +//~| ERROR destructor +const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} +//~^ ERROR trait bounds other than `Sized` const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } //~^ ERROR trait bounds other than `Sized` +//~| ERROR unsizing cast +//~| ERROR unsizing cast 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 unsizing cast const fn no_fn_ptrs(_x: fn()) {} -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } -//~^ ERROR function pointers in const fn are unstable +//~^ ERROR function pointer +//~| ERROR function pointer cast diff --git a/src/test/ui/consts/min_const_fn/min_const_fn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn.stderr index 9b55b6c6f3..ee5434b147 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn.stderr @@ -6,60 +6,132 @@ LL | const fn into_inner(self) -> T { self.0 } | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:39:22 + | +LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:39:36 | LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:39:45 + | +LL | const fn get_mut(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:44:28 + --> $DIR/min_const_fn.rs:46:28 | LL | const fn into_inner_lt(self) -> T { self.0 } | ^^^^ - value is dropped here | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:46:42 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:25 + | +LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:42 | LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:48:51 + | +LL | const fn get_mut_lt(&'a mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/min_const_fn.rs:51:27 + --> $DIR/min_const_fn.rs:55:27 | LL | const fn into_inner_s(self) -> T { self.0 } | ^^^^ - value is dropped here | | | constant functions cannot evaluate destructors -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:53:38 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:24 + | +LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:38 | LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable - --> $DIR/min_const_fn.rs:58:39 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:57:47 + | +LL | const fn get_mut_s(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:25 + | +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:39 | LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable + +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/min_const_fn.rs:64:48 + | +LL | const fn get_mut_sq(&mut self) -> &mut T { &mut self.0 } + | ^^^^^^^^^^^ + | + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:76:16 + --> $DIR/min_const_fn.rs:84:16 | LL | const fn foo11(t: T) -> T { t } | ^ @@ -68,7 +140,7 @@ LL | const fn foo11(t: T) -> T { t } = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:78:18 + --> $DIR/min_const_fn.rs:86:18 | LL | const fn foo11_2(t: T) -> T { t } | ^ @@ -76,104 +148,66 @@ LL | const fn foo11_2(t: T) -> T { t } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:80:33 - | -LL | const fn foo19(f: f32) -> f32 { f * 2.0 } - | ^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:82:35 - | -LL | const fn foo19_2(f: f32) -> f32 { 2.0 - f } - | ^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int and `bool` operations are stable in const fn - --> $DIR/min_const_fn.rs:84:35 - | -LL | const fn foo19_3(f: f32) -> f32 { -f } - | ^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: only int, `bool` and `char` operations are stable in const fn - --> $DIR/min_const_fn.rs:86:43 - | -LL | const fn foo19_4(f: f32, g: f32) -> f32 { f / g } - | ^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable - -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:90:27 | LL | const fn foo25() -> u32 { BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: cannot access `static` items in const fn +error[E0013]: constant functions cannot refer to statics --> $DIR/min_const_fn.rs:91:37 | LL | const fn foo26() -> &'static u32 { &BAR } | ^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: consider extracting the value of the `static` to a `const`, and referring to that -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:92:42 | LL | const fn foo30(x: *const u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:94:63 | LL | const fn foo30_with_unsafe(x: *const u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:96:42 | LL | const fn foo30_2(x: *mut u32) -> usize { x as usize } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: casting pointers to ints is unstable in const fn +error[E0658]: casting pointers to integers in constant functions is unstable --> $DIR/min_const_fn.rs:98:63 | LL | const fn foo30_2_with_unsafe(x: *mut u32) -> usize { unsafe { x as usize } } | ^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51910 for more information + = help: add `#![feature(const_raw_ptr_to_usize_cast)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable +error[E0658]: mutable references are not allowed in constant functions --> $DIR/min_const_fn.rs:101:14 | LL | const fn inc(x: &mut i32) { *x += 1 } | ^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable --> $DIR/min_const_fn.rs:110:6 @@ -211,8 +245,16 @@ LL | const fn no_apit2(_x: AlanTuring) {} = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:126:19 + | +LL | const fn no_apit2(_x: AlanTuring) {} + | ^^ - value is dropped here + | | + | constant functions cannot evaluate destructors + error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:128:22 + --> $DIR/min_const_fn.rs:129:22 | LL | const fn no_apit(_x: impl std::fmt::Debug) {} | ^^^^^^^^^^^^^^^^^^^^ @@ -220,8 +262,16 @@ LL | const fn no_apit(_x: impl std::fmt::Debug) {} = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/min_const_fn.rs:129:18 + | +LL | const fn no_apit(_x: impl std::fmt::Debug) {} + | ^^ - value is dropped here + | | + | constant functions cannot evaluate destructors + error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:129:23 + --> $DIR/min_const_fn.rs:132:23 | LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} | ^^ @@ -230,7 +280,7 @@ LL | const fn no_dyn_trait(_x: &dyn std::fmt::Debug) {} = help: add `#![feature(const_fn)]` to the crate attributes to enable error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:130:32 + --> $DIR/min_const_fn.rs:134:32 | LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -238,34 +288,61 @@ LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable - --> $DIR/min_const_fn.rs:135:41 +error[E0723]: unsizing casts to types besides slices are not allowed in const fn + --> $DIR/min_const_fn.rs:134:63 | -LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + | ^^^ | = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:138:21 +error[E0723]: unsizing casts to types besides slices are not allowed in const fn + --> $DIR/min_const_fn.rs:134:63 + | +LL | const fn no_dyn_trait_ret() -> &'static dyn std::fmt::Debug { &() } + | ^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0723]: unsizing casts to types besides slices are not allowed in const fn + --> $DIR/min_const_fn.rs:141:42 + | +LL | const fn really_no_traits_i_mean_it() { (&() as &dyn std::fmt::Debug, ()).1 } + | ^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn)]` to the crate attributes to enable + +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/min_const_fn.rs:144:21 | LL | const fn no_fn_ptrs(_x: fn()) {} | ^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn.rs:140:27 +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/min_const_fn.rs:146:27 | LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } | ^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error: aborting due to 30 previous errors +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/min_const_fn.rs:146:46 + | +LL | const fn no_fn_ptrs2() -> fn() { fn foo() {} foo } + | ^^^ + | + = note: see issue #57563 for more information + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -Some errors have detailed explanations: E0493, E0723. -For more information about an error, try `rustc --explain E0493`. +error: aborting due to 39 previous errors + +Some errors have detailed explanations: E0013, E0493, E0658, E0723. +For more information about an error, try `rustc --explain E0013`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs index 6ca1e59b3a..4a22ef2dff 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.rs @@ -10,6 +10,6 @@ const fn no_inner_dyn_trait2(x: Hide) { //~^ ERROR trait bounds other than `Sized` } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } -//~^ ERROR trait bounds other than `Sized` +//~^ ERROR unsizing cast fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr index 17e171c2fc..1394db591c 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_dyn.stderr @@ -7,7 +7,7 @@ LL | x.0.field; = note: see issue #57563 for more information = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: trait bounds other than `Sized` on const fn parameters are unstable +error[E0723]: unsizing casts to types besides slices are not allowed in const fn --> $DIR/min_const_fn_dyn.rs:12:66 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasDyn { field: &0 }) } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs index 584ea46b1a..bc6fe89222 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.rs @@ -1,3 +1,5 @@ +// gate-test-const_fn_fn_ptr_basics + struct HasPtr { field: fn(), } @@ -9,9 +11,9 @@ fn field() {} const fn no_inner_dyn_trait(_x: Hide) {} const fn no_inner_dyn_trait2(x: Hide) { x.0.field; -//~^ ERROR function pointers in const fn +//~^ ERROR function pointer } const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) } -//~^ ERROR function pointers in const fn +//~^ ERROR function pointer fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr index 58acbb5339..8d82674bbf 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_fn_ptr.stderr @@ -1,21 +1,21 @@ -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn_fn_ptr.rs:11:5 +error[E0658]: function pointers cannot appear in constant functions + --> $DIR/min_const_fn_fn_ptr.rs:13:5 | LL | x.0.field; | ^^^^^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable -error[E0723]: function pointers in const fn are unstable - --> $DIR/min_const_fn_fn_ptr.rs:14:59 +error[E0658]: function pointer casts are not allowed in constant functions + --> $DIR/min_const_fn_fn_ptr.rs:16:59 | LL | const fn no_inner_dyn_trait_ret() -> Hide { Hide(HasPtr { field }) } | ^^^^^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs index df10f3496c..292e2dd167 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] -// conformity is required, even with `const_fn` feature gate -const fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` operations +// Const-stable functions cannot rely on unstable const-eval features. +const fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -35,6 +36,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr index bef4f240ee..de6a9a1926 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_libstd_stability.stderr @@ -1,39 +1,41 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:16:25 | LL | const fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_fn_libstd_stability.rs:24:26 | LL | const fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_fn_libstd_stability.rs:29:26 | LL | const fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks + | +LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_fn_libstd_stability.rs:38:32 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_fn_libstd_stability.rs:39:32 | LL | const fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs index 6462d736ad..0c8af5a199 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.rs @@ -12,5 +12,5 @@ fn main() {} const unsafe fn no_union() { union Foo { x: (), y: () } Foo { x: () }.y - //~^ accessing union fields is unstable + //~^ unions in const fn } diff --git a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr index 427ecff5c6..322052c28f 100644 --- a/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_fn_unsafe_bad.stderr @@ -25,16 +25,15 @@ LL | const unsafe fn bad_const_unsafe_deref_raw_ref(x: *mut usize) -> &'static u = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0723]: accessing union fields is unstable +error[E0658]: unions in const fn are unstable --> $DIR/min_const_fn_unsafe_bad.rs:14:5 | LL | Foo { x: () }.y | ^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #51909 for more information + = help: add `#![feature(const_fn_union)]` to the crate attributes to enable error: aborting due to 4 previous errors -Some errors have detailed explanations: E0658, E0723. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs index 12b41ee2b0..0f48341ddf 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.rs @@ -3,7 +3,7 @@ we're apparently really bad at it", issue = "none")] -#![feature(const_fn, foo, foo2)] +#![feature(const_fn, const_fn_floating_point_arithmetic, foo, foo2)] #![feature(staged_api)] #[stable(feature = "rust1", since = "1.0.0")] @@ -13,7 +13,7 @@ const unsafe fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { unsafe { foo() } } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const unsafe fn foo2() -> u32 { 42 } @@ -21,12 +21,13 @@ const unsafe fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { unsafe { foo2() } } //~ ERROR not yet stable as a const fn #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // conformity is required, even with `const_fn` feature gate -const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } //~ ERROR only int, `bool` and `char` op +const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } +//~^ ERROR const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -36,6 +37,6 @@ const unsafe fn foo2_gated() -> u32 { 42 } #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } -//~^ ERROR can only call other `const fn` +//~^ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr index c5ff340dfc..f258deb12a 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability.stderr @@ -1,39 +1,41 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:16:41 | LL | const unsafe fn bar() -> u32 { unsafe { foo() } } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability.rs:24:42 | LL | const unsafe fn bar2() -> u32 { unsafe { foo2() } } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: only int, `bool` and `char` operations are stable in const fn +error: const-stable function cannot use `#[feature(const_fn_floating_point_arithmetic)]` --> $DIR/min_const_unsafe_fn_libstd_stability.rs:29:33 | LL | const unsafe fn bar3() -> u32 { (5f32 + 6f32) as u32 } | ^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable +help: if it is not part of the public API, make this function unstably const + | +LL | #[rustc_const_unstable(feature = "...", issue = "...")] + | +help: otherwise `#[allow_internal_unstable]` can be used to bypass stability checks + | +LL | #[allow_internal_unstable(const_fn_floating_point_arithmetic)] + | -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` - --> $DIR/min_const_unsafe_fn_libstd_stability.rs:38:48 +error: `foo2_gated` is not yet stable as a const fn + --> $DIR/min_const_unsafe_fn_libstd_stability.rs:39:48 | LL | const unsafe fn bar2_gated() -> u32 { unsafe { foo2_gated() } } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs index 44a6209498..d17dcb2811 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.rs @@ -13,7 +13,7 @@ const fn foo() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar() -> u32 { foo() } //~ ERROR can only call other `const fn` +const unsafe fn bar() -> u32 { foo() } //~ ERROR not yet stable as a const fn #[unstable(feature = "rust1", issue = "none")] const fn foo2() -> u32 { 42 } @@ -21,7 +21,7 @@ const fn foo2() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2() -> u32 { foo2() } //~ ERROR can only call other `const fn` +const unsafe fn bar2() -> u32 { foo2() } //~ ERROR not yet stable as a const fn // check whether this function cannot be called even with the feature gate active #[unstable(feature = "foo2", issue = "none")] @@ -30,6 +30,6 @@ const fn foo2_gated() -> u32 { 42 } #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] // can't call non-min_const_fn -const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR can only call other `const fn` +const unsafe fn bar2_gated() -> u32 { foo2_gated() } //~ ERROR not yet stable as a const fn fn main() {} diff --git a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr index 31ad12c955..891c34a888 100644 --- a/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr +++ b/src/test/ui/consts/min_const_fn/min_const_unsafe_fn_libstd_stability2.stderr @@ -1,30 +1,26 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `foo` is not stable as `const fn` +error: `foo` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:16:32 | LL | const unsafe fn bar() -> u32 { foo() } | ^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2` is not stable as `const fn` +error: `foo2` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:24:33 | LL | const unsafe fn bar2() -> u32 { foo2() } | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions -error[E0723]: can only call other `const fn` within a `const fn`, but `foo2_gated` is not stable as `const fn` +error: `foo2_gated` is not yet stable as a const fn --> $DIR/min_const_unsafe_fn_libstd_stability2.rs:33:39 | LL | const unsafe fn bar2_gated() -> u32 { foo2_gated() } | ^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0723`. diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.rs b/src/test/ui/consts/min_const_fn/mutable_borrow.rs index 89acfea6ed..580b1d50f7 100644 --- a/src/test/ui/consts/min_const_fn/mutable_borrow.rs +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.rs @@ -1,6 +1,6 @@ const fn mutable_ref_in_const() -> u8 { let mut a = 0; - let b = &mut a; //~ ERROR mutable references in const fn + let b = &mut a; //~ ERROR mutable references *b } @@ -9,7 +9,7 @@ struct X; impl X { const fn inherent_mutable_ref_in_const() -> u8 { let mut a = 0; - let b = &mut a; //~ ERROR mutable references in const fn + let b = &mut a; //~ ERROR mutable references *b } } diff --git a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr index f5a3c168a8..8e95a4c68a 100644 --- a/src/test/ui/consts/min_const_fn/mutable_borrow.stderr +++ b/src/test/ui/consts/min_const_fn/mutable_borrow.stderr @@ -1,21 +1,21 @@ -error[E0723]: mutable references in const fn are unstable - --> $DIR/mutable_borrow.rs:3:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/mutable_borrow.rs:3:13 | LL | let b = &mut a; - | ^ + | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable - --> $DIR/mutable_borrow.rs:12:13 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/mutable_borrow.rs:12:17 | LL | let b = &mut a; - | ^ + | ^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr index eb250081d6..8fd562c5da 100644 --- a/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr +++ b/src/test/ui/consts/miri_unleashed/abi-mismatch.stderr @@ -12,6 +12,16 @@ LL | static VAL: () = call_rust_fn(unsafe { std::mem::transmute(c_fn as extern " warning: skipping const checks | +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/abi-mismatch.rs:9:23 + | +LL | const fn call_rust_fn(my_fn: extern "Rust" fn()) { + | ^^^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/abi-mismatch.rs:10:5 + | +LL | my_fn(); + | ^^^^^ help: skipping check that does not even have a feature gate --> $DIR/abi-mismatch.rs:10:5 | diff --git a/src/test/ui/consts/miri_unleashed/box.stderr b/src/test/ui/consts/miri_unleashed/box.stderr index 768b795ca5..66ea9d5924 100644 --- a/src/test/ui/consts/miri_unleashed/box.stderr +++ b/src/test/ui/consts/miri_unleashed/box.stderr @@ -21,7 +21,7 @@ help: skipping check for `const_mut_refs` feature | LL | &mut *(box 0) | ^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/box.rs:10:5 | LL | &mut *(box 0) diff --git a/src/test/ui/consts/miri_unleashed/drop.rs b/src/test/ui/consts/miri_unleashed/drop.rs index 9bd56e81cb..4afa954d90 100644 --- a/src/test/ui/consts/miri_unleashed/drop.rs +++ b/src/test/ui/consts/miri_unleashed/drop.rs @@ -1,5 +1,5 @@ // compile-flags: -Zunleash-the-miri-inside-of-you -// error-pattern: calling non-const function ` as std::ops::Drop>::drop` +// error-pattern: calling non-const function ` as Drop>::drop` #![allow(const_err)] use std::mem::ManuallyDrop; diff --git a/src/test/ui/consts/miri_unleashed/drop.stderr b/src/test/ui/consts/miri_unleashed/drop.stderr index c1ab52435e..eb1b42c57b 100644 --- a/src/test/ui/consts/miri_unleashed/drop.stderr +++ b/src/test/ui/consts/miri_unleashed/drop.stderr @@ -1,22 +1,16 @@ error[E0080]: could not evaluate static initializer --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | | ^ - | | | - | |_calling non-const function ` as std::ops::Drop>::drop` - | inside `std::intrinsics::drop_in_place::> - shim(Some(std::vec::Vec))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | | + | calling non-const function ` as Drop>::drop` + | inside `drop_in_place::> - shim(Some(Vec))` at $SRC_DIR/core/src/ptr/mod.rs:LL:COL | ::: $DIR/drop.rs:18:1 | -LL | }; - | - inside `TEST_BAD` at $DIR/drop.rs:18:1 +LL | }; + | - inside `TEST_BAD` at $DIR/drop.rs:18:1 warning: skipping const checks | diff --git a/src/test/ui/consts/miri_unleashed/mutable_references.stderr b/src/test/ui/consts/miri_unleashed/mutable_references.stderr index 7109ffd8b6..c6180c1e00 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references.stderr @@ -6,17 +6,17 @@ LL | *OH_YES = 99; warning: skipping const checks | -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:9:26 | LL | static FOO: &&mut u32 = &&mut 42; | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:13:23 | LL | static BAR: &mut () = &mut (); | ^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:18:28 | LL | static BOO: &mut Foo<()> = &mut Foo(()); @@ -26,7 +26,7 @@ help: skipping check that does not even have a feature gate | LL | x: &UnsafeCell::new(42), | ^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references.rs:30:27 | LL | static OH_YES: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr index 45e7d5a2cc..7647a9ff4f 100644 --- a/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr +++ b/src/test/ui/consts/miri_unleashed/mutable_references_err.stderr @@ -30,7 +30,7 @@ help: skipping check that does not even have a feature gate | LL | const SNEAKY: &dyn Sync = &Synced { x: UnsafeCell::new(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -help: skipping check for `const_mut_refs` feature +help: skipping check that does not even have a feature gate --> $DIR/mutable_references_err.rs:30:25 | LL | const BLUNT: &mut i32 = &mut 42; diff --git a/src/test/ui/consts/miri_unleashed/tls.stderr b/src/test/ui/consts/miri_unleashed/tls.stderr index 27d2b2df4d..5cef636e0a 100644 --- a/src/test/ui/consts/miri_unleashed/tls.stderr +++ b/src/test/ui/consts/miri_unleashed/tls.stderr @@ -2,13 +2,13 @@ error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:12:25 | LL | unsafe { let _val = A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A[0])) + | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) error[E0080]: could not evaluate static initializer --> $DIR/tls.rs:19:26 | LL | unsafe { let _val = &A; } - | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A[0])) + | ^ cannot access thread local static (DefId(0:4 ~ tls[317d]::A)) warning: skipping const checks | diff --git a/src/test/ui/consts/offset_from_ub.stderr b/src/test/ui/consts/offset_from_ub.stderr index a89dcefd83..ebe17e8730 100644 --- a/src/test/ui/consts/offset_from_ub.stderr +++ b/src/test/ui/consts/offset_from_ub.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | ptr_offset_from cannot compute offset of pointers into different allocations. - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `DIFFERENT_ALLOC` at $DIR/offset_from_ub.rs:16:27 | ::: $DIR/offset_from_ub.rs:10:1 @@ -28,7 +28,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `NOT_PTR` at $DIR/offset_from_ub.rs:22:14 | ::: $DIR/offset_from_ub.rs:20:1 @@ -46,7 +46,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | exact_div: 1_isize cannot be divided by 2_isize without remainder - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `NOT_MULTIPLE_OF_SIZE` at $DIR/offset_from_ub.rs:30:14 | ::: $DIR/offset_from_ub.rs:25:1 @@ -67,7 +67,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: 0x0 is not a valid pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `OFFSET_FROM_NULL` at $DIR/offset_from_ub.rs:36:14 | ::: $DIR/offset_from_ub.rs:33:1 @@ -86,7 +86,7 @@ LL | unsafe { intrinsics::ptr_offset_from(self, origin) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset_from` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `DIFFERENT_INT` at $DIR/offset_from_ub.rs:43:14 | ::: $DIR/offset_from_ub.rs:39:1 diff --git a/src/test/ui/consts/offset_ub.stderr b/src/test/ui/consts/offset_ub.stderr index 6245354590..e58db1efaf 100644 --- a/src/test/ui/consts/offset_ub.stderr +++ b/src/test/ui/consts/offset_ub.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `BEFORE_START` at $DIR/offset_ub.rs:7:46 | ::: $DIR/offset_ub.rs:7:1 @@ -22,7 +22,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset 2, but is outside bounds of allocN which has size 1 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `AFTER_END` at $DIR/offset_ub.rs:8:43 | ::: $DIR/offset_ub.rs:8:1 @@ -37,7 +37,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset 101, but is outside bounds of allocN which has size 100 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `AFTER_ARRAY` at $DIR/offset_ub.rs:9:45 | ::: $DIR/offset_ub.rs:9:1 @@ -52,7 +52,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `OVERFLOW` at $DIR/offset_ub.rs:11:43 | ::: $DIR/offset_ub.rs:11:1 @@ -67,7 +67,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW` at $DIR/offset_ub.rs:12:44 | ::: $DIR/offset_ub.rs:12:1 @@ -82,7 +82,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `OVERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:13:56 | ::: $DIR/offset_ub.rs:13:1 @@ -97,7 +97,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | overflowing in-bounds pointer arithmetic - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW_ADDRESS_SPACE` at $DIR/offset_ub.rs:14:57 | ::: $DIR/offset_ub.rs:14:1 @@ -112,7 +112,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset 1, but is outside bounds of allocN which has size 0 - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `ZERO_SIZED_ALLOC` at $DIR/offset_ub.rs:16:50 | ::: $DIR/offset_ub.rs:16:1 @@ -127,7 +127,7 @@ LL | unsafe { intrinsics::offset(self, count) as *mut T } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::mut_ptr::::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL + | inside `ptr::mut_ptr::::offset` at $SRC_DIR/core/src/ptr/mut_ptr.rs:LL:COL | inside `DANGLING` at $DIR/offset_ub.rs:17:42 | ::: $DIR/offset_ub.rs:17:1 @@ -142,7 +142,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: 0x0 is not a valid pointer - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `NULL_OFFSET_ZERO` at $DIR/offset_ub.rs:20:50 | ::: $DIR/offset_ub.rs:20:1 @@ -157,7 +157,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | unable to turn bytes into a pointer - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `UNDERFLOW_ABS` at $DIR/offset_ub.rs:23:47 | ::: $DIR/offset_ub.rs:23:1 diff --git a/src/test/ui/consts/projection_qualif.rs b/src/test/ui/consts/projection_qualif.rs index 7db970cf13..5e2584a6e9 100644 --- a/src/test/ui/consts/projection_qualif.rs +++ b/src/test/ui/consts/projection_qualif.rs @@ -9,7 +9,6 @@ const FOO: &u32 = { { let b: *mut u32 = &mut a; //~ ERROR mutable references are not allowed in constants unsafe { *b = 5; } //~ ERROR dereferencing raw pointers in constants - //[stock]~^ contains unimplemented expression } &{a} }; diff --git a/src/test/ui/consts/projection_qualif.stock.stderr b/src/test/ui/consts/projection_qualif.stock.stderr index 212f122864..fad8f011f7 100644 --- a/src/test/ui/consts/projection_qualif.stock.stderr +++ b/src/test/ui/consts/projection_qualif.stock.stderr @@ -13,15 +13,7 @@ LL | unsafe { *b = 5; } = note: see issue #51911 for more information = help: add `#![feature(const_raw_ptr_deref)]` to the crate attributes to enable -error[E0019]: constant contains unimplemented expression type - --> $DIR/projection_qualif.rs:11:18 - | -LL | unsafe { *b = 5; } - | ^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error: aborting due to 2 previous errors -error: aborting due to 3 previous errors - -Some errors have detailed explanations: E0019, E0658, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0658, E0764. +For more information about an error, try `rustc --explain E0658`. diff --git a/src/test/ui/consts/promote-not.rs b/src/test/ui/consts/promote-not.rs new file mode 100644 index 0000000000..8daac75837 --- /dev/null +++ b/src/test/ui/consts/promote-not.rs @@ -0,0 +1,30 @@ +// ignore-tidy-linelength +// Test various things that we do not want to promote. +#![allow(unconditional_panic, const_err)] +#![feature(const_fn, const_fn_union)] + +// We do not promote mutable references. +static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); //~ ERROR temporary value dropped while borrowed + +static mut TEST2: &'static mut [i32] = { + let x = &mut [1,2,3]; //~ ERROR temporary value dropped while borrowed + x +}; + +// We do not promote fn calls in `fn`, including `const fn`. +pub const fn promote_cal(b: bool) -> i32 { + const fn foo() { [()][42] } + + if b { + let _x: &'static () = &foo(); //~ ERROR temporary value dropped while borrowed + } + 13 +} + +// We do not promote union field accesses in `fn. +union U { x: i32, y: i32 } +pub const fn promote_union() { + let _x: &'static i32 = &unsafe { U { x: 0 }.x }; //~ ERROR temporary value dropped while borrowed +} + +fn main() {} diff --git a/src/test/ui/consts/promote-not.stderr b/src/test/ui/consts/promote-not.stderr new file mode 100644 index 0000000000..efe921b601 --- /dev/null +++ b/src/test/ui/consts/promote-not.stderr @@ -0,0 +1,43 @@ +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:7:50 + | +LL | static mut TEST1: Option<&mut [i32]> = Some(&mut [1, 2, 3]); + | ----------^^^^^^^^^- + | | | | + | | | temporary value is freed at the end of this statement + | | creates a temporary which is freed while still in use + | using this value as a static requires that borrow lasts for `'static` + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:10:18 + | +LL | let x = &mut [1,2,3]; + | ^^^^^^^ creates a temporary which is freed while still in use +LL | x + | - using this value as a static requires that borrow lasts for `'static` +LL | }; + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:19:32 + | +LL | let _x: &'static () = &foo(); + | ----------- ^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error[E0716]: temporary value dropped while borrowed + --> $DIR/promote-not.rs:27:29 + | +LL | let _x: &'static i32 = &unsafe { U { x: 0 }.x }; + | ------------ ^^^^^^^^^^^^^^^^^^^^^^^ creates a temporary which is freed while still in use + | | + | type annotation requires that borrow lasts for `'static` +LL | } + | - temporary value is freed at the end of this statement + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0716`. diff --git a/src/test/ui/consts/promotion-mutable-ref.rs b/src/test/ui/consts/promotion-mutable-ref.rs new file mode 100644 index 0000000000..d103c5a9d2 --- /dev/null +++ b/src/test/ui/consts/promotion-mutable-ref.rs @@ -0,0 +1,17 @@ +// run-pass +#![feature(const_mut_refs)] + +static mut TEST: i32 = { + // We must not promote this, as CTFE needs to be able to mutate it later. + let x = &mut [1,2,3]; + x[0] += 1; + x[0] +}; + +// This still works -- it's not done via promotion. +#[allow(unused)] +static mut TEST2: &'static mut [i32] = &mut [0,1,2]; + +fn main() { + assert_eq!(unsafe { TEST }, 2); +} diff --git a/src/test/ui/consts/promotion.rs b/src/test/ui/consts/promotion.rs index 3c5401e421..5f84030a9e 100644 --- a/src/test/ui/consts/promotion.rs +++ b/src/test/ui/consts/promotion.rs @@ -1,4 +1,4 @@ -// run-pass +// check-pass // compile-flags: -O diff --git a/src/test/ui/consts/ptr_comparisons.stderr b/src/test/ui/consts/ptr_comparisons.stderr index 493d9be8f7..63faae275d 100644 --- a/src/test/ui/consts/ptr_comparisons.stderr +++ b/src/test/ui/consts/ptr_comparisons.stderr @@ -5,7 +5,7 @@ LL | unsafe { intrinsics::offset(self, count) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | inbounds test failed: pointer must be in-bounds at offset $TWO_WORDS, but is outside bounds of alloc2 which has size $WORD - | inside `std::ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL + | inside `ptr::const_ptr::::offset` at $SRC_DIR/core/src/ptr/const_ptr.rs:LL:COL | inside `_` at $DIR/ptr_comparisons.rs:62:34 | ::: $DIR/ptr_comparisons.rs:62:1 diff --git a/src/test/ui/consts/recursive-zst-static.default.stderr b/src/test/ui/consts/recursive-zst-static.default.stderr index 9042c6f6be..03f8f5c5a0 100644 --- a/src/test/ui/consts/recursive-zst-static.default.stderr +++ b/src/test/ui/consts/recursive-zst-static.default.stderr @@ -1,20 +1,16 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/recursive-zst-static.rs b/src/test/ui/consts/recursive-zst-static.rs index 29a467c006..4e61634b34 100644 --- a/src/test/ui/consts/recursive-zst-static.rs +++ b/src/test/ui/consts/recursive-zst-static.rs @@ -7,7 +7,7 @@ // can depend on this fact and will thus do unsound things when it is violated. // See https://github.com/rust-lang/rust/issues/71078 for more details. -static FOO: () = FOO; //~ cycle detected when const-evaluating `FOO` +static FOO: () = FOO; //~ cycle detected when const-evaluating + checking `FOO` fn main() { FOO diff --git a/src/test/ui/consts/recursive-zst-static.unleash.stderr b/src/test/ui/consts/recursive-zst-static.unleash.stderr index 9042c6f6be..03f8f5c5a0 100644 --- a/src/test/ui/consts/recursive-zst-static.unleash.stderr +++ b/src/test/ui/consts/recursive-zst-static.unleash.stderr @@ -1,20 +1,16 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... - --> $DIR/recursive-zst-static.rs:10:1 - | -LL | static FOO: () = FOO; - | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-zst-static.rs:10:1 | LL | static FOO: () = FOO; | ^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs index 38f744e99a..d40facf232 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.rs @@ -14,5 +14,5 @@ const fn copy() -> u32 { fn main() { let _: [u32; 2] = [copy(); 2]; let _: [Option; 2] = [no_copy(); 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Option: Copy` is not satisfied } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr index 8219d836a2..48092432bb 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/fn-call-in-non-const.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Option: Copy` is not satisfied --> $DIR/fn-call-in-non-const.rs:16:31 | LL | let _: [Option; 2] = [no_copy(); 2]; - | ^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to previous error diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs index 3b7d7e5b51..d04b0b7e16 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // ignore-compare-mode-nll // compile-flags: -Z borrowck=migrate #![feature(const_in_array_repeat_expressions)] @@ -13,13 +12,13 @@ mod non_constants { fn no_impl_copy_empty_value_multiple_elements() { let x = None; let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } fn no_impl_copy_value_multiple_elements() { let x = Some(Bar); let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr index aad6763f15..476d48fd49 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/migrate-fail.stderr @@ -1,21 +1,21 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/migrate-fail.rs:15:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/migrate-fail.rs:14:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/migrate-fail.rs:21:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/migrate-fail.rs:20:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs index dc1193a2fe..2d5c59d112 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength // ignore-compare-mode-nll #![feature(const_in_array_repeat_expressions, nll)] #![allow(warnings)] @@ -12,13 +11,13 @@ mod non_constants { fn no_impl_copy_empty_value_multiple_elements() { let x = None; let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } fn no_impl_copy_value_multiple_elements() { let x = Some(Bar); let arr: [Option; 2] = [x; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr index fd32484ff9..3aa69996ff 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/nll-fail.stderr @@ -1,21 +1,21 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/nll-fail.rs:14:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/nll-fail.rs:13:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/nll-fail.rs:20:37 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/nll-fail.rs:19:37 | LL | let arr: [Option; 2] = [x; 2]; - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to 2 previous errors diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs index 35484d265b..f8df7aafa6 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![feature(const_in_array_repeat_expressions)] #[derive(Copy, Clone)] @@ -6,5 +5,5 @@ struct Foo(T); fn main() { [Foo(String::new()); 4]; - //~^ ERROR the trait bound `Foo: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Foo: Copy` is not satisfied [E0277] } diff --git a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr index 186909e469..26de67e50f 100644 --- a/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr +++ b/src/test/ui/consts/rfc-2203-const-array-repeat-exprs/trait-error.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `Foo: std::marker::Copy` is not satisfied - --> $DIR/trait-error.rs:8:5 +error[E0277]: the trait bound `Foo: Copy` is not satisfied + --> $DIR/trait-error.rs:7:5 | LL | [Foo(String::new()); 4]; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Foo` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Foo` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to previous error diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000..651462d7ef --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.rs @@ -0,0 +1,22 @@ +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops, const_fn)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_stable(feature = "foo", since = "1.0.0")] + pub const fn unwrap(self) -> T { + //~^ ERROR destructors cannot be evaluated at compile-time + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr new file mode 100644 index 0000000000..a3f513541d --- /dev/null +++ b/src/test/ui/consts/stable-precise-live-drops-in-libcore.stderr @@ -0,0 +1,12 @@ +error[E0493]: destructors cannot be evaluated at compile-time + --> $DIR/stable-precise-live-drops-in-libcore.rs:13:25 + | +LL | pub const fn unwrap(self) -> T { + | ^^^^ constant functions cannot evaluate destructors +... +LL | } + | - value is dropped here + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0493`. diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.rs b/src/test/ui/consts/static_mut_containing_mut_ref2.rs index a6bbe8d6ec..2821d1a015 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.rs +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.rs @@ -6,6 +6,5 @@ static mut STDERR_BUFFER_SPACE: u8 = 0; pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; //~^ ERROR mutable references are not allowed in statics -//[stock]~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr index 57fb27e642..36c280ca5c 100644 --- a/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr +++ b/src/test/ui/consts/static_mut_containing_mut_ref2.stock.stderr @@ -4,15 +4,6 @@ error[E0764]: mutable references are not allowed in statics LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `&mut` is only allowed in `const fn` -error[E0019]: static contains unimplemented expression type - --> $DIR/static_mut_containing_mut_ref2.rs:7:45 - | -LL | pub static mut STDERR_BUFFER: () = unsafe { *(&mut STDERR_BUFFER_SPACE) = 42; }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0019, E0764. -For more information about an error, try `rustc --explain E0019`. +For more information about this error, try `rustc --explain E0764`. diff --git a/src/test/ui/consts/too_generic_eval_ice.stderr b/src/test/ui/consts/too_generic_eval_ice.stderr index d5816fbb8e..ac104ed4a5 100644 --- a/src/test/ui/consts/too_generic_eval_ice.stderr +++ b/src/test/ui/consts/too_generic_eval_ice.stderr @@ -20,7 +20,7 @@ error[E0277]: can't compare `[{integer}; _]` with `[{integer}; 0]` LL | [5; Self::HOST_SIZE] == [6; 0] | ^^ no implementation for `[{integer}; _] == [{integer}; 0]` | - = help: the trait `std::cmp::PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` + = help: the trait `PartialEq<[{integer}; 0]>` is not implemented for `[{integer}; _]` error: aborting due to 3 previous errors diff --git a/src/test/ui/consts/unsizing-cast-non-null.rs b/src/test/ui/consts/unsizing-cast-non-null.rs index 67d9f6baca..af6bc2d85f 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.rs +++ b/src/test/ui/consts/unsizing-cast-non-null.rs @@ -4,7 +4,7 @@ use std::ptr::NonNull; pub const fn dangling_slice() -> NonNull<[T]> { NonNull::<[T; 0]>::dangling() - //~^ ERROR: unsizing casts are only allowed for references right now + //~^ ERROR: unsizing casts to types besides slices } fn main() {} diff --git a/src/test/ui/consts/unsizing-cast-non-null.stderr b/src/test/ui/consts/unsizing-cast-non-null.stderr index 6575355daa..dc08ccd02b 100644 --- a/src/test/ui/consts/unsizing-cast-non-null.stderr +++ b/src/test/ui/consts/unsizing-cast-non-null.stderr @@ -1,4 +1,4 @@ -error[E0723]: unsizing casts are only allowed for references right now +error[E0723]: unsizing casts to types besides slices are not allowed in const fn --> $DIR/unsizing-cast-non-null.rs:6:5 | LL | NonNull::<[T; 0]>::dangling() diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.rs b/src/test/ui/consts/unstable-const-fn-in-libcore.rs index 29d3dc18fa..43951c6854 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.rs +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.rs @@ -6,6 +6,7 @@ #![stable(feature = "core", since = "1.6.0")] #![feature(rustc_const_unstable)] #![feature(staged_api)] +#![feature(const_fn)] enum Opt { Some(T), diff --git a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr index be797cae7c..928605356a 100644 --- a/src/test/ui/consts/unstable-const-fn-in-libcore.stderr +++ b/src/test/ui/consts/unstable-const-fn-in-libcore.stderr @@ -1,11 +1,11 @@ error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants - --> $DIR/unstable-const-fn-in-libcore.rs:23:26 + --> $DIR/unstable-const-fn-in-libcore.rs:24:26 | LL | Opt::None => f(), | ^^^ error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:53 + --> $DIR/unstable-const-fn-in-libcore.rs:19:53 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^ constant functions cannot evaluate destructors @@ -14,7 +14,7 @@ LL | } | - value is dropped here error[E0493]: destructors cannot be evaluated at compile-time - --> $DIR/unstable-const-fn-in-libcore.rs:18:47 + --> $DIR/unstable-const-fn-in-libcore.rs:19:47 | LL | const fn unwrap_or_else T>(self, f: F) -> T { | ^^^^ constant functions cannot evaluate destructors diff --git a/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs new file mode 100644 index 0000000000..619084eaa5 --- /dev/null +++ b/src/test/ui/consts/unstable-precise-live-drops-in-libcore.rs @@ -0,0 +1,23 @@ +// check-pass + +#![stable(feature = "core", since = "1.6.0")] +#![feature(staged_api)] +#![feature(const_precise_live_drops)] + +enum Either { + Left(T), + Right(S), +} + +impl Either { + #[stable(feature = "rust1", since = "1.0.0")] + #[rustc_const_unstable(feature = "foo", issue = "none")] + pub const fn unwrap(self) -> T { + match self { + Self::Left(t) => t, + Self::Right(t) => t, + } + } +} + +fn main() {} diff --git a/src/test/ui/conversion-methods.stderr b/src/test/ui/conversion-methods.stderr index b3621a27ac..4f47e1fd0f 100644 --- a/src/test/ui/conversion-methods.stderr +++ b/src/test/ui/conversion-methods.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let _tis_an_instants_play: String = "'Tis a fond Ambush—"; | ------ ^^^^^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&str` + | | expected struct `String`, found `&str` | | help: try using a conversion method: `"'Tis a fond Ambush—".to_string()` | expected due to this @@ -14,7 +14,7 @@ error[E0308]: mismatched types LL | let _just_to_make_bliss: PathBuf = Path::new("/ern/her/own/surprise"); | ------- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::path::PathBuf`, found `&std::path::Path` + | | expected struct `PathBuf`, found `&Path` | | help: try using a conversion method: `Path::new("/ern/her/own/surprise").to_path_buf()` | expected due to this @@ -24,7 +24,7 @@ error[E0308]: mismatched types LL | let _but_should_the_play: String = 2; // Perhaps surprisingly, we suggest .to_string() here | ------ ^ | | | - | | expected struct `std::string::String`, found integer + | | expected struct `String`, found integer | | help: try using a conversion method: `2.to_string()` | expected due to this @@ -34,11 +34,11 @@ error[E0308]: mismatched types LL | let _prove_piercing_earnest: Vec = &[1, 2, 3]; | ---------- ^^^^^^^^^^ | | | - | | expected struct `std::vec::Vec`, found `&[{integer}; 3]` + | | expected struct `Vec`, found `&[{integer}; 3]` | | help: try using a conversion method: `(&[1, 2, 3]).to_vec()` | expected due to this | - = note: expected struct `std::vec::Vec` + = note: expected struct `Vec` found reference `&[{integer}; 3]` error: aborting due to 4 previous errors diff --git a/src/test/ui/copy-a-resource.stderr b/src/test/ui/copy-a-resource.stderr index 477a383690..36cf57bd3c 100644 --- a/src/test/ui/copy-a-resource.stderr +++ b/src/test/ui/copy-a-resource.stderr @@ -12,12 +12,12 @@ LL | let _y = x.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here | = 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: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/cross/cross-borrow-trait.rs b/src/test/ui/cross/cross-borrow-trait.rs index ce42b696dd..180a75e3df 100644 --- a/src/test/ui/cross/cross-borrow-trait.rs +++ b/src/test/ui/cross/cross-borrow-trait.rs @@ -9,5 +9,5 @@ pub fn main() { let x: Box = Box::new(Foo); let _y: &dyn Trait = x; //~ ERROR E0308 //~| expected reference `&dyn Trait` - //~| found struct `std::boxed::Box` + //~| found struct `Box` } diff --git a/src/test/ui/cross/cross-borrow-trait.stderr b/src/test/ui/cross/cross-borrow-trait.stderr index 618f6595d4..f693a3149b 100644 --- a/src/test/ui/cross/cross-borrow-trait.stderr +++ b/src/test/ui/cross/cross-borrow-trait.stderr @@ -4,12 +4,12 @@ error[E0308]: mismatched types LL | let _y: &dyn Trait = x; | ---------- ^ | | | - | | expected `&dyn Trait`, found struct `std::boxed::Box` + | | expected `&dyn Trait`, found struct `Box` | | help: consider borrowing here: `&x` | expected due to this | = note: expected reference `&dyn Trait` - found struct `std::boxed::Box` + found struct `Box` error: aborting due to previous error diff --git a/src/test/ui/custom_test_frameworks/mismatch.rs b/src/test/ui/custom_test_frameworks/mismatch.rs index e6848e2f3b..ac850552b5 100644 --- a/src/test/ui/custom_test_frameworks/mismatch.rs +++ b/src/test/ui/custom_test_frameworks/mismatch.rs @@ -7,4 +7,4 @@ extern crate example_runner; #[test] fn wrong_kind(){} -//~^ ERROR trait bound `test::TestDescAndFn: example_runner::Testable` is not satisfied +//~^ ERROR trait bound `TestDescAndFn: Testable` is not satisfied diff --git a/src/test/ui/custom_test_frameworks/mismatch.stderr b/src/test/ui/custom_test_frameworks/mismatch.stderr index 420ddbc3de..ea4445deb4 100644 --- a/src/test/ui/custom_test_frameworks/mismatch.stderr +++ b/src/test/ui/custom_test_frameworks/mismatch.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `test::TestDescAndFn: example_runner::Testable` is not satisfied +error[E0277]: the trait bound `TestDescAndFn: Testable` is not satisfied --> $DIR/mismatch.rs:9:1 | LL | fn wrong_kind(){} - | ^^^^^^^^^^^^^^^^^ the trait `example_runner::Testable` is not implemented for `test::TestDescAndFn` + | ^^^^^^^^^^^^^^^^^ the trait `Testable` is not implemented for `TestDescAndFn` | - = note: required for the cast to the object type `dyn example_runner::Testable` + = note: required for the cast to the object type `dyn Testable` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr index 164c474183..3d968aa3ea 100644 --- a/src/test/ui/dep-graph/dep-graph-caller-callee.stderr +++ b/src/test/ui/dep-graph/dep-graph-caller-callee.stderr @@ -4,7 +4,7 @@ error: OK LL | #[rustc_then_this_would_need(typeck)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: no path from `x::x` to `typeck` +error: no path from `x` to `typeck` --> $DIR/dep-graph-caller-callee.rs:31:5 | LL | #[rustc_then_this_would_need(typeck)] diff --git a/src/test/ui/deprecation/deprecation-lint.rs b/src/test/ui/deprecation/deprecation-lint.rs index 1932344fc5..560e296888 100644 --- a/src/test/ui/deprecation/deprecation-lint.rs +++ b/src/test/ui/deprecation/deprecation-lint.rs @@ -314,7 +314,7 @@ mod this_crate { let _ = || { #[deprecated] fn bar() { } - bar(); //~ ERROR use of deprecated function `this_crate::test_fn_closure_body::{{closure}}#0::bar` + bar(); //~ ERROR use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` }; } diff --git a/src/test/ui/deprecation/deprecation-lint.stderr b/src/test/ui/deprecation/deprecation-lint.stderr index 03a2ec7edc..12c76f0f4a 100644 --- a/src/test/ui/deprecation/deprecation-lint.stderr +++ b/src/test/ui/deprecation/deprecation-lint.stderr @@ -298,7 +298,7 @@ error: use of deprecated associated function `this_crate::Trait::trait_deprecate LL | ... ::trait_deprecated_text(&foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: use of deprecated function `this_crate::test_fn_closure_body::{{closure}}#0::bar` +error: use of deprecated function `this_crate::test_fn_closure_body::{closure#0}::bar` --> $DIR/deprecation-lint.rs:317:13 | LL | bar(); diff --git a/src/test/ui/deref-lval.rs b/src/test/ui/deref-lval.rs deleted file mode 100644 index f57872f80e..0000000000 --- a/src/test/ui/deref-lval.rs +++ /dev/null @@ -1,11 +0,0 @@ -// run-pass - -#![feature(box_syntax)] - -use std::cell::Cell; - -pub fn main() { - let x: Box<_> = box Cell::new(5); - x.set(1000); - println!("{}", x.get()); -} diff --git a/src/test/ui/deref-suggestion.stderr b/src/test/ui/deref-suggestion.stderr index 89fd7aae3b..f59f05db9c 100644 --- a/src/test/ui/deref-suggestion.stderr +++ b/src/test/ui/deref-suggestion.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo(s); | ^ | | - | expected struct `std::string::String`, found `&std::string::String` + | expected struct `String`, found `&String` | help: try using a conversion method: `s.to_string()` error[E0308]: mismatched types @@ -22,7 +22,7 @@ error[E0308]: mismatched types LL | foo(&"aaa".to_owned()); | ^^^^^^^^^^^^^^^^^ | | - | expected struct `std::string::String`, found `&std::string::String` + | expected struct `String`, found `&String` | help: consider removing the borrow: `"aaa".to_owned()` error[E0308]: mismatched types @@ -31,7 +31,7 @@ error[E0308]: mismatched types LL | foo(&mut "aaa".to_owned()); | ^^^^^^^^^^^^^^^^^^^^^ | | - | expected struct `std::string::String`, found `&mut std::string::String` + | expected struct `String`, found `&mut String` | help: consider removing the borrow: `"aaa".to_owned()` error[E0308]: mismatched types diff --git a/src/test/ui/derived-errors/issue-31997-1.stderr b/src/test/ui/derived-errors/issue-31997-1.stderr index 229c5c9e80..6d177666ed 100644 --- a/src/test/ui/derived-errors/issue-31997-1.stderr +++ b/src/test/ui/derived-errors/issue-31997-1.stderr @@ -1,4 +1,4 @@ -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/issue-31997-1.rs:20:19 | LL | let mut map = HashMap::new(); diff --git a/src/test/ui/derives/derive-assoc-type-not-impl.stderr b/src/test/ui/derives/derive-assoc-type-not-impl.stderr index e4d6794bbf..92ba4f0704 100644 --- a/src/test/ui/derives/derive-assoc-type-not-impl.stderr +++ b/src/test/ui/derives/derive-assoc-type-not-impl.stderr @@ -5,10 +5,10 @@ LL | struct Bar { | ------------------ | | | method `clone` not found for this - | doesn't satisfy `Bar: std::clone::Clone` + | doesn't satisfy `Bar: Clone` ... LL | struct NotClone; - | ---------------- doesn't satisfy `NotClone: std::clone::Clone` + | ---------------- doesn't satisfy `NotClone: Clone` ... LL | Bar:: { x: 1 }.clone(); | ^^^^^ method not found in `Bar` @@ -18,15 +18,15 @@ LL | Bar:: { x: 1 }.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `NotClone: std::clone::Clone` - which is required by `Bar: std::clone::Clone` + `NotClone: Clone` + which is required by `Bar: Clone` = 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: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr b/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr index b3aa886cd4..e892d3f086 100644 --- a/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr +++ b/src/test/ui/derives/derive-on-trait-item-or-impl-item.stderr @@ -1,10 +1,10 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/derive-on-trait-item-or-impl-item.rs:2:5 | LL | #[derive(Clone)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/derive-on-trait-item-or-impl-item.rs:10:5 | LL | #[derive(Clone)] @@ -12,3 +12,4 @@ LL | #[derive(Clone)] error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr index bbb8776f4f..aa33faf599 100644 --- a/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Clone-enum-struct-variant.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Clone-enum.stderr b/src/test/ui/derives/derives-span-Clone-enum.stderr index 0e410e795e..e3bc2d6a9a 100644 --- a/src/test/ui/derives/derives-span-Clone-enum.stderr +++ b/src/test/ui/derives/derives-span-Clone-enum.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-enum.rs:9:6 | LL | Error - | ^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Clone-struct.stderr b/src/test/ui/derives/derives-span-Clone-struct.stderr index 889128a662..99c0cdecb6 100644 --- a/src/test/ui/derives/derives-span-Clone-struct.stderr +++ b/src/test/ui/derives/derives-span-Clone-struct.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr b/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr index 0024199ca5..e6d734bfcc 100644 --- a/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Clone-tuple-struct.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `Error: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Error: Clone` is not satisfied --> $DIR/derives-span-Clone-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::clone::Clone` is not implemented for `Error` + | ^^^^^ the trait `Clone` is not implemented for `Error` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr index 77779a55b6..64caba8e80 100644 --- a/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Debug-enum-struct-variant.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-enum-struct-variant.rs:9:6 | LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-enum.stderr b/src/test/ui/derives/derives-span-Debug-enum.stderr index f64c33c2bc..88b61f3fcc 100644 --- a/src/test/ui/derives/derives-span-Debug-enum.stderr +++ b/src/test/ui/derives/derives-span-Debug-enum.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-enum.rs:9:6 | LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-struct.stderr b/src/test/ui/derives/derives-span-Debug-struct.stderr index 0013bcf832..558a5796d2 100644 --- a/src/test/ui/derives/derives-span-Debug-struct.stderr +++ b/src/test/ui/derives/derives-span-Debug-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-struct.rs:8:5 | LL | x: Error | ^^^^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr b/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr index 7e0039e8a7..73a88a653f 100644 --- a/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Debug-tuple-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: `Error` doesn't implement `std::fmt::Debug` +error[E0277]: `Error` doesn't implement `Debug` --> $DIR/derives-span-Debug-tuple-struct.rs:8:5 | LL | Error | ^^^^^ `Error` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Error` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&Error` - = note: required for the cast to the object type `dyn std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Error` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&Error` + = note: required for the cast to the object type `dyn Debug` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/derives/derives-span-Default-struct.stderr b/src/test/ui/derives/derives-span-Default-struct.stderr index 492847fc02..d2a5280ac6 100644 --- a/src/test/ui/derives/derives-span-Default-struct.stderr +++ b/src/test/ui/derives/derives-span-Default-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::default::Default` is not satisfied +error[E0277]: the trait bound `Error: Default` is not satisfied --> $DIR/derives-span-Default-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::default::Default` is not implemented for `Error` + | ^^^^^^^^ the trait `Default` is not implemented for `Error` | = note: required by `std::default::Default::default` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Default-tuple-struct.stderr b/src/test/ui/derives/derives-span-Default-tuple-struct.stderr index fa7b27e770..96ff7adc72 100644 --- a/src/test/ui/derives/derives-span-Default-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Default-tuple-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::default::Default` is not satisfied +error[E0277]: the trait bound `Error: Default` is not satisfied --> $DIR/derives-span-Default-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::default::Default` is not implemented for `Error` + | ^^^^^ the trait `Default` is not implemented for `Error` | = note: required by `std::default::Default::default` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr index 698eb8375e..4ad7b94e41 100644 --- a/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Eq-enum-struct-variant.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-enum.stderr b/src/test/ui/derives/derives-span-Eq-enum.stderr index 7009fcf439..8ee7274933 100644 --- a/src/test/ui/derives/derives-span-Eq-enum.stderr +++ b/src/test/ui/derives/derives-span-Eq-enum.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-enum.rs:9:6 | LL | Error - | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-struct.stderr b/src/test/ui/derives/derives-span-Eq-struct.stderr index 7ee0bc59ee..1b751365a3 100644 --- a/src/test/ui/derives/derives-span-Eq-struct.stderr +++ b/src/test/ui/derives/derives-span-Eq-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr b/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr index a23b2fbd1c..44b1d2cc02 100644 --- a/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Eq-tuple-struct.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `Error: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Error: Eq` is not satisfied --> $DIR/derives-span-Eq-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Error` + | ^^^^^ the trait `Eq` is not implemented for `Error` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr index 3f41918493..9a03153797 100644 --- a/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum-struct-variant.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Hash-enum.stderr b/src/test/ui/derives/derives-span-Hash-enum.stderr index 7f64070ddb..08ddc66dd0 100644 --- a/src/test/ui/derives/derives-span-Hash-enum.stderr +++ b/src/test/ui/derives/derives-span-Hash-enum.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-enum.rs:8:6 | LL | Error - | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Hash-struct.stderr b/src/test/ui/derives/derives-span-Hash-struct.stderr index 4082c6cbd3..a2be46dc77 100644 --- a/src/test/ui/derives/derives-span-Hash-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr index 7cac216bc1..30cc6dc27a 100644 --- a/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Hash-tuple-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Error: Hash` is not satisfied --> $DIR/derives-span-Hash-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::hash::Hash` is not implemented for `Error` + | ^^^^^ the trait `Hash` is not implemented for `Error` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr index d0286ad17e..b0b2321753 100644 --- a/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-Ord-enum-struct-variant.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-enum-struct-variant.rs:9:6 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Ord-enum.stderr b/src/test/ui/derives/derives-span-Ord-enum.stderr index aabbd0a1d1..bc95769294 100644 --- a/src/test/ui/derives/derives-span-Ord-enum.stderr +++ b/src/test/ui/derives/derives-span-Ord-enum.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-enum.rs:9:6 | LL | Error - | ^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Ord-struct.stderr b/src/test/ui/derives/derives-span-Ord-struct.stderr index eaac3dafd0..5f324c131c 100644 --- a/src/test/ui/derives/derives-span-Ord-struct.stderr +++ b/src/test/ui/derives/derives-span-Ord-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-struct.rs:8:5 | LL | x: Error - | ^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr b/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr index 0ae36bcb8b..1c277e34ff 100644 --- a/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-Ord-tuple-struct.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Error: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `Error: Ord` is not satisfied --> $DIR/derives-span-Ord-tuple-struct.rs:8:5 | LL | Error - | ^^^^^ the trait `std::cmp::Ord` is not implemented for `Error` + | ^^^^^ the trait `Ord` is not implemented for `Error` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr b/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr index 0be75972e8..0736e71460 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-enum-struct-variant.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-enum.stderr b/src/test/ui/derives/derives-span-PartialOrd-enum.stderr index 64290023c6..d88321b979 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-enum.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-enum.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-struct.stderr b/src/test/ui/derives/derives-span-PartialOrd-struct.stderr index dcd81589e9..3023517752 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-struct.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | x: Error | ^^^^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr b/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr index 8dbf103d2d..3abf1ded8d 100644 --- a/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr +++ b/src/test/ui/derives/derives-span-PartialOrd-tuple-struct.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Error` with `Error` LL | Error | ^^^^^ no implementation for `Error < Error` and `Error > Error` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Error` + = help: the trait `PartialOrd` is not implemented for `Error` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/derives/deriving-copyclone.stderr b/src/test/ui/derives/deriving-copyclone.stderr index 5fa2710cba..4919bac526 100644 --- a/src/test/ui/derives/deriving-copyclone.stderr +++ b/src/test/ui/derives/deriving-copyclone.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `C: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `C: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:31:13 | LL | fn is_copy(_: T) {} @@ -7,12 +7,12 @@ LL | fn is_copy(_: T) {} LL | is_copy(B { a: 1, b: C }); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Copy` + | expected an implementor of trait `Copy` | help: consider borrowing here: `&B { a: 1, b: C }` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `B` + = note: required because of the requirements on the impl of `Copy` for `B` -error[E0277]: the trait bound `C: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `C: Clone` is not satisfied --> $DIR/deriving-copyclone.rs:32:14 | LL | fn is_clone(_: T) {} @@ -21,12 +21,12 @@ LL | fn is_clone(_: T) {} LL | is_clone(B { a: 1, b: C }); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::clone::Clone` + | expected an implementor of trait `Clone` | help: consider borrowing here: `&B { a: 1, b: C }` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `B` + = note: required because of the requirements on the impl of `Clone` for `B` -error[E0277]: the trait bound `D: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `D: Copy` is not satisfied --> $DIR/deriving-copyclone.rs:35:13 | LL | fn is_copy(_: T) {} @@ -35,10 +35,10 @@ LL | fn is_copy(_: T) {} LL | is_copy(B { a: 1, b: D }); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Copy` + | expected an implementor of trait `Copy` | help: consider borrowing here: `&B { a: 1, b: D }` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `B` + = note: required because of the requirements on the impl of `Copy` for `B` error: aborting due to 3 previous errors diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.rs b/src/test/ui/derives/deriving-no-inner-impl-error-message.rs index d3ac5d2fe2..39e41a59ef 100644 --- a/src/test/ui/derives/deriving-no-inner-impl-error-message.rs +++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.rs @@ -8,7 +8,7 @@ struct E { #[derive(Clone)] struct C { x: NoCloneOrEq - //~^ ERROR `NoCloneOrEq: std::clone::Clone` is not satisfied + //~^ ERROR `NoCloneOrEq: Clone` is not satisfied } diff --git a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr index d4995c1d50..1842a88bb2 100644 --- a/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr +++ b/src/test/ui/derives/deriving-no-inner-impl-error-message.stderr @@ -16,13 +16,13 @@ LL | x: NoCloneOrEq = note: an implementation of `std::cmp::PartialEq` might be missing for `NoCloneOrEq` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `NoCloneOrEq: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NoCloneOrEq: Clone` is not satisfied --> $DIR/deriving-no-inner-impl-error-message.rs:10:5 | LL | x: NoCloneOrEq - | ^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `NoCloneOrEq` + | ^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `NoCloneOrEq` | - = note: required by `std::clone::Clone::clone` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 3 previous errors diff --git a/src/test/ui/derives/deriving-non-type.stderr b/src/test/ui/derives/deriving-non-type.stderr index 563e76dc60..8c9daf4d4b 100644 --- a/src/test/ui/derives/deriving-non-type.stderr +++ b/src/test/ui/derives/deriving-non-type.stderr @@ -1,52 +1,52 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:5:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:8:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:11:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:14:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:17:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:20:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:23:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:26:1 | LL | #[derive(PartialEq)] | ^^^^^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/deriving-non-type.rs:29:1 | LL | #[derive(PartialEq)] @@ -54,3 +54,4 @@ LL | #[derive(PartialEq)] error: aborting due to 9 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/dest-prop/skeptic-miscompile.rs b/src/test/ui/dest-prop/skeptic-miscompile.rs new file mode 100644 index 0000000000..c27a1f0453 --- /dev/null +++ b/src/test/ui/dest-prop/skeptic-miscompile.rs @@ -0,0 +1,24 @@ +// run-pass + +// compile-flags: -Zmir-opt-level=2 + +trait IterExt: Iterator { + fn fold_ex(mut self, init: B, mut f: F) -> B + where + Self: Sized, + F: FnMut(B, Self::Item) -> B, + { + let mut accum = init; + while let Some(x) = self.next() { + accum = f(accum, x); + } + accum + } +} + +impl IterExt for T {} + +fn main() { + let test = &["\n"]; + test.iter().fold_ex(String::new(), |_, b| b.to_string()); +} diff --git a/src/test/ui/destructure-trait-ref.rs b/src/test/ui/destructure-trait-ref.rs index 34e7cad935..fdc9bbab73 100644 --- a/src/test/ui/destructure-trait-ref.rs +++ b/src/test/ui/destructure-trait-ref.rs @@ -26,7 +26,7 @@ fn main() { 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; - //~^ ERROR type `std::boxed::Box` cannot be dereferenced + //~^ ERROR type `Box` cannot be dereferenced // n > m let &&x = &1isize as &dyn T; @@ -40,5 +40,5 @@ fn main() { let box box x = box 1isize as Box; //~^ ERROR mismatched types //~| expected trait object `dyn T` - //~| found struct `std::boxed::Box<_>` + //~| found struct `Box<_>` } diff --git a/src/test/ui/destructure-trait-ref.stderr b/src/test/ui/destructure-trait-ref.stderr index 1382cf643a..fb43ca760b 100644 --- a/src/test/ui/destructure-trait-ref.stderr +++ b/src/test/ui/destructure-trait-ref.stderr @@ -10,11 +10,11 @@ error[E0033]: type `&dyn T` cannot be dereferenced LL | let &&x = &(&1isize as &dyn T); | ^^ type `&dyn T` cannot be dereferenced -error[E0033]: type `std::boxed::Box` cannot be dereferenced +error[E0033]: type `Box` cannot be dereferenced --> $DIR/destructure-trait-ref.rs:28:9 | LL | let box x = box 1isize as Box; - | ^^^^^ type `std::boxed::Box` cannot be dereferenced + | ^^^^^ type `Box` cannot be dereferenced error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:32:10 @@ -44,12 +44,12 @@ error[E0308]: mismatched types --> $DIR/destructure-trait-ref.rs:40:13 | LL | let box box x = box 1isize as Box; - | ^^^^^ ------------------------ this expression has type `std::boxed::Box` + | ^^^^^ ------------------------ this expression has type `Box` | | - | expected trait object `dyn T`, found struct `std::boxed::Box` + | expected trait object `dyn T`, found struct `Box` | = note: expected trait object `dyn T` - found struct `std::boxed::Box<_>` + found struct `Box<_>` error: aborting due to 6 previous errors diff --git a/src/test/ui/did_you_mean/bad-assoc-ty.stderr b/src/test/ui/did_you_mean/bad-assoc-ty.stderr index c409ea9c65..4835d9ab10 100644 --- a/src/test/ui/did_you_mean/bad-assoc-ty.stderr +++ b/src/test/ui/did_you_mean/bad-assoc-ty.stderr @@ -110,13 +110,13 @@ error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:27:10 | LL | type G = dyn 'static + (Send)::AssocTy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::marker::Send + 'static) as Trait>::AssocTy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Send + 'static) as Trait>::AssocTy` error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:33:10 | LL | type H = Fn(u8) -> (u8)::Output; - | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn std::ops::Fn(u8) -> u8 + 'static) as Trait>::Output` + | ^^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `<(dyn Fn(u8) -> u8 + 'static) as Trait>::Output` error[E0223]: ambiguous associated type --> $DIR/bad-assoc-ty.rs:37:19 diff --git a/src/test/ui/did_you_mean/issue-40396.rs b/src/test/ui/did_you_mean/issue-40396.rs index e4e94bb949..5497ba2e11 100644 --- a/src/test/ui/did_you_mean/issue-40396.rs +++ b/src/test/ui/did_you_mean/issue-40396.rs @@ -1,8 +1,29 @@ fn main() { (0..13).collect>(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead Vec::new(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead (0..13).collect(); //~^ ERROR comparison operators cannot be chained + //~| HELP use `::<...>` instead + let x = std::collections::HashMap::new(); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 42; //~ ERROR mismatched types + let x = { + std::collections::HashMap::new() //~ ERROR expected one of + //~^ HELP use `::<...>` instead + }; + let x: () = 42; //~ ERROR mismatched types + let x = { + std::collections::HashMap::new(); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 42; //~ ERROR mismatched types + }; + { + std::collections::HashMap::new(1, 2); //~ ERROR expected one of + //~^ HELP use `::<...>` instead + let x: () = 32; //~ ERROR mismatched types + }; } diff --git a/src/test/ui/did_you_mean/issue-40396.stderr b/src/test/ui/did_you_mean/issue-40396.stderr index 10972697f9..184bcf0c74 100644 --- a/src/test/ui/did_you_mean/issue-40396.stderr +++ b/src/test/ui/did_you_mean/issue-40396.stderr @@ -10,7 +10,7 @@ LL | (0..13).collect::>(); | ^^ error: comparison operators cannot be chained - --> $DIR/issue-40396.rs:4:8 + --> $DIR/issue-40396.rs:5:8 | LL | Vec::new(); | ^ ^ @@ -21,7 +21,7 @@ LL | Vec::::new(); | ^^ error: comparison operators cannot be chained - --> $DIR/issue-40396.rs:6:20 + --> $DIR/issue-40396.rs:8:20 | LL | (0..13).collect(); | ^ ^ @@ -31,5 +31,82 @@ help: use `::<...>` instead of `<...>` to specify type arguments LL | (0..13).collect::(); | ^^ -error: aborting due to 3 previous errors +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, or an operator, found `,` + --> $DIR/issue-40396.rs:11:43 + | +LL | let x = std::collections::HashMap::new(); + | ^ expected one of 7 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | let x = std::collections::HashMap::::new(); + | ^^ +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:15:39 + | +LL | std::collections::HashMap::new() + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new() + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:20:39 + | +LL | std::collections::HashMap::new(); + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new(); + | ^^ + +error: expected one of `!`, `.`, `::`, `;`, `?`, `{`, `}`, or an operator, found `,` + --> $DIR/issue-40396.rs:25:39 + | +LL | std::collections::HashMap::new(1, 2); + | ^ expected one of 8 possible tokens + | +help: use `::<...>` instead of `<...>` to specify type arguments + | +LL | std::collections::HashMap::::new(1, 2); + | ^^ + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:13:17 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:18:17 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:22:21 + | +LL | let x: () = 42; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error[E0308]: mismatched types + --> $DIR/issue-40396.rs:27:21 + | +LL | let x: () = 32; + | -- ^^ expected `()`, found integer + | | + | expected due to this + +error: aborting due to 11 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr index 143d7f695c..dbd9dc1bc4 100644 --- a/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr +++ b/src/test/ui/did_you_mean/issue-42599_available_fields_note.stderr @@ -1,24 +1,24 @@ -error[E0560]: struct `submodule::Demo` has no field named `inocently_mispellable` +error[E0560]: struct `Demo` has no field named `inocently_mispellable` --> $DIR/issue-42599_available_fields_note.rs:16:39 | LL | Self { secret_integer: 2, inocently_mispellable: () } | ^^^^^^^^^^^^^^^^^^^^^ help: a field with a similar name exists: `innocently_misspellable` -error[E0560]: struct `submodule::Demo` has no field named `egregiously_nonexistent_field` +error[E0560]: struct `Demo` has no field named `egregiously_nonexistent_field` --> $DIR/issue-42599_available_fields_note.rs:21:39 | LL | Self { secret_integer: 3, egregiously_nonexistent_field: () } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `submodule::Demo` does not have this field + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Demo` does not have this field | = note: available fields are: `favorite_integer`, `secret_integer`, `innocently_misspellable`, `another_field`, `yet_another_field` ... and 2 others -error[E0609]: no field `inocently_mispellable` on type `submodule::Demo` +error[E0609]: no field `inocently_mispellable` on type `Demo` --> $DIR/issue-42599_available_fields_note.rs:32:41 | LL | let innocent_field_misaccess = demo.inocently_mispellable; | ^^^^^^^^^^^^^^^^^^^^^ help: a field with a similar name exists: `innocently_misspellable` -error[E0609]: no field `egregiously_nonexistent_field` on type `submodule::Demo` +error[E0609]: no field `egregiously_nonexistent_field` on type `Demo` --> $DIR/issue-42599_available_fields_note.rs:35:42 | LL | let egregious_field_misaccess = demo.egregiously_nonexistent_field; diff --git a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr index f194b335fd..0ccccb53aa 100644 --- a/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr +++ b/src/test/ui/did_you_mean/issue-49746-unicode-confusable-in-float-literal-expt.stderr @@ -21,7 +21,7 @@ error[E0277]: cannot subtract `{integer}` from `{float}` LL | const UNIVERSAL_GRAVITATIONAL_CONSTANT: f64 = 6.674e−11; // m³⋅kg⁻¹⋅s⁻² | ^ no implementation for `{float} - {integer}` | - = help: the trait `std::ops::Sub<{integer}>` is not implemented for `{float}` + = help: the trait `Sub<{integer}>` is not implemented for `{float}` error: aborting due to 3 previous errors diff --git a/src/test/ui/did_you_mean/recursion_limit.stderr b/src/test/ui/did_you_mean/recursion_limit.stderr index c9a6d42b5c..c5b42416ea 100644 --- a/src/test/ui/did_you_mean/recursion_limit.stderr +++ b/src/test/ui/did_you_mean/recursion_limit.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `K: std::marker::Send` +error[E0275]: overflow evaluating the requirement `K: Send` --> $DIR/recursion_limit.rs:34:5 | LL | fn is_send() { } diff --git a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr index 333754891c..a8b160bbb2 100644 --- a/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr +++ b/src/test/ui/did_you_mean/trait-object-reference-without-parens-suggestion.stderr @@ -10,11 +10,11 @@ error[E0178]: expected a path on the left-hand side of `+`, not `&'static Copy` LL | let _: &'static Copy + 'static; | ^^^^^^^^^^^^^^^^^^^^^^^ help: try adding parentheses: `&'static (Copy + 'static)` -error[E0038]: the trait `std::marker::Copy` cannot be made into an object +error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/trait-object-reference-without-parens-suggestion.rs:4:12 | LL | let _: &Copy + 'static; - | ^^^^^ the trait `std::marker::Copy` cannot be made into an object + | ^^^^^ the trait `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr index 8c64149a0f..cda81d1366 100644 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr +++ b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-let.stderr @@ -5,7 +5,7 @@ LL | let X { x: y } = x; | - ^ cannot move out of here | | | data moved here - | move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `y` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr index afc5170e1b..70cdd6446c 100644 --- a/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr +++ b/src/test/ui/disallowed-deconstructing/disallowed-deconstructing-destructing-struct-match.stderr @@ -8,7 +8,7 @@ LL | X { x: y } => println!("contents: {}", y) | - | | | data moved here - | move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `y` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/disambiguate-identical-names.rs b/src/test/ui/disambiguate-identical-names.rs new file mode 100644 index 0000000000..708d2cd76a --- /dev/null +++ b/src/test/ui/disambiguate-identical-names.rs @@ -0,0 +1,15 @@ +pub mod submod { + // Create ambiguity with the std::vec::Vec item: + pub struct Vec; +} + +fn test(_v: &Vec>) { +} + +fn main() { + let v = std::collections::HashMap::new(); + v.insert(3u8, 1u8); + + test(&v); + //~^ ERROR mismatched types +} diff --git a/src/test/ui/disambiguate-identical-names.stderr b/src/test/ui/disambiguate-identical-names.stderr new file mode 100644 index 0000000000..0c6bd9379f --- /dev/null +++ b/src/test/ui/disambiguate-identical-names.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/disambiguate-identical-names.rs:13:10 + | +LL | test(&v); + | ^^ expected struct `std::vec::Vec`, found struct `HashMap` + | + = note: expected reference `&std::vec::Vec>` + found reference `&HashMap` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr index c10232107e..5d53405579 100644 --- a/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr +++ b/src/test/ui/dropck/dropck-eyepatch-extern-crate.stderr @@ -8,7 +8,7 @@ LL | } | - | | | `c_shortest` dropped here while still borrowed - | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `other::Dt` + | borrow might be used here, when `dt` is dropped and runs the `Drop` code for type `Dt` | = note: values in a scope are dropped in the opposite order they are defined @@ -22,7 +22,7 @@ LL | } | - | | | `c_shortest` dropped here while still borrowed - | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `other::Pt` + | borrow might be used here, when `pt` is dropped and runs the `Drop` code for type `Pt` | = note: values in a scope are dropped in the opposite order they are defined diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs index e2e600b17f..558b4342da 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.rs @@ -29,8 +29,8 @@ enum Wrapper { } fn main() { - let w = //~ ERROR overflow while adding drop-check rules for std::option + let w = //~ ERROR overflow while adding drop-check rules for Option Some(Wrapper::Simple::); - //~^ ERROR overflow while adding drop-check rules for std::option::Option + //~^ ERROR overflow while adding drop-check rules for Option //~| ERROR overflow while adding drop-check rules for Wrapper } diff --git a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr index 1c810df242..b24e1d1bf7 100644 --- a/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr +++ b/src/test/ui/dropck/dropck_no_diverge_on_nonregular_3.stderr @@ -1,4 +1,4 @@ -error[E0320]: overflow while adding drop-check rules for std::option::Option> +error[E0320]: overflow while adding drop-check rules for Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:32:9 | LL | let w = @@ -6,7 +6,7 @@ LL | let w = | = note: overflowed on FingerTree>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> -error[E0320]: overflow while adding drop-check rules for std::option::Option> +error[E0320]: overflow while adding drop-check rules for Option> --> $DIR/dropck_no_diverge_on_nonregular_3.rs:33:9 | LL | Some(Wrapper::Simple::); diff --git a/src/test/ui/dst/dst-bad-assign-2.stderr b/src/test/ui/dst/dst-bad-assign-2.stderr index a5374aedab..6c9e2971c6 100644 --- a/src/test/ui/dst/dst-bad-assign-2.stderr +++ b/src/test/ui/dst/dst-bad-assign-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `dyn ToBar` cannot be known at compila LL | f5.ptr = *z; | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` + = help: the trait `Sized` is not implemented for `dyn ToBar` = note: the left-hand-side of an assignment must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/dst/dst-bad-assign-3.stderr b/src/test/ui/dst/dst-bad-assign-3.stderr index f8d9300f11..04e4623353 100644 --- a/src/test/ui/dst/dst-bad-assign-3.stderr +++ b/src/test/ui/dst/dst-bad-assign-3.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `dyn ToBar` cannot be known at compila LL | f5.2 = Bar1 {f: 36}; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` + = help: the trait `Sized` is not implemented for `dyn ToBar` = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-assign.stderr b/src/test/ui/dst/dst-bad-assign.stderr index 8e3eeefb9e..f87a34c6d3 100644 --- a/src/test/ui/dst/dst-bad-assign.stderr +++ b/src/test/ui/dst/dst-bad-assign.stderr @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `dyn ToBar` cannot be known at compila LL | f5.ptr = Bar1 {f: 36}; | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn ToBar` + = help: the trait `Sized` is not implemented for `dyn ToBar` = note: the left-hand-side of an assignment must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/dst/dst-bad-deep-2.stderr b/src/test/ui/dst/dst-bad-deep-2.stderr index d9d6ca3292..b228508141 100644 --- a/src/test/ui/dst/dst-bad-deep-2.stderr +++ b/src/test/ui/dst/dst-bad-deep-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &(([isize],),) = &(*g,); | ^^^^^ doesn't have a size known at compile-time | - = help: within `(([isize],),)`, the trait `std::marker::Sized` is not implemented for `[isize]` + = help: within `(([isize],),)`, the trait `Sized` is not implemented for `[isize]` = note: required because it appears within the type `([isize],)` = note: required because it appears within the type `(([isize],),)` = note: tuples must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-bad-deep.stderr b/src/test/ui/dst/dst-bad-deep.stderr index 1304f04f82..ea6b239047 100644 --- a/src/test/ui/dst/dst-bad-deep.stderr +++ b/src/test/ui/dst/dst-bad-deep.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[isize]` cannot be known at compilati LL | let h: &Fat> = &Fat { ptr: *g }; | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Fat>`, the trait `std::marker::Sized` is not implemented for `[isize]` + = help: within `Fat>`, the trait `Sized` is not implemented for `[isize]` = note: required because it appears within the type `Fat<[isize]>` = note: required because it appears within the type `Fat>` = note: structs must have a statically known size to be initialized diff --git a/src/test/ui/dst/dst-index.stderr b/src/test/ui/dst/dst-index.stderr index 6cdb0e76e9..6bcd70cbaa 100644 --- a/src/test/ui/dst/dst-index.stderr +++ b/src/test/ui/dst/dst-index.stderr @@ -4,7 +4,7 @@ error[E0161]: cannot move a value of type str: the size of str cannot be statica LL | S[0]; | ^^^^ -error[E0161]: cannot move a value of type dyn std::fmt::Debug: the size of dyn std::fmt::Debug cannot be statically determined +error[E0161]: cannot move a value of type dyn Debug: the size of dyn Debug cannot be statically determined --> $DIR/dst-index.rs:34:5 | LL | T[0]; @@ -20,7 +20,7 @@ error[E0507]: cannot move out of index of `T` --> $DIR/dst-index.rs:34:5 | LL | T[0]; - | ^^^^ move occurs because value has type `dyn std::fmt::Debug`, which does not implement the `Copy` trait + | ^^^^ move occurs because value has type `dyn Debug`, which does not implement the `Copy` trait error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-object-from-unsized-type.stderr b/src/test/ui/dst/dst-object-from-unsized-type.stderr index da8ead885c..49940112a9 100644 --- a/src/test/ui/dst/dst-object-from-unsized-type.stderr +++ b/src/test/ui/dst/dst-object-from-unsized-type.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/dst-object-from-unsized-type.rs:8:23 | LL | fn test1(t: &T) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let u: &dyn Foo = t; | ^ doesn't have a size known at compile-time | @@ -12,7 +12,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/dst-object-from-unsized-type.rs:13:23 | LL | fn test2(t: &T) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let v: &dyn Foo = t as &dyn Foo; | ^ doesn't have a size known at compile-time | @@ -24,7 +24,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let _: &[&dyn Foo] = &["hi"]; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `[u8]` cannot be known at compilation time @@ -33,7 +33,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | let _: &dyn Foo = x as &dyn Foo; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: required for the cast to the object type `dyn Foo` error: aborting due to 4 previous errors diff --git a/src/test/ui/dst/dst-sized-trait-param.stderr b/src/test/ui/dst/dst-sized-trait-param.stderr index 7e90e9ce17..481c01a75e 100644 --- a/src/test/ui/dst/dst-sized-trait-param.stderr +++ b/src/test/ui/dst/dst-sized-trait-param.stderr @@ -7,7 +7,7 @@ LL | LL | impl Foo<[isize]> for usize { } | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[isize]` + = help: the trait `Sized` is not implemented for `[isize]` help: consider relaxing the implicit `Sized` restriction | LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized @@ -22,7 +22,7 @@ LL | trait Foo : Sized { fn take(self, x: &T) { } } // Note: T is sized LL | impl Foo for [usize] { } | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[usize]` + = help: the trait `Sized` is not implemented for `[usize]` error: aborting due to 2 previous errors diff --git a/src/test/ui/dyn-trait-compatibility.rs b/src/test/ui/dyn-trait-compatibility.rs index 2a1cea6c34..d2b02cc2af 100644 --- a/src/test/ui/dyn-trait-compatibility.rs +++ b/src/test/ui/dyn-trait-compatibility.rs @@ -1,7 +1,7 @@ type A0 = dyn; //~^ ERROR cannot find type `dyn` in this scope type A1 = dyn::dyn; -//~^ ERROR use of undeclared type or module `dyn` +//~^ ERROR use of undeclared crate or module `dyn` type A2 = dyn; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope @@ -9,6 +9,6 @@ type A2 = dyn; type A3 = dyn<::dyn>; //~^ ERROR cannot find type `dyn` in this scope //~| ERROR cannot find type `dyn` in this scope -//~| ERROR use of undeclared type or module `dyn` +//~| ERROR use of undeclared crate or module `dyn` fn main() {} diff --git a/src/test/ui/dyn-trait-compatibility.stderr b/src/test/ui/dyn-trait-compatibility.stderr index 8fe8ceb4d0..9218ae9d5d 100644 --- a/src/test/ui/dyn-trait-compatibility.stderr +++ b/src/test/ui/dyn-trait-compatibility.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:3:11 | LL | type A1 = dyn::dyn; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` -error[E0433]: failed to resolve: use of undeclared type or module `dyn` +error[E0433]: failed to resolve: use of undeclared crate or module `dyn` --> $DIR/dyn-trait-compatibility.rs:9:23 | LL | type A3 = dyn<::dyn>; - | ^^^ use of undeclared type or module `dyn` + | ^^^ use of undeclared crate or module `dyn` error[E0412]: cannot find type `dyn` in this scope --> $DIR/dyn-trait-compatibility.rs:1:11 diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs new file mode 100644 index 0000000000..26b923f431 --- /dev/null +++ b/src/test/ui/dynamically-sized-types/dst-tuple-no-reorder.rs @@ -0,0 +1,26 @@ +// run-pass + +#![feature(unsized_tuple_coercion)] + +// Ensure that unsizable fields that might be accessed don't get reordered + +fn nonzero_size() { + let sized: (u8, [u32; 2]) = (123, [456, 789]); + let unsize: &(u8, [u32]) = &sized; + assert_eq!(unsize.0, 123); + assert_eq!(unsize.1.len(), 2); + assert_eq!(unsize.1[0], 456); + assert_eq!(unsize.1[1], 789); +} + +fn zst() { + let sized: (u8, [u32; 0]) = (123, []); + let unsize: &(u8, [u32]) = &sized; + assert_eq!(unsize.0, 123); + assert_eq!(unsize.1.len(), 0); +} + +pub fn main() { + nonzero_size(); + zst(); +} diff --git a/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs new file mode 100644 index 0000000000..b0cefe7703 --- /dev/null +++ b/src/test/ui/dynamically-sized-types/dst-tuple-zst-offsets.rs @@ -0,0 +1,22 @@ +// run-pass + +#![feature(unsized_tuple_coercion)] + +// Check that we do not change the offsets of ZST fields when unsizing + +fn scalar_layout() { + let sized: &(u8, [(); 13]) = &(123, [(); 13]); + let unsize: &(u8, [()]) = sized; + assert_eq!(sized.1.as_ptr(), unsize.1.as_ptr()); +} + +fn scalarpair_layout() { + let sized: &(u8, u16, [(); 13]) = &(123, 456, [(); 13]); + let unsize: &(u8, u16, [()]) = sized; + assert_eq!(sized.2.as_ptr(), unsize.2.as_ptr()); +} + +pub fn main() { + scalar_layout(); + scalarpair_layout(); +} diff --git a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr index 52e58aa4c6..0dc5432d28 100644 --- a/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr +++ b/src/test/ui/enum-discriminant/issue-70453-generics-in-discr-ice.stderr @@ -12,7 +12,7 @@ error[E0392]: parameter `T` is never used LL | enum MyWeirdOption { | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs index 5a528379b0..cdc1db4c0b 100644 --- a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.rs @@ -1,5 +1,4 @@ // run-pass - #![feature(arbitrary_enum_discriminant, core_intrinsics)] extern crate core; @@ -9,6 +8,8 @@ use core::intrinsics::discriminant_value; enum MyWeirdOption { None = 0, Some(T) = core::mem::size_of::<*mut T>(), + //~^ WARN cannot use constants which depend on generic parameters in types + //~| WARN this was previously accepted by the compiler but is being phased out } fn main() { diff --git a/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr new file mode 100644 index 0000000000..906927e705 --- /dev/null +++ b/src/test/ui/enum-discriminant/issue-70453-polymorphic-ctfe.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-70453-polymorphic-ctfe.rs:10:15 + | +LL | Some(T) = core::mem::size_of::<*mut T>(), + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` 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 #76200 + +warning: 1 warning emitted + diff --git a/src/test/ui/error-codes/E0004-2.stderr b/src/test/ui/error-codes/E0004-2.stderr index bb155aaf4b..7b3deb1579 100644 --- a/src/test/ui/error-codes/E0004-2.stderr +++ b/src/test/ui/error-codes/E0004-2.stderr @@ -13,7 +13,7 @@ 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 `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0005.stderr b/src/test/ui/error-codes/E0005.stderr index e15189413b..b9f2702e88 100644 --- a/src/test/ui/error-codes/E0005.stderr +++ b/src/test/ui/error-codes/E0005.stderr @@ -11,7 +11,7 @@ LL | None, | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` help: you might want to use `if let` to ignore the variant that isn't matched | LL | if let Some(y) = x { /* */ } diff --git a/src/test/ui/error-codes/E0007.stderr b/src/test/ui/error-codes/E0007.stderr index 31af917172..89c1051619 100644 --- a/src/test/ui/error-codes/E0007.stderr +++ b/src/test/ui/error-codes/E0007.stderr @@ -8,7 +8,7 @@ error[E0382]: use of moved value --> $DIR/E0007.rs:6:26 | LL | let x = Some("s".to_string()); - | - move occurs because `x` has type `std::option::Option`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Option`, which does not implement the `Copy` trait LL | match x { LL | op_string @ Some(s) => {}, | -----------------^- diff --git a/src/test/ui/error-codes/E0010-teach.rs b/src/test/ui/error-codes/E0010-teach.rs index da51035ab5..fc5dffb37c 100644 --- a/src/test/ui/error-codes/E0010-teach.rs +++ b/src/test/ui/error-codes/E0010-teach.rs @@ -4,6 +4,5 @@ #![allow(warnings)] const CON : Box = box 0; //~ ERROR E0010 -//~^ ERROR constant contains unimplemented expression type fn main() {} diff --git a/src/test/ui/error-codes/E0010-teach.stderr b/src/test/ui/error-codes/E0010-teach.stderr index c15ab5c655..33de9fd685 100644 --- a/src/test/ui/error-codes/E0010-teach.stderr +++ b/src/test/ui/error-codes/E0010-teach.stderr @@ -6,17 +6,6 @@ LL | const CON : Box = box 0; | = 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. -error[E0019]: constant contains unimplemented expression type - --> $DIR/E0010-teach.rs:6:28 - | -LL | const CON : Box = box 0; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - = note: A function call isn't allowed in the const's initialization expression because the expression's value must be known at compile-time. - = note: Remember: you can't use a function call inside a const's initialization expression! However, you can use it anywhere else. +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0010, E0019. -For more information about an error, try `rustc --explain E0010`. +For more information about this error, try `rustc --explain E0010`. diff --git a/src/test/ui/error-codes/E0010.rs b/src/test/ui/error-codes/E0010.rs index 3398e2c28b..e62997640f 100644 --- a/src/test/ui/error-codes/E0010.rs +++ b/src/test/ui/error-codes/E0010.rs @@ -2,6 +2,5 @@ #![allow(warnings)] const CON : Box = box 0; //~ ERROR E0010 -//~^ ERROR constant contains unimplemented expression type fn main() {} diff --git a/src/test/ui/error-codes/E0010.stderr b/src/test/ui/error-codes/E0010.stderr index f49fb9c463..0042333b98 100644 --- a/src/test/ui/error-codes/E0010.stderr +++ b/src/test/ui/error-codes/E0010.stderr @@ -4,15 +4,6 @@ error[E0010]: allocations are not allowed in constants LL | const CON : Box = box 0; | ^^^^^ allocation not allowed in constants -error[E0019]: constant contains unimplemented expression type - --> $DIR/E0010.rs:4:28 - | -LL | const CON : Box = box 0; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0010, E0019. -For more information about an error, try `rustc --explain E0010`. +For more information about this error, try `rustc --explain E0010`. diff --git a/src/test/ui/error-codes/E0017.rs b/src/test/ui/error-codes/E0017.rs index 818dec1207..262f7bc72c 100644 --- a/src/test/ui/error-codes/E0017.rs +++ b/src/test/ui/error-codes/E0017.rs @@ -3,9 +3,11 @@ const C: i32 = 2; static mut M: i32 = 3; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0764 - //~| ERROR E0019 //~| ERROR cannot borrow + static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; //~ ERROR E0764 fn main() {} diff --git a/src/test/ui/error-codes/E0017.stderr b/src/test/ui/error-codes/E0017.stderr index c1d96de1dc..ea591587e6 100644 --- a/src/test/ui/error-codes/E0017.stderr +++ b/src/test/ui/error-codes/E0017.stderr @@ -1,42 +1,63 @@ +warning: taking a mutable reference to a `const` item + --> $DIR/E0017.rs:5:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = 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 +note: `const` item defined here + --> $DIR/E0017.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in constants --> $DIR/E0017.rs:5:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0019]: static contains unimplemented expression type - --> $DIR/E0017.rs:6:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0017.rs:6:39 + --> $DIR/E0017.rs:7:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0017.rs:10:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = 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 +note: `const` item defined here + --> $DIR/E0017.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:9:38 + --> $DIR/E0017.rs:10:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0764]: mutable references are not allowed in statics - --> $DIR/E0017.rs:10:52 + --> $DIR/E0017.rs:12:52 | LL | static STATIC_MUT_REF: &'static mut i32 = unsafe { &mut M }; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 6 previous errors +error: aborting due to 5 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0019, E0596, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0596, E0764. +For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/error-codes/E0027-teach.rs b/src/test/ui/error-codes/E0027-teach.rs deleted file mode 100644 index 11402f0148..0000000000 --- a/src/test/ui/error-codes/E0027-teach.rs +++ /dev/null @@ -1,15 +0,0 @@ -// compile-flags: -Z teach - -struct Dog { - name: String, - age: u32, -} - -fn main() { - let d = Dog { name: "Rusty".to_string(), age: 8 }; - - match d { - Dog { age: x } => {} - //~^ ERROR pattern does not mention field `name` - } -} diff --git a/src/test/ui/error-codes/E0027-teach.stderr b/src/test/ui/error-codes/E0027-teach.stderr deleted file mode 100644 index aa4cb9d4d1..0000000000 --- a/src/test/ui/error-codes/E0027-teach.stderr +++ /dev/null @@ -1,11 +0,0 @@ -error[E0027]: pattern does not mention field `name` - --> $DIR/E0027-teach.rs:12:9 - | -LL | Dog { age: x } => {} - | ^^^^^^^^^^^^^^ missing field `name` - | - = note: This error indicates that a pattern for a struct fails to specify a sub-pattern for every one of the struct's fields. Ensure that each field from the struct's definition is mentioned in the pattern, or use `..` to ignore unwanted fields. - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/error-codes/E0027.rs b/src/test/ui/error-codes/E0027.rs index b8c6a2b7fc..8d08e17893 100644 --- a/src/test/ui/error-codes/E0027.rs +++ b/src/test/ui/error-codes/E0027.rs @@ -7,7 +7,9 @@ fn main() { let d = Dog { name: "Rusty".to_string(), age: 8 }; match d { - Dog { age: x } => {} - //~^ ERROR pattern does not mention field `name` + Dog { age: x } => {} //~ ERROR pattern does not mention field `name` + } + match d { + Dog {} => {} //~ ERROR pattern does not mention fields `name`, `age` } } diff --git a/src/test/ui/error-codes/E0027.stderr b/src/test/ui/error-codes/E0027.stderr index 4f17bba647..c09f1ff1f2 100644 --- a/src/test/ui/error-codes/E0027.stderr +++ b/src/test/ui/error-codes/E0027.stderr @@ -3,7 +3,31 @@ error[E0027]: pattern does not mention field `name` | LL | Dog { age: x } => {} | ^^^^^^^^^^^^^^ missing field `name` + | +help: include the missing field in the pattern + | +LL | Dog { age: x, name } => {} + | ^^^^^^ +help: if you don't care about this missing field, you can explicitely ignore it + | +LL | Dog { age: x, .. } => {} + | ^^^^ -error: aborting due to previous error +error[E0027]: pattern does not mention fields `name`, `age` + --> $DIR/E0027.rs:13:9 + | +LL | Dog {} => {} + | ^^^^^^ missing fields `name`, `age` + | +help: include the missing fields in the pattern + | +LL | Dog { name, age } => {} + | ^^^^^^^^^^^^^ +help: if you don't care about these missing fields, you can explicitely ignore them + | +LL | Dog { .. } => {} + | ^^^^^^ + +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0027`. diff --git a/src/test/ui/error-codes/E0029-teach.rs b/src/test/ui/error-codes/E0029-teach.rs index 83058d397c..3ff8cb348e 100644 --- a/src/test/ui/error-codes/E0029-teach.rs +++ b/src/test/ui/error-codes/E0029-teach.rs @@ -5,7 +5,7 @@ fn main() { match s { "hello" ..= "world" => {} - //~^ ERROR only char and numeric types are allowed in range patterns + //~^ ERROR only `char` and numeric types are allowed in range patterns _ => {} } } diff --git a/src/test/ui/error-codes/E0029-teach.stderr b/src/test/ui/error-codes/E0029-teach.stderr index ec146ca86f..b89b2e7d11 100644 --- a/src/test/ui/error-codes/E0029-teach.stderr +++ b/src/test/ui/error-codes/E0029-teach.stderr @@ -1,4 +1,4 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/E0029-teach.rs:7:9 | LL | "hello" ..= "world" => {} diff --git a/src/test/ui/error-codes/E0029.rs b/src/test/ui/error-codes/E0029.rs index fe0d851832..d9b53e113c 100644 --- a/src/test/ui/error-codes/E0029.rs +++ b/src/test/ui/error-codes/E0029.rs @@ -3,7 +3,7 @@ fn main() { match s { "hello" ..= "world" => {} - //~^ ERROR only char and numeric types are allowed in range patterns + //~^ ERROR only `char` and numeric types are allowed in range patterns _ => {} } } diff --git a/src/test/ui/error-codes/E0029.stderr b/src/test/ui/error-codes/E0029.stderr index e54722ae7b..f7250b39d3 100644 --- a/src/test/ui/error-codes/E0029.stderr +++ b/src/test/ui/error-codes/E0029.stderr @@ -1,4 +1,4 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/E0029.rs:5:9 | LL | "hello" ..= "world" => {} diff --git a/src/test/ui/error-codes/E0067.stderr b/src/test/ui/error-codes/E0067.stderr index fad8270fd5..ec0358cb7d 100644 --- a/src/test/ui/error-codes/E0067.stderr +++ b/src/test/ui/error-codes/E0067.stderr @@ -1,10 +1,10 @@ -error[E0368]: binary assignment operation `+=` cannot be applied to type `std::collections::LinkedList<_>` +error[E0368]: binary assignment operation `+=` cannot be applied to type `LinkedList<_>` --> $DIR/E0067.rs:4:5 | LL | LinkedList::new() += 1; | -----------------^^^^^ | | - | cannot use `+=` on type `std::collections::LinkedList<_>` + | cannot use `+=` on type `LinkedList<_>` error[E0067]: invalid left-hand side of assignment --> $DIR/E0067.rs:4:23 diff --git a/src/test/ui/error-codes/E0070.stderr b/src/test/ui/error-codes/E0070.stderr index d809bb18de..e24d498e35 100644 --- a/src/test/ui/error-codes/E0070.stderr +++ b/src/test/ui/error-codes/E0070.stderr @@ -14,12 +14,6 @@ LL | 1 = 3; | | | cannot assign to this expression -error[E0308]: mismatched types - --> $DIR/E0070.rs:8:25 - | -LL | some_other_func() = 4; - | ^ expected `()`, found integer - error[E0070]: invalid left-hand side of assignment --> $DIR/E0070.rs:8:23 | @@ -28,6 +22,12 @@ LL | some_other_func() = 4; | | | cannot assign to this expression +error[E0308]: mismatched types + --> $DIR/E0070.rs:8:25 + | +LL | some_other_func() = 4; + | ^ expected `()`, found integer + error: aborting due to 4 previous errors Some errors have detailed explanations: E0070, E0308. diff --git a/src/test/ui/error-codes/E0080.rs b/src/test/ui/error-codes/E0080.rs index b31cf2ec44..ea3264b61b 100644 --- a/src/test/ui/error-codes/E0080.rs +++ b/src/test/ui/error-codes/E0080.rs @@ -1,6 +1,6 @@ enum Enum { X = (1 << 500), //~ ERROR E0080 - //~| attempt to shift left by 500_i32 which would overflow + //~| attempt to shift left by `500_i32`, which would overflow Y = (1 / 0) //~ ERROR E0080 } diff --git a/src/test/ui/error-codes/E0080.stderr b/src/test/ui/error-codes/E0080.stderr index 3acd15ff6b..60ed9a4358 100644 --- a/src/test/ui/error-codes/E0080.stderr +++ b/src/test/ui/error-codes/E0080.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/E0080.rs:2:9 | LL | X = (1 << 500), - | ^^^^^^^^^^ attempt to shift left by 500_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `500_i32`, which would overflow error[E0080]: evaluation of constant value failed --> $DIR/E0080.rs:4:9 | LL | Y = (1 / 0) - | ^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^ attempt to divide `1_isize` by zero error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0118-2.rs b/src/test/ui/error-codes/E0118-2.rs new file mode 100644 index 0000000000..fe04190162 --- /dev/null +++ b/src/test/ui/error-codes/E0118-2.rs @@ -0,0 +1,8 @@ +struct Foo; + +impl &mut Foo { + //~^ ERROR E0118 + fn bar(self) {} +} + +fn main() {} diff --git a/src/test/ui/error-codes/E0118-2.stderr b/src/test/ui/error-codes/E0118-2.stderr new file mode 100644 index 0000000000..2a1fe23111 --- /dev/null +++ b/src/test/ui/error-codes/E0118-2.stderr @@ -0,0 +1,12 @@ +error[E0118]: no nominal type found for inherent implementation + --> $DIR/E0118-2.rs:3:6 + | +LL | impl &mut Foo { + | ^^^^^^^^ impl requires a nominal type + | + = note: either implement a trait on it or create a newtype to wrap it instead + = note: you could also try moving the reference to uses of `Foo` (such as `self`) within the implementation + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0118`. diff --git a/src/test/ui/error-codes/E0118.stderr b/src/test/ui/error-codes/E0118.stderr index b0afaeb5c1..2693a93213 100644 --- a/src/test/ui/error-codes/E0118.stderr +++ b/src/test/ui/error-codes/E0118.stderr @@ -1,8 +1,8 @@ -error[E0118]: no base type found for inherent implementation +error[E0118]: no nominal type found for inherent implementation --> $DIR/E0118.rs:1:6 | LL | impl (u8, u8) { - | ^^^^^^^^ impl requires a base type + | ^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/error-codes/E0221.stderr b/src/test/ui/error-codes/E0221.stderr index 0b4819143c..085f80f44f 100644 --- a/src/test/ui/error-codes/E0221.stderr +++ b/src/test/ui/error-codes/E0221.stderr @@ -31,7 +31,7 @@ LL | let _: Self::Err; | ambiguous associated type `Err` | help: use fully qualified syntax to disambiguate: `::Err` | - = note: associated type `Self` could derive from `std::str::FromStr` + = note: associated type `Self` could derive from `FromStr` error: aborting due to 2 previous errors diff --git a/src/test/ui/error-codes/E0276.stderr b/src/test/ui/error-codes/E0276.stderr index a8b016ebf5..8857e1646e 100644 --- a/src/test/ui/error-codes/E0276.stderr +++ b/src/test/ui/error-codes/E0276.stderr @@ -5,7 +5,7 @@ LL | fn foo(x: T); | ---------------- definition of `foo` from trait ... LL | fn foo(x: T) where T: Copy {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::marker::Copy` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Copy` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0277-2.stderr b/src/test/ui/error-codes/E0277-2.stderr index f5ba46ca01..a0ab1641ca 100644 --- a/src/test/ui/error-codes/E0277-2.stderr +++ b/src/test/ui/error-codes/E0277-2.stderr @@ -7,7 +7,7 @@ LL | fn is_send() { } LL | is_send::(); | ^^^^^^^^^^^^^^ `*const u8` cannot be sent between threads safely | - = help: within `Foo`, the trait `std::marker::Send` is not implemented for `*const u8` + = help: within `Foo`, the trait `Send` is not implemented for `*const u8` = note: required because it appears within the type `Baz` = note: required because it appears within the type `Bar` = note: required because it appears within the type `Foo` diff --git a/src/test/ui/error-codes/E0277.stderr b/src/test/ui/error-codes/E0277.stderr index 203fc18915..c2e15007cf 100644 --- a/src/test/ui/error-codes/E0277.stderr +++ b/src/test/ui/error-codes/E0277.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time | - = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: required because it appears within the type `std::path::Path` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]` + = note: required because it appears within the type `Path` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/error-codes/E0297.stderr b/src/test/ui/error-codes/E0297.stderr index 9134e90557..ec3452b1dd 100644 --- a/src/test/ui/error-codes/E0297.stderr +++ b/src/test/ui/error-codes/E0297.stderr @@ -9,7 +9,7 @@ LL | for Some(x) in xs {} LL | None, | ---- not covered | - = note: the matched value is of type `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0308-2.stderr b/src/test/ui/error-codes/E0308-2.stderr index e7c5e4b424..47fea5a23a 100644 --- a/src/test/ui/error-codes/E0308-2.stderr +++ b/src/test/ui/error-codes/E0308-2.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | impl Eq for &dyn DynEq {} | ^^ lifetime mismatch | - = note: expected trait `std::cmp::PartialEq` - found trait `std::cmp::PartialEq` + = note: expected trait `PartialEq` + found trait `PartialEq` note: the lifetime `'_` as defined on the impl at 9:13... --> $DIR/E0308-2.rs:9:13 | diff --git a/src/test/ui/error-codes/E0388.rs b/src/test/ui/error-codes/E0388.rs index 13131017c2..bb0c4979b9 100644 --- a/src/test/ui/error-codes/E0388.rs +++ b/src/test/ui/error-codes/E0388.rs @@ -2,9 +2,11 @@ static X: i32 = 1; const C: i32 = 2; const CR: &'static mut i32 = &mut C; //~ ERROR E0764 -static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR E0019 - //~| ERROR cannot borrow + //~| WARN taking a mutable +static STATIC_REF: &'static mut i32 = &mut X; //~ ERROR cannot borrow //~| ERROR E0764 + static CONST_REF: &'static mut i32 = &mut C; //~ ERROR E0764 + //~| WARN taking a mutable fn main() {} diff --git a/src/test/ui/error-codes/E0388.stderr b/src/test/ui/error-codes/E0388.stderr index f09100bac4..73e0b139cd 100644 --- a/src/test/ui/error-codes/E0388.stderr +++ b/src/test/ui/error-codes/E0388.stderr @@ -1,36 +1,57 @@ +warning: taking a mutable reference to a `const` item + --> $DIR/E0388.rs:4:30 + | +LL | const CR: &'static mut i32 = &mut C; + | ^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = 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 +note: `const` item defined here + --> $DIR/E0388.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in constants --> $DIR/E0388.rs:4:30 | LL | const CR: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` -error[E0019]: static contains unimplemented expression type - --> $DIR/E0388.rs:5:39 - | -LL | static STATIC_REF: &'static mut i32 = &mut X; - | ^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ `&mut` is only allowed in `const fn` error[E0596]: cannot borrow immutable static item `X` as mutable - --> $DIR/E0388.rs:5:39 + --> $DIR/E0388.rs:6:39 | LL | static STATIC_REF: &'static mut i32 = &mut X; | ^^^^^^ cannot borrow as mutable +warning: taking a mutable reference to a `const` item + --> $DIR/E0388.rs:9:38 + | +LL | static CONST_REF: &'static mut i32 = &mut C; + | ^^^^^^ + | + = 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 +note: `const` item defined here + --> $DIR/E0388.rs:2:1 + | +LL | const C: i32 = 2; + | ^^^^^^^^^^^^^^^^^ + error[E0764]: mutable references are not allowed in statics - --> $DIR/E0388.rs:8:38 + --> $DIR/E0388.rs:9:38 | LL | static CONST_REF: &'static mut i32 = &mut C; | ^^^^^^ `&mut` is only allowed in `const fn` -error: aborting due to 5 previous errors +error: aborting due to 4 previous errors; 2 warnings emitted -Some errors have detailed explanations: E0019, E0596, E0764. -For more information about an error, try `rustc --explain E0019`. +Some errors have detailed explanations: E0596, E0764. +For more information about an error, try `rustc --explain E0596`. diff --git a/src/test/ui/error-codes/E0392.stderr b/src/test/ui/error-codes/E0392.stderr index 7b0bfe3727..860bf68f01 100644 --- a/src/test/ui/error-codes/E0392.stderr +++ b/src/test/ui/error-codes/E0392.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `T` is never used LL | enum Foo { Bar } | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0433.stderr b/src/test/ui/error-codes/E0433.stderr index d9555e1fcf..265d8885c8 100644 --- a/src/test/ui/error-codes/E0433.stderr +++ b/src/test/ui/error-codes/E0433.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistingMap` +error[E0433]: failed to resolve: use of undeclared type `NonExistingMap` --> $DIR/E0433.rs:2:15 | LL | let map = NonExistingMap::new(); - | ^^^^^^^^^^^^^^ use of undeclared type or module `NonExistingMap` + | ^^^^^^^^^^^^^^ use of undeclared type `NonExistingMap` error: aborting due to previous error diff --git a/src/test/ui/error-codes/E0446.stderr b/src/test/ui/error-codes/E0446.stderr index bb00926097..c538bae2e5 100644 --- a/src/test/ui/error-codes/E0446.stderr +++ b/src/test/ui/error-codes/E0446.stderr @@ -1,8 +1,8 @@ -error[E0446]: private type `foo::Bar` in public interface +error[E0446]: private type `Bar` in public interface --> $DIR/E0446.rs:4:5 | LL | struct Bar(u32); - | - `foo::Bar` declared as private + | - `Bar` declared as private LL | LL | pub fn bar() -> Bar { | ^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/error-codes/E0451.stderr b/src/test/ui/error-codes/E0451.stderr index bb92c23e0f..419cf117ef 100644 --- a/src/test/ui/error-codes/E0451.stderr +++ b/src/test/ui/error-codes/E0451.stderr @@ -1,10 +1,10 @@ -error[E0451]: field `b` of struct `bar::Foo` is private +error[E0451]: field `b` of struct `Foo` is private --> $DIR/E0451.rs:14:21 | LL | let bar::Foo{a, b} = foo; | ^ private field -error[E0451]: field `b` of struct `bar::Foo` is private +error[E0451]: field `b` of struct `Foo` is private --> $DIR/E0451.rs:18:29 | LL | let f = bar::Foo{ a: 0, b: 0 }; diff --git a/src/test/ui/error-codes/E0507.stderr b/src/test/ui/error-codes/E0507.stderr index 170b883191..cd5e467944 100644 --- a/src/test/ui/error-codes/E0507.stderr +++ b/src/test/ui/error-codes/E0507.stderr @@ -1,4 +1,4 @@ -error[E0507]: cannot move out of dereference of `std::cell::Ref<'_, TheDarkKnight>` +error[E0507]: cannot move out of dereference of `Ref<'_, TheDarkKnight>` --> $DIR/E0507.rs:12:5 | LL | x.borrow().nothing_is_true(); diff --git a/src/test/ui/error-codes/E0605.stderr b/src/test/ui/error-codes/E0605.stderr index f23d2008e0..43269c095d 100644 --- a/src/test/ui/error-codes/E0605.stderr +++ b/src/test/ui/error-codes/E0605.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `u8` as `std::vec::Vec` +error[E0605]: non-primitive cast: `u8` as `Vec` --> $DIR/E0605.rs:3:5 | LL | x as Vec; diff --git a/src/test/ui/error-codes/E0616.stderr b/src/test/ui/error-codes/E0616.stderr index 422bf687e7..da349ed2fd 100644 --- a/src/test/ui/error-codes/E0616.stderr +++ b/src/test/ui/error-codes/E0616.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `x` of struct `a::Foo` is private +error[E0616]: field `x` of struct `Foo` is private --> $DIR/E0616.rs:13:7 | LL | f.x; diff --git a/src/test/ui/error-codes/E0719.stderr b/src/test/ui/error-codes/E0719.stderr index 0e4bbf083b..b342d63433 100644 --- a/src/test/ui/error-codes/E0719.stderr +++ b/src/test/ui/error-codes/E0719.stderr @@ -1,4 +1,4 @@ -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/E0719.rs:1:33 | LL | trait Foo: Iterator {} @@ -6,7 +6,7 @@ LL | trait Foo: Iterator {} | | | `Item` bound here first -error[E0719]: the value of the associated type `Item` (from trait `std::iter::Iterator`) is already specified +error[E0719]: the value of the associated type `Item` (from trait `Iterator`) is already specified --> $DIR/E0719.rs:6:42 | LL | fn test() -> Box> { diff --git a/src/test/ui/error-codes/e0119/complex-impl.stderr b/src/test/ui/error-codes/e0119/complex-impl.stderr index 2cc09e8b14..d617d81292 100644 --- a/src/test/ui/error-codes/e0119/complex-impl.stderr +++ b/src/test/ui/error-codes/e0119/complex-impl.stderr @@ -5,8 +5,8 @@ LL | impl External for (Q, R) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `complex_impl_support`: - - impl<'a, 'b, 'c, T, U, V, W> complex_impl_support::External for (T, complex_impl_support::M<'a, 'b, 'c, std::boxed::Box, V, W>) - where >::Output == V, ::Item == T, 'b: 'a, T: 'a, U: std::ops::FnOnce<(T,)>, U: 'static, V: std::iter::Iterator, V: std::clone::Clone, W: std::ops::Add, ::Output: std::marker::Copy; + - 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; error[E0117]: only traits defined in the current crate can be implemented for arbitrary types --> $DIR/complex-impl.rs:9:1 diff --git a/src/test/ui/error-codes/e0119/conflict-with-std.stderr b/src/test/ui/error-codes/e0119/conflict-with-std.stderr index 3e0c71e907..4b6b4430f3 100644 --- a/src/test/ui/error-codes/e0119/conflict-with-std.stderr +++ b/src/test/ui/error-codes/e0119/conflict-with-std.stderr @@ -5,7 +5,7 @@ LL | impl AsRef for Box { | ^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `alloc`: - - impl std::convert::AsRef for std::boxed::Box + - impl AsRef for Box where T: ?Sized; error[E0119]: conflicting implementations of trait `std::convert::From` for type `S`: @@ -15,7 +15,7 @@ LL | impl From for S { | ^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::From for T; + - impl From for T; error[E0119]: conflicting implementations of trait `std::convert::TryFrom` for type `X`: --> $DIR/conflict-with-std.rs:19:1 @@ -24,8 +24,8 @@ LL | impl TryFrom for X { | ^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::TryFrom for T - where U: std::convert::Into; + - impl TryFrom for T + where U: Into; error: aborting due to 3 previous errors diff --git a/src/test/ui/error-codes/e0119/issue-23563.stderr b/src/test/ui/error-codes/e0119/issue-23563.stderr index 8011689880..912a80fec7 100644 --- a/src/test/ui/error-codes/e0119/issue-23563.stderr +++ b/src/test/ui/error-codes/e0119/issue-23563.stderr @@ -5,8 +5,8 @@ LL | impl<'a, T> LolFrom<&'a [T]> for LocalType { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `issue_23563_a`: - - impl a::LolFrom for U - where T: a::LolInto; + - impl LolFrom for U + where T: LolInto; error: aborting due to previous error diff --git a/src/test/ui/error-codes/e0119/issue-27403.stderr b/src/test/ui/error-codes/e0119/issue-27403.stderr index cba10432a9..ea74c9b21b 100644 --- a/src/test/ui/error-codes/e0119/issue-27403.stderr +++ b/src/test/ui/error-codes/e0119/issue-27403.stderr @@ -5,8 +5,8 @@ LL | impl Into for GenX { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::Into for T - where U: std::convert::From; + - impl Into for T + where U: From; error: aborting due to previous error diff --git a/src/test/ui/error-codes/e0119/issue-28981.stderr b/src/test/ui/error-codes/e0119/issue-28981.stderr index 2a78cc8b2d..c22cc65c87 100644 --- a/src/test/ui/error-codes/e0119/issue-28981.stderr +++ b/src/test/ui/error-codes/e0119/issue-28981.stderr @@ -5,7 +5,7 @@ LL | impl Deref for Foo { } | ^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::ops::Deref for &T + - impl Deref for &T where T: ?Sized; error[E0210]: type parameter `Foo` must be used as the type parameter for some local type (e.g., `MyStruct`) diff --git a/src/test/ui/error-codes/e0119/so-37347311.stderr b/src/test/ui/error-codes/e0119/so-37347311.stderr index f2166de71f..a9fbd0fee4 100644 --- a/src/test/ui/error-codes/e0119/so-37347311.stderr +++ b/src/test/ui/error-codes/e0119/so-37347311.stderr @@ -5,7 +5,7 @@ LL | impl From for MyError { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::convert::From for T; + - impl From for T; error: aborting due to previous error diff --git a/src/test/ui/error-codes/ex-E0611.rs b/src/test/ui/error-codes/ex-E0611.rs index 8460341c44..f18a3619f3 100644 --- a/src/test/ui/error-codes/ex-E0611.rs +++ b/src/test/ui/error-codes/ex-E0611.rs @@ -8,5 +8,5 @@ mod a { fn main() { let y = a::Foo::new(); - y.0; //~ ERROR field `0` of struct `a::Foo` is private + y.0; //~ ERROR field `0` of struct `Foo` is private } diff --git a/src/test/ui/error-codes/ex-E0611.stderr b/src/test/ui/error-codes/ex-E0611.stderr index 2d22bb3951..1da7b33be9 100644 --- a/src/test/ui/error-codes/ex-E0611.stderr +++ b/src/test/ui/error-codes/ex-E0611.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `0` of struct `a::Foo` is private +error[E0616]: field `0` of struct `Foo` is private --> $DIR/ex-E0611.rs:11:6 | LL | y.0; diff --git a/src/test/ui/error-festival.stderr b/src/test/ui/error-festival.stderr index 905195d4ad..89a9d965de 100644 --- a/src/test/ui/error-festival.stderr +++ b/src/test/ui/error-festival.stderr @@ -44,7 +44,7 @@ error[E0604]: only `u8` can be cast as `char`, not `u32` LL | 0u32 as char; | ^^^^^^^^^^^^ invalid cast -error[E0605]: non-primitive cast: `u8` as `std::vec::Vec` +error[E0605]: non-primitive cast: `u8` as `Vec` --> $DIR/error-festival.rs:29:5 | LL | x as Vec; diff --git a/src/test/ui/error-should-say-copy-not-pod.rs b/src/test/ui/error-should-say-copy-not-pod.rs index be4e451ceb..40c4730ef6 100644 --- a/src/test/ui/error-should-say-copy-not-pod.rs +++ b/src/test/ui/error-should-say-copy-not-pod.rs @@ -3,5 +3,5 @@ fn check_bound(_: T) {} fn main() { - check_bound("nocopy".to_string()); //~ ERROR : std::marker::Copy` is not satisfied + check_bound("nocopy".to_string()); //~ ERROR : Copy` is not satisfied } diff --git a/src/test/ui/error-should-say-copy-not-pod.stderr b/src/test/ui/error-should-say-copy-not-pod.stderr index 96ffa6f3e0..346e882485 100644 --- a/src/test/ui/error-should-say-copy-not-pod.stderr +++ b/src/test/ui/error-should-say-copy-not-pod.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/error-should-say-copy-not-pod.rs:6:17 | LL | fn check_bound(_: T) {} | ---- required by this bound in `check_bound` ... LL | check_bound("nocopy".to_string()); - | ^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `String` error: aborting due to previous error diff --git a/src/test/ui/estr-subtyping.stderr b/src/test/ui/estr-subtyping.stderr index e5dbab6441..268ec63a80 100644 --- a/src/test/ui/estr-subtyping.stderr +++ b/src/test/ui/estr-subtyping.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | wants_uniq(x); | ^ | | - | expected struct `std::string::String`, found `&str` + | expected struct `String`, found `&str` | help: try using a conversion method: `x.to_string()` error: aborting due to previous error diff --git a/src/test/ui/eval-enum.rs b/src/test/ui/eval-enum.rs index 4ef06c7806..551f10e66e 100644 --- a/src/test/ui/eval-enum.rs +++ b/src/test/ui/eval-enum.rs @@ -1,9 +1,9 @@ enum Test { DivZero = 1/0, - //~^ attempt to divide 1_isize by zero + //~^ attempt to divide `1_isize` by zero //~| ERROR evaluation of constant value failed RemZero = 1%0, - //~^ attempt to calculate the remainder of 1_isize with a divisor of zero + //~^ attempt to calculate the remainder of `1_isize` with a divisor of zero //~| ERROR evaluation of constant value failed } diff --git a/src/test/ui/eval-enum.stderr b/src/test/ui/eval-enum.stderr index dd89a2d7c3..fb4d903489 100644 --- a/src/test/ui/eval-enum.stderr +++ b/src/test/ui/eval-enum.stderr @@ -2,13 +2,13 @@ error[E0080]: evaluation of constant value failed --> $DIR/eval-enum.rs:2:15 | LL | DivZero = 1/0, - | ^^^ attempt to divide 1_isize by zero + | ^^^ attempt to divide `1_isize` by zero error[E0080]: evaluation of constant value failed --> $DIR/eval-enum.rs:5:15 | LL | RemZero = 1%0, - | ^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: aborting due to 2 previous errors diff --git a/src/test/ui/explore-issue-38412.stderr b/src/test/ui/explore-issue-38412.stderr index 1855c0b143..55f43840b9 100644 --- a/src/test/ui/explore-issue-38412.stderr +++ b/src/test/ui/explore-issue-38412.stderr @@ -16,19 +16,19 @@ LL | r.a_unstable_undeclared_pub; = note: see issue #38412 for more information = help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable -error[E0616]: field `b_crate` of struct `pub_and_stability::Record` is private +error[E0616]: field `b_crate` of struct `Record` is private --> $DIR/explore-issue-38412.rs:31:7 | LL | r.b_crate; | ^^^^^^^ private field -error[E0616]: field `c_mod` of struct `pub_and_stability::Record` is private +error[E0616]: field `c_mod` of struct `Record` is private --> $DIR/explore-issue-38412.rs:32:7 | LL | r.c_mod; | ^^^^^ private field -error[E0616]: field `d_priv` of struct `pub_and_stability::Record` is private +error[E0616]: field `d_priv` of struct `Record` is private --> $DIR/explore-issue-38412.rs:33:7 | LL | r.d_priv; @@ -43,19 +43,19 @@ LL | t.2; = note: see issue #38412 for more information = help: add `#![feature(unstable_undeclared)]` to the crate attributes to enable -error[E0616]: field `3` of struct `pub_and_stability::Tuple` is private +error[E0616]: field `3` of struct `Tuple` is private --> $DIR/explore-issue-38412.rs:38:7 | LL | t.3; | ^ private field -error[E0616]: field `4` of struct `pub_and_stability::Tuple` is private +error[E0616]: field `4` of struct `Tuple` is private --> $DIR/explore-issue-38412.rs:39:7 | LL | t.4; | ^ private field -error[E0616]: field `5` of struct `pub_and_stability::Tuple` is private +error[E0616]: field `5` of struct `Tuple` is private --> $DIR/explore-issue-38412.rs:40:7 | LL | t.5; diff --git a/src/test/ui/export-fully-qualified.rs b/src/test/ui/export-fully-qualified.rs index 99cb558908..40f26c7095 100644 --- a/src/test/ui/export-fully-qualified.rs +++ b/src/test/ui/export-fully-qualified.rs @@ -1,9 +1,11 @@ +// ignore-tidy-linelength + // In this test baz isn't resolved when called as foo.baz even though // it's called from inside foo. This is somewhat surprising and may // want to change eventually. mod foo { - pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared type or module `foo` + pub fn bar() { foo::baz(); } //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn baz() { } } diff --git a/src/test/ui/export-fully-qualified.stderr b/src/test/ui/export-fully-qualified.stderr index c2ec160086..a8af0c7c9b 100644 --- a/src/test/ui/export-fully-qualified.stderr +++ b/src/test/ui/export-fully-qualified.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` - --> $DIR/export-fully-qualified.rs:6:20 +error[E0433]: failed to resolve: use of undeclared crate or module `foo` + --> $DIR/export-fully-qualified.rs:8:20 | LL | pub fn bar() { foo::baz(); } - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/export2.rs b/src/test/ui/export2.rs index 811d96f26d..64ebeddffa 100644 --- a/src/test/ui/export2.rs +++ b/src/test/ui/export2.rs @@ -1,5 +1,5 @@ mod foo { - pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared type or module `bar` + pub fn x() { bar::x(); } //~ ERROR failed to resolve: use of undeclared crate or module `bar` } mod bar { diff --git a/src/test/ui/export2.stderr b/src/test/ui/export2.stderr index e0cd4404d3..7cf47d0764 100644 --- a/src/test/ui/export2.stderr +++ b/src/test/ui/export2.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `bar` +error[E0433]: failed to resolve: use of undeclared crate or module `bar` --> $DIR/export2.rs:2:18 | LL | pub fn x() { bar::x(); } - | ^^^ use of undeclared type or module `bar` + | ^^^ use of undeclared crate or module `bar` error: aborting due to previous error diff --git a/src/test/ui/exterior.rs b/src/test/ui/exterior.rs deleted file mode 100644 index 6f2c37926b..0000000000 --- a/src/test/ui/exterior.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - -#![allow(dead_code)] - - -use std::cell::Cell; - -#[derive(Copy, Clone)] -struct Point {x: isize, y: isize, z: isize} - -fn f(p: &Cell) { - assert_eq!(p.get().z, 12); - p.set(Point {x: 10, y: 11, z: 13}); - assert_eq!(p.get().z, 13); -} - -pub fn main() { - let a: Point = Point {x: 10, y: 11, z: 12}; - let b: &Cell = &Cell::new(a); - assert_eq!(b.get().z, 12); - f(b); - assert_eq!(a.z, 12); - assert_eq!(b.get().z, 13); -} diff --git a/src/test/ui/extern-flag/multiple-opts.stderr b/src/test/ui/extern-flag/multiple-opts.stderr index 3bf73d11cf..5088fb1c4d 100644 --- a/src/test/ui/extern-flag/multiple-opts.stderr +++ b/src/test/ui/extern-flag/multiple-opts.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/multiple-opts.rs:19:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/noprelude.stderr b/src/test/ui/extern-flag/noprelude.stderr index beb9200ddd..5787872168 100644 --- a/src/test/ui/extern-flag/noprelude.stderr +++ b/src/test/ui/extern-flag/noprelude.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `somedep` +error[E0433]: failed to resolve: use of undeclared crate or module `somedep` --> $DIR/noprelude.rs:6:5 | LL | somedep::somefun(); - | ^^^^^^^ use of undeclared type or module `somedep` + | ^^^^^^^ use of undeclared crate or module `somedep` error: aborting due to previous error diff --git a/src/test/ui/extern-flag/public-and-private.stderr b/src/test/ui/extern-flag/public-and-private.stderr index 94c7deaa80..9dfc10effc 100644 --- a/src/test/ui/extern-flag/public-and-private.stderr +++ b/src/test/ui/extern-flag/public-and-private.stderr @@ -1,4 +1,4 @@ -error: type `somedep::S` from private dependency 'somedep' in public interface +error: type `S` from private dependency 'somedep' in public interface --> $DIR/public-and-private.rs:10:5 | LL | pub field: somedep::S, diff --git a/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs new file mode 100644 index 0000000000..a1efe18184 --- /dev/null +++ b/src/test/ui/extern/auxiliary/extern-types-inherent-impl.rs @@ -0,0 +1,9 @@ +#![feature(extern_types)] + +extern "C" { + pub type CrossCrate; +} + +impl CrossCrate { + pub fn foo(&self) {} +} diff --git a/src/test/ui/extern/extern-types-inherent-impl.rs b/src/test/ui/extern/extern-types-inherent-impl.rs index fc98f55dc0..3f09ac7b8c 100644 --- a/src/test/ui/extern/extern-types-inherent-impl.rs +++ b/src/test/ui/extern/extern-types-inherent-impl.rs @@ -1,19 +1,26 @@ -// run-pass -#![allow(dead_code)] // Test that inherent impls can be defined for extern types. +// check-pass +// aux-build:extern-types-inherent-impl.rs + #![feature(extern_types)] -extern { - type A; +extern crate extern_types_inherent_impl; +use extern_types_inherent_impl::CrossCrate; + +extern "C" { + type Local; } -impl A { - fn foo(&self) { } +impl Local { + fn foo(&self) {} } -fn use_foo(x: &A) { +fn use_foo(x: &Local, y: &CrossCrate) { + Local::foo(x); x.foo(); + CrossCrate::foo(y); + y.foo(); } -fn main() { } +fn main() {} diff --git a/src/test/ui/extern/extern-types-not-sync-send.stderr b/src/test/ui/extern/extern-types-not-sync-send.stderr index a1138c3234..dc9810cfcf 100644 --- a/src/test/ui/extern/extern-types-not-sync-send.stderr +++ b/src/test/ui/extern/extern-types-not-sync-send.stderr @@ -7,7 +7,7 @@ LL | fn assert_sync() { } LL | assert_sync::(); | ^ `A` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `A` + = help: the trait `Sync` is not implemented for `A` error[E0277]: `A` cannot be sent between threads safely --> $DIR/extern-types-not-sync-send.rs:16:19 @@ -18,7 +18,7 @@ LL | fn assert_send() { } LL | assert_send::(); | ^ `A` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `A` + = help: the trait `Send` is not implemented for `A` error: aborting due to 2 previous errors diff --git a/src/test/ui/extern/extern-types-unsized.stderr b/src/test/ui/extern/extern-types-unsized.stderr index 8938afd33f..fba919ceff 100644 --- a/src/test/ui/extern/extern-types-unsized.stderr +++ b/src/test/ui/extern/extern-types-unsized.stderr @@ -7,7 +7,7 @@ LL | fn assert_sized() { } LL | assert_sized::(); | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `A` + = help: the trait `Sized` is not implemented for `A` help: consider relaxing the implicit `Sized` restriction | LL | fn assert_sized() { } @@ -22,7 +22,7 @@ LL | fn assert_sized() { } LL | assert_sized::(); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Foo`, the trait `std::marker::Sized` is not implemented for `A` + = help: within `Foo`, the trait `Sized` is not implemented for `A` = note: required because it appears within the type `Foo` help: consider relaxing the implicit `Sized` restriction | @@ -38,7 +38,7 @@ LL | fn assert_sized() { } LL | assert_sized::>(); | ^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar`, the trait `std::marker::Sized` is not implemented for `A` + = help: within `Bar`, the trait `Sized` is not implemented for `A` = note: required because it appears within the type `Bar` help: consider relaxing the implicit `Sized` restriction | @@ -54,7 +54,7 @@ LL | fn assert_sized() { } LL | assert_sized::>>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `Bar>`, the trait `std::marker::Sized` is not implemented for `A` + = help: within `Bar>`, the trait `Sized` is not implemented for `A` = note: required because it appears within the type `Bar` = note: required because it appears within the type `Bar>` help: consider relaxing the implicit `Sized` restriction diff --git a/src/test/ui/extern/extern-wrong-value-type.rs b/src/test/ui/extern/extern-wrong-value-type.rs index aba52427eb..a4d7b00b1c 100644 --- a/src/test/ui/extern/extern-wrong-value-type.rs +++ b/src/test/ui/extern/extern-wrong-value-type.rs @@ -7,5 +7,5 @@ fn main() { // extern functions are extern "C" fn let _x: extern "C" fn() = f; // OK is_fn(f); - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `extern "C" fn() {f}` + //~^ ERROR expected a `Fn<()>` closure, found `extern "C" fn() {f}` } diff --git a/src/test/ui/extern/extern-wrong-value-type.stderr b/src/test/ui/extern/extern-wrong-value-type.stderr index 2cb15f84f6..d92b5f4311 100644 --- a/src/test/ui/extern/extern-wrong-value-type.stderr +++ b/src/test/ui/extern/extern-wrong-value-type.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<()>` closure, found `extern "C" fn() {f}` +error[E0277]: expected a `Fn<()>` closure, found `extern "C" fn() {f}` --> $DIR/extern-wrong-value-type.rs:9:11 | LL | fn is_fn(_: F) where F: Fn() {} @@ -7,7 +7,7 @@ LL | fn is_fn(_: F) where F: Fn() {} LL | is_fn(f); | ^ expected an `Fn<()>` closure, found `extern "C" fn() {f}` | - = help: the trait `std::ops::Fn<()>` is not implemented for `extern "C" fn() {f}` + = 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 */ }` error: aborting due to previous error diff --git a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr index 5a58e57d36..5f78775f54 100644 --- a/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr +++ b/src/test/ui/extern/issue-36122-accessing-externed-dst.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[usize]` cannot be known at compilati LL | static symbol: [usize]; | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[usize]` + = help: the trait `Sized` is not implemented for `[usize]` error: aborting due to previous error diff --git a/src/test/ui/fat-ptr-cast.stderr b/src/test/ui/fat-ptr-cast.stderr index 56d5a26beb..0b0c288fe3 100644 --- a/src/test/ui/fat-ptr-cast.stderr +++ b/src/test/ui/fat-ptr-cast.stderr @@ -30,7 +30,7 @@ LL | a as u32; | = help: cast through a raw pointer first -error[E0605]: non-primitive cast: `std::boxed::Box<[i32]>` as `usize` +error[E0605]: non-primitive cast: `Box<[i32]>` as `usize` --> $DIR/fat-ptr-cast.rs:14:5 | LL | b as usize; diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs new file mode 100644 index 0000000000..3ac8ba5232 --- /dev/null +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.rs @@ -0,0 +1,91 @@ +// This is testing whether various builtin attributes signals an +// error or warning when put in "weird" places. +// +// (This file sits on its own because it actually signals an error, +// which would mess up the treatment of other cases in +// issue-43106-gating-of-builtin-attrs.rs) + +// ignore-tidy-linelength + +// Crate-level is accepted, though it is almost certainly unused? +#![inline] + +#[inline] +//~^ ERROR attribute should be applied to function or closure +mod inline { + //~^ NOTE not a function or closure + + mod inner { #![inline] } + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline = "2100"] fn f() { } + //~^ ERROR attribute must be of the form + //~| WARN this was previously accepted + //~| NOTE #[deny(ill_formed_attribute_input)]` on by default + //~| NOTE for more information, see issue #57571 + + #[inline] struct S; + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline] type T = S; + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure + + #[inline] impl S { } + //~^ ERROR attribute should be applied to function or closure + //~| NOTE not a function or closure +} + +#[no_link] +//~^ ERROR attribute should be applied to an `extern crate` item +mod no_link { + //~^ NOTE not an `extern crate` item + + mod inner { #![no_link] } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] fn f() { } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] struct S; + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link]type T = S; + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item + + #[no_link] impl S { } + //~^ ERROR attribute should be applied to an `extern crate` item + //~| NOTE not an `extern crate` item +} + +#[export_name = "2200"] +//~^ ERROR attribute should be applied to a function or static +mod export_name { + //~^ NOTE not a function or static + + mod inner { #![export_name="2200"] } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] fn f() { } + + #[export_name = "2200"] struct S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] type T = S; + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static + + #[export_name = "2200"] impl S { } + //~^ ERROR attribute should be applied to a function or static + //~| NOTE not a function or static +} + +fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr new file mode 100644 index 0000000000..c9255d2be1 --- /dev/null +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs-error.stderr @@ -0,0 +1,136 @@ +error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:22:5 + | +LL | #[inline = "2100"] fn f() { } + | ^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(ill_formed_attribute_input)]` 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 #57571 + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:13:1 + | +LL | #[inline] + | ^^^^^^^^^ +LL | +LL | / mod inline { +LL | | +LL | | +LL | | mod inner { #![inline] } +... | +LL | | +LL | | } + | |_- not a function or closure + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:41:1 + | +LL | #[no_link] + | ^^^^^^^^^^ +LL | +LL | / mod no_link { +LL | | +LL | | +LL | | mod inner { #![no_link] } +... | +LL | | +LL | | } + | |_- not an `extern crate` item + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:67:1 + | +LL | #[export_name = "2200"] + | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / mod export_name { +LL | | +LL | | +LL | | mod inner { #![export_name="2200"] } +... | +LL | | +LL | | } + | |_- not a function or static + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:18:17 + | +LL | mod inner { #![inline] } + | ------------^^^^^^^^^^-- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:28:5 + | +LL | #[inline] struct S; + | ^^^^^^^^^ --------- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:32:5 + | +LL | #[inline] type T = S; + | ^^^^^^^^^ ----------- not a function or closure + +error[E0518]: attribute should be applied to function or closure + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:36:5 + | +LL | #[inline] impl S { } + | ^^^^^^^^^ ---------- not a function or closure + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:46:17 + | +LL | mod inner { #![no_link] } + | ------------^^^^^^^^^^^-- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:50:5 + | +LL | #[no_link] fn f() { } + | ^^^^^^^^^^ ---------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:54:5 + | +LL | #[no_link] struct S; + | ^^^^^^^^^^ --------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:58:5 + | +LL | #[no_link]type T = S; + | ^^^^^^^^^^----------- not an `extern crate` item + +error: attribute should be applied to an `extern crate` item + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:62:5 + | +LL | #[no_link] impl S { } + | ^^^^^^^^^^ ---------- not an `extern crate` item + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:72:17 + | +LL | mod inner { #![export_name="2200"] } + | ------------^^^^^^^^^^^^^^^^^^^^^^-- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:78:5 + | +LL | #[export_name = "2200"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:82:5 + | +LL | #[export_name = "2200"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static + +error: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs-error.rs:86:5 + | +LL | #[export_name = "2200"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static + +error: aborting due to 17 previous errors + +For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs index f702b10ccd..f94434f459 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.rs @@ -31,14 +31,19 @@ // occurrences in the source text. // check-pass +// ignore-tidy-linelength #![feature(test, plugin_registrar)] #![warn(unused_attributes, unknown_lints)] +//~^ NOTE the lint level is defined here +//~| NOTE the lint level is defined here // Exception, a gated and deprecated attribute. -#![plugin_registrar] //~ WARN unused attribute +#![plugin_registrar] +//~^ WARN unused attribute //~| WARN use of deprecated attribute +//~| HELP may be removed in a future compiler version // UNGATED WHITE-LISTED BUILT-IN ATTRIBUTES @@ -72,7 +77,7 @@ #![doc = "2400"] #![cold] #![export_name = "2200"] -// see issue-43106-gating-of-inline.rs +// see issue-43106-gating-of-builtin-attrs-error.rs #![link()] #![link_name = "1900"] #![link_section = "1800"] @@ -88,12 +93,18 @@ #![crate_name = "0900"] #![crate_type = "bin"] // cannot pass "0800" here -#![crate_id = "10"] //~ WARN use of deprecated attribute +#![crate_id = "10"] +//~^ WARN use of deprecated attribute +//~| HELP remove this attribute // FIXME(#44232) we should warn that this isn't used. -#![feature(rust1)] //~ WARN no longer requires an attribute to enable +#![feature(rust1)] +//~^ WARN no longer requires an attribute to enable +//~| NOTE `#[warn(stable_features)]` on by default -#![no_start] //~ WARN use of deprecated attribute +#![no_start] +//~^ WARN use of deprecated attribute +//~| HELP remove this attribute // (cannot easily gating state of crate-level #[no_main]; but non crate-level is below at "0400") #![no_builtins] @@ -217,24 +228,30 @@ mod macro_export { #[plugin_registrar] //~^ WARN unused attribute //~| WARN use of deprecated attribute +//~| HELP may be removed in a future compiler version mod plugin_registrar { mod inner { #![plugin_registrar] } //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version + //~| NOTE `#[warn(deprecated)]` on by default // for `fn f()` case, see gated-plugin_registrar.rs #[plugin_registrar] struct S; //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version #[plugin_registrar] type T = S; //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version #[plugin_registrar] impl S { } //~^ WARN unused attribute //~| WARN use of deprecated attribute + //~| HELP may be removed in a future compiler version } #[main] @@ -355,35 +372,31 @@ mod automatically_derived { } #[no_mangle] +//~^ WARN attribute should be applied to a function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! mod no_mangle { + //~^ NOTE not a function or static mod inner { #![no_mangle] } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] fn f() { } #[no_mangle] struct S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] type T = S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static #[no_mangle] impl S { } -} - -#[no_link] -//~^ WARN unused attribute -mod no_link { - mod inner { #![no_link] } - //~^ WARN unused attribute - - #[no_link] fn f() { } - //~^ WARN unused attribute - - #[no_link] struct S; - //~^ WARN unused attribute - - #[no_link]type T = S; - //~^ WARN unused attribute - - #[no_link] impl S { } - //~^ WARN unused attribute + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static } #[should_panic] @@ -468,6 +481,7 @@ mod reexport_test_harness_main { mod macro_escape { mod inner { #![macro_escape] } //~^ WARN `#[macro_escape]` is a deprecated synonym for `#[macro_use]` + //~| HELP try an outer attribute: `#[macro_use]` #[macro_escape] fn f() { } //~^ WARN unused attribute @@ -525,31 +539,103 @@ mod doc { } #[cold] +//~^ WARN attribute should be applied to a function +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! mod cold { + //~^ NOTE not a function + mod inner { #![cold] } + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function #[cold] fn f() { } #[cold] struct S; + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function #[cold] type T = S; + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function #[cold] impl S { } + //~^ WARN attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function } -#[export_name = "2200"] -mod export_name { - mod inner { #![export_name="2200"] } +#[link_name = "1900"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +mod link_name { + //~^ NOTE not a foreign function or static - #[export_name = "2200"] fn f() { } + #[link_name = "1900"] + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| HELP try `#[link(name = "1900")]` instead + extern { } + //~^ NOTE not a foreign function or static - #[export_name = "2200"] struct S; + mod inner { #![link_name="1900"] } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static - #[export_name = "2200"] type T = S; + #[link_name = "1900"] fn f() { } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static - #[export_name = "2200"] impl S { } + #[link_name = "1900"] struct S; + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static + + #[link_name = "1900"] type T = S; + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static + + #[link_name = "1900"] impl S { } + //~^ WARN attribute should be applied to a foreign function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a foreign function or static } +#[link_section = "1800"] +//~^ WARN attribute should be applied to a function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +mod link_section { + //~^ NOTE not a function or static + + mod inner { #![link_section="1800"] } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static + + #[link_section = "1800"] fn f() { } + + #[link_section = "1800"] struct S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static + + #[link_section = "1800"] type T = S; + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static + + #[link_section = "1800"] impl S { } + //~^ WARN attribute should be applied to a function or static [unused_attributes] + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + //~| NOTE not a function or static +} + + // Note that this is a `check-pass` test, so it // will never invoke the linker. These are here nonetheless to point // out that we allow them at non-crate-level (though I do not know @@ -568,32 +654,6 @@ mod link { #[link()] impl S { } } -#[link_name = "1900"] -mod link_name { - mod inner { #![link_name="1900"] } - - #[link_name = "1900"] fn f() { } - - #[link_name = "1900"] struct S; - - #[link_name = "1900"] type T = S; - - #[link_name = "1900"] impl S { } -} - -#[link_section = "1800"] -mod link_section { - mod inner { #![link_section="1800"] } - - #[link_section = "1800"] fn f() { } - - #[link_section = "1800"] struct S; - - #[link_section = "1800"] type T = S; - - #[link_section = "1800"] impl S { } -} - struct StructForDeprecated; #[deprecated] diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr index 02bed6723b..461c1bd610 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-builtin-attrs.stderr @@ -1,185 +1,185 @@ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:45:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:9 | LL | #![warn(x5400)] | ^^^^^ | note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:28 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:28 | LL | #![warn(unused_attributes, unknown_lints)] | ^^^^^^^^^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:46:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:51:10 | LL | #![allow(x5300)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:47:11 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:52:11 | LL | #![forbid(x5200)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:48:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:9 | LL | #![deny(x5100)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:116:8 | LL | #[warn(x5400)] | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:108:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:119:25 | LL | mod inner { #![warn(x5400)] } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:111:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:122:12 | LL | #[warn(x5400)] fn f() { } | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:114:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:125:12 | LL | #[warn(x5400)] struct S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:117:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:128:12 | LL | #[warn(x5400)] type T = S; | ^^^^^ warning: unknown lint: `x5400` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:120:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:131:12 | LL | #[warn(x5400)] impl S { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:124:9 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:135:9 | LL | #[allow(x5300)] | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:127:26 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:138:26 | LL | mod inner { #![allow(x5300)] } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:130:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:141:13 | LL | #[allow(x5300)] fn f() { } | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:133:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:144:13 | LL | #[allow(x5300)] struct S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:136:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:147:13 | LL | #[allow(x5300)] type T = S; | ^^^^^ warning: unknown lint: `x5300` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:139:13 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:150:13 | LL | #[allow(x5300)] impl S { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:143:10 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:154:10 | LL | #[forbid(x5200)] | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:146:27 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:157:27 | LL | mod inner { #![forbid(x5200)] } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:149:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:160:14 | LL | #[forbid(x5200)] fn f() { } | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:152:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:163:14 | LL | #[forbid(x5200)] struct S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:155:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:166:14 | LL | #[forbid(x5200)] type T = S; | ^^^^^ warning: unknown lint: `x5200` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:158:14 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:169:14 | LL | #[forbid(x5200)] impl S { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:162:8 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:173:8 | LL | #[deny(x5100)] | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:165:25 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:176:25 | LL | mod inner { #![deny(x5100)] } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:168:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:179:12 | LL | #[deny(x5100)] fn f() { } | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:171:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:182:12 | LL | #[deny(x5100)] struct S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:174:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:12 | LL | #[deny(x5100)] type T = S; | ^^^^^ warning: unknown lint: `x5100` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:177:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:12 | LL | #[deny(x5100)] impl S { } | ^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:466:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:479:1 | LL | #[macro_escape] | ^^^^^^^^^^^^^^^ warning: `#[macro_escape]` is a deprecated synonym for `#[macro_use]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:469:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:482:17 | LL | mod inner { #![macro_escape] } | ^^^^^^^^^^^^^^^^ @@ -187,7 +187,7 @@ LL | mod inner { #![macro_escape] } = help: try an outer attribute: `#[macro_use]` warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version @@ -195,49 +195,274 @@ LL | mod inner { #![plugin_registrar] } = note: `#[warn(deprecated)]` on by default warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `plugin_registrar`: compiler plugins are deprecated. See https://github.com/rust-lang/rust/pull/64675 - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1 | LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ help: may be removed in a future compiler version warning: use of deprecated attribute `crate_id`: no longer used. - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:91:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1 | LL | #![crate_id = "10"] | ^^^^^^^^^^^^^^^^^^^ help: remove this attribute warning: use of deprecated attribute `no_start`: no longer used. - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:96:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:105:1 | LL | #![no_start] | ^^^^^^^^^^^^ help: remove this attribute +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:374:1 + | +LL | #[no_mangle] + | ^^^^^^^^^^^^ +... +LL | / mod no_mangle { +LL | | +LL | | mod inner { #![no_mangle] } +LL | | +... | +LL | | +LL | | } + | |_- not a function or static + | +note: the lint level is defined here + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:37:9 + | +LL | #![warn(unused_attributes, unknown_lints)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:541:1 + | +LL | #[cold] + | ^^^^^^^ +... +LL | / mod cold { +LL | | +LL | | +LL | | mod inner { #![cold] } +... | +LL | | +LL | | } + | |_- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:570:1 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | / mod link_name { +LL | | +LL | | +LL | | #[link_name = "1900"] +... | +LL | | +LL | | } + | |_- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:609:1 + | +LL | #[link_section = "1800"] + | ^^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / mod link_section { +LL | | +LL | | +LL | | mod inner { #![link_section="1800"] } +... | +LL | | +LL | | } + | |_- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:17 + | +LL | mod inner { #![no_mangle] } + | ------------^^^^^^^^^^^^^-- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:386:5 + | +LL | #[no_mangle] struct S; + | ^^^^^^^^^^^^ --------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:391:5 + | +LL | #[no_mangle] type T = S; + | ^^^^^^^^^^^^ ----------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:396:5 + | +LL | #[no_mangle] impl S { } + | ^^^^^^^^^^^^ ---------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:547:17 + | +LL | mod inner { #![cold] } + | ------------^^^^^^^^-- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:554:5 + | +LL | #[cold] struct S; + | ^^^^^^^ --------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:559:5 + | +LL | #[cold] type T = S; + | ^^^^^^^ ----------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:564:5 + | +LL | #[cold] impl S { } + | ^^^^^^^ ---------- not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ +... +LL | extern { } + | ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: try `#[link(name = "1900")]` instead + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:576:5 + | +LL | #[link_name = "1900"] + | ^^^^^^^^^^^^^^^^^^^^^ + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:583:17 + | +LL | mod inner { #![link_name="1900"] } + | ------------^^^^^^^^^^^^^^^^^^^^-- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:588:5 + | +LL | #[link_name = "1900"] fn f() { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:593:5 + | +LL | #[link_name = "1900"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^ --------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:598:5 + | +LL | #[link_name = "1900"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^ ----------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:603:5 + | +LL | #[link_name = "1900"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^ ---------- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:615:17 + | +LL | mod inner { #![link_section="1800"] } + | ------------^^^^^^^^^^^^^^^^^^^^^^^-- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:622:5 + | +LL | #[link_section = "1800"] struct S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ --------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:627:5 + | +LL | #[link_section = "1800"] type T = S; + | ^^^^^^^^^^^^^^^^^^^^^^^^ ----------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a function or static + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:632:5 + | +LL | #[link_section = "1800"] impl S { } + | ^^^^^^^^^^^^^^^^^^^^^^^^ ---------- not a function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + warning: the feature `rust1` has been stable since 1.0.0 and no longer requires an attribute to enable - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:94:12 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:101:12 | LL | #![feature(rust1)] | ^^^^^ @@ -245,994 +470,952 @@ LL | #![feature(rust1)] = note: `#[warn(stable_features)]` on by default warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:185:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:196:5 | LL | #[macro_use] fn f() { } | ^^^^^^^^^^^^ - | -note: the lint level is defined here - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:36:9 - | -LL | #![warn(unused_attributes, unknown_lints)] - | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:188:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:199:5 | LL | #[macro_use] struct S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:191:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:202:5 | LL | #[macro_use] type T = S; | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:194:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:205:5 | LL | #[macro_use] impl S { } | ^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:201:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:212:17 | LL | mod inner { #![macro_export] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:204:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:215:5 | LL | #[macro_export] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:207:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:218:5 | LL | #[macro_export] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:210:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:5 | LL | #[macro_export] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:213:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:224:5 | LL | #[macro_export] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:198:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:209:1 | LL | #[macro_export] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:221:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:233:17 | LL | mod inner { #![plugin_registrar] } | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:227:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:241:5 | LL | #[plugin_registrar] struct S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:231:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:246:5 | LL | #[plugin_registrar] type T = S; | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:235:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 | LL | #[plugin_registrar] impl S { } | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:217:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:228:1 | LL | #[plugin_registrar] | ^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:243:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:260:17 | LL | mod inner { #![main] } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:248:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:265:5 | LL | #[main] struct S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:251:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:268:5 | LL | #[main] type T = S; | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:254:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:271:5 | LL | #[main] impl S { } | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:240:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:257:1 | LL | #[main] | ^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:261:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:278:17 | LL | mod inner { #![start] } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:266:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:283:5 | LL | #[start] struct S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:269:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:286:5 | LL | #[start] type T = S; | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:272:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:289:5 | LL | #[start] impl S { } | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:258:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:275:1 | LL | #[start] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:325:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:342:5 | LL | #[path = "3800"] fn f() { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:328:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:345:5 | LL | #[path = "3800"] struct S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:331:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:348:5 | LL | #[path = "3800"] type T = S; | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:334:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:351:5 | LL | #[path = "3800"] impl S { } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:341:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:358:17 | LL | mod inner { #![automatically_derived] } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:344:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:361:5 | LL | #[automatically_derived] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:347:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:364:5 | LL | #[automatically_derived] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:350:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:367:5 | LL | #[automatically_derived] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:353:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:5 | LL | #[automatically_derived] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:338:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:355:1 | LL | #[automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:373:17 - | -LL | mod inner { #![no_link] } - | ^^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:376:5 - | -LL | #[no_link] fn f() { } - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:379:5 - | -LL | #[no_link] struct S; - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:382:5 - | -LL | #[no_link]type T = S; - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:385:5 - | -LL | #[no_link] impl S { } - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:370:1 - | -LL | #[no_link] - | ^^^^^^^^^^ - -warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:392:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:405:17 | LL | mod inner { #![should_panic] } | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:395:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:5 | LL | #[should_panic] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:398:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:5 | LL | #[should_panic] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:401:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 | LL | #[should_panic] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:404:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 | LL | #[should_panic] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:389:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:402:1 | LL | #[should_panic] | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:411:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:424:17 | LL | mod inner { #![ignore] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:414:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:5 | LL | #[ignore] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:417:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:5 | LL | #[ignore] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:420:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 | LL | #[ignore] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:423:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 | LL | #[ignore] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:408:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:421:1 | LL | #[ignore] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:430:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:443:17 | LL | mod inner { #![no_implicit_prelude] } | ^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:433:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:5 | LL | #[no_implicit_prelude] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:436:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:5 | LL | #[no_implicit_prelude] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:439:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 | LL | #[no_implicit_prelude] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:442:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 | LL | #[no_implicit_prelude] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:427:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:440:1 | LL | #[no_implicit_prelude] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:449:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:462:17 | LL | mod inner { #![reexport_test_harness_main="2900"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:452:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:465:5 | LL | #[reexport_test_harness_main = "2900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:455:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:468:5 | LL | #[reexport_test_harness_main = "2900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:458:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:471:5 | LL | #[reexport_test_harness_main = "2900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:461:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:474:5 | LL | #[reexport_test_harness_main = "2900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:446:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:459:1 | LL | #[reexport_test_harness_main = "2900"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:472:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:486:5 | LL | #[macro_escape] fn f() { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:475:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:5 | LL | #[macro_escape] struct S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:478:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:492:5 | LL | #[macro_escape] type T = S; | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:481:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:495:5 | LL | #[macro_escape] impl S { } | ^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:489:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:503:17 | LL | mod inner { #![no_std] } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:493:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:507:5 | LL | #[no_std] fn f() { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:497:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:511:5 | LL | #[no_std] struct S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:501:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:515:5 | LL | #[no_std] type T = S; | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:505:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:519:5 | LL | #[no_std] impl S { } | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1 | LL | #[no_std] | ^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:485:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:499:1 | LL | #[no_std] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:644:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:704:17 | LL | mod inner { #![crate_name="0900"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:648:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:708:5 | LL | #[crate_name = "0900"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:652:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:712:5 | LL | #[crate_name = "0900"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:656:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:5 | LL | #[crate_name = "0900"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:660:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:5 | LL | #[crate_name = "0900"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:640:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:700:1 | LL | #[crate_name = "0900"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:669:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:729:17 | LL | mod inner { #![crate_type="0800"] } | ^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:673:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:733:5 | LL | #[crate_type = "0800"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:677:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:737:5 | LL | #[crate_type = "0800"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:681:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:741:5 | LL | #[crate_type = "0800"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:685:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:745:5 | LL | #[crate_type = "0800"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:665:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:725:1 | LL | #[crate_type = "0800"] | ^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:694:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:17 | LL | mod inner { #![feature(x0600)] } | ^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:698:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:5 | LL | #[feature(x0600)] fn f() { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:702:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 | LL | #[feature(x0600)] struct S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:706:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 | LL | #[feature(x0600)] type T = S; | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:710:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 | LL | #[feature(x0600)] impl S { } | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:690:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:750:1 | LL | #[feature(x0600)] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:720:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:780:17 | LL | mod inner { #![no_main] } | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:724:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:784:5 | LL | #[no_main] fn f() { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:728:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:788:5 | LL | #[no_main] struct S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:732:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:792:5 | LL | #[no_main] type T = S; | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:736:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:796:5 | LL | #[no_main] impl S { } | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1 | LL | #[no_main] | ^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:716:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:776:1 | LL | #[no_main] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:758:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:818:17 | LL | mod inner { #![recursion_limit="0200"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:762:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:822:5 | LL | #[recursion_limit="0200"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:766:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:826:5 | LL | #[recursion_limit="0200"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:770:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:830:5 | LL | #[recursion_limit="0200"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:774:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:834:5 | LL | #[recursion_limit="0200"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:754:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:814:1 | LL | #[recursion_limit="0200"] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be in the root module - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:783:17 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:843:17 | LL | mod inner { #![type_length_limit="0100"] } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:787:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:847:5 | LL | #[type_length_limit="0100"] fn f() { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:791:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:851:5 | LL | #[type_length_limit="0100"] struct S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:795:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:855:5 | LL | #[type_length_limit="0100"] type T = S; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:799:5 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:859:5 | LL | #[type_length_limit="0100"] impl S { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: crate-level attribute should be an inner attribute: add an exclamation mark: `#![foo]` - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:779:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:839:1 | LL | #[type_length_limit="0100"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:40:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:43:1 | LL | #![plugin_registrar] | ^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:50:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:55:1 | LL | #![macro_export] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:53:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:58:1 | LL | #![main] | ^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:54:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 | LL | #![start] | ^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:57:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 | LL | #![repr()] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:59:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 | LL | #![path = "3800"] | ^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:60:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 | LL | #![automatically_derived] | ^^^^^^^^^^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:62:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:67:1 | LL | #![no_link] | ^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:64:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:69:1 | LL | #![should_panic] | ^^^^^^^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:65:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:70:1 | LL | #![ignore] | ^^^^^^^^^^ warning: unused attribute - --> $DIR/issue-43106-gating-of-builtin-attrs.rs:71:1 + --> $DIR/issue-43106-gating-of-builtin-attrs.rs:76:1 | LL | #![proc_macro_derive()] | ^^^^^^^^^^^^^^^^^^^^^^^ -warning: 203 warnings emitted +warning: 219 warnings emitted diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr index db29a2bddd..ffec76f409 100644 --- a/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr +++ b/src/test/ui/feature-gate/issue-43106-gating-of-derive.stderr @@ -1,28 +1,28 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:4:1 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:7:17 | LL | mod inner { #![derive(Debug)] } | ^^^^^^^^^^^^^^^^^ help: try an outer attribute: `#[derive(Debug)]` -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:10:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:23:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43106-gating-of-derive.rs:27:5 | LL | #[derive(Debug)] @@ -30,3 +30,4 @@ LL | #[derive(Debug)] error: aborting due to 5 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs b/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs deleted file mode 100644 index 80c602eb00..0000000000 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.rs +++ /dev/null @@ -1,31 +0,0 @@ -// This is testing whether `#[inline]` signals an error or warning -// when put in "weird" places. -// -// (This file sits on its own because it actually signals an error, -// which would mess up the treatment of other cases in -// issue-43106-gating-of-builtin-attrs.rs) - -// Crate-level is accepted, though it is almost certainly unused? -#![inline] - -#[inline] -//~^ ERROR attribute should be applied to function or closure -mod inline { - mod inner { #![inline] } - //~^ ERROR attribute should be applied to function or closure - - #[inline = "2100"] fn f() { } - //~^ ERROR attribute must be of the form - //~| WARN this was previously accepted - - #[inline] struct S; - //~^ ERROR attribute should be applied to function or closure - - #[inline] type T = S; - //~^ ERROR attribute should be applied to function or closure - - #[inline] impl S { } - //~^ ERROR attribute should be applied to function or closure -} - -fn main() {} diff --git a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr b/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr deleted file mode 100644 index 0987937192..0000000000 --- a/src/test/ui/feature-gate/issue-43106-gating-of-inline.stderr +++ /dev/null @@ -1,52 +0,0 @@ -error: attribute must be of the form `#[inline]` or `#[inline(always|never)]` - --> $DIR/issue-43106-gating-of-inline.rs:17:5 - | -LL | #[inline = "2100"] fn f() { } - | ^^^^^^^^^^^^^^^^^^ - | - = note: `#[deny(ill_formed_attribute_input)]` 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 #57571 - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:11:1 - | -LL | #[inline] - | ^^^^^^^^^ -LL | -LL | / mod inline { -LL | | mod inner { #![inline] } -LL | | -LL | | -... | -LL | | -LL | | } - | |_- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:14:17 - | -LL | mod inner { #![inline] } - | ------------^^^^^^^^^^-- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:21:5 - | -LL | #[inline] struct S; - | ^^^^^^^^^ --------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:24:5 - | -LL | #[inline] type T = S; - | ^^^^^^^^^ ----------- not a function or closure - -error[E0518]: attribute should be applied to function or closure - --> $DIR/issue-43106-gating-of-inline.rs:27:5 - | -LL | #[inline] impl S { } - | ^^^^^^^^^ ---------- not a function or closure - -error: aborting due to 6 previous errors - -For more information about this error, try `rustc --explain E0518`. diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs index 6e0b71bc1e..47ca7e3497 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.rs @@ -23,7 +23,7 @@ impl Foo for Bar { } impl Bar { - fn bar(self: Box>) {} //~ ERROR `std::boxed::Box>` cannot be used as the + fn bar(self: Box>) {} //~ ERROR `Box>` cannot be used as the } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr index f5d74d7a84..a06c4b2b48 100644 --- a/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr +++ b/src/test/ui/feature-gates/feature-gate-arbitrary-self-types.stderr @@ -18,7 +18,7 @@ LL | fn foo(self: Ptr) {} = help: add `#![feature(arbitrary_self_types)]` to the crate attributes to enable = help: consider changing to `self`, `&self`, `&mut self`, `self: Box`, `self: Rc`, `self: Arc`, or `self: Pin

    ` (where P is one of the previous types except `Self`) -error[E0658]: `std::boxed::Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature +error[E0658]: `Box>` cannot be used as the type of `self` without the `arbitrary_self_types` feature --> $DIR/feature-gate-arbitrary-self-types.rs:26:18 | LL | fn bar(self: Box>) {} diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs index 506b21dc7d..049fdd84d8 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.rs @@ -87,6 +87,30 @@ fn main() { //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change cfg!(target_has_atomic = "ptr"); //~^ ERROR `cfg(target_has_atomic)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "8"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "16"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "32"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "64"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "128"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_load_store = "ptr"); + //~^ ERROR `cfg(target_has_atomic_load_store)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "8"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "16"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "32"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "64"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "128"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + cfg!(target_has_atomic_equal_alignment = "ptr"); + //~^ ERROR `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change } #[macro_export] diff --git a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr index 6132c53087..16e1dc6440 100644 --- a/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr +++ b/src/test/ui/feature-gates/feature-gate-cfg-target-has-atomic.stderr @@ -160,6 +160,114 @@ LL | cfg!(target_has_atomic = "ptr"); = note: see issue #32976 for more information = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable -error: aborting due to 18 previous errors +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:90:10 + | +LL | cfg!(target_has_atomic_load_store = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:92:10 + | +LL | cfg!(target_has_atomic_load_store = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:94:10 + | +LL | cfg!(target_has_atomic_load_store = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:96:10 + | +LL | cfg!(target_has_atomic_load_store = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:98:10 + | +LL | cfg!(target_has_atomic_load_store = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_load_store)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:100:10 + | +LL | cfg!(target_has_atomic_load_store = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:102:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "8"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:104:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "16"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:106:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "32"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:108:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "64"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:110:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "128"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error[E0658]: `cfg(target_has_atomic_equal_alignment)` is experimental and subject to change + --> $DIR/feature-gate-cfg-target-has-atomic.rs:112:10 + | +LL | cfg!(target_has_atomic_equal_alignment = "ptr"); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: see issue #32976 for more information + = help: add `#![feature(cfg_target_has_atomic)]` to the crate attributes to enable + +error: aborting due to 30 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs index 981680b5d1..9007e501bc 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.rs @@ -6,33 +6,33 @@ struct Foo(u32); const TRANSMUTED_U32: u32 = unsafe { mem::transmute(Foo(3)) }; const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn transmute_fn_intrinsic() -> u32 { unsafe { std::intrinsics::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn transmute_fn_core_intrinsic() -> u32 { unsafe { core::intrinsics::transmute(Foo(3)) } } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } -//~^ ERROR can only call `transmute` from const items, not `const fn` +//~^ ERROR `transmute` //~| ERROR call to unsafe function is unsafe and requires unsafe function or block fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr index 44430fd577..08ba14dc40 100644 --- a/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_fn_transmute.stderr @@ -1,83 +1,92 @@ -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:8:43 | LL | const fn transmute_fn() -> u32 { unsafe { mem::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:11:53 | LL | const fn transmute_fn_intrinsic() -> u32 { unsafe { std::intrinsics::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:14:58 | LL | const fn transmute_fn_core_intrinsic() -> u32 { unsafe { core::intrinsics::transmute(Foo(3)) } } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:17:48 | LL | const unsafe fn unsafe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:20:58 | LL | const unsafe fn unsafe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:23:63 | LL | const unsafe fn unsafe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:26:39 | LL | const fn safe_transmute_fn() -> u32 { mem::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:30:49 | LL | const fn safe_transmute_fn_intrinsic() -> u32 { std::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/feature-gate-const_fn_transmute.rs:34:54 | LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::transmute(Foo(3)) } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now error[E0133]: call to unsafe function is unsafe and requires unsafe function or block --> $DIR/feature-gate-const_fn_transmute.rs:26:39 @@ -105,5 +114,5 @@ LL | const fn safe_transmute_fn_core_intrinsic() -> u32 { core::intrinsics::tran error: aborting due to 12 previous errors -Some errors have detailed explanations: E0133, E0723. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs index c3c554d7d2..5ed302bbff 100644 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs +++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.rs @@ -1,4 +1,3 @@ -// ignore-tidy-linelength #![allow(warnings)] struct Bar; @@ -6,13 +5,13 @@ struct Bar; // This function would compile with the feature gate, and tests that it is suggested. fn foo() { let arr: [Option; 2] = [None::; 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } // This function would not compile with the feature gate, and tests that it is not suggested. fn bar() { let arr: [Option; 2] = [Some("foo".to_string()); 2]; - //~^ ERROR the trait bound `std::option::Option: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Option: Copy` is not satisfied [E0277] } fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr index 6772178068..ca1706169a 100644 --- a/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr +++ b/src/test/ui/feature-gates/feature-gate-const_in_array_repeat_expressions.stderr @@ -1,23 +1,23 @@ -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:8:36 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:7:36 | LL | let arr: [Option; 2] = [None::; 2]; - | ^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied = note: this array initializer can be evaluated at compile-time, see issue #49147 for more information = help: add `#![feature(const_in_array_repeat_expressions)]` to the crate attributes to enable -error[E0277]: the trait bound `std::option::Option: std::marker::Copy` is not satisfied - --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:14:36 +error[E0277]: the trait bound `Option: Copy` is not satisfied + --> $DIR/feature-gate-const_in_array_repeat_expressions.rs:13:36 | LL | let arr: [Option; 2] = [Some("foo".to_string()); 2]; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Option` | = help: the following implementations were found: - as std::marker::Copy> + as Copy> = note: the `Copy` trait is required because the repeated element will be copied error: aborting due to 2 previous errors diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.rs b/src/test/ui/feature-gates/feature-gate-doc_alias.rs deleted file mode 100644 index c95722102d..0000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.rs +++ /dev/null @@ -1,4 +0,0 @@ -#[doc(alias = "foo")] //~ ERROR: `#[doc(alias)]` is experimental -pub struct Foo; - -fn main() {} diff --git a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr b/src/test/ui/feature-gates/feature-gate-doc_alias.stderr deleted file mode 100644 index f66d1602ba..0000000000 --- a/src/test/ui/feature-gates/feature-gate-doc_alias.stderr +++ /dev/null @@ -1,12 +0,0 @@ -error[E0658]: `#[doc(alias)]` is experimental - --> $DIR/feature-gate-doc_alias.rs:1:1 - | -LL | #[doc(alias = "foo")] - | ^^^^^^^^^^^^^^^^^^^^^ - | - = note: see issue #50146 for more information - = help: add `#![feature(doc_alias)]` to the crate attributes to enable - -error: aborting due to previous error - -For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr index d4c09ec40f..f3fa641209 100644 --- a/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr +++ b/src/test/ui/feature-gates/feature-gate-trivial_bounds.stderr @@ -64,13 +64,13 @@ LL | | } = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable -error[E0277]: the trait bound `std::string::String: std::ops::Neg` is not satisfied +error[E0277]: the trait bound `String: Neg` is not satisfied --> $DIR/feature-gate-trivial_bounds.rs:36:1 | LL | / fn use_op(s: String) -> String where String: ::std::ops::Neg { LL | | -s LL | | } - | |_^ the trait `std::ops::Neg` is not implemented for `std::string::String` + | |_^ the trait `Neg` is not implemented for `String` | = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -83,7 +83,7 @@ LL | | for _ in 2i32 {} LL | | } | |_^ `i32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i32` + = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -94,7 +94,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | struct TwoStrs(str, str) where str: Sized; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -106,7 +106,7 @@ LL | | let x: Dst = *(Box::new(Dst { x: 1 }) as Box>); LL | | } | |_^ doesn't have a size known at compile-time | - = help: within `Dst<(dyn A + 'static)>`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` + = help: within `Dst<(dyn A + 'static)>`, the trait `Sized` is not implemented for `(dyn A + 'static)` = note: required because it appears within the type `Dst<(dyn A + 'static)>` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable @@ -119,7 +119,7 @@ LL | | *"Sized".to_string().into_boxed_str() LL | | } | |_^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: see issue #48214 = help: add `#![feature(trivial_bounds)]` to the crate attributes to enable diff --git a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr index 0195cc1481..29595c9237 100644 --- a/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr +++ b/src/test/ui/feature-gates/feature-gate-unsized_locals.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `(dyn std::ops::FnOnce() + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn FnOnce() + 'static)` cannot be known at compilation time --> $DIR/feature-gate-unsized_locals.rs:1:6 | LL | fn f(f: dyn FnOnce()) {} | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::FnOnce() + 'static)` + = help: the trait `Sized` is not implemented for `(dyn FnOnce() + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/ffi_const.stderr b/src/test/ui/ffi_const.stderr index 623551cc07..bc3c12eaf9 100644 --- a/src/test/ui/ffi_const.stderr +++ b/src/test/ui/ffi_const.stderr @@ -6,3 +6,4 @@ LL | #[ffi_const] error: aborting due to previous error +For more information about this error, try `rustc --explain E0756`. diff --git a/src/test/ui/ffi_pure.stderr b/src/test/ui/ffi_pure.stderr index 3a849c0bca..bc911c85dd 100644 --- a/src/test/ui/ffi_pure.stderr +++ b/src/test/ui/ffi_pure.stderr @@ -6,3 +6,4 @@ LL | #[ffi_pure] error: aborting due to previous error +For more information about this error, try `rustc --explain E0755`. diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.rs b/src/test/ui/fmt/format-args-capture-missing-variables.rs index 3c596ae3bb..3a4b6144b0 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.rs +++ b/src/test/ui/fmt/format-args-capture-missing-variables.rs @@ -5,7 +5,7 @@ fn main() { //~^ ERROR: cannot find value `foo` in this scope //~^^ ERROR: cannot find value `bar` in this scope - format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope + format!("{foo}"); //~ ERROR: cannot find value `foo` in this scope format!("{valuea} {valueb}", valuea=5, valuec=7); //~^ ERROR cannot find value `valueb` in this scope @@ -16,7 +16,7 @@ fn main() { {foo} "##); - //~^^^^^ ERROR: cannot find value `foo` in this scope + //~^^^ ERROR: cannot find value `foo` in this scope - panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope + panic!("{foo} {bar}", bar=1); //~ ERROR: cannot find value `foo` in this scope } diff --git a/src/test/ui/fmt/format-args-capture-missing-variables.stderr b/src/test/ui/fmt/format-args-capture-missing-variables.stderr index c3d740eef9..ec2faa4185 100644 --- a/src/test/ui/fmt/format-args-capture-missing-variables.stderr +++ b/src/test/ui/fmt/format-args-capture-missing-variables.stderr @@ -7,45 +7,40 @@ LL | format!("{valuea} {valueb}", valuea=5, valuec=7); | formatting specifier missing error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:17 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `bar` in this scope - --> $DIR/format-args-capture-missing-variables.rs:4:13 + --> $DIR/format-args-capture-missing-variables.rs:4:26 | LL | format!("{} {foo} {} {bar} {}", 1, 2, 3); - | ^^^^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:8:13 + --> $DIR/format-args-capture-missing-variables.rs:8:14 | LL | format!("{foo}"); - | ^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error[E0425]: cannot find value `valueb` in this scope - --> $DIR/format-args-capture-missing-variables.rs:10:13 + --> $DIR/format-args-capture-missing-variables.rs:10:23 | LL | format!("{valuea} {valueb}", valuea=5, valuec=7); - | ^^^^^^^^^^^^^^^^^^^ not found in this scope + | ^^^^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:14:13 + --> $DIR/format-args-capture-missing-variables.rs:16:9 | -LL | format!(r##" - | _____________^ -LL | | -LL | | {foo} -LL | | -LL | | "##); - | |_______^ not found in this scope +LL | {foo} + | ^^^^^ not found in this scope error[E0425]: cannot find value `foo` in this scope - --> $DIR/format-args-capture-missing-variables.rs:21:12 + --> $DIR/format-args-capture-missing-variables.rs:21:13 | LL | panic!("{foo} {bar}", bar=1); - | ^^^^^^^^^^^^^ not found in this scope + | ^^^^^ not found in this scope error: aborting due to 7 previous errors diff --git a/src/test/ui/fmt/incorrect-separator.rs b/src/test/ui/fmt/incorrect-separator.rs new file mode 100644 index 0000000000..b8d2e4a347 --- /dev/null +++ b/src/test/ui/fmt/incorrect-separator.rs @@ -0,0 +1,29 @@ +// Allows to track issue #75492: +// https://github.com/rust-lang/rust/issues/75492 + +use std::iter; + +fn main() { + format!("A number: {}". iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `.` + + // Other kind of types are also checked: + + format!("A number: {}" / iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `/` + + format!("A number: {}"; iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `;` + + // Note: this character is an COMBINING COMMA BELOW unicode char + format!("A number: {}" ̦ iter::once(42).next().unwrap()); + //~^ ERROR expected `,`, found `iter` + //~^^ ERROR unknown start of token: \u{326} + + // Here recovery is tested. + // If the `compile_error!` is emitted, then the parser is able to recover + // from the incorrect first separator. + format!("{}". compile_error!("fail")); + //~^ ERROR expected `,`, found `.` + //~^^ ERROR fail +} diff --git a/src/test/ui/fmt/incorrect-separator.stderr b/src/test/ui/fmt/incorrect-separator.stderr new file mode 100644 index 0000000000..5a3e5515bb --- /dev/null +++ b/src/test/ui/fmt/incorrect-separator.stderr @@ -0,0 +1,44 @@ +error: unknown start of token: \u{326} + --> $DIR/incorrect-separator.rs:19:28 + | +LL | format!("A number: {}" ̦ iter::once(42).next().unwrap()); + | ^ + +error: expected `,`, found `.` + --> $DIR/incorrect-separator.rs:7:27 + | +LL | format!("A number: {}". iter::once(42).next().unwrap()); + | ^ expected `,` + +error: expected `,`, found `/` + --> $DIR/incorrect-separator.rs:12:28 + | +LL | format!("A number: {}" / iter::once(42).next().unwrap()); + | ^ expected `,` + +error: expected `,`, found `;` + --> $DIR/incorrect-separator.rs:15:27 + | +LL | format!("A number: {}"; iter::once(42).next().unwrap()); + | ^ expected `,` + +error: expected `,`, found `iter` + --> $DIR/incorrect-separator.rs:19:30 + | +LL | format!("A number: {}" ̦ iter::once(42).next().unwrap()); + | ^^^^ expected `,` + +error: expected `,`, found `.` + --> $DIR/incorrect-separator.rs:26:17 + | +LL | format!("{}". compile_error!("fail")); + | ^ expected `,` + +error: fail + --> $DIR/incorrect-separator.rs:26:19 + | +LL | format!("{}". compile_error!("fail")); + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/fmt/send-sync.stderr b/src/test/ui/fmt/send-sync.stderr index b3b53971a3..780c71128d 100644 --- a/src/test/ui/fmt/send-sync.stderr +++ b/src/test/ui/fmt/send-sync.stderr @@ -7,12 +7,12 @@ LL | fn send(_: T) {} LL | send(format_args!("{:?}", c)); | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `[std::fmt::ArgumentV1<'_>]`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = help: within `[ArgumentV1<'_>]`, the trait `Sync` is not implemented for `core::fmt::Opaque` = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` - = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` - = note: required because of the requirements on the impl of `std::marker::Send` for `&[std::fmt::ArgumentV1<'_>]` - = note: required because it appears within the type `std::fmt::Arguments<'_>` + = note: required because it appears within the type `ArgumentV1<'_>` + = note: required because it appears within the type `[ArgumentV1<'_>]` + = note: required because of the requirements on the impl of `Send` for `&[ArgumentV1<'_>]` + = note: required because it appears within the type `Arguments<'_>` error[E0277]: `core::fmt::Opaque` cannot be shared between threads safely --> $DIR/send-sync.rs:9:5 @@ -23,12 +23,12 @@ LL | fn sync(_: T) {} LL | sync(format_args!("{:?}", c)); | ^^^^ `core::fmt::Opaque` cannot be shared between threads safely | - = help: within `std::fmt::Arguments<'_>`, the trait `std::marker::Sync` is not implemented for `core::fmt::Opaque` + = help: within `Arguments<'_>`, the trait `Sync` is not implemented for `core::fmt::Opaque` = note: required because it appears within the type `&core::fmt::Opaque` - = note: required because it appears within the type `std::fmt::ArgumentV1<'_>` - = note: required because it appears within the type `[std::fmt::ArgumentV1<'_>]` - = note: required because it appears within the type `&[std::fmt::ArgumentV1<'_>]` - = note: required because it appears within the type `std::fmt::Arguments<'_>` + = note: required because it appears within the type `ArgumentV1<'_>` + = note: required because it appears within the type `[ArgumentV1<'_>]` + = note: required because it appears within the type `&[ArgumentV1<'_>]` + = note: required because it appears within the type `Arguments<'_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/fn/fn-compare-mismatch.stderr b/src/test/ui/fn/fn-compare-mismatch.stderr index fa74d027f1..326418ecbf 100644 --- a/src/test/ui/fn/fn-compare-mismatch.stderr +++ b/src/test/ui/fn/fn-compare-mismatch.stderr @@ -1,10 +1,10 @@ -error[E0369]: binary operation `==` cannot be applied to type `fn() {main::f}` +error[E0369]: binary operation `==` cannot be applied to type `fn() {f}` --> $DIR/fn-compare-mismatch.rs:4:15 | LL | let x = f == g; - | - ^^ - fn() {main::g} + | - ^^ - fn() {g} | | - | fn() {main::f} + | fn() {f} | help: you might have forgotten to call this function | @@ -21,8 +21,8 @@ error[E0308]: mismatched types LL | let x = f == g; | ^ expected fn item, found a different fn item | - = note: expected fn item `fn() {main::f}` - found fn item `fn() {main::g}` + = note: expected fn item `fn() {f}` + found fn item `fn() {g}` error: aborting due to 2 previous errors diff --git a/src/test/ui/fn/fn-item-type.rs b/src/test/ui/fn/fn-item-type.rs index abae40162a..415e87b42f 100644 --- a/src/test/ui/fn/fn-item-type.rs +++ b/src/test/ui/fn/fn-item-type.rs @@ -28,9 +28,9 @@ fn main() { eq(bar::, bar::>); //~^ ERROR mismatched types - //~| expected fn item `fn(_) -> _ {bar::}` - //~| found fn item `fn(_) -> _ {bar::>}` - //~| expected struct `std::string::String`, found struct `std::vec::Vec` + //~| expected fn item `fn(_) -> _ {bar::}` + //~| found fn item `fn(_) -> _ {bar::>}` + //~| expected struct `String`, found struct `Vec` //~| different `fn` items always have unique types, even if their signatures are the same //~| change the expected type to be function pointer //~| if the expected type is due to type inference, cast the expected `fn` to a function pointer diff --git a/src/test/ui/fn/fn-item-type.stderr b/src/test/ui/fn/fn-item-type.stderr index bfa9efa219..4bd51a668a 100644 --- a/src/test/ui/fn/fn-item-type.stderr +++ b/src/test/ui/fn/fn-item-type.stderr @@ -26,13 +26,13 @@ error[E0308]: mismatched types --> $DIR/fn-item-type.rs:29:23 | LL | eq(bar::, bar::>); - | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec` + | ^^^^^^^^^^^^^^ expected struct `String`, found struct `Vec` | - = note: expected fn item `fn(_) -> _ {bar::}` - found fn item `fn(_) -> _ {bar::>}` + = note: expected fn item `fn(_) -> _ {bar::}` + found fn item `fn(_) -> _ {bar::>}` = note: different `fn` items always have unique types, even if their signatures are the same = help: change the expected type to be function pointer `fn(isize) -> isize` - = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar:: as fn(isize) -> isize` + = help: if the expected type is due to type inference, cast the expected `fn` to a function pointer: `bar:: as fn(isize) -> isize` error[E0308]: mismatched types --> $DIR/fn-item-type.rs:39:26 diff --git a/src/test/ui/fn/fn-trait-formatting.rs b/src/test/ui/fn/fn-trait-formatting.rs index 63ab8e88e4..0c389e1dc5 100644 --- a/src/test/ui/fn/fn-trait-formatting.rs +++ b/src/test/ui/fn/fn-trait-formatting.rs @@ -6,16 +6,16 @@ fn main() { let _: () = (box |_: isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` - //~| found struct `std::boxed::Box` + //~| found struct `Box` let _: () = (box |_: isize, isize| {}) as Box; //~^ ERROR mismatched types //~| expected unit type `()` - //~| found struct `std::boxed::Box` + //~| found struct `Box` let _: () = (box || -> isize { unimplemented!() }) as Box isize>; //~^ ERROR mismatched types //~| expected unit type `()` - //~| found struct `std::boxed::Box isize>` + //~| found struct `Box isize>` needs_fn(1); - //~^ ERROR expected a `std::ops::Fn<(isize,)>` closure, found `{integer}` + //~^ ERROR expected a `Fn<(isize,)>` closure, found `{integer}` } diff --git a/src/test/ui/fn/fn-trait-formatting.stderr b/src/test/ui/fn/fn-trait-formatting.stderr index e3ada4f6ba..5b63b8e228 100644 --- a/src/test/ui/fn/fn-trait-formatting.stderr +++ b/src/test/ui/fn/fn-trait-formatting.stderr @@ -2,36 +2,36 @@ error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:6:17 | LL | let _: () = (box |_: isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `std::boxed::Box` + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | = note: expected unit type `()` - found struct `std::boxed::Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:10:17 | LL | let _: () = (box |_: isize, isize| {}) as Box; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `std::boxed::Box` + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | = note: expected unit type `()` - found struct `std::boxed::Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/fn-trait-formatting.rs:14:17 | LL | let _: () = (box || -> isize { unimplemented!() }) as Box isize>; - | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `std::boxed::Box` + | -- ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `()`, found struct `Box` | | | expected due to this | = note: expected unit type `()` - found struct `std::boxed::Box isize>` + found struct `Box isize>` -error[E0277]: expected a `std::ops::Fn<(isize,)>` closure, found `{integer}` +error[E0277]: expected a `Fn<(isize,)>` closure, found `{integer}` --> $DIR/fn-trait-formatting.rs:19:14 | LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} @@ -40,7 +40,7 @@ LL | fn needs_fn(x: F) where F: Fn(isize) -> isize {} LL | needs_fn(1); | ^ expected an `Fn<(isize,)>` closure, found `{integer}` | - = help: the trait `std::ops::Fn<(isize,)>` is not implemented for `{integer}` + = help: the trait `Fn<(isize,)>` is not implemented for `{integer}` error: aborting due to 4 previous errors diff --git a/src/test/ui/for/for-c-in-str.rs b/src/test/ui/for/for-c-in-str.rs index 1871cf9d23..df66127c60 100644 --- a/src/test/ui/for/for-c-in-str.rs +++ b/src/test/ui/for/for-c-in-str.rs @@ -4,8 +4,8 @@ fn main() { for c in "asdf" { //~^ ERROR `&str` is not an iterator //~| NOTE `&str` is not an iterator - //~| HELP the trait `std::iter::Iterator` is not implemented for `&str` - //~| NOTE required by `std::iter::IntoIterator::into_iter` + //~| HELP the trait `Iterator` is not implemented for `&str` + //~| NOTE required by `into_iter` //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE in this expansion of desugaring of `for` loop //~| NOTE in this expansion of desugaring of `for` loop diff --git a/src/test/ui/for/for-c-in-str.stderr b/src/test/ui/for/for-c-in-str.stderr index 9185399804..b0f959ba02 100644 --- a/src/test/ui/for/for-c-in-str.stderr +++ b/src/test/ui/for/for-c-in-str.stderr @@ -4,8 +4,8 @@ error[E0277]: `&str` is not an iterator LL | for c in "asdf" { | ^^^^^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `std::iter::Iterator` is not implemented for `&str` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&str` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/for/for-loop-bogosity.stderr b/src/test/ui/for/for-loop-bogosity.stderr index fe6ac529b4..ccacd655a1 100644 --- a/src/test/ui/for/for-loop-bogosity.stderr +++ b/src/test/ui/for/for-loop-bogosity.stderr @@ -4,8 +4,8 @@ error[E0277]: `MyStruct` is not an iterator LL | for x in bogus { | ^^^^^ `MyStruct` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `MyStruct` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `MyStruct` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/format-ref-cell.rs b/src/test/ui/format-ref-cell.rs deleted file mode 100644 index afb2f8488b..0000000000 --- a/src/test/ui/format-ref-cell.rs +++ /dev/null @@ -1,10 +0,0 @@ -// run-pass - -use std::cell::RefCell; - -pub fn main() { - let name = RefCell::new("rust"); - let what = RefCell::new("rocks"); - let msg = format!("{name} {}", &*what.borrow(), name=&*name.borrow()); - assert_eq!(msg, "rust rocks".to_string()); -} diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs index b4f9a38ff3..1c6b9805b5 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.rs @@ -4,7 +4,7 @@ fn main() { let x: Option; x = 5; //~^ ERROR mismatched types - //~| expected enum `std::option::Option` + //~| expected enum `Option` //~| found type `{integer}` - //~| expected enum `std::option::Option`, found integer + //~| expected enum `Option`, found integer } diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr index 6a550b93be..b5018b47b7 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name1.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | x = 5; | ^ | | - | expected enum `std::option::Option`, found integer + | expected enum `Option`, found integer | help: try using a variant of the expected enum: `Some(5)` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `{integer}` error: aborting due to previous error diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs index 30cb3ee48e..2486ae009c 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.rs @@ -5,9 +5,9 @@ use std::option::Option; fn bar(x: usize) -> Option { return x; //~^ ERROR mismatched types - //~| expected enum `std::option::Option` + //~| expected enum `Option` //~| found type `usize` - //~| expected enum `std::option::Option`, found `usize` + //~| expected enum `Option`, found `usize` } fn main() { diff --git a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr index ca61fb0c17..b9574e3975 100644 --- a/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr +++ b/src/test/ui/fully-qualified-type/fully-qualified-type-name4.stderr @@ -2,14 +2,14 @@ error[E0308]: mismatched types --> $DIR/fully-qualified-type-name4.rs:6:12 | LL | fn bar(x: usize) -> Option { - | ------------- expected `std::option::Option` because of return type + | ------------- expected `Option` because of return type LL | return x; | ^ | | - | expected enum `std::option::Option`, found `usize` + | expected enum `Option`, found `usize` | help: try using a variant of the expected enum: `Some(x)` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `usize` error: aborting due to previous error diff --git a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr b/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr index 635f83bbf4..45cdd3d2dd 100644 --- a/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr +++ b/src/test/ui/functional-struct-update/functional-struct-update-noncopyable.stderr @@ -5,7 +5,7 @@ LL | let _b = A { y: Arc::new(3), ..a }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ | | | cannot move out of here - | move occurs because `a.x` has type `std::sync::Arc`, which does not implement the `Copy` trait + | move occurs because `a.x` has type `Arc`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs index 7ae53020fe..500633edf1 100644 --- a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs +++ b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.rs @@ -26,7 +26,7 @@ mod foo { fn main() { let s_1 = foo::make_secrets(3, format!("ess one")); let s_2 = foo::S { b: format!("ess two"), ..s_1 }; // FRU ... - //~^ ERROR field `secret_uid` of struct `foo::S` is private + //~^ ERROR field `secret_uid` of struct `S` is private println!("main forged an S named: {}", s_2.b); // at end of scope, ... both s_1 *and* s_2 get dropped. Boom! } diff --git a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr index 2aeffc3e5e..0b8af90b41 100644 --- a/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr +++ b/src/test/ui/functional-struct-update/functional-struct-update-respects-privacy.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `secret_uid` of struct `foo::S` is private +error[E0451]: field `secret_uid` of struct `S` is private --> $DIR/functional-struct-update-respects-privacy.rs:28:49 | LL | let s_2 = foo::S { b: format!("ess two"), ..s_1 }; // FRU ... diff --git a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr index 9699abd566..16a5ab2cc8 100644 --- a/src/test/ui/generator/generator-yielding-or-returning-itself.stderr +++ b/src/test/ui/generator/generator-yielding-or-returning-itself.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as std::ops::Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _] as Generator>::Return == [generator@$DIR/generator-yielding-or-returning-itself.rs:15:34: 19:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:15:5 | LL | pub fn want_cyclic_generator_return(_: T) @@ -14,7 +14,7 @@ LL | want_cyclic_generator_return(|| { see issue #46062 for more information -error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as std::ops::Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` +error[E0271]: type mismatch resolving `<[generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _] as Generator>::Yield == [generator@$DIR/generator-yielding-or-returning-itself.rs:28:33: 32:6 _]` --> $DIR/generator-yielding-or-returning-itself.rs:28:5 | LL | pub fn want_cyclic_generator_yield(_: T) diff --git a/src/test/ui/generator/issue-68112.rs b/src/test/ui/generator/issue-68112.rs index 9ab2abf740..feb07c9bf8 100644 --- a/src/test/ui/generator/issue-68112.rs +++ b/src/test/ui/generator/issue-68112.rs @@ -50,7 +50,7 @@ fn test2() { yield; }; require_send(send_gen); - //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely + //~^ ERROR `RefCell` cannot be shared between threads safely } fn main() {} diff --git a/src/test/ui/generator/issue-68112.stderr b/src/test/ui/generator/issue-68112.stderr index 83536f2af1..96a8d6d70e 100644 --- a/src/test/ui/generator/issue-68112.stderr +++ b/src/test/ui/generator/issue-68112.stderr @@ -7,33 +7,33 @@ LL | fn require_send(_: impl Send) {} LL | require_send(send_gen); | ^^^^^^^^^^^^ generator is not `Send` | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` note: generator is not `Send` as this value is used across a yield --> $DIR/issue-68112.rs:31:9 | LL | let _non_send_gen = make_non_send_generator(); - | ------------- has type `impl std::ops::Generator` which is not `Send` + | ------------- has type `impl Generator` which is not `Send` LL | yield; | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later LL | }; | - `_non_send_gen` is later dropped here -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-68112.rs:52:5 | LL | fn require_send(_: impl Send) {} | ---- required by this bound in `require_send` ... LL | require_send(send_gen); - | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc>` - = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 t:std::sync::Arc> {()}]` - = note: required because it appears within the type `impl std::ops::Generator` - = note: required because it appears within the type `impl std::ops::Generator` - = note: required because it appears within the type `{impl std::ops::Generator, ()}` - = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl std::ops::Generator, ()}]` + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Send` for `Arc>` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:38:5: 41:6 {()}]` + = note: required because it appears within the type `impl Generator` + = note: required because it appears within the type `impl Generator` + = note: required because it appears within the type `{impl Generator, ()}` + = note: required because it appears within the type `[generator@$DIR/issue-68112.rs:48:20: 51:6 {impl Generator, ()}]` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/not-send-sync.stderr b/src/test/ui/generator/not-send-sync.stderr index 5df2c1b52f..2384ed3d24 100644 --- a/src/test/ui/generator/not-send-sync.stderr +++ b/src/test/ui/generator/not-send-sync.stderr @@ -1,31 +1,31 @@ -error[E0277]: `std::cell::Cell` cannot be shared between threads safely +error[E0277]: `Cell` cannot be shared between threads safely --> $DIR/not-send-sync.rs:16:5 | LL | fn assert_send(_: T) {} - | ---- required by this bound in `main::assert_send` + | ---- required by this bound in `assert_send` ... LL | assert_send(|| { - | ^^^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely + | ^^^^^^^^^^^ `Cell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` - = note: required because of the requirements on the impl of `std::marker::Send` for `&std::cell::Cell` - = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 a:&std::cell::Cell _]` + = help: the trait `Sync` is not implemented for `Cell` + = note: required because of the requirements on the impl of `Send` for `&Cell` + = note: required because it appears within the type `[generator@$DIR/not-send-sync.rs:16:17: 20:6 _]` error: generator cannot be shared between threads safely --> $DIR/not-send-sync.rs:9:5 | LL | fn assert_sync(_: T) {} - | ---- required by this bound in `main::assert_sync` + | ---- required by this bound in `assert_sync` ... LL | assert_sync(|| { | ^^^^^^^^^^^ generator is not `Sync` | - = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {std::cell::Cell, ()}]`, the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = help: within `[generator@$DIR/not-send-sync.rs:9:17: 13:6 {Cell, ()}]`, the trait `Sync` is not implemented for `Cell` note: generator is not `Sync` as this value is used across a yield --> $DIR/not-send-sync.rs:12:9 | LL | let a = Cell::new(2); - | - has type `std::cell::Cell` which is not `Sync` + | - has type `Cell` which is not `Sync` LL | yield; | ^^^^^ yield occurs here, with `a` maybe used later LL | }); diff --git a/src/test/ui/generator/print/generator-print-verbose-1.rs b/src/test/ui/generator/print/generator-print-verbose-1.rs new file mode 100644 index 0000000000..fe0687722b --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-1.rs @@ -0,0 +1,60 @@ +// compile-flags: -Zverbose + +// Same as: src/test/ui/generator/issue-68112.stderr + +#![feature(generators, generator_trait)] + +use std::{ + cell::RefCell, + sync::Arc, + pin::Pin, + ops::{Generator, GeneratorState}, +}; + +pub struct Ready(Option); +impl Generator<()> for Ready { + type Return = T; + type Yield = (); + fn resume(mut self: Pin<&mut Self>, _args: ()) -> GeneratorState<(), T> { + GeneratorState::Complete(self.0.take().unwrap()) + } +} +pub fn make_gen1(t: T) -> Ready { + Ready(Some(t)) +} + +fn require_send(_: impl Send) {} + +fn make_non_send_generator() -> impl Generator>> { + make_gen1(Arc::new(RefCell::new(0))) +} + +fn test1() { + let send_gen = || { + let _non_send_gen = make_non_send_generator(); + yield; + }; + require_send(send_gen); + //~^ ERROR generator cannot be sent between threads +} + +pub fn make_gen2(t: T) -> impl Generator { + || { + yield; + t + } +} +fn make_non_send_generator2() -> impl Generator>> { + make_gen2(Arc::new(RefCell::new(0))) +} + +fn test2() { + let send_gen = || { + let _non_send_gen = make_non_send_generator2(); + yield; + }; + require_send(send_gen); + //~^ ERROR `RefCell` cannot be shared between threads safely +} + +fn main() {} diff --git a/src/test/ui/generator/print/generator-print-verbose-1.stderr b/src/test/ui/generator/print/generator-print-verbose-1.stderr new file mode 100644 index 0000000000..b5c63584c6 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-1.stderr @@ -0,0 +1,40 @@ +error: generator cannot be sent between threads safely + --> $DIR/generator-print-verbose-1.rs:37:5 + | +LL | fn require_send(_: impl Send) {} + | ---- required by this bound in `require_send` +... +LL | require_send(send_gen); + | ^^^^^^^^^^^^ generator is not `Send` + | + = help: the trait `Sync` is not implemented for `RefCell` +note: generator is not `Send` as this value is used across a yield + --> $DIR/generator-print-verbose-1.rs:35:9 + | +LL | let _non_send_gen = make_non_send_generator(); + | ------------- has type `Opaque(DefId(0:24 ~ generator_print_verbose_1[317d]::make_non_send_generator::{opaque#0}), [])` which is not `Send` +LL | yield; + | ^^^^^ yield occurs here, with `_non_send_gen` maybe used later +LL | }; + | - `_non_send_gen` is later dropped here + +error[E0277]: `RefCell` cannot be shared between threads safely + --> $DIR/generator-print-verbose-1.rs:56:5 + | +LL | fn require_send(_: impl Send) {} + | ---- required by this bound in `require_send` +... +LL | require_send(send_gen); + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Send` for `Arc>` + = note: required because it appears within the type `[make_gen2>>::{closure#0} upvar_tys=(Arc>) {()}]` + = note: required because it appears within the type `Opaque(DefId(0:29 ~ generator_print_verbose_1[317d]::make_gen2::{opaque#0}), [std::sync::Arc>])` + = note: required because it appears within the type `Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), [])` + = note: required because it appears within the type `{Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}` + = note: required because it appears within the type `[test2::{closure#0} upvar_tys=() {Opaque(DefId(0:32 ~ generator_print_verbose_1[317d]::make_non_send_generator2::{opaque#0}), []), ()}]` + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/print/generator-print-verbose-2.rs b/src/test/ui/generator/print/generator-print-verbose-2.rs new file mode 100644 index 0000000000..d914719cb3 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-2.rs @@ -0,0 +1,24 @@ +// compile-flags: -Zverbose + +// Same as test/ui/generator/not-send-sync.rs +#![feature(generators)] + +use std::cell::Cell; + +fn main() { + fn assert_sync(_: T) {} + fn assert_send(_: T) {} + + assert_sync(|| { + //~^ ERROR: generator cannot be shared between threads safely + let a = Cell::new(2); + yield; + }); + + let a = Cell::new(2); + assert_send(|| { + //~^ ERROR: E0277 + drop(&a); + yield; + }); +} diff --git a/src/test/ui/generator/print/generator-print-verbose-2.stderr b/src/test/ui/generator/print/generator-print-verbose-2.stderr new file mode 100644 index 0000000000..cc45d5631c --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-2.stderr @@ -0,0 +1,36 @@ +error[E0277]: `Cell` cannot be shared between threads safely + --> $DIR/generator-print-verbose-2.rs:19:5 + | +LL | fn assert_send(_: T) {} + | ---- required by this bound in `assert_send` +... +LL | assert_send(|| { + | ^^^^^^^^^^^ `Cell` cannot be shared between threads safely + | + = help: the trait `Sync` is not implemented for `Cell` + = note: required because of the requirements on the impl of `Send` for `&'_#3r Cell` + = note: required because it appears within the type `[main::{closure#1} upvar_tys=(&'_#3r Cell) _#16t]` + +error: generator cannot be shared between threads safely + --> $DIR/generator-print-verbose-2.rs:12:5 + | +LL | fn assert_sync(_: T) {} + | ---- required by this bound in `assert_sync` +... +LL | assert_sync(|| { + | ^^^^^^^^^^^ generator is not `Sync` + | + = help: within `[main::{closure#0} upvar_tys=() {Cell, ()}]`, the trait `Sync` is not implemented for `Cell` +note: generator is not `Sync` as this value is used across a yield + --> $DIR/generator-print-verbose-2.rs:15:9 + | +LL | let a = Cell::new(2); + | - has type `Cell` which is not `Sync` +LL | yield; + | ^^^^^ yield occurs here, with `a` maybe used later +LL | }); + | - `a` is later dropped here + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/generator/print/generator-print-verbose-3.rs b/src/test/ui/generator/print/generator-print-verbose-3.rs new file mode 100644 index 0000000000..8689539ec8 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-3.rs @@ -0,0 +1,12 @@ +// compile-flags: -Zverbose + +#![feature(generators, generator_trait)] + +fn main() { + let x = "Type mismatch test"; + let generator :() = || { + //~^ ERROR mismatched types + yield 1i32; + return x + }; +} diff --git a/src/test/ui/generator/print/generator-print-verbose-3.stderr b/src/test/ui/generator/print/generator-print-verbose-3.stderr new file mode 100644 index 0000000000..0ce108dfd6 --- /dev/null +++ b/src/test/ui/generator/print/generator-print-verbose-3.stderr @@ -0,0 +1,19 @@ +error[E0308]: mismatched types + --> $DIR/generator-print-verbose-3.rs:7:25 + | +LL | let generator :() = || { + | ____________________--___^ + | | | + | | expected due to this +LL | | +LL | | yield 1i32; +LL | | return x +LL | | }; + | |_____^ expected `()`, found generator + | + = note: expected unit type `()` + found generator `[main::{closure#0} upvar_tys=(unavailable) _#5t]` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/generator/resume-arg-late-bound.stderr b/src/test/ui/generator/resume-arg-late-bound.stderr index c379d9eae8..dc0864165a 100644 --- a/src/test/ui/generator/resume-arg-late-bound.stderr +++ b/src/test/ui/generator/resume-arg-late-bound.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | test(gen); | ^^^^ one type is more general than the other | - = note: expected type `for<'a> std::ops::Generator<&'a mut bool>` - found type `std::ops::Generator<&mut bool>` + = note: expected type `for<'a> Generator<&'a mut bool>` + found type `Generator<&mut bool>` error[E0308]: mismatched types --> $DIR/resume-arg-late-bound.rs:15:5 @@ -13,8 +13,8 @@ error[E0308]: mismatched types LL | test(gen); | ^^^^ one type is more general than the other | - = note: expected type `for<'a> std::ops::Generator<&'a mut bool>` - found type `std::ops::Generator<&mut bool>` + = note: expected type `for<'a> Generator<&'a mut bool>` + found type `Generator<&mut bool>` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/sized-yield.stderr b/src/test/ui/generator/sized-yield.stderr index 379bd8ebd1..2bcf66dbea 100644 --- a/src/test/ui/generator/sized-yield.stderr +++ b/src/test/ui/generator/sized-yield.stderr @@ -8,7 +8,7 @@ LL | | yield s[..]; LL | | }; | |____^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: the yield type of a generator must have a statically known size error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -17,7 +17,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | Pin::new(&mut gen).resume(()); | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` error: aborting due to 2 previous errors diff --git a/src/test/ui/generator/static-generators.rs b/src/test/ui/generator/static-generators.rs index 3980766c42..d098bf1e68 100644 --- a/src/test/ui/generator/static-generators.rs +++ b/src/test/ui/generator/static-generators.rs @@ -12,7 +12,7 @@ fn main() { yield; assert_eq!(b as *const _, &a as *const _); }; - // Safety: We shadow the original generator variable so have no safe API to + // SAFETY: We shadow the original generator variable so have no safe API to // move it after this point. let mut generator = unsafe { Pin::new_unchecked(&mut generator) }; assert_eq!(generator.as_mut().resume(()), GeneratorState::Yielded(())); diff --git a/src/test/ui/generator/static-not-unpin.stderr b/src/test/ui/generator/static-not-unpin.stderr index 3bb899cd89..216b707bb1 100644 --- a/src/test/ui/generator/static-not-unpin.stderr +++ b/src/test/ui/generator/static-not-unpin.stderr @@ -5,7 +5,7 @@ LL | fn assert_unpin(_: T) { | ----- required by this bound in `assert_unpin` ... LL | assert_unpin(generator); - | ^^^^^^^^^ the trait `std::marker::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 _]` error: aborting due to previous error diff --git a/src/test/ui/generator/type-mismatch-signature-deduction.stderr b/src/test/ui/generator/type-mismatch-signature-deduction.stderr index 8de77798ff..260fbb2ec7 100644 --- a/src/test/ui/generator/type-mismatch-signature-deduction.stderr +++ b/src/test/ui/generator/type-mismatch-signature-deduction.stderr @@ -7,7 +7,7 @@ LL | 5 = note: expected type `std::result::Result<{integer}, _>` found type `{integer}` -error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as std::ops::Generator>::Return == i32` +error[E0271]: type mismatch resolving `<[generator@$DIR/type-mismatch-signature-deduction.rs:6:5: 14:6 _] as Generator>::Return == i32` --> $DIR/type-mismatch-signature-deduction.rs:5:13 | LL | fn foo() -> impl Generator { diff --git a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr index 4d02f2c46a..c95765d906 100644 --- a/src/test/ui/generic-associated-types/generic-associated-types-where.stderr +++ b/src/test/ui/generic-associated-types/generic-associated-types-where.stderr @@ -5,7 +5,7 @@ LL | type Assoc3; | --------------- definition of `Assoc3` from trait ... LL | type Assoc3 where T: Iterator = Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/impl_bounds.rs b/src/test/ui/generic-associated-types/impl_bounds.rs index 3ffa6c6eec..77bebc9854 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.rs +++ b/src/test/ui/generic-associated-types/impl_bounds.rs @@ -17,7 +17,7 @@ impl Foo for Fooy { type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); //~^ ERROR lifetime bound not satisfied type C where Self: Copy = String; - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() {} diff --git a/src/test/ui/generic-associated-types/impl_bounds.stderr b/src/test/ui/generic-associated-types/impl_bounds.stderr index e06977ebbe..0546e38a33 100644 --- a/src/test/ui/generic-associated-types/impl_bounds.stderr +++ b/src/test/ui/generic-associated-types/impl_bounds.stderr @@ -24,18 +24,18 @@ note: but lifetime parameter must outlive the lifetime `'a` as defined on the as LL | type B<'a, 'b> where 'b: 'a = (&'a(), &'b ()); | ^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/impl_bounds.rs:19:5 | LL | type C where Self: Copy = String; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `Fooy` - = note: the requirement `Fooy: std::marker::Copy` appears on the associated impl type but not on the corresponding associated trait type + = note: required because of the requirements on the impl of `Copy` for `Fooy` + = note: the requirement `Fooy: Copy` appears on the associated impl type but not on the corresponding associated trait type help: consider restricting type parameter `T` | -LL | impl Foo for Fooy { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for Fooy { + | ^^^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr index bc5c40ff02..439b8ab90c 100644 --- a/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr +++ b/src/test/ui/generic-associated-types/issue-47206-where-clause.stderr @@ -5,7 +5,7 @@ LL | type Assoc3; | --------------- definition of `Assoc3` from trait ... LL | type Assoc3 where T: Iterator = Vec; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: std::iter::Iterator` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Iterator` error: aborting due to previous error diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs index 71f9b2967d..0020887eae 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.rs @@ -13,7 +13,7 @@ trait UnsafeCopy { impl UnsafeCopy for T { type Item<'a> = T; - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr index 834bc3b787..6ba79dd543 100644 --- a/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr +++ b/src/test/ui/generic-associated-types/issue-68641-check-gat-bounds.stderr @@ -7,19 +7,19 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-68641-check-gat-bounds.rs:15:5 | LL | type Item<'a>: Copy; | -------------------- required by `UnsafeCopy::Item` ... LL | type Item<'a> = T; - | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl UnsafeCopy for T { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl UnsafeCopy for T { + | ^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs index c99073c132..ff8d2ca05b 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr index 2fe266b801..15a66e25b1 100644 --- a/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr +++ b/src/test/ui/generic-associated-types/issue-68642-broken-llvm-ir.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68642-broken-llvm-ir.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs index 24133e75cc..2107804a8b 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } pub fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr index e335523778..9b2ddb2326 100644 --- a/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr +++ b/src/test/ui/generic-associated-types/issue-68643-broken-mir.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68643-broken-mir.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs index 22620c61b8..bfe63b1be7 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr index d7a5bb0ebe..f7bfab3505 100644 --- a/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr +++ b/src/test/ui/generic-associated-types/issue-68644-codegen-selection.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68644-codegen-selection.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs index 423b80e847..676dcf9023 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.rs @@ -13,7 +13,7 @@ trait Fun { impl Fun for T { type F<'a> = Self; - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `T` + //~^ ERROR expected a `Fn<()>` closure, found `T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr index 0670625aa2..6c2d330a19 100644 --- a/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr +++ b/src/test/ui/generic-associated-types/issue-68645-codegen-fulfillment.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0277]: expected a `std::ops::Fn<()>` closure, found `T` +error[E0277]: expected a `Fn<()>` closure, found `T` --> $DIR/issue-68645-codegen-fulfillment.rs:15:5 | LL | type F<'a>: Fn() -> u32; @@ -19,8 +19,8 @@ LL | type F<'a> = Self; = note: wrap the `T` in a closure with no arguments: `|| { /* code */ }` help: consider restricting type parameter `T` | -LL | impl> Fun for T { - | ^^^^^^^^^^^^^^^^^^ +LL | impl> Fun for T { + | ^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs index 4ccd42ba64..f682bdd8ac 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.rs @@ -14,7 +14,7 @@ trait UnsafeCopy { impl UnsafeCopy for T { type Item<'a> = T; - //~^ ERROR type mismatch resolving `::Target == T` + //~^ ERROR type mismatch resolving `::Target == T` } fn main() { diff --git a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr index e1ceeac319..a9336151b6 100644 --- a/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr +++ b/src/test/ui/generic-associated-types/issue-68656-unsized-values.stderr @@ -7,7 +7,7 @@ LL | #![feature(generic_associated_types)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #44265 for more information -error[E0271]: type mismatch resolving `::Target == T` +error[E0271]: type mismatch resolving `::Target == T` --> $DIR/issue-68656-unsized-values.rs:16:5 | LL | type Item<'a>: std::ops::Deref; @@ -19,11 +19,11 @@ LL | type Item<'a> = T; | ^^^^^^^^^^^^^^^^^^ expected type parameter `T`, found associated type | = note: expected type parameter `T` - found associated type `::Target` + found associated type `::Target` help: consider further restricting this bound | -LL | impl> UnsafeCopy for T { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> UnsafeCopy for T { + | ^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/generic-associated-types/missing-bounds.fixed b/src/test/ui/generic-associated-types/missing-bounds.fixed index 3ba7d043d0..54478d1628 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.fixed +++ b/src/test/ui/generic-associated-types/missing-bounds.fixed @@ -4,7 +4,7 @@ use std::ops::Add; struct A(B); -impl Add for A where B: Add + std::ops::Add { +impl Add for A where B: Add + Add { type Output = Self; fn add(self, rhs: Self) -> Self { @@ -14,7 +14,7 @@ impl Add for A where B: Add + std::ops::Add { struct C(B); -impl> Add for C { +impl> Add for C { type Output = Self; fn add(self, rhs: Self) -> Self { diff --git a/src/test/ui/generic-associated-types/missing-bounds.stderr b/src/test/ui/generic-associated-types/missing-bounds.stderr index 630ceac093..4d4f7e5587 100644 --- a/src/test/ui/generic-associated-types/missing-bounds.stderr +++ b/src/test/ui/generic-associated-types/missing-bounds.stderr @@ -8,11 +8,11 @@ LL | A(self.0 + rhs.0) | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type | = note: expected type parameter `B` - found associated type `::Output` + found associated type `::Output` help: consider further restricting this bound | -LL | impl Add for A where B: Add + std::ops::Add { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Add for A where B: Add + Add { + | ^^^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/missing-bounds.rs:21:14 @@ -24,11 +24,11 @@ LL | Self(self.0 + rhs.0) | ^^^^^^^^^^^^^^ expected type parameter `B`, found associated type | = note: expected type parameter `B` - found associated type `::Output` + found associated type `::Output` help: consider further restricting this bound | -LL | impl> Add for C { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | impl> Add for C { + | ^^^^^^^^^^^^^^^^^ error[E0369]: cannot add `B` to `B` --> $DIR/missing-bounds.rs:31:21 diff --git a/src/test/ui/generic/generic-type-params-name-repr.rs b/src/test/ui/generic/generic-type-params-name-repr.rs index 45dc85a252..6e0beec663 100644 --- a/src/test/ui/generic/generic-type-params-name-repr.rs +++ b/src/test/ui/generic/generic-type-params-name-repr.rs @@ -27,12 +27,12 @@ fn main() { let _: HashMap = (); //~^ ERROR mismatched types //~| expected struct `HashMap`, found `()` - //~| expected struct `HashMap` + //~| expected struct `HashMap` //~| found unit type `()` let _: HashMap> = (); //~^ ERROR mismatched types //~| expected struct `HashMap`, found `()` - //~| expected struct `HashMap` + //~| expected struct `HashMap` //~| found unit type `()` // But not when there's a different type in between. diff --git a/src/test/ui/generic/generic-type-params-name-repr.stderr b/src/test/ui/generic/generic-type-params-name-repr.stderr index 1418076611..4c3c003965 100644 --- a/src/test/ui/generic/generic-type-params-name-repr.stderr +++ b/src/test/ui/generic/generic-type-params-name-repr.stderr @@ -28,7 +28,7 @@ LL | let _: HashMap = (); | | | expected due to this | - = note: expected struct `HashMap` + = note: expected struct `HashMap` found unit type `()` error[E0308]: mismatched types @@ -39,7 +39,7 @@ LL | let _: HashMap> = (); | | | expected due to this | - = note: expected struct `HashMap` + = note: expected struct `HashMap` found unit type `()` error[E0308]: mismatched types diff --git a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr index 7a6c07d4e0..2b88a6046f 100644 --- a/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr +++ b/src/test/ui/generics/issue-61631-default-type-param-can-reference-self-in-trait.stderr @@ -7,7 +7,7 @@ LL | LL | impl Tsized for () {} | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[()]` + = help: the trait `Sized` is not implemented for `[()]` error: aborting due to previous error diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs index 7cddf5f652..b08732219d 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.rs @@ -2,7 +2,7 @@ #![feature(exclusive_range_pattern)] fn main() { - let "a".. = "a"; //~ ERROR only char and numeric types are allowed in range patterns - let .."a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns - let ..="a" = "a"; //~ ERROR only char and numeric types are allowed in range patterns + let "a".. = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns + let .."a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns + let ..="a" = "a"; //~ ERROR only `char` and numeric types are allowed in range patterns } diff --git a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr index 68ca363715..df0dae5696 100644 --- a/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr +++ b/src/test/ui/half-open-range-patterns/half-open-range-pats-bad-types.stderr @@ -1,16 +1,16 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/half-open-range-pats-bad-types.rs:5:9 | LL | let "a".. = "a"; | ^^^ this is of type `&'static str` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/half-open-range-pats-bad-types.rs:6:11 | LL | let .."a" = "a"; | ^^^ this is of type `&'static str` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/half-open-range-pats-bad-types.rs:7:12 | LL | let ..="a" = "a"; diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr index 92a8582503..f6acb34982 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_b_ret_a_vs_bound_a_ret_a.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_a_b_ret_a_vs_bound_a_ret_a: (for<'a,'b> fn(&'a u32, &'b u3 LL | | for<'a> fn(&'a u32, &'a u32) -> &'a u32) } | |_____________________________________________- in this macro invocation | - = note: expected enum `std::option::Option fn(&'a u32, &'b u32) -> &'a u32>` - found enum `std::option::Option fn(&'a u32, &'a u32) -> &'a 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 a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr index 98f5bff732..ebad4b93dc 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_a_vs_free_x.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_a_vs_free_x: (for<'a> fn(&'a u32), LL | | fn(&'x u32)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option fn(&'a u32)>` - found enum `std::option::Option` + = note: expected enum `Option fn(&'a u32)>` + found enum `Option` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr index 100ba6ac27..40a0ff97b6 100644 --- a/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.bound_inv_a_b_vs_bound_inv_a.stderr @@ -8,8 +8,8 @@ LL | / check! { bound_inv_a_b_vs_bound_inv_a: (for<'a,'b> fn(Inv<'a>, Inv<'b>), LL | | for<'a> fn(Inv<'a>, Inv<'a>)) } | |__________________________________- in this macro invocation | - = note: expected enum `std::option::Option fn(Inv<'a>, Inv<'b>)>` - found enum `std::option::Option fn(Inv<'a>, Inv<'a>)>` + = note: expected enum `Option fn(Inv<'a>, Inv<'b>)>` + found enum `Option fn(Inv<'a>, Inv<'a>)>` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr index 3c8af20e50..d2f40f7fb5 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_inv_x_vs_free_inv_y.stderr @@ -8,8 +8,8 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), LL | | fn(Inv<'y>)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option)>` - found enum `std::option::Option)>` + = note: expected enum `Option)>` + found enum `Option)>` note: the lifetime `'x` as defined on the function body at 38:20... --> $DIR/hr-subtype.rs:38:20 | @@ -40,8 +40,8 @@ LL | / check! { free_inv_x_vs_free_inv_y: (fn(Inv<'x>), LL | | fn(Inv<'y>)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option)>` - found enum `std::option::Option)>` + = note: expected enum `Option)>` + found enum `Option)>` note: the lifetime `'x` as defined on the function body at 44:22... --> $DIR/hr-subtype.rs:44:22 | diff --git a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr index 7b4cdd4a41..57610beb86 100644 --- a/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr +++ b/src/test/ui/hr-subtype/hr-subtype.free_x_vs_free_y.stderr @@ -8,8 +8,8 @@ LL | / check! { free_x_vs_free_y: (fn(&'x u32), LL | | fn(&'y u32)) } | |______________- in this macro invocation | - = note: expected enum `std::option::Option` - found enum `std::option::Option` + = note: expected enum `Option` + found enum `Option` note: the lifetime `'x` as defined on the function body at 44:22... --> $DIR/hr-subtype.rs:44:22 | diff --git a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr index 720e2276d5..8bd23aa901 100644 --- a/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr +++ b/src/test/ui/hrtb/hrtb-exists-forall-trait-invariant.stderr @@ -7,8 +7,8 @@ LL | trait Trait {} LL | foo::<()>(); | ^^^^^^^^^ implementation of `Trait` is not general enough | - = note: `()` must implement `Trait fn(std::cell::Cell<&'b u32>)>` - = note: ...but `()` actually implements `Trait)>`, for some specific lifetime `'0` + = note: `()` must implement `Trait fn(Cell<&'b u32>)>` + = note: ...but `()` actually implements `Trait)>`, for some specific lifetime `'0` error: aborting due to previous error diff --git a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr index 1c7bfa65d7..2342a4f6e1 100644 --- a/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr +++ b/src/test/ui/hrtb/issue-62203-hrtb-ice.stderr @@ -9,7 +9,7 @@ LL | let v = Unit2.m( = help: consider constraining the associated type `<_ as Ty<'_>>::V` to `Unit4` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html -error[E0271]: type mismatch resolving `<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as std::ops::FnOnce<((&u8,),)>>::Output == Unit3` +error[E0271]: type mismatch resolving `<[closure@$DIR/issue-62203-hrtb-ice.rs:42:17: 42:39] as FnOnce<((&u8,),)>>::Output == Unit3` --> $DIR/issue-62203-hrtb-ice.rs:38:19 | LL | let v = Unit2.m( diff --git a/src/test/ui/huge-enum.stderr b/src/test/ui/huge-enum.stderr index 8398c511b9..a069c37b80 100644 --- a/src/test/ui/huge-enum.stderr +++ b/src/test/ui/huge-enum.stderr @@ -1,4 +1,4 @@ -error: the type `TYPE` is too big for the current architecture +error: the type `Option` is too big for the current architecture --> $DIR/huge-enum.rs:16:9 | LL | let big: BIG = None; diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs index 06d62656e9..571017df4d 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.rs @@ -9,7 +9,7 @@ macro a() { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } } @@ -22,7 +22,7 @@ mod v { mod u { // Late resolution. fn f() { my_core::mem::drop(0); } - //~^ ERROR failed to resolve: use of undeclared type or module `my_core` + //~^ ERROR failed to resolve: use of undeclared crate or module `my_core` } fn main() {} diff --git a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr index b9e05c84a8..d3e6021a1e 100644 --- a/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr +++ b/src/test/ui/hygiene/extern-prelude-from-opaque-fail.stderr @@ -18,22 +18,22 @@ LL | a!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:11:18 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` ... LL | a!(); | ----- in this macro invocation | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `my_core` +error[E0433]: failed to resolve: use of undeclared crate or module `my_core` --> $DIR/extern-prelude-from-opaque-fail.rs:24:14 | LL | fn f() { my_core::mem::drop(0); } - | ^^^^^^^ use of undeclared type or module `my_core` + | ^^^^^^^ use of undeclared crate or module `my_core` error: aborting due to 4 previous errors diff --git a/src/test/ui/hygiene/fields.rs b/src/test/ui/hygiene/fields.rs index 597019cb1e..7a417b46fc 100644 --- a/src/test/ui/hygiene/fields.rs +++ b/src/test/ui/hygiene/fields.rs @@ -15,8 +15,8 @@ mod foo { let s = S { x: 0 }; //~ ERROR type `foo::S` is private let _ = s.x; //~ ERROR type `foo::S` is private - let t = T(0); //~ ERROR type `foo::T` is private - let _ = t.0; //~ ERROR type `foo::T` is private + let t = T(0); //~ ERROR type `T` is private + let _ = t.0; //~ ERROR type `T` is private let s = $S { $x: 0, x: 1 }; assert_eq!((s.$x, s.x), (0, 1)); diff --git a/src/test/ui/hygiene/fields.stderr b/src/test/ui/hygiene/fields.stderr index 6d78440801..3666aeabfa 100644 --- a/src/test/ui/hygiene/fields.stderr +++ b/src/test/ui/hygiene/fields.stderr @@ -20,7 +20,7 @@ LL | let s = foo::m!(S, x); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `foo::T` is private +error: type `T` is private --> $DIR/fields.rs:18:17 | LL | let t = T(0); @@ -31,7 +31,7 @@ LL | let s = foo::m!(S, x); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `foo::T` is private +error: type `T` is private --> $DIR/fields.rs:19:17 | LL | let _ = t.0; diff --git a/src/test/ui/hygiene/intercrate.rs b/src/test/ui/hygiene/intercrate.rs index 2acbc893cf..d9b5b789e4 100644 --- a/src/test/ui/hygiene/intercrate.rs +++ b/src/test/ui/hygiene/intercrate.rs @@ -8,5 +8,5 @@ extern crate intercrate; fn main() { assert_eq!(intercrate::foo::m!(), 1); - //~^ ERROR type `fn() -> u32 {intercrate::foo::bar::f}` is private + //~^ ERROR type `fn() -> u32 {foo::bar::f}` is private } diff --git a/src/test/ui/hygiene/intercrate.stderr b/src/test/ui/hygiene/intercrate.stderr index c27ba74a26..cd593abf53 100644 --- a/src/test/ui/hygiene/intercrate.stderr +++ b/src/test/ui/hygiene/intercrate.stderr @@ -1,4 +1,4 @@ -error: type `fn() -> u32 {intercrate::foo::bar::f}` is private +error: type `fn() -> u32 {foo::bar::f}` is private --> $DIR/intercrate.rs:10:16 | LL | assert_eq!(intercrate::foo::m!(), 1); diff --git a/src/test/ui/hygiene/nested_macro_privacy.rs b/src/test/ui/hygiene/nested_macro_privacy.rs index bee90e2bb8..dea9101ee0 100644 --- a/src/test/ui/hygiene/nested_macro_privacy.rs +++ b/src/test/ui/hygiene/nested_macro_privacy.rs @@ -12,6 +12,6 @@ n!(foo, S, i, m); fn main() { use foo::{S, m}; - S::default().i; //~ ERROR field `i` of struct `foo::S` is private + S::default().i; //~ ERROR field `i` of struct `S` is private m!(S::default()); // ok } diff --git a/src/test/ui/hygiene/nested_macro_privacy.stderr b/src/test/ui/hygiene/nested_macro_privacy.stderr index 482957a326..1d11cd0f57 100644 --- a/src/test/ui/hygiene/nested_macro_privacy.stderr +++ b/src/test/ui/hygiene/nested_macro_privacy.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `i` of struct `foo::S` is private +error[E0616]: field `i` of struct `S` is private --> $DIR/nested_macro_privacy.rs:15:18 | LL | S::default().i; diff --git a/src/test/ui/hygiene/no_implicit_prelude.stderr b/src/test/ui/hygiene/no_implicit_prelude.stderr index 990210ffb6..3c0c045077 100644 --- a/src/test/ui/hygiene/no_implicit_prelude.stderr +++ b/src/test/ui/hygiene/no_implicit_prelude.stderr @@ -6,7 +6,7 @@ LL | assert_eq!(0, 0); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `Vec` +error[E0433]: failed to resolve: use of undeclared type `Vec` --> $DIR/no_implicit_prelude.rs:11:9 | LL | fn f() { ::bar::m!(); } diff --git a/src/test/ui/if/ifmt-unimpl.rs b/src/test/ui/if/ifmt-unimpl.rs index 65daae4b25..258f4eea50 100644 --- a/src/test/ui/if/ifmt-unimpl.rs +++ b/src/test/ui/if/ifmt-unimpl.rs @@ -1,4 +1,4 @@ fn main() { format!("{:X}", "3"); - //~^ ERROR: `str: std::fmt::UpperHex` is not satisfied + //~^ ERROR: `str: UpperHex` is not satisfied } diff --git a/src/test/ui/if/ifmt-unimpl.stderr b/src/test/ui/if/ifmt-unimpl.stderr index a142896ada..65b0f4a09b 100644 --- a/src/test/ui/if/ifmt-unimpl.stderr +++ b/src/test/ui/if/ifmt-unimpl.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `str: std::fmt::UpperHex` is not satisfied +error[E0277]: the trait bound `str: UpperHex` is not satisfied --> $DIR/ifmt-unimpl.rs:2:21 | LL | format!("{:X}", "3"); - | ^^^ the trait `std::fmt::UpperHex` is not implemented for `str` + | ^^^ the trait `UpperHex` is not implemented for `str` | - = note: required because of the requirements on the impl of `std::fmt::UpperHex` for `&str` + = note: required because of the requirements on the impl of `UpperHex` for `&str` = note: required by `std::fmt::UpperHex::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/ifmt.rs b/src/test/ui/ifmt.rs deleted file mode 100644 index 27ab3d6b7a..0000000000 --- a/src/test/ui/ifmt.rs +++ /dev/null @@ -1,319 +0,0 @@ -// run-pass - -#![deny(warnings)] -#![allow(unused_must_use)] -#![allow(unused_features)] -#![feature(box_syntax)] - -use std::cell::RefCell; -use std::fmt::{self, Write}; -use std::usize; - -struct A; -struct B; -struct C; -struct D; - -impl fmt::LowerHex for A { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("aloha") - } -} -impl fmt::UpperHex for B { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("adios") - } -} -impl fmt::Display for C { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad_integral(true, "☃", "123") - } -} -impl fmt::Binary for D { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.write_str("aa")?; - f.write_char('☃')?; - f.write_str("bb") - } -} - -macro_rules! t { - ($a:expr, $b:expr) => { assert_eq!($a, $b) } -} - -pub fn main() { - // Various edge cases without formats - t!(format!(""), ""); - t!(format!("hello"), "hello"); - t!(format!("hello {{"), "hello {"); - - // default formatters should work - t!(format!("{}", 1.0f32), "1"); - t!(format!("{}", 1.0f64), "1"); - t!(format!("{}", "a"), "a"); - t!(format!("{}", "a".to_string()), "a"); - t!(format!("{}", false), "false"); - t!(format!("{}", 'a'), "a"); - - // At least exercise all the formats - t!(format!("{}", true), "true"); - t!(format!("{}", '☃'), "☃"); - t!(format!("{}", 10), "10"); - t!(format!("{}", 10_usize), "10"); - t!(format!("{:?}", '☃'), "'☃'"); - t!(format!("{:?}", 10), "10"); - t!(format!("{:?}", 10_usize), "10"); - t!(format!("{:?}", "true"), "\"true\""); - t!(format!("{:?}", "foo\nbar"), "\"foo\\nbar\""); - t!(format!("{:?}", "foo\n\"bar\"\r\n\'baz\'\t\\qux\\"), - r#""foo\n\"bar\"\r\n\'baz\'\t\\qux\\""#); - t!(format!("{:?}", "foo\0bar\x01baz\u{7f}q\u{75}x"), - r#""foo\u{0}bar\u{1}baz\u{7f}qux""#); - t!(format!("{:o}", 10_usize), "12"); - t!(format!("{:x}", 10_usize), "a"); - t!(format!("{:X}", 10_usize), "A"); - t!(format!("{}", "foo"), "foo"); - t!(format!("{}", "foo".to_string()), "foo"); - if cfg!(target_pointer_width = "32") { - t!(format!("{:#p}", 0x1234 as *const isize), "0x00001234"); - t!(format!("{:#p}", 0x1234 as *mut isize), "0x00001234"); - } else { - t!(format!("{:#p}", 0x1234 as *const isize), "0x0000000000001234"); - t!(format!("{:#p}", 0x1234 as *mut isize), "0x0000000000001234"); - } - t!(format!("{:p}", 0x1234 as *const isize), "0x1234"); - t!(format!("{:p}", 0x1234 as *mut isize), "0x1234"); - t!(format!("{:x}", A), "aloha"); - t!(format!("{:X}", B), "adios"); - t!(format!("foo {} ☃☃☃☃☃☃", "bar"), "foo bar ☃☃☃☃☃☃"); - t!(format!("{1} {0}", 0, 1), "1 0"); - t!(format!("{foo} {bar}", foo=0, bar=1), "0 1"); - t!(format!("{foo} {1} {bar} {0}", 0, 1, foo=2, bar=3), "2 1 3 0"); - t!(format!("{} {0}", "a"), "a a"); - t!(format!("{_foo}", _foo = 6usize), "6"); - t!(format!("{foo_bar}", foo_bar=1), "1"); - t!(format!("{}", 5 + 5), "10"); - t!(format!("{:#4}", C), "☃123"); - t!(format!("{:b}", D), "aa☃bb"); - - let a: &dyn fmt::Debug = &1; - t!(format!("{:?}", a), "1"); - - // Formatting strings and their arguments - t!(format!("{}", "a"), "a"); - t!(format!("{:4}", "a"), "a "); - t!(format!("{:4}", "☃"), "☃ "); - t!(format!("{:>4}", "a"), " a"); - t!(format!("{:<4}", "a"), "a "); - t!(format!("{:^5}", "a"), " a "); - t!(format!("{:^5}", "aa"), " aa "); - t!(format!("{:^4}", "a"), " a "); - t!(format!("{:^4}", "aa"), " aa "); - t!(format!("{:.4}", "a"), "a"); - t!(format!("{:4.4}", "a"), "a "); - t!(format!("{:4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:<4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:^4.4}", "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:>10.4}", "aaaaaaaaaaaaaaaaaa"), " aaaa"); - t!(format!("{:2.4}", "aaaaa"), "aaaa"); - t!(format!("{:2.4}", "aaaa"), "aaaa"); - t!(format!("{:2.4}", "aaa"), "aaa"); - t!(format!("{:2.4}", "aa"), "aa"); - t!(format!("{:2.4}", "a"), "a "); - t!(format!("{:0>2}", "a"), "0a"); - t!(format!("{:.*}", 4, "aaaaaaaaaaaaaaaaaa"), "aaaa"); - t!(format!("{:.1$}", "aaaaaaaaaaaaaaaaaa", 4), "aaaa"); - t!(format!("{:.a$}", "aaaaaaaaaaaaaaaaaa", a=4), "aaaa"); - t!(format!("{:._a$}", "aaaaaaaaaaaaaaaaaa", _a=4), "aaaa"); - t!(format!("{:1$}", "a", 4), "a "); - t!(format!("{1:0$}", 4, "a"), "a "); - t!(format!("{:a$}", "a", a=4), "a "); - t!(format!("{:-#}", "a"), "a"); - t!(format!("{:+#}", "a"), "a"); - t!(format!("{:/^10.8}", "1234567890"), "/12345678/"); - - // Some float stuff - t!(format!("{:}", 1.0f32), "1"); - t!(format!("{:}", 1.0f64), "1"); - t!(format!("{:.3}", 1.0f64), "1.000"); - t!(format!("{:10.3}", 1.0f64), " 1.000"); - t!(format!("{:+10.3}", 1.0f64), " +1.000"); - t!(format!("{:+10.3}", -1.0f64), " -1.000"); - - t!(format!("{:e}", 1.2345e6f32), "1.2345e6"); - t!(format!("{:e}", 1.2345e6f64), "1.2345e6"); - t!(format!("{:E}", 1.2345e6f64), "1.2345E6"); - t!(format!("{:.3e}", 1.2345e6f64), "1.234e6"); - t!(format!("{:10.3e}", 1.2345e6f64), " 1.234e6"); - t!(format!("{:+10.3e}", 1.2345e6f64), " +1.234e6"); - t!(format!("{:+10.3e}", -1.2345e6f64), " -1.234e6"); - - // Float edge cases - t!(format!("{}", -0.0), "0"); - t!(format!("{:?}", -0.0), "-0.0"); - t!(format!("{:?}", 0.0), "0.0"); - - // sign aware zero padding - t!(format!("{:<3}", 1), "1 "); - t!(format!("{:>3}", 1), " 1"); - t!(format!("{:^3}", 1), " 1 "); - t!(format!("{:03}", 1), "001"); - t!(format!("{:<03}", 1), "001"); - t!(format!("{:>03}", 1), "001"); - t!(format!("{:^03}", 1), "001"); - t!(format!("{:+03}", 1), "+01"); - t!(format!("{:<+03}", 1), "+01"); - t!(format!("{:>+03}", 1), "+01"); - t!(format!("{:^+03}", 1), "+01"); - t!(format!("{:#05x}", 1), "0x001"); - t!(format!("{:<#05x}", 1), "0x001"); - t!(format!("{:>#05x}", 1), "0x001"); - t!(format!("{:^#05x}", 1), "0x001"); - t!(format!("{:05}", 1.2), "001.2"); - t!(format!("{:<05}", 1.2), "001.2"); - t!(format!("{:>05}", 1.2), "001.2"); - t!(format!("{:^05}", 1.2), "001.2"); - t!(format!("{:05}", -1.2), "-01.2"); - t!(format!("{:<05}", -1.2), "-01.2"); - t!(format!("{:>05}", -1.2), "-01.2"); - t!(format!("{:^05}", -1.2), "-01.2"); - t!(format!("{:+05}", 1.2), "+01.2"); - t!(format!("{:<+05}", 1.2), "+01.2"); - t!(format!("{:>+05}", 1.2), "+01.2"); - t!(format!("{:^+05}", 1.2), "+01.2"); - - // Ergonomic format_args! - t!(format!("{0:x} {0:X}", 15), "f F"); - t!(format!("{0:x} {0:X} {}", 15), "f F 15"); - t!(format!("{:x}{0:X}{a:x}{:X}{1:x}{a:X}", 13, 14, a=15), "dDfEeF"); - t!(format!("{a:x} {a:X}", a=15), "f F"); - - // And its edge cases - t!(format!("{a:.0$} {b:.0$} {0:.0$}\n{a:.c$} {b:.c$} {c:.c$}", - 4, a="abcdefg", b="hijklmn", c=3), - "abcd hijk 4\nabc hij 3"); - t!(format!("{a:.*} {0} {:.*}", 4, 3, "efgh", a="abcdef"), "abcd 4 efg"); - t!(format!("{:.a$} {a} {a:#x}", "aaaaaa", a=2), "aa 2 0x2"); - - // Test that pointers don't get truncated. - { - let val = usize::MAX; - let exp = format!("{:#x}", val); - t!(format!("{:p}", val as *const isize), exp); - } - - // Escaping - t!(format!("{{"), "{"); - t!(format!("}}"), "}"); - - test_write(); - test_print(); - test_order(); - test_once(); - - // make sure that format! doesn't move out of local variables - let a: Box<_> = box 3; - format!("{}", a); - format!("{}", a); - - // make sure that format! doesn't cause spurious unused-unsafe warnings when - // it's inside of an outer unsafe block - unsafe { - let a: isize = ::std::mem::transmute(3_usize); - format!("{}", a); - } - - test_format_args(); - - // test that trailing commas are acceptable - format!("{}", "test",); - format!("{foo}", foo="test",); - - test_refcell(); -} - -// Basic test to make sure that we can invoke the `write!` macro with an -// fmt::Write instance. -fn test_write() { - let mut buf = String::new(); - write!(&mut buf, "{}", 3); - { - let w = &mut buf; - write!(w, "{foo}", foo=4); - write!(w, "{}", "hello"); - writeln!(w, "{}", "line"); - writeln!(w, "{foo}", foo="bar"); - w.write_char('☃'); - w.write_str("str"); - } - - t!(buf, "34helloline\nbar\n☃str"); -} - -// Just make sure that the macros are defined, there's not really a lot that we -// can do with them just yet (to test the output) -fn test_print() { - print!("hi"); - print!("{:?}", vec![0u8]); - println!("hello"); - println!("this is a {}", "test"); - println!("{foo}", foo="bar"); -} - -// Just make sure that the macros are defined, there's not really a lot that we -// can do with them just yet (to test the output) -fn test_format_args() { - let mut buf = String::new(); - { - let w = &mut buf; - write!(w, "{}", format_args!("{}", 1)); - write!(w, "{}", format_args!("test")); - write!(w, "{}", format_args!("{test}", test=3)); - } - let s = buf; - t!(s, "1test3"); - - let s = fmt::format(format_args!("hello {}", "world")); - t!(s, "hello world"); - let s = format!("{}: {}", "args were", format_args!("hello {}", "world")); - t!(s, "args were: hello world"); -} - -fn test_order() { - // Make sure format!() arguments are always evaluated in a left-to-right - // ordering - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } - assert_eq!(format!("{} {} {a} {b} {} {c}", - foo(), foo(), foo(), a=foo(), b=foo(), c=foo()), - "1 2 4 5 3 6".to_string()); -} - -fn test_once() { - // Make sure each argument are evaluated only once even though it may be - // formatted multiple times - fn foo() -> isize { - static mut FOO: isize = 0; - unsafe { - FOO += 1; - FOO - } - } - assert_eq!(format!("{0} {0} {0} {a} {a} {a}", foo(), a=foo()), - "1 1 1 2 2 2".to_string()); -} - -fn test_refcell() { - let refcell = RefCell::new(5); - assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); - let borrow = refcell.borrow_mut(); - assert_eq!(format!("{:?}", refcell), "RefCell { value: }"); - drop(borrow); - assert_eq!(format!("{:?}", refcell), "RefCell { value: 5 }"); -} diff --git a/src/test/ui/impl-trait/auto-trait-leak.stderr b/src/test/ui/impl-trait/auto-trait-leak.stderr index 679b26efe5..e578c4b4f8 100644 --- a/src/test/ui/impl-trait/auto-trait-leak.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak.stderr @@ -1,4 +1,4 @@ -error[E0391]: cycle detected when computing type of `cycle1::{{opaque}}#0` +error[E0391]: cycle detected when computing type of `cycle1::{opaque#0}` --> $DIR/auto-trait-leak.rs:12:16 | LL | fn cycle1() -> impl Clone { @@ -35,7 +35,7 @@ note: ...which requires type-checking `cycle1`... LL | fn cycle1() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... -note: ...which requires computing type of `cycle2::{{opaque}}#0`... +note: ...which requires computing type of `cycle2::{opaque#0}`... --> $DIR/auto-trait-leak.rs:20:16 | LL | fn cycle2() -> impl Clone { @@ -71,7 +71,7 @@ note: ...which requires type-checking `cycle2`... LL | fn cycle2() -> impl Clone { | ^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires evaluating trait selection obligation `impl std::clone::Clone: std::marker::Send`... - = note: ...which again requires computing type of `cycle1::{{opaque}}#0`, completing the cycle + = 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 | @@ -84,20 +84,20 @@ LL | | Rc::new(String::from("foo")) LL | | } | |_^ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/auto-trait-leak.rs:14:5 | LL | fn send(_: T) {} | ---- required by this bound in `send` ... LL | send(cycle2().clone()); - | ^^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^^ `Rc` cannot be sent between threads safely ... LL | fn cycle2() -> impl Clone { - | ---------- within this `impl std::clone::Clone` + | ---------- within this `impl Clone` | - = help: within `impl std::clone::Clone`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` - = note: required because it appears within the type `impl std::clone::Clone` + = help: within `impl Clone`, the trait `Send` is not implemented for `Rc` + = note: required because it appears within the type `impl Clone` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/auto-trait-leak2.rs b/src/test/ui/impl-trait/auto-trait-leak2.rs index fb4b540512..a464f576dc 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.rs +++ b/src/test/ui/impl-trait/auto-trait-leak2.rs @@ -11,10 +11,10 @@ fn send(_: T) {} fn main() { send(before()); - //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely + //~^ ERROR `Rc>` cannot be sent between threads safely send(after()); - //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely + //~^ ERROR `Rc>` cannot be sent between threads safely } // Deferred path, main has to wait until typeck finishes, diff --git a/src/test/ui/impl-trait/auto-trait-leak2.stderr b/src/test/ui/impl-trait/auto-trait-leak2.stderr index b02ef7d4a5..6b2b8248a4 100644 --- a/src/test/ui/impl-trait/auto-trait-leak2.stderr +++ b/src/test/ui/impl-trait/auto-trait-leak2.stderr @@ -1,34 +1,34 @@ -error[E0277]: `std::rc::Rc>` cannot be sent between threads safely +error[E0277]: `Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:13:5 | LL | fn before() -> impl Fn(i32) { - | ------------ within this `impl std::ops::Fn<(i32,)>` + | ------------ within this `impl Fn<(i32,)>` ... LL | fn send(_: T) {} | ---- required by this bound in `send` ... LL | send(before()); - | ^^^^ `std::rc::Rc>` cannot be sent between threads safely + | ^^^^ `Rc>` cannot be sent between threads safely | - = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22 p:std::rc::Rc>]` - = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` + = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc>` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:7:5: 7:22]` + = note: required because it appears within the type `impl Fn<(i32,)>` -error[E0277]: `std::rc::Rc>` cannot be sent between threads safely +error[E0277]: `Rc>` cannot be sent between threads safely --> $DIR/auto-trait-leak2.rs:16:5 | LL | fn send(_: T) {} | ---- required by this bound in `send` ... LL | send(after()); - | ^^^^ `std::rc::Rc>` cannot be sent between threads safely + | ^^^^ `Rc>` cannot be sent between threads safely ... LL | fn after() -> impl Fn(i32) { - | ------------ within this `impl std::ops::Fn<(i32,)>` + | ------------ within this `impl Fn<(i32,)>` | - = help: within `impl std::ops::Fn<(i32,)>`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22 p:std::rc::Rc>]` - = note: required because it appears within the type `impl std::ops::Fn<(i32,)>` + = help: within `impl Fn<(i32,)>`, the trait `Send` is not implemented for `Rc>` + = note: required because it appears within the type `[closure@$DIR/auto-trait-leak2.rs:24:5: 24:22]` + = note: required because it appears within the type `impl Fn<(i32,)>` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/bindings-opaque.stderr b/src/test/ui/impl-trait/bindings-opaque.stderr index 6656968d79..170bd46123 100644 --- a/src/test/ui/impl-trait/bindings-opaque.stderr +++ b/src/test/ui/impl-trait/bindings-opaque.stderr @@ -7,23 +7,23 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #63065 for more information -error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope +error[E0599]: no method named `count_ones` found for opaque type `impl Copy` in the current scope --> $DIR/bindings-opaque.rs:11:17 | LL | let _ = FOO.count_ones(); - | ^^^^^^^^^^ method not found in `impl std::marker::Copy` + | ^^^^^^^^^^ method not found in `impl Copy` -error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope +error[E0599]: no method named `count_ones` found for opaque type `impl Copy` in the current scope --> $DIR/bindings-opaque.rs:13:17 | LL | let _ = BAR.count_ones(); - | ^^^^^^^^^^ method not found in `impl std::marker::Copy` + | ^^^^^^^^^^ method not found in `impl Copy` -error[E0599]: no method named `count_ones` found for opaque type `impl std::marker::Copy` in the current scope +error[E0599]: no method named `count_ones` found for opaque type `impl Copy` in the current scope --> $DIR/bindings-opaque.rs:15:17 | LL | let _ = foo.count_ones(); - | ^^^^^^^^^^ method not found in `impl std::marker::Copy` + | ^^^^^^^^^^ method not found in `impl Copy` error: aborting due to 3 previous errors; 1 warning emitted diff --git a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr index 96f961a2aa..00145d10ed 100644 --- a/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr +++ b/src/test/ui/impl-trait/dyn-trait-return-should-be-impl-trait.stderr @@ -15,7 +15,7 @@ LL | fn fuz() -> (usize, Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -36,7 +36,7 @@ LL | fn bar() -> (usize, dyn Trait) { (42, Struct) } | | | doesn't have a size known at compile-time | - = help: within `(usize, (dyn Trait + 'static))`, the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` + = help: within `(usize, (dyn Trait + 'static))`, the trait `Sized` is not implemented for `(dyn Trait + 'static)` = note: required because it appears within the type `(usize, (dyn Trait + 'static))` = note: the return type of a function must have a statically known size @@ -137,15 +137,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:34:16 | LL | fn bam() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | return Struct; | ^^^^^^ | | - | expected struct `std::boxed::Box`, found struct `Struct` + | expected struct `Box`, found struct `Struct` | help: store this in the heap by calling `Box::new`: `Box::new(Struct)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found struct `Struct` = 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 @@ -153,15 +153,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:36:5 | LL | fn bam() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = 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 @@ -169,15 +169,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:40:16 | LL | fn baq() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | return 0; | ^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(0)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = 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 @@ -185,15 +185,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:42:5 | LL | fn baq() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = 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 @@ -201,15 +201,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:46:9 | LL | fn baz() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | Struct | ^^^^^^ | | - | expected struct `std::boxed::Box`, found struct `Struct` + | expected struct `Box`, found struct `Struct` | help: store this in the heap by calling `Box::new`: `Box::new(Struct)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found struct `Struct` = 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 @@ -217,15 +217,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:48:9 | LL | fn baz() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = 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 @@ -233,15 +233,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:53:9 | LL | fn baw() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type LL | if true { LL | 0 | ^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(0)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = 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 @@ -249,15 +249,15 @@ error[E0308]: mismatched types --> $DIR/dyn-trait-return-should-be-impl-trait.rs:55:9 | LL | fn baw() -> Box { - | -------------- expected `std::boxed::Box<(dyn Trait + 'static)>` because of return type + | -------------- expected `Box<(dyn Trait + 'static)>` because of return type ... LL | 42 | ^^ | | - | expected struct `std::boxed::Box`, found integer + | expected struct `Box`, found integer | help: store this in the heap by calling `Box::new`: `Box::new(42)` | - = note: expected struct `std::boxed::Box<(dyn Trait + 'static)>` + = note: expected struct `Box<(dyn Trait + 'static)>` found type `{integer}` = 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 diff --git a/src/test/ui/impl-trait/equality.stderr b/src/test/ui/impl-trait/equality.stderr index 628dfb13d4..cdaa61ac32 100644 --- a/src/test/ui/impl-trait/equality.stderr +++ b/src/test/ui/impl-trait/equality.stderr @@ -23,7 +23,7 @@ LL | 0_u32 = note: for information on `impl Trait`, see = help: if the trait `Foo` were object safe, you could return a boxed trait object = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type error[E0277]: cannot add `impl Foo` to `u32` --> $DIR/equality.rs:24:11 @@ -31,7 +31,7 @@ error[E0277]: cannot add `impl Foo` to `u32` LL | n + sum_to(n - 1) | ^ no implementation for `u32 + impl Foo` | - = help: the trait `std::ops::Add` is not implemented for `u32` + = help: the trait `Add` is not implemented for `u32` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/impl-trait/hidden-lifetimes.stderr b/src/test/ui/impl-trait/hidden-lifetimes.stderr index 956ac1f1a1..7cea4fb93d 100644 --- a/src/test/ui/impl-trait/hidden-lifetimes.stderr +++ b/src/test/ui/impl-trait/hidden-lifetimes.stderr @@ -16,7 +16,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { | ^^^^^^^^^^^^^^ | -note: hidden type `std::rc::Rc>` captures the lifetime `'b` as defined on the function body at 45:24 +note: hidden type `Rc>` captures the lifetime `'b` as defined on the function body at 45:24 --> $DIR/hidden-lifetimes.rs:45:24 | LL | fn hide_rc_refcell<'a, 'b: 'a, T: 'static>(x: Rc>) -> impl Swap + 'a { diff --git a/src/test/ui/impl-trait/impl_trait_projections.stderr b/src/test/ui/impl-trait/impl_trait_projections.stderr index ff4382187a..e85ed0eda5 100644 --- a/src/test/ui/impl-trait/impl_trait_projections.stderr +++ b/src/test/ui/impl-trait/impl_trait_projections.stderr @@ -26,7 +26,7 @@ error[E0223]: ambiguous associated type --> $DIR/impl_trait_projections.rs:12:50 | LL | fn projection_is_disallowed(x: impl Iterator) -> ::Item { - | ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Item` + | ^^^^^^^^^^^^^^^^^^^^^ help: use fully-qualified syntax: `::Item` error: aborting due to 5 previous errors diff --git a/src/test/ui/impl-trait/issue-55872-1.rs b/src/test/ui/impl-trait/issue-55872-1.rs index f99096b4d5..a746ed09af 100644 --- a/src/test/ui/impl-trait/issue-55872-1.rs +++ b/src/test/ui/impl-trait/issue-55872-1.rs @@ -1,8 +1,7 @@ // ignore-tidy-linelength #![feature(type_alias_impl_trait)] -pub trait Bar -{ +pub trait Bar { type E: Copy; fn foo() -> Self::E; @@ -10,11 +9,12 @@ pub trait Bar impl Bar for S { type E = impl Copy; - //~^ ERROR the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` [E0277] - //~^^ ERROR the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` [E0277] + //~^ ERROR the trait bound `S: Copy` is not satisfied in `(S, T)` [E0277] + //~^^ ERROR the trait bound `T: Copy` is not satisfied in `(S, T)` [E0277] fn foo() -> Self::E { - //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias + //~| ERROR impl has stricter requirements than trait (S::default(), T::default()) } } diff --git a/src/test/ui/impl-trait/issue-55872-1.stderr b/src/test/ui/impl-trait/issue-55872-1.stderr index 5131509cdf..db49d988bb 100644 --- a/src/test/ui/impl-trait/issue-55872-1.stderr +++ b/src/test/ui/impl-trait/issue-55872-1.stderr @@ -1,39 +1,50 @@ -error[E0277]: the trait bound `S: std::marker::Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:14 +error[E0276]: impl has stricter requirements than trait + --> $DIR/issue-55872-1.rs:15:5 | -LL | type E = impl Copy; - | ^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `S` - | - = note: required because it appears within the type `(S, T)` - = note: the return type of a function must have a statically known size -help: consider further restricting this bound - | -LL | impl Bar for S { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo() -> Self::E; + | ----------------------- definition of `foo` from trait +... +LL | fn foo() -> Self::E { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl has extra requirement `T: Default` -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied in `(S, T)` - --> $DIR/issue-55872-1.rs:12:14 +error[E0277]: the trait bound `S: Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:11:14 | LL | type E = impl Copy; - | ^^^^^^^^^ within `(S, T)`, the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `S` | = note: required because it appears within the type `(S, T)` = note: the return type of a function must have a statically known size help: consider further restricting this bound | -LL | fn foo() -> Self::E { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Bar for S { + | ^^^^^^ + +error[E0277]: the trait bound `T: Copy` is not satisfied in `(S, T)` + --> $DIR/issue-55872-1.rs:11:14 + | +LL | type E = impl Copy; + | ^^^^^^^^^ within `(S, T)`, the trait `Copy` is not implemented for `T` + | + = note: required because it appears within the type `(S, T)` + = note: the return type of a function must have a statically known size +help: consider further restricting this bound + | +LL | fn foo() -> Self::E { + | ^^^^^^ error: type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias - --> $DIR/issue-55872-1.rs:16:37 + --> $DIR/issue-55872-1.rs:15:37 | LL | fn foo() -> Self::E { | _____________________________________^ LL | | +LL | | LL | | (S::default(), T::default()) LL | | } | |_____^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors -For more information about this error, try `rustc --explain E0277`. +Some errors have detailed explanations: E0276, E0277. +For more information about an error, try `rustc --explain E0276`. diff --git a/src/test/ui/impl-trait/issue-55872-2.rs b/src/test/ui/impl-trait/issue-55872-2.rs index 1ca2e3d906..7708576ae7 100644 --- a/src/test/ui/impl-trait/issue-55872-2.rs +++ b/src/test/ui/impl-trait/issue-55872-2.rs @@ -10,8 +10,8 @@ pub trait Bar { } impl Bar for S { - type E = impl Copy; - //~^ ERROR the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied [E0277] + type E = impl std::marker::Copy; + //~^ ERROR the trait bound `impl Future: Copy` is not satisfied [E0277] fn foo() -> Self::E { //~^ ERROR type parameter `T` is part of concrete type but not used in parameter list for the `impl Trait` type alias async {} diff --git a/src/test/ui/impl-trait/issue-55872-2.stderr b/src/test/ui/impl-trait/issue-55872-2.stderr index 649109e4c9..6da3704184 100644 --- a/src/test/ui/impl-trait/issue-55872-2.stderr +++ b/src/test/ui/impl-trait/issue-55872-2.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `impl std::future::Future: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `impl Future: Copy` is not satisfied --> $DIR/issue-55872-2.rs:13:14 | -LL | type E = impl Copy; - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `impl std::future::Future` +LL | type E = impl std::marker::Copy; + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `impl Future` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/impl-trait/issue-56445.rs b/src/test/ui/impl-trait/issue-56445.rs index a34d7bae3a..6dd1648c9b 100644 --- a/src/test/ui/impl-trait/issue-56445.rs +++ b/src/test/ui/impl-trait/issue-56445.rs @@ -5,8 +5,7 @@ use std::marker::PhantomData; -pub struct S<'a> -{ +pub struct S<'a> { pub m1: PhantomData<&'a u8>, pub m2: [u8; S::size()], } diff --git a/src/test/ui/impl-trait/issue-72911.stderr b/src/test/ui/impl-trait/issue-72911.stderr index b28142b916..17748ae427 100644 --- a/src/test/ui/impl-trait/issue-72911.stderr +++ b/src/test/ui/impl-trait/issue-72911.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:12:33 | LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/issue-72911.rs:17:41 | LL | fn lint_files() -> impl Iterator { - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error[E0720]: cannot resolve opaque type --> $DIR/issue-72911.rs:7:24 @@ -19,14 +19,14 @@ LL | LL | lint_files().flat_map(|f| gather_from_file(&f)) | ----------------------------------------------- | | - | returning here with type `std::iter::FlatMap` - | returning here with type `std::iter::FlatMap` + | returning here with type `FlatMap` + | returning here with type `FlatMap` ... LL | fn gather_from_file(dir_entry: &foo::MissingItem) -> impl Iterator { - | -------------------------- returning this opaque type `std::iter::FlatMap` + | -------------------------- returning this opaque type `FlatMap` ... LL | fn lint_files() -> impl Iterator { - | -------------------------------------- returning this opaque type `std::iter::FlatMap` + | -------------------------------------- returning this opaque type `FlatMap` error: aborting due to 3 previous errors diff --git a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr index c538b77098..16a1262ec2 100644 --- a/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr +++ b/src/test/ui/impl-trait/issues/infinite-impl-trait-issue-38064.stderr @@ -5,22 +5,22 @@ LL | fn foo() -> impl Quux { | ^^^^^^^^^ recursive opaque type ... LL | Foo(bar()) - | ---------- returning here with type `foo::Foo` + | ---------- returning here with type `Foo` ... LL | fn bar() -> impl Quux { - | --------- returning this opaque type `foo::Foo` + | --------- returning this opaque type `Foo` error[E0720]: cannot resolve opaque type --> $DIR/infinite-impl-trait-issue-38064.rs:14:13 | LL | fn foo() -> impl Quux { - | --------- returning this opaque type `bar::Bar` + | --------- returning this opaque type `Bar` ... LL | fn bar() -> impl Quux { | ^^^^^^^^^ recursive opaque type ... LL | Bar(foo()) - | ---------- returning here with type `bar::Bar` + | ---------- returning here with type `Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr index 7f2eb0c21e..f6bb52bf63 100644 --- a/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr +++ b/src/test/ui/impl-trait/method-suggestion-no-duplication.stderr @@ -9,7 +9,7 @@ LL | foo(|s| s.is_empty()); | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `is_empty`, perhaps you need to implement it: - candidate #1: `std::iter::ExactSizeIterator` + candidate #1: `ExactSizeIterator` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/no-method-suggested-traits.stderr b/src/test/ui/impl-trait/no-method-suggested-traits.stderr index 3cd4d0dd39..64ddcb81c0 100644 --- a/src/test/ui/impl-trait/no-method-suggested-traits.stderr +++ b/src/test/ui/impl-trait/no-method-suggested-traits.stderr @@ -16,11 +16,11 @@ LL | use no_method_suggested_traits::qux::PrivPub; LL | use no_method_suggested_traits::Reexported; | -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&u32>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&u32>>` in the current scope --> $DIR/no-method-suggested-traits.rs:26:44 | LL | std::rc::Rc::new(&mut Box::new(&1u32)).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u32>>` + | ^^^^^^ method not found in `Rc<&mut Box<&u32>>` | = help: items from traits can only be used if the trait is in scope help: the following traits are implemented but not in scope; perhaps add a `use` for one of them: @@ -46,11 +46,11 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use foo::Bar; | -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&char>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&char>>` in the current scope --> $DIR/no-method-suggested-traits.rs:32:43 | LL | std::rc::Rc::new(&mut Box::new(&'a')).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&char>>` + | ^^^^^^ method not found in `Rc<&mut Box<&char>>` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -70,11 +70,11 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use no_method_suggested_traits::foo::PubPub; | -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&i32>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&i32>>` in the current scope --> $DIR/no-method-suggested-traits.rs:37:44 | LL | std::rc::Rc::new(&mut Box::new(&1i32)).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&i32>>` + | ^^^^^^ method not found in `Rc<&mut Box<&i32>>` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -94,22 +94,22 @@ LL | Foo.method(); = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `method`, perhaps you need to implement one of them: candidate #1: `foo::Bar` - candidate #2: `no_method_suggested_traits::foo::PubPub` + candidate #2: `PubPub` candidate #3: `no_method_suggested_traits::qux::PrivPub` - candidate #4: `no_method_suggested_traits::Reexported` + candidate #4: `Reexported` -error[E0599]: no method named `method` found for struct `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope +error[E0599]: no method named `method` found for struct `Rc<&mut Box<&Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:42:43 | LL | std::rc::Rc::new(&mut Box::new(&Foo)).method(); - | ^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Foo>>` + | ^^^^^^ method not found in `Rc<&mut Box<&Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following traits define an item `method`, perhaps you need to implement one of them: candidate #1: `foo::Bar` - candidate #2: `no_method_suggested_traits::foo::PubPub` + candidate #2: `PubPub` candidate #3: `no_method_suggested_traits::qux::PrivPub` - candidate #4: `no_method_suggested_traits::Reexported` + candidate #4: `Reexported` error[E0599]: no method named `method2` found for type `u64` in the current scope --> $DIR/no-method-suggested-traits.rs:45:10 @@ -124,11 +124,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it LL | pub trait Bar { | ^^^^^^^^^^^^^ -error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&u64>>` in the current scope +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&u64>>` in the current scope --> $DIR/no-method-suggested-traits.rs:47:44 | LL | std::rc::Rc::new(&mut Box::new(&1u64)).method2(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&u64>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&u64>>` | = help: items from traits can only be used if the trait is implemented and in scope note: `foo::Bar` defines an item `method2`, perhaps you need to implement it @@ -150,11 +150,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it LL | pub trait Bar { | ^^^^^^^^^^^^^ -error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:52:71 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method2(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope note: `foo::Bar` defines an item `method2`, perhaps you need to implement it @@ -176,11 +176,11 @@ note: `foo::Bar` defines an item `method2`, perhaps you need to implement it LL | pub trait Bar { | ^^^^^^^^^^^^^ -error[E0599]: no method named `method2` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope +error[E0599]: no method named `method2` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:56:74 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method2(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>` | = help: items from traits can only be used if the trait is implemented and in scope note: `foo::Bar` defines an item `method2`, perhaps you need to implement it @@ -200,17 +200,17 @@ LL | Foo.method3(); | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&Foo>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:61:43 | LL | std::rc::Rc::new(&mut Box::new(&Foo)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Foo>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&Foo>>` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` error[E0599]: no method named `method3` found for enum `Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:63:12 @@ -223,17 +223,17 @@ LL | Bar::X.method3(); | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&Bar>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:65:46 | LL | std::rc::Rc::new(&mut Box::new(&Bar::X)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&Bar>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&Bar>>` | = help: items from traits can only be used if the trait is implemented and in scope = note: the following trait defines an item `method3`, perhaps you need to implement it: - candidate #1: `no_method_suggested_traits::foo::PubPub` + candidate #1: `PubPub` error[E0599]: no method named `method3` found for type `usize` in the current scope --> $DIR/no-method-suggested-traits.rs:69:13 @@ -241,11 +241,11 @@ error[E0599]: no method named `method3` found for type `usize` in the current sc LL | 1_usize.method3(); | ^^^^^^^ method not found in `usize` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&usize>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&usize>>` in the current scope --> $DIR/no-method-suggested-traits.rs:70:47 | LL | std::rc::Rc::new(&mut Box::new(&1_usize)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&usize>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&usize>>` error[E0599]: no method named `method3` found for struct `no_method_suggested_traits::Foo` in the current scope --> $DIR/no-method-suggested-traits.rs:71:37 @@ -253,11 +253,11 @@ error[E0599]: no method named `method3` found for struct `no_method_suggested_tr LL | no_method_suggested_traits::Foo.method3(); | ^^^^^^^ method not found in `no_method_suggested_traits::Foo` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Foo>>` in the current scope --> $DIR/no-method-suggested-traits.rs:72:71 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Foo)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Foo>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Foo>>` error[E0599]: no method named `method3` found for enum `no_method_suggested_traits::Bar` in the current scope --> $DIR/no-method-suggested-traits.rs:74:40 @@ -265,11 +265,11 @@ error[E0599]: no method named `method3` found for enum `no_method_suggested_trai LL | no_method_suggested_traits::Bar::X.method3(); | ^^^^^^^ method not found in `no_method_suggested_traits::Bar` -error[E0599]: no method named `method3` found for struct `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` in the current scope +error[E0599]: no method named `method3` found for struct `Rc<&mut Box<&no_method_suggested_traits::Bar>>` in the current scope --> $DIR/no-method-suggested-traits.rs:75:74 | LL | std::rc::Rc::new(&mut Box::new(&no_method_suggested_traits::Bar::X)).method3(); - | ^^^^^^^ method not found in `std::rc::Rc<&mut std::boxed::Box<&no_method_suggested_traits::Bar>>` + | ^^^^^^^ method not found in `Rc<&mut Box<&no_method_suggested_traits::Bar>>` error: aborting due to 24 previous errors diff --git a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr index dd4260fbe4..66043267f9 100644 --- a/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr +++ b/src/test/ui/impl-trait/object-unsafe-trait-in-return-position-impl-trait.stderr @@ -14,7 +14,7 @@ LL | B = note: for information on `impl Trait`, see = help: if the trait `NotObjectSafe` were object safe, you could return a boxed trait object = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type error[E0308]: mismatched types --> $DIR/object-unsafe-trait-in-return-position-impl-trait.rs:43:5 @@ -30,9 +30,18 @@ LL | B | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn cat() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(A); +LL | } +LL | Box::new(B) + | error: aborting due to 2 previous errors diff --git a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr index 75ff9e078c..0f89ec2475 100644 --- a/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr +++ b/src/test/ui/impl-trait/recursive-impl-trait-type-indirect.stderr @@ -5,9 +5,9 @@ LL | fn option(i: i32) -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | if i < 0 { None } else { Some((option(i - 1), i)) } - | ---- ------------------------ returning here with type `std::option::Option<(impl Sized, i32)>` + | ---- ------------------------ returning here with type `Option<(impl Sized, i32)>` | | - | returning here with type `std::option::Option<(impl Sized, i32)>` + | returning here with type `Option<(impl Sized, i32)>` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:12:15 @@ -54,7 +54,7 @@ LL | fn closure_capture() -> impl Sized { LL | / move || { LL | | x; LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6 x:impl Sized]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:35:5: 37:6]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:40:29 @@ -65,7 +65,7 @@ LL | fn closure_ref_capture() -> impl Sized { LL | / move || { LL | | &x; LL | | } - | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6 x:impl Sized]` + | |_____- returning here with type `[closure@$DIR/recursive-impl-trait-type-indirect.rs:43:5: 45:6]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:48:21 @@ -95,7 +95,7 @@ LL | / move || { LL | | yield; LL | | x; LL | | } - | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 x:impl Sized {()}]` + | |_____- returning here with type `[generator@$DIR/recursive-impl-trait-type-indirect.rs:61:5: 64:6 {()}]` error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:67:35 @@ -135,13 +135,13 @@ error[E0720]: cannot resolve opaque type --> $DIR/recursive-impl-trait-type-indirect.rs:91:28 | LL | fn mutual_recursion() -> impl Sync { - | --------- returning this opaque type `impl std::marker::Sync` + | --------- returning this opaque type `impl Sync` ... LL | fn mutual_recursion_b() -> impl Sized { | ^^^^^^^^^^ recursive opaque type LL | LL | mutual_recursion() - | ------------------ returning here with type `impl std::marker::Sync` + | ------------------ returning here with type `impl Sync` error: aborting due to 14 previous errors diff --git a/src/test/ui/impl-trait/region-escape-via-bound.stderr b/src/test/ui/impl-trait/region-escape-via-bound.stderr index 894a65ff38..969ddc57af 100644 --- a/src/test/ui/impl-trait/region-escape-via-bound.stderr +++ b/src/test/ui/impl-trait/region-escape-via-bound.stderr @@ -4,7 +4,7 @@ error[E0700]: hidden type for `impl Trait` captures lifetime that does not appea LL | fn foo(x: Cell<&'x u32>) -> impl Trait<'y> | ^^^^^^^^^^^^^^ | -note: hidden type `std::cell::Cell<&'x u32>` captures the lifetime `'x` as defined on the function body at 17:7 +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 | LL | where 'x: 'y diff --git a/src/test/ui/impl-trait/trait_type.stderr b/src/test/ui/impl-trait/trait_type.stderr index 748bc639a0..e94f2c7021 100644 --- a/src/test/ui/impl-trait/trait_type.stderr +++ b/src/test/ui/impl-trait/trait_type.stderr @@ -4,7 +4,7 @@ error[E0053]: method `fmt` has an incompatible type for trait LL | fn fmt(&self, x: &str) -> () { } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ types differ in mutability | - = note: expected fn pointer `fn(&MyType, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = note: expected fn pointer `fn(&MyType, &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` found fn pointer `fn(&MyType, &str)` error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fmt::Display::fmt` has 2 @@ -13,7 +13,7 @@ error[E0050]: method `fmt` has 1 parameter but the declaration in trait `std::fm LL | fn fmt(&self) -> () { } | ^^^^^ expected 2 parameters, found 1 | - = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = note: `fmt` from trait: `fn(&Self, &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in the impl --> $DIR/trait_type.rs:17:4 @@ -21,7 +21,7 @@ error[E0186]: method `fmt` has a `&self` declaration in the trait, but not in th LL | fn fmt() -> () { } | ^^^^^^^^^^^^^^ expected `&self` in impl | - = note: `fmt` from trait: `fn(&Self, &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` + = note: `fmt` from trait: `fn(&Self, &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error>` error[E0046]: not all trait items implemented, missing: `fmt` --> $DIR/trait_type.rs:21:1 @@ -29,7 +29,7 @@ error[E0046]: not all trait items implemented, missing: `fmt` LL | impl std::fmt::Display for MyType4 {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation | - = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` + = help: implement the missing item: `fn fmt(&self, _: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` error: aborting due to 4 previous errors diff --git a/src/test/ui/impl-trait/universal-mismatched-type.stderr b/src/test/ui/impl-trait/universal-mismatched-type.stderr index a12b01b4d2..817c573c09 100644 --- a/src/test/ui/impl-trait/universal-mismatched-type.stderr +++ b/src/test/ui/impl-trait/universal-mismatched-type.stderr @@ -2,13 +2,13 @@ error[E0308]: mismatched types --> $DIR/universal-mismatched-type.rs:4:5 | LL | fn foo(x: impl Debug) -> String { - | ---------- ------ expected `std::string::String` because of return type + | ---------- ------ expected `String` because of return type | | | this type parameter LL | x - | ^ expected struct `std::string::String`, found type parameter `impl Debug` + | ^ expected struct `String`, found type parameter `impl Debug` | - = note: expected struct `std::string::String` + = note: expected struct `String` found type parameter `impl Debug` error: aborting due to previous error diff --git a/src/test/ui/impl-trait/where-allowed.rs b/src/test/ui/impl-trait/where-allowed.rs index 211a14ed4d..72b880fb92 100644 --- a/src/test/ui/impl-trait/where-allowed.rs +++ b/src/test/ui/impl-trait/where-allowed.rs @@ -56,10 +56,12 @@ fn in_impl_Fn_return_in_parameters(_: &impl Fn() -> impl Debug) { panic!() } fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types //~| ERROR nested `impl Trait` is not allowed +//~| ERROR cannot resolve opaque type // Disallowed fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } //~^ ERROR `impl Trait` not allowed outside of function and inherent method return types +//~| ERROR cannot resolve opaque type // Disallowed fn in_Fn_parameter_in_generics (_: F) { panic!() } diff --git a/src/test/ui/impl-trait/where-allowed.stderr b/src/test/ui/impl-trait/where-allowed.stderr index 7addc006e1..93f9724140 100644 --- a/src/test/ui/impl-trait/where-allowed.stderr +++ b/src/test/ui/impl-trait/where-allowed.stderr @@ -17,7 +17,7 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | outer `impl Trait` error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:119:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ @@ -26,7 +26,7 @@ LL | type Out = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:155:23 + --> $DIR/where-allowed.rs:157:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | type InTypeAlias = impl Debug; = help: add `#![feature(type_alias_impl_trait)]` to the crate attributes to enable error[E0658]: `impl Trait` in type aliases is unstable - --> $DIR/where-allowed.rs:159:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ @@ -110,139 +110,139 @@ LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:61:59 + --> $DIR/where-allowed.rs:62:59 | LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:65:38 + --> $DIR/where-allowed.rs:67:38 | LL | fn in_Fn_parameter_in_generics (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:69:40 + --> $DIR/where-allowed.rs:71:40 | LL | fn in_Fn_return_in_generics impl Debug> (_: F) { panic!() } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:82:32 + --> $DIR/where-allowed.rs:84:32 | LL | struct InBraceStructField { x: impl Debug } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:86:41 + --> $DIR/where-allowed.rs:88:41 | LL | struct InAdtInBraceStructField { x: Vec } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:90:27 + --> $DIR/where-allowed.rs:92:27 | LL | struct InTupleStructField(impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:95:25 + --> $DIR/where-allowed.rs:97:25 | LL | InBraceVariant { x: impl Debug }, | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:97:20 + --> $DIR/where-allowed.rs:99:20 | LL | InTupleVariant(impl Debug), | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:108:23 + --> $DIR/where-allowed.rs:110:23 | LL | fn in_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:126:34 + --> $DIR/where-allowed.rs:128:34 | LL | fn in_trait_impl_return() -> impl Debug { () } | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:139:33 + --> $DIR/where-allowed.rs:141:33 | LL | fn in_foreign_parameters(_: impl Debug); | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:142:31 + --> $DIR/where-allowed.rs:144:31 | LL | fn in_foreign_return() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:159:39 + --> $DIR/where-allowed.rs:161:39 | LL | type InReturnInTypeAlias = fn() -> impl Debug; | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:164:16 + --> $DIR/where-allowed.rs:166:16 | LL | impl PartialEq for () { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:169:24 + --> $DIR/where-allowed.rs:171:24 | LL | impl PartialEq<()> for impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:174:6 + --> $DIR/where-allowed.rs:176:6 | LL | impl impl Debug { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:180:24 + --> $DIR/where-allowed.rs:182:24 | LL | impl InInherentImplAdt { | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:186:11 + --> $DIR/where-allowed.rs:188:11 | LL | where impl Debug: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:193:15 + --> $DIR/where-allowed.rs:195:15 | LL | where Vec: Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:200:24 + --> $DIR/where-allowed.rs:202:24 | LL | where T: PartialEq | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:207:17 + --> $DIR/where-allowed.rs:209:17 | LL | where T: Fn(impl Debug) | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:214:22 + --> $DIR/where-allowed.rs:216:22 | LL | where T: Fn() -> impl Debug | ^^^^^^^^^^ error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:220:29 + --> $DIR/where-allowed.rs:222:29 | LL | let _in_local_variable: impl Fn() = || {}; | ^^^^^^^^^ @@ -250,24 +250,44 @@ LL | let _in_local_variable: impl Fn() = || {}; = help: add `#![feature(impl_trait_in_bindings)]` to the crate attributes to enable error[E0562]: `impl Trait` not allowed outside of function and inherent method return types - --> $DIR/where-allowed.rs:222:46 + --> $DIR/where-allowed.rs:224:46 | LL | let _in_return_in_local_variable = || -> impl Fn() { || {} }; | ^^^^^^^^^ +error[E0720]: cannot resolve opaque type + --> $DIR/where-allowed.rs:56:49 + | +LL | fn in_impl_Fn_parameter_in_return() -> &'static impl Fn(impl Debug) { panic!() } + | ^^^^^^^^^^^^^^^^^^^ -------- this returned value is of `!` type + | | + | cannot resolve opaque type + | + = help: this error will resolve once the item's body returns a concrete type + +error[E0720]: cannot resolve opaque type + --> $DIR/where-allowed.rs:62:46 + | +LL | fn in_impl_Fn_return_in_return() -> &'static impl Fn() -> impl Debug { panic!() } + | ^^^^^^^^^^^^^^^^^^^^^^^ -------- this returned value is of `!` type + | | + | cannot resolve opaque type + | + = help: this error will resolve once the item's body returns a concrete type + error: could not find defining uses - --> $DIR/where-allowed.rs:119:16 + --> $DIR/where-allowed.rs:121:16 | LL | type Out = impl Debug; | ^^^^^^^^^^ error: could not find defining uses - --> $DIR/where-allowed.rs:155:23 + --> $DIR/where-allowed.rs:157:23 | LL | type InTypeAlias = impl Debug; | ^^^^^^^^^^ -error: aborting due to 42 previous errors +error: aborting due to 44 previous errors -Some errors have detailed explanations: E0562, E0658, E0666. +Some errors have detailed explanations: E0562, E0658, E0666, E0720. For more information about an error, try `rustc --explain E0562`. diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs index 6b70efe0c4..4a0c612020 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.rs +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.rs @@ -1,3 +1,5 @@ +// ignore-tidy-linelength + // aux-build:two_macros.rs // compile-flags:--extern non_existent @@ -7,7 +9,7 @@ mod n { mod m { fn check() { - two_macros::m!(); //~ ERROR failed to resolve: use of undeclared type or module `two_macros` + two_macros::m!(); //~ ERROR failed to resolve: use of undeclared crate or module `two_macros` } } diff --git a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr index f7544306d3..2d7a1bf468 100644 --- a/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr +++ b/src/test/ui/imports/extern-prelude-extern-crate-fail.stderr @@ -1,5 +1,5 @@ error: macro-expanded `extern crate` items cannot shadow names passed with `--extern` - --> $DIR/extern-prelude-extern-crate-fail.rs:16:9 + --> $DIR/extern-prelude-extern-crate-fail.rs:18:9 | LL | extern crate std as non_existent; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -9,11 +9,11 @@ LL | define_std_as_non_existent!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0433]: failed to resolve: use of undeclared type or module `two_macros` - --> $DIR/extern-prelude-extern-crate-fail.rs:10:9 +error[E0433]: failed to resolve: use of undeclared crate or module `two_macros` + --> $DIR/extern-prelude-extern-crate-fail.rs:12:9 | LL | two_macros::m!(); - | ^^^^^^^^^^ use of undeclared type or module `two_macros` + | ^^^^^^^^^^ use of undeclared crate or module `two_macros` error: aborting due to 2 previous errors diff --git a/src/test/ui/imports/issue-62767.rs b/src/test/ui/imports/issue-62767.rs index 984d3f0ca9..0e0f915ea5 100644 --- a/src/test/ui/imports/issue-62767.rs +++ b/src/test/ui/imports/issue-62767.rs @@ -1,5 +1,4 @@ -// check-pass - +// Minimized case from #62767. mod m { pub enum Same { Same, @@ -8,8 +7,22 @@ mod m { use m::*; -// The variant `Same` introduced by this import is not considered when resolving the prefix -// `Same::` during import validation (issue #62767). -use Same::Same; +// The variant `Same` introduced by this import is also considered when resolving the prefix +// `Same::` during import validation to avoid effects similar to time travel (#74556). +use Same::Same; //~ ERROR unresolved import `Same` + +// Case from #74556. +mod foo { + pub mod bar { + pub mod bar { + pub fn foobar() {} + } + } +} + +use foo::*; +use bar::bar; //~ ERROR unresolved import `bar::bar` + //~| ERROR inconsistent resolution for an import +use bar::foobar; fn main() {} diff --git a/src/test/ui/imports/issue-62767.stderr b/src/test/ui/imports/issue-62767.stderr new file mode 100644 index 0000000000..a4334bda6d --- /dev/null +++ b/src/test/ui/imports/issue-62767.stderr @@ -0,0 +1,21 @@ +error: inconsistent resolution for an import + --> $DIR/issue-62767.rs:24:5 + | +LL | use bar::bar; + | ^^^^^^^^ + +error[E0432]: unresolved import `Same` + --> $DIR/issue-62767.rs:12:5 + | +LL | use Same::Same; + | ^^^^ `Same` is a variant, not a module + +error[E0432]: unresolved import `bar::bar` + --> $DIR/issue-62767.rs:24:5 + | +LL | use bar::bar; + | ^^^^^^^^ no `bar` in `foo::bar::bar` + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0432`. diff --git a/src/test/ui/index-help.stderr b/src/test/ui/index-help.stderr index cd4d835674..78a8f439a7 100644 --- a/src/test/ui/index-help.stderr +++ b/src/test/ui/index-help.stderr @@ -4,8 +4,8 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `i32` LL | x[0i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[{integer}]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec<{integer}>` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `Vec<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/indexing-requires-a-uint.stderr b/src/test/ui/indexing-requires-a-uint.stderr index 70614cbbf9..31fcd4b1c2 100644 --- a/src/test/ui/indexing-requires-a-uint.stderr +++ b/src/test/ui/indexing-requires-a-uint.stderr @@ -4,8 +4,8 @@ error[E0277]: the type `[{integer}]` cannot be indexed by `u8` LL | [0][0u8]; | ^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[{integer}]>` is not implemented for `u8` - = note: required because of the requirements on the impl of `std::ops::Index` for `[{integer}]` + = help: the trait `SliceIndex<[{integer}]>` is not implemented for `u8` + = note: required because of the requirements on the impl of `Index` for `[{integer}]` error[E0308]: mismatched types --> $DIR/indexing-requires-a-uint.rs:12:18 diff --git a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr index 89a22f5e5d..b6e3bb190e 100644 --- a/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr +++ b/src/test/ui/inference/cannot-infer-async-enabled-impl-trait-bindings.stderr @@ -7,11 +7,11 @@ LL | #![feature(impl_trait_in_bindings)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #63065 for more information -error[E0282]: type annotations needed for `impl std::future::Future` +error[E0282]: type annotations needed for `impl Future` --> $DIR/cannot-infer-async-enabled-impl-trait-bindings.rs:13:9 | LL | let fut = async { - | --- consider giving `fut` the explicit type `impl std::future::Future`, with the type parameters specified + | --- consider giving `fut` the explicit type `impl Future`, with the type parameters specified LL | make_unit()?; | ^^^^^^^^^^^^ cannot infer type diff --git a/src/test/ui/inference/inference_unstable_featured.stderr b/src/test/ui/inference/inference_unstable_featured.stderr index e23b934ac1..0dd4baf80d 100644 --- a/src/test/ui/inference/inference_unstable_featured.stderr +++ b/src/test/ui/inference/inference_unstable_featured.stderr @@ -4,16 +4,16 @@ error[E0034]: multiple applicable items in scope LL | assert_eq!('x'.ipu_flatten(), 0); | ^^^^^^^^^^^ multiple `ipu_flatten` found | - = note: candidate #1 is defined in an impl of the trait `inference_unstable_iterator::IpuIterator` for the type `char` - = note: candidate #2 is defined in an impl of the trait `inference_unstable_itertools::IpuItertools` for the type `char` + = note: candidate #1 is defined in an impl of the trait `IpuIterator` for the type `char` + = note: candidate #2 is defined in an impl of the trait `IpuItertools` for the type `char` help: disambiguate the associated function for candidate #1 | -LL | assert_eq!(inference_unstable_iterator::IpuIterator::ipu_flatten(&'x'), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert_eq!(IpuIterator::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | assert_eq!(inference_unstable_itertools::IpuItertools::ipu_flatten(&'x'), 0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | assert_eq!(IpuItertools::ipu_flatten(&'x'), 0); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/infinite/infinite-instantiation.rs b/src/test/ui/infinite/infinite-instantiation.rs index 9fee01c1ba..9b9f332ca8 100644 --- a/src/test/ui/infinite/infinite-instantiation.rs +++ b/src/test/ui/infinite/infinite-instantiation.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" trait ToOpt: Sized { fn to_option(&self) -> Option; @@ -19,7 +20,7 @@ impl ToOpt for Option { fn function(counter: usize, t: T) { if counter > 0 { function(counter - 1, t.to_option()); - //~^ ERROR reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/infinite-instantiation.rs:21:9 +error: reached the recursion limit while instantiating `function::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/infinite-instantiation.rs:22:9 | LL | function(counter - 1, t.to_option()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `function` defined here - --> $DIR/infinite-instantiation.rs:19:1 + --> $DIR/infinite-instantiation.rs:20:1 | LL | fn function(counter: usize, t: T) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/infinite/infinite-instantiation/infinite-instantiation.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.rs b/src/test/ui/infinite/infinite-recursion-const-fn.rs index 8289a3db6f..3458040792 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.rs +++ b/src/test/ui/infinite/infinite-recursion-const-fn.rs @@ -1,7 +1,12 @@ //https://github.com/rust-lang/rust/issues/31364 -const fn a() -> usize { b() } //~ ERROR cycle detected when const-evaluating `a` [E0391] -const fn b() -> usize { a() } +const fn a() -> usize { + //~^ ERROR cycle detected when const-evaluating + checking `a` [E0391] + b() +} +const fn b() -> usize { + a() +} const ARR: [i32; a()] = [5; 6]; -fn main(){} +fn main() {} diff --git a/src/test/ui/infinite/infinite-recursion-const-fn.stderr b/src/test/ui/infinite/infinite-recursion-const-fn.stderr index de0c579f63..7ccc7cc987 100644 --- a/src/test/ui/infinite/infinite-recursion-const-fn.stderr +++ b/src/test/ui/infinite/infinite-recursion-const-fn.stderr @@ -1,17 +1,17 @@ -error[E0391]: cycle detected when const-evaluating `a` +error[E0391]: cycle detected when const-evaluating + checking `a` --> $DIR/infinite-recursion-const-fn.rs:3:1 | -LL | const fn a() -> usize { b() } +LL | const fn a() -> usize { | ^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `b`... - --> $DIR/infinite-recursion-const-fn.rs:4:1 +note: ...which requires const-evaluating + checking `b`... + --> $DIR/infinite-recursion-const-fn.rs:7:1 | -LL | const fn b() -> usize { a() } +LL | const fn b() -> usize { | ^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `a`, completing the cycle -note: cycle used when const-evaluating `ARR::{{constant}}#0` - --> $DIR/infinite-recursion-const-fn.rs:5:18 + = note: ...which again requires const-evaluating + checking `a`, completing the cycle +note: cycle used when const-evaluating + checking `ARR::{constant#0}` + --> $DIR/infinite-recursion-const-fn.rs:10:18 | LL | const ARR: [i32; a()] = [5; 6]; | ^^^ diff --git a/src/test/ui/infinite/infinite-tag-type-recursion.stderr b/src/test/ui/infinite/infinite-tag-type-recursion.stderr index 6d1df4fda2..45322ea967 100644 --- a/src/test/ui/infinite/infinite-tag-type-recursion.stderr +++ b/src/test/ui/infinite/infinite-tag-type-recursion.stderr @@ -18,7 +18,7 @@ LL | enum MList { Cons(isize, MList), Nil } | ^^^^^^^^^^ | = note: ...which again requires computing drop-check constraints for `MList`, 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, def_id: None }, value: MList } }` + = note: cycle used when computing dropck types for `Canonical { max_universe: U0, variables: [], value: ParamEnvAnd { param_env: ParamEnv { caller_bounds: [], reveal: UserFacing }, value: MList } }` error: aborting due to 2 previous errors diff --git a/src/test/ui/inner-static-type-parameter.stderr b/src/test/ui/inner-static-type-parameter.stderr index 1e74445af5..990e4649a5 100644 --- a/src/test/ui/inner-static-type-parameter.stderr +++ b/src/test/ui/inner-static-type-parameter.stderr @@ -12,7 +12,7 @@ error[E0392]: parameter `T` is never used LL | enum Bar { What } | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/integral-indexing.stderr b/src/test/ui/integral-indexing.stderr index 28ef5937ea..fcd79d19aa 100644 --- a/src/test/ui/integral-indexing.stderr +++ b/src/test/ui/integral-indexing.stderr @@ -4,8 +4,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `u8` LL | v[3u8]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u8` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u8` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `i8` --> $DIR/integral-indexing.rs:7:5 @@ -13,8 +13,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `i8` LL | v[3i8]; | ^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i8` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i8` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `u32` --> $DIR/integral-indexing.rs:8:5 @@ -22,8 +22,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `u32` LL | v[3u32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `u32` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `u32` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[isize]` cannot be indexed by `i32` --> $DIR/integral-indexing.rs:9:5 @@ -31,8 +31,8 @@ error[E0277]: the type `[isize]` cannot be indexed by `i32` LL | v[3i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[isize]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `std::vec::Vec` + = help: the trait `SliceIndex<[isize]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `Vec` error[E0277]: the type `[u8]` cannot be indexed by `u8` --> $DIR/integral-indexing.rs:12:5 @@ -40,8 +40,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `u8` LL | s.as_bytes()[3u8]; | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u8` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u8` + = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `i8` --> $DIR/integral-indexing.rs:13:5 @@ -49,8 +49,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `i8` LL | s.as_bytes()[3i8]; | ^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i8` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i8` + = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `u32` --> $DIR/integral-indexing.rs:14:5 @@ -58,8 +58,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `u32` LL | s.as_bytes()[3u32]; | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `u32` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `u32` + = note: required because of the requirements on the impl of `Index` for `[u8]` error[E0277]: the type `[u8]` cannot be indexed by `i32` --> $DIR/integral-indexing.rs:15:5 @@ -67,8 +67,8 @@ error[E0277]: the type `[u8]` cannot be indexed by `i32` LL | s.as_bytes()[3i32]; | ^^^^^^^^^^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[u8]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `[u8]` + = help: the trait `SliceIndex<[u8]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `[u8]` error: aborting due to 8 previous errors diff --git a/src/test/ui/interior-mutability/interior-mutability.rs b/src/test/ui/interior-mutability/interior-mutability.rs index ddc882cccf..c704acc22a 100644 --- a/src/test/ui/interior-mutability/interior-mutability.rs +++ b/src/test/ui/interior-mutability/interior-mutability.rs @@ -3,5 +3,5 @@ use std::panic::catch_unwind; fn main() { let mut x = Cell::new(22); catch_unwind(|| { x.set(23); }); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/interior-mutability/interior-mutability.stderr b/src/test/ui/interior-mutability/interior-mutability.stderr index a25acf10a1..dd43da1166 100644 --- a/src/test/ui/interior-mutability/interior-mutability.stderr +++ b/src/test/ui/interior-mutability/interior-mutability.stderr @@ -1,18 +1,18 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/interior-mutability.rs:5:5 | LL | catch_unwind(|| { x.set(23); }); - | ^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | ::: $SRC_DIR/std/src/panic.rs:LL:COL | LL | pub fn catch_unwind R + UnwindSafe, R>(f: F) -> Result { - | ---------- required by this bound in `std::panic::catch_unwind` + | ---------- required by this bound in `catch_unwind` | - = help: within `std::cell::Cell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::Cell` - = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35 x:&std::cell::Cell]` + = help: within `Cell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because of the requirements on the impl of `UnwindSafe` for `&Cell` + = note: required because it appears within the type `[closure@$DIR/interior-mutability.rs:5:18: 5:35]` error: aborting due to previous error diff --git a/src/test/ui/internal/auxiliary/internal_unstable.rs b/src/test/ui/internal/auxiliary/internal_unstable.rs index 148cbd1899..eb4d6cb380 100644 --- a/src/test/ui/internal/auxiliary/internal_unstable.rs +++ b/src/test/ui/internal/auxiliary/internal_unstable.rs @@ -52,6 +52,15 @@ macro_rules! access_field_allow { ($e: expr) => { $e.x } } +// regression test for #77088 +#[stable(feature = "stable", since = "1.0.0")] +#[allow_internal_unstable(struct_field)] +#[allow_internal_unstable(struct2_field)] +#[macro_export] +macro_rules! access_field_allow2 { + ($e: expr) => { $e.x } +} + #[stable(feature = "stable", since = "1.0.0")] #[allow_internal_unstable()] #[macro_export] diff --git a/src/test/ui/internal/internal-unstable-const.rs b/src/test/ui/internal/internal-unstable-const.rs index b923bc22f6..554c67be4e 100644 --- a/src/test/ui/internal/internal-unstable-const.rs +++ b/src/test/ui/internal/internal-unstable-const.rs @@ -8,7 +8,7 @@ #[stable(feature = "rust1", since = "1.0.0")] #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn foo() -> i32 { - unsafe { std::mem::transmute(4u32) } //~ ERROR can only call `transmute` from const items + unsafe { std::mem::transmute(4u32) } //~ ERROR `transmute` } fn main() {} diff --git a/src/test/ui/internal/internal-unstable-const.stderr b/src/test/ui/internal/internal-unstable-const.stderr index 9626df23ec..adfb8dc369 100644 --- a/src/test/ui/internal/internal-unstable-const.stderr +++ b/src/test/ui/internal/internal-unstable-const.stderr @@ -1,12 +1,13 @@ -error[E0723]: can only call `transmute` from const items, not `const fn` +error[E0658]: `transmute` is not allowed in constant functions --> $DIR/internal-unstable-const.rs:11:14 | LL | unsafe { std::mem::transmute(4u32) } | ^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #53605 for more information + = help: add `#![feature(const_fn_transmute)]` to the crate attributes to enable + = note: `transmute` is only allowed in constants and statics for now error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/internal/internal-unstable.rs b/src/test/ui/internal/internal-unstable.rs index e09a5d8917..94bd6aab23 100644 --- a/src/test/ui/internal/internal-unstable.rs +++ b/src/test/ui/internal/internal-unstable.rs @@ -28,6 +28,7 @@ fn main() { construct_unstable_allow!(0); |x: internal_unstable::Foo| { call_method_allow!(x) }; |x: internal_unstable::Bar| { access_field_allow!(x) }; + |x: internal_unstable::Bar| { access_field_allow2!(x) }; // regression test for #77088 // bad. pass_through_allow!(internal_unstable::unstable()); //~ ERROR use of unstable diff --git a/src/test/ui/internal/internal-unstable.stderr b/src/test/ui/internal/internal-unstable.stderr index 2c6bf42ae8..2e6360c75c 100644 --- a/src/test/ui/internal/internal-unstable.stderr +++ b/src/test/ui/internal/internal-unstable.stderr @@ -1,5 +1,5 @@ error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:33:25 + --> $DIR/internal-unstable.rs:34:25 | LL | pass_through_allow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -7,7 +7,7 @@ LL | pass_through_allow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:35:27 + --> $DIR/internal-unstable.rs:36:27 | LL | pass_through_noallow!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -15,7 +15,7 @@ LL | pass_through_noallow!(internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:39:22 + --> $DIR/internal-unstable.rs:40:22 | LL | println!("{:?}", internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -23,7 +23,7 @@ LL | println!("{:?}", internal_unstable::unstable()); = help: add `#![feature(function)]` to the crate attributes to enable error[E0658]: use of unstable library feature 'function' - --> $DIR/internal-unstable.rs:41:10 + --> $DIR/internal-unstable.rs:42:10 | LL | bar!(internal_unstable::unstable()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs index 02f8ecaa4e..24474cabf1 100644 --- a/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs +++ b/src/test/ui/intrinsics/panic-uninitialized-zeroed.rs @@ -3,7 +3,7 @@ // This test checks panic emitted from `mem::{uninitialized,zeroed}`. -#![feature(never_type)] +#![feature(never_type, arbitrary_enum_discriminant)] #![allow(deprecated, invalid_value)] use std::{ @@ -24,6 +24,20 @@ enum Bar {} #[allow(dead_code)] enum OneVariant { Variant(i32) } +#[allow(dead_code, non_camel_case_types)] +enum OneVariant_NonZero { + Variant(i32, i32, num::NonZeroI32), + DeadVariant(Bar), +} + +// An `Aggregate` abi enum where 0 is not a valid discriminant. +#[allow(dead_code)] +#[repr(i32)] +enum NoNullVariant { + Variant1(i32, i32) = 1, + Variant2(i32, i32) = 2, +} + // An enum with ScalarPair layout #[allow(dead_code)] enum LR { @@ -125,6 +139,7 @@ fn main() { "attempted to zero-initialize type `std::mem::ManuallyDrop`, \ which is invalid" ); + */ test_panic_msg( || mem::uninitialized::<(NonNull, u32, u32)>(), @@ -136,7 +151,28 @@ fn main() { "attempted to zero-initialize type `(std::ptr::NonNull, u32, u32)`, \ which is invalid" ); - */ + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `OneVariant_NonZero` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `OneVariant_NonZero`, \ + which is invalid" + ); + + test_panic_msg( + || mem::uninitialized::(), + "attempted to leave type `NoNullVariant` uninitialized, \ + which is invalid" + ); + test_panic_msg( + || mem::zeroed::(), + "attempted to zero-initialize type `NoNullVariant`, \ + which is invalid" + ); // Types that can be zero, but not uninit. test_panic_msg( diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.rs b/src/test/ui/invalid-rustc_args_required_const-arguments.rs new file mode 100644 index 0000000000..76c01c2130 --- /dev/null +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.rs @@ -0,0 +1,26 @@ +#![feature(rustc_attrs)] + +#[rustc_args_required_const(0)] //~ ERROR index exceeds number of arguments +fn foo1() {} + +#[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments +fn foo2(_: u8) {} + +#[rustc_args_required_const(a)] //~ ERROR arguments should be non-negative integers +fn foo4() {} + +#[rustc_args_required_const(1, a, 2, b)] //~ ERROR arguments should be non-negative integers +fn foo5(_: u8, _: u8, _: u8) {} + +#[rustc_args_required_const(0)] //~ ERROR attribute should be applied to a function +struct S; + +#[rustc_args_required_const(0usize)] //~ ERROR suffixed literals are not allowed in attributes +fn foo6(_: u8) {} + +extern { + #[rustc_args_required_const(1)] //~ ERROR index exceeds number of arguments + fn foo7(_: u8); +} + +fn main() {} diff --git a/src/test/ui/invalid-rustc_args_required_const-arguments.stderr b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr new file mode 100644 index 0000000000..39d0462616 --- /dev/null +++ b/src/test/ui/invalid-rustc_args_required_const-arguments.stderr @@ -0,0 +1,48 @@ +error: suffixed literals are not allowed in attributes + --> $DIR/invalid-rustc_args_required_const-arguments.rs:18:29 + | +LL | #[rustc_args_required_const(0usize)] + | ^^^^^^ + | + = help: instead of using a suffixed literal (`1u8`, `1.0f32`, etc.), use an unsuffixed version (`1`, `1.0`, etc.) + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_args_required_const-arguments.rs:3:29 + | +LL | #[rustc_args_required_const(0)] + | ^ there are only 0 arguments + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_args_required_const-arguments.rs:6:29 + | +LL | #[rustc_args_required_const(1)] + | ^ there is only 1 argument + +error: arguments should be non-negative integers + --> $DIR/invalid-rustc_args_required_const-arguments.rs:9:29 + | +LL | #[rustc_args_required_const(a)] + | ^ + +error: arguments should be non-negative integers + --> $DIR/invalid-rustc_args_required_const-arguments.rs:12:32 + | +LL | #[rustc_args_required_const(1, a, 2, b)] + | ^ ^ + +error: attribute should be applied to a function + --> $DIR/invalid-rustc_args_required_const-arguments.rs:15:1 + | +LL | #[rustc_args_required_const(0)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct S; + | --------- not a function + +error: index exceeds number of arguments + --> $DIR/invalid-rustc_args_required_const-arguments.rs:22:33 + | +LL | #[rustc_args_required_const(1)] + | ^ there is only 1 argument + +error: aborting due to 7 previous errors + diff --git a/src/test/ui/issue-74047.stderr b/src/test/ui/issue-74047.stderr index 6f477c77ce..8f7c91a78d 100644 --- a/src/test/ui/issue-74047.stderr +++ b/src/test/ui/issue-74047.stderr @@ -5,7 +5,7 @@ LL | impl TryFrom for MyStream {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `Error`, `try_from` in implementation | = help: implement the missing item: `type Error = Type;` - = help: implement the missing item: `fn try_from(_: T) -> std::result::Result>::Error> { todo!() }` + = help: implement the missing item: `fn try_from(_: T) -> std::result::Result>::Error> { todo!() }` error: aborting due to previous error diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr index b3b29a7264..867f8f0496 100644 --- a/src/test/ui/issues-71798.stderr +++ b/src/test/ui/issues-71798.stderr @@ -12,7 +12,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future + '_ { LL | *x | -- this returned value is of type `u32` | - = help: the trait `std::future::Future` is not implemented for `u32` + = help: the trait `Future` is not implemented for `u32` = note: the return type of a function must have a statically known size error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/auxiliary/issue-75907.rs b/src/test/ui/issues/auxiliary/issue-75907.rs new file mode 100644 index 0000000000..0b70452a24 --- /dev/null +++ b/src/test/ui/issues/auxiliary/issue-75907.rs @@ -0,0 +1,5 @@ +pub struct Bar(pub u8, u8, u8); + +pub fn make_bar() -> Bar { + Bar(1, 12, 10) +} diff --git a/src/test/ui/issues/issue-10398.stderr b/src/test/ui/issues/issue-10398.stderr index f5f4974265..8d9faf324e 100644 --- a/src/test/ui/issues/issue-10398.stderr +++ b/src/test/ui/issues/issue-10398.stderr @@ -6,7 +6,7 @@ LL | let _a = x; LL | drop(x); | ^ value used here after move | - = note: move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-10412.stderr b/src/test/ui/issues/issue-10412.stderr index d241e6406d..2a6e241459 100644 --- a/src/test/ui/issues/issue-10412.stderr +++ b/src/test/ui/issues/issue-10412.stderr @@ -55,7 +55,7 @@ LL | trait Serializable<'self, T> { LL | impl<'self> Serializable for &'self str { | ^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` help: consider relaxing the implicit `Sized` restriction | LL | trait Serializable<'self, T: ?Sized> { diff --git a/src/test/ui/issues/issue-10465.stderr b/src/test/ui/issues/issue-10465.stderr index 666fb6ab2b..eb32c8db3f 100644 --- a/src/test/ui/issues/issue-10465.stderr +++ b/src/test/ui/issues/issue-10465.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `foo` found for reference `&b::B` in the current scope +error[E0599]: no method named `foo` found for reference `&B` in the current scope --> $DIR/issue-10465.rs:17:15 | LL | b.foo(); - | ^^^ method not found in `&b::B` + | ^^^ 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: diff --git a/src/test/ui/issues/issue-11374.stderr b/src/test/ui/issues/issue-11374.stderr index bc7d124750..d6a3e758de 100644 --- a/src/test/ui/issues/issue-11374.stderr +++ b/src/test/ui/issues/issue-11374.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | c.read_to(v); | ^ | | - | expected `&mut [u8]`, found struct `std::vec::Vec` + | expected `&mut [u8]`, found struct `Vec` | help: consider mutably borrowing here: `&mut v` | = note: expected mutable reference `&mut [u8]` - found struct `std::vec::Vec<_>` + found struct `Vec<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11515.stderr b/src/test/ui/issues/issue-11515.stderr index b53563d7b6..7935615ad7 100644 --- a/src/test/ui/issues/issue-11515.stderr +++ b/src/test/ui/issues/issue-11515.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-11515.rs:9:33 | LL | let test = box Test { func: closure }; - | ^^^^^^^ expected trait `std::ops::FnMut`, found trait `std::ops::Fn` + | ^^^^^^^ expected trait `FnMut`, found trait `Fn` | - = note: expected struct `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` - found struct `std::boxed::Box<(dyn std::ops::Fn() + 'static)>` + = note: expected struct `Box<(dyn FnMut() + 'static)>` + found struct `Box<(dyn Fn() + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-11771.stderr b/src/test/ui/issues/issue-11771.stderr index e78d8423e8..9f250925e5 100644 --- a/src/test/ui/issues/issue-11771.stderr +++ b/src/test/ui/issues/issue-11771.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `()` to `{integer}` LL | 1 + | ^ no implementation for `{integer} + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` + = help: the trait `Add<()>` is not implemented for `{integer}` error[E0277]: cannot add `()` to `{integer}` --> $DIR/issue-11771.rs:8:7 @@ -12,7 +12,7 @@ error[E0277]: cannot add `()` to `{integer}` LL | 1 + | ^ no implementation for `{integer} + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` + = help: the trait `Add<()>` is not implemented for `{integer}` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-11844.stderr b/src/test/ui/issues/issue-11844.stderr index 57533ba5e3..00eecbc9a9 100644 --- a/src/test/ui/issues/issue-11844.stderr +++ b/src/test/ui/issues/issue-11844.stderr @@ -2,11 +2,11 @@ error[E0308]: mismatched types --> $DIR/issue-11844.rs:6:9 | LL | match a { - | - this expression has type `std::option::Option>` + | - this expression has type `Option>` LL | Ok(a) => - | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option>` + = note: expected enum `Option>` found enum `std::result::Result<_, _>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12041.stderr b/src/test/ui/issues/issue-12041.stderr index d95cc89ce9..b9ffa499af 100644 --- a/src/test/ui/issues/issue-12041.stderr +++ b/src/test/ui/issues/issue-12041.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value: `tx` LL | let tx = tx; | ^^ value moved here, in previous iteration of loop | - = note: move occurs because `tx` has type `std::sync::mpsc::Sender`, which does not implement the `Copy` trait + = note: move occurs because `tx` has type `Sender`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12127.stderr b/src/test/ui/issues/issue-12127.stderr index b759aa45e3..e1559ab2fe 100644 --- a/src/test/ui/issues/issue-12127.stderr +++ b/src/test/ui/issues/issue-12127.stderr @@ -11,7 +11,7 @@ note: this value implements `FnOnce`, which causes it to be moved when called | LL | f(); | ^ - = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41 x:std::boxed::Box]`, which does not implement the `Copy` trait + = note: move occurs because `f` has type `[closure@$DIR/issue-12127.rs:8:24: 8:41]`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-12552.stderr b/src/test/ui/issues/issue-12552.stderr index 45fede4410..1594c9f503 100644 --- a/src/test/ui/issues/issue-12552.stderr +++ b/src/test/ui/issues/issue-12552.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | match t { | - this expression has type `std::result::Result<_, {integer}>` LL | Some(k) => match k { - | ^^^^^^^ expected enum `std::result::Result`, found enum `std::option::Option` + | ^^^^^^^ expected enum `std::result::Result`, found enum `Option` | = note: expected enum `std::result::Result<_, {integer}>` - found enum `std::option::Option<_>` + found enum `Option<_>` error[E0308]: mismatched types --> $DIR/issue-12552.rs:9:5 @@ -16,10 +16,10 @@ LL | match t { | - this expression has type `std::result::Result<_, {integer}>` ... LL | None => () - | ^^^^ expected enum `std::result::Result`, found enum `std::option::Option` + | ^^^^ expected enum `std::result::Result`, found enum `Option` | = note: expected enum `std::result::Result<_, {integer}>` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-12997-2.stderr b/src/test/ui/issues/issue-12997-2.stderr index 04464896e9..895b415a7e 100644 --- a/src/test/ui/issues/issue-12997-2.stderr +++ b/src/test/ui/issues/issue-12997-2.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-12997-2.rs:8:1 | LL | fn bar(x: isize) { } - | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `&mut test::Bencher` + | ^^^^^^^^^^^^^^^^^^^^ expected `isize`, found `&mut Bencher` | = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-13407.stderr b/src/test/ui/issues/issue-13407.stderr index f30b6cdeaf..4df1813a71 100644 --- a/src/test/ui/issues/issue-13407.stderr +++ b/src/test/ui/issues/issue-13407.stderr @@ -10,12 +10,6 @@ note: the unit struct `C` is defined here LL | struct C; | ^^^^^^^^^ -error[E0308]: mismatched types - --> $DIR/issue-13407.rs:6:12 - | -LL | A::C = 1; - | ^ expected struct `A::C`, found integer - error[E0070]: invalid left-hand side of assignment --> $DIR/issue-13407.rs:6:10 | @@ -24,6 +18,12 @@ LL | A::C = 1; | | | cannot assign to this expression +error[E0308]: mismatched types + --> $DIR/issue-13407.rs:6:12 + | +LL | A::C = 1; + | ^ expected struct `C`, found integer + error: aborting due to 3 previous errors Some errors have detailed explanations: E0070, E0308, E0603. diff --git a/src/test/ui/issues/issue-13446.stderr b/src/test/ui/issues/issue-13446.stderr index 71d3bfe339..962f8ee9dd 100644 --- a/src/test/ui/issues/issue-13446.stderr +++ b/src/test/ui/issues/issue-13446.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-13446.rs:3:26 | LL | static VEC: [u32; 256] = vec![]; - | ^^^^^^ expected array `[u32; 256]`, found struct `std::vec::Vec` + | ^^^^^^ expected array `[u32; 256]`, found struct `Vec` | = note: expected array `[u32; 256]` - found struct `std::vec::Vec<_>` + found struct `Vec<_>` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/issues/issue-13466.rs b/src/test/ui/issues/issue-13466.rs index 411e7cbeeb..8048dae123 100644 --- a/src/test/ui/issues/issue-13466.rs +++ b/src/test/ui/issues/issue-13466.rs @@ -7,14 +7,14 @@ pub fn main() { let _x: usize = match Some(1) { Ok(u) => u, //~^ ERROR mismatched types - //~| expected enum `std::option::Option<{integer}>` + //~| expected enum `Option<{integer}>` //~| found enum `std::result::Result<_, _>` - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` Err(e) => panic!(e) //~^ ERROR mismatched types - //~| expected enum `std::option::Option<{integer}>` + //~| expected enum `Option<{integer}>` //~| found enum `std::result::Result<_, _>` - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` }; } diff --git a/src/test/ui/issues/issue-13466.stderr b/src/test/ui/issues/issue-13466.stderr index 52d9e2a91b..792cc398bb 100644 --- a/src/test/ui/issues/issue-13466.stderr +++ b/src/test/ui/issues/issue-13466.stderr @@ -2,23 +2,23 @@ error[E0308]: mismatched types --> $DIR/issue-13466.rs:8:9 | LL | let _x: usize = match Some(1) { - | ------- this expression has type `std::option::Option<{integer}>` + | ------- this expression has type `Option<{integer}>` LL | Ok(u) => u, - | ^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option<{integer}>` + = note: expected enum `Option<{integer}>` found enum `std::result::Result<_, _>` error[E0308]: mismatched types --> $DIR/issue-13466.rs:14:9 | LL | let _x: usize = match Some(1) { - | ------- this expression has type `std::option::Option<{integer}>` + | ------- this expression has type `Option<{integer}>` ... LL | Err(e) => panic!(e) - | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option<{integer}>` + = note: expected enum `Option<{integer}>` found enum `std::result::Result<_, _>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-13853-2.stderr b/src/test/ui/issues/issue-13853-2.stderr index 49b946b354..667ddbca97 100644 --- a/src/test/ui/issues/issue-13853-2.stderr +++ b/src/test/ui/issues/issue-13853-2.stderr @@ -1,4 +1,4 @@ -error[E0615]: attempted to take value of method `get` on type `std::boxed::Box<(dyn ResponseHook + 'static)>` +error[E0615]: attempted to take value of method `get` on type `Box<(dyn ResponseHook + 'static)>` --> $DIR/issue-13853-2.rs:5:43 | LL | fn foo(res : Box) { res.get } diff --git a/src/test/ui/issues/issue-13853.stderr b/src/test/ui/issues/issue-13853.stderr index 3f1b955ddd..527e0225eb 100644 --- a/src/test/ui/issues/issue-13853.stderr +++ b/src/test/ui/issues/issue-13853.stderr @@ -22,11 +22,11 @@ error[E0308]: mismatched types LL | iterate(graph); | ^^^^^ | | - | expected reference, found struct `std::vec::Vec` + | expected reference, found struct `Vec` | help: consider borrowing here: `&graph` | = note: expected reference `&_` - found struct `std::vec::Vec` + found struct `Vec` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-14366.stderr b/src/test/ui/issues/issue-14366.stderr index 4e41acf433..d5dab561dd 100644 --- a/src/test/ui/issues/issue-14366.stderr +++ b/src/test/ui/issues/issue-14366.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let _x = "test" as &dyn (::std::any::Any); | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::any::Any` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn Any` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-14915.rs b/src/test/ui/issues/issue-14915.rs index 4acb51a4e5..909540355e 100644 --- a/src/test/ui/issues/issue-14915.rs +++ b/src/test/ui/issues/issue-14915.rs @@ -4,5 +4,5 @@ fn main() { let x: Box = box 0; println!("{}", x + 1); - //~^ ERROR cannot add `{integer}` to `std::boxed::Box` + //~^ ERROR cannot add `{integer}` to `Box` } diff --git a/src/test/ui/issues/issue-14915.stderr b/src/test/ui/issues/issue-14915.stderr index 3c34a8a346..bd0b1d39a5 100644 --- a/src/test/ui/issues/issue-14915.stderr +++ b/src/test/ui/issues/issue-14915.stderr @@ -1,10 +1,10 @@ -error[E0369]: cannot add `{integer}` to `std::boxed::Box` +error[E0369]: cannot add `{integer}` to `Box` --> $DIR/issue-14915.rs:6:22 | LL | println!("{}", x + 1); | - ^ - {integer} | | - | std::boxed::Box + | Box error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15756.stderr b/src/test/ui/issues/issue-15756.stderr index 68ceebc5b6..d9bdc69ad7 100644 --- a/src/test/ui/issues/issue-15756.stderr +++ b/src/test/ui/issues/issue-15756.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[T]` cannot be known at compilation t LL | &mut something | ^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[T]` + = help: the trait `Sized` is not implemented for `[T]` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-15783.rs b/src/test/ui/issues/issue-15783.rs index 0c1db02a8e..0b1f4545e8 100644 --- a/src/test/ui/issues/issue-15783.rs +++ b/src/test/ui/issues/issue-15783.rs @@ -7,8 +7,8 @@ fn main() { let x = Some(&[name]); let msg = foo(x); //~^ ERROR mismatched types - //~| expected enum `std::option::Option<&[&str]>` - //~| found enum `std::option::Option<&[&str; 1]>` + //~| expected enum `Option<&[&str]>` + //~| found enum `Option<&[&str; 1]>` //~| expected slice `[&str]`, found array `[&str; 1]` assert_eq!(msg, 3); } diff --git a/src/test/ui/issues/issue-15783.stderr b/src/test/ui/issues/issue-15783.stderr index 74a96df5b1..0b09751676 100644 --- a/src/test/ui/issues/issue-15783.stderr +++ b/src/test/ui/issues/issue-15783.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | let msg = foo(x); | ^ expected slice `[&str]`, found array `[&str; 1]` | - = note: expected enum `std::option::Option<&[&str]>` - found enum `std::option::Option<&[&str; 1]>` + = note: expected enum `Option<&[&str]>` + found enum `Option<&[&str; 1]>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-15896.rs b/src/test/ui/issues/issue-15896.rs index a11c9d07f6..d3153b516e 100644 --- a/src/test/ui/issues/issue-15896.rs +++ b/src/test/ui/issues/issue-15896.rs @@ -10,7 +10,6 @@ fn main() { E::B( Tau{t: x}, //~^ ERROR mismatched types - //~| expected enum `main::R`, found struct `main::Tau` _) => x, }; } diff --git a/src/test/ui/issues/issue-15896.stderr b/src/test/ui/issues/issue-15896.stderr index b3f0907b81..038337f5ac 100644 --- a/src/test/ui/issues/issue-15896.stderr +++ b/src/test/ui/issues/issue-15896.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-15896.rs:11:11 | LL | let u = match e { - | - this expression has type `main::E` + | - this expression has type `E` LL | E::B( LL | Tau{t: x}, - | ^^^^^^^^^ expected enum `main::R`, found struct `main::Tau` + | ^^^^^^^^^ expected enum `R`, found struct `Tau` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-16538.stderr b/src/test/ui/issues/issue-16538.stderr index 5e1f95a989..81a91db371 100644 --- a/src/test/ui/issues/issue-16538.stderr +++ b/src/test/ui/issues/issue-16538.stderr @@ -10,7 +10,7 @@ error[E0277]: `*const usize` cannot be shared between threads safely LL | static foo: *const Y::X = Y::foo(Y::x as *const Y::X); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*const usize` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `*const usize` + = help: the trait `Sync` is not implemented for `*const usize` = note: shared static variables must have a type that implements `Sync` error[E0133]: use of extern static is unsafe and requires unsafe function or block diff --git a/src/test/ui/issues/issue-17252.stderr b/src/test/ui/issues/issue-17252.stderr index ee621a8cb1..1148577016 100644 --- a/src/test/ui/issues/issue-17252.stderr +++ b/src/test/ui/issues/issue-17252.stderr @@ -1,6 +1,11 @@ error[E0391]: cycle detected when normalizing `FOO` | -note: ...which requires const-evaluating + checking `FOO`... +note: ...which requires simplifying constant for the type system `FOO`... + --> $DIR/issue-17252.rs:1:1 + | +LL | const FOO: usize = FOO; + | ^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `FOO`... --> $DIR/issue-17252.rs:1:1 | LL | const FOO: usize = FOO; @@ -8,15 +13,10 @@ LL | const FOO: usize = FOO; note: ...which requires const-evaluating + checking `FOO`... --> $DIR/issue-17252.rs:1:1 | -LL | const FOO: usize = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `FOO`... - --> $DIR/issue-17252.rs:1:1 - | LL | const FOO: usize = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which again requires normalizing `FOO`, completing the cycle -note: cycle used when const-evaluating `main::{{constant}}#0` +note: cycle used when const-evaluating + checking `main::{constant#0}` --> $DIR/issue-17252.rs:4:18 | LL | let _x: [u8; FOO]; // caused stack overflow prior to fix diff --git a/src/test/ui/issues/issue-17441.rs b/src/test/ui/issues/issue-17441.rs index b9813ef1ee..e5f83c4eba 100644 --- a/src/test/ui/issues/issue-17441.rs +++ b/src/test/ui/issues/issue-17441.rs @@ -3,10 +3,10 @@ fn main() { //~^ ERROR cast to unsized type: `&[usize; 2]` as `[usize]` let _bar = Box::new(1_usize) as dyn std::fmt::Debug; - //~^ ERROR cast to unsized type: `std::boxed::Box` as `dyn std::fmt::Debug` + //~^ ERROR cast to unsized type: `Box` as `dyn Debug` let _baz = 1_usize as dyn std::fmt::Debug; - //~^ ERROR cast to unsized type: `usize` as `dyn std::fmt::Debug` + //~^ ERROR cast to unsized type: `usize` as `dyn Debug` let _quux = [1_usize, 2] as [usize]; //~^ ERROR cast to unsized type: `[usize; 2]` as `[usize]` diff --git a/src/test/ui/issues/issue-17441.stderr b/src/test/ui/issues/issue-17441.stderr index b63a3995d2..4dbe50178c 100644 --- a/src/test/ui/issues/issue-17441.stderr +++ b/src/test/ui/issues/issue-17441.stderr @@ -10,7 +10,7 @@ help: consider using an implicit coercion to `&[usize]` instead LL | let _foo = &[1_usize, 2] as [usize]; | ^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0620]: cast to unsized type: `std::boxed::Box` as `dyn std::fmt::Debug` +error[E0620]: cast to unsized type: `Box` as `dyn Debug` --> $DIR/issue-17441.rs:5:16 | LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; @@ -18,7 +18,7 @@ LL | let _bar = Box::new(1_usize) as dyn std::fmt::Debug; | | | help: you can cast to a `Box` instead: `Box` -error[E0620]: cast to unsized type: `usize` as `dyn std::fmt::Debug` +error[E0620]: cast to unsized type: `usize` as `dyn Debug` --> $DIR/issue-17441.rs:8:16 | LL | let _baz = 1_usize as dyn std::fmt::Debug; diff --git a/src/test/ui/issues/issue-17651.stderr b/src/test/ui/issues/issue-17651.stderr index 812778911a..987f4e97f3 100644 --- a/src/test/ui/issues/issue-17651.stderr +++ b/src/test/ui/issues/issue-17651.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` - = note: required by `std::boxed::Box::::new` + = help: the trait `Sized` is not implemented for `[{integer}]` + = note: required by `Box::::new` error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time --> $DIR/issue-17651.rs:5:9 @@ -13,7 +13,7 @@ error[E0277]: the size for values of type `[{integer}]` cannot be known at compi LL | (|| Box::new(*(&[0][..])))(); | ^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` + = help: the trait `Sized` is not implemented for `[{integer}]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-17718-static-sync.stderr b/src/test/ui/issues/issue-17718-static-sync.stderr index 7f162a9985..4cd85124c3 100644 --- a/src/test/ui/issues/issue-17718-static-sync.stderr +++ b/src/test/ui/issues/issue-17718-static-sync.stderr @@ -4,7 +4,7 @@ error[E0277]: `Foo` cannot be shared between threads safely LL | static BAR: Foo = Foo; | ^^^^^^^^^^^^^^^^^^^^^^ `Foo` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `Foo` + = help: the trait `Sync` is not implemented for `Foo` = note: shared static variables must have a type that implements `Sync` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17728.nll.stderr b/src/test/ui/issues/issue-17728.nll.stderr index d515cf451c..a13d2dfa1f 100644 --- a/src/test/ui/issues/issue-17728.nll.stderr +++ b/src/test/ui/issues/issue-17728.nll.stderr @@ -9,12 +9,12 @@ LL | | "n" | "north" => RoomDirection::North, LL | | "down" => RoomDirection::Down, | | ------------------- this and all prior arms are found to be of type `RoomDirection` LL | | _ => None - | | ^^^^ expected enum `RoomDirection`, found enum `std::option::Option` + | | ^^^^ expected enum `RoomDirection`, found enum `Option` LL | | } | |_____- `match` arms have incompatible types | = note: expected enum `RoomDirection` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17728.stderr b/src/test/ui/issues/issue-17728.stderr index 2f9ae63aa4..50e3b853fc 100644 --- a/src/test/ui/issues/issue-17728.stderr +++ b/src/test/ui/issues/issue-17728.stderr @@ -20,12 +20,12 @@ LL | | "n" | "north" => RoomDirection::North, LL | | "down" => RoomDirection::Down, | | ------------------- this and all prior arms are found to be of type `RoomDirection` LL | | _ => None - | | ^^^^ expected enum `RoomDirection`, found enum `std::option::Option` + | | ^^^^ expected enum `RoomDirection`, found enum `Option` LL | | } | |_____- `match` arms have incompatible types | = note: expected enum `RoomDirection` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-17904-2.stderr b/src/test/ui/issues/issue-17904-2.stderr index 25f32b6610..62b7b79538 100644 --- a/src/test/ui/issues/issue-17904-2.stderr +++ b/src/test/ui/issues/issue-17904-2.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `T` is never used LL | struct Foo where T: Copy; | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-17959.rs b/src/test/ui/issues/issue-17959.rs index 01416a0d79..8bf9e62360 100644 --- a/src/test/ui/issues/issue-17959.rs +++ b/src/test/ui/issues/issue-17959.rs @@ -9,7 +9,7 @@ struct G { } impl Drop for G { -//~^ ERROR `Drop` impl requires `T: std::marker::Sized` +//~^ ERROR `Drop` impl requires `T: Sized` fn drop(&mut self) { if !self._ptr.is_null() { } diff --git a/src/test/ui/issues/issue-17959.stderr b/src/test/ui/issues/issue-17959.stderr index 29d32c1f3c..f00356f602 100644 --- a/src/test/ui/issues/issue-17959.stderr +++ b/src/test/ui/issues/issue-17959.stderr @@ -1,4 +1,4 @@ -error[E0367]: `Drop` impl requires `T: std::marker::Sized` but the struct it is implemented for does not +error[E0367]: `Drop` impl requires `T: Sized` but the struct it is implemented for does not --> $DIR/issue-17959.rs:11:6 | LL | impl Drop for G { diff --git a/src/test/ui/issues/issue-18400.stderr b/src/test/ui/issues/issue-18400.stderr index ed9137ce39..35fa5fde0a 100644 --- a/src/test/ui/issues/issue-18400.stderr +++ b/src/test/ui/issues/issue-18400.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `_: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `_: Sized` --> $DIR/issue-18400.rs:24:7 | LL | 0.contains(bits); diff --git a/src/test/ui/issues/issue-18783.stderr b/src/test/ui/issues/issue-18783.stderr index 047b42578a..cc223ac464 100644 --- a/src/test/ui/issues/issue-18783.stderr +++ b/src/test/ui/issues/issue-18783.stderr @@ -11,7 +11,7 @@ LL | c.push(Box::new(|| y = 0)); | second mutable borrow occurs here LL | LL | } - | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` + | - first borrow might be used here, when `c` is dropped and runs the destructor for type `RefCell>>` error[E0499]: cannot borrow `y` as mutable more than once at a time --> $DIR/issue-18783.rs:16:29 @@ -26,7 +26,7 @@ LL | Push::push(&c, Box::new(|| y = 0)); | second mutable borrow occurs here LL | LL | } - | - first borrow might be used here, when `c` is dropped and runs the destructor for type `std::cell::RefCell>>` + | - first borrow might be used here, when `c` is dropped and runs the destructor for type `RefCell>>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-18919.stderr b/src/test/ui/issues/issue-18919.stderr index 3b5dfd1ad1..ece714c949 100644 --- a/src/test/ui/issues/issue-18919.stderr +++ b/src/test/ui/issues/issue-18919.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for values of type `dyn for<'r> std::ops::Fn(&'r isize) -> isize` cannot be known at compilation time +error[E0277]: the size for values of type `dyn for<'r> Fn(&'r isize) -> isize` cannot be known at compilation time --> $DIR/issue-18919.rs:3:15 | LL | fn ho_func(f: Option) { @@ -7,7 +7,7 @@ LL | fn ho_func(f: Option) { LL | enum Option { | - required by this bound in `Option` | - = help: the trait `std::marker::Sized` is not implemented for `dyn for<'r> std::ops::Fn(&'r isize) -> isize` + = help: the trait `Sized` is not implemented for `dyn for<'r> Fn(&'r isize) -> isize` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-18919.rs:7:13 | diff --git a/src/test/ui/issues/issue-1920-1.rs b/src/test/ui/issues/issue-1920-1.rs index 996052d749..26553f56b8 100644 --- a/src/test/ui/issues/issue-1920-1.rs +++ b/src/test/ui/issues/issue-1920-1.rs @@ -10,5 +10,5 @@ fn assert_clone() where T : Clone { } fn main() { assert_clone::(); - //~^ ERROR `foo::issue_1920::S: std::clone::Clone` is not satisfied + //~^ ERROR `S: Clone` is not satisfied } diff --git a/src/test/ui/issues/issue-1920-1.stderr b/src/test/ui/issues/issue-1920-1.stderr index 3130434f6f..0a2459c3a5 100644 --- a/src/test/ui/issues/issue-1920-1.stderr +++ b/src/test/ui/issues/issue-1920-1.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `foo::issue_1920::S: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `S: Clone` is not satisfied --> $DIR/issue-1920-1.rs:12:20 | LL | fn assert_clone() where T : Clone { } | ----- required by this bound in `assert_clone` ... LL | assert_clone::(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `foo::issue_1920::S` + | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1920-2.rs b/src/test/ui/issues/issue-1920-2.rs index 56d842ec4a..8d4a5f6631 100644 --- a/src/test/ui/issues/issue-1920-2.rs +++ b/src/test/ui/issues/issue-1920-2.rs @@ -8,5 +8,5 @@ fn assert_clone() where T : Clone { } fn main() { assert_clone::(); - //~^ ERROR `bar::S: std::clone::Clone` is not satisfied + //~^ ERROR `S: Clone` is not satisfied } diff --git a/src/test/ui/issues/issue-1920-2.stderr b/src/test/ui/issues/issue-1920-2.stderr index 1084c47f00..06bc78a387 100644 --- a/src/test/ui/issues/issue-1920-2.stderr +++ b/src/test/ui/issues/issue-1920-2.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `bar::S: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `S: Clone` is not satisfied --> $DIR/issue-1920-2.rs:10:20 | LL | fn assert_clone() where T : Clone { } | ----- required by this bound in `assert_clone` ... LL | assert_clone::(); - | ^^^^^^ the trait `std::clone::Clone` is not implemented for `bar::S` + | ^^^^^^ the trait `Clone` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-1920-3.rs b/src/test/ui/issues/issue-1920-3.rs index 83f3fdb9eb..520db50f94 100644 --- a/src/test/ui/issues/issue-1920-3.rs +++ b/src/test/ui/issues/issue-1920-3.rs @@ -12,5 +12,5 @@ fn assert_clone() where T : Clone { } fn main() { assert_clone::(); - //~^ ERROR `issue_1920::S: std::clone::Clone` is not satisfied + //~^ ERROR `S: Clone` is not satisfied } diff --git a/src/test/ui/issues/issue-1920-3.stderr b/src/test/ui/issues/issue-1920-3.stderr index 11740317e5..48d3105bf9 100644 --- a/src/test/ui/issues/issue-1920-3.stderr +++ b/src/test/ui/issues/issue-1920-3.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `issue_1920::S: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `S: Clone` is not satisfied --> $DIR/issue-1920-3.rs:14:20 | LL | fn assert_clone() where T : Clone { } | ----- required by this bound in `assert_clone` ... LL | assert_clone::(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `issue_1920::S` + | ^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-19538.stderr b/src/test/ui/issues/issue-19538.stderr index b6033e47b1..71a013248c 100644 --- a/src/test/ui/issues/issue-19538.stderr +++ b/src/test/ui/issues/issue-19538.stderr @@ -25,7 +25,7 @@ LL | let test: &mut dyn Bar = &mut thing; | ^^^^^^^^^^ the trait `Bar` cannot be made into an object | = help: consider moving `foo` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&mut dyn Bar>` for `&mut Thing` + = 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` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-20005.stderr b/src/test/ui/issues/issue-20005.stderr index cbaa750724..bc414044f7 100644 --- a/src/test/ui/issues/issue-20005.stderr +++ b/src/test/ui/issues/issue-20005.stderr @@ -9,8 +9,8 @@ LL | ) -> >::Result where Dst: From { | help: consider further restricting `Self` | -LL | ) -> >::Result where Dst: From, Self: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | ) -> >::Result where Dst: From, Self: Sized { + | ^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | trait From { diff --git a/src/test/ui/issues/issue-20162.rs b/src/test/ui/issues/issue-20162.rs index b7f9caee89..b491bc37f5 100644 --- a/src/test/ui/issues/issue-20162.rs +++ b/src/test/ui/issues/issue-20162.rs @@ -3,5 +3,5 @@ struct X { x: i32 } fn main() { let mut b: Vec = vec![]; b.sort(); - //~^ ERROR `X: std::cmp::Ord` is not satisfied + //~^ ERROR `X: Ord` is not satisfied } diff --git a/src/test/ui/issues/issue-20162.stderr b/src/test/ui/issues/issue-20162.stderr index 1d0d6d5c5d..ef1eb2ea6c 100644 --- a/src/test/ui/issues/issue-20162.stderr +++ b/src/test/ui/issues/issue-20162.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `X: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `X: Ord` is not satisfied --> $DIR/issue-20162.rs:5:7 | LL | b.sort(); - | ^^^^ the trait `std::cmp::Ord` is not implemented for `X` + | ^^^^ the trait `Ord` is not implemented for `X` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20413.stderr b/src/test/ui/issues/issue-20413.stderr index a3eb4fec70..3f96f0bfcd 100644 --- a/src/test/ui/issues/issue-20413.stderr +++ b/src/test/ui/issues/issue-20413.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `T` is never used LL | struct NoData; | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error[E0275]: overflow evaluating the requirement `NoData>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>: Foo` --> $DIR/issue-20413.rs:8:36 diff --git a/src/test/ui/issues/issue-20433.stderr b/src/test/ui/issues/issue-20433.stderr index fda3f2f5db..3c14226b73 100644 --- a/src/test/ui/issues/issue-20433.stderr +++ b/src/test/ui/issues/issue-20433.stderr @@ -7,9 +7,9 @@ LL | fn iceman(c: Vec<[i32]>) {} ::: $SRC_DIR/alloc/src/vec.rs:LL:COL | LL | pub struct Vec { - | - required by this bound in `std::vec::Vec` + | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = help: the trait `Sized` is not implemented for `[i32]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20605.stderr b/src/test/ui/issues/issue-20605.stderr index 5e06e3bc95..e8d16a55e9 100644 --- a/src/test/ui/issues/issue-20605.stderr +++ b/src/test/ui/issues/issue-20605.stderr @@ -1,11 +1,11 @@ -error[E0277]: the size for values of type `dyn std::iter::Iterator` cannot be known at compilation time +error[E0277]: the size for values of type `dyn Iterator` cannot be known at compilation time --> $DIR/issue-20605.rs:2:17 | LL | for item in *things { *item = 0 } | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `dyn std::iter::Iterator` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Sized` is not implemented for `dyn Iterator` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20692.stderr b/src/test/ui/issues/issue-20692.stderr index ca2611e0f9..0badf66ba7 100644 --- a/src/test/ui/issues/issue-20692.stderr +++ b/src/test/ui/issues/issue-20692.stderr @@ -22,7 +22,7 @@ LL | trait Array: Sized + Copy {} LL | let _ = x | ^ the trait `Array` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Array>` for `&T` + = 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 diff --git a/src/test/ui/issues/issue-2111.stderr b/src/test/ui/issues/issue-2111.stderr index aab2559a15..a39a479e07 100644 --- a/src/test/ui/issues/issue-2111.stderr +++ b/src/test/ui/issues/issue-2111.stderr @@ -5,7 +5,7 @@ LL | match (a,b) { | ^^^^^ pattern `(None, None)` 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 `(std::option::Option, std::option::Option)` + = note: the matched value is of type `(Option, Option)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21160.rs b/src/test/ui/issues/issue-21160.rs index 46733566cf..10136ba11a 100644 --- a/src/test/ui/issues/issue-21160.rs +++ b/src/test/ui/issues/issue-21160.rs @@ -6,6 +6,6 @@ impl Bar { #[derive(Hash)] struct Foo(Bar); -//~^ error: `Bar: std::hash::Hash` is not satisfied +//~^ error: `Bar: Hash` is not satisfied fn main() {} diff --git a/src/test/ui/issues/issue-21160.stderr b/src/test/ui/issues/issue-21160.stderr index aaba014fcb..b6ebfb3556 100644 --- a/src/test/ui/issues/issue-21160.stderr +++ b/src/test/ui/issues/issue-21160.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Bar: std::hash::Hash` is not satisfied +error[E0277]: the trait bound `Bar: Hash` is not satisfied --> $DIR/issue-21160.rs:8:12 | LL | struct Foo(Bar); - | ^^^ the trait `std::hash::Hash` is not implemented for `Bar` + | ^^^ the trait `Hash` is not implemented for `Bar` | ::: $SRC_DIR/core/src/hash/mod.rs:LL:COL | diff --git a/src/test/ui/issues/issue-21332.rs b/src/test/ui/issues/issue-21332.rs index db157f095a..1b13f000b8 100644 --- a/src/test/ui/issues/issue-21332.rs +++ b/src/test/ui/issues/issue-21332.rs @@ -4,7 +4,7 @@ impl Iterator for S { type Item = i32; fn next(&mut self) -> Result { Ok(7) } //~^ ERROR method `next` has an incompatible type for trait - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` } fn main() {} diff --git a/src/test/ui/issues/issue-21332.stderr b/src/test/ui/issues/issue-21332.stderr index ace3e01464..1d6ddd2660 100644 --- a/src/test/ui/issues/issue-21332.stderr +++ b/src/test/ui/issues/issue-21332.stderr @@ -2,9 +2,9 @@ error[E0053]: method `next` has an incompatible type for trait --> $DIR/issue-21332.rs:5:5 | LL | fn next(&mut self) -> Result { Ok(7) } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected fn pointer `fn(&mut S) -> std::option::Option` + = note: expected fn pointer `fn(&mut S) -> Option` found fn pointer `fn(&mut S) -> std::result::Result` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21596.stderr b/src/test/ui/issues/issue-21596.stderr index 3e0a532b2b..70b975524e 100644 --- a/src/test/ui/issues/issue-21596.stderr +++ b/src/test/ui/issues/issue-21596.stderr @@ -8,7 +8,7 @@ LL | println!("{}", z.to_string()); = note: using `<*const T>::as_ref()` on a pointer which is unaligned or points to invalid or uninitialized memory is undefined behavior = note: the method `to_string` exists but the following trait bounds were not satisfied: `*const u8: std::fmt::Display` - which is required by `*const u8: std::string::ToString` + which is required by `*const u8: ToString` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-21763.rs b/src/test/ui/issues/issue-21763.rs index 29ee5f9171..5beb1d8b8c 100644 --- a/src/test/ui/issues/issue-21763.rs +++ b/src/test/ui/issues/issue-21763.rs @@ -7,5 +7,5 @@ fn foo() {} fn main() { foo::, Rc<()>>>(); - //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + //~^ ERROR `Rc<()>` cannot be sent between threads safely } diff --git a/src/test/ui/issues/issue-21763.stderr b/src/test/ui/issues/issue-21763.stderr index 3ec876f37d..4d27f507e2 100644 --- a/src/test/ui/issues/issue-21763.stderr +++ b/src/test/ui/issues/issue-21763.stderr @@ -1,17 +1,17 @@ -error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely +error[E0277]: `Rc<()>` cannot be sent between threads safely --> $DIR/issue-21763.rs:9:5 | LL | fn foo() {} | ---- required by this bound in `foo` ... LL | foo::, Rc<()>>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::rc::Rc<()>` cannot be sent between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `Rc<()>` cannot be sent between threads safely | - = help: within `(std::rc::Rc<()>, std::rc::Rc<()>)`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` - = note: required because it appears within the type `(std::rc::Rc<()>, std::rc::Rc<()>)` - = note: required because of the requirements on the impl of `std::marker::Send` for `hashbrown::raw::RawTable<(std::rc::Rc<()>, std::rc::Rc<()>)>` - = note: required because it appears within the type `hashbrown::map::HashMap, std::rc::Rc<()>, std::collections::hash_map::RandomState>` - = note: required because it appears within the type `std::collections::HashMap, std::rc::Rc<()>>` + = help: within `(Rc<()>, Rc<()>)`, the trait `Send` is not implemented for `Rc<()>` + = note: required because it appears within the type `(Rc<()>, Rc<()>)` + = note: required because of the requirements on the impl of `Send` for `hashbrown::raw::RawTable<(Rc<()>, Rc<()>)>` + = note: required because it appears within the type `hashbrown::map::HashMap, Rc<()>, RandomState>` + = note: required because it appears within the type `HashMap, Rc<()>>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22034.rs b/src/test/ui/issues/issue-22034.rs index fab1cdadaf..405ffd089c 100644 --- a/src/test/ui/issues/issue-22034.rs +++ b/src/test/ui/issues/issue-22034.rs @@ -6,6 +6,6 @@ fn main() { let ptr: *mut () = core::ptr::null_mut(); let _: &mut dyn Fn() = unsafe { &mut *(ptr as *mut dyn Fn()) - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `()` + //~^ ERROR expected a `Fn<()>` closure, found `()` }; } diff --git a/src/test/ui/issues/issue-22034.stderr b/src/test/ui/issues/issue-22034.stderr index 132880aab1..edcd21ebd6 100644 --- a/src/test/ui/issues/issue-22034.stderr +++ b/src/test/ui/issues/issue-22034.stderr @@ -1,12 +1,12 @@ -error[E0277]: expected a `std::ops::Fn<()>` closure, found `()` +error[E0277]: expected a `Fn<()>` closure, found `()` --> $DIR/issue-22034.rs:8:16 | LL | &mut *(ptr as *mut dyn Fn()) | ^^^ expected an `Fn<()>` closure, found `()` | - = help: the trait `std::ops::Fn<()>` is not implemented for `()` + = help: the trait `Fn<()>` is not implemented for `()` = note: wrap the `()` in a closure with no arguments: `|| { /* code */ }` - = note: required for the cast to the object type `dyn std::ops::Fn()` + = note: required for the cast to the object type `dyn Fn()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-2214.rs b/src/test/ui/issues/issue-2214.rs index c4c56cd109..9b7c448541 100644 --- a/src/test/ui/issues/issue-2214.rs +++ b/src/test/ui/issues/issue-2214.rs @@ -23,7 +23,6 @@ fn lgamma(n: c_double, value: &mut isize) -> c_double { mod m { use libc::{c_double, c_int}; - #[link_name = "m"] extern { #[cfg(any(all(unix, not(target_os = "vxworks")), target_os = "cloudabi"))] #[link_name="lgamma_r"] diff --git a/src/test/ui/issues/issue-22289.stderr b/src/test/ui/issues/issue-22289.stderr index 4c35deb1fb..6002785360 100644 --- a/src/test/ui/issues/issue-22289.stderr +++ b/src/test/ui/issues/issue-22289.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `i32` as `&(dyn std::any::Any + 'static)` +error[E0605]: non-primitive cast: `i32` as `&(dyn Any + 'static)` --> $DIR/issue-22289.rs:2:5 | LL | 0 as &dyn std::any::Any; diff --git a/src/test/ui/issues/issue-22312.stderr b/src/test/ui/issues/issue-22312.stderr index 28564b0746..823ffc6de6 100644 --- a/src/test/ui/issues/issue-22312.stderr +++ b/src/test/ui/issues/issue-22312.stderr @@ -1,4 +1,4 @@ -error[E0605]: non-primitive cast: `Self` as `&dyn std::ops::Index>::Output>` +error[E0605]: non-primitive cast: `Self` as `&dyn Index>::Output>` --> $DIR/issue-22312.rs:11:24 | LL | let indexer = &(*self as &dyn Index>::Output>); diff --git a/src/test/ui/issues/issue-22638.rs b/src/test/ui/issues/issue-22638.rs index 8913753842..198ceccc2c 100644 --- a/src/test/ui/issues/issue-22638.rs +++ b/src/test/ui/issues/issue-22638.rs @@ -1,5 +1,6 @@ // build-fail // normalize-stderr-test: "<\[closure@.+`" -> "$$CLOSURE`" +// normalize-stderr-test: ".nll/" -> "/" #![allow(unused)] diff --git a/src/test/ui/issues/issue-22638.stderr b/src/test/ui/issues/issue-22638.stderr index c4255b95b7..1354ec8e89 100644 --- a/src/test/ui/issues/issue-22638.stderr +++ b/src/test/ui/issues/issue-22638.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `A::matches::$CLOSURE` - --> $DIR/issue-22638.rs:55:9 + --> $DIR/issue-22638.rs:56:9 | LL | a.matches(f) | ^^^^^^^^^^^^ | note: `A::matches` defined here - --> $DIR/issue-22638.rs:14:5 + --> $DIR/issue-22638.rs:15:5 | LL | pub fn matches(&self, f: &F) { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-22638/issue-22638.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22872.stderr b/src/test/ui/issues/issue-22872.stderr index 038490bbd7..c65a97d999 100644 --- a/src/test/ui/issues/issue-22872.stderr +++ b/src/test/ui/issues/issue-22872.stderr @@ -4,13 +4,13 @@ error[E0277]: `

    >::Item` is not an iterator LL | let _: Box Wrap<'b>> = Box::new(Wrapper(process)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `

    >::Item` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `

    >::Item` + = help: the trait `Iterator` is not implemented for `

    >::Item` = note: required because of the requirements on the impl of `for<'b> Wrap<'b>` for `Wrapper

    ` = note: required for the cast to the object type `dyn for<'b> Wrap<'b>` help: consider further restricting the associated type | -LL | fn push_process

    (process: P) where P: Process<'static>,

    >::Item: std::iter::Iterator { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn push_process

    (process: P) where P: Process<'static>,

    >::Item: Iterator { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-22874.stderr b/src/test/ui/issues/issue-22874.stderr index 6f22fe6a99..d648990804 100644 --- a/src/test/ui/issues/issue-22874.stderr +++ b/src/test/ui/issues/issue-22874.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `[std::string::String]` cannot be known at compilation time +error[E0277]: the size for values of type `[String]` cannot be known at compilation time --> $DIR/issue-22874.rs:2:11 | LL | rows: [[String]], | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[std::string::String]` + = help: the trait `Sized` is not implemented for `[String]` = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23024.rs b/src/test/ui/issues/issue-23024.rs index 6367536816..ddeb516a4b 100644 --- a/src/test/ui/issues/issue-23024.rs +++ b/src/test/ui/issues/issue-23024.rs @@ -9,5 +9,5 @@ fn main() println!("{:?}",(vfnfer[0] as dyn Fn)(3)); //~^ ERROR the precise format of `Fn`-family traits' //~| ERROR wrong number of type arguments: expected 1, found 0 [E0107] - //~| ERROR the value of the associated type `Output` (from trait `std::ops::FnOnce`) + //~| ERROR the value of the associated type `Output` (from trait `FnOnce`) } diff --git a/src/test/ui/issues/issue-23024.stderr b/src/test/ui/issues/issue-23024.stderr index f9403cd077..fdb68ff712 100644 --- a/src/test/ui/issues/issue-23024.stderr +++ b/src/test/ui/issues/issue-23024.stderr @@ -13,7 +13,7 @@ error[E0107]: wrong number of type arguments: expected 1, found 0 LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); | ^^ expected 1 type argument -error[E0191]: the value of the associated type `Output` (from trait `std::ops::FnOnce`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `FnOnce`) must be specified --> $DIR/issue-23024.rs:9:39 | LL | println!("{:?}",(vfnfer[0] as dyn Fn)(3)); diff --git a/src/test/ui/issues/issue-23122-2.stderr b/src/test/ui/issues/issue-23122-2.stderr index c4032b27ed..60dbb15d0f 100644 --- a/src/test/ui/issues/issue-23122-2.stderr +++ b/src/test/ui/issues/issue-23122-2.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::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: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::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: Sized` --> $DIR/issue-23122-2.rs:7:15 | LL | impl Next for GetNext { @@ -7,7 +7,7 @@ LL | impl Next for GetNext { = help: consider 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>` -error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::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: std::marker::Sized` +error[E0275]: overflow evaluating the requirement `<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<<::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: Sized` --> $DIR/issue-23122-2.rs:9:5 | LL | type Next = as Next>::Next; diff --git a/src/test/ui/issues/issue-23281.stderr b/src/test/ui/issues/issue-23281.stderr index 46b4be6fd3..d8046497b9 100644 --- a/src/test/ui/issues/issue-23281.stderr +++ b/src/test/ui/issues/issue-23281.stderr @@ -1,4 +1,4 @@ -error[E0277]: the size for values of type `(dyn std::ops::Fn() + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Fn() + 'static)` cannot be known at compilation time --> $DIR/issue-23281.rs:4:27 | LL | pub fn function(funs: Vec ()>) {} @@ -7,7 +7,7 @@ LL | pub fn function(funs: Vec ()>) {} LL | struct Vec { | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Fn() + 'static)` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/issue-23281.rs:8:12 | diff --git a/src/test/ui/issues/issue-23302-1.stderr b/src/test/ui/issues/issue-23302-1.stderr index b6c85b9e22..d3a1993536 100644 --- a/src/test/ui/issues/issue-23302-1.stderr +++ b/src/test/ui/issues/issue-23302-1.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when const-evaluating + checking `X::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `X::A::{constant#0}` --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `X::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating `X::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `X::A::{constant#0}`... --> $DIR/issue-23302-1.rs:4:9 | LL | A = X::A as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `X::A as isize`... - = note: ...which again requires const-evaluating + checking `X::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `X::A::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-1.rs:3:1 | diff --git a/src/test/ui/issues/issue-23302-2.stderr b/src/test/ui/issues/issue-23302-2.stderr index d014922fe2..d3b78ea1af 100644 --- a/src/test/ui/issues/issue-23302-2.stderr +++ b/src/test/ui/issues/issue-23302-2.stderr @@ -1,21 +1,21 @@ -error[E0391]: cycle detected when const-evaluating + checking `Y::A::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Y::A::{constant#0}` --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ | -note: ...which requires const-evaluating + checking `Y::A::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ -note: ...which requires const-evaluating `Y::A::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Y::A::{constant#0}`... --> $DIR/issue-23302-2.rs:4:9 | LL | A = Y::B as isize, | ^^^^^^^^^^^^^ = note: ...which requires normalizing `Y::B as isize`... - = note: ...which again requires const-evaluating + checking `Y::A::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Y::A::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-23302-2.rs:3:1 | diff --git a/src/test/ui/issues/issue-23302-3.stderr b/src/test/ui/issues/issue-23302-3.stderr index b30b121427..5233b832ec 100644 --- a/src/test/ui/issues/issue-23302-3.stderr +++ b/src/test/ui/issues/issue-23302-3.stderr @@ -1,21 +1,26 @@ -error[E0391]: cycle detected when const-evaluating + checking `A` +error[E0391]: cycle detected when simplifying constant for the type system `A` --> $DIR/issue-23302-3.rs:1:1 | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ | +note: ...which requires simplifying constant for the type system `A`... + --> $DIR/issue-23302-3.rs:1:1 + | +LL | const A: i32 = B; + | ^^^^^^^^^^^^^^^^^ note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-23302-3.rs:1:1 | -LL | const A: i32 = B; - | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `A`... - --> $DIR/issue-23302-3.rs:1:1 - | LL | const A: i32 = B; | ^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `B`... -note: ...which requires const-evaluating + checking `B`... +note: ...which requires simplifying constant for the type system `B`... + --> $DIR/issue-23302-3.rs:3:1 + | +LL | const B: i32 = A; + | ^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `B`... --> $DIR/issue-23302-3.rs:3:1 | LL | const B: i32 = A; @@ -23,15 +28,10 @@ LL | const B: i32 = A; note: ...which requires const-evaluating + checking `B`... --> $DIR/issue-23302-3.rs:3:1 | -LL | const B: i32 = A; - | ^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `B`... - --> $DIR/issue-23302-3.rs:3:1 - | LL | const B: i32 = A; | ^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `A`... - = note: ...which again requires const-evaluating + checking `A`, completing the cycle + = note: ...which again requires simplifying constant for the type system `A`, completing the cycle = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/issues/issue-23966.stderr b/src/test/ui/issues/issue-23966.stderr index c2fe6d92b9..fff9b3c303 100644 --- a/src/test/ui/issues/issue-23966.stderr +++ b/src/test/ui/issues/issue-23966.stderr @@ -1,10 +1,10 @@ -error[E0277]: expected a `std::ops::FnMut<(_, char)>` closure, found `()` +error[E0277]: expected a `FnMut<(_, char)>` closure, found `()` --> $DIR/issue-23966.rs:2:32 | LL | "".chars().fold(|_, _| (), ()); | ^^ expected an `FnMut<(_, char)>` closure, found `()` | - = help: the trait `std::ops::FnMut<(_, char)>` is not implemented for `()` + = help: the trait `FnMut<(_, char)>` is not implemented for `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24352.stderr b/src/test/ui/issues/issue-24352.stderr index a315ca8b08..69cd778906 100644 --- a/src/test/ui/issues/issue-24352.stderr +++ b/src/test/ui/issues/issue-24352.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot subtract `{integer}` from `f64` LL | 1.0f64 - 1 | ^ no implementation for `f64 - {integer}` | - = help: the trait `std::ops::Sub<{integer}>` is not implemented for `f64` + = help: the trait `Sub<{integer}>` is not implemented for `f64` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24446.stderr b/src/test/ui/issues/issue-24446.stderr index d2714408d8..1674fa8af2 100644 --- a/src/test/ui/issues/issue-24446.stderr +++ b/src/test/ui/issues/issue-24446.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `(dyn std::ops::Fn() -> u32 + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Fn() -> u32 + 'static)` cannot be known at compilation time --> $DIR/issue-24446.rs:2:17 | LL | static foo: dyn Fn() -> u32 = || -> u32 { | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::ops::Fn() -> u32 + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Fn() -> u32 + 'static)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-24819.rs b/src/test/ui/issues/issue-24819.rs index 1155e8d5d5..59c3f2cd11 100644 --- a/src/test/ui/issues/issue-24819.rs +++ b/src/test/ui/issues/issue-24819.rs @@ -4,7 +4,7 @@ fn main() { let mut v = Vec::new(); foo(&mut v); //~^ ERROR mismatched types - //~| expected struct `std::collections::HashSet`, found struct `std::vec::Vec` + //~| expected struct `HashSet`, found struct `Vec` } fn foo(h: &mut HashSet) { diff --git a/src/test/ui/issues/issue-24819.stderr b/src/test/ui/issues/issue-24819.stderr index 1166a887f8..2f931e59d5 100644 --- a/src/test/ui/issues/issue-24819.stderr +++ b/src/test/ui/issues/issue-24819.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-24819.rs:5:9 | LL | foo(&mut v); - | ^^^^^^ expected struct `std::collections::HashSet`, found struct `std::vec::Vec` + | ^^^^^^ expected struct `HashSet`, found struct `Vec` | - = note: expected mutable reference `&mut std::collections::HashSet` - found mutable reference `&mut std::vec::Vec<_>` + = note: expected mutable reference `&mut HashSet` + found mutable reference `&mut Vec<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-25368.stderr b/src/test/ui/issues/issue-25368.stderr index a09de86a70..6a970bc049 100644 --- a/src/test/ui/issues/issue-25368.stderr +++ b/src/test/ui/issues/issue-25368.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed for `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)` +error[E0282]: type annotations needed for `(Sender>, std::sync::mpsc::Receiver>)` --> $DIR/issue-25368.rs:11:17 | LL | let (tx, rx) = channel(); - | -------- consider giving this pattern the explicit type `(std::sync::mpsc::Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified + | -------- consider giving this pattern the explicit type `(Sender>, std::sync::mpsc::Receiver>)`, where the type parameter `T` is specified ... LL | tx.send(Foo{ foo: PhantomData }); | ^^^ cannot infer type for type parameter `T` declared on the struct `Foo` diff --git a/src/test/ui/issues/issue-25386.rs b/src/test/ui/issues/issue-25386.rs index 45775e0e4a..a76d8a615f 100644 --- a/src/test/ui/issues/issue-25386.rs +++ b/src/test/ui/issues/issue-25386.rs @@ -17,12 +17,12 @@ mod stuff { macro_rules! check_ptr_exist { ($var:expr, $member:ident) => ( (*$var.c_object).$member.is_some() - //~^ ERROR field `c_object` of struct `stuff::Item` is private + //~^ ERROR field `c_object` of struct `Item` is private ); } fn main() { let item = stuff::Item::new(); println!("{}", check_ptr_exist!(item, name)); - //~^ ERROR field `name` of struct `stuff::CObj` is private + //~^ ERROR field `name` of struct `CObj` is private } diff --git a/src/test/ui/issues/issue-25386.stderr b/src/test/ui/issues/issue-25386.stderr index 6419e7a557..dcf2f5afa5 100644 --- a/src/test/ui/issues/issue-25386.stderr +++ b/src/test/ui/issues/issue-25386.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `c_object` of struct `stuff::Item` is private +error[E0616]: field `c_object` of struct `Item` is private --> $DIR/issue-25386.rs:19:16 | LL | (*$var.c_object).$member.is_some() @@ -9,7 +9,7 @@ LL | println!("{}", check_ptr_exist!(item, name)); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0616]: field `name` of struct `stuff::CObj` is private +error[E0616]: field `name` of struct `CObj` is private --> $DIR/issue-25386.rs:26:43 | LL | println!("{}", check_ptr_exist!(item, name)); diff --git a/src/test/ui/issues/issue-2590.stderr b/src/test/ui/issues/issue-2590.stderr index 3517d92403..6aacd563af 100644 --- a/src/test/ui/issues/issue-2590.stderr +++ b/src/test/ui/issues/issue-2590.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `self.tokens` which is behind a shared referenc --> $DIR/issue-2590.rs:11:9 | LL | self.tokens - | ^^^^^^^^^^^ move occurs because `self.tokens` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^^^^^^^^ move occurs because `self.tokens` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-26472.rs b/src/test/ui/issues/issue-26472.rs index 4eb38d10a7..b100c59ad0 100644 --- a/src/test/ui/issues/issue-26472.rs +++ b/src/test/ui/issues/issue-26472.rs @@ -8,6 +8,6 @@ mod sub { fn main() { let s = sub::S::new(); - let v = s.len; //~ ERROR field `len` of struct `sub::S` is private - s.len = v; //~ ERROR field `len` of struct `sub::S` is private + let v = s.len; //~ ERROR field `len` of struct `S` is private + s.len = v; //~ ERROR field `len` of struct `S` is private } diff --git a/src/test/ui/issues/issue-26472.stderr b/src/test/ui/issues/issue-26472.stderr index f7df5b6232..8e95b2ff68 100644 --- a/src/test/ui/issues/issue-26472.stderr +++ b/src/test/ui/issues/issue-26472.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `len` of struct `sub::S` is private +error[E0616]: field `len` of struct `S` is private --> $DIR/issue-26472.rs:11:15 | LL | let v = s.len; @@ -9,7 +9,7 @@ help: a method `len` also exists, call it with parentheses LL | let v = s.len(); | ^^ -error[E0616]: field `len` of struct `sub::S` is private +error[E0616]: field `len` of struct `S` is private --> $DIR/issue-26472.rs:12:7 | LL | s.len = v; diff --git a/src/test/ui/issues/issue-27060-2.stderr b/src/test/ui/issues/issue-27060-2.stderr index 5dbcc96e87..c4faecbdf2 100644 --- a/src/test/ui/issues/issue-27060-2.stderr +++ b/src/test/ui/issues/issue-27060-2.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/issue-27060-2.rs:3:11 | LL | pub struct Bad { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | data: T, | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/issues/issue-27078.stderr b/src/test/ui/issues/issue-27078.stderr index de1810e99a..006389f753 100644 --- a/src/test/ui/issues/issue-27078.stderr +++ b/src/test/ui/issues/issue-27078.stderr @@ -7,8 +7,8 @@ LL | fn foo(self) -> &'static i32 { = help: unsized locals are gated as an unstable feature help: consider further restricting `Self` | -LL | fn foo(self) -> &'static i32 where Self: std::marker::Sized { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(self) -> &'static i32 where Self: Sized { + | ^^^^^^^^^^^^^^^^^ help: function arguments must have a statically known size, borrowed types always have a known size | LL | fn foo(&self) -> &'static i32 { diff --git a/src/test/ui/issues/issue-2718-a.rs b/src/test/ui/issues/issue-2718-a.rs index 188168bb94..6c49158454 100644 --- a/src/test/ui/issues/issue-2718-a.rs +++ b/src/test/ui/issues/issue-2718-a.rs @@ -6,7 +6,7 @@ mod pingpong { use SendPacket; pub type Ping = SendPacket; pub struct Pong(SendPacket); - //~^ ERROR recursive type `pingpong::Pong` has infinite size + //~^ ERROR recursive type `Pong` has infinite size } fn main() {} diff --git a/src/test/ui/issues/issue-2718-a.stderr b/src/test/ui/issues/issue-2718-a.stderr index d152ffde4e..5c6c99a1ff 100644 --- a/src/test/ui/issues/issue-2718-a.stderr +++ b/src/test/ui/issues/issue-2718-a.stderr @@ -1,4 +1,4 @@ -error[E0072]: recursive type `pingpong::Pong` has infinite size +error[E0072]: recursive type `Pong` has infinite size --> $DIR/issue-2718-a.rs:8:5 | LL | pub struct Pong(SendPacket); @@ -7,7 +7,7 @@ LL | pub struct Pong(SendPacket); | | recursive without indirection | recursive type has infinite size | -help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `pingpong::Pong` representable +help: insert some indirection (e.g., a `Box`, `Rc`, or `&`) to make `Pong` representable | LL | pub struct Pong(Box>); | ^^^^ ^ diff --git a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr index 30cf0d66af..7895cefb4c 100644 --- a/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr +++ b/src/test/ui/issues/issue-27282-move-ref-mut-into-guard.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | if { (|| { let bar = foo; bar.take() })(); false } => {}, | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/issues/issue-28098.stderr b/src/test/ui/issues/issue-28098.stderr index 8b724b9331..df552fc2d0 100644 --- a/src/test/ui/issues/issue-28098.stderr +++ b/src/test/ui/issues/issue-28098.stderr @@ -4,7 +4,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `bool` is not an iterator @@ -13,8 +13,8 @@ error[E0277]: `bool` is not an iterator LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `bool` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `bool` + = note: required by `into_iter` error[E0277]: `()` is not an iterator --> $DIR/issue-28098.rs:9:28 @@ -22,7 +22,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `()` is not an iterator @@ -31,7 +31,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` error[E0277]: `()` is not an iterator --> $DIR/issue-28098.rs:18:28 @@ -39,7 +39,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `()` is not an iterator @@ -48,7 +48,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` = note: required by `std::iter::Iterator::next` error[E0277]: `bool` is not an iterator @@ -57,8 +57,8 @@ error[E0277]: `bool` is not an iterator LL | for _ in false {} | ^^^^^ `bool` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `bool` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `bool` + = note: required by `into_iter` error[E0277]: `()` is not an iterator --> $DIR/issue-28098.rs:18:13 @@ -66,7 +66,7 @@ error[E0277]: `()` is not an iterator LL | let _ = Iterator::next(&mut ()); | ^^^^^^^^^^^^^^ `()` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `()` + = help: the trait `Iterator` is not implemented for `()` error: aborting due to 8 previous errors diff --git a/src/test/ui/issues/issue-2823.stderr b/src/test/ui/issues/issue-2823.stderr index fc38f4b61f..e044352e95 100644 --- a/src/test/ui/issues/issue-2823.stderr +++ b/src/test/ui/issues/issue-2823.stderr @@ -12,12 +12,12 @@ LL | let _d = c.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here | = 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: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-28344.stderr b/src/test/ui/issues/issue-28344.stderr index e34ac45e69..4955dea564 100644 --- a/src/test/ui/issues/issue-28344.stderr +++ b/src/test/ui/issues/issue-28344.stderr @@ -1,31 +1,31 @@ -error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `BitXor`) must be specified --> $DIR/issue-28344.rs:4:17 | LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | ^^^^^^ help: specify the associated type: `BitXor` -error[E0599]: no function or associated item named `bitor` found for trait object `dyn std::ops::BitXor<_>` in the current scope +error[E0599]: no function or associated item named `bitor` found for trait object `dyn BitXor<_>` in the current scope --> $DIR/issue-28344.rs:4:25 | LL | let x: u8 = BitXor::bitor(0 as u8, 0 as u8); | ^^^^^ | | - | function or associated item not found in `dyn std::ops::BitXor<_>` + | function or associated item not found in `dyn BitXor<_>` | help: there is an associated function with a similar name: `bitxor` -error[E0191]: the value of the associated type `Output` (from trait `std::ops::BitXor`) must be specified +error[E0191]: the value of the associated type `Output` (from trait `BitXor`) must be specified --> $DIR/issue-28344.rs:8:13 | LL | let g = BitXor::bitor; | ^^^^^^ help: specify the associated type: `BitXor` -error[E0599]: no function or associated item named `bitor` found for trait object `dyn std::ops::BitXor<_>` in the current scope +error[E0599]: no function or associated item named `bitor` found for trait object `dyn BitXor<_>` in the current scope --> $DIR/issue-28344.rs:8:21 | LL | let g = BitXor::bitor; | ^^^^^ | | - | function or associated item not found in `dyn std::ops::BitXor<_>` + | function or associated item not found in `dyn BitXor<_>` | help: there is an associated function with a similar name: `bitxor` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-29723.stderr b/src/test/ui/issues/issue-29723.stderr index 04915ab5f9..e39ddfc81c 100644 --- a/src/test/ui/issues/issue-29723.stderr +++ b/src/test/ui/issues/issue-29723.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `s` --> $DIR/issue-29723.rs:10:13 | LL | let s = String::new(); - | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `s` has type `String`, which does not implement the `Copy` trait LL | let _s = match 0 { LL | 0 if { drop(s); false } => String::from("oops"), | - value moved here diff --git a/src/test/ui/issues/issue-30355.stderr b/src/test/ui/issues/issue-30355.stderr index 98de768a5a..db7a5a7f6d 100644 --- a/src/test/ui/issues/issue-30355.stderr +++ b/src/test/ui/issues/issue-30355.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | &X(*Y) | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/issues/issue-31173.stderr b/src/test/ui/issues/issue-31173.stderr index 23a1a27675..818e004ffc 100644 --- a/src/test/ui/issues/issue-31173.stderr +++ b/src/test/ui/issues/issue-31173.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving `, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item == &_` --> $DIR/issue-31173.rs:10:10 | LL | .cloned() @@ -7,25 +7,25 @@ LL | .cloned() = note: expected type `u8` found reference `&_` -error[E0599]: no method named `collect` found for struct `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` in the current scope +error[E0599]: no method named `collect` found for struct `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` in the current scope --> $DIR/issue-31173.rs:14:10 | LL | .collect(); - | ^^^^^^^ method not found in `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>` + | ^^^^^^^ method not found in `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>` | ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL | LL | pub struct Cloned { - | -------------------- doesn't satisfy `_: std::iter::Iterator` + | -------------------- doesn't satisfy `_: Iterator` ... LL | pub struct TakeWhile { - | -------------------------- doesn't satisfy `<_ as std::iter::Iterator>::Item = &_` + | -------------------------- doesn't satisfy `<_ as Iterator>::Item = &_` | = note: the method `collect` exists but the following trait bounds were not satisfied: - `, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]> as std::iter::Iterator>::Item = &_` - which is required by `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: std::iter::Iterator` - `std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: std::iter::Iterator` - which is required by `&mut std::iter::Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6 found_e:_]>>: std::iter::Iterator` + `, [closure@$DIR/issue-31173.rs:6:39: 9:6]> as Iterator>::Item = &_` + which is required by `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` + `Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` + which is required by `&mut Cloned, [closure@$DIR/issue-31173.rs:6:39: 9:6]>>: Iterator` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-32709.stderr b/src/test/ui/issues/issue-32709.stderr index af272633f2..cc12c15362 100644 --- a/src/test/ui/issues/issue-32709.stderr +++ b/src/test/ui/issues/issue-32709.stderr @@ -4,10 +4,10 @@ error[E0277]: `?` couldn't convert the error to `()` LL | fn a() -> Result { | --------------- expected `()` because of this LL | Err(5)?; - | ^ the trait `std::convert::From<{integer}>` is not implemented for `()` + | ^ the trait `From<{integer}>` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-32963.rs b/src/test/ui/issues/issue-32963.rs index 3e6cf446da..58055cd545 100644 --- a/src/test/ui/issues/issue-32963.rs +++ b/src/test/ui/issues/issue-32963.rs @@ -8,5 +8,5 @@ fn main() { size_of_copy::(); //~^ ERROR only auto traits can be used as additional traits in a trait object //~| ERROR only auto traits can be used as additional traits in a trait object - //~| ERROR the trait bound `dyn Misc: std::marker::Copy` is not satisfied + //~| ERROR the trait bound `dyn Misc: Copy` is not satisfied } diff --git a/src/test/ui/issues/issue-32963.stderr b/src/test/ui/issues/issue-32963.stderr index f9628f2c2e..76c62c1c6d 100644 --- a/src/test/ui/issues/issue-32963.stderr +++ b/src/test/ui/issues/issue-32963.stderr @@ -6,7 +6,7 @@ LL | size_of_copy::(); | | | 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 + std::marker::Copy {}` + = help: consider creating a new trait with all of these as super-traits 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,17 +17,17 @@ LL | size_of_copy::(); | | | 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 + std::marker::Copy {}` + = help: consider creating a new trait with all of these as super-traits 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: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `dyn Misc: Copy` is not satisfied --> $DIR/issue-32963.rs:8:5 | LL | fn size_of_copy() -> usize { mem::size_of::() } | ---- required by this bound in `size_of_copy` ... LL | size_of_copy::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `dyn Misc` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `dyn Misc` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-33293.rs b/src/test/ui/issues/issue-33293.rs index d367037428..a6ef007d51 100644 --- a/src/test/ui/issues/issue-33293.rs +++ b/src/test/ui/issues/issue-33293.rs @@ -1,6 +1,6 @@ fn main() { match 0 { aaa::bbb(_) => () - //~^ ERROR failed to resolve: use of undeclared type or module `aaa` + //~^ ERROR failed to resolve: use of undeclared crate or module `aaa` }; } diff --git a/src/test/ui/issues/issue-33293.stderr b/src/test/ui/issues/issue-33293.stderr index 6b7333f22f..c8450f4004 100644 --- a/src/test/ui/issues/issue-33293.stderr +++ b/src/test/ui/issues/issue-33293.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `aaa` +error[E0433]: failed to resolve: use of undeclared crate or module `aaa` --> $DIR/issue-33293.rs:3:9 | LL | aaa::bbb(_) => () - | ^^^ use of undeclared type or module `aaa` + | ^^^ use of undeclared crate or module `aaa` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-3344.stderr b/src/test/ui/issues/issue-3344.stderr index 723e03d452..11d5999672 100644 --- a/src/test/ui/issues/issue-3344.stderr +++ b/src/test/ui/issues/issue-3344.stderr @@ -4,7 +4,7 @@ error[E0046]: not all trait items implemented, missing: `partial_cmp` LL | impl PartialOrd for Thing { | ^^^^^^^^^^^^^^^^^^^^^^^^^ missing `partial_cmp` in implementation | - = help: implement the missing item: `fn partial_cmp(&self, _: &Rhs) -> std::option::Option { todo!() }` + = help: implement the missing item: `fn partial_cmp(&self, _: &Rhs) -> Option { todo!() }` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-33941.stderr b/src/test/ui/issues/issue-33941.stderr index 20335d2cdd..aeab923d2d 100644 --- a/src/test/ui/issues/issue-33941.stderr +++ b/src/test/ui/issues/issue-33941.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:36 | LL | for _ in HashMap::new().iter().cloned() {} @@ -7,7 +7,7 @@ LL | for _ in HashMap::new().iter().cloned() {} = note: expected tuple `(&_, &_)` found reference `&_` -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:14 | LL | for _ in HashMap::new().iter().cloned() {} @@ -15,9 +15,9 @@ LL | for _ in HashMap::new().iter().cloned() {} | = note: expected tuple `(&_, &_)` found reference `&_` - = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned>` + = note: required because of the requirements on the impl of `Iterator` for `Cloned>` -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == &_` +error[E0271]: type mismatch resolving ` as Iterator>::Item == &_` --> $DIR/issue-33941.rs:4:14 | LL | for _ in HashMap::new().iter().cloned() {} @@ -25,7 +25,7 @@ LL | for _ in HashMap::new().iter().cloned() {} | = note: expected tuple `(&_, &_)` found reference `&_` - = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::iter::Cloned>` + = note: required because of the requirements on the impl of `Iterator` for `Cloned>` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-34229.stderr b/src/test/ui/issues/issue-34229.stderr index cd9be6ab72..d25189e783 100644 --- a/src/test/ui/issues/issue-34229.stderr +++ b/src/test/ui/issues/issue-34229.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `Comparable` with `Comparable` LL | #[derive(PartialEq, PartialOrd)] struct Nope(Comparable); | ^^^^^^^^^^ no implementation for `Comparable < Comparable` and `Comparable > Comparable` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `Comparable` + = help: the trait `PartialOrd` is not implemented for `Comparable` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-34334.rs b/src/test/ui/issues/issue-34334.rs index 97905e2f8f..bf2d091a01 100644 --- a/src/test/ui/issues/issue-34334.rs +++ b/src/test/ui/issues/issue-34334.rs @@ -2,5 +2,5 @@ fn main () { let sr: Vec<(u32, _, _) = vec![]; //~^ ERROR expected one of `,` or `>`, found `=` let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); - //~^ ERROR a value of type `std::vec::Vec<(u32, _, _)>` cannot be built + //~^ ERROR a value of type `Vec<(u32, _, _)>` cannot be built } diff --git a/src/test/ui/issues/issue-34334.stderr b/src/test/ui/issues/issue-34334.stderr index 364f8264db..c10a414430 100644 --- a/src/test/ui/issues/issue-34334.stderr +++ b/src/test/ui/issues/issue-34334.stderr @@ -6,13 +6,13 @@ LL | let sr: Vec<(u32, _, _) = vec![]; | | | while parsing the type for `sr` -error[E0277]: a value of type `std::vec::Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()` +error[E0277]: a value of type `Vec<(u32, _, _)>` cannot be built from an iterator over elements of type `()` --> $DIR/issue-34334.rs:4:87 | LL | let sr2: Vec<(u32, _, _)> = sr.iter().map(|(faction, th_sender, th_receiver)| {}).collect(); - | ^^^^^^^ value of type `std::vec::Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator` + | ^^^^^^^ value of type `Vec<(u32, _, _)>` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator<()>` is not implemented for `std::vec::Vec<(u32, _, _)>` + = help: the trait `FromIterator<()>` is not implemented for `Vec<(u32, _, _)>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-34784.rs b/src/test/ui/issues/issue-34784.rs index d3206e9943..98d943470a 100644 --- a/src/test/ui/issues/issue-34784.rs +++ b/src/test/ui/issues/issue-34784.rs @@ -1,4 +1,6 @@ // run-pass + +#![warn(pointer_structural_match)] #![allow(dead_code)] const C: *const u8 = &0; diff --git a/src/test/ui/issues/issue-35677.stderr b/src/test/ui/issues/issue-35677.stderr index 978221e502..afdc5d68ca 100644 --- a/src/test/ui/issues/issue-35677.stderr +++ b/src/test/ui/issues/issue-35677.stderr @@ -1,12 +1,12 @@ -error[E0599]: no method named `is_subset` found for reference `&std::collections::HashSet` in the current scope +error[E0599]: no method named `is_subset` found for reference `&HashSet` in the current scope --> $DIR/issue-35677.rs:4:10 | LL | this.is_subset(other) - | ^^^^^^^^^ method not found in `&std::collections::HashSet` + | ^^^^^^^^^ method not found in `&HashSet` | = note: the method `is_subset` exists but the following trait bounds were not satisfied: - `T: std::cmp::Eq` - `T: std::hash::Hash` + `T: Eq` + `T: Hash` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-35869.stderr b/src/test/ui/issues/issue-35869.stderr index 66e89998e1..f80561bf6b 100644 --- a/src/test/ui/issues/issue-35869.stderr +++ b/src/test/ui/issues/issue-35869.stderr @@ -19,8 +19,8 @@ LL | fn bar(_: Option); LL | fn bar(_: Option) {} | ^^^^^^^^^^^ expected `u8`, found `u16` | - = note: expected fn pointer `fn(std::option::Option)` - found fn pointer `fn(std::option::Option)` + = note: expected fn pointer `fn(Option)` + found fn pointer `fn(Option)` error[E0053]: method `baz` has an incompatible type for trait --> $DIR/issue-35869.rs:15:15 diff --git a/src/test/ui/issues/issue-35988.stderr b/src/test/ui/issues/issue-35988.stderr index 0f0b80a9ff..2e03acc112 100644 --- a/src/test/ui/issues/issue-35988.stderr +++ b/src/test/ui/issues/issue-35988.stderr @@ -1,10 +1,10 @@ -error[E0277]: the size for values of type `[std::boxed::Box]` cannot be known at compilation time +error[E0277]: the size for values of type `[Box]` cannot be known at compilation time --> $DIR/issue-35988.rs:2:7 | LL | V([Box]), | ^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[std::boxed::Box]` + = help: the trait `Sized` is not implemented for `[Box]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size diff --git a/src/test/ui/issues/issue-3601.stderr b/src/test/ui/issues/issue-3601.stderr index 6b2a5d7624..adad480f92 100644 --- a/src/test/ui/issues/issue-3601.stderr +++ b/src/test/ui/issues/issue-3601.stderr @@ -5,7 +5,7 @@ LL | box NodeKind::Element(ed) => match ed.kind { | ^^^^^^^ 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 `std::boxed::Box` + = note: the matched value is of type `Box` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-36163.stderr b/src/test/ui/issues/issue-36163.stderr index 7c2da9dce6..113f86cf0f 100644 --- a/src/test/ui/issues/issue-36163.stderr +++ b/src/test/ui/issues/issue-36163.stderr @@ -1,21 +1,26 @@ -error[E0391]: cycle detected when const-evaluating + checking `Foo::B::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Foo::B::{constant#0}` --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ | -note: ...which requires const-evaluating + checking `Foo::B::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ -note: ...which requires const-evaluating `Foo::B::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Foo::B::{constant#0}`... --> $DIR/issue-36163.rs:4:9 | LL | B = A, | ^ = note: ...which requires normalizing `A`... -note: ...which requires const-evaluating + checking `A`... +note: ...which requires simplifying constant for the type system `A`... + --> $DIR/issue-36163.rs:1:1 + | +LL | const A: isize = Foo::B as isize; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +note: ...which requires simplifying constant for the type system `A`... --> $DIR/issue-36163.rs:1:1 | LL | const A: isize = Foo::B as isize; @@ -23,15 +28,10 @@ LL | const A: isize = Foo::B as isize; note: ...which requires const-evaluating + checking `A`... --> $DIR/issue-36163.rs:1:1 | -LL | const A: isize = Foo::B as isize; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...which requires const-evaluating `A`... - --> $DIR/issue-36163.rs:1:1 - | LL | const A: isize = Foo::B as isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: ...which requires normalizing `A`... - = note: ...which again requires const-evaluating + checking `Foo::B::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Foo::B::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/issue-36163.rs:1:1 | diff --git a/src/test/ui/issues/issue-36299.stderr b/src/test/ui/issues/issue-36299.stderr index a9516b8e5e..8e29a925d8 100644 --- a/src/test/ui/issues/issue-36299.stderr +++ b/src/test/ui/issues/issue-36299.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | struct Foo<'a, A> {} | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `A` is never used --> $DIR/issue-36299.rs:1:16 @@ -12,7 +12,7 @@ error[E0392]: parameter `A` is never used LL | struct Foo<'a, A> {} | ^ unused parameter | - = help: consider removing `A`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-36617.stderr b/src/test/ui/issues/issue-36617.stderr index 98b41b07ea..586dcf2cea 100644 --- a/src/test/ui/issues/issue-36617.stderr +++ b/src/test/ui/issues/issue-36617.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-36617.rs:1:1 | LL | #![derive(Copy)] @@ -22,3 +22,4 @@ LL | #![derive(Copy)] error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-36638.stderr b/src/test/ui/issues/issue-36638.stderr index fe48ea158d..e5d6f8ec7a 100644 --- a/src/test/ui/issues/issue-36638.stderr +++ b/src/test/ui/issues/issue-36638.stderr @@ -16,7 +16,7 @@ error[E0392]: parameter `Self` is never used LL | struct Foo(Self); | ^^^^ unused parameter | - = help: consider removing `Self`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `Self`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 3 previous errors diff --git a/src/test/ui/issues/issue-3680.rs b/src/test/ui/issues/issue-3680.rs index 64050c72f2..8912e7a18a 100644 --- a/src/test/ui/issues/issue-3680.rs +++ b/src/test/ui/issues/issue-3680.rs @@ -2,8 +2,8 @@ fn main() { match None { Err(_) => () //~^ ERROR mismatched types - //~| expected enum `std::option::Option<_>` + //~| expected enum `Option<_>` //~| found enum `std::result::Result<_, _>` - //~| expected enum `std::option::Option`, found enum `std::result::Result` + //~| expected enum `Option`, found enum `std::result::Result` } } diff --git a/src/test/ui/issues/issue-3680.stderr b/src/test/ui/issues/issue-3680.stderr index 713e4b5ccd..479942b8e2 100644 --- a/src/test/ui/issues/issue-3680.stderr +++ b/src/test/ui/issues/issue-3680.stderr @@ -2,11 +2,11 @@ error[E0308]: mismatched types --> $DIR/issue-3680.rs:3:9 | LL | match None { - | ---- this expression has type `std::option::Option<_>` + | ---- this expression has type `Option<_>` LL | Err(_) => () - | ^^^^^^ expected enum `std::option::Option`, found enum `std::result::Result` + | ^^^^^^ expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option<_>` + = note: expected enum `Option<_>` found enum `std::result::Result<_, _>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37026.stderr b/src/test/ui/issues/issue-37026.stderr index f0285730c5..48a4a5bcad 100644 --- a/src/test/ui/issues/issue-37026.stderr +++ b/src/test/ui/issues/issue-37026.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let empty_struct::XEmpty2 = (); | ^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` | | - | expected `()`, found struct `empty_struct::XEmpty2` + | expected `()`, found struct `XEmpty2` error[E0308]: mismatched types --> $DIR/issue-37026.rs:7:9 @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | let empty_struct::XEmpty6(..) = (); | ^^^^^^^^^^^^^^^^^^^^^^^^^ -- this expression has type `()` | | - | expected `()`, found struct `empty_struct::XEmpty6` + | expected `()`, found struct `XEmpty6` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs index d3d5863ddb..50d1f166c9 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" trait Mirror { type Image; diff --git a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr index a94f190d6b..93aeb89469 100644 --- a/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr +++ b/src/test/ui/issues/issue-37311-type-length-limit/issue-37311.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `<(&(&(&(&(&(&(&(&(&(&(&(&(&(&(&(.....), ...), ...) as Foo>::recurse` - --> $DIR/issue-37311.rs:16:9 + --> $DIR/issue-37311.rs:17:9 | LL | (self, self).recurse(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `::recurse` defined here - --> $DIR/issue-37311.rs:15:5 + --> $DIR/issue-37311.rs:16:5 | LL | fn recurse(&self) { | ^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-37311-type-length-limit/issue-37311/issue-37311.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-37534.stderr b/src/test/ui/issues/issue-37534.stderr index 5d008cf24d..895479986f 100644 --- a/src/test/ui/issues/issue-37534.stderr +++ b/src/test/ui/issues/issue-37534.stderr @@ -21,7 +21,7 @@ error[E0392]: parameter `T` is never used LL | struct Foo { } | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/issues/issue-37550.rs b/src/test/ui/issues/issue-37550.rs index 505c030b96..35b63bddca 100644 --- a/src/test/ui/issues/issue-37550.rs +++ b/src/test/ui/issues/issue-37550.rs @@ -1,6 +1,6 @@ const fn x() { let t = true; - let x = || t; //~ ERROR function pointers in const fn are unstable + let x = || t; //~ ERROR function pointer } fn main() {} diff --git a/src/test/ui/issues/issue-37550.stderr b/src/test/ui/issues/issue-37550.stderr index 35da625801..54b60df70f 100644 --- a/src/test/ui/issues/issue-37550.stderr +++ b/src/test/ui/issues/issue-37550.stderr @@ -1,12 +1,12 @@ -error[E0723]: function pointers in const fn are unstable +error[E0658]: function pointers cannot appear in constant functions --> $DIR/issue-37550.rs:3:9 | LL | let x = || t; | ^ | = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: add `#![feature(const_fn_fn_ptr_basics)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/issues/issue-3763.rs b/src/test/ui/issues/issue-3763.rs index 451321c550..25ad6b319f 100644 --- a/src/test/ui/issues/issue-3763.rs +++ b/src/test/ui/issues/issue-3763.rs @@ -16,14 +16,14 @@ mod my_mod { fn main() { let my_struct = my_mod::MyStruct(); let _woohoo = (&my_struct).priv_field; - //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private + //~^ ERROR field `priv_field` of struct `MyStruct` is private let _woohoo = (Box::new(my_struct)).priv_field; - //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private + //~^ ERROR field `priv_field` of struct `MyStruct` is private (&my_struct).happyfun(); //~ ERROR associated function `happyfun` is private (Box::new(my_struct)).happyfun(); //~ ERROR associated function `happyfun` is private let nope = my_struct.priv_field; - //~^ ERROR field `priv_field` of struct `my_mod::MyStruct` is private + //~^ ERROR field `priv_field` of struct `MyStruct` is private } diff --git a/src/test/ui/issues/issue-3763.stderr b/src/test/ui/issues/issue-3763.stderr index b63967bb9d..7f54c9f8a6 100644 --- a/src/test/ui/issues/issue-3763.stderr +++ b/src/test/ui/issues/issue-3763.stderr @@ -1,10 +1,10 @@ -error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private +error[E0616]: field `priv_field` of struct `MyStruct` is private --> $DIR/issue-3763.rs:18:32 | LL | let _woohoo = (&my_struct).priv_field; | ^^^^^^^^^^ private field -error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private +error[E0616]: field `priv_field` of struct `MyStruct` is private --> $DIR/issue-3763.rs:21:41 | LL | let _woohoo = (Box::new(my_struct)).priv_field; @@ -22,7 +22,7 @@ error[E0624]: associated function `happyfun` is private LL | (Box::new(my_struct)).happyfun(); | ^^^^^^^^ private associated function -error[E0616]: field `priv_field` of struct `my_mod::MyStruct` is private +error[E0616]: field `priv_field` of struct `MyStruct` is private --> $DIR/issue-3763.rs:27:26 | LL | let nope = my_struct.priv_field; diff --git a/src/test/ui/issues/issue-37884.stderr b/src/test/ui/issues/issue-37884.stderr index 5baa245b3c..d741d42685 100644 --- a/src/test/ui/issues/issue-37884.stderr +++ b/src/test/ui/issues/issue-37884.stderr @@ -9,8 +9,8 @@ LL | | Some(&mut self.0) LL | | } | |_____^ lifetime mismatch | - = note: expected fn pointer `fn(&mut RepeatMut<'a, T>) -> std::option::Option<_>` - found fn pointer `fn(&'a mut RepeatMut<'a, T>) -> std::option::Option<_>` + = 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... --> $DIR/issue-37884.rs:6:5 | diff --git a/src/test/ui/issues/issue-38604.stderr b/src/test/ui/issues/issue-38604.stderr index 2bba50e1f4..39a62b81c6 100644 --- a/src/test/ui/issues/issue-38604.stderr +++ b/src/test/ui/issues/issue-38604.stderr @@ -20,8 +20,8 @@ LL | trait Foo where u32: Q { LL | Box::new(()); | ^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box<()>` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box<()>` + = note: required by cast to type `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-38954.stderr b/src/test/ui/issues/issue-38954.stderr index e96bbe1a99..bc40fd07c5 100644 --- a/src/test/ui/issues/issue-38954.stderr +++ b/src/test/ui/issues/issue-38954.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | fn _test(ref _p: str) {} | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/issues/issue-39175.stderr b/src/test/ui/issues/issue-39175.stderr index 2f6e676538..dbb334e7b9 100644 --- a/src/test/ui/issues/issue-39175.stderr +++ b/src/test/ui/issues/issue-39175.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `exec` found for mutable reference `&mut std::process::Command` in the current scope +error[E0599]: no method named `exec` found for mutable reference `&mut Command` in the current scope --> $DIR/issue-39175.rs:15:39 | LL | Command::new("echo").arg("hello").exec(); - | ^^^^ method not found in `&mut std::process::Command` + | ^^^^ method not found in `&mut Command` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-40000.stderr b/src/test/ui/issues/issue-40000.stderr index 3eb3482ac9..00543c5fff 100644 --- a/src/test/ui/issues/issue-40000.stderr +++ b/src/test/ui/issues/issue-40000.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | foo(bar); | ^^^ one type is more general than the other | - = note: expected trait object `dyn for<'r> std::ops::Fn(&'r i32)` - found trait object `dyn std::ops::Fn(&i32)` + = note: expected trait object `dyn for<'r> Fn(&'r i32)` + found trait object `dyn Fn(&i32)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr index 8a9d9aab81..0a5a6b80e9 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-1.stderr @@ -1,10 +1,10 @@ -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/issue-40402-1.rs:9:13 | LL | let e = f.v[0]; | ^^^^^^ | | - | move occurs because value has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because value has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&f.v[0]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr index d0a4097de6..b6049f967f 100644 --- a/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr +++ b/src/test/ui/issues/issue-40402-ref-hints/issue-40402-2.stderr @@ -1,4 +1,4 @@ -error[E0507]: cannot move out of index of `std::vec::Vec<(std::string::String, std::string::String)>` +error[E0507]: cannot move out of index of `Vec<(String, String)>` --> $DIR/issue-40402-2.rs:5:18 | LL | let (a, b) = x[0]; diff --git a/src/test/ui/issues/issue-40749.rs b/src/test/ui/issues/issue-40749.rs index 87ff5a650f..0a847853b1 100644 --- a/src/test/ui/issues/issue-40749.rs +++ b/src/test/ui/issues/issue-40749.rs @@ -2,5 +2,5 @@ fn main() { [0; ..10]; //~^ ERROR mismatched types //~| expected type `usize` - //~| found struct `std::ops::RangeTo<{integer}>` + //~| found struct `RangeTo<{integer}>` } diff --git a/src/test/ui/issues/issue-40749.stderr b/src/test/ui/issues/issue-40749.stderr index 4170a96bdd..fa239f744f 100644 --- a/src/test/ui/issues/issue-40749.stderr +++ b/src/test/ui/issues/issue-40749.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-40749.rs:2:9 | LL | [0; ..10]; - | ^^^^ expected `usize`, found struct `std::ops::RangeTo` + | ^^^^ expected `usize`, found struct `RangeTo` | = note: expected type `usize` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-40827.stderr b/src/test/ui/issues/issue-40827.stderr index a10abb8902..5ea795d139 100644 --- a/src/test/ui/issues/issue-40827.stderr +++ b/src/test/ui/issues/issue-40827.stderr @@ -1,29 +1,29 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/issue-40827.rs:14:5 | LL | fn f(_: T) {} | ---- required by this bound in `f` ... LL | f(Foo(Arc::new(Bar::B(None)))); - | ^ `std::rc::Rc` cannot be sent between threads safely + | ^ `Rc` cannot be sent between threads safely | - = help: within `Bar`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = help: within `Bar`, the trait `Send` is not implemented for `Rc` = note: required because it appears within the type `Bar` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc` + = note: required because of the requirements on the impl of `Send` for `Arc` = note: required because it appears within the type `Foo` -error[E0277]: `std::rc::Rc` cannot be shared between threads safely +error[E0277]: `Rc` cannot be shared between threads safely --> $DIR/issue-40827.rs:14:5 | LL | fn f(_: T) {} | ---- required by this bound in `f` ... LL | f(Foo(Arc::new(Bar::B(None)))); - | ^ `std::rc::Rc` cannot be shared between threads safely + | ^ `Rc` cannot be shared between threads safely | - = help: within `Bar`, the trait `std::marker::Sync` is not implemented for `std::rc::Rc` + = help: within `Bar`, the trait `Sync` is not implemented for `Rc` = note: required because it appears within the type `Bar` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::sync::Arc` + = note: required because of the requirements on the impl of `Send` for `Arc` = note: required because it appears within the type `Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-41229-ref-str.stderr b/src/test/ui/issues/issue-41229-ref-str.stderr index 35aa1acdc1..c5c848e63e 100644 --- a/src/test/ui/issues/issue-41229-ref-str.stderr +++ b/src/test/ui/issues/issue-41229-ref-str.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | pub fn example(ref s: str) {} | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/issues/issue-41726.stderr b/src/test/ui/issues/issue-41726.stderr index aa7f23511d..b00a420bc3 100644 --- a/src/test/ui/issues/issue-41726.stderr +++ b/src/test/ui/issues/issue-41726.stderr @@ -1,10 +1,10 @@ -error[E0596]: cannot borrow data in an index of `std::collections::HashMap>` as mutable +error[E0596]: cannot borrow data in an index of `HashMap>` as mutable --> $DIR/issue-41726.rs:5:9 | LL | things[src.as_str()].sort(); | ^^^^^^^^^^^^^^^^^^^^ cannot borrow as mutable | - = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `std::collections::HashMap>` + = help: trait `IndexMut` is required to modify indexed content, but it is not implemented for `HashMap>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-41974.stderr b/src/test/ui/issues/issue-41974.stderr index d082e0a6b5..f1342181b3 100644 --- a/src/test/ui/issues/issue-41974.stderr +++ b/src/test/ui/issues/issue-41974.stderr @@ -5,7 +5,7 @@ LL | impl Drop for T where T: A { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `alloc`: - - impl std::ops::Drop for std::boxed::Box + - impl Drop for Box where T: ?Sized; = note: downstream crates may implement trait `A` for type `std::boxed::Box<_>` diff --git a/src/test/ui/issues/issue-42312.stderr b/src/test/ui/issues/issue-42312.stderr index fbe87aa2db..b55a724c0d 100644 --- a/src/test/ui/issues/issue-42312.stderr +++ b/src/test/ui/issues/issue-42312.stderr @@ -1,27 +1,27 @@ -error[E0277]: the size for values of type `::Target` cannot be known at compilation time +error[E0277]: the size for values of type `::Target` cannot be known at compilation time --> $DIR/issue-42312.rs:4:12 | LL | fn baz(_: Self::Target) where Self: Deref {} | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `::Target` + = help: the trait `Sized` is not implemented for `::Target` = help: unsized locals are gated as an unstable feature help: consider further restricting the associated type | -LL | fn baz(_: Self::Target) where Self: Deref, ::Target: std::marker::Sized {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn baz(_: Self::Target) where Self: Deref, ::Target: Sized {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: function arguments must have a statically known size, borrowed types always have a known size | LL | fn baz(_: &Self::Target) where Self: Deref {} | ^ -error[E0277]: the size for values of type `(dyn std::string::ToString + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn ToString + 'static)` cannot be known at compilation time --> $DIR/issue-42312.rs:8:10 | LL | pub fn f(_: dyn ToString) {} | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::string::ToString + 'static)` + = help: the trait `Sized` is not implemented for `(dyn ToString + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/issues/issue-42796.stderr b/src/test/ui/issues/issue-42796.stderr index d9dfbc999f..61cf3f25d0 100644 --- a/src/test/ui/issues/issue-42796.stderr +++ b/src/test/ui/issues/issue-42796.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `s` --> $DIR/issue-42796.rs:18:20 | LL | let s = "Hello!".to_owned(); - | - move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `s` has type `String`, which does not implement the `Copy` trait LL | let mut s_copy = s; | - value moved here ... diff --git a/src/test/ui/issues/issue-42880.stderr b/src/test/ui/issues/issue-42880.stderr index 82cdc20df2..bec14429d3 100644 --- a/src/test/ui/issues/issue-42880.stderr +++ b/src/test/ui/issues/issue-42880.stderr @@ -1,8 +1,8 @@ -error[E0599]: no associated item named `String` found for struct `std::string::String` in the current scope +error[E0599]: no associated item named `String` found for struct `String` in the current scope --> $DIR/issue-42880.rs:4:22 | LL | let f = |&Value::String(_)| (); - | ^^^^^^ associated item not found in `std::string::String` + | ^^^^^^ associated item not found in `String` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43023.stderr b/src/test/ui/issues/issue-43023.stderr index 206a51645f..f5f51cdcd4 100644 --- a/src/test/ui/issues/issue-43023.stderr +++ b/src/test/ui/issues/issue-43023.stderr @@ -1,16 +1,16 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:4:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:11:5 | LL | #[derive(Debug)] | ^^^^^^^^^^^^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43023.rs:16:5 | LL | #[derive(Debug)] @@ -18,3 +18,4 @@ LL | #[derive(Debug)] error: aborting due to 3 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-43420-no-over-suggest.stderr b/src/test/ui/issues/issue-43420-no-over-suggest.stderr index 27aebc548e..77d52f6eca 100644 --- a/src/test/ui/issues/issue-43420-no-over-suggest.stderr +++ b/src/test/ui/issues/issue-43420-no-over-suggest.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/issue-43420-no-over-suggest.rs:8:9 | LL | foo(&a); - | ^^ expected slice `[u16]`, found struct `std::vec::Vec` + | ^^ expected slice `[u16]`, found struct `Vec` | = note: expected reference `&[u16]` - found reference `&std::vec::Vec` + found reference `&Vec` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43784-associated-type.rs b/src/test/ui/issues/issue-43784-associated-type.rs index 92083d88f1..78815d8d3f 100644 --- a/src/test/ui/issues/issue-43784-associated-type.rs +++ b/src/test/ui/issues/issue-43784-associated-type.rs @@ -11,7 +11,7 @@ impl Partial for T::Assoc where } impl Complete for T { - type Assoc = T; //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied + type Assoc = T; //~ ERROR the trait bound `T: Copy` is not satisfied } fn main() {} diff --git a/src/test/ui/issues/issue-43784-associated-type.stderr b/src/test/ui/issues/issue-43784-associated-type.stderr index d8e9110fbb..039852ad16 100644 --- a/src/test/ui/issues/issue-43784-associated-type.stderr +++ b/src/test/ui/issues/issue-43784-associated-type.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-associated-type.rs:14:18 | LL | type Assoc = T; - | ^ the trait `std::marker::Copy` is not implemented for `T` + | ^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Complete for T { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Complete for T { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-43784-supertrait.rs b/src/test/ui/issues/issue-43784-supertrait.rs index 3c03433a26..55c26ccd2d 100644 --- a/src/test/ui/issues/issue-43784-supertrait.rs +++ b/src/test/ui/issues/issue-43784-supertrait.rs @@ -5,6 +5,6 @@ pub trait Complete: Partial { } impl Partial for T where T: Complete {} -impl Complete for T {} //~ ERROR the trait bound `T: std::marker::Copy` is not satisfied +impl Complete for T {} //~ ERROR the trait bound `T: Copy` is not satisfied fn main() {} diff --git a/src/test/ui/issues/issue-43784-supertrait.stderr b/src/test/ui/issues/issue-43784-supertrait.stderr index 2fb0583ee7..d92e4fa9e4 100644 --- a/src/test/ui/issues/issue-43784-supertrait.stderr +++ b/src/test/ui/issues/issue-43784-supertrait.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/issue-43784-supertrait.rs:8:9 | LL | impl Complete for T {} - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Complete for T {} - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Complete for T {} + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/issues/issue-44333.rs b/src/test/ui/issues/issue-44333.rs index fffef97504..96e8795e52 100644 --- a/src/test/ui/issues/issue-44333.rs +++ b/src/test/ui/issues/issue-44333.rs @@ -1,4 +1,7 @@ // run-pass + +#![warn(pointer_structural_match)] + type Func = fn(usize, usize) -> usize; fn foo(a: usize, b: usize) -> usize { a + b } @@ -13,8 +16,10 @@ const BAR: Func = bar; fn main() { match test(std::env::consts::ARCH.len()) { - FOO => println!("foo"), - BAR => println!("bar"), + FOO => println!("foo"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error + BAR => println!("bar"), //~ WARN pointers in patterns behave unpredictably + //~^ WARN will become a hard error _ => unreachable!(), } } diff --git a/src/test/ui/issues/issue-44333.stderr b/src/test/ui/issues/issue-44333.stderr new file mode 100644 index 0000000000..8302b09e53 --- /dev/null +++ b/src/test/ui/issues/issue-44333.stderr @@ -0,0 +1,25 @@ +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:19:9 + | +LL | FOO => println!("foo"), + | ^^^ + | +note: the lint level is defined here + --> $DIR/issue-44333.rs:3:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 #62411 + +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-44333.rs:21:9 + | +LL | BAR => println!("bar"), + | ^^^ + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #62411 + +warning: 2 warnings emitted + diff --git a/src/test/ui/issues/issue-46112.stderr b/src/test/ui/issues/issue-46112.stderr index a861c38b00..ec05fbe580 100644 --- a/src/test/ui/issues/issue-46112.stderr +++ b/src/test/ui/issues/issue-46112.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | fn main() { test(Ok(())); } | ^^ | | - | expected enum `std::option::Option`, found `()` + | expected enum `Option`, found `()` | help: try using a variant of the expected enum: `Some(())` | - = note: expected enum `std::option::Option<()>` + = note: expected enum `Option<()>` found unit type `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-46553.rs b/src/test/ui/issues/issue-46553.rs index e21a532eff..0a1e835672 100644 --- a/src/test/ui/issues/issue-46553.rs +++ b/src/test/ui/issues/issue-46553.rs @@ -1,5 +1,5 @@ // run-pass -#![feature(const_fn)] +#![feature(const_fn_fn_ptr_basics)] #![deny(const_err)] pub struct Data { diff --git a/src/test/ui/issues/issue-46771.rs b/src/test/ui/issues/issue-46771.rs index 2b5241e5ff..22be8d6af8 100644 --- a/src/test/ui/issues/issue-46771.rs +++ b/src/test/ui/issues/issue-46771.rs @@ -1,4 +1,4 @@ fn main() { struct Foo; - (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `main::Foo` + (1 .. 2).find(|_| Foo(0) == 0); //~ ERROR expected function, found `Foo` } diff --git a/src/test/ui/issues/issue-46771.stderr b/src/test/ui/issues/issue-46771.stderr index 76c86d7aa9..a37b564895 100644 --- a/src/test/ui/issues/issue-46771.stderr +++ b/src/test/ui/issues/issue-46771.stderr @@ -1,8 +1,8 @@ -error[E0618]: expected function, found `main::Foo` +error[E0618]: expected function, found `Foo` --> $DIR/issue-46771.rs:3:23 | LL | struct Foo; - | ----------- `main::Foo` defined here + | ----------- `Foo` defined here LL | (1 .. 2).find(|_| Foo(0) == 0); | ^^^--- | | diff --git a/src/test/ui/issues/issue-47646.stderr b/src/test/ui/issues/issue-47646.stderr index c0b8763684..b46c277d04 100644 --- a/src/test/ui/issues/issue-47646.stderr +++ b/src/test/ui/issues/issue-47646.stderr @@ -11,7 +11,7 @@ LL | println!("{:?}", heap); | ^^^^ immutable borrow occurs here ... LL | }; - | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(std::option::Option>, ())` + | - ... and the mutable borrow might be used here, when that temporary is dropped and runs the destructor for type `(Option>, ())` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-47725.rs b/src/test/ui/issues/issue-47725.rs new file mode 100644 index 0000000000..21108da500 --- /dev/null +++ b/src/test/ui/issues/issue-47725.rs @@ -0,0 +1,29 @@ +// ignore-tidy-linelength +#![warn(unused_attributes)] //~ NOTE lint level is defined here + +#[link_name = "foo"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +struct Foo; //~ NOTE not a foreign function or static + +#[link_name = "foobar"] +//~^ WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~| HELP try `#[link(name = "foobar")]` instead +extern "C" { + fn foo() -> u32; +} +//~^^^ NOTE not a foreign function or static + +#[link_name] +//~^ ERROR malformed `link_name` attribute input +//~| HELP must be of the form +//~| WARN attribute should be applied to a foreign function or static [unused_attributes] +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +//~| HELP try `#[link(name = "...")]` instead +extern "C" { + fn bar() -> u32; +} +//~^^^ NOTE not a foreign function or static + +fn main() {} diff --git a/src/test/ui/issues/issue-47725.stderr b/src/test/ui/issues/issue-47725.stderr new file mode 100644 index 0000000000..b1e8d3292e --- /dev/null +++ b/src/test/ui/issues/issue-47725.stderr @@ -0,0 +1,60 @@ +error: malformed `link_name` attribute input + --> $DIR/issue-47725.rs:18:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ help: must be of the form: `#[link_name = "name"]` + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:4:1 + | +LL | #[link_name = "foo"] + | ^^^^^^^^^^^^^^^^^^^^ +... +LL | struct Foo; + | ----------- not a foreign function or static + | +note: the lint level is defined here + --> $DIR/issue-47725.rs:2:9 + | +LL | #![warn(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:9:1 + | +LL | #[link_name = "foobar"] + | ^^^^^^^^^^^^^^^^^^^^^^^ +... +LL | / extern "C" { +LL | | fn foo() -> u32; +LL | | } + | |_- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: try `#[link(name = "foobar")]` instead + --> $DIR/issue-47725.rs:9:1 + | +LL | #[link_name = "foobar"] + | ^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attribute should be applied to a foreign function or static + --> $DIR/issue-47725.rs:18:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ +... +LL | / extern "C" { +LL | | fn bar() -> u32; +LL | | } + | |_- not a foreign function or static + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +help: try `#[link(name = "...")]` instead + --> $DIR/issue-47725.rs:18:1 + | +LL | #[link_name] + | ^^^^^^^^^^^^ + +error: aborting due to previous error; 3 warnings emitted + diff --git a/src/test/ui/issues/issue-4972.stderr b/src/test/ui/issues/issue-4972.stderr index b1947e2a9d..40db50278c 100644 --- a/src/test/ui/issues/issue-4972.stderr +++ b/src/test/ui/issues/issue-4972.stderr @@ -1,8 +1,8 @@ -error[E0033]: type `std::boxed::Box<(dyn MyTrait + 'static)>` cannot be dereferenced +error[E0033]: type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced --> $DIR/issue-4972.rs:14:25 | LL | TraitWrapper::A(box ref map) => map, - | ^^^^^^^^^^^ type `std::boxed::Box<(dyn MyTrait + 'static)>` cannot be dereferenced + | ^^^^^^^^^^^ type `Box<(dyn MyTrait + 'static)>` cannot be dereferenced error: aborting due to previous error diff --git a/src/test/ui/issues/issue-49934-errors.stderr b/src/test/ui/issues/issue-49934-errors.stderr index 8778d88d0e..3befb38a20 100644 --- a/src/test/ui/issues/issue-49934-errors.stderr +++ b/src/test/ui/issues/issue-49934-errors.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-49934-errors.rs:1:8 | LL | fn foo<#[derive(Debug)] T>() { @@ -10,7 +10,7 @@ error: expected an inert attribute, found a derive macro LL | fn foo<#[derive(Debug)] T>() { | ^^^^^ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-49934-errors.rs:5:9 | LL | #[derive(Debug)] @@ -24,3 +24,4 @@ LL | #[derive(Debug)] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs index 5b6b8f8de1..153ca0843d 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.rs @@ -1,4 +1,4 @@ fn main() { let _result = &Some(42).as_deref(); -//~^ ERROR no method named `as_deref` found for enum `std::option::Option<{integer}>` +//~^ ERROR no method named `as_deref` found for enum `Option<{integer}>` } diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr index b97131a199..a8cd98b610 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref.stderr @@ -1,12 +1,12 @@ -error[E0599]: no method named `as_deref` found for enum `std::option::Option<{integer}>` in the current scope +error[E0599]: no method named `as_deref` found for enum `Option<{integer}>` in the current scope --> $DIR/option-as_deref.rs:2:29 | LL | let _result = &Some(42).as_deref(); | ^^^^^^^^ help: there is an associated function with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::Deref` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: Deref` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs index c5fe6ea82c..11d5378fe3 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.rs @@ -1,4 +1,4 @@ fn main() { let _result = &mut Some(42).as_deref_mut(); -//~^ ERROR no method named `as_deref_mut` found for enum `std::option::Option<{integer}>` +//~^ ERROR no method named `as_deref_mut` found for enum `Option<{integer}>` } diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr index f2133c8c84..08399fcea7 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/option-as_deref_mut.stderr @@ -1,12 +1,12 @@ -error[E0599]: no method named `as_deref_mut` found for enum `std::option::Option<{integer}>` in the current scope +error[E0599]: no method named `as_deref_mut` found for enum `Option<{integer}>` in the current scope --> $DIR/option-as_deref_mut.rs:2:33 | LL | let _result = &mut Some(42).as_deref_mut(); - | ^^^^^^^^^^^^ method not found in `std::option::Option<{integer}>` + | ^^^^^^^^^^^^ method not found in `Option<{integer}>` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::DerefMut` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: DerefMut` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr index 96524c3095..933e8a0c44 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref.stderr @@ -5,8 +5,8 @@ LL | let _result = &Ok(42).as_deref(); | ^^^^^^^^ help: there is an associated function with a similar name: `as_ref` | = note: the method `as_deref` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::Deref` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: Deref` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr index 73266bc7f6..69d85126f1 100644 --- a/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr +++ b/src/test/ui/issues/issue-50264-inner-deref-trait/result-as_deref_mut.stderr @@ -5,8 +5,8 @@ LL | let _result = &mut Ok(42).as_deref_mut(); | ^^^^^^^^^^^^ method not found in `std::result::Result<{integer}, _>` | = note: the method `as_deref_mut` exists but the following trait bounds were not satisfied: - `{integer}: std::ops::DerefMut` - `<{integer} as std::ops::Deref>::Target = _` + `{integer}: DerefMut` + `<{integer} as Deref>::Target = _` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-50480.stderr b/src/test/ui/issues/issue-50480.stderr index dfcac12817..50691f1f57 100644 --- a/src/test/ui/issues/issue-50480.stderr +++ b/src/test/ui/issues/issue-50480.stderr @@ -16,7 +16,7 @@ error[E0277]: `i32` is not an iterator LL | struct Foo(NotDefined, ::Item, Vec, String); | ^^^^^^^^^^^^^^^^^^^^^^^ `i32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i32` + = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` error[E0204]: the trait `Copy` may not be implemented for this type diff --git a/src/test/ui/issues/issue-50582.stderr b/src/test/ui/issues/issue-50582.stderr index 13f6c4d763..4f531460e6 100644 --- a/src/test/ui/issues/issue-50582.stderr +++ b/src/test/ui/issues/issue-50582.stderr @@ -10,7 +10,7 @@ error[E0277]: cannot add `()` to `{integer}` LL | Vec::<[(); 1 + for x in 0..1 {}]>::new(); | ^ no implementation for `{integer} + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `{integer}` + = help: the trait `Add<()>` is not implemented for `{integer}` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-5100.rs b/src/test/ui/issues/issue-5100.rs index 71dd237cad..5e926fabe2 100644 --- a/src/test/ui/issues/issue-5100.rs +++ b/src/test/ui/issues/issue-5100.rs @@ -33,7 +33,7 @@ fn main() { box (true, false) => () //~^ ERROR mismatched types //~| expected tuple `(bool, bool)` -//~| found struct `std::boxed::Box<_>` +//~| found struct `Box<_>` } match (true, false) { diff --git a/src/test/ui/issues/issue-5100.stderr b/src/test/ui/issues/issue-5100.stderr index a89980964c..de71e1d1a6 100644 --- a/src/test/ui/issues/issue-5100.stderr +++ b/src/test/ui/issues/issue-5100.stderr @@ -40,10 +40,10 @@ error[E0308]: mismatched types LL | match (true, false) { | ------------- this expression has type `(bool, bool)` LL | box (true, false) => () - | ^^^^^^^^^^^^^^^^^ expected tuple, found struct `std::boxed::Box` + | ^^^^^^^^^^^^^^^^^ expected tuple, found struct `Box` | = note: expected tuple `(bool, bool)` - found struct `std::boxed::Box<_>` + found struct `Box<_>` error[E0308]: mismatched types --> $DIR/issue-5100.rs:40:9 diff --git a/src/test/ui/issues/issue-51154.rs b/src/test/ui/issues/issue-51154.rs new file mode 100644 index 0000000000..12903f7901 --- /dev/null +++ b/src/test/ui/issues/issue-51154.rs @@ -0,0 +1,6 @@ +fn foo() { + let _: Box = Box::new(|| ()); + //~^ ERROR mismatched types +} + +fn main() {} diff --git a/src/test/ui/issues/issue-51154.stderr b/src/test/ui/issues/issue-51154.stderr new file mode 100644 index 0000000000..3c3428f309 --- /dev/null +++ b/src/test/ui/issues/issue-51154.stderr @@ -0,0 +1,15 @@ +error[E0308]: mismatched types + --> $DIR/issue-51154.rs:2:30 + | +LL | fn foo() { + | - this type parameter +LL | let _: Box = Box::new(|| ()); + | ^^^^^ expected type parameter `F`, found closure + | + = note: expected type parameter `F` + found closure `[closure@$DIR/issue-51154.rs:2:30: 2:35]` + = help: every closure has a distinct type and so could not always match the caller-chosen type of parameter `F` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-5216.stderr b/src/test/ui/issues/issue-5216.stderr index 21d9333735..7a1f42adf6 100644 --- a/src/test/ui/issues/issue-5216.stderr +++ b/src/test/ui/issues/issue-5216.stderr @@ -2,18 +2,18 @@ error[E0308]: mismatched types --> $DIR/issue-5216.rs:3:21 | LL | pub static C: S = S(f); - | ^ expected struct `std::boxed::Box`, found fn item + | ^ expected struct `Box`, found fn item | - = note: expected struct `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` + = note: expected struct `Box<(dyn FnMut() + 'static)>` found fn item `fn() {f}` error[E0308]: mismatched types --> $DIR/issue-5216.rs:8:19 | LL | pub static D: T = g; - | ^ expected struct `std::boxed::Box`, found fn item + | ^ expected struct `Box`, found fn item | - = note: expected struct `std::boxed::Box<(dyn std::ops::FnMut() + 'static)>` + = note: expected struct `Box<(dyn FnMut() + 'static)>` found fn item `fn() {g}` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-52262.stderr b/src/test/ui/issues/issue-52262.stderr index 7312976c80..c0bde4b232 100644 --- a/src/test/ui/issues/issue-52262.stderr +++ b/src/test/ui/issues/issue-52262.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `*key` which is behind a shared reference --> $DIR/issue-52262.rs:16:35 | LL | String::from_utf8(*key).unwrap() - | ^^^^ move occurs because `*key` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^ move occurs because `*key` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/issues/issue-53348.rs b/src/test/ui/issues/issue-53348.rs index bbfdd9c538..65f4656b02 100644 --- a/src/test/ui/issues/issue-53348.rs +++ b/src/test/ui/issues/issue-53348.rs @@ -9,7 +9,7 @@ fn main() { for i in v { a = *i.to_string(); //~^ ERROR mismatched types - //~| NOTE expected struct `std::string::String`, found `str` + //~| NOTE expected struct `String`, found `str` v2.push(a); } } diff --git a/src/test/ui/issues/issue-53348.stderr b/src/test/ui/issues/issue-53348.stderr index 433fe40ea0..8f50026124 100644 --- a/src/test/ui/issues/issue-53348.stderr +++ b/src/test/ui/issues/issue-53348.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-53348.rs:10:13 | LL | a = *i.to_string(); - | ^^^^^^^^^^^^^^ expected struct `std::string::String`, found `str` + | ^^^^^^^^^^^^^^ expected struct `String`, found `str` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-53692.stderr b/src/test/ui/issues/issue-53692.stderr index b83fb346b1..09c78da54b 100644 --- a/src/test/ui/issues/issue-53692.stderr +++ b/src/test/ui/issues/issue-53692.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | let items_clone: Vec = ref_items.clone(); | -------- ^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::vec::Vec`, found `&[i32]` + | | expected struct `Vec`, found `&[i32]` | | help: try using a conversion method: `ref_items.to_vec()` | expected due to this | - = note: expected struct `std::vec::Vec` + = note: expected struct `Vec` found reference `&[i32]` error[E0308]: mismatched types @@ -17,7 +17,7 @@ error[E0308]: mismatched types LL | let string: String = s.clone(); | ------ ^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&str` + | | expected struct `String`, found `&str` | | help: try using a conversion method: `s.to_string()` | expected due to this diff --git a/src/test/ui/issues/issue-54044.rs b/src/test/ui/issues/issue-54044.rs new file mode 100644 index 0000000000..3f0b8bc5e3 --- /dev/null +++ b/src/test/ui/issues/issue-54044.rs @@ -0,0 +1,14 @@ +// ignore-tidy-linelength +#![deny(unused_attributes)] //~ NOTE lint level is defined here + +#[cold] +//~^ ERROR attribute should be applied to a function +//~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! +struct Foo; //~ NOTE not a function + +fn main() { + #[cold] + //~^ ERROR attribute should be applied to a function + //~| WARN this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + 5; //~ NOTE not a function +} diff --git a/src/test/ui/issues/issue-54044.stderr b/src/test/ui/issues/issue-54044.stderr new file mode 100644 index 0000000000..a13e84bbee --- /dev/null +++ b/src/test/ui/issues/issue-54044.stderr @@ -0,0 +1,29 @@ +error: attribute should be applied to a function + --> $DIR/issue-54044.rs:4:1 + | +LL | #[cold] + | ^^^^^^^ +... +LL | struct Foo; + | ----------- not a function + | +note: the lint level is defined here + --> $DIR/issue-54044.rs:2:9 + | +LL | #![deny(unused_attributes)] + | ^^^^^^^^^^^^^^^^^ + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: attribute should be applied to a function + --> $DIR/issue-54044.rs:10:5 + | +LL | #[cold] + | ^^^^^^^ +... +LL | 5; + | - not a function + | + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-54062.rs b/src/test/ui/issues/issue-54062.rs index 495b7343f2..093d6601d4 100644 --- a/src/test/ui/issues/issue-54062.rs +++ b/src/test/ui/issues/issue-54062.rs @@ -7,7 +7,6 @@ struct Test { fn main() {} fn testing(test: Test) { - let _ = test.comps.inner.lock().unwrap(); - //~^ ERROR: field `inner` of struct `std::sync::Mutex` is private - //~| ERROR: no method named `unwrap` found + let _ = test.comps.inner.try_lock(); + //~^ ERROR: field `inner` of struct `Mutex` is private } diff --git a/src/test/ui/issues/issue-54062.stderr b/src/test/ui/issues/issue-54062.stderr index f9aef08c35..5361ee1d34 100644 --- a/src/test/ui/issues/issue-54062.stderr +++ b/src/test/ui/issues/issue-54062.stderr @@ -1,16 +1,9 @@ -error[E0616]: field `inner` of struct `std::sync::Mutex` is private +error[E0616]: field `inner` of struct `Mutex` is private --> $DIR/issue-54062.rs:10:24 | -LL | let _ = test.comps.inner.lock().unwrap(); +LL | let _ = test.comps.inner.try_lock(); | ^^^^^ private field -error[E0599]: no method named `unwrap` found for struct `std::sys_common::mutex::MutexGuard<'_>` in the current scope - --> $DIR/issue-54062.rs:10:37 - | -LL | let _ = test.comps.inner.lock().unwrap(); - | ^^^^^^ method not found in `std::sys_common::mutex::MutexGuard<'_>` +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0599, E0616. -For more information about an error, try `rustc --explain E0599`. +For more information about this error, try `rustc --explain E0616`. diff --git a/src/test/ui/issues/issue-54348.stderr b/src/test/ui/issues/issue-54348.stderr index 6b67125e36..eb85f34984 100644 --- a/src/test/ui/issues/issue-54348.stderr +++ b/src/test/ui/issues/issue-54348.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/issue-54348.rs:5:5 | LL | [1][1.5 as usize]; - | ^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 | = note: `#[deny(unconditional_panic)]` on by default @@ -10,7 +10,7 @@ error: this operation will panic at runtime --> $DIR/issue-54348.rs:6:5 | LL | [1][1u64 as usize]; - | ^^^^^^^^^^^^^^^^^^ index out of bounds: the len is 1 but the index is 1 + | ^^^^^^^^^^^^^^^^^^ index out of bounds: the length is 1 but the index is 1 error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-54410.stderr b/src/test/ui/issues/issue-54410.stderr index 9205a518c8..516c59afb3 100644 --- a/src/test/ui/issues/issue-54410.stderr +++ b/src/test/ui/issues/issue-54410.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i8]` cannot be known at compilation LL | pub static mut symbol: [i8]; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i8]` + = help: the trait `Sized` is not implemented for `[i8]` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-55796.stderr b/src/test/ui/issues/issue-55796.stderr index 6bfb7af544..1aa0050336 100644 --- a/src/test/ui/issues/issue-55796.stderr +++ b/src/test/ui/issues/issue-55796.stderr @@ -9,7 +9,7 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the tra | LL | pub trait Graph<'a> { | ^^ -note: ...so that the type `std::iter::Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds +note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:16:40: 16:54]>` will meet its required lifetime bounds --> $DIR/issue-55796.rs:16:9 | LL | Box::new(self.out_edges(u).map(|e| e.target())) @@ -20,8 +20,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.out_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `Box<(dyn Iterator>::Node> + 'static)>` + found `Box>::Node>>` error[E0495]: cannot infer an appropriate lifetime due to conflicting requirements --> $DIR/issue-55796.rs:21:9 @@ -34,7 +34,7 @@ note: first, the lifetime cannot outlive the lifetime `'a` as defined on the tra | LL | pub trait Graph<'a> { | ^^ -note: ...so that the type `std::iter::Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds +note: ...so that the type `Map<>::EdgesIter, [closure@$DIR/issue-55796.rs:21:39: 21:53]>` will meet its required lifetime bounds --> $DIR/issue-55796.rs:21:9 | LL | Box::new(self.in_edges(u).map(|e| e.target())) @@ -45,8 +45,8 @@ note: ...so that the expression is assignable | LL | Box::new(self.in_edges(u).map(|e| e.target())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn std::iter::Iterator>::Node> + 'static)>` - found `std::boxed::Box>::Node>>` + = note: expected `Box<(dyn Iterator>::Node> + 'static)>` + found `Box>::Node>>` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-56175.stderr b/src/test/ui/issues/issue-56175.stderr index c0799db7c1..ee3f609f47 100644 --- a/src/test/ui/issues/issue-56175.stderr +++ b/src/test/ui/issues/issue-56175.stderr @@ -1,8 +1,8 @@ -error[E0599]: no method named `trait_method` found for struct `reexported_trait::FooStruct` in the current scope +error[E0599]: no method named `trait_method` found for struct `FooStruct` in the current scope --> $DIR/issue-56175.rs:5:33 | LL | reexported_trait::FooStruct.trait_method(); - | ^^^^^^^^^^^^ method not found in `reexported_trait::FooStruct` + | ^^^^^^^^^^^^ method not found in `FooStruct` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: @@ -10,11 +10,11 @@ help: the following trait is implemented but not in scope; perhaps add a `use` f LL | use reexported_trait::Trait; | -error[E0599]: no method named `trait_method_b` found for struct `reexported_trait::FooStruct` in the current scope +error[E0599]: no method named `trait_method_b` found for struct `FooStruct` in the current scope --> $DIR/issue-56175.rs:7:33 | LL | reexported_trait::FooStruct.trait_method_b(); - | ^^^^^^^^^^^^^^ method not found in `reexported_trait::FooStruct` + | ^^^^^^^^^^^^^^ method not found in `FooStruct` | = help: items from traits can only be used if the trait is in scope help: the following trait is implemented but not in scope; perhaps add a `use` for it: diff --git a/src/test/ui/issues/issue-56806.stderr b/src/test/ui/issues/issue-56806.stderr index a4f9aadcfe..f164fd0c5d 100644 --- a/src/test/ui/issues/issue-56806.stderr +++ b/src/test/ui/issues/issue-56806.stderr @@ -1,4 +1,4 @@ -error[E0307]: invalid `self` parameter type: std::boxed::Box<(dyn Trait + 'static)> +error[E0307]: invalid `self` parameter type: Box<(dyn Trait + 'static)> --> $DIR/issue-56806.rs:2:34 | LL | fn dyn_instead_of_self(self: Box); diff --git a/src/test/ui/issues/issue-56943.stderr b/src/test/ui/issues/issue-56943.stderr index 6caf974809..74ed5ec0fb 100644 --- a/src/test/ui/issues/issue-56943.stderr +++ b/src/test/ui/issues/issue-56943.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-56943.rs:6:29 | LL | let _: issue_56943::S = issue_56943::S2; - | -------------- ^^^^^^^^^^^^^^^ expected struct `issue_56943::S`, found struct `issue_56943::S2` + | -------------- ^^^^^^^^^^^^^^^ expected struct `S`, found struct `S2` | | | expected due to this diff --git a/src/test/ui/issues/issue-57741-1.stderr b/src/test/ui/issues/issue-57741-1.stderr index a4f1ac9482..789a1f44db 100644 --- a/src/test/ui/issues/issue-57741-1.stderr +++ b/src/test/ui/issues/issue-57741-1.stderr @@ -2,22 +2,22 @@ error[E0308]: mismatched types --> $DIR/issue-57741-1.rs:14:9 | LL | let y = match x { - | - this expression has type `std::boxed::Box` + | - this expression has type `Box` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error[E0308]: mismatched types --> $DIR/issue-57741-1.rs:14:22 | LL | let y = match x { - | - this expression has type `std::boxed::Box` + | - this expression has type `Box` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-57741.stderr b/src/test/ui/issues/issue-57741.stderr index 6f9e5b08a8..cd277f20ef 100644 --- a/src/test/ui/issues/issue-57741.stderr +++ b/src/test/ui/issues/issue-57741.stderr @@ -4,12 +4,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | T::A(a) | T::B(a) => a, - | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` + | ^^^^^^^ expected struct `Box`, found enum `T` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `T` error[E0308]: mismatched types @@ -18,12 +18,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | T::A(a) | T::B(a) => a, - | ^^^^^^^ expected struct `std::boxed::Box`, found enum `T` + | ^^^^^^^ expected struct `Box`, found enum `T` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `T` error[E0308]: mismatched types @@ -32,12 +32,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error[E0308]: mismatched types @@ -46,12 +46,12 @@ error[E0308]: mismatched types LL | let y = match x { | - | | - | this expression has type `std::boxed::Box` + | this expression has type `Box` | help: consider dereferencing the boxed value: `*x` LL | S::A { a } | S::B { b: a } => a, - | ^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found enum `S` + | ^^^^^^^^^^^^^ expected struct `Box`, found enum `S` | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found enum `S` error: aborting due to 4 previous errors diff --git a/src/test/ui/issues/issue-57843.stderr b/src/test/ui/issues/issue-57843.stderr index 57b206d7bf..01edb9507a 100644 --- a/src/test/ui/issues/issue-57843.stderr +++ b/src/test/ui/issues/issue-57843.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | Foo(Box::new(|_| ())); | ^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&'a bool,)>` - found type `std::ops::FnOnce<(&bool,)>` + = note: expected type `FnOnce<(&'a bool,)>` + found type `FnOnce<(&bool,)>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-58344.rs b/src/test/ui/issues/issue-58344.rs index 99b656d74f..9b184e296a 100644 --- a/src/test/ui/issues/issue-58344.rs +++ b/src/test/ui/issues/issue-58344.rs @@ -40,8 +40,8 @@ fn add_generic, B>(lhs: A, rhs: B) -> Either< fn add_one( value: u32, ) -> Either>::Output>, impl Trait<>::Output>> { - //~^ ERROR: the trait bound `impl Trait<::Output>: Trait` - //~| ERROR: the trait bound `impl Trait<::Output>: Trait` + //~^ ERROR: the trait bound `impl Trait<::Output>: Trait` + //~| ERROR: the trait bound `impl Trait<::Output>: Trait` add_generic(value, 1u32) } diff --git a/src/test/ui/issues/issue-58344.stderr b/src/test/ui/issues/issue-58344.stderr index e0c196e518..ade85d8b01 100644 --- a/src/test/ui/issues/issue-58344.stderr +++ b/src/test/ui/issues/issue-58344.stderr @@ -1,22 +1,22 @@ -error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied +error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied --> $DIR/issue-58344.rs:42:13 | LL | ) -> Either>::Output>, impl Trait<>::Output>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` ... LL | add_generic(value, 1u32) - | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` + | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` | = note: the return type of a function must have a statically known size -error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied +error[E0277]: the trait bound `impl Trait<::Output>: Trait` is not satisfied --> $DIR/issue-58344.rs:42:52 | LL | ) -> Either>::Output>, impl Trait<>::Output>> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `impl Trait<::Output>` ... LL | add_generic(value, 1u32) - | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` + | ------------------------ this returned value is of type `Either::Output>, impl Trait<::Output>>` | = note: the return type of a function must have a statically known size diff --git a/src/test/ui/issues/issue-5883.stderr b/src/test/ui/issues/issue-5883.stderr index 897984d0ae..8d639304ab 100644 --- a/src/test/ui/issues/issue-5883.stderr +++ b/src/test/ui/issues/issue-5883.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `(dyn A + 'static)` cannot be known at LL | fn new_struct(r: dyn A + 'static) | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` + = help: the trait `Sized` is not implemented for `(dyn A + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | @@ -20,7 +20,7 @@ LL | LL | Struct { r: r } | --------------- this returned value is of type `Struct` | - = help: within `Struct`, the trait `std::marker::Sized` is not implemented for `(dyn A + 'static)` + = help: within `Struct`, the trait `Sized` is not implemented for `(dyn A + 'static)` = note: required because it appears within the type `Struct` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/issues/issue-59488.rs b/src/test/ui/issues/issue-59488.rs index 6fa9961f26..384501e3e5 100644 --- a/src/test/ui/issues/issue-59488.rs +++ b/src/test/ui/issues/issue-59488.rs @@ -29,6 +29,6 @@ fn main() { let i = Foo::Bar; assert_eq!(Foo::Bar, i); //~^ ERROR binary operation `==` cannot be applied to type `fn(usize) -> Foo {Foo::Bar}` [E0369] - //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` [E0277] - //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` [E0277] + //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` [E0277] + //~| ERROR `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` [E0277] } diff --git a/src/test/ui/issues/issue-59488.stderr b/src/test/ui/issues/issue-59488.stderr index 58f1376b19..3b10491a8a 100644 --- a/src/test/ui/issues/issue-59488.stderr +++ b/src/test/ui/issues/issue-59488.stderr @@ -79,25 +79,25 @@ LL | assert_eq!(Foo::Bar, i); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` +error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $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 `std::fmt::Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn(usize) -> Foo {Foo::Bar}` + = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = note: required because of the requirements on the impl of `Debug` for `&fn(usize) -> Foo {Foo::Bar}` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `std::fmt::Debug` +error[E0277]: `fn(usize) -> Foo {Foo::Bar}` doesn't implement `Debug` --> $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 `std::fmt::Debug` + | ^^^^^^^^^^^^^^^^^^^^^^^^ `fn(usize) -> Foo {Foo::Bar}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn(usize) -> Foo {Foo::Bar}` + = help: the trait `Debug` is not implemented for `fn(usize) -> Foo {Foo::Bar}` + = note: required because of the requirements on the impl of `Debug` for `&fn(usize) -> Foo {Foo::Bar}` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-60218.stderr b/src/test/ui/issues/issue-60218.stderr index 77b9d9c4aa..a2b2fdd4fd 100644 --- a/src/test/ui/issues/issue-60218.stderr +++ b/src/test/ui/issues/issue-60218.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `for<'t> ::IntoIter, _> as std::iter::Iterator>::Item: Foo` is not satisfied +error[E0277]: the trait bound `for<'t> ::IntoIter, _> as Iterator>::Item: Foo` is not satisfied --> $DIR/issue-60218.rs:18:5 | LL | pub fn trigger_error(iterable: I, functor: F) @@ -8,7 +8,7 @@ LL | for<'t> ::IntoIter, F> as Iterator>::Item: Foo, | --- required by this bound in `trigger_error` ... LL | trigger_error(vec![], |x: &u32| x) - | ^^^^^^^^^^^^^ the trait `for<'t> Foo` is not implemented for `::IntoIter, _> as std::iter::Iterator>::Item` + | ^^^^^^^^^^^^^ the trait `for<'t> Foo` is not implemented for `::IntoIter, _> as Iterator>::Item` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-61106.stderr b/src/test/ui/issues/issue-61106.stderr index 163aa816ab..2d841d28ee 100644 --- a/src/test/ui/issues/issue-61106.stderr +++ b/src/test/ui/issues/issue-61106.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | foo(x.clone()); | ^^^^^^^^^ | | - | expected `&str`, found struct `std::string::String` + | expected `&str`, found struct `String` | help: consider borrowing here: `&x` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-61108.stderr b/src/test/ui/issues/issue-61108.stderr index d7c2bbf917..d6c289cbd6 100644 --- a/src/test/ui/issues/issue-61108.stderr +++ b/src/test/ui/issues/issue-61108.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `bad_letters` --> $DIR/issue-61108.rs:6:5 | LL | let mut bad_letters = vec!['e', 't', 'o', 'i']; - | --------------- move occurs because `bad_letters` has type `std::vec::Vec`, which does not implement the `Copy` trait + | --------------- move occurs because `bad_letters` has type `Vec`, which does not implement the `Copy` trait LL | for l in bad_letters { | ----------- | | diff --git a/src/test/ui/issues/issue-64559.stderr b/src/test/ui/issues/issue-64559.stderr index e942a1aeba..5b97e21b88 100644 --- a/src/test/ui/issues/issue-64559.stderr +++ b/src/test/ui/issues/issue-64559.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `orig` --> $DIR/issue-64559.rs:4:20 | LL | let orig = vec![true]; - | ---- move occurs because `orig` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ---- move occurs because `orig` has type `Vec`, which does not implement the `Copy` trait LL | for _val in orig {} | ---- | | diff --git a/src/test/ui/issues/issue-6458-4.stderr b/src/test/ui/issues/issue-6458-4.stderr index 6537867bbf..00ebff9007 100644 --- a/src/test/ui/issues/issue-6458-4.stderr +++ b/src/test/ui/issues/issue-6458-4.stderr @@ -8,7 +8,7 @@ LL | fn foo(b: bool) -> Result { LL | Err("bar".to_string()); | - help: consider removing this semicolon | - = note: expected enum `std::result::Result` + = note: expected enum `std::result::Result` found unit type `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-65611.stderr b/src/test/ui/issues/issue-65611.stderr index 20e2ba144d..e3c005a059 100644 --- a/src/test/ui/issues/issue-65611.stderr +++ b/src/test/ui/issues/issue-65611.stderr @@ -5,7 +5,7 @@ LL | let x = buffer.last().unwrap().0.clone(); | -------^^^^-- | | | | | cannot infer type for type parameter `T` - | this method call resolves to `std::option::Option<&T>` + | this method call resolves to `Option<&T>` | = note: type must be known at this point diff --git a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr index 83d8770b2e..de0e78ac20 100644 --- a/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr +++ b/src/test/ui/issues/issue-65634-raw-ident-suggestion.stderr @@ -4,12 +4,12 @@ error[E0034]: multiple applicable items in scope LL | r#fn {}.r#struct(); | ^^^^^^^^ multiple `r#struct` found | -note: candidate #1 is defined in an impl of the trait `async` for the type `r#fn` +note: candidate #1 is defined in an impl of the trait `async` for the type `fn` --> $DIR/issue-65634-raw-ident-suggestion.rs:4:5 | LL | fn r#struct(&self) { | ^^^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `await` for the type `r#fn` +note: candidate #2 is defined in an impl of the trait `await` for the type `fn` --> $DIR/issue-65634-raw-ident-suggestion.rs:10:5 | LL | fn r#struct(&self) { diff --git a/src/test/ui/issues/issue-65673.stderr b/src/test/ui/issues/issue-65673.stderr index fef64ebf2d..aa43ac9414 100644 --- a/src/test/ui/issues/issue-65673.stderr +++ b/src/test/ui/issues/issue-65673.stderr @@ -9,7 +9,7 @@ LL | type Ctx; LL | type Ctx = dyn Alias; | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Trait + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Trait + 'static)` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr index 8e7ee97e0b..a08531000b 100644 --- a/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr +++ b/src/test/ui/issues/issue-66923-show-error-for-correct-call.stderr @@ -1,18 +1,18 @@ -error[E0277]: a value of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` +error[E0277]: a value of type `Vec` cannot be built from an iterator over elements of type `&f64` --> $DIR/issue-66923-show-error-for-correct-call.rs:8:39 | LL | let x2: Vec = x1.into_iter().collect(); - | ^^^^^^^ value of type `std::vec::Vec` cannot be built from `std::iter::Iterator` + | ^^^^^^^ value of type `Vec` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec` + = help: the trait `FromIterator<&f64>` is not implemented for `Vec` -error[E0277]: a value of type `std::vec::Vec` cannot be built from an iterator over elements of type `&f64` +error[E0277]: a value of type `Vec` cannot be built from an iterator over elements of type `&f64` --> $DIR/issue-66923-show-error-for-correct-call.rs:12:29 | LL | let x3 = x1.into_iter().collect::>(); - | ^^^^^^^ value of type `std::vec::Vec` cannot be built from `std::iter::Iterator` + | ^^^^^^^ value of type `Vec` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator<&f64>` is not implemented for `std::vec::Vec` + = help: the trait `FromIterator<&f64>` is not implemented for `Vec` error: aborting due to 2 previous errors diff --git a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr index 3330d60242..036a9300a1 100644 --- a/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr +++ b/src/test/ui/issues/issue-67039-unsound-pin-partialeq.stderr @@ -1,12 +1,12 @@ -error[E0271]: type mismatch resolving ` as std::ops::Deref>::Target == std::rc::Rc` +error[E0271]: type mismatch resolving ` as Deref>::Target == Rc` --> $DIR/issue-67039-unsound-pin-partialeq.rs:25:29 | LL | let _ = Pin::new(Apple) == Rc::pin(Apple); - | ^^ expected struct `Apple`, found struct `std::rc::Rc` + | ^^ expected struct `Apple`, found struct `Rc` | = note: expected type `Apple` - found struct `std::rc::Rc` - = note: required because of the requirements on the impl of `std::cmp::PartialEq>>` for `std::pin::Pin` + found struct `Rc` + = note: required because of the requirements on the impl of `PartialEq>>` for `Pin` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-67552.rs b/src/test/ui/issues/issue-67552.rs index b0fcb74764..98192dae20 100644 --- a/src/test/ui/issues/issue-67552.rs +++ b/src/test/ui/issues/issue-67552.rs @@ -1,4 +1,5 @@ // build-fail +// normalize-stderr-test: ".nll/" -> "/" fn main() { rec(Empty); diff --git a/src/test/ui/issues/issue-67552.stderr b/src/test/ui/issues/issue-67552.stderr index f3e73399b5..cf05a72e92 100644 --- a/src/test/ui/issues/issue-67552.stderr +++ b/src/test/ui/issues/issue-67552.stderr @@ -1,16 +1,17 @@ error: reached the recursion limit while instantiating `rec::<&mut &mut &mut &mut &mut &... &mut &mut &mut &mut &mut Empty>` - --> $DIR/issue-67552.rs:27:9 + --> $DIR/issue-67552.rs:28:9 | LL | rec(identity(&mut it)) | ^^^^^^^^^^^^^^^^^^^^^^ | note: `rec` defined here - --> $DIR/issue-67552.rs:20:1 + --> $DIR/issue-67552.rs:21:1 | LL | / fn rec(mut it: T) LL | | where LL | | T: Iterator, | |________________^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-67552/issue-67552.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/issues/issue-69725.stderr b/src/test/ui/issues/issue-69725.stderr index 20420d37b3..3f70dbcc2a 100644 --- a/src/test/ui/issues/issue-69725.stderr +++ b/src/test/ui/issues/issue-69725.stderr @@ -1,25 +1,25 @@ -error[E0599]: no method named `clone` found for struct `issue_69725::Struct` in the current scope +error[E0599]: no method named `clone` found for struct `Struct` in the current scope --> $DIR/issue-69725.rs:7:32 | LL | let _ = Struct::::new().clone(); - | ^^^^^ method not found in `issue_69725::Struct` + | ^^^^^ method not found in `Struct` | ::: $DIR/auxiliary/issue-69725.rs:2:1 | LL | pub struct Struct(A); - | ------------------------ doesn't satisfy `issue_69725::Struct: std::clone::Clone` + | ------------------------ doesn't satisfy `Struct: Clone` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `A: std::clone::Clone` - which is required by `issue_69725::Struct: std::clone::Clone` + `A: Clone` + which is required by `Struct: Clone` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-7013.rs b/src/test/ui/issues/issue-7013.rs index 3d72b67e39..c1f400b330 100644 --- a/src/test/ui/issues/issue-7013.rs +++ b/src/test/ui/issues/issue-7013.rs @@ -24,5 +24,5 @@ struct A { fn main() { let a = A {v: box B{v: None} as Box}; - //~^ ERROR `std::rc::Rc>` cannot be sent between threads safely + //~^ ERROR `Rc>` cannot be sent between threads safely } diff --git a/src/test/ui/issues/issue-7013.stderr b/src/test/ui/issues/issue-7013.stderr index f2668d3312..5f3156a540 100644 --- a/src/test/ui/issues/issue-7013.stderr +++ b/src/test/ui/issues/issue-7013.stderr @@ -1,13 +1,13 @@ -error[E0277]: `std::rc::Rc>` cannot be sent between threads safely +error[E0277]: `Rc>` cannot be sent between threads safely --> $DIR/issue-7013.rs:26:19 | LL | let a = A {v: box B{v: None} as Box}; - | ^^^^^^^^^^^^^^ `std::rc::Rc>` cannot be sent between threads safely + | ^^^^^^^^^^^^^^ `Rc>` cannot be sent between threads safely | - = help: within `B`, the trait `std::marker::Send` is not implemented for `std::rc::Rc>` - = note: required because it appears within the type `std::option::Option>>` + = help: within `B`, the trait `Send` is not implemented for `Rc>` + = note: required because it appears within the type `Option>>` = note: required because it appears within the type `B` - = note: required for the cast to the object type `dyn Foo + std::marker::Send` + = note: required for the cast to the object type `dyn Foo + Send` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-70381.rs b/src/test/ui/issues/issue-70381.rs new file mode 100644 index 0000000000..3df8277b87 --- /dev/null +++ b/src/test/ui/issues/issue-70381.rs @@ -0,0 +1,6 @@ +// Test that multi-byte unicode characters with missing parameters do not ICE. + +fn main() { + println!("\r¡{}") + //~^ ERROR 1 positional argument in format string +} diff --git a/src/test/ui/issues/issue-70381.stderr b/src/test/ui/issues/issue-70381.stderr new file mode 100644 index 0000000000..96b8e65699 --- /dev/null +++ b/src/test/ui/issues/issue-70381.stderr @@ -0,0 +1,8 @@ +error: 1 positional argument in format string, but no arguments were given + --> $DIR/issue-70381.rs:4:16 + | +LL | println!("\r¡{}") + | ^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-7061.rs b/src/test/ui/issues/issue-7061.rs index ef61eac7ba..8a6ee920a3 100644 --- a/src/test/ui/issues/issue-7061.rs +++ b/src/test/ui/issues/issue-7061.rs @@ -3,7 +3,7 @@ struct BarStruct; impl<'a> BarStruct { fn foo(&'a mut self) -> Box { self } //~^ ERROR mismatched types - //~| expected struct `std::boxed::Box` + //~| expected struct `Box` //~| found mutable reference `&'a mut BarStruct` } diff --git a/src/test/ui/issues/issue-7061.stderr b/src/test/ui/issues/issue-7061.stderr index bf1450ca76..27034378d3 100644 --- a/src/test/ui/issues/issue-7061.stderr +++ b/src/test/ui/issues/issue-7061.stderr @@ -2,11 +2,11 @@ error[E0308]: mismatched types --> $DIR/issue-7061.rs:4:46 | LL | fn foo(&'a mut self) -> Box { self } - | -------------- ^^^^ expected struct `std::boxed::Box`, found `&mut BarStruct` + | -------------- ^^^^ expected struct `Box`, found `&mut BarStruct` | | - | expected `std::boxed::Box` because of return type + | expected `Box` because of return type | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found mutable reference `&'a mut BarStruct` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr index 467c15cc52..f5a56d7553 100644 --- a/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr +++ b/src/test/ui/issues/issue-70724-add_type_neq_err_label-unwrap.stderr @@ -20,18 +20,18 @@ LL | assert_eq!(a, 0); found type `i32` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `fn() -> i32 {a}` doesn't implement `std::fmt::Debug` +error[E0277]: `fn() -> i32 {a}` doesn't implement `Debug` --> $DIR/issue-70724-add_type_neq_err_label-unwrap.rs:6:5 | LL | fn a() -> i32 { | - consider calling this function ... LL | assert_eq!(a, 0); - | ^^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^^^^^^^^ `fn() -> i32 {a}` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `fn() -> i32 {a}` + = help: the trait `Debug` is not implemented for `fn() -> i32 {a}` = help: use parentheses to call the function: `a()` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&fn() -> i32 {a}` + = note: required because of the requirements on the impl of `Debug` for `&fn() -> i32 {a}` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/issues/issue-7092.rs b/src/test/ui/issues/issue-7092.rs index 09fa6c5250..85bfbf90d9 100644 --- a/src/test/ui/issues/issue-7092.rs +++ b/src/test/ui/issues/issue-7092.rs @@ -5,9 +5,9 @@ fn foo(x: Whatever) { match x { Some(field) => //~^ ERROR mismatched types -//~| expected enum `Whatever`, found enum `std::option::Option` +//~| expected enum `Whatever`, found enum `Option` //~| expected enum `Whatever` -//~| found enum `std::option::Option<_>` +//~| found enum `Option<_>` field.access(), } } diff --git a/src/test/ui/issues/issue-7092.stderr b/src/test/ui/issues/issue-7092.stderr index 590dd40c65..59e8d75e23 100644 --- a/src/test/ui/issues/issue-7092.stderr +++ b/src/test/ui/issues/issue-7092.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | match x { | - this expression has type `Whatever` LL | Some(field) => - | ^^^^^^^^^^^ expected enum `Whatever`, found enum `std::option::Option` + | ^^^^^^^^^^^ expected enum `Whatever`, found enum `Option` | = note: expected enum `Whatever` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-71036.rs b/src/test/ui/issues/issue-71036.rs index 01d1cff42e..3d2df6fe99 100644 --- a/src/test/ui/issues/issue-71036.rs +++ b/src/test/ui/issues/issue-71036.rs @@ -9,8 +9,8 @@ struct Foo<'a, T: ?Sized> { } impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn> for Foo<'a, T> {} -//~^ ERROR the trait bound `&'a T: std::marker::Unsize<&'a U>` is not satisfied -//~| NOTE the trait `std::marker::Unsize<&'a U>` is not implemented for `&'a T` +//~^ ERROR the trait bound `&'a T: Unsize<&'a U>` is not satisfied +//~| NOTE the trait `Unsize<&'a U>` is not implemented for `&'a T` //~| NOTE all implementations of `Unsize` are provided automatically by the compiler //~| NOTE required because of the requirements on the impl diff --git a/src/test/ui/issues/issue-71036.stderr b/src/test/ui/issues/issue-71036.stderr index 57cf246894..db1f694666 100644 --- a/src/test/ui/issues/issue-71036.stderr +++ b/src/test/ui/issues/issue-71036.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `&'a T: std::marker::Unsize<&'a U>` is not satisfied +error[E0277]: the trait bound `&'a T: Unsize<&'a U>` is not satisfied --> $DIR/issue-71036.rs:11:1 | LL | impl<'a, T: ?Sized + Unsize, U: ?Sized> DispatchFromDyn> for Foo<'a, T> {} - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Unsize<&'a U>` is not implemented for `&'a T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Unsize<&'a U>` is not implemented for `&'a T` | = note: all implementations of `Unsize` are provided automatically by the compiler, see for more information - = note: required because of the requirements on the impl of `std::ops::DispatchFromDyn<&'a &'a U>` for `&'a &'a T` + = note: required because of the requirements on the impl of `DispatchFromDyn<&'a &'a U>` for `&'a &'a T` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-71584.stderr b/src/test/ui/issues/issue-71584.stderr index c162d338a9..1c216e6498 100644 --- a/src/test/ui/issues/issue-71584.stderr +++ b/src/test/ui/issues/issue-71584.stderr @@ -1,8 +1,8 @@ -error[E0284]: type annotations needed: cannot satisfy `>::Output == u64` +error[E0284]: type annotations needed: cannot satisfy `>::Output == u64` --> $DIR/issue-71584.rs:4:11 | LL | d = d % n.into(); - | ^ cannot satisfy `>::Output == u64` + | ^ cannot satisfy `>::Output == u64` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-72690.stderr b/src/test/ui/issues/issue-72690.stderr index 64e78ddf60..feb1316357 100644 --- a/src/test/ui/issues/issue-72690.stderr +++ b/src/test/ui/issues/issue-72690.stderr @@ -2,10 +2,10 @@ error[E0283]: type annotations needed --> $DIR/issue-72690.rs:7:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error[E0282]: type annotations needed --> $DIR/issue-72690.rs:11:6 @@ -19,68 +19,68 @@ error[E0283]: type annotations needed LL | let _ = "x".as_ref(); | ^^^^^^ cannot infer type for type `str` | - = note: cannot satisfy `str: std::convert::AsRef<_>` + = note: cannot satisfy `str: AsRef<_>` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:19:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:25:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error[E0283]: type annotations needed --> $DIR/issue-72690.rs:33:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` -error[E0283]: type annotations needed for `std::string::String` +error[E0283]: type annotations needed for `String` --> $DIR/issue-72690.rs:41:5 | LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` LL | let _ = String::from("x"); | - consider giving this pattern a type | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` -error[E0283]: type annotations needed for `std::string::String` +error[E0283]: type annotations needed for `String` --> $DIR/issue-72690.rs:47:5 | LL | let _ = String::from("x"); | - consider giving this pattern a type LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` -error[E0283]: type annotations needed for `std::string::String` +error[E0283]: type annotations needed for `String` --> $DIR/issue-72690.rs:55:5 | LL | let _ = String::from("x"); | - consider giving this pattern a type ... LL | String::from("x".as_ref()); - | ^^^^^^^^^^^^ cannot infer type for struct `std::string::String` + | ^^^^^^^^^^^^ cannot infer type for struct `String` | - = note: cannot satisfy `std::string::String: std::convert::From<&_>` - = note: required by `std::convert::From::from` + = note: cannot satisfy `String: From<&_>` + = note: required by `from` error: aborting due to 9 previous errors diff --git a/src/test/ui/issues/issue-7364.rs b/src/test/ui/issues/issue-7364.rs index 52ec9e42be..29a1644673 100644 --- a/src/test/ui/issues/issue-7364.rs +++ b/src/test/ui/issues/issue-7364.rs @@ -5,7 +5,6 @@ use std::cell::RefCell; // Regression test for issue 7364 static boxed: Box> = box RefCell::new(0); //~^ ERROR allocations are not allowed in statics -//~| ERROR `std::cell::RefCell` cannot be shared between threads safely [E0277] -//~| ERROR static contains unimplemented expression type +//~| ERROR `RefCell` cannot be shared between threads safely [E0277] fn main() { } diff --git a/src/test/ui/issues/issue-7364.stderr b/src/test/ui/issues/issue-7364.stderr index efff2c2452..8ceb3be7ec 100644 --- a/src/test/ui/issues/issue-7364.stderr +++ b/src/test/ui/issues/issue-7364.stderr @@ -4,26 +4,18 @@ error[E0010]: allocations are not allowed in statics LL | static boxed: Box> = box RefCell::new(0); | ^^^^^^^^^^^^^^^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/issue-7364.rs:6:41 - | -LL | static boxed: Box> = box RefCell::new(0); - | ^^^^^^^^^^^^^^^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable - -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/issue-7364.rs:6:1 | LL | static boxed: Box> = box RefCell::new(0); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::marker::Sync` for `std::ptr::Unique>` - = note: required because it appears within the type `std::boxed::Box>` + = help: the trait `Sync` is not implemented for `RefCell` + = note: required because of the requirements on the impl of `Sync` for `Unique>` + = note: required because it appears within the type `Box>` = note: shared static variables must have a type that implements `Sync` -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors -Some errors have detailed explanations: E0010, E0019, E0277. +Some errors have detailed explanations: E0010, E0277. For more information about an error, try `rustc --explain E0010`. diff --git a/src/test/ui/issues/issue-73886.rs b/src/test/ui/issues/issue-73886.rs index 2f1ec8c6d6..9c0c87a5cf 100644 --- a/src/test/ui/issues/issue-73886.rs +++ b/src/test/ui/issues/issue-73886.rs @@ -2,5 +2,5 @@ fn main() { let _ = &&[0] as &[_]; //~^ ERROR non-primitive cast: `&&[i32; 1]` as `&[_]` let _ = 7u32 as Option<_>; - //~^ ERROR non-primitive cast: `u32` as `std::option::Option<_>` + //~^ ERROR non-primitive cast: `u32` as `Option<_>` } diff --git a/src/test/ui/issues/issue-73886.stderr b/src/test/ui/issues/issue-73886.stderr index e8ab7db6b8..31f642ea66 100644 --- a/src/test/ui/issues/issue-73886.stderr +++ b/src/test/ui/issues/issue-73886.stderr @@ -4,7 +4,7 @@ error[E0605]: non-primitive cast: `&&[i32; 1]` as `&[_]` LL | let _ = &&[0] as &[_]; | ^^^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error[E0605]: non-primitive cast: `u32` as `std::option::Option<_>` +error[E0605]: non-primitive cast: `u32` as `Option<_>` --> $DIR/issue-73886.rs:4:13 | LL | let _ = 7u32 as Option<_>; diff --git a/src/test/ui/issues/issue-74236/main.stderr b/src/test/ui/issues/issue-74236/main.stderr index 51d4833e01..55e94ae72c 100644 --- a/src/test/ui/issues/issue-74236/main.stderr +++ b/src/test/ui/issues/issue-74236/main.stderr @@ -2,9 +2,9 @@ error[E0308]: mismatched types --> $DIR/main.rs:7:9 | LL | let () = dep::Renamed; - | ^^ ------------ this expression has type `dep::Renamed` + | ^^ ------------ this expression has type `Renamed` | | - | expected struct `dep::Renamed`, found `()` + | expected struct `Renamed`, found `()` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-75907.rs b/src/test/ui/issues/issue-75907.rs new file mode 100644 index 0000000000..8c155d9be3 --- /dev/null +++ b/src/test/ui/issues/issue-75907.rs @@ -0,0 +1,18 @@ +// Test for for diagnostic improvement issue #75907 + +mod foo { + pub(crate) struct Foo(u8); + pub(crate) struct Bar(pub u8, u8, Foo); + + pub(crate) fn make_bar() -> Bar { + Bar(1, 12, Foo(10)) + } +} + +use foo::{make_bar, Bar, Foo}; + +fn main() { + let Bar(x, y, Foo(z)) = make_bar(); + //~^ ERROR expected tuple struct + //~| ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907.stderr b/src/test/ui/issues/issue-75907.stderr new file mode 100644 index 0000000000..65b9a51e01 --- /dev/null +++ b/src/test/ui/issues/issue-75907.stderr @@ -0,0 +1,29 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907.rs:15:9 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:16 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ ^^^^^^ private field + | | + | private field + +error[E0532]: expected tuple struct or tuple variant, found struct `Foo` + --> $DIR/issue-75907.rs:15:19 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^^^ + | +note: constructor is not visible here due to private fields + --> $DIR/issue-75907.rs:15:23 + | +LL | let Bar(x, y, Foo(z)) = make_bar(); + | ^ private field + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/issues/issue-75907_b.rs b/src/test/ui/issues/issue-75907_b.rs new file mode 100644 index 0000000000..fdd3bc6d72 --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.rs @@ -0,0 +1,11 @@ +// Test for for diagnostic improvement issue #75907, extern crate +// aux-build:issue-75907.rs + +extern crate issue_75907 as a; + +use a::{make_bar, Bar}; + +fn main() { + let Bar(x, y, z) = make_bar(); + //~^ ERROR expected tuple struct +} diff --git a/src/test/ui/issues/issue-75907_b.stderr b/src/test/ui/issues/issue-75907_b.stderr new file mode 100644 index 0000000000..cdd21de6c3 --- /dev/null +++ b/src/test/ui/issues/issue-75907_b.stderr @@ -0,0 +1,9 @@ +error[E0532]: expected tuple struct or tuple variant, found struct `Bar` + --> $DIR/issue-75907_b.rs:9:9 + | +LL | let Bar(x, y, z) = make_bar(); + | ^^^ constructor is not visible here due to private fields + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0532`. diff --git a/src/test/ui/issues/issue-76077-1.fixed b/src/test/ui/issues/issue-76077-1.fixed new file mode 100644 index 0000000000..8103a7ca47 --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.fixed @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo { .. } = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible, .. } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.rs b/src/test/ui/issues/issue-76077-1.rs new file mode 100644 index 0000000000..730332853c --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.rs @@ -0,0 +1,18 @@ +// run-rustfix +#![allow(dead_code, unused_variables)] + +pub mod foo { + #[derive(Default)] + pub struct Foo { invisible: bool, } + + #[derive(Default)] + pub struct Bar { pub visible: bool, invisible: bool, } +} + +fn main() { + let foo::Foo {} = foo::Foo::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields + + let foo::Bar { visible } = foo::Bar::default(); + //~^ ERROR pattern requires `..` due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077-1.stderr b/src/test/ui/issues/issue-76077-1.stderr new file mode 100644 index 0000000000..4557595529 --- /dev/null +++ b/src/test/ui/issues/issue-76077-1.stderr @@ -0,0 +1,24 @@ +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:13:9 + | +LL | let foo::Foo {} = foo::Foo::default(); + | ^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Foo { .. } = foo::Foo::default(); + | ^^^^^^ + +error: pattern requires `..` due to inaccessible fields + --> $DIR/issue-76077-1.rs:16:9 + | +LL | let foo::Bar { visible } = foo::Bar::default(); + | ^^^^^^^^^^^^^^^^^^^^ + | +help: ignore the inaccessible and unused fields + | +LL | let foo::Bar { visible, .. } = foo::Bar::default(); + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/issues/issue-76077.rs b/src/test/ui/issues/issue-76077.rs new file mode 100644 index 0000000000..1ecd37de2e --- /dev/null +++ b/src/test/ui/issues/issue-76077.rs @@ -0,0 +1,10 @@ +pub mod foo { + pub struct Foo { + you_cant_use_this_field: bool, + } +} + +fn main() { + foo::Foo {}; + //~^ ERROR cannot construct `Foo` with struct literal syntax due to inaccessible fields +} diff --git a/src/test/ui/issues/issue-76077.stderr b/src/test/ui/issues/issue-76077.stderr new file mode 100644 index 0000000000..d834ec5e0e --- /dev/null +++ b/src/test/ui/issues/issue-76077.stderr @@ -0,0 +1,8 @@ +error: cannot construct `Foo` with struct literal syntax due to inaccessible fields + --> $DIR/issue-76077.rs:8:5 + | +LL | foo::Foo {}; + | ^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/issues/issue-76191.rs b/src/test/ui/issues/issue-76191.rs new file mode 100644 index 0000000000..d9790d2b56 --- /dev/null +++ b/src/test/ui/issues/issue-76191.rs @@ -0,0 +1,19 @@ +// Regression test for diagnostic issue #76191 +#![allow(non_snake_case)] + +use std::ops::RangeInclusive; + +const RANGE: RangeInclusive = 0..=255; + +const RANGE2: RangeInclusive = panic!(); + +fn main() { + let n: i32 = 1; + match n { + RANGE => {} + //~^ ERROR mismatched types + RANGE2 => {} + //~^ ERROR mismatched types + _ => {} + } +} diff --git a/src/test/ui/issues/issue-76191.stderr b/src/test/ui/issues/issue-76191.stderr new file mode 100644 index 0000000000..bdcd2fe1ad --- /dev/null +++ b/src/test/ui/issues/issue-76191.stderr @@ -0,0 +1,43 @@ +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:13:9 + | +LL | const RANGE: RangeInclusive = 0..=255; + | ------------------------------------------- constant defined here +... +LL | match n { + | - this expression has type `i32` +LL | RANGE => {} + | ^^^^^ + | | + | expected `i32`, found struct `RangeInclusive` + | `RANGE` is interpreted as a constant, not a new binding + | + = note: expected type `i32` + found struct `RangeInclusive` +help: you may want to move the range into the match block + | +LL | 0..=255 => {} + | ^^^^^^^ + +error[E0308]: mismatched types + --> $DIR/issue-76191.rs:15:9 + | +LL | const RANGE2: RangeInclusive = panic!(); + | --------------------------------------------- constant defined here +... +LL | match n { + | - this expression has type `i32` +... +LL | RANGE2 => {} + | ^^^^^^ + | | + | expected `i32`, found struct `RangeInclusive` + | `RANGE2` is interpreted as a constant, not a new binding + | + = note: expected type `i32` + found struct `RangeInclusive` + = note: constants only support matching by type, if you meant to match against a range of values, consider using a range pattern like `min ..= max` in the match block + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-77002.rs b/src/test/ui/issues/issue-77002.rs new file mode 100644 index 0000000000..c7dd3cf810 --- /dev/null +++ b/src/test/ui/issues/issue-77002.rs @@ -0,0 +1,16 @@ +// compile-flags: -Zmir-opt-level=2 -Copt-level=0 +// run-pass + +type M = [i64; 2]; + +fn f(a: &M) -> M { + let mut b: M = M::default(); + b[0] = a[0] * a[0]; + b +} + +fn main() { + let mut a: M = [1, 1]; + a = f(&a); + assert_eq!(a[0], 1); +} diff --git a/src/test/ui/issues/issue-77218.rs b/src/test/ui/issues/issue-77218.rs new file mode 100644 index 0000000000..bc992c21dc --- /dev/null +++ b/src/test/ui/issues/issue-77218.rs @@ -0,0 +1,7 @@ +fn main() { + let value = [7u8]; + while Some(0) = value.get(0) { //~ ERROR mismatched types + //~^ NOTE expected `bool`, found `()` + //~| HELP you might have meant to use pattern matching + } +} diff --git a/src/test/ui/issues/issue-77218.stderr b/src/test/ui/issues/issue-77218.stderr new file mode 100644 index 0000000000..eca44725eb --- /dev/null +++ b/src/test/ui/issues/issue-77218.stderr @@ -0,0 +1,14 @@ +error[E0308]: mismatched types + --> $DIR/issue-77218.rs:3:11 + | +LL | while Some(0) = value.get(0) { + | ^^^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | while let Some(0) = value.get(0) { + | ^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/issues/issue-77919.rs b/src/test/ui/issues/issue-77919.rs new file mode 100644 index 0000000000..9b04d5ee00 --- /dev/null +++ b/src/test/ui/issues/issue-77919.rs @@ -0,0 +1,13 @@ +fn main() { + [1; >::VAL]; //~ ERROR evaluation of constant value failed +} +trait TypeVal { + const VAL: T; //~ ERROR any use of this value will cause an error +} +struct Five; +struct Multiply { + _n: PhantomData, //~ ERROR cannot find type `PhantomData` in this scope +} +impl TypeVal for Multiply where N: TypeVal {} +//~^ ERROR cannot find type `VAL` in this scope +//~| ERROR not all trait items implemented, missing: `VAL` diff --git a/src/test/ui/issues/issue-77919.stderr b/src/test/ui/issues/issue-77919.stderr new file mode 100644 index 0000000000..129af00644 --- /dev/null +++ b/src/test/ui/issues/issue-77919.stderr @@ -0,0 +1,46 @@ +error[E0412]: cannot find type `PhantomData` in this scope + --> $DIR/issue-77919.rs:9:9 + | +LL | _n: PhantomData, + | ^^^^^^^^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::marker::PhantomData; + | + +error[E0412]: cannot find type `VAL` in this scope + --> $DIR/issue-77919.rs:11:63 + | +LL | impl TypeVal for Multiply where N: TypeVal {} + | - ^^^ not found in this scope + | | + | help: you might be missing a type parameter: `, VAL` + +error[E0046]: not all trait items implemented, missing: `VAL` + --> $DIR/issue-77919.rs:11:1 + | +LL | const VAL: T; + | ------------- `VAL` from trait +... +LL | impl TypeVal for Multiply where N: TypeVal {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `VAL` in implementation + +error: any use of this value will cause an error + --> $DIR/issue-77919.rs:5:5 + | +LL | const VAL: T; + | ^^^^^^^^^^^^^ no MIR body is available for DefId(0:7 ~ issue_77919[317d]::TypeVal::VAL) + | + = note: `#[deny(const_err)]` on by default + +error[E0080]: evaluation of constant value failed + --> $DIR/issue-77919.rs:2:9 + | +LL | [1; >::VAL]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ referenced constant has errors + +error: aborting due to 5 previous errors + +Some errors have detailed explanations: E0046, E0080, E0412. +For more information about an error, try `rustc --explain E0046`. diff --git a/src/test/ui/issues/issue-78372.rs b/src/test/ui/issues/issue-78372.rs new file mode 100644 index 0000000000..77a8c92c81 --- /dev/null +++ b/src/test/ui/issues/issue-78372.rs @@ -0,0 +1,14 @@ +use std::ops::DispatchFromDyn; //~ ERROR use of unstable library feature 'dispatch_from_dyn' +struct Smaht(PhantomData); //~ ERROR cannot find type `PhantomData` in this scope +impl DispatchFromDyn> for T {} //~ ERROR cannot find type `U` in this scope +//~^ ERROR cannot find type `MISC` in this scope +//~| ERROR use of unstable library feature 'dispatch_from_dyn' +//~| ERROR the trait `DispatchFromDyn` may only be implemented for a coercion between structures +//~| ERROR type parameter `T` must be covered by another type when it appears before the first +trait Foo: X {} +trait X { + fn foo(self: Smaht); +} +trait Marker {} +impl Marker for dyn Foo {} +fn main() {} diff --git a/src/test/ui/issues/issue-78372.stderr b/src/test/ui/issues/issue-78372.stderr new file mode 100644 index 0000000000..9cdec1a5df --- /dev/null +++ b/src/test/ui/issues/issue-78372.stderr @@ -0,0 +1,62 @@ +error[E0412]: cannot find type `PhantomData` in this scope + --> $DIR/issue-78372.rs:2:23 + | +LL | struct Smaht(PhantomData); + | ^^^^^^^^^^^ not found in this scope + | +help: consider importing this struct + | +LL | use std::marker::PhantomData; + | + +error[E0412]: cannot find type `U` in this scope + --> $DIR/issue-78372.rs:3:31 + | +LL | impl DispatchFromDyn> for T {} + | - ^ help: a type parameter with a similar name exists: `T` + | | + | similarly named type parameter `T` defined here + +error[E0412]: cannot find type `MISC` in this scope + --> $DIR/issue-78372.rs:3:34 + | +LL | impl DispatchFromDyn> for T {} + | - ^^^^ not found in this scope + | | + | help: you might be missing a type parameter: `, MISC` + +error[E0658]: use of unstable library feature 'dispatch_from_dyn' + --> $DIR/issue-78372.rs:1:5 + | +LL | use std::ops::DispatchFromDyn; + | ^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'dispatch_from_dyn' + --> $DIR/issue-78372.rs:3:9 + | +LL | impl DispatchFromDyn> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = help: add `#![feature(dispatch_from_dyn)]` to the crate attributes to enable + +error[E0378]: the trait `DispatchFromDyn` may only be implemented for a coercion between structures + --> $DIR/issue-78372.rs:3:1 + | +LL | impl DispatchFromDyn> for T {} + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`Smaht<[type error], [type error]>`) + --> $DIR/issue-78372.rs:3:6 + | +LL | impl DispatchFromDyn> for T {} + | ^ type parameter `T` must be covered by another type when it appears before the first local type (`Smaht<[type error], [type error]>`) + | + = note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type + = note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait for T0`, where `T0` is the first and `Tn` is the last + +error: aborting due to 7 previous errors + +Some errors have detailed explanations: E0210, E0378, E0412, E0658. +For more information about an error, try `rustc --explain E0210`. diff --git a/src/test/ui/issues/issue-78622.rs b/src/test/ui/issues/issue-78622.rs new file mode 100644 index 0000000000..c00fd26606 --- /dev/null +++ b/src/test/ui/issues/issue-78622.rs @@ -0,0 +1,7 @@ +#![crate_type = "lib"] + +struct S; +fn f() { + S::A:: {} + //~^ ERROR ambiguous associated type +} diff --git a/src/test/ui/issues/issue-78622.stderr b/src/test/ui/issues/issue-78622.stderr new file mode 100644 index 0000000000..f13073da0a --- /dev/null +++ b/src/test/ui/issues/issue-78622.stderr @@ -0,0 +1,9 @@ +error[E0223]: ambiguous associated type + --> $DIR/issue-78622.rs:5:5 + | +LL | S::A:: {} + | ^^^^^^^^^ help: use fully-qualified syntax: `::A` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0223`. diff --git a/src/test/ui/issues/issue-8460-const.noopt.stderr b/src/test/ui/issues/issue-8460-const.noopt.stderr index eb8d66790c..739b546874 100644 --- a/src/test/ui/issues/issue-8460-const.noopt.stderr +++ b/src/test/ui/issues/issue-8460-const.noopt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:14:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:16:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:18:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:20:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:22:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:24:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:26:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^^^^ attempt to divide `1_isize` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -48,103 +48,103 @@ error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:28:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ attempt to divide 1_i8 by zero + | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:30:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i16 by zero + | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:32:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:34:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i64 by zero + | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:36:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ attempt to divide 1_i128 by zero + | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:38:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:40:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:42:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:44:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:46:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:48:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:50:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:52:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero + | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:54:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:56:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:58:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:60:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero + | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: aborting due to 24 previous errors diff --git a/src/test/ui/issues/issue-8460-const.opt.stderr b/src/test/ui/issues/issue-8460-const.opt.stderr index eb8d66790c..739b546874 100644 --- a/src/test/ui/issues/issue-8460-const.opt.stderr +++ b/src/test/ui/issues/issue-8460-const.opt.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:14:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:16:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:18:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:20:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:22:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:24:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:26:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^^^^ attempt to divide `1_isize` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -48,103 +48,103 @@ error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:28:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ attempt to divide 1_i8 by zero + | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:30:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i16 by zero + | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:32:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:34:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i64 by zero + | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:36:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ attempt to divide 1_i128 by zero + | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:38:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:40:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:42:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:44:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:46:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:48:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:50:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:52:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero + | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:54:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:56:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:58:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:60:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero + | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: aborting due to 24 previous errors diff --git a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr index eb8d66790c..739b546874 100644 --- a/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr +++ b/src/test/ui/issues/issue-8460-const.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:14:36 | LL | assert!(thread::spawn(move|| { isize::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute `isize::MIN / -1_isize`, which would overflow | = note: `#[deny(arithmetic_overflow)]` on by default @@ -10,37 +10,37 @@ error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:16:36 | LL | assert!(thread::spawn(move|| { i8::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute `i8::MIN / -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:18:36 | LL | assert!(thread::spawn(move|| { i16::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i16::MIN / -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:20:36 | LL | assert!(thread::spawn(move|| { i32::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i32::MIN / -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:22:36 | LL | assert!(thread::spawn(move|| { i64::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute `i64::MIN / -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:24:36 | LL | assert!(thread::spawn(move|| { i128::MIN / -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute `i128::MIN / -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:26:36 | LL | assert!(thread::spawn(move|| { 1isize / 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to divide 1_isize by zero + | ^^^^^^^^^^ attempt to divide `1_isize` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -48,103 +48,103 @@ error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:28:36 | LL | assert!(thread::spawn(move|| { 1i8 / 0; }).join().is_err()); - | ^^^^^^^ attempt to divide 1_i8 by zero + | ^^^^^^^ attempt to divide `1_i8` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:30:36 | LL | assert!(thread::spawn(move|| { 1i16 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i16 by zero + | ^^^^^^^^ attempt to divide `1_i16` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:32:36 | LL | assert!(thread::spawn(move|| { 1i32 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i32 by zero + | ^^^^^^^^ attempt to divide `1_i32` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:34:36 | LL | assert!(thread::spawn(move|| { 1i64 / 0; }).join().is_err()); - | ^^^^^^^^ attempt to divide 1_i64 by zero + | ^^^^^^^^ attempt to divide `1_i64` by zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:36:36 | LL | assert!(thread::spawn(move|| { 1i128 / 0; }).join().is_err()); - | ^^^^^^^^^ attempt to divide 1_i128 by zero + | ^^^^^^^^^ attempt to divide `1_i128` by zero error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:38:36 | LL | assert!(thread::spawn(move|| { isize::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize` which would overflow + | ^^^^^^^^^^^^^^^ attempt to compute the remainder of `isize::MIN % -1_isize`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:40:36 | LL | assert!(thread::spawn(move|| { i8::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8` which would overflow + | ^^^^^^^^^^^^ attempt to compute the remainder of `i8::MIN % -1_i8`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:42:36 | LL | assert!(thread::spawn(move|| { i16::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i16::MIN % -1_i16`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:44:36 | LL | assert!(thread::spawn(move|| { i32::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i32::MIN % -1_i32`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:46:36 | LL | assert!(thread::spawn(move|| { i64::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64` which would overflow + | ^^^^^^^^^^^^^ attempt to compute the remainder of `i64::MIN % -1_i64`, which would overflow error: this arithmetic operation will overflow --> $DIR/issue-8460-const.rs:48:36 | LL | assert!(thread::spawn(move|| { i128::MIN % -1; }).join().is_err()); - | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128` which would overflow + | ^^^^^^^^^^^^^^ attempt to compute the remainder of `i128::MIN % -1_i128`, which would overflow error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:50:36 | LL | assert!(thread::spawn(move|| { 1isize % 0; }).join().is_err()); - | ^^^^^^^^^^ attempt to calculate the remainder of 1_isize with a divisor of zero + | ^^^^^^^^^^ attempt to calculate the remainder of `1_isize` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:52:36 | LL | assert!(thread::spawn(move|| { 1i8 % 0; }).join().is_err()); - | ^^^^^^^ attempt to calculate the remainder of 1_i8 with a divisor of zero + | ^^^^^^^ attempt to calculate the remainder of `1_i8` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:54:36 | LL | assert!(thread::spawn(move|| { 1i16 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i16 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i16` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:56:36 | LL | assert!(thread::spawn(move|| { 1i32 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:58:36 | LL | assert!(thread::spawn(move|| { 1i64 % 0; }).join().is_err()); - | ^^^^^^^^ attempt to calculate the remainder of 1_i64 with a divisor of zero + | ^^^^^^^^ attempt to calculate the remainder of `1_i64` with a divisor of zero error: this operation will panic at runtime --> $DIR/issue-8460-const.rs:60:36 | LL | assert!(thread::spawn(move|| { 1i128 % 0; }).join().is_err()); - | ^^^^^^^^^ attempt to calculate the remainder of 1_i128 with a divisor of zero + | ^^^^^^^^^ attempt to calculate the remainder of `1_i128` with a divisor of zero error: aborting due to 24 previous errors diff --git a/src/test/ui/issues/issue-8727.rs b/src/test/ui/issues/issue-8727.rs index 14bdd85111..a9b8126618 100644 --- a/src/test/ui/issues/issue-8727.rs +++ b/src/test/ui/issues/issue-8727.rs @@ -2,11 +2,12 @@ // recursions. // build-fail +// normalize-stderr-test: ".nll/" -> "/" fn generic() { //~ WARN function cannot return without recursing generic::>(); } -//~^^ ERROR reached the recursion limit while instantiating `generic:: $DIR/issue-8727.rs:6:1 + --> $DIR/issue-8727.rs:7:1 | LL | fn generic() { | ^^^^^^^^^^^^^^^ cannot return without recursing @@ -9,17 +9,18 @@ LL | generic::>(); = note: `#[warn(unconditional_recursion)]` on by default = help: a `loop` may express intention better if this is on purpose -error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/issue-8727.rs:7:5 +error: reached the recursion limit while instantiating `generic::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` + --> $DIR/issue-8727.rs:8:5 | LL | generic::>(); | ^^^^^^^^^^^^^^^^^^^^^^ | note: `generic` defined here - --> $DIR/issue-8727.rs:6:1 + --> $DIR/issue-8727.rs:7:1 | LL | fn generic() { | ^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/issues/issue-8727/issue-8727.long-type.txt' error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/iterators/array-of-ranges.stderr b/src/test/ui/iterators/array-of-ranges.stderr index 3dbed9a106..6271d8107b 100644 --- a/src/test/ui/iterators/array-of-ranges.stderr +++ b/src/test/ui/iterators/array-of-ranges.stderr @@ -4,49 +4,49 @@ error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator LL | for _ in [0..1] {} | ^^^^^^ if you meant to iterate between two values, remove the square brackets | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeInclusive<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:4:14 | LL | for _ in [0..=1] {} - | ^^^^^^^ if you meant to iterate between two values, remove the square brackets + | ^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeInclusive<{integer}>; 1]` - = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeFrom<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeFrom<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:6:14 | LL | for _ in [0..] {} - | ^^^^^ if you meant to iterate from a value onwards, remove the square brackets + | ^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeFrom<{integer}>; 1]` - = note: `[start..]` is an array of one `RangeFrom`; you might have meant to have a `RangeFrom` without the brackets: `start..`, keeping in mind that iterating over an unbounded iterator will run forever unless you `break` or `return` from within the loop - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeFrom<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeTo<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeTo<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:8:14 | LL | for _ in [..1] {} - | ^^^^^ if you meant to iterate until a value, remove the square brackets and add a starting value + | ^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeTo<{integer}>; 1]` - = note: `[..end]` is an array of one `RangeTo`; you might have meant to have a bounded `Range` without the brackets: `0..end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeTo<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeToInclusive<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeToInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:10:14 | LL | for _ in [..=1] {} - | ^^^^^^ if you meant to iterate until a value (including it), remove the square brackets and add a starting value + | ^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeToInclusive<{integer}>; 1]` - = note: `[..=end]` is an array of one `RangeToInclusive`; you might have meant to have a bounded `RangeInclusive` without the brackets: `0..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeToInclusive<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:14:14 @@ -54,9 +54,9 @@ error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator LL | for _ in [start..end] {} | ^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:17:14 @@ -64,9 +64,9 @@ error[E0277]: `[std::ops::Range<{integer}>; 1]` is not an iterator LL | for _ in array_of_range {} | ^^^^^^^^^^^^^^ if you meant to iterate between two values, remove the square brackets | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 1]` = note: `[start..end]` is an array of one `Range`; you might have meant to have a `Range` without the brackets: `start..end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator --> $DIR/array-of-ranges.rs:19:14 @@ -74,19 +74,19 @@ error[E0277]: `[std::ops::Range<{integer}>; 2]` is not an iterator LL | for _ in [0..1, 2..3] {} | ^^^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]` + = help: the trait `Iterator` is not implemented for `[std::ops::Range<{integer}>; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` -error[E0277]: `[std::ops::RangeInclusive<{integer}>; 1]` is not an iterator +error[E0277]: `[RangeInclusive<{integer}>; 1]` is not an iterator --> $DIR/array-of-ranges.rs:21:14 | LL | for _ in [0..=1] {} - | ^^^^^^^ if you meant to iterate between two values, remove the square brackets + | ^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[std::ops::RangeInclusive<{integer}>; 1]` - = note: `[start..=end]` is an array of one `RangeInclusive`; you might have meant to have a `RangeInclusive` without the brackets: `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `[RangeInclusive<{integer}>; 1]` + = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` + = note: required by `into_iter` error: aborting due to 9 previous errors diff --git a/src/test/ui/iterators/array.stderr b/src/test/ui/iterators/array.stderr index 94731f1c74..f86c82e491 100644 --- a/src/test/ui/iterators/array.stderr +++ b/src/test/ui/iterators/array.stderr @@ -4,9 +4,9 @@ error[E0277]: `[{integer}; 2]` is not an iterator LL | for _ in [1, 2] {} | ^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 2]` + = help: the trait `Iterator` is not implemented for `[{integer}; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[{integer}; 2]` is not an iterator --> $DIR/array.rs:5:14 @@ -14,9 +14,9 @@ error[E0277]: `[{integer}; 2]` is not an iterator LL | for _ in x {} | ^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[{integer}; 2]` + = help: the trait `Iterator` is not implemented for `[{integer}; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `[{float}; 2]` is not an iterator --> $DIR/array.rs:7:14 @@ -24,9 +24,9 @@ error[E0277]: `[{float}; 2]` is not an iterator LL | for _ in [1.0, 2.0] {} | ^^^^^^^^^^ borrow the array with `&` or call `.iter()` on it to iterate over it | - = help: the trait `std::iter::Iterator` is not implemented for `[{float}; 2]` + = help: the trait `Iterator` is not implemented for `[{float}; 2]` = note: arrays are not iterators, but slices like the following are: `&[1, 2, 3]` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error: aborting due to 3 previous errors diff --git a/src/test/ui/iterators/bound.stderr b/src/test/ui/iterators/bound.stderr index 1a5aad6c36..eaf2e66d0f 100644 --- a/src/test/ui/iterators/bound.stderr +++ b/src/test/ui/iterators/bound.stderr @@ -6,7 +6,7 @@ LL | struct S(I); LL | struct T(S); | ^^^^^ `u8` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u8` + = help: the trait `Iterator` is not implemented for `u8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` error: aborting due to previous error diff --git a/src/test/ui/iterators/integral.stderr b/src/test/ui/iterators/integral.stderr index 71e1e81e5a..c4c4641261 100644 --- a/src/test/ui/iterators/integral.stderr +++ b/src/test/ui/iterators/integral.stderr @@ -4,9 +4,9 @@ error[E0277]: `{integer}` is not an iterator LL | for _ in 42 {} | ^^ `{integer}` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `{integer}` + = help: the trait `Iterator` is not implemented for `{integer}` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u8` is not an iterator --> $DIR/integral.rs:4:14 @@ -14,9 +14,9 @@ error[E0277]: `u8` is not an iterator LL | for _ in 42 as u8 {} | ^^^^^^^^ `u8` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u8` + = help: the trait `Iterator` is not implemented for `u8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i8` is not an iterator --> $DIR/integral.rs:6:14 @@ -24,9 +24,9 @@ error[E0277]: `i8` is not an iterator LL | for _ in 42 as i8 {} | ^^^^^^^^ `i8` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i8` + = help: the trait `Iterator` is not implemented for `i8` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u16` is not an iterator --> $DIR/integral.rs:8:14 @@ -34,9 +34,9 @@ error[E0277]: `u16` is not an iterator LL | for _ in 42 as u16 {} | ^^^^^^^^^ `u16` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u16` + = help: the trait `Iterator` is not implemented for `u16` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i16` is not an iterator --> $DIR/integral.rs:10:14 @@ -44,9 +44,9 @@ error[E0277]: `i16` is not an iterator LL | for _ in 42 as i16 {} | ^^^^^^^^^ `i16` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i16` + = help: the trait `Iterator` is not implemented for `i16` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u32` is not an iterator --> $DIR/integral.rs:12:14 @@ -54,9 +54,9 @@ error[E0277]: `u32` is not an iterator LL | for _ in 42 as u32 {} | ^^^^^^^^^ `u32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u32` + = help: the trait `Iterator` is not implemented for `u32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i32` is not an iterator --> $DIR/integral.rs:14:14 @@ -64,9 +64,9 @@ error[E0277]: `i32` is not an iterator LL | for _ in 42 as i32 {} | ^^^^^^^^^ `i32` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i32` + = help: the trait `Iterator` is not implemented for `i32` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `u64` is not an iterator --> $DIR/integral.rs:16:14 @@ -74,9 +74,9 @@ error[E0277]: `u64` is not an iterator LL | for _ in 42 as u64 {} | ^^^^^^^^^ `u64` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `u64` + = help: the trait `Iterator` is not implemented for `u64` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `i64` is not an iterator --> $DIR/integral.rs:18:14 @@ -84,9 +84,9 @@ error[E0277]: `i64` is not an iterator LL | for _ in 42 as i64 {} | ^^^^^^^^^ `i64` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `i64` + = help: the trait `Iterator` is not implemented for `i64` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `usize` is not an iterator --> $DIR/integral.rs:20:14 @@ -94,9 +94,9 @@ error[E0277]: `usize` is not an iterator LL | for _ in 42 as usize {} | ^^^^^^^^^^^ `usize` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `usize` + = help: the trait `Iterator` is not implemented for `usize` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `isize` is not an iterator --> $DIR/integral.rs:22:14 @@ -104,9 +104,9 @@ error[E0277]: `isize` is not an iterator LL | for _ in 42 as isize {} | ^^^^^^^^^^^ `isize` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `isize` + = help: the trait `Iterator` is not implemented for `isize` = note: if you want to iterate between `start` until a value `end`, use the exclusive range syntax `start..end` or the inclusive range syntax `start..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = note: required by `into_iter` error[E0277]: `{float}` is not an iterator --> $DIR/integral.rs:24:14 @@ -114,8 +114,8 @@ error[E0277]: `{float}` is not an iterator LL | for _ in 42.0 {} | ^^^^ `{float}` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `{float}` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `{float}` + = note: required by `into_iter` error: aborting due to 12 previous errors diff --git a/src/test/ui/iterators/issue-58952-filter-type-length.rs b/src/test/ui/iterators/issue-58952-filter-type-length.rs index 046e378408..ffbe89a14e 100644 --- a/src/test/ui/iterators/issue-58952-filter-type-length.rs +++ b/src/test/ui/iterators/issue-58952-filter-type-length.rs @@ -3,6 +3,7 @@ //! so check that we don't accidentially exceed the type length limit. // FIXME: Once the size of iterator adaptors is further reduced, // increase the complexity of this test. +use std::collections::VecDeque; fn main() { let c = 2; @@ -27,5 +28,5 @@ fn main() { .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) .filter(|a| b.clone().any(|b| *b == *a)) - .collect::>(); + .collect::>(); } diff --git a/src/test/ui/iterators/iter-zip.rs b/src/test/ui/iterators/iter-zip.rs deleted file mode 100644 index a76fa2408b..0000000000 --- a/src/test/ui/iterators/iter-zip.rs +++ /dev/null @@ -1,103 +0,0 @@ -// run-pass -// Test that .zip() specialization preserves side effects -// in sideeffectful iterator adaptors. - -use std::cell::Cell; - -#[derive(Debug)] -struct CountClone(Cell); - -fn count_clone() -> CountClone { CountClone(Cell::new(0)) } - -impl PartialEq for CountClone { - fn eq(&self, rhs: &i32) -> bool { - self.0.get() == *rhs - } -} - -impl Clone for CountClone { - fn clone(&self) -> Self { - let ret = CountClone(self.0.clone()); - let n = self.0.get(); - self.0.set(n + 1); - ret - } -} - -fn test_zip_cloned_sideffectful() { - let xs = [count_clone(), count_clone(), count_clone(), count_clone()]; - let ys = [count_clone(), count_clone()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } - - assert_eq!(&xs, &[1, 1, 1, 0][..]); - assert_eq!(&ys, &[1, 1][..]); - - let xs = [count_clone(), count_clone()]; - let ys = [count_clone(), count_clone(), count_clone(), count_clone()]; - - for _ in xs.iter().cloned().zip(ys.iter().cloned()) { } - - assert_eq!(&xs, &[1, 1][..]); - assert_eq!(&ys, &[1, 1, 0, 0][..]); -} - -fn test_zip_map_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } - - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); - assert_eq!(&ys, &[1, 1, 1, 1]); - - let mut xs = [0; 4]; - let mut ys = [0; 6]; - - for _ in xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)) { } - - assert_eq!(&xs, &[1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1, 0, 0]); -} - -fn test_zip_map_rev_sideffectful() { - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - it.next_back(); - } - assert_eq!(&xs, &[0, 0, 0, 1, 1, 1]); - assert_eq!(&ys, &[0, 0, 0, 1]); - - let mut xs = [0; 6]; - let mut ys = [0; 4]; - - { - let mut it = xs.iter_mut().map(|x| *x += 1).zip(ys.iter_mut().map(|y| *y += 1)); - (&mut it).take(5).count(); - it.next_back(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 1]); - assert_eq!(&ys, &[1, 1, 1, 1]); -} - -fn test_zip_nested_sideffectful() { - let mut xs = [0; 6]; - let ys = [0; 4]; - - { - // test that it has the side effect nested inside enumerate - let it = xs.iter_mut().map(|x| *x = 1).enumerate().zip(&ys); - it.count(); - } - assert_eq!(&xs, &[1, 1, 1, 1, 1, 0]); -} - -fn main() { - test_zip_cloned_sideffectful(); - test_zip_map_sideffectful(); - test_zip_map_rev_sideffectful(); - test_zip_nested_sideffectful(); -} diff --git a/src/test/ui/iterators/ranges.stderr b/src/test/ui/iterators/ranges.stderr index e5e2d87879..0324d5f1a9 100644 --- a/src/test/ui/iterators/ranges.stderr +++ b/src/test/ui/iterators/ranges.stderr @@ -1,22 +1,20 @@ -error[E0277]: `std::ops::RangeTo<{integer}>` is not an iterator +error[E0277]: `RangeTo<{integer}>` is not an iterator --> $DIR/ranges.rs:2:14 | LL | for _ in ..10 {} - | ^^^^ if you meant to iterate until a value, add a starting value + | ^^^^ `RangeTo<{integer}>` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `std::ops::RangeTo<{integer}>` - = note: `..end` is a `RangeTo`, which cannot be iterated on; you might have meant to have a bounded `Range`: `0..end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `RangeTo<{integer}>` + = note: required by `into_iter` -error[E0277]: `std::ops::RangeToInclusive<{integer}>` is not an iterator +error[E0277]: `RangeToInclusive<{integer}>` is not an iterator --> $DIR/ranges.rs:4:14 | LL | for _ in ..=10 {} - | ^^^^^ if you meant to iterate until a value (including it), add a starting value + | ^^^^^ `RangeToInclusive<{integer}>` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `std::ops::RangeToInclusive<{integer}>` - = note: `..=end` is a `RangeToInclusive`, which cannot be iterated on; you might have meant to have a bounded `RangeInclusive`: `0..=end` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `RangeToInclusive<{integer}>` + = note: required by `into_iter` error: aborting due to 2 previous errors diff --git a/src/test/ui/iterators/string.rs b/src/test/ui/iterators/string.rs index 4373dcaabe..ad58a463e9 100644 --- a/src/test/ui/iterators/string.rs +++ b/src/test/ui/iterators/string.rs @@ -1,6 +1,6 @@ fn main() { for _ in "".to_owned() {} - //~^ ERROR `std::string::String` is not an iterator + //~^ ERROR `String` is not an iterator for _ in "" {} //~^ ERROR `&str` is not an iterator } diff --git a/src/test/ui/iterators/string.stderr b/src/test/ui/iterators/string.stderr index 927de952cc..fecdbd1785 100644 --- a/src/test/ui/iterators/string.stderr +++ b/src/test/ui/iterators/string.stderr @@ -1,11 +1,11 @@ -error[E0277]: `std::string::String` is not an iterator +error[E0277]: `String` is not an iterator --> $DIR/string.rs:2:14 | LL | for _ in "".to_owned() {} - | ^^^^^^^^^^^^^ `std::string::String` is not an iterator; try calling `.chars()` or `.bytes()` + | ^^^^^^^^^^^^^ `String` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `std::string::String` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `String` + = note: required by `into_iter` error[E0277]: `&str` is not an iterator --> $DIR/string.rs:4:14 @@ -13,8 +13,8 @@ error[E0277]: `&str` is not an iterator LL | for _ in "" {} | ^^ `&str` is not an iterator; try calling `.chars()` or `.bytes()` | - = help: the trait `std::iter::Iterator` is not implemented for `&str` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&str` + = note: required by `into_iter` error: aborting due to 2 previous errors diff --git a/src/test/ui/json-bom-plus-crlf-multifile.stderr b/src/test/ui/json-bom-plus-crlf-multifile.stderr index 8d3c316e46..b222334eda 100644 --- a/src/test/ui/json-bom-plus-crlf-multifile.stderr +++ b/src/test/ui/json-bom-plus-crlf-multifile.stderr @@ -16,7 +16,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":612,"byte_end":618,"line_start":17,"line_end":17,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":621,"byte_end":622,"line_start":17,"line_end":17,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:17:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -36,7 +36,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":672,"byte_end":678,"line_start":19,"line_end":19,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":681,"byte_end":682,"line_start":19,"line_end":19,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:19:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -56,7 +56,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":735,"byte_end":741,"line_start":22,"line_end":22,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":745,"byte_end":746,"line_start":23,"line_end":23,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:23:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -76,7 +76,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":801,"byte_end":809,"line_start":25,"line_end":26,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf-multifile-aux.rs","byte_start":792,"byte_end":798,"line_start":25,"line_end":25,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf-multifile-aux.rs:25:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors "} diff --git a/src/test/ui/json-bom-plus-crlf.stderr b/src/test/ui/json-bom-plus-crlf.stderr index ed6b583f32..6041366dbd 100644 --- a/src/test/ui/json-bom-plus-crlf.stderr +++ b/src/test/ui/json-bom-plus-crlf.stderr @@ -16,7 +16,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":597,"byte_end":603,"line_start":16,"line_end":16,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":606,"byte_end":607,"line_start":16,"line_end":16,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1; // Error in the middle of line.","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:16:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -36,7 +36,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":657,"byte_end":663,"line_start":18,"line_end":18,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = 1","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":666,"byte_end":667,"line_start":18,"line_end":18,"column_start":22,"column_end":23,"is_primary":true,"text":[{"text":" let s : String = 1","highlight_start":22,"highlight_end":23}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:18:22: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -56,7 +56,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `std::string::String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":"expected struct `String`, found integer","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":720,"byte_end":726,"line_start":21,"line_end":21,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String =","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[{"message":"try using a conversion method","code":null,"level":"help","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":730,"byte_end":731,"line_start":22,"line_end":22,"column_start":1,"column_end":2,"is_primary":true,"text":[{"text":"1; // Error after the newline.","highlight_start":1,"highlight_end":2}],"label":null,"suggested_replacement":"1.to_string()","suggestion_applicability":"MaybeIncorrect","expansion":null}],"children":[],"rendered":null}],"rendered":"$DIR/json-bom-plus-crlf.rs:22:1: error[E0308]: mismatched types "} {"message":"mismatched types","code":{"code":"E0308","explanation":"Expected type did not match the received type. @@ -76,7 +76,7 @@ This error occurs when the compiler is unable to infer the concrete type of a variable. It can occur in several cases, the most common being a mismatch between two types: the type the author explicitly assigned, and the type the compiler inferred. -"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `std::string::String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types +"},"level":"error","spans":[{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":786,"byte_end":794,"line_start":24,"line_end":25,"column_start":22,"column_end":6,"is_primary":true,"text":[{"text":" let s : String = (","highlight_start":22,"highlight_end":23},{"text":" ); // Error spanning the newline.","highlight_start":1,"highlight_end":6}],"label":"expected struct `String`, found `()`","suggested_replacement":null,"suggestion_applicability":null,"expansion":null},{"file_name":"$DIR/json-bom-plus-crlf.rs","byte_start":777,"byte_end":783,"line_start":24,"line_end":24,"column_start":13,"column_end":19,"is_primary":false,"text":[{"text":" let s : String = (","highlight_start":13,"highlight_end":19}],"label":"expected due to this","suggested_replacement":null,"suggestion_applicability":null,"expansion":null}],"children":[],"rendered":"$DIR/json-bom-plus-crlf.rs:24:22: error[E0308]: mismatched types "} {"message":"aborting due to 4 previous errors","code":null,"level":"error","spans":[],"children":[],"rendered":"error: aborting due to 4 previous errors "} diff --git a/src/test/ui/kindck/kindck-copy.rs b/src/test/ui/kindck/kindck-copy.rs index eb18613682..6df98c230e 100644 --- a/src/test/ui/kindck/kindck-copy.rs +++ b/src/test/ui/kindck/kindck-copy.rs @@ -24,14 +24,14 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::<&'a [isize]>(); // ...unless they are mutable - assert_copy::<&'static mut isize>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::<&'a mut isize>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::<&'static mut isize>(); //~ ERROR : Copy` is not satisfied + assert_copy::<&'a mut isize>(); //~ ERROR : Copy` is not satisfied // boxes are not ok - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy:: >(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::(); //~ ERROR : Copy` is not satisfied + assert_copy:: >(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied // borrowed object types are generally ok assert_copy::<&'a dyn Dummy>(); @@ -39,11 +39,11 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::<&'static (dyn Dummy + Send)>(); // owned object types are not ok - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied // mutable object types are not ok - assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::<&'a mut (dyn Dummy + Send)>(); //~ ERROR : Copy` is not satisfied // unsafe ptrs are ok assert_copy::<*const isize>(); @@ -61,10 +61,10 @@ fn test<'a,T,U:Copy>(_: &'a isize) { assert_copy::(); // structs containing non-POD are not ok - assert_copy::(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::(); //~ ERROR : Copy` is not satisfied // ref counted types are not ok - assert_copy::>(); //~ ERROR : std::marker::Copy` is not satisfied + assert_copy::>(); //~ ERROR : Copy` is not satisfied } pub fn main() { diff --git a/src/test/ui/kindck/kindck-copy.stderr b/src/test/ui/kindck/kindck-copy.stderr index 5a7cd458e5..1194304573 100644 --- a/src/test/ui/kindck/kindck-copy.stderr +++ b/src/test/ui/kindck/kindck-copy.stderr @@ -1,107 +1,107 @@ -error[E0277]: the trait bound `&'static mut isize: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `&'static mut isize: Copy` is not satisfied --> $DIR/kindck-copy.rs:27:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::<&'static mut isize>(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'static mut isize` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'static mut isize` | = help: the following implementations were found: - + -error[E0277]: the trait bound `&'a mut isize: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `&'a mut isize: Copy` is not satisfied --> $DIR/kindck-copy.rs:28:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::<&'a mut isize>(); - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut isize` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut isize` | = help: the following implementations were found: - + -error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:31:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `Box` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-copy.rs:32:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::(); - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^^^^^^ the trait `Copy` is not implemented for `String` -error[E0277]: the trait bound `std::vec::Vec: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Vec: Copy` is not satisfied --> $DIR/kindck-copy.rs:33:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy:: >(); - | ^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::vec::Vec` + | ^^^^^^^^^^ the trait `Copy` is not implemented for `Vec` -error[E0277]: the trait bound `std::boxed::Box<&'a mut isize>: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box<&'a mut isize>: Copy` is not satisfied --> $DIR/kindck-copy.rs:34:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<&'a mut isize>` + | ^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box<&'a mut isize>` -error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:42:5 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` -error[E0277]: the trait bound `std::boxed::Box: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Box: Copy` is not satisfied --> $DIR/kindck-copy.rs:43:5 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `Box` -error[E0277]: the trait bound `&'a mut (dyn Dummy + std::marker::Send + 'a): std::marker::Copy` is not satisfied +error[E0277]: the trait bound `&'a mut (dyn Dummy + Send + 'a): Copy` is not satisfied --> $DIR/kindck-copy.rs:46:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::<&'a mut (dyn Dummy + Send)>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `&'a mut (dyn Dummy + std::marker::Send + 'a)` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `&'a mut (dyn Dummy + Send + 'a)` -error[E0277]: the trait bound `MyNoncopyStruct: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `MyNoncopyStruct: Copy` is not satisfied --> $DIR/kindck-copy.rs:64:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::(); - | ^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `MyNoncopyStruct` + | ^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `MyNoncopyStruct` -error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Rc: Copy` is not satisfied --> $DIR/kindck-copy.rs:67:19 | LL | fn assert_copy() { } | ---- required by this bound in `assert_copy` ... LL | assert_copy::>(); - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` + | ^^^^^^^^^ the trait `Copy` is not implemented for `Rc` error: aborting due to 11 previous errors diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.rs b/src/test/ui/kindck/kindck-impl-type-params-2.rs index d5fcc68a75..c08f776dbf 100644 --- a/src/test/ui/kindck/kindck-impl-type-params-2.rs +++ b/src/test/ui/kindck/kindck-impl-type-params-2.rs @@ -11,5 +11,5 @@ fn take_param(foo: &T) { } fn main() { let x: Box<_> = box 3; take_param(&x); - //~^ ERROR the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied + //~^ ERROR the trait bound `Box<{integer}>: Foo` is not satisfied } diff --git a/src/test/ui/kindck/kindck-impl-type-params-2.stderr b/src/test/ui/kindck/kindck-impl-type-params-2.stderr index 984960efae..7e0f6e0b2d 100644 --- a/src/test/ui/kindck/kindck-impl-type-params-2.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params-2.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied +error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-impl-type-params-2.rs:13:16 | LL | fn take_param(foo: &T) { } | --- required by this bound in `take_param` ... LL | take_param(&x); - | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | ^^ the trait `Copy` is not implemented for `Box<{integer}>` | - = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr index eb400cf061..b01b8258e7 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.nll.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.nll.stderr @@ -8,21 +8,21 @@ LL | let a = &t as &dyn Gettable; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:25:31 @@ -34,39 +34,39 @@ LL | let a: &dyn Gettable = &t; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:38:13 | LL | let a = t as Box>; - | ^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^ the trait `Copy` is not implemented for `String` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` -error[E0277]: the trait bound `foo3::Foo: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:46:37 | LL | let a: Box> = t; - | ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo` + | ^ the trait `Copy` is not implemented for `Foo` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` error: aborting due to 6 previous errors diff --git a/src/test/ui/kindck/kindck-impl-type-params.rs b/src/test/ui/kindck/kindck-impl-type-params.rs index c4f90f36ac..4d4d191b6a 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.rs +++ b/src/test/ui/kindck/kindck-impl-type-params.rs @@ -17,14 +17,14 @@ fn f(val: T) { let t: S = S(marker::PhantomData); let a = &t as &dyn Gettable; //~^ ERROR `T` cannot be sent between threads safely - //~| ERROR : std::marker::Copy` is not satisfied + //~| ERROR : Copy` is not satisfied } fn g(val: T) { let t: S = S(marker::PhantomData); let a: &dyn Gettable = &t; //~^ ERROR `T` cannot be sent between threads safely - //~| ERROR : std::marker::Copy` is not satisfied + //~| ERROR : Copy` is not satisfied } fn foo<'a>() { @@ -36,7 +36,7 @@ fn foo<'a>() { fn foo2<'a>() { let t: Box> = box S(marker::PhantomData); let a = t as Box>; - //~^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR : Copy` is not satisfied } fn foo3<'a>() { @@ -44,7 +44,7 @@ fn foo3<'a>() { let t: Box> = box S(marker::PhantomData); let a: Box> = t; - //~^ ERROR : std::marker::Copy` is not satisfied + //~^ ERROR : Copy` is not satisfied } fn main() { } diff --git a/src/test/ui/kindck/kindck-impl-type-params.stderr b/src/test/ui/kindck/kindck-impl-type-params.stderr index ab9dfc9b8a..ddf8adf363 100644 --- a/src/test/ui/kindck/kindck-impl-type-params.stderr +++ b/src/test/ui/kindck/kindck-impl-type-params.stderr @@ -8,21 +8,21 @@ LL | let a = &t as &dyn Gettable; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:18:13 | LL | let a = &t as &dyn Gettable; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn f(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn f(val: T) { + | ^^^^^^ error[E0277]: `T` cannot be sent between threads safely --> $DIR/kindck-impl-type-params.rs:25:31 @@ -34,21 +34,21 @@ LL | let a: &dyn Gettable = &t; = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:25:31 | LL | let a: &dyn Gettable = &t; - | ^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^ the trait `Copy` is not implemented for `T` | = note: required because of the requirements on the impl of `Gettable` for `S` = note: required for the cast to the object type `dyn Gettable` help: consider restricting type parameter `T` | -LL | fn g(val: T) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn g(val: T) { + | ^^^^^^ error[E0477]: the type `&'a isize` does not fulfill the required lifetime --> $DIR/kindck-impl-type-params.rs:32:13 @@ -58,23 +58,23 @@ LL | let a = &t as &dyn Gettable<&'a isize>; | = note: type must satisfy the static lifetime -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:38:13 | LL | let a = t as Box>; - | ^ the trait `std::marker::Copy` is not implemented for `std::string::String` + | ^ the trait `Copy` is not implemented for `String` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` -error[E0277]: the trait bound `foo3::Foo: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/kindck-impl-type-params.rs:46:37 | LL | let a: Box> = t; - | ^ the trait `std::marker::Copy` is not implemented for `foo3::Foo` + | ^ the trait `Copy` is not implemented for `Foo` | - = note: required because of the requirements on the impl of `Gettable` for `S` - = note: required for the cast to the object type `dyn Gettable` + = note: required because of the requirements on the impl of `Gettable` for `S` + = note: required for the cast to the object type `dyn Gettable` error: aborting due to 7 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr index 7df98366ed..a6fd44d174 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.curr.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied +error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | fn take_param(foo: &T) { } | --- required by this bound in `take_param` ... LL | take_param(&x); - | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | ^^ the trait `Copy` is not implemented for `Box<{integer}>` | - = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:19 @@ -31,7 +31,7 @@ LL | trait Foo : Copy { LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Foo>` for `&Box<{integer}>` = note: required by cast to type `&dyn Foo` error: aborting due to 3 previous errors diff --git a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr index 6b511e0a6e..bc7448a05e 100644 --- a/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr +++ b/src/test/ui/kindck/kindck-inherited-copy-bound.object_safe_for_dispatch.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `std::boxed::Box<{integer}>: Foo` is not satisfied +error[E0277]: the trait bound `Box<{integer}>: Foo` is not satisfied --> $DIR/kindck-inherited-copy-bound.rs:21:16 | LL | fn take_param(foo: &T) { } | --- required by this bound in `take_param` ... LL | take_param(&x); - | ^^ the trait `std::marker::Copy` is not implemented for `std::boxed::Box<{integer}>` + | ^^ the trait `Copy` is not implemented for `Box<{integer}>` | - = note: required because of the requirements on the impl of `Foo` for `std::boxed::Box<{integer}>` + = note: required because of the requirements on the impl of `Foo` for `Box<{integer}>` error[E0038]: the trait `Foo` cannot be made into an object --> $DIR/kindck-inherited-copy-bound.rs:28:13 @@ -20,7 +20,7 @@ LL | trait Foo : Copy { LL | let z = &x as &dyn Foo; | ^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Foo>` for `&std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Foo>` for `&Box` = note: required by cast to type `&dyn Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-nonsendable-1.rs b/src/test/ui/kindck/kindck-nonsendable-1.rs index eaff5b1b99..b32fd78624 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.rs +++ b/src/test/ui/kindck/kindck-nonsendable-1.rs @@ -7,5 +7,5 @@ fn bar(_: F) { } fn main() { let x = Rc::new(3); bar(move|| foo(x)); - //~^ ERROR `std::rc::Rc` cannot be sent between threads safely + //~^ ERROR `Rc` cannot be sent between threads safely } diff --git a/src/test/ui/kindck/kindck-nonsendable-1.stderr b/src/test/ui/kindck/kindck-nonsendable-1.stderr index c7f9058dd7..c7d67a991b 100644 --- a/src/test/ui/kindck/kindck-nonsendable-1.stderr +++ b/src/test/ui/kindck/kindck-nonsendable-1.stderr @@ -1,16 +1,16 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/kindck-nonsendable-1.rs:9:5 | LL | fn bar(_: F) { } | ---- required by this bound in `bar` ... LL | bar(move|| foo(x)); - | ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` + | ^^^ ------------- within this `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]` | | - | `std::rc::Rc` cannot be sent between threads safely + | `Rc` cannot be sent between threads safely | - = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc` - = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22 x:std::rc::Rc]` + = help: within `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]`, the trait `Send` is not implemented for `Rc` + = note: required because it appears within the type `[closure@$DIR/kindck-nonsendable-1.rs:9:9: 9:22]` error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-send-object.stderr b/src/test/ui/kindck/kindck-send-object.stderr index a59a375c6c..0df7df8537 100644 --- a/src/test/ui/kindck/kindck-send-object.stderr +++ b/src/test/ui/kindck/kindck-send-object.stderr @@ -7,8 +7,8 @@ LL | fn assert_send() { } LL | assert_send::<&'static (dyn Dummy + 'static)>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required because of the requirements on the impl of `Send` for `&'static (dyn Dummy + 'static)` error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object.rs:17:5 @@ -19,9 +19,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` - = note: required because it appears within the type `std::boxed::Box` + = help: the trait `Send` is not implemented for `dyn Dummy` + = note: required because of the requirements on the impl of `Send` for `Unique` + = note: required because it appears within the type `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-object1.nll.stderr b/src/test/ui/kindck/kindck-send-object1.nll.stderr index 14a6f554f6..4792914d95 100644 --- a/src/test/ui/kindck/kindck-send-object1.nll.stderr +++ b/src/test/ui/kindck/kindck-send-object1.nll.stderr @@ -7,8 +7,8 @@ LL | fn assert_send() { } LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `&'a (dyn Dummy + 'a)` error[E0277]: `(dyn Dummy + 'a)` cannot be sent between threads safely --> $DIR/kindck-send-object1.rs:29:5 @@ -19,9 +19,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` - = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>` + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `Unique<(dyn Dummy + 'a)>` + = note: required because it appears within the type `Box<(dyn Dummy + 'a)>` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-object1.stderr b/src/test/ui/kindck/kindck-send-object1.stderr index b6d82e3195..aa72fda367 100644 --- a/src/test/ui/kindck/kindck-send-object1.stderr +++ b/src/test/ui/kindck/kindck-send-object1.stderr @@ -7,10 +7,10 @@ LL | fn assert_send() { } LL | assert_send::<&'a dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'a (dyn Dummy + 'a)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `&'a (dyn Dummy + 'a)` -error[E0477]: the type `&'a (dyn Dummy + std::marker::Sync + 'a)` does not fulfill the required lifetime +error[E0477]: the type `&'a (dyn Dummy + Sync + 'a)` does not fulfill the required lifetime --> $DIR/kindck-send-object1.rs:14:5 | LL | assert_send::<&'a (dyn Dummy + Sync)>(); @@ -27,9 +27,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'a)` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `(dyn Dummy + 'a)` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<(dyn Dummy + 'a)>` - = note: required because it appears within the type `std::boxed::Box<(dyn Dummy + 'a)>` + = help: the trait `Send` is not implemented for `(dyn Dummy + 'a)` + = note: required because of the requirements on the impl of `Send` for `Unique<(dyn Dummy + 'a)>` + = note: required because it appears within the type `Box<(dyn Dummy + 'a)>` error: aborting due to 3 previous errors diff --git a/src/test/ui/kindck/kindck-send-object2.stderr b/src/test/ui/kindck/kindck-send-object2.stderr index e6daf987c8..f7fb32ac04 100644 --- a/src/test/ui/kindck/kindck-send-object2.stderr +++ b/src/test/ui/kindck/kindck-send-object2.stderr @@ -7,8 +7,8 @@ LL | fn assert_send() { } LL | assert_send::<&'static dyn Dummy>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `(dyn Dummy + 'static)` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `(dyn Dummy + 'static)` - = note: required because of the requirements on the impl of `std::marker::Send` for `&'static (dyn Dummy + 'static)` + = help: the trait `Sync` is not implemented for `(dyn Dummy + 'static)` + = note: required because of the requirements on the impl of `Send` for `&'static (dyn Dummy + 'static)` error[E0277]: `dyn Dummy` cannot be sent between threads safely --> $DIR/kindck-send-object2.rs:12:5 @@ -19,9 +19,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `dyn Dummy` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dyn Dummy` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` - = note: required because it appears within the type `std::boxed::Box` + = help: the trait `Send` is not implemented for `dyn Dummy` + = note: required because of the requirements on the impl of `Send` for `Unique` + = note: required because it appears within the type `Box` error: aborting due to 2 previous errors diff --git a/src/test/ui/kindck/kindck-send-owned.stderr b/src/test/ui/kindck/kindck-send-owned.stderr index 2c6c2c6267..d6664ec24f 100644 --- a/src/test/ui/kindck/kindck-send-owned.stderr +++ b/src/test/ui/kindck/kindck-send-owned.stderr @@ -7,9 +7,9 @@ LL | fn assert_send() { } LL | assert_send::>(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `*mut u8` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `*mut u8` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique<*mut u8>` - = note: required because it appears within the type `std::boxed::Box<*mut u8>` + = help: the trait `Send` is not implemented for `*mut u8` + = note: required because of the requirements on the impl of `Send` for `Unique<*mut u8>` + = note: required because it appears within the type `Box<*mut u8>` error: aborting due to previous error diff --git a/src/test/ui/kindck/kindck-send-unsafe.stderr b/src/test/ui/kindck/kindck-send-unsafe.stderr index 34f9821819..069e8dc67f 100644 --- a/src/test/ui/kindck/kindck-send-unsafe.stderr +++ b/src/test/ui/kindck/kindck-send-unsafe.stderr @@ -7,7 +7,7 @@ LL | fn assert_send() { } LL | assert_send::<*mut &'a isize>(); | ^^^^^^^^^^^^^^ `*mut &'a isize` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `*mut &'a isize` + = help: the trait `Send` is not implemented for `*mut &'a isize` error: aborting due to previous error diff --git a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr index 98bf992382..5a6c86d133 100644 --- a/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr +++ b/src/test/ui/lazy_normalization_consts/feature-gate-lazy_normalization_consts.stderr @@ -5,7 +5,7 @@ LL | pub const fn sof() -> usize { | - required by this bound in `sof` ... LL | fn test() { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let _: [u8; sof::()]; | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.rs b/src/test/ui/lazy_normalization_consts/issue-73980.rs index 339b22c0b4..e10040652c 100644 --- a/src/test/ui/lazy_normalization_consts/issue-73980.rs +++ b/src/test/ui/lazy_normalization_consts/issue-73980.rs @@ -10,5 +10,7 @@ impl L { } impl X::S]> {} +//~^ WARN cannot use constants which depend on generic parameters +//~| WARN this was previously accepted by the compiler but is being phased out fn main() {} diff --git a/src/test/ui/lazy_normalization_consts/issue-73980.stderr b/src/test/ui/lazy_normalization_consts/issue-73980.stderr new file mode 100644 index 0000000000..5ed1ca362f --- /dev/null +++ b/src/test/ui/lazy_normalization_consts/issue-73980.stderr @@ -0,0 +1,12 @@ +warning: cannot use constants which depend on generic parameters in types + --> $DIR/issue-73980.rs:12:9 + | +LL | impl X::S]> {} + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[warn(const_evaluatable_unchecked)]` 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 #76200 + +warning: 1 warning emitted + diff --git a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr index 93160a1c5e..91cdc0205d 100644 --- a/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr +++ b/src/test/ui/lifetimes/lifetime-bound-will-change-warning.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | ref_obj(x) | ^ lifetime mismatch | - = note: expected reference `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>` - found reference `&std::boxed::Box<(dyn std::ops::Fn() + 'a)>` + = 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... --> $DIR/lifetime-bound-will-change-warning.rs:32:10 | @@ -19,8 +19,8 @@ error[E0308]: mismatched types LL | lib::ref_obj(x) | ^ lifetime mismatch | - = note: expected reference `&std::boxed::Box<(dyn std::ops::Fn() + 'static)>` - found reference `&std::boxed::Box<(dyn std::ops::Fn() + 'a)>` + = 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... --> $DIR/lifetime-bound-will-change-warning.rs:37:12 | diff --git a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr index 735f7a0dfc..1622ce4229 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex2b-push-no-existing-names.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn foo(x: &mut Vec>, y: Ref) { | - - has type `Ref<'1, i32>` | | - | has type `&mut std::vec::Vec>` + | has type `&mut Vec>` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr index f9c33c2480..9630729d0e 100644 --- a/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr +++ b/src/test/ui/lifetimes/lifetime-errors/ex3-both-anon-regions-both-are-structs.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | fn foo(mut x: Vec, y: Ref) { | ----- - has type `Ref<'1>` | | - | has type `std::vec::Vec>` + | has type `Vec>` LL | x.push(y); | ^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/lint/clashing-extern-fn.rs b/src/test/ui/lint/clashing-extern-fn.rs index d6ac7ccccc..41f0baecf2 100644 --- a/src/test/ui/lint/clashing-extern-fn.rs +++ b/src/test/ui/lint/clashing-extern-fn.rs @@ -182,7 +182,9 @@ mod same_sized_members_clash { y: f32, z: f32, } - extern "C" { fn origin() -> Point3; } + extern "C" { + fn origin() -> Point3; + } } mod b { #[repr(C)] @@ -191,8 +193,9 @@ mod same_sized_members_clash { y: i32, z: i32, // NOTE: Incorrectly redeclared as i32 } - extern "C" { fn origin() -> Point3; } - //~^ WARN `origin` redeclared with a different signature + extern "C" { + fn origin() -> Point3; //~ WARN `origin` redeclared with a different signature + } } } @@ -258,6 +261,78 @@ mod non_zero_and_non_null { } } +// See #75739 +mod non_zero_transparent { + mod a1 { + use std::num::NonZeroUsize; + extern "C" { + fn f1() -> NonZeroUsize; + } + } + + mod b1 { + #[repr(transparent)] + struct X(NonZeroUsize); + use std::num::NonZeroUsize; + extern "C" { + fn f1() -> X; + } + } + + mod a2 { + use std::num::NonZeroUsize; + extern "C" { + fn f2() -> NonZeroUsize; + } + } + + mod b2 { + #[repr(transparent)] + struct X1(NonZeroUsize); + + #[repr(transparent)] + struct X(X1); + + use std::num::NonZeroUsize; + extern "C" { + // Same case as above, but with two layers of newtyping. + fn f2() -> X; + } + } + + mod a3 { + #[repr(transparent)] + struct X(core::ptr::NonNull); + + use std::num::NonZeroUsize; + extern "C" { + fn f3() -> X; + } + } + + mod b3 { + extern "C" { + fn f3() -> core::ptr::NonNull; + } + } + + mod a4 { + #[repr(transparent)] + enum E { + X(std::num::NonZeroUsize), + } + extern "C" { + fn f4() -> E; + } + } + + mod b4 { + extern "C" { + fn f4() -> std::num::NonZeroUsize; + } + } +} + mod null_optimised_enums { mod a { extern "C" { @@ -285,3 +360,26 @@ mod null_optimised_enums { } } } + +#[allow(improper_ctypes)] +mod unknown_layout { + mod a { + extern "C" { + pub fn generic(l: Link); + } + pub struct Link { + pub item: T, + pub next: *const Link, + } + } + + mod b { + extern "C" { + pub fn generic(l: Link); + } + pub struct Link { + pub item: T, + pub next: *const Link, + } + } +} diff --git a/src/test/ui/lint/clashing-extern-fn.stderr b/src/test/ui/lint/clashing-extern-fn.stderr index cca0c4c59e..a48b0d008f 100644 --- a/src/test/ui/lint/clashing-extern-fn.stderr +++ b/src/test/ui/lint/clashing-extern-fn.stderr @@ -90,8 +90,8 @@ LL | fn weigh_banana(count: *const Banana) -> u64; LL | fn weigh_banana(count: *const Banana) -> u64; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn(*const banana::one::Banana) -> u64` - found `unsafe extern "C" fn(*const banana::three::Banana) -> u64` + = note: expected `unsafe extern "C" fn(*const one::Banana) -> u64` + found `unsafe extern "C" fn(*const three::Banana) -> u64` warning: `draw_point` redeclared with a different signature --> $DIR/clashing-extern-fn.rs:171:13 @@ -106,19 +106,19 @@ LL | fn draw_point(p: Point); found `unsafe extern "C" fn(sameish_members::b::Point)` warning: `origin` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:194:22 + --> $DIR/clashing-extern-fn.rs:197:13 | -LL | extern "C" { fn origin() -> Point3; } - | ---------------------- `origin` previously declared here +LL | fn origin() -> Point3; + | ---------------------- `origin` previously declared here ... -LL | extern "C" { fn origin() -> Point3; } - | ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration +LL | fn origin() -> Point3; + | ^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | = note: expected `unsafe extern "C" fn() -> same_sized_members_clash::a::Point3` found `unsafe extern "C" fn() -> same_sized_members_clash::b::Point3` warning: `transparent_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:217:13 + --> $DIR/clashing-extern-fn.rs:220:13 | LL | fn transparent_incorrect() -> T; | -------------------------------- `transparent_incorrect` previously declared here @@ -126,11 +126,11 @@ LL | fn transparent_incorrect() -> T; LL | fn transparent_incorrect() -> isize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> transparent::T` + = note: expected `unsafe extern "C" fn() -> T` found `unsafe extern "C" fn() -> isize` warning: `missing_return_type` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:235:13 + --> $DIR/clashing-extern-fn.rs:238:13 | LL | fn missing_return_type() -> usize; | ---------------------------------- `missing_return_type` previously declared here @@ -142,7 +142,7 @@ LL | fn missing_return_type(); found `unsafe extern "C" fn()` warning: `non_zero_usize` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:253:13 + --> $DIR/clashing-extern-fn.rs:256:13 | LL | fn non_zero_usize() -> core::num::NonZeroUsize; | ----------------------------------------------- `non_zero_usize` previously declared here @@ -150,11 +150,11 @@ LL | fn non_zero_usize() -> core::num::NonZeroUsize; LL | fn non_zero_usize() -> usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> std::num::NonZeroUsize` + = note: expected `unsafe extern "C" fn() -> NonZeroUsize` found `unsafe extern "C" fn() -> usize` warning: `non_null_ptr` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:255:13 + --> $DIR/clashing-extern-fn.rs:258:13 | LL | fn non_null_ptr() -> core::ptr::NonNull; | ----------------------------------------------- `non_null_ptr` previously declared here @@ -162,11 +162,11 @@ LL | fn non_null_ptr() -> core::ptr::NonNull; LL | fn non_null_ptr() -> *const usize; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ this signature doesn't match the previous declaration | - = note: expected `unsafe extern "C" fn() -> std::ptr::NonNull` + = note: expected `unsafe extern "C" fn() -> NonNull` found `unsafe extern "C" fn() -> *const usize` warning: `option_non_zero_usize_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:281:13 + --> $DIR/clashing-extern-fn.rs:356:13 | LL | fn option_non_zero_usize_incorrect() -> usize; | ---------------------------------------------- `option_non_zero_usize_incorrect` previously declared here @@ -178,7 +178,7 @@ LL | fn option_non_zero_usize_incorrect() -> isize; found `unsafe extern "C" fn() -> isize` warning: `option_non_null_ptr_incorrect` redeclared with a different signature - --> $DIR/clashing-extern-fn.rs:283:13 + --> $DIR/clashing-extern-fn.rs:358:13 | LL | fn option_non_null_ptr_incorrect() -> *const usize; | --------------------------------------------------- `option_non_null_ptr_incorrect` previously declared here diff --git a/src/test/ui/lint/dead-code/trait-impl.rs b/src/test/ui/lint/dead-code/trait-impl.rs new file mode 100644 index 0000000000..92e389a938 --- /dev/null +++ b/src/test/ui/lint/dead-code/trait-impl.rs @@ -0,0 +1,19 @@ +// check-pass +#![deny(dead_code)] + +enum Foo { + Bar, +} + +fn main() { + let p = [0; 0]; + p.bar(); +} + +trait Bar { + fn bar(&self) -> usize { + 3 + } +} + +impl Bar for [u32; Foo::Bar as usize] {} diff --git a/src/test/ui/lint/lint-const-item-mutation.rs b/src/test/ui/lint/lint-const-item-mutation.rs new file mode 100644 index 0000000000..c49a13f106 --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.rs @@ -0,0 +1,53 @@ +// check-pass + +struct MyStruct { + field: bool, + inner_array: [char; 1], + raw_ptr: *mut u8 +} +impl MyStruct { + fn use_mut(&mut self) {} +} + +struct Mutable { + msg: &'static str, +} +impl Drop for Mutable { + fn drop(&mut self) { + println!("{}", self.msg); + } +} + +struct Mutable2 { // this one has drop glue but not a Drop impl + msg: &'static str, + other: String, +} + +const ARRAY: [u8; 1] = [25]; +const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; +const RAW_PTR: *mut u8 = 1 as *mut u8; +const MUTABLE: Mutable = Mutable { msg: "" }; +const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; +const VEC: Vec = Vec::new(); + +fn main() { + ARRAY[0] = 5; //~ WARN attempting to modify + MY_STRUCT.field = false; //~ WARN attempting to modify + MY_STRUCT.inner_array[0] = 'b'; //~ WARN attempting to modify + MY_STRUCT.use_mut(); //~ WARN taking + &mut MY_STRUCT; //~ WARN taking + (&mut MY_STRUCT).use_mut(); //~ WARN taking + + // Test that we don't warn when writing through + // a raw pointer + // This is U.B., but this test is check-pass, + // so this never actually executes + unsafe { + *RAW_PTR = 0; + *MY_STRUCT.raw_ptr = 0; + } + + MUTABLE.msg = "wow"; // no warning, because Drop observes the mutation + MUTABLE2.msg = "wow"; //~ WARN attempting to modify + VEC.push(0); //~ WARN taking a mutable reference to a `const` item +} diff --git a/src/test/ui/lint/lint-const-item-mutation.stderr b/src/test/ui/lint/lint-const-item-mutation.stderr new file mode 100644 index 0000000000..11b5124b2d --- /dev/null +++ b/src/test/ui/lint/lint-const-item-mutation.stderr @@ -0,0 +1,127 @@ +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:34:5 + | +LL | ARRAY[0] = 5; + | ^^^^^^^^^^^^ + | + = note: `#[warn(const_item_mutation)]` on by default + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:26:1 + | +LL | const ARRAY: [u8; 1] = [25]; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:35:5 + | +LL | MY_STRUCT.field = false; + | ^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:36:5 + | +LL | MY_STRUCT.inner_array[0] = 'b'; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:37:5 + | +LL | MY_STRUCT.use_mut(); + | ^^^^^^^^^^^^^^^^^^^ + | + = 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 +note: mutable reference created due to call to this method + --> $DIR/lint-const-item-mutation.rs:9:5 + | +LL | fn use_mut(&mut self) {} + | ^^^^^^^^^^^^^^^^^^^^^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:38:5 + | +LL | &mut MY_STRUCT; + | ^^^^^^^^^^^^^^ + | + = 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 +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:39:5 + | +LL | (&mut MY_STRUCT).use_mut(); + | ^^^^^^^^^^^^^^^^ + | + = 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 +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:27:1 + | +LL | const MY_STRUCT: MyStruct = MyStruct { field: true, inner_array: ['a'], raw_ptr: 2 as *mut u8 }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: attempting to modify a `const` item + --> $DIR/lint-const-item-mutation.rs:51:5 + | +LL | MUTABLE2.msg = "wow"; + | ^^^^^^^^^^^^^^^^^^^^ + | + = note: each usage of a `const` item creates a new temporary - the original `const` item will not be modified +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:30:1 + | +LL | const MUTABLE2: Mutable2 = Mutable2 { msg: "", other: String::new() }; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: taking a mutable reference to a `const` item + --> $DIR/lint-const-item-mutation.rs:52:5 + | +LL | VEC.push(0); + | ^^^^^^^^^^^ + | + = 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 +note: mutable reference created due to call to this method + --> $SRC_DIR/alloc/src/vec.rs:LL:COL + | +LL | / pub fn push(&mut self, value: T) { +LL | | // This will panic or abort if we would allocate > isize::MAX bytes +LL | | // or if the length increment would overflow for zero-sized types. +LL | | if self.len == self.buf.capacity() { +... | +LL | | } +LL | | } + | |_____^ +note: `const` item defined here + --> $DIR/lint-const-item-mutation.rs:31:1 + | +LL | const VEC: Vec = Vec::new(); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +warning: 8 warnings emitted + diff --git a/src/test/ui/lint/lint-ctypes-enum.rs b/src/test/ui/lint/lint-ctypes-enum.rs index ccda005575..17cb705373 100644 --- a/src/test/ui/lint/lint-ctypes-enum.rs +++ b/src/test/ui/lint/lint-ctypes-enum.rs @@ -46,7 +46,7 @@ extern { fn option_fn(x: Option); fn nonnull(x: Option>); fn unique(x: Option>); - //~^ ERROR `extern` block uses type `std::option::Option>` + //~^ ERROR `extern` block uses type `Option>` fn nonzero_u8(x: Option); fn nonzero_u16(x: Option); fn nonzero_u32(x: Option); diff --git a/src/test/ui/lint/lint-ctypes-enum.stderr b/src/test/ui/lint/lint-ctypes-enum.stderr index 297ac2237a..3d02cda7d3 100644 --- a/src/test/ui/lint/lint-ctypes-enum.stderr +++ b/src/test/ui/lint/lint-ctypes-enum.stderr @@ -45,7 +45,7 @@ note: the type is defined here LL | enum T { E, F, G } | ^^^^^^^^^^^^^^^^^^ -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:48:17 | LL | fn unique(x: Option>); @@ -70,7 +70,7 @@ LL | fn nonzero_i128(x: Option); | = note: 128-bit integers don't currently have a known stable ABI -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:66:28 | LL | fn transparent_union(x: Option>); @@ -79,7 +79,7 @@ LL | fn transparent_union(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:68:20 | LL | fn repr_rust(x: Option>); @@ -88,7 +88,7 @@ LL | fn repr_rust(x: Option>); = help: consider adding a `#[repr(C)]`, `#[repr(transparent)]`, or integer `#[repr(...)]` attribute to this enum = note: enum has no representation hint -error: `extern` block uses type `std::result::Result<(), std::num::NonZeroI32>`, which is not FFI-safe +error: `extern` block uses type `std::result::Result<(), NonZeroI32>`, which is not FFI-safe --> $DIR/lint-ctypes-enum.rs:69:20 | LL | fn no_result(x: Result<(), num::NonZeroI32>); diff --git a/src/test/ui/lint/lint-ctypes-fn.rs b/src/test/ui/lint/lint-ctypes-fn.rs index aa02e57866..170a04efb0 100644 --- a/src/test/ui/lint/lint-ctypes-fn.rs +++ b/src/test/ui/lint/lint-ctypes-fn.rs @@ -96,7 +96,7 @@ pub extern "C" fn zero_size_phantom(p: ZeroSizeWithPhantomData) { } //~^ ERROR uses type `ZeroSizeWithPhantomData` pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { -//~^ ERROR uses type `std::marker::PhantomData` +//~^ ERROR uses type `PhantomData` Default::default() } @@ -158,7 +158,7 @@ pub extern "C" fn good2(size: *const libc::c_uint) { } pub extern "C" fn unused_generic1(size: *const Foo) { } pub extern "C" fn unused_generic2() -> PhantomData { -//~^ ERROR uses type `std::marker::PhantomData` +//~^ ERROR uses type `PhantomData` Default::default() } @@ -171,10 +171,10 @@ pub extern "C" fn used_generic3() -> T { } pub extern "C" fn used_generic4(x: Vec) { } -//~^ ERROR: uses type `std::vec::Vec` +//~^ ERROR: uses type `Vec` pub extern "C" fn used_generic5() -> Vec { -//~^ ERROR: uses type `std::vec::Vec` +//~^ ERROR: uses type `Vec` Default::default() } diff --git a/src/test/ui/lint/lint-ctypes-fn.stderr b/src/test/ui/lint/lint-ctypes-fn.stderr index d0a449514e..e6a0778ddb 100644 --- a/src/test/ui/lint/lint-ctypes-fn.stderr +++ b/src/test/ui/lint/lint-ctypes-fn.stderr @@ -91,7 +91,7 @@ note: the type is defined here LL | pub struct ZeroSizeWithPhantomData(PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `extern` fn uses type `std::marker::PhantomData`, which is not FFI-safe +error: `extern` fn uses type `PhantomData`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:98:51 | LL | pub extern "C" fn zero_size_phantom_toplevel() -> PhantomData { @@ -134,7 +134,7 @@ LL | pub extern "C" fn transparent_str(p: TransparentStr) { } = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent -error: `extern` fn uses type `std::marker::PhantomData`, which is not FFI-safe +error: `extern` fn uses type `PhantomData`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:160:43 | LL | pub extern "C" fn unused_generic2() -> PhantomData { @@ -142,7 +142,7 @@ LL | pub extern "C" fn unused_generic2() -> PhantomData { | = note: composed only of `PhantomData` -error: `extern` fn uses type `std::vec::Vec`, which is not FFI-safe +error: `extern` fn uses type `Vec`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:173:39 | LL | pub extern "C" fn used_generic4(x: Vec) { } @@ -151,7 +151,7 @@ LL | pub extern "C" fn used_generic4(x: Vec) { } = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout -error: `extern` fn uses type `std::vec::Vec`, which is not FFI-safe +error: `extern` fn uses type `Vec`, which is not FFI-safe --> $DIR/lint-ctypes-fn.rs:176:41 | LL | pub extern "C" fn used_generic5() -> Vec { diff --git a/src/test/ui/lint/lint-ctypes.rs b/src/test/ui/lint/lint-ctypes.rs index f485766bcd..e8a90bca7d 100644 --- a/src/test/ui/lint/lint-ctypes.rs +++ b/src/test/ui/lint/lint-ctypes.rs @@ -48,9 +48,9 @@ extern { pub fn ptr_type2(size: *const Foo); //~ ERROR: uses type `Foo` 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 `std::boxed::Box` + pub fn box_type(p: Box); //~ ERROR uses type `Box` pub fn opt_box_type(p: Option>); - //~^ ERROR uses type `std::option::Option>` + //~^ ERROR uses type `Option>` pub fn char_type(p: char); //~ ERROR uses type `char` pub fn i128_type(p: i128); //~ ERROR uses type `i128` pub fn u128_type(p: u128); //~ ERROR uses type `u128` @@ -61,13 +61,13 @@ extern { pub fn zero_size_phantom(p: ZeroSizeWithPhantomData); //~^ ERROR uses type `ZeroSizeWithPhantomData` pub fn zero_size_phantom_toplevel() - -> ::std::marker::PhantomData; //~ ERROR uses type `std::marker::PhantomData` + -> ::std::marker::PhantomData; //~ ERROR uses type `PhantomData` pub fn fn_type(p: RustFn); //~ ERROR uses type `fn()` pub fn fn_type2(p: fn()); //~ ERROR uses type `fn()` - pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `std::boxed::Box` + pub fn fn_contained(p: RustBadRet); //~ ERROR: uses type `Box` pub fn transparent_i128(p: TransparentI128); //~ ERROR: uses type `i128` pub fn transparent_str(p: TransparentStr); //~ ERROR: uses type `str` - pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `std::boxed::Box` + pub fn transparent_fn(p: TransparentBadFn); //~ ERROR: uses type `Box` pub fn raw_array(arr: [u8; 8]); //~ ERROR: uses type `[u8; 8]` pub static static_u128_type: u128; //~ ERROR: uses type `u128` diff --git a/src/test/ui/lint/lint-ctypes.stderr b/src/test/ui/lint/lint-ctypes.stderr index a54226a7fc..6a968fca92 100644 --- a/src/test/ui/lint/lint-ctypes.stderr +++ b/src/test/ui/lint/lint-ctypes.stderr @@ -49,7 +49,7 @@ LL | pub fn str_type(p: &str); = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent -error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe +error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:51:24 | LL | pub fn box_type(p: Box); @@ -58,7 +58,7 @@ LL | pub fn box_type(p: Box); = help: consider adding a `#[repr(C)]` or `#[repr(transparent)]` attribute to this struct = note: this struct has unspecified layout -error: `extern` block uses type `std::option::Option>`, which is not FFI-safe +error: `extern` block uses type `Option>`, which is not FFI-safe --> $DIR/lint-ctypes.rs:52:28 | LL | pub fn opt_box_type(p: Option>); @@ -145,7 +145,7 @@ note: the type is defined here LL | pub struct ZeroSizeWithPhantomData(::std::marker::PhantomData); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: `extern` block uses type `std::marker::PhantomData`, which is not FFI-safe +error: `extern` block uses type `PhantomData`, which is not FFI-safe --> $DIR/lint-ctypes.rs:64:12 | LL | -> ::std::marker::PhantomData; @@ -171,7 +171,7 @@ LL | pub fn fn_type2(p: fn()); = help: consider using an `extern fn(...) -> ...` function pointer instead = note: this function pointer has Rust-specific calling convention -error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe +error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:67:28 | LL | pub fn fn_contained(p: RustBadRet); @@ -197,7 +197,7 @@ LL | pub fn transparent_str(p: TransparentStr); = help: consider using `*const u8` and a length instead = note: string slices have no C equivalent -error: `extern` block uses type `std::boxed::Box`, which is not FFI-safe +error: `extern` block uses type `Box`, which is not FFI-safe --> $DIR/lint-ctypes.rs:70:30 | LL | pub fn transparent_fn(p: TransparentBadFn); diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr index d33b99bdc4..d7fd514611 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.noopt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:18:20 | LL | const N: i32 = T::N << 42; - | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow | note: the lint level is defined here --> $DIR/lint-exceeding-bitshifts.rs:10:9 @@ -14,139 +14,139 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:22:13 | LL | let _ = x << 42; - | ^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^ attempt to shift left by `42_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:27:15 | LL | let n = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:29:15 | LL | let n = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:31:15 | LL | let n = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:33:15 | LL | let n = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:35:15 | LL | let n = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:37:15 | LL | let n = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:39:15 | LL | let n = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:41:15 | LL | let n = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 | LL | let n = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:46:15 | LL | let n = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:48:15 | LL | let n = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:50:15 | LL | let n = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:52:15 | LL | let n = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:54:15 | LL | let n = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:56:15 | LL | let n = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:58:15 | LL | let n = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:62:15 | LL | let n = n << 8; - | ^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:64:15 | LL | let n = 1u8 << -8; - | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow + | ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:69:15 | LL | let n = 1u8 << (4+4); - | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:71:15 | LL | let n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 | LL | let n = 1_isize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:78:15 | LL | let n = 1_usize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: 24 warnings emitted diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr index d33b99bdc4..d7fd514611 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:18:20 | LL | const N: i32 = T::N << 42; - | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow | note: the lint level is defined here --> $DIR/lint-exceeding-bitshifts.rs:10:9 @@ -14,139 +14,139 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:22:13 | LL | let _ = x << 42; - | ^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^ attempt to shift left by `42_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:27:15 | LL | let n = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:29:15 | LL | let n = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:31:15 | LL | let n = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:33:15 | LL | let n = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:35:15 | LL | let n = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:37:15 | LL | let n = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:39:15 | LL | let n = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:41:15 | LL | let n = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 | LL | let n = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:46:15 | LL | let n = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:48:15 | LL | let n = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:50:15 | LL | let n = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:52:15 | LL | let n = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:54:15 | LL | let n = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:56:15 | LL | let n = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:58:15 | LL | let n = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:62:15 | LL | let n = n << 8; - | ^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:64:15 | LL | let n = 1u8 << -8; - | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow + | ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:69:15 | LL | let n = 1u8 << (4+4); - | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:71:15 | LL | let n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 | LL | let n = 1_isize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:78:15 | LL | let n = 1_usize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: 24 warnings emitted diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr index d33b99bdc4..d7fd514611 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr +++ b/src/test/ui/lint/lint-exceeding-bitshifts.opt_with_overflow_checks.stderr @@ -2,7 +2,7 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:18:20 | LL | const N: i32 = T::N << 42; - | ^^^^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `42_i32`, which would overflow | note: the lint level is defined here --> $DIR/lint-exceeding-bitshifts.rs:10:9 @@ -14,139 +14,139 @@ warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:22:13 | LL | let _ = x << 42; - | ^^^^^^^ attempt to shift left by 42_i32 which would overflow + | ^^^^^^^ attempt to shift left by `42_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:27:15 | LL | let n = 1u8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:29:15 | LL | let n = 1u16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:31:15 | LL | let n = 1u32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:33:15 | LL | let n = 1u64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:35:15 | LL | let n = 1i8 << 8; - | ^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:37:15 | LL | let n = 1i16 << 16; - | ^^^^^^^^^^ attempt to shift left by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:39:15 | LL | let n = 1i32 << 32; - | ^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:41:15 | LL | let n = 1i64 << 64; - | ^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:44:15 | LL | let n = 1u8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:46:15 | LL | let n = 1u16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:48:15 | LL | let n = 1u32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:50:15 | LL | let n = 1u64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:52:15 | LL | let n = 1i8 >> 8; - | ^^^^^^^^ attempt to shift right by 8_i32 which would overflow + | ^^^^^^^^ attempt to shift right by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:54:15 | LL | let n = 1i16 >> 16; - | ^^^^^^^^^^ attempt to shift right by 16_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `16_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:56:15 | LL | let n = 1i32 >> 32; - | ^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:58:15 | LL | let n = 1i64 >> 64; - | ^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:62:15 | LL | let n = n << 8; - | ^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:64:15 | LL | let n = 1u8 << -8; - | ^^^^^^^^^ attempt to shift left by -8_i32 which would overflow + | ^^^^^^^^^ attempt to shift left by `-8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:69:15 | LL | let n = 1u8 << (4+4); - | ^^^^^^^^^^^^ attempt to shift left by 8_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift left by `8_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:71:15 | LL | let n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:77:15 | LL | let n = 1_isize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: this arithmetic operation will overflow --> $DIR/lint-exceeding-bitshifts.rs:78:15 | LL | let n = 1_usize << BITS; - | ^^^^^^^^^^^^^^^ attempt to shift left by %BITS% which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift left by `%BITS%`, which would overflow warning: 24 warnings emitted diff --git a/src/test/ui/lint/lint-exceeding-bitshifts.rs b/src/test/ui/lint/lint-exceeding-bitshifts.rs index a76ca93f8e..d8774cb4df 100644 --- a/src/test/ui/lint/lint-exceeding-bitshifts.rs +++ b/src/test/ui/lint/lint-exceeding-bitshifts.rs @@ -4,7 +4,7 @@ //[opt_with_overflow_checks]compile-flags: -C overflow-checks=on -O // build-pass // ignore-pass (test emits codegen-time warnings and verifies that they are not errors) -// normalize-stderr-test "shift left by (64|32)_usize which" -> "shift left by %BITS% which" +// normalize-stderr-test "shift left by `(64|32)_usize`, which" -> "shift left by `%BITS%`, which" #![crate_type="lib"] #![warn(arithmetic_overflow, const_err)] diff --git a/src/test/ui/lint/lint-missing-doc.rs b/src/test/ui/lint/lint-missing-doc.rs index bab6f4e9e5..2297257919 100644 --- a/src/test/ui/lint/lint-missing-doc.rs +++ b/src/test/ui/lint/lint-missing-doc.rs @@ -2,7 +2,7 @@ // injected intrinsics by the compiler. #![deny(missing_docs)] #![allow(dead_code)] -#![feature(associated_type_defaults)] +#![feature(associated_type_defaults, extern_types)] //! Some garbage docs for the crate here #![doc="More garbage"] @@ -183,4 +183,21 @@ pub mod public_interface { pub use internal_impl::globbed::*; } +extern "C" { + /// dox + pub fn extern_fn_documented(f: f32) -> f32; + pub fn extern_fn_undocumented(f: f32) -> f32; + //~^ ERROR: missing documentation for a function + + /// dox + pub static EXTERN_STATIC_DOCUMENTED: u8; + pub static EXTERN_STATIC_UNDOCUMENTED: u8; + //~^ ERROR: missing documentation for a static + + /// dox + pub type ExternTyDocumented; + pub type ExternTyUndocumented; + //~^ ERROR: missing documentation for a foreign type +} + fn main() {} diff --git a/src/test/ui/lint/lint-missing-doc.stderr b/src/test/ui/lint/lint-missing-doc.stderr index 21da4fae4c..56f8fc10e8 100644 --- a/src/test/ui/lint/lint-missing-doc.stderr +++ b/src/test/ui/lint/lint-missing-doc.stderr @@ -118,5 +118,23 @@ error: missing documentation for a function LL | pub fn also_undocumented1() {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 19 previous errors +error: missing documentation for a function + --> $DIR/lint-missing-doc.rs:189:5 + | +LL | pub fn extern_fn_undocumented(f: f32) -> f32; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a static + --> $DIR/lint-missing-doc.rs:194:5 + | +LL | pub static EXTERN_STATIC_UNDOCUMENTED: u8; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: missing documentation for a foreign type + --> $DIR/lint-missing-doc.rs:199:5 + | +LL | pub type ExternTyUndocumented; + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 22 previous errors diff --git a/src/test/ui/lint/lint-owned-heap-memory.stderr b/src/test/ui/lint/lint-owned-heap-memory.stderr index 2c6b47e494..40310f9387 100644 --- a/src/test/ui/lint/lint-owned-heap-memory.stderr +++ b/src/test/ui/lint/lint-owned-heap-memory.stderr @@ -1,4 +1,4 @@ -error: type uses owned (Box type) pointers: std::boxed::Box +error: type uses owned (Box type) pointers: Box --> $DIR/lint-owned-heap-memory.rs:6:5 | LL | x: Box @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![forbid(box_pointers)] | ^^^^^^^^^^^^ -error: type uses owned (Box type) pointers: std::boxed::Box +error: type uses owned (Box type) pointers: Box --> $DIR/lint-owned-heap-memory.rs:10:29 | LL | let _x : Foo = Foo {x : box 10}; diff --git a/src/test/ui/lint/lint-unconditional-recursion.stderr b/src/test/ui/lint/lint-unconditional-recursion.stderr index 1770d71e2e..fb884e3129 100644 --- a/src/test/ui/lint/lint-unconditional-recursion.stderr +++ b/src/test/ui/lint/lint-unconditional-recursion.stderr @@ -149,7 +149,7 @@ error: function cannot return without recursing LL | fn deref(&self) -> &Baz { | ^^^^^^^^^^^^^^^^^^^^^^^ cannot return without recursing LL | self.as_ref() - | ---- recursive call site + | ------------- recursive call site | = help: a `loop` may express intention better if this is on purpose diff --git a/src/test/ui/lint/lint-uppercase-variables.rs b/src/test/ui/lint/lint-uppercase-variables.rs index a98b4f2fd4..b590fa697a 100644 --- a/src/test/ui/lint/lint-uppercase-variables.rs +++ b/src/test/ui/lint/lint-uppercase-variables.rs @@ -21,18 +21,18 @@ fn main() { match foo::Foo::Foo { Foo => {} //~^ ERROR variable `Foo` should have a snake case name -//~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` +//~^^ WARN `Foo` is named the same as one of the variants of the type `Foo` //~^^^ WARN unused variable: `Foo` } let Foo = foo::Foo::Foo; //~^ ERROR variable `Foo` should have a snake case name - //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo` //~^^^ WARN unused variable: `Foo` fn in_param(Foo: foo::Foo) {} //~^ ERROR variable `Foo` should have a snake case name - //~^^ WARN `Foo` is named the same as one of the variants of the type `foo::Foo` + //~^^ WARN `Foo` is named the same as one of the variants of the type `Foo` //~^^^ WARN unused variable: `Foo` test(1); diff --git a/src/test/ui/lint/lint-uppercase-variables.stderr b/src/test/ui/lint/lint-uppercase-variables.stderr index d476d856e2..71b24a835b 100644 --- a/src/test/ui/lint/lint-uppercase-variables.stderr +++ b/src/test/ui/lint/lint-uppercase-variables.stderr @@ -1,22 +1,22 @@ -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo` --> $DIR/lint-uppercase-variables.rs:22:9 | LL | Foo => {} - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + | ^^^ help: to match on the variant, qualify the path: `Foo::Foo` | = note: `#[warn(bindings_with_variant_name)]` on by default -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo` --> $DIR/lint-uppercase-variables.rs:28:9 | LL | let Foo = foo::Foo::Foo; - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + | ^^^ help: to match on the variant, qualify the path: `Foo::Foo` -warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `foo::Foo` +warning[E0170]: pattern binding `Foo` is named the same as one of the variants of the type `Foo` --> $DIR/lint-uppercase-variables.rs:33:17 | LL | fn in_param(Foo: foo::Foo) {} - | ^^^ help: to match on the variant, qualify the path: `foo::Foo::Foo` + | ^^^ help: to match on the variant, qualify the path: `Foo::Foo` warning: unused variable: `Foo` --> $DIR/lint-uppercase-variables.rs:22:9 diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs index 3cbc084eca..4ceb0c3da0 100644 --- a/src/test/ui/lint/opaque-ty-ffi-unsafe.rs +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.rs @@ -9,7 +9,7 @@ pub fn ret_closure() -> A { extern "C" { pub fn a(_: A); -//~^ ERROR `extern` block uses type `impl std::ops::Fn<()>`, which is not FFI-safe +//~^ ERROR `extern` block uses type `impl Fn<()>`, which is not FFI-safe } fn main() {} diff --git a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr index 06dfb7b8fb..9d46f6d936 100644 --- a/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr +++ b/src/test/ui/lint/opaque-ty-ffi-unsafe.stderr @@ -1,4 +1,4 @@ -error: `extern` block uses type `impl std::ops::Fn<()>`, which is not FFI-safe +error: `extern` block uses type `impl Fn<()>`, which is not FFI-safe --> $DIR/opaque-ty-ffi-unsafe.rs:11:17 | LL | pub fn a(_: A); diff --git a/src/test/ui/lint/uninitialized-zeroed.stderr b/src/test/ui/lint/uninitialized-zeroed.stderr index 3bf8a66ab0..de1b6c7617 100644 --- a/src/test/ui/lint/uninitialized-zeroed.stderr +++ b/src/test/ui/lint/uninitialized-zeroed.stderr @@ -285,7 +285,7 @@ note: references must be non-null (in this struct field) LL | struct RefPair((&'static i32, i32)); | ^^^^^^^^^^^^^^^^^^^ -error: the type `std::ptr::NonNull` does not permit zero-initialization +error: the type `NonNull` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:79:34 | LL | let _val: NonNull = mem::zeroed(); @@ -296,7 +296,7 @@ LL | let _val: NonNull = mem::zeroed(); | = note: `std::ptr::NonNull` must be non-null -error: the type `std::ptr::NonNull` does not permit being left uninitialized +error: the type `NonNull` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:80:34 | LL | let _val: NonNull = mem::uninitialized(); @@ -307,7 +307,7 @@ LL | let _val: NonNull = mem::uninitialized(); | = note: `std::ptr::NonNull` must be non-null -error: the type `*const dyn std::marker::Send` does not permit zero-initialization +error: the type `*const dyn Send` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:82:37 | LL | let _val: *const dyn Send = mem::zeroed(); @@ -318,7 +318,7 @@ LL | let _val: *const dyn Send = mem::zeroed(); | = note: the vtable of a wide raw pointer must be non-null -error: the type `*const dyn std::marker::Send` does not permit being left uninitialized +error: the type `*const dyn Send` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:83:37 | LL | let _val: *const dyn Send = mem::uninitialized(); @@ -406,7 +406,7 @@ LL | let _val: &'static [i32] = mem::transmute((0usize, 0usize)); | = note: references must be non-null -error: the type `std::num::NonZeroU32` does not permit zero-initialization +error: the type `NonZeroU32` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:101:32 | LL | let _val: NonZeroU32 = mem::transmute(0); @@ -417,7 +417,7 @@ LL | let _val: NonZeroU32 = mem::transmute(0); | = note: `std::num::NonZeroU32` must be non-null -error: the type `std::ptr::NonNull` does not permit zero-initialization +error: the type `NonNull` does not permit zero-initialization --> $DIR/uninitialized-zeroed.rs:104:34 | LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); @@ -428,7 +428,7 @@ LL | let _val: NonNull = MaybeUninit::zeroed().assume_init(); | = note: `std::ptr::NonNull` must be non-null -error: the type `std::ptr::NonNull` does not permit being left uninitialized +error: the type `NonNull` does not permit being left uninitialized --> $DIR/uninitialized-zeroed.rs:105:34 | LL | let _val: NonNull = MaybeUninit::uninit().assume_init(); diff --git a/src/test/ui/liveness/liveness-consts.rs b/src/test/ui/liveness/liveness-consts.rs new file mode 100644 index 0000000000..8fe2453ca2 --- /dev/null +++ b/src/test/ui/liveness/liveness-consts.rs @@ -0,0 +1,63 @@ +// check-pass +#![warn(unused)] +#![allow(unreachable_code)] + +pub static A: i32 = { + let mut i = 0; + let mut a = 0; //~ WARN variable `a` is assigned to, but never used + while i < 10 { + i += 1; + a += 1; + } + i +}; + +pub const B: u32 = { + let mut b = 1; + b += 1; //~ WARN value assigned to `b` is never read + b = 42; + b +}; + +pub enum E { + V1 = { + let e = 1; //~ WARN unused variable: `e` + 1 + }, + V2 = { + let _f = 10; + 2 + } +} + +pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + //~^ WARN unused variable: `s` + //~| WARN unused variable: `z` + x +} + +pub trait T { + const T: usize = { + let mut t = 10; + t = t + t; //~ WARN value assigned to `t` is never read + 20 + }; +} + +impl T for String { + const T: usize = { + let w = 10; //~ WARN unused variable: `w` + loop { + break; + let _ = w; + } + 44 + }; +} + +fn main() { + let _ = [(); { + let z = 42; //~ WARN unused variable: `z` + 35 + }]; +} diff --git a/src/test/ui/liveness/liveness-consts.stderr b/src/test/ui/liveness/liveness-consts.stderr new file mode 100644 index 0000000000..fa8a590a81 --- /dev/null +++ b/src/test/ui/liveness/liveness-consts.stderr @@ -0,0 +1,68 @@ +warning: variable `a` is assigned to, but never used + --> $DIR/liveness-consts.rs:7:9 + | +LL | let mut a = 0; + | ^^^^^ + | +note: the lint level is defined here + --> $DIR/liveness-consts.rs:2:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + = note: consider using `_a` instead + +warning: value assigned to `b` is never read + --> $DIR/liveness-consts.rs:17:5 + | +LL | b += 1; + | ^ + | +note: the lint level is defined here + --> $DIR/liveness-consts.rs:2:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_assignments)]` implied by `#[warn(unused)]` + = help: maybe it is overwritten before being read? + +warning: unused variable: `e` + --> $DIR/liveness-consts.rs:24:13 + | +LL | let e = 1; + | ^ help: if this is intentional, prefix it with an underscore: `_e` + +warning: unused variable: `s` + --> $DIR/liveness-consts.rs:33:24 + | +LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + | ^ help: if this is intentional, prefix it with an underscore: `_s` + +warning: unused variable: `z` + --> $DIR/liveness-consts.rs:33:55 + | +LL | pub fn f(x: [u8; { let s = 17; 100 }]) -> [u8; { let z = 18; 100 }] { + | ^ help: if this is intentional, prefix it with an underscore: `_z` + +warning: unused variable: `z` + --> $DIR/liveness-consts.rs:60:13 + | +LL | let z = 42; + | ^ help: if this is intentional, prefix it with an underscore: `_z` + +warning: value assigned to `t` is never read + --> $DIR/liveness-consts.rs:42:9 + | +LL | t = t + t; + | ^ + | + = help: maybe it is overwritten before being read? + +warning: unused variable: `w` + --> $DIR/liveness-consts.rs:49:13 + | +LL | let w = 10; + | ^ help: if this is intentional, prefix it with an underscore: `_w` + +warning: 8 warnings emitted + diff --git a/src/test/ui/liveness/liveness-derive.rs b/src/test/ui/liveness/liveness-derive.rs new file mode 100644 index 0000000000..1921d0d72b --- /dev/null +++ b/src/test/ui/liveness/liveness-derive.rs @@ -0,0 +1,38 @@ +// Test for interaction between #[automatically_derived] attribute used by +// built-in derives and lints generated by liveness pass. +// +// edition:2018 +// check-pass +#![warn(unused)] + +pub trait T: Sized { + const N: usize; + fn t(&self) -> Self; +} + +impl T for u32 { + const N: usize = { + let a = 0; //~ WARN unused variable: `a` + 4 + }; + + fn t(&self) -> Self { + let b = 16; //~ WARN unused variable: `b` + 0 + } +} + +#[automatically_derived] +impl T for i32 { + const N: usize = { + let c = 0; + 4 + }; + + fn t(&self) -> Self { + let d = 17; + 0 + } +} + +fn main() {} diff --git a/src/test/ui/liveness/liveness-derive.stderr b/src/test/ui/liveness/liveness-derive.stderr new file mode 100644 index 0000000000..c03d909918 --- /dev/null +++ b/src/test/ui/liveness/liveness-derive.stderr @@ -0,0 +1,21 @@ +warning: unused variable: `a` + --> $DIR/liveness-derive.rs:15:13 + | +LL | let a = 0; + | ^ help: if this is intentional, prefix it with an underscore: `_a` + | +note: the lint level is defined here + --> $DIR/liveness-derive.rs:6:9 + | +LL | #![warn(unused)] + | ^^^^^^ + = note: `#[warn(unused_variables)]` implied by `#[warn(unused)]` + +warning: unused variable: `b` + --> $DIR/liveness-derive.rs:20:13 + | +LL | let b = 16; + | ^ help: if this is intentional, prefix it with an underscore: `_b` + +warning: 2 warnings emitted + diff --git a/src/test/ui/liveness/liveness-move-call-arg.stderr b/src/test/ui/liveness/liveness-move-call-arg.stderr index ab4460a326..5ea5c40f2a 100644 --- a/src/test/ui/liveness/liveness-move-call-arg.stderr +++ b/src/test/ui/liveness/liveness-move-call-arg.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/liveness-move-call-arg.rs:9:14 | LL | let x: Box = box 25; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - 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 --git a/src/test/ui/liveness/liveness-move-in-loop.stderr b/src/test/ui/liveness/liveness-move-in-loop.stderr index 150c1ec82b..66b6373e45 100644 --- a/src/test/ui/liveness/liveness-move-in-loop.stderr +++ b/src/test/ui/liveness/liveness-move-in-loop.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `y` --> $DIR/liveness-move-in-loop.rs:11:25 | LL | let y: Box = box 42; - | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | x = y; | ^ value moved here, in previous iteration of loop diff --git a/src/test/ui/liveness/liveness-move-in-while.stderr b/src/test/ui/liveness/liveness-move-in-while.stderr index 45c00e8d6d..92e0f37252 100644 --- a/src/test/ui/liveness/liveness-move-in-while.stderr +++ b/src/test/ui/liveness/liveness-move-in-while.stderr @@ -22,7 +22,7 @@ error[E0382]: borrow of moved value: `y` --> $DIR/liveness-move-in-while.rs:7:24 | LL | let y: Box = box 42; - | - move occurs because `y` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `y` has type `Box`, which does not implement the `Copy` trait ... LL | println!("{}", y); | ^ value borrowed here after move diff --git a/src/test/ui/liveness/liveness-use-after-move.stderr b/src/test/ui/liveness/liveness-use-after-move.stderr index 383b89afaa..3977a3f413 100644 --- a/src/test/ui/liveness/liveness-use-after-move.stderr +++ b/src/test/ui/liveness/liveness-use-after-move.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/liveness-use-after-move.rs:6:20 | LL | let x: Box<_> = box 5; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | let y = x; | - value moved here LL | println!("{}", *x); diff --git a/src/test/ui/liveness/liveness-use-after-send.stderr b/src/test/ui/liveness/liveness-use-after-send.stderr index ccf9499f64..50ae98ca9b 100644 --- a/src/test/ui/liveness/liveness-use-after-send.stderr +++ b/src/test/ui/liveness/liveness-use-after-send.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `message` --> $DIR/liveness-use-after-send.rs:16:20 | LL | fn test00_start(ch: Chan>, message: Box, _count: Box) { - | ------- move occurs because `message` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ------- move occurs because `message` has type `Box`, which does not implement the `Copy` trait LL | send(ch, message); | ------- value moved here LL | println!("{}", message); diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.rs b/src/test/ui/macros/builtin-prelude-no-accidents.rs index ac82f343ac..01691a82dd 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.rs +++ b/src/test/ui/macros/builtin-prelude-no-accidents.rs @@ -2,7 +2,7 @@ // because macros with the same names are in prelude. fn main() { - env::current_dir; //~ ERROR use of undeclared type or module `env` - type A = panic::PanicInfo; //~ ERROR use of undeclared type or module `panic` - type B = vec::Vec; //~ ERROR use of undeclared type or module `vec` + env::current_dir; //~ ERROR use of undeclared crate or module `env` + type A = panic::PanicInfo; //~ ERROR use of undeclared crate or module `panic` + type B = vec::Vec; //~ ERROR use of undeclared crate or module `vec` } diff --git a/src/test/ui/macros/builtin-prelude-no-accidents.stderr b/src/test/ui/macros/builtin-prelude-no-accidents.stderr index 914e906df5..56af618d48 100644 --- a/src/test/ui/macros/builtin-prelude-no-accidents.stderr +++ b/src/test/ui/macros/builtin-prelude-no-accidents.stderr @@ -1,20 +1,20 @@ -error[E0433]: failed to resolve: use of undeclared type or module `env` +error[E0433]: failed to resolve: use of undeclared crate or module `env` --> $DIR/builtin-prelude-no-accidents.rs:5:5 | LL | env::current_dir; - | ^^^ use of undeclared type or module `env` + | ^^^ use of undeclared crate or module `env` -error[E0433]: failed to resolve: use of undeclared type or module `panic` +error[E0433]: failed to resolve: use of undeclared crate or module `panic` --> $DIR/builtin-prelude-no-accidents.rs:6:14 | LL | type A = panic::PanicInfo; - | ^^^^^ use of undeclared type or module `panic` + | ^^^^^ use of undeclared crate or module `panic` -error[E0433]: failed to resolve: use of undeclared type or module `vec` +error[E0433]: failed to resolve: use of undeclared crate or module `vec` --> $DIR/builtin-prelude-no-accidents.rs:7:14 | LL | type B = vec::Vec; - | ^^^ use of undeclared type or module `vec` + | ^^^ use of undeclared crate or module `vec` error: aborting due to 3 previous errors diff --git a/src/test/ui/macros/duplicate-builtin.rs b/src/test/ui/macros/duplicate-builtin.rs new file mode 100644 index 0000000000..35f0f42905 --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.rs @@ -0,0 +1,17 @@ +// compile-flags:--crate-type lib +#![feature(decl_macro)] +#![feature(rustc_attrs)] + +#[rustc_builtin_macro] +pub macro test($item:item) { +//~^ NOTE previously defined + /* compiler built-in */ +} + +mod inner { + #[rustc_builtin_macro] + pub macro test($item:item) { + //~^ ERROR attempted to define built-in macro more than once [E0773] + /* compiler built-in */ + } +} diff --git a/src/test/ui/macros/duplicate-builtin.stderr b/src/test/ui/macros/duplicate-builtin.stderr new file mode 100644 index 0000000000..58accea27b --- /dev/null +++ b/src/test/ui/macros/duplicate-builtin.stderr @@ -0,0 +1,21 @@ +error[E0773]: attempted to define built-in macro more than once + --> $DIR/duplicate-builtin.rs:13:5 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_____^ + | +note: previously defined here + --> $DIR/duplicate-builtin.rs:6:1 + | +LL | / pub macro test($item:item) { +LL | | +LL | | /* compiler built-in */ +LL | | } + | |_^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0773`. diff --git a/src/test/ui/macros/issue-68060.rs b/src/test/ui/macros/issue-68060.rs index 8772e98b6e..f82eb338f4 100644 --- a/src/test/ui/macros/issue-68060.rs +++ b/src/test/ui/macros/issue-68060.rs @@ -2,11 +2,13 @@ fn main() { (0..) .map( #[target_feature(enable = "")] - //~^ ERROR: the feature named `` is not valid for this target - //~| ERROR: `#[target_feature(..)]` can only be applied to `unsafe` functions + //~^ ERROR: attribute should be applied to a function + //~| ERROR: the feature named `` is not valid for this target + //~| NOTE: `` is not valid for this target #[track_caller] - //~^ ERROR: `#[track_caller]` requires Rust ABI + //~^ ERROR: `#[track_caller]` requires Rust ABI [E0737] |_| (), + //~^ NOTE: not a function ) .next(); } diff --git a/src/test/ui/macros/issue-68060.stderr b/src/test/ui/macros/issue-68060.stderr index b9b2f946c5..a01c3827bb 100644 --- a/src/test/ui/macros/issue-68060.stderr +++ b/src/test/ui/macros/issue-68060.stderr @@ -1,14 +1,11 @@ -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions +error: attribute should be applied to a function --> $DIR/issue-68060.rs:4:13 | LL | #[target_feature(enable = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ... LL | |_| (), - | ------ not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + | ------ not a function error: the feature named `` is not valid for this target --> $DIR/issue-68060.rs:4:30 @@ -17,12 +14,11 @@ LL | #[target_feature(enable = "")] | ^^^^^^^^^^^ `` is not valid for this target error[E0737]: `#[track_caller]` requires Rust ABI - --> $DIR/issue-68060.rs:7:13 + --> $DIR/issue-68060.rs:8:13 | LL | #[track_caller] | ^^^^^^^^^^^^^^^ error: aborting due to 3 previous errors -Some errors have detailed explanations: E0658, E0737. -For more information about an error, try `rustc --explain E0658`. +For more information about this error, try `rustc --explain E0737`. diff --git a/src/test/ui/macros/macro-comma-behavior.core.stderr b/src/test/ui/macros/macro-comma-behavior.core.stderr index 83a88ab3bd..dd0cac659f 100644 --- a/src/test/ui/macros/macro-comma-behavior.core.stderr +++ b/src/test/ui/macros/macro-comma-behavior.core.stderr @@ -1,41 +1,41 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:20:23 + --> $DIR/macro-comma-behavior.rs:21:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:23:23 + --> $DIR/macro-comma-behavior.rs:24:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:29:29 + --> $DIR/macro-comma-behavior.rs:30:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:32:29 + --> $DIR/macro-comma-behavior.rs:33:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:53:19 + --> $DIR/macro-comma-behavior.rs:54:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:71:21 + --> $DIR/macro-comma-behavior.rs:72:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:80:24 + --> $DIR/macro-comma-behavior.rs:81:24 | LL | write!(f, "{}",)?; | ^^ diff --git a/src/test/ui/macros/macro-comma-behavior.rs b/src/test/ui/macros/macro-comma-behavior.rs index 04714c65b5..0bfe068307 100644 --- a/src/test/ui/macros/macro-comma-behavior.rs +++ b/src/test/ui/macros/macro-comma-behavior.rs @@ -9,6 +9,7 @@ #[cfg(std)] use std::fmt; #[cfg(core)] use core::fmt; #[cfg(core)] #[lang = "eh_personality"] fn eh_personality() {} +#[cfg(core)] #[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; #[cfg(core)] #[lang = "panic_impl"] fn panic_impl(panic: &core::panic::PanicInfo) -> ! { loop {} } // (see documentation of the similarly-named test in run-pass) diff --git a/src/test/ui/macros/macro-comma-behavior.std.stderr b/src/test/ui/macros/macro-comma-behavior.std.stderr index 26445f2c5c..4372d89fbf 100644 --- a/src/test/ui/macros/macro-comma-behavior.std.stderr +++ b/src/test/ui/macros/macro-comma-behavior.std.stderr @@ -1,59 +1,59 @@ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:20:23 + --> $DIR/macro-comma-behavior.rs:21:23 | LL | assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:23:23 + --> $DIR/macro-comma-behavior.rs:24:23 | LL | assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:29:29 + --> $DIR/macro-comma-behavior.rs:30:29 | LL | debug_assert_eq!(1, 1, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:32:29 + --> $DIR/macro-comma-behavior.rs:33:29 | LL | debug_assert_ne!(1, 2, "{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:37:18 + --> $DIR/macro-comma-behavior.rs:38:18 | LL | eprint!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:49:18 + --> $DIR/macro-comma-behavior.rs:50:18 | LL | format!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:53:19 + --> $DIR/macro-comma-behavior.rs:54:19 | LL | format_args!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:60:17 + --> $DIR/macro-comma-behavior.rs:61:17 | LL | print!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:71:21 + --> $DIR/macro-comma-behavior.rs:72:21 | LL | unimplemented!("{}",); | ^^ error: 1 positional argument in format string, but no arguments were given - --> $DIR/macro-comma-behavior.rs:80:24 + --> $DIR/macro-comma-behavior.rs:81:24 | LL | write!(f, "{}",)?; | ^^ diff --git a/src/test/ui/macros/macro-inner-attributes.rs b/src/test/ui/macros/macro-inner-attributes.rs index 56a9023156..a8cda23075 100644 --- a/src/test/ui/macros/macro-inner-attributes.rs +++ b/src/test/ui/macros/macro-inner-attributes.rs @@ -15,6 +15,6 @@ test!(b, #[rustc_dummy] fn main() { a::bar(); - //~^ ERROR failed to resolve: use of undeclared type or module `a` + //~^ ERROR failed to resolve: use of undeclared crate or module `a` b::bar(); } diff --git a/src/test/ui/macros/macro-inner-attributes.stderr b/src/test/ui/macros/macro-inner-attributes.stderr index 5e20f106a9..8223220d9a 100644 --- a/src/test/ui/macros/macro-inner-attributes.stderr +++ b/src/test/ui/macros/macro-inner-attributes.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `a` +error[E0433]: failed to resolve: use of undeclared crate or module `a` --> $DIR/macro-inner-attributes.rs:17:5 | LL | a::bar(); - | ^ use of undeclared type or module `a` + | ^ use of undeclared crate or module `a` error: aborting due to previous error diff --git a/src/test/ui/macros/macro_path_as_generic_bound.stderr b/src/test/ui/macros/macro_path_as_generic_bound.stderr index 48c33575ad..00d954d24f 100644 --- a/src/test/ui/macros/macro_path_as_generic_bound.stderr +++ b/src/test/ui/macros/macro_path_as_generic_bound.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `m` +error[E0433]: failed to resolve: use of undeclared crate or module `m` --> $DIR/macro_path_as_generic_bound.rs:7:6 | LL | foo!(m::m2::A); - | ^ use of undeclared type or module `m` + | ^ use of undeclared crate or module `m` error: aborting due to previous error diff --git a/src/test/ui/macros/missing-comma.rs b/src/test/ui/macros/missing-comma.rs index 2002fed6c9..92f8a77950 100644 --- a/src/test/ui/macros/missing-comma.rs +++ b/src/test/ui/macros/missing-comma.rs @@ -17,7 +17,7 @@ macro_rules! check { fn main() { println!("{}" a); - //~^ ERROR expected token: `,` + //~^ ERROR expected `,`, found `a` foo!(a b); //~^ ERROR no rules expected the token `b` foo!(a, b, c, d e); diff --git a/src/test/ui/macros/missing-comma.stderr b/src/test/ui/macros/missing-comma.stderr index f96848f823..6da92bdea1 100644 --- a/src/test/ui/macros/missing-comma.stderr +++ b/src/test/ui/macros/missing-comma.stderr @@ -1,4 +1,4 @@ -error: expected token: `,` +error: expected `,`, found `a` --> $DIR/missing-comma.rs:19:19 | LL | println!("{}" a); diff --git a/src/test/ui/macros/same-sequence-span.stderr b/src/test/ui/macros/same-sequence-span.stderr index 65b67a9423..63b8b29d6c 100644 --- a/src/test/ui/macros/same-sequence-span.stderr +++ b/src/test/ui/macros/same-sequence-span.stderr @@ -17,15 +17,11 @@ LL | $(= $z:tt)* error: `$x:expr` may be followed by `$y:tt`, which is not allowed for `expr` fragments --> $DIR/same-sequence-span.rs:19:1 | -LL | proc_macro_sequence::make_foo!(); - | ^-------------------------------- - | | - | _in this macro invocation +LL | proc_macro_sequence::make_foo!(); + | ---------------------------------^^^^^^^^^^^^^ | | -LL | | -LL | | -LL | | fn main() {} -... | + | not allowed after `expr` fragments + | in this macro invocation | = note: allowed there are: `=>`, `,` or `;` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/macros/trace_faulty_macros.stderr b/src/test/ui/macros/trace_faulty_macros.stderr index aec9d1ab19..cecc942f47 100644 --- a/src/test/ui/macros/trace_faulty_macros.stderr +++ b/src/test/ui/macros/trace_faulty_macros.stderr @@ -60,7 +60,7 @@ LL | let a = pat_macro!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/trace_faulty_macros.rs:42:1 | LL | #[derive(Debug)] @@ -79,3 +79,4 @@ LL | let a = pat_macro!(); error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/macros/unknown-builtin.rs b/src/test/ui/macros/unknown-builtin.rs index a96b99ae4f..16f9139e64 100644 --- a/src/test/ui/macros/unknown-builtin.rs +++ b/src/test/ui/macros/unknown-builtin.rs @@ -1,4 +1,4 @@ -// error-pattern: cannot find a built-in macro with name `line` +// error-pattern: attempted to define built-in macro more than once #![feature(rustc_attrs)] @@ -6,7 +6,7 @@ macro_rules! unknown { () => () } //~ ERROR cannot find a built-in macro with name `unknown` #[rustc_builtin_macro] -macro_rules! line { () => () } +macro_rules! line { () => () } //~ NOTE previously defined here fn main() { line!(); diff --git a/src/test/ui/macros/unknown-builtin.stderr b/src/test/ui/macros/unknown-builtin.stderr index 4b650b2c47..7b04e05293 100644 --- a/src/test/ui/macros/unknown-builtin.stderr +++ b/src/test/ui/macros/unknown-builtin.stderr @@ -4,7 +4,7 @@ error: cannot find a built-in macro with name `unknown` LL | macro_rules! unknown { () => () } | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: cannot find a built-in macro with name `line` +error[E0773]: attempted to define built-in macro more than once --> $SRC_DIR/core/src/macros/mod.rs:LL:COL | LL | / macro_rules! line { @@ -13,6 +13,13 @@ LL | | /* compiler built-in */ LL | | }; LL | | } | |_____^ + | +note: previously defined here + --> $DIR/unknown-builtin.rs:9:1 + | +LL | macro_rules! line { () => () } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 2 previous errors +For more information about this error, try `rustc --explain E0773`. diff --git a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr index e8f96178d1..c4532a375a 100644 --- a/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr +++ b/src/test/ui/malformed/issue-69341-malformed-derive-inert.stderr @@ -4,7 +4,7 @@ error: traits in `#[derive(...)]` don't accept arguments LL | #[derive(parse())] | ^^ help: remove the arguments -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-69341-malformed-derive-inert.rs:8:5 | LL | path: (), @@ -24,3 +24,4 @@ LL | #[derive(parse())] error: aborting due to 4 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/malformed/malformed-derive-entry.stderr b/src/test/ui/malformed/malformed-derive-entry.stderr index 587fc5a5ae..63be8f9ca1 100644 --- a/src/test/ui/malformed/malformed-derive-entry.stderr +++ b/src/test/ui/malformed/malformed-derive-entry.stderr @@ -16,29 +16,29 @@ error: malformed `derive` attribute input LL | #[derive] | ^^^^^^^^^ help: missing traits to be derived: `#[derive(Trait1, Trait2, ...)]` -error[E0277]: the trait bound `Test1: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Test1: Clone` is not satisfied --> $DIR/malformed-derive-entry.rs:1:10 | LL | #[derive(Copy(Bad))] - | ^^^^ the trait `std::clone::Clone` is not implemented for `Test1` + | ^^^^ the trait `Clone` is not implemented for `Test1` | ::: $SRC_DIR/core/src/marker.rs:LL:COL | LL | pub trait Copy: Clone { - | ----- required by this bound in `std::marker::Copy` + | ----- required by this bound in `Copy` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `Test2: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Test2: Clone` is not satisfied --> $DIR/malformed-derive-entry.rs:6:10 | LL | #[derive(Copy="bad")] - | ^^^^ the trait `std::clone::Clone` is not implemented for `Test2` + | ^^^^ the trait `Clone` is not implemented for `Test2` | ::: $SRC_DIR/core/src/marker.rs:LL:COL | LL | pub trait Copy: Clone { - | ----- required by this bound in `std::marker::Copy` + | ----- required by this bound in `Copy` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/map-types.rs b/src/test/ui/map-types.rs index c355a0e420..89b5708750 100644 --- a/src/test/ui/map-types.rs +++ b/src/test/ui/map-types.rs @@ -15,5 +15,5 @@ fn main() { let x: Box> = box HashMap::new(); let x: Box> = x; let y: Box> = Box::new(x); - //~^ ERROR `std::boxed::Box>: Map` is not satisfied + //~^ ERROR `Box>: Map` is not satisfied } diff --git a/src/test/ui/map-types.stderr b/src/test/ui/map-types.stderr index 21dac1ab1e..71006e1f4e 100644 --- a/src/test/ui/map-types.stderr +++ b/src/test/ui/map-types.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `std::boxed::Box>: Map` is not satisfied +error[E0277]: the trait bound `Box>: Map` is not satisfied --> $DIR/map-types.rs:17:41 | LL | let y: Box> = Box::new(x); - | ^^^^^^^^^^^ the trait `Map` is not implemented for `std::boxed::Box>` + | ^^^^^^^^^^^ the trait `Map` is not implemented for `Box>` | = note: required for the cast to the object type `dyn Map` diff --git a/src/test/ui/match/const_non_normal_zst_ref_pattern.rs b/src/test/ui/match/const_non_normal_zst_ref_pattern.rs new file mode 100644 index 0000000000..a114fafb64 --- /dev/null +++ b/src/test/ui/match/const_non_normal_zst_ref_pattern.rs @@ -0,0 +1,9 @@ +// check-pass + +const FOO: isize = 10; +const ZST: &() = unsafe { std::mem::transmute(FOO) }; +fn main() { + match &() { + ZST => 9, + }; +} diff --git a/src/test/ui/match/issue-70972-dyn-trait.rs b/src/test/ui/match/issue-70972-dyn-trait.rs index a9b2699caf..97d161c59e 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.rs +++ b/src/test/ui/match/issue-70972-dyn-trait.rs @@ -4,7 +4,7 @@ fn main() { let a: &dyn Send = &7u32; match a { F => panic!(), - //~^ ERROR trait objects cannot be used in patterns + //~^ ERROR `&dyn Send` cannot be used in patterns _ => {} } } diff --git a/src/test/ui/match/issue-70972-dyn-trait.stderr b/src/test/ui/match/issue-70972-dyn-trait.stderr index a4e827357d..7581070ebc 100644 --- a/src/test/ui/match/issue-70972-dyn-trait.stderr +++ b/src/test/ui/match/issue-70972-dyn-trait.stderr @@ -1,4 +1,4 @@ -error: trait objects cannot be used in patterns +error: `&dyn Send` cannot be used in patterns --> $DIR/issue-70972-dyn-trait.rs:6:9 | LL | F => panic!(), diff --git a/src/test/ui/match/match-range-fail.rs b/src/test/ui/match/match-range-fail.rs index c0cdbe342a..e53c8463ef 100644 --- a/src/test/ui/match/match-range-fail.rs +++ b/src/test/ui/match/match-range-fail.rs @@ -2,17 +2,17 @@ fn main() { match "wow" { "bar" ..= "foo" => { } }; - //~^^ ERROR only char and numeric types are allowed in range + //~^^ ERROR only `char` and numeric types are allowed in range match "wow" { 10 ..= "what" => () }; - //~^^ ERROR only char and numeric types are allowed in range + //~^^ ERROR only `char` and numeric types are allowed in range match "wow" { true ..= "what" => {} }; - //~^^ ERROR only char and numeric types are allowed in range + //~^^ ERROR only `char` and numeric types are allowed in range match 5 { 'c' ..= 100 => { } diff --git a/src/test/ui/match/match-range-fail.stderr b/src/test/ui/match/match-range-fail.stderr index 64105dc73d..938c05ac73 100644 --- a/src/test/ui/match/match-range-fail.stderr +++ b/src/test/ui/match/match-range-fail.stderr @@ -1,4 +1,4 @@ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/match-range-fail.rs:3:9 | LL | "bar" ..= "foo" => { } @@ -7,7 +7,7 @@ LL | "bar" ..= "foo" => { } | | this is of type `&'static str` but it should be `char` or numeric | this is of type `&'static str` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/match-range-fail.rs:8:16 | LL | 10 ..= "what" => () @@ -15,7 +15,7 @@ LL | 10 ..= "what" => () | | | this is of type `{integer}` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/match-range-fail.rs:13:9 | LL | true ..= "what" => {} diff --git a/src/test/ui/match/pattern-deref-miscompile.rs b/src/test/ui/match/pattern-deref-miscompile.rs new file mode 100644 index 0000000000..caa6d184a9 --- /dev/null +++ b/src/test/ui/match/pattern-deref-miscompile.rs @@ -0,0 +1,46 @@ +// run-pass + +fn main() { + match b"." as &[u8] { + b"." if true => {}, + b"." => panic!(), + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b"." as &[u8] { + b"." if false => panic!(), + b"." => {}, + b".." => panic!(), + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if true => panic!(), // the miscompile caused this arm to be reached + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b".." as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => {}, + b"" => panic!(), + _ => panic!(), + } + match b"" as &[u8] { + b"." if true => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } + match b"" as &[u8] { + b"." if false => panic!(), + b"." => panic!(), + b".." => panic!(), + b"" => {}, + _ => panic!(), + } +} diff --git a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr index f3f3c47680..33e8282c9d 100644 --- a/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr +++ b/src/test/ui/methods/method-ambig-one-trait-unknown-int-type.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `std::vec::Vec` +error[E0282]: type annotations needed for `Vec` --> $DIR/method-ambig-one-trait-unknown-int-type.rs:24:17 | LL | let mut x = Vec::new(); | ----- ^^^^^^^^ cannot infer type for type parameter `T` | | - | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified + | consider giving `x` the explicit type `Vec`, where the type parameter `T` is specified error[E0308]: mismatched types --> $DIR/method-ambig-one-trait-unknown-int-type.rs:33:20 diff --git a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr index 1b354fc697..42802ba1d0 100644 --- a/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr +++ b/src/test/ui/methods/method-ambig-two-traits-cross-crate.stderr @@ -9,15 +9,15 @@ note: candidate #1 is defined in an impl of the trait `Me2` for the type `usize` | LL | impl Me2 for usize { fn me(&self) -> usize { *self } } | ^^^^^^^^^^^^^^^^^^^^^ - = note: candidate #2 is defined in an impl of the trait `ambig_impl_2_lib::Me` for the type `usize` + = note: candidate #2 is defined in an impl of the trait `Me` for the type `usize` help: disambiguate the associated function for candidate #1 | LL | fn main() { Me2::me(&1_usize); } | ^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | fn main() { ambig_impl_2_lib::Me::me(&1_usize); } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn main() { Me::me(&1_usize); } + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/methods/method-call-err-msg.stderr b/src/test/ui/methods/method-call-err-msg.stderr index 4678642dd6..b0d1bb9823 100644 --- a/src/test/ui/methods/method-call-err-msg.stderr +++ b/src/test/ui/methods/method-call-err-msg.stderr @@ -38,17 +38,17 @@ LL | pub struct Foo; | --------------- | | | method `take` not found for this - | doesn't satisfy `Foo: std::iter::Iterator` + | doesn't satisfy `Foo: Iterator` ... LL | .take() | ^^^^ method not found in `Foo` | = note: the method `take` exists but the following trait bounds were not satisfied: - `Foo: std::iter::Iterator` - which is required by `&mut Foo: std::iter::Iterator` + `Foo: Iterator` + which is required by `&mut Foo: Iterator` = 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: `std::iter::Iterator` + candidate #1: `Iterator` error[E0061]: this function takes 3 arguments but 0 arguments were supplied --> $DIR/method-call-err-msg.rs:21:7 diff --git a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr index 1bc7f30d04..08be7ee155 100644 --- a/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr +++ b/src/test/ui/methods/method-deref-to-same-trait-object-with-separate-params.stderr @@ -20,12 +20,12 @@ error[E0034]: multiple applicable items in scope LL | let z = x.foo(); | ^^^ multiple `foo` found | -note: candidate #1 is defined in an impl of the trait `internal::X` for the type `T` +note: candidate #1 is defined in an impl of the trait `X` for the type `T` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:43:9 | LL | fn foo(self: Smaht) -> u64 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `nuisance_foo::NuisanceFoo` for the type `T` +note: candidate #2 is defined in an impl of the trait `NuisanceFoo` for the type `T` --> $DIR/method-deref-to-same-trait-object-with-separate-params.rs:70:9 | LL | fn foo(self) {} @@ -37,12 +37,12 @@ LL | fn foo(&self) -> u8; | ^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | let z = internal::X::foo(x); - | ^^^^^^^^^^^^^^^^^^^ +LL | let z = X::foo(x); + | ^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | let z = nuisance_foo::NuisanceFoo::foo(x); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | let z = NuisanceFoo::foo(x); + | ^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #3 | LL | let z = FinalFoo::foo(x); diff --git a/src/test/ui/methods/method-missing-call.stderr b/src/test/ui/methods/method-missing-call.stderr index bc8a1c85e5..241c50d7ce 100644 --- a/src/test/ui/methods/method-missing-call.stderr +++ b/src/test/ui/methods/method-missing-call.stderr @@ -9,7 +9,7 @@ help: use parentheses to call the method LL | .get_x(); | ^^ -error[E0615]: attempted to take value of method `filter_map` on type `std::iter::Filter, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` +error[E0615]: attempted to take value of method `filter_map` on type `Filter, [closure@$DIR/method-missing-call.rs:27:20: 27:25]>, [closure@$DIR/method-missing-call.rs:28:23: 28:35]>` --> $DIR/method-missing-call.rs:29:16 | LL | .filter_map; diff --git a/src/test/ui/minus-string.rs b/src/test/ui/minus-string.rs index 946c587ce4..018f0ef9ac 100644 --- a/src/test/ui/minus-string.rs +++ b/src/test/ui/minus-string.rs @@ -1,3 +1,3 @@ -// error-pattern:cannot apply unary operator `-` to type `std::string::String` +// error-pattern:cannot apply unary operator `-` to type `String` fn main() { -"foo".to_string(); } diff --git a/src/test/ui/minus-string.stderr b/src/test/ui/minus-string.stderr index 3fbec7c89c..b429ad3046 100644 --- a/src/test/ui/minus-string.stderr +++ b/src/test/ui/minus-string.stderr @@ -1,4 +1,4 @@ -error[E0600]: cannot apply unary operator `-` to type `std::string::String` +error[E0600]: cannot apply unary operator `-` to type `String` --> $DIR/minus-string.rs:3:13 | LL | fn main() { -"foo".to_string(); } diff --git a/src/test/ui/mir/issue-71793-inline-args-storage.rs b/src/test/ui/mir/issue-71793-inline-args-storage.rs new file mode 100644 index 0000000000..87b2806d4e --- /dev/null +++ b/src/test/ui/mir/issue-71793-inline-args-storage.rs @@ -0,0 +1,16 @@ +// Verifies that inliner emits StorageLive & StorageDead when introducing +// temporaries for arguments, so that they don't become part of the generator. +// Regression test for #71793. +// +// check-pass +// edition:2018 +// compile-args: -Zmir-opt-level=2 + +#![crate_type = "lib"] + +pub async fn connect() {} + +pub async fn connect_many() { + Vec::::new().first().ok_or("").unwrap(); + connect().await; +} diff --git a/src/test/ui/mir/issue-76248.rs b/src/test/ui/mir/issue-76248.rs new file mode 100644 index 0000000000..b01a972785 --- /dev/null +++ b/src/test/ui/mir/issue-76248.rs @@ -0,0 +1,29 @@ +// This used to ICE during codegen after MIR inlining of g into f. +// The root cause was a missing fold of length constant in Rvalue::Repeat. +// Regression test for #76248. +// +// build-pass +// compile-flags: -Zmir-opt-level=2 + +const N: usize = 1; + +pub struct Elem { + pub x: [usize; N], + pub m: M, +} + +pub fn f() -> Elem<()> { + g(()) +} + +#[inline] +pub fn g(m: M) -> Elem { + Elem { + x: [0; N], + m, + } +} + +pub fn main() { + f(); +} diff --git a/src/test/ui/mir/issue-76740-copy-propagation.rs b/src/test/ui/mir/issue-76740-copy-propagation.rs new file mode 100644 index 0000000000..90999a3e55 --- /dev/null +++ b/src/test/ui/mir/issue-76740-copy-propagation.rs @@ -0,0 +1,30 @@ +// Regression test for issue #76740. +// run-pass +// compile-flags: -Zmir-opt-level=3 + +#[derive(Copy, Clone)] +pub struct V([usize; 4]); + +impl V { + fn new() -> Self { + V([0; 4]) + } + + #[inline(never)] + fn check(mut self) { + assert_eq!(self.0[0], 0); + self.0[0] = 1; + } +} + +fn main() { + let v = V::new(); + let mut i = 0; + while i != 10 { + // Copy propagation incorrectly assumed that Operand::Move does not + // mutate the local, and used the same v for each V::check call, + // rather than a copy. + v.check(); + i += 1; + } +} diff --git a/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs b/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs new file mode 100644 index 0000000000..e58ba50a9e --- /dev/null +++ b/src/test/ui/mir/issue-77359-simplify-arm-identity-.rs @@ -0,0 +1,35 @@ +// run-pass + +#![allow(dead_code)] + +#[derive(Debug)] +enum MyEnum { + Variant1(Vec), + Variant2, + Variant3, + Variant4, +} + +fn f(arg1: &bool, arg2: &bool, arg3: bool) -> MyStruct { + if *arg1 { + println!("{:?}", f(&arg2, arg2, arg3)); + MyStruct(None) + } else { + match if arg3 { Some(MyEnum::Variant3) } else { None } { + Some(t) => { + let ah = t; + return MyStruct(Some(ah)); + } + _ => MyStruct(None) + } + } +} + +#[derive(Debug)] +struct MyStruct(Option); + +fn main() { + let arg1 = true; + let arg2 = false; + f(&arg1, &arg2, true); +} diff --git a/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs b/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs new file mode 100644 index 0000000000..629b50dec6 --- /dev/null +++ b/src/test/ui/mir/mir_const_prop_tuple_field_reorder.rs @@ -0,0 +1,27 @@ +// compile-flags: -Z mir-opt-level=2 +// build-pass +#![crate_type="lib"] + +// This used to ICE: const-prop did not account for field reordering of scalar pairs, +// and would generate a tuple like `(0x1337, VariantBar): (FooEnum, isize)`, +// causing assertion failures in codegen when trying to read 0x1337 at the wrong type. + +pub enum FooEnum { + VariantBar, + VariantBaz, + VariantBuz, +} + +pub fn wrong_index() -> isize { + let (_, b) = id((FooEnum::VariantBar, 0x1337)); + b +} + +pub fn wrong_index_two() -> isize { + let (_, (_, b)) = id(((), (FooEnum::VariantBar, 0x1338))); + b +} + +fn id(x: T) -> T { + x +} diff --git a/src/test/ui/mir/mir_detects_invalid_ops.stderr b/src/test/ui/mir/mir_detects_invalid_ops.stderr index b4f74a52a7..0fe56f4172 100644 --- a/src/test/ui/mir/mir_detects_invalid_ops.stderr +++ b/src/test/ui/mir/mir_detects_invalid_ops.stderr @@ -2,7 +2,7 @@ error: this operation will panic at runtime --> $DIR/mir_detects_invalid_ops.rs:11:14 | LL | let _z = 1 / y; - | ^^^^^ attempt to divide 1_i32 by zero + | ^^^^^ attempt to divide `1_i32` by zero | = note: `#[deny(unconditional_panic)]` on by default @@ -10,7 +10,7 @@ error: this operation will panic at runtime --> $DIR/mir_detects_invalid_ops.rs:16:14 | LL | let _z = 1 % y; - | ^^^^^ attempt to calculate the remainder of 1_i32 with a divisor of zero + | ^^^^^ attempt to calculate the remainder of `1_i32` with a divisor of zero error: aborting due to 2 previous errors diff --git a/src/test/ui/mismatched_types/abridged.stderr b/src/test/ui/mismatched_types/abridged.stderr index c73130643d..b7564686cd 100644 --- a/src/test/ui/mismatched_types/abridged.stderr +++ b/src/test/ui/mismatched_types/abridged.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | fn a() -> Foo { | --- expected `Foo` because of return type LL | Some(Foo { bar: 1 }) - | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^^ expected struct `Foo`, found enum `Option` | = note: expected struct `Foo` - found enum `std::option::Option` + found enum `Option` error[E0308]: mismatched types --> $DIR/abridged.rs:20:5 @@ -24,14 +24,14 @@ error[E0308]: mismatched types --> $DIR/abridged.rs:24:5 | LL | fn b() -> Option { - | ----------- expected `std::option::Option` because of return type + | ----------- expected `Option` because of return type LL | Foo { bar: 1 } | ^^^^^^^^^^^^^^ | | - | expected enum `std::option::Option`, found struct `Foo` + | expected enum `Option`, found struct `Foo` | help: try using a variant of the expected enum: `Some(Foo { bar: 1 })` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found struct `Foo` error[E0308]: mismatched types @@ -52,46 +52,46 @@ error[E0308]: mismatched types --> $DIR/abridged.rs:39:5 | LL | fn d() -> X, String> { - | ---------------------------- expected `X, std::string::String>` because of return type + | ---------------------------- expected `X, String>` because of return type ... LL | x - | ^ expected struct `std::string::String`, found integer + | ^ expected struct `String`, found integer | - = note: expected struct `X, std::string::String>` + = note: expected struct `X, String>` found struct `X, {integer}>` error[E0308]: mismatched types --> $DIR/abridged.rs:50:5 | LL | fn e() -> X, String> { - | ---------------------------- expected `X, std::string::String>` because of return type + | ---------------------------- expected `X, String>` because of return type ... LL | x - | ^ expected struct `std::string::String`, found integer + | ^ expected struct `String`, found integer | - = note: expected struct `X, _>` + = note: expected struct `X, _>` found struct `X, _>` error[E0308]: mismatched types --> $DIR/abridged.rs:54:5 | LL | fn f() -> String { - | ------ expected `std::string::String` because of return type + | ------ expected `String` because of return type LL | 1+2 | ^^^ | | - | expected struct `std::string::String`, found integer + | expected struct `String`, found integer | help: try using a conversion method: `(1+2).to_string()` error[E0308]: mismatched types --> $DIR/abridged.rs:59:5 | LL | fn g() -> String { - | ------ expected `std::string::String` because of return type + | ------ expected `String` because of return type LL | -2 | ^^ | | - | expected struct `std::string::String`, found integer + | expected struct `String`, found integer | help: try using a conversion method: `(-2).to_string()` error: aborting due to 8 previous errors diff --git a/src/test/ui/mismatched_types/binops.rs b/src/test/ui/mismatched_types/binops.rs index 621599ddb8..12d4826649 100644 --- a/src/test/ui/mismatched_types/binops.rs +++ b/src/test/ui/mismatched_types/binops.rs @@ -1,8 +1,8 @@ fn main() { - 1 + Some(1); //~ ERROR cannot add `std::option::Option<{integer}>` to `{integer}` - 2 as usize - Some(1); //~ ERROR cannot subtract `std::option::Option<{integer}>` from `usize` + 1 + Some(1); //~ ERROR cannot add `Option<{integer}>` to `{integer}` + 2 as usize - Some(1); //~ ERROR cannot subtract `Option<{integer}>` from `usize` 3 * (); //~ ERROR cannot multiply `()` to `{integer}` 4 / ""; //~ ERROR cannot divide `{integer}` by `&str` - 5 < String::new(); //~ ERROR can't compare `{integer}` with `std::string::String` + 5 < String::new(); //~ ERROR can't compare `{integer}` with `String` 6 == Ok(1); //~ ERROR can't compare `{integer}` with `std::result::Result<{integer}, _>` } diff --git a/src/test/ui/mismatched_types/binops.stderr b/src/test/ui/mismatched_types/binops.stderr index 9dda44a856..227c7887fb 100644 --- a/src/test/ui/mismatched_types/binops.stderr +++ b/src/test/ui/mismatched_types/binops.stderr @@ -1,18 +1,18 @@ -error[E0277]: cannot add `std::option::Option<{integer}>` to `{integer}` +error[E0277]: cannot add `Option<{integer}>` to `{integer}` --> $DIR/binops.rs:2:7 | LL | 1 + Some(1); - | ^ no implementation for `{integer} + std::option::Option<{integer}>` + | ^ no implementation for `{integer} + Option<{integer}>` | - = help: the trait `std::ops::Add>` is not implemented for `{integer}` + = help: the trait `Add>` is not implemented for `{integer}` -error[E0277]: cannot subtract `std::option::Option<{integer}>` from `usize` +error[E0277]: cannot subtract `Option<{integer}>` from `usize` --> $DIR/binops.rs:3:16 | LL | 2 as usize - Some(1); - | ^ no implementation for `usize - std::option::Option<{integer}>` + | ^ no implementation for `usize - Option<{integer}>` | - = help: the trait `std::ops::Sub>` is not implemented for `usize` + = help: the trait `Sub>` is not implemented for `usize` error[E0277]: cannot multiply `()` to `{integer}` --> $DIR/binops.rs:4:7 @@ -20,7 +20,7 @@ error[E0277]: cannot multiply `()` to `{integer}` LL | 3 * (); | ^ no implementation for `{integer} * ()` | - = help: the trait `std::ops::Mul<()>` is not implemented for `{integer}` + = help: the trait `Mul<()>` is not implemented for `{integer}` error[E0277]: cannot divide `{integer}` by `&str` --> $DIR/binops.rs:5:7 @@ -28,15 +28,15 @@ error[E0277]: cannot divide `{integer}` by `&str` LL | 4 / ""; | ^ no implementation for `{integer} / &str` | - = help: the trait `std::ops::Div<&str>` is not implemented for `{integer}` + = help: the trait `Div<&str>` is not implemented for `{integer}` -error[E0277]: can't compare `{integer}` with `std::string::String` +error[E0277]: can't compare `{integer}` with `String` --> $DIR/binops.rs:6:7 | LL | 5 < String::new(); - | ^ no implementation for `{integer} < std::string::String` and `{integer} > std::string::String` + | ^ no implementation for `{integer} < String` and `{integer} > String` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `{integer}` + = help: the trait `PartialOrd` is not implemented for `{integer}` error[E0277]: can't compare `{integer}` with `std::result::Result<{integer}, _>` --> $DIR/binops.rs:7:7 @@ -44,7 +44,7 @@ error[E0277]: can't compare `{integer}` with `std::result::Result<{integer}, _>` LL | 6 == Ok(1); | ^^ no implementation for `{integer} == std::result::Result<{integer}, _>` | - = help: the trait `std::cmp::PartialEq>` is not implemented for `{integer}` + = help: the trait `PartialEq>` is not implemented for `{integer}` error: aborting due to 6 previous errors diff --git a/src/test/ui/mismatched_types/cast-rfc0401.stderr b/src/test/ui/mismatched_types/cast-rfc0401.stderr index 71abda5206..388c978d03 100644 --- a/src/test/ui/mismatched_types/cast-rfc0401.stderr +++ b/src/test/ui/mismatched_types/cast-rfc0401.stderr @@ -44,7 +44,7 @@ error[E0605]: non-primitive cast: `*const u8` as `(u32,)` LL | let _ = v as (u32,); | ^^^^^^^^^^^ an `as` expression can only be used to convert between primitive types or to coerce to a specific trait object -error[E0605]: non-primitive cast: `std::option::Option<&*const u8>` as `*const u8` +error[E0605]: non-primitive cast: `Option<&*const u8>` as `*const u8` --> $DIR/cast-rfc0401.rs:33:13 | LL | let _ = Some(&v) as *const u8; @@ -208,7 +208,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | let _ = fat_v as *const dyn Foo; | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: required for the cast to the object type `dyn Foo` error[E0277]: the size for values of type `str` cannot be known at compilation time @@ -217,7 +217,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let _ = a as *const dyn Foo; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required for the cast to the object type `dyn Foo` error[E0606]: casting `&{float}` as `f32` is invalid diff --git a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr index 664fa4bcaf..0af44d2119 100644 --- a/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-arg-type-mismatch.stderr @@ -28,8 +28,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` - found type `std::ops::Fn<(*mut &'a u32,)>` + = note: expected type `for<'r> Fn<(*mut &'r u32,)>` + found type `Fn<(*mut &'a u32,)>` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -37,8 +37,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(*mut &u32,)>` - found type `std::ops::FnOnce<(*mut &'a u32,)>` + = note: expected type `FnOnce<(*mut &u32,)>` + found type `FnOnce<(*mut &'a u32,)>` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -46,8 +46,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `for<'r> std::ops::Fn<(*mut &'r u32,)>` - found type `std::ops::Fn<(*mut &'a u32,)>` + = note: expected type `for<'r> Fn<(*mut &'r u32,)>` + found type `Fn<(*mut &'a u32,)>` error[E0308]: mismatched types --> $DIR/closure-arg-type-mismatch.rs:10:5 @@ -55,8 +55,8 @@ error[E0308]: mismatched types LL | baz(f); | ^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(*mut &u32,)>` - found type `std::ops::FnOnce<(*mut &'a u32,)>` + = note: expected type `FnOnce<(*mut &u32,)>` + found type `FnOnce<(*mut &'a u32,)>` error: aborting due to 7 previous errors diff --git a/src/test/ui/mismatched_types/closure-mismatch.stderr b/src/test/ui/mismatched_types/closure-mismatch.stderr index d6c17d125c..149f505dc6 100644 --- a/src/test/ui/mismatched_types/closure-mismatch.stderr +++ b/src/test/ui/mismatched_types/closure-mismatch.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | baz(|_| ()); | ^^^ one type is more general than the other | - = note: expected type `for<'r> std::ops::Fn<(&'r (),)>` - found type `std::ops::Fn<(&(),)>` + = note: expected type `for<'r> Fn<(&'r (),)>` + found type `Fn<(&(),)>` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/issue-36053-2.stderr b/src/test/ui/mismatched_types/issue-36053-2.stderr index 213b61bc6f..63c04bcd7b 100644 --- a/src/test/ui/mismatched_types/issue-36053-2.stderr +++ b/src/test/ui/mismatched_types/issue-36053-2.stderr @@ -1,24 +1,24 @@ -error[E0599]: no method named `count` found for struct `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope +error[E0599]: no method named `count` found for struct `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` in the current scope --> $DIR/issue-36053-2.rs:7:55 | LL | once::<&str>("str").fuse().filter(|a: &str| true).count(); - | -------------- ^^^^^ method not found in `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` + | -------------- ^^^^^ method not found in `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>` | | - | doesn't satisfy `<_ as std::ops::FnOnce<(&&str,)>>::Output = bool` - | doesn't satisfy `_: std::ops::FnMut<(&&str,)>` + | doesn't satisfy `<_ as FnOnce<(&&str,)>>::Output = bool` + | doesn't satisfy `_: FnMut<(&&str,)>` | ::: $SRC_DIR/core/src/iter/adapters/mod.rs:LL:COL | LL | pub struct Filter { - | ----------------------- doesn't satisfy `_: std::iter::Iterator` + | ----------------------- doesn't satisfy `_: Iterator` | = note: the method `count` exists but the following trait bounds were not satisfied: - `<[closure@$DIR/issue-36053-2.rs:7:39: 7:53] as std::ops::FnOnce<(&&str,)>>::Output = bool` - which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` - `[closure@$DIR/issue-36053-2.rs:7:39: 7:53]: std::ops::FnMut<(&&str,)>` - which is required by `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` - `std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` - which is required by `&mut std::iter::Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: std::iter::Iterator` + `<[closure@$DIR/issue-36053-2.rs:7:39: 7:53] as FnOnce<(&&str,)>>::Output = bool` + which is required by `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` + `[closure@$DIR/issue-36053-2.rs:7:39: 7:53]: FnMut<(&&str,)>` + which is required by `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` + `Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` + which is required by `&mut Filter>, [closure@$DIR/issue-36053-2.rs:7:39: 7:53]>: Iterator` error[E0631]: type mismatch in closure arguments --> $DIR/issue-36053-2.rs:7:32 diff --git a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr index d260addef4..5df35fa571 100644 --- a/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr +++ b/src/test/ui/mismatched_types/issue-74918-missing-lifetime.stderr @@ -13,15 +13,15 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/issue-74918-missing-lifetime.rs:11:5 | LL | fn next(&mut self) -> Option> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&mut ChunkingIterator) -> std::option::Option>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&mut ChunkingIterator) -> Option>` | ::: $SRC_DIR/core/src/iter/traits/iterator.rs:LL:COL | LL | fn next(&mut self) -> Option; - | ----------------------------------------- expected `fn(&mut ChunkingIterator) -> std::option::Option>` + | ----------------------------------------- expected `fn(&mut ChunkingIterator) -> Option>` | - = note: expected `fn(&mut ChunkingIterator) -> std::option::Option>` - found `fn(&mut ChunkingIterator) -> std::option::Option>` + = note: expected `fn(&mut ChunkingIterator) -> Option>` + found `fn(&mut ChunkingIterator) -> Option>` = help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` = help: verify the lifetime relationships in the `trait` and `impl` between the `self` argument, the other inputs and its output diff --git a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr index 5be7f5271d..4b86a1fede 100644 --- a/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr +++ b/src/test/ui/mismatched_types/issue-75361-mismatched-impl.stderr @@ -2,13 +2,13 @@ error: `impl` item signature doesn't match `trait` item signature --> $DIR/issue-75361-mismatched-impl.rs:18:3 | LL | fn adjacent_edges(&self) -> Box>; - | --------------------------------------------------------------------- expected `fn(&T) -> std::boxed::Box<(dyn MyTrait + 'static)>` + | --------------------------------------------------------------------- expected `fn(&T) -> Box<(dyn MyTrait + 'static)>` ... LL | fn adjacent_edges(&self) -> Box + '_> { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> std::boxed::Box>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ found `fn(&T) -> Box>` | - = note: expected `fn(&T) -> std::boxed::Box<(dyn MyTrait + 'static)>` - found `fn(&T) -> std::boxed::Box>` + = note: expected `fn(&T) -> Box<(dyn MyTrait + 'static)>` + found `fn(&T) -> Box>` help: the lifetime requirements from the `impl` do not correspond to the requirements in the `trait` --> $DIR/issue-75361-mismatched-impl.rs:12:55 | diff --git a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr index 5ab191b927..67f79a8147 100644 --- a/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr +++ b/src/test/ui/mismatched_types/method-help-unsatisfied-bound.stderr @@ -2,13 +2,13 @@ error[E0599]: no method named `unwrap` found for enum `std::result::Result<(), F --> $DIR/method-help-unsatisfied-bound.rs:5:7 | LL | struct Foo; - | ----------- doesn't satisfy `Foo: std::fmt::Debug` + | ----------- doesn't satisfy `Foo: Debug` ... LL | a.unwrap(); | ^^^^^^ method not found in `std::result::Result<(), Foo>` | = note: the method `unwrap` exists but the following trait bounds were not satisfied: - `Foo: std::fmt::Debug` + `Foo: Debug` error: aborting due to previous error diff --git a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr index d9dd186624..485fae6d4d 100644 --- a/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr +++ b/src/test/ui/mismatched_types/trait-bounds-cant-coerce.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/trait-bounds-cant-coerce.rs:13:7 | LL | a(x); - | ^ expected trait `Foo + std::marker::Send`, found trait `Foo` + | ^ expected trait `Foo + Send`, found trait `Foo` | - = note: expected struct `std::boxed::Box<(dyn Foo + std::marker::Send + 'static)>` - found struct `std::boxed::Box<(dyn Foo + 'static)>` + = note: expected struct `Box<(dyn Foo + Send + 'static)>` + found struct `Box<(dyn Foo + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/missing/missing-items/m2.stderr b/src/test/ui/missing/missing-items/m2.stderr index 64e9530e61..d18fb443aa 100644 --- a/src/test/ui/missing/missing-items/m2.stderr +++ b/src/test/ui/missing/missing-items/m2.stderr @@ -6,11 +6,11 @@ LL | impl m1::X for X { | = help: implement the missing item: `const CONSTANT: u32 = 42;` = help: implement the missing item: `type Type = Type;` - = help: implement the missing item: `fn method(&self, _: std::string::String) -> ::Type { todo!() }` - = help: implement the missing item: `fn method2(self: std::boxed::Box, _: std::string::String) -> ::Type { todo!() }` - = help: implement the missing item: `fn method3(_: &Self, _: std::string::String) -> ::Type { todo!() }` + = help: implement the missing item: `fn method(&self, _: String) -> ::Type { todo!() }` + = help: implement the missing item: `fn method2(self: Box, _: String) -> ::Type { todo!() }` + = help: implement the missing item: `fn method3(_: &Self, _: String) -> ::Type { todo!() }` = help: implement the missing item: `fn method4(&self, _: &Self) -> ::Type { todo!() }` - = help: implement the missing item: `fn method5(self: &std::boxed::Box) -> ::Type { todo!() }` + = help: implement the missing item: `fn method5(self: &Box) -> ::Type { todo!() }` error: aborting due to previous error diff --git a/src/test/ui/missing_debug_impls.rs b/src/test/ui/missing_debug_impls.rs index 72fcba5158..dc4dacfc46 100644 --- a/src/test/ui/missing_debug_impls.rs +++ b/src/test/ui/missing_debug_impls.rs @@ -4,7 +4,7 @@ use std::fmt; -pub enum A {} //~ ERROR type does not implement `std::fmt::Debug` +pub enum A {} //~ ERROR type does not implement `Debug` #[derive(Debug)] pub enum B {} @@ -17,7 +17,7 @@ impl fmt::Debug for C { } } -pub struct Foo; //~ ERROR type does not implement `std::fmt::Debug` +pub struct Foo; //~ ERROR type does not implement `Debug` #[derive(Debug)] pub struct Bar; diff --git a/src/test/ui/missing_debug_impls.stderr b/src/test/ui/missing_debug_impls.stderr index 51c65589b0..0538f207b4 100644 --- a/src/test/ui/missing_debug_impls.stderr +++ b/src/test/ui/missing_debug_impls.stderr @@ -1,4 +1,4 @@ -error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation +error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation --> $DIR/missing_debug_impls.rs:7:1 | LL | pub enum A {} @@ -10,7 +10,7 @@ note: the lint level is defined here LL | #![deny(missing_debug_implementations)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: type does not implement `std::fmt::Debug`; consider adding `#[derive(Debug)]` or a manual implementation +error: type does not implement `Debug`; consider adding `#[derive(Debug)]` or a manual implementation --> $DIR/missing_debug_impls.rs:20:1 | LL | pub struct Foo; diff --git a/src/test/ui/mod/mod_file_disambig.rs b/src/test/ui/mod/mod_file_disambig.rs index 7b182421d3..e5958af173 100644 --- a/src/test/ui/mod/mod_file_disambig.rs +++ b/src/test/ui/mod/mod_file_disambig.rs @@ -2,5 +2,5 @@ mod mod_file_disambig_aux; //~ ERROR file for module `mod_file_disambig_aux` fou fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/mod/mod_file_disambig.stderr b/src/test/ui/mod/mod_file_disambig.stderr index 2cb99b7514..3a3d2e2ddd 100644 --- a/src/test/ui/mod/mod_file_disambig.stderr +++ b/src/test/ui/mod/mod_file_disambig.stderr @@ -6,11 +6,11 @@ LL | mod mod_file_disambig_aux; | = help: delete or rename one of them to remove the ambiguity -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_disambig.rs:4:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/moves/issue-46099-move-in-macro.stderr b/src/test/ui/moves/issue-46099-move-in-macro.stderr index 83c99db870..db4c3979e3 100644 --- a/src/test/ui/moves/issue-46099-move-in-macro.stderr +++ b/src/test/ui/moves/issue-46099-move-in-macro.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `b` --> $DIR/issue-46099-move-in-macro.rs:14:12 | LL | let b = Box::new(true); - | - move occurs because `b` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `b` has type `Box`, which does not implement the `Copy` trait LL | test!({b}); | ^ | | diff --git a/src/test/ui/moves/issue-75904-move-closure-loop.rs b/src/test/ui/moves/issue-75904-move-closure-loop.rs new file mode 100644 index 0000000000..6641a0376c --- /dev/null +++ b/src/test/ui/moves/issue-75904-move-closure-loop.rs @@ -0,0 +1,15 @@ +// Regression test for issue #75904 +// Tests that we point at an expression +// that required the upvar to be moved, rather than just borrowed. + +struct NotCopy; + +fn main() { + let mut a = NotCopy; + loop { + || { //~ ERROR use of moved value + &mut a; + a; + }; + } +} diff --git a/src/test/ui/moves/issue-75904-move-closure-loop.stderr b/src/test/ui/moves/issue-75904-move-closure-loop.stderr new file mode 100644 index 0000000000..5e427a1fcd --- /dev/null +++ b/src/test/ui/moves/issue-75904-move-closure-loop.stderr @@ -0,0 +1,15 @@ +error[E0382]: use of moved value: `a` + --> $DIR/issue-75904-move-closure-loop.rs:10:9 + | +LL | let mut a = NotCopy; + | ----- move occurs because `a` has type `NotCopy`, which does not implement the `Copy` trait +LL | loop { +LL | || { + | ^^ value moved into closure here, in previous iteration of loop +LL | &mut a; +LL | a; + | - use occurs due to use in closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-deref-coercion.rs b/src/test/ui/moves/move-deref-coercion.rs new file mode 100644 index 0000000000..41154388f5 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.rs @@ -0,0 +1,33 @@ +use std::ops::Deref; + +struct NotCopy { + inner: bool +} + +impl NotCopy { + fn inner_method(&self) {} +} + +struct Foo { + first: NotCopy, + second: NotCopy +} + +impl Deref for Foo { + type Target = NotCopy; + fn deref(&self) -> &NotCopy { + &self.second + } +} + +fn use_field(val: Foo) { + let _val = val.first; + val.inner; //~ ERROR borrow of +} + +fn use_method(val: Foo) { + let _val = val.first; + val.inner_method(); //~ ERROR borrow of +} + +fn main() {} diff --git a/src/test/ui/moves/move-deref-coercion.stderr b/src/test/ui/moves/move-deref-coercion.stderr new file mode 100644 index 0000000000..e3bdf6d783 --- /dev/null +++ b/src/test/ui/moves/move-deref-coercion.stderr @@ -0,0 +1,35 @@ +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:25:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner; + | ^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error[E0382]: borrow of partially moved value: `val` + --> $DIR/move-deref-coercion.rs:30:5 + | +LL | let _val = val.first; + | --------- value partially moved here +LL | val.inner_method(); + | ^^^^^^^^^^^^^^^^^^ value borrowed here after partial move + | + = note: partial move occurs because `val.first` has type `NotCopy`, which does not implement the `Copy` trait + = note: borrow occurs due to deref coercion to `NotCopy` +note: deref defined here + --> $DIR/move-deref-coercion.rs:17:5 + | +LL | type Target = NotCopy; + | ^^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0382`. diff --git a/src/test/ui/moves/move-fn-self-receiver.stderr b/src/test/ui/moves/move-fn-self-receiver.stderr index 671d07a281..dd263c1e90 100644 --- a/src/test/ui/moves/move-fn-self-receiver.stderr +++ b/src/test/ui/moves/move-fn-self-receiver.stderr @@ -11,7 +11,7 @@ note: this function consumes the receiver `self` by taking ownership of it, whic | LL | fn into_iter(self) -> Self::IntoIter; | ^^^^ - = note: move occurs because `val.0` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because `val.0` has type `Vec`, which does not implement the `Copy` trait error[E0382]: use of moved value: `foo` --> $DIR/move-fn-self-receiver.rs:34:5 @@ -43,7 +43,7 @@ error[E0382]: use of moved value: `boxed_foo` --> $DIR/move-fn-self-receiver.rs:42:5 | LL | let boxed_foo = Box::new(Foo); - | --------- move occurs because `boxed_foo` has type `std::boxed::Box`, which does not implement the `Copy` trait + | --------- move occurs because `boxed_foo` has type `Box`, which does not implement the `Copy` trait LL | boxed_foo.use_box_self(); | -------------- `boxed_foo` moved due to this method call LL | boxed_foo; @@ -59,7 +59,7 @@ error[E0382]: use of moved value: `pin_box_foo` --> $DIR/move-fn-self-receiver.rs:46:5 | LL | let pin_box_foo = Box::pin(Foo); - | ----------- move occurs because `pin_box_foo` has type `std::pin::Pin>`, which does not implement the `Copy` trait + | ----------- move occurs because `pin_box_foo` has type `Pin>`, which does not implement the `Copy` trait LL | pin_box_foo.use_pin_box_self(); | ------------------ `pin_box_foo` moved due to this method call LL | pin_box_foo; @@ -85,7 +85,7 @@ error[E0382]: use of moved value: `rc_foo` --> $DIR/move-fn-self-receiver.rs:55:5 | LL | let rc_foo = Rc::new(Foo); - | ------ move occurs because `rc_foo` has type `std::rc::Rc`, which does not implement the `Copy` trait + | ------ move occurs because `rc_foo` has type `Rc`, which does not implement the `Copy` trait LL | rc_foo.use_rc_self(); | ------------- `rc_foo` moved due to this method call LL | rc_foo; @@ -117,7 +117,7 @@ error[E0382]: use of moved value: `implicit_into_iter` --> $DIR/move-fn-self-receiver.rs:63:5 | LL | let implicit_into_iter = vec![true]; - | ------------------ move occurs because `implicit_into_iter` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ------------------ move occurs because `implicit_into_iter` has type `Vec`, which does not implement the `Copy` trait LL | for _val in implicit_into_iter {} | ------------------ | | @@ -130,7 +130,7 @@ error[E0382]: use of moved value: `explicit_into_iter` --> $DIR/move-fn-self-receiver.rs:67:5 | LL | let explicit_into_iter = vec![true]; - | ------------------ move occurs because `explicit_into_iter` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ------------------ move occurs because `explicit_into_iter` has type `Vec`, which does not implement the `Copy` trait LL | for _val in explicit_into_iter.into_iter() {} | ----------- `explicit_into_iter` moved due to this method call LL | explicit_into_iter; diff --git a/src/test/ui/moves/move-guard-same-consts.stderr b/src/test/ui/moves/move-guard-same-consts.stderr index 0945fbe68a..5fc8a54993 100644 --- a/src/test/ui/moves/move-guard-same-consts.stderr +++ b/src/test/ui/moves/move-guard-same-consts.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-guard-same-consts.rs:20:24 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, 2) if take(x) => (), | - value moved here diff --git a/src/test/ui/moves/move-in-guard-1.stderr b/src/test/ui/moves/move-in-guard-1.stderr index 542fd16986..d894209f51 100644 --- a/src/test/ui/moves/move-in-guard-1.stderr +++ b/src/test/ui/moves/move-in-guard-1.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-1.rs:10:24 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (1, _) if take(x) => (), | - value moved here diff --git a/src/test/ui/moves/move-in-guard-2.stderr b/src/test/ui/moves/move-in-guard-2.stderr index 00d89f5507..a067d43389 100644 --- a/src/test/ui/moves/move-in-guard-2.stderr +++ b/src/test/ui/moves/move-in-guard-2.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/move-in-guard-2.rs:10:24 | LL | let x: Box<_> = box 1; - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait ... LL | (_, 2) if take(x) => (), | ^ diff --git a/src/test/ui/moves/move-out-of-tuple-field.stderr b/src/test/ui/moves/move-out-of-tuple-field.stderr index 888ef3352e..bb4eb76772 100644 --- a/src/test/ui/moves/move-out-of-tuple-field.stderr +++ b/src/test/ui/moves/move-out-of-tuple-field.stderr @@ -6,7 +6,7 @@ LL | let y = x.0; LL | let z = x.0; | ^^^ value used here after move | - = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.0` has type `Box`, which does not implement the `Copy` trait error[E0382]: use of moved value: `x.0` --> $DIR/move-out-of-tuple-field.rs:12:13 @@ -16,7 +16,7 @@ LL | let y = x.0; LL | let z = x.0; | ^^^ value used here after move | - = note: move occurs because `x.0` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `x.0` has type `Box`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr index aa0e9c7f68..11e9456958 100644 --- a/src/test/ui/moves/moves-based-on-type-access-to-field.stderr +++ b/src/test/ui/moves/moves-based-on-type-access-to-field.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-access-to-field.rs:11:12 | LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | consume(x.into_iter().next().unwrap()); | ----------- `x` moved due to this method call LL | touch(&x[0]); diff --git a/src/test/ui/moves/moves-based-on-type-block-bad.stderr b/src/test/ui/moves/moves-based-on-type-block-bad.stderr index 12b87c54b9..a9ac9d63a9 100644 --- a/src/test/ui/moves/moves-based-on-type-block-bad.stderr +++ b/src/test/ui/moves/moves-based-on-type-block-bad.stderr @@ -8,7 +8,7 @@ LL | box E::Bar(x) => println!("{}", x.to_string()), | - | | | data moved here - | move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr index 3a05a1305b..acb0932f6d 100644 --- a/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr +++ b/src/test/ui/moves/moves-based-on-type-capture-clause-bad.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-capture-clause-bad.rs:8:20 | LL | let x = "Hello world!".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | thread::spawn(move|| { | ------ value moved into closure here LL | println!("{}", x); diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs index b070671cb2..4417fb926d 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.rs @@ -10,7 +10,7 @@ fn foo(node: Box) -> isize { Some(right) => consume(right), None => 0 }; - consume(node) + r //~ ERROR use of moved value: `node` + consume(node) + r //~ ERROR use of partially moved value: `node` } fn consume(v: Box) -> isize { diff --git a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr index 952985fcdd..f7e17815b6 100644 --- a/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr +++ b/src/test/ui/moves/moves-based-on-type-cyclic-types-issue-4821.stderr @@ -1,13 +1,13 @@ -error[E0382]: use of moved value: `node` +error[E0382]: use of partially moved value: `node` --> $DIR/moves-based-on-type-cyclic-types-issue-4821.rs:13:13 | LL | Some(right) => consume(right), - | ----- value moved here + | ----- value partially moved here ... LL | consume(node) + r | ^^^^ value used here after partial move | - = note: move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `Box`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `node.next.0` | LL | Some(ref right) => consume(right), diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs index 0b44ca56ce..d256e18b6c 100644 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.rs @@ -6,7 +6,7 @@ fn touch(_a: &A) {} fn f00() { let x = "hi".to_string(); - //~^ NOTE move occurs because `x` has type `std::string::String` + //~^ NOTE move occurs because `x` has type `String` let _y = Foo { f:x }; //~^ NOTE value moved here touch(&x); //~ ERROR borrow of moved value: `x` @@ -15,7 +15,7 @@ fn f00() { fn f05() { let x = "hi".to_string(); - //~^ NOTE move occurs because `x` has type `std::string::String` + //~^ NOTE move occurs because `x` has type `String` let _y = Foo { f:(((x))) }; //~^ NOTE value moved here touch(&x); //~ ERROR borrow of moved value: `x` diff --git a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr index d7a7ceabf8..ee7971691a 100644 --- a/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr +++ b/src/test/ui/moves/moves-based-on-type-distribute-copy-over-paren.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:12:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | LL | let _y = Foo { f:x }; | - value moved here @@ -14,7 +14,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-distribute-copy-over-paren.rs:21:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | LL | let _y = Foo { f:(((x))) }; | ------- value moved here diff --git a/src/test/ui/moves/moves-based-on-type-exprs.stderr b/src/test/ui/moves/moves-based-on-type-exprs.stderr index 95a591b225..46940cf493 100644 --- a/src/test/ui/moves/moves-based-on-type-exprs.stderr +++ b/src/test/ui/moves/moves-based-on-type-exprs.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:12:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = Foo { f:x }; | - value moved here LL | touch(&x); @@ -12,7 +12,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:18:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = (x, 3); | - value moved here LL | touch(&x); @@ -22,7 +22,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:35:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | x | - value moved here @@ -34,7 +34,7 @@ error[E0382]: borrow of moved value: `y` --> $DIR/moves-based-on-type-exprs.rs:36:11 | LL | let y = "ho".to_string(); - | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `y` has type `String`, which does not implement the `Copy` trait ... LL | y | - value moved here @@ -46,7 +46,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:46:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | true => x, | - value moved here @@ -58,7 +58,7 @@ error[E0382]: borrow of moved value: `y` --> $DIR/moves-based-on-type-exprs.rs:47:11 | LL | let y = "ho".to_string(); - | - move occurs because `y` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `y` has type `String`, which does not implement the `Copy` trait ... LL | false => y | - value moved here @@ -70,7 +70,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:58:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | _ if guard(x) => 10, | - value moved here @@ -82,7 +82,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:65:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = [x]; | - value moved here LL | touch(&x); @@ -92,7 +92,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:71:11 | LL | let x = "hi".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = vec![x]; | - value moved here LL | touch(&x); @@ -102,7 +102,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:77:11 | LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let _y = x.into_iter().next().unwrap(); | ----------- `x` moved due to this method call LL | touch(&x); @@ -118,7 +118,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/moves-based-on-type-exprs.rs:83:11 | LL | let x = vec!["hi".to_string()]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let _y = [x.into_iter().next().unwrap(); 1]; | ----------- `x` moved due to this method call LL | touch(&x); diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.rs b/src/test/ui/moves/moves-based-on-type-match-bindings.rs index 1290d4a25a..4fb9b40e87 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.rs +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.rs @@ -13,9 +13,9 @@ fn f10() { Foo {f} => {} }; - touch(&x); //~ ERROR borrow of moved value: `x` + touch(&x); //~ ERROR borrow of partially moved value: `x` //~^ value borrowed here after partial move - //~| move occurs because `x.f` has type `std::string::String` + //~| partial move occurs because `x.f` has type `String` } fn main() {} diff --git a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr index 322999a1f0..ad1a2db8b5 100644 --- a/src/test/ui/moves/moves-based-on-type-match-bindings.stderr +++ b/src/test/ui/moves/moves-based-on-type-match-bindings.stderr @@ -1,13 +1,13 @@ -error[E0382]: borrow of moved value: `x` +error[E0382]: borrow of partially moved value: `x` --> $DIR/moves-based-on-type-match-bindings.rs:16:11 | LL | Foo {f} => {} - | - value moved here + | - value partially moved here ... LL | touch(&x); | ^^ value borrowed here after partial move | - = note: move occurs because `x.f` has type `std::string::String`, which does not implement the `Copy` trait + = note: partial move occurs because `x.f` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index fafd377c12..462bbd7be5 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure LL | let i = box 3; | - captured outer variable LL | let _f = to_fn(|| test(i)); - | ^ move occurs because `i` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `i` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-tuple.stderr b/src/test/ui/moves/moves-based-on-type-tuple.stderr index 2e1ddbdf57..a52c023e20 100644 --- a/src/test/ui/moves/moves-based-on-type-tuple.stderr +++ b/src/test/ui/moves/moves-based-on-type-tuple.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/moves-based-on-type-tuple.rs:4:13 | LL | fn dup(x: Box) -> Box<(Box,Box)> { - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | box (x, x) | - ^ value used here after move | | diff --git a/src/test/ui/moves/moves-sru-moved-field.stderr b/src/test/ui/moves/moves-sru-moved-field.stderr index a012c2d9b7..cf7213637c 100644 --- a/src/test/ui/moves/moves-sru-moved-field.stderr +++ b/src/test/ui/moves/moves-sru-moved-field.stderr @@ -6,7 +6,7 @@ LL | let _b = Foo {noncopyable: g, ..f}; LL | let _c = Foo {noncopyable: h, ..f}; | ^^^^^^^^^^^^^^^^^^^^^^^^^ value used here after move | - = note: move occurs because `f.moved` has type `std::boxed::Box`, which does not implement the `Copy` trait + = note: move occurs because `f.moved` has type `Box`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/mut/mut-cross-borrowing.stderr b/src/test/ui/mut/mut-cross-borrowing.stderr index c262d1336a..b77813f8af 100644 --- a/src/test/ui/mut/mut-cross-borrowing.stderr +++ b/src/test/ui/mut/mut-cross-borrowing.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | f(x) | ^ | | - | expected `&mut isize`, found struct `std::boxed::Box` + | expected `&mut isize`, found struct `Box` | help: consider mutably borrowing here: `&mut x` | = note: expected mutable reference `&mut isize` - found struct `std::boxed::Box<{integer}>` + found struct `Box<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/mut/mutable-enum-indirect.stderr b/src/test/ui/mut/mutable-enum-indirect.stderr index 9decba790d..3be6acb41a 100644 --- a/src/test/ui/mut/mutable-enum-indirect.stderr +++ b/src/test/ui/mut/mutable-enum-indirect.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(&x); | ^^^ `NoSync` cannot be shared between threads safely | - = help: within `&Foo`, the trait `std::marker::Sync` is not implemented for `NoSync` + = help: within `&Foo`, the trait `Sync` is not implemented for `NoSync` = note: required because it appears within the type `Foo` = note: required because it appears within the type `&Foo` diff --git a/src/test/ui/mutexguard-sync.rs b/src/test/ui/mutexguard-sync.rs index 8e1370041d..b564183831 100644 --- a/src/test/ui/mutexguard-sync.rs +++ b/src/test/ui/mutexguard-sync.rs @@ -9,5 +9,5 @@ fn main() let m = Mutex::new(Cell::new(0i32)); let guard = m.lock().unwrap(); test_sync(guard); - //~^ ERROR `std::cell::Cell` cannot be shared between threads safely [E0277] + //~^ ERROR `Cell` cannot be shared between threads safely [E0277] } diff --git a/src/test/ui/mutexguard-sync.stderr b/src/test/ui/mutexguard-sync.stderr index 8b5362490b..588c32a755 100644 --- a/src/test/ui/mutexguard-sync.stderr +++ b/src/test/ui/mutexguard-sync.stderr @@ -1,14 +1,14 @@ -error[E0277]: `std::cell::Cell` cannot be shared between threads safely +error[E0277]: `Cell` cannot be shared between threads safely --> $DIR/mutexguard-sync.rs:11:15 | LL | fn test_sync(_t: T) {} | ---- required by this bound in `test_sync` ... LL | test_sync(guard); - | ^^^^^ `std::cell::Cell` cannot be shared between threads safely + | ^^^^^ `Cell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` - = note: required because of the requirements on the impl of `std::marker::Sync` for `std::sync::MutexGuard<'_, std::cell::Cell>` + = help: the trait `Sync` is not implemented for `Cell` + = note: required because of the requirements on the impl of `Sync` for `MutexGuard<'_, Cell>` error: aborting due to previous error diff --git a/src/test/ui/never_type/issue-13352.stderr b/src/test/ui/never_type/issue-13352.stderr index 58ac74be3e..93c792a72e 100644 --- a/src/test/ui/never_type/issue-13352.stderr +++ b/src/test/ui/never_type/issue-13352.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `()` to `usize` LL | 2_usize + (loop {}); | ^ no implementation for `usize + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `usize` + = help: the trait `Add<()>` is not implemented for `usize` error: aborting due to previous error diff --git a/src/test/ui/never_type/issue-2149.stderr b/src/test/ui/never_type/issue-2149.stderr index 3cdd6372ec..58fe2edb1e 100644 --- a/src/test/ui/never_type/issue-2149.stderr +++ b/src/test/ui/never_type/issue-2149.stderr @@ -1,10 +1,10 @@ -error[E0277]: cannot add `std::vec::Vec` to `()` +error[E0277]: cannot add `Vec` to `()` --> $DIR/issue-2149.rs:8:33 | LL | for elt in self { r = r + f(*elt); } - | ^ no implementation for `() + std::vec::Vec` + | ^ no implementation for `() + Vec` | - = help: the trait `std::ops::Add>` is not implemented for `()` + = help: the trait `Add>` is not implemented for `()` error[E0599]: no method named `bind` found for array `[&str; 1]` in the current scope --> $DIR/issue-2149.rs:13:12 diff --git a/src/test/ui/never_type/issue-51506.stderr b/src/test/ui/never_type/issue-51506.stderr index 73865a9b5a..c54cbe9b4d 100644 --- a/src/test/ui/never_type/issue-51506.stderr +++ b/src/test/ui/never_type/issue-51506.stderr @@ -7,7 +7,7 @@ LL | type Out: Iterator; LL | default type Out = !; | ^^^^^^^^^^^^^^^^^^^^^ `!` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `!` + = help: the trait `Iterator` is not implemented for `!` error: aborting due to previous error diff --git a/src/test/ui/nll/cannot-move-block-spans.stderr b/src/test/ui/nll/cannot-move-block-spans.stderr index 7db5d731ac..56a5cdff07 100644 --- a/src/test/ui/nll/cannot-move-block-spans.stderr +++ b/src/test/ui/nll/cannot-move-block-spans.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let x = { *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -13,7 +13,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let y = unsafe { *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -22,37 +22,37 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let z = loop { break *r; }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array +error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:11:15 | LL | let x = { arr[0] }; | ^^^^^^ | | | cannot move out of here - | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&arr[0]` -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array +error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:12:22 | LL | let y = unsafe { arr[0] }; | ^^^^^^ | | | cannot move out of here - | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&arr[0]` -error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array +error[E0508]: cannot move out of type `[String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:13:26 | LL | let z = loop { break arr[0]; }; | ^^^^^^ | | | cannot move out of here - | move occurs because `arr[_]` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `arr[_]` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&arr[0]` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -61,7 +61,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let x = { let mut u = 0; u += 1; *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -70,7 +70,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let y = unsafe { let mut u = 0; u += 1; *r }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference @@ -79,7 +79,7 @@ error[E0507]: cannot move out of `*r` which is behind a shared reference LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; | ^^ | | - | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `*r` has type `String`, which does not implement the `Copy` trait | help: consider borrowing here: `&*r` error: aborting due to 9 previous errors diff --git a/src/test/ui/nll/closure-access-spans.stderr b/src/test/ui/nll/closure-access-spans.stderr index 4a8086905b..ccc043a189 100644 --- a/src/test/ui/nll/closure-access-spans.stderr +++ b/src/test/ui/nll/closure-access-spans.stderr @@ -60,7 +60,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:35:5 | LL | fn closure_imm_capture_moved(mut x: String) { - | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || x.len(); @@ -72,7 +72,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:40:5 | LL | fn closure_mut_capture_moved(mut x: String) { - | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || x = String::new(); @@ -84,7 +84,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-access-spans.rs:45:5 | LL | fn closure_unique_capture_moved(x: &mut String) { - | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `&mut String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || *x = String::new(); @@ -96,7 +96,7 @@ error[E0382]: use of moved value: `x` --> $DIR/closure-access-spans.rs:50:5 | LL | fn closure_move_capture_moved(x: &mut String) { - | - move occurs because `x` has type `&mut std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `&mut String`, which does not implement the `Copy` trait LL | let r = x; | - value moved here LL | || x; diff --git a/src/test/ui/nll/closure-move-spans.stderr b/src/test/ui/nll/closure-move-spans.stderr index 972dbc6a61..0446ef7b06 100644 --- a/src/test/ui/nll/closure-move-spans.stderr +++ b/src/test/ui/nll/closure-move-spans.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/closure-move-spans.rs:5:13 | LL | fn move_after_move(x: String) { - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | || x; | -- - variable moved due to use in closure | | @@ -14,7 +14,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-move-spans.rs:10:13 | LL | fn borrow_after_move(x: String) { - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | || x; | -- - variable moved due to use in closure | | @@ -26,7 +26,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/closure-move-spans.rs:15:13 | LL | fn borrow_mut_after_move(mut x: String) { - | ----- move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | ----- move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | || x; | -- - variable moved due to use in closure | | diff --git a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr index f0d169f419..799ed89dcc 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument-callee.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's, 't0> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) i32)), (), diff --git a/src/test/ui/nll/closure-requirements/escape-argument.stderr b/src/test/ui/nll/closure-requirements/escape-argument.stderr index e251e69997..a094fc4517 100644 --- a/src/test/ui/nll/closure-requirements/escape-argument.stderr +++ b/src/test/ui/nll/closure-requirements/escape-argument.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | let mut closure = expect_sig(|p, y| *p = y); | ^^^^^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) mut &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)), (), diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr index 36257700be..1a82583761 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-nested.stderr @@ -4,7 +4,7 @@ note: external requirements LL | let mut closure1 = || p = &y; | ^^^^^^^^^ | - = note: defining type: test::{{closure}}#0::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0}::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), @@ -22,7 +22,7 @@ LL | | closure1(); LL | | }; | |_________^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), diff --git a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr index d1c64fac3c..29fd796882 100644 --- a/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr +++ b/src/test/ui/nll/closure-requirements/escape-upvar-ref.stderr @@ -4,7 +4,7 @@ note: external requirements LL | let mut closure = || p = &y; | ^^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, extern "rust-call" fn(()), (&'_#1r i32, &'_#2r mut &'_#3r i32), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr index 549ebb78d7..c4f4facae1 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-fail-no-postdom.stderr @@ -8,7 +8,7 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#3r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), @@ -21,9 +21,9 @@ error: lifetime may not live long enough --> $DIR/propagate-approximated-fail-no-postdom.rs:46:13 | LL | |_outlives1, _outlives2, _outlives3, x, y| { - | ---------- ---------- has type `std::cell::Cell<&'2 &'_#3r u32>` + | ---------- ---------- has type `Cell<&'2 &'_#3r u32>` | | - | has type `std::cell::Cell<&'_#1r &'1 u32>` + | has type `Cell<&'_#1r &'1 u32>` ... LL | demand_y(x, y, p) | ^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr index 346b4af6ca..c1450564c4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-ref.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr index 3b1769ed3a..e7b8dff4e7 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-comparing-against-free.stderr @@ -8,7 +8,7 @@ LL | | LL | | }) | |_____^ | - = note: defining type: case1::{{closure}}#0 with closure substs [ + = note: defining type: case1::{closure#0} with closure substs [ i32, for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), (), @@ -47,7 +47,7 @@ LL | | cell_x.set(cell_a.get()); // forces 'a: 'x, implies 'a = 'static LL | | }) | |_____^ | - = note: defining type: case2::{{closure}}#0 with closure substs [ + = note: defining type: case2::{closure#0} with closure substs [ i32, for<'r> extern "rust-call" fn((std::cell::Cell<&'_#1r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr index b167dafff0..c7e68d02dc 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-no-bound.stderr @@ -10,7 +10,7 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t1)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t2)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr index 91aacc3dff..abbc76eaf4 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-shorter-to-static-wrong-bound.stderr @@ -10,7 +10,7 @@ LL | | demand_y(x, y, x.get()) LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&'_#2r &ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr index ae44770862..c91b514a79 100644 --- a/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-approximated-val.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr index 256446a6e8..4ddf6f8323 100644 --- a/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-despite-same-free-region.stderr @@ -8,7 +8,7 @@ LL | | demand_y(x, y, p) LL | | }, | |_________^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::cell::Cell<&'_#1r &ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#2r u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('r)) u32>, std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr index 5c156d0d1e..6dc6f45680 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-no-bounds.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>)), (), @@ -21,9 +21,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-no-bounds.rs:37:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives, x, y| { - | --------- - has type `&'_#7r std::cell::Cell<&'1 u32>` + | --------- - has type `&'_#7r Cell<&'1 u32>` | | - | has type `&'_#5r std::cell::Cell<&'2 &'_#1r u32>` + | has type `&'_#5r Cell<&'2 &'_#1r u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr index 46e3f2e75f..6bcada5c26 100644 --- a/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-fail-to-approximate-longer-wrong-bounds.stderr @@ -9,7 +9,7 @@ LL | | LL | | }); | |_____^ | - = note: defining type: supply::{{closure}}#0 with closure substs [ + = note: defining type: supply::{closure#0} with closure substs [ i16, for<'r, 's, 't0, 't1, 't2, 't3> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) &'_#1r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t0)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) &'_#2r u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t2)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('s)) u32>, &ReLateBound(DebruijnIndex(0), BrNamed('t3)) std::cell::Cell<&ReLateBound(DebruijnIndex(0), BrNamed('t1)) u32>)), (), @@ -21,9 +21,9 @@ error: lifetime may not live long enough --> $DIR/propagate-fail-to-approximate-longer-wrong-bounds.rs:41:9 | LL | establish_relationships(&cell_a, &cell_b, |_outlives1, _outlives2, x, y| { - | ---------- ---------- has type `&'_#8r std::cell::Cell<&'2 &'_#2r u32>` + | ---------- ---------- has type `&'_#8r Cell<&'2 &'_#2r u32>` | | - | has type `&'_#6r std::cell::Cell<&'1 &'_#1r u32>` + | has type `&'_#6r Cell<&'1 &'_#1r u32>` LL | // Only works if 'x: 'y: LL | demand_y(x, y, x.get()) | ^^^^^^^^^^^^^^^^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr index ef94147289..4b860a5505 100644 --- a/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr +++ b/src/test/ui/nll/closure-requirements/propagate-from-trait-match.stderr @@ -11,7 +11,7 @@ LL | | require(value); LL | | }); | |_____^ | - = note: defining type: supply::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: supply::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((T,)), (), diff --git a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr index 2a382030f9..1da6c6d2c6 100644 --- a/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr +++ b/src/test/ui/nll/closure-requirements/return-wrong-bound-region.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | expect_sig(|a, b| b); // ought to return `a` | ^^^^^^^^ | - = note: defining type: test::{{closure}}#0 with closure substs [ + = note: defining type: test::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((&ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, &ReLateBound(DebruijnIndex(0), BrNamed('s)) i32)) -> &ReLateBound(DebruijnIndex(0), BrNamed('r)) i32, (), diff --git a/src/test/ui/nll/closures-in-loops.stderr b/src/test/ui/nll/closures-in-loops.stderr index 0b15d9bcfe..37638a93d7 100644 --- a/src/test/ui/nll/closures-in-loops.stderr +++ b/src/test/ui/nll/closures-in-loops.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/closures-in-loops.rs:6:9 | LL | fn repreated_move(x: String) { - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | for i in 0..10 { LL | || x; | ^^ - use occurs due to use in closure diff --git a/src/test/ui/nll/guarantor-issue-46974.stderr b/src/test/ui/nll/guarantor-issue-46974.stderr index 80df393598..361466c4d5 100644 --- a/src/test/ui/nll/guarantor-issue-46974.stderr +++ b/src/test/ui/nll/guarantor-issue-46974.stderr @@ -13,7 +13,7 @@ error[E0621]: explicit lifetime required in the type of `s` --> $DIR/guarantor-issue-46974.rs:15:5 | LL | fn bar(s: &Box<(i32,)>) -> &'static i32 { - | ------------ help: add explicit lifetime `'static` to the type of `s`: `&'static std::boxed::Box<(i32,)>` + | ------------ help: add explicit lifetime `'static` to the type of `s`: `&'static Box<(i32,)>` LL | // FIXME(#46983): error message should be better LL | &s.0 | ^^^^ lifetime `'static` required diff --git a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr index 9e69262b38..77fa484c21 100644 --- a/src/test/ui/nll/issue-21232-partial-init-and-use.stderr +++ b/src/test/ui/nll/issue-21232-partial-init-and-use.stderr @@ -16,7 +16,7 @@ error[E0382]: assign to part of moved value: `s` LL | let mut s: S = S::new(); drop(s); | ----- - value moved here | | - | move occurs because `s` has type `S>`, which does not implement the `Copy` trait + | move occurs because `s` has type `S>`, which does not implement the `Copy` trait LL | s.x = 10; s.y = Box::new(20); | ^^^^^^^^ value partially assigned here after move @@ -26,7 +26,7 @@ error[E0382]: assign to part of moved value: `t` LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here | | - | move occurs because `t` has type `(u32, std::boxed::Box)`, which does not implement the `Copy` trait + | move occurs because `t` has type `(u32, Box)`, which does not implement the `Copy` trait LL | t.0 = 10; t.1 = Box::new(20); | ^^^^^^^^ value partially assigned here after move @@ -48,7 +48,7 @@ error[E0382]: assign to part of moved value: `s` LL | let mut s: S = S::new(); drop(s); | ----- - value moved here | | - | move occurs because `s` has type `S>`, which does not implement the `Copy` trait + | move occurs because `s` has type `S>`, which does not implement the `Copy` trait LL | s.x = 10; | ^^^^^^^^ value partially assigned here after move @@ -58,7 +58,7 @@ error[E0382]: assign to part of moved value: `t` LL | let mut t: T = (0, Box::new(0)); drop(t); | ----- - value moved here | | - | move occurs because `t` has type `(u32, std::boxed::Box)`, which does not implement the `Copy` trait + | move occurs because `t` has type `(u32, Box)`, which does not implement the `Copy` trait LL | t.0 = 10; | ^^^^^^^^ value partially assigned here after move @@ -94,7 +94,7 @@ LL | let mut q: Q> = Q::new(S::new()); drop(q.r); LL | q.r.f.x = 10; q.r.f.y = Box::new(20); | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` --> $DIR/issue-21232-partial-init-and-use.rs:197:5 @@ -104,7 +104,7 @@ LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); LL | q.r.f.0 = 10; q.r.f.1 = Box::new(20); | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R<(u32, std::boxed::Box)>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: assign to part of possibly-uninitialized variable: `q` --> $DIR/issue-21232-partial-init-and-use.rs:204:5 @@ -126,7 +126,7 @@ LL | let mut q: Q> = Q::new(S::new()); drop(q.r); LL | q.r.f.x = 10; | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R>>`, which does not implement the `Copy` trait error[E0382]: assign to part of moved value: `q.r` --> $DIR/issue-21232-partial-init-and-use.rs:225:5 @@ -136,7 +136,7 @@ LL | let mut q: Q = Q::new((0, Box::new(0))); drop(q.r); LL | q.r.f.0 = 10; | ^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `q.r` has type `R<(u32, std::boxed::Box)>`, which does not implement the `Copy` trait + = note: move occurs because `q.r` has type `R<(u32, Box)>`, which does not implement the `Copy` trait error[E0381]: assign to part of possibly-uninitialized variable: `q` --> $DIR/issue-21232-partial-init-and-use.rs:232:5 @@ -154,7 +154,7 @@ error[E0382]: assign to part of moved value: `c` --> $DIR/issue-21232-partial-init-and-use.rs:257:13 | LL | let mut c = (1, "".to_owned()); - | ----- move occurs because `c` has type `(i32, std::string::String)`, which does not implement the `Copy` trait + | ----- move occurs because `c` has type `(i32, String)`, which does not implement the `Copy` trait LL | match c { LL | c2 => { | -- value moved here @@ -165,7 +165,7 @@ error[E0382]: assign to part of moved value: `c` --> $DIR/issue-21232-partial-init-and-use.rs:267:13 | LL | let mut c = (1, (1, "".to_owned())); - | ----- move occurs because `c` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait + | ----- move occurs because `c` has type `(i32, (i32, String))`, which does not implement the `Copy` trait LL | match c { LL | c2 => { | -- value moved here @@ -180,7 +180,7 @@ LL | c2 => { LL | ((c.1).1).0 = 3; | ^^^^^^^^^^^^^^^ value partially assigned here after move | - = note: move occurs because `c.1` has type `(i32, (i32, std::string::String))`, which does not implement the `Copy` trait + = note: move occurs because `c.1` has type `(i32, (i32, String))`, which does not implement the `Copy` trait error: aborting due to 23 previous errors diff --git a/src/test/ui/nll/issue-50716.stderr b/src/test/ui/nll/issue-50716.stderr index 74c33df37a..3dee3345db 100644 --- a/src/test/ui/nll/issue-50716.stderr +++ b/src/test/ui/nll/issue-50716.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | let _x = *s; | ^^ lifetime mismatch | - = note: expected type `std::marker::Sized` - found type `std::marker::Sized` + = note: expected type `Sized` + found type `Sized` note: the lifetime `'a` as defined on the function body at 9:8... --> $DIR/issue-50716.rs:9:8 | diff --git a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr index 1a1250ff93..c0a17a67ee 100644 --- a/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr +++ b/src/test/ui/nll/issue-52059-report-when-borrow-and-drop-conflict.stderr @@ -35,7 +35,7 @@ LL | let p = s.url; p | ^^^^^ | | | cannot move out of here - | move occurs because `s.url` has type `&mut std::string::String`, which does not implement the `Copy` trait + | move occurs because `s.url` has type `&mut String`, which does not implement the `Copy` trait | help: consider borrowing here: `&s.url` error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/issue-52086.stderr b/src/test/ui/nll/issue-52086.stderr index e9aa7939f7..3b2dae9b72 100644 --- a/src/test/ui/nll/issue-52086.stderr +++ b/src/test/ui/nll/issue-52086.stderr @@ -2,13 +2,13 @@ error[E0507]: cannot move out of an `Rc` --> $DIR/issue-52086.rs:8:10 | LL | drop(x.field); - | ^^^^^^^ move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^^^^^ move occurs because value has type `Vec`, which does not implement the `Copy` trait error[E0507]: cannot move out of an `Arc` --> $DIR/issue-52086.rs:12:10 | LL | drop(y.field); - | ^^^^^^^ move occurs because value has type `std::vec::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 2 previous errors diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr index 57b9dc1f0b..67115a5ccd 100644 --- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` LL | let x = (vec![22], vec![44]); | - captured outer variable LL | expect_fn(|| drop(x.0)); - | ^^^ move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^^^ move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/issue-53807.stderr b/src/test/ui/nll/issue-53807.stderr index 4f36a4ccab..6767f7cd61 100644 --- a/src/test/ui/nll/issue-53807.stderr +++ b/src/test/ui/nll/issue-53807.stderr @@ -4,7 +4,7 @@ error[E0382]: use of moved value LL | if let Some(thing) = maybe { | ^^^^^ value moved here, in previous iteration of loop | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: move occurs because value has type `Vec`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `maybe.0` | LL | if let Some(ref thing) = maybe { diff --git a/src/test/ui/nll/issue-54556-stephaneyfx.stderr b/src/test/ui/nll/issue-54556-stephaneyfx.stderr index 77065f0b8d..bfb0eb74a5 100644 --- a/src/test/ui/nll/issue-54556-stephaneyfx.stderr +++ b/src/test/ui/nll/issue-54556-stephaneyfx.stderr @@ -10,7 +10,7 @@ LL | } | - | | | `stmt` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::iter::Map, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>` + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Map, [closure@$DIR/issue-54556-stephaneyfx.rs:28:14: 28:23]>` | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped diff --git a/src/test/ui/nll/match-cfg-fake-edges.stderr b/src/test/ui/nll/match-cfg-fake-edges.stderr index 06fe564ac6..4b3817929f 100644 --- a/src/test/ui/nll/match-cfg-fake-edges.stderr +++ b/src/test/ui/nll/match-cfg-fake-edges.stderr @@ -8,7 +8,7 @@ error[E0382]: use of moved value: `x` --> $DIR/match-cfg-fake-edges.rs:35:13 | LL | let x = String::new(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | false if { drop(x); true } => 1, | - value moved here diff --git a/src/test/ui/nll/match-guards-always-borrow.stderr b/src/test/ui/nll/match-guards-always-borrow.stderr index 15f94043b4..df6d65056a 100644 --- a/src/test/ui/nll/match-guards-always-borrow.stderr +++ b/src/test/ui/nll/match-guards-always-borrow.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `foo` in pattern guard LL | (|| { let bar = foo; bar.take() })(); | ^^ --- | | | - | | move occurs because `foo` has type `&mut std::option::Option<&i32>`, which does not implement the `Copy` trait + | | move occurs because `foo` has type `&mut Option<&i32>`, which does not implement the `Copy` trait | | move occurs due to use in closure | move out of `foo` occurs here | diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr index d4a0e45648..0df326425a 100644 --- a/src/test/ui/nll/move-errors.stderr +++ b/src/test/ui/nll/move-errors.stderr @@ -52,7 +52,7 @@ LL | let A(s) = *a; | - ^^ help: consider borrowing here: `&*a` | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `D`, which implements the `Drop` trait --> $DIR/move-errors.rs:44:19 @@ -61,7 +61,7 @@ LL | let C(D(s)) = c; | - ^ cannot move out of here | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*a` which is behind a shared reference --> $DIR/move-errors.rs:51:9 @@ -95,7 +95,7 @@ LL | B::U(D(s)) => (), | - | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `D`, which implements the `Drop` trait --> $DIR/move-errors.rs:92:11 @@ -107,7 +107,7 @@ LL | (D(s), &t) => (), | - | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error[E0507]: cannot move out of `*x.1` which is behind a shared reference --> $DIR/move-errors.rs:92:11 @@ -119,7 +119,7 @@ LL | (D(s), &t) => (), | - | | | data moved here - | move occurs because `t` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `t` has type `String`, which does not implement the `Copy` trait error[E0509]: cannot move out of type `F`, which implements the `Drop` trait --> $DIR/move-errors.rs:102:11 @@ -144,7 +144,7 @@ LL | Ok(s) | Err(s) => (), | - | | | data moved here - | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait + | move occurs because `s` has type `String`, which does not implement the `Copy` trait error: aborting due to 14 previous errors diff --git a/src/test/ui/nll/move-subpaths-moves-root.rs b/src/test/ui/nll/move-subpaths-moves-root.rs index e7caf89e78..d266c6bb65 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.rs +++ b/src/test/ui/nll/move-subpaths-moves-root.rs @@ -1,5 +1,5 @@ fn main() { let x = (vec![1, 2, 3], ); drop(x.0); - drop(x); //~ ERROR use of moved value + drop(x); //~ ERROR use of partially moved value } diff --git a/src/test/ui/nll/move-subpaths-moves-root.stderr b/src/test/ui/nll/move-subpaths-moves-root.stderr index 7030d5b330..ae9287f922 100644 --- a/src/test/ui/nll/move-subpaths-moves-root.stderr +++ b/src/test/ui/nll/move-subpaths-moves-root.stderr @@ -1,12 +1,12 @@ -error[E0382]: use of moved value: `x` +error[E0382]: use of partially moved value: `x` --> $DIR/move-subpaths-moves-root.rs:4:10 | LL | drop(x.0); - | --- value moved here + | --- value partially moved here LL | drop(x); | ^ value used here after partial move | - = note: move occurs because `x.0` has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: partial move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/nll/trait-associated-constant.stderr b/src/test/ui/nll/trait-associated-constant.stderr index 5158420c73..2af5b2a2e0 100644 --- a/src/test/ui/nll/trait-associated-constant.stderr +++ b/src/test/ui/nll/trait-associated-constant.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | const AC: Option<&'c str> = None; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ lifetime mismatch | - = note: expected enum `std::option::Option<&'b str>` - found enum `std::option::Option<&'c str>` + = note: expected enum `Option<&'b str>` + found enum `Option<&'c str>` note: the lifetime `'c` as defined on the impl at 20:18... --> $DIR/trait-associated-constant.rs:20:18 | diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs index 20af0fbdc8..28010e198d 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.rs @@ -23,7 +23,7 @@ where T: Iterator, { with_signature(x, |mut y| Box::new(y.next())) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } #[rustc_regions] @@ -40,7 +40,7 @@ where T: 'b + Iterator, { with_signature(x, |mut y| Box::new(y.next())) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } #[rustc_regions] diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr index 38e59ae3e2..983d6a06af 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), @@ -26,13 +26,13 @@ LL | | } | = note: defining type: no_region::<'_#1r, T> -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:25:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... note: external requirements --> $DIR/projection-no-regions-closure.rs:34:23 @@ -40,7 +40,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#2r)>, (), @@ -67,7 +67,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: wrong_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), @@ -89,13 +89,13 @@ LL | | } | = note: defining type: wrong_region::<'_#1r, '_#2r, T> -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-closure.rs:42:23 | LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... note: external requirements --> $DIR/projection-no-regions-closure.rs:52:23 @@ -103,7 +103,7 @@ note: external requirements LL | with_signature(x, |mut y| Box::new(y.next())) | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn Anything + '_#3r)>, (), diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs index 64073bec8a..c9989fb426 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.rs @@ -11,7 +11,7 @@ where T: Iterator, { Box::new(x.next()) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } fn correct_region<'a, T>(mut x: T) -> Box @@ -26,7 +26,7 @@ where T: 'b + Iterator, { Box::new(x.next()) - //~^ ERROR the associated type `::Item` may not live long enough + //~^ ERROR the associated type `::Item` may not live long enough } fn outlives_region<'a, 'b, T>(mut x: T) -> Box diff --git a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr index b0338de933..c4df04b99b 100644 --- a/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr +++ b/src/test/ui/nll/ty-outlives/projection-no-regions-fn.stderr @@ -1,18 +1,18 @@ -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-fn.rs:13:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... -error[E0309]: the associated type `::Item` may not live long enough +error[E0309]: the associated type `::Item` may not live long enough --> $DIR/projection-no-regions-fn.rs:28:5 | LL | Box::new(x.next()) | ^^^^^^^^^^^^^^^^^^ | - = help: consider adding an explicit lifetime bound `::Item: 'a`... + = help: consider adding an explicit lifetime bound `::Item: 'a`... error: aborting due to 2 previous errors diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr index d551ccf9cf..2513b0bfcc 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -55,7 +55,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -105,7 +105,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -133,7 +133,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr index 3e17de1bf0..4eebe682d4 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -46,7 +46,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -87,7 +87,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -115,7 +115,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -143,7 +143,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr index 3d9a01fec1..46a02598e1 100644 --- a/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-one-region-trait-bound-static-closure.stderr @@ -4,7 +4,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -30,7 +30,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -56,7 +56,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -82,7 +82,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -108,7 +108,7 @@ note: no external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr index e354f1b5f7..4e0155bdf2 100644 --- a/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr +++ b/src/test/ui/nll/ty-outlives/projection-two-region-trait-bound-closure.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_late::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -41,7 +41,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_relationships_early::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -77,7 +77,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: projection_outlives::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -105,7 +105,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive1::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -133,7 +133,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{{closure}}#0 with closure substs [ + = note: defining type: elements_outlive2::<'_#1r, '_#2r, '_#3r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#4r ()>, T)), (), @@ -161,7 +161,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: two_regions::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: two_regions::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -203,7 +203,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: two_regions_outlive::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), @@ -231,7 +231,7 @@ note: external requirements LL | with_signature(cell, t, |cell, t| require(cell, t)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: defining type: one_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: one_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr index 167ca740c6..7c0d63c368 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-approximate-lower-bound.stderr @@ -4,7 +4,7 @@ note: external requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: generic::::{{closure}}#0 with closure substs [ + = note: defining type: generic::::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), (), @@ -29,7 +29,7 @@ note: external requirements LL | twice(cell, value, |a, b| invoke(a, b)); | ^^^^^^^^^^^^^^^^^^^ | - = note: defining type: generic_fail::::{{closure}}#0 with closure substs [ + = note: defining type: generic_fail::::{closure#0} with closure substs [ i16, for<'r, 's> extern "rust-call" fn((std::option::Option>, &ReLateBound(DebruijnIndex(0), BrNamed('s)) T)), (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr index 528da502b9..88d73e7a72 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-return-type.stderr @@ -4,7 +4,7 @@ note: external requirements LL | with_signature(x, |y| y) | ^^^^^ | - = note: defining type: no_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: no_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::boxed::Box,)) -> std::boxed::Box<(dyn std::fmt::Debug + '_#2r)>, (), diff --git a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr index e341ee4829..5b175aac1e 100644 --- a/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr +++ b/src/test/ui/nll/ty-outlives/ty-param-closure-outlives-from-where-clause.stderr @@ -11,7 +11,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: no_region::::{{closure}}#0 with closure substs [ + = note: defining type: no_region::::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#1r ()>, T)), (), @@ -62,7 +62,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: correct_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: correct_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -95,7 +95,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: wrong_region::<'_#1r, T>::{{closure}}#0 with closure substs [ + = note: defining type: wrong_region::<'_#1r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#2r ()>, T)), (), @@ -141,7 +141,7 @@ LL | | require(&x, &y) LL | | }) | |_____^ | - = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{{closure}}#0 with closure substs [ + = note: defining type: outlives_region::<'_#1r, '_#2r, T>::{closure#0} with closure substs [ i32, extern "rust-call" fn((std::cell::Cell<&'_#3r ()>, T)), (), diff --git a/src/test/ui/nll/type-alias-free-regions.nll.stderr b/src/test/ui/nll/type-alias-free-regions.nll.stderr index 235bf4167d..bde73b0589 100644 --- a/src/test/ui/nll/type-alias-free-regions.nll.stderr +++ b/src/test/ui/nll/type-alias-free-regions.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | impl<'a> FromBox<'a> for C<'a> { | -- lifetime `'a` defined here LL | fn from_box(b: Box) -> Self { - | - has type `std::boxed::Box>` + | - has type `Box>` LL | C { f: b } | ^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` @@ -14,7 +14,7 @@ error: lifetime may not live long enough LL | impl<'a> FromTuple<'a> for C<'a> { | -- lifetime `'a` defined here LL | fn from_tuple(b: (B,)) -> Self { - | - has type `(std::boxed::Box<&'1 isize>,)` + | - has type `(Box<&'1 isize>,)` LL | C { f: Box::new(b.0) } | ^^^^^^^^^^^^^^^^^^^^^^ returning this value requires that `'1` must outlive `'a` diff --git a/src/test/ui/nll/type-alias-free-regions.stderr b/src/test/ui/nll/type-alias-free-regions.stderr index 65ce058112..38e3e05d1c 100644 --- a/src/test/ui/nll/type-alias-free-regions.stderr +++ b/src/test/ui/nll/type-alias-free-regions.stderr @@ -14,8 +14,8 @@ note: ...so that the expression is assignable | LL | C { f: b } | ^ - = note: expected `std::boxed::Box>` - found `std::boxed::Box>` + = note: expected `Box>` + found `Box>` note: but, the lifetime must be valid for the lifetime `'a` as defined on the impl at 15:6... --> $DIR/type-alias-free-regions.rs:15:6 | @@ -45,8 +45,8 @@ note: ...so that the expression is assignable | LL | C { f: Box::new(b.0) } | ^^^ - = note: expected `std::boxed::Box<&isize>` - found `std::boxed::Box<&isize>` + = 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... --> $DIR/type-alias-free-regions.rs:25:6 | diff --git a/src/test/ui/no-capture-arc.stderr b/src/test/ui/no-capture-arc.stderr index 476b6f75ab..37032e73f1 100644 --- a/src/test/ui/no-capture-arc.stderr +++ b/src/test/ui/no-capture-arc.stderr @@ -1,8 +1,8 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-capture-arc.rs:14:18 + --> $DIR/no-capture-arc.rs:14:16 | LL | let arc_v = Arc::new(v); - | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait + | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait LL | LL | thread::spawn(move|| { | ------ value moved into closure here @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-reuse-move-arc.stderr b/src/test/ui/no-reuse-move-arc.stderr index 3f7169e6fc..6f37d4c9d8 100644 --- a/src/test/ui/no-reuse-move-arc.stderr +++ b/src/test/ui/no-reuse-move-arc.stderr @@ -1,8 +1,8 @@ error[E0382]: borrow of moved value: `arc_v` - --> $DIR/no-reuse-move-arc.rs:12:18 + --> $DIR/no-reuse-move-arc.rs:12:16 | LL | let arc_v = Arc::new(v); - | ----- move occurs because `arc_v` has type `std::sync::Arc>`, which does not implement the `Copy` trait + | ----- move occurs because `arc_v` has type `Arc>`, which does not implement the `Copy` trait LL | LL | thread::spawn(move|| { | ------ value moved into closure here @@ -10,7 +10,14 @@ LL | assert_eq!((*arc_v)[3], 4); | ----- variable moved due to use in closure ... LL | assert_eq!((*arc_v)[2], 3); - | ^^^^^ value borrowed here after move + | ^^^^^^^^ value borrowed here after move + | + = note: borrow occurs due to deref coercion to `Vec` +note: deref defined here + --> $SRC_DIR/alloc/src/sync.rs:LL:COL + | +LL | type Target = T; + | ^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/no-send-res-ports.rs b/src/test/ui/no-send-res-ports.rs index e10f447365..1bac5868e7 100644 --- a/src/test/ui/no-send-res-ports.rs +++ b/src/test/ui/no-send-res-ports.rs @@ -23,7 +23,7 @@ fn main() { let x = foo(Port(Rc::new(()))); thread::spawn(move|| { - //~^ ERROR `std::rc::Rc<()>` cannot be sent between threads safely + //~^ ERROR `Rc<()>` cannot be sent between threads safely let y = x; println!("{:?}", y); }); diff --git a/src/test/ui/no-send-res-ports.stderr b/src/test/ui/no-send-res-ports.stderr index dbe1fde964..ef7fb4ad7b 100644 --- a/src/test/ui/no-send-res-ports.stderr +++ b/src/test/ui/no-send-res-ports.stderr @@ -1,25 +1,25 @@ -error[E0277]: `std::rc::Rc<()>` cannot be sent between threads safely +error[E0277]: `Rc<()>` cannot be sent between threads safely --> $DIR/no-send-res-ports.rs:25:5 | LL | thread::spawn(move|| { | _____^^^^^^^^^^^^^_- | | | - | | `std::rc::Rc<()>` cannot be sent between threads safely + | | `Rc<()>` cannot be sent between threads safely LL | | LL | | let y = x; LL | | println!("{:?}", y); LL | | }); - | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:main::Foo]` + | |_____- within this `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]` | ::: $SRC_DIR/std/src/thread/mod.rs:LL:COL | LL | F: Send + 'static, - | ---- required by this bound in `std::thread::spawn` + | ---- required by this bound in `spawn` | - = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:main::Foo]`, the trait `std::marker::Send` is not implemented for `std::rc::Rc<()>` + = help: within `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]`, the trait `Send` is not implemented for `Rc<()>` = note: required because it appears within the type `Port<()>` - = note: required because it appears within the type `main::Foo` - = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6 x:main::Foo]` + = note: required because it appears within the type `Foo` + = note: required because it appears within the type `[closure@$DIR/no-send-res-ports.rs:25:19: 29:6]` error: aborting due to previous error diff --git a/src/test/ui/no-stdio.rs b/src/test/ui/no-stdio.rs index e72b7b26e2..1b0ad930da 100644 --- a/src/test/ui/no-stdio.rs +++ b/src/test/ui/no-stdio.rs @@ -36,6 +36,16 @@ unsafe fn without_stdio R>(f: F) -> R { return r } +#[cfg(unix)] +fn assert_fd_is_valid(fd: libc::c_int) { + if unsafe { libc::fcntl(fd, libc::F_GETFD) == -1 } { + panic!("file descriptor {} is not valid: {}", fd, io::Error::last_os_error()); + } +} + +#[cfg(windows)] +fn assert_fd_is_valid(_fd: libc::c_int) {} + #[cfg(windows)] unsafe fn without_stdio R>(f: F) -> R { type DWORD = u32; @@ -77,10 +87,18 @@ unsafe fn without_stdio R>(f: F) -> R { fn main() { if env::args().len() > 1 { + // Writing to stdout & stderr should not panic. println!("test"); assert!(io::stdout().write(b"test\n").is_ok()); assert!(io::stderr().write(b"test\n").is_ok()); + + // Stdin should be at EOF. assert_eq!(io::stdin().read(&mut [0; 10]).unwrap(), 0); + + // Standard file descriptors should be valid on UNIX: + assert_fd_is_valid(0); + assert_fd_is_valid(1); + assert_fd_is_valid(2); return } @@ -109,12 +127,12 @@ fn main() { .stdout(Stdio::null()) .stderr(Stdio::null()) .status().unwrap(); - assert!(status.success(), "{:?} isn't a success", status); + assert!(status.success(), "{} isn't a success", status); // Finally, close everything then spawn a child to make sure everything is // *still* ok. let status = unsafe { without_stdio(|| Command::new(&me).arg("next").status()) }.unwrap(); - assert!(status.success(), "{:?} isn't a success", status); + assert!(status.success(), "{} isn't a success", status); } diff --git a/src/test/ui/no_owned_box_lang_item.rs b/src/test/ui/no_owned_box_lang_item.rs index 58e45ff73a..bef630d826 100644 --- a/src/test/ui/no_owned_box_lang_item.rs +++ b/src/test/ui/no_owned_box_lang_item.rs @@ -12,4 +12,5 @@ fn main() { } #[lang = "eh_personality"] extern fn eh_personality() {} +#[lang = "eh_catch_typeinfo"] static EH_CATCH_TYPEINFO: u8 = 0; #[lang = "panic_impl"] fn panic_impl(panic: &PanicInfo) -> ! { loop {} } diff --git a/src/test/ui/no_send-enum.stderr b/src/test/ui/no_send-enum.stderr index 95a0d77676..b617fe410f 100644 --- a/src/test/ui/no_send-enum.stderr +++ b/src/test/ui/no_send-enum.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^^^ `NoSend` cannot be sent between threads safely | - = help: within `Foo`, the trait `std::marker::Send` is not implemented for `NoSend` + = help: within `Foo`, the trait `Send` is not implemented for `NoSend` = note: required because it appears within the type `Foo` error: aborting due to previous error diff --git a/src/test/ui/no_send-rc.rs b/src/test/ui/no_send-rc.rs index 6ed0286ef1..f31db15ef2 100644 --- a/src/test/ui/no_send-rc.rs +++ b/src/test/ui/no_send-rc.rs @@ -5,5 +5,5 @@ fn bar(_: T) {} fn main() { let x = Rc::new(5); bar(x); - //~^ ERROR `std::rc::Rc<{integer}>` cannot be sent between threads safely + //~^ ERROR `Rc<{integer}>` cannot be sent between threads safely } diff --git a/src/test/ui/no_send-rc.stderr b/src/test/ui/no_send-rc.stderr index 1eb2edb14b..713dd75366 100644 --- a/src/test/ui/no_send-rc.stderr +++ b/src/test/ui/no_send-rc.stderr @@ -1,13 +1,13 @@ -error[E0277]: `std::rc::Rc<{integer}>` cannot be sent between threads safely +error[E0277]: `Rc<{integer}>` cannot be sent between threads safely --> $DIR/no_send-rc.rs:7:9 | LL | fn bar(_: T) {} | ---- required by this bound in `bar` ... LL | bar(x); - | ^ `std::rc::Rc<{integer}>` cannot be sent between threads safely + | ^ `Rc<{integer}>` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc<{integer}>` + = help: the trait `Send` is not implemented for `Rc<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/no_send-struct.stderr b/src/test/ui/no_send-struct.stderr index 4e8801a58b..a28a5e6d3d 100644 --- a/src/test/ui/no_send-struct.stderr +++ b/src/test/ui/no_send-struct.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^ `Foo` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `Foo` + = help: the trait `Send` is not implemented for `Foo` error: aborting due to previous error diff --git a/src/test/ui/no_share-enum.stderr b/src/test/ui/no_share-enum.stderr index 40996aef70..4a93edc100 100644 --- a/src/test/ui/no_share-enum.stderr +++ b/src/test/ui/no_share-enum.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^^^ `NoSync` cannot be shared between threads safely | - = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `NoSync` + = help: within `Foo`, the trait `Sync` is not implemented for `NoSync` = note: required because it appears within the type `Foo` error: aborting due to previous error diff --git a/src/test/ui/no_share-struct.stderr b/src/test/ui/no_share-struct.stderr index f14b06835f..a35271a8b7 100644 --- a/src/test/ui/no_share-struct.stderr +++ b/src/test/ui/no_share-struct.stderr @@ -7,7 +7,7 @@ LL | fn bar(_: T) {} LL | bar(x); | ^ `Foo` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `Foo` + = help: the trait `Sync` is not implemented for `Foo` error: aborting due to previous error diff --git a/src/test/ui/noexporttypeexe.rs b/src/test/ui/noexporttypeexe.rs index 0a8b40b08f..964ac9a300 100644 --- a/src/test/ui/noexporttypeexe.rs +++ b/src/test/ui/noexporttypeexe.rs @@ -10,6 +10,6 @@ fn main() { let x: isize = noexporttypelib::foo(); //~^ ERROR mismatched types //~| expected type `isize` - //~| found enum `std::option::Option` - //~| expected `isize`, found enum `std::option::Option` + //~| found enum `Option` + //~| expected `isize`, found enum `Option` } diff --git a/src/test/ui/noexporttypeexe.stderr b/src/test/ui/noexporttypeexe.stderr index e80fcd1368..7fc239613e 100644 --- a/src/test/ui/noexporttypeexe.stderr +++ b/src/test/ui/noexporttypeexe.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/noexporttypeexe.rs:10:18 | LL | let x: isize = noexporttypelib::foo(); - | ----- ^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found enum `std::option::Option` + | ----- ^^^^^^^^^^^^^^^^^^^^^^ expected `isize`, found enum `Option` | | | expected due to this | = note: expected type `isize` - found enum `std::option::Option` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/non-copyable-void.stderr b/src/test/ui/non-copyable-void.stderr index 9b0277186c..8395a3a056 100644 --- a/src/test/ui/non-copyable-void.stderr +++ b/src/test/ui/non-copyable-void.stderr @@ -1,16 +1,16 @@ -error[E0599]: no method named `clone` found for enum `libc::c_void` in the current scope +error[E0599]: no method named `clone` found for enum `c_void` in the current scope --> $DIR/non-copyable-void.rs:11:23 | LL | let _z = (*y).clone(); - | ^^^^^ method not found in `libc::c_void` + | ^^^^^ method not found in `c_void` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here error: aborting due to previous error diff --git a/src/test/ui/non-integer-atomic.rs b/src/test/ui/non-integer-atomic.rs index 26d7e66ae3..00a7f368a0 100644 --- a/src/test/ui/non-integer-atomic.rs +++ b/src/test/ui/non-integer-atomic.rs @@ -53,22 +53,22 @@ pub unsafe fn test_Foo_cxchg(p: &mut Foo, v: Foo) { pub unsafe fn test_Bar_load(p: &mut Bar, v: Bar) { intrinsics::atomic_load(p); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_store(p: &mut Bar, v: Bar) { intrinsics::atomic_store(p, v); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_xchg(p: &mut Bar, v: Bar) { intrinsics::atomic_xchg(p, v); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Bar_cxchg(p: &mut Bar, v: Bar) { intrinsics::atomic_cxchg(p, v, v); - //~^ ERROR expected basic integer type, found `&dyn std::ops::Fn()` + //~^ ERROR expected basic integer type, found `&dyn Fn()` } pub unsafe fn test_Quux_load(p: &mut Quux, v: Quux) { diff --git a/src/test/ui/non-integer-atomic.stderr b/src/test/ui/non-integer-atomic.stderr index 468e76da66..ee485c21cd 100644 --- a/src/test/ui/non-integer-atomic.stderr +++ b/src/test/ui/non-integer-atomic.stderr @@ -46,25 +46,25 @@ error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected bas LL | intrinsics::atomic_cxchg(p, v, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_load` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:55:5 | LL | intrinsics::atomic_load(p); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_store` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:60:5 | LL | intrinsics::atomic_store(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_xchg` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:65:5 | LL | intrinsics::atomic_xchg(p, v); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn std::ops::Fn()` +error[E0511]: invalid monomorphization of `atomic_cxchg` intrinsic: expected basic integer type, found `&dyn Fn()` --> $DIR/non-integer-atomic.rs:70:5 | LL | intrinsics::atomic_cxchg(p, v, v); diff --git a/src/test/ui/noncopyable-class.stderr b/src/test/ui/noncopyable-class.stderr index 75009ec130..b8e467d840 100644 --- a/src/test/ui/noncopyable-class.stderr +++ b/src/test/ui/noncopyable-class.stderr @@ -12,12 +12,12 @@ LL | let _y = x.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc` here - | the method is available for `std::rc::Rc` here + | the method is available for `Arc` here + | the method is available for `Rc` here | = 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: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/not-clone-closure.rs b/src/test/ui/not-clone-closure.rs index 134d52c495..25635bc833 100644 --- a/src/test/ui/not-clone-closure.rs +++ b/src/test/ui/not-clone-closure.rs @@ -8,5 +8,5 @@ fn main() { println!("Hello {}", a.0); }; - let hello = hello.clone(); //~ ERROR the trait bound `S: std::clone::Clone` is not satisfied + let hello = hello.clone(); //~ ERROR the trait bound `S: Clone` is not satisfied } diff --git a/src/test/ui/not-clone-closure.stderr b/src/test/ui/not-clone-closure.stderr index 20c7f81cf5..a62c21f2ee 100644 --- a/src/test/ui/not-clone-closure.stderr +++ b/src/test/ui/not-clone-closure.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `S: std::clone::Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` +error[E0277]: the trait bound `S: Clone` is not satisfied in `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` --> $DIR/not-clone-closure.rs:11:23 | LL | let hello = move || { | _________________- LL | | println!("Hello {}", a.0); LL | | }; - | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` + | |_____- within this `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` LL | LL | let hello = hello.clone(); - | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]`, the trait `std::clone::Clone` is not implemented for `S` + | ^^^^^ within `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]`, the trait `Clone` is not implemented for `S` | - = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6 a:S]` + = note: required because it appears within the type `[closure@$DIR/not-clone-closure.rs:7:17: 9:6]` error: aborting due to previous error diff --git a/src/test/ui/not-panic/not-panic-safe-2.rs b/src/test/ui/not-panic/not-panic-safe-2.rs index cd074281d0..f3faa70432 100644 --- a/src/test/ui/not-panic/not-panic-safe-2.rs +++ b/src/test/ui/not-panic/not-panic-safe-2.rs @@ -8,6 +8,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-2.stderr b/src/test/ui/not-panic/not-panic-safe-2.stderr index c52d5b9ade..6deb1e7d6f 100644 --- a/src/test/ui/not-panic/not-panic-safe-2.stderr +++ b/src/test/ui/not-panic/not-panic-safe-2.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-2.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::rc::Rc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Rc>` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-2.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::rc::Rc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Rc>` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-3.rs b/src/test/ui/not-panic/not-panic-safe-3.rs index b0ba3781f3..21f0c09931 100644 --- a/src/test/ui/not-panic/not-panic-safe-3.rs +++ b/src/test/ui/not-panic/not-panic-safe-3.rs @@ -8,6 +8,6 @@ fn assert() {} fn main() { assert::>>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-3.stderr b/src/test/ui/not-panic/not-panic-safe-3.stderr index 711346b7b1..ef1cf548df 100644 --- a/src/test/ui/not-panic/not-panic-safe-3.stderr +++ b/src/test/ui/not-panic/not-panic-safe-3.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-3.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::sync::Arc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Arc>` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-3.rs:10:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::>>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `std::sync::Arc>` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `Arc>` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-4.rs b/src/test/ui/not-panic/not-panic-safe-4.rs index ed2760576d..ba93af5c0a 100644 --- a/src/test/ui/not-panic/not-panic-safe-4.rs +++ b/src/test/ui/not-panic/not-panic-safe-4.rs @@ -7,6 +7,6 @@ fn assert() {} fn main() { assert::<&RefCell>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-4.stderr b/src/test/ui/not-panic/not-panic-safe-4.stderr index ada22fe9a7..2f86b96540 100644 --- a/src/test/ui/not-panic/not-panic-safe-4.stderr +++ b/src/test/ui/not-panic/not-panic-safe-4.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-4.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<&RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `&RefCell` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-4.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<&RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `&std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `&RefCell` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe-5.stderr b/src/test/ui/not-panic/not-panic-safe-5.stderr index c987ca7c08..c9f407a7f7 100644 --- a/src/test/ui/not-panic/not-panic-safe-5.stderr +++ b/src/test/ui/not-panic/not-panic-safe-5.stderr @@ -1,14 +1,14 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-5.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<*const UnsafeCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*const std::cell::UnsafeCell` + = help: the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `*const UnsafeCell` error: aborting due to previous error diff --git a/src/test/ui/not-panic/not-panic-safe-6.rs b/src/test/ui/not-panic/not-panic-safe-6.rs index a42e337ad9..4915096dc3 100644 --- a/src/test/ui/not-panic/not-panic-safe-6.rs +++ b/src/test/ui/not-panic/not-panic-safe-6.rs @@ -7,6 +7,6 @@ fn assert() {} fn main() { assert::<*mut RefCell>(); - //~^ ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a - //~| ERROR the type `std::cell::UnsafeCell` may contain interior mutability and a + //~^ ERROR the type `UnsafeCell` may contain interior mutability and a + //~| ERROR the type `UnsafeCell` may contain interior mutability and a } diff --git a/src/test/ui/not-panic/not-panic-safe-6.stderr b/src/test/ui/not-panic/not-panic-safe-6.stderr index f184a459b8..cf75c89f27 100644 --- a/src/test/ui/not-panic/not-panic-safe-6.stderr +++ b/src/test/ui/not-panic/not-panic-safe-6.stderr @@ -1,29 +1,29 @@ -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-6.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<*mut RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*mut std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `*mut RefCell` -error[E0277]: the type `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary +error[E0277]: the type `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary --> $DIR/not-panic-safe-6.rs:9:5 | LL | fn assert() {} | ---------- required by this bound in `assert` ... LL | assert::<*mut RefCell>(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` may contain interior mutability and a reference may not be safely transferrable across a catch_unwind boundary | - = help: within `std::cell::RefCell`, the trait `std::panic::RefUnwindSafe` is not implemented for `std::cell::UnsafeCell` - = note: required because it appears within the type `std::cell::Cell` - = note: required because it appears within the type `std::cell::RefCell` - = note: required because of the requirements on the impl of `std::panic::UnwindSafe` for `*mut std::cell::RefCell` + = help: within `RefCell`, the trait `RefUnwindSafe` is not implemented for `UnsafeCell` + = note: required because it appears within the type `Cell` + = note: required because it appears within the type `RefCell` + = note: required because of the requirements on the impl of `UnwindSafe` for `*mut RefCell` error: aborting due to 2 previous errors diff --git a/src/test/ui/not-panic/not-panic-safe.stderr b/src/test/ui/not-panic/not-panic-safe.stderr index b254a04166..1aaf17b1cd 100644 --- a/src/test/ui/not-panic/not-panic-safe.stderr +++ b/src/test/ui/not-panic/not-panic-safe.stderr @@ -7,8 +7,8 @@ LL | fn assert() {} LL | assert::<&mut i32>(); | ^^^^^^^^^^^^^^^^^^ `&mut i32` may not be safely transferred across an unwind boundary | - = help: the trait `std::panic::UnwindSafe` is not implemented for `&mut i32` - = note: `std::panic::UnwindSafe` is implemented for `&i32`, but not for `&mut i32` + = help: the trait `UnwindSafe` is not implemented for `&mut i32` + = note: `UnwindSafe` is implemented for `&i32`, but not for `&mut i32` error: aborting due to previous error diff --git a/src/test/ui/not-sync.rs b/src/test/ui/not-sync.rs index 70ba1fc580..f4648994fa 100644 --- a/src/test/ui/not-sync.rs +++ b/src/test/ui/not-sync.rs @@ -6,17 +6,17 @@ fn test() {} fn main() { test::>(); - //~^ ERROR `std::cell::Cell` cannot be shared between threads safely [E0277] + //~^ ERROR `Cell` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::cell::RefCell` cannot be shared between threads safely [E0277] + //~^ ERROR `RefCell` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::rc::Rc` cannot be shared between threads safely [E0277] + //~^ ERROR `Rc` cannot be shared between threads safely [E0277] test::>(); //~^ ERROR `std::rc::Weak` cannot be shared between threads safely [E0277] test::>(); //~^ ERROR `std::sync::mpsc::Receiver` cannot be shared between threads safely [E0277] test::>(); - //~^ ERROR `std::sync::mpsc::Sender` cannot be shared between threads safely [E0277] + //~^ ERROR `Sender` cannot be shared between threads safely [E0277] } diff --git a/src/test/ui/not-sync.stderr b/src/test/ui/not-sync.stderr index 25f1a66062..85d3599da0 100644 --- a/src/test/ui/not-sync.stderr +++ b/src/test/ui/not-sync.stderr @@ -1,35 +1,35 @@ -error[E0277]: `std::cell::Cell` cannot be shared between threads safely +error[E0277]: `Cell` cannot be shared between threads safely --> $DIR/not-sync.rs:8:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^^^ `std::cell::Cell` cannot be shared between threads safely + | ^^^^^^^^^ `Cell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::Cell` + = help: the trait `Sync` is not implemented for `Cell` -error[E0277]: `std::cell::RefCell` cannot be shared between threads safely +error[E0277]: `RefCell` cannot be shared between threads safely --> $DIR/not-sync.rs:10:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^^^^^^ `std::cell::RefCell` cannot be shared between threads safely + | ^^^^^^^^^^^^ `RefCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::RefCell` + = help: the trait `Sync` is not implemented for `RefCell` -error[E0277]: `std::rc::Rc` cannot be shared between threads safely +error[E0277]: `Rc` cannot be shared between threads safely --> $DIR/not-sync.rs:13:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^ `std::rc::Rc` cannot be shared between threads safely + | ^^^^^^^ `Rc` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc` + = help: the trait `Sync` is not implemented for `Rc` error[E0277]: `std::rc::Weak` cannot be shared between threads safely --> $DIR/not-sync.rs:15:12 @@ -40,7 +40,7 @@ LL | fn test() {} LL | test::>(); | ^^^^^^^^^ `std::rc::Weak` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::rc::Weak` + = help: the trait `Sync` is not implemented for `std::rc::Weak` error[E0277]: `std::sync::mpsc::Receiver` cannot be shared between threads safely --> $DIR/not-sync.rs:18:12 @@ -51,18 +51,18 @@ LL | fn test() {} LL | test::>(); | ^^^^^^^^^^^^^ `std::sync::mpsc::Receiver` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Receiver` + = help: the trait `Sync` is not implemented for `std::sync::mpsc::Receiver` -error[E0277]: `std::sync::mpsc::Sender` cannot be shared between threads safely +error[E0277]: `Sender` cannot be shared between threads safely --> $DIR/not-sync.rs:20:12 | LL | fn test() {} | ---- required by this bound in `test` ... LL | test::>(); - | ^^^^^^^^^^^ `std::sync::mpsc::Sender` cannot be shared between threads safely + | ^^^^^^^^^^^ `Sender` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::sync::mpsc::Sender` + = help: the trait `Sync` is not implemented for `Sender` error: aborting due to 6 previous errors diff --git a/src/test/ui/numbers-arithmetic/arith-0.rs b/src/test/ui/numbers-arithmetic/arith-0.rs deleted file mode 100644 index 7943cb908d..0000000000 --- a/src/test/ui/numbers-arithmetic/arith-0.rs +++ /dev/null @@ -1,8 +0,0 @@ -// run-pass - - -pub fn main() { - let a: isize = 10; - println!("{}", a); - assert_eq!(a * (a - 1), 90); -} diff --git a/src/test/ui/numbers-arithmetic/arith-1.rs b/src/test/ui/numbers-arithmetic/arith-1.rs deleted file mode 100644 index c13c8d8b76..0000000000 --- a/src/test/ui/numbers-arithmetic/arith-1.rs +++ /dev/null @@ -1,24 +0,0 @@ -// run-pass - - -pub fn main() { - let i32_a: isize = 10; - assert_eq!(i32_a, 10); - assert_eq!(i32_a - 10, 0); - assert_eq!(i32_a / 10, 1); - assert_eq!(i32_a - 20, -10); - assert_eq!(i32_a << 10, 10240); - assert_eq!(i32_a << 16, 655360); - assert_eq!(i32_a * 16, 160); - assert_eq!(i32_a * i32_a * i32_a, 1000); - assert_eq!(i32_a * i32_a * i32_a * i32_a, 10000); - assert_eq!(i32_a * i32_a / i32_a * i32_a, 100); - assert_eq!(i32_a * (i32_a - 1) << (2 + i32_a as usize), 368640); - let i32_b: isize = 0x10101010; - assert_eq!(i32_b + 1 - 1, i32_b); - assert_eq!(i32_b << 1, i32_b << 1); - assert_eq!(i32_b >> 1, i32_b >> 1); - assert_eq!(i32_b & i32_b << 1, 0); - println!("{}", i32_b | i32_b << 1); - assert_eq!(i32_b | i32_b << 1, 0x30303030); -} diff --git a/src/test/ui/numbers-arithmetic/arith-2.rs b/src/test/ui/numbers-arithmetic/arith-2.rs deleted file mode 100644 index 46c280677c..0000000000 --- a/src/test/ui/numbers-arithmetic/arith-2.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - - - -pub fn main() { - let i32_c: isize = 0x10101010; - assert_eq!(i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3), - i32_c + i32_c * 2 / 3 * 2 + (i32_c - 7 % 3)); -} diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr index 995afeeed8..1d029939c7 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-1.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-1.rs:7:14 | LL | let _x = 1_i32 << 32; - | ^^^^^^^^^^^ attempt to shift left by 32_i32 which would overflow + | ^^^^^^^^^^^ attempt to shift left by `32_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-1.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr index e6f6b1ccd1..8598792e08 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-2.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-2.rs:7:14 | LL | let _x = 1 << -1; - | ^^^^^^^ attempt to shift left by -1_i32 which would overflow + | ^^^^^^^ attempt to shift left by `-1_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-2.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr index e57b892b80..9c6f806f1d 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-3.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-3.rs:7:14 | LL | let _x = 1_u64 << 64; - | ^^^^^^^^^^^ attempt to shift left by 64_i32 which would overflow + | ^^^^^^^^^^^ attempt to shift left by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-3.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr b/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr index f20b41c1ba..08081a0b78 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-lsh-4.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-lsh-4.rs:11:13 | LL | let x = 1_i8 << 17; - | ^^^^^^^^^^ attempt to shift left by 17_i32 which would overflow + | ^^^^^^^^^^ attempt to shift left by `17_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-lsh-4.rs:7:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr index 18861a1b96..4d726fa7fe 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-1.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-1.rs:7:14 | LL | let _x = -1_i32 >> 32; - | ^^^^^^^^^^^^ attempt to shift right by 32_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift right by `32_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-1.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr index a2fb2b9053..9a8349d5dd 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-2.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-2.rs:7:14 | LL | let _x = -1_i32 >> -1; - | ^^^^^^^^^^^^ attempt to shift right by -1_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift right by `-1_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-2.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr index 24588b4a6b..f48b7ff6de 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-3.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-3.rs:7:14 | LL | let _x = -1_i64 >> 64; - | ^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-3.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr index 3f59653ea6..4816a38996 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-4.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-4.rs:11:13 | LL | let x = 2_i8 >> 17; - | ^^^^^^^^^^ attempt to shift right by 17_i32 which would overflow + | ^^^^^^^^^^ attempt to shift right by `17_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-4.rs:7:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr index 8b0daf1551..cd36f543d6 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-5.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-5.rs:7:14 | LL | let _n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-5.rs:4:9 diff --git a/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr b/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr index 53a1445b54..bec8b17df0 100644 --- a/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr +++ b/src/test/ui/numbers-arithmetic/overflowing-rsh-6.stderr @@ -2,7 +2,7 @@ error: this arithmetic operation will overflow --> $DIR/overflowing-rsh-6.rs:7:14 | LL | let _n = 1i64 >> [64][0]; - | ^^^^^^^^^^^^^^^ attempt to shift right by 64_i32 which would overflow + | ^^^^^^^^^^^^^^^ attempt to shift right by `64_i32`, which would overflow | note: the lint level is defined here --> $DIR/overflowing-rsh-6.rs:4:9 diff --git a/src/test/ui/object-does-not-impl-trait.rs b/src/test/ui/object-does-not-impl-trait.rs index 104e7b2e21..b3b679813c 100644 --- a/src/test/ui/object-does-not-impl-trait.rs +++ b/src/test/ui/object-does-not-impl-trait.rs @@ -4,5 +4,5 @@ trait Foo {} fn take_foo(f: F) {} fn take_object(f: Box) { take_foo(f); } -//~^ ERROR `std::boxed::Box: Foo` is not satisfied +//~^ ERROR `Box: Foo` is not satisfied fn main() {} diff --git a/src/test/ui/object-does-not-impl-trait.stderr b/src/test/ui/object-does-not-impl-trait.stderr index 1d3675bf1c..44424bc4ae 100644 --- a/src/test/ui/object-does-not-impl-trait.stderr +++ b/src/test/ui/object-does-not-impl-trait.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `std::boxed::Box: Foo` is not satisfied +error[E0277]: the trait bound `Box: Foo` is not satisfied --> $DIR/object-does-not-impl-trait.rs:6:44 | LL | fn take_foo(f: F) {} | --- required by this bound in `take_foo` LL | fn take_object(f: Box) { take_foo(f); } - | ^ the trait `Foo` is not implemented for `std::boxed::Box` + | ^ the trait `Foo` is not implemented for `Box` error: aborting due to previous error diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr index 9563c0dff3..ae02c58d08 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-box-error.nll.stderr @@ -11,7 +11,7 @@ error[E0507]: cannot move out of `ss.r` which is behind a mutable reference --> $DIR/object-lifetime-default-from-box-error.rs:18:5 | LL | ss.r - | ^^^^ move occurs because `ss.r` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^^^^ move occurs because `ss.r` has type `Box`, which does not implement the `Copy` trait error[E0621]: explicit lifetime required in the type of `ss` --> $DIR/object-lifetime-default-from-box-error.rs:31:5 diff --git a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr index 86ec58d3f0..a789c4906e 100644 --- a/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr +++ b/src/test/ui/object-lifetime/object-lifetime-default-from-rptr-box-error.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | ss.t = t; | ^ lifetime mismatch | - = note: expected reference `&'a std::boxed::Box<(dyn Test + 'static)>` - found reference `&'a std::boxed::Box<(dyn Test + 'a)>` + = 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... --> $DIR/object-lifetime-default-from-rptr-box-error.rs:14:6 | diff --git a/src/test/ui/object-pointer-types.stderr b/src/test/ui/object-pointer-types.stderr index 021aa8670f..a477425edc 100644 --- a/src/test/ui/object-pointer-types.stderr +++ b/src/test/ui/object-pointer-types.stderr @@ -16,11 +16,11 @@ LL | fn owned(self: Box); LL | x.owned(); | ^^^^^ method not found in `&mut dyn Foo` -error[E0599]: no method named `managed` found for struct `std::boxed::Box<(dyn Foo + 'static)>` in the current scope +error[E0599]: no method named `managed` found for struct `Box<(dyn Foo + 'static)>` in the current scope --> $DIR/object-pointer-types.rs:23:7 | LL | x.managed(); - | ^^^^^^^ method not found in `std::boxed::Box<(dyn Foo + 'static)>` + | ^^^^^^^ method not found in `Box<(dyn Foo + 'static)>` error: aborting due to 3 previous errors diff --git a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr index e2a95d95a1..c32038b5a2 100644 --- a/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-associated-consts.object_safe_for_dispatch.stderr @@ -10,7 +10,7 @@ LL | t | ^ the trait `Bar` cannot be made into an object | = help: consider moving `X` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr index 7443d38470..7c104fa158 100644 --- a/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-generics.object_safe_for_dispatch.stderr @@ -10,7 +10,7 @@ LL | t | ^ the trait `Bar` cannot be made into an object | = help: consider moving `bar` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error[E0038]: the trait `Bar` cannot be made into an object @@ -25,7 +25,7 @@ LL | t as &dyn Bar | ^ the trait `Bar` cannot be made into an object | = help: consider moving `bar` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr index 89b273fb8a..ced26889ba 100644 --- a/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-mentions-Self.object_safe_for_dispatch.stderr @@ -10,7 +10,7 @@ LL | t | ^ the trait `Bar` cannot be made into an object | = help: consider moving `bar` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error[E0038]: the trait `Baz` cannot be made into an object @@ -25,7 +25,7 @@ LL | t | ^ the trait `Baz` cannot be made into an object | = help: consider moving `baz` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Baz>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Baz>` for `&T` = note: required by cast to type `&dyn Baz` error: aborting due to 2 previous errors diff --git a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr index de56843962..8e920697d8 100644 --- a/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-no-static.object_safe_for_dispatch.stderr @@ -9,8 +9,8 @@ LL | fn foo() {} LL | let b: Box = Box::new(Bar); | ^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box` help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects | LL | fn foo() where Self: Sized {} diff --git a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr index 2f1f06f4cf..cc0463f5d8 100644 --- a/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-sized-2.object_safe_for_dispatch.stderr @@ -9,7 +9,7 @@ LL | where Self : Sized LL | t | ^ the trait `Bar` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to previous error diff --git a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr index 58c2b77214..aceacac2db 100644 --- a/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr +++ b/src/test/ui/object-safety/object-safety-sized.object_safe_for_dispatch.stderr @@ -9,7 +9,7 @@ LL | trait Bar : Sized { LL | t | ^ the trait `Bar` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Bar>` for `&T` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Bar>` for `&T` = note: required by cast to type `&dyn Bar` error: aborting due to previous error diff --git a/src/test/ui/on-unimplemented/no-debug.rs b/src/test/ui/on-unimplemented/no-debug.rs index 45c9ea46fa..bdc80c5b35 100644 --- a/src/test/ui/on-unimplemented/no-debug.rs +++ b/src/test/ui/on-unimplemented/no-debug.rs @@ -10,7 +10,7 @@ fn main() { println!("{:?} {:?}", Foo, Bar); println!("{} {}", Foo, Bar); } -//~^^^ ERROR `Foo` doesn't implement `std::fmt::Debug` -//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Debug` +//~^^^ ERROR `Foo` doesn't implement `Debug` +//~| ERROR `Bar` doesn't implement `Debug` //~^^^^ ERROR `Foo` doesn't implement `std::fmt::Display` -//~| ERROR `no_debug::Bar` doesn't implement `std::fmt::Display` +//~| ERROR `Bar` doesn't implement `std::fmt::Display` diff --git a/src/test/ui/on-unimplemented/no-debug.stderr b/src/test/ui/on-unimplemented/no-debug.stderr index 4f9d428546..2382fd8484 100644 --- a/src/test/ui/on-unimplemented/no-debug.stderr +++ b/src/test/ui/on-unimplemented/no-debug.stderr @@ -1,21 +1,21 @@ -error[E0277]: `Foo` doesn't implement `std::fmt::Debug` +error[E0277]: `Foo` doesn't implement `Debug` --> $DIR/no-debug.rs:10:27 | LL | println!("{:?} {:?}", Foo, Bar); | ^^^ `Foo` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `Foo` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` + = help: the trait `Debug` is not implemented for `Foo` + = note: add `#[derive(Debug)]` or manually implement `Debug` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Debug` +error[E0277]: `Bar` doesn't implement `Debug` --> $DIR/no-debug.rs:10:32 | LL | println!("{:?} {:?}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^ `Bar` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = help: the trait `std::fmt::Debug` is not implemented for `no_debug::Bar` + = help: the trait `Debug` is not implemented for `Bar` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -30,13 +30,13 @@ LL | println!("{} {}", Foo, Bar); = note: required by `std::fmt::Display::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: `no_debug::Bar` doesn't implement `std::fmt::Display` +error[E0277]: `Bar` doesn't implement `std::fmt::Display` --> $DIR/no-debug.rs:11:28 | LL | println!("{} {}", Foo, Bar); - | ^^^ `no_debug::Bar` cannot be formatted with the default formatter + | ^^^ `Bar` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `no_debug::Bar` + = help: the trait `std::fmt::Display` is not implemented for `Bar` = 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 a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/on-unimplemented/on-trait.stderr b/src/test/ui/on-unimplemented/on-trait.stderr index be8efbf2ce..00c8492abc 100644 --- a/src/test/ui/on-unimplemented/on-trait.stderr +++ b/src/test/ui/on-unimplemented/on-trait.stderr @@ -1,24 +1,24 @@ -error[E0277]: the trait bound `std::option::Option>: MyFromIterator<&u8>` is not satisfied +error[E0277]: the trait bound `Option>: MyFromIterator<&u8>` is not satisfied --> $DIR/on-trait.rs:28:30 | LL | fn collect, B: MyFromIterator>(it: I) -> B { | ----------------- required by this bound in `collect` ... LL | let y: Option> = collect(x.iter()); // this should give approximately the same error for x.iter().collect() - | ^^^^^^^ a collection of type `std::option::Option>` cannot be built from an iterator over elements of type `&u8` + | ^^^^^^^ a collection of type `Option>` cannot be built from an iterator over elements of type `&u8` | - = help: the trait `MyFromIterator<&u8>` is not implemented for `std::option::Option>` + = help: the trait `MyFromIterator<&u8>` is not implemented for `Option>` -error[E0277]: the trait bound `std::string::String: Bar::Foo` is not satisfied +error[E0277]: the trait bound `String: Foo` is not satisfied --> $DIR/on-trait.rs:31:21 | LL | fn foobar>() -> T { | --------------- required by this bound in `foobar` ... LL | let x: String = foobar(); - | ^^^^^^ test error `std::string::String` with `u8` `_` `u32` in `Bar::Foo` + | ^^^^^^ test error `String` with `u8` `_` `u32` in `Foo` | - = help: the trait `Bar::Foo` is not implemented for `std::string::String` + = help: the trait `Foo` is not implemented for `String` error: aborting due to 2 previous errors diff --git a/src/test/ui/on-unimplemented/slice-index.stderr b/src/test/ui/on-unimplemented/slice-index.stderr index 25a6546007..44b8b0d8d8 100644 --- a/src/test/ui/on-unimplemented/slice-index.stderr +++ b/src/test/ui/on-unimplemented/slice-index.stderr @@ -4,17 +4,17 @@ error[E0277]: the type `[i32]` cannot be indexed by `i32` LL | x[1i32]; | ^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[i32]>` is not implemented for `i32` - = note: required because of the requirements on the impl of `std::ops::Index` for `[i32]` + = help: the trait `SliceIndex<[i32]>` is not implemented for `i32` + = note: required because of the requirements on the impl of `Index` for `[i32]` -error[E0277]: the type `[i32]` cannot be indexed by `std::ops::RangeTo` +error[E0277]: the type `[i32]` cannot be indexed by `RangeTo` --> $DIR/slice-index.rs:9:5 | LL | x[..1i32]; | ^^^^^^^^^ slice indices are of type `usize` or ranges of `usize` | - = help: the trait `std::slice::SliceIndex<[i32]>` is not implemented for `std::ops::RangeTo` - = note: required because of the requirements on the impl of `std::ops::Index>` for `[i32]` + = help: the trait `SliceIndex<[i32]>` is not implemented for `RangeTo` + = note: required because of the requirements on the impl of `Index>` for `[i32]` error: aborting due to 2 previous errors diff --git a/src/test/ui/option-to-result.stderr b/src/test/ui/option-to-result.stderr index 5fa0677838..551b9f4650 100644 --- a/src/test/ui/option-to-result.stderr +++ b/src/test/ui/option-to-result.stderr @@ -5,26 +5,26 @@ LL | fn test_result() -> Result<(),()> { | ------------- expected `()` because of this LL | let a:Option<()> = Some(()); LL | a?; - | ^ the trait `std::convert::From` is not implemented for `()` + | ^ the trait `From` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` | LL | a.ok_or_else(|| /* error value */)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `?` couldn't convert the error to `std::option::NoneError` +error[E0277]: `?` couldn't convert the error to `NoneError` --> $DIR/option-to-result.rs:11:6 | LL | fn test_option() -> Option{ - | ----------- expected `std::option::NoneError` because of this + | ----------- expected `NoneError` because of this LL | let a:Result = Ok(5); LL | a?; - | ^ the trait `std::convert::From` is not implemented for `std::option::NoneError` + | ^ the trait `From` is not implemented for `NoneError` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` help: consider converting the `Result` into an `Option` using `Result::ok` | LL | a.ok()?; diff --git a/src/test/ui/option-unwrap.rs b/src/test/ui/option-unwrap.rs deleted file mode 100644 index 173f803ee2..0000000000 --- a/src/test/ui/option-unwrap.rs +++ /dev/null @@ -1,32 +0,0 @@ -// run-pass - -#![allow(non_camel_case_types)] -use std::cell::Cell; - -struct dtor<'a> { - x: &'a Cell, -} - -impl<'a> Drop for dtor<'a> { - fn drop(&mut self) { - self.x.set(self.x.get() - 1); - } -} - -fn unwrap(o: Option) -> T { - match o { - Some(v) => v, - None => panic!() - } -} - -pub fn main() { - let x = &Cell::new(1); - - { - let b = Some(dtor { x:x }); - let _c = unwrap(b); - } - - assert_eq!(x.get(), 0); -} diff --git a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr index 7e8bb73190..d3ae798ead 100644 --- a/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr +++ b/src/test/ui/or-patterns/exhaustiveness-non-exhaustive.stderr @@ -23,7 +23,7 @@ LL | match (Some(0u8),) { | ^^^^^^^^^^^^ pattern `(Some(2_u8..=u8::MAX))` 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 `(std::option::Option,)` + = note: the matched value is of type `(Option,)` error: aborting due to 3 previous errors diff --git a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr index 1dabb7c975..00dba053a5 100644 --- a/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr +++ b/src/test/ui/or-patterns/or-patterns-binding-type-mismatch.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:13:39 | LL | match Blah::A(1, 1, 2) { - | ---------------- this expression has type `main::Blah` + | ---------------- this expression has type `Blah` LL | Blah::A(_, x, y) | Blah::B(x, y) => {} | - ^ expected `usize`, found `isize` | | @@ -14,7 +14,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:17:44 | LL | match Some(Blah::A(1, 1, 2)) { - | ---------------------- this expression has type `std::option::Option` + | ---------------------- this expression has type `Option` LL | Some(Blah::A(_, x, y) | Blah::B(x, y)) => {} | - ^ expected `usize`, found `isize` | | @@ -50,7 +50,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:41 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - ^ expected `u16`, found `u8` | | @@ -62,7 +62,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:50 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - ^ expected `u8`, found `u16` | | @@ -74,7 +74,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:59 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - ^ expected `u32`, found `u16` | | @@ -86,7 +86,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:26:62 | LL | match Some((0u8, Some((1u16, 2u32)))) { - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` LL | Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) => {} | - first introduced with type `u8` here ^ expected `u8`, found `u32` | @@ -96,7 +96,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:34:42 | LL | if let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2) { - | - ^ ---------------- this expression has type `main::Blah` + | - ^ ---------------- this expression has type `Blah` | | | | | expected `usize`, found `isize` | first introduced with type `usize` here @@ -107,7 +107,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:38:47 | LL | if let Some(Blah::A(_, x, y) | Blah::B(x, y)) = Some(Blah::A(1, 1, 2)) { - | - ^ ---------------------- this expression has type `std::option::Option` + | - ^ ---------------------- this expression has type `Option` | | | | | expected `usize`, found `isize` | first introduced with type `usize` here @@ -145,7 +145,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | first introduced with type `u16` here ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -158,7 +158,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | first introduced with type `u8` here ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -171,7 +171,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | first introduced with type `u32` here ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -182,7 +182,7 @@ LL | if let Some((x, Some((y, z)))) | Some((y, Some((x, z) | (z, x)))) | - first introduced with type `u8` here ^ expected `u8`, found `u32` ... LL | = Some((0u8, Some((1u16, 2u32)))) - | ------------------------------- this expression has type `std::option::Option<(u8, std::option::Option<(u16, u32)>)>` + | ------------------------------- this expression has type `Option<(u8, Option<(u16, u32)>)>` | = note: a binding must have the same type in all alternatives @@ -190,7 +190,7 @@ error[E0308]: mismatched types --> $DIR/or-patterns-binding-type-mismatch.rs:55:39 | LL | let Blah::A(_, x, y) | Blah::B(x, y) = Blah::A(1, 1, 2); - | - ^ ---------------- this expression has type `main::Blah` + | - ^ ---------------- this expression has type `Blah` | | | | | expected `usize`, found `isize` | first introduced with type `usize` here diff --git a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr index 6cbb59dc22..861d274ab5 100644 --- a/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr +++ b/src/test/ui/or-patterns/or-patterns-syntactic-fail.stderr @@ -112,7 +112,7 @@ error[E0308]: mismatched types LL | let recovery_witness: String = 0; | ------ ^ | | | - | | expected struct `std::string::String`, found integer + | | expected struct `String`, found integer | | help: try using a conversion method: `0.to_string()` | expected due to this diff --git a/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs b/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs index 3e5cdad7ab..b9ef2f3294 100644 --- a/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs +++ b/src/test/ui/panic-runtime/auxiliary/panic-runtime-lang-items.rs @@ -11,3 +11,5 @@ use core::panic::PanicInfo; fn panic_impl(info: &PanicInfo) -> ! { loop {} } #[lang = "eh_personality"] fn eh_personality() {} +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; diff --git a/src/test/ui/paren-span.rs b/src/test/ui/paren-span.rs index 24fadb24de..c8cb63d519 100644 --- a/src/test/ui/paren-span.rs +++ b/src/test/ui/paren-span.rs @@ -16,6 +16,6 @@ mod m { fn main() { let s = m::make(); - paren!(s.x); //~ ERROR field `x` of struct `m::S` is private + paren!(s.x); //~ ERROR field `x` of struct `S` is private // ^^^ highlight here } diff --git a/src/test/ui/paren-span.stderr b/src/test/ui/paren-span.stderr index ca22401f45..fc31371576 100644 --- a/src/test/ui/paren-span.stderr +++ b/src/test/ui/paren-span.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `x` of struct `m::S` is private +error[E0616]: field `x` of struct `S` is private --> $DIR/paren-span.rs:19:14 | LL | paren!(s.x); diff --git a/src/test/ui/parser/bind-struct-early-modifiers.stderr b/src/test/ui/parser/bind-struct-early-modifiers.stderr index 03482a41f5..b35762a887 100644 --- a/src/test/ui/parser/bind-struct-early-modifiers.stderr +++ b/src/test/ui/parser/bind-struct-early-modifiers.stderr @@ -1,8 +1,10 @@ error: expected `,` - --> $DIR/bind-struct-early-modifiers.rs:4:19 + --> $DIR/bind-struct-early-modifiers.rs:4:20 | LL | Foo { ref x: ref x } => {}, - | ^ + | --- ^ + | | + | while parsing the fields for this pattern error: aborting due to previous error diff --git a/src/test/ui/parser/float-field.stderr b/src/test/ui/parser/float-field.stderr index 62202b9996..7090efc501 100644 --- a/src/test/ui/parser/float-field.stderr +++ b/src/test/ui/parser/float-field.stderr @@ -271,10 +271,10 @@ LL | s.1e1; = note: available fields are: `0`, `1` error[E0609]: no field `1e1` on type `(u8, u8)` - --> $DIR/float-field.rs:9:7 + --> $DIR/float-field.rs:9:9 | LL | s.1.1e1; - | ^^^^^ + | ^^^ error[E0609]: no field `0x1e1` on type `S` --> $DIR/float-field.rs:24:7 @@ -288,7 +288,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:25:7 | LL | s.0x1.; - | ^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` @@ -296,7 +296,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:28:7 | LL | s.0x1.1; - | ^^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` @@ -304,7 +304,7 @@ error[E0609]: no field `0x1` on type `S` --> $DIR/float-field.rs:30:7 | LL | s.0x1.1e1; - | ^^^^^^^ unknown field + | ^^^ unknown field | = note: available fields are: `0`, `1` diff --git a/src/test/ui/parser/fn-header-semantic-fail.stderr b/src/test/ui/parser/fn-header-semantic-fail.stderr index d6b36fbb71..4193b3ee69 100644 --- a/src/test/ui/parser/fn-header-semantic-fail.stderr +++ b/src/test/ui/parser/fn-header-semantic-fail.stderr @@ -178,7 +178,7 @@ LL | async fn ft1() {} | expected `()`, found opaque type | = note: expected fn pointer `fn()` - found fn pointer `fn() -> impl std::future::Future` + found fn pointer `fn() -> impl Future` error[E0053]: method `ft5` has an incompatible type for trait --> $DIR/fn-header-semantic-fail.rs:34:48 @@ -193,7 +193,7 @@ LL | const async unsafe extern "C" fn ft5() {} | expected `()`, found opaque type | = note: expected fn pointer `unsafe extern "C" fn()` - found fn pointer `unsafe extern "C" fn() -> impl std::future::Future` + found fn pointer `unsafe extern "C" fn() -> impl Future` error: aborting due to 20 previous errors diff --git a/src/test/ui/parser/issue-10392.stderr b/src/test/ui/parser/issue-10392.stderr index 34991151c1..438ea67d33 100644 --- a/src/test/ui/parser/issue-10392.stderr +++ b/src/test/ui/parser/issue-10392.stderr @@ -2,7 +2,9 @@ error: expected identifier, found `,` --> $DIR/issue-10392.rs:6:13 | LL | let A { , } = a(); - | ^ expected identifier + | - ^ expected identifier + | | + | while parsing the fields for this pattern error: aborting due to previous error diff --git a/src/test/ui/parser/issue-63135.stderr b/src/test/ui/parser/issue-63135.stderr index 396aec8335..80e9ac5bed 100644 --- a/src/test/ui/parser/issue-63135.stderr +++ b/src/test/ui/parser/issue-63135.stderr @@ -35,7 +35,9 @@ error: expected one of `!` or `[`, found `}` --> $DIR/issue-63135.rs:3:16 | LL | fn i(n{...,f # - | ^ expected one of `!` or `[` + | - ^ expected one of `!` or `[` + | | + | while parsing the fields for this pattern error: aborting due to 5 previous errors diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.rs b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs new file mode 100644 index 0000000000..0b10a5f6f4 --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.rs @@ -0,0 +1,21 @@ +#![crate_type="lib"] +fn x<'a>(x: &mut 'a i32){} //~ ERROR lifetime must precede `mut` + +macro_rules! mac { + ($lt:lifetime) => { + fn w<$lt>(w: &mut $lt i32) {} + //~^ ERROR lifetime must precede `mut` + } +} + +mac!('a); + +// avoid false positives +fn y<'a>(y: &mut 'a + Send) { + //~^ ERROR expected a path on the left-hand side of `+`, not `&mut 'a` + //~| WARNING trait objects without an explicit `dyn` are deprecated + //~| ERROR at least one trait is required for an object type + let z = y as &mut 'a + Send; + //~^ ERROR expected value, found trait `Send` + //~| WARNING trait objects without an explicit `dyn` are deprecated +} diff --git a/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr new file mode 100644 index 0000000000..abb64f7e49 --- /dev/null +++ b/src/test/ui/parser/issue-73568-lifetime-after-mut.stderr @@ -0,0 +1,53 @@ +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:2:13 + | +LL | fn x<'a>(x: &mut 'a i32){} + | ^^^^^^^ help: place the lifetime before `mut`: `&'a mut` + +error[E0178]: expected a path on the left-hand side of `+`, not `&mut 'a` + --> $DIR/issue-73568-lifetime-after-mut.rs:14:13 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^^^^^^^^^^^^^ help: try adding parentheses: `&mut ('a + Send)` + +error: lifetime must precede `mut` + --> $DIR/issue-73568-lifetime-after-mut.rs:6:22 + | +LL | fn w<$lt>(w: &mut $lt i32) {} + | ^^^^^^^^ help: place the lifetime before `mut`: `&$lt mut` +... +LL | mac!('a); + | --------- in this macro invocation + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0423]: expected value, found trait `Send` + --> $DIR/issue-73568-lifetime-after-mut.rs:18:28 + | +LL | let z = y as &mut 'a + Send; + | ^^^^ not a value + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ help: use `dyn`: `dyn 'a` + | + = note: `#[warn(bare_trait_objects)]` on by default + +warning: trait objects without an explicit `dyn` are deprecated + --> $DIR/issue-73568-lifetime-after-mut.rs:18:23 + | +LL | let z = y as &mut 'a + Send; + | ^^ help: use `dyn`: `dyn 'a` + +error[E0224]: at least one trait is required for an object type + --> $DIR/issue-73568-lifetime-after-mut.rs:14:18 + | +LL | fn y<'a>(y: &mut 'a + Send) { + | ^^ + +error: aborting due to 5 previous errors; 2 warnings emitted + +Some errors have detailed explanations: E0178, E0224, E0423. +For more information about an error, try `rustc --explain E0178`. diff --git a/src/test/ui/parser/lex-bad-char-literals-6.stderr b/src/test/ui/parser/lex-bad-char-literals-6.stderr index 82c46ad82c..48b8fc6a72 100644 --- a/src/test/ui/parser/lex-bad-char-literals-6.stderr +++ b/src/test/ui/parser/lex-bad-char-literals-6.stderr @@ -37,7 +37,7 @@ error[E0277]: can't compare `&str` with `char` LL | if x == y {} | ^^ no implementation for `&str == char` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + = help: the trait `PartialEq` is not implemented for `&str` error[E0308]: mismatched types --> $DIR/lex-bad-char-literals-6.rs:15:20 @@ -53,7 +53,7 @@ error[E0277]: can't compare `&str` with `char` LL | if x == z {} | ^^ no implementation for `&str == char` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&str` + = help: the trait `PartialEq` is not implemented for `&str` error: aborting due to 6 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist.rs b/src/test/ui/parser/mod_file_not_exist.rs index f4a27b52ec..7b079eb02d 100644 --- a/src/test/ui/parser/mod_file_not_exist.rs +++ b/src/test/ui/parser/mod_file_not_exist.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist.stderr b/src/test/ui/parser/mod_file_not_exist.stderr index 087ae9fe3e..4e08125625 100644 --- a/src/test/ui/parser/mod_file_not_exist.stderr +++ b/src/test/ui/parser/mod_file_not_exist.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/mod_file_not_exist_windows.rs b/src/test/ui/parser/mod_file_not_exist_windows.rs index 4b7d7a02bb..5db21e2bbc 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.rs +++ b/src/test/ui/parser/mod_file_not_exist_windows.rs @@ -5,5 +5,5 @@ mod not_a_real_file; //~ ERROR file not found for module `not_a_real_file` fn main() { assert_eq!(mod_file_aux::bar(), 10); - //~^ ERROR failed to resolve: use of undeclared type or module `mod_file_aux` + //~^ ERROR failed to resolve: use of undeclared crate or module `mod_file_aux` } diff --git a/src/test/ui/parser/mod_file_not_exist_windows.stderr b/src/test/ui/parser/mod_file_not_exist_windows.stderr index d67205cfdf..73cdf098b0 100644 --- a/src/test/ui/parser/mod_file_not_exist_windows.stderr +++ b/src/test/ui/parser/mod_file_not_exist_windows.stderr @@ -6,11 +6,11 @@ LL | mod not_a_real_file; | = help: to create the module `not_a_real_file`, create file "$DIR/not_a_real_file.rs" -error[E0433]: failed to resolve: use of undeclared type or module `mod_file_aux` +error[E0433]: failed to resolve: use of undeclared crate or module `mod_file_aux` --> $DIR/mod_file_not_exist_windows.rs:7:16 | LL | assert_eq!(mod_file_aux::bar(), 10); - | ^^^^^^^^^^^^ use of undeclared type or module `mod_file_aux` + | ^^^^^^^^^^^^ use of undeclared crate or module `mod_file_aux` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/recover-range-pats.rs b/src/test/ui/parser/recover-range-pats.rs index e07ea6221d..7412b624b0 100644 --- a/src/test/ui/parser/recover-range-pats.rs +++ b/src/test/ui/parser/recover-range-pats.rs @@ -17,8 +17,8 @@ fn exclusive_from_to() { if let 0..Y = 0 {} // OK. if let X..3 = 0 {} // OK. if let X..Y = 0 {} // OK. - if let true..Y = 0 {} //~ ERROR only char and numeric types - if let X..true = 0 {} //~ ERROR only char and numeric types + if let true..Y = 0 {} //~ ERROR only `char` and numeric types + if let X..true = 0 {} //~ ERROR only `char` and numeric types if let .0..Y = 0 {} //~ ERROR mismatched types //~^ ERROR float literals must have an integer part if let X.. .0 = 0 {} //~ ERROR mismatched types @@ -30,8 +30,8 @@ fn inclusive_from_to() { if let 0..=Y = 0 {} // OK. if let X..=3 = 0 {} // OK. if let X..=Y = 0 {} // OK. - if let true..=Y = 0 {} //~ ERROR only char and numeric types - if let X..=true = 0 {} //~ ERROR only char and numeric types + if let true..=Y = 0 {} //~ ERROR only `char` and numeric types + if let X..=true = 0 {} //~ ERROR only `char` and numeric types if let .0..=Y = 0 {} //~ ERROR mismatched types //~^ ERROR float literals must have an integer part if let X..=.0 = 0 {} //~ ERROR mismatched types @@ -43,9 +43,9 @@ fn inclusive2_from_to() { if let 0...Y = 0 {} //~ ERROR `...` range patterns are deprecated if let X...3 = 0 {} //~ ERROR `...` range patterns are deprecated if let X...Y = 0 {} //~ ERROR `...` range patterns are deprecated - if let true...Y = 0 {} //~ ERROR only char and numeric types + if let true...Y = 0 {} //~ ERROR only `char` and numeric types //~^ ERROR `...` range patterns are deprecated - if let X...true = 0 {} //~ ERROR only char and numeric types + if let X...true = 0 {} //~ ERROR only `char` and numeric types //~^ ERROR `...` range patterns are deprecated if let .0...Y = 0 {} //~ ERROR mismatched types //~^ ERROR float literals must have an integer part @@ -59,7 +59,7 @@ fn exclusive_from() { if let 0.. = 0 {} if let X.. = 0 {} if let true.. = 0 {} - //~^ ERROR only char and numeric types + //~^ ERROR only `char` and numeric types if let .0.. = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -69,7 +69,7 @@ fn inclusive_from() { if let 0..= = 0 {} //~ ERROR inclusive range with no end if let X..= = 0 {} //~ ERROR inclusive range with no end if let true..= = 0 {} //~ ERROR inclusive range with no end - //~| ERROR only char and numeric types + //~| ERROR only `char` and numeric types if let .0..= = 0 {} //~ ERROR inclusive range with no end //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -79,7 +79,7 @@ fn inclusive2_from() { if let 0... = 0 {} //~ ERROR inclusive range with no end if let X... = 0 {} //~ ERROR inclusive range with no end if let true... = 0 {} //~ ERROR inclusive range with no end - //~| ERROR only char and numeric types + //~| ERROR only `char` and numeric types if let .0... = 0 {} //~ ERROR inclusive range with no end //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -89,7 +89,7 @@ fn exclusive_to() { if let ..0 = 0 {} if let ..Y = 0 {} if let ..true = 0 {} - //~^ ERROR only char and numeric types + //~^ ERROR only `char` and numeric types if let .. .0 = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -99,7 +99,7 @@ fn inclusive_to() { if let ..=3 = 0 {} if let ..=Y = 0 {} if let ..=true = 0 {} - //~^ ERROR only char and numeric types + //~^ ERROR only `char` and numeric types if let ..=.0 = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR mismatched types @@ -112,7 +112,7 @@ fn inclusive2_to() { //~^ ERROR range-to patterns with `...` are not allowed if let ...true = 0 {} //~^ ERROR range-to patterns with `...` are not allowed - //~| ERROR only char and numeric types + //~| ERROR only `char` and numeric types if let ....3 = 0 {} //~^ ERROR float literals must have an integer part //~| ERROR range-to patterns with `...` are not allowed diff --git a/src/test/ui/parser/recover-range-pats.stderr b/src/test/ui/parser/recover-range-pats.stderr index 0d4db74f9f..e351a9783b 100644 --- a/src/test/ui/parser/recover-range-pats.stderr +++ b/src/test/ui/parser/recover-range-pats.stderr @@ -258,7 +258,7 @@ LL | mac2!(0, 1); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:20:12 | LL | if let true..Y = 0 {} @@ -266,7 +266,7 @@ LL | if let true..Y = 0 {} | | | this is of type `bool` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:21:15 | LL | if let X..true = 0 {} @@ -291,7 +291,7 @@ LL | if let X.. .0 = 0 {} | | expected integer, found floating-point number | this is of type `u8` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:33:12 | LL | if let true..=Y = 0 {} @@ -299,7 +299,7 @@ LL | if let true..=Y = 0 {} | | | this is of type `bool` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:34:16 | LL | if let X..=true = 0 {} @@ -324,7 +324,7 @@ LL | if let X..=.0 = 0 {} | | expected integer, found floating-point number | this is of type `u8` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:46:12 | LL | if let true...Y = 0 {} @@ -332,7 +332,7 @@ LL | if let true...Y = 0 {} | | | this is of type `bool` but it should be `char` or numeric -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:48:16 | LL | if let X...true = 0 {} @@ -357,7 +357,7 @@ LL | if let X... .0 = 0 {} | | expected integer, found floating-point number | this is of type `u8` -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:61:12 | LL | if let true.. = 0 {} @@ -369,7 +369,7 @@ error[E0308]: mismatched types LL | if let .0.. = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:71:12 | LL | if let true..= = 0 {} @@ -381,7 +381,7 @@ error[E0308]: mismatched types LL | if let .0..= = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:81:12 | LL | if let true... = 0 {} @@ -393,7 +393,7 @@ error[E0308]: mismatched types LL | if let .0... = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:91:14 | LL | if let ..true = 0 {} @@ -405,7 +405,7 @@ error[E0308]: mismatched types LL | if let .. .0 = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:101:15 | LL | if let ..=true = 0 {} @@ -417,7 +417,7 @@ error[E0308]: mismatched types LL | if let ..=.0 = 0 {} | ^^ expected integer, found floating-point number -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/recover-range-pats.rs:113:15 | LL | if let ...true = 0 {} diff --git a/src/test/ui/parser/removed-syntax-with-2.rs b/src/test/ui/parser/removed-syntax-with-2.rs index f666da4969..8a489e7199 100644 --- a/src/test/ui/parser/removed-syntax-with-2.rs +++ b/src/test/ui/parser/removed-syntax-with-2.rs @@ -7,5 +7,5 @@ fn main() { let a = S { foo: (), bar: () }; let b = S { foo: (), with a }; //~^ ERROR expected one of `,` or `}`, found `a` - //~| ERROR missing field `bar` in initializer of `main::S` + //~| ERROR missing field `bar` in initializer of `S` } diff --git a/src/test/ui/parser/removed-syntax-with-2.stderr b/src/test/ui/parser/removed-syntax-with-2.stderr index 024c97cc9c..2c96dceb58 100644 --- a/src/test/ui/parser/removed-syntax-with-2.stderr +++ b/src/test/ui/parser/removed-syntax-with-2.stderr @@ -6,7 +6,7 @@ LL | let b = S { foo: (), with a }; | | | while parsing this struct -error[E0063]: missing field `bar` in initializer of `main::S` +error[E0063]: missing field `bar` in initializer of `S` --> $DIR/removed-syntax-with-2.rs:8:13 | LL | let b = S { foo: (), with a }; diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.rs b/src/test/ui/parser/shebang/shebang-doc-comment.rs index 7dbb9eebc7..72866753e0 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.rs +++ b/src/test/ui/parser/shebang/shebang-doc-comment.rs @@ -1,6 +1,3 @@ #!///bin/bash [allow(unused_variables)] -//~^^ ERROR expected `[`, found doc comment - -// Doc comment is misinterpreted as a whitespace (regular comment) during shebang detection. -// Even if it wasn't, it would still result in an error, just a different one. +//~^ ERROR expected item, found `[` diff --git a/src/test/ui/parser/shebang/shebang-doc-comment.stderr b/src/test/ui/parser/shebang/shebang-doc-comment.stderr index f524f55683..2227d45ec5 100644 --- a/src/test/ui/parser/shebang/shebang-doc-comment.stderr +++ b/src/test/ui/parser/shebang/shebang-doc-comment.stderr @@ -1,8 +1,8 @@ -error: expected `[`, found doc comment `///bin/bash` - --> $DIR/shebang-doc-comment.rs:1:3 +error: expected item, found `[` + --> $DIR/shebang-doc-comment.rs:2:1 | -LL | #!///bin/bash - | ^^^^^^^^^^^ expected `[` +LL | [allow(unused_variables)] + | ^ expected item error: aborting due to previous error diff --git a/src/test/ui/parser/struct-literal-in-for.stderr b/src/test/ui/parser/struct-literal-in-for.stderr index 2e59914864..42f5f1e7e7 100644 --- a/src/test/ui/parser/struct-literal-in-for.stderr +++ b/src/test/ui/parser/struct-literal-in-for.stderr @@ -23,8 +23,8 @@ LL | | x: 3 LL | | }.hi() { | |__________^ `bool` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `bool` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `bool` + = note: required by `into_iter` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr index a32a27bf98..d63a50034c 100644 --- a/src/test/ui/parser/unclosed-delimiter-in-dep.stderr +++ b/src/test/ui/parser/unclosed-delimiter-in-dep.stderr @@ -18,7 +18,7 @@ LL | let _: usize = unclosed_delim_mod::new(); | expected due to this | = note: expected type `usize` - found enum `std::result::Result` + found enum `std::result::Result` error: aborting due to 2 previous errors diff --git a/src/test/ui/parser/unicode-quote-chars.rs b/src/test/ui/parser/unicode-quote-chars.rs index 1812dad81a..eeaea3628b 100644 --- a/src/test/ui/parser/unicode-quote-chars.rs +++ b/src/test/ui/parser/unicode-quote-chars.rs @@ -6,5 +6,5 @@ fn main() { //~^^ HELP Unicode characters '“' (Left Double Quotation Mark) and '”' (Right Double Quotation Mark) look like '"' (Quotation Mark), but are not //~^^^ ERROR unknown start of token: \u{201d} //~^^^^ HELP Unicode character '”' (Right Double Quotation Mark) looks like '"' (Quotation Mark), but it is not - //~^^^^^ ERROR expected token: `,` + //~^^^^^ ERROR expected `,`, found `world` } diff --git a/src/test/ui/parser/unicode-quote-chars.stderr b/src/test/ui/parser/unicode-quote-chars.stderr index 4b0cb96ed2..d9ec92b3f8 100644 --- a/src/test/ui/parser/unicode-quote-chars.stderr +++ b/src/test/ui/parser/unicode-quote-chars.stderr @@ -20,7 +20,7 @@ help: Unicode character '”' (Right Double Quotation Mark) looks like '"' (Quot LL | println!(“hello world"); | ^ -error: expected token: `,` +error: expected `,`, found `world` --> $DIR/unicode-quote-chars.rs:4:21 | LL | println!(“hello world”); diff --git a/src/test/ui/parser/unsafe-foreign-mod.rs b/src/test/ui/parser/unsafe-foreign-mod.rs new file mode 100644 index 0000000000..872af95bd2 --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.rs @@ -0,0 +1,9 @@ +unsafe extern { + //~^ ERROR extern block cannot be declared unsafe +} + +unsafe extern "C" { + //~^ ERROR extern block cannot be declared unsafe +} + +fn main() {} diff --git a/src/test/ui/parser/unsafe-foreign-mod.stderr b/src/test/ui/parser/unsafe-foreign-mod.stderr new file mode 100644 index 0000000000..5e10988051 --- /dev/null +++ b/src/test/ui/parser/unsafe-foreign-mod.stderr @@ -0,0 +1,14 @@ +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:1:1 + | +LL | unsafe extern { + | ^^^^^^ + +error: extern block cannot be declared unsafe + --> $DIR/unsafe-foreign-mod.rs:5:1 + | +LL | unsafe extern "C" { + | ^^^^^^ + +error: aborting due to 2 previous errors + diff --git a/src/test/ui/parser/unsafe-mod.rs b/src/test/ui/parser/unsafe-mod.rs new file mode 100644 index 0000000000..7916d878ea --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.rs @@ -0,0 +1,9 @@ +unsafe mod m { + //~^ ERROR module cannot be declared unsafe +} + +unsafe mod n; +//~^ ERROR module cannot be declared unsafe +//~^^ ERROR file not found for module `n` + +fn main() {} diff --git a/src/test/ui/parser/unsafe-mod.stderr b/src/test/ui/parser/unsafe-mod.stderr new file mode 100644 index 0000000000..259b2c1d61 --- /dev/null +++ b/src/test/ui/parser/unsafe-mod.stderr @@ -0,0 +1,23 @@ +error[E0583]: file not found for module `n` + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^^^^^^^^ + | + = help: to create the module `n`, create file "$DIR/n.rs" + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:1:1 + | +LL | unsafe mod m { + | ^^^^^^ + +error: module cannot be declared unsafe + --> $DIR/unsafe-mod.rs:5:1 + | +LL | unsafe mod n; + | ^^^^^^ + +error: aborting due to 3 previous errors + +For more information about this error, try `rustc --explain E0583`. diff --git a/src/test/ui/partialeq_help.stderr b/src/test/ui/partialeq_help.stderr index 6acc09b62c..6decbef1af 100644 --- a/src/test/ui/partialeq_help.stderr +++ b/src/test/ui/partialeq_help.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `&T` with `T` LL | a == b; | ^^ no implementation for `&T == T` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&T` + = help: the trait `PartialEq` is not implemented for `&T` error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr index 56613ee761..d28edd11e1 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-move-and-move.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:14:13 | LL | let a @ b = U; - | ----^ - move occurs because value has type `main::U`, which does not implement the `Copy` trait + | ----^ - move occurs because value has type `U`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -11,7 +11,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:16:17 | LL | let a @ (b, c) = (U, U); - | --------^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | --------^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -20,7 +20,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:18:17 | LL | let a @ (b, c) = (u(), u()); - | --------^- ---------- move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | --------^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -29,7 +29,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:21:16 | LL | match Ok(U) { - | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait + | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} | -------^- | | | @@ -40,7 +40,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:21:29 | LL | match Ok(U) { - | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait + | ----- move occurs because value has type `std::result::Result`, which does not implement the `Copy` trait LL | a @ Ok(b) | a @ Err(b) => {} | --------^- | | | @@ -51,7 +51,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:28:22 | LL | match [u(), u(), u(), u()] { - | -------------------- move occurs because value has type `[main::U; 4]`, which does not implement the `Copy` trait + | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait LL | xs @ [a, .., b] => {} | -------------^- | | | @@ -62,7 +62,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-move-and-move.rs:32:18 | LL | match [u(), u(), u(), u()] { - | -------------------- move occurs because value has type `[main::U; 4]`, which does not implement the `Copy` trait + | -------------------- move occurs because value has type `[U; 4]`, which does not implement the `Copy` trait LL | xs @ [_, ys @ .., _] => {} | ---------^^^^^^^---- | | | @@ -77,7 +77,7 @@ LL | fn fun(a @ b: U) {} | | | | | value used here after move | value moved here - | move occurs because value has type `main::U`, which does not implement the `Copy` trait + | move occurs because value has type `U`, which does not implement the `Copy` trait error: aborting due to 8 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr index 5ce546f08b..44888369ab 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-at-and-box.stderr @@ -74,7 +74,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:21:18 | LL | let a @ box &b = Box::new(&C); - | ---------^ ------------ move occurs because value has type `std::boxed::Box<&C>`, which does not implement the `Copy` trait + | ---------^ ------------ move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -83,7 +83,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:24:17 | LL | let a @ box b = Box::new(C); - | --------^ ----------- move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | --------^ ----------- move occurs because value has type `Box`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -92,7 +92,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:34:17 | LL | match Box::new(C) { - | ----------- move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | ----------- move occurs because value has type `Box`, which does not implement the `Copy` trait LL | a @ box b => {} | --------^ | | | @@ -143,7 +143,7 @@ LL | fn f1(a @ box &b: Box<&C>) {} | | | | | value used here after move | value moved here - | move occurs because value has type `std::boxed::Box<&C>`, which does not implement the `Copy` trait + | move occurs because value has type `Box<&C>`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-at-and-box.rs:30:19 @@ -153,7 +153,7 @@ LL | fn f2(a @ box b: Box) {} | | | | | value used here after move | value moved here - | move occurs because value has type `std::boxed::Box`, which does not implement the `Copy` trait + | move occurs because value has type `Box`, which does not implement the `Copy` trait error[E0502]: cannot borrow value as immutable because it is also borrowed as mutable --> $DIR/borrowck-pat-at-and-box.rs:58:27 diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr index 54900e958c..dacf23f9de 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse-promotion.stderr @@ -6,7 +6,7 @@ LL | let a @ ref b = U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr index 5058998f2a..86e09e5558 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-by-move-and-ref-inverse.stderr @@ -6,7 +6,7 @@ LL | let a @ ref b = U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:9 @@ -17,7 +17,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:14 @@ -27,7 +27,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 @@ -37,7 +37,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:9 @@ -48,7 +48,7 @@ LL | let a @ [ref mut b, ref c] = [U, U]; | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:9 @@ -58,7 +58,7 @@ LL | let a @ ref b = u(); | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:9 @@ -69,7 +69,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:14 @@ -79,7 +79,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 @@ -89,7 +89,7 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:9 @@ -100,7 +100,7 @@ LL | let a @ [ref mut b, ref c] = [u(), u()]; | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:56:9 @@ -110,7 +110,7 @@ LL | a @ Some(ref b) => {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option` which does not implement the `Copy` trait + | move occurs because `a` has type `Option` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:9 @@ -121,7 +121,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:19 @@ -131,7 +131,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 @@ -141,7 +141,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:9 @@ -152,7 +152,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:9 @@ -162,7 +162,7 @@ LL | a @ Some(ref b) => {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option` which does not implement the `Copy` trait + | move occurs because `a` has type `Option` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:9 @@ -173,7 +173,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<(main::U, main::U)>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<(U, U)>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:19 @@ -183,7 +183,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 @@ -193,7 +193,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:9 @@ -204,7 +204,7 @@ LL | mut a @ Some([ref b, ref mut c]) => {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `std::option::Option<[main::U; 2]>` which does not implement the `Copy` trait + | move occurs because `a` has type `Option<[U; 2]>` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:14:11 @@ -214,7 +214,7 @@ LL | fn f1(a @ ref b: U) {} | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:11 @@ -225,7 +225,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:20 @@ -235,7 +235,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::U` which does not implement the `Copy` trait + | move occurs because `b` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 @@ -245,7 +245,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value borrowed here after move | value moved into `d` here - | move occurs because `d` has type `main::U` which does not implement the `Copy` trait + | move occurs because `d` has type `U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:11 @@ -256,7 +256,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `[main::U; 2]` which does not implement the `Copy` trait + | move occurs because `a` has type `[U; 2]` which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:22 @@ -267,13 +267,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:31:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); - | ------------------------^^^^^^^^^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | ------------------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -287,13 +287,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (U, U); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:38:25 | LL | let a @ [ref mut b, ref c] = [U, U]; - | ----------------^^^^^- ------ move occurs because value has type `[main::U; 2]`, which does not implement the `Copy` trait + | ----------------^^^^^- ------ move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -302,7 +302,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:41:13 | LL | let a @ ref b = u(); - | ----^^^^^ --- move occurs because value has type `main::U`, which does not implement the `Copy` trait + | ----^^^^^ --- move occurs because value has type `U`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -316,13 +316,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:44:33 | LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); - | ------------------------^^^^^^^^^- ---------- move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | ------------------------^^^^^^^^^- ---------- move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value used here after move | value moved here @@ -336,13 +336,13 @@ LL | let a @ (mut b @ ref mut c, d @ ref e) = (u(), u()); | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:51:25 | LL | let a @ [ref mut b, ref c] = [u(), u()]; - | ----------------^^^^^- ---------- move occurs because value has type `[main::U; 2]`, which does not implement the `Copy` trait + | ----------------^^^^^- ---------- move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -356,7 +356,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} @@ -366,7 +366,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:61:38 | LL | match Some((U, U)) { - | ------------ move occurs because value has type `std::option::Option<(main::U, main::U)>`, which does not implement the `Copy` trait + | ------------ move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----------------------------^^^^^^^^^-- | | | @@ -382,7 +382,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} @@ -392,7 +392,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:71:30 | LL | match Some([U, U]) { - | ------------ move occurs because value has type `std::option::Option<[main::U; 2]>`, which does not implement the `Copy` trait + | ------------ move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait LL | mut a @ Some([ref b, ref mut c]) => {} | ---------------------^^^^^^^^^-- | | | @@ -403,7 +403,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:77:18 | LL | match Some(u()) { - | --------- move occurs because value has type `std::option::Option`, which does not implement the `Copy` trait + | --------- move occurs because value has type `Option`, which does not implement the `Copy` trait LL | a @ Some(ref b) => {} | ---------^^^^^- | | | @@ -419,7 +419,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((ref mut b @ ref mut c, d @ ref e)) => {} @@ -429,7 +429,7 @@ error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:83:38 | LL | match Some((u(), u())) { - | ---------------- move occurs because value has type `std::option::Option<(main::U, main::U)>`, which does not implement the `Copy` trait + | ---------------- move occurs because value has type `Option<(U, U)>`, which does not implement the `Copy` trait LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | -----------------------------^^^^^^^^^-- | | | @@ -445,7 +445,7 @@ LL | a @ Some((mut b @ ref mut c, d @ ref e)) => {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving the value | LL | a @ Some((mut b @ ref mut c, ref d @ ref e)) => {} @@ -455,7 +455,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:93:30 | LL | match Some([u(), u()]) { - | ---------------- move occurs because value has type `std::option::Option<[main::U; 2]>`, which does not implement the `Copy` trait + | ---------------- move occurs because value has type `Option<[U; 2]>`, which does not implement the `Copy` trait LL | mut a @ Some([ref b, ref mut c]) => {} | ---------------------^^^^^^^^^-- | | | @@ -470,7 +470,7 @@ LL | fn f1(a @ ref b: U) {} | | | | | value borrowed here after move | value moved here - | move occurs because value has type `main::U`, which does not implement the `Copy` trait + | move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:24 @@ -481,7 +481,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: use of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:31 @@ -491,7 +491,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | | | | value used here after move | value moved here - | move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | move occurs because value has type `(U, U)`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:18:39 @@ -502,7 +502,7 @@ LL | fn f2(mut a @ (b @ ref c, mut d @ ref e): (U, U)) {} | | value borrowed here after move | value moved here | - = note: move occurs because value has type `main::U`, which does not implement the `Copy` trait + = note: move occurs because value has type `U`, which does not implement the `Copy` trait error[E0382]: borrow of moved value --> $DIR/borrowck-pat-by-move-and-ref-inverse.rs:25:27 @@ -512,7 +512,7 @@ LL | fn f3(a @ [ref mut b, ref c]: [U; 2]) {} | | | | | value borrowed here after move | value moved here - | move occurs because value has type `[main::U; 2]`, which does not implement the `Copy` trait + | move occurs because value has type `[U; 2]`, which does not implement the `Copy` trait error: aborting due to 48 previous errors diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr index b161054414..695da9639a 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-and-ref.stderr @@ -374,7 +374,7 @@ error[E0507]: cannot move out of `b` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} - | ^ move occurs because `b` has type `&mut main::U`, which does not implement the `Copy` trait + | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -382,7 +382,7 @@ error[E0507]: cannot move out of `b` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:103:66 | LL | ref a @ Ok(ref mut b) | ref a @ Err(ref mut b) if { drop(b); false } => {} - | ^ move occurs because `b` has type `&mut main::U`, which does not implement the `Copy` trait + | ^ move occurs because `b` has type `&mut U`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -390,7 +390,7 @@ error[E0507]: cannot move out of `a` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} - | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait + | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard @@ -398,7 +398,7 @@ error[E0507]: cannot move out of `a` in pattern guard --> $DIR/borrowck-pat-ref-mut-and-ref.rs:111:66 | LL | ref mut a @ Ok(ref b) | ref mut a @ Err(ref b) if { drop(a); false } => {} - | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait + | ^ move occurs because `a` has type `&mut std::result::Result`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr index ae7c8f38e1..1cd3e267b9 100644 --- a/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr +++ b/src/test/ui/pattern/bindings-after-at/borrowck-pat-ref-mut-twice.stderr @@ -96,7 +96,7 @@ LL | let a @ (ref mut b, ref mut c) = (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `(main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `(U, U)` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:70:9 @@ -108,7 +108,7 @@ LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut (main::U, [main::U; 2])` which does not implement the `Copy` trait + | move occurs because `a` has type `&mut (U, [U; 2])` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:74:9 @@ -118,7 +118,7 @@ LL | let a @ &mut ref mut b = &mut U; | | | | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut main::U` which does not implement the `Copy` trait + | move occurs because `a` has type `&mut U` which does not implement the `Copy` trait error: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:77:9 @@ -129,7 +129,7 @@ LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); | | | value borrowed here after move | | value borrowed here after move | value moved into `a` here - | move occurs because `a` has type `&mut (main::U, main::U)` which does not implement the `Copy` trait + | move occurs because `a` has type `&mut (U, U)` which does not implement the `Copy` trait error: cannot borrow value as mutable more than once at a time --> $DIR/borrowck-pat-ref-mut-twice.rs:82:9 @@ -286,7 +286,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:66:25 | LL | let a @ (ref mut b, ref mut c) = (U, U); - | ----------------^^^^^^^^^- ------ move occurs because value has type `(main::U, main::U)`, which does not implement the `Copy` trait + | ----------------^^^^^^^^^- ------ move occurs because value has type `(U, U)`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -295,7 +295,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:70:21 | LL | let a @ (b, [c, d]) = &mut val; // Same as ^-- - | ------------^-- -------- move occurs because value has type `&mut (main::U, [main::U; 2])`, which does not implement the `Copy` trait + | ------------^-- -------- move occurs because value has type `&mut (U, [U; 2])`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -304,7 +304,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:74:18 | LL | let a @ &mut ref mut b = &mut U; - | ---------^^^^^^^^^ ------ move occurs because value has type `&mut main::U`, which does not implement the `Copy` trait + | ---------^^^^^^^^^ ------ move occurs because value has type `&mut U`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here @@ -313,7 +313,7 @@ error[E0382]: borrow of moved value --> $DIR/borrowck-pat-ref-mut-twice.rs:77:30 | LL | let a @ &mut (ref mut b, ref mut c) = &mut (U, U); - | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (main::U, main::U)`, which does not implement the `Copy` trait + | ---------------------^^^^^^^^^- ----------- move occurs because value has type `&mut (U, U)`, which does not implement the `Copy` trait | | | | | value borrowed here after move | value moved here diff --git a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr index 141d667c74..a63a5a1e6c 100644 --- a/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr +++ b/src/test/ui/pattern/bindings-after-at/default-binding-modes-both-sides-independent.stderr @@ -33,7 +33,7 @@ LL | Ok(ref a @ b) | Err(b @ ref a) => { | | | | | value borrowed here after move | value moved into `b` here - | move occurs because `b` has type `main::NotCopy` which does not implement the `Copy` trait + | move occurs because `b` has type `NotCopy` which does not implement the `Copy` trait error: cannot move out of value because it is borrowed --> $DIR/default-binding-modes-both-sides-independent.rs:44:9 diff --git a/src/test/ui/pattern/const-pat-ice.rs b/src/test/ui/pattern/const-pat-ice.rs index 0655876788..abfacf3936 100644 --- a/src/test/ui/pattern/const-pat-ice.rs +++ b/src/test/ui/pattern/const-pat-ice.rs @@ -1,10 +1,4 @@ -// failure-status: 101 -// rustc-env:RUST_BACKTRACE=0 -// normalize-stderr-test "note: rustc 1.* running on .*" -> "note: rustc VERSION running on TARGET" -// normalize-stderr-test "note: compiler flags: .*" -> "note: compiler flags: FLAGS" -// normalize-stderr-test "/_match.rs:[0-9]+:[0-9]+" -> "/_match.rs:LL:CC" - -// This is a repro test for an ICE in our pattern handling of constants. +// check-pass const FOO: &&&u32 = &&&42; diff --git a/src/test/ui/pattern/const-pat-ice.stderr b/src/test/ui/pattern/const-pat-ice.stderr deleted file mode 100644 index 2aa0824f30..0000000000 --- a/src/test/ui/pattern/const-pat-ice.stderr +++ /dev/null @@ -1,13 +0,0 @@ -thread 'rustc' panicked at 'assertion failed: rows.iter().all(|r| r.len() == v.len())', src/librustc_mir_build/thir/pattern/_match.rs:LL:CC -note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace - -error: internal compiler error: unexpected panic - -note: the compiler unexpectedly panicked. this is a bug. - -note: we would appreciate a bug report: https://github.com/rust-lang/rust/issues/new?labels=C-bug%2C+I-ICE%2C+T-compiler&template=ice.md - -note: rustc VERSION running on TARGET - -note: compiler flags: FLAGS - diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs index c5e4a72fb9..65f27cf78f 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.rs @@ -4,6 +4,7 @@ fn main() { const C: impl Copy = 0; match C { - C | _ => {} //~ ERROR: opaque types cannot be used in patterns + C | //~ ERROR: `impl Copy` cannot be used in patterns + _ => {} } } diff --git a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr index 7695223f2c..62dc856be8 100644 --- a/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr +++ b/src/test/ui/pattern/issue-71042-opaquely-typed-constant-used-in-pattern.stderr @@ -1,7 +1,7 @@ -error: opaque types cannot be used in patterns +error: `impl Copy` cannot be used in patterns --> $DIR/issue-71042-opaquely-typed-constant-used-in-pattern.rs:7:9 | -LL | C | _ => {} +LL | C | | ^ error: aborting due to previous error diff --git a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr index eb5391a95d..5335569a97 100644 --- a/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr +++ b/src/test/ui/pattern/move-ref-patterns/feature-gate-move_ref_pattern.stderr @@ -49,7 +49,7 @@ LL | let (a, mut b) = &tup; | ----- ^^^^ | | | data moved here - | move occurs because `b` has type `main::X`, which does not implement the `Copy` trait + | move occurs because `b` has type `X`, which does not implement the `Copy` trait error[E0507]: cannot move out of a mutable reference --> $DIR/feature-gate-move_ref_pattern.rs:20:22 @@ -58,7 +58,7 @@ LL | let (mut a, b) = &mut tup; | ----- ^^^^^^^^ | | | data moved here - | move occurs because `a` has type `main::X`, which does not implement the `Copy` trait + | move occurs because `a` has type `X`, which does not implement the `Copy` trait error: aborting due to 6 previous errors diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr index 9159e3e221..9ad8487959 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-closure-captures-inside.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `tup0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:33:10 | LL | let mut tup0 = (S, S); - | -------- move occurs because `tup0` has type `(main::S, main::S)`, which does not implement the `Copy` trait + | -------- move occurs because `tup0` has type `(S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -17,7 +17,7 @@ error[E0382]: borrow of moved value: `tup1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:34:10 | LL | let mut tup1 = (S, S, S); - | -------- move occurs because `tup1` has type `(main::S, main::S, main::S)`, which does not implement the `Copy` trait + | -------- move occurs because `tup1` has type `(S, S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -32,7 +32,7 @@ error[E0382]: borrow of moved value: `tup2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:35:10 | LL | let tup2 = (S, S); - | ---- move occurs because `tup2` has type `(main::S, main::S)`, which does not implement the `Copy` trait + | ---- move occurs because `tup2` has type `(S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -47,7 +47,7 @@ error[E0382]: borrow of moved value: `tup3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:36:10 | LL | let tup3 = (S, S, S); - | ---- move occurs because `tup3` has type `(main::S, main::S, main::S)`, which does not implement the `Copy` trait + | ---- move occurs because `tup3` has type `(S, S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -62,7 +62,7 @@ error[E0382]: borrow of moved value: `tup4` --> $DIR/move-ref-patterns-closure-captures-inside.rs:41:10 | LL | let tup4 = (S, S); - | ---- move occurs because `tup4` has type `(main::S, main::S)`, which does not implement the `Copy` trait + | ---- move occurs because `tup4` has type `(S, S)`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -77,7 +77,7 @@ error[E0382]: borrow of moved value: `arr0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:43:10 | LL | let mut arr0 = [S, S, S]; - | -------- move occurs because `arr0` has type `[main::S; 3]`, which does not implement the `Copy` trait + | -------- move occurs because `arr0` has type `[S; 3]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -92,7 +92,7 @@ error[E0382]: borrow of moved value: `arr1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:44:36 | LL | let mut arr1 = [S, S, S, S, S]; - | -------- move occurs because `arr1` has type `[main::S; 5]`, which does not implement the `Copy` trait + | -------- move occurs because `arr1` has type `[S; 5]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -107,7 +107,7 @@ error[E0382]: borrow of moved value: `arr2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:45:10 | LL | let arr2 = [S, S, S]; - | ---- move occurs because `arr2` has type `[main::S; 3]`, which does not implement the `Copy` trait + | ---- move occurs because `arr2` has type `[S; 3]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -122,7 +122,7 @@ error[E0382]: borrow of moved value: `arr3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:46:36 | LL | let arr3 = [S, S, S, S, S]; - | ---- move occurs because `arr3` has type `[main::S; 5]`, which does not implement the `Copy` trait + | ---- move occurs because `arr3` has type `[S; 5]`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -137,7 +137,7 @@ error[E0382]: borrow of moved value: `tup0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:77:10 | LL | let mut tup0: Option<(S, S)> = None; - | -------- move occurs because `tup0` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -151,7 +151,7 @@ error[E0382]: borrow of moved value: `tup1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:78:10 | LL | let mut tup1: Option<(S, S, S)> = None; - | -------- move occurs because `tup1` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -166,7 +166,7 @@ error[E0382]: borrow of moved value: `tup2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:79:10 | LL | let tup2: Option<(S, S)> = None; - | ---- move occurs because `tup2` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -181,7 +181,7 @@ error[E0382]: borrow of moved value: `tup3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:80:10 | LL | let tup3: Option<(S, S, S)> = None; - | ---- move occurs because `tup3` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -196,7 +196,7 @@ error[E0382]: borrow of moved value: `tup4` --> $DIR/move-ref-patterns-closure-captures-inside.rs:81:21 | LL | let tup4: Option<(S, S)> = None; - | ---- move occurs because `tup4` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -211,7 +211,7 @@ error[E0382]: borrow of moved value: `arr0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:82:10 | LL | let mut arr0: Option<[S; 3]> = None; - | -------- move occurs because `arr0` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -226,7 +226,7 @@ error[E0382]: borrow of moved value: `arr1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:83:35 | LL | let mut arr1: Option<[S; 5]> = None; - | -------- move occurs because `arr1` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -241,7 +241,7 @@ error[E0382]: borrow of moved value: `arr2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:84:10 | LL | let arr2: Option<[S; 3]> = None; - | ---- move occurs because `arr2` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait LL | let arr3: Option<[S; 5]> = None; LL | let mut closure = || { | -- value moved into closure here @@ -256,7 +256,7 @@ error[E0382]: borrow of moved value: `arr3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:85:35 | LL | let arr3: Option<[S; 5]> = None; - | ---- move occurs because `arr3` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait LL | let mut closure = || { | -- value moved into closure here ... @@ -270,7 +270,7 @@ error[E0382]: borrow of moved value: `tup0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:113:10 | LL | let mut tup0: Option<(S, S)> = None; - | -------- move occurs because `tup0` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup0` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -284,7 +284,7 @@ error[E0382]: borrow of moved value: `tup1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:114:10 | LL | let mut tup1: Option<(S, S, S)> = None; - | -------- move occurs because `tup1` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | -------- move occurs because `tup1` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -299,7 +299,7 @@ error[E0382]: borrow of moved value: `tup2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:115:10 | LL | let tup2: Option<(S, S)> = None; - | ---- move occurs because `tup2` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup2` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -314,7 +314,7 @@ error[E0382]: borrow of moved value: `tup3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:116:10 | LL | let tup3: Option<(S, S, S)> = None; - | ---- move occurs because `tup3` has type `std::option::Option<(main::S, main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup3` has type `Option<(S, S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -329,7 +329,7 @@ error[E0382]: borrow of moved value: `tup4` --> $DIR/move-ref-patterns-closure-captures-inside.rs:117:21 | LL | let tup4: Option<(S, S)> = None; - | ---- move occurs because `tup4` has type `std::option::Option<(main::S, main::S)>`, which does not implement the `Copy` trait + | ---- move occurs because `tup4` has type `Option<(S, S)>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -344,7 +344,7 @@ error[E0382]: borrow of moved value: `arr0` --> $DIR/move-ref-patterns-closure-captures-inside.rs:118:10 | LL | let mut arr0: Option<[S; 3]> = None; - | -------- move occurs because `arr0` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr0` has type `Option<[S; 3]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -359,7 +359,7 @@ error[E0382]: borrow of moved value: `arr1` --> $DIR/move-ref-patterns-closure-captures-inside.rs:119:35 | LL | let mut arr1: Option<[S; 5]> = None; - | -------- move occurs because `arr1` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | -------- move occurs because `arr1` has type `Option<[S; 5]>`, which does not implement the `Copy` trait ... LL | let mut closure = || { | -- value moved into closure here @@ -374,7 +374,7 @@ error[E0382]: borrow of moved value: `arr2` --> $DIR/move-ref-patterns-closure-captures-inside.rs:120:10 | LL | let arr2: Option<[S; 3]> = None; - | ---- move occurs because `arr2` has type `std::option::Option<[main::S; 3]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr2` has type `Option<[S; 3]>`, which does not implement the `Copy` trait LL | let arr3: Option<[S; 5]> = None; LL | let mut closure = || { | -- value moved into closure here @@ -389,7 +389,7 @@ error[E0382]: borrow of moved value: `arr3` --> $DIR/move-ref-patterns-closure-captures-inside.rs:121:35 | LL | let arr3: Option<[S; 5]> = None; - | ---- move occurs because `arr3` has type `std::option::Option<[main::S; 5]>`, which does not implement the `Copy` trait + | ---- move occurs because `arr3` has type `Option<[S; 5]>`, which does not implement the `Copy` trait LL | let mut closure = || { | -- value moved into closure here ... diff --git a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr index fe7f71e6c4..f92699f5c3 100644 --- a/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr +++ b/src/test/ui/pattern/move-ref-patterns/move-ref-patterns-default-binding-modes.stderr @@ -5,7 +5,7 @@ LL | let (a, mut b) = &p; | ----- ^^ | | | data moved here - | move occurs because `b` has type `main::U`, which does not implement the `Copy` trait + | move occurs because `b` has type `U`, which does not implement the `Copy` trait error[E0507]: cannot move out of a mutable reference --> $DIR/move-ref-patterns-default-binding-modes.rs:14:22 @@ -14,7 +14,7 @@ LL | let (a, mut b) = &mut p; | ----- ^^^^^^ | | | data moved here - | move occurs because `b` has type `main::U`, which does not implement the `Copy` trait + | move occurs because `b` has type `U`, which does not implement the `Copy` trait error: aborting due to 2 previous errors diff --git a/src/test/ui/pattern/pat-type-err-formal-param.stderr b/src/test/ui/pattern/pat-type-err-formal-param.stderr index 2d7eb62fae..206713a4bf 100644 --- a/src/test/ui/pattern/pat-type-err-formal-param.stderr +++ b/src/test/ui/pattern/pat-type-err-formal-param.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn foo(Tuple(_): String) {} | ^^^^^^^^ ------ expected due to this | | - | expected struct `std::string::String`, found struct `Tuple` + | expected struct `String`, found struct `Tuple` error: aborting due to previous error diff --git a/src/test/ui/pattern/pat-type-err-let-stmt.stderr b/src/test/ui/pattern/pat-type-err-let-stmt.stderr index d75fa3f247..42258cfc1a 100644 --- a/src/test/ui/pattern/pat-type-err-let-stmt.stderr +++ b/src/test/ui/pattern/pat-type-err-let-stmt.stderr @@ -4,11 +4,11 @@ error[E0308]: mismatched types LL | let Ok(0): Option = 42u8; | ---------- ^^^^ | | | - | | expected enum `std::option::Option`, found `u8` + | | expected enum `Option`, found `u8` | | help: try using a variant of the expected enum: `Some(42u8)` | expected due to this | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found type `u8` error[E0308]: mismatched types @@ -17,9 +17,9 @@ error[E0308]: mismatched types LL | let Ok(0): Option = 42u8; | ^^^^^ ---------- expected due to this | | - | expected enum `std::option::Option`, found enum `std::result::Result` + | expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found enum `std::result::Result<_, _>` error[E0308]: mismatched types @@ -28,9 +28,9 @@ error[E0308]: mismatched types LL | let Ok(0): Option; | ^^^^^ ---------- expected due to this | | - | expected enum `std::option::Option`, found enum `std::result::Result` + | expected enum `Option`, found enum `std::result::Result` | - = note: expected enum `std::option::Option` + = note: expected enum `Option` found enum `std::result::Result<_, _>` error[E0308]: mismatched types diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.rs b/src/test/ui/pattern/patkind-litrange-no-expr.rs index 5b3db2e57c..9464f277fb 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.rs +++ b/src/test/ui/pattern/patkind-litrange-no-expr.rs @@ -19,7 +19,7 @@ enum_number!(Change { 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 + //~| ERROR only `char` and numeric types are allowed in range patterns }); fn main() {} diff --git a/src/test/ui/pattern/patkind-litrange-no-expr.stderr b/src/test/ui/pattern/patkind-litrange-no-expr.stderr index 70dd1a9263..51af167a7c 100644 --- a/src/test/ui/pattern/patkind-litrange-no-expr.stderr +++ b/src/test/ui/pattern/patkind-litrange-no-expr.stderr @@ -10,7 +10,7 @@ error: arbitrary expressions aren't allowed in patterns LL | Arith = 1 + 1, | ^^^^^ -error[E0029]: only char and numeric types are allowed in range patterns +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 diff --git a/src/test/ui/pattern/pattern-error-continue.rs b/src/test/ui/pattern/pattern-error-continue.rs index 8635622ab3..0702a9986f 100644 --- a/src/test/ui/pattern/pattern-error-continue.rs +++ b/src/test/ui/pattern/pattern-error-continue.rs @@ -30,6 +30,6 @@ fn main() { //~| expected `char`, found `bool` match () { - E::V => {} //~ ERROR failed to resolve: use of undeclared type or module `E` + E::V => {} //~ ERROR failed to resolve: use of undeclared type `E` } } diff --git a/src/test/ui/pattern/pattern-error-continue.stderr b/src/test/ui/pattern/pattern-error-continue.stderr index 60f76796c0..497c93b294 100644 --- a/src/test/ui/pattern/pattern-error-continue.stderr +++ b/src/test/ui/pattern/pattern-error-continue.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `E` +error[E0433]: failed to resolve: use of undeclared type `E` --> $DIR/pattern-error-continue.rs:33:9 | LL | E::V => {} - | ^ use of undeclared type or module `E` + | ^ use of undeclared type `E` error[E0532]: expected tuple struct or tuple variant, found unit variant `A::D` --> $DIR/pattern-error-continue.rs:18:9 diff --git a/src/test/ui/pattern/pattern-ident-path-generics.stderr b/src/test/ui/pattern/pattern-ident-path-generics.stderr index 24b5cdf98d..01b082bd35 100644 --- a/src/test/ui/pattern/pattern-ident-path-generics.stderr +++ b/src/test/ui/pattern/pattern-ident-path-generics.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/pattern-ident-path-generics.rs:3:9 | LL | match Some("foo") { - | ----------- this expression has type `std::option::Option<&str>` + | ----------- this expression has type `Option<&str>` LL | None:: => {} | ^^^^^^^^^^^^^ expected `&str`, found `isize` | - = note: expected enum `std::option::Option<&str>` - found enum `std::option::Option` + = note: expected enum `Option<&str>` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/pattern/pattern-tyvar-2.rs b/src/test/ui/pattern/pattern-tyvar-2.rs index 4c6d515b86..532df4fa0c 100644 --- a/src/test/ui/pattern/pattern-tyvar-2.rs +++ b/src/test/ui/pattern/pattern-tyvar-2.rs @@ -1,6 +1,6 @@ enum Bar { T1((), Option>), T2, } fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } } -//~^ ERROR cannot multiply `{integer}` to `std::vec::Vec` +//~^ ERROR cannot multiply `{integer}` to `Vec` fn main() { } diff --git a/src/test/ui/pattern/pattern-tyvar-2.stderr b/src/test/ui/pattern/pattern-tyvar-2.stderr index 9566244464..e205cd9015 100644 --- a/src/test/ui/pattern/pattern-tyvar-2.stderr +++ b/src/test/ui/pattern/pattern-tyvar-2.stderr @@ -1,10 +1,10 @@ -error[E0369]: cannot multiply `{integer}` to `std::vec::Vec` +error[E0369]: cannot multiply `{integer}` to `Vec` --> $DIR/pattern-tyvar-2.rs:3:71 | LL | fn foo(t: Bar) -> isize { match t { Bar::T1(_, Some(x)) => { return x * 3; } _ => { panic!(); } } } | - ^ - {integer} | | - | std::vec::Vec + | Vec error: aborting due to previous error diff --git a/src/test/ui/pattern/pattern-tyvar.stderr b/src/test/ui/pattern/pattern-tyvar.stderr index 15425da69b..f1e2a9d72c 100644 --- a/src/test/ui/pattern/pattern-tyvar.stderr +++ b/src/test/ui/pattern/pattern-tyvar.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | match t { | - this expression has type `Bar` LL | Bar::T1(_, Some::(x)) => { - | ^^^^^^^^^^^^^^^^ expected struct `std::vec::Vec`, found `isize` + | ^^^^^^^^^^^^^^^^ expected struct `Vec`, found `isize` | - = note: expected enum `std::option::Option>` - found enum `std::option::Option` + = note: expected enum `Option>` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs index d379dc44bf..78cc0d28fb 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.rs @@ -160,7 +160,7 @@ fn main() { match &0 { &42 => {} &FOO => {} //~ ERROR unreachable pattern - BAR => {} // Not detected as unreachable because `try_eval_bits` fails on `BAR`. + BAR => {} //~ ERROR unreachable pattern _ => {} } diff --git a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr index 161ac47718..9f076c50a8 100644 --- a/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr +++ b/src/test/ui/pattern/usefulness/exhaustive_integer_patterns.stderr @@ -77,7 +77,7 @@ LL | match (0u8, Some(())) { | ^^^^^^^^^^^^^^^ patterns `(0_u8, Some(_))` and `(2_u8..=u8::MAX, Some(_))` 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 `(u8, std::option::Option<()>)` + = note: the matched value is of type `(u8, Option<()>)` error[E0004]: non-exhaustive patterns: `(126_u8..=127_u8, false)` not covered --> $DIR/exhaustive_integer_patterns.rs:126:11 @@ -135,6 +135,12 @@ error: unreachable pattern LL | &FOO => {} | ^^^^ -error: aborting due to 15 previous errors +error: unreachable pattern + --> $DIR/exhaustive_integer_patterns.rs:163:9 + | +LL | BAR => {} + | ^^^ + +error: aborting due to 16 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/pattern/usefulness/issue-35609.stderr b/src/test/ui/pattern/usefulness/issue-35609.stderr index 66f904aced..0598c8d6f3 100644 --- a/src/test/ui/pattern/usefulness/issue-35609.stderr +++ b/src/test/ui/pattern/usefulness/issue-35609.stderr @@ -74,7 +74,7 @@ LL | match Some(A) { | ^^^^^^^ patterns `Some(B)`, `Some(C)`, `Some(D)` and 2 more 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 `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to 8 previous errors diff --git a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr index d541597508..f515525123 100644 --- a/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr +++ b/src/test/ui/pattern/usefulness/match-arm-statics-2.stderr @@ -22,7 +22,7 @@ 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 `std::option::Option>` + = note: the matched value is of type `Option>` error[E0004]: non-exhaustive patterns: `Foo { bar: Some(North), baz: NewBool(true) }` not covered --> $DIR/match-arm-statics-2.rs:48:11 diff --git a/src/test/ui/pattern/usefulness/match-privately-empty.stderr b/src/test/ui/pattern/usefulness/match-privately-empty.stderr index ca9006469e..cd157debcd 100644 --- a/src/test/ui/pattern/usefulness/match-privately-empty.stderr +++ b/src/test/ui/pattern/usefulness/match-privately-empty.stderr @@ -10,7 +10,7 @@ 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 `std::option::Option` + = note: the matched value is of type `Option` error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/match-slice-patterns.stderr b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr index ba5312d213..88f27be041 100644 --- a/src/test/ui/pattern/usefulness/match-slice-patterns.stderr +++ b/src/test/ui/pattern/usefulness/match-slice-patterns.stderr @@ -5,7 +5,7 @@ LL | match list { | ^^^^ pattern `&[_, Some(_), .., None, _]` 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 `&[std::option::Option<()>]` + = note: the matched value is of type `&[Option<()>]` error: aborting due to previous error diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr index c9f26db6f1..d1cab75210 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match-nested.stderr @@ -5,7 +5,7 @@ LL | match (l1, l2) { | ^^^^^^^^ pattern `(Some(&[]), Err(_))` 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 `(std::option::Option<&[T]>, std::result::Result<&[T], ()>)` + = note: the matched value is of type `(Option<&[T]>, std::result::Result<&[T], ()>)` error[E0004]: non-exhaustive patterns: `A(C)` not covered --> $DIR/non-exhaustive-match-nested.rs:15:11 diff --git a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr index 5d29feb562..12412743b8 100644 --- a/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr +++ b/src/test/ui/pattern/usefulness/non-exhaustive-match.stderr @@ -34,7 +34,7 @@ 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 `std::option::Option` + = note: the matched value is of type `Option` error[E0004]: non-exhaustive patterns: `(_, _, i32::MIN..=3_i32)` and `(_, _, 5_i32..=i32::MAX)` not covered --> $DIR/non-exhaustive-match.rs:14:11 @@ -76,7 +76,7 @@ LL | match *vec { | ^^^^ 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 `[std::option::Option]` + = note: the matched value is of type `[Option]` error[E0004]: non-exhaustive patterns: `[_, _, _, _, ..]` not covered --> $DIR/non-exhaustive-match.rs:46:11 diff --git a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr index 8d0409a6af..99af71cadf 100644 --- a/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr +++ b/src/test/ui/pattern/usefulness/refutable-pattern-errors.stderr @@ -4,7 +4,7 @@ error[E0005]: refutable pattern in function argument: `(_, _)` not covered LL | fn func((1, (Some(1), 2..=3)): (isize, (Option, isize))) { } | ^^^^^^^^^^^^^^^^^^^^^ pattern `(_, _)` not covered | - = note: the matched value is of type `(isize, (std::option::Option, isize))` + = note: the matched value is of type `(isize, (Option, isize))` error[E0005]: refutable pattern in local binding: `(i32::MIN..=0_i32, _)` and `(2_i32..=i32::MAX, _)` not covered --> $DIR/refutable-pattern-errors.rs:7:9 @@ -14,7 +14,7 @@ LL | let (1, (Some(1), 2..=3)) = (1, (None, 2)); | = note: `let` bindings require an "irrefutable pattern", like a `struct` or an `enum` with only one variant = note: for more information, visit https://doc.rust-lang.org/book/ch18-02-refutability.html - = note: the matched value is of type `(i32, (std::option::Option, i32))` + = note: the matched value is of type `(i32, (Option, i32))` help: you might want to use `if let` to ignore the variant that isn't matched | LL | if let (1, (Some(1), 2..=3)) = (1, (None, 2)) { /* */ } diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs index a36c550f53..4bf8d0fd2d 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), [0x00, 0x00, 0x00, 0x00] => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), MAGIC_TEST => (), - [4, 5, 6, 7] => (), // FIXME(oli-obk): this should warn, but currently does not + [4, 5, 6, 7] => (), //~ ERROR unreachable pattern _ => (), } match s { [0x00, 0x00, 0x00, 0x00] => (), [4, 5, 6, 7] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [u32; 1] = [4]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr index cd0cb2e887..dcad11a38a 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-2.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-2.rs:28:9 + --> $DIR/slice-pattern-const-2.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-2.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:15:9 + | +LL | [4, 5, 6, 7] => (), + | ^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-2.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs index 8805c43ba0..2ca8323f00 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.rs @@ -6,19 +6,19 @@ fn main() { match s { MAGIC_TEST => (), ["0x00", "0x00", "0x00", "0x00"] => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), MAGIC_TEST => (), - ["4", "5", "6", "7"] => (), // FIXME(oli-obk): this should warn, but currently does not + ["4", "5", "6", "7"] => (), //~ ERROR unreachable pattern _ => (), } match s { ["0x00", "0x00", "0x00", "0x00"] => (), ["4", "5", "6", "7"] => (), - MAGIC_TEST => (), // FIXME(oli-obk): this should warn, but currently does not + MAGIC_TEST => (), //~ ERROR unreachable pattern _ => (), } const FOO: [&str; 1] = ["boo"]; diff --git a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr index 3ba01b9eba..b90b3a88a1 100644 --- a/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr +++ b/src/test/ui/pattern/usefulness/slice-pattern-const-3.stderr @@ -1,8 +1,8 @@ error: unreachable pattern - --> $DIR/slice-pattern-const-3.rs:28:9 + --> $DIR/slice-pattern-const-3.rs:9:9 | -LL | FOO => (), - | ^^^ +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ | note: the lint level is defined here --> $DIR/slice-pattern-const-3.rs:1:9 @@ -10,5 +10,23 @@ note: the lint level is defined here LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:15:9 + | +LL | ["4", "5", "6", "7"] => (), + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:21:9 + | +LL | MAGIC_TEST => (), + | ^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice-pattern-const-3.rs:28:9 + | +LL | FOO => (), + | ^^^ + +error: aborting due to 4 previous errors diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs index 52d1320dad..46e0da5be9 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -6,15 +6,15 @@ fn main() { let s10: &[bool; 10] = &[false; 10]; match s2 { - //~^ ERROR `&[false, _]` not covered + //~^ ERROR `&[false, _]` not covered [true, .., true] => {} } match s3 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } match s10 { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [true, .., true] => {} } @@ -23,58 +23,58 @@ fn main() { [.., false] => {} } match s2 { - //~^ ERROR `&[false, true]` not covered + //~^ ERROR `&[false, true]` not covered [true, ..] => {} [.., false] => {} } match s3 { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[false, .., true]` not covered + //~^ ERROR `&[false, .., true]` not covered [] => {} [true, ..] => {} [.., false] => {} } match s { - //~^ ERROR `&[_, ..]` not covered + //~^ ERROR `&[_, ..]` not covered [] => {} } match s { - //~^ ERROR `&[_, _, ..]` not covered + //~^ ERROR `&[_, _, ..]` not covered [] => {} [_] => {} } match s { - //~^ ERROR `&[false, ..]` not covered + //~^ ERROR `&[false, ..]` not covered [] => {} [true, ..] => {} } match s { - //~^ ERROR `&[false, _, ..]` not covered + //~^ ERROR `&[false, _, ..]` not covered [] => {} [_] => {} [true, ..] => {} } match s { - //~^ ERROR `&[_, .., false]` not covered + //~^ ERROR `&[_, .., false]` not covered [] => {} [_] => {} [.., true] => {} } match s { - //~^ ERROR `&[_, _, .., true]` not covered + //~^ ERROR `&[_, _, .., true]` not covered [] => {} [_] => {} [_, _] => {} [.., false] => {} } match s { - //~^ ERROR `&[true, _, .., _]` not covered + //~^ ERROR `&[true, _, .., _]` not covered [] => {} [_] => {} [_, _] => {} @@ -83,19 +83,43 @@ fn main() { const CONST: &[bool] = &[true]; match s { - //~^ ERROR `&[..]` not covered + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[true] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered CONST => {} } match s { - //~^ ERROR `&[true]` not covered - [] => {}, - [false] => {}, - CONST => {}, + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + CONST => {} + &[false] => {} + } + match s { + //~^ ERROR `&[]` and `&[_, _, ..]` not covered + &[false] => {} + CONST => {} + } + match s { + //~^ ERROR `&[_, _, ..]` not covered + &[] => {} + CONST => {} + } + match s { + //~^ ERROR `&[false]` not covered + &[] => {} + CONST => {} + &[_, _, ..] => {} + } + match s { + [] => {} + [false] => {} + CONST => {} [_, _, ..] => {} } const CONST1: &[bool; 1] = &[true]; match s1 { - //~^ ERROR `&[false]` not covered + //~^ ERROR `&[false]` not covered CONST1 => {} } match s1 { diff --git a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index 8b85eaeda0..e34770fb91 100644 --- a/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/src/test/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -115,26 +115,62 @@ LL | match s { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool]` -error[E0004]: non-exhaustive patterns: `&[..]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:85:11 | LL | match s { - | ^ pattern `&[..]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` 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 `&[bool]` -error[E0004]: non-exhaustive patterns: `&[true]` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:89:11 | LL | match s { - | ^ pattern `&[true]` not covered + | ^ patterns `&[]` and `&[_, _, ..]` 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 `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:93:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` 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 `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:98:11 + | +LL | match s { + | ^ patterns `&[]` and `&[_, _, ..]` 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 `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:103:11 + | +LL | match s { + | ^ 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 `&[bool]` error[E0004]: non-exhaustive patterns: `&[false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:97:11 + --> $DIR/slice-patterns-exhaustiveness.rs:108:11 + | +LL | match s { + | ^ pattern `&[false]` 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 `&[bool]` + +error[E0004]: non-exhaustive patterns: `&[false]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:121:11 | LL | match s1 { | ^^ pattern `&[false]` not covered @@ -142,6 +178,6 @@ LL | match s1 { = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms = note: the matched value is of type `&[bool; 1]` -error: aborting due to 16 previous errors +error: aborting due to 20 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/src/test/ui/phantom-oibit.stderr b/src/test/ui/phantom-oibit.stderr index e143747d63..8a02f23da9 100644 --- a/src/test/ui/phantom-oibit.stderr +++ b/src/test/ui/phantom-oibit.stderr @@ -8,12 +8,12 @@ LL | is_zen(x) | ^ `T` cannot be shared between threads safely | = note: required because of the requirements on the impl of `Zen` for `&T` - = note: required because it appears within the type `std::marker::PhantomData<&T>` + = note: required because it appears within the type `PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` help: consider restricting type parameter `T` | -LL | fn not_sync(x: Guard) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn not_sync(x: Guard) { + | ^^^^^^ error[E0277]: `T` cannot be shared between threads safely --> $DIR/phantom-oibit.rs:26:12 @@ -25,13 +25,13 @@ LL | is_zen(x) | ^ `T` cannot be shared between threads safely | = note: required because of the requirements on the impl of `Zen` for `&T` - = note: required because it appears within the type `std::marker::PhantomData<&T>` + = note: required because it appears within the type `PhantomData<&T>` = note: required because it appears within the type `Guard<'_, T>` = note: required because it appears within the type `Nested>` help: consider restricting type parameter `T` | -LL | fn nested_not_sync(x: Nested>) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn nested_not_sync(x: Nested>) { + | ^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs index a80e5df1a2..fa7664a83e 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.rs @@ -2,16 +2,14 @@ fn foo() -> impl std::fmt::Display { if false { return 0i32; } - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types } fn bar() -> impl std::fmt::Display { if false { return 0i32; } else { - return 1u32; - //~^ ERROR mismatched types + return 1u32; //~ ERROR mismatched types } } @@ -19,8 +17,7 @@ fn baz() -> impl std::fmt::Display { if false { return 0i32; } else { - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types } } @@ -28,22 +25,19 @@ fn qux() -> impl std::fmt::Display { if false { 0i32 } else { - 1u32 - //~^ ERROR `if` and `else` have incompatible types + 1u32 //~ ERROR `if` and `else` have incompatible types } } fn bat() -> impl std::fmt::Display { match 13 { 0 => return 0i32, - _ => 1u32, - //~^ ERROR mismatched types + _ => 1u32, //~ ERROR mismatched types } } fn can() -> impl std::fmt::Display { - match 13 { - //~^ ERROR mismatched types + match 13 { //~ ERROR mismatched types 0 => return 0i32, 1 => 1u32, _ => 2u32, @@ -56,10 +50,52 @@ fn cat() -> impl std::fmt::Display { return 0i32; } _ => { - 1u32 - //~^ ERROR mismatched types + 1u32 //~ ERROR mismatched types } } } +fn dog() -> impl std::fmt::Display { + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, + } +} + +fn hat() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + match 13 { + 0 => { + return 0i32; + } + _ => { + 1u32 + } + } +} + +fn pug() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + match 13 { + 0 => 0i32, + 1 => 1u32, //~ ERROR `match` arms have incompatible types + _ => 2u32, + } +} + +fn man() -> dyn std::fmt::Display { //~ ERROR return type cannot have an unboxed trait object + if false { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + +fn apt() -> impl std::fmt::Display { + if let Some(42) = Some(42) { + 0i32 + } else { + 1u32 //~ ERROR `if` and `else` have incompatible types + } +} + fn main() {} diff --git a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr index b663cccbee..eb4dc45c8a 100644 --- a/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr +++ b/src/test/ui/point-to-type-err-cause-on-impl-trait-return.stderr @@ -12,12 +12,21 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn foo() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } +LL | Box::new(1u32) + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:13:16 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:12:16 | LL | fn bar() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -30,12 +39,21 @@ LL | return 1u32; | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn bar() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } else { +LL | return Box::new(1u32); + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:22:9 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:20:9 | LL | fn baz() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -48,12 +66,21 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn baz() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } else { +LL | Box::new(1u32) + | error[E0308]: `if` and `else` have incompatible types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:31:9 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:28:9 | LL | / if false { LL | | 0i32 @@ -61,12 +88,22 @@ LL | | 0i32 LL | | } else { LL | | 1u32 | | ^^^^ expected `i32`, found `u32` -LL | | LL | | } | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn qux() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:39:14 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:35:14 | LL | fn bat() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -78,17 +115,24 @@ LL | _ => 1u32, | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn bat() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | 0 => return Box::new(0i32), +LL | _ => Box::new(1u32), + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:45:5 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:40:5 | LL | fn can() -> impl std::fmt::Display { | ---------------------- expected because this return type... LL | / match 13 { -LL | | LL | | 0 => return 0i32, | | ---- ...is found to be `i32` here LL | | 1 => 1u32, @@ -98,12 +142,23 @@ LL | | } | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn can() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(match 13 { +LL | 0 => return Box::new(0i32), +LL | 1 => 1u32, +LL | _ => 2u32, +LL | }) + | error[E0308]: mismatched types - --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:59:13 + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:53:13 | LL | fn cat() -> impl std::fmt::Display { | ---------------------- expected because this return type... @@ -116,10 +171,148 @@ LL | 1u32 | = note: to return `impl Trait`, all returned values must be of the same type = note: for information on `impl Trait`, see - = help: you can instead return a boxed trait object using `Box` = note: for information on trait objects, see - = help: alternatively, create a new `enum` with a variant for each returned type + = help: you could instead create a new `enum` with a variant for each returned type +help: you could change the return type to be a boxed trait object + | +LL | fn cat() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | return Box::new(0i32); +LL | } +LL | _ => { +LL | Box::new(1u32) + | -error: aborting due to 7 previous errors +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:61:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn dog() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | 0 => Box::new(0i32), +LL | 1 => Box::new(1u32), + | -For more information about this error, try `rustc --explain E0308`. +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:97:9 + | +LL | / if let Some(42) = Some(42) { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + | +help: you could change the return type to be a boxed trait object + | +LL | fn apt() -> Box { + | ^^^^^^^ ^ +help: if you change the return type to expect trait objects, box the returned expressions + | +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:66:13 + | +LL | fn hat() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn hat() -> Box { +LL | match 13 { +LL | 0 => { +LL | return Box::new(0i32); +LL | } +LL | _ => { + ... + +error[E0308]: `match` arms have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:80:14 + | +LL | / match 13 { +LL | | 0 => 0i32, + | | ---- this is found to be of type `i32` +LL | | 1 => 1u32, + | | ^^^^ expected `i32`, found `u32` +LL | | _ => 2u32, +LL | | } + | |_____- `match` arms have incompatible types + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:77:13 + | +LL | fn pug() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn pug() -> Box { +LL | match 13 { +LL | 0 => Box::new(0i32), +LL | 1 => Box::new(1u32), +LL | _ => Box::new(2u32), + | + +error[E0308]: `if` and `else` have incompatible types + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:89:9 + | +LL | / if false { +LL | | 0i32 + | | ---- expected because of this +LL | | } else { +LL | | 1u32 + | | ^^^^ expected `i32`, found `u32` +LL | | } + | |_____- `if` and `else` have incompatible types + +error[E0746]: return type cannot have an unboxed trait object + --> $DIR/point-to-type-err-cause-on-impl-trait-return.rs:85:13 + | +LL | fn man() -> dyn std::fmt::Display { + | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time + | + = note: for information on trait objects, see + = note: if all the returned values were of the same type you could use `impl std::fmt::Display` as the return type + = note: for information on `impl Trait`, see + = note: you can create a new `enum` with a variant for each returned type +help: return a boxed trait object instead + | +LL | fn man() -> Box { +LL | if false { +LL | Box::new(0i32) +LL | } else { +LL | Box::new(1u32) + | + +error: aborting due to 14 previous errors + +Some errors have detailed explanations: E0308, E0746. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/privacy/associated-item-privacy-trait.rs b/src/test/ui/privacy/associated-item-privacy-trait.rs index b1482bc040..b4e98debcf 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.rs +++ b/src/test/ui/privacy/associated-item-privacy-trait.rs @@ -15,21 +15,21 @@ mod priv_trait { pub macro mac() { let value = ::method; - //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private + //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private value; - //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private + //~^ ERROR type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private Pub.method(); - //~^ ERROR type `for<'r> fn(&'r Self) {::method}` is private + //~^ ERROR type `for<'r> fn(&'r Self) {::method}` is private ::CONST; //~^ ERROR associated constant `::CONST` is private let _: ::AssocTy; //~^ ERROR associated type `::AssocTy` is private pub type InSignatureTy = ::AssocTy; - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private pub trait InSignatureTr: PrivTr {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private impl PrivTr for u8 {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private } } fn priv_trait() { diff --git a/src/test/ui/privacy/associated-item-privacy-trait.stderr b/src/test/ui/privacy/associated-item-privacy-trait.stderr index b9f3e35d72..8e58a2fa08 100644 --- a/src/test/ui/privacy/associated-item-privacy-trait.stderr +++ b/src/test/ui/privacy/associated-item-privacy-trait.stderr @@ -1,4 +1,4 @@ -error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private +error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private --> $DIR/associated-item-privacy-trait.rs:17:21 | LL | let value = ::method; @@ -9,7 +9,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private +error: type `for<'r> fn(&'r priv_trait::Pub) {::method}` is private --> $DIR/associated-item-privacy-trait.rs:19:9 | LL | value; @@ -20,7 +20,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r Self) {::method}` is private +error: type `for<'r> fn(&'r Self) {::method}` is private --> $DIR/associated-item-privacy-trait.rs:21:13 | LL | Pub.method(); @@ -53,7 +53,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-trait.rs:27:34 | LL | pub type InSignatureTy = ::AssocTy; @@ -64,7 +64,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-trait.rs:29:34 | LL | pub trait InSignatureTr: PrivTr {} @@ -75,7 +75,7 @@ LL | priv_trait::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-trait.rs:31:14 | LL | impl PrivTr for u8 {} diff --git a/src/test/ui/privacy/associated-item-privacy-type-binding.rs b/src/test/ui/privacy/associated-item-privacy-type-binding.rs index b9c526f515..9826b83a35 100644 --- a/src/test/ui/privacy/associated-item-privacy-type-binding.rs +++ b/src/test/ui/privacy/associated-item-privacy-type-binding.rs @@ -9,21 +9,21 @@ mod priv_trait { pub macro mac1() { let _: Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private - //~| ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private + //~| ERROR trait `PrivTr` is private type InSignatureTy2 = Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private trait InSignatureTr2: PubTr {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private } pub macro mac2() { let _: Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private - //~| ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private + //~| ERROR trait `PrivTr` is private type InSignatureTy1 = Box>; - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private trait InSignatureTr1: PrivTr {} - //~^ ERROR trait `priv_trait::PrivTr` is private + //~^ ERROR trait `PrivTr` is private } } fn priv_trait1() { @@ -42,19 +42,19 @@ mod priv_parent_substs { pub macro mac() { let _: Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private - //~| ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private + //~| ERROR type `Priv` is private let _: Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private - //~| ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private + //~| ERROR type `Priv` is private pub type InSignatureTy1 = Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private pub type InSignatureTy2 = Box>; - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private trait InSignatureTr1: PubTrWithParam {} - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private trait InSignatureTr2: PubTr {} - //~^ ERROR type `priv_parent_substs::Priv` is private + //~^ ERROR type `Priv` is private } } fn priv_parent_substs() { diff --git a/src/test/ui/privacy/associated-item-privacy-type-binding.stderr b/src/test/ui/privacy/associated-item-privacy-type-binding.stderr index d8515ccb66..5df2dfb871 100644 --- a/src/test/ui/privacy/associated-item-privacy-type-binding.stderr +++ b/src/test/ui/privacy/associated-item-privacy-type-binding.stderr @@ -1,4 +1,4 @@ -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:11:13 | LL | let _: Box>; @@ -9,7 +9,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:11:16 | LL | let _: Box>; @@ -20,7 +20,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:14:31 | LL | type InSignatureTy2 = Box>; @@ -31,7 +31,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:16:31 | LL | trait InSignatureTr2: PubTr {} @@ -42,7 +42,7 @@ LL | priv_trait::mac1!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:20:13 | LL | let _: Box>; @@ -53,7 +53,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:20:16 | LL | let _: Box>; @@ -64,7 +64,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:23:31 | LL | type InSignatureTy1 = Box>; @@ -75,7 +75,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `priv_trait::PrivTr` is private +error: trait `PrivTr` is private --> $DIR/associated-item-privacy-type-binding.rs:25:31 | LL | trait InSignatureTr1: PrivTr {} @@ -86,7 +86,7 @@ LL | priv_trait::mac2!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:44:13 | LL | let _: Box>; @@ -97,7 +97,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:44:16 | LL | let _: Box>; @@ -108,7 +108,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:47:13 | LL | let _: Box>; @@ -119,7 +119,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:47:16 | LL | let _: Box>; @@ -130,7 +130,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:50:35 | LL | pub type InSignatureTy1 = Box>; @@ -141,7 +141,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:52:35 | LL | pub type InSignatureTy2 = Box>; @@ -152,7 +152,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:54:31 | LL | trait InSignatureTr1: PubTrWithParam {} @@ -163,7 +163,7 @@ LL | priv_parent_substs::mac!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `priv_parent_substs::Priv` is private +error: type `Priv` is private --> $DIR/associated-item-privacy-type-binding.rs:56:31 | LL | trait InSignatureTr2: PubTr {} diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.rs b/src/test/ui/privacy/private-in-public-assoc-ty.rs index cd7c37cb04..5238894a97 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.rs +++ b/src/test/ui/privacy/private-in-public-assoc-ty.rs @@ -15,16 +15,16 @@ mod m { impl PubTrAux1 for u8 {} impl PubTrAux2 for u8 { type A = Priv; - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface } // "Private-in-public in associated types is hard error" in RFC 2145 // applies only to the aliased types, not bounds. pub trait PubTr { - //~^ WARN private trait `m::PrivTr` in public interface + //~^ WARN private trait `PrivTr` in public interface //~| WARN this was previously accepted - //~| WARN private type `m::Priv` in public interface - //~| WARN private type `m::Priv` in public interface + //~| WARN private type `Priv` in public interface + //~| WARN private type `Priv` in public interface //~| WARN this was previously accepted //~| WARN this was previously accepted type Alias1: PrivTr; @@ -32,17 +32,17 @@ mod m { type Alias3: PubTrAux2 = u8; type Alias4 = Priv; - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface type Exist; fn infer_exist() -> Self::Exist; } impl PubTr for u8 { type Alias1 = Priv; - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface type Exist = impl PrivTr; - //~^ ERROR private trait `m::PrivTr` in public interface + //~^ ERROR private trait `PrivTr` in public interface fn infer_exist() -> Self::Exist { Priv } diff --git a/src/test/ui/privacy/private-in-public-assoc-ty.stderr b/src/test/ui/privacy/private-in-public-assoc-ty.stderr index 1a3ca3f16e..acc6e20cf3 100644 --- a/src/test/ui/privacy/private-in-public-assoc-ty.stderr +++ b/src/test/ui/privacy/private-in-public-assoc-ty.stderr @@ -1,13 +1,13 @@ -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:17:9 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | type A = Priv; | ^^^^^^^^^^^^^^ can't leak private type -warning: private trait `m::PrivTr` in public interface (error E0445) +warning: private trait `PrivTr` in public interface (error E0445) --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { @@ -23,7 +23,7 @@ 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 #34537 -warning: private type `m::Priv` in public interface (error E0446) +warning: private type `Priv` in public interface (error E0446) --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { @@ -38,7 +38,7 @@ 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 #34537 -warning: private type `m::Priv` in public interface (error E0446) +warning: private type `Priv` in public interface (error E0446) --> $DIR/private-in-public-assoc-ty.rs:23:5 | LL | / pub trait PubTr { @@ -53,29 +53,29 @@ 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 #34537 -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:34:9 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | type Alias4 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public-assoc-ty.rs:41:9 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | type Alias1 = Priv; | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0445]: private trait `m::PrivTr` in public interface +error[E0445]: private trait `PrivTr` in public interface --> $DIR/private-in-public-assoc-ty.rs:44:9 | LL | trait PrivTr {} - | - `m::PrivTr` declared as private + | - `PrivTr` declared as private ... LL | type Exist = impl PrivTr; | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private trait diff --git a/src/test/ui/privacy/private-in-public-ill-formed.rs b/src/test/ui/privacy/private-in-public-ill-formed.rs index 0ef5d89002..031e2874a2 100644 --- a/src/test/ui/privacy/private-in-public-ill-formed.rs +++ b/src/test/ui/privacy/private-in-public-ill-formed.rs @@ -11,7 +11,8 @@ mod aliases_pub { type AssocAlias = m::Pub3; } - impl ::AssocAlias { //~ ERROR no base type found for inherent implementation + impl ::AssocAlias { + //~^ ERROR no nominal type found for inherent implementation pub fn f(arg: Priv) {} // private type `aliases_pub::Priv` in public interface } } @@ -27,7 +28,8 @@ mod aliases_priv { type AssocAlias = Priv3; } - impl ::AssocAlias { //~ ERROR no base type found for inherent implementation + impl ::AssocAlias { + //~^ ERROR no nominal type found for inherent implementation pub fn f(arg: Priv) {} // OK } } diff --git a/src/test/ui/privacy/private-in-public-ill-formed.stderr b/src/test/ui/privacy/private-in-public-ill-formed.stderr index a1a326f287..e7c94bc301 100644 --- a/src/test/ui/privacy/private-in-public-ill-formed.stderr +++ b/src/test/ui/privacy/private-in-public-ill-formed.stderr @@ -1,16 +1,16 @@ -error[E0118]: no base type found for inherent implementation +error[E0118]: no nominal type found for inherent implementation --> $DIR/private-in-public-ill-formed.rs:14:10 | LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead -error[E0118]: no base type found for inherent implementation - --> $DIR/private-in-public-ill-formed.rs:30:10 +error[E0118]: no nominal type found for inherent implementation + --> $DIR/private-in-public-ill-formed.rs:31:10 | LL | impl ::AssocAlias { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a base type + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ impl requires a nominal type | = note: either implement a trait on it or create a newtype to wrap it instead diff --git a/src/test/ui/privacy/private-in-public-non-principal-2.rs b/src/test/ui/privacy/private-in-public-non-principal-2.rs index cd3d609ca3..effcb508e2 100644 --- a/src/test/ui/privacy/private-in-public-non-principal-2.rs +++ b/src/test/ui/privacy/private-in-public-non-principal-2.rs @@ -10,5 +10,5 @@ mod m { fn main() { m::leak_dyn_nonprincipal(); - //~^ ERROR trait `m::PrivNonPrincipal` is private + //~^ ERROR trait `PrivNonPrincipal` is private } diff --git a/src/test/ui/privacy/private-in-public-non-principal-2.stderr b/src/test/ui/privacy/private-in-public-non-principal-2.stderr index 7850694aab..7cc8bf0de2 100644 --- a/src/test/ui/privacy/private-in-public-non-principal-2.stderr +++ b/src/test/ui/privacy/private-in-public-non-principal-2.stderr @@ -1,4 +1,4 @@ -error: trait `m::PrivNonPrincipal` is private +error: trait `PrivNonPrincipal` is private --> $DIR/private-in-public-non-principal-2.rs:12:5 | LL | m::leak_dyn_nonprincipal(); diff --git a/src/test/ui/privacy/private-in-public-warn.rs b/src/test/ui/privacy/private-in-public-warn.rs index 467b837467..3022b470b7 100644 --- a/src/test/ui/privacy/private-in-public-warn.rs +++ b/src/test/ui/privacy/private-in-public-warn.rs @@ -247,12 +247,12 @@ mod aliases_priv { } pub trait Tr1: PrivUseAliasTr {} - //~^ ERROR private trait `aliases_priv::PrivTr1` in public interface + //~^ ERROR private trait `PrivTr1` in public interface //~| WARNING hard error pub trait Tr2: PrivUseAliasTr {} - //~^ ERROR private trait `aliases_priv::PrivTr1` in public interface + //~^ ERROR private trait `PrivTr1` in public interface //~| WARNING hard error - //~| ERROR private type `aliases_priv::Priv2` in public interface + //~| ERROR private type `Priv2` in public interface //~| WARNING hard error impl PrivUseAlias { diff --git a/src/test/ui/privacy/private-in-public-warn.stderr b/src/test/ui/privacy/private-in-public-warn.stderr index 4905e29519..36577a6010 100644 --- a/src/test/ui/privacy/private-in-public-warn.stderr +++ b/src/test/ui/privacy/private-in-public-warn.stderr @@ -306,7 +306,7 @@ LL | struct Priv; LL | type Check = Priv; | ^^^^^^^^^^^^^^^^^^ can't leak private type -error: private trait `aliases_priv::PrivTr1` in public interface (error E0445) +error: private trait `PrivTr1` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:249:5 | LL | pub trait Tr1: PrivUseAliasTr {} @@ -315,7 +315,7 @@ LL | pub trait Tr1: PrivUseAliasTr {} = 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 #34537 -error: private trait `aliases_priv::PrivTr1` in public interface (error E0445) +error: private trait `PrivTr1` in public interface (error E0445) --> $DIR/private-in-public-warn.rs:252:5 | LL | pub trait Tr2: PrivUseAliasTr {} @@ -324,7 +324,7 @@ LL | pub trait Tr2: PrivUseAliasTr {} = 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 #34537 -error: private type `aliases_priv::Priv2` in public interface (error E0446) +error: private type `Priv2` in public interface (error E0446) --> $DIR/private-in-public-warn.rs:252:5 | LL | pub trait Tr2: PrivUseAliasTr {} diff --git a/src/test/ui/privacy/private-in-public.rs b/src/test/ui/privacy/private-in-public.rs index 08c00f44f2..dbd1c483f8 100644 --- a/src/test/ui/privacy/private-in-public.rs +++ b/src/test/ui/privacy/private-in-public.rs @@ -128,8 +128,8 @@ mod aliases_priv { } impl PrivTr for Priv {} - pub fn f1(arg: PrivUseAlias) {} //~ ERROR private type `aliases_priv::Priv1` in public interface - pub fn f2(arg: PrivAlias) {} //~ ERROR private type `aliases_priv::Priv2` in public interface + pub fn f1(arg: PrivUseAlias) {} //~ ERROR private type `Priv1` in public interface + pub fn f2(arg: PrivAlias) {} //~ ERROR private type `Priv2` in public interface pub fn f3(arg: ::Assoc) {} //~^ ERROR private trait `aliases_priv::PrivTr` in public interface //~| ERROR private type `aliases_priv::Priv` in public interface diff --git a/src/test/ui/privacy/private-in-public.stderr b/src/test/ui/privacy/private-in-public.stderr index 4750fe8687..2ec5b45d21 100644 --- a/src/test/ui/privacy/private-in-public.stderr +++ b/src/test/ui/privacy/private-in-public.stderr @@ -238,20 +238,20 @@ LL | struct Priv; LL | pub fn f(arg: Priv) {} | ^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `aliases_priv::Priv1` in public interface +error[E0446]: private type `Priv1` in public interface --> $DIR/private-in-public.rs:131:5 | LL | struct Priv1; - | - `aliases_priv::Priv1` declared as private + | - `Priv1` declared as private ... LL | pub fn f1(arg: PrivUseAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `aliases_priv::Priv2` in public interface +error[E0446]: private type `Priv2` in public interface --> $DIR/private-in-public.rs:132:5 | LL | struct Priv2; - | - `aliases_priv::Priv2` declared as private + | - `Priv2` declared as private ... LL | pub fn f2(arg: PrivAlias) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/privacy/private-inferred-type-1.rs b/src/test/ui/privacy/private-inferred-type-1.rs index 69eeb2a26e..d633189e3f 100644 --- a/src/test/ui/privacy/private-inferred-type-1.rs +++ b/src/test/ui/privacy/private-inferred-type-1.rs @@ -13,6 +13,6 @@ mod m { } fn main() { - [].arr0_secret(); //~ ERROR type `m::Priv` is private - None.ty_param_secret(); //~ ERROR type `m::Priv` is private + [].arr0_secret(); //~ ERROR type `Priv` is private + None.ty_param_secret(); //~ ERROR type `Priv` is private } diff --git a/src/test/ui/privacy/private-inferred-type-1.stderr b/src/test/ui/privacy/private-inferred-type-1.stderr index 576498b2cf..245789f435 100644 --- a/src/test/ui/privacy/private-inferred-type-1.stderr +++ b/src/test/ui/privacy/private-inferred-type-1.stderr @@ -1,10 +1,10 @@ -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-1.rs:16:5 | LL | [].arr0_secret(); | ^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-1.rs:17:5 | LL | None.ty_param_secret(); diff --git a/src/test/ui/privacy/private-inferred-type-2.rs b/src/test/ui/privacy/private-inferred-type-2.rs index 28b47606d1..15b263b381 100644 --- a/src/test/ui/privacy/private-inferred-type-2.rs +++ b/src/test/ui/privacy/private-inferred-type-2.rs @@ -13,7 +13,7 @@ mod m { } fn main() { - m::Pub::get_priv; //~ ERROR type `m::Priv` is private - m::Pub::static_method; //~ ERROR type `m::Priv` is private + m::Pub::get_priv; //~ ERROR type `Priv` is private + m::Pub::static_method; //~ ERROR type `Priv` is private ext::Pub::static_method; //~ ERROR type `ext::Priv` is private } diff --git a/src/test/ui/privacy/private-inferred-type-2.stderr b/src/test/ui/privacy/private-inferred-type-2.stderr index f19e367ef1..3a0fc03b4d 100644 --- a/src/test/ui/privacy/private-inferred-type-2.stderr +++ b/src/test/ui/privacy/private-inferred-type-2.stderr @@ -1,10 +1,10 @@ -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-2.rs:16:5 | LL | m::Pub::get_priv; | ^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type-2.rs:17:5 | LL | m::Pub::static_method; diff --git a/src/test/ui/privacy/private-inferred-type-3.rs b/src/test/ui/privacy/private-inferred-type-3.rs index 39f2e5d4af..00f0a715a8 100644 --- a/src/test/ui/privacy/private-inferred-type-3.rs +++ b/src/test/ui/privacy/private-inferred-type-3.rs @@ -5,8 +5,8 @@ // error-pattern:type `ext::PrivEnum` is private // error-pattern:type `fn() {::method}` is private // error-pattern:type `fn(u8) -> ext::PrivTupleStruct {ext::PrivTupleStruct}` is private -// error-pattern:type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct}` is private -// error-pattern:type `for<'r> fn(&'r ext::Pub) {ext::Pub::::priv_method}` is private +// error-pattern:type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private +// error-pattern:type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private #![feature(decl_macro)] diff --git a/src/test/ui/privacy/private-inferred-type-3.stderr b/src/test/ui/privacy/private-inferred-type-3.stderr index 39ef647252..165d932f08 100644 --- a/src/test/ui/privacy/private-inferred-type-3.stderr +++ b/src/test/ui/privacy/private-inferred-type-3.stderr @@ -38,7 +38,7 @@ LL | ext::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn(u8) -> ext::PubTupleStruct {ext::PubTupleStruct}` is private +error: type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); @@ -46,7 +46,7 @@ LL | ext::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r ext::Pub) {ext::Pub::::priv_method}` is private +error: type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private --> $DIR/private-inferred-type-3.rs:16:5 | LL | ext::m!(); diff --git a/src/test/ui/privacy/private-inferred-type.rs b/src/test/ui/privacy/private-inferred-type.rs index dab440b2d9..b083a3970d 100644 --- a/src/test/ui/privacy/private-inferred-type.rs +++ b/src/test/ui/privacy/private-inferred-type.rs @@ -36,18 +36,18 @@ mod m { impl TraitWithAssocTy for Priv { type AssocTy = u8; } pub macro m() { - priv_fn; //~ ERROR type `fn() {m::priv_fn}` is private + priv_fn; //~ ERROR type `fn() {priv_fn}` is private PRIV_STATIC; // OK, not cross-crate - PrivEnum::Variant; //~ ERROR type `m::PrivEnum` is private + PrivEnum::Variant; //~ ERROR type `PrivEnum` is private PubEnum::Variant; // OK - ::method; //~ ERROR type `fn() {::method}` is private + ::method; //~ ERROR type `fn() {::method}` is private ::method; // OK PrivTupleStruct; - //~^ ERROR type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct}` is private + //~^ ERROR type `fn(u8) -> PrivTupleStruct {PrivTupleStruct}` is private PubTupleStruct; - //~^ ERROR type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct}` is private + //~^ ERROR type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private Pub(0u8).priv_method(); - //~^ ERROR type `for<'r> fn(&'r m::Pub) {m::Pub::::priv_method}` is private + //~^ ERROR type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private } trait Trait {} @@ -59,7 +59,7 @@ mod m { impl TraitWithTyParam for u8 {} impl TraitWithTyParam2 for u8 {} impl TraitWithAssocTy for u8 { type AssocTy = Priv; } - //~^ ERROR private type `m::Priv` in public interface + //~^ ERROR private type `Priv` in public interface pub fn leak_anon1() -> impl Trait + 'static { 0 } pub fn leak_anon2() -> impl TraitWithTyParam { 0 } @@ -80,7 +80,7 @@ mod adjust { pub struct S3; impl Deref for S1 { - type Target = S2Alias; //~ ERROR private type `adjust::S2` in public interface + type Target = S2Alias; //~ ERROR private type `S2` in public interface fn deref(&self) -> &Self::Target { loop {} } } impl Deref for S2 { @@ -94,40 +94,40 @@ mod adjust { } fn main() { - let _: m::Alias; //~ ERROR type `m::Priv` is private - //~^ ERROR type `m::Priv` is private - let _: ::AssocTy; //~ ERROR type `m::Priv` is private - m::Alias {}; //~ ERROR type `m::Priv` is private - m::Pub { 0: m::Alias {} }; //~ ERROR type `m::Priv` is private + let _: m::Alias; //~ ERROR type `Priv` is private + //~^ ERROR type `Priv` is private + let _: ::AssocTy; //~ ERROR type `Priv` is private + m::Alias {}; //~ ERROR type `Priv` is private + m::Pub { 0: m::Alias {} }; //~ ERROR type `Priv` is private m::Pub { 0: loop {} }; // OK, `m::Pub` is in value context, so it means Pub<_>, not Pub - m::Pub::static_method; //~ ERROR type `m::Priv` is private - m::Pub::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private - m::Pub(0u8).method_with_substs::(); //~ ERROR type `m::Priv` is private - m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `m::Priv` is private - ::TRAIT_ASSOC_CONST; //~ ERROR type `m::Priv` is private - >::INHERENT_ASSOC_CONST; //~ ERROR type `m::Priv` is private - >::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `m::Priv` is private - >::static_method_generic_self; //~ ERROR type `m::Priv` is private + m::Pub::static_method; //~ ERROR type `Priv` is private + m::Pub::INHERENT_ASSOC_CONST; //~ ERROR type `Priv` is private + m::Pub(0u8).method_with_substs::(); //~ ERROR type `Priv` is private + m::Pub(0u8).method_with_priv_params(loop{}); //~ ERROR type `Priv` is private + ::TRAIT_ASSOC_CONST; //~ ERROR type `Priv` is private + >::INHERENT_ASSOC_CONST; //~ ERROR type `Priv` is private + >::INHERENT_ASSOC_CONST_GENERIC_SELF; //~ ERROR type `Priv` is private + >::static_method_generic_self; //~ ERROR type `Priv` is private use m::TraitWithTyParam2; - u8::pub_method; //~ ERROR type `m::Priv` is private + u8::pub_method; //~ ERROR type `Priv` is private - adjust::S1.method_s3(); //~ ERROR type `adjust::S2` is private + adjust::S1.method_s3(); //~ ERROR type `S2` is private m::m!(); - m::leak_anon1(); //~ ERROR trait `m::Trait` is private - m::leak_anon2(); //~ ERROR type `m::Priv` is private - m::leak_anon3(); //~ ERROR type `m::Priv` is private + m::leak_anon1(); //~ ERROR trait `Trait` is private + m::leak_anon2(); //~ ERROR type `Priv` is private + m::leak_anon3(); //~ ERROR type `Priv` is private - m::leak_dyn1(); //~ ERROR trait `m::Trait` is private - m::leak_dyn2(); //~ ERROR type `m::Priv` is private - m::leak_dyn3(); //~ ERROR type `m::Priv` is private + m::leak_dyn1(); //~ ERROR trait `Trait` is private + m::leak_dyn2(); //~ ERROR type `Priv` is private + m::leak_dyn3(); //~ ERROR type `Priv` is private // Check that messages are not duplicated for various kinds of assignments - let a = m::Alias {}; //~ ERROR type `m::Priv` is private - let mut b = a; //~ ERROR type `m::Priv` is private - b = a; //~ ERROR type `m::Priv` is private - match a { //~ ERROR type `m::Priv` is private + let a = m::Alias {}; //~ ERROR type `Priv` is private + let mut b = a; //~ ERROR type `Priv` is private + b = a; //~ ERROR type `Priv` is private + match a { //~ ERROR type `Priv` is private _ => {} } } diff --git a/src/test/ui/privacy/private-inferred-type.stderr b/src/test/ui/privacy/private-inferred-type.stderr index 7d1f794bfe..4a310f7009 100644 --- a/src/test/ui/privacy/private-inferred-type.stderr +++ b/src/test/ui/privacy/private-inferred-type.stderr @@ -1,112 +1,112 @@ -error[E0446]: private type `m::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-inferred-type.rs:61:36 | LL | struct Priv; - | - `m::Priv` declared as private + | - `Priv` declared as private ... LL | impl TraitWithAssocTy for u8 { type AssocTy = Priv; } | ^^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `adjust::S2` in public interface +error[E0446]: private type `S2` in public interface --> $DIR/private-inferred-type.rs:83:9 | LL | struct S2; - | - `adjust::S2` declared as private + | - `S2` declared as private ... LL | type Target = S2Alias; | ^^^^^^^^^^^^^^^^^^^^^^ can't leak private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:97:9 | LL | let _: m::Alias; | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:97:12 | LL | let _: m::Alias; | ^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:99:13 | LL | let _: ::AssocTy; | ^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:100:5 | LL | m::Alias {}; | ^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:101:5 | LL | m::Pub { 0: m::Alias {} }; | ^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:103:5 | LL | m::Pub::static_method; | ^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:104:5 | LL | m::Pub::INHERENT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:105:5 | LL | m::Pub(0u8).method_with_substs::(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:106:17 | LL | m::Pub(0u8).method_with_priv_params(loop{}); | ^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:107:5 | LL | ::TRAIT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:108:6 | LL | >::INHERENT_ASSOC_CONST; | ^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:109:5 | LL | >::INHERENT_ASSOC_CONST_GENERIC_SELF; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:110:5 | LL | >::static_method_generic_self; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:112:5 | LL | u8::pub_method; | ^^^^^^^^^^^^^^ private type -error: type `adjust::S2` is private +error: type `S2` is private --> $DIR/private-inferred-type.rs:114:5 | LL | adjust::S1.method_s3(); | ^^^^^^^^^^ private type -error: type `fn() {m::priv_fn}` is private +error: type `fn() {priv_fn}` is private --> $DIR/private-inferred-type.rs:39:9 | LL | priv_fn; @@ -117,7 +117,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `m::PrivEnum` is private +error: type `PrivEnum` is private --> $DIR/private-inferred-type.rs:41:9 | LL | PrivEnum::Variant; @@ -128,7 +128,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn() {::method}` is private +error: type `fn() {::method}` is private --> $DIR/private-inferred-type.rs:43:9 | LL | ::method; @@ -139,7 +139,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn(u8) -> m::PrivTupleStruct {m::PrivTupleStruct}` is private +error: type `fn(u8) -> PrivTupleStruct {PrivTupleStruct}` is private --> $DIR/private-inferred-type.rs:45:9 | LL | PrivTupleStruct; @@ -150,7 +150,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `fn(u8) -> m::PubTupleStruct {m::PubTupleStruct}` is private +error: type `fn(u8) -> PubTupleStruct {PubTupleStruct}` is private --> $DIR/private-inferred-type.rs:47:9 | LL | PubTupleStruct; @@ -161,7 +161,7 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: type `for<'r> fn(&'r m::Pub) {m::Pub::::priv_method}` is private +error: type `for<'r> fn(&'r Pub) {Pub::::priv_method}` is private --> $DIR/private-inferred-type.rs:49:18 | LL | Pub(0u8).priv_method(); @@ -172,61 +172,61 @@ LL | m::m!(); | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) -error: trait `m::Trait` is private +error: trait `Trait` is private --> $DIR/private-inferred-type.rs:118:5 | LL | m::leak_anon1(); | ^^^^^^^^^^^^^^^ private trait -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:119:5 | LL | m::leak_anon2(); | ^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:120:5 | LL | m::leak_anon3(); | ^^^^^^^^^^^^^^^ private type -error: trait `m::Trait` is private +error: trait `Trait` is private --> $DIR/private-inferred-type.rs:122:5 | LL | m::leak_dyn1(); | ^^^^^^^^^^^^^^ private trait -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:123:5 | LL | m::leak_dyn2(); | ^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:124:5 | LL | m::leak_dyn3(); | ^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:127:13 | LL | let a = m::Alias {}; | ^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:128:17 | LL | let mut b = a; | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:129:9 | LL | b = a; | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-inferred-type.rs:130:11 | LL | match a { diff --git a/src/test/ui/privacy/private-struct-field-cross-crate.rs b/src/test/ui/privacy/private-struct-field-cross-crate.rs index 2efcb7f1d8..301cd37b76 100644 --- a/src/test/ui/privacy/private-struct-field-cross-crate.rs +++ b/src/test/ui/privacy/private-struct-field-cross-crate.rs @@ -5,5 +5,5 @@ use cci_class::kitties::cat; fn main() { let nyan : cat = cat(52, 99); assert_eq!(nyan.meows, 52); - //~^ ERROR field `meows` of struct `cci_class::kitties::cat` is private + //~^ ERROR field `meows` of struct `cat` is private } diff --git a/src/test/ui/privacy/private-struct-field-cross-crate.stderr b/src/test/ui/privacy/private-struct-field-cross-crate.stderr index ac00d82ada..40cf3448d6 100644 --- a/src/test/ui/privacy/private-struct-field-cross-crate.stderr +++ b/src/test/ui/privacy/private-struct-field-cross-crate.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `meows` of struct `cci_class::kitties::cat` is private +error[E0616]: field `meows` of struct `cat` is private --> $DIR/private-struct-field-cross-crate.rs:7:19 | LL | assert_eq!(nyan.meows, 52); diff --git a/src/test/ui/privacy/private-struct-field-ctor.rs b/src/test/ui/privacy/private-struct-field-ctor.rs index 2c506f3479..56e84a7510 100644 --- a/src/test/ui/privacy/private-struct-field-ctor.rs +++ b/src/test/ui/privacy/private-struct-field-ctor.rs @@ -5,5 +5,5 @@ mod a { } fn main() { - let s = a::Foo { x: 1 }; //~ ERROR field `x` of struct `a::Foo` is private + let s = a::Foo { x: 1 }; //~ ERROR field `x` of struct `Foo` is private } diff --git a/src/test/ui/privacy/private-struct-field-ctor.stderr b/src/test/ui/privacy/private-struct-field-ctor.stderr index 7c32ebc2cf..9dc9db0eac 100644 --- a/src/test/ui/privacy/private-struct-field-ctor.stderr +++ b/src/test/ui/privacy/private-struct-field-ctor.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `x` of struct `a::Foo` is private +error[E0451]: field `x` of struct `Foo` is private --> $DIR/private-struct-field-ctor.rs:8:22 | LL | let s = a::Foo { x: 1 }; diff --git a/src/test/ui/privacy/private-struct-field-pattern.rs b/src/test/ui/privacy/private-struct-field-pattern.rs index b3da6092ab..4a766500e1 100644 --- a/src/test/ui/privacy/private-struct-field-pattern.rs +++ b/src/test/ui/privacy/private-struct-field-pattern.rs @@ -12,6 +12,6 @@ mod a { fn main() { match a::make() { - Foo { x: _ } => {} //~ ERROR field `x` of struct `a::Foo` is private + Foo { x: _ } => {} //~ ERROR field `x` of struct `Foo` is private } } diff --git a/src/test/ui/privacy/private-struct-field-pattern.stderr b/src/test/ui/privacy/private-struct-field-pattern.stderr index 9190317403..6305530368 100644 --- a/src/test/ui/privacy/private-struct-field-pattern.stderr +++ b/src/test/ui/privacy/private-struct-field-pattern.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `x` of struct `a::Foo` is private +error[E0451]: field `x` of struct `Foo` is private --> $DIR/private-struct-field-pattern.rs:15:15 | LL | Foo { x: _ } => {} diff --git a/src/test/ui/privacy/private-struct-field.rs b/src/test/ui/privacy/private-struct-field.rs index 216ae20e15..94cee4eff2 100644 --- a/src/test/ui/privacy/private-struct-field.rs +++ b/src/test/ui/privacy/private-struct-field.rs @@ -10,5 +10,5 @@ mod cat { fn main() { let nyan = cat::new_cat(); - assert_eq!(nyan.meows, 52); //~ ERROR field `meows` of struct `cat::Cat` is private + assert_eq!(nyan.meows, 52); //~ ERROR field `meows` of struct `Cat` is private } diff --git a/src/test/ui/privacy/private-struct-field.stderr b/src/test/ui/privacy/private-struct-field.stderr index c89ae507ab..facf4e82fd 100644 --- a/src/test/ui/privacy/private-struct-field.stderr +++ b/src/test/ui/privacy/private-struct-field.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `meows` of struct `cat::Cat` is private +error[E0616]: field `meows` of struct `Cat` is private --> $DIR/private-struct-field.rs:13:21 | LL | assert_eq!(nyan.meows, 52); diff --git a/src/test/ui/privacy/private-type-in-interface.rs b/src/test/ui/privacy/private-type-in-interface.rs index 359b6da1d7..7fbdbaf5f3 100644 --- a/src/test/ui/privacy/private-type-in-interface.rs +++ b/src/test/ui/privacy/private-type-in-interface.rs @@ -12,19 +12,19 @@ mod m { impl Trait for Priv { type X = u8; } } -fn f(_: m::Alias) {} //~ ERROR type `m::Priv` is private - //~^ ERROR type `m::Priv` is private +fn f(_: m::Alias) {} //~ ERROR type `Priv` is private + //~^ ERROR type `Priv` is private fn f_ext(_: ext::Alias) {} //~ ERROR type `ext::Priv` is private //~^ ERROR type `ext::Priv` is private trait Tr1 {} -impl m::Alias {} //~ ERROR type `m::Priv` is private +impl m::Alias {} //~ ERROR type `Priv` is private impl Tr1 for ext::Alias {} //~ ERROR type `ext::Priv` is private -type A = ::X; //~ ERROR type `m::Priv` is private +type A = ::X; //~ ERROR type `Priv` is private trait Tr2 {} impl Tr2 for u8 {} -fn g() -> impl Tr2 { 0 } //~ ERROR type `m::Priv` is private +fn g() -> impl Tr2 { 0 } //~ ERROR type `Priv` is private fn g_ext() -> impl Tr2 { 0 } //~ ERROR type `ext::Priv` is private fn main() {} diff --git a/src/test/ui/privacy/private-type-in-interface.stderr b/src/test/ui/privacy/private-type-in-interface.stderr index ea89035c3d..4e87caa341 100644 --- a/src/test/ui/privacy/private-type-in-interface.stderr +++ b/src/test/ui/privacy/private-type-in-interface.stderr @@ -1,10 +1,10 @@ -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:15:9 | LL | fn f(_: m::Alias) {} | ^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:15:6 | LL | fn f(_: m::Alias) {} @@ -22,7 +22,7 @@ error: type `ext::Priv` is private LL | fn f_ext(_: ext::Alias) {} | ^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:21:6 | LL | impl m::Alias {} @@ -34,13 +34,13 @@ error: type `ext::Priv` is private LL | impl Tr1 for ext::Alias {} | ^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:23:10 | LL | type A = ::X; | ^^^^^^^^^^^^^^^^^^^^^^^^^ private type -error: type `m::Priv` is private +error: type `Priv` is private --> $DIR/private-type-in-interface.rs:27:11 | LL | fn g() -> impl Tr2 { 0 } diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs index feab72b3ef..e485263aff 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.rs @@ -18,14 +18,14 @@ struct PrivateType { pub struct PublicType { pub field: OtherType, - //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface + //~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface priv_field: OtherType, // Private field - this is fine pub other_field: PubType // Type from public dependency - this is fine } impl PublicType { pub fn pub_fn(param: OtherType) {} - //~^ ERROR type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface + //~^ ERROR type `OtherType` from private dependency 'priv_dep' in public interface fn priv_fn(param: OtherType) {} } @@ -33,7 +33,7 @@ impl PublicType { pub trait MyPubTrait { type Foo: OtherTrait; } -//~^^^ ERROR trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface +//~^^^ ERROR trait `OtherTrait` from private dependency 'priv_dep' in public interface pub struct AllowedPrivType { #[allow(exported_private_dependencies)] diff --git a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr index 727134bd51..3b5b782344 100644 --- a/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr +++ b/src/test/ui/privacy/pub-priv-dep/pub-priv1.stderr @@ -1,4 +1,4 @@ -error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface +error: type `OtherType` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:20:5 | LL | pub field: OtherType, @@ -10,13 +10,13 @@ note: the lint level is defined here LL | #![deny(exported_private_dependencies)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: type `priv_dep::OtherType` from private dependency 'priv_dep' in public interface +error: type `OtherType` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:27:5 | LL | pub fn pub_fn(param: OtherType) {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: trait `priv_dep::OtherTrait` from private dependency 'priv_dep' in public interface +error: trait `OtherTrait` from private dependency 'priv_dep' in public interface --> $DIR/pub-priv1.rs:33:1 | LL | / pub trait MyPubTrait { diff --git a/src/test/ui/privacy/restricted/private-in-public.stderr b/src/test/ui/privacy/restricted/private-in-public.stderr index c597935e7f..80995ab98e 100644 --- a/src/test/ui/privacy/restricted/private-in-public.stderr +++ b/src/test/ui/privacy/restricted/private-in-public.stderr @@ -1,17 +1,17 @@ -error[E0446]: private type `foo::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public.rs:8:9 | LL | struct Priv; - | - `foo::Priv` declared as private + | - `Priv` declared as private ... LL | pub(crate) fn g(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^^^^^^ can't leak private type -error[E0446]: private type `foo::Priv` in public interface +error[E0446]: private type `Priv` in public interface --> $DIR/private-in-public.rs:9:9 | LL | struct Priv; - | - `foo::Priv` declared as private + | - `Priv` declared as private ... LL | crate fn h(_: Priv) {} | ^^^^^^^^^^^^^^^^^^^ can't leak private type diff --git a/src/test/ui/privacy/restricted/struct-literal-field.stderr b/src/test/ui/privacy/restricted/struct-literal-field.stderr index 591980dc34..eee964f022 100644 --- a/src/test/ui/privacy/restricted/struct-literal-field.stderr +++ b/src/test/ui/privacy/restricted/struct-literal-field.stderr @@ -1,4 +1,4 @@ -error[E0451]: field `x` of struct `foo::bar::S` is private +error[E0451]: field `x` of struct `S` is private --> $DIR/struct-literal-field.rs:18:9 | LL | S { x: 0 }; diff --git a/src/test/ui/privacy/restricted/test.stderr b/src/test/ui/privacy/restricted/test.stderr index 40512a34bd..61b9a43f89 100644 --- a/src/test/ui/privacy/restricted/test.stderr +++ b/src/test/ui/privacy/restricted/test.stderr @@ -46,7 +46,7 @@ note: the function `f` is defined here LL | pub(super) fn f() {} | ^^^^^^^^^^^^^^^^^ -error[E0616]: field `x` of struct `foo::bar::S` is private +error[E0616]: field `x` of struct `S` is private --> $DIR/test.rs:31:18 | LL | S::default().x; @@ -64,13 +64,13 @@ error[E0624]: associated function `g` is private LL | S::g(); | ^ private associated function -error[E0616]: field `y` of struct `pub_restricted::Universe` is private +error[E0616]: field `y` of struct `Universe` is private --> $DIR/test.rs:42:15 | LL | let _ = u.y; | ^ private field -error[E0616]: field `z` of struct `pub_restricted::Universe` is private +error[E0616]: field `z` of struct `Universe` is private --> $DIR/test.rs:43:15 | LL | let _ = u.z; diff --git a/src/test/ui/privacy/union-field-privacy-1.rs b/src/test/ui/privacy/union-field-privacy-1.rs index 1ff4d513fa..8a84bd86ae 100644 --- a/src/test/ui/privacy/union-field-privacy-1.rs +++ b/src/test/ui/privacy/union-field-privacy-1.rs @@ -9,9 +9,9 @@ mod m { fn main() { unsafe { let u = m::U { a: 0 }; // OK let u = m::U { b: 0 }; // OK - let u = m::U { c: 0 }; //~ ERROR field `c` of union `m::U` is private + let u = m::U { c: 0 }; //~ ERROR field `c` of union `U` is private let m::U { a } = u; // OK let m::U { b } = u; // OK - let m::U { c } = u; //~ ERROR field `c` of union `m::U` is private + let m::U { c } = u; //~ ERROR field `c` of union `U` is private }} diff --git a/src/test/ui/privacy/union-field-privacy-1.stderr b/src/test/ui/privacy/union-field-privacy-1.stderr index 15096eb113..b1f0b785ea 100644 --- a/src/test/ui/privacy/union-field-privacy-1.stderr +++ b/src/test/ui/privacy/union-field-privacy-1.stderr @@ -1,10 +1,10 @@ -error[E0451]: field `c` of union `m::U` is private +error[E0451]: field `c` of union `U` is private --> $DIR/union-field-privacy-1.rs:12:20 | LL | let u = m::U { c: 0 }; | ^^^^ private field -error[E0451]: field `c` of union `m::U` is private +error[E0451]: field `c` of union `U` is private --> $DIR/union-field-privacy-1.rs:16:16 | LL | let m::U { c } = u; diff --git a/src/test/ui/privacy/union-field-privacy-2.rs b/src/test/ui/privacy/union-field-privacy-2.rs index c2458f74bc..f02e0f8a9b 100644 --- a/src/test/ui/privacy/union-field-privacy-2.rs +++ b/src/test/ui/privacy/union-field-privacy-2.rs @@ -11,5 +11,5 @@ fn main() { let a = u.a; // OK let b = u.b; // OK - let c = u.c; //~ ERROR field `c` of union `m::U` is private + let c = u.c; //~ ERROR field `c` of union `U` is private } diff --git a/src/test/ui/privacy/union-field-privacy-2.stderr b/src/test/ui/privacy/union-field-privacy-2.stderr index a23cf90332..bf6a2b625d 100644 --- a/src/test/ui/privacy/union-field-privacy-2.stderr +++ b/src/test/ui/privacy/union-field-privacy-2.stderr @@ -1,4 +1,4 @@ -error[E0616]: field `c` of union `m::U` is private +error[E0616]: field `c` of union `U` is private --> $DIR/union-field-privacy-2.rs:14:15 | LL | let c = u.c; diff --git a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr index 97b2f22e16..7141a1b50b 100644 --- a/src/test/ui/proc-macro/attributes-on-modules-fail.stderr +++ b/src/test/ui/proc-macro/attributes-on-modules-fail.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/attributes-on-modules-fail.rs:16:1 | LL | #[derive(Copy)] @@ -64,5 +64,5 @@ LL | use m::X; error: aborting due to 7 previous errors -Some errors have detailed explanations: E0412, E0658. +Some errors have detailed explanations: E0412, E0658, E0774. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs new file mode 100644 index 0000000000..c72306c3d5 --- /dev/null +++ b/src/test/ui/proc-macro/auxiliary/macro-only-syntax.rs @@ -0,0 +1,89 @@ +// force-host +// no-prefer-dynamic + +// These are tests for syntax that is accepted by the Rust parser but +// unconditionally rejected semantically after macro expansion. Attribute macros +// are permitted to accept such syntax as long as they replace it with something +// that makes sense to Rust. +// +// We also inspect some of the spans to verify the syntax is not triggering the +// lossy string reparse hack (https://github.com/rust-lang/rust/issues/43081). + +#![crate_type = "proc-macro"] +#![feature(proc_macro_span)] + +extern crate proc_macro; +use proc_macro::{token_stream, Delimiter, TokenStream, TokenTree}; +use std::path::Component; + +// unsafe mod m { +// pub unsafe mod inner; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + expect(tokens, "m"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "pub"); + expect(tokens, "unsafe"); + expect(tokens, "mod"); + let ident = expect(tokens, "inner"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-mod.rs"); + TokenStream::new() +} + +// unsafe extern { +// type T; +// } +#[proc_macro_attribute] +pub fn expect_unsafe_foreign_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let tokens = &mut expect_brace(tokens); + expect(tokens, "type"); + let ident = expect(tokens, "T"); + expect(tokens, ";"); + check_useful_span(ident, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +// unsafe extern "C++" {} +#[proc_macro_attribute] +pub fn expect_unsafe_extern_cpp_mod(_attrs: TokenStream, input: TokenStream) -> TokenStream { + let tokens = &mut input.into_iter(); + expect(tokens, "unsafe"); + expect(tokens, "extern"); + let abi = expect(tokens, "\"C++\""); + expect_brace(tokens); + check_useful_span(abi, "unsafe-foreign-mod.rs"); + TokenStream::new() +} + +fn expect(tokens: &mut token_stream::IntoIter, expected: &str) -> TokenTree { + match tokens.next() { + Some(token) if token.to_string() == expected => token, + wrong => panic!("unexpected token: {:?}, expected `{}`", wrong, expected), + } +} + +fn expect_brace(tokens: &mut token_stream::IntoIter) -> token_stream::IntoIter { + match tokens.next() { + Some(TokenTree::Group(group)) if group.delimiter() == Delimiter::Brace => { + group.stream().into_iter() + } + wrong => panic!("unexpected token: {:?}, expected `{{`", wrong), + } +} + +fn check_useful_span(token: TokenTree, expected_filename: &str) { + let span = token.span(); + assert!(span.start().column < span.end().column); + + let source_path = span.source_file().path(); + let filename = source_path.components().last().unwrap(); + assert_eq!(filename, Component::Normal(expected_filename.as_ref())); +} diff --git a/src/test/ui/proc-macro/break-token-spans.stderr b/src/test/ui/proc-macro/break-token-spans.stderr index caca973f25..0a0322b8a3 100644 --- a/src/test/ui/proc-macro/break-token-spans.stderr +++ b/src/test/ui/proc-macro/break-token-spans.stderr @@ -8,11 +8,11 @@ error[E0308]: mismatched types --> $DIR/break-token-spans.rs:14:32 | LL | let a: Option>= true; - | ------------------ ^^^^ expected enum `std::option::Option`, found `bool` + | ------------------ ^^^^ expected enum `Option`, found `bool` | | | expected due to this | - = note: expected enum `std::option::Option>` + = note: expected enum `Option>` found type `bool` error: aborting due to 2 previous errors diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs index 2ff6ad6d68..de008a3708 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.rs +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.rs @@ -1,10 +1,20 @@ // aux-build:test-macros.rs // check-pass // compile-flags: -Z span-debug -// normalize-stdout-test "#\d+" -> "#CTXT" + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; extern crate test_macros; -use test_macros::print_bang; +use test_macros::{print_bang, print_bang_consume}; + +macro_rules! test_matchers { + ($expr:expr, $block:block, $stmt:stmt, $ty:ty, $ident:ident, $lifetime:lifetime, + $meta:meta, $path:path, $vis:vis, $tt:tt, $lit:literal) => { + print_bang_consume!($expr, $block, $stmt, $ty, $ident, + $lifetime, $meta, $path, $vis, $tt, $lit) + } +} macro_rules! use_expr { ($expr:expr) => { @@ -24,10 +34,23 @@ impl Foo { #[allow(dead_code)] fn use_self(self) { drop(use_expr!(self)); + test_matchers!( + 1 + 1, + { "a" }, + let a = 1, + String, + my_name, + 'a, + my_val = 30, + std::option::Option, + pub(in some::path), + [ a b c ], + -30 + ); } fn with_pat(use_pat!((a, b)): (u32, u32)) { - println!("Args: {} {}", a, b); + let _ = (a, b); } } diff --git a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout index 28812e2054..0e7b429d62 100644 --- a/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout +++ b/src/test/ui/proc-macro/capture-macro-rules-invoke.stdout @@ -5,10 +5,299 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "self", - span: $DIR/capture-macro-rules-invoke.rs:26:24: 26:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:36:24: 36:28 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:11:21: 11:26 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:21:21: 21:26 (#4), + }, +] +PRINT-BANG INPUT (DISPLAY): 1 + 1, { "a" }, let a = 1;, String, my_name, 'a, my_val = 30, +std::option::Option, pub(in some::path) , [a b c], -30 +PRINT-BANG RE-COLLECTED (DISPLAY): 1 + 1, { "a" }, let a = 1, String, my_name, 'a, my_val = 30, +std :: option :: Option, pub(in some :: path), [a b c], - 30 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:13: 38:14 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:38:15: 38:16 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:38:17: 38:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:29: 14:34 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:34: 14:35 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: Brace, + stream: TokenStream [ + Literal { + kind: Str, + symbol: "a", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:39:15: 39:18 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:39:13: 39:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:36: 14:42 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:42: 14:43 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "let", + span: $DIR/capture-macro-rules-invoke.rs:40:13: 40:16 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:40:17: 40:18 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:40:19: 40:20 (#0), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:40:21: 40:22 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:44: 14:49 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:49: 14:50 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "String", + span: $DIR/capture-macro-rules-invoke.rs:41:13: 41:19 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:51: 14:54 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:54: 14:55 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_name", + span: $DIR/capture-macro-rules-invoke.rs:42:13: 42:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:14:56: 14:62 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:14:62: 14:63 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '\'', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:43:13: 43:15 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:29: 15:38 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:38: 15:39 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "my_val", + span: $DIR/capture-macro-rules-invoke.rs:44:13: 44:19 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:44:20: 44:21 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:44:22: 44:24 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:40: 15:45 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:45: 15:46 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "std", + span: $DIR/capture-macro-rules-invoke.rs:45:13: 45:16 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:16: 45:18 (#0), + }, + Ident { + ident: "option", + span: $DIR/capture-macro-rules-invoke.rs:45:18: 45:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:45:24: 45:26 (#0), + }, + Ident { + ident: "Option", + span: $DIR/capture-macro-rules-invoke.rs:45:26: 45:32 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:47: 15:52 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:52: 15:53 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Ident { + ident: "pub", + span: $DIR/capture-macro-rules-invoke.rs:46:13: 46:16 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "in", + span: $DIR/capture-macro-rules-invoke.rs:46:17: 46:19 (#0), + }, + Ident { + ident: "some", + span: $DIR/capture-macro-rules-invoke.rs:46:20: 46:24 (#0), + }, + Punct { + ch: ':', + spacing: Joint, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:46:24: 46:26 (#0), + }, + Ident { + ident: "path", + span: $DIR/capture-macro-rules-invoke.rs:46:26: 46:30 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:46:16: 46:31 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:54: 15:58 (#8), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:58: 15:59 (#8), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/capture-macro-rules-invoke.rs:47:15: 47:16 (#0), + }, + Ident { + ident: "b", + span: $DIR/capture-macro-rules-invoke.rs:47:17: 47:18 (#0), + }, + Ident { + ident: "c", + span: $DIR/capture-macro-rules-invoke.rs:47:19: 47:20 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:47:13: 47:22 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:15:63: 15:64 (#8), + }, + Group { + delimiter: None, + stream: TokenStream [ + Punct { + ch: '-', + spacing: Alone, + span: $DIR/capture-macro-rules-invoke.rs:48:13: 48:14 (#0), + }, + Literal { + kind: Integer, + symbol: "30", + suffix: None, + span: $DIR/capture-macro-rules-invoke.rs:48:14: 48:16 (#0), + }, + ], + span: $DIR/capture-macro-rules-invoke.rs:15:65: 15:69 (#8), }, ] PRINT-BANG INPUT (DISPLAY): (a, b) @@ -21,21 +310,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "a", - span: $DIR/capture-macro-rules-invoke.rs:29:27: 29:28 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:27: 52:28 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/capture-macro-rules-invoke.rs:29:28: 29:29 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:28: 52:29 (#0), }, Ident { ident: "b", - span: $DIR/capture-macro-rules-invoke.rs:29:30: 29:31 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:30: 52:31 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:29:26: 29:32 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:52:26: 52:32 (#0), }, ], - span: $DIR/capture-macro-rules-invoke.rs:17:21: 17:25 (#CTXT), + span: $DIR/capture-macro-rules-invoke.rs:27:21: 27:25 (#12), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout index 9a5afbd604..c0c9ed72c5 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-57089.stdout @@ -2,79 +2,79 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:13: 17:19 (#4), }, Ident { ident: "M", - span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:20: 17:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:22: 17:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:28: 17:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:30: 17:31 (#4), }, ], - span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:21: 17:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#3), + span: $DIR/dollar-crate-issue-57089.rs:17:32: 17:33 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:9: 21:15 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:16: 21:17 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:18: 21:24 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:24: 21:26 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:26: 21:27 (#4), }, ], - span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:17: 21:28 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#3), + span: $DIR/dollar-crate-issue-57089.rs:21:28: 21:29 (#4), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout index fc62eadd31..7f133fd05d 100644 --- a/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout +++ b/src/test/ui/proc-macro/dollar-crate-issue-62325.stdout @@ -2,109 +2,109 @@ PRINT-ATTR INPUT (DISPLAY): struct A(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:5: 19:11 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:12: 19:13 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:14: 19:22 (#4), }, Punct { ch: '!', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:22: 19:23 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:24: 19:30 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:30: 19:32 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:32: 19:33 (#4), }, ], - span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:23: 19:34 (#4), }, ], - span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:13: 19:35 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#3), + span: $DIR/dollar-crate-issue-62325.rs:19:35: 19:36 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct B(identity ! ($crate :: S)) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:5: 21:11 (#12), }, Ident { ident: "B", - span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:12: 21:13 (#12), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "identity", - span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:14: 21:22 (#12), }, Punct { ch: '!', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:22: 21:23 (#12), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:24: 21:30 (#12), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#12), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:30: 21:32 (#12), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:32: 21:33 (#12), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:23: 21:34 (#12), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:13: 21:35 (#12), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#10), + span: $DIR/auxiliary/dollar-crate-external.rs:21:35: 21:36 (#12), }, ] diff --git a/src/test/ui/proc-macro/dollar-crate.stdout b/src/test/ui/proc-macro/dollar-crate.stdout index 72fc658858..d01fcb9d0e 100644 --- a/src/test/ui/proc-macro/dollar-crate.stdout +++ b/src/test/ui/proc-macro/dollar-crate.stdout @@ -2,239 +2,239 @@ PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:20:17: 20:23 (#3), + span: $DIR/dollar-crate.rs:20:17: 20:23 (#4), }, Ident { ident: "M", - span: $DIR/dollar-crate.rs:20:24: 20:25 (#3), + span: $DIR/dollar-crate.rs:20:24: 20:25 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:20:26: 20:32 (#3), + span: $DIR/dollar-crate.rs:20:26: 20:32 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:20:32: 20:34 (#3), + span: $DIR/dollar-crate.rs:20:32: 20:34 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:20:32: 20:34 (#3), + span: $DIR/dollar-crate.rs:20:32: 20:34 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:20:34: 20:35 (#3), + span: $DIR/dollar-crate.rs:20:34: 20:35 (#4), }, ], - span: $DIR/dollar-crate.rs:20:25: 20:36 (#3), + span: $DIR/dollar-crate.rs:20:25: 20:36 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:20:36: 20:37 (#3), + span: $DIR/dollar-crate.rs:20:36: 20:37 (#4), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:24:13: 24:19 (#3), + span: $DIR/dollar-crate.rs:24:13: 24:19 (#4), }, Ident { ident: "A", - span: $DIR/dollar-crate.rs:24:20: 24:21 (#3), + span: $DIR/dollar-crate.rs:24:20: 24:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:24:22: 24:28 (#3), + span: $DIR/dollar-crate.rs:24:22: 24:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:24:28: 24:30 (#3), + span: $DIR/dollar-crate.rs:24:28: 24:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:24:28: 24:30 (#3), + span: $DIR/dollar-crate.rs:24:28: 24:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:24:30: 24:31 (#3), + span: $DIR/dollar-crate.rs:24:30: 24:31 (#4), }, ], - span: $DIR/dollar-crate.rs:24:21: 24:32 (#3), + span: $DIR/dollar-crate.rs:24:21: 24:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:24:32: 24:33 (#3), + span: $DIR/dollar-crate.rs:24:32: 24:33 (#4), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/dollar-crate.rs:27:13: 27:19 (#3), + span: $DIR/dollar-crate.rs:27:13: 27:19 (#4), }, Ident { ident: "D", - span: $DIR/dollar-crate.rs:27:20: 27:21 (#3), + span: $DIR/dollar-crate.rs:27:20: 27:21 (#4), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/dollar-crate.rs:27:22: 27:28 (#3), + span: $DIR/dollar-crate.rs:27:22: 27:28 (#4), }, Punct { ch: ':', spacing: Joint, - span: $DIR/dollar-crate.rs:27:28: 27:30 (#3), + span: $DIR/dollar-crate.rs:27:28: 27:30 (#4), }, Punct { ch: ':', spacing: Alone, - span: $DIR/dollar-crate.rs:27:28: 27:30 (#3), + span: $DIR/dollar-crate.rs:27:28: 27:30 (#4), }, Ident { ident: "S", - span: $DIR/dollar-crate.rs:27:30: 27:31 (#3), + span: $DIR/dollar-crate.rs:27:30: 27:31 (#4), }, ], - span: $DIR/dollar-crate.rs:27:21: 27:32 (#3), + span: $DIR/dollar-crate.rs:27:21: 27:32 (#4), }, Punct { ch: ';', spacing: Alone, - span: $DIR/dollar-crate.rs:27:32: 27:33 (#3), + span: $DIR/dollar-crate.rs:27:32: 27:33 (#4), }, ] PRINT-BANG INPUT (DISPLAY): struct M($crate :: S) ; PRINT-BANG INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:13: 7:19 (#15), }, Ident { ident: "M", - span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:20: 7:21 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:22: 7:28 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:28: 7:30 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:30: 7:31 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:21: 7:32 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:7:32: 7:33 (#15), }, ] PRINT-ATTR INPUT (DISPLAY): struct A($crate :: S) ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:9: 11:15 (#15), }, Ident { ident: "A", - span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:16: 11:17 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:18: 11:24 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:24: 11:26 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:26: 11:27 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:17: 11:28 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:11:28: 11:29 (#15), }, ] PRINT-DERIVE INPUT (DISPLAY): struct D($crate :: S) ; PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:9: 14:15 (#15), }, Ident { ident: "D", - span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:16: 14:17 (#15), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "$crate", - span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:18: 14:24 (#15), }, Punct { ch: ':', spacing: Joint, - span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#15), }, Punct { ch: ':', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:24: 14:26 (#15), }, Ident { ident: "S", - span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:26: 14:27 (#15), }, ], - span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:17: 14:28 (#15), }, Punct { ch: ';', spacing: Alone, - span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#13), + span: $DIR/auxiliary/dollar-crate-external.rs:14:28: 14:29 (#15), }, ] diff --git a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout index e7645280a7..e83bc9f8fc 100644 --- a/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout +++ b/src/test/ui/proc-macro/group-compat-hack/group-compat-hack.stdout @@ -1,6 +1,6 @@ -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#5) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#5) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#5) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#5) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#9) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#9) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#9) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#9) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#13) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#13) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#13) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#13) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#13) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#19) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#19) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#19) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#19) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#23) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#23) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#23) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#23) }] -Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#27) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#27) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#27) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#27) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#27) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl/src/lib.rs:5:21: 5:27 (#6) }, Ident { ident: "One", span: $DIR/time-macros-impl/src/lib.rs:5:28: 5:31 (#6) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:27:18: 27:21 (#0) }], span: $DIR/time-macros-impl/src/lib.rs:5:31: 5:38 (#6) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl/src/lib.rs:5:38: 5:39 (#6) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys/src/lib.rs:5:21: 5:27 (#10) }, Ident { ident: "Two", span: $DIR/js-sys/src/lib.rs:5:28: 5:31 (#10) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:28:13: 28:16 (#0) }], span: $DIR/js-sys/src/lib.rs:5:31: 5:38 (#10) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys/src/lib.rs:5:38: 5:39 (#10) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:22:25: 22:31 (#14) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:22:32: 22:37 (#14) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:29:12: 29:15 (#0) }], span: $DIR/group-compat-hack.rs:22:38: 22:43 (#14) }], span: $DIR/group-compat-hack.rs:22:37: 22:44 (#14) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:22:44: 22:45 (#14) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:21: 5:27 (#20) }, Ident { ident: "One", span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:28: 5:31 (#20) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:43:18: 43:21 (#0) }], span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:31: 5:38 (#20) }, Punct { ch: ';', spacing: Alone, span: $DIR/time-macros-impl-0.1.0/src/lib.rs:5:38: 5:39 (#20) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/js-sys-0.3.17/src/lib.rs:5:21: 5:27 (#24) }, Ident { ident: "Two", span: $DIR/js-sys-0.3.17/src/lib.rs:5:28: 5:31 (#24) }, Group { delimiter: Parenthesis, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:44:13: 44:16 (#0) }], span: $DIR/js-sys-0.3.17/src/lib.rs:5:31: 5:38 (#24) }, Punct { ch: ';', spacing: Alone, span: $DIR/js-sys-0.3.17/src/lib.rs:5:38: 5:39 (#24) }] +Called proc_macro_hack with TokenStream [Ident { ident: "struct", span: $DIR/group-compat-hack.rs:38:25: 38:31 (#28) }, Ident { ident: "Three", span: $DIR/group-compat-hack.rs:38:32: 38:37 (#28) }, Group { delimiter: Parenthesis, stream: TokenStream [Group { delimiter: None, stream: TokenStream [Ident { ident: "Foo", span: $DIR/group-compat-hack.rs:45:12: 45:15 (#0) }], span: $DIR/group-compat-hack.rs:38:38: 38:43 (#28) }], span: $DIR/group-compat-hack.rs:38:37: 38:44 (#28) }, Punct { ch: ';', spacing: Alone, span: $DIR/group-compat-hack.rs:38:44: 38:45 (#28) }] diff --git a/src/test/ui/proc-macro/input-interpolated.stdout b/src/test/ui/proc-macro/input-interpolated.stdout index a9636cfef8..866608e4d8 100644 --- a/src/test/ui/proc-macro/input-interpolated.stdout +++ b/src/test/ui/proc-macro/input-interpolated.stdout @@ -8,14 +8,14 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(370..372), + span: #4 bytes(370..372), }, ] PRINT-ATTR INPUT (DISPLAY): const A : u8 = 0 ; PRINT-ATTR INPUT (DEBUG): TokenStream [ Ident { ident: "const", - span: #3 bytes(416..421), + span: #4 bytes(416..421), }, Group { delimiter: None, @@ -25,39 +25,39 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(422..424), + span: #4 bytes(422..424), }, Punct { ch: ':', spacing: Alone, - span: #3 bytes(424..425), + span: #4 bytes(424..425), }, Ident { ident: "u8", - span: #3 bytes(426..428), + span: #4 bytes(426..428), }, Punct { ch: '=', spacing: Alone, - span: #3 bytes(429..430), + span: #4 bytes(429..430), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: #3 bytes(431..432), + span: #4 bytes(431..432), }, Punct { ch: ';', spacing: Alone, - span: #3 bytes(432..433), + span: #4 bytes(432..433), }, ] PRINT-DERIVE INPUT (DISPLAY): struct A { } PRINT-DERIVE INPUT (DEBUG): TokenStream [ Ident { ident: "struct", - span: #3 bytes(468..474), + span: #4 bytes(468..474), }, Group { delimiter: None, @@ -67,11 +67,11 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ span: #0 bytes(503..504), }, ], - span: #3 bytes(475..477), + span: #4 bytes(475..477), }, Group { delimiter: Brace, stream: TokenStream [], - span: #3 bytes(478..480), + span: #4 bytes(478..480), }, ] diff --git a/src/test/ui/proc-macro/issue-37788.stderr b/src/test/ui/proc-macro/issue-37788.stderr index f2c833e69f..0538701290 100644 --- a/src/test/ui/proc-macro/issue-37788.stderr +++ b/src/test/ui/proc-macro/issue-37788.stderr @@ -7,10 +7,10 @@ LL | // Test that constructing the `visible_parent_map` (in `cstore_impl.rs` LL | std::cell::Cell::new(0) | ^^^^^^^^^^^^^^^^^^^^^^^- help: try adding a semicolon: `;` | | - | expected `()`, found struct `std::cell::Cell` + | expected `()`, found struct `Cell` | = note: expected unit type `()` - found struct `std::cell::Cell<{integer}>` + found struct `Cell<{integer}>` error: aborting due to previous error diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.rs b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs new file mode 100644 index 0000000000..a051d23bac --- /dev/null +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.rs @@ -0,0 +1,66 @@ +// check-pass +// compile-flags: -Z span-debug --error-format human +// aux-build:test-macros.rs + +// Regression test for issue #75930 +// Tests that we cfg-strip all targets before invoking +// a derive macro +// We need '--error-format human' to stop compiletest from +// trying to interpret proc-macro output as JSON messages +// (a pretty-printed struct may cause a line to start with '{' ) +// FIXME: We currently lose spans here (see issue #43081) + +#[macro_use] +extern crate test_macros; + +#[print_helper(a)] +#[cfg_attr(not(FALSE), allow(dead_code))] +#[print_attr] +#[derive(Print)] +#[print_helper(b)] +struct Foo<#[cfg(FALSE)] A, B> { + #[cfg(FALSE)] first: String, + #[cfg_attr(FALSE, deny(warnings))] second: bool, + third: [u8; { + #[cfg(FALSE)] struct Bar; + #[cfg(not(FALSE))] struct Inner; + #[cfg(FALSE)] let a = 25; + match true { + #[cfg(FALSE)] true => {}, + #[cfg_attr(not(FALSE), allow(warnings))] false => {}, + _ => {} + }; + + #[print_helper(should_be_removed)] + fn removed_fn() { + #![cfg(FALSE)] + } + + #[print_helper(c)] #[cfg(not(FALSE))] fn kept_fn() { + #![cfg(not(FALSE))] + let my_val = true; + } + + enum TupleEnum { + Foo( + #[cfg(FALSE)] u8, + #[cfg(FALSE)] bool, + #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8 + ) + } + + struct TupleStruct( + #[cfg(FALSE)] String, + #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, + u8 + ); + + 0 + }], + #[print_helper(d)] + fourth: B +} + +fn main() {} diff --git a/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout new file mode 100644 index 0000000000..f3daa56a49 --- /dev/null +++ b/src/test/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -0,0 +1,1831 @@ +PRINT-ATTR INPUT (DISPLAY): #[allow(dead_code)] #[derive(Print)] #[print_helper(b)] #[print_helper(a)] +struct Foo < #[cfg(FALSE)] A, B > +{ + #[cfg(FALSE)] first : String, #[cfg_attr(FALSE, deny(warnings))] second : + bool, third : + [u8 ; + { + #[cfg(FALSE)] struct Bar ; #[cfg(not(FALSE))] struct Inner ; + #[cfg(FALSE)] let a = 25 ; match true + { + #[cfg(FALSE)] true => { }, + #[cfg_attr(not(FALSE), allow(warnings))] false => { }, _ => { } + } ; #[print_helper(should_be_removed)] fn removed_fn() + { # ! [cfg(FALSE)] } #[print_helper(c)] #[cfg(not(FALSE))] fn + kept_fn() { # ! [cfg(not(FALSE))] let my_val = true ; } enum + TupleEnum + { + Foo(#[cfg(FALSE)] u8, #[cfg(FALSE)] bool, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] String, u8) + } struct + TupleStruct(#[cfg(FALSE)] String, #[cfg(not(FALSE))] i32, + #[cfg(FALSE)] bool, u8) ; 0 + }], #[print_helper(d)] fourth : B +} +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:40 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:29 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/issue-75930-derive-cfg.rs:17:30: 17:39 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:17:29: 17:40 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:17:24: 17:40 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:17 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "derive", + span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:9 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "Print", + span: $DIR/issue-75930-derive-cfg.rs:19:10: 19:15 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:19:9: 19:16 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:17 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:19 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:20:3: 20:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "b", + span: $DIR/issue-75930-derive-cfg.rs:20:16: 20:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:20:15: 20:18 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:20:1: 20:19 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:19 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:16:3: 16:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:16:16: 16:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:15: 16:18 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:16:1: 16:19 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:7 (#0), + }, + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:21:8: 21:11 (#0), + }, + Punct { + ch: '<', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:21:11: 21:12 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:12: 21:13 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:21:14: 21:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:21:18: 21:23 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:17: 21:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:13: 21:25 (#0), + }, + Ident { + ident: "A", + span: $DIR/issue-75930-derive-cfg.rs:21:26: 21:27 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:27: 21:28 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:30 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:31 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:5: 22:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:22:7: 22:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:22:11: 22:16 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:22:10: 22:17 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:22:6: 22:18 (#0), + }, + Ident { + ident: "first", + span: $DIR/issue-75930-derive-cfg.rs:22:19: 22:24 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:24: 22:25 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:22:26: 22:32 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:22:32: 22:33 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:5: 23:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/issue-75930-derive-cfg.rs:23:7: 23:15 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:23:16: 23:21 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:21: 23:22 (#0), + }, + Ident { + ident: "deny", + span: $DIR/issue-75930-derive-cfg.rs:23:23: 23:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:23:28: 23:36 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:27: 23:37 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:15: 23:38 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:23:6: 23:39 (#0), + }, + Ident { + ident: "second", + span: $DIR/issue-75930-derive-cfg.rs:23:40: 23:46 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:46: 23:47 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:23:48: 23:52 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:23:52: 23:53 (#0), + }, + Ident { + ident: "third", + span: $DIR/issue-75930-derive-cfg.rs:24:5: 24:10 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:24:10: 24:11 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:24:13: 24:15 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:16 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:25:9: 25:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:25:15: 25:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:25:14: 25:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:25:10: 25:22 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:25:23: 25:29 (#0), + }, + Ident { + ident: "Bar", + span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:25:33: 25:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:26:9: 26:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:26:15: 26:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:26:19: 26:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:18: 26:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:14: 26:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:27 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:26:28: 26:34 (#0), + }, + Ident { + ident: "Inner", + span: $DIR/issue-75930-derive-cfg.rs:26:35: 26:40 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:26:40: 26:41 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:9: 27:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:27:11: 27:14 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:27:14: 27:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:27:10: 27:22 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:27:23: 27:26 (#0), + }, + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:27:27: 27:28 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:29: 27:30 (#0), + }, + Literal { + kind: Integer, + symbol: "25", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:27:31: 27:33 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:27:33: 27:34 (#0), + }, + Ident { + ident: "match", + span: $DIR/issue-75930-derive-cfg.rs:28:9: 28:14 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:19 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:13: 29:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:29:19: 29:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:29:18: 29:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:29:14: 29:26 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:29:27: 29:31 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:32: 29:34 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:29:35: 29:37 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:29:37: 29:38 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:13: 30:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg_attr", + span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:30:24: 30:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:33 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:27: 30:34 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:34: 30:35 (#0), + }, + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:30:36: 30:41 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:30:42: 30:50 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:41: 30:51 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:23: 30:52 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:53 (#0), + }, + Ident { + ident: "false", + span: $DIR/issue-75930-derive-cfg.rs:30:54: 30:59 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:60: 30:62 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:30:63: 30:65 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:30:65: 30:66 (#0), + }, + Ident { + ident: "_", + span: $DIR/issue-75930-derive-cfg.rs:31:13: 31:14 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:17 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:31:18: 31:20 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:28:20: 32:10 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:32:10: 32:11 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:34:9: 34:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:34:11: 34:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "should_be_removed", + span: $DIR/issue-75930-derive-cfg.rs:34:24: 34:41 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:34:23: 34:42 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:34:10: 34:43 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:35:9: 35:11 (#0), + }, + Ident { + ident: "removed_fn", + span: $DIR/issue-75930-derive-cfg.rs:35:12: 35:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:35:22: 35:24 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:36:13: 36:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:36:14: 36:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:36:16: 36:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:36:20: 36:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:36:19: 36:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:36:15: 36:27 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:35:25: 37:10 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:39:9: 39:10 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:39:11: 39:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "c", + span: $DIR/issue-75930-derive-cfg.rs:39:24: 39:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:23: 39:26 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:10: 39:27 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:39:28: 39:29 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:39:30: 39:33 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:39:34: 39:37 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:39:38: 39:43 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:37: 39:44 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:33: 39:45 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:29: 39:46 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:39:47: 39:49 (#0), + }, + Ident { + ident: "kept_fn", + span: $DIR/issue-75930-derive-cfg.rs:39:50: 39:57 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:39:57: 39:59 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:40:13: 40:14 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:40:14: 40:15 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:40:16: 40:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:40:20: 40:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:40:24: 40:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:23: 40:30 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:19: 40:31 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:40:15: 40:32 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:41:13: 41:16 (#0), + }, + Ident { + ident: "my_val", + span: $DIR/issue-75930-derive-cfg.rs:41:17: 41:23 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:41:24: 41:25 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:41:26: 41:30 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:41:30: 41:31 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:39:60: 42:10 (#0), + }, + Ident { + ident: "enum", + span: $DIR/issue-75930-derive-cfg.rs:44:9: 44:13 (#0), + }, + Ident { + ident: "TupleEnum", + span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:23 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:46:17: 46:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:46:19: 46:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:46:23: 46:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:46:22: 46:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:46:18: 46:30 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:46:31: 46:33 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:46:33: 46:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:47:17: 47:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:47:19: 47:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:47:23: 47:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:47:22: 47:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:47:18: 47:30 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:47:31: 47:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:47:35: 47:36 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:48:17: 48:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:48:19: 48:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:48:23: 48:26 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:48:27: 48:32 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:26: 48:33 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:22: 48:34 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:48:18: 48:35 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:48:36: 48:39 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:48:39: 48:40 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:49:17: 49:18 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:49:19: 49:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:49:23: 49:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:49:22: 49:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:49:18: 49:30 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:49:31: 49:37 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:49:37: 49:38 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:49:39: 49:41 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:45:16: 50:14 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:44:24: 51:10 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:53:9: 53:15 (#0), + }, + Ident { + ident: "TupleStruct", + span: $DIR/issue-75930-derive-cfg.rs:53:16: 53:27 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:54:13: 54:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:54:19: 54:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:54:18: 54:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:54:14: 54:26 (#0), + }, + Ident { + ident: "String", + span: $DIR/issue-75930-derive-cfg.rs:54:27: 54:33 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:54:33: 54:34 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:55:15: 55:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:55:19: 55:22 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:55:23: 55:28 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:22: 55:29 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:30 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:31 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:55:32: 55:35 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:55:35: 55:36 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:56:13: 56:14 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:56:15: 56:18 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:24 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:56:18: 56:25 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:56:14: 56:26 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:56:27: 56:31 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:56:31: 56:32 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:57:13: 57:15 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:53:27: 58:10 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:24:17: 61:6 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:24:12: 61:7 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:61:7: 61:8 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:62:5: 62:6 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:62:7: 62:19 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "d", + span: $DIR/issue-75930-derive-cfg.rs:62:20: 62:21 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:62:19: 62:22 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:62:6: 62:23 (#0), + }, + Ident { + ident: "fourth", + span: $DIR/issue-75930-derive-cfg.rs:63:5: 63:11 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:63:11: 63:12 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:21:32: 64:2 (#0), + }, +] +PRINT-DERIVE INPUT (DISPLAY): #[allow(dead_code)] #[print_helper(b)] #[print_helper(a)] struct Foo < B > +{ + second : bool, third : + [u8 ; + { + #[cfg(not(FALSE))] struct Inner ; match true + { #[allow(warnings)] false => { } _ => { } } ; #[print_helper(c)] + #[cfg(not(FALSE))] fn kept_fn() + { # ! [cfg(not(FALSE))] let my_val = true ; } enum TupleEnum + { Foo(#[cfg(not(FALSE))] i32, u8), } struct + TupleStruct(#[cfg(not(FALSE))] i32, u8) ; 0 + }], #[print_helper(d)] fourth : B, +} +PRINT-DERIVE INPUT (DEBUG): TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "dead_code", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "b", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "a", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "second", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "bool", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "third", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "Inner", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "match", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "allow", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "warnings", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "false", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "_", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "c", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "fn", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "kept_fn", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Joint, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '!', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "let", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "my_val", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '=', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "true", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "enum", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "TupleEnum", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "Foo", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "struct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "TupleStruct", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "cfg", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "not", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "FALSE", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "i32", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "u8", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ';', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: '#', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Bracket, + stream: TokenStream [ + Ident { + ident: "print_helper", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [ + Ident { + ident: "d", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "fourth", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Ident { + ident: "B", + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + Punct { + ch: ',', + spacing: Alone, + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, + ], + span: $DIR/issue-75930-derive-cfg.rs:1:1: 1:1 (#0), + }, +] diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs new file mode 100644 index 0000000000..7d31de1d22 --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.rs @@ -0,0 +1,16 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug +// +// Regression test for issue #76182 +// Tests that we properly handle patterns with a leading vert + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn main() { + match () { | () => () } +} diff --git a/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout new file mode 100644 index 0000000000..5493f9c7b6 --- /dev/null +++ b/src/test/ui/proc-macro/issue-76182-leading-vert-pat.stdout @@ -0,0 +1,62 @@ +PRINT-ATTR INPUT (DISPLAY): fn main() { match() { | () => () } } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/issue-76182-leading-vert-pat.rs:14:1: 14:3 (#0), + }, + Ident { + ident: "main", + span: $DIR/issue-76182-leading-vert-pat.rs:14:4: 14:8 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:14:8: 14:10 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Ident { + ident: "match", + span: $DIR/issue-76182-leading-vert-pat.rs:15:5: 15:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:11: 15:13 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [ + Punct { + ch: '|', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:16: 15:17 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:18: 15:20 (#0), + }, + Punct { + ch: '=', + spacing: Joint, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/issue-76182-leading-vert-pat.rs:15:21: 15:23 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/issue-76182-leading-vert-pat.rs:15:24: 15:26 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:15:14: 15:28 (#0), + }, + ], + span: $DIR/issue-76182-leading-vert-pat.rs:14:11: 16:2 (#0), + }, +] diff --git a/src/test/ui/proc-macro/load-panic-backtrace.rs b/src/test/ui/proc-macro/load-panic-backtrace.rs new file mode 100644 index 0000000000..90fe109abb --- /dev/null +++ b/src/test/ui/proc-macro/load-panic-backtrace.rs @@ -0,0 +1,21 @@ +// aux-build:test-macros.rs +// compile-flags: -Z proc-macro-backtrace +// rustc-env:RUST_BACKTRACE=0 + +// FIXME https://github.com/rust-lang/rust/issues/59998 +// normalize-stderr-test "thread '.*' panicked " -> "" +// normalize-stderr-test "note:.*RUST_BACKTRACE=1.*\n" -> "" +// normalize-stderr-test "\nerror: internal compiler error.*\n\n" -> "" +// normalize-stderr-test "note:.*unexpectedly panicked.*\n\n" -> "" +// normalize-stderr-test "note: we would appreciate a bug report.*\n\n" -> "" +// normalize-stderr-test "note: compiler flags.*\n\n" -> "" +// normalize-stderr-test "note: rustc.*running on.*\n\n" -> "" + +#[macro_use] +extern crate test_macros; + +#[derive(Panic)] +//~^ ERROR: proc-macro derive panicked +struct Foo; + +fn main() {} diff --git a/src/test/ui/proc-macro/load-panic-backtrace.stderr b/src/test/ui/proc-macro/load-panic-backtrace.stderr new file mode 100644 index 0000000000..63378b5735 --- /dev/null +++ b/src/test/ui/proc-macro/load-panic-backtrace.stderr @@ -0,0 +1,11 @@ +at 'panic-derive', $DIR/auxiliary/test-macros.rs:43:5 +error: proc-macro derive panicked + --> $DIR/load-panic-backtrace.rs:17:10 + | +LL | #[derive(Panic)] + | ^^^^^ + | + = help: message: panic-derive + +error: aborting due to previous error + diff --git a/src/test/ui/proc-macro/macros-in-extern-derive.stderr b/src/test/ui/proc-macro/macros-in-extern-derive.stderr index e2afb7d34c..6b73744920 100644 --- a/src/test/ui/proc-macro/macros-in-extern-derive.stderr +++ b/src/test/ui/proc-macro/macros-in-extern-derive.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/macros-in-extern-derive.rs:2:5 | LL | #[derive(Copy)] @@ -6,3 +6,4 @@ LL | #[derive(Copy)] error: aborting due to previous error +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.rs b/src/test/ui/proc-macro/meta-macro-hygiene.rs index c11cf42956..7e839f747f 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.rs +++ b/src/test/ui/proc-macro/meta-macro-hygiene.rs @@ -1,7 +1,8 @@ +// ignore-tidy-linelength // aux-build:make-macro.rs // aux-build:meta-macro.rs // edition:2018 -// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene +// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" // diff --git a/src/test/ui/proc-macro/meta-macro-hygiene.stdout b/src/test/ui/proc-macro/meta-macro-hygiene.stdout index dfd3e6a839..81cebae17a 100644 --- a/src/test/ui/proc-macro/meta-macro-hygiene.stdout +++ b/src/test/ui/proc-macro/meta-macro-hygiene.stdout @@ -1,11 +1,12 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) -Input: TokenStream [Ident { ident: "$crate", span: $DIR/meta-macro-hygiene.rs:23:37: 23:43 (#3) }, Punct { ch: ':', spacing: Joint, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Punct { ch: ':', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:43: 23:45 (#3) }, Ident { ident: "dummy", span: $DIR/meta-macro-hygiene.rs:23:45: 23:50 (#3) }, Punct { ch: '!', spacing: Alone, span: $DIR/meta-macro-hygiene.rs:23:50: 23:51 (#3) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/meta-macro-hygiene.rs:23:51: 23:53 (#3) }] -Respanned: TokenStream [Ident { ident: "$crate", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Joint, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: ':', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Ident { ident: "dummy", span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Punct { ch: '!', spacing: Alone, span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }, Group { delimiter: Parenthesis, stream: TokenStream [], span: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#4) }] +Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#5) +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)] +// ignore-tidy-linelength // aux-build:make-macro.rs // aux-build:meta-macro.rs // edition:2018 -// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene +// compile-flags: -Z span-debug -Z macro-backtrace -Z unpretty=expanded,hygiene -Z trim-diagnostic-paths=no // check-pass // normalize-stdout-test "\d+#" -> "0#" // @@ -46,18 +47,20 @@ Expansions: 0: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Root 1: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) 2: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: Macro(Bang, "produce_it") -3: parent: ExpnId(2), call_site_ctxt: #3, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") -4: parent: ExpnId(3), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") +3: parent: ExpnId(0), call_site_ctxt: #0, def_site_ctxt: #0, kind: AstPass(StdImports) +4: parent: ExpnId(2), call_site_ctxt: #4, def_site_ctxt: #0, kind: Macro(Bang, "meta_macro::print_def_site") +5: parent: ExpnId(4), call_site_ctxt: #5, def_site_ctxt: #0, kind: Macro(Bang, "$crate::dummy") SyntaxContexts: #0: parent: #0, outer_mark: (ExpnId(0), Opaque) #1: parent: #0, outer_mark: (ExpnId(1), Opaque) #2: parent: #0, outer_mark: (ExpnId(1), Transparent) -#3: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) -#4: parent: #0, outer_mark: (ExpnId(3), Opaque) -#5: parent: #3, outer_mark: (ExpnId(3), Transparent) -#6: parent: #0, outer_mark: (ExpnId(3), SemiTransparent) -#7: parent: #0, outer_mark: (ExpnId(4), Opaque) -#8: parent: #4, outer_mark: (ExpnId(4), Transparent) -#9: parent: #4, outer_mark: (ExpnId(4), SemiTransparent) +#3: parent: #0, outer_mark: (ExpnId(3), Opaque) +#4: parent: #0, outer_mark: (ExpnId(2), SemiTransparent) +#5: parent: #0, outer_mark: (ExpnId(4), Opaque) +#6: parent: #4, outer_mark: (ExpnId(4), Transparent) +#7: parent: #0, outer_mark: (ExpnId(4), SemiTransparent) +#8: parent: #0, outer_mark: (ExpnId(5), Opaque) +#9: parent: #5, outer_mark: (ExpnId(5), Transparent) +#10: parent: #5, outer_mark: (ExpnId(5), SemiTransparent) */ diff --git a/src/test/ui/proc-macro/meta-macro.stdout b/src/test/ui/proc-macro/meta-macro.stdout index 71aa565f4d..662682d40b 100644 --- a/src/test/ui/proc-macro/meta-macro.stdout +++ b/src/test/ui/proc-macro/meta-macro.stdout @@ -1,3 +1,3 @@ -Def site: $DIR/auxiliary/make-macro.rs:7:9: 16:10 (#3) +Def site: $DIR/auxiliary/make-macro.rs:7:9: 7:56 (#4) Input: TokenStream [] Respanned: TokenStream [] diff --git a/src/test/ui/proc-macro/nested-macro-rules.stdout b/src/test/ui/proc-macro/nested-macro-rules.stdout index 7feea56c5d..dcafe3b4bd 100644 --- a/src/test/ui/proc-macro/nested-macro-rules.stdout +++ b/src/test/ui/proc-macro/nested-macro-rules.stdout @@ -5,10 +5,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "FirstStruct", - span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#5), + span: $DIR/auxiliary/nested-macro-rules.rs:15:14: 15:25 (#7), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#4), + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#6), }, ] PRINT-BANG INPUT (DISPLAY): SecondStruct @@ -18,9 +18,9 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ stream: TokenStream [ Ident { ident: "SecondStruct", - span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#11), + span: $DIR/nested-macro-rules.rs:21:38: 21:50 (#13), }, ], - span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#10), + span: $DIR/auxiliary/nested-macro-rules.rs:9:27: 9:32 (#12), }, ] diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.rs b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs new file mode 100644 index 0000000000..2f5af10a40 --- /dev/null +++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs @@ -0,0 +1,26 @@ +// check-pass +// edition:2018 +// compile-flags: -Z span-debug +// aux-build:test-macros.rs + +// Tests that we properly pass tokens to proc-macro when nested +// nonterminals are involved. + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +#[macro_use] +extern crate test_macros; + + +macro_rules! wrap { + (first, $e:expr) => { wrap!(second, $e + 1) }; + (second, $e:expr) => { wrap!(third, $e + 2) }; + (third, $e:expr) => { + print_bang!($e + 3); + }; +} + +fn main() { + let _ = wrap!(first, 0); +} diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout new file mode 100644 index 0000000000..a3d24dd26f --- /dev/null +++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.stdout @@ -0,0 +1,60 @@ +PRINT-BANG INPUT (DISPLAY): 0 + 1 + 2 + 3 +PRINT-BANG INPUT (DEBUG): TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Group { + delimiter: None, + stream: TokenStream [ + Literal { + kind: Integer, + symbol: "0", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:25:26: 25:27 (#0), + }, + ], + span: $DIR/nested-nonterminal-tokens.rs:17:41: 17:43 (#4), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nested-nonterminal-tokens.rs:17:44: 17:45 (#4), + }, + Literal { + kind: Integer, + symbol: "1", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:17:46: 17:47 (#4), + }, + ], + span: $DIR/nested-nonterminal-tokens.rs:18:41: 18:43 (#5), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nested-nonterminal-tokens.rs:18:44: 18:45 (#5), + }, + Literal { + kind: Integer, + symbol: "2", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:18:46: 18:47 (#5), + }, + ], + span: $DIR/nested-nonterminal-tokens.rs:20:21: 20:23 (#6), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/nested-nonterminal-tokens.rs:20:24: 20:25 (#6), + }, + Literal { + kind: Integer, + symbol: "3", + suffix: None, + span: $DIR/nested-nonterminal-tokens.rs:20:26: 20:27 (#6), + }, +] diff --git a/src/test/ui/proc-macro/nodelim-groups.stdout b/src/test/ui/proc-macro/nodelim-groups.stdout index cdf851b535..6b410f0bfb 100644 --- a/src/test/ui/proc-macro/nodelim-groups.stdout +++ b/src/test/ui/proc-macro/nodelim-groups.stdout @@ -4,7 +4,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Str, symbol: "hi", suffix: None, - span: $DIR/nodelim-groups.rs:16:42: 16:46 (#3), + span: $DIR/nodelim-groups.rs:16:42: 16:46 (#4), }, Group { delimiter: None, @@ -44,7 +44,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:20:27: 20:28 (#0), }, ], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#3), + span: $DIR/nodelim-groups.rs:16:47: 16:51 (#4), }, Group { delimiter: Parenthesis, @@ -53,21 +53,21 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:53: 16:54 (#3), + span: $DIR/nodelim-groups.rs:16:53: 16:54 (#4), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:16:55: 16:56 (#3), + span: $DIR/nodelim-groups.rs:16:55: 16:56 (#4), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:57: 16:58 (#3), + span: $DIR/nodelim-groups.rs:16:57: 16:58 (#4), }, ], - span: $DIR/nodelim-groups.rs:16:52: 16:59 (#3), + span: $DIR/nodelim-groups.rs:16:52: 16:59 (#4), }, ] PRINT-BANG INPUT (DISPLAY): "hi" "hello".len() + "world".len() (1 + 1) @@ -76,7 +76,7 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Str, symbol: "hi", suffix: None, - span: $DIR/nodelim-groups.rs:16:42: 16:46 (#8), + span: $DIR/nodelim-groups.rs:16:42: 16:46 (#9), }, Group { delimiter: None, @@ -105,12 +105,12 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:21:28: 21:30 (#0), }, ], - span: $DIR/nodelim-groups.rs:15:49: 15:54 (#7), + span: $DIR/nodelim-groups.rs:15:49: 15:54 (#8), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:15:55: 15:56 (#7), + span: $DIR/nodelim-groups.rs:15:55: 15:56 (#8), }, Group { delimiter: None, @@ -136,10 +136,10 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ span: $DIR/nodelim-groups.rs:21:44: 21:46 (#0), }, ], - span: $DIR/nodelim-groups.rs:15:57: 15:62 (#7), + span: $DIR/nodelim-groups.rs:15:57: 15:62 (#8), }, ], - span: $DIR/nodelim-groups.rs:16:47: 16:51 (#8), + span: $DIR/nodelim-groups.rs:16:47: 16:51 (#9), }, Group { delimiter: Parenthesis, @@ -148,20 +148,20 @@ PRINT-BANG INPUT (DEBUG): TokenStream [ kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:53: 16:54 (#8), + span: $DIR/nodelim-groups.rs:16:53: 16:54 (#9), }, Punct { ch: '+', spacing: Alone, - span: $DIR/nodelim-groups.rs:16:55: 16:56 (#8), + span: $DIR/nodelim-groups.rs:16:55: 16:56 (#9), }, Literal { kind: Integer, symbol: "1", suffix: None, - span: $DIR/nodelim-groups.rs:16:57: 16:58 (#8), + span: $DIR/nodelim-groups.rs:16:57: 16:58 (#9), }, ], - span: $DIR/nodelim-groups.rs:16:52: 16:59 (#8), + span: $DIR/nodelim-groups.rs:16:52: 16:59 (#9), }, ] diff --git a/src/test/ui/proc-macro/resolved-located-at.stderr b/src/test/ui/proc-macro/resolved-located-at.stderr index e71e79514f..db1aa5d572 100644 --- a/src/test/ui/proc-macro/resolved-located-at.stderr +++ b/src/test/ui/proc-macro/resolved-located-at.stderr @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | fn main() { | - expected `()` because of default return type LL | resolve_located_at!(a b) - | ^ expected `()`, found struct `main::S` + | ^ expected `()`, found struct `S` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/proc-macro/span-preservation.stderr b/src/test/ui/proc-macro/span-preservation.stderr index a77e92022e..70e992a4f7 100644 --- a/src/test/ui/proc-macro/span-preservation.stderr +++ b/src/test/ui/proc-macro/span-preservation.stderr @@ -26,11 +26,11 @@ error[E0308]: mismatched types LL | let x = Foo { a: 10isize }; | ^^^^^^^ expected `usize`, found `isize` -error[E0560]: struct `c::Foo` has no field named `b` +error[E0560]: struct `Foo` has no field named `b` --> $DIR/span-preservation.rs:34:26 | LL | let y = Foo { a: 10, b: 10isize }; - | ^ `c::Foo` does not have this field + | ^ `Foo` does not have this field | = note: available fields are: `a` diff --git a/src/test/ui/proc-macro/trailing-plus.rs b/src/test/ui/proc-macro/trailing-plus.rs new file mode 100644 index 0000000000..4f61de47d8 --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.rs @@ -0,0 +1,14 @@ +// check-pass +// aux-build:test-macros.rs +// compile-flags: -Z span-debug + +#![no_std] // Don't load unnecessary hygiene information from std +extern crate std; + +extern crate test_macros; + +#[test_macros::print_attr] +fn foo() where T: Copy + { +} + +fn main() {} diff --git a/src/test/ui/proc-macro/trailing-plus.stdout b/src/test/ui/proc-macro/trailing-plus.stdout new file mode 100644 index 0000000000..d60f400af2 --- /dev/null +++ b/src/test/ui/proc-macro/trailing-plus.stdout @@ -0,0 +1,57 @@ +PRINT-ATTR INPUT (DISPLAY): fn foo < T > () where T : Copy + { } +PRINT-ATTR INPUT (DEBUG): TokenStream [ + Ident { + ident: "fn", + span: $DIR/trailing-plus.rs:11:1: 11:3 (#0), + }, + Ident { + ident: "foo", + span: $DIR/trailing-plus.rs:11:4: 11:7 (#0), + }, + Punct { + ch: '<', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:7: 11:8 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:8: 11:9 (#0), + }, + Punct { + ch: '>', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:9: 11:10 (#0), + }, + Group { + delimiter: Parenthesis, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:10: 11:12 (#0), + }, + Ident { + ident: "where", + span: $DIR/trailing-plus.rs:11:13: 11:18 (#0), + }, + Ident { + ident: "T", + span: $DIR/trailing-plus.rs:11:19: 11:20 (#0), + }, + Punct { + ch: ':', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:20: 11:21 (#0), + }, + Ident { + ident: "Copy", + span: $DIR/trailing-plus.rs:11:22: 11:26 (#0), + }, + Punct { + ch: '+', + spacing: Alone, + span: $DIR/trailing-plus.rs:11:27: 11:28 (#0), + }, + Group { + delimiter: Brace, + stream: TokenStream [], + span: $DIR/trailing-plus.rs:11:29: 12:2 (#0), + }, +] diff --git a/src/test/ui/proc-macro/unsafe-foreign-mod.rs b/src/test/ui/proc-macro/unsafe-foreign-mod.rs new file mode 100644 index 0000000000..7bdfa93c21 --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-foreign-mod.rs @@ -0,0 +1,14 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_foreign_mod] +unsafe extern { + type T; +} + +#[macro_only_syntax::expect_unsafe_extern_cpp_mod] +unsafe extern "C++" {} + +fn main() {} diff --git a/src/test/ui/proc-macro/unsafe-mod.rs b/src/test/ui/proc-macro/unsafe-mod.rs new file mode 100644 index 0000000000..8ff6e352c5 --- /dev/null +++ b/src/test/ui/proc-macro/unsafe-mod.rs @@ -0,0 +1,13 @@ +// run-pass +// aux-build:macro-only-syntax.rs + +#![feature(proc_macro_hygiene)] + +extern crate macro_only_syntax; + +#[macro_only_syntax::expect_unsafe_mod] +unsafe mod m { + pub unsafe mod inner; +} + +fn main() {} diff --git a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs index 45dfb63992..d089359503 100644 --- a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs +++ b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.rs @@ -5,7 +5,7 @@ pub(crate) struct Snail; mod sea { pub(super) struct Turtle; - //~^ NOTE `sea::Turtle` declared as restricted + //~^ NOTE `Turtle` declared as restricted } struct Tortoise; @@ -19,7 +19,7 @@ pub type Helix_pomatia = Shell; //~^ ERROR crate-visible type `Snail` in public interface //~| NOTE can't leak crate-visible type pub type Dermochelys_coriacea = Shell; -//~^ ERROR restricted type `sea::Turtle` in public interface +//~^ ERROR restricted type `Turtle` in public interface //~| NOTE can't leak restricted type pub type Testudo_graeca = Shell; //~^ ERROR private type `Tortoise` in public interface diff --git a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr index ae9a33e944..41b6b09554 100644 --- a/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr +++ b/src/test/ui/pub/issue-33174-restricted-type-in-public-interface.stderr @@ -7,11 +7,11 @@ LL | pub(crate) struct Snail; LL | pub type Helix_pomatia = Shell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak crate-visible type -error[E0446]: restricted type `sea::Turtle` in public interface +error[E0446]: restricted type `Turtle` in public interface --> $DIR/issue-33174-restricted-type-in-public-interface.rs:21:1 | LL | pub(super) struct Turtle; - | ---------- `sea::Turtle` declared as restricted + | ---------- `Turtle` declared as restricted ... LL | pub type Dermochelys_coriacea = Shell; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ can't leak restricted type diff --git a/src/test/ui/qualified/qualified-path-params.rs b/src/test/ui/qualified/qualified-path-params.rs index 65549d909d..e8a95a4601 100644 --- a/src/test/ui/qualified/qualified-path-params.rs +++ b/src/test/ui/qualified/qualified-path-params.rs @@ -18,7 +18,8 @@ impl S { fn main() { match 10 { ::A::f:: => {} - //~^ ERROR expected unit struct, unit variant or constant, found associated function - 0 ..= ::A::f:: => {} //~ ERROR only char and numeric types are allowed in range + //~^ ERROR expected unit struct, unit variant or constant, found associated function + 0 ..= ::A::f:: => {} + //~^ ERROR only `char` and numeric types are allowed in range } } diff --git a/src/test/ui/qualified/qualified-path-params.stderr b/src/test/ui/qualified/qualified-path-params.stderr index 4214e2503c..2be2deeb75 100644 --- a/src/test/ui/qualified/qualified-path-params.stderr +++ b/src/test/ui/qualified/qualified-path-params.stderr @@ -4,7 +4,7 @@ error[E0533]: expected unit struct, unit variant or constant, found associated f LL | ::A::f:: => {} | ^^^^^^^^^^^^^^^^^^^^^ -error[E0029]: only char and numeric types are allowed in range patterns +error[E0029]: only `char` and numeric types are allowed in range patterns --> $DIR/qualified-path-params.rs:22:15 | LL | 0 ..= ::A::f:: => {} diff --git a/src/test/ui/question-mark-type-infer.stderr b/src/test/ui/question-mark-type-infer.stderr index 64d8f68563..f530534ec8 100644 --- a/src/test/ui/question-mark-type-infer.stderr +++ b/src/test/ui/question-mark-type-infer.stderr @@ -4,7 +4,7 @@ error[E0284]: type annotations needed LL | l.iter().map(f).collect()? | ^^^^^^^ cannot infer type | - = note: cannot satisfy `<_ as std::ops::Try>::Ok == _` + = note: cannot satisfy `<_ as Try>::Ok == _` help: consider specifying the type argument in the method call | LL | l.iter().map(f).collect::()? diff --git a/src/test/ui/range/issue-54505-no-literals.stderr b/src/test/ui/range/issue-54505-no-literals.stderr index c49093343c..065e16a822 100644 --- a/src/test/ui/range/issue-54505-no-literals.stderr +++ b/src/test/ui/range/issue-54505-no-literals.stderr @@ -28,11 +28,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeFrom { start: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&std::ops::RangeFrom { start: 1 }` | = note: expected reference `&_` - found struct `std::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:31:16 @@ -40,11 +40,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeFrom { start: 1 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&::std::ops::RangeFrom { start: 1 }` | = note: expected reference `&_` - found struct `std::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:36:16 @@ -52,11 +52,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeFull {}); | ^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&std::ops::RangeFull {}` | = note: expected reference `&_` - found struct `std::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:41:16 @@ -64,11 +64,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeFull {}); | ^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&::std::ops::RangeFull {}` | = note: expected reference `&_` - found struct `std::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:46:16 @@ -76,11 +76,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeInclusive::new(0, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&std::ops::RangeInclusive::new(0, 1)` | = note: expected reference `&_` - found struct `std::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:51:16 @@ -88,11 +88,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeInclusive::new(0, 1)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&::std::ops::RangeInclusive::new(0, 1)` | = note: expected reference `&_` - found struct `std::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:56:16 @@ -100,11 +100,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeTo { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&std::ops::RangeTo { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:61:16 @@ -112,11 +112,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeTo { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&::std::ops::RangeTo { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:66:16 @@ -124,11 +124,11 @@ error[E0308]: mismatched types LL | take_range(std::ops::RangeToInclusive { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&std::ops::RangeToInclusive { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505-no-literals.rs:71:16 @@ -136,11 +136,11 @@ error[E0308]: mismatched types LL | take_range(::std::ops::RangeToInclusive { end: 5 }); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | | - | expected reference, found struct `std::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&::std::ops::RangeToInclusive { end: 5 }` | = note: expected reference `&_` - found struct `std::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error: aborting due to 12 previous errors diff --git a/src/test/ui/range/issue-54505-no-std.rs b/src/test/ui/range/issue-54505-no-std.rs index c6a3cc346f..f5d5823e46 100644 --- a/src/test/ui/range/issue-54505-no-std.rs +++ b/src/test/ui/range/issue-54505-no-std.rs @@ -14,6 +14,9 @@ use core::ops::RangeBounds; #[cfg(any(not(target_arch = "wasm32"), target_os = "emscripten"))] #[lang = "eh_personality"] extern fn eh_personality() {} +#[cfg(target_os = "emscripten")] +#[lang = "eh_catch_typeinfo"] +static EH_CATCH_TYPEINFO: u8 = 0; // take a reference to any built-in range diff --git a/src/test/ui/range/issue-54505-no-std.stderr b/src/test/ui/range/issue-54505-no-std.stderr index 9093406113..73507f4836 100644 --- a/src/test/ui/range/issue-54505-no-std.stderr +++ b/src/test/ui/range/issue-54505-no-std.stderr @@ -1,76 +1,76 @@ error: `#[panic_handler]` function required, but not found error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:24:16 + --> $DIR/issue-54505-no-std.rs:27:16 | LL | take_range(0..1); | ^^^^ | | - | expected reference, found struct `core::ops::Range` + | expected reference, found struct `Range` | help: consider borrowing here: `&(0..1)` | = note: expected reference `&_` - found struct `core::ops::Range<{integer}>` + found struct `Range<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:29:16 + --> $DIR/issue-54505-no-std.rs:32:16 | LL | take_range(1..); | ^^^ | | - | expected reference, found struct `core::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&(1..)` | = note: expected reference `&_` - found struct `core::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:34:16 + --> $DIR/issue-54505-no-std.rs:37:16 | LL | take_range(..); | ^^ | | - | expected reference, found struct `core::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&(..)` | = note: expected reference `&_` - found struct `core::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:39:16 + --> $DIR/issue-54505-no-std.rs:42:16 | LL | take_range(0..=1); | ^^^^^ | | - | expected reference, found struct `core::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&(0..=1)` | = note: expected reference `&_` - found struct `core::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:44:16 + --> $DIR/issue-54505-no-std.rs:47:16 | LL | take_range(..5); | ^^^ | | - | expected reference, found struct `core::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&(..5)` | = note: expected reference `&_` - found struct `core::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types - --> $DIR/issue-54505-no-std.rs:49:16 + --> $DIR/issue-54505-no-std.rs:52:16 | LL | take_range(..=42); | ^^^^^ | | - | expected reference, found struct `core::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&(..=42)` | = note: expected reference `&_` - found struct `core::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error: aborting due to 7 previous errors diff --git a/src/test/ui/range/issue-54505.stderr b/src/test/ui/range/issue-54505.stderr index 9949ff8567..121af29834 100644 --- a/src/test/ui/range/issue-54505.stderr +++ b/src/test/ui/range/issue-54505.stderr @@ -16,11 +16,11 @@ error[E0308]: mismatched types LL | take_range(1..); | ^^^ | | - | expected reference, found struct `std::ops::RangeFrom` + | expected reference, found struct `RangeFrom` | help: consider borrowing here: `&(1..)` | = note: expected reference `&_` - found struct `std::ops::RangeFrom<{integer}>` + found struct `RangeFrom<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505.rs:24:16 @@ -28,11 +28,11 @@ error[E0308]: mismatched types LL | take_range(..); | ^^ | | - | expected reference, found struct `std::ops::RangeFull` + | expected reference, found struct `RangeFull` | help: consider borrowing here: `&(..)` | = note: expected reference `&_` - found struct `std::ops::RangeFull` + found struct `RangeFull` error[E0308]: mismatched types --> $DIR/issue-54505.rs:29:16 @@ -40,11 +40,11 @@ error[E0308]: mismatched types LL | take_range(0..=1); | ^^^^^ | | - | expected reference, found struct `std::ops::RangeInclusive` + | expected reference, found struct `RangeInclusive` | help: consider borrowing here: `&(0..=1)` | = note: expected reference `&_` - found struct `std::ops::RangeInclusive<{integer}>` + found struct `RangeInclusive<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505.rs:34:16 @@ -52,11 +52,11 @@ error[E0308]: mismatched types LL | take_range(..5); | ^^^ | | - | expected reference, found struct `std::ops::RangeTo` + | expected reference, found struct `RangeTo` | help: consider borrowing here: `&(..5)` | = note: expected reference `&_` - found struct `std::ops::RangeTo<{integer}>` + found struct `RangeTo<{integer}>` error[E0308]: mismatched types --> $DIR/issue-54505.rs:39:16 @@ -64,11 +64,11 @@ error[E0308]: mismatched types LL | take_range(..=42); | ^^^^^ | | - | expected reference, found struct `std::ops::RangeToInclusive` + | expected reference, found struct `RangeToInclusive` | help: consider borrowing here: `&(..=42)` | = note: expected reference `&_` - found struct `std::ops::RangeToInclusive<{integer}>` + found struct `RangeToInclusive<{integer}>` error: aborting due to 6 previous errors diff --git a/src/test/ui/range/range-1.rs b/src/test/ui/range/range-1.rs index f13787b1d6..192426fe22 100644 --- a/src/test/ui/range/range-1.rs +++ b/src/test/ui/range/range-1.rs @@ -7,7 +7,7 @@ pub fn main() { // Bool => does not implement iterator. for i in false..true {} - //~^ ERROR `bool: std::iter::Step` is not satisfied + //~^ ERROR `bool: Step` is not satisfied // Unsized type. let arr: &[_] = &[1, 2, 3]; diff --git a/src/test/ui/range/range-1.stderr b/src/test/ui/range/range-1.stderr index 11cb72fa2b..a7557320fa 100644 --- a/src/test/ui/range/range-1.stderr +++ b/src/test/ui/range/range-1.stderr @@ -4,13 +4,13 @@ error[E0308]: mismatched types LL | let _ = 0u32..10i32; | ^^^^^ expected `u32`, found `i32` -error[E0277]: the trait bound `bool: std::iter::Step` is not satisfied +error[E0277]: the trait bound `bool: Step` is not satisfied --> $DIR/range-1.rs:9:14 | LL | for i in false..true {} - | ^^^^^^^^^^^ the trait `std::iter::Step` is not implemented for `bool` + | ^^^^^^^^^^^ the trait `Step` is not implemented for `bool` | - = note: required because of the requirements on the impl of `std::iter::Iterator` for `std::ops::Range` + = note: required because of the requirements on the impl of `Iterator` for `std::ops::Range` error[E0277]: the size for values of type `[{integer}]` cannot be known at compilation time --> $DIR/range-1.rs:14:17 @@ -21,9 +21,9 @@ LL | let range = *arr..; ::: $SRC_DIR/core/src/ops/range.rs:LL:COL | LL | pub struct RangeFrom { - | --- required by this bound in `std::ops::RangeFrom` + | --- required by this bound in `RangeFrom` | - = help: the trait `std::marker::Sized` is not implemented for `[{integer}]` + = help: the trait `Sized` is not implemented for `[{integer}]` error: aborting due to 3 previous errors diff --git a/src/test/ui/range/range_traits-1.stderr b/src/test/ui/range/range_traits-1.stderr index 0e1da3d3f7..165fcd415c 100644 --- a/src/test/ui/range/range_traits-1.stderr +++ b/src/test/ui/range/range_traits-1.stderr @@ -4,7 +4,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -14,7 +14,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -24,7 +24,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -34,7 +34,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -44,7 +44,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -54,7 +54,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -64,7 +64,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -74,7 +74,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -84,7 +84,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -94,7 +94,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -104,7 +104,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -114,7 +114,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -124,7 +124,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -134,7 +134,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -144,7 +144,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -154,7 +154,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -164,7 +164,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -174,7 +174,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -184,7 +184,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -194,7 +194,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -204,7 +204,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -214,7 +214,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -224,7 +224,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -234,7 +234,7 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -244,7 +244,7 @@ error[E0277]: can't compare `std::ops::Range` with `std::ops::Range, | ^^^^^^^^^^^^^^^ no implementation for `std::ops::Range < std::ops::Range` and `std::ops::Range > std::ops::Range` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::Range` + = help: the trait `PartialOrd` is not implemented for `std::ops::Range` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -254,7 +254,7 @@ error[E0277]: can't compare `std::ops::RangeTo` with `std::ops::RangeTo, | ^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeTo < std::ops::RangeTo` and `std::ops::RangeTo > std::ops::RangeTo` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeTo` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeTo` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -264,7 +264,7 @@ error[E0277]: can't compare `std::ops::RangeFrom` with `std::ops::RangeFr LL | c: RangeFrom, | ^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeFrom < std::ops::RangeFrom` and `std::ops::RangeFrom > std::ops::RangeFrom` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFrom` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFrom` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -274,7 +274,7 @@ error[E0277]: can't compare `std::ops::RangeFull` with `std::ops::RangeFull` LL | d: RangeFull, | ^^^^^^^^^^^^ no implementation for `std::ops::RangeFull < std::ops::RangeFull` and `std::ops::RangeFull > std::ops::RangeFull` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeFull` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeFull` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -284,7 +284,7 @@ error[E0277]: can't compare `std::ops::RangeInclusive` with `std::ops::Ra LL | e: RangeInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeInclusive < std::ops::RangeInclusive` and `std::ops::RangeInclusive > std::ops::RangeInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -294,60 +294,60 @@ error[E0277]: can't compare `std::ops::RangeToInclusive` with `std::ops:: LL | f: RangeToInclusive, | ^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `std::ops::RangeToInclusive < std::ops::RangeToInclusive` and `std::ops::RangeToInclusive > std::ops::RangeToInclusive` | - = help: the trait `std::cmp::PartialOrd` is not implemented for `std::ops::RangeToInclusive` + = help: the trait `PartialOrd` is not implemented for `std::ops::RangeToInclusive` = note: required by `std::cmp::PartialOrd::partial_cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::Range: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::Range: Ord` is not satisfied --> $DIR/range_traits-1.rs:5:5 | LL | a: Range, - | ^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::Range` + | ^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::Range` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeTo: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeTo: Ord` is not satisfied --> $DIR/range_traits-1.rs:12:5 | LL | b: RangeTo, - | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeTo` + | ^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeTo` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeFrom: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeFrom: Ord` is not satisfied --> $DIR/range_traits-1.rs:19:5 | LL | c: RangeFrom, - | ^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeFrom` + | ^^^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeFrom` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeFull: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeFull: Ord` is not satisfied --> $DIR/range_traits-1.rs:26:5 | LL | d: RangeFull, - | ^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeFull` + | ^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeFull` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeInclusive: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeInclusive: Ord` is not satisfied --> $DIR/range_traits-1.rs:33:5 | LL | e: RangeInclusive, - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeInclusive` + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeInclusive` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) -error[E0277]: the trait bound `std::ops::RangeToInclusive: std::cmp::Ord` is not satisfied +error[E0277]: the trait bound `std::ops::RangeToInclusive: Ord` is not satisfied --> $DIR/range_traits-1.rs:40:5 | LL | f: RangeToInclusive, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::cmp::Ord` is not implemented for `std::ops::RangeToInclusive` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Ord` is not implemented for `std::ops::RangeToInclusive` | = note: required by `std::cmp::Ord::cmp` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/realloc-16687.rs b/src/test/ui/realloc-16687.rs index bdcd47a726..2e07fdcbe8 100644 --- a/src/test/ui/realloc-16687.rs +++ b/src/test/ui/realloc-16687.rs @@ -48,7 +48,7 @@ unsafe fn test_triangle() -> bool { println!("allocate({:?}) = {:?}", layout, ptr); } - ptr.as_non_null_ptr().as_ptr() + ptr.as_mut_ptr() } unsafe fn deallocate(ptr: *mut u8, layout: Layout) { @@ -65,23 +65,17 @@ unsafe fn test_triangle() -> bool { } let memory = if new.size() > old.size() { - Global.grow( - NonNull::new_unchecked(ptr), - old, - new.size(), - ) + Global.grow(NonNull::new_unchecked(ptr), old, new) } else { - Global.shrink(NonNull::new_unchecked(ptr), old, new.size()) + Global.shrink(NonNull::new_unchecked(ptr), old, new) }; - let ptr = memory.unwrap_or_else(|_| { - handle_alloc_error(Layout::from_size_align_unchecked(new.size(), old.align())) - }); + let ptr = memory.unwrap_or_else(|_| handle_alloc_error(new)); if PRINT { println!("reallocate({:?}, old={:?}, new={:?}) = {:?}", ptr, old, new, ptr); } - ptr.as_non_null_ptr().as_ptr() + ptr.as_mut_ptr() } fn idx_to_size(i: usize) -> usize { diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs index d9996b80ac..658def0ad5 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.rs @@ -2,7 +2,9 @@ // no free regions or type parameters. // Codegen however, has to error for the infinitely many `drop_in_place` // functions it has been asked to create. + // build-fail +// normalize-stderr-test: ".nll/" -> "/" struct S { t: T, diff --git a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr index 72547fe79f..5bf381607c 100644 --- a/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr +++ b/src/test/ui/recursion/issue-38591-non-regular-dropck-recursion.stderr @@ -1,26 +1,15 @@ -error: reached the recursion limit while instantiating `std::intrinsics::drop_in_place::...)))))))))))))))))))))))))))))>))` +error: reached the recursion limit while instantiating `drop_in_place::))` --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | |_^ +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: `std::intrinsics::drop_in_place` defined here +note: `drop_in_place` defined here --> $SRC_DIR/core/src/ptr/mod.rs:LL:COL | -LL | / pub unsafe fn drop_in_place(to_drop: *mut T) { -LL | | // Code here does not matter - this is replaced by the -LL | | // real drop glue by the compiler. -LL | | -LL | | // SAFETY: see comment above -LL | | unsafe { drop_in_place(to_drop) } -LL | | } - | |_^ +LL | pub unsafe fn drop_in_place(to_drop: *mut T) { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/issue-38591-non-regular-dropck-recursion/issue-38591-non-regular-dropck-recursion.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/recursion/recursion.rs b/src/test/ui/recursion/recursion.rs index 373cc17d0e..b3ba0ec3a2 100644 --- a/src/test/ui/recursion/recursion.rs +++ b/src/test/ui/recursion/recursion.rs @@ -1,5 +1,6 @@ // build-fail // compile-flags:-C overflow-checks=off +// normalize-stderr-test: ".nll/" -> "/" enum Nil {NilValue} struct Cons {head:isize, tail:T} diff --git a/src/test/ui/recursion/recursion.stderr b/src/test/ui/recursion/recursion.stderr index 085bf82ef8..d2844d0e6d 100644 --- a/src/test/ui/recursion/recursion.stderr +++ b/src/test/ui/recursion/recursion.stderr @@ -1,14 +1,15 @@ error: reached the recursion limit while instantiating `test::>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>` - --> $DIR/recursion.rs:17:11 + --> $DIR/recursion.rs:18:11 | LL | _ => {test (n-1, i+1, Cons {head:2*i+1, tail:first}, Cons{head:i*i, tail:second})} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: `test` defined here - --> $DIR/recursion.rs:15:1 + --> $DIR/recursion.rs:16:1 | LL | fn test (n:isize, i:isize, first:T, second:T) ->isize { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: the full type name has been written to '$TEST_BUILD_DIR/recursion/recursion/recursion.long-type.txt' error: aborting due to previous error diff --git a/src/test/ui/recursion/recursive-requirements.stderr b/src/test/ui/recursion/recursive-requirements.stderr index 0237675aee..6c0be0f7f8 100644 --- a/src/test/ui/recursion/recursive-requirements.stderr +++ b/src/test/ui/recursion/recursive-requirements.stderr @@ -7,7 +7,7 @@ LL | struct AssertSync(PhantomData); LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Bar` cannot be shared between threads safely | - = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `*const Bar` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Bar` = note: required because it appears within the type `Foo` error[E0277]: `*const Foo` cannot be shared between threads safely @@ -19,9 +19,9 @@ LL | struct AssertSync(PhantomData); LL | let _: AssertSync = unimplemented!(); | ^^^^^^^^^^^^^^^ `*const Foo` cannot be shared between threads safely | - = help: within `Foo`, the trait `std::marker::Sync` is not implemented for `*const Foo` + = help: within `Foo`, the trait `Sync` is not implemented for `*const Foo` = note: required because it appears within the type `Bar` - = note: required because it appears within the type `std::marker::PhantomData` + = note: required because it appears within the type `PhantomData` = note: required because it appears within the type `Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/recursion/recursive-static-definition.rs b/src/test/ui/recursion/recursive-static-definition.rs index e816ce4e0c..f59ef7316d 100644 --- a/src/test/ui/recursion/recursive-static-definition.rs +++ b/src/test/ui/recursion/recursive-static-definition.rs @@ -1,4 +1,4 @@ pub static FOO: u32 = FOO; -//~^ ERROR cycle detected when const-evaluating `FOO` +//~^ ERROR cycle detected when const-evaluating + checking `FOO` fn main() {} diff --git a/src/test/ui/recursion/recursive-static-definition.stderr b/src/test/ui/recursion/recursive-static-definition.stderr index 093606e100..ee73b026a0 100644 --- a/src/test/ui/recursion/recursive-static-definition.stderr +++ b/src/test/ui/recursion/recursive-static-definition.stderr @@ -1,20 +1,16 @@ -error[E0391]: cycle detected when const-evaluating `FOO` +error[E0391]: cycle detected when const-evaluating + checking `FOO` --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `FOO`... - --> $DIR/recursive-static-definition.rs:1:1 - | -LL | pub static FOO: u32 = FOO; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `FOO`, completing the cycle -note: cycle used when const-evaluating + checking `FOO` +note: ...which requires const-evaluating + checking `FOO`... --> $DIR/recursive-static-definition.rs:1:1 | LL | pub static FOO: u32 = FOO; | ^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `FOO`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to previous error diff --git a/src/test/ui/ref-suggestion.rs b/src/test/ui/ref-suggestion.rs index 49d199cd9e..346d118f0f 100644 --- a/src/test/ui/ref-suggestion.rs +++ b/src/test/ui/ref-suggestion.rs @@ -13,5 +13,5 @@ fn main() { (Some(y), ()) => {}, _ => {}, } - x; //~ ERROR use of moved value + x; //~ ERROR use of partially moved value } diff --git a/src/test/ui/ref-suggestion.stderr b/src/test/ui/ref-suggestion.stderr index 97d2c174d9..332dbb79cf 100644 --- a/src/test/ui/ref-suggestion.stderr +++ b/src/test/ui/ref-suggestion.stderr @@ -2,7 +2,7 @@ error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:4:5 | LL | let x = vec![1]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let y = x; | - value moved here LL | x; @@ -12,22 +12,22 @@ error[E0382]: use of moved value: `x` --> $DIR/ref-suggestion.rs:8:5 | LL | let x = vec![1]; - | - move occurs because `x` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Vec`, which does not implement the `Copy` trait LL | let mut y = x; | - value moved here LL | x; | ^ value used here after move -error[E0382]: use of moved value: `x` +error[E0382]: use of partially moved value: `x` --> $DIR/ref-suggestion.rs:16:5 | LL | (Some(y), ()) => {}, - | - value moved here + | - value partially moved here ... LL | x; | ^ value used here after partial move | - = note: move occurs because value has type `std::vec::Vec`, which does not implement the `Copy` trait + = note: partial move occurs because value has type `Vec`, which does not implement the `Copy` trait help: borrow this field in the pattern to avoid moving `x.0.0` | LL | (Some(ref y), ()) => {}, diff --git a/src/test/ui/regions/issue-78262.default.stderr b/src/test/ui/regions/issue-78262.default.stderr new file mode 100644 index 0000000000..e97b8eca94 --- /dev/null +++ b/src/test/ui/regions/issue-78262.default.stderr @@ -0,0 +1,18 @@ +error[E0308]: mismatched types + --> $DIR/issue-78262.rs:12:28 + | +LL | let f = |x: &dyn TT| x.func(); + | ^^^^ lifetime mismatch + | + = note: expected reference `&(dyn TT + 'static)` + found reference `&dyn TT` +note: the anonymous lifetime #1 defined on the body at 12:13... + --> $DIR/issue-78262.rs:12:13 + | +LL | let f = |x: &dyn TT| x.func(); + | ^^^^^^^^^^^^^^^^^^^^^ + = 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 --git a/src/test/ui/regions/issue-78262.nll.stderr b/src/test/ui/regions/issue-78262.nll.stderr new file mode 100644 index 0000000000..4607dbad42 --- /dev/null +++ b/src/test/ui/regions/issue-78262.nll.stderr @@ -0,0 +1,10 @@ +error[E0521]: borrowed data escapes outside of closure + --> $DIR/issue-78262.rs:12:26 + | +LL | let f = |x: &dyn TT| x.func(); + | - ^^^^^^^^ `x` escapes the closure body here + | | + | `x` is a reference that is only valid in the closure body + +error: aborting due to previous error + diff --git a/src/test/ui/regions/issue-78262.rs b/src/test/ui/regions/issue-78262.rs new file mode 100644 index 0000000000..0bdb0abac3 --- /dev/null +++ b/src/test/ui/regions/issue-78262.rs @@ -0,0 +1,14 @@ +// revisions: nll default +// ignore-compare-mode-nll +//[nll]compile-flags: -Z borrowck=mir + +trait TT {} + +impl dyn TT { + fn func(&self) {} +} + +fn main() { + let f = |x: &dyn TT| x.func(); //[default]~ ERROR: mismatched types + //[nll]~^ ERROR: borrowed data escapes outside of closure +} diff --git a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr index 22586b5de9..1fff85e766 100644 --- a/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr +++ b/src/test/ui/regions/region-bounds-on-objects-and-type-parameters.stderr @@ -27,7 +27,7 @@ error[E0392]: parameter `'c` is never used LL | struct Foo<'a,'b,'c> { | ^^ unused parameter | - = help: consider removing `'c`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'c`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 3 previous errors diff --git a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr index 63fea1f416..3607d6a722 100644 --- a/src/test/ui/regions/region-object-lifetime-in-coercion.stderr +++ b/src/test/ui/regions/region-object-lifetime-in-coercion.stderr @@ -74,8 +74,8 @@ note: ...so that the expression is assignable | LL | Box::new(v) | ^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn Foo + 'b)>` - found `std::boxed::Box` + = note: expected `Box<(dyn Foo + 'b)>` + found `Box` error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr index c72d6483c2..930bf608ac 100644 --- a/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr +++ b/src/test/ui/regions/regions-bounded-by-trait-requiring-static.stderr @@ -22,7 +22,7 @@ LL | assert_send::<&'a [isize]>(); | = note: type must satisfy the static lifetime -error[E0477]: the type `std::boxed::Box<&'a isize>` does not fulfill the required lifetime +error[E0477]: the type `Box<&'a isize>` does not fulfill the required lifetime --> $DIR/regions-bounded-by-trait-requiring-static.rs:44:5 | LL | assert_send::>(); diff --git a/src/test/ui/regions/regions-close-associated-type-into-object.stderr b/src/test/ui/regions/regions-close-associated-type-into-object.stderr index 9303e0f8e6..536a1b5e35 100644 --- a/src/test/ui/regions/regions-close-associated-type-into-object.stderr +++ b/src/test/ui/regions/regions-close-associated-type-into-object.stderr @@ -14,7 +14,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'static`... - = note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds + = note: ...so that the type `Box<::Item>` will meet its required lifetime bounds error[E0309]: the associated type `::Item` may not live long enough --> $DIR/regions-close-associated-type-into-object.rs:28:5 @@ -32,7 +32,7 @@ LL | Box::new(item) | ^^^^^^^^^^^^^^ | = help: consider adding an explicit lifetime bound `::Item: 'a`... - = note: ...so that the type `std::boxed::Box<::Item>` will meet its required lifetime bounds + = note: ...so that the type `Box<::Item>` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-close-object-into-object-2.stderr b/src/test/ui/regions/regions-close-object-into-object-2.stderr index aab7ce993a..da995a9631 100644 --- a/src/test/ui/regions/regions-close-object-into-object-2.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-2.stderr @@ -12,8 +12,8 @@ LL | fn g<'a, T: 'static>(v: Box + 'a>) -> Box { | ^^ help: alternatively, add an explicit `'static` bound to this reference | -LL | fn g<'a, T: 'static>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn g<'a, T: 'static>(v: Box<(dyn A + 'static)>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-object-into-object-4.stderr b/src/test/ui/regions/regions-close-object-into-object-4.stderr index 90f807a41c..7dc880849a 100644 --- a/src/test/ui/regions/regions-close-object-into-object-4.stderr +++ b/src/test/ui/regions/regions-close-object-into-object-4.stderr @@ -12,8 +12,8 @@ LL | fn i<'a, T, U>(v: Box+'a>) -> Box { | ^^ help: alternatively, add an explicit `'static` bound to this reference | -LL | fn i<'a, T, U>(v: std::boxed::Box<(dyn A + 'static)>) -> Box { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn i<'a, T, U>(v: Box<(dyn A + 'static)>) -> Box { + | ^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr index 2070ce257b..0cce89215d 100644 --- a/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr +++ b/src/test/ui/regions/regions-close-over-type-parameter-multiple.stderr @@ -24,8 +24,8 @@ note: ...so that the expression is assignable | LL | box v as Box | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: expected `std::boxed::Box<(dyn SomeTrait + 'c)>` - found `std::boxed::Box` + = note: expected `Box<(dyn SomeTrait + 'c)>` + found `Box` error: aborting due to previous error diff --git a/src/test/ui/regions/regions-close-param-into-object.stderr b/src/test/ui/regions/regions-close-param-into-object.stderr index 705d21078e..5c355bbb73 100644 --- a/src/test/ui/regions/regions-close-param-into-object.stderr +++ b/src/test/ui/regions/regions-close-param-into-object.stderr @@ -14,7 +14,7 @@ LL | fn p2(v: Box) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'static` ... LL | Box::new(v) - | ^^^^^^^^^^^ ...so that the type `std::boxed::Box` will meet its required lifetime bounds + | ^^^^^^^^^^^ ...so that the type `Box` will meet its required lifetime bounds error[E0309]: the parameter type `T` may not live long enough --> $DIR/regions-close-param-into-object.rs:18:5 @@ -32,7 +32,7 @@ LL | fn p4<'a,T>(v: Box) -> Box | - help: consider adding an explicit lifetime bound...: `T: 'a` ... LL | Box::new(v) - | ^^^^^^^^^^^ ...so that the type `std::boxed::Box` will meet its required lifetime bounds + | ^^^^^^^^^^^ ...so that the type `Box` will meet its required lifetime bounds error: aborting due to 4 previous errors diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr index a86e6ccdc5..afabdc1de1 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr +++ b/src/test/ui/regions/regions-infer-paramd-indirect.nll.stderr @@ -5,7 +5,7 @@ LL | impl<'a> SetF<'a> for C<'a> { | -- lifetime `'a` defined here ... LL | fn set_f_bad(&mut self, b: Box) { - | - has type `std::boxed::Box>` + | - has type `Box>` LL | self.f = b; | ^^^^^^ assignment requires that `'1` must outlive `'a` diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.rs b/src/test/ui/regions/regions-infer-paramd-indirect.rs index beb88e81bc..3b18bbf1df 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.rs +++ b/src/test/ui/regions/regions-infer-paramd-indirect.rs @@ -21,8 +21,8 @@ impl<'a> SetF<'a> for C<'a> { fn set_f_bad(&mut self, b: Box) { self.f = b; //~^ ERROR mismatched types - //~| expected struct `std::boxed::Box>` - //~| found struct `std::boxed::Box>` + //~| expected struct `Box>` + //~| found struct `Box>` //~| lifetime mismatch } } diff --git a/src/test/ui/regions/regions-infer-paramd-indirect.stderr b/src/test/ui/regions/regions-infer-paramd-indirect.stderr index 3e196cf8f1..620b25c9e0 100644 --- a/src/test/ui/regions/regions-infer-paramd-indirect.stderr +++ b/src/test/ui/regions/regions-infer-paramd-indirect.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | self.f = b; | ^ lifetime mismatch | - = note: expected struct `std::boxed::Box>` - found struct `std::boxed::Box>` + = note: expected struct `Box>` + found struct `Box>` note: the anonymous lifetime #2 defined on the method body at 21:5... --> $DIR/regions-infer-paramd-indirect.rs:21:5 | diff --git a/src/test/ui/reify-intrinsic.stderr b/src/test/ui/reify-intrinsic.stderr index c4eee0f466..675447f972 100644 --- a/src/test/ui/reify-intrinsic.stderr +++ b/src/test/ui/reify-intrinsic.stderr @@ -7,13 +7,13 @@ LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::tr | expected due to this | = note: expected fn pointer `unsafe extern "rust-intrinsic" fn(isize) -> usize` - found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` + found fn item `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` help: use parentheses to call this function | LL | let _: unsafe extern "rust-intrinsic" fn(isize) -> usize = std::mem::transmute(...); | ^^^^^ -error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {std::intrinsics::transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid +error[E0606]: casting `unsafe extern "rust-intrinsic" fn(_) -> _ {transmute::<_, _>}` as `unsafe extern "rust-intrinsic" fn(isize) -> usize` is invalid --> $DIR/reify-intrinsic.rs:11:13 | LL | let _ = std::mem::transmute as unsafe extern "rust-intrinsic" fn(isize) -> usize; diff --git a/src/test/ui/repeat-to-run-dtor-twice.rs b/src/test/ui/repeat-to-run-dtor-twice.rs index d857178166..0cd8eceefc 100644 --- a/src/test/ui/repeat-to-run-dtor-twice.rs +++ b/src/test/ui/repeat-to-run-dtor-twice.rs @@ -15,5 +15,5 @@ impl Drop for Foo { fn main() { let a = Foo { x: 3 }; let _ = [ a; 5 ]; - //~^ ERROR the trait bound `Foo: std::marker::Copy` is not satisfied [E0277] + //~^ ERROR the trait bound `Foo: Copy` is not satisfied [E0277] } diff --git a/src/test/ui/repeat-to-run-dtor-twice.stderr b/src/test/ui/repeat-to-run-dtor-twice.stderr index 5434f6cef5..f07bbe3b9f 100644 --- a/src/test/ui/repeat-to-run-dtor-twice.stderr +++ b/src/test/ui/repeat-to-run-dtor-twice.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Foo: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Foo: Copy` is not satisfied --> $DIR/repeat-to-run-dtor-twice.rs:17:13 | LL | let _ = [ a; 5 ]; - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `Foo` + | ^^^^^^^^ the trait `Copy` is not implemented for `Foo` | = note: the `Copy` trait is required because the repeated element will be copied diff --git a/src/test/ui/repeat_count.rs b/src/test/ui/repeat_count.rs index 7e30491f0b..96abff4ab4 100644 --- a/src/test/ui/repeat_count.rs +++ b/src/test/ui/repeat_count.rs @@ -30,5 +30,5 @@ fn main() { } let g = [0; G { g: () }]; //~^ ERROR mismatched types - //~| expected `usize`, found struct `main::G` + //~| expected `usize`, found struct `G` } diff --git a/src/test/ui/repeat_count.stderr b/src/test/ui/repeat_count.stderr index 2eab3ebc76..5fcda348ab 100644 --- a/src/test/ui/repeat_count.stderr +++ b/src/test/ui/repeat_count.stderr @@ -32,7 +32,7 @@ error[E0308]: mismatched types --> $DIR/repeat_count.rs:31:17 | LL | let g = [0; G { g: () }]; - | ^^^^^^^^^^^ expected `usize`, found struct `main::G` + | ^^^^^^^^^^^ expected `usize`, found struct `G` error[E0308]: mismatched types --> $DIR/repeat_count.rs:19:17 diff --git a/src/test/ui/resolve/issue-5035-2.stderr b/src/test/ui/resolve/issue-5035-2.stderr index 4ed93ad327..5078ffbec7 100644 --- a/src/test/ui/resolve/issue-5035-2.stderr +++ b/src/test/ui/resolve/issue-5035-2.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `(dyn I + 'static)` cannot be known at LL | fn foo(_x: K) {} | ^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn I + 'static)` + = help: the trait `Sized` is not implemented for `(dyn I + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/resolve/issue-54379.stderr b/src/test/ui/resolve/issue-54379.stderr index 2a6b54572d..750727273e 100644 --- a/src/test/ui/resolve/issue-54379.stderr +++ b/src/test/ui/resolve/issue-54379.stderr @@ -8,10 +8,12 @@ LL | MyStruct { .., Some(_) } => {}, | `..` must be at the end and cannot have a trailing comma error: expected `,` - --> $DIR/issue-54379.rs:9:24 + --> $DIR/issue-54379.rs:9:28 | LL | MyStruct { .., Some(_) } => {}, - | ^^^^ + | -------- ^ + | | + | while parsing the fields for this pattern error: aborting due to 2 previous errors diff --git a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr index a324d04d39..9b59e41501 100644 --- a/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr +++ b/src/test/ui/resolve/issue-70736-async-fn-no-body-def-collector.stderr @@ -57,7 +57,7 @@ LL | async fn associated(); | expected `()`, found opaque type | = note: expected fn pointer `fn()` - found fn pointer `fn() -> impl std::future::Future` + found fn pointer `fn() -> impl Future` error: aborting due to 6 previous errors diff --git a/src/test/ui/resolve/name-clash-nullary.stderr b/src/test/ui/resolve/name-clash-nullary.stderr index 2de0b6a496..76c4b5914c 100644 --- a/src/test/ui/resolve/name-clash-nullary.stderr +++ b/src/test/ui/resolve/name-clash-nullary.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | let None: isize = 42; | ^^^^ ----- expected due to this | | - | expected `isize`, found enum `std::option::Option` + | expected `isize`, found enum `Option` | = note: expected type `isize` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/resolve/privacy-enum-ctor.stderr b/src/test/ui/resolve/privacy-enum-ctor.stderr index f1ed7aaa86..32eff15119 100644 --- a/src/test/ui/resolve/privacy-enum-ctor.stderr +++ b/src/test/ui/resolve/privacy-enum-ctor.stderr @@ -260,15 +260,15 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:27:20 | LL | Fn(u8), - | ------ fn(u8) -> m::n::Z {m::n::Z::Fn} defined here + | ------ fn(u8) -> Z {Z::Fn} defined here ... LL | let _: Z = Z::Fn; - | - ^^^^^ expected enum `m::n::Z`, found fn item + | - ^^^^^ expected enum `Z`, found fn item | | | expected due to this | - = note: expected enum `m::n::Z` - found fn item `fn(u8) -> m::n::Z {m::n::Z::Fn}` + = note: expected enum `Z` + found fn item `fn(u8) -> Z {Z::Fn}` help: use parentheses to instantiate this tuple variant | LL | let _: Z = Z::Fn(_); @@ -294,15 +294,15 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:43:16 | LL | Fn(u8), - | ------ fn(u8) -> m::E {m::E::Fn} defined here + | ------ fn(u8) -> E {E::Fn} defined here ... LL | let _: E = m::E::Fn; - | - ^^^^^^^^ expected enum `m::E`, found fn item + | - ^^^^^^^^ expected enum `E`, found fn item | | | expected due to this | - = note: expected enum `m::E` - found fn item `fn(u8) -> m::E {m::E::Fn}` + = note: expected enum `E` + found fn item `fn(u8) -> E {E::Fn}` help: use parentheses to instantiate this tuple variant | LL | let _: E = m::E::Fn(_); @@ -328,15 +328,15 @@ error[E0308]: mismatched types --> $DIR/privacy-enum-ctor.rs:51:16 | LL | Fn(u8), - | ------ fn(u8) -> m::E {m::E::Fn} defined here + | ------ fn(u8) -> E {E::Fn} defined here ... LL | let _: E = E::Fn; - | - ^^^^^ expected enum `m::E`, found fn item + | - ^^^^^ expected enum `E`, found fn item | | | expected due to this | - = note: expected enum `m::E` - found fn item `fn(u8) -> m::E {m::E::Fn}` + = note: expected enum `E` + found fn item `fn(u8) -> E {E::Fn}` help: use parentheses to instantiate this tuple variant | LL | let _: E = E::Fn(_); diff --git a/src/test/ui/resolve/use_suggestion.stderr b/src/test/ui/resolve/use_suggestion.stderr index 72dda94072..4fff179b1f 100644 --- a/src/test/ui/resolve/use_suggestion.stderr +++ b/src/test/ui/resolve/use_suggestion.stderr @@ -1,10 +1,10 @@ -error[E0433]: failed to resolve: use of undeclared type or module `GooMap` +error[E0433]: failed to resolve: use of undeclared type `GooMap` --> $DIR/use_suggestion.rs:3:14 | LL | let x2 = GooMap::new(); - | ^^^^^^ use of undeclared type or module `GooMap` + | ^^^^^^ use of undeclared type `GooMap` -error[E0433]: failed to resolve: use of undeclared type or module `HashMap` +error[E0433]: failed to resolve: use of undeclared type `HashMap` --> $DIR/use_suggestion.rs:2:14 | LL | let x1 = HashMap::new(); diff --git a/src/test/ui/retslot-cast.stderr b/src/test/ui/retslot-cast.stderr index cdef304cdc..9b5f11ce66 100644 --- a/src/test/ui/retslot-cast.stderr +++ b/src/test/ui/retslot-cast.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/retslot-cast.rs:13:5 | LL | inner(x) - | ^^^^^^^^ expected trait `std::iter::Iterator`, found trait `std::iter::Iterator + std::marker::Send` + | ^^^^^^^^ expected trait `Iterator`, found trait `Iterator + Send` | - = note: expected enum `std::option::Option<&dyn std::iter::Iterator>` - found enum `std::option::Option<&dyn std::iter::Iterator + std::marker::Send>` + = note: expected enum `Option<&dyn Iterator>` + found enum `Option<&dyn Iterator + Send>` error: aborting due to previous error diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr index 7becd01324..6c3d1caf80 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-across-arms.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-across-arms.rs:5:36 | LL | VecWrapper::A(v) if { drop(v); false } => 1, - | ^ move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | ^ move occurs because `v` has type `Vec`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr index b93e721906..d1204bc260 100644 --- a/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr +++ b/src/test/ui/rfc-0107-bind-by-move-pattern-guards/rfc-reject-double-move-in-first-arm.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `v` in pattern guard --> $DIR/rfc-reject-double-move-in-first-arm.rs:6:30 | LL | A { a: v } if { drop(v); true } => v, - | ^ move occurs because `v` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `v` has type `Box`, which does not implement the `Copy` trait | = note: variables bound in patterns cannot be moved from until after the end of the pattern guard diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs index 8f65144b14..3b60cbc578 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.rs @@ -1,3 +1,3 @@ // Tests that an `impl Trait` that is not `impl Termination` will not work. fn main() -> impl Copy { } -//~^ ERROR `main` has invalid return type `impl std::marker::Copy` +//~^ ERROR `main` has invalid return type `impl Copy` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr index 8a718183a8..5ee6d127e8 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-impl-trait.stderr @@ -1,8 +1,8 @@ -error[E0277]: `main` has invalid return type `impl std::marker::Copy` +error[E0277]: `main` has invalid return type `impl Copy` --> $DIR/termination-trait-impl-trait.rs:2:14 | LL | fn main() -> impl Copy { } - | ^^^^^^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^^^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs index 09bd1c8492..10f7d2215c 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.rs @@ -1,6 +1,6 @@ fn main() -> i32 { //~^ ERROR `main` has invalid return type `i32` -//~| NOTE `main` can only return types that implement `std::process::Termination` +//~| NOTE `main` can only return types that implement `Termination` //~| HELP consider using `()`, or a `Result` 0 } diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr index e88e3d884e..53779d365f 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-i32.stderr @@ -2,7 +2,7 @@ error[E0277]: `main` has invalid return type `i32` --> $DIR/termination-trait-main-i32.rs:1:14 | LL | fn main() -> i32 { - | ^^^ `main` can only return types that implement `std::process::Termination` + | ^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr index 31b90340d7..bc8fd92ce5 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-main-wrong-type.stderr @@ -2,7 +2,7 @@ error[E0277]: `main` has invalid return type `char` --> $DIR/termination-trait-main-wrong-type.rs:1:14 | LL | fn main() -> char { - | ^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr index 72a58a0417..cb329548d8 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-not-satisfied.stderr @@ -2,7 +2,7 @@ error[E0277]: `main` has invalid return type `ReturnType` --> $DIR/termination-trait-not-satisfied.rs:3:14 | LL | fn main() -> ReturnType { - | ^^^^^^^^^^ `main` can only return types that implement `std::process::Termination` + | ^^^^^^^^^^ `main` can only return types that implement `Termination` | = help: consider using `()`, or a `Result` diff --git a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr index d28232515f..d015b72c5c 100644 --- a/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr +++ b/src/test/ui/rfc-1937-termination-trait/termination-trait-test-wrong-type.stderr @@ -1,17 +1,17 @@ -error[E0277]: `main` has invalid return type `std::result::Result` +error[E0277]: `main` has invalid return type `std::result::Result` --> $DIR/termination-trait-test-wrong-type.rs:6:1 | LL | / fn can_parse_zero_as_f32() -> Result { LL | | "0".parse() LL | | } - | |_^ `main` can only return types that implement `std::process::Termination` + | |_^ `main` can only return types that implement `Termination` | ::: $SRC_DIR/test/src/lib.rs:LL:COL | LL | pub fn assert_test_result(result: T) { - | ----------- required by this bound in `test::assert_test_result` + | ----------- required by this bound in `assert_test_result` | - = help: the trait `std::process::Termination` is not implemented for `std::result::Result` + = help: the trait `Termination` is not implemented for `std::result::Result` = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.rs b/src/test/ui/rfc-2008-non-exhaustive/enum.rs index 802f20b4be..73e0b98296 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.rs @@ -4,7 +4,7 @@ extern crate enums; use enums::{EmptyNonExhaustiveEnum, NonExhaustiveEnum}; fn empty(x: EmptyNonExhaustiveEnum) { - match x {} //~ ERROR type `enums::EmptyNonExhaustiveEnum` is non-empty + match x {} //~ ERROR type `EmptyNonExhaustiveEnum` is non-empty match x { _ => {}, // ok } diff --git a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr index 28e450336f..1d1c43c9e8 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/enum.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/enum.stderr @@ -1,11 +1,11 @@ -error[E0004]: non-exhaustive patterns: type `enums::EmptyNonExhaustiveEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `EmptyNonExhaustiveEnum` is non-empty --> $DIR/enum.rs:7:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `enums::EmptyNonExhaustiveEnum` + = note: the matched value is of type `EmptyNonExhaustiveEnum` error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/enum.rs:16:11 @@ -14,7 +14,7 @@ LL | match enum_unit { | ^^^^^^^^^ 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 `enums::NonExhaustiveEnum` + = note: the matched value is of type `NonExhaustiveEnum` error[E0004]: non-exhaustive patterns: `_` not covered --> $DIR/enum.rs:23:11 @@ -23,7 +23,7 @@ LL | match enum_unit {}; | ^^^^^^^^^ 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 `enums::NonExhaustiveEnum` + = note: the matched value is of type `NonExhaustiveEnum` error: aborting due to 3 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs index 900b9333f7..5feb9c98e9 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs +++ b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.rs @@ -10,15 +10,15 @@ use types::{NonExhaustiveEnum, NormalStruct, UnitStruct, TupleStruct, NonExhaust extern { pub fn non_exhaustive_enum(_: NonExhaustiveEnum); - //~^ ERROR `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe + //~^ ERROR `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe pub fn non_exhaustive_normal_struct(_: NormalStruct); - //~^ ERROR `extern` block uses type `types::NormalStruct`, which is not FFI-safe + //~^ ERROR `extern` block uses type `NormalStruct`, which is not FFI-safe pub fn non_exhaustive_unit_struct(_: UnitStruct); - //~^ ERROR `extern` block uses type `types::UnitStruct`, which is not FFI-safe + //~^ ERROR `extern` block uses type `UnitStruct`, which is not FFI-safe pub fn non_exhaustive_tuple_struct(_: TupleStruct); - //~^ ERROR `extern` block uses type `types::TupleStruct`, which is not FFI-safe + //~^ ERROR `extern` block uses type `TupleStruct`, which is not FFI-safe pub fn non_exhaustive_variant(_: NonExhaustiveVariants); - //~^ ERROR `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe + //~^ ERROR `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe } fn main() { } diff --git a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr index 4956226712..8a18ebc16f 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/improper_ctypes/extern_crate_improper.stderr @@ -1,4 +1,4 @@ -error: `extern` block uses type `types::NonExhaustiveEnum`, which is not FFI-safe +error: `extern` block uses type `NonExhaustiveEnum`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:12:35 | LL | pub fn non_exhaustive_enum(_: NonExhaustiveEnum); @@ -11,7 +11,7 @@ LL | #![deny(improper_ctypes)] | ^^^^^^^^^^^^^^^ = note: this enum is non-exhaustive -error: `extern` block uses type `types::NormalStruct`, which is not FFI-safe +error: `extern` block uses type `NormalStruct`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:14:44 | LL | pub fn non_exhaustive_normal_struct(_: NormalStruct); @@ -19,7 +19,7 @@ LL | pub fn non_exhaustive_normal_struct(_: NormalStruct); | = note: this struct is non-exhaustive -error: `extern` block uses type `types::UnitStruct`, which is not FFI-safe +error: `extern` block uses type `UnitStruct`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:16:42 | LL | pub fn non_exhaustive_unit_struct(_: UnitStruct); @@ -27,7 +27,7 @@ LL | pub fn non_exhaustive_unit_struct(_: UnitStruct); | = note: this struct is non-exhaustive -error: `extern` block uses type `types::TupleStruct`, which is not FFI-safe +error: `extern` block uses type `TupleStruct`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:18:43 | LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct); @@ -35,7 +35,7 @@ LL | pub fn non_exhaustive_tuple_struct(_: TupleStruct); | = note: this struct is non-exhaustive -error: `extern` block uses type `types::NonExhaustiveVariants`, which is not FFI-safe +error: `extern` block uses type `NonExhaustiveVariants`, which is not FFI-safe --> $DIR/extern_crate_improper.rs:20:38 | LL | pub fn non_exhaustive_variant(_: NonExhaustiveVariants); diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr index d2d319f50c..f8ed156b57 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/coercions.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_empty_enum_to_anything(x: UninhabitedEnum) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found enum `uninhabited::UninhabitedEnum` + | ^ expected struct `A`, found enum `UninhabitedEnum` error[E0308]: mismatched types --> $DIR/coercions.rs:27:5 @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_empty_tuple_struct_to_anything(x: UninhabitedTupleStruct) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found struct `uninhabited::UninhabitedTupleStruct` + | ^ expected struct `A`, found struct `UninhabitedTupleStruct` error[E0308]: mismatched types --> $DIR/coercions.rs:31:5 @@ -20,7 +20,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_empty_struct_to_anything(x: UninhabitedStruct) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found struct `uninhabited::UninhabitedStruct` + | ^ expected struct `A`, found struct `UninhabitedStruct` error[E0308]: mismatched types --> $DIR/coercions.rs:35:5 @@ -28,7 +28,7 @@ error[E0308]: mismatched types LL | fn cannot_coerce_enum_with_empty_variants_to_anything(x: UninhabitedVariants) -> A { | - expected `A` because of return type LL | x - | ^ expected struct `A`, found enum `uninhabited::UninhabitedVariants` + | ^ expected struct `A`, found enum `UninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr index bd136333b7..c461302a36 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match.stderr @@ -1,38 +1,38 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty --> $DIR/indirect_match.rs:19:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedEnum` + = note: the matched value is of type `IndirectUninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty --> $DIR/indirect_match.rs:23:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedStruct` + = note: the matched value is of type `IndirectUninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty --> $DIR/indirect_match.rs:27:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedTupleStruct` + = note: the matched value is of type `IndirectUninhabitedTupleStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty --> $DIR/indirect_match.rs:33:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedVariants` + = note: the matched value is of type `IndirectUninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr index 5211b57726..c397158c02 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/indirect_match_with_exhaustive_patterns.stderr @@ -1,38 +1,38 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedEnum` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:23:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedEnum` + = note: the matched value is of type `IndirectUninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedStruct` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:27:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedStruct` + = note: the matched value is of type `IndirectUninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedTupleStruct` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:31:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedTupleStruct` + = note: the matched value is of type `IndirectUninhabitedTupleStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::IndirectUninhabitedVariants` is non-empty +error[E0004]: non-exhaustive patterns: type `IndirectUninhabitedVariants` is non-empty --> $DIR/indirect_match_with_exhaustive_patterns.rs:37:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::IndirectUninhabitedVariants` + = note: the matched value is of type `IndirectUninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr index 961b3e5673..1f981ba82d 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match.stderr @@ -1,29 +1,29 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty --> $DIR/match.rs:19:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedEnum` + = note: the matched value is of type `UninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty --> $DIR/match.rs:23:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedStruct` + = note: the matched value is of type `UninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty --> $DIR/match.rs:27:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedTupleStruct` + = note: the matched value is of type `UninhabitedTupleStruct` error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered --> $DIR/match.rs:31:11 @@ -39,7 +39,7 @@ LL | #[non_exhaustive] Struct { x: ! } | ------ 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 `uninhabited::UninhabitedVariants` + = note: the matched value is of type `UninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr index c489edeb69..0ff1c01cbd 100644 --- a/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr +++ b/src/test/ui/rfc-2008-non-exhaustive/uninhabited/match_with_exhaustive_patterns.stderr @@ -1,29 +1,29 @@ -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedEnum` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedEnum` is non-empty --> $DIR/match_with_exhaustive_patterns.rs:22:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedEnum` + = note: the matched value is of type `UninhabitedEnum` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedStruct` is non-empty --> $DIR/match_with_exhaustive_patterns.rs:26:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedStruct` + = note: the matched value is of type `UninhabitedStruct` -error[E0004]: non-exhaustive patterns: type `uninhabited::UninhabitedTupleStruct` is non-empty +error[E0004]: non-exhaustive patterns: type `UninhabitedTupleStruct` is non-empty --> $DIR/match_with_exhaustive_patterns.rs:30:11 | LL | match x {} | ^ | = help: ensure that all possible cases are being handled, possibly by adding wildcards or more match arms - = note: the matched value is of type `uninhabited::UninhabitedTupleStruct` + = note: the matched value is of type `UninhabitedTupleStruct` error[E0004]: non-exhaustive patterns: `Tuple(_)` and `Struct { .. }` not covered --> $DIR/match_with_exhaustive_patterns.rs:34:11 @@ -39,7 +39,7 @@ LL | #[non_exhaustive] Struct { x: ! } | ------ 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 `uninhabited::UninhabitedVariants` + = note: the matched value is of type `UninhabitedVariants` error: aborting due to 4 previous errors diff --git a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr index cf8ca57714..0291a52633 100644 --- a/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr +++ b/src/test/ui/rfc-2091-track-caller/caller-location-fnptr-rt-ctfe-equiv.stderr @@ -1,10 +1,27 @@ warning: skipping const checks | +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:9 + | +LL | let ptr: fn() -> L = attributed; + | ^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5 + | +LL | ptr() + | ^^^ +help: skipping check for `const_fn_fn_ptr_basics` feature + --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:20:26 + | +LL | let ptr: fn() -> L = attributed; + | ^^^^^^^^^^ help: skipping check that does not even have a feature gate --> $DIR/caller-location-fnptr-rt-ctfe-equiv.rs:21:5 | LL | ptr() | ^^^^^ -warning: 1 warning emitted +error: `-Zunleash-the-miri-inside-of-you` may not be used to circumvent feature gates, except when testing error paths in the CTFE engine + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/rfc-2093-infer-outlives/projection.stderr b/src/test/ui/rfc-2093-infer-outlives/projection.stderr index 3746bab4d5..840676e796 100644 --- a/src/test/ui/rfc-2093-infer-outlives/projection.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/projection.stderr @@ -6,7 +6,7 @@ LL | | bar: &'a T::Item LL | | } | |_^ | - = note: ::Item: 'a + = note: ::Item: 'a error: aborting due to previous error diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr index 6efc1176d0..dfa44008ad 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region-rev.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a rev_variant_struct_region::Foo<'b>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<'b>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-region-rev.rs:17:9 | LL | type Out = &'a Foo<'b>; diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr index 06e5f24dec..3561379138 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-region.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a variant_struct_region::Foo<'b>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<'b>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-region.rs:17:9 | LL | type Out = &'a Foo<'b>; diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr index d02f7b7962..207686defa 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type-rev.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<&'b i32>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-type-rev.rs:17:9 | LL | type Out = &'a Foo<&'b i32>; diff --git a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr index 40c70f5324..c1c4e78f78 100644 --- a/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr +++ b/src/test/ui/rfc-2093-infer-outlives/regions-outlives-nominal-type-type.stderr @@ -1,4 +1,4 @@ -error[E0491]: in type `&'a variant_struct_type::Foo<&'b i32>`, reference has a longer lifetime than the data it references +error[E0491]: in type `&'a Foo<&'b i32>`, reference has a longer lifetime than the data it references --> $DIR/regions-outlives-nominal-type-type.rs:17:9 | LL | type Out = &'a Foo<&'b i32>; diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr index 64b920e9aa..8189157217 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-1.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `xcrate` --> $DIR/non-existent-1.rs:3:5 | LL | use xcrate::S; - | ^^^^^^ use of undeclared type or module `xcrate` + | ^^^^^^ use of undeclared crate or module `xcrate` error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr index bfce180789..bd6778cf3d 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/non-existent-3.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `ycrate` --> $DIR/non-existent-3.rs:3:5 | LL | use ycrate; - | ^^^^^^ no `ycrate` external crate + | ^^^^^^ no external crate `ycrate` error: aborting due to previous error diff --git a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr index 6d2b4508a0..a66330ccc4 100644 --- a/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr +++ b/src/test/ui/rfc-2126-extern-absolute-paths/not-allowed.stderr @@ -2,7 +2,7 @@ error[E0432]: unresolved import `alloc` --> $DIR/not-allowed.rs:5:5 | LL | use alloc; - | ^^^^^ no `alloc` external crate + | ^^^^^ no external crate `alloc` error: aborting due to previous error diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs index bdde484c25..f2fb62d76f 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.rs @@ -3,5 +3,5 @@ struct NotDebug; fn main() { - let _: NotDebug = dbg!(NotDebug); //~ ERROR `NotDebug` doesn't implement `std::fmt::Debug` + let _: NotDebug = dbg!(NotDebug); //~ ERROR `NotDebug` doesn't implement `Debug` } diff --git a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr index 799a05bf7e..6d150b84dd 100644 --- a/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr +++ b/src/test/ui/rfc-2361-dbg-macro/dbg-macro-requires-debug.stderr @@ -1,12 +1,12 @@ -error[E0277]: `NotDebug` doesn't implement `std::fmt::Debug` +error[E0277]: `NotDebug` doesn't implement `Debug` --> $DIR/dbg-macro-requires-debug.rs:6:23 | LL | let _: NotDebug = dbg!(NotDebug); | ^^^^^^^^^^^^^^ `NotDebug` cannot be formatted using `{:?}` | - = help: the trait `std::fmt::Debug` is not implemented for `NotDebug` - = note: add `#[derive(Debug)]` or manually implement `std::fmt::Debug` - = note: required because of the requirements on the impl of `std::fmt::Debug` for `&NotDebug` + = help: the trait `Debug` is not implemented for `NotDebug` + = note: add `#[derive(Debug)]` or manually implement `Debug` + = note: required because of the requirements on the impl of `Debug` for `&NotDebug` = note: required by `std::fmt::Debug::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs index 71af704c69..25c7fe760d 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.rs @@ -40,11 +40,11 @@ fn nested_within_if_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { if let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } if (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` //~| ERROR the `?` operator can only be used in a function that returns `Result` if true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here @@ -104,11 +104,11 @@ fn nested_within_while_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { while let 0 = 0? {} - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } while (let 0 = 0)? {} //~ ERROR `let` expressions are not supported here - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` //~| ERROR the `?` operator can only be used in a function that returns `Result` while true || let 0 = 0 {} //~ ERROR `let` expressions are not supported here @@ -177,12 +177,12 @@ fn outside_if_and_while_expr() { fn _check_try_binds_tighter() -> Result<(), ()> { let 0 = 0?; - //~^ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~^ ERROR the `?` operator can only be applied to values that implement `Try` Ok(()) } (let 0 = 0)?; //~ ERROR `let` expressions are not supported here //~^ ERROR the `?` operator can only be used in a function that returns `Result` - //~| ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + //~| ERROR the `?` operator can only be applied to values that implement `Try` true || let 0 = 0; //~ ERROR `let` expressions are not supported here (true || let 0 = 0); //~ ERROR `let` expressions are not supported here diff --git a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr index 7f343d1a85..d38a3aba46 100644 --- a/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr +++ b/src/test/ui/rfc-2497-if-let-chains/disallowed-positions.stderr @@ -537,16 +537,16 @@ error[E0600]: cannot apply unary operator `-` to type `bool` LL | if -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:46:8 | LL | if (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | - = help: the trait `std::ops::Try` is not implemented for `bool` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `bool` + = note: required by `into_result` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/disallowed-positions.rs:46:8 | LL | / fn nested_within_if_expr() { @@ -561,17 +561,19 @@ LL | | if let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:56:8 | LL | if x = let 0 = 0 {} - | ^^^^^^^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == let 0 = 0` + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if x == let 0 = 0 {} + | ^^ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:59:8 @@ -586,19 +588,19 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:61:8 | LL | if ..(let 0 = 0) {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeTo` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` | = note: expected type `bool` - found struct `std::ops::RangeTo` + found struct `RangeTo` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:63:8 | LL | if (let 0 = 0).. {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeFrom` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` | = note: expected type `bool` - found struct `std::ops::RangeFrom` + found struct `RangeFrom` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:67:12 @@ -693,14 +695,14 @@ LL | if let Range { start: true, end } = t..&&false {} = note: expected type `bool` found struct `std::ops::Range` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:42:20 | LL | if let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `into_result` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:96:11 @@ -723,16 +725,16 @@ error[E0600]: cannot apply unary operator `-` to type `bool` LL | while -let 0 = 0 {} | ^^^^^^^^^^ cannot apply unary operator `-` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:110:11 | LL | while (let 0 = 0)? {} | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | - = help: the trait `std::ops::Try` is not implemented for `bool` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `bool` + = note: required by `into_result` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/disallowed-positions.rs:110:11 | LL | / fn nested_within_while_expr() { @@ -747,17 +749,19 @@ LL | | while let true = let true = true {} LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:120:11 | LL | while x = let 0 = 0 {} - | ^^^^^^^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == let 0 = 0` + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | while x == let 0 = 0 {} + | ^^ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:123:11 @@ -772,19 +776,19 @@ error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:125:11 | LL | while ..(let 0 = 0) {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeTo` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeTo` | = note: expected type `bool` - found struct `std::ops::RangeTo` + found struct `RangeTo` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:127:11 | LL | while (let 0 = 0).. {} - | ^^^^^^^^^^^^^ expected `bool`, found struct `std::ops::RangeFrom` + | ^^^^^^^^^^^^^ expected `bool`, found struct `RangeFrom` | = note: expected type `bool` - found struct `std::ops::RangeFrom` + found struct `RangeFrom` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:131:15 @@ -879,14 +883,14 @@ LL | while let Range { start: true, end } = t..&&false {} = note: expected type `bool` found struct `std::ops::Range` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:106:23 | LL | while let 0 = 0? {} | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `into_result` error[E0614]: type `bool` cannot be dereferenced --> $DIR/disallowed-positions.rs:173:5 @@ -900,16 +904,16 @@ error[E0600]: cannot apply unary operator `-` to type `bool` LL | -let 0 = 0; | ^^^^^^^^^^ cannot apply unary operator `-` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:183:5 | LL | (let 0 = 0)?; | ^^^^^^^^^^^^ the `?` operator cannot be applied to type `bool` | - = help: the trait `std::ops::Try` is not implemented for `bool` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `bool` + = note: required by `into_result` -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/disallowed-positions.rs:183:5 | LL | / fn outside_if_and_while_expr() { @@ -924,8 +928,8 @@ LL | | LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error[E0308]: mismatched types --> $DIR/disallowed-positions.rs:198:10 @@ -947,14 +951,14 @@ LL | fn outside_if_and_while_expr() { LL | &let 0 = 0 | ^^^^^^^^^^ expected `()`, found `&bool` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/disallowed-positions.rs:179:17 | LL | let 0 = 0?; | ^^ the `?` operator cannot be applied to type `{integer}` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `into_result` error: aborting due to 103 previous errors; 2 warnings emitted diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr index b57472d959..2b4fa66ecf 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-and-non-const-impl.stderr @@ -5,7 +5,7 @@ LL | impl const std::ops::Add for i32 { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::ops::Add for i32; + - impl Add for i32; error[E0119]: conflicting implementations of trait `std::ops::Add` for type `Int`: --> $DIR/const-and-non-const-impl.rs:24:1 diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs index 3278f35bad..fc85e98ef5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.rs @@ -10,7 +10,7 @@ fn non_const() {} impl const T for S { fn foo() { non_const() } - //~^ ERROR can only call other `const fn` + //~^ ERROR calls in constant functions } fn main() {} diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr index b50dd03a86..c6c78c7d1e 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-check-fns-in-const-impl.stderr @@ -1,12 +1,9 @@ -error[E0723]: can only call other `const fn` within a `const fn`, but `non_const` is not stable as `const fn` +error[E0015]: calls in constant functions are limited to constant functions, tuple structs and tuple variants --> $DIR/const-check-fns-in-const-impl.rs:12:16 | LL | fn foo() { non_const() } | ^^^^^^^^^^^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable error: aborting due to previous error -For more information about this error, try `rustc --explain E0723`. +For more information about this error, try `rustc --explain E0015`. diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr index 3994bd97c3..58041454d5 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.gated.stderr @@ -1,5 +1,5 @@ error: fatal error triggered by #[rustc_error] - --> $DIR/feature-gate.rs:16:1 + --> $DIR/feature-gate.rs:17:1 | LL | fn main() {} | ^^^^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs index d600b53e44..3506237d1f 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.rs @@ -4,6 +4,7 @@ #![cfg_attr(gated, feature(const_trait_bound_opt_out))] #![allow(incomplete_features)] #![feature(rustc_attrs)] +#![feature(const_fn)] trait T { const CONST: i32; diff --git a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr index a1e1c3249a..8ae8b8868d 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/const-trait-bound-opt-out/feature-gate.stock.stderr @@ -1,5 +1,5 @@ error[E0658]: `?const` on trait bounds is experimental - --> $DIR/feature-gate.rs:12:29 + --> $DIR/feature-gate.rs:13:29 | LL | const fn get_assoc_const() -> i32 { ::CONST } | ^^^^^^ diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.rs b/src/test/ui/rfc-2632-const-trait-impl/stability.rs index 03a6fb5150..454fde34a2 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.rs +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.rs @@ -30,7 +30,7 @@ impl const std::ops::Add for Int { #[rustc_const_stable(feature = "rust1", since = "1.0.0")] pub const fn foo() -> Int { Int(1i32) + Int(2i32) - //~^ ERROR can only call other `const fn` within a `const fn` + //~^ ERROR not yet stable as a const fn } // ok diff --git a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr index e7002a1a04..54d7cfd5d7 100644 --- a/src/test/ui/rfc-2632-const-trait-impl/stability.stderr +++ b/src/test/ui/rfc-2632-const-trait-impl/stability.stderr @@ -6,18 +6,14 @@ LL | | LL | | Int(self.0 - rhs.0) LL | | } | |_____^ - | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable -error[E0723]: can only call other `const fn` within a `const fn`, but `::add` is not stable as `const fn` +error: `::add` is not yet stable as a const fn --> $DIR/stability.rs:32:5 | LL | Int(1i32) + Int(2i32) | ^^^^^^^^^^^^^^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = help: Const-stable functions can only call other const-stable functions error: aborting due to 2 previous errors diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs index b90a750cc1..c6d7166e74 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs index 1076b9f25d..cc7ea6cde8 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-direct-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs index a4b832d377..86db09cc08 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-embedded.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs index 47b70e2e9c..99c574d078 100644 --- a/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs +++ b/src/test/ui/rfc1445/allow-hide-behind-indirect-unsafe-ptr-param.rs @@ -3,6 +3,8 @@ // run-pass +#![warn(pointer_structural_match)] + struct NoDerive(i32); // This impl makes NoDerive irreflexive diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs index c663535e53..4a8a094937 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_INLINE { WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr index 9c7d1f3a18..c73a6cf132 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-embedded.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } | ^^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-embedded.rs:22:9 - | -LL | WRAP_DIRECT_INLINE => { panic!("WRAP_DIRECT_INLINE matched itself"); } - | ^^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs index 872bf5a63f..93022a23db 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.rs @@ -21,7 +21,6 @@ fn main() { match WRAP_DIRECT_PARAM { WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { println!("WRAP_DIRECT_PARAM did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr index 6f49a8a0c9..6fdf9db89b 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr +++ b/src/test/ui/rfc1445/cant-hide-behind-direct-struct-param.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be ann LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } | ^^^^^^^^^^^^^^^^^ -error: to use a constant of type `NoDerive` in a pattern, `NoDerive` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/cant-hide-behind-direct-struct-param.rs:22:9 - | -LL | WRAP_DIRECT_PARAM => { panic!("WRAP_DIRECT_PARAM matched itself"); } - | ^^^^^^^^^^^^^^^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs index f694781969..fe62774d22 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_INLINE { WRAP_DOUBLY_INDIRECT_INLINE => { panic!("WRAP_DOUBLY_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_INLINE correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs index 1c29d67b65..c3a30674ea 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-doubly-indirect-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_DOUBLY_INDIRECT_PARAM { WRAP_DOUBLY_INDIRECT_PARAM => { panic!("WRAP_DOUBLY_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_DOUBLY_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs index 1a41dbb55c..4d0e80d5af 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-embedded.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_INLINE { WRAP_INDIRECT_INLINE => { panic!("WRAP_INDIRECT_INLINE matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_INLINE did not match itself"); } } } diff --git a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs index 46032c4b0e..432f196ec8 100644 --- a/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs +++ b/src/test/ui/rfc1445/cant-hide-behind-indirect-struct-param.rs @@ -23,7 +23,7 @@ fn main() { match WRAP_INDIRECT_PARAM { WRAP_INDIRECT_PARAM => { panic!("WRAP_INDIRECT_PARAM matched itself"); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { println!("WRAP_INDIRECT_PARAM correctly did not match itself"); } } } diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs index 6ebb948d73..46d8ee3b6b 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.rs @@ -10,7 +10,7 @@ // Issue 62307 pointed out a case where the structural-match checking // was too shallow. -#![warn(indirect_structural_match)] +#![warn(indirect_structural_match, nontrivial_structural_match)] // run-pass #[derive(Debug)] @@ -30,14 +30,14 @@ fn main() { match RR_B0 { RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } match RR_B1 { RR_B1 => { println!("CLAIM RR1: {:?} matches {:?}", RR_B1, RR_B1); } //~^ WARN must be annotated with `#[derive(PartialEq, Eq)]` - //~| WARN will become a hard error in a future release + //~| WARN this was previously accepted _ => { } } } diff --git a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr index ae011dfcdb..a50093a5b1 100644 --- a/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/issue-62307-match-ref-ref-forbidden-without-eq.stderr @@ -7,7 +7,7 @@ LL | RR_B1 => { println!("CLAIM RR0: {:?} matches {:?}", RR_B1, RR_B0); note: the lint level is defined here --> $DIR/issue-62307-match-ref-ref-forbidden-without-eq.rs:13:9 | -LL | #![warn(indirect_structural_match)] +LL | #![warn(indirect_structural_match, nontrivial_structural_match)] | ^^^^^^^^^^^^^^^^^^^^^^^^^ = 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 #62411 diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs index b3c91cec58..567685950e 100644 --- a/src/test/ui/rfc1445/issue-63479-match-fnptr.rs +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.rs @@ -5,6 +5,8 @@ // cover the case this hit; I've since expanded it accordingly, but the // experience left me wary of leaving this regression test out.) +#![warn(pointer_structural_match)] + #[derive(Eq)] struct A { a: i64 @@ -31,6 +33,8 @@ fn main() { let s = B(my_fn); match s { B(TEST) => println!("matched"), + //~^ WARN pointers in patterns behave unpredictably + //~| WARN this was previously accepted by the compiler but is being phased out _ => panic!("didn't match") }; } diff --git a/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr new file mode 100644 index 0000000000..8cf87cc85a --- /dev/null +++ b/src/test/ui/rfc1445/issue-63479-match-fnptr.stderr @@ -0,0 +1,16 @@ +warning: function pointers and unsized pointers in patterns behave unpredictably and should not be relied upon. See https://github.com/rust-lang/rust/issues/70861 for details. + --> $DIR/issue-63479-match-fnptr.rs:35:7 + | +LL | B(TEST) => println!("matched"), + | ^^^^ + | +note: the lint level is defined here + --> $DIR/issue-63479-match-fnptr.rs:8:9 + | +LL | #![warn(pointer_structural_match)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ + = 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 #62411 + +warning: 1 warning emitted + diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-forbidden-without-eq.rs index 59141eac3e..1cca275206 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.rs @@ -12,7 +12,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } diff --git a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr index 1f26f0f11d..02fa239818 100644 --- a/src/test/ui/rfc1445/match-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-forbidden-without-eq.stderr @@ -5,7 +5,7 @@ LL | FOO => { } | ^^^ warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -14,14 +14,8 @@ LL | f32::INFINITY => { } = 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: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-forbidden-without-eq.rs:13:9 - | -LL | FOO => { } - | ^^^ - warning: floating-point types cannot be used in patterns - --> $DIR/match-forbidden-without-eq.rs:21:9 + --> $DIR/match-forbidden-without-eq.rs:20:9 | LL | f32::INFINITY => { } | ^^^^^^^^^^^^^ @@ -29,5 +23,5 @@ LL | f32::INFINITY => { } = 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 2 previous errors; 2 warnings emitted +error: aborting due to previous error; 2 warnings emitted diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs index 4112e8f451..151a475c91 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.rs @@ -15,6 +15,5 @@ fn main() { match [B(1)] { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` } } diff --git a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr index 7e354bf9ad..371f8a0aa1 100644 --- a/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr +++ b/src/test/ui/rfc1445/match-nonempty-array-forbidden-without-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `B` in a pattern, `B` must be annotated with `# LL | FOO => { } | ^^^ -error: to use a constant of type `B` in a pattern, `B` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-nonempty-array-forbidden-without-eq.rs:16:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs index 9530a1ffec..6b7d94603b 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.rs @@ -16,7 +16,6 @@ fn main() { match y { FOO => { } //~^ ERROR must be annotated with `#[derive(PartialEq, Eq)]` - //~| ERROR must be annotated with `#[derive(PartialEq, Eq)]` _ => { } } } diff --git a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr index 7ef082852b..4157cf6528 100644 --- a/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr +++ b/src/test/ui/rfc1445/match-requires-both-partialeq-and-eq.stderr @@ -4,11 +4,5 @@ error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated wit LL | FOO => { } | ^^^ -error: to use a constant of type `Foo` in a pattern, `Foo` must be annotated with `#[derive(PartialEq, Eq)]` - --> $DIR/match-requires-both-partialeq-and-eq.rs:17:9 - | -LL | FOO => { } - | ^^^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/rfc1623.nll.stderr b/src/test/ui/rfc1623.nll.stderr index 848d4fef1a..b5dd0c9d2a 100644 --- a/src/test/ui/rfc1623.nll.stderr +++ b/src/test/ui/rfc1623.nll.stderr @@ -1,4 +1,4 @@ -error[E0277]: `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely +error[E0277]: `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely --> $DIR/rfc1623.rs:21:1 | LL | / static SOME_STRUCT: &SomeStruct = &SomeStruct { @@ -7,10 +7,10 @@ LL | | bar: &Bar { bools: &[true, true] }, LL | | f: &id, LL | | LL | | }; - | |__^ `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely + | |__^ `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` cannot be shared between threads safely | - = help: within `&SomeStruct`, the trait `std::marker::Sync` is not implemented for `dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` - = note: required because it appears within the type `&dyn for<'a, 'b> std::ops::Fn(&'a Foo<'b>) -> &'a Foo<'b>` + = help: within `&SomeStruct`, the trait `Sync` is not implemented for `dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` + = note: required because it appears within the type `&dyn for<'a, 'b> Fn(&'a Foo<'b>) -> &'a Foo<'b>` = note: required because it appears within the type `SomeStruct` = note: required because it appears within the type `&SomeStruct` = note: shared static variables must have a type that implements `Sync` diff --git a/src/test/ui/rfc1623.stderr b/src/test/ui/rfc1623.stderr index 2efc58ac38..2835e47fa4 100644 --- a/src/test/ui/rfc1623.stderr +++ b/src/test/ui/rfc1623.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | f: &id, | ^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&'a Foo<'b>,)>` - found type `std::ops::FnOnce<(&Foo<'_>,)>` + = note: expected type `FnOnce<(&'a Foo<'b>,)>` + found type `FnOnce<(&Foo<'_>,)>` error: aborting due to previous error diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs index 5c838fd719..43bda49624 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.rs @@ -21,14 +21,14 @@ fn call_once(f: impl FnOnce()) { } fn main() { - call(foo); //~ ERROR expected a `std::ops::Fn<()>` closure, found `fn() {foo}` - call_mut(foo); //~ ERROR expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` - call_once(foo); //~ ERROR expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` + call(foo); //~ ERROR expected a `Fn<()>` closure, found `fn() {foo}` + call_mut(foo); //~ ERROR expected a `FnMut<()>` closure, found `fn() {foo}` + call_once(foo); //~ ERROR expected a `FnOnce<()>` closure, found `fn() {foo}` call(foo_unsafe); - //~^ ERROR expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` call_mut(foo_unsafe); - //~^ ERROR expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` call_once(foo_unsafe); - //~^ ERROR expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` + //~^ ERROR expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` } diff --git a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr index f9b4eed049..4ed86b34a3 100644 --- a/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr +++ b/src/test/ui/rfcs/rfc-2396-target_feature-11/fn-traits.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<()>` closure, found `fn() {foo}` +error[E0277]: expected a `Fn<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:24:10 | LL | fn call(f: impl Fn()) { @@ -7,11 +7,11 @@ LL | fn call(f: impl Fn()) { LL | call(foo); | ^^^ expected an `Fn<()>` closure, found `fn() {foo}` | - = help: the trait `std::ops::Fn<()>` is not implemented for `fn() {foo}` + = help: the trait `Fn<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnMut<()>` closure, found `fn() {foo}` +error[E0277]: expected a `FnMut<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:25:14 | LL | fn call_mut(f: impl FnMut()) { @@ -20,11 +20,11 @@ LL | fn call_mut(f: impl FnMut()) { LL | call_mut(foo); | ^^^ expected an `FnMut<()>` closure, found `fn() {foo}` | - = help: the trait `std::ops::FnMut<()>` is not implemented for `fn() {foo}` + = help: the trait `FnMut<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `fn() {foo}` +error[E0277]: expected a `FnOnce<()>` closure, found `fn() {foo}` --> $DIR/fn-traits.rs:26:15 | LL | fn call_once(f: impl FnOnce()) { @@ -33,11 +33,11 @@ LL | fn call_once(f: impl FnOnce()) { LL | call_once(foo); | ^^^ expected an `FnOnce<()>` closure, found `fn() {foo}` | - = help: the trait `std::ops::FnOnce<()>` is not implemented for `fn() {foo}` + = help: the trait `FnOnce<()>` is not implemented for `fn() {foo}` = note: wrap the `fn() {foo}` in a closure with no arguments: `|| { /* code */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::Fn<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:28:10 | LL | fn call(f: impl Fn()) { @@ -46,11 +46,11 @@ LL | fn call(f: impl Fn()) { LL | call(foo_unsafe); | ^^^^^^^^^^ expected an `Fn<()>` closure, found `unsafe fn() {foo_unsafe}` | - = help: the trait `std::ops::Fn<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = 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 */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:30:14 | LL | fn call_mut(f: impl FnMut()) { @@ -59,11 +59,11 @@ LL | fn call_mut(f: impl FnMut()) { LL | call_mut(foo_unsafe); | ^^^^^^^^^^ expected an `FnMut<()>` closure, found `unsafe fn() {foo_unsafe}` | - = help: the trait `std::ops::FnMut<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = 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 */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits -error[E0277]: expected a `std::ops::FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` +error[E0277]: expected a `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` --> $DIR/fn-traits.rs:32:15 | LL | fn call_once(f: impl FnOnce()) { @@ -72,7 +72,7 @@ LL | fn call_once(f: impl FnOnce()) { LL | call_once(foo_unsafe); | ^^^^^^^^^^ expected an `FnOnce<()>` closure, found `unsafe fn() {foo_unsafe}` | - = help: the trait `std::ops::FnOnce<()>` is not implemented for `unsafe fn() {foo_unsafe}` + = 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 */ }` = note: `#[target_feature]` functions do not implement the `Fn` traits diff --git a/src/test/ui/rmeta_meta_main.rs b/src/test/ui/rmeta_meta_main.rs index 52cd0c2f53..839f350d74 100644 --- a/src/test/ui/rmeta_meta_main.rs +++ b/src/test/ui/rmeta_meta_main.rs @@ -10,5 +10,5 @@ extern crate rmeta_meta; use rmeta_meta::Foo; fn main() { - let _ = Foo { field2: 42 }; //~ ERROR struct `rmeta_meta::Foo` has no field named `field2` + let _ = Foo { field2: 42 }; //~ ERROR struct `Foo` has no field named `field2` } diff --git a/src/test/ui/rmeta_meta_main.stderr b/src/test/ui/rmeta_meta_main.stderr index 347e5e97d7..0c6ed9afd3 100644 --- a/src/test/ui/rmeta_meta_main.stderr +++ b/src/test/ui/rmeta_meta_main.stderr @@ -1,4 +1,4 @@ -error[E0560]: struct `rmeta_meta::Foo` has no field named `field2` +error[E0560]: struct `Foo` has no field named `field2` --> $DIR/rmeta_meta_main.rs:13:19 | LL | let _ = Foo { field2: 42 }; diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr index 7948f7e9d6..85da2c6eeb 100644 --- a/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.curr.stderr @@ -26,8 +26,8 @@ LL | fn foo(self: &Rc) -> usize; LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` - = note: required by cast to type `std::rc::Rc` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Rc` + = note: required by cast to type `Rc` error: aborting due to 2 previous errors diff --git a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr index 74e76b8265..c4cde2c356 100644 --- a/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr +++ b/src/test/ui/self/arbitrary-self-types-not-object-safe.object_safe_for_dispatch.stderr @@ -12,8 +12,8 @@ LL | fn foo(self: &Rc) -> usize; LL | let x = Rc::new(5usize) as Rc; | ^^^^^^^^^^^^^^^ the trait `Foo` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::rc::Rc` - = note: required by cast to type `std::rc::Rc` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Rc` + = note: required by cast to type `Rc` error: aborting due to previous error diff --git a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr index 17099201d1..92241b2fb2 100644 --- a/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr +++ b/src/test/ui/self/arbitrary_self_types_pin_lifetime_mismatch.nll.stderr @@ -20,7 +20,7 @@ error: lifetime may not live long enough --> $DIR/arbitrary_self_types_pin_lifetime_mismatch.rs:13:58 | LL | fn bar<'a>(self: Alias<&Self>, arg: &'a ()) -> &() { arg } - | -- ---- has type `std::pin::Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` + | -- ---- has type `Pin<&'1 Foo>` ^^^ associated function was supposed to return data with lifetime `'1` but it is returning data with lifetime `'a` | | | lifetime `'a` defined here diff --git a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr index 96401cb71d..2954a499c1 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-method.stderr @@ -5,7 +5,7 @@ LL | struct A; | --------- method `foo` not found for this ... LL | fn foo(self: Box) {} - | --- the method is available for `std::boxed::Box` here + | --- the method is available for `Box` here ... LL | A.foo(); | ^^^ method not found in `A` diff --git a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr index 37873031da..89fe84c0d2 100644 --- a/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr +++ b/src/test/ui/self/point-at-arbitrary-self-type-trait-method.stderr @@ -4,7 +4,7 @@ error[E0599]: no method named `foo` found for struct `A` in the current scope LL | trait B { fn foo(self: Box); } | --- --------- the method might not be found because of this arbitrary self type | | - | the method is available for `std::boxed::Box` here + | the method is available for `Box` here LL | struct A; | --------- method `foo` not found for this ... diff --git a/src/test/ui/self/self_type_keyword.stderr b/src/test/ui/self/self_type_keyword.stderr index 7997cdc295..47c04f1eb7 100644 --- a/src/test/ui/self/self_type_keyword.stderr +++ b/src/test/ui/self/self_type_keyword.stderr @@ -77,7 +77,7 @@ error[E0392]: parameter `'Self` is never used LL | struct Bar<'Self>; | ^^^^^ unused parameter | - = help: consider removing `'Self`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'Self`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 12 previous errors diff --git a/src/test/ui/shift-various-bad-types.stderr b/src/test/ui/shift-various-bad-types.stderr index 91f8b0e630..c27bdf09a8 100644 --- a/src/test/ui/shift-various-bad-types.stderr +++ b/src/test/ui/shift-various-bad-types.stderr @@ -4,7 +4,7 @@ error[E0277]: no implementation for `{integer} >> char` LL | 22 >> p.char; | ^^ no implementation for `{integer} >> char` | - = help: the trait `std::ops::Shr` is not implemented for `{integer}` + = help: the trait `Shr` is not implemented for `{integer}` error[E0277]: no implementation for `{integer} >> &str` --> $DIR/shift-various-bad-types.rs:12:8 @@ -12,7 +12,7 @@ error[E0277]: no implementation for `{integer} >> &str` LL | 22 >> p.str; | ^^ no implementation for `{integer} >> &str` | - = help: the trait `std::ops::Shr<&str>` is not implemented for `{integer}` + = help: the trait `Shr<&str>` is not implemented for `{integer}` error[E0277]: no implementation for `{integer} >> &Panolpy` --> $DIR/shift-various-bad-types.rs:15:8 @@ -20,7 +20,7 @@ error[E0277]: no implementation for `{integer} >> &Panolpy` LL | 22 >> p; | ^^ no implementation for `{integer} >> &Panolpy` | - = help: the trait `std::ops::Shr<&Panolpy>` is not implemented for `{integer}` + = help: the trait `Shr<&Panolpy>` is not implemented for `{integer}` error[E0308]: mismatched types --> $DIR/shift-various-bad-types.rs:25:18 diff --git a/src/test/ui/slice-to-vec-comparison.rs b/src/test/ui/slice-to-vec-comparison.rs new file mode 100644 index 0000000000..7026a49000 --- /dev/null +++ b/src/test/ui/slice-to-vec-comparison.rs @@ -0,0 +1,6 @@ +fn main() { + let a = &[]; + let b: &Vec = &vec![]; + a > b; + //~^ ERROR mismatched types +} diff --git a/src/test/ui/slice-to-vec-comparison.stderr b/src/test/ui/slice-to-vec-comparison.stderr new file mode 100644 index 0000000000..e3b3b040f6 --- /dev/null +++ b/src/test/ui/slice-to-vec-comparison.stderr @@ -0,0 +1,12 @@ +error[E0308]: mismatched types + --> $DIR/slice-to-vec-comparison.rs:4:9 + | +LL | a > b; + | ^ expected array of 0 elements, found struct `Vec` + | + = note: expected reference `&[_; 0]` + found reference `&Vec` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index 72f875bbd1..ab1fa2a4d8 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -33,7 +33,7 @@ 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 s:std::string::String]`, which does not implement the `Copy` trait + | ^ 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 error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 diff --git a/src/test/ui/span/borrowck-fn-in-const-b.stderr b/src/test/ui/span/borrowck-fn-in-const-b.stderr index 9133d482c2..8949a10481 100644 --- a/src/test/ui/span/borrowck-fn-in-const-b.stderr +++ b/src/test/ui/span/borrowck-fn-in-const-b.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference --> $DIR/borrowck-fn-in-const-b.rs:7:9 | LL | fn broken(x: &Vec) { - | ------------ help: consider changing this to be a mutable reference: `&mut std::vec::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 diff --git a/src/test/ui/span/coerce-suggestions.stderr b/src/test/ui/span/coerce-suggestions.stderr index d1960a8aab..857c3081c6 100644 --- a/src/test/ui/span/coerce-suggestions.stderr +++ b/src/test/ui/span/coerce-suggestions.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:7:20 | LL | let x: usize = String::new(); - | ----- ^^^^^^^^^^^^^ expected `usize`, found struct `std::string::String` + | ----- ^^^^^^^^^^^^^ expected `usize`, found struct `String` | | | expected due to this @@ -12,7 +12,7 @@ error[E0308]: mismatched types LL | let x: &str = String::new(); | ---- ^^^^^^^^^^^^^ | | | - | | expected `&str`, found struct `std::string::String` + | | expected `&str`, found struct `String` | | help: consider borrowing here: `&String::new()` | expected due to this @@ -22,8 +22,8 @@ error[E0308]: mismatched types LL | test(&y); | ^^ types differ in mutability | - = note: expected mutable reference `&mut std::string::String` - found reference `&std::string::String` + = note: expected mutable reference `&mut String` + found reference `&String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:14:11 @@ -32,7 +32,7 @@ LL | test2(&y); | ^^ types differ in mutability | = note: expected mutable reference `&mut i32` - found reference `&std::string::String` + found reference `&String` error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:17:9 @@ -47,7 +47,7 @@ error[E0308]: mismatched types --> $DIR/coerce-suggestions.rs:21:9 | LL | s = format!("foo"); - | ^^^^^^^^^^^^^^ expected `&mut std::string::String`, found struct `std::string::String` + | ^^^^^^^^^^^^^^ expected `&mut String`, found struct `String` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/span/destructor-restrictions.stderr b/src/test/ui/span/destructor-restrictions.stderr index b5cd29f99c..f63d97780c 100644 --- a/src/test/ui/span/destructor-restrictions.stderr +++ b/src/test/ui/span/destructor-restrictions.stderr @@ -7,7 +7,7 @@ LL | *a.borrow() + 1 | borrowed value does not live long enough | a temporary with access to the borrow is created here ... LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, i32>` + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, i32>` | | | `*a` dropped here while still borrowed | diff --git a/src/test/ui/span/dropck-object-cycle.stderr b/src/test/ui/span/dropck-object-cycle.stderr index cfaf470212..229d17e1cf 100644 --- a/src/test/ui/span/dropck-object-cycle.stderr +++ b/src/test/ui/span/dropck-object-cycle.stderr @@ -8,7 +8,7 @@ LL | } | - | | | `*m` dropped here while still borrowed - | borrow might be used here, when `m` is dropped and runs the destructor for type `std::boxed::Box>` + | borrow might be used here, when `m` is dropped and runs the destructor for type `Box>` error: aborting due to previous error diff --git a/src/test/ui/span/impl-wrong-item-for-trait.stderr b/src/test/ui/span/impl-wrong-item-for-trait.stderr index cda191522a..9b0aad28b0 100644 --- a/src/test/ui/span/impl-wrong-item-for-trait.stderr +++ b/src/test/ui/span/impl-wrong-item-for-trait.stderr @@ -64,7 +64,7 @@ error[E0046]: not all trait items implemented, missing: `fmt` LL | impl Debug for FooTypeForMethod { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `fmt` in implementation | - = help: implement the missing item: `fn fmt(&self, _: &mut std::fmt::Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` + = help: implement the missing item: `fn fmt(&self, _: &mut Formatter<'_>) -> std::result::Result<(), std::fmt::Error> { todo!() }` error: aborting due to 8 previous errors diff --git a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr index 46702d364a..e04ca0f526 100644 --- a/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr +++ b/src/test/ui/span/issue-23338-locals-die-before-temps-of-body.stderr @@ -10,7 +10,7 @@ LL | } | - | | | `y` dropped here while still borrowed - | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` + | ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, String>` | = note: the temporary is part of an expression at the end of a block; consider forcing this temporary to be dropped sooner, before the block's local variables are dropped @@ -28,7 +28,7 @@ LL | y.borrow().clone() | borrowed value does not live long enough | a temporary with access to the borrow is created here ... LL | }; - | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `std::cell::Ref<'_, std::string::String>` + | -- ... and the borrow might be used here, when that temporary is dropped and runs the destructor for type `Ref<'_, String>` | | | `y` dropped here while still borrowed | diff --git a/src/test/ui/span/issue-29106.stderr b/src/test/ui/span/issue-29106.stderr index 3b403de12d..71fbd60ee7 100644 --- a/src/test/ui/span/issue-29106.stderr +++ b/src/test/ui/span/issue-29106.stderr @@ -7,7 +7,7 @@ LL | } | - | | | `x` dropped here while still borrowed - | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::sync::Arc` + | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `Arc` | = note: values in a scope are dropped in the opposite order they are defined @@ -20,7 +20,7 @@ LL | } | - | | | `x` dropped here while still borrowed - | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `std::rc::Rc` + | borrow might be used here, when `y` is dropped and runs the `Drop` code for type `Rc` | = note: values in a scope are dropped in the opposite order they are defined diff --git a/src/test/ui/span/issue-33884.stderr b/src/test/ui/span/issue-33884.stderr index 184d9644c8..46f36679b8 100644 --- a/src/test/ui/span/issue-33884.stderr +++ b/src/test/ui/span/issue-33884.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/issue-33884.rs:8:22 | LL | stream.write_fmt(format!("message received")) - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `std::fmt::Arguments`, found struct `std::string::String` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected struct `Arguments`, found struct `String` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/span/issue-39018.stderr b/src/test/ui/span/issue-39018.stderr index 8caa5bea4a..a7131ab8af 100644 --- a/src/test/ui/span/issue-39018.stderr +++ b/src/test/ui/span/issue-39018.stderr @@ -22,11 +22,11 @@ LL | let y = World::Hello + World::Goodbye; | = note: an implementation of `std::ops::Add` might be missing for `World` -error[E0369]: cannot add `std::string::String` to `&str` +error[E0369]: cannot add `String` to `&str` --> $DIR/issue-39018.rs:11:22 | LL | let x = "Hello " + "World!".to_owned(); - | -------- ^ ------------------- std::string::String + | -------- ^ ------------------- String | | | | | `+` cannot be used to concatenate a `&str` with a `String` | &str @@ -36,28 +36,28 @@ help: `to_owned()` can be used to create an owned `String` from a string referen LL | let x = "Hello ".to_owned() + &"World!".to_owned(); | ^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^^^ -error[E0369]: cannot add `&std::string::String` to `&std::string::String` +error[E0369]: cannot add `&String` to `&String` --> $DIR/issue-39018.rs:26:16 | LL | let _ = &a + &b; - | -- ^ -- &std::string::String + | -- ^ -- &String | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = a + &b; | ^ -error[E0369]: cannot add `std::string::String` to `&std::string::String` +error[E0369]: cannot add `String` to `&String` --> $DIR/issue-39018.rs:27:16 | LL | let _ = &a + b; - | -- ^ - std::string::String + | -- ^ - String | | | | | `+` cannot be used to concatenate a `&str` with a `String` - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | @@ -70,59 +70,59 @@ error[E0308]: mismatched types LL | let _ = a + b; | ^ | | - | expected `&str`, found struct `std::string::String` + | expected `&str`, found struct `String` | help: consider borrowing here: `&b` -error[E0369]: cannot add `std::string::String` to `&std::string::String` +error[E0369]: cannot add `String` to `&String` --> $DIR/issue-39018.rs:30:15 | LL | let _ = e + b; - | - ^ - std::string::String + | - ^ - String | | | | | `+` cannot be used to concatenate a `&str` with a `String` - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = e.to_owned() + &b; | ^^^^^^^^^^^^ ^^ -error[E0369]: cannot add `&std::string::String` to `&std::string::String` +error[E0369]: cannot add `&String` to `&String` --> $DIR/issue-39018.rs:31:15 | LL | let _ = e + &b; - | - ^ -- &std::string::String + | - ^ -- &String | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = e.to_owned() + &b; | ^^^^^^^^^^^^ -error[E0369]: cannot add `&str` to `&std::string::String` +error[E0369]: cannot add `&str` to `&String` --> $DIR/issue-39018.rs:32:15 | LL | let _ = e + d; | - ^ - &str | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | LL | let _ = e.to_owned() + d; | ^^^^^^^^^^^^ -error[E0369]: cannot add `&&str` to `&std::string::String` +error[E0369]: cannot add `&&str` to `&String` --> $DIR/issue-39018.rs:33:15 | LL | let _ = e + &d; | - ^ -- &&str | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr index 9824d879db..c64c5b1c28 100644 --- a/src/test/ui/span/issue-42234-unknown-receiver-type.stderr +++ b/src/test/ui/span/issue-42234-unknown-receiver-type.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed for `std::option::Option<_>` +error[E0282]: type annotations needed for `Option<_>` --> $DIR/issue-42234-unknown-receiver-type.rs:7:7 | LL | let x: Option<_> = None; - | - consider giving `x` the explicit type `std::option::Option<_>`, where the type parameter `T` is specified + | - consider giving `x` the explicit type `Option<_>`, where the type parameter `T` is specified LL | x.unwrap().method_that_could_exist_on_some_type(); | ^^^^^^ cannot infer type for type parameter `T` | diff --git a/src/test/ui/span/issue-43927-non-ADT-derive.stderr b/src/test/ui/span/issue-43927-non-ADT-derive.stderr index b68681c529..b160a4e587 100644 --- a/src/test/ui/span/issue-43927-non-ADT-derive.stderr +++ b/src/test/ui/span/issue-43927-non-ADT-derive.stderr @@ -1,4 +1,4 @@ -error: `derive` may only be applied to structs, enums and unions +error[E0774]: `derive` may only be applied to structs, enums and unions --> $DIR/issue-43927-non-ADT-derive.rs:3:1 | LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! @@ -54,3 +54,4 @@ LL | #![derive(Debug, PartialEq, Eq)] // should be an outer attribute! error: aborting due to 7 previous errors +For more information about this error, try `rustc --explain E0774`. diff --git a/src/test/ui/span/multiline-span-simple.stderr b/src/test/ui/span/multiline-span-simple.stderr index 6495d9bc73..13ef0d1820 100644 --- a/src/test/ui/span/multiline-span-simple.stderr +++ b/src/test/ui/span/multiline-span-simple.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `()` to `u32` LL | foo(1 as u32 + | ^ no implementation for `u32 + ()` | - = help: the trait `std::ops::Add<()>` is not implemented for `u32` + = help: the trait `Add<()>` is not implemented for `u32` error: aborting due to previous error diff --git a/src/test/ui/span/mut-arg-hint.stderr b/src/test/ui/span/mut-arg-hint.stderr index 8027cf69cf..e04e4cbdab 100644 --- a/src/test/ui/span/mut-arg-hint.stderr +++ b/src/test/ui/span/mut-arg-hint.stderr @@ -2,7 +2,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:3:9 | LL | fn foo(mut a: &String) { - | ------- help: consider changing this to be a mutable reference: `&mut std::string::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 @@ -18,7 +18,7 @@ error[E0596]: cannot borrow `*a` as mutable, as it is behind a `&` reference --> $DIR/mut-arg-hint.rs:15:9 | LL | pub fn foo(mut a: &String) { - | ------- help: consider changing this to be a mutable reference: `&mut std::string::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 diff --git a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr index 2be2d0ff7b..ba0c45acf2 100644 --- a/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr +++ b/src/test/ui/span/regions-close-over-borrowed-ref-in-obj.stderr @@ -7,7 +7,7 @@ LL | let ss: &isize = &id(1); LL | } | - temporary value is freed at the end of this statement LL | } - | - borrow might be used here, when `blah` is dropped and runs the destructor for type `std::boxed::Box` + | - borrow might be used here, when `blah` is dropped and runs the destructor for type `Box` | = note: consider using a `let` binding to create a longer lived value diff --git a/src/test/ui/span/send-is-not-static-std-sync.stderr b/src/test/ui/span/send-is-not-static-std-sync.stderr index d00b157d38..81de8c2990 100644 --- a/src/test/ui/span/send-is-not-static-std-sync.stderr +++ b/src/test/ui/span/send-is-not-static-std-sync.stderr @@ -62,7 +62,7 @@ LL | } | - `z` dropped here while still borrowed ... LL | } - | - borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `std::sync::mpsc::Sender` + | - borrow might be used here, when `tx` is dropped and runs the `Drop` code for type `Sender` | = note: values in a scope are dropped in the opposite order they are defined diff --git a/src/test/ui/span/type-binding.stderr b/src/test/ui/span/type-binding.stderr index f698993355..cb0aefe060 100644 --- a/src/test/ui/span/type-binding.stderr +++ b/src/test/ui/span/type-binding.stderr @@ -1,4 +1,4 @@ -error[E0220]: associated type `Trget` not found for `std::ops::Deref` +error[E0220]: associated type `Trget` not found for `Deref` --> $DIR/type-binding.rs:6:20 | LL | fn homura>(_: T) {} diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.rs b/src/test/ui/specialization/deafult-associated-type-bound-1.rs index 272a5e3fe1..c043114b56 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.rs +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.rs @@ -16,7 +16,7 @@ trait X { // normalization. impl X for T { default type U = str; - //~^ ERROR the trait bound `str: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `str: Clone` is not satisfied } pub fn main() { diff --git a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr index 90ad5d4c15..612e22c204 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-1.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-1.stderr @@ -7,14 +7,14 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -error[E0277]: the trait bound `str: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `str: Clone` is not satisfied --> $DIR/deafult-associated-type-bound-1.rs:18:5 | LL | type U: Clone; | -------------- required by `X::U` ... LL | default type U = str; - | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::clone::Clone` is not implemented for `str` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Clone` is not implemented for `str` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr index ea40f846e3..a14024c160 100644 --- a/src/test/ui/specialization/deafult-associated-type-bound-2.stderr +++ b/src/test/ui/specialization/deafult-associated-type-bound-2.stderr @@ -16,7 +16,7 @@ LL | type U: PartialEq; LL | default type U = &'static B; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `&'static B == B` | - = help: the trait `std::cmp::PartialEq` is not implemented for `&'static B` + = help: the trait `PartialEq` is not implemented for `&'static B` error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr index 3da8725d88..556feda642 100644 --- a/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr +++ b/src/test/ui/specialization/deafult-generic-associated-type-bound.stderr @@ -24,11 +24,11 @@ LL | type U<'a>: PartialEq<&'a Self>; LL | default type U<'a> = &'a T; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ no implementation for `T == T` | - = note: required because of the requirements on the impl of `std::cmp::PartialEq` for `&'a T` + = note: required because of the requirements on the impl of `PartialEq` for `&'a T` help: consider further restricting this bound | -LL | impl X for T { - | ^^^^^^^^^^^^^^^^^^^^^ +LL | impl X for T { + | ^^^^^^^^^^^ error: aborting due to previous error; 2 warnings emitted diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs index afd634725e..eb18d6eaac 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.rs @@ -5,6 +5,6 @@ trait Foo<'a, T: Eq + 'a> { } default impl Foo<'static, U> for () {} -//~^ ERROR the trait bound `U: std::cmp::Eq` is not satisfied +//~^ ERROR the trait bound `U: Eq` is not satisfied fn main(){} diff --git a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr index d45825651a..dcac310ed0 100644 --- a/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr +++ b/src/test/ui/specialization/defaultimpl/specialization-wfcheck.stderr @@ -7,19 +7,19 @@ LL | #![feature(specialization)] = note: `#[warn(incomplete_features)]` on by default = note: see issue #31844 for more information -error[E0277]: the trait bound `U: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `U: Eq` is not satisfied --> $DIR/specialization-wfcheck.rs:7:17 | LL | trait Foo<'a, T: Eq + 'a> { } | -- required by this bound in `Foo` LL | LL | default impl Foo<'static, U> for () {} - | ^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `U` + | ^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `U` | help: consider restricting type parameter `U` | -LL | default impl Foo<'static, U> for () {} - | ^^^^^^^^^^^^^^ +LL | default impl Foo<'static, U> for () {} + | ^^^^ error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/specialization/issue-44861.rs b/src/test/ui/specialization/issue-44861.rs index c37a6273de..79d9b9490d 100644 --- a/src/test/ui/specialization/issue-44861.rs +++ b/src/test/ui/specialization/issue-44861.rs @@ -19,7 +19,7 @@ impl MaybeObjectSafe for () {} impl Smartass for T { type Data = ::Data2; default type Data2 = (); - //~^ ERROR: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied + //~^ ERROR: the trait bound `(): CoerceUnsized<*const [u8]>` is not satisfied } impl Smartass for () { diff --git a/src/test/ui/specialization/issue-44861.stderr b/src/test/ui/specialization/issue-44861.stderr index b41b17e76a..be7196a63c 100644 --- a/src/test/ui/specialization/issue-44861.stderr +++ b/src/test/ui/specialization/issue-44861.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `(): std::ops::CoerceUnsized<*const [u8]>` is not satisfied +error[E0277]: the trait bound `(): CoerceUnsized<*const [u8]>` is not satisfied --> $DIR/issue-44861.rs:21:5 | LL | type Data2: CoerceUnsized<*const [u8]>; | --------------------------------------- required by `Smartass::Data2` ... LL | default type Data2 = (); - | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::ops::CoerceUnsized<*const [u8]>` is not implemented for `()` + | ^^^^^^^^^^^^^^^^^^^^^^^^ the trait `CoerceUnsized<*const [u8]>` is not implemented for `()` error: aborting due to previous error diff --git a/src/test/ui/specialization/issue-59435.rs b/src/test/ui/specialization/issue-59435.rs index 47323d3096..3239002566 100644 --- a/src/test/ui/specialization/issue-59435.rs +++ b/src/test/ui/specialization/issue-59435.rs @@ -9,7 +9,7 @@ trait MyTrait { impl MyTrait for i32 { default type MyType = MyStruct; - //~^ ERROR: the trait bound `MyStruct: std::default::Default` is not satisfied + //~^ ERROR: the trait bound `MyStruct: Default` is not satisfied } fn main() { diff --git a/src/test/ui/specialization/issue-59435.stderr b/src/test/ui/specialization/issue-59435.stderr index fd512a539a..ee5c061592 100644 --- a/src/test/ui/specialization/issue-59435.stderr +++ b/src/test/ui/specialization/issue-59435.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `MyStruct: std::default::Default` is not satisfied +error[E0277]: the trait bound `MyStruct: Default` is not satisfied --> $DIR/issue-59435.rs:11:5 | LL | type MyType: Default; | --------------------- required by `MyTrait::MyType` ... LL | default type MyType = MyStruct; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::default::Default` is not implemented for `MyStruct` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Default` is not implemented for `MyStruct` error: aborting due to previous error diff --git a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr index 1361117f6c..fee8b06e94 100644 --- a/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr +++ b/src/test/ui/specialization/min_specialization/repeated_projection_type.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on `ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id[0]::This[0]) }, (I,))` +error: cannot specialize on `ProjectionPredicate(ProjectionTy { substs: [V], item_def_id: DefId(0:6 ~ repeated_projection_type[317d]::Id::This) }, (I,))` --> $DIR/repeated_projection_type.rs:19:1 | LL | / impl> X for V { diff --git a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr index 154c839c6d..5782ad01b3 100644 --- a/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr +++ b/src/test/ui/specialization/min_specialization/specialization_super_trait.stderr @@ -1,4 +1,4 @@ -error: cannot specialize on trait `std::default::Default` +error: cannot specialize on trait `Default` --> $DIR/specialization_super_trait.rs:13:1 | LL | / impl SpecMarker for T { diff --git a/src/test/ui/specialization/min_specialization/specialization_trait.stderr b/src/test/ui/specialization/min_specialization/specialization_trait.stderr index 4357d2318f..8a70d6cc1b 100644 --- a/src/test/ui/specialization/min_specialization/specialization_trait.stderr +++ b/src/test/ui/specialization/min_specialization/specialization_trait.stderr @@ -16,7 +16,7 @@ LL | | fn f() {} LL | | } | |_^ -error: cannot specialize on trait `std::clone::Clone` +error: cannot specialize on trait `Clone` --> $DIR/specialization_trait.rs:21:1 | LL | / impl SpecMarker for [T] { diff --git a/src/test/ui/specialization/specialization-default-types.stderr b/src/test/ui/specialization/specialization-default-types.stderr index 5e0221f078..5acfb53e20 100644 --- a/src/test/ui/specialization/specialization-default-types.stderr +++ b/src/test/ui/specialization/specialization-default-types.stderr @@ -15,22 +15,22 @@ LL | default type Output = Box; LL | default fn generate(self) -> Self::Output { | ------------ expected `::Output` because of return type LL | Box::new(self) - | ^^^^^^^^^^^^^^ expected associated type, found struct `std::boxed::Box` + | ^^^^^^^^^^^^^^ expected associated type, found struct `Box` | = note: expected associated type `::Output` - found struct `std::boxed::Box` + found struct `Box` error[E0308]: mismatched types --> $DIR/specialization-default-types.rs:25:5 | LL | fn trouble(t: T) -> Box { - | ------ expected `std::boxed::Box` because of return type + | ------ expected `Box` because of return type LL | Example::generate(t) - | ^^^^^^^^^^^^^^^^^^^^ expected struct `std::boxed::Box`, found associated type + | ^^^^^^^^^^^^^^^^^^^^ expected struct `Box`, found associated type | - = note: expected struct `std::boxed::Box` + = note: expected struct `Box` found associated type `::Output` - = help: consider constraining the associated type `::Output` to `std::boxed::Box` + = help: consider constraining the associated type `::Output` to `Box` = note: for more information, visit https://doc.rust-lang.org/book/ch19-03-advanced-traits.html error: aborting due to 2 previous errors; 1 warning emitted diff --git a/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs new file mode 100644 index 0000000000..231ab96655 --- /dev/null +++ b/src/test/ui/stability-attribute/auxiliary/unstable_generic_param.rs @@ -0,0 +1,229 @@ +#![crate_type = "lib"] +#![feature(staged_api)] +#![stable(feature = "stable_test_feature", since = "1.0.0")] + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait1<#[unstable(feature = "unstable_default", issue = "none")] T = ()> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait2<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Trait3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + fn foo() -> T; +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field1: A, + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field2: B, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct4 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: A, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct5<#[unstable(feature = "unstable_default", issue = "none")] A = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: A, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Struct6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub field: T, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT1: Struct1 = Struct1 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT2: Struct2 = Struct2 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT3: Struct3 = Struct3 { field1: 1, field2: 2 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT4: Struct4 = Struct4 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const STRUCT5: Struct5 = Struct5 { field: 1 }; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Ok(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Err(#[stable(feature = "stable_test_feature", since = "1.0.0")] E), +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum4 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub enum Enum6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + Some(#[stable(feature = "stable_test_feature", since = "1.0.0")] T), + #[stable(feature = "stable_test_feature", since = "1.0.0")] + None, +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM1: Enum1 = Enum1::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM2: Enum2 = Enum2::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM3: Enum3 = Enum3::Ok(1); +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM3B: Enum3 = Enum3::Err(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM4: Enum4 = Enum4::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ENUM5: Enum5 = Enum5::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias1<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias2 = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias3 = + Result; + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias4 = Option; + +#[rustc_deprecated(since = "1.1.0", reason = "test")] +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias5<#[unstable(feature = "unstable_default", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub type Alias6<#[unstable(feature = "unstable_default6", issue = "none")] T = usize> = Option; + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS1: Alias1 = Alias1::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS2: Alias2 = Alias2::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS3: Alias3 = Alias3::Ok(1); +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS3B: Alias3 = Alias3::Err(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS4: Alias4 = Alias4::Some(1); + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub const ALIAS5: Alias5 = Alias5::Some(1); + + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub trait Alloc {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct System {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +impl Alloc for System {} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box1 { + ptr: *mut T, + alloc: A, +} + +impl Box1 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + unsafe { Self { ptr: &mut t, alloc: System {} } } + } +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box2 { + ptr: *mut T, + alloc: A, +} + +impl Box2 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + Self { ptr: &mut t, alloc: System {} } + } +} + +#[stable(feature = "stable_test_feature", since = "1.0.0")] +pub struct Box3 { + ptr: *mut T, +} + +impl Box3 { + #[stable(feature = "stable_test_feature", since = "1.0.0")] + pub fn new(mut t: T) -> Self { + Self { ptr: &mut t } + } +} diff --git a/src/test/ui/stability-attribute/generics-default-stability-where.rs b/src/test/ui/stability-attribute/generics-default-stability-where.rs new file mode 100644 index 0000000000..3fd14e25d0 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability-where.rs @@ -0,0 +1,12 @@ +// ignore-tidy-linelength +// aux-build:unstable_generic_param.rs + +extern crate unstable_generic_param; + +use unstable_generic_param::*; + +impl Trait3 for T where T: Trait2 { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { T::foo() } +} + +fn main() {} diff --git a/src/test/ui/stability-attribute/generics-default-stability-where.stderr b/src/test/ui/stability-attribute/generics-default-stability-where.stderr new file mode 100644 index 0000000000..19fa09f311 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability-where.stderr @@ -0,0 +1,11 @@ +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability-where.rs:8:45 + | +LL | impl Trait3 for T where T: Trait2 { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/generics-default-stability.rs b/src/test/ui/stability-attribute/generics-default-stability.rs new file mode 100644 index 0000000000..d6f28e3e44 --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability.rs @@ -0,0 +1,264 @@ +// ignore-tidy-linelength +// aux-build:unstable_generic_param.rs +#![feature(unstable_default6)] + +extern crate unstable_generic_param; + +use unstable_generic_param::*; + +struct R; + +impl Trait1 for S { + fn foo() -> () { () } // ok +} + +struct S; + +impl Trait1 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { 0 } +} + +impl Trait1 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> isize { 0 } +} + +impl Trait2 for S { //~ ERROR use of unstable library feature 'unstable_default' + fn foo() -> usize { 0 } +} + +impl Trait3 for S { + fn foo() -> usize { 0 } // ok +} + +fn main() { + let _ = S; + + let _: Struct1 = Struct1 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + + let _ = STRUCT1; // ok + let _: Struct1 = STRUCT1; // ok + let _: Struct1 = STRUCT1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct1 = Struct1 { field: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = STRUCT1.field; + let _ = Struct1 { field: 1 }; + let _ = Struct1 { field: () }; + let _ = Struct1 { field: 1isize }; + let _: Struct1 = Struct1 { field: 1 }; + let _: usize = STRUCT1.field; + let _ = STRUCT1.field + 1; + let _ = STRUCT1.field + 1usize; + + let _ = Struct2 { field: 1 }; // ok + let _: Struct2 = Struct2 { field: 1 }; // ok + let _: Struct2 = Struct2 { field: 1 }; // ok + + let _ = STRUCT2; + let _: Struct2 = STRUCT2; // ok + let _: Struct2 = STRUCT2; // ok + let _: Struct2 = Struct2 { field: 0 }; // ok + let _ = STRUCT2.field; // ok + let _: usize = STRUCT2.field; // ok + let _ = STRUCT2.field + 1; // ok + let _ = STRUCT2.field + 1usize; // ok + + let _ = STRUCT3; + let _: Struct3 = STRUCT3; // ok + let _: Struct3 = STRUCT3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct3 = STRUCT3; // ok + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + let _ = STRUCT3.field1; // ok + let _: isize = STRUCT3.field1; // ok + let _ = STRUCT3.field1 + 1; // ok + // Note the aforementioned leak. + let _: usize = STRUCT3.field2; // ok + let _: Struct3 = Struct3 { field1: 0, field2: 0 }; // ok + let _ = STRUCT3.field2 + 1; // ok + let _ = STRUCT3.field2 + 1usize; // ok + + let _ = STRUCT4; + let _: Struct4 = Struct4 { field: 1 }; + //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] + let _ = STRUCT4; + let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + let _: Struct4 = STRUCT4; //~ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + let _: Struct4 = Struct4 { field: 0 }; + //~^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct4`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct4::field`: test [deprecated] + + let _ = STRUCT5; + let _: Struct5 = Struct5 { field: 1 }; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] + let _ = STRUCT5; + let _: Struct5 = STRUCT5; //~ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + let _: Struct5 = STRUCT5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + let _: Struct5 = Struct5 { field: 0 }; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^ use of deprecated struct `unstable_generic_param::Struct5`: test [deprecated] + //~^^^ use of deprecated field `unstable_generic_param::Struct5::field`: test [deprecated] + + let _: Struct6 = Struct6 { field: 1 }; // ok + let _: Struct6 = Struct6 { field: 0 }; // ok + + let _: Alias1 = Alias1::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + + let _ = ALIAS1; // ok + let _: Alias1 = ALIAS1; // ok + let _: Alias1 = ALIAS1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias1 = Alias1::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = Alias1::Some(1); + let _ = Alias1::Some(()); + let _ = Alias1::Some(1isize); + let _: Alias1 = Alias1::Some(1); + let _: usize = ALIAS1.unwrap(); + let _ = ALIAS1.unwrap() + 1; + let _ = ALIAS1.unwrap() + 1usize; + + let _ = Alias2::Some(1); // ok + let _: Alias2 = Alias2::Some(1); // ok + let _: Alias2 = Alias2::Some(1); // ok + + let _ = ALIAS2; + let _: Alias2 = ALIAS2; // ok + let _: Alias2 = ALIAS2; // ok + let _: Alias2 = Alias2::Some(0); // ok + let _ = ALIAS2.unwrap(); // ok + let _: usize = ALIAS2.unwrap(); // ok + let _ = ALIAS2.unwrap() + 1; // ok + let _ = ALIAS2.unwrap() + 1usize; // ok + + let _ = ALIAS3; + let _: Alias3 = ALIAS3; // ok + let _: Alias3 = ALIAS3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias3 = ALIAS3; // ok + let _: Alias3 = Alias3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _: Alias3 = Alias3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _ = ALIAS3.unwrap(); // ok + let _: isize = ALIAS3.unwrap(); // ok + let _ = ALIAS3.unwrap() + 1; // ok + // Note the aforementioned leak. + let _: usize = ALIAS3B.unwrap_err(); // ok + let _: Alias3 = Alias3::Err(0); // ok + let _ = ALIAS3B.unwrap_err() + 1; // ok + let _ = ALIAS3B.unwrap_err() + 1usize; // ok + + let _ = ALIAS4; + let _: Alias4 = Alias4::Some(1); + //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _ = ALIAS4; + let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = ALIAS4; //~ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + let _: Alias4 = Alias4::Some(0); + //~^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias4`: test [deprecated] + + let _ = ALIAS5; + let _: Alias5 = Alias5::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _ = ALIAS5; + let _: Alias5 = ALIAS5; //~ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _: Alias5 = ALIAS5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + let _: Alias5 = Alias5::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + //~^^ use of deprecated type alias `unstable_generic_param::Alias5`: test [deprecated] + + let _: Alias6 = Alias6::Some(1); // ok + let _: Alias6 = Alias6::Some(0); // ok + + let _: Enum1 = Enum1::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + + let _ = ENUM1; // ok + let _: Enum1 = ENUM1; // ok + let _: Enum1 = ENUM1; //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum1 = Enum1::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + + // Instability is not enforced for generic type parameters used in public fields. + // Note how the unstable type default `usize` leaks, + // and can be used without the 'unstable_default' feature. + let _ = Enum1::Some(1); + let _ = Enum1::Some(()); + let _ = Enum1::Some(1isize); + let _: Enum1 = Enum1::Some(1); + if let Enum1::Some(x) = ENUM1 {let _: usize = x;} + if let Enum1::Some(x) = ENUM1 {let _ = x + 1;} + if let Enum1::Some(x) = ENUM1 {let _ = x + 1usize;} + + let _ = Enum2::Some(1); // ok + let _: Enum2 = Enum2::Some(1); // ok + let _: Enum2 = Enum2::Some(1); // ok + + let _ = ENUM2; + let _: Enum2 = ENUM2; // ok + let _: Enum2 = ENUM2; // ok + let _: Enum2 = Enum2::Some(0); // ok + if let Enum2::Some(x) = ENUM2 {let _ = x;} // ok + if let Enum2::Some(x) = ENUM2 {let _: usize = x;} // ok + if let Enum2::Some(x) = ENUM2 {let _ = x + 1;} // ok + if let Enum2::Some(x) = ENUM2 {let _ = x + 1usize;} // ok + + let _ = ENUM3; + let _: Enum3 = ENUM3; // ok + let _: Enum3 = ENUM3; //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum3 = ENUM3; // ok + let _: Enum3 = Enum3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + let _: Enum3 = Enum3::Ok(0); //~ ERROR use of unstable library feature 'unstable_default' + if let Enum3::Ok(x) = ENUM3 {let _ = x;} // ok + if let Enum3::Ok(x) = ENUM3 {let _: isize = x;} // ok + if let Enum3::Ok(x) = ENUM3 {let _ = x + 1;} // ok + // Note the aforementioned leak. + if let Enum3::Err(x) = ENUM3B {let _: usize = x;} // ok + let _: Enum3 = Enum3::Err(0); // ok + if let Enum3::Err(x) = ENUM3B {let _ = x + 1;} // ok + if let Enum3::Err(x) = ENUM3B {let _ = x + 1usize;} // ok + + let _ = ENUM4; + let _: Enum4 = Enum4::Some(1); + //~^ use of deprecated variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _ = ENUM4; + let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = ENUM4; //~ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + let _: Enum4 = Enum4::Some(0); + //~^ use of deprecated variant `unstable_generic_param::Enum4::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum4`: test [deprecated] + + let _ = ENUM5; + let _: Enum5 = Enum5::Some(1); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _ = ENUM5; + let _: Enum5 = ENUM5; //~ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _: Enum5 = ENUM5; //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + let _: Enum5 = Enum5::Some(0); //~ ERROR use of unstable library feature 'unstable_default' + //~^ use of deprecated variant `unstable_generic_param::Enum5::Some`: test [deprecated] + //~^^ use of deprecated enum `unstable_generic_param::Enum5`: test [deprecated] + + let _: Enum6 = Enum6::Some(1); // ok + let _: Enum6 = Enum6::Some(0); // ok + + let _: Box1 = Box1::new(1); //~ ERROR use of unstable library feature 'box_alloc_param' + let _: Box1 = Box1::new(1); // ok + + let _: Box2 = Box2::new(1); // ok + let _: Box2 = Box2::new(1); // ok + + let _: Box3 = Box3::new(1); // ok +} diff --git a/src/test/ui/stability-attribute/generics-default-stability.stderr b/src/test/ui/stability-attribute/generics-default-stability.stderr new file mode 100644 index 0000000000..a5df70bb8b --- /dev/null +++ b/src/test/ui/stability-attribute/generics-default-stability.stderr @@ -0,0 +1,493 @@ +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:17:13 + | +LL | impl Trait1 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:21:13 + | +LL | impl Trait1 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:25:13 + | +LL | impl Trait2 for S { + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:84:29 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^ + | + = note: `#[warn(deprecated)]` on by default + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:84:12 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:89:12 + | +LL | let _: Struct4 = STRUCT4; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:90:12 + | +LL | let _: Struct4 = STRUCT4; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:91:29 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct4`: test + --> $DIR/generics-default-stability.rs:91:12 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:97:29 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:97:12 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:102:12 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:103:12 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:105:29 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^ + +warning: use of deprecated struct `unstable_generic_param::Struct5`: test + --> $DIR/generics-default-stability.rs:105:12 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:160:28 + | +LL | let _: Alias4 = Alias4::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:160:12 + | +LL | let _: Alias4 = Alias4::Some(1); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:164:12 + | +LL | let _: Alias4 = ALIAS4; + | ^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:165:12 + | +LL | let _: Alias4 = ALIAS4; + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:166:28 + | +LL | let _: Alias4 = Alias4::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias4`: test + --> $DIR/generics-default-stability.rs:166:12 + | +LL | let _: Alias4 = Alias4::Some(0); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:171:28 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:171:12 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:175:12 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:176:12 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:178:28 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated type alias `unstable_generic_param::Alias5`: test + --> $DIR/generics-default-stability.rs:178:12 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test + --> $DIR/generics-default-stability.rs:232:27 + | +LL | let _: Enum4 = Enum4::Some(1); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:232:12 + | +LL | let _: Enum4 = Enum4::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:236:12 + | +LL | let _: Enum4 = ENUM4; + | ^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:237:12 + | +LL | let _: Enum4 = ENUM4; + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum4::Some`: test + --> $DIR/generics-default-stability.rs:238:27 + | +LL | let _: Enum4 = Enum4::Some(0); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum4`: test + --> $DIR/generics-default-stability.rs:238:12 + | +LL | let _: Enum4 = Enum4::Some(0); + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test + --> $DIR/generics-default-stability.rs:243:27 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:243:12 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:247:12 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:248:12 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^^^^^^^^ + +warning: use of deprecated variant `unstable_generic_param::Enum5::Some`: test + --> $DIR/generics-default-stability.rs:250:27 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^^^^^^^ + +warning: use of deprecated enum `unstable_generic_param::Enum5`: test + --> $DIR/generics-default-stability.rs:250:12 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^^^^^^^^ + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:36:20 + | +LL | let _: Struct1 = Struct1 { field: 1 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:40:20 + | +LL | let _: Struct1 = STRUCT1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:41:20 + | +LL | let _: Struct1 = Struct1 { field: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:70:27 + | +LL | let _: Struct3 = STRUCT3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:72:27 + | +LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:73:27 + | +LL | let _: Struct3 = Struct3 { field1: 0, field2: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:97:20 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:103:20 + | +LL | let _: Struct5 = STRUCT5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:105:20 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:113:19 + | +LL | let _: Alias1 = Alias1::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:117:19 + | +LL | let _: Alias1 = ALIAS1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:118:19 + | +LL | let _: Alias1 = Alias1::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:146:26 + | +LL | let _: Alias3 = ALIAS3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:148:26 + | +LL | let _: Alias3 = Alias3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:149:26 + | +LL | let _: Alias3 = Alias3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:171:19 + | +LL | let _: Alias5 = Alias5::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:176:19 + | +LL | let _: Alias5 = ALIAS5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:178:19 + | +LL | let _: Alias5 = Alias5::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:185:18 + | +LL | let _: Enum1 = Enum1::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:189:18 + | +LL | let _: Enum1 = ENUM1; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:190:18 + | +LL | let _: Enum1 = Enum1::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:218:25 + | +LL | let _: Enum3 = ENUM3; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:220:25 + | +LL | let _: Enum3 = Enum3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:221:25 + | +LL | let _: Enum3 = Enum3::Ok(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:243:18 + | +LL | let _: Enum5 = Enum5::Some(1); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:248:18 + | +LL | let _: Enum5 = ENUM5; + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'unstable_default' + --> $DIR/generics-default-stability.rs:250:18 + | +LL | let _: Enum5 = Enum5::Some(0); + | ^^^^^ + | + = help: add `#![feature(unstable_default)]` to the crate attributes to enable + +error[E0658]: use of unstable library feature 'box_alloc_param' + --> $DIR/generics-default-stability.rs:257:24 + | +LL | let _: Box1 = Box1::new(1); + | ^^^^^^ + | + = help: add `#![feature(box_alloc_param)]` to the crate attributes to enable + +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:84:39 + | +LL | let _: Struct4 = Struct4 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct4::field`: test + --> $DIR/generics-default-stability.rs:91:39 + | +LL | let _: Struct4 = Struct4 { field: 0 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:97:39 + | +LL | let _: Struct5 = Struct5 { field: 1 }; + | ^^^^^^^^ + +warning: use of deprecated field `unstable_generic_param::Struct5::field`: test + --> $DIR/generics-default-stability.rs:105:39 + | +LL | let _: Struct5 = Struct5 { field: 0 }; + | ^^^^^^^^ + +error: aborting due to 31 previous errors; 40 warnings emitted + +For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/stability-attribute/missing-const-stability.rs b/src/test/ui/stability-attribute/missing-const-stability.rs new file mode 100644 index 0000000000..7d499c611a --- /dev/null +++ b/src/test/ui/stability-attribute/missing-const-stability.rs @@ -0,0 +1,12 @@ +#![feature(staged_api)] + +#![stable(feature = "rust1", since = "1.0.0")] + +#[stable(feature = "foo", since = "1.0.0")] +pub const fn foo() {} +//~^ ERROR rustc_const_stable + +#[unstable(feature = "bar", issue = "none")] +pub const fn bar() {} // ok + +fn main() {} diff --git a/src/test/ui/stability-attribute/missing-const-stability.stderr b/src/test/ui/stability-attribute/missing-const-stability.stderr new file mode 100644 index 0000000000..450a5303fd --- /dev/null +++ b/src/test/ui/stability-attribute/missing-const-stability.stderr @@ -0,0 +1,8 @@ +error: `#[stable]` const functions must also be either `#[rustc_const_stable]` or `#[rustc_const_unstable]` + --> $DIR/missing-const-stability.rs:6:1 + | +LL | pub const fn foo() {} + | ^^^^^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs new file mode 100644 index 0000000000..cc57071b87 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.rs @@ -0,0 +1,28 @@ +#![feature(staged_api)] + +#[stable(feature = "x", since = "1")] +struct StableType; + +#[unstable(feature = "x", issue = "none")] +struct UnstableType; + +#[stable(feature = "x", since = "1")] +trait StableTrait {} + +#[unstable(feature = "x", issue = "none")] +trait UnstableTrait {} + +#[unstable(feature = "x", issue = "none")] +impl UnstableTrait for UnstableType {} + +#[unstable(feature = "x", issue = "none")] +impl StableTrait for UnstableType {} + +#[unstable(feature = "x", issue = "none")] +impl UnstableTrait for StableType {} + +#[unstable(feature = "x", issue = "none")] +//~^ ERROR an `#[unstable]` annotation here has no effect [rustc::ineffective_unstable_trait_impl] +impl StableTrait for StableType {} + +fn main() {} diff --git a/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr new file mode 100644 index 0000000000..1915d03fb0 --- /dev/null +++ b/src/test/ui/stability-attribute/stability-attribute-trait-impl.stderr @@ -0,0 +1,11 @@ +error: an `#[unstable]` annotation here has no effect + --> $DIR/stability-attribute-trait-impl.rs:24:1 + | +LL | #[unstable(feature = "x", issue = "none")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: `#[deny(rustc::ineffective_unstable_trait_impl)]` on by default + = note: see issue #55436 for more information + +error: aborting due to previous error + diff --git a/src/test/ui/static/static-mut-not-constant.rs b/src/test/ui/static/static-mut-not-constant.rs index 84d401c9fa..2091fffd41 100644 --- a/src/test/ui/static/static-mut-not-constant.rs +++ b/src/test/ui/static/static-mut-not-constant.rs @@ -2,6 +2,5 @@ static mut a: Box = box 3; //~^ ERROR allocations are not allowed in statics -//~| ERROR static contains unimplemented expression type fn main() {} diff --git a/src/test/ui/static/static-mut-not-constant.stderr b/src/test/ui/static/static-mut-not-constant.stderr index a618b49d10..a0fa245156 100644 --- a/src/test/ui/static/static-mut-not-constant.stderr +++ b/src/test/ui/static/static-mut-not-constant.stderr @@ -4,15 +4,6 @@ error[E0010]: allocations are not allowed in statics LL | static mut a: Box = box 3; | ^^^^^ allocation not allowed in statics -error[E0019]: static contains unimplemented expression type - --> $DIR/static-mut-not-constant.rs:3:32 - | -LL | static mut a: Box = box 3; - | ^ - | - = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable +error: aborting due to previous error -error: aborting due to 2 previous errors - -Some errors have detailed explanations: E0010, E0019. -For more information about an error, try `rustc --explain E0010`. +For more information about this error, try `rustc --explain E0010`. diff --git a/src/test/ui/static/static-reference-to-fn-1.stderr b/src/test/ui/static/static-reference-to-fn-1.stderr index 77ab62c321..67b478bdb7 100644 --- a/src/test/ui/static/static-reference-to-fn-1.stderr +++ b/src/test/ui/static/static-reference-to-fn-1.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | func: &foo, | ^^^^ expected fn pointer, found fn item | - = note: expected reference `&fn() -> std::option::Option` - found reference `&fn() -> std::option::Option {foo}` + = note: expected reference `&fn() -> Option` + found reference `&fn() -> Option {foo}` error: aborting due to previous error diff --git a/src/test/ui/statics/static-promotion.rs b/src/test/ui/statics/static-promotion.rs index bd8910bdb3..b9eff46917 100644 --- a/src/test/ui/statics/static-promotion.rs +++ b/src/test/ui/statics/static-promotion.rs @@ -1,4 +1,4 @@ -// check-pass +// run-pass // Use of global static variables in literal values should be allowed for // promotion. diff --git a/src/test/ui/stdout-during-shutdown.rs b/src/test/ui/stdout-during-shutdown.rs new file mode 100644 index 0000000000..a6cf812ca6 --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.rs @@ -0,0 +1,19 @@ +// run-pass +// check-run-results +// ignore-emscripten + +// Emscripten doesn't flush its own stdout buffers on exit, which would fail +// this test. So this test is disabled on this platform. +// See https://emscripten.org/docs/getting_started/FAQ.html#what-does-exiting-the-runtime-mean-why-don-t-atexit-s-run + +#![feature(rustc_private)] + +extern crate libc; + +fn main() { + extern "C" fn bye() { + print!(", world!"); + } + unsafe { libc::atexit(bye) }; + print!("hello"); +} diff --git a/src/test/ui/stdout-during-shutdown.run.stdout b/src/test/ui/stdout-during-shutdown.run.stdout new file mode 100644 index 0000000000..30f51a3fba --- /dev/null +++ b/src/test/ui/stdout-during-shutdown.run.stdout @@ -0,0 +1 @@ +hello, world! \ No newline at end of file diff --git a/src/test/ui/str-concat.rs b/src/test/ui/str-concat.rs deleted file mode 100644 index fa2fc97d7b..0000000000 --- a/src/test/ui/str-concat.rs +++ /dev/null @@ -1,9 +0,0 @@ -// run-pass - -pub fn main() { - let a: String = "hello".to_string(); - let b: String = "world".to_string(); - let s: String = format!("{}{}", a, b); - println!("{}", s.clone()); - assert_eq!(s.as_bytes()[9], 'd' as u8); -} diff --git a/src/test/ui/str-multiline.rs b/src/test/ui/str-multiline.rs deleted file mode 100644 index 2b2e001d8b..0000000000 --- a/src/test/ui/str-multiline.rs +++ /dev/null @@ -1,13 +0,0 @@ -// run-pass - -pub fn main() { - let a: String = "this \ -is a test".to_string(); - let b: String = - "this \ - is \ - another \ - test".to_string(); - assert_eq!(a, "this is a test".to_string()); - assert_eq!(b, "this is another test".to_string()); -} diff --git a/src/test/ui/str/str-array-assignment.stderr b/src/test/ui/str/str-array-assignment.stderr index 52d3aefe12..73c03f09f2 100644 --- a/src/test/ui/str/str-array-assignment.stderr +++ b/src/test/ui/str/str-array-assignment.stderr @@ -21,7 +21,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | let v = s[..2]; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: all local variables must have a statically known size = help: unsized locals are gated as an unstable feature help: consider borrowing here diff --git a/src/test/ui/str/str-concat-on-double-ref.rs b/src/test/ui/str/str-concat-on-double-ref.rs index 23e5f89206..e68210d53b 100644 --- a/src/test/ui/str/str-concat-on-double-ref.rs +++ b/src/test/ui/str/str-concat-on-double-ref.rs @@ -2,6 +2,6 @@ fn main() { let a: &String = &"1".to_owned(); let b: &str = &"2"; let c = a + b; - //~^ ERROR cannot add `&str` to `&std::string::String` + //~^ ERROR cannot add `&str` to `&String` println!("{:?}", c); } diff --git a/src/test/ui/str/str-concat-on-double-ref.stderr b/src/test/ui/str/str-concat-on-double-ref.stderr index d77e0d8f24..ac87d6ecca 100644 --- a/src/test/ui/str/str-concat-on-double-ref.stderr +++ b/src/test/ui/str/str-concat-on-double-ref.stderr @@ -1,11 +1,11 @@ -error[E0369]: cannot add `&str` to `&std::string::String` +error[E0369]: cannot add `&str` to `&String` --> $DIR/str-concat-on-double-ref.rs:4:15 | LL | let c = a + b; | - ^ - &str | | | | | `+` cannot be used to concatenate two `&str` strings - | &std::string::String + | &String | help: `to_owned()` can be used to create an owned `String` from a string reference. String concatenation appends the string on the right to the string on the left and may require reallocation. This requires ownership of the string on the left | diff --git a/src/test/ui/str/str-idx.stderr b/src/test/ui/str/str-idx.stderr index 9f21aaaeba..f323ba03c0 100644 --- a/src/test/ui/str/str-idx.stderr +++ b/src/test/ui/str/str-idx.stderr @@ -4,10 +4,10 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _: u8 = s[4]; | ^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book - = note: required because of the requirements on the impl of `std::ops::Index<{integer}>` for `str` + for more information, see chapter 8 in The Book: + = note: required because of the requirements on the impl of `Index<{integer}>` for `str` error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:4:19 @@ -15,9 +15,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _ = s.get(4); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-idx.rs:5:29 @@ -25,9 +25,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | let _ = s.get_unchecked(4); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-idx.rs:6:17 @@ -35,8 +35,8 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | let _: u8 = s['c']; | ^^^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `char` - = note: required because of the requirements on the impl of `std::ops::Index` for `str` + = help: the trait `SliceIndex` is not implemented for `char` + = note: required because of the requirements on the impl of `Index` for `str` error: aborting due to 4 previous errors diff --git a/src/test/ui/str/str-mut-idx.stderr b/src/test/ui/str/str-mut-idx.stderr index 7c834165e7..405542820a 100644 --- a/src/test/ui/str/str-mut-idx.stderr +++ b/src/test/ui/str/str-mut-idx.stderr @@ -7,7 +7,7 @@ LL | fn bot() -> T { loop {} } LL | s[1..2] = bot(); | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` help: consider relaxing the implicit `Sized` restriction | LL | fn bot() -> T { loop {} } @@ -19,7 +19,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | s[1..2] = bot(); | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: the left-hand-side of an assignment must have a statically known size error[E0277]: the type `str` cannot be indexed by `usize` @@ -28,8 +28,8 @@ error[E0277]: the type `str` cannot be indexed by `usize` LL | s[1usize] = bot(); | ^^^^^^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `usize` - = note: required because of the requirements on the impl of `std::ops::Index` for `str` + = help: the trait `SliceIndex` is not implemented for `usize` + = note: required because of the requirements on the impl of `Index` for `str` error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-mut-idx.rs:9:15 @@ -37,9 +37,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | s.get_mut(1); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `{integer}` --> $DIR/str-mut-idx.rs:11:25 @@ -47,9 +47,9 @@ error[E0277]: the type `str` cannot be indexed by `{integer}` LL | s.get_unchecked_mut(1); | ^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `{integer}` + = help: the trait `SliceIndex` is not implemented for `{integer}` = note: you can use `.chars().nth()` or `.bytes().nth()` - see chapter in The Book + for more information, see chapter 8 in The Book: error[E0277]: the type `str` cannot be indexed by `char` --> $DIR/str-mut-idx.rs:13:5 @@ -57,8 +57,8 @@ error[E0277]: the type `str` cannot be indexed by `char` LL | s['c']; | ^^^^^^ string indices are ranges of `usize` | - = help: the trait `std::slice::SliceIndex` is not implemented for `char` - = note: required because of the requirements on the impl of `std::ops::Index` for `str` + = help: the trait `SliceIndex` is not implemented for `char` + = note: required because of the requirements on the impl of `Index` for `str` error: aborting due to 6 previous errors diff --git a/src/test/ui/string-escapes.rs b/src/test/ui/string-escapes.rs deleted file mode 100644 index cee5e27786..0000000000 --- a/src/test/ui/string-escapes.rs +++ /dev/null @@ -1,7 +0,0 @@ -// run-pass - -fn main() { - let x = "\\\\\ - "; - assert_eq!(x, r"\\"); // extraneous whitespace stripped -} diff --git a/src/test/ui/structs/struct-field-cfg.stderr b/src/test/ui/structs/struct-field-cfg.stderr index 29bad31ef9..b913b92907 100644 --- a/src/test/ui/structs/struct-field-cfg.stderr +++ b/src/test/ui/structs/struct-field-cfg.stderr @@ -17,6 +17,15 @@ error[E0027]: pattern does not mention field `present` | LL | let Foo { #[cfg(any())] present: () } = foo; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing field `present` + | +help: include the missing field in the pattern + | +LL | let Foo { present } = foo; + | ^^^^^^^^^^^ +help: if you don't care about this missing field, you can explicitely ignore it + | +LL | let Foo { .. } = foo; + | ^^^^^^ error[E0026]: struct `Foo` does not have a field named `absent` --> $DIR/struct-field-cfg.rs:16:42 diff --git a/src/test/ui/structs/struct-field-privacy.rs b/src/test/ui/structs/struct-field-privacy.rs index 5c35c04a69..898ca475cb 100644 --- a/src/test/ui/structs/struct-field-privacy.rs +++ b/src/test/ui/structs/struct-field-privacy.rs @@ -32,7 +32,7 @@ fn test(a: A, b: inner::A, c: inner::B, d: xc::A, e: xc::B, z: inner::Z) { e.b; //~ ERROR: field `b` of struct `xc::B` is private z.0; - z.1; //~ ERROR: field `1` of struct `inner::Z` is private + z.1; //~ ERROR: field `1` of struct `Z` is private } fn main() {} diff --git a/src/test/ui/structs/struct-field-privacy.stderr b/src/test/ui/structs/struct-field-privacy.stderr index f8b16ec0d0..ee83e0d6c2 100644 --- a/src/test/ui/structs/struct-field-privacy.stderr +++ b/src/test/ui/structs/struct-field-privacy.stderr @@ -22,7 +22,7 @@ error[E0616]: field `b` of struct `xc::B` is private LL | e.b; | ^ private field -error[E0616]: field `1` of struct `inner::Z` is private +error[E0616]: field `1` of struct `Z` is private --> $DIR/struct-field-privacy.rs:35:7 | LL | z.1; diff --git a/src/test/ui/structs/struct-pat-derived-error.stderr b/src/test/ui/structs/struct-pat-derived-error.stderr index 6526ef58a4..f3e9ce76f1 100644 --- a/src/test/ui/structs/struct-pat-derived-error.stderr +++ b/src/test/ui/structs/struct-pat-derived-error.stderr @@ -15,6 +15,15 @@ error[E0027]: pattern does not mention fields `b`, `c` | LL | let A { x, y } = self.d; | ^^^^^^^^^^ missing fields `b`, `c` + | +help: include the missing fields in the pattern + | +LL | let A { x, y, b, c } = self.d; + | ^^^^^^ +help: if you don't care about these missing fields, you can explicitely ignore them + | +LL | let A { x, y, .. } = self.d; + | ^^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/structs/struct-path-alias-bounds.rs b/src/test/ui/structs/struct-path-alias-bounds.rs index ae6ca80826..1e2c4b836a 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.rs +++ b/src/test/ui/structs/struct-path-alias-bounds.rs @@ -7,5 +7,5 @@ type A = S; fn main() { let s = A { a: NoClone }; - //~^ ERROR the trait bound `NoClone: std::clone::Clone` is not satisfied + //~^ ERROR the trait bound `NoClone: Clone` is not satisfied } diff --git a/src/test/ui/structs/struct-path-alias-bounds.stderr b/src/test/ui/structs/struct-path-alias-bounds.stderr index 1c2c205e01..cea3d5d4df 100644 --- a/src/test/ui/structs/struct-path-alias-bounds.stderr +++ b/src/test/ui/structs/struct-path-alias-bounds.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `NoClone: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `NoClone: Clone` is not satisfied --> $DIR/struct-path-alias-bounds.rs:9:13 | LL | struct S { a: T } | ------------------ required by `S` ... LL | let s = A { a: NoClone }; - | ^ the trait `std::clone::Clone` is not implemented for `NoClone` + | ^ the trait `Clone` is not implemented for `NoClone` error: aborting due to previous error diff --git a/src/test/ui/substs-ppaux.normal.stderr b/src/test/ui/substs-ppaux.normal.stderr index 8dab8add80..89be3d29e0 100644 --- a/src/test/ui/substs-ppaux.normal.stderr +++ b/src/test/ui/substs-ppaux.normal.stderr @@ -79,7 +79,7 @@ LL | fn bar<'a, T>() where T: 'a {} LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required because of the requirements on the impl of `Foo<'_, '_, u8>` for `str` error: aborting due to 5 previous errors diff --git a/src/test/ui/substs-ppaux.verbose.stderr b/src/test/ui/substs-ppaux.verbose.stderr index a40d5e4bf7..e37d087fcc 100644 --- a/src/test/ui/substs-ppaux.verbose.stderr +++ b/src/test/ui/substs-ppaux.verbose.stderr @@ -79,7 +79,7 @@ LL | fn bar<'a, T>() where T: 'a {} LL | >::bar; | ^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: required because of the requirements on the impl of `Foo<'_#0r, '_#1r, u8>` for `str` error: aborting due to 5 previous errors diff --git a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr index f4c0d0f96c..9450612332 100644 --- a/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr +++ b/src/test/ui/suggestions/adt-param-with-implicit-sized-bound.stderr @@ -5,7 +5,7 @@ LL | struct X(T); | - required by this bound in `X` ... LL | struct Struct5{ - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | _t: X, | ^^^^ doesn't have a size known at compile-time | @@ -28,8 +28,8 @@ LL | struct Struct1{ | help: consider further restricting `Self` | -LL | fn func1() -> Struct1 where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func1() -> Struct1 where Self: Sized; + | ^^^^^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | struct Struct1{ @@ -46,8 +46,8 @@ LL | struct Struct2<'a, T>{ | help: consider further restricting `Self` | -LL | fn func2<'a>() -> Struct2<'a, Self> where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func2<'a>() -> Struct2<'a, Self> where Self: Sized; + | ^^^^^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | struct Struct2<'a, T: ?Sized>{ @@ -71,8 +71,8 @@ LL | _t: T, | - ...if indirection was used here: `Box` help: consider further restricting `Self` | -LL | fn func3() -> Struct3 where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func3() -> Struct3 where Self: Sized; + | ^^^^^^^^^^^^^^^^^ error[E0277]: the size for values of type `Self` cannot be known at compilation time --> $DIR/adt-param-with-implicit-sized-bound.rs:5:19 @@ -85,8 +85,8 @@ LL | struct Struct4{ | help: consider further restricting `Self` | -LL | fn func4() -> Struct4 where Self: std::marker::Sized; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn func4() -> Struct4 where Self: Sized; + | ^^^^^^^^^^^^^^^^^ help: consider relaxing the implicit `Sized` restriction | LL | struct Struct4{ diff --git a/src/test/ui/suggestions/as-ref.stderr b/src/test/ui/suggestions/as-ref.stderr index 8445a706f4..4b5a9be7e5 100644 --- a/src/test/ui/suggestions/as-ref.stderr +++ b/src/test/ui/suggestions/as-ref.stderr @@ -36,12 +36,12 @@ error[E0308]: mismatched types LL | let y: Option<&usize> = x; | -------------- ^ | | | - | | expected enum `std::option::Option`, found reference + | | expected enum `Option`, found `&Option` | | help: you can convert from `&Option` to `Option<&T>` using `.as_ref()`: `x.as_ref()` | expected due to this | - = note: expected enum `std::option::Option<&usize>` - found reference `&std::option::Option` + = note: expected enum `Option<&usize>` + found reference `&Option` error[E0308]: mismatched types --> $DIR/as-ref.rs:19:35 diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 1137249477..cb4acc4c39 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -1,4 +1,4 @@ -error[E0277]: `fn() -> impl std::future::Future {foo}` is not a future +error[E0277]: `fn() -> impl Future {foo}` is not a future --> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:10:9 | LL | async fn foo() {} @@ -8,9 +8,9 @@ LL | fn bar(f: impl Future) {} | ----------------- required by this bound in `bar` ... LL | bar(foo); - | ^^^ `fn() -> impl std::future::Future {foo}` is not a future + | ^^^ `fn() -> impl Future {foo}` is not a future | - = help: the trait `std::future::Future` is not implemented for `fn() -> impl std::future::Future {foo}` + = help: the trait `Future` is not implemented for `fn() -> impl Future {foo}` help: use parentheses to call the function | LL | bar(foo()); @@ -27,7 +27,7 @@ LL | let async_closure = async || (); 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 | - = help: the trait `std::future::Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]` + = 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]` help: use parentheses to call the closure | LL | bar(async_closure()); diff --git a/src/test/ui/suggestions/borrow-for-loop-head.stderr b/src/test/ui/suggestions/borrow-for-loop-head.stderr index 36bced9e43..de342a969f 100644 --- a/src/test/ui/suggestions/borrow-for-loop-head.stderr +++ b/src/test/ui/suggestions/borrow-for-loop-head.stderr @@ -10,7 +10,7 @@ error[E0382]: use of moved value: `a` --> $DIR/borrow-for-loop-head.rs:4:18 | LL | let a = vec![1, 2, 3]; - | - move occurs because `a` has type `std::vec::Vec`, which does not implement the `Copy` trait + | - move occurs because `a` has type `Vec`, which does not implement the `Copy` trait LL | for i in &a { LL | for j in a { | ^ diff --git a/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr b/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr index 63e3bb7895..965dbb9679 100644 --- a/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr +++ b/src/test/ui/suggestions/chain-method-call-mutation-in-place.stderr @@ -2,9 +2,9 @@ error[E0308]: mismatched types --> $DIR/chain-method-call-mutation-in-place.rs:3:5 | LL | fn foo(mut s: String) -> String { - | ------ expected `std::string::String` because of return type + | ------ expected `String` because of return type LL | s.push_str("asdf") - | ^^^^^^^^^^^^^^^^^^ expected struct `std::string::String`, found `()` + | ^^^^^^^^^^^^^^^^^^ expected struct `String`, found `()` | note: method `push_str` modifies its receiver in-place --> $DIR/chain-method-call-mutation-in-place.rs:3:7 diff --git a/src/test/ui/suggestions/const-in-struct-pat.stderr b/src/test/ui/suggestions/const-in-struct-pat.stderr index ab336b14d2..df9c230eef 100644 --- a/src/test/ui/suggestions/const-in-struct-pat.stderr +++ b/src/test/ui/suggestions/const-in-struct-pat.stderr @@ -7,7 +7,7 @@ LL | struct foo; LL | let Thing { foo } = t; | ^^^ - this expression has type `Thing` | | - | expected struct `std::string::String`, found struct `foo` + | expected struct `String`, found struct `foo` | `foo` is interpreted as a unit struct, not a new binding | help: bind the struct field to a different name instead diff --git a/src/test/ui/suggestions/const-no-type.rs b/src/test/ui/suggestions/const-no-type.rs index b931a04c28..2ffb24c6e6 100644 --- a/src/test/ui/suggestions/const-no-type.rs +++ b/src/test/ui/suggestions/const-no-type.rs @@ -43,7 +43,7 @@ const D = &&42; static S = Vec::::new(); //~^ ERROR missing type for `static` item //~| HELP provide a type for the item -//~| SUGGESTION S: std::vec::Vec +//~| SUGGESTION S: Vec static mut SM = "abc"; //~^ ERROR missing type for `static mut` item diff --git a/src/test/ui/suggestions/const-no-type.stderr b/src/test/ui/suggestions/const-no-type.stderr index 874c1bac10..b180a6a9a9 100644 --- a/src/test/ui/suggestions/const-no-type.stderr +++ b/src/test/ui/suggestions/const-no-type.stderr @@ -14,7 +14,7 @@ error: missing type for `static` item --> $DIR/const-no-type.rs:43:8 | LL | static S = Vec::::new(); - | ^ help: provide a type for the item: `S: std::vec::Vec` + | ^ help: provide a type for the item: `S: Vec` error: missing type for `static mut` item --> $DIR/const-no-type.rs:48:12 diff --git a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr index b0cef952b2..0123e617c4 100644 --- a/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr +++ b/src/test/ui/suggestions/dont-suggest-deref-inside-macro-issue-58298.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | / intrinsic_match! { LL | | "abc" LL | | }; - | |______^ expected `&str`, found struct `std::string::String` + | |______^ expected `&str`, found struct `String` | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr index 5550e097cf..f7528b5ccd 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr @@ -112,7 +112,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:102:17 | LL | let X(_t) = vs[0]; @@ -121,7 +121,7 @@ LL | let X(_t) = vs[0]; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:106:30 | LL | if let Either::One(_t) = vr[0] { } @@ -130,7 +130,7 @@ LL | if let Either::One(_t) = vr[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:110:33 | LL | while let Either::One(_t) = vr[0] { } @@ -139,7 +139,7 @@ LL | while let Either::One(_t) = vr[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:114:11 | LL | match vr[0] { @@ -151,7 +151,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:121:11 | LL | match vr[0] { @@ -163,7 +163,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:130:17 | LL | let X(_t) = vsm[0]; @@ -172,7 +172,7 @@ LL | let X(_t) = vsm[0]; | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:134:30 | LL | if let Either::One(_t) = vrm[0] { } @@ -181,7 +181,7 @@ LL | if let Either::One(_t) = vrm[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:138:33 | LL | while let Either::One(_t) = vrm[0] { } @@ -190,7 +190,7 @@ LL | while let Either::One(_t) = vrm[0] { } | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:142:11 | LL | match vrm[0] { @@ -202,7 +202,7 @@ LL | Either::One(_t) | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:149:11 | LL | match vrm[0] { @@ -214,7 +214,7 @@ LL | Either::One(_t) => (), | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait -error[E0507]: cannot move out of index of `std::vec::Vec` +error[E0507]: cannot move out of index of `Vec` --> $DIR/simple.rs:157:11 | LL | match vrm[0] { diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index baa84115e2..32961b7f87 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -2,27 +2,27 @@ error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:11:5 | LL | fn foo + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - | - this type parameter ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type + | - this type parameter ----------------------- expected `Pin + Send + 'static)>>` because of return type LL | // We could instead use an `async` block, but this way we have no std spans. LL | x | ^ | | - | expected struct `std::pin::Pin`, found type parameter `F` + | expected struct `Pin`, found type parameter `F` | help: you need to pin and box this expression: `Box::pin(x)` | - = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` + = note: expected struct `Pin + Send + 'static)>>` found type parameter `F` error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:18:5 | LL | fn bar + Send + 'static>(x: F) -> BoxFuture<'static, i32> { - | ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type + | ----------------------- expected `Pin + Send + 'static)>>` because of return type LL | Box::new(x) - | ^^^^^^^^^^^ expected struct `std::pin::Pin`, found struct `std::boxed::Box` + | ^^^^^^^^^^^ expected struct `Pin`, found struct `Box` | - = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` - found struct `std::boxed::Box` + = note: expected struct `Pin + Send + 'static)>>` + found struct `Box` = help: use `Box::pin` error[E0308]: mismatched types @@ -33,48 +33,46 @@ LL | fn baz + Send + 'static>(x: F) -> BoxFuture<'static, LL | Pin::new(x) | ^ | | - | expected struct `std::boxed::Box`, found type parameter `F` + | expected struct `Box`, found type parameter `F` | help: store this in the heap by calling `Box::new`: `Box::new(x)` | - = note: expected struct `std::boxed::Box + std::marker::Send>` + = 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 -error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned +error[E0277]: `dyn Future + Send` cannot be unpinned --> $DIR/expected-boxed-future-isnt-pinned.rs:22:5 | LL | Pin::new(x) - | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` + | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future + Send` | - = note: consider using `Box::pin` - = note: required by `std::pin::Pin::

    ::new` + = note: required by `Pin::

    ::new` -error[E0277]: `dyn std::future::Future + std::marker::Send` cannot be unpinned +error[E0277]: `dyn Future + Send` cannot be unpinned --> $DIR/expected-boxed-future-isnt-pinned.rs:27:5 | LL | Pin::new(Box::new(x)) - | ^^^^^^^^ the trait `std::marker::Unpin` is not implemented for `dyn std::future::Future + std::marker::Send` + | ^^^^^^^^ the trait `Unpin` is not implemented for `dyn Future + Send` | - = note: consider using `Box::pin` - = note: required by `std::pin::Pin::

    ::new` + = note: required by `Pin::

    ::new` error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:31:5 | LL | fn zap() -> BoxFuture<'static, i32> { - | ----------------------- expected `std::pin::Pin + std::marker::Send + 'static)>>` because of return type + | ----------------------- expected `Pin + Send + 'static)>>` because of return type LL | / async { LL | | 42 LL | | } - | |_____^ expected struct `std::pin::Pin`, found opaque type + | |_____^ expected struct `Pin`, found opaque type | ::: $SRC_DIR/core/src/future/mod.rs:LL:COL | LL | pub const fn from_generator(gen: T) -> impl Future | ------------------------------- the found opaque type | - = note: expected struct `std::pin::Pin + std::marker::Send + 'static)>>` - found opaque type `impl std::future::Future` + = note: expected struct `Pin + Send + 'static)>>` + found opaque type `impl Future` help: you need to pin and box this expression | LL | Box::pin(async { diff --git a/src/test/ui/suggestions/for-i-in-vec.stderr b/src/test/ui/suggestions/for-i-in-vec.stderr index 576a7cc2f6..48f3f423ac 100644 --- a/src/test/ui/suggestions/for-i-in-vec.stderr +++ b/src/test/ui/suggestions/for-i-in-vec.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `self.v` which is behind a shared reference LL | for _ in self.v { | ^^^^^^ | | - | move occurs because `self.v` has type `std::vec::Vec`, which does not implement the `Copy` trait + | move occurs because `self.v` has type `Vec`, which does not implement the `Copy` trait | help: consider iterating over a slice of the `Vec<_>`'s content: `&self.v` error: aborting due to previous error diff --git a/src/test/ui/suggestions/format-borrow.stderr b/src/test/ui/suggestions/format-borrow.stderr index 44fac16260..05d8fcd3ed 100644 --- a/src/test/ui/suggestions/format-borrow.stderr +++ b/src/test/ui/suggestions/format-borrow.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | let a: String = &String::from("a"); | ------ ^^^^^^^^^^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&std::string::String` + | | expected struct `String`, found `&String` | | help: consider removing the borrow: `String::from("a")` | expected due to this @@ -14,7 +14,7 @@ error[E0308]: mismatched types LL | let b: String = &format!("b"); | ------ ^^^^^^^^^^^^^ | | | - | | expected struct `std::string::String`, found `&std::string::String` + | | expected struct `String`, found `&String` | | help: consider removing the borrow: `format!("b")` | expected due to this diff --git a/src/test/ui/suggestions/if-let-typo.rs b/src/test/ui/suggestions/if-let-typo.rs new file mode 100644 index 0000000000..87def13c47 --- /dev/null +++ b/src/test/ui/suggestions/if-let-typo.rs @@ -0,0 +1,8 @@ +fn main() { + let foo = Some(0); + let bar = None; + if Some(x) = foo {} //~ ERROR cannot find value `x` in this scope + if Some(foo) = bar {} //~ ERROR mismatched types + if 3 = foo {} //~ ERROR mismatched types + if Some(3) = foo {} //~ ERROR mismatched types +} diff --git a/src/test/ui/suggestions/if-let-typo.stderr b/src/test/ui/suggestions/if-let-typo.stderr new file mode 100644 index 0000000000..d8e50cae55 --- /dev/null +++ b/src/test/ui/suggestions/if-let-typo.stderr @@ -0,0 +1,56 @@ +error[E0425]: cannot find value `x` in this scope + --> $DIR/if-let-typo.rs:4:13 + | +LL | if Some(x) = foo {} + | ^ not found in this scope + | +help: you might have meant to use pattern matching + | +LL | if let Some(x) = foo {} + | ^^^ + +error[E0308]: mismatched types + --> $DIR/if-let-typo.rs:5:8 + | +LL | if Some(foo) = bar {} + | ^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let Some(foo) = bar {} + | ^^^ +help: you might have meant to compare for equality + | +LL | if Some(foo) == bar {} + | ^^ + +error[E0308]: mismatched types + --> $DIR/if-let-typo.rs:6:8 + | +LL | if 3 = foo {} + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let 3 = foo {} + | ^^^ + +error[E0308]: mismatched types + --> $DIR/if-let-typo.rs:7:8 + | +LL | if Some(3) = foo {} + | ^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let Some(3) = foo {} + | ^^^ +help: you might have meant to compare for equality + | +LL | if Some(3) == foo {} + | ^^ + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0308, E0425. +For more information about an error, try `rustc --explain E0308`. diff --git a/src/test/ui/suggestions/imm-ref-trait-object.stderr b/src/test/ui/suggestions/imm-ref-trait-object.stderr index cbaed41cf9..9f89dcd912 100644 --- a/src/test/ui/suggestions/imm-ref-trait-object.stderr +++ b/src/test/ui/suggestions/imm-ref-trait-object.stderr @@ -9,7 +9,7 @@ LL | t.min().unwrap() LL | Self: Sized, | ----- this has a `Sized` requirement | - = note: you need `&mut dyn std::iter::Iterator` instead of `&dyn std::iter::Iterator` + = note: you need `&mut dyn Iterator` instead of `&dyn Iterator` error: aborting due to previous error diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs index 6e9e8821cf..d401328077 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.rs @@ -4,7 +4,7 @@ fn foo(constraints: impl Iterator) { for constraint in constraints { qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } @@ -12,7 +12,7 @@ fn bar(t: T, constraints: impl Iterator) where T: std::fmt::Debug { for constraint in constraints { qux(t); qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } @@ -20,7 +20,7 @@ fn baz(t: impl std::fmt::Debug, constraints: impl Iterator) { for constraint in constraints { qux(t); qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } @@ -28,14 +28,14 @@ fn bat(t: T, constraints: impl Iterator, _: I) { for constraint in constraints { qux(t); qux(constraint); -//~^ ERROR `::Item` doesn't implement `std::fmt::Debug` +//~^ ERROR `::Item` doesn't implement `Debug` } } fn bak(constraints: impl Iterator + std::fmt::Debug) { for constraint in constraints { qux(constraint); -//~^ ERROR `::Item` doesn't implement +//~^ ERROR `::Item` doesn't implement } } diff --git a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr index fb0914a874..099eb1c9d0 100644 --- a/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr +++ b/src/test/ui/suggestions/impl-trait-with-missing-bounds.stderr @@ -1,77 +1,77 @@ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:6:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn foo(constraints: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo(constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:14:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bar(t: T, constraints: I) where T: std::fmt::Debug, ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(t: T, constraints: I) where T: std::fmt::Debug, ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:22:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn baz(t: impl std::fmt::Debug, constraints: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn baz(t: impl std::fmt::Debug, constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:30:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bat(t: T, constraints: U, _: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bat(t: T, constraints: U, _: I) where ::Item: Debug { + | ^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: `::Item` doesn't implement `std::fmt::Debug` +error[E0277]: `::Item` doesn't implement `Debug` --> $DIR/impl-trait-with-missing-bounds.rs:37:13 | LL | qux(constraint); - | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | ^^^^^^^^^^ `::Item` cannot be formatted using `{:?}` because it doesn't implement `Debug` ... LL | fn qux(_: impl std::fmt::Debug) {} | --------------- required by this bound in `qux` | - = help: the trait `std::fmt::Debug` is not implemented for `::Item` + = help: the trait `Debug` is not implemented for `::Item` help: introduce a type parameter with a trait bound instead of using `impl Trait` | -LL | fn bak(constraints: I) where ::Item: std::fmt::Debug { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bak(constraints: I) where ::Item: Debug { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to 5 previous errors diff --git a/src/test/ui/suggestions/into-str.rs b/src/test/ui/suggestions/into-str.rs index 9793ee801d..606e44b2eb 100644 --- a/src/test/ui/suggestions/into-str.rs +++ b/src/test/ui/suggestions/into-str.rs @@ -2,5 +2,5 @@ fn foo<'a, T>(_t: T) where T: Into<&'a str> {} fn main() { foo(String::new()); - //~^ ERROR the trait bound `&str: std::convert::From` is not satisfied + //~^ ERROR the trait bound `&str: From` is not satisfied } diff --git a/src/test/ui/suggestions/into-str.stderr b/src/test/ui/suggestions/into-str.stderr index f7affdbf1b..2854b830ba 100644 --- a/src/test/ui/suggestions/into-str.stderr +++ b/src/test/ui/suggestions/into-str.stderr @@ -1,14 +1,13 @@ -error[E0277]: the trait bound `&str: std::convert::From` is not satisfied +error[E0277]: the trait bound `&str: From` is not satisfied --> $DIR/into-str.rs:4:5 | LL | fn foo<'a, T>(_t: T) where T: Into<&'a str> {} | ------------- required by this bound in `foo` ... LL | foo(String::new()); - | ^^^ the trait `std::convert::From` is not implemented for `&str` + | ^^^ the trait `From` is not implemented for `&str` | - = note: to coerce a `std::string::String` into a `&str`, use `&*` as a prefix - = note: required because of the requirements on the impl of `std::convert::Into<&str>` for `std::string::String` + = note: required because of the requirements on the impl of `Into<&str>` for `String` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-52820.stderr b/src/test/ui/suggestions/issue-52820.stderr index 5ad6597b82..ece784de3e 100644 --- a/src/test/ui/suggestions/issue-52820.stderr +++ b/src/test/ui/suggestions/issue-52820.stderr @@ -4,7 +4,7 @@ error[E0308]: mismatched types LL | guts, | ^^^^ | | - | expected struct `std::string::String`, found `&str` + | expected struct `String`, found `&str` | help: try using a conversion method: `guts: guts.to_string()` error[E0308]: mismatched types @@ -13,7 +13,7 @@ error[E0308]: mismatched types LL | brains: guts.clone(), | ^^^^^^^^^^^^ | | - | expected struct `std::string::String`, found `&str` + | expected struct `String`, found `&str` | help: try using a conversion method: `guts.to_string()` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/issue-59819.stderr b/src/test/ui/suggestions/issue-59819.stderr index b20327a9ff..43e0016ee2 100644 --- a/src/test/ui/suggestions/issue-59819.stderr +++ b/src/test/ui/suggestions/issue-59819.stderr @@ -24,7 +24,7 @@ error[E0308]: mismatched types LL | let g: String = f; | ------ ^ | | | - | | expected struct `std::string::String`, found struct `Bar` + | | expected struct `String`, found struct `Bar` | | help: try using a conversion method: `f.to_string()` | expected due to this diff --git a/src/test/ui/suggestions/issue-62843.stderr b/src/test/ui/suggestions/issue-62843.stderr index 3b7f85c566..b2be09a4c7 100644 --- a/src/test/ui/suggestions/issue-62843.stderr +++ b/src/test/ui/suggestions/issue-62843.stderr @@ -1,14 +1,14 @@ -error[E0277]: expected a `std::ops::FnMut<(char,)>` closure, found `std::string::String` +error[E0277]: expected a `FnMut<(char,)>` closure, found `String` --> $DIR/issue-62843.rs:4:32 | LL | println!("{:?}", line.find(pattern)); | ^^^^^^^ | | - | expected an implementor of trait `std::str::pattern::Pattern<'_>` + | expected an implementor of trait `Pattern<'_>` | help: consider borrowing here: `&pattern` | - = note: the trait bound `std::string::String: std::str::pattern::Pattern<'_>` is not satisfied - = note: required because of the requirements on the impl of `std::str::pattern::Pattern<'_>` for `std::string::String` + = note: the trait bound `String: Pattern<'_>` is not satisfied + = note: required because of the requirements on the impl of `Pattern<'_>` for `String` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.rs b/src/test/ui/suggestions/issue-71394-no-from-impl.rs index 9ffcc3f7bc..0c35deb51e 100644 --- a/src/test/ui/suggestions/issue-71394-no-from-impl.rs +++ b/src/test/ui/suggestions/issue-71394-no-from-impl.rs @@ -1,5 +1,5 @@ fn main() { let data: &[u8] = &[0; 10]; let _: &[i8] = data.into(); - //~^ ERROR the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied + //~^ ERROR the trait bound `&[i8]: From<&[u8]>` is not satisfied } diff --git a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr index 84c73c2f67..355f2038df 100644 --- a/src/test/ui/suggestions/issue-71394-no-from-impl.stderr +++ b/src/test/ui/suggestions/issue-71394-no-from-impl.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `&[i8]: std::convert::From<&[u8]>` is not satisfied +error[E0277]: the trait bound `&[i8]: From<&[u8]>` is not satisfied --> $DIR/issue-71394-no-from-impl.rs:3:25 | LL | let _: &[i8] = data.into(); - | ^^^^ the trait `std::convert::From<&[u8]>` is not implemented for `&[i8]` + | ^^^^ the trait `From<&[u8]>` is not implemented for `&[i8]` | - = note: required because of the requirements on the impl of `std::convert::Into<&[i8]>` for `&[u8]` + = note: required because of the requirements on the impl of `Into<&[i8]>` for `&[u8]` error: aborting due to previous error diff --git a/src/test/ui/suggestions/issue-72766.stderr b/src/test/ui/suggestions/issue-72766.stderr index 4290f3b4bf..a1a5949b19 100644 --- a/src/test/ui/suggestions/issue-72766.stderr +++ b/src/test/ui/suggestions/issue-72766.stderr @@ -1,14 +1,14 @@ -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/issue-72766.rs:14:5 | LL | SadGirl {}.call()?; | ^^^^^^^^^^^^^^^^^^ | | - | the `?` operator cannot be applied to type `impl std::future::Future` + | the `?` operator cannot be applied to type `impl Future` | help: consider using `.await` here: `SadGirl {}.call().await?` | - = help: the trait `std::ops::Try` is not implemented for `impl std::future::Future` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `impl Future` + = note: required by `into_result` error: aborting due to previous error diff --git a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr index cec01fefca..69e95efa72 100644 --- a/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr +++ b/src/test/ui/suggestions/lifetimes/missing-lifetimes-in-signature.stderr @@ -41,7 +41,7 @@ LL | | LL | | where LL | | G: Get | |_____________^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6 g:G, dest:&mut T]` will meet its required lifetime bounds +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:30:5: 32:6]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:25:37 | LL | fn bar(g: G, dest: &mut T) -> impl FnOnce() + '_ @@ -65,7 +65,7 @@ LL | | LL | | where LL | | G: Get | |_____________^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6 g:G, dest:&mut T]` will meet its required lifetime bounds +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:52:5: 54:6]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:47:45 | LL | fn qux<'a, G: 'a, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ @@ -86,7 +86,7 @@ note: the parameter type `G` must be valid for the anonymous lifetime #1 defined | LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10 g:G, dest:&mut T]` will meet its required lifetime bounds +note: ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:61:9: 63:10]` will meet its required lifetime bounds --> $DIR/missing-lifetimes-in-signature.rs:59:58 | LL | fn qux<'b, G: Get + 'b, T>(g: G, dest: &mut T) -> impl FnOnce() + '_ { @@ -108,7 +108,7 @@ error[E0309]: the parameter type `G` may not live long enough --> $DIR/missing-lifetimes-in-signature.rs:79:44 | LL | fn bak<'a, G, T>(g: G, dest: &'a mut T) -> impl FnOnce() + 'a - | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6 g:G, dest:&mut T]` will meet its required lifetime bounds + | - ^^^^^^^^^^^^^^^^^^ ...so that the type `[closure@$DIR/missing-lifetimes-in-signature.rs:84:5: 86:6]` will meet its required lifetime bounds | | | help: consider adding an explicit lifetime bound...: `G: 'a` diff --git a/src/test/ui/suggestions/match-ergonomics.stderr b/src/test/ui/suggestions/match-ergonomics.stderr index 559a2d2955..ca7562beb1 100644 --- a/src/test/ui/suggestions/match-ergonomics.stderr +++ b/src/test/ui/suggestions/match-ergonomics.stderr @@ -12,17 +12,17 @@ LL | [&v] => {}, = note: expected type `i32` found reference `&_` -error[E0529]: expected an array or slice, found `std::vec::Vec` +error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:8:9 | LL | [&v] => {}, - | ^^^^ pattern cannot match with input type `std::vec::Vec` + | ^^^^ pattern cannot match with input type `Vec` -error[E0529]: expected an array or slice, found `std::vec::Vec` +error[E0529]: expected an array or slice, found `Vec` --> $DIR/match-ergonomics.rs:20:9 | LL | [v] => {}, - | ^^^ pattern cannot match with input type `std::vec::Vec` + | ^^^ pattern cannot match with input type `Vec` error[E0308]: mismatched types --> $DIR/match-ergonomics.rs:29:9 diff --git a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed index 64a1aeae3e..a0cb39a3f8 100644 --- a/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed +++ b/src/test/ui/suggestions/missing-assoc-fn-applicable-suggestions.fixed @@ -13,7 +13,7 @@ struct S; struct Type; impl TraitA<()> for S { //~ ERROR not all trait items implemented -fn baz(_: T) -> Self where T: TraitB, ::Item: std::marker::Copy { todo!() } +fn baz(_: T) -> Self where T: TraitB, ::Item: Copy { todo!() } fn bar(_: T) -> Self { todo!() } type Type = Type; } diff --git a/src/test/ui/suggestions/missing-assoc-fn.stderr b/src/test/ui/suggestions/missing-assoc-fn.stderr index 4f75e2b838..136ec2152e 100644 --- a/src/test/ui/suggestions/missing-assoc-fn.stderr +++ b/src/test/ui/suggestions/missing-assoc-fn.stderr @@ -28,7 +28,7 @@ error[E0046]: not all trait items implemented, missing: `from_iter` LL | impl FromIterator<()> for X { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ missing `from_iter` in implementation | - = help: implement the missing item: `fn from_iter(_: T) -> Self where T: std::iter::IntoIterator, std::iter::IntoIterator::Item = A { todo!() }` + = help: implement the missing item: `fn from_iter(_: T) -> Self where T: IntoIterator, std::iter::IntoIterator::Item = A { todo!() }` error: aborting due to 3 previous errors diff --git a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr index c6d94826c0..eb695379b5 100644 --- a/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr +++ b/src/test/ui/suggestions/missing-trait-bounds-for-method-call.stderr @@ -10,12 +10,12 @@ LL | self.foo(); = note: the method `foo` exists but the following trait bounds were not satisfied: `T: Bar` which is required by `Foo: Bar` - `T: std::default::Default` + `T: Default` which is required by `Foo: Bar` help: consider restricting the type parameters to satisfy the trait bounds | -LL | struct Foo where T: Bar, T: std::default::Default { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct Foo where T: Bar, T: Default { + | ^^^^^^^^^^^^^^^^^^^^^^^^ error[E0599]: no method named `foo` found for reference `&Fin` in the current scope --> $DIR/missing-trait-bounds-for-method-call.rs:27:14 @@ -27,12 +27,12 @@ LL | self.foo(); | ^^^ method not found in `&Fin` | = note: the method `foo` exists but the following trait bounds were not satisfied: - `T: std::default::Default` + `T: Default` which is required by `Fin: Bar` help: consider restricting the type parameter to satisfy the trait bound | -LL | struct Fin where T: Bar, T: std::default::Default { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | struct Fin where T: Bar, T: Default { + | ^^^^^^^^^^^^ error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr index c3bb37cf83..c1eea56f70 100644 --- a/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr +++ b/src/test/ui/suggestions/mut-borrow-needed-by-trait.stderr @@ -5,7 +5,7 @@ LL | let fp = BufWriter::new(fp); | ^^ the trait `std::io::Write` is not implemented for `&dyn std::io::Write` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` - = note: required by `std::io::BufWriter::::new` + = note: required by `BufWriter::::new` error[E0277]: the trait bound `&dyn std::io::Write: std::io::Write` is not satisfied --> $DIR/mut-borrow-needed-by-trait.rs:17:14 @@ -16,7 +16,7 @@ LL | let fp = BufWriter::new(fp); ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL | LL | pub struct BufWriter { - | ----- required by this bound in `std::io::BufWriter` + | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` @@ -29,24 +29,24 @@ LL | let fp = BufWriter::new(fp); ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL | LL | pub struct BufWriter { - | ----- required by this bound in `std::io::BufWriter` + | ----- required by this bound in `BufWriter` | = note: `std::io::Write` is implemented for `&mut dyn std::io::Write`, but not for `&dyn std::io::Write` -error[E0599]: no method named `write_fmt` found for struct `std::io::BufWriter<&dyn std::io::Write>` in the current scope +error[E0599]: no method named `write_fmt` found for struct `BufWriter<&dyn std::io::Write>` in the current scope --> $DIR/mut-borrow-needed-by-trait.rs:22:5 | LL | writeln!(fp, "hello world").unwrap(); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `std::io::BufWriter<&dyn std::io::Write>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ method not found in `BufWriter<&dyn std::io::Write>` | ::: $SRC_DIR/std/src/io/buffered.rs:LL:COL | LL | pub struct BufWriter { - | ------------------------------ doesn't satisfy `_: std::io::Write` + | ------------------------------ doesn't satisfy `BufWriter<&dyn std::io::Write>: std::io::Write` | = note: the method `write_fmt` exists but the following trait bounds were not satisfied: `&dyn std::io::Write: std::io::Write` - which is required by `std::io::BufWriter<&dyn std::io::Write>: std::io::Write` + which is required by `BufWriter<&dyn std::io::Write>: std::io::Write` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/mut-ref-reassignment.stderr b/src/test/ui/suggestions/mut-ref-reassignment.stderr index e774800849..e31c4dc66c 100644 --- a/src/test/ui/suggestions/mut-ref-reassignment.stderr +++ b/src/test/ui/suggestions/mut-ref-reassignment.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:2:11 | LL | opt = None; - | ^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::option::Option` - found enum `std::option::Option<_>` + = note: expected mutable reference `&mut Option` + found enum `Option<_>` help: consider dereferencing here to assign to the mutable borrowed piece of memory | LL | *opt = None; @@ -15,19 +15,19 @@ error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:6:11 | LL | opt = None - | ^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::result::Result` - found enum `std::option::Option<_>` + = note: expected mutable reference `&mut std::result::Result` + found enum `Option<_>` error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:10:11 | LL | opt = Some(String::new()) - | ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^^^^^^^^^^^^^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::option::Option` - found enum `std::option::Option` + = note: expected mutable reference `&mut Option` + found enum `Option` help: consider dereferencing here to assign to the mutable borrowed piece of memory | LL | *opt = Some(String::new()) @@ -37,10 +37,10 @@ error[E0308]: mismatched types --> $DIR/mut-ref-reassignment.rs:14:11 | LL | opt = Some(42) - | ^^^^^^^^ expected mutable reference, found enum `std::option::Option` + | ^^^^^^^^ expected mutable reference, found enum `Option` | - = note: expected mutable reference `&mut std::option::Option` - found enum `std::option::Option<{integer}>` + = note: expected mutable reference `&mut Option` + found enum `Option<{integer}>` error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/opaque-type-error.stderr b/src/test/ui/suggestions/opaque-type-error.stderr index 167d61bdf7..a7c2b82942 100644 --- a/src/test/ui/suggestions/opaque-type-error.stderr +++ b/src/test/ui/suggestions/opaque-type-error.stderr @@ -13,10 +13,9 @@ LL | | thing_two() LL | | }.await | |_____- `if` and `else` have incompatible types | - = note: expected type `impl std::future::Future` (opaque type at <$DIR/opaque-type-error.rs:8:19>) - found opaque type `impl std::future::Future` (opaque type at <$DIR/opaque-type-error.rs:12:19>) + = note: expected type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:8:19>) + found opaque type `impl Future` (opaque type at <$DIR/opaque-type-error.rs:12:19>) = note: distinct uses of `impl Trait` result in different opaque types - = help: if both `Future`s have the same `Output` type, consider `.await`ing on both of them error: aborting due to previous error diff --git a/src/test/ui/suggestions/option-content-move.stderr b/src/test/ui/suggestions/option-content-move.stderr index c842e7b293..0f3dd346e8 100644 --- a/src/test/ui/suggestions/option-content-move.stderr +++ b/src/test/ui/suggestions/option-content-move.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared referenc LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ | | - | move occurs because `selection.1` has type `std::option::Option`, which does not implement the `Copy` trait + | move occurs because `selection.1` has type `Option`, which does not implement the `Copy` trait | help: consider borrowing the `Option`'s content: `selection.1.as_ref()` error[E0507]: cannot move out of `selection.1` which is behind a shared reference @@ -13,7 +13,7 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared referenc LL | if selection.1.unwrap().contains(selection.0) { | ^^^^^^^^^^^ | | - | move occurs because `selection.1` has type `std::result::Result`, which does not implement the `Copy` trait + | move occurs because `selection.1` has type `std::result::Result`, which does not implement the `Copy` trait | help: consider borrowing the `Result`'s content: `selection.1.as_ref()` error: aborting due to 2 previous errors diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr index 71f745374e..cfbee1518c 100644 --- a/src/test/ui/suggestions/option-content-move2.stderr +++ b/src/test/ui/suggestions/option-content-move2.stderr @@ -10,7 +10,7 @@ LL | LL | var = Some(NotCopyable); | --- | | - | move occurs because `var` has type `std::option::Option`, which does not implement the `Copy` trait + | move occurs because `var` has type `Option`, which does not implement the `Copy` trait | move occurs due to use in closure error: aborting due to previous error diff --git a/src/test/ui/suggestions/path-by-value.stderr b/src/test/ui/suggestions/path-by-value.stderr index 2b7c29e20c..ea0c63ac25 100644 --- a/src/test/ui/suggestions/path-by-value.stderr +++ b/src/test/ui/suggestions/path-by-value.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | fn f(p: Path) { } | ^ doesn't have a size known at compile-time | - = help: within `std::path::Path`, the trait `std::marker::Sized` is not implemented for `[u8]` - = note: required because it appears within the type `std::path::Path` + = help: within `Path`, the trait `Sized` is not implemented for `[u8]` + = note: required because it appears within the type `Path` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/suggestions/path-display.stderr b/src/test/ui/suggestions/path-display.stderr index 13546cddbd..b08e22eaab 100644 --- a/src/test/ui/suggestions/path-display.stderr +++ b/src/test/ui/suggestions/path-display.stderr @@ -1,12 +1,12 @@ -error[E0277]: `std::path::Path` doesn't implement `std::fmt::Display` +error[E0277]: `Path` doesn't implement `std::fmt::Display` --> $DIR/path-display.rs:5:20 | LL | println!("{}", path); - | ^^^^ `std::path::Path` cannot be formatted with the default formatter; call `.display()` on it + | ^^^^ `Path` cannot be formatted with the default formatter | - = help: the trait `std::fmt::Display` is not implemented for `std::path::Path` - = note: call `.display()` or `.to_string_lossy()` to safely print paths, as they may contain non-Unicode data - = note: required because of the requirements on the impl of `std::fmt::Display` for `&std::path::Path` + = help: the trait `std::fmt::Display` is not implemented for `Path` + = note: in format strings you may be able to use `{:?}` (or {:#?} for pretty-print) instead + = note: required because of the requirements on the impl of `std::fmt::Display` for `&Path` = note: required by `std::fmt::Display::fmt` = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr index 163be4cfce..aa621111c0 100644 --- a/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr +++ b/src/test/ui/suggestions/recover-from-semicolon-trailing-item.stderr @@ -30,7 +30,7 @@ error[E0308]: mismatched types --> $DIR/recover-from-semicolon-trailing-item.rs:12:20 | LL | let _: usize = X {}; - | ----- ^^^^ expected `usize`, found struct `main::X` + | ----- ^^^^ expected `usize`, found struct `X` | | | expected due to this diff --git a/src/test/ui/suggestions/restrict-type-argument.stderr b/src/test/ui/suggestions/restrict-type-argument.stderr index 33af13d943..7a7242a636 100644 --- a/src/test/ui/suggestions/restrict-type-argument.stderr +++ b/src/test/ui/suggestions/restrict-type-argument.stderr @@ -9,8 +9,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_impl_sync(val: impl Sync + std::marker::Send) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_impl_sync(val: impl Sync + Send) { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:8:13 @@ -23,8 +23,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_where(val: S) where S: Sync + std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_where(val: S) where S: Sync + Send { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:12:13 @@ -37,8 +37,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_bound(val: S) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_bound(val: S) { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:20:13 @@ -51,8 +51,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | Sync + std::marker::Send - | ^^^^^^^^^^^^^^^^^^^ +LL | Sync + Send + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:24:13 @@ -65,8 +65,8 @@ LL | is_send(val); | help: consider further restricting this bound | -LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug + std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_bound_and_where(val: S) where S: std::fmt::Debug + Send { + | ^^^^^^ error[E0277]: `S` cannot be sent between threads safely --> $DIR/restrict-type-argument.rs:28:13 @@ -79,8 +79,8 @@ LL | is_send(val); | help: consider restricting type parameter `S` | -LL | fn use_unbound(val: S) { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn use_unbound(val: S) { + | ^^^^^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr index 507f822e7b..996d577311 100644 --- a/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr +++ b/src/test/ui/suggestions/suggest-assoc-fn-call-with-turbofish-through-deref.stderr @@ -1,4 +1,4 @@ -error[E0599]: no method named `hello` found for struct `std::cell::RefMut<'_, HasAssocMethod>` in the current scope +error[E0599]: no method named `hello` found for struct `RefMut<'_, HasAssocMethod>` in the current scope --> $DIR/suggest-assoc-fn-call-with-turbofish-through-deref.rs:11:11 | LL | state.hello(); diff --git a/src/test/ui/suggestions/suggest-box.stderr b/src/test/ui/suggestions/suggest-box.stderr index 19786bee9c..57c83baf4f 100644 --- a/src/test/ui/suggestions/suggest-box.stderr +++ b/src/test/ui/suggestions/suggest-box.stderr @@ -8,9 +8,9 @@ LL | let _x: Box Result<(), ()>> = || { LL | | Err(())?; LL | | Ok(()) LL | | }; - | |_____^ expected struct `std::boxed::Box`, found closure + | |_____^ expected struct `Box`, found closure | - = note: expected struct `std::boxed::Box std::result::Result<(), ()>>` + = note: expected struct `Box std::result::Result<(), ()>>` found closure `[closure@$DIR/suggest-box.rs:4:47: 7:6]` = 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` diff --git a/src/test/ui/suggestions/suggest-methods.stderr b/src/test/ui/suggestions/suggest-methods.stderr index c343071ac3..535841e535 100644 --- a/src/test/ui/suggestions/suggest-methods.stderr +++ b/src/test/ui/suggestions/suggest-methods.stderr @@ -7,7 +7,7 @@ LL | struct Foo; LL | f.bat(1.0); | ^^^ help: there is an associated function with a similar name: `bar` -error[E0599]: no method named `is_emtpy` found for struct `std::string::String` in the current scope +error[E0599]: no method named `is_emtpy` found for struct `String` in the current scope --> $DIR/suggest-methods.rs:21:15 | LL | let _ = s.is_emtpy(); diff --git a/src/test/ui/suggestions/suggest-private-fields.rs b/src/test/ui/suggestions/suggest-private-fields.rs index 347c8aeed6..8267a82fe2 100644 --- a/src/test/ui/suggestions/suggest-private-fields.rs +++ b/src/test/ui/suggestions/suggest-private-fields.rs @@ -13,9 +13,9 @@ fn main () { // external crate struct let k = B { aa: 20, - //~^ ERROR struct `xc::B` has no field named `aa` + //~^ ERROR struct `B` has no field named `aa` bb: 20, - //~^ ERROR struct `xc::B` has no field named `bb` + //~^ ERROR struct `B` has no field named `bb` }; // local crate struct let l = A { diff --git a/src/test/ui/suggestions/suggest-private-fields.stderr b/src/test/ui/suggestions/suggest-private-fields.stderr index 524558e0ec..d628bd1620 100644 --- a/src/test/ui/suggestions/suggest-private-fields.stderr +++ b/src/test/ui/suggestions/suggest-private-fields.stderr @@ -1,14 +1,14 @@ -error[E0560]: struct `xc::B` has no field named `aa` +error[E0560]: struct `B` has no field named `aa` --> $DIR/suggest-private-fields.rs:15:9 | LL | aa: 20, | ^^ help: a field with a similar name exists: `a` -error[E0560]: struct `xc::B` has no field named `bb` +error[E0560]: struct `B` has no field named `bb` --> $DIR/suggest-private-fields.rs:17:9 | LL | bb: 20, - | ^^ `xc::B` does not have this field + | ^^ `B` does not have this field | = note: available fields are: `a` diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.fixed b/src/test/ui/suggestions/suggest-remove-refs-1.fixed index 042e85b10a..a39e0fbd11 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.fixed +++ b/src/test/ui/suggestions/suggest-remove-refs-1.fixed @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in v.iter().enumerate() { - //~^ ERROR `&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.rs b/src/test/ui/suggestions/suggest-remove-refs-1.rs index 7bdf5dbf35..6f767f2c17 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.rs +++ b/src/test/ui/suggestions/suggest-remove-refs-1.rs @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in &v.iter().enumerate() { - //~^ ERROR `&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-1.stderr b/src/test/ui/suggestions/suggest-remove-refs-1.stderr index 5be0072fa3..0dd1b2a59e 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-1.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-1.stderr @@ -1,14 +1,14 @@ -error[E0277]: `&std::iter::Enumerate>` is not an iterator +error[E0277]: `&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-1.rs:6:19 | LL | for (i, _) in &v.iter().enumerate() { | -^^^^^^^^^^^^^^^^^^^^ | | - | `&std::iter::Enumerate>` is not an iterator + | `&Enumerate>` is not an iterator | help: consider removing the leading `&`-reference | - = help: the trait `std::iter::Iterator` is not implemented for `&std::iter::Enumerate>` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&Enumerate>` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-remove-refs-2.fixed b/src/test/ui/suggestions/suggest-remove-refs-2.fixed index bdf47b0e87..0f9c3abfe8 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-2.fixed +++ b/src/test/ui/suggestions/suggest-remove-refs-2.fixed @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in v.iter().enumerate() { - //~^ ERROR `&&&&&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&&&&&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-2.rs b/src/test/ui/suggestions/suggest-remove-refs-2.rs index 3ed56377e1..6c94b12d20 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-2.rs +++ b/src/test/ui/suggestions/suggest-remove-refs-2.rs @@ -4,7 +4,7 @@ fn main() { let v = vec![0, 1, 2, 3]; for (i, _) in & & & & &v.iter().enumerate() { - //~^ ERROR `&&&&&std::iter::Enumerate>` is not an iterator + //~^ ERROR `&&&&&Enumerate>` is not an iterator println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-2.stderr b/src/test/ui/suggestions/suggest-remove-refs-2.stderr index ff84a2ce37..5c2efdb197 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-2.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-2.stderr @@ -1,14 +1,14 @@ -error[E0277]: `&&&&&std::iter::Enumerate>` is not an iterator +error[E0277]: `&&&&&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-2.rs:6:19 | LL | for (i, _) in & & & & &v.iter().enumerate() { | ---------^^^^^^^^^^^^^^^^^^^^ | | - | `&&&&&std::iter::Enumerate>` is not an iterator + | `&&&&&Enumerate>` is not an iterator | help: consider removing 5 leading `&`-references | - = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/suggestions/suggest-remove-refs-3.fixed b/src/test/ui/suggestions/suggest-remove-refs-3.fixed index e0ecafabf3..3148fcbe5d 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-3.fixed +++ b/src/test/ui/suggestions/suggest-remove-refs-3.fixed @@ -6,7 +6,7 @@ fn main() { for (i, _) in v .iter() .enumerate() { - //~^^^^ ERROR `&&&&&std::iter::Enumerate>` is not an + //~^^^^ ERROR `&&&&&Enumerate>` is not an println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-3.rs b/src/test/ui/suggestions/suggest-remove-refs-3.rs index e13099e8c3..0622adada0 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-3.rs +++ b/src/test/ui/suggestions/suggest-remove-refs-3.rs @@ -7,7 +7,7 @@ fn main() { & &v .iter() .enumerate() { - //~^^^^ ERROR `&&&&&std::iter::Enumerate>` is not an + //~^^^^ ERROR `&&&&&Enumerate>` is not an println!("{}", i); } } diff --git a/src/test/ui/suggestions/suggest-remove-refs-3.stderr b/src/test/ui/suggestions/suggest-remove-refs-3.stderr index d2f7c72b0e..c7fbd3d9bd 100644 --- a/src/test/ui/suggestions/suggest-remove-refs-3.stderr +++ b/src/test/ui/suggestions/suggest-remove-refs-3.stderr @@ -1,4 +1,4 @@ -error[E0277]: `&&&&&std::iter::Enumerate>` is not an iterator +error[E0277]: `&&&&&Enumerate>` is not an iterator --> $DIR/suggest-remove-refs-3.rs:6:19 | LL | for (i, _) in & & & @@ -9,10 +9,10 @@ LL | || & &v | ||___________- help: consider removing 5 leading `&`-references LL | | .iter() LL | | .enumerate() { - | |_____________________^ `&&&&&std::iter::Enumerate>` is not an iterator + | |_____________________^ `&&&&&Enumerate>` is not an iterator | - = help: the trait `std::iter::Iterator` is not implemented for `&&&&&std::iter::Enumerate>` - = note: required by `std::iter::IntoIterator::into_iter` + = help: the trait `Iterator` is not implemented for `&&&&&Enumerate>` + = note: required by `into_iter` error: aborting due to previous error diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.rs b/src/test/ui/suggestions/type-ascription-instead-of-path.rs index e92087e294..ce40b55f1e 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.rs +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.rs @@ -1,5 +1,5 @@ fn main() { std:io::stdin(); - //~^ ERROR failed to resolve: use of undeclared type or module `io` + //~^ ERROR failed to resolve: use of undeclared crate or module `io` //~| ERROR expected value, found crate } diff --git a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr index fd2fedc764..518660cfa1 100644 --- a/src/test/ui/suggestions/type-ascription-instead-of-path.stderr +++ b/src/test/ui/suggestions/type-ascription-instead-of-path.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `io` +error[E0433]: failed to resolve: use of undeclared crate or module `io` --> $DIR/type-ascription-instead-of-path.rs:2:9 | LL | std:io::stdin(); - | ^^ use of undeclared type or module `io` + | ^^ use of undeclared crate or module `io` error[E0423]: expected value, found crate `std` --> $DIR/type-ascription-instead-of-path.rs:2:5 diff --git a/src/test/ui/switched-expectations.stderr b/src/test/ui/switched-expectations.stderr index dca9c6ce4d..82fea0f14b 100644 --- a/src/test/ui/switched-expectations.stderr +++ b/src/test/ui/switched-expectations.stderr @@ -2,7 +2,7 @@ error[E0308]: mismatched types --> $DIR/switched-expectations.rs:3:30 | LL | let ref string: String = var; - | ^^^ expected struct `std::string::String`, found `i32` + | ^^^ expected struct `String`, found `i32` error: aborting due to previous error diff --git a/src/test/ui/symbol-names/impl1.legacy.stderr b/src/test/ui/symbol-names/impl1.legacy.stderr index 52ee3452a4..e4c20cd882 100644 --- a/src/test/ui/symbol-names/impl1.legacy.stderr +++ b/src/test/ui/symbol-names/impl1.legacy.stderr @@ -64,7 +64,7 @@ error: demangling-alt(<[&dyn impl1::Foo+Assoc = extern "C" fn(&u8, ::.)+impl1::A LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) +error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) --> $DIR/impl1.rs:71:13 | LL | #[rustc_def_path] diff --git a/src/test/ui/symbol-names/impl1.rs b/src/test/ui/symbol-names/impl1.rs index 380d20d0b1..1d86abd002 100644 --- a/src/test/ui/symbol-names/impl1.rs +++ b/src/test/ui/symbol-names/impl1.rs @@ -69,8 +69,8 @@ fn main() { //[v0]~| ERROR demangling(<[&dyn impl1[317d481089b8c8fe]::Foo extern "C" fn(&'a u8, ...)> + impl1[317d481089b8c8fe]::AutoTrait; 3: usize] as impl1[317d481089b8c8fe]::main::{closure#1}::Bar>::method) //[v0]~| ERROR demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'a u8, ...)> + impl1::AutoTrait; 3] as impl1::main::{closure#1}::Bar>::method) #[rustc_def_path] - //[legacy]~^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) - //[v0]~^^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) + //[legacy]~^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) + //[v0]~^^ ERROR def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) fn method(&self) {} } }; diff --git a/src/test/ui/symbol-names/impl1.v0.stderr b/src/test/ui/symbol-names/impl1.v0.stderr index b6a35d9746..01d047d34a 100644 --- a/src/test/ui/symbol-names/impl1.v0.stderr +++ b/src/test/ui/symbol-names/impl1.v0.stderr @@ -64,7 +64,7 @@ error: demangling-alt(<[&dyn impl1::Foo extern "C" fn(&'a u8, .. LL | #[rustc_symbol_name] | ^^^^^^^^^^^^^^^^^^^^ -error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as main::{{closure}}#1::Bar>::method) +error: def-path(<[&dyn Foo extern "C" fn(&'r u8, ...)> + AutoTrait; 3] as Bar>::method) --> $DIR/impl1.rs:71:13 | LL | #[rustc_def_path] diff --git a/src/test/ui/symbol-names/issue-76365.rs b/src/test/ui/symbol-names/issue-76365.rs new file mode 100644 index 0000000000..61ba255dac --- /dev/null +++ b/src/test/ui/symbol-names/issue-76365.rs @@ -0,0 +1,18 @@ +// check-pass +// revisions: legacy v0 +//[legacy]compile-flags: -Z symbol-mangling-version=legacy --crate-type=lib + //[v0]compile-flags: -Z symbol-mangling-version=v0 --crate-type=lib + +#![feature(min_const_generics)] + +pub struct Bar; + +impl Bar { + pub fn foo() {} +} + +impl Bar { + pub fn bar() {} +} + +fn main() {} diff --git a/src/test/ui/tag-that-dare-not-speak-its-name.rs b/src/test/ui/tag-that-dare-not-speak-its-name.rs index 4d9a98827d..36e22f0b5f 100644 --- a/src/test/ui/tag-that-dare-not-speak-its-name.rs +++ b/src/test/ui/tag-that-dare-not-speak-its-name.rs @@ -11,6 +11,6 @@ fn main() { let x : char = last(y); //~^ ERROR mismatched types //~| expected type `char` - //~| found enum `std::option::Option<_>` - //~| expected `char`, found enum `std::option::Option` + //~| found enum `Option<_>` + //~| expected `char`, found enum `Option` } diff --git a/src/test/ui/tag-that-dare-not-speak-its-name.stderr b/src/test/ui/tag-that-dare-not-speak-its-name.stderr index cafb6d2d28..96bab15261 100644 --- a/src/test/ui/tag-that-dare-not-speak-its-name.stderr +++ b/src/test/ui/tag-that-dare-not-speak-its-name.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/tag-that-dare-not-speak-its-name.rs:11:20 | LL | let x : char = last(y); - | ---- ^^^^^^^ expected `char`, found enum `std::option::Option` + | ---- ^^^^^^^ expected `char`, found enum `Option` | | | expected due to this | = note: expected type `char` - found enum `std::option::Option<_>` + found enum `Option<_>` error: aborting due to previous error diff --git a/src/test/ui/target-feature/gate.rs b/src/test/ui/target-feature/gate.rs index 10fbba36d3..e4b78c76e1 100644 --- a/src/test/ui/target-feature/gate.rs +++ b/src/test/ui/target-feature/gate.rs @@ -19,7 +19,6 @@ // gate-test-aarch64_target_feature // gate-test-hexagon_target_feature // gate-test-mips_target_feature -// gate-test-mmx_target_feature // gate-test-wasm_target_feature // gate-test-adx_target_feature // gate-test-cmpxchg16b_target_feature @@ -30,7 +29,6 @@ #[target_feature(enable = "avx512bw")] //~^ ERROR: currently unstable -unsafe fn foo() { -} +unsafe fn foo() {} fn main() {} diff --git a/src/test/ui/target-feature/gate.stderr b/src/test/ui/target-feature/gate.stderr index 2d6abcc0a0..2384a00aa4 100644 --- a/src/test/ui/target-feature/gate.stderr +++ b/src/test/ui/target-feature/gate.stderr @@ -1,5 +1,5 @@ error[E0658]: the target feature `avx512bw` is currently unstable - --> $DIR/gate.rs:31:18 + --> $DIR/gate.rs:30:18 | LL | #[target_feature(enable = "avx512bw")] | ^^^^^^^^^^^^^^^^^^^ diff --git a/src/test/ui/target-feature/invalid-attribute.rs b/src/test/ui/target-feature/invalid-attribute.rs index 98afded671..5ea7821554 100644 --- a/src/test/ui/target-feature/invalid-attribute.rs +++ b/src/test/ui/target-feature/invalid-attribute.rs @@ -13,6 +13,7 @@ // ignore-sparc64 #![feature(target_feature)] +#![warn(unused_attributes)] #[target_feature = "+sse2"] //~^ ERROR malformed `target_feature` attribute @@ -48,17 +49,20 @@ struct Foo; #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -enum Bar { } +enum Bar {} //~^ NOTE not a function #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -union Qux { f1: u16, f2: u16 } +union Qux { //~^ NOTE not a function + f1: u16, + f2: u16, +} #[target_feature(enable = "sse2")] //~^ ERROR attribute should be applied to a function -trait Baz { } +trait Baz {} //~^ NOTE not a function #[inline(always)] @@ -79,13 +83,16 @@ impl Quux for Foo { } fn main() { + #[target_feature(enable = "sse2")] + //~^ ERROR attribute should be applied to a function unsafe { foo(); bar(); } + //~^^^^ NOTE not a function + #[target_feature(enable = "sse2")] - //~^ ERROR `#[target_feature(..)]` can only be applied to `unsafe` functions - //~| NOTE see issue #69098 + //~^ ERROR attribute should be applied to a function || {}; - //~^ NOTE not an `unsafe` function + //~^ NOTE not a function } diff --git a/src/test/ui/target-feature/invalid-attribute.stderr b/src/test/ui/target-feature/invalid-attribute.stderr index 3d629afb9a..8c8e24ccc5 100644 --- a/src/test/ui/target-feature/invalid-attribute.stderr +++ b/src/test/ui/target-feature/invalid-attribute.stderr @@ -1,29 +1,29 @@ error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:17:1 + --> $DIR/invalid-attribute.rs:18:1 | LL | #[target_feature = "+sse2"] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: must be of the form: `#[target_feature(enable = "name")]` error: the feature named `foo` is not valid for this target - --> $DIR/invalid-attribute.rs:19:18 + --> $DIR/invalid-attribute.rs:20:18 | LL | #[target_feature(enable = "foo")] | ^^^^^^^^^^^^^^ `foo` is not valid for this target error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:22:18 + --> $DIR/invalid-attribute.rs:23:18 | LL | #[target_feature(bar)] | ^^^ help: must be of the form: `enable = ".."` error: malformed `target_feature` attribute input - --> $DIR/invalid-attribute.rs:24:18 + --> $DIR/invalid-attribute.rs:25:18 | LL | #[target_feature(disable = "baz")] | ^^^^^^^^^^^^^^^ help: must be of the form: `enable = ".."` error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:28:1 + --> $DIR/invalid-attribute.rs:29:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -35,7 +35,7 @@ LL | fn bar() {} = help: add `#![feature(target_feature_11)]` to the crate attributes to enable error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:34:1 + --> $DIR/invalid-attribute.rs:35:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -44,7 +44,7 @@ LL | mod another {} | -------------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:39:1 + --> $DIR/invalid-attribute.rs:40:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -53,7 +53,7 @@ LL | const FOO: usize = 7; | --------------------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:44:1 + --> $DIR/invalid-attribute.rs:45:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -62,52 +62,65 @@ LL | struct Foo; | ----------- not a function error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:49:1 + --> $DIR/invalid-attribute.rs:50:1 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ LL | -LL | enum Bar { } +LL | enum Bar {} + | ----------- not a function + +error: attribute should be applied to a function + --> $DIR/invalid-attribute.rs:55:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / union Qux { +LL | | +LL | | f1: u16, +LL | | f2: u16, +LL | | } + | |_- not a function + +error: attribute should be applied to a function + --> $DIR/invalid-attribute.rs:63:1 + | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | trait Baz {} | ------------ not a function -error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:54:1 - | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | union Qux { f1: u16, f2: u16 } - | ------------------------------ not a function - -error: attribute should be applied to a function - --> $DIR/invalid-attribute.rs:59:1 - | -LL | #[target_feature(enable = "sse2")] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -LL | -LL | trait Baz { } - | ------------- not a function - error: cannot use `#[inline(always)]` with `#[target_feature]` - --> $DIR/invalid-attribute.rs:64:1 + --> $DIR/invalid-attribute.rs:68:1 | LL | #[inline(always)] | ^^^^^^^^^^^^^^^^^ -error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions +error: attribute should be applied to a function --> $DIR/invalid-attribute.rs:86:5 | +LL | #[target_feature(enable = "sse2")] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | +LL | / unsafe { +LL | | foo(); +LL | | bar(); +LL | | } + | |_____- not a function + +error: attribute should be applied to a function + --> $DIR/invalid-attribute.rs:94:5 + | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -... +LL | LL | || {}; - | ----- not an `unsafe` function - | - = note: see issue #69098 for more information - = help: add `#![feature(target_feature_11)]` to the crate attributes to enable + | ----- not a function error[E0658]: `#[target_feature(..)]` can only be applied to `unsafe` functions - --> $DIR/invalid-attribute.rs:74:5 + --> $DIR/invalid-attribute.rs:78:5 | LL | #[target_feature(enable = "sse2")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -118,6 +131,6 @@ LL | fn foo() {} = note: see issue #69098 for more information = help: add `#![feature(target_feature_11)]` to the crate attributes to enable -error: aborting due to 14 previous errors +error: aborting due to 15 previous errors For more information about this error, try `rustc --explain E0658`. diff --git a/src/test/ui/terr-sorts.rs b/src/test/ui/terr-sorts.rs index f91185fd7c..c1e2f7daee 100644 --- a/src/test/ui/terr-sorts.rs +++ b/src/test/ui/terr-sorts.rs @@ -9,7 +9,7 @@ fn want_foo(f: Foo) {} fn have_bar(b: Bar) { want_foo(b); //~ ERROR mismatched types //~| expected struct `Foo` - //~| found struct `std::boxed::Box` + //~| found struct `Box` } fn main() {} diff --git a/src/test/ui/terr-sorts.stderr b/src/test/ui/terr-sorts.stderr index 2f7cc66f10..869b372965 100644 --- a/src/test/ui/terr-sorts.stderr +++ b/src/test/ui/terr-sorts.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/terr-sorts.rs:10:14 | LL | want_foo(b); - | ^ expected struct `Foo`, found struct `std::boxed::Box` + | ^ expected struct `Foo`, found struct `Box` | = note: expected struct `Foo` - found struct `std::boxed::Box` + found struct `Box` error: aborting due to previous error diff --git a/src/test/ui/trait-impl-bound-suggestions.fixed b/src/test/ui/trait-impl-bound-suggestions.fixed new file mode 100644 index 0000000000..db3a95f5c4 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.fixed @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric where X: Copy { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.rs b/src/test/ui/trait-impl-bound-suggestions.rs new file mode 100644 index 0000000000..bf75175179 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.rs @@ -0,0 +1,20 @@ +// run-rustfix + +#[allow(unused)] +use std::fmt::Debug; +// Rustfix should add this, or use `std::fmt::Debug` instead. + +#[allow(dead_code)] +struct ConstrainedStruct { + x: X +} + +#[allow(dead_code)] +trait InsufficientlyConstrainedGeneric { + fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + //~^ ERROR the trait bound `X: Copy` is not satisfied + ConstrainedStruct { x } + } +} + +pub fn main() { } diff --git a/src/test/ui/trait-impl-bound-suggestions.stderr b/src/test/ui/trait-impl-bound-suggestions.stderr new file mode 100644 index 0000000000..3a21e9c6b2 --- /dev/null +++ b/src/test/ui/trait-impl-bound-suggestions.stderr @@ -0,0 +1,17 @@ +error[E0277]: the trait bound `X: Copy` is not satisfied + --> $DIR/trait-impl-bound-suggestions.rs:14:52 + | +LL | struct ConstrainedStruct { + | ---- required by this bound in `ConstrainedStruct` +... +LL | fn return_the_constrained_type(&self, x: X) -> ConstrainedStruct { + | ^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `X` + | +help: consider further restricting type parameter `X` + | +LL | trait InsufficientlyConstrainedGeneric where X: Copy { + | ^^^^^^^^^^^^^ + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/traits/cycle-cache-err-60010.stderr b/src/test/ui/traits/cycle-cache-err-60010.stderr index 324316ceaf..25b1f427f3 100644 --- a/src/test/ui/traits/cycle-cache-err-60010.stderr +++ b/src/test/ui/traits/cycle-cache-err-60010.stderr @@ -6,7 +6,7 @@ LL | _parse: >::Data, | = note: required because of the requirements on the impl of `Query` for `ParseQuery` -error[E0275]: overflow evaluating the requirement `Runtime: std::panic::RefUnwindSafe` +error[E0275]: overflow evaluating the requirement `Runtime: RefUnwindSafe` --> $DIR/cycle-cache-err-60010.rs:31:20 | LL | trait Database { diff --git a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr index 446b8dbf11..83b1b83d19 100644 --- a/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr +++ b/src/test/ui/traits/negative-impls/negated-auto-traits-error.stderr @@ -7,7 +7,7 @@ LL | struct Outer(T); LL | Outer(TestType); | ^^^^^^^^ `dummy::TestType` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` + = help: the trait `Send` is not implemented for `dummy::TestType` error[E0277]: `dummy::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:23:5 @@ -18,7 +18,7 @@ LL | struct Outer(T); LL | Outer(TestType); | ^^^^^^^^^^^^^^^ `dummy::TestType` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dummy::TestType` + = help: the trait `Send` is not implemented for `dummy::TestType` error[E0277]: `dummy1b::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:32:13 @@ -29,7 +29,7 @@ LL | fn is_send(_: T) {} LL | is_send(TestType); | ^^^^^^^^ `dummy1b::TestType` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `dummy1b::TestType` + = help: the trait `Send` is not implemented for `dummy1b::TestType` error[E0277]: `dummy1c::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:40:13 @@ -40,7 +40,7 @@ LL | fn is_send(_: T) {} LL | is_send((8, TestType)); | ^^^^^^^^^^^^^ `dummy1c::TestType` cannot be sent between threads safely | - = help: within `({integer}, dummy1c::TestType)`, the trait `std::marker::Send` is not implemented for `dummy1c::TestType` + = help: within `({integer}, dummy1c::TestType)`, the trait `Send` is not implemented for `dummy1c::TestType` = note: required because it appears within the type `({integer}, dummy1c::TestType)` error[E0277]: `dummy2::TestType` cannot be sent between threads safely @@ -52,12 +52,12 @@ LL | fn is_send(_: T) {} LL | is_send(Box::new(TestType)); | ^^^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Send` + | expected an implementor of trait `Send` | help: consider borrowing here: `&Box::new(TestType)` | - = note: the trait bound `dummy2::TestType: std::marker::Send` is not satisfied - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique` - = note: required because it appears within the type `std::boxed::Box` + = note: the trait bound `dummy2::TestType: Send` is not satisfied + = note: required because of the requirements on the impl of `Send` for `Unique` + = note: required because it appears within the type `Box` error[E0277]: `dummy3::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:56:13 @@ -68,10 +68,10 @@ LL | fn is_send(_: T) {} LL | is_send(Box::new(Outer2(TestType))); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ `dummy3::TestType` cannot be sent between threads safely | - = help: within `Outer2`, the trait `std::marker::Send` is not implemented for `dummy3::TestType` + = help: within `Outer2`, the trait `Send` is not implemented for `dummy3::TestType` = note: required because it appears within the type `Outer2` - = note: required because of the requirements on the impl of `std::marker::Send` for `std::ptr::Unique>` - = note: required because it appears within the type `std::boxed::Box>` + = note: required because of the requirements on the impl of `Send` for `Unique>` + = note: required because it appears within the type `Box>` error[E0277]: `main::TestType` cannot be sent between threads safely --> $DIR/negated-auto-traits-error.rs:66:13 @@ -82,11 +82,11 @@ LL | fn is_sync(_: T) {} LL | is_sync(Outer2(TestType)); | ^^^^^^^^^^^^^^^^ | | - | expected an implementor of trait `std::marker::Sync` + | expected an implementor of trait `Sync` | help: consider borrowing here: `&Outer2(TestType)` | - = note: the trait bound `main::TestType: std::marker::Sync` is not satisfied - = note: required because of the requirements on the impl of `std::marker::Sync` for `Outer2` + = note: the trait bound `main::TestType: Sync` is not satisfied + = note: required because of the requirements on the impl of `Sync` for `Outer2` error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/trait-alias-ambiguous.stderr b/src/test/ui/traits/trait-alias-ambiguous.stderr index 7c00bb5207..f692e92d86 100644 --- a/src/test/ui/traits/trait-alias-ambiguous.stderr +++ b/src/test/ui/traits/trait-alias-ambiguous.stderr @@ -4,24 +4,24 @@ error[E0034]: multiple applicable items in scope LL | t.foo(); | ^^^ multiple `foo` found | -note: candidate #1 is defined in an impl of the trait `inner::A` for the type `u8` +note: candidate #1 is defined in an impl of the trait `A` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:8:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ -note: candidate #2 is defined in an impl of the trait `inner::B` for the type `u8` +note: candidate #2 is defined in an impl of the trait `B` for the type `u8` --> $DIR/trait-alias-ambiguous.rs:11:9 | LL | fn foo(&self) {} | ^^^^^^^^^^^^^ help: disambiguate the associated function for candidate #1 | -LL | inner::A::foo(&t); - | ^^^^^^^^^^^^^^^^^ +LL | A::foo(&t); + | ^^^^^^^^^^ help: disambiguate the associated function for candidate #2 | -LL | inner::B::foo(&t); - | ^^^^^^^^^^^^^^^^^ +LL | B::foo(&t); + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs index 259fc4fa5d..14edfdd7a3 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs +++ b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.rs @@ -12,6 +12,6 @@ fn use_alias() {} fn main() { use_alias::(); use_alias::>(); - //~^ ERROR `std::rc::Rc` cannot be sent between threads safely [E0277] - //~^^ ERROR `std::rc::Rc` cannot be shared between threads safely [E0277] + //~^ ERROR `Rc` cannot be sent between threads safely [E0277] + //~^^ ERROR `Rc` cannot be shared between threads safely [E0277] } diff --git a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr index 04c86cb240..60a4a46a05 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-cross-crate.stderr @@ -1,24 +1,24 @@ -error[E0277]: `std::rc::Rc` cannot be sent between threads safely +error[E0277]: `Rc` cannot be sent between threads safely --> $DIR/trait-alias-cross-crate.rs:14:17 | LL | fn use_alias() {} | -------- required by this bound in `use_alias` ... LL | use_alias::>(); - | ^^^^^^^ `std::rc::Rc` cannot be sent between threads safely + | ^^^^^^^ `Rc` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `std::rc::Rc` + = help: the trait `Send` is not implemented for `Rc` -error[E0277]: `std::rc::Rc` cannot be shared between threads safely +error[E0277]: `Rc` cannot be shared between threads safely --> $DIR/trait-alias-cross-crate.rs:14:17 | LL | fn use_alias() {} | -------- required by this bound in `use_alias` ... LL | use_alias::>(); - | ^^^^^^^ `std::rc::Rc` cannot be shared between threads safely + | ^^^^^^^ `Rc` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::rc::Rc` + = help: the trait `Sync` is not implemented for `Rc` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs index d62fd7e59c..5c753ff207 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.rs @@ -5,7 +5,7 @@ trait IteratorAlias = Iterator; fn main() { let _: &dyn EqAlias = &123; - //~^ ERROR the trait `std::cmp::Eq` cannot be made into an object [E0038] + //~^ ERROR the trait `Eq` cannot be made into an object [E0038] let _: &dyn IteratorAlias = &vec![123].into_iter(); //~^ ERROR must be specified } diff --git a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr index 4cad710789..1f54e03ee6 100644 --- a/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr +++ b/src/test/ui/traits/trait-alias/trait-alias-object-fail.stderr @@ -1,15 +1,15 @@ -error[E0038]: the trait `std::cmp::Eq` cannot be made into an object +error[E0038]: the trait `Eq` cannot be made into an object --> $DIR/trait-alias-object-fail.rs:7:13 | LL | let _: &dyn EqAlias = &123; - | ^^^^^^^^^^^ the trait `std::cmp::Eq` cannot be made into an object + | ^^^^^^^^^^^ the trait `Eq` cannot be made into an object | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub trait Eq: PartialEq { | --------------- the trait cannot be made into an object because it uses `Self` as a type parameter in this -error[E0191]: the value of the associated type `Item` (from trait `std::iter::Iterator`) must be specified +error[E0191]: the value of the associated type `Item` (from trait `Iterator`) must be specified --> $DIR/trait-alias-object-fail.rs:9:17 | LL | let _: &dyn IteratorAlias = &vec![123].into_iter(); diff --git a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr index daca91abff..b403fb4184 100644 --- a/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr +++ b/src/test/ui/traits/trait-bounds-not-on-bare-trait.stderr @@ -6,13 +6,13 @@ LL | fn foo(_x: Foo + Send) { | = note: `#[warn(bare_trait_objects)]` on by default -error[E0277]: the size for values of type `(dyn Foo + std::marker::Send + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Foo + Send + 'static)` cannot be known at compilation time --> $DIR/trait-bounds-not-on-bare-trait.rs:7:8 | LL | fn foo(_x: Foo + Send) { | ^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + std::marker::Send + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Foo + Send + 'static)` = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size | diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr index d2fa211b48..3e8c727dda 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc.stderr @@ -1,24 +1,24 @@ -error[E0277]: the trait bound `usize: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `usize: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc.rs:7:15 | LL | fn explode(x: Foo) {} - | ^^^^^^^^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `usize` + | ^^^^^^^^^^ the trait `Trait` is not implemented for `usize` | ::: $DIR/auxiliary/trait_bounds_on_structs_and_enums_xc.rs:5:18 | LL | pub struct Foo { - | ----- required by this bound in `trait_bounds_on_structs_and_enums_xc::Foo` + | ----- required by this bound in `Foo` -error[E0277]: the trait bound `f32: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `f32: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc.rs:10:14 | LL | fn kaboom(y: Bar) {} - | ^^^^^^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `f32` + | ^^^^^^^^ the trait `Trait` is not implemented for `f32` | ::: $DIR/auxiliary/trait_bounds_on_structs_and_enums_xc.rs:9:16 | LL | pub enum Bar { - | ----- required by this bound in `trait_bounds_on_structs_and_enums_xc::Bar` + | ----- required by this bound in `Bar` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr index ee3e755c95..899e994199 100644 --- a/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr +++ b/src/test/ui/traits/trait-bounds-on-structs-and-enums-xc1.stderr @@ -1,21 +1,21 @@ -error[E0277]: the trait bound `f64: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `f64: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc1.rs:12:14 | LL | let bar: Bar = return; - | ^^^^^^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `f64` + | ^^^^^^^^ the trait `Trait` is not implemented for `f64` | ::: $DIR/auxiliary/trait_bounds_on_structs_and_enums_xc.rs:9:16 | LL | pub enum Bar { - | ----- required by this bound in `trait_bounds_on_structs_and_enums_xc::Bar` + | ----- required by this bound in `Bar` -error[E0277]: the trait bound `{integer}: trait_bounds_on_structs_and_enums_xc::Trait` is not satisfied +error[E0277]: the trait bound `{integer}: Trait` is not satisfied --> $DIR/trait-bounds-on-structs-and-enums-xc1.rs:8:15 | LL | let foo = Foo { - | ^^^ the trait `trait_bounds_on_structs_and_enums_xc::Trait` is not implemented for `{integer}` + | ^^^ the trait `Trait` is not implemented for `{integer}` | - = note: required by `trait_bounds_on_structs_and_enums_xc::Foo` + = note: required by `Foo` error: aborting due to 2 previous errors diff --git a/src/test/ui/traits/trait-bounds-same-crate-name.stderr b/src/test/ui/traits/trait-bounds-same-crate-name.stderr index 8a6e059604..af5ba8808f 100644 --- a/src/test/ui/traits/trait-bounds-same-crate-name.stderr +++ b/src/test/ui/traits/trait-bounds-same-crate-name.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `main::a::Foo: main::a::Bar` is not satisfied +error[E0277]: the trait bound `Foo: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:31:20 | LL | a::try_foo(foo); - | ^^^ the trait `main::a::Bar` is not implemented for `main::a::Foo` + | ^^^ the trait `main::a::Bar` is not implemented for `Foo` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` | help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:5:1 @@ -16,27 +16,27 @@ LL | impl Bar for Foo {} | ^^^^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? -error[E0277]: the trait bound `main::a::DoesNotImplementTrait: main::a::Bar` is not satisfied +error[E0277]: the trait bound `DoesNotImplementTrait: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:38:20 | LL | a::try_foo(implements_no_traits); - | ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::DoesNotImplementTrait` + | ^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `DoesNotImplementTrait` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` -error[E0277]: the trait bound `main::a::ImplementsWrongTraitConditionally: main::a::Bar` is not satisfied +error[E0277]: the trait bound `ImplementsWrongTraitConditionally: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:45:20 | LL | a::try_foo(other_variant_implements_mismatched_trait); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::ImplementsWrongTraitConditionally` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsWrongTraitConditionally` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` | help: trait impl with same name found --> $DIR/auxiliary/crate_a2.rs:13:1 @@ -45,19 +45,19 @@ LL | impl Bar for ImplementsWrongTraitConditionally {} | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: perhaps two different versions of crate `crate_a2` are being used? -error[E0277]: the trait bound `main::a::ImplementsTraitForUsize: main::a::Bar` is not satisfied +error[E0277]: the trait bound `ImplementsTraitForUsize: main::a::Bar` is not satisfied --> $DIR/trait-bounds-same-crate-name.rs:51:20 | LL | a::try_foo(other_variant_implements_correct_trait); - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `main::a::ImplementsTraitForUsize` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `main::a::Bar` is not implemented for `ImplementsTraitForUsize` | ::: $DIR/auxiliary/crate_a1.rs:3:24 | LL | pub fn try_foo(x: impl Bar) {} - | --- required by this bound in `main::a::try_foo` + | --- required by this bound in `try_foo` | = help: the following implementations were found: - as main::a::Bar> + as main::a::Bar> error: aborting due to 4 previous errors diff --git a/src/test/ui/traits/trait-bounds-sugar.stderr b/src/test/ui/traits/trait-bounds-sugar.stderr index 5ee8be51dd..6bd335fe47 100644 --- a/src/test/ui/traits/trait-bounds-sugar.stderr +++ b/src/test/ui/traits/trait-bounds-sugar.stderr @@ -2,10 +2,10 @@ error[E0308]: mismatched types --> $DIR/trait-bounds-sugar.rs:12:7 | LL | a(x); - | ^ expected trait `Foo + std::marker::Send`, found trait `Foo + std::marker::Sync` + | ^ expected trait `Foo + Send`, found trait `Foo + Sync` | - = note: expected struct `std::boxed::Box<(dyn Foo + std::marker::Send + 'static)>` - found struct `std::boxed::Box<(dyn Foo + std::marker::Sync + 'static)>` + = note: expected struct `Box<(dyn Foo + Send + 'static)>` + found struct `Box<(dyn Foo + Sync + 'static)>` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-object-macro-matcher.rs b/src/test/ui/traits/trait-object-macro-matcher.rs index a6852569f3..9109787499 100644 --- a/src/test/ui/traits/trait-object-macro-matcher.rs +++ b/src/test/ui/traits/trait-object-macro-matcher.rs @@ -6,7 +6,7 @@ macro_rules! m { fn main() { m!(dyn Copy + Send + 'static); - //~^ ERROR the trait `std::marker::Copy` cannot be made into an object + //~^ ERROR the trait `Copy` cannot be made into an object m!(dyn 'static + Send); m!(dyn 'static +); //~ ERROR at least one trait is required for an object type } diff --git a/src/test/ui/traits/trait-object-macro-matcher.stderr b/src/test/ui/traits/trait-object-macro-matcher.stderr index cb48bd1258..bc56736073 100644 --- a/src/test/ui/traits/trait-object-macro-matcher.stderr +++ b/src/test/ui/traits/trait-object-macro-matcher.stderr @@ -4,11 +4,11 @@ error[E0224]: at least one trait is required for an object type LL | m!(dyn 'static +); | ^^^^^^^^^^^^^ -error[E0038]: the trait `std::marker::Copy` cannot be made into an object +error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/trait-object-macro-matcher.rs:8:8 | LL | m!(dyn Copy + Send + 'static); - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` diff --git a/src/test/ui/traits/trait-object-safety.stderr b/src/test/ui/traits/trait-object-safety.stderr index 162e9249b8..3fa7c0c484 100644 --- a/src/test/ui/traits/trait-object-safety.stderr +++ b/src/test/ui/traits/trait-object-safety.stderr @@ -9,7 +9,7 @@ LL | fn foo(); LL | let _: &dyn Tr = &St; | ^^^ the trait `Tr` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Tr>` for `&St` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Tr>` for `&St` = note: required by cast to type `&dyn Tr` help: consider turning `foo` into a method by giving it a `&self` argument or constraining it so it does not apply to trait objects | diff --git a/src/test/ui/traits/trait-safety-trait-impl-cc.stderr b/src/test/ui/traits/trait-safety-trait-impl-cc.stderr index 5234e205a8..2fcedc5cc5 100644 --- a/src/test/ui/traits/trait-safety-trait-impl-cc.stderr +++ b/src/test/ui/traits/trait-safety-trait-impl-cc.stderr @@ -1,4 +1,4 @@ -error[E0200]: the trait `lib::Foo` requires an `unsafe impl` declaration +error[E0200]: the trait `Foo` requires an `unsafe impl` declaration --> $DIR/trait-safety-trait-impl-cc.rs:9:1 | LL | / impl lib::Foo for Bar { diff --git a/src/test/ui/traits/trait-static-method-generic-inference.stderr b/src/test/ui/traits/trait-static-method-generic-inference.stderr index 8f20cc5093..6a7e8f59d8 100644 --- a/src/test/ui/traits/trait-static-method-generic-inference.stderr +++ b/src/test/ui/traits/trait-static-method-generic-inference.stderr @@ -2,12 +2,12 @@ error[E0283]: type annotations needed --> $DIR/trait-static-method-generic-inference.rs:24:25 | LL | fn new() -> T; - | -------------- required by `base::HasNew::new` + | -------------- required by `HasNew::new` ... LL | let _f: base::Foo = base::HasNew::new(); | ^^^^^^^^^^^^^^^^^ cannot infer type | - = note: cannot satisfy `_: base::HasNew` + = note: cannot satisfy `_: HasNew` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed index 2bb34b0ebe..a1abf668b8 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.fixed @@ -14,5 +14,5 @@ fn main() { let _works = TcpListener::bind("some string"); let bad = NoToSocketAddrs("bad".to_owned()); let _errors = TcpListener::bind(&*bad); - //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied + //~^ ERROR the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs index 33d524608a..90d097105e 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.rs @@ -14,5 +14,5 @@ fn main() { let _works = TcpListener::bind("some string"); let bad = NoToSocketAddrs("bad".to_owned()); let _errors = TcpListener::bind(&bad); - //~^ ERROR the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied + //~^ ERROR the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr index 6dff2e418c..4273b8e3f3 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr +++ b/src/test/ui/traits/trait-suggest-deferences-issue-39029.stderr @@ -1,18 +1,18 @@ -error[E0277]: the trait bound `NoToSocketAddrs: std::net::ToSocketAddrs` is not satisfied +error[E0277]: the trait bound `NoToSocketAddrs: ToSocketAddrs` is not satisfied --> $DIR/trait-suggest-deferences-issue-39029.rs:16:37 | LL | let _errors = TcpListener::bind(&bad); | ^^^^ | | - | the trait `std::net::ToSocketAddrs` is not implemented for `NoToSocketAddrs` + | the trait `ToSocketAddrs` is not implemented for `NoToSocketAddrs` | help: consider adding dereference here: `&*bad` | ::: $SRC_DIR/std/src/net/tcp.rs:LL:COL | LL | pub fn bind(addr: A) -> io::Result { - | ------------- required by this bound in `std::net::TcpListener::bind` + | ------------- required by this bound in `TcpListener::bind` | - = note: required because of the requirements on the impl of `std::net::ToSocketAddrs` for `&NoToSocketAddrs` + = note: required because of the requirements on the impl of `ToSocketAddrs` for `&NoToSocketAddrs` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed index fa7b9167d8..406caaa007 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.fixed @@ -11,5 +11,5 @@ fn main() { let string = String::new(); takes_str(&string); // Ok takes_type_parameter(&*string); // Error - //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied + //~^ ERROR the trait bound `&String: SomeTrait` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs index e785f01217..53846be730 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.rs @@ -11,5 +11,5 @@ fn main() { let string = String::new(); takes_str(&string); // Ok takes_type_parameter(&string); // Error - //~^ ERROR the trait bound `&std::string::String: SomeTrait` is not satisfied + //~^ ERROR the trait bound `&String: SomeTrait` is not satisfied } diff --git a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr index 9c2a582638..eaec87d01d 100644 --- a/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr +++ b/src/test/ui/traits/trait-suggest-deferences-issue-62530.stderr @@ -1,4 +1,4 @@ -error[E0277]: the trait bound `&std::string::String: SomeTrait` is not satisfied +error[E0277]: the trait bound `&String: SomeTrait` is not satisfied --> $DIR/trait-suggest-deferences-issue-62530.rs:13:26 | LL | fn takes_type_parameter(_x: T) where T: SomeTrait {} @@ -7,7 +7,7 @@ LL | fn takes_type_parameter(_x: T) where T: SomeTrait {} LL | takes_type_parameter(&string); // Error | ^^^^^^^ | | - | the trait `SomeTrait` is not implemented for `&std::string::String` + | the trait `SomeTrait` is not implemented for `&String` | help: consider adding dereference here: `&*string` error: aborting due to previous error diff --git a/src/test/ui/traits/trait-suggest-where-clause.rs b/src/test/ui/traits/trait-suggest-where-clause.rs index 8405e5ff62..46d047a2de 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.rs +++ b/src/test/ui/traits/trait-suggest-where-clause.rs @@ -13,15 +13,15 @@ fn check() { // ... even if T occurs as a type parameter >::from; - //~^ ERROR `u64: std::convert::From` is not satisfied + //~^ ERROR `u64: From` is not satisfied ::Item>>::from; - //~^ ERROR `u64: std::convert::From<::Item>` is not satisfied + //~^ ERROR `u64: From<::Item>` is not satisfied // ... but not if there are inference variables as From>::from; - //~^ ERROR `Misc<_>: std::convert::From` is not satisfied + //~^ ERROR `Misc<_>: From` is not satisfied // ... and also not if the error is not related to the type diff --git a/src/test/ui/traits/trait-suggest-where-clause.stderr b/src/test/ui/traits/trait-suggest-where-clause.stderr index 73da2a6eb4..0f6f8d75c5 100644 --- a/src/test/ui/traits/trait-suggest-where-clause.stderr +++ b/src/test/ui/traits/trait-suggest-where-clause.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `U` cannot be known at compilation tim --> $DIR/trait-suggest-where-clause.rs:7:20 | LL | fn check() { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | // suggest a where-clause, if needed LL | mem::size_of::(); | ^ doesn't have a size known at compile-time @@ -16,7 +16,7 @@ error[E0277]: the size for values of type `U` cannot be known at compilation tim --> $DIR/trait-suggest-where-clause.rs:10:5 | LL | fn check() { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | mem::size_of::>(); | ^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -28,29 +28,29 @@ LL | pub const fn size_of() -> usize { | = note: required because it appears within the type `Misc` -error[E0277]: the trait bound `u64: std::convert::From` is not satisfied +error[E0277]: the trait bound `u64: From` is not satisfied --> $DIR/trait-suggest-where-clause.rs:15:5 | LL | >::from; - | ^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From` is not implemented for `u64` + | ^^^^^^^^^^^^^^^^^^^^^^ the trait `From` is not implemented for `u64` | - = note: required by `std::convert::From::from` + = note: required by `from` -error[E0277]: the trait bound `u64: std::convert::From<::Item>` is not satisfied +error[E0277]: the trait bound `u64: From<::Item>` is not satisfied --> $DIR/trait-suggest-where-clause.rs:18:5 | LL | ::Item>>::from; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From<::Item>` is not implemented for `u64` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From<::Item>` is not implemented for `u64` | - = note: required by `std::convert::From::from` + = note: required by `from` -error[E0277]: the trait bound `Misc<_>: std::convert::From` is not satisfied +error[E0277]: the trait bound `Misc<_>: From` is not satisfied --> $DIR/trait-suggest-where-clause.rs:23:5 | LL | as From>::from; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::convert::From` is not implemented for `Misc<_>` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `From` is not implemented for `Misc<_>` | - = note: required by `std::convert::From::from` + = note: required by `from` error[E0277]: the size for values of type `[T]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:28:20 @@ -63,7 +63,7 @@ LL | mem::size_of::<[T]>(); LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | - = help: the trait `std::marker::Sized` is not implemented for `[T]` + = help: the trait `Sized` is not implemented for `[T]` error[E0277]: the size for values of type `[&U]` cannot be known at compilation time --> $DIR/trait-suggest-where-clause.rs:31:5 @@ -76,7 +76,7 @@ LL | mem::size_of::<[&U]>(); LL | pub const fn size_of() -> usize { | - required by this bound in `std::mem::size_of` | - = help: the trait `std::marker::Sized` is not implemented for `[&U]` + = help: the trait `Sized` is not implemented for `[&U]` error: aborting due to 7 previous errors diff --git a/src/test/ui/traits/trait-test-2.stderr b/src/test/ui/traits/trait-test-2.stderr index 9d1eef5475..0a62f1aeb2 100644 --- a/src/test/ui/traits/trait-test-2.stderr +++ b/src/test/ui/traits/trait-test-2.stderr @@ -39,8 +39,8 @@ LL | (box 10 as Box).dup(); | = help: consider moving `dup` to another trait = help: consider moving `blah` to another trait - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box<{integer}>` - = note: required by cast to type `std::boxed::Box` + = 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 diff --git a/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr b/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr index 604763f8e3..5ac7b08e52 100644 --- a/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr +++ b/src/test/ui/traits/traits-assoc-type-in-supertrait-bad.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as std::iter::Iterator>::Item == u32` +error[E0271]: type mismatch resolving ` as Iterator>::Item == u32` --> $DIR/traits-assoc-type-in-supertrait-bad.rs:12:16 | LL | type Key = u32; diff --git a/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr b/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr index 9a227229ea..b904826081 100644 --- a/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-lifetime.stderr @@ -1,4 +1,4 @@ -error[E0275]: overflow evaluating the requirement `std::boxed::Box>>: NotAuto` +error[E0275]: overflow evaluating the requirement `Box>>: NotAuto` --> $DIR/traits-inductive-overflow-lifetime.rs:27:5 | LL | fn is_send() {} diff --git a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr index b97197285e..c11234ee48 100644 --- a/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr +++ b/src/test/ui/traits/traits-inductive-overflow-supertrait-oibit.stderr @@ -6,14 +6,14 @@ LL | auto trait Magic: Copy {} | | | auto trait cannot have super traits -error[E0277]: the trait bound `NoClone: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `NoClone: Copy` is not satisfied --> $DIR/traits-inductive-overflow-supertrait-oibit.rs:16:23 | LL | fn copy(x: T) -> (T, T) { (x, x) } | ----- required by this bound in `copy` ... LL | let (a, b) = copy(NoClone); - | ^^^^^^^ the trait `std::marker::Copy` is not implemented for `NoClone` + | ^^^^^^^ the trait `Copy` is not implemented for `NoClone` | = note: required because of the requirements on the impl of `Magic` for `NoClone` diff --git a/src/test/ui/traits/traits-issue-71136.stderr b/src/test/ui/traits/traits-issue-71136.stderr index 4c0a43062f..23a8040f6f 100644 --- a/src/test/ui/traits/traits-issue-71136.stderr +++ b/src/test/ui/traits/traits-issue-71136.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `Foo: std::clone::Clone` is not satisfied +error[E0277]: the trait bound `Foo: Clone` is not satisfied --> $DIR/traits-issue-71136.rs:5:5 | LL | the_foos: Vec, - | ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `std::clone::Clone` + | ^^^^^^^^^^^^^^^^^^ expected an implementor of trait `Clone` | - = note: required because of the requirements on the impl of `std::clone::Clone` for `std::vec::Vec` - = note: required by `std::clone::Clone::clone` + = note: required because of the requirements on the impl of `Clone` for `Vec` + = note: required by `clone` = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error diff --git a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr index 1a6093343a..aefe3fb8e2 100644 --- a/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr +++ b/src/test/ui/transmute/transmute-from-fn-item-types-error.stderr @@ -13,7 +13,7 @@ error[E0591]: can't transmute zero-sized type LL | let p = mem::transmute(foo); | ^^^^^^^^^^^^^^ | - = note: source type: unsafe fn() -> (i8, *const (), std::option::Option) {foo} + = note: source type: unsafe fn() -> (i8, *const (), Option) {foo} = note: target type: *const () = help: cast with `as` to a pointer instead @@ -24,7 +24,7 @@ LL | let of = mem::transmute(main); | ^^^^^^^^^^^^^^ | = note: source type: fn() {main} - = note: target type: std::option::Option + = note: target type: Option = help: cast with `as` to a pointer instead error[E0512]: cannot transmute between types of different sizes, or dependently-sized types @@ -42,7 +42,7 @@ error[E0591]: can't transmute zero-sized type LL | mem::transmute::<_, *mut ()>(foo); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: source type: unsafe fn() -> (i8, *const (), std::option::Option) {foo} + = note: source type: unsafe fn() -> (i8, *const (), Option) {foo} = note: target type: *mut () = help: cast with `as` to a pointer instead @@ -62,7 +62,7 @@ error[E0591]: can't transmute zero-sized type LL | mem::transmute::<_, *mut ()>(Some(foo)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | - = note: source type: unsafe fn() -> (i8, *const (), std::option::Option) {foo} + = note: source type: unsafe fn() -> (i8, *const (), Option) {foo} = note: target type: *mut () = help: cast with `as` to a pointer instead @@ -83,7 +83,7 @@ LL | mem::transmute::<_, Option>(Some(baz)); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: source type: unsafe fn() {baz} - = note: target type: std::option::Option + = note: target type: Option = help: cast with `as` to a pointer instead error: aborting due to 9 previous errors diff --git a/src/test/ui/transmute/transmute-type-parameters.stderr b/src/test/ui/transmute/transmute-type-parameters.stderr index a355a1bf31..220b929d4f 100644 --- a/src/test/ui/transmute/transmute-type-parameters.stderr +++ b/src/test/ui/transmute/transmute-type-parameters.stderr @@ -49,7 +49,7 @@ error[E0512]: cannot transmute between types of different sizes, or dependently- LL | let _: i32 = transmute(x); | ^^^^^^^^^ | - = note: source type: `std::option::Option` (size can vary because of T) + = note: source type: `Option` (size can vary because of T) = note: target type: `i32` (32 bits) error: aborting due to 6 previous errors diff --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr index 39f7fb148f..7bd951febf 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-copy.stderr @@ -1,4 +1,4 @@ -warning: Trait bound std::string::String: std::marker::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 @@ LL | fn copy_string(t: String) -> String where String: Copy { | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound std::string::String: std::marker::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 std::string::String: std::marker::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: std::marker::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 --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr index aa5d4fcc72..ff254edbd7 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-sized.stderr @@ -1,4 +1,4 @@ -warning: Trait bound str: std::marker::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 @@ LL | struct S(str, str) where str: Sized; | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound for<'a> T<(dyn A + 'a)>: std::marker::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: std::marker::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 --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr index ffcfbdf54a..a9905052ff 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent-well-formed.stderr @@ -1,4 +1,4 @@ -warning: Trait bound std::vec::Vec: std::fmt::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 @@ LL | pub fn foo() where Vec: Debug, str: Copy { | = note: `#[warn(trivial_bounds)]` on by default -warning: Trait bound str: std::marker::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 --git a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr index d863cf6249..38245010c7 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-inconsistent.stderr @@ -60,31 +60,31 @@ warning: Trait bound &'static str: Foo does not depend on any type or lifetime p LL | fn g() where &'static str: Foo { | ^^^ -warning: Trait bound str: std::marker::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)>: std::marker::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: std::marker::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 std::string::String: std::ops::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: std::iter::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 --git a/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr index e96a241968..b3ec3cd8d9 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak-copy.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `*t` which is behind a shared reference --> $DIR/trivial-bounds-leak-copy.rs:9:5 | LL | *t - | ^^ move occurs because `*t` has type `std::string::String`, which does not implement the `Copy` trait + | ^^ move occurs because `*t` has type `String`, which does not implement the `Copy` trait error: aborting due to previous error diff --git a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr index 4f4695612d..de7a431d6f 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-leak.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | fn cant_return_str() -> str { | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: the return type of a function must have a statically known size error[E0599]: no method named `test` found for type `i32` in the current scope diff --git a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr index 3f2162365d..c685d9e740 100644 --- a/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr +++ b/src/test/ui/trivial-bounds/trivial-bounds-lint.stderr @@ -1,4 +1,4 @@ -error: Trait bound i32: std::marker::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; @@ -40,7 +40,7 @@ error: Lifetime bound 'static: 'static does not depend on any type or lifetime p LL | fn global_outlives() where 'static: 'static {} | ^^^^^^^ -error: Trait bound i32: std::marker::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 --git a/src/test/ui/trivial_casts.rs b/src/test/ui/trivial_casts.rs index dd578e074f..0a8b9de1de 100644 --- a/src/test/ui/trivial_casts.rs +++ b/src/test/ui/trivial_casts.rs @@ -43,7 +43,7 @@ pub fn main() { let x: Box<[u32; 3]> = Box::new([42, 43, 44]); let _ = x as Box<[u32]>; - //~^ ERROR trivial cast: `std::boxed::Box<[u32; 3]>` as `std::boxed::Box<[u32]>` + //~^ ERROR trivial cast: `Box<[u32; 3]>` as `Box<[u32]>` let x: Box<[u32; 3]> = Box::new([42, 43, 44]); let _: Box<[u32]> = x; @@ -61,13 +61,13 @@ pub fn main() { let _: *mut dyn Foo = x; let x: Box = Box::new(Bar); - let _ = x as Box; //~ERROR `std::boxed::Box` as `std::boxed::Box` + let _ = x as Box; //~ERROR `Box` as `Box` let x: Box = Box::new(Bar); let _: Box = x; // functions fn baz(_x: i32) {} - let _ = &baz as &dyn Fn(i32); //~ERROR `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` + let _ = &baz as &dyn Fn(i32); //~ERROR `&fn(i32) {baz}` as `&dyn Fn(i32)` let _: &dyn Fn(i32) = &baz; let x = |_x: i32| {}; let _ = &x as &dyn Fn(i32); //~ERROR trivial cast diff --git a/src/test/ui/trivial_casts.stderr b/src/test/ui/trivial_casts.stderr index 70954f00ba..141703460b 100644 --- a/src/test/ui/trivial_casts.stderr +++ b/src/test/ui/trivial_casts.stderr @@ -72,7 +72,7 @@ LL | let _ = x as *mut [u32]; | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `std::boxed::Box<[u32; 3]>` as `std::boxed::Box<[u32]>` +error: trivial cast: `Box<[u32; 3]>` as `Box<[u32]>` --> $DIR/trivial_casts.rs:45:13 | LL | let _ = x as Box<[u32]>; @@ -112,7 +112,7 @@ LL | let _ = x as *mut dyn Foo; | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `std::boxed::Box` as `std::boxed::Box` +error: trivial cast: `Box` as `Box` --> $DIR/trivial_casts.rs:64:13 | LL | let _ = x as Box; @@ -120,7 +120,7 @@ LL | let _ = x as Box; | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `&fn(i32) {main::baz}` as `&dyn std::ops::Fn(i32)` +error: trivial cast: `&fn(i32) {baz}` as `&dyn Fn(i32)` --> $DIR/trivial_casts.rs:70:13 | LL | let _ = &baz as &dyn Fn(i32); @@ -128,7 +128,7 @@ LL | let _ = &baz as &dyn Fn(i32); | = help: cast can be replaced by coercion; this might require a temporary variable -error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:25]` as `&dyn std::ops::Fn(i32)` +error: trivial cast: `&[closure@$DIR/trivial_casts.rs:72:13: 72:25]` as `&dyn Fn(i32)` --> $DIR/trivial_casts.rs:73:13 | LL | let _ = &x as &dyn Fn(i32); diff --git a/src/test/ui/try-block/try-block-bad-type.rs b/src/test/ui/try-block/try-block-bad-type.rs index 4dfc8e6a2f..c338294913 100644 --- a/src/test/ui/try-block/try-block-bad-type.rs +++ b/src/test/ui/try-block/try-block-bad-type.rs @@ -14,7 +14,7 @@ pub fn main() { let res: Result = try { }; //~ ERROR type mismatch - let res: () = try { }; //~ the trait bound `(): std::ops::Try` is not satisfied + let res: () = try { }; //~ the trait bound `(): Try` is not satisfied - let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: std::ops::Try` is not satisfied + let res: i32 = try { 5 }; //~ ERROR the trait bound `i32: Try` is not satisfied } diff --git a/src/test/ui/try-block/try-block-bad-type.stderr b/src/test/ui/try-block/try-block-bad-type.stderr index 414c3f24d3..03d5d3661d 100644 --- a/src/test/ui/try-block/try-block-bad-type.stderr +++ b/src/test/ui/try-block/try-block-bad-type.stderr @@ -2,44 +2,44 @@ error[E0277]: `?` couldn't convert the error to `i32` --> $DIR/try-block-bad-type.rs:7:16 | LL | Err("")?; - | ^ the trait `std::convert::From<&str>` is not implemented for `i32` + | ^ the trait `From<&str>` is not implemented for `i32` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait = help: the following implementations were found: - > - > - > - > + > + > + > + > and 2 others - = note: required by `std::convert::From::from` + = note: required by `from` -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == &str` +error[E0271]: type mismatch resolving ` as Try>::Ok == &str` --> $DIR/try-block-bad-type.rs:12:9 | LL | "" | ^^ expected `i32`, found `&str` -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == ()` +error[E0271]: type mismatch resolving ` as Try>::Ok == ()` --> $DIR/try-block-bad-type.rs:15:39 | LL | let res: Result = try { }; | ^ expected `i32`, found `()` -error[E0277]: the trait bound `(): std::ops::Try` is not satisfied +error[E0277]: the trait bound `(): Try` is not satisfied --> $DIR/try-block-bad-type.rs:17:23 | LL | let res: () = try { }; - | ^^^ the trait `std::ops::Try` is not implemented for `()` + | ^^^ the trait `Try` is not implemented for `()` | - = note: required by `std::ops::Try::from_ok` + = note: required by `from_ok` -error[E0277]: the trait bound `i32: std::ops::Try` is not satisfied +error[E0277]: the trait bound `i32: Try` is not satisfied --> $DIR/try-block-bad-type.rs:19:24 | LL | let res: i32 = try { 5 }; - | ^^^^^ the trait `std::ops::Try` is not implemented for `i32` + | ^^^^^ the trait `Try` is not implemented for `i32` | - = note: required by `std::ops::Try::from_ok` + = note: required by `from_ok` error: aborting due to 5 previous errors diff --git a/src/test/ui/try-block/try-block-in-return.rs b/src/test/ui/try-block/try-block-in-return.rs new file mode 100644 index 0000000000..a15bfeef1c --- /dev/null +++ b/src/test/ui/try-block/try-block-in-return.rs @@ -0,0 +1,12 @@ +// run-pass +// compile-flags: --edition 2018 + +#![feature(try_blocks)] + +fn issue_76271() -> Option { + return try { 4 } +} + +fn main() { + assert_eq!(issue_76271(), Some(4)); +} diff --git a/src/test/ui/try-block/try-block-in-while.rs b/src/test/ui/try-block/try-block-in-while.rs index 33d2723651..5d8748f1dd 100644 --- a/src/test/ui/try-block/try-block-in-while.rs +++ b/src/test/ui/try-block/try-block-in-while.rs @@ -4,5 +4,5 @@ fn main() { while try { false } {} - //~^ ERROR the trait bound `bool: std::ops::Try` is not satisfied + //~^ ERROR the trait bound `bool: Try` is not satisfied } diff --git a/src/test/ui/try-block/try-block-in-while.stderr b/src/test/ui/try-block/try-block-in-while.stderr index ac41ddfd8c..bc0f5bb650 100644 --- a/src/test/ui/try-block/try-block-in-while.stderr +++ b/src/test/ui/try-block/try-block-in-while.stderr @@ -1,10 +1,10 @@ -error[E0277]: the trait bound `bool: std::ops::Try` is not satisfied +error[E0277]: the trait bound `bool: Try` is not satisfied --> $DIR/try-block-in-while.rs:6:15 | LL | while try { false } {} - | ^^^^^^^^^ the trait `std::ops::Try` is not implemented for `bool` + | ^^^^^^^^^ the trait `Try` is not implemented for `bool` | - = note: required by `std::ops::Try::from_ok` + = note: required by `from_ok` error: aborting due to previous error diff --git a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr index 1f0e09277b..c092aa2694 100644 --- a/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr +++ b/src/test/ui/try-block/try-block-maybe-bad-lifetime.stderr @@ -14,7 +14,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/try-block-maybe-bad-lifetime.rs:28:24 | LL | let x = String::new(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait ... LL | ::std::mem::drop(x); | - value moved here diff --git a/src/test/ui/try-block/try-block-type-error.stderr b/src/test/ui/try-block/try-block-type-error.stderr index f779121bbc..df1441c83d 100644 --- a/src/test/ui/try-block/try-block-type-error.stderr +++ b/src/test/ui/try-block/try-block-type-error.stderr @@ -1,4 +1,4 @@ -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == {integer}` +error[E0271]: type mismatch resolving ` as Try>::Ok == {integer}` --> $DIR/try-block-type-error.rs:10:9 | LL | 42 @@ -7,7 +7,7 @@ LL | 42 | expected `f32`, found integer | help: use a float literal: `42.0` -error[E0271]: type mismatch resolving ` as std::ops::Try>::Ok == ()` +error[E0271]: type mismatch resolving ` as Try>::Ok == ()` --> $DIR/try-block-type-error.rs:16:5 | LL | }; diff --git a/src/test/ui/try-on-option-diagnostics.stderr b/src/test/ui/try-on-option-diagnostics.stderr index c9dc3f1b87..a71ee20aac 100644 --- a/src/test/ui/try-on-option-diagnostics.stderr +++ b/src/test/ui/try-on-option-diagnostics.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:7:5 | LL | / fn a_function() -> u32 { @@ -9,10 +9,10 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a closure that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:14:9 | LL | let a_closure = || { @@ -24,10 +24,10 @@ LL | | 22 LL | | }; | |_____- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `{integer}` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `{integer}` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a method that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:26:13 | LL | / fn a_method() { @@ -37,10 +37,10 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` -error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a trait method that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option-diagnostics.rs:39:13 | LL | / fn a_trait_method() { @@ -50,8 +50,8 @@ LL | | x?; LL | | } | |_________- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` error: aborting due to 4 previous errors diff --git a/src/test/ui/try-on-option.stderr b/src/test/ui/try-on-option.stderr index 33ca58bf7f..ecd12c430f 100644 --- a/src/test/ui/try-on-option.stderr +++ b/src/test/ui/try-on-option.stderr @@ -5,16 +5,16 @@ LL | fn foo() -> Result { | --------------- expected `()` because of this LL | let x: Option = None; LL | x?; - | ^ the trait `std::convert::From` is not implemented for `()` + | ^ the trait `From` is not implemented for `()` | = note: the question mark operation (`?`) implicitly performs a conversion on the error value using the `From` trait - = note: required by `std::convert::From::from` + = note: required by `from` help: consider converting the `Option` into a `Result` using `Option::ok_or` or `Option::ok_or_else` | LL | x.ok_or_else(|| /* error value */)?; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-on-option.rs:13:5 | LL | / fn bar() -> u32 { @@ -25,8 +25,8 @@ LL | | 22 LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `u32` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `u32` + = note: required by `from_error` error: aborting due to 2 previous errors diff --git a/src/test/ui/try-operator-on-main.rs b/src/test/ui/try-operator-on-main.rs index 602c3c5c35..a8a99a150c 100644 --- a/src/test/ui/try-operator-on-main.rs +++ b/src/test/ui/try-operator-on-main.rs @@ -19,7 +19,7 @@ fn main() { fn try_trait_generic() -> T { // and a non-`Try` object on a `Try` fn. - ()?; //~ ERROR the `?` operator can only be applied to values that implement `std::ops::Try` + ()?; //~ ERROR the `?` operator can only be applied to values that implement `Try` loop {} } diff --git a/src/test/ui/try-operator-on-main.stderr b/src/test/ui/try-operator-on-main.stderr index ecad5a7d11..f2e17812ae 100644 --- a/src/test/ui/try-operator-on-main.stderr +++ b/src/test/ui/try-operator-on-main.stderr @@ -1,4 +1,4 @@ -error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `std::ops::Try`) +error[E0277]: the `?` operator can only be used in a function that returns `Result` or `Option` (or another type that implements `Try`) --> $DIR/try-operator-on-main.rs:9:5 | LL | / fn main() { @@ -11,35 +11,35 @@ LL | | try_trait_generic::<()>(); LL | | } | |_- this function should return `Result` or `Option` to accept `?` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::from_error` + = help: the trait `Try` is not implemented for `()` + = note: required by `from_error` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/try-operator-on-main.rs:12:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `()` + = note: required by `into_result` -error[E0277]: the trait bound `(): std::ops::Try` is not satisfied +error[E0277]: the trait bound `(): Try` is not satisfied --> $DIR/try-operator-on-main.rs:15:25 | LL | try_trait_generic::<()>(); - | ^^ the trait `std::ops::Try` is not implemented for `()` + | ^^ the trait `Try` is not implemented for `()` ... LL | fn try_trait_generic() -> T { | --- required by this bound in `try_trait_generic` -error[E0277]: the `?` operator can only be applied to values that implement `std::ops::Try` +error[E0277]: the `?` operator can only be applied to values that implement `Try` --> $DIR/try-operator-on-main.rs:22:5 | LL | ()?; | ^^^ the `?` operator cannot be applied to type `()` | - = help: the trait `std::ops::Try` is not implemented for `()` - = note: required by `std::ops::Try::into_result` + = help: the trait `Try` is not implemented for `()` + = note: required by `into_result` error: aborting due to 4 previous errors diff --git a/src/test/ui/tuple/index-invalid.stderr b/src/test/ui/tuple/index-invalid.stderr index 800b5a31d9..8d22f458a6 100644 --- a/src/test/ui/tuple/index-invalid.stderr +++ b/src/test/ui/tuple/index-invalid.stderr @@ -2,19 +2,19 @@ error[E0609]: no field `1` on type `(((),),)` --> $DIR/index-invalid.rs:2:22 | LL | let _ = (((),),).1.0; - | ^^^ + | ^ error[E0609]: no field `1` on type `((),)` - --> $DIR/index-invalid.rs:4:22 + --> $DIR/index-invalid.rs:4:24 | LL | let _ = (((),),).0.1; - | ^^^ + | ^ error[E0609]: no field `000` on type `(((),),)` --> $DIR/index-invalid.rs:6:22 | LL | let _ = (((),),).000.000; - | ^^^^^^^ + | ^^^ error: aborting due to 3 previous errors diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs index 63b21faa62..8dadd77fc1 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.rs @@ -1,8 +1,8 @@ #[repr(u8)] enum Alpha { V1 = 41, - V2 = Self::V1 as u8 + 1, // OK; See #50072. - V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when const-evaluating + V2 = Self::V1 as u8 + 1, // OK; See #50072. + V3 = Self::V1 {} as u8 + 2, //~ ERROR cycle detected when simplifying constant } fn main() {} diff --git a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr index db535b53fc..277f4e8424 100644 --- a/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr +++ b/src/test/ui/type-alias-enum-variants/self-in-enum-definition.stderr @@ -1,28 +1,28 @@ -error[E0391]: cycle detected when const-evaluating + checking `Alpha::V3::{{constant}}#0` +error[E0391]: cycle detected when simplifying constant for the type system `Alpha::V3::{constant#0}` --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ | -note: ...which requires const-evaluating + checking `Alpha::V3::{{constant}}#0`... +note: ...which requires simplifying constant for the type system `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ -note: ...which requires const-evaluating `Alpha::V3::{{constant}}#0`... +note: ...which requires const-evaluating + checking `Alpha::V3::{constant#0}`... --> $DIR/self-in-enum-definition.rs:5:10 | LL | V3 = Self::V1 {} as u8 + 2, | ^^^^^^^^ = note: ...which requires computing layout of `Alpha`... - = note: ...which again requires const-evaluating + checking `Alpha::V3::{{constant}}#0`, completing the cycle + = note: ...which again requires simplifying constant for the type system `Alpha::V3::{constant#0}`, completing the cycle note: cycle used when collecting item types in top-level module --> $DIR/self-in-enum-definition.rs:1:1 | LL | / #[repr(u8)] LL | | enum Alpha { LL | | V1 = 41, -LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072. +LL | | V2 = Self::V1 as u8 + 1, // OK; See #50072. ... | LL | | LL | | fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs index 0a4cc9b7fe..a15074c359 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.rs +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.rs @@ -1,19 +1,18 @@ #![feature(type_alias_impl_trait)] -fn main() { -} +fn main() {} trait TraitWithAssoc { type Assoc; } type Foo = impl Trait; -//~^ ERROR the trait bound `T: TraitWithAssoc` is not satisfied trait Trait {} impl Trait for () {} fn foo_desugared(_: T) -> Foo { + //~^ ERROR non-defining opaque type use in defining scope () } diff --git a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr index 9ebf63468e..c9d6a43b90 100644 --- a/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr +++ b/src/test/ui/type-alias-impl-trait/bound_reduction2.stderr @@ -1,14 +1,14 @@ -error[E0277]: the trait bound `T: TraitWithAssoc` is not satisfied - --> $DIR/bound_reduction2.rs:10:15 +error: non-defining opaque type use in defining scope + --> $DIR/bound_reduction2.rs:15:46 + | +LL | fn foo_desugared(_: T) -> Foo { + | ^^^^^^^^^^^^^ + | +note: used non-generic type `::Assoc` for generic parameter + --> $DIR/bound_reduction2.rs:9:10 | LL | type Foo = impl Trait; - | ^^^^^^^^^^^^^ the trait `TraitWithAssoc` is not implemented for `T` - | -help: consider further restricting this bound - | -LL | fn foo_desugared(_: T) -> Foo { - | ^^^^^^^^^^^^^^^^ + | ^ error: aborting due to previous error -For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs index 09873a8c8c..7ea517eb73 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs +++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.rs @@ -9,4 +9,5 @@ mod boo { fn bomp() -> boo::Boo { "" + //~^ mismatched types } diff --git a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr index c0cb94b15d..0b4c262bbb 100644 --- a/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr +++ b/src/test/ui/type-alias-impl-trait/declared_but_not_defined_in_scope.stderr @@ -4,5 +4,20 @@ error: could not find defining uses LL | pub type Boo = impl ::std::fmt::Debug; | ^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to previous error +error[E0308]: mismatched types + --> $DIR/declared_but_not_defined_in_scope.rs:11:5 + | +LL | pub type Boo = impl ::std::fmt::Debug; + | ---------------------- the expected opaque type +... +LL | fn bomp() -> boo::Boo { + | -------- expected `impl Debug` because of return type +LL | "" + | ^^ expected opaque type, found `&str` + | + = note: expected opaque type `impl Debug` + found reference `&'static str` +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0308`. diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs index 2b98d8fc63..a74731df69 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.rs @@ -8,10 +8,10 @@ fn main() {} type Two = impl Debug; fn one(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope t } fn two(t: T, _: U) -> Two { -//~^ ERROR concrete type differs from previous defining opaque type use t } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr index 7900da47ca..d87e8c5783 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use2.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/generic_duplicate_param_use2.rs:14:1 - | -LL | fn two(t: T, _: U) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` - | -note: previous use here - --> $DIR/generic_duplicate_param_use2.rs:10:1 +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use2.rs:10:27 | LL | fn one(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ + | +note: type used multiple times + --> $DIR/generic_duplicate_param_use2.rs:8:10 + | +LL | type Two = impl Debug; + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs index d9133fd11f..0597b8385d 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.rs @@ -8,11 +8,11 @@ fn main() {} type Two = impl Debug; fn one(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope t } fn two(t: T, _: U) -> Two { -//~^ ERROR concrete type differs from previous defining opaque type use t } diff --git a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr index ac5f7947d5..711de855f0 100644 --- a/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_duplicate_param_use3.stderr @@ -1,14 +1,14 @@ -error: concrete type differs from previous defining opaque type use - --> $DIR/generic_duplicate_param_use3.rs:14:1 - | -LL | fn two(t: T, _: U) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ expected `U`, got `T` - | -note: previous use here - --> $DIR/generic_duplicate_param_use3.rs:10:1 +error: non-defining opaque type use in defining scope + --> $DIR/generic_duplicate_param_use3.rs:10:27 | LL | fn one(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^ + | +note: type used multiple times + --> $DIR/generic_duplicate_param_use3.rs:8:10 + | +LL | type Two = impl Debug; + | ^ ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs index 589612d5ed..766ee36c02 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.rs @@ -3,10 +3,11 @@ fn main() {} trait Trait {} -type Underconstrained = impl 'static; //~ ERROR the trait bound `T: Trait` +type Underconstrained = impl 'static; //~^ ERROR: at least one trait must be specified // no `Trait` bound fn underconstrain(_: T) -> Underconstrained { + //~^ ERROR the trait bound `T: Trait` unimplemented!() } diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr index 911f592f73..cefc5d99b3 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained.stderr @@ -5,12 +5,14 @@ LL | type Underconstrained = impl 'static; | ^^^^^^^^^^^^ error[E0277]: the trait bound `T: Trait` is not satisfied - --> $DIR/generic_underconstrained.rs:6:35 + --> $DIR/generic_underconstrained.rs:10:31 | LL | type Underconstrained = impl 'static; - | ^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` + | ----- required by this bound in `Underconstrained` +... +LL | fn underconstrain(_: T) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ the trait `Trait` is not implemented for `T` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `T` | LL | fn underconstrain(_: T) -> Underconstrained { diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs index 87b8aaad95..cd7c962e2d 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.rs @@ -3,19 +3,19 @@ fn main() {} type Underconstrained = impl 'static; -//~^ ERROR `U` doesn't implement `std::fmt::Debug` -//~^^ ERROR: at least one trait must be specified +//~^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained(_: U) -> Underconstrained { + //~^ ERROR `U` doesn't implement `Debug` 5u32 } type Underconstrained2 = impl 'static; -//~^ ERROR `V` doesn't implement `std::fmt::Debug` -//~^^ ERROR: at least one trait must be specified +//~^ ERROR: at least one trait must be specified // not a defining use, because it doesn't define *all* possible generics fn underconstrained2(_: U, _: V) -> Underconstrained2 { + //~^ ERROR `V` doesn't implement `Debug` 5u32 } diff --git a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr index 28e30cbdd9..669546aef8 100644 --- a/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr +++ b/src/test/ui/type-alias-impl-trait/generic_underconstrained2.stderr @@ -10,35 +10,33 @@ error: at least one trait must be specified LL | type Underconstrained2 = impl 'static; | ^^^^^^^^^^^^ -error[E0277]: `U` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:5:45 +error[E0277]: `U` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:9:33 | LL | type Underconstrained = impl 'static; - | ^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | --------------- required by this bound in `Underconstrained` ... -LL | 5u32 - | ---- this returned value is of type `u32` +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^^^^^^^^^^^^^ `U` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `U` | -LL | fn underconstrained(_: U) -> Underconstrained { - | ^^^^^^^^^^^^^^^^^ +LL | fn underconstrained(_: U) -> Underconstrained { + | ^^^^^^^ -error[E0277]: `V` doesn't implement `std::fmt::Debug` - --> $DIR/generic_underconstrained2.rs:14:46 +error[E0277]: `V` doesn't implement `Debug` + --> $DIR/generic_underconstrained2.rs:18:43 | LL | type Underconstrained2 = impl 'static; - | ^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `std::fmt::Debug` + | --------------- required by this bound in `Underconstrained2` ... -LL | 5u32 - | ---- this returned value is of type `u32` +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^^^^^^^^^^^^^^ `V` cannot be formatted using `{:?}` because it doesn't implement `Debug` | - = note: the return type of a function must have a statically known size help: consider restricting type parameter `V` | -LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { - | ^^^^^^^^^^^^^^^^^ +LL | fn underconstrained2(_: U, _: V) -> Underconstrained2 { + | ^^^^^^^ error: aborting due to 4 previous errors diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs index bc6543a922..851c2f66c4 100644 --- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.rs @@ -9,10 +9,9 @@ trait X { } impl X for () { + //~^ ERROR the type parameter `T` is not constrained type I = impl Sized; - //~^ ERROR could not find defining uses fn f() -> Self::I {} - //~^ ERROR type annotations needed } fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr index e8b677113d..8cf8fb1d16 100644 --- a/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr +++ b/src/test/ui/type-alias-impl-trait/impl-with-unconstrained-param.stderr @@ -1,15 +1,9 @@ -error[E0282]: type annotations needed - --> $DIR/impl-with-unconstrained-param.rs:14:23 +error[E0207]: the type parameter `T` is not constrained by the impl trait, self type, or predicates + --> $DIR/impl-with-unconstrained-param.rs:11:6 | -LL | fn f() -> Self::I {} - | ^^ cannot infer type for type parameter `T` +LL | impl X for () { + | ^ unconstrained type parameter -error: could not find defining uses - --> $DIR/impl-with-unconstrained-param.rs:12:14 - | -LL | type I = impl Sized; - | ^^^^^^^^^^ +error: aborting due to previous error -error: aborting due to 2 previous errors - -For more information about this error, try `rustc --explain E0282`. +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr index f8e1e55f23..cb893c40c3 100644 --- a/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr +++ b/src/test/ui/type-alias-impl-trait/incoherent-assoc-imp-trait.stderr @@ -5,8 +5,8 @@ LL | impl FnOnce<()> for &F { | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = note: conflicting implementation in crate `core`: - - impl std::ops::FnOnce for &F - where F: std::ops::Fn, F: ?Sized; + - impl FnOnce for &F + where F: Fn, F: ?Sized; error[E0210]: type parameter `F` must be used as the type parameter for some local type (e.g., `MyStruct`) --> $DIR/incoherent-assoc-imp-trait.rs:10:6 diff --git a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr index 13069126ba..d82050e263 100644 --- a/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-52843-closure-constrain.stderr @@ -2,7 +2,7 @@ error: concrete type differs from previous defining opaque type use --> $DIR/issue-52843-closure-constrain.rs:10:16 | LL | let null = || -> Opaque { 0 }; - | ^^^^^^^^^^^^^^^^^^ expected `std::string::String`, got `i32` + | ^^^^^^^^^^^^^^^^^^ expected `String`, got `i32` | note: previous use here --> $DIR/issue-52843-closure-constrain.rs:9:5 diff --git a/src/test/ui/type-alias-impl-trait/issue-53096.rs b/src/test/ui/type-alias-impl-trait/issue-53096.rs index 564c5c3d33..bdf426bbd3 100644 --- a/src/test/ui/type-alias-impl-trait/issue-53096.rs +++ b/src/test/ui/type-alias-impl-trait/issue-53096.rs @@ -1,5 +1,5 @@ // check-pass -#![feature(const_fn)] +#![feature(const_fn, const_fn_fn_ptr_basics)] #![feature(type_alias_impl_trait)] type Foo = impl Fn() -> usize; diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs index 41e019247c..782eb0fb3d 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.rs @@ -22,6 +22,6 @@ impl Foo for X { } } -trait Baz = Fn(&A) -> &B; +trait Baz = Fn(&A) -> &B; fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr index cd637056c9..a8706aa9a2 100644 --- a/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-57611-trait-alias.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | type Bar = impl Baz; | ^^^^^^^^^^^^^^^^^^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&X,)>` - found type `std::ops::FnOnce<(&X,)>` + = note: expected type `FnOnce<(&X,)>` + found type `FnOnce<(&X,)>` error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/issue-63279.stderr b/src/test/ui/type-alias-impl-trait/issue-63279.stderr index d07f64c331..9ad181b368 100644 --- a/src/test/ui/type-alias-impl-trait/issue-63279.stderr +++ b/src/test/ui/type-alias-impl-trait/issue-63279.stderr @@ -1,10 +1,10 @@ -error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:8:5: 8:28] as std::ops::FnOnce<()>>::Output == ()` +error[E0271]: type mismatch resolving `<[closure@$DIR/issue-63279.rs:8:5: 8:28] as FnOnce<()>>::Output == ()` --> $DIR/issue-63279.rs:5:16 | LL | type Closure = impl FnOnce(); | ^^^^^^^^^^^^^ expected opaque type, found `()` | - = note: expected opaque type `impl std::ops::FnOnce<()>` + = note: expected opaque type `impl FnOnce<()>` found unit type `()` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.rs b/src/test/ui/type-alias-impl-trait/issue-74761.rs new file mode 100644 index 0000000000..4345b5d886 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761.rs @@ -0,0 +1,16 @@ +#![feature(member_constraints)] +#![feature(type_alias_impl_trait)] + +pub trait A { + type B; + fn f(&self) -> Self::B; +} +impl<'a, 'b> A for () { + //~^ ERROR the lifetime parameter `'a` is not constrained + //~| ERROR the lifetime parameter `'b` is not constrained + type B = impl core::fmt::Debug; + + fn f(&self) -> Self::B {} +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-74761.stderr b/src/test/ui/type-alias-impl-trait/issue-74761.stderr new file mode 100644 index 0000000000..3f38fa4de0 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74761.stderr @@ -0,0 +1,15 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/issue-74761.rs:8: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.rs:8:10 + | +LL | impl<'a, 'b> A for () { + | ^^ unconstrained lifetime parameter + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs new file mode 100644 index 0000000000..9ce19536e7 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.rs @@ -0,0 +1,23 @@ +// Regression test for issue #76202 +// Tests that we don't ICE when we have a trait impl on a TAIT. + +#![feature(type_alias_impl_trait)] + +trait Dummy {} +impl Dummy for () {} + +type F = impl Dummy; +fn f() -> F {} + +trait Test { + fn test(self); +} + +impl Test for F { //~ ERROR cannot implement trait + fn test(self) {} +} + +fn main() { + let x: F = f(); + x.test(); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr new file mode 100644 index 0000000000..8689ee5366 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-76202-trait-impl-for-tait.stderr @@ -0,0 +1,14 @@ +error: cannot implement trait on type alias impl trait + --> $DIR/issue-76202-trait-impl-for-tait.rs:16:1 + | +LL | impl Test for F { + | ^^^^^^^^^^^^^^^ + | +note: type alias impl trait defined here + --> $DIR/issue-76202-trait-impl-for-tait.rs:9:10 + | +LL | type F = impl Dummy; + | ^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr index a6b7e35b48..b438f84451 100644 --- a/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr +++ b/src/test/ui/type-alias-impl-trait/never_reveal_concrete_type.stderr @@ -10,9 +10,9 @@ LL | let _: &'static str = x; | expected due to this | = note: expected reference `&'static str` - found opaque type `impl std::fmt::Debug` + found opaque type `impl Debug` -error[E0605]: non-primitive cast: `impl std::fmt::Debug` as `&'static str` +error[E0605]: non-primitive cast: `impl Debug` as `&'static str` --> $DIR/never_reveal_concrete_type.rs:14:13 | LL | let _ = x as &'static str; diff --git a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr index d237cc6238..67752acb8c 100644 --- a/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr +++ b/src/test/ui/type-alias-impl-trait/no_revealing_outside_defining_module.stderr @@ -10,7 +10,7 @@ LL | let _: &str = bomp(); | expected due to this | = note: expected reference `&str` - found opaque type `impl std::fmt::Debug` + found opaque type `impl Debug` error[E0308]: mismatched types --> $DIR/no_revealing_outside_defining_module.rs:19:5 @@ -19,11 +19,11 @@ LL | pub type Boo = impl ::std::fmt::Debug; | ---------------------- the expected opaque type ... LL | fn bomp() -> boo::Boo { - | -------- expected `impl std::fmt::Debug` because of return type + | -------- expected `impl Debug` because of return type LL | "" | ^^ expected opaque type, found `&str` | - = note: expected opaque type `impl std::fmt::Debug` + = note: expected opaque type `impl Debug` found reference `&'static str` error: aborting due to 2 previous errors diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs index 02485b24e7..f29b980dfd 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.rs @@ -7,6 +7,7 @@ fn main() {} type Two = impl Debug; fn two(t: T) -> Two { + //~^ ERROR non-defining opaque type use in defining scope (t, 4i8) } @@ -24,9 +25,7 @@ impl Bar for u32 { const FOO: i32 = 42; } -// this should work! But it requires `two` and `three` not to be defining uses, -// just restricting uses -fn four(t: T) -> Two { //~ concrete type differs from previous +fn four(t: T) -> Two { (t, ::FOO) } diff --git a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr index 9ce07a879f..2fa236b373 100644 --- a/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr +++ b/src/test/ui/type-alias-impl-trait/not_a_defining_use.stderr @@ -1,14 +1,14 @@ -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:9:1 +error: non-defining opaque type use in defining scope + --> $DIR/not_a_defining_use.rs:9:27 | LL | fn two(t: T) -> Two { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^ + | +note: used non-generic type `u32` for generic parameter + --> $DIR/not_a_defining_use.rs:7:13 + | +LL | type Two = impl Debug; + | ^ error: aborting due to previous error diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs index 479d6cd9af..d50835608f 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.rs @@ -12,9 +12,9 @@ const LEAK_FREE: Bar = leak_free(); fn leak_free_test() { match todo!() { LEAK_FREE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr index ae0d8e8d42..889c4fd4b0 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match-no-leak.stderr @@ -1,4 +1,4 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match-no-leak.rs:14:9 | LL | LEAK_FREE => (), diff --git a/src/test/ui/type-alias-impl-trait/structural-match.rs b/src/test/ui/type-alias-impl-trait/structural-match.rs index 481448d64b..a3ff4ad1d4 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.rs +++ b/src/test/ui/type-alias-impl-trait/structural-match.rs @@ -13,9 +13,9 @@ const VALUE: Foo = value(); fn test() { match todo!() { VALUE => (), - //~^ opaque types cannot be used in patterns + //~^ `impl Send` cannot be used in patterns _ => (), } } -fn main() { } +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/structural-match.stderr b/src/test/ui/type-alias-impl-trait/structural-match.stderr index ad9036a87d..262fd07261 100644 --- a/src/test/ui/type-alias-impl-trait/structural-match.stderr +++ b/src/test/ui/type-alias-impl-trait/structural-match.stderr @@ -1,4 +1,4 @@ -error: opaque types cannot be used in patterns +error: `impl Send` cannot be used in patterns --> $DIR/structural-match.rs:15:9 | LL | VALUE => (), diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs index bc2bf9eca9..01769f7115 100644 --- a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-const.rs @@ -4,7 +4,7 @@ // Currently, the `type_alias_impl_trait` feature implicitly // depends on `impl_trait_in_bindings` in order to work properly. // Specifically, this line requires `impl_trait_in_bindings` to be enabled: -// https://github.com/rust-lang/rust/blob/481068a707679257e2a738b40987246e0420e787/src/librustc_typeck/check/mod.rs#L856 +// https://github.com/rust-lang/rust/blob/481068a707679257e2a738b40987246e0420e787/compiler/rustc_typeck/check/mod.rs#L856 #![feature(impl_trait_in_bindings)] //~^ WARN the feature `impl_trait_in_bindings` is incomplete diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs new file mode 100644 index 0000000000..efbf4f1e35 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.rs @@ -0,0 +1,18 @@ +// regression test for #74018 + +#![feature(type_alias_impl_trait)] + +trait Trait { + type Associated; + fn into(self) -> Self::Associated; +} + +impl<'a, I: Iterator> Trait for (i32, I) { + //~^ ERROR the lifetime parameter `'a` is not constrained + type Associated = (i32, impl Iterator); + fn into(self) -> Self::Associated { + (0_i32, [0_i32].iter().copied()) + } +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr new file mode 100644 index 0000000000..8cdce2f8e8 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/type-alias-impl-trait-unconstrained-lifetime.stderr @@ -0,0 +1,9 @@ +error[E0207]: the lifetime parameter `'a` is not constrained by the impl trait, self type, or predicates + --> $DIR/type-alias-impl-trait-unconstrained-lifetime.rs:10:6 + | +LL | impl<'a, I: Iterator> Trait for (i32, I) { + | ^^ unconstrained lifetime parameter + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0207`. diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.rs b/src/test/ui/type-alias/issue-62263-self-in-atb.rs index 5e812db4d2..1f64b4cfe5 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.rs +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.rs @@ -3,6 +3,6 @@ pub trait Trait { } pub type Alias = dyn Trait; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr index a642d029f9..d34b6ed503 100644 --- a/src/test/ui/type-alias/issue-62263-self-in-atb.stderr +++ b/src/test/ui/type-alias/issue-62263-self-in-atb.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62263-self-in-atb.rs:5:32 | LL | pub type Alias = dyn Trait; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs index 0b95ddeb19..999902fb18 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.rs @@ -1,4 +1,4 @@ type Alias = Self::Target; -//~^ ERROR failed to resolve: use of undeclared type or module `Self` [E0433] +//~^ ERROR failed to resolve: use of undeclared type `Self` [E0433] fn main() {} diff --git a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr index 6eb445e9db..823a5fa50f 100644 --- a/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr +++ b/src/test/ui/type-alias/issue-62305-self-assoc-ty.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/issue-62305-self-assoc-ty.rs:1:14 | LL | type Alias = Self::Target; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to previous error diff --git a/src/test/ui/type/type-annotation-needed.stderr b/src/test/ui/type/type-annotation-needed.stderr index 927cc50726..97817a1f9f 100644 --- a/src/test/ui/type/type-annotation-needed.stderr +++ b/src/test/ui/type/type-annotation-needed.stderr @@ -7,7 +7,7 @@ LL | fn foo>(x: i32) {} LL | foo(42); | ^^^ cannot infer type for type parameter `T` declared on the function `foo` | - = note: cannot satisfy `_: std::convert::Into` + = note: cannot satisfy `_: Into` help: consider specifying the type argument in the function call | LL | foo::(42); diff --git a/src/test/ui/type/type-check-defaults.rs b/src/test/ui/type/type-check-defaults.rs index 5380fae541..6a0a7ed338 100644 --- a/src/test/ui/type/type-check-defaults.rs +++ b/src/test/ui/type/type-check-defaults.rs @@ -9,17 +9,17 @@ struct WellFormedNoBounds>(Z); //~^ ERROR a value of type `i32` cannot be built from an iterator over elements of type `i32` struct Bounds(T); -//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] struct WhereClause(T) where T: Copy; -//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] trait TraitBound {} -//~^ ERROR the trait bound `std::string::String: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `String: Copy` is not satisfied [E0277] trait Super { } trait Base: Super { } -//~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied [E0277] +//~^ ERROR the trait bound `T: Copy` is not satisfied [E0277] trait ProjectionPred> where T::Item : Add {} //~^ ERROR cannot add `u8` to `i32` [E0277] diff --git a/src/test/ui/type/type-check-defaults.stderr b/src/test/ui/type/type-check-defaults.stderr index e2729c65e0..d8c7f595e6 100644 --- a/src/test/ui/type/type-check-defaults.stderr +++ b/src/test/ui/type/type-check-defaults.stderr @@ -6,7 +6,7 @@ LL | struct Foo>(T, U); LL | struct WellFormed>(Z); | ^ value of type `i32` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator` is not implemented for `i32` + = help: the trait `FromIterator` is not implemented for `i32` error[E0277]: a value of type `i32` cannot be built from an iterator over elements of type `i32` --> $DIR/type-check-defaults.rs:8:27 @@ -17,47 +17,47 @@ LL | struct Foo>(T, U); LL | struct WellFormedNoBounds>(Z); | ^ value of type `i32` cannot be built from `std::iter::Iterator` | - = help: the trait `std::iter::FromIterator` is not implemented for `i32` + = help: the trait `FromIterator` is not implemented for `i32` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/type-check-defaults.rs:11:17 | LL | struct Bounds(T); | ----------------^^^^------------ | | | - | | the trait `std::marker::Copy` is not implemented for `std::string::String` + | | the trait `Copy` is not implemented for `String` | required by `Bounds` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/type-check-defaults.rs:14:42 | LL | struct WhereClause(T) where T: Copy; | -----------------------------------------^^^^- | | | - | | the trait `std::marker::Copy` is not implemented for `std::string::String` + | | the trait `Copy` is not implemented for `String` | required by `WhereClause` -error[E0277]: the trait bound `std::string::String: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `String: Copy` is not satisfied --> $DIR/type-check-defaults.rs:17:20 | LL | trait TraitBound {} | -------------------^^^^-------- | | | - | | the trait `std::marker::Copy` is not implemented for `std::string::String` + | | the trait `Copy` is not implemented for `String` | required by `TraitBound` -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/type-check-defaults.rs:21:25 | LL | trait Super { } | ---- required by this bound in `Super` LL | trait Base: Super { } - | ^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider further restricting type parameter `T` | -LL | trait Base: Super, T: std::marker::Copy { } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | trait Base: Super where T: Copy { } + | ^^^^^^^^^^^^^ error[E0277]: cannot add `u8` to `i32` --> $DIR/type-check-defaults.rs:24:66 @@ -68,7 +68,7 @@ LL | trait ProjectionPred> where T::Item : Add {} | | no implementation for `i32 + u8` | required by `ProjectionPred` | - = help: the trait `std::ops::Add` is not implemented for `i32` + = help: the trait `Add` is not implemented for `i32` error: aborting due to 7 previous errors diff --git a/src/test/ui/type/type-check/assignment-expected-bool.stderr b/src/test/ui/type/type-check/assignment-expected-bool.stderr index 3f1caddf72..d1c13a33f7 100644 --- a/src/test/ui/type/type-check/assignment-expected-bool.stderr +++ b/src/test/ui/type/type-check/assignment-expected-bool.stderr @@ -2,100 +2,126 @@ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:6:19 | LL | let _: bool = 0 = 0; - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | let _: bool = 0 == 0; + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:9:14 | LL | 0 => 0 = 0, - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | 0 => 0 == 0, + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:10:14 | LL | _ => 0 = 0, - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | _ => 0 == 0, + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:14:17 | LL | true => 0 = 0, - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | true => 0 == 0, + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:18:8 | LL | if 0 = 0 {} - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let 0 = 0 {} + | ^^^ +help: you might have meant to compare for equality + | +LL | if 0 == 0 {} + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:20:24 | LL | let _: bool = if { 0 = 0 } { - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | let _: bool = if { 0 == 0 } { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:21:9 | LL | 0 = 0 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | 0 == 0 + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:23:9 | LL | 0 = 0 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | 0 == 0 + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:26:13 | LL | let _ = (0 = 0) - | ^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | let _ = (0 == 0) + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:27:14 | LL | && { 0 = 0 } - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | && { 0 == 0 } + | ^^ error[E0308]: mismatched types --> $DIR/assignment-expected-bool.rs:28:12 | LL | || (0 = 0); - | ^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `0 == 0` + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | || (0 == 0); + | ^^ error[E0070]: invalid left-hand side of assignment --> $DIR/assignment-expected-bool.rs:31:22 diff --git a/src/test/ui/type/type-check/assignment-in-if.stderr b/src/test/ui/type/type-check/assignment-in-if.stderr index 0957dcb986..f5306a1226 100644 --- a/src/test/ui/type/type-check/assignment-in-if.stderr +++ b/src/test/ui/type/type-check/assignment-in-if.stderr @@ -2,55 +2,71 @@ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:15:8 | LL | if x = x { - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == x` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if x == x { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:20:8 | LL | if (x = x) { - | ^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == x` + | ^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if (x == x) { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:25:8 | LL | if y = (Foo { foo: x }) { - | ^^^^^^^^^^^^^^^^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `y == (Foo { foo: x })` + | ^^^^^^^^^^^^^^^^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | if y == (Foo { foo: x }) { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:30:8 | LL | if 3 = x { - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `3 == x` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to use pattern matching + | +LL | if let 3 = x { + | ^^^ +help: you might have meant to compare for equality + | +LL | if 3 == x { + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:36:13 | LL | x = 4 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == 4` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | x == 4 + | ^^ error[E0308]: mismatched types --> $DIR/assignment-in-if.rs:38:13 | LL | x = 5 - | ^^^^^ - | | - | expected `bool`, found `()` - | help: try comparing for equality: `x == 5` + | ^^^^^ expected `bool`, found `()` + | +help: you might have meant to compare for equality + | +LL | x == 5 + | ^^ error: aborting due to 6 previous errors diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr index 8162fed2cd..729a8c63b6 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `std::vec::Vec` +error[E0282]: type annotations needed for `Vec` --> $DIR/cannot_infer_local_or_vec.rs:2:13 | LL | let x = vec![]; | - ^^^^^^ cannot infer type for type parameter `T` | | - | consider giving `x` the explicit type `std::vec::Vec`, where the type parameter `T` is specified + | consider giving `x` the explicit type `Vec`, where the type parameter `T` is specified | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr index e62565c8f9..e24593a89b 100644 --- a/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr +++ b/src/test/ui/type/type-check/cannot_infer_local_or_vec_in_tuples.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `(std::vec::Vec,)` +error[E0282]: type annotations needed for `(Vec,)` --> $DIR/cannot_infer_local_or_vec_in_tuples.rs:2:18 | LL | let (x, ) = (vec![], ); | ----- ^^^^^^ cannot infer type for type parameter `T` | | - | consider giving this pattern the explicit type `(std::vec::Vec,)`, where the type parameter `T` is specified + | consider giving this pattern the explicit type `(Vec,)`, where the type parameter `T` is specified | = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/type/type-mismatch-same-crate-name.rs b/src/test/ui/type/type-mismatch-same-crate-name.rs index eeda5460ac..c9cdc874c0 100644 --- a/src/test/ui/type/type-mismatch-same-crate-name.rs +++ b/src/test/ui/type/type-mismatch-same-crate-name.rs @@ -21,7 +21,7 @@ fn main() { //~^ ERROR mismatched types //~| perhaps two different versions of crate `crate_a1` //~| expected trait `main::a::Bar` - //~| expected struct `std::boxed::Box<(dyn main::a::Bar + 'static)>` - //~| found struct `std::boxed::Box` + //~| expected struct `Box<(dyn main::a::Bar + 'static)>` + //~| found struct `Box` } } diff --git a/src/test/ui/type/type-mismatch-same-crate-name.stderr b/src/test/ui/type/type-mismatch-same-crate-name.stderr index be5406696b..49d40ebed1 100644 --- a/src/test/ui/type/type-mismatch-same-crate-name.stderr +++ b/src/test/ui/type/type-mismatch-same-crate-name.stderr @@ -12,8 +12,8 @@ error[E0308]: mismatched types LL | a::try_bar(bar2); | ^^^^ expected trait `main::a::Bar`, found a different trait `main::a::Bar` | - = note: expected struct `std::boxed::Box<(dyn main::a::Bar + 'static)>` - found struct `std::boxed::Box` + = note: expected struct `Box<(dyn main::a::Bar + 'static)>` + found struct `Box` = note: perhaps two different versions of crate `crate_a1` are being used? error: aborting due to 2 previous errors diff --git a/src/test/ui/type/type-path-err-node-types.rs b/src/test/ui/type/type-path-err-node-types.rs index 15adfebb33..b3795772e6 100644 --- a/src/test/ui/type/type-path-err-node-types.rs +++ b/src/test/ui/type/type-path-err-node-types.rs @@ -12,7 +12,7 @@ fn ufcs_trait() { } fn ufcs_item() { - NonExistent::Assoc::; //~ ERROR undeclared type or module `NonExistent` + NonExistent::Assoc::; //~ ERROR undeclared type `NonExistent` } fn method() { diff --git a/src/test/ui/type/type-path-err-node-types.stderr b/src/test/ui/type/type-path-err-node-types.stderr index ea9cca2bfa..baf218243c 100644 --- a/src/test/ui/type/type-path-err-node-types.stderr +++ b/src/test/ui/type/type-path-err-node-types.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `NonExistent` +error[E0433]: failed to resolve: use of undeclared type `NonExistent` --> $DIR/type-path-err-node-types.rs:15:5 | LL | NonExistent::Assoc::; - | ^^^^^^^^^^^ use of undeclared type or module `NonExistent` + | ^^^^^^^^^^^ use of undeclared type `NonExistent` error[E0412]: cannot find type `Nonexistent` in this scope --> $DIR/type-path-err-node-types.rs:7:12 diff --git a/src/test/ui/type_length_limit.rs b/src/test/ui/type_length_limit.rs index 921cded503..c1f3acbecf 100644 --- a/src/test/ui/type_length_limit.rs +++ b/src/test/ui/type_length_limit.rs @@ -1,5 +1,6 @@ // build-fail // error-pattern: reached the type-length limit while instantiating +// normalize-stderr-test: ".nll/" -> "/" // Test that the type length limit can be changed. diff --git a/src/test/ui/type_length_limit.stderr b/src/test/ui/type_length_limit.stderr index 83da193eb0..a2ddffff99 100644 --- a/src/test/ui/type_length_limit.stderr +++ b/src/test/ui/type_length_limit.stderr @@ -1,10 +1,11 @@ -error: reached the type-length limit while instantiating `std::mem::drop::>` +error: reached the type-length limit while instantiating `std::mem::drop::>` --> $SRC_DIR/core/src/mem/mod.rs:LL:COL | LL | pub fn drop(_x: T) {} - | ^^^^^^^^^^^^^^^^^^^^^^^^ + | ^^^^^^^^^^^^^^^^^^^^^ | - = note: consider adding a `#![type_length_limit="8"]` attribute to your crate + = note: the full type name has been written to '$TEST_BUILD_DIR/type_length_limit/type_length_limit.long-type.txt' + = help: consider adding a `#![type_length_limit="8"]` attribute to your crate error: aborting due to previous error diff --git a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr index a656b20c23..b4d7dfe06b 100644 --- a/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr +++ b/src/test/ui/typeck/issue-57673-ice-on-deref-of-boxed-trait.stderr @@ -4,10 +4,10 @@ error[E0308]: mismatched types LL | fn ice(x: Box>) { | - possibly return type missing here? LL | *x - | ^^ expected `()`, found trait object `dyn std::iter::Iterator` + | ^^ expected `()`, found trait object `dyn Iterator` | = note: expected unit type `()` - found trait object `(dyn std::iter::Iterator + 'static)` + found trait object `(dyn Iterator + 'static)` error: aborting due to previous error diff --git a/src/test/ui/typeck/issue-67971.stderr b/src/test/ui/typeck/issue-67971.stderr index 36ad3fcb34..5d07f9cc74 100644 --- a/src/test/ui/typeck/issue-67971.stderr +++ b/src/test/ui/typeck/issue-67971.stderr @@ -8,7 +8,7 @@ error[E0308]: mismatched types --> $DIR/issue-67971.rs:3:24 | LL | fn foo(ctx: &mut S) -> String { - | --- ^^^^^^ expected struct `std::string::String`, found `()` + | --- ^^^^^^ expected struct `String`, found `()` | | | implicitly returns `()` as its body has no tail or `return` expression diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed index dd1195b99f..a9107f9987 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.fixed @@ -7,7 +7,7 @@ trait Trait { type AssocType; fn dummy(&self) { } } -fn bar() where ::AssocType: std::marker::Send { +fn bar() where ::AssocType: Send { is_send::(); //~ ERROR E0277 } diff --git a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr index f97d41637b..17ad017294 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-assoc-type.stderr @@ -7,11 +7,11 @@ LL | is_send::(); LL | fn is_send() { | ---- required by this bound in `is_send` | - = help: the trait `std::marker::Send` is not implemented for `::AssocType` + = help: the trait `Send` is not implemented for `::AssocType` help: consider further restricting the associated type | -LL | fn bar() where ::AssocType: std::marker::Send { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar() where ::AssocType: Send { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr index a54826787d..90ab5be016 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-cross-crate-coherence.stderr @@ -20,7 +20,7 @@ LL | impl !DefaultedTrait for (B,) { } | = note: define and implement a trait or new type instead -error[E0321]: cross-crate traits with a default impl, like `lib::DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate +error[E0321]: cross-crate traits with a default impl, like `DefaultedTrait`, can only be implemented for a struct/enum type defined in the current crate --> $DIR/typeck-default-trait-impl-cross-crate-coherence.rs:20:1 | LL | impl DefaultedTrait for Box { } @@ -32,7 +32,7 @@ error[E0117]: only traits defined in the current crate can be implemented for ar LL | impl DefaultedTrait for lib::Something { } | ^^^^^^^^^^^^^^^^^^^^^^^^----------------- | | | - | | `lib::Something` is not defined in the current crate + | | `Something` is not defined in the current crate | impl doesn't use only types from inside the current crate | = note: define and implement a trait or new type instead diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr index b6ab36f515..e164bb01f7 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-send.stderr @@ -7,7 +7,7 @@ LL | fn is_send() {} LL | is_send::(); | ^^^^^^^^^^^^^ `MyNotSendable` cannot be sent between threads safely | - = help: the trait `std::marker::Send` is not implemented for `MyNotSendable` + = help: the trait `Send` is not implemented for `MyNotSendable` error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs index 2734b761e6..b9042188ad 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.rs @@ -34,7 +34,7 @@ fn main() { //~^ ERROR `MyNotSync` cannot be shared between threads safely [E0277] is_sync::(); - //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] + //~^ ERROR `UnsafeCell` cannot be shared between threads safely [E0277] is_sync::(); //~^ ERROR `Managed` cannot be shared between threads safely [E0277] diff --git a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr index d671b8eb75..1f21e12597 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-negation-sync.stderr @@ -7,18 +7,18 @@ LL | fn is_sync() {} LL | is_sync::(); | ^^^^^^^^^ `MyNotSync` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `MyNotSync` + = help: the trait `Sync` is not implemented for `MyNotSync` -error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely +error[E0277]: `UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-default-trait-impl-negation-sync.rs:36:5 | LL | fn is_sync() {} | ---- required by this bound in `is_sync` ... LL | is_sync::(); - | ^^^^^^^^^^^^^^^^^^^^^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely + | ^^^^^^^^^^^^^^^^^^^^^^^^ `UnsafeCell` cannot be shared between threads safely | - = help: within `MyTypeWUnsafe`, the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` + = help: within `MyTypeWUnsafe`, the trait `Sync` is not implemented for `UnsafeCell` = note: required because it appears within the type `MyTypeWUnsafe` error[E0277]: `Managed` cannot be shared between threads safely @@ -30,7 +30,7 @@ LL | fn is_sync() {} LL | is_sync::(); | ^^^^^^^^^^^^^^^^^^^^^^^^ `Managed` cannot be shared between threads safely | - = help: within `MyTypeManaged`, the trait `std::marker::Sync` is not implemented for `Managed` + = help: within `MyTypeManaged`, the trait `Sync` is not implemented for `Managed` = note: required because it appears within the type `MyTypeManaged` error: aborting due to 3 previous errors diff --git a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr index 7398b48a23..4fb423b9a2 100644 --- a/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr +++ b/src/test/ui/typeck/typeck-default-trait-impl-send-param.stderr @@ -9,8 +9,8 @@ LL | fn is_send() { | help: consider restricting type parameter `T` | -LL | fn foo() { - | ^^^^^^^^^^^^^^^^^^^ +LL | fn foo() { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/typeck/typeck-unsafe-always-share.rs b/src/test/ui/typeck/typeck-unsafe-always-share.rs index dc5ddf5156..be87ab1726 100644 --- a/src/test/ui/typeck/typeck-unsafe-always-share.rs +++ b/src/test/ui/typeck/typeck-unsafe-always-share.rs @@ -17,15 +17,15 @@ fn test(s: T) {} fn main() { let us = UnsafeCell::new(MySync{u: UnsafeCell::new(0)}); test(us); - //~^ ERROR `std::cell::UnsafeCell>` cannot be shared between threads safely + //~^ ERROR `UnsafeCell>` cannot be shared between threads safely let uns = UnsafeCell::new(NoSync); test(uns); - //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] + //~^ ERROR `UnsafeCell` cannot be shared between threads safely [E0277] let ms = MySync{u: uns}; test(ms); - //~^ ERROR `std::cell::UnsafeCell` cannot be shared between threads safely [E0277] + //~^ ERROR `UnsafeCell` cannot be shared between threads safely [E0277] test(NoSync); //~^ ERROR `NoSync` cannot be shared between threads safely [E0277] diff --git a/src/test/ui/typeck/typeck-unsafe-always-share.stderr b/src/test/ui/typeck/typeck-unsafe-always-share.stderr index 61585fcc1c..2a6ae736d7 100644 --- a/src/test/ui/typeck/typeck-unsafe-always-share.stderr +++ b/src/test/ui/typeck/typeck-unsafe-always-share.stderr @@ -1,35 +1,35 @@ -error[E0277]: `std::cell::UnsafeCell>` cannot be shared between threads safely +error[E0277]: `UnsafeCell>` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:19:10 | LL | fn test(s: T) {} | ---- required by this bound in `test` ... LL | test(us); - | ^^ `std::cell::UnsafeCell>` cannot be shared between threads safely + | ^^ `UnsafeCell>` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell>` + = help: the trait `Sync` is not implemented for `UnsafeCell>` -error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely +error[E0277]: `UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:23:10 | LL | fn test(s: T) {} | ---- required by this bound in `test` ... LL | test(uns); - | ^^^ `std::cell::UnsafeCell` cannot be shared between threads safely + | ^^^ `UnsafeCell` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` + = help: the trait `Sync` is not implemented for `UnsafeCell` -error[E0277]: `std::cell::UnsafeCell` cannot be shared between threads safely +error[E0277]: `UnsafeCell` cannot be shared between threads safely --> $DIR/typeck-unsafe-always-share.rs:27:5 | LL | fn test(s: T) {} | ---- required by this bound in `test` ... LL | test(ms); - | ^^^^ `std::cell::UnsafeCell` cannot be shared between threads safely + | ^^^^ `UnsafeCell` cannot be shared between threads safely | - = help: within `MySync`, the trait `std::marker::Sync` is not implemented for `std::cell::UnsafeCell` + = help: within `MySync`, the trait `Sync` is not implemented for `UnsafeCell` = note: required because it appears within the type `MySync` error[E0277]: `NoSync` cannot be shared between threads safely @@ -41,7 +41,7 @@ LL | fn test(s: T) {} LL | test(NoSync); | ^^^^^^ `NoSync` cannot be shared between threads safely | - = help: the trait `std::marker::Sync` is not implemented for `NoSync` + = help: the trait `Sync` is not implemented for `NoSync` error: aborting due to 4 previous errors diff --git a/src/test/ui/typeck/typeck_type_placeholder_item.stderr b/src/test/ui/typeck/typeck_type_placeholder_item.stderr index 782ff4948c..684f451b7c 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item.stderr @@ -405,15 +405,10 @@ LL | type X = Box<_>; | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:43:27 + --> $DIR/typeck_type_placeholder_item.rs:182:21 | -LL | fn test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn test10(&self, _x : T) { } - | ^^^ ^ +LL | type Y = impl Trait<_>; + | ^ not allowed in type signatures error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:140:31 @@ -485,45 +480,6 @@ help: use type parameters instead LL | fn assoc_fn_test3() -> T; | ^^^ ^ -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:61:37 - | -LL | fn clone_from(&mut self, other: _) { *self = Test9; } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn clone_from(&mut self, other: T) { *self = Test9; } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:110:34 - | -LL | fn fn_test10(&self, _x : _) { } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn fn_test10(&self, _x : T) { } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:118:41 - | -LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } - | ^ not allowed in type signatures - | -help: use type parameters instead - | -LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } - | ^^^ ^ - -error[E0121]: the type placeholder `_` is not allowed within types on item signatures - --> $DIR/typeck_type_placeholder_item.rs:182:21 - | -LL | type Y = impl Trait<_>; - | ^ not allowed in type signatures - error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:190:14 | @@ -560,6 +516,17 @@ LL | fn test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:43:27 + | +LL | fn test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn test10(&self, _x : T) { } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:58:24 | @@ -569,6 +536,17 @@ LL | fn clone(&self) -> _ { Test9 } | not allowed in type signatures | help: replace with the correct return type: `Test9` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:61:37 + | +LL | fn clone_from(&mut self, other: _) { *self = Test9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = Test9; } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:107:31 | @@ -578,6 +556,17 @@ LL | fn fn_test9(&self) -> _ { () } | not allowed in type signatures | help: replace with the correct return type: `()` +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:110:34 + | +LL | fn fn_test10(&self, _x : _) { } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn fn_test10(&self, _x : T) { } + | ^^^ ^ + error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:115:28 | @@ -585,7 +574,18 @@ LL | fn clone(&self) -> _ { FnTest9 } | ^ | | | not allowed in type signatures - | help: replace with the correct return type: `main::FnTest9` + | help: replace with the correct return type: `FnTest9` + +error[E0121]: the type placeholder `_` is not allowed within types on item signatures + --> $DIR/typeck_type_placeholder_item.rs:118:41 + | +LL | fn clone_from(&mut self, other: _) { *self = FnTest9; } + | ^ not allowed in type signatures + | +help: use type parameters instead + | +LL | fn clone_from(&mut self, other: T) { *self = FnTest9; } + | ^^^ ^ error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item.rs:201:14 diff --git a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr index e3bc059d1f..88133814d2 100644 --- a/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr +++ b/src/test/ui/typeck/typeck_type_placeholder_item_help.stderr @@ -5,7 +5,7 @@ LL | fn test1() -> _ { Some(42) } | ^ | | | not allowed in type signatures - | help: replace with the correct return type: `std::option::Option` + | help: replace with the correct return type: `Option` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:7:14 @@ -23,7 +23,7 @@ LL | const TEST3: _ = Some(42); | ^ | | | not allowed in type signatures - | help: replace `_` with the correct type: `std::option::Option` + | help: replace `_` with the correct type: `Option` error[E0121]: the type placeholder `_` is not allowed within types on item signatures --> $DIR/typeck_type_placeholder_item_help.rs:14:18 diff --git a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr index 59f699b702..9e710c15fd 100644 --- a/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr +++ b/src/test/ui/ufcs/ufcs-qpath-self-mismatch.stderr @@ -4,7 +4,7 @@ error[E0277]: cannot add `u32` to `i32` LL | >::add(1, 2); | ^^^^^^^^^^^^^^^^^^^^^^ no implementation for `i32 + u32` | - = help: the trait `std::ops::Add` is not implemented for `i32` + = help: the trait `Add` is not implemented for `i32` error[E0308]: mismatched types --> $DIR/ufcs-qpath-self-mismatch.rs:6:28 diff --git a/src/test/ui/unboxed-closures/issue-30906.stderr b/src/test/ui/unboxed-closures/issue-30906.stderr index 5c3a1154e7..5f343ff74a 100644 --- a/src/test/ui/unboxed-closures/issue-30906.stderr +++ b/src/test/ui/unboxed-closures/issue-30906.stderr @@ -4,8 +4,8 @@ error[E0308]: mismatched types LL | test(Compose(f, |_| {})); | ^^^^ one type is more general than the other | - = note: expected type `std::ops::FnOnce<(&'x str,)>` - found type `std::ops::FnOnce<(&str,)>` + = note: expected type `FnOnce<(&'x str,)>` + found type `FnOnce<(&str,)>` error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr index 58062872aa..f8c90176ff 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -4,7 +4,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(|| drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:19:35 @@ -12,7 +12,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(|| drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:28:36 @@ -20,7 +20,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(move || drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:32:40 @@ -28,7 +28,7 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(move || drop(x)); - | ^ move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait error: aborting due to 4 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr index 0466887e37..94de194705 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-1.stderr @@ -10,7 +10,7 @@ LL | } | - | | | `factorial` dropped here while still borrowed - | borrow might be used here, when `factorial` is dropped and runs the destructor for type `std::option::Option u32>>` + | borrow might be used here, when `factorial` is dropped and runs the destructor for type `Option u32>>` error[E0506]: cannot assign to `factorial` because it is borrowed --> $DIR/unboxed-closures-failed-recursive-fn-1.rs:20:5 diff --git a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr index 18af3dc640..de20a38c44 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-failed-recursive-fn-2.stderr @@ -1,8 +1,8 @@ -error[E0282]: type annotations needed for `std::option::Option` +error[E0282]: type annotations needed for `Option` --> $DIR/unboxed-closures-failed-recursive-fn-2.rs:16:32 | LL | let mut closure0 = None; - | ------------ consider giving `closure0` the explicit type `std::option::Option`, with the type parameters specified + | ------------ consider giving `closure0` the explicit type `Option`, with the type parameters specified ... LL | return c(); | ^^^ cannot infer type diff --git a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr index d427873ebc..df3563455b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-fnmut-as-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(isize,)>` closure, found `S` +error[E0277]: expected a `Fn<(isize,)>` closure, found `S` --> $DIR/unboxed-closures-fnmut-as-fn.rs:28:21 | LL | fn call_itisize>(f: &F, x: isize) -> isize { @@ -7,7 +7,7 @@ LL | fn call_itisize>(f: &F, x: isize) -> isize { LL | let x = call_it(&S, 22); | ^^ expected an `Fn<(isize,)>` closure, found `S` | - = help: the trait `std::ops::Fn<(isize,)>` is not implemented for `S` + = help: the trait `Fn<(isize,)>` is not implemented for `S` error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr index ead42c1488..e97157b839 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-infer-argument-types-two-region-pointers.nll.stderr @@ -4,7 +4,7 @@ error: lifetime may not live long enough LL | doit(0, &|x, y| { | - - has type `&'1 i32` | | - | has type `&std::cell::Cell<&'2 i32>` + | has type `&Cell<&'2 i32>` LL | x.set(y); | ^^^^^^^^ argument requires that `'1` must outlive `'2` diff --git a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr index b06f745e7c..d1f433e92d 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-unsafe-extern-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` +error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:20:21 | LL | fn call_it isize>(_: &F, _: isize) -> isize { @@ -7,9 +7,9 @@ LL | fn call_it isize>(_: &F, _: isize) -> isize { LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:25:25 | LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { @@ -18,9 +18,9 @@ LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-unsafe-extern-fn.rs:30:26 | LL | fn call_it_once isize>(_: F, _: isize) -> isize { @@ -29,7 +29,7 @@ LL | fn call_it_once isize>(_: F, _: isize) -> isize { LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> unsafe fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> unsafe fn(&'r isize) -> isize {square}` error: aborting due to 3 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr index 8f6945cda8..05b532e983 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-abi.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` +error[E0277]: expected a `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:20:21 | LL | fn call_it isize>(_: &F, _: isize) -> isize { @@ -7,9 +7,9 @@ LL | fn call_it isize>(_: &F, _: isize) -> isize { LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:25:25 | LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { @@ -18,9 +18,9 @@ LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-abi.rs:30:26 | LL | fn call_it_once isize>(_: F, _: isize) -> isize { @@ -29,7 +29,7 @@ LL | fn call_it_once isize>(_: F, _: isize) -> isize { LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `for<'r> extern "C" fn(&'r isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `for<'r> extern "C" fn(&'r isize) -> isize {square}` error: aborting due to 3 previous errors diff --git a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr index 93a645b485..3b88b35d4b 100644 --- a/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closures-wrong-arg-type-extern-fn.stderr @@ -1,4 +1,4 @@ -error[E0277]: expected a `std::ops::Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:21:21 | LL | fn call_it isize>(_: &F, _: isize) -> isize { @@ -7,9 +7,9 @@ LL | fn call_it isize>(_: &F, _: isize) -> isize { LL | let x = call_it(&square, 22); | ^^^^^^^ expected an `Fn<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> Fn<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:26:25 | LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { @@ -18,9 +18,9 @@ LL | fn call_it_mut isize>(_: &mut F, _: isize) -> isize { LL | let y = call_it_mut(&mut square, 22); | ^^^^^^^^^^^ expected an `FnMut<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> FnMut<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` -error[E0277]: expected a `std::ops::FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` +error[E0277]: expected a `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` --> $DIR/unboxed-closures-wrong-arg-type-extern-fn.rs:31:26 | LL | fn call_it_once isize>(_: F, _: isize) -> isize { @@ -29,7 +29,7 @@ LL | fn call_it_once isize>(_: F, _: isize) -> isize { LL | let z = call_it_once(square, 22); | ^^^^^^ expected an `FnOnce<(&isize,)>` closure, found `unsafe fn(isize) -> isize {square}` | - = help: the trait `for<'r> std::ops::FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` + = help: the trait `for<'r> FnOnce<(&'r isize,)>` is not implemented for `unsafe fn(isize) -> isize {square}` error: aborting due to 3 previous errors diff --git a/src/test/ui/union/union-const-pat.rs b/src/test/ui/union/union-const-pat.rs index cb2248cc6d..e7cb248a20 100644 --- a/src/test/ui/union/union-const-pat.rs +++ b/src/test/ui/union/union-const-pat.rs @@ -8,7 +8,6 @@ const C: U = U { a: 10 }; fn main() { match C { C => {} //~ ERROR cannot use unions in constant patterns - //~| ERROR cannot use unions in constant patterns _ => {} } } diff --git a/src/test/ui/union/union-const-pat.stderr b/src/test/ui/union/union-const-pat.stderr index bec720401b..dc87f4de52 100644 --- a/src/test/ui/union/union-const-pat.stderr +++ b/src/test/ui/union/union-const-pat.stderr @@ -4,11 +4,5 @@ error: cannot use unions in constant patterns LL | C => {} | ^ -error: cannot use unions in constant patterns - --> $DIR/union-const-pat.rs:10:9 - | -LL | C => {} - | ^ - -error: aborting due to 2 previous errors +error: aborting due to previous error diff --git a/src/test/ui/union/union-deref.rs b/src/test/ui/union/union-deref.rs new file mode 100644 index 0000000000..df598eea9e --- /dev/null +++ b/src/test/ui/union/union-deref.rs @@ -0,0 +1,28 @@ +// ignore-tidy-linelength +//! Test the part of RFC 2514 that is about not applying `DerefMut` coercions +//! of union fields. +#![feature(untagged_unions)] + +use std::mem::ManuallyDrop; + +union U1 { x:(), f: ManuallyDrop<(T,)> } + +union U2 { x:(), f: (ManuallyDrop<(T,)>,) } + +fn main() { + let mut u : U1> = U1 { x: () }; + unsafe { (*u.f).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + + let mut u : U2> = U2 { x: () }; + unsafe { (*u.f.0).0 = Vec::new() }; // explicit deref, this compiles + unsafe { u.f.0.0 = Vec::new() }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { &mut (*u.f.0).0 }; // explicit deref, this compiles + unsafe { &mut u.f.0.0 }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field + unsafe { (*u.f.0).0.push(0) }; // explicit deref, this compiles + unsafe { u.f.0.0.push(0) }; //~ERROR not automatically applying `DerefMut` on `ManuallyDrop` union field +} diff --git a/src/test/ui/union/union-deref.stderr b/src/test/ui/union/union-deref.stderr new file mode 100644 index 0000000000..f7722764cd --- /dev/null +++ b/src/test/ui/union/union-deref.stderr @@ -0,0 +1,56 @@ +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:15:14 + | +LL | unsafe { u.f.0 = Vec::new() }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:17:19 + | +LL | unsafe { &mut u.f.0 }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:19:14 + | +LL | unsafe { u.f.0.push(0) }; + | ^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:23:14 + | +LL | unsafe { u.f.0.0 = Vec::new() }; + | ^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:25:19 + | +LL | unsafe { &mut u.f.0.0 }; + | ^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: not automatically applying `DerefMut` on `ManuallyDrop` union field + --> $DIR/union-deref.rs:27:14 + | +LL | unsafe { u.f.0.0.push(0) }; + | ^^^^^ + | + = help: writing to this reference calls the destructor for the old value + = help: add an explicit `*` if that is desired, or call `ptr::write` to not run the destructor + +error: aborting due to 6 previous errors + diff --git a/src/test/ui/union/union-derive-clone.rs b/src/test/ui/union/union-derive-clone.rs index 4a106cc940..8126980604 100644 --- a/src/test/ui/union/union-derive-clone.rs +++ b/src/test/ui/union/union-derive-clone.rs @@ -2,7 +2,7 @@ use std::mem::ManuallyDrop; -#[derive(Clone)] //~ ERROR the trait bound `U1: std::marker::Copy` is not satisfied +#[derive(Clone)] //~ ERROR the trait bound `U1: Copy` is not satisfied union U1 { a: u8, } diff --git a/src/test/ui/union/union-derive-clone.stderr b/src/test/ui/union/union-derive-clone.stderr index f02b7605a3..7a59f539c3 100644 --- a/src/test/ui/union/union-derive-clone.stderr +++ b/src/test/ui/union/union-derive-clone.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `U1: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U1: Copy` is not satisfied --> $DIR/union-derive-clone.rs:5:10 | LL | #[derive(Clone)] - | ^^^^^ the trait `std::marker::Copy` is not implemented for `U1` + | ^^^^^ the trait `Copy` is not implemented for `U1` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | pub struct AssertParamIsCopy { - | ---- required by this bound in `std::clone::AssertParamIsCopy` + | ---- required by this bound in `AssertParamIsCopy` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) @@ -18,10 +18,10 @@ LL | union U5 { | ----------- | | | method `clone` not found for this - | doesn't satisfy `U5: std::clone::Clone` + | doesn't satisfy `U5: Clone` ... LL | struct CloneNoCopy; - | ------------------- doesn't satisfy `CloneNoCopy: std::marker::Copy` + | ------------------- doesn't satisfy `CloneNoCopy: Copy` ... LL | let w = u.clone(); | ^^^^^ method not found in `U5` @@ -31,12 +31,12 @@ LL | let w = u.clone(); LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `CloneNoCopy: std::marker::Copy` - which is required by `U5: std::clone::Clone` + `CloneNoCopy: Copy` + which is required by `U5: Clone` error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-derive-eq.rs b/src/test/ui/union/union-derive-eq.rs index 698c38fac7..ac5808e436 100644 --- a/src/test/ui/union/union-derive-eq.rs +++ b/src/test/ui/union/union-derive-eq.rs @@ -12,7 +12,7 @@ struct PartialEqNotEq; #[derive(Eq)] union U2 { - a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied + a: PartialEqNotEq, //~ ERROR the trait bound `PartialEqNotEq: Eq` is not satisfied } impl PartialEq for U2 { fn eq(&self, rhs: &Self) -> bool { true } } diff --git a/src/test/ui/union/union-derive-eq.stderr b/src/test/ui/union/union-derive-eq.stderr index 4a9b689b44..c4d437c6cd 100644 --- a/src/test/ui/union/union-derive-eq.stderr +++ b/src/test/ui/union/union-derive-eq.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `PartialEqNotEq: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `PartialEqNotEq: Eq` is not satisfied --> $DIR/union-derive-eq.rs:15:5 | LL | a: PartialEqNotEq, - | ^^^^^^^^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `PartialEqNotEq` + | ^^^^^^^^^^^^^^^^^ the trait `Eq` is not implemented for `PartialEqNotEq` | ::: $SRC_DIR/core/src/cmp.rs:LL:COL | LL | pub struct AssertParamIsEq { - | -- required by this bound in `std::cmp::AssertParamIsEq` + | -- required by this bound in `AssertParamIsEq` | = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/union/union-drop.rs b/src/test/ui/union/union-drop.rs index daa03ce6b6..4df3ed5028 100644 --- a/src/test/ui/union/union-drop.rs +++ b/src/test/ui/union/union-drop.rs @@ -48,6 +48,11 @@ fn main() { { let y = Y { a: S }; } - assert_eq!(CHECK, 2); // 2, dtor of Y is called + assert_eq!(CHECK, 2); // 2, Y has no dtor + { + let u2 = U { a: 1 }; + std::mem::forget(u2); + } + assert_eq!(CHECK, 2); // 2, dtor of U *not* called for u2 } } diff --git a/src/test/ui/union/union-generic.rs b/src/test/ui/union/union-generic.rs index 4b2ccbdb7b..ff87789257 100644 --- a/src/test/ui/union/union-generic.rs +++ b/src/test/ui/union/union-generic.rs @@ -6,7 +6,7 @@ union U { fn main() { let u = U { a: Rc::new(0u32) }; - //~^ ERROR the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Rc: Copy` is not satisfied let u = U::> { a: Default::default() }; - //~^ ERROR the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `Rc: Copy` is not satisfied } diff --git a/src/test/ui/union/union-generic.stderr b/src/test/ui/union/union-generic.stderr index f13b2def6d..c418b27ce6 100644 --- a/src/test/ui/union/union-generic.stderr +++ b/src/test/ui/union/union-generic.stderr @@ -1,20 +1,20 @@ -error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Rc: Copy` is not satisfied --> $DIR/union-generic.rs:8:13 | LL | union U { | ---------------- required by `U` ... LL | let u = U { a: Rc::new(0u32) }; - | ^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` + | ^ the trait `Copy` is not implemented for `Rc` -error[E0277]: the trait bound `std::rc::Rc: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `Rc: Copy` is not satisfied --> $DIR/union-generic.rs:10:13 | LL | union U { | ---------------- required by `U` ... LL | let u = U::> { a: Default::default() }; - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `std::rc::Rc` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `Rc` error: aborting due to 2 previous errors diff --git a/src/test/ui/union/union-move.rs b/src/test/ui/union/union-move.rs new file mode 100644 index 0000000000..a0a2d0d659 --- /dev/null +++ b/src/test/ui/union/union-move.rs @@ -0,0 +1,53 @@ +//! Test the behavior of moving out of non-`Copy` union fields. +//! Avoid types that `Drop`, we want to focus on moving. +#![feature(untagged_unions)] + +use std::cell::RefCell; + +fn move_out(x: T) {} + +union U1 { + f1_nocopy: RefCell, + f2_nocopy: RefCell, + f3_copy: i32, +} + +union U2 { + f1_nocopy: RefCell, +} +impl Drop for U2 { + fn drop(&mut self) {} +} + +fn test1(x: U1) { + // Moving out of a nocopy field prevents accessing other nocopy field. + unsafe { + move_out(x.f1_nocopy); + move_out(x.f2_nocopy); //~ ERROR use of moved value: `x` + } +} + +fn test2(x: U1) { + // "Moving" out of copy field doesn't prevent later field accesses. + unsafe { + move_out(x.f3_copy); + move_out(x.f2_nocopy); // no error + } +} + +fn test3(x: U1) { + // Moving out of a nocopy field prevents accessing other copy field. + unsafe { + move_out(x.f2_nocopy); + move_out(x.f3_copy); //~ ERROR use of moved value: `x` + } +} + +fn test4(x: U2) { + // Cannot move out of union that implements `Drop`. + unsafe { + move_out(x.f1_nocopy); //~ ERROR cannot move out of type `U2`, which implements the `Drop` + } +} + +fn main() {} diff --git a/src/test/ui/union/union-move.stderr b/src/test/ui/union/union-move.stderr new file mode 100644 index 0000000000..5679192b64 --- /dev/null +++ b/src/test/ui/union/union-move.stderr @@ -0,0 +1,35 @@ +error[E0382]: use of moved value: `x` + --> $DIR/union-move.rs:26:18 + | +LL | fn test1(x: U1) { + | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait +... +LL | move_out(x.f1_nocopy); + | ----------- value moved here +LL | move_out(x.f2_nocopy); + | ^^^^^^^^^^^ value used here after move + +error[E0382]: use of moved value: `x` + --> $DIR/union-move.rs:42:18 + | +LL | fn test3(x: U1) { + | - move occurs because `x` has type `U1`, which does not implement the `Copy` trait +... +LL | move_out(x.f2_nocopy); + | ----------- value moved here +LL | move_out(x.f3_copy); + | ^^^^^^^^^ value used here after move + +error[E0509]: cannot move out of type `U2`, which implements the `Drop` trait + --> $DIR/union-move.rs:49:18 + | +LL | move_out(x.f1_nocopy); + | ^^^^^^^^^^^ + | | + | cannot move out of here + | move occurs because `x.f1_nocopy` has type `RefCell`, which does not implement the `Copy` trait + +error: aborting due to 3 previous errors + +Some errors have detailed explanations: E0382, E0509. +For more information about an error, try `rustc --explain E0382`. diff --git a/src/test/ui/union/union-sized-field.stderr b/src/test/ui/union/union-sized-field.stderr index b916bbe8ad..cebeeb59a7 100644 --- a/src/test/ui/union/union-sized-field.stderr +++ b/src/test/ui/union/union-sized-field.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/union-sized-field.rs:4:12 | LL | union Foo { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | value: T, | ^ doesn't have a size known at compile-time | @@ -21,7 +21,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/union-sized-field.rs:9:12 | LL | struct Foo2 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | value: T, | ^ doesn't have a size known at compile-time | @@ -40,7 +40,7 @@ error[E0277]: the size for values of type `T` cannot be known at compilation tim --> $DIR/union-sized-field.rs:15:11 | LL | enum Foo3 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | Value(T), | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/union/union-unsized.stderr b/src/test/ui/union/union-unsized.stderr index f62a3b4d14..454580dcba 100644 --- a/src/test/ui/union/union-unsized.stderr +++ b/src/test/ui/union/union-unsized.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | a: str, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -22,7 +22,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | b: str, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: no field of a union may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size diff --git a/src/test/ui/unique-object-noncopyable.stderr b/src/test/ui/unique-object-noncopyable.stderr index 5b4c892299..423350cd93 100644 --- a/src/test/ui/unique-object-noncopyable.stderr +++ b/src/test/ui/unique-object-noncopyable.stderr @@ -1,33 +1,33 @@ -error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope +error[E0599]: no method named `clone` found for struct `Box` in the current scope --> $DIR/unique-object-noncopyable.rs:24:16 | LL | trait Foo { | --------- | | - | doesn't satisfy `dyn Foo: std::clone::Clone` - | doesn't satisfy `dyn Foo: std::marker::Sized` + | doesn't satisfy `dyn Foo: Clone` + | doesn't satisfy `dyn Foo: Sized` ... LL | let _z = y.clone(); - | ^^^^^ method not found in `std::boxed::Box` + | ^^^^^ method not found in `Box` | ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL | LL | pub struct Box(Unique); - | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` + | ------------------------------------- doesn't satisfy `Box: Clone` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `dyn Foo: std::marker::Sized` - which is required by `std::boxed::Box: std::clone::Clone` - `dyn Foo: std::clone::Clone` - which is required by `std::boxed::Box: std::clone::Clone` + `dyn Foo: Sized` + which is required by `Box: Clone` + `dyn Foo: Clone` + which is required by `Box: Clone` error: aborting due to previous error diff --git a/src/test/ui/unique-pinned-nocopy.stderr b/src/test/ui/unique-pinned-nocopy.stderr index ef3dcb478c..d39db22504 100644 --- a/src/test/ui/unique-pinned-nocopy.stderr +++ b/src/test/ui/unique-pinned-nocopy.stderr @@ -1,31 +1,31 @@ -error[E0599]: no method named `clone` found for struct `std::boxed::Box` in the current scope +error[E0599]: no method named `clone` found for struct `Box` in the current scope --> $DIR/unique-pinned-nocopy.rs:12:16 | LL | struct R { - | -------- doesn't satisfy `R: std::clone::Clone` + | -------- doesn't satisfy `R: Clone` ... LL | let _j = i.clone(); - | ^^^^^ method not found in `std::boxed::Box` + | ^^^^^ method not found in `Box` | ::: $SRC_DIR/alloc/src/boxed.rs:LL:COL | LL | pub struct Box(Unique); - | ------------------------------------- doesn't satisfy `std::boxed::Box: std::clone::Clone` + | ------------------------------------- doesn't satisfy `Box: Clone` | ::: $SRC_DIR/core/src/clone.rs:LL:COL | LL | fn clone(&self) -> Self; | ----- | | - | the method is available for `std::sync::Arc>` here - | the method is available for `std::rc::Rc>` here + | the method is available for `Arc>` here + | the method is available for `Rc>` here | = note: the method `clone` exists but the following trait bounds were not satisfied: - `R: std::clone::Clone` - which is required by `std::boxed::Box: std::clone::Clone` + `R: Clone` + which is required by `Box: Clone` = 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: `std::clone::Clone` + candidate #1: `Clone` error: aborting due to previous error diff --git a/src/test/ui/unknown-tool-name.rs b/src/test/ui/unknown-tool-name.rs index 05f99ced68..73fca61c65 100644 --- a/src/test/ui/unknown-tool-name.rs +++ b/src/test/ui/unknown-tool-name.rs @@ -1,2 +1,2 @@ -#[foo::bar] //~ ERROR failed to resolve: use of undeclared type or module `foo` +#[foo::bar] //~ ERROR failed to resolve: use of undeclared crate or module `foo` fn main() {} diff --git a/src/test/ui/unknown-tool-name.stderr b/src/test/ui/unknown-tool-name.stderr index 7a6ed57bda..4a1370ba80 100644 --- a/src/test/ui/unknown-tool-name.stderr +++ b/src/test/ui/unknown-tool-name.stderr @@ -1,8 +1,8 @@ -error[E0433]: failed to resolve: use of undeclared type or module `foo` +error[E0433]: failed to resolve: use of undeclared crate or module `foo` --> $DIR/unknown-tool-name.rs:1:3 | LL | #[foo::bar] - | ^^^ use of undeclared type or module `foo` + | ^^^ use of undeclared crate or module `foo` error: aborting due to previous error diff --git a/src/test/ui/unsafe/ranged_ints2_const.rs b/src/test/ui/unsafe/ranged_ints2_const.rs index 788f49f743..65e0d79308 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.rs +++ b/src/test/ui/unsafe/ranged_ints2_const.rs @@ -8,13 +8,13 @@ fn main() { const fn foo() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = &mut x.0; //~ ERROR references in const fn are unstable + let y = &mut x.0; //~ ERROR mutable references //~^ ERROR mutation of layout constrained field is unsafe unsafe { NonZero(1) } } const fn bar() -> NonZero { let mut x = unsafe { NonZero(1) }; - let y = unsafe { &mut x.0 }; //~ ERROR mutable references in const fn are unstable + let y = unsafe { &mut x.0 }; //~ ERROR mutable references unsafe { NonZero(1) } } diff --git a/src/test/ui/unsafe/ranged_ints2_const.stderr b/src/test/ui/unsafe/ranged_ints2_const.stderr index d508d07791..5ce4296458 100644 --- a/src/test/ui/unsafe/ranged_ints2_const.stderr +++ b/src/test/ui/unsafe/ranged_ints2_const.stderr @@ -1,20 +1,20 @@ -error[E0723]: mutable references in const fn are unstable - --> $DIR/ranged_ints2_const.rs:11:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/ranged_ints2_const.rs:11:13 | LL | let y = &mut x.0; - | ^ + | ^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable -error[E0723]: mutable references in const fn are unstable - --> $DIR/ranged_ints2_const.rs:18:9 +error[E0658]: mutable references are not allowed in constant functions + --> $DIR/ranged_ints2_const.rs:18:22 | LL | let y = unsafe { &mut x.0 }; - | ^ + | ^^^^^^^^ | - = note: see issue #57563 for more information - = help: add `#![feature(const_fn)]` to the crate attributes to enable + = note: see issue #57349 for more information + = help: add `#![feature(const_mut_refs)]` to the crate attributes to enable error[E0133]: mutation of layout constrained field is unsafe and requires unsafe function or block --> $DIR/ranged_ints2_const.rs:11:13 @@ -26,5 +26,5 @@ LL | let y = &mut x.0; error: aborting due to 3 previous errors -Some errors have detailed explanations: E0133, E0723. +Some errors have detailed explanations: E0133, E0658. For more information about an error, try `rustc --explain E0133`. diff --git a/src/test/ui/unsafe/unsafe-subtyping.stderr b/src/test/ui/unsafe/unsafe-subtyping.stderr index 19f5ef463c..2db7cc3128 100644 --- a/src/test/ui/unsafe/unsafe-subtyping.stderr +++ b/src/test/ui/unsafe/unsafe-subtyping.stderr @@ -2,12 +2,12 @@ error[E0308]: mismatched types --> $DIR/unsafe-subtyping.rs:4:5 | LL | fn foo(x: Option) -> Option { - | ---------------------- expected `std::option::Option` because of return type + | ---------------------- expected `Option` because of return type LL | x | ^ expected unsafe fn, found normal fn | - = note: expected enum `std::option::Option` - found enum `std::option::Option` + = note: expected enum `Option` + found enum `Option` error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr index 906b543e42..b49c32f5f8 100644 --- a/src/test/ui/unsized-locals/borrow-after-move.stderr +++ b/src/test/ui/unsized-locals/borrow-after-move.stderr @@ -5,7 +5,7 @@ LL | let y = *x; | -- value moved here LL | drop_unsized(y); LL | println!("{}", &x); - | ^^ value borrowed here after partial move + | ^^ value borrowed here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -27,7 +27,7 @@ LL | let y = *x; | -- value moved here LL | y.foo(); LL | println!("{}", &x); - | ^^ value borrowed here after partial move + | ^^ value borrowed here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -52,7 +52,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/borrow-after-move.rs:39:24 | LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | x.foo(); | - value moved here LL | println!("{}", &x); diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr index 49b2031c6b..36fb32ae09 100644 --- a/src/test/ui/unsized-locals/double-move.stderr +++ b/src/test/ui/unsized-locals/double-move.stderr @@ -14,7 +14,7 @@ error[E0382]: use of moved value: `x` LL | let _y = *x; | -- value moved here LL | drop_unsized(x); - | ^ value used here after partial move + | ^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -22,7 +22,7 @@ error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:32:18 | LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | drop_unsized(x); | - value moved here LL | let _y = *x; @@ -50,7 +50,7 @@ error[E0382]: use of moved value: `x` LL | let _y = *x; | -- value moved here LL | x.foo(); - | ^ value used here after partial move + | ^ value used here after move | = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait @@ -58,7 +58,7 @@ error[E0382]: use of moved value: `*x` --> $DIR/double-move.rs:51:18 | LL | let x = "hello".to_owned().into_boxed_str(); - | - move occurs because `x` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - move occurs because `x` has type `Box`, which does not implement the `Copy` trait LL | x.foo(); | - value moved here LL | let _y = *x; diff --git a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr index 2ed35dc0e2..46e381611a 100644 --- a/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr +++ b/src/test/ui/unsized-locals/issue-30276-feature-flagged.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | - = help: within `Test`, the trait `std::marker::Sized` is not implemented for `[i32]` + = help: within `Test`, the trait `Sized` is not implemented for `[i32]` = note: required because it appears within the type `Test` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/issue-30276.stderr b/src/test/ui/unsized-locals/issue-30276.stderr index 461efcf3db..e9258a61c3 100644 --- a/src/test/ui/unsized-locals/issue-30276.stderr +++ b/src/test/ui/unsized-locals/issue-30276.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | let _x: fn(_) -> Test = Test; | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = help: the trait `Sized` is not implemented for `[i32]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr index 04a8de1b5d..dc20b92b42 100644 --- a/src/test/ui/unsized-locals/issue-50940-with-feature.stderr +++ b/src/test/ui/unsized-locals/issue-50940-with-feature.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | - = help: within `main::A`, the trait `std::marker::Sized` is not implemented for `str` - = note: required because it appears within the type `main::A` + = help: within `A`, the trait `Sized` is not implemented for `str` + = note: required because it appears within the type `A` = note: the return type of a function must have a statically known size error: aborting due to previous error diff --git a/src/test/ui/unsized-locals/issue-50940.stderr b/src/test/ui/unsized-locals/issue-50940.stderr index 8e5f753082..c602fae883 100644 --- a/src/test/ui/unsized-locals/issue-50940.stderr +++ b/src/test/ui/unsized-locals/issue-50940.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | A as fn(str) -> A; | ^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr index 0a9b43dac3..9fb401aec2 100644 --- a/src/test/ui/unsized-locals/unsized-exprs.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::<(i32, [u8])>((42, *foo())); | ^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]` + = help: within `({integer}, [u8])`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `({integer}, [u8])` = note: tuples must have a statically known size to be initialized @@ -14,7 +14,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::>(A { 0: *foo() }); | ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `A<[u8]>` = note: structs must have a statically known size to be initialized @@ -24,7 +24,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop::>(A(*foo())); | ^ doesn't have a size known at compile-time | - = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]` + = help: within `A<[u8]>`, the trait `Sized` is not implemented for `[u8]` = note: required because it appears within the type `A<[u8]>` = note: the return type of a function must have a statically known size diff --git a/src/test/ui/unsized-locals/unsized-exprs3.stderr b/src/test/ui/unsized-locals/unsized-exprs3.stderr index 11435ec035..426262e82b 100644 --- a/src/test/ui/unsized-locals/unsized-exprs3.stderr +++ b/src/test/ui/unsized-locals/unsized-exprs3.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | udrop as fn([u8]); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: all function arguments must have a statically known size = help: unsized locals are gated as an unstable feature diff --git a/src/test/ui/unsized/unsized-bare-typaram.stderr b/src/test/ui/unsized/unsized-bare-typaram.stderr index 19978ae24c..b2ff3159c9 100644 --- a/src/test/ui/unsized/unsized-bare-typaram.stderr +++ b/src/test/ui/unsized/unsized-bare-typaram.stderr @@ -6,7 +6,7 @@ LL | fn bar() { } LL | fn foo() { bar::() } | - ^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` error: aborting due to previous error diff --git a/src/test/ui/unsized/unsized-enum.stderr b/src/test/ui/unsized/unsized-enum.stderr index fdfdb9b4e2..795c7beab0 100644 --- a/src/test/ui/unsized/unsized-enum.stderr +++ b/src/test/ui/unsized/unsized-enum.stderr @@ -7,7 +7,7 @@ LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } | - ^^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `U` if it were used through indirection like `&U` or `Box` --> $DIR/unsized-enum.rs:4:10 diff --git a/src/test/ui/unsized/unsized-enum2.stderr b/src/test/ui/unsized/unsized-enum2.stderr index 988c310167..0a0896638e 100644 --- a/src/test/ui/unsized/unsized-enum2.stderr +++ b/src/test/ui/unsized/unsized-enum2.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `W` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:23:8 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | // parameter LL | VA(W), | ^ doesn't have a size known at compile-time @@ -22,7 +22,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:25:11 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | VB{x: X}, | ^ doesn't have a size known at compile-time @@ -42,7 +42,7 @@ error[E0277]: the size for values of type `Y` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:27:15 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | VC(isize, Y), | ^ doesn't have a size known at compile-time @@ -62,7 +62,7 @@ error[E0277]: the size for values of type `Z` cannot be known at compilation tim --> $DIR/unsized-enum2.rs:29:21 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | VD{u: isize, x: Z}, | ^ doesn't have a size known at compile-time @@ -84,7 +84,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | VE([u8]), | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -102,7 +102,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | VF{x: str}, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -120,7 +120,7 @@ error[E0277]: the size for values of type `[f32]` cannot be known at compilation LL | VG(isize, [f32]), | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[f32]` + = help: the trait `Sized` is not implemented for `[f32]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -138,7 +138,7 @@ error[E0277]: the size for values of type `[u32]` cannot be known at compilation LL | VH{u: isize, x: [u32]}, | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u32]` + = help: the trait `Sized` is not implemented for `[u32]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -156,7 +156,7 @@ error[E0277]: the size for values of type `(dyn Foo + 'static)` cannot be known LL | VM(dyn Foo), | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Foo + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Foo + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -174,7 +174,7 @@ error[E0277]: the size for values of type `(dyn Bar + 'static)` cannot be known LL | VN{x: dyn Bar}, | ^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn Bar + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Bar + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -192,7 +192,7 @@ error[E0277]: the size for values of type `(dyn FooBar + 'static)` cannot be kno LL | VO(isize, dyn FooBar), | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn FooBar + 'static)` + = help: the trait `Sized` is not implemented for `(dyn FooBar + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -210,7 +210,7 @@ error[E0277]: the size for values of type `(dyn BarFoo + 'static)` cannot be kno LL | VP{u: isize, x: dyn BarFoo}, | ^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `(dyn BarFoo + 'static)` + = help: the trait `Sized` is not implemented for `(dyn BarFoo + 'static)` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -228,7 +228,7 @@ error[E0277]: the size for values of type `[i8]` cannot be known at compilation LL | VQ(<&'static [i8] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i8]` + = help: the trait `Sized` is not implemented for `[i8]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -246,7 +246,7 @@ error[E0277]: the size for values of type `[char]` cannot be known at compilatio LL | VR{x: <&'static [char] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[char]` + = help: the trait `Sized` is not implemented for `[char]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -264,7 +264,7 @@ error[E0277]: the size for values of type `[f64]` cannot be known at compilation LL | VS(isize, <&'static [f64] as Deref>::Target), | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[f64]` + = help: the trait `Sized` is not implemented for `[f64]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -282,7 +282,7 @@ error[E0277]: the size for values of type `[i32]` cannot be known at compilation LL | VT{u: isize, x: <&'static [i32] as Deref>::Target}, | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[i32]` + = help: the trait `Sized` is not implemented for `[i32]` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -300,7 +300,7 @@ error[E0277]: the size for values of type `(dyn PathHelper1 + 'static)` cannot b LL | VI(Path1), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path1`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper1 + 'static)` + = help: within `Path1`, the trait `Sized` is not implemented for `(dyn PathHelper1 + 'static)` = note: required because it appears within the type `Path1` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size @@ -319,7 +319,7 @@ error[E0277]: the size for values of type `(dyn PathHelper2 + 'static)` cannot b LL | VJ{x: Path2}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path2`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper2 + 'static)` + = help: within `Path2`, the trait `Sized` is not implemented for `(dyn PathHelper2 + 'static)` = note: required because it appears within the type `Path2` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size @@ -338,7 +338,7 @@ error[E0277]: the size for values of type `(dyn PathHelper3 + 'static)` cannot b LL | VK(isize, Path3), | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path3`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper3 + 'static)` + = help: within `Path3`, the trait `Sized` is not implemented for `(dyn PathHelper3 + 'static)` = note: required because it appears within the type `Path3` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size @@ -357,7 +357,7 @@ error[E0277]: the size for values of type `(dyn PathHelper4 + 'static)` cannot b LL | VL{u: isize, x: Path4}, | ^^^^^ doesn't have a size known at compile-time | - = help: within `Path4`, the trait `std::marker::Sized` is not implemented for `(dyn PathHelper4 + 'static)` + = help: within `Path4`, the trait `Sized` is not implemented for `(dyn PathHelper4 + 'static)` = note: required because it appears within the type `Path4` = note: no field of an enum variant may have a dynamically sized type = help: change the field's type to have a statically known size diff --git a/src/test/ui/unsized/unsized-fn-param.stderr b/src/test/ui/unsized/unsized-fn-param.stderr index 6b54db7148..b498259efe 100644 --- a/src/test/ui/unsized/unsized-fn-param.stderr +++ b/src/test/ui/unsized/unsized-fn-param.stderr @@ -4,8 +4,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo11("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:13:19 @@ -13,8 +13,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo12(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:16:11 @@ -22,8 +22,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo21("bar", &"baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error[E0277]: the size for values of type `str` cannot be known at compilation time --> $DIR/unsized-fn-param.rs:18:19 @@ -31,8 +31,8 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | foo22(&"bar", "baz"); | ^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` - = note: required for the cast to the object type `dyn std::convert::AsRef` + = help: the trait `Sized` is not implemented for `str` + = note: required for the cast to the object type `dyn AsRef` error: aborting due to 4 previous errors diff --git a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr index 50b54593f3..9efebe3aef 100644 --- a/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-inherent-impl-self-type.stderr @@ -7,7 +7,7 @@ LL | LL | impl S5 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-inherent-impl-self-type.rs:5:11 diff --git a/src/test/ui/unsized/unsized-struct.stderr b/src/test/ui/unsized/unsized-struct.stderr index 0c8529bf1a..e013b8fc69 100644 --- a/src/test/ui/unsized/unsized-struct.stderr +++ b/src/test/ui/unsized/unsized-struct.stderr @@ -7,7 +7,7 @@ LL | fn foo1() { not_sized::>() } // Hunky dory. LL | fn foo2() { not_sized::>() } | - ^^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/unsized-struct.rs:4:12 @@ -26,7 +26,7 @@ LL | fn is_sized() { } LL | fn bar2() { is_sized::>() } | - ^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | = note: required because it appears within the type `Bar` diff --git a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr index 071547c945..516c750cb3 100644 --- a/src/test/ui/unsized/unsized-trait-impl-self-type.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-self-type.stderr @@ -7,7 +7,7 @@ LL | LL | impl T3 for S5 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: you could relax the implicit `Sized` bound on `Y` if it were used through indirection like `&Y` or `Box` --> $DIR/unsized-trait-impl-self-type.rs:8:11 diff --git a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr index f48d4ef9f1..17fe16ed4f 100644 --- a/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr +++ b/src/test/ui/unsized/unsized-trait-impl-trait-arg.stderr @@ -7,7 +7,7 @@ LL | trait T2 { LL | impl T2 for S4 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: consider relaxing the implicit `Sized` restriction | diff --git a/src/test/ui/unsized3.stderr b/src/test/ui/unsized3.stderr index ddddae4eab..7ed43c38f1 100644 --- a/src/test/ui/unsized3.stderr +++ b/src/test/ui/unsized3.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:7:13 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f2::(x); | ^ doesn't have a size known at compile-time ... @@ -18,7 +18,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:18:13 | LL | fn f3(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f4::(x); | ^ doesn't have a size known at compile-time ... @@ -37,7 +37,7 @@ LL | fn f5(x: &Y) {} | - required by this bound in `f5` ... LL | fn f8(x1: &S, x2: &S) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(x1); | ^^ doesn't have a size known at compile-time | @@ -51,7 +51,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:40:8 | LL | fn f9(x1: Box>) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(&(*x1, 34)); | ^^^^^^^^^^ doesn't have a size known at compile-time | @@ -62,7 +62,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized3.rs:45:9 | LL | fn f10(x1: Box>) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(&(32, *x1)); | ^^^^^^^^^ doesn't have a size known at compile-time | @@ -77,7 +77,7 @@ LL | fn f5(x: &Y) {} | - required by this bound in `f5` ... LL | fn f10(x1: Box>) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f5(&(32, *x1)); | ^^^^^^^^^^ doesn't have a size known at compile-time | diff --git a/src/test/ui/unsized5.stderr b/src/test/ui/unsized5.stderr index 3fd0b429be..a7539b0672 100644 --- a/src/test/ui/unsized5.stderr +++ b/src/test/ui/unsized5.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:4:9 | LL | struct S1 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f1: X, | ^ doesn't have a size known at compile-time | @@ -21,7 +21,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:10:8 | LL | struct S2 { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | f: isize, LL | g: X, | ^ doesn't have a size known at compile-time @@ -43,7 +43,7 @@ error[E0277]: the size for values of type `str` cannot be known at compilation t LL | f: str, | ^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `str` + = help: the trait `Sized` is not implemented for `str` = note: only the last field of a struct may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -61,7 +61,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | f: [u8], | ^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: only the last field of a struct may have a dynamically sized type = help: change the field's type to have a statically known size help: borrowed types always have a statically known size @@ -77,7 +77,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:25:8 | LL | enum E { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | V1(X, isize), | ^ doesn't have a size known at compile-time | @@ -96,7 +96,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized5.rs:29:12 | LL | enum F { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | V2{f1: X, f: isize}, | ^ doesn't have a size known at compile-time | diff --git a/src/test/ui/unsized6.stderr b/src/test/ui/unsized6.stderr index f045bfe244..e85b73355e 100644 --- a/src/test/ui/unsized6.stderr +++ b/src/test/ui/unsized6.stderr @@ -2,7 +2,7 @@ error[E0277]: the size for values of type `Y` cannot be known at compilation tim --> $DIR/unsized6.rs:9:9 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y: Y; | ^ doesn't have a size known at compile-time @@ -14,7 +14,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:7:12 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let _: W; // <-- this is OK, no bindings created, no initializer. LL | let _: (isize, (X, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -25,7 +25,7 @@ error[E0277]: the size for values of type `Z` cannot be known at compilation tim --> $DIR/unsized6.rs:11:12 | LL | fn f1(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y: (isize, (Z, usize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -36,7 +36,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:15:9 | LL | fn f2(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let y: X; | ^ doesn't have a size known at compile-time | @@ -47,7 +47,7 @@ error[E0277]: the size for values of type `Y` cannot be known at compilation tim --> $DIR/unsized6.rs:17:12 | LL | fn f2(x: &X) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y: (isize, (Y, isize)); | ^^^^^^^^^^^^^^^^^^^ doesn't have a size known at compile-time @@ -58,7 +58,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:22:9 | LL | fn f3(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | @@ -69,7 +69,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:24:9 | LL | fn f3(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y = *x2; | ^ doesn't have a size known at compile-time @@ -81,7 +81,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:26:10 | LL | fn f3(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time @@ -93,7 +93,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:30:9 | LL | fn f4(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` LL | let y: X = *x1; | ^ doesn't have a size known at compile-time | @@ -104,7 +104,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:32:9 | LL | fn f4(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let y = *x2; | ^ doesn't have a size known at compile-time @@ -116,7 +116,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim --> $DIR/unsized6.rs:34:10 | LL | fn f4(x1: Box, x2: Box, x3: Box) { - | - this type parameter needs to be `std::marker::Sized` + | - this type parameter needs to be `Sized` ... LL | let (y, z) = (*x3, 4); | ^ doesn't have a size known at compile-time @@ -130,7 +130,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim LL | fn g1(x: X) {} | - ^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size @@ -144,7 +144,7 @@ error[E0277]: the size for values of type `X` cannot be known at compilation tim LL | fn g2(x: X) {} | - ^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | = help: unsized locals are gated as an unstable feature help: function arguments must have a statically known size, borrowed types always have a known size diff --git a/src/test/ui/unsized7.stderr b/src/test/ui/unsized7.stderr index 7dbddd4ed2..5f9a2604ed 100644 --- a/src/test/ui/unsized7.stderr +++ b/src/test/ui/unsized7.stderr @@ -7,7 +7,7 @@ LL | trait T1 { LL | impl T1 for S3 { | - ^^^^^ doesn't have a size known at compile-time | | - | this type parameter needs to be `std::marker::Sized` + | this type parameter needs to be `Sized` | help: consider relaxing the implicit `Sized` restriction | diff --git a/src/test/ui/unused/unused-closure.rs b/src/test/ui/unused/unused-closure.rs index 637d8bb43a..5100636842 100644 --- a/src/test/ui/unused/unused-closure.rs +++ b/src/test/ui/unused/unused-closure.rs @@ -11,7 +11,7 @@ fn unused() { println!("Hello!"); }; - async {}; //~ ERROR unused implementer of `std::future::Future` that must be used + async {}; //~ ERROR unused implementer of `Future` that must be used || async {}; //~ ERROR unused closure that must be used async || {}; //~ ERROR unused closure that must be used diff --git a/src/test/ui/unused/unused-closure.stderr b/src/test/ui/unused/unused-closure.stderr index 9dc73fb7ab..f8b4cbb02c 100644 --- a/src/test/ui/unused/unused-closure.stderr +++ b/src/test/ui/unused/unused-closure.stderr @@ -13,7 +13,7 @@ LL | #![deny(unused_must_use)] | ^^^^^^^^^^^^^^^ = note: closures are lazy and do nothing unless called -error: unused implementer of `std::future::Future` that must be used +error: unused implementer of `Future` that must be used --> $DIR/unused-closure.rs:14:5 | LL | async {}; diff --git a/src/test/ui/use/use-after-move-based-on-type.stderr b/src/test/ui/use/use-after-move-based-on-type.stderr index 520f88f55d..11ce005bb4 100644 --- a/src/test/ui/use/use-after-move-based-on-type.stderr +++ b/src/test/ui/use/use-after-move-based-on-type.stderr @@ -2,7 +2,7 @@ error[E0382]: borrow of moved value: `x` --> $DIR/use-after-move-based-on-type.rs:4:20 | LL | let x = "Hello!".to_string(); - | - move occurs because `x` has type `std::string::String`, which does not implement the `Copy` trait + | - move occurs because `x` has type `String`, which does not implement the `Copy` trait LL | let _y = x; | - value moved here LL | println!("{}", x); diff --git a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr index e16bca3806..b3266562d1 100644 --- a/src/test/ui/use/use-after-move-implicity-coerced-object.stderr +++ b/src/test/ui/use/use-after-move-implicity-coerced-object.stderr @@ -2,7 +2,7 @@ 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 }; - | - move occurs because `n` has type `std::boxed::Box`, which does not implement the `Copy` trait + | - 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 | l.push(n); | - value moved here diff --git a/src/test/ui/use/use-self-type.rs b/src/test/ui/use/use-self-type.rs index 3e5c7bf3cc..370593b2eb 100644 --- a/src/test/ui/use/use-self-type.rs +++ b/src/test/ui/use/use-self-type.rs @@ -4,7 +4,7 @@ impl S { fn f() {} fn g() { use Self::f; //~ ERROR unresolved import - pub(in Self::f) struct Z; //~ ERROR use of undeclared type or module `Self` + pub(in Self::f) struct Z; //~ ERROR use of undeclared type `Self` } } diff --git a/src/test/ui/use/use-self-type.stderr b/src/test/ui/use/use-self-type.stderr index 0dd0e04267..d1469fb349 100644 --- a/src/test/ui/use/use-self-type.stderr +++ b/src/test/ui/use/use-self-type.stderr @@ -1,14 +1,14 @@ -error[E0433]: failed to resolve: use of undeclared type or module `Self` +error[E0433]: failed to resolve: use of undeclared type `Self` --> $DIR/use-self-type.rs:7:16 | LL | pub(in Self::f) struct Z; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error[E0432]: unresolved import `Self` --> $DIR/use-self-type.rs:6:13 | LL | use Self::f; - | ^^^^ use of undeclared type or module `Self` + | ^^^^ use of undeclared type `Self` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-regions-unused-direct.stderr b/src/test/ui/variance/variance-regions-unused-direct.stderr index cf375ccae8..1a600f5b05 100644 --- a/src/test/ui/variance/variance-regions-unused-direct.stderr +++ b/src/test/ui/variance/variance-regions-unused-direct.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | struct Bivariant<'a>; | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `'d` is never used --> $DIR/variance-regions-unused-direct.rs:7:19 @@ -12,7 +12,7 @@ error[E0392]: parameter `'d` is never used LL | struct Struct<'a, 'd> { | ^^ unused parameter | - = help: consider removing `'d`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'d`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-regions-unused-indirect.stderr b/src/test/ui/variance/variance-regions-unused-indirect.stderr index 7c7ba69db2..93710cc133 100644 --- a/src/test/ui/variance/variance-regions-unused-indirect.stderr +++ b/src/test/ui/variance/variance-regions-unused-indirect.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | enum Foo<'a> { | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `'a` is never used --> $DIR/variance-regions-unused-indirect.rs:7:10 @@ -12,7 +12,7 @@ error[E0392]: parameter `'a` is never used LL | enum Bar<'a> { | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-unused-region-param.stderr b/src/test/ui/variance/variance-unused-region-param.stderr index 4cd3135803..7c7ec40ba3 100644 --- a/src/test/ui/variance/variance-unused-region-param.stderr +++ b/src/test/ui/variance/variance-unused-region-param.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `'a` is never used LL | struct SomeStruct<'a> { x: u32 } | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `'a` is never used --> $DIR/variance-unused-region-param.rs:4:15 @@ -12,7 +12,7 @@ error[E0392]: parameter `'a` is never used LL | enum SomeEnum<'a> { Nothing } | ^^ unused parameter | - = help: consider removing `'a`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `'a`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 2 previous errors diff --git a/src/test/ui/variance/variance-unused-type-param.stderr b/src/test/ui/variance/variance-unused-type-param.stderr index b648e3c1d5..a4d636bc03 100644 --- a/src/test/ui/variance/variance-unused-type-param.stderr +++ b/src/test/ui/variance/variance-unused-type-param.stderr @@ -4,7 +4,7 @@ error[E0392]: parameter `A` is never used LL | struct SomeStruct { x: u32 } | ^ unused parameter | - = help: consider removing `A`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `A` is never used --> $DIR/variance-unused-type-param.rs:9:15 @@ -12,7 +12,7 @@ error[E0392]: parameter `A` is never used LL | enum SomeEnum { Nothing } | ^ unused parameter | - = help: consider removing `A`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `A`, referring to it in a field, or using a marker such as `PhantomData` error[E0392]: parameter `T` is never used --> $DIR/variance-unused-type-param.rs:13:15 @@ -20,7 +20,7 @@ error[E0392]: parameter `T` is never used LL | enum ListCell { | ^ unused parameter | - = help: consider removing `T`, referring to it in a field, or using a marker such as `std::marker::PhantomData` + = help: consider removing `T`, referring to it in a field, or using a marker such as `PhantomData` error: aborting due to 3 previous errors diff --git a/src/test/ui/vec/vec-res-add.rs b/src/test/ui/vec/vec-res-add.rs index 4785178fb2..57b552ee55 100644 --- a/src/test/ui/vec/vec-res-add.rs +++ b/src/test/ui/vec/vec-res-add.rs @@ -14,6 +14,6 @@ fn main() { let i = vec![r(0)]; let j = vec![r(1)]; let k = i + j; - //~^ ERROR cannot add `std::vec::Vec` to `std::vec::Vec` + //~^ ERROR cannot add `Vec` to `Vec` println!("{:?}", j); } diff --git a/src/test/ui/vec/vec-res-add.stderr b/src/test/ui/vec/vec-res-add.stderr index 2d41583268..7511271361 100644 --- a/src/test/ui/vec/vec-res-add.stderr +++ b/src/test/ui/vec/vec-res-add.stderr @@ -1,10 +1,10 @@ -error[E0369]: cannot add `std::vec::Vec` to `std::vec::Vec` +error[E0369]: cannot add `Vec` to `Vec` --> $DIR/vec-res-add.rs:16:15 | LL | let k = i + j; - | - ^ - std::vec::Vec + | - ^ - Vec | | - | std::vec::Vec + | Vec error: aborting due to previous error diff --git a/src/test/ui/vector-no-ann.stderr b/src/test/ui/vector-no-ann.stderr index 62fc42fbae..8a7b8d2276 100644 --- a/src/test/ui/vector-no-ann.stderr +++ b/src/test/ui/vector-no-ann.stderr @@ -1,10 +1,10 @@ -error[E0282]: type annotations needed for `std::vec::Vec` +error[E0282]: type annotations needed for `Vec` --> $DIR/vector-no-ann.rs:2:16 | LL | let _foo = Vec::new(); | ---- ^^^^^^^^ cannot infer type for type parameter `T` | | - | consider giving `_foo` the explicit type `std::vec::Vec`, where the type parameter `T` is specified + | consider giving `_foo` the explicit type `Vec`, where the type parameter `T` is specified error: aborting due to previous error diff --git a/src/test/ui/wf/wf-array-elem-sized.stderr b/src/test/ui/wf/wf-array-elem-sized.stderr index fedec1909f..7f3c58d6bb 100644 --- a/src/test/ui/wf/wf-array-elem-sized.stderr +++ b/src/test/ui/wf/wf-array-elem-sized.stderr @@ -4,7 +4,7 @@ error[E0277]: the size for values of type `[u8]` cannot be known at compilation LL | foo: [[u8]], | ^^^^^^ doesn't have a size known at compile-time | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` = note: slice and array elements must have `Sized` type error: aborting due to previous error diff --git a/src/test/ui/wf/wf-const-type.stderr b/src/test/ui/wf/wf-const-type.stderr index 1b7f8b6fca..d2e6854880 100644 --- a/src/test/ui/wf/wf-const-type.stderr +++ b/src/test/ui/wf/wf-const-type.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `NotCopy: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-const-type.rs:10:12 | LL | struct IsCopy { t: T } | ---- required by this bound in `IsCopy` ... LL | const FOO: IsCopy> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `NotCopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option` + = note: required because of the requirements on the impl of `Copy` for `Option` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr index eefb450155..e707839a97 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj-box.stderr @@ -9,8 +9,8 @@ LL | trait Trait: Sized {} LL | let t_box: Box = Box::new(S); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj-box.rs:17:15 @@ -23,8 +23,8 @@ LL | trait Trait: Sized {} LL | takes_box(Box::new(S)); | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box<(dyn Trait + 'static)>` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box<(dyn Trait + 'static)>` error[E0038]: the trait `Trait` cannot be made into an object --> $DIR/wf-convert-unsafe-trait-obj-box.rs:15:5 @@ -37,8 +37,8 @@ LL | trait Trait: Sized {} LL | Box::new(S) as Box; | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized>` for `std::boxed::Box` - = note: required by cast to type `std::boxed::Box` + = note: required because of the requirements on the impl of `CoerceUnsized>` for `Box` + = note: required by cast to type `Box` error: aborting due to 3 previous errors diff --git a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr index 5e645382d1..08d4808b77 100644 --- a/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr +++ b/src/test/ui/wf/wf-convert-unsafe-trait-obj.stderr @@ -9,7 +9,7 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = &S; | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object @@ -23,7 +23,7 @@ LL | trait Trait: Sized {} LL | takes_trait(&S); | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object @@ -37,7 +37,7 @@ LL | trait Trait: Sized {} LL | &S as &dyn Trait; | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error: aborting due to 3 previous errors diff --git a/src/test/ui/wf/wf-enum-bound.stderr b/src/test/ui/wf/wf-enum-bound.stderr index 962a1b839a..e7bc858225 100644 --- a/src/test/ui/wf/wf-enum-bound.stderr +++ b/src/test/ui/wf/wf-enum-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-enum-bound.rs:10:14 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr index 1eb7010c77..c97ce53885 100644 --- a/src/test/ui/wf/wf-enum-fields-struct-variant.stderr +++ b/src/test/ui/wf/wf-enum-fields-struct-variant.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `A: Copy` is not satisfied --> $DIR/wf-enum-fields-struct-variant.rs:13:12 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | f: IsCopy - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `Copy` is not implemented for `A` | help: consider restricting type parameter `A` | -LL | enum AnotherEnum { - | ^^^^^^^^^^^^^^^^^^^ +LL | enum AnotherEnum { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-enum-fields.stderr b/src/test/ui/wf/wf-enum-fields.stderr index a833eeacbd..85da1bf583 100644 --- a/src/test/ui/wf/wf-enum-fields.stderr +++ b/src/test/ui/wf/wf-enum-fields.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `A: Copy` is not satisfied --> $DIR/wf-enum-fields.rs:12:17 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | SomeVariant(IsCopy) - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `Copy` is not implemented for `A` | help: consider restricting type parameter `A` | -LL | enum SomeEnum { - | ^^^^^^^^^^^^^^^^^^^ +LL | enum SomeEnum { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-fn-where-clause.stderr b/src/test/ui/wf/wf-fn-where-clause.stderr index 938336d3ac..e7921f3496 100644 --- a/src/test/ui/wf/wf-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-fn-where-clause.stderr @@ -1,18 +1,18 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-fn-where-clause.rs:8:24 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` LL | LL | fn foo() where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | fn foo() where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | fn foo() where T: ExtraCopy, U: Copy + | ^^^^^^^^^ -error[E0277]: the size for values of type `(dyn std::marker::Copy + 'static)` cannot be known at compilation time +error[E0277]: the size for values of type `(dyn Copy + 'static)` cannot be known at compilation time --> $DIR/wf-fn-where-clause.rs:12:16 | LL | fn bar() where Vec:, {} @@ -21,7 +21,7 @@ LL | fn bar() where Vec:, {} LL | struct Vec { | - required by this bound in `Vec` | - = help: the trait `std::marker::Sized` is not implemented for `(dyn std::marker::Copy + 'static)` + = help: the trait `Sized` is not implemented for `(dyn Copy + 'static)` help: you could relax the implicit `Sized` bound on `T` if it were used through indirection like `&T` or `Box` --> $DIR/wf-fn-where-clause.rs:16:12 | @@ -30,11 +30,11 @@ LL | struct Vec { LL | t: T, | - ...if indirection was used here: `Box` -error[E0038]: the trait `std::marker::Copy` cannot be made into an object +error[E0038]: the trait `Copy` cannot be made into an object --> $DIR/wf-fn-where-clause.rs:12:16 | LL | fn bar() where Vec:, {} - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` cannot be made into an object + | ^^^^^^^^^^^^^ the trait `Copy` cannot be made into an object | = note: the trait cannot be made into an object because it requires `Self: Sized` diff --git a/src/test/ui/wf/wf-impl-self-type.stderr b/src/test/ui/wf/wf-impl-self-type.stderr index 0c24cafb24..bc30fc90f3 100644 --- a/src/test/ui/wf/wf-impl-self-type.stderr +++ b/src/test/ui/wf/wf-impl-self-type.stderr @@ -7,9 +7,9 @@ LL | impl Foo for Option<[u8]> {} ::: $SRC_DIR/core/src/option.rs:LL:COL | LL | pub enum Option { - | - required by this bound in `std::option::Option` + | - required by this bound in `Option` | - = help: the trait `std::marker::Sized` is not implemented for `[u8]` + = help: the trait `Sized` is not implemented for `[u8]` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-arg.stderr b/src/test/ui/wf/wf-in-fn-arg.stderr index 84adf04a68..d6010d1d79 100644 --- a/src/test/ui/wf/wf-in-fn-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-arg.rs:10:14 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | fn bar(_: &MustBeCopy) - | ^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | fn bar(_: &MustBeCopy) - | ^^^^^^^^^^^^^^^^^^^ +LL | fn bar(_: &MustBeCopy) + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-ret.stderr b/src/test/ui/wf/wf-in-fn-ret.stderr index 68ef734be5..c22252657f 100644 --- a/src/test/ui/wf/wf-in-fn-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-ret.rs:10:16 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | fn bar() -> MustBeCopy - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | fn bar() -> MustBeCopy - | ^^^^^^^^^^^^^^^^^^^ +LL | fn bar() -> MustBeCopy + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-arg.stderr b/src/test/ui/wf/wf-in-fn-type-arg.stderr index 212c61e1e5..6d249f5f91 100644 --- a/src/test/ui/wf/wf-in-fn-type-arg.stderr +++ b/src/test/ui/wf/wf-in-fn-type-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-type-arg.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn(MustBeCopy) - | ^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | struct Bar { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct Bar { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-type-ret.stderr b/src/test/ui/wf/wf-in-fn-type-ret.stderr index 3fb05fe817..30ff365b11 100644 --- a/src/test/ui/wf/wf-in-fn-type-ret.stderr +++ b/src/test/ui/wf/wf-in-fn-type-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-fn-type-ret.rs:9:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: fn() -> MustBeCopy - | ^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | struct Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct Foo { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-fn-where-clause.stderr b/src/test/ui/wf/wf-in-fn-where-clause.stderr index 41cfb18631..64e9694c0e 100644 --- a/src/test/ui/wf/wf-in-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-in-fn-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-in-fn-where-clause.rs:10:14 | LL | trait MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | where T: MustBeCopy - | ^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: MustBeCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: MustBeCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-in-obj-type-trait.stderr b/src/test/ui/wf/wf-in-obj-type-trait.stderr index 129f9484df..55ea08ccbe 100644 --- a/src/test/ui/wf/wf-in-obj-type-trait.stderr +++ b/src/test/ui/wf/wf-in-obj-type-trait.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-in-obj-type-trait.rs:11:8 | LL | struct MustBeCopy { | ---- required by this bound in `MustBeCopy` ... LL | x: dyn Object> - | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | struct Bar { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct Bar { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr index 1a2a20ec68..7bbdd4bcf2 100644 --- a/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-method-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-inherent-impl-method-where-clause.rs:12:27 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | fn foo(self) where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider restricting type parameter `U` | -LL | impl Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr index ba1d4a036c..2a44e1cdc7 100644 --- a/src/test/ui/wf/wf-inherent-impl-where-clause.stderr +++ b/src/test/ui/wf/wf-inherent-impl-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-inherent-impl-where-clause.rs:11:29 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | impl Foo where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | impl Foo where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | impl Foo where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-static-type.stderr b/src/test/ui/wf/wf-static-type.stderr index 4e78090f99..a98184633b 100644 --- a/src/test/ui/wf/wf-static-type.stderr +++ b/src/test/ui/wf/wf-static-type.stderr @@ -1,13 +1,13 @@ -error[E0277]: the trait bound `NotCopy: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `NotCopy: Copy` is not satisfied --> $DIR/wf-static-type.rs:10:13 | LL | struct IsCopy { t: T } | ---- required by this bound in `IsCopy` ... LL | static FOO: IsCopy> = IsCopy { t: None }; - | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `NotCopy` + | ^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `NotCopy` | - = note: required because of the requirements on the impl of `std::marker::Copy` for `std::option::Option` + = note: required because of the requirements on the impl of `Copy` for `Option` error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-bound.stderr b/src/test/ui/wf/wf-struct-bound.stderr index d9d193aa79..948693ac6f 100644 --- a/src/test/ui/wf/wf-struct-bound.stderr +++ b/src/test/ui/wf/wf-struct-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-struct-bound.rs:10:14 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-struct-field.stderr b/src/test/ui/wf/wf-struct-field.stderr index d7d0b7a082..04e62a7fcb 100644 --- a/src/test/ui/wf/wf-struct-field.stderr +++ b/src/test/ui/wf/wf-struct-field.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `A: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `A: Copy` is not satisfied --> $DIR/wf-struct-field.rs:12:11 | LL | struct IsCopy { | ---- required by this bound in `IsCopy` ... LL | data: IsCopy - | ^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `A` + | ^^^^^^^^^ the trait `Copy` is not implemented for `A` | help: consider restricting type parameter `A` | -LL | struct SomeStruct { - | ^^^^^^^^^^^^^^^^^^^ +LL | struct SomeStruct { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-associated-type-bound.stderr b/src/test/ui/wf/wf-trait-associated-type-bound.stderr index a4ceb41ffa..166e3626f0 100644 --- a/src/test/ui/wf/wf-trait-associated-type-bound.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-trait-associated-type-bound.rs:10:17 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | type Type1: ExtraCopy; - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | trait SomeTrait { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait SomeTrait { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-associated-type-trait.stderr b/src/test/ui/wf/wf-trait-associated-type-trait.stderr index e2892e3d24..a139186ebb 100644 --- a/src/test/ui/wf/wf-trait-associated-type-trait.stderr +++ b/src/test/ui/wf/wf-trait-associated-type-trait.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `::Type1: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `::Type1: Copy` is not satisfied --> $DIR/wf-trait-associated-type-trait.rs:11:5 | LL | struct IsCopy { x: T } | ---- required by this bound in `IsCopy` ... LL | type Type2 = IsCopy; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `::Type1` + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ the trait `Copy` is not implemented for `::Type1` | help: consider further restricting the associated type | -LL | trait SomeTrait where ::Type1: std::marker::Copy { - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | trait SomeTrait where ::Type1: Copy { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-bound.stderr b/src/test/ui/wf/wf-trait-bound.stderr index 384d668d80..abb97adcfd 100644 --- a/src/test/ui/wf/wf-trait-bound.stderr +++ b/src/test/ui/wf/wf-trait-bound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `U: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `U: Copy` is not satisfied --> $DIR/wf-trait-bound.rs:10:14 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` ... LL | where T: ExtraCopy - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `U` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `U` | help: consider further restricting type parameter `U` | -LL | where T: ExtraCopy, U: std::marker::Copy - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | where T: ExtraCopy, U: Copy + | ^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-arg.stderr b/src/test/ui/wf/wf-trait-default-fn-arg.stderr index 23d886e25f..c3d5d2b966 100644 --- a/src/test/ui/wf/wf-trait-default-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-default-fn-arg.rs:11:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar) { - | ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self, x: &Bar) where Self: std::cmp::Eq { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self, x: &Bar) where Self: Eq { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-ret.stderr b/src/test/ui/wf/wf-trait-default-fn-ret.stderr index 0214064017..4382a8fe81 100644 --- a/src/test/ui/wf/wf-trait-default-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-default-fn-ret.rs:11:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self) -> Bar { - | ^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) -> Bar where Self: std::cmp::Eq { - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) -> Bar where Self: Eq { + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr index 3664c8b25a..16c0424915 100644 --- a/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-default-fn-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-default-fn-where-clause.rs:11:31 | LL | trait Bar { } | -- required by this bound in `Bar` ... LL | fn bar(&self) where A: Bar { - | ^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) where A: Bar, Self: std::cmp::Eq { - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) where A: Bar, Self: Eq { + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-arg.stderr b/src/test/ui/wf/wf-trait-fn-arg.stderr index b5f5f70ce8..4510f50fee 100644 --- a/src/test/ui/wf/wf-trait-fn-arg.stderr +++ b/src/test/ui/wf/wf-trait-fn-arg.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-fn-arg.rs:10:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self, x: &Bar); - | ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self, x: &Bar) where Self: std::cmp::Eq; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self, x: &Bar) where Self: Eq; + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-ret.stderr b/src/test/ui/wf/wf-trait-fn-ret.stderr index 5e7d8cbfea..bd0bbc09a8 100644 --- a/src/test/ui/wf/wf-trait-fn-ret.stderr +++ b/src/test/ui/wf/wf-trait-fn-ret.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-fn-ret.rs:10:22 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self) -> &Bar; - | ^^^^^^^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^^^^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) -> &Bar where Self: std::cmp::Eq; - | ^^^^^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) -> &Bar where Self: Eq; + | ^^^^^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-fn-where-clause.stderr b/src/test/ui/wf/wf-trait-fn-where-clause.stderr index 2d9ba56c58..62e5318802 100644 --- a/src/test/ui/wf/wf-trait-fn-where-clause.stderr +++ b/src/test/ui/wf/wf-trait-fn-where-clause.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `Self: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Self: Eq` is not satisfied --> $DIR/wf-trait-fn-where-clause.rs:10:49 | LL | struct Bar { value: Box } | -- required by this bound in `Bar` ... LL | fn bar(&self) where Self: Sized, Bar: Copy; - | ^^^^ the trait `std::cmp::Eq` is not implemented for `Self` + | ^^^^ the trait `Eq` is not implemented for `Self` | help: consider further restricting `Self` | -LL | fn bar(&self) where Self: Sized, Bar: Copy, Self: std::cmp::Eq; - | ^^^^^^^^^^^^^^^^^^^^ +LL | fn bar(&self) where Self: Sized, Bar: Copy, Self: Eq; + | ^^^^^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-trait-superbound.stderr b/src/test/ui/wf/wf-trait-superbound.stderr index 7d99b8f5a2..db337a7c6d 100644 --- a/src/test/ui/wf/wf-trait-superbound.stderr +++ b/src/test/ui/wf/wf-trait-superbound.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/wf-trait-superbound.rs:9:21 | LL | trait ExtraCopy { } | ---- required by this bound in `ExtraCopy` LL | LL | trait SomeTrait: ExtraCopy { - | ^^^^^^^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | trait SomeTrait: ExtraCopy { - | ^^^^^^^^^^^^^^^^^^^ +LL | trait SomeTrait: ExtraCopy { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr index 9319e3382c..d0f43f800f 100644 --- a/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr +++ b/src/test/ui/wf/wf-unsafe-trait-obj-match.stderr @@ -23,7 +23,7 @@ LL | trait Trait: Sized {} LL | Some(()) => &S, | ^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&S` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&S` = note: required by cast to type `&dyn Trait` error[E0038]: the trait `Trait` cannot be made into an object @@ -37,7 +37,7 @@ LL | trait Trait: Sized {} LL | let t: &dyn Trait = match opt() { | ^^^^^^^^^^^ the trait `Trait` cannot be made into an object | - = note: required because of the requirements on the impl of `std::ops::CoerceUnsized<&dyn Trait>` for `&R` + = note: required because of the requirements on the impl of `CoerceUnsized<&dyn Trait>` for `&R` = note: required by cast to type `&dyn Trait` error: aborting due to 3 previous errors diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs index e55316bb92..0e8bb61a79 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.rs @@ -11,7 +11,7 @@ impl Foo { fn fails_copy(self) { require_copy(self.x); - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } } diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr index 7e88107470..916c6dc6d5 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-inherent-impl.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/where-clause-constraints-are-local-for-inherent-impl.rs:13:22 | LL | fn require_copy(x: T) {} | ---- required by this bound in `require_copy` ... LL | require_copy(self.x); - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Foo { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs index b628a2ae14..25c46330e4 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.rs @@ -16,7 +16,7 @@ impl Foo for Bar { fn fails_copy(self) { require_copy(self.x); - //~^ ERROR the trait bound `T: std::marker::Copy` is not satisfied + //~^ ERROR the trait bound `T: Copy` is not satisfied } } diff --git a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr index 3558d779d9..8814018964 100644 --- a/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr +++ b/src/test/ui/where-clauses/where-clause-constraints-are-local-for-trait-impl.stderr @@ -1,16 +1,16 @@ -error[E0277]: the trait bound `T: std::marker::Copy` is not satisfied +error[E0277]: the trait bound `T: Copy` is not satisfied --> $DIR/where-clause-constraints-are-local-for-trait-impl.rs:18:22 | LL | fn require_copy(x: T) {} | ---- required by this bound in `require_copy` ... LL | require_copy(self.x); - | ^^^^^^ the trait `std::marker::Copy` is not implemented for `T` + | ^^^^^^ the trait `Copy` is not implemented for `T` | help: consider restricting type parameter `T` | -LL | impl Foo for Bar { - | ^^^^^^^^^^^^^^^^^^^ +LL | impl Foo for Bar { + | ^^^^^^ error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs index d63f37a722..a8ae029640 100644 --- a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs +++ b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.rs @@ -16,5 +16,5 @@ impl Foo { fn main() { let x = Foo { value: Bar }; x.equals(&x); - //~^ ERROR `Bar: std::cmp::Eq` is not satisfied + //~^ ERROR `Bar: Eq` is not satisfied } diff --git a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr index 6fd3872877..d7de83104c 100644 --- a/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr +++ b/src/test/ui/where-clauses/where-clauses-method-unsatisfied.stderr @@ -1,8 +1,8 @@ -error[E0277]: the trait bound `Bar: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Bar: Eq` is not satisfied --> $DIR/where-clauses-method-unsatisfied.rs:18:14 | LL | x.equals(&x); - | ^^ the trait `std::cmp::Eq` is not implemented for `Bar` + | ^^ the trait `Eq` is not implemented for `Bar` error: aborting due to previous error diff --git a/src/test/ui/where-clauses/where-clauses-unsatisfied.rs b/src/test/ui/where-clauses/where-clauses-unsatisfied.rs index 83620e5cf3..8b067d30a2 100644 --- a/src/test/ui/where-clauses/where-clauses-unsatisfied.rs +++ b/src/test/ui/where-clauses/where-clauses-unsatisfied.rs @@ -4,5 +4,5 @@ struct Struct; fn main() { drop(equal(&Struct, &Struct)) - //~^ ERROR the trait bound `Struct: std::cmp::Eq` is not satisfied + //~^ ERROR the trait bound `Struct: Eq` is not satisfied } diff --git a/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr index e92a8fc83d..9e19b9a3b1 100644 --- a/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr +++ b/src/test/ui/where-clauses/where-clauses-unsatisfied.stderr @@ -1,11 +1,11 @@ -error[E0277]: the trait bound `Struct: std::cmp::Eq` is not satisfied +error[E0277]: the trait bound `Struct: Eq` is not satisfied --> $DIR/where-clauses-unsatisfied.rs:6:10 | LL | fn equal(a: &T, b: &T) -> bool where T : Eq { a == b } | -- required by this bound in `equal` ... LL | drop(equal(&Struct, &Struct)) - | ^^^^^ the trait `std::cmp::Eq` is not implemented for `Struct` + | ^^^^^ the trait `Eq` is not implemented for `Struct` error: aborting due to previous error diff --git a/src/test/ui/wrapping-int-combinations.rs b/src/test/ui/wrapping-int-combinations.rs deleted file mode 100644 index f0bc479ee0..0000000000 --- a/src/test/ui/wrapping-int-combinations.rs +++ /dev/null @@ -1,77 +0,0 @@ -// run-pass - -use std::num::Wrapping; - -macro_rules! wrapping_operation { - ($result:expr, $lhs:ident $op:tt $rhs:expr) => { - assert_eq!($result, $lhs $op $rhs); - assert_eq!($result, &$lhs $op $rhs); - assert_eq!($result, $lhs $op &$rhs); - assert_eq!($result, &$lhs $op &$rhs); - }; - ($result:expr, $op:tt $expr:expr) => { - assert_eq!($result, $op $expr); - assert_eq!($result, $op &$expr); - }; -} - -macro_rules! wrapping_assignment { - ($result:expr, $lhs:ident $op:tt $rhs:expr) => { - let mut lhs1 = $lhs; - lhs1 $op $rhs; - assert_eq!($result, lhs1); - - let mut lhs2 = $lhs; - lhs2 $op &$rhs; - assert_eq!($result, lhs2); - }; -} - -macro_rules! wrapping_test { - ($type:ty, $min:expr, $max:expr) => { - let zero: Wrapping<$type> = Wrapping(0); - let one: Wrapping<$type> = Wrapping(1); - let min: Wrapping<$type> = Wrapping($min); - let max: Wrapping<$type> = Wrapping($max); - - wrapping_operation!(min, max + one); - wrapping_assignment!(min, max += one); - wrapping_operation!(max, min - one); - wrapping_assignment!(max, min -= one); - wrapping_operation!(max, max * one); - wrapping_assignment!(max, max *= one); - wrapping_operation!(max, max / one); - wrapping_assignment!(max, max /= one); - wrapping_operation!(zero, max % one); - wrapping_assignment!(zero, max %= one); - wrapping_operation!(zero, zero & max); - wrapping_assignment!(zero, zero &= max); - wrapping_operation!(max, zero | max); - wrapping_assignment!(max, zero |= max); - wrapping_operation!(zero, max ^ max); - wrapping_assignment!(zero, max ^= max); - wrapping_operation!(zero, zero << 1usize); - wrapping_assignment!(zero, zero <<= 1usize); - wrapping_operation!(zero, zero >> 1usize); - wrapping_assignment!(zero, zero >>= 1usize); - wrapping_operation!(zero, -zero); - wrapping_operation!(max, !min); - }; -} - -fn main() { - wrapping_test!(i8, std::i8::MIN, std::i8::MAX); - wrapping_test!(i16, std::i16::MIN, std::i16::MAX); - wrapping_test!(i32, std::i32::MIN, std::i32::MAX); - wrapping_test!(i64, std::i64::MIN, std::i64::MAX); - #[cfg(not(target_os = "emscripten"))] - wrapping_test!(i128, std::i128::MIN, std::i128::MAX); - wrapping_test!(isize, std::isize::MIN, std::isize::MAX); - wrapping_test!(u8, std::u8::MIN, std::u8::MAX); - wrapping_test!(u16, std::u16::MIN, std::u16::MAX); - wrapping_test!(u32, std::u32::MIN, std::u32::MAX); - wrapping_test!(u64, std::u64::MIN, std::u64::MAX); - #[cfg(not(target_os = "emscripten"))] - wrapping_test!(u128, std::u128::MIN, std::u128::MAX); - wrapping_test!(usize, std::usize::MIN, std::usize::MAX); -} diff --git a/src/test/ui/write-to-static-mut-in-static.stderr b/src/test/ui/write-to-static-mut-in-static.stderr index 50dfce3448..789919bd16 100644 --- a/src/test/ui/write-to-static-mut-in-static.stderr +++ b/src/test/ui/write-to-static-mut-in-static.stderr @@ -4,23 +4,19 @@ error[E0080]: could not evaluate static initializer LL | pub static mut B: () = unsafe { A = 1; }; | ^^^^^ modifying a static's initial value from another static's initializer -error[E0391]: cycle detected when const-evaluating `C` +error[E0391]: cycle detected when const-evaluating + checking `C` --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | -note: ...which requires const-evaluating `C`... - --> $DIR/write-to-static-mut-in-static.rs:5:1 - | -LL | pub static mut C: u32 = unsafe { C = 1; 0 }; - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ - = note: ...which again requires const-evaluating `C`, completing the cycle -note: cycle used when const-evaluating + checking `C` +note: ...which requires const-evaluating + checking `C`... --> $DIR/write-to-static-mut-in-static.rs:5:1 | LL | pub static mut C: u32 = unsafe { C = 1; 0 }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = note: ...which again requires const-evaluating + checking `C`, completing the cycle + = note: cycle used when running analysis passes on this crate error: aborting due to 2 previous errors diff --git a/src/tools/build-manifest/Cargo.toml b/src/tools/build-manifest/Cargo.toml index 0bbbabd299..4a2c710811 100644 --- a/src/tools/build-manifest/Cargo.toml +++ b/src/tools/build-manifest/Cargo.toml @@ -8,3 +8,10 @@ edition = "2018" toml = "0.5" serde = { version = "1.0", features = ["derive"] } serde_json = "1.0" +anyhow = "1.0.32" +flate2 = "1.0.16" +tar = "0.4.29" +sha2 = "0.9.1" +rayon = "1.3.1" +hex = "0.4.2" +num_cpus = "1.13.0" diff --git a/src/tools/build-manifest/README.md b/src/tools/build-manifest/README.md index a80f36d496..b77c5a907c 100644 --- a/src/tools/build-manifest/README.md +++ b/src/tools/build-manifest/README.md @@ -20,11 +20,9 @@ Then, you can generate the manifest and all the packages from `path/to/dist` to `path/to/output` with: ``` -$ BUILD_MANIFEST_DISABLE_SIGNING=1 cargo +nightly run \ - path/to/dist path/to/output 1970-01-01 \ - nightly nightly nightly nightly nightly nightly nightly nightly \ - http://example.com +$ cargo +nightly run path/to/dist path/to/output 1970-01-01 http://example.com \ + CHANNEL VERSION ``` -In the future, if the tool complains about missing arguments just add more -`nightly`s in the middle. +Remember to replace `CHANNEL` with the channel you produced dist artifacts of +and `VERSION` with the current Rust version. diff --git a/src/tools/build-manifest/src/main.rs b/src/tools/build-manifest/src/main.rs index 58022484fa..cb04900c73 100644 --- a/src/tools/build-manifest/src/main.rs +++ b/src/tools/build-manifest/src/main.rs @@ -4,18 +4,26 @@ //! via `x.py dist hash-and-sign`; the cmdline arguments are set up //! by rustbuild (in `src/bootstrap/dist.rs`). -use serde::Serialize; +mod manifest; +mod versions; -use std::collections::BTreeMap; -use std::collections::HashMap; +use crate::manifest::{Component, FileHash, Manifest, Package, Rename, Target}; +use crate::versions::{PkgType, Versions}; +use rayon::prelude::*; +use sha2::Digest; +use std::collections::{BTreeMap, HashMap, HashSet}; use std::env; +use std::error::Error; use std::fs::{self, File}; -use std::io::{self, Read, Write}; +use std::io::{self, BufReader, Read, Write}; use std::path::{Path, PathBuf}; use std::process::{Command, Stdio}; +use std::sync::Mutex; +use std::time::Instant; static HOSTS: &[&str] = &[ "aarch64-unknown-linux-gnu", + "aarch64-unknown-linux-musl", "arm-unknown-linux-gnueabi", "arm-unknown-linux-gnueabihf", "armv7-unknown-linux-gnueabihf", @@ -110,6 +118,7 @@ static TARGETS: &[&str] = &[ "riscv32i-unknown-none-elf", "riscv32imc-unknown-none-elf", "riscv32imac-unknown-none-elf", + "riscv32gc-unknown-linux-gnu", "riscv64imac-unknown-none-elf", "riscv64gc-unknown-none-elf", "riscv64gc-unknown-linux-gnu", @@ -163,57 +172,6 @@ static MINGW: &[&str] = &["i686-pc-windows-gnu", "x86_64-pc-windows-gnu"]; static NIGHTLY_ONLY_COMPONENTS: &[&str] = &["miri-preview", "rust-analyzer-preview"]; -#[derive(Serialize)] -#[serde(rename_all = "kebab-case")] -struct Manifest { - manifest_version: String, - date: String, - pkg: BTreeMap, - renames: BTreeMap, - profiles: BTreeMap>, -} - -#[derive(Serialize)] -struct Package { - version: String, - git_commit_hash: Option, - target: BTreeMap, -} - -#[derive(Serialize)] -struct Rename { - to: String, -} - -#[derive(Serialize, Default)] -struct Target { - available: bool, - url: Option, - hash: Option, - xz_url: Option, - xz_hash: Option, - components: Option>, - extensions: Option>, -} - -impl Target { - fn unavailable() -> Self { - Self::default() - } -} - -#[derive(Serialize)] -struct Component { - pkg: String, - target: String, -} - -impl Component { - fn from_str(pkg: &str, target: &str) -> Self { - Self { pkg: pkg.to_string(), target: target.to_string() } - } -} - macro_rules! t { ($e:expr) => { match $e { @@ -224,175 +182,89 @@ macro_rules! t { } struct Builder { - rust_release: String, - cargo_release: String, - rls_release: String, - rust_analyzer_release: String, - clippy_release: String, - rustfmt_release: String, - llvm_tools_release: String, - miri_release: String, + versions: Versions, input: PathBuf, output: PathBuf, - gpg_passphrase: String, - digests: BTreeMap, s3_address: String, date: String, - rust_version: Option, - cargo_version: Option, - rls_version: Option, - rust_analyzer_version: Option, - clippy_version: Option, - rustfmt_version: Option, - llvm_tools_version: Option, - miri_version: Option, - - rust_git_commit_hash: Option, - cargo_git_commit_hash: Option, - rls_git_commit_hash: Option, - rust_analyzer_git_commit_hash: Option, - clippy_git_commit_hash: Option, - rustfmt_git_commit_hash: Option, - llvm_tools_git_commit_hash: Option, - miri_git_commit_hash: Option, - - should_sign: bool, + legacy: bool, + legacy_gpg_passphrase: String, } fn main() { - // Avoid signing packages while manually testing - // Do NOT set this envvar in CI - let should_sign = env::var("BUILD_MANIFEST_DISABLE_SIGNING").is_err(); + // Up until Rust 1.48 the release process relied on build-manifest to create the SHA256 + // checksums of released files and to sign the tarballs. That was moved over to promote-release + // in time for the branching of Rust 1.48, but the old release process still had to work the + // old way. + // + // When running build-manifest through the old ./x.py dist hash-and-sign the environment + // variable will be set, enabling the legacy behavior of generating the .sha256 files and + // signing the tarballs. + // + // Once the old release process is fully decommissioned, the environment variable, all the + // related code in this tool and ./x.py dist hash-and-sign can be removed. + let legacy = env::var_os("BUILD_MANIFEST_LEGACY").is_some(); - // Safety check to ensure signing is always enabled on CI - // The CI environment variable is set by both Travis and AppVeyor - if !should_sign && env::var("CI").is_ok() { - println!("The 'BUILD_MANIFEST_DISABLE_SIGNING' env var can't be enabled on CI."); - println!("If you're not running this on CI, unset the 'CI' env var."); - panic!(); - } + let num_threads = if legacy { + // Avoid overloading the old server in legacy mode. + 1 + } else if let Some(num) = env::var_os("BUILD_MANIFEST_NUM_THREADS") { + num.to_str().unwrap().parse().expect("invalid number for BUILD_MANIFEST_NUM_THREADS") + } else { + num_cpus::get() + }; + rayon::ThreadPoolBuilder::new() + .num_threads(num_threads) + .build_global() + .expect("failed to initialize Rayon"); let mut args = env::args().skip(1); let input = PathBuf::from(args.next().unwrap()); let output = PathBuf::from(args.next().unwrap()); let date = args.next().unwrap(); - let rust_release = args.next().unwrap(); let s3_address = args.next().unwrap(); - let cargo_release = args.next().unwrap(); - let rls_release = args.next().unwrap(); - let rust_analyzer_release = args.next().unwrap(); - let clippy_release = args.next().unwrap(); - let miri_release = args.next().unwrap(); - let rustfmt_release = args.next().unwrap(); - let llvm_tools_release = args.next().unwrap(); + let channel = args.next().unwrap(); // Do not ask for a passphrase while manually testing let mut passphrase = String::new(); - if should_sign { + if legacy { // `x.py` passes the passphrase via stdin. t!(io::stdin().read_to_string(&mut passphrase)); } Builder { - rust_release, - cargo_release, - rls_release, - rust_analyzer_release, - clippy_release, - rustfmt_release, - llvm_tools_release, - miri_release, + versions: Versions::new(&channel, &input).unwrap(), input, output, - gpg_passphrase: passphrase, - digests: BTreeMap::new(), s3_address, date, - rust_version: None, - cargo_version: None, - rls_version: None, - rust_analyzer_version: None, - clippy_version: None, - rustfmt_version: None, - llvm_tools_version: None, - miri_version: None, - - rust_git_commit_hash: None, - cargo_git_commit_hash: None, - rls_git_commit_hash: None, - rust_analyzer_git_commit_hash: None, - clippy_git_commit_hash: None, - rustfmt_git_commit_hash: None, - llvm_tools_git_commit_hash: None, - miri_git_commit_hash: None, - - should_sign, + legacy, + legacy_gpg_passphrase: passphrase, } .build(); } -enum PkgType { - RustSrc, - Cargo, - Rls, - RustAnalyzer, - Clippy, - Rustfmt, - LlvmTools, - Miri, - Other, -} - -impl PkgType { - fn from_component(component: &str) -> Self { - use PkgType::*; - match component { - "rust-src" => RustSrc, - "cargo" => Cargo, - "rls" | "rls-preview" => Rls, - "rust-analyzer" | "rust-analyzer-preview" => RustAnalyzer, - "clippy" | "clippy-preview" => Clippy, - "rustfmt" | "rustfmt-preview" => Rustfmt, - "llvm-tools" | "llvm-tools-preview" => LlvmTools, - "miri" | "miri-preview" => Miri, - _ => Other, - } - } -} - impl Builder { fn build(&mut self) { - self.rust_version = self.version("rust", "x86_64-unknown-linux-gnu"); - self.cargo_version = self.version("cargo", "x86_64-unknown-linux-gnu"); - self.rls_version = self.version("rls", "x86_64-unknown-linux-gnu"); - self.rust_analyzer_version = self.version("rust-analyzer", "x86_64-unknown-linux-gnu"); - self.clippy_version = self.version("clippy", "x86_64-unknown-linux-gnu"); - self.rustfmt_version = self.version("rustfmt", "x86_64-unknown-linux-gnu"); - self.llvm_tools_version = self.version("llvm-tools", "x86_64-unknown-linux-gnu"); - self.miri_version = self.version("miri", "x86_64-unknown-linux-gnu"); - - self.rust_git_commit_hash = self.git_commit_hash("rust", "x86_64-unknown-linux-gnu"); - self.cargo_git_commit_hash = self.git_commit_hash("cargo", "x86_64-unknown-linux-gnu"); - self.rls_git_commit_hash = self.git_commit_hash("rls", "x86_64-unknown-linux-gnu"); - self.rust_analyzer_git_commit_hash = - self.git_commit_hash("rust-analyzer", "x86_64-unknown-linux-gnu"); - self.clippy_git_commit_hash = self.git_commit_hash("clippy", "x86_64-unknown-linux-gnu"); - self.rustfmt_git_commit_hash = self.git_commit_hash("rustfmt", "x86_64-unknown-linux-gnu"); - self.llvm_tools_git_commit_hash = - self.git_commit_hash("llvm-tools", "x86_64-unknown-linux-gnu"); - self.miri_git_commit_hash = self.git_commit_hash("miri", "x86_64-unknown-linux-gnu"); - self.check_toolstate(); - self.digest_and_sign(); + if self.legacy { + self.digest_and_sign(); + } let manifest = self.build_manifest(); - self.write_channel_files(&self.rust_release, &manifest); - if self.rust_release != "beta" && self.rust_release != "nightly" { - self.write_channel_files("stable", &manifest); + self.write_channel_files(self.versions.channel(), &manifest); + if self.versions.channel() == "stable" { + // channel-rust-1.XX.YY.toml + let rust_version = self.versions.rustc_version(); + self.write_channel_files(rust_version, &manifest); + + // channel-rust-1.XX.toml + let major_minor = rust_version.split('.').take(2).collect::>().join("."); + self.write_channel_files(&major_minor, &manifest); } } @@ -413,18 +285,16 @@ impl Builder { // Mark some tools as missing based on toolstate. if toolstates.get("miri").map(|s| &*s as &str) != Some("test-pass") { println!("Miri tests are not passing, removing component"); - self.miri_version = None; - self.miri_git_commit_hash = None; + self.versions.disable_version(&PkgType::Miri); } } /// Hash all files, compute their signatures, and collect the hashes in `self.digests`. fn digest_and_sign(&mut self) { for file in t!(self.input.read_dir()).map(|e| t!(e).path()) { - let filename = file.file_name().unwrap().to_str().unwrap(); - let digest = self.hash(&file); + file.file_name().unwrap().to_str().unwrap(); + self.hash(&file); self.sign(&file); - assert!(self.digests.insert(filename.to_string(), digest).is_none()); } } @@ -440,6 +310,9 @@ impl Builder { self.add_profiles_to(&mut manifest); self.add_renames_to(&mut manifest); manifest.pkg.insert("rust".to_string(), self.rust_package(&manifest)); + + self.fill_missing_hashes(&mut manifest); + manifest } @@ -499,7 +372,7 @@ impl Builder { // The compiler libraries are not stable for end users, and they're also huge, so we only // `rustc-dev` for nightly users, and only in the "complete" profile. It's still possible // for users to install the additional component manually, if needed. - if self.rust_release == "nightly" { + if self.versions.channel() == "nightly" { self.extend_profile("complete", &mut manifest.profiles, &["rustc-dev"]); self.extend_profile("complete", &mut manifest.profiles, &["rustc-docs"]); } @@ -516,13 +389,10 @@ impl Builder { } fn rust_package(&mut self, manifest: &Manifest) -> Package { + let version_info = self.versions.version(&PkgType::Rust).expect("missing Rust tarball"); let mut pkg = Package { - version: self - .cached_version("rust") - .as_ref() - .expect("Couldn't find Rust version") - .clone(), - git_commit_hash: self.cached_git_commit_hash("rust").clone(), + version: version_info.version.expect("missing Rust version"), + git_commit_hash: version_info.git_commit, target: BTreeMap::new(), }; for host in HOSTS { @@ -537,10 +407,13 @@ impl Builder { } fn target_host_combination(&mut self, host: &str, manifest: &Manifest) -> Option { - let filename = self.filename("rust", host); - let digest = self.digests.remove(&filename)?; - let xz_filename = filename.replace(".tar.gz", ".tar.xz"); - let xz_digest = self.digests.remove(&xz_filename); + let filename = self.versions.tarball_name(&PkgType::Rust, host).unwrap(); + + let mut target = Target::from_compressed_tar(self, &filename); + if !target.available { + return None; + } + let mut components = Vec::new(); let mut extensions = Vec::new(); @@ -596,15 +469,9 @@ impl Builder { extensions.retain(&has_component); components.retain(&has_component); - Some(Target { - available: true, - url: Some(self.url(&filename)), - hash: Some(digest), - xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)), - xz_hash: xz_digest, - components: Some(components), - extensions: Some(extensions), - }) + target.components = Some(components); + target.extensions = Some(extensions); + Some(target) } fn profile( @@ -628,135 +495,49 @@ impl Builder { } fn package(&mut self, pkgname: &str, dst: &mut BTreeMap, targets: &[&str]) { - let (version, mut is_present) = self - .cached_version(pkgname) - .as_ref() - .cloned() - .map(|version| (version, true)) - .unwrap_or_default(); // `is_present` defaults to `false` here. + let version_info = self + .versions + .version(&PkgType::from_component(pkgname)) + .expect("failed to load package version"); + let mut is_present = version_info.present; // Never ship nightly-only components for other trains. - if self.rust_release != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) { + if self.versions.channel() != "nightly" && NIGHTLY_ONLY_COMPONENTS.contains(&pkgname) { is_present = false; // Pretend the component is entirely missing. } let targets = targets .iter() .map(|name| { - if is_present { - // The component generally exists, but it might still be missing for this target. - let filename = self.filename(pkgname, name); - let digest = match self.digests.remove(&filename) { - Some(digest) => digest, - // This component does not exist for this target -- skip it. - None => return (name.to_string(), Target::unavailable()), - }; - let xz_filename = filename.replace(".tar.gz", ".tar.xz"); - let xz_digest = self.digests.remove(&xz_filename); + let target = if is_present { + let filename = self + .versions + .tarball_name(&PkgType::from_component(pkgname), name) + .unwrap(); - ( - name.to_string(), - Target { - available: true, - url: Some(self.url(&filename)), - hash: Some(digest), - xz_url: xz_digest.as_ref().map(|_| self.url(&xz_filename)), - xz_hash: xz_digest, - components: None, - extensions: None, - }, - ) + Target::from_compressed_tar(self, &filename) } else { // If the component is not present for this build add it anyway but mark it as // unavailable -- this way rustup won't allow upgrades without --force - (name.to_string(), Target::unavailable()) - } + Target::unavailable() + }; + (name.to_string(), target) }) .collect(); dst.insert( pkgname.to_string(), Package { - version, - git_commit_hash: self.cached_git_commit_hash(pkgname).clone(), + version: version_info.version.unwrap_or_default(), + git_commit_hash: version_info.git_commit, target: targets, }, ); } - fn url(&self, filename: &str) -> String { - format!("{}/{}/{}", self.s3_address, self.date, filename) - } - - fn filename(&self, component: &str, target: &str) -> String { - use PkgType::*; - match PkgType::from_component(component) { - RustSrc => format!("rust-src-{}.tar.gz", self.rust_release), - Cargo => format!("cargo-{}-{}.tar.gz", self.cargo_release, target), - Rls => format!("rls-{}-{}.tar.gz", self.rls_release, target), - RustAnalyzer => { - format!("rust-analyzer-{}-{}.tar.gz", self.rust_analyzer_release, target) - } - Clippy => format!("clippy-{}-{}.tar.gz", self.clippy_release, target), - Rustfmt => format!("rustfmt-{}-{}.tar.gz", self.rustfmt_release, target), - LlvmTools => format!("llvm-tools-{}-{}.tar.gz", self.llvm_tools_release, target), - Miri => format!("miri-{}-{}.tar.gz", self.miri_release, target), - Other => format!("{}-{}-{}.tar.gz", component, self.rust_release, target), - } - } - - fn cached_version(&self, component: &str) -> &Option { - use PkgType::*; - match PkgType::from_component(component) { - Cargo => &self.cargo_version, - Rls => &self.rls_version, - RustAnalyzer => &self.rust_analyzer_version, - Clippy => &self.clippy_version, - Rustfmt => &self.rustfmt_version, - LlvmTools => &self.llvm_tools_version, - Miri => &self.miri_version, - _ => &self.rust_version, - } - } - - fn cached_git_commit_hash(&self, component: &str) -> &Option { - use PkgType::*; - match PkgType::from_component(component) { - Cargo => &self.cargo_git_commit_hash, - Rls => &self.rls_git_commit_hash, - RustAnalyzer => &self.rust_analyzer_git_commit_hash, - Clippy => &self.clippy_git_commit_hash, - Rustfmt => &self.rustfmt_git_commit_hash, - LlvmTools => &self.llvm_tools_git_commit_hash, - Miri => &self.miri_git_commit_hash, - _ => &self.rust_git_commit_hash, - } - } - - fn version(&self, component: &str, target: &str) -> Option { - self.untar(component, target, |filename| format!("{}/version", filename)) - } - - fn git_commit_hash(&self, component: &str, target: &str) -> Option { - self.untar(component, target, |filename| format!("{}/git-commit-hash", filename)) - } - - fn untar(&self, component: &str, target: &str, dir: F) -> Option - where - F: FnOnce(String) -> String, - { - let mut cmd = Command::new("tar"); - let filename = self.filename(component, target); - cmd.arg("xf") - .arg(self.input.join(&filename)) - .arg(dir(filename.replace(".tar.gz", ""))) - .arg("-O"); - let output = t!(cmd.output()); - if output.status.success() { - Some(String::from_utf8_lossy(&output.stdout).trim().to_string()) - } else { - None - } + fn url(&self, path: &Path) -> String { + let file_name = path.file_name().unwrap().to_str().unwrap(); + format!("{}/{}/{}", self.s3_address, self.date, file_name) } fn hash(&self, path: &Path) -> String { @@ -777,7 +558,7 @@ impl Builder { } fn sign(&self, path: &Path) { - if !self.should_sign { + if !self.legacy { return; } @@ -800,10 +581,45 @@ impl Builder { .arg(path) .stdin(Stdio::piped()); let mut child = t!(cmd.spawn()); - t!(child.stdin.take().unwrap().write_all(self.gpg_passphrase.as_bytes())); + t!(child.stdin.take().unwrap().write_all(self.legacy_gpg_passphrase.as_bytes())); assert!(t!(child.wait()).success()); } + fn fill_missing_hashes(&self, manifest: &mut Manifest) { + // First collect all files that need hashes + let mut need_hashes = HashSet::new(); + crate::manifest::visit_file_hashes(manifest, |file_hash| { + if let FileHash::Missing(path) = file_hash { + need_hashes.insert(path.clone()); + } + }); + + let collected = Mutex::new(HashMap::new()); + let collection_start = Instant::now(); + println!( + "collecting hashes for {} tarballs across {} threads", + need_hashes.len(), + rayon::current_num_threads().min(need_hashes.len()), + ); + need_hashes.par_iter().for_each(|path| match fetch_hash(path) { + Ok(hash) => { + collected.lock().unwrap().insert(path, hash); + } + Err(err) => eprintln!("error while fetching the hash for {}: {}", path.display(), err), + }); + let collected = collected.into_inner().unwrap(); + println!("collected {} hashes in {:.2?}", collected.len(), collection_start.elapsed()); + + crate::manifest::visit_file_hashes(manifest, |file_hash| { + if let FileHash::Missing(path) = file_hash { + match collected.get(path) { + Some(hash) => *file_hash = FileHash::Present(hash.clone()), + None => panic!("missing hash for file {}", path.display()), + } + } + }) + } + fn write_channel_files(&self, channel_name: &str, manifest: &Manifest) { self.write(&toml::to_string(&manifest).unwrap(), channel_name, ".toml"); self.write(&manifest.date, channel_name, "-date.txt"); @@ -817,7 +633,16 @@ impl Builder { fn write(&self, contents: &str, channel_name: &str, suffix: &str) { let dst = self.output.join(format!("channel-rust-{}{}", channel_name, suffix)); t!(fs::write(&dst, contents)); - self.hash(&dst); - self.sign(&dst); + if self.legacy { + self.hash(&dst); + self.sign(&dst); + } } } + +fn fetch_hash(path: &Path) -> Result> { + let mut file = BufReader::new(File::open(path)?); + let mut sha256 = sha2::Sha256::default(); + std::io::copy(&mut file, &mut sha256)?; + Ok(hex::encode(sha256.finalize())) +} diff --git a/src/tools/build-manifest/src/manifest.rs b/src/tools/build-manifest/src/manifest.rs new file mode 100644 index 0000000000..20e62abb54 --- /dev/null +++ b/src/tools/build-manifest/src/manifest.rs @@ -0,0 +1,114 @@ +use crate::Builder; +use serde::{Serialize, Serializer}; +use std::collections::BTreeMap; +use std::path::{Path, PathBuf}; + +#[derive(Serialize)] +#[serde(rename_all = "kebab-case")] +pub(crate) struct Manifest { + pub(crate) manifest_version: String, + pub(crate) date: String, + pub(crate) pkg: BTreeMap, + pub(crate) renames: BTreeMap, + pub(crate) profiles: BTreeMap>, +} + +#[derive(Serialize)] +pub(crate) struct Package { + pub(crate) version: String, + pub(crate) git_commit_hash: Option, + pub(crate) target: BTreeMap, +} + +#[derive(Serialize)] +pub(crate) struct Rename { + pub(crate) to: String, +} + +#[derive(Serialize, Default)] +pub(crate) struct Target { + pub(crate) available: bool, + pub(crate) url: Option, + pub(crate) hash: Option, + pub(crate) xz_url: Option, + pub(crate) xz_hash: Option, + pub(crate) components: Option>, + pub(crate) extensions: Option>, +} + +impl Target { + pub(crate) fn from_compressed_tar(builder: &Builder, base_path: &str) -> Self { + let base_path = builder.input.join(base_path); + let gz = Self::tarball_variant(&base_path, "gz"); + let xz = Self::tarball_variant(&base_path, "xz"); + + if gz.is_none() { + return Self::unavailable(); + } + + Self { + available: true, + components: None, + extensions: None, + // .gz + url: gz.as_ref().map(|path| builder.url(path)), + hash: gz.map(FileHash::Missing), + // .xz + xz_url: xz.as_ref().map(|path| builder.url(path)), + xz_hash: xz.map(FileHash::Missing), + } + } + + fn tarball_variant(base: &Path, ext: &str) -> Option { + let mut path = base.to_path_buf(); + path.set_extension(ext); + if path.is_file() { Some(path) } else { None } + } + + pub(crate) fn unavailable() -> Self { + Self::default() + } +} + +#[derive(Serialize)] +pub(crate) struct Component { + pub(crate) pkg: String, + pub(crate) target: String, +} + +impl Component { + pub(crate) fn from_str(pkg: &str, target: &str) -> Self { + Self { pkg: pkg.to_string(), target: target.to_string() } + } +} + +#[allow(unused)] +pub(crate) enum FileHash { + Missing(PathBuf), + Present(String), +} + +impl Serialize for FileHash { + fn serialize(&self, serializer: S) -> Result { + match self { + FileHash::Missing(path) => Err(serde::ser::Error::custom(format!( + "can't serialize a missing hash for file {}", + path.display() + ))), + FileHash::Present(inner) => inner.serialize(serializer), + } + } +} + +pub(crate) fn visit_file_hashes(manifest: &mut Manifest, mut f: impl FnMut(&mut FileHash)) { + for pkg in manifest.pkg.values_mut() { + for target in pkg.target.values_mut() { + if let Some(hash) = &mut target.hash { + f(hash); + } + if let Some(hash) = &mut target.xz_hash { + f(hash); + } + } + } +} diff --git a/src/tools/build-manifest/src/versions.rs b/src/tools/build-manifest/src/versions.rs new file mode 100644 index 0000000000..79f2ef8dfc --- /dev/null +++ b/src/tools/build-manifest/src/versions.rs @@ -0,0 +1,191 @@ +use anyhow::Error; +use flate2::read::GzDecoder; +use std::collections::HashMap; +use std::fs::File; +use std::io::Read; +use std::path::{Path, PathBuf}; +use tar::Archive; + +const DEFAULT_TARGET: &str = "x86_64-unknown-linux-gnu"; +const RUSTC_VERSION: &str = include_str!("../../../version"); + +#[derive(Debug, Hash, Eq, PartialEq, Clone)] +pub(crate) enum PkgType { + Rust, + RustSrc, + Cargo, + Rls, + RustAnalyzer, + Clippy, + Rustfmt, + LlvmTools, + Miri, + Other(String), +} + +impl PkgType { + pub(crate) fn from_component(component: &str) -> Self { + match component { + "rust" => PkgType::Rust, + "rust-src" => PkgType::RustSrc, + "cargo" => PkgType::Cargo, + "rls" | "rls-preview" => PkgType::Rls, + "rust-analyzer" | "rust-analyzer-preview" => PkgType::RustAnalyzer, + "clippy" | "clippy-preview" => PkgType::Clippy, + "rustfmt" | "rustfmt-preview" => PkgType::Rustfmt, + "llvm-tools" | "llvm-tools-preview" => PkgType::LlvmTools, + "miri" | "miri-preview" => PkgType::Miri, + other => PkgType::Other(other.into()), + } + } + + /// First part of the tarball name. + fn tarball_component_name(&self) -> &str { + match self { + PkgType::Rust => "rust", + PkgType::RustSrc => "rust-src", + PkgType::Cargo => "cargo", + PkgType::Rls => "rls", + PkgType::RustAnalyzer => "rust-analyzer", + PkgType::Clippy => "clippy", + PkgType::Rustfmt => "rustfmt", + PkgType::LlvmTools => "llvm-tools", + PkgType::Miri => "miri", + PkgType::Other(component) => component, + } + } + + /// Whether this package has the same version as Rust itself, or has its own `version` and + /// `git-commit-hash` files inside the tarball. + fn should_use_rust_version(&self) -> bool { + match self { + PkgType::Cargo => false, + PkgType::Rls => false, + PkgType::RustAnalyzer => false, + PkgType::Clippy => false, + PkgType::Rustfmt => false, + PkgType::LlvmTools => false, + PkgType::Miri => false, + + PkgType::Rust => true, + PkgType::RustSrc => true, + PkgType::Other(_) => true, + } + } + + /// Whether this package is target-independent or not. + fn target_independent(&self) -> bool { + *self == PkgType::RustSrc + } +} + +#[derive(Debug, Default, Clone)] +pub(crate) struct VersionInfo { + pub(crate) version: Option, + pub(crate) git_commit: Option, + pub(crate) present: bool, +} + +pub(crate) struct Versions { + channel: String, + dist_path: PathBuf, + versions: HashMap, +} + +impl Versions { + pub(crate) fn new(channel: &str, dist_path: &Path) -> Result { + Ok(Self { channel: channel.into(), dist_path: dist_path.into(), versions: HashMap::new() }) + } + + pub(crate) fn channel(&self) -> &str { + &self.channel + } + + pub(crate) fn version(&mut self, mut package: &PkgType) -> Result { + if package.should_use_rust_version() { + package = &PkgType::Rust; + } + + match self.versions.get(package) { + Some(version) => Ok(version.clone()), + None => { + let version_info = self.load_version_from_tarball(package)?; + self.versions.insert(package.clone(), version_info.clone()); + Ok(version_info) + } + } + } + + fn load_version_from_tarball(&mut self, package: &PkgType) -> Result { + let tarball_name = self.tarball_name(package, DEFAULT_TARGET)?; + let tarball = self.dist_path.join(tarball_name); + + let file = match File::open(&tarball) { + Ok(file) => file, + Err(err) if err.kind() == std::io::ErrorKind::NotFound => { + // Missing tarballs do not return an error, but return empty data. + return Ok(VersionInfo::default()); + } + Err(err) => return Err(err.into()), + }; + let mut tar = Archive::new(GzDecoder::new(file)); + + let mut version = None; + let mut git_commit = None; + for entry in tar.entries()? { + let mut entry = entry?; + + let dest; + match entry.path()?.components().nth(1).and_then(|c| c.as_os_str().to_str()) { + Some("version") => dest = &mut version, + Some("git-commit-hash") => dest = &mut git_commit, + _ => continue, + } + let mut buf = String::new(); + entry.read_to_string(&mut buf)?; + *dest = Some(buf); + + // Short circuit to avoid reading the whole tar file if not necessary. + if version.is_some() && git_commit.is_some() { + break; + } + } + + Ok(VersionInfo { version, git_commit, present: true }) + } + + pub(crate) fn disable_version(&mut self, package: &PkgType) { + match self.versions.get_mut(package) { + Some(version) => { + *version = VersionInfo::default(); + } + None => { + self.versions.insert(package.clone(), VersionInfo::default()); + } + } + } + + pub(crate) fn tarball_name( + &mut self, + package: &PkgType, + target: &str, + ) -> Result { + let component_name = package.tarball_component_name(); + let version = match self.channel.as_str() { + "stable" => RUSTC_VERSION.into(), + "beta" => "beta".into(), + "nightly" => "nightly".into(), + _ => format!("{}-dev", RUSTC_VERSION), + }; + + if package.target_independent() { + Ok(format!("{}-{}.tar.gz", component_name, version)) + } else { + Ok(format!("{}-{}-{}.tar.gz", component_name, version, target)) + } + } + + pub(crate) fn rustc_version(&self) -> &str { + RUSTC_VERSION + } +} diff --git a/src/tools/cargotest/main.rs b/src/tools/cargotest/main.rs index 0f56dbba1d..8aabe077cf 100644 --- a/src/tools/cargotest/main.rs +++ b/src/tools/cargotest/main.rs @@ -22,21 +22,14 @@ const TEST_REPOS: &[Test] = &[ Test { name: "ripgrep", repo: "https://github.com/BurntSushi/ripgrep", - sha: "ad9befbc1d3b5c695e7f6b6734ee1b8e683edd41", + sha: "3de31f752729525d85a3d1575ac1978733b3f7e7", lock: None, packages: &[], }, Test { name: "tokei", repo: "https://github.com/XAMPPRocky/tokei", - sha: "5e11c4852fe4aa086b0e4fe5885822fbe57ba928", - lock: None, - packages: &[], - }, - Test { - name: "treeify", - repo: "https://github.com/dzamlo/treeify", - sha: "999001b223152441198f117a68fb81f57bc086dd", + sha: "fdf3f8cb279a7aeac0696c87e5d8b0cd946e4f9e", lock: None, packages: &[], }, diff --git a/src/tools/compiletest/src/common.rs b/src/tools/compiletest/src/common.rs index 848bd3a43e..2f832b53a9 100644 --- a/src/tools/compiletest/src/common.rs +++ b/src/tools/compiletest/src/common.rs @@ -261,6 +261,9 @@ pub struct Config { /// Path to / name of the Microsoft Console Debugger (CDB) executable pub cdb: Option, + /// Version of CDB + pub cdb_version: Option<[u16; 4]>, + /// Path to / name of the GDB executable pub gdb: Option, diff --git a/src/tools/compiletest/src/header.rs b/src/tools/compiletest/src/header.rs index 0efa668ecc..59f64e7df0 100644 --- a/src/tools/compiletest/src/header.rs +++ b/src/tools/compiletest/src/header.rs @@ -8,8 +8,8 @@ use std::path::{Path, PathBuf}; use tracing::*; use crate::common::{CompareMode, Config, Debugger, FailMode, Mode, PassMode}; -use crate::extract_gdb_version; use crate::util; +use crate::{extract_cdb_version, extract_gdb_version}; #[cfg(test)] mod tests; @@ -105,6 +105,10 @@ impl EarlyProps { props.ignore = true; } + if config.debugger == Some(Debugger::Cdb) && ignore_cdb(config, ln) { + props.ignore = true; + } + if config.debugger == Some(Debugger::Gdb) && ignore_gdb(config, ln) { props.ignore = true; } @@ -131,6 +135,21 @@ impl EarlyProps { return props; + fn ignore_cdb(config: &Config, line: &str) -> bool { + if let Some(actual_version) = config.cdb_version { + if let Some(min_version) = line.strip_prefix("min-cdb-version:").map(str::trim) { + let min_version = extract_cdb_version(min_version).unwrap_or_else(|| { + panic!("couldn't parse version range: {:?}", min_version); + }); + + // Ignore if actual version is smaller than the minimum + // required version + return actual_version < min_version; + } + } + false + } + fn ignore_gdb(config: &Config, line: &str) -> bool { if let Some(actual_version) = config.gdb_version { if let Some(rest) = line.strip_prefix("min-gdb-version:").map(str::trim) { @@ -142,8 +161,8 @@ impl EarlyProps { if start_ver != end_ver { panic!("Expected single GDB version") } - // Ignore if actual version is smaller the minimum required - // version + // Ignore if actual version is smaller than the minimum + // required version return actual_version < start_ver; } else if let Some(rest) = line.strip_prefix("ignore-gdb-version:").map(str::trim) { let (min_version, max_version) = @@ -189,10 +208,13 @@ impl EarlyProps { config.parse_name_value_directive(line, "needs-llvm-components") { let components: HashSet<_> = config.llvm_components.split_whitespace().collect(); - if !needed_components + if let Some(missing_component) = needed_components .split_whitespace() - .all(|needed_component| components.contains(needed_component)) + .find(|needed_component| !components.contains(needed_component)) { + if env::var_os("COMPILETEST_NEEDS_ALL_LLVM_COMPONENTS").is_some() { + panic!("missing LLVM component: {}", missing_component); + } return true; } } diff --git a/src/tools/compiletest/src/main.rs b/src/tools/compiletest/src/main.rs index adf2fa7fd8..190a9c6221 100644 --- a/src/tools/compiletest/src/main.rs +++ b/src/tools/compiletest/src/main.rs @@ -163,7 +163,7 @@ pub fn parse_config(args: Vec) -> Config { let target = opt_str2(matches.opt_str("target")); let android_cross_path = opt_path(matches, "android-cross-path"); - let cdb = analyze_cdb(matches.opt_str("cdb"), &target); + let (cdb, cdb_version) = analyze_cdb(matches.opt_str("cdb"), &target); let (gdb, gdb_version, gdb_native_rust) = analyze_gdb(matches.opt_str("gdb"), &target, &android_cross_path); let (lldb_version, lldb_native_rust) = matches @@ -216,6 +216,7 @@ pub fn parse_config(args: Vec) -> Config { target, host: opt_str2(matches.opt_str("host")), cdb, + cdb_version, gdb, gdb_version, gdb_native_rust, @@ -773,8 +774,30 @@ fn find_cdb(target: &str) -> Option { } /// Returns Path to CDB -fn analyze_cdb(cdb: Option, target: &str) -> Option { - cdb.map(OsString::from).or_else(|| find_cdb(target)) +fn analyze_cdb(cdb: Option, target: &str) -> (Option, Option<[u16; 4]>) { + let cdb = cdb.map(OsString::from).or_else(|| find_cdb(target)); + + let mut version = None; + if let Some(cdb) = cdb.as_ref() { + if let Ok(output) = Command::new(cdb).arg("/version").output() { + if let Some(first_line) = String::from_utf8_lossy(&output.stdout).lines().next() { + version = extract_cdb_version(&first_line); + } + } + } + + (cdb, version) +} + +fn extract_cdb_version(full_version_line: &str) -> Option<[u16; 4]> { + // Example full_version_line: "cdb version 10.0.18362.1" + let version = full_version_line.rsplit(' ').next()?; + let mut components = version.split('.'); + let major: u16 = components.next().unwrap().parse().unwrap(); + let minor: u16 = components.next().unwrap().parse().unwrap(); + let patch: u16 = components.next().unwrap_or("0").parse().unwrap(); + let build: u16 = components.next().unwrap_or("0").parse().unwrap(); + Some([major, minor, patch, build]) } /// Returns (Path to GDB, GDB Version, GDB has Rust Support) diff --git a/src/tools/compiletest/src/runtest.rs b/src/tools/compiletest/src/runtest.rs index 124a9adcab..acad316d80 100644 --- a/src/tools/compiletest/src/runtest.rs +++ b/src/tools/compiletest/src/runtest.rs @@ -2782,6 +2782,18 @@ impl<'test> TestCx<'test> { cmd.env("RUSTFLAGS", "-Ctarget-feature=-crt-static").env("IS_MUSL_HOST", "1"); } + if self.config.bless { + cmd.env("RUSTC_BLESS_TEST", "--bless"); + // Assume this option is active if the environment variable is "defined", with _any_ value. + // As an example, a `Makefile` can use this option by: + // + // ifdef RUSTC_BLESS_TEST + // cp "$(TMPDIR)"/actual_something.ext expected_something.ext + // else + // $(DIFF) expected_something.ext "$(TMPDIR)"/actual_something.ext + // endif + } + if self.config.target.contains("msvc") && self.config.cc != "" { // We need to pass a path to `lib.exe`, so assume that `cc` is `cl.exe` // and that `lib.exe` lives next to it. @@ -3144,12 +3156,12 @@ impl<'test> TestCx<'test> { if self.config.bless { for e in - glob(&format!("{}/{}.*.mir{}", test_dir.display(), test_crate, bit_width)).unwrap() + glob(&format!("{}/{}.*{}.mir", test_dir.display(), test_crate, bit_width)).unwrap() { std::fs::remove_file(e.unwrap()).unwrap(); } for e in - glob(&format!("{}/{}.*.diff{}", test_dir.display(), test_crate, bit_width)).unwrap() + glob(&format!("{}/{}.*{}.diff", test_dir.display(), test_crate, bit_width)).unwrap() { std::fs::remove_file(e.unwrap()).unwrap(); } @@ -3169,7 +3181,7 @@ impl<'test> TestCx<'test> { let trimmed = test_name.trim_end_matches(".diff"); let test_against = format!("{}.after.mir", trimmed); from_file = format!("{}.before.mir", trimmed); - expected_file = format!("{}{}", test_name, bit_width); + expected_file = format!("{}{}.diff", trimmed, bit_width); assert!( test_names.next().is_none(), "two mir pass names specified for MIR diff" @@ -3187,7 +3199,8 @@ impl<'test> TestCx<'test> { from_file = format!("{}.{}.mir", test_name, first_pass); to_file = Some(second_file); } else { - expected_file = format!("{}{}", test_name, bit_width); + expected_file = + format!("{}{}.mir", test_name.trim_end_matches(".mir"), bit_width); from_file = test_name.to_string(); assert!( test_names.next().is_none(), diff --git a/src/tools/error_index_generator/build.rs b/src/tools/error_index_generator/build.rs index efa4177d1d..caae8c6117 100644 --- a/src/tools/error_index_generator/build.rs +++ b/src/tools/error_index_generator/build.rs @@ -9,7 +9,7 @@ fn main() { let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap()); let dest = out_dir.join("error_codes.rs"); - let error_codes_path = "../../../src/librustc_error_codes/error_codes.rs"; + let error_codes_path = "../../../compiler/rustc_error_codes/src/error_codes.rs"; println!("cargo:rerun-if-changed={}", error_codes_path); let file = fs::read_to_string(error_codes_path) @@ -19,7 +19,7 @@ fn main() { fs::write(&out_dir.join("all_error_codes.rs"), &contents).unwrap(); // We copy the md files as well to the target directory. - for entry in WalkDir::new("../../../src/librustc_error_codes/error_codes") { + for entry in WalkDir::new("../../../compiler/rustc_error_codes/src/error_codes") { let entry = entry.unwrap(); match entry.path().extension() { Some(s) if s == "md" => {} diff --git a/src/tools/linkchecker/main.rs b/src/tools/linkchecker/main.rs index d83fd7b292..4fe493a850 100644 --- a/src/tools/linkchecker/main.rs +++ b/src/tools/linkchecker/main.rs @@ -39,6 +39,7 @@ const LINKCHECK_EXCEPTIONS: &[(&str, &[&str])] = &[ "#method.sort_by_key", "#method.make_ascii_uppercase", "#method.make_ascii_lowercase", + "#method.get_unchecked_mut", ], ), // These try to link to std::collections, but are defined in alloc diff --git a/src/tools/lint-docs/Cargo.toml b/src/tools/lint-docs/Cargo.toml new file mode 100644 index 0000000000..657b115671 --- /dev/null +++ b/src/tools/lint-docs/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "lint-docs" +version = "0.1.0" +authors = ["The Rust Project Developers"] +edition = "2018" +description = "A script to extract the lint documentation for the rustc book." + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +serde_json = "1.0.57" +tempfile = "3.1.0" +walkdir = "2.3.1" diff --git a/src/tools/lint-docs/src/groups.rs b/src/tools/lint-docs/src/groups.rs new file mode 100644 index 0000000000..6b32ebdc28 --- /dev/null +++ b/src/tools/lint-docs/src/groups.rs @@ -0,0 +1,114 @@ +use crate::Lint; +use std::collections::{BTreeMap, BTreeSet}; +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::Path; +use std::process::Command; + +static GROUP_DESCRIPTIONS: &[(&str, &str)] = &[ + ("unused", "Lints that detect things being declared but not used, or excess syntax"), + ("rustdoc", "Rustdoc-specific lints"), + ("rust-2018-idioms", "Lints to nudge you toward idiomatic features of Rust 2018"), + ("nonstandard-style", "Violation of standard naming conventions"), + ("future-incompatible", "Lints that detect code that has future-compatibility problems"), + ("rust-2018-compatibility", "Lints used to transition code from the 2015 edition to 2018"), +]; + +/// Updates the documentation of lint groups. +pub(crate) fn generate_group_docs( + lints: &[Lint], + rustc: crate::Rustc<'_>, + out_path: &Path, +) -> Result<(), Box> { + let groups = collect_groups(rustc)?; + let groups_path = out_path.join("groups.md"); + let contents = fs::read_to_string(&groups_path) + .map_err(|e| format!("could not read {}: {}", groups_path.display(), e))?; + let new_contents = contents.replace("{{groups-table}}", &make_groups_table(lints, &groups)?); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&groups_path); + fs::write(&groups_path, new_contents) + .map_err(|e| format!("could not write to {}: {}", groups_path.display(), e))?; + Ok(()) +} + +type LintGroups = BTreeMap>; + +/// Collects the group names from rustc. +fn collect_groups(rustc: crate::Rustc<'_>) -> Result> { + let mut result = BTreeMap::new(); + let mut cmd = Command::new(rustc.path); + cmd.arg("-Whelp"); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + if !output.status.success() { + return Err(format!( + "failed to collect lint info: {:?}\n--- stderr\n{}--- stdout\n{}\n", + output.status, + std::str::from_utf8(&output.stderr).unwrap(), + std::str::from_utf8(&output.stdout).unwrap(), + ) + .into()); + } + let stdout = std::str::from_utf8(&output.stdout).unwrap(); + let lines = stdout.lines(); + let group_start = lines.skip_while(|line| !line.contains("groups provided")).skip(1); + let table_start = group_start.skip_while(|line| !line.contains("----")).skip(1); + for line in table_start { + if line.is_empty() { + break; + } + let mut parts = line.trim().splitn(2, ' '); + let name = parts.next().expect("name in group"); + if name == "warnings" { + // This is special. + continue; + } + let lints = + parts.next().ok_or_else(|| format!("expected lints following name, got `{}`", line))?; + let lints = lints.split(',').map(|l| l.trim().to_string()).collect(); + assert!(result.insert(name.to_string(), lints).is_none()); + } + if result.is_empty() { + return Err( + format!("expected at least one group in -Whelp output, got:\n{}", stdout).into() + ); + } + Ok(result) +} + +fn make_groups_table(lints: &[Lint], groups: &LintGroups) -> Result> { + let mut result = String::new(); + let mut to_link = Vec::new(); + result.push_str("| Group | Description | Lints |\n"); + result.push_str("|-------|-------------|-------|\n"); + result.push_str("| warnings | All lints that are set to issue warnings | See [warn-by-default] for the default set of warnings |\n"); + for (group_name, group_lints) in groups { + let description = GROUP_DESCRIPTIONS.iter().find(|(n, _)| n == group_name) + .ok_or_else(|| format!("lint group `{}` does not have a description, please update the GROUP_DESCRIPTIONS list", group_name))? + .1; + to_link.extend(group_lints); + let brackets: Vec<_> = group_lints.iter().map(|l| format!("[{}]", l)).collect(); + write!(result, "| {} | {} | {} |\n", group_name, description, brackets.join(", ")).unwrap(); + } + result.push('\n'); + result.push_str("[warn-by-default]: listing/warn-by-default.md\n"); + for lint_name in to_link { + let lint_def = + lints.iter().find(|l| l.name == lint_name.replace("-", "_")).ok_or_else(|| { + format!( + "`rustc -W help` defined lint `{}` but that lint does not appear to exist", + lint_name + ) + })?; + write!( + result, + "[{}]: listing/{}#{}\n", + lint_name, + lint_def.level.doc_filename(), + lint_name + ) + .unwrap(); + } + Ok(result) +} diff --git a/src/tools/lint-docs/src/lib.rs b/src/tools/lint-docs/src/lib.rs new file mode 100644 index 0000000000..6ca71dcaf3 --- /dev/null +++ b/src/tools/lint-docs/src/lib.rs @@ -0,0 +1,482 @@ +use std::error::Error; +use std::fmt::Write; +use std::fs; +use std::path::{Path, PathBuf}; +use std::process::Command; +use walkdir::WalkDir; + +mod groups; + +struct Lint { + name: String, + doc: Vec, + level: Level, + path: PathBuf, + lineno: usize, +} + +impl Lint { + fn doc_contains(&self, text: &str) -> bool { + self.doc.iter().any(|line| line.contains(text)) + } + + fn is_ignored(&self) -> bool { + self.doc + .iter() + .filter(|line| line.starts_with("```rust")) + .all(|line| line.contains(",ignore")) + } +} + +#[derive(Clone, Copy, PartialEq)] +enum Level { + Allow, + Warn, + Deny, +} + +impl Level { + fn doc_filename(&self) -> &str { + match self { + Level::Allow => "allowed-by-default.md", + Level::Warn => "warn-by-default.md", + Level::Deny => "deny-by-default.md", + } + } +} + +#[derive(Copy, Clone)] +pub struct Rustc<'a> { + pub path: &'a Path, + pub target: &'a str, +} + +/// Collects all lints, and writes the markdown documentation at the given directory. +pub fn extract_lint_docs( + src_path: &Path, + out_path: &Path, + rustc: Rustc<'_>, + verbose: bool, +) -> Result<(), Box> { + let mut lints = gather_lints(src_path)?; + for lint in &mut lints { + generate_output_example(lint, rustc, verbose).map_err(|e| { + format!( + "failed to test example in lint docs for `{}` in {}:{}: {}", + lint.name, + lint.path.display(), + lint.lineno, + e + ) + })?; + } + save_lints_markdown(&lints, &out_path.join("listing"))?; + groups::generate_group_docs(&lints, rustc, out_path)?; + Ok(()) +} + +/// Collects all lints from all files in the given directory. +fn gather_lints(src_path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + for entry in WalkDir::new(src_path).into_iter().filter_map(|e| e.ok()) { + if !entry.path().extension().map_or(false, |ext| ext == "rs") { + continue; + } + lints.extend(lints_from_file(entry.path())?); + } + if lints.is_empty() { + return Err("no lints were found!".into()); + } + Ok(lints) +} + +/// Collects all lints from the given file. +fn lints_from_file(path: &Path) -> Result, Box> { + let mut lints = Vec::new(); + let contents = fs::read_to_string(path) + .map_err(|e| format!("could not read {}: {}", path.display(), e))?; + let mut lines = contents.lines().enumerate(); + loop { + // Find a lint declaration. + let lint_start = loop { + match lines.next() { + Some((lineno, line)) => { + if line.trim().starts_with("declare_lint!") { + break lineno + 1; + } + } + None => return Ok(lints), + } + }; + // Read the lint. + let mut doc_lines = Vec::new(); + let (doc, name) = loop { + match lines.next() { + Some((lineno, line)) => { + let line = line.trim(); + if line.starts_with("/// ") { + doc_lines.push(line.trim()[4..].to_string()); + } else if line.starts_with("///") { + doc_lines.push("".to_string()); + } else if line.starts_with("// ") { + // Ignore comments. + continue; + } else { + let name = lint_name(line).map_err(|e| { + format!( + "could not determine lint name in {}:{}: {}, line was `{}`", + path.display(), + lineno, + e, + line + ) + })?; + if doc_lines.is_empty() { + return Err(format!( + "did not find doc lines for lint `{}` in {}", + name, + path.display() + ) + .into()); + } + break (doc_lines, name); + } + } + None => { + return Err(format!( + "unexpected EOF for lint definition at {}:{}", + path.display(), + lint_start + ) + .into()); + } + } + }; + // These lints are specifically undocumented. This should be reserved + // for internal rustc-lints only. + if name == "deprecated_in_future" { + continue; + } + // Read the level. + let level = loop { + match lines.next() { + // Ignore comments. + Some((_, line)) if line.trim().starts_with("// ") => {} + Some((lineno, line)) => match line.trim() { + "Allow," => break Level::Allow, + "Warn," => break Level::Warn, + "Deny," => break Level::Deny, + _ => { + return Err(format!( + "unexpected lint level `{}` in {}:{}", + line, + path.display(), + lineno + ) + .into()); + } + }, + None => { + return Err(format!( + "expected lint level in {}:{}, got EOF", + path.display(), + lint_start + ) + .into()); + } + } + }; + // The rest of the lint definition is ignored. + assert!(!doc.is_empty()); + lints.push(Lint { name, doc, level, path: PathBuf::from(path), lineno: lint_start }); + } +} + +/// Extracts the lint name (removing the visibility modifier, and checking validity). +fn lint_name(line: &str) -> Result { + // Skip over any potential `pub` visibility. + match line.trim().split(' ').next_back() { + Some(name) => { + if !name.ends_with(',') { + return Err("lint name should end with comma"); + } + let name = &name[..name.len() - 1]; + if !name.chars().all(|ch| ch.is_uppercase() || ch == '_') || name.is_empty() { + return Err("lint name did not have expected format"); + } + Ok(name.to_lowercase().to_string()) + } + None => Err("could not find lint name"), + } +} + +/// Mutates the lint definition to replace the `{{produces}}` marker with the +/// actual output from the compiler. +fn generate_output_example( + lint: &mut Lint, + rustc: Rustc<'_>, + verbose: bool, +) -> Result<(), Box> { + // Explicit list of lints that are allowed to not have an example. Please + // try to avoid adding to this list. + if matches!( + lint.name.as_str(), + "unused_features" // broken lint + | "unstable_features" // deprecated + ) { + return Ok(()); + } + if lint.doc_contains("[rustdoc book]") && !lint.doc_contains("{{produces}}") { + // Rustdoc lints are documented in the rustdoc book, don't check these. + return Ok(()); + } + check_style(lint)?; + // Unfortunately some lints have extra requirements that this simple test + // setup can't handle (like extern crates). An alternative is to use a + // separate test suite, and use an include mechanism such as mdbook's + // `{{#rustdoc_include}}`. + if !lint.is_ignored() { + replace_produces(lint, rustc, verbose)?; + } + Ok(()) +} + +/// Checks the doc style of the lint. +fn check_style(lint: &Lint) -> Result<(), Box> { + for &expected in &["### Example", "### Explanation", "{{produces}}"] { + if expected == "{{produces}}" && lint.is_ignored() { + continue; + } + if !lint.doc_contains(expected) { + return Err(format!("lint docs should contain the line `{}`", expected).into()); + } + } + if let Some(first) = lint.doc.first() { + if !first.starts_with(&format!("The `{}` lint", lint.name)) { + return Err(format!( + "lint docs should start with the text \"The `{}` lint\" to introduce the lint", + lint.name + ) + .into()); + } + } + Ok(()) +} + +/// Mutates the lint docs to replace the `{{produces}}` marker with the actual +/// output from the compiler. +fn replace_produces( + lint: &mut Lint, + rustc: Rustc<'_>, + verbose: bool, +) -> Result<(), Box> { + let mut lines = lint.doc.iter_mut(); + loop { + // Find start of example. + let options = loop { + match lines.next() { + Some(line) if line.starts_with("```rust") => { + break line[7..].split(',').collect::>(); + } + Some(line) if line.contains("{{produces}}") => { + return Err("lint marker {{{{produces}}}} found, \ + but expected to immediately follow a rust code block" + .into()); + } + Some(_) => {} + None => return Ok(()), + } + }; + // Find the end of example. + let mut example = Vec::new(); + loop { + match lines.next() { + Some(line) if line == "```" => break, + Some(line) => example.push(line), + None => { + return Err(format!( + "did not find end of example triple ticks ```, docs were:\n{:?}", + lint.doc + ) + .into()); + } + } + } + // Find the {{produces}} line. + loop { + match lines.next() { + Some(line) if line.is_empty() => {} + Some(line) if line == "{{produces}}" => { + let output = + generate_lint_output(&lint.name, &example, &options, rustc, verbose)?; + line.replace_range( + .., + &format!( + "This will produce:\n\ + \n\ + ```text\n\ + {}\ + ```", + output + ), + ); + break; + } + // No {{produces}} after example, find next example. + Some(_line) => break, + None => return Ok(()), + } + } + } +} + +/// Runs the compiler against the example, and extracts the output. +fn generate_lint_output( + name: &str, + example: &[&mut String], + options: &[&str], + rustc: Rustc<'_>, + verbose: bool, +) -> Result> { + if verbose { + eprintln!("compiling lint {}", name); + } + let tempdir = tempfile::TempDir::new()?; + let tempfile = tempdir.path().join("lint_example.rs"); + let mut source = String::new(); + let needs_main = !example.iter().any(|line| line.contains("fn main")); + // Remove `# ` prefix for hidden lines. + let unhidden = + example.iter().map(|line| if line.starts_with("# ") { &line[2..] } else { line }); + let mut lines = unhidden.peekable(); + while let Some(line) = lines.peek() { + if line.starts_with("#!") { + source.push_str(line); + source.push('\n'); + lines.next(); + } else { + break; + } + } + if needs_main { + source.push_str("fn main() {\n"); + } + for line in lines { + source.push_str(line); + source.push('\n') + } + if needs_main { + source.push_str("}\n"); + } + fs::write(&tempfile, source) + .map_err(|e| format!("failed to write {}: {}", tempfile.display(), e))?; + let mut cmd = Command::new(rustc.path); + if options.contains(&"edition2015") { + cmd.arg("--edition=2015"); + } else { + cmd.arg("--edition=2018"); + } + cmd.arg("--error-format=json"); + cmd.arg("--target").arg(rustc.target); + if options.contains(&"test") { + cmd.arg("--test"); + } + cmd.arg("lint_example.rs"); + cmd.current_dir(tempdir.path()); + let output = cmd.output().map_err(|e| format!("failed to run command {:?}\n{}", cmd, e))?; + let stderr = std::str::from_utf8(&output.stderr).unwrap(); + let msgs = stderr + .lines() + .filter(|line| line.starts_with('{')) + .map(serde_json::from_str) + .collect::, _>>()?; + match msgs + .iter() + .find(|msg| matches!(&msg["code"]["code"], serde_json::Value::String(s) if s==name)) + { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + match msgs.iter().find( + |msg| matches!(&msg["rendered"], serde_json::Value::String(s) if s.contains(name)), + ) { + Some(msg) => { + let rendered = msg["rendered"].as_str().expect("rendered field should exist"); + Ok(rendered.to_string()) + } + None => { + let rendered: Vec<&str> = + msgs.iter().filter_map(|msg| msg["rendered"].as_str()).collect(); + let non_json: Vec<&str> = + stderr.lines().filter(|line| !line.starts_with('{')).collect(); + Err(format!( + "did not find lint `{}` in output of example, got:\n{}\n{}", + name, + non_json.join("\n"), + rendered.join("\n") + ) + .into()) + } + } + } + } +} + +static ALLOWED_MD: &str = r#"# Allowed-by-default lints + +These lints are all set to the 'allow' level by default. As such, they won't show up +unless you set them to a higher lint level with a flag or attribute. + +"#; + +static WARN_MD: &str = r#"# Warn-by-default lints + +These lints are all set to the 'warn' level by default. + +"#; + +static DENY_MD: &str = r#"# Deny-by-default lints + +These lints are all set to the 'deny' level by default. + +"#; + +/// Saves the mdbook lint chapters at the given path. +fn save_lints_markdown(lints: &[Lint], out_dir: &Path) -> Result<(), Box> { + save_level(lints, Level::Allow, out_dir, ALLOWED_MD)?; + save_level(lints, Level::Warn, out_dir, WARN_MD)?; + save_level(lints, Level::Deny, out_dir, DENY_MD)?; + Ok(()) +} + +fn save_level( + lints: &[Lint], + level: Level, + out_dir: &Path, + header: &str, +) -> Result<(), Box> { + let mut result = String::new(); + result.push_str(header); + let mut these_lints: Vec<_> = lints.iter().filter(|lint| lint.level == level).collect(); + these_lints.sort_unstable_by_key(|lint| &lint.name); + for lint in &these_lints { + write!(result, "* [`{}`](#{})\n", lint.name, lint.name.replace("_", "-")).unwrap(); + } + result.push('\n'); + for lint in &these_lints { + write!(result, "## {}\n\n", lint.name.replace("_", "-")).unwrap(); + for line in &lint.doc { + result.push_str(line); + result.push('\n'); + } + result.push('\n'); + } + let out_path = out_dir.join(level.doc_filename()); + // Delete the output because rustbuild uses hard links in its copies. + let _ = fs::remove_file(&out_path); + fs::write(&out_path, result) + .map_err(|e| format!("could not write to {}: {}", out_path.display(), e))?; + Ok(()) +} diff --git a/src/tools/lint-docs/src/main.rs b/src/tools/lint-docs/src/main.rs new file mode 100644 index 0000000000..5db49007d3 --- /dev/null +++ b/src/tools/lint-docs/src/main.rs @@ -0,0 +1,69 @@ +use std::error::Error; +use std::path::PathBuf; + +fn main() { + if let Err(e) = doit() { + println!("error: {}", e); + std::process::exit(1); + } +} + +fn doit() -> Result<(), Box> { + let mut args = std::env::args().skip(1); + let mut src_path = None; + let mut out_path = None; + let mut rustc_path = None; + let mut rustc_target = None; + let mut verbose = false; + while let Some(arg) = args.next() { + match arg.as_str() { + "--src" => { + src_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--src requires a value".into()), + }; + } + "--out" => { + out_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--out requires a value".into()), + }; + } + "--rustc" => { + rustc_path = match args.next() { + Some(s) => Some(PathBuf::from(s)), + None => return Err("--rustc requires a value".into()), + }; + } + "--rustc-target" => { + rustc_target = match args.next() { + Some(s) => Some(s), + None => return Err("--rustc-target requires a value".into()), + }; + } + "-v" | "--verbose" => verbose = true, + s => return Err(format!("unexpected argument `{}`", s).into()), + } + } + if src_path.is_none() { + return Err("--src must be specified to the directory with the compiler source".into()); + } + if out_path.is_none() { + return Err("--out must be specified to the directory with the lint listing docs".into()); + } + if rustc_path.is_none() { + return Err("--rustc must be specified to the path of rustc".into()); + } + if rustc_target.is_none() { + return Err("--rustc-target must be specified to the rustc target".into()); + } + lint_docs::extract_lint_docs( + &src_path.unwrap(), + &out_path.unwrap(), + lint_docs::Rustc { + path: rustc_path.as_deref().unwrap(), + target: rustc_target.as_deref().unwrap(), + }, + verbose, + ) +} diff --git a/src/tools/publish_toolstate.py b/src/tools/publish_toolstate.py index 51416c8ce6..7586f5aa3b 100755 --- a/src/tools/publish_toolstate.py +++ b/src/tools/publish_toolstate.py @@ -33,7 +33,7 @@ MAINTAINERS = { 'rust-by-example': {'steveklabnik', 'marioidival'}, 'embedded-book': {'adamgreig', 'andre-richter', 'jamesmunns', 'therealprof'}, 'edition-guide': {'ehuss', 'steveklabnik'}, - 'rustc-dev-guide': {'mark-i-m', 'spastorino', 'amanjeev', 'JohnTitor'}, + 'rustc-dev-guide': {'spastorino', 'amanjeev', 'JohnTitor'}, } LABELS = { @@ -157,9 +157,6 @@ def issue( cc @{}, do you think you would have time to do the follow-up work? If so, that would be great! - - And nominating for compiler team prioritization. - ''').format( relevant_pr_number, tool, status_description, REPOS.get(tool), relevant_pr_user @@ -275,7 +272,12 @@ def update_latest( return message -def main(): +# Warning: Do not try to add a function containing the body of this try block. +# There are variables declared within that are implicitly global; it is unknown +# which ones precisely but at least this is true for `github_token`. +try: + if __name__ != '__main__': + exit(0) repo = os.environ.get('TOOLSTATE_VALIDATE_MAINTAINERS_REPO') if repo: github_token = os.environ.get('TOOLSTATE_REPO_ACCESS_TOKEN') @@ -342,11 +344,6 @@ def main(): } )) response.read() - - -if __name__ == '__main__': - try: - main() - except urllib2.HTTPError as e: - print("HTTPError: %s\n%s" % (e, e.read())) - raise +except urllib2.HTTPError as e: + print("HTTPError: %s\n%s" % (e, e.read())) + raise diff --git a/src/tools/rustbook/Cargo.toml b/src/tools/rustbook/Cargo.toml index f0a6ce2fa0..f5e5c0867b 100644 --- a/src/tools/rustbook/Cargo.toml +++ b/src/tools/rustbook/Cargo.toml @@ -9,6 +9,6 @@ edition = "2018" clap = "2.25.0" [dependencies.mdbook] -version = "0.4.0" +version = "0.4.3" default-features = false features = ["search"] diff --git a/src/tools/rustc-workspace-hack/Cargo.toml b/src/tools/rustc-workspace-hack/Cargo.toml index 351e2d4481..11d61606ff 100644 --- a/src/tools/rustc-workspace-hack/Cargo.toml +++ b/src/tools/rustc-workspace-hack/Cargo.toml @@ -69,7 +69,7 @@ serde = { version = "1.0.82", features = ['derive'] } serde_json = { version = "1.0.31", features = ["raw_value"] } smallvec-0_6 = { package = "smallvec", version = "0.6", features = ['union', 'may_dangle'] } smallvec = { version = "1.0", features = ['union', 'may_dangle'] } -syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit'] } +syn = { version = "1", features = ['fold', 'full', 'extra-traits', 'visit', 'visit-mut'] } url = { version = "2.0", features = ['serde'] } [target.'cfg(not(windows))'.dependencies] diff --git a/src/tools/tidy/src/debug_artifacts.rs b/src/tools/tidy/src/debug_artifacts.rs index 408be83b92..ab87230f88 100644 --- a/src/tools/tidy/src/debug_artifacts.rs +++ b/src/tools/tidy/src/debug_artifacts.rs @@ -1,4 +1,4 @@ -//! Tidy check to prevent creation of unnecessary debug artifacts. +//! Tidy check to prevent creation of unnecessary debug artifacts while running tests. use std::path::{Path, PathBuf}; diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index af3fb40370..356705305d 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -42,6 +42,7 @@ const EXCEPTIONS: &[(&str, &str)] = &[ ("crossbeam-queue", "MIT/Apache-2.0 AND BSD-2-Clause"), // rls via rayon ("arrayref", "BSD-2-Clause"), // cargo-miri/directories/.../rust-argon2 (redox) ("instant", "BSD-3-Clause"), // rustc_driver/tracing-subscriber/parking_lot + ("snap", "BSD-3-Clause"), // rustc // FIXME: this dependency violates the documentation comment above: ("fortanix-sgx-abi", "MPL-2.0"), // libstd but only for `sgx` target ]; @@ -161,6 +162,7 @@ const PERMITTED_DEPENDENCIES: &[&str] = &[ "serde_derive", "sha-1", "smallvec", + "snap", "stable_deref_trait", "stacker", "syn", diff --git a/src/tools/tidy/src/edition.rs b/src/tools/tidy/src/edition.rs index 4a2e49fd1c..7761ae64ee 100644 --- a/src/tools/tidy/src/edition.rs +++ b/src/tools/tidy/src/edition.rs @@ -1,5 +1,4 @@ //! Tidy check to ensure that crate `edition` is '2018' -//! use std::path::Path; diff --git a/src/tools/tidy/src/features.rs b/src/tools/tidy/src/features.rs index 678e346bd4..d8029ea04f 100644 --- a/src/tools/tidy/src/features.rs +++ b/src/tools/tidy/src/features.rs @@ -71,8 +71,14 @@ pub fn collect_lib_features(base_src_path: &Path) -> Features { lib_features } -pub fn check(src_path: &Path, lib_path: &Path, bad: &mut bool, verbose: bool) -> CollectedFeatures { - let mut features = collect_lang_features(src_path, bad); +pub fn check( + src_path: &Path, + compiler_path: &Path, + lib_path: &Path, + bad: &mut bool, + verbose: bool, +) -> CollectedFeatures { + let mut features = collect_lang_features(compiler_path, bad); assert!(!features.is_empty()); let lib_features = get_and_check_lib_features(lib_path, bad, &features); @@ -225,15 +231,15 @@ fn test_filen_gate(filen_underscore: &str, features: &mut Features) -> bool { false } -pub fn collect_lang_features(base_src_path: &Path, bad: &mut bool) -> Features { - let mut all = collect_lang_features_in(base_src_path, "active.rs", bad); - all.extend(collect_lang_features_in(base_src_path, "accepted.rs", bad)); - all.extend(collect_lang_features_in(base_src_path, "removed.rs", bad)); +pub fn collect_lang_features(base_compiler_path: &Path, bad: &mut bool) -> Features { + let mut all = collect_lang_features_in(base_compiler_path, "active.rs", bad); + all.extend(collect_lang_features_in(base_compiler_path, "accepted.rs", bad)); + all.extend(collect_lang_features_in(base_compiler_path, "removed.rs", bad)); all } fn collect_lang_features_in(base: &Path, file: &str, bad: &mut bool) -> Features { - let path = base.join("librustc_feature").join(file); + let path = base.join("rustc_feature").join("src").join(file); let contents = t!(fs::read_to_string(&path)); // We allow rustc-internal features to omit a tracking issue. diff --git a/src/tools/tidy/src/main.rs b/src/tools/tidy/src/main.rs index 43105188ec..36c9e58eb9 100644 --- a/src/tools/tidy/src/main.rs +++ b/src/tools/tidy/src/main.rs @@ -11,44 +11,53 @@ use std::path::PathBuf; use std::process; fn main() { - let path: PathBuf = env::args_os().nth(1).expect("need path to src").into(); + let root_path: PathBuf = env::args_os().nth(1).expect("need path to root of repo").into(); let cargo: PathBuf = env::args_os().nth(2).expect("need path to cargo").into(); - let library_path: PathBuf = path - .join("..") - .join("library") - .canonicalize() - .expect("unable to canonicalize path to library/"); + let src_path = root_path.join("src"); + let library_path = root_path.join("library"); + let compiler_path = root_path.join("compiler"); let args: Vec = env::args().skip(1).collect(); let mut bad = false; let verbose = args.iter().any(|s| *s == "--verbose"); + // Checks over tests. + debug_artifacts::check(&src_path, &mut bad); + ui_tests::check(&src_path, &mut bad); + // Checks that only make sense for the compiler. - debug_artifacts::check(&path, &mut bad); - errors::check(&path, &mut bad); - ui_tests::check(&path, &mut bad); - error_codes_check::check(&path, &mut bad); + errors::check(&compiler_path, &mut bad); + error_codes_check::check(&src_path, &mut bad); // Checks that only make sense for the std libs. pal::check(&library_path, &mut bad); unit_tests::check(&library_path, &mut bad); - // Check that need to be done for both the compiler and std libraries. - bins::check(&path, &mut bad); + // Checks that need to be done for both the compiler and std libraries. + bins::check(&src_path, &mut bad); + bins::check(&compiler_path, &mut bad); bins::check(&library_path, &mut bad); - style::check(&path, &mut bad); + + style::check(&src_path, &mut bad); + style::check(&compiler_path, &mut bad); style::check(&library_path, &mut bad); - cargo::check(&path, &mut bad); + + cargo::check(&src_path, &mut bad); + cargo::check(&compiler_path, &mut bad); cargo::check(&library_path, &mut bad); - edition::check(&path, &mut bad); + + edition::check(&src_path, &mut bad); + edition::check(&compiler_path, &mut bad); edition::check(&library_path, &mut bad); - let collected = features::check(&path, &library_path, &mut bad, verbose); - unstable_book::check(&path, collected, &mut bad); - deps::check(&path.parent().unwrap(), &cargo, &mut bad); - extdeps::check(&path.parent().unwrap(), &mut bad); + let collected = features::check(&src_path, &compiler_path, &library_path, &mut bad, verbose); + unstable_book::check(&src_path, collected, &mut bad); + + // Checks that are done on the cargo workspace. + deps::check(&root_path, &cargo, &mut bad); + extdeps::check(&root_path, &mut bad); if bad { eprintln!("some tidy checks failed"); diff --git a/src/tools/tidy/src/pal.rs b/src/tools/tidy/src/pal.rs index 8f9d691579..1dba6b73b9 100644 --- a/src/tools/tidy/src/pal.rs +++ b/src/tools/tidy/src/pal.rs @@ -56,9 +56,14 @@ const EXCEPTION_PATHS: &[&str] = &[ // Integration test for platform-specific run-time feature detection: "library/std/tests/run-time-detect.rs", "library/std/src/net/test.rs", + "library/std/src/net/addr", + "library/std/src/net/udp", "library/std/src/sys_common/mod.rs", "library/std/src/sys_common/net.rs", "library/std/src/sys_common/backtrace.rs", + "library/std/src/sys_common/remutex.rs", + "library/std/src/sync/mutex.rs", + "library/std/src/sync/rwlock.rs", // panic_unwind shims "library/std/src/panicking.rs", "library/term", // Not sure how to make this crate portable, but test crate needs it. diff --git a/src/tools/tidy/src/unit_tests.rs b/src/tools/tidy/src/unit_tests.rs index c6d67844a2..04f2bbaa0d 100644 --- a/src/tools/tidy/src/unit_tests.rs +++ b/src/tools/tidy/src/unit_tests.rs @@ -20,15 +20,19 @@ pub fn check(root_path: &Path, bad: &mut bool) { let mut skip = |path: &Path| { let file_name = path.file_name().unwrap_or_default(); if path.is_dir() { - super::filter_dirs(path) || - path.ends_with("src/test") || - path.ends_with("src/doc") || - path.ends_with("library/std") || // FIXME? - (file_name == "tests" || file_name == "benches") && !is_core(path) + super::filter_dirs(path) + || path.ends_with("src/test") + || path.ends_with("src/doc") + || (file_name == "tests" || file_name == "benches") && !is_core(path) } else { let extension = path.extension().unwrap_or_default(); extension != "rs" || (file_name == "tests.rs" || file_name == "benches.rs") && !is_core(path) + // UI tests with different names + || path.ends_with("src/thread/local/dynamic_tests.rs") + || path.ends_with("src/sync/mpsc/sync_tests.rs") + // Has copyright banner + || path.ends_with("src/sys/cloudabi/abi/cloudabi.rs") } }; diff --git a/src/tools/tier-check/src/main.rs b/src/tools/tier-check/src/main.rs index b8d60a5e2f..6a492bbff4 100644 --- a/src/tools/tier-check/src/main.rs +++ b/src/tools/tier-check/src/main.rs @@ -25,8 +25,6 @@ fn main() { let doc_targets: HashSet<_> = doc_targets_md .lines() .filter(|line| line.starts_with('`') && line.contains('|')) - // These platforms only exist on macos. - .filter(|line| !line.contains("[^apple]") || cfg!(target_os = "macos")) .map(|line| line.split('`').skip(1).next().expect("expected target code span")) .collect(); diff --git a/src/tools/unstable-book-gen/src/main.rs b/src/tools/unstable-book-gen/src/main.rs index 5d277e1c41..e10f72a47b 100644 --- a/src/tools/unstable-book-gen/src/main.rs +++ b/src/tools/unstable-book-gen/src/main.rs @@ -27,12 +27,12 @@ macro_rules! t { fn generate_stub_issue(path: &Path, name: &str, issue: u32) { let mut file = t!(File::create(path)); - t!(file.write_fmt(format_args!(include_str!("stub-issue.md"), name = name, issue = issue))); + t!(write!(file, include_str!("stub-issue.md"), name = name, issue = issue)); } fn generate_stub_no_issue(path: &Path, name: &str) { let mut file = t!(File::create(path)); - t!(file.write_fmt(format_args!(include_str!("stub-no-issue.md"), name = name))); + t!(write!(file, include_str!("stub-no-issue.md"), name = name)); } fn set_to_summary_str(set: &BTreeSet, dir: &str) -> String { @@ -94,14 +94,16 @@ fn copy_recursive(from: &Path, to: &Path) { } fn main() { - let library_path_str = env::args_os().nth(1).expect("library path required"); - let src_path_str = env::args_os().nth(2).expect("source path required"); - let dest_path_str = env::args_os().nth(3).expect("destination path required"); + let library_path_str = env::args_os().nth(1).expect("library/ path required"); + let compiler_path_str = env::args_os().nth(2).expect("compiler/ path required"); + let src_path_str = env::args_os().nth(3).expect("src/ path required"); + let dest_path_str = env::args_os().nth(4).expect("destination path required"); let library_path = Path::new(&library_path_str); + let compiler_path = Path::new(&compiler_path_str); let src_path = Path::new(&src_path_str); let dest_path = Path::new(&dest_path_str); - let lang_features = collect_lang_features(src_path, &mut false); + let lang_features = collect_lang_features(compiler_path, &mut false); let lib_features = collect_lib_features(library_path) .into_iter() .filter(|&(ref name, _)| !lang_features.contains_key(name)) diff --git a/src/version b/src/version new file mode 100644 index 0000000000..9db5ea12f5 --- /dev/null +++ b/src/version @@ -0,0 +1 @@ +1.48.0 diff --git a/vendor/block-buffer-0.7.3/.cargo-checksum.json b/vendor/block-buffer-0.7.3/.cargo-checksum.json new file mode 100644 index 0000000000..779d602b1b --- /dev/null +++ b/vendor/block-buffer-0.7.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"e4e9e182794c2185438af0c505714df9e051d1d1b17aec7a42265be672b1d027","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"59dd4084e456153bee968153ee45e34c8e853abfb756a53571c5844ccaf18c23"},"package":"c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"} \ No newline at end of file diff --git a/vendor/block-buffer-0.7.3/Cargo.toml b/vendor/block-buffer-0.7.3/Cargo.toml new file mode 100644 index 0000000000..6b10954cbb --- /dev/null +++ b/vendor/block-buffer-0.7.3/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "block-buffer" +version = "0.7.3" +authors = ["RustCrypto Developers"] +description = "Fixed size buffer for block processing of data" +documentation = "https://docs.rs/block-buffer" +keywords = ["block", "buffer"] +categories = ["cryptography", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/utils" +[dependencies.block-padding] +version = "0.1" + +[dependencies.byte-tools] +version = "0.3" + +[dependencies.byteorder] +version = "1.1" +default-features = false + +[dependencies.generic-array] +version = "0.12" +[badges.travis-ci] +repository = "RustCrypto/utils" diff --git a/vendor/block-buffer-0.7.3/LICENSE-APACHE b/vendor/block-buffer-0.7.3/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/block-buffer-0.7.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/block-buffer-0.7.3/LICENSE-MIT b/vendor/block-buffer-0.7.3/LICENSE-MIT new file mode 100644 index 0000000000..502cee6e85 --- /dev/null +++ b/vendor/block-buffer-0.7.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018-2019 The RustCrypto Project Developers + +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 --git a/vendor/block-buffer-0.7.3/src/lib.rs b/vendor/block-buffer-0.7.3/src/lib.rs new file mode 100644 index 0000000000..d3b6916554 --- /dev/null +++ b/vendor/block-buffer-0.7.3/src/lib.rs @@ -0,0 +1,210 @@ +#![no_std] +pub extern crate byteorder; +pub extern crate block_padding; +pub extern crate generic_array; +extern crate byte_tools; + +use byteorder::{ByteOrder, BE}; +use byte_tools::zero; +use block_padding::{Padding, PadError}; +use generic_array::{GenericArray, ArrayLength}; +use core::slice; + +/// Buffer for block processing of data +#[derive(Clone, Default)] +pub struct BlockBuffer> { + buffer: GenericArray, + pos: usize, +} + +#[inline(always)] +unsafe fn cast>(block: &[u8]) -> &GenericArray { + debug_assert_eq!(block.len(), N::to_usize()); + &*(block.as_ptr() as *const GenericArray) +} + + + +impl> BlockBuffer { + /// Process data in `input` in blocks of size `BlockSize` using function `f`. + #[inline] + pub fn input(&mut self, mut input: &[u8], mut f: F) + where F: FnMut(&GenericArray) + { + // If there is already data in the buffer, process it if we have + // enough to complete the chunk. + let rem = self.remaining(); + if self.pos != 0 && input.len() >= rem { + let (l, r) = input.split_at(rem); + input = r; + self.buffer[self.pos..].copy_from_slice(l); + self.pos = 0; + f(&self.buffer); + } + + // While we have at least a full buffer size chunks's worth of data, + // process that data without copying it into the buffer + while input.len() >= self.size() { + let (block, r) = input.split_at(self.size()); + input = r; + f(unsafe { cast(block) }); + } + + // Copy any remaining data into the buffer. + self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); + self.pos += input.len(); + } + + /* + /// Process data in `input` in blocks of size `BlockSize` using function `f`, which accepts + /// slice of blocks. + #[inline] + pub fn input2(&mut self, mut input: &[u8], mut f: F) + where F: FnMut(&[GenericArray]) + { + // If there is already data in the buffer, process it if we have + // enough to complete the chunk. + let rem = self.remaining(); + if self.pos != 0 && input.len() >= rem { + let (l, r) = input.split_at(rem); + input = r; + self.buffer[self.pos..].copy_from_slice(l); + self.pos = 0; + f(slice::from_ref(&self.buffer)); + } + + // While we have at least a full buffer size chunks's worth of data, + // process it data without copying into the buffer + let n_blocks = input.len()/self.size(); + let (left, right) = input.split_at(n_blocks*self.size()); + // safe because we guarantee that `blocks` does not point outside of `input` + let blocks = unsafe { + slice::from_raw_parts( + left.as_ptr() as *const GenericArray, + n_blocks, + ) + }; + f(blocks); + + // Copy remaining data into the buffer. + self.buffer[self.pos..self.pos+right.len()].copy_from_slice(right); + self.pos += right.len(); + } + */ + + /// Variant that doesn't flush the buffer until there's additional + /// data to be processed. Suitable for tweakable block ciphers + /// like Threefish that need to know whether a block is the *last* + /// data block before processing it. + #[inline] + pub fn input_lazy(&mut self, mut input: &[u8], mut f: F) + where F: FnMut(&GenericArray) + { + let rem = self.remaining(); + if self.pos != 0 && input.len() > rem { + let (l, r) = input.split_at(rem); + input = r; + self.buffer[self.pos..].copy_from_slice(l); + self.pos = 0; + f(&self.buffer); + } + + while input.len() > self.size() { + let (block, r) = input.split_at(self.size()); + input = r; + f(unsafe { cast(block) }); + } + + self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); + self.pos += input.len(); + } + + /// Pad buffer with `prefix` and make sure that internall buffer + /// has at least `up_to` free bytes. All remaining bytes get + /// zeroed-out. + #[inline] + fn digest_pad(&mut self, up_to: usize, f: &mut F) + where F: FnMut(&GenericArray) + { + if self.pos == self.size() { + f(&self.buffer); + self.pos = 0; + } + self.buffer[self.pos] = 0x80; + self.pos += 1; + + zero(&mut self.buffer[self.pos..]); + + if self.remaining() < up_to { + f(&self.buffer); + zero(&mut self.buffer[..self.pos]); + } + } + + /// Pad message with 0x80, zeros and 64-bit message length + /// in a byte order specified by `B` + #[inline] + pub fn len64_padding(&mut self, data_len: u64, mut f: F) + where B: ByteOrder, F: FnMut(&GenericArray) + { + // TODO: replace `F` with `impl Trait` on MSRV bump + self.digest_pad(8, &mut f); + let s = self.size(); + B::write_u64(&mut self.buffer[s-8..], data_len); + f(&self.buffer); + self.pos = 0; + } + + + /// Pad message with 0x80, zeros and 128-bit message length + /// in the big-endian byte order + #[inline] + pub fn len128_padding_be(&mut self, hi: u64, lo: u64, mut f: F) + where F: FnMut(&GenericArray) + { + // TODO: on MSRV bump replace `F` with `impl Trait`, use `u128`, add `B` + self.digest_pad(16, &mut f); + let s = self.size(); + BE::write_u64(&mut self.buffer[s-16..s-8], hi); + BE::write_u64(&mut self.buffer[s-8..], lo); + f(&self.buffer); + self.pos = 0; + } + + /// Pad message with a given padding `P` + /// + /// Returns `PadError` if internall buffer is full, which can only happen if + /// `input_lazy` was used. + #[inline] + pub fn pad_with(&mut self) + -> Result<&mut GenericArray, PadError> + { + P::pad_block(&mut self.buffer[..], self.pos)?; + self.pos = 0; + Ok(&mut self.buffer) + } + + /// Return size of the internall buffer in bytes + #[inline] + pub fn size(&self) -> usize { + BlockSize::to_usize() + } + + /// Return current cursor position + #[inline] + pub fn position(&self) -> usize { + self.pos + } + + /// Return number of remaining bytes in the internall buffer + #[inline] + pub fn remaining(&self) -> usize { + self.size() - self.pos + } + + /// Reset buffer by setting cursor position to zero + #[inline] + pub fn reset(&mut self) { + self.pos = 0 + } +} diff --git a/vendor/block-buffer/.cargo-checksum.json b/vendor/block-buffer/.cargo-checksum.json index 779d602b1b..ad6294a06e 100644 --- a/vendor/block-buffer/.cargo-checksum.json +++ b/vendor/block-buffer/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"e4e9e182794c2185438af0c505714df9e051d1d1b17aec7a42265be672b1d027","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"59dd4084e456153bee968153ee45e34c8e853abfb756a53571c5844ccaf18c23"},"package":"c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b"} \ No newline at end of file +{"files":{"Cargo.toml":"34462967bea652daffb9de37578231a0c8318b5b9ed0f7682c8ab5d00820cb82","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"39a549b74d83a11887e1f257d3273d7c1b82052b671e6e5ac1938f87a9ee4717"},"package":"4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4"} \ No newline at end of file diff --git a/vendor/block-buffer/Cargo.toml b/vendor/block-buffer/Cargo.toml index 6b10954cbb..99c0f39af5 100644 --- a/vendor/block-buffer/Cargo.toml +++ b/vendor/block-buffer/Cargo.toml @@ -11,8 +11,9 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "block-buffer" -version = "0.7.3" +version = "0.9.0" authors = ["RustCrypto Developers"] description = "Fixed size buffer for block processing of data" documentation = "https://docs.rs/block-buffer" @@ -21,16 +22,8 @@ categories = ["cryptography", "no-std"] license = "MIT OR Apache-2.0" repository = "https://github.com/RustCrypto/utils" [dependencies.block-padding] -version = "0.1" - -[dependencies.byte-tools] -version = "0.3" - -[dependencies.byteorder] -version = "1.1" -default-features = false +version = "0.2.0" +optional = true [dependencies.generic-array] -version = "0.12" -[badges.travis-ci] -repository = "RustCrypto/utils" +version = "0.14" diff --git a/vendor/block-buffer/src/lib.rs b/vendor/block-buffer/src/lib.rs index d3b6916554..49b8b3dcdb 100644 --- a/vendor/block-buffer/src/lib.rs +++ b/vendor/block-buffer/src/lib.rs @@ -1,14 +1,12 @@ #![no_std] -pub extern crate byteorder; -pub extern crate block_padding; -pub extern crate generic_array; -extern crate byte_tools; +pub use generic_array; +#[cfg(feature = "block-padding")] +pub use block_padding; -use byteorder::{ByteOrder, BE}; -use byte_tools::zero; -use block_padding::{Padding, PadError}; +use core::{slice, convert::TryInto}; use generic_array::{GenericArray, ArrayLength}; -use core::slice; +#[cfg(feature = "block-padding")] +use block_padding::{Padding, PadError}; /// Buffer for block processing of data #[derive(Clone, Default)] @@ -17,56 +15,52 @@ pub struct BlockBuffer> { pos: usize, } -#[inline(always)] -unsafe fn cast>(block: &[u8]) -> &GenericArray { - debug_assert_eq!(block.len(), N::to_usize()); - &*(block.as_ptr() as *const GenericArray) -} - - - impl> BlockBuffer { /// Process data in `input` in blocks of size `BlockSize` using function `f`. #[inline] - pub fn input(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&GenericArray) - { - // If there is already data in the buffer, process it if we have - // enough to complete the chunk. - let rem = self.remaining(); - if self.pos != 0 && input.len() >= rem { - let (l, r) = input.split_at(rem); + pub fn input_block( + &mut self, mut input: &[u8], mut f: impl FnMut(&GenericArray), + ) { + let r = self.remaining(); + if input.len() < r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() >= r { + let (l, r) = input.split_at(r); input = r; self.buffer[self.pos..].copy_from_slice(l); - self.pos = 0; f(&self.buffer); } - // While we have at least a full buffer size chunks's worth of data, - // process that data without copying it into the buffer - while input.len() >= self.size() { - let (block, r) = input.split_at(self.size()); - input = r; - f(unsafe { cast(block) }); + let mut chunks_iter = input.chunks_exact(self.size()); + for chunk in &mut chunks_iter { + f(chunk.try_into().unwrap()); } + let rem = chunks_iter.remainder(); // Copy any remaining data into the buffer. - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); + self.buffer[..rem.len()].copy_from_slice(rem); + self.pos = rem.len(); } - /* /// Process data in `input` in blocks of size `BlockSize` using function `f`, which accepts /// slice of blocks. #[inline] - pub fn input2(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&[GenericArray]) - { - // If there is already data in the buffer, process it if we have - // enough to complete the chunk. - let rem = self.remaining(); - if self.pos != 0 && input.len() >= rem { - let (l, r) = input.split_at(rem); + pub fn input_blocks( + &mut self, mut input: &[u8], mut f: impl FnMut(&[GenericArray]), + ) { + let r = self.remaining(); + if input.len() < r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() >= r { + let (l, r) = input.split_at(r); input = r; self.buffer[self.pos..].copy_from_slice(l); self.pos = 0; @@ -74,10 +68,10 @@ impl> BlockBuffer { } // While we have at least a full buffer size chunks's worth of data, - // process it data without copying into the buffer + // process its data without copying into the buffer let n_blocks = input.len()/self.size(); let (left, right) = input.split_at(n_blocks*self.size()); - // safe because we guarantee that `blocks` does not point outside of `input` + // SAFETY: we guarantee that `blocks` does not point outside of `input` let blocks = unsafe { slice::from_raw_parts( left.as_ptr() as *const GenericArray, @@ -87,45 +81,50 @@ impl> BlockBuffer { f(blocks); // Copy remaining data into the buffer. - self.buffer[self.pos..self.pos+right.len()].copy_from_slice(right); - self.pos += right.len(); + let n = right.len(); + self.buffer[..n].copy_from_slice(right); + self.pos = n; } - */ /// Variant that doesn't flush the buffer until there's additional /// data to be processed. Suitable for tweakable block ciphers /// like Threefish that need to know whether a block is the *last* /// data block before processing it. #[inline] - pub fn input_lazy(&mut self, mut input: &[u8], mut f: F) - where F: FnMut(&GenericArray) - { - let rem = self.remaining(); - if self.pos != 0 && input.len() > rem { - let (l, r) = input.split_at(rem); + pub fn input_lazy( + &mut self, mut input: &[u8], mut f: impl FnMut(&GenericArray), + ) { + let r = self.remaining(); + if input.len() <= r { + let n = input.len(); + self.buffer[self.pos..self.pos + n].copy_from_slice(input); + self.pos += n; + return; + } + if self.pos != 0 && input.len() > r { + let (l, r) = input.split_at(r); input = r; self.buffer[self.pos..].copy_from_slice(l); - self.pos = 0; f(&self.buffer); } while input.len() > self.size() { let (block, r) = input.split_at(self.size()); input = r; - f(unsafe { cast(block) }); + f(block.try_into().unwrap()); } - self.buffer[self.pos..self.pos+input.len()].copy_from_slice(input); - self.pos += input.len(); + self.buffer[..input.len()].copy_from_slice(input); + self.pos = input.len(); } /// Pad buffer with `prefix` and make sure that internall buffer /// has at least `up_to` free bytes. All remaining bytes get /// zeroed-out. #[inline] - fn digest_pad(&mut self, up_to: usize, f: &mut F) - where F: FnMut(&GenericArray) - { + fn digest_pad( + &mut self, up_to: usize, mut f: impl FnMut(&GenericArray), + ) { if self.pos == self.size() { f(&self.buffer); self.pos = 0; @@ -133,40 +132,52 @@ impl> BlockBuffer { self.buffer[self.pos] = 0x80; self.pos += 1; - zero(&mut self.buffer[self.pos..]); + set_zero(&mut self.buffer[self.pos..]); if self.remaining() < up_to { f(&self.buffer); - zero(&mut self.buffer[..self.pos]); + set_zero(&mut self.buffer[..self.pos]); } } /// Pad message with 0x80, zeros and 64-bit message length - /// in a byte order specified by `B` + /// using big-endian byte order #[inline] - pub fn len64_padding(&mut self, data_len: u64, mut f: F) - where B: ByteOrder, F: FnMut(&GenericArray) - { - // TODO: replace `F` with `impl Trait` on MSRV bump + pub fn len64_padding_be( + &mut self, data_len: u64, mut f: impl FnMut(&GenericArray), + ) { self.digest_pad(8, &mut f); - let s = self.size(); - B::write_u64(&mut self.buffer[s-8..], data_len); + let b = data_len.to_be_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); f(&self.buffer); self.pos = 0; } + /// Pad message with 0x80, zeros and 64-bit message length + /// using little-endian byte order + #[inline] + pub fn len64_padding_le( + &mut self, data_len: u64, mut f: impl FnMut(&GenericArray), + ) { + self.digest_pad(8, &mut f); + let b = data_len.to_le_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); + f(&self.buffer); + self.pos = 0; + } /// Pad message with 0x80, zeros and 128-bit message length - /// in the big-endian byte order + /// using big-endian byte order #[inline] - pub fn len128_padding_be(&mut self, hi: u64, lo: u64, mut f: F) - where F: FnMut(&GenericArray) - { - // TODO: on MSRV bump replace `F` with `impl Trait`, use `u128`, add `B` + pub fn len128_padding_be( + &mut self, data_len: u128, mut f: impl FnMut(&GenericArray), + ) { self.digest_pad(16, &mut f); - let s = self.size(); - BE::write_u64(&mut self.buffer[s-16..s-8], hi); - BE::write_u64(&mut self.buffer[s-8..], lo); + let b = data_len.to_be_bytes(); + let n = self.buffer.len() - b.len(); + self.buffer[n..].copy_from_slice(&b); f(&self.buffer); self.pos = 0; } @@ -175,6 +186,7 @@ impl> BlockBuffer { /// /// Returns `PadError` if internall buffer is full, which can only happen if /// `input_lazy` was used. + #[cfg(feature = "block-padding")] #[inline] pub fn pad_with(&mut self) -> Result<&mut GenericArray, PadError> @@ -208,3 +220,14 @@ impl> BlockBuffer { self.pos = 0 } } + +/// Sets all bytes in `dst` to zero +#[inline(always)] +fn set_zero(dst: &mut [u8]) { + // SAFETY: we overwrite valid memory behind `dst` + // note: loop is not used here because it produces + // unnecessary branch which tests for zero-length slices + unsafe { + core::ptr::write_bytes(dst.as_mut_ptr(), 0, dst.len()); + } +} diff --git a/vendor/cargo_metadata/.cargo-checksum.json b/vendor/cargo_metadata/.cargo-checksum.json index 3de50a81f7..1cbbe337d4 100644 --- a/vendor/cargo_metadata/.cargo-checksum.json +++ b/vendor/cargo_metadata/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"be8b1e989478350479ab1d521682ddf562f767023121a6d0ae603af545a23462","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"b1816348f92faff49f0b8caacb9b31f38333381ff7bb4abbd11ac5bcd92e45a1","src/dependency.rs":"c85c395f4cbd4fee0a7268c614dd69437b916339bca0f94b7a14917cd8b33aff","src/diagnostic.rs":"3d497083d3704289fa003a8ba06df41db929e067e36a90ebfcd51b411721debc","src/errors.rs":"b7d396821f3c031510e18b434011a351166448889bcbdffa3c4e96e593fff474","src/lib.rs":"8823b593ced1d95d10e83ac0341c34ad4336eddbb4d618e5baae317a4ecbdcae","src/messages.rs":"6183e5ca4e49d42118f43a7cb0293c6f6281ae6d8d7135dbaa94e5869f868c2d","tests/selftest.rs":"257436f1e219aadf9343d1cd2db7cc0748c7b89340ff43ae8b5c83fceb0a8b7f","tests/test_samples.rs":"7c4ad89485e470b0271c81763bddc4f533c821b2ab600b162433a7b95a22366c"},"package":"89fec17b16f1ac67908af82e47d0a90a7afd0e1827b181cd77504323d3263d35"} \ No newline at end of file +{"files":{"Cargo.toml":"f0e34187daaec536ba3bbfc307d951e213b2f60e7e522bbb7d86918dd90c919c","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"b1816348f92faff49f0b8caacb9b31f38333381ff7bb4abbd11ac5bcd92e45a1","src/dependency.rs":"c85c395f4cbd4fee0a7268c614dd69437b916339bca0f94b7a14917cd8b33aff","src/diagnostic.rs":"3d497083d3704289fa003a8ba06df41db929e067e36a90ebfcd51b411721debc","src/errors.rs":"b7d396821f3c031510e18b434011a351166448889bcbdffa3c4e96e593fff474","src/lib.rs":"69ef2145b406ded504821438da5f78ba87ccf9bd7e239af30d57665f01fb81cd","src/messages.rs":"6183e5ca4e49d42118f43a7cb0293c6f6281ae6d8d7135dbaa94e5869f868c2d","tests/selftest.rs":"257436f1e219aadf9343d1cd2db7cc0748c7b89340ff43ae8b5c83fceb0a8b7f","tests/test_samples.rs":"c52641f82f279157cf08eb8394bd53f8bd74493d27967db0d80eabd6069518d5"},"package":"c990b1694d29f8e477f456db1b2fcd5dd1cd6e29d5be082df45213e8834eb39a"} \ No newline at end of file diff --git a/vendor/cargo_metadata/Cargo.toml b/vendor/cargo_metadata/Cargo.toml index df37960a64..2ea3317f8f 100644 --- a/vendor/cargo_metadata/Cargo.toml +++ b/vendor/cargo_metadata/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "cargo_metadata" -version = "0.11.1" +version = "0.11.2" authors = ["Oliver Schneider "] description = "structured access to the output of `cargo metadata`" readme = "README.md" @@ -27,7 +27,7 @@ version = "0.10" features = ["serde"] [dependencies.serde] -version = "1.0.79" +version = "1.0.107" features = ["derive"] [dependencies.serde_json] diff --git a/vendor/cargo_metadata/src/lib.rs b/vendor/cargo_metadata/src/lib.rs index a06479db43..afb2599baa 100644 --- a/vendor/cargo_metadata/src/lib.rs +++ b/vendor/cargo_metadata/src/lib.rs @@ -380,6 +380,11 @@ pub struct Target { /// This is always `true` if running with a version of Cargo older than 1.37. #[serde(default = "default_true")] pub doctest: bool, + /// Whether or not this target is tested by default by `cargo test`. + /// + /// This is always `true` if running with a version of Cargo older than 1.47. + #[serde(default = "default_true")] + pub test: bool, #[doc(hidden)] #[serde(skip)] __do_not_match_exhaustively: (), diff --git a/vendor/cargo_metadata/tests/test_samples.rs b/vendor/cargo_metadata/tests/test_samples.rs index 58f30f5e5e..2a8f74bc0f 100644 --- a/vendor/cargo_metadata/tests/test_samples.rs +++ b/vendor/cargo_metadata/tests/test_samples.rs @@ -94,6 +94,7 @@ fn old_minimal() { assert_eq!(target.src_path, PathBuf::from("/foo/src/main.rs")); assert_eq!(target.edition, "2015"); assert_eq!(target.doctest, true); + assert_eq!(target.test, true); assert_eq!(pkg.features.len(), 0); assert_eq!(pkg.manifest_path, PathBuf::from("/foo/Cargo.toml")); assert_eq!(pkg.categories.len(), 0); @@ -141,10 +142,10 @@ fn cargo_version() -> semver::Version { #[test] fn all_the_fields() { - // All the fields currently generated as of 1.41. This tries to exercise as + // All the fields currently generated as of 1.47. This tries to exercise as // much as possible. let ver = cargo_version(); - let minimum = semver::Version::parse("1.41.0").unwrap(); + let minimum = semver::Version::parse("1.47.0").unwrap(); if ver < minimum { // edition added in 1.30 // rename added in 1.31 @@ -152,6 +153,7 @@ fn all_the_fields() { // doctest added in 1.37 // publish added in 1.39 // dep_kinds added in 1.41 + // test added in 1.47 eprintln!("Skipping all_the_fields test, cargo {} is too old.", ver); return; } @@ -262,11 +264,13 @@ fn all_the_fields() { assert_eq!(lib.required_features.len(), 0); assert_eq!(lib.edition, "2018"); assert_eq!(lib.doctest, true); + assert_eq!(lib.test, true); let main = get_file_name!("main.rs"); assert_eq!(main.crate_types, vec!["bin"]); assert_eq!(main.kind, vec!["bin"]); assert_eq!(main.doctest, false); + assert_eq!(main.test, true); let otherbin = get_file_name!("otherbin.rs"); assert_eq!(otherbin.edition, "2015"); @@ -276,6 +280,7 @@ fn all_the_fields() { let ex1 = get_file_name!("ex1.rs"); assert_eq!(ex1.kind, vec!["example"]); + assert_eq!(ex1.test, false); let t1 = get_file_name!("t1.rs"); assert_eq!(t1.kind, vec!["test"]); diff --git a/vendor/cc-1.0.59/.cargo-checksum.json b/vendor/cc-1.0.59/.cargo-checksum.json new file mode 100644 index 0000000000..a9252fa545 --- /dev/null +++ b/vendor/cc-1.0.59/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.lock":"bd34a585a35969291c78b96b1f239fa09f1f9dbeee48474989695def1ed64052","Cargo.toml":"cb73923110f764c2a6da0fde98db8f5f7c7194bd56e96e2f302da9ba29cba0a8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"68fe1bc9f8aab4d8d195e8bc39fe76562742dc392f5c490e5404e01463100277","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"96f4782c70e0bd8d9ab7ce3efcc2091d2591c3276c0ed672e2379748bb3930aa","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"} \ No newline at end of file diff --git a/vendor/cc-1.0.59/Cargo.lock b/vendor/cc-1.0.59/Cargo.lock new file mode 100644 index 0000000000..a624f35455 --- /dev/null +++ b/vendor/cc-1.0.59/Cargo.lock @@ -0,0 +1,145 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "cc" +version = "1.0.59" +dependencies = [ + "jobserver", + "tempfile", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "jobserver" +version = "0.1.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5c71313ebb9439f74b00d9d2dcec36440beaf57a6aa0623068441dd7cd81a7f2" +dependencies = [ + "libc", +] + +[[package]] +name = "libc" +version = "0.2.74" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +dependencies = [ + "getrandom", + "libc", + "rand_chacha", + "rand_core", + "rand_hc", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +dependencies = [ + "getrandom", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +dependencies = [ + "rand_core", +] + +[[package]] +name = "redox_syscall" +version = "0.1.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "41cc0f7e4d5d4544e8861606a285bb08d3e70712ccc7d2b84d7c0ccfaf4b05ce" + +[[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 = "tempfile" +version = "3.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6e24d9338a0a5be79593e2fa15a648add6138caa803e2d5bc782c371732ca9" +dependencies = [ + "cfg-if", + "libc", + "rand", + "redox_syscall", + "remove_dir_all", + "winapi", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/cc-1.0.59/Cargo.toml b/vendor/cc-1.0.59/Cargo.toml new file mode 100644 index 0000000000..2b3aac577f --- /dev/null +++ b/vendor/cc-1.0.59/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "cc" +version = "1.0.59" +authors = ["Alex Crichton "] +exclude = ["/.travis.yml", "/appveyor.yml"] +description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" +homepage = "https://github.com/alexcrichton/cc-rs" +documentation = "https://docs.rs/cc" +readme = "README.md" +keywords = ["build-dependencies"] +categories = ["development-tools::build-utils"] +license = "MIT/Apache-2.0" +repository = "https://github.com/alexcrichton/cc-rs" +[dependencies.jobserver] +version = "0.1.16" +optional = true +[dev-dependencies.tempfile] +version = "3" + +[features] +parallel = ["jobserver"] diff --git a/vendor/crossbeam-queue/LICENSE-APACHE b/vendor/cc-1.0.59/LICENSE-APACHE similarity index 100% rename from vendor/crossbeam-queue/LICENSE-APACHE rename to vendor/cc-1.0.59/LICENSE-APACHE diff --git a/vendor/parking_lot-0.10.2/LICENSE-MIT b/vendor/cc-1.0.59/LICENSE-MIT similarity index 95% rename from vendor/parking_lot-0.10.2/LICENSE-MIT rename to vendor/cc-1.0.59/LICENSE-MIT index 40b8817a47..39e0ed6602 100644 --- a/vendor/parking_lot-0.10.2/LICENSE-MIT +++ b/vendor/cc-1.0.59/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2016 The Rust Project Developers +Copyright (c) 2014 Alex Crichton Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/vendor/cc-1.0.59/README.md b/vendor/cc-1.0.59/README.md new file mode 100644 index 0000000000..e147d7e177 --- /dev/null +++ b/vendor/cc-1.0.59/README.md @@ -0,0 +1,195 @@ +# cc-rs + +A library to compile C/C++/assembly into a Rust library/application. + +[Documentation](https://docs.rs/cc) + +A simple library meant to be used as a build dependency with Cargo packages in +order to build a set of C/C++ files into a static archive. This crate calls out +to the most relevant compiler for a platform, for example using `cl` on MSVC. + +> **Note**: this crate was recently renamed from the `gcc` crate, so if you're +> looking for the `gcc` crate you're in the right spot! + +## Using cc-rs + +First, you'll want to both add a build script for your crate (`build.rs`) and +also add this crate to your `Cargo.toml` via: + +```toml +[build-dependencies] +cc = "1.0" +``` + +Next up, you'll want to write a build script like so: + +```rust,no_run +// build.rs + +fn main() { + cc::Build::new() + .file("foo.c") + .file("bar.c") + .compile("foo"); +} +``` + +And that's it! Running `cargo build` should take care of the rest and your Rust +application will now have the C files `foo.c` and `bar.c` compiled into a file +named libfoo.a. You can call the functions in Rust by declaring functions in +your Rust code like so: + +```rust,no_run +extern { + fn foo_function(); + fn bar_function(); +} + +pub fn call() { + unsafe { + foo_function(); + bar_function(); + } +} + +fn main() { + // ... +} +``` + +## External configuration via environment variables + +To control the programs and flags used for building, the builder can set a +number of different environment variables. + +* `CFLAGS` - a series of space separated flags passed to compilers. Note that + individual flags cannot currently contain spaces, so doing + something like: "-L=foo\ bar" is not possible. +* `CC` - the actual C compiler used. Note that this is used as an exact + executable name, so (for example) no extra flags can be passed inside + this variable, and the builder must ensure that there aren't any + trailing spaces. This compiler must understand the `-c` flag. For + certain `TARGET`s, it also is assumed to know about other flags (most + common is `-fPIC`). +* `AR` - the `ar` (archiver) executable to use to build the static library. +* `CRATE_CC_NO_DEFAULTS` - the default compiler flags may cause conflicts in some cross compiling scenarios. Setting this variable will disable the generation of default compiler flags. + +Each of these variables can also be supplied with certain prefixes and suffixes, +in the following prioritized order: + +1. `_` - for example, `CC_x86_64-unknown-linux-gnu` +2. `_` - for example, `CC_x86_64_unknown_linux_gnu` +3. `_` - for example, `HOST_CC` or `TARGET_CFLAGS` +4. `` - a plain `CC`, `AR` as above. + +If none of these variables exist, cc-rs uses built-in defaults + +In addition to the above optional environment variables, `cc-rs` has some +functions with hard requirements on some variables supplied by [cargo's +build-script driver][cargo] that it has the `TARGET`, `OUT_DIR`, `OPT_LEVEL`, +and `HOST` variables. + +[cargo]: http://doc.crates.io/build-script.html#inputs-to-the-build-script + +## Optional features + +### Parallel + +Currently cc-rs supports parallel compilation (think `make -jN`) but this +feature is turned off by default. To enable cc-rs to compile C/C++ in parallel, +you can change your dependency to: + +```toml +[build-dependencies] +cc = { version = "1.0", features = ["parallel"] } +``` + +By default cc-rs will limit parallelism to `$NUM_JOBS`, or if not present it +will limit it to the number of cpus on the machine. If you are using cargo, +use `-jN` option of `build`, `test` and `run` commands as `$NUM_JOBS` +is supplied by cargo. + +## Compile-time Requirements + +To work properly this crate needs access to a C compiler when the build script +is being run. This crate does not ship a C compiler with it. The compiler +required varies per platform, but there are three broad categories: + +* Unix platforms require `cc` to be the C compiler. This can be found by + installing cc/clang on Linux distributions and Xcode on OSX, for example. +* Windows platforms targeting MSVC (e.g. your target triple ends in `-msvc`) + require `cl.exe` to be available and in `PATH`. This is typically found in + standard Visual Studio installations and the `PATH` can be set up by running + the appropriate developer tools shell. +* Windows platforms targeting MinGW (e.g. your target triple ends in `-gnu`) + require `cc` to be available in `PATH`. We recommend the + [MinGW-w64](http://mingw-w64.org) distribution, which is using the + [Win-builds](http://win-builds.org) installation system. + You may also acquire it via + [MSYS2](http://msys2.github.io), as explained [here][msys2-help]. Make sure + to install the appropriate architecture corresponding to your installation of + rustc. GCC from older [MinGW](http://www.mingw.org) project is compatible + only with 32-bit rust compiler. + +[msys2-help]: http://github.com/rust-lang/rust#building-on-windows + +## C++ support + +`cc-rs` supports C++ libraries compilation by using the `cpp` method on +`Build`: + +```rust,no_run +fn main() { + cc::Build::new() + .cpp(true) // Switch to C++ library compilation. + .file("foo.cpp") + .compile("libfoo.a"); +} +``` + +When using C++ library compilation switch, the `CXX` and `CXXFLAGS` env +variables are used instead of `CC` and `CFLAGS` and the C++ standard library is +linked to the crate target. +Remember that C++ does name mangling so `extern "C"` might be required to enable rust linker to find your functions. + +## CUDA C++ support + +`cc-rs` also supports compiling CUDA C++ libraries by using the `cuda` method +on `Build` (currently for GNU/Clang toolchains only): + +```rust,no_run +fn main() { + cc::Build::new() + // Switch to CUDA C++ library compilation using NVCC. + .cuda(true) + // Generate code for Maxwell (GTX 970, 980, 980 Ti, Titan X). + .flag("-gencode").flag("arch=compute_52,code=sm_52") + // Generate code for Maxwell (Jetson TX1). + .flag("-gencode").flag("arch=compute_53,code=sm_53") + // Generate code for Pascal (GTX 1070, 1080, 1080 Ti, Titan Xp). + .flag("-gencode").flag("arch=compute_61,code=sm_61") + // Generate code for Pascal (Tesla P100). + .flag("-gencode").flag("arch=compute_60,code=sm_60") + // Generate code for Pascal (Jetson TX2). + .flag("-gencode").flag("arch=compute_62,code=sm_62") + .file("bar.cu") + .compile("libbar.a"); +} +``` + +## License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in cc-rs by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/vendor/cc-1.0.59/src/bin/gcc-shim.rs b/vendor/cc-1.0.59/src/bin/gcc-shim.rs new file mode 100644 index 0000000000..1731df82ea --- /dev/null +++ b/vendor/cc-1.0.59/src/bin/gcc-shim.rs @@ -0,0 +1,48 @@ +#![cfg_attr(test, allow(dead_code))] + +use std::env; +use std::fs::File; +use std::io::prelude::*; +use std::path::PathBuf; + +fn main() { + let mut args = env::args(); + let program = args.next().expect("Unexpected empty args"); + + let out_dir = PathBuf::from( + env::var_os("GCCTEST_OUT_DIR").expect(&format!("{}: GCCTEST_OUT_DIR not found", program)), + ); + + // Find the first nonexistent candidate file to which the program's args can be written. + for i in 0.. { + let candidate = &out_dir.join(format!("out{}", i)); + + // If the file exists, commands have already run. Try again. + if candidate.exists() { + continue; + } + + // Create a file and record the args passed to the command. + let mut f = File::create(candidate).expect(&format!( + "{}: can't create candidate: {}", + program, + candidate.to_string_lossy() + )); + for arg in args { + writeln!(f, "{}", arg).expect(&format!( + "{}: can't write to candidate: {}", + program, + candidate.to_string_lossy() + )); + } + break; + } + + // Create a file used by some tests. + let path = &out_dir.join("libfoo.a"); + File::create(path).expect(&format!( + "{}: can't create libfoo.a: {}", + program, + path.to_string_lossy() + )); +} diff --git a/vendor/cc-1.0.59/src/com.rs b/vendor/cc-1.0.59/src/com.rs new file mode 100644 index 0000000000..a5f2afedf4 --- /dev/null +++ b/vendor/cc-1.0.59/src/com.rs @@ -0,0 +1,155 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(unused)] + +use crate::winapi::CoInitializeEx; +use crate::winapi::IUnknown; +use crate::winapi::Interface; +use crate::winapi::BSTR; +use crate::winapi::COINIT_MULTITHREADED; +use crate::winapi::{SysFreeString, SysStringLen}; +use crate::winapi::{HRESULT, S_FALSE, S_OK}; +use std::ffi::{OsStr, OsString}; +use std::mem::forget; +use std::ops::Deref; +use std::os::windows::ffi::{OsStrExt, OsStringExt}; +use std::ptr::null_mut; +use std::slice::from_raw_parts; + +pub fn initialize() -> Result<(), HRESULT> { + let err = unsafe { CoInitializeEx(null_mut(), COINIT_MULTITHREADED) }; + if err != S_OK && err != S_FALSE { + // S_FALSE just means COM is already initialized + return Err(err); + } + Ok(()) +} + +pub struct ComPtr(*mut T) +where + T: Interface; +impl ComPtr +where + T: Interface, +{ + /// Creates a `ComPtr` to wrap a raw pointer. + /// It takes ownership over the pointer which means it does __not__ call `AddRef`. + /// `T` __must__ be a COM interface that inherits from `IUnknown`. + pub unsafe fn from_raw(ptr: *mut T) -> ComPtr { + assert!(!ptr.is_null()); + ComPtr(ptr) + } + /// Casts up the inheritance chain + pub fn up(self) -> ComPtr + where + T: Deref, + U: Interface, + { + ComPtr(self.into_raw() as *mut U) + } + /// Extracts the raw pointer. + /// You are now responsible for releasing it yourself. + pub fn into_raw(self) -> *mut T { + let p = self.0; + forget(self); + p + } + /// For internal use only. + fn as_unknown(&self) -> &IUnknown { + unsafe { &*(self.0 as *mut IUnknown) } + } + /// Performs QueryInterface fun. + pub fn cast(&self) -> Result, i32> + where + U: Interface, + { + let mut obj = null_mut(); + let err = unsafe { self.as_unknown().QueryInterface(&U::uuidof(), &mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { ComPtr::from_raw(obj as *mut U) }) + } +} +impl Deref for ComPtr +where + T: Interface, +{ + type Target = T; + fn deref(&self) -> &T { + unsafe { &*self.0 } + } +} +impl Clone for ComPtr +where + T: Interface, +{ + fn clone(&self) -> Self { + unsafe { + self.as_unknown().AddRef(); + ComPtr::from_raw(self.0) + } + } +} +impl Drop for ComPtr +where + T: Interface, +{ + fn drop(&mut self) { + unsafe { + self.as_unknown().Release(); + } + } +} +pub struct BStr(BSTR); +impl BStr { + pub unsafe fn from_raw(s: BSTR) -> BStr { + BStr(s) + } + pub fn to_osstring(&self) -> OsString { + let len = unsafe { SysStringLen(self.0) }; + let slice = unsafe { from_raw_parts(self.0, len as usize) }; + OsStringExt::from_wide(slice) + } +} +impl Drop for BStr { + fn drop(&mut self) { + unsafe { SysFreeString(self.0) }; + } +} + +pub trait ToWide { + fn to_wide(&self) -> Vec; + fn to_wide_null(&self) -> Vec; +} +impl ToWide for T +where + T: AsRef, +{ + fn to_wide(&self) -> Vec { + self.as_ref().encode_wide().collect() + } + fn to_wide_null(&self) -> Vec { + self.as_ref().encode_wide().chain(Some(0)).collect() + } +} +pub trait FromWide +where + Self: Sized, +{ + fn from_wide(wide: &[u16]) -> Self; + fn from_wide_null(wide: &[u16]) -> Self { + let len = wide.iter().take_while(|&&c| c != 0).count(); + Self::from_wide(&wide[..len]) + } +} +impl FromWide for OsString { + fn from_wide(wide: &[u16]) -> OsString { + OsStringExt::from_wide(wide) + } +} diff --git a/vendor/cc-1.0.59/src/lib.rs b/vendor/cc-1.0.59/src/lib.rs new file mode 100644 index 0000000000..fecc073056 --- /dev/null +++ b/vendor/cc-1.0.59/src/lib.rs @@ -0,0 +1,2960 @@ +//! A library for build scripts to compile custom C code +//! +//! This library is intended to be used as a `build-dependencies` entry in +//! `Cargo.toml`: +//! +//! ```toml +//! [build-dependencies] +//! cc = "1.0" +//! ``` +//! +//! The purpose of this crate is to provide the utility functions necessary to +//! compile C code into a static archive which is then linked into a Rust crate. +//! Configuration is available through the `Build` struct. +//! +//! This crate will automatically detect situations such as cross compilation or +//! other environment variables set by Cargo and will build code appropriately. +//! +//! The crate is not limited to C code, it can accept any source code that can +//! be passed to a C or C++ compiler. As such, assembly files with extensions +//! `.s` (gcc/clang) and `.asm` (MSVC) can also be compiled. +//! +//! [`Build`]: struct.Build.html +//! +//! # Parallelism +//! +//! To parallelize computation, enable the `parallel` feature for the crate. +//! +//! ```toml +//! [build-dependencies] +//! cc = { version = "1.0", features = ["parallel"] } +//! ``` +//! To specify the max number of concurrent compilation jobs, set the `NUM_JOBS` +//! environment variable to the desired amount. +//! +//! Cargo will also set this environment variable when executed with the `-jN` flag. +//! +//! If `NUM_JOBS` is not set, the `RAYON_NUM_THREADS` environment variable can +//! also specify the build parallelism. +//! +//! # Examples +//! +//! Use the `Build` struct to compile `src/foo.c`: +//! +//! ```no_run +//! fn main() { +//! cc::Build::new() +//! .file("src/foo.c") +//! .define("FOO", Some("bar")) +//! .include("src") +//! .compile("foo"); +//! } +//! ``` + +#![doc(html_root_url = "https://docs.rs/cc/1.0")] +#![cfg_attr(test, deny(warnings))] +#![allow(deprecated)] +#![deny(missing_docs)] + +use std::collections::HashMap; +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fmt::{self, Display}; +use std::fs; +use std::io::{self, BufRead, BufReader, Read, Write}; +use std::path::{Path, PathBuf}; +use std::process::{Child, Command, Stdio}; +use std::sync::{Arc, Mutex}; +use std::thread::{self, JoinHandle}; + +// These modules are all glue to support reading the MSVC version from +// the registry and from COM interfaces +#[cfg(windows)] +mod registry; +#[cfg(windows)] +#[macro_use] +mod winapi; +#[cfg(windows)] +mod com; +#[cfg(windows)] +mod setup_config; + +pub mod windows_registry; + +/// A builder for compilation of a native static library. +/// +/// A `Build` is the main type of the `cc` crate and is used to control all the +/// various configuration options and such of a compile. You'll find more +/// documentation on each method itself. +#[derive(Clone, Debug)] +pub struct Build { + include_directories: Vec, + definitions: Vec<(String, Option)>, + objects: Vec, + flags: Vec, + flags_supported: Vec, + known_flag_support_status: Arc>>, + ar_flags: Vec, + no_default_flags: bool, + files: Vec, + cpp: bool, + cpp_link_stdlib: Option>, + cpp_set_stdlib: Option, + cuda: bool, + target: Option, + host: Option, + out_dir: Option, + opt_level: Option, + debug: Option, + force_frame_pointer: Option, + env: Vec<(OsString, OsString)>, + compiler: Option, + archiver: Option, + cargo_metadata: bool, + pic: Option, + use_plt: Option, + static_crt: Option, + shared_flag: Option, + static_flag: Option, + warnings_into_errors: bool, + warnings: Option, + extra_warnings: Option, + env_cache: Arc>>>, + apple_sdk_root_cache: Arc>>, +} + +/// Represents the types of errors that may occur while using cc-rs. +#[derive(Clone, Debug)] +enum ErrorKind { + /// Error occurred while performing I/O. + IOError, + /// Invalid architecture supplied. + ArchitectureInvalid, + /// Environment variable not found, with the var in question as extra info. + EnvVarNotFound, + /// Error occurred while using external tools (ie: invocation of compiler). + ToolExecError, + /// Error occurred due to missing external tools. + ToolNotFound, +} + +/// Represents an internal error that occurred, with an explanation. +#[derive(Clone, Debug)] +pub struct Error { + /// Describes the kind of error that occurred. + kind: ErrorKind, + /// More explanation of error that occurred. + message: String, +} + +impl Error { + fn new(kind: ErrorKind, message: &str) -> Error { + Error { + kind: kind, + message: message.to_owned(), + } + } +} + +impl From for Error { + fn from(e: io::Error) -> Error { + Error::new(ErrorKind::IOError, &format!("{}", e)) + } +} + +impl Display for Error { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{:?}: {}", self.kind, self.message) + } +} + +impl std::error::Error for Error {} + +/// Configuration used to represent an invocation of a C compiler. +/// +/// This can be used to figure out what compiler is in use, what the arguments +/// to it are, and what the environment variables look like for the compiler. +/// This can be used to further configure other build systems (e.g. forward +/// along CC and/or CFLAGS) or the `to_command` method can be used to run the +/// compiler itself. +#[derive(Clone, Debug)] +pub struct Tool { + path: PathBuf, + cc_wrapper_path: Option, + cc_wrapper_args: Vec, + args: Vec, + env: Vec<(OsString, OsString)>, + family: ToolFamily, + cuda: bool, + removed_args: Vec, +} + +/// Represents the family of tools this tool belongs to. +/// +/// Each family of tools differs in how and what arguments they accept. +/// +/// Detection of a family is done on best-effort basis and may not accurately reflect the tool. +#[derive(Copy, Clone, Debug, PartialEq)] +enum ToolFamily { + /// Tool is GNU Compiler Collection-like. + Gnu, + /// Tool is Clang-like. It differs from the GCC in a sense that it accepts superset of flags + /// and its cross-compilation approach is different. + Clang, + /// Tool is the MSVC cl.exe. + Msvc { clang_cl: bool }, +} + +impl ToolFamily { + /// What the flag to request debug info for this family of tools look like + fn add_debug_flags(&self, cmd: &mut Tool) { + match *self { + ToolFamily::Msvc { .. } => { + cmd.push_cc_arg("-Z7".into()); + } + ToolFamily::Gnu | ToolFamily::Clang => { + cmd.push_cc_arg("-g".into()); + } + } + } + + /// What the flag to force frame pointers. + fn add_force_frame_pointer(&self, cmd: &mut Tool) { + match *self { + ToolFamily::Gnu | ToolFamily::Clang => { + cmd.push_cc_arg("-fno-omit-frame-pointer".into()); + } + _ => (), + } + } + + /// What the flags to enable all warnings + fn warnings_flags(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "-W4", + ToolFamily::Gnu | ToolFamily::Clang => "-Wall", + } + } + + /// What the flags to enable extra warnings + fn extra_warnings_flags(&self) -> Option<&'static str> { + match *self { + ToolFamily::Msvc { .. } => None, + ToolFamily::Gnu | ToolFamily::Clang => Some("-Wextra"), + } + } + + /// What the flag to turn warning into errors + fn warnings_to_errors_flag(&self) -> &'static str { + match *self { + ToolFamily::Msvc { .. } => "-WX", + ToolFamily::Gnu | ToolFamily::Clang => "-Werror", + } + } + + fn verbose_stderr(&self) -> bool { + *self == ToolFamily::Clang + } +} + +/// Represents an object. +/// +/// This is a source file -> object file pair. +#[derive(Clone, Debug)] +struct Object { + src: PathBuf, + dst: PathBuf, +} + +impl Object { + /// Create a new source file -> object file pair. + fn new(src: PathBuf, dst: PathBuf) -> Object { + Object { src: src, dst: dst } + } +} + +impl Build { + /// Construct a new instance of a blank set of configuration. + /// + /// This builder is finished with the [`compile`] function. + /// + /// [`compile`]: struct.Build.html#method.compile + pub fn new() -> Build { + Build { + include_directories: Vec::new(), + definitions: Vec::new(), + objects: Vec::new(), + flags: Vec::new(), + flags_supported: Vec::new(), + known_flag_support_status: Arc::new(Mutex::new(HashMap::new())), + ar_flags: Vec::new(), + no_default_flags: false, + files: Vec::new(), + shared_flag: None, + static_flag: None, + cpp: false, + cpp_link_stdlib: None, + cpp_set_stdlib: None, + cuda: false, + target: None, + host: None, + out_dir: None, + opt_level: None, + debug: None, + force_frame_pointer: None, + env: Vec::new(), + compiler: None, + archiver: None, + cargo_metadata: true, + pic: None, + use_plt: None, + static_crt: None, + warnings: None, + extra_warnings: None, + warnings_into_errors: false, + env_cache: Arc::new(Mutex::new(HashMap::new())), + apple_sdk_root_cache: Arc::new(Mutex::new(HashMap::new())), + } + } + + /// Add a directory to the `-I` or include path for headers + /// + /// # Example + /// + /// ```no_run + /// use std::path::Path; + /// + /// let library_path = Path::new("/path/to/library"); + /// + /// cc::Build::new() + /// .file("src/foo.c") + /// .include(library_path) + /// .include("src") + /// .compile("foo"); + /// ``` + pub fn include>(&mut self, dir: P) -> &mut Build { + self.include_directories.push(dir.as_ref().to_path_buf()); + self + } + + /// Specify a `-D` variable with an optional value. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .define("FOO", "BAR") + /// .define("BAZ", None) + /// .compile("foo"); + /// ``` + pub fn define<'a, V: Into>>(&mut self, var: &str, val: V) -> &mut Build { + self.definitions + .push((var.to_string(), val.into().map(|s| s.to_string()))); + self + } + + /// Add an arbitrary object file to link in + pub fn object>(&mut self, obj: P) -> &mut Build { + self.objects.push(obj.as_ref().to_path_buf()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag("-ffunction-sections") + /// .compile("foo"); + /// ``` + pub fn flag(&mut self, flag: &str) -> &mut Build { + self.flags.push(flag.to_string()); + self + } + + /// Add an arbitrary flag to the invocation of the compiler + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .file("src/bar.c") + /// .ar_flag("/NODEFAULTLIB:libc.dll") + /// .compile("foo"); + /// ``` + + pub fn ar_flag(&mut self, flag: &str) -> &mut Build { + self.ar_flags.push(flag.to_string()); + self + } + + fn ensure_check_file(&self) -> Result { + let out_dir = self.get_out_dir()?; + let src = if self.cuda { + assert!(self.cpp); + out_dir.join("flag_check.cu") + } else if self.cpp { + out_dir.join("flag_check.cpp") + } else { + out_dir.join("flag_check.c") + }; + + if !src.exists() { + let mut f = fs::File::create(&src)?; + write!(f, "int main(void) {{ return 0; }}")?; + } + + Ok(src) + } + + /// Run the compiler to test if it accepts the given flag. + /// + /// For a convenience method for setting flags conditionally, + /// see `flag_if_supported()`. + /// + /// It may return error if it's unable to run the compiler with a test file + /// (e.g. the compiler is missing or a write to the `out_dir` failed). + /// + /// Note: Once computed, the result of this call is stored in the + /// `known_flag_support` field. If `is_flag_supported(flag)` + /// is called again, the result will be read from the hash table. + pub fn is_flag_supported(&self, flag: &str) -> Result { + let mut known_status = self.known_flag_support_status.lock().unwrap(); + if let Some(is_supported) = known_status.get(flag).cloned() { + return Ok(is_supported); + } + + let out_dir = self.get_out_dir()?; + let src = self.ensure_check_file()?; + let obj = out_dir.join("flag_check"); + let target = self.get_target()?; + let host = self.get_host()?; + let mut cfg = Build::new(); + cfg.flag(flag) + .target(&target) + .opt_level(0) + .host(&host) + .debug(false) + .cpp(self.cpp) + .cuda(self.cuda); + let mut compiler = cfg.try_get_compiler()?; + + // Clang uses stderr for verbose output, which yields a false positive + // result if the CFLAGS/CXXFLAGS include -v to aid in debugging. + if compiler.family.verbose_stderr() { + compiler.remove_arg("-v".into()); + } + + let mut cmd = compiler.to_command(); + let is_arm = target.contains("aarch64") || target.contains("arm"); + let clang = compiler.family == ToolFamily::Clang; + command_add_output_file( + &mut cmd, + &obj, + self.cuda, + target.contains("msvc"), + clang, + false, + is_arm, + ); + + // We need to explicitly tell msvc not to link and create an exe + // in the root directory of the crate + if target.contains("msvc") && !self.cuda { + cmd.arg("-c"); + } + + cmd.arg(&src); + + let output = cmd.output()?; + let is_supported = output.stderr.is_empty(); + + known_status.insert(flag.to_owned(), is_supported); + Ok(is_supported) + } + + /// Add an arbitrary flag to the invocation of the compiler if it supports it + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .flag_if_supported("-Wlogical-op") // only supported by GCC + /// .flag_if_supported("-Wunreachable-code") // only supported by clang + /// .compile("foo"); + /// ``` + pub fn flag_if_supported(&mut self, flag: &str) -> &mut Build { + self.flags_supported.push(flag.to_string()); + self + } + + /// Set the `-shared` flag. + /// + /// When enabled, the compiler will produce a shared object which can + /// then be linked with other objects to form an executable. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .compile("libfoo.so"); + /// ``` + pub fn shared_flag(&mut self, shared_flag: bool) -> &mut Build { + self.shared_flag = Some(shared_flag); + self + } + + /// Set the `-static` flag. + /// + /// When enabled on systems that support dynamic linking, this prevents + /// linking with the shared libraries. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .static_flag(true) + /// .compile("foo"); + /// ``` + pub fn static_flag(&mut self, static_flag: bool) -> &mut Build { + self.static_flag = Some(static_flag); + self + } + + /// Disables the generation of default compiler flags. The default compiler + /// flags may cause conflicts in some cross compiling scenarios. + /// + /// Setting the `CRATE_CC_NO_DEFAULTS` environment variable has the same + /// effect as setting this to `true`. The presence of the environment + /// variable and the value of `no_default_flags` will be OR'd together. + pub fn no_default_flags(&mut self, no_default_flags: bool) -> &mut Build { + self.no_default_flags = no_default_flags; + self + } + + /// Add a file which will be compiled + pub fn file>(&mut self, p: P) -> &mut Build { + self.files.push(p.as_ref().to_path_buf()); + self + } + + /// Add files which will be compiled + pub fn files

    (&mut self, p: P) -> &mut Build + where + P: IntoIterator, + P::Item: AsRef, + { + for file in p.into_iter() { + self.file(file); + } + self + } + + /// Set C++ support. + /// + /// The other `cpp_*` options will only become active if this is set to + /// `true`. + pub fn cpp(&mut self, cpp: bool) -> &mut Build { + self.cpp = cpp; + self + } + + /// Set CUDA C++ support. + /// + /// Enabling CUDA will pass the detected C/C++ toolchain as an argument to + /// the CUDA compiler, NVCC. NVCC itself accepts some limited GNU-like args; + /// any other arguments for the C/C++ toolchain will be redirected using + /// "-Xcompiler" flags. + /// + /// If enabled, this also implicitly enables C++ support. + pub fn cuda(&mut self, cuda: bool) -> &mut Build { + self.cuda = cuda; + if cuda { + self.cpp = true; + } + self + } + + /// Set warnings into errors flag. + /// + /// Disabled by default. + /// + /// Warning: turning warnings into errors only make sense + /// if you are a developer of the crate using cc-rs. + /// Some warnings only appear on some architecture or + /// specific version of the compiler. Any user of this crate, + /// or any other crate depending on it, could fail during + /// compile time. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings_into_errors(true) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings_into_errors(&mut self, warnings_into_errors: bool) -> &mut Build { + self.warnings_into_errors = warnings_into_errors; + self + } + + /// Set warnings flags. + /// + /// Adds some flags: + /// - "-Wall" for MSVC. + /// - "-Wall", "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn warnings(&mut self, warnings: bool) -> &mut Build { + self.warnings = Some(warnings); + self.extra_warnings = Some(warnings); + self + } + + /// Set extra warnings flags. + /// + /// Adds some flags: + /// - nothing for MSVC. + /// - "-Wextra" for GNU and Clang. + /// + /// Enabled by default. + /// + /// # Example + /// + /// ```no_run + /// // Disables -Wextra, -Wall remains enabled: + /// cc::Build::new() + /// .file("src/foo.c") + /// .extra_warnings(false) + /// .compile("libfoo.a"); + /// ``` + pub fn extra_warnings(&mut self, warnings: bool) -> &mut Build { + self.extra_warnings = Some(warnings); + self + } + + /// Set the standard library to link against when compiling with C++ + /// support. + /// + /// The default value of this property depends on the current target: On + /// OS X `Some("c++")` is used, when compiling for a Visual Studio based + /// target `None` is used and for other targets `Some("stdc++")` is used. + /// If the `CXXSTDLIB` environment variable is set, its value will + /// override the default value. + /// + /// A value of `None` indicates that no automatic linking should happen, + /// otherwise cargo will link against the specified library. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .shared_flag(true) + /// .cpp_link_stdlib("stdc++") + /// .compile("libfoo.so"); + /// ``` + pub fn cpp_link_stdlib<'a, V: Into>>( + &mut self, + cpp_link_stdlib: V, + ) -> &mut Build { + self.cpp_link_stdlib = Some(cpp_link_stdlib.into().map(|s| s.into())); + self + } + + /// Force the C++ compiler to use the specified standard library. + /// + /// Setting this option will automatically set `cpp_link_stdlib` to the same + /// value. + /// + /// The default value of this option is always `None`. + /// + /// This option has no effect when compiling for a Visual Studio based + /// target. + /// + /// This option sets the `-stdlib` flag, which is only supported by some + /// compilers (clang, icc) but not by others (gcc). The library will not + /// detect which compiler is used, as such it is the responsibility of the + /// caller to ensure that this option is only used in conjuction with a + /// compiler which supports the `-stdlib` flag. + /// + /// A value of `None` indicates that no specific C++ standard library should + /// be used, otherwise `-stdlib` is added to the compile invocation. + /// + /// The given library name must not contain the `lib` prefix. + /// + /// Common values: + /// - `stdc++` for GNU + /// - `c++` for Clang + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .cpp_set_stdlib("c++") + /// .compile("libfoo.a"); + /// ``` + pub fn cpp_set_stdlib<'a, V: Into>>( + &mut self, + cpp_set_stdlib: V, + ) -> &mut Build { + let cpp_set_stdlib = cpp_set_stdlib.into(); + self.cpp_set_stdlib = cpp_set_stdlib.map(|s| s.into()); + self.cpp_link_stdlib(cpp_set_stdlib); + self + } + + /// Configures the target this configuration will be compiling for. + /// + /// This option is automatically scraped from the `TARGET` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .target("aarch64-linux-android") + /// .compile("foo"); + /// ``` + pub fn target(&mut self, target: &str) -> &mut Build { + self.target = Some(target.to_string()); + self + } + + /// Configures the host assumed by this configuration. + /// + /// This option is automatically scraped from the `HOST` environment + /// variable by build scripts, so it's not required to call this function. + /// + /// # Example + /// + /// ```no_run + /// cc::Build::new() + /// .file("src/foo.c") + /// .host("arm-linux-gnueabihf") + /// .compile("foo"); + /// ``` + pub fn host(&mut self, host: &str) -> &mut Build { + self.host = Some(host.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level(&mut self, opt_level: u32) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures the optimization level of the generated object files. + /// + /// This option is automatically scraped from the `OPT_LEVEL` environment + /// variable by build scripts, so it's not required to call this function. + pub fn opt_level_str(&mut self, opt_level: &str) -> &mut Build { + self.opt_level = Some(opt_level.to_string()); + self + } + + /// Configures whether the compiler will emit debug information when + /// generating object files. + /// + /// This option is automatically scraped from the `DEBUG` environment + /// variable by build scripts, so it's not required to call this function. + pub fn debug(&mut self, debug: bool) -> &mut Build { + self.debug = Some(debug); + self + } + + /// Configures whether the compiler will emit instructions to store + /// frame pointers during codegen. + /// + /// This option is automatically enabled when debug information is emitted. + /// Otherwise the target platform compiler's default will be used. + /// You can use this option to force a specific setting. + pub fn force_frame_pointer(&mut self, force: bool) -> &mut Build { + self.force_frame_pointer = Some(force); + self + } + + /// Configures the output directory where all object files and static + /// libraries will be located. + /// + /// This option is automatically scraped from the `OUT_DIR` environment + /// variable by build scripts, so it's not required to call this function. + pub fn out_dir>(&mut self, out_dir: P) -> &mut Build { + self.out_dir = Some(out_dir.as_ref().to_owned()); + self + } + + /// Configures the compiler to be used to produce output. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn compiler>(&mut self, compiler: P) -> &mut Build { + self.compiler = Some(compiler.as_ref().to_owned()); + self + } + + /// Configures the tool used to assemble archives. + /// + /// This option is automatically determined from the target platform or a + /// number of environment variables, so it's not required to call this + /// function. + pub fn archiver>(&mut self, archiver: P) -> &mut Build { + self.archiver = Some(archiver.as_ref().to_owned()); + self + } + /// Define whether metadata should be emitted for cargo allowing it to + /// automatically link the binary. Defaults to `true`. + /// + /// The emitted metadata is: + /// + /// - `rustc-link-lib=static=`*compiled lib* + /// - `rustc-link-search=native=`*target folder* + /// - When target is MSVC, the ATL-MFC libs are added via `rustc-link-search=native=` + /// - When C++ is enabled, the C++ stdlib is added via `rustc-link-lib` + /// + pub fn cargo_metadata(&mut self, cargo_metadata: bool) -> &mut Build { + self.cargo_metadata = cargo_metadata; + self + } + + /// Configures whether the compiler will emit position independent code. + /// + /// This option defaults to `false` for `windows-gnu` and bare metal targets and + /// to `true` for all other targets. + pub fn pic(&mut self, pic: bool) -> &mut Build { + self.pic = Some(pic); + self + } + + /// Configures whether the Procedure Linkage Table is used for indirect + /// calls into shared libraries. + /// + /// The PLT is used to provide features like lazy binding, but introduces + /// a small performance loss due to extra pointer indirection. Setting + /// `use_plt` to `false` can provide a small performance increase. + /// + /// Note that skipping the PLT requires a recent version of GCC/Clang. + /// + /// This only applies to ELF targets. It has no effect on other platforms. + pub fn use_plt(&mut self, use_plt: bool) -> &mut Build { + self.use_plt = Some(use_plt); + self + } + + /// Configures whether the /MT flag or the /MD flag will be passed to msvc build tools. + /// + /// This option defaults to `false`, and affect only msvc targets. + pub fn static_crt(&mut self, static_crt: bool) -> &mut Build { + self.static_crt = Some(static_crt); + self + } + + #[doc(hidden)] + pub fn __set_env(&mut self, a: A, b: B) -> &mut Build + where + A: AsRef, + B: AsRef, + { + self.env + .push((a.as_ref().to_owned(), b.as_ref().to_owned())); + self + } + + /// Run the compiler, generating the file `output` + /// + /// This will return a result instead of panicing; see compile() for the complete description. + pub fn try_compile(&self, output: &str) -> Result<(), Error> { + let (lib_name, gnu_lib_name) = if output.starts_with("lib") && output.ends_with(".a") { + (&output[3..output.len() - 2], output.to_owned()) + } else { + let mut gnu = String::with_capacity(5 + output.len()); + gnu.push_str("lib"); + gnu.push_str(&output); + gnu.push_str(".a"); + (output, gnu) + }; + let dst = self.get_out_dir()?; + + let mut objects = Vec::new(); + for file in self.files.iter() { + let obj = dst.join(file).with_extension("o"); + let obj = if !obj.starts_with(&dst) { + dst.join(obj.file_name().ok_or_else(|| { + Error::new(ErrorKind::IOError, "Getting object file details failed.") + })?) + } else { + obj + }; + + match obj.parent() { + Some(s) => fs::create_dir_all(s)?, + None => { + return Err(Error::new( + ErrorKind::IOError, + "Getting object file details failed.", + )); + } + }; + + objects.push(Object::new(file.to_path_buf(), obj)); + } + self.compile_objects(&objects)?; + self.assemble(lib_name, &dst.join(gnu_lib_name), &objects)?; + + if self.get_target()?.contains("msvc") { + let compiler = self.get_base_compiler()?; + let atlmfc_lib = compiler + .env() + .iter() + .find(|&&(ref var, _)| var.as_os_str() == OsStr::new("LIB")) + .and_then(|&(_, ref lib_paths)| { + env::split_paths(lib_paths).find(|path| { + let sub = Path::new("atlmfc/lib"); + path.ends_with(sub) || path.parent().map_or(false, |p| p.ends_with(sub)) + }) + }); + + if let Some(atlmfc_lib) = atlmfc_lib { + self.print(&format!( + "cargo:rustc-link-search=native={}", + atlmfc_lib.display() + )); + } + } + + self.print(&format!("cargo:rustc-link-lib=static={}", lib_name)); + self.print(&format!("cargo:rustc-link-search=native={}", dst.display())); + + // Add specific C++ libraries, if enabled. + if self.cpp { + if let Some(stdlib) = self.get_cpp_link_stdlib()? { + self.print(&format!("cargo:rustc-link-lib={}", stdlib)); + } + } + + Ok(()) + } + + /// Run the compiler, generating the file `output` + /// + /// The name `output` should be the name of the library. For backwards compatibility, + /// the `output` may start with `lib` and end with `.a`. The Rust compiler will create + /// the assembly with the lib prefix and .a extension. MSVC will create a file without prefix, + /// ending with `.lib`. + /// + /// # Panics + /// + /// Panics if `output` is not formatted correctly or if one of the underlying + /// compiler commands fails. It can also panic if it fails reading file names + /// or creating directories. + pub fn compile(&self, output: &str) { + if let Err(e) = self.try_compile(output) { + fail(&e.message); + } + } + + #[cfg(feature = "parallel")] + fn compile_objects<'me>(&'me self, objs: &[Object]) -> Result<(), Error> { + use std::sync::atomic::{AtomicBool, Ordering::SeqCst}; + use std::sync::Once; + + // Limit our parallelism globally with a jobserver. Start off by + // releasing our own token for this process so we can have a bit of an + // easier to write loop below. If this fails, though, then we're likely + // on Windows with the main implicit token, so we just have a bit extra + // parallelism for a bit and don't reacquire later. + let server = jobserver(); + let reacquire = server.release_raw().is_ok(); + + // When compiling objects in parallel we do a few dirty tricks to speed + // things up: + // + // * First is that we use the `jobserver` crate to limit the parallelism + // of this build script. The `jobserver` crate will use a jobserver + // configured by Cargo for build scripts to ensure that parallelism is + // coordinated across C compilations and Rust compilations. Before we + // compile anything we make sure to wait until we acquire a token. + // + // Note that this jobserver is cached globally so we only used one per + // process and only worry about creating it once. + // + // * Next we use a raw `thread::spawn` per thread to actually compile + // objects in parallel. We only actually spawn a thread after we've + // acquired a token to perform some work + // + // * Finally though we want to keep the dependencies of this crate + // pretty light, so we avoid using a safe abstraction like `rayon` and + // instead rely on some bits of `unsafe` code. We know that this stack + // frame persists while everything is compiling so we use all the + // stack-allocated objects without cloning/reallocating. We use a + // transmute to `State` with a `'static` lifetime to persist + // everything we need across the boundary, and the join-on-drop + // semantics of `JoinOnDrop` should ensure that our stack frame is + // alive while threads are alive. + // + // With all that in mind we compile all objects in a loop here, after we + // acquire the appropriate tokens, Once all objects have been compiled + // we join on all the threads and propagate the results of compilation. + // + // Note that as a slight optimization we try to break out as soon as + // possible as soon as any compilation fails to ensure that errors get + // out to the user as fast as possible. + let error = AtomicBool::new(false); + let mut threads = Vec::new(); + for obj in objs { + if error.load(SeqCst) { + break; + } + let token = server.acquire()?; + let state = State { + build: self, + obj, + error: &error, + }; + let state = unsafe { std::mem::transmute::>(state) }; + let thread = thread::spawn(|| { + let state: State<'me> = state; // erase the `'static` lifetime + let result = state.build.compile_object(state.obj); + if result.is_err() { + state.error.store(true, SeqCst); + } + drop(token); // make sure our jobserver token is released after the compile + return result; + }); + threads.push(JoinOnDrop(Some(thread))); + } + + for mut thread in threads { + if let Some(thread) = thread.0.take() { + thread.join().expect("thread should not panic")?; + } + } + + // Reacquire our process's token before we proceed, which we released + // before entering the loop above. + if reacquire { + server.acquire_raw()?; + } + + return Ok(()); + + /// Shared state from the parent thread to the child thread. This + /// package of pointers is temporarily transmuted to a `'static` + /// lifetime to cross the thread boundary and then once the thread is + /// running we erase the `'static` to go back to an anonymous lifetime. + struct State<'a> { + build: &'a Build, + obj: &'a Object, + error: &'a AtomicBool, + } + + /// Returns a suitable `jobserver::Client` used to coordinate + /// parallelism between build scripts. + fn jobserver() -> &'static jobserver::Client { + static INIT: Once = Once::new(); + static mut JOBSERVER: Option = None; + + fn _assert_sync() {} + _assert_sync::(); + + unsafe { + INIT.call_once(|| { + let server = default_jobserver(); + JOBSERVER = Some(server); + }); + JOBSERVER.as_ref().unwrap() + } + } + + unsafe fn default_jobserver() -> jobserver::Client { + // Try to use the environmental jobserver which Cargo typically + // initializes for us... + if let Some(client) = jobserver::Client::from_env() { + return client; + } + + // ... but if that fails for whatever reason select something + // reasonable and crate a new jobserver. Use `NUM_JOBS` if set (it's + // configured by Cargo) and otherwise just fall back to a + // semi-reasonable number. Note that we could use `num_cpus` here + // but it's an extra dependency that will almost never be used, so + // it's generally not too worth it. + let mut parallelism = 4; + if let Ok(amt) = env::var("NUM_JOBS") { + if let Ok(amt) = amt.parse() { + parallelism = amt; + } + } + + // If we create our own jobserver then be sure to reserve one token + // for ourselves. + let client = jobserver::Client::new(parallelism).expect("failed to create jobserver"); + client.acquire_raw().expect("failed to acquire initial"); + return client; + } + + struct JoinOnDrop(Option>>); + + impl Drop for JoinOnDrop { + fn drop(&mut self) { + if let Some(thread) = self.0.take() { + drop(thread.join()); + } + } + } + } + + #[cfg(not(feature = "parallel"))] + fn compile_objects(&self, objs: &[Object]) -> Result<(), Error> { + for obj in objs { + self.compile_object(obj)?; + } + Ok(()) + } + + fn compile_object(&self, obj: &Object) -> Result<(), Error> { + let is_asm = obj.src.extension().and_then(|s| s.to_str()) == Some("asm"); + let target = self.get_target()?; + let msvc = target.contains("msvc"); + let compiler = self.try_get_compiler()?; + let clang = compiler.family == ToolFamily::Clang; + let (mut cmd, name) = if msvc && is_asm { + self.msvc_macro_assembler()? + } else { + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + ( + cmd, + compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(), + ) + }; + let is_arm = target.contains("aarch64") || target.contains("arm"); + command_add_output_file(&mut cmd, &obj.dst, self.cuda, msvc, clang, is_asm, is_arm); + // armasm and armasm64 don't requrie -c option + if !msvc || !is_asm || !is_arm { + cmd.arg("-c"); + } + cmd.arg(&obj.src); + if cfg!(target_os = "macos") { + self.fix_env_for_apple_os(&mut cmd)?; + } + + run(&mut cmd, &name)?; + Ok(()) + } + + /// This will return a result instead of panicing; see expand() for the complete description. + pub fn try_expand(&self) -> Result, Error> { + let compiler = self.try_get_compiler()?; + let mut cmd = compiler.to_command(); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd.arg("-E"); + + assert!( + self.files.len() <= 1, + "Expand may only be called for a single file" + ); + + for file in self.files.iter() { + cmd.arg(file); + } + + let name = compiler + .path + .file_name() + .ok_or_else(|| Error::new(ErrorKind::IOError, "Failed to get compiler path."))? + .to_string_lossy() + .into_owned(); + + Ok(run_output(&mut cmd, &name)?) + } + + /// Run the compiler, returning the macro-expanded version of the input files. + /// + /// This is only relevant for C and C++ files. + /// + /// # Panics + /// Panics if more than one file is present in the config, or if compiler + /// path has an invalid file name. + /// + /// # Example + /// ```no_run + /// let out = cc::Build::new().file("src/foo.c").expand(); + /// ``` + pub fn expand(&self) -> Vec { + match self.try_expand() { + Err(e) => fail(&e.message), + Ok(v) => v, + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This function will return a `Tool` which represents the culmination + /// of this configuration at a snapshot in time. The returned compiler can + /// be inspected (e.g. the path, arguments, environment) to forward along to + /// other tools, or the `to_command` method can be used to invoke the + /// compiler itself. + /// + /// This method will take into account all configuration such as debug + /// information, optimization level, include directories, defines, etc. + /// Additionally, the compiler binary in use follows the standard + /// conventions for this path, e.g. looking at the explicitly set compiler, + /// environment variables (a number of which are inspected here), and then + /// falling back to the default configuration. + /// + /// # Panics + /// + /// Panics if an error occurred while determining the architecture. + pub fn get_compiler(&self) -> Tool { + match self.try_get_compiler() { + Ok(tool) => tool, + Err(e) => fail(&e.message), + } + } + + /// Get the compiler that's in use for this configuration. + /// + /// This will return a result instead of panicing; see get_compiler() for the complete description. + pub fn try_get_compiler(&self) -> Result { + let opt_level = self.get_opt_level()?; + let target = self.get_target()?; + + let mut cmd = self.get_base_compiler()?; + let envflags = self.envflags(if self.cpp { "CXXFLAGS" } else { "CFLAGS" }); + + // Disable default flag generation via `no_default_flags` or environment variable + let no_defaults = self.no_default_flags || self.getenv("CRATE_CC_NO_DEFAULTS").is_some(); + + if !no_defaults { + self.add_default_flags(&mut cmd, &target, &opt_level)?; + } else { + println!("Info: default compiler flags are disabled"); + } + + for arg in envflags { + cmd.push_cc_arg(arg.into()); + } + + for directory in self.include_directories.iter() { + cmd.args.push("-I".into()); + cmd.args.push(directory.into()); + } + + // If warnings and/or extra_warnings haven't been explicitly set, + // then we set them only if the environment doesn't already have + // CFLAGS/CXXFLAGS, since those variables presumably already contain + // the desired set of warnings flags. + + if self + .warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + let wflags = cmd.family.warnings_flags().into(); + cmd.push_cc_arg(wflags); + } + + if self + .extra_warnings + .unwrap_or(if self.has_flags() { false } else { true }) + { + if let Some(wflags) = cmd.family.extra_warnings_flags() { + cmd.push_cc_arg(wflags.into()); + } + } + + for flag in self.flags.iter() { + cmd.args.push(flag.into()); + } + + for flag in self.flags_supported.iter() { + if self.is_flag_supported(flag).unwrap_or(false) { + cmd.push_cc_arg(flag.into()); + } + } + + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.args.push(format!("-D{}={}", key, value).into()); + } else { + cmd.args.push(format!("-D{}", key).into()); + } + } + + if self.warnings_into_errors { + let warnings_to_errors_flag = cmd.family.warnings_to_errors_flag().into(); + cmd.push_cc_arg(warnings_to_errors_flag); + } + + Ok(cmd) + } + + fn add_default_flags( + &self, + cmd: &mut Tool, + target: &str, + opt_level: &str, + ) -> Result<(), Error> { + // Non-target flags + // If the flag is not conditioned on target variable, it belongs here :) + match cmd.family { + ToolFamily::Msvc { .. } => { + cmd.push_cc_arg("-nologo".into()); + + let crt_flag = match self.static_crt { + Some(true) => "-MT", + Some(false) => "-MD", + None => { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + "-MT" + } else { + "-MD" + } + } + }; + cmd.push_cc_arg(crt_flag.into()); + + match &opt_level[..] { + // Msvc uses /O1 to enable all optimizations that minimize code size. + "z" | "s" | "1" => cmd.push_opt_unless_duplicate("-O1".into()), + // -O3 is a valid value for gcc and clang compilers, but not msvc. Cap to /O2. + "2" | "3" => cmd.push_opt_unless_duplicate("-O2".into()), + _ => {} + } + } + ToolFamily::Gnu | ToolFamily::Clang => { + // arm-linux-androideabi-gcc 4.8 shipped with Android NDK does + // not support '-Oz' + if opt_level == "z" && cmd.family != ToolFamily::Clang { + cmd.push_opt_unless_duplicate("-Os".into()); + } else { + cmd.push_opt_unless_duplicate(format!("-O{}", opt_level).into()); + } + + if cmd.family == ToolFamily::Clang && target.contains("android") { + // For compatibility with code that doesn't use pre-defined `__ANDROID__` macro. + // If compiler used via ndk-build or cmake (officially supported build methods) + // this macros is defined. + // See https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/cmake/android.toolchain.cmake#456 + // https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/build/core/build-binary.mk#141 + cmd.push_opt_unless_duplicate("-DANDROID".into()); + } + + if !target.contains("-ios") { + cmd.push_cc_arg("-ffunction-sections".into()); + cmd.push_cc_arg("-fdata-sections".into()); + } + // Disable generation of PIC on bare-metal for now: rust-lld doesn't support this yet + if self + .pic + .unwrap_or(!target.contains("windows") && !target.contains("-none-")) + { + cmd.push_cc_arg("-fPIC".into()); + // PLT only applies if code is compiled with PIC support, + // and only for ELF targets. + if target.contains("linux") && !self.use_plt.unwrap_or(true) { + cmd.push_cc_arg("-fno-plt".into()); + } + } + } + } + + if self.get_debug() { + if self.cuda { + // NVCC debug flag + cmd.args.push("-G".into()); + } + let family = cmd.family; + family.add_debug_flags(cmd); + } + + if self.get_force_frame_pointer() { + let family = cmd.family; + family.add_force_frame_pointer(cmd); + } + + // Target flags + match cmd.family { + ToolFamily::Clang => { + if !(target.contains("android") + && android_clang_compiler_uses_target_arg_internally(&cmd.path)) + { + cmd.args.push(format!("--target={}", target).into()); + } + } + ToolFamily::Msvc { clang_cl } => { + // This is an undocumented flag from MSVC but helps with making + // builds more reproducible by avoiding putting timestamps into + // files. + cmd.push_cc_arg("-Brepro".into()); + + if clang_cl { + if target.contains("x86_64") { + cmd.push_cc_arg("-m64".into()); + } else if target.contains("86") { + cmd.push_cc_arg("-m32".into()); + cmd.push_cc_arg("-arch:IA32".into()); + } else { + cmd.push_cc_arg(format!("--target={}", target).into()); + } + } else { + if target.contains("i586") { + cmd.push_cc_arg("-arch:IA32".into()); + } + } + + // There is a check in corecrt.h that will generate a + // compilation error if + // _ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE is + // not defined to 1. The check was added in Windows + // 8 days because only store apps were allowed on ARM. + // This changed with the release of Windows 10 IoT Core. + // The check will be going away in future versions of + // the SDK, but for all released versions of the + // Windows SDK it is required. + if target.contains("arm") || target.contains("thumb") { + cmd.args + .push("-D_ARM_WINAPI_PARTITION_DESKTOP_SDK_AVAILABLE=1".into()); + } + } + ToolFamily::Gnu => { + if target.contains("i686") || target.contains("i586") { + cmd.args.push("-m32".into()); + } else if target == "x86_64-unknown-linux-gnux32" { + cmd.args.push("-mx32".into()); + } else if target.contains("x86_64") || target.contains("powerpc64") { + cmd.args.push("-m64".into()); + } + + if target.contains("darwin") { + if target.contains("x86_64") { + cmd.args.push("-arch".into()); + cmd.args.push("x86_64".into()); + } else if target.contains("arm64e") { + cmd.args.push("-arch".into()); + cmd.args.push("arm64e".into()); + } else if target.contains("aarch64") { + cmd.args.push("-arch".into()); + cmd.args.push("arm64".into()); + } + } + + if self.static_flag.is_none() { + let features = self + .getenv("CARGO_CFG_TARGET_FEATURE") + .unwrap_or(String::new()); + if features.contains("crt-static") { + cmd.args.push("-static".into()); + } + } + + // armv7 targets get to use armv7 instructions + if (target.starts_with("armv7") || target.starts_with("thumbv7")) + && target.contains("-linux-") + { + cmd.args.push("-march=armv7-a".into()); + } + + // (x86 Android doesn't say "eabi") + if target.contains("-androideabi") && target.contains("v7") { + // -march=armv7-a handled above + cmd.args.push("-mthumb".into()); + if !target.contains("neon") { + // On android we can guarantee some extra float instructions + // (specified in the android spec online) + // NEON guarantees even more; see below. + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + cmd.args.push("-mfloat-abi=softfp".into()); + } + + if target.contains("neon") { + cmd.args.push("-mfpu=neon-vfpv4".into()); + } + + if target.starts_with("armv4t-unknown-linux-") { + cmd.args.push("-march=armv4t".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + if target.starts_with("armv5te-unknown-linux-") { + cmd.args.push("-march=armv5te".into()); + cmd.args.push("-marm".into()); + cmd.args.push("-mfloat-abi=soft".into()); + } + + // For us arm == armv6 by default + if target.starts_with("arm-unknown-linux-") { + cmd.args.push("-march=armv6".into()); + cmd.args.push("-marm".into()); + if target.ends_with("hf") { + cmd.args.push("-mfpu=vfp".into()); + } else { + cmd.args.push("-mfloat-abi=soft".into()); + } + } + + // We can guarantee some settings for FRC + if target.starts_with("arm-frc-") { + cmd.args.push("-march=armv7-a".into()); + cmd.args.push("-mcpu=cortex-a9".into()); + cmd.args.push("-mfpu=vfpv3".into()); + cmd.args.push("-mfloat-abi=softfp".into()); + cmd.args.push("-marm".into()); + } + + // Turn codegen down on i586 to avoid some instructions. + if target.starts_with("i586-unknown-linux-") { + cmd.args.push("-march=pentium".into()); + } + + // Set codegen level for i686 correctly + if target.starts_with("i686-unknown-linux-") { + cmd.args.push("-march=i686".into()); + } + + // Looks like `musl-gcc` makes is hard for `-m32` to make its way + // all the way to the linker, so we need to actually instruct the + // linker that we're generating 32-bit executables as well. This'll + // typically only be used for build scripts which transitively use + // these flags that try to compile executables. + if target == "i686-unknown-linux-musl" || target == "i586-unknown-linux-musl" { + cmd.args.push("-Wl,-melf_i386".into()); + } + + if target.starts_with("thumb") { + cmd.args.push("-mthumb".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfloat-abi=hard".into()) + } + } + if target.starts_with("thumbv6m") { + cmd.args.push("-march=armv6s-m".into()); + } + if target.starts_with("thumbv7em") { + cmd.args.push("-march=armv7e-m".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv4-sp-d16".into()) + } + } + if target.starts_with("thumbv7m") { + cmd.args.push("-march=armv7-m".into()); + } + if target.starts_with("thumbv8m.base") { + cmd.args.push("-march=armv8-m.base".into()); + } + if target.starts_with("thumbv8m.main") { + cmd.args.push("-march=armv8-m.main".into()); + + if target.ends_with("eabihf") { + cmd.args.push("-mfpu=fpv5-sp-d16".into()) + } + } + if target.starts_with("armebv7r") | target.starts_with("armv7r") { + if target.starts_with("armeb") { + cmd.args.push("-mbig-endian".into()); + } else { + cmd.args.push("-mlittle-endian".into()); + } + + // ARM mode + cmd.args.push("-marm".into()); + + // R Profile + cmd.args.push("-march=armv7-r".into()); + + if target.ends_with("eabihf") { + // Calling convention + cmd.args.push("-mfloat-abi=hard".into()); + + // lowest common denominator FPU + // (see Cortex-R4 technical reference manual) + cmd.args.push("-mfpu=vfpv3-d16".into()) + } else { + // Calling convention + cmd.args.push("-mfloat-abi=soft".into()); + } + } + if target.starts_with("armv7a") { + cmd.args.push("-march=armv7-a".into()); + + if target.ends_with("eabihf") { + // lowest common denominator FPU + cmd.args.push("-mfpu=vfpv3-d16".into()); + } + } + if target.starts_with("riscv32") || target.starts_with("riscv64") { + // get the 32i/32imac/32imc/64gc/64imac/... part + let mut parts = target.split('-'); + if let Some(arch) = parts.next() { + let arch = &arch[5..]; + cmd.args.push(("-march=rv".to_owned() + arch).into()); + if target.contains("linux") && arch.starts_with("64") { + cmd.args.push("-mabi=lp64d".into()); + } else if target.contains("linux") && arch.starts_with("32") { + cmd.args.push("-mabi=ilp32d".into()); + } else if arch.starts_with("64") { + cmd.args.push("-mabi=lp64".into()); + } else { + cmd.args.push("-mabi=ilp32".into()); + } + cmd.args.push("-mcmodel=medany".into()); + } + } + } + } + + if target.contains("-ios") { + // FIXME: potential bug. iOS is always compiled with Clang, but Gcc compiler may be + // detected instead. + self.ios_flags(cmd)?; + } + + if self.static_flag.unwrap_or(false) { + cmd.args.push("-static".into()); + } + if self.shared_flag.unwrap_or(false) { + cmd.args.push("-shared".into()); + } + + if self.cpp { + match (self.cpp_set_stdlib.as_ref(), cmd.family) { + (None, _) => {} + (Some(stdlib), ToolFamily::Gnu) | (Some(stdlib), ToolFamily::Clang) => { + cmd.push_cc_arg(format!("-stdlib=lib{}", stdlib).into()); + } + _ => { + println!( + "cargo:warning=cpp_set_stdlib is specified, but the {:?} compiler \ + does not support this option, ignored", + cmd.family + ); + } + } + } + + Ok(()) + } + + fn has_flags(&self) -> bool { + let flags_env_var_name = if self.cpp { "CXXFLAGS" } else { "CFLAGS" }; + let flags_env_var_value = self.get_var(flags_env_var_name); + if let Ok(_) = flags_env_var_value { + true + } else { + false + } + } + + fn msvc_macro_assembler(&self) -> Result<(Command, String), Error> { + let target = self.get_target()?; + let tool = if target.contains("x86_64") { + "ml64.exe" + } else if target.contains("arm") { + "armasm.exe" + } else if target.contains("aarch64") { + "armasm64.exe" + } else { + "ml.exe" + }; + let mut cmd = windows_registry::find(&target, tool).unwrap_or_else(|| self.cmd(tool)); + cmd.arg("-nologo"); // undocumented, yet working with armasm[64] + for directory in self.include_directories.iter() { + cmd.arg("-I").arg(directory); + } + if target.contains("aarch64") || target.contains("arm") { + println!("cargo:warning=The MSVC ARM assemblers do not support -D flags"); + } else { + for &(ref key, ref value) in self.definitions.iter() { + if let Some(ref value) = *value { + cmd.arg(&format!("-D{}={}", key, value)); + } else { + cmd.arg(&format!("-D{}", key)); + } + } + } + + if target.contains("i686") || target.contains("i586") { + cmd.arg("-safeseh"); + } + for flag in self.flags.iter() { + cmd.arg(flag); + } + + Ok((cmd, tool.to_string())) + } + + fn assemble(&self, lib_name: &str, dst: &Path, objs: &[Object]) -> Result<(), Error> { + // Delete the destination if it exists as the `ar` tool at least on Unix + // appends to it, which we don't want. + let _ = fs::remove_file(&dst); + + let objects: Vec<_> = objs.iter().map(|obj| obj.dst.clone()).collect(); + let target = self.get_target()?; + if target.contains("msvc") { + let (mut cmd, program) = self.get_ar()?; + let mut out = OsString::from("-out:"); + out.push(dst); + cmd.arg(out).arg("-nologo"); + for flag in self.ar_flags.iter() { + cmd.arg(flag); + } + + // Similar to https://github.com/rust-lang/rust/pull/47507 + // and https://github.com/rust-lang/rust/pull/48548 + let estimated_command_line_len = objects + .iter() + .chain(&self.objects) + .map(|a| a.as_os_str().len()) + .sum::(); + if estimated_command_line_len > 1024 * 6 { + let mut args = String::from("\u{FEFF}"); // BOM + for arg in objects.iter().chain(&self.objects) { + args.push('"'); + for c in arg.to_str().unwrap().chars() { + if c == '"' { + args.push('\\') + } + args.push(c) + } + args.push('"'); + args.push('\n'); + } + + let mut utf16le = Vec::new(); + for code_unit in args.encode_utf16() { + utf16le.push(code_unit as u8); + utf16le.push((code_unit >> 8) as u8); + } + + let mut args_file = OsString::from(dst); + args_file.push(".args"); + fs::File::create(&args_file) + .unwrap() + .write_all(&utf16le) + .unwrap(); + + let mut args_file_arg = OsString::from("@"); + args_file_arg.push(args_file); + cmd.arg(args_file_arg); + } else { + cmd.args(&objects).args(&self.objects); + } + run(&mut cmd, &program)?; + + // The Rust compiler will look for libfoo.a and foo.lib, but the + // MSVC linker will also be passed foo.lib, so be sure that both + // exist for now. + let lib_dst = dst.with_file_name(format!("{}.lib", lib_name)); + let _ = fs::remove_file(&lib_dst); + match fs::hard_link(&dst, &lib_dst).or_else(|_| { + // if hard-link fails, just copy (ignoring the number of bytes written) + fs::copy(&dst, &lib_dst).map(|_| ()) + }) { + Ok(_) => (), + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Could not copy or create a hard-link to the generated lib file.", + )); + } + }; + } else { + let (mut ar, cmd) = self.get_ar()?; + + // Set an environment variable to tell the OSX archiver to ensure + // that all dates listed in the archive are zero, improving + // determinism of builds. AFAIK there's not really official + // documentation of this but there's a lot of references to it if + // you search google. + // + // You can reproduce this locally on a mac with: + // + // $ touch foo.c + // $ cc -c foo.c -o foo.o + // + // # Notice that these two checksums are different + // $ ar crus libfoo1.a foo.o && sleep 2 && ar crus libfoo2.a foo.o + // $ md5sum libfoo*.a + // + // # Notice that these two checksums are the same + // $ export ZERO_AR_DATE=1 + // $ ar crus libfoo1.a foo.o && sleep 2 && touch foo.o && ar crus libfoo2.a foo.o + // $ md5sum libfoo*.a + // + // In any case if this doesn't end up getting read, it shouldn't + // cause that many issues! + ar.env("ZERO_AR_DATE", "1"); + for flag in self.ar_flags.iter() { + ar.arg(flag); + } + run( + ar.arg("crs").arg(dst).args(&objects).args(&self.objects), + &cmd, + )?; + } + + Ok(()) + } + + fn ios_flags(&self, cmd: &mut Tool) -> Result<(), Error> { + enum ArchSpec { + Device(&'static str), + Simulator(&'static str), + } + + let target = self.get_target()?; + let arch = target.split('-').nth(0).ok_or_else(|| { + Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + ) + })?; + let arch = match arch { + "arm" | "armv7" | "thumbv7" => ArchSpec::Device("armv7"), + "armv7s" | "thumbv7s" => ArchSpec::Device("armv7s"), + "arm64e" => ArchSpec::Device("arm64e"), + "arm64" | "aarch64" => ArchSpec::Device("arm64"), + "i386" | "i686" => ArchSpec::Simulator("-m32"), + "x86_64" => ArchSpec::Simulator("-m64"), + _ => { + return Err(Error::new( + ErrorKind::ArchitectureInvalid, + "Unknown architecture for iOS target.", + )); + } + }; + + let min_version = + std::env::var("IPHONEOS_DEPLOYMENT_TARGET").unwrap_or_else(|_| "7.0".into()); + + let sdk = match arch { + ArchSpec::Device(arch) => { + cmd.args.push("-arch".into()); + cmd.args.push(arch.into()); + cmd.args + .push(format!("-miphoneos-version-min={}", min_version).into()); + "iphoneos" + } + ArchSpec::Simulator(arch) => { + cmd.args.push(arch.into()); + cmd.args + .push(format!("-mios-simulator-version-min={}", min_version).into()); + "iphonesimulator" + } + }; + + self.print(&format!("Detecting iOS SDK path for {}", sdk)); + let sdk_path = self.apple_sdk_root(sdk)?; + cmd.args.push("-isysroot".into()); + cmd.args.push(sdk_path); + cmd.args.push("-fembed-bitcode".into()); + /* + * TODO we probably ultimately want the -fembed-bitcode-marker flag + * but can't have it now because of an issue in LLVM: + * https://github.com/alexcrichton/cc-rs/issues/301 + * https://github.com/rust-lang/rust/pull/48896#comment-372192660 + */ + /* + if self.get_opt_level()? == "0" { + cmd.args.push("-fembed-bitcode-marker".into()); + } + */ + + Ok(()) + } + + fn cmd>(&self, prog: P) -> Command { + let mut cmd = Command::new(prog); + for &(ref a, ref b) in self.env.iter() { + cmd.env(a, b); + } + cmd + } + + fn get_base_compiler(&self) -> Result { + if let Some(ref c) = self.compiler { + return Ok(Tool::new(c.clone())); + } + let host = self.get_host()?; + let target = self.get_target()?; + let (env, msvc, gnu, traditional, clang) = if self.cpp { + ("CXX", "cl.exe", "g++", "c++", "clang++") + } else { + ("CC", "cl.exe", "gcc", "cc", "clang") + }; + + // On historical Solaris systems, "cc" may have been Sun Studio, which + // is not flag-compatible with "gcc". This history casts a long shadow, + // and many modern illumos distributions today ship GCC as "gcc" without + // also making it available as "cc". + let default = if host.contains("solaris") || host.contains("illumos") { + gnu + } else { + traditional + }; + + let cl_exe = windows_registry::find_tool(&target, "cl.exe"); + + let tool_opt: Option = self + .env_tool(env) + .map(|(tool, wrapper, args)| { + // find the driver mode, if any + const DRIVER_MODE: &str = "--driver-mode="; + let driver_mode = args + .iter() + .find(|a| a.starts_with(DRIVER_MODE)) + .map(|a| &a[DRIVER_MODE.len()..]); + // Chop off leading/trailing whitespace to work around + // semi-buggy build scripts which are shared in + // makefiles/configure scripts (where spaces are far more + // lenient) + let mut t = Tool::with_clang_driver(PathBuf::from(tool.trim()), driver_mode); + if let Some(cc_wrapper) = wrapper { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + } + for arg in args { + t.cc_wrapper_args.push(arg.into()); + } + t + }) + .or_else(|| { + if target.contains("emscripten") { + let tool = if self.cpp { "em++" } else { "emcc" }; + // Windows uses bat file so we have to be a bit more specific + if cfg!(windows) { + let mut t = Tool::new(PathBuf::from("cmd")); + t.args.push("/c".into()); + t.args.push(format!("{}.bat", tool).into()); + Some(t) + } else { + Some(Tool::new(PathBuf::from(tool))) + } + } else { + None + } + }) + .or_else(|| cl_exe.clone()); + + let tool = match tool_opt { + Some(t) => t, + None => { + let compiler = if host.contains("windows") && target.contains("windows") { + if target.contains("msvc") { + msvc.to_string() + } else { + format!("{}.exe", gnu) + } + } else if target.contains("android") { + autodetect_android_compiler(&target, &host, gnu, clang) + } else if target.contains("cloudabi") { + format!("{}-{}", target, traditional) + } else if target == "wasm32-wasi" + || target == "wasm32-unknown-wasi" + || target == "wasm32-unknown-unknown" + { + "clang".to_string() + } else if target.contains("vxworks") { + "wr-c++".to_string() + } else if self.get_host()? != target { + let prefix = self.prefix_for_target(&target); + match prefix { + Some(prefix) => format!("{}-{}", prefix, gnu), + None => default.to_string(), + } + } else { + default.to_string() + }; + + let mut t = Tool::new(PathBuf::from(compiler)); + if let Some(cc_wrapper) = Self::rustc_wrapper_fallback() { + t.cc_wrapper_path = Some(PathBuf::from(cc_wrapper)); + } + t + } + }; + + let mut tool = if self.cuda { + assert!( + tool.args.is_empty(), + "CUDA compilation currently assumes empty pre-existing args" + ); + let nvcc = match self.get_var("NVCC") { + Err(_) => "nvcc".into(), + Ok(nvcc) => nvcc, + }; + let mut nvcc_tool = Tool::with_features(PathBuf::from(nvcc), None, self.cuda); + nvcc_tool + .args + .push(format!("-ccbin={}", tool.path.display()).into()); + nvcc_tool.family = tool.family; + nvcc_tool + } else { + tool + }; + + // If we found `cl.exe` in our environment, the tool we're returning is + // an MSVC-like tool, *and* no env vars were set then set env vars for + // the tool that we're returning. + // + // Env vars are needed for things like `link.exe` being put into PATH as + // well as header include paths sometimes. These paths are automatically + // included by default but if the `CC` or `CXX` env vars are set these + // won't be used. This'll ensure that when the env vars are used to + // configure for invocations like `clang-cl` we still get a "works out + // of the box" experience. + if let Some(cl_exe) = cl_exe { + if tool.family == (ToolFamily::Msvc { clang_cl: true }) + && tool.env.len() == 0 + && target.contains("msvc") + { + for &(ref k, ref v) in cl_exe.env.iter() { + tool.env.push((k.to_owned(), v.to_owned())); + } + } + } + + Ok(tool) + } + + fn get_var(&self, var_base: &str) -> Result { + let target = self.get_target()?; + let host = self.get_host()?; + let kind = if host == target { "HOST" } else { "TARGET" }; + let target_u = target.replace("-", "_"); + let res = self + .getenv(&format!("{}_{}", var_base, target)) + .or_else(|| self.getenv(&format!("{}_{}", var_base, target_u))) + .or_else(|| self.getenv(&format!("{}_{}", kind, var_base))) + .or_else(|| self.getenv(var_base)); + + match res { + Some(res) => Ok(res), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Could not find environment variable {}.", var_base), + )), + } + } + + fn envflags(&self, name: &str) -> Vec { + self.get_var(name) + .unwrap_or(String::new()) + .split(|c: char| c.is_whitespace()) + .filter(|s| !s.is_empty()) + .map(|s| s.to_string()) + .collect() + } + + /// Returns a fallback `cc_compiler_wrapper` by introspecting `RUSTC_WRAPPER` + fn rustc_wrapper_fallback() -> Option { + // No explicit CC wrapper was detected, but check if RUSTC_WRAPPER + // is defined and is a build accelerator that is compatible with + // C/C++ compilers (e.g. sccache) + let valid_wrappers = ["sccache"]; + + let rustc_wrapper = std::env::var_os("RUSTC_WRAPPER")?; + let wrapper_path = Path::new(&rustc_wrapper); + let wrapper_stem = wrapper_path.file_stem()?; + + if valid_wrappers.contains(&wrapper_stem.to_str()?) { + Some(rustc_wrapper.to_str()?.to_owned()) + } else { + None + } + } + + /// Returns compiler path, optional modifier name from whitelist, and arguments vec + fn env_tool(&self, name: &str) -> Option<(String, Option, Vec)> { + let tool = match self.get_var(name) { + Ok(tool) => tool, + Err(_) => return None, + }; + + // If this is an exact path on the filesystem we don't want to do any + // interpretation at all, just pass it on through. This'll hopefully get + // us to support spaces-in-paths. + if Path::new(&tool).exists() { + return Some((tool, None, Vec::new())); + } + + // Ok now we want to handle a couple of scenarios. We'll assume from + // here on out that spaces are splitting separate arguments. Two major + // features we want to support are: + // + // CC='sccache cc' + // + // aka using `sccache` or any other wrapper/caching-like-thing for + // compilations. We want to know what the actual compiler is still, + // though, because our `Tool` API support introspection of it to see + // what compiler is in use. + // + // additionally we want to support + // + // CC='cc -flag' + // + // where the CC env var is used to also pass default flags to the C + // compiler. + // + // It's true that everything here is a bit of a pain, but apparently if + // you're not literally make or bash then you get a lot of bug reports. + let known_wrappers = ["ccache", "distcc", "sccache", "icecc"]; + + let mut parts = tool.split_whitespace(); + let maybe_wrapper = match parts.next() { + Some(s) => s, + None => return None, + }; + + let file_stem = Path::new(maybe_wrapper) + .file_stem() + .unwrap() + .to_str() + .unwrap(); + if known_wrappers.contains(&file_stem) { + if let Some(compiler) = parts.next() { + return Some(( + compiler.to_string(), + Some(maybe_wrapper.to_string()), + parts.map(|s| s.to_string()).collect(), + )); + } + } + + Some(( + maybe_wrapper.to_string(), + Self::rustc_wrapper_fallback(), + parts.map(|s| s.to_string()).collect(), + )) + } + + /// Returns the default C++ standard library for the current target: `libc++` + /// for OS X and `libstdc++` for anything else. + fn get_cpp_link_stdlib(&self) -> Result, Error> { + match self.cpp_link_stdlib.clone() { + Some(s) => Ok(s), + None => { + if let Ok(stdlib) = self.get_var("CXXSTDLIB") { + if stdlib.is_empty() { + Ok(None) + } else { + Ok(Some(stdlib)) + } + } else { + let target = self.get_target()?; + if target.contains("msvc") { + Ok(None) + } else if target.contains("apple") { + Ok(Some("c++".to_string())) + } else if target.contains("freebsd") { + Ok(Some("c++".to_string())) + } else if target.contains("openbsd") { + Ok(Some("c++".to_string())) + } else { + Ok(Some("stdc++".to_string())) + } + } + } + } + } + + fn get_ar(&self) -> Result<(Command, String), Error> { + if let Some(ref p) = self.archiver { + let name = p.file_name().and_then(|s| s.to_str()).unwrap_or("ar"); + return Ok((self.cmd(p), name.to_string())); + } + if let Ok(p) = self.get_var("AR") { + return Ok((self.cmd(&p), p)); + } + let target = self.get_target()?; + let default_ar = "ar".to_string(); + let program = if target.contains("android") { + format!("{}-ar", target.replace("armv7", "arm")) + } else if target.contains("emscripten") { + // Windows use bat files so we have to be a bit more specific + if cfg!(windows) { + let mut cmd = self.cmd("cmd"); + cmd.arg("/c").arg("emar.bat"); + return Ok((cmd, "emar.bat".to_string())); + } + + "emar".to_string() + } else if target.contains("msvc") { + match windows_registry::find(&target, "lib.exe") { + Some(t) => return Ok((t, "lib.exe".to_string())), + None => "lib.exe".to_string(), + } + } else if self.get_host()? != target { + match self.prefix_for_target(&target) { + Some(p) => { + let target_ar = format!("{}-ar", p); + if Command::new(&target_ar).output().is_ok() { + target_ar + } else { + default_ar + } + } + None => default_ar, + } + } else { + default_ar + }; + Ok((self.cmd(&program), program)) + } + + fn prefix_for_target(&self, target: &str) -> Option { + // CROSS_COMPILE is of the form: "arm-linux-gnueabi-" + let cc_env = self.getenv("CROSS_COMPILE"); + let cross_compile = cc_env + .as_ref() + .map(|s| s.trim_right_matches('-').to_owned()); + cross_compile.or(match &target[..] { + "aarch64-unknown-linux-gnu" => Some("aarch64-linux-gnu"), + "aarch64-unknown-linux-musl" => Some("aarch64-linux-musl"), + "aarch64-unknown-netbsd" => Some("aarch64--netbsd"), + "arm-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv4t-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv5te-unknown-linux-musleabi" => Some("arm-linux-gnueabi"), + "arm-frc-linux-gnueabi" => Some("arm-frc-linux-gnueabi"), + "arm-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "arm-unknown-linux-musleabi" => Some("arm-linux-musleabi"), + "arm-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "arm-unknown-netbsd-eabi" => Some("arm--netbsdelf-eabi"), + "armv6-unknown-netbsd-eabihf" => Some("armv6--netbsdelf-eabihf"), + "armv7-unknown-linux-gnueabi" => Some("arm-linux-gnueabi"), + "armv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "armv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "thumbv7neon-unknown-linux-gnueabihf" => Some("arm-linux-gnueabihf"), + "thumbv7neon-unknown-linux-musleabihf" => Some("arm-linux-musleabihf"), + "armv7-unknown-netbsd-eabihf" => Some("armv7--netbsdelf-eabihf"), + "hexagon-unknown-linux-musl" => Some("hexagon-linux-musl"), + "i586-unknown-linux-musl" => Some("musl"), + "i686-pc-windows-gnu" => Some("i686-w64-mingw32"), + "i686-uwp-windows-gnu" => Some("i686-w64-mingw32"), + "i686-unknown-linux-musl" => Some("musl"), + "i686-unknown-netbsd" => Some("i486--netbsdelf"), + "mips-unknown-linux-gnu" => Some("mips-linux-gnu"), + "mipsel-unknown-linux-gnu" => Some("mipsel-linux-gnu"), + "mips64-unknown-linux-gnuabi64" => Some("mips64-linux-gnuabi64"), + "mips64el-unknown-linux-gnuabi64" => Some("mips64el-linux-gnuabi64"), + "mipsisa32r6-unknown-linux-gnu" => Some("mipsisa32r6-linux-gnu"), + "mipsisa32r6el-unknown-linux-gnu" => Some("mipsisa32r6el-linux-gnu"), + "mipsisa64r6-unknown-linux-gnuabi64" => Some("mipsisa64r6-linux-gnuabi64"), + "mipsisa64r6el-unknown-linux-gnuabi64" => Some("mipsisa64r6el-linux-gnuabi64"), + "powerpc-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc-unknown-linux-gnuspe" => Some("powerpc-linux-gnuspe"), + "powerpc-unknown-netbsd" => Some("powerpc--netbsd"), + "powerpc64-unknown-linux-gnu" => Some("powerpc-linux-gnu"), + "powerpc64le-unknown-linux-gnu" => Some("powerpc64le-linux-gnu"), + "riscv32i-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv32imc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv32-unknown-elf", + "riscv64-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64imac-unknown-none-elf" => self.find_working_gnu_prefix(&[ + "riscv64-unknown-elf", + "riscv32-unknown-elf", + "riscv-none-embed", + ]), + "riscv64gc-unknown-linux-gnu" => Some("riscv64-linux-gnu"), + "s390x-unknown-linux-gnu" => Some("s390x-linux-gnu"), + "sparc-unknown-linux-gnu" => Some("sparc-linux-gnu"), + "sparc64-unknown-linux-gnu" => Some("sparc64-linux-gnu"), + "sparc64-unknown-netbsd" => Some("sparc64--netbsd"), + "sparcv9-sun-solaris" => Some("sparcv9-sun-solaris"), + "armv7a-none-eabi" => Some("arm-none-eabi"), + "armv7a-none-eabihf" => Some("arm-none-eabi"), + "armebv7r-none-eabi" => Some("arm-none-eabi"), + "armebv7r-none-eabihf" => Some("arm-none-eabi"), + "armv7r-none-eabi" => Some("arm-none-eabi"), + "armv7r-none-eabihf" => Some("arm-none-eabi"), + "thumbv6m-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabi" => Some("arm-none-eabi"), + "thumbv7em-none-eabihf" => Some("arm-none-eabi"), + "thumbv7m-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.base-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabi" => Some("arm-none-eabi"), + "thumbv8m.main-none-eabihf" => Some("arm-none-eabi"), + "x86_64-pc-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-uwp-windows-gnu" => Some("x86_64-w64-mingw32"), + "x86_64-rumprun-netbsd" => Some("x86_64-rumprun-netbsd"), + "x86_64-unknown-linux-musl" => Some("musl"), + "x86_64-unknown-netbsd" => Some("x86_64--netbsd"), + _ => None, + } + .map(|x| x.to_owned())) + } + + /// Some platforms have multiple, compatible, canonical prefixes. Look through + /// each possible prefix for a compiler that exists and return it. The prefixes + /// should be ordered from most-likely to least-likely. + fn find_working_gnu_prefix(&self, prefixes: &[&'static str]) -> Option<&'static str> { + let suffix = if self.cpp { "-g++" } else { "-gcc" }; + let extension = std::env::consts::EXE_SUFFIX; + + // Loop through PATH entries searching for each toolchain. This ensures that we + // are more likely to discover the toolchain early on, because chances are good + // that the desired toolchain is in one of the higher-priority paths. + env::var_os("PATH") + .as_ref() + .and_then(|path_entries| { + env::split_paths(path_entries).find_map(|path_entry| { + for prefix in prefixes { + let target_compiler = format!("{}{}{}", prefix, suffix, extension); + if path_entry.join(&target_compiler).exists() { + return Some(prefix); + } + } + None + }) + }) + .map(|prefix| *prefix) + .or_else(|| + // If no toolchain was found, provide the first toolchain that was passed in. + // This toolchain has been shown not to exist, however it will appear in the + // error that is shown to the user which should make it easier to search for + // where it should be obtained. + prefixes.first().map(|prefix| *prefix)) + } + + fn get_target(&self) -> Result { + match self.target.clone() { + Some(t) => Ok(t), + None => Ok(self.getenv_unwrap("TARGET")?), + } + } + + fn get_host(&self) -> Result { + match self.host.clone() { + Some(h) => Ok(h), + None => Ok(self.getenv_unwrap("HOST")?), + } + } + + fn get_opt_level(&self) -> Result { + match self.opt_level.as_ref().cloned() { + Some(ol) => Ok(ol), + None => Ok(self.getenv_unwrap("OPT_LEVEL")?), + } + } + + fn get_debug(&self) -> bool { + self.debug.unwrap_or_else(|| match self.getenv("DEBUG") { + Some(s) => s != "false", + None => false, + }) + } + + fn get_force_frame_pointer(&self) -> bool { + self.force_frame_pointer.unwrap_or_else(|| self.get_debug()) + } + + fn get_out_dir(&self) -> Result { + match self.out_dir.clone() { + Some(p) => Ok(p), + None => Ok(env::var_os("OUT_DIR").map(PathBuf::from).ok_or_else(|| { + Error::new( + ErrorKind::EnvVarNotFound, + "Environment variable OUT_DIR not defined.", + ) + })?), + } + } + + fn getenv(&self, v: &str) -> Option { + let mut cache = self.env_cache.lock().unwrap(); + if let Some(val) = cache.get(v) { + return val.clone(); + } + let r = env::var(v).ok(); + self.print(&format!("{} = {:?}", v, r)); + cache.insert(v.to_string(), r.clone()); + r + } + + fn getenv_unwrap(&self, v: &str) -> Result { + match self.getenv(v) { + Some(s) => Ok(s), + None => Err(Error::new( + ErrorKind::EnvVarNotFound, + &format!("Environment variable {} not defined.", v.to_string()), + )), + } + } + + fn print(&self, s: &str) { + if self.cargo_metadata { + println!("{}", s); + } + } + + fn fix_env_for_apple_os(&self, cmd: &mut Command) -> Result<(), Error> { + let target = self.get_target()?; + let host = self.get_host()?; + if host.contains("apple-darwin") && target.contains("apple-darwin") { + // If, for example, `cargo` runs during the build of an XCode project, then `SDKROOT` environment variable + // would represent the current target, and this is the problem for us, if we want to compile something + // for the host, when host != target. + // We can not just remove `SDKROOT`, because, again, for example, XCode add to PATH + // /Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin + // and `cc` from this path can not find system include files, like `pthread.h`, if `SDKROOT` + // is not set + if let Ok(sdkroot) = env::var("SDKROOT") { + if !sdkroot.contains("MacOSX") { + let macos_sdk = self.apple_sdk_root("macosx")?; + cmd.env("SDKROOT", macos_sdk); + } + } + // Additionally, `IPHONEOS_DEPLOYMENT_TARGET` must not be set when using the Xcode linker at + // "/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/ld", + // although this is apparently ignored when using the linker at "/usr/bin/ld". + cmd.env_remove("IPHONEOS_DEPLOYMENT_TARGET"); + } + Ok(()) + } + + fn apple_sdk_root(&self, sdk: &str) -> Result { + let mut cache = self + .apple_sdk_root_cache + .lock() + .expect("apple_sdk_root_cache lock failed"); + if let Some(ret) = cache.get(sdk) { + return Ok(ret.clone()); + } + + let sdk_path = self + .cmd("xcrun") + .arg("--show-sdk-path") + .arg("--sdk") + .arg(sdk) + .stderr(Stdio::inherit()) + .output()? + .stdout; + + let sdk_path = match String::from_utf8(sdk_path) { + Ok(p) => p, + Err(_) => { + return Err(Error::new( + ErrorKind::IOError, + "Unable to determine iOS SDK path.", + )); + } + }; + let ret: OsString = sdk_path.trim().into(); + cache.insert(sdk.into(), ret.clone()); + Ok(ret) + } +} + +impl Default for Build { + fn default() -> Build { + Build::new() + } +} + +impl Tool { + fn new(path: PathBuf) -> Self { + Tool::with_features(path, None, false) + } + + fn with_clang_driver(path: PathBuf, clang_driver: Option<&str>) -> Self { + Self::with_features(path, clang_driver, false) + } + + #[cfg(windows)] + /// Explictly set the `ToolFamily`, skipping name-based detection. + fn with_family(path: PathBuf, family: ToolFamily) -> Self { + Self { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: false, + removed_args: Vec::new(), + } + } + + fn with_features(path: PathBuf, clang_driver: Option<&str>, cuda: bool) -> Self { + // Try to detect family of the tool from its name, falling back to Gnu. + let family = if let Some(fname) = path.file_name().and_then(|p| p.to_str()) { + if fname.contains("clang-cl") { + ToolFamily::Msvc { clang_cl: true } + } else if fname.contains("cl") + && !fname.contains("cloudabi") + && !fname.contains("uclibc") + && !fname.contains("clang") + { + ToolFamily::Msvc { clang_cl: false } + } else if fname.contains("clang") { + match clang_driver { + Some("cl") => ToolFamily::Msvc { clang_cl: true }, + _ => ToolFamily::Clang, + } + } else { + ToolFamily::Gnu + } + } else { + ToolFamily::Gnu + }; + + Tool { + path: path, + cc_wrapper_path: None, + cc_wrapper_args: Vec::new(), + args: Vec::new(), + env: Vec::new(), + family: family, + cuda: cuda, + removed_args: Vec::new(), + } + } + + /// Add an argument to be stripped from the final command arguments. + fn remove_arg(&mut self, flag: OsString) { + self.removed_args.push(flag); + } + + /// Add a flag, and optionally prepend the NVCC wrapper flag "-Xcompiler". + /// + /// Currently this is only used for compiling CUDA sources, since NVCC only + /// accepts a limited set of GNU-like flags, and the rest must be prefixed + /// with a "-Xcompiler" flag to get passed to the underlying C++ compiler. + fn push_cc_arg(&mut self, flag: OsString) { + if self.cuda { + self.args.push("-Xcompiler".into()); + } + self.args.push(flag); + } + + fn is_duplicate_opt_arg(&self, flag: &OsString) -> bool { + let flag = flag.to_str().unwrap(); + let mut chars = flag.chars(); + + // Only duplicate check compiler flags + if self.is_like_msvc() { + if chars.next() != Some('/') { + return false; + } + } else if self.is_like_gnu() || self.is_like_clang() { + if chars.next() != Some('-') { + return false; + } + } + + // Check for existing optimization flags (-O, /O) + if chars.next() == Some('O') { + return self + .args() + .iter() + .any(|ref a| a.to_str().unwrap_or("").chars().nth(1) == Some('O')); + } + + // TODO Check for existing -m..., -m...=..., /arch:... flags + return false; + } + + /// Don't push optimization arg if it conflicts with existing args + fn push_opt_unless_duplicate(&mut self, flag: OsString) { + if self.is_duplicate_opt_arg(&flag) { + println!("Info: Ignoring duplicate arg {:?}", &flag); + } else { + self.push_cc_arg(flag); + } + } + + /// Converts this compiler into a `Command` that's ready to be run. + /// + /// This is useful for when the compiler needs to be executed and the + /// command returned will already have the initial arguments and environment + /// variables configured. + pub fn to_command(&self) -> Command { + let mut cmd = match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cmd = Command::new(&cc_wrapper_path); + cmd.arg(&self.path); + cmd + } + None => Command::new(&self.path), + }; + cmd.args(&self.cc_wrapper_args); + + let value = self + .args + .iter() + .filter(|a| !self.removed_args.contains(a)) + .collect::>(); + cmd.args(&value); + + for &(ref k, ref v) in self.env.iter() { + cmd.env(k, v); + } + cmd + } + + /// Returns the path for this compiler. + /// + /// Note that this may not be a path to a file on the filesystem, e.g. "cc", + /// but rather something which will be resolved when a process is spawned. + pub fn path(&self) -> &Path { + &self.path + } + + /// Returns the default set of arguments to the compiler needed to produce + /// executables for the target this compiler generates. + pub fn args(&self) -> &[OsString] { + &self.args + } + + /// Returns the set of environment variables needed for this compiler to + /// operate. + /// + /// This is typically only used for MSVC compilers currently. + pub fn env(&self) -> &[(OsString, OsString)] { + &self.env + } + + /// Returns the compiler command in format of CC environment variable. + /// Or empty string if CC env was not present + /// + /// This is typically used by configure script + pub fn cc_env(&self) -> OsString { + match self.cc_wrapper_path { + Some(ref cc_wrapper_path) => { + let mut cc_env = cc_wrapper_path.as_os_str().to_owned(); + cc_env.push(" "); + cc_env.push(self.path.to_path_buf().into_os_string()); + for arg in self.cc_wrapper_args.iter() { + cc_env.push(" "); + cc_env.push(arg); + } + cc_env + } + None => OsString::from(""), + } + } + + /// Returns the compiler flags in format of CFLAGS environment variable. + /// Important here - this will not be CFLAGS from env, its internal gcc's flags to use as CFLAGS + /// This is typically used by configure script + pub fn cflags_env(&self) -> OsString { + let mut flags = OsString::new(); + for (i, arg) in self.args.iter().enumerate() { + if i > 0 { + flags.push(" "); + } + flags.push(arg); + } + flags + } + + /// Whether the tool is GNU Compiler Collection-like. + pub fn is_like_gnu(&self) -> bool { + self.family == ToolFamily::Gnu + } + + /// Whether the tool is Clang-like. + pub fn is_like_clang(&self) -> bool { + self.family == ToolFamily::Clang + } + + /// Whether the tool is MSVC-like. + pub fn is_like_msvc(&self) -> bool { + match self.family { + ToolFamily::Msvc { .. } => true, + _ => false, + } + } +} + +fn run(cmd: &mut Command, program: &str) -> Result<(), Error> { + let (mut child, print) = spawn(cmd, program)?; + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(()) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn run_output(cmd: &mut Command, program: &str) -> Result, Error> { + cmd.stdout(Stdio::piped()); + let (mut child, print) = spawn(cmd, program)?; + let mut stdout = vec![]; + child + .stdout + .take() + .unwrap() + .read_to_end(&mut stdout) + .unwrap(); + let status = match child.wait() { + Ok(s) => s, + Err(_) => { + return Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Failed to wait on spawned child process, command {:?} with args {:?}.", + cmd, program + ), + )); + } + }; + print.join().unwrap(); + println!("{}", status); + + if status.success() { + Ok(stdout) + } else { + Err(Error::new( + ErrorKind::ToolExecError, + &format!( + "Command {:?} with args {:?} did not execute successfully (status code {}).", + cmd, program, status + ), + )) + } +} + +fn spawn(cmd: &mut Command, program: &str) -> Result<(Child, JoinHandle<()>), Error> { + println!("running: {:?}", cmd); + + // Capture the standard error coming from these programs, and write it out + // with cargo:warning= prefixes. Note that this is a bit wonky to avoid + // requiring the output to be UTF-8, we instead just ship bytes from one + // location to another. + match cmd.stderr(Stdio::piped()).spawn() { + Ok(mut child) => { + let stderr = BufReader::new(child.stderr.take().unwrap()); + let print = thread::spawn(move || { + for line in stderr.split(b'\n').filter_map(|l| l.ok()) { + print!("cargo:warning="); + std::io::stdout().write_all(&line).unwrap(); + println!(""); + } + }); + Ok((child, print)) + } + Err(ref e) if e.kind() == io::ErrorKind::NotFound => { + let extra = if cfg!(windows) { + " (see https://github.com/alexcrichton/cc-rs#compile-time-requirements \ + for help)" + } else { + "" + }; + Err(Error::new( + ErrorKind::ToolNotFound, + &format!("Failed to find tool. Is `{}` installed?{}", program, extra), + )) + } + Err(_) => Err(Error::new( + ErrorKind::ToolExecError, + &format!("Command {:?} with args {:?} failed to start.", cmd, program), + )), + } +} + +fn fail(s: &str) -> ! { + let _ = writeln!(io::stderr(), "\n\nerror occurred: {}\n\n", s); + std::process::exit(1); +} + +fn command_add_output_file( + cmd: &mut Command, + dst: &Path, + cuda: bool, + msvc: bool, + clang: bool, + is_asm: bool, + is_arm: bool, +) { + if msvc && !clang && !cuda && !(is_asm && is_arm) { + let mut s = OsString::from("-Fo"); + s.push(&dst); + cmd.arg(s); + } else { + cmd.arg("-o").arg(&dst); + } +} + +// Use by default minimum available API level +// See note about naming here +// https://android.googlesource.com/platform/ndk/+/refs/heads/ndk-release-r21/docs/BuildSystemMaintainers.md#Clang +static NEW_STANDALONE_ANDROID_COMPILERS: [&str; 4] = [ + "aarch64-linux-android21-clang", + "armv7a-linux-androideabi16-clang", + "i686-linux-android16-clang", + "x86_64-linux-android21-clang", +]; + +// New "standalone" C/C++ cross-compiler executables from recent Android NDK +// are just shell scripts that call main clang binary (from Android NDK) with +// proper `--target` argument. +// +// For example, armv7a-linux-androideabi16-clang passes +// `--target=armv7a-linux-androideabi16` to clang. +// So to construct proper command line check if +// `--target` argument would be passed or not to clang +fn android_clang_compiler_uses_target_arg_internally(clang_path: &Path) -> bool { + if let Some(filename) = clang_path.file_name() { + if let Some(filename_str) = filename.to_str() { + filename_str.contains("android") + } else { + false + } + } else { + false + } +} + +#[test] +fn test_android_clang_compiler_uses_target_arg_internally() { + for version in 16..21 { + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang", version)) + )); + assert!(android_clang_compiler_uses_target_arg_internally( + &PathBuf::from(format!("armv7a-linux-androideabi{}-clang++", version)) + )); + } + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang") + )); + assert!(!android_clang_compiler_uses_target_arg_internally( + &PathBuf::from("clang++") + )); +} + +fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) -> String { + let new_clang_key = match target { + "aarch64-linux-android" => Some("aarch64"), + "armv7-linux-androideabi" => Some("armv7a"), + "i686-linux-android" => Some("i686"), + "x86_64-linux-android" => Some("x86_64"), + _ => None, + }; + + let new_clang = new_clang_key + .map(|key| { + NEW_STANDALONE_ANDROID_COMPILERS + .iter() + .find(|x| x.starts_with(key)) + }) + .unwrap_or(None); + + if let Some(new_clang) = new_clang { + if Command::new(new_clang).output().is_ok() { + return (*new_clang).into(); + } + } + + let target = target + .replace("armv7neon", "arm") + .replace("armv7", "arm") + .replace("thumbv7neon", "arm") + .replace("thumbv7", "arm"); + let gnu_compiler = format!("{}-{}", target, gnu); + let clang_compiler = format!("{}-{}", target, clang); + + // On Windows, the Android clang compiler is provided as a `.cmd` file instead + // of a `.exe` file. `std::process::Command` won't run `.cmd` files unless the + // `.cmd` is explicitly appended to the command name, so we do that here. + let clang_compiler_cmd = format!("{}-{}.cmd", target, clang); + + // Check if gnu compiler is present + // if not, use clang + if Command::new(&gnu_compiler).output().is_ok() { + gnu_compiler + } else if host.contains("windows") && Command::new(&clang_compiler_cmd).output().is_ok() { + clang_compiler_cmd + } else { + clang_compiler + } +} diff --git a/vendor/cc-1.0.59/src/registry.rs b/vendor/cc-1.0.59/src/registry.rs new file mode 100644 index 0000000000..2ac2fa63ba --- /dev/null +++ b/vendor/cc-1.0.59/src/registry.rs @@ -0,0 +1,204 @@ +// 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. + +use std::ffi::{OsStr, OsString}; +use std::io; +use std::ops::RangeFrom; +use std::os::raw; +use std::os::windows::prelude::*; + +pub struct RegistryKey(Repr); + +type HKEY = *mut u8; +type DWORD = u32; +type LPDWORD = *mut DWORD; +type LPCWSTR = *const u16; +type LPWSTR = *mut u16; +type LONG = raw::c_long; +type PHKEY = *mut HKEY; +type PFILETIME = *mut u8; +type LPBYTE = *mut u8; +type REGSAM = u32; + +const ERROR_SUCCESS: DWORD = 0; +const ERROR_NO_MORE_ITEMS: DWORD = 259; +const HKEY_LOCAL_MACHINE: HKEY = 0x80000002 as HKEY; +const REG_SZ: DWORD = 1; +const KEY_READ: DWORD = 0x20019; +const KEY_WOW64_32KEY: DWORD = 0x200; + +#[link(name = "advapi32")] +extern "system" { + fn RegOpenKeyExW( + key: HKEY, + lpSubKey: LPCWSTR, + ulOptions: DWORD, + samDesired: REGSAM, + phkResult: PHKEY, + ) -> LONG; + fn RegEnumKeyExW( + key: HKEY, + dwIndex: DWORD, + lpName: LPWSTR, + lpcName: LPDWORD, + lpReserved: LPDWORD, + lpClass: LPWSTR, + lpcClass: LPDWORD, + lpftLastWriteTime: PFILETIME, + ) -> LONG; + fn RegQueryValueExW( + hKey: HKEY, + lpValueName: LPCWSTR, + lpReserved: LPDWORD, + lpType: LPDWORD, + lpData: LPBYTE, + lpcbData: LPDWORD, + ) -> LONG; + fn RegCloseKey(hKey: HKEY) -> LONG; +} + +struct OwnedKey(HKEY); + +enum Repr { + Const(HKEY), + Owned(OwnedKey), +} + +pub struct Iter<'a> { + idx: RangeFrom, + key: &'a RegistryKey, +} + +unsafe impl Sync for Repr {} +unsafe impl Send for Repr {} + +pub static LOCAL_MACHINE: RegistryKey = RegistryKey(Repr::Const(HKEY_LOCAL_MACHINE)); + +impl RegistryKey { + fn raw(&self) -> HKEY { + match self.0 { + Repr::Const(val) => val, + Repr::Owned(ref val) => val.0, + } + } + + pub fn open(&self, key: &OsStr) -> io::Result { + let key = key.encode_wide().chain(Some(0)).collect::>(); + let mut ret = 0 as *mut _; + let err = unsafe { + RegOpenKeyExW( + self.raw(), + key.as_ptr(), + 0, + KEY_READ | KEY_WOW64_32KEY, + &mut ret, + ) + }; + if err == ERROR_SUCCESS as LONG { + Ok(RegistryKey(Repr::Owned(OwnedKey(ret)))) + } else { + Err(io::Error::from_raw_os_error(err as i32)) + } + } + + pub fn iter(&self) -> Iter { + Iter { + idx: 0.., + key: self, + } + } + + pub fn query_str(&self, name: &str) -> io::Result { + let name: &OsStr = name.as_ref(); + let name = name.encode_wide().chain(Some(0)).collect::>(); + let mut len = 0; + let mut kind = 0; + unsafe { + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + 0 as *mut _, + &mut kind, + 0 as *mut _, + &mut len, + ); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + if kind != REG_SZ { + return Err(io::Error::new( + io::ErrorKind::Other, + "registry key wasn't a string", + )); + } + + // The length here is the length in bytes, but we're using wide + // characters so we need to be sure to halve it for the capacity + // passed in. + let mut v = Vec::with_capacity(len as usize / 2); + let err = RegQueryValueExW( + self.raw(), + name.as_ptr(), + 0 as *mut _, + 0 as *mut _, + v.as_mut_ptr() as *mut _, + &mut len, + ); + if err != ERROR_SUCCESS as LONG { + return Err(io::Error::from_raw_os_error(err as i32)); + } + v.set_len(len as usize / 2); + + // Some registry keys may have a terminating nul character, but + // we're not interested in that, so chop it off if it's there. + if v[v.len() - 1] == 0 { + v.pop(); + } + Ok(OsString::from_wide(&v)) + } + } +} + +impl Drop for OwnedKey { + fn drop(&mut self) { + unsafe { + RegCloseKey(self.0); + } + } +} + +impl<'a> Iterator for Iter<'a> { + type Item = io::Result; + + fn next(&mut self) -> Option> { + self.idx.next().and_then(|i| unsafe { + let mut v = Vec::with_capacity(256); + let mut len = v.capacity() as DWORD; + let ret = RegEnumKeyExW( + self.key.raw(), + i, + v.as_mut_ptr(), + &mut len, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _, + 0 as *mut _, + ); + if ret == ERROR_NO_MORE_ITEMS as LONG { + None + } else if ret != ERROR_SUCCESS as LONG { + Some(Err(io::Error::from_raw_os_error(ret as i32))) + } else { + v.set_len(len as usize); + Some(Ok(OsString::from_wide(&v))) + } + }) + } +} diff --git a/vendor/cc-1.0.59/src/setup_config.rs b/vendor/cc-1.0.59/src/setup_config.rs new file mode 100644 index 0000000000..bc2b1c2d30 --- /dev/null +++ b/vendor/cc-1.0.59/src/setup_config.rs @@ -0,0 +1,283 @@ +// Copyright © 2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] +#![allow(unused)] + +use crate::winapi::Interface; +use crate::winapi::BSTR; +use crate::winapi::LPCOLESTR; +use crate::winapi::LPSAFEARRAY; +use crate::winapi::S_FALSE; +use crate::winapi::{CoCreateInstance, CLSCTX_ALL}; +use crate::winapi::{IUnknown, IUnknownVtbl}; +use crate::winapi::{HRESULT, LCID, LPCWSTR, PULONGLONG}; +use crate::winapi::{LPFILETIME, ULONG}; +use std::ffi::OsString; +use std::ptr::null_mut; + +use crate::com::{BStr, ComPtr}; + +// Bindings to the Setup.Configuration stuff +pub type InstanceState = u32; + +pub const eNone: InstanceState = 0; +pub const eLocal: InstanceState = 1; +pub const eRegistered: InstanceState = 2; +pub const eNoRebootRequired: InstanceState = 4; +pub const eComplete: InstanceState = -1i32 as u32; + +RIDL! {#[uuid(0xb41463c3, 0x8866, 0x43b5, 0xbc, 0x33, 0x2b, 0x06, 0x76, 0xf7, 0xf4, 0x2e)] +interface ISetupInstance(ISetupInstanceVtbl): IUnknown(IUnknownVtbl) { + fn GetInstanceId( + pbstrInstanceId: *mut BSTR, + ) -> HRESULT, + fn GetInstallDate( + pInstallDate: LPFILETIME, + ) -> HRESULT, + fn GetInstallationName( + pbstrInstallationName: *mut BSTR, + ) -> HRESULT, + fn GetInstallationPath( + pbstrInstallationPath: *mut BSTR, + ) -> HRESULT, + fn GetInstallationVersion( + pbstrInstallationVersion: *mut BSTR, + ) -> HRESULT, + fn GetDisplayName( + lcid: LCID, + pbstrDisplayName: *mut BSTR, + ) -> HRESULT, + fn GetDescription( + lcid: LCID, + pbstrDescription: *mut BSTR, + ) -> HRESULT, + fn ResolvePath( + pwszRelativePath: LPCOLESTR, + pbstrAbsolutePath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x89143c9a, 0x05af, 0x49b0, 0xb7, 0x17, 0x72, 0xe2, 0x18, 0xa2, 0x18, 0x5c)] +interface ISetupInstance2(ISetupInstance2Vtbl): ISetupInstance(ISetupInstanceVtbl) { + fn GetState( + pState: *mut InstanceState, + ) -> HRESULT, + fn GetPackages( + ppsaPackages: *mut LPSAFEARRAY, + ) -> HRESULT, + fn GetProduct( + ppPackage: *mut *mut ISetupPackageReference, + ) -> HRESULT, + fn GetProductPath( + pbstrProductPath: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x6380bcff, 0x41d3, 0x4b2e, 0x8b, 0x2e, 0xbf, 0x8a, 0x68, 0x10, 0xc8, 0x48)] +interface IEnumSetupInstances(IEnumSetupInstancesVtbl): IUnknown(IUnknownVtbl) { + fn Next( + celt: ULONG, + rgelt: *mut *mut ISetupInstance, + pceltFetched: *mut ULONG, + ) -> HRESULT, + fn Skip( + celt: ULONG, + ) -> HRESULT, + fn Reset() -> HRESULT, + fn Clone( + ppenum: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42843719, 0xdb4c, 0x46c2, 0x8e, 0x7c, 0x64, 0xf1, 0x81, 0x6e, 0xfd, 0x5b)] +interface ISetupConfiguration(ISetupConfigurationVtbl): IUnknown(IUnknownVtbl) { + fn EnumInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, + fn GetInstanceForCurrentProcess( + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, + fn GetInstanceForPath( + wzPath: LPCWSTR, + ppInstance: *mut *mut ISetupInstance, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x26aab78c, 0x4a60, 0x49d6, 0xaf, 0x3b, 0x3c, 0x35, 0xbc, 0x93, 0x36, 0x5d)] +interface ISetupConfiguration2(ISetupConfiguration2Vtbl): + ISetupConfiguration(ISetupConfigurationVtbl) { + fn EnumAllInstances( + ppEnumInstances: *mut *mut IEnumSetupInstances, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0xda8d8a16, 0xb2b6, 0x4487, 0xa2, 0xf1, 0x59, 0x4c, 0xcc, 0xcd, 0x6b, 0xf5)] +interface ISetupPackageReference(ISetupPackageReferenceVtbl): IUnknown(IUnknownVtbl) { + fn GetId( + pbstrId: *mut BSTR, + ) -> HRESULT, + fn GetVersion( + pbstrVersion: *mut BSTR, + ) -> HRESULT, + fn GetChip( + pbstrChip: *mut BSTR, + ) -> HRESULT, + fn GetLanguage( + pbstrLanguage: *mut BSTR, + ) -> HRESULT, + fn GetBranch( + pbstrBranch: *mut BSTR, + ) -> HRESULT, + fn GetType( + pbstrType: *mut BSTR, + ) -> HRESULT, + fn GetUniqueId( + pbstrUniqueId: *mut BSTR, + ) -> HRESULT, +}} + +RIDL! {#[uuid(0x42b21b78, 0x6192, 0x463e, 0x87, 0xbf, 0xd5, 0x77, 0x83, 0x8f, 0x1d, 0x5c)] +interface ISetupHelper(ISetupHelperVtbl): IUnknown(IUnknownVtbl) { + fn ParseVersion( + pwszVersion: LPCOLESTR, + pullVersion: PULONGLONG, + ) -> HRESULT, + fn ParseVersionRange( + pwszVersionRange: LPCOLESTR, + pullMinVersion: PULONGLONG, + pullMaxVersion: PULONGLONG, + ) -> HRESULT, +}} + +DEFINE_GUID! {CLSID_SetupConfiguration, +0x177f0c4a, 0x1cd3, 0x4de7, 0xa3, 0x2c, 0x71, 0xdb, 0xbb, 0x9f, 0xa3, 0x6d} + +// Safe wrapper around the COM interfaces +pub struct SetupConfiguration(ComPtr); + +impl SetupConfiguration { + pub fn new() -> Result { + let mut obj = null_mut(); + let err = unsafe { + CoCreateInstance( + &CLSID_SetupConfiguration, + null_mut(), + CLSCTX_ALL, + &ISetupConfiguration::uuidof(), + &mut obj, + ) + }; + if err < 0 { + return Err(err); + } + let obj = unsafe { ComPtr::from_raw(obj as *mut ISetupConfiguration) }; + Ok(SetupConfiguration(obj)) + } + pub fn get_instance_for_current_process(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.GetInstanceForCurrentProcess(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { SetupInstance::from_raw(obj) }) + } + pub fn enum_instances(&self) -> Result { + let mut obj = null_mut(); + let err = unsafe { self.0.EnumInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } + pub fn enum_all_instances(&self) -> Result { + let mut obj = null_mut(); + let this = self.0.cast::()?; + let err = unsafe { this.EnumAllInstances(&mut obj) }; + if err < 0 { + return Err(err); + } + Ok(unsafe { EnumSetupInstances::from_raw(obj) }) + } +} + +pub struct SetupInstance(ComPtr); + +impl SetupInstance { + pub unsafe fn from_raw(obj: *mut ISetupInstance) -> SetupInstance { + SetupInstance(ComPtr::from_raw(obj)) + } + pub fn instance_id(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstanceId(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_name(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationName(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_path(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn installation_version(&self) -> Result { + let mut s = null_mut(); + let err = unsafe { self.0.GetInstallationVersion(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } + pub fn product_path(&self) -> Result { + let mut s = null_mut(); + let this = self.0.cast::()?; + let err = unsafe { this.GetProductPath(&mut s) }; + let bstr = unsafe { BStr::from_raw(s) }; + if err < 0 { + return Err(err); + } + Ok(bstr.to_osstring()) + } +} + +pub struct EnumSetupInstances(ComPtr); + +impl EnumSetupInstances { + pub unsafe fn from_raw(obj: *mut IEnumSetupInstances) -> EnumSetupInstances { + EnumSetupInstances(ComPtr::from_raw(obj)) + } +} + +impl Iterator for EnumSetupInstances { + type Item = Result; + fn next(&mut self) -> Option> { + let mut obj = null_mut(); + let err = unsafe { self.0.Next(1, &mut obj, null_mut()) }; + if err < 0 { + return Some(Err(err)); + } + if err == S_FALSE { + return None; + } + Some(Ok(unsafe { SetupInstance::from_raw(obj) })) + } +} diff --git a/vendor/cc-1.0.59/src/winapi.rs b/vendor/cc-1.0.59/src/winapi.rs new file mode 100644 index 0000000000..c416325b52 --- /dev/null +++ b/vendor/cc-1.0.59/src/winapi.rs @@ -0,0 +1,218 @@ +// Copyright © 2015-2017 winapi-rs developers +// Licensed under the Apache License, Version 2.0 +// or the MIT license +// , at your option. +// All files in the project carrying such notice may not be copied, modified, or distributed +// except according to those terms. + +#![allow(bad_style)] + +use std::os::raw; + +pub type wchar_t = u16; + +pub type UINT = raw::c_uint; +pub type LPUNKNOWN = *mut IUnknown; +pub type REFIID = *const IID; +pub type IID = GUID; +pub type REFCLSID = *const IID; +pub type PVOID = *mut raw::c_void; +pub type USHORT = raw::c_ushort; +pub type ULONG = raw::c_ulong; +pub type LONG = raw::c_long; +pub type DWORD = u32; +pub type LPVOID = *mut raw::c_void; +pub type HRESULT = raw::c_long; +pub type LPFILETIME = *mut FILETIME; +pub type BSTR = *mut OLECHAR; +pub type OLECHAR = WCHAR; +pub type WCHAR = wchar_t; +pub type LPCOLESTR = *const OLECHAR; +pub type LCID = DWORD; +pub type LPCWSTR = *const WCHAR; +pub type PULONGLONG = *mut ULONGLONG; +pub type ULONGLONG = u64; + +pub const S_OK: HRESULT = 0; +pub const S_FALSE: HRESULT = 1; +pub const COINIT_MULTITHREADED: u32 = 0x0; + +pub type CLSCTX = u32; + +pub const CLSCTX_INPROC_SERVER: CLSCTX = 0x1; +pub const CLSCTX_INPROC_HANDLER: CLSCTX = 0x2; +pub const CLSCTX_LOCAL_SERVER: CLSCTX = 0x4; +pub const CLSCTX_REMOTE_SERVER: CLSCTX = 0x10; + +pub const CLSCTX_ALL: CLSCTX = + CLSCTX_INPROC_SERVER | CLSCTX_INPROC_HANDLER | CLSCTX_LOCAL_SERVER | CLSCTX_REMOTE_SERVER; + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct GUID { + pub Data1: raw::c_ulong, + pub Data2: raw::c_ushort, + pub Data3: raw::c_ushort, + pub Data4: [raw::c_uchar; 8], +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct FILETIME { + pub dwLowDateTime: DWORD, + pub dwHighDateTime: DWORD, +} + +pub trait Interface { + fn uuidof() -> GUID; +} + +#[link(name = "ole32")] +#[link(name = "oleaut32")] +extern "C" {} + +extern "system" { + pub fn CoInitializeEx(pvReserved: LPVOID, dwCoInit: DWORD) -> HRESULT; + pub fn CoCreateInstance( + rclsid: REFCLSID, + pUnkOuter: LPUNKNOWN, + dwClsContext: DWORD, + riid: REFIID, + ppv: *mut LPVOID, + ) -> HRESULT; + pub fn SysFreeString(bstrString: BSTR); + pub fn SysStringLen(pbstr: BSTR) -> UINT; +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAYBOUND { + pub cElements: ULONG, + pub lLbound: LONG, +} + +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SAFEARRAY { + pub cDims: USHORT, + pub fFeatures: USHORT, + pub cbElements: ULONG, + pub cLocks: ULONG, + pub pvData: PVOID, + pub rgsabound: [SAFEARRAYBOUND; 1], +} + +pub type LPSAFEARRAY = *mut SAFEARRAY; + +macro_rules! DEFINE_GUID { + ( + $name:ident, $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => { + pub const $name: $crate::winapi::GUID = $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + }; + }; +} + +macro_rules! RIDL { + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t),* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) { + }) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (#[uuid($($uuid:expr),+)] + interface $interface:ident ($vtbl:ident) : $pinterface:ident ($pvtbl:ident) {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + #[repr(C)] + pub struct $vtbl { + pub parent: $pvtbl, + $(pub $method: unsafe extern "system" fn( + This: *mut $interface, + $($p: $t,)* + ) -> $rtr,)+ + } + #[repr(C)] + pub struct $interface { + pub lpVtbl: *const $vtbl, + } + RIDL!{@impl $interface {$(fn $method($($p: $t,)*) -> $rtr,)+}} + RIDL!{@deref $interface $pinterface} + RIDL!{@uuid $interface $($uuid),+} + ); + (@deref $interface:ident $pinterface:ident) => ( + impl ::std::ops::Deref for $interface { + type Target = $pinterface; + #[inline] + fn deref(&self) -> &$pinterface { + unsafe { &*(self as *const $interface as *const $pinterface) } + } + } + ); + (@impl $interface:ident {$( + fn $method:ident($($p:ident : $t:ty,)*) -> $rtr:ty, + )+}) => ( + impl $interface { + $(#[inline] pub unsafe fn $method(&self, $($p: $t,)*) -> $rtr { + ((*self.lpVtbl).$method)(self as *const _ as *mut _, $($p,)*) + })+ + } + ); + (@uuid $interface:ident + $l:expr, $w1:expr, $w2:expr, + $b1:expr, $b2:expr, $b3:expr, $b4:expr, $b5:expr, $b6:expr, $b7:expr, $b8:expr + ) => ( + impl $crate::winapi::Interface for $interface { + #[inline] + fn uuidof() -> $crate::winapi::GUID { + $crate::winapi::GUID { + Data1: $l, + Data2: $w1, + Data3: $w2, + Data4: [$b1, $b2, $b3, $b4, $b5, $b6, $b7, $b8], + } + } + } + ); +} + +RIDL! {#[uuid(0x00000000, 0x0000, 0x0000, 0xc0, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x46)] +interface IUnknown(IUnknownVtbl) { + fn QueryInterface( + riid: REFIID, + ppvObject: *mut *mut raw::c_void, + ) -> HRESULT, + fn AddRef() -> ULONG, + fn Release() -> ULONG, +}} diff --git a/vendor/cc-1.0.59/src/windows_registry.rs b/vendor/cc-1.0.59/src/windows_registry.rs new file mode 100644 index 0000000000..81725026b3 --- /dev/null +++ b/vendor/cc-1.0.59/src/windows_registry.rs @@ -0,0 +1,794 @@ +// 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. + +//! A helper module to probe the Windows Registry when looking for +//! windows-specific tools. + +use std::process::Command; + +use crate::Tool; +#[cfg(windows)] +use crate::ToolFamily; + +#[cfg(windows)] +const MSVC_FAMILY: ToolFamily = ToolFamily::Msvc { clang_cl: false }; + +/// Attempts to find a tool within an MSVC installation using the Windows +/// registry as a point to search from. +/// +/// The `target` argument is the target that the tool should work for (e.g. +/// compile or link for) and the `tool` argument is the tool to find (e.g. +/// `cl.exe` or `link.exe`). +/// +/// This function will return `None` if the tool could not be found, or it will +/// return `Some(cmd)` which represents a command that's ready to execute the +/// tool with the appropriate environment variables set. +/// +/// Note that this function always returns `None` for non-MSVC targets. +pub fn find(target: &str, tool: &str) -> Option { + find_tool(target, tool).map(|c| c.to_command()) +} + +/// Similar to the `find` function above, this function will attempt the same +/// operation (finding a MSVC tool in a local install) but instead returns a +/// `Tool` which may be introspected. +#[cfg(not(windows))] +pub fn find_tool(_target: &str, _tool: &str) -> Option { + None +} + +/// Documented above. +#[cfg(windows)] +pub fn find_tool(target: &str, tool: &str) -> Option { + use std::env; + + // This logic is all tailored for MSVC, if we're not that then bail out + // early. + if !target.contains("msvc") { + return None; + } + + // Looks like msbuild isn't located in the same location as other tools like + // cl.exe and lib.exe. To handle this we probe for it manually with + // dedicated registry keys. + if tool.contains("msbuild") { + return impl_::find_msbuild(target); + } + + if tool.contains("devenv") { + return impl_::find_devenv(target); + } + + // If VCINSTALLDIR is set, then someone's probably already run vcvars and we + // should just find whatever that indicates. + if env::var_os("VCINSTALLDIR").is_some() { + return env::var_os("PATH") + .and_then(|path| { + env::split_paths(&path) + .map(|p| p.join(tool)) + .find(|p| p.exists()) + }) + .map(|path| Tool::with_family(path.into(), MSVC_FAMILY)); + } + + // Ok, if we're here, now comes the fun part of the probing. Default shells + // or shells like MSYS aren't really configured to execute `cl.exe` and the + // various compiler tools shipped as part of Visual Studio. Here we try to + // first find the relevant tool, then we also have to be sure to fill in + // environment variables like `LIB`, `INCLUDE`, and `PATH` to ensure that + // the tool is actually usable. + + return impl_::find_msvc_15plus(tool, target) + .or_else(|| impl_::find_msvc_14(tool, target)) + .or_else(|| impl_::find_msvc_12(tool, target)) + .or_else(|| impl_::find_msvc_11(tool, target)); +} + +/// A version of Visual Studio +#[derive(Debug, PartialEq, Eq, Copy, Clone)] +pub enum VsVers { + /// Visual Studio 12 (2013) + Vs12, + /// Visual Studio 14 (2015) + Vs14, + /// Visual Studio 15 (2017) + Vs15, + /// Visual Studio 16 (2019) + Vs16, + + /// Hidden variant that should not be matched on. Callers that want to + /// handle an enumeration of `VsVers` instances should always have a default + /// case meaning that it's a VS version they don't understand. + #[doc(hidden)] + #[allow(bad_style)] + __Nonexhaustive_do_not_match_this_or_your_code_will_break, +} + +/// Find the most recent installed version of Visual Studio +/// +/// This is used by the cmake crate to figure out the correct +/// generator. +#[cfg(not(windows))] +pub fn find_vs_version() -> Result { + Err(format!("not windows")) +} + +/// Documented above +#[cfg(windows)] +pub fn find_vs_version() -> Result { + use std::env; + + match env::var("VisualStudioVersion") { + Ok(version) => match &version[..] { + "16.0" => Ok(VsVers::Vs16), + "15.0" => Ok(VsVers::Vs15), + "14.0" => Ok(VsVers::Vs14), + "12.0" => Ok(VsVers::Vs12), + vers => Err(format!( + "\n\n\ + unsupported or unknown VisualStudio version: {}\n\ + if another version is installed consider running \ + the appropriate vcvars script before building this \ + crate\n\ + ", + vers + )), + }, + _ => { + // Check for the presense of a specific registry key + // that indicates visual studio is installed. + if impl_::has_msbuild_version("16.0") { + Ok(VsVers::Vs16) + } else if impl_::has_msbuild_version("15.0") { + Ok(VsVers::Vs15) + } else if impl_::has_msbuild_version("14.0") { + Ok(VsVers::Vs14) + } else if impl_::has_msbuild_version("12.0") { + Ok(VsVers::Vs12) + } else { + Err(format!( + "\n\n\ + couldn't determine visual studio generator\n\ + if VisualStudio is installed, however, consider \ + running the appropriate vcvars script before building \ + this crate\n\ + " + )) + } + } + } +} + +#[cfg(windows)] +mod impl_ { + use crate::com; + use crate::registry::{RegistryKey, LOCAL_MACHINE}; + use crate::setup_config::{EnumSetupInstances, SetupConfiguration, SetupInstance}; + use std::env; + use std::ffi::OsString; + use std::fs::File; + use std::io::Read; + use std::iter; + use std::mem; + use std::path::{Path, PathBuf}; + use std::str::FromStr; + + use super::MSVC_FAMILY; + use crate::Tool; + + struct MsvcTool { + tool: PathBuf, + libs: Vec, + path: Vec, + include: Vec, + } + + impl MsvcTool { + fn new(tool: PathBuf) -> MsvcTool { + MsvcTool { + tool: tool, + libs: Vec::new(), + path: Vec::new(), + include: Vec::new(), + } + } + + fn into_tool(self) -> Tool { + let MsvcTool { + tool, + libs, + path, + include, + } = self; + let mut tool = Tool::with_family(tool.into(), MSVC_FAMILY); + add_env(&mut tool, "LIB", libs); + add_env(&mut tool, "PATH", path); + add_env(&mut tool, "INCLUDE", include); + tool + } + } + + #[allow(bare_trait_objects)] + fn vs16_instances() -> Box> { + let instances = if let Some(instances) = vs15plus_instances() { + instances + } else { + return Box::new(iter::empty()); + }; + Box::new(instances.filter_map(|instance| { + let instance = instance.ok()?; + let installation_name = instance.installation_name().ok()?; + if installation_name.to_str()?.starts_with("VisualStudio/16.") { + Some(PathBuf::from(instance.installation_path().ok()?)) + } else if installation_name + .to_str()? + .starts_with("VisualStudioPreview/16.") + { + Some(PathBuf::from(instance.installation_path().ok()?)) + } else { + None + } + })) + } + + fn find_tool_in_vs16_path(tool: &str, target: &str) -> Option { + vs16_instances() + .filter_map(|path| { + let path = path.join(tool); + if !path.is_file() { + return None; + } + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + Some(tool) + }) + .next() + } + + fn find_msbuild_vs16(target: &str) -> Option { + find_tool_in_vs16_path(r"MSBuild\Current\Bin\MSBuild.exe", target) + } + + // In MSVC 15 (2017) MS once again changed the scheme for locating + // the tooling. Now we must go through some COM interfaces, which + // is super fun for Rust. + // + // Note that much of this logic can be found [online] wrt paths, COM, etc. + // + // [online]: https://blogs.msdn.microsoft.com/vcblog/2017/03/06/finding-the-visual-c-compiler-tools-in-visual-studio-2017/ + // + // Returns MSVC 15+ instances (15, 16 right now), the order should be consider undefined. + fn vs15plus_instances() -> Option { + com::initialize().ok()?; + + let config = SetupConfiguration::new().ok()?; + config.enum_all_instances().ok() + } + + // Inspired from official microsoft/vswhere ParseVersionString + // i.e. at most four u16 numbers separated by '.' + fn parse_version(version: &str) -> Option> { + version + .split('.') + .map(|chunk| u16::from_str(chunk).ok()) + .collect() + } + + pub fn find_msvc_15plus(tool: &str, target: &str) -> Option { + let iter = vs15plus_instances()?; + iter.filter_map(|instance| { + let instance = instance.ok()?; + let version = parse_version(instance.installation_version().ok()?.to_str()?)?; + let tool = tool_from_vs15plus_instance(tool, target, &instance)?; + Some((version, tool)) + }) + .max_by(|(a_version, _), (b_version, _)| a_version.cmp(b_version)) + .map(|(_version, tool)| tool) + } + + // While the paths to Visual Studio 2017's devenv and MSBuild could + // potentially be retrieved from the registry, finding them via + // SetupConfiguration has shown to be [more reliable], and is preferred + // according to Microsoft. To help head off potential regressions though, + // we keep the registry method as a fallback option. + // + // [more reliable]: https://github.com/alexcrichton/cc-rs/pull/331 + fn find_tool_in_vs15_path(tool: &str, target: &str) -> Option { + let mut path = match vs15plus_instances() { + Some(instances) => instances + .filter_map(|instance| { + instance + .ok() + .and_then(|instance| instance.installation_path().ok()) + }) + .map(|path| PathBuf::from(path).join(tool)) + .find(|ref path| path.is_file()), + None => None, + }; + + if path.is_none() { + let key = r"SOFTWARE\WOW6432Node\Microsoft\VisualStudio\SxS\VS7"; + path = LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| key.query_str("15.0").ok()) + .map(|path| PathBuf::from(path).join(tool)) + .and_then(|path| if path.is_file() { Some(path) } else { None }); + } + + path.map(|path| { + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } + + fn tool_from_vs15plus_instance( + tool: &str, + target: &str, + instance: &SetupInstance, + ) -> Option { + let (bin_path, host_dylib_path, lib_path, include_path) = + vs15plus_vc_paths(target, instance)?; + let tool_path = bin_path.join(tool); + if !tool_path.exists() { + return None; + }; + + let mut tool = MsvcTool::new(tool_path); + tool.path.push(bin_path.clone()); + tool.path.push(host_dylib_path); + tool.libs.push(lib_path); + tool.include.push(include_path); + + if let Some((atl_lib_path, atl_include_path)) = atl_paths(target, &bin_path) { + tool.libs.push(atl_lib_path); + tool.include.push(atl_include_path); + } + + add_sdks(&mut tool, target)?; + + Some(tool.into_tool()) + } + + fn vs15plus_vc_paths( + target: &str, + instance: &SetupInstance, + ) -> Option<(PathBuf, PathBuf, PathBuf, PathBuf)> { + let instance_path: PathBuf = instance.installation_path().ok()?.into(); + let version_path = + instance_path.join(r"VC\Auxiliary\Build\Microsoft.VCToolsVersion.default.txt"); + let mut version_file = File::open(version_path).ok()?; + let mut version = String::new(); + version_file.read_to_string(&mut version).ok()?; + let version = version.trim(); + let host = match host_arch() { + X86 => "X86", + X86_64 => "X64", + // There is no natively hosted compiler on ARM64. + // Instead, use the x86 toolchain under emulation (there is no x64 emulation). + AARCH64 => "X86", + _ => return None, + }; + let target = lib_subdir(target)?; + // The directory layout here is MSVC/bin/Host$host/$target/ + let path = instance_path.join(r"VC\Tools\MSVC").join(version); + // This is the path to the toolchain for a particular target, running + // on a given host + let bin_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&target); + // But! we also need PATH to contain the target directory for the host + // architecture, because it contains dlls like mspdb140.dll compiled for + // the host architecture. + let host_dylib_path = path + .join("bin") + .join(&format!("Host{}", host)) + .join(&host.to_lowercase()); + let lib_path = path.join("lib").join(&target); + let include_path = path.join("include"); + Some((bin_path, host_dylib_path, lib_path, include_path)) + } + + fn atl_paths(target: &str, path: &Path) -> Option<(PathBuf, PathBuf)> { + let atl_path = path.join("atlfmc"); + let sub = lib_subdir(target)?; + if atl_path.exists() { + Some((atl_path.join("lib").join(sub), atl_path.join("include"))) + } else { + None + } + } + + // For MSVC 14 we need to find the Universal CRT as well as either + // the Windows 10 SDK or Windows 8.1 SDK. + pub fn find_msvc_14(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("14.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + add_sdks(&mut tool, target)?; + Some(tool.into_tool()) + } + + fn add_sdks(tool: &mut MsvcTool, target: &str) -> Option<()> { + let sub = lib_subdir(target)?; + let (ucrt, ucrt_version) = get_ucrt_dir()?; + + let host = match host_arch() { + X86 => "x86", + X86_64 => "x64", + AARCH64 => "arm64", + _ => return None, + }; + + tool.path + .push(ucrt.join("bin").join(&ucrt_version).join(host)); + + let ucrt_include = ucrt.join("include").join(&ucrt_version); + tool.include.push(ucrt_include.join("ucrt")); + + let ucrt_lib = ucrt.join("lib").join(&ucrt_version); + tool.libs.push(ucrt_lib.join("ucrt").join(sub)); + + if let Some((sdk, version)) = get_sdk10_dir() { + tool.path.push(sdk.join("bin").join(host)); + let sdk_lib = sdk.join("lib").join(&version); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include").join(&version); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("cppwinrt")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } else if let Some(sdk) = get_sdk81_dir() { + tool.path.push(sdk.join("bin").join(host)); + let sdk_lib = sdk.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk.join("include"); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + tool.include.push(sdk_include.join("shared")); + } + + Some(()) + } + + // For MSVC 12 we need to find the Windows 8.1 SDK. + pub fn find_msvc_12(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("12.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + let sub = lib_subdir(target)?; + let sdk81 = get_sdk81_dir()?; + tool.path.push(sdk81.join("bin").join(sub)); + let sdk_lib = sdk81.join("lib").join("winv6.3"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk81.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + // For MSVC 11 we need to find the Windows 8 SDK. + pub fn find_msvc_11(tool: &str, target: &str) -> Option { + let vcdir = get_vc_dir("11.0")?; + let mut tool = get_tool(tool, &vcdir, target)?; + let sub = lib_subdir(target)?; + let sdk8 = get_sdk8_dir()?; + tool.path.push(sdk8.join("bin").join(sub)); + let sdk_lib = sdk8.join("lib").join("win8"); + tool.libs.push(sdk_lib.join("um").join(sub)); + let sdk_include = sdk8.join("include"); + tool.include.push(sdk_include.join("shared")); + tool.include.push(sdk_include.join("um")); + tool.include.push(sdk_include.join("winrt")); + Some(tool.into_tool()) + } + + fn add_env(tool: &mut Tool, env: &str, paths: Vec) { + let prev = env::var_os(env).unwrap_or(OsString::new()); + let prev = env::split_paths(&prev); + let new = paths.into_iter().chain(prev); + tool.env + .push((env.to_string().into(), env::join_paths(new).unwrap())); + } + + // Given a possible MSVC installation directory, we look for the linker and + // then add the MSVC library path. + fn get_tool(tool: &str, path: &Path, target: &str) -> Option { + bin_subdir(target) + .into_iter() + .map(|(sub, host)| { + ( + path.join("bin").join(sub).join(tool), + path.join("bin").join(host), + ) + }) + .filter(|&(ref path, _)| path.is_file()) + .map(|(path, host)| { + let mut tool = MsvcTool::new(path); + tool.path.push(host); + tool + }) + .filter_map(|mut tool| { + let sub = vc_lib_subdir(target)?; + tool.libs.push(path.join("lib").join(sub)); + tool.include.push(path.join("include")); + let atlmfc_path = path.join("atlmfc"); + if atlmfc_path.exists() { + tool.libs.push(atlmfc_path.join("lib").join(sub)); + tool.include.push(atlmfc_path.join("include")); + } + Some(tool) + }) + .next() + } + + // To find MSVC we look in a specific registry key for the version we are + // trying to find. + fn get_vc_dir(ver: &str) -> Option { + let key = r"SOFTWARE\Microsoft\VisualStudio\SxS\VC7"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let path = key.query_str(ver).ok()?; + Some(path.into()) + } + + // To find the Universal CRT we look in a specific registry key for where + // all the Universal CRTs are located and then sort them asciibetically to + // find the newest version. While this sort of sorting isn't ideal, it is + // what vcvars does so that's good enough for us. + // + // Returns a pair of (root, version) for the ucrt dir if found + fn get_ucrt_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Windows Kits\Installed Roots"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("KitsRoot10").ok()?; + let readdir = Path::new(&root).join("lib").read_dir().ok()?; + let max_libdir = readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .filter(|dir| { + dir.components() + .last() + .and_then(|c| c.as_os_str().to_str()) + .map(|c| c.starts_with("10.") && dir.join("ucrt").is_dir()) + .unwrap_or(false) + }) + .max()?; + let version = max_libdir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Vcvars finds the correct version of the Windows 10 SDK by looking + // for the include `um\Windows.h` because sometimes a given version will + // only have UCRT bits without the rest of the SDK. Since we only care about + // libraries and not includes, we instead look for `um\x64\kernel32.lib`. + // Since the 32-bit and 64-bit libraries are always installed together we + // only need to bother checking x64, making this code a tiny bit simpler. + // Like we do for the Universal CRT, we sort the possibilities + // asciibetically to find the newest one as that is what vcvars does. + fn get_sdk10_dir() -> Option<(PathBuf, String)> { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v10.0"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + let readdir = Path::new(&root).join("lib").read_dir().ok()?; + let mut dirs = readdir + .filter_map(|dir| dir.ok()) + .map(|dir| dir.path()) + .collect::>(); + dirs.sort(); + let dir = dirs + .into_iter() + .rev() + .filter(|dir| dir.join("um").join("x64").join("kernel32.lib").is_file()) + .next()?; + let version = dir.components().last().unwrap(); + let version = version.as_os_str().to_str().unwrap().to_string(); + Some((root.into(), version)) + } + + // Interestingly there are several subdirectories, `win7` `win8` and + // `winv6.3`. Vcvars seems to only care about `winv6.3` though, so the same + // applies to us. Note that if we were targetting kernel mode drivers + // instead of user mode applications, we would care. + fn get_sdk81_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.1"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + Some(root.into()) + } + + fn get_sdk8_dir() -> Option { + let key = r"SOFTWARE\Microsoft\Microsoft SDKs\Windows\v8.0"; + let key = LOCAL_MACHINE.open(key.as_ref()).ok()?; + let root = key.query_str("InstallationFolder").ok()?; + Some(root.into()) + } + + const PROCESSOR_ARCHITECTURE_INTEL: u16 = 0; + const PROCESSOR_ARCHITECTURE_AMD64: u16 = 9; + const PROCESSOR_ARCHITECTURE_ARM64: u16 = 12; + const X86: u16 = PROCESSOR_ARCHITECTURE_INTEL; + const X86_64: u16 = PROCESSOR_ARCHITECTURE_AMD64; + const AARCH64: u16 = PROCESSOR_ARCHITECTURE_ARM64; + + // When choosing the tool to use, we have to choose the one which matches + // the target architecture. Otherwise we end up in situations where someone + // on 32-bit Windows is trying to cross compile to 64-bit and it tries to + // invoke the native 64-bit compiler which won't work. + // + // For the return value of this function, the first member of the tuple is + // the folder of the tool we will be invoking, while the second member is + // the folder of the host toolchain for that tool which is essential when + // using a cross linker. We return a Vec since on x64 there are often two + // linkers that can target the architecture we desire. The 64-bit host + // linker is preferred, and hence first, due to 64-bit allowing it more + // address space to work with and potentially being faster. + fn bin_subdir(target: &str) -> Vec<(&'static str, &'static str)> { + let arch = target.split('-').next().unwrap(); + match (arch, host_arch()) { + ("i586", X86) | ("i686", X86) => vec![("", "")], + ("i586", X86_64) | ("i686", X86_64) => vec![("amd64_x86", "amd64"), ("", "")], + ("x86_64", X86) => vec![("x86_amd64", "")], + ("x86_64", X86_64) => vec![("amd64", "amd64"), ("x86_amd64", "")], + ("arm", X86) | ("thumbv7a", X86) => vec![("x86_arm", "")], + ("arm", X86_64) | ("thumbv7a", X86_64) => vec![("amd64_arm", "amd64"), ("x86_arm", "")], + _ => vec![], + } + } + + fn lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some("x86"), + "x86_64" => Some("x64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + // MSVC's x86 libraries are not in a subfolder + fn vc_lib_subdir(target: &str) -> Option<&'static str> { + let arch = target.split('-').next().unwrap(); + match arch { + "i586" | "i686" => Some(""), + "x86_64" => Some("amd64"), + "arm" | "thumbv7a" => Some("arm"), + "aarch64" => Some("arm64"), + _ => None, + } + } + + #[allow(bad_style)] + fn host_arch() -> u16 { + type DWORD = u32; + type WORD = u16; + type LPVOID = *mut u8; + type DWORD_PTR = usize; + + #[repr(C)] + struct SYSTEM_INFO { + wProcessorArchitecture: WORD, + _wReserved: WORD, + _dwPageSize: DWORD, + _lpMinimumApplicationAddress: LPVOID, + _lpMaximumApplicationAddress: LPVOID, + _dwActiveProcessorMask: DWORD_PTR, + _dwNumberOfProcessors: DWORD, + _dwProcessorType: DWORD, + _dwAllocationGranularity: DWORD, + _wProcessorLevel: WORD, + _wProcessorRevision: WORD, + } + + extern "system" { + fn GetNativeSystemInfo(lpSystemInfo: *mut SYSTEM_INFO); + } + + unsafe { + let mut info = mem::zeroed(); + GetNativeSystemInfo(&mut info); + info.wProcessorArchitecture + } + } + + // Given a registry key, look at all the sub keys and find the one which has + // the maximal numeric value. + // + // Returns the name of the maximal key as well as the opened maximal key. + fn max_version(key: &RegistryKey) -> Option<(OsString, RegistryKey)> { + let mut max_vers = 0; + let mut max_key = None; + for subkey in key.iter().filter_map(|k| k.ok()) { + let val = subkey + .to_str() + .and_then(|s| s.trim_left_matches("v").replace(".", "").parse().ok()); + let val = match val { + Some(s) => s, + None => continue, + }; + if val > max_vers { + if let Ok(k) = key.open(&subkey) { + max_vers = val; + max_key = Some((subkey, k)); + } + } + } + max_key + } + + pub fn has_msbuild_version(version: &str) -> bool { + match version { + "16.0" => { + find_msbuild_vs16("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs16("i686-pc-windows-msvc").is_some() + } + "15.0" => { + find_msbuild_vs15("x86_64-pc-windows-msvc").is_some() + || find_msbuild_vs15("i686-pc-windows-msvc").is_some() + } + "12.0" | "14.0" => LOCAL_MACHINE + .open(&OsString::from(format!( + "SOFTWARE\\Microsoft\\MSBuild\\ToolsVersions\\{}", + version + ))) + .is_ok(), + _ => false, + } + } + + pub fn find_devenv(target: &str) -> Option { + find_devenv_vs15(&target) + } + + fn find_devenv_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"Common7\IDE\devenv.exe", target) + } + + // see http://stackoverflow.com/questions/328017/path-to-msbuild + pub fn find_msbuild(target: &str) -> Option { + // VS 15 (2017) changed how to locate msbuild + if let Some(r) = find_msbuild_vs16(target) { + return Some(r); + } else if let Some(r) = find_msbuild_vs15(target) { + return Some(r); + } else { + find_old_msbuild(target) + } + } + + fn find_msbuild_vs15(target: &str) -> Option { + find_tool_in_vs15_path(r"MSBuild\15.0\Bin\MSBuild.exe", target) + } + + fn find_old_msbuild(target: &str) -> Option { + let key = r"SOFTWARE\Microsoft\MSBuild\ToolsVersions"; + LOCAL_MACHINE + .open(key.as_ref()) + .ok() + .and_then(|key| { + max_version(&key).and_then(|(_vers, key)| key.query_str("MSBuildToolsPath").ok()) + }) + .map(|path| { + let mut path = PathBuf::from(path); + path.push("MSBuild.exe"); + let mut tool = Tool::with_family(path, MSVC_FAMILY); + if target.contains("x86_64") { + tool.env.push(("Platform".into(), "X64".into())); + } + tool + }) + } +} diff --git a/vendor/cc-1.0.59/tests/cc_env.rs b/vendor/cc-1.0.59/tests/cc_env.rs new file mode 100644 index 0000000000..43eb689f0f --- /dev/null +++ b/vendor/cc-1.0.59/tests/cc_env.rs @@ -0,0 +1,118 @@ +use std::env; +use std::ffi::OsString; +use std::path::Path; + +mod support; +use crate::support::Test; + +#[test] +fn main() { + ccache(); + distcc(); + ccache_spaces(); + ccache_env_flags(); + leading_spaces(); + extra_flags(); + path_to_ccache(); + more_spaces(); +} + +fn ccache() { + let test = Test::gnu(); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn distcc() { + let test = Test::gnu(); + test.shim("distcc"); + + env::set_var("CC", "distcc cc"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn ccache_env_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache lol-this-is-not-a-compiler"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("lol-this-is-not-a-compiler")); + assert_eq!( + compiler.cc_env(), + OsString::from("ccache lol-this-is-not-a-compiler") + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains("ccache") + == false + ); + assert!( + compiler + .cflags_env() + .into_string() + .unwrap() + .contains(" lol-this-is-not-a-compiler") + == false + ); + + env::set_var("CC", ""); +} + +fn leading_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", " test "); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("test")); + + env::set_var("CC", ""); +} + +fn extra_flags() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "ccache cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} + +fn path_to_ccache() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "/path/to/ccache.exe cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); + assert_eq!( + compiler.cc_env(), + OsString::from("/path/to/ccache.exe cc -m32"), + ); +} + +fn more_spaces() { + let test = Test::gnu(); + test.shim("ccache"); + + env::set_var("CC", "cc -m32"); + let compiler = test.gcc().file("foo.c").get_compiler(); + assert_eq!(compiler.path(), Path::new("cc")); +} diff --git a/vendor/cc-1.0.59/tests/cflags.rs b/vendor/cc-1.0.59/tests/cflags.rs new file mode 100644 index 0000000000..caec6ea4ed --- /dev/null +++ b/vendor/cc-1.0.59/tests/cflags.rs @@ -0,0 +1,15 @@ +mod support; + +use crate::support::Test; +use std::env; + +/// This test is in its own module because it modifies the environment and would affect other tests +/// when run in parallel with them. +#[test] +fn gnu_no_warnings_if_cflags() { + env::set_var("CFLAGS", "-arbitrary"); + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); +} diff --git a/vendor/cc-1.0.59/tests/cxxflags.rs b/vendor/cc-1.0.59/tests/cxxflags.rs new file mode 100644 index 0000000000..c524c7da4e --- /dev/null +++ b/vendor/cc-1.0.59/tests/cxxflags.rs @@ -0,0 +1,15 @@ +mod support; + +use crate::support::Test; +use std::env; + +/// This test is in its own module because it modifies the environment and would affect other tests +/// when run in parallel with them. +#[test] +fn gnu_no_warnings_if_cxxflags() { + env::set_var("CXXFLAGS", "-arbitrary"); + let test = Test::gnu(); + test.gcc().file("foo.cpp").cpp(true).compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_not_have("-Wextra"); +} diff --git a/vendor/cc-1.0.59/tests/support/mod.rs b/vendor/cc-1.0.59/tests/support/mod.rs new file mode 100644 index 0000000000..cde930e90b --- /dev/null +++ b/vendor/cc-1.0.59/tests/support/mod.rs @@ -0,0 +1,173 @@ +#![allow(dead_code)] + +use std::env; +use std::ffi::{OsStr, OsString}; +use std::fs::{self, File}; +use std::io; +use std::io::prelude::*; +use std::path::{Path, PathBuf}; + +use cc; +use tempfile::{Builder, TempDir}; + +pub struct Test { + pub td: TempDir, + pub gcc: PathBuf, + pub msvc: bool, +} + +pub struct Execution { + args: Vec, +} + +impl Test { + pub fn new() -> Test { + // This is ugly: `sccache` needs to introspect the compiler it is + // executing, as it adjusts its behavior depending on the + // language/compiler. This crate's test driver uses mock compilers that + // are obviously not supported by sccache, so the tests fail if + // RUSTC_WRAPPER is set. rust doesn't build test dependencies with + // the `test` feature enabled, so we can't conditionally disable the + // usage of `sccache` if running in a test environment, at least not + // without setting an environment variable here and testing for it + // there. Explicitly deasserting RUSTC_WRAPPER here seems to be the + // lesser of the two evils. + env::remove_var("RUSTC_WRAPPER"); + + let mut gcc = PathBuf::from(env::current_exe().unwrap()); + gcc.pop(); + if gcc.ends_with("deps") { + gcc.pop(); + } + let td = Builder::new().prefix("gcc-test").tempdir_in(&gcc).unwrap(); + gcc.push(format!("gcc-shim{}", env::consts::EXE_SUFFIX)); + Test { + td: td, + gcc: gcc, + msvc: false, + } + } + + pub fn gnu() -> Test { + let t = Test::new(); + t.shim("cc").shim("c++").shim("ar"); + t + } + + pub fn msvc() -> Test { + let mut t = Test::new(); + t.shim("cl").shim("lib.exe"); + t.msvc = true; + t + } + + pub fn shim(&self, name: &str) -> &Test { + link_or_copy( + &self.gcc, + self.td + .path() + .join(&format!("{}{}", name, env::consts::EXE_SUFFIX)), + ) + .unwrap(); + self + } + + pub fn gcc(&self) -> cc::Build { + let mut cfg = cc::Build::new(); + let target = if self.msvc { + "x86_64-pc-windows-msvc" + } else { + "x86_64-unknown-linux-gnu" + }; + + cfg.target(target) + .host(target) + .opt_level(2) + .debug(false) + .out_dir(self.td.path()) + .__set_env("PATH", self.path()) + .__set_env("GCCTEST_OUT_DIR", self.td.path()); + if self.msvc { + cfg.compiler(self.td.path().join("cl")); + cfg.archiver(self.td.path().join("lib.exe")); + } + cfg + } + + fn path(&self) -> OsString { + let mut path = env::split_paths(&env::var_os("PATH").unwrap()).collect::>(); + path.insert(0, self.td.path().to_owned()); + env::join_paths(path).unwrap() + } + + pub fn cmd(&self, i: u32) -> Execution { + let mut s = String::new(); + File::open(self.td.path().join(format!("out{}", i))) + .unwrap() + .read_to_string(&mut s) + .unwrap(); + Execution { + args: s.lines().map(|s| s.to_string()).collect(), + } + } +} + +impl Execution { + pub fn must_have>(&self, p: P) -> &Execution { + if !self.has(p.as_ref()) { + panic!("didn't find {:?} in {:?}", p.as_ref(), self.args); + } else { + self + } + } + + pub fn must_not_have>(&self, p: P) -> &Execution { + if self.has(p.as_ref()) { + panic!("found {:?}", p.as_ref()); + } else { + self + } + } + + pub fn has(&self, p: &OsStr) -> bool { + self.args.iter().any(|arg| OsStr::new(arg) == p) + } + + pub fn must_have_in_order(&self, before: &str, after: &str) -> &Execution { + let before_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(before)); + let after_position = self + .args + .iter() + .rposition(|x| OsStr::new(x) == OsStr::new(after)); + match (before_position, after_position) { + (Some(b), Some(a)) if b < a => {} + (b, a) => panic!( + "{:?} (last position: {:?}) did not appear before {:?} (last position: {:?})", + before, b, after, a + ), + }; + self + } +} + +/// Hard link an executable or copy it if that fails. +/// +/// We first try to hard link an executable to save space. If that fails (as on Windows with +/// different mount points, issue #60), we copy. +#[cfg(not(target_os = "macos"))] +fn link_or_copy, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + let from = from.as_ref(); + let to = to.as_ref(); + fs::hard_link(from, to).or_else(|_| fs::copy(from, to).map(|_| ())) +} + +/// Copy an executable. +/// +/// On macOS, hard linking the executable leads to strange failures (issue #419), so we just copy. +#[cfg(target_os = "macos")] +fn link_or_copy, Q: AsRef>(from: P, to: Q) -> io::Result<()> { + fs::copy(from, to).map(|_| ()) +} diff --git a/vendor/cc-1.0.59/tests/test.rs b/vendor/cc-1.0.59/tests/test.rs new file mode 100644 index 0000000000..3c9b4dc498 --- /dev/null +++ b/vendor/cc-1.0.59/tests/test.rs @@ -0,0 +1,413 @@ +use crate::support::Test; + +mod support; + +// Some tests check that a flag is *not* present. These tests might fail if the flag is set in the +// CFLAGS or CXXFLAGS environment variables. This function clears the CFLAGS and CXXFLAGS +// variables to make sure that the tests can run correctly. +fn reset_env() { + std::env::set_var("CFLAGS", ""); + std::env::set_var("CXXFLAGS", ""); +} + +#[test] +fn gnu_smoke() { + reset_env(); + + let test = Test::gnu(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-g") + .must_have("-c") + .must_have("-ffunction-sections") + .must_have("-fdata-sections"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn gnu_opt_level_1() { + reset_env(); + + let test = Test::gnu(); + test.gcc().opt_level(1).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-O1").must_not_have("-O2"); +} + +#[test] +fn gnu_opt_level_s() { + reset_env(); + + let test = Test::gnu(); + test.gcc().opt_level_str("s").file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-Os") + .must_not_have("-O1") + .must_not_have("-O2") + .must_not_have("-O3") + .must_not_have("-Oz"); +} + +#[test] +fn gnu_debug_fp_auto() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_debug_fp() { + let test = Test::gnu(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_debug_nofp() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .debug(true) + .force_frame_pointer(false) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_not_have("-fno-omit-frame-pointer"); + + let test = Test::gnu(); + test.gcc() + .force_frame_pointer(false) + .debug(true) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-g"); + test.cmd(0).must_not_have("-fno-omit-frame-pointer"); +} + +#[test] +fn gnu_warnings_into_errors() { + let test = Test::gnu(); + test.gcc() + .warnings_into_errors(true) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Werror"); +} + +#[test] +fn gnu_warnings() { + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings0() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(true) + .extra_warnings(false) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-Wall").must_not_have("-Wextra"); +} + +#[test] +fn gnu_extra_warnings1() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(false) + .extra_warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-Wall").must_have("-Wextra"); +} + +#[test] +fn gnu_warnings_overridable() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .warnings(true) + .flag("-Wno-missing-field-initializers") + .file("foo.c") + .compile("foo"); + + test.cmd(0) + .must_have_in_order("-Wall", "-Wno-missing-field-initializers"); +} + +#[test] +fn gnu_x86_64() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC").must_have("-m64"); + } +} + +#[test] +fn gnu_x86_64_no_pic() { + reset_env(); + + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("x86_64-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-fPIC"); + } +} + +#[test] +fn gnu_i686() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-m32"); + } +} + +#[test] +fn gnu_i686_pic() { + for vendor in &["unknown-linux-gnu", "apple-darwin"] { + let target = format!("i686-{}", vendor); + let test = Test::gnu(); + test.gcc() + .pic(true) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-fPIC"); + } +} + +#[test] +fn gnu_x86_64_no_plt() { + let target = "x86_64-unknown-linux-gnu"; + let test = Test::gnu(); + test.gcc() + .pic(true) + .use_plt(false) + .target(&target) + .host(&target) + .file("foo.c") + .compile("foo"); + test.cmd(0).must_have("-fno-plt"); +} + +#[test] +fn gnu_set_stdlib() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .cpp_set_stdlib(Some("foo")) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_not_have("-stdlib=foo"); +} + +#[test] +fn gnu_include() { + let test = Test::gnu(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn gnu_define() { + let test = Test::gnu(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn gnu_compile_assembly() { + let test = Test::gnu(); + test.gcc().file("foo.S").compile("foo"); + test.cmd(0).must_have("foo.S"); +} + +#[test] +fn gnu_shared() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(true) + .static_flag(false) + .compile("foo"); + + test.cmd(0).must_have("-shared").must_not_have("-static"); +} + +#[test] +fn gnu_flag_if_supported() { + reset_env(); + + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .flag("-v") + .flag_if_supported("-Wall") + .flag_if_supported("-Wflag-does-not-exist") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0) + .must_have("-v") + .must_have("-Wall") + .must_not_have("-Wflag-does-not-exist") + .must_not_have("-std=c++11"); +} + +#[test] +fn gnu_flag_if_supported_cpp() { + if cfg!(windows) { + return; + } + let test = Test::gnu(); + test.gcc() + .cpp(true) + .file("foo.cpp") + .flag_if_supported("-std=c++11") + .compile("foo"); + + test.cmd(0).must_have("-std=c++11"); +} + +#[test] +fn gnu_static() { + reset_env(); + + let test = Test::gnu(); + test.gcc() + .file("foo.c") + .shared_flag(false) + .static_flag(true) + .compile("foo"); + + test.cmd(0).must_have("-static").must_not_have("-shared"); +} + +#[test] +fn msvc_smoke() { + reset_env(); + + let test = Test::msvc(); + test.gcc().file("foo.c").compile("foo"); + + test.cmd(0) + .must_have("-O2") + .must_have("foo.c") + .must_not_have("-Z7") + .must_have("-c") + .must_have("-MD"); + test.cmd(1).must_have(test.td.path().join("foo.o")); +} + +#[test] +fn msvc_opt_level_0() { + reset_env(); + + let test = Test::msvc(); + test.gcc().opt_level(0).file("foo.c").compile("foo"); + + test.cmd(0).must_not_have("-O2"); +} + +#[test] +fn msvc_debug() { + let test = Test::msvc(); + test.gcc().debug(true).file("foo.c").compile("foo"); + test.cmd(0).must_have("-Z7"); +} + +#[test] +fn msvc_include() { + let test = Test::msvc(); + test.gcc().include("foo/bar").file("foo.c").compile("foo"); + + test.cmd(0).must_have("-I").must_have("foo/bar"); +} + +#[test] +fn msvc_define() { + let test = Test::msvc(); + test.gcc() + .define("FOO", "bar") + .define("BAR", None) + .file("foo.c") + .compile("foo"); + + test.cmd(0).must_have("-DFOO=bar").must_have("-DBAR"); +} + +#[test] +fn msvc_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(true).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-MT"); +} + +#[test] +fn msvc_no_static_crt() { + let test = Test::msvc(); + test.gcc().static_crt(false).file("foo.c").compile("foo"); + + test.cmd(0).must_have("-MD"); +} diff --git a/vendor/cc/.cargo-checksum.json b/vendor/cc/.cargo-checksum.json index a9252fa545..6b12277a4b 100644 --- a/vendor/cc/.cargo-checksum.json +++ b/vendor/cc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"bd34a585a35969291c78b96b1f239fa09f1f9dbeee48474989695def1ed64052","Cargo.toml":"cb73923110f764c2a6da0fde98db8f5f7c7194bd56e96e2f302da9ba29cba0a8","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"68fe1bc9f8aab4d8d195e8bc39fe76562742dc392f5c490e5404e01463100277","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"96f4782c70e0bd8d9ab7ce3efcc2091d2591c3276c0ed672e2379748bb3930aa","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"66120af515773fb005778dc07c261bd201ec8ce50bd6e7144c927753fe013381"} \ No newline at end of file +{"files":{"Cargo.lock":"30b9e23f97015aea3eed3e17c6d76d565c2924efec8bdae64c899080847afe89","Cargo.toml":"f6f22b69df3df57c58373cdee72b22218ffa030bc375b36632660037dd72c866","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"51405d284d2e0620db62c655c652fc0ec84f20c1cb30529227355c9575a9e6dd","src/bin/gcc-shim.rs":"b77907875029494b6288841c3aed2e4939ed40708c7f597fca5c9e2570490ca6","src/com.rs":"bcdaf1c28b71e6ef889c6b08d1ce9d7c0761344a677f523bc4c3cd297957f804","src/lib.rs":"903c5f2f5dd0cc7d04f99f605a95e6abde8b38156fd4e73eefc58493f55a4e5a","src/registry.rs":"3cc1b5a50879fa751572878ae1d0afbfc960c11665258492754b2c8bccb0ff5d","src/setup_config.rs":"7014103587d3382eac599cb76f016e2609b8140970861b2237982d1db24af265","src/winapi.rs":"ea8b7edbb9ff87957254f465c2334e714c5d6b3b19a8d757c48ea7ca0881c50c","src/windows_registry.rs":"52afe8554f577c87841c48ddee3ba7ffe70a00129e1d6eeb2ec0efb3d2b9aa11","tests/cc_env.rs":"e02b3b0824ad039b47e4462c5ef6dbe6c824c28e7953af94a0f28f7b5158042e","tests/cflags.rs":"57f06eb5ce1557e5b4a032d0c4673e18fbe6f8d26c1deb153126e368b96b41b3","tests/cxxflags.rs":"c2c6c6d8a0d7146616fa1caed26876ee7bc9fcfffd525eb4743593cade5f3371","tests/support/mod.rs":"16274867f23871e9b07614eda4c7344da13d1751fed63d4f633857e40be86394","tests/test.rs":"65c073e0e2cf4aa0433066102788e9f57442719e6f32f5ad5248aa7132bb4597"},"package":"ef611cc68ff783f18535d77ddd080185275713d852c4f5cbb6122c462a7a825c"} \ No newline at end of file diff --git a/vendor/cc/Cargo.lock b/vendor/cc/Cargo.lock index a624f35455..f48ad9b92f 100644 --- a/vendor/cc/Cargo.lock +++ b/vendor/cc/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "cc" -version = "1.0.59" +version = "1.0.60" dependencies = [ "jobserver", "tempfile", @@ -16,9 +16,9 @@ checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" [[package]] name = "getrandom" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +checksum = "fc587bc0ec293155d5bfa6b9891ec18a1e330c234f896ea47fbada4cadbe47e6" dependencies = [ "cfg-if", "libc", @@ -36,15 +36,15 @@ dependencies = [ [[package]] name = "libc" -version = "0.2.74" +version = "0.2.77" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a2f02823cf78b754822df5f7f268fb59822e7296276d3e069d8e8cb26a14bd10" +checksum = "f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235" [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +checksum = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" [[package]] name = "rand" diff --git a/vendor/cc/Cargo.toml b/vendor/cc/Cargo.toml index 2b3aac577f..a198b2fdee 100644 --- a/vendor/cc/Cargo.toml +++ b/vendor/cc/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "cc" -version = "1.0.59" +version = "1.0.60" authors = ["Alex Crichton "] exclude = ["/.travis.yml", "/appveyor.yml"] description = "A build-time dependency for Cargo build scripts to assist in invoking the native\nC compiler to compile native C code into a static archive to be linked into Rust\ncode.\n" diff --git a/vendor/cc/README.md b/vendor/cc/README.md index e147d7e177..c792132af0 100644 --- a/vendor/cc/README.md +++ b/vendor/cc/README.md @@ -8,9 +8,6 @@ A simple library meant to be used as a build dependency with Cargo packages in order to build a set of C/C++ files into a static archive. This crate calls out to the most relevant compiler for a platform, for example using `cl` on MSVC. -> **Note**: this crate was recently renamed from the `gcc` crate, so if you're -> looking for the `gcc` crate you're in the right spot! - ## Using cc-rs First, you'll want to both add a build script for your crate (`build.rs`) and diff --git a/vendor/cc/src/lib.rs b/vendor/cc/src/lib.rs index fecc073056..aff6be86a9 100644 --- a/vendor/cc/src/lib.rs +++ b/vendor/cc/src/lib.rs @@ -1423,7 +1423,16 @@ impl Build { if !(target.contains("android") && android_clang_compiler_uses_target_arg_internally(&cmd.path)) { - cmd.args.push(format!("--target={}", target).into()); + if target.contains("darwin") { + if let Some(arch) = + map_darwin_target_from_rust_to_compiler_architecture(target) + { + cmd.args + .push(format!("--target={}-apple-darwin", arch).into()); + } + } else { + cmd.args.push(format!("--target={}", target).into()); + } } } ToolFamily::Msvc { clang_cl } => { @@ -1471,15 +1480,10 @@ impl Build { } if target.contains("darwin") { - if target.contains("x86_64") { + if let Some(arch) = map_darwin_target_from_rust_to_compiler_architecture(target) + { cmd.args.push("-arch".into()); - cmd.args.push("x86_64".into()); - } else if target.contains("arm64e") { - cmd.args.push("-arch".into()); - cmd.args.push("arm64e".into()); - } else if target.contains("aarch64") { - cmd.args.push("-arch".into()); - cmd.args.push("arm64".into()); + cmd.args.push(arch.into()); } } @@ -2002,7 +2006,11 @@ impl Build { { "clang".to_string() } else if target.contains("vxworks") { - "wr-c++".to_string() + if self.cpp { + "wr-c++".to_string() + } else { + "wr-cc".to_string() + } } else if self.get_host()? != target { let prefix = self.prefix_for_target(&target); match prefix { @@ -2958,3 +2966,16 @@ fn autodetect_android_compiler(target: &str, host: &str, gnu: &str, clang: &str) clang_compiler } } + +// Rust and clang/cc don't agree on how to name the target. +fn map_darwin_target_from_rust_to_compiler_architecture(target: &str) -> Option<&'static str> { + if target.contains("x86_64") { + Some("x86_64") + } else if target.contains("arm64e") { + Some("arm64e") + } else if target.contains("aarch64") { + Some("arm64") + } else { + None + } +} diff --git a/vendor/chalk-derive-0.14.0/.cargo-checksum.json b/vendor/chalk-derive-0.14.0/.cargo-checksum.json deleted file mode 100644 index fa6df7fe6b..0000000000 --- a/vendor/chalk-derive-0.14.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"5afc28841a188f45dab6b221c873c9e32f6292cb68b84585a2552c83761c1542","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"d463e01905d607e181de72e8608721d3269f29176c9a14ce037011316ae7131d"} \ No newline at end of file diff --git a/vendor/chalk-derive-0.25.0/.cargo-checksum.json b/vendor/chalk-derive-0.25.0/.cargo-checksum.json new file mode 100644 index 0000000000..105ed5c0da --- /dev/null +++ b/vendor/chalk-derive-0.25.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b9d70df3e3d8b2b593772a42e2997e2e8e4a04ecdb87ae6f6bce09246cc89497","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"624e14d3f029186e6ffd97081ffa082f98ddd5df20655b6f0e8efb83dd8ac8b4"} \ No newline at end of file diff --git a/vendor/chalk-derive-0.14.0/Cargo.toml b/vendor/chalk-derive-0.25.0/Cargo.toml similarity index 98% rename from vendor/chalk-derive-0.14.0/Cargo.toml rename to vendor/chalk-derive-0.25.0/Cargo.toml index 2ca4f319d7..af9654d259 100644 --- a/vendor/chalk-derive-0.14.0/Cargo.toml +++ b/vendor/chalk-derive-0.25.0/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-derive" -version = "0.14.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "A helper crate for use by chalk crates for `derive` macros." readme = "README.md" diff --git a/vendor/chalk-derive-0.14.0/README.md b/vendor/chalk-derive-0.25.0/README.md similarity index 100% rename from vendor/chalk-derive-0.14.0/README.md rename to vendor/chalk-derive-0.25.0/README.md diff --git a/vendor/chalk-derive-0.14.0/src/lib.rs b/vendor/chalk-derive-0.25.0/src/lib.rs similarity index 100% rename from vendor/chalk-derive-0.14.0/src/lib.rs rename to vendor/chalk-derive-0.25.0/src/lib.rs diff --git a/vendor/chalk-derive/.cargo-checksum.json b/vendor/chalk-derive/.cargo-checksum.json index 6657399932..0a2e24c003 100644 --- a/vendor/chalk-derive/.cargo-checksum.json +++ b/vendor/chalk-derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"89cff317fa4dbf470456d226db4e76a146490cf0bcdbb250d62f7cad58561710","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"c3cb438e961fd7f1183dc5e0bdcfd09253bf9b90592cf665d1ce6787d8a4908f"} \ No newline at end of file +{"files":{"Cargo.toml":"00ef8d136fcbf3b4a9ff2348994d1bf5fb991067ef00fe447b8dc17ba71b13ec","README.md":"41a362e6750d37202fcf0a87a0b48ae41552715d97d740ee9883424ebae78564","src/lib.rs":"fea6545836f3b1c61cea44bba2b9c85c81fc85e310615d4f148466a12197e68c"},"package":"3a7f257e3bcdc56d8877ae31c012bd69fba0be66929d588e603905f2632c0c59"} \ No newline at end of file diff --git a/vendor/chalk-derive/Cargo.toml b/vendor/chalk-derive/Cargo.toml index 90ab38b870..6f6b1902c7 100644 --- a/vendor/chalk-derive/Cargo.toml +++ b/vendor/chalk-derive/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-derive" -version = "0.23.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "A helper crate for use by chalk crates for `derive` macros." readme = "README.md" diff --git a/vendor/chalk-engine/.cargo-checksum.json b/vendor/chalk-engine/.cargo-checksum.json index ce5202e5d6..71a6151fe6 100644 --- a/vendor/chalk-engine/.cargo-checksum.json +++ b/vendor/chalk-engine/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"0b93b1a262052bb3da1c77b89966bed3a6d67f62ce694e9a0c991ca2ac2cc757","README.md":"d8d9a21a6700b554e110030288fb94ca98fa6c6398fa6a5a1dafa52b3f7dd545","src/README.md":"6606b446db6a271e99f1019cd6e59a44af50e7b1ee995718d30fde11c09bbc80","src/context.rs":"e9c9485eacd80f44a16e9d23c8290b09e8a35ca20ff15d97786b7d853ed98693","src/derived.rs":"a59fe981325e664865bf21407e4a24e317b00cc2545b380d1140b4fddc86ede3","src/forest.rs":"a3fd27964be8465932ec4de4bb4cf991faf0df927fe0c960941eaeff1434deb3","src/lib.rs":"15367f2f3e0af018fb6aa8fab3715aea599a0f340aa98dd638f8e9f04b249140","src/logic.rs":"68ac57c93b163d86d7d27f45fdadc155effe512155c489dd60c97d4ed5d37e15","src/simplify.rs":"9e595790550c6e8d26dcfdfe3a041908cb8c059c28f51c0aeb5e672071151e6b","src/stack.rs":"aff571cc6e7383dd4d7365d9fb19b5f9c1e91106de74f47fbaf6fd07af03b466","src/strand.rs":"03f70b15c17452dab3604819edf6ebae94d373ab47e2bfa32d8bbff706a70101","src/table.rs":"fd6751107314b836dc8738df025fb7a6f40d93fd18effc9fdf61dd055194c01c","src/tables.rs":"8c0e31d1d16120580e214a84c3d1a841462a50903a0da509a9c68c35b00cd642"},"package":"efaf428f5398d36284f79690cf988762b7c091249f50a6c11db613a46c057000"} \ No newline at end of file +{"files":{"Cargo.toml":"db8f2d350c608a2a4f781754d506f040a884240b6f506051f4a446dbc33b7ea4","README.md":"d8d9a21a6700b554e110030288fb94ca98fa6c6398fa6a5a1dafa52b3f7dd545","src/README.md":"6606b446db6a271e99f1019cd6e59a44af50e7b1ee995718d30fde11c09bbc80","src/context.rs":"e9c9485eacd80f44a16e9d23c8290b09e8a35ca20ff15d97786b7d853ed98693","src/derived.rs":"a59fe981325e664865bf21407e4a24e317b00cc2545b380d1140b4fddc86ede3","src/forest.rs":"af603f739e0921dc5520f2ddaa0606c5e7901f918826cfecbb34b9d5fe90d090","src/lib.rs":"a23eb51a4a9854f550700e66e1c8035fec59cbedd2a15a7e35a5e8e60a99f369","src/logic.rs":"96b55c0b85b4568fa1211047187bae7ac33e448e6375cc4c340493288ca81435","src/normalize_deep.rs":"c95cdd01aba4a0dd000b7cb765f1668bcc874199342274a3fb12f65e3dbb827c","src/simplify.rs":"8d1d0691897f9823c61037aadfaaf39538d770c410470bb11402fca33b0303d9","src/slg.rs":"5d162d8934b512a336fe7fc4f6f9927cfb6caba74e473395a667d7131741845d","src/slg/aggregate.rs":"cc11aa6a0ef4dc1f3894fafb3f0d8cb157f168c0d0d811e10e9b3d6cb6afc9ff","src/slg/resolvent.rs":"3132d66fd6a7139f7e1ffa276626fde1f6010c7e00fb0bc1b978dca3feb2cc78","src/solve.rs":"7ab67699c8d70ca60aded258c37b98f06004b2ad63a702af8af6114a46d578d5","src/stack.rs":"3c872d5ccc5f86184b936b1faff927c8cfe57ea068a1d8d9e9946bb6a0c5fa26","src/strand.rs":"03f70b15c17452dab3604819edf6ebae94d373ab47e2bfa32d8bbff706a70101","src/table.rs":"57debdcd6ec49a68122fdcb2ba6f704e82307074bda9ac82a509892b6d778927","src/tables.rs":"c140ea3b7ada35c097f578dc81873164c2c36f41adfb5f7d0d71cd9978974a23"},"package":"c43fcc7edf4d51b42f44ed50e2337bd90ddc8e088d0cd78a71db92a6f780f782"} \ No newline at end of file diff --git a/vendor/chalk-engine/Cargo.toml b/vendor/chalk-engine/Cargo.toml index 792947dfcf..dce8801d95 100644 --- a/vendor/chalk-engine/Cargo.toml +++ b/vendor/chalk-engine/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-engine" -version = "0.14.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Core trait engine from Chalk project" readme = "README.md" @@ -21,10 +21,13 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.14.0" +version = "=0.29.0" [dependencies.chalk-ir] -version = "=0.14.0" +version = "=0.29.0" + +[dependencies.chalk-solve] +version = "=0.29.0" [dependencies.rustc-hash] version = "1.1.0" @@ -32,5 +35,7 @@ version = "1.1.0" [dependencies.tracing] version = "0.1" +[dev-dependencies] + [features] default = [] diff --git a/vendor/chalk-engine/src/forest.rs b/vendor/chalk-engine/src/forest.rs index 2a45067957..2a6a309393 100644 --- a/vendor/chalk-engine/src/forest.rs +++ b/vendor/chalk-engine/src/forest.rs @@ -8,7 +8,7 @@ use chalk_ir::interner::Interner; use chalk_ir::{Goal, InEnvironment, Substitution, UCanonical}; use tracing::debug; -pub struct Forest> { +pub(crate) struct Forest> { pub(crate) tables: Tables, /// This is a clock which always increases. It is @@ -76,7 +76,7 @@ impl<'me, I: Interner, C: Context, CO: ContextOps> AnswerStream .root_answer(self.context, self.table, self.answer) { Ok(answer) => { - debug!("Answer: {:?}", &answer); + debug!(answer = ?(&answer)); return AnswerResult::Answer(answer); } diff --git a/vendor/chalk-engine/src/lib.rs b/vendor/chalk-engine/src/lib.rs index 0a958a3933..369de54fe9 100644 --- a/vendor/chalk-engine/src/lib.rs +++ b/vendor/chalk-engine/src/lib.rs @@ -68,7 +68,10 @@ pub mod context; mod derived; pub mod forest; mod logic; +mod normalize_deep; mod simplify; +pub mod slg; +pub mod solve; mod stack; mod strand; mod table; diff --git a/vendor/chalk-engine/src/logic.rs b/vendor/chalk-engine/src/logic.rs index 931b642c71..de17def483 100644 --- a/vendor/chalk-engine/src/logic.rs +++ b/vendor/chalk-engine/src/logic.rs @@ -12,8 +12,8 @@ use crate::{ use chalk_ir::interner::Interner; use chalk_ir::{ - Canonical, ConstrainedSubst, DomainGoal, Floundered, Goal, GoalData, InEnvironment, NoSolution, - Substitution, UCanonical, UniverseMap, WhereClause, + Canonical, ConstrainedSubst, Floundered, Goal, GoalData, InEnvironment, NoSolution, + Substitution, UCanonical, UniverseMap, }; use tracing::{debug, debug_span, info, instrument}; @@ -196,8 +196,7 @@ impl> Forest { } }; - debug!("ucanonical_subgoal={:?}", ucanonical_subgoal); - debug!("universe_map={:?}", universe_map); + debug!(?ucanonical_subgoal, ?universe_map); let table = self.get_or_create_table_for_ucanonical_goal(context, ucanonical_subgoal); @@ -218,14 +217,14 @@ impl> Forest { goal: UCanonical>>, ) -> TableIndex { if let Some(table) = self.tables.index_of(&goal) { - debug!("found existing table {:?}", table); + debug!(?table, "found existing table"); return table; } info!( - "creating new table {:?} and goal {:#?}", - self.tables.next_index(), - goal + table = ?self.tables.next_index(), + "creating new table with goal = {:#?}", + goal, ); let table = Self::build_table(context, self.tables.next_index(), goal); self.tables.insert(table) @@ -251,16 +250,8 @@ impl> Forest { let (mut infer, subst, environment, goal) = context.instantiate_ucanonical_goal(&goal); let goal_data = goal.data(context.interner()); - let is_outlives_goal = |dg: &DomainGoal| { - if let DomainGoal::Holds(WhereClause::LifetimeOutlives(_)) = dg { - true - } else { - false - } - }; - match goal_data { - GoalData::DomainGoal(domain_goal) if !is_outlives_goal(domain_goal) => { + GoalData::DomainGoal(domain_goal) => { match context.program_clauses(&environment, &domain_goal, &mut infer) { Ok(clauses) => { for clause in clauses { @@ -287,6 +278,7 @@ impl> Forest { } Err(Floundered) => { debug!( + table = ?table_idx, "Marking table {:?} as floundered! (failed to create program clauses)", table_idx ); @@ -308,8 +300,8 @@ impl> Forest { Self::simplify_goal(context, &mut infer, subst, environment, goal) { info!( - "pushing initial strand with ex-clause: {:#?}", - infer.debug_ex_clause(context.interner(), &ex_clause), + ex_clause = ?infer.debug_ex_clause(context.interner(), &ex_clause), + "pushing initial strand" ); let strand = Strand { infer, @@ -464,8 +456,6 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore self.stack .push(initial_table, Minimums::MAX, self.forest.increment_clock()); loop { - // FIXME: use depth for debug/info printing - let clock = self.stack.top().clock; // If we had an active strand, continue to pursue it let table = self.stack.top().table; @@ -500,18 +490,17 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore } = canonical_strand; let (infer, ex_clause) = context.instantiate_ex_clause(num_universes, &canonical_ex_clause); - let strand = Strand { + Strand { infer, ex_clause, - selected_subgoal: selected_subgoal.clone(), + selected_subgoal, last_pursued_time, - }; - strand + } }) }); match next_strand { Some(mut strand) => { - debug!("next strand: {:#?}", strand); + debug!("starting next strand = {:#?}", strand); strand.last_pursued_time = clock; match self.select_subgoal(&mut strand) { @@ -606,7 +595,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore infer: strand.infer.clone(), ex_clause: strand.ex_clause.clone(), selected_subgoal: Some(next_subgoal), - last_pursued_time: strand.last_pursued_time.clone(), + last_pursued_time: strand.last_pursued_time, }; let table = self.stack.top().table; let canonical_next_strand = Forest::canonicalize_strand(self.context, next_strand); @@ -723,7 +712,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // We want to disproval the subgoal, but we // have an unconditional answer for the subgoal, // therefore we have failed to disprove it. - debug!("Marking Strand as ambiguous because answer to (negative) subgoal was ambiguous"); + debug!(?strand, "Marking Strand as ambiguous because answer to (negative) subgoal was ambiguous"); strand.ex_clause.ambiguous = true; // Strand is ambigious. @@ -757,7 +746,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // and maybe come back to it. self.flounder_subgoal(&mut strand.ex_clause, selected_subgoal.subgoal_index); - return false; + false } Literal::Negative(_) => { // Floundering on a negative literal isn't like a @@ -779,7 +768,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // This strand has no solution. It is no longer active, // so it dropped at the end of this scope. - return true; + true } } } @@ -811,7 +800,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore strand.ex_clause.delayed_subgoals.push(subgoal); self.stack.top().active_strand = Some(strand); - return Ok(()); + Ok(()) } Literal::Negative(_) => { // We don't allow coinduction for negative literals @@ -887,7 +876,9 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore } = *strand.selected_subgoal.as_ref().unwrap(); debug!( - "table selection {:?} with goal: {:#?}", + ?subgoal_table, + goal = ?self.forest.tables[subgoal_table].table_goal, + "table selection {:?} with goal: {:?}", subgoal_table, self.forest.tables[subgoal_table].table_goal ); @@ -902,12 +893,12 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // We need to check if we can merge it into the current `Strand`. match self.merge_answer_into_strand(&mut strand) { Err(e) => { - debug!("could not merge into current strand"); + debug!(?strand, "could not merge into current strand"); drop(strand); return Err(e); } Ok(_) => { - debug!("merged answer into current strand"); + debug!(?strand, "merged answer into current strand"); self.stack.top().active_strand = Some(strand); return Ok(()); } @@ -967,7 +958,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore return NoRemainingSubgoalsResult::RootSearchFail(RootSearchFail::QuantumExceeded); } } - let floundered = strand.ex_clause.floundered_subgoals.len() > 0; + let floundered = !strand.ex_clause.floundered_subgoals.is_empty(); if floundered { debug!("all remaining subgoals floundered for the table"); } else { @@ -984,7 +975,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore match self.stack.pop_and_take_caller_strand() { Some(caller_strand) => { self.stack.top().active_strand = Some(caller_strand); - return NoRemainingSubgoalsResult::Success; + NoRemainingSubgoalsResult::Success } None => { // That was the root table, so we are done -- @@ -1003,9 +994,9 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore self.forest.tables[table].enqueue_strand(strand); } - return NoRemainingSubgoalsResult::RootAnswerAvailable; + NoRemainingSubgoalsResult::RootAnswerAvailable } - }; + } } None => { debug!("answer is not available (or not new)"); @@ -1016,9 +1007,9 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // Now we yield with `QuantumExceeded` self.unwind_stack(); - return NoRemainingSubgoalsResult::RootSearchFail(RootSearchFail::QuantumExceeded); + NoRemainingSubgoalsResult::RootSearchFail(RootSearchFail::QuantumExceeded) } - }; + } } /// A "refinement" strand is used in coinduction. When the root @@ -1074,13 +1065,13 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore } fn on_no_strands_left(&mut self) -> Result<(), RootSearchFail> { - debug!("no more strands available (or all cycles)"); + let table = self.stack.top().table; + debug!("no more strands available (or all cycles) for {:?}", table); // No more strands left to try! This is either because all // strands have failed, because all strands encountered a // cycle, or all strands have would give ambiguous answers. - let table = self.stack.top().table; if self.forest.tables[table].strands_mut().count() == 0 { // All strands for the table T on the top of the stack // have **failed**. Hence we can pop it off the stack and @@ -1127,36 +1118,12 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore }; } - let num_universes = self.forest.tables[table].table_goal.universes; - let table_answer_mode = self.forest.tables[table].answer_mode; - let forest = &mut self.forest; - let context = &self.context; - let strand_is_participating = |strand: &CanonicalStrand| { - let (_, ex_clause) = - context.instantiate_ex_clause(num_universes, &strand.canonical_ex_clause); - match (table_answer_mode, ex_clause.ambiguous) { - (AnswerMode::Complete, true) => false, - (AnswerMode::Complete, false) => true, - (AnswerMode::Ambiguous, _) => true, - } - }; - if forest.tables[table] - .strands_mut() - .all(|s| !strand_is_participating(s)) - { - // If no strands are participating, then that means they are all - // ambiguous and we are in complete mode. - debug!("All strands would return ambiguous answers."); - match self.forest.tables[table].answer_mode { - AnswerMode::Complete => { - debug!("Allowing ambiguous answers."); - self.forest.tables[table].answer_mode = AnswerMode::Ambiguous; - return Err(RootSearchFail::QuantumExceeded); - } - AnswerMode::Ambiguous => { - unreachable!(); - } - } + // We can't consider this table as part of a cycle unless we've handled + // all strands, not just non-ambiguous ones. See chalk#571. + if let AnswerMode::Complete = self.forest.tables[table].answer_mode { + debug!("Allowing ambiguous answers."); + self.forest.tables[table].answer_mode = AnswerMode::Ambiguous; + return Err(RootSearchFail::QuantumExceeded); } let clock = self.stack.top().clock; @@ -1175,9 +1142,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore // then no more answers are forthcoming. We can clear all // the strands for those things recursively. let table = self.stack.top().table; - // N.B. If we try to pursue a strand and it's found to be ambiguous, - // we know that isn't part of a cycle. - let cyclic_strands = self.forest.tables[table].drain_strands(strand_is_participating); + let cyclic_strands = self.forest.tables[table].take_strands(); self.clear_strands_after_cycle(cyclic_strands); // Now we yield with `QuantumExceeded` @@ -1418,10 +1383,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore constraints, filtered_delayed_subgoals, ); - debug!( - "answer: table={:?}, subst={:?}, floundered={:?}", - table, subst, floundered - ); + debug!(?table, ?subst, ?floundered, "found answer"); let answer = Answer { subst, ambiguous }; @@ -1486,7 +1448,11 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore let is_trivial_answer = { self.context .is_trivial_substitution(&self.forest.tables[table].table_goal, &answer.subst) - && answer.subst.value.constraints.is_empty() + && answer + .subst + .value + .constraints + .is_empty(self.context.interner()) }; if let Some(answer_index) = self.forest.tables[table].push_answer(answer) { @@ -1536,7 +1502,7 @@ impl<'forest, I: Interner, C: Context + 'forest, CO: ContextOps + 'fore floundered_literal, floundered_time, }); - debug!("flounder_subgoal: ex_clause={:#?}", ex_clause); + debug!(?ex_clause); } /// True if all the tables on the stack starting from `depth` and diff --git a/vendor/chalk-solve-0.14.0/src/infer/normalize_deep.rs b/vendor/chalk-engine/src/normalize_deep.rs similarity index 66% rename from vendor/chalk-solve-0.14.0/src/infer/normalize_deep.rs rename to vendor/chalk-engine/src/normalize_deep.rs index 4491929057..6e37d6f7b7 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/normalize_deep.rs +++ b/vendor/chalk-engine/src/normalize_deep.rs @@ -2,10 +2,14 @@ use chalk_ir::fold::shift::Shift; use chalk_ir::fold::{Fold, Folder}; use chalk_ir::interner::Interner; use chalk_ir::*; +use chalk_solve::infer::InferenceTable; -use super::InferenceTable; +pub(crate) struct DeepNormalizer<'table, 'i, I: Interner> { + table: &'table mut InferenceTable, + interner: &'i I, +} -impl InferenceTable { +impl DeepNormalizer<'_, '_, I> { /// Given a value `value` with variables in it, replaces those variables /// with their instantiated values (if any). Uninstantiated variables are /// left as-is. @@ -17,24 +21,20 @@ impl InferenceTable { /// See also `InferenceTable::canonicalize`, which -- during real /// processing -- is often used to capture the "current state" of /// variables. - pub(crate) fn normalize_deep>(&mut self, interner: &I, value: &T) -> T::Result { + pub fn normalize_deep>( + table: &mut InferenceTable, + interner: &I, + value: &T, + ) -> T::Result { value .fold_with( - &mut DeepNormalizer { - interner, - table: self, - }, + &mut DeepNormalizer { interner, table }, DebruijnIndex::INNERMOST, ) .unwrap() } } -struct DeepNormalizer<'table, 'i, I: Interner> { - table: &'table mut InferenceTable, - interner: &'i I, -} - impl<'i, I: Interner> Folder<'i, I> for DeepNormalizer<'_, 'i, I> where I: 'i, @@ -102,3 +102,35 @@ where self.interner() } } + +#[cfg(test)] +mod test { + use super::*; + use chalk_integration::interner::ChalkIr; + use chalk_integration::{arg, ty, ty_name}; + + const U0: UniverseIndex = UniverseIndex { counter: 0 }; + + #[test] + fn infer() { + let interner = &ChalkIr; + let mut table: InferenceTable = InferenceTable::new(); + let environment0 = Environment::new(interner); + let a = table.new_variable(U0).to_ty(interner); + let b = table.new_variable(U0).to_ty(interner); + table + .unify(interner, &environment0, &a, &ty!(apply (item 0) (expr b))) + .unwrap(); + assert_eq!( + DeepNormalizer::normalize_deep(&mut table, interner, &a), + ty!(apply (item 0) (expr b)) + ); + table + .unify(interner, &environment0, &b, &ty!(apply (item 1))) + .unwrap(); + assert_eq!( + DeepNormalizer::normalize_deep(&mut table, interner, &a), + ty!(apply (item 0) (apply (item 1))) + ); + } +} diff --git a/vendor/chalk-engine/src/simplify.rs b/vendor/chalk-engine/src/simplify.rs index 9e9c6ed600..a1087eea82 100644 --- a/vendor/chalk-engine/src/simplify.rs +++ b/vendor/chalk-engine/src/simplify.rs @@ -4,8 +4,7 @@ use crate::{ExClause, Literal, TimeStamp}; use chalk_ir::interner::Interner; use chalk_ir::{ - Constraint, DomainGoal, Environment, Fallible, Goal, GoalData, InEnvironment, LifetimeOutlives, - QuantifierKind, Substitution, WhereClause, + Environment, Fallible, Goal, GoalData, InEnvironment, QuantifierKind, Substitution, }; use tracing::debug; @@ -69,23 +68,15 @@ impl> Forest { &goal.b, &mut ex_clause, )?, - GoalData::DomainGoal(domain_goal) => match domain_goal { - DomainGoal::Holds(WhereClause::LifetimeOutlives(LifetimeOutlives { a, b })) => { - ex_clause.constraints.push(InEnvironment::new( + GoalData::DomainGoal(domain_goal) => { + ex_clause + .subgoals + .push(Literal::Positive(InEnvironment::new( &environment, - Constraint::Outlives(a.clone(), b.clone()), - )); - } - _ => { - ex_clause - .subgoals - .push(Literal::Positive(InEnvironment::new( - &environment, - context.into_goal(domain_goal.clone()), - ))); - } - }, - GoalData::CannotProve(()) => { + context.into_goal(domain_goal.clone()), + ))); + } + GoalData::CannotProve => { debug!("Marking Strand as ambiguous because of a `CannotProve` subgoal"); ex_clause.ambiguous = true; } diff --git a/vendor/chalk-solve-0.14.0/src/solve/slg.rs b/vendor/chalk-engine/src/slg.rs similarity index 88% rename from vendor/chalk-solve-0.14.0/src/solve/slg.rs rename to vendor/chalk-engine/src/slg.rs index fbf880ed3a..640f12cc3a 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/slg.rs +++ b/vendor/chalk-engine/src/slg.rs @@ -1,58 +1,26 @@ -use crate::clauses::program_clauses_for_goal; -use crate::coinductive_goal::IsCoinductive; -use crate::infer::ucanonicalize::UCanonicalized; -use crate::infer::unify::UnificationResult; -use crate::infer::InferenceTable; -use crate::solve::truncate; -use crate::RustIrDatabase; +use crate::context; +use crate::normalize_deep::DeepNormalizer; +use crate::{ExClause, Literal}; + use chalk_derive::HasInterner; -use chalk_engine::context; -use chalk_engine::{ExClause, Literal}; use chalk_ir::cast::Cast; use chalk_ir::cast::Caster; use chalk_ir::interner::Interner; use chalk_ir::*; +use chalk_solve::clauses::program_clauses_for_goal; +use chalk_solve::coinductive_goal::IsCoinductive; +use chalk_solve::infer::ucanonicalize::UCanonicalized; +use chalk_solve::infer::unify::UnificationResult; +use chalk_solve::infer::InferenceTable; +use chalk_solve::solve::truncate; +use chalk_solve::RustIrDatabase; -use std::fmt::{Debug, Display}; +use std::fmt::Debug; use std::marker::PhantomData; pub(crate) mod aggregate; mod resolvent; -#[derive(Debug)] -pub enum SubstitutionResult { - Definite(S), - Ambiguous(S), - Floundered, -} - -impl SubstitutionResult { - pub fn as_ref(&self) -> SubstitutionResult<&S> { - match self { - SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(subst), - SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(subst), - SubstitutionResult::Floundered => SubstitutionResult::Floundered, - } - } - pub fn map U>(self, f: F) -> SubstitutionResult { - match self { - SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(f(subst)), - SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(f(subst)), - SubstitutionResult::Floundered => SubstitutionResult::Floundered, - } - } -} - -impl Display for SubstitutionResult { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - match self { - SubstitutionResult::Definite(subst) => write!(fmt, "{}", subst), - SubstitutionResult::Ambiguous(subst) => write!(fmt, "Ambiguous({})", subst), - SubstitutionResult::Floundered => write!(fmt, "Floundered"), - } - } -} - #[derive(Clone, Debug, HasInterner)] pub(crate) struct SlgContext { phantom: PhantomData, @@ -66,11 +34,11 @@ pub(crate) struct SlgContextOps<'me, I: Interner> { } impl SlgContextOps<'_, I> { - pub(crate) fn new<'p>( - program: &'p dyn RustIrDatabase, + pub(crate) fn new( + program: &dyn RustIrDatabase, max_size: usize, expected_answers: Option, - ) -> SlgContextOps<'p, I> { + ) -> SlgContextOps<'_, I> { SlgContextOps { program, max_size, @@ -111,7 +79,7 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' map: &UniverseMap, value: &Canonical>>, ) -> Canonical>> { - use crate::infer::ucanonicalize::UniverseMapExt; + use chalk_solve::infer::ucanonicalize::UniverseMapExt; map.map_from_canonical(self.program.interner(), value) } @@ -120,7 +88,7 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' map: &UniverseMap, value: &Canonical>, ) -> Canonical> { - use crate::infer::ucanonicalize::UniverseMapExt; + use chalk_solve::infer::ucanonicalize::UniverseMapExt; map.map_from_canonical(self.program.interner(), value) } @@ -130,7 +98,12 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' goal: &DomainGoal, _infer: &mut TruncatingInferenceTable, ) -> Result>, Floundered> { - let clauses: Vec<_> = program_clauses_for_goal(self.program, environment, goal)?; + let clauses: Vec<_> = program_clauses_for_goal( + self.program, + environment, + goal, + &CanonicalVarKinds::empty(self.program.interner()), + )?; Ok(clauses) } @@ -190,7 +163,12 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' }, ) = InferenceTable::from_canonical(self.program.interner(), num_universes, answer); let infer_table = TruncatingInferenceTable::new(self.max_size, infer); - (infer_table, subst, constraints, delayed_subgoals) + ( + infer_table, + subst, + constraints.as_slice(self.interner()).to_vec(), + delayed_subgoals, + ) } fn identity_constrained_subst( @@ -207,7 +185,7 @@ impl<'me, I: Interner> context::ContextOps> for SlgContextOps<' self.program.interner(), &ConstrainedSubst { subst, - constraints: vec![], + constraints: Constraints::empty(self.program.interner()), }, ) .quantified @@ -271,7 +249,11 @@ impl context::UnificationOps> for TruncatingInfere } fn debug_ex_clause<'v>(&mut self, interner: &I, value: &'v ExClause) -> Box { - Box::new(self.infer.normalize_deep(interner, value)) + Box::new(DeepNormalizer::normalize_deep( + &mut self.infer, + interner, + value, + )) } fn fully_canonicalize_goal( @@ -302,7 +284,13 @@ impl context::UnificationOps> for TruncatingInfere constraints: Vec>>, ) -> Canonical> { self.infer - .canonicalize(interner, &ConstrainedSubst { subst, constraints }) + .canonicalize( + interner, + &ConstrainedSubst { + subst, + constraints: Constraints::from_iter(interner, constraints), + }, + ) .quantified } @@ -318,7 +306,7 @@ impl context::UnificationOps> for TruncatingInfere interner, &AnswerSubst { subst, - constraints, + constraints: Constraints::from_iter(interner, constraints), delayed_subgoals, }, ) @@ -359,7 +347,6 @@ fn into_ex_clause( .casted(interner) .map(Literal::Positive), ); - ex_clause.constraints.extend(result.constraints); } trait SubstitutionExt { diff --git a/vendor/chalk-solve-0.14.0/src/solve/slg/aggregate.rs b/vendor/chalk-engine/src/slg/aggregate.rs similarity index 86% rename from vendor/chalk-solve-0.14.0/src/solve/slg/aggregate.rs rename to vendor/chalk-engine/src/slg/aggregate.rs index 2018229e12..d2387538cc 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/slg/aggregate.rs +++ b/vendor/chalk-engine/src/slg/aggregate.rs @@ -1,14 +1,14 @@ -use crate::ext::*; -use crate::infer::InferenceTable; -use crate::solve::slg::SlgContextOps; -use crate::solve::slg::SubstitutionExt; -use crate::solve::{Guidance, Solution}; +use crate::context::{self, AnswerResult, ContextOps}; +use crate::slg::SlgContextOps; +use crate::slg::SubstitutionExt; +use crate::CompleteAnswer; use chalk_ir::cast::Cast; use chalk_ir::interner::Interner; use chalk_ir::*; +use chalk_solve::ext::*; +use chalk_solve::infer::InferenceTable; +use chalk_solve::solve::{Guidance, Solution}; -use chalk_engine::context::{self, AnswerResult, ContextOps}; -use chalk_engine::CompleteAnswer; use std::fmt::Debug; /// Methods for combining solutions to yield an aggregate solution. @@ -179,7 +179,7 @@ fn merge_into_guidance( }) .collect(); - let aggr_subst = Substitution::from(interner, aggr_generic_args); + let aggr_subst = Substitution::from_iter(interner, aggr_generic_args); infer.canonicalize(interner, &aggr_subst).quantified } @@ -307,7 +307,7 @@ impl AntiUnifier<'_, '_, I> { if index1 != index2 { self.new_ty_variable() } else { - TyData::Placeholder(index1.clone()).intern(interner) + TyData::Placeholder(*index1).intern(interner) } } @@ -388,7 +388,7 @@ impl AntiUnifier<'_, '_, I> { substitution2.len(interner) ); - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, substitution1 .iter(interner) @@ -465,7 +465,7 @@ impl AntiUnifier<'_, '_, I> { } (ConstValue::BoundVar(_), _) | (_, ConstValue::BoundVar(_)) => { - self.new_const_variable(ty.clone()) + self.new_const_variable(ty) } (ConstValue::Placeholder(_), ConstValue::Placeholder(_)) => { @@ -507,63 +507,71 @@ impl AntiUnifier<'_, '_, I> { } } -/// Test the equivalent of `Vec` vs `Vec` -#[test] -fn vec_i32_vs_vec_u32() { - use chalk_integration::interner::ChalkIr; - let mut infer: InferenceTable = InferenceTable::new(); - let mut anti_unifier = AntiUnifier { - infer: &mut infer, - universe: UniverseIndex::root(), - interner: &ChalkIr, - }; +#[cfg(test)] +mod test { + use crate::slg::aggregate::AntiUnifier; + use chalk_integration::{arg, ty, ty_name}; + use chalk_ir::UniverseIndex; + use chalk_solve::infer::InferenceTable; - let ty = anti_unifier.aggregate_tys( - &ty!(apply (item 0) (apply (item 1))), - &ty!(apply (item 0) (apply (item 2))), - ); - assert_eq!(ty!(apply (item 0) (infer 0)), ty); -} - -/// Test the equivalent of `Vec` vs `Vec` -#[test] -fn vec_i32_vs_vec_i32() { - use chalk_integration::interner::ChalkIr; - let interner = &ChalkIr; - let mut infer: InferenceTable = InferenceTable::new(); - let mut anti_unifier = AntiUnifier { - interner, - infer: &mut infer, - universe: UniverseIndex::root(), - }; - - let ty = anti_unifier.aggregate_tys( - &ty!(apply (item 0) (apply (item 1))), - &ty!(apply (item 0) (apply (item 1))), - ); - assert_eq!(ty!(apply (item 0) (apply (item 1))), ty); -} - -/// Test the equivalent of `Vec` vs `Vec` -#[test] -fn vec_x_vs_vec_y() { - use chalk_integration::interner::ChalkIr; - let interner = &ChalkIr; - let mut infer: InferenceTable = InferenceTable::new(); - let mut anti_unifier = AntiUnifier { - interner, - infer: &mut infer, - universe: UniverseIndex::root(), - }; - - // Note that the `var 0` and `var 1` in these types would be - // referring to canonicalized free variables, not variables in - // `infer`. - let ty = anti_unifier.aggregate_tys( - &ty!(apply (item 0) (infer 0)), - &ty!(apply (item 0) (infer 1)), - ); - - // But this `var 0` is from `infer. - assert_eq!(ty!(apply (item 0) (infer 0)), ty); + /// Test the equivalent of `Vec` vs `Vec` + #[test] + fn vec_i32_vs_vec_u32() { + use chalk_integration::interner::ChalkIr; + let mut infer: InferenceTable = InferenceTable::new(); + let mut anti_unifier = AntiUnifier { + infer: &mut infer, + universe: UniverseIndex::root(), + interner: &ChalkIr, + }; + + let ty = anti_unifier.aggregate_tys( + &ty!(apply (item 0) (apply (item 1))), + &ty!(apply (item 0) (apply (item 2))), + ); + assert_eq!(ty!(apply (item 0) (infer 0)), ty); + } + + /// Test the equivalent of `Vec` vs `Vec` + #[test] + fn vec_i32_vs_vec_i32() { + use chalk_integration::interner::ChalkIr; + let interner = &ChalkIr; + let mut infer: InferenceTable = InferenceTable::new(); + let mut anti_unifier = AntiUnifier { + interner, + infer: &mut infer, + universe: UniverseIndex::root(), + }; + + let ty = anti_unifier.aggregate_tys( + &ty!(apply (item 0) (apply (item 1))), + &ty!(apply (item 0) (apply (item 1))), + ); + assert_eq!(ty!(apply (item 0) (apply (item 1))), ty); + } + + /// Test the equivalent of `Vec` vs `Vec` + #[test] + fn vec_x_vs_vec_y() { + use chalk_integration::interner::ChalkIr; + let interner = &ChalkIr; + let mut infer: InferenceTable = InferenceTable::new(); + let mut anti_unifier = AntiUnifier { + interner, + infer: &mut infer, + universe: UniverseIndex::root(), + }; + + // Note that the `var 0` and `var 1` in these types would be + // referring to canonicalized free variables, not variables in + // `infer`. + let ty = anti_unifier.aggregate_tys( + &ty!(apply (item 0) (infer 0)), + &ty!(apply (item 0) (infer 1)), + ); + + // But this `var 0` is from `infer. + assert_eq!(ty!(apply (item 0) (infer 0)), ty); + } } diff --git a/vendor/chalk-solve-0.14.0/src/solve/slg/resolvent.rs b/vendor/chalk-engine/src/slg/resolvent.rs similarity index 97% rename from vendor/chalk-solve-0.14.0/src/solve/slg/resolvent.rs rename to vendor/chalk-engine/src/slg/resolvent.rs index b47ecac575..7cbdd697dd 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/slg/resolvent.rs +++ b/vendor/chalk-engine/src/slg/resolvent.rs @@ -1,15 +1,15 @@ -use crate::infer::InferenceTable; -use crate::solve::slg::{self, SlgContext, TruncatingInferenceTable}; +use crate::context; +use crate::normalize_deep::DeepNormalizer; +use crate::slg::{self, SlgContext, TruncatingInferenceTable}; +use crate::{ExClause, Literal, TimeStamp}; use chalk_ir::fold::shift::Shift; use chalk_ir::fold::Fold; use chalk_ir::interner::{HasInterner, Interner}; use chalk_ir::zip::{Zip, Zipper}; use chalk_ir::*; +use chalk_solve::infer::InferenceTable; use tracing::{debug, instrument}; -use chalk_engine::context; -use chalk_engine::{ExClause, Literal, TimeStamp}; - /////////////////////////////////////////////////////////////////////////// // SLG RESOLVENTS // @@ -76,6 +76,7 @@ impl context::ResolventOps> for TruncatingInferenc let ProgramClauseImplication { consequence, conditions, + constraints, priority: _, } = { let ProgramClauseData(implication) = clause.data(interner); @@ -83,8 +84,7 @@ impl context::ResolventOps> for TruncatingInferenc self.infer .instantiate_binders_existentially(interner, implication) }; - debug!("consequence = {:?}", consequence); - debug!("conditions = {:?}", conditions); + debug!(?consequence, ?conditions, ?constraints); // Unify the selected literal Li with C'. let unification_result = self @@ -105,6 +105,10 @@ impl context::ResolventOps> for TruncatingInferenc // Add the subgoals/region-constraints that unification gave us. slg::into_ex_clause(interner, unification_result, &mut ex_clause); + ex_clause + .constraints + .extend(constraints.as_slice(interner).to_owned()); + // Add the `conditions` from the program clause into the result too. ex_clause .subgoals @@ -205,10 +209,7 @@ impl context::ResolventOps> for TruncatingInferenc answer_table_goal: &Canonical>>, canonical_answer_subst: &Canonical>, ) -> Fallible<()> { - debug!( - "selected_goal={:?}", - self.infer.normalize_deep(interner, selected_goal) - ); + debug!(selected_goal = ?DeepNormalizer::normalize_deep(&mut self.infer, interner, selected_goal)); // C' is now `answer`. No variables in common with G. let AnswerSubst { @@ -235,7 +236,9 @@ impl context::ResolventOps> for TruncatingInferenc &answer_table_goal.value, selected_goal, )?; - ex_clause.constraints.extend(answer_constraints); + ex_clause + .constraints + .extend(answer_constraints.as_slice(interner).to_vec()); // at that point we should only have goals that stemmed // from non trivial self cycles ex_clause.delayed_subgoals.extend(delayed_subgoals); diff --git a/vendor/chalk-engine/src/solve.rs b/vendor/chalk-engine/src/solve.rs new file mode 100644 index 0000000000..6c3b0c321d --- /dev/null +++ b/vendor/chalk-engine/src/solve.rs @@ -0,0 +1,84 @@ +use crate::context::{AnswerResult, AnswerStream, ContextOps}; +use crate::forest::Forest; +use crate::slg::aggregate::AggregateOps; +use crate::slg::{SlgContext, SlgContextOps}; +use chalk_ir::interner::Interner; +use chalk_ir::{Canonical, ConstrainedSubst, Goal, InEnvironment, UCanonical}; +use chalk_solve::{RustIrDatabase, Solution, Solver, SubstitutionResult}; + +use std::fmt; + +pub struct SLGSolver { + pub(crate) forest: Forest>, + pub(crate) max_size: usize, + pub(crate) expected_answers: Option, +} + +impl SLGSolver { + pub fn new(max_size: usize, expected_answers: Option) -> Self { + Self { + forest: Forest::new(), + max_size, + expected_answers, + } + } +} + +impl fmt::Debug for SLGSolver { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(fmt, "SLGSolver") + } +} + +impl Solver for SLGSolver { + fn solve( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + ) -> Option> { + let ops = SlgContextOps::new(program, self.max_size, self.expected_answers); + ops.make_solution(goal, self.forest.iter_answers(&ops, goal), || true) + } + + fn solve_limited( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + should_continue: &dyn std::ops::Fn() -> bool, + ) -> Option> { + let ops = SlgContextOps::new(program, self.max_size, self.expected_answers); + ops.make_solution(goal, self.forest.iter_answers(&ops, goal), should_continue) + } + + fn solve_multiple( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + f: &mut dyn FnMut(SubstitutionResult>>, bool) -> bool, + ) -> bool { + let ops = SlgContextOps::new(program, self.max_size, self.expected_answers); + let mut answers = self.forest.iter_answers(&ops, goal); + loop { + let subst = match answers.next_answer(|| true) { + AnswerResult::Answer(answer) => { + if !answer.ambiguous { + SubstitutionResult::Definite(answer.subst) + } else if ops.is_trivial_constrained_substitution(&answer.subst) { + SubstitutionResult::Floundered + } else { + SubstitutionResult::Ambiguous(answer.subst) + } + } + AnswerResult::Floundered => SubstitutionResult::Floundered, + AnswerResult::NoMoreSolutions => { + return true; + } + AnswerResult::QuantumExceeded => continue, + }; + + if !f(subst, !answers.peek_answer(|| true).is_no_more_solutions()) { + return false; + } + } + } +} diff --git a/vendor/chalk-engine/src/stack.rs b/vendor/chalk-engine/src/stack.rs index f200c70c13..4b2ea059d7 100644 --- a/vendor/chalk-engine/src/stack.rs +++ b/vendor/chalk-engine/src/stack.rs @@ -1,7 +1,9 @@ use crate::context::Context; use crate::index_struct; use crate::strand::Strand; +use crate::tables::Tables; use crate::{Minimums, TableIndex, TimeStamp}; +use std::fmt; use std::ops::{Index, IndexMut, Range}; use chalk_ir::interner::Interner; @@ -13,6 +15,44 @@ pub(crate) struct Stack> { stack: Vec>, } +impl> Stack { + // This isn't actually used, but it can be helpful when debugging stack issues + #[allow(dead_code)] + pub(crate) fn debug_with<'a>(&'a self, tables: &'a Tables) -> StackDebug<'_, I, C> { + StackDebug { + stack: self, + tables, + } + } +} + +pub(crate) struct StackDebug<'a, I: Interner, C: Context> { + stack: &'a Stack, + tables: &'a Tables, +} + +impl> fmt::Debug for StackDebug<'_, I, C> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + writeln!(f, "---- Stack ----")?; + for entry in self.stack.stack.iter() { + writeln!(f, " --- StackEntry ---")?; + writeln!( + f, + " Table {:?} with goal {:?}", + entry.table, self.tables[entry.table].table_goal + )?; + writeln!(f, " Active strand: {:#?}", entry.active_strand)?; + writeln!( + f, + " Additional strands: {:#?}", + self.tables[entry.table].strands().collect::>() + )?; + } + write!(f, "---- End Stack ----")?; + Ok(()) + } +} + impl> Default for Stack { fn default() -> Self { Stack { stack: vec![] } diff --git a/vendor/chalk-engine/src/table.rs b/vendor/chalk-engine/src/table.rs index ff68b018d5..bb0de48bb9 100644 --- a/vendor/chalk-engine/src/table.rs +++ b/vendor/chalk-engine/src/table.rs @@ -10,6 +10,7 @@ use chalk_ir::interner::Interner; use chalk_ir::{AnswerSubst, Canonical, Goal, InEnvironment, UCanonical}; use tracing::{debug, info, instrument}; +#[derive(Debug)] pub(crate) struct Table { /// The goal this table is trying to solve (also the key to look /// it up). @@ -85,17 +86,6 @@ impl Table { mem::replace(&mut self.strands, VecDeque::new()) } - pub(crate) fn drain_strands( - &mut self, - test: impl Fn(&CanonicalStrand) -> bool, - ) -> VecDeque> { - let old = mem::replace(&mut self.strands, VecDeque::new()); - let (test_in, test_out): (VecDeque>, VecDeque>) = - old.into_iter().partition(test); - let _ = mem::replace(&mut self.strands, test_out); - test_in - } - /// Remove the next strand from the queue that meets the given criteria pub(crate) fn dequeue_next_strand_that( &mut self, @@ -157,8 +147,8 @@ impl Table { }; info!( - "new answer to table with goal {:?}: answer={:?}", - self.table_goal, answer, + goal = ?self.table_goal, ?answer, + "new answer to table", ); if !added { return None; diff --git a/vendor/chalk-engine/src/tables.rs b/vendor/chalk-engine/src/tables.rs index e1e020f057..76508eaa8d 100644 --- a/vendor/chalk-engine/src/tables.rs +++ b/vendor/chalk-engine/src/tables.rs @@ -7,6 +7,7 @@ use chalk_ir::interner::Interner; use chalk_ir::{Goal, InEnvironment, UCanonical}; /// See `Forest`. +#[derive(Debug)] pub(crate) struct Tables { /// Maps from a canonical goal to the index of its table. table_indices: FxHashMap>>, TableIndex>, diff --git a/vendor/chalk-ir-0.14.0/.cargo-checksum.json b/vendor/chalk-ir-0.14.0/.cargo-checksum.json deleted file mode 100644 index c0008e7e36..0000000000 --- a/vendor/chalk-ir-0.14.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"349a9d115dc2b195d3b67519c7074a5298cb735f667e42d8dd51b05ebf4fc7e1","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"23f99f9cb896c3c54c07a6f1bd242f40c3ba4102441c65344f58209bd8b8a4fe","src/could_match.rs":"329f99b596d7548e2502956905d2788d289e2c695d5573969d37bf2d8d5938f5","src/debug.rs":"579f88d223fd3382264dd7519857582269dd72334f6842b9cecf647543bac75b","src/fold.rs":"2060ea5b4647aa80a9ca171e8c446cb1f77b30f2d299a62e6c9b62a714f81fdb","src/fold/binder_impls.rs":"000af61a46ffc0ed9d01fbd6764402157969af6b4a501ad1027593ef15ca20ec","src/fold/boring_impls.rs":"38c7167a8b6e351a47b060f89017794ef6406d5462544bd93c0d3d1241fe2df1","src/fold/shift.rs":"5ae3b2efd6275411bba822459e0a9377594c9116c2bdc3b86fde90efa6dab020","src/fold/subst.rs":"59db128e9bc82cf0f7dd49c9057bde85d31e2c51832736a359ca726639a69d15","src/interner.rs":"25735e216d5ba9efeee1c7d829bcf72d7599e976f6a02487dc343cec4cda2e1b","src/lib.rs":"8c305524ed505ea87035b23a1c1fe3c480933c0b4710339e64e0a8ebaab2e426","src/visit.rs":"e78a78472c1ef7fbd33a158b146471b2177d184e1de0839f1e789f5e4b309cf7","src/visit/binder_impls.rs":"8e02aadf0551a66ce0748c6c890d8a85543c0d72d4d22990ed2eccad29813afb","src/visit/boring_impls.rs":"5423adb7cac7dde0a614405575c4c612efebc1802d639871a87a31e6e1151cad","src/visit/visitors.rs":"abda40eb51d97a68af62148e906dd2957b34617059d8b8c0fbe01eac6653196c","src/zip.rs":"8f49ef5dda9d98c9f74977502197d9bb7927b30754afe8abaf790163170e1f16"},"package":"fd3fdc1e9f68498ffe80f4a23b0b95f1ca6fb21d5a4c9b0c085fab3ca712bdbe"} \ No newline at end of file diff --git a/vendor/chalk-ir-0.25.0/.cargo-checksum.json b/vendor/chalk-ir-0.25.0/.cargo-checksum.json new file mode 100644 index 0000000000..131ca2f0c0 --- /dev/null +++ b/vendor/chalk-ir-0.25.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"40254e614cf85d16362f59878865e03647a7645cfcc2b24cd4879163ad91c362","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"6e8bc7ebd3d94a27c561499a15de2cc5d9501e6bf387b62e76772d7cb7ecd0a2","src/could_match.rs":"46507c372868dcd51c4a04dcd4bcc4e6e61f0fa537d980b3dc615be52c98171b","src/debug.rs":"e130908297f47a08ec7ed0d36131e5bd8534434fb9d30881da4fcbd714d2d95a","src/fold.rs":"2d1f8fd0f8603dad54428ba9d93f281d478c380dfca9d755e96a362d3be9d470","src/fold/binder_impls.rs":"0cb4f2b40b34e5f80e5a5946289959431ac5c22f6ec87d30e9b2f7d4122d0fd0","src/fold/boring_impls.rs":"f83bddd6061e0d035fb37a250013c2ce55fb624d0a3ee63d5e1840bb8ebd8227","src/fold/shift.rs":"134caa51a84399e7bd31471e3a31f7ca05b91c99cb1f06132f1d42151328e5d3","src/fold/subst.rs":"4db018d2b5d447420ae4b9269de36f3ce816de201b4eeaf30d54ae5c3b5db7cd","src/interner.rs":"993b347617e2a6dc8f34d966e4f140a082dfadc946d52e1e4064311db07f4b65","src/lib.rs":"808cf7a58fc04b89fd10eac36125dd9356a00bc33cc6570d81d63796a1572497","src/visit.rs":"22e5230a397b3d5ec1c2002cdd03dc6c8adb3d5497e83534d93b9ff72875896c","src/visit/binder_impls.rs":"4e544fc24158c8a1c84237ed21b83673225f87876ee78eeda83b41bc2b65f408","src/visit/boring_impls.rs":"f9904bf7200af8dc55e01ff24c238406596b7e7353ad7361d074ec5af4a4d013","src/visit/visitors.rs":"5f429cc2f9a94f918258c8df776a0fec15cffaff4dd7b20019a2ad6c091a1ddd","src/zip.rs":"f2b25e7221e32b5176adc95220b338d079555fae2949e12bf197e28dd8b24c2f"},"package":"118c68eccdda5604af50bbef84c94550f3854f76989cb03c36ffd36cc2ffe958"} \ No newline at end of file diff --git a/vendor/chalk-ir-0.14.0/Cargo.toml b/vendor/chalk-ir-0.25.0/Cargo.toml similarity index 95% rename from vendor/chalk-ir-0.14.0/Cargo.toml rename to vendor/chalk-ir-0.25.0/Cargo.toml index 451b3b83ad..940c51750e 100644 --- a/vendor/chalk-ir-0.14.0/Cargo.toml +++ b/vendor/chalk-ir-0.25.0/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-ir" -version = "0.14.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Chalk's internal representation of types, goals, and clauses" readme = "README.md" @@ -21,7 +21,7 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.14.0" +version = "=0.25.0" [dependencies.lazy_static] version = "1.4.0" diff --git a/vendor/chalk-ir-0.14.0/README.md b/vendor/chalk-ir-0.25.0/README.md similarity index 100% rename from vendor/chalk-ir-0.14.0/README.md rename to vendor/chalk-ir-0.25.0/README.md diff --git a/vendor/chalk-ir-0.14.0/src/cast.rs b/vendor/chalk-ir-0.25.0/src/cast.rs similarity index 94% rename from vendor/chalk-ir-0.14.0/src/cast.rs rename to vendor/chalk-ir-0.25.0/src/cast.rs index 310ef3b467..c363d3800b 100644 --- a/vendor/chalk-ir-0.14.0/src/cast.rs +++ b/vendor/chalk-ir-0.25.0/src/cast.rs @@ -1,3 +1,5 @@ +//! Upcasts, to avoid writing out wrapper types. + use crate::*; use std::marker::PhantomData; @@ -38,6 +40,7 @@ use std::marker::PhantomData; /// This split setup allows us to write `foo.cast::()` to mean /// "cast to T". pub trait Cast: Sized { + /// Cast a value to type `U` using `CastTo`. fn cast(self, interner: &U::Interner) -> U where Self: CastTo, @@ -54,6 +57,7 @@ impl Cast for T {} /// functions that take (e.g.) an `impl CastTo>` or something /// like that. pub trait CastTo: Sized { + /// Cast a value to type `T`. fn cast_to(self, interner: &T::Interner) -> T; } @@ -83,8 +87,11 @@ reflexive_impl!(for(I: Interner) Goal); reflexive_impl!(for(I: Interner) WhereClause); reflexive_impl!(for(I: Interner) ProgramClause); reflexive_impl!(for(I: Interner) QuantifiedWhereClause); +reflexive_impl!(for(I: Interner) VariableKind); reflexive_impl!(for(I: Interner) VariableKinds); +reflexive_impl!(for(I: Interner) CanonicalVarKind); reflexive_impl!(for(I: Interner) CanonicalVarKinds); +reflexive_impl!(for(I: Interner) Constraint); impl CastTo> for TraitRef { fn cast_to(self, _interner: &I) -> WhereClause { @@ -201,7 +208,8 @@ where fn cast_to(self, interner: &I) -> ProgramClause { let implication = ProgramClauseImplication { consequence: self.cast(interner), - conditions: Goals::new(interner), + conditions: Goals::empty(interner), + constraints: Constraints::empty(interner), priority: ClausePriority::High, }; @@ -218,7 +226,8 @@ where fn cast_to(self, interner: &I) -> ProgramClause { ProgramClauseData(self.map(|bound| ProgramClauseImplication { consequence: bound.cast(interner), - conditions: Goals::new(interner), + conditions: Goals::empty(interner), + constraints: Constraints::empty(interner), priority: ClausePriority::High, })) .intern(interner) @@ -333,6 +342,7 @@ where } } +/// An iterator that casts each element to some other type. pub struct Casted<'i, IT, U: HasInterner> { interner: &'i U::Interner, iterator: IT, @@ -358,6 +368,7 @@ where /// An iterator adapter that casts each element we are iterating over /// to some other type. pub trait Caster: Iterator + Sized { + /// Cast each element in this iterator. fn casted(self, interner: &U::Interner) -> Casted<'_, Self, U> where Self::Item: CastTo, diff --git a/vendor/chalk-ir-0.14.0/src/could_match.rs b/vendor/chalk-ir-0.25.0/src/could_match.rs similarity index 95% rename from vendor/chalk-ir-0.14.0/src/could_match.rs rename to vendor/chalk-ir-0.25.0/src/could_match.rs index c070d32a44..a8446c621d 100644 --- a/vendor/chalk-ir-0.14.0/src/could_match.rs +++ b/vendor/chalk-ir-0.25.0/src/could_match.rs @@ -1,9 +1,12 @@ +//! Fast matching check for zippable values. + use crate::interner::HasInterner; use crate::zip::{Zip, Zipper}; use crate::*; /// A fast check to see whether two things could ever possibly match. pub trait CouldMatch { + /// Checks whether `self` and `other` could possibly match. fn could_match(&self, interner: &T::Interner, other: &T) -> bool; } diff --git a/vendor/chalk-ir-0.14.0/src/debug.rs b/vendor/chalk-ir-0.25.0/src/debug.rs similarity index 91% rename from vendor/chalk-ir-0.14.0/src/debug.rs rename to vendor/chalk-ir-0.25.0/src/debug.rs index 485471f9f9..7c2f21853c 100644 --- a/vendor/chalk-ir-0.14.0/src/debug.rs +++ b/vendor/chalk-ir-0.25.0/src/debug.rs @@ -1,3 +1,5 @@ +//! Debug impls for types. + use std::fmt::{Debug, Display, Error, Formatter}; use super::*; @@ -94,6 +96,12 @@ impl Debug for ProgramClauses { } } +impl Debug for Constraints { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { + I::debug_constraints(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned)) + } +} + impl Debug for ApplicationTy { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { I::debug_application_ty(self, fmt).unwrap_or_else(|| write!(fmt, "ApplicationTy(?)")) @@ -224,14 +232,21 @@ impl Debug for InferenceVar { } } -impl Debug for Fn { +impl Debug for FnPointer { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { // FIXME -- we should introduce some names or something here - let Fn { + let FnPointer { num_binders, substitution, + abi, + safety, + variadic: _, } = self; - write!(fmt, "for<{}> {:?}", num_binders, substitution) + write!( + fmt, + "for<{}> {:?} {:?} {:?}", + num_binders, safety, abi, substitution + ) } } @@ -251,6 +266,7 @@ impl VariableKinds { VariableKindsDebug(self) } + /// Helper method for debugging variable kinds. pub fn inner_debug<'a>(&'a self, interner: &'a I) -> VariableKindsInnerDebug<'a, I> { VariableKindsInnerDebug { variable_kinds: self, @@ -268,6 +284,7 @@ impl<'a, I: Interner> Debug for VariableKindsDebug<'a, I> { } } +/// Helper struct for showing debug output for `VariableKinds`. pub struct VariableKindsInnerDebug<'a, I: Interner> { variable_kinds: &'a VariableKinds, interner: &'a I, @@ -322,11 +339,12 @@ impl Debug for GoalData { GoalData::Not(ref g) => write!(fmt, "not {{ {:?} }}", g), GoalData::EqGoal(ref wc) => write!(fmt, "{:?}", wc), GoalData::DomainGoal(ref wc) => write!(fmt, "{:?}", wc), - GoalData::CannotProve(()) => write!(fmt, r"¯\_(ツ)_/¯"), + GoalData::CannotProve => write!(fmt, r"¯\_(ツ)_/¯"), } } } +/// Helper struct for showing debug output for `Goals`. pub struct GoalsDebug<'a, I: Interner> { goals: &'a Goals, interner: &'a I, @@ -347,6 +365,7 @@ impl<'a, I: Interner> Debug for GoalsDebug<'a, I> { } impl Goals { + /// Show debug output for `Goals`. pub fn debug<'a>(&'a self, interner: &'a I) -> GoalsDebug<'a, I> { GoalsDebug { goals: self, @@ -355,6 +374,7 @@ impl Goals { } } +/// Helper struct for showing debug output for `GenericArgData`. pub struct GenericArgDataInnerDebug<'a, I: Interner>(&'a GenericArgData); impl<'a, I: Interner> Debug for GenericArgDataInnerDebug<'a, I> { @@ -368,11 +388,13 @@ impl<'a, I: Interner> Debug for GenericArgDataInnerDebug<'a, I> { } impl GenericArgData { + /// Helper method for debugging `GenericArgData`. pub fn inner_debug(&self) -> GenericArgDataInnerDebug<'_, I> { GenericArgDataInnerDebug(self) } } +/// Helper struct for showing debug output for program clause implications. pub struct ProgramClauseImplicationDebug<'a, I: Interner> { pci: &'a ProgramClauseImplication, interner: &'a I, @@ -399,6 +421,7 @@ impl<'a, I: Interner> Debug for ProgramClauseImplicationDebug<'a, I> { } impl ProgramClauseImplication { + /// Show debug output for the program clause implication. pub fn debug<'a>(&'a self, interner: &'a I) -> ProgramClauseImplicationDebug<'a, I> { ProgramClauseImplicationDebug { pci: self, @@ -407,6 +430,7 @@ impl ProgramClauseImplication { } } +/// Helper struct for showing debug output for application types. pub struct ApplicationTyDebug<'a, I: Interner> { application_ty: &'a ApplicationTy, interner: &'a I, @@ -424,6 +448,7 @@ impl<'a, I: Interner> Debug for ApplicationTyDebug<'a, I> { } impl ApplicationTy { + /// Show debug output for the application type. pub fn debug<'a>(&'a self, interner: &'a I) -> ApplicationTyDebug<'a, I> { ApplicationTyDebug { application_ty: self, @@ -432,6 +457,7 @@ impl ApplicationTy { } } +/// Helper struct for showing debug output for substitutions. pub struct SubstitutionDebug<'a, I: Interner> { substitution: &'a Substitution, interner: &'a I, @@ -464,6 +490,7 @@ impl<'a, I: Interner> Debug for SubstitutionDebug<'a, I> { } impl Substitution { + /// Show debug output for the substitution. pub fn debug<'a>(&'a self, interner: &'a I) -> SubstitutionDebug<'a, I> { SubstitutionDebug { substitution: self, @@ -480,7 +507,7 @@ impl Debug for PlaceholderIndex { } impl TraitRef { - /// Returns a "Debuggable" type that prints like `P0 as Trait` + /// Returns a "Debuggable" type that prints like `P0 as Trait`. pub fn with_as(&self) -> impl std::fmt::Debug + '_ { SeparatorTraitRef { trait_ref: self, @@ -488,7 +515,7 @@ impl TraitRef { } } - /// Returns a "Debuggable" type that prints like `P0: Trait` + /// Returns a "Debuggable" type that prints like `P0: Trait`. pub fn with_colon(&self) -> impl std::fmt::Debug + '_ { SeparatorTraitRef { trait_ref: self, @@ -503,11 +530,16 @@ impl Debug for TraitRef { } } +/// Trait ref with associated separator used for debug output. pub struct SeparatorTraitRef<'me, I: Interner> { + /// The `TraitRef` itself. pub trait_ref: &'me TraitRef, + + /// The separator used for displaying the `TraitRef`. pub separator: &'me str, } +/// Helper struct for showing debug output for the `SeperatorTraitRef`. pub struct SeparatorTraitRefDebug<'a, 'me, I: Interner> { separator_trait_ref: &'a SeparatorTraitRef<'me, I>, interner: &'a I, @@ -522,7 +554,7 @@ impl<'a, 'me, I: Interner> Debug for SeparatorTraitRefDebug<'a, 'me, I> { let parameters = separator_trait_ref .trait_ref .substitution - .parameters(interner); + .as_slice(interner); write!( fmt, "{:?}{}{:?}{:?}", @@ -535,6 +567,7 @@ impl<'a, 'me, I: Interner> Debug for SeparatorTraitRefDebug<'a, 'me, I> { } impl<'me, I: Interner> SeparatorTraitRef<'me, I> { + /// Show debug output for the `SeperatorTraitRef`. pub fn debug<'a>(&'a self, interner: &'a I) -> SeparatorTraitRefDebug<'a, 'me, I> { SeparatorTraitRefDebug { separator_trait_ref: self, @@ -549,6 +582,13 @@ impl Debug for LifetimeOutlives { } } +impl Debug for TypeOutlives { + fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { + write!(fmt, "{:?}: {:?}", self.ty, self.lifetime) + } +} + +/// Helper struct for showing debug output for projection types. pub struct ProjectionTyDebug<'a, I: Interner> { projection_ty: &'a ProjectionTy, interner: &'a I, @@ -570,6 +610,7 @@ impl<'a, I: Interner> Debug for ProjectionTyDebug<'a, I> { } impl ProjectionTy { + /// Show debug output for the projection type. pub fn debug<'a>(&'a self, interner: &'a I) -> ProjectionTyDebug<'a, I> { ProjectionTyDebug { projection_ty: self, @@ -578,6 +619,7 @@ impl ProjectionTy { } } +/// Helper struct for showing debug output for opaque types. pub struct OpaqueTyDebug<'a, I: Interner> { opaque_ty: &'a OpaqueTy, interner: &'a I, @@ -599,6 +641,7 @@ impl<'a, I: Interner> Debug for OpaqueTyDebug<'a, I> { } impl OpaqueTy { + /// Show debug output for the opaque type. pub fn debug<'a>(&'a self, interner: &'a I) -> OpaqueTyDebug<'a, I> { OpaqueTyDebug { opaque_ty: self, @@ -607,11 +650,12 @@ impl OpaqueTy { } } +/// Wraps debug output in angle brackets (`<>`). pub struct Angle<'a, T>(pub &'a [T]); impl<'a, T: Debug> Debug for Angle<'a, T> { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { - if self.0.len() > 0 { + if !self.0.is_empty() { write!(fmt, "<")?; for (index, elem) in self.0.iter().enumerate() { if index > 0 { @@ -644,6 +688,7 @@ impl Debug for WhereClause { WhereClause::Implemented(tr) => write!(fmt, "Implemented({:?})", tr.with_colon()), WhereClause::AliasEq(a) => write!(fmt, "{:?}", a), WhereClause::LifetimeOutlives(l_o) => write!(fmt, "{:?}", l_o), + WhereClause::TypeOutlives(t_o) => write!(fmt, "{:?}", t_o), } } } @@ -679,9 +724,9 @@ impl Debug for DomainGoal { DomainGoal::LocalImplAllowed(tr) => { write!(fmt, "LocalImplAllowed({:?})", tr.with_colon(),) } - DomainGoal::Compatible(_) => write!(fmt, "Compatible"), + DomainGoal::Compatible => write!(fmt, "Compatible"), DomainGoal::DownstreamType(n) => write!(fmt, "DownstreamType({:?})", n), - DomainGoal::Reveal(_) => write!(fmt, "Reveal"), + DomainGoal::Reveal => write!(fmt, "Reveal"), DomainGoal::ObjectSafe(n) => write!(fmt, "ObjectSafe({:?})", n), } } @@ -724,6 +769,7 @@ impl Debug for CanonicalVarKinds { } impl Canonical { + /// Display the canonicalized item. pub fn display<'a>(&'a self, interner: &'a T::Interner) -> CanonicalDisplay<'a, T> { CanonicalDisplay { canonical: self, @@ -732,6 +778,7 @@ impl Canonical { } } +/// Helper struct for displaying canonicalized items. pub struct CanonicalDisplay<'a, T: HasInterner> { canonical: &'a Canonical, interner: &'a T::Interner, @@ -805,7 +852,8 @@ impl Debug for WithKind { impl Debug for Constraint { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { match self { - Constraint::Outlives(a, b) => write!(fmt, "{:?}: {:?}", a, b), + Constraint::LifetimeOutlives(a, b) => write!(fmt, "{:?}: {:?}", a, b), + Constraint::TypeOutlives(ty, lifetime) => write!(fmt, "{:?}: {:?}", ty, lifetime), } } } @@ -826,7 +874,7 @@ impl Substitution { /// Displays the substitution in the form `< P0, .. Pn >`, or (if /// the substitution is empty) as an empty string. pub fn with_angle(&self, interner: &I) -> Angle<'_, GenericArg> { - Angle(self.parameters(interner)) + Angle(self.as_slice(interner)) } } diff --git a/vendor/chalk-ir-0.14.0/src/fold.rs b/vendor/chalk-ir-0.25.0/src/fold.rs similarity index 98% rename from vendor/chalk-ir-0.14.0/src/fold.rs rename to vendor/chalk-ir-0.25.0/src/fold.rs index 5cec1558fa..40f5f276da 100644 --- a/vendor/chalk-ir-0.14.0/src/fold.rs +++ b/vendor/chalk-ir-0.25.0/src/fold.rs @@ -172,6 +172,7 @@ where } } + /// As `fold_free_var_ty`, but for constants. fn fold_free_var_const( &mut self, ty: &Ty, @@ -233,6 +234,7 @@ where } } + /// As with `fold_free_placeholder_ty`, but for constants. #[allow(unused_variables)] fn fold_free_placeholder_const( &mut self, @@ -278,7 +280,7 @@ where } } - /// As with `fold_free_inference_ty`, but for lifetimes. + /// As with `fold_inference_ty`, but for lifetimes. #[allow(unused_variables)] fn fold_inference_lifetime( &mut self, @@ -292,6 +294,7 @@ where } } + /// As with `fold_inference_ty`, but for constants. #[allow(unused_variables)] fn fold_inference_const( &mut self, @@ -309,8 +312,10 @@ where } } + /// Gets the interner that is being folded from. fn interner(&self) -> &'i I; + /// Gets the interner that is being folded to. fn target_interner(&self) -> &'i TI; } @@ -356,6 +361,7 @@ pub trait Fold = I>: Debug { /// `SuperFold` trait captures the recursive behavior that folds all /// the contents of the type. pub trait SuperFold = I>: Fold { + /// Recursively folds the value. fn super_fold_with<'i>( &self, folder: &mut dyn Folder<'i, I, TI>, diff --git a/vendor/chalk-ir-0.14.0/src/fold/binder_impls.rs b/vendor/chalk-ir-0.25.0/src/fold/binder_impls.rs similarity index 86% rename from vendor/chalk-ir-0.14.0/src/fold/binder_impls.rs rename to vendor/chalk-ir-0.25.0/src/fold/binder_impls.rs index b514d8f189..1f751f16ca 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/binder_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/binder_impls.rs @@ -6,8 +6,8 @@ use crate::interner::TargetInterner; use crate::*; -impl> Fold for Fn { - type Result = Fn; +impl> Fold for FnPointer { + type Result = FnPointer; fn fold_with<'i>( &self, folder: &mut dyn Folder<'i, I, TI>, @@ -17,13 +17,19 @@ impl> Fold for Fn { I: 'i, TI: 'i, { - let Fn { + let FnPointer { num_binders, substitution, + abi, + safety, + variadic, } = self; - Ok(Fn { + Ok(FnPointer { num_binders: *num_binders, substitution: substitution.fold_with(folder, outer_binder.shifted_in())?, + abi: TI::transfer_abi(*abi), + safety: *safety, + variadic: *variadic, }) } } @@ -81,9 +87,6 @@ where let binders = CanonicalVarKinds { interned: TI::transfer_canonical_var_kinds(self_binders.interned().clone()), }; - Ok(Canonical { - binders: binders, - value: value, - }) + Ok(Canonical { binders, value }) } } diff --git a/vendor/chalk-ir-0.14.0/src/fold/boring_impls.rs b/vendor/chalk-ir-0.25.0/src/fold/boring_impls.rs similarity index 93% rename from vendor/chalk-ir-0.14.0/src/fold/boring_impls.rs rename to vendor/chalk-ir-0.25.0/src/fold/boring_impls.rs index 7d14b02349..9922315a39 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/boring_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/boring_impls.rs @@ -213,6 +213,27 @@ impl> Fold for QuantifiedWhereClauses< } } +impl> Fold for Constraints { + type Result = Constraints; + fn fold_with<'i>( + &self, + folder: &mut dyn Folder<'i, I, TI>, + outer_binder: DebruijnIndex, + ) -> Fallible + where + I: 'i, + TI: 'i, + { + let interner = folder.interner(); + let target_interner = folder.target_interner(); + let folded = self + .iter(interner) + .map(|p| p.fold_with(folder, outer_binder)); + Ok(Constraints::from_fallible(target_interner, folded)?) + } +} + +#[doc(hidden)] #[macro_export] macro_rules! copy_fold { ($t:ty) => { @@ -246,7 +267,9 @@ copy_fold!(FloatTy); copy_fold!(Scalar); copy_fold!(ClausePriority); copy_fold!(Mutability); +copy_fold!(Safety); +#[doc(hidden)] #[macro_export] macro_rules! id_fold { ($t:ident) => { diff --git a/vendor/chalk-ir-0.14.0/src/fold/shift.rs b/vendor/chalk-ir-0.25.0/src/fold/shift.rs similarity index 99% rename from vendor/chalk-ir-0.14.0/src/fold/shift.rs rename to vendor/chalk-ir-0.25.0/src/fold/shift.rs index 1c34f59fe4..2a144ae2d2 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/shift.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/shift.rs @@ -1,3 +1,5 @@ +//! Shifting of debruijn indices + use super::Fold; use crate::*; diff --git a/vendor/chalk-ir-0.14.0/src/fold/subst.rs b/vendor/chalk-ir-0.25.0/src/fold/subst.rs similarity index 97% rename from vendor/chalk-ir-0.14.0/src/fold/subst.rs rename to vendor/chalk-ir-0.25.0/src/fold/subst.rs index ffee986bec..6c6cb2c7a1 100644 --- a/vendor/chalk-ir-0.14.0/src/fold/subst.rs +++ b/vendor/chalk-ir-0.25.0/src/fold/subst.rs @@ -1,6 +1,7 @@ use super::*; use crate::fold::shift::Shift; +/// Substitution used during folding pub struct Subst<'s, 'i, I: Interner> { /// Values to substitute. A reference to a free variable with /// index `i` will be mapped to `parameters[i]` -- if `i > @@ -10,6 +11,7 @@ pub struct Subst<'s, 'i, I: Interner> { } impl Subst<'_, '_, I> { + /// Applies the substitution by folding pub fn apply>( interner: &I, parameters: &[GenericArg], diff --git a/vendor/chalk-ir-0.14.0/src/interner.rs b/vendor/chalk-ir-0.25.0/src/interner.rs similarity index 72% rename from vendor/chalk-ir-0.14.0/src/interner.rs rename to vendor/chalk-ir-0.25.0/src/interner.rs index eae60aef2c..c996059d97 100644 --- a/vendor/chalk-ir-0.14.0/src/interner.rs +++ b/vendor/chalk-ir-0.25.0/src/interner.rs @@ -1,3 +1,4 @@ +//! Encapsulates the concrete representation of core types such as types and goals. use crate::AdtId; use crate::AliasTy; use crate::ApplicationTy; @@ -5,12 +6,15 @@ use crate::AssocTypeId; use crate::CanonicalVarKind; use crate::CanonicalVarKinds; use crate::ClosureId; +use crate::Constraint; +use crate::Constraints; use crate::FnDefId; use crate::GenericArg; use crate::GenericArgData; use crate::Goal; use crate::GoalData; use crate::Goals; +use crate::InEnvironment; use crate::Lifetime; use crate::LifetimeData; use crate::OpaqueTy; @@ -163,33 +167,34 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// to its underlying data via `canonical_var_kinds_data`. type InternedCanonicalVarKinds: Debug + Clone + Eq + Hash; + /// "Interned" representation of a list of region constraints. + /// In normal user code, `Self::InternedConstraints` is not referenced. + /// Instead, we refer to `Constraints`, which wraps this type. + /// + /// An `InternedConstraints` is created by `intern_constraints` + /// and can be converted back to its underlying data via `constraints_data`. + type InternedConstraints: Debug + Clone + Eq + Hash; + /// The core "id" type used for trait-ids and the like. type DefId: Debug + Copy + Eq + Ord + Hash; /// The ID type for ADTs type InternedAdtId: Debug + Copy + Eq + Ord + Hash; + /// Representation of identifiers. type Identifier: Debug + Clone + Eq + Hash; + /// Representation of function ABI (e.g. calling convention). type FnAbi: Debug + Copy + Eq + Hash; - /// Prints the debug representation of a type-kind-id. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a type-kind-id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_adt_id(adt_id: AdtId, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a type-kind-id. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// + /// Prints the debug representation of a type-kind-id. /// Returns `None` to fallback to the default debug output (e.g., /// if no info about current program is available from TLS). #[allow(unused_variables)] @@ -200,10 +205,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a type-kind-id. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). + /// Prints the debug representation of a type-kind-id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_assoc_type_id( type_id: AssocTypeId, @@ -212,13 +215,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an opaque type. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific type-family (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an opaque type. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_opaque_ty_id( opaque_ty_id: OpaqueTyId, @@ -227,6 +225,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a function-def-id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_fn_def_id( fn_def_id: FnDefId, @@ -235,6 +235,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a closure id. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_closure_id( fn_def_id: ClosureId, @@ -243,25 +245,15 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an alias. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an alias. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_alias(alias: &AliasTy, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a ProjectionTy. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProjectionTy. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_projection_ty( projection_ty: &ProjectionTy, @@ -270,13 +262,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an OpaqueTy. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an OpaqueTy. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_opaque_ty( opaque_ty: &OpaqueTy, @@ -285,25 +272,15 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a type. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a type. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_ty(ty: &Ty, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a lifetime. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a lifetime. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_lifetime( lifetime: &Lifetime, @@ -312,25 +289,15 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a const. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a const. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_const(constant: &Const, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of an parameter. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an parameter. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_generic_arg( generic_arg: &GenericArg, @@ -339,13 +306,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a parameter kinds list. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a parameter kinds list. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_variable_kinds( variable_kinds: &VariableKinds, @@ -355,12 +317,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { } /// Prints the debug representation of a parameter kinds list, with angle brackets. - /// To get good results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_variable_kinds_with_angles( variable_kinds: &VariableKinds, @@ -370,12 +327,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { } /// Prints the debug representation of an parameter kinds list with universe index. - /// To get good results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_canonical_var_kinds( canonical_var_kinds: &CanonicalVarKinds, @@ -384,37 +336,22 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an goal. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an goal. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_goal(goal: &Goal, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a list of goals. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a list of goals. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_goals(goals: &Goals, fmt: &mut fmt::Formatter<'_>) -> Option { None } - /// Prints the debug representation of a ProgramClauseImplication. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProgramClauseImplication. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_program_clause_implication( pci: &ProgramClauseImplication, @@ -423,13 +360,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a ProgramClause. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProgramClause. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_program_clause( clause: &ProgramClause, @@ -438,13 +370,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a ProgramClauses. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a ProgramClauses. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_program_clauses( clauses: &ProgramClauses, @@ -453,13 +380,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of an ApplicationTy. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of an ApplicationTy. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_application_ty( application_ty: &ApplicationTy, @@ -468,13 +390,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a Substitution. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a Substitution. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_substitution( substitution: &Substitution, @@ -483,13 +400,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a SeparatorTraitRef. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a SeparatorTraitRef. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_separator_trait_ref( separator_trait_ref: &SeparatorTraitRef<'_, Self>, @@ -498,13 +410,8 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } - /// Prints the debug representation of a QuantifiedWhereClauses. To get good - /// results, this requires inspecting TLS, and is difficult to - /// code without reference to a specific interner (and hence - /// fully known types). - /// - /// Returns `None` to fallback to the default debug output (e.g., - /// if no info about current program is available from TLS). + /// Prints the debug representation of a QuantifiedWhereClauses. + /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] fn debug_quantified_where_clauses( clauses: &QuantifiedWhereClauses, @@ -513,6 +420,16 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a Constraints. + /// Returns `None` to fallback to the default debug output. + #[allow(unused_variables)] + fn debug_constraints( + clauses: &Constraints, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + /// Create an "interned" type from `ty`. This is not normally /// invoked directly; instead, you invoke `TyData::intern` (which /// will ultimately call this method). @@ -539,6 +456,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Lookup the `ConstData` that was interned to create a `InternedConst`. fn const_data<'a>(&self, constant: &'a Self::InternedConst) -> &'a ConstData; + /// Deterermine whether two concrete const values are equal. fn const_eq( &self, ty: &Self::InternedType, @@ -608,7 +526,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create an "interned" program clauses from `data`. This is not /// normally invoked directly; instead, you invoke - /// `ProgramClauses::from` (which will ultimately call this + /// `ProgramClauses::from_iter` (which will ultimately call this /// method). fn intern_program_clauses( &self, @@ -623,7 +541,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create an "interned" quantified where clauses from `data`. This is not /// normally invoked directly; instead, you invoke - /// `QuantifiedWhereClauses::from` (which will ultimately call this + /// `QuantifiedWhereClauses::from_iter` (which will ultimately call this /// method). fn intern_quantified_where_clauses( &self, @@ -639,7 +557,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create an "interned" parameter kinds from `data`. This is not /// normally invoked directly; instead, you invoke - /// `VariableKinds::from` (which will ultimately call this + /// `VariableKinds::from_iter` (which will ultimately call this /// method). fn intern_generic_arg_kinds( &self, @@ -655,7 +573,7 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { /// Create "interned" variable kinds with universe index from `data`. This is not /// normally invoked directly; instead, you invoke - /// `CanonicalVarKinds::from` (which will ultimately call this + /// `CanonicalVarKinds::from_iter` (which will ultimately call this /// method). fn intern_canonical_var_kinds( &self, @@ -668,25 +586,56 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { &self, canonical_var_kinds: &'a Self::InternedCanonicalVarKinds, ) -> &'a [CanonicalVarKind]; + + /// Create "interned" constraints from `data`. This is not + /// normally invoked dirctly; instead, you invoke + /// `Constraints::from_iter` (which will ultimately call this + /// method). + fn intern_constraints( + &self, + data: impl IntoIterator>, E>>, + ) -> Result; + + /// Lookup the slice of `Constraint` that was interned to + /// create a `Constraints`. + fn constraints_data<'a>( + &self, + constraints: &'a Self::InternedConstraints, + ) -> &'a [InEnvironment>]; } +/// "Target" interner, used to specify the interner of the folded value. +/// In most cases, both interners are the same, but in some cases you want +/// to change a value to a different internal representation, and as such +/// a different target interner. +/// +/// Contains several methods to transfer types from another interner to +/// the `TargetInterner`. pub trait TargetInterner: Interner { + /// Transfer a `DefId` to the target interner. fn transfer_def_id(def_id: I::DefId) -> Self::DefId; + /// Transfer an AdtId to the target interner. fn transfer_adt_id(adt_id: I::InternedAdtId) -> Self::InternedAdtId; + /// Transfer variable kinds to the target interner. fn transfer_variable_kinds( variable_kinds: I::InternedVariableKinds, ) -> Self::InternedVariableKinds; + /// Transfer canonical var kinds to the target interner. fn transfer_canonical_var_kinds( variable_kinds: I::InternedCanonicalVarKinds, ) -> Self::InternedCanonicalVarKinds; + /// Transfer constant values to the target interner. fn transfer_const( &self, const_evaluated: &I::InternedConcreteConst, ) -> Self::InternedConcreteConst; + + /// Transfer function ABI to the target interner. + fn transfer_abi(abi: I::FnAbi) -> Self::FnAbi; } impl TargetInterner for I { @@ -716,6 +665,10 @@ impl TargetInterner for I { ) -> Self::InternedConcreteConst { const_evaluated.clone() } + + fn transfer_abi(abi: I::FnAbi) -> Self::FnAbi { + abi + } } /// Implemented by types that have an associated interner (which @@ -725,6 +678,7 @@ impl TargetInterner for I { /// It's particularly useful for writing `Fold` impls for generic types like /// `Binder`, since it allows us to figure out the interner of `T`. pub trait HasInterner { + /// The interner associated with the type. type Interner: Interner; } diff --git a/vendor/chalk-ir-0.14.0/src/lib.rs b/vendor/chalk-ir-0.25.0/src/lib.rs similarity index 74% rename from vendor/chalk-ir-0.14.0/src/lib.rs rename to vendor/chalk-ir-0.25.0/src/lib.rs index e650f5dc00..3a1cad53f3 100644 --- a/vendor/chalk-ir-0.14.0/src/lib.rs +++ b/vendor/chalk-ir-0.25.0/src/lib.rs @@ -1,18 +1,21 @@ +//! Defines the IR for types and logical predicates. + #![deny(rust_2018_idioms)] +#![warn(missing_docs)] // Allows macros to refer to this crate as `::chalk_ir` extern crate self as chalk_ir; -use crate::cast::{Cast, CastTo}; +use crate::cast::{Cast, CastTo, Caster}; use crate::fold::shift::Shift; use crate::fold::{Fold, Folder, Subst, SuperFold}; use crate::visit::{SuperVisit, Visit, VisitExt, VisitResult, Visitor}; use chalk_derive::{Fold, HasInterner, SuperVisit, Visit, Zip}; -use std::iter; use std::marker::PhantomData; pub use crate::debug::SeparatorTraitRef; +/// Uninhabited (empty) type, used in combination with `PhantomData`. #[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Void {} @@ -63,34 +66,66 @@ pub mod debug; /// The set of assumptions we've made so far, and the current number of /// universal (forall) quantifiers we're within. pub struct Environment { + /// The clauses in the environment. pub clauses: ProgramClauses, } +impl Copy for Environment where I::InternedProgramClauses: Copy {} + impl Environment { + /// Creates a new environment. pub fn new(interner: &I) -> Self { Environment { - clauses: ProgramClauses::new(interner), + clauses: ProgramClauses::empty(interner), } } + /// Adds (an iterator of) clauses to the environment. pub fn add_clauses(&self, interner: &I, clauses: II) -> Self where II: IntoIterator>, { let mut env = self.clone(); env.clauses = - ProgramClauses::from(interner, env.clauses.iter(interner).cloned().chain(clauses)); + ProgramClauses::from_iter(interner, env.clauses.iter(interner).cloned().chain(clauses)); env } + + /// True if any of the clauses in the environment have a consequence of `Compatible`. + /// Panics if the conditions or constraints of that clause are not empty. + pub fn has_compatible_clause(&self, interner: &I) -> bool { + self.clauses.as_slice(interner).iter().any(|c| { + let ProgramClauseData(implication) = c.data(interner); + match implication.skip_binders().consequence { + DomainGoal::Compatible => { + // We currently don't generate `Compatible` with any conditions or constraints + // If this was needed, for whatever reason, then a third "yes, but must evaluate" + // return value would have to be added. + assert!(implication.skip_binders().conditions.is_empty(interner)); + assert!(implication.skip_binders().constraints.is_empty(interner)); + true + } + _ => false, + } + }) + } } +/// A goal with an environment to solve it in. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] +#[allow(missing_docs)] pub struct InEnvironment { pub environment: Environment, pub goal: G, } +impl + Copy, I: Interner> Copy for InEnvironment where + I::InternedProgramClauses: Copy +{ +} + impl InEnvironment { + /// Creates a new environment/goal pair. pub fn new(environment: &Environment, goal: G) -> Self { InEnvironment { environment: environment.clone(), @@ -98,6 +133,7 @@ impl InEnvironment { } } + /// Maps the goal without touching the environment. pub fn map(self, op: OP) -> InEnvironment where OP: FnOnce(G) -> H, @@ -114,7 +150,9 @@ impl HasInterner for InEnvironment { type Interner = G::Interner; } +/// Different signed int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum IntTy { Isize, I8, @@ -124,7 +162,9 @@ pub enum IntTy { I128, } +/// Different unsigned int types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum UintTy { Usize, U8, @@ -134,13 +174,17 @@ pub enum UintTy { U128, } +/// Different kinds of float types. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum FloatTy { F32, F64, } +/// Types of scalar values. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +#[allow(missing_docs)] pub enum Scalar { Bool, Char, @@ -149,12 +193,25 @@ pub enum Scalar { Float(FloatTy), } +/// Whether a function is safe or not. +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Safety { + /// Safe + Safe, + /// Unsafe + Unsafe, +} + +/// Whether a type is mutable or not. #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub enum Mutability { + /// Mutable Mut, + /// Immutable Not, } +/// Different kinds of Rust types. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Fold, Visit)] pub enum TypeName { /// Abstract data types, i.e., structs, unions, or enumerations. @@ -215,20 +272,25 @@ impl HasInterner for TypeName { /// See https://rustc-dev-guide.rust-lang.org/borrow_check/region_inference.html#placeholders-and-universes for more. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct UniverseIndex { + /// The counter for the universe index, starts with 0. pub counter: usize, } impl UniverseIndex { + /// Root universe index (0). pub const ROOT: UniverseIndex = UniverseIndex { counter: 0 }; + /// Root universe index (0). pub fn root() -> UniverseIndex { Self::ROOT } + /// Whether one universe can "see" another. pub fn can_see(self, ui: UniverseIndex) -> bool { self.counter >= ui.counter } + /// Increases the index counter. pub fn next(self) -> UniverseIndex { UniverseIndex { counter: self.counter + 1, @@ -250,6 +312,7 @@ pub struct UniverseMap { } impl UniverseMap { + /// Creates a new universe map. pub fn new() -> Self { UniverseMap { universes: vec![UniverseIndex::root()], @@ -261,6 +324,8 @@ impl UniverseMap { self.universes.len() } } + +/// The id for an Abstract Data Type (i.e. structs, unions and enums). #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AdtId(pub I::InternedAdtId); @@ -271,9 +336,11 @@ pub struct AdtId(pub I::InternedAdtId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct TraitId(pub I::DefId); +/// The id for an impl. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ImplId(pub I::DefId); +/// Id for a specific clause. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClauseId(pub I::DefId); @@ -284,41 +351,50 @@ pub struct ClauseId(pub I::DefId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AssocTypeId(pub I::DefId); +/// Id for an opaque type. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct OpaqueTyId(pub I::DefId); +/// Function definition id. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct FnDefId(pub I::DefId); +/// Id for Rust closures. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClosureId(pub I::DefId); impl_debugs!(ImplId, ClauseId); +/// A Rust type. The actual type data is stored in `TyData`. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Ty { interned: I::InternedType, } impl Ty { + /// Creates a type from `TyData`. pub fn new(interner: &I, data: impl CastTo>) -> Self { Ty { interned: I::intern_ty(interner, data.cast(interner)), } } + /// Gets the interned type. pub fn interned(&self) -> &I::InternedType { &self.interned } + /// Gets the underlying type data. pub fn data(&self, interner: &I) -> &TyData { I::ty_data(interner, &self.interned) } + /// Creates a `FromEnv` constraint using this type. pub fn from_env(&self) -> FromEnv { FromEnv::Ty(self.clone()) } + /// Creates a WF-constraint for this type. pub fn well_formed(&self) -> WellFormed { WellFormed::Ty(self.clone()) } @@ -346,14 +422,21 @@ impl Ty { } } - /// Returns true if this is a `BoundVar` or `InferenceVar`. - pub fn is_var(&self, interner: &I) -> bool { + /// Returns true if this is a `BoundVar` or an `InferenceVar` of `TyKind::General`. + pub fn is_general_var(&self, interner: &I, binders: &CanonicalVarKinds) -> bool { match self.data(interner) { - TyData::BoundVar(_) | TyData::InferenceVar(_, _) => true, + TyData::BoundVar(bv) + if bv.debruijn == DebruijnIndex::INNERMOST + && binders.at(interner, bv.index).kind == VariableKind::Ty(TyKind::General) => + { + true + } + TyData::InferenceVar(_, TyKind::General) => true, _ => false, } } + /// Returns true if this is an `Alias`. pub fn is_alias(&self, interner: &I) -> bool { match self.data(interner) { TyData::Alias(..) => true, @@ -361,7 +444,7 @@ impl Ty { } } - /// Returns true if this is an `IntTy` or `UintTy` + /// Returns true if this is an `IntTy` or `UintTy`. pub fn is_integer(&self, interner: &I) -> bool { match self.data(interner) { TyData::Apply(ApplicationTy { @@ -376,7 +459,7 @@ impl Ty { } } - /// Returns true if this is a `FloatTy` + /// Returns true if this is a `FloatTy`. pub fn is_float(&self, interner: &I) -> bool { match self.data(interner) { TyData::Apply(ApplicationTy { @@ -395,6 +478,7 @@ impl Ty { } } +/// Type data, which holds the actual type information. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub enum TyData { /// An "application" type is one that applies the set of type @@ -404,7 +488,7 @@ pub enum TyData { /// an empty list). Apply(ApplicationTy), - /// instantiated form a universally quantified type, e.g., from + /// instantiated from a universally quantified type, e.g., from /// `forall { .. }`. Stands in as a representative of "some /// unknown type". Placeholder(PlaceholderIndex), @@ -428,7 +512,7 @@ pub enum TyData { /// Note that "higher-ranked" types (starting with `for<>`) are either /// function types or dyn types, and do not appear otherwise in Rust /// surface syntax. - Function(Fn), + Function(FnPointer), /// References the binding at the given depth. The index is a [de /// Bruijn index], so it counts back through the in-scope binders. @@ -438,7 +522,17 @@ pub enum TyData { InferenceVar(InferenceVar, TyKind), } +impl Copy for TyData +where + I::InternedLifetime: Copy, + I::InternedSubstitution: Copy, + I::InternedVariableKinds: Copy, + I::InternedQuantifiedWhereClauses: Copy, +{ +} + impl TyData { + /// Casts the type data to a type. pub fn intern(self, interner: &I) -> Ty { Ty::new(interner, self) } @@ -470,23 +564,29 @@ impl TyData { /// indices identify the location *within* that binder. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct BoundVar { + /// Debruijn index, which identifies the binder. pub debruijn: DebruijnIndex, + /// Index within the binder. pub index: usize, } impl BoundVar { + /// Creates a new bound variable. pub fn new(debruijn: DebruijnIndex, index: usize) -> Self { Self { debruijn, index } } + /// Casts the bound variable to a type. pub fn to_ty(self, interner: &I) -> Ty { TyData::::BoundVar(self).intern(interner) } + /// Wrap the bound variable in a lifetime. pub fn to_lifetime(self, interner: &I) -> Lifetime { LifetimeData::::BoundVar(self).intern(interner) } + /// Wraps the bound variable in a constant. pub fn to_const(self, interner: &I, ty: Ty) -> Const { ConstData { ty, @@ -559,13 +659,18 @@ pub struct DebruijnIndex { } impl DebruijnIndex { + /// Innermost index. pub const INNERMOST: DebruijnIndex = DebruijnIndex { depth: 0 }; + /// One level higher than the innermost index. pub const ONE: DebruijnIndex = DebruijnIndex { depth: 1 }; + /// Creates a new de Bruijn index with a given depth. pub fn new(depth: u32) -> Self { DebruijnIndex { depth } } + /// Depth of the De Bruijn index, counting from 0 starting with + /// the innermost binder. pub fn depth(self) -> u32 { self.depth } @@ -685,10 +790,10 @@ impl DebruijnIndex { /// A "DynTy" represents a trait object (`dyn Trait`). Trait objects /// are conceptually very related to an "existential type" of the form -/// `exists { T: Trait }` (another exaple of such type is `impl Trait`). +/// `exists { T: Trait }` (another example of such type is `impl Trait`). /// `DynTy` represents the bounds on that type. /// -/// The "binder" here represents the unknown self type. So, a type like +/// The "bounds" here represents the unknown self type. So, a type like /// `dyn for<'a> Fn(&'a u32)` would be represented with two-levels of /// binder, as "depicted" here: /// @@ -708,10 +813,21 @@ impl DebruijnIndex { /// level of binder). #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct DynTy { + /// The unknown self type. pub bounds: Binders>, + /// Lifetime of the `DynTy`. pub lifetime: Lifetime, } +impl Copy for DynTy +where + I::InternedLifetime: Copy, + I::InternedQuantifiedWhereClauses: Copy, + I::InternedVariableKinds: Copy, +{ +} + +/// A type, lifetime or constant whose value is being inferred. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub struct InferenceVar { index: u32, @@ -724,18 +840,22 @@ impl From for InferenceVar { } impl InferenceVar { + /// Gets the underlying index value. pub fn index(self) -> u32 { self.index } + /// Wraps the inference variable in a type. pub fn to_ty(self, interner: &I, kind: TyKind) -> Ty { TyData::::InferenceVar(self, kind).intern(interner) } + /// Wraps the inference variable in a lifetime. pub fn to_lifetime(self, interner: &I) -> Lifetime { LifetimeData::::InferenceVar(self).intern(interner) } + /// Wraps the inference variable in a constant. pub fn to_const(self, interner: &I, ty: Ty) -> Const { ConstData { ty, @@ -748,27 +868,37 @@ impl InferenceVar { /// for<'a...'z> X -- all binders are instantiated at once, /// and we use deBruijn indices within `self.ty` #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] -pub struct Fn { +#[allow(missing_docs)] +pub struct FnPointer { pub num_binders: usize, + pub abi: I::FnAbi, + pub safety: Safety, + pub variadic: bool, pub substitution: Substitution, } -#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] +impl Copy for FnPointer where I::InternedSubstitution: Copy {} + +/// Constants. +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Const { interned: I::InternedConst, } impl Const { + /// Create a `Const` using something that can be cast to const data. pub fn new(interner: &I, data: impl CastTo>) -> Self { Const { interned: I::intern_const(interner, data.cast(interner)), } } + /// Gets the interned constant. pub fn interned(&self) -> &I::InternedConst { &self.interned } + /// Gets the constant data from the interner. pub fn data(&self, interner: &I) -> &ConstData { I::const_data(interner, &self.interned) } @@ -803,53 +933,73 @@ impl Const { } } +/// Constant data, containing the constant's type and value. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub struct ConstData { + /// Type that holds the constant. pub ty: Ty, + /// The value of the constant. pub value: ConstValue, } +/// A constant value, not necessarily concrete. #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] pub enum ConstValue { + /// Bound var (e.g. a parameter). BoundVar(BoundVar), + /// Constant whose value is being inferred. InferenceVar(InferenceVar), + /// Lifetime on some yet-unknown placeholder. Placeholder(PlaceholderIndex), + /// Concrete constant value. Concrete(ConcreteConst), } +impl Copy for ConstValue where I::InternedConcreteConst: Copy {} + impl ConstData { + /// Wraps the constant data in a `Const`. pub fn intern(self, interner: &I) -> Const { Const::new(interner, self) } } -#[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] +/// Concrete constant, whose value is known (as opposed to +/// inferred constants and placeholders). +#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct ConcreteConst { + /// The interned constant. pub interned: I::InternedConcreteConst, } impl ConcreteConst { + /// Checks whether two concrete constants are equal. pub fn const_eq(&self, ty: &Ty, other: &ConcreteConst, interner: &I) -> bool { interner.const_eq(&ty.interned, &self.interned, &other.interned) } } +/// A Rust lifetime. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct Lifetime { interned: I::InternedLifetime, } impl Lifetime { + /// Create a lifetime from lifetime data + /// (or something that can be cast to lifetime data). pub fn new(interner: &I, data: impl CastTo>) -> Self { Lifetime { interned: I::intern_lifetime(interner, data.cast(interner)), } } + /// Gets the interned value. pub fn interned(&self) -> &I::InternedLifetime { &self.interned } + /// Gets the lifetime data. pub fn data(&self, interner: &I) -> &LifetimeData { I::lifetime_data(interner, &self.interned) } @@ -884,16 +1034,21 @@ impl Lifetime { } } +/// Lifetime data, including what kind of lifetime it is and what it points to. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub enum LifetimeData { - /// See TyData::Var(_). + /// See TyData::BoundVar. BoundVar(BoundVar), + /// Lifetime whose value is being inferred. InferenceVar(InferenceVar), + /// Lifetime on some yet-unknown placeholder. Placeholder(PlaceholderIndex), + /// Lifetime on phantom data. Phantom(Void, PhantomData), } impl LifetimeData { + /// Wrap the lifetime data in a lifetime. pub fn intern(self, interner: &I) -> Lifetime { Lifetime::new(interner, self) } @@ -911,14 +1066,17 @@ pub struct PlaceholderIndex { } impl PlaceholderIndex { + /// Wrap the placeholder instance in a lifetime. pub fn to_lifetime(self, interner: &I) -> Lifetime { LifetimeData::::Placeholder(self).intern(interner) } + /// Create an interned type. pub fn to_ty(self, interner: &I) -> Ty { TyData::Placeholder(self).intern(interner) } + /// Wrap the placeholder index in a constant. pub fn to_const(self, interner: &I, ty: Ty) -> Const { ConstData { ty, @@ -928,18 +1086,25 @@ impl PlaceholderIndex { } } -// Fold derive intentionally omitted, folded through Ty +/// Normal Rust types, containing the type name and zero or more generic arguments. +/// For example, in `Vec` those would be `Vec` and `[u32]` respectively. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct ApplicationTy { + /// The type name. pub name: TypeName, + /// The substitution containing the generic arguments. pub substitution: Substitution, } +impl Copy for ApplicationTy where I::InternedSubstitution: Copy {} + impl ApplicationTy { + /// Create an interned type from this application type. pub fn intern(self, interner: &I) -> Ty { Ty::new(interner, self) } + /// Gets an iterator of all type parameters. pub fn type_parameters<'a>(&'a self, interner: &'a I) -> impl Iterator> + 'a { self.substitution .iter(interner) @@ -947,10 +1112,12 @@ impl ApplicationTy { .cloned() } + /// Gets the first type parameter. pub fn first_type_parameter(&self, interner: &I) -> Option> { self.type_parameters(interner).next() } + /// Gets the number of type parameters. pub fn len_type_parameters(&self, interner: &I) -> usize { self.type_parameters(interner).count() } @@ -967,19 +1134,28 @@ impl ApplicationTy { /// `Index` impl for. `i` would have a `TyKind` of `Integer` to guide the /// inference process. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +#[allow(missing_docs)] pub enum TyKind { General, Integer, Float, } +/// The "kind" of variable. Type, lifetime or constant. #[derive(Clone, PartialEq, Eq, Hash)] +#[allow(missing_docs)] pub enum VariableKind { Ty(TyKind), Lifetime, Const(Ty), } +impl interner::HasInterner for VariableKind { + type Interner = I; +} + +impl Copy for VariableKind where I::InternedType: Copy {} + impl VariableKind { fn to_bound_variable(&self, interner: &I, bound_var: BoundVar) -> GenericArg { match self { @@ -1002,37 +1178,45 @@ impl VariableKind { } } +/// A generic argument, see `GenericArgData` for more information. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct GenericArg { interned: I::InternedGenericArg, } impl GenericArg { + /// Constructs a generic argument using `GenericArgData`. pub fn new(interner: &I, data: GenericArgData) -> Self { let interned = I::intern_generic_arg(interner, data); GenericArg { interned } } + /// Gets the interned value. pub fn interned(&self) -> &I::InternedGenericArg { &self.interned } + /// Gets the underlying data. pub fn data(&self, interner: &I) -> &GenericArgData { I::generic_arg_data(interner, &self.interned) } + /// Asserts that this is a type argument. pub fn assert_ty_ref(&self, interner: &I) -> &Ty { self.ty(interner).unwrap() } + /// Asserts that this is a lifetime argument. pub fn assert_lifetime_ref(&self, interner: &I) -> &Lifetime { self.lifetime(interner).unwrap() } + /// Asserts that this is a constant argument. pub fn assert_const_ref(&self, interner: &I) -> &Const { self.constant(interner).unwrap() } + /// Checks whether the generic argument is a type. pub fn is_ty(&self, interner: &I) -> bool { match self.data(interner) { GenericArgData::Ty(_) => true, @@ -1041,6 +1225,7 @@ impl GenericArg { } } + /// Returns the type if it is one, `None` otherwise. pub fn ty(&self, interner: &I) -> Option<&Ty> { match self.data(interner) { GenericArgData::Ty(t) => Some(t), @@ -1048,6 +1233,7 @@ impl GenericArg { } } + /// Returns the lifetime if it is one, `None` otherwise. pub fn lifetime(&self, interner: &I) -> Option<&Lifetime> { match self.data(interner) { GenericArgData::Lifetime(t) => Some(t), @@ -1055,6 +1241,7 @@ impl GenericArg { } } + /// Returns the constant if it is one, `None` otherwise. pub fn constant(&self, interner: &I) -> Option<&Const> { match self.data(interner) { GenericArgData::Const(c) => Some(c), @@ -1063,25 +1250,43 @@ impl GenericArg { } } +/// Generic arguments data. #[derive(Clone, PartialEq, Eq, Hash, Visit, Fold, Zip)] pub enum GenericArgData { + /// Type argument Ty(Ty), + /// Lifetime argument Lifetime(Lifetime), + /// Constant argument Const(Const), } +impl Copy for GenericArgData +where + I::InternedType: Copy, + I::InternedLifetime: Copy, + I::InternedConst: Copy, +{ +} + impl GenericArgData { + /// Create an interned type. pub fn intern(self, interner: &I) -> GenericArg { GenericArg::new(interner, self) } } +/// A value with an associated variable kind. #[derive(Clone, PartialEq, Eq, Hash)] pub struct WithKind { + /// The associated variable kind. pub kind: VariableKind, + /// The wrapped value. value: T, } +impl Copy for WithKind where I::InternedType: Copy {} + impl HasInterner for WithKind { type Interner = I; } @@ -1093,10 +1298,12 @@ impl From> for (VariableKind, T) { } impl WithKind { + /// Creates a `WithKind` from a variable kind and a value. pub fn new(kind: VariableKind, value: T) -> Self { Self { kind, value } } + /// Maps the value in `WithKind`. pub fn map(self, op: OP) -> WithKind where OP: FnOnce(T) -> U, @@ -1107,6 +1314,7 @@ impl WithKind { } } + /// Maps a function taking `WithKind` over `&WithKind`. pub fn map_ref(&self, op: OP) -> WithKind where OP: FnOnce(&T) -> U, @@ -1117,25 +1325,34 @@ impl WithKind { } } + /// Extract the value, ignoring the variable kind. pub fn skip_kind(&self) -> &T { &self.value } } +/// A variable kind with universe index. #[allow(type_alias_bounds)] pub type CanonicalVarKind = WithKind; +/// An alias, which is a trait indirection such as a projection or opaque type. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum AliasTy { + /// An associated type projection. Projection(ProjectionTy), + /// An opaque type. Opaque(OpaqueTy), } +impl Copy for AliasTy where I::InternedSubstitution: Copy {} + impl AliasTy { + /// Create an interned type for this alias. pub fn intern(self, interner: &I) -> Ty { Ty::new(interner, self) } + /// Gets the type parameters of the `Self` type in this alias type. pub fn self_type_parameter(&self, interner: &I) -> Ty { match self { AliasTy::Projection(projection_ty) => projection_ty @@ -1149,25 +1366,46 @@ impl AliasTy { } } +/// A projection `>::AssocItem`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct ProjectionTy { + /// The id for the associated type member. pub associated_ty_id: AssocTypeId, + /// The substitution for the projection. pub substitution: Substitution, } +impl Copy for ProjectionTy where I::InternedSubstitution: Copy {} + +/// An opaque type `opaque type T<..>: Trait = HiddenTy`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct OpaqueTy { + /// The id for the opaque type. pub opaque_ty_id: OpaqueTyId, + /// The substitution for the opaque type. pub substitution: Substitution, } +impl Copy for OpaqueTy where I::InternedSubstitution: Copy {} + +/// A trait reference describes the relationship between a type and a trait. +/// This can be used in two forms: +/// - `P0: Trait` (e.g. `i32: Copy`), which mentions that the type +/// implements the trait. +/// - `>` (e.g. `i32 as Copy`), which casts the type to +/// that specific trait. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct TraitRef { + /// The trait id. pub trait_id: TraitId, + /// The substitution, containing both the `Self` type and the parameters. pub substitution: Substitution, } +impl Copy for TraitRef where I::InternedSubstitution: Copy {} + impl TraitRef { + /// Gets all type parameters in this trait ref, including `Self`. pub fn type_parameters<'a>(&'a self, interner: &'a I) -> impl Iterator> + 'a { self.substitution .iter(interner) @@ -1175,32 +1413,72 @@ impl TraitRef { .cloned() } + /// Gets the type parameters of the `Self` type in this trait ref. pub fn self_type_parameter(&self, interner: &I) -> Ty { self.type_parameters(interner).next().unwrap() } + /// Construct a `FromEnv` using this trait ref. pub fn from_env(self) -> FromEnv { FromEnv::Trait(self) } + /// Construct a `WellFormed` using this trait ref. pub fn well_formed(self) -> WellFormed { WellFormed::Trait(self) } } +/// Lifetime outlives, which for `'a: 'b`` checks that the lifetime `'a` +/// is a superset of the value of `'b`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] +#[allow(missing_docs)] pub struct LifetimeOutlives { pub a: Lifetime, pub b: Lifetime, } + +impl Copy for LifetimeOutlives where I::InternedLifetime: Copy {} + +/// Type outlives, which for `T: 'a` checks that the type `T` +/// lives at least as long as the lifetime `'a` +#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] +pub struct TypeOutlives { + /// The type which must outlive the given lifetime. + pub ty: Ty, + /// The lifetime which the type must outlive. + pub lifetime: Lifetime, +} + +impl Copy for TypeOutlives +where + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ +} + /// Where clauses that can be written by a Rust programmer. #[derive(Clone, PartialEq, Eq, Hash, Fold, SuperVisit, HasInterner, Zip)] pub enum WhereClause { + /// Type implements a trait. Implemented(TraitRef), + /// Type is equal to an alias. AliasEq(AliasEq), + /// One lifetime outlives another. LifetimeOutlives(LifetimeOutlives), + /// Type outlives a lifetime. + TypeOutlives(TypeOutlives), } +impl Copy for WhereClause +where + I::InternedSubstitution: Copy, + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ +} + +/// Checks whether a type or trait ref is well-formed. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum WellFormed { /// A predicate which is true when some trait ref is well-formed. @@ -1231,6 +1509,14 @@ pub enum WellFormed { Ty(Ty), } +impl Copy for WellFormed +where + I::InternedType: Copy, + I::InternedSubstitution: Copy, +{ +} + +/// Checks whether a type or trait ref can be derived from the contents of the environment. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum FromEnv { /// A predicate which enables deriving everything which should be true if we *know* that @@ -1260,17 +1546,28 @@ pub enum FromEnv { Ty(Ty), } +impl Copy for FromEnv +where + I::InternedType: Copy, + I::InternedSubstitution: Copy, +{ +} + /// A "domain goal" is a goal that is directly about Rust, rather than a pure /// logical statement. As much as possible, the Chalk solver should avoid /// decomposing this enum, and instead treat its values opaquely. #[derive(Clone, PartialEq, Eq, Hash, Fold, SuperVisit, HasInterner, Zip)] pub enum DomainGoal { + /// Simple goal that is true if the where clause is true. Holds(WhereClause), + /// True if the type or trait ref is well-formed. WellFormed(WellFormed), + /// True if the trait ref can be derived from in-scope where clauses. FromEnv(FromEnv), + /// True if the alias type can be normalized to some other type Normalize(Normalize), /// True if a type is considered to have been "defined" by the current crate. This is true for @@ -1310,9 +1607,7 @@ pub enum DomainGoal { /// Used to activate the "compatible modality" rules. Rules that introduce predicates that have /// to do with "all compatible universes" should depend on this clause so that they only apply /// if this is present. - /// - /// (HACK: Having `()` makes some of our macros work better.) - Compatible(()), + Compatible, /// Used to indicate that a given type is in a downstream crate. Downstream crates contain the /// current crate at some level of their dependencies. @@ -1327,12 +1622,21 @@ pub enum DomainGoal { /// Used to activate the "reveal mode", in which opaque (`impl Trait`) types can be equated /// to their actual type. - Reveal(()), + Reveal, /// Used to indicate that a trait is object safe. ObjectSafe(TraitId), } +impl Copy for DomainGoal +where + I::InternedSubstitution: Copy, + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ +} + +/// A where clause that can contain `forall<>` or `exists<>` quantifiers. pub type QuantifiedWhereClause = Binders>; impl WhereClause { @@ -1355,12 +1659,13 @@ impl WhereClause { } } - /// If where clause is a `TraitRef`, returns its trait id + /// If where clause is a `TraitRef`, returns its trait id. pub fn trait_id(&self) -> Option> { match self { WhereClause::Implemented(trait_ref) => Some(trait_ref.trait_id), WhereClause::AliasEq(_) => None, WhereClause::LifetimeOutlives(_) => None, + WhereClause::TypeOutlives(_) => None, } } } @@ -1382,69 +1687,12 @@ impl QuantifiedWhereClause { self.map(|wc| wc.into_from_env_goal(interner)) } - /// If the underlying where clause is a `TraitRef`, returns its trait id + /// If the underlying where clause is a `TraitRef`, returns its trait id. pub fn trait_id(&self) -> Option> { self.skip_binders().trait_id() } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct QuantifiedWhereClauses { - interned: I::InternedQuantifiedWhereClauses, -} - -impl QuantifiedWhereClauses { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedQuantifiedWhereClauses { - &self.interned - } - - pub fn from( - interner: &I, - clauses: impl IntoIterator>>, - ) -> Self { - Self::from_fallible( - interner, - clauses - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - clauses: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(QuantifiedWhereClauses { - interned: I::intern_quantified_where_clauses( - interner, - clauses.into_iter().casted(interner), - )?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, QuantifiedWhereClause> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[QuantifiedWhereClause] { - interner.quantified_where_clauses_data(&self.interned) - } -} - impl DomainGoal { /// Convert `Implemented(...)` into `FromEnv(...)`, but leave other /// goals unchanged. @@ -1455,6 +1703,7 @@ impl DomainGoal { } } + /// Lists generic arguments that are inputs to this domain goal. pub fn inputs(&self, interner: &I) -> Vec> { match self { DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => { @@ -1465,29 +1714,49 @@ impl DomainGoal { } } +/// Equality goal: tries to prove that two values are equal. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, Zip)] +#[allow(missing_docs)] pub struct EqGoal { pub a: GenericArg, pub b: GenericArg, } +impl Copy for EqGoal where I::InternedGenericArg: Copy {} + /// Proves that the given type alias **normalizes** to the given /// type. A projection `T::Foo` normalizes to the type `U` if we can /// **match it to an impl** and that impl has a `type Foo = V` where /// `U = V`. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, Zip)] +#[allow(missing_docs)] pub struct Normalize { pub alias: AliasTy, pub ty: Ty, } +impl Copy for Normalize +where + I::InternedSubstitution: Copy, + I::InternedType: Copy, +{ +} + /// Proves **equality** between an alias and a type. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, Zip)] +#[allow(missing_docs)] pub struct AliasEq { pub alias: AliasTy, pub ty: Ty, } +impl Copy for AliasEq +where + I::InternedSubstitution: Copy, + I::InternedType: Copy, +{ +} + impl HasInterner for AliasEq { type Interner = I; } @@ -1501,15 +1770,24 @@ impl HasInterner for AliasEq { /// of `self.binders`.) #[derive(Clone, PartialEq, Eq, Hash)] pub struct Binders { + /// The binders that quantify over the value. pub binders: VariableKinds, + + /// The value being quantified over. value: T, } +impl Copy for Binders where + ::InternedVariableKinds: Copy +{ +} + impl HasInterner for Binders { type Interner = T::Interner; } impl Binders { + /// Create new binders. pub fn new(binders: VariableKinds, value: T) -> Self { Self { binders, value } } @@ -1518,7 +1796,7 @@ impl Binders { /// (value)`. Since our deBruijn indices count binders, not variables, this /// is sometimes useful. pub fn empty(interner: &T::Interner, value: T) -> Self { - let binders = VariableKinds::new(interner); + let binders = VariableKinds::empty(interner); Self { binders, value } } @@ -1547,6 +1825,7 @@ impl Binders { } } + /// Maps the binders by applying a function. pub fn map(self, op: OP) -> Binders where OP: FnOnce(T) -> U, @@ -1573,6 +1852,7 @@ impl Binders { }) } + /// Maps a function taking `Binders<&T>` over `&Binders`. pub fn map_ref<'a, U, OP>(&'a self, op: OP) -> Binders where OP: FnOnce(&'a T) -> U, @@ -1585,12 +1865,12 @@ impl Binders { /// substitution will not change the value, i.e. `^0.0, ^0.1, ^0.2` and so /// on. pub fn identity_substitution(&self, interner: &T::Interner) -> Substitution { - Substitution::from( + Substitution::from_iter( interner, self.binders .iter(interner) .enumerate() - .map(|(i, pk)| (pk, i).to_generic_arg(interner)), + .map(|p| p.to_generic_arg(interner)), ) } @@ -1607,10 +1887,11 @@ impl Binders { // The new variable is at the front and everything afterwards is shifted up by 1 let new_var = TyData::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0)).intern(interner); let value = op(new_var); - let binders = VariableKinds::from(interner, iter::once(VariableKind::Ty(TyKind::General))); + let binders = VariableKinds::from1(interner, VariableKind::Ty(TyKind::General)); Binders { binders, value } } + /// Returns the number of binders. pub fn len(&self, interner: &T::Interner) -> usize { self.binders.len(interner) } @@ -1626,16 +1907,16 @@ where pub fn fuse_binders(self, interner: &T::Interner) -> Binders { let num_binders = self.len(interner); // generate a substitution to shift the indexes of the inner binder: - let subst = Substitution::from( + let subst = Substitution::from_iter( interner, self.value .binders .iter(interner) .enumerate() - .map(|(i, pk)| (pk, i + num_binders).to_generic_arg(interner)), + .map(|(i, pk)| (i + num_binders, pk).to_generic_arg(interner)), ); let value = self.value.substitute(interner, &subst); - let binders = VariableKinds::from( + let binders = VariableKinds::from_iter( interner, self.binders .iter(interner) @@ -1690,6 +1971,7 @@ where } } +/// `IntoIterator` for binders. pub struct BindersIntoIterator { iter: ::IntoIter, binders: VariableKinds, @@ -1713,14 +1995,26 @@ where /// conditions. #[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub struct ProgramClauseImplication { + /// The consequence of the clause, which holds if the conditions holds. pub consequence: DomainGoal, + + /// The condition goals that should hold. pub conditions: Goals, + + /// The lifetime constraints that should be proven. + pub constraints: Constraints, + + /// The relative priority of the implication. pub priority: ClausePriority, } +/// Specifies how important an implication is. #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub enum ClausePriority { + /// High priority, the solver should prioritize this. High, + + /// Low priority, this implication has lower chance to be relevant to the goal. Low, } @@ -1734,15 +2028,18 @@ impl std::ops::BitAnd for ClausePriority { } } +/// Contains the data for a program clause. #[derive(Clone, PartialEq, Eq, Hash, Fold, HasInterner, Zip)] pub struct ProgramClauseData(pub Binders>); impl ProgramClauseImplication { + /// Change the implication into an application holding a `FromEnv` goal. pub fn into_from_env_clause(self, interner: &I) -> ProgramClauseImplication { if self.conditions.is_empty(interner) { ProgramClauseImplication { consequence: self.consequence.into_from_env_goal(interner), conditions: self.conditions.clone(), + constraints: self.constraints.clone(), priority: self.priority, } } else { @@ -1752,10 +2049,12 @@ impl ProgramClauseImplication { } impl ProgramClauseData { + /// Change the program clause data into a `FromEnv` program clause. pub fn into_from_env_clause(self, interner: &I) -> ProgramClauseData { ProgramClauseData(self.0.map(|i| i.into_from_env_clause(interner))) } + /// Intern the program clause data. pub fn intern(self, interner: &I) -> ProgramClause { ProgramClause { interned: interner.intern_program_clause(self), @@ -1763,189 +2062,37 @@ impl ProgramClauseData { } } +/// A program clause is a logic expression used to describe a part of the program. #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] pub struct ProgramClause { interned: I::InternedProgramClause, } impl ProgramClause { + /// Create a new program clause using `ProgramClauseData`. pub fn new(interner: &I, clause: ProgramClauseData) -> Self { let interned = interner.intern_program_clause(clause); Self { interned } } + /// Change the clause into a `FromEnv` clause. pub fn into_from_env_clause(self, interner: &I) -> ProgramClause { let program_clause_data = self.data(interner); let new_clause = program_clause_data.clone().into_from_env_clause(interner); Self::new(interner, new_clause) } + /// Get the interned program clause. pub fn interned(&self) -> &I::InternedProgramClause { &self.interned } + /// Get the program clause data. pub fn data(&self, interner: &I) -> &ProgramClauseData { interner.program_clause_data(&self.interned) } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct ProgramClauses { - interned: I::InternedProgramClauses, -} - -impl ProgramClauses { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedProgramClauses { - &self.interned - } - - pub fn from( - interner: &I, - clauses: impl IntoIterator>>, - ) -> Self { - Self::from_fallible( - interner, - clauses - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - clauses: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(ProgramClauses { - interned: I::intern_program_clauses(interner, clauses.into_iter().casted(interner))?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, ProgramClause> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[ProgramClause] { - interner.program_clauses_data(&self.interned) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct VariableKinds { - interned: I::InternedVariableKinds, -} - -impl VariableKinds { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedVariableKinds { - &self.interned - } - - pub fn from(interner: &I, variable_kinds: impl IntoIterator>) -> Self { - Self::from_fallible( - interner, - variable_kinds - .into_iter() - .map(|p| -> Result, ()> { Ok(p) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - variable_kinds: impl IntoIterator, E>>, - ) -> Result { - Ok(VariableKinds { - interned: I::intern_generic_arg_kinds(interner, variable_kinds.into_iter())?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, VariableKind> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[VariableKind] { - interner.variable_kinds_data(&self.interned) - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] -pub struct CanonicalVarKinds { - interned: I::InternedCanonicalVarKinds, -} - -impl CanonicalVarKinds { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedCanonicalVarKinds { - &self.interned - } - - pub fn from( - interner: &I, - variable_kinds: impl IntoIterator>, - ) -> Self { - Self::from_fallible( - interner, - variable_kinds - .into_iter() - .map(|p| -> Result, ()> { Ok(p) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - variable_kinds: impl IntoIterator, E>>, - ) -> Result { - Ok(CanonicalVarKinds { - interned: I::intern_canonical_var_kinds(interner, variable_kinds.into_iter())?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, CanonicalVarKind> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[CanonicalVarKind] { - interner.canonical_var_kinds_data(&self.interned) - } -} - /// Wraps a "canonicalized item". Items are canonicalized as follows: /// /// All unresolved existential variables are "renumbered" according to their @@ -1953,7 +2100,10 @@ impl CanonicalVarKinds { /// `binders` field. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct Canonical { + /// The item that is canonicalized. pub value: T, + + /// The kind/universe of the variable. pub binders: CanonicalVarKinds, } @@ -1969,11 +2119,16 @@ impl HasInterner for Canonical { /// To produce one of these values, use the `u_canonicalize` method. #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct UCanonical { + /// The wrapped `Canonical`. pub canonical: Canonical, + + /// The number of universes that have been collapsed. pub universes: usize, } impl UCanonical { + /// Checks whether the universe canonical value is a trivial + /// substitution (e.g. an identity substitution). pub fn is_trivial_substitution( &self, interner: &T::Interner, @@ -1982,14 +2137,15 @@ impl UCanonical { let subst = &canonical_subst.value.subst; assert_eq!( self.canonical.binders.len(interner), - subst.parameters(interner).len() + subst.as_slice(interner).len() ); subst.is_identity_subst(interner) } + /// Creates an identity substitution. pub fn trivial_substitution(&self, interner: &T::Interner) -> Substitution { let binders = &self.canonical.binders; - Substitution::from( + Substitution::from_iter( interner, binders .iter(interner) @@ -2020,58 +2176,6 @@ impl UCanonical { } } -#[derive(Copy, Clone, PartialEq, Eq, Hash, HasInterner)] -/// A list of goals. -pub struct Goals { - interned: I::InternedGoals, -} - -impl Goals { - pub fn new(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn interned(&self) -> &I::InternedGoals { - &self.interned - } - - pub fn from(interner: &I, goals: impl IntoIterator>>) -> Self { - Self::from_fallible( - interner, - goals - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - goals: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(Goals { - interned: I::intern_goals(interner, goals.into_iter().casted(interner))?, - }) - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, Goal> { - self.as_slice(interner).iter() - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.as_slice(interner).is_empty() - } - - pub fn len(&self, interner: &I) -> usize { - self.as_slice(interner).len() - } - - pub fn as_slice(&self, interner: &I) -> &[Goal] { - interner.goals_data(&self.interned) - } -} - #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] /// A general goal; this is the full range of questions you can pose to Chalk. pub struct Goal { @@ -2079,19 +2183,23 @@ pub struct Goal { } impl Goal { + /// Create a new goal using `GoalData`. pub fn new(interner: &I, interned: GoalData) -> Self { let interned = I::intern_goal(interner, interned); Self { interned } } + /// Gets the interned goal. pub fn interned(&self) -> &I::InternedGoal { &self.interned } + /// Gets the interned goal data. pub fn data(&self, interner: &I) -> &GoalData { interner.goal_data(&self.interned) } + /// Create a goal using a `forall` or `exists` quantifier. pub fn quantify( self, interner: &I, @@ -2101,7 +2209,7 @@ impl Goal { GoalData::Quantified(kind, Binders::new(binders, self)).intern(interner) } - /// Takes a goal `G` and turns it into `not { G }` + /// Takes a goal `G` and turns it into `not { G }`. pub fn negate(self, interner: &I) -> Self { GoalData::Not(self).intern(interner) } @@ -2114,9 +2222,9 @@ impl Goal { QuantifierKind::ForAll, Binders::with_fresh_type_var(interner, |ty| { GoalData::Implies( - ProgramClauses::from( + ProgramClauses::from_iter( interner, - vec![DomainGoal::Compatible(()), DomainGoal::DownstreamType(ty)], + vec![DomainGoal::Compatible, DomainGoal::DownstreamType(ty)], ), self.shifted_in(interner), ) @@ -2126,6 +2234,7 @@ impl Goal { .intern(interner) } + /// Create an implication goal that holds if the predicates are true. pub fn implied_by(self, interner: &I, predicates: ProgramClauses) -> Goal { GoalData::Implies(predicates, self).intern(interner) } @@ -2144,6 +2253,7 @@ impl Goal where I: Interner, { + /// Creates a single goal that only holds if a list of goals holds. pub fn all(interner: &I, iter: II) -> Self where II: IntoIterator>, @@ -2152,7 +2262,7 @@ where if let Some(goal0) = iter.next() { if let Some(goal1) = iter.next() { // More than one goal to prove - let goals = Goals::from( + let goals = Goals::from_iter( interner, Some(goal0).into_iter().chain(Some(goal1)).chain(iter), ); @@ -2163,7 +2273,7 @@ where } } else { // No goals to prove, always true - GoalData::All(Goals::new(interner)).intern(interner) + GoalData::All(Goals::empty(interner)).intern(interner) } } } @@ -2174,8 +2284,14 @@ pub enum GoalData { /// Introduces a binding at depth 0, shifting other bindings up /// (deBruijn index). Quantified(QuantifierKind, Binders>), + + /// A goal that holds given some clauses (like an if-statement). Implies(ProgramClauses, Goal), + + /// List of goals that all should hold. All(Goals), + + /// Negation: the inner goal should not hold. Not(Goal), /// Make two things equal; the rules for doing so are well known to the logic @@ -2192,20 +2308,47 @@ pub enum GoalData { /// X, Y where `X = Y` is not true. But we treat it as "cannot /// prove" so that `forall { not { X = Y } }` also winds up /// as cannot prove. - /// - /// (TOTAL HACK: Having a unit result makes some of our macros work better.) - CannotProve(()), + CannotProve, +} + +impl Copy for GoalData +where + I::InternedType: Copy, + I::InternedLifetime: Copy, + I::InternedGenericArg: Copy, + I::InternedSubstitution: Copy, + I::InternedGoal: Copy, + I::InternedGoals: Copy, + I::InternedProgramClauses: Copy, + I::InternedVariableKinds: Copy, +{ } impl GoalData { + /// Create an interned goal. pub fn intern(self, interner: &I) -> Goal { Goal::new(interner, self) } } +/// Kinds of quantifiers in the logic, such as `forall` and `exists`. #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum QuantifierKind { + /// Universal quantifier `ForAll`. + /// + /// A formula with the universal quantifier `forall(x). P(x)` is satisfiable + /// if and only if the subformula `P(x)` is true for all possible values for x. ForAll, + + /// Existential quantifier `Exists`. + /// + /// A formula with the existential quantifier `exists(x). P(x)` is satisfiable + /// if and only if there exists at least one value for all possible values of x + /// which satisfies the subformula `P(x)`. + + /// In the context of chalk, the existential quantifier usually demands the + /// existence of exactly one instance (i.e. type) that satisfies the formula + /// (i.e. type constraints). More than one instance means that the result is ambiguous. Exists, } @@ -2215,77 +2358,25 @@ pub enum QuantifierKind { /// lifetime constraints, instead gathering them up to return with our solution /// for later checking. This allows for decoupling between type and region /// checking in the compiler. -#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] +#[derive(Clone, PartialEq, Eq, Hash, Fold, Visit, HasInterner, Zip)] pub enum Constraint { - Outlives(Lifetime, Lifetime), + /// Outlives constraint `'a: 'b`, indicating that the value of `'a` must be + /// a superset of the value of `'b`. + LifetimeOutlives(Lifetime, Lifetime), + + /// Type outlives constraint `T: 'a`, indicating that the type `T` must live + /// at least as long as the value of `'a`. + TypeOutlives(Ty, Lifetime), } -/// A mapping of inference variables to instantiations thereof. -#[derive(Copy, Clone, PartialEq, Eq, Hash, HasInterner)] -pub struct Substitution { - /// Map free variable with given index to the value with the same - /// index. Naturally, the kind of the variable must agree with - /// the kind of the value. - interned: I::InternedSubstitution, +impl Copy for Constraint +where + I::InternedLifetime: Copy, + I::InternedType: Copy, +{ } impl Substitution { - pub fn from( - interner: &I, - parameters: impl IntoIterator>>, - ) -> Self { - Self::from_fallible( - interner, - parameters - .into_iter() - .map(|p| -> Result, ()> { Ok(p.cast(interner)) }), - ) - .unwrap() - } - - pub fn from_fallible( - interner: &I, - parameters: impl IntoIterator>, E>>, - ) -> Result { - use crate::cast::Caster; - Ok(Substitution { - interned: I::intern_substitution(interner, parameters.into_iter().casted(interner))?, - }) - } - - pub fn interned(&self) -> &I::InternedSubstitution { - &self.interned - } - - /// Index into the list of parameters - pub fn at(&self, interner: &I, index: usize) -> &GenericArg { - &self.parameters(interner)[index] - } - - pub fn from1(interner: &I, parameter: impl CastTo>) -> Self { - Self::from(interner, Some(parameter)) - } - - pub fn empty(interner: &I) -> Self { - Self::from(interner, None::>) - } - - pub fn is_empty(&self, interner: &I) -> bool { - self.parameters(interner).is_empty() - } - - pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, GenericArg> { - self.parameters(interner).iter() - } - - pub fn parameters(&self, interner: &I) -> &[GenericArg] { - interner.substitution_data(&self.interned) - } - - pub fn len(&self, interner: &I) -> usize { - self.parameters(interner).len() - } - /// A substitution is an **identity substitution** if it looks /// like this /// @@ -2318,6 +2409,7 @@ impl Substitution { }) } + /// Apply the substitution to a value. pub fn apply(&self, value: &T, interner: &I) -> T::Result where T: Fold, @@ -2340,21 +2432,23 @@ struct SubstFolder<'i, I: Interner> { } impl SubstFolder<'_, I> { - /// Index into the list of parameters + /// Index into the list of parameters. pub fn at(&self, index: usize) -> &GenericArg { let interner = self.interner; - &self.subst.parameters(interner)[index] + &self.subst.as_slice(interner)[index] } } +/// Convert a value to a list of parameters. pub trait AsParameters { + /// Convert the current value to parameters. fn as_parameters(&self, interner: &I) -> &[GenericArg]; } impl AsParameters for Substitution { #[allow(unreachable_code, unused_variables)] fn as_parameters(&self, interner: &I) -> &[GenericArg] { - self.parameters(interner) + self.as_slice(interner) } } @@ -2385,22 +2479,24 @@ where } } +/// Utility for converting a list of all the binders into scope +/// into references to those binders. Simply pair the binders with +/// the indices, and invoke `to_generic_arg()` on the `(binder, +/// index)` pair. The result will be a reference to a bound +/// variable of appropriate kind at the corresponding index. pub trait ToGenericArg { - /// Utility for converting a list of all the binders into scope - /// into references to those binders. Simply pair the binders with - /// the indices, and invoke `to_generic_arg()` on the `(binder, - /// index)` pair. The result will be a reference to a bound - /// variable of appropriate kind at the corresponding index. + /// Converts the binders in scope to references to those binders. fn to_generic_arg(&self, interner: &I) -> GenericArg { self.to_generic_arg_at_depth(interner, DebruijnIndex::INNERMOST) } + /// Converts the binders at the specified depth to references to those binders. fn to_generic_arg_at_depth(&self, interner: &I, debruijn: DebruijnIndex) -> GenericArg; } -impl<'a, I: Interner> ToGenericArg for (&'a VariableKind, usize) { +impl<'a, I: Interner> ToGenericArg for (usize, &'a VariableKind) { fn to_generic_arg_at_depth(&self, interner: &I, debruijn: DebruijnIndex) -> GenericArg { - let &(binder, index) = self; + let &(index, binder) = self; let bound_var = BoundVar::new(debruijn, index); binder.to_bound_variable(interner, bound_var) } @@ -2454,6 +2550,122 @@ impl<'i, I: Interner> Folder<'i, I> for &SubstFolder<'i, I> { } } +macro_rules! interned_slice { + ($seq:ident, $data:ident => $elem:ty, $intern:ident => $interned:ident) => { + /// List of interned elements. + #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, HasInterner)] + pub struct $seq { + interned: I::$interned, + } + + impl $seq { + /// Get the interned elements. + pub fn interned(&self) -> &I::$interned { + &self.interned + } + } + + impl $seq { + /// Tries to create a sequence using an iterator of element-like things. + pub fn from_fallible( + interner: &I, + elements: impl IntoIterator, E>>, + ) -> Result { + Ok(Self { + interned: I::$intern(interner, elements.into_iter().casted(interner))?, + }) + } + + /// Returns a slice containing the elements. + pub fn as_slice(&self, interner: &I) -> &[$elem] { + Interner::$data(interner, &self.interned) + } + + /// Create a sequence from elements + pub fn from_iter( + interner: &I, + elements: impl IntoIterator>, + ) -> Self { + Self::from_fallible( + interner, + elements + .into_iter() + .map(|el| -> Result<$elem, ()> { Ok(el.cast(interner)) }), + ) + .unwrap() + } + + /// Index into the sequence. + pub fn at(&self, interner: &I, index: usize) -> &$elem { + &self.as_slice(interner)[index] + } + + /// Create a sequence from a single element. + pub fn from1(interner: &I, element: impl CastTo<$elem>) -> Self { + Self::from_iter(interner, Some(element)) + } + + /// Create an empty sequence. + pub fn empty(interner: &I) -> Self { + Self::from_iter(interner, None::<$elem>) + } + + /// Check whether this is an empty sequence. + pub fn is_empty(&self, interner: &I) -> bool { + self.as_slice(interner).is_empty() + } + + /// Get an iterator over the elements of the sequence. + pub fn iter(&self, interner: &I) -> std::slice::Iter<'_, $elem> { + self.as_slice(interner).iter() + } + + /// Get the length of the sequence. + pub fn len(&self, interner: &I) -> usize { + self.as_slice(interner).len() + } + } + }; +} + +interned_slice!( + QuantifiedWhereClauses, + quantified_where_clauses_data => QuantifiedWhereClause, + intern_quantified_where_clauses => InternedQuantifiedWhereClauses +); + +interned_slice!( + ProgramClauses, + program_clauses_data => ProgramClause, + intern_program_clauses => InternedProgramClauses +); + +interned_slice!( + VariableKinds, + variable_kinds_data => VariableKind, + intern_generic_arg_kinds => InternedVariableKinds +); + +interned_slice!( + CanonicalVarKinds, + canonical_var_kinds_data => CanonicalVarKind, + intern_canonical_var_kinds => InternedCanonicalVarKinds +); + +interned_slice!(Goals, goals_data => Goal, intern_goals => InternedGoals); + +interned_slice!( + Constraints, + constraints_data => InEnvironment>, + intern_constraints => InternedConstraints +); + +interned_slice!( + Substitution, + substitution_data => GenericArg, + intern_substitution => InternedSubstitution +); + /// Combines a substitution (`subst`) with a set of region constraints /// (`constraints`). This represents the result of a query; the /// substitution stores the values for the query's unknown variables, @@ -2461,13 +2673,26 @@ impl<'i, I: Interner> Folder<'i, I> for &SubstFolder<'i, I> { /// additionally be solved. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub struct ConstrainedSubst { - pub subst: Substitution, /* NB: The `is_trivial` routine relies on the fact that `subst` is folded first. */ - pub constraints: Vec>>, + /// The substitution that is being constrained. + /// + /// NB: The `is_trivial` routine relies on the fact that `subst` is folded first. + pub subst: Substitution, + + /// Region constraints that constrain the substitution. + pub constraints: Constraints, } +/// The resulting substitution after solving a goal. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub struct AnswerSubst { - pub subst: Substitution, /* NB: The `is_trivial` routine relies on the fact that `subst` is folded first. */ - pub constraints: Vec>>, + /// The substitution result. + /// + /// NB: The `is_trivial` routine relies on the fact that `subst` is folded first. + pub subst: Substitution, + + /// List of constraints that are part of the answer. + pub constraints: Constraints, + + /// Delayed subgoals, used when the solver answered with an (incomplete) `Answer` (instead of a `CompleteAnswer`). pub delayed_subgoals: Vec>>, } diff --git a/vendor/chalk-ir-0.14.0/src/visit.rs b/vendor/chalk-ir-0.25.0/src/visit.rs similarity index 97% rename from vendor/chalk-ir-0.14.0/src/visit.rs rename to vendor/chalk-ir-0.25.0/src/visit.rs index 0568f3db8f..7612807dd6 100644 --- a/vendor/chalk-ir-0.14.0/src/visit.rs +++ b/vendor/chalk-ir-0.25.0/src/visit.rs @@ -17,12 +17,15 @@ pub use visitors::VisitExt; /// are doing. A common choice is `FindAny`, which indicates that the visitor /// is searching for something and that the visitor should stop once it is found. pub trait VisitResult: Sized { + /// Creates a new visitor result. fn new() -> Self; /// Returns true if this result is "complete" and we can stop visiting any /// further parts of the term. This is used by `FindAny`, for example, to /// stop the search after a match has been found. fn return_early(&self) -> bool; + + /// Combines two visitor results. fn combine(self, other: Self) -> Self; /// Convenience helper for use in writing `Visitor` impls. Returns `self` @@ -50,7 +53,7 @@ pub trait VisitResult: Sized { /// Unit type for a visitor indicates a "side-effecting" visitor that /// should visit an entire term. impl VisitResult for () { - fn new() -> () {} + fn new() -> Self {} fn return_early(&self) -> bool { false @@ -71,6 +74,7 @@ pub trait Visitor<'i, I: Interner> where I: 'i, { + /// The type of result that this visitor produces. type Result: VisitResult; /// Creates a `dyn` value from this visitor. Unfortunately, this @@ -124,6 +128,7 @@ where goal.super_visit_with(self.as_dyn(), outer_binder) } + /// Invoked for each domain goal. fn visit_domain_goal( &mut self, domain_goal: &DomainGoal, @@ -172,6 +177,7 @@ where } } + /// Invoked for each where clause. fn visit_where_clause( &mut self, where_clause: &WhereClause, @@ -201,6 +207,7 @@ where } } + /// Gets the visitor's interner. fn interner(&self) -> &'i I; } @@ -225,6 +232,7 @@ pub trait Visit: Debug { /// `SuperVisit` trait captures the recursive behavior that visits all /// the contents of the type. pub trait SuperVisit: Visit { + /// Recursively visits the type contents. fn super_visit_with<'i, R: VisitResult>( &self, visitor: &mut dyn Visitor<'i, I, Result = R>, diff --git a/vendor/chalk-ir-0.14.0/src/visit/binder_impls.rs b/vendor/chalk-ir-0.25.0/src/visit/binder_impls.rs similarity index 87% rename from vendor/chalk-ir-0.14.0/src/visit/binder_impls.rs rename to vendor/chalk-ir-0.25.0/src/visit/binder_impls.rs index 58ab0871db..ab0bf559d7 100644 --- a/vendor/chalk-ir-0.14.0/src/visit/binder_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/visit/binder_impls.rs @@ -4,9 +4,9 @@ //! The more interesting impls of `Visit` remain in the `visit` module. use crate::interner::HasInterner; -use crate::{Binders, Canonical, DebruijnIndex, Fn, Interner, Visit, VisitResult, Visitor}; +use crate::{Binders, Canonical, DebruijnIndex, FnPointer, Interner, Visit, VisitResult, Visitor}; -impl Visit for Fn { +impl Visit for FnPointer { fn visit_with<'i, R: VisitResult>( &self, visitor: &mut dyn Visitor<'i, I, Result = R>, @@ -17,7 +17,7 @@ impl Visit for Fn { { let interner = visitor.interner(); self.substitution - .parameters(interner) + .as_slice(interner) .visit_with(visitor, outer_binder.shifted_in()) } } diff --git a/vendor/chalk-ir-0.14.0/src/visit/boring_impls.rs b/vendor/chalk-ir-0.25.0/src/visit/boring_impls.rs similarity index 90% rename from vendor/chalk-ir-0.14.0/src/visit/boring_impls.rs rename to vendor/chalk-ir-0.25.0/src/visit/boring_impls.rs index 34f10c79af..242844fc40 100644 --- a/vendor/chalk-ir-0.14.0/src/visit/boring_impls.rs +++ b/vendor/chalk-ir-0.25.0/src/visit/boring_impls.rs @@ -5,10 +5,10 @@ //! The more interesting impls of `Visit` remain in the `visit` module. use crate::{ - AdtId, AssocTypeId, ClausePriority, ClosureId, DebruijnIndex, FloatTy, FnDefId, GenericArg, - Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, ProgramClause, - ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Scalar, Substitution, SuperVisit, - TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor, + AdtId, AssocTypeId, ClausePriority, ClosureId, Constraints, DebruijnIndex, FloatTy, FnDefId, + GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, + ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Safety, Scalar, + Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor, }; use std::{marker::PhantomData, sync::Arc}; @@ -179,6 +179,7 @@ impl Visit for Goals { } } +#[doc(hidden)] #[macro_export] macro_rules! const_visit { ($t:ty) => { @@ -210,7 +211,9 @@ const_visit!(UintTy); const_visit!(IntTy); const_visit!(FloatTy); const_visit!(Mutability); +const_visit!(Safety); +#[doc(hidden)] #[macro_export] macro_rules! id_visit { ($t:ident) => { @@ -267,6 +270,21 @@ impl Visit for ProgramClauses { } } +impl Visit for Constraints { + fn visit_with<'i, R: VisitResult>( + &self, + visitor: &mut dyn Visitor<'i, I, Result = R>, + outer_binder: DebruijnIndex, + ) -> R + where + I: 'i, + { + let interner = visitor.interner(); + + visit_iter(self.iter(interner), visitor, outer_binder) + } +} + impl Visit for QuantifiedWhereClauses { fn visit_with<'i, R: VisitResult>( &self, diff --git a/vendor/chalk-ir-0.14.0/src/visit/visitors.rs b/vendor/chalk-ir-0.25.0/src/visit/visitors.rs similarity index 84% rename from vendor/chalk-ir-0.14.0/src/visit/visitors.rs rename to vendor/chalk-ir-0.25.0/src/visit/visitors.rs index 8eb37b920b..892280eb1a 100644 --- a/vendor/chalk-ir-0.14.0/src/visit/visitors.rs +++ b/vendor/chalk-ir-0.25.0/src/visit/visitors.rs @@ -1,6 +1,10 @@ +//! Visitor helpers + use crate::{BoundVar, DebruijnIndex, Interner, Visit, VisitResult, Visitor}; +/// Visitor extensions. pub trait VisitExt: Visit { + /// Check whether there are free (non-bound) variables. fn has_free_vars(&self, interner: &I) -> bool { self.visit_with( &mut FindFreeVarsVisitor { interner }, @@ -12,14 +16,18 @@ pub trait VisitExt: Visit { impl VisitExt for T where T: Visit {} +/// Helper visitor for finding a specific value. #[derive(Clone, Copy, Debug, PartialEq, Eq)] +#[allow(missing_docs)] pub struct FindAny { pub found: bool, } impl FindAny { + /// Visitor has found the value. pub const FOUND: FindAny = FindAny { found: true }; + /// Checks whether the value has been found. pub fn to_bool(&self) -> bool { self.found } diff --git a/vendor/chalk-ir-0.14.0/src/zip.rs b/vendor/chalk-ir-0.25.0/src/zip.rs similarity index 94% rename from vendor/chalk-ir-0.14.0/src/zip.rs rename to vendor/chalk-ir-0.25.0/src/zip.rs index e7dc072800..ad439058a6 100644 --- a/vendor/chalk-ir-0.14.0/src/zip.rs +++ b/vendor/chalk-ir-0.25.0/src/zip.rs @@ -1,3 +1,5 @@ +//! Traits for "zipping" types, walking through two structures and checking that they match. + use crate::fold::Fold; use crate::*; use std::fmt::Debug; @@ -78,6 +80,7 @@ pub trait Zip: Debug where I: Interner, { + /// Uses the zipper to walk through two values, ensuring that they match. fn zip_with<'i, Z: Zipper<'i, I>>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> where I: 'i; @@ -267,6 +270,17 @@ impl Zip for ProgramClauses { } } +impl Zip for Constraints { + fn zip_with<'i, Z: Zipper<'i, I>>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> + where + I: 'i, + { + let interner = zipper.interner(); + Zip::zip_with(zipper, a.as_slice(interner), b.as_slice(interner))?; + Ok(()) + } +} + impl Zip for QuantifiedWhereClauses { fn zip_with<'i, Z: Zipper<'i, I>>(zipper: &mut Z, a: &Self, b: &Self) -> Fallible<()> where @@ -284,7 +298,7 @@ impl Zip for Substitution { I: 'i, { let interner = zipper.interner(); - Zip::zip_with(zipper, a.parameters(interner), b.parameters(interner)) + Zip::zip_with(zipper, a.as_slice(interner), b.as_slice(interner)) } } diff --git a/vendor/chalk-ir/.cargo-checksum.json b/vendor/chalk-ir/.cargo-checksum.json index 59db159d38..ef105669ae 100644 --- a/vendor/chalk-ir/.cargo-checksum.json +++ b/vendor/chalk-ir/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"051d24338c250ec6f390e5990e2691e110faa9484cc4957cb4229c9b522668e5","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"6e8bc7ebd3d94a27c561499a15de2cc5d9501e6bf387b62e76772d7cb7ecd0a2","src/could_match.rs":"46507c372868dcd51c4a04dcd4bcc4e6e61f0fa537d980b3dc615be52c98171b","src/debug.rs":"e130908297f47a08ec7ed0d36131e5bd8534434fb9d30881da4fcbd714d2d95a","src/fold.rs":"2d1f8fd0f8603dad54428ba9d93f281d478c380dfca9d755e96a362d3be9d470","src/fold/binder_impls.rs":"0cb4f2b40b34e5f80e5a5946289959431ac5c22f6ec87d30e9b2f7d4122d0fd0","src/fold/boring_impls.rs":"f83bddd6061e0d035fb37a250013c2ce55fb624d0a3ee63d5e1840bb8ebd8227","src/fold/shift.rs":"134caa51a84399e7bd31471e3a31f7ca05b91c99cb1f06132f1d42151328e5d3","src/fold/subst.rs":"4db018d2b5d447420ae4b9269de36f3ce816de201b4eeaf30d54ae5c3b5db7cd","src/interner.rs":"993b347617e2a6dc8f34d966e4f140a082dfadc946d52e1e4064311db07f4b65","src/lib.rs":"808cf7a58fc04b89fd10eac36125dd9356a00bc33cc6570d81d63796a1572497","src/visit.rs":"22e5230a397b3d5ec1c2002cdd03dc6c8adb3d5497e83534d93b9ff72875896c","src/visit/binder_impls.rs":"4e544fc24158c8a1c84237ed21b83673225f87876ee78eeda83b41bc2b65f408","src/visit/boring_impls.rs":"f9904bf7200af8dc55e01ff24c238406596b7e7353ad7361d074ec5af4a4d013","src/visit/visitors.rs":"5f429cc2f9a94f918258c8df776a0fec15cffaff4dd7b20019a2ad6c091a1ddd","src/zip.rs":"f2b25e7221e32b5176adc95220b338d079555fae2949e12bf197e28dd8b24c2f"},"package":"bb332abfcb015b148c6fbab39b1d13282745b0f7f312019dd8e138f5f3f0855d"} \ No newline at end of file +{"files":{"Cargo.toml":"0e7c7b33a3d6e048149a5d007a9e4dad3ab002b69a024e8cef30dae69d5df697","README.md":"64cba0ddf3e9b5c168fbe069f1a84c401ce0b33e765ea49acb1345d0923afe8d","src/cast.rs":"6e8bc7ebd3d94a27c561499a15de2cc5d9501e6bf387b62e76772d7cb7ecd0a2","src/could_match.rs":"46507c372868dcd51c4a04dcd4bcc4e6e61f0fa537d980b3dc615be52c98171b","src/debug.rs":"9f2107f33d1fb6b8e941d01445829d09882bd06512bd3f48a24aae6b8d3c3fa7","src/fold.rs":"2d1f8fd0f8603dad54428ba9d93f281d478c380dfca9d755e96a362d3be9d470","src/fold/binder_impls.rs":"31c5fe338fb31fdee44730902f6dc3ce7f091d57bddd24c13e14bea14443a167","src/fold/boring_impls.rs":"3acd9e4c79d57864113d8f87c93e80c4ea734c1679443699c7f5a873980469ac","src/fold/shift.rs":"134caa51a84399e7bd31471e3a31f7ca05b91c99cb1f06132f1d42151328e5d3","src/fold/subst.rs":"4db018d2b5d447420ae4b9269de36f3ce816de201b4eeaf30d54ae5c3b5db7cd","src/interner.rs":"235f430a7b7a1885a073d154ecae18fa9b1b41543df24a89781ba6d0d4d3436b","src/lib.rs":"cac3d9e4931702212aa2b6d99cdfd26ab696fd8ef7a5264ba5e9819303652c62","src/visit.rs":"22e5230a397b3d5ec1c2002cdd03dc6c8adb3d5497e83534d93b9ff72875896c","src/visit/binder_impls.rs":"4e544fc24158c8a1c84237ed21b83673225f87876ee78eeda83b41bc2b65f408","src/visit/boring_impls.rs":"6e8974e191211a16ec4d7f38a4cba4db7e27aaec30ce4979fa55406e1d5214d4","src/visit/visitors.rs":"5f429cc2f9a94f918258c8df776a0fec15cffaff4dd7b20019a2ad6c091a1ddd","src/zip.rs":"f2b25e7221e32b5176adc95220b338d079555fae2949e12bf197e28dd8b24c2f"},"package":"03a4050029ecb2b5a1ff3bfc64c39279179b294821ec2e8891a4a5c6e3a08db0"} \ No newline at end of file diff --git a/vendor/chalk-ir/Cargo.toml b/vendor/chalk-ir/Cargo.toml index 8ea73ccf66..5b37c9c64d 100644 --- a/vendor/chalk-ir/Cargo.toml +++ b/vendor/chalk-ir/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-ir" -version = "0.23.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Chalk's internal representation of types, goals, and clauses" readme = "README.md" @@ -21,7 +21,7 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.23.0" +version = "=0.29.0" [dependencies.lazy_static] version = "1.4.0" diff --git a/vendor/chalk-ir/src/debug.rs b/vendor/chalk-ir/src/debug.rs index 7c2f21853c..4d77dea862 100644 --- a/vendor/chalk-ir/src/debug.rs +++ b/vendor/chalk-ir/src/debug.rs @@ -35,6 +35,13 @@ impl Debug for ClosureId { } } +impl Debug for ForeignDefId { + fn fmt(&self, fmt: &mut Formatter<'_>) -> std::fmt::Result { + I::debug_foreign_def_id(*self, fmt) + .unwrap_or_else(|| write!(fmt, "ForeignDefId({:?})", self.0)) + } +} + impl Debug for Ty { fn fmt(&self, fmt: &mut Formatter<'_>) -> Result<(), Error> { I::debug_ty(self, fmt).unwrap_or_else(|| write!(fmt, "{:?}", self.interned)) @@ -179,11 +186,26 @@ impl Debug for TypeName { TypeName::OpaqueType(opaque_ty) => write!(fmt, "!{:?}", opaque_ty), TypeName::Slice => write!(fmt, "{{slice}}"), TypeName::FnDef(fn_def) => write!(fmt, "{:?}", fn_def), - TypeName::Raw(mutability) => write!(fmt, "{:?}", mutability), - TypeName::Ref(mutability) => write!(fmt, "{:?}", mutability), + TypeName::Ref(mutability) => write!( + fmt, + "{}", + match mutability { + Mutability::Mut => "{{&mut}}", + Mutability::Not => "{{&}}", + } + ), + TypeName::Raw(mutability) => write!( + fmt, + "{}", + match mutability { + Mutability::Mut => "{{*mut}}", + Mutability::Not => "{{*const}}", + } + ), TypeName::Never => write!(fmt, "Never"), TypeName::Array => write!(fmt, "{{array}}"), TypeName::Closure(id) => write!(fmt, "{{closure:{:?}}}", id), + TypeName::Foreign(foreign_ty) => write!(fmt, "{:?}", foreign_ty), TypeName::Error => write!(fmt, "{{error}}"), } } @@ -238,14 +260,12 @@ impl Debug for FnPointer { let FnPointer { num_binders, substitution, - abi, - safety, - variadic: _, + sig, } = self; write!( fmt, "for<{}> {:?} {:?} {:?}", - num_binders, safety, abi, substitution + num_binders, sig.safety, sig.abi, substitution ) } } diff --git a/vendor/chalk-ir/src/fold/binder_impls.rs b/vendor/chalk-ir/src/fold/binder_impls.rs index 1f751f16ca..dc290e9224 100644 --- a/vendor/chalk-ir/src/fold/binder_impls.rs +++ b/vendor/chalk-ir/src/fold/binder_impls.rs @@ -20,16 +20,16 @@ impl> Fold for FnPointer { let FnPointer { num_binders, substitution, - abi, - safety, - variadic, + sig, } = self; Ok(FnPointer { num_binders: *num_binders, substitution: substitution.fold_with(folder, outer_binder.shifted_in())?, - abi: TI::transfer_abi(*abi), - safety: *safety, - variadic: *variadic, + sig: FnSig { + abi: TI::transfer_abi(sig.abi), + safety: sig.safety, + variadic: sig.variadic, + }, }) } } diff --git a/vendor/chalk-ir/src/fold/boring_impls.rs b/vendor/chalk-ir/src/fold/boring_impls.rs index 9922315a39..9d6f835e1d 100644 --- a/vendor/chalk-ir/src/fold/boring_impls.rs +++ b/vendor/chalk-ir/src/fold/boring_impls.rs @@ -303,6 +303,7 @@ id_fold!(AssocTypeId); id_fold!(OpaqueTyId); id_fold!(FnDefId); id_fold!(ClosureId); +id_fold!(ForeignDefId); impl> SuperFold for ProgramClauseData { fn super_fold_with<'i>( diff --git a/vendor/chalk-ir/src/interner.rs b/vendor/chalk-ir/src/interner.rs index c996059d97..b4da73c53d 100644 --- a/vendor/chalk-ir/src/interner.rs +++ b/vendor/chalk-ir/src/interner.rs @@ -9,6 +9,7 @@ use crate::ClosureId; use crate::Constraint; use crate::Constraints; use crate::FnDefId; +use crate::ForeignDefId; use crate::GenericArg; use crate::GenericArgData; use crate::Goal; @@ -245,6 +246,16 @@ pub trait Interner: Debug + Copy + Eq + Ord + Hash { None } + /// Prints the debug representation of a foreign-def-id. + /// Returns `None` to fallback to the default debug output. + #[allow(unused_variables)] + fn debug_foreign_def_id( + foreign_def_id: ForeignDefId, + fmt: &mut fmt::Formatter<'_>, + ) -> Option { + None + } + /// Prints the debug representation of an alias. /// Returns `None` to fallback to the default debug output. #[allow(unused_variables)] @@ -715,6 +726,16 @@ where type Interner = I; } +impl HasInterner for (A, B, C) +where + A: HasInterner, + B: HasInterner, + C: HasInterner, + I: Interner, +{ + type Interner = I; +} + impl<'a, T: HasInterner> HasInterner for std::slice::Iter<'a, T> { type Interner = T::Interner; } diff --git a/vendor/chalk-ir/src/lib.rs b/vendor/chalk-ir/src/lib.rs index 3a1cad53f3..2464b1dc24 100644 --- a/vendor/chalk-ir/src/lib.rs +++ b/vendor/chalk-ir/src/lib.rs @@ -254,6 +254,9 @@ pub enum TypeName { /// A closure. Closure(ClosureId), + /// foreign types + Foreign(ForeignDefId), + /// This can be used to represent an error, e.g. during name resolution of a type. /// Chalk itself will not produce this, just pass it through when given. Error, @@ -363,6 +366,10 @@ pub struct FnDefId(pub I::DefId); #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct ClosureId(pub I::DefId); +/// Id for foreign types. +#[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct ForeignDefId(pub I::DefId); + impl_debugs!(ImplId, ClauseId); /// A Rust type. The actual type data is stored in `TyData`. @@ -470,6 +477,17 @@ impl Ty { } } + /// Returns `Some(adt_id)` if this is an ADT, `None` otherwise + pub fn adt_id(&self, interner: &I) -> Option> { + match self.data(interner) { + TyData::Apply(ApplicationTy { + name: TypeName::Adt(adt_id), + .. + }) => Some(*adt_id), + _ => None, + } + } + /// True if this type contains "bound" types/lifetimes, and hence /// needs to be shifted across binders. This is a very inefficient /// check, intended only for debug assertions, because I am lazy. @@ -865,15 +883,22 @@ impl InferenceVar { } } +/// A function signature. +#[derive(Clone, Copy, PartialEq, Eq, Hash, HasInterner, Debug)] +#[allow(missing_docs)] +pub struct FnSig { + pub abi: I::FnAbi, + pub safety: Safety, + pub variadic: bool, +} + /// for<'a...'z> X -- all binders are instantiated at once, /// and we use deBruijn indices within `self.ty` #[derive(Clone, PartialEq, Eq, Hash, HasInterner)] #[allow(missing_docs)] pub struct FnPointer { pub num_binders: usize, - pub abi: I::FnAbi, - pub safety: Safety, - pub variadic: bool, + pub sig: FnSig, pub substitution: Substitution, } diff --git a/vendor/chalk-ir/src/visit/boring_impls.rs b/vendor/chalk-ir/src/visit/boring_impls.rs index 242844fc40..43e4cf1652 100644 --- a/vendor/chalk-ir/src/visit/boring_impls.rs +++ b/vendor/chalk-ir/src/visit/boring_impls.rs @@ -6,9 +6,10 @@ use crate::{ AdtId, AssocTypeId, ClausePriority, ClosureId, Constraints, DebruijnIndex, FloatTy, FnDefId, - GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, PlaceholderIndex, - ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, Safety, Scalar, - Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, Visitor, + ForeignDefId, GenericArg, Goals, ImplId, IntTy, Interner, Mutability, OpaqueTyId, + PlaceholderIndex, ProgramClause, ProgramClauses, QuantifiedWhereClauses, QuantifierKind, + Safety, Scalar, Substitution, SuperVisit, TraitId, UintTy, UniverseIndex, Visit, VisitResult, + Visitor, }; use std::{marker::PhantomData, sync::Arc}; @@ -239,6 +240,7 @@ id_visit!(OpaqueTyId); id_visit!(AssocTypeId); id_visit!(FnDefId); id_visit!(ClosureId); +id_visit!(ForeignDefId); impl SuperVisit for ProgramClause { fn super_visit_with<'i, R: VisitResult>( diff --git a/vendor/chalk-recursive/.cargo-checksum.json b/vendor/chalk-recursive/.cargo-checksum.json index 05c3993daa..fb0363492e 100644 --- a/vendor/chalk-recursive/.cargo-checksum.json +++ b/vendor/chalk-recursive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d36cc5e58b884205292bce50b222d520a4ed021e71cdc794dce26731f1553e5a","README.md":"2742a242541363c8a1ee50ef908c63d9b940d8c75c77f941a74afb51654c22c0","src/combine.rs":"b8addb86955f08265dc9d3664b51b8acd80b45c48456a8e99aa18dc2495576f8","src/fulfill.rs":"7f7555597cb76523e115415f3f9c3d144284ba826faaee4ac90cb76463cf2c92","src/lib.rs":"30c9772443b0c98a0292e4b9e1f3675d5bd6b459f6f150a9f2614e950cb559b0","src/recursive.rs":"5d3e77da4131ccd853c2587f82557ce48700085853b5c041f4b157b2dce5d969","src/search_graph.rs":"d123fc1fbb06c20284fa9bd1ee57f32dc33de5a8adebc21bf515e13736a44402","src/solve.rs":"bfbbe4cddce519ac7848f431ccb37dbc3add9f6d2b90c309c0b778097c5d61e3","src/stack.rs":"babcaae992f46febbb86997627f17f620cd926d244b7d48b0e7a53856e9fd73f"},"package":"e7c7673f10c5fa1acf7fa07d4f4c5917cbcf161ed3a952d14530c79950de32d2"} \ No newline at end of file +{"files":{"Cargo.toml":"9559d15a01a6154cf689e58c2e3d489fca15daf5218a2b40140968be80880e56","README.md":"2742a242541363c8a1ee50ef908c63d9b940d8c75c77f941a74afb51654c22c0","src/combine.rs":"b8addb86955f08265dc9d3664b51b8acd80b45c48456a8e99aa18dc2495576f8","src/fulfill.rs":"69d0ac7b256f85a3a8db7f170f7a075f02c486dc713a93973ee535b72f035896","src/lib.rs":"cd7ed2dda48bbeb1a4d6ce97ec8c2d2b0b3b393f5dced9110ab89c37ed06d735","src/recursive.rs":"5d3e77da4131ccd853c2587f82557ce48700085853b5c041f4b157b2dce5d969","src/search_graph.rs":"d123fc1fbb06c20284fa9bd1ee57f32dc33de5a8adebc21bf515e13736a44402","src/solve.rs":"bfbbe4cddce519ac7848f431ccb37dbc3add9f6d2b90c309c0b778097c5d61e3","src/stack.rs":"babcaae992f46febbb86997627f17f620cd926d244b7d48b0e7a53856e9fd73f"},"package":"5130de3065e3cdfd2ab6d7d70b02b917bafbc096f270c9a643c23da249053606"} \ No newline at end of file diff --git a/vendor/chalk-recursive/Cargo.toml b/vendor/chalk-recursive/Cargo.toml index 68704e64c6..f2cf6f8ee8 100644 --- a/vendor/chalk-recursive/Cargo.toml +++ b/vendor/chalk-recursive/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-recursive" -version = "0.23.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Recursive solver for the Chalk project" readme = "README.md" @@ -21,13 +21,13 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.23.0" +version = "=0.25.0" [dependencies.chalk-ir] -version = "=0.23.0" +version = "=0.25.0" [dependencies.chalk-solve] -version = "=0.23.0" +version = "=0.25.0" [dependencies.rustc-hash] version = "1.1.0" diff --git a/vendor/chalk-recursive/src/fulfill.rs b/vendor/chalk-recursive/src/fulfill.rs index 63d597923f..b2cf64cf1c 100644 --- a/vendor/chalk-recursive/src/fulfill.rs +++ b/vendor/chalk-recursive/src/fulfill.rs @@ -447,9 +447,17 @@ impl<'s, I: Interner, Solver: SolveDatabase, Infer: RecursiveInferenceTable Solution { } /// Determine whether this solution contains type information that *must* - /// hold. - pub(crate) fn has_definite(&self) -> bool { - match *self { - Solution::Unique(_) => true, - Solution::Ambig(Guidance::Definite(_)) => true, - _ => false, + /// hold, and returns the subst in that case. + pub(crate) fn definite_subst(&self, interner: &I) -> Option>> { + match self { + Solution::Unique(constrained) => Some(constrained.clone()), + Solution::Ambig(Guidance::Definite(canonical)) => { + let value = ConstrainedSubst { + subst: canonical.value.clone(), + constraints: Constraints::empty(interner), + }; + Some(Canonical { + value, + binders: canonical.binders.clone(), + }) + } + _ => None, } } diff --git a/vendor/chalk-solve-0.14.0/.cargo-checksum.json b/vendor/chalk-solve-0.14.0/.cargo-checksum.json deleted file mode 100644 index 95b7eac8c0..0000000000 --- a/vendor/chalk-solve-0.14.0/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"aab8c2b4711cf8d263ee626158e7ce046ead9fc940ddafd61cb3edea9312704c","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"68b7e9aa192744f9907bca52da3282ef7ef321c6674cf9627f1ab457b34eb0af","src/clauses/builder.rs":"0807ccb0313729ebaa16b8ed65e6853ac121c0a1eff338ccdef8d8945daa6aad","src/clauses/builtin_traits.rs":"2001fee54cc892b72745d7a51d08a0bc243d0ab14306d7458ef797e60f7844cd","src/clauses/builtin_traits/clone.rs":"e07279b49184e6e3636e3d124cb0470270c96d9e7305a2b560f8206feabf3c02","src/clauses/builtin_traits/copy.rs":"7ad5332f0891ec0b5c89c67006085955bdbb67098d26076ee47f2aa70999804c","src/clauses/builtin_traits/fn_family.rs":"c9bcf132f5509c52695639263384d94470e24554b766850b61b02597fa45a4f7","src/clauses/builtin_traits/sized.rs":"2d83af31a481e97c62ef22008319de7110cb6c1e4f3c5c71f515890018638e84","src/clauses/builtin_traits/unsize.rs":"95d7f75d25148f918dafd418384ef9df2b52f10bf76f0307b85ed31fc52acce7","src/clauses/dyn_ty.rs":"4359c991e85a622f713defa3a21b31f2df94d0fab9b3f35a4fcd406ad1fc63d6","src/clauses/env_elaborator.rs":"b5c54aa5747602deaf524d88c3323d1ab470f939baca0622188ad9edd025f2a9","src/clauses/generalize.rs":"1bea574a507b7499f8a5dae20746ca46cb7c38554edff215273575dd19410a96","src/clauses/program_clauses.rs":"ff77edf1f793a4139399a486f0191cf28b983bff9fe4c3b866d40abc4189fc3a","src/coherence.rs":"7ed42d105871abe22562955e8fcb788738bc378fdf20f705e6d15bff581d1119","src/coherence/orphan.rs":"ad607bd620a883c135092e75636545738da21c0526dcb72a1a8bc9474828a715","src/coherence/solve.rs":"bf4ddefb0ebb79ac13d6d319ae5a981c057a2687a75f19a68fc6fdf582e1e33f","src/coinductive_goal.rs":"bbef8deeb1c423b0d2215ecb287c96fceb22f6d11da31502b995e4a6aa9391f4","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"f5a2f0883165faf173a031f8576196abe88316596196a6b1bcf928dfe0c66089","src/infer.rs":"12143d3ed9324ccdb86acc5edaa897c2a7226396b291a77dec168a7a4856d327","src/infer/canonicalize.rs":"e09c7e82741fe988cec330ffbc75dcf8877e8f766bffd8e0b2d62ba61ae15632","src/infer/instantiate.rs":"b2b25da7840dc3a1cb6505f6523d392c430ba00feed331f774ad8d57959e90a3","src/infer/invert.rs":"c155fc04db1206a8212a9a55f68a1b33f5210c9c5d3523784c91e055a1b62e91","src/infer/normalize_deep.rs":"d70f351944c7d0982e5a0be4ef62085a5944f45be806cc71abff97c9fb56fa9f","src/infer/test.rs":"30cc313ab07250c3ffe1fcaa72ece6b61b4c7eeffb24d62ef6b4254eb12e65bb","src/infer/ucanonicalize.rs":"e9390b67b0cb3684a330d14cc8820edddd5cb6b57e301d9f1c52d97dc9fd5a02","src/infer/unify.rs":"3c54b32b0dd59340556f3e52417b95d30a93bf3f1fea3043a326150015960902","src/infer/var.rs":"4653b7ff3022e689c147c546c36b6f112e2b5bbc9b6dd266d2931fc0b985b813","src/lib.rs":"873280d9858e824f73c4fcb58ac2ddac066032615518802433c3b8f4a663fe80","src/recursive.rs":"b905871086c2e1969f5ad27a1a1fc7229c81e826841a62eb8ceb3436c7a7cc10","src/recursive/combine.rs":"c40b4e26adb6f3edbdcf129c8b2843a7342c47d6a84bdfcb866ca90e037bfc48","src/recursive/fulfill.rs":"0205074c731d1c0ea9e6fa6a63516429557edf2ed2a1a2924181f8b2230bed9d","src/recursive/lib.rs":"862e086f9e1815fa2b56583ac3c659752cf5b57515f1d35d2e5a276a5bc25457","src/recursive/search_graph.rs":"817b4b56c75e4202e1868891aa36504c8d9d67b7e176c1a681370d9af5037e95","src/recursive/solve.rs":"9856cbde2805c73fdf31c5f7838bafc40b3e6079a73d689f06b524e56daaacaf","src/recursive/stack.rs":"babcaae992f46febbb86997627f17f620cd926d244b7d48b0e7a53856e9fd73f","src/rust_ir.rs":"97bbf72539d0985c2de5f0e2efe01cfa8b42c12ce8a847437fdf790e2f9d0d53","src/solve.rs":"74249d77c50336ca7cfd9b3777b52ecb5adc52f819ca60f63a4868ade0d6ebf2","src/solve/slg.rs":"973e3111db82f35efcede1b53d1428dfaa0621e1ce2a2e0adcfd95e51daf9776","src/solve/slg/aggregate.rs":"f4d29294bd9bf66f7e6cdd6ec96979e741464ac44acad06c717c1d3547b520e4","src/solve/slg/resolvent.rs":"0c10b7babe7367bd5ced2c3c7e3a7c8ebd0c186103439773ae6a2b3edb5eed01","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"4762189065a55fc58434e2adde2f2a510ff2275f273b8a9ba7f7b7d69a79ef4f","src/split.rs":"7df598067f5ff2b1f1aa42e154533471554041d5933ccac0c38d485365960665","src/test_macros.rs":"f43f44c44c68b7192bdf72a70de55e26e2ee608b7477a7c0ee6920641eab3810","src/wf.rs":"28ff03c9b3fd0a1ff13dc894f348db8acd99377238017fc866e9ffaba8dae6aa"},"package":"5b9fd4102807b7ebe8fb034fa0f488c5656e1966d3261b558b81a08d519cdb29"} \ No newline at end of file diff --git a/vendor/chalk-solve-0.14.0/src/recursive.rs b/vendor/chalk-solve-0.14.0/src/recursive.rs deleted file mode 100644 index 46848edba8..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive.rs +++ /dev/null @@ -1,279 +0,0 @@ -mod combine; -mod fulfill; -pub mod lib; -mod search_graph; -mod solve; -mod stack; - -use self::lib::{Minimums, Solution, UCanonicalGoal}; -use self::search_graph::{DepthFirstNumber, SearchGraph}; -use self::solve::{SolveDatabase, SolveIteration}; -use self::stack::{Stack, StackDepth}; -use crate::{coinductive_goal::IsCoinductive, RustIrDatabase}; -use chalk_ir::interner::Interner; -use chalk_ir::{Canonical, ConstrainedSubst, Fallible}; -use rustc_hash::FxHashMap; -use tracing::{debug, info, instrument}; - -pub(crate) struct RecursiveContext { - stack: Stack, - - /// The "search graph" stores "in-progress results" that are still being - /// solved. - search_graph: SearchGraph, - - /// The "cache" stores results for goals that we have completely solved. - /// Things are added to the cache when we have completely processed their - /// result. - cache: FxHashMap, Fallible>>, - - caching_enabled: bool, -} - -/// A Solver is the basic context in which you can propose goals for a given -/// program. **All questions posed to the solver are in canonical, closed form, -/// so that each question is answered with effectively a "clean slate"**. This -/// allows for better caching, and simplifies management of the inference -/// context. -pub(crate) struct Solver<'me, I: Interner> { - program: &'me dyn RustIrDatabase, - context: &'me mut RecursiveContext, -} - -/// An extension trait for merging `Result`s -trait MergeWith { - fn merge_with(self, other: Self, f: F) -> Self - where - F: FnOnce(T, T) -> T; -} - -impl MergeWith for Fallible { - fn merge_with(self: Fallible, other: Fallible, f: F) -> Fallible - where - F: FnOnce(T, T) -> T, - { - match (self, other) { - (Err(_), Ok(v)) | (Ok(v), Err(_)) => Ok(v), - (Ok(v1), Ok(v2)) => Ok(f(v1, v2)), - (Err(_), Err(e)) => Err(e), - } - } -} - -impl RecursiveContext { - pub(crate) fn new(overflow_depth: usize, caching_enabled: bool) -> Self { - RecursiveContext { - stack: Stack::new(overflow_depth), - search_graph: SearchGraph::new(), - cache: FxHashMap::default(), - caching_enabled, - } - } - - pub(crate) fn solver<'me>( - &'me mut self, - program: &'me dyn RustIrDatabase, - ) -> Solver<'me, I> { - Solver { - program, - context: self, - } - } -} - -impl<'me, I: Interner> Solver<'me, I> { - /// Solves a canonical goal. The substitution returned in the - /// solution will be for the fully decomposed goal. For example, given the - /// program - /// - /// ```ignore - /// struct u8 { } - /// struct SomeType { } - /// trait Foo { } - /// impl Foo for SomeType { } - /// ``` - /// - /// and the goal `exists { forall { SomeType: Foo } - /// }`, `into_peeled_goal` can be used to create a canonical goal - /// `SomeType: Foo`. This function will then return a - /// solution with the substitution `?0 := u8`. - pub(crate) fn solve_root_goal( - &mut self, - canonical_goal: &UCanonicalGoal, - ) -> Fallible> { - debug!("solve_root_goal(canonical_goal={:?})", canonical_goal); - assert!(self.context.stack.is_empty()); - let minimums = &mut Minimums::new(); - self.solve_goal(canonical_goal.clone(), minimums) - } - - #[instrument(level = "debug", skip(self))] - fn solve_new_subgoal( - &mut self, - canonical_goal: UCanonicalGoal, - depth: StackDepth, - dfn: DepthFirstNumber, - ) -> Minimums { - // We start with `answer = None` and try to solve the goal. At the end of the iteration, - // `answer` will be updated with the result of the solving process. If we detect a cycle - // during the solving process, we cache `answer` and try to solve the goal again. We repeat - // until we reach a fixed point for `answer`. - // Considering the partial order: - // - None < Some(Unique) < Some(Ambiguous) - // - None < Some(CannotProve) - // the function which maps the loop iteration to `answer` is a nondecreasing function - // so this function will eventually be constant and the loop terminates. - loop { - let minimums = &mut Minimums::new(); - let (current_answer, current_prio) = self.solve_iteration(&canonical_goal, minimums); - - debug!( - "solve_new_subgoal: loop iteration result = {:?} with minimums {:?}", - current_answer, minimums - ); - - if !self.context.stack[depth].read_and_reset_cycle_flag() { - // None of our subgoals depended on us directly. - // We can return. - self.context.search_graph[dfn].solution = current_answer; - self.context.search_graph[dfn].solution_priority = current_prio; - return *minimums; - } - - let old_answer = &self.context.search_graph[dfn].solution; - let old_prio = self.context.search_graph[dfn].solution_priority; - - let (current_answer, current_prio) = combine::with_priorities_for_goal( - self.program.interner(), - &canonical_goal.canonical.value.goal, - old_answer.clone(), - old_prio, - current_answer, - current_prio, - ); - - // Some of our subgoals depended on us. We need to re-run - // with the current answer. - if self.context.search_graph[dfn].solution == current_answer { - // Reached a fixed point. - return *minimums; - } - - let current_answer_is_ambig = match ¤t_answer { - Ok(s) => s.is_ambig(), - Err(_) => false, - }; - - self.context.search_graph[dfn].solution = current_answer; - self.context.search_graph[dfn].solution_priority = current_prio; - - // Subtle: if our current answer is ambiguous, we can just stop, and - // in fact we *must* -- otherwise, we sometimes fail to reach a - // fixed point. See `multiple_ambiguous_cycles` for more. - if current_answer_is_ambig { - return *minimums; - } - - // Otherwise: rollback the search tree and try again. - self.context.search_graph.rollback_to(dfn + 1); - } - } -} - -impl<'me, I: Interner> SolveDatabase for Solver<'me, I> { - /// Attempt to solve a goal that has been fully broken down into leaf form - /// and canonicalized. This is where the action really happens, and is the - /// place where we would perform caching in rustc (and may eventually do in Chalk). - #[instrument(level = "info", skip(self, minimums))] - fn solve_goal( - &mut self, - goal: UCanonicalGoal, - minimums: &mut Minimums, - ) -> Fallible> { - // First check the cache. - if let Some(value) = self.context.cache.get(&goal) { - debug!("solve_reduced_goal: cache hit, value={:?}", value); - return value.clone(); - } - - // Next, check if the goal is in the search tree already. - if let Some(dfn) = self.context.search_graph.lookup(&goal) { - // Check if this table is still on the stack. - if let Some(depth) = self.context.search_graph[dfn].stack_depth { - // Is this a coinductive goal? If so, that is success, - // so we can return normally. Note that this return is - // not tabled. - // - // XXX how does caching with coinduction work? - if self.context.stack.coinductive_cycle_from(depth) { - let value = ConstrainedSubst { - subst: goal.trivial_substitution(self.program.interner()), - constraints: vec![], - }; - debug!("applying coinductive semantics"); - return Ok(Solution::Unique(Canonical { - value, - binders: goal.canonical.binders, - })); - } - - self.context.stack[depth].flag_cycle(); - } - - minimums.update_from(self.context.search_graph[dfn].links); - - // Return the solution from the table. - let previous_solution = self.context.search_graph[dfn].solution.clone(); - let previous_solution_priority = self.context.search_graph[dfn].solution_priority; - info!( - "solve_goal: cycle detected, previous solution {:?} with prio {:?}", - previous_solution, previous_solution_priority - ); - previous_solution - } else { - // Otherwise, push the goal onto the stack and create a table. - // The initial result for this table is error. - let coinductive_goal = goal.is_coinductive(self.program); - let depth = self.context.stack.push(coinductive_goal); - let dfn = self.context.search_graph.insert(&goal, depth); - let subgoal_minimums = self.solve_new_subgoal(goal, depth, dfn); - self.context.search_graph[dfn].links = subgoal_minimums; - self.context.search_graph[dfn].stack_depth = None; - self.context.stack.pop(depth); - minimums.update_from(subgoal_minimums); - - // Read final result from table. - let result = self.context.search_graph[dfn].solution.clone(); - let priority = self.context.search_graph[dfn].solution_priority; - - // If processing this subgoal did not involve anything - // outside of its subtree, then we can promote it to the - // cache now. This is a sort of hack to alleviate the - // worst of the repeated work that we do during tabling. - if subgoal_minimums.positive >= dfn { - if self.context.caching_enabled { - self.context - .search_graph - .move_to_cache(dfn, &mut self.context.cache); - debug!("solve_reduced_goal: SCC head encountered, moving to cache"); - } else { - debug!( - "solve_reduced_goal: SCC head encountered, rolling back as caching disabled" - ); - self.context.search_graph.rollback_to(dfn); - } - } - - info!("solve_goal: solution = {:?} prio {:?}", result, priority); - result - } - } - - fn interner(&self) -> &I { - &self.program.interner() - } - - fn db(&self) -> &dyn RustIrDatabase { - self.program - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/combine.rs b/vendor/chalk-solve-0.14.0/src/recursive/combine.rs deleted file mode 100644 index e42c282c6a..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/combine.rs +++ /dev/null @@ -1,77 +0,0 @@ -use super::lib::Solution; -use tracing::debug; - -use chalk_ir::interner::Interner; -use chalk_ir::{ClausePriority, DomainGoal, Fallible, GenericArg, Goal, GoalData}; - -pub(super) fn with_priorities_for_goal( - interner: &I, - goal: &Goal, - a: Fallible>, - prio_a: ClausePriority, - b: Fallible>, - prio_b: ClausePriority, -) -> (Fallible>, ClausePriority) { - let domain_goal = match goal.data(interner) { - GoalData::DomainGoal(domain_goal) => domain_goal, - _ => { - // non-domain goals currently have no priorities, so we always take the new solution here - return (b, prio_b); - } - }; - match (a, b) { - (Ok(a), Ok(b)) => { - let (solution, prio) = with_priorities(interner, domain_goal, a, prio_a, b, prio_b); - (Ok(solution), prio) - } - (Ok(solution), Err(_)) => (Ok(solution), prio_a), - (Err(_), Ok(solution)) => (Ok(solution), prio_b), - (Err(_), Err(e)) => (Err(e), prio_b), - } -} - -pub(super) fn with_priorities( - interner: &I, - domain_goal: &DomainGoal, - a: Solution, - prio_a: ClausePriority, - b: Solution, - prio_b: ClausePriority, -) -> (Solution, ClausePriority) { - match (prio_a, prio_b, a, b) { - (ClausePriority::High, ClausePriority::Low, higher, lower) - | (ClausePriority::Low, ClausePriority::High, lower, higher) => { - // if we have a high-priority solution and a low-priority solution, - // the high-priority solution overrides *if* they are both for the - // same inputs -- we don't want a more specific high-priority - // solution overriding a general low-priority one. Currently inputs - // only matter for projections; in a goal like `AliasEq(::Type = ?1)`, ?0 is the input. - let inputs_higher = calculate_inputs(interner, domain_goal, &higher); - let inputs_lower = calculate_inputs(interner, domain_goal, &lower); - if inputs_higher == inputs_lower { - debug!( - "preferring solution: {:?} over {:?} because of higher prio", - higher, lower - ); - (higher, ClausePriority::High) - } else { - (higher.combine(lower, interner), ClausePriority::High) - } - } - (_, _, a, b) => (a.combine(b, interner), prio_a), - } -} - -fn calculate_inputs( - interner: &I, - domain_goal: &DomainGoal, - solution: &Solution, -) -> Vec> { - if let Some(subst) = solution.constrained_subst() { - let subst_goal = subst.value.subst.apply(&domain_goal, interner); - subst_goal.inputs(interner) - } else { - domain_goal.inputs(interner) - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/fulfill.rs b/vendor/chalk-solve-0.14.0/src/recursive/fulfill.rs deleted file mode 100644 index 773ed575a7..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/fulfill.rs +++ /dev/null @@ -1,577 +0,0 @@ -use super::lib::{Guidance, Minimums, Solution}; -use super::solve::SolveDatabase; -use crate::debug_span; -use chalk_ir::cast::Cast; -use chalk_ir::fold::Fold; -use chalk_ir::interner::{HasInterner, Interner}; -use chalk_ir::visit::Visit; -use chalk_ir::zip::Zip; -use chalk_ir::{ - Binders, Canonical, ConstrainedSubst, Constraint, DomainGoal, Environment, EqGoal, Fallible, - GenericArg, Goal, GoalData, InEnvironment, LifetimeOutlives, NoSolution, - ProgramClauseImplication, QuantifierKind, Substitution, UCanonical, UniverseMap, WhereClause, -}; -use rustc_hash::FxHashSet; -use std::fmt::Debug; -use tracing::debug; - -enum Outcome { - Complete, - Incomplete, -} - -impl Outcome { - fn is_complete(&self) -> bool { - match *self { - Outcome::Complete => true, - _ => false, - } - } -} - -/// A goal that must be resolved -#[derive(Clone, Debug, PartialEq, Eq)] -enum Obligation { - /// For "positive" goals, we flatten all the way out to leafs within the - /// current `Fulfill` - Prove(InEnvironment>), - - /// For "negative" goals, we don't flatten in *this* `Fulfill`, which would - /// require having a logical "or" operator. Instead, we recursively solve in - /// a fresh `Fulfill`. - Refute(InEnvironment>), -} - -/// When proving a leaf goal, we record the free variables that appear within it -/// so that we can update inference state accordingly. -#[derive(Clone, Debug)] -struct PositiveSolution { - free_vars: Vec>, - universes: UniverseMap, - solution: Solution, -} - -/// When refuting a goal, there's no impact on inference state. -#[derive(Copy, Clone, Debug, PartialEq, Eq)] -enum NegativeSolution { - Refuted, - Ambiguous, -} - -pub(super) trait RecursiveInferenceTable { - fn instantiate_binders_universally<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner; - - fn instantiate_binders_existentially<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner; - - fn canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> (Canonical, Vec>) - where - T: Fold, - T::Result: HasInterner; - - fn u_canonicalize( - &mut self, - interner: &I, - value0: &Canonical, - ) -> (UCanonical, UniverseMap) - where - T: HasInterner + Fold + Visit, - T::Result: HasInterner; - - fn unify( - &mut self, - interner: &I, - environment: &Environment, - a: &T, - b: &T, - ) -> Fallible<( - Vec>>, - Vec>>, - )> - where - T: ?Sized + Zip; - - fn instantiate_canonical(&mut self, interner: &I, bound: &Canonical) -> T::Result - where - T: HasInterner + Fold + Debug; - - fn invert_then_canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> Option> - where - T: Fold + HasInterner; - - fn needs_truncation(&mut self, interner: &I, max_size: usize, value: impl Visit) -> bool; -} - -/// A `Fulfill` is where we actually break down complex goals, instantiate -/// variables, and perform inference. It's highly stateful. It's generally used -/// in Chalk to try to solve a goal, and then package up what was learned in a -/// stateless, canonical way. -/// -/// In rustc, you can think of there being an outermost `Fulfill` that's used when -/// type checking each function body, etc. There, the state reflects the state -/// of type inference in general. But when solving trait constraints, *fresh* -/// `Fulfill` instances will be created to solve canonicalized, free-standing -/// goals, and transport what was learned back to the outer context. -pub(super) struct Fulfill< - 's, - I: Interner, - Solver: SolveDatabase, - Infer: RecursiveInferenceTable, -> { - solver: &'s mut Solver, - subst: Substitution, - infer: Infer, - - /// The remaining goals to prove or refute - obligations: Vec>, - - /// Lifetime constraints that must be fulfilled for a solution to be fully - /// validated. - constraints: FxHashSet>>, - - /// Record that a goal has been processed that can neither be proved nor - /// refuted. In such a case the solution will be either `CannotProve`, or `Err` - /// in the case where some other goal leads to an error. - cannot_prove: bool, -} - -impl<'s, I: Interner, Solver: SolveDatabase, Infer: RecursiveInferenceTable> - Fulfill<'s, I, Solver, Infer> -{ - pub(super) fn new_with_clause( - solver: &'s mut Solver, - infer: Infer, - subst: Substitution, - canonical_goal: InEnvironment>, - clause: &Binders>, - ) -> Fallible { - let mut fulfill = Fulfill { - solver, - infer, - subst, - obligations: vec![], - constraints: FxHashSet::default(), - cannot_prove: false, - }; - - let ProgramClauseImplication { - consequence, - conditions, - priority: _, - } = fulfill - .infer - .instantiate_binders_existentially(fulfill.solver.interner(), clause); - - debug!("the subst is {:?}", fulfill.subst); - - if let Err(e) = fulfill.unify( - &canonical_goal.environment, - &canonical_goal.goal, - &consequence, - ) { - return Err(e); - } - - // if so, toss in all of its premises - for condition in conditions.as_slice(fulfill.solver.interner()) { - if let Err(e) = fulfill.push_goal(&canonical_goal.environment, condition.clone()) { - return Err(e); - } - } - - Ok(fulfill) - } - - pub(super) fn new_with_simplification( - solver: &'s mut Solver, - infer: Infer, - subst: Substitution, - canonical_goal: InEnvironment>, - ) -> Fallible { - let mut fulfill = Fulfill { - solver, - infer, - subst, - obligations: vec![], - constraints: FxHashSet::default(), - cannot_prove: false, - }; - - if let Err(e) = fulfill.push_goal(&canonical_goal.environment, canonical_goal.goal.clone()) - { - return Err(e); - } - - Ok(fulfill) - } - - fn push_obligation(&mut self, obligation: Obligation) { - // truncate to avoid overflows - match &obligation { - Obligation::Prove(goal) => { - if self - .infer - .needs_truncation(self.solver.interner(), 30, goal) - { - // the goal is too big. Record that we should return Ambiguous - self.cannot_prove = true; - return; - } - } - Obligation::Refute(goal) => { - if self - .infer - .needs_truncation(self.solver.interner(), 30, goal) - { - // the goal is too big. Record that we should return Ambiguous - self.cannot_prove = true; - return; - } - } - }; - self.obligations.push(obligation); - } - - /// Unifies `a` and `b` in the given environment. - /// - /// Wraps `InferenceTable::unify`; any resulting normalizations are added - /// into our list of pending obligations with the given environment. - pub(super) fn unify(&mut self, environment: &Environment, a: &T, b: &T) -> Fallible<()> - where - T: ?Sized + Zip + Debug, - { - let (goals, constraints) = self - .infer - .unify(self.solver.interner(), environment, a, b)?; - debug!("unify({:?}, {:?}) succeeded", a, b); - debug!("unify: goals={:?}", goals); - debug!("unify: constraints={:?}", constraints); - self.constraints.extend(constraints); - for goal in goals { - let goal = goal.cast(self.solver.interner()); - self.push_obligation(Obligation::Prove(goal)); - } - Ok(()) - } - - /// Create obligations for the given goal in the given environment. This may - /// ultimately create any number of obligations. - pub(super) fn push_goal( - &mut self, - environment: &Environment, - goal: Goal, - ) -> Fallible<()> { - debug!("push_goal({:?}, {:?})", goal, environment); - let interner = self.interner(); - match goal.data(interner) { - GoalData::Quantified(QuantifierKind::ForAll, subgoal) => { - let subgoal = self - .infer - .instantiate_binders_universally(self.solver.interner(), subgoal); - self.push_goal(environment, subgoal)?; - } - GoalData::Quantified(QuantifierKind::Exists, subgoal) => { - let subgoal = self - .infer - .instantiate_binders_existentially(self.solver.interner(), subgoal); - self.push_goal(environment, subgoal)?; - } - GoalData::Implies(wc, subgoal) => { - let new_environment = - &environment.add_clauses(interner, wc.iter(interner).cloned()); - self.push_goal(new_environment, subgoal.clone())?; - } - GoalData::All(goals) => { - for subgoal in goals.as_slice(interner) { - self.push_goal(environment, subgoal.clone())?; - } - } - GoalData::Not(subgoal) => { - let in_env = InEnvironment::new(environment, subgoal.clone()); - self.push_obligation(Obligation::Refute(in_env)); - } - GoalData::DomainGoal(domain_goal) => match domain_goal { - DomainGoal::Holds(WhereClause::LifetimeOutlives(LifetimeOutlives { a, b })) => { - self.constraints.insert(InEnvironment::new( - &environment, - Constraint::Outlives(a.clone(), b.clone()), - )); - } - _ => { - let in_env = InEnvironment::new(environment, goal); - self.push_obligation(Obligation::Prove(in_env)); - } - }, - GoalData::EqGoal(EqGoal { a, b }) => { - self.unify(&environment, &a, &b)?; - } - GoalData::CannotProve(()) => { - self.cannot_prove = true; - } - } - Ok(()) - } - - fn prove( - &mut self, - wc: &InEnvironment>, - minimums: &mut Minimums, - ) -> Fallible> { - let interner = self.solver.interner(); - let (quantified, free_vars) = self.infer.canonicalize(interner, &wc); - let (quantified, universes) = self.infer.u_canonicalize(interner, &quantified); - let result = self.solver.solve_goal(quantified, minimums); - Ok(PositiveSolution { - free_vars, - universes, - solution: result?, - }) - } - - fn refute(&mut self, goal: &InEnvironment>) -> Fallible { - let canonicalized = match self - .infer - .invert_then_canonicalize(self.solver.interner(), goal) - { - Some(v) => v, - None => { - // Treat non-ground negatives as ambiguous. Note that, as inference - // proceeds, we may wind up with more information here. - return Ok(NegativeSolution::Ambiguous); - } - }; - - // Negate the result - let (quantified, _) = self - .infer - .u_canonicalize(self.solver.interner(), &canonicalized); - let mut minimums = Minimums::new(); // FIXME -- minimums here seems wrong - if let Ok(solution) = self.solver.solve_goal(quantified, &mut minimums) { - if solution.is_unique() { - Err(NoSolution) - } else { - Ok(NegativeSolution::Ambiguous) - } - } else { - Ok(NegativeSolution::Refuted) - } - } - - /// Trying to prove some goal led to a the substitution `subst`; we - /// wish to apply that substitution to our own inference variables - /// (and incorporate any region constraints). This substitution - /// requires some mapping to get it into our namespace -- first, - /// the universes it refers to have been canonicalized, and - /// `universes` stores the mapping back into our - /// universes. Second, the free variables that appear within can - /// be mapped into our variables with `free_vars`. - fn apply_solution( - &mut self, - free_vars: Vec>, - universes: UniverseMap, - subst: Canonical>, - ) { - use crate::infer::ucanonicalize::UniverseMapExt; - let subst = universes.map_from_canonical(self.interner(), &subst); - let ConstrainedSubst { subst, constraints } = self - .infer - .instantiate_canonical(self.solver.interner(), &subst); - - debug!( - "fulfill::apply_solution: adding constraints {:?}", - constraints - ); - self.constraints.extend(constraints); - - // We use the empty environment for unification here because we're - // really just doing a substitution on unconstrained variables, which is - // guaranteed to succeed without generating any new constraints. - let empty_env = &Environment::new(self.solver.interner()); - - for (i, free_var) in free_vars.into_iter().enumerate() { - let subst_value = subst.at(self.interner(), i); - self.unify(empty_env, &free_var, subst_value) - .unwrap_or_else(|err| { - panic!( - "apply_solution failed with free_var={:?}, subst_value={:?}: {:?}", - free_var, subst_value, err - ); - }); - } - } - - fn fulfill(&mut self, minimums: &mut Minimums) -> Fallible { - debug_span!("fulfill", obligations=?self.obligations); - - // Try to solve all the obligations. We do this via a fixed-point - // iteration. We try to solve each obligation in turn. Anything which is - // successful, we drop; anything ambiguous, we retain in the - // `obligations` array. This process is repeated so long as we are - // learning new things about our inference state. - let mut obligations = Vec::with_capacity(self.obligations.len()); - let mut progress = true; - - while progress { - progress = false; - debug!("start of round, {} obligations", self.obligations.len()); - - // Take the list of `obligations` to solve this round and replace it - // with an empty vector. Iterate through each obligation to solve - // and solve it if we can. If not (because of ambiguity), then push - // it back onto `self.to_prove` for next round. Note that - // `solve_one` may also push onto the `self.to_prove` list - // directly. - assert!(obligations.is_empty()); - while let Some(obligation) = self.obligations.pop() { - let ambiguous = match obligation { - Obligation::Prove(ref wc) => { - let PositiveSolution { - free_vars, - universes, - solution, - } = self.prove(wc, minimums)?; - - if solution.has_definite() { - if let Some(constrained_subst) = solution.constrained_subst() { - self.apply_solution(free_vars, universes, constrained_subst); - progress = true; - } - } - - solution.is_ambig() - } - Obligation::Refute(ref goal) => { - let answer = self.refute(goal)?; - answer == NegativeSolution::Ambiguous - } - }; - - if ambiguous { - debug!("ambiguous result: {:?}", obligation); - obligations.push(obligation); - } - } - - self.obligations.extend(obligations.drain(..)); - debug!("end of round, {} obligations left", self.obligations.len()); - } - - // At the end of this process, `self.obligations` should have - // all of the ambiguous obligations, and `obligations` should - // be empty. - assert!(obligations.is_empty()); - - if self.obligations.is_empty() { - Ok(Outcome::Complete) - } else { - Ok(Outcome::Incomplete) - } - } - - /// Try to fulfill all pending obligations and build the resulting - /// solution. The returned solution will transform `subst` substitution with - /// the outcome of type inference by updating the replacements it provides. - pub(super) fn solve(mut self, minimums: &mut Minimums) -> Fallible> { - let outcome = match self.fulfill(minimums) { - Ok(o) => o, - Err(e) => return Err(e), - }; - - if self.cannot_prove { - return Ok(Solution::Ambig(Guidance::Unknown)); - } - - if outcome.is_complete() { - // No obligations remain, so we have definitively solved our goals, - // and the current inference state is the unique way to solve them. - - let constraints = self.constraints.into_iter().collect(); - let constrained = self.infer.canonicalize( - self.solver.interner(), - &ConstrainedSubst { - subst: self.subst, - constraints, - }, - ); - return Ok(Solution::Unique(constrained.0)); - } - - // Otherwise, we have (positive or negative) obligations remaining, but - // haven't proved that it's *impossible* to satisfy out obligations. we - // need to determine how to package up what we learned about type - // inference as an ambiguous solution. - - let interner = self.solver.interner(); - let canonical_subst = self.infer.canonicalize(interner, &self.subst); - - if canonical_subst.0.value.is_identity_subst(interner) { - // In this case, we didn't learn *anything* definitively. So now, we - // go one last time through the positive obligations, this time - // applying even *tentative* inference suggestions, so that we can - // yield these upwards as our own suggestions. There are no - // particular guarantees about *which* obligaiton we derive - // suggestions from. - - while let Some(obligation) = self.obligations.pop() { - if let Obligation::Prove(goal) = obligation { - let PositiveSolution { - free_vars, - universes, - solution, - } = self.prove(&goal, minimums).unwrap(); - if let Some(constrained_subst) = solution.constrained_subst() { - self.apply_solution(free_vars, universes, constrained_subst); - return Ok(Solution::Ambig(Guidance::Suggested(canonical_subst.0))); - } - } - } - - Ok(Solution::Ambig(Guidance::Unknown)) - } else { - // While we failed to prove the goal, we still learned that - // something had to hold. Here's an example where this happens: - // - // ```rust - // trait Display {} - // trait Debug {} - // struct Foo {} - // struct Bar {} - // struct Baz {} - // - // impl Display for Bar {} - // impl Display for Baz {} - // - // impl Debug for Foo where T: Display {} - // ``` - // - // If we pose the goal `exists { T: Debug }`, we can't say - // for sure what `T` must be (it could be either `Foo` or - // `Foo`, but we *can* say for sure that it must be of the - // form `Foo`. - Ok(Solution::Ambig(Guidance::Definite(canonical_subst.0))) - } - } - - fn interner(&self) -> &I { - self.solver.interner() - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/search_graph.rs b/vendor/chalk-solve-0.14.0/src/recursive/search_graph.rs deleted file mode 100644 index 77b3078f87..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/search_graph.rs +++ /dev/null @@ -1,131 +0,0 @@ -use std::ops::Add; -use std::ops::Index; -use std::ops::IndexMut; -use std::usize; - -use super::lib::{Minimums, Solution, UCanonicalGoal}; -use super::stack::StackDepth; -use chalk_ir::{interner::Interner, ClausePriority, Fallible, NoSolution}; -use rustc_hash::FxHashMap; -use tracing::debug; - -/// The "search graph" stores in-progress goals that are still -/// being solved. -pub(super) struct SearchGraph { - indices: FxHashMap, DepthFirstNumber>, - nodes: Vec>, -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub(super) struct DepthFirstNumber { - index: usize, -} - -pub(super) struct Node { - pub(crate) goal: UCanonicalGoal, - - pub(crate) solution: Fallible>, - pub(crate) solution_priority: ClausePriority, - - /// This is `Some(X)` if we are actively exploring this node, or - /// `None` otherwise. - pub(crate) stack_depth: Option, - - /// While this node is on the stack, this field will be set to - /// contain our own depth-first number. Once the node is popped - /// from the stack, it contains the DFN of the minimal ancestor - /// that the table reached (or MAX if no cycle was encountered). - pub(crate) links: Minimums, -} - -impl SearchGraph { - pub(crate) fn new() -> Self { - SearchGraph { - indices: FxHashMap::default(), - nodes: vec![], - } - } - - pub(crate) fn lookup(&self, goal: &UCanonicalGoal) -> Option { - self.indices.get(goal).cloned() - } - - /// Insert a new search node in the tree. The node will be in the initial - /// state for a search node: - /// - /// - stack depth as given - /// - links set to its own DFN - /// - solution is initially `NoSolution` - pub(crate) fn insert( - &mut self, - goal: &UCanonicalGoal, - stack_depth: StackDepth, - ) -> DepthFirstNumber { - let dfn = DepthFirstNumber { - index: self.nodes.len(), - }; - let node = Node { - goal: goal.clone(), - solution: Err(NoSolution), - solution_priority: ClausePriority::High, - stack_depth: Some(stack_depth), - links: Minimums { positive: dfn }, - }; - self.nodes.push(node); - let previous_index = self.indices.insert(goal.clone(), dfn); - assert!(previous_index.is_none()); - dfn - } - - /// Clears all nodes with a depth-first number greater than or equal `dfn`. - pub(crate) fn rollback_to(&mut self, dfn: DepthFirstNumber) { - debug!("rollback_to(dfn={:?})", dfn); - self.indices.retain(|_key, value| *value < dfn); - self.nodes.truncate(dfn.index); - } - - /// Removes all nodes with a depth-first-number greater than or - /// equal to `dfn`, adding their final solutions into the cache. - pub(crate) fn move_to_cache( - &mut self, - dfn: DepthFirstNumber, - cache: &mut FxHashMap, Fallible>>, - ) { - debug!("move_to_cache(dfn={:?})", dfn); - self.indices.retain(|_key, value| *value < dfn); - for node in self.nodes.drain(dfn.index..) { - assert!(node.stack_depth.is_none()); - assert!(node.links.positive >= dfn); - debug!("caching solution {:?} for {:?}", node.solution, node.goal); - cache.insert(node.goal, node.solution); - } - } -} - -impl Index for SearchGraph { - type Output = Node; - - fn index(&self, table_index: DepthFirstNumber) -> &Node { - &self.nodes[table_index.index] - } -} - -impl IndexMut for SearchGraph { - fn index_mut(&mut self, table_index: DepthFirstNumber) -> &mut Node { - &mut self.nodes[table_index.index] - } -} - -impl DepthFirstNumber { - pub(crate) const MAX: DepthFirstNumber = DepthFirstNumber { index: usize::MAX }; -} - -impl Add for DepthFirstNumber { - type Output = DepthFirstNumber; - - fn add(self, v: usize) -> DepthFirstNumber { - DepthFirstNumber { - index: self.index + v, - } - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/solve.rs b/vendor/chalk-solve-0.14.0/src/recursive/solve.rs deleted file mode 100644 index ab6b7acbbb..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/solve.rs +++ /dev/null @@ -1,314 +0,0 @@ -use super::combine; -use super::fulfill::{Fulfill, RecursiveInferenceTable}; -use super::lib::{Guidance, Minimums, Solution, UCanonicalGoal}; -use crate::clauses::program_clauses_for_goal; -use crate::debug_span; -use crate::infer::{InferenceTable, ParameterEnaVariableExt}; -use crate::{solve::truncate, RustIrDatabase}; -use chalk_ir::fold::Fold; -use chalk_ir::interner::{HasInterner, Interner}; -use chalk_ir::visit::Visit; -use chalk_ir::zip::Zip; -use chalk_ir::{ - Binders, Canonical, ClausePriority, Constraint, DomainGoal, Environment, Fallible, Floundered, - GenericArg, Goal, GoalData, InEnvironment, NoSolution, ProgramClause, ProgramClauseData, - ProgramClauseImplication, Substitution, UCanonical, UniverseMap, -}; -use std::fmt::Debug; -use tracing::{debug, instrument}; - -pub(super) trait SolveDatabase: Sized { - fn solve_goal( - &mut self, - goal: UCanonical>>, - minimums: &mut Minimums, - ) -> Fallible>; - - fn interner(&self) -> &I; - - fn db(&self) -> &dyn RustIrDatabase; -} - -/// The `solve_iteration` method -- implemented for any type that implements -/// `SolveDb`. -pub(super) trait SolveIteration: SolveDatabase { - /// Executes one iteration of the recursive solver, computing the current - /// solution to the given canonical goal. This is used as part of a loop in - /// the case of cyclic goals. - fn solve_iteration( - &mut self, - canonical_goal: &UCanonicalGoal, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) { - let UCanonical { - universes, - canonical: - Canonical { - binders, - value: InEnvironment { environment, goal }, - }, - } = canonical_goal.clone(); - - match goal.data(self.interner()) { - GoalData::DomainGoal(domain_goal) => { - let canonical_goal = UCanonical { - universes, - canonical: Canonical { - binders, - value: InEnvironment { - environment, - goal: domain_goal.clone(), - }, - }, - }; - - // "Domain" goals (i.e., leaf goals that are Rust-specific) are - // always solved via some form of implication. We can either - // apply assumptions from our environment (i.e. where clauses), - // or from the lowered program, which includes fallback - // clauses. We try each approach in turn: - - let InEnvironment { environment, goal } = &canonical_goal.canonical.value; - - let (prog_solution, prog_prio) = { - debug_span!("prog_clauses"); - - let prog_clauses = self.program_clauses_for_goal(environment, &goal); - match prog_clauses { - Ok(clauses) => self.solve_from_clauses(&canonical_goal, clauses, minimums), - Err(Floundered) => { - (Ok(Solution::Ambig(Guidance::Unknown)), ClausePriority::High) - } - } - }; - debug!("prog_solution={:?}", prog_solution); - - (prog_solution, prog_prio) - } - - _ => { - let canonical_goal = UCanonical { - universes, - canonical: Canonical { - binders, - value: InEnvironment { environment, goal }, - }, - }; - - self.solve_via_simplification(&canonical_goal, minimums) - } - } - } -} - -impl SolveIteration for S -where - S: SolveDatabase, - I: Interner, -{ -} - -/// Helper methods for `solve_iteration`, private to this module. -trait SolveIterationHelpers: SolveDatabase { - #[instrument(level = "debug", skip(self, minimums))] - fn solve_via_simplification( - &mut self, - canonical_goal: &UCanonicalGoal, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) { - let (infer, subst, goal) = self.new_inference_table(canonical_goal); - match Fulfill::new_with_simplification(self, infer, subst, goal) { - Ok(fulfill) => (fulfill.solve(minimums), ClausePriority::High), - Err(e) => (Err(e), ClausePriority::High), - } - } - - /// See whether we can solve a goal by implication on any of the given - /// clauses. If multiple such solutions are possible, we attempt to combine - /// them. - fn solve_from_clauses( - &mut self, - canonical_goal: &UCanonical>>, - clauses: C, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) - where - C: IntoIterator>, - { - let mut cur_solution = None; - for program_clause in clauses { - debug_span!("solve_from_clauses", clause = ?program_clause); - - // If we have a completely ambiguous answer, it's not going to get better, so stop - if cur_solution == Some((Solution::Ambig(Guidance::Unknown), ClausePriority::High)) { - return (Ok(Solution::Ambig(Guidance::Unknown)), ClausePriority::High); - } - - let ProgramClauseData(implication) = program_clause.data(self.interner()); - let res = self.solve_via_implication(canonical_goal, implication, minimums); - - if let (Ok(solution), priority) = res { - debug!("ok: solution={:?} prio={:?}", solution, priority); - cur_solution = Some(match cur_solution { - None => (solution, priority), - Some((cur, cur_priority)) => combine::with_priorities( - self.interner(), - &canonical_goal.canonical.value.goal, - cur, - cur_priority, - solution, - priority, - ), - }); - } else { - debug!("error"); - } - } - cur_solution.map_or((Err(NoSolution), ClausePriority::High), |(s, p)| (Ok(s), p)) - } - - /// Modus ponens! That is: try to apply an implication by proving its premises. - #[instrument(level = "info", skip(self, minimums))] - fn solve_via_implication( - &mut self, - canonical_goal: &UCanonical>>, - clause: &Binders>, - minimums: &mut Minimums, - ) -> (Fallible>, ClausePriority) { - let (infer, subst, goal) = self.new_inference_table(canonical_goal); - match Fulfill::new_with_clause(self, infer, subst, goal, clause) { - Ok(fulfill) => (fulfill.solve(minimums), clause.skip_binders().priority), - Err(e) => (Err(e), ClausePriority::High), - } - } - - fn new_inference_table + HasInterner + Clone>( - &self, - ucanonical_goal: &UCanonical>, - ) -> ( - RecursiveInferenceTableImpl, - Substitution, - InEnvironment, - ) { - let (infer, subst, canonical_goal) = InferenceTable::from_canonical( - self.interner(), - ucanonical_goal.universes, - &ucanonical_goal.canonical, - ); - let infer = RecursiveInferenceTableImpl { infer }; - (infer, subst, canonical_goal) - } - - fn program_clauses_for_goal( - &self, - environment: &Environment, - goal: &DomainGoal, - ) -> Result>, Floundered> { - program_clauses_for_goal(self.db(), environment, goal) - } -} - -impl SolveIterationHelpers for S -where - S: SolveDatabase, - I: Interner, -{ -} - -struct RecursiveInferenceTableImpl { - infer: InferenceTable, -} - -impl RecursiveInferenceTable for RecursiveInferenceTableImpl { - fn instantiate_binders_universally<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner, - { - self.infer.instantiate_binders_universally(interner, arg) - } - - fn instantiate_binders_existentially<'a, T>( - &mut self, - interner: &'a I, - arg: &'a Binders, - ) -> T::Result - where - T: Fold + HasInterner, - { - self.infer.instantiate_binders_existentially(interner, arg) - } - - fn canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> (Canonical, Vec>) - where - T: Fold, - T::Result: HasInterner, - { - let res = self.infer.canonicalize(interner, value); - let free_vars = res - .free_vars - .into_iter() - .map(|free_var| free_var.to_generic_arg(interner)) - .collect(); - (res.quantified, free_vars) - } - - fn u_canonicalize( - &mut self, - interner: &I, - value0: &Canonical, - ) -> (UCanonical, UniverseMap) - where - T: HasInterner + Fold + Visit, - T::Result: HasInterner, - { - let res = self.infer.u_canonicalize(interner, value0); - (res.quantified, res.universes) - } - - fn unify( - &mut self, - interner: &I, - environment: &Environment, - a: &T, - b: &T, - ) -> Fallible<( - Vec>>, - Vec>>, - )> - where - T: ?Sized + Zip, - { - let res = self.infer.unify(interner, environment, a, b)?; - Ok((res.goals, res.constraints)) - } - - fn instantiate_canonical(&mut self, interner: &I, bound: &Canonical) -> T::Result - where - T: HasInterner + Fold + Debug, - { - self.infer.instantiate_canonical(interner, bound) - } - - fn invert_then_canonicalize( - &mut self, - interner: &I, - value: &T, - ) -> Option> - where - T: Fold + HasInterner, - { - self.infer.invert_then_canonicalize(interner, value) - } - - fn needs_truncation(&mut self, interner: &I, max_size: usize, value: impl Visit) -> bool { - truncate::needs_truncation(interner, &mut self.infer, max_size, value) - } -} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/stack.rs b/vendor/chalk-solve-0.14.0/src/recursive/stack.rs deleted file mode 100644 index 917d39c764..0000000000 --- a/vendor/chalk-solve-0.14.0/src/recursive/stack.rs +++ /dev/null @@ -1,101 +0,0 @@ -use std::mem; -use std::ops::Index; -use std::ops::IndexMut; -use std::usize; - -pub(crate) struct Stack { - // program: Arc, - entries: Vec, - overflow_depth: usize, -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub(crate) struct StackDepth { - depth: usize, -} - -/// The data we actively keep for each goal on the stack. -pub(crate) struct StackEntry { - /// Was this a coinductive goal? - coinductive_goal: bool, - - /// Initially false, set to true when some subgoal depends on us. - cycle: bool, -} - -impl Stack { - pub(crate) fn new( - // program: &Arc, - overflow_depth: usize, - ) -> Self { - Stack { - // program: program.clone(), - entries: vec![], - overflow_depth, - } - } - - pub(crate) fn is_empty(&self) -> bool { - self.entries.is_empty() - } - - pub(crate) fn push(&mut self, coinductive_goal: bool) -> StackDepth { - let depth = StackDepth { - depth: self.entries.len(), - }; - - if depth.depth >= self.overflow_depth { - // This shoudl perhaps be a result or something, though - // really I'd prefer to move to subgoal abstraction for - // guaranteeing termination. -nmatsakis - panic!("overflow depth reached") - } - - self.entries.push(StackEntry { - coinductive_goal, - cycle: false, - }); - depth - } - - pub(crate) fn pop(&mut self, depth: StackDepth) { - assert_eq!( - depth.depth + 1, - self.entries.len(), - "mismatched stack push/pop" - ); - self.entries.pop(); - } - - /// True if all the goals from the top of the stack down to (and - /// including) the given depth are coinductive. - pub(crate) fn coinductive_cycle_from(&self, depth: StackDepth) -> bool { - self.entries[depth.depth..] - .iter() - .all(|entry| entry.coinductive_goal) - } -} - -impl StackEntry { - pub(crate) fn flag_cycle(&mut self) { - self.cycle = true; - } - - pub(crate) fn read_and_reset_cycle_flag(&mut self) -> bool { - mem::replace(&mut self.cycle, false) - } -} - -impl Index for Stack { - type Output = StackEntry; - - fn index(&self, depth: StackDepth) -> &StackEntry { - &self.entries[depth.depth] - } -} - -impl IndexMut for Stack { - fn index_mut(&mut self, depth: StackDepth) -> &mut StackEntry { - &mut self.entries[depth.depth] - } -} diff --git a/vendor/chalk-solve-0.14.0/src/solve.rs b/vendor/chalk-solve-0.14.0/src/solve.rs deleted file mode 100644 index 342bb77119..0000000000 --- a/vendor/chalk-solve-0.14.0/src/solve.rs +++ /dev/null @@ -1,395 +0,0 @@ -use crate::RustIrDatabase; -use chalk_ir::interner::Interner; -use chalk_ir::*; -use std::fmt; - -#[cfg(feature = "slg-solver")] -pub use crate::solve::slg::SubstitutionResult; -#[cfg(feature = "slg-solver")] -use { - crate::solve::slg::{aggregate::AggregateOps, SlgContext, SlgContextOps}, - chalk_engine::context::{AnswerResult, AnswerStream, ContextOps}, - chalk_engine::forest::Forest, -}; - -#[cfg(feature = "recursive-solver")] -use crate::recursive::RecursiveContext; - -#[cfg(feature = "slg-solver")] -mod slg; -pub(crate) mod truncate; - -/// A (possible) solution for a proposed goal. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Solution { - /// The goal indeed holds, and there is a unique value for all existential - /// variables. In this case, we also record a set of lifetime constraints - /// which must also hold for the goal to be valid. - Unique(Canonical>), - - /// The goal may be provable in multiple ways, but regardless we may have some guidance - /// for type inference. In this case, we don't return any lifetime - /// constraints, since we have not "committed" to any particular solution - /// yet. - Ambig(Guidance), -} - -/// When a goal holds ambiguously (e.g., because there are multiple possible -/// solutions), we issue a set of *guidance* back to type inference. -#[derive(Clone, Debug, PartialEq, Eq)] -pub enum Guidance { - /// The existential variables *must* have the given values if the goal is - /// ever to hold, but that alone isn't enough to guarantee the goal will - /// actually hold. - Definite(Canonical>), - - /// There are multiple plausible values for the existentials, but the ones - /// here are suggested as the preferred choice heuristically. These should - /// be used for inference fallback only. - Suggested(Canonical>), - - /// There's no useful information to feed back to type inference - Unknown, -} - -impl Solution { - pub fn is_unique(&self) -> bool { - match *self { - Solution::Unique(..) => true, - _ => false, - } - } - - pub fn display<'a>(&'a self, interner: &'a I) -> SolutionDisplay<'a, I> { - SolutionDisplay { - solution: self, - interner, - } - } -} - -pub struct SolutionDisplay<'a, I: Interner> { - solution: &'a Solution, - interner: &'a I, -} - -impl<'a, I: Interner> fmt::Display for SolutionDisplay<'a, I> { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { - let SolutionDisplay { solution, interner } = self; - match solution { - Solution::Unique(constrained) => write!(f, "Unique; {}", constrained.display(interner)), - Solution::Ambig(Guidance::Definite(subst)) => write!( - f, - "Ambiguous; definite substitution {}", - subst.display(interner) - ), - Solution::Ambig(Guidance::Suggested(subst)) => write!( - f, - "Ambiguous; suggested substitution {}", - subst.display(interner) - ), - Solution::Ambig(Guidance::Unknown) => write!(f, "Ambiguous; no inference guidance"), - } - } -} - -#[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq, Hash)] -pub enum SolverChoice { - /// Run the SLG solver, producing a Solution. - #[cfg(feature = "slg-solver")] - SLG { - max_size: usize, - expected_answers: Option, - }, - /// Run the recursive solver. - #[cfg(feature = "recursive-solver")] - Recursive { - overflow_depth: usize, - caching_enabled: bool, - }, -} - -impl SolverChoice { - /// Returns specific SLG parameters. - #[cfg(feature = "slg-solver")] - pub fn slg(max_size: usize, expected_answers: Option) -> Self { - SolverChoice::SLG { - max_size, - expected_answers, - } - } - - /// Returns the default SLG parameters. - #[cfg(feature = "slg-solver")] - pub fn slg_default() -> Self { - SolverChoice::slg(10, None) - } - - /// Returns the default recursive solver setup. - #[cfg(feature = "recursive-solver")] - pub fn recursive() -> Self { - SolverChoice::Recursive { - overflow_depth: 100, - caching_enabled: true, - } - } - - /// Creates a solver state. - pub fn into_solver(self) -> Solver { - match self { - #[cfg(feature = "slg-solver")] - SolverChoice::SLG { - max_size, - expected_answers, - } => Solver(SolverImpl::Slg { - forest: Box::new(Forest::new()), - max_size, - expected_answers, - }), - #[cfg(feature = "recursive-solver")] - SolverChoice::Recursive { - overflow_depth, - caching_enabled, - } => Solver(SolverImpl::Recursive(Box::new(RecursiveContext::new( - overflow_depth, - caching_enabled, - )))), - } - } -} - -#[cfg(feature = "slg-solver")] -impl Default for SolverChoice { - fn default() -> Self { - SolverChoice::slg_default() - } -} - -#[cfg(all(not(feature = "slg-solver"), feature = "recursive-solver"))] -impl Default for SolverChoice { - fn default() -> Self { - SolverChoice::recursive() - } -} - -/// Finds the solution to "goals", or trait queries -- i.e., figures -/// out what sets of types implement which traits. Also, between -/// queries, this struct stores the cached state from previous solver -/// attempts, which can then be re-used later. -pub struct Solver(SolverImpl); - -enum SolverImpl { - #[cfg(feature = "slg-solver")] - Slg { - forest: Box>>, - max_size: usize, - /// The expected number of answers for a solution. - /// Only really useful for tests, since `make_solution` - /// will panic if the number of cached answers does not - /// equal this when a solution is made. - expected_answers: Option, - }, - #[cfg(feature = "recursive-solver")] - Recursive(Box>), -} - -impl Solver { - /// Attempts to solve the given goal, which must be in canonical - /// form. Returns a unique solution (if one exists). This will do - /// only as much work towards `goal` as it has to (and that work - /// is cached for future attempts). - /// - /// # Parameters - /// - /// - `program` -- defines the program clauses in scope. - /// - **Important:** You must supply the same set of program clauses - /// each time you invoke `solve`, as otherwise the cached data may be - /// invalid. - /// - `goal` the goal to solve - /// - /// # Returns - /// - /// - `None` is the goal cannot be proven. - /// - `Some(solution)` if we succeeded in finding *some* answers, - /// although `solution` may reflect ambiguity and unknowns. - pub fn solve( - &mut self, - program: &dyn RustIrDatabase, - goal: &UCanonical>>, - ) -> Option> { - match &mut self.0 { - #[cfg(feature = "slg-solver")] - SolverImpl::Slg { - forest, - max_size, - expected_answers, - } => { - let ops = SlgContextOps::new(program, *max_size, *expected_answers); - ops.make_solution(goal, forest.iter_answers(&ops, goal), || true) - } - #[cfg(feature = "recursive-solver")] - SolverImpl::Recursive(ctx) => { - ctx.solver(program) - .solve_root_goal(goal) - .ok() - .map(|s| match s { - crate::recursive::lib::Solution::Unique(c) => { - crate::solve::Solution::Unique(c) - } - crate::recursive::lib::Solution::Ambig(g) => { - crate::solve::Solution::Ambig(match g { - crate::recursive::lib::Guidance::Definite(g) => { - crate::solve::Guidance::Definite(g) - } - crate::recursive::lib::Guidance::Suggested(g) => { - crate::solve::Guidance::Suggested(g) - } - crate::recursive::lib::Guidance::Unknown => { - crate::solve::Guidance::Unknown - } - }) - } - }) - } - } - } - - /// Attempts to solve the given goal, which must be in canonical - /// form. Returns a unique solution (if one exists). This will do - /// only as much work towards `goal` as it has to (and that work - /// is cached for future attempts). In addition, the solving of the - /// goal can be limited by returning `false` from `should_continue`. - /// - /// # Parameters - /// - /// - `program` -- defines the program clauses in scope. - /// - **Important:** You must supply the same set of program clauses - /// each time you invoke `solve`, as otherwise the cached data may be - /// invalid. - /// - `goal` the goal to solve - /// - `should_continue` if `false` is returned, the no further solving - /// will be done. A `Guidance(Suggested(...))` will be returned a - /// `Solution`, using any answers that were generated up to that point. - /// - /// # Returns - /// - /// - `None` is the goal cannot be proven. - /// - `Some(solution)` if we succeeded in finding *some* answers, - /// although `solution` may reflect ambiguity and unknowns. - pub fn solve_limited( - &mut self, - program: &dyn RustIrDatabase, - goal: &UCanonical>>, - should_continue: impl std::ops::Fn() -> bool, - ) -> Option> { - match &mut self.0 { - #[cfg(feature = "slg-solver")] - SolverImpl::Slg { - forest, - max_size, - expected_answers, - } => { - let ops = SlgContextOps::new(program, *max_size, *expected_answers); - ops.make_solution(goal, forest.iter_answers(&ops, goal), should_continue) - } - #[cfg(feature = "recursive-solver")] - SolverImpl::Recursive(ctx) => { - // TODO support should_continue in recursive solver - ctx.solver(program) - .solve_root_goal(goal) - .ok() - .map(|s| match s { - crate::recursive::lib::Solution::Unique(c) => { - crate::solve::Solution::Unique(c) - } - crate::recursive::lib::Solution::Ambig(g) => { - crate::solve::Solution::Ambig(match g { - crate::recursive::lib::Guidance::Definite(g) => { - crate::solve::Guidance::Definite(g) - } - crate::recursive::lib::Guidance::Suggested(g) => { - crate::solve::Guidance::Suggested(g) - } - crate::recursive::lib::Guidance::Unknown => { - crate::solve::Guidance::Unknown - } - }) - } - }) - } - } - } - - /// Attempts to solve the given goal, which must be in canonical - /// form. Provides multiple solutions to function `f`. This will do - /// only as much work towards `goal` as it has to (and that work - /// is cached for future attempts). - /// - /// # Parameters - /// - /// - `program` -- defines the program clauses in scope. - /// - **Important:** You must supply the same set of program clauses - /// each time you invoke `solve`, as otherwise the cached data may be - /// invalid. - /// - `goal` the goal to solve - /// - `f` -- function to proceed solution. New solutions will be generated - /// while function returns `true`. - /// - first argument is solution found - /// - second argument is ther next solution present - /// - returns true if next solution should be handled - /// - /// # Returns - /// - /// - `true` all solutions were processed with the function. - /// - `false` the function returned `false` and solutions were interrupted. - #[cfg(feature = "slg-solver")] - pub fn solve_multiple( - &mut self, - program: &dyn RustIrDatabase, - goal: &UCanonical>>, - mut f: impl FnMut(SubstitutionResult>>, bool) -> bool, - ) -> bool { - match &mut self.0 { - SolverImpl::Slg { - forest, - max_size, - expected_answers, - } => { - let ops = SlgContextOps::new(program, *max_size, *expected_answers); - let mut answers = forest.iter_answers(&ops, goal); - loop { - let subst = match answers.next_answer(|| true) { - AnswerResult::Answer(answer) => { - if !answer.ambiguous { - SubstitutionResult::Definite(answer.subst) - } else { - if ops.is_trivial_constrained_substitution(&answer.subst) { - SubstitutionResult::Floundered - } else { - SubstitutionResult::Ambiguous(answer.subst) - } - } - } - AnswerResult::Floundered => SubstitutionResult::Floundered, - AnswerResult::NoMoreSolutions => { - return true; - } - AnswerResult::QuantumExceeded => continue, - }; - - if !f(subst, !answers.peek_answer(|| true).is_no_more_solutions()) { - return false; - } - } - } - #[cfg(feature = "recursive-solver")] - SolverImpl::Recursive(_ctx) => unimplemented!(), - } - } -} - -impl std::fmt::Debug for Solver { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - write!(fmt, "Solver {{ .. }}") - } -} diff --git a/vendor/chalk-solve-0.14.0/src/test_macros.rs b/vendor/chalk-solve-0.14.0/src/test_macros.rs deleted file mode 100644 index 20f39e3fdb..0000000000 --- a/vendor/chalk-solve-0.14.0/src/test_macros.rs +++ /dev/null @@ -1,115 +0,0 @@ -//! Useful macros for writing unit tests. They let you gin up dummy types and things. - -macro_rules! ty { - (apply $n:tt $($arg:tt)*) => { - chalk_ir::TyData::Apply(ApplicationTy { - name: ty_name!($n), - substitution: chalk_ir::Substitution::from( - &chalk_integration::interner::ChalkIr, - vec![$(arg!($arg)),*] as Vec> - ), - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (function $n:tt $($arg:tt)*) => { - chalk_ir::TyData::Function(Fn { - num_binders: $n, - substitution: chalk_ir::Substitution::from( - &chalk_integration::interner::ChalkIr, - vec![$(arg!($arg)),*] as Vec> - ), - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (placeholder $n:expr) => { - chalk_ir::TyData::Placeholder(PlaceholderIndex { - ui: UniverseIndex { counter: $n }, - idx: 0, - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (projection (item $n:tt) $($arg:tt)*) => { - chalk_ir::AliasTy::Projection(chalk_ir::ProjectionTy { - associated_ty_id: AssocTypeId(chalk_integration::interner::RawId { index: $n }), - substitution: chalk_ir::Substitution::from( - &chalk_integration::interner::ChalkIr, - vec![$(arg!($arg)),*] as Vec> - ), - }).intern(&chalk_integration::interner::ChalkIr) - }; - - (infer $b:expr) => { - chalk_ir::TyData::InferenceVar(chalk_ir::InferenceVar::from($b), chalk_ir::TyKind::General) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $d:tt $b:tt) => { - chalk_ir::TyData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new($d), $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $b:expr) => { - chalk_ir::TyData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::INNERMOST, $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (expr $b:expr) => { - $b.clone() - }; - - (($($b:tt)*)) => { - ty!($($b)*) - }; -} - -macro_rules! arg { - ((lifetime $b:tt)) => { - chalk_ir::GenericArg::new( - &chalk_integration::interner::ChalkIr, - chalk_ir::GenericArgData::Lifetime(lifetime!($b)), - ) - }; - - ($arg:tt) => { - chalk_ir::GenericArg::new( - &chalk_integration::interner::ChalkIr, - chalk_ir::GenericArgData::Ty(ty!($arg)), - ) - }; -} - -macro_rules! lifetime { - (infer $b:expr) => { - chalk_ir::LifetimeData::InferenceVar(chalk_ir::InferenceVar::from($b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $d:tt $b:tt) => { - chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::new($d), $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (bound $b:expr) => { - chalk_ir::LifetimeData::BoundVar(chalk_ir::BoundVar::new(chalk_ir::DebruijnIndex::INNERMOST, $b)) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (placeholder $b:expr) => { - chalk_ir::LifetimeData::Placeholder(PlaceholderIndex { ui: UniverseIndex { counter: $b }, idx: 0}) - .intern(&chalk_integration::interner::ChalkIr) - }; - - (expr $b:expr) => { - $b.clone() - }; - - (($($b:tt)*)) => { - lifetime!($($b)*) - }; -} - -macro_rules! ty_name { - ((item $n:expr)) => { - chalk_ir::TypeName::Adt(AdtId(chalk_integration::interner::RawId { index: $n })) - }; -} diff --git a/vendor/chalk-solve-0.25.0/.cargo-checksum.json b/vendor/chalk-solve-0.25.0/.cargo-checksum.json new file mode 100644 index 0000000000..8b5dbeb285 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"b5c6f88446f266ca3638fb46bd55caac0d836b5452ca46033ca13a39c1c1d9f8","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"b4e8d03cf1137b3512b3dee245d05471396069131e2391ca667d3b192c942425","src/clauses/builder.rs":"ea0e37237addb834d3b274d316fae270dcbd418fc89d3c6cebf09e31fe346634","src/clauses/builtin_traits.rs":"0d8280fa4b261154a101698d2dbb63e5ff14c314fd7801732055c2f9d1ab66d0","src/clauses/builtin_traits/clone.rs":"963a3a192aa8283733d3bc2c0a5e7cf0debcf47986df85a25eef3e3c647de257","src/clauses/builtin_traits/copy.rs":"e5e2e9d8355fb2aaf36ab6d9ab89cf28d6a0984eb621773cb8a4d82a6302e25c","src/clauses/builtin_traits/fn_family.rs":"b81715f2521a1ee9aafd429931c2a250675898f0ee121c374298cb4af20aff58","src/clauses/builtin_traits/sized.rs":"7147c0bdc117fb7e768430ad963ce5c627bfe3641c04e3269f8a08a215c93dab","src/clauses/builtin_traits/unsize.rs":"9ac311cc905d068f5626204cdacadfe8b3e9c126fb821c8cbd054f7fd21165d2","src/clauses/dyn_ty.rs":"7c32ccd5a3bc7479b0e34ca2d3da254edcc7f73e38ace9f1860c5f64bb8def8a","src/clauses/env_elaborator.rs":"bd598d47075b7c5366c9db55d99b1426c7ea646bd2508c7674bcc52d918bdf76","src/clauses/generalize.rs":"c44f8e559a12f67ad55cff2dd3ffb39d9333cf39a7c8b78c6a8fe87e764c2f98","src/clauses/program_clauses.rs":"4ff101e17087299b3e431796dbb2fe8950b2bb3f2f4b2e7b4464bd3698656d41","src/coherence.rs":"665658b1dda7d5a37e9183a6ff176048c5b1001d23766b3b97288cdf8f3a94cc","src/coherence/orphan.rs":"621a839058309f1977e9eea972afa1622a372e06889d8d20aff64788cfba1829","src/coherence/solve.rs":"34746fd1a3e5984b8b3163bf89a906f5e2f99f17f57b1364ec688c3754d5272e","src/coinductive_goal.rs":"7a2179fb2d61435cf55c5c87301db6c15edb3cb46750bea381451649b2f1051d","src/display.rs":"c5c0a796b6037dea1cf18dcb063f0ccd3bd82012b480231f4e15d2186bb9a9f8","src/display/bounds.rs":"47b402d34c9a0cb7d4f4f35b40d86f983b6a335c9dfae95645eaa472404b6098","src/display/identifiers.rs":"22937fc099812dd9282c20c77ad3797cfa13a8838a0c68638bc4fc32178afbc8","src/display/items.rs":"0e24b30a35c079b8661c2fb5f957b0fc5932b5aef995495fa0c96b3a045f3650","src/display/render_trait.rs":"ccdcbe8e5a1771630dd61eb24b8e384fc30147c285bd40865f9ccc87ab4931b7","src/display/state.rs":"598f115023570bb6659a043d2410aef538364473031e53018bd78c247658d51b","src/display/stub.rs":"28e1ee74aefd8e491956f30e7c703778b68b62288e4763bb429313c5cbe5738e","src/display/ty.rs":"6673ac4c5e767b2afb35d133ff607cfba7f9bc9514ed6888b678ded09891d50c","src/display/utils.rs":"929d68b566265674e31a3fce6ffa0123fd6fc7b7c7323baf62aefd56ce67e085","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"1acef3990ec74d515200c2f42045028496f1799352d945481505ca00698d9838","src/infer.rs":"b5a533153d2a3ae342892b250d0eac0dcd87a26a38626a3753f326d3ce93966e","src/infer/canonicalize.rs":"85de8d18c62b151587a8df45af65b105faa20a14c033ca38d5b20965614ac515","src/infer/instantiate.rs":"0b43c5b86afae964298cc33b11d89b81feb8094074aa71ebcbbfa218c6a11a86","src/infer/invert.rs":"18ff374ff9ac9735ecedd66b3afa8dfa3531867d2b578eb011fdd97d56e150c1","src/infer/test.rs":"b3e69f1110aca3e6d261e01d2da7b7159b08e3e6345375f55bedaf3ae4c995aa","src/infer/ucanonicalize.rs":"f53f9b113921e122646d90075c0c518c48b3e6483b2bce72e3edc22083fcf957","src/infer/unify.rs":"fb17f98014d56618d5ea3ff0b491387c986266a1b80fe3bf906135f1b859a6a3","src/infer/var.rs":"35f88c269fbe1c7da572d9b21a64a1bed80036c563d91f7c71a639c51cac9801","src/lib.rs":"35517aa1e7b3ddaad9d52babedb497f5d068c48ce44ee768d2db171a7f3ed08e","src/logging.rs":"a3e3fa6bb03f29db9f87aedfa6051d4ad649c2aa2be292d03260d64c9bb8c5e2","src/logging_db.rs":"6d153fcf823a19680ab015286ad3d6e2ab47e1f6b39262f77271e664f8acef27","src/logging_db/id_collector.rs":"1f793e32ddb4b4562f139a63e9888a3320291209e91370ec7475b37a6dd396e2","src/recursive/lib.rs":"24f1dd3310eae203607835f063de7b8ed0fc75dee934428ad08abedb6c3e8704","src/rust_ir.rs":"f122a9c96aaa17f02739fb7443b3ffc38fcdd2c1b2a08b39cf3184011d43a403","src/solve.rs":"aa4d20a73dce06a0a5bb0459f4b2bdd80fd842d7a193f65ca48878ed915c6dd3","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"f77bacc0545b4f6af841fd4707185bb79bac768eabb44a9bdc9514b9f19800d0","src/split.rs":"f01ead861bc2abf79b08a67c7d620e8794f73db833ec516b5115602aa9d07d1c","src/wf.rs":"546fa2af849cd8afa480896c6e52816e96e2705b3d10628388eedfded1a6ddd0"},"package":"45b235a1f568b28707f117b2d30eabbee9cbcfccaa0d6e9697300400c8ca0996"} \ No newline at end of file diff --git a/vendor/chalk-solve-0.14.0/Cargo.toml b/vendor/chalk-solve-0.25.0/Cargo.toml similarity index 79% rename from vendor/chalk-solve-0.14.0/Cargo.toml rename to vendor/chalk-solve-0.25.0/Cargo.toml index a330a1dd0f..0267d04875 100644 --- a/vendor/chalk-solve-0.14.0/Cargo.toml +++ b/vendor/chalk-solve-0.25.0/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-solve" -version = "0.14.0" +version = "0.25.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Combines the chalk-engine with chalk-ir" readme = "README.md" @@ -21,14 +21,10 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.14.0" - -[dependencies.chalk-engine] -version = "=0.14.0" -optional = true +version = "=0.25.0" [dependencies.chalk-ir] -version = "=0.14.0" +version = "=0.25.0" [dependencies.ena] version = "0.14.0" @@ -37,17 +33,24 @@ version = "0.14.0" version = "0.9.0" [dependencies.petgraph] -version = "0.5.0" +version = "0.5.1" [dependencies.rustc-hash] -version = "1.0.0" +version = "1.1.0" [dependencies.tracing] version = "0.1" +[dependencies.tracing-subscriber] +version = "0.2" +optional = true + +[dependencies.tracing-tree] +version = "0.1.4" +optional = true + [dev-dependencies] [features] -default = ["slg-solver", "recursive-solver"] -recursive-solver = [] -slg-solver = ["chalk-engine"] +default = ["tracing-full"] +tracing-full = ["tracing-subscriber", "tracing-tree"] diff --git a/vendor/chalk-solve-0.14.0/README.md b/vendor/chalk-solve-0.25.0/README.md similarity index 100% rename from vendor/chalk-solve-0.14.0/README.md rename to vendor/chalk-solve-0.25.0/README.md diff --git a/vendor/chalk-solve-0.14.0/src/clauses.rs b/vendor/chalk-solve-0.25.0/src/clauses.rs similarity index 66% rename from vendor/chalk-solve-0.14.0/src/clauses.rs rename to vendor/chalk-solve-0.25.0/src/clauses.rs index 7fc248363f..db54807664 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses.rs @@ -3,11 +3,12 @@ use self::env_elaborator::elaborate_env_clauses; use self::program_clauses::ToProgramClauses; use crate::split::Split; use crate::RustIrDatabase; -use chalk_ir::cast::Cast; +use chalk_ir::cast::{Cast, Caster}; use chalk_ir::could_match::CouldMatch; use chalk_ir::interner::Interner; use chalk_ir::*; use rustc_hash::FxHashSet; +use std::iter; use tracing::{debug, instrument}; pub mod builder; @@ -17,6 +18,7 @@ mod env_elaborator; mod generalize; pub mod program_clauses; +/// FIXME(#505) update comments for ADTs /// For auto-traits, we generate a default rule for every struct, /// unless there is a manual impl for that struct given explicitly. /// @@ -73,8 +75,8 @@ pub fn push_auto_trait_impls( return; } - let binders = adt_datum.binders.map_ref(|b| &b.fields); - builder.push_binders(&binders, |builder, fields| { + let binders = adt_datum.binders.map_ref(|b| &b.variants); + builder.push_binders(&binders, |builder, variants| { let self_ty: Ty<_> = ApplicationTy { name: adt_id.cast(interner), substitution: builder.substitution_in_scope(), @@ -95,9 +97,11 @@ pub fn push_auto_trait_impls( // } builder.push_clause( auto_trait_ref, - fields.iter().map(|field_ty| TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, field_ty.clone()), + variants.iter().flat_map(|variant| { + variant.fields.iter().map(|field_ty| TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, field_ty.clone()), + }) }), ); }); @@ -168,16 +172,17 @@ pub fn push_auto_trait_impls_opaque( /// is `Implemented(T: Clone)`, then this function might return clauses /// derived from the trait `Clone` and its impls. #[instrument(level = "debug", skip(db))] -pub(crate) fn program_clauses_for_goal<'db, I: Interner>( +pub fn program_clauses_for_goal<'db, I: Interner>( db: &'db dyn RustIrDatabase, environment: &Environment, goal: &DomainGoal, + binders: &CanonicalVarKinds, ) -> Result>, Floundered> { let interner = db.interner(); let custom_clauses = db.custom_clauses().into_iter(); - let clauses_that_could_match = - program_clauses_that_could_match(db, environment, goal).map(|cl| cl.into_iter())?; + let clauses_that_could_match = program_clauses_that_could_match(db, environment, goal, binders) + .map(|cl| cl.into_iter())?; let clauses: Vec> = custom_clauses .chain(clauses_that_could_match) @@ -189,7 +194,7 @@ pub(crate) fn program_clauses_for_goal<'db, I: Interner>( .filter(|c| c.could_match(interner, goal)) .collect(); - debug!("vec = {:#?}", clauses); + debug!(?clauses); Ok(clauses) } @@ -203,6 +208,11 @@ fn program_clauses_that_could_match( db: &dyn RustIrDatabase, environment: &Environment, goal: &DomainGoal, + // FIXME: These are the binders for `goal`. We're passing them separately + // because `goal` is not necessarily canonicalized: The recursive solver + // passes the canonical goal; the SLG solver instantiates the goal first. + // (See #568.) + binders: &CanonicalVarKinds, ) -> Result>, Floundered> { let interner = db.interner(); let mut clauses: Vec> = vec![]; @@ -221,22 +231,22 @@ fn program_clauses_that_could_match( if trait_datum.is_auto_trait() { push_auto_trait_impls_opaque(builder, trait_id, opaque_ty.opaque_ty_id) } - } else if self_ty.bound_var(interner).is_some() - || self_ty.inference_var(interner).is_some() - { + } else if self_ty.is_general_var(interner, binders) { return Err(Floundered); } } // This is needed for the coherence related impls, as well // as for the `Implemented(Foo) :- FromEnv(Foo)` rule. - trait_datum.to_program_clauses(builder); + trait_datum.to_program_clauses(builder, environment); for impl_id in db.impls_for_trait( trait_ref.trait_id, - trait_ref.substitution.parameters(interner), + trait_ref.substitution.as_slice(interner), + binders, ) { - db.impl_datum(impl_id).to_program_clauses(builder); + db.impl_datum(impl_id) + .to_program_clauses(builder, environment); } // If this is a `Foo: Send` (or any auto-trait), then add @@ -279,13 +289,33 @@ fn program_clauses_that_could_match( .. }) | TyData::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => { - db.opaque_ty_data(*opaque_ty_id).to_program_clauses(builder); + db.opaque_ty_data(*opaque_ty_id) + .to_program_clauses(builder, environment); + } + _ => {} + } + + // We don't actually do anything here, but we need to record the types it when logging + match self_ty.data(interner) { + TyData::Apply(ApplicationTy { + name: TypeName::Adt(adt_id), + .. + }) => { + let _ = db.adt_datum(*adt_id); + } + TyData::Apply(ApplicationTy { + name: TypeName::FnDef(fn_def_id), + .. + }) => { + let _ = db.fn_def_datum(*fn_def_id); } _ => {} } if let Some(well_known) = trait_datum.well_known { - builtin_traits::add_builtin_program_clauses(db, builder, well_known, trait_ref)?; + builtin_traits::add_builtin_program_clauses( + db, builder, well_known, trait_ref, binders, + )?; } } DomainGoal::Holds(WhereClause::AliasEq(alias_eq)) => match &alias_eq.alias { @@ -300,23 +330,62 @@ fn program_clauses_that_could_match( .. }) | TyData::Alias(AliasTy::Opaque(OpaqueTy { opaque_ty_id, .. })) => { - db.opaque_ty_data(*opaque_ty_id).to_program_clauses(builder); + db.opaque_ty_data(*opaque_ty_id) + .to_program_clauses(builder, environment); } _ => {} } + // If the self type is a `dyn trait` type, generate program-clauses + // for any associated type bindings it contains. + // FIXME: see the fixme for the analogous code for Implemented goals. + if let TyData::Dyn(_) = trait_self_ty.data(interner) { + dyn_ty::build_dyn_self_ty_clauses(db, builder, trait_self_ty.clone()) + } + db.associated_ty_data(proj.associated_ty_id) - .to_program_clauses(builder) + .to_program_clauses(builder, environment) } AliasTy::Opaque(opaque_ty) => db .opaque_ty_data(opaque_ty.opaque_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), }, - DomainGoal::Holds(WhereClause::LifetimeOutlives(_)) => {} + DomainGoal::Holds(WhereClause::LifetimeOutlives(..)) => { + builder.push_bound_lifetime(|builder, a| { + builder.push_bound_lifetime(|builder, b| { + builder.push_fact_with_constraints( + DomainGoal::Holds(WhereClause::LifetimeOutlives(LifetimeOutlives { + a: a.clone(), + b: b.clone(), + })), + Some(InEnvironment::new( + environment, + Constraint::LifetimeOutlives(a, b), + )), + ); + }) + }); + } + DomainGoal::Holds(WhereClause::TypeOutlives(..)) => { + builder.push_bound_ty(|builder, ty| { + builder.push_bound_lifetime(|builder, lifetime| { + builder.push_fact_with_constraints( + DomainGoal::Holds(WhereClause::TypeOutlives(TypeOutlives { + ty: ty.clone(), + lifetime: lifetime.clone(), + })), + Some(InEnvironment::new( + environment, + Constraint::TypeOutlives(ty, lifetime), + )), + ) + }) + }); + } DomainGoal::WellFormed(WellFormed::Trait(trait_ref)) | DomainGoal::LocalImplAllowed(trait_ref) => { db.trait_datum(trait_ref.trait_id) - .to_program_clauses(builder); + .to_program_clauses(builder, environment); } DomainGoal::ObjectSafe(trait_id) => { if builder.db.is_object_safe(*trait_id) { @@ -353,7 +422,9 @@ fn program_clauses_that_could_match( // Flounder if the self-type is unknown and the trait is non-enumerable. // // e.g., Normalize(::Item = u32) - if (self_ty.is_var(interner)) && trait_datum.is_non_enumerable_trait() { + if (self_ty.is_general_var(interner, binders)) + && trait_datum.is_non_enumerable_trait() + { return Err(Floundered); } @@ -365,18 +436,87 @@ fn program_clauses_that_could_match( push_program_clauses_for_associated_type_values_in_impls_of( builder, + environment, trait_id, trait_parameters, + binders, ); + + if environment.has_compatible_clause(interner) { + push_clauses_for_compatible_normalize( + db, + builder, + interner, + trait_id, + proj.associated_ty_id, + ); + } } AliasTy::Opaque(_) => (), }, - DomainGoal::Compatible(()) | DomainGoal::Reveal(()) => (), + DomainGoal::Compatible | DomainGoal::Reveal => (), }; Ok(clauses) } +/// Adds clauses to allow normalizing possible downstream associated type +/// implementations when in the "compatible" mode. Example clauses: +/// +/// ```notrust +/// for Normalize(<^0.0 as Trait<^0.1>>::Item -> ^0.2) +/// :- Compatible, Implemented(^0.0: Trait<^0.1>), DownstreamType(^0.1), CannotProve +/// for Normalize(<^0.0 as Trait<^0.1>>::Item -> ^0.2) +/// :- Compatible, Implemented(^0.0: Trait<^0.1>), IsFullyVisible(^0.0), DownstreamType(^0.1), CannotProve +/// ``` +fn push_clauses_for_compatible_normalize( + db: &dyn RustIrDatabase, + builder: &mut ClauseBuilder<'_, I>, + interner: &I, + trait_id: TraitId, + associated_ty_id: AssocTypeId, +) { + let trait_datum = db.trait_datum(trait_id); + let trait_binders = trait_datum.binders.map_ref(|b| &b.where_clauses); + builder.push_binders(&trait_binders, |builder, where_clauses| { + let projection = ProjectionTy { + associated_ty_id, + substitution: builder.substitution_in_scope(), + }; + let trait_ref = TraitRef { + trait_id, + substitution: builder.substitution_in_scope(), + }; + let type_parameters: Vec<_> = trait_ref.type_parameters(interner).collect(); + + builder.push_bound_ty(|builder, target_ty| { + for i in 0..type_parameters.len() { + builder.push_clause( + DomainGoal::Normalize(Normalize { + ty: target_ty.clone(), + alias: AliasTy::Projection(projection.clone()), + }), + where_clauses + .iter() + .cloned() + .casted(interner) + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain(iter::once( + WhereClause::Implemented(trait_ref.clone()).cast(interner), + )) + .chain((0..i).map(|j| { + DomainGoal::IsFullyVisible(type_parameters[j].clone()).cast(interner) + })) + .chain(iter::once( + DomainGoal::DownstreamType(type_parameters[i].clone()).cast(interner), + )) + .chain(iter::once(GoalData::CannotProve.intern(interner))), + ); + } + }); + }); +} + /// Generate program clauses from the associated-type values /// found in impls of the given trait. i.e., if `trait_id` = Iterator, /// then we would generate program clauses from each `type Item = ...` @@ -394,21 +534,26 @@ fn program_clauses_that_could_match( #[instrument(level = "debug", skip(builder))] fn push_program_clauses_for_associated_type_values_in_impls_of( builder: &mut ClauseBuilder<'_, I>, + environment: &Environment, trait_id: TraitId, trait_parameters: &[GenericArg], + binders: &CanonicalVarKinds, ) { - for impl_id in builder.db.impls_for_trait(trait_id, trait_parameters) { + for impl_id in builder + .db + .impls_for_trait(trait_id, trait_parameters, binders) + { let impl_datum = builder.db.impl_datum(impl_id); if !impl_datum.is_positive() { continue; } - debug!("impl_id = {:?}", impl_id); + debug!(?impl_id); for &atv_id in &impl_datum.associated_ty_value_ids { let atv = builder.db.associated_ty_value(atv_id); - debug!("atv_id = {:?} atv = {:#?}", atv_id, atv); - atv.to_program_clauses(builder); + debug!(?atv_id, ?atv); + atv.to_program_clauses(builder, environment); } } } @@ -431,18 +576,18 @@ fn match_ty( ) -> Result<(), Floundered> { let interner = builder.interner(); Ok(match ty.data(interner) { - TyData::Apply(application_ty) => match_type_name(builder, interner, application_ty), + TyData::Apply(application_ty) => match_type_name(builder, environment, application_ty), TyData::Placeholder(_) => { builder.push_clause(WellFormed::Ty(ty.clone()), Some(FromEnv::Ty(ty.clone()))); } TyData::Alias(AliasTy::Projection(proj)) => builder .db .associated_ty_data(proj.associated_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TyData::Alias(AliasTy::Opaque(opaque_ty)) => builder .db .opaque_ty_data(opaque_ty.opaque_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TyData::Function(quantified_ty) => { builder.push_fact(WellFormed::Ty(ty.clone())); quantified_ty @@ -460,24 +605,28 @@ fn match_ty( /// Lower a Rust IR application type to logic fn match_type_name( builder: &mut ClauseBuilder<'_, I>, - interner: &I, + environment: &Environment, application: &ApplicationTy, ) { + let interner = builder.interner(); match application.name { - TypeName::Adt(adt_id) => match_adt(builder, adt_id), + TypeName::Adt(adt_id) => builder + .db + .adt_datum(adt_id) + .to_program_clauses(builder, environment), TypeName::OpaqueType(opaque_ty_id) => builder .db .opaque_ty_data(opaque_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TypeName::Error => {} TypeName::AssociatedType(type_id) => builder .db .associated_ty_data(type_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TypeName::FnDef(fn_def_id) => builder .db .fn_def_datum(fn_def_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), TypeName::Tuple(_) | TypeName::Scalar(_) | TypeName::Str @@ -492,20 +641,20 @@ fn match_type_name( } } -fn match_alias_ty(builder: &mut ClauseBuilder<'_, I>, alias: &AliasTy) { +fn match_alias_ty( + builder: &mut ClauseBuilder<'_, I>, + environment: &Environment, + alias: &AliasTy, +) { match alias { AliasTy::Projection(projection_ty) => builder .db .associated_ty_data(projection_ty.associated_ty_id) - .to_program_clauses(builder), + .to_program_clauses(builder, environment), _ => (), } } -fn match_adt(builder: &mut ClauseBuilder<'_, I>, adt_id: AdtId) { - builder.db.adt_datum(adt_id).to_program_clauses(builder) -} - pub fn program_clauses_for_env<'db, I: Interner>( db: &'db dyn RustIrDatabase, environment: &Environment, @@ -519,7 +668,12 @@ pub fn program_clauses_for_env<'db, I: Interner>( let mut closure = last_round.clone(); let mut next_round = FxHashSet::default(); while !last_round.is_empty() { - elaborate_env_clauses(db, &last_round.drain().collect::>(), &mut next_round); + elaborate_env_clauses( + db, + &last_round.drain().collect::>(), + &mut next_round, + environment, + ); last_round.extend( next_round .drain() @@ -527,5 +681,5 @@ pub fn program_clauses_for_env<'db, I: Interner>( ); } - ProgramClauses::from(db.interner(), closure) + ProgramClauses::from_iter(db.interner(), closure) } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builder.rs b/vendor/chalk-solve-0.25.0/src/clauses/builder.rs similarity index 74% rename from vendor/chalk-solve-0.14.0/src/clauses/builder.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builder.rs index 7bd4085617..2359358d4a 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builder.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builder.rs @@ -1,4 +1,3 @@ -use std::iter; use std::marker::PhantomData; use crate::cast::{Cast, CastTo}; @@ -44,9 +43,10 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { pub fn push_fact_with_priority( &mut self, consequence: impl CastTo>, + constraints: impl IntoIterator>>, priority: ClausePriority, ) { - self.push_clause_with_priority(consequence, None::>, priority); + self.push_clause_with_priority(consequence, None::>, constraints, priority); } /// Pushes a clause `forall<..> { consequence :- conditions }` @@ -58,23 +58,34 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { consequence: impl CastTo>, conditions: impl IntoIterator>>, ) { - self.push_clause_with_priority(consequence, conditions, ClausePriority::High) + self.push_clause_with_priority(consequence, conditions, None, ClausePriority::High) } - /// Pushes a clause `forall<..> { consequence :- conditions }` + pub fn push_fact_with_constraints( + &mut self, + consequence: impl CastTo>, + constraints: impl IntoIterator>>, + ) { + self.push_fact_with_priority(consequence, constraints, ClausePriority::High) + } + + /// Pushes a clause `forall<..> { consequence :- conditions ; constraints }` /// into the set of program clauses, meaning that `consequence` - /// can be proven if `conditions` are all true. The `forall<..>` - /// binders will be whichever binders have been pushed (see `push_binders`). + /// can be proven if `conditions` are all true and `constraints` + /// are proven to hold. The `forall<..>` binders will be whichever binders + /// have been pushed (see `push_binders`). pub fn push_clause_with_priority( &mut self, consequence: impl CastTo>, conditions: impl IntoIterator>>, + constraints: impl IntoIterator>>, priority: ClausePriority, ) { let interner = self.db.interner(); let clause = ProgramClauseImplication { consequence: consequence.cast(interner), - conditions: Goals::from(interner, conditions), + conditions: Goals::from_iter(interner, conditions), + constraints: Constraints::from_iter(interner, constraints), priority, }; @@ -87,7 +98,7 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { self.clauses.push( ProgramClauseData(Binders::new( - VariableKinds::from(interner, self.binders.clone()), + VariableKinds::from_iter(interner, self.binders.clone()), clause, )) .intern(interner), @@ -104,7 +115,7 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { /// Accesses the placeholders for the current list of parameters in scope, /// in the form of a `Substitution`. pub fn substitution_in_scope(&self) -> Substitution { - Substitution::from( + Substitution::from_iter( self.db.interner(), self.placeholders_in_scope().iter().cloned(), ) @@ -135,11 +146,11 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { .binders .iter(interner) .zip(old_len..) - .map(|p| p.to_generic_arg(interner)), + .map(|(pk, i)| (i, pk).to_generic_arg(interner)), ); let value = binders.substitute(self.interner(), &self.parameters[old_len..]); - debug!("push_binders: value={:?}", value); + debug!(?value); let res = op(self, value); self.binders.truncate(old_len); @@ -152,11 +163,10 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { /// unaffected and hence the context remains usable. Invokes `op`, /// passing a type representing this new type variable in as an /// argument. - #[allow(dead_code)] pub fn push_bound_ty(&mut self, op: impl FnOnce(&mut Self, Ty)) { let interner = self.interner(); let binders = Binders::new( - VariableKinds::from(interner, iter::once(VariableKind::Ty(TyKind::General))), + VariableKinds::from1(interner, VariableKind::Ty(TyKind::General)), PhantomData::, ); self.push_binders(&binders, |this, PhantomData| { @@ -170,6 +180,28 @@ impl<'me, I: Interner> ClauseBuilder<'me, I> { }); } + /// Push a single binder, for a lifetime, at the end of the binder + /// list. The indices of previously bound variables are + /// unaffected and hence the context remains usable. Invokes `op`, + /// passing a lifetime representing this new lifetime variable in as an + /// argument. + pub fn push_bound_lifetime(&mut self, op: impl FnOnce(&mut Self, Lifetime)) { + let interner = self.interner(); + let binders = Binders::new( + VariableKinds::from1(interner, VariableKind::Lifetime), + PhantomData::, + ); + self.push_binders(&binders, |this, PhantomData| { + let lifetime = this + .placeholders_in_scope() + .last() + .unwrap() + .assert_lifetime_ref(interner) + .clone(); + op(this, lifetime) + }); + } + pub fn interner(&self) -> &'me I { self.db.interner() } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits.rs similarity index 72% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits.rs index d88cd6591b..d21a4b602b 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits.rs @@ -1,5 +1,5 @@ use super::{builder::ClauseBuilder, generalize}; -use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; +use crate::{CanonicalVarKinds, Interner, RustIrDatabase, TraitRef, WellKnownTrait}; use chalk_ir::{Floundered, Substitution, Ty}; mod clone; @@ -15,6 +15,7 @@ pub fn add_builtin_program_clauses( builder: &mut ClauseBuilder<'_, I>, well_known: WellKnownTrait, trait_ref: &TraitRef, + binders: &CanonicalVarKinds, ) -> Result<(), Floundered> { // If `trait_ref` contains bound vars, we want to universally quantify them. // `Generalize` collects them for us. @@ -23,17 +24,17 @@ pub fn add_builtin_program_clauses( builder.push_binders(&generalized, |builder, trait_ref| { let self_ty = trait_ref.self_type_parameter(db.interner()); let ty = self_ty.data(db.interner()); - if let Some(force_impl) = db.force_impl_for(well_known, ty) { - if force_impl { - builder.push_fact(trait_ref.clone()); - } - return Ok(()); - } match well_known { - WellKnownTrait::Sized => sized::add_sized_program_clauses(db, builder, &trait_ref, ty), - WellKnownTrait::Copy => copy::add_copy_program_clauses(db, builder, &trait_ref, ty), - WellKnownTrait::Clone => clone::add_clone_program_clauses(db, builder, &trait_ref, ty), + WellKnownTrait::Sized => { + sized::add_sized_program_clauses(db, builder, &trait_ref, ty, binders) + } + WellKnownTrait::Copy => { + copy::add_copy_program_clauses(db, builder, &trait_ref, ty, binders) + } + WellKnownTrait::Clone => { + clone::add_clone_program_clauses(db, builder, &trait_ref, ty, binders) + } WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn => { fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)? } @@ -57,11 +58,17 @@ pub fn add_builtin_assoc_program_clauses( ) -> Result<(), Floundered> { match well_known { WellKnownTrait::FnOnce => { - fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?; + // If `self_ty` contains bound vars, we want to universally quantify them. + // `Generalize` collects them for us. + let generalized = generalize::Generalize::apply(db.interner(), &self_ty); + + builder.push_binders(&generalized, |builder, self_ty| { + fn_family::add_fn_trait_program_clauses(db, builder, well_known, self_ty)?; + Ok(()) + }) } - _ => {} + _ => Ok(()), } - Ok(()) } /// Given a trait ref `T0: Trait` and a list of types `U0..Un`, pushes a clause of the form diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/clone.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/clone.rs similarity index 71% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/clone.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/clone.rs index 7fb62fbd0a..69943be85d 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/clone.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/clone.rs @@ -1,6 +1,6 @@ use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::TyData; +use chalk_ir::{CanonicalVarKinds, TyData}; use super::copy::add_copy_program_clauses; @@ -9,9 +9,8 @@ pub fn add_clone_program_clauses( builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { - let _interner = db.interner(); - // Implement Clone for types that automaticly implement Copy - add_copy_program_clauses(db, builder, trait_ref, ty); + add_copy_program_clauses(db, builder, trait_ref, ty, binders); } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/copy.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/copy.rs similarity index 61% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/copy.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/copy.rs index 7642ef1578..5fd9c1a17a 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/copy.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/copy.rs @@ -1,8 +1,11 @@ use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{ApplicationTy, Substitution, TyData, TypeName}; +use chalk_ir::{ + ApplicationTy, CanonicalVarKinds, Substitution, TyData, TyKind, TypeName, VariableKind, +}; use std::iter; +use tracing::instrument; fn push_tuple_copy_conditions( db: &dyn RustIrDatabase, @@ -29,11 +32,13 @@ fn push_tuple_copy_conditions( ); } +#[instrument(skip(db, builder))] pub fn add_copy_program_clauses( db: &dyn RustIrDatabase, builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { match ty { TyData::Apply(ApplicationTy { name, substitution }) => match name { @@ -58,11 +63,38 @@ pub fn add_copy_program_clauses( let upvars = upvars.substitute(db.interner(), &closure_fn_substitution); needs_impl_for_tys(db, builder, trait_ref, Some(upvars).into_iter()); } - _ => return, + + // these impls are in libcore + TypeName::Ref(_) + | TypeName::Raw(_) + | TypeName::Scalar(_) + | TypeName::Never + | TypeName::Str => {} + + TypeName::Adt(_) + | TypeName::AssociatedType(_) + | TypeName::Slice + | TypeName::OpaqueType(_) + | TypeName::Error => {} }, + TyData::Function(_) => builder.push_fact(trait_ref.clone()), - // TODO(areredify) - // when #368 lands, extend this to handle everything accordingly - _ => return, + + TyData::InferenceVar(_, kind) => match kind { + TyKind::Integer | TyKind::Float => builder.push_fact(trait_ref.clone()), + TyKind::General => {} + }, + + TyData::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyKind::Integer) | VariableKind::Ty(TyKind::Float) => { + builder.push_fact(trait_ref.clone()) + } + VariableKind::Ty(_) | VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + + TyData::Alias(_) | TyData::Dyn(_) | TyData::Placeholder(_) => {} }; } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/fn_family.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/fn_family.rs similarity index 83% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/fn_family.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/fn_family.rs index ca878026b9..2012367b68 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/fn_family.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/fn_family.rs @@ -4,8 +4,8 @@ use crate::rust_ir::{ClosureKind, FnDefInputsAndOutputDatum, WellKnownTrait}; use crate::{Interner, RustIrDatabase, TraitRef}; use chalk_ir::cast::Cast; use chalk_ir::{ - AliasTy, ApplicationTy, Binders, Floundered, Normalize, ProjectionTy, Substitution, TraitId, - Ty, TyData, TypeName, VariableKinds, + AliasTy, ApplicationTy, Binders, Floundered, Normalize, ProjectionTy, Safety, Substitution, + TraitId, Ty, TyData, TypeName, VariableKinds, }; fn push_clauses( @@ -24,7 +24,7 @@ fn push_clauses( }) .intern(interner); let substitution = - Substitution::from(interner, &[self_ty.cast(interner), tupled.cast(interner)]); + Substitution::from_iter(interner, &[self_ty.cast(interner), tupled.cast(interner)]); builder.push_fact(TraitRef { trait_id, substitution: substitution.clone(), @@ -68,7 +68,7 @@ fn push_clauses_for_apply( .iter() .cloned() .map(|ty| ty.cast(interner)); - let arg_sub = Substitution::from(interner, arg_sub); + let arg_sub = Substitution::from_iter(interner, arg_sub); let output_ty = inputs_and_output.return_type; push_clauses( @@ -99,22 +99,19 @@ pub fn add_fn_trait_program_clauses( TyData::Apply(apply) => match apply.name { TypeName::FnDef(fn_def_id) => { let fn_def_datum = builder.db.fn_def_datum(fn_def_id); - let bound = fn_def_datum - .binders - .substitute(builder.interner(), &apply.substitution); - let self_ty = ApplicationTy { - name: apply.name, - substitution: builder.substitution_in_scope(), + if fn_def_datum.safety == Safety::Safe && !fn_def_datum.variadic { + let bound = fn_def_datum + .binders + .substitute(builder.interner(), &apply.substitution); + push_clauses_for_apply( + db, + builder, + well_known, + trait_id, + self_ty, + &bound.inputs_and_output, + ); } - .intern(interner); - push_clauses_for_apply( - db, - builder, - well_known, - trait_id, - self_ty, - &bound.inputs_and_output, - ); Ok(()) } TypeName::Closure(closure_id) => { @@ -143,15 +140,15 @@ pub fn add_fn_trait_program_clauses( } _ => Ok(()), }, - TyData::Function(fn_val) => { + TyData::Function(fn_val) if fn_val.safety == Safety::Safe && !fn_val.variadic => { let (binders, orig_sub) = fn_val.into_binders_and_value(interner); - let bound_ref = Binders::new(VariableKinds::from(interner, binders), orig_sub); + let bound_ref = Binders::new(VariableKinds::from_iter(interner, binders), orig_sub); builder.push_binders(&bound_ref, |builder, orig_sub| { // The last parameter represents the function return type let (arg_sub, fn_output_ty) = orig_sub - .parameters(interner) + .as_slice(interner) .split_at(orig_sub.len(interner) - 1); - let arg_sub = Substitution::from(interner, arg_sub); + let arg_sub = Substitution::from_iter(interner, arg_sub); let output_ty = fn_output_ty[0].assert_ty_ref(interner).clone(); push_clauses( diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/sized.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/sized.rs similarity index 58% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/sized.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/sized.rs index fc5a525bc7..786c705a29 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/sized.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/sized.rs @@ -2,8 +2,11 @@ use std::iter; use crate::clauses::builtin_traits::needs_impl_for_tys; use crate::clauses::ClauseBuilder; +use crate::rust_ir::AdtKind; use crate::{Interner, RustIrDatabase, TraitRef}; -use chalk_ir::{AdtId, ApplicationTy, Substitution, TyData, TypeName}; +use chalk_ir::{ + AdtId, ApplicationTy, CanonicalVarKinds, Substitution, TyData, TyKind, TypeName, VariableKind, +}; fn push_adt_sized_conditions( db: &dyn RustIrDatabase, @@ -14,22 +17,25 @@ fn push_adt_sized_conditions( ) { let adt_datum = db.adt_datum(adt_id); - // ADTs with no fields are always Sized - if adt_datum.binders.skip_binders().fields.is_empty() { + // WF ensures that all enums are Sized, so we only have to consider structs. + if adt_datum.kind != AdtKind::Struct { builder.push_fact(trait_ref.clone()); return; } let interner = db.interner(); - // To check if an ADT type S<..> is Sized, we only have to look at its last field. + // To check if a struct S<..> is Sized, we only have to look at its last field. // This is because the WF checks for ADTs require that all the other fields must be Sized. let last_field_ty = adt_datum .binders - .map_ref(|b| b.fields.last().unwrap()) - .substitute(interner, substitution); + .map_ref(|b| &b.variants) + .substitute(interner, substitution) + .into_iter() + .take(1) // We have a struct so we're guaranteed one variant + .flat_map(|mut v| v.fields.pop()); - needs_impl_for_tys(db, builder, trait_ref, iter::once(last_field_ty)); + needs_impl_for_tys(db, builder, trait_ref, last_field_ty); } fn push_tuple_sized_conditions( @@ -65,6 +71,7 @@ pub fn add_sized_program_clauses( builder: &mut ClauseBuilder<'_, I>, trait_ref: &TraitRef, ty: &TyData, + binders: &CanonicalVarKinds, ) { match ty { TyData::Apply(ApplicationTy { name, substitution }) => match name { @@ -81,11 +88,31 @@ pub fn add_sized_program_clauses( | TypeName::Scalar(_) | TypeName::Raw(_) | TypeName::Ref(_) => builder.push_fact(trait_ref.clone()), - _ => return, + + TypeName::AssociatedType(_) + | TypeName::Slice + | TypeName::OpaqueType(_) + | TypeName::Str + | TypeName::Error => {} }, - TyData::Function(_) => builder.push_fact(trait_ref.clone()), - // TODO(areredify) - // when #368 lands, extend this to handle everything accordingly - _ => return, + + TyData::Function(_) + | TyData::InferenceVar(_, TyKind::Float) + | TyData::InferenceVar(_, TyKind::Integer) => builder.push_fact(trait_ref.clone()), + + TyData::BoundVar(bound_var) => { + let var_kind = &binders.at(db.interner(), bound_var.index).kind; + match var_kind { + VariableKind::Ty(TyKind::Integer) | VariableKind::Ty(TyKind::Float) => { + builder.push_fact(trait_ref.clone()) + } + VariableKind::Ty(_) | VariableKind::Const(_) | VariableKind::Lifetime => {} + } + } + + TyData::InferenceVar(_, TyKind::General) + | TyData::Placeholder(_) + | TyData::Dyn(_) + | TyData::Alias(_) => {} } } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/unsize.rs b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/unsize.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/unsize.rs rename to vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/unsize.rs index df1fd09941..e2bd3f7f1e 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/builtin_traits/unsize.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/builtin_traits/unsize.rs @@ -2,6 +2,7 @@ use std::collections::HashSet; use std::iter; use crate::clauses::ClauseBuilder; +use crate::rust_ir::AdtKind; use crate::{Interner, RustIrDatabase, TraitRef, WellKnownTrait}; use chalk_ir::{ cast::Cast, @@ -9,7 +10,7 @@ use chalk_ir::{ visit::{visitors::FindAny, SuperVisit, Visit, VisitResult, Visitor}, ApplicationTy, Binders, Const, ConstValue, DebruijnIndex, DomainGoal, DynTy, EqGoal, Goal, LifetimeOutlives, QuantifiedWhereClauses, Substitution, TraitId, Ty, TyData, TypeName, - WhereClause, + TypeOutlives, WhereClause, }; struct UnsizeParameterCollector<'a, I: Interner> { @@ -42,14 +43,11 @@ impl<'a, I: Interner> Visitor<'a, I> for UnsizeParameterCollector<'a, I> { fn visit_const(&mut self, constant: &Const, outer_binder: DebruijnIndex) -> Self::Result { let interner = self.interner; - match constant.data(interner).value { - ConstValue::BoundVar(bound_var) => { - // check if bound var refers to the outermost binder - if bound_var.debruijn.shifted_in() == outer_binder { - self.parameters.insert(bound_var.index); - } + if let ConstValue::BoundVar(bound_var) = constant.data(interner).value { + // check if bound var refers to the outermost binder + if bound_var.debruijn.shifted_in() == outer_binder { + self.parameters.insert(bound_var.index); } - _ => (), } } @@ -140,12 +138,11 @@ fn principal_id<'a, I: Interner>( ) -> Option> { let interner = db.interner(); - return bounds + bounds .skip_binders() .iter(interner) .filter_map(|b| b.trait_id()) - .filter(|&id| !db.trait_datum(id).is_auto_trait()) - .next(); + .find(|&id| !db.trait_datum(id).is_auto_trait()) } fn auto_trait_ids<'a, I: Interner>( @@ -239,7 +236,7 @@ pub fn add_unsize_program_clauses( // should be equal to target type. let new_source_ty = TyData::Dyn(DynTy { bounds: bounds_a.map_ref(|bounds| { - QuantifiedWhereClauses::from( + QuantifiedWhereClauses::from_iter( interner, bounds.iter(interner).filter(|bound| { let trait_id = match bound.trait_id() { @@ -276,13 +273,7 @@ pub fn add_unsize_program_clauses( } // T -> dyn Trait + 'a - ( - _, - TyData::Dyn(DynTy { - bounds, - lifetime: _, - }), - ) => { + (_, TyData::Dyn(DynTy { bounds, lifetime })) => { // Check if all traits in trait object are object safe let object_safe_goals = bounds .skip_binders() @@ -304,7 +295,12 @@ pub fn add_unsize_program_clauses( } .cast(interner); - // FIXME(areredify) we need a `source_ty: 'lifetime` goal here + // Check that `source_ty` outlives `'a` + let source_ty_outlives: Goal<_> = WhereClause::TypeOutlives(TypeOutlives { + ty: source_ty, + lifetime: lifetime.clone(), + }) + .cast(interner); builder.push_clause( trait_ref.clone(), @@ -312,7 +308,8 @@ pub fn add_unsize_program_clauses( .iter(interner) .map(|bound| bound.clone().cast::>(interner)) .chain(object_safe_goals) - .chain(iter::once(self_sized_goal.cast(interner))), + .chain(iter::once(self_sized_goal.cast(interner))) + .chain(iter::once(source_ty_outlives)), ); } @@ -337,40 +334,53 @@ pub fn add_unsize_program_clauses( builder.push_clause(trait_ref.clone(), iter::once(eq_goal)); } - // Struct -> Struct - // Unsizing of enums is not allowed + // Adt -> Adt ( TyData::Apply(ApplicationTy { - name: TypeName::Adt(struct_id_a), + name: TypeName::Adt(adt_id_a), substitution: substitution_a, }), TyData::Apply(ApplicationTy { - name: TypeName::Adt(struct_id_b), + name: TypeName::Adt(adt_id_b), substitution: substitution_b, }), ) => { - if struct_id_a != struct_id_b { + if adt_id_a != adt_id_b { return; } - let struct_id = *struct_id_a; - let struct_datum = db.adt_datum(struct_id); - let fields_len = struct_datum.binders.skip_binders().fields.len(); + let adt_id = *adt_id_a; + let adt_datum = db.adt_datum(adt_id); + + // Unsizing of enums is not allowed + if adt_datum.kind == AdtKind::Enum { + return; + } + + // We have a `struct` so we're guaranteed a single variant + let fields_len = adt_datum + .binders + .skip_binders() + .variants + .last() + .unwrap() + .fields + .len(); if fields_len == 0 { return; } - let adt_tail_field = struct_datum + let adt_tail_field = adt_datum .binders - .map_ref(|bound| bound.fields.last().unwrap()); + .map_ref(|bound| bound.variants.last().unwrap().fields.last().unwrap()); // Collect unsize parameters that last field contains and // ensure there at least one of them. let unsize_parameter_candidates = outer_binder_parameters_used(interner, &adt_tail_field); - if unsize_parameter_candidates.len() == 0 { + if unsize_parameter_candidates.is_empty() { return; } // Ensure none of the other fields mention the parameters used @@ -379,16 +389,16 @@ pub fn add_unsize_program_clauses( // i.e. the struct generic arguments binder. if uses_outer_binder_params( interner, - &struct_datum + &adt_datum .binders - .map_ref(|bound| &bound.fields[..fields_len - 1]), + .map_ref(|bound| &bound.variants.last().unwrap().fields[..fields_len - 1]), &unsize_parameter_candidates, ) { return; } - let parameters_a = substitution_a.parameters(interner); - let parameters_b = substitution_b.parameters(interner); + let parameters_a = substitution_a.as_slice(interner); + let parameters_b = substitution_b.as_slice(interner); // Check that the source adt with the target's // unsizing parameters is equal to the target. // We construct a new substitution where if a parameter is used in the @@ -398,7 +408,7 @@ pub fn add_unsize_program_clauses( // // In order for the coercion to be valid, target struct and // struct with this newly constructed substitution applied to it should be equal. - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, parameters_a.iter().enumerate().map(|(i, p)| { if unsize_parameter_candidates.contains(&i) { @@ -411,7 +421,7 @@ pub fn add_unsize_program_clauses( let eq_goal = EqGoal { a: TyData::Apply(ApplicationTy { - name: TypeName::Adt(struct_id), + name: TypeName::Adt(adt_id), substitution, }) .intern(interner) @@ -427,7 +437,7 @@ pub fn add_unsize_program_clauses( // Check that `TailField: Unsize>` let last_field_unsizing_goal: Goal = TraitRef { trait_id: unsize_trait_id, - substitution: Substitution::from( + substitution: Substitution::from_iter( interner, [source_tail_field, target_tail_field].iter().cloned(), ), @@ -463,7 +473,7 @@ pub fn add_unsize_program_clauses( // last element is equal to the target. let new_tuple = ApplicationTy { name: TypeName::Tuple(*arity), - substitution: Substitution::from( + substitution: Substitution::from_iter( interner, substitution_a .iter(interner) @@ -483,7 +493,10 @@ pub fn add_unsize_program_clauses( // Check that `T: Unsize` let last_field_unsizing_goal: Goal = TraitRef { trait_id: unsize_trait_id, - substitution: Substitution::from(interner, [tail_ty_a, tail_ty_b].iter().cloned()), + substitution: Substitution::from_iter( + interner, + [tail_ty_a, tail_ty_b].iter().cloned(), + ), } .cast(interner); diff --git a/vendor/chalk-solve-0.14.0/src/clauses/dyn_ty.rs b/vendor/chalk-solve-0.25.0/src/clauses/dyn_ty.rs similarity index 98% rename from vendor/chalk-solve-0.14.0/src/clauses/dyn_ty.rs rename to vendor/chalk-solve-0.25.0/src/clauses/dyn_ty.rs index ad54a39719..6859437e1d 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/dyn_ty.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/dyn_ty.rs @@ -73,6 +73,7 @@ pub(super) fn build_dyn_self_ty_clauses( // Associated item bindings are just taken as facts (?) WhereClause::AliasEq(_) => builder.push_fact(wc), WhereClause::LifetimeOutlives(..) => {} + WhereClause::TypeOutlives(..) => {} }); } }); @@ -162,6 +163,7 @@ pub fn super_traits( } WhereClause::AliasEq(_) => None, WhereClause::LifetimeOutlives(..) => None, + WhereClause::TypeOutlives(..) => None, }) }) .collect::>() diff --git a/vendor/chalk-solve-0.14.0/src/clauses/env_elaborator.rs b/vendor/chalk-solve-0.25.0/src/clauses/env_elaborator.rs similarity index 77% rename from vendor/chalk-solve-0.14.0/src/clauses/env_elaborator.rs rename to vendor/chalk-solve-0.25.0/src/clauses/env_elaborator.rs index 5b239a129c..ddce951277 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/env_elaborator.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/env_elaborator.rs @@ -6,12 +6,12 @@ use crate::FromEnv; use crate::ProgramClause; use crate::RustIrDatabase; use crate::Ty; -use crate::TyData; +use crate::{debug_span, TyData}; use chalk_ir::interner::Interner; use chalk_ir::visit::{Visit, Visitor}; -use chalk_ir::DebruijnIndex; +use chalk_ir::{DebruijnIndex, Environment}; use rustc_hash::FxHashSet; -use tracing::debug; +use tracing::instrument; /// When proving a `FromEnv` goal, we elaborate all `FromEnv` goals /// found in the environment. @@ -23,10 +23,11 @@ pub(super) fn elaborate_env_clauses( db: &dyn RustIrDatabase, in_clauses: &[ProgramClause], out: &mut FxHashSet>, + environment: &Environment, ) { let mut this_round = vec![]; in_clauses.visit_with( - &mut EnvElaborator::new(db, &mut this_round), + &mut EnvElaborator::new(db, &mut this_round, environment), DebruijnIndex::INNERMOST, ); out.extend(this_round); @@ -35,13 +36,19 @@ pub(super) fn elaborate_env_clauses( struct EnvElaborator<'me, I: Interner> { db: &'me dyn RustIrDatabase, builder: ClauseBuilder<'me, I>, + environment: &'me Environment, } impl<'me, I: Interner> EnvElaborator<'me, I> { - fn new(db: &'me dyn RustIrDatabase, out: &'me mut Vec>) -> Self { + fn new( + db: &'me dyn RustIrDatabase, + out: &'me mut Vec>, + environment: &'me Environment, + ) -> Self { EnvElaborator { db, builder: ClauseBuilder::new(db, out), + environment, } } } @@ -56,15 +63,15 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { fn interner(&self) -> &'me I { self.db.interner() } - + #[instrument(level = "debug", skip(self, _outer_binder))] fn visit_ty(&mut self, ty: &Ty, _outer_binder: DebruijnIndex) { - debug!("EnvElaborator::visit_ty(ty={:?})", ty); - let interner = self.db.interner(); - match ty.data(interner) { + match ty.data(self.interner()) { TyData::Apply(application_ty) => { - match_type_name(&mut self.builder, interner, application_ty) + match_type_name(&mut self.builder, self.environment, application_ty) + } + TyData::Alias(alias_ty) => { + match_alias_ty(&mut self.builder, self.environment, alias_ty) } - TyData::Alias(alias_ty) => match_alias_ty(&mut self.builder, alias_ty), TyData::Placeholder(_) => {} // FIXME(#203) -- We haven't fully figured out the implied @@ -77,12 +84,12 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { fn visit_domain_goal(&mut self, domain_goal: &DomainGoal, outer_binder: DebruijnIndex) { if let DomainGoal::FromEnv(from_env) = domain_goal { - debug!("EnvElaborator::visit_domain_goal(from_env={:?})", from_env); + debug_span!("visit_domain_goal", ?from_env); match from_env { FromEnv::Trait(trait_ref) => { let trait_datum = self.db.trait_datum(trait_ref.trait_id); - trait_datum.to_program_clauses(&mut self.builder); + trait_datum.to_program_clauses(&mut self.builder, self.environment); // If we know that `T: Iterator`, then we also know // things about `::Item`, so push those @@ -90,7 +97,7 @@ impl<'me, I: Interner> Visitor<'me, I> for EnvElaborator<'me, I> { for &associated_ty_id in &trait_datum.associated_ty_ids { self.db .associated_ty_data(associated_ty_id) - .to_program_clauses(&mut self.builder); + .to_program_clauses(&mut self.builder, self.environment); } } FromEnv::Ty(ty) => ty.visit_with(self, outer_binder), diff --git a/vendor/chalk-solve-0.14.0/src/clauses/generalize.rs b/vendor/chalk-solve-0.25.0/src/clauses/generalize.rs similarity index 95% rename from vendor/chalk-solve-0.14.0/src/clauses/generalize.rs rename to vendor/chalk-solve-0.25.0/src/clauses/generalize.rs index fc5e5a7c3a..42f80ac9ec 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/generalize.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/generalize.rs @@ -34,7 +34,10 @@ impl Generalize<'_, I> { let value = value .fold_with(&mut generalize, DebruijnIndex::INNERMOST) .unwrap(); - Binders::new(VariableKinds::from(interner, generalize.binders), value) + Binders::new( + VariableKinds::from_iter(interner, generalize.binders), + value, + ) } } diff --git a/vendor/chalk-solve-0.14.0/src/clauses/program_clauses.rs b/vendor/chalk-solve-0.25.0/src/clauses/program_clauses.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/clauses/program_clauses.rs rename to vendor/chalk-solve-0.25.0/src/clauses/program_clauses.rs index 81610cba97..2f9ed502c4 100644 --- a/vendor/chalk-solve-0.14.0/src/clauses/program_clauses.rs +++ b/vendor/chalk-solve-0.25.0/src/clauses/program_clauses.rs @@ -11,7 +11,7 @@ use tracing::instrument; /// or struct definition) into its associated "program clauses" -- /// that is, into the lowered, logical rules that it defines. pub trait ToProgramClauses { - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>); + fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment); } impl ToProgramClauses for ImplDatum { @@ -28,7 +28,11 @@ impl ToProgramClauses for ImplDatum { /// generate nothing -- this is just a way to *opt out* from the /// default auto trait impls, it doesn't have any positive effect /// on its own. - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { if self.is_positive() { let binders = self.binders.map_ref(|b| (&b.trait_ref, &b.where_clauses)); builder.push_binders(&binders, |builder, (trait_ref, where_clauses)| { @@ -64,7 +68,11 @@ impl ToProgramClauses for AssociatedTyValue { /// Implemented(Iter<'a, T>: 'a). // (2) /// } /// ``` - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let impl_datum = builder.db.impl_datum(self.impl_id); let associated_ty = builder.db.associated_ty_data(self.associated_ty_id); @@ -120,17 +128,22 @@ impl ToProgramClauses for AssociatedTyValue { } impl ToProgramClauses for OpaqueTyDatum { - /// Given `opaque type T<..>: A + B = HiddenTy;`, we generate: + /// Given `opaque type T: A + B = HiddenTy where U: C;`, we generate: /// /// ```notrust - /// AliasEq(T<..> = HiddenTy) :- Reveal. - /// AliasEq(T<..> = !T<..>). - /// Implemented(!T<..>: A). - /// Implemented(!T<..>: B). + /// AliasEq(T = HiddenTy) :- Reveal. + /// AliasEq(T = !T). + /// WF(T) :- WF(U: C). + /// Implemented(!T: A). + /// Implemented(!T: B). /// ``` /// where `!T<..>` is the placeholder for the unnormalized type `T<..>`. #[instrument(level = "debug", skip(builder))] - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { builder.push_binders(&self.bound, |builder, opaque_ty_bound| { let interner = builder.interner(); let substitution = builder.substitution_in_scope(); @@ -156,19 +169,29 @@ impl ToProgramClauses for OpaqueTyDatum { } .cast(interner), ), - iter::once(DomainGoal::Reveal(())), + iter::once(DomainGoal::Reveal), ); // AliasEq(T<..> = !T<..>). builder.push_fact(DomainGoal::Holds( AliasEq { - alias: alias.clone(), + alias, ty: alias_placeholder_ty.clone(), } .cast(interner), )); - let substitution = Substitution::from1(interner, alias_placeholder_ty.clone()); + // WF(!T<..>) :- WF(WC). + builder.push_binders(&opaque_ty_bound.where_clauses, |builder, where_clauses| { + builder.push_clause( + WellFormed::Ty(alias_placeholder_ty.clone()), + where_clauses + .into_iter() + .map(|wc| wc.into_well_formed_goal(interner)), + ); + }); + + let substitution = Substitution::from1(interner, alias_placeholder_ty); for bound in opaque_ty_bound.bounds { // Implemented(!T<..>: Bound). let bound_with_placeholder_ty = bound.substitute(interner, &substitution); @@ -220,9 +243,9 @@ fn well_formed_program_clauses<'a, I, Wc>( { let interner = builder.interner(); let appl_ty = application_ty(builder, type_name); - let ty = appl_ty.clone().intern(interner); + let ty = appl_ty.intern(interner); builder.push_clause( - WellFormed::Ty(ty.clone()), + WellFormed::Ty(ty), where_clauses .cloned() .map(|qwc| qwc.into_well_formed_goal(interner)), @@ -248,8 +271,8 @@ fn well_formed_program_clauses<'a, I, Wc>( /// /// - builder -- the clause builder. We assume all the generic types from `Foo` are in scope /// - type_name -- in our example above, the name `Foo` -fn fully_visible_program_clauses<'a, I>( - builder: &'a mut ClauseBuilder<'_, I>, +fn fully_visible_program_clauses( + builder: &mut ClauseBuilder<'_, I>, type_name: impl CastTo>, ) where I: Interner, @@ -258,7 +281,7 @@ fn fully_visible_program_clauses<'a, I>( let appl_ty = application_ty(builder, type_name); let ty = appl_ty.clone().intern(interner); builder.push_clause( - DomainGoal::IsFullyVisible(ty.clone()), + DomainGoal::IsFullyVisible(ty), appl_ty .type_parameters(interner) .map(|typ| DomainGoal::IsFullyVisible(typ).cast::>(interner)), @@ -294,7 +317,7 @@ fn implied_bounds_program_clauses<'a, I, Wc>( { let interner = builder.interner(); let appl_ty = application_ty(builder, type_name); - let ty = appl_ty.clone().intern(interner); + let ty = appl_ty.intern(interner); for qwc in where_clauses { builder.push_binders(&qwc, |builder, wc| { @@ -353,7 +376,11 @@ impl ToProgramClauses for AdtDatum { /// ``` /// #[instrument(level = "debug", skip(builder))] - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let interner = builder.interner(); let binders = self.binders.map_ref(|b| &b.where_clauses); let id = self.id; @@ -442,7 +469,11 @@ impl ToProgramClauses for FnDefDatum { /// } /// ``` #[instrument(level = "debug", skip(builder))] - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let binders = self.binders.map_ref(|b| &b.where_clauses); let id = self.id; @@ -570,7 +601,7 @@ impl ToProgramClauses for TraitDatum { /// To implement fundamental traits, we simply just do not add the rule above that allows /// upstream types to implement upstream traits. Fundamental traits are not allowed to /// compatibly do that. - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>, environment: &Environment) { let interner = builder.interner(); let binders = self.binders.map_ref(|b| &b.where_clauses); builder.push_binders(&binders, |builder, where_clauses| { @@ -596,30 +627,56 @@ impl ToProgramClauses for TraitDatum { // conditions. let type_parameters: Vec<_> = trait_ref.type_parameters(interner).collect(); - // Drop trait can't have downstream implementation because it can only - // be implemented with the same genericity as the struct definition, - // i.e. Drop implementation for `struct S {}` is forced to be - // `impl Drop for S { ... }`. That means that orphan rules - // prevent Drop from being implemented in downstream crates. - if self.well_known != Some(WellKnownTrait::Drop) { - // Add all cases for potential downstream impls that could exist - for i in 0..type_parameters.len() { + if environment.has_compatible_clause(interner) { + // Note: even though we do check for a `Compatible` clause here, + // we also keep it as a condition for the clauses below, purely + // for logical consistency. But really, it's not needed and could be + // removed. + + // Drop trait can't have downstream implementation because it can only + // be implemented with the same genericity as the struct definition, + // i.e. Drop implementation for `struct S {}` is forced to be + // `impl Drop for S { ... }`. That means that orphan rules + // prevent Drop from being implemented in downstream crates. + if self.well_known != Some(WellKnownTrait::Drop) { + // Add all cases for potential downstream impls that could exist + for i in 0..type_parameters.len() { + builder.push_clause( + trait_ref.clone(), + where_clauses + .iter() + .cloned() + .casted(interner) + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain((0..i).map(|j| { + DomainGoal::IsFullyVisible(type_parameters[j].clone()) + .cast(interner) + })) + .chain(iter::once( + DomainGoal::DownstreamType(type_parameters[i].clone()) + .cast(interner), + )) + .chain(iter::once(GoalData::CannotProve.intern(interner))), + ); + } + } + + // Fundamental traits can be reasoned about negatively without any ambiguity, so no + // need for this rule if the trait is fundamental. + if !self.flags.fundamental { builder.push_clause( trait_ref.clone(), where_clauses .iter() .cloned() .casted(interner) - .chain(iter::once(DomainGoal::Compatible(()).cast(interner))) - .chain((0..i).map(|j| { - DomainGoal::IsFullyVisible(type_parameters[j].clone()) - .cast(interner) - })) - .chain(iter::once( - DomainGoal::DownstreamType(type_parameters[i].clone()) - .cast(interner), - )) - .chain(iter::once(GoalData::CannotProve(()).intern(interner))), + .chain(iter::once(DomainGoal::Compatible.cast(interner))) + .chain( + trait_ref + .type_parameters(interner) + .map(|ty| DomainGoal::IsUpstream(ty).cast(interner)), + ) + .chain(iter::once(GoalData::CannotProve.intern(interner))), ); } } @@ -640,25 +697,6 @@ impl ToProgramClauses for TraitDatum { } } - // Fundamental traits can be reasoned about negatively without any ambiguity, so no - // need for this rule if the trait is fundamental. - if !self.flags.fundamental { - builder.push_clause( - trait_ref.clone(), - where_clauses - .iter() - .cloned() - .casted(interner) - .chain(iter::once(DomainGoal::Compatible(()).cast(interner))) - .chain( - trait_ref - .type_parameters(interner) - .map(|ty| DomainGoal::IsUpstream(ty).cast(interner)), - ) - .chain(iter::once(GoalData::CannotProve(()).intern(interner))), - ); - } - // Reverse implied bound rules: given (e.g.) `trait Foo: Bar + Baz`, // we create rules like: // @@ -685,7 +723,7 @@ impl ToProgramClauses for TraitDatum { // ``` // Implemented(T: Foo) :- FromEnv(T: Foo) // ``` - builder.push_clause(trait_ref.clone(), Some(trait_ref.clone().from_env())); + builder.push_clause(trait_ref.clone(), Some(trait_ref.from_env())); }); } } @@ -759,7 +797,11 @@ impl ToProgramClauses for AssociatedTyDatum { /// FromEnv(Self: Foo) :- FromEnv((Foo::Assoc)). /// } /// ``` - fn to_program_clauses(&self, builder: &mut ClauseBuilder<'_, I>) { + fn to_program_clauses( + &self, + builder: &mut ClauseBuilder<'_, I>, + _environment: &Environment, + ) { let interner = builder.interner(); let binders = self.binders.map_ref(|b| (&b.where_clauses, &b.bounds)); builder.push_binders(&binders, |builder, (where_clauses, bounds)| { @@ -793,7 +835,7 @@ impl ToProgramClauses for AssociatedTyDatum { // forall { // AliasEq(::Assoc = (Foo::Assoc)). // } - builder.push_fact_with_priority(projection_eq, ClausePriority::Low); + builder.push_fact_with_priority(projection_eq, None, ClausePriority::Low); // Well-formedness of projection type. // diff --git a/vendor/chalk-solve-0.14.0/src/coherence.rs b/vendor/chalk-solve-0.25.0/src/coherence.rs similarity index 93% rename from vendor/chalk-solve-0.14.0/src/coherence.rs rename to vendor/chalk-solve-0.25.0/src/coherence.rs index 060ab6d223..31384c0d82 100644 --- a/vendor/chalk-solve-0.14.0/src/coherence.rs +++ b/vendor/chalk-solve-0.25.0/src/coherence.rs @@ -1,6 +1,6 @@ use petgraph::prelude::*; -use crate::solve::SolverChoice; +use crate::solve::Solver; use crate::RustIrDatabase; use chalk_ir::interner::Interner; use chalk_ir::{self, ImplId, TraitId}; @@ -11,9 +11,9 @@ use std::sync::Arc; pub mod orphan; mod solve; -pub struct CoherenceSolver<'db, I: Interner> { - db: &'db dyn RustIrDatabase, - solver_choice: SolverChoice, +pub struct CoherenceSolver<'a, I: Interner> { + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, trait_id: TraitId, } @@ -71,19 +71,19 @@ impl SpecializationPriorities { #[derive(Copy, Clone, Default, PartialOrd, Ord, PartialEq, Eq, Debug)] pub struct SpecializationPriority(usize); -impl<'db, I> CoherenceSolver<'db, I> +impl<'a, I> CoherenceSolver<'a, I> where I: Interner, { /// Constructs a new `CoherenceSolver`. pub fn new( - db: &'db dyn RustIrDatabase, - solver_choice: SolverChoice, + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, trait_id: TraitId, ) -> Self { Self { db, - solver_choice, + solver_builder, trait_id, } } diff --git a/vendor/chalk-solve-0.14.0/src/coherence/orphan.rs b/vendor/chalk-solve-0.25.0/src/coherence/orphan.rs similarity index 76% rename from vendor/chalk-solve-0.14.0/src/coherence/orphan.rs rename to vendor/chalk-solve-0.25.0/src/coherence/orphan.rs index b339def322..f8e06b901e 100644 --- a/vendor/chalk-solve-0.14.0/src/coherence/orphan.rs +++ b/vendor/chalk-solve-0.25.0/src/coherence/orphan.rs @@ -1,6 +1,6 @@ use crate::coherence::CoherenceError; use crate::ext::GoalExt; -use crate::solve::SolverChoice; +use crate::solve::Solver; use crate::RustIrDatabase; use chalk_ir::cast::*; use chalk_ir::interner::Interner; @@ -14,14 +14,14 @@ use tracing::{debug, instrument}; // forall { LocalImplAllowed(MyType: Trait) } // // This must be provable in order to pass the orphan check. -#[instrument(level = "debug", skip(db, solver_choice))] +#[instrument(level = "debug", skip(db, solver))] pub fn perform_orphan_check( db: &dyn RustIrDatabase, - solver_choice: SolverChoice, + solver: &mut dyn Solver, impl_id: ImplId, ) -> Result<(), CoherenceError> { let impl_datum = db.impl_datum(impl_id); - debug!("impl_datum={:#?}", impl_datum); + debug!(?impl_datum); let impl_allowed: Goal = impl_datum .binders @@ -32,15 +32,12 @@ pub fn perform_orphan_check( .cast(db.interner()); let canonical_goal = &impl_allowed.into_closed_goal(db.interner()); - let is_allowed = solver_choice - .into_solver() - .solve(db, canonical_goal) - .is_some(); + let is_allowed = solver.solve(db, canonical_goal).is_some(); debug!("overlaps = {:?}", is_allowed); if !is_allowed { let trait_id = impl_datum.trait_id(); - Err(CoherenceError::FailedOrphanCheck(trait_id))?; + return Err(CoherenceError::FailedOrphanCheck(trait_id)); } Ok(()) diff --git a/vendor/chalk-solve-0.14.0/src/coherence/solve.rs b/vendor/chalk-solve-0.25.0/src/coherence/solve.rs similarity index 94% rename from vendor/chalk-solve-0.14.0/src/coherence/solve.rs rename to vendor/chalk-solve-0.25.0/src/coherence/solve.rs index 35cd035201..98081ce9b8 100644 --- a/vendor/chalk-solve-0.14.0/src/coherence/solve.rs +++ b/vendor/chalk-solve-0.25.0/src/coherence/solve.rs @@ -40,7 +40,7 @@ impl CoherenceSolver<'_, I> { (true, false) => record_specialization(l_id, r_id), (false, true) => record_specialization(r_id, l_id), (_, _) => { - Err(CoherenceError::OverlappingImpls(self.trait_id))?; + return Err(CoherenceError::OverlappingImpls(self.trait_id)); } } } @@ -93,13 +93,13 @@ impl CoherenceSolver<'_, I> { let lhs_params = lhs_bound .trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .cloned(); let rhs_params = rhs_bound .trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .map(|param| param.shifted_in(interner)); @@ -130,10 +130,8 @@ impl CoherenceSolver<'_, I> { .negate(interner); let canonical_goal = &goal.into_closed_goal(interner); - let solution = self - .solver_choice - .into_solver() - .solve(self.db, canonical_goal); + let mut fresh_solver = (self.solver_builder)(); + let solution = fresh_solver.solve(self.db, canonical_goal); let result = match solution { // Goal was proven with a unique solution, so no impl was found that causes these two // to overlap @@ -223,14 +221,14 @@ impl CoherenceSolver<'_, I> { // T0 = U0, ..., Tm = Um let params_goals = more_special_trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .cloned() .zip( less_special_impl .trait_ref .substitution - .parameters(interner) + .as_slice(interner) .iter() .cloned(), ) @@ -252,11 +250,8 @@ impl CoherenceSolver<'_, I> { ); let canonical_goal = &goal.into_closed_goal(interner); - let result = match self - .solver_choice - .into_solver() - .solve(self.db, canonical_goal) - { + let mut fresh_solver = (self.solver_builder)(); + let result = match fresh_solver.solve(self.db, canonical_goal) { Some(sol) => sol.is_unique(), None => false, }; diff --git a/vendor/chalk-solve-0.14.0/src/coinductive_goal.rs b/vendor/chalk-solve-0.25.0/src/coinductive_goal.rs similarity index 96% rename from vendor/chalk-solve-0.14.0/src/coinductive_goal.rs rename to vendor/chalk-solve-0.25.0/src/coinductive_goal.rs index 3c06933bce..cdb5cca108 100644 --- a/vendor/chalk-solve-0.14.0/src/coinductive_goal.rs +++ b/vendor/chalk-solve-0.25.0/src/coinductive_goal.rs @@ -25,6 +25,7 @@ impl IsCoinductive for Goal { } WhereClause::AliasEq(..) => false, WhereClause::LifetimeOutlives(..) => false, + WhereClause::TypeOutlives(..) => false, }, GoalData::DomainGoal(DomainGoal::WellFormed(WellFormed::Trait(..))) => true, GoalData::Quantified(QuantifierKind::ForAll, goal) => { diff --git a/vendor/chalk-solve-0.25.0/src/display.rs b/vendor/chalk-solve-0.25.0/src/display.rs new file mode 100644 index 0000000000..677332ace3 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display.rs @@ -0,0 +1,219 @@ +use std::{ + borrow::Borrow, + fmt::{Display, Result}, + sync::Arc, +}; + +use crate::rust_ir::*; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use crate::{logging_db::RecordedItemId, split::Split, RustIrDatabase}; + +#[macro_use] +mod utils; + +mod bounds; +mod identifiers; +mod items; +mod render_trait; +mod state; +mod stub; +mod ty; + +use self::render_trait::*; +pub use self::state::*; +pub use self::utils::sanitize_debug_name; + +use self::utils::as_display; + +fn write_item(f: &mut F, ws: &InternalWriterState<'_, I>, v: &T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + T: RenderAsRust, +{ + writeln!(f, "{}", v.display(ws)) +} + +/// Writes stubs for items which were referenced by name, but for which we +/// didn't directly access. For instance, traits mentioned in where bounds which +/// are only usually checked during well-formedness, when we weren't recording +/// well-formedness. +/// +/// The "stub" nature of this means it writes output with the right names and +/// the right number of generics, but nothing else. Where clauses, bounds, and +/// fields are skipped. Associated types are ???? skipped. +/// +/// `RecordedItemId::Impl` is not supported. +pub fn write_stub_items(f: &mut F, ws: &WriterState, ids: T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + DB: RustIrDatabase, + P: Borrow, + T: IntoIterator>, +{ + let wrapped_db = &ws.wrap_db_ref(|db| stub::StubWrapper::new(db.borrow())); + + write_items(f, wrapped_db, ids) +} + +/// Writes out each item recorded by a [`LoggingRustIrDatabase`]. +/// +/// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase +pub fn write_items(f: &mut F, ws: &WriterState, ids: T) -> Result +where + F: std::fmt::Write + ?Sized, + I: Interner, + DB: RustIrDatabase, + P: Borrow, + T: IntoIterator>, +{ + for id in ids { + match id { + RecordedItemId::Impl(id) => { + let v = ws.db().impl_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::Adt(id) => { + let v = ws.db().adt_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::Trait(id) => { + let v = ws.db().trait_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::OpaqueTy(id) => { + let v = ws.db().opaque_ty_data(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + RecordedItemId::FnDef(id) => { + let v = ws.db().fn_def_datum(id); + write_item(f, &InternalWriterState::new(ws), &*v)?; + } + } + } + Ok(()) +} + +/// Displays a set of bounds, all targeting `Self`, as just the trait names, +/// separated by `+`. +/// +/// For example, a list of quantified where clauses which would normally be +/// displayed as: +/// +/// ```notrust +/// Self: A, Self: B, Self: C +/// ``` +/// +/// Is instead displayed by this function as: +/// +/// ```notrust +/// A + B + C +/// ``` +/// +/// Shared between the `Trait` in `dyn Trait` and [`OpaqueTyDatum`] bounds. +fn display_self_where_clauses_as_bounds<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + bounds: &'a [QuantifiedWhereClause], +) -> impl Display + 'a { + as_display(move |f| { + let interner = s.db().interner(); + write!( + f, + "{}", + bounds + .iter() + .map(|bound| { + as_display(|f| { + // each individual trait can have a forall + let s = &s.add_debrujin_index(None); + if !bound.binders.is_empty(interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&bound.binders) + .collect::>() + .join(", ") + )?; + } + match &bound.skip_binders() { + WhereClause::Implemented(trait_ref) => display_type_with_generics( + s, + trait_ref.trait_id, + &trait_ref.substitution.as_slice(interner)[1..], + ) + .fmt(f), + WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { + AliasTy::Projection(projection_ty) => { + let (assoc_ty_datum, trait_params, assoc_type_params) = + s.db().split_projection(&projection_ty); + display_trait_with_assoc_ty_value( + s, + assoc_ty_datum, + &trait_params[1..], + assoc_type_params, + &alias_eq.ty, + ) + .fmt(f) + } + AliasTy::Opaque(_opaque) => todo!("opaque type AliasTy"), + }, + WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f), + WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f), + } + }) + .to_string() + }) + .format(" + ") + ) + }) +} + +/// Displays a type with its parameters - something like `AsRef`, +/// OpaqueTyName, or `AdtName`. +/// +/// This is shared between where bounds, OpaqueTy, & dyn Trait. +fn display_type_with_generics<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + trait_name: impl RenderAsRust + 'a, + trait_params: impl IntoIterator> + 'a, +) -> impl Display + 'a { + use std::fmt::Write; + let trait_params = trait_params.into_iter().map(|param| param.display(s)); + let mut trait_params_str = String::new(); + write_joined_non_empty_list!(trait_params_str, "<{}>", trait_params, ", ").unwrap(); + as_display(move |f| write!(f, "{}{}", trait_name.display(s), trait_params_str)) +} + +/// Displays a trait with its parameters and a single associated type - +/// something like `IntoIterator`. +/// +/// This is shared between where bounds & dyn Trait. +fn display_trait_with_assoc_ty_value<'a, I: Interner>( + s: &'a InternalWriterState<'a, I>, + assoc_ty_datum: Arc>, + trait_params: &'a [GenericArg], + assoc_ty_params: &'a [GenericArg], + assoc_ty_value: &'a Ty, +) -> impl Display + 'a { + as_display(move |f| { + write!(f, "{}<", assoc_ty_datum.trait_id.display(s))?; + write_joined_non_empty_list!( + f, + "{}, ", + trait_params.iter().map(|param| param.display(s)), + ", " + )?; + write!(f, "{}", assoc_ty_datum.id.display(s))?; + write_joined_non_empty_list!( + f, + "<{}>", + assoc_ty_params.iter().map(|param| param.display(s)), + ", " + )?; + write!(f, "={}>", assoc_ty_value.display(s))?; + Ok(()) + }) +} diff --git a/vendor/chalk-solve-0.25.0/src/display/bounds.rs b/vendor/chalk-solve-0.25.0/src/display/bounds.rs new file mode 100644 index 0000000000..627b0bb8d2 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/bounds.rs @@ -0,0 +1,168 @@ +//! Writer logic for `where` clauses and other bounds. +//! +//! Contains logic for writing the various forms of `Foo: Bar`. +use std::fmt::{Display, Formatter, Result}; + +use crate::rust_ir::*; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use super::{ + display_trait_with_assoc_ty_value, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; +use crate::split::Split; + +impl RenderAsRust for InlineBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + // Foo: Vec + InlineBound::TraitBound(trait_bound) => trait_bound.fmt(s, f), + // Foo: Iterator + InlineBound::AliasEqBound(eq_bound) => eq_bound.fmt(s, f), + } + } +} + +impl RenderAsRust for TraitBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + display_type_with_generics(s, self.trait_id, &self.args_no_self).fmt(f) + } +} + +impl RenderAsRust for AliasEqBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + display_trait_with_assoc_ty_value( + s, + s.db().associated_ty_data(self.associated_ty_id), + &self.trait_bound.args_no_self, + &self.parameters, + &self.value, + ) + .fmt(f) + } +} + +impl RenderAsRust for QuantifiedWhereClause { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if !self.binders.is_empty(interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&self.binders).format(", ") + )?; + } + self.skip_binders().fmt(s, f) + } +} + +impl RenderAsRust for QuantifiedInlineBound { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if !self.binders.is_empty(&interner) { + write!( + f, + "forall<{}> ", + s.binder_var_display(&self.binders).format(", ") + )?; + } + self.skip_binders().fmt(s, f) + } +} + +impl RenderAsRust for Vec> { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + write!( + f, + "{}", + self.iter() + .map(|where_clause| { format!("{}{}", s.indent(), where_clause.display(s)) }) + .format(",\n") + )?; + Ok(()) + } +} + +impl RenderAsRust for WhereClause { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + WhereClause::Implemented(trait_ref) => trait_ref.fmt(s, f), + WhereClause::AliasEq(alias_eq) => alias_eq.fmt(s, f), + WhereClause::LifetimeOutlives(lifetime) => lifetime.display(s).fmt(f), + WhereClause::TypeOutlives(ty) => ty.display(s).fmt(f), + } + } +} + +/// This renders `TraitRef` as a clause in a where clause, as opposed to its +/// usage in other places. +impl RenderAsRust for TraitRef { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + write!( + f, + "{}: {}", + self.self_type_parameter(interner).display(s), + display_type_with_generics( + s, + self.trait_id, + &self.substitution.as_slice(interner)[1..] + ) + ) + } +} + +/// This renders `AliasEq` as a clause in a where clause, as opposed to its +/// usage in other places. +impl RenderAsRust for AliasEq { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // we have: X: Y=D> + // B1, B2, B3, X, A1, A2, A3 are put into alias_eq.alias.substitution + // D is alias_eq.ty + // Z is alias_eq.alias.associated_ty_id + // Y is also packed into alias_eq.alias.associated_ty_id + // Now, we split out A*, Y/Z and B*: + // trait_params is X, A1, A2, A3, + // assoc_type_params is B1, B2, B3, + // assoc_ty_datum stores info about Y and Z. + match &self.alias { + AliasTy::Projection(projection_ty) => { + let (assoc_ty_datum, trait_params, assoc_type_params) = + s.db().split_projection(&projection_ty); + // An alternate form might be `<{} as {}<{}>>::{}<{}> = {}` (with same + // parameter ordering). This alternate form would require type equality + // constraints (https://github.com/rust-lang/rust/issues/20041). + write!( + f, + "{}: {}", + trait_params[0].display(s), + display_trait_with_assoc_ty_value( + s, + assoc_ty_datum, + &trait_params[1..], + assoc_type_params, + &self.ty + ), + ) + } + AliasTy::Opaque(_) => todo!("opaque types"), + } + } +} + +impl RenderAsRust for LifetimeOutlives { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + // a': 'b + write!(f, "{}: {}", self.a.display(s), self.b.display(s)) + } +} + +impl RenderAsRust for TypeOutlives { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + // T: 'a + write!(f, "{}: {}", self.ty.display(s), self.lifetime.display(s)) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/identifiers.rs b/vendor/chalk-solve-0.25.0/src/display/identifiers.rs new file mode 100644 index 0000000000..81a08d71b3 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/identifiers.rs @@ -0,0 +1,54 @@ +//! Writer logic for simple IDs +//! +//! `RenderAsRust` impls for identifiers which are either too small or too +//! shared to belong anywhere else belong here. +use std::fmt::{Formatter, Result}; + +use chalk_ir::interner::Interner; +use chalk_ir::*; + +use super::{render_trait::RenderAsRust, state::InternalWriterState}; + +impl RenderAsRust for AdtId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_adt_id_name(self.0, s.db().adt_name(*self)) + ) + } +} + +impl RenderAsRust for TraitId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().trait_name(*self)) + ) + } +} + +impl RenderAsRust for AssocTypeId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().assoc_type_name(*self)) + ) + } +} + +impl RenderAsRust for OpaqueTyId { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // TODO: use debug methods? + write!( + f, + "{}", + s.alias_for_id_name(self.0, s.db().opaque_type_name(*self)) + ) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/items.rs b/vendor/chalk-solve-0.25.0/src/display/items.rs new file mode 100644 index 0000000000..13da1a01b2 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/items.rs @@ -0,0 +1,490 @@ +//! Writer logic for top level items. +//! +//! Contains code specific to top-level items and other structures specific to a +//! single top-level item. + +use std::fmt::{Formatter, Result}; + +use crate::rust_ir::*; +use crate::split::Split; +use chalk_ir::interner::Interner; +use itertools::Itertools; + +use super::{ + display_self_where_clauses_as_bounds, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; + +/// Used in `AdtDatum` and `TraitDatum` to write n flags from a flags struct +/// to a writer. Each flag field turns into an if expression + write!, so we can +/// just list the names and not repeat this pattern over and over. +/// +/// This macro will error if unknown flags are specified. This will also error +/// if any flags are missing. +/// +/// # Usage +/// +/// ```rust,ignore +/// write_flags!(f, self.flags, XFlags { red, green }) +/// ``` +/// +/// Turns into +/// +/// ```rust,ignore +/// match self.flags { +/// XFlags { red, green } => { +/// if red { +/// write!(f, "#[red]")?; +/// } +/// if green { +/// write!(f, "#[green]")?; +/// } +/// } +/// } +/// ``` +macro_rules! write_flags { + ($writer:ident, $val:expr, $struct_name:ident { $($n:ident $(: $extra_arg:tt)?),* }) => { + match $val { + // if any fields are missing, the destructuring will error + $struct_name { + $($n,)* + } => { + $(if $n { + write!($writer, "#[{}]\n", write_flags!(@default $n $(: $extra_arg)*))?; + })* + } + } + }; + (@default $n:ident : $name:literal) => { + $name + }; + (@default $n:ident ) => { + stringify!($n) + }; +} + +impl RenderAsRust for AdtDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // When support for Self in structs is added, self_binding should be + // changed to Some(0) + let s = &s.add_debrujin_index(None); + let value = self.binders.skip_binders(); + + // flags + write_flags!( + f, + self.flags, + AdtFlags { + // Ordering matters + upstream, + fundamental, + phantom_data + } + ); + + // repr + let repr = s.db().adt_repr(self.id); + + write_flags!( + f, + repr, + AdtRepr { + repr_c: "repr(C)", + repr_packed: "repr(packed)" + } + ); + + // name + match self.kind { + AdtKind::Struct => write!(f, "struct {}", self.id.display(s),)?, + AdtKind::Enum => write!(f, "enum {}", self.id.display(s),)?, + AdtKind::Union => write!(f, "union {}", self.id.display(s),)?, + } + write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.binders.binders), ", ")?; + + // where clauses + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + write!(f, "{{")?; + let s = &s.add_indent(); + match self.kind { + AdtKind::Struct | AdtKind::Union => { + write_joined_non_empty_list!( + f, + "\n{}\n", + value.variants[0] + .fields + .iter() + .enumerate() + .map(|(idx, field)| { + format!("{}field_{}: {}", s.indent(), idx, field.display(s)) + }), + ",\n" + )?; + } + AdtKind::Enum => { + for (variant_idx, variant) in value.variants.iter().enumerate() { + write!(f, "\n{}variant_{} {{", s.indent(), variant_idx)?; + let s = &s.add_indent(); + write_joined_non_empty_list!( + f, + "\n{}\n", + variant.fields.iter().enumerate().map(|(idx, field)| { + format!("{}field_{}: {}", s.indent(), idx, field.display(s)) + }), + ",\n" + )?; + write!(f, "{}}},", s.indent())?; + } + } + } + write!(f, "}}")?; + Ok(()) + } +} + +impl RenderAsRust for Polarity { + fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + if !self.is_positive() { + write!(f, "!")?; + } + Ok(()) + } +} + +impl RenderAsRust for TraitDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(Some(0)); + let value = self.binders.skip_binders(); + + // flags + write_flags!( + f, + self.flags, + TraitFlags { + auto, + marker, + upstream, + fundamental, + non_enumerable, + coinductive + } + ); + + // object safe + if s.db().is_object_safe(self.id) { + writeln!(f, "#[object_safe]")?; + } + + // well-known + if let Some(well_known) = self.well_known { + let name = match well_known { + WellKnownTrait::Sized => "sized", + WellKnownTrait::Copy => "copy", + WellKnownTrait::Clone => "clone", + WellKnownTrait::Drop => "drop", + WellKnownTrait::FnOnce => "fn_once", + WellKnownTrait::FnMut => "fn_mut", + WellKnownTrait::Fn => "fn", + WellKnownTrait::Unsize => "unsize", + }; + writeln!(f, "#[lang({})]", name)?; + } + + // trait declaration + let binders = s.binder_var_display(&self.binders.binders).skip(1); + write!(f, "trait {}", self.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + // where clauses + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + write!(f, "{{")?; + let s = &s.add_indent(); + write_joined_non_empty_list!( + f, + "\n{}\n", + self.associated_ty_ids.iter().map(|assoc_ty_id| { + let assoc_ty_data = s.db().associated_ty_data(*assoc_ty_id); + format!("{}{}", s.indent(), (*assoc_ty_data).display(s)) + }), + "\n" + )?; + write!(f, "}}")?; + Ok(()) + } +} + +impl RenderAsRust for ImplDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + + let s = &s.add_debrujin_index(None); + let binders = s.binder_var_display(&self.binders.binders); + let value = self.binders.skip_binders(); + + // annotations + // #[upstream] + // ^^^^^^^^^^^ + // impl Foo for Bar where T: Baz { } + if self.impl_type == ImplType::External { + writeln!(f, "#[upstream]")?; + } + + // impl keyword + // impl Foo for Bar where T: Baz { } + // ^^^^ + write!(f, "impl")?; + let trait_ref = &value.trait_ref; + + // generic binders + // impl Foo for Bar where T: Baz + // ^^^ + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + // trait, type and parameters + // impl Foo for Bar where T: Baz { } + // ^^^^^^^^^^^^^^^^^ + let full_trait_name = display_type_with_generics( + s, + trait_ref.trait_id, + // Ignore automatically added Self parameter by skipping first parameter + &trait_ref.substitution.as_slice(interner)[1..], + ); + write!( + f, + " {}{} for {}", + self.polarity.display(s), + full_trait_name, + trait_ref.self_type_parameter(interner).display(s) + )?; + + // where clauses + // impl Foo for Bar where T: Baz { } + // ^^^^^^^^^^^^ + if !value.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}\n", value.where_clauses.display(s))?; + } else { + write!(f, " ")?; + } + + // body + // impl Foo for Bar where T: Baz { } + // ^^^ + write!(f, "{{")?; + { + let s = &s.add_indent(); + let assoc_ty_values = self.associated_ty_value_ids.iter().map(|assoc_ty_value| { + s.db() + .associated_ty_value(*assoc_ty_value) + .display(s) + .to_string() + }); + write_joined_non_empty_list!(f, "\n{}\n", assoc_ty_values, "\n")?; + } + write!(f, "}}")?; + Ok(()) + } +} + +impl RenderAsRust for OpaqueTyDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(None); + let bounds = self.bound.skip_binders(); + write!(f, "opaque type {}", self.opaque_ty_id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", s.binder_var_display(&self.bound.binders), ", ")?; + { + let s = &s.add_debrujin_index(Some(0)); + let clauses = bounds.bounds.skip_binders(); + write!( + f, + ": {} = ", + display_self_where_clauses_as_bounds(s, clauses) + )?; + } + write!( + f, + "{};", + s.db().hidden_opaque_type(self.opaque_ty_id).display(s) + )?; + Ok(()) + } +} + +impl RenderAsRust for AssociatedTyDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // In lowering, a completely new empty environment is created for each + // AssociatedTyDatum, and it's given generic parameters for each generic + // parameter that its trait had. We want to map the new binders for + // those generic parameters back into their original names. To do that, + // first find their original names (trait_binder_names), then the names + // they have inside the AssociatedTyDatum (assoc_ty_names_for_trait_params), + // and then add that mapping to the WriterState when writing bounds and + // where clauses. + let trait_datum = s.db().trait_datum(self.trait_id); + // inverted Debrujin indices for the trait's parameters in the trait + // environment + let trait_param_names_in_trait_env = s.binder_var_indices(&trait_datum.binders.binders); + let s = &s.add_debrujin_index(None); + // inverted Debrujin indices for the trait's parameters in the + // associated type environment + let param_names_in_assoc_ty_env = s + .binder_var_indices(&self.binders.binders) + .collect::>(); + // inverted Debrujin indices to render the trait's parameters in the + // associated type environment + let (trait_param_names_in_assoc_ty_env, _) = s + .db() + .split_associated_ty_parameters(¶m_names_in_assoc_ty_env, self); + + let s = &s.add_parameter_mapping( + trait_param_names_in_assoc_ty_env.iter().copied(), + trait_param_names_in_trait_env, + ); + + // rendered names for the associated type's generics in the associated + // type environment + let binder_display_in_assoc_ty = s + .binder_var_display(&self.binders.binders) + .collect::>(); + + let (_, assoc_ty_params) = s + .db() + .split_associated_ty_parameters(&binder_display_in_assoc_ty, self); + write!(f, "type {}", self.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", assoc_ty_params, ", ")?; + + let datum_bounds = &self.binders.skip_binders(); + + if !datum_bounds.bounds.is_empty() { + write!(f, ": ")?; + } + + // bounds is `A: V, B: D, C = E`? + // type Foo: X + Y + Z; + let bounds = datum_bounds + .bounds + .iter() + .map(|bound| bound.display(s).to_string()) + .format(" + "); + write!(f, "{}", bounds)?; + + // where_clause is 'X: Y, Z: D' + // type Foo<...>: ... where X: Y, Z: D; + + // note: it's a quantified clause b/c we could have `for<'a> T: Foo<'a>` + // within 'where' + if !datum_bounds.where_clauses.is_empty() { + let where_s = &s.add_indent(); + let where_clauses = datum_bounds.where_clauses.display(where_s); + write!(f, "\n{}where\n{}", s.indent(), where_clauses)?; + } + write!(f, ";")?; + Ok(()) + } +} + +impl RenderAsRust for AssociatedTyValue { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // see comments for a similar empty env operation in AssociatedTyDatum's + // impl of RenderAsRust. + let assoc_ty_data = s.db().associated_ty_data(self.associated_ty_id); + let impl_datum = s.db().impl_datum(self.impl_id); + + let impl_param_names_in_impl_env = s.binder_var_indices(&impl_datum.binders.binders); + + let s = &s.add_debrujin_index(None); + let value = self.value.skip_binders(); + + let param_names_in_assoc_ty_value_env = s + .binder_var_indices(&self.value.binders) + .collect::>(); + + let (impl_params_in_assoc_ty_value_env, _assoc_ty_value_params) = s + .db() + .split_associated_ty_value_parameters(¶m_names_in_assoc_ty_value_env, self); + + let s = &s.add_parameter_mapping( + impl_params_in_assoc_ty_value_env.iter().cloned(), + impl_param_names_in_impl_env, + ); + + let display_params = s + .binder_var_display(&self.value.binders) + .collect::>(); + + let (_impl_display, assoc_ty_value_display) = s + .db() + .split_associated_ty_value_parameters(&display_params, self); + + write!(f, "{}type {}", s.indent(), assoc_ty_data.id.display(s))?; + write_joined_non_empty_list!(f, "<{}>", &assoc_ty_value_display, ", ")?; + write!(f, " = {};", value.ty.display(s))?; + Ok(()) + } +} + +impl RenderAsRust for FnDefDatum { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + let s = &s.add_debrujin_index(None); + let bound_datum = self.binders.skip_binders(); + + // declaration + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^ + write!(f, "fn {}", s.db().fn_def_name(self.id))?; + + // binders + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^ + let binders = s.binder_var_display(&self.binders.binders); + write_joined_non_empty_list!(f, "<{}>", binders, ", ")?; + + { + let s = &s.add_debrujin_index(None); + let inputs_and_output = bound_datum.inputs_and_output.skip_binders(); + + // arguments + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^^^^^^^^^^^^^^ + let arguments = inputs_and_output + .argument_types + .iter() + .enumerate() + .map(|(idx, arg)| format!("arg_{}: {}", idx, arg.display(s))) + .format(", "); + + write!(f, "({})", arguments)?; + + // return Type + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^^^^^^^^ + write!(f, " -> {}", inputs_and_output.return_type.display(s))?; + } + + // where clause + // fn foo(arg: u32, arg2: T) -> Result where T: Bar + // ^^^^^^^^^^^^ + if !bound_datum.where_clauses.is_empty() { + let s = &s.add_indent(); + write!(f, "\nwhere\n{}", bound_datum.where_clauses.display(s))?; + } + + write!(f, ";")?; + + Ok(()) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/render_trait.rs b/vendor/chalk-solve-0.25.0/src/display/render_trait.rs new file mode 100644 index 0000000000..a565f076c7 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/render_trait.rs @@ -0,0 +1,30 @@ +//! `RenderAsRust` trait and related utils. +use std::fmt::{Display, Formatter, Result}; + +use chalk_ir::interner::Interner; + +use super::state::InternalWriterState; + +/// Displays `RenderAsRust` data. +/// +/// This is a utility struct for making `RenderAsRust` nice to use with rust format macros. +pub(in crate::display) struct DisplayRenderAsRust<'a, I: Interner, T> { + s: &'a InternalWriterState<'a, I>, + rar: &'a T, +} + +impl> Display for DisplayRenderAsRust<'_, I, T> { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + self.rar.fmt(self.s, f) + } +} + +pub(in crate::display) trait RenderAsRust { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result; + fn display<'a>(&'a self, s: &'a InternalWriterState<'a, I>) -> DisplayRenderAsRust<'a, I, Self> + where + Self: Sized, + { + DisplayRenderAsRust { s, rar: self } + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/state.rs b/vendor/chalk-solve-0.25.0/src/display/state.rs new file mode 100644 index 0000000000..3501d5916d --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/state.rs @@ -0,0 +1,350 @@ +//! Persistent state passed down between writers. +//! +//! This is essentially `InternalWriterState` and other things supporting that. +use std::{ + borrow::Borrow, + collections::BTreeMap, + fmt::{Debug, Display, Formatter, Result}, + marker::PhantomData, + rc::Rc, + sync::{Arc, Mutex}, +}; + +use crate::RustIrDatabase; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +/// Like a BoundVar, but with the debrujin index inverted so as to create a +/// canonical name we can use anywhere for each bound variable. +/// +/// In BoundVar, the innermost bound variables have debrujin index `0`, and +/// each further out BoundVar has a debrujin index `1` higher. +/// +/// In InvertedBoundVar, the outermost variables have inverted_debrujin_idx `0`, +/// and the innermost have their depth, not the other way around. +#[derive(Debug, Copy, Clone, PartialOrd, Ord, PartialEq, Eq)] +pub struct InvertedBoundVar { + /// The inverted debrujin index. Corresponds roughly to an inverted `DebrujinIndex::depth`. + inverted_debrujin_idx: i64, + /// The index within the debrujin index. Corresponds to `BoundVar::index`. + within_idx: IndexWithinBinding, +} + +impl Display for InvertedBoundVar { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + write!(f, "_{}_{}", self.inverted_debrujin_idx, self.within_idx) + } +} + +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)] +enum UnifiedId { + AdtId(I::InternedAdtId), + DefId(I::DefId), +} + +#[derive(Debug)] +pub struct IdAliasStore { + /// Map from the DefIds we've encountered to a u32 alias id unique to all ids + /// the same name. + aliases: BTreeMap, + /// Map from each name to the next unused u32 alias id. + next_unused_for_name: BTreeMap, +} + +impl Default for IdAliasStore { + fn default() -> Self { + IdAliasStore { + aliases: BTreeMap::default(), + next_unused_for_name: BTreeMap::default(), + } + } +} + +impl IdAliasStore { + fn alias_for_id_name(&mut self, id: T, name: String) -> String { + let next_unused_for_name = &mut self.next_unused_for_name; + let alias = *self.aliases.entry(id).or_insert_with(|| { + let next_unused: &mut u32 = next_unused_for_name.entry(name.clone()).or_default(); + let id = *next_unused; + *next_unused += 1; + id + }); + // If there are no conflicts, keep the name the same so that we don't + // need name-agnostic equality in display tests. + if alias == 0 { + name + } else { + format!("{}_{}", name, alias) + } + } +} + +#[derive(Debug)] +struct IdAliases { + id_aliases: IdAliasStore>, +} + +impl Default for IdAliases { + fn default() -> Self { + IdAliases { + id_aliases: IdAliasStore::default(), + } + } +} + +/// Writer state which persists across multiple writes. +/// +/// Currently, this means keeping track of what IDs have been given what names, +/// including deduplication information. +/// +/// This data is stored using interior mutability - clones will point to the same underlying +/// data. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +#[derive(Debug)] +pub struct WriterState +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + pub(super) db: P, + id_aliases: Arc>>, + _phantom: PhantomData, +} + +impl Clone for WriterState +where + DB: RustIrDatabase, + P: Borrow + Clone, + I: Interner, +{ + fn clone(&self) -> Self { + WriterState { + db: self.db.clone(), + id_aliases: self.id_aliases.clone(), + _phantom: PhantomData, + } + } +} + +impl WriterState +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + pub fn new(db: P) -> Self { + WriterState { + db, + id_aliases: Arc::new(Mutex::new(IdAliases::default())), + _phantom: PhantomData, + } + } + + /// Returns a new version of self containing a wrapped database which + /// references the outer data. + /// + /// `f` will be run on the internal database, and the returned result will + /// wrap the result from `f`. For consistency, `f` should always contain the + /// given database, and must keep the same ID<->item relationships. + pub(super) fn wrap_db_ref<'a, DB2: ?Sized, P2, F>(&'a self, f: F) -> WriterState + where + DB2: RustIrDatabase, + P2: Borrow, + // We need to pass in `&'a P` specifically to guarantee that the `&P` + // can outlive the function body, and thus that it's safe to store `&P` + // in `P2`. + F: FnOnce(&'a P) -> P2, + { + WriterState { + db: f(&self.db), + id_aliases: self.id_aliases.clone(), + _phantom: PhantomData, + } + } + + pub(crate) fn db(&self) -> &DB { + self.db.borrow() + } +} + +/// Writer state for a single write call, persistent only as long as necessary +/// to write a single item. +/// +/// Stores things necessary for . +#[derive(Clone, Debug)] +pub(super) struct InternalWriterState<'a, I: Interner> { + persistent_state: WriterState + 'a, &'a dyn RustIrDatabase>, + indent_level: usize, + debrujin_indices_deep: u32, + // lowered_(inverted_debrujin_idx, index) -> src_correct_(inverted_debrujin_idx, index) + remapping: Rc>, + // the inverted_bound_var which maps to "Self" + self_mapping: Option, +} + +type IndexWithinBinding = usize; + +impl<'a, I: Interner> InternalWriterState<'a, I> { + pub fn new(persistent_state: &'a WriterState) -> Self + where + DB: RustIrDatabase, + P: Borrow, + { + InternalWriterState { + persistent_state: persistent_state + .wrap_db_ref(|db| db.borrow() as &dyn RustIrDatabase), + indent_level: 0, + debrujin_indices_deep: 0, + remapping: Rc::new(BTreeMap::new()), + self_mapping: None, + } + } + + pub(super) fn db(&self) -> &dyn RustIrDatabase { + self.persistent_state.db + } + + pub(super) fn add_indent(&self) -> Self { + InternalWriterState { + indent_level: self.indent_level + 1, + ..self.clone() + } + } + + pub(super) fn indent(&self) -> impl Display { + std::iter::repeat(" ").take(self.indent_level).format("") + } + + pub(super) fn alias_for_adt_id_name(&self, id: I::InternedAdtId, name: String) -> impl Display { + self.persistent_state + .id_aliases + .lock() + .unwrap() + .id_aliases + .alias_for_id_name(UnifiedId::AdtId(id), name) + } + + pub(super) fn alias_for_id_name(&self, id: I::DefId, name: String) -> impl Display { + self.persistent_state + .id_aliases + .lock() + .unwrap() + .id_aliases + .alias_for_id_name(UnifiedId::DefId(id), name) + } + + /// Adds a level of debrujin index, and possibly a "Self" parameter. + /// + /// This should be called whenever recursing into the value within a + /// [`Binders`]. + /// + /// If `self_binding` is `Some`, then it will introduce a new variable named + /// `Self` with the within-debrujin index given within and the innermost + /// debrujian index after increasing debrujin index. + #[must_use = "this returns a new `InternalWriterState`, and does not modify the existing one"] + pub(super) fn add_debrujin_index(&self, self_binding: Option) -> Self { + let mut new_state = self.clone(); + new_state.debrujin_indices_deep += 1; + new_state.self_mapping = self_binding + .map(|idx| new_state.indices_for_introduced_bound_var(idx)) + .or(self.self_mapping); + new_state + } + + /// Adds parameter remapping. + /// + /// Each of the parameters in `lowered_vars` will be mapped to its + /// corresponding variable in `original_vars` when printed through the + /// `InternalWriterState` returned from this method. + /// + /// `lowered_vars` and `original_vars` must have the same length. + pub(super) fn add_parameter_mapping( + &self, + lowered_vars: impl Iterator, + original_vars: impl Iterator, + ) -> Self { + let remapping = self + .remapping + .iter() + .map(|(a, b)| (*a, *b)) + .chain(lowered_vars.zip(original_vars)) + .collect::>(); + + InternalWriterState { + remapping: Rc::new(remapping), + ..self.clone() + } + } + + /// Inverts the debrujin index so as to create a canonical name we can + /// anywhere for each bound variable. + /// + /// See [`InvertedBoundVar`][InvertedBoundVar]. + pub(super) fn invert_debrujin_idx( + &self, + debrujin_idx: u32, + index: IndexWithinBinding, + ) -> InvertedBoundVar { + InvertedBoundVar { + inverted_debrujin_idx: (self.debrujin_indices_deep as i64) - (debrujin_idx as i64), + within_idx: index, + } + } + + pub(super) fn apply_mappings(&self, b: InvertedBoundVar) -> impl Display { + let remapped = self.remapping.get(&b).copied().unwrap_or(b); + if self.self_mapping == Some(remapped) { + "Self".to_owned() + } else { + remapped.to_string() + } + } + + pub(super) fn indices_for_bound_var(&self, b: &BoundVar) -> InvertedBoundVar { + self.invert_debrujin_idx(b.debruijn.depth(), b.index) + } + + pub(super) fn indices_for_introduced_bound_var( + &self, + idx: IndexWithinBinding, + ) -> InvertedBoundVar { + // freshly introduced bound vars will always have debrujin index of 0, + // they're always "innermost". + self.invert_debrujin_idx(0, idx) + } + + pub(super) fn display_bound_var(&self, b: &BoundVar) -> impl Display { + self.apply_mappings(self.indices_for_bound_var(b)) + } + + pub(super) fn name_for_introduced_bound_var(&self, idx: IndexWithinBinding) -> impl Display { + self.apply_mappings(self.indices_for_introduced_bound_var(idx)) + } + + pub(super) fn binder_var_indices<'b>( + &'b self, + binders: &'b VariableKinds, + ) -> impl Iterator + 'b { + binders + .iter(self.db().interner()) + .enumerate() + .map(move |(idx, _param)| self.indices_for_introduced_bound_var(idx)) + } + + pub(super) fn binder_var_display<'b>( + &'b self, + binders: &'b VariableKinds, + ) -> impl Iterator + 'b { + binders + .iter(self.db().interner()) + .zip(self.binder_var_indices(binders)) + .map(move |(parameter, var)| match parameter { + VariableKind::Ty(_) => format!("{}", self.apply_mappings(var)), + VariableKind::Lifetime => format!("'{}", self.apply_mappings(var)), + VariableKind::Const(_ty) => format!("const {}", self.apply_mappings(var)), + }) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/stub.rs b/vendor/chalk-solve-0.25.0/src/display/stub.rs new file mode 100644 index 0000000000..2c433578c2 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/stub.rs @@ -0,0 +1,239 @@ +//! Contains a `LoggingIrDatabase` which returns stub versions of everything +//! queried. +use std::sync::Arc; + +use crate::{ + rust_ir::{ + AdtDatumBound, AdtKind, AdtVariantDatum, AssociatedTyDatumBound, FnDefDatumBound, + OpaqueTyDatumBound, TraitDatumBound, + }, + RustIrDatabase, +}; +use chalk_ir::{ + interner::Interner, ApplicationTy, Binders, CanonicalVarKinds, TypeName, VariableKinds, +}; + +#[derive(Debug)] +pub struct StubWrapper<'a, DB> { + db: &'a DB, +} + +impl<'a, DB> StubWrapper<'a, DB> { + pub fn new(db: &'a DB) -> Self { + StubWrapper { db } + } +} + +impl> RustIrDatabase for StubWrapper<'_, DB> { + fn custom_clauses(&self) -> Vec> { + self.db.custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId, + ) -> std::sync::Arc> { + let mut v = (*self.db.associated_ty_data(ty)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + AssociatedTyDatumBound { + where_clauses: Vec::new(), + bounds: Vec::new(), + }, + ); + Arc::new(v) + } + + fn trait_datum( + &self, + trait_id: chalk_ir::TraitId, + ) -> std::sync::Arc> { + let mut v = (*self.db.trait_datum(trait_id)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + TraitDatumBound { + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn adt_datum(&self, adt_id: chalk_ir::AdtId) -> std::sync::Arc> { + let mut v = (*self.db.adt_datum(adt_id)).clone(); + let variants = match v.kind { + AdtKind::Struct | AdtKind::Union => vec![AdtVariantDatum { fields: vec![] }], + AdtKind::Enum => vec![], + }; + v.binders = Binders::new( + v.binders.binders.clone(), + AdtDatumBound { + variants, + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn adt_repr(&self, id: chalk_ir::AdtId) -> crate::rust_ir::AdtRepr { + self.db.adt_repr(id) + } + + fn fn_def_datum( + &self, + fn_def_id: chalk_ir::FnDefId, + ) -> std::sync::Arc> { + let mut v = (*self.db.fn_def_datum(fn_def_id)).clone(); + v.binders = Binders::new( + v.binders.binders.clone(), + FnDefDatumBound { + inputs_and_output: v.binders.skip_binders().inputs_and_output.clone(), + where_clauses: Vec::new(), + }, + ); + Arc::new(v) + } + + fn impl_datum( + &self, + _impl_id: chalk_ir::ImplId, + ) -> std::sync::Arc> { + unreachable!("impl items should never be stubbed") + } + + fn associated_ty_value( + &self, + _id: crate::rust_ir::AssociatedTyValueId, + ) -> std::sync::Arc> { + unreachable!("associated type values should never be stubbed") + } + + fn opaque_ty_data( + &self, + id: chalk_ir::OpaqueTyId, + ) -> std::sync::Arc> { + let mut v = (*self.db.opaque_ty_data(id)).clone(); + v.bound = Binders::new( + v.bound.binders, + OpaqueTyDatumBound { + bounds: Binders::new(VariableKinds::empty(self.db.interner()), Vec::new()), + where_clauses: Binders::new(VariableKinds::empty(self.db.interner()), Vec::new()), + }, + ); + Arc::new(v) + } + + fn hidden_opaque_type(&self, _id: chalk_ir::OpaqueTyId) -> chalk_ir::Ty { + // Return a unit since the particular hidden type doesn't matter (If it + // did matter, it would have been recorded) + chalk_ir::TyData::Apply(ApplicationTy { + name: TypeName::Tuple(0), + substitution: chalk_ir::Substitution::from_iter( + self.db.interner(), + Vec::>::new(), + ), + }) + .intern(self.db.interner()) + } + + fn impls_for_trait( + &self, + _trait_id: chalk_ir::TraitId, + _parameters: &[chalk_ir::GenericArg], + _binders: &CanonicalVarKinds, + ) -> Vec> { + // We panic here because the returned ids may not be collected, + // resulting in unresolvable names. + unimplemented!("stub display code should call this") + } + + fn local_impls_to_coherence_check( + &self, + trait_id: chalk_ir::TraitId, + ) -> Vec> { + self.db.local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for( + &self, + _auto_trait_id: chalk_ir::TraitId, + _adt_id: chalk_ir::AdtId, + ) -> bool { + // We panic here because the returned ids may not be collected, + // resulting in unresolvable names. + unimplemented!("stub display code should call this") + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option> { + self.db.well_known_trait_id(well_known_trait) + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment, + ) -> chalk_ir::ProgramClauses { + self.db.program_clauses_for_env(environment) + } + + fn interner(&self) -> &I { + self.db.interner() + } + + fn is_object_safe(&self, trait_id: chalk_ir::TraitId) -> bool { + self.db.is_object_safe(trait_id) + } + + fn closure_kind( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> crate::rust_ir::ClosureKind { + unimplemented!("cannot stub closures") + } + + fn closure_inputs_and_output( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> chalk_ir::Binders> { + unimplemented!("cannot stub closures") + } + + fn closure_upvars( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> chalk_ir::Binders> { + unimplemented!("cannot stub closures") + } + + fn closure_fn_substitution( + &self, + _closure_id: chalk_ir::ClosureId, + _substs: &chalk_ir::Substitution, + ) -> chalk_ir::Substitution { + unimplemented!("cannot stub closures") + } + + fn trait_name(&self, trait_id: chalk_ir::TraitId) -> String { + self.db.trait_name(trait_id) + } + + fn adt_name(&self, struct_id: chalk_ir::AdtId) -> String { + self.db.adt_name(struct_id) + } + + fn assoc_type_name(&self, assoc_ty_id: chalk_ir::AssocTypeId) -> String { + self.db.assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: chalk_ir::OpaqueTyId) -> String { + self.db.opaque_type_name(opaque_ty_id) + } + + fn fn_def_name(&self, fn_def_id: chalk_ir::FnDefId) -> String { + self.db.fn_def_name(fn_def_id) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/ty.rs b/vendor/chalk-solve-0.25.0/src/display/ty.rs new file mode 100644 index 0000000000..6792703096 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/ty.rs @@ -0,0 +1,333 @@ +//! Writer logic for types. +//! +//! Contains the highly-recursive logic for writing `TyData` and its variants. +use std::fmt::{Formatter, Result}; + +use crate::split::Split; +use chalk_ir::{interner::Interner, *}; +use itertools::Itertools; + +use super::{ + display_self_where_clauses_as_bounds, display_type_with_generics, render_trait::RenderAsRust, + state::InternalWriterState, +}; + +impl RenderAsRust for TyData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + match self { + TyData::Dyn(dyn_ty) => { + // the lifetime needs to be outside of the bounds, so we + // introduce a new scope for the bounds + { + let s = &s.add_debrujin_index(None); + // dyn_ty.bounds.binders creates a Self binding for the trait + let bounds = dyn_ty.bounds.skip_binders(); + + write!( + f, + "dyn {}", + display_self_where_clauses_as_bounds(s, bounds.as_slice(interner)), + )?; + } + + write!(f, " + {}", dyn_ty.lifetime.display(s))?; + Ok(()) + } + TyData::BoundVar(bound_var) => write!(f, "{}", s.display_bound_var(bound_var)), + TyData::InferenceVar(_, _) => write!(f, "_"), + TyData::Alias(alias_ty) => alias_ty.fmt(s, f), + TyData::Apply(apply_ty) => apply_ty.fmt(s, f), + TyData::Function(func) => func.fmt(s, f), + TyData::Placeholder(_) => write!(f, ""), + } + } +} + +impl RenderAsRust for AliasTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + AliasTy::Projection(projection_ty) => projection_ty.fmt(s, f), + AliasTy::Opaque(opaque_ty) => opaque_ty.fmt(s, f), + } + } +} + +impl RenderAsRust for ProjectionTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // >::Z + + // Now, we split out A*, Y/Z and B*: + // trait_params is X, A1, A2, A3, + // assoc_type_params is B1, B2, B3, + // assoc_ty_datum stores info about Y and Z. + let (assoc_ty_datum, trait_params, assoc_type_params) = s.db().split_projection(&self); + write!( + f, + "<{} as {}>::{}", + trait_params[0].display(s), + display_type_with_generics(s, assoc_ty_datum.trait_id, &trait_params[1..]), + assoc_ty_datum.id.display(s), + )?; + write_joined_non_empty_list!( + f, + "<{}>", + assoc_type_params.iter().map(|param| param.display(s)), + ", " + )?; + Ok(()) + } +} + +impl RenderAsRust for OpaqueTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + write!( + f, + "{}", + display_type_with_generics(s, self.opaque_ty_id, self.substitution.as_slice(interner),) + ) + } +} + +impl RenderAsRust for FnPointer { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + let s = &s.add_debrujin_index(None); + if self.num_binders > 0 { + write!( + f, + "for<{}> ", + (0..self.num_binders) + .map(|n| format!("'{}", s.name_for_introduced_bound_var(n))) + .format(", ") + )?; + } + let parameters = self.substitution.as_slice(interner); + write!( + f, + "fn({}) -> {}", + parameters[..parameters.len() - 1] + .iter() + .map(|param| param.display(s)) + .format(", "), + parameters[parameters.len() - 1].display(s), + ) + } +} + +impl RenderAsRust for ApplicationTy { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + let interner = s.db().interner(); + match self.name { + TypeName::Adt(sid) => { + write!(f, "{}", sid.display(s))?; + let parameters = self.substitution.as_slice(interner); + let parameters = parameters.iter().map(|param| param.display(s)); + write_joined_non_empty_list!(f, "<{}>", parameters, ", ")?; + } + TypeName::AssociatedType(assoc_type_id) => { + // (Iterator::Item)(x) + // should be written in Rust as ::Item + let datum = s.db().associated_ty_data(assoc_type_id); + assert!( + self.len_type_parameters(interner) >= 1, + "AssociatedType should have at least 1 parameter" + ); + write!( + f, + "<{} as {}>::{}", + self.first_type_parameter(interner).unwrap().display(s), + datum.trait_id.display(s), + datum.id.display(s), + )?; + let params = self.substitution.as_slice(interner); + write_joined_non_empty_list!( + f, + "<{}>", + params[1..].iter().map(|ty| ty.display(s)), + "," + )?; + } + TypeName::Scalar(scalar) => write!(f, "{}", scalar.display(s))?, + TypeName::Tuple(arity) => { + write!( + f, + "({}{})", + self.substitution + .as_slice(interner) + .iter() + .map(|p| p.display(s)) + .format(", "), + if arity == 1 { + // need trailing single comma + "," + } else { + "" + } + )? + } + TypeName::OpaqueType(opaque_ty_id) => { + write!( + f, + "{}", + display_type_with_generics( + s, + opaque_ty_id, + self.substitution.as_slice(interner) + ) + )?; + } + TypeName::Raw(raw) => { + let mutability = match raw { + Mutability::Mut => "*mut ", + Mutability::Not => "*const ", + }; + write!( + f, + "{}{}", + mutability, + self.first_type_parameter(interner).unwrap().display(s) + )? + } + TypeName::Ref(mutability) => { + let mutability = match mutability { + Mutability::Mut => "mut ", + Mutability::Not => "", + }; + write!( + f, + "&{} {}{}", + self.substitution.at(interner, 0).display(s), + mutability, + self.substitution.at(interner, 1).display(s) + )?; + } + TypeName::Str => write!(f, "str")?, + TypeName::Slice => { + write!( + f, + "[{}]", + self.first_type_parameter(interner).unwrap().display(s) + )?; + } + TypeName::Error => write!(f, "{{error}}")?, + TypeName::Never => write!(f, "!")?, + + // FIXME: write out valid types for these variants + TypeName::FnDef(_) => write!(f, "")?, + TypeName::Closure(..) => write!(f, "")?, + + TypeName::Array => write!( + f, + "[{}; {}]", + self.first_type_parameter(interner).unwrap().display(s), + self.substitution.at(interner, 1).display(s) + )?, + } + Ok(()) + } +} + +impl RenderAsRust for Scalar { + fn fmt(&self, _s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + use chalk_ir::{FloatTy::*, IntTy::*, UintTy::*}; + write!( + f, + "{}", + match self { + Scalar::Bool => "bool", + Scalar::Char => "char", + Scalar::Int(int) => match int { + Isize => "isize", + I8 => "i8", + I16 => "i16", + I32 => "i32", + I64 => "i64", + I128 => "i128", + }, + Scalar::Uint(uint) => match uint { + Usize => "usize", + U8 => "u8", + U16 => "u16", + U32 => "u32", + U64 => "u64", + U128 => "u128", + }, + Scalar::Float(float) => match float { + F32 => "f32", + F64 => "f64", + }, + } + ) + } +} + +impl RenderAsRust for LifetimeData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + LifetimeData::BoundVar(v) => write!(f, "'{}", s.display_bound_var(v)), + LifetimeData::InferenceVar(_) => write!(f, "'_"), + LifetimeData::Placeholder(ix) => { + write!(f, "'_placeholder_{}_{}", ix.ui.counter, ix.idx) + } + // Matching the void ensures at compile time that this code is + // unreachable + LifetimeData::Phantom(void, _) => match *void {}, + } + } +} + +impl RenderAsRust for ConstData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + write!(f, "{}", self.value.display(s)) + } +} + +impl RenderAsRust for ConstValue { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + match self { + ConstValue::BoundVar(v) => write!(f, "{}", s.display_bound_var(v)), + ConstValue::InferenceVar(_) => write!(f, "_"), + ConstValue::Placeholder(_) => write!(f, ""), + ConstValue::Concrete(_value) => unimplemented!("const values"), + } + } +} + +impl RenderAsRust for GenericArgData { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + match self { + GenericArgData::Ty(ty) => write!(f, "{}", ty.display(s)), + GenericArgData::Lifetime(lt) => write!(f, "{}", lt.display(s)), + GenericArgData::Const(const_ty) => write!(f, "{}", const_ty.display(s)), + } + } +} + +impl RenderAsRust for Ty { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to TyData + self.data(s.db().interner()).fmt(s, f) + } +} + +impl RenderAsRust for Lifetime { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to LifetimeData + self.data(s.db().interner()).fmt(s, f) + } +} + +impl RenderAsRust for Const { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &mut Formatter<'_>) -> Result { + self.data(s.db().interner()).fmt(s, f) + } +} + +impl RenderAsRust for GenericArg { + fn fmt(&self, s: &InternalWriterState<'_, I>, f: &'_ mut Formatter<'_>) -> Result { + // delegate to GenericArgData + self.data(s.db().interner()).fmt(s, f) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/display/utils.rs b/vendor/chalk-solve-0.25.0/src/display/utils.rs new file mode 100644 index 0000000000..31a8a9357d --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/display/utils.rs @@ -0,0 +1,51 @@ +//! Render utilities which don't belong anywhere else. +use std::fmt::{Display, Formatter, Result}; + +pub fn as_display) -> Result>(f: F) -> impl Display { + struct ClosureDisplay) -> Result>(F); + + impl) -> Result> Display for ClosureDisplay { + fn fmt(&self, f: &mut Formatter<'_>) -> Result { + self.0(f) + } + } + + ClosureDisplay(f) +} + +macro_rules! write_joined_non_empty_list { + ($f:expr,$template:tt,$list:expr,$sep:expr) => {{ + let mut x = $list.into_iter().peekable(); + if x.peek().is_some() { + write!($f, $template, x.format($sep)) + } else { + Ok(()) + } + }}; +} + +/// Processes a name given by an [`Interner`][chalk_ir::Interner] debug +/// method into something usable by the `display` module. +/// +/// This is specifically useful when implementing +/// [`RustIrDatabase`][crate::RustIrDatabase] `name_*` methods. +pub fn sanitize_debug_name(func: impl Fn(&mut Formatter<'_>) -> Option) -> String { + use std::fmt::Write; + + // First, write the debug method contents to a String. + let mut debug_out = String::new(); + // ignore if the result is `None`, as we can just as easily tell by looking + // to see if anything was written to `debug_out`. + write!( + debug_out, + "{}", + as_display(|fmt| { func(fmt).unwrap_or(Ok(())) }) + ) + .expect("expected writing to a String to succeed"); + if debug_out.is_empty() { + return "Unknown".to_owned(); + } + + // now the actual sanitization + debug_out.replace(|c: char| !c.is_ascii_alphanumeric(), "_") +} diff --git a/vendor/chalk-solve-0.14.0/src/ext.rs b/vendor/chalk-solve-0.25.0/src/ext.rs similarity index 100% rename from vendor/chalk-solve-0.14.0/src/ext.rs rename to vendor/chalk-solve-0.25.0/src/ext.rs diff --git a/vendor/chalk-solve-0.14.0/src/goal_builder.rs b/vendor/chalk-solve-0.25.0/src/goal_builder.rs similarity index 97% rename from vendor/chalk-solve-0.14.0/src/goal_builder.rs rename to vendor/chalk-solve-0.25.0/src/goal_builder.rs index a5bf84d163..e78b3c31dc 100644 --- a/vendor/chalk-solve-0.14.0/src/goal_builder.rs +++ b/vendor/chalk-solve-0.25.0/src/goal_builder.rs @@ -45,7 +45,7 @@ impl<'i, I: Interner> GoalBuilder<'i, I> { G: CastTo>, { GoalData::Implies( - ProgramClauses::from(self.interner(), clauses), + ProgramClauses::from_iter(self.interner(), clauses), goal(self).cast(self.interner()), ) .intern(self.interner()) @@ -132,12 +132,12 @@ impl<'i, I: Interner> GoalBuilder<'i, I> { // actually an identity mapping, since this `forall` will be the innermost // debruijn binder and so forth, so there's no actual reason to // *do* the substitution, since it would effectively just be a clone. - let substitution: Substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, binders .binders .iter(interner) - .zip(0..) + .enumerate() .map(|p| p.to_generic_arg(interner)), ); diff --git a/vendor/chalk-solve-0.14.0/src/infer.rs b/vendor/chalk-solve-0.25.0/src/infer.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/infer.rs rename to vendor/chalk-solve-0.25.0/src/infer.rs index c9fcaa51ba..df7fec405a 100644 --- a/vendor/chalk-solve-0.14.0/src/infer.rs +++ b/vendor/chalk-solve-0.25.0/src/infer.rs @@ -3,19 +3,18 @@ use chalk_ir::*; use chalk_ir::{cast::Cast, fold::Fold}; use tracing::{debug, instrument}; -pub(crate) mod canonicalize; +mod canonicalize; pub(crate) mod instantiate; mod invert; -mod normalize_deep; mod test; -pub(crate) mod ucanonicalize; -pub(crate) mod unify; -pub(crate) mod var; +pub mod ucanonicalize; +pub mod unify; +mod var; use self::var::*; #[derive(Clone)] -pub(crate) struct InferenceTable { +pub struct InferenceTable { unify: ena::unify::InPlaceUnificationTable>, vars: Vec>, max_universe: UniverseIndex, @@ -32,7 +31,7 @@ pub(crate) type ParameterEnaVariable = WithKind>; impl InferenceTable { /// Create an empty inference table with no variables. - pub(crate) fn new() -> Self { + pub fn new() -> Self { InferenceTable { unify: ena::unify::UnificationTable::new(), vars: vec![], @@ -47,7 +46,7 @@ impl InferenceTable { /// the substitution mapping from each canonical binder to its /// corresponding existential variable, along with the /// instantiated result. - pub(crate) fn from_canonical( + pub fn from_canonical( interner: &I, num_universes: usize, canonical: &Canonical, @@ -76,17 +75,17 @@ impl InferenceTable { pub(crate) fn new_universe(&mut self) -> UniverseIndex { let u = self.max_universe.next(); self.max_universe = u; - debug!("new_universe: {:?}", u); + debug!("created new universe: {:?}", u); u } /// Creates a new inference variable and returns its index. The /// kind of the variable should be known by the caller, but is not /// tracked directly by the inference table. - pub(crate) fn new_variable(&mut self, ui: UniverseIndex) -> EnaVariable { + pub fn new_variable(&mut self, ui: UniverseIndex) -> EnaVariable { let var = self.unify.new_key(InferenceValue::Unbound(ui)); self.vars.push(var); - debug!("new_variable: var={:?} ui={:?}", var, ui); + debug!(?var, ?ui, "created new variable"); var } @@ -119,12 +118,12 @@ impl InferenceTable { self.unify.commit(snapshot.unify_snapshot); } - pub(crate) fn normalize_ty_shallow(&mut self, interner: &I, leaf: &Ty) -> Option> { + pub fn normalize_ty_shallow(&mut self, interner: &I, leaf: &Ty) -> Option> { self.probe_var(leaf.inference_var(interner)?) .map(|p| p.assert_ty_ref(interner).clone()) } - pub(crate) fn normalize_lifetime_shallow( + pub fn normalize_lifetime_shallow( &mut self, interner: &I, leaf: &Lifetime, @@ -133,18 +132,14 @@ impl InferenceTable { .map(|p| p.assert_lifetime_ref(interner).clone()) } - pub(crate) fn normalize_const_shallow( - &mut self, - interner: &I, - leaf: &Const, - ) -> Option> { + pub fn normalize_const_shallow(&mut self, interner: &I, leaf: &Const) -> Option> { self.probe_var(leaf.inference_var(interner)?) .map(|p| p.assert_const_ref(interner).clone()) } /// If type `leaf` is a free inference variable, and that variable has been /// bound, returns `Some(P)` where `P` is the parameter to which it has been bound. - pub(crate) fn probe_var(&mut self, leaf: InferenceVar) -> Option> { + pub fn probe_var(&mut self, leaf: InferenceVar) -> Option> { match self.unify.probe_value(EnaVariable::from(leaf)) { InferenceValue::Unbound(_) => None, InferenceValue::Bound(val) => Some(val), @@ -164,7 +159,7 @@ impl InferenceTable { } } -pub(crate) trait ParameterEnaVariableExt { +pub trait ParameterEnaVariableExt { fn to_generic_arg(&self, interner: &I) -> GenericArg; } diff --git a/vendor/chalk-solve-0.14.0/src/infer/canonicalize.rs b/vendor/chalk-solve-0.25.0/src/infer/canonicalize.rs similarity index 93% rename from vendor/chalk-solve-0.14.0/src/infer/canonicalize.rs rename to vendor/chalk-solve-0.25.0/src/infer/canonicalize.rs index bb0c086a82..d821460681 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/canonicalize.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/canonicalize.rs @@ -1,3 +1,4 @@ +use crate::debug_span; use chalk_ir::fold::shift::Shift; use chalk_ir::fold::{Fold, Folder}; use chalk_ir::interner::{HasInterner, Interner}; @@ -26,12 +27,12 @@ impl InferenceTable { /// /// A substitution mapping from the free variables to their re-bound form is /// also returned. - pub(crate) fn canonicalize(&mut self, interner: &I, value: &T) -> Canonicalized + pub fn canonicalize(&mut self, interner: &I, value: &T) -> Canonicalized where T: Fold, T::Result: HasInterner, { - debug!("canonicalize({:#?})", value); + debug_span!("canonicalize", "{:#?}", value); let mut q = Canonicalizer { table: self, free_vars: Vec::new(), @@ -54,12 +55,12 @@ impl InferenceTable { } #[derive(Debug)] -pub(crate) struct Canonicalized { +pub struct Canonicalized { /// The canonicalized result. - pub(crate) quantified: Canonical, + pub quantified: Canonical, /// The free existential variables, along with the universes they inhabit. - pub(crate) free_vars: Vec>, + pub free_vars: Vec>, /// The maximum universe of any universally quantified variables /// encountered. @@ -81,7 +82,7 @@ impl<'q, I: Interner> Canonicalizer<'q, I> { interner, .. } = self; - CanonicalVarKinds::from( + CanonicalVarKinds::from_iter( interner, free_vars .into_iter() @@ -174,7 +175,7 @@ where ParameterEnaVariable::new(VariableKind::Ty(kind), self.table.unify.find(var)); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); - debug!("not yet unified: position={:?}", bound_var); + debug!(position=?bound_var, "not yet unified"); Ok(TyData::BoundVar(bound_var.shifted_in_from(outer_binder)).intern(interner)) } } @@ -198,7 +199,7 @@ where let free_var = ParameterEnaVariable::new(VariableKind::Lifetime, self.table.unify.find(var)); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); - debug!("not yet unified: position={:?}", bound_var); + debug!(position=?bound_var, "not yet unified"); Ok( LifetimeData::BoundVar(bound_var.shifted_in_from(outer_binder)) .intern(interner), @@ -228,7 +229,7 @@ where self.table.unify.find(var), ); let bound_var = BoundVar::new(DebruijnIndex::INNERMOST, self.add(free_var)); - debug!("not yet unified: position={:?}", bound_var); + debug!(position = ?bound_var, "not yet unified"); Ok(bound_var .shifted_in_from(outer_binder) .to_const(interner, ty.clone())) diff --git a/vendor/chalk-solve-0.14.0/src/infer/instantiate.rs b/vendor/chalk-solve-0.25.0/src/infer/instantiate.rs similarity index 92% rename from vendor/chalk-solve-0.14.0/src/infer/instantiate.rs rename to vendor/chalk-solve-0.25.0/src/infer/instantiate.rs index 9269b3b635..8250be649e 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/instantiate.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/instantiate.rs @@ -15,7 +15,7 @@ impl InferenceTable { interner: &I, binders: &[CanonicalVarKind], ) -> Substitution { - Substitution::from( + Substitution::from_iter( interner, binders.iter().map(|kind| { let param_infer_var = kind.map_ref(|&ui| self.new_variable(ui)); @@ -25,11 +25,7 @@ impl InferenceTable { } /// Variant on `instantiate` that takes a `Canonical`. - pub(crate) fn instantiate_canonical( - &mut self, - interner: &I, - bound: &Canonical, - ) -> T::Result + pub fn instantiate_canonical(&mut self, interner: &I, bound: &Canonical) -> T::Result where T: HasInterner + Fold + Debug, { @@ -62,7 +58,7 @@ impl InferenceTable { } /// Variant on `instantiate_in` that takes a `Binders`. - pub(crate) fn instantiate_binders_existentially<'a, T>( + pub fn instantiate_binders_existentially<'a, T>( &mut self, interner: &'a I, arg: impl IntoBindersAndValue<'a, I, Value = T>, @@ -75,7 +71,7 @@ impl InferenceTable { self.instantiate_in(interner, max_universe, binders, &value) } - pub(crate) fn instantiate_binders_universally<'a, T>( + pub fn instantiate_binders_universally<'a, T>( &mut self, interner: &'a I, arg: impl IntoBindersAndValue<'a, I, Value = T>, @@ -106,7 +102,7 @@ impl InferenceTable { } } -pub(crate) trait IntoBindersAndValue<'a, I: Interner> { +pub trait IntoBindersAndValue<'a, I: Interner> { type Binders: IntoIterator>; type Value; @@ -127,7 +123,7 @@ where } } -impl<'a, I> IntoBindersAndValue<'a, I> for &'a Fn +impl<'a, I> IntoBindersAndValue<'a, I> for &'a FnPointer where I: Interner, { diff --git a/vendor/chalk-solve-0.14.0/src/infer/invert.rs b/vendor/chalk-solve-0.25.0/src/infer/invert.rs similarity index 98% rename from vendor/chalk-solve-0.14.0/src/infer/invert.rs rename to vendor/chalk-solve-0.25.0/src/infer/invert.rs index ff1f59322f..5569b5a521 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/invert.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/invert.rs @@ -71,7 +71,7 @@ impl InferenceTable { /// `?T: Clone` in the case where `?T = Vec`. The current /// version would delay processing the negative goal (i.e., return /// `None`) until the second unification has occurred.) - pub(crate) fn invert(&mut self, interner: &I, value: &T) -> Option + pub fn invert(&mut self, interner: &I, value: &T) -> Option where T: Fold + HasInterner, { @@ -97,7 +97,7 @@ impl InferenceTable { /// As `negated_instantiated`, but canonicalizes before /// returning. Just a convenience function. - pub(crate) fn invert_then_canonicalize( + pub fn invert_then_canonicalize( &mut self, interner: &I, value: &T, diff --git a/vendor/chalk-solve-0.14.0/src/infer/test.rs b/vendor/chalk-solve-0.25.0/src/infer/test.rs similarity index 87% rename from vendor/chalk-solve-0.14.0/src/infer/test.rs rename to vendor/chalk-solve-0.25.0/src/infer/test.rs index eac42c1a9f..7f8486720a 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/test.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/test.rs @@ -3,29 +3,7 @@ use super::unify::UnificationResult; use super::*; use chalk_integration::interner::ChalkIr; - -#[test] -fn infer() { - let interner = &ChalkIr; - let mut table: InferenceTable = InferenceTable::new(); - let environment0 = Environment::new(interner); - let a = table.new_variable(U0).to_ty(interner); - let b = table.new_variable(U0).to_ty(interner); - table - .unify(interner, &environment0, &a, &ty!(apply (item 0) (expr b))) - .unwrap(); - assert_eq!( - table.normalize_deep(interner, &a), - ty!(apply (item 0) (expr b)) - ); - table - .unify(interner, &environment0, &b, &ty!(apply (item 1))) - .unwrap(); - assert_eq!( - table.normalize_deep(interner, &a), - ty!(apply (item 0) (apply (item 1))) - ); -} +use chalk_integration::{arg, lifetime, ty, ty_name}; #[test] fn universe_error() { @@ -181,7 +159,7 @@ fn quantify_simple() { .quantified, Canonical { value: ty!(apply (item 0) (bound 0) (bound 1) (bound 2)), - binders: CanonicalVarKinds::from( + binders: CanonicalVarKinds::from_iter( interner, vec![ CanonicalVarKind::new(VariableKind::Ty(TyKind::General), U2), @@ -222,7 +200,7 @@ fn quantify_bound() { .quantified, Canonical { value: ty!(apply (item 0) (apply (item 1) (bound 0) (bound 1)) (bound 2) (bound 0) (bound 1)), - binders: CanonicalVarKinds::from( + binders: CanonicalVarKinds::from_iter( interner, vec![ CanonicalVarKind::new(VariableKind::Ty(TyKind::General), U1), @@ -266,7 +244,7 @@ fn quantify_ty_under_binder() { .quantified, Canonical { value: ty!(function 3 (apply (item 0) (bound 1) (bound 1 0) (bound 1 0) (lifetime (bound 1 1)))), - binders: CanonicalVarKinds::from( + binders: CanonicalVarKinds::from_iter( interner, vec![ CanonicalVarKind::new(VariableKind::Ty(TyKind::General), U0), @@ -292,10 +270,8 @@ fn lifetime_constraint_indirect() { // '!1. let t_a = ty!(apply (item 0) (lifetime (placeholder 1))); let t_b = ty!(apply (item 0) (lifetime (infer 1))); - let UnificationResult { goals, constraints } = - table.unify(interner, &environment0, &t_a, &t_b).unwrap(); + let UnificationResult { goals } = table.unify(interner, &environment0, &t_a, &t_b).unwrap(); assert!(goals.is_empty()); - assert!(constraints.is_empty()); // Here, we try to unify `?0` (the type variable in universe 0) // with something that involves `'?1`. Since `'?1` has been @@ -303,16 +279,14 @@ fn lifetime_constraint_indirect() { // we will replace `'!1` with a new variable `'?2` and introduce a // (likely unsatisfiable) constraint relating them. let t_c = ty!(infer 0); - let UnificationResult { goals, constraints } = - table.unify(interner, &environment0, &t_c, &t_b).unwrap(); - assert!(goals.is_empty()); - assert_eq!(constraints.len(), 2); + let UnificationResult { goals } = table.unify(interner, &environment0, &t_c, &t_b).unwrap(); + assert_eq!(goals.len(), 2); assert_eq!( - format!("{:?}", constraints[0]), + format!("{:?}", goals[0]), "InEnvironment { environment: Env([]), goal: \'?2: \'!1_0 }", ); assert_eq!( - format!("{:?}", constraints[1]), + format!("{:?}", goals[1]), "InEnvironment { environment: Env([]), goal: \'!1_0: \'?2 }", ); } diff --git a/vendor/chalk-solve-0.14.0/src/infer/ucanonicalize.rs b/vendor/chalk-solve-0.25.0/src/infer/ucanonicalize.rs similarity index 95% rename from vendor/chalk-solve-0.14.0/src/infer/ucanonicalize.rs rename to vendor/chalk-solve-0.25.0/src/infer/ucanonicalize.rs index 507981d384..7dedc2842f 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/ucanonicalize.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/ucanonicalize.rs @@ -1,13 +1,13 @@ +use crate::debug_span; use chalk_ir::fold::{Fold, Folder}; use chalk_ir::interner::{HasInterner, Interner}; use chalk_ir::visit::{Visit, Visitor}; use chalk_ir::*; -use tracing::debug; use super::InferenceTable; impl InferenceTable { - pub(crate) fn u_canonicalize( + pub fn u_canonicalize( &mut self, interner: &I, value0: &Canonical, @@ -16,7 +16,7 @@ impl InferenceTable { T: HasInterner + Fold + Visit, T::Result: HasInterner, { - debug!("u_canonicalize({:#?})", value0); + debug_span!("u_canonicalize", "{:#?}", value0); // First, find all the universes that appear in `value`. let mut universes = UniverseMap::new(); @@ -46,7 +46,7 @@ impl InferenceTable { DebruijnIndex::INNERMOST, ) .unwrap(); - let binders = CanonicalVarKinds::from( + let binders = CanonicalVarKinds::from_iter( interner, value0 .binders @@ -68,15 +68,15 @@ impl InferenceTable { } #[derive(Debug)] -pub(crate) struct UCanonicalized { +pub struct UCanonicalized { /// The canonicalized result. - pub(crate) quantified: UCanonical, + pub quantified: UCanonical, /// A map between the universes in `quantified` and the original universes - pub(crate) universes: UniverseMap, + pub universes: UniverseMap, } -pub(crate) trait UniverseMapExt { +pub trait UniverseMapExt { fn add(&mut self, universe: UniverseIndex); fn map_universe_to_canonical(&self, universe: UniverseIndex) -> Option; fn map_universe_from_canonical(&self, universe: UniverseIndex) -> UniverseIndex; @@ -169,8 +169,7 @@ impl UniverseMapExt for UniverseMap { T::Result: HasInterner, I: Interner, { - debug!("map_from_canonical(value={:?})", canonical_value); - debug!("map_from_canonical: universes = {:?}", self.universes); + debug_span!("map_from_canonical", ?canonical_value, universes = ?self.universes); let binders = canonical_value .binders @@ -189,7 +188,7 @@ impl UniverseMapExt for UniverseMap { .unwrap(); Canonical { - binders: CanonicalVarKinds::from(interner, binders), + binders: CanonicalVarKinds::from_iter(interner, binders), value, } } diff --git a/vendor/chalk-solve-0.14.0/src/infer/unify.rs b/vendor/chalk-solve-0.25.0/src/infer/unify.rs similarity index 91% rename from vendor/chalk-solve-0.14.0/src/infer/unify.rs rename to vendor/chalk-solve-0.25.0/src/infer/unify.rs index 55229091e7..57b76d5b55 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/unify.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/unify.rs @@ -10,7 +10,7 @@ use std::fmt::Debug; impl InferenceTable { #[instrument(level = "debug", skip(self, interner, environment))] - pub(crate) fn unify( + pub fn unify( &mut self, interner: &I, environment: &Environment, @@ -37,15 +37,13 @@ impl InferenceTable { struct Unifier<'t, I: Interner> { table: &'t mut InferenceTable, environment: &'t Environment, - goals: Vec>>, - constraints: Vec>>, + goals: Vec>>, interner: &'t I, } #[derive(Debug)] -pub(crate) struct UnificationResult { - pub(crate) goals: Vec>>, - pub(crate) constraints: Vec>>, +pub struct UnificationResult { + pub goals: Vec>>, } impl<'t, I: Interner> Unifier<'t, I> { @@ -55,10 +53,9 @@ impl<'t, I: Interner> Unifier<'t, I> { environment: &'t Environment, ) -> Self { Unifier { - environment: environment, - table: table, + environment, + table, goals: vec![], - constraints: vec![], interner, } } @@ -71,10 +68,7 @@ impl<'t, I: Interner> Unifier<'t, I> { T: ?Sized + Zip, { Zip::zip_with(&mut self, a, b)?; - Ok(UnificationResult { - goals: self.goals, - constraints: self.constraints, - }) + Ok(UnificationResult { goals: self.goals }) } fn unify_ty_ty(&mut self, a: &Ty, b: &Ty) -> Fallible<()> { @@ -86,7 +80,6 @@ impl<'t, I: Interner> Unifier<'t, I> { let b = n_b.as_ref().unwrap_or(b); debug_span!("unify_ty_ty", ?a, ?b); - // let _s = span.enter(); match (a.data(interner), b.data(interner)) { // Unifying two inference variables: unify them in the underlying @@ -136,7 +129,11 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying `forall { T }` with some other forall type `forall { U }` (&TyData::Function(ref fn1), &TyData::Function(ref fn2)) => { - self.unify_binders(fn1, fn2) + if fn1.abi == fn2.abi && fn1.safety == fn2.safety && fn1.variadic == fn2.variadic { + self.unify_binders(fn1, fn2) + } else { + Err(NoSolution) + } } // This would correspond to unifying a `fn` type with a non-fn @@ -191,8 +188,8 @@ impl<'t, I: Interner> Unifier<'t, I> { } /// Unify two inference variables + #[instrument(level = "debug", skip(self))] fn unify_var_var(&mut self, a: InferenceVar, b: InferenceVar) -> Fallible<()> { - debug!("unify_var_var({:?}, {:?})", a, b); let var1 = EnaVariable::from(a); let var2 = EnaVariable::from(b); Ok(self @@ -206,16 +203,13 @@ impl<'t, I: Interner> Unifier<'t, I> { /// (type kind is not `General`). For example, unify a `TyKind::General` /// inference variable with a `TyKind::Integer` variable, resulting in the /// general inference variable narrowing to an integer variable. + + #[instrument(level = "debug", skip(self))] fn unify_general_var_specific_ty( &mut self, general_var: InferenceVar, specific_ty: Ty, ) -> Fallible<()> { - debug!( - "unify_general_var_specific_var({:?}, {:?})", - general_var, specific_ty - ); - self.table .unify .unify_var_value( @@ -227,6 +221,7 @@ impl<'t, I: Interner> Unifier<'t, I> { Ok(()) } + #[instrument(level = "debug", skip(self))] fn unify_binders<'a, T, R>( &mut self, a: impl IntoBindersAndValue<'a, I, Value = T> + Copy + Debug, @@ -244,7 +239,6 @@ impl<'t, I: Interner> Unifier<'t, I> { // for<'a...> exists<'b...> T == U && // for<'b...> exists<'a...> T == U - debug!("unify_binders({:?}, {:?})", a, b); let interner = self.interner; { @@ -307,7 +301,7 @@ impl<'t, I: Interner> Unifier<'t, I> { .unify .unify_var_value(var, InferenceValue::from_ty(interner, ty1.clone())) .unwrap(); - debug!("unify_var_ty: var {:?} set to {:?}", var, ty1); + debug!("var {:?} set to {:?}", var, ty1); Ok(()) } @@ -326,10 +320,7 @@ impl<'t, I: Interner> Unifier<'t, I> { (&LifetimeData::InferenceVar(var_a), &LifetimeData::InferenceVar(var_b)) => { let var_a = EnaVariable::from(var_a); let var_b = EnaVariable::from(var_b); - debug!( - "unify_lifetime_lifetime: var_a={:?} var_b={:?}", - var_a, var_b - ); + debug!(?var_a, ?var_b); self.table.unify.unify_var_var(var_a, var_b).unwrap(); Ok(()) } @@ -344,7 +335,7 @@ impl<'t, I: Interner> Unifier<'t, I> { (&LifetimeData::Placeholder(_), &LifetimeData::Placeholder(_)) => { if a != b { - Ok(self.push_lifetime_eq_constraint(a.clone(), b.clone())) + Ok(self.push_lifetime_eq_goals(a.clone(), b.clone())) } else { Ok(()) } @@ -371,10 +362,7 @@ impl<'t, I: Interner> Unifier<'t, I> { let var = EnaVariable::from(var); let var_ui = self.table.universe_of_unbound_var(var); if var_ui.can_see(value_ui) { - debug!( - "unify_lifetime_var: {:?} in {:?} can see {:?}; unifying", - var, var_ui, value_ui - ); + debug!("{:?} in {:?} can see {:?}; unifying", var, var_ui, value_ui); self.table .unify .unify_var_value( @@ -385,10 +373,10 @@ impl<'t, I: Interner> Unifier<'t, I> { Ok(()) } else { debug!( - "unify_lifetime_var: {:?} in {:?} cannot see {:?}; pushing constraint", + "{:?} in {:?} cannot see {:?}; pushing constraint", var, var_ui, value_ui ); - Ok(self.push_lifetime_eq_constraint(a.clone(), b.clone())) + Ok(self.push_lifetime_eq_goals(a.clone(), b.clone())) } } @@ -417,7 +405,7 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying two inference variables: unify them in the underlying // ena table. (&ConstValue::InferenceVar(var1), &ConstValue::InferenceVar(var2)) => { - // debug!("unify_ty_ty: unify_var_var({:?}, {:?})", var1, var2); + debug!(?var1, ?var2, "unify_ty_ty"); let var1 = EnaVariable::from(var1); let var2 = EnaVariable::from(var2); Ok(self @@ -430,14 +418,13 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying an inference variables with a non-inference variable. (&ConstValue::InferenceVar(var), &ConstValue::Concrete(_)) | (&ConstValue::InferenceVar(var), &ConstValue::Placeholder(_)) => { - debug!("unify_var_ty(var={:?}, ty={:?})", var, b); + debug!(?var, ty=?b, "unify_var_ty"); self.unify_var_const(var, b) } (&ConstValue::Concrete(_), &ConstValue::InferenceVar(var)) | (&ConstValue::Placeholder(_), &ConstValue::InferenceVar(var)) => { - debug!("unify_var_ty(var={:?}, ty={:?})", var, a); - + debug!(?var, ty=?a, "unify_var_ty"); self.unify_var_const(var, a) } @@ -463,9 +450,8 @@ impl<'t, I: Interner> Unifier<'t, I> { } } + #[instrument(level = "debug", skip(self))] fn unify_var_const(&mut self, var: InferenceVar, c: &Const) -> Fallible<()> { - debug!("unify_var_const(var={:?}, c={:?})", var, c); - let interner = self.interner; let var = EnaVariable::from(var); @@ -478,14 +464,18 @@ impl<'t, I: Interner> Unifier<'t, I> { Ok(()) } - fn push_lifetime_eq_constraint(&mut self, a: Lifetime, b: Lifetime) { - self.constraints.push(InEnvironment::new( + fn push_lifetime_eq_goals(&mut self, a: Lifetime, b: Lifetime) { + self.goals.push(InEnvironment::new( self.environment, - Constraint::Outlives(a.clone(), b.clone()), + WhereClause::LifetimeOutlives(LifetimeOutlives { + a: a.clone(), + b: b.clone(), + }) + .cast(self.interner), )); - self.constraints.push(InEnvironment::new( + self.goals.push(InEnvironment::new( self.environment, - Constraint::Outlives(b, a), + WhereClause::LifetimeOutlives(LifetimeOutlives { a: b, b: a }).cast(self.interner), )); } } @@ -567,6 +557,7 @@ where } } + #[instrument(level = "debug", skip(self))] fn fold_free_placeholder_lifetime( &mut self, ui: PlaceholderIndex, @@ -588,10 +579,8 @@ where // exists<'x> forall<'b> ?T = Foo<'x>, where 'x = 'b let tick_x = self.unifier.table.new_variable(self.universe_index); - self.unifier.push_lifetime_eq_constraint( - tick_x.to_lifetime(interner), - ui.to_lifetime(interner), - ); + self.unifier + .push_lifetime_eq_goals(tick_x.to_lifetime(interner), ui.to_lifetime(interner)); Ok(tick_x.to_lifetime(interner)) } else { // If the `ui` is higher than `self.universe_index`, then we can name diff --git a/vendor/chalk-solve-0.14.0/src/infer/var.rs b/vendor/chalk-solve-0.25.0/src/infer/var.rs similarity index 93% rename from vendor/chalk-solve-0.14.0/src/infer/var.rs rename to vendor/chalk-solve-0.25.0/src/infer/var.rs index eacd086171..e272f27102 100644 --- a/vendor/chalk-solve-0.14.0/src/infer/var.rs +++ b/vendor/chalk-solve-0.25.0/src/infer/var.rs @@ -36,7 +36,7 @@ use std::u32; /// "downcast" the resulting variable using /// e.g. `value.ty().unwrap()`. #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)] -pub(crate) struct EnaVariable { +pub struct EnaVariable { var: InferenceVar, phantom: PhantomData, } @@ -54,28 +54,28 @@ impl EnaVariable { /// Convert this inference variable into a type. When using this /// method, naturally you should know from context that the kind /// of this inference variable is a type (we can't check it). - pub(crate) fn to_ty_with_kind(self, interner: &I, kind: TyKind) -> Ty { + pub fn to_ty_with_kind(self, interner: &I, kind: TyKind) -> Ty { self.var.to_ty(interner, kind) } /// Same as `to_ty_with_kind`, but the kind is set to `TyKind::General`. /// This should be used instead of `to_ty_with_kind` when creating a new /// inference variable (when the kind is not known). - pub(crate) fn to_ty(self, interner: &I) -> Ty { + pub fn to_ty(self, interner: &I) -> Ty { self.var.to_ty(interner, TyKind::General) } /// Convert this inference variable into a lifetime. When using this /// method, naturally you should know from context that the kind /// of this inference variable is a lifetime (we can't check it). - pub(crate) fn to_lifetime(self, interner: &I) -> Lifetime { + pub fn to_lifetime(self, interner: &I) -> Lifetime { self.var.to_lifetime(interner) } /// Convert this inference variable into a const. When using this /// method, naturally you should know from context that the kind /// of this inference variable is a const (we can't check it). - pub(crate) fn to_const(self, interner: &I, ty: Ty) -> Const { + pub fn to_const(self, interner: &I, ty: Ty) -> Const { self.var.to_const(interner, ty) } } @@ -100,7 +100,7 @@ impl UnifyKey for EnaVariable { /// universe index; when the inference variable is assigned a value, it becomes /// bound and records that value. See `EnaVariable` for more details. #[derive(Clone, Debug, PartialEq, Eq)] -pub(crate) enum InferenceValue { +pub enum InferenceValue { Unbound(UniverseIndex), Bound(GenericArg), } diff --git a/vendor/chalk-solve-0.14.0/src/lib.rs b/vendor/chalk-solve-0.25.0/src/lib.rs similarity index 64% rename from vendor/chalk-solve-0.14.0/src/lib.rs rename to vendor/chalk-solve-0.25.0/src/lib.rs index 616d656d7d..0c6d300959 100644 --- a/vendor/chalk-solve-0.14.0/src/lib.rs +++ b/vendor/chalk-solve-0.25.0/src/lib.rs @@ -1,5 +1,6 @@ #![deny(rust_2018_idioms)] +use crate::display::sanitize_debug_name; use crate::rust_ir::*; use chalk_ir::interner::Interner; @@ -7,23 +8,39 @@ use chalk_ir::*; use std::fmt::Debug; use std::sync::Arc; -#[cfg(test)] -#[macro_use] -mod test_macros; - pub mod clauses; pub mod coherence; -mod coinductive_goal; +pub mod coinductive_goal; +pub mod display; pub mod ext; pub mod goal_builder; -mod infer; -#[cfg(feature = "recursive-solver")] -pub mod recursive; +pub mod infer; +pub mod logging; +pub mod logging_db; pub mod rust_ir; -mod solve; +pub mod solve; pub mod split; pub mod wf; +/// Trait representing access to a database of rust types. +/// +/// # `*_name` methods +/// +/// This trait has a number of `*_name` methods with default implementations. +/// These are used in the implementation for [`LoggingRustIrDatabase`], so that +/// when printing `.chalk` files equivalent to the data used, we can use real +/// names. +/// +/// The default implementations simply fall back to calling [`Interner`] debug +/// methods, and printing `"UnknownN"` (where `N` is the demultiplexing integer) +/// if those methods return `None`. +/// +/// The [`display::sanitize_debug_name`] utility is used in the default +/// implementations, and might be useful when providing custom implementations. +/// +/// [`LoggingRustIrDatabase`]: crate::logging_db::LoggingRustIrDatabase +/// [`display::sanitize_debug_name`]: crate::display::sanitize_debug_name +/// [`Interner`]: Interner pub trait RustIrDatabase: Debug { /// Returns any "custom program clauses" that do not derive from /// Rust IR. Used only in testing the underlying solver. @@ -35,9 +52,13 @@ pub trait RustIrDatabase: Debug { /// Returns the datum for the definition with the given id. fn trait_datum(&self, trait_id: TraitId) -> Arc>; - /// Returns the datum for the impl with the given id. + /// Returns the datum for the ADT with the given id. fn adt_datum(&self, adt_id: AdtId) -> Arc>; + /// Returns the representation for the ADT definition with the given id. + fn adt_repr(&self, id: AdtId) -> AdtRepr; + + /// Returns the datum for the fn definition with the given id. fn fn_def_datum(&self, fn_def_id: FnDefId) -> Arc>; /// Returns the datum for the impl with the given id. @@ -61,8 +82,15 @@ pub trait RustIrDatabase: Debug { /// apply. The parameters are provided as a "hint" to help the /// implementor do less work, but can be completely ignored if /// desired. - fn impls_for_trait(&self, trait_id: TraitId, parameters: &[GenericArg]) - -> Vec>; + /// + /// The `binders` are for the `parameters`; if the recursive solver is used, + /// the parameters can contain bound variables referring to these binders. + fn impls_for_trait( + &self, + trait_id: TraitId, + parameters: &[GenericArg], + binders: &CanonicalVarKinds, + ) -> Vec>; /// Returns the impls that require coherence checking. This is not the /// full set of impls that exist: @@ -80,17 +108,6 @@ pub trait RustIrDatabase: Debug { /// user gave). fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool; - /// A stop-gap solution to force an impl for a given well-known trait. - /// Useful when the logic for a given trait is absent or incomplete. - /// A value of `Some(true)` means that the the clause for the impl will be - /// added. A value of `Some(false)` means that the clause for the impl will - /// not be added, and fallback logic will not be checked. A value of `None` - /// means that the clause will not be added, but fallback logic may add logic. - #[allow(unused_variables)] - fn force_impl_for(&self, well_known: WellKnownTrait, ty: &TyData) -> Option { - None - } - /// Returns id of a trait lang item, if found fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option>; @@ -135,6 +152,36 @@ pub trait RustIrDatabase: Debug { closure_id: ClosureId, substs: &Substitution, ) -> Substitution; + + /// Retrieves a trait's original name. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn trait_name(&self, trait_id: TraitId) -> String { + sanitize_debug_name(|f| I::debug_trait_id(trait_id, f)) + } + + /// Retrieves a struct's original name. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn adt_name(&self, adt_id: AdtId) -> String { + sanitize_debug_name(|f| I::debug_adt_id(adt_id, f)) + } + + /// Retrieves the name of an associated type. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId) -> String { + sanitize_debug_name(|f| I::debug_assoc_type_id(assoc_ty_id, f)) + } + + /// Retrieves the name of an opaque type. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId) -> String { + sanitize_debug_name(|f| I::debug_opaque_ty_id(opaque_ty_id, f)) + } + + /// Retrieves the name of a function definition. No uniqueness guarantees, but must + /// a valid Rust identifier. + fn fn_def_name(&self, fn_def_id: FnDefId) -> String { + sanitize_debug_name(|f| I::debug_fn_def_id(fn_def_id, f)) + } } pub use clauses::program_clauses_for_env; @@ -142,7 +189,6 @@ pub use clauses::program_clauses_for_env; pub use solve::Guidance; pub use solve::Solution; pub use solve::Solver; -pub use solve::SolverChoice; pub use solve::SubstitutionResult; #[macro_use] diff --git a/vendor/chalk-solve-0.25.0/src/logging.rs b/vendor/chalk-solve-0.25.0/src/logging.rs new file mode 100644 index 0000000000..ac7305c480 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/logging.rs @@ -0,0 +1,19 @@ +/// Run an action with a tracing log subscriber. The logging level is loaded +/// from `CHALK_DEBUG`. +#[cfg(feature = "tracing-full")] +pub fn with_tracing_logs(action: impl FnOnce() -> T) -> T { + use tracing_subscriber::{layer::SubscriberExt, EnvFilter, Registry}; + use tracing_tree::HierarchicalLayer; + let filter = EnvFilter::from_env("CHALK_DEBUG"); + let subscriber = Registry::default() + .with(filter) + .with(HierarchicalLayer::new(2)); + tracing::subscriber::with_default(subscriber, action) +} + +/// Run an action with a tracing log subscriber. The logging level is loaded +/// from `CHALK_DEBUG`. +#[cfg(not(feature = "tracing-full"))] +pub fn with_tracing_logs(action: impl FnOnce() -> T) -> T { + action() +} diff --git a/vendor/chalk-solve-0.25.0/src/logging_db.rs b/vendor/chalk-solve-0.25.0/src/logging_db.rs new file mode 100644 index 0000000000..52279110db --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/logging_db.rs @@ -0,0 +1,529 @@ +//! Provides wrappers over `RustIrDatabase` which record used definitions and write +//! `.chalk` files containing those definitions. +use std::{ + borrow::Borrow, + cmp::{Ord, Ordering}, + collections::BTreeSet, + fmt::{self, Debug, Display}, + io::Write, + marker::PhantomData, + sync::Arc, + sync::Mutex, +}; + +use crate::rust_ir::*; +use crate::{ + display::{self, WriterState}, + RustIrDatabase, +}; +use chalk_ir::{interner::Interner, *}; + +mod id_collector; + +/// Wraps another `RustIrDatabase` (`DB`) and records which definitions are +/// used. +/// +/// A full .chalk file containing all used definitions can be recovered through +/// `LoggingRustIrDatabase`'s `Display` implementation. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +#[derive(Debug)] +pub struct LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + ws: WriterState, + def_ids: Mutex>>, + _phantom: PhantomData, +} + +impl LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + pub fn new(db: P) -> Self { + LoggingRustIrDatabase { + ws: WriterState::new(db), + def_ids: Default::default(), + _phantom: PhantomData, + } + } +} + +impl Display for LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let def_ids = self.def_ids.lock().unwrap(); + let stub_ids = id_collector::collect_unrecorded_ids(self.ws.db(), &def_ids); + display::write_stub_items(f, &self.ws, stub_ids)?; + display::write_items(f, &self.ws, def_ids.iter().copied()) + } +} + +impl LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow, + I: Interner, +{ + fn record(&self, id: impl Into>) { + self.def_ids.lock().unwrap().insert(id.into()); + } + + fn record_all(&self, ids: T) + where + T: IntoIterator, + U: Into>, + { + self.def_ids + .lock() + .unwrap() + .extend(ids.into_iter().map(Into::into)); + } +} + +impl RustIrDatabase for LoggingRustIrDatabase +where + DB: RustIrDatabase, + P: Borrow + Debug, + I: Interner, +{ + fn custom_clauses(&self) -> Vec> { + self.ws.db().custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId, + ) -> Arc> { + let ty_datum = self.ws.db().associated_ty_data(ty); + self.record(ty_datum.trait_id); + ty_datum + } + + fn trait_datum(&self, trait_id: TraitId) -> Arc> { + self.record(trait_id); + self.ws.db().trait_datum(trait_id) + } + + fn adt_datum(&self, adt_id: AdtId) -> Arc> { + self.record(adt_id); + self.ws.db().adt_datum(adt_id) + } + + fn adt_repr(&self, id: AdtId) -> AdtRepr { + self.record(id); + self.ws.db().adt_repr(id) + } + + fn impl_datum(&self, impl_id: ImplId) -> Arc> { + self.record(impl_id); + self.ws.db().impl_datum(impl_id) + } + + fn hidden_opaque_type(&self, id: OpaqueTyId) -> Ty { + self.record(id); + self.ws.db().hidden_opaque_type(id) + } + + fn associated_ty_value( + &self, + id: crate::rust_ir::AssociatedTyValueId, + ) -> Arc> { + let value = self.ws.db().associated_ty_value(id); + self.record(value.impl_id); + value + } + + fn opaque_ty_data(&self, id: OpaqueTyId) -> Arc> { + self.record(id); + self.ws.db().opaque_ty_data(id) + } + + fn impls_for_trait( + &self, + trait_id: TraitId, + parameters: &[chalk_ir::GenericArg], + binders: &CanonicalVarKinds, + ) -> Vec> { + self.record(trait_id); + let impl_ids = self.ws.db().impls_for_trait(trait_id, parameters, binders); + self.record_all(impl_ids.iter().copied()); + impl_ids + } + + fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec> { + self.record(trait_id); + self.ws.db().local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + self.record(auto_trait_id); + self.record(adt_id); + self.ws.db().impl_provided_for(auto_trait_id, adt_id) + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option> { + let trait_id = self.ws.db().well_known_trait_id(well_known_trait); + trait_id.map(|id| self.record(id)); + trait_id + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment, + ) -> chalk_ir::ProgramClauses { + self.ws.db().program_clauses_for_env(environment) + } + + fn interner(&self) -> &I { + self.ws.db().interner() + } + + fn trait_name(&self, trait_id: TraitId) -> String { + self.ws.db().trait_name(trait_id) + } + + fn adt_name(&self, adt_id: AdtId) -> String { + self.ws.db().adt_name(adt_id) + } + + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId) -> String { + self.ws.db().assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId) -> String { + self.ws.db().opaque_type_name(opaque_ty_id) + } + + fn is_object_safe(&self, trait_id: TraitId) -> bool { + self.record(trait_id); + self.ws.db().is_object_safe(trait_id) + } + + fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId) -> Arc> { + self.record(fn_def_id); + self.ws.db().fn_def_datum(fn_def_id) + } + + fn fn_def_name(&self, fn_def_id: FnDefId) -> String { + self.ws.db().fn_def_name(fn_def_id) + } + + fn closure_kind(&self, closure_id: ClosureId, substs: &Substitution) -> ClosureKind { + // TODO: record closure IDs + self.ws.db().closure_kind(closure_id, substs) + } + + fn closure_inputs_and_output( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Binders> { + // TODO: record closure IDs + self.ws.db().closure_inputs_and_output(closure_id, substs) + } + + fn closure_upvars(&self, closure_id: ClosureId, substs: &Substitution) -> Binders> { + // TODO: record closure IDs + self.ws.db().closure_upvars(closure_id, substs) + } + + fn closure_fn_substitution( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Substitution { + // TODO: record closure IDs + self.ws.db().closure_fn_substitution(closure_id, substs) + } +} + +/// Wraps a [`RustIrDatabase`], and, when dropped, writes out all used +/// definition to the given file. +/// +/// Uses [`LoggingRustIrDatabase`] internally. +/// +/// Uses a separate type, `P`, for the database stored inside to account for +/// `Arc` or wrapping other storage mediums. +pub struct WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow, +{ + db: LoggingRustIrDatabase, + write: W, +} + +impl fmt::Debug for WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow + fmt::Debug, +{ + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("WriteOnDropRustIrDatabase") + .field("db", &self.db) + .field("write", &"") + .finish() + } +} + +impl WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow, +{ + pub fn new(db: P, write: W) -> Self { + WriteOnDropRustIrDatabase { + db: LoggingRustIrDatabase::new(db), + write, + } + } + + pub fn from_logging_db(db: LoggingRustIrDatabase, write: W) -> Self { + WriteOnDropRustIrDatabase { db, write } + } +} + +impl Drop for WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow, +{ + fn drop(&mut self) { + write!(self.write, "{}", self.db) + .and_then(|_| self.write.flush()) + .expect("expected to be able to write rust ir database"); + } +} + +impl RustIrDatabase for WriteOnDropRustIrDatabase +where + I: Interner, + W: Write, + DB: RustIrDatabase, + P: Borrow + Debug, +{ + fn custom_clauses(&self) -> Vec> { + self.db.custom_clauses() + } + + fn associated_ty_data( + &self, + ty: chalk_ir::AssocTypeId, + ) -> Arc> { + self.db.associated_ty_data(ty) + } + + fn trait_datum(&self, trait_id: TraitId) -> Arc> { + self.db.trait_datum(trait_id) + } + + fn adt_datum(&self, adt_id: AdtId) -> Arc> { + self.db.adt_datum(adt_id) + } + + fn adt_repr(&self, id: AdtId) -> AdtRepr { + self.db.adt_repr(id) + } + + fn impl_datum(&self, impl_id: ImplId) -> Arc> { + self.db.impl_datum(impl_id) + } + + fn associated_ty_value( + &self, + id: crate::rust_ir::AssociatedTyValueId, + ) -> Arc> { + self.db.associated_ty_value(id) + } + + fn opaque_ty_data(&self, id: OpaqueTyId) -> Arc> { + self.db.opaque_ty_data(id) + } + + fn hidden_opaque_type(&self, id: OpaqueTyId) -> Ty { + self.db.hidden_opaque_type(id) + } + + fn impls_for_trait( + &self, + trait_id: TraitId, + parameters: &[chalk_ir::GenericArg], + binders: &CanonicalVarKinds, + ) -> Vec> { + self.db.impls_for_trait(trait_id, parameters, binders) + } + + fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec> { + self.db.local_impls_to_coherence_check(trait_id) + } + + fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + self.db.impl_provided_for(auto_trait_id, adt_id) + } + + fn well_known_trait_id( + &self, + well_known_trait: crate::rust_ir::WellKnownTrait, + ) -> Option> { + self.db.well_known_trait_id(well_known_trait) + } + + fn program_clauses_for_env( + &self, + environment: &chalk_ir::Environment, + ) -> chalk_ir::ProgramClauses { + self.db.program_clauses_for_env(environment) + } + + fn interner(&self) -> &I { + self.db.interner() + } + + fn is_object_safe(&self, trait_id: TraitId) -> bool { + self.db.is_object_safe(trait_id) + } + + fn trait_name(&self, trait_id: TraitId) -> String { + self.db.trait_name(trait_id) + } + + fn adt_name(&self, adt_id: AdtId) -> String { + self.db.adt_name(adt_id) + } + + fn assoc_type_name(&self, assoc_ty_id: AssocTypeId) -> String { + self.db.assoc_type_name(assoc_ty_id) + } + + fn opaque_type_name(&self, opaque_ty_id: OpaqueTyId) -> String { + self.db.opaque_type_name(opaque_ty_id) + } + + fn fn_def_datum(&self, fn_def_id: chalk_ir::FnDefId) -> Arc> { + self.db.fn_def_datum(fn_def_id) + } + + fn fn_def_name(&self, fn_def_id: FnDefId) -> String { + self.db.fn_def_name(fn_def_id) + } + + fn closure_kind(&self, closure_id: ClosureId, substs: &Substitution) -> ClosureKind { + // TODO: record closure IDs + self.db.closure_kind(closure_id, substs) + } + + fn closure_inputs_and_output( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Binders> { + self.db.closure_inputs_and_output(closure_id, substs) + } + + fn closure_upvars(&self, closure_id: ClosureId, substs: &Substitution) -> Binders> { + self.db.closure_upvars(closure_id, substs) + } + + fn closure_fn_substitution( + &self, + closure_id: ClosureId, + substs: &Substitution, + ) -> Substitution { + self.db.closure_fn_substitution(closure_id, substs) + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +pub enum RecordedItemId { + Adt(AdtId), + Trait(TraitId), + Impl(ImplId), + OpaqueTy(OpaqueTyId), + FnDef(FnDefId), +} + +impl From> for RecordedItemId { + fn from(v: AdtId) -> Self { + RecordedItemId::Adt(v) + } +} + +impl From> for RecordedItemId { + fn from(v: TraitId) -> Self { + RecordedItemId::Trait(v) + } +} + +impl From> for RecordedItemId { + fn from(v: ImplId) -> Self { + RecordedItemId::Impl(v) + } +} + +impl From> for RecordedItemId { + fn from(v: OpaqueTyId) -> Self { + RecordedItemId::OpaqueTy(v) + } +} + +impl From> for RecordedItemId { + fn from(v: FnDefId) -> Self { + RecordedItemId::FnDef(v) + } +} + +/// Utility for implementing Ord for RecordedItemId. +#[derive(PartialEq, Eq, PartialOrd, Ord)] +enum OrderedItemId<'a, DefId, AdtId> { + DefId(&'a DefId), + AdtId(&'a AdtId), +} + +impl RecordedItemId { + /// Extract internal identifier. Allows for absolute ordering matching the + /// order in which chalk saw things (and thus reproducing that order in + /// printed programs) + fn ordered_item_id(&self) -> OrderedItemId<'_, I::DefId, I::InternedAdtId> { + match self { + RecordedItemId::Trait(TraitId(x)) + | RecordedItemId::Impl(ImplId(x)) + | RecordedItemId::OpaqueTy(OpaqueTyId(x)) + | RecordedItemId::FnDef(FnDefId(x)) => OrderedItemId::DefId(x), + RecordedItemId::Adt(AdtId(x)) => OrderedItemId::AdtId(x), + } + } +} + +impl PartialOrd for RecordedItemId { + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } +} + +impl Ord for RecordedItemId { + fn cmp(&self, other: &Self) -> Ordering { + self.ordered_item_id().cmp(&other.ordered_item_id()) + } +} diff --git a/vendor/chalk-solve-0.25.0/src/logging_db/id_collector.rs b/vendor/chalk-solve-0.25.0/src/logging_db/id_collector.rs new file mode 100644 index 0000000000..9c3dd8d866 --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/logging_db/id_collector.rs @@ -0,0 +1,170 @@ +use super::RecordedItemId; +use crate::RustIrDatabase; +use chalk_ir::{ + interner::Interner, + visit::Visitor, + visit::{SuperVisit, Visit}, + AliasTy, DebruijnIndex, TyData, TypeName, WhereClause, +}; +use std::collections::BTreeSet; + +/// Collects the identifiers needed to resolve all the names for a given +/// set of identifers, excluding identifiers we already have. +/// +/// When recording identifiers to print, the `LoggingRustIrDatabase` only +/// records identifiers the solver uses. But the solver assumes well-formedness, +/// and thus skips over many names referenced in the definitions. +/// +/// For instance, if we have: +/// +/// ```rust,ignore +/// struct S {} +/// +/// trait Parent {} +/// trait Child where Self: Parent {} +/// impl Parent for S {} +/// impl Child for S {} +/// ``` +/// +/// And our goal is `S: Child`, we will only render `S`, `impl Child for S`, and +/// `trait Child`. This will not parse because the `Child` trait's definition +/// references parent. IdCollector solves this by collecting all of the directly +/// related identifiers, allowing those to be rendered as well, ensuring name +/// resolution is successful. +pub fn collect_unrecorded_ids<'i, I: Interner, DB: RustIrDatabase>( + db: &'i DB, + identifiers: &'_ BTreeSet>, +) -> BTreeSet> { + let mut collector = IdCollector { + db, + found_identifiers: BTreeSet::new(), + }; + for id in identifiers { + match *id { + RecordedItemId::Adt(adt_id) => { + collector + .db + .adt_datum(adt_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::FnDef(fn_def) => { + collector + .db + .fn_def_datum(fn_def) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::Trait(trait_id) => { + let trait_datum = collector.db.trait_datum(trait_id); + + trait_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); + for assoc_ty_id in &trait_datum.associated_ty_ids { + let assoc_ty_datum = collector.db.associated_ty_data(*assoc_ty_id); + assoc_ty_datum + .bounds_on_self(collector.db.interner()) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + assoc_ty_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST) + } + } + RecordedItemId::OpaqueTy(opaque_id) => { + collector + .db + .opaque_ty_data(opaque_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + collector + .db + .hidden_opaque_type(opaque_id) + .visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + RecordedItemId::Impl(impl_id) => { + let impl_datum = collector.db.impl_datum(impl_id); + for id in &impl_datum.associated_ty_value_ids { + let assoc_ty_value = collector.db.associated_ty_value(*id); + assoc_ty_value.visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + impl_datum.visit_with(&mut collector, DebruijnIndex::INNERMOST); + } + } + } + collector + .found_identifiers + .difference(identifiers) + .copied() + .collect() +} + +struct IdCollector<'i, I: Interner, DB: RustIrDatabase> { + db: &'i DB, + found_identifiers: BTreeSet>, +} + +impl<'i, I: Interner, DB: RustIrDatabase> IdCollector<'i, I, DB> { + fn record(&mut self, id: impl Into>) { + self.found_identifiers.insert(id.into()); + } +} + +impl<'i, I: Interner, DB: RustIrDatabase> Visitor<'i, I> for IdCollector<'i, I, DB> +where + I: 'i, +{ + type Result = (); + fn as_dyn(&mut self) -> &mut dyn Visitor<'i, I, Result = Self::Result> { + self + } + fn interner(&self) -> &'i I { + self.db.interner() + } + + fn visit_ty( + &mut self, + ty: &chalk_ir::Ty, + outer_binder: chalk_ir::DebruijnIndex, + ) -> Self::Result { + let ty_data = ty.data(self.db.interner()); + match ty_data { + TyData::Apply(apply_ty) => match apply_ty.name { + TypeName::Adt(adt) => self.record(adt), + TypeName::FnDef(fn_def) => self.record(fn_def), + TypeName::OpaqueType(opaque) => self.record(opaque), + _ => {} + }, + TyData::Alias(alias) => match alias { + AliasTy::Projection(projection_ty) => { + let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id); + self.record(assoc_ty_datum.trait_id) + } + AliasTy::Opaque(opaque_ty) => { + self.record(opaque_ty.opaque_ty_id); + } + }, + TyData::BoundVar(..) => (), + TyData::Dyn(..) => (), + TyData::Function(..) => (), + TyData::InferenceVar(..) => (), + TyData::Placeholder(..) => (), + } + ty.super_visit_with(self, outer_binder) + } + + fn visit_where_clause( + &mut self, + where_clause: &WhereClause, + outer_binder: DebruijnIndex, + ) -> Self::Result { + match where_clause { + WhereClause::Implemented(trait_ref) => self.record(trait_ref.trait_id), + WhereClause::AliasEq(alias_eq) => match &alias_eq.alias { + AliasTy::Projection(projection_ty) => { + let assoc_ty_datum = self.db.associated_ty_data(projection_ty.associated_ty_id); + self.record(assoc_ty_datum.trait_id) + } + AliasTy::Opaque(opaque_ty) => { + self.record(opaque_ty.opaque_ty_id); + } + }, + WhereClause::LifetimeOutlives(_lifetime_outlives) => (), + WhereClause::TypeOutlives(_type_outlives) => (), + } + where_clause.super_visit_with(self.as_dyn(), outer_binder) + } +} diff --git a/vendor/chalk-solve-0.14.0/src/recursive/lib.rs b/vendor/chalk-solve-0.25.0/src/recursive/lib.rs similarity index 96% rename from vendor/chalk-solve-0.14.0/src/recursive/lib.rs rename to vendor/chalk-solve-0.25.0/src/recursive/lib.rs index b81a41fb55..8c30267eef 100644 --- a/vendor/chalk-solve-0.14.0/src/recursive/lib.rs +++ b/vendor/chalk-solve-0.25.0/src/recursive/lib.rs @@ -1,6 +1,8 @@ use super::search_graph::DepthFirstNumber; use chalk_ir::interner::Interner; -use chalk_ir::{Canonical, ConstrainedSubst, Goal, InEnvironment, Substitution, UCanonical}; +use chalk_ir::{ + Canonical, ConstrainedSubst, Constraints, Goal, InEnvironment, Substitution, UCanonical, +}; use std::fmt; use tracing::debug; @@ -118,14 +120,14 @@ impl Solution { } /// Extract a constrained substitution from this solution, even if ambiguous. - pub(crate) fn constrained_subst(&self) -> Option>> { + pub(crate) fn constrained_subst(&self, interner: &I) -> Option>> { match *self { Solution::Unique(ref constrained) => Some(constrained.clone()), Solution::Ambig(Guidance::Definite(ref canonical)) | Solution::Ambig(Guidance::Suggested(ref canonical)) => { let value = ConstrainedSubst { subst: canonical.value.clone(), - constraints: vec![], + constraints: Constraints::empty(interner), }; Some(Canonical { value, diff --git a/vendor/chalk-solve-0.14.0/src/rust_ir.rs b/vendor/chalk-solve-0.25.0/src/rust_ir.rs similarity index 84% rename from vendor/chalk-solve-0.14.0/src/rust_ir.rs rename to vendor/chalk-solve-0.25.0/src/rust_ir.rs index 7b576539dd..74fdd85b4d 100644 --- a/vendor/chalk-solve-0.14.0/src/rust_ir.rs +++ b/vendor/chalk-solve-0.25.0/src/rust_ir.rs @@ -1,5 +1,3 @@ -#![deny(rust_2018_idioms)] - //! Contains the definition for the "Rust IR" -- this is basically a "lowered" //! version of the AST, roughly corresponding to [the HIR] in the Rust //! compiler. @@ -9,9 +7,10 @@ use chalk_ir::cast::Cast; use chalk_ir::fold::shift::Shift; use chalk_ir::interner::{Interner, TargetInterner}; use chalk_ir::{ + visit::{Visit, VisitResult}, AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, FnDefId, GenericArg, ImplId, - OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, - Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, + OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Safety, Substitution, ToGenericArg, TraitId, + TraitRef, Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, }; use std::iter; @@ -19,9 +18,10 @@ use std::iter; #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct AssociatedTyValueId(pub I::DefId); +chalk_ir::id_visit!(AssociatedTyValueId); chalk_ir::id_fold!(AssociatedTyValueId); -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Visit)] pub struct ImplDatum { pub polarity: Polarity, pub binders: Binders>, @@ -55,7 +55,7 @@ impl ImplDatum { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Fold)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Fold, Visit)] pub struct ImplDatumBound { pub trait_ref: TraitRef, pub where_clauses: Vec>, @@ -67,6 +67,8 @@ pub enum ImplType { External, } +chalk_ir::const_visit!(ImplType); + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct DefaultImplDatum { pub binders: Binders>, @@ -78,25 +80,40 @@ pub struct DefaultImplDatumBound { pub accessible_tys: Vec>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Visit)] pub struct AdtDatum { pub binders: Binders>, pub id: AdtId, pub flags: AdtFlags, + pub kind: AdtKind, } +#[derive(Copy, Clone, PartialEq, Eq, Debug, Hash)] +pub enum AdtKind { + Struct, + Enum, + Union, +} + +chalk_ir::const_visit!(AdtKind); + impl AdtDatum { pub fn name(&self, interner: &I) -> TypeName { self.id.cast(interner) } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct AdtDatumBound { - pub fields: Vec>, + pub variants: Vec>, pub where_clauses: Vec>, } +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] +pub struct AdtVariantDatum { + pub fields: Vec>, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] pub struct AdtFlags { pub upstream: bool, @@ -104,6 +121,14 @@ pub struct AdtFlags { pub phantom_data: bool, } +chalk_ir::const_visit!(AdtFlags); + +#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] +pub struct AdtRepr { + pub repr_c: bool, + pub repr_packed: bool, +} + #[derive(Clone, Debug, PartialEq, Eq, Hash)] /// A rust intermediate represention (rust_ir) of a function definition/declaration. /// For example, in the following rust code: @@ -120,12 +145,32 @@ pub struct AdtFlags { pub struct FnDefDatum { pub id: FnDefId, pub abi: I::FnAbi, + pub safety: Safety, + pub variadic: bool, pub binders: Binders>, } +/// Avoids visiting `I::FnAbi` +impl Visit for FnDefDatum { + fn visit_with<'i, R: VisitResult>( + &self, + visitor: &mut dyn chalk_ir::visit::Visitor<'i, I, Result = R>, + outer_binder: DebruijnIndex, + ) -> R + where + I: 'i, + { + let result = R::new().combine(self.id.visit_with(visitor, outer_binder)); + if result.return_early() { + return result; + } + result.combine(self.binders.visit_with(visitor, outer_binder)) + } +} + /// Represents the inputs and outputs on a `FnDefDatum`. This is split /// from the where clauses, since these can contain bound lifetimes. -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct FnDefInputsAndOutputDatum { /// Types of the function's arguments /// ```ignore @@ -142,7 +187,7 @@ pub struct FnDefInputsAndOutputDatum { pub return_type: Ty, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] /// Represents the bounds on a `FnDefDatum`, including /// the function definition's type signature and where clauses. pub struct FnDefDatumBound { @@ -193,6 +238,7 @@ pub struct FnDefDatumBound { /// /// [`ImplDatum`]: struct.ImplDatum.html /// [`AssociatedTyDatum`]: struct.AssociatedTyDatum.html +#[derive(Visit)] pub struct TraitDatum { pub id: TraitId, @@ -227,6 +273,8 @@ pub enum WellKnownTrait { Unsize, } +chalk_ir::const_visit!(WellKnownTrait); + impl TraitDatum { pub fn is_auto_trait(&self) -> bool { self.flags.auto @@ -251,7 +299,7 @@ impl TraitDatum { } } -#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, HasInterner, Visit)] pub struct TraitDatumBound { /// Where clauses defined on the trait: /// @@ -295,6 +343,8 @@ pub struct TraitFlags { pub coinductive: bool, } +chalk_ir::const_visit!(TraitFlags); + /// An inline bound, e.g. `: Foo` in `impl> SomeType`. #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] pub enum InlineBound { @@ -355,7 +405,7 @@ impl TraitBound { pub fn as_trait_ref(&self, interner: &I, self_ty: Ty) -> TraitRef { TraitRef { trait_id: self.trait_id, - substitution: Substitution::from( + substitution: Substitution::from_iter( interner, iter::once(self_ty.cast(interner)).chain(self.args_no_self.iter().cloned()), ), @@ -378,7 +428,7 @@ impl AliasEqBound { fn into_where_clauses(&self, interner: &I, self_ty: Ty) -> Vec> { let trait_ref = self.trait_bound.as_trait_ref(interner, self_ty); - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, self.parameters .iter() @@ -448,6 +498,28 @@ pub struct AssociatedTyDatum { pub binders: Binders>, } +// Manual implementation to avoid I::Identifier type. +impl Visit for AssociatedTyDatum { + fn visit_with<'i, R: VisitResult>( + &self, + visitor: &mut dyn chalk_ir::visit::Visitor<'i, I, Result = R>, + outer_binder: DebruijnIndex, + ) -> R + where + I: 'i, + { + let result = R::new().combine(self.trait_id.visit_with(visitor, outer_binder)); + if result.return_early() { + return result; + } + let result = result.combine(self.id.visit_with(visitor, outer_binder)); + if result.return_early() { + return result; + } + result.combine(self.binders.visit_with(visitor, outer_binder)) + } +} + /// Encodes the parts of `AssociatedTyDatum` where the parameters /// `P0..Pm` are in scope (`bounds` and `where_clauses`). #[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit, HasInterner)] @@ -475,11 +547,11 @@ impl AssociatedTyDatum { let (binders, assoc_ty_datum) = self.binders.as_ref().into(); // Create a list `P0...Pn` of references to the binders in // scope for this associated type: - let substitution = Substitution::from( + let substitution = Substitution::from_iter( interner, binders .iter(interner) - .zip(0..) + .enumerate() .map(|p| p.to_generic_arg(interner)), ); @@ -562,7 +634,7 @@ pub struct AssociatedTyValueBound { /// ```ignore /// opaque type T: A + B = HiddenTy; /// ``` -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, Visit)] pub struct OpaqueTyDatum { /// The placeholder `!T` that corresponds to the opaque type `T`. pub opaque_ty_id: OpaqueTyId, @@ -571,10 +643,14 @@ pub struct OpaqueTyDatum { pub bound: Binders>, } -#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner)] +#[derive(Clone, Debug, PartialEq, Eq, Hash, Fold, HasInterner, Visit)] pub struct OpaqueTyDatumBound { - /// Trait bounds for the opaque type. + /// Trait bounds for the opaque type. These are bounds that the hidden type must meet. pub bounds: Binders>>, + /// Where clauses that inform well-formedness conditions for the opaque type. + /// These are conditions on the generic parameters of the opaque type which must be true + /// for a reference to the opaque type to be well-formed. + pub where_clauses: Binders>>, } #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord, Debug)] @@ -583,6 +659,8 @@ pub enum Polarity { Negative, } +chalk_ir::const_visit!(Polarity); + impl Polarity { pub fn is_positive(&self) -> bool { match *self { diff --git a/vendor/chalk-solve-0.25.0/src/solve.rs b/vendor/chalk-solve-0.25.0/src/solve.rs new file mode 100644 index 0000000000..dc74045acd --- /dev/null +++ b/vendor/chalk-solve-0.25.0/src/solve.rs @@ -0,0 +1,206 @@ +use crate::RustIrDatabase; +use chalk_derive::HasInterner; +use chalk_ir::interner::Interner; +use chalk_ir::*; +use std::fmt; + +pub mod truncate; + +/// A (possible) solution for a proposed goal. +#[derive(Clone, Debug, PartialEq, Eq, HasInterner)] +pub enum Solution { + /// The goal indeed holds, and there is a unique value for all existential + /// variables. In this case, we also record a set of lifetime constraints + /// which must also hold for the goal to be valid. + Unique(Canonical>), + + /// The goal may be provable in multiple ways, but regardless we may have some guidance + /// for type inference. In this case, we don't return any lifetime + /// constraints, since we have not "committed" to any particular solution + /// yet. + Ambig(Guidance), +} + +/// When a goal holds ambiguously (e.g., because there are multiple possible +/// solutions), we issue a set of *guidance* back to type inference. +#[derive(Clone, Debug, PartialEq, Eq)] +pub enum Guidance { + /// The existential variables *must* have the given values if the goal is + /// ever to hold, but that alone isn't enough to guarantee the goal will + /// actually hold. + Definite(Canonical>), + + /// There are multiple plausible values for the existentials, but the ones + /// here are suggested as the preferred choice heuristically. These should + /// be used for inference fallback only. + Suggested(Canonical>), + + /// There's no useful information to feed back to type inference + Unknown, +} + +impl Solution { + pub fn is_unique(&self) -> bool { + match *self { + Solution::Unique(..) => true, + _ => false, + } + } + + pub fn display<'a>(&'a self, interner: &'a I) -> SolutionDisplay<'a, I> { + SolutionDisplay { + solution: self, + interner, + } + } +} + +pub struct SolutionDisplay<'a, I: Interner> { + solution: &'a Solution, + interner: &'a I, +} + +impl<'a, I: Interner> fmt::Display for SolutionDisplay<'a, I> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> Result<(), fmt::Error> { + let SolutionDisplay { solution, interner } = self; + match solution { + Solution::Unique(constrained) => write!(f, "Unique; {}", constrained.display(interner)), + Solution::Ambig(Guidance::Definite(subst)) => write!( + f, + "Ambiguous; definite substitution {}", + subst.display(interner) + ), + Solution::Ambig(Guidance::Suggested(subst)) => write!( + f, + "Ambiguous; suggested substitution {}", + subst.display(interner) + ), + Solution::Ambig(Guidance::Unknown) => write!(f, "Ambiguous; no inference guidance"), + } + } +} + +#[derive(Debug)] +pub enum SubstitutionResult { + Definite(S), + Ambiguous(S), + Floundered, +} + +impl SubstitutionResult { + pub fn as_ref(&self) -> SubstitutionResult<&S> { + match self { + SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(subst), + SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(subst), + SubstitutionResult::Floundered => SubstitutionResult::Floundered, + } + } + pub fn map U>(self, f: F) -> SubstitutionResult { + match self { + SubstitutionResult::Definite(subst) => SubstitutionResult::Definite(f(subst)), + SubstitutionResult::Ambiguous(subst) => SubstitutionResult::Ambiguous(f(subst)), + SubstitutionResult::Floundered => SubstitutionResult::Floundered, + } + } +} + +impl fmt::Display for SubstitutionResult { + fn fmt(&self, fmt: &mut fmt::Formatter<'_>) -> fmt::Result { + match self { + SubstitutionResult::Definite(subst) => write!(fmt, "{}", subst), + SubstitutionResult::Ambiguous(subst) => write!(fmt, "Ambiguous({})", subst), + SubstitutionResult::Floundered => write!(fmt, "Floundered"), + } + } +} + +/// Finds the solution to "goals", or trait queries -- i.e., figures +/// out what sets of types implement which traits. Also, between +/// queries, this struct stores the cached state from previous solver +/// attempts, which can then be re-used later. +pub trait Solver +where + Self: fmt::Debug, +{ + /// Attempts to solve the given goal, which must be in canonical + /// form. Returns a unique solution (if one exists). This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// + /// # Returns + /// + /// - `None` is the goal cannot be proven. + /// - `Some(solution)` if we succeeded in finding *some* answers, + /// although `solution` may reflect ambiguity and unknowns. + fn solve( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + ) -> Option>; + + /// Attempts to solve the given goal, which must be in canonical + /// form. Returns a unique solution (if one exists). This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). In addition, the solving of the + /// goal can be limited by returning `false` from `should_continue`. + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// - `should_continue` if `false` is returned, the no further solving + /// will be done. A `Guidance(Suggested(...))` will be returned a + /// `Solution`, using any answers that were generated up to that point. + /// + /// # Returns + /// + /// - `None` is the goal cannot be proven. + /// - `Some(solution)` if we succeeded in finding *some* answers, + /// although `solution` may reflect ambiguity and unknowns. + fn solve_limited( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + should_continue: &dyn std::ops::Fn() -> bool, + ) -> Option>; + + /// Attempts to solve the given goal, which must be in canonical + /// form. Provides multiple solutions to function `f`. This will do + /// only as much work towards `goal` as it has to (and that work + /// is cached for future attempts). + /// + /// # Parameters + /// + /// - `program` -- defines the program clauses in scope. + /// - **Important:** You must supply the same set of program clauses + /// each time you invoke `solve`, as otherwise the cached data may be + /// invalid. + /// - `goal` the goal to solve + /// - `f` -- function to proceed solution. New solutions will be generated + /// while function returns `true`. + /// - first argument is solution found + /// - second argument is ther next solution present + /// - returns true if next solution should be handled + /// + /// # Returns + /// + /// - `true` all solutions were processed with the function. + /// - `false` the function returned `false` and solutions were interrupted. + fn solve_multiple( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + f: &mut dyn FnMut(SubstitutionResult>>, bool) -> bool, + ) -> bool; +} diff --git a/vendor/chalk-solve-0.14.0/src/solve/test/bench.rs b/vendor/chalk-solve-0.25.0/src/solve/test/bench.rs similarity index 100% rename from vendor/chalk-solve-0.14.0/src/solve/test/bench.rs rename to vendor/chalk-solve-0.25.0/src/solve/test/bench.rs diff --git a/vendor/chalk-solve-0.14.0/src/solve/truncate.rs b/vendor/chalk-solve-0.25.0/src/solve/truncate.rs similarity index 97% rename from vendor/chalk-solve-0.14.0/src/solve/truncate.rs rename to vendor/chalk-solve-0.25.0/src/solve/truncate.rs index a56528ba12..44c5ea81ea 100644 --- a/vendor/chalk-solve-0.14.0/src/solve/truncate.rs +++ b/vendor/chalk-solve-0.25.0/src/solve/truncate.rs @@ -6,7 +6,7 @@ use chalk_ir::visit::{SuperVisit, Visit, Visitor}; use chalk_ir::*; use std::cmp::max; -pub(crate) fn needs_truncation( +pub fn needs_truncation( interner: &I, infer: &mut InferenceTable, max_size: usize, @@ -73,6 +73,8 @@ impl<'infer, 'i, I: Interner> Visitor<'i, I> for TySizeVisitor<'infer, 'i, I> { #[cfg(test)] mod tests { use super::*; + use chalk_integration::{arg, ty, ty_name}; + #[test] fn one_type() { use chalk_integration::interner::ChalkIr; diff --git a/vendor/chalk-solve-0.14.0/src/split.rs b/vendor/chalk-solve-0.25.0/src/split.rs similarity index 79% rename from vendor/chalk-solve-0.14.0/src/split.rs rename to vendor/chalk-solve-0.25.0/src/split.rs index 616958d006..b94adc195d 100644 --- a/vendor/chalk-solve-0.14.0/src/split.rs +++ b/vendor/chalk-solve-0.25.0/src/split.rs @@ -27,12 +27,10 @@ pub trait Split: RustIrDatabase { associated_ty_id, ref substitution, } = *projection; - let parameters = substitution.parameters(interner); + let parameters = substitution.as_slice(interner); let associated_ty_data = &self.associated_ty_data(associated_ty_id); - let trait_datum = &self.trait_datum(associated_ty_data.trait_id); - let trait_num_params = trait_datum.binders.len(interner); - let split_point = parameters.len() - trait_num_params; - let (other_params, trait_params) = parameters.split_at(split_point); + let (trait_params, other_params) = + self.split_associated_ty_parameters(parameters, &**associated_ty_data); (associated_ty_data.clone(), trait_params, other_params) } @@ -55,7 +53,7 @@ pub trait Split: RustIrDatabase { let (associated_ty_data, trait_params, _) = self.split_projection(&projection); TraitRef { trait_id: associated_ty_data.trait_id, - substitution: Substitution::from(interner, trait_params), + substitution: Substitution::from_iter(interner, trait_params), } } @@ -137,14 +135,14 @@ pub trait Split: RustIrDatabase { self.split_associated_ty_value_parameters(¶meters, associated_ty_value); let trait_ref = { let opaque_ty_ref = impl_datum.binders.map_ref(|b| &b.trait_ref); - debug!("opaque_ty_ref: {:?}", opaque_ty_ref); + debug!(?opaque_ty_ref); opaque_ty_ref.substitute(interner, impl_parameters) }; // Create the parameters for the projection -- in our example // above, this would be `['!a, Box]`, corresponding to // ` as Foo>::Item<'!a>` - let projection_substitution = Substitution::from( + let projection_substitution = Substitution::from_iter( interner, atv_parameters .iter() @@ -157,12 +155,45 @@ pub trait Split: RustIrDatabase { substitution: projection_substitution, }; - debug!("impl_parameters: {:?}", impl_parameters); - debug!("trait_ref: {:?}", trait_ref); - debug!("projection: {:?}", projection); + debug!(?impl_parameters, ?trait_ref, ?projection); (impl_parameters, projection) } + + /// Given the full set of parameters (or binders) for an + /// associated type datum (the one appearing in a trait), splits + /// them into the parameters for the *trait* and those for the + /// *associated type*. + /// + /// # Example + /// + /// ```ignore (example) + /// trait Foo { + /// type Assoc<'a>; + /// } + /// ``` + /// + /// in this example, the full set of parameters would be `['x, + /// Y]`, where `'x` is the value for `'a` and `Y` is the value for + /// `T`. + /// + /// # Returns + /// + /// Returns the tuple of: + /// + /// * the parameters for the impl (`[Y]`, in our example) + /// * the parameters for the associated type value (`['a]`, in our example) + fn split_associated_ty_parameters<'p, P>( + &self, + parameters: &'p [P], + associated_ty_datum: &AssociatedTyDatum, + ) -> (&'p [P], &'p [P]) { + let trait_datum = &self.trait_datum(associated_ty_datum.trait_id); + let trait_num_params = trait_datum.binders.len(self.interner()); + let split_point = parameters.len() - trait_num_params; + let (other_params, trait_params) = parameters.split_at(split_point); + (trait_params, other_params) + } } impl + ?Sized, I: Interner> Split for DB {} diff --git a/vendor/chalk-solve-0.14.0/src/wf.rs b/vendor/chalk-solve-0.25.0/src/wf.rs similarity index 85% rename from vendor/chalk-solve-0.14.0/src/wf.rs rename to vendor/chalk-solve-0.25.0/src/wf.rs index d5892c76f6..03c60e66da 100644 --- a/vendor/chalk-solve-0.14.0/src/wf.rs +++ b/vendor/chalk-solve-0.25.0/src/wf.rs @@ -3,7 +3,7 @@ use std::{fmt, iter}; use crate::ext::*; use crate::goal_builder::GoalBuilder; use crate::rust_ir::*; -use crate::solve::SolverChoice; +use crate::solve::Solver; use crate::split::Split; use crate::RustIrDatabase; use chalk_ir::cast::*; @@ -38,9 +38,9 @@ impl fmt::Display for WfError { impl std::error::Error for WfError {} -pub struct WfSolver<'db, I: Interner> { - db: &'db dyn RustIrDatabase, - solver_choice: SolverChoice, +pub struct WfSolver<'a, I: Interner> { + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, } struct InputTypeCollector<'i, I: Interner> { @@ -84,6 +84,7 @@ impl<'i, I: Interner> Visitor<'i, I> for InputTypeCollector<'i, I> { WhereClause::Implemented(trait_ref) => { trait_ref.visit_with(self, outer_binder); } + WhereClause::TypeOutlives(TypeOutlives { ty, .. }) => ty.visit_with(self, outer_binder), WhereClause::LifetimeOutlives(..) => {} } } @@ -137,16 +138,18 @@ impl<'i, I: Interner> Visitor<'i, I> for InputTypeCollector<'i, I> { } } -impl<'db, I> WfSolver<'db, I> +impl<'a, I> WfSolver<'a, I> where I: Interner, { /// Constructs a new `WfSolver`. - pub fn new(db: &'db dyn RustIrDatabase, solver_choice: SolverChoice) -> Self { - Self { db, solver_choice } + pub fn new( + db: &'a dyn RustIrDatabase, + solver_builder: &'a dyn Fn() -> Box>, + ) -> Self { + Self { db, solver_builder } } - /// TODO: Currently only handles structs, may need more work for enums & unions pub fn verify_adt_decl(&self, adt_id: AdtId) -> Result<(), WfError> { let interner = self.db.interner(); @@ -157,46 +160,67 @@ where // data: Vec // } // ``` - let struct_datum = self.db.adt_datum(adt_id); + let adt_datum = self.db.adt_datum(adt_id); + let is_enum = adt_datum.kind == AdtKind::Enum; let mut gb = GoalBuilder::new(self.db); - let struct_data = struct_datum + let adt_data = adt_datum .binders - .map_ref(|b| (&b.fields, &b.where_clauses)); + .map_ref(|b| (&b.variants, &b.where_clauses)); // We make a goal like... // // forall { ... } - let wg_goal = gb.forall(&struct_data, (), |gb, _, (fields, where_clauses), ()| { - let interner = gb.interner(); + let wg_goal = gb.forall( + &adt_data, + is_enum, + |gb, _, (variants, where_clauses), is_enum| { + let interner = gb.interner(); - // struct is well-formed in terms of Sized - let sized_constraint_goal = WfWellKnownGoals::struct_sized_constraint(gb.db(), fields); + // (FromEnv(T: Eq) => ...) + gb.implies( + where_clauses + .iter() + .cloned() + .map(|wc| wc.into_from_env_goal(interner)), + |gb| { + let sub_goals: Vec<_> = variants + .iter() + .flat_map(|variant| { + let fields = &variant.fields; - // (FromEnv(T: Eq) => ...) - gb.implies( - where_clauses - .iter() - .cloned() - .map(|wc| wc.into_from_env_goal(interner)), - |gb| { - // WellFormed(Vec), for each field type `Vec` or type that appears in the where clauses - let types = - InputTypeCollector::types_in(gb.interner(), (&fields, &where_clauses)); + // When checking if Enum is well-formed, we require that all fields of + // each variant are sized. For `structs`, we relax this requirement to + // all but the last field. + let sized_constraint_goal = + WfWellKnownGoals::struct_sized_constraint( + gb.db(), + fields, + is_enum, + ); - gb.all( - types - .into_iter() - .map(|ty| ty.well_formed().cast(interner)) - .chain(sized_constraint_goal.into_iter()), - ) - }, - ) - }); + // WellFormed(Vec), for each field type `Vec` or type that appears in the where clauses + let types = InputTypeCollector::types_in( + gb.interner(), + (&fields, &where_clauses), + ); + + types + .into_iter() + .map(|ty| ty.well_formed().cast(interner)) + .chain(sized_constraint_goal.into_iter()) + }) + .collect(); + + gb.all(sub_goals) + }, + ) + }, + ); let wg_goal = wg_goal.into_closed_goal(interner); - - let is_legal = match self.solver_choice.into_solver().solve(self.db, &wg_goal) { + let mut fresh_solver = (self.solver_builder)(); + let is_legal = match fresh_solver.solve(self.db, &wg_goal) { Some(sol) => sol.is_unique(), None => false, }; @@ -226,11 +250,8 @@ where debug!("WF trait goal: {:?}", impl_goal); - let is_legal = match self - .solver_choice - .into_solver() - .solve(self.db, &impl_goal.into_closed_goal(interner)) - { + let mut fresh_solver = (self.solver_builder)(); + let is_legal = match fresh_solver.solve(self.db, &impl_goal.into_closed_goal(interner)) { Some(sol) => sol.is_unique(), None => false, }; @@ -280,7 +301,7 @@ fn impl_header_wf_goal( // Things to prove well-formed: input types of the where-clauses, projection types // appearing in the header, associated type values, and of course the trait ref. - debug!("verify_trait_impl: input_types={:?}", types); + debug!(input_types=?types); let goals = types .into_iter() .map(|ty| ty.well_formed().cast(interner)) @@ -386,7 +407,7 @@ fn compute_assoc_ty_goal( let (impl_parameters, projection) = db .impl_parameters_and_projection_from_associated_ty_value( - &assoc_ty_substitution.parameters(interner), + &assoc_ty_substitution.as_slice(interner), assoc_ty, ); @@ -499,7 +520,7 @@ impl WfWellKnownGoals { | WellKnownTrait::FnOnce | WellKnownTrait::FnMut | WellKnownTrait::Fn - | WellKnownTrait::Unsize => Some(GoalData::CannotProve(()).intern(interner)), + | WellKnownTrait::Unsize => Some(GoalData::CannotProve.intern(interner)), } } @@ -509,8 +530,11 @@ impl WfWellKnownGoals { pub fn struct_sized_constraint( db: &dyn RustIrDatabase, fields: &[Ty], + size_all: bool, ) -> Option> { - if fields.len() <= 1 { + let excluded = if size_all { 0 } else { 1 }; + + if fields.len() <= excluded { return None; } @@ -520,7 +544,7 @@ impl WfWellKnownGoals { Some(Goal::all( interner, - fields[..fields.len() - 1].iter().map(|ty| { + fields[..fields.len() - excluded].iter().map(|ty| { TraitRef { trait_id: sized_trait, substitution: Substitution::from1(interner, ty.clone()), @@ -533,7 +557,7 @@ impl WfWellKnownGoals { /// Computes a goal to prove constraints on a Copy implementation. /// Copy impl is considered well-formed for /// a) certain builtin types (scalar values, shared ref, etc..) - /// b) structs which + /// b) adts which /// 1) have all Copy fields /// 2) don't have a Drop impl fn copy_impl_constraint( @@ -554,10 +578,10 @@ impl WfWellKnownGoals { | TypeName::Ref(Mutability::Not) | TypeName::Never => return None, TypeName::Adt(adt_id) => (*adt_id, substitution), - _ => return Some(GoalData::CannotProve(()).intern(interner)), + _ => return Some(GoalData::CannotProve.intern(interner)), }, - _ => return Some(GoalData::CannotProve(()).intern(interner)), + _ => return Some(GoalData::CannotProve.intern(interner)), }; // not { Implemented(ImplSelfTy: Drop) } @@ -576,16 +600,18 @@ impl WfWellKnownGoals { let goals = adt_datum .binders - .map_ref(|b| &b.fields) + .map_ref(|b| &b.variants) .substitute(interner, substitution) .into_iter() - .map(|f| { - // Implemented(FieldTy: Copy) - TraitRef { - trait_id: trait_ref.trait_id, - substitution: Substitution::from1(interner, f), - } - .cast(interner) + .flat_map(|v| { + v.fields.into_iter().map(|f| { + // Implemented(FieldTy: Copy) + TraitRef { + trait_id: trait_ref.trait_id, + substitution: Substitution::from1(interner, f), + } + .cast(interner) + }) }) .chain(neg_drop_goal.into_iter()); @@ -635,7 +661,7 @@ impl WfWellKnownGoals { let adt_id = match impl_datum.self_type_adt_id(interner) { Some(id) => id, // Drop can only be implemented on a nominal type - None => return Some(GoalData::CannotProve(()).intern(interner)), + None => return Some(GoalData::CannotProve.intern(interner)), }; let mut gb = GoalBuilder::new(db); diff --git a/vendor/chalk-solve/.cargo-checksum.json b/vendor/chalk-solve/.cargo-checksum.json index f2e511090b..7b027f6d9e 100644 --- a/vendor/chalk-solve/.cargo-checksum.json +++ b/vendor/chalk-solve/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"cd30176dbc4a3acb159f54698bf07d567cc0d6edc373ff74b79b14b014d456aa","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"b4e8d03cf1137b3512b3dee245d05471396069131e2391ca667d3b192c942425","src/clauses/builder.rs":"ea0e37237addb834d3b274d316fae270dcbd418fc89d3c6cebf09e31fe346634","src/clauses/builtin_traits.rs":"0d8280fa4b261154a101698d2dbb63e5ff14c314fd7801732055c2f9d1ab66d0","src/clauses/builtin_traits/clone.rs":"963a3a192aa8283733d3bc2c0a5e7cf0debcf47986df85a25eef3e3c647de257","src/clauses/builtin_traits/copy.rs":"e5e2e9d8355fb2aaf36ab6d9ab89cf28d6a0984eb621773cb8a4d82a6302e25c","src/clauses/builtin_traits/fn_family.rs":"b81715f2521a1ee9aafd429931c2a250675898f0ee121c374298cb4af20aff58","src/clauses/builtin_traits/sized.rs":"7147c0bdc117fb7e768430ad963ce5c627bfe3641c04e3269f8a08a215c93dab","src/clauses/builtin_traits/unsize.rs":"9ac311cc905d068f5626204cdacadfe8b3e9c126fb821c8cbd054f7fd21165d2","src/clauses/dyn_ty.rs":"7c32ccd5a3bc7479b0e34ca2d3da254edcc7f73e38ace9f1860c5f64bb8def8a","src/clauses/env_elaborator.rs":"bd598d47075b7c5366c9db55d99b1426c7ea646bd2508c7674bcc52d918bdf76","src/clauses/generalize.rs":"c44f8e559a12f67ad55cff2dd3ffb39d9333cf39a7c8b78c6a8fe87e764c2f98","src/clauses/program_clauses.rs":"4ff101e17087299b3e431796dbb2fe8950b2bb3f2f4b2e7b4464bd3698656d41","src/coherence.rs":"665658b1dda7d5a37e9183a6ff176048c5b1001d23766b3b97288cdf8f3a94cc","src/coherence/orphan.rs":"621a839058309f1977e9eea972afa1622a372e06889d8d20aff64788cfba1829","src/coherence/solve.rs":"34746fd1a3e5984b8b3163bf89a906f5e2f99f17f57b1364ec688c3754d5272e","src/coinductive_goal.rs":"7a2179fb2d61435cf55c5c87301db6c15edb3cb46750bea381451649b2f1051d","src/display.rs":"c5c0a796b6037dea1cf18dcb063f0ccd3bd82012b480231f4e15d2186bb9a9f8","src/display/bounds.rs":"47b402d34c9a0cb7d4f4f35b40d86f983b6a335c9dfae95645eaa472404b6098","src/display/identifiers.rs":"22937fc099812dd9282c20c77ad3797cfa13a8838a0c68638bc4fc32178afbc8","src/display/items.rs":"0e24b30a35c079b8661c2fb5f957b0fc5932b5aef995495fa0c96b3a045f3650","src/display/render_trait.rs":"ccdcbe8e5a1771630dd61eb24b8e384fc30147c285bd40865f9ccc87ab4931b7","src/display/state.rs":"598f115023570bb6659a043d2410aef538364473031e53018bd78c247658d51b","src/display/stub.rs":"28e1ee74aefd8e491956f30e7c703778b68b62288e4763bb429313c5cbe5738e","src/display/ty.rs":"6673ac4c5e767b2afb35d133ff607cfba7f9bc9514ed6888b678ded09891d50c","src/display/utils.rs":"929d68b566265674e31a3fce6ffa0123fd6fc7b7c7323baf62aefd56ce67e085","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"1acef3990ec74d515200c2f42045028496f1799352d945481505ca00698d9838","src/infer.rs":"b5a533153d2a3ae342892b250d0eac0dcd87a26a38626a3753f326d3ce93966e","src/infer/canonicalize.rs":"85de8d18c62b151587a8df45af65b105faa20a14c033ca38d5b20965614ac515","src/infer/instantiate.rs":"0b43c5b86afae964298cc33b11d89b81feb8094074aa71ebcbbfa218c6a11a86","src/infer/invert.rs":"18ff374ff9ac9735ecedd66b3afa8dfa3531867d2b578eb011fdd97d56e150c1","src/infer/test.rs":"b3e69f1110aca3e6d261e01d2da7b7159b08e3e6345375f55bedaf3ae4c995aa","src/infer/ucanonicalize.rs":"f53f9b113921e122646d90075c0c518c48b3e6483b2bce72e3edc22083fcf957","src/infer/unify.rs":"fb17f98014d56618d5ea3ff0b491387c986266a1b80fe3bf906135f1b859a6a3","src/infer/var.rs":"35f88c269fbe1c7da572d9b21a64a1bed80036c563d91f7c71a639c51cac9801","src/lib.rs":"35517aa1e7b3ddaad9d52babedb497f5d068c48ce44ee768d2db171a7f3ed08e","src/logging.rs":"a3e3fa6bb03f29db9f87aedfa6051d4ad649c2aa2be292d03260d64c9bb8c5e2","src/logging_db.rs":"6d153fcf823a19680ab015286ad3d6e2ab47e1f6b39262f77271e664f8acef27","src/logging_db/id_collector.rs":"1f793e32ddb4b4562f139a63e9888a3320291209e91370ec7475b37a6dd396e2","src/recursive/lib.rs":"24f1dd3310eae203607835f063de7b8ed0fc75dee934428ad08abedb6c3e8704","src/rust_ir.rs":"f122a9c96aaa17f02739fb7443b3ffc38fcdd2c1b2a08b39cf3184011d43a403","src/solve.rs":"aa4d20a73dce06a0a5bb0459f4b2bdd80fd842d7a193f65ca48878ed915c6dd3","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"f77bacc0545b4f6af841fd4707185bb79bac768eabb44a9bdc9514b9f19800d0","src/split.rs":"f01ead861bc2abf79b08a67c7d620e8794f73db833ec516b5115602aa9d07d1c","src/wf.rs":"546fa2af849cd8afa480896c6e52816e96e2705b3d10628388eedfded1a6ddd0"},"package":"802de4eff72e5a5d2828e6c07224c74d66949dc6308aff025d0ae2871a11b4eb"} \ No newline at end of file +{"files":{"Cargo.toml":"57a5e65f384e3d148e718d77af88bab9e1d3a9f4f3b86cef7df6c43cf6234ea9","README.md":"2de2da988dbbaa8feb78b0a771b7bee942f34705ab057c824b1183300c535c74","src/clauses.rs":"b621b0b8f9f7411519fa9c8107af3d27c59d4042015259e6190d71259d6589f0","src/clauses/builder.rs":"ea0e37237addb834d3b274d316fae270dcbd418fc89d3c6cebf09e31fe346634","src/clauses/builtin_traits.rs":"0b401afe5f1a90d08d7decf4d1a5ae63caa279c2a5c91af2c8c6446cfb137ade","src/clauses/builtin_traits/clone.rs":"963a3a192aa8283733d3bc2c0a5e7cf0debcf47986df85a25eef3e3c647de257","src/clauses/builtin_traits/copy.rs":"edeb7565820075cb03ca452b41e6bce61ed6cd0f290ed92953f863435ce19afb","src/clauses/builtin_traits/fn_family.rs":"b96a30c3245228c20a1ceca237b3d1b3fb18a6eee0338876a6e488b06d186f19","src/clauses/builtin_traits/sized.rs":"837c85f520aa51b712b07c14f5f5d31929e76e347de54d9d2b8d27f7186cc92b","src/clauses/builtin_traits/unsize.rs":"9ac311cc905d068f5626204cdacadfe8b3e9c126fb821c8cbd054f7fd21165d2","src/clauses/dyn_ty.rs":"7c32ccd5a3bc7479b0e34ca2d3da254edcc7f73e38ace9f1860c5f64bb8def8a","src/clauses/env_elaborator.rs":"bd598d47075b7c5366c9db55d99b1426c7ea646bd2508c7674bcc52d918bdf76","src/clauses/generalize.rs":"c44f8e559a12f67ad55cff2dd3ffb39d9333cf39a7c8b78c6a8fe87e764c2f98","src/clauses/program_clauses.rs":"4ff101e17087299b3e431796dbb2fe8950b2bb3f2f4b2e7b4464bd3698656d41","src/coherence.rs":"665658b1dda7d5a37e9183a6ff176048c5b1001d23766b3b97288cdf8f3a94cc","src/coherence/orphan.rs":"621a839058309f1977e9eea972afa1622a372e06889d8d20aff64788cfba1829","src/coherence/solve.rs":"76c8ab111b8946aeb014563e13bf6f30a3bdf15c1fda63276f1711becbcf187b","src/coinductive_goal.rs":"7a2179fb2d61435cf55c5c87301db6c15edb3cb46750bea381451649b2f1051d","src/display.rs":"c5c0a796b6037dea1cf18dcb063f0ccd3bd82012b480231f4e15d2186bb9a9f8","src/display/bounds.rs":"47b402d34c9a0cb7d4f4f35b40d86f983b6a335c9dfae95645eaa472404b6098","src/display/identifiers.rs":"22937fc099812dd9282c20c77ad3797cfa13a8838a0c68638bc4fc32178afbc8","src/display/items.rs":"8aeb2923137d3bc1efe2cee0b93f2a97fa112d43438fa261963f8760f8ca4cfc","src/display/render_trait.rs":"ccdcbe8e5a1771630dd61eb24b8e384fc30147c285bd40865f9ccc87ab4931b7","src/display/state.rs":"598f115023570bb6659a043d2410aef538364473031e53018bd78c247658d51b","src/display/stub.rs":"d95da21650ace65b11f4ceb4583364d3114a39657ba37c97e5b93c4ed5a2913b","src/display/ty.rs":"26e23e3876d91554b6672f8b779b0342e2b221ba195c6a65d2a87f2aa061f504","src/display/utils.rs":"929d68b566265674e31a3fce6ffa0123fd6fc7b7c7323baf62aefd56ce67e085","src/ext.rs":"b71de835698b02434ffb67000d33bd82be53c3dadd41aee0056f0e4b31e102cd","src/goal_builder.rs":"1acef3990ec74d515200c2f42045028496f1799352d945481505ca00698d9838","src/infer.rs":"b5a533153d2a3ae342892b250d0eac0dcd87a26a38626a3753f326d3ce93966e","src/infer/canonicalize.rs":"85de8d18c62b151587a8df45af65b105faa20a14c033ca38d5b20965614ac515","src/infer/instantiate.rs":"0b43c5b86afae964298cc33b11d89b81feb8094074aa71ebcbbfa218c6a11a86","src/infer/invert.rs":"18ff374ff9ac9735ecedd66b3afa8dfa3531867d2b578eb011fdd97d56e150c1","src/infer/test.rs":"b3e69f1110aca3e6d261e01d2da7b7159b08e3e6345375f55bedaf3ae4c995aa","src/infer/ucanonicalize.rs":"f53f9b113921e122646d90075c0c518c48b3e6483b2bce72e3edc22083fcf957","src/infer/unify.rs":"fa64bc2a04978c0598d1fae74a77ed11325904e69b0785cb38d7acce47d7a794","src/infer/var.rs":"35f88c269fbe1c7da572d9b21a64a1bed80036c563d91f7c71a639c51cac9801","src/lib.rs":"9c70de2446236e71269cfca5b0cbf26e28765ceede71e460a56b2f891865c039","src/logging.rs":"a3e3fa6bb03f29db9f87aedfa6051d4ad649c2aa2be292d03260d64c9bb8c5e2","src/logging_db.rs":"a5c4bc36b4d242871ff6cd9b1550eadd627e29af7364d50f45892301d8d4f4cb","src/logging_db/id_collector.rs":"1f793e32ddb4b4562f139a63e9888a3320291209e91370ec7475b37a6dd396e2","src/recursive/lib.rs":"24f1dd3310eae203607835f063de7b8ed0fc75dee934428ad08abedb6c3e8704","src/rust_ir.rs":"5a1d30410997f6514af21e0311c4ad0d55e15f073aa75b25811ae9ebe6cd29b2","src/solve.rs":"487802e88356bae4f2b334dc9e4347f2f7574b0f888ea3524554998d9c956e96","src/solve/test/bench.rs":"8da8bb948bdf598ed7f225fd695b12c9e8626cd7a14d4b7d8650de0fae73d655","src/solve/truncate.rs":"f77bacc0545b4f6af841fd4707185bb79bac768eabb44a9bdc9514b9f19800d0","src/split.rs":"f01ead861bc2abf79b08a67c7d620e8794f73db833ec516b5115602aa9d07d1c","src/wf.rs":"77f688b8812e04bf90484fd9f7bd318611a0d7f4eb0c6016c78946c9e3b0b69e"},"package":"828c1f80d4eaf681027cce02050c54a3c97370f81988d31bf2a56df54048746c"} \ No newline at end of file diff --git a/vendor/chalk-solve/Cargo.toml b/vendor/chalk-solve/Cargo.toml index de0d4f5146..ef19ea8b01 100644 --- a/vendor/chalk-solve/Cargo.toml +++ b/vendor/chalk-solve/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "chalk-solve" -version = "0.23.0" +version = "0.29.0" authors = ["Rust Compiler Team", "Chalk developers"] description = "Combines the chalk-engine with chalk-ir" readme = "README.md" @@ -21,10 +21,10 @@ keywords = ["compiler", "traits", "prolog"] license = "Apache-2.0/MIT" repository = "https://github.com/rust-lang/chalk" [dependencies.chalk-derive] -version = "=0.23.0" +version = "=0.29.0" [dependencies.chalk-ir] -version = "=0.23.0" +version = "=0.29.0" [dependencies.ena] version = "0.14.0" diff --git a/vendor/chalk-solve/src/clauses.rs b/vendor/chalk-solve/src/clauses.rs index db54807664..ebea5efaf1 100644 --- a/vendor/chalk-solve/src/clauses.rs +++ b/vendor/chalk-solve/src/clauses.rs @@ -18,6 +18,49 @@ mod env_elaborator; mod generalize; pub mod program_clauses; +// yields the types "contained" in `app_ty` +fn constituent_types( + db: &dyn RustIrDatabase, + app_ty: &ApplicationTy, +) -> Vec> { + let interner = db.interner(); + + match app_ty.name { + // For non-phantom_data adts we collect its variants/fields + TypeName::Adt(adt_id) if !db.adt_datum(adt_id).flags.phantom_data => { + let adt_datum = &db.adt_datum(adt_id); + let adt_datum_bound = adt_datum.binders.substitute(interner, &app_ty.substitution); + adt_datum_bound + .variants + .into_iter() + .flat_map(|variant| variant.fields.into_iter()) + .collect() + } + // And for `PhantomData`, we pass `T`. + TypeName::Adt(_) + | TypeName::Array + | TypeName::Tuple(_) + | TypeName::Slice + | TypeName::Raw(_) + | TypeName::Ref(_) + | TypeName::Scalar(_) + | TypeName::Str + | TypeName::Never + | TypeName::FnDef(_) => app_ty + .substitution + .iter(interner) + .filter_map(|x| x.ty(interner)) + .cloned() + .collect(), + + TypeName::Closure(_) => panic!("this function should not be called for closures"), + TypeName::Foreign(_) => panic!("constituent_types of foreign types are unknown!"), + TypeName::Error => Vec::new(), + TypeName::OpaqueType(_) => unimplemented!(), + TypeName::AssociatedType(_) => unimplemented!(), + } +} + /// FIXME(#505) update comments for ADTs /// For auto-traits, we generate a default rule for every struct, /// unless there is a manual impl for that struct given explicitly. @@ -53,9 +96,8 @@ pub mod program_clauses; pub fn push_auto_trait_impls( builder: &mut ClauseBuilder<'_, I>, auto_trait_id: TraitId, - adt_id: AdtId, + app_ty: &ApplicationTy, ) { - let adt_datum = &builder.db.adt_datum(adt_id); let interner = builder.interner(); // Must be an auto trait. @@ -67,44 +109,48 @@ pub fn push_auto_trait_impls( 1 ); + // we assume that the builder has no binders so far. + assert!(builder.placeholders_in_scope().is_empty()); + // If there is a `impl AutoTrait for Foo<..>` or `impl !AutoTrait // for Foo<..>`, where `Foo` is the adt we're looking at, then // we don't generate our own rules. - if builder.db.impl_provided_for(auto_trait_id, adt_id) { + if builder.db.impl_provided_for(auto_trait_id, app_ty) { debug!("impl provided"); return; } - let binders = adt_datum.binders.map_ref(|b| &b.variants); - builder.push_binders(&binders, |builder, variants| { - let self_ty: Ty<_> = ApplicationTy { - name: adt_id.cast(interner), - substitution: builder.substitution_in_scope(), + let mk_ref = |ty: Ty| TraitRef { + trait_id: auto_trait_id, + substitution: Substitution::from1(interner, ty.cast(interner)), + }; + + let consequence = mk_ref(app_ty.clone().intern(interner)); + + match app_ty.name { + // auto traits are not implemented for foreign types + TypeName::Foreign(_) => return, + + // closures require binders, while the other types do not + TypeName::Closure(closure_id) => { + let binders = builder + .db + .closure_upvars(closure_id, &Substitution::empty(interner)); + builder.push_binders(&binders, |builder, upvar_ty| { + let conditions = iter::once(mk_ref(upvar_ty)); + builder.push_clause(consequence, conditions); + }); } - .intern(interner); - // trait_ref = `MyStruct<...>: MyAutoTrait` - let auto_trait_ref = TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, self_ty), - }; + // app_ty implements AutoTrait if all constituents of app_ty implement AutoTrait + _ => { + let conditions = constituent_types(builder.db, app_ty) + .into_iter() + .map(mk_ref); - // forall { // generic parameters from struct - // MyStruct<...>: MyAutoTrait :- - // Field0: MyAutoTrait, - // ... - // FieldN: MyAutoTrait - // } - builder.push_clause( - auto_trait_ref, - variants.iter().flat_map(|variant| { - variant.fields.iter().map(|field_ty| TraitRef { - trait_id: auto_trait_id, - substitution: Substitution::from1(interner, field_ty.clone()), - }) - }), - ); - }); + builder.push_clause(consequence, conditions); + } + } } /// Leak auto traits for opaque types, just like `push_auto_trait_impls` does for structs. @@ -253,13 +299,20 @@ fn program_clauses_that_could_match( // the automatic impls for `Foo`. let trait_datum = db.trait_datum(trait_id); if trait_datum.is_auto_trait() { - match trait_ref.self_type_parameter(interner).data(interner) { - TyData::Apply(apply) => match &apply.name { - TypeName::Adt(adt_id) => { - push_auto_trait_impls(builder, trait_id, *adt_id); - } - _ => {} - }, + let ty = trait_ref.self_type_parameter(interner); + match ty.data(interner) { + TyData::Apply(apply) => { + push_auto_trait_impls(builder, trait_id, apply); + } + // function-types implement auto traits unconditionally + TyData::Function(_) => { + let auto_trait_ref = TraitRef { + trait_id, + substitution: Substitution::from1(interner, ty.cast(interner)), + }; + + builder.push_fact(auto_trait_ref); + } TyData::InferenceVar(_, _) | TyData::BoundVar(_) => { return Err(Floundered); } @@ -635,7 +688,8 @@ fn match_type_name( | TypeName::Ref(_) | TypeName::Array | TypeName::Never - | TypeName::Closure(_) => { + | TypeName::Closure(_) + | TypeName::Foreign(_) => { builder.push_fact(WellFormed::Ty(application.clone().intern(interner))) } } diff --git a/vendor/chalk-solve/src/clauses/builtin_traits.rs b/vendor/chalk-solve/src/clauses/builtin_traits.rs index d21a4b602b..6a4eed3759 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits.rs @@ -41,8 +41,8 @@ pub fn add_builtin_program_clauses( WellKnownTrait::Unsize => { unsize::add_unsize_program_clauses(db, builder, &trait_ref, ty) } - // Drop impls are provided explicitly - WellKnownTrait::Drop => (), + // There are no builtin impls provided for the following traits: + WellKnownTrait::Unpin | WellKnownTrait::Drop | WellKnownTrait::CoerceUnsized => (), } Ok(()) }) diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs b/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs index 5fd9c1a17a..d8528da8f2 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits/copy.rs @@ -75,6 +75,7 @@ pub fn add_copy_program_clauses( | TypeName::AssociatedType(_) | TypeName::Slice | TypeName::OpaqueType(_) + | TypeName::Foreign(_) | TypeName::Error => {} }, diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs b/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs index 2012367b68..9178f80a6a 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits/fn_family.rs @@ -99,7 +99,7 @@ pub fn add_fn_trait_program_clauses( TyData::Apply(apply) => match apply.name { TypeName::FnDef(fn_def_id) => { let fn_def_datum = builder.db.fn_def_datum(fn_def_id); - if fn_def_datum.safety == Safety::Safe && !fn_def_datum.variadic { + if fn_def_datum.sig.safety == Safety::Safe && !fn_def_datum.sig.variadic { let bound = fn_def_datum .binders .substitute(builder.interner(), &apply.substitution); @@ -140,7 +140,7 @@ pub fn add_fn_trait_program_clauses( } _ => Ok(()), }, - TyData::Function(fn_val) if fn_val.safety == Safety::Safe && !fn_val.variadic => { + TyData::Function(fn_val) if fn_val.sig.safety == Safety::Safe && !fn_val.sig.variadic => { let (binders, orig_sub) = fn_val.into_binders_and_value(interner); let bound_ref = Binders::new(VariableKinds::from_iter(interner, binders), orig_sub); builder.push_binders(&bound_ref, |builder, orig_sub| { diff --git a/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs b/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs index 786c705a29..b256a4bf82 100644 --- a/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs +++ b/vendor/chalk-solve/src/clauses/builtin_traits/sized.rs @@ -93,6 +93,7 @@ pub fn add_sized_program_clauses( | TypeName::Slice | TypeName::OpaqueType(_) | TypeName::Str + | TypeName::Foreign(_) | TypeName::Error => {} }, diff --git a/vendor/chalk-solve/src/coherence/solve.rs b/vendor/chalk-solve/src/coherence/solve.rs index 98081ce9b8..25fb25344d 100644 --- a/vendor/chalk-solve/src/coherence/solve.rs +++ b/vendor/chalk-solve/src/coherence/solve.rs @@ -251,10 +251,7 @@ impl CoherenceSolver<'_, I> { let canonical_goal = &goal.into_closed_goal(interner); let mut fresh_solver = (self.solver_builder)(); - let result = match fresh_solver.solve(self.db, canonical_goal) { - Some(sol) => sol.is_unique(), - None => false, - }; + let result = fresh_solver.has_unique_solution(self.db, canonical_goal); debug!("specializes: result = {:?}", result); diff --git a/vendor/chalk-solve/src/display/items.rs b/vendor/chalk-solve/src/display/items.rs index 13da1a01b2..62a2154d65 100644 --- a/vendor/chalk-solve/src/display/items.rs +++ b/vendor/chalk-solve/src/display/items.rs @@ -193,6 +193,8 @@ impl RenderAsRust for TraitDatum { WellKnownTrait::FnMut => "fn_mut", WellKnownTrait::Fn => "fn", WellKnownTrait::Unsize => "unsize", + WellKnownTrait::Unpin => "unpin", + WellKnownTrait::CoerceUnsized => "coerce_unsized", }; writeln!(f, "#[lang({})]", name)?; } diff --git a/vendor/chalk-solve/src/display/stub.rs b/vendor/chalk-solve/src/display/stub.rs index 2c433578c2..2ad5791d49 100644 --- a/vendor/chalk-solve/src/display/stub.rs +++ b/vendor/chalk-solve/src/display/stub.rs @@ -156,7 +156,7 @@ impl> RustIrDatabase for StubWrapper<'_, D fn impl_provided_for( &self, _auto_trait_id: chalk_ir::TraitId, - _adt_id: chalk_ir::AdtId, + _app_ty: &chalk_ir::ApplicationTy, ) -> bool { // We panic here because the returned ids may not be collected, // resulting in unresolvable names. diff --git a/vendor/chalk-solve/src/display/ty.rs b/vendor/chalk-solve/src/display/ty.rs index 6792703096..8454cd15b6 100644 --- a/vendor/chalk-solve/src/display/ty.rs +++ b/vendor/chalk-solve/src/display/ty.rs @@ -217,6 +217,7 @@ impl RenderAsRust for ApplicationTy { // FIXME: write out valid types for these variants TypeName::FnDef(_) => write!(f, "")?, TypeName::Closure(..) => write!(f, "")?, + TypeName::Foreign(_) => write!(f, "")?, TypeName::Array => write!( f, diff --git a/vendor/chalk-solve/src/infer/unify.rs b/vendor/chalk-solve/src/infer/unify.rs index 57b76d5b55..46648c5ac8 100644 --- a/vendor/chalk-solve/src/infer/unify.rs +++ b/vendor/chalk-solve/src/infer/unify.rs @@ -129,7 +129,7 @@ impl<'t, I: Interner> Unifier<'t, I> { // Unifying `forall { T }` with some other forall type `forall { U }` (&TyData::Function(ref fn1), &TyData::Function(ref fn2)) => { - if fn1.abi == fn2.abi && fn1.safety == fn2.safety && fn1.variadic == fn2.variadic { + if fn1.sig == fn2.sig { self.unify_binders(fn1, fn2) } else { Err(NoSolution) @@ -455,11 +455,23 @@ impl<'t, I: Interner> Unifier<'t, I> { let interner = self.interner; let var = EnaVariable::from(var); + // Determine the universe index associated with this + // variable. This is basically a count of the number of + // `forall` binders that had been introduced at the point + // this variable was created -- though it may change over time + // as the variable is unified. + let universe_index = self.table.universe_of_unbound_var(var); + + let c1 = c.fold_with( + &mut OccursCheck::new(self, var, universe_index), + DebruijnIndex::INNERMOST, + )?; + + debug!("unify_var_const: var {:?} set to {:?}", var, c1); self.table .unify - .unify_var_value(var, InferenceValue::from_const(interner, c.clone())) + .unify_var_value(var, InferenceValue::from_const(interner, c1)) .unwrap(); - debug!("unify_var_const: var {:?} set to {:?}", var, c); Ok(()) } @@ -557,6 +569,20 @@ where } } + fn fold_free_placeholder_const( + &mut self, + ty: &Ty, + universe: PlaceholderIndex, + _outer_binder: DebruijnIndex, + ) -> Fallible> { + let interner = self.interner(); + if self.universe_index < universe.ui { + Err(NoSolution) + } else { + Ok(universe.to_const(interner, ty.clone())) // no need to shift, not relative to depth + } + } + #[instrument(level = "debug", skip(self))] fn fold_free_placeholder_lifetime( &mut self, @@ -633,6 +659,51 @@ where } } + fn fold_inference_const( + &mut self, + ty: &Ty, + var: InferenceVar, + _outer_binder: DebruijnIndex, + ) -> Fallible> { + let interner = self.interner(); + let var = EnaVariable::from(var); + match self.unifier.table.unify.probe_value(var) { + // If this variable already has a value, fold over that value instead. + InferenceValue::Bound(normalized_const) => { + let normalized_const = normalized_const.assert_const_ref(interner); + let normalized_const = + normalized_const.fold_with(self, DebruijnIndex::INNERMOST)?; + assert!(!normalized_const.needs_shift(interner)); + Ok(normalized_const) + } + + // Otherwise, check the universe of the variable, and also + // check for cycles with `self.var` (which this will soon + // become the value of). + InferenceValue::Unbound(ui) => { + if self.unifier.table.unify.unioned(var, self.var) { + return Err(NoSolution); + } + + if self.universe_index < ui { + // Scenario is like: + // + // forall exists ?C = Foo + // + // where A is in universe 0 and B is in universe 1. + // This is OK, if B is promoted to universe 0. + self.unifier + .table + .unify + .unify_var_value(var, InferenceValue::Unbound(self.universe_index)) + .unwrap(); + } + + Ok(var.to_const(interner, ty.clone())) + } + } + } + fn fold_inference_lifetime( &mut self, var: InferenceVar, diff --git a/vendor/chalk-solve/src/lib.rs b/vendor/chalk-solve/src/lib.rs index 0c6d300959..583595e11c 100644 --- a/vendor/chalk-solve/src/lib.rs +++ b/vendor/chalk-solve/src/lib.rs @@ -101,12 +101,11 @@ pub trait RustIrDatabase: Debug { fn local_impls_to_coherence_check(&self, trait_id: TraitId) -> Vec>; /// Returns true if there is an explicit impl of the auto trait - /// `auto_trait_id` for the ADT `adt_id`. This is part of + /// `auto_trait_id` for the type `app_ty`. This is part of /// the auto trait handling -- if there is no explicit impl given - /// by the user for the struct, then we provide default impls - /// based on the field types (otherwise, we rely on the impls the - /// user gave). - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool; + /// by the user for `app_ty`, then we provide default impls + /// (otherwise, we rely on the impls the user gave). + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool; /// Returns id of a trait lang item, if found fn well_known_trait_id(&self, well_known_trait: WellKnownTrait) -> Option>; diff --git a/vendor/chalk-solve/src/logging_db.rs b/vendor/chalk-solve/src/logging_db.rs index 52279110db..3681e8c280 100644 --- a/vendor/chalk-solve/src/logging_db.rs +++ b/vendor/chalk-solve/src/logging_db.rs @@ -166,10 +166,12 @@ where self.ws.db().local_impls_to_coherence_check(trait_id) } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool { self.record(auto_trait_id); - self.record(adt_id); - self.ws.db().impl_provided_for(auto_trait_id, adt_id) + if let TypeName::Adt(adt_id) = app_ty.name { + self.record(adt_id); + } + self.ws.db().impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id( @@ -379,8 +381,8 @@ where self.db.local_impls_to_coherence_check(trait_id) } - fn impl_provided_for(&self, auto_trait_id: TraitId, adt_id: AdtId) -> bool { - self.db.impl_provided_for(auto_trait_id, adt_id) + fn impl_provided_for(&self, auto_trait_id: TraitId, app_ty: &ApplicationTy) -> bool { + self.db.impl_provided_for(auto_trait_id, app_ty) } fn well_known_trait_id( diff --git a/vendor/chalk-solve/src/rust_ir.rs b/vendor/chalk-solve/src/rust_ir.rs index 74fdd85b4d..3dabc05f2f 100644 --- a/vendor/chalk-solve/src/rust_ir.rs +++ b/vendor/chalk-solve/src/rust_ir.rs @@ -9,8 +9,8 @@ use chalk_ir::interner::{Interner, TargetInterner}; use chalk_ir::{ visit::{Visit, VisitResult}, AdtId, AliasEq, AliasTy, AssocTypeId, Binders, DebruijnIndex, FnDefId, GenericArg, ImplId, - OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Safety, Substitution, ToGenericArg, TraitId, - TraitRef, Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, + OpaqueTyId, ProjectionTy, QuantifiedWhereClause, Substitution, ToGenericArg, TraitId, TraitRef, + Ty, TyData, TypeName, VariableKind, WhereClause, WithKind, }; use std::iter; @@ -144,9 +144,7 @@ pub struct AdtRepr { /// a specific function definition. pub struct FnDefDatum { pub id: FnDefId, - pub abi: I::FnAbi, - pub safety: Safety, - pub variadic: bool, + pub sig: chalk_ir::FnSig, pub binders: Binders>, } @@ -271,6 +269,8 @@ pub enum WellKnownTrait { FnMut, Fn, Unsize, + Unpin, + CoerceUnsized, } chalk_ir::const_visit!(WellKnownTrait); diff --git a/vendor/chalk-solve/src/solve.rs b/vendor/chalk-solve/src/solve.rs index dc74045acd..8d0315219d 100644 --- a/vendor/chalk-solve/src/solve.rs +++ b/vendor/chalk-solve/src/solve.rs @@ -203,4 +203,17 @@ where goal: &UCanonical>>, f: &mut dyn FnMut(SubstitutionResult>>, bool) -> bool, ) -> bool; + + /// A convenience method for when one doesn't need the actual solution, + /// only whether or not one exists. + fn has_unique_solution( + &mut self, + program: &dyn RustIrDatabase, + goal: &UCanonical>>, + ) -> bool { + match self.solve(program, goal) { + Some(sol) => sol.is_unique(), + None => false, + } + } } diff --git a/vendor/chalk-solve/src/wf.rs b/vendor/chalk-solve/src/wf.rs index 03c60e66da..be09a9050f 100644 --- a/vendor/chalk-solve/src/wf.rs +++ b/vendor/chalk-solve/src/wf.rs @@ -1,21 +1,21 @@ use std::{fmt, iter}; -use crate::ext::*; -use crate::goal_builder::GoalBuilder; -use crate::rust_ir::*; -use crate::solve::Solver; -use crate::split::Split; -use crate::RustIrDatabase; -use chalk_ir::cast::*; -use chalk_ir::fold::shift::Shift; -use chalk_ir::interner::Interner; -use chalk_ir::visit::{Visit, Visitor}; -use chalk_ir::*; +use crate::{ + ext::*, goal_builder::GoalBuilder, rust_ir::*, solve::Solver, split::Split, RustIrDatabase, +}; +use chalk_ir::{ + cast::*, + fold::shift::Shift, + interner::Interner, + visit::{Visit, Visitor}, + *, +}; use tracing::debug; #[derive(Debug)] pub enum WfError { IllFormedTypeDecl(chalk_ir::AdtId), + IllFormedOpaqueTypeDecl(chalk_ir::OpaqueTyId), IllFormedTraitImpl(chalk_ir::TraitId), } @@ -27,6 +27,11 @@ impl fmt::Display for WfError { "type declaration `{:?}` does not meet well-formedness requirements", id ), + WfError::IllFormedOpaqueTypeDecl(id) => write!( + f, + "opaque type declaration `{:?}` does not meet well-formedness requirements", + id + ), WfError::IllFormedTraitImpl(id) => write!( f, "trait impl for `{:?}` does not meet well-formedness requirements", @@ -193,7 +198,7 @@ where // each variant are sized. For `structs`, we relax this requirement to // all but the last field. let sized_constraint_goal = - WfWellKnownGoals::struct_sized_constraint( + WfWellKnownConstraints::struct_sized_constraint( gb.db(), fields, is_enum, @@ -220,10 +225,7 @@ where let wg_goal = wg_goal.into_closed_goal(interner); let mut fresh_solver = (self.solver_builder)(); - let is_legal = match fresh_solver.solve(self.db, &wg_goal) { - Some(sol) => sol.is_unique(), - None => false, - }; + let is_legal = fresh_solver.has_unique_solution(self.db, &wg_goal); if !is_legal { Err(WfError::IllFormedTypeDecl(adt_id)) @@ -248,13 +250,15 @@ where ), ); + if let Some(well_known) = self.db.trait_datum(trait_id).well_known { + self.verify_well_known_impl(impl_id, well_known)? + } + debug!("WF trait goal: {:?}", impl_goal); let mut fresh_solver = (self.solver_builder)(); - let is_legal = match fresh_solver.solve(self.db, &impl_goal.into_closed_goal(interner)) { - Some(sol) => sol.is_unique(), - None => false, - }; + let is_legal = + fresh_solver.has_unique_solution(self.db, &impl_goal.into_closed_goal(interner)); if is_legal { Ok(()) @@ -262,6 +266,99 @@ where Err(WfError::IllFormedTraitImpl(trait_id)) } } + + pub fn verify_opaque_ty_decl(&self, opaque_ty_id: OpaqueTyId) -> Result<(), WfError> { + // Given an opaque type like + // ```notrust + // opaque type Foo: Clone where T: Bar = Baz; + // ``` + let interner = self.db.interner(); + + let mut gb = GoalBuilder::new(self.db); + + let datum = self.db.opaque_ty_data(opaque_ty_id); + let bound = &datum.bound; + + // We make a goal like + // + // forall + let goal = gb.forall(&bound, opaque_ty_id, |gb, _, bound, opaque_ty_id| { + let interner = gb.interner(); + + let subst = Substitution::from1(interner, gb.db().hidden_opaque_type(opaque_ty_id)); + + let bounds = bound.bounds.substitute(interner, &subst); + let where_clauses = bound.where_clauses.substitute(interner, &subst); + + let clauses = where_clauses + .iter() + .cloned() + .map(|wc| wc.into_from_env_goal(interner)); + + // if (WellFormed(T: Bar)) + gb.implies(clauses, |gb| { + let interner = gb.interner(); + + // all(WellFormed(Baz: Clone)) + gb.all( + bounds + .iter() + .cloned() + .map(|b| b.into_well_formed_goal(interner)), + ) + }) + }); + + debug!("WF opaque type goal: {:#?}", goal); + + let mut new_solver = (self.solver_builder)(); + let is_legal = new_solver.has_unique_solution(self.db, &goal.into_closed_goal(interner)); + + if is_legal { + Ok(()) + } else { + Err(WfError::IllFormedOpaqueTypeDecl(opaque_ty_id)) + } + } + + /// Verify builtin rules for well-known traits + pub fn verify_well_known_impl( + &self, + impl_id: ImplId, + well_known: WellKnownTrait, + ) -> Result<(), WfError> { + let mut solver = (self.solver_builder)(); + let impl_datum = self.db.impl_datum(impl_id); + + let is_legal = match well_known { + WellKnownTrait::Copy => { + WfWellKnownConstraints::copy_impl_constraint(&mut *solver, self.db, &impl_datum) + } + WellKnownTrait::Drop => { + WfWellKnownConstraints::drop_impl_constraint(&mut *solver, self.db, &impl_datum) + } + WellKnownTrait::CoerceUnsized => { + WfWellKnownConstraints::coerce_unsized_impl_constraint( + &mut *solver, + self.db, + &impl_datum, + ) + } + WellKnownTrait::Clone | WellKnownTrait::Unpin => true, + // You can't add a manual implementation for the following traits: + WellKnownTrait::Fn + | WellKnownTrait::FnOnce + | WellKnownTrait::FnMut + | WellKnownTrait::Unsize + | WellKnownTrait::Sized => false, + }; + + if is_legal { + Ok(()) + } else { + Err(WfError::IllFormedTraitImpl(impl_datum.trait_id())) + } + } } fn impl_header_wf_goal( @@ -283,8 +380,6 @@ fn impl_header_wf_goal( let well_formed_goal = gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| { let interner = gb.interner(); - let trait_constraint_goal = WfWellKnownGoals::inside_impl(gb.db(), &trait_ref); - // if (WC && input types are well formed) { ... } gb.implies( impl_wf_environment(interner, &where_clauses, &trait_ref), @@ -305,20 +400,14 @@ fn impl_header_wf_goal( let goals = types .into_iter() .map(|ty| ty.well_formed().cast(interner)) - .chain(Some((*trait_ref).clone().well_formed().cast(interner))) - .chain(trait_constraint_goal.into_iter()); + .chain(Some((*trait_ref).clone().well_formed().cast(interner))); gb.all::<_, Goal>(goals) }, ) }); - Some( - gb.all( - iter::once(well_formed_goal) - .chain(WfWellKnownGoals::outside_impl(db, &impl_datum).into_iter()), - ), - ) + Some(well_formed_goal) } /// Creates the conditions that an impl (and its contents of an impl) @@ -482,48 +571,9 @@ fn compute_assoc_ty_goal( /// Defines methods to compute well-formedness goals for well-known /// traits (e.g. a goal for all fields of struct in a Copy impl to be Copy) -struct WfWellKnownGoals {} - -impl WfWellKnownGoals { - /// A convenience method to compute the goal assuming `trait_ref` - /// well-formedness requirements are in the environment. - pub fn inside_impl( - db: &dyn RustIrDatabase, - trait_ref: &TraitRef, - ) -> Option> { - match db.trait_datum(trait_ref.trait_id).well_known? { - WellKnownTrait::Copy => Self::copy_impl_constraint(db, trait_ref), - WellKnownTrait::Drop - | WellKnownTrait::Clone - | WellKnownTrait::Sized - | WellKnownTrait::FnOnce - | WellKnownTrait::FnMut - | WellKnownTrait::Fn - | WellKnownTrait::Unsize => None, - } - } - - /// Computes well-formedness goals without any assumptions about the environment. - /// Note that `outside_impl` does not call `inside_impl`, one needs to call both - /// in order to get the full set of goals to be proven. - pub fn outside_impl( - db: &dyn RustIrDatabase, - impl_datum: &ImplDatum, - ) -> Option> { - let interner = db.interner(); - - match db.trait_datum(impl_datum.trait_id()).well_known? { - WellKnownTrait::Drop => Self::drop_impl_constraint(db, impl_datum), - WellKnownTrait::Copy | WellKnownTrait::Clone => None, - // You can't add a manual implementation for following traits: - WellKnownTrait::Sized - | WellKnownTrait::FnOnce - | WellKnownTrait::FnMut - | WellKnownTrait::Fn - | WellKnownTrait::Unsize => Some(GoalData::CannotProve.intern(interner)), - } - } +struct WfWellKnownConstraints; +impl WfWellKnownConstraints { /// Computes a goal to prove Sized constraints on a struct definition. /// Struct is considered well-formed (in terms of Sized) when it either /// has no fields or all of it's fields except the last are proven to be Sized. @@ -554,71 +604,108 @@ impl WfWellKnownGoals { )) } - /// Computes a goal to prove constraints on a Copy implementation. + /// Verify constraints on a Copy implementation. /// Copy impl is considered well-formed for /// a) certain builtin types (scalar values, shared ref, etc..) /// b) adts which /// 1) have all Copy fields /// 2) don't have a Drop impl fn copy_impl_constraint( + solver: &mut dyn Solver, db: &dyn RustIrDatabase, - trait_ref: &TraitRef, - ) -> Option> { + impl_datum: &ImplDatum, + ) -> bool { let interner = db.interner(); - let ty = trait_ref.self_type_parameter(interner); - let ty_data = ty.data(interner); + let mut gb = GoalBuilder::new(db); + + let impl_fields = impl_datum + .binders + .map_ref(|v| (&v.trait_ref, &v.where_clauses)); // Implementations for scalars, pointer types and never type are provided by libcore. // User implementations on types other than ADTs are forbidden. - let (adt_id, substitution) = match ty_data { - TyData::Apply(ApplicationTy { name, substitution }) => match name { + match impl_datum + .binders + .skip_binders() + .trait_ref + .self_type_parameter(interner) + .data(interner) + { + TyData::Apply(ApplicationTy { name, .. }) => match name { TypeName::Scalar(_) | TypeName::Raw(_) | TypeName::Ref(Mutability::Not) - | TypeName::Never => return None, - TypeName::Adt(adt_id) => (*adt_id, substitution), - _ => return Some(GoalData::CannotProve.intern(interner)), + | TypeName::Never => return true, + TypeName::Adt(_) => (), + _ => return false, }, - _ => return Some(GoalData::CannotProve.intern(interner)), + _ => return false, }; - // not { Implemented(ImplSelfTy: Drop) } - let neg_drop_goal = db - .well_known_trait_id(WellKnownTrait::Drop) - .map(|drop_trait_id| { - TraitRef { - trait_id: drop_trait_id, - substitution: Substitution::from1(interner, ty.clone()), - } - .cast::>(interner) - .negate(interner) + // Well fomedness goal for ADTs + let well_formed_goal = + gb.forall(&impl_fields, (), |gb, _, (trait_ref, where_clauses), ()| { + let interner = gb.interner(); + + let ty = trait_ref.self_type_parameter(interner); + let ty_data = ty.data(interner); + + let (adt_id, substitution) = match ty_data { + TyData::Apply(ApplicationTy { name, substitution }) => match name { + TypeName::Adt(adt_id) => (*adt_id, substitution), + _ => unreachable!(), + }, + + _ => unreachable!(), + }; + + // if (WC) { ... } + gb.implies( + impl_wf_environment(interner, &where_clauses, &trait_ref), + |gb| -> Goal { + let db = gb.db(); + + // not { Implemented(ImplSelfTy: Drop) } + let neg_drop_goal = + db.well_known_trait_id(WellKnownTrait::Drop) + .map(|drop_trait_id| { + TraitRef { + trait_id: drop_trait_id, + substitution: Substitution::from1(interner, ty.clone()), + } + .cast::>(interner) + .negate(interner) + }); + + let adt_datum = db.adt_datum(adt_id); + + let goals = adt_datum + .binders + .map_ref(|b| &b.variants) + .substitute(interner, substitution) + .into_iter() + .flat_map(|v| { + v.fields.into_iter().map(|f| { + // Implemented(FieldTy: Copy) + TraitRef { + trait_id: trait_ref.trait_id, + substitution: Substitution::from1(interner, f), + } + .cast(interner) + }) + }) + .chain(neg_drop_goal.into_iter()); + gb.all(goals) + }, + ) }); - let adt_datum = db.adt_datum(adt_id); - - let goals = adt_datum - .binders - .map_ref(|b| &b.variants) - .substitute(interner, substitution) - .into_iter() - .flat_map(|v| { - v.fields.into_iter().map(|f| { - // Implemented(FieldTy: Copy) - TraitRef { - trait_id: trait_ref.trait_id, - substitution: Substitution::from1(interner, f), - } - .cast(interner) - }) - }) - .chain(neg_drop_goal.into_iter()); - - Some(Goal::all(interner, goals)) + solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner)) } - /// Computes goal to prove constraints on a Drop implementation + /// Verifies constraints on a Drop implementation /// Drop implementation is considered well-formed if: /// a) it's implemented on an ADT /// b) The generic parameters of the impl's type must all be parameters @@ -653,15 +740,16 @@ impl WfWellKnownGoals { /// } /// ``` fn drop_impl_constraint( + solver: &mut dyn Solver, db: &dyn RustIrDatabase, impl_datum: &ImplDatum, - ) -> Option> { + ) -> bool { let interner = db.interner(); let adt_id = match impl_datum.self_type_adt_id(interner) { Some(id) => id, // Drop can only be implemented on a nominal type - None => return Some(GoalData::CannotProve.intern(interner)), + None => return false, }; let mut gb = GoalBuilder::new(db); @@ -727,6 +815,189 @@ impl WfWellKnownGoals { }, ); - Some(gb.all([implied_by_adt_def_goal, eq_goal].iter())) + let well_formed_goal = gb.all([implied_by_adt_def_goal, eq_goal].iter()); + + solver.has_unique_solution(db, &well_formed_goal.into_closed_goal(interner)) + } + + /// Verify constraints a CoerceUnsized impl. + /// Rules for CoerceUnsized impl to be considered well-formed: + /// a) pointer conversions: &[mut] T -> &[mut] U, &[mut] T -> *[mut] U, + /// *[mut] T -> *[mut] U are considered valid if + /// 1) T: Unsize + /// 2) mutability is respected, i.e. immutable -> immutable, mutable -> immutable, + /// mutable -> mutable conversions are allowed, immutable -> mutable is not. + /// b) struct conversions of structures with the same definition, `S` -> `S`. + /// To check if this impl is legal, we would walk down the fields of `S` + /// and consider their types with both substitutes. We are looking to find + /// exactly one (non-phantom) field that has changed its type (from T to U), and + /// expect T to be unsizeable to U, i.e. T: CoerceUnsized. + /// + /// As an example, consider a struct + /// ```rust + /// struct Foo { + /// extra: T, + /// ptr: *mut U, + /// } + /// ``` + /// + /// We might have an impl that allows (e.g.) `Foo` to be unsized + /// to `Foo`. That impl would look like: + /// ```rust,ignore + /// impl, V> CoerceUnsized> for Foo {} + /// ``` + /// In this case: + /// + /// - `extra` has type `T` before and type `T` after + /// - `ptr` has type `*mut U` before and type `*mut V` after + /// + /// Since just one field changed, we would then check that `*mut U: CoerceUnsized<*mut V>` + /// is implemented. This will work out because `U: Unsize`, and we have a libcore rule + /// that `*mut U` can be coerced to `*mut V` if `U: Unsize`. + fn coerce_unsized_impl_constraint( + solver: &mut dyn Solver, + db: &dyn RustIrDatabase, + impl_datum: &ImplDatum, + ) -> bool { + let interner = db.interner(); + let mut gb = GoalBuilder::new(db); + + let (binders, impl_datum) = impl_datum.binders.as_ref().into(); + + let trait_ref: &TraitRef = &impl_datum.trait_ref; + + let source = trait_ref.self_type_parameter(interner); + let target = trait_ref + .substitution + .at(interner, 1) + .assert_ty_ref(interner) + .clone(); + + let mut place_in_environment = |goal| -> Goal { + gb.forall( + &Binders::new( + binders.clone(), + (goal, trait_ref, &impl_datum.where_clauses), + ), + (), + |gb, _, (goal, trait_ref, where_clauses), ()| { + let interner = gb.interner(); + gb.implies( + impl_wf_environment(interner, &where_clauses, &trait_ref), + |_| goal, + ) + }, + ) + }; + + match (source.data(interner), target.data(interner)) { + (TyData::Apply(source_app), TyData::Apply(target_app)) => { + match (&source_app.name, &target_app.name) { + (TypeName::Ref(s_m), TypeName::Ref(t_m)) + | (TypeName::Ref(s_m), TypeName::Raw(t_m)) + | (TypeName::Raw(s_m), TypeName::Raw(t_m)) => { + if (*s_m, *t_m) == (Mutability::Not, Mutability::Mut) { + return false; + } + + let source = source_app.first_type_parameter(interner).unwrap(); + let target = target_app.first_type_parameter(interner).unwrap(); + + let unsize_trait_id = + if let Some(id) = db.well_known_trait_id(WellKnownTrait::Unsize) { + id + } else { + return false; + }; + + // Source: Unsize + let unsize_goal: Goal = TraitRef { + trait_id: unsize_trait_id, + substitution: Substitution::from_iter( + interner, + [source, target].iter().cloned(), + ), + } + .cast(interner); + + // ImplEnv -> Source: Unsize + let unsize_goal = place_in_environment(unsize_goal); + + solver.has_unique_solution(db, &unsize_goal.into_closed_goal(interner)) + } + (TypeName::Adt(source_id), TypeName::Adt(target_id)) => { + let adt_datum = db.adt_datum(*source_id); + + if source_id != target_id || adt_datum.kind != AdtKind::Struct { + return false; + } + + let fields = adt_datum + .binders + .map_ref(|bound| &bound.variants.last().unwrap().fields); + + let (source_fields, target_fields) = ( + fields.substitute(interner, &source_app.substitution), + fields.substitute(interner, &target_app.substitution), + ); + + // collect fields with unequal ids + let uneq_field_ids: Vec = (0..source_fields.len()) + .filter(|&i| { + // ignore phantom data fields + if let Some(adt_id) = source_fields[i].adt_id(interner) { + if db.adt_datum(adt_id).flags.phantom_data { + return false; + } + } + + let eq_goal: Goal = EqGoal { + a: source_fields[i].clone().cast(interner), + b: target_fields[i].clone().cast(interner), + } + .cast(interner); + + // ImplEnv -> Source.fields[i] = Target.fields[i] + let eq_goal = place_in_environment(eq_goal); + + // We are interested in !UNEQUAL! fields + !solver.has_unique_solution(db, &eq_goal.into_closed_goal(interner)) + }) + .collect(); + + if uneq_field_ids.len() != 1 { + return false; + } + + let field_id = uneq_field_ids[0]; + + // Source.fields[i]: CoerceUnsized + let coerce_unsized_goal: Goal = TraitRef { + trait_id: trait_ref.trait_id, + substitution: Substitution::from_iter( + interner, + [ + source_fields[field_id].clone(), + target_fields[field_id].clone(), + ] + .iter() + .cloned(), + ), + } + .cast(interner); + + // ImplEnv -> Source.fields[i]: CoerceUnsized + let coerce_unsized_goal = place_in_environment(coerce_unsized_goal); + + solver.has_unique_solution( + db, + &coerce_unsized_goal.into_closed_goal(interner), + ) + } + _ => false, + } + } + _ => false, + } } } diff --git a/vendor/compiler_builtins/.cargo-checksum.json b/vendor/compiler_builtins/.cargo-checksum.json index b14e1309a8..838b788c8c 100644 --- a/vendor/compiler_builtins/.cargo-checksum.json +++ b/vendor/compiler_builtins/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"1dfa9c1f68c8e0f1d1fc90ed0712a3eeb2ea68478064c19d601249f60acde4a1","Cargo.toml":"d12e720542879582d4a8b9d6582a367d2962def71cd58cddfccf4e5d8df8b0cd","README.md":"2dd28b207028773ffee09ed0db563ac71b255b6b67256289d67a13cb19d15f94","build.rs":"bb626c4ce8b3b4c7e61548a1a56684997a58fc9d5f052df690031901321a43e6","examples/intrinsics.rs":"5bc2a8e39a541a6b55567f36ff9de17afad3cb620702a9e7c5b069a237f1197b","libm/src/math/acos.rs":"fb066ba84aba1372d706425ec14f35ff8d971756d15eeebd22ecf42a716493bb","libm/src/math/acosf.rs":"a112b82309bba1d35c4e3d6ad4d6c21ef305343d9ab601ddf4bc61d43bc9f1af","libm/src/math/acosh.rs":"56dac8538e4350cd7cf001327c89f087b68abb2e6aaad58edba8a094b09f6b0f","libm/src/math/acoshf.rs":"df5b0c4d8e37e64cf5ff2d8328b28bc35c78e84060ff769e64523ea9ff9065c1","libm/src/math/asin.rs":"095a1e98996daff45df0b154ca0ec35bbf31db964ee9fdda0207308cb20df441","libm/src/math/asinf.rs":"49cccb4db2881982643a4a7d5453f4f8daf527711bbb67313607a3c178856d61","libm/src/math/asinh.rs":"e8fc94031015fddf35e9c26b94da9f6431ee17c81cd7bd37da8ffc98f7e0b32c","libm/src/math/asinhf.rs":"8a0b8933a98a17617a66fef4c7b89eba645fdf05302000babf4a5a5f45328430","libm/src/math/atan.rs":"d4fe46e1c5739dd09997869dcfbc3c85f03c534af52e700d6c6bcf9c3fedda07","libm/src/math/atan2.rs":"2623bc8ca707d13a7092ce49adf68e9cbf4452ad1bf4a861dc40ca858606a747","libm/src/math/atan2f.rs":"dd01943e0e1f1955912e5c3ffc9467529cf64bd02ac0a6ad5ab31dbe6657f05d","libm/src/math/atanf.rs":"e41b41569474a59c970ede3538e00bda4072cf4d90040017101cc79d7dc28caa","libm/src/math/atanh.rs":"5934dbd6b7395ca4f103ace7598da723a9270e1cf6b47e7f786debe4bb3651ff","libm/src/math/atanhf.rs":"8ba4711dda19ef2dc33622be65c1483902868083543198c6bbd040d4026293de","libm/src/math/cbrt.rs":"f2c45612d2eecd93cfcdd9ebf824c754fc8f8dfd6d16862c0b9c4ccea78c2a0f","libm/src/math/cbrtf.rs":"ad0b483854aa9f17a44d36c049bf0e8ebab34c27e90b787c05f45cc230ec7d19","libm/src/math/ceil.rs":"0e6caff1597818471c28b7c3226dbfe9976fdb38ace5246172ac030754be6b79","libm/src/math/ceilf.rs":"f942bcea617de7da880b68bdfe676837a7984e2a887eaafe181be24c6bc13cc2","libm/src/math/copysign.rs":"d80c880efaf0cdf2ce0a4d4f5a68dd6c36c88d46fa997ec8ac8604bfdb26fa33","libm/src/math/copysignf.rs":"1547116071e68a42b1605eb2fc722db6466a34517dc96b92de1f29a274c3d8e3","libm/src/math/cos.rs":"74babdc13ede78e400c5ca1854c3e22d2e08cbdc5618aefa5bba6f9303ef65b6","libm/src/math/cosf.rs":"09c40f93c445b741e22477ceedf163ca33b6a47f973f7c9876cfba2692edb29c","libm/src/math/cosh.rs":"0d0a7cef18577f321996b8b87561963139f754ad7f2ea0a3b3883811f3f0693a","libm/src/math/coshf.rs":"be8ca8739e4cf1978425b349f941cb4838bba8c10cb559c7940b9fd4fdde21ad","libm/src/math/erf.rs":"9c55fc6756ba816996f0b585e07ccfa4cd87575ad525cd30c4a968b30acffda3","libm/src/math/erff.rs":"cb020e8bada9a54573a11fe3271750d73f14fed3092a881a9ceaf98fe32fd5a6","libm/src/math/exp.rs":"ca7405ad0d1993fffcf9aae96f9256307bed3c4916545aaebd1cf1d2df1807fa","libm/src/math/exp10.rs":"2deb037f88feac87a0e924b69dd496f0dd3b5d35f2a58e09d4c5166b207e517b","libm/src/math/exp10f.rs":"6979464dfe3f4f2da1f9afc909646499c4bfaef15e10a039384750e2f1586fea","libm/src/math/exp2.rs":"94a9304a2ce3bc81f6d2aefd3cde6faa30f13260d46cb13692863cdea1c9a3a1","libm/src/math/exp2f.rs":"785f2630accd35118ec07bf60273e219ed91a215b956b1552eeea5bc2a708cc8","libm/src/math/expf.rs":"ec14c18f891a9e37735ec39e6fc2e9bf674a2c2e083f22e2533b481177359c98","libm/src/math/expm1.rs":"124069f456c8ad331f265c7509d9e223b2a300e461bbfd3d6adfdcdd2ee5b8ac","libm/src/math/expm1f.rs":"18e2116d31ea8410051cc709b9d04b754b0e3ba6758ee1bf0b48749f4999b840","libm/src/math/expo2.rs":"4f4f9fecfccb43f30c2784aa7c0bb656754a52b8ab431f7d1b551c673ab133f1","libm/src/math/fabs.rs":"e6c7db39f98508098cdf64ac0c2f53866c466149a7490afb9fe22b44c4dd81b3","libm/src/math/fabsf.rs":"dc85b66e4ef662721276ae3a301af22795524e4367ee8dd40f0c24c439773c6d","libm/src/math/fdim.rs":"8ec091996005207297c2389ae563e1b18dbc6a9eac951de29a976c5cd7bc32a7","libm/src/math/fdimf.rs":"c7f3f2269834d55be26b6580ddc07c42531577955fa4de35bad1e2a361085614","libm/src/math/fenv.rs":"8730d45aa4c591f91dccdcc1ce533fa23e9c6df0c38defb9c57f749cb25e1cd0","libm/src/math/floor.rs":"be15e687a6798defc6f2c6b43028481f8104fb93d2b3f359d3d5d16b78e79d4f","libm/src/math/floorf.rs":"4ec41aa64cfafd23b8cfc043eacea5e9125cca5dcb3f5e655cc3d3458c6ba2c5","libm/src/math/fma.rs":"6872e79787e9270520189b53608f602b8ad5a099f3cef10ad5b9e0c06ef01fe0","libm/src/math/fmaf.rs":"3e0f5727e56f31218f674b9b8975d7e67b3a24a097f06a2a3eca9723cd786213","libm/src/math/fmax.rs":"f6c8e96a8b1a170648d2fa3513e7b6b459085d708c839869f82e305fe58fac37","libm/src/math/fmaxf.rs":"dff0025433232e8a5ec7bd54d847ccf596d762ea4e35f5c54fbaac9404d732fd","libm/src/math/fmin.rs":"95b6cb66ca0e0e22276f0bf88dbe8fb69796a69a196a7491bd4802efbcf2e298","libm/src/math/fminf.rs":"304bc839b15ea3d84e68d2af9f40524ec120d30a36a667b22fcb98a6c258f4c7","libm/src/math/fmod.rs":"a1c0550fc7df8164733d914e222ff0966a2ab886d6e75a1098f24fe0283ae227","libm/src/math/fmodf.rs":"ee51ed092c0eeb8195f35735ff725cfd46612e0d689a7c483538bd92fbe61828","libm/src/math/frexp.rs":"28af70026922a8ab979744c7ad4d8faba6079c4743b7eeb6d14c983a982fbbcc","libm/src/math/frexpf.rs":"2e2593ae8002ba420809ebfaf737ef001cdc912354be3d978a8c0cb930350d4d","libm/src/math/hypot.rs":"841131c4a0cea75bc8a86e29f3f6d0815a61fc99731c9984651ce83d3050d218","libm/src/math/hypotf.rs":"5f317323edc2eb699580fe54b074b7e570a7734d51a0a149c0b49b54470a836c","libm/src/math/ilogb.rs":"813413bf6266d4fc40db9c5921af3cef4f892ba93e8f6d9efe62a449d1234532","libm/src/math/ilogbf.rs":"dec462780f46682e16cfaa733238bed3b692729e951f53a44726100b6c73a716","libm/src/math/j0.rs":"9572b6396c489927d332d0e717920e61ec0618e5e9c31f7eeeec70f5e4abab06","libm/src/math/j0f.rs":"802c8254bded9b3afb6eea8b9af240038a5a4a5d811396729f69ca509e3e7d87","libm/src/math/j1.rs":"97b1af1611fa3d110c2b349ee8e4176100132ea1391b619086b47ac063b81803","libm/src/math/j1f.rs":"1d504d7750c0481273baad88196d3644f258af9ad10f8b5b16341c0aab8b9125","libm/src/math/jn.rs":"847d122334e5707ad9627146cddccc082a1f2f5bcd3e5ef54399013a7007ce88","libm/src/math/jnf.rs":"4045076f7d1a1b89882ed60d4dd60a4cbbc66b85cfb90491378c8015effcc476","libm/src/math/k_cos.rs":"f34a69e44d6b8901b03b578a75972f438ab20a7b98a0903fc1903d6fde3899be","libm/src/math/k_cosf.rs":"8f7117ff21cebf8e890a5bcfd7ea858a94172f4172b79a66d53824c2cb0888b1","libm/src/math/k_expo2.rs":"eb4ca9e6a525b7ea6da868c3cb136896682cc46f8396ba2a2ebc3ae9e9ba54b0","libm/src/math/k_expo2f.rs":"d51ad5df61cb5d1258bdb90c52bfed4572bb446a9337de9c04411ed9454ae0cb","libm/src/math/k_sin.rs":"14b2aba6ca07150c92768b5a72acaf5cde6a11d6619e14896512a7ba242e289a","libm/src/math/k_sinf.rs":"2775fcc710807164e6f37a4f8da3c8143cd5f16e19ce7c31c5591522151d7a96","libm/src/math/k_tan.rs":"a72beae4ccd9631eeeb61d6365bbeecae81c8411f3120a999c515cca0d5ea5c5","libm/src/math/k_tanf.rs":"6a794be56fa4b2f60452b9bab19af01c388f174560acbf829a351378ea39495d","libm/src/math/ldexp.rs":"b647f0096e80e4d926d8dd18d294c892ee2cb1778effe2c5e1b2664ae5cb1a4e","libm/src/math/ldexpf.rs":"98743fad2cd97a7be496f40ba3157ac1438fce0d0c25d5ab90c3b8c71c3fd0ed","libm/src/math/lgamma.rs":"498552658cc8106d7754f85ae8dbc3306ac2f0a9f7eb5a796be70c5beac92c41","libm/src/math/lgamma_r.rs":"77fb6442aeb5343926d8965e1549dde3e2cc4fd09555de6b56506001d956c344","libm/src/math/lgammaf.rs":"457105f53a4c8717e8f5a117d261dcf94e222e83981337fe23602abe883fe3f7","libm/src/math/lgammaf_r.rs":"44de75babbdd53c4a5879cd6f426e7311db82669def39df5f63914d67d6cc1b1","libm/src/math/log.rs":"b5e0c5f30d9e94351488732801be3107c12b854c3f95ad37e256dd88eeca408f","libm/src/math/log10.rs":"3425ff8be001fd1646ba15e254eb6ef4bdc6ccaf0cbee27ddf1fa84e04178b90","libm/src/math/log10f.rs":"fee4f71879bc4c99259e68c0c641364901629fb29a8ebddfcc0d090102cceddd","libm/src/math/log1p.rs":"9cf400852f165e6be19b97036ae9521fb9ca857d0a9a91c117d9123221622185","libm/src/math/log1pf.rs":"2716e6d2afa271996b7c8f47fd9e4952c88f4c1fd8c07c3e8ce8c62794bf71d8","libm/src/math/log2.rs":"dbbbfbaaa8aa6a4dbefea554ea3983090a9691228b011910c751f6adca912c40","libm/src/math/log2f.rs":"92a90350d8edce21c31c285c3e620fca7c62a2366008921715945c2c73b5b79f","libm/src/math/logf.rs":"845342cffc34d3db1f5ec12d8e5b773cd5a79056e28662fcb9bcd80207596f50","libm/src/math/mod.rs":"ffa73c08f4c0a4dc6c9d1cb9d62fe97f3a5046edede128c9441cc3adc9170dd3","libm/src/math/modf.rs":"d012ed5a708ef52b6d1313c22a46cadaf5764dde1220816e3df2f03a0fcc60ae","libm/src/math/modff.rs":"f8f1e4c27a85d2cdb3c8e74439d59ef64aa543b948f22c23227d02d8388d61c2","libm/src/math/nextafter.rs":"3282e7eef214a32736fb6928d490198ad394b26b402b45495115b104839eebfe","libm/src/math/nextafterf.rs":"0937dc8a8155c19842c12181e741cec1f7df1f7a00cee81fcb2475e2842761b7","libm/src/math/pow.rs":"64fba587143fa88cdfa5c9d30b658ab03e3a19e3ea3759394836add4068983c6","libm/src/math/powf.rs":"2c423a0ea57fdc4e20f3533f744c6e6288c998b4de8f2914fafaa0e78be81b04","libm/src/math/rem_pio2.rs":"9be99c44493b2b7088578c0fa2872630725b2da544c751516df0c6c686112a43","libm/src/math/rem_pio2_large.rs":"21762d08d72dc6f2e313123a7311683000974a09b8fcae50994d9c39239721b1","libm/src/math/rem_pio2f.rs":"377349d1308bda8cd2f776e4856fe090baa78fa3db816b680780ddf31b80d446","libm/src/math/remainder.rs":"63865f4370853c476b45bb27a5c54a4072146aa4a626835ae5263871a4e7e5dc","libm/src/math/remainderf.rs":"dd3fa432dbda8f2135428198be7bd69c57f8d13df3f365b12f52bf6a82352ac4","libm/src/math/remquo.rs":"3cc0bf55069f165c4843f2c358b3a27279c01e8cdd99f9057a3f7f31f45408f2","libm/src/math/remquof.rs":"cc749e18ecb7e766b8b8eeabdbf89ac99087d3d587e71e30f690676a3d2c1f9b","libm/src/math/round.rs":"955649c893fa3151b4a81c8e550fbc03f01bb99b40d60986e5f153ee71043f69","libm/src/math/roundf.rs":"8ae8f1f71eedd158566771cfe80b352d2f13c170a0ce8dc2691a14e8a791cfbb","libm/src/math/scalbn.rs":"b5c9d6d4177fe393cbfe1c634d75ce14b754f6cbce87c5bf979a9661491748a2","libm/src/math/scalbnf.rs":"4f198d06db1896386256fb9a5ac5b805b16b836226c18780a475cf18d7c1449c","libm/src/math/sin.rs":"0e014e6377c9673a73395ab2ffcf5962e512392afddf8a4e731fb694098faf34","libm/src/math/sincos.rs":"59e9f196140681fa817652134b8d1bdd2d6dd47bb8557b0346c77b176389f883","libm/src/math/sincosf.rs":"d37d71c7204c7892fe24c956df0fb95e7a014a808f5cbd5e125aee48c3c449b5","libm/src/math/sinf.rs":"dcddac1d56b084cbb8d0e019433c9c5fe2201d9b257a7dcf2f85c9a8f14b79cf","libm/src/math/sinh.rs":"d8ee4c7af883a526f36c1a6da13bb81fba9181b477e2f2538161a2bee97edc35","libm/src/math/sinhf.rs":"d06eb030ba9dbf7094df127262bfe99f149b4db49fa8ab8c15499660f1e46b26","libm/src/math/sqrt.rs":"824570a631c2542ccee68b65e3eb08fe79c037a29bbaaf54da5367e7b236124a","libm/src/math/sqrtf.rs":"d9e12ac55c5471c18175efdfb15c092ba71a2eb914d2e1ee3b3310a22202042e","libm/src/math/tan.rs":"930ecedaadc60f704c2dfa4e15186f59713c1ba7d948529d215223b424827db5","libm/src/math/tanf.rs":"894156a3b107aee08461eb4e7e412fc049aa237d176ae705c6e3e2d7060d94e3","libm/src/math/tanh.rs":"f1f08eb98ed959a17370a7aaf0177be36e3764543424e78feb033ed3f5e8ec98","libm/src/math/tanhf.rs":"74027b0c672a4e64bdef6d7a3069b90caec50e1e7dbb2c12d2828f310502f41e","libm/src/math/tgamma.rs":"a6aabb8365410af6611f19f58694ccb74e82bb9ba9e1cdec7e1af787cfa44815","libm/src/math/tgammaf.rs":"c95bd69957387533853532164f7e2251d2b04f5e775406b9e647226ae2bdd5ad","libm/src/math/trunc.rs":"642264897cc1505e720c8cf313be81aa9fd53aae866644a2e988d01dbc77fd8a","libm/src/math/truncf.rs":"619b675b6a9bb81eccddb1fa8214cff63e1f62136629b645c87f036672311732","src/arm.rs":"2035935972d728031d31d35067f0ec474f1c3b1ab86e166130d29df266b09b90","src/arm_linux.rs":"80d18ce84bdfa841fa133f5ee9e9fd50167344436d2d398f74347a90f27606c6","src/float/add.rs":"1a230ed4e17148cfffb7c880929c9c0d5d48d85581d75164c5031b8f05a5d567","src/float/cmp.rs":"a86ccbc0e56f07ba439dc6a4fd835184645178c0a6da625bd4ae24ecf9a790f8","src/float/conv.rs":"0af148b6c717d124e870e5d1926eaa562de37e374c605ea81c1f7eea994146f4","src/float/div.rs":"58bdcd73c5ffafde9cca8a0e7986de0660fb8b5b4d4132e7a63dd21f93f4fe0e","src/float/extend.rs":"180b2e791c58e0526de0a798845c580ce3222c8a15c8665e6e6a4bf5cf1a34aa","src/float/mod.rs":"d15b78070d824f5523f12d55fc084879b638241324451dbcd0ac291589c53125","src/float/mul.rs":"9465960b326897a04543789aa44640aefeb4cc63311e58ae8213f664dd4ac21e","src/float/pow.rs":"64f4935f4bed46d3b9cde4d16f59cca76a110d36d02d76f4b909157349edf5e3","src/float/sub.rs":"c2a87f4628f51d5d908d0f25b5d51ce0599dc559d5a72b20e131261f484d5848","src/int/addsub.rs":"9e7a393c76958fe9e8fb7de9bfe1304766c276bfdaa25761913357e0f6172369","src/int/mod.rs":"d15781df9dc054aa11e23f4825152ae9c609aab15bf43599ff07ff683f513643","src/int/mul.rs":"3142da8783cfac3ef704efcae19838bfda4916965fb852294685cf7664976e8a","src/int/sdiv.rs":"ca47f2a41fe0aad1e37f4e56ab1e0959c5b10c32c3593596c8cef2ff17694389","src/int/shift.rs":"0427e05a39cf6a0abab0b6525e8567afcf336f49fbb0ed0977b480e16a878bd8","src/int/udiv.rs":"9a222e79c0bf74ab77728cfa2026508508b33e7f2ac6cafc1fa34040e5538ba0","src/lib.rs":"da4433593615a60f05aff9f5252f15350e537d97dfa96e6536619545dd173851","src/macros.rs":"9f3aa9b66195b258ff29209c6b1e7962d6f82d31579d669dd74c9fdeee134170","src/math.rs":"a2e45a208bcdd742d32639591c91525a44f891db6057ce066052d67c4d4ae809","src/mem.rs":"4ece60ca07aaff3611a716a80f55668a785ad8399b65fc36cc9ab4b481fa639c","src/probestack.rs":"c1ad1e4a9550a3507bcbec00c8917530a954ba971c02506aeec949381443674a","src/riscv32.rs":"b9b433d248fce35e43a7df430697545f39898fad46be7d0197284764e44993b2","src/x86.rs":"068e456417d4740f048800da1d18eb49dd85f85604e5e383446331925e1effc3","src/x86_64.rs":"3ffbefe3bdc75cd4674ba1bbab9029bc4d6d8635f5e0b1fe30329ec6209bfd8a"},"package":"7bc4ac2c824d2bfc612cba57708198547e9a26943af0632aff033e0693074d5c"} \ No newline at end of file +{"files":{"Cargo.lock":"4772ce261c2f483910066a5cc1617e71a977b5c29f8a482be4ca4296f0154016","Cargo.toml":"465bc9f84288f6569851041d8a1ae04f7cda2eb1f1a4e9e06a71b2eb4262ae6a","README.md":"2dd28b207028773ffee09ed0db563ac71b255b6b67256289d67a13cb19d15f94","build.rs":"8140e3dce70516bbf8d151565f8f50a31bbfab60e749becd649f4c11ee350282","examples/intrinsics.rs":"5bc2a8e39a541a6b55567f36ff9de17afad3cb620702a9e7c5b069a237f1197b","libm/src/math/acos.rs":"fb066ba84aba1372d706425ec14f35ff8d971756d15eeebd22ecf42a716493bb","libm/src/math/acosf.rs":"a112b82309bba1d35c4e3d6ad4d6c21ef305343d9ab601ddf4bc61d43bc9f1af","libm/src/math/acosh.rs":"56dac8538e4350cd7cf001327c89f087b68abb2e6aaad58edba8a094b09f6b0f","libm/src/math/acoshf.rs":"df5b0c4d8e37e64cf5ff2d8328b28bc35c78e84060ff769e64523ea9ff9065c1","libm/src/math/asin.rs":"095a1e98996daff45df0b154ca0ec35bbf31db964ee9fdda0207308cb20df441","libm/src/math/asinf.rs":"49cccb4db2881982643a4a7d5453f4f8daf527711bbb67313607a3c178856d61","libm/src/math/asinh.rs":"e8fc94031015fddf35e9c26b94da9f6431ee17c81cd7bd37da8ffc98f7e0b32c","libm/src/math/asinhf.rs":"8a0b8933a98a17617a66fef4c7b89eba645fdf05302000babf4a5a5f45328430","libm/src/math/atan.rs":"d4fe46e1c5739dd09997869dcfbc3c85f03c534af52e700d6c6bcf9c3fedda07","libm/src/math/atan2.rs":"2623bc8ca707d13a7092ce49adf68e9cbf4452ad1bf4a861dc40ca858606a747","libm/src/math/atan2f.rs":"dd01943e0e1f1955912e5c3ffc9467529cf64bd02ac0a6ad5ab31dbe6657f05d","libm/src/math/atanf.rs":"e41b41569474a59c970ede3538e00bda4072cf4d90040017101cc79d7dc28caa","libm/src/math/atanh.rs":"5934dbd6b7395ca4f103ace7598da723a9270e1cf6b47e7f786debe4bb3651ff","libm/src/math/atanhf.rs":"8ba4711dda19ef2dc33622be65c1483902868083543198c6bbd040d4026293de","libm/src/math/cbrt.rs":"f2c45612d2eecd93cfcdd9ebf824c754fc8f8dfd6d16862c0b9c4ccea78c2a0f","libm/src/math/cbrtf.rs":"ad0b483854aa9f17a44d36c049bf0e8ebab34c27e90b787c05f45cc230ec7d19","libm/src/math/ceil.rs":"0e6caff1597818471c28b7c3226dbfe9976fdb38ace5246172ac030754be6b79","libm/src/math/ceilf.rs":"f942bcea617de7da880b68bdfe676837a7984e2a887eaafe181be24c6bc13cc2","libm/src/math/copysign.rs":"d80c880efaf0cdf2ce0a4d4f5a68dd6c36c88d46fa997ec8ac8604bfdb26fa33","libm/src/math/copysignf.rs":"1547116071e68a42b1605eb2fc722db6466a34517dc96b92de1f29a274c3d8e3","libm/src/math/cos.rs":"74babdc13ede78e400c5ca1854c3e22d2e08cbdc5618aefa5bba6f9303ef65b6","libm/src/math/cosf.rs":"09c40f93c445b741e22477ceedf163ca33b6a47f973f7c9876cfba2692edb29c","libm/src/math/cosh.rs":"0d0a7cef18577f321996b8b87561963139f754ad7f2ea0a3b3883811f3f0693a","libm/src/math/coshf.rs":"be8ca8739e4cf1978425b349f941cb4838bba8c10cb559c7940b9fd4fdde21ad","libm/src/math/erf.rs":"9c55fc6756ba816996f0b585e07ccfa4cd87575ad525cd30c4a968b30acffda3","libm/src/math/erff.rs":"cb020e8bada9a54573a11fe3271750d73f14fed3092a881a9ceaf98fe32fd5a6","libm/src/math/exp.rs":"ca7405ad0d1993fffcf9aae96f9256307bed3c4916545aaebd1cf1d2df1807fa","libm/src/math/exp10.rs":"2deb037f88feac87a0e924b69dd496f0dd3b5d35f2a58e09d4c5166b207e517b","libm/src/math/exp10f.rs":"6979464dfe3f4f2da1f9afc909646499c4bfaef15e10a039384750e2f1586fea","libm/src/math/exp2.rs":"94a9304a2ce3bc81f6d2aefd3cde6faa30f13260d46cb13692863cdea1c9a3a1","libm/src/math/exp2f.rs":"785f2630accd35118ec07bf60273e219ed91a215b956b1552eeea5bc2a708cc8","libm/src/math/expf.rs":"ec14c18f891a9e37735ec39e6fc2e9bf674a2c2e083f22e2533b481177359c98","libm/src/math/expm1.rs":"124069f456c8ad331f265c7509d9e223b2a300e461bbfd3d6adfdcdd2ee5b8ac","libm/src/math/expm1f.rs":"18e2116d31ea8410051cc709b9d04b754b0e3ba6758ee1bf0b48749f4999b840","libm/src/math/expo2.rs":"4f4f9fecfccb43f30c2784aa7c0bb656754a52b8ab431f7d1b551c673ab133f1","libm/src/math/fabs.rs":"e6c7db39f98508098cdf64ac0c2f53866c466149a7490afb9fe22b44c4dd81b3","libm/src/math/fabsf.rs":"dc85b66e4ef662721276ae3a301af22795524e4367ee8dd40f0c24c439773c6d","libm/src/math/fdim.rs":"8ec091996005207297c2389ae563e1b18dbc6a9eac951de29a976c5cd7bc32a7","libm/src/math/fdimf.rs":"c7f3f2269834d55be26b6580ddc07c42531577955fa4de35bad1e2a361085614","libm/src/math/fenv.rs":"8730d45aa4c591f91dccdcc1ce533fa23e9c6df0c38defb9c57f749cb25e1cd0","libm/src/math/floor.rs":"be15e687a6798defc6f2c6b43028481f8104fb93d2b3f359d3d5d16b78e79d4f","libm/src/math/floorf.rs":"4ec41aa64cfafd23b8cfc043eacea5e9125cca5dcb3f5e655cc3d3458c6ba2c5","libm/src/math/fma.rs":"6872e79787e9270520189b53608f602b8ad5a099f3cef10ad5b9e0c06ef01fe0","libm/src/math/fmaf.rs":"3e0f5727e56f31218f674b9b8975d7e67b3a24a097f06a2a3eca9723cd786213","libm/src/math/fmax.rs":"f6c8e96a8b1a170648d2fa3513e7b6b459085d708c839869f82e305fe58fac37","libm/src/math/fmaxf.rs":"dff0025433232e8a5ec7bd54d847ccf596d762ea4e35f5c54fbaac9404d732fd","libm/src/math/fmin.rs":"95b6cb66ca0e0e22276f0bf88dbe8fb69796a69a196a7491bd4802efbcf2e298","libm/src/math/fminf.rs":"304bc839b15ea3d84e68d2af9f40524ec120d30a36a667b22fcb98a6c258f4c7","libm/src/math/fmod.rs":"a1c0550fc7df8164733d914e222ff0966a2ab886d6e75a1098f24fe0283ae227","libm/src/math/fmodf.rs":"ee51ed092c0eeb8195f35735ff725cfd46612e0d689a7c483538bd92fbe61828","libm/src/math/frexp.rs":"28af70026922a8ab979744c7ad4d8faba6079c4743b7eeb6d14c983a982fbbcc","libm/src/math/frexpf.rs":"2e2593ae8002ba420809ebfaf737ef001cdc912354be3d978a8c0cb930350d4d","libm/src/math/hypot.rs":"841131c4a0cea75bc8a86e29f3f6d0815a61fc99731c9984651ce83d3050d218","libm/src/math/hypotf.rs":"5f317323edc2eb699580fe54b074b7e570a7734d51a0a149c0b49b54470a836c","libm/src/math/ilogb.rs":"813413bf6266d4fc40db9c5921af3cef4f892ba93e8f6d9efe62a449d1234532","libm/src/math/ilogbf.rs":"dec462780f46682e16cfaa733238bed3b692729e951f53a44726100b6c73a716","libm/src/math/j0.rs":"9572b6396c489927d332d0e717920e61ec0618e5e9c31f7eeeec70f5e4abab06","libm/src/math/j0f.rs":"802c8254bded9b3afb6eea8b9af240038a5a4a5d811396729f69ca509e3e7d87","libm/src/math/j1.rs":"97b1af1611fa3d110c2b349ee8e4176100132ea1391b619086b47ac063b81803","libm/src/math/j1f.rs":"1d504d7750c0481273baad88196d3644f258af9ad10f8b5b16341c0aab8b9125","libm/src/math/jn.rs":"847d122334e5707ad9627146cddccc082a1f2f5bcd3e5ef54399013a7007ce88","libm/src/math/jnf.rs":"4045076f7d1a1b89882ed60d4dd60a4cbbc66b85cfb90491378c8015effcc476","libm/src/math/k_cos.rs":"f34a69e44d6b8901b03b578a75972f438ab20a7b98a0903fc1903d6fde3899be","libm/src/math/k_cosf.rs":"8f7117ff21cebf8e890a5bcfd7ea858a94172f4172b79a66d53824c2cb0888b1","libm/src/math/k_expo2.rs":"eb4ca9e6a525b7ea6da868c3cb136896682cc46f8396ba2a2ebc3ae9e9ba54b0","libm/src/math/k_expo2f.rs":"d51ad5df61cb5d1258bdb90c52bfed4572bb446a9337de9c04411ed9454ae0cb","libm/src/math/k_sin.rs":"14b2aba6ca07150c92768b5a72acaf5cde6a11d6619e14896512a7ba242e289a","libm/src/math/k_sinf.rs":"2775fcc710807164e6f37a4f8da3c8143cd5f16e19ce7c31c5591522151d7a96","libm/src/math/k_tan.rs":"a72beae4ccd9631eeeb61d6365bbeecae81c8411f3120a999c515cca0d5ea5c5","libm/src/math/k_tanf.rs":"6a794be56fa4b2f60452b9bab19af01c388f174560acbf829a351378ea39495d","libm/src/math/ldexp.rs":"b647f0096e80e4d926d8dd18d294c892ee2cb1778effe2c5e1b2664ae5cb1a4e","libm/src/math/ldexpf.rs":"98743fad2cd97a7be496f40ba3157ac1438fce0d0c25d5ab90c3b8c71c3fd0ed","libm/src/math/lgamma.rs":"498552658cc8106d7754f85ae8dbc3306ac2f0a9f7eb5a796be70c5beac92c41","libm/src/math/lgamma_r.rs":"77fb6442aeb5343926d8965e1549dde3e2cc4fd09555de6b56506001d956c344","libm/src/math/lgammaf.rs":"457105f53a4c8717e8f5a117d261dcf94e222e83981337fe23602abe883fe3f7","libm/src/math/lgammaf_r.rs":"44de75babbdd53c4a5879cd6f426e7311db82669def39df5f63914d67d6cc1b1","libm/src/math/log.rs":"b5e0c5f30d9e94351488732801be3107c12b854c3f95ad37e256dd88eeca408f","libm/src/math/log10.rs":"3425ff8be001fd1646ba15e254eb6ef4bdc6ccaf0cbee27ddf1fa84e04178b90","libm/src/math/log10f.rs":"fee4f71879bc4c99259e68c0c641364901629fb29a8ebddfcc0d090102cceddd","libm/src/math/log1p.rs":"9cf400852f165e6be19b97036ae9521fb9ca857d0a9a91c117d9123221622185","libm/src/math/log1pf.rs":"2716e6d2afa271996b7c8f47fd9e4952c88f4c1fd8c07c3e8ce8c62794bf71d8","libm/src/math/log2.rs":"dbbbfbaaa8aa6a4dbefea554ea3983090a9691228b011910c751f6adca912c40","libm/src/math/log2f.rs":"92a90350d8edce21c31c285c3e620fca7c62a2366008921715945c2c73b5b79f","libm/src/math/logf.rs":"845342cffc34d3db1f5ec12d8e5b773cd5a79056e28662fcb9bcd80207596f50","libm/src/math/mod.rs":"ffa73c08f4c0a4dc6c9d1cb9d62fe97f3a5046edede128c9441cc3adc9170dd3","libm/src/math/modf.rs":"d012ed5a708ef52b6d1313c22a46cadaf5764dde1220816e3df2f03a0fcc60ae","libm/src/math/modff.rs":"f8f1e4c27a85d2cdb3c8e74439d59ef64aa543b948f22c23227d02d8388d61c2","libm/src/math/nextafter.rs":"3282e7eef214a32736fb6928d490198ad394b26b402b45495115b104839eebfe","libm/src/math/nextafterf.rs":"0937dc8a8155c19842c12181e741cec1f7df1f7a00cee81fcb2475e2842761b7","libm/src/math/pow.rs":"64fba587143fa88cdfa5c9d30b658ab03e3a19e3ea3759394836add4068983c6","libm/src/math/powf.rs":"2c423a0ea57fdc4e20f3533f744c6e6288c998b4de8f2914fafaa0e78be81b04","libm/src/math/rem_pio2.rs":"9be99c44493b2b7088578c0fa2872630725b2da544c751516df0c6c686112a43","libm/src/math/rem_pio2_large.rs":"21762d08d72dc6f2e313123a7311683000974a09b8fcae50994d9c39239721b1","libm/src/math/rem_pio2f.rs":"377349d1308bda8cd2f776e4856fe090baa78fa3db816b680780ddf31b80d446","libm/src/math/remainder.rs":"63865f4370853c476b45bb27a5c54a4072146aa4a626835ae5263871a4e7e5dc","libm/src/math/remainderf.rs":"dd3fa432dbda8f2135428198be7bd69c57f8d13df3f365b12f52bf6a82352ac4","libm/src/math/remquo.rs":"3cc0bf55069f165c4843f2c358b3a27279c01e8cdd99f9057a3f7f31f45408f2","libm/src/math/remquof.rs":"cc749e18ecb7e766b8b8eeabdbf89ac99087d3d587e71e30f690676a3d2c1f9b","libm/src/math/round.rs":"955649c893fa3151b4a81c8e550fbc03f01bb99b40d60986e5f153ee71043f69","libm/src/math/roundf.rs":"8ae8f1f71eedd158566771cfe80b352d2f13c170a0ce8dc2691a14e8a791cfbb","libm/src/math/scalbn.rs":"b5c9d6d4177fe393cbfe1c634d75ce14b754f6cbce87c5bf979a9661491748a2","libm/src/math/scalbnf.rs":"4f198d06db1896386256fb9a5ac5b805b16b836226c18780a475cf18d7c1449c","libm/src/math/sin.rs":"0e014e6377c9673a73395ab2ffcf5962e512392afddf8a4e731fb694098faf34","libm/src/math/sincos.rs":"59e9f196140681fa817652134b8d1bdd2d6dd47bb8557b0346c77b176389f883","libm/src/math/sincosf.rs":"d37d71c7204c7892fe24c956df0fb95e7a014a808f5cbd5e125aee48c3c449b5","libm/src/math/sinf.rs":"dcddac1d56b084cbb8d0e019433c9c5fe2201d9b257a7dcf2f85c9a8f14b79cf","libm/src/math/sinh.rs":"d8ee4c7af883a526f36c1a6da13bb81fba9181b477e2f2538161a2bee97edc35","libm/src/math/sinhf.rs":"d06eb030ba9dbf7094df127262bfe99f149b4db49fa8ab8c15499660f1e46b26","libm/src/math/sqrt.rs":"824570a631c2542ccee68b65e3eb08fe79c037a29bbaaf54da5367e7b236124a","libm/src/math/sqrtf.rs":"d9e12ac55c5471c18175efdfb15c092ba71a2eb914d2e1ee3b3310a22202042e","libm/src/math/tan.rs":"930ecedaadc60f704c2dfa4e15186f59713c1ba7d948529d215223b424827db5","libm/src/math/tanf.rs":"894156a3b107aee08461eb4e7e412fc049aa237d176ae705c6e3e2d7060d94e3","libm/src/math/tanh.rs":"f1f08eb98ed959a17370a7aaf0177be36e3764543424e78feb033ed3f5e8ec98","libm/src/math/tanhf.rs":"74027b0c672a4e64bdef6d7a3069b90caec50e1e7dbb2c12d2828f310502f41e","libm/src/math/tgamma.rs":"a6aabb8365410af6611f19f58694ccb74e82bb9ba9e1cdec7e1af787cfa44815","libm/src/math/tgammaf.rs":"c95bd69957387533853532164f7e2251d2b04f5e775406b9e647226ae2bdd5ad","libm/src/math/trunc.rs":"642264897cc1505e720c8cf313be81aa9fd53aae866644a2e988d01dbc77fd8a","libm/src/math/truncf.rs":"619b675b6a9bb81eccddb1fa8214cff63e1f62136629b645c87f036672311732","src/arm.rs":"2035935972d728031d31d35067f0ec474f1c3b1ab86e166130d29df266b09b90","src/arm_linux.rs":"80d18ce84bdfa841fa133f5ee9e9fd50167344436d2d398f74347a90f27606c6","src/float/add.rs":"1a230ed4e17148cfffb7c880929c9c0d5d48d85581d75164c5031b8f05a5d567","src/float/cmp.rs":"a86ccbc0e56f07ba439dc6a4fd835184645178c0a6da625bd4ae24ecf9a790f8","src/float/conv.rs":"0af148b6c717d124e870e5d1926eaa562de37e374c605ea81c1f7eea994146f4","src/float/div.rs":"58bdcd73c5ffafde9cca8a0e7986de0660fb8b5b4d4132e7a63dd21f93f4fe0e","src/float/extend.rs":"180b2e791c58e0526de0a798845c580ce3222c8a15c8665e6e6a4bf5cf1a34aa","src/float/mod.rs":"d15b78070d824f5523f12d55fc084879b638241324451dbcd0ac291589c53125","src/float/mul.rs":"9465960b326897a04543789aa44640aefeb4cc63311e58ae8213f664dd4ac21e","src/float/pow.rs":"64f4935f4bed46d3b9cde4d16f59cca76a110d36d02d76f4b909157349edf5e3","src/float/sub.rs":"c2a87f4628f51d5d908d0f25b5d51ce0599dc559d5a72b20e131261f484d5848","src/int/addsub.rs":"9e7a393c76958fe9e8fb7de9bfe1304766c276bfdaa25761913357e0f6172369","src/int/leading_zeros.rs":"b2c8763857b0687c45e540c585d5884eaf4f3badf5a0827350cff5b1c324beed","src/int/mod.rs":"0ae6151f3bc73783405507ab9c108eb006cc3a437ca4a215c9c4ef50b5081d00","src/int/mul.rs":"3142da8783cfac3ef704efcae19838bfda4916965fb852294685cf7664976e8a","src/int/sdiv.rs":"ca47f2a41fe0aad1e37f4e56ab1e0959c5b10c32c3593596c8cef2ff17694389","src/int/shift.rs":"0427e05a39cf6a0abab0b6525e8567afcf336f49fbb0ed0977b480e16a878bd8","src/int/udiv.rs":"9a222e79c0bf74ab77728cfa2026508508b33e7f2ac6cafc1fa34040e5538ba0","src/lib.rs":"f6ffd1dac18ea01184379e447a29bc4fb446fc15da15227fde82aa5fa0369bdf","src/macros.rs":"9f3aa9b66195b258ff29209c6b1e7962d6f82d31579d669dd74c9fdeee134170","src/math.rs":"a2e45a208bcdd742d32639591c91525a44f891db6057ce066052d67c4d4ae809","src/mem.rs":"4ece60ca07aaff3611a716a80f55668a785ad8399b65fc36cc9ab4b481fa639c","src/probestack.rs":"c1ad1e4a9550a3507bcbec00c8917530a954ba971c02506aeec949381443674a","src/riscv32.rs":"b9b433d248fce35e43a7df430697545f39898fad46be7d0197284764e44993b2","src/x86.rs":"068e456417d4740f048800da1d18eb49dd85f85604e5e383446331925e1effc3","src/x86_64.rs":"3ffbefe3bdc75cd4674ba1bbab9029bc4d6d8635f5e0b1fe30329ec6209bfd8a"},"package":"e3fcd8aba10d17504c87ef12d4f62ef404c6a4703d16682a9eb5543e6cf24455"} \ No newline at end of file diff --git a/vendor/compiler_builtins/Cargo.lock b/vendor/compiler_builtins/Cargo.lock index 04152f7db4..caead05b05 100644 --- a/vendor/compiler_builtins/Cargo.lock +++ b/vendor/compiler_builtins/Cargo.lock @@ -2,13 +2,13 @@ # It is not intended for manual editing. [[package]] name = "cc" -version = "1.0.52" +version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c3d87b23d6a92cd03af510a5ade527033f6aa6fa92161e2d5863a907d4c5e31d" +checksum = "7db2f146208d7e0fbee761b09cd65a7f51ccc38705d4e7262dad4d73b12a76b1" [[package]] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.35" dependencies = [ "cc", "rustc-std-workspace-core", diff --git a/vendor/compiler_builtins/Cargo.toml b/vendor/compiler_builtins/Cargo.toml index aafd5b9eac..fb3000592c 100644 --- a/vendor/compiler_builtins/Cargo.toml +++ b/vendor/compiler_builtins/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "compiler_builtins" -version = "0.1.32" +version = "0.1.35" authors = ["Jorge Aparicio "] links = "compiler-rt" include = ["/Cargo.toml", "/build.rs", "/src/*", "/examples/*", "/LICENSE.txt", "/README.md", "/compiler-rt/*", "/libm/src/math/*"] diff --git a/vendor/compiler_builtins/build.rs b/vendor/compiler_builtins/build.rs index abeac9bf1e..f948edba9e 100644 --- a/vendor/compiler_builtins/build.rs +++ b/vendor/compiler_builtins/build.rs @@ -419,6 +419,37 @@ mod c { if target_os != "windows" { sources.extend(&[("__multc3", "multc3.c")]); } + + if target_env == "musl" { + sources.extend(&[ + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__divtf3", "divtf3.c"), + ("__powitf2", "powitf2.c"), + ("__fe_getround", "fp_mode.c"), + ("__fe_raise_inexact", "fp_mode.c"), + ]); + } + } + + if target_arch == "mips" { + sources.extend(&[("__bswapsi2", "bswapsi2.c")]); + } + + if target_arch == "mips64" { + sources.extend(&[ + ("__extenddftf2", "extenddftf2.c"), + ("__netf2", "comparetf2.c"), + ("__addtf3", "addtf3.c"), + ("__multf3", "multf3.c"), + ("__subtf3", "subtf3.c"), + ("__fixtfsi", "fixtfsi.c"), + ("__floatsitf", "floatsitf.c"), + ("__fixunstfsi", "fixunstfsi.c"), + ("__floatunsitf", "floatunsitf.c"), + ("__fe_getround", "fp_mode.c"), + ]); } // Remove the assembly implementations that won't compile for the target diff --git a/vendor/compiler_builtins/src/int/leading_zeros.rs b/vendor/compiler_builtins/src/int/leading_zeros.rs new file mode 100644 index 0000000000..78556f0bcf --- /dev/null +++ b/vendor/compiler_builtins/src/int/leading_zeros.rs @@ -0,0 +1,143 @@ +// Note: these functions happen to produce the correct `usize::leading_zeros(0)` value +// without a explicit zero check. Zero is probably common enough that it could warrant +// adding a zero check at the beginning, but `__clzsi2` has a precondition that `x != 0`. +// Compilers will insert the check for zero in cases where it is needed. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_default(x: usize) -> usize { + // The basic idea is to test if the higher bits of `x` are zero and bisect the number + // of leading zeros. It is possible for all branches of the bisection to use the same + // code path by conditionally shifting the higher parts down to let the next bisection + // step work on the higher or lower parts of `x`. Instead of starting with `z == 0` + // and adding to the number of zeros, it is slightly faster to start with + // `z == usize::MAX.count_ones()` and subtract from the potential number of zeros, + // because it simplifies the final bisection step. + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + #[cfg(target_pointer_width = "64")] + { + t = x >> 32; + if t != 0 { + z -= 32; + x = t; + } + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = x >> 16; + if t != 0 { + z -= 16; + x = t; + } + } + t = x >> 8; + if t != 0 { + z -= 8; + x = t; + } + t = x >> 4; + if t != 0 { + z -= 4; + x = t; + } + t = x >> 2; + if t != 0 { + z -= 2; + x = t; + } + // the last two bisections are combined into one conditional + t = x >> 1; + if t != 0 { + z - 2 + } else { + z - x + } + + // We could potentially save a few cycles by using the LUT trick from + // "https://embeddedgurus.com/state-space/2014/09/ + // fast-deterministic-and-portable-counting-leading-zeros/". + // However, 256 bytes for a LUT is too large for embedded use cases. We could remove + // the last 3 bisections and use this 16 byte LUT for the rest of the work: + //const LUT: [u8; 16] = [0, 1, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4, 4, 4]; + //z -= LUT[x] as usize; + //z + // However, it ends up generating about the same number of instructions. When benchmarked + // on x86_64, it is slightly faster to use the LUT, but this is probably because of OOO + // execution effects. Changing to using a LUT and branching is risky for smaller cores. +} + +// The above method does not compile well on RISC-V (because of the lack of predicated +// instructions), producing code with many branches or using an excessively long +// branchless solution. This method takes advantage of the set-if-less-than instruction on +// RISC-V that allows `(x >= power-of-two) as usize` to be branchless. + +/// Returns the number of leading binary zeros in `x`. +pub fn usize_leading_zeros_riscv(x: usize) -> usize { + let mut x = x; + // the number of potential leading zeros + let mut z = usize::MAX.count_ones() as usize; + // a temporary + let mut t: usize; + + // RISC-V does not have a set-if-greater-than-or-equal instruction and + // `(x >= power-of-two) as usize` will get compiled into two instructions, but this is + // still the most optimal method. A conditional set can only be turned into a single + // immediate instruction if `x` is compared with an immediate `imm` (that can fit into + // 12 bits) like `x < imm` but not `imm < x` (because the immediate is always on the + // right). If we try to save an instruction by using `x < imm` for each bisection, we + // have to shift `x` left and compare with powers of two approaching `usize::MAX + 1`, + // but the immediate will never fit into 12 bits and never save an instruction. + #[cfg(target_pointer_width = "64")] + { + // If the upper 32 bits of `x` are not all 0, `t` is set to `1 << 5`, otherwise + // `t` is set to 0. + t = ((x >= (1 << 32)) as usize) << 5; + // If `t` was set to `1 << 5`, then the upper 32 bits are shifted down for the + // next step to process. + x >>= t; + // If `t` was set to `1 << 5`, then we subtract 32 from the number of potential + // leading zeros + z -= t; + } + #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] + { + t = ((x >= (1 << 16)) as usize) << 4; + x >>= t; + z -= t; + } + t = ((x >= (1 << 8)) as usize) << 3; + x >>= t; + z -= t; + t = ((x >= (1 << 4)) as usize) << 2; + x >>= t; + z -= t; + t = ((x >= (1 << 2)) as usize) << 1; + x >>= t; + z -= t; + t = (x >= (1 << 1)) as usize; + x >>= t; + z -= t; + // All bits except the LSB are guaranteed to be zero for this final bisection step. + // If `x != 0` then `x == 1` and subtracts one potential zero from `z`. + z - x +} + +intrinsics! { + #[maybe_use_optimized_c_shim] + #[cfg(any( + target_pointer_width = "16", + target_pointer_width = "32", + target_pointer_width = "64" + ))] + /// Returns the number of leading binary zeros in `x`. + pub extern "C" fn __clzsi2(x: usize) -> usize { + if cfg!(any(target_arch = "riscv32", target_arch = "riscv64")) { + usize_leading_zeros_riscv(x) + } else { + usize_leading_zeros_default(x) + } + } +} diff --git a/vendor/compiler_builtins/src/int/mod.rs b/vendor/compiler_builtins/src/int/mod.rs index d73bf6db99..8a469d9014 100644 --- a/vendor/compiler_builtins/src/int/mod.rs +++ b/vendor/compiler_builtins/src/int/mod.rs @@ -13,11 +13,14 @@ macro_rules! os_ty { } pub mod addsub; +pub mod leading_zeros; pub mod mul; pub mod sdiv; pub mod shift; pub mod udiv; +pub use self::leading_zeros::__clzsi2; + /// Trait for some basic operations on integers pub(crate) trait Int: Copy @@ -300,69 +303,3 @@ macro_rules! impl_wide_int { impl_wide_int!(u32, u64, 32); impl_wide_int!(u64, u128, 64); - -intrinsics! { - #[maybe_use_optimized_c_shim] - #[cfg(any( - target_pointer_width = "16", - target_pointer_width = "32", - target_pointer_width = "64" - ))] - pub extern "C" fn __clzsi2(x: usize) -> usize { - // TODO: const this? Would require const-if - // Note(Lokathor): the `intrinsics!` macro can't process mut inputs - let mut x = x; - let mut y: usize; - let mut n: usize = { - #[cfg(target_pointer_width = "64")] - { - 64 - } - #[cfg(target_pointer_width = "32")] - { - 32 - } - #[cfg(target_pointer_width = "16")] - { - 16 - } - }; - #[cfg(target_pointer_width = "64")] - { - y = x >> 32; - if y != 0 { - n -= 32; - x = y; - } - } - #[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] - { - y = x >> 16; - if y != 0 { - n -= 16; - x = y; - } - } - y = x >> 8; - if y != 0 { - n -= 8; - x = y; - } - y = x >> 4; - if y != 0 { - n -= 4; - x = y; - } - y = x >> 2; - if y != 0 { - n -= 2; - x = y; - } - y = x >> 1; - if y != 0 { - n - 2 - } else { - n - x - } - } -} diff --git a/vendor/compiler_builtins/src/lib.rs b/vendor/compiler_builtins/src/lib.rs index db05af5de3..34397e0d25 100644 --- a/vendor/compiler_builtins/src/lib.rs +++ b/vendor/compiler_builtins/src/lib.rs @@ -15,7 +15,7 @@ // We use `u128` in a whole bunch of places which we currently agree with the // compiler on ABIs and such, so we should be "good enough" for now and changes // to the `u128` ABI will be reflected here. -#![allow(improper_ctypes)] +#![allow(improper_ctypes, improper_ctypes_definitions)] // We disable #[no_mangle] for tests so that we can verify the test results // against the native compiler-rt implementations of the builtins. diff --git a/vendor/cpuid-bool/.cargo-checksum.json b/vendor/cpuid-bool/.cargo-checksum.json new file mode 100644 index 0000000000..1903d4c1e5 --- /dev/null +++ b/vendor/cpuid-bool/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"e0cd09e38fffd25bdf238995b8a1855e3162b6a6609decfd07e18a7ac9f18ec0","Cargo.toml":"081493bc0588bd6edc77176138e21039312aae65dcd2a700f8d8b4368d6ae3ad","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"904801faf3f1850328af8e1aa1047b9190cc22ed40df5c87f2d93d17f847ef67","src/lib.rs":"e724effc564546e40616f5a64e722a3c81a5b4837f178b7a0e656c4b39e816c9"},"package":"8aebca1129a03dc6dc2b127edd729435bbc4a37e1d5f4d7513165089ceb02634"} \ No newline at end of file diff --git a/vendor/cpuid-bool/CHANGELOG.md b/vendor/cpuid-bool/CHANGELOG.md new file mode 100644 index 0000000000..961ba48c89 --- /dev/null +++ b/vendor/cpuid-bool/CHANGELOG.md @@ -0,0 +1,21 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.1.2 (2020-07-20) +### Added +- LICENSE files ([#70]) + +[#70]: https://github.com/RustCrypto/utils/pull/70 + +## 0.1.1 (2020-07-14) +### Fixed +- SGX target support ([#68]) + +[#68]: https://github.com/RustCrypto/utils/pull/68 + +## 0.1.0 (2020-06-11) +- Initial release \ No newline at end of file diff --git a/vendor/cpuid-bool/Cargo.toml b/vendor/cpuid-bool/Cargo.toml new file mode 100644 index 0000000000..b7b7e07d48 --- /dev/null +++ b/vendor/cpuid-bool/Cargo.toml @@ -0,0 +1,23 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "cpuid-bool" +version = "0.1.2" +authors = ["RustCrypto Developers"] +description = "A lightweight no-std compatible alternative to is_x86_feature_detected" +documentation = "https://docs.rs/cpuid-bool" +keywords = ["cpuid", "target-feature"] +categories = ["no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/utils" diff --git a/vendor/cpuid-bool/LICENSE-APACHE b/vendor/cpuid-bool/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/cpuid-bool/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/cpuid-bool/LICENSE-MIT b/vendor/cpuid-bool/LICENSE-MIT new file mode 100644 index 0000000000..2726e14a40 --- /dev/null +++ b/vendor/cpuid-bool/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2020 The RustCrypto Project Developers + +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 --git a/vendor/cpuid-bool/src/lib.rs b/vendor/cpuid-bool/src/lib.rs new file mode 100644 index 0000000000..557539a75b --- /dev/null +++ b/vendor/cpuid-bool/src/lib.rs @@ -0,0 +1,121 @@ +//! Macro for checking CPU capabilities at runtime. +//! +//! # Usage example +//! ``` +//! if cpuid_bool::cpuid_bool!("sha", "aes") { +//! println!("CPU supports both SHA and AES extensions"); +//! } else { +//! println!("SHA and AES extensions are not supported"); +//! } +//! ``` +//! Note that if all tested target features are enabled via compiler options +//! (e.g. by using `RUSTFLAGS`), `cpuid_bool!` macro immideatly will expand +//! to `true` and will not use CPUID instruction. Such behavior allows +//! compiler to eliminate fallback code. +//! +//! After first call macro caches result and returns it in subsequent +//! calls, thus runtime overhead for them is minimal. +#![no_std] +#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))] +compile_error!("This crate works only on x86 and x86-64 targets."); + +use core::sync::atomic::{AtomicU8, Ordering::Relaxed}; + +/// This structure represents a lazily initialized static boolean value. +/// +/// Useful when it is preferable to just rerun initialization instead of +/// locking. Used internally by the `cpuid_bool` macro. +pub struct LazyBool(AtomicU8); + +impl LazyBool { + const UNINIT: u8 = u8::max_value(); + + pub const fn new() -> Self { + Self(AtomicU8::new(Self::UNINIT)) + } + + // Runs the init() function at least once, returning the value of some run + // of init(). Multiple callers can run their init() functions in parallel. + // init() should always return the same value, if it succeeds. + pub fn unsync_init(&self, init: impl FnOnce() -> bool) -> bool { + // Relaxed ordering is fine, as we only have a single atomic variable. + let mut val = self.0.load(Relaxed); + if val == Self::UNINIT { + val = init() as u8; + self.0.store(val as u8, Relaxed); + } + val != 0 + } +} + +// TODO: find how to define private macro usable inside a public one +macro_rules! expand_check_macro { + ($(($name:tt, $i:expr, $reg:ident, $offset:expr)),* $(,)?) => { + #[macro_export] + #[doc(hidden)] + macro_rules! check { + $( + ($cr:expr, $name) => { ($cr[$i].$reg & (1 << $offset) != 0) }; + )* + } + }; +} + +expand_check_macro! { + ("mmx", 0, edx, 23), + ("sse", 0, edx, 25), + ("sse2", 0, edx, 26), + ("sse3", 0, ecx, 0), + ("pclmulqdq", 0, ecx, 1), + ("ssse3", 0, ecx, 9), + ("fma", 0, ecx, 12), + ("sse4.1", 0, ecx, 19), + ("sse4.2", 0, ecx, 20), + ("popcnt", 0, ecx, 23), + ("aes", 0, ecx, 25), + ("avx", 0, ecx, 28), + ("rdrand", 0, ecx, 30), + ("sgx", 1, ebx, 2), + ("bmi1", 1, ebx, 3), + ("avx2", 1, ebx, 5), + ("bmi2", 1, ebx, 8), + ("rdseed", 1, ebx, 18), + ("adx", 1, ebx, 19), + ("sha", 1, ebx, 29), +} + +/// Check at runtime if CPU supports sequence of target features. +/// +/// During first execution this macro will use CPUID to check requested +/// target features, results will be cached and further calls will return +/// it instead. +#[macro_export] +macro_rules! cpuid_bool { + ($($tf:tt),+ $(,)? ) => {{ + // CPUID is not available on SGX targets + #[cfg(all(not(target_env = "sgx"), not(all($(target_feature=$tf, )*))))] + let res = { + #[cfg(target_arch = "x86")] + use core::arch::x86::{__cpuid, __cpuid_count}; + #[cfg(target_arch = "x86_64")] + use core::arch::x86_64::{__cpuid, __cpuid_count}; + + static CPUID_BOOL: cpuid_bool::LazyBool = cpuid_bool::LazyBool::new(); + CPUID_BOOL.unsync_init(|| { + #[allow(unused_variables)] + let cr = unsafe { + [__cpuid(1), __cpuid_count(7, 0)] + }; + // TODO: find how to remove `true` + $(cpuid_bool::check!(cr, $tf) & )+ true + }) + }; + + #[cfg(all(target_env = "sgx", not(all($(target_feature=$tf, )*))))] + let res = false; + #[cfg(all($(target_feature=$tf, )*))] + let res = true; + + res + }}; +} diff --git a/vendor/crossbeam-channel/.cargo-checksum.json b/vendor/crossbeam-channel/.cargo-checksum.json new file mode 100644 index 0000000000..61a680a18a --- /dev/null +++ b/vendor/crossbeam-channel/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"d55a5f1a75b60fbbd53a5b1432f19b8fa7e2bb822e1cc93ec956e542e7e8b3cd","Cargo.lock":"dcb3de08ddba81cf97f49253b63b8eb4f386338c0db8d4b77ae943fc138bfe69","Cargo.toml":"c20147fdaf2d6e99fe30c9f639fc0339f6af18994c2756cba1c869cd8e198bc0","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"924a49392dc8304def57586be4ebd69aaf51e16fd245b55b4b69ad2cce6b715a","README.md":"7967172d90f7ebc20531d76c5a2bad7be8d81670fbc64abc33be4315d1430757","benches/crossbeam.rs":"baef02dffd58ee4d84d33a4e999254e81fcf45241623cfa6c4b1ef73dbd7479d","examples/fibonacci.rs":"8755bcb9cf05e391d8679fbb51db40ed9692703c3b66341cd1c1e4cca2068874","examples/matching.rs":"a1bdd7d211cf8612d649de3de3e24f56e911bc8d5e95b86b06f412314f9edd6c","examples/stopwatch.rs":"4e90ce134475859a421da0a095baea52a575b03e41fb8fb50cf47446f422ee6e","src/channel.rs":"4483ddf38c4b9b308b81dd156653ccb590524aae1e5ff8efcab6b8f44a8d3dfc","src/context.rs":"48eb848538482aeadd5bafb8fd24695dcf5635243d6f9d3b059a22538ce67014","src/counter.rs":"8b6d4d69db59bc992ddc7ed33f709788c3fab482521bb1adf985f77499506c09","src/err.rs":"80c47848fbfeeabaa83ea49c0928274cd4ae0ced7ebf214a075322fe301f3fa6","src/flavors/after.rs":"4f761618efe21036145e44f01506bdfbc2524879368ac138600e0feed921a6a7","src/flavors/array.rs":"606e27d3376c3cee128656b3690bd429964a22e3078886b6b7bf10cfa072fabb","src/flavors/list.rs":"0e2bf126b07ba8c2ef5db881043a3987b5f91013d47ae2da147a1c61a033c320","src/flavors/mod.rs":"a5af9b6105207e293c0d64928b4486fb1da9bfe0318354c66c8b5069e41ec31f","src/flavors/never.rs":"86e21b4d8b154e5d795cf72c7203a1d16a846c4d670095c8b592c12569f35a98","src/flavors/tick.rs":"d80858e0d5d1d7ec3886fb607e49bbc9577d64dc7c7304c5d3e6c8629a065476","src/flavors/zero.rs":"a24c2fb547586ab4bf2a09efb8af5264274f7b373749cd259a7dd3c843c8aac5","src/lib.rs":"1f0e6c4fb470dfe2fbdda90b7ac17f72c32fd62d41bccb4db9a756a88481fb44","src/select.rs":"f917459c033f8edbb45f377d6a4af24ffb583583d039182e72252d4af64a8807","src/select_macro.rs":"b1a3d2b9d4c64b48f6b176d2ff8b44c3d754f157ddbe830e8a1e86e4c100e0e9","src/utils.rs":"8b1184222df9047355e6044ad7e3fefd6065a5dda98b968cae45cca5f4b2fb5d","src/waker.rs":"345b551d467389a3a18dc22b351674dfbf288945b984450f607e644faa8a9731","tests/after.rs":"effb341c02f03a45ce09ab7862bc5b191191e0175997c494f988e6daca1ef8af","tests/array.rs":"35cd46fc7310f4206e3bbd81f900c18053a3a22943e221fbb81f9b89505fee46","tests/golang.rs":"9cb210ef2668428f7efb542ff4a8ab4e61f77dd4ff7e39720d63ad0797ff4ec1","tests/iter.rs":"b6df3f21273bb21dfecda47ffc0c296541214cde6bed876a31db5f2410839e83","tests/list.rs":"eb6cfc9a0f02c77df6d6d608fbbe1f82e09901e167b4b86993c49f9d6052a8ee","tests/mpsc.rs":"965e18abbfcdebec09380f8ec9bb62e5556ad2aa0176ed088ce091994c1d2500","tests/never.rs":"cd455a4c78403d9a96fe0f3a4e968164cca533cc85c96aaa4558987f9b088fcc","tests/ready.rs":"b91cebde45a6c46bd2cf16b1fc58b2ec258dcc960cb9f8eb5b4c39b1a144cadc","tests/same_channel.rs":"bd93f72e982f9881235848a4a2da67276feca810ed1e4d22e0e2bda8675cae4a","tests/select.rs":"57558f93834dc1ae1a56fe8d1211536e16015a74c8c7458c653852472c21ddcd","tests/select_macro.rs":"1cd5250d46d6d2e8c0a87ee9b1c0a5d80aac193c3eb0a86877249684e7aabd39","tests/thread_locals.rs":"845f8c8f1a37a14e4235fc9fc20d8b7288fd9fda307c075c0e61e6ab79b33921","tests/tick.rs":"dd4257f1f8de01477d542e20a816eede3b4e2e4dc6fcdf07d554220f0ef8a86f","tests/zero.rs":"088804df377904eca4a985d8f1703f98550e51304d6849bfce143fcd0b69c349"},"package":"b153fe7cbef478c567df0f972e02e6d736db11affe43dfc9c56a9374d1adfb87"} \ No newline at end of file diff --git a/vendor/crossbeam-channel/CHANGELOG.md b/vendor/crossbeam-channel/CHANGELOG.md new file mode 100644 index 0000000000..8c1c7fc42f --- /dev/null +++ b/vendor/crossbeam-channel/CHANGELOG.md @@ -0,0 +1,167 @@ +# Version 0.4.4 + +- Fix bug in release (yanking 0.4.3) +- Fix UB and breaking change introduced in 0.4.3 + +# Version 0.4.3 + +- Change license to "MIT OR Apache-2.0". + +# Version 0.4.2 + +- Fix bug in release (yanking 0.4.1) + +# Version 0.4.1 + +- Avoid time drift in `channel::tick`. (#456) +- Fix unsoundness issues by adopting `MaybeUninit`. (#458) + +# Version 0.4.0 + +- Bump the minimum required version to 1.28. +- Bump `crossbeam-utils` to `0.7`. + +# Version 0.3.9 + +- Fix a bug in reference counting. +- Optimize `recv_timeout()`. +- Add `Select::remove()`. +- Various small improvements, code cleanup, more tests. + +# Version 0.3.8 + +- Bump the minimum required version of `crossbeam-utils`. + +# Version 0.3.7 + +- Remove `parking_lot` and `rand` dependencies. +- Expand documentation. +- Implement `Default` for `Select`. +- Make `size_of::>()` smaller. +- Several minor optimizations. +- Add more tests. + +# Version 0.3.6 + +- Fix a bug in initialization of unbounded channels. + +# Version 0.3.5 + +- New implementation for unbounded channels. +- A number of small performance improvements. +- Remove `crossbeam-epoch` dependency. + +# Version 0.3.4 + +- Bump `crossbeam-epoch` to `0.7`. +- Improve documentation. + +# Version 0.3.3 + +- Relax the lifetime in `SelectedOperation<'_>`. +- Add `Select::try_ready()`, `Select::ready()`, and `Select::ready_timeout()`. +- Update licensing notices. +- Improve documentation. +- Add methods `is_disconnected()`, `is_timeout()`, `is_empty()`, and `is_full()` on error types. + +# Version 0.3.2 + +- More elaborate licensing notices. + +# Version 0.3.1 + +- Update `crossbeam-utils` to `0.6`. + +# Version 0.3.0 + +- Add a special `never` channel type. +- Dropping all receivers now closes the channel. +- The interface of sending and receiving methods is now very similar to those in v0.1. +- The syntax for `send` in `select!` is now `send(sender, msg) -> res => body`. +- The syntax for `recv` in `select!` is now `recv(receiver) -> res => body`. +- New, more efficient interface for `Select` without callbacks. +- Timeouts can be specified in `select!`. + +# Version 0.2.6 + +- `Select` struct that can add cases dynamically. +- More documentation (in particular, the FAQ section). +- Optimize contended sends/receives in unbounded channels. + +# Version 0.2.5 + +- Use `LocalKey::try_with` instead of `LocalKey::with`. +- Remove helper macros `__crossbeam_channel*`. + +# Version 0.2.4 + +- Make `select!` linearizable with other channel operations. +- Update `crossbeam-utils` to `0.5.0`. +- Update `parking_lot` to `0.6.3`. +- Remove Mac OS X tests. + +# Version 0.2.3 + +- Add Mac OS X tests. +- Lower some memory orderings. +- Eliminate calls to `mem::unitialized`, which caused bugs with ZST. + +# Version 0.2.2 + +- Add more tests. +- Update `crossbeam-epoch` to 0.5.0 +- Initialize the RNG seed to a random value. +- Replace `libc::abort` with `std::process::abort`. +- Ignore clippy warnings in `select!`. +- Better interaction of `select!` with the NLL borrow checker. + +# Version 0.2.1 + +- Fix compilation errors when using `select!` with `#[deny(unsafe_code)]`. + +# Version 0.2.0 + +- Implement `IntoIterator` for `Receiver`. +- Add a new `select!` macro. +- Add special channels `after` and `tick`. +- Dropping receivers doesn't close the channel anymore. +- Change the signature of `recv`, `send`, and `try_recv`. +- Remove `Sender::is_closed` and `Receiver::is_closed`. +- Remove `Sender::close` and `Receiver::close`. +- Remove `Sender::send_timeout` and `Receiver::recv_timeout`. +- Remove `Sender::try_send`. +- Remove `Select` and `select_loop!`. +- Remove all error types. +- Remove `Iter`, `TryIter`, and `IntoIter`. +- Remove the `nightly` feature. +- Remove ordering operators for `Sender` and `Receiver`. + +# Version 0.1.3 + +- Add `Sender::disconnect` and `Receiver::disconnect`. +- Implement comparison operators for `Sender` and `Receiver`. +- Allow arbitrary patterns in place of `msg` in `recv(r, msg)`. +- Add a few conversion impls between error types. +- Add benchmarks for `atomicring` and `mpmc`. +- Add benchmarks for different message sizes. +- Documentation improvements. +- Update `crossbeam-epoch` to 0.4.0 +- Update `crossbeam-utils` to 0.3.0 +- Update `parking_lot` to 0.5 +- Update `rand` to 0.4 + +# Version 0.1.2 + +- Allow conditional cases in `select_loop!` macro. +- Fix typos in documentation. +- Fix deadlock in selection when all channels are disconnected and a timeout is specified. + +# Version 0.1.1 + +- Implement `Debug` for `Sender`, `Receiver`, `Iter`, `TryIter`, `IntoIter`, and `Select`. +- Implement `Default` for `Select`. + +# Version 0.1.0 + +- First implementation of the channels. +- Add `select_loop!` macro by @TimNN. diff --git a/vendor/crossbeam-channel/Cargo.lock b/vendor/crossbeam-channel/Cargo.lock new file mode 100644 index 0000000000..fe038cc011 --- /dev/null +++ b/vendor/crossbeam-channel/Cargo.lock @@ -0,0 +1,262 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "arc-swap" +version = "0.4.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4d25d88fd6b8041580a654f9d0c581a047baee2b3efee13275f2fc392fc75034" + +[[package]] +name = "autocfg" +version = "0.1.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cloudabi" +version = "0.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" +dependencies = [ + "bitflags", +] + +[[package]] +name = "crossbeam-channel" +version = "0.4.4" +dependencies = [ + "crossbeam-utils", + "maybe-uninit", + "num_cpus", + "rand", + "signal-hook", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +dependencies = [ + "autocfg 1.0.1", + "cfg-if", + "lazy_static", +] + +[[package]] +name = "fuchsia-cprng" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" + +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +dependencies = [ + "libc", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" + +[[package]] +name = "libc" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +dependencies = [ + "hermit-abi", + "libc", +] + +[[package]] +name = "rand" +version = "0.6.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" +dependencies = [ + "autocfg 0.1.7", + "libc", + "rand_chacha", + "rand_core 0.4.2", + "rand_hc", + "rand_isaac", + "rand_jitter", + "rand_os", + "rand_pcg", + "rand_xorshift", + "winapi", +] + +[[package]] +name = "rand_chacha" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.3.1", +] + +[[package]] +name = "rand_core" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" +dependencies = [ + "rand_core 0.4.2", +] + +[[package]] +name = "rand_core" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" + +[[package]] +name = "rand_hc" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_isaac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rand_jitter" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" +dependencies = [ + "libc", + "rand_core 0.4.2", + "winapi", +] + +[[package]] +name = "rand_os" +version = "0.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" +dependencies = [ + "cloudabi", + "fuchsia-cprng", + "libc", + "rand_core 0.4.2", + "rdrand", + "winapi", +] + +[[package]] +name = "rand_pcg" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" +dependencies = [ + "autocfg 0.1.7", + "rand_core 0.4.2", +] + +[[package]] +name = "rand_xorshift" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "rdrand" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" +dependencies = [ + "rand_core 0.3.1", +] + +[[package]] +name = "signal-hook" +version = "0.1.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "604508c1418b99dfe1925ca9224829bb2a8a9a04dda655cc01fcad46f4ab05ed" +dependencies = [ + "libc", + "signal-hook-registry", +] + +[[package]] +name = "signal-hook-registry" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a3e12110bc539e657a646068aaf5eb5b63af9d0c1f7b29c97113fad80e15f035" +dependencies = [ + "arc-swap", + "libc", +] + +[[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-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/crossbeam-queue/Cargo.toml b/vendor/crossbeam-channel/Cargo.toml similarity index 65% rename from vendor/crossbeam-queue/Cargo.toml rename to vendor/crossbeam-channel/Cargo.toml index c03e35b1dc..86f264b99b 100644 --- a/vendor/crossbeam-queue/Cargo.toml +++ b/vendor/crossbeam-channel/Cargo.toml @@ -11,30 +11,27 @@ # will likely look very different (and much more reasonable) [package] -name = "crossbeam-queue" -version = "0.2.3" +name = "crossbeam-channel" +version = "0.4.4" authors = ["The Crossbeam Project Developers"] -description = "Concurrent queues" -homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-utils" -documentation = "https://docs.rs/crossbeam-queue" +description = "Multi-producer multi-consumer channels for message passing" +homepage = "https://github.com/crossbeam-rs/crossbeam/tree/master/crossbeam-channel" +documentation = "https://docs.rs/crossbeam-channel" readme = "README.md" -keywords = ["queue", "mpmc", "lock-free", "producer", "consumer"] -categories = ["concurrency", "data-structures"] -license = "MIT/Apache-2.0 AND BSD-2-Clause" +keywords = ["channel", "mpmc", "select", "golang", "message"] +categories = ["algorithms", "concurrency", "data-structures"] +license = "MIT OR Apache-2.0" repository = "https://github.com/crossbeam-rs/crossbeam" -[dependencies.cfg-if] -version = "0.1.2" - [dependencies.crossbeam-utils] version = "0.7" -default-features = false [dependencies.maybe-uninit] version = "2.0.0" +[dev-dependencies.num_cpus] +version = "1.10.0" + [dev-dependencies.rand] version = "0.6" -[features] -alloc = ["crossbeam-utils/alloc"] -default = ["std"] -std = ["crossbeam-utils/std"] +[dev-dependencies.signal-hook] +version = "0.1.5" diff --git a/vendor/itertools-0.8.2/LICENSE-APACHE b/vendor/crossbeam-channel/LICENSE-APACHE similarity index 100% rename from vendor/itertools-0.8.2/LICENSE-APACHE rename to vendor/crossbeam-channel/LICENSE-APACHE diff --git a/vendor/crossbeam-queue/LICENSE-MIT b/vendor/crossbeam-channel/LICENSE-MIT similarity index 100% rename from vendor/crossbeam-queue/LICENSE-MIT rename to vendor/crossbeam-channel/LICENSE-MIT diff --git a/vendor/crossbeam-channel/LICENSE-THIRD-PARTY b/vendor/crossbeam-channel/LICENSE-THIRD-PARTY new file mode 100644 index 0000000000..d15e32bc71 --- /dev/null +++ b/vendor/crossbeam-channel/LICENSE-THIRD-PARTY @@ -0,0 +1,625 @@ +=============================================================================== + +Bounded MPMC queue +http://www.1024cores.net/home/code-license + +Copyright (c) 2010-2011 Dmitry Vyukov. +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +1. Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. +2. Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED +WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF +MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO +EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, +INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF +LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE +OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF +ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +The views and conclusions contained in the software and documentation are those +of the authors and should not be interpreted as representing official policies, +either expressed or implied, of Dmitry Vyukov. + +=============================================================================== + +matching.go +https://creativecommons.org/licenses/by/3.0/legalcode + +Creative Commons Legal Code + +Attribution 3.0 Unported + + CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE + LEGAL SERVICES. DISTRIBUTION OF THIS LICENSE DOES NOT CREATE AN + ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS + INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES + REGARDING THE INFORMATION PROVIDED, AND DISCLAIMS LIABILITY FOR + DAMAGES RESULTING FROM ITS USE. + +License + +THE WORK (AS DEFINED BELOW) IS PROVIDED UNDER THE TERMS OF THIS CREATIVE +COMMONS PUBLIC LICENSE ("CCPL" OR "LICENSE"). THE WORK IS PROTECTED BY +COPYRIGHT AND/OR OTHER APPLICABLE LAW. ANY USE OF THE WORK OTHER THAN AS +AUTHORIZED UNDER THIS LICENSE OR COPYRIGHT LAW IS PROHIBITED. + +BY EXERCISING ANY RIGHTS TO THE WORK PROVIDED HERE, YOU ACCEPT AND AGREE +TO BE BOUND BY THE TERMS OF THIS LICENSE. TO THE EXTENT THIS LICENSE MAY +BE CONSIDERED TO BE A CONTRACT, THE LICENSOR GRANTS YOU THE RIGHTS +CONTAINED HERE IN CONSIDERATION OF YOUR ACCEPTANCE OF SUCH TERMS AND +CONDITIONS. + +1. Definitions + + a. "Adaptation" means a work based upon the Work, or upon the Work and + other pre-existing works, such as a translation, adaptation, + derivative work, arrangement of music or other alterations of a + literary or artistic work, or phonogram or performance and includes + cinematographic adaptations or any other form in which the Work may be + recast, transformed, or adapted including in any form recognizably + derived from the original, except that a work that constitutes a + Collection will not be considered an Adaptation for the purpose of + this License. For the avoidance of doubt, where the Work is a musical + work, performance or phonogram, the synchronization of the Work in + timed-relation with a moving image ("synching") will be considered an + Adaptation for the purpose of this License. + b. "Collection" means a collection of literary or artistic works, such as + encyclopedias and anthologies, or performances, phonograms or + broadcasts, or other works or subject matter other than works listed + in Section 1(f) below, which, by reason of the selection and + arrangement of their contents, constitute intellectual creations, in + which the Work is included in its entirety in unmodified form along + with one or more other contributions, each constituting separate and + independent works in themselves, which together are assembled into a + collective whole. A work that constitutes a Collection will not be + considered an Adaptation (as defined above) for the purposes of this + License. + c. "Distribute" means to make available to the public the original and + copies of the Work or Adaptation, as appropriate, through sale or + other transfer of ownership. + d. "Licensor" means the individual, individuals, entity or entities that + offer(s) the Work under the terms of this License. + e. "Original Author" means, in the case of a literary or artistic work, + the individual, individuals, entity or entities who created the Work + or if no individual or entity can be identified, the publisher; and in + addition (i) in the case of a performance the actors, singers, + musicians, dancers, and other persons who act, sing, deliver, declaim, + play in, interpret or otherwise perform literary or artistic works or + expressions of folklore; (ii) in the case of a phonogram the producer + being the person or legal entity who first fixes the sounds of a + performance or other sounds; and, (iii) in the case of broadcasts, the + organization that transmits the broadcast. + f. "Work" means the literary and/or artistic work offered under the terms + of this License including without limitation any production in the + literary, scientific and artistic domain, whatever may be the mode or + form of its expression including digital form, such as a book, + pamphlet and other writing; a lecture, address, sermon or other work + of the same nature; a dramatic or dramatico-musical work; a + choreographic work or entertainment in dumb show; a musical + composition with or without words; a cinematographic work to which are + assimilated works expressed by a process analogous to cinematography; + a work of drawing, painting, architecture, sculpture, engraving or + lithography; a photographic work to which are assimilated works + expressed by a process analogous to photography; a work of applied + art; an illustration, map, plan, sketch or three-dimensional work + relative to geography, topography, architecture or science; a + performance; a broadcast; a phonogram; a compilation of data to the + extent it is protected as a copyrightable work; or a work performed by + a variety or circus performer to the extent it is not otherwise + considered a literary or artistic work. + g. "You" means an individual or entity exercising rights under this + License who has not previously violated the terms of this License with + respect to the Work, or who has received express permission from the + Licensor to exercise rights under this License despite a previous + violation. + h. "Publicly Perform" means to perform public recitations of the Work and + to communicate to the public those public recitations, by any means or + process, including by wire or wireless means or public digital + performances; to make available to the public Works in such a way that + members of the public may access these Works from a place and at a + place individually chosen by them; to perform the Work to the public + by any means or process and the communication to the public of the + performances of the Work, including by public digital performance; to + broadcast and rebroadcast the Work by any means including signs, + sounds or images. + i. "Reproduce" means to make copies of the Work by any means including + without limitation by sound or visual recordings and the right of + fixation and reproducing fixations of the Work, including storage of a + protected performance or phonogram in digital form or other electronic + medium. + +2. Fair Dealing Rights. Nothing in this License is intended to reduce, +limit, or restrict any uses free from copyright or rights arising from +limitations or exceptions that are provided for in connection with the +copyright protection under copyright law or other applicable laws. + +3. License Grant. Subject to the terms and conditions of this License, +Licensor hereby grants You a worldwide, royalty-free, non-exclusive, +perpetual (for the duration of the applicable copyright) license to +exercise the rights in the Work as stated below: + + a. to Reproduce the Work, to incorporate the Work into one or more + Collections, and to Reproduce the Work as incorporated in the + Collections; + b. to create and Reproduce Adaptations provided that any such Adaptation, + including any translation in any medium, takes reasonable steps to + clearly label, demarcate or otherwise identify that changes were made + to the original Work. For example, a translation could be marked "The + original work was translated from English to Spanish," or a + modification could indicate "The original work has been modified."; + c. to Distribute and Publicly Perform the Work including as incorporated + in Collections; and, + d. to Distribute and Publicly Perform Adaptations. + e. For the avoidance of doubt: + + i. Non-waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme cannot be waived, the Licensor + reserves the exclusive right to collect such royalties for any + exercise by You of the rights granted under this License; + ii. Waivable Compulsory License Schemes. In those jurisdictions in + which the right to collect royalties through any statutory or + compulsory licensing scheme can be waived, the Licensor waives the + exclusive right to collect such royalties for any exercise by You + of the rights granted under this License; and, + iii. Voluntary License Schemes. The Licensor waives the right to + collect royalties, whether individually or, in the event that the + Licensor is a member of a collecting society that administers + voluntary licensing schemes, via that society, from any exercise + by You of the rights granted under this License. + +The above rights may be exercised in all media and formats whether now +known or hereafter devised. The above rights include the right to make +such modifications as are technically necessary to exercise the rights in +other media and formats. Subject to Section 8(f), all rights not expressly +granted by Licensor are hereby reserved. + +4. Restrictions. The license granted in Section 3 above is expressly made +subject to and limited by the following restrictions: + + a. You may Distribute or Publicly Perform the Work only under the terms + of this License. You must include a copy of, or the Uniform Resource + Identifier (URI) for, this License with every copy of the Work You + Distribute or Publicly Perform. You may not offer or impose any terms + on the Work that restrict the terms of this License or the ability of + the recipient of the Work to exercise the rights granted to that + recipient under the terms of the License. You may not sublicense the + Work. You must keep intact all notices that refer to this License and + to the disclaimer of warranties with every copy of the Work You + Distribute or Publicly Perform. When You Distribute or Publicly + Perform the Work, You may not impose any effective technological + measures on the Work that restrict the ability of a recipient of the + Work from You to exercise the rights granted to that recipient under + the terms of the License. This Section 4(a) applies to the Work as + incorporated in a Collection, but this does not require the Collection + apart from the Work itself to be made subject to the terms of this + License. If You create a Collection, upon notice from any Licensor You + must, to the extent practicable, remove from the Collection any credit + as required by Section 4(b), as requested. If You create an + Adaptation, upon notice from any Licensor You must, to the extent + practicable, remove from the Adaptation any credit as required by + Section 4(b), as requested. + b. If You Distribute, or Publicly Perform the Work or any Adaptations or + Collections, You must, unless a request has been made pursuant to + Section 4(a), keep intact all copyright notices for the Work and + provide, reasonable to the medium or means You are utilizing: (i) the + name of the Original Author (or pseudonym, if applicable) if supplied, + and/or if the Original Author and/or Licensor designate another party + or parties (e.g., a sponsor institute, publishing entity, journal) for + attribution ("Attribution Parties") in Licensor's copyright notice, + terms of service or by other reasonable means, the name of such party + or parties; (ii) the title of the Work if supplied; (iii) to the + extent reasonably practicable, the URI, if any, that Licensor + specifies to be associated with the Work, unless such URI does not + refer to the copyright notice or licensing information for the Work; + and (iv) , consistent with Section 3(b), in the case of an Adaptation, + a credit identifying the use of the Work in the Adaptation (e.g., + "French translation of the Work by Original Author," or "Screenplay + based on original Work by Original Author"). The credit required by + this Section 4 (b) may be implemented in any reasonable manner; + provided, however, that in the case of a Adaptation or Collection, at + a minimum such credit will appear, if a credit for all contributing + authors of the Adaptation or Collection appears, then as part of these + credits and in a manner at least as prominent as the credits for the + other contributing authors. For the avoidance of doubt, You may only + use the credit required by this Section for the purpose of attribution + in the manner set out above and, by exercising Your rights under this + License, You may not implicitly or explicitly assert or imply any + connection with, sponsorship or endorsement by the Original Author, + Licensor and/or Attribution Parties, as appropriate, of You or Your + use of the Work, without the separate, express prior written + permission of the Original Author, Licensor and/or Attribution + Parties. + c. Except as otherwise agreed in writing by the Licensor or as may be + otherwise permitted by applicable law, if You Reproduce, Distribute or + Publicly Perform the Work either by itself or as part of any + Adaptations or Collections, You must not distort, mutilate, modify or + take other derogatory action in relation to the Work which would be + prejudicial to the Original Author's honor or reputation. Licensor + agrees that in those jurisdictions (e.g. Japan), in which any exercise + of the right granted in Section 3(b) of this License (the right to + make Adaptations) would be deemed to be a distortion, mutilation, + modification or other derogatory action prejudicial to the Original + Author's honor and reputation, the Licensor will waive or not assert, + as appropriate, this Section, to the fullest extent permitted by the + applicable national law, to enable You to reasonably exercise Your + right under Section 3(b) of this License (right to make Adaptations) + but not otherwise. + +5. Representations, Warranties and Disclaimer + +UNLESS OTHERWISE MUTUALLY AGREED TO BY THE PARTIES IN WRITING, LICENSOR +OFFERS THE WORK AS-IS AND MAKES NO REPRESENTATIONS OR WARRANTIES OF ANY +KIND CONCERNING THE WORK, EXPRESS, IMPLIED, STATUTORY OR OTHERWISE, +INCLUDING, WITHOUT LIMITATION, WARRANTIES OF TITLE, MERCHANTIBILITY, +FITNESS FOR A PARTICULAR PURPOSE, NONINFRINGEMENT, OR THE ABSENCE OF +LATENT OR OTHER DEFECTS, ACCURACY, OR THE PRESENCE OF ABSENCE OF ERRORS, +WHETHER OR NOT DISCOVERABLE. SOME JURISDICTIONS DO NOT ALLOW THE EXCLUSION +OF IMPLIED WARRANTIES, SO SUCH EXCLUSION MAY NOT APPLY TO YOU. + +6. Limitation on Liability. EXCEPT TO THE EXTENT REQUIRED BY APPLICABLE +LAW, IN NO EVENT WILL LICENSOR BE LIABLE TO YOU ON ANY LEGAL THEORY FOR +ANY SPECIAL, INCIDENTAL, CONSEQUENTIAL, PUNITIVE OR EXEMPLARY DAMAGES +ARISING OUT OF THIS LICENSE OR THE USE OF THE WORK, EVEN IF LICENSOR HAS +BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +7. Termination + + a. This License and the rights granted hereunder will terminate + automatically upon any breach by You of the terms of this License. + Individuals or entities who have received Adaptations or Collections + from You under this License, however, will not have their licenses + terminated provided such individuals or entities remain in full + compliance with those licenses. Sections 1, 2, 5, 6, 7, and 8 will + survive any termination of this License. + b. Subject to the above terms and conditions, the license granted here is + perpetual (for the duration of the applicable copyright in the Work). + Notwithstanding the above, Licensor reserves the right to release the + Work under different license terms or to stop distributing the Work at + any time; provided, however that any such election will not serve to + withdraw this License (or any other license that has been, or is + required to be, granted under the terms of this License), and this + License will continue in full force and effect unless terminated as + stated above. + +8. Miscellaneous + + a. Each time You Distribute or Publicly Perform the Work or a Collection, + the Licensor offers to the recipient a license to the Work on the same + terms and conditions as the license granted to You under this License. + b. Each time You Distribute or Publicly Perform an Adaptation, Licensor + offers to the recipient a license to the original Work on the same + terms and conditions as the license granted to You under this License. + c. If any provision of this License is invalid or unenforceable under + applicable law, it shall not affect the validity or enforceability of + the remainder of the terms of this License, and without further action + by the parties to this agreement, such provision shall be reformed to + the minimum extent necessary to make such provision valid and + enforceable. + d. No term or provision of this License shall be deemed waived and no + breach consented to unless such waiver or consent shall be in writing + and signed by the party to be charged with such waiver or consent. + e. This License constitutes the entire agreement between the parties with + respect to the Work licensed here. There are no understandings, + agreements or representations with respect to the Work not specified + here. Licensor shall not be bound by any additional provisions that + may appear in any communication from You. This License may not be + modified without the mutual written agreement of the Licensor and You. + f. The rights granted under, and the subject matter referenced, in this + License were drafted utilizing the terminology of the Berne Convention + for the Protection of Literary and Artistic Works (as amended on + September 28, 1979), the Rome Convention of 1961, the WIPO Copyright + Treaty of 1996, the WIPO Performances and Phonograms Treaty of 1996 + and the Universal Copyright Convention (as revised on July 24, 1971). + These rights and subject matter take effect in the relevant + jurisdiction in which the License terms are sought to be enforced + according to the corresponding provisions of the implementation of + those treaty provisions in the applicable national law. If the + standard suite of rights granted under applicable copyright law + includes additional rights not granted under this License, such + additional rights are deemed to be included in the License; this + License is not intended to restrict the license of any rights under + applicable law. + + +Creative Commons Notice + + Creative Commons is not a party to this License, and makes no warranty + whatsoever in connection with the Work. Creative Commons will not be + liable to You or any party on any legal theory for any damages + whatsoever, including without limitation any general, special, + incidental or consequential damages arising in connection to this + license. Notwithstanding the foregoing two (2) sentences, if Creative + Commons has expressly identified itself as the Licensor hereunder, it + shall have all rights and obligations of Licensor. + + Except for the limited purpose of indicating to the public that the + Work is licensed under the CCPL, Creative Commons does not authorize + the use by either party of the trademark "Creative Commons" or any + related trademark or logo of Creative Commons without the prior + written consent of Creative Commons. Any permitted use will be in + compliance with Creative Commons' then-current trademark usage + guidelines, as may be published on its website or otherwise made + available upon request from time to time. For the avoidance of doubt, + this trademark restriction does not form part of this License. + + Creative Commons may be contacted at https://creativecommons.org/. + +=============================================================================== + +The Go Programming Language +https://golang.org/LICENSE + +Copyright (c) 2009 The Go Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of Google Inc. nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +=============================================================================== + +The Rust Programming Language +https://github.com/rust-lang/rust/blob/master/LICENSE-MIT + +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. + +=============================================================================== + +The Rust Programming Language +https://github.com/rust-lang/rust/blob/master/LICENSE-APACHE + + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/crossbeam-channel/README.md b/vendor/crossbeam-channel/README.md new file mode 100644 index 0000000000..be2e0b8f32 --- /dev/null +++ b/vendor/crossbeam-channel/README.md @@ -0,0 +1,93 @@ +# Crossbeam Channel + +[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam.svg?branch=master)]( +https://travis-ci.org/crossbeam-rs/crossbeam) +[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( +https://github.com/crossbeam-rs/crossbeam-channel) +[![Cargo](https://img.shields.io/crates/v/crossbeam-channel.svg)]( +https://crates.io/crates/crossbeam-channel) +[![Documentation](https://docs.rs/crossbeam-channel/badge.svg)]( +https://docs.rs/crossbeam-channel) +[![Rust 1.28+](https://img.shields.io/badge/rust-1.28+-lightgray.svg)]( +https://www.rust-lang.org) +[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) + +This crate provides multi-producer multi-consumer channels for message passing. +It is an alternative to [`std::sync::mpsc`] with more features and better performance. + +Some highlights: + +* [`Sender`]s and [`Receiver`]s can be cloned and shared among threads. +* Two main kinds of channels are [`bounded`] and [`unbounded`]. +* Convenient extra channels like [`after`], [`never`], and [`tick`]. +* The [`select!`] macro can block on multiple channel operations. +* [`Select`] can select over a dynamically built list of channel operations. +* Channels use locks very sparingly for maximum [performance](benchmarks). + +[`std::sync::mpsc`]: https://doc.rust-lang.org/std/sync/mpsc/index.html +[`Sender`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Sender.html +[`Receiver`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Receiver.html +[`bounded`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.bounded.html +[`unbounded`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.unbounded.html +[`after`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.after.html +[`never`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.never.html +[`tick`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/fn.tick.html +[`select!`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/macro.select.html +[`Select`]: https://docs.rs/crossbeam-channel/*/crossbeam_channel/struct.Select.html + +## Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +crossbeam-channel = "0.4" +``` + +Next, add this to your crate: + +```rust +#[macro_use] +extern crate crossbeam_channel; +``` + +## Compatibility + +The minimum supported Rust version is 1.28. Any change to this is considered a breaking change. + +## License + +Licensed under either of + + * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +#### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +#### Third party software + +This product includes copies and modifications of software developed by third parties: + +* [examples/matching.rs](examples/matching.rs) includes + [matching.go](http://www.nada.kth.se/~snilsson/concurrency/src/matching.go) by Stefan Nilsson, + licensed under Creative Commons Attribution 3.0 Unported License. + +* [src/flavors/array.rs](src/flavors/array.rs) is based on + [Bounded MPMC queue](http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) + by Dmitry Vyukov, licensed under the Simplified BSD License and the Apache License, Version 2.0. + +* [tests/mpsc.rs](tests/mpsc.rs) includes modifications of code from The Rust Programming Language, + licensed under the MIT License and the Apache License, Version 2.0. + +* [tests/golang.rs](tests/golang.rs) is based on code from The Go Programming Language, licensed + under the 3-Clause BSD License. + +See the source code files for more details. + +Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY). diff --git a/vendor/crossbeam-channel/benches/crossbeam.rs b/vendor/crossbeam-channel/benches/crossbeam.rs new file mode 100644 index 0000000000..4dd956b12c --- /dev/null +++ b/vendor/crossbeam-channel/benches/crossbeam.rs @@ -0,0 +1,715 @@ +#![feature(test)] + +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate num_cpus; +extern crate test; + +use crossbeam_channel::{bounded, unbounded}; +use crossbeam_utils::thread::scope; +use test::Bencher; + +const TOTAL_STEPS: usize = 40_000; + +mod unbounded { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| unbounded::()); + } + + #[bench] + fn oneshot(b: &mut Bencher) { + b.iter(|| { + let (s, r) = unbounded::(); + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn inout(b: &mut Bencher) { + let (s, r) = unbounded::(); + b.iter(|| { + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn par_inout(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = unbounded::(); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_n { + use super::*; + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(steps); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn par_inout(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + assert_eq!(threads % 2, 0); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(steps * threads); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_1 { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| bounded::(1)); + } + + #[bench] + fn oneshot(b: &mut Bencher) { + b.iter(|| { + let (s, r) = bounded::(1); + s.send(0).unwrap(); + r.recv().unwrap(); + }); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(1); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} + +mod bounded_0 { + use super::*; + + #[bench] + fn create(b: &mut Bencher) { + b.iter(|| bounded::(0)); + } + + #[bench] + fn spsc(b: &mut Bencher) { + let steps = TOTAL_STEPS; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + + b.iter(|| { + s1.send(()).unwrap(); + for _ in 0..steps { + r.recv().unwrap(); + } + r2.recv().unwrap(); + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn spmc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for i in 0..steps * threads { + s.send(i as i32).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpsc(b: &mut Bencher) { + let threads = num_cpus::get() - 1; + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..steps * threads { + r.recv().unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } + + #[bench] + fn mpmc(b: &mut Bencher) { + let threads = num_cpus::get(); + let steps = TOTAL_STEPS / threads; + let (s, r) = bounded::(0); + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + scope(|scope| { + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for i in 0..steps { + s.send(i as i32).unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + for _ in 0..threads / 2 { + scope.spawn(|_| { + while r1.recv().is_ok() { + for _ in 0..steps { + r.recv().unwrap(); + } + s2.send(()).unwrap(); + } + }); + } + + b.iter(|| { + for _ in 0..threads { + s1.send(()).unwrap(); + } + for _ in 0..threads { + r2.recv().unwrap(); + } + }); + drop(s1); + }) + .unwrap(); + } +} diff --git a/vendor/crossbeam-channel/examples/fibonacci.rs b/vendor/crossbeam-channel/examples/fibonacci.rs new file mode 100644 index 0000000000..499887a052 --- /dev/null +++ b/vendor/crossbeam-channel/examples/fibonacci.rs @@ -0,0 +1,27 @@ +//! An asynchronous fibonacci sequence generator. + +extern crate crossbeam_channel; + +use std::thread; + +use crossbeam_channel::{bounded, Sender}; + +// Sends the Fibonacci sequence into the channel until it becomes disconnected. +fn fibonacci(sender: Sender) { + let (mut x, mut y) = (0, 1); + while sender.send(x).is_ok() { + let tmp = x; + x = y; + y = tmp + y; + } +} + +fn main() { + let (s, r) = bounded(0); + thread::spawn(|| fibonacci(s)); + + // Print the first 20 Fibonacci numbers. + for num in r.iter().take(20) { + println!("{}", num); + } +} diff --git a/vendor/crossbeam-channel/examples/matching.rs b/vendor/crossbeam-channel/examples/matching.rs new file mode 100644 index 0000000000..4b157ff56c --- /dev/null +++ b/vendor/crossbeam-channel/examples/matching.rs @@ -0,0 +1,76 @@ +//! Using `select!` to send and receive on the same channel at the same time. +//! +//! This example is based on the following program in Go. +//! +//! Source: +//! - https://web.archive.org/web/20171209034309/https://www.nada.kth.se/~snilsson/concurrency +//! - http://www.nada.kth.se/~snilsson/concurrency/src/matching.go +//! +//! Copyright & License: +//! - Stefan Nilsson +//! - Creative Commons Attribution 3.0 Unported License +//! - https://creativecommons.org/licenses/by/3.0/ +//! +//! ```go +//! func main() { +//! people := []string{"Anna", "Bob", "Cody", "Dave", "Eva"} +//! match := make(chan string, 1) // Make room for one unmatched send. +//! wg := new(sync.WaitGroup) +//! for _, name := range people { +//! wg.Add(1) +//! go Seek(name, match, wg) +//! } +//! wg.Wait() +//! select { +//! case name := <-match: +//! fmt.Printf("No one received %s’s message.\n", name) +//! default: +//! // There was no pending send operation. +//! } +//! } +//! +//! // Seek either sends or receives, whichever possible, a name on the match +//! // channel and notifies the wait group when done. +//! func Seek(name string, match chan string, wg *sync.WaitGroup) { +//! select { +//! case peer := <-match: +//! fmt.Printf("%s received a message from %s.\n", name, peer) +//! case match <- name: +//! // Wait for someone to receive my message. +//! } +//! wg.Done() +//! } +//! ``` + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use crossbeam_channel::bounded; +use crossbeam_utils::thread; + +fn main() { + let people = vec!["Anna", "Bob", "Cody", "Dave", "Eva"]; + let (s, r) = bounded(1); // Make room for one unmatched send. + + // Either send my name into the channel or receive someone else's, whatever happens first. + let seek = |name, s, r| { + select! { + recv(r) -> peer => println!("{} received a message from {}.", name, peer.unwrap()), + send(s, name) -> _ => {}, // Wait for someone to receive my message. + } + }; + + thread::scope(|scope| { + for name in people { + let (s, r) = (s.clone(), r.clone()); + scope.spawn(move |_| seek(name, s, r)); + } + }) + .unwrap(); + + // Check if there is a pending send operation. + if let Ok(name) = r.try_recv() { + println!("No one received {}’s message.", name); + } +} diff --git a/vendor/crossbeam-channel/examples/stopwatch.rs b/vendor/crossbeam-channel/examples/stopwatch.rs new file mode 100644 index 0000000000..137ea210e6 --- /dev/null +++ b/vendor/crossbeam-channel/examples/stopwatch.rs @@ -0,0 +1,58 @@ +//! Prints the elapsed time every 1 second and quits on Ctrl+C. + +#[macro_use] +extern crate crossbeam_channel; +extern crate signal_hook; + +use std::io; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{bounded, tick, Receiver}; +use signal_hook::iterator::Signals; +use signal_hook::SIGINT; + +// Creates a channel that gets a message every time `SIGINT` is signalled. +fn sigint_notifier() -> io::Result> { + let (s, r) = bounded(100); + let signals = Signals::new(&[SIGINT])?; + + thread::spawn(move || { + for _ in signals.forever() { + if s.send(()).is_err() { + break; + } + } + }); + + Ok(r) +} + +// Prints the elapsed time. +fn show(dur: Duration) { + println!( + "Elapsed: {}.{:03} sec", + dur.as_secs(), + dur.subsec_nanos() / 1_000_000 + ); +} + +fn main() { + let start = Instant::now(); + let update = tick(Duration::from_secs(1)); + let ctrl_c = sigint_notifier().unwrap(); + + loop { + select! { + recv(update) -> _ => { + show(start.elapsed()); + } + recv(ctrl_c) -> _ => { + println!(); + println!("Goodbye!"); + show(start.elapsed()); + break; + } + } + } +} diff --git a/vendor/crossbeam-channel/src/channel.rs b/vendor/crossbeam-channel/src/channel.rs new file mode 100644 index 0000000000..bc7908f0f4 --- /dev/null +++ b/vendor/crossbeam-channel/src/channel.rs @@ -0,0 +1,1389 @@ +//! The channel interface. + +use std::fmt; +use std::iter::FusedIterator; +use std::mem; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::sync::Arc; +use std::time::{Duration, Instant}; + +use context::Context; +use counter; +use err::{RecvError, RecvTimeoutError, SendError, SendTimeoutError, TryRecvError, TrySendError}; +use flavors; +use select::{Operation, SelectHandle, Token}; + +/// Creates a channel of unbounded capacity. +/// +/// This channel has a growable buffer that can hold any number of messages at a time. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// // Computes the n-th Fibonacci number. +/// fn fib(n: i32) -> i32 { +/// if n <= 1 { +/// n +/// } else { +/// fib(n - 1) + fib(n - 2) +/// } +/// } +/// +/// // Spawn an asynchronous computation. +/// thread::spawn(move || s.send(fib(20)).unwrap()); +/// +/// // Print the result of the computation. +/// println!("{}", r.recv().unwrap()); +/// ``` +pub fn unbounded() -> (Sender, Receiver) { + let (s, r) = counter::new(flavors::list::Channel::new()); + let s = Sender { + flavor: SenderFlavor::List(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::List(r), + }; + (s, r) +} + +/// Creates a channel of bounded capacity. +/// +/// This channel has a buffer that can hold at most `cap` messages at a time. +/// +/// A special case is zero-capacity channel, which cannot hold any messages. Instead, send and +/// receive operations must appear at the same time in order to pair up and pass the message over. +/// +/// # Examples +/// +/// A channel of capacity 1: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::bounded; +/// +/// let (s, r) = bounded(1); +/// +/// // This call returns immediately because there is enough space in the channel. +/// s.send(1).unwrap(); +/// +/// thread::spawn(move || { +/// // This call blocks the current thread because the channel is full. +/// // It will be able to complete only after the first message is received. +/// s.send(2).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(1)); +/// assert_eq!(r.recv(), Ok(1)); +/// assert_eq!(r.recv(), Ok(2)); +/// ``` +/// +/// A zero-capacity channel: +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::bounded; +/// +/// let (s, r) = bounded(0); +/// +/// thread::spawn(move || { +/// // This call blocks the current thread until a receive operation appears +/// // on the other side of the channel. +/// s.send(1).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(1)); +/// assert_eq!(r.recv(), Ok(1)); +/// ``` +pub fn bounded(cap: usize) -> (Sender, Receiver) { + if cap == 0 { + let (s, r) = counter::new(flavors::zero::Channel::new()); + let s = Sender { + flavor: SenderFlavor::Zero(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::Zero(r), + }; + (s, r) + } else { + let (s, r) = counter::new(flavors::array::Channel::with_capacity(cap)); + let s = Sender { + flavor: SenderFlavor::Array(s), + }; + let r = Receiver { + flavor: ReceiverFlavor::Array(r), + }; + (s, r) + } +} + +/// Creates a receiver that delivers a message after a certain duration of time. +/// +/// The channel is bounded with capacity of 1 and never gets disconnected. Exactly one message will +/// be sent into the channel after `duration` elapses. The message is the instant at which it is +/// sent. +/// +/// # Examples +/// +/// Using an `after` channel for timeouts: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::time::Duration; +/// use crossbeam_channel::{after, unbounded}; +/// +/// let (s, r) = unbounded::(); +/// let timeout = Duration::from_millis(100); +/// +/// select! { +/// recv(r) -> msg => println!("received {:?}", msg), +/// recv(after(timeout)) -> _ => println!("timed out"), +/// } +/// # } +/// ``` +/// +/// When the message gets sent: +/// +/// ``` +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::after; +/// +/// // Converts a number of milliseconds into a `Duration`. +/// let ms = |ms| Duration::from_millis(ms); +/// +/// // Returns `true` if `a` and `b` are very close `Instant`s. +/// let eq = |a, b| a + ms(50) > b && b + ms(50) > a; +/// +/// let start = Instant::now(); +/// let r = after(ms(100)); +/// +/// thread::sleep(ms(500)); +/// +/// // This message was sent 100 ms from the start and received 500 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(100))); +/// assert!(eq(Instant::now(), start + ms(500))); +/// ``` +pub fn after(duration: Duration) -> Receiver { + Receiver { + flavor: ReceiverFlavor::After(Arc::new(flavors::after::Channel::new(duration))), + } +} + +/// Creates a receiver that never delivers messages. +/// +/// The channel is bounded with capacity of 0 and never gets disconnected. +/// +/// # Examples +/// +/// Using a `never` channel to optionally add a timeout to [`select!`]: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::{after, never, unbounded}; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s.send(1).unwrap(); +/// }); +/// +/// // Suppose this duration can be a `Some` or a `None`. +/// let duration = Some(Duration::from_millis(100)); +/// +/// // Create a channel that times out after the specified duration. +/// let timeout = duration +/// .map(|d| after(d)) +/// .unwrap_or(never()); +/// +/// select! { +/// recv(r) -> msg => assert_eq!(msg, Ok(1)), +/// recv(timeout) -> _ => println!("timed out"), +/// } +/// # } +/// ``` +/// +/// [`select!`]: macro.select.html +pub fn never() -> Receiver { + Receiver { + flavor: ReceiverFlavor::Never(flavors::never::Channel::new()), + } +} + +/// Creates a receiver that delivers messages periodically. +/// +/// The channel is bounded with capacity of 1 and never gets disconnected. Messages will be +/// sent into the channel in intervals of `duration`. Each message is the instant at which it is +/// sent. +/// +/// # Examples +/// +/// Using a `tick` channel to periodically print elapsed time: +/// +/// ``` +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::tick; +/// +/// let start = Instant::now(); +/// let ticker = tick(Duration::from_millis(100)); +/// +/// for _ in 0..5 { +/// ticker.recv().unwrap(); +/// println!("elapsed: {:?}", start.elapsed()); +/// } +/// ``` +/// +/// When messages get sent: +/// +/// ``` +/// use std::thread; +/// use std::time::{Duration, Instant}; +/// use crossbeam_channel::tick; +/// +/// // Converts a number of milliseconds into a `Duration`. +/// let ms = |ms| Duration::from_millis(ms); +/// +/// // Returns `true` if `a` and `b` are very close `Instant`s. +/// let eq = |a, b| a + ms(50) > b && b + ms(50) > a; +/// +/// let start = Instant::now(); +/// let r = tick(ms(100)); +/// +/// // This message was sent 100 ms from the start and received 100 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(100))); +/// assert!(eq(Instant::now(), start + ms(100))); +/// +/// thread::sleep(ms(500)); +/// +/// // This message was sent 200 ms from the start and received 600 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(200))); +/// assert!(eq(Instant::now(), start + ms(600))); +/// +/// // This message was sent 700 ms from the start and received 700 ms from the start. +/// assert!(eq(r.recv().unwrap(), start + ms(700))); +/// assert!(eq(Instant::now(), start + ms(700))); +/// ``` +pub fn tick(duration: Duration) -> Receiver { + Receiver { + flavor: ReceiverFlavor::Tick(Arc::new(flavors::tick::Channel::new(duration))), + } +} + +/// The sending side of a channel. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r) = unbounded(); +/// let s2 = s1.clone(); +/// +/// thread::spawn(move || s1.send(1).unwrap()); +/// thread::spawn(move || s2.send(2).unwrap()); +/// +/// let msg1 = r.recv().unwrap(); +/// let msg2 = r.recv().unwrap(); +/// +/// assert_eq!(msg1 + msg2, 3); +/// ``` +pub struct Sender { + flavor: SenderFlavor, +} + +/// Sender flavors. +enum SenderFlavor { + /// Bounded channel based on a preallocated array. + Array(counter::Sender>), + + /// Unbounded channel implemented as a linked list. + List(counter::Sender>), + + /// Zero-capacity channel. + Zero(counter::Sender>), +} + +unsafe impl Send for Sender {} +unsafe impl Sync for Sender {} + +impl UnwindSafe for Sender {} +impl RefUnwindSafe for Sender {} + +impl Sender { + /// Attempts to send a message into the channel without blocking. + /// + /// This method will either send a message into the channel immediately or return an error if + /// the channel is full or disconnected. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will send the message only if there + /// happens to be a receive operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, TrySendError}; + /// + /// let (s, r) = bounded(1); + /// + /// assert_eq!(s.try_send(1), Ok(())); + /// assert_eq!(s.try_send(2), Err(TrySendError::Full(2))); + /// + /// drop(r); + /// assert_eq!(s.try_send(3), Err(TrySendError::Disconnected(3))); + /// ``` + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + match &self.flavor { + SenderFlavor::Array(chan) => chan.try_send(msg), + SenderFlavor::List(chan) => chan.try_send(msg), + SenderFlavor::Zero(chan) => chan.try_send(msg), + } + } + + /// Blocks the current thread until a message is sent or the channel is disconnected. + /// + /// If the channel is full and not disconnected, this call will block until the send operation + /// can proceed. If the channel becomes disconnected, this call will wake up and return an + /// error. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive operation to + /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{bounded, SendError}; + /// + /// let (s, r) = bounded(1); + /// assert_eq!(s.send(1), Ok(())); + /// + /// thread::spawn(move || { + /// assert_eq!(r.recv(), Ok(1)); + /// thread::sleep(Duration::from_secs(1)); + /// drop(r); + /// }); + /// + /// assert_eq!(s.send(2), Ok(())); + /// assert_eq!(s.send(3), Err(SendError(3))); + /// ``` + pub fn send(&self, msg: T) -> Result<(), SendError> { + match &self.flavor { + SenderFlavor::Array(chan) => chan.send(msg, None), + SenderFlavor::List(chan) => chan.send(msg, None), + SenderFlavor::Zero(chan) => chan.send(msg, None), + } + .map_err(|err| match err { + SendTimeoutError::Disconnected(msg) => SendError(msg), + SendTimeoutError::Timeout(_) => unreachable!(), + }) + } + + /// Waits for a message to be sent into the channel, but only for a limited time. + /// + /// If the channel is full and not disconnected, this call will block until the send operation + /// can proceed or the operation times out. If the channel becomes disconnected, this call will + /// wake up and return an error. The returned error contains the original message. + /// + /// If called on a zero-capacity channel, this method will wait for a receive operation to + /// appear on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{bounded, SendTimeoutError}; + /// + /// let (s, r) = bounded(0); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// assert_eq!(r.recv(), Ok(2)); + /// drop(r); + /// }); + /// + /// assert_eq!( + /// s.send_timeout(1, Duration::from_millis(500)), + /// Err(SendTimeoutError::Timeout(1)), + /// ); + /// assert_eq!( + /// s.send_timeout(2, Duration::from_secs(1)), + /// Ok(()), + /// ); + /// assert_eq!( + /// s.send_timeout(3, Duration::from_millis(500)), + /// Err(SendTimeoutError::Disconnected(3)), + /// ); + /// ``` + pub fn send_timeout(&self, msg: T, timeout: Duration) -> Result<(), SendTimeoutError> { + let deadline = Instant::now() + timeout; + + match &self.flavor { + SenderFlavor::Array(chan) => chan.send(msg, Some(deadline)), + SenderFlavor::List(chan) => chan.send(msg, Some(deadline)), + SenderFlavor::Zero(chan) => chan.send(msg, Some(deadline)), + } + } + + /// Returns `true` if the channel is empty. + /// + /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert!(s.is_empty()); + /// + /// s.send(0).unwrap(); + /// assert!(!s.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_empty(), + SenderFlavor::List(chan) => chan.is_empty(), + SenderFlavor::Zero(chan) => chan.is_empty(), + } + } + + /// Returns `true` if the channel is full. + /// + /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(1); + /// + /// assert!(!s.is_full()); + /// s.send(0).unwrap(); + /// assert!(s.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.is_full(), + SenderFlavor::List(chan) => chan.is_full(), + SenderFlavor::Zero(chan) => chan.is_full(), + } + } + + /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(s.len(), 0); + /// + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// assert_eq!(s.len(), 2); + /// ``` + pub fn len(&self) -> usize { + match &self.flavor { + SenderFlavor::Array(chan) => chan.len(), + SenderFlavor::List(chan) => chan.len(), + SenderFlavor::Zero(chan) => chan.len(), + } + } + + /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, unbounded}; + /// + /// let (s, _) = unbounded::(); + /// assert_eq!(s.capacity(), None); + /// + /// let (s, _) = bounded::(5); + /// assert_eq!(s.capacity(), Some(5)); + /// + /// let (s, _) = bounded::(0); + /// assert_eq!(s.capacity(), Some(0)); + /// ``` + pub fn capacity(&self) -> Option { + match &self.flavor { + SenderFlavor::Array(chan) => chan.capacity(), + SenderFlavor::List(chan) => chan.capacity(), + SenderFlavor::Zero(chan) => chan.capacity(), + } + } + + /// Returns `true` if senders belong to the same channel. + /// + /// # Examples + /// + /// ```rust + /// use crossbeam_channel::unbounded; + /// + /// let (s, _) = unbounded::(); + /// + /// let s2 = s.clone(); + /// assert!(s.same_channel(&s2)); + /// + /// let (s3, _) = unbounded(); + /// assert!(!s.same_channel(&s3)); + /// ``` + pub fn same_channel(&self, other: &Sender) -> bool { + match (&self.flavor, &other.flavor) { + (SenderFlavor::Array(ref a), SenderFlavor::Array(ref b)) => a == b, + (SenderFlavor::List(ref a), SenderFlavor::List(ref b)) => a == b, + (SenderFlavor::Zero(ref a), SenderFlavor::Zero(ref b)) => a == b, + _ => false, + } + } +} + +impl Drop for Sender { + fn drop(&mut self) { + unsafe { + match &self.flavor { + SenderFlavor::Array(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::List(chan) => chan.release(|c| c.disconnect()), + SenderFlavor::Zero(chan) => chan.release(|c| c.disconnect()), + } + } + } +} + +impl Clone for Sender { + fn clone(&self) -> Self { + let flavor = match &self.flavor { + SenderFlavor::Array(chan) => SenderFlavor::Array(chan.acquire()), + SenderFlavor::List(chan) => SenderFlavor::List(chan.acquire()), + SenderFlavor::Zero(chan) => SenderFlavor::Zero(chan.acquire()), + }; + + Sender { flavor } + } +} + +impl fmt::Debug for Sender { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Sender { .. }") + } +} + +/// The receiving side of a channel. +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1); +/// thread::sleep(Duration::from_secs(1)); +/// s.send(2); +/// }); +/// +/// assert_eq!(r.recv(), Ok(1)); // Received immediately. +/// assert_eq!(r.recv(), Ok(2)); // Received after 1 second. +/// ``` +pub struct Receiver { + flavor: ReceiverFlavor, +} + +/// Receiver flavors. +enum ReceiverFlavor { + /// Bounded channel based on a preallocated array. + Array(counter::Receiver>), + + /// Unbounded channel implemented as a linked list. + List(counter::Receiver>), + + /// Zero-capacity channel. + Zero(counter::Receiver>), + + /// The after flavor. + After(Arc), + + /// The tick flavor. + Tick(Arc), + + /// The never flavor. + Never(flavors::never::Channel), +} + +unsafe impl Send for Receiver {} +unsafe impl Sync for Receiver {} + +impl UnwindSafe for Receiver {} +impl RefUnwindSafe for Receiver {} + +impl Receiver { + /// Attempts to receive a message from the channel without blocking. + /// + /// This method will either receive a message from the channel immediately or return an error + /// if the channel is empty. + /// + /// If called on a zero-capacity channel, this method will receive a message only if there + /// happens to be a send operation on the other side of the channel at the same time. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{unbounded, TryRecvError}; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + /// + /// s.send(5).unwrap(); + /// drop(s); + /// + /// assert_eq!(r.try_recv(), Ok(5)); + /// assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + /// ``` + pub fn try_recv(&self) -> Result { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.try_recv(), + ReceiverFlavor::List(chan) => chan.try_recv(), + ReceiverFlavor::Zero(chan) => chan.try_recv(), + ReceiverFlavor::After(chan) => { + let msg = chan.try_recv(); + unsafe { + mem::transmute_copy::, Result>( + &msg, + ) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.try_recv(); + unsafe { + mem::transmute_copy::, Result>( + &msg, + ) + } + } + ReceiverFlavor::Never(chan) => chan.try_recv(), + } + } + + /// Blocks the current thread until a message is received or the channel is empty and + /// disconnected. + /// + /// If the channel is empty and not disconnected, this call will block until the receive + /// operation can proceed. If the channel is empty and becomes disconnected, this call will + /// wake up and return an error. + /// + /// If called on a zero-capacity channel, this method will wait for a send operation to appear + /// on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, RecvError}; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s.send(5).unwrap(); + /// drop(s); + /// }); + /// + /// assert_eq!(r.recv(), Ok(5)); + /// assert_eq!(r.recv(), Err(RecvError)); + /// ``` + pub fn recv(&self) -> Result { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.recv(None), + ReceiverFlavor::List(chan) => chan.recv(None), + ReceiverFlavor::Zero(chan) => chan.recv(None), + ReceiverFlavor::After(chan) => { + let msg = chan.recv(None); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.recv(None); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Never(chan) => chan.recv(None), + } + .map_err(|_| RecvError) + } + + /// Waits for a message to be received from the channel, but only for a limited time. + /// + /// If the channel is empty and not disconnected, this call will block until the receive + /// operation can proceed or the operation times out. If the channel is empty and becomes + /// disconnected, this call will wake up and return an error. + /// + /// If called on a zero-capacity channel, this method will wait for a send operation to appear + /// on the other side of the channel. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, RecvTimeoutError}; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s.send(5).unwrap(); + /// drop(s); + /// }); + /// + /// assert_eq!( + /// r.recv_timeout(Duration::from_millis(500)), + /// Err(RecvTimeoutError::Timeout), + /// ); + /// assert_eq!( + /// r.recv_timeout(Duration::from_secs(1)), + /// Ok(5), + /// ); + /// assert_eq!( + /// r.recv_timeout(Duration::from_secs(1)), + /// Err(RecvTimeoutError::Disconnected), + /// ); + /// ``` + pub fn recv_timeout(&self, timeout: Duration) -> Result { + let deadline = Instant::now() + timeout; + + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::List(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::Zero(chan) => chan.recv(Some(deadline)), + ReceiverFlavor::After(chan) => { + let msg = chan.recv(Some(deadline)); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Tick(chan) => { + let msg = chan.recv(Some(deadline)); + unsafe { + mem::transmute_copy::< + Result, + Result, + >(&msg) + } + } + ReceiverFlavor::Never(chan) => chan.recv(Some(deadline)), + } + } + + /// Returns `true` if the channel is empty. + /// + /// Note: Zero-capacity channels are always empty. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// assert!(r.is_empty()); + /// s.send(0).unwrap(); + /// assert!(!r.is_empty()); + /// ``` + pub fn is_empty(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_empty(), + ReceiverFlavor::List(chan) => chan.is_empty(), + ReceiverFlavor::Zero(chan) => chan.is_empty(), + ReceiverFlavor::After(chan) => chan.is_empty(), + ReceiverFlavor::Tick(chan) => chan.is_empty(), + ReceiverFlavor::Never(chan) => chan.is_empty(), + } + } + + /// Returns `true` if the channel is full. + /// + /// Note: Zero-capacity channels are always full. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(1); + /// + /// assert!(!r.is_full()); + /// s.send(0).unwrap(); + /// assert!(r.is_full()); + /// ``` + pub fn is_full(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.is_full(), + ReceiverFlavor::List(chan) => chan.is_full(), + ReceiverFlavor::Zero(chan) => chan.is_full(), + ReceiverFlavor::After(chan) => chan.is_full(), + ReceiverFlavor::Tick(chan) => chan.is_full(), + ReceiverFlavor::Never(chan) => chan.is_full(), + } + } + + /// Returns the number of messages in the channel. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// assert_eq!(r.len(), 0); + /// + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// assert_eq!(r.len(), 2); + /// ``` + pub fn len(&self) -> usize { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.len(), + ReceiverFlavor::List(chan) => chan.len(), + ReceiverFlavor::Zero(chan) => chan.len(), + ReceiverFlavor::After(chan) => chan.len(), + ReceiverFlavor::Tick(chan) => chan.len(), + ReceiverFlavor::Never(chan) => chan.len(), + } + } + + /// If the channel is bounded, returns its capacity. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, unbounded}; + /// + /// let (_, r) = unbounded::(); + /// assert_eq!(r.capacity(), None); + /// + /// let (_, r) = bounded::(5); + /// assert_eq!(r.capacity(), Some(5)); + /// + /// let (_, r) = bounded::(0); + /// assert_eq!(r.capacity(), Some(0)); + /// ``` + pub fn capacity(&self) -> Option { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.capacity(), + ReceiverFlavor::List(chan) => chan.capacity(), + ReceiverFlavor::Zero(chan) => chan.capacity(), + ReceiverFlavor::After(chan) => chan.capacity(), + ReceiverFlavor::Tick(chan) => chan.capacity(), + ReceiverFlavor::Never(chan) => chan.capacity(), + } + } + + /// A blocking iterator over messages in the channel. + /// + /// Each call to [`next`] blocks waiting for the next message and then returns it. However, if + /// the channel becomes empty and disconnected, it returns [`None`] without blocking. + /// + /// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next + /// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// thread::spawn(move || { + /// s.send(1).unwrap(); + /// s.send(2).unwrap(); + /// s.send(3).unwrap(); + /// drop(s); // Disconnect the channel. + /// }); + /// + /// // Collect all messages from the channel. + /// // Note that the call to `collect` blocks until the sender is dropped. + /// let v: Vec<_> = r.iter().collect(); + /// + /// assert_eq!(v, [1, 2, 3]); + /// ``` + pub fn iter(&self) -> Iter { + Iter { receiver: self } + } + + /// A non-blocking iterator over messages in the channel. + /// + /// Each call to [`next`] returns a message if there is one ready to be received. The iterator + /// never blocks waiting for the next message. + /// + /// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded::(); + /// + /// thread::spawn(move || { + /// s.send(1).unwrap(); + /// thread::sleep(Duration::from_secs(1)); + /// s.send(2).unwrap(); + /// thread::sleep(Duration::from_secs(2)); + /// s.send(3).unwrap(); + /// }); + /// + /// thread::sleep(Duration::from_secs(2)); + /// + /// // Collect all messages from the channel without blocking. + /// // The third message hasn't been sent yet so we'll collect only the first two. + /// let v: Vec<_> = r.try_iter().collect(); + /// + /// assert_eq!(v, [1, 2]); + /// ``` + pub fn try_iter(&self) -> TryIter { + TryIter { receiver: self } + } + + /// Returns `true` if receivers belong to the same channel. + /// + /// # Examples + /// + /// ```rust + /// use crossbeam_channel::unbounded; + /// + /// let (_, r) = unbounded::(); + /// + /// let r2 = r.clone(); + /// assert!(r.same_channel(&r2)); + /// + /// let (_, r3) = unbounded(); + /// assert!(!r.same_channel(&r3)); + /// ``` + pub fn same_channel(&self, other: &Receiver) -> bool { + match (&self.flavor, &other.flavor) { + (ReceiverFlavor::Array(a), ReceiverFlavor::Array(b)) => a == b, + (ReceiverFlavor::List(a), ReceiverFlavor::List(b)) => a == b, + (ReceiverFlavor::Zero(a), ReceiverFlavor::Zero(b)) => a == b, + (ReceiverFlavor::After(a), ReceiverFlavor::After(b)) => Arc::ptr_eq(a, b), + (ReceiverFlavor::Tick(a), ReceiverFlavor::Tick(b)) => Arc::ptr_eq(a, b), + (ReceiverFlavor::Never(_), ReceiverFlavor::Never(_)) => true, + _ => false, + } + } +} + +impl Drop for Receiver { + fn drop(&mut self) { + unsafe { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::List(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::Zero(chan) => chan.release(|c| c.disconnect()), + ReceiverFlavor::After(_) => {} + ReceiverFlavor::Tick(_) => {} + ReceiverFlavor::Never(_) => {} + } + } + } +} + +impl Clone for Receiver { + fn clone(&self) -> Self { + let flavor = match &self.flavor { + ReceiverFlavor::Array(chan) => ReceiverFlavor::Array(chan.acquire()), + ReceiverFlavor::List(chan) => ReceiverFlavor::List(chan.acquire()), + ReceiverFlavor::Zero(chan) => ReceiverFlavor::Zero(chan.acquire()), + ReceiverFlavor::After(chan) => ReceiverFlavor::After(chan.clone()), + ReceiverFlavor::Tick(chan) => ReceiverFlavor::Tick(chan.clone()), + ReceiverFlavor::Never(_) => ReceiverFlavor::Never(flavors::never::Channel::new()), + }; + + Receiver { flavor } + } +} + +impl fmt::Debug for Receiver { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Receiver { .. }") + } +} + +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Self::IntoIter { + self.iter() + } +} + +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> Self::IntoIter { + IntoIter { receiver: self } + } +} + +/// A blocking iterator over messages in a channel. +/// +/// Each call to [`next`] blocks waiting for the next message and then returns it. However, if the +/// channel becomes empty and disconnected, it returns [`None`] without blocking. +/// +/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// s.send(2).unwrap(); +/// s.send(3).unwrap(); +/// drop(s); // Disconnect the channel. +/// }); +/// +/// // Collect all messages from the channel. +/// // Note that the call to `collect` blocks until the sender is dropped. +/// let v: Vec<_> = r.iter().collect(); +/// +/// assert_eq!(v, [1, 2, 3]); +/// ``` +pub struct Iter<'a, T: 'a> { + receiver: &'a Receiver, +} + +impl<'a, T> FusedIterator for Iter<'a, T> {} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.recv().ok() + } +} + +impl<'a, T> fmt::Debug for Iter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Iter { .. }") + } +} + +/// A non-blocking iterator over messages in a channel. +/// +/// Each call to [`next`] returns a message if there is one ready to be received. The iterator +/// never blocks waiting for the next message. +/// +/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded::(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// thread::sleep(Duration::from_secs(1)); +/// s.send(2).unwrap(); +/// thread::sleep(Duration::from_secs(2)); +/// s.send(3).unwrap(); +/// }); +/// +/// thread::sleep(Duration::from_secs(2)); +/// +/// // Collect all messages from the channel without blocking. +/// // The third message hasn't been sent yet so we'll collect only the first two. +/// let v: Vec<_> = r.try_iter().collect(); +/// +/// assert_eq!(v, [1, 2]); +/// ``` +pub struct TryIter<'a, T: 'a> { + receiver: &'a Receiver, +} + +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.try_recv().ok() + } +} + +impl<'a, T> fmt::Debug for TryIter<'a, T> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("TryIter { .. }") + } +} + +/// A blocking iterator over messages in a channel. +/// +/// Each call to [`next`] blocks waiting for the next message and then returns it. However, if the +/// channel becomes empty and disconnected, it returns [`None`] without blocking. +/// +/// [`next`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html#tymethod.next +/// [`None`]: https://doc.rust-lang.org/std/option/enum.Option.html#variant.None +/// +/// # Examples +/// +/// ``` +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s, r) = unbounded(); +/// +/// thread::spawn(move || { +/// s.send(1).unwrap(); +/// s.send(2).unwrap(); +/// s.send(3).unwrap(); +/// drop(s); // Disconnect the channel. +/// }); +/// +/// // Collect all messages from the channel. +/// // Note that the call to `collect` blocks until the sender is dropped. +/// let v: Vec<_> = r.into_iter().collect(); +/// +/// assert_eq!(v, [1, 2, 3]); +/// ``` +pub struct IntoIter { + receiver: Receiver, +} + +impl FusedIterator for IntoIter {} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.receiver.recv().ok() + } +} + +impl fmt::Debug for IntoIter { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("IntoIter { .. }") + } +} + +impl SelectHandle for Sender { + fn try_select(&self, token: &mut Token) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().try_select(token), + SenderFlavor::List(chan) => chan.sender().try_select(token), + SenderFlavor::Zero(chan) => chan.sender().try_select(token), + } + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().register(oper, cx), + SenderFlavor::List(chan) => chan.sender().register(oper, cx), + SenderFlavor::Zero(chan) => chan.sender().register(oper, cx), + } + } + + fn unregister(&self, oper: Operation) { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().unregister(oper), + SenderFlavor::List(chan) => chan.sender().unregister(oper), + SenderFlavor::Zero(chan) => chan.sender().unregister(oper), + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().accept(token, cx), + SenderFlavor::List(chan) => chan.sender().accept(token, cx), + SenderFlavor::Zero(chan) => chan.sender().accept(token, cx), + } + } + + fn is_ready(&self) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().is_ready(), + SenderFlavor::List(chan) => chan.sender().is_ready(), + SenderFlavor::Zero(chan) => chan.sender().is_ready(), + } + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().watch(oper, cx), + SenderFlavor::List(chan) => chan.sender().watch(oper, cx), + SenderFlavor::Zero(chan) => chan.sender().watch(oper, cx), + } + } + + fn unwatch(&self, oper: Operation) { + match &self.flavor { + SenderFlavor::Array(chan) => chan.sender().unwatch(oper), + SenderFlavor::List(chan) => chan.sender().unwatch(oper), + SenderFlavor::Zero(chan) => chan.sender().unwatch(oper), + } + } +} + +impl SelectHandle for Receiver { + fn try_select(&self, token: &mut Token) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().try_select(token), + ReceiverFlavor::List(chan) => chan.receiver().try_select(token), + ReceiverFlavor::Zero(chan) => chan.receiver().try_select(token), + ReceiverFlavor::After(chan) => chan.try_select(token), + ReceiverFlavor::Tick(chan) => chan.try_select(token), + ReceiverFlavor::Never(chan) => chan.try_select(token), + } + } + + fn deadline(&self) -> Option { + match &self.flavor { + ReceiverFlavor::Array(_) => None, + ReceiverFlavor::List(_) => None, + ReceiverFlavor::Zero(_) => None, + ReceiverFlavor::After(chan) => chan.deadline(), + ReceiverFlavor::Tick(chan) => chan.deadline(), + ReceiverFlavor::Never(chan) => chan.deadline(), + } + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::List(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().register(oper, cx), + ReceiverFlavor::After(chan) => chan.register(oper, cx), + ReceiverFlavor::Tick(chan) => chan.register(oper, cx), + ReceiverFlavor::Never(chan) => chan.register(oper, cx), + } + } + + fn unregister(&self, oper: Operation) { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::List(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::Zero(chan) => chan.receiver().unregister(oper), + ReceiverFlavor::After(chan) => chan.unregister(oper), + ReceiverFlavor::Tick(chan) => chan.unregister(oper), + ReceiverFlavor::Never(chan) => chan.unregister(oper), + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::List(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().accept(token, cx), + ReceiverFlavor::After(chan) => chan.accept(token, cx), + ReceiverFlavor::Tick(chan) => chan.accept(token, cx), + ReceiverFlavor::Never(chan) => chan.accept(token, cx), + } + } + + fn is_ready(&self) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().is_ready(), + ReceiverFlavor::List(chan) => chan.receiver().is_ready(), + ReceiverFlavor::Zero(chan) => chan.receiver().is_ready(), + ReceiverFlavor::After(chan) => chan.is_ready(), + ReceiverFlavor::Tick(chan) => chan.is_ready(), + ReceiverFlavor::Never(chan) => chan.is_ready(), + } + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::List(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::Zero(chan) => chan.receiver().watch(oper, cx), + ReceiverFlavor::After(chan) => chan.watch(oper, cx), + ReceiverFlavor::Tick(chan) => chan.watch(oper, cx), + ReceiverFlavor::Never(chan) => chan.watch(oper, cx), + } + } + + fn unwatch(&self, oper: Operation) { + match &self.flavor { + ReceiverFlavor::Array(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::List(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::Zero(chan) => chan.receiver().unwatch(oper), + ReceiverFlavor::After(chan) => chan.unwatch(oper), + ReceiverFlavor::Tick(chan) => chan.unwatch(oper), + ReceiverFlavor::Never(chan) => chan.unwatch(oper), + } + } +} + +/// Writes a message into the channel. +pub unsafe fn write(s: &Sender, token: &mut Token, msg: T) -> Result<(), T> { + match &s.flavor { + SenderFlavor::Array(chan) => chan.write(token, msg), + SenderFlavor::List(chan) => chan.write(token, msg), + SenderFlavor::Zero(chan) => chan.write(token, msg), + } +} + +/// Reads a message from the channel. +pub unsafe fn read(r: &Receiver, token: &mut Token) -> Result { + match &r.flavor { + ReceiverFlavor::Array(chan) => chan.read(token), + ReceiverFlavor::List(chan) => chan.read(token), + ReceiverFlavor::Zero(chan) => chan.read(token), + ReceiverFlavor::After(chan) => { + mem::transmute_copy::, Result>(&chan.read(token)) + } + ReceiverFlavor::Tick(chan) => { + mem::transmute_copy::, Result>(&chan.read(token)) + } + ReceiverFlavor::Never(chan) => chan.read(token), + } +} diff --git a/vendor/crossbeam-channel/src/context.rs b/vendor/crossbeam-channel/src/context.rs new file mode 100644 index 0000000000..c6e5c15db3 --- /dev/null +++ b/vendor/crossbeam-channel/src/context.rs @@ -0,0 +1,191 @@ +//! Thread-local context used in select. + +use std::cell::Cell; +use std::sync::atomic::{AtomicUsize, Ordering}; +use std::sync::Arc; +use std::thread::{self, Thread, ThreadId}; +use std::time::Instant; + +use crossbeam_utils::Backoff; + +use select::Selected; + +/// Thread-local context used in select. +#[derive(Debug, Clone)] +pub struct Context { + inner: Arc, +} + +/// Inner representation of `Context`. +#[derive(Debug)] +struct Inner { + /// Selected operation. + select: AtomicUsize, + + /// A slot into which another thread may store a pointer to its `Packet`. + packet: AtomicUsize, + + /// Thread handle. + thread: Thread, + + /// Thread id. + thread_id: ThreadId, +} + +impl Context { + /// Creates a new context for the duration of the closure. + #[inline] + pub fn with(f: F) -> R + where + F: FnOnce(&Context) -> R, + { + thread_local! { + /// Cached thread-local context. + static CONTEXT: Cell> = Cell::new(Some(Context::new())); + } + + let mut f = Some(f); + let mut f = move |cx: &Context| -> R { + let f = f.take().unwrap(); + f(cx) + }; + + CONTEXT + .try_with(|cell| match cell.take() { + None => f(&Context::new()), + Some(cx) => { + cx.reset(); + let res = f(&cx); + cell.set(Some(cx)); + res + } + }) + .unwrap_or_else(|_| f(&Context::new())) + } + + /// Creates a new `Context`. + #[cold] + fn new() -> Context { + Context { + inner: Arc::new(Inner { + select: AtomicUsize::new(Selected::Waiting.into()), + packet: AtomicUsize::new(0), + thread: thread::current(), + thread_id: thread::current().id(), + }), + } + } + + /// Resets `select` and `packet`. + #[inline] + fn reset(&self) { + self.inner + .select + .store(Selected::Waiting.into(), Ordering::Release); + self.inner.packet.store(0, Ordering::Release); + } + + /// Attempts to select an operation. + /// + /// On failure, the previously selected operation is returned. + #[inline] + pub fn try_select(&self, select: Selected) -> Result<(), Selected> { + self.inner + .select + .compare_exchange( + Selected::Waiting.into(), + select.into(), + Ordering::AcqRel, + Ordering::Acquire, + ) + .map(|_| ()) + .map_err(|e| e.into()) + } + + /// Returns the selected operation. + #[inline] + pub fn selected(&self) -> Selected { + Selected::from(self.inner.select.load(Ordering::Acquire)) + } + + /// Stores a packet. + /// + /// This method must be called after `try_select` succeeds and there is a packet to provide. + #[inline] + pub fn store_packet(&self, packet: usize) { + if packet != 0 { + self.inner.packet.store(packet, Ordering::Release); + } + } + + /// Waits until a packet is provided and returns it. + #[inline] + pub fn wait_packet(&self) -> usize { + let backoff = Backoff::new(); + loop { + let packet = self.inner.packet.load(Ordering::Acquire); + if packet != 0 { + return packet; + } + backoff.snooze(); + } + } + + /// Waits until an operation is selected and returns it. + /// + /// If the deadline is reached, `Selected::Aborted` will be selected. + #[inline] + pub fn wait_until(&self, deadline: Option) -> Selected { + // Spin for a short time, waiting until an operation is selected. + let backoff = Backoff::new(); + loop { + let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); + if sel != Selected::Waiting { + return sel; + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + loop { + // Check whether an operation has been selected. + let sel = Selected::from(self.inner.select.load(Ordering::Acquire)); + if sel != Selected::Waiting { + return sel; + } + + // If there's a deadline, park the current thread until the deadline is reached. + if let Some(end) = deadline { + let now = Instant::now(); + + if now < end { + thread::park_timeout(end - now); + } else { + // The deadline has been reached. Try aborting select. + return match self.try_select(Selected::Aborted) { + Ok(()) => Selected::Aborted, + Err(s) => s, + }; + } + } else { + thread::park(); + } + } + } + + /// Unparks the thread this context belongs to. + #[inline] + pub fn unpark(&self) { + self.inner.thread.unpark(); + } + + /// Returns the id of the thread this context belongs to. + #[inline] + pub fn thread_id(&self) -> ThreadId { + self.inner.thread_id + } +} diff --git a/vendor/crossbeam-channel/src/counter.rs b/vendor/crossbeam-channel/src/counter.rs new file mode 100644 index 0000000000..2eaf067820 --- /dev/null +++ b/vendor/crossbeam-channel/src/counter.rs @@ -0,0 +1,144 @@ +//! Reference counter for channels. + +use std::isize; +use std::ops; +use std::process; +use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; + +/// Reference counter internals. +struct Counter { + /// The number of senders associated with the channel. + senders: AtomicUsize, + + /// The number of receivers associated with the channel. + receivers: AtomicUsize, + + /// Set to `true` if the last sender or the last receiver reference deallocates the channel. + destroy: AtomicBool, + + /// The internal channel. + chan: C, +} + +/// Wraps a channel into the reference counter. +pub fn new(chan: C) -> (Sender, Receiver) { + let counter = Box::into_raw(Box::new(Counter { + senders: AtomicUsize::new(1), + receivers: AtomicUsize::new(1), + destroy: AtomicBool::new(false), + chan, + })); + let s = Sender { counter }; + let r = Receiver { counter }; + (s, r) +} + +/// The sending side. +pub struct Sender { + counter: *mut Counter, +} + +impl Sender { + /// Returns the internal `Counter`. + fn counter(&self) -> &Counter { + unsafe { &*self.counter } + } + + /// Acquires another sender reference. + pub fn acquire(&self) -> Sender { + let count = self.counter().senders.fetch_add(1, Ordering::Relaxed); + + // Cloning senders and calling `mem::forget` on the clones could potentially overflow the + // counter. It's very difficult to recover sensibly from such degenerate scenarios so we + // just abort when the count becomes very large. + if count > isize::MAX as usize { + process::abort(); + } + + Sender { + counter: self.counter, + } + } + + /// Releases the sender reference. + /// + /// Function `disconnect` will be called if this is the last sender reference. + pub unsafe fn release bool>(&self, disconnect: F) { + if self.counter().senders.fetch_sub(1, Ordering::AcqRel) == 1 { + disconnect(&self.counter().chan); + + if self.counter().destroy.swap(true, Ordering::AcqRel) { + drop(Box::from_raw(self.counter)); + } + } + } +} + +impl ops::Deref for Sender { + type Target = C; + + fn deref(&self) -> &C { + &self.counter().chan + } +} + +impl PartialEq for Sender { + fn eq(&self, other: &Sender) -> bool { + self.counter == other.counter + } +} + +/// The receiving side. +pub struct Receiver { + counter: *mut Counter, +} + +impl Receiver { + /// Returns the internal `Counter`. + fn counter(&self) -> &Counter { + unsafe { &*self.counter } + } + + /// Acquires another receiver reference. + pub fn acquire(&self) -> Receiver { + let count = self.counter().receivers.fetch_add(1, Ordering::Relaxed); + + // Cloning receivers and calling `mem::forget` on the clones could potentially overflow the + // counter. It's very difficult to recover sensibly from such degenerate scenarios so we + // just abort when the count becomes very large. + if count > isize::MAX as usize { + process::abort(); + } + + Receiver { + counter: self.counter, + } + } + + /// Releases the receiver reference. + /// + /// Function `disconnect` will be called if this is the last receiver reference. + pub unsafe fn release bool>(&self, disconnect: F) { + if self.counter().receivers.fetch_sub(1, Ordering::AcqRel) == 1 { + disconnect(&self.counter().chan); + + if self.counter().destroy.swap(true, Ordering::AcqRel) { + drop(Box::from_raw(self.counter)); + } + } + } +} + +impl ops::Deref for Receiver { + type Target = C; + + fn deref(&self) -> &C { + &self.counter().chan + } +} + +impl PartialEq for Receiver { + fn eq(&self, other: &Receiver) -> bool { + self.counter == other.counter + } +} diff --git a/vendor/crossbeam-channel/src/err.rs b/vendor/crossbeam-channel/src/err.rs new file mode 100644 index 0000000000..468ce5cd89 --- /dev/null +++ b/vendor/crossbeam-channel/src/err.rs @@ -0,0 +1,451 @@ +use std::error; +use std::fmt; + +/// An error returned from the [`send`] method. +/// +/// The message could not be sent because the channel is disconnected. +/// +/// The error contains the message so it can be recovered. +/// +/// [`send`]: struct.Sender.html#method.send +#[derive(PartialEq, Eq, Clone, Copy)] +pub struct SendError(pub T); + +/// An error returned from the [`try_send`] method. +/// +/// The error contains the message being sent so it can be recovered. +/// +/// [`try_send`]: struct.Sender.html#method.try_send +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum TrySendError { + /// The message could not be sent because the channel is full. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no receiver + /// available to receive the message at the time. + Full(T), + + /// The message could not be sent because the channel is disconnected. + Disconnected(T), +} + +/// An error returned from the [`send_timeout`] method. +/// +/// The error contains the message being sent so it can be recovered. +/// +/// [`send_timeout`]: struct.Sender.html#method.send_timeout +#[derive(PartialEq, Eq, Clone, Copy)] +pub enum SendTimeoutError { + /// The message could not be sent because the channel is full and the operation timed out. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no receiver + /// available to receive the message and the operation timed out. + Timeout(T), + + /// The message could not be sent because the channel is disconnected. + Disconnected(T), +} + +/// An error returned from the [`recv`] method. +/// +/// A message could not be received because the channel is empty and disconnected. +/// +/// [`recv`]: struct.Receiver.html#method.recv +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct RecvError; + +/// An error returned from the [`try_recv`] method. +/// +/// [`try_recv`]: struct.Receiver.html#method.recv +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum TryRecvError { + /// A message could not be received because the channel is empty. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no sender + /// available to send a message at the time. + Empty, + + /// The message could not be received because the channel is empty and disconnected. + Disconnected, +} + +/// An error returned from the [`recv_timeout`] method. +/// +/// [`recv_timeout`]: struct.Receiver.html#method.recv_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub enum RecvTimeoutError { + /// A message could not be received because the channel is empty and the operation timed out. + /// + /// If this is a zero-capacity channel, then the error indicates that there was no sender + /// available to send a message and the operation timed out. + Timeout, + + /// The message could not be received because the channel is empty and disconnected. + Disconnected, +} + +/// An error returned from the [`try_select`] method. +/// +/// Failed because none of the channel operations were ready. +/// +/// [`try_select`]: struct.Select.html#method.try_select +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct TrySelectError; + +/// An error returned from the [`select_timeout`] method. +/// +/// Failed because none of the channel operations became ready before the timeout. +/// +/// [`select_timeout`]: struct.Select.html#method.select_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct SelectTimeoutError; + +/// An error returned from the [`try_ready`] method. +/// +/// Failed because none of the channel operations were ready. +/// +/// [`try_ready`]: struct.Select.html#method.try_ready +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct TryReadyError; + +/// An error returned from the [`ready_timeout`] method. +/// +/// Failed because none of the channel operations became ready before the timeout. +/// +/// [`ready_timeout`]: struct.Select.html#method.ready_timeout +#[derive(PartialEq, Eq, Clone, Copy, Debug)] +pub struct ReadyTimeoutError; + +impl fmt::Debug for SendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "SendError(..)".fmt(f) + } +} + +impl fmt::Display for SendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "sending on a disconnected channel".fmt(f) + } +} + +impl error::Error for SendError { + fn description(&self) -> &str { + "sending on a disconnected channel" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl SendError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// drop(r); + /// + /// if let Err(err) = s.send("foo") { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + self.0 + } +} + +impl fmt::Debug for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TrySendError::Full(..) => "Full(..)".fmt(f), + TrySendError::Disconnected(..) => "Disconnected(..)".fmt(f), + } + } +} + +impl fmt::Display for TrySendError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TrySendError::Full(..) => "sending on a full channel".fmt(f), + TrySendError::Disconnected(..) => "sending on a disconnected channel".fmt(f), + } + } +} + +impl error::Error for TrySendError { + fn description(&self) -> &str { + match *self { + TrySendError::Full(..) => "sending on a full channel", + TrySendError::Disconnected(..) => "sending on a disconnected channel", + } + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From> for TrySendError { + fn from(err: SendError) -> TrySendError { + match err { + SendError(t) => TrySendError::Disconnected(t), + } + } +} + +impl TrySendError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::bounded; + /// + /// let (s, r) = bounded(0); + /// + /// if let Err(err) = s.try_send("foo") { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + match self { + TrySendError::Full(v) => v, + TrySendError::Disconnected(v) => v, + } + } + + /// Returns `true` if the send operation failed because the channel is full. + pub fn is_full(&self) -> bool { + match self { + TrySendError::Full(_) => true, + _ => false, + } + } + + /// Returns `true` if the send operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + TrySendError::Disconnected(_) => true, + _ => false, + } + } +} + +impl fmt::Debug for SendTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "SendTimeoutError(..)".fmt(f) + } +} + +impl fmt::Display for SendTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + SendTimeoutError::Timeout(..) => "timed out waiting on send operation".fmt(f), + SendTimeoutError::Disconnected(..) => "sending on a disconnected channel".fmt(f), + } + } +} + +impl error::Error for SendTimeoutError { + fn description(&self) -> &str { + "sending on an empty and disconnected channel" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From> for SendTimeoutError { + fn from(err: SendError) -> SendTimeoutError { + match err { + SendError(e) => SendTimeoutError::Disconnected(e), + } + } +} + +impl SendTimeoutError { + /// Unwraps the message. + /// + /// # Examples + /// + /// ``` + /// use std::time::Duration; + /// use crossbeam_channel::unbounded; + /// + /// let (s, r) = unbounded(); + /// + /// if let Err(err) = s.send_timeout("foo", Duration::from_secs(1)) { + /// assert_eq!(err.into_inner(), "foo"); + /// } + /// ``` + pub fn into_inner(self) -> T { + match self { + SendTimeoutError::Timeout(v) => v, + SendTimeoutError::Disconnected(v) => v, + } + } + + /// Returns `true` if the send operation timed out. + pub fn is_timeout(&self) -> bool { + match self { + SendTimeoutError::Timeout(_) => true, + _ => false, + } + } + + /// Returns `true` if the send operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + SendTimeoutError::Disconnected(_) => true, + _ => false, + } + } +} + +impl fmt::Display for RecvError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "receiving on an empty and disconnected channel".fmt(f) + } +} + +impl error::Error for RecvError { + fn description(&self) -> &str { + "receiving on an empty and disconnected channel" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl fmt::Display for TryRecvError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + TryRecvError::Empty => "receiving on an empty channel".fmt(f), + TryRecvError::Disconnected => "receiving on an empty and disconnected channel".fmt(f), + } + } +} + +impl error::Error for TryRecvError { + fn description(&self) -> &str { + match *self { + TryRecvError::Empty => "receiving on an empty channel", + TryRecvError::Disconnected => "receiving on an empty and disconnected channel", + } + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From for TryRecvError { + fn from(err: RecvError) -> TryRecvError { + match err { + RecvError => TryRecvError::Disconnected, + } + } +} + +impl TryRecvError { + /// Returns `true` if the receive operation failed because the channel is empty. + pub fn is_empty(&self) -> bool { + match self { + TryRecvError::Empty => true, + _ => false, + } + } + + /// Returns `true` if the receive operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + TryRecvError::Disconnected => true, + _ => false, + } + } +} + +impl fmt::Display for RecvTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + RecvTimeoutError::Timeout => "timed out waiting on receive operation".fmt(f), + RecvTimeoutError::Disconnected => "channel is empty and disconnected".fmt(f), + } + } +} + +impl error::Error for RecvTimeoutError { + fn description(&self) -> &str { + match *self { + RecvTimeoutError::Timeout => "timed out waiting on receive operation", + RecvTimeoutError::Disconnected => "channel is empty and disconnected", + } + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl From for RecvTimeoutError { + fn from(err: RecvError) -> RecvTimeoutError { + match err { + RecvError => RecvTimeoutError::Disconnected, + } + } +} + +impl RecvTimeoutError { + /// Returns `true` if the receive operation timed out. + pub fn is_timeout(&self) -> bool { + match self { + RecvTimeoutError::Timeout => true, + _ => false, + } + } + + /// Returns `true` if the receive operation failed because the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + match self { + RecvTimeoutError::Disconnected => true, + _ => false, + } + } +} + +impl fmt::Display for TrySelectError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "all operations in select would block".fmt(f) + } +} + +impl error::Error for TrySelectError { + fn description(&self) -> &str { + "all operations in select would block" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} + +impl fmt::Display for SelectTimeoutError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + "timed out waiting on select".fmt(f) + } +} + +impl error::Error for SelectTimeoutError { + fn description(&self) -> &str { + "timed out waiting on select" + } + + fn cause(&self) -> Option<&dyn error::Error> { + None + } +} diff --git a/vendor/crossbeam-channel/src/flavors/after.rs b/vendor/crossbeam-channel/src/flavors/after.rs new file mode 100644 index 0000000000..b57f8a7879 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/after.rs @@ -0,0 +1,200 @@ +//! Channel that delivers a message after a certain amount of time. +//! +//! Messages cannot be sent into this kind of channel; they are materialized on demand. + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +use context::Context; +use err::{RecvTimeoutError, TryRecvError}; +use select::{Operation, SelectHandle, Token}; +use utils; + +/// Result of a receive operation. +pub type AfterToken = Option; + +/// Channel that delivers a message after a certain amount of time. +pub struct Channel { + /// The instant at which the message will be delivered. + delivery_time: Instant, + + /// `true` if the message has been received. + received: AtomicBool, +} + +impl Channel { + /// Creates a channel that delivers a message after a certain duration of time. + #[inline] + pub fn new(dur: Duration) -> Self { + Channel { + delivery_time: Instant::now() + dur, + received: AtomicBool::new(false), + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + // The message has already been received. + return Err(TryRecvError::Empty); + } + + if Instant::now() < self.delivery_time { + // The message was not delivered yet. + return Err(TryRecvError::Empty); + } + + // Try receiving the message if it is still available. + if !self.received.swap(true, Ordering::SeqCst) { + // Success! Return delivery time as the message. + Ok(self.delivery_time) + } else { + // The message was already received. + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + // The message has already been received. + utils::sleep_until(deadline); + return Err(RecvTimeoutError::Timeout); + } + + // Wait until the message is received or the deadline is reached. + loop { + let now = Instant::now(); + + // Check if we can receive the next message. + if now >= self.delivery_time { + break; + } + + // Check if the deadline has been reached. + if let Some(d) = deadline { + if now >= d { + return Err(RecvTimeoutError::Timeout); + } + + thread::sleep(self.delivery_time.min(d) - now); + } else { + thread::sleep(self.delivery_time - now); + } + } + + // Try receiving the message if it is still available. + if !self.received.swap(true, Ordering::SeqCst) { + // Success! Return the message, which is the instant at which it was delivered. + Ok(self.delivery_time) + } else { + // The message was already received. Block forever. + utils::sleep_until(None); + unreachable!() + } + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, token: &mut Token) -> Result { + token.after.ok_or(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + return true; + } + + // If the delivery time hasn't been reached yet, the channel is empty. + if Instant::now() < self.delivery_time { + return true; + } + + // The delivery time has been reached. The channel is empty only if the message has already + // been received. + self.received.load(Ordering::SeqCst) + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + !self.is_empty() + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + if self.is_empty() { + 0 + } else { + 1 + } + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(1) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, token: &mut Token) -> bool { + match self.try_recv() { + Ok(msg) => { + token.after = Some(msg); + true + } + Err(TryRecvError::Disconnected) => { + token.after = None; + true + } + Err(TryRecvError::Empty) => false, + } + } + + #[inline] + fn deadline(&self) -> Option { + // We use relaxed ordering because this is just an optional optimistic check. + if self.received.load(Ordering::Relaxed) { + None + } else { + Some(self.delivery_time) + } + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + !self.is_empty() + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/array.rs b/vendor/crossbeam-channel/src/flavors/array.rs new file mode 100644 index 0000000000..659fce69a1 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/array.rs @@ -0,0 +1,639 @@ +//! Bounded channel based on a preallocated array. +//! +//! This flavor has a fixed, positive capacity. +//! +//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. +//! +//! Source: +//! - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue +//! - https://docs.google.com/document/d/1yIAYmbvL3JxOKOjuCyon7JhW4cSv1wy5hC0ApeGMV9s/pub +//! +//! Copyright & License: +//! - Copyright (c) 2010-2011 Dmitry Vyukov +//! - Simplified BSD License and Apache License, Version 2.0 +//! - http://www.1024cores.net/home/code-license + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::mem; +use std::ptr; +use std::sync::atomic::{self, AtomicUsize, Ordering}; +use std::time::Instant; + +use crossbeam_utils::{Backoff, CachePadded}; + +use maybe_uninit::MaybeUninit; + +use context::Context; +use err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use select::{Operation, SelectHandle, Selected, Token}; +use waker::SyncWaker; + +/// A slot in a channel. +struct Slot { + /// The current stamp. + stamp: AtomicUsize, + + /// The message in this slot. + msg: UnsafeCell>, +} + +/// The token type for the array flavor. +#[derive(Debug)] +pub struct ArrayToken { + /// Slot to read from or write to. + slot: *const u8, + + /// Stamp to store into the slot after reading or writing. + stamp: usize, +} + +impl Default for ArrayToken { + #[inline] + fn default() -> Self { + ArrayToken { + slot: ptr::null(), + stamp: 0, + } + } +} + +/// Bounded channel based on a preallocated array. +pub struct Channel { + /// The head of the channel. + /// + /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but + /// packed into a single `usize`. The lower bits represent the index, while the upper bits + /// represent the lap. The mark bit in the head is always zero. + /// + /// Messages are popped from the head of the channel. + head: CachePadded, + + /// The tail of the channel. + /// + /// This value is a "stamp" consisting of an index into the buffer, a mark bit, and a lap, but + /// packed into a single `usize`. The lower bits represent the index, while the upper bits + /// represent the lap. The mark bit indicates that the channel is disconnected. + /// + /// Messages are pushed into the tail of the channel. + tail: CachePadded, + + /// The buffer holding slots. + buffer: *mut Slot, + + /// The channel capacity. + cap: usize, + + /// A stamp with the value of `{ lap: 1, mark: 0, index: 0 }`. + one_lap: usize, + + /// If this bit is set in the tail, that means the channel is disconnected. + mark_bit: usize, + + /// Senders waiting while the channel is full. + senders: SyncWaker, + + /// Receivers waiting while the channel is empty and not disconnected. + receivers: SyncWaker, + + /// Indicates that dropping a `Channel` may drop values of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Creates a bounded channel of capacity `cap`. + pub fn with_capacity(cap: usize) -> Self { + assert!(cap > 0, "capacity must be positive"); + + // Compute constants `mark_bit` and `one_lap`. + let mark_bit = (cap + 1).next_power_of_two(); + let one_lap = mark_bit * 2; + + // Head is initialized to `{ lap: 0, mark: 0, index: 0 }`. + let head = 0; + // Tail is initialized to `{ lap: 0, mark: 0, index: 0 }`. + let tail = 0; + + // Allocate a buffer of `cap` slots. + let buffer = { + let mut v = Vec::>::with_capacity(cap); + let ptr = v.as_mut_ptr(); + mem::forget(v); + ptr + }; + + // Initialize stamps in the slots. + for i in 0..cap { + unsafe { + // Set the stamp to `{ lap: 0, mark: 0, index: i }`. + let slot = buffer.add(i); + ptr::write(&mut (*slot).stamp, AtomicUsize::new(i)); + } + } + + Channel { + buffer, + cap, + one_lap, + mark_bit, + head: CachePadded::new(AtomicUsize::new(head)), + tail: CachePadded::new(AtomicUsize::new(tail)), + senders: SyncWaker::new(), + receivers: SyncWaker::new(), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut tail = self.tail.load(Ordering::Relaxed); + + loop { + // Check if the channel is disconnected. + if tail & self.mark_bit != 0 { + token.array.slot = ptr::null(); + token.array.stamp = 0; + return true; + } + + // Deconstruct the tail. + let index = tail & (self.mark_bit - 1); + let lap = tail & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the tail and the stamp match, we may attempt to push. + if tail == stamp { + let new_tail = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + tail + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the tail. + match self.tail.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Prepare the token for the follow-up call to `write`. + token.array.slot = slot as *const Slot as *const u8; + token.array.stamp = tail + 1; + return true; + } + Err(t) => { + tail = t; + backoff.spin(); + } + } + } else if stamp.wrapping_add(self.one_lap) == tail + 1 { + atomic::fence(Ordering::SeqCst); + let head = self.head.load(Ordering::Relaxed); + + // If the head lags one lap behind the tail as well... + if head.wrapping_add(self.one_lap) == tail { + // ...then the channel is full. + return false; + } + + backoff.spin(); + tail = self.tail.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + tail = self.tail.load(Ordering::Relaxed); + } + } + } + + /// Writes a message into the channel. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no slot, the channel is disconnected. + if token.array.slot.is_null() { + return Err(msg); + } + + let slot: &Slot = &*(token.array.slot as *const Slot); + + // Write the message into the slot and update the stamp. + slot.msg.get().write(MaybeUninit::new(msg)); + slot.stamp.store(token.array.stamp, Ordering::Release); + + // Wake a sleeping receiver. + self.receivers.notify(); + Ok(()) + } + + /// Attempts to reserve a slot for receiving a message. + fn start_recv(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut head = self.head.load(Ordering::Relaxed); + + loop { + // Deconstruct the head. + let index = head & (self.mark_bit - 1); + let lap = head & !(self.one_lap - 1); + + // Inspect the corresponding slot. + let slot = unsafe { &*self.buffer.add(index) }; + let stamp = slot.stamp.load(Ordering::Acquire); + + // If the the stamp is ahead of the head by 1, we may attempt to pop. + if head + 1 == stamp { + let new = if index + 1 < self.cap { + // Same lap, incremented index. + // Set to `{ lap: lap, mark: 0, index: index + 1 }`. + head + 1 + } else { + // One lap forward, index wraps around to zero. + // Set to `{ lap: lap.wrapping_add(1), mark: 0, index: 0 }`. + lap.wrapping_add(self.one_lap) + }; + + // Try moving the head. + match self.head.compare_exchange_weak( + head, + new, + Ordering::SeqCst, + Ordering::Relaxed, + ) { + Ok(_) => { + // Prepare the token for the follow-up call to `read`. + token.array.slot = slot as *const Slot as *const u8; + token.array.stamp = head.wrapping_add(self.one_lap); + return true; + } + Err(h) => { + head = h; + backoff.spin(); + } + } + } else if stamp == head { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.load(Ordering::Relaxed); + + // If the tail equals the head, that means the channel is empty. + if (tail & !self.mark_bit) == head { + // If the channel is disconnected... + if tail & self.mark_bit != 0 { + // ...then receive an error. + token.array.slot = ptr::null(); + token.array.stamp = 0; + return true; + } else { + // Otherwise, the receive operation is not ready. + return false; + } + } + + backoff.spin(); + head = self.head.load(Ordering::Relaxed); + } else { + // Snooze because we need to wait for the stamp to get updated. + backoff.snooze(); + head = self.head.load(Ordering::Relaxed); + } + } + } + + /// Reads a message from the channel. + pub unsafe fn read(&self, token: &mut Token) -> Result { + if token.array.slot.is_null() { + // The channel is disconnected. + return Err(()); + } + + let slot: &Slot = &*(token.array.slot as *const Slot); + + // Read the message from the slot and update the stamp. + let msg = slot.msg.get().read().assume_init(); + slot.stamp.store(token.array.stamp, Ordering::Release); + + // Wake a sleeping sender. + self.senders.notify(); + Ok(msg) + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + let token = &mut Token::default(); + if self.start_send(token) { + unsafe { self.write(token, msg).map_err(TrySendError::Disconnected) } + } else { + Err(TrySendError::Full(msg)) + } + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + loop { + // Try sending a message several times. + let backoff = Backoff::new(); + loop { + if self.start_send(token) { + let res = unsafe { self.write(token, msg) }; + return res.map_err(SendTimeoutError::Disconnected); + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(SendTimeoutError::Timeout(msg)); + } + } + + Context::with(|cx| { + // Prepare for blocking until a receiver wakes us up. + let oper = Operation::hook(token); + self.senders.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_full() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.senders.unregister(oper).unwrap(); + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + + if self.start_recv(token) { + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + loop { + // Try receiving a message several times. + let backoff = Backoff::new(); + loop { + if self.start_recv(token) { + let res = unsafe { self.read(token) }; + return res.map_err(|_| RecvTimeoutError::Disconnected); + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(RecvTimeoutError::Timeout); + } + } + + Context::with(|cx| { + // Prepare for blocking until a sender wakes us up. + let oper = Operation::hook(token); + self.receivers.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_empty() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.receivers.unregister(oper).unwrap(); + // If the channel was disconnected, we still have to check for remaining + // messages. + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + loop { + // Load the tail, then load the head. + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // If the tail didn't change, we've got consistent values to work with. + if self.tail.load(Ordering::SeqCst) == tail { + let hix = head & (self.mark_bit - 1); + let tix = tail & (self.mark_bit - 1); + + return if hix < tix { + tix - hix + } else if hix > tix { + self.cap - hix + tix + } else if (tail & !self.mark_bit) == head { + 0 + } else { + self.cap + }; + } + } + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + Some(self.cap) + } + + /// Disconnects the channel and wakes up all blocked senders and receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let tail = self.tail.fetch_or(self.mark_bit, Ordering::SeqCst); + + if tail & self.mark_bit == 0 { + self.senders.disconnect(); + self.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns `true` if the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + self.tail.load(Ordering::SeqCst) & self.mark_bit != 0 + } + + /// Returns `true` if the channel is empty. + pub fn is_empty(&self) -> bool { + let head = self.head.load(Ordering::SeqCst); + let tail = self.tail.load(Ordering::SeqCst); + + // Is the tail equal to the head? + // + // Note: If the head changes just before we load the tail, that means there was a moment + // when the channel was not empty, so it is safe to just return `false`. + (tail & !self.mark_bit) == head + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + let tail = self.tail.load(Ordering::SeqCst); + let head = self.head.load(Ordering::SeqCst); + + // Is the head lagging one lap behind tail? + // + // Note: If the tail changes just before we load the head, that means there was a moment + // when the channel was not full, so it is safe to just return `false`. + head.wrapping_add(self.one_lap) == tail & !self.mark_bit + } +} + +impl Drop for Channel { + fn drop(&mut self) { + // Get the index of the head. + let hix = self.head.load(Ordering::Relaxed) & (self.mark_bit - 1); + + // Loop over all slots that hold a message and drop them. + for i in 0..self.len() { + // Compute the index of the next slot holding a message. + let index = if hix + i < self.cap { + hix + i + } else { + hix + i - self.cap + }; + + unsafe { + let p = { + let slot = &mut *self.buffer.add(index); + let msg = &mut *slot.msg.get(); + msg.as_mut_ptr() + }; + p.drop_in_place(); + } + } + + // Finally, deallocate the buffer, but don't run any destructors. + unsafe { + Vec::from_raw_parts(self.buffer, 0, self.cap); + } + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T: 'a>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T: 'a>(&'a Channel); + +impl<'a, T> SelectHandle for Receiver<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.receivers.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_empty() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.receivers.unwatch(oper); + } +} + +impl<'a, T> SelectHandle for Sender<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.senders.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.senders.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_full() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.senders.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.senders.unwatch(oper); + } +} diff --git a/vendor/crossbeam-channel/src/flavors/list.rs b/vendor/crossbeam-channel/src/flavors/list.rs new file mode 100644 index 0000000000..dd9e6e9dee --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/list.rs @@ -0,0 +1,671 @@ +//! Unbounded channel implemented as a linked list. + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::ptr; +use std::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; +use std::time::Instant; + +use crossbeam_utils::{Backoff, CachePadded}; + +use maybe_uninit::MaybeUninit; + +use context::Context; +use err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use select::{Operation, SelectHandle, Selected, Token}; +use waker::SyncWaker; + +// TODO(stjepang): Once we bump the minimum required Rust version to 1.28 or newer, re-apply the +// following changes by @kleimkuhler: +// +// 1. https://github.com/crossbeam-rs/crossbeam-channel/pull/100 +// 2. https://github.com/crossbeam-rs/crossbeam-channel/pull/101 + +// Bits indicating the state of a slot: +// * If a message has been written into the slot, `WRITE` is set. +// * If a message has been read from the slot, `READ` is set. +// * If the block is being destroyed, `DESTROY` is set. +const WRITE: usize = 1; +const READ: usize = 2; +const DESTROY: usize = 4; + +// Each block covers one "lap" of indices. +const LAP: usize = 32; +// The maximum number of messages a block can hold. +const BLOCK_CAP: usize = LAP - 1; +// How many lower bits are reserved for metadata. +const SHIFT: usize = 1; +// Has two different purposes: +// * If set in head, indicates that the block is not the last one. +// * If set in tail, indicates that the channel is disconnected. +const MARK_BIT: usize = 1; + +/// A slot in a block. +struct Slot { + /// The message. + msg: UnsafeCell>, + + /// The state of the slot. + state: AtomicUsize, +} + +impl Slot { + /// Waits until a message is written into the slot. + fn wait_write(&self) { + let backoff = Backoff::new(); + while self.state.load(Ordering::Acquire) & WRITE == 0 { + backoff.snooze(); + } + } +} + +/// A block in a linked list. +/// +/// Each block in the list can hold up to `BLOCK_CAP` messages. +struct Block { + /// The next block in the linked list. + next: AtomicPtr>, + + /// Slots for messages. + slots: [Slot; BLOCK_CAP], +} + +impl Block { + /// Creates an empty block. + fn new() -> Block { + // SAFETY: This is safe because: + // [1] `Block::next` (AtomicPtr) may be safely zero initialized. + // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. + // [3] `Slot::msg` (UnsafeCell) may be safely zero initialized because it + // holds a MaybeUninit. + // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. + unsafe { MaybeUninit::zeroed().assume_init() } + } + + /// Waits until the next pointer is set. + fn wait_next(&self) -> *mut Block { + let backoff = Backoff::new(); + loop { + let next = self.next.load(Ordering::Acquire); + if !next.is_null() { + return next; + } + backoff.snooze(); + } + } + + /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. + unsafe fn destroy(this: *mut Block, start: usize) { + // It is not necessary to set the `DESTROY bit in the last slot because that slot has begun + // destruction of the block. + for i in start..BLOCK_CAP - 1 { + let slot = (*this).slots.get_unchecked(i); + + // Mark the `DESTROY` bit if a thread is still using the slot. + if slot.state.load(Ordering::Acquire) & READ == 0 + && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 + { + // If a thread is still using the slot, it will continue destruction of the block. + return; + } + } + + // No thread is using the block, now it is safe to destroy it. + drop(Box::from_raw(this)); + } +} + +/// A position in a channel. +#[derive(Debug)] +struct Position { + /// The index in the channel. + index: AtomicUsize, + + /// The block in the linked list. + block: AtomicPtr>, +} + +/// The token type for the list flavor. +#[derive(Debug)] +pub struct ListToken { + /// The block of slots. + block: *const u8, + + /// The offset into the block. + offset: usize, +} + +impl Default for ListToken { + #[inline] + fn default() -> Self { + ListToken { + block: ptr::null(), + offset: 0, + } + } +} + +/// Unbounded channel implemented as a linked list. +/// +/// Each message sent into the channel is assigned a sequence number, i.e. an index. Indices are +/// represented as numbers of type `usize` and wrap on overflow. +/// +/// Consecutive messages are grouped into blocks in order to put less pressure on the allocator and +/// improve cache efficiency. +pub struct Channel { + /// The head of the channel. + head: CachePadded>, + + /// The tail of the channel. + tail: CachePadded>, + + /// Receivers waiting while the channel is empty and not disconnected. + receivers: SyncWaker, + + /// Indicates that dropping a `Channel` may drop messages of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Creates a new unbounded channel. + pub fn new() -> Self { + Channel { + head: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + tail: CachePadded::new(Position { + block: AtomicPtr::new(ptr::null_mut()), + index: AtomicUsize::new(0), + }), + receivers: SyncWaker::new(), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut tail = self.tail.index.load(Ordering::Acquire); + let mut block = self.tail.block.load(Ordering::Acquire); + let mut next_block = None; + + loop { + // Check if the channel is disconnected. + if tail & MARK_BIT != 0 { + token.list.block = ptr::null(); + return true; + } + + // Calculate the offset of the index into the block. + let offset = (tail >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + + // If we're going to have to install the next block, allocate it in advance in order to + // make the wait for other threads as short as possible. + if offset + 1 == BLOCK_CAP && next_block.is_none() { + next_block = Some(Box::new(Block::::new())); + } + + // If this is the first message to be sent into the channel, we need to allocate the + // first block and install it. + if block.is_null() { + let new = Box::into_raw(Box::new(Block::::new())); + + if self + .tail + .block + .compare_and_swap(block, new, Ordering::Release) + == block + { + self.head.block.store(new, Ordering::Release); + block = new; + } else { + next_block = unsafe { Some(Box::from_raw(new)) }; + tail = self.tail.index.load(Ordering::Acquire); + block = self.tail.block.load(Ordering::Acquire); + continue; + } + } + + let new_tail = tail + (1 << SHIFT); + + // Try advancing the tail forward. + match self.tail.index.compare_exchange_weak( + tail, + new_tail, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, install the next one. + if offset + 1 == BLOCK_CAP { + let next_block = Box::into_raw(next_block.unwrap()); + self.tail.block.store(next_block, Ordering::Release); + self.tail.index.fetch_add(1 << SHIFT, Ordering::Release); + (*block).next.store(next_block, Ordering::Release); + } + + token.list.block = block as *const u8; + token.list.offset = offset; + return true; + }, + Err(t) => { + tail = t; + block = self.tail.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Writes a message into the channel. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no slot, the channel is disconnected. + if token.list.block.is_null() { + return Err(msg); + } + + // Write the message into the slot. + let block = token.list.block as *mut Block; + let offset = token.list.offset; + let slot = (*block).slots.get_unchecked(offset); + slot.msg.get().write(MaybeUninit::new(msg)); + slot.state.fetch_or(WRITE, Ordering::Release); + + // Wake a sleeping receiver. + self.receivers.notify(); + Ok(()) + } + + /// Attempts to reserve a slot for receiving a message. + fn start_recv(&self, token: &mut Token) -> bool { + let backoff = Backoff::new(); + let mut head = self.head.index.load(Ordering::Acquire); + let mut block = self.head.block.load(Ordering::Acquire); + + loop { + // Calculate the offset of the index into the block. + let offset = (head >> SHIFT) % LAP; + + // If we reached the end of the block, wait until the next one is installed. + if offset == BLOCK_CAP { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + let mut new_head = head + (1 << SHIFT); + + if new_head & MARK_BIT == 0 { + atomic::fence(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::Relaxed); + + // If the tail equals the head, that means the channel is empty. + if head >> SHIFT == tail >> SHIFT { + // If the channel is disconnected... + if tail & MARK_BIT != 0 { + // ...then receive an error. + token.list.block = ptr::null(); + return true; + } else { + // Otherwise, the receive operation is not ready. + return false; + } + } + + // If head and tail are not in the same block, set `MARK_BIT` in head. + if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { + new_head |= MARK_BIT; + } + } + + // The block can be null here only if the first message is being sent into the channel. + // In that case, just wait until it gets initialized. + if block.is_null() { + backoff.snooze(); + head = self.head.index.load(Ordering::Acquire); + block = self.head.block.load(Ordering::Acquire); + continue; + } + + // Try moving the head index forward. + match self.head.index.compare_exchange_weak( + head, + new_head, + Ordering::SeqCst, + Ordering::Acquire, + ) { + Ok(_) => unsafe { + // If we've reached the end of the block, move to the next one. + if offset + 1 == BLOCK_CAP { + let next = (*block).wait_next(); + let mut next_index = (new_head & !MARK_BIT).wrapping_add(1 << SHIFT); + if !(*next).next.load(Ordering::Relaxed).is_null() { + next_index |= MARK_BIT; + } + + self.head.block.store(next, Ordering::Release); + self.head.index.store(next_index, Ordering::Release); + } + + token.list.block = block as *const u8; + token.list.offset = offset; + return true; + }, + Err(h) => { + head = h; + block = self.head.block.load(Ordering::Acquire); + backoff.spin(); + } + } + } + } + + /// Reads a message from the channel. + pub unsafe fn read(&self, token: &mut Token) -> Result { + if token.list.block.is_null() { + // The channel is disconnected. + return Err(()); + } + + // Read the message. + let block = token.list.block as *mut Block; + let offset = token.list.offset; + let slot = (*block).slots.get_unchecked(offset); + slot.wait_write(); + let msg = slot.msg.get().read().assume_init(); + + // Destroy the block if we've reached the end, or if another thread wanted to destroy but + // couldn't because we were busy reading from the slot. + if offset + 1 == BLOCK_CAP { + Block::destroy(block, 0); + } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { + Block::destroy(block, offset + 1); + } + + Ok(msg) + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + self.send(msg, None).map_err(|err| match err { + SendTimeoutError::Disconnected(msg) => TrySendError::Disconnected(msg), + SendTimeoutError::Timeout(_) => unreachable!(), + }) + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, _deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + assert!(self.start_send(token)); + unsafe { + self.write(token, msg) + .map_err(SendTimeoutError::Disconnected) + } + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + + if self.start_recv(token) { + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + loop { + // Try receiving a message several times. + let backoff = Backoff::new(); + loop { + if self.start_recv(token) { + unsafe { + return self.read(token).map_err(|_| RecvTimeoutError::Disconnected); + } + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + if let Some(d) = deadline { + if Instant::now() >= d { + return Err(RecvTimeoutError::Timeout); + } + } + + // Prepare for blocking until a sender wakes us up. + Context::with(|cx| { + let oper = Operation::hook(token); + self.receivers.register(oper, cx); + + // Has the channel become ready just now? + if !self.is_empty() || self.is_disconnected() { + let _ = cx.try_select(Selected::Aborted); + } + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted | Selected::Disconnected => { + self.receivers.unregister(oper).unwrap(); + // If the channel was disconnected, we still have to check for remaining + // messages. + } + Selected::Operation(_) => {} + } + }); + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + loop { + // Load the tail index, then load the head index. + let mut tail = self.tail.index.load(Ordering::SeqCst); + let mut head = self.head.index.load(Ordering::SeqCst); + + // If the tail index didn't change, we've got consistent indices to work with. + if self.tail.index.load(Ordering::SeqCst) == tail { + // Erase the lower bits. + tail &= !((1 << SHIFT) - 1); + head &= !((1 << SHIFT) - 1); + + // Rotate indices so that head falls into the first block. + let lap = (head >> SHIFT) / LAP; + tail = tail.wrapping_sub((lap * LAP) << SHIFT); + head = head.wrapping_sub((lap * LAP) << SHIFT); + + // Remove the lower bits. + tail >>= SHIFT; + head >>= SHIFT; + + // Fix up indices if they fall onto block ends. + if head == BLOCK_CAP { + head = 0; + tail -= LAP; + } + if tail == BLOCK_CAP { + tail += 1; + } + + // Return the difference minus the number of blocks between tail and head. + return tail - head - tail / LAP; + } + } + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + None + } + + /// Disconnects the channel and wakes up all blocked receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let tail = self.tail.index.fetch_or(MARK_BIT, Ordering::SeqCst); + + if tail & MARK_BIT == 0 { + self.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns `true` if the channel is disconnected. + pub fn is_disconnected(&self) -> bool { + self.tail.index.load(Ordering::SeqCst) & MARK_BIT != 0 + } + + /// Returns `true` if the channel is empty. + pub fn is_empty(&self) -> bool { + let head = self.head.index.load(Ordering::SeqCst); + let tail = self.tail.index.load(Ordering::SeqCst); + head >> SHIFT == tail >> SHIFT + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + false + } +} + +impl Drop for Channel { + fn drop(&mut self) { + let mut head = self.head.index.load(Ordering::Relaxed); + let mut tail = self.tail.index.load(Ordering::Relaxed); + let mut block = self.head.block.load(Ordering::Relaxed); + + // Erase the lower bits. + head &= !((1 << SHIFT) - 1); + tail &= !((1 << SHIFT) - 1); + + unsafe { + // Drop all messages between head and tail and deallocate the heap-allocated blocks. + while head != tail { + let offset = (head >> SHIFT) % LAP; + + if offset < BLOCK_CAP { + // Drop the message in the slot. + let slot = (*block).slots.get_unchecked(offset); + let p = &mut *slot.msg.get(); + p.as_mut_ptr().drop_in_place(); + } else { + // Deallocate the block and move to the next one. + let next = (*block).next.load(Ordering::Relaxed); + drop(Box::from_raw(block)); + block = next; + } + + head = head.wrapping_add(1 << SHIFT); + } + + // Deallocate the last remaining block. + if !block.is_null() { + drop(Box::from_raw(block)); + } + } + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T: 'a>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T: 'a>(&'a Channel); + +impl<'a, T> SelectHandle for Receiver<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.register(oper, cx); + self.is_ready() + } + + fn unregister(&self, oper: Operation) { + self.0.receivers.unregister(oper); + } + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + !self.0.is_empty() || self.0.is_disconnected() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + self.0.receivers.watch(oper, cx); + self.is_ready() + } + + fn unwatch(&self, oper: Operation) { + self.0.receivers.unwatch(oper); + } +} + +impl<'a, T> SelectHandle for Sender<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + fn unregister(&self, _oper: Operation) {} + + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + fn is_ready(&self) -> bool { + true + } + + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/mod.rs b/vendor/crossbeam-channel/src/flavors/mod.rs new file mode 100644 index 0000000000..ebd0cfa540 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/mod.rs @@ -0,0 +1,17 @@ +//! Channel flavors. +//! +//! There are six flavors: +//! +//! 1. `after` - Channel that delivers a message after a certain amount of time. +//! 2. `array` - Bounded channel based on a preallocated array. +//! 3. `list` - Unbounded channel implemented as a linked list. +//! 4. `never` - Channel that never delivers messages. +//! 5. `tick` - Channel that delivers messages periodically. +//! 6. `zero` - Zero-capacity channel. + +pub mod after; +pub mod array; +pub mod list; +pub mod never; +pub mod tick; +pub mod zero; diff --git a/vendor/crossbeam-channel/src/flavors/never.rs b/vendor/crossbeam-channel/src/flavors/never.rs new file mode 100644 index 0000000000..5fb12e67ed --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/never.rs @@ -0,0 +1,110 @@ +//! Channel that never delivers messages. +//! +//! Messages cannot be sent into this kind of channel. + +use std::marker::PhantomData; +use std::time::Instant; + +use context::Context; +use err::{RecvTimeoutError, TryRecvError}; +use select::{Operation, SelectHandle, Token}; +use utils; + +/// This flavor doesn't need a token. +pub type NeverToken = (); + +/// Channel that never delivers messages. +pub struct Channel { + _marker: PhantomData, +} + +impl Channel { + /// Creates a channel that never delivers messages. + #[inline] + pub fn new() -> Self { + Channel { + _marker: PhantomData, + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + Err(TryRecvError::Empty) + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + utils::sleep_until(deadline); + Err(RecvTimeoutError::Timeout) + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, _token: &mut Token) -> Result { + Err(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + true + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + true + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + 0 + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(0) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, _token: &mut Token) -> bool { + false + } + + #[inline] + fn deadline(&self) -> Option { + None + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + false + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/tick.rs b/vendor/crossbeam-channel/src/flavors/tick.rs new file mode 100644 index 0000000000..2941117614 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/tick.rs @@ -0,0 +1,167 @@ +//! Channel that delivers messages periodically. +//! +//! Messages cannot be sent into this kind of channel; they are materialized on demand. + +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_utils::atomic::AtomicCell; + +use context::Context; +use err::{RecvTimeoutError, TryRecvError}; +use select::{Operation, SelectHandle, Token}; + +/// Result of a receive operation. +pub type TickToken = Option; + +/// Channel that delivers messages periodically. +pub struct Channel { + /// The instant at which the next message will be delivered. + delivery_time: AtomicCell, + + /// The time interval in which messages get delivered. + duration: Duration, +} + +impl Channel { + /// Creates a channel that delivers messages periodically. + #[inline] + pub fn new(dur: Duration) -> Self { + Channel { + delivery_time: AtomicCell::new(Instant::now() + dur), + duration: dur, + } + } + + /// Attempts to receive a message without blocking. + #[inline] + pub fn try_recv(&self) -> Result { + loop { + let now = Instant::now(); + let delivery_time = self.delivery_time.load(); + + if now < delivery_time { + return Err(TryRecvError::Empty); + } + + if self + .delivery_time + .compare_exchange(delivery_time, now + self.duration) + .is_ok() + { + return Ok(delivery_time); + } + } + } + + /// Receives a message from the channel. + #[inline] + pub fn recv(&self, deadline: Option) -> Result { + loop { + let delivery_time = self.delivery_time.load(); + let now = Instant::now(); + + if let Some(d) = deadline { + if d < delivery_time { + if now < d { + thread::sleep(d - now); + } + return Err(RecvTimeoutError::Timeout); + } + } + + if self + .delivery_time + .compare_exchange(delivery_time, delivery_time.max(now) + self.duration) + .is_ok() + { + if now < delivery_time { + thread::sleep(delivery_time - now); + } + return Ok(delivery_time); + } + } + } + + /// Reads a message from the channel. + #[inline] + pub unsafe fn read(&self, token: &mut Token) -> Result { + token.tick.ok_or(()) + } + + /// Returns `true` if the channel is empty. + #[inline] + pub fn is_empty(&self) -> bool { + Instant::now() < self.delivery_time.load() + } + + /// Returns `true` if the channel is full. + #[inline] + pub fn is_full(&self) -> bool { + !self.is_empty() + } + + /// Returns the number of messages in the channel. + #[inline] + pub fn len(&self) -> usize { + if self.is_empty() { + 0 + } else { + 1 + } + } + + /// Returns the capacity of the channel. + #[inline] + pub fn capacity(&self) -> Option { + Some(1) + } +} + +impl SelectHandle for Channel { + #[inline] + fn try_select(&self, token: &mut Token) -> bool { + match self.try_recv() { + Ok(msg) => { + token.tick = Some(msg); + true + } + Err(TryRecvError::Disconnected) => { + token.tick = None; + true + } + Err(TryRecvError::Empty) => false, + } + } + + #[inline] + fn deadline(&self) -> Option { + Some(self.delivery_time.load()) + } + + #[inline] + fn register(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unregister(&self, _oper: Operation) {} + + #[inline] + fn accept(&self, token: &mut Token, _cx: &Context) -> bool { + self.try_select(token) + } + + #[inline] + fn is_ready(&self) -> bool { + !self.is_empty() + } + + #[inline] + fn watch(&self, _oper: Operation, _cx: &Context) -> bool { + self.is_ready() + } + + #[inline] + fn unwatch(&self, _oper: Operation) {} +} diff --git a/vendor/crossbeam-channel/src/flavors/zero.rs b/vendor/crossbeam-channel/src/flavors/zero.rs new file mode 100644 index 0000000000..ee1bfc5344 --- /dev/null +++ b/vendor/crossbeam-channel/src/flavors/zero.rs @@ -0,0 +1,466 @@ +//! Zero-capacity channel. +//! +//! This kind of channel is also known as *rendezvous* channel. + +use std::cell::UnsafeCell; +use std::marker::PhantomData; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::time::Instant; + +use crossbeam_utils::Backoff; + +use context::Context; +use err::{RecvTimeoutError, SendTimeoutError, TryRecvError, TrySendError}; +use select::{Operation, SelectHandle, Selected, Token}; +use utils::Spinlock; +use waker::Waker; + +/// A pointer to a packet. +pub type ZeroToken = usize; + +/// A slot for passing one message from a sender to a receiver. +struct Packet { + /// Equals `true` if the packet is allocated on the stack. + on_stack: bool, + + /// Equals `true` once the packet is ready for reading or writing. + ready: AtomicBool, + + /// The message. + msg: UnsafeCell>, +} + +impl Packet { + /// Creates an empty packet on the stack. + fn empty_on_stack() -> Packet { + Packet { + on_stack: true, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(None), + } + } + + /// Creates an empty packet on the heap. + fn empty_on_heap() -> Box> { + Box::new(Packet { + on_stack: false, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(None), + }) + } + + /// Creates a packet on the stack, containing a message. + fn message_on_stack(msg: T) -> Packet { + Packet { + on_stack: true, + ready: AtomicBool::new(false), + msg: UnsafeCell::new(Some(msg)), + } + } + + /// Waits until the packet becomes ready for reading or writing. + fn wait_ready(&self) { + let backoff = Backoff::new(); + while !self.ready.load(Ordering::Acquire) { + backoff.snooze(); + } + } +} + +/// Inner representation of a zero-capacity channel. +struct Inner { + /// Senders waiting to pair up with a receive operation. + senders: Waker, + + /// Receivers waiting to pair up with a send operation. + receivers: Waker, + + /// Equals `true` when the channel is disconnected. + is_disconnected: bool, +} + +/// Zero-capacity channel. +pub struct Channel { + /// Inner representation of the channel. + inner: Spinlock, + + /// Indicates that dropping a `Channel` may drop values of type `T`. + _marker: PhantomData, +} + +impl Channel { + /// Constructs a new zero-capacity channel. + pub fn new() -> Self { + Channel { + inner: Spinlock::new(Inner { + senders: Waker::new(), + receivers: Waker::new(), + is_disconnected: false, + }), + _marker: PhantomData, + } + } + + /// Returns a receiver handle to the channel. + pub fn receiver(&self) -> Receiver { + Receiver(self) + } + + /// Returns a sender handle to the channel. + pub fn sender(&self) -> Sender { + Sender(self) + } + + /// Attempts to reserve a slot for sending a message. + fn start_send(&self, token: &mut Token) -> bool { + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + true + } else if inner.is_disconnected { + token.zero = 0; + true + } else { + false + } + } + + /// Writes a message into the packet. + pub unsafe fn write(&self, token: &mut Token, msg: T) -> Result<(), T> { + // If there is no packet, the channel is disconnected. + if token.zero == 0 { + return Err(msg); + } + + let packet = &*(token.zero as *const Packet); + packet.msg.get().write(Some(msg)); + packet.ready.store(true, Ordering::Release); + Ok(()) + } + + /// Attempts to pair up with a sender. + fn start_recv(&self, token: &mut Token) -> bool { + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + true + } else if inner.is_disconnected { + token.zero = 0; + true + } else { + false + } + } + + /// Reads a message from the packet. + pub unsafe fn read(&self, token: &mut Token) -> Result { + // If there is no packet, the channel is disconnected. + if token.zero == 0 { + return Err(()); + } + + let packet = &*(token.zero as *const Packet); + + if packet.on_stack { + // The message has been in the packet from the beginning, so there is no need to wait + // for it. However, after reading the message, we need to set `ready` to `true` in + // order to signal that the packet can be destroyed. + let msg = packet.msg.get().replace(None).unwrap(); + packet.ready.store(true, Ordering::Release); + Ok(msg) + } else { + // Wait until the message becomes available, then read it and destroy the + // heap-allocated packet. + packet.wait_ready(); + let msg = packet.msg.get().replace(None).unwrap(); + drop(Box::from_raw(packet as *const Packet as *mut Packet)); + Ok(msg) + } + } + + /// Attempts to send a message into the channel. + pub fn try_send(&self, msg: T) -> Result<(), TrySendError> { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + self.write(token, msg).ok().unwrap(); + } + Ok(()) + } else if inner.is_disconnected { + Err(TrySendError::Disconnected(msg)) + } else { + Err(TrySendError::Full(msg)) + } + } + + /// Sends a message into the channel. + pub fn send(&self, msg: T, deadline: Option) -> Result<(), SendTimeoutError> { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting receiver, pair up with it. + if let Some(operation) = inner.receivers.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + self.write(token, msg).ok().unwrap(); + } + return Ok(()); + } + + if inner.is_disconnected { + return Err(SendTimeoutError::Disconnected(msg)); + } + + Context::with(|cx| { + // Prepare for blocking until a receiver wakes us up. + let oper = Operation::hook(token); + let packet = Packet::::message_on_stack(msg); + inner + .senders + .register_with_packet(oper, &packet as *const Packet as usize, cx); + inner.receivers.notify(); + drop(inner); + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + self.inner.lock().senders.unregister(oper).unwrap(); + let msg = unsafe { packet.msg.get().replace(None).unwrap() }; + Err(SendTimeoutError::Timeout(msg)) + } + Selected::Disconnected => { + self.inner.lock().senders.unregister(oper).unwrap(); + let msg = unsafe { packet.msg.get().replace(None).unwrap() }; + Err(SendTimeoutError::Disconnected(msg)) + } + Selected::Operation(_) => { + // Wait until the message is read, then drop the packet. + packet.wait_ready(); + Ok(()) + } + } + }) + } + + /// Attempts to receive a message without blocking. + pub fn try_recv(&self) -> Result { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { self.read(token).map_err(|_| TryRecvError::Disconnected) } + } else if inner.is_disconnected { + Err(TryRecvError::Disconnected) + } else { + Err(TryRecvError::Empty) + } + } + + /// Receives a message from the channel. + pub fn recv(&self, deadline: Option) -> Result { + let token = &mut Token::default(); + let mut inner = self.inner.lock(); + + // If there's a waiting sender, pair up with it. + if let Some(operation) = inner.senders.try_select() { + token.zero = operation.packet; + drop(inner); + unsafe { + return self.read(token).map_err(|_| RecvTimeoutError::Disconnected); + } + } + + if inner.is_disconnected { + return Err(RecvTimeoutError::Disconnected); + } + + Context::with(|cx| { + // Prepare for blocking until a sender wakes us up. + let oper = Operation::hook(token); + let packet = Packet::::empty_on_stack(); + inner + .receivers + .register_with_packet(oper, &packet as *const Packet as usize, cx); + inner.senders.notify(); + drop(inner); + + // Block the current thread. + let sel = cx.wait_until(deadline); + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + self.inner.lock().receivers.unregister(oper).unwrap(); + Err(RecvTimeoutError::Timeout) + } + Selected::Disconnected => { + self.inner.lock().receivers.unregister(oper).unwrap(); + Err(RecvTimeoutError::Disconnected) + } + Selected::Operation(_) => { + // Wait until the message is provided, then read it. + packet.wait_ready(); + unsafe { Ok(packet.msg.get().replace(None).unwrap()) } + } + } + }) + } + + /// Disconnects the channel and wakes up all blocked senders and receivers. + /// + /// Returns `true` if this call disconnected the channel. + pub fn disconnect(&self) -> bool { + let mut inner = self.inner.lock(); + + if !inner.is_disconnected { + inner.is_disconnected = true; + inner.senders.disconnect(); + inner.receivers.disconnect(); + true + } else { + false + } + } + + /// Returns the current number of messages inside the channel. + pub fn len(&self) -> usize { + 0 + } + + /// Returns the capacity of the channel. + pub fn capacity(&self) -> Option { + Some(0) + } + + /// Returns `true` if the channel is empty. + pub fn is_empty(&self) -> bool { + true + } + + /// Returns `true` if the channel is full. + pub fn is_full(&self) -> bool { + true + } +} + +/// Receiver handle to a channel. +pub struct Receiver<'a, T: 'a>(&'a Channel); + +/// Sender handle to a channel. +pub struct Sender<'a, T: 'a>(&'a Channel); + +impl<'a, T> SelectHandle for Receiver<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_recv(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + let packet = Box::into_raw(Packet::::empty_on_heap()); + + let mut inner = self.0.inner.lock(); + inner + .receivers + .register_with_packet(oper, packet as usize, cx); + inner.senders.notify(); + inner.senders.can_select() || inner.is_disconnected + } + + fn unregister(&self, oper: Operation) { + if let Some(operation) = self.0.inner.lock().receivers.unregister(oper) { + unsafe { + drop(Box::from_raw(operation.packet as *mut Packet)); + } + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + token.zero = cx.wait_packet(); + true + } + + fn is_ready(&self) -> bool { + let inner = self.0.inner.lock(); + inner.senders.can_select() || inner.is_disconnected + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + let mut inner = self.0.inner.lock(); + inner.receivers.watch(oper, cx); + inner.senders.can_select() || inner.is_disconnected + } + + fn unwatch(&self, oper: Operation) { + let mut inner = self.0.inner.lock(); + inner.receivers.unwatch(oper); + } +} + +impl<'a, T> SelectHandle for Sender<'a, T> { + fn try_select(&self, token: &mut Token) -> bool { + self.0.start_send(token) + } + + fn deadline(&self) -> Option { + None + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + let packet = Box::into_raw(Packet::::empty_on_heap()); + + let mut inner = self.0.inner.lock(); + inner + .senders + .register_with_packet(oper, packet as usize, cx); + inner.receivers.notify(); + inner.receivers.can_select() || inner.is_disconnected + } + + fn unregister(&self, oper: Operation) { + if let Some(operation) = self.0.inner.lock().senders.unregister(oper) { + unsafe { + drop(Box::from_raw(operation.packet as *mut Packet)); + } + } + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + token.zero = cx.wait_packet(); + true + } + + fn is_ready(&self) -> bool { + let inner = self.0.inner.lock(); + inner.receivers.can_select() || inner.is_disconnected + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + let mut inner = self.0.inner.lock(); + inner.senders.watch(oper, cx); + inner.receivers.can_select() || inner.is_disconnected + } + + fn unwatch(&self, oper: Operation) { + let mut inner = self.0.inner.lock(); + inner.senders.unwatch(oper); + } +} diff --git a/vendor/crossbeam-channel/src/lib.rs b/vendor/crossbeam-channel/src/lib.rs new file mode 100644 index 0000000000..898239632f --- /dev/null +++ b/vendor/crossbeam-channel/src/lib.rs @@ -0,0 +1,379 @@ +//! Multi-producer multi-consumer channels for message passing. +//! +//! This crate is an alternative to [`std::sync::mpsc`] with more features and better performance. +//! +//! # Hello, world! +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! // Create a channel of unbounded capacity. +//! let (s, r) = unbounded(); +//! +//! // Send a message into the channel. +//! s.send("Hello, world!").unwrap(); +//! +//! // Receive the message from the channel. +//! assert_eq!(r.recv(), Ok("Hello, world!")); +//! ``` +//! +//! # Channel types +//! +//! Channels can be created using two functions: +//! +//! * [`bounded`] creates a channel of bounded capacity, i.e. there is a limit to how many messages +//! it can hold at a time. +//! +//! * [`unbounded`] creates a channel of unbounded capacity, i.e. it can hold any number of +//! messages at a time. +//! +//! Both functions return a [`Sender`] and a [`Receiver`], which represent the two opposite sides +//! of a channel. +//! +//! Creating a bounded channel: +//! +//! ``` +//! use crossbeam_channel::bounded; +//! +//! // Create a channel that can hold at most 5 messages at a time. +//! let (s, r) = bounded(5); +//! +//! // Can send only 5 messages without blocking. +//! for i in 0..5 { +//! s.send(i).unwrap(); +//! } +//! +//! // Another call to `send` would block because the channel is full. +//! // s.send(5).unwrap(); +//! ``` +//! +//! Creating an unbounded channel: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! // Create an unbounded channel. +//! let (s, r) = unbounded(); +//! +//! // Can send any number of messages into the channel without blocking. +//! for i in 0..1000 { +//! s.send(i).unwrap(); +//! } +//! ``` +//! +//! A special case is zero-capacity channel, which cannot hold any messages. Instead, send and +//! receive operations must appear at the same time in order to pair up and pass the message over: +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::bounded; +//! +//! // Create a zero-capacity channel. +//! let (s, r) = bounded(0); +//! +//! // Sending blocks until a receive operation appears on the other side. +//! thread::spawn(move || s.send("Hi!").unwrap()); +//! +//! // Receiving blocks until a send operation appears on the other side. +//! assert_eq!(r.recv(), Ok("Hi!")); +//! ``` +//! +//! # Sharing channels +//! +//! Senders and receivers can be cloned and sent to other threads: +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::bounded; +//! +//! let (s1, r1) = bounded(0); +//! let (s2, r2) = (s1.clone(), r1.clone()); +//! +//! // Spawn a thread that receives a message and then sends one. +//! thread::spawn(move || { +//! r2.recv().unwrap(); +//! s2.send(2).unwrap(); +//! }); +//! +//! // Send a message and then receive one. +//! s1.send(1).unwrap(); +//! r1.recv().unwrap(); +//! ``` +//! +//! Note that cloning only creates a new handle to the same sending or receiving side. It does not +//! create a separate stream of messages in any way: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! let (s1, r1) = unbounded(); +//! let (s2, r2) = (s1.clone(), r1.clone()); +//! let (s3, r3) = (s2.clone(), r2.clone()); +//! +//! s1.send(10).unwrap(); +//! s2.send(20).unwrap(); +//! s3.send(30).unwrap(); +//! +//! assert_eq!(r3.recv(), Ok(10)); +//! assert_eq!(r1.recv(), Ok(20)); +//! assert_eq!(r2.recv(), Ok(30)); +//! ``` +//! +//! It's also possible to share senders and receivers by reference: +//! +//! ``` +//! # extern crate crossbeam_channel; +//! # extern crate crossbeam_utils; +//! # fn main() { +//! use std::thread; +//! use crossbeam_channel::bounded; +//! use crossbeam_utils::thread::scope; +//! +//! let (s, r) = bounded(0); +//! +//! scope(|scope| { +//! // Spawn a thread that receives a message and then sends one. +//! scope.spawn(|_| { +//! r.recv().unwrap(); +//! s.send(2).unwrap(); +//! }); +//! +//! // Send a message and then receive one. +//! s.send(1).unwrap(); +//! r.recv().unwrap(); +//! }).unwrap(); +//! # } +//! ``` +//! +//! # Disconnection +//! +//! When all senders or all receivers associated with a channel get dropped, the channel becomes +//! disconnected. No more messages can be sent, but any remaining messages can still be received. +//! Send and receive operations on a disconnected channel never block. +//! +//! ``` +//! use crossbeam_channel::{unbounded, RecvError}; +//! +//! let (s, r) = unbounded(); +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! +//! // The only sender is dropped, disconnecting the channel. +//! drop(s); +//! +//! // The remaining messages can be received. +//! assert_eq!(r.recv(), Ok(1)); +//! assert_eq!(r.recv(), Ok(2)); +//! assert_eq!(r.recv(), Ok(3)); +//! +//! // There are no more messages in the channel. +//! assert!(r.is_empty()); +//! +//! // Note that calling `r.recv()` does not block. +//! // Instead, `Err(RecvError)` is returned immediately. +//! assert_eq!(r.recv(), Err(RecvError)); +//! ``` +//! +//! # Blocking operations +//! +//! Send and receive operations come in three flavors: +//! +//! * Non-blocking (returns immediately with success or failure). +//! * Blocking (waits until the operation succeeds or the channel becomes disconnected). +//! * Blocking with a timeout (blocks only for a certain duration of time). +//! +//! A simple example showing the difference between non-blocking and blocking operations: +//! +//! ``` +//! use crossbeam_channel::{bounded, RecvError, TryRecvError}; +//! +//! let (s, r) = bounded(1); +//! +//! // Send a message into the channel. +//! s.send("foo").unwrap(); +//! +//! // This call would block because the channel is full. +//! // s.send("bar").unwrap(); +//! +//! // Receive the message. +//! assert_eq!(r.recv(), Ok("foo")); +//! +//! // This call would block because the channel is empty. +//! // r.recv(); +//! +//! // Try receiving a message without blocking. +//! assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +//! +//! // Disconnect the channel. +//! drop(s); +//! +//! // This call doesn't block because the channel is now disconnected. +//! assert_eq!(r.recv(), Err(RecvError)); +//! ``` +//! +//! # Iteration +//! +//! Receivers can be used as iterators. For example, method [`iter`] creates an iterator that +//! receives messages until the channel becomes empty and disconnected. Note that iteration may +//! block waiting for next message to arrive. +//! +//! ``` +//! use std::thread; +//! use crossbeam_channel::unbounded; +//! +//! let (s, r) = unbounded(); +//! +//! thread::spawn(move || { +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! drop(s); // Disconnect the channel. +//! }); +//! +//! // Collect all messages from the channel. +//! // Note that the call to `collect` blocks until the sender is dropped. +//! let v: Vec<_> = r.iter().collect(); +//! +//! assert_eq!(v, [1, 2, 3]); +//! ``` +//! +//! A non-blocking iterator can be created using [`try_iter`], which receives all available +//! messages without blocking: +//! +//! ``` +//! use crossbeam_channel::unbounded; +//! +//! let (s, r) = unbounded(); +//! s.send(1).unwrap(); +//! s.send(2).unwrap(); +//! s.send(3).unwrap(); +//! // No need to drop the sender. +//! +//! // Receive all messages currently in the channel. +//! let v: Vec<_> = r.try_iter().collect(); +//! +//! assert_eq!(v, [1, 2, 3]); +//! ``` +//! +//! # Selection +//! +//! The [`select!`] macro allows you to define a set of channel operations, wait until any one of +//! them becomes ready, and finally execute it. If multiple operations are ready at the same time, +//! a random one among them is selected. +//! +//! It is also possible to define a `default` case that gets executed if none of the operations are +//! ready, either right away or for a certain duration of time. +//! +//! An operation is considered to be ready if it doesn't have to block. Note that it is ready even +//! when it will simply return an error because the channel is disconnected. +//! +//! An example of receiving a message from two channels: +//! +//! ``` +//! # #[macro_use] +//! # extern crate crossbeam_channel; +//! # fn main() { +//! use std::thread; +//! use std::time::Duration; +//! use crossbeam_channel::unbounded; +//! +//! let (s1, r1) = unbounded(); +//! let (s2, r2) = unbounded(); +//! +//! thread::spawn(move || s1.send(10).unwrap()); +//! thread::spawn(move || s2.send(20).unwrap()); +//! +//! // At most one of these two receive operations will be executed. +//! select! { +//! recv(r1) -> msg => assert_eq!(msg, Ok(10)), +//! recv(r2) -> msg => assert_eq!(msg, Ok(20)), +//! default(Duration::from_secs(1)) => println!("timed out"), +//! } +//! # } +//! ``` +//! +//! If you need to select over a dynamically created list of channel operations, use [`Select`] +//! instead. The [`select!`] macro is just a convenience wrapper around [`Select`]. +//! +//! # Extra channels +//! +//! Three functions can create special kinds of channels, all of which return just a [`Receiver`] +//! handle: +//! +//! * [`after`] creates a channel that delivers a single message after a certain duration of time. +//! * [`tick`] creates a channel that delivers messages periodically. +//! * [`never`] creates a channel that never delivers messages. +//! +//! These channels are very efficient because messages get lazily generated on receive operations. +//! +//! An example that prints elapsed time every 50 milliseconds for the duration of 1 second: +//! +//! ``` +//! # #[macro_use] +//! # extern crate crossbeam_channel; +//! # fn main() { +//! use std::time::{Duration, Instant}; +//! use crossbeam_channel::{after, tick}; +//! +//! let start = Instant::now(); +//! let ticker = tick(Duration::from_millis(50)); +//! let timeout = after(Duration::from_secs(1)); +//! +//! loop { +//! select! { +//! recv(ticker) -> _ => println!("elapsed: {:?}", start.elapsed()), +//! recv(timeout) -> _ => break, +//! } +//! } +//! # } +//! ``` +//! +//! [`std::sync::mpsc`]: https://doc.rust-lang.org/std/sync/mpsc/index.html +//! [`unbounded`]: fn.unbounded.html +//! [`bounded`]: fn.bounded.html +//! [`after`]: fn.after.html +//! [`tick`]: fn.tick.html +//! [`never`]: fn.never.html +//! [`send`]: struct.Sender.html#method.send +//! [`recv`]: struct.Receiver.html#method.recv +//! [`iter`]: struct.Receiver.html#method.iter +//! [`try_iter`]: struct.Receiver.html#method.try_iter +//! [`select!`]: macro.select.html +//! [`Select`]: struct.Select.html +//! [`Sender`]: struct.Sender.html +//! [`Receiver`]: struct.Receiver.html + +#![warn(missing_docs)] +#![warn(missing_debug_implementations)] + +extern crate crossbeam_utils; +extern crate maybe_uninit; + +mod channel; +mod context; +mod counter; +mod err; +mod flavors; +mod select; +mod select_macro; +mod utils; +mod waker; + +/// Crate internals used by the `select!` macro. +#[doc(hidden)] +pub mod internal { + pub use select::SelectHandle; + pub use select::{select, select_timeout, try_select}; +} + +pub use channel::{after, never, tick}; +pub use channel::{bounded, unbounded}; +pub use channel::{IntoIter, Iter, TryIter}; +pub use channel::{Receiver, Sender}; + +pub use select::{Select, SelectedOperation}; + +pub use err::{ReadyTimeoutError, SelectTimeoutError, TryReadyError, TrySelectError}; +pub use err::{RecvError, RecvTimeoutError, TryRecvError}; +pub use err::{SendError, SendTimeoutError, TrySendError}; diff --git a/vendor/crossbeam-channel/src/select.rs b/vendor/crossbeam-channel/src/select.rs new file mode 100644 index 0000000000..60c6a45dcb --- /dev/null +++ b/vendor/crossbeam-channel/src/select.rs @@ -0,0 +1,1166 @@ +//! Interface to the select mechanism. + +use std::fmt; +use std::marker::PhantomData; +use std::mem; +use std::time::{Duration, Instant}; + +use crossbeam_utils::Backoff; + +use channel::{self, Receiver, Sender}; +use context::Context; +use err::{ReadyTimeoutError, TryReadyError}; +use err::{RecvError, SendError}; +use err::{SelectTimeoutError, TrySelectError}; +use flavors; +use utils; + +/// Temporary data that gets initialized during select or a blocking operation, and is consumed by +/// `read` or `write`. +/// +/// Each field contains data associated with a specific channel flavor. +#[derive(Debug, Default)] +pub struct Token { + pub after: flavors::after::AfterToken, + pub array: flavors::array::ArrayToken, + pub list: flavors::list::ListToken, + pub never: flavors::never::NeverToken, + pub tick: flavors::tick::TickToken, + pub zero: flavors::zero::ZeroToken, +} + +/// Identifier associated with an operation by a specific thread on a specific channel. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub struct Operation(usize); + +impl Operation { + /// Creates an operation identifier from a mutable reference. + /// + /// This function essentially just turns the address of the reference into a number. The + /// reference should point to a variable that is specific to the thread and the operation, + /// and is alive for the entire duration of select or blocking operation. + #[inline] + pub fn hook(r: &mut T) -> Operation { + let val = r as *mut T as usize; + // Make sure that the pointer address doesn't equal the numerical representation of + // `Selected::{Waiting, Aborted, Disconnected}`. + assert!(val > 2); + Operation(val) + } +} + +/// Current state of a select or a blocking operation. +#[derive(Debug, Clone, Copy, PartialEq, Eq)] +pub enum Selected { + /// Still waiting for an operation. + Waiting, + + /// The attempt to block the current thread has been aborted. + Aborted, + + /// An operation became ready because a channel is disconnected. + Disconnected, + + /// An operation became ready because a message can be sent or received. + Operation(Operation), +} + +impl From for Selected { + #[inline] + fn from(val: usize) -> Selected { + match val { + 0 => Selected::Waiting, + 1 => Selected::Aborted, + 2 => Selected::Disconnected, + oper => Selected::Operation(Operation(oper)), + } + } +} + +impl Into for Selected { + #[inline] + fn into(self) -> usize { + match self { + Selected::Waiting => 0, + Selected::Aborted => 1, + Selected::Disconnected => 2, + Selected::Operation(Operation(val)) => val, + } + } +} + +/// A receiver or a sender that can participate in select. +/// +/// This is a handle that assists select in executing an operation, registration, deciding on the +/// appropriate deadline for blocking, etc. +pub trait SelectHandle { + /// Attempts to select an operation and returns `true` on success. + fn try_select(&self, token: &mut Token) -> bool; + + /// Returns a deadline for an operation, if there is one. + fn deadline(&self) -> Option; + + /// Registers an operation for execution and returns `true` if it is now ready. + fn register(&self, oper: Operation, cx: &Context) -> bool; + + /// Unregisters an operation for execution. + fn unregister(&self, oper: Operation); + + /// Attempts to select an operation the thread got woken up for and returns `true` on success. + fn accept(&self, token: &mut Token, cx: &Context) -> bool; + + /// Returns `true` if an operation can be executed without blocking. + fn is_ready(&self) -> bool; + + /// Registers an operation for readiness notification and returns `true` if it is now ready. + fn watch(&self, oper: Operation, cx: &Context) -> bool; + + /// Unregisters an operation for readiness notification. + fn unwatch(&self, oper: Operation); +} + +impl<'a, T: SelectHandle> SelectHandle for &'a T { + fn try_select(&self, token: &mut Token) -> bool { + (**self).try_select(token) + } + + fn deadline(&self) -> Option { + (**self).deadline() + } + + fn register(&self, oper: Operation, cx: &Context) -> bool { + (**self).register(oper, cx) + } + + fn unregister(&self, oper: Operation) { + (**self).unregister(oper); + } + + fn accept(&self, token: &mut Token, cx: &Context) -> bool { + (**self).accept(token, cx) + } + + fn is_ready(&self) -> bool { + (**self).is_ready() + } + + fn watch(&self, oper: Operation, cx: &Context) -> bool { + (**self).watch(oper, cx) + } + + fn unwatch(&self, oper: Operation) { + (**self).unwatch(oper) + } +} + +/// Determines when a select operation should time out. +#[derive(Clone, Copy, Eq, PartialEq)] +enum Timeout { + /// No blocking. + Now, + + /// Block forever. + Never, + + /// Time out after the time instant. + At(Instant), +} + +/// Runs until one of the operations is selected, potentially blocking the current thread. +/// +/// Successful receive operations will have to be followed up by `channel::read()` and successful +/// send operations by `channel::write()`. +fn run_select( + handles: &mut [(&dyn SelectHandle, usize, *const u8)], + timeout: Timeout, +) -> Option<(Token, usize, *const u8)> { + if handles.is_empty() { + // Wait until the timeout and return. + match timeout { + Timeout::Now => return None, + Timeout::Never => { + utils::sleep_until(None); + unreachable!(); + } + Timeout::At(when) => { + utils::sleep_until(Some(when)); + return None; + } + } + } + + // Shuffle the operations for fairness. + utils::shuffle(handles); + + // Create a token, which serves as a temporary variable that gets initialized in this function + // and is later used by a call to `channel::read()` or `channel::write()` that completes the + // selected operation. + let mut token = Token::default(); + + // Try selecting one of the operations without blocking. + for &(handle, i, ptr) in handles.iter() { + if handle.try_select(&mut token) { + return Some((token, i, ptr)); + } + } + + loop { + // Prepare for blocking. + let res = Context::with(|cx| { + let mut sel = Selected::Waiting; + let mut registered_count = 0; + let mut index_ready = None; + + if let Timeout::Now = timeout { + cx.try_select(Selected::Aborted).unwrap(); + } + + // Register all operations. + for (handle, i, _) in handles.iter_mut() { + registered_count += 1; + + // If registration returns `false`, that means the operation has just become ready. + if handle.register(Operation::hook::<&dyn SelectHandle>(handle), cx) { + // Try aborting select. + sel = match cx.try_select(Selected::Aborted) { + Ok(()) => { + index_ready = Some(*i); + Selected::Aborted + } + Err(s) => s, + }; + break; + } + + // If another thread has already selected one of the operations, stop registration. + sel = cx.selected(); + if sel != Selected::Waiting { + break; + } + } + + if sel == Selected::Waiting { + // Check with each operation for how long we're allowed to block, and compute the + // earliest deadline. + let mut deadline: Option = match timeout { + Timeout::Now => return None, + Timeout::Never => None, + Timeout::At(when) => Some(when), + }; + for &(handle, _, _) in handles.iter() { + if let Some(x) = handle.deadline() { + deadline = deadline.map(|y| x.min(y)).or(Some(x)); + } + } + + // Block the current thread. + sel = cx.wait_until(deadline); + } + + // Unregister all registered operations. + for (handle, _, _) in handles.iter_mut().take(registered_count) { + handle.unregister(Operation::hook::<&dyn SelectHandle>(handle)); + } + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => { + // If an operation became ready during registration, try selecting it. + if let Some(index_ready) = index_ready { + for &(handle, i, ptr) in handles.iter() { + if i == index_ready && handle.try_select(&mut token) { + return Some((i, ptr)); + } + } + } + } + Selected::Disconnected => {} + Selected::Operation(_) => { + // Find the selected operation. + for (handle, i, ptr) in handles.iter_mut() { + // Is this the selected operation? + if sel == Selected::Operation(Operation::hook::<&dyn SelectHandle>(handle)) + { + // Try selecting this operation. + if handle.accept(&mut token, cx) { + return Some((*i, *ptr)); + } + } + } + } + } + + None + }); + + // Return if an operation was selected. + if let Some((i, ptr)) = res { + return Some((token, i, ptr)); + } + + // Try selecting one of the operations without blocking. + for &(handle, i, ptr) in handles.iter() { + if handle.try_select(&mut token) { + return Some((token, i, ptr)); + } + } + + match timeout { + Timeout::Now => return None, + Timeout::Never => {} + Timeout::At(when) => { + if Instant::now() >= when { + return None; + } + } + } + } +} + +/// Runs until one of the operations becomes ready, potentially blocking the current thread. +fn run_ready( + handles: &mut [(&dyn SelectHandle, usize, *const u8)], + timeout: Timeout, +) -> Option { + if handles.is_empty() { + // Wait until the timeout and return. + match timeout { + Timeout::Now => return None, + Timeout::Never => { + utils::sleep_until(None); + unreachable!(); + } + Timeout::At(when) => { + utils::sleep_until(Some(when)); + return None; + } + } + } + + // Shuffle the operations for fairness. + utils::shuffle(handles); + + loop { + let backoff = Backoff::new(); + loop { + // Check operations for readiness. + for &(handle, i, _) in handles.iter() { + if handle.is_ready() { + return Some(i); + } + } + + if backoff.is_completed() { + break; + } else { + backoff.snooze(); + } + } + + // Check for timeout. + match timeout { + Timeout::Now => return None, + Timeout::Never => {} + Timeout::At(when) => { + if Instant::now() >= when { + return None; + } + } + } + + // Prepare for blocking. + let res = Context::with(|cx| { + let mut sel = Selected::Waiting; + let mut registered_count = 0; + + // Begin watching all operations. + for (handle, _, _) in handles.iter_mut() { + registered_count += 1; + let oper = Operation::hook::<&dyn SelectHandle>(handle); + + // If registration returns `false`, that means the operation has just become ready. + if handle.watch(oper, cx) { + sel = match cx.try_select(Selected::Operation(oper)) { + Ok(()) => Selected::Operation(oper), + Err(s) => s, + }; + break; + } + + // If another thread has already chosen one of the operations, stop registration. + sel = cx.selected(); + if sel != Selected::Waiting { + break; + } + } + + if sel == Selected::Waiting { + // Check with each operation for how long we're allowed to block, and compute the + // earliest deadline. + let mut deadline: Option = match timeout { + Timeout::Now => unreachable!(), + Timeout::Never => None, + Timeout::At(when) => Some(when), + }; + for &(handle, _, _) in handles.iter() { + if let Some(x) = handle.deadline() { + deadline = deadline.map(|y| x.min(y)).or(Some(x)); + } + } + + // Block the current thread. + sel = cx.wait_until(deadline); + } + + // Unwatch all operations. + for (handle, _, _) in handles.iter_mut().take(registered_count) { + handle.unwatch(Operation::hook::<&dyn SelectHandle>(handle)); + } + + match sel { + Selected::Waiting => unreachable!(), + Selected::Aborted => {} + Selected::Disconnected => {} + Selected::Operation(_) => { + for (handle, i, _) in handles.iter_mut() { + let oper = Operation::hook::<&dyn SelectHandle>(handle); + if sel == Selected::Operation(oper) { + return Some(*i); + } + } + } + } + + None + }); + + // Return if an operation became ready. + if res.is_some() { + return res; + } + } +} + +/// Attempts to select one of the operations without blocking. +#[inline] +pub fn try_select<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], +) -> Result, TrySelectError> { + match run_select(handles, Timeout::Now) { + None => Err(TrySelectError), + Some((token, index, ptr)) => Ok(SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + }), + } +} + +/// Blocks until one of the operations becomes ready and selects it. +#[inline] +pub fn select<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], +) -> SelectedOperation<'a> { + if handles.is_empty() { + panic!("no operations have been added to `Select`"); + } + + let (token, index, ptr) = run_select(handles, Timeout::Never).unwrap(); + SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + } +} + +/// Blocks for a limited time until one of the operations becomes ready and selects it. +#[inline] +pub fn select_timeout<'a>( + handles: &mut [(&'a dyn SelectHandle, usize, *const u8)], + timeout: Duration, +) -> Result, SelectTimeoutError> { + let timeout = Timeout::At(Instant::now() + timeout); + + match run_select(handles, timeout) { + None => Err(SelectTimeoutError), + Some((token, index, ptr)) => Ok(SelectedOperation { + token, + index, + ptr, + _marker: PhantomData, + }), + } +} + +/// Selects from a set of channel operations. +/// +/// `Select` allows you to define a set of channel operations, wait until any one of them becomes +/// ready, and finally execute it. If multiple operations are ready at the same time, a random one +/// among them is selected. +/// +/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even +/// when it will simply return an error because the channel is disconnected. +/// +/// The [`select!`] macro is a convenience wrapper around `Select`. However, it cannot select over a +/// dynamically created list of channel operations. +/// +/// Once a list of operations has been built with `Select`, there are two different ways of +/// proceeding: +/// +/// * Select an operation with [`try_select`], [`select`], or [`select_timeout`]. If successful, +/// the returned selected operation has already begun and **must** be completed. If we don't +/// complete it, a panic will occur. +/// +/// * Wait for an operation to become ready with [`try_ready`], [`ready`], or [`ready_timeout`]. If +/// successful, we may attempt to execute the operation, but are not obliged to. In fact, it's +/// possible for another thread to make the operation not ready just before we try executing it, +/// so it's wise to use a retry loop. However, note that these methods might return with success +/// spuriously, so it's a good idea to always double check if the operation is really ready. +/// +/// # Examples +/// +/// Use [`select`] to receive a message from a list of receivers: +/// +/// ``` +/// use crossbeam_channel::{Receiver, RecvError, Select}; +/// +/// fn recv_multiple(rs: &[Receiver]) -> Result { +/// // Build a list of operations. +/// let mut sel = Select::new(); +/// for r in rs { +/// sel.recv(r); +/// } +/// +/// // Complete the selected operation. +/// let oper = sel.select(); +/// let index = oper.index(); +/// oper.recv(&rs[index]) +/// } +/// ``` +/// +/// Use [`ready`] to receive a message from a list of receivers: +/// +/// ``` +/// use crossbeam_channel::{Receiver, RecvError, Select}; +/// +/// fn recv_multiple(rs: &[Receiver]) -> Result { +/// // Build a list of operations. +/// let mut sel = Select::new(); +/// for r in rs { +/// sel.recv(r); +/// } +/// +/// loop { +/// // Wait until a receive operation becomes ready and try executing it. +/// let index = sel.ready(); +/// let res = rs[index].try_recv(); +/// +/// // If the operation turns out not to be ready, retry. +/// if let Err(e) = res { +/// if e.is_empty() { +/// continue; +/// } +/// } +/// +/// // Success! +/// return res.map_err(|_| RecvError); +/// } +/// } +/// ``` +/// +/// [`select!`]: macro.select.html +/// [`try_select`]: struct.Select.html#method.try_select +/// [`select`]: struct.Select.html#method.select +/// [`select_timeout`]: struct.Select.html#method.select_timeout +/// [`try_ready`]: struct.Select.html#method.try_ready +/// [`ready`]: struct.Select.html#method.ready +/// [`ready_timeout`]: struct.Select.html#method.ready_timeout +pub struct Select<'a> { + /// A list of senders and receivers participating in selection. + handles: Vec<(&'a dyn SelectHandle, usize, *const u8)>, + + /// The next index to assign to an operation. + next_index: usize, +} + +unsafe impl<'a> Send for Select<'a> {} +unsafe impl<'a> Sync for Select<'a> {} + +impl<'a> Select<'a> { + /// Creates an empty list of channel operations for selection. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::Select; + /// + /// let mut sel = Select::new(); + /// + /// // The list of operations is empty, which means no operation can be selected. + /// assert!(sel.try_select().is_err()); + /// ``` + pub fn new() -> Select<'a> { + Select { + handles: Vec::with_capacity(4), + next_index: 0, + } + } + + /// Adds a send operation. + /// + /// Returns the index of the added operation. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s, r) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let index = sel.send(&s); + /// ``` + pub fn send(&mut self, s: &'a Sender) -> usize { + let i = self.next_index; + let ptr = s as *const Sender<_> as *const u8; + self.handles.push((s, i, ptr)); + self.next_index += 1; + i + } + + /// Adds a receive operation. + /// + /// Returns the index of the added operation. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s, r) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let index = sel.recv(&r); + /// ``` + pub fn recv(&mut self, r: &'a Receiver) -> usize { + let i = self.next_index; + let ptr = r as *const Receiver<_> as *const u8; + self.handles.push((r, i, ptr)); + self.next_index += 1; + i + } + + /// Removes a previously added operation. + /// + /// This is useful when an operation is selected because the channel got disconnected and we + /// want to try again to select a different operation instead. + /// + /// If new operations are added after removing some, the indices of removed operations will not + /// be reused. + /// + /// # Panics + /// + /// An attempt to remove a non-existing or already removed operation will panic. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded::(); + /// let (_, r2) = unbounded::(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be executed. + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper2); + /// assert!(oper.recv(&r2).is_err()); + /// sel.remove(oper2); + /// + /// s1.send(10).unwrap(); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.recv(&r1), Ok(10)); + /// ``` + pub fn remove(&mut self, index: usize) { + assert!( + index < self.next_index, + "index out of bounds; {} >= {}", + index, + self.next_index, + ); + + let i = self + .handles + .iter() + .enumerate() + .find(|(_, (_, i, _))| *i == index) + .expect("no operation with this index") + .0; + + self.handles.swap_remove(i); + } + + /// Attempts to select one of the operations without blocking. + /// + /// If an operation is ready, it is selected and returned. If multiple operations are ready at + /// the same time, a random one among them is selected. If none of the operations are ready, an + /// error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// [`SelectedOperation::send`]: struct.SelectedOperation.html#method.send + /// [`SelectedOperation::recv`]: struct.SelectedOperation.html#method.recv + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// s1.send(10).unwrap(); + /// s2.send(20).unwrap(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be executed. + /// let oper = sel.try_select(); + /// match oper { + /// Err(_) => panic!("both operations should be ready"), + /// Ok(oper) => match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// } + /// ``` + pub fn try_select(&mut self) -> Result, TrySelectError> { + try_select(&mut self.handles) + } + + /// Blocks until one of the operations becomes ready and selects it. + /// + /// Once an operation becomes ready, it is selected and returned. If multiple operations are + /// ready at the same time, a random one among them is selected. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// [`SelectedOperation::send`]: struct.SelectedOperation.html#method.send + /// [`SelectedOperation::recv`]: struct.SelectedOperation.html#method.recv + /// + /// # Panics + /// + /// Panics if no operations have been added to `Select`. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// let oper = sel.select(); + /// match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// ``` + pub fn select(&mut self) -> SelectedOperation<'a> { + select(&mut self.handles) + } + + /// Blocks for a limited time until one of the operations becomes ready and selects it. + /// + /// If an operation becomes ready, it is selected and returned. If multiple operations are + /// ready at the same time, a random one among them is selected. If none of the operations + /// become ready for the specified duration, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// The selected operation must be completed with [`SelectedOperation::send`] + /// or [`SelectedOperation::recv`]. + /// + /// [`SelectedOperation::send`]: struct.SelectedOperation.html#method.send + /// [`SelectedOperation::recv`]: struct.SelectedOperation.html#method.recv + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// let oper = sel.select_timeout(Duration::from_millis(500)); + /// match oper { + /// Err(_) => panic!("should not have timed out"), + /// Ok(oper) => match oper.index() { + /// i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(10)), + /// i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(20)), + /// _ => unreachable!(), + /// } + /// } + /// ``` + pub fn select_timeout( + &mut self, + timeout: Duration, + ) -> Result, SelectTimeoutError> { + select_timeout(&mut self.handles, timeout) + } + + /// Attempts to find a ready operation without blocking. + /// + /// If an operation is ready, its index is returned. If multiple operations are ready at the + /// same time, a random one among them is chosen. If none of the operations are ready, an error + /// is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to always + /// double check if the operation is really ready. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// s1.send(10).unwrap(); + /// s2.send(20).unwrap(); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // Both operations are initially ready, so a random one will be chosen. + /// match sel.try_ready() { + /// Err(_) => panic!("both operations should be ready"), + /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// Ok(_) => unreachable!(), + /// } + /// ``` + pub fn try_ready(&mut self) -> Result { + match run_ready(&mut self.handles, Timeout::Now) { + None => Err(TryReadyError), + Some(index) => Ok(index), + } + } + + /// Blocks until one of the operations becomes ready. + /// + /// Once an operation becomes ready, its index is returned. If multiple operations are ready at + /// the same time, a random one among them is chosen. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to always + /// double check if the operation is really ready. + /// + /// # Panics + /// + /// Panics if no operations have been added to `Select`. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// match sel.ready() { + /// i if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// i if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// _ => unreachable!(), + /// } + /// ``` + pub fn ready(&mut self) -> usize { + if self.handles.is_empty() { + panic!("no operations have been added to `Select`"); + } + + run_ready(&mut self.handles, Timeout::Never).unwrap() + } + + /// Blocks for a limited time until one of the operations becomes ready. + /// + /// If an operation becomes ready, its index is returned. If multiple operations are ready at + /// the same time, a random one among them is chosen. If none of the operations become ready + /// for the specified duration, an error is returned. + /// + /// An operation is considered to be ready if it doesn't have to block. Note that it is ready + /// even when it will simply return an error because the channel is disconnected. + /// + /// Note that this method might return with success spuriously, so it's a good idea to double + /// check if the operation is really ready. + /// + /// # Examples + /// + /// ``` + /// use std::thread; + /// use std::time::Duration; + /// use crossbeam_channel::{unbounded, Select}; + /// + /// let (s1, r1) = unbounded(); + /// let (s2, r2) = unbounded(); + /// + /// thread::spawn(move || { + /// thread::sleep(Duration::from_secs(1)); + /// s1.send(10).unwrap(); + /// }); + /// thread::spawn(move || s2.send(20).unwrap()); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r1); + /// let oper2 = sel.recv(&r2); + /// + /// // The second operation will be selected because it becomes ready first. + /// match sel.ready_timeout(Duration::from_millis(500)) { + /// Err(_) => panic!("should not have timed out"), + /// Ok(i) if i == oper1 => assert_eq!(r1.try_recv(), Ok(10)), + /// Ok(i) if i == oper2 => assert_eq!(r2.try_recv(), Ok(20)), + /// Ok(_) => unreachable!(), + /// } + /// ``` + pub fn ready_timeout(&mut self, timeout: Duration) -> Result { + let timeout = Timeout::At(Instant::now() + timeout); + + match run_ready(&mut self.handles, timeout) { + None => Err(ReadyTimeoutError), + Some(index) => Ok(index), + } + } +} + +impl<'a> Clone for Select<'a> { + fn clone(&self) -> Select<'a> { + Select { + handles: self.handles.clone(), + next_index: self.next_index, + } + } +} + +impl<'a> Default for Select<'a> { + fn default() -> Select<'a> { + Select::new() + } +} + +impl<'a> fmt::Debug for Select<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("Select { .. }") + } +} + +/// A selected operation that needs to be completed. +/// +/// To complete the operation, call [`send`] or [`recv`]. +/// +/// # Panics +/// +/// Forgetting to complete the operation is an error and might lead to deadlocks. If a +/// `SelectedOperation` is dropped without completion, a panic occurs. +/// +/// [`send`]: struct.SelectedOperation.html#method.send +/// [`recv`]: struct.SelectedOperation.html#method.recv +#[must_use] +pub struct SelectedOperation<'a> { + /// Token needed to complete the operation. + token: Token, + + /// The index of the selected operation. + index: usize, + + /// The address of the selected `Sender` or `Receiver`. + ptr: *const u8, + + /// Indicates that `Sender`s and `Receiver`s are borrowed. + _marker: PhantomData<&'a ()>, +} + +impl<'a> SelectedOperation<'a> { + /// Returns the index of the selected operation. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select}; + /// + /// let (s1, r1) = bounded::<()>(0); + /// let (s2, r2) = bounded::<()>(0); + /// let (s3, r3) = bounded::<()>(1); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.send(&s1); + /// let oper2 = sel.recv(&r2); + /// let oper3 = sel.send(&s3); + /// + /// // Only the last operation is ready. + /// let oper = sel.select(); + /// assert_eq!(oper.index(), 2); + /// assert_eq!(oper.index(), oper3); + /// + /// // Complete the operation. + /// oper.send(&s3, ()).unwrap(); + /// ``` + pub fn index(&self) -> usize { + self.index + } + + /// Completes the send operation. + /// + /// The passed [`Sender`] reference must be the same one that was used in [`Select::send`] + /// when the operation was added. + /// + /// # Panics + /// + /// Panics if an incorrect [`Sender`] reference is passed. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select, SendError}; + /// + /// let (s, r) = bounded::(0); + /// drop(r); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.send(&s); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.send(&s, 10), Err(SendError(10))); + /// ``` + /// + /// [`Sender`]: struct.Sender.html + /// [`Select::send`]: struct.Select.html#method.send + pub fn send(mut self, s: &Sender, msg: T) -> Result<(), SendError> { + assert!( + s as *const Sender as *const u8 == self.ptr, + "passed a sender that wasn't selected", + ); + let res = unsafe { channel::write(s, &mut self.token, msg) }; + mem::forget(self); + res.map_err(SendError) + } + + /// Completes the receive operation. + /// + /// The passed [`Receiver`] reference must be the same one that was used in [`Select::recv`] + /// when the operation was added. + /// + /// # Panics + /// + /// Panics if an incorrect [`Receiver`] reference is passed. + /// + /// # Examples + /// + /// ``` + /// use crossbeam_channel::{bounded, Select, RecvError}; + /// + /// let (s, r) = bounded::(0); + /// drop(s); + /// + /// let mut sel = Select::new(); + /// let oper1 = sel.recv(&r); + /// + /// let oper = sel.select(); + /// assert_eq!(oper.index(), oper1); + /// assert_eq!(oper.recv(&r), Err(RecvError)); + /// ``` + /// + /// [`Receiver`]: struct.Receiver.html + /// [`Select::recv`]: struct.Select.html#method.recv + pub fn recv(mut self, r: &Receiver) -> Result { + assert!( + r as *const Receiver as *const u8 == self.ptr, + "passed a receiver that wasn't selected", + ); + let res = unsafe { channel::read(r, &mut self.token) }; + mem::forget(self); + res.map_err(|_| RecvError) + } +} + +impl<'a> fmt::Debug for SelectedOperation<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.pad("SelectedOperation { .. }") + } +} + +impl<'a> Drop for SelectedOperation<'a> { + fn drop(&mut self) { + panic!("dropped `SelectedOperation` without completing the operation"); + } +} diff --git a/vendor/crossbeam-channel/src/select_macro.rs b/vendor/crossbeam-channel/src/select_macro.rs new file mode 100644 index 0000000000..9aaaa9e935 --- /dev/null +++ b/vendor/crossbeam-channel/src/select_macro.rs @@ -0,0 +1,1214 @@ +//! The `select!` macro. + +/// A simple wrapper around the standard macros. +/// +/// This is just an ugly workaround until it becomes possible to import macros with `use` +/// statements. +/// +/// TODO(stjepang): Once we bump the minimum required Rust version to 1.30 or newer, we should: +/// +/// 1. Remove all `#[macro_export(local_inner_macros)]` lines. +/// 2. Replace `crossbeam_channel_delegate` with direct macro invocations. +#[doc(hidden)] +#[macro_export] +macro_rules! crossbeam_channel_delegate { + (concat($($args:tt)*)) => { + concat!($($args)*) + }; + (stringify($($args:tt)*)) => { + stringify!($($args)*) + }; + (unreachable($($args:tt)*)) => { + unreachable!($($args)*) + }; + (compile_error($($args:tt)*)) => { + compile_error!($($args)*) + }; +} + +/// A helper macro for `select!` to hide the long list of macro patterns from the documentation. +/// +/// The macro consists of two stages: +/// 1. Parsing +/// 2. Code generation +/// +/// The parsing stage consists of these subparts: +/// 1. `@list`: Turns a list of tokens into a list of cases. +/// 2. `@list_errorN`: Diagnoses the syntax error. +/// 3. `@case`: Parses a single case and verifies its argument list. +/// +/// The codegen stage consists of these subparts: +/// 1. `@init`: Attempts to optimize `select!` away and initializes the list of handles. +/// 1. `@count`: Counts the listed cases. +/// 3. `@add`: Adds send/receive operations to the list of handles and starts selection. +/// 4. `@complete`: Completes the selected send/receive operation. +/// +/// If the parsing stage encounters a syntax error or the codegen stage ends up with too many +/// cases to process, the macro fails with a compile-time error. +#[doc(hidden)] +#[macro_export(local_inner_macros)] +macro_rules! crossbeam_channel_internal { + // The list is empty. Now check the arguments of each processed case. + (@list + () + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @case + ($($head)*) + () + () + ) + }; + // If necessary, insert an empty argument list after `default`. + (@list + (default => $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + (default() => $($tail)*) + ($($head)*) + ) + }; + // But print an error if `default` is followed by a `->`. + (@list + (default -> $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `=>` after `default` case, found `->`" + )) + }; + // Print an error if there's an `->` after the argument list in the default case. + (@list + (default $args:tt -> $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `=>` after `default` case, found `->`" + )) + }; + // Print an error if there is a missing result in a recv case. + (@list + (recv($($args:tt)*) => $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `->` after `recv` case, found `=>`" + )) + }; + // Print an error if there is a missing result in a send case. + (@list + (send($($args:tt)*) => $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "expected `->` after `send` operation, found `=>`" + )) + }; + // Make sure the arrow and the result are not repeated. + (@list + ($case:ident $args:tt -> $res:tt -> $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error("expected `=>`, found `->`")) + }; + // Print an error if there is a semicolon after the block. + (@list + ($case:ident $args:tt $(-> $res:pat)* => $body:block; $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_delegate!(compile_error( + "did you mean to put a comma instead of the semicolon after `}`?" + )) + }; + // The first case is separated by a comma. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr, $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + ($($tail)*) + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Don't require a comma after the case if it has a proper block. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:block $($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + ($($tail)*) + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Only one case remains. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + () + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Accept a trailing comma at the end of the list. + (@list + ($case:ident ($($args:tt)*) $(-> $res:pat)* => $body:expr,) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!( + @list + () + ($($head)* $case ($($args)*) $(-> $res)* => { $body },) + ) + }; + // Diagnose and print an error. + (@list + ($($tail:tt)*) + ($($head:tt)*) + ) => { + crossbeam_channel_internal!(@list_error1 $($tail)*) + }; + // Stage 1: check the case type. + (@list_error1 recv $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 recv $($tail)*) + }; + (@list_error1 send $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 send $($tail)*) + }; + (@list_error1 default $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 default $($tail)*) + }; + (@list_error1 $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected one of `recv`, `send`, or `default`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error1 $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error2 $($tail)*); + }; + // Stage 2: check the argument list. + (@list_error2 $case:ident) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "missing argument list after `", + crossbeam_channel_delegate!(stringify($case)), + "`", + )) + )) + }; + (@list_error2 $case:ident => $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "missing argument list after `", + crossbeam_channel_delegate!(stringify($case)), + "`", + )) + )) + }; + (@list_error2 $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error3 $($tail)*) + }; + // Stage 3: check the `=>` and what comes after it. + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "missing `=>` after `", + crossbeam_channel_delegate!(stringify($case)), + "` case", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* =>) => { + crossbeam_channel_delegate!(compile_error( + "expected expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:expr; $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma instead of the semicolon after `", + crossbeam_channel_delegate!(stringify($body)), + "`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => recv($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + "expected an expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => send($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + "expected an expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => default($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + "expected an expression after `=>`" + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "(", + crossbeam_channel_delegate!(stringify($($a)*)), + ")`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!($($a:tt)*) $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "!(", + crossbeam_channel_delegate!(stringify($($a)*)), + ")`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident![$($a:tt)*] $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "![", + crossbeam_channel_delegate!(stringify($($a)*)), + "]`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $f:ident!{$($a:tt)*} $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($f)), + "!{", + crossbeam_channel_delegate!(stringify($($a)*)), + "}`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) $(-> $r:pat)* => $body:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "did you mean to put a comma after `", + crossbeam_channel_delegate!(stringify($body)), + "`?", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) -> => $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error("missing pattern after `->`")) + }; + (@list_error3 $case:ident($($args:tt)*) $t:tt $(-> $r:pat)* => $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected `->`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 $case:ident($($args:tt)*) -> $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected a pattern, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 recv($($args:tt)*) $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected `->`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 send($($args:tt)*) $t:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected `->`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + (@list_error3 recv $args:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `recv`, found `", + crossbeam_channel_delegate!(stringify($args)), + "`", + )) + )) + }; + (@list_error3 send $args:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `send`, found `", + crossbeam_channel_delegate!(stringify($args)), + "`", + )) + )) + }; + (@list_error3 default $args:tt $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list or `=>` after `default`, found `", + crossbeam_channel_delegate!(stringify($args)), + "`", + )) + )) + }; + (@list_error3 $($tail:tt)*) => { + crossbeam_channel_internal!(@list_error4 $($tail)*) + }; + // Stage 4: fail with a generic error message. + (@list_error4 $($tail:tt)*) => { + crossbeam_channel_delegate!(compile_error("invalid syntax")) + }; + + // Success! All cases were parsed. + (@case + () + $cases:tt + $default:tt + ) => { + crossbeam_channel_internal!( + @init + $cases + $default + ) + }; + + // Check the format of a recv case. + (@case + (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* recv($r) -> $res => $body,) + $default + ) + }; + // Allow trailing comma... + (@case + (recv($r:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* recv($r) -> $res => $body,) + $default + ) + }; + // Print an error if the argument list is invalid. + (@case + (recv($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "invalid argument list in `recv(", + crossbeam_channel_delegate!(stringify($($args)*)), + ")`", + )) + )) + }; + // Print an error if there is no argument list. + (@case + (recv $t:tt $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `recv`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + + // Check the format of a send case. + (@case + (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* send($s, $m) -> $res => $body,) + $default + ) + }; + // Allow trailing comma... + (@case + (send($s:expr, $m:expr,) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + ($($cases)* send($s, $m) -> $res => $body,) + $default + ) + }; + // Print an error if the argument list is invalid. + (@case + (send($($args:tt)*) -> $res:pat => $body:tt, $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "invalid argument list in `send(", + crossbeam_channel_delegate!(stringify($($args)*)), + ")`", + )) + )) + }; + // Print an error if there is no argument list. + (@case + (send $t:tt $($tail:tt)*) + ($($cases:tt)*) + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list after `send`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + + // Check the format of a default case. + (@case + (default() => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default() => $body,) + ) + }; + // Check the format of a default case with timeout. + (@case + (default($timeout:expr) => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default($timeout) => $body,) + ) + }; + // Allow trailing comma... + (@case + (default($timeout:expr,) => $body:tt, $($tail:tt)*) + $cases:tt + () + ) => { + crossbeam_channel_internal!( + @case + ($($tail)*) + $cases + (default($timeout) => $body,) + ) + }; + // Check for duplicate default cases... + (@case + (default $($tail:tt)*) + $cases:tt + ($($def:tt)+) + ) => { + crossbeam_channel_delegate!(compile_error( + "there can be only one `default` case in a `select!` block" + )) + }; + // Print an error if the argument list is invalid. + (@case + (default($($args:tt)*) => $body:tt, $($tail:tt)*) + $cases:tt + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "invalid argument list in `default(", + crossbeam_channel_delegate!(stringify($($args)*)), + ")`", + )) + )) + }; + // Print an error if there is an unexpected token after `default`. + (@case + (default $t:tt $($tail:tt)*) + $cases:tt + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected an argument list or `=>` after `default`, found `", + crossbeam_channel_delegate!(stringify($t)), + "`", + )) + )) + }; + + // The case was not consumed, therefore it must be invalid. + (@case + ($case:ident $($tail:tt)*) + $cases:tt + $default:tt + ) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "expected one of `recv`, `send`, or `default`, found `", + crossbeam_channel_delegate!(stringify($case)), + "`", + )) + )) + }; + + // Optimize `select!` into `try_recv()`. + (@init + (recv($r:expr) -> $res:pat => $recv_body:tt,) + (default() => $default_body:tt,) + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + match _r.try_recv() { + ::std::result::Result::Err($crate::TryRecvError::Empty) => { + $default_body + } + _res => { + let _res = _res.map_err(|_| $crate::RecvError); + let $res = _res; + $recv_body + } + } + } + } + }}; + // Optimize `select!` into `recv()`. + (@init + (recv($r:expr) -> $res:pat => $body:tt,) + () + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + let _res = _r.recv(); + let $res = _res; + $body + } + } + }}; + // Optimize `select!` into `recv_timeout()`. + (@init + (recv($r:expr) -> $res:pat => $recv_body:tt,) + (default($timeout:expr) => $default_body:tt,) + ) => {{ + match $r { + ref _r => { + let _r: &$crate::Receiver<_> = _r; + match _r.recv_timeout($timeout) { + ::std::result::Result::Err($crate::RecvTimeoutError::Timeout) => { + $default_body + } + _res => { + let _res = _res.map_err(|_| $crate::RecvError); + let $res = _res; + $recv_body + } + } + } + } + }}; + + // // Optimize the non-blocking case with two receive operations. + // (@init + // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,) + // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,) + // (default() => $default_body:tt,) + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + // // Optimize the blocking case with two receive operations. + // (@init + // (recv($r1:expr) -> $res1:pat => $body1:tt,) + // (recv($r2:expr) -> $res2:pat => $body2:tt,) + // () + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + // // Optimize the case with two receive operations and a timeout. + // (@init + // (recv($r1:expr) -> $res1:pat => $recv_body1:tt,) + // (recv($r2:expr) -> $res2:pat => $recv_body2:tt,) + // (default($timeout:expr) => $default_body:tt,) + // ) => {{ + // match $r1 { + // ref _r1 => { + // let _r1: &$crate::Receiver<_> = _r1; + // + // match $r2 { + // ref _r2 => { + // let _r2: &$crate::Receiver<_> = _r2; + // + // // TODO(stjepang): Implement this optimization. + // } + // } + // } + // } + // }}; + + // // Optimize `select!` into `try_send()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $send_body:tt,) + // (default() => $default_body:tt,) + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + // // Optimize `select!` into `send()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $body:tt,) + // () + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + // // Optimize `select!` into `send_timeout()`. + // (@init + // (send($s:expr, $m:expr) -> $res:pat => $body:tt,) + // (default($timeout:expr) => $body:tt,) + // ) => {{ + // match $s { + // ref _s => { + // let _s: &$crate::Sender<_> = _s; + // // TODO(stjepang): Implement this optimization. + // } + // } + // }}; + + // Create the list of handles and add operations to it. + (@init + ($($cases:tt)*) + $default:tt + ) => {{ + const _LEN: usize = crossbeam_channel_internal!(@count ($($cases)*)); + let _handle: &$crate::internal::SelectHandle = &$crate::never::<()>(); + + #[allow(unused_mut)] + let mut _sel = [(_handle, 0, ::std::ptr::null()); _LEN]; + + crossbeam_channel_internal!( + @add + _sel + ($($cases)*) + $default + ( + (0usize _oper0) + (1usize _oper1) + (2usize _oper2) + (3usize _oper3) + (4usize _oper4) + (5usize _oper5) + (6usize _oper6) + (7usize _oper7) + (8usize _oper8) + (9usize _oper9) + (10usize _oper10) + (11usize _oper11) + (12usize _oper12) + (13usize _oper13) + (14usize _oper14) + (15usize _oper15) + (16usize _oper16) + (17usize _oper17) + (18usize _oper18) + (19usize _oper19) + (20usize _oper20) + (21usize _oper21) + (22usize _oper22) + (23usize _oper23) + (24usize _oper24) + (25usize _oper25) + (26usize _oper26) + (27usize _oper27) + (28usize _oper28) + (29usize _oper29) + (30usize _oper30) + (31usize _oper31) + ) + () + ) + }}; + + // Count the listed cases. + (@count ()) => { + 0 + }; + (@count ($oper:ident $args:tt -> $res:pat => $body:tt, $($cases:tt)*)) => { + 1 + crossbeam_channel_internal!(@count ($($cases)*)) + }; + + // Run blocking selection. + (@add + $sel:ident + () + () + $labels:tt + $cases:tt + ) => {{ + let _oper: $crate::SelectedOperation<'_> = { + let _oper = $crate::internal::select(&mut $sel); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + #[allow(unsafe_code)] + unsafe { ::std::mem::transmute(_oper) } + }; + + crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + }}; + // Run non-blocking selection. + (@add + $sel:ident + () + (default() => $body:tt,) + $labels:tt + $cases:tt + ) => {{ + let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = { + let _oper = $crate::internal::try_select(&mut $sel); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + #[allow(unsafe_code)] + unsafe { ::std::mem::transmute(_oper) } + }; + + match _oper { + None => { + { $sel }; + $body + } + Some(_oper) => { + crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + } + } + }}; + // Run selection with a timeout. + (@add + $sel:ident + () + (default($timeout:expr) => $body:tt,) + $labels:tt + $cases:tt + ) => {{ + let _oper: ::std::option::Option<$crate::SelectedOperation<'_>> = { + let _oper = $crate::internal::select_timeout(&mut $sel, $timeout); + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + #[allow(unsafe_code)] + unsafe { ::std::mem::transmute(_oper) } + }; + + match _oper { + ::std::option::Option::None => { + { $sel }; + $body + } + ::std::option::Option::Some(_oper) => { + crossbeam_channel_internal! { + @complete + $sel + _oper + $cases + } + } + } + }}; + // Have we used up all labels? + (@add + $sel:ident + $input:tt + $default:tt + () + $cases:tt + ) => { + crossbeam_channel_delegate!(compile_error("too many operations in a `select!` block")) + }; + // Add a receive operation to `sel`. + (@add + $sel:ident + (recv($r:expr) -> $res:pat => $body:tt, $($tail:tt)*) + $default:tt + (($i:tt $var:ident) $($labels:tt)*) + ($($cases:tt)*) + ) => {{ + match $r { + ref _r => { + #[allow(unsafe_code)] + let $var: &$crate::Receiver<_> = unsafe { + let _r: &$crate::Receiver<_> = _r; + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe fn unbind<'a, T>(x: &T) -> &'a T { + ::std::mem::transmute(x) + } + unbind(_r) + }; + $sel[$i] = ($var, $i, $var as *const $crate::Receiver<_> as *const u8); + + crossbeam_channel_internal!( + @add + $sel + ($($tail)*) + $default + ($($labels)*) + ($($cases)* [$i] recv($var) -> $res => $body,) + ) + } + } + }}; + // Add a send operation to `sel`. + (@add + $sel:ident + (send($s:expr, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + $default:tt + (($i:tt $var:ident) $($labels:tt)*) + ($($cases:tt)*) + ) => {{ + match $s { + ref _s => { + #[allow(unsafe_code)] + let $var: &$crate::Sender<_> = unsafe { + let _s: &$crate::Sender<_> = _s; + + // Erase the lifetime so that `sel` can be dropped early even without NLL. + unsafe fn unbind<'a, T>(x: &T) -> &'a T { + ::std::mem::transmute(x) + } + unbind(_s) + }; + $sel[$i] = ($var, $i, $var as *const $crate::Sender<_> as *const u8); + + crossbeam_channel_internal!( + @add + $sel + ($($tail)*) + $default + ($($labels)*) + ($($cases)* [$i] send($var, $m) -> $res => $body,) + ) + } + } + }}; + + // Complete a receive operation. + (@complete + $sel:ident + $oper:ident + ([$i:tt] recv($r:ident) -> $res:pat => $body:tt, $($tail:tt)*) + ) => {{ + if $oper.index() == $i { + let _res = $oper.recv($r); + { $sel }; + + let $res = _res; + $body + } else { + crossbeam_channel_internal! { + @complete + $sel + $oper + ($($tail)*) + } + } + }}; + // Complete a send operation. + (@complete + $sel:ident + $oper:ident + ([$i:tt] send($s:ident, $m:expr) -> $res:pat => $body:tt, $($tail:tt)*) + ) => {{ + if $oper.index() == $i { + let _res = $oper.send($s, $m); + { $sel }; + + let $res = _res; + $body + } else { + crossbeam_channel_internal! { + @complete + $sel + $oper + ($($tail)*) + } + } + }}; + // Panic if we don't identify the selected case, but this should never happen. + (@complete + $sel:ident + $oper:ident + () + ) => {{ + crossbeam_channel_delegate!(unreachable( + "internal error in crossbeam-channel: invalid case" + )) + }}; + + // Catches a bug within this macro (should not happen). + (@$($tokens:tt)*) => { + crossbeam_channel_delegate!(compile_error( + crossbeam_channel_delegate!(concat( + "internal error in crossbeam-channel: ", + crossbeam_channel_delegate!(stringify(@$($tokens)*)), + )) + )) + }; + + // The entry points. + () => { + crossbeam_channel_delegate!(compile_error("empty `select!` block")) + }; + ($($case:ident $(($($args:tt)*))* => $body:expr $(,)*)*) => { + crossbeam_channel_internal!( + @list + ($($case $(($($args)*))* => { $body },)*) + () + ) + }; + ($($tokens:tt)*) => { + crossbeam_channel_internal!( + @list + ($($tokens)*) + () + ) + }; +} + +/// Selects from a set of channel operations. +/// +/// This macro allows you to define a set of channel operations, wait until any one of them becomes +/// ready, and finally execute it. If multiple operations are ready at the same time, a random one +/// among them is selected. +/// +/// It is also possible to define a `default` case that gets executed if none of the operations are +/// ready, either right away or for a certain duration of time. +/// +/// An operation is considered to be ready if it doesn't have to block. Note that it is ready even +/// when it will simply return an error because the channel is disconnected. +/// +/// The `select` macro is a convenience wrapper around [`Select`]. However, it cannot select over a +/// dynamically created list of channel operations. +/// +/// [`Select`]: struct.Select.html +/// +/// # Examples +/// +/// Block until a send or a receive operation is selected: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// s1.send(10).unwrap(); +/// +/// // Since both operations are initially ready, a random one will be executed. +/// select! { +/// recv(r1) -> msg => assert_eq!(msg, Ok(10)), +/// send(s2, 20) -> res => { +/// assert_eq!(res, Ok(())); +/// assert_eq!(r2.recv(), Ok(20)); +/// } +/// } +/// # } +/// ``` +/// +/// Select from a set of operations without blocking: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // None of the operations are initially ready. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2) -> msg => panic!(), +/// default => println!("not ready"), +/// } +/// # } +/// ``` +/// +/// Select over a set of operations with a timeout: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::unbounded; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // None of the two operations will become ready within 100 milliseconds. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2) -> msg => panic!(), +/// default(Duration::from_millis(100)) => println!("timed out"), +/// } +/// # } +/// ``` +/// +/// Optionally add a receive operation to `select!` using [`never`]: +/// +/// ``` +/// # #[macro_use] +/// # extern crate crossbeam_channel; +/// # fn main() { +/// use std::thread; +/// use std::time::Duration; +/// use crossbeam_channel::{never, unbounded}; +/// +/// let (s1, r1) = unbounded(); +/// let (s2, r2) = unbounded(); +/// +/// thread::spawn(move || { +/// thread::sleep(Duration::from_secs(1)); +/// s1.send(10).unwrap(); +/// }); +/// thread::spawn(move || { +/// thread::sleep(Duration::from_millis(500)); +/// s2.send(20).unwrap(); +/// }); +/// +/// // This receiver can be a `Some` or a `None`. +/// let r2 = Some(&r2); +/// +/// // None of the two operations will become ready within 100 milliseconds. +/// select! { +/// recv(r1) -> msg => panic!(), +/// recv(r2.unwrap_or(&never())) -> msg => assert_eq!(msg, Ok(20)), +/// } +/// # } +/// ``` +/// +/// To optionally add a timeout to `select!`, see the [example] for [`never`]. +/// +/// [`never`]: fn.never.html +/// [example]: fn.never.html#examples +#[macro_export(local_inner_macros)] +macro_rules! select { + ($($tokens:tt)*) => { + crossbeam_channel_internal!( + $($tokens)* + ) + }; +} diff --git a/vendor/crossbeam-channel/src/utils.rs b/vendor/crossbeam-channel/src/utils.rs new file mode 100644 index 0000000000..c6513bc3f8 --- /dev/null +++ b/vendor/crossbeam-channel/src/utils.rs @@ -0,0 +1,112 @@ +//! Miscellaneous utilities. + +use std::cell::{Cell, UnsafeCell}; +use std::num::Wrapping; +use std::ops::{Deref, DerefMut}; +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_utils::Backoff; + +/// Randomly shuffles a slice. +pub fn shuffle(v: &mut [T]) { + let len = v.len(); + if len <= 1 { + return; + } + + thread_local! { + static RNG: Cell> = Cell::new(Wrapping(1406868647)); + } + + let _ = RNG.try_with(|rng| { + for i in 1..len { + // This is the 32-bit variant of Xorshift. + // + // Source: https://en.wikipedia.org/wiki/Xorshift + let mut x = rng.get(); + x ^= x << 13; + x ^= x >> 17; + x ^= x << 5; + rng.set(x); + + let x = x.0; + let n = i + 1; + + // This is a fast alternative to `let j = x % n`. + // + // Author: Daniel Lemire + // Source: https://lemire.me/blog/2016/06/27/a-fast-alternative-to-the-modulo-reduction/ + let j = ((x as u64).wrapping_mul(n as u64) >> 32) as u32 as usize; + + v.swap(i, j); + } + }); +} + +/// Sleeps until the deadline, or forever if the deadline isn't specified. +pub fn sleep_until(deadline: Option) { + loop { + match deadline { + None => thread::sleep(Duration::from_secs(1000)), + Some(d) => { + let now = Instant::now(); + if now >= d { + break; + } + thread::sleep(d - now); + } + } + } +} + +/// A simple spinlock. +pub struct Spinlock { + flag: AtomicBool, + value: UnsafeCell, +} + +impl Spinlock { + /// Returns a new spinlock initialized with `value`. + pub fn new(value: T) -> Spinlock { + Spinlock { + flag: AtomicBool::new(false), + value: UnsafeCell::new(value), + } + } + + /// Locks the spinlock. + pub fn lock(&self) -> SpinlockGuard<'_, T> { + let backoff = Backoff::new(); + while self.flag.swap(true, Ordering::Acquire) { + backoff.snooze(); + } + SpinlockGuard { parent: self } + } +} + +/// A guard holding a spinlock locked. +pub struct SpinlockGuard<'a, T: 'a> { + parent: &'a Spinlock, +} + +impl<'a, T> Drop for SpinlockGuard<'a, T> { + fn drop(&mut self) { + self.parent.flag.store(false, Ordering::Release); + } +} + +impl<'a, T> Deref for SpinlockGuard<'a, T> { + type Target = T; + + fn deref(&self) -> &T { + unsafe { &*self.parent.value.get() } + } +} + +impl<'a, T> DerefMut for SpinlockGuard<'a, T> { + fn deref_mut(&mut self) -> &mut T { + unsafe { &mut *self.parent.value.get() } + } +} diff --git a/vendor/crossbeam-channel/src/waker.rs b/vendor/crossbeam-channel/src/waker.rs new file mode 100644 index 0000000000..7f3428b7eb --- /dev/null +++ b/vendor/crossbeam-channel/src/waker.rs @@ -0,0 +1,285 @@ +//! Waking mechanism for threads blocked on channel operations. + +use std::sync::atomic::{AtomicBool, Ordering}; +use std::thread::{self, ThreadId}; + +use context::Context; +use select::{Operation, Selected}; +use utils::Spinlock; + +/// Represents a thread blocked on a specific channel operation. +pub struct Entry { + /// The operation. + pub oper: Operation, + + /// Optional packet. + pub packet: usize, + + /// Context associated with the thread owning this operation. + pub cx: Context, +} + +/// A queue of threads blocked on channel operations. +/// +/// This data structure is used by threads to register blocking operations and get woken up once +/// an operation becomes ready. +pub struct Waker { + /// A list of select operations. + selectors: Vec, + + /// A list of operations waiting to be ready. + observers: Vec, +} + +impl Waker { + /// Creates a new `Waker`. + #[inline] + pub fn new() -> Self { + Waker { + selectors: Vec::new(), + observers: Vec::new(), + } + } + + /// Registers a select operation. + #[inline] + pub fn register(&mut self, oper: Operation, cx: &Context) { + self.register_with_packet(oper, 0, cx); + } + + /// Registers a select operation and a packet. + #[inline] + pub fn register_with_packet(&mut self, oper: Operation, packet: usize, cx: &Context) { + self.selectors.push(Entry { + oper, + packet, + cx: cx.clone(), + }); + } + + /// Unregisters a select operation. + #[inline] + pub fn unregister(&mut self, oper: Operation) -> Option { + if let Some((i, _)) = self + .selectors + .iter() + .enumerate() + .find(|&(_, entry)| entry.oper == oper) + { + let entry = self.selectors.remove(i); + Some(entry) + } else { + None + } + } + + /// Attempts to find another thread's entry, select the operation, and wake it up. + #[inline] + pub fn try_select(&mut self) -> Option { + let mut entry = None; + + if !self.selectors.is_empty() { + let thread_id = current_thread_id(); + + for i in 0..self.selectors.len() { + // Does the entry belong to a different thread? + if self.selectors[i].cx.thread_id() != thread_id { + // Try selecting this operation. + let sel = Selected::Operation(self.selectors[i].oper); + let res = self.selectors[i].cx.try_select(sel); + + if res.is_ok() { + // Provide the packet. + self.selectors[i].cx.store_packet(self.selectors[i].packet); + // Wake the thread up. + self.selectors[i].cx.unpark(); + + // Remove the entry from the queue to keep it clean and improve + // performance. + entry = Some(self.selectors.remove(i)); + break; + } + } + } + } + + entry + } + + /// Returns `true` if there is an entry which can be selected by the current thread. + #[inline] + pub fn can_select(&self) -> bool { + if self.selectors.is_empty() { + false + } else { + let thread_id = current_thread_id(); + + self.selectors.iter().any(|entry| { + entry.cx.thread_id() != thread_id && entry.cx.selected() == Selected::Waiting + }) + } + } + + /// Registers an operation waiting to be ready. + #[inline] + pub fn watch(&mut self, oper: Operation, cx: &Context) { + self.observers.push(Entry { + oper, + packet: 0, + cx: cx.clone(), + }); + } + + /// Unregisters an operation waiting to be ready. + #[inline] + pub fn unwatch(&mut self, oper: Operation) { + self.observers.retain(|e| e.oper != oper); + } + + /// Notifies all operations waiting to be ready. + #[inline] + pub fn notify(&mut self) { + for entry in self.observers.drain(..) { + if entry.cx.try_select(Selected::Operation(entry.oper)).is_ok() { + entry.cx.unpark(); + } + } + } + + /// Notifies all registered operations that the channel is disconnected. + #[inline] + pub fn disconnect(&mut self) { + for entry in self.selectors.iter() { + if entry.cx.try_select(Selected::Disconnected).is_ok() { + // Wake the thread up. + // + // Here we don't remove the entry from the queue. Registered threads must + // unregister from the waker by themselves. They might also want to recover the + // packet value and destroy it, if necessary. + entry.cx.unpark(); + } + } + + self.notify(); + } +} + +impl Drop for Waker { + #[inline] + fn drop(&mut self) { + debug_assert_eq!(self.selectors.len(), 0); + debug_assert_eq!(self.observers.len(), 0); + } +} + +/// A waker that can be shared among threads without locking. +/// +/// This is a simple wrapper around `Waker` that internally uses a mutex for synchronization. +pub struct SyncWaker { + /// The inner `Waker`. + inner: Spinlock, + + /// `true` if the waker is empty. + is_empty: AtomicBool, +} + +impl SyncWaker { + /// Creates a new `SyncWaker`. + #[inline] + pub fn new() -> Self { + SyncWaker { + inner: Spinlock::new(Waker::new()), + is_empty: AtomicBool::new(true), + } + } + + /// Registers the current thread with an operation. + #[inline] + pub fn register(&self, oper: Operation, cx: &Context) { + let mut inner = self.inner.lock(); + inner.register(oper, cx); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Unregisters an operation previously registered by the current thread. + #[inline] + pub fn unregister(&self, oper: Operation) -> Option { + let mut inner = self.inner.lock(); + let entry = inner.unregister(oper); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + entry + } + + /// Attempts to find one thread (not the current one), select its operation, and wake it up. + #[inline] + pub fn notify(&self) { + if !self.is_empty.load(Ordering::SeqCst) { + let mut inner = self.inner.lock(); + inner.try_select(); + inner.notify(); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + } + + /// Registers an operation waiting to be ready. + #[inline] + pub fn watch(&self, oper: Operation, cx: &Context) { + let mut inner = self.inner.lock(); + inner.watch(oper, cx); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Unregisters an operation waiting to be ready. + #[inline] + pub fn unwatch(&self, oper: Operation) { + let mut inner = self.inner.lock(); + inner.unwatch(oper); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } + + /// Notifies all threads that the channel is disconnected. + #[inline] + pub fn disconnect(&self) { + let mut inner = self.inner.lock(); + inner.disconnect(); + self.is_empty.store( + inner.selectors.is_empty() && inner.observers.is_empty(), + Ordering::SeqCst, + ); + } +} + +impl Drop for SyncWaker { + #[inline] + fn drop(&mut self) { + debug_assert_eq!(self.is_empty.load(Ordering::SeqCst), true); + } +} + +/// Returns the id of the current thread. +#[inline] +fn current_thread_id() -> ThreadId { + thread_local! { + /// Cached thread-local id. + static THREAD_ID: ThreadId = thread::current().id(); + } + + THREAD_ID + .try_with(|id| *id) + .unwrap_or_else(|_| thread::current().id()) +} diff --git a/vendor/crossbeam-channel/tests/after.rs b/vendor/crossbeam-channel/tests/after.rs new file mode 100644 index 0000000000..1137bb1b77 --- /dev/null +++ b/vendor/crossbeam-channel/tests/after.rs @@ -0,0 +1,339 @@ +//! Tests for the after channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn fire() { + let start = Instant::now(); + let r = after(ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(100)); + + let fired = r.try_recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired >= ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + + select! { + recv(r) -> _ => panic!(), + recv(after(ms(200))) -> _ => {} + } +} + +#[test] +fn capacity() { + const COUNT: usize = 10; + + for i in 0..COUNT { + let r = after(ms(i as u64)); + assert_eq!(r.capacity(), Some(1)); + } +} + +#[test] +fn len_empty_full() { + let r = after(ms(50)); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + thread::sleep(ms(100)); + + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.try_recv().unwrap(); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let r = after(ms(200)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv() { + let start = Instant::now(); + let r = after(ms(50)); + + let fired = r.recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired < fired - start); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = after(ms(200)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(200)); + assert!(fired - start <= ms(250)); + + assert!(r.recv_timeout(ms(200)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(400)); + assert!(now - start <= ms(450)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_two() { + let r1 = after(ms(50)); + let r2 = after(ms(50)); + + scope(|scope| { + scope.spawn(|_| { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + }); + scope.spawn(|_| { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_race() { + select! { + recv(after(ms(50))) -> _ => {} + recv(after(ms(100))) -> _ => panic!(), + } + + select! { + recv(after(ms(100))) -> _ => panic!(), + recv(after(ms(50))) -> _ => {} + } +} + +#[test] +fn stress_default() { + const COUNT: usize = 10; + + for _ in 0..COUNT { + select! { + recv(after(ms(0))) -> _ => {} + default => panic!(), + } + } + + for _ in 0..COUNT { + select! { + recv(after(ms(100))) -> _ => panic!(), + default => {} + } + } +} + +#[test] +fn select() { + const THREADS: usize = 4; + const COUNT: usize = 1000; + const TIMEOUT_MS: u64 = 100; + + let v = (0..COUNT) + .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) + .collect::>(); + let hits = AtomicUsize::new(0); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let v: Vec<&_> = v.iter().collect(); + + loop { + let timeout = after(ms(TIMEOUT_MS)); + let mut sel = Select::new(); + for r in &v { + sel.recv(r); + } + let oper_timeout = sel.recv(&timeout); + + let oper = sel.select(); + match oper.index() { + i if i == oper_timeout => { + oper.recv(&timeout).unwrap(); + break; + } + i => { + oper.recv(&v[i]).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), COUNT); +} + +#[test] +fn ready() { + const THREADS: usize = 4; + const COUNT: usize = 1000; + const TIMEOUT_MS: u64 = 100; + + let v = (0..COUNT) + .map(|i| after(ms(i as u64 / TIMEOUT_MS / 2))) + .collect::>(); + let hits = AtomicUsize::new(0); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let v: Vec<&_> = v.iter().collect(); + + loop { + let timeout = after(ms(TIMEOUT_MS)); + let mut sel = Select::new(); + for r in &v { + sel.recv(r); + } + let oper_timeout = sel.recv(&timeout); + + loop { + let i = sel.ready(); + if i == oper_timeout { + timeout.try_recv().unwrap(); + return; + } else if v[i].try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), COUNT); +} + +#[test] +fn stress_clone() { + const RUNS: usize = 1000; + const THREADS: usize = 10; + const COUNT: usize = 50; + + for i in 0..RUNS { + let r = after(ms(i as u64)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let r = r.clone(); + let _ = r.try_recv(); + + for _ in 0..COUNT { + drop(r.clone()); + thread::yield_now(); + } + }); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness() { + const COUNT: usize = 1000; + + for &dur in &[0, 1] { + let mut hits = [0usize; 2]; + + for _ in 0..COUNT { + select! { + recv(after(ms(dur))) -> _ => hits[0] += 1, + recv(after(ms(dur))) -> _ => hits[1] += 1, + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 1000; + + for &dur in &[0, 1] { + let mut hits = [0usize; 5]; + + for _ in 0..COUNT { + let r = after(ms(dur)); + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} diff --git a/vendor/crossbeam-channel/tests/array.rs b/vendor/crossbeam-channel/tests/array.rs new file mode 100644 index 0000000000..a6fc8451b1 --- /dev/null +++ b/vendor/crossbeam-channel/tests/array.rs @@ -0,0 +1,659 @@ +//! Tests for the array channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = bounded(1); + s.send(7).unwrap(); + assert_eq!(r.try_recv(), Ok(7)); + + s.send(8).unwrap(); + assert_eq!(r.recv(), Ok(8)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); +} + +#[test] +fn capacity() { + for i in 1..10 { + let (s, r) = bounded::<()>(i); + assert_eq!(s.capacity(), Some(i)); + assert_eq!(r.capacity(), Some(i)); + } +} + +#[test] +fn len_empty_full() { + let (s, r) = bounded(2); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 2); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 2); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.recv().unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let (s, r) = bounded(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(100); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.try_send(1), Ok(())); + assert_eq!(s.try_send(2), Err(TrySendError::Full(2))); + thread::sleep(ms(1500)); + assert_eq!(s.try_send(3), Ok(())); + thread::sleep(ms(500)); + assert_eq!(s.try_send(4), Err(TrySendError::Disconnected(4))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.try_recv(), Ok(1)); + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv(), Ok(3)); + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| { + s.send(7).unwrap(); + thread::sleep(ms(1000)); + s.send(8).unwrap(); + thread::sleep(ms(1000)); + s.send(9).unwrap(); + thread::sleep(ms(1000)); + s.send(10).unwrap(); + }); + scope.spawn(|_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(7)); + assert_eq!(r.recv(), Ok(8)); + assert_eq!(r.recv(), Ok(9)); + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send_timeout(1, ms(1000)), Ok(())); + assert_eq!(s.send_timeout(2, ms(1000)), Ok(())); + assert_eq!( + s.send_timeout(3, ms(500)), + Err(SendTimeoutError::Timeout(3)) + ); + thread::sleep(ms(1000)); + assert_eq!(s.send_timeout(4, ms(1000)), Ok(())); + thread::sleep(ms(1000)); + assert_eq!(s.send(5), Err(SendError(5))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(1)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(4)); + }); + }) + .unwrap(); +} + +#[test] +fn send_after_disconnect() { + let (s, r) = bounded(100); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(r); + + assert_eq!(s.send(4), Err(SendError(4))); + assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); + assert_eq!( + s.send_timeout(6, ms(500)), + Err(SendTimeoutError::Disconnected(6)) + ); +} + +#[test] +fn recv_after_disconnect() { + let (s, r) = bounded(100); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(s); + + assert_eq!(r.recv(), Ok(1)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(3)); + assert_eq!(r.recv(), Err(RecvError)); +} + +#[test] +fn len() { + const COUNT: usize = 25_000; + const CAP: usize = 1000; + + let (s, r) = bounded(CAP); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for _ in 0..CAP / 10 { + for i in 0..50 { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for i in 0..50 { + r.recv().unwrap(); + assert_eq!(r.len(), 50 - i - 1); + } + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for i in 0..CAP { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for _ in 0..CAP { + r.recv().unwrap(); + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + let len = r.len(); + assert!(len <= CAP); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + let len = s.len(); + assert!(len <= CAP); + } + }); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send(()), Ok(())); + assert_eq!(s.send(()), Err(SendError(()))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(1); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = bounded(3); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded::(3); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 100_000; + + let (request_s, request_r) = bounded(1); + let (response_s, response_r) = bounded(1); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(()) = s.send_timeout(i, ms(10)) { + break; + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + const RUNS: usize = 100; + + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..RUNS { + let steps = rng.gen_range(0, 10_000); + let additional = rng.gen_range(0, 50); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = bounded::(50); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + for _ in 0..additional { + s.send(DropCounter).unwrap(); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} + +#[test] +fn linearizable() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded(THREADS); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + s.send(0).unwrap(); + r.try_recv().unwrap(); + } + }); + } + }) + .unwrap(); +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = bounded::<()>(COUNT); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = bounded::<()>(COUNT); + + for _ in 0..COUNT { + s.send(()).unwrap(); + } + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn recv_in_send() { + let (s, _r) = bounded(1); + s.send(()).unwrap(); + + #[allow(unreachable_code)] + { + select! { + send(s, panic!()) -> _ => panic!(), + default => {} + } + } + + let (s, r) = bounded(2); + s.send(()).unwrap(); + + select! { + send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = bounded::(1); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(1); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/golang.rs b/vendor/crossbeam-channel/tests/golang.rs new file mode 100644 index 0000000000..be015b28fc --- /dev/null +++ b/vendor/crossbeam-channel/tests/golang.rs @@ -0,0 +1,1448 @@ +//! Tests copied from Go and manually rewritten in Rust. +//! +//! Source: +//! - https://github.com/golang/go +//! +//! Copyright & License: +//! - Copyright (c) 2009 The Go Authors +//! - https://golang.org/AUTHORS +//! - https://golang.org/LICENSE +//! - https://golang.org/PATENTS + +#[macro_use] +extern crate crossbeam_channel; + +use std::any::Any; +use std::cell::Cell; +use std::collections::HashMap; +use std::sync::{Arc, Condvar, Mutex}; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, tick, Receiver, Select, Sender}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +struct Chan { + inner: Arc>>, +} + +struct ChanInner { + s: Option>, + r: Receiver, +} + +impl Clone for Chan { + fn clone(&self) -> Chan { + Chan { + inner: self.inner.clone(), + } + } +} + +impl Chan { + fn send(&self, msg: T) { + let s = self + .inner + .lock() + .unwrap() + .s + .as_ref() + .expect("sending into closed channel") + .clone(); + let _ = s.send(msg); + } + + fn try_recv(&self) -> Option { + let r = self.inner.lock().unwrap().r.clone(); + r.try_recv().ok() + } + + fn recv(&self) -> Option { + let r = self.inner.lock().unwrap().r.clone(); + r.recv().ok() + } + + fn close(&self) { + self.inner + .lock() + .unwrap() + .s + .take() + .expect("channel already closed"); + } + + fn rx(&self) -> Receiver { + self.inner.lock().unwrap().r.clone() + } + + fn tx(&self) -> Sender { + match self.inner.lock().unwrap().s.as_ref() { + None => { + let (s, r) = bounded(0); + std::mem::forget(r); + s + } + Some(s) => s.clone(), + } + } +} + +impl Iterator for Chan { + type Item = T; + + fn next(&mut self) -> Option { + self.recv() + } +} + +impl<'a, T> IntoIterator for &'a Chan { + type Item = T; + type IntoIter = Chan; + + fn into_iter(self) -> Self::IntoIter { + self.clone() + } +} + +fn make(cap: usize) -> Chan { + let (s, r) = bounded(cap); + Chan { + inner: Arc::new(Mutex::new(ChanInner { s: Some(s), r })), + } +} + +#[derive(Clone)] +struct WaitGroup(Arc); + +struct WaitGroupInner { + cond: Condvar, + count: Mutex, +} + +impl WaitGroup { + fn new() -> WaitGroup { + WaitGroup(Arc::new(WaitGroupInner { + cond: Condvar::new(), + count: Mutex::new(0), + })) + } + + fn add(&self, delta: i32) { + let mut count = self.0.count.lock().unwrap(); + *count += delta; + assert!(*count >= 0); + self.0.cond.notify_all(); + } + + fn done(&self) { + self.add(-1); + } + + fn wait(&self) { + let mut count = self.0.count.lock().unwrap(); + while *count > 0 { + count = self.0.cond.wait(count).unwrap(); + } + } +} + +struct Defer { + f: Option>, +} + +impl Drop for Defer { + fn drop(&mut self) { + let f = self.f.take().unwrap(); + let mut f = Some(f); + let mut f = move || f.take().unwrap()(); + f(); + } +} + +macro_rules! defer { + ($body:expr) => { + let _defer = Defer { + f: Some(Box::new(|| $body)), + }; + }; +} + +macro_rules! go { + (@parse ref $v:ident, $($tail:tt)*) => {{ + let ref $v = $v; + go!(@parse $($tail)*) + }}; + (@parse move $v:ident, $($tail:tt)*) => {{ + let $v = $v; + go!(@parse $($tail)*) + }}; + (@parse $v:ident, $($tail:tt)*) => {{ + let $v = $v.clone(); + go!(@parse $($tail)*) + }}; + (@parse $body:expr) => { + ::std::thread::spawn(move || { + let res = ::std::panic::catch_unwind(::std::panic::AssertUnwindSafe(|| { + $body + })); + if res.is_err() { + eprintln!("goroutine panicked: {:?}", res); + ::std::process::abort(); + } + }) + }; + (@parse $($tail:tt)*) => { + compile_error!("invalid `go!` syntax") + }; + ($($tail:tt)*) => {{ + go!(@parse $($tail)*) + }}; +} + +// https://github.com/golang/go/blob/master/test/chan/doubleselect.go +mod doubleselect { + use super::*; + + const ITERATIONS: i32 = 10_000; + + fn sender(n: i32, c1: Chan, c2: Chan, c3: Chan, c4: Chan) { + defer! { c1.close() } + defer! { c2.close() } + defer! { c3.close() } + defer! { c4.close() } + + for i in 0..n { + select! { + send(c1.tx(), i) -> _ => {} + send(c2.tx(), i) -> _ => {} + send(c3.tx(), i) -> _ => {} + send(c4.tx(), i) -> _ => {} + } + } + } + + fn mux(out: Chan, inp: Chan, done: Chan) { + for v in inp { + out.send(v); + } + done.send(true); + } + + fn recver(inp: Chan) { + let mut seen = HashMap::new(); + + for v in &inp { + if seen.contains_key(&v) { + panic!("got duplicate value for {}", v); + } + seen.insert(v, true); + } + } + + #[test] + fn main() { + let c1 = make::(0); + let c2 = make::(0); + let c3 = make::(0); + let c4 = make::(0); + let done = make::(0); + let cmux = make::(0); + + go!(c1, c2, c3, c4, sender(ITERATIONS, c1, c2, c3, c4)); + go!(cmux, c1, done, mux(cmux, c1, done)); + go!(cmux, c2, done, mux(cmux, c2, done)); + go!(cmux, c3, done, mux(cmux, c3, done)); + go!(cmux, c4, done, mux(cmux, c4, done)); + go!(done, cmux, { + done.recv(); + done.recv(); + done.recv(); + done.recv(); + cmux.close(); + }); + recver(cmux); + } +} + +// https://github.com/golang/go/blob/master/test/chan/fifo.go +mod fifo { + use super::*; + + const N: i32 = 10; + + #[test] + fn asynch_fifo() { + let ch = make::(N as usize); + for i in 0..N { + ch.send(i); + } + for i in 0..N { + if ch.recv() != Some(i) { + panic!("bad receive"); + } + } + } + + fn chain(ch: Chan, val: i32, inp: Chan, out: Chan) { + inp.recv(); + if ch.recv() != Some(val) { + panic!(val); + } + out.send(1); + } + + #[test] + fn synch_fifo() { + let ch = make::(0); + let mut inp = make::(0); + let start = inp.clone(); + + for i in 0..N { + let out = make::(0); + go!(ch, i, inp, out, chain(ch, i, inp, out)); + inp = out; + } + + start.send(0); + for i in 0..N { + ch.send(i); + } + inp.recv(); + } +} + +// https://github.com/golang/go/blob/master/test/chan/goroutines.go +mod goroutines { + use super::*; + + fn f(left: Chan, right: Chan) { + left.send(right.recv().unwrap()); + } + + #[test] + fn main() { + let n = 100i32; + + let leftmost = make::(0); + let mut right = leftmost.clone(); + let mut left = leftmost.clone(); + + for _ in 0..n { + right = make::(0); + go!(left, right, f(left, right)); + left = right.clone(); + } + + go!(right, right.send(1)); + leftmost.recv().unwrap(); + } +} + +// https://github.com/golang/go/blob/master/test/chan/nonblock.go +mod nonblock { + use super::*; + + fn i32receiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != 123 { + panic!("i32 value"); + } + strobe.send(true); + } + + fn i32sender(c: Chan, strobe: Chan) { + c.send(234); + strobe.send(true); + } + + fn i64receiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != 123456 { + panic!("i64 value"); + } + strobe.send(true); + } + + fn i64sender(c: Chan, strobe: Chan) { + c.send(234567); + strobe.send(true); + } + + fn breceiver(c: Chan, strobe: Chan) { + if !c.recv().unwrap() { + panic!("b value"); + } + strobe.send(true); + } + + fn bsender(c: Chan, strobe: Chan) { + c.send(true); + strobe.send(true); + } + + fn sreceiver(c: Chan, strobe: Chan) { + if c.recv().unwrap() != "hello" { + panic!("x value"); + } + strobe.send(true); + } + + fn ssender(c: Chan, strobe: Chan) { + c.send("hello again".to_string()); + strobe.send(true); + } + + const MAX_TRIES: usize = 10000; // Up to 100ms per test. + + #[test] + fn main() { + let ticker = tick(Duration::new(0, 10_000)); // 10 us + let sleep = || { + ticker.recv().unwrap(); + ticker.recv().unwrap(); + thread::yield_now(); + thread::yield_now(); + thread::yield_now(); + }; + + let sync = make::(0); + + for buffer in 0..2 { + let c32 = make::(buffer); + let c64 = make::(buffer); + let cb = make::(buffer); + let cs = make::(buffer); + + select! { + recv(c32.rx()) -> _ => panic!("blocked i32sender"), + default => {} + } + + select! { + recv(c64.rx()) -> _ => panic!("blocked i64sender"), + default => {} + } + + select! { + recv(cb.rx()) -> _ => panic!("blocked bsender"), + default => {} + } + + select! { + recv(cs.rx()) -> _ => panic!("blocked ssender"), + default => {} + } + + go!(c32, sync, i32receiver(c32, sync)); + let mut try = 0; + loop { + select! { + send(c32.tx(), 123) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("i32receiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(c32, sync, i32sender(c32, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(c32.rx()) -> v => { + if v != Ok(234) { + panic!("i32sender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("i32sender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(c64, sync, i64receiver(c64, sync)); + let mut try = 0; + loop { + select! { + send(c64.tx(), 123456) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("i64receiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(c64, sync, i64sender(c64, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(c64.rx()) -> v => { + if v != Ok(234567) { + panic!("i64sender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("i64sender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(cb, sync, breceiver(cb, sync)); + let mut try = 0; + loop { + select! { + send(cb.tx(), true) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("breceiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(cb, sync, bsender(cb, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(cb.rx()) -> v => { + if v != Ok(true) { + panic!("bsender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("bsender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + + go!(cs, sync, sreceiver(cs, sync)); + let mut try = 0; + loop { + select! { + send(cs.tx(), "hello".to_string()) -> _ => break, + default => { + try += 1; + if try > MAX_TRIES { + println!("sreceiver buffer={}", buffer); + panic!("fail") + } + sleep(); + } + } + } + sync.recv(); + go!(cs, sync, ssender(cs, sync)); + if buffer > 0 { + sync.recv(); + } + let mut try = 0; + loop { + select! { + recv(cs.rx()) -> v => { + if v != Ok("hello again".to_string()) { + panic!("ssender value"); + } + break; + } + default => { + try += 1; + if try > MAX_TRIES { + println!("ssender buffer={}", buffer); + panic!("fail"); + } + sleep(); + } + } + } + if buffer == 0 { + sync.recv(); + } + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/select.go +mod select { + use super::*; + + #[test] + fn main() { + let shift = Cell::new(0); + let counter = Cell::new(0); + + let get_value = || { + counter.set(counter.get() + 1); + 1 << shift.get() + }; + + let send = |mut a: Option<&Chan>, mut b: Option<&Chan>| { + let mut i = 0; + let never = make::(0); + loop { + let nil1 = never.tx(); + let nil2 = never.tx(); + let v1 = get_value(); + let v2 = get_value(); + select! { + send(a.map(|c| c.tx()).unwrap_or(nil1), v1) -> _ => { + i += 1; + a = None; + } + send(b.map(|c| c.tx()).unwrap_or(nil2), v2) -> _ => { + i += 1; + b = None; + } + default => break, + } + shift.set(shift.get() + 1); + } + i + }; + + let a = make::(1); + let b = make::(1); + + assert_eq!(send(Some(&a), Some(&b)), 2); + + let av = a.recv().unwrap(); + let bv = b.recv().unwrap(); + assert_eq!(av | bv, 3); + + assert_eq!(send(Some(&a), None), 1); + assert_eq!(counter.get(), 10); + } +} + +// https://github.com/golang/go/blob/master/test/chan/select2.go +mod select2 { + // TODO +} + +// https://github.com/golang/go/blob/master/test/chan/select3.go +mod select3 { + // TODO +} + +// https://github.com/golang/go/blob/master/test/chan/select4.go +mod select4 { + use super::*; + + #[test] + fn main() { + let c = make::(1); + let c1 = make::(0); + c.send(42); + select! { + recv(c1.rx()) -> _ => panic!("BUG"), + recv(c.rx()) -> v => assert_eq!(v, Ok(42)), + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/select6.go +mod select6 { + use super::*; + + #[test] + fn main() { + let c1 = make::(0); + let c2 = make::(0); + let c3 = make::(0); + + go!(c1, c1.recv()); + go!(c1, c2, c3, { + select! { + recv(c1.rx()) -> _ => panic!("dummy"), + recv(c2.rx()) -> _ => c3.send(true), + } + c1.recv(); + }); + go!(c2, c2.send(true)); + + c3.recv(); + c1.send(true); + c1.send(true); + } +} + +// https://github.com/golang/go/blob/master/test/chan/select7.go +mod select7 { + use super::*; + + fn recv1(c: Chan) { + c.recv().unwrap(); + } + + fn recv2(c: Chan) { + select! { + recv(c.rx()) -> _ => () + } + } + + fn recv3(c: Chan) { + let c2 = make::(1); + select! { + recv(c.rx()) -> _ => (), + recv(c2.rx()) -> _ => () + } + } + + fn send1(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + c.send(1); + } + + fn send2(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + select! { + send(c.tx(), 1) -> _ => () + } + } + + fn send3(recv: fn(Chan)) { + let c = make::(1); + go!(c, recv(c)); + thread::yield_now(); + let c2 = make::(1); + select! { + send(c.tx(), 1) -> _ => (), + send(c2.tx(), 1) -> _ => () + } + } + + #[test] + fn main() { + send1(recv1); + send2(recv1); + send3(recv1); + send1(recv2); + send2(recv2); + send3(recv2); + send1(recv3); + send2(recv3); + send3(recv3); + } +} + +// https://github.com/golang/go/blob/master/test/chan/sieve1.go +mod sieve1 { + use super::*; + + fn generate(ch: Chan) { + let mut i = 2; + loop { + ch.send(i); + i += 1; + } + } + + fn filter(in_ch: Chan, out_ch: Chan, prime: i32) { + for i in in_ch { + if i % prime != 0 { + out_ch.send(i); + } + } + } + + fn sieve(primes: Chan) { + let mut ch = make::(1); + go!(ch, generate(ch)); + loop { + let prime = ch.recv().unwrap(); + primes.send(prime); + + let ch1 = make::(1); + go!(ch, ch1, prime, filter(ch, ch1, prime)); + ch = ch1; + } + } + + #[test] + fn main() { + let primes = make::(1); + go!(primes, sieve(primes)); + + let a = [ + 2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, + 89, 97, + ]; + for item in a.iter() { + let x = primes.recv().unwrap(); + if x != *item { + println!("{} != {}", x, item); + panic!("fail"); + } + } + } +} + +// https://github.com/golang/go/blob/master/test/chan/zerosize.go +mod zerosize { + use super::*; + + #[test] + fn zero_size_struct() { + struct ZeroSize; + let _ = make::(0); + } + + #[test] + fn zero_size_array() { + let _ = make::<[u8; 0]>(0); + } +} + +// https://github.com/golang/go/blob/master/src/runtime/chan_test.go +mod chan_test { + use super::*; + + #[test] + fn test_chan() { + const N: i32 = 200; + + for cap in 0..N { + { + // Ensure that receive from empty chan blocks. + let c = make::(cap as usize); + + let recv1 = Arc::new(Mutex::new(false)); + go!(c, recv1, { + c.recv(); + *recv1.lock().unwrap() = true; + }); + + let recv2 = Arc::new(Mutex::new(false)); + go!(c, recv2, { + c.recv(); + *recv2.lock().unwrap() = true; + }); + + thread::sleep(ms(1)); + + if *recv1.lock().unwrap() || *recv2.lock().unwrap() { + panic!(); + } + + // Ensure that non-blocking receive does not block. + select! { + recv(c.rx()) -> _ => panic!(), + default => {} + } + select! { + recv(c.rx()) -> _ => panic!(), + default => {} + } + + c.send(0); + c.send(0); + } + + { + // Ensure that send to full chan blocks. + let c = make::(cap as usize); + for i in 0..cap { + c.send(i); + } + + let sent = Arc::new(Mutex::new(0)); + go!(sent, c, { + c.send(0); + *sent.lock().unwrap() = 1; + }); + + thread::sleep(ms(1)); + + if *sent.lock().unwrap() != 0 { + panic!(); + } + + // Ensure that non-blocking send does not block. + select! { + send(c.tx(), 0) -> _ => panic!(), + default => {} + } + c.recv(); + } + + { + // Ensure that we receive 0 from closed chan. + let c = make::(cap as usize); + for i in 0..cap { + c.send(i); + } + c.close(); + + for i in 0..cap { + let v = c.recv(); + if v != Some(i) { + panic!(); + } + } + + if c.recv() != None { + panic!(); + } + if c.try_recv() != None { + panic!(); + } + } + + { + // Ensure that close unblocks receive. + let c = make::(cap as usize); + let done = make::(0); + + go!(c, done, { + let v = c.try_recv(); + done.send(v.is_some()); + }); + + thread::sleep(ms(1)); + c.close(); + + if !done.recv().unwrap() { + // panic!(); + } + } + + { + // Send 100 integers, + // ensure that we receive them non-corrupted in FIFO order. + let c = make::(cap as usize); + go!(c, { + for i in 0..100 { + c.send(i); + } + }); + for i in 0..100 { + if c.recv() != Some(i) { + panic!(); + } + } + + // Same, but using recv2. + go!(c, { + for i in 0..100 { + c.send(i); + } + }); + for i in 0..100 { + if c.recv() != Some(i) { + panic!(); + } + } + } + } + } + + #[test] + fn test_nonblock_recv_race() { + const N: usize = 1000; + + for _ in 0..N { + let c = make::(1); + c.send(1); + + let t = go!(c, { + select! { + recv(c.rx()) -> _ => {} + default => panic!("chan is not ready"), + } + }); + + c.close(); + c.recv(); + t.join().unwrap(); + } + } + + #[test] + fn test_nonblock_select_race() { + const N: usize = 1000; + + let done = make::(1); + for _ in 0..N { + let c1 = make::(1); + let c2 = make::(1); + c1.send(1); + + go!(c1, c2, done, { + select! { + recv(c1.rx()) -> _ => {} + recv(c2.rx()) -> _ => {} + default => { + done.send(false); + return; + } + } + done.send(true); + }); + + c2.send(1); + select! { + recv(c1.rx()) -> _ => {} + default => {} + } + if !done.recv().unwrap() { + panic!("no chan is ready"); + } + } + } + + #[test] + fn test_nonblock_select_race2() { + const N: usize = 1000; + + let done = make::(1); + for _ in 0..N { + let c1 = make::(1); + let c2 = make::(0); + c1.send(1); + + go!(c1, c2, done, { + select! { + recv(c1.rx()) -> _ => {} + recv(c2.rx()) -> _ => {} + default => { + done.send(false); + return; + } + } + done.send(true); + }); + + c2.close(); + select! { + recv(c1.rx()) -> _ => {} + default => {} + } + if !done.recv().unwrap() { + panic!("no chan is ready"); + } + } + } + + #[test] + fn test_self_select() { + // Ensure that send/recv on the same chan in select + // does not crash nor deadlock. + + for &cap in &[0, 10] { + let wg = WaitGroup::new(); + wg.add(2); + let c = make::(cap); + + for p in 0..2 { + let p = p; + go!(wg, p, c, { + defer! { wg.done() } + for i in 0..1000 { + if p == 0 || i % 2 == 0 { + select! { + send(c.tx(), p) -> _ => {} + recv(c.rx()) -> v => { + if cap == 0 && v.ok() == Some(p) { + panic!("self receive"); + } + } + } + } else { + select! { + recv(c.rx()) -> v => { + if cap == 0 && v.ok() == Some(p) { + panic!("self receive"); + } + } + send(c.tx(), p) -> _ => {} + } + } + } + }); + } + wg.wait(); + } + } + + #[test] + fn test_select_stress() { + let c = vec![ + make::(0), + make::(0), + make::(2), + make::(3), + ]; + + const N: usize = 10000; + + // There are 4 goroutines that send N values on each of the chans, + // + 4 goroutines that receive N values on each of the chans, + // + 1 goroutine that sends N values on each of the chans in a single select, + // + 1 goroutine that receives N values on each of the chans in a single select. + // All these sends, receives and selects interact chaotically at runtime, + // but we are careful that this whole construct does not deadlock. + let wg = WaitGroup::new(); + wg.add(10); + + for k in 0..4 { + go!(k, c, wg, { + for _ in 0..N { + c[k].send(0); + } + wg.done(); + }); + go!(k, c, wg, { + for _ in 0..N { + c[k].recv(); + } + wg.done(); + }); + } + + go!(c, wg, { + let mut n = [0; 4]; + let mut c1 = c.iter().map(|c| Some(c.rx().clone())).collect::>(); + + for _ in 0..4 * N { + let index = { + let mut sel = Select::new(); + let mut opers = [!0; 4]; + for &i in &[3, 2, 0, 1] { + if let Some(c) = &c1[i] { + opers[i] = sel.recv(c); + } + } + + let oper = sel.select(); + let mut index = !0; + for i in 0..4 { + if opers[i] == oper.index() { + index = i; + let _ = oper.recv(c1[i].as_ref().unwrap()); + break; + } + } + index + }; + + n[index] += 1; + if n[index] == N { + c1[index] = None; + } + } + wg.done(); + }); + + go!(c, wg, { + let mut n = [0; 4]; + let mut c1 = c.iter().map(|c| Some(c.tx().clone())).collect::>(); + + for _ in 0..4 * N { + let index = { + let mut sel = Select::new(); + let mut opers = [!0; 4]; + for &i in &[0, 1, 2, 3] { + if let Some(c) = &c1[i] { + opers[i] = sel.send(c); + } + } + + let oper = sel.select(); + let mut index = !0; + for i in 0..4 { + if opers[i] == oper.index() { + index = i; + let _ = oper.send(c1[i].as_ref().unwrap(), 0); + break; + } + } + index + }; + + n[index] += 1; + if n[index] == N { + c1[index] = None; + } + } + wg.done(); + }); + + wg.wait(); + } + + #[test] + fn test_select_fairness() { + const TRIALS: usize = 10000; + + let c1 = make::(TRIALS + 1); + let c2 = make::(TRIALS + 1); + + for _ in 0..TRIALS + 1 { + c1.send(1); + c2.send(2); + } + + let c3 = make::(0); + let c4 = make::(0); + let out = make::(0); + let done = make::(0); + let wg = WaitGroup::new(); + + wg.add(1); + go!(wg, c1, c2, c3, c4, out, done, { + defer! { wg.done() }; + loop { + let b; + select! { + recv(c3.rx()) -> m => b = m.unwrap(), + recv(c4.rx()) -> m => b = m.unwrap(), + recv(c1.rx()) -> m => b = m.unwrap(), + recv(c2.rx()) -> m => b = m.unwrap(), + } + select! { + send(out.tx(), b) -> _ => {} + recv(done.rx()) -> _ => return, + } + } + }); + + let (mut cnt1, mut cnt2) = (0, 0); + for _ in 0..TRIALS { + match out.recv() { + Some(1) => cnt1 += 1, + Some(2) => cnt2 += 1, + b => panic!("unexpected value {:?} on channel", b), + } + } + + // If the select in the goroutine is fair, + // cnt1 and cnt2 should be about the same value. + // With 10,000 trials, the expected margin of error at + // a confidence level of five nines is 4.4172 / (2 * Sqrt(10000)). + + let r = cnt1 as f64 / TRIALS as f64; + let e = (r - 0.5).abs(); + + if e > 4.4172 / (2.0 * (TRIALS as f64).sqrt()) { + panic!( + "unfair select: in {} trials, results were {}, {}", + TRIALS, cnt1, cnt2, + ); + } + + done.close(); + wg.wait(); + } + + #[test] + fn test_chan_send_interface() { + struct Mt; + + let c = make::>(1); + c.send(Box::new(Mt)); + + select! { + send(c.tx(), Box::new(Mt)) -> _ => {} + default => {} + } + + select! { + send(c.tx(), Box::new(Mt)) -> _ => {} + send(c.tx(), Box::new(Mt)) -> _ => {} + default => {} + } + } + + #[test] + fn test_pseudo_random_send() { + const N: usize = 100; + + for cap in 0..N { + let c = make::(cap); + let l = Arc::new(Mutex::new(vec![0i32; N])); + let done = make::(0); + + go!(c, done, l, { + let mut l = l.lock().unwrap(); + for i in 0..N { + thread::yield_now(); + l[i] = c.recv().unwrap(); + } + done.send(true); + }); + + for _ in 0..N { + select! { + send(c.tx(), 1) -> _ => {} + send(c.tx(), 0) -> _ => {} + } + } + done.recv(); + + let mut n0 = 0; + let mut n1 = 0; + for &i in l.lock().unwrap().iter() { + n0 += (i + 1) % 2; + n1 += i; + } + + if n0 <= N as i32 / 10 || n1 <= N as i32 / 10 { + panic!( + "Want pseudorandom, got {} zeros and {} ones (chan cap {})", + n0, n1, cap, + ); + } + } + } + + #[test] + fn test_multi_consumer() { + const NWORK: usize = 23; + const NITER: usize = 271828; + + let pn = [2, 3, 7, 11, 13, 17, 19, 23, 27, 31]; + + let q = make::(NWORK * 3); + let r = make::(NWORK * 3); + + let wg = WaitGroup::new(); + for i in 0..NWORK { + wg.add(1); + let w = i; + go!(q, r, wg, pn, { + for v in &q { + if pn[w % pn.len()] == v { + thread::yield_now(); + } + r.send(v); + } + wg.done(); + }); + } + + let expect = Arc::new(Mutex::new(0)); + go!(q, r, expect, wg, pn, { + for i in 0..NITER { + let v = pn[i % pn.len()]; + *expect.lock().unwrap() += v; + q.send(v); + } + q.close(); + wg.wait(); + r.close(); + }); + + let mut n = 0; + let mut s = 0; + for v in &r { + n += 1; + s += v; + } + + if n != NITER || s != *expect.lock().unwrap() { + panic!(); + } + } + + #[test] + fn test_select_duplicate_channel() { + // This test makes sure we can queue a G on + // the same channel multiple times. + let c = make::(0); + let d = make::(0); + let e = make::(0); + + go!(c, d, e, { + select! { + recv(c.rx()) -> _ => {} + recv(d.rx()) -> _ => {} + recv(e.rx()) -> _ => {} + } + e.send(9); + }); + thread::sleep(ms(1)); + + go!(c, c.recv()); + thread::sleep(ms(1)); + + d.send(7); + e.recv(); + c.send(8); + } +} + +// https://github.com/golang/go/blob/master/test/closedchan.go +mod closedchan { + // TODO +} + +// https://github.com/golang/go/blob/master/src/runtime/chanbarrier_test.go +mod chanbarrier_test { + // TODO +} + +// https://github.com/golang/go/blob/master/src/runtime/race/testdata/chan_test.go +mod race_chan_test { + // TODO +} + +// https://github.com/golang/go/blob/master/test/ken/chan.go +mod chan { + // TODO +} + +// https://github.com/golang/go/blob/master/test/ken/chan1.go +mod chan1 { + // TODO +} diff --git a/vendor/crossbeam-channel/tests/iter.rs b/vendor/crossbeam-channel/tests/iter.rs new file mode 100644 index 0000000000..6acec59c28 --- /dev/null +++ b/vendor/crossbeam-channel/tests/iter.rs @@ -0,0 +1,113 @@ +//! Tests for iteration over receivers. + +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use crossbeam_channel::unbounded; +use crossbeam_utils::thread::scope; + +#[test] +fn nested_recv_iter() { + let (s, r) = unbounded::(); + let (total_s, total_r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + let mut acc = 0; + for x in r.iter() { + acc += x; + } + total_s.send(acc).unwrap(); + }); + + s.send(3).unwrap(); + s.send(1).unwrap(); + s.send(2).unwrap(); + drop(s); + assert_eq!(total_r.recv().unwrap(), 6); + }) + .unwrap(); +} + +#[test] +fn recv_iter_break() { + let (s, r) = unbounded::(); + let (count_s, count_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + for x in r.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_s.send(count).unwrap(); + }); + + s.send(2).unwrap(); + s.send(2).unwrap(); + s.send(2).unwrap(); + let _ = s.send(2); + drop(s); + assert_eq!(count_r.recv().unwrap(), 4); + }) + .unwrap(); +} + +#[test] +fn recv_try_iter() { + let (request_s, request_r) = unbounded(); + let (response_s, response_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == 6 { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(2).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn recv_into_iter_owned() { + let mut iter = { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + r.into_iter() + }; + + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} + +#[test] +fn recv_into_iter_borrowed() { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + drop(s); + + let mut iter = (&r).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); +} diff --git a/vendor/crossbeam-channel/tests/list.rs b/vendor/crossbeam-channel/tests/list.rs new file mode 100644 index 0000000000..ed1d4c4209 --- /dev/null +++ b/vendor/crossbeam-channel/tests/list.rs @@ -0,0 +1,538 @@ +//! Tests for the list channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{unbounded, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = unbounded(); + s.try_send(7).unwrap(); + assert_eq!(r.try_recv(), Ok(7)); + + s.send(8).unwrap(); + assert_eq!(r.recv(), Ok(8)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); +} + +#[test] +fn capacity() { + let (s, r) = unbounded::<()>(); + assert_eq!(s.capacity(), None); + assert_eq!(r.capacity(), None); +} + +#[test] +fn len_empty_full() { + let (s, r) = unbounded(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + s.send(()).unwrap(); + + assert_eq!(s.len(), 1); + assert_eq!(s.is_empty(), false); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), false); + + r.recv().unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), false); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.try_send(i), Ok(())); + } + + drop(r); + assert_eq!(s.try_send(777), Err(TrySendError::Disconnected(777))); +} + +#[test] +fn send() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.send(i), Ok(())); + } + + drop(r); + assert_eq!(s.send(777), Err(SendError(777))); +} + +#[test] +fn send_timeout() { + let (s, r) = unbounded(); + for i in 0..1000 { + assert_eq!(s.send_timeout(i, ms(i as u64)), Ok(())); + } + + drop(r); + assert_eq!( + s.send_timeout(777, ms(0)), + Err(SendTimeoutError::Disconnected(777)) + ); +} + +#[test] +fn send_after_disconnect() { + let (s, r) = unbounded(); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(r); + + assert_eq!(s.send(4), Err(SendError(4))); + assert_eq!(s.try_send(5), Err(TrySendError::Disconnected(5))); + assert_eq!( + s.send_timeout(6, ms(0)), + Err(SendTimeoutError::Disconnected(6)) + ); +} + +#[test] +fn recv_after_disconnect() { + let (s, r) = unbounded(); + + s.send(1).unwrap(); + s.send(2).unwrap(); + s.send(3).unwrap(); + + drop(s); + + assert_eq!(r.recv(), Ok(1)); + assert_eq!(r.recv(), Ok(2)); + assert_eq!(r.recv(), Ok(3)); + assert_eq!(r.recv(), Err(RecvError)); +} + +#[test] +fn len() { + let (s, r) = unbounded(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + for i in 0..50 { + s.send(i).unwrap(); + assert_eq!(s.len(), i + 1); + } + + for i in 0..50 { + r.recv().unwrap(); + assert_eq!(r.len(), 50 - i - 1); + } + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = unbounded::(); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 100_000; + + let (request_s, request_r) = unbounded(); + let (response_s, response_r) = unbounded(); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + request_s.send(()).unwrap(); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = unbounded(); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + s.send(i).unwrap(); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..100 { + let steps = rng.gen_range(0, 10_000); + let additional = rng.gen_range(0, 1000); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + for _ in 0..additional { + s.try_send(DropCounter).unwrap(); + } + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); + } +} + +#[test] +fn linearizable() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = unbounded(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + s.send(0).unwrap(); + r.try_recv().unwrap(); + } + }); + } + }) + .unwrap(); +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = unbounded(); + + for _ in 0..COUNT { + s.send(()).unwrap(); + } + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn recv_in_send() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + select! { + send(s, assert_eq!(r.recv(), Ok(()))) -> _ => {} + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = unbounded::(); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = unbounded(); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/mpsc.rs b/vendor/crossbeam-channel/tests/mpsc.rs new file mode 100644 index 0000000000..213b9d8b7d --- /dev/null +++ b/vendor/crossbeam-channel/tests/mpsc.rs @@ -0,0 +1,2095 @@ +//! Tests copied from `std::sync::mpsc`. +//! +//! This is a copy of tests for the `std::sync::mpsc` channels from the standard library, but +//! modified to work with `crossbeam-channel` instead. +//! +//! Minor tweaks were needed to make the tests compile: +//! +//! - Replace `box` syntax with `Box::new`. +//! - Replace all uses of `Select` with `select!`. +//! - Change the imports. +//! - Join all spawned threads. +//! - Removed assertion from oneshot_multi_thread_send_close_stress tests. +//! +//! Source: +//! - https://github.com/rust-lang/rust/tree/master/src/libstd/sync/mpsc +//! +//! Copyright & License: +//! - Copyright 2013-2014 The Rust Project Developers +//! - Apache License, Version 2.0 or MIT license, at your option +//! - https://github.com/rust-lang/rust/blob/master/COPYRIGHT +//! - https://www.rust-lang.org/en-US/legal.html + +#[macro_use] +extern crate crossbeam_channel as cc; + +use std::sync::mpsc::{RecvError, RecvTimeoutError, TryRecvError}; +use std::sync::mpsc::{SendError, TrySendError}; +use std::thread::JoinHandle; +use std::time::Duration; + +pub struct Sender { + pub inner: cc::Sender, +} + +impl Sender { + pub fn send(&self, t: T) -> Result<(), SendError> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } +} + +impl Clone for Sender { + fn clone(&self) -> Sender { + Sender { + inner: self.inner.clone(), + } + } +} + +pub struct SyncSender { + pub inner: cc::Sender, +} + +impl SyncSender { + pub fn send(&self, t: T) -> Result<(), SendError> { + self.inner.send(t).map_err(|cc::SendError(m)| SendError(m)) + } + + pub fn try_send(&self, t: T) -> Result<(), TrySendError> { + self.inner.try_send(t).map_err(|err| match err { + cc::TrySendError::Full(m) => TrySendError::Full(m), + cc::TrySendError::Disconnected(m) => TrySendError::Disconnected(m), + }) + } +} + +impl Clone for SyncSender { + fn clone(&self) -> SyncSender { + SyncSender { + inner: self.inner.clone(), + } + } +} + +pub struct Receiver { + pub inner: cc::Receiver, +} + +impl Receiver { + pub fn try_recv(&self) -> Result { + self.inner.try_recv().map_err(|err| match err { + cc::TryRecvError::Empty => TryRecvError::Empty, + cc::TryRecvError::Disconnected => TryRecvError::Disconnected, + }) + } + + pub fn recv(&self) -> Result { + self.inner.recv().map_err(|_| RecvError) + } + + pub fn recv_timeout(&self, timeout: Duration) -> Result { + self.inner.recv_timeout(timeout).map_err(|err| match err { + cc::RecvTimeoutError::Timeout => RecvTimeoutError::Timeout, + cc::RecvTimeoutError::Disconnected => RecvTimeoutError::Disconnected, + }) + } + + pub fn iter(&self) -> Iter { + Iter { inner: self } + } + + pub fn try_iter(&self) -> TryIter { + TryIter { inner: self } + } +} + +impl<'a, T> IntoIterator for &'a Receiver { + type Item = T; + type IntoIter = Iter<'a, T>; + + fn into_iter(self) -> Iter<'a, T> { + self.iter() + } +} + +impl IntoIterator for Receiver { + type Item = T; + type IntoIter = IntoIter; + + fn into_iter(self) -> IntoIter { + IntoIter { inner: self } + } +} + +pub struct TryIter<'a, T: 'a> { + inner: &'a Receiver, +} + +impl<'a, T> Iterator for TryIter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.try_recv().ok() + } +} + +pub struct Iter<'a, T: 'a> { + inner: &'a Receiver, +} + +impl<'a, T> Iterator for Iter<'a, T> { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.recv().ok() + } +} + +pub struct IntoIter { + inner: Receiver, +} + +impl Iterator for IntoIter { + type Item = T; + + fn next(&mut self) -> Option { + self.inner.recv().ok() + } +} + +pub fn channel() -> (Sender, Receiver) { + let (s, r) = cc::unbounded(); + let s = Sender { inner: s }; + let r = Receiver { inner: r }; + (s, r) +} + +pub fn sync_channel(bound: usize) -> (SyncSender, Receiver) { + let (s, r) = cc::bounded(bound); + let s = SyncSender { inner: s }; + let r = Receiver { inner: r }; + (s, r) +} + +macro_rules! select { + ( + $($name:pat = $rx:ident.$meth:ident() => $code:expr),+ + ) => ({ + crossbeam_channel_internal! { + $( + recv(($rx).inner) -> res => { + let $name = res.map_err(|_| ::std::sync::mpsc::RecvError); + $code + } + )+ + } + }) +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs +mod channel_tests { + use super::*; + + use std::env; + use std::thread; + use std::time::{Duration, Instant}; + + pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } + } + + #[test] + fn smoke() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = channel::>(); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn drop_full_shared() { + let (tx, _rx) = channel::>(); + drop(tx.clone()); + drop(tx.clone()); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn smoke_threads() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); + t.join().unwrap(); + } + + #[test] + fn smoke_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(1).is_err()) + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = channel::(); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); + } + + #[test] + fn port_gone_concurrent() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn port_gone_concurrent_shared() { + let (tx, rx) = channel::(); + let tx2 = tx.clone(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn smoke_chan_gone() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn smoke_chan_gone_shared() { + let (tx, rx) = channel::<()>(); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); + } + + #[test] + fn chan_gone_concurrent() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} + t.join().unwrap(); + } + + #[test] + fn stress() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().ok().unwrap(); + } + + #[test] + fn stress_shared() { + const AMT: u32 = 10000; + const NTHREADS: u32 = 8; + let (tx, rx) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + }); + + let mut ts = Vec::with_capacity(NTHREADS as usize); + for _ in 0..NTHREADS { + let tx = tx.clone(); + let t = thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + drop(tx); + t.join().ok().unwrap(); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn send_from_outside_runtime() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + tx1.send(()).unwrap(); + for _ in 0..40 { + assert_eq!(rx2.recv().unwrap(), 1); + } + }); + rx1.recv().unwrap(); + let t2 = thread::spawn(move || { + for _ in 0..40 { + tx2.send(1).unwrap(); + } + }); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); + } + + #[test] + fn recv_from_outside_runtime() { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + for _ in 0..40 { + assert_eq!(rx.recv().unwrap(), 1); + } + }); + for _ in 0..40 { + tx.send(1).unwrap(); + } + t.join().ok().unwrap(); + } + + #[test] + fn no_runtime() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let t1 = thread::spawn(move || { + assert_eq!(rx1.recv().unwrap(), 1); + tx2.send(2).unwrap(); + }); + let t2 = thread::spawn(move || { + tx1.send(1).unwrap(); + assert_eq!(rx2.recv().unwrap(), 2); + }); + t1.join().ok().unwrap(); + t2.join().ok().unwrap(); + } + + #[test] + fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = channel::(); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = channel::(); + drop(tx); + } + + #[test] + fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = channel::>(); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = channel::>(); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_open() { + let (tx, rx) = channel::(); + assert!(tx.send(10).is_ok()); + assert!(rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = channel::(); + drop(rx); + assert!(tx.send(10).is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = channel::(); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = channel::(); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_peek_data() { + let (tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); + } + + #[test] + fn oneshot_single_thread_peek_close() { + let (tx, rx) = channel::(); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_open() { + let (_tx, rx) = channel::(); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + drop(tx); + }); + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_thread_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + drop(tx); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + thread::spawn(move || { + let _ = tx.send(1); + }) + .join() + .unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_recv_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::(); + let t = thread::spawn(move || { + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + }); + ts.push(t); + let t2 = thread::spawn(move || { + let t = thread::spawn(move || { + drop(tx); + }); + t.join().unwrap(); + }); + ts.push(t2); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel::>(); + let t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + ts.push(t); + assert!(*rx.recv().unwrap() == 10); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn stream_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = channel(); + + if let Some(t) = send(tx, 0) { + ts.push(t); + } + if let Some(t2) = recv(rx, 0) { + ts.push(t2); + } + + fn send(tx: Sender>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + })) + } + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_single_thread_recv_timeout() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + } + + #[test] + fn stress_recv_timeout_two_threads() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + let timeout = Duration::from_millis(100); + + let t = thread::spawn(move || { + for i in 0..stress { + if i % 2 == 0 { + thread::sleep(timeout * 2); + } + tx.send(1usize).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(timeout) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); + t.join().unwrap() + } + + #[test] + fn recv_timeout_upgrade() { + let (tx, rx) = channel::<()>(); + let timeout = Duration::from_millis(1); + let _tx_clone = tx.clone(); + + let start = Instant::now(); + assert_eq!(rx.recv_timeout(timeout), Err(RecvTimeoutError::Timeout)); + assert!(Instant::now() >= start + timeout); + } + + #[test] + fn stress_recv_timeout_shared() { + let (tx, rx) = channel(); + let stress = stress_factor() + 100; + + let mut ts = Vec::with_capacity(stress); + for i in 0..stress { + let tx = tx.clone(); + let t = thread::spawn(move || { + thread::sleep(Duration::from_millis(i as u64 * 10)); + tx.send(1usize).unwrap(); + }); + ts.push(t); + } + + drop(tx); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(n) => { + assert_eq!(n, 1usize); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, stress); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = channel(); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } + } + + #[test] + fn shared_recv_timeout() { + let (tx, rx) = channel(); + let total = 5; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(()).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(())); + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn shared_chan_stress() { + let (tx, rx) = channel(); + let total = stress_factor() + 100; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn test_nested_recv_iter() { + let (tx, rx) = channel::(); + let (total_tx, total_rx) = channel::(); + + let t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); + t.join().unwrap(); + } + + #[test] + fn test_recv_iter_break() { + let (tx, rx) = channel::(); + let (count_tx, count_rx) = channel(); + + let t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); + t.join().unwrap(); + } + + #[test] + fn test_recv_try_iter() { + let (request_tx, request_rx) = channel(); + let (response_tx, response_rx) = channel(); + + // Request `x`s until we have `6`. + let t = thread::spawn(move || { + let mut count = 0; + loop { + for x in response_rx.try_iter() { + count += x; + if count == 6 { + return count; + } + } + request_tx.send(()).unwrap(); + } + }); + + for _ in request_rx.iter() { + if response_tx.send(2).is_err() { + break; + } + } + + assert_eq!(t.join().unwrap(), 6); + } + + #[test] + fn test_recv_into_iter_owned() { + let mut iter = { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + + rx.into_iter() + }; + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); + } + + #[test] + fn test_recv_into_iter_borrowed() { + let (tx, rx) = channel::(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + let mut iter = (&rx).into_iter(); + assert_eq!(iter.next().unwrap(), 1); + assert_eq!(iter.next().unwrap(), 2); + assert_eq!(iter.next().is_none(), true); + } + + #[test] + fn try_recv_states() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + t.join().unwrap(); + } + + // This bug used to end up in a livelock inside of the Receiver destructor + // because the internal state of the Shared packet was corrupted + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = channel(); + let (tx2, rx2) = channel(); + let t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let tx2 = tx.clone(); + drop(tx); + tx2.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn issue_32114() { + let (tx, _) = channel(); + let _ = tx.send(123); + assert_eq!(tx.send(123), Err(SendError(123))); + } +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/mod.rs +mod sync_channel_tests { + use super::*; + + use std::env; + use std::thread; + use std::time::Duration; + + pub fn stress_factor() -> usize { + match env::var("RUST_TEST_STRESS") { + Ok(val) => val.parse().unwrap(), + Err(..) => 1, + } + } + + #[test] + fn smoke() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn drop_full() { + let (tx, _rx) = sync_channel::>(1); + tx.send(Box::new(1)).unwrap(); + } + + #[test] + fn smoke_shared() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + let tx = tx.clone(); + tx.send(1).unwrap(); + assert_eq!(rx.recv().unwrap(), 1); + } + + #[test] + fn recv_timeout() { + let (tx, rx) = sync_channel::(1); + assert_eq!( + rx.recv_timeout(Duration::from_millis(1)), + Err(RecvTimeoutError::Timeout) + ); + tx.send(1).unwrap(); + assert_eq!(rx.recv_timeout(Duration::from_millis(1)), Ok(1)); + } + + #[test] + fn smoke_threads() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + }); + assert_eq!(rx.recv().unwrap(), 1); + t.join().unwrap(); + } + + #[test] + fn smoke_port_gone() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert!(tx.send(1).is_err()); + } + + #[test] + fn smoke_shared_port_gone2() { + let (tx, rx) = sync_channel::(0); + drop(rx); + let tx2 = tx.clone(); + drop(tx); + assert!(tx2.send(1).is_err()); + } + + #[test] + fn port_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn port_gone_concurrent_shared() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + while tx.send(1).is_ok() && tx2.send(1).is_ok() {} + t.join().unwrap(); + } + + #[test] + fn smoke_chan_gone() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn smoke_chan_gone_shared() { + let (tx, rx) = sync_channel::<()>(0); + let tx2 = tx.clone(); + drop(tx); + drop(tx2); + assert!(rx.recv().is_err()); + } + + #[test] + fn chan_gone_concurrent() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + tx.send(1).unwrap(); + tx.send(1).unwrap(); + }); + while rx.recv().is_ok() {} + t.join().unwrap(); + } + + #[test] + fn stress() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + for _ in 0..10000 { + assert_eq!(rx.recv().unwrap(), 1); + } + t.join().unwrap(); + } + + #[test] + fn stress_recv_timeout_two_threads() { + let (tx, rx) = sync_channel::(0); + + let t = thread::spawn(move || { + for _ in 0..10000 { + tx.send(1).unwrap(); + } + }); + + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(1)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, 10000); + t.join().unwrap(); + } + + #[test] + fn stress_recv_timeout_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + let t = thread::spawn(move || { + let mut recv_count = 0; + loop { + match rx.recv_timeout(Duration::from_millis(10)) { + Ok(v) => { + assert_eq!(v, 1); + recv_count += 1; + } + Err(RecvTimeoutError::Timeout) => continue, + Err(RecvTimeoutError::Disconnected) => break, + } + } + + assert_eq!(recv_count, AMT * NTHREADS); + assert!(rx.try_recv().is_err()); + + dtx.send(()).unwrap(); + }); + + let mut ts = Vec::with_capacity(NTHREADS as usize); + for _ in 0..NTHREADS { + let tx = tx.clone(); + let t = thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + + drop(tx); + + drx.recv().unwrap(); + for t in ts { + t.join().unwrap(); + } + t.join().unwrap(); + } + + #[test] + fn stress_shared() { + const AMT: u32 = 1000; + const NTHREADS: u32 = 8; + let (tx, rx) = sync_channel::(0); + let (dtx, drx) = sync_channel::<()>(0); + + let t = thread::spawn(move || { + for _ in 0..AMT * NTHREADS { + assert_eq!(rx.recv().unwrap(), 1); + } + match rx.try_recv() { + Ok(..) => panic!(), + _ => {} + } + dtx.send(()).unwrap(); + }); + + let mut ts = Vec::with_capacity(NTHREADS as usize); + for _ in 0..NTHREADS { + let tx = tx.clone(); + let t = thread::spawn(move || { + for _ in 0..AMT { + tx.send(1).unwrap(); + } + }); + ts.push(t); + } + drop(tx); + drx.recv().unwrap(); + for t in ts { + t.join().unwrap(); + } + t.join().unwrap(); + } + + #[test] + fn oneshot_single_thread_close_port_first() { + // Simple test of closing without sending + let (_tx, rx) = sync_channel::(0); + drop(rx); + } + + #[test] + fn oneshot_single_thread_close_chan_first() { + // Simple test of closing without sending + let (tx, _rx) = sync_channel::(0); + drop(tx); + } + + #[test] + fn oneshot_single_thread_send_port_close() { + // Testing that the sender cleans up the payload if receiver is closed + let (tx, rx) = sync_channel::>(0); + drop(rx); + assert!(tx.send(Box::new(0)).is_err()); + } + + #[test] + fn oneshot_single_thread_recv_chan_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.recv(), Err(RecvError)); + } + + #[test] + fn oneshot_single_thread_send_then_recv() { + let (tx, rx) = sync_channel::>(1); + tx.send(Box::new(10)).unwrap(); + assert!(*rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_open() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(10), Ok(())); + assert!(rx.recv().unwrap() == 10); + } + + #[test] + fn oneshot_single_thread_try_send_closed() { + let (tx, rx) = sync_channel::(0); + drop(rx); + assert_eq!(tx.try_send(10), Err(TrySendError::Disconnected(10))); + } + + #[test] + fn oneshot_single_thread_try_send_closed2() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(10), Err(TrySendError::Full(10))); + } + + #[test] + fn oneshot_single_thread_try_recv_open() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + assert!(rx.recv() == Ok(10)); + } + + #[test] + fn oneshot_single_thread_try_recv_closed() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert!(rx.recv().is_err()); + } + + #[test] + fn oneshot_single_thread_try_recv_closed_with_data() { + let (tx, rx) = sync_channel::(1); + tx.send(10).unwrap(); + drop(tx); + assert_eq!(rx.try_recv(), Ok(10)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_data() { + let (tx, rx) = sync_channel::(1); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + tx.send(10).unwrap(); + assert_eq!(rx.try_recv(), Ok(10)); + } + + #[test] + fn oneshot_single_thread_peek_close() { + let (tx, rx) = sync_channel::(0); + drop(tx); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + assert_eq!(rx.try_recv(), Err(TryRecvError::Disconnected)); + } + + #[test] + fn oneshot_single_thread_peek_open() { + let (_tx, rx) = sync_channel::(0); + assert_eq!(rx.try_recv(), Err(TryRecvError::Empty)); + } + + #[test] + fn oneshot_multi_task_recv_then_send() { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + assert!(*rx.recv().unwrap() == 10); + }); + + tx.send(Box::new(10)).unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_task_recv_then_close() { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + drop(tx); + }); + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + t.join().unwrap(); + } + + #[test] + fn oneshot_multi_thread_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + drop(tx); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + ts.push(t); + thread::spawn(move || { + let _ = tx.send(1); + }) + .join() + .unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_recv_close_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + thread::spawn(move || { + assert_eq!(rx.recv(), Err(RecvError)); + }) + .join() + .unwrap(); + }); + ts.push(t); + let t2 = thread::spawn(move || { + thread::spawn(move || { + drop(tx); + }); + }); + ts.push(t2); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn oneshot_multi_thread_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::>(0); + let t = thread::spawn(move || { + tx.send(Box::new(10)).unwrap(); + }); + ts.push(t); + assert!(*rx.recv().unwrap() == 10); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn stream_send_recv_stress() { + let stress_factor = stress_factor(); + let mut ts = Vec::with_capacity(2 * stress_factor); + for _ in 0..stress_factor { + let (tx, rx) = sync_channel::>(0); + + if let Some(t) = send(tx, 0) { + ts.push(t); + } + if let Some(t) = recv(rx, 0) { + ts.push(t); + } + + fn send(tx: SyncSender>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + tx.send(Box::new(i)).unwrap(); + send(tx, i + 1); + })) + } + + fn recv(rx: Receiver>, i: i32) -> Option> { + if i == 10 { + return None; + } + + Some(thread::spawn(move || { + assert!(*rx.recv().unwrap() == i); + recv(rx, i + 1); + })) + } + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn recv_a_lot() { + // Regression test that we don't run out of stack in scheduler context + let (tx, rx) = sync_channel(10000); + for _ in 0..10000 { + tx.send(()).unwrap(); + } + for _ in 0..10000 { + rx.recv().unwrap(); + } + } + + #[test] + fn shared_chan_stress() { + let (tx, rx) = sync_channel(0); + let total = stress_factor() + 100; + let mut ts = Vec::with_capacity(total); + for _ in 0..total { + let tx = tx.clone(); + let t = thread::spawn(move || { + tx.send(()).unwrap(); + }); + ts.push(t); + } + + for _ in 0..total { + rx.recv().unwrap(); + } + for t in ts { + t.join().unwrap(); + } + } + + #[test] + fn test_nested_recv_iter() { + let (tx, rx) = sync_channel::(0); + let (total_tx, total_rx) = sync_channel::(0); + + let t = thread::spawn(move || { + let mut acc = 0; + for x in rx.iter() { + acc += x; + } + total_tx.send(acc).unwrap(); + }); + + tx.send(3).unwrap(); + tx.send(1).unwrap(); + tx.send(2).unwrap(); + drop(tx); + assert_eq!(total_rx.recv().unwrap(), 6); + t.join().unwrap(); + } + + #[test] + fn test_recv_iter_break() { + let (tx, rx) = sync_channel::(0); + let (count_tx, count_rx) = sync_channel(0); + + let t = thread::spawn(move || { + let mut count = 0; + for x in rx.iter() { + if count >= 3 { + break; + } else { + count += x; + } + } + count_tx.send(count).unwrap(); + }); + + tx.send(2).unwrap(); + tx.send(2).unwrap(); + tx.send(2).unwrap(); + let _ = tx.try_send(2); + drop(tx); + assert_eq!(count_rx.recv().unwrap(), 4); + t.join().unwrap(); + } + + #[test] + fn try_recv_states() { + let (tx1, rx1) = sync_channel::(1); + let (tx2, rx2) = sync_channel::<()>(1); + let (tx3, rx3) = sync_channel::<()>(1); + let t = thread::spawn(move || { + rx2.recv().unwrap(); + tx1.send(1).unwrap(); + tx3.send(()).unwrap(); + rx2.recv().unwrap(); + drop(tx1); + tx3.send(()).unwrap(); + }); + + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Ok(1)); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + assert_eq!(rx1.try_recv(), Err(TryRecvError::Disconnected)); + t.join().unwrap(); + } + + // This bug used to end up in a livelock inside of the Receiver destructor + // because the internal state of the Shared packet was corrupted + #[test] + fn destroy_upgraded_shared_port_when_sender_still_active() { + let (tx, rx) = sync_channel::<()>(0); + let (tx2, rx2) = sync_channel::<()>(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); // wait on a oneshot + drop(rx); // destroy a shared + tx2.send(()).unwrap(); + }); + // make sure the other thread has gone to sleep + for _ in 0..5000 { + thread::yield_now(); + } + + // upgrade to a shared chan and send a message + let tx2 = tx.clone(); + drop(tx); + tx2.send(()).unwrap(); + + // wait for the child thread to exit before we exit + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn send1() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + rx.recv().unwrap(); + }); + assert_eq!(tx.send(1), Ok(())); + t.join().unwrap(); + } + + #[test] + fn send2() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); + t.join().unwrap(); + } + + #[test] + fn send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.send(1), Ok(())); + let t = thread::spawn(move || { + drop(rx); + }); + assert!(tx.send(1).is_err()); + t.join().unwrap(); + } + + #[test] + fn send4() { + let (tx, rx) = sync_channel::(0); + let tx2 = tx.clone(); + let (done, donerx) = channel(); + let done2 = done.clone(); + let t = thread::spawn(move || { + assert!(tx.send(1).is_err()); + done.send(()).unwrap(); + }); + let t2 = thread::spawn(move || { + assert!(tx2.send(2).is_err()); + done2.send(()).unwrap(); + }); + drop(rx); + donerx.recv().unwrap(); + donerx.recv().unwrap(); + t.join().unwrap(); + t2.join().unwrap(); + } + + #[test] + fn try_send1() { + let (tx, _rx) = sync_channel::(0); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } + + #[test] + fn try_send2() { + let (tx, _rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + assert_eq!(tx.try_send(1), Err(TrySendError::Full(1))); + } + + #[test] + fn try_send3() { + let (tx, rx) = sync_channel::(1); + assert_eq!(tx.try_send(1), Ok(())); + drop(rx); + assert_eq!(tx.try_send(1), Err(TrySendError::Disconnected(1))); + } + + #[test] + fn issue_15761() { + fn repro() { + let (tx1, rx1) = sync_channel::<()>(3); + let (tx2, rx2) = sync_channel::<()>(3); + + let _t = thread::spawn(move || { + rx1.recv().unwrap(); + tx2.try_send(()).unwrap(); + }); + + tx1.try_send(()).unwrap(); + rx2.recv().unwrap(); + } + + for _ in 0..100 { + repro() + } + } +} + +// Source: https://github.com/rust-lang/rust/blob/master/src/libstd/sync/mpsc/select.rs +mod select_tests { + use super::*; + + use std::thread; + + #[test] + fn smoke() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + tx1.send(1).unwrap(); + select! { + foo = rx1.recv() => { assert_eq!(foo.unwrap(), 1); }, + _bar = rx2.recv() => { panic!() } + } + tx2.send(2).unwrap(); + select! { + _foo = rx1.recv() => { panic!() }, + bar = rx2.recv() => { assert_eq!(bar.unwrap(), 2) } + } + drop(tx1); + select! { + foo = rx1.recv() => { assert!(foo.is_err()); }, + _bar = rx2.recv() => { panic!() } + } + drop(tx2); + select! { + bar = rx2.recv() => { assert!(bar.is_err()); } + } + } + + #[test] + fn smoke2() { + let (_tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (_tx3, rx3) = channel::(); + let (_tx4, rx4) = channel::(); + let (tx5, rx5) = channel::(); + tx5.send(4).unwrap(); + select! { + _foo = rx1.recv() => { panic!("1") }, + _foo = rx2.recv() => { panic!("2") }, + _foo = rx3.recv() => { panic!("3") }, + _foo = rx4.recv() => { panic!("4") }, + foo = rx5.recv() => { assert_eq!(foo.unwrap(), 4); } + } + } + + #[test] + fn closed() { + let (_tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + drop(tx2); + + select! { + _a1 = rx1.recv() => { panic!() }, + a2 = rx2.recv() => { assert!(a2.is_err()); } + } + } + + #[test] + fn unblocks() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::(); + + let t = thread::spawn(move || { + for _ in 0..20 { + thread::yield_now(); + } + tx1.send(1).unwrap(); + rx3.recv().unwrap(); + for _ in 0..20 { + thread::yield_now(); + } + }); + + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + _b = rx2.recv() => { panic!() } + } + tx3.send(1).unwrap(); + select! { + a = rx1.recv() => { assert!(a.is_err()) }, + _b = rx2.recv() => { panic!() } + } + t.join().unwrap(); + } + + #[test] + fn both_ready() { + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + for _ in 0..20 { + thread::yield_now(); + } + tx1.send(1).unwrap(); + tx2.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } + } + select! { + a = rx1.recv() => { assert_eq!(a.unwrap(), 1); }, + a = rx2.recv() => { assert_eq!(a.unwrap(), 2); } + } + assert_eq!(rx1.try_recv(), Err(TryRecvError::Empty)); + assert_eq!(rx2.try_recv(), Err(TryRecvError::Empty)); + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[test] + fn stress() { + const AMT: i32 = 10000; + let (tx1, rx1) = channel::(); + let (tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + for i in 0..AMT { + if i % 2 == 0 { + tx1.send(i).unwrap(); + } else { + tx2.send(i).unwrap(); + } + rx3.recv().unwrap(); + } + }); + + for i in 0..AMT { + select! { + i1 = rx1.recv() => { assert!(i % 2 == 0 && i == i1.unwrap()); }, + i2 = rx2.recv() => { assert!(i % 2 == 1 && i == i2.unwrap()); } + } + tx3.send(()).unwrap(); + } + t.join().unwrap(); + } + + #[allow(unused_must_use)] + #[test] + fn cloning() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + rx3.recv().unwrap(); + tx1.clone(); + assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); + tx1.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + tx3.send(()).unwrap(); + select! { + _i1 = rx1.recv() => {}, + _i2 = rx2.recv() => panic!() + } + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[allow(unused_must_use)] + #[test] + fn cloning2() { + let (tx1, rx1) = channel::(); + let (_tx2, rx2) = channel::(); + let (tx3, rx3) = channel::<()>(); + + let t = thread::spawn(move || { + rx3.recv().unwrap(); + tx1.clone(); + assert_eq!(rx3.try_recv(), Err(TryRecvError::Empty)); + tx1.send(2).unwrap(); + rx3.recv().unwrap(); + }); + + tx3.send(()).unwrap(); + select! { + _i1 = rx1.recv() => {}, + _i2 = rx2.recv() => panic!() + } + tx3.send(()).unwrap(); + t.join().unwrap(); + } + + #[test] + fn cloning3() { + let (tx1, rx1) = channel::<()>(); + let (tx2, rx2) = channel::<()>(); + let (tx3, rx3) = channel::<()>(); + let t = thread::spawn(move || { + select! { + _ = rx1.recv() => panic!(), + _ = rx2.recv() => {} + } + tx3.send(()).unwrap(); + }); + + for _ in 0..1000 { + thread::yield_now(); + } + drop(tx1.clone()); + tx2.send(()).unwrap(); + rx3.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn preflight1() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight2() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight3() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + select! { + _n = rx.recv() => {} + } + } + + #[test] + fn preflight4() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight5() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight6() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight7() { + let (tx, rx) = channel::<()>(); + drop(tx); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight8() { + let (tx, rx) = channel(); + tx.send(()).unwrap(); + drop(tx); + rx.recv().unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn preflight9() { + let (tx, rx) = channel(); + drop(tx.clone()); + tx.send(()).unwrap(); + drop(tx); + rx.recv().unwrap(); + select! { + _ = rx.recv() => {} + } + } + + #[test] + fn oneshot_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn stream_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + tx1.send(()).unwrap(); + tx1.send(()).unwrap(); + rx1.recv().unwrap(); + rx1.recv().unwrap(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn shared_data_waiting() { + let (tx1, rx1) = channel(); + let (tx2, rx2) = channel(); + drop(tx1.clone()); + tx1.send(()).unwrap(); + rx1.recv().unwrap(); + let t = thread::spawn(move || { + select! { + _n = rx1.recv() => {} + } + tx2.send(()).unwrap(); + }); + + for _ in 0..100 { + thread::yield_now() + } + tx1.send(()).unwrap(); + rx2.recv().unwrap(); + t.join().unwrap(); + } + + #[test] + fn sync1() { + let (tx, rx) = sync_channel::(1); + tx.send(1).unwrap(); + select! { + n = rx.recv() => { assert_eq!(n.unwrap(), 1); } + } + } + + #[test] + fn sync2() { + let (tx, rx) = sync_channel::(0); + let t = thread::spawn(move || { + for _ in 0..100 { + thread::yield_now() + } + tx.send(1).unwrap(); + }); + select! { + n = rx.recv() => { assert_eq!(n.unwrap(), 1); } + } + t.join().unwrap(); + } + + #[test] + fn sync3() { + let (tx1, rx1) = sync_channel::(0); + let (tx2, rx2): (Sender, Receiver) = channel(); + let t = thread::spawn(move || { + tx1.send(1).unwrap(); + }); + let t2 = thread::spawn(move || { + tx2.send(2).unwrap(); + }); + select! { + n = rx1.recv() => { + let n = n.unwrap(); + assert_eq!(n, 1); + assert_eq!(rx2.recv().unwrap(), 2); + }, + n = rx2.recv() => { + let n = n.unwrap(); + assert_eq!(n, 2); + assert_eq!(rx1.recv().unwrap(), 1); + } + } + t.join().unwrap(); + t2.join().unwrap(); + } +} diff --git a/vendor/crossbeam-channel/tests/never.rs b/vendor/crossbeam-channel/tests/never.rs new file mode 100644 index 0000000000..35b6f74dda --- /dev/null +++ b/vendor/crossbeam-channel/tests/never.rs @@ -0,0 +1,99 @@ +//! Tests for the never channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate rand; + +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{never, tick, unbounded}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + select! { + recv(never::()) -> _ => panic!(), + default => {} + } +} + +#[test] +fn optional() { + let (s, r) = unbounded::(); + s.send(1).unwrap(); + s.send(2).unwrap(); + + let mut r = Some(&r); + select! { + recv(r.unwrap_or(&never())) -> _ => {} + default => panic!(), + } + + r = None; + select! { + recv(r.unwrap_or(&never())) -> _ => panic!(), + default => {} + } +} + +#[test] +fn tick_n() { + let mut r = tick(ms(100)); + let mut step = 0; + + loop { + select! { + recv(r) -> _ => step += 1, + default(ms(500)) => break, + } + + if step == 10 { + r = never(); + } + } + + assert_eq!(step, 10); +} + +#[test] +fn capacity() { + let r = never::(); + assert_eq!(r.capacity(), Some(0)); +} + +#[test] +fn len_empty_full() { + let r = never::(); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); +} + +#[test] +fn try_recv() { + let r = never::(); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = never::(); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(200)); + assert!(now - start <= ms(250)); +} diff --git a/vendor/crossbeam-channel/tests/ready.rs b/vendor/crossbeam-channel/tests/ready.rs new file mode 100644 index 0000000000..23769b7bd7 --- /dev/null +++ b/vendor/crossbeam-channel/tests/ready.rs @@ -0,0 +1,837 @@ +//! Tests for channel readiness using the `Select` struct. + +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::any::Any; +use std::cell::Cell; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, tick, unbounded}; +use crossbeam_channel::{Receiver, Select, TryRecvError, TrySendError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert_eq!(sel.ready(), 0); + assert_eq!(r1.try_recv(), Ok(1)); + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert_eq!(sel.ready(), 1); + assert_eq!(r2.try_recv(), Ok(2)); +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&r3); + sel.recv(&r4); + sel.recv(&r5); + assert_eq!(sel.ready(), 4); + assert_eq!(r5.try_recv(), Ok(5)); +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + r2.recv().unwrap(); + }) + .unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r1.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + let mut sel = Select::new(); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r2.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert!(sel.try_ready().is_err()); + + drop(s1); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.try_ready() { + Ok(0) => assert!(r1.try_recv().is_err()), + _ => panic!(), + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r2); + match sel.try_ready() { + Ok(0) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + + let mut sel = Select::new(); + sel.recv(&r2); + assert!(sel.try_ready().is_err()); + + let mut sel = Select::new(); + assert!(sel.try_ready().is_err()); +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + assert!(sel.ready_timeout(ms(1000)).is_err()); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + let mut sel = Select::new(); + assert!(sel.ready_timeout(ms(1000)).is_err()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.try_ready() { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.try_ready() { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + sel.send(&s); + match sel.try_ready() { + Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), + _ => panic!(), + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready_timeout(ms(1000)) { + Ok(0) => assert_eq!(s.try_send(0), Err(TrySendError::Disconnected(0))), + _ => panic!(), + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + + let mut sel = Select::new(); + assert!(sel.try_ready().is_err()); + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + let mut sel = Select::new(); + assert!(sel.ready_timeout(ms(500)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready_timeout(ms(1000)) { + Ok(1) => assert_eq!(r2.try_recv(), Ok(2)), + _ => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => oper.send(&s1, 1).unwrap(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.send(&s2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(1)), + 1 => s2.try_send(2).unwrap(), + _ => panic!(), + } + } + }) + .unwrap(); +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert!(r3.try_recv().is_err()); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => drop(r1.try_recv()), + 1 => drop(r2.try_recv()), + _ => panic!(), + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => panic!(), + 1 => drop(r2.try_recv()), + _ => panic!(), + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => drop(r.try_recv()), + _ => panic!(), + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => assert_eq!(r.try_recv(), Ok(())), + _ => panic!(), + } + + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)), + _ => panic!(), + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let hit = vec![Cell::new(false); 4]; + + while hit.iter().map(|h| h.get()).any(|hit| !hit) { + let mut sel = Select::new(); + sel.recv(&r); + sel.recv(&r); + sel.send(&s); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(r.try_recv().is_ok()); + hit[0].set(true); + } + 1 => { + assert!(r.try_recv().is_ok()); + hit[1].set(true); + } + 2 => { + assert!(s.try_send(0).is_ok()); + hit[2].set(true); + } + 3 => { + assert!(s.try_send(0).is_ok()); + hit[3].set(true); + } + _ => panic!(), + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(s.try_send(0).is_ok()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => { + assert_eq!(r.try_recv(), Ok(0)); + + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => { + assert!(s.try_send(1).is_ok()); + + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => { + assert_eq!(r.try_recv(), Ok(1)); + } + _ => panic!(), + } + } + _ => panic!(), + } + } + _ => panic!(), + } + } + _ => panic!(), + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(i)), + 1 => assert_eq!(r2.try_recv(), Ok(i)), + _ => panic!(), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.send(&s1); + sel.send(&s2); + match sel.ready() { + 0 => assert!(s1.try_send(i).is_ok()), + 1 => assert!(s2.try_send(i).is_ok()), + _ => panic!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + sel.recv(&r1); + sel.send(&s2); + match sel.ready() { + 0 => assert_eq!(r1.try_recv(), Ok(i)), + 1 => assert!(s2.try_send(i).is_ok()), + _ => panic!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let done = false; + while !done { + let mut sel = Select::new(); + sel.send(&s); + match sel.ready_timeout(ms(100)) { + Err(_) => {} + Ok(0) => { + assert!(s.try_send(i).is_ok()); + break; + } + Ok(_) => panic!(), + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let mut done = false; + while !done { + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready_timeout(ms(100)) { + Err(_) => {} + Ok(0) => { + assert_eq!(r.try_recv(), Ok(i)); + done = true; + } + Ok(_) => panic!(), + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + let mut sel = Select::new(); + sel.send(&s); + sel.recv(&r); + assert!(sel.ready_timeout(ms(100)).is_err()); + + let (s, r) = unbounded::(); + let mut sel = Select::new(); + sel.send(&s); + sel.recv(&r); + match sel.ready_timeout(ms(100)) { + Err(_) => panic!(), + Ok(0) => assert!(s.try_send(0).is_ok()), + Ok(_) => panic!(), + } +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 1..4 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + { + let mut sel = Select::new(); + sel.send(&s); + match sel.ready() { + 0 => assert!(s.try_send(new_r).is_ok()), + _ => panic!(), + } + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + let new = { + let mut sel = Select::new(); + sel.recv(&r); + match sel.ready() { + 0 => r + .try_recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap(), + _ => panic!(), + } + }; + r = new; + } + }); + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let hits = vec![Cell::new(0usize); 4]; + for _ in 0..COUNT { + let after = after(ms(0)); + let tick = tick(ms(0)); + + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&after); + sel.recv(&tick); + match sel.ready() { + 0 => { + r1.try_recv().unwrap(); + hits[0].set(hits[0].get() + 1); + } + 1 => { + r2.try_recv().unwrap(); + hits[1].set(hits[1].get() + 1); + } + 2 => { + after.try_recv().unwrap(); + hits[2].set(hits[2].get() + 1); + } + 3 => { + tick.try_recv().unwrap(); + hits[3].set(hits[3].get() + 1); + } + _ => panic!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + let mut sel = Select::new(); + let mut oper1 = None; + let mut oper2 = None; + if s1.is_empty() { + oper1 = Some(sel.send(&s1)); + } + if s2.is_empty() { + oper2 = Some(sel.send(&s2)); + } + let oper3 = sel.send(&s3); + let oper = sel.select(); + match oper.index() { + i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), + i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), + i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), + _ => unreachable!(), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&r3); + loop { + match sel.ready() { + 0 => { + if r1.try_recv().is_ok() { + hits[0].set(hits[0].get() + 1); + break; + } + } + 1 => { + if r2.try_recv().is_ok() { + hits[1].set(hits[1].get() + 1); + break; + } + } + 2 => { + if r3.try_recv().is_ok() { + hits[2].set(hits[2].get() + 1); + break; + } + } + _ => unreachable!(), + } + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 10)); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/same_channel.rs b/vendor/crossbeam-channel/tests/same_channel.rs new file mode 100644 index 0000000000..8e34faf448 --- /dev/null +++ b/vendor/crossbeam-channel/tests/same_channel.rs @@ -0,0 +1,114 @@ +extern crate crossbeam_channel; + +use std::time::Duration; + +use crossbeam_channel::{after, bounded, never, tick, unbounded}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn after_same_channel() { + let r = after(ms(50)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let r3 = after(ms(50)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); + + let r4 = after(ms(100)); + assert!(!r.same_channel(&r4)); + assert!(!r2.same_channel(&r4)); +} + +#[test] +fn array_same_channel() { + let (s, r) = bounded::(1); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = bounded::(1); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn list_same_channel() { + let (s, r) = unbounded::(); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = unbounded::(); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn never_same_channel() { + let r = never::(); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + // Never channel are always equal to one another. + let r3 = never::(); + assert!(r.same_channel(&r3)); + assert!(r2.same_channel(&r3)); +} + +#[test] +fn tick_same_channel() { + let r = tick(ms(50)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let r3 = tick(ms(50)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); + + let r4 = tick(ms(100)); + assert!(!r.same_channel(&r4)); + assert!(!r2.same_channel(&r4)); +} + +#[test] +fn zero_same_channel() { + let (s, r) = bounded::(0); + + let s2 = s.clone(); + assert!(s.same_channel(&s2)); + + let r2 = r.clone(); + assert!(r.same_channel(&r2)); + + let (s3, r3) = bounded::(0); + assert!(!s.same_channel(&s3)); + assert!(!s2.same_channel(&s3)); + assert!(!r.same_channel(&r3)); + assert!(!r2.same_channel(&r3)); +} + +#[test] +fn different_flavors_same_channel() { + let (s1, r1) = bounded::(0); + let (s2, r2) = unbounded::(); + + assert!(!s1.same_channel(&s2)); + assert!(!r1.same_channel(&r2)); +} diff --git a/vendor/crossbeam-channel/tests/select.rs b/vendor/crossbeam-channel/tests/select.rs new file mode 100644 index 0000000000..b18d66d7cd --- /dev/null +++ b/vendor/crossbeam-channel/tests/select.rs @@ -0,0 +1,1304 @@ +//! Tests for channel selection using the `Select` struct. + +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::any::Any; +use std::cell::Cell; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, tick, unbounded, Receiver, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => panic!(), + _ => unreachable!(), + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + } +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&r3); + let oper4 = sel.recv(&r4); + let oper5 = sel.recv(&r5); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => panic!(), + i if i == oper3 => panic!(), + i if i == oper4 => panic!(), + i if i == oper5 => assert_eq!(oper.recv(&r5), Ok(5)), + _ => unreachable!(), + } +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + r2.recv().unwrap(); + }) + .unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r2).is_err()), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + let mut sel = Select::new(); + let _oper1 = sel.recv(&r1); + let _oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } + + drop(s1); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r1).is_err()), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + s2.send(2).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + + let mut sel = Select::new(); + let _oper1 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } + + let mut sel = Select::new(); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(_) => panic!(), + } +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + let mut sel = Select::new(); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + } + Ok(_) => unreachable!(), + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + + let (_, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + }, + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.try_select(); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.send(&s, 0).is_err()), + _ => unreachable!(), + }, + } + + let (s, _) = bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => assert!(oper.send(&s, 0).is_err()), + _ => unreachable!(), + }, + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + + let mut sel = Select::new(); + let oper = sel.try_select(); + assert!(oper.is_err()); + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + let mut sel = Select::new(); + let oper = sel.select_timeout(ms(500)); + assert!(oper.is_err()); + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => assert_eq!(oper.recv(&r2), Ok(2)), + _ => unreachable!(), + }, + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + i if i == oper1 => oper.send(&s1, 1).unwrap(), + i if i == oper2 => panic!(), + _ => unreachable!(), + }, + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => oper.send(&s2, 2).unwrap(), + _ => unreachable!(), + } + } + }) + .unwrap(); +} + +#[test] +fn loop_try() { + const RUNS: usize = 20; + + for _ in 0..RUNS { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + let (s_end, r_end) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| loop { + let mut done = false; + + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.send(&s1, 1); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + + let mut sel = Select::new(); + let oper1 = sel.recv(&r_end); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.recv(&r_end); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + }); + + scope.spawn(|_| loop { + if let Ok(x) = r2.try_recv() { + assert_eq!(x, 2); + break; + } + + let mut done = false; + let mut sel = Select::new(); + let oper1 = sel.recv(&r_end); + let oper = sel.try_select(); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => { + let _ = oper.recv(&r_end); + done = true; + } + _ => unreachable!(), + }, + } + if done { + break; + } + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select_timeout(ms(1000)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r1), Ok(1)), + i if i == oper2 => assert!(oper.send(&s2, 2).is_ok()), + _ => unreachable!(), + }, + } + + drop(s_end); + }); + }) + .unwrap(); + } +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert!(r3.try_recv().is_err()); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => drop(oper.recv(&r1)), + i if i == oper2 => drop(oper.recv(&r2)), + _ => unreachable!(), + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => panic!(), + i if i == oper2 => drop(oper.recv(&r2)), + _ => unreachable!(), + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => drop(oper.recv(&r)), + _ => unreachable!(), + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert_eq!(oper.recv(&r), Ok(())), + _ => unreachable!(), + } + + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => assert!(oper.recv(&r).is_err()), + _ => unreachable!(), + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let hit = vec![Cell::new(false); 4]; + + while hit.iter().map(|h| h.get()).any(|hit| !hit) { + let mut sel = Select::new(); + let oper0 = sel.recv(&r); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper3 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper0 => { + assert!(oper.recv(&r).is_ok()); + hit[0].set(true); + } + i if i == oper1 => { + assert!(oper.recv(&r).is_ok()); + hit[1].set(true); + } + i if i == oper2 => { + assert!(oper.send(&s, 0).is_ok()); + hit[2].set(true); + } + i if i == oper3 => { + assert!(oper.send(&s, 0).is_ok()); + hit[3].set(true); + } + _ => unreachable!(), + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert!(oper.send(&s, 0).is_ok()); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert_eq!(oper.recv(&r), Ok(0)); + + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert!(oper.send(&s, 1).is_ok()); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + assert_eq!(oper.recv(&r), Ok(1)); + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } + } + _ => unreachable!(), + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert_eq!(oper.recv(&r2), Ok(i)), + _ => unreachable!(), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.send(&s1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s1, i).is_ok()), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let done = false; + while !done { + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => { + assert!(oper.send(&s, i).is_ok()); + break; + } + _ => unreachable!(), + }, + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + let mut done = false; + while !done { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => { + assert_eq!(oper.recv(&r), Ok(i)); + done = true; + } + _ => unreachable!(), + }, + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper2 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => {} + Ok(oper) => match oper.index() { + ix if ix == oper1 => panic!(), + ix if ix == oper2 => panic!(), + _ => unreachable!(), + }, + } + + let (s, r) = unbounded::(); + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper2 = sel.recv(&r); + let oper = sel.select_timeout(ms(100)); + match oper { + Err(_) => panic!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s, 0).is_ok()), + ix if ix == oper2 => panic!(), + _ => unreachable!(), + }, + } +} + +#[test] +fn matching() { + const THREADS: usize = 44; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn matching_with_leftover() { + const THREADS: usize = 55; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + s.send(!0).unwrap(); + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 0..3 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + { + let mut sel = Select::new(); + let oper1 = sel.send(&s); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert!(oper.send(&s, new_r).is_ok()), + _ => unreachable!(), + } + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + let new = { + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => oper + .recv(&r) + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap(), + _ => unreachable!(), + } + }; + r = new; + } + }); + }) + .unwrap(); + } +} + +#[test] +fn linearizable_try() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.try_select(); + match oper { + Err(_) => unreachable!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), + ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), + _ => unreachable!(), + }, + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn linearizable_timeout() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper = sel.select_timeout(ms(0)); + match oper { + Err(_) => unreachable!(), + Ok(oper) => match oper.index() { + ix if ix == oper1 => assert!(oper.recv(&r1).is_ok()), + ix if ix == oper2 => assert!(oper.recv(&r2).is_ok()), + _ => unreachable!(), + }, + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let hits = vec![Cell::new(0usize); 4]; + for _ in 0..COUNT { + let after = after(ms(0)); + let tick = tick(ms(0)); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&after); + let oper4 = sel.recv(&tick); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits[0].set(hits[0].get() + 1); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits[1].set(hits[1].get() + 1); + } + i if i == oper3 => { + oper.recv(&after).unwrap(); + hits[2].set(hits[2].get() + 1); + } + i if i == oper4 => { + oper.recv(&tick).unwrap(); + hits[3].set(hits[3].get() + 1); + } + _ => unreachable!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + let mut sel = Select::new(); + let mut oper1 = None; + let mut oper2 = None; + if s1.is_empty() { + oper1 = Some(sel.send(&s1)); + } + if s2.is_empty() { + oper2 = Some(sel.send(&s2)); + } + let oper3 = sel.send(&s3); + let oper = sel.select(); + match oper.index() { + i if Some(i) == oper1 => assert!(oper.send(&s1, ()).is_ok()), + i if Some(i) == oper2 => assert!(oper.send(&s2, ()).is_ok()), + i if i == oper3 => assert!(oper.send(&s3, ()).is_ok()), + _ => unreachable!(), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&r3); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits[0].set(hits[0].get() + 1); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits[1].set(hits[1].get() + 1); + } + i if i == oper3 => { + oper.recv(&r3).unwrap(); + hits[2].set(hits[2].get() + 1); + } + _ => unreachable!(), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); + }) + .unwrap(); +} + +#[test] +fn sync_and_clone() { + const THREADS: usize = 20; + + let (s, r) = &bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + let sel = &sel; + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + let mut sel = sel.clone(); + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn send_and_clone() { + const THREADS: usize = 20; + + let (s, r) = &bounded::(0); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r); + let oper2 = sel.send(&s); + + scope(|scope| { + for i in 0..THREADS { + let mut sel = sel.clone(); + scope.spawn(move |_| { + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_ne!(oper.recv(&r), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s, i).is_ok()), + _ => unreachable!(), + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn reuse() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.send(&s2); + + for i in 0..COUNT { + for _ in 0..2 { + let oper = sel.select(); + match oper.index() { + ix if ix == oper1 => assert_eq!(oper.recv(&r1), Ok(i)), + ix if ix == oper2 => assert!(oper.send(&s2, i).is_ok()), + _ => unreachable!(), + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/select_macro.rs b/vendor/crossbeam-channel/tests/select_macro.rs new file mode 100644 index 0000000000..a9cc7fac79 --- /dev/null +++ b/vendor/crossbeam-channel/tests/select_macro.rs @@ -0,0 +1,1440 @@ +//! Tests for the `select!` macro. + +#![deny(unsafe_code)] + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::any::Any; +use std::cell::Cell; +use std::ops::Deref; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, bounded, never, tick, unbounded}; +use crossbeam_channel::{Receiver, RecvError, SendError, Sender, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke1() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + s1.send(1).unwrap(); + + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + recv(r2) -> _ => panic!(), + } + + s2.send(2).unwrap(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + } +} + +#[test] +fn smoke2() { + let (_s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (_s3, r3) = unbounded::(); + let (_s4, r4) = unbounded::(); + let (s5, r5) = unbounded::(); + + s5.send(5).unwrap(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + recv(r3) -> _ => panic!(), + recv(r4) -> _ => panic!(), + recv(r5) -> v => assert_eq!(v, Ok(5)), + } +} + +#[test] +fn disconnected() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + drop(s1); + thread::sleep(ms(500)); + s2.send(5).unwrap(); + }); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + + r2.recv().unwrap(); + }) + .unwrap(); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + drop(s2); + }); + + select! { + recv(r2) -> v => assert!(v.is_err()), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn default() { + let (s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + default => {} + } + + drop(s1); + + select! { + recv(r1) -> v => assert!(v.is_err()), + recv(r2) -> _ => panic!(), + default => panic!(), + } + + s2.send(2).unwrap(); + + select! { + recv(r2) -> v => assert_eq!(v, Ok(2)), + default => panic!(), + } + + select! { + recv(r2) -> _ => panic!(), + default => {}, + } + + select! { + default => {}, + } +} + +#[test] +fn timeout() { + let (_s1, r1) = unbounded::(); + let (s2, r2) = unbounded::(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(1500)); + s2.send(2).unwrap(); + }); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => panic!(), + default(ms(1000)) => {}, + } + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + let (s, r) = unbounded::(); + + scope.spawn(move |_| { + thread::sleep(ms(500)); + drop(s); + }); + + select! { + default(ms(1000)) => { + select! { + recv(r) -> v => assert!(v.is_err()), + default => panic!(), + } + } + } + }) + .unwrap(); +} + +#[test] +fn default_when_disconnected() { + let (_, r) = unbounded::(); + + select! { + recv(r) -> res => assert!(res.is_err()), + default => panic!(), + } + + let (_, r) = unbounded::(); + + select! { + recv(r) -> res => assert!(res.is_err()), + default(ms(1000)) => panic!(), + } + + let (s, _) = bounded::(0); + + select! { + send(s, 0) -> res => assert!(res.is_err()), + default => panic!(), + } + + let (s, _) = bounded::(0); + + select! { + send(s, 0) -> res => assert!(res.is_err()), + default(ms(1000)) => panic!(), + } +} + +#[test] +fn default_only() { + let start = Instant::now(); + select! { + default => {} + } + let now = Instant::now(); + assert!(now - start <= ms(50)); + + let start = Instant::now(); + select! { + default(ms(500)) => {} + } + let now = Instant::now(); + assert!(now - start >= ms(450)); + assert!(now - start <= ms(550)); +} + +#[test] +fn unblocks() { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s2.send(2).unwrap(); + }); + + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> v => assert_eq!(v, Ok(2)), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + assert_eq!(r1.recv().unwrap(), 1); + }); + + select! { + send(s1, 1) -> _ => {}, + send(s2, 2) -> _ => panic!(), + default(ms(1000)) => panic!(), + } + }) + .unwrap(); +} + +#[test] +fn both_ready() { + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(500)); + s1.send(1).unwrap(); + assert_eq!(r2.recv().unwrap(), 2); + }); + + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + send(s2, 2) -> _ => {}, + } + } + }) + .unwrap(); +} + +#[test] +fn loop_try() { + const RUNS: usize = 20; + + for _ in 0..RUNS { + let (s1, r1) = bounded::(0); + let (s2, r2) = bounded::(0); + let (s_end, r_end) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| loop { + select! { + send(s1, 1) -> _ => break, + default => {} + } + + select! { + recv(r_end) -> _ => break, + default => {} + } + }); + + scope.spawn(|_| loop { + if let Ok(x) = r2.try_recv() { + assert_eq!(x, 2); + break; + } + + select! { + recv(r_end) -> _ => break, + default => {} + } + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + + select! { + recv(r1) -> v => assert_eq!(v, Ok(1)), + send(s2, 2) -> _ => {}, + default(ms(500)) => panic!(), + } + + drop(s_end); + }); + }) + .unwrap(); + } +} + +#[test] +fn cloning1() { + scope(|scope| { + let (s1, r1) = unbounded::(); + let (_s2, r2) = unbounded::(); + let (s3, r3) = unbounded::<()>(); + + scope.spawn(move |_| { + r3.recv().unwrap(); + drop(s1.clone()); + assert_eq!(r3.try_recv(), Err(TryRecvError::Empty)); + s1.send(1).unwrap(); + r3.recv().unwrap(); + }); + + s3.send(()).unwrap(); + + select! { + recv(r1) -> _ => {}, + recv(r2) -> _ => {}, + } + + s3.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn cloning2() { + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = unbounded::<()>(); + let (_s3, _r3) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r1) -> _ => panic!(), + recv(r2) -> _ => {}, + } + }); + + thread::sleep(ms(500)); + drop(s1.clone()); + s2.send(()).unwrap(); + }) + .unwrap(); +} + +#[test] +fn preflight1() { + let (s, r) = unbounded(); + s.send(()).unwrap(); + + select! { + recv(r) -> _ => {} + } +} + +#[test] +fn preflight2() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + + select! { + recv(r) -> v => assert!(v.is_ok()), + } + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); +} + +#[test] +fn preflight3() { + let (s, r) = unbounded(); + drop(s.clone()); + s.send(()).unwrap(); + drop(s); + r.recv().unwrap(); + + select! { + recv(r) -> v => assert!(v.is_err()) + } +} + +#[test] +fn duplicate_operations() { + let (s, r) = unbounded::(); + let mut hit = [false; 4]; + + while hit.iter().any(|hit| !hit) { + select! { + recv(r) -> _ => hit[0] = true, + recv(r) -> _ => hit[1] = true, + send(s, 0) -> _ => hit[2] = true, + send(s, 0) -> _ => hit[3] = true, + } + } +} + +#[test] +fn nesting() { + let (s, r) = unbounded::(); + + select! { + send(s, 0) -> _ => { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(0)); + select! { + send(s, 1) -> _ => { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(1)); + } + } + } + } + } + } + } + } +} + +#[test] +#[should_panic(expected = "send panicked")] +fn panic_sender() { + fn get() -> Sender { + panic!("send panicked") + } + + #[allow(unreachable_code)] + { + select! { + send(get(), panic!()) -> _ => {} + } + } +} + +#[test] +#[should_panic(expected = "recv panicked")] +fn panic_receiver() { + fn get() -> Receiver { + panic!("recv panicked") + } + + select! { + recv(get()) -> _ => {} + } +} + +#[test] +fn stress_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded(); + let (s2, r2) = bounded(5); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + r3.recv().unwrap(); + + s2.send(i).unwrap(); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(i)), + recv(r2) -> v => assert_eq!(v, Ok(i)), + } + + s3.send(()).unwrap(); + } + } + }) + .unwrap(); +} + +#[test] +fn stress_send() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r1.recv().unwrap(), i); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + send(s1, i) -> _ => {}, + send(s2, i) -> _ => {}, + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_mixed() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded(0); + let (s2, r2) = bounded(0); + let (s3, r3) = bounded(100); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + s1.send(i).unwrap(); + assert_eq!(r2.recv().unwrap(), i); + r3.recv().unwrap(); + } + }); + + for i in 0..COUNT { + for _ in 0..2 { + select! { + recv(r1) -> v => assert_eq!(v, Ok(i)), + send(s2, i) -> _ => {}, + } + } + s3.send(()).unwrap(); + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 20; + + let (s, r) = bounded(2); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + loop { + select! { + send(s, i) -> _ => break, + default(ms(100)) => {} + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(500)); + } + + loop { + select! { + recv(r) -> v => { + assert_eq!(v, Ok(i)); + break; + } + default(ms(100)) => {} + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn send_recv_same_channel() { + let (s, r) = bounded::(0); + select! { + send(s, 0) -> _ => panic!(), + recv(r) -> _ => panic!(), + default(ms(500)) => {} + } + + let (s, r) = unbounded::(); + select! { + send(s, 0) -> _ => {}, + recv(r) -> _ => panic!(), + default(ms(500)) => panic!(), + } +} + +#[test] +fn matching() { + const THREADS: usize = 44; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_ne!(v.unwrap(), i), + send(s, i) -> _ => {}, + } + }); + } + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn matching_with_leftover() { + const THREADS: usize = 55; + + let (s, r) = &bounded::(0); + + scope(|scope| { + for i in 0..THREADS { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_ne!(v.unwrap(), i), + send(s, i) -> _ => {}, + } + }); + } + s.send(!0).unwrap(); + }) + .unwrap(); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + for cap in 0..3 { + let (s, r) = bounded::(cap); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(cap); + let new_r: T = Box::new(Some(new_r)); + + select! { + send(s, new_r) -> _ => {} + } + + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = select! { + recv(r) -> msg => { + msg.unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + } + } + }); + }) + .unwrap(); + } +} + +#[test] +fn linearizable_default() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + default => unreachable!() + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn linearizable_timeout() { + const COUNT: usize = 100_000; + + for step in 0..2 { + let (start_s, start_r) = bounded::<()>(0); + let (end_s, end_r) = bounded::<()>(0); + + let ((s1, r1), (s2, r2)) = if step == 0 { + (bounded::(1), bounded::(1)) + } else { + (unbounded::(), unbounded::()) + }; + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..COUNT { + start_s.send(()).unwrap(); + + s1.send(1).unwrap(); + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + default(ms(0)) => unreachable!() + } + + end_s.send(()).unwrap(); + let _ = r2.try_recv(); + } + }); + + for _ in 0..COUNT { + start_r.recv().unwrap(); + + s2.send(1).unwrap(); + let _ = r1.try_recv(); + + end_r.recv().unwrap(); + } + }) + .unwrap(); + } +} + +#[test] +fn fairness1() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 4]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + recv(after(ms(0))) -> _ => hits[2] += 1, + recv(tick(ms(0))) -> _ => hits[3] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); +} + +#[test] +fn fairness2() { + const COUNT: usize = 10_000; + + let (s1, r1) = unbounded::<()>(); + let (s2, r2) = bounded::<()>(1); + let (s3, r3) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let (hole, _r) = bounded(0); + + for _ in 0..COUNT { + let s1 = if s1.is_empty() { &s1 } else { &hole }; + let s2 = if s2.is_empty() { &s2 } else { &hole }; + + select! { + send(s1, ()) -> res => assert!(res.is_ok()), + send(s2, ()) -> res => assert!(res.is_ok()), + send(s3, ()) -> res => assert!(res.is_ok()), + } + } + }); + + let hits = vec![Cell::new(0usize); 3]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0].set(hits[0].get() + 1), + recv(r2) -> _ => hits[1].set(hits[1].get() + 1), + recv(r3) -> _ => hits[2].set(hits[2].get() + 1), + } + } + assert!(hits.iter().all(|x| x.get() >= COUNT / hits.len() / 50)); + }) + .unwrap(); +} + +#[test] +fn fairness_recv() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(COUNT); + let (s2, r2) = unbounded::<()>(); + + for _ in 0..COUNT { + s1.send(()).unwrap(); + s2.send(()).unwrap(); + } + + let mut hits = [0usize; 2]; + while hits[0] + hits[1] < COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / 4)); +} + +#[test] +fn fairness_send() { + const COUNT: usize = 10_000; + + let (s1, _r1) = bounded::<()>(COUNT); + let (s2, _r2) = unbounded::<()>(); + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + send(s1, ()) -> _ => hits[0] += 1, + send(s2, ()) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / 4)); +} + +#[test] +fn references() { + let (s, r) = unbounded::(); + select! { + send(s, 0) -> _ => {} + recv(r) -> _ => {} + } + select! { + send(&&&&s, 0) -> _ => {} + recv(&&&&r) -> _ => {} + } + select! { + recv(Some(&r).unwrap_or(&never())) -> _ => {}, + default => {} + } + select! { + recv(Some(r).unwrap_or(never())) -> _ => {}, + default => {} + } +} + +#[test] +fn case_blocks() { + let (s, r) = unbounded::(); + + select! { + recv(r) -> _ => 3.0, + recv(r) -> _ => loop { + unreachable!() + }, + recv(r) -> _ => match 7 + 3 { + _ => unreachable!() + }, + default => 7. + }; + + select! { + recv(r) -> msg => if msg.is_ok() { + unreachable!() + }, + default => () + } + + drop(s); +} + +#[test] +fn move_handles() { + let (s, r) = unbounded::(); + select! { + recv((move || r)()) -> _ => {} + send((move || s)(), 0) -> _ => {} + } +} + +#[test] +fn infer_types() { + let (s, r) = unbounded(); + select! { + recv(r) -> _ => {} + default => {} + } + s.send(()).unwrap(); + + let (s, r) = unbounded(); + select! { + send(s, ()) -> _ => {} + } + r.recv().unwrap(); +} + +#[test] +fn default_syntax() { + let (s, r) = bounded::(0); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + select! { + send(s, 0) -> _ => panic!(), + default() => {} + } + select! { + default => {} + } + select! { + default() => {} + } +} + +#[test] +fn same_variable_name() { + let (_, r) = unbounded::(); + select! { + recv(r) -> r => assert!(r.is_err()), + } +} + +#[test] +fn handles_on_heap() { + let (s, r) = unbounded::(); + let (s, r) = (Box::new(s), Box::new(r)); + + select! { + send(*s, 0) -> _ => {} + recv(*r) -> _ => {} + default => {} + } + + drop(s); + drop(r); +} + +#[test] +fn once_blocks() { + let (s, r) = unbounded::(); + + let once = Box::new(()); + select! { + send(s, 0) -> _ => drop(once), + } + + let once = Box::new(()); + select! { + recv(r) -> _ => drop(once), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + send(s, 0) -> _ => drop(once1), + default => drop(once2), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + recv(r) -> _ => drop(once1), + default => drop(once2), + } + + let once1 = Box::new(()); + let once2 = Box::new(()); + select! { + recv(r) -> _ => drop(once1), + send(s, 0) -> _ => drop(once2), + } +} + +#[test] +fn once_receiver() { + let (_, r) = unbounded::(); + + let once = Box::new(()); + let get = move || { + drop(once); + r + }; + + select! { + recv(get()) -> _ => {} + } +} + +#[test] +fn once_sender() { + let (s, _) = unbounded::(); + + let once = Box::new(()); + let get = move || { + drop(once); + s + }; + + select! { + send(get(), 5) -> _ => {} + } +} + +#[test] +fn parse_nesting() { + let (_, r) = unbounded::(); + + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + recv(r) -> _ => {} + recv(r) -> _ => { + select! { + default => {} + } + } + } + } + } + } + } +} + +#[test] +fn evaluate() { + let (s, r) = unbounded::(); + + let v = select! { + recv(r) -> _ => "foo".into(), + send(s, 0) -> _ => "bar".to_owned(), + default => "baz".to_string(), + }; + assert_eq!(v, "bar"); + + let v = select! { + recv(r) -> _ => "foo".into(), + default => "baz".to_string(), + }; + assert_eq!(v, "foo"); + + let v = select! { + recv(r) -> _ => "foo".into(), + default => "baz".to_string(), + }; + assert_eq!(v, "baz"); +} + +#[test] +fn deref() { + use crossbeam_channel as cc; + + struct Sender(cc::Sender); + struct Receiver(cc::Receiver); + + impl Deref for Receiver { + type Target = cc::Receiver; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + impl Deref for Sender { + type Target = cc::Sender; + + fn deref(&self) -> &Self::Target { + &self.0 + } + } + + let (s, r) = bounded::(0); + let (s, r) = (Sender(s), Receiver(r)); + + select! { + send(s, 0) -> _ => panic!(), + recv(r) -> _ => panic!(), + default => {} + } +} + +#[test] +fn result_types() { + let (s, _) = bounded::(0); + let (_, r) = bounded::(0); + + select! { + recv(r) -> res => drop::>(res), + } + select! { + recv(r) -> res => drop::>(res), + default => {} + } + select! { + recv(r) -> res => drop::>(res), + default(ms(0)) => {} + } + + select! { + send(s, 0) -> res => drop::>>(res), + } + select! { + send(s, 0) -> res => drop::>>(res), + default => {} + } + select! { + send(s, 0) -> res => drop::>>(res), + default(ms(0)) => {} + } + + select! { + send(s, 0) -> res => drop::>>(res), + recv(r) -> res => drop::>(res), + } +} + +#[test] +fn try_recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> _ => panic!(), + default => {} + } + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + default => panic!(), + } + thread::sleep(ms(500)); + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + default => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + select! { + send(s, 7) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + } + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(9)), + } + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + send(s, 7) -> res => res.unwrap(), + } + select! { + send(s, 8) -> res => res.unwrap(), + } + select! { + send(s, 9) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> _ => panic!(), + default(ms(1000)) => {} + } + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + default(ms(1000)) => panic!(), + } + select! { + recv(r) -> v => assert_eq!(v, Err(RecvError)), + default(ms(1000)) => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + send(s, 7) -> res => res.unwrap(), + } + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> _ => panic!(), + default => {} + } + thread::sleep(ms(1500)); + select! { + send(s, 8) -> res => res.unwrap(), + default => panic!(), + } + thread::sleep(ms(500)); + select! { + send(s, 8) -> res => assert_eq!(res, Err(SendError(8))), + default => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> res => res.unwrap(), + } + thread::sleep(ms(1000)); + select! { + send(s, 8) -> res => res.unwrap(), + } + thread::sleep(ms(1000)); + select! { + send(s, 9) -> res => res.unwrap(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(7)), + } + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + select! { + recv(r) -> v => assert_eq!(v, Ok(9)), + } + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, 7) -> _ => panic!(), + default(ms(1000)) => {} + } + select! { + send(s, 8) -> res => res.unwrap(), + default(ms(1000)) => panic!(), + } + select! { + send(s, 9) -> res => assert_eq!(res, Err(SendError(9))), + default(ms(1000)) => panic!(), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + select! { + recv(r) -> v => assert_eq!(v, Ok(8)), + } + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + send(s, ()) -> res => assert_eq!(res, Err(SendError(()))), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(move |_| { + select! { + recv(r) -> res => assert_eq!(res, Err(RecvError)), + } + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/thread_locals.rs b/vendor/crossbeam-channel/tests/thread_locals.rs new file mode 100644 index 0000000000..fd319c7284 --- /dev/null +++ b/vendor/crossbeam-channel/tests/thread_locals.rs @@ -0,0 +1,55 @@ +//! Tests that make sure accessing thread-locals while exiting the thread doesn't cause panics. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; + +use std::thread; +use std::time::Duration; + +use crossbeam_channel::unbounded; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +#[cfg_attr(target_os = "macos", ignore = "TLS is destroyed too early on macOS")] +fn use_while_exiting() { + struct Foo; + + impl Drop for Foo { + fn drop(&mut self) { + // A blocking operation after the thread-locals have been dropped. This will attempt to + // use the thread-locals and must not panic. + let (_s, r) = unbounded::<()>(); + select! { + recv(r) -> _ => {} + default(ms(100)) => {} + } + } + } + + thread_local! { + static FOO: Foo = Foo; + } + + let (s, r) = unbounded::<()>(); + + scope(|scope| { + scope.spawn(|_| { + // First initialize `FOO`, then the thread-locals related to crossbeam-channel. + FOO.with(|_| ()); + r.recv().unwrap(); + // At thread exit, thread-locals related to crossbeam-channel get dropped first and + // `FOO` is dropped last. + }); + + scope.spawn(|_| { + thread::sleep(ms(100)); + s.send(()).unwrap(); + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-channel/tests/tick.rs b/vendor/crossbeam-channel/tests/tick.rs new file mode 100644 index 0000000000..34e55b31bf --- /dev/null +++ b/vendor/crossbeam-channel/tests/tick.rs @@ -0,0 +1,353 @@ +//! Tests for the tick channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::{Duration, Instant}; + +use crossbeam_channel::{after, tick, Select, TryRecvError}; +use crossbeam_utils::thread::scope; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn fire() { + let start = Instant::now(); + let r = tick(ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(100)); + + let fired = r.try_recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired >= ms(50)); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + + select! { + recv(r) -> _ => panic!(), + default => {} + } + + select! { + recv(r) -> _ => {} + recv(tick(ms(200))) -> _ => panic!(), + } +} + +#[test] +fn intervals() { + let start = Instant::now(); + let r = tick(ms(50)); + + let t1 = r.recv().unwrap(); + assert!(start + ms(50) <= t1); + assert!(start + ms(100) > t1); + + thread::sleep(ms(300)); + let t2 = r.try_recv().unwrap(); + assert!(start + ms(100) <= t2); + assert!(start + ms(150) > t2); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + let t3 = r.recv().unwrap(); + assert!(start + ms(400) <= t3); + assert!(start + ms(450) > t3); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn capacity() { + const COUNT: usize = 10; + + for i in 0..COUNT { + let r = tick(ms(i as u64)); + assert_eq!(r.capacity(), Some(1)); + } +} + +#[test] +fn len_empty_full() { + let r = tick(ms(50)); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); + + thread::sleep(ms(100)); + + assert_eq!(r.len(), 1); + assert_eq!(r.is_empty(), false); + assert_eq!(r.is_full(), true); + + r.try_recv().unwrap(); + + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), false); +} + +#[test] +fn try_recv() { + let r = tick(ms(200)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(100)); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); + + thread::sleep(ms(200)); + assert!(r.try_recv().is_ok()); + assert!(r.try_recv().is_err()); +} + +#[test] +fn recv() { + let start = Instant::now(); + let r = tick(ms(50)); + + let fired = r.recv().unwrap(); + assert!(start < fired); + assert!(fired - start >= ms(50)); + + let now = Instant::now(); + assert!(fired < now); + assert!(now - fired < fired - start); + + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn recv_timeout() { + let start = Instant::now(); + let r = tick(ms(200)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(100)); + assert!(now - start <= ms(150)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(200)); + assert!(fired - start <= ms(250)); + + assert!(r.recv_timeout(ms(100)).is_err()); + let now = Instant::now(); + assert!(now - start >= ms(300)); + assert!(now - start <= ms(350)); + + let fired = r.recv_timeout(ms(200)).unwrap(); + assert!(fired - start >= ms(400)); + assert!(fired - start <= ms(450)); +} + +#[test] +fn recv_two() { + let r1 = tick(ms(50)); + let r2 = tick(ms(50)); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..10 { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + } + }); + scope.spawn(|_| { + for _ in 0..10 { + select! { + recv(r1) -> _ => {} + recv(r2) -> _ => {} + } + } + }); + }) + .unwrap(); +} + +#[test] +fn recv_race() { + select! { + recv(tick(ms(50))) -> _ => {} + recv(tick(ms(100))) -> _ => panic!(), + } + + select! { + recv(tick(ms(100))) -> _ => panic!(), + recv(tick(ms(50))) -> _ => {} + } +} + +#[test] +fn stress_default() { + const COUNT: usize = 10; + + for _ in 0..COUNT { + select! { + recv(tick(ms(0))) -> _ => {} + default => panic!(), + } + } + + for _ in 0..COUNT { + select! { + recv(tick(ms(100))) -> _ => panic!(), + default => {} + } + } +} + +#[test] +fn select() { + const THREADS: usize = 4; + + let hits = AtomicUsize::new(0); + let r1 = tick(ms(200)); + let r2 = tick(ms(300)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let timeout = after(ms(1100)); + loop { + let mut sel = Select::new(); + let oper1 = sel.recv(&r1); + let oper2 = sel.recv(&r2); + let oper3 = sel.recv(&timeout); + let oper = sel.select(); + match oper.index() { + i if i == oper1 => { + oper.recv(&r1).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + i if i == oper2 => { + oper.recv(&r2).unwrap(); + hits.fetch_add(1, Ordering::SeqCst); + } + i if i == oper3 => { + oper.recv(&timeout).unwrap(); + break; + } + _ => unreachable!(), + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), 8); +} + +#[test] +fn ready() { + const THREADS: usize = 4; + + let hits = AtomicUsize::new(0); + let r1 = tick(ms(200)); + let r2 = tick(ms(300)); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + let timeout = after(ms(1100)); + 'outer: loop { + let mut sel = Select::new(); + sel.recv(&r1); + sel.recv(&r2); + sel.recv(&timeout); + loop { + match sel.ready() { + 0 => { + if r1.try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + 1 => { + if r2.try_recv().is_ok() { + hits.fetch_add(1, Ordering::SeqCst); + break; + } + } + 2 => { + if timeout.try_recv().is_ok() { + break 'outer; + } + } + _ => unreachable!(), + } + } + } + }); + } + }) + .unwrap(); + + assert_eq!(hits.load(Ordering::SeqCst), 8); +} + +#[test] +fn fairness() { + const COUNT: usize = 30; + + for &dur in &[0, 1] { + let mut hits = [0usize; 2]; + + for _ in 0..COUNT { + let r1 = tick(ms(dur)); + let r2 = tick(ms(dur)); + + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 30; + + for &dur in &[0, 1] { + let mut hits = [0usize; 5]; + + for _ in 0..COUNT { + let r = tick(ms(dur)); + + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + } + + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + } +} diff --git a/vendor/crossbeam-channel/tests/zero.rs b/vendor/crossbeam-channel/tests/zero.rs new file mode 100644 index 0000000000..bd336ee157 --- /dev/null +++ b/vendor/crossbeam-channel/tests/zero.rs @@ -0,0 +1,559 @@ +//! Tests for the zero channel flavor. + +#[macro_use] +extern crate crossbeam_channel; +extern crate crossbeam_utils; +extern crate rand; + +use std::any::Any; +use std::sync::atomic::AtomicUsize; +use std::sync::atomic::Ordering; +use std::thread; +use std::time::Duration; + +use crossbeam_channel::{bounded, Receiver}; +use crossbeam_channel::{RecvError, RecvTimeoutError, TryRecvError}; +use crossbeam_channel::{SendError, SendTimeoutError, TrySendError}; +use crossbeam_utils::thread::scope; +use rand::{thread_rng, Rng}; + +fn ms(ms: u64) -> Duration { + Duration::from_millis(ms) +} + +#[test] +fn smoke() { + let (s, r) = bounded(0); + assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); +} + +#[test] +fn capacity() { + let (s, r) = bounded::<()>(0); + assert_eq!(s.capacity(), Some(0)); + assert_eq!(r.capacity(), Some(0)); +} + +#[test] +fn len_empty_full() { + let (s, r) = bounded(0); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); + + scope(|scope| { + scope.spawn(|_| s.send(0).unwrap()); + scope.spawn(|_| r.recv().unwrap()); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(s.is_empty(), true); + assert_eq!(s.is_full(), true); + assert_eq!(r.len(), 0); + assert_eq!(r.is_empty(), true); + assert_eq!(r.is_full(), true); +} + +#[test] +fn try_recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.try_recv(), Err(TryRecvError::Empty)); + thread::sleep(ms(1500)); + assert_eq!(r.try_recv(), Ok(7)); + thread::sleep(ms(500)); + assert_eq!(r.try_recv(), Err(TryRecvError::Disconnected)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Ok(7)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(9)); + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + s.send(8).unwrap(); + s.send(9).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn recv_timeout() { + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv_timeout(ms(1000)), Err(RecvTimeoutError::Timeout)); + assert_eq!(r.recv_timeout(ms(1000)), Ok(7)); + assert_eq!( + r.recv_timeout(ms(1000)), + Err(RecvTimeoutError::Disconnected) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + s.send(7).unwrap(); + }); + }) + .unwrap(); +} + +#[test] +fn try_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.try_send(7), Err(TrySendError::Full(7))); + thread::sleep(ms(1500)); + assert_eq!(s.try_send(8), Ok(())); + thread::sleep(ms(500)); + assert_eq!(s.try_send(9), Err(TrySendError::Disconnected(9))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + assert_eq!(r.recv(), Ok(8)); + }); + }) + .unwrap(); +} + +#[test] +fn send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + s.send(7).unwrap(); + thread::sleep(ms(1000)); + s.send(8).unwrap(); + thread::sleep(ms(1000)); + s.send(9).unwrap(); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(7)); + assert_eq!(r.recv(), Ok(8)); + assert_eq!(r.recv(), Ok(9)); + }); + }) + .unwrap(); +} + +#[test] +fn send_timeout() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!( + s.send_timeout(7, ms(1000)), + Err(SendTimeoutError::Timeout(7)) + ); + assert_eq!(s.send_timeout(8, ms(1000)), Ok(())); + assert_eq!( + s.send_timeout(9, ms(1000)), + Err(SendTimeoutError::Disconnected(9)) + ); + }); + scope.spawn(move |_| { + thread::sleep(ms(1500)); + assert_eq!(r.recv(), Ok(8)); + }); + }) + .unwrap(); +} + +#[test] +fn len() { + const COUNT: usize = 25_000; + + let (s, r) = bounded(0); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + assert_eq!(r.len(), 0); + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + assert_eq!(s.len(), 0); + } + }); + }) + .unwrap(); + + assert_eq!(s.len(), 0); + assert_eq!(r.len(), 0); +} + +#[test] +fn disconnect_wakes_sender() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(s.send(()), Err(SendError(()))); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(r); + }); + }) + .unwrap(); +} + +#[test] +fn disconnect_wakes_receiver() { + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(move |_| { + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + thread::sleep(ms(1000)); + drop(s); + }); + }) + .unwrap(); +} + +#[test] +fn spsc() { + const COUNT: usize = 100_000; + + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + for i in 0..COUNT { + assert_eq!(r.recv(), Ok(i)); + } + assert_eq!(r.recv(), Err(RecvError)); + }); + scope.spawn(move |_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + }) + .unwrap(); +} + +#[test] +fn mpmc() { + const COUNT: usize = 25_000; + const THREADS: usize = 4; + + let (s, r) = bounded::(0); + let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); + + scope(|scope| { + for _ in 0..THREADS { + scope.spawn(|_| { + for _ in 0..COUNT { + let n = r.recv().unwrap(); + v[n].fetch_add(1, Ordering::SeqCst); + } + }); + } + for _ in 0..THREADS { + scope.spawn(|_| { + for i in 0..COUNT { + s.send(i).unwrap(); + } + }); + } + }) + .unwrap(); + + for c in v { + assert_eq!(c.load(Ordering::SeqCst), THREADS); + } +} + +#[test] +fn stress_oneshot() { + const COUNT: usize = 10_000; + + for _ in 0..COUNT { + let (s, r) = bounded(1); + + scope(|scope| { + scope.spawn(|_| r.recv().unwrap()); + scope.spawn(|_| s.send(0).unwrap()); + }) + .unwrap(); + } +} + +#[test] +fn stress_iter() { + const COUNT: usize = 1000; + + let (request_s, request_r) = bounded(0); + let (response_s, response_r) = bounded(0); + + scope(|scope| { + scope.spawn(move |_| { + let mut count = 0; + loop { + for x in response_r.try_iter() { + count += x; + if count == COUNT { + return; + } + } + let _ = request_s.try_send(()); + } + }); + + for _ in request_r.iter() { + if response_s.send(1).is_err() { + break; + } + } + }) + .unwrap(); +} + +#[test] +fn stress_timeout_two_threads() { + const COUNT: usize = 100; + + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(()) = s.send_timeout(i, ms(10)) { + break; + } + } + } + }); + + scope.spawn(|_| { + for i in 0..COUNT { + if i % 2 == 0 { + thread::sleep(ms(50)); + } + loop { + if let Ok(x) = r.recv_timeout(ms(10)) { + assert_eq!(x, i); + break; + } + } + } + }); + }) + .unwrap(); +} + +#[test] +fn drops() { + static DROPS: AtomicUsize = AtomicUsize::new(0); + + #[derive(Debug, PartialEq)] + struct DropCounter; + + impl Drop for DropCounter { + fn drop(&mut self) { + DROPS.fetch_add(1, Ordering::SeqCst); + } + } + + let mut rng = thread_rng(); + + for _ in 0..100 { + let steps = rng.gen_range(0, 3_000); + + DROPS.store(0, Ordering::SeqCst); + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(|_| { + for _ in 0..steps { + r.recv().unwrap(); + } + }); + + scope.spawn(|_| { + for _ in 0..steps { + s.send(DropCounter).unwrap(); + } + }); + }) + .unwrap(); + + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + drop(s); + drop(r); + assert_eq!(DROPS.load(Ordering::SeqCst), steps); + } +} + +#[test] +fn fairness() { + const COUNT: usize = 10_000; + + let (s1, r1) = bounded::<()>(0); + let (s2, r2) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + recv(r1) -> _ => hits[0] += 1, + recv(r2) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }); + + let mut hits = [0usize; 2]; + for _ in 0..COUNT { + select! { + send(s1, ()) -> _ => hits[0] += 1, + send(s2, ()) -> _ => hits[1] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }) + .unwrap(); +} + +#[test] +fn fairness_duplicates() { + const COUNT: usize = 10_000; + + let (s, r) = bounded::<()>(0); + + scope(|scope| { + scope.spawn(|_| { + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + recv(r) -> _ => hits[0] += 1, + recv(r) -> _ => hits[1] += 1, + recv(r) -> _ => hits[2] += 1, + recv(r) -> _ => hits[3] += 1, + recv(r) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }); + + let mut hits = [0usize; 5]; + for _ in 0..COUNT { + select! { + send(s, ()) -> _ => hits[0] += 1, + send(s, ()) -> _ => hits[1] += 1, + send(s, ()) -> _ => hits[2] += 1, + send(s, ()) -> _ => hits[3] += 1, + send(s, ()) -> _ => hits[4] += 1, + } + } + assert!(hits.iter().all(|x| *x >= COUNT / hits.len() / 2)); + }) + .unwrap(); +} + +#[test] +fn recv_in_send() { + let (s, r) = bounded(0); + + scope(|scope| { + scope.spawn(|_| { + thread::sleep(ms(100)); + r.recv() + }); + + scope.spawn(|_| { + thread::sleep(ms(500)); + s.send(()).unwrap(); + }); + + select! { + send(s, r.recv().unwrap()) -> _ => {} + } + }) + .unwrap(); +} + +#[test] +fn channel_through_channel() { + const COUNT: usize = 1000; + + type T = Box; + + let (s, r) = bounded::(0); + + scope(|scope| { + scope.spawn(move |_| { + let mut s = s; + + for _ in 0..COUNT { + let (new_s, new_r) = bounded(0); + let new_r: T = Box::new(Some(new_r)); + + s.send(new_r).unwrap(); + s = new_s; + } + }); + + scope.spawn(move |_| { + let mut r = r; + + for _ in 0..COUNT { + r = r + .recv() + .unwrap() + .downcast_mut::>>() + .unwrap() + .take() + .unwrap() + } + }); + }) + .unwrap(); +} diff --git a/vendor/crossbeam-queue/.cargo-checksum.json b/vendor/crossbeam-queue/.cargo-checksum.json deleted file mode 100644 index b0d2114fcc..0000000000 --- a/vendor/crossbeam-queue/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"fd132a0c0418817ad83e67f46762a13e8c210ce6e94293abfa902361d99b953d","Cargo.toml":"49f1e746f6258de6e2b2127cd974a54735b08d565068b4079378a68eb73a5946","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"5734ed989dfca1f625b40281ee9f4530f91b2411ec01cb748223e7eb87e201ab","LICENSE-THIRD-PARTY":"abb1905b1c2b7db73902e6c328d332d82f3797d7fab61e6fc1c2fc366b132014","README.md":"b487d2d9d9cf9726fbf3b5cf736ddc363f8d1e1410a0a4020dda27c4df72c627","src/array_queue.rs":"02d3deea53652d6fadba3bb4236324262776242176f487688dcf624b379ad500","src/err.rs":"cde063a29dc8887d4c3bd0994f7aab08879841d94c61ecf104a8a85f2c436302","src/lib.rs":"a1331aa4f2d67b4e634667f225c63d55b234802bd1ff72a485d2d56a08eab521","src/seg_queue.rs":"732b5b032313329e39d9c08cf6e63d2926950d645467983fc62e7cabb3cbe330","tests/array_queue.rs":"3faa35bbe2acb3dabdfab5e81860a19e0237c57513420bbb9afe0cb89ac25909","tests/seg_queue.rs":"885ea52ce2c5d1fa9b4265250957d51ffa3f0781d57b01d28cb871371e32ac92"},"package":"774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570"} \ No newline at end of file diff --git a/vendor/crossbeam-queue/CHANGELOG.md b/vendor/crossbeam-queue/CHANGELOG.md deleted file mode 100644 index e44d1f9a40..0000000000 --- a/vendor/crossbeam-queue/CHANGELOG.md +++ /dev/null @@ -1,28 +0,0 @@ -# Version 0.2.3 - -- Fix bug in release (yanking 0.2.2) - -# Version 0.2.2 - -- Fix unsoundness issues by adopting `MaybeUninit`. (#458) - -# Version 0.2.1 - -- Add `no_std` support. - -# Version 0.2.0 - -- Bump the minimum required version to 1.28. -- Bump `crossbeam-utils` to `0.7`. - -# Version 0.1.2 - -- Update `crossbeam-utils` to `0.6.5`. - -# Version 0.1.1 - -- Update `crossbeam-utils` to `0.6.4`. - -# Version 0.1.0 - -- Initial version with `ArrayQueue` and `SegQueue`. diff --git a/vendor/crossbeam-queue/LICENSE-THIRD-PARTY b/vendor/crossbeam-queue/LICENSE-THIRD-PARTY deleted file mode 100644 index 8914949a8e..0000000000 --- a/vendor/crossbeam-queue/LICENSE-THIRD-PARTY +++ /dev/null @@ -1,31 +0,0 @@ -=============================================================================== - -Bounded MPMC queue -http://www.1024cores.net/home/code-license - -Copyright (c) 2010-2011 Dmitry Vyukov. -All rights reserved. - -Redistribution and use in source and binary forms, with or without -modification, are permitted provided that the following conditions are met: - -1. Redistributions of source code must retain the above copyright notice, this - list of conditions and the following disclaimer. -2. Redistributions in binary form must reproduce the above copyright notice, - this list of conditions and the following disclaimer in the documentation - and/or other materials provided with the distribution. - -THIS SOFTWARE IS PROVIDED BY DMITRY VYUKOV "AS IS" AND ANY EXPRESS OR IMPLIED -WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO -EVENT SHALL DMITRY VYUKOV OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, -INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT -LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE -OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF -ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - -The views and conclusions contained in the software and documentation are those -of the authors and should not be interpreted as representing official policies, -either expressed or implied, of Dmitry Vyukov. diff --git a/vendor/crossbeam-queue/README.md b/vendor/crossbeam-queue/README.md deleted file mode 100644 index 646f9cfaad..0000000000 --- a/vendor/crossbeam-queue/README.md +++ /dev/null @@ -1,67 +0,0 @@ -# Crossbeam Queue - -[![Build Status](https://travis-ci.org/crossbeam-rs/crossbeam.svg?branch=master)]( -https://travis-ci.org/crossbeam-rs/crossbeam) -[![License](https://img.shields.io/badge/license-MIT%2FApache--2.0-blue.svg)]( -https://github.com/crossbeam-rs/crossbeam-queue/tree/master/src) -[![Cargo](https://img.shields.io/crates/v/crossbeam-queue.svg)]( -https://crates.io/crates/crossbeam-queue) -[![Documentation](https://docs.rs/crossbeam-queue/badge.svg)]( -https://docs.rs/crossbeam-queue) -[![Rust 1.28+](https://img.shields.io/badge/rust-1.28+-lightgray.svg)]( -https://www.rust-lang.org) -[![chat](https://img.shields.io/discord/569610676205781012.svg?logo=discord)](https://discord.gg/BBYwKq) - -This crate provides concurrent queues that can be shared among threads: - -* [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -* [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. - -[`ArrayQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.ArrayQueue.html -[`SegQueue`]: https://docs.rs/crossbeam-queue/*/crossbeam_queue/struct.SegQueue.html - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -crossbeam-queue = "0.2" -``` - -Next, add this to your crate: - -```rust -extern crate crossbeam_queue; -``` - -## Compatibility - -The minimum supported Rust version is 1.28. Any change to this is considered a breaking change. - -## License - -Licensed under either of - - * Apache License, Version 2.0 ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -#### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be -dual licensed as above, without any additional terms or conditions. - -#### Third party software - -This product includes copies and modifications of software developed by third parties: - -* [src/array_queue.rs](src/array_queue.rs) is based on - [Bounded MPMC queue](http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue) - by Dmitry Vyukov, licensed under the Simplified BSD License and the Apache License, Version 2.0. - -See the source code files for more details. - -Copies of third party licenses can be found in [LICENSE-THIRD-PARTY](LICENSE-THIRD-PARTY). diff --git a/vendor/crossbeam-queue/src/array_queue.rs b/vendor/crossbeam-queue/src/array_queue.rs deleted file mode 100644 index 45b055abde..0000000000 --- a/vendor/crossbeam-queue/src/array_queue.rs +++ /dev/null @@ -1,440 +0,0 @@ -//! The implementation is based on Dmitry Vyukov's bounded MPMC queue. -//! -//! Source: -//! - http://www.1024cores.net/home/lock-free-algorithms/queues/bounded-mpmc-queue -//! -//! Copyright & License: -//! - Copyright (c) 2010-2011 Dmitry Vyukov -//! - Simplified BSD License and Apache License, Version 2.0 -//! - http://www.1024cores.net/home/code-license - -use alloc::vec::Vec; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::mem; -use core::ptr; -use core::sync::atomic::{self, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -use maybe_uninit::MaybeUninit; - -use err::{PopError, PushError}; - -/// A slot in a queue. -struct Slot { - /// The current stamp. - /// - /// If the stamp equals the tail, this node will be next written to. If it equals head + 1, - /// this node will be next read from. - stamp: AtomicUsize, - - /// The value in this slot. - value: UnsafeCell>, -} - -/// A bounded multi-producer multi-consumer queue. -/// -/// This queue allocates a fixed-capacity buffer on construction, which is used to store pushed -/// elements. The queue cannot hold more elements than the buffer allows. Attempting to push an -/// element into a full queue will fail. Having a buffer allocated upfront makes this queue a bit -/// faster than [`SegQueue`]. -/// -/// [`SegQueue`]: struct.SegQueue.html -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::{ArrayQueue, PushError}; -/// -/// let q = ArrayQueue::new(2); -/// -/// assert_eq!(q.push('a'), Ok(())); -/// assert_eq!(q.push('b'), Ok(())); -/// assert_eq!(q.push('c'), Err(PushError('c'))); -/// assert_eq!(q.pop(), Ok('a')); -/// ``` -pub struct ArrayQueue { - /// The head of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are popped from the head of the queue. - head: CachePadded, - - /// The tail of the queue. - /// - /// This value is a "stamp" consisting of an index into the buffer and a lap, but packed into a - /// single `usize`. The lower bits represent the index, while the upper bits represent the lap. - /// - /// Elements are pushed into the tail of the queue. - tail: CachePadded, - - /// The buffer holding slots. - buffer: *mut Slot, - - /// The queue capacity. - cap: usize, - - /// A stamp with the value of `{ lap: 1, index: 0 }`. - one_lap: usize, - - /// Indicates that dropping an `ArrayQueue` may drop elements of type `T`. - _marker: PhantomData, -} - -unsafe impl Sync for ArrayQueue {} -unsafe impl Send for ArrayQueue {} - -impl ArrayQueue { - /// Creates a new bounded queue with the given capacity. - /// - /// # Panics - /// - /// Panics if the capacity is zero. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::ArrayQueue; - /// - /// let q = ArrayQueue::::new(100); - /// ``` - pub fn new(cap: usize) -> ArrayQueue { - assert!(cap > 0, "capacity must be non-zero"); - - // Head is initialized to `{ lap: 0, index: 0 }`. - // Tail is initialized to `{ lap: 0, index: 0 }`. - let head = 0; - let tail = 0; - - // Allocate a buffer of `cap` slots. - let buffer = { - let mut v = Vec::>::with_capacity(cap); - let ptr = v.as_mut_ptr(); - mem::forget(v); - ptr - }; - - // Initialize stamps in the slots. - for i in 0..cap { - unsafe { - // Set the stamp to `{ lap: 0, index: i }`. - let slot = buffer.add(i); - ptr::write(&mut (*slot).stamp, AtomicUsize::new(i)); - } - } - - // One lap is the smallest power of two greater than `cap`. - let one_lap = (cap + 1).next_power_of_two(); - - ArrayQueue { - buffer, - cap, - one_lap, - head: CachePadded::new(AtomicUsize::new(head)), - tail: CachePadded::new(AtomicUsize::new(tail)), - _marker: PhantomData, - } - } - - /// Attempts to push an element into the queue. - /// - /// If the queue is full, the element is returned back as an error. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PushError}; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert_eq!(q.push(10), Ok(())); - /// assert_eq!(q.push(20), Err(PushError(20))); - /// ``` - pub fn push(&self, value: T) -> Result<(), PushError> { - let backoff = Backoff::new(); - let mut tail = self.tail.load(Ordering::Relaxed); - - loop { - // Deconstruct the tail. - let index = tail & (self.one_lap - 1); - let lap = tail & !(self.one_lap - 1); - - // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the tail and the stamp match, we may attempt to push. - if tail == stamp { - let new_tail = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - tail + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Try moving the tail. - match self.tail.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Write the value into the slot and update the stamp. - unsafe { - slot.value.get().write(MaybeUninit::new(value)); - } - slot.stamp.store(tail + 1, Ordering::Release); - return Ok(()); - } - Err(t) => { - tail = t; - backoff.spin(); - } - } - } else if stamp.wrapping_add(self.one_lap) == tail + 1 { - atomic::fence(Ordering::SeqCst); - let head = self.head.load(Ordering::Relaxed); - - // If the head lags one lap behind the tail as well... - if head.wrapping_add(self.one_lap) == tail { - // ...then the queue is full. - return Err(PushError(value)); - } - - backoff.spin(); - tail = self.tail.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - tail = self.tail.load(Ordering::Relaxed); - } - } - } - - /// Attempts to pop an element from the queue. - /// - /// If the queue is empty, an error is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PopError}; - /// - /// let q = ArrayQueue::new(1); - /// assert_eq!(q.push(10), Ok(())); - /// - /// assert_eq!(q.pop(), Ok(10)); - /// assert_eq!(q.pop(), Err(PopError)); - /// ``` - pub fn pop(&self) -> Result { - let backoff = Backoff::new(); - let mut head = self.head.load(Ordering::Relaxed); - - loop { - // Deconstruct the head. - let index = head & (self.one_lap - 1); - let lap = head & !(self.one_lap - 1); - - // Inspect the corresponding slot. - let slot = unsafe { &*self.buffer.add(index) }; - let stamp = slot.stamp.load(Ordering::Acquire); - - // If the the stamp is ahead of the head by 1, we may attempt to pop. - if head + 1 == stamp { - let new = if index + 1 < self.cap { - // Same lap, incremented index. - // Set to `{ lap: lap, index: index + 1 }`. - head + 1 - } else { - // One lap forward, index wraps around to zero. - // Set to `{ lap: lap.wrapping_add(1), index: 0 }`. - lap.wrapping_add(self.one_lap) - }; - - // Try moving the head. - match self.head.compare_exchange_weak( - head, - new, - Ordering::SeqCst, - Ordering::Relaxed, - ) { - Ok(_) => { - // Read the value from the slot and update the stamp. - let msg = unsafe { slot.value.get().read().assume_init() }; - slot.stamp - .store(head.wrapping_add(self.one_lap), Ordering::Release); - return Ok(msg); - } - Err(h) => { - head = h; - backoff.spin(); - } - } - } else if stamp == head { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.load(Ordering::Relaxed); - - // If the tail equals the head, that means the channel is empty. - if tail == head { - return Err(PopError); - } - - backoff.spin(); - head = self.head.load(Ordering::Relaxed); - } else { - // Snooze because we need to wait for the stamp to get updated. - backoff.snooze(); - head = self.head.load(Ordering::Relaxed); - } - } - } - - /// Returns the capacity of the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PopError}; - /// - /// let q = ArrayQueue::::new(100); - /// - /// assert_eq!(q.capacity(), 100); - /// ``` - pub fn capacity(&self) -> usize { - self.cap - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PopError}; - /// - /// let q = ArrayQueue::new(100); - /// - /// assert!(q.is_empty()); - /// q.push(1).unwrap(); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.load(Ordering::SeqCst); - let tail = self.tail.load(Ordering::SeqCst); - - // Is the tail lagging one lap behind head? - // Is the tail equal to the head? - // - // Note: If the head changes just before we load the tail, that means there was a moment - // when the channel was not empty, so it is safe to just return `false`. - tail == head - } - - /// Returns `true` if the queue is full. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PopError}; - /// - /// let q = ArrayQueue::new(1); - /// - /// assert!(!q.is_full()); - /// q.push(1).unwrap(); - /// assert!(q.is_full()); - /// ``` - pub fn is_full(&self) -> bool { - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // Is the head lagging one lap behind tail? - // - // Note: If the tail changes just before we load the head, that means there was a moment - // when the queue was not full, so it is safe to just return `false`. - head.wrapping_add(self.one_lap) == tail - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{ArrayQueue, PopError}; - /// - /// let q = ArrayQueue::new(100); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10).unwrap(); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20).unwrap(); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail, then load the head. - let tail = self.tail.load(Ordering::SeqCst); - let head = self.head.load(Ordering::SeqCst); - - // If the tail didn't change, we've got consistent values to work with. - if self.tail.load(Ordering::SeqCst) == tail { - let hix = head & (self.one_lap - 1); - let tix = tail & (self.one_lap - 1); - - return if hix < tix { - tix - hix - } else if hix > tix { - self.cap - hix + tix - } else if tail == head { - 0 - } else { - self.cap - }; - } - } - } -} - -impl Drop for ArrayQueue { - fn drop(&mut self) { - // Get the index of the head. - let hix = self.head.load(Ordering::Relaxed) & (self.one_lap - 1); - - // Loop over all slots that hold a message and drop them. - for i in 0..self.len() { - // Compute the index of the next slot holding a message. - let index = if hix + i < self.cap { - hix + i - } else { - hix + i - self.cap - }; - - unsafe { - let p = { - let slot = &mut *self.buffer.add(index); - let value = &mut *slot.value.get(); - value.as_mut_ptr() - }; - p.drop_in_place(); - } - } - - // Finally, deallocate the buffer, but don't run any destructors. - unsafe { - Vec::from_raw_parts(self.buffer, 0, self.cap); - } - } -} - -impl fmt::Debug for ArrayQueue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("ArrayQueue { .. }") - } -} diff --git a/vendor/crossbeam-queue/src/err.rs b/vendor/crossbeam-queue/src/err.rs deleted file mode 100644 index 42880e89ec..0000000000 --- a/vendor/crossbeam-queue/src/err.rs +++ /dev/null @@ -1,47 +0,0 @@ -use core::fmt; - -/// Error which occurs when popping from an empty queue. -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct PopError; - -impl fmt::Debug for PopError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "PopError".fmt(f) - } -} - -impl fmt::Display for PopError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "popping from an empty queue".fmt(f) - } -} - -#[cfg(features = "std")] -impl std::error::Error for PopError { - fn description(&self) -> &str { - "popping from an empty queue" - } -} - -/// Error which occurs when pushing into a full queue. -#[derive(Clone, Copy, Eq, PartialEq)] -pub struct PushError(pub T); - -impl fmt::Debug for PushError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "PushError(..)".fmt(f) - } -} - -impl fmt::Display for PushError { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - "pushing into a full queue".fmt(f) - } -} - -#[cfg(features = "std")] -impl std::error::Error for PushError { - fn description(&self) -> &str { - "pushing into a full queue" - } -} diff --git a/vendor/crossbeam-queue/src/lib.rs b/vendor/crossbeam-queue/src/lib.rs deleted file mode 100644 index fd99392070..0000000000 --- a/vendor/crossbeam-queue/src/lib.rs +++ /dev/null @@ -1,42 +0,0 @@ -//! Concurrent queues. -//! -//! This crate provides concurrent queues that can be shared among threads: -//! -//! * [`ArrayQueue`], a bounded MPMC queue that allocates a fixed-capacity buffer on construction. -//! * [`SegQueue`], an unbounded MPMC queue that allocates small buffers, segments, on demand. -//! -//! [`ArrayQueue`]: struct.ArrayQueue.html -//! [`SegQueue`]: struct.SegQueue.html - -#![warn(missing_docs)] -#![warn(missing_debug_implementations)] -#![cfg_attr(not(feature = "std"), no_std)] - -#[macro_use] -extern crate cfg_if; -#[cfg(feature = "std")] -extern crate core; - -extern crate maybe_uninit; - -cfg_if! { - if #[cfg(feature = "alloc")] { - extern crate alloc; - } else if #[cfg(feature = "std")] { - extern crate std as alloc; - } -} - -extern crate crossbeam_utils; - -cfg_if! { - if #[cfg(any(feature = "alloc", feature = "std"))] { - mod array_queue; - mod err; - mod seg_queue; - - pub use self::array_queue::ArrayQueue; - pub use self::err::{PopError, PushError}; - pub use self::seg_queue::SegQueue; - } -} diff --git a/vendor/crossbeam-queue/src/seg_queue.rs b/vendor/crossbeam-queue/src/seg_queue.rs deleted file mode 100644 index b52da4f5c0..0000000000 --- a/vendor/crossbeam-queue/src/seg_queue.rs +++ /dev/null @@ -1,490 +0,0 @@ -use alloc::boxed::Box; -use core::cell::UnsafeCell; -use core::fmt; -use core::marker::PhantomData; -use core::ptr; -use core::sync::atomic::{self, AtomicPtr, AtomicUsize, Ordering}; - -use crossbeam_utils::{Backoff, CachePadded}; - -use maybe_uninit::MaybeUninit; - -use err::PopError; - -// Bits indicating the state of a slot: -// * If a value has been written into the slot, `WRITE` is set. -// * If a value has been read from the slot, `READ` is set. -// * If the block is being destroyed, `DESTROY` is set. -const WRITE: usize = 1; -const READ: usize = 2; -const DESTROY: usize = 4; - -// Each block covers one "lap" of indices. -const LAP: usize = 32; -// The maximum number of values a block can hold. -const BLOCK_CAP: usize = LAP - 1; -// How many lower bits are reserved for metadata. -const SHIFT: usize = 1; -// Indicates that the block is not the last one. -const HAS_NEXT: usize = 1; - -/// A slot in a block. -struct Slot { - /// The value. - value: UnsafeCell>, - - /// The state of the slot. - state: AtomicUsize, -} - -impl Slot { - /// Waits until a value is written into the slot. - fn wait_write(&self) { - let backoff = Backoff::new(); - while self.state.load(Ordering::Acquire) & WRITE == 0 { - backoff.snooze(); - } - } -} - -/// A block in a linked list. -/// -/// Each block in the list can hold up to `BLOCK_CAP` values. -struct Block { - /// The next block in the linked list. - next: AtomicPtr>, - - /// Slots for values. - slots: [Slot; BLOCK_CAP], -} - -impl Block { - /// Creates an empty block that starts at `start_index`. - fn new() -> Block { - // SAFETY: This is safe because: - // [1] `Block::next` (AtomicPtr) may be safely zero initialized. - // [2] `Block::slots` (Array) may be safely zero initialized because of [3, 4]. - // [3] `Slot::value` (UnsafeCell) may be safely zero initialized because it - // holds a MaybeUninit. - // [4] `Slot::state` (AtomicUsize) may be safely zero initialized. - unsafe { MaybeUninit::zeroed().assume_init() } - } - - /// Waits until the next pointer is set. - fn wait_next(&self) -> *mut Block { - let backoff = Backoff::new(); - loop { - let next = self.next.load(Ordering::Acquire); - if !next.is_null() { - return next; - } - backoff.snooze(); - } - } - - /// Sets the `DESTROY` bit in slots starting from `start` and destroys the block. - unsafe fn destroy(this: *mut Block, start: usize) { - // It is not necessary to set the `DESTROY` bit in the last slot because that slot has - // begun destruction of the block. - for i in start..BLOCK_CAP - 1 { - let slot = (*this).slots.get_unchecked(i); - - // Mark the `DESTROY` bit if a thread is still using the slot. - if slot.state.load(Ordering::Acquire) & READ == 0 - && slot.state.fetch_or(DESTROY, Ordering::AcqRel) & READ == 0 - { - // If a thread is still using the slot, it will continue destruction of the block. - return; - } - } - - // No thread is using the block, now it is safe to destroy it. - drop(Box::from_raw(this)); - } -} - -/// A position in a queue. -struct Position { - /// The index in the queue. - index: AtomicUsize, - - /// The block in the linked list. - block: AtomicPtr>, -} - -/// An unbounded multi-producer multi-consumer queue. -/// -/// This queue is implemented as a linked list of segments, where each segment is a small buffer -/// that can hold a handful of elements. There is no limit to how many elements can be in the queue -/// at a time. However, since segments need to be dynamically allocated as elements get pushed, -/// this queue is somewhat slower than [`ArrayQueue`]. -/// -/// [`ArrayQueue`]: struct.ArrayQueue.html -/// -/// # Examples -/// -/// ``` -/// use crossbeam_queue::{PopError, SegQueue}; -/// -/// let q = SegQueue::new(); -/// -/// q.push('a'); -/// q.push('b'); -/// -/// assert_eq!(q.pop(), Ok('a')); -/// assert_eq!(q.pop(), Ok('b')); -/// assert_eq!(q.pop(), Err(PopError)); -/// ``` -pub struct SegQueue { - /// The head of the queue. - head: CachePadded>, - - /// The tail of the queue. - tail: CachePadded>, - - /// Indicates that dropping a `SegQueue` may drop values of type `T`. - _marker: PhantomData, -} - -unsafe impl Send for SegQueue {} -unsafe impl Sync for SegQueue {} - -impl SegQueue { - /// Creates a new unbounded queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::::new(); - /// ``` - pub fn new() -> SegQueue { - SegQueue { - head: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - tail: CachePadded::new(Position { - block: AtomicPtr::new(ptr::null_mut()), - index: AtomicUsize::new(0), - }), - _marker: PhantomData, - } - } - - /// Pushes an element into the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// q.push(20); - /// ``` - pub fn push(&self, value: T) { - let backoff = Backoff::new(); - let mut tail = self.tail.index.load(Ordering::Acquire); - let mut block = self.tail.block.load(Ordering::Acquire); - let mut next_block = None; - - loop { - // Calculate the offset of the index into the block. - let offset = (tail >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - - // If we're going to have to install the next block, allocate it in advance in order to - // make the wait for other threads as short as possible. - if offset + 1 == BLOCK_CAP && next_block.is_none() { - next_block = Some(Box::new(Block::::new())); - } - - // If this is the first push operation, we need to allocate the first block. - if block.is_null() { - let new = Box::into_raw(Box::new(Block::::new())); - - if self - .tail - .block - .compare_and_swap(block, new, Ordering::Release) - == block - { - self.head.block.store(new, Ordering::Release); - block = new; - } else { - next_block = unsafe { Some(Box::from_raw(new)) }; - tail = self.tail.index.load(Ordering::Acquire); - block = self.tail.block.load(Ordering::Acquire); - continue; - } - } - - let new_tail = tail + (1 << SHIFT); - - // Try advancing the tail forward. - match self.tail.index.compare_exchange_weak( - tail, - new_tail, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, install the next one. - if offset + 1 == BLOCK_CAP { - let next_block = Box::into_raw(next_block.unwrap()); - let next_index = new_tail.wrapping_add(1 << SHIFT); - - self.tail.block.store(next_block, Ordering::Release); - self.tail.index.store(next_index, Ordering::Release); - (*block).next.store(next_block, Ordering::Release); - } - - // Write the value into the slot. - let slot = (*block).slots.get_unchecked(offset); - slot.value.get().write(MaybeUninit::new(value)); - slot.state.fetch_or(WRITE, Ordering::Release); - - return; - }, - Err(t) => { - tail = t; - block = self.tail.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Pops an element from the queue. - /// - /// If the queue is empty, an error is returned. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{PopError, SegQueue}; - /// - /// let q = SegQueue::new(); - /// - /// q.push(10); - /// assert_eq!(q.pop(), Ok(10)); - /// assert_eq!(q.pop(), Err(PopError)); - /// ``` - pub fn pop(&self) -> Result { - let backoff = Backoff::new(); - let mut head = self.head.index.load(Ordering::Acquire); - let mut block = self.head.block.load(Ordering::Acquire); - - loop { - // Calculate the offset of the index into the block. - let offset = (head >> SHIFT) % LAP; - - // If we reached the end of the block, wait until the next one is installed. - if offset == BLOCK_CAP { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - let mut new_head = head + (1 << SHIFT); - - if new_head & HAS_NEXT == 0 { - atomic::fence(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::Relaxed); - - // If the tail equals the head, that means the queue is empty. - if head >> SHIFT == tail >> SHIFT { - return Err(PopError); - } - - // If head and tail are not in the same block, set `HAS_NEXT` in head. - if (head >> SHIFT) / LAP != (tail >> SHIFT) / LAP { - new_head |= HAS_NEXT; - } - } - - // The block can be null here only if the first push operation is in progress. In that - // case, just wait until it gets initialized. - if block.is_null() { - backoff.snooze(); - head = self.head.index.load(Ordering::Acquire); - block = self.head.block.load(Ordering::Acquire); - continue; - } - - // Try moving the head index forward. - match self.head.index.compare_exchange_weak( - head, - new_head, - Ordering::SeqCst, - Ordering::Acquire, - ) { - Ok(_) => unsafe { - // If we've reached the end of the block, move to the next one. - if offset + 1 == BLOCK_CAP { - let next = (*block).wait_next(); - let mut next_index = (new_head & !HAS_NEXT).wrapping_add(1 << SHIFT); - if !(*next).next.load(Ordering::Relaxed).is_null() { - next_index |= HAS_NEXT; - } - - self.head.block.store(next, Ordering::Release); - self.head.index.store(next_index, Ordering::Release); - } - - // Read the value. - let slot = (*block).slots.get_unchecked(offset); - slot.wait_write(); - let value = slot.value.get().read().assume_init(); - - // Destroy the block if we've reached the end, or if another thread wanted to - // destroy but couldn't because we were busy reading from the slot. - if offset + 1 == BLOCK_CAP { - Block::destroy(block, 0); - } else if slot.state.fetch_or(READ, Ordering::AcqRel) & DESTROY != 0 { - Block::destroy(block, offset + 1); - } - - return Ok(value); - }, - Err(h) => { - head = h; - block = self.head.block.load(Ordering::Acquire); - backoff.spin(); - } - } - } - } - - /// Returns `true` if the queue is empty. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::SegQueue; - /// - /// let q = SegQueue::new(); - /// - /// assert!(q.is_empty()); - /// q.push(1); - /// assert!(!q.is_empty()); - /// ``` - pub fn is_empty(&self) -> bool { - let head = self.head.index.load(Ordering::SeqCst); - let tail = self.tail.index.load(Ordering::SeqCst); - head >> SHIFT == tail >> SHIFT - } - - /// Returns the number of elements in the queue. - /// - /// # Examples - /// - /// ``` - /// use crossbeam_queue::{SegQueue, PopError}; - /// - /// let q = SegQueue::new(); - /// assert_eq!(q.len(), 0); - /// - /// q.push(10); - /// assert_eq!(q.len(), 1); - /// - /// q.push(20); - /// assert_eq!(q.len(), 2); - /// ``` - pub fn len(&self) -> usize { - loop { - // Load the tail index, then load the head index. - let mut tail = self.tail.index.load(Ordering::SeqCst); - let mut head = self.head.index.load(Ordering::SeqCst); - - // If the tail index didn't change, we've got consistent indices to work with. - if self.tail.index.load(Ordering::SeqCst) == tail { - // Erase the lower bits. - tail &= !((1 << SHIFT) - 1); - head &= !((1 << SHIFT) - 1); - - // Rotate indices so that head falls into the first block. - let lap = (head >> SHIFT) / LAP; - tail = tail.wrapping_sub((lap * LAP) << SHIFT); - head = head.wrapping_sub((lap * LAP) << SHIFT); - - // Remove the lower bits. - tail >>= SHIFT; - head >>= SHIFT; - - // Fix up indices if they fall onto block ends. - if head == BLOCK_CAP { - head = 0; - tail -= LAP; - } - if tail == BLOCK_CAP { - tail += 1; - } - - // Return the difference minus the number of blocks between tail and head. - return tail - head - tail / LAP; - } - } - } -} - -impl Drop for SegQueue { - fn drop(&mut self) { - let mut head = self.head.index.load(Ordering::Relaxed); - let mut tail = self.tail.index.load(Ordering::Relaxed); - let mut block = self.head.block.load(Ordering::Relaxed); - - // Erase the lower bits. - head &= !((1 << SHIFT) - 1); - tail &= !((1 << SHIFT) - 1); - - unsafe { - // Drop all values between `head` and `tail` and deallocate the heap-allocated blocks. - while head != tail { - let offset = (head >> SHIFT) % LAP; - - if offset < BLOCK_CAP { - // Drop the value in the slot. - let slot = (*block).slots.get_unchecked(offset); - let p = &mut *slot.value.get(); - p.as_mut_ptr().drop_in_place(); - } else { - // Deallocate the block and move to the next one. - let next = (*block).next.load(Ordering::Relaxed); - drop(Box::from_raw(block)); - block = next; - } - - head = head.wrapping_add(1 << SHIFT); - } - - // Deallocate the last remaining block. - if !block.is_null() { - drop(Box::from_raw(block)); - } - } - } -} - -impl fmt::Debug for SegQueue { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - f.pad("SegQueue { .. }") - } -} - -impl Default for SegQueue { - fn default() -> SegQueue { - SegQueue::new() - } -} diff --git a/vendor/crossbeam-queue/tests/array_queue.rs b/vendor/crossbeam-queue/tests/array_queue.rs deleted file mode 100644 index a4f64f3432..0000000000 --- a/vendor/crossbeam-queue/tests/array_queue.rs +++ /dev/null @@ -1,254 +0,0 @@ -extern crate crossbeam_queue; -extern crate crossbeam_utils; -extern crate rand; - -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::ArrayQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = ArrayQueue::new(1); - - q.push(7).unwrap(); - assert_eq!(q.pop(), Ok(7)); - - q.push(8).unwrap(); - assert_eq!(q.pop(), Ok(8)); - assert!(q.pop().is_err()); -} - -#[test] -fn capacity() { - for i in 1..10 { - let q = ArrayQueue::::new(i); - assert_eq!(q.capacity(), i); - } -} - -#[test] -#[should_panic(expected = "capacity must be non-zero")] -fn zero_capacity() { - let _ = ArrayQueue::::new(0); -} - -#[test] -fn len_empty_full() { - let q = ArrayQueue::new(2); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); - assert_eq!(q.is_full(), false); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), false); - - q.push(()).unwrap(); - - assert_eq!(q.len(), 2); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), true); - - q.pop().unwrap(); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - assert_eq!(q.is_full(), false); -} - -#[test] -fn len() { - const COUNT: usize = 25_000; - const CAP: usize = 1000; - - let q = ArrayQueue::new(CAP); - assert_eq!(q.len(), 0); - - for _ in 0..CAP / 10 { - for i in 0..50 { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for i in 0..50 { - q.pop().unwrap(); - assert_eq!(q.len(), 50 - i - 1); - } - } - assert_eq!(q.len(), 0); - - for i in 0..CAP { - q.push(i).unwrap(); - assert_eq!(q.len(), i + 1); - } - - for _ in 0..CAP { - q.pop().unwrap(); - } - assert_eq!(q.len(), 0); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - let len = q.len(); - assert!(len <= CAP); - } - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - let len = q.len(); - assert!(len <= CAP); - } - }); - }) - .unwrap(); - assert_eq!(q.len(), 0); -} - -#[test] -fn spsc() { - const COUNT: usize = 100_000; - - let q = ArrayQueue::new(3); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_err()); - }); - - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - }) - .unwrap(); -} - -#[test] -fn mpmc() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::::new(3); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Ok(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - while q.push(i).is_err() {} - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[test] -fn drops() { - const RUNS: usize = 100; - - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..RUNS { - let steps = rng.gen_range(0, 10_000); - let additional = rng.gen_range(0, 50); - - DROPS.store(0, Ordering::SeqCst); - let q = ArrayQueue::new(50); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_err() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - while q.push(DropCounter).is_err() { - DROPS.fetch_sub(1, Ordering::SeqCst); - } - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter).unwrap(); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} - -#[test] -fn linearizable() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = ArrayQueue::new(THREADS); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - while q.push(0).is_err() {} - q.pop().unwrap(); - } - }); - } - }) - .unwrap(); -} diff --git a/vendor/crossbeam-queue/tests/seg_queue.rs b/vendor/crossbeam-queue/tests/seg_queue.rs deleted file mode 100644 index ec32e1f642..0000000000 --- a/vendor/crossbeam-queue/tests/seg_queue.rs +++ /dev/null @@ -1,167 +0,0 @@ -extern crate crossbeam_queue; -extern crate crossbeam_utils; -extern crate rand; - -use std::sync::atomic::{AtomicUsize, Ordering}; - -use crossbeam_queue::SegQueue; -use crossbeam_utils::thread::scope; -use rand::{thread_rng, Rng}; - -#[test] -fn smoke() { - let q = SegQueue::new(); - q.push(7); - assert_eq!(q.pop(), Ok(7)); - - q.push(8); - assert_eq!(q.pop(), Ok(8)); - assert!(q.pop().is_err()); -} - -#[test] -fn len_empty_full() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); - - q.push(()); - - assert_eq!(q.len(), 1); - assert_eq!(q.is_empty(), false); - - q.pop().unwrap(); - - assert_eq!(q.len(), 0); - assert_eq!(q.is_empty(), true); -} - -#[test] -fn len() { - let q = SegQueue::new(); - - assert_eq!(q.len(), 0); - - for i in 0..50 { - q.push(i); - assert_eq!(q.len(), i + 1); - } - - for i in 0..50 { - q.pop().unwrap(); - assert_eq!(q.len(), 50 - i - 1); - } - - assert_eq!(q.len(), 0); -} - -#[test] -fn spsc() { - const COUNT: usize = 100_000; - - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for i in 0..COUNT { - loop { - if let Ok(x) = q.pop() { - assert_eq!(x, i); - break; - } - } - } - assert!(q.pop().is_err()); - }); - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - }) - .unwrap(); -} - -#[test] -fn mpmc() { - const COUNT: usize = 25_000; - const THREADS: usize = 4; - - let q = SegQueue::::new(); - let v = (0..COUNT).map(|_| AtomicUsize::new(0)).collect::>(); - - scope(|scope| { - for _ in 0..THREADS { - scope.spawn(|_| { - for _ in 0..COUNT { - let n = loop { - if let Ok(x) = q.pop() { - break x; - } - }; - v[n].fetch_add(1, Ordering::SeqCst); - } - }); - } - for _ in 0..THREADS { - scope.spawn(|_| { - for i in 0..COUNT { - q.push(i); - } - }); - } - }) - .unwrap(); - - for c in v { - assert_eq!(c.load(Ordering::SeqCst), THREADS); - } -} - -#[test] -fn drops() { - static DROPS: AtomicUsize = AtomicUsize::new(0); - - #[derive(Debug, PartialEq)] - struct DropCounter; - - impl Drop for DropCounter { - fn drop(&mut self) { - DROPS.fetch_add(1, Ordering::SeqCst); - } - } - - let mut rng = thread_rng(); - - for _ in 0..100 { - let steps = rng.gen_range(0, 10_000); - let additional = rng.gen_range(0, 1000); - - DROPS.store(0, Ordering::SeqCst); - let q = SegQueue::new(); - - scope(|scope| { - scope.spawn(|_| { - for _ in 0..steps { - while q.pop().is_err() {} - } - }); - - scope.spawn(|_| { - for _ in 0..steps { - q.push(DropCounter); - } - }); - }) - .unwrap(); - - for _ in 0..additional { - q.push(DropCounter); - } - - assert_eq!(DROPS.load(Ordering::SeqCst), steps); - drop(q); - assert_eq!(DROPS.load(Ordering::SeqCst), steps + additional); - } -} diff --git a/vendor/digest-0.8.1/.cargo-checksum.json b/vendor/digest-0.8.1/.cargo-checksum.json new file mode 100644 index 0000000000..ed59510b23 --- /dev/null +++ b/vendor/digest-0.8.1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"bfdc024e55a5d9f2f415045e9083abb13159e0276c3eb3dbdca290c69f8b4824","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/dev.rs":"5890305be2cd3d221d1c2ce295b911cc57017dc341966ba434def4a072f8bf1c","src/digest.rs":"73f564cb8084e61baf850948443bacdea81727dfbff5abeb520c0e5bb690da7a","src/dyn_digest.rs":"abfa9a30ed2dc71ad2042501961146c87fe3cbf9254b5b203fe24920d0e246b8","src/errors.rs":"2584007e98d691160313cc27e6237db9bd886e9774137b59a1289a20054e9375","src/lib.rs":"71d838697e87561de4b6b2fda94df44639a525d4469316d4ad21f0f0075a130d"},"package":"f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"} \ No newline at end of file diff --git a/vendor/digest-0.8.1/Cargo.toml b/vendor/digest-0.8.1/Cargo.toml new file mode 100644 index 0000000000..d363007695 --- /dev/null +++ b/vendor/digest-0.8.1/Cargo.toml @@ -0,0 +1,36 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "digest" +version = "0.8.1" +authors = ["RustCrypto Developers"] +description = "Traits for cryptographic hash functions" +documentation = "https://docs.rs/digest" +keywords = ["digest", "crypto", "hash"] +categories = ["cryptography", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/traits" +[package.metadata.docs.rs] +features = ["std"] +[dependencies.blobby] +version = "0.1" +optional = true + +[dependencies.generic-array] +version = "0.12" + +[features] +dev = ["blobby"] +std = [] +[badges.travis-ci] +repository = "RustCrypto/traits" diff --git a/vendor/digest-0.8.1/LICENSE-APACHE b/vendor/digest-0.8.1/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/digest-0.8.1/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/parking_lot_core-0.7.2/LICENSE-MIT b/vendor/digest-0.8.1/LICENSE-MIT similarity index 95% rename from vendor/parking_lot_core-0.7.2/LICENSE-MIT rename to vendor/digest-0.8.1/LICENSE-MIT index 40b8817a47..8dcb85b302 100644 --- a/vendor/parking_lot_core-0.7.2/LICENSE-MIT +++ b/vendor/digest-0.8.1/LICENSE-MIT @@ -1,4 +1,4 @@ -Copyright (c) 2016 The Rust Project Developers +Copyright (c) 2017 Artyom Pavlov Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated diff --git a/vendor/digest-0.8.1/src/dev.rs b/vendor/digest-0.8.1/src/dev.rs new file mode 100644 index 0000000000..e9950ee799 --- /dev/null +++ b/vendor/digest-0.8.1/src/dev.rs @@ -0,0 +1,218 @@ +use super::{Input, VariableOutput, ExtendableOutput, Reset, XofReader}; +use core::fmt::Debug; + +#[macro_export] +macro_rules! new_test { + ($name:ident, $test_name:expr, $hasher:ty, $test_func:ident) => { + #[test] + fn $name() { + use digest::blobby::Blob2Iterator; + let data = include_bytes!(concat!("data/", $test_name, ".blb")); + + for (i, row) in Blob2Iterator::new(data).unwrap().enumerate() { + let input = row[0]; + let output = row[1]; + if let Some(desc) = $test_func::<$hasher>(input, output) { + panic!("\n\ + Failed test №{}: {}\n\ + input:\t{:?}\n\ + output:\t{:?}\n", + i, desc, input, output, + ); + } + } + } + } +} + +// module to separate Digest from other traits +mod foo { + use super::super::Digest; + use core::fmt::Debug; + + pub fn digest_test(input: &[u8], output: &[u8]) -> Option<&'static str> + where D: Digest + Debug + Clone + { + let mut hasher = D::new(); + // Test that it works when accepting the message all at once + hasher.input(input); + let mut hasher2 = hasher.clone(); + if hasher.result().as_slice() != output { + return Some("whole message"); + } + + // Test if reset works correctly + hasher2.reset(); + hasher2.input(input); + if hasher2.result().as_slice() != output { + return Some("whole message after reset"); + } + + // Test that it works when accepting the message in pieces + let mut hasher = D::new(); + let len = input.len(); + let mut left = len; + while left > 0 { + let take = (left + 1) / 2; + hasher.input(&input[len - left..take + len - left]); + left = left - take; + } + if hasher.result().as_slice() != output { + return Some("message in pieces"); + } + + // Test processing byte-by-byte + let mut hasher = D::new(); + for chunk in input.chunks(1) { + hasher.input(chunk) + } + if hasher.result().as_slice() != output { + return Some("message byte-by-byte"); + } + None + } + + + pub fn one_million_a(expected: &[u8]) + where D: Digest + Debug + Clone + { + let mut sh = D::new(); + for _ in 0..50_000 { + sh.input(&[b'a'; 10]); + } + sh.input(&[b'a'; 500_000][..]); + let out = sh.result(); + assert_eq!(out[..], expected[..]); + } +} + +pub use self::foo::{digest_test, one_million_a}; + +pub fn xof_test(input: &[u8], output: &[u8]) + -> Option<&'static str> + where D: Input + ExtendableOutput + Default + Debug + Reset + Clone +{ + let mut hasher = D::default(); + let mut buf = [0u8; 1024]; + // Test that it works when accepting the message all at once + hasher.input(input); + + let mut hasher2 = hasher.clone(); + { + let out = &mut buf[..output.len()]; + hasher.xof_result().read(out); + + if out != output { return Some("whole message"); } + } + + // Test if hasher resets correctly + hasher2.reset(); + hasher2.input(input); + + { + let out = &mut buf[..output.len()]; + hasher2.xof_result().read(out); + + if out != output { return Some("whole message after reset"); } + } + + // Test if hasher accepts message in pieces correctly + let mut hasher = D::default(); + let len = input.len(); + let mut left = len; + while left > 0 { + let take = (left + 1) / 2; + hasher.input(&input[len - left..take + len - left]); + left = left - take; + } + + { + let out = &mut buf[..output.len()]; + hasher.xof_result().read(out); + if out != output { return Some("message in pieces"); } + } + + // Test reading from reader byte by byte + let mut hasher = D::default(); + hasher.input(input); + + let mut reader = hasher.xof_result(); + let out = &mut buf[..output.len()]; + for chunk in out.chunks_mut(1) { + reader.read(chunk); + } + + if out != output { return Some("message in pieces"); } + None +} + +pub fn variable_test(input: &[u8], output: &[u8]) + -> Option<&'static str> + where D: Input + VariableOutput + Reset + Debug + Clone +{ + let mut hasher = D::new(output.len()).unwrap(); + let mut buf = [0u8; 128]; + let buf = &mut buf[..output.len()]; + // Test that it works when accepting the message all at once + hasher.input(input); + let mut hasher2 = hasher.clone(); + hasher.variable_result(|res| buf.copy_from_slice(res)); + if buf != output { return Some("whole message"); } + + // Test if reset works correctly + hasher2.reset(); + hasher2.input(input); + hasher2.variable_result(|res| buf.copy_from_slice(res)); + if buf != output { return Some("whole message after reset"); } + + // Test that it works when accepting the message in pieces + let mut hasher = D::new(output.len()).unwrap(); + let len = input.len(); + let mut left = len; + while left > 0 { + let take = (left + 1) / 2; + hasher.input(&input[len - left..take + len - left]); + left = left - take; + } + hasher.variable_result(|res| buf.copy_from_slice(res)); + if buf != output { return Some("message in pieces"); } + + // Test processing byte-by-byte + let mut hasher = D::new(output.len()).unwrap(); + for chunk in input.chunks(1) { + hasher.input(chunk) + } + hasher.variable_result(|res| buf.copy_from_slice(res)); + if buf != output { return Some("message byte-by-byte"); } + None +} + + +#[macro_export] +macro_rules! bench { + ($name:ident, $engine:path, $bs:expr) => { + #[bench] + fn $name(b: &mut Bencher) { + let mut d = <$engine>::default(); + let data = [0; $bs]; + + b.iter(|| { + d.input(&data[..]); + }); + + b.bytes = $bs; + } + }; + + ($engine:path) => { + extern crate test; + + use test::Bencher; + use digest::Digest; + + bench!(bench1_10, $engine, 10); + bench!(bench2_100, $engine, 100); + bench!(bench3_1000, $engine, 1000); + bench!(bench4_10000, $engine, 10000); + } +} diff --git a/vendor/digest-0.8.1/src/digest.rs b/vendor/digest-0.8.1/src/digest.rs new file mode 100644 index 0000000000..50128e13ec --- /dev/null +++ b/vendor/digest-0.8.1/src/digest.rs @@ -0,0 +1,86 @@ +use super::{Input, FixedOutput, Reset}; +use generic_array::{GenericArray, ArrayLength}; +use generic_array::typenum::Unsigned; + +/// The `Digest` trait specifies an interface common for digest functions. +/// +/// It's a convenience wrapper around `Input`, `FixedOutput`, `Reset`, `Clone`, +/// and `Default` traits. It also provides additional convenience methods. +pub trait Digest { + type OutputSize: ArrayLength; + /// Create new hasher instance + fn new() -> Self; + + /// Digest input data. + /// + /// This method can be called repeatedly for use with streaming messages. + fn input>(&mut self, data: B); + + /// Digest input data in a chained manner. + fn chain>(self, data: B) -> Self where Self: Sized; + + /// Retrieve result and consume hasher instance. + fn result(self) -> GenericArray; + + /// Retrieve result and reset hasher instance. + /// + /// This method sometimes can be more efficient compared to hasher + /// re-creation. + fn result_reset(&mut self) -> GenericArray; + + /// Reset hasher instance to its initial state. + fn reset(&mut self); + + /// Get output size of the hasher + fn output_size() -> usize; + + /// Convenience function to compute hash of the `data`. It will handle + /// hasher creation, data feeding and finalization. + /// + /// Example: + /// + /// ```rust,ignore + /// println!("{:x}", sha2::Sha256::digest(b"Hello world")); + /// ``` + fn digest(data: &[u8]) -> GenericArray; +} + +impl Digest for D { + type OutputSize = ::OutputSize; + + fn new() -> Self { + Self::default() + } + + fn input>(&mut self, data: B) { + Input::input(self, data); + } + + fn chain>(self, data: B) -> Self where Self: Sized { + Input::chain(self, data) + } + + fn result(self) -> GenericArray { + self.fixed_result() + } + + fn result_reset(&mut self) -> GenericArray { + let res = self.clone().fixed_result(); + self.reset(); + res + } + + fn reset(&mut self) { + ::reset(self) + } + + fn output_size() -> usize { + Self::OutputSize::to_usize() + } + + fn digest(data: &[u8]) -> GenericArray { + let mut hasher = Self::default(); + Input::input(&mut hasher, data); + hasher.fixed_result() + } +} diff --git a/vendor/digest-0.8.1/src/dyn_digest.rs b/vendor/digest-0.8.1/src/dyn_digest.rs new file mode 100644 index 0000000000..2af43a8e3d --- /dev/null +++ b/vendor/digest-0.8.1/src/dyn_digest.rs @@ -0,0 +1,63 @@ +#![cfg(feature = "std")] +use std::boxed::Box; + +use super::{Input, FixedOutput, Reset}; +use generic_array::typenum::Unsigned; + +/// The `DynDigest` trait is a modification of `Digest` trait suitable +/// for trait objects. +pub trait DynDigest { + /// Digest input data. + /// + /// This method can be called repeatedly for use with streaming messages. + fn input(&mut self, data: &[u8]); + + /// Retrieve result and reset hasher instance + fn result_reset(&mut self) -> Box<[u8]>; + + /// Retrieve result and consume boxed hasher instance + fn result(self: Box) -> Box<[u8]>; + + /// Reset hasher instance to its initial state. + fn reset(&mut self); + + /// Get output size of the hasher + fn output_size(&self) -> usize; + + /// Clone hasher state into a boxed trait object + fn box_clone(&self) -> Box; +} + +impl DynDigest for D { + fn input(&mut self, data: &[u8]) { + Input::input(self, data); + } + + fn result_reset(&mut self) -> Box<[u8]> { + let res = self.clone().fixed_result().to_vec().into_boxed_slice(); + Reset::reset(self); + res + } + + fn result(self: Box) -> Box<[u8]> { + self.fixed_result().to_vec().into_boxed_slice() + } + + fn reset(&mut self) { + Reset::reset(self); + } + + fn output_size(&self) -> usize { + ::OutputSize::to_usize() + } + + fn box_clone(&self) -> Box { + Box::new(self.clone()) + } +} + +impl Clone for Box { + fn clone(&self) -> Self { + self.box_clone() + } +} diff --git a/vendor/digest-0.8.1/src/errors.rs b/vendor/digest-0.8.1/src/errors.rs new file mode 100644 index 0000000000..aa026a21a1 --- /dev/null +++ b/vendor/digest-0.8.1/src/errors.rs @@ -0,0 +1,20 @@ +use core::fmt; +#[cfg(feature = "std")] +use std::error; + +/// The error type for variable hasher initialization +#[derive(Clone, Copy, Debug, Default)] +pub struct InvalidOutputSize; + +impl fmt::Display for InvalidOutputSize { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.write_str("invalid output size") + } +} + +#[cfg(feature = "std")] +impl error::Error for InvalidOutputSize { + fn description(&self) -> &str { + "invalid output size" + } +} diff --git a/vendor/digest-0.8.1/src/lib.rs b/vendor/digest-0.8.1/src/lib.rs new file mode 100644 index 0000000000..f03c501076 --- /dev/null +++ b/vendor/digest-0.8.1/src/lib.rs @@ -0,0 +1,141 @@ +//! This crate provides traits which describe functionality of cryptographic hash +//! functions. +//! +//! Traits in this repository can be separated into two levels: +//! - Low level traits: `Input`, `BlockInput`, `Reset`, `FixedOutput`, +//! `VariableOutput`, `ExtendableOutput`. These traits atomically describe +//! available functionality of hash function implementations. +//! - Convenience trait: `Digest`, `DynDigest`. They are wrappers around +//! low level traits for most common hash-function use-cases. +//! +//! Additionally hash functions implement traits from `std`: `Default`, `Clone`, +//! `Write`. (the latter depends on enabled-by-default `std` crate feature) +//! +//! The `Digest` trait is the most commonly used trait. +#![no_std] +#![doc(html_logo_url = + "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] +pub extern crate generic_array; +#[cfg(feature = "std")] +#[macro_use] extern crate std; +#[cfg(feature = "dev")] +pub extern crate blobby; +use generic_array::{GenericArray, ArrayLength}; +#[cfg(feature = "std")] +use std::vec::Vec; + +mod digest; +mod dyn_digest; +mod errors; +#[cfg(feature = "dev")] +pub mod dev; + +pub use errors::InvalidOutputSize; +pub use digest::Digest; +#[cfg(feature = "std")] +pub use dyn_digest::DynDigest; + +/// Trait for processing input data +pub trait Input { + /// Digest input data. + /// + /// This method can be called repeatedly, e.g. for processing streaming + /// messages. + fn input>(&mut self, data: B); + + /// Digest input data in a chained manner. + fn chain>(mut self, data: B) -> Self where Self: Sized { + self.input(data); + self + } +} + +/// Trait to indicate that digest function processes data in blocks of size +/// `BlockSize`. +/// +/// The main usage of this trait is for implementing HMAC generically. +pub trait BlockInput { + type BlockSize: ArrayLength; +} + +/// Trait for returning digest result with the fixed size +pub trait FixedOutput { + type OutputSize: ArrayLength; + + /// Retrieve result and consume hasher instance. + fn fixed_result(self) -> GenericArray; +} + +/// Trait for returning digest result with the variable size +pub trait VariableOutput: core::marker::Sized { + /// Create new hasher instance with the given output size. + /// + /// It will return `Err(InvalidOutputSize)` in case if hasher can not return + /// specified output size. It will always return an error if output size + /// equals to zero. + fn new(output_size: usize) -> Result; + + /// Get output size of the hasher instance provided to the `new` method + fn output_size(&self) -> usize; + + /// Retrieve result via closure and consume hasher. + /// + /// Closure is guaranteed to be called, length of the buffer passed to it + /// will be equal to `output_size`. + fn variable_result(self, f: F); + + /// Retrieve result into vector and consume hasher. + #[cfg(feature = "std")] + fn vec_result(self) -> Vec { + let mut buf = Vec::with_capacity(self.output_size()); + self.variable_result(|res| buf.extend_from_slice(res)); + buf + } +} + +/// Trait for describing readers which are used to extract extendable output +/// from XOF (extendable-output function) result. +pub trait XofReader { + /// Read output into the `buffer`. Can be called unlimited number of times. + fn read(&mut self, buffer: &mut [u8]); +} + +/// Trait which describes extendable-output functions (XOF). +pub trait ExtendableOutput: core::marker::Sized { + type Reader: XofReader; + + /// Retrieve XOF reader and consume hasher instance. + fn xof_result(self) -> Self::Reader; + + /// Retrieve result into vector of specified length. + #[cfg(feature = "std")] + fn vec_result(self, n: usize) -> Vec { + let mut buf = vec![0u8; n]; + self.xof_result().read(&mut buf); + buf + } +} + +/// Trait for resetting hash instances +pub trait Reset { + /// Reset hasher instance to its initial state and return current state. + fn reset(&mut self); +} + +#[macro_export] +/// Implements `std::io::Write` trait for implementer of `Input` +macro_rules! impl_write { + ($hasher:ident) => { + #[cfg(feature = "std")] + impl ::std::io::Write for $hasher { + fn write(&mut self, buf: &[u8]) -> ::std::io::Result { + Input::input(self, buf); + Ok(buf.len()) + } + + fn flush(&mut self) -> ::std::io::Result<()> { + Ok(()) + } + } + } +} diff --git a/vendor/digest/.cargo-checksum.json b/vendor/digest/.cargo-checksum.json index ed59510b23..00bfd169d8 100644 --- a/vendor/digest/.cargo-checksum.json +++ b/vendor/digest/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"bfdc024e55a5d9f2f415045e9083abb13159e0276c3eb3dbdca290c69f8b4824","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","src/dev.rs":"5890305be2cd3d221d1c2ce295b911cc57017dc341966ba434def4a072f8bf1c","src/digest.rs":"73f564cb8084e61baf850948443bacdea81727dfbff5abeb520c0e5bb690da7a","src/dyn_digest.rs":"abfa9a30ed2dc71ad2042501961146c87fe3cbf9254b5b203fe24920d0e246b8","src/errors.rs":"2584007e98d691160313cc27e6237db9bd886e9774137b59a1289a20054e9375","src/lib.rs":"71d838697e87561de4b6b2fda94df44639a525d4469316d4ad21f0f0075a130d"},"package":"f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5"} \ No newline at end of file +{"files":{"CHANGELOG.md":"dc6fb3107d31625c783c08064beae3169506996d4a8680543d220f63b235dfed","Cargo.toml":"10e467adec4f2b31ef4d9b65aaf16e4724ccafcc9631660406e4ab225c15014d","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"9e0dfd2dd4173a530e238cb6adb37aa78c34c6bc7444e0e10c1ab5d8881f63ba","README.md":"b09a5f742c7bbba7fa2ce9d38a4584ad88e9ff835b18563d27daedb234142667","src/dev.rs":"1a57f754b3fdaaef5f2f6f8b89cc4c426b16830d57398d4b2e170094304424a6","src/digest.rs":"3155f2b42578b759da226efb51c92acec99eeee4b293c33e83c63c4b62492f7c","src/dyn_digest.rs":"ce6100ee4af7c785dc257c86fd1c2f08a8d096d520164ee5a993500fc19dd211","src/errors.rs":"b8412605e73c8d75e128ced82bbd2b02691d40d93c5436271307a2e74c5cbf66","src/fixed.rs":"06d144dec57157ad89e7c36fbf9494d9a597eadcf98006cfbf4599ddd3ab9b08","src/lib.rs":"dc5fdf8ea8a5cfcb2c2fdbc412cd8bf9aec58af4f274e3788f86eea5f755688f","src/variable.rs":"6aaa3fd4409ca9aeada08246d0bb535c66d26bc09ce2ca6b7eddf460456e9157","src/xof.rs":"53032d946352b74b74e6a8f7b11df3e45985438701e7e7621fe563008eb3c627"},"package":"d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066"} \ No newline at end of file diff --git a/vendor/digest/CHANGELOG.md b/vendor/digest/CHANGELOG.md new file mode 100644 index 0000000000..03f0ad387c --- /dev/null +++ b/vendor/digest/CHANGELOG.md @@ -0,0 +1,78 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.9.0 (2020-06-09) +### Added +- `ExtendableOutputDirty` and `VariableOutputDirty` traits ([#183]) +- `FixedOutputDirty` trait + `finalize_into*` ([#180]) +- `XofReader::read_boxed` method ([#178], [#181], [#182]) +- `alloc` feature ([#163]) +- Re-export `typenum::consts` as `consts` ([#123]) +- `Output` type alias ([#115]) + +### Changed +- Rename `*result*` methods to `finalize` ala IUF ([#161]) +- Use `impl AsRef<[u8]>` instead of generic params on methods ([#112]) +- Rename `Input::input` to `Update::update` ala IUF ([#111]) +- Upgrade to Rust 2018 edition ([#109]) +- Bump `generic-array` to v0.14 ([#95]) + +[#183]: https://github.com/RustCrypto/traits/pull/183 +[#181]: https://github.com/RustCrypto/traits/pull/181 +[#182]: https://github.com/RustCrypto/traits/pull/182 +[#180]: https://github.com/RustCrypto/traits/pull/180 +[#178]: https://github.com/RustCrypto/traits/pull/178 +[#163]: https://github.com/RustCrypto/traits/pull/163 +[#161]: https://github.com/RustCrypto/traits/pull/161 +[#123]: https://github.com/RustCrypto/traits/pull/123 +[#115]: https://github.com/RustCrypto/traits/pull/115 +[#111]: https://github.com/RustCrypto/traits/pull/111 +[#112]: https://github.com/RustCrypto/traits/pull/112 +[#109]: https://github.com/RustCrypto/traits/pull/109 +[#95]: https://github.com/RustCrypto/traits/pull/95 + +## 0.8.1 (2019-06-30) + +## 0.8.0 (2018-10-01) + +## 0.7.6 (2018-09-21) + +## 0.7.5 (2018-07-13) + +## 0.7.4 (2018-06-21) + +## 0.7.3 (2018-06-20) + +## 0.7.2 (2017-11-17) + +## 0.7.1 (2017-11-15) + +## 0.7.0 (2017-11-14) + +## 0.6.2 (2017-07-24) + +## 0.6.1 (2017-06-18) + +## 0.6.0 (2017-06-12) + +## 0.5.2 (2017-05-02) + +## 0.5.1 (2017-05-02) + +## 0.5.0 (2017-04-06) + +## 0.4.0 (2016-12-24) + +## 0.3.1 (2016-12-16) + +## 0.3.0 (2016-11-17) + +## 0.2.1 (2016-10-14) + +## 0.2.0 (2016-10-14) + +## 0.1.0 (2016-10-06) diff --git a/vendor/digest/Cargo.toml b/vendor/digest/Cargo.toml index d363007695..83c818ce6c 100644 --- a/vendor/digest/Cargo.toml +++ b/vendor/digest/Cargo.toml @@ -11,26 +11,28 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "digest" -version = "0.8.1" +version = "0.9.0" authors = ["RustCrypto Developers"] description = "Traits for cryptographic hash functions" documentation = "https://docs.rs/digest" +readme = "README.md" keywords = ["digest", "crypto", "hash"] categories = ["cryptography", "no-std"] license = "MIT OR Apache-2.0" repository = "https://github.com/RustCrypto/traits" [package.metadata.docs.rs] -features = ["std"] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] [dependencies.blobby] version = "0.1" optional = true [dependencies.generic-array] -version = "0.12" +version = "0.14" [features] +alloc = [] dev = ["blobby"] -std = [] -[badges.travis-ci] -repository = "RustCrypto/traits" +std = ["alloc"] diff --git a/vendor/digest/README.md b/vendor/digest/README.md new file mode 100644 index 0000000000..e68638771e --- /dev/null +++ b/vendor/digest/README.md @@ -0,0 +1,161 @@ +# RustCrypto: Digest Algorithm Traits + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Build Status][build-image]][build-link] + +Traits which describe functionality of [cryptographic hash functions][0], a.k.a. +digest algorithms. + +See [RustCrypto/hashes][1] for implementations which use this trait. + +[Documentation][docs-link] + +## Minimum Supported Rust Version + +Rust **1.41** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## Usage + +Let us demonstrate how to use crates in this repository using BLAKE2b as an +example. + +First add `blake2` crate to your `Cargo.toml`: + +```toml +[dependencies] +blake2 = "0.8" +``` + +`blake2` and other crates re-export `digest` crate and `Digest` trait for +convenience, so you don't have to add `digest` crate as an explicit dependency. + +Now you can write the following code: + +```rust +use blake2::{Blake2b, Digest}; + +let mut hasher = Blake2b::new(); +let data = b"Hello world!"; +hasher.input(data); +// `input` can be called repeatedly and is generic over `AsRef<[u8]>` +hasher.input("String data"); +// Note that calling `finalize()` consumes hasher +let hash = hasher.finalize(); +println!("Result: {:x}", hash); +``` + +In this example `hash` has type [`GenericArray`][2], which is a generic +alternative to `[u8; 64]`. + +Alternatively you can use chained approach, which is equivalent to the previous +example: + +```rust +let hash = Blake2b::new() + .chain(b"Hello world!") + .chain("String data") + .finalize(); + +println!("Result: {:x}", hash); +``` + +If the whole message is available you also can use convinience `digest` method: + +```rust +let hash = Blake2b::digest(b"my message"); +println!("Result: {:x}", hash); +``` + +### Hashing `Read`-able objects + +If you want to hash data from [`Read`][3] trait (e.g. from file) you can rely on +implementation of [`Write`][4] trait (requires enabled-by-default `std` feature): + +```rust +use blake2::{Blake2b, Digest}; +use std::{fs, io}; + +let mut file = fs::File::open(&path)?; +let mut hasher = Blake2b::new(); +let n = io::copy(&mut file, &mut hasher)?; +let hash = hasher.finalize(); + +println!("Path: {}", path); +println!("Bytes processed: {}", n); +println!("Hash value: {:x}", hash); +``` + +### Generic code + +You can write generic code over `Digest` (or other traits from `digest` crate) +trait which will work over different hash functions: + +```rust +use digest::Digest; + +// Toy example, do not use it in practice! +// Instead use crates from: https://github.com/RustCrypto/password-hashing +fn hash_password(password: &str, salt: &str, output: &mut [u8]) { + let mut hasher = D::new(); + hasher.input(password.as_bytes()); + hasher.input(b"$"); + hasher.input(salt.as_bytes()); + output.copy_from_slice(hasher.finalize().as_slice()) +} + +use blake2::Blake2b; +use sha2::Sha256; + +hash_password::("my_password", "abcd", &mut buf); +hash_password::("my_password", "abcd", &mut buf); +``` + +If you want to use hash functions with trait objects, use `digest::DynDigest` +trait. + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/digest.svg +[crate-link]: https://crates.io/crates/digest +[docs-image]: https://docs.rs/digest/badge.svg +[docs-link]: https://docs.rs/digest/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[build-image]: https://github.com/RustCrypto/traits/workflows/digest/badge.svg?branch=master&event=push +[build-link]: https://github.com/RustCrypto/traits/actions?query=workflow%3Adigest + +[//]: # (general links) + +[0]: https://en.wikipedia.org/wiki/Cryptographic_hash_function +[1]: https://github.com/RustCrypto/hashes +[2]: https://docs.rs/generic-array +[3]: https://doc.rust-lang.org/std/io/trait.Read.html +[4]: https://doc.rust-lang.org/std/io/trait.Write.html +[5]: https://en.wikipedia.org/wiki/Hash-based_message_authentication_code +[6]: https://github.com/RustCrypto/MACs diff --git a/vendor/digest/src/dev.rs b/vendor/digest/src/dev.rs index e9950ee799..c205cab439 100644 --- a/vendor/digest/src/dev.rs +++ b/vendor/digest/src/dev.rs @@ -1,50 +1,59 @@ -use super::{Input, VariableOutput, ExtendableOutput, Reset, XofReader}; +//! Development-related functionality + +pub use blobby; + +use super::{ExtendableOutput, Reset, Update, VariableOutput, XofReader}; use core::fmt::Debug; +/// Define test #[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! new_test { ($name:ident, $test_name:expr, $hasher:ty, $test_func:ident) => { #[test] fn $name() { - use digest::blobby::Blob2Iterator; + use digest::dev::blobby::Blob2Iterator; let data = include_bytes!(concat!("data/", $test_name, ".blb")); for (i, row) in Blob2Iterator::new(data).unwrap().enumerate() { let input = row[0]; let output = row[1]; if let Some(desc) = $test_func::<$hasher>(input, output) { - panic!("\n\ - Failed test №{}: {}\n\ - input:\t{:?}\n\ - output:\t{:?}\n", + panic!( + "\n\ + Failed test №{}: {}\n\ + input:\t{:?}\n\ + output:\t{:?}\n", i, desc, input, output, ); } } } - } + }; } -// module to separate Digest from other traits +/// Module to separate Digest from other traits mod foo { use super::super::Digest; use core::fmt::Debug; + /// Digest test pub fn digest_test(input: &[u8], output: &[u8]) -> Option<&'static str> - where D: Digest + Debug + Clone + where + D: Digest + Debug + Clone, { let mut hasher = D::new(); // Test that it works when accepting the message all at once - hasher.input(input); + hasher.update(input); let mut hasher2 = hasher.clone(); - if hasher.result().as_slice() != output { + if hasher.finalize().as_slice() != output { return Some("whole message"); } // Test if reset works correctly hasher2.reset(); - hasher2.input(input); - if hasher2.result().as_slice() != output { + hasher2.update(input); + if hasher2.finalize().as_slice() != output { return Some("whole message after reset"); } @@ -54,66 +63,72 @@ mod foo { let mut left = len; while left > 0 { let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; + hasher.update(&input[len - left..take + len - left]); + left -= take; } - if hasher.result().as_slice() != output { + if hasher.finalize().as_slice() != output { return Some("message in pieces"); } // Test processing byte-by-byte let mut hasher = D::new(); for chunk in input.chunks(1) { - hasher.input(chunk) + hasher.update(chunk) } - if hasher.result().as_slice() != output { + if hasher.finalize().as_slice() != output { return Some("message byte-by-byte"); } None } - + /// Compute digest of one million `a` bytes pub fn one_million_a(expected: &[u8]) - where D: Digest + Debug + Clone + where + D: Digest + Debug + Clone, { let mut sh = D::new(); for _ in 0..50_000 { - sh.input(&[b'a'; 10]); + sh.update(&[b'a'; 10]); } - sh.input(&[b'a'; 500_000][..]); - let out = sh.result(); + sh.update(&[b'a'; 500_000][..]); + let out = sh.finalize(); assert_eq!(out[..], expected[..]); } } pub use self::foo::{digest_test, one_million_a}; -pub fn xof_test(input: &[u8], output: &[u8]) - -> Option<&'static str> - where D: Input + ExtendableOutput + Default + Debug + Reset + Clone +/// XOF test +pub fn xof_test(input: &[u8], output: &[u8]) -> Option<&'static str> +where + D: Update + ExtendableOutput + Default + Debug + Reset + Clone, { let mut hasher = D::default(); let mut buf = [0u8; 1024]; // Test that it works when accepting the message all at once - hasher.input(input); + hasher.update(input); let mut hasher2 = hasher.clone(); { let out = &mut buf[..output.len()]; - hasher.xof_result().read(out); + hasher.finalize_xof().read(out); - if out != output { return Some("whole message"); } + if out != output { + return Some("whole message"); + } } // Test if hasher resets correctly hasher2.reset(); - hasher2.input(input); + hasher2.update(input); { let out = &mut buf[..output.len()]; - hasher2.xof_result().read(out); + hasher2.finalize_xof().read(out); - if out != output { return Some("whole message after reset"); } + if out != output { + return Some("whole message after reset"); + } } // Test if hasher accepts message in pieces correctly @@ -122,48 +137,57 @@ pub fn xof_test(input: &[u8], output: &[u8]) let mut left = len; while left > 0 { let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; + hasher.update(&input[len - left..take + len - left]); + left -= take; } { let out = &mut buf[..output.len()]; - hasher.xof_result().read(out); - if out != output { return Some("message in pieces"); } + hasher.finalize_xof().read(out); + if out != output { + return Some("message in pieces"); + } } // Test reading from reader byte by byte let mut hasher = D::default(); - hasher.input(input); + hasher.update(input); - let mut reader = hasher.xof_result(); + let mut reader = hasher.finalize_xof(); let out = &mut buf[..output.len()]; for chunk in out.chunks_mut(1) { reader.read(chunk); } - if out != output { return Some("message in pieces"); } + if out != output { + return Some("message in pieces"); + } None } -pub fn variable_test(input: &[u8], output: &[u8]) - -> Option<&'static str> - where D: Input + VariableOutput + Reset + Debug + Clone +/// Variable-output digest test +pub fn variable_test(input: &[u8], output: &[u8]) -> Option<&'static str> +where + D: Update + VariableOutput + Reset + Debug + Clone, { let mut hasher = D::new(output.len()).unwrap(); let mut buf = [0u8; 128]; let buf = &mut buf[..output.len()]; // Test that it works when accepting the message all at once - hasher.input(input); + hasher.update(input); let mut hasher2 = hasher.clone(); - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("whole message"); } + hasher.finalize_variable(|res| buf.copy_from_slice(res)); + if buf != output { + return Some("whole message"); + } // Test if reset works correctly hasher2.reset(); - hasher2.input(input); - hasher2.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("whole message after reset"); } + hasher2.update(input); + hasher2.finalize_variable(|res| buf.copy_from_slice(res)); + if buf != output { + return Some("whole message after reset"); + } // Test that it works when accepting the message in pieces let mut hasher = D::new(output.len()).unwrap(); @@ -171,24 +195,29 @@ pub fn variable_test(input: &[u8], output: &[u8]) let mut left = len; while left > 0 { let take = (left + 1) / 2; - hasher.input(&input[len - left..take + len - left]); - left = left - take; + hasher.update(&input[len - left..take + len - left]); + left -= take; + } + hasher.finalize_variable(|res| buf.copy_from_slice(res)); + if buf != output { + return Some("message in pieces"); } - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("message in pieces"); } // Test processing byte-by-byte let mut hasher = D::new(output.len()).unwrap(); for chunk in input.chunks(1) { - hasher.input(chunk) + hasher.update(chunk) + } + hasher.finalize_variable(|res| buf.copy_from_slice(res)); + if buf != output { + return Some("message byte-by-byte"); } - hasher.variable_result(|res| buf.copy_from_slice(res)); - if buf != output { return Some("message byte-by-byte"); } None } - +/// Define benchmark #[macro_export] +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] macro_rules! bench { ($name:ident, $engine:path, $bs:expr) => { #[bench] @@ -197,7 +226,7 @@ macro_rules! bench { let data = [0; $bs]; b.iter(|| { - d.input(&data[..]); + d.update(&data[..]); }); b.bytes = $bs; @@ -207,12 +236,12 @@ macro_rules! bench { ($engine:path) => { extern crate test; - use test::Bencher; use digest::Digest; + use test::Bencher; - bench!(bench1_10, $engine, 10); - bench!(bench2_100, $engine, 100); - bench!(bench3_1000, $engine, 1000); - bench!(bench4_10000, $engine, 10000); - } + $crate::bench!(bench1_10, $engine, 10); + $crate::bench!(bench2_100, $engine, 100); + $crate::bench!(bench3_1000, $engine, 1000); + $crate::bench!(bench4_10000, $engine, 10000); + }; } diff --git a/vendor/digest/src/digest.rs b/vendor/digest/src/digest.rs index 50128e13ec..ef72951d8b 100644 --- a/vendor/digest/src/digest.rs +++ b/vendor/digest/src/digest.rs @@ -1,32 +1,36 @@ -use super::{Input, FixedOutput, Reset}; -use generic_array::{GenericArray, ArrayLength}; +use super::{FixedOutput, Reset, Update}; use generic_array::typenum::Unsigned; +use generic_array::{ArrayLength, GenericArray}; /// The `Digest` trait specifies an interface common for digest functions. /// -/// It's a convenience wrapper around `Input`, `FixedOutput`, `Reset`, `Clone`, -/// and `Default` traits. It also provides additional convenience methods. +/// It's a convenience wrapper around [`Update`], [`FixedOutput`], [`Reset`], +/// [`Clone`], and [`Default`] traits. It also provides additional convenience methods. pub trait Digest { + /// Output size for `Digest` type OutputSize: ArrayLength; + /// Create new hasher instance fn new() -> Self; - /// Digest input data. + /// Digest data, updating the internal state. /// /// This method can be called repeatedly for use with streaming messages. - fn input>(&mut self, data: B); + fn update(&mut self, data: impl AsRef<[u8]>); /// Digest input data in a chained manner. - fn chain>(self, data: B) -> Self where Self: Sized; + fn chain(self, data: impl AsRef<[u8]>) -> Self + where + Self: Sized; /// Retrieve result and consume hasher instance. - fn result(self) -> GenericArray; + fn finalize(self) -> Output; /// Retrieve result and reset hasher instance. /// /// This method sometimes can be more efficient compared to hasher /// re-creation. - fn result_reset(&mut self) -> GenericArray; + fn finalize_reset(&mut self) -> Output; /// Reset hasher instance to its initial state. fn reset(&mut self); @@ -42,30 +46,33 @@ pub trait Digest { /// ```rust,ignore /// println!("{:x}", sha2::Sha256::digest(b"Hello world")); /// ``` - fn digest(data: &[u8]) -> GenericArray; + fn digest(data: &[u8]) -> Output; } -impl Digest for D { +impl Digest for D { type OutputSize = ::OutputSize; fn new() -> Self { Self::default() } - fn input>(&mut self, data: B) { - Input::input(self, data); + fn update(&mut self, data: impl AsRef<[u8]>) { + Update::update(self, data); } - fn chain>(self, data: B) -> Self where Self: Sized { - Input::chain(self, data) + fn chain(self, data: impl AsRef<[u8]>) -> Self + where + Self: Sized, + { + Update::chain(self, data) } - fn result(self) -> GenericArray { - self.fixed_result() + fn finalize(self) -> Output { + self.finalize_fixed() } - fn result_reset(&mut self) -> GenericArray { - let res = self.clone().fixed_result(); + fn finalize_reset(&mut self) -> Output { + let res = self.clone().finalize_fixed(); self.reset(); res } @@ -78,9 +85,12 @@ impl Digest for D { Self::OutputSize::to_usize() } - fn digest(data: &[u8]) -> GenericArray { + fn digest(data: &[u8]) -> Output { let mut hasher = Self::default(); - Input::input(&mut hasher, data); - hasher.fixed_result() + Update::update(&mut hasher, data); + hasher.finalize_fixed() } } + +/// Output of a [`Digest`] function +pub type Output = GenericArray::OutputSize>; diff --git a/vendor/digest/src/dyn_digest.rs b/vendor/digest/src/dyn_digest.rs index 2af43a8e3d..156f9bdbff 100644 --- a/vendor/digest/src/dyn_digest.rs +++ b/vendor/digest/src/dyn_digest.rs @@ -1,22 +1,23 @@ -#![cfg(feature = "std")] -use std::boxed::Box; +#![cfg(feature = "alloc")] +use alloc::boxed::Box; -use super::{Input, FixedOutput, Reset}; +use super::{FixedOutput, Reset, Update}; use generic_array::typenum::Unsigned; /// The `DynDigest` trait is a modification of `Digest` trait suitable /// for trait objects. +#[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] pub trait DynDigest { /// Digest input data. /// /// This method can be called repeatedly for use with streaming messages. - fn input(&mut self, data: &[u8]); + fn update(&mut self, data: &[u8]); /// Retrieve result and reset hasher instance - fn result_reset(&mut self) -> Box<[u8]>; + fn finalize_reset(&mut self) -> Box<[u8]>; /// Retrieve result and consume boxed hasher instance - fn result(self: Box) -> Box<[u8]>; + fn finalize(self: Box) -> Box<[u8]>; /// Reset hasher instance to its initial state. fn reset(&mut self); @@ -25,22 +26,22 @@ pub trait DynDigest { fn output_size(&self) -> usize; /// Clone hasher state into a boxed trait object - fn box_clone(&self) -> Box; + fn box_clone(&self) -> Box; } -impl DynDigest for D { - fn input(&mut self, data: &[u8]) { - Input::input(self, data); +impl DynDigest for D { + fn update(&mut self, data: &[u8]) { + Update::update(self, data); } - fn result_reset(&mut self) -> Box<[u8]> { - let res = self.clone().fixed_result().to_vec().into_boxed_slice(); + fn finalize_reset(&mut self) -> Box<[u8]> { + let res = self.finalize_fixed_reset().to_vec().into_boxed_slice(); Reset::reset(self); res } - fn result(self: Box) -> Box<[u8]> { - self.fixed_result().to_vec().into_boxed_slice() + fn finalize(self: Box) -> Box<[u8]> { + self.finalize_fixed().to_vec().into_boxed_slice() } fn reset(&mut self) { @@ -51,12 +52,12 @@ impl DynDigest for D { ::OutputSize::to_usize() } - fn box_clone(&self) -> Box { + fn box_clone(&self) -> Box { Box::new(self.clone()) } } -impl Clone for Box { +impl Clone for Box { fn clone(&self) -> Self { self.box_clone() } diff --git a/vendor/digest/src/errors.rs b/vendor/digest/src/errors.rs index aa026a21a1..6071e456b0 100644 --- a/vendor/digest/src/errors.rs +++ b/vendor/digest/src/errors.rs @@ -1,20 +1,14 @@ use core::fmt; -#[cfg(feature = "std")] -use std::error; /// The error type for variable hasher initialization #[derive(Clone, Copy, Debug, Default)] pub struct InvalidOutputSize; impl fmt::Display for InvalidOutputSize { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("invalid output size") } } #[cfg(feature = "std")] -impl error::Error for InvalidOutputSize { - fn description(&self) -> &str { - "invalid output size" - } -} +impl std::error::Error for InvalidOutputSize {} diff --git a/vendor/digest/src/fixed.rs b/vendor/digest/src/fixed.rs new file mode 100644 index 0000000000..432a6c42cf --- /dev/null +++ b/vendor/digest/src/fixed.rs @@ -0,0 +1,71 @@ +//! Fixed-size output digest support + +use crate::Reset; +use generic_array::{ArrayLength, GenericArray}; + +/// Trait for returning digest result with the fixed size +pub trait FixedOutput { + /// Output size for fixed output digest + type OutputSize: ArrayLength; + + /// Write result into provided array and consume the hasher instance. + fn finalize_into(self, out: &mut GenericArray); + + /// Write result into provided array and reset the hasher instance. + fn finalize_into_reset(&mut self, out: &mut GenericArray); + + /// Retrieve result and consume the hasher instance. + #[inline] + fn finalize_fixed(self) -> GenericArray + where + Self: Sized, + { + let mut out = Default::default(); + self.finalize_into(&mut out); + out + } + + /// Retrieve result and reset the hasher instance. + #[inline] + fn finalize_fixed_reset(&mut self) -> GenericArray { + let mut out = Default::default(); + self.finalize_into_reset(&mut out); + out + } +} + +/// Trait for fixed-output digest implementations to use to retrieve the +/// hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`FixedOutput::finalize_fixed`] or [`FixedOutput::finalize_fixed_reset`] +/// methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`FixedOutput`]. +pub trait FixedOutputDirty { + /// Output size for fixed output digest + type OutputSize: ArrayLength; + + /// Retrieve result into provided buffer and leave hasher in a dirty state. + /// + /// This method is expected to only be called once unless + /// [`Reset::reset`] is called, after which point it can be + /// called again and reset again (and so on). + fn finalize_into_dirty(&mut self, out: &mut GenericArray); +} + +impl FixedOutput for D { + type OutputSize = D::OutputSize; + + #[inline] + fn finalize_into(mut self, out: &mut GenericArray) { + self.finalize_into_dirty(out); + } + + #[inline] + fn finalize_into_reset(&mut self, out: &mut GenericArray) { + self.finalize_into_dirty(out); + self.reset(); + } +} diff --git a/vendor/digest/src/lib.rs b/vendor/digest/src/lib.rs index f03c501076..b049a694d8 100644 --- a/vendor/digest/src/lib.rs +++ b/vendor/digest/src/lib.rs @@ -1,51 +1,77 @@ //! This crate provides traits which describe functionality of cryptographic hash //! functions. //! -//! Traits in this repository can be separated into two levels: -//! - Low level traits: `Input`, `BlockInput`, `Reset`, `FixedOutput`, -//! `VariableOutput`, `ExtendableOutput`. These traits atomically describe -//! available functionality of hash function implementations. -//! - Convenience trait: `Digest`, `DynDigest`. They are wrappers around -//! low level traits for most common hash-function use-cases. +//! Traits in this repository are organized into high-level convenience traits, +//! mid-level traits which expose more fine-grained functionality, and +//! low-level traits intended to only be used by algorithm implementations: //! -//! Additionally hash functions implement traits from `std`: `Default`, `Clone`, -//! `Write`. (the latter depends on enabled-by-default `std` crate feature) +//! - **High-level convenience traits**: [`Digest`], [`DynDigest`]. They are wrappers +//! around lower-level traits for most common hash-function use-cases. +//! - **Mid-level traits**: [`Update`], [`BlockInput`], [`Reset`], [`FixedOutput`], +//! [`VariableOutput`], [`ExtendableOutput`]. These traits atomically describe +//! available functionality of hash function implementations. +//! - **Low-level traits**: [`FixedOutputDirty`], [`VariableOutputDirty`], +//! [`ExtendableOutputDirty`]. These traits are intended to be implemented by +//! low-level algorithm providers only and simplify the amount of work +//! implementers need to do and therefore shouldn't be used in +//! application-level code. //! -//! The `Digest` trait is the most commonly used trait. +//! Additionally hash functions implement traits from the standard library: +//! `Default`, `Clone`, `Write`. The latter is feature-gated behind `std` feature, +//! which is usually enabled by default by hash implementation crates. +//! +//! The [`Digest`] trait is the most commonly used trait. + #![no_std] -#![doc(html_logo_url = - "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] -pub extern crate generic_array; +#![cfg_attr(docsrs, feature(doc_cfg))] +#![forbid(unsafe_code)] +#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] +#![warn(missing_docs, rust_2018_idioms)] + +#[cfg(feature = "alloc")] +#[macro_use] +extern crate alloc; + #[cfg(feature = "std")] -#[macro_use] extern crate std; +extern crate std; + #[cfg(feature = "dev")] -pub extern crate blobby; -use generic_array::{GenericArray, ArrayLength}; -#[cfg(feature = "std")] -use std::vec::Vec; +#[cfg_attr(docsrs, doc(cfg(feature = "dev")))] +pub mod dev; mod digest; mod dyn_digest; mod errors; -#[cfg(feature = "dev")] -pub mod dev; +mod fixed; +mod variable; +mod xof; -pub use errors::InvalidOutputSize; -pub use digest::Digest; -#[cfg(feature = "std")] +pub use crate::digest::{Digest, Output}; +pub use crate::errors::InvalidOutputSize; +pub use crate::fixed::{FixedOutput, FixedOutputDirty}; +pub use crate::variable::{VariableOutput, VariableOutputDirty}; +pub use crate::xof::{ExtendableOutput, ExtendableOutputDirty, XofReader}; +pub use generic_array::{self, typenum::consts}; + +#[cfg(feature = "alloc")] pub use dyn_digest::DynDigest; -/// Trait for processing input data -pub trait Input { +use generic_array::ArrayLength; + +/// Trait for updating digest state with input data. +pub trait Update { /// Digest input data. /// /// This method can be called repeatedly, e.g. for processing streaming /// messages. - fn input>(&mut self, data: B); + fn update(&mut self, data: impl AsRef<[u8]>); /// Digest input data in a chained manner. - fn chain>(mut self, data: B) -> Self where Self: Sized { - self.input(data); + fn chain(mut self, data: impl AsRef<[u8]>) -> Self + where + Self: Sized, + { + self.update(data); self } } @@ -55,67 +81,10 @@ pub trait Input { /// /// The main usage of this trait is for implementing HMAC generically. pub trait BlockInput { + /// Block size type BlockSize: ArrayLength; } -/// Trait for returning digest result with the fixed size -pub trait FixedOutput { - type OutputSize: ArrayLength; - - /// Retrieve result and consume hasher instance. - fn fixed_result(self) -> GenericArray; -} - -/// Trait for returning digest result with the variable size -pub trait VariableOutput: core::marker::Sized { - /// Create new hasher instance with the given output size. - /// - /// It will return `Err(InvalidOutputSize)` in case if hasher can not return - /// specified output size. It will always return an error if output size - /// equals to zero. - fn new(output_size: usize) -> Result; - - /// Get output size of the hasher instance provided to the `new` method - fn output_size(&self) -> usize; - - /// Retrieve result via closure and consume hasher. - /// - /// Closure is guaranteed to be called, length of the buffer passed to it - /// will be equal to `output_size`. - fn variable_result(self, f: F); - - /// Retrieve result into vector and consume hasher. - #[cfg(feature = "std")] - fn vec_result(self) -> Vec { - let mut buf = Vec::with_capacity(self.output_size()); - self.variable_result(|res| buf.extend_from_slice(res)); - buf - } -} - -/// Trait for describing readers which are used to extract extendable output -/// from XOF (extendable-output function) result. -pub trait XofReader { - /// Read output into the `buffer`. Can be called unlimited number of times. - fn read(&mut self, buffer: &mut [u8]); -} - -/// Trait which describes extendable-output functions (XOF). -pub trait ExtendableOutput: core::marker::Sized { - type Reader: XofReader; - - /// Retrieve XOF reader and consume hasher instance. - fn xof_result(self) -> Self::Reader; - - /// Retrieve result into vector of specified length. - #[cfg(feature = "std")] - fn vec_result(self, n: usize) -> Vec { - let mut buf = vec![0u8; n]; - self.xof_result().read(&mut buf); - buf - } -} - /// Trait for resetting hash instances pub trait Reset { /// Reset hasher instance to its initial state and return current state. @@ -123,19 +92,19 @@ pub trait Reset { } #[macro_export] -/// Implements `std::io::Write` trait for implementer of `Input` +/// Implements `std::io::Write` trait for implementer of [`Update`] macro_rules! impl_write { ($hasher:ident) => { #[cfg(feature = "std")] - impl ::std::io::Write for $hasher { - fn write(&mut self, buf: &[u8]) -> ::std::io::Result { - Input::input(self, buf); + impl std::io::Write for $hasher { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + Update::update(self, buf); Ok(buf.len()) } - fn flush(&mut self) -> ::std::io::Result<()> { + fn flush(&mut self) -> std::io::Result<()> { Ok(()) } } - } + }; } diff --git a/vendor/digest/src/variable.rs b/vendor/digest/src/variable.rs new file mode 100644 index 0000000000..7f444931ff --- /dev/null +++ b/vendor/digest/src/variable.rs @@ -0,0 +1,106 @@ +//! Variable-sized output digest support + +use crate::{InvalidOutputSize, Reset}; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Trait for returning digest result with the variable size +pub trait VariableOutput: Sized { + /// Create new hasher instance with the given output size. + /// + /// It will return `Err(InvalidOutputSize)` in case if hasher can not return + /// specified output size. It will always return an error if output size + /// equals to zero. + fn new(output_size: usize) -> Result; + + /// Get output size of the hasher instance provided to the `new` method + fn output_size(&self) -> usize; + + /// Retrieve result via closure and consume hasher. + /// + /// Closure is guaranteed to be called, length of the buffer passed to it + /// will be equal to `output_size`. + fn finalize_variable(self, f: impl FnOnce(&[u8])); + + /// Retrieve result via closure and reset the hasher state. + /// + /// Closure is guaranteed to be called, length of the buffer passed to it + /// will be equal to `output_size`. + fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])); + + /// Retrieve result into a boxed slice and consume hasher. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed(self) -> Box<[u8]> { + let n = self.output_size(); + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_variable(|res| buf.copy_from_slice(res)); + buf + } + + /// Retrieve result into a boxed slice and reset hasher state. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed_reset(&mut self) -> Box<[u8]> { + let n = self.output_size(); + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_variable_reset(|res| buf.copy_from_slice(res)); + buf + } +} + +/// Trait for variable-sized output digest implementations to use to retrieve +/// the hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`VariableOutput::finalize_variable`] or +/// [`VariableOutput::finalize_variable_reset`] methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`VariableOutput`]. +pub trait VariableOutputDirty: Sized { + /// Create new hasher instance with the given output size. + /// + /// It will return `Err(InvalidOutputSize)` in case if hasher can not return + /// specified output size. It will always return an error if output size + /// equals to zero. + fn new(output_size: usize) -> Result; + + /// Get output size of the hasher instance provided to the `new` method + fn output_size(&self) -> usize; + + /// Retrieve result into provided buffer and leave hasher in a dirty state. + /// + /// This method is expected to only be called once unless + /// [`Reset::reset`] is called, after which point it can be + /// called again and reset again (and so on). + fn finalize_variable_dirty(&mut self, f: impl FnOnce(&[u8])); +} + +impl VariableOutput for D { + fn new(output_size: usize) -> Result { + ::new(output_size) + } + + fn output_size(&self) -> usize { + ::output_size(self) + } + + #[inline] + fn finalize_variable(mut self, f: impl FnOnce(&[u8])) { + self.finalize_variable_dirty(f); + } + + #[inline] + fn finalize_variable_reset(&mut self, f: impl FnOnce(&[u8])) { + self.finalize_variable_dirty(f); + self.reset(); + } +} diff --git a/vendor/digest/src/xof.rs b/vendor/digest/src/xof.rs new file mode 100644 index 0000000000..0a41833b0c --- /dev/null +++ b/vendor/digest/src/xof.rs @@ -0,0 +1,102 @@ +//! Extendable-Output Function (XOF) support + +use crate::Reset; + +#[cfg(feature = "alloc")] +use alloc::boxed::Box; + +/// Trait for describing readers which are used to extract extendable output +/// from XOF (extendable-output function) result. +pub trait XofReader { + /// Read output into the `buffer`. Can be called an unlimited number of times. + fn read(&mut self, buffer: &mut [u8]); + + /// Read output into a boxed slice of the specified size. + /// + /// Can be called an unlimited number of times in combination with `read`. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn read_boxed(&mut self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.read(&mut buf); + buf + } +} + +/// Trait which describes extendable-output functions (XOF). +pub trait ExtendableOutput: Sized { + /// Reader + type Reader: XofReader; + + /// Retrieve XOF reader and consume hasher instance. + fn finalize_xof(self) -> Self::Reader; + + /// Retrieve XOF reader and reset hasher instance state. + fn finalize_xof_reset(&mut self) -> Self::Reader; + + /// Retrieve result into a boxed slice of the specified size and consume + /// the hasher. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed(self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_xof().read(&mut buf); + buf + } + + /// Retrieve result into a boxed slice of the specified size and reset + /// the hasher's state. + /// + /// `Box<[u8]>` is used instead of `Vec` to save stack space, since + /// they have size of 2 and 3 words respectively. + #[cfg(feature = "alloc")] + #[cfg_attr(docsrs, doc(cfg(feature = "alloc")))] + fn finalize_boxed_reset(&mut self, n: usize) -> Box<[u8]> { + let mut buf = vec![0u8; n].into_boxed_slice(); + self.finalize_xof_reset().read(&mut buf); + buf + } +} + +/// Trait for extendable-output function (XOF) implementations to use to +/// retrieve the hash output. +/// +/// Usage of this trait in user code is discouraged. Instead use the +/// [`ExtendableOutput::finalize_xof`] or +/// [`ExtendableOutput::finalize_xof_reset`] methods. +/// +/// Types which impl this trait along with [`Reset`] will receive a blanket +/// impl of [`ExtendableOutput`]. +pub trait ExtendableOutputDirty: Sized { + /// Reader + type Reader: XofReader; + + /// Retrieve XOF reader. + /// + /// This method is expected to only be called once unless + /// [`Reset::reset`] is called, after which point it can be + /// called again and reset again (and so on). + fn finalize_xof_dirty(&mut self) -> Self::Reader; +} + +impl ExtendableOutput for X { + type Reader = X::Reader; + + #[inline] + fn finalize_xof(mut self) -> Self::Reader { + self.finalize_xof_dirty() + } + + #[inline] + fn finalize_xof_reset(&mut self) -> Self::Reader { + let reader = self.finalize_xof_dirty(); + self.reset(); + reader + } +} diff --git a/vendor/expect-test/.cargo-checksum.json b/vendor/expect-test/.cargo-checksum.json index 94abf0aaa0..a647d9b4be 100644 --- a/vendor/expect-test/.cargo-checksum.json +++ b/vendor/expect-test/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"2d0741c78cbf44d9df22433e83b0b4202edddb70bc0ad36da295e474817ff242","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"1c299480321bd07dcae24086bd1a5ff1a13ed6d0f855a0d962bf362ecb532b79","src/lib.rs":"35e6a84e7b8e911dbb2b5febfda296524d8227cf7159c53b772714557fbfbaaa"},"package":"a3e383741ea1982866572109d1a8c807bd36aad91fca701489fdca56ef92b3b8"} \ No newline at end of file +{"files":{"Cargo.toml":"5c0bf7c6a2323d45f0557fb2bd81a11426e8be3b570a7ad076a5c6f76a1af09e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5a67ee6ca778c7280704bf08cbdd197edb798ab69ee79841037fde2248400814","src/lib.rs":"0802f71f4439ba9ce1b472e6053691350457f26dbf30d21d1749deb64ffdadd4"},"package":"ceb96f3eaa0d4e8769c52dacfd4eb60183b817ed2f176171b3c691d5022b0f2e"} \ No newline at end of file diff --git a/vendor/expect-test/Cargo.toml b/vendor/expect-test/Cargo.toml index 3c0b6cc6cc..f73029d7bc 100644 --- a/vendor/expect-test/Cargo.toml +++ b/vendor/expect-test/Cargo.toml @@ -13,12 +13,14 @@ [package] edition = "2018" name = "expect-test" -version = "0.1.0" +version = "1.0.1" authors = ["rust-analyzer developers"] -exclude = [".github/", "bors.toml"] -description = "A minimal snapshot testing library" +exclude = [".github/", "bors.toml", "rustfmt.toml"] +description = "Minimalistic snapshot testing library" +keywords = ["snapshot", "testing", "expect"] +categories = ["development-tools::testing"] license = "MIT OR Apache-2.0" -repository = "https://github.com/rust-analyzer/rust-analyzer" +repository = "https://github.com/rust-analyzer/expect-test" [dependencies.difference] version = "2" diff --git a/vendor/expect-test/README.md b/vendor/expect-test/README.md index 734f57f7b3..90a4bc9d1a 100644 --- a/vendor/expect-test/README.md +++ b/vendor/expect-test/README.md @@ -1,3 +1,3 @@ -# expect_test +# expect-test Minimalistic snapshot testing for Rust. diff --git a/vendor/expect-test/src/lib.rs b/vendor/expect-test/src/lib.rs index d58f2ae11f..07f9dd6704 100644 --- a/vendor/expect-test/src/lib.rs +++ b/vendor/expect-test/src/lib.rs @@ -13,8 +13,8 @@ //! ```no_run //! use expect_test::expect; //! -//! let expected = expect![["5"]]; //! let actual = 2 + 2; +//! let expected = expect![["5"]]; //! expected.assert_eq(&actual.to_string()) //! ``` //! @@ -72,11 +72,11 @@ //! use expect_test::expect_file; //! //! let actual = 42; -//! let expected = expect_file!["the-answer.txt"]; +//! let expected = expect_file!["./the-answer.txt"]; //! expected.assert_eq(&actual.to_string()); //! ``` //! -//! File path is relative to the root of the Cargo workspace. +//! File path is relative to the current file. //! //! # Suggested Workflows //! @@ -105,7 +105,7 @@ //! Each test's body is a single call to `check`. All the variation in tests //! comes from the input data. //! -//! When writing new test, I usually copy-paste and old one, leave the `expect` +//! When writing a new test, I usually copy-paste an old one, leave the `expect` //! blank and use `UPDATE_EXPECT` to fill the value for me: //! //! ``` @@ -120,6 +120,21 @@ //! See //! https://blog.janestreet.com/using-ascii-waveforms-to-test-hardware-designs/ //! for a cool example of snapshot testing in the wild! +//! +//! # Alternatives +//! +//! * [insta](https://crates.io/crates/insta) -- a more feature full snapshot +//! testing library. +//! * [k9](https://crates.io/crates/k9) -- testing library which includes +//! support for snapshot testing among other things. +//! +//! # Maintenance status +//! +//! The main customer of this library is rust-analyzer. The library is expected +//! to be relatively stable, but, if the need arises, it could be significantly +//! reworked to fit rust-analyzer better. +//! +//! MSRV: latest stable. use std::{ collections::HashMap, env, fmt, fs, mem, @@ -167,16 +182,17 @@ macro_rules! expect { [[]] => { $crate::expect![[""]] }; } -/// Creates an instance of `ExpectFile` from workspace-relative path: +/// Creates an instance of `ExpectFile` from relative or absolute path: /// /// ``` /// # use expect_test::expect_file; -/// expect_file!["/crates/foo/test_data/bar.html"]; +/// expect_file!["./test_data/bar.html"]; /// ``` #[macro_export] macro_rules! expect_file { [$path:expr] => {$crate::ExpectFile { - path: std::path::PathBuf::from($path) + path: std::path::PathBuf::from($path), + position: file!(), }}; } @@ -194,6 +210,8 @@ pub struct Expect { pub struct ExpectFile { #[doc(hidden)] pub path: PathBuf, + #[doc(hidden)] + pub position: &'static str, } /// Position of original `expect!` in the source file. @@ -278,7 +296,8 @@ impl ExpectFile { fs::write(self.abs_path(), contents).unwrap() } fn abs_path(&self) -> PathBuf { - WORKSPACE_ROOT.join(&self.path) + let dir = Path::new(self.position).parent().unwrap(); + WORKSPACE_ROOT.join(dir).join(&self.path) } } @@ -302,7 +321,6 @@ impl Runtime { } rt.panic(expect.position.to_string(), expected, actual); } - fn fail_file(expect: &ExpectFile, expected: &str, actual: &str) { let mut rt = RT.lock().unwrap_or_else(|poisoned| poisoned.into_inner()); if update_expect() { @@ -312,7 +330,6 @@ impl Runtime { } rt.panic(expect.path.display().to_string(), expected, actual); } - fn panic(&mut self, position: String, expected: &str, actual: &str) { let print_help = !mem::replace(&mut self.help_printed, true); let help = if print_help { HELP } else { "" }; @@ -543,4 +560,9 @@ mod tests { "#]] .assert_debug_eq(&patchwork); } + + #[test] + fn test_expect_file() { + expect_file!["./lib.rs"].assert_eq(include_str!("./lib.rs")) + } } diff --git a/vendor/fs-err/.cargo-checksum.json b/vendor/fs-err/.cargo-checksum.json new file mode 100644 index 0000000000..7975f71f1f --- /dev/null +++ b/vendor/fs-err/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"4309b9e2bad51a76be93951a205a9410a641488a2094b7e0d081a8c854d40814","Cargo.toml":"cc8b8da949a2ff953b49c8d9a6c5fe63d51f290c9138ab6f3cb50846c612675e","LICENSE-APACHE":"7cfd738c53d61c79f07e348f622bf7707c9084237054d37fbe07788a75f5881c","LICENSE-MIT":"36516aefdc84c5d5a1e7485425913a22dbda69eb1930c5e84d6ae4972b5194b9","README.md":"e5c3355cb080a50bade0664df1f853e3f041121a9aa5bda2074ce6e01e210437","README.tpl":"de2f4fa16d473b928004aed4e11bd70522690961c6e34094a07fc68e9a092426","src/dir.rs":"1fbc8a3ada7e5e8a8c15dc0bf0e3c94cbeeea26e4a5f2b411c62d93adc023ebb","src/errors.rs":"a6a381326d6c0406409d6dc2dafa5f7c0e7f84e0ec304d234ad90c313c74d798","src/file.rs":"13463b9da1cd61dc4bee7a7a5d0e8e020b6d562a72395d66354b4ce956cfd17b","src/lib.rs":"38ff1b0362e9c2fcd741245126b08588183e5f98afd79ff6220bcc2b5eecf00b","tests/version-numbers.rs":"370467b40ce930d655389ba82015ae2842b3361bf24280c3dc7214d3ac163a2d"},"package":"c1a51f8b7158efbe531f7baa74e38e49fbc41239e5d66720bb37ed39c27c241a"} \ No newline at end of file diff --git a/vendor/fs-err/CHANGELOG.md b/vendor/fs-err/CHANGELOG.md new file mode 100644 index 0000000000..39743116a8 --- /dev/null +++ b/vendor/fs-err/CHANGELOG.md @@ -0,0 +1,33 @@ +# fs-err Changelog + +## 2.3.0 +* Added `create_dir` and `create_dir_all`. ([#19](https://github.com/andrewhickman/fs-err/pull/19)) +* Added `remove_file`, `remove_dir`, and `remove_dir_all`. ([#16](https://github.com/andrewhickman/fs-err/pull/16)) + +## 2.2.0 +* Added `metadata`. ([#15](https://github.com/andrewhickman/fs-err/pull/15)) + +## 2.1.0 +* Updated crate-level documentation. ([#8](https://github.com/andrewhickman/fs-err/pull/8)) +* Added `read_dir`, `ReadDir`, and `DirEntry`. ([#9](https://github.com/andrewhickman/fs-err/pull/9)) + +## 2.0.1 (2020-02-22) +* Added `copy`. ([#7](https://github.com/andrewhickman/fs-err/pull/7)) + +## 2.0.0 (2020-02-19) +* Removed custom error type in favor of `std::io::Error`. ([#2](https://github.com/andrewhickman/fs-err/pull/2)) + +## 1.0.1 (2020-02-15) +* Fixed bad documentation link in `Cargo.toml`. + +## 1.0.0 (2020-02-15) +* No changes from 0.1.2. + +## 0.1.2 (2020-02-10) +* Added `Error::cause` implementation for `fs_err::Error`. + +## 0.1.1 (2020-02-05) +* Added wrappers for `std::fs::*` functions. + +## 0.1.0 (2020-02-02) +* Initial release, containing a wrapper around `std::fs::File`. diff --git a/vendor/fs-err/Cargo.toml b/vendor/fs-err/Cargo.toml new file mode 100644 index 0000000000..c911b14e97 --- /dev/null +++ b/vendor/fs-err/Cargo.toml @@ -0,0 +1,30 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "fs-err" +version = "2.3.0" +authors = ["Andrew Hickman "] +description = "A drop-in replacement for std::fs with more helpful error messages." +documentation = "https://docs.rs/fs-err" +readme = "README.md" +categories = ["command-line-interface", "filesystem"] +license = "MIT/Apache-2.0" +repository = "https://github.com/andrewhickman/fs-err" + +[dependencies] +[dev-dependencies.serde_json] +version = "1.0.48" + +[dev-dependencies.version-sync] +version = "0.8.1" diff --git a/vendor/fs-err/LICENSE-APACHE b/vendor/fs-err/LICENSE-APACHE new file mode 100644 index 0000000000..f47c941141 --- /dev/null +++ b/vendor/fs-err/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/fs-err/LICENSE-MIT b/vendor/fs-err/LICENSE-MIT new file mode 100644 index 0000000000..458723b374 --- /dev/null +++ b/vendor/fs-err/LICENSE-MIT @@ -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 --git a/vendor/fs-err/README.md b/vendor/fs-err/README.md new file mode 100644 index 0000000000..70bf1fa440 --- /dev/null +++ b/vendor/fs-err/README.md @@ -0,0 +1,88 @@ + + +# fs-err + +[![Crates.io](https://img.shields.io/crates/v/fs-err.svg)](https://crates.io/crates/fs-err) +[![GitHub Actions](https://github.com/andrewhickman/fs-err/workflows/CI/badge.svg)](https://github.com/andrewhickman/fs-err/actions?query=workflow%3ACI) + +fs-err is a drop-in replacement for [`std::fs`][std::fs] that provides more +helpful messages on errors. Extra information includes which operations was +attmpted and any involved paths. + +## Error Messages + +Using [`std::fs`][std::fs], if this code fails: + +```rust +let file = File::open("does not exist.txt")?; +``` + +The error message that Rust gives you isn't very useful: + +```txt +The system cannot find the file specified. (os error 2) +``` + +...but if we use fs-err instead, our error contains more actionable information: + +```txt +failed to open file `does not exist.txt` + caused by: The system cannot find the file specified. (os error 2) +``` + +## Usage + +fs-err's API is the same as [`std::fs`][std::fs], so migrating code to use it is easy. + +```rust +// use std::fs; +use fs_err as fs; + +let contents = fs::read_to_string("foo.txt")?; + +println!("Read foo.txt: {}", contents); + +``` + +fs-err uses [`std::io::Error`][std::io::Error] for all errors. This helps fs-err +compose well with traits from the standard library like +[`std::io::Read`][std::io::Read] and crates that use them like +[`serde_json`][serde_json]: + +```rust +use fs_err::File; + +let file = File::open("my-config.json")?; + +// If an I/O error occurs inside serde_json, the error will include a file path +// as well as what operation was being performed. +let decoded: Vec = serde_json::from_reader(file)?; + +println!("Program config: {:?}", decoded); + +``` + +[std::fs]: https://doc.rust-lang.org/stable/std/fs/ +[std::io::Error]: https://doc.rust-lang.org/stable/std/io/struct.Error.html +[std::io::Read]: https://doc.rust-lang.org/stable/std/io/trait.Read.html +[serde_json]: https://crates.io/crates/serde_json + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/vendor/fs-err/README.tpl b/vendor/fs-err/README.tpl new file mode 100644 index 0000000000..35ac8052d8 --- /dev/null +++ b/vendor/fs-err/README.tpl @@ -0,0 +1,28 @@ + + +# {{crate}} + +[![Crates.io](https://img.shields.io/crates/v/fs-err.svg)](https://crates.io/crates/fs-err) +[![GitHub Actions](https://github.com/andrewhickman/fs-err/workflows/CI/badge.svg)](https://github.com/andrewhickman/fs-err/actions?query=workflow%3ACI) + +{{readme}} + +## License + +Licensed under either of + +* Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or https://www.apache.org/licenses/LICENSE-2.0) +* MIT license ([LICENSE-MIT](LICENSE-MIT) or https://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. \ No newline at end of file diff --git a/vendor/fs-err/src/dir.rs b/vendor/fs-err/src/dir.rs new file mode 100644 index 0000000000..adba643b9c --- /dev/null +++ b/vendor/fs-err/src/dir.rs @@ -0,0 +1,85 @@ +use std::ffi::OsString; +use std::fs; +use std::io; +use std::path::PathBuf; + +use crate::errors::{Error, ErrorKind}; + +/// Wrapper for [`fs::read_dir`](https://doc.rust-lang.org/stable/std/fs/fn.read_dir.html). +pub fn read_dir>(path: P) -> io::Result { + let path = path.into(); + + match fs::read_dir(&path) { + Ok(inner) => Ok(ReadDir { inner, path }), + Err(source) => Err(Error::new(source, ErrorKind::ReadDir, path)), + } +} + +/// Wrapper around [`std::fs::ReadDir`][std::fs::ReadDir] which adds more +/// helpful information to all errors. +/// +/// This struct is created via [`fs_err::read_dir`][fs_err::read_dir]. +/// +/// [std::fs::ReadDir]: https://doc.rust-lang.org/stable/std/fs/struct.ReadDir.html +/// [fs_err::read_dir]: fn.read_dir.html +#[derive(Debug)] +pub struct ReadDir { + inner: fs::ReadDir, + path: PathBuf, +} + +impl Iterator for ReadDir { + type Item = io::Result; + + fn next(&mut self) -> Option { + Some(self.inner.next()?.map(|inner| DirEntry { inner })) + } +} + +/// Wrapper around [`std::fs::DirEntry`][std::fs::DirEntry] which adds more +/// helpful information to all errors. +/// +/// [std::fs::DirEntry]: https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html +#[derive(Debug)] +pub struct DirEntry { + inner: fs::DirEntry, +} + +impl DirEntry { + /// Wrapper for [`DirEntry::path`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.path). + pub fn path(&self) -> PathBuf { + self.inner.path() + } + + /// Wrapper for [`DirEntry::metadata`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.metadata). + pub fn metadata(&self) -> io::Result { + self.inner + .metadata() + .map_err(|source| Error::new(source, ErrorKind::Metadata, self.path())) + } + + /// Wrapper for [`DirEntry::file_type`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.file_type). + pub fn file_type(&self) -> io::Result { + self.inner + .file_type() + .map_err(|source| Error::new(source, ErrorKind::Metadata, self.path())) + } + + /// Wrapper for [`DirEntry::file_name`](https://doc.rust-lang.org/stable/std/fs/struct.DirEntry.html#method.file_name). + pub fn file_name(&self) -> OsString { + self.inner.file_name() + } +} + +#[cfg(unix)] +mod unix { + use std::os::unix::fs::DirEntryExt; + + use super::*; + + impl DirEntryExt for DirEntry { + fn ino(&self) -> u64 { + self.inner.ino() + } + } +} diff --git a/vendor/fs-err/src/errors.rs b/vendor/fs-err/src/errors.rs new file mode 100644 index 0000000000..37e0f80366 --- /dev/null +++ b/vendor/fs-err/src/errors.rs @@ -0,0 +1,125 @@ +use std::error::Error as StdError; +use std::fmt; +use std::io; +use std::path::PathBuf; + +#[derive(Debug, Clone, Copy)] +pub(crate) enum ErrorKind { + OpenFile, + CreateFile, + CreateDir, + SyncFile, + SetLen, + Metadata, + Clone, + SetPermissions, + Read, + Seek, + Write, + Flush, + ReadDir, + RemoveFile, + RemoveDir, +} + +/// Contains an IO error that has a file path attached. +/// +/// This type is never returned directly, but is instead wrapped inside yet +/// another IO error. +#[derive(Debug)] +pub(crate) struct Error { + kind: ErrorKind, + source: io::Error, + path: PathBuf, +} + +impl Error { + pub fn new>(source: io::Error, kind: ErrorKind, path: P) -> io::Error { + io::Error::new( + source.kind(), + Self { + kind, + source, + path: path.into(), + }, + ) + } +} + +impl fmt::Display for Error { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + use ErrorKind::*; + + let path = self.path.display(); + + match self.kind { + OpenFile => write!(formatter, "failed to open file `{}`", path), + CreateFile => write!(formatter, "failed to create file `{}`", path), + CreateDir => write!(formatter, "failed to create directory `{}`", path), + SyncFile => write!(formatter, "failed to sync file `{}`", path), + SetLen => write!(formatter, "failed to set length of file `{}`", path), + Metadata => write!(formatter, "failed to query metadata of file `{}`", path), + Clone => write!(formatter, "failed to clone handle for file `{}`", path), + SetPermissions => write!(formatter, "failed to set permissions for file `{}`", path), + Read => write!(formatter, "failed to read from file `{}`", path), + Seek => write!(formatter, "failed to seek in file `{}`", path), + Write => write!(formatter, "failed to write to file `{}`", path), + Flush => write!(formatter, "failed to flush file `{}`", path), + ReadDir => write!(formatter, "failed to read directory `{}`", path), + RemoveFile => write!(formatter, "failed to remove file `{}`", path), + RemoveDir => write!(formatter, "failed to remove directory `{}`", path), + } + } +} + +impl StdError for Error { + fn cause(&self) -> Option<&dyn StdError> { + self.source() + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.source) + } +} + +/// Error type used by `fs::copy` that holds two paths. +#[derive(Debug)] +pub(crate) struct CopyError { + source: io::Error, + from_path: PathBuf, + to_path: PathBuf, +} + +impl CopyError { + pub fn new, Q: Into>(source: io::Error, from: P, to: Q) -> io::Error { + io::Error::new( + source.kind(), + Self { + source, + from_path: from.into(), + to_path: to.into(), + }, + ) + } +} + +impl fmt::Display for CopyError { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + write!( + formatter, + "failed to copy file from {} to {}", + self.from_path.display(), + self.to_path.display() + ) + } +} + +impl StdError for CopyError { + fn cause(&self) -> Option<&dyn StdError> { + self.source() + } + + fn source(&self) -> Option<&(dyn StdError + 'static)> { + Some(&self.source) + } +} diff --git a/vendor/fs-err/src/file.rs b/vendor/fs-err/src/file.rs new file mode 100644 index 0000000000..3a839ab7c7 --- /dev/null +++ b/vendor/fs-err/src/file.rs @@ -0,0 +1,217 @@ +use std::fs; +use std::io::{self, Read, Seek, Write}; +use std::path::{Path, PathBuf}; + +use crate::errors::{Error, ErrorKind}; + +/// Wrapper around [`std::fs::File`][std::fs::File] which adds more helpful +/// information to all errors. +/// +/// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html +#[derive(Debug)] +pub struct File { + file: fs::File, + path: PathBuf, +} + +/// Wrappers for methods from [`std::fs::File`][std::fs::File]. +/// +/// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html +impl File { + /// Wrapper for [`File::open`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.open). + pub fn open

    (path: P) -> Result + where + P: AsRef + Into, + { + match fs::File::open(path.as_ref()) { + Ok(file) => Ok(File::from_parts(file, path.into())), + Err(source) => Err(Error::new(source, ErrorKind::OpenFile, path)), + } + } + + /// Wrapper for [`File::create`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.create). + pub fn create

    (path: P) -> Result + where + P: AsRef + Into, + { + match fs::File::create(path.as_ref()) { + Ok(file) => Ok(File::from_parts(file, path.into())), + Err(source) => Err(Error::new(source, ErrorKind::CreateFile, path)), + } + } + + /// Wrapper for [`OpenOptions::open`](https://doc.rust-lang.org/stable/std/fs/struct.OpenOptions.html#method.open). + pub fn from_options

    (path: P, options: &fs::OpenOptions) -> Result + where + P: AsRef + Into, + { + match options.open(path.as_ref()) { + Ok(file) => Ok(File::from_parts(file, path.into())), + Err(source) => Err(Error::new(source, ErrorKind::OpenFile, path)), + } + } + + /// Wrapper for [`File::sync_all`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.sync_all). + pub fn sync_all(&self) -> Result<(), io::Error> { + self.file + .sync_all() + .map_err(|source| self.error(source, ErrorKind::SyncFile)) + } + + /// Wrapper for [`File::sync_data`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.sync_data). + pub fn sync_data(&self) -> Result<(), io::Error> { + self.file + .sync_data() + .map_err(|source| self.error(source, ErrorKind::SyncFile)) + } + + /// Wrapper for [`File::set_len`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.set_len). + pub fn set_len(&self, size: u64) -> Result<(), io::Error> { + self.file + .set_len(size) + .map_err(|source| self.error(source, ErrorKind::SetLen)) + } + + /// Wrapper for [`File::metadata`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.metadata). + pub fn metadata(&self) -> Result { + self.file + .metadata() + .map_err(|source| self.error(source, ErrorKind::Metadata)) + } + + /// Wrapper for [`File::try_clone`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.try_clone). + pub fn try_clone(&self) -> Result { + self.file + .try_clone() + .map(|file| File { + file, + path: self.path.clone(), + }) + .map_err(|source| self.error(source, ErrorKind::Clone)) + } + + /// Wrapper for [`File::set_permissions`](https://doc.rust-lang.org/stable/std/fs/struct.File.html#method.set_permissions). + pub fn set_permissions(&self, perm: fs::Permissions) -> Result<(), io::Error> { + self.file + .set_permissions(perm) + .map_err(|source| self.error(source, ErrorKind::SetPermissions)) + } + + /// Creates a [`File`](struct.File.html) from a raw file and its path. + pub fn from_parts

    (file: fs::File, path: P) -> Self + where + P: Into, + { + File { + file, + path: path.into(), + } + } +} + +/// Methods added by fs-err that are not available on +/// [`std::fs::File`][std::fs::File]. +/// +/// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html +impl File { + /// Returns a reference to the underlying [`std::fs::File`][std::fs::File]. + /// + /// [std::fs::File]: https://doc.rust-lang.org/stable/std/fs/struct.File.html + pub fn file(&self) -> &fs::File { + &self.file + } + + /// Returns a reference to the path that this file was created with. + pub fn path(&self) -> &Path { + &self.path + } + + /// Wrap the error in information specific to this `File` object. + fn error(&self, source: io::Error, kind: ErrorKind) -> io::Error { + Error::new(source, kind, &self.path) + } +} + +impl Read for File { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + self.file + .read(buf) + .map_err(|source| self.error(source, ErrorKind::Read)) + } + + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { + self.file + .read_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Read)) + } +} + +impl<'a> Read for &'a File { + fn read(&mut self, buf: &mut [u8]) -> std::io::Result { + (&(**self).file) + .read(buf) + .map_err(|source| self.error(source, ErrorKind::Read)) + } + + fn read_vectored(&mut self, bufs: &mut [std::io::IoSliceMut<'_>]) -> std::io::Result { + (&(**self).file) + .read_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Read)) + } +} + +impl Seek for File { + fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { + self.file + .seek(pos) + .map_err(|source| self.error(source, ErrorKind::Seek)) + } +} + +impl<'a> Seek for &'a File { + fn seek(&mut self, pos: std::io::SeekFrom) -> std::io::Result { + (&(**self).file) + .seek(pos) + .map_err(|source| self.error(source, ErrorKind::Seek)) + } +} + +impl Write for File { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + self.file + .write(buf) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + self.file + .write_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn flush(&mut self) -> std::io::Result<()> { + self.file + .flush() + .map_err(|source| self.error(source, ErrorKind::Flush)) + } +} + +impl<'a> Write for &'a File { + fn write(&mut self, buf: &[u8]) -> std::io::Result { + (&(**self).file) + .write(buf) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn write_vectored(&mut self, bufs: &[std::io::IoSlice<'_>]) -> std::io::Result { + (&(**self).file) + .write_vectored(bufs) + .map_err(|source| self.error(source, ErrorKind::Write)) + } + + fn flush(&mut self) -> std::io::Result<()> { + (&(**self).file) + .flush() + .map_err(|source| self.error(source, ErrorKind::Flush)) + } +} diff --git a/vendor/fs-err/src/lib.rs b/vendor/fs-err/src/lib.rs new file mode 100644 index 0000000000..96cba8c768 --- /dev/null +++ b/vendor/fs-err/src/lib.rs @@ -0,0 +1,170 @@ +/*! +fs-err is a drop-in replacement for [`std::fs`][std::fs] that provides more +helpful messages on errors. Extra information includes which operations was +attmpted and any involved paths. + +# Error Messages + +Using [`std::fs`][std::fs], if this code fails: + +```no_run +# use std::fs::File; +let file = File::open("does not exist.txt")?; +# Ok::<(), std::io::Error>(()) +``` + +The error message that Rust gives you isn't very useful: + +```txt +The system cannot find the file specified. (os error 2) +``` + +...but if we use fs-err instead, our error contains more actionable information: + +```txt +failed to open file `does not exist.txt` + caused by: The system cannot find the file specified. (os error 2) +``` + +# Usage + +fs-err's API is the same as [`std::fs`][std::fs], so migrating code to use it is easy. + +```no_run +// use std::fs; +use fs_err as fs; + +let contents = fs::read_to_string("foo.txt")?; + +println!("Read foo.txt: {}", contents); + +# Ok::<(), std::io::Error>(()) +``` + +fs-err uses [`std::io::Error`][std::io::Error] for all errors. This helps fs-err +compose well with traits from the standard library like +[`std::io::Read`][std::io::Read] and crates that use them like +[`serde_json`][serde_json]: + +```no_run +use fs_err::File; + +let file = File::open("my-config.json")?; + +// If an I/O error occurs inside serde_json, the error will include a file path +// as well as what operation was being performed. +let decoded: Vec = serde_json::from_reader(file)?; + +println!("Program config: {:?}", decoded); + +# Ok::<(), Box>(()) +``` + +[std::fs]: https://doc.rust-lang.org/stable/std/fs/ +[std::io::Error]: https://doc.rust-lang.org/stable/std/io/struct.Error.html +[std::io::Read]: https://doc.rust-lang.org/stable/std/io/trait.Read.html +[serde_json]: https://crates.io/crates/serde_json +*/ + +#![doc(html_root_url = "https://docs.rs/fs-err/2.3.0")] +#![deny(missing_debug_implementations, missing_docs)] + +mod dir; +mod errors; +mod file; + +use std::fs; +use std::io::{self, Read, Write}; +use std::path::{Path, PathBuf}; + +use errors::{CopyError, Error, ErrorKind}; + +pub use dir::*; +pub use file::*; + +/// Wrapper for [`fs::read`](https://doc.rust-lang.org/stable/std/fs/fn.read.html). +pub fn read + Into>(path: P) -> io::Result> { + let mut file = File::open(path)?; + let mut bytes = Vec::with_capacity(initial_buffer_size(&file)); + file.read_to_end(&mut bytes)?; + Ok(bytes) +} + +/// Wrapper for [`fs::read_to_string`](https://doc.rust-lang.org/stable/std/fs/fn.read_to_string.html). +pub fn read_to_string + Into>(path: P) -> io::Result { + let mut file = File::open(path)?; + let mut string = String::with_capacity(initial_buffer_size(&file)); + file.read_to_string(&mut string)?; + Ok(string) +} + +/// Wrapper for [`fs::write`](https://doc.rust-lang.org/stable/std/fs/fn.write.html). +pub fn write + Into, C: AsRef<[u8]>>( + path: P, + contents: C, +) -> io::Result<()> { + File::create(path)?.write_all(contents.as_ref()) +} + +/// Wrapper for [`fs::copy`](https://doc.rust-lang.org/stable/std/fs/fn.copy.html). +pub fn copy(from: P, to: Q) -> io::Result +where + P: AsRef + Into, + Q: AsRef + Into, +{ + fs::copy(from.as_ref(), to.as_ref()).map_err(|source| CopyError::new(source, from, to)) +} + +/// Wrapper for [`fs::create_dir`](https://doc.rust-lang.org/stable/std/fs/fn.create_dir.html). +pub fn create_dir

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::create_dir(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::CreateDir, path)) +} + +/// Wrapper for [`fs::create_dir_all`](https://doc.rust-lang.org/stable/std/fs/fn.create_dir_all.html). +pub fn create_dir_all

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::create_dir_all(path.as_ref()) + .map_err(|source| Error::new(source, ErrorKind::CreateDir, path)) +} + +/// Wrapper for [`fs::remove_dir`](https://doc.rust-lang.org/stable/std/fs/fn.remove_dir.html). +pub fn remove_dir

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::remove_dir(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::RemoveDir, path)) +} + +/// Wrapper for [`fs::remove_dir_all`](https://doc.rust-lang.org/stable/std/fs/fn.remove_dir_all.html). +pub fn remove_dir_all

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::remove_dir_all(path.as_ref()) + .map_err(|source| Error::new(source, ErrorKind::RemoveDir, path)) +} + +/// Wrapper for [`fs::remove_file`](https://doc.rust-lang.org/stable/std/fs/fn.remove_file.html). +pub fn remove_file

    (path: P) -> io::Result<()> +where + P: AsRef + Into, +{ + fs::remove_file(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::RemoveFile, path)) +} + +/// Wrapper for [`fs::metadata`](https://doc.rust-lang.org/stable/std/fs/fn.metadata.html). +pub fn metadata + Into>(path: P) -> io::Result { + fs::metadata(path.as_ref()).map_err(|source| Error::new(source, ErrorKind::Metadata, path)) +} + +fn initial_buffer_size(file: &File) -> usize { + file.file() + .metadata() + .map(|m| m.len() as usize + 1) + .unwrap_or(0) +} diff --git a/vendor/fs-err/tests/version-numbers.rs b/vendor/fs-err/tests/version-numbers.rs new file mode 100644 index 0000000000..41a5ea4802 --- /dev/null +++ b/vendor/fs-err/tests/version-numbers.rs @@ -0,0 +1,9 @@ +#[test] +fn test_readme_deps() { + version_sync::assert_markdown_deps_updated!("README.md"); +} + +#[test] +fn test_html_root_url() { + version_sync::assert_html_root_url_updated!("src/lib.rs"); +} diff --git a/vendor/generic-array-0.12.3/.cargo-checksum.json b/vendor/generic-array-0.12.3/.cargo-checksum.json new file mode 100644 index 0000000000..66e17ddfc4 --- /dev/null +++ b/vendor/generic-array-0.12.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"aa938a1a7581e59cbb554b44cc2dcf628cc1af9ddee6dccd53f557ed8d62775e","Cargo.toml":"6f83fe34b8c252299c537c8f5cdb22bffb583c5676d5353ad73bef7f4d6958fc","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"aad2a8508f8ae6b009d04d388bffb751875d4cfdcc6f3398212c65cc3c390d03","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"5fee5550800b890383c1dd80e00a0a568475a8599e7678e143740c941e98099d","src/functional.rs":"2437c360c645d8a9816a3b13531f23b005d1aed3ef7b1d9bcc9b2859b1d56826","src/hex.rs":"438288cf41fad3fd40ce60eb893cd038e9a88e450bab0189fe4dba8ce833a686","src/impl_serde.rs":"2cab2f808ba000c214a3ded9f43b4d5363114fe57c2c7abf545345b8b749f0db","src/impls.rs":"0472fc62d69e3e78b3f31e340cfc038bf12c3d7c4bdcd5fee064e7113d2f171d","src/iter.rs":"156f798c82bc0d5e2c9a0a7777acc156bfdda793b64295ad7495cc5daa5ecb97","src/lib.rs":"d2f4b74c7ac8f9a9d7a782089b95315ec6b1f1571d79a2b16bd76bcff2004bd4","src/sequence.rs":"63813c9e305b6642ac29f0ba3dd70d7db86e27fc58b31e7508c68ea52c060e82","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"edf27c43ed13bf8cba2cd01de2fd7b6451c1226c8ad8331880996248e7f14d12","tests/mod.rs":"fca2966183ccd1d1681f91a845773911ab61f618bd412470612fac240ecfe0db"},"package":"c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"} \ No newline at end of file diff --git a/vendor/generic-array-0.12.3/CHANGELOG.md b/vendor/generic-array-0.12.3/CHANGELOG.md new file mode 100644 index 0000000000..f8ee86b8e6 --- /dev/null +++ b/vendor/generic-array-0.12.3/CHANGELOG.md @@ -0,0 +1,48 @@ +* **`0.12.0`** + * Allow trailing commas in `arr!` macro. + * **BREAKING**: Serialize `GenericArray` using `serde` tuples, instead of variable-length sequences. This may not be compatible with old serialized data. + +* **`0.11.0`** + * **BREAKING** Redesign `GenericSequence` with an emphasis on use in generic type parameters. + * Add `MappedGenericSequence` and `FunctionalSequence` + * Implements optimized `map`, `zip` and `fold` for `GenericArray`, `&GenericArray` and `&mut GenericArray` + * **BREAKING** Remove `map_ref`, `zip_ref` and `map_slice` + * `map_slice` is now equivalent to `GenericArray::from_iter(slice.iter().map(...))` +* **`0.10.0`** + * Add `GenericSequence`, `Lengthen`, `Shorten`, `Split` and `Concat` traits. + * Redefine `transmute` to avert errors. +* **`0.9.0`** + * Rewrite construction methods to be well-defined in panic situations, correctly dropping elements. + * `NoDrop` crate replaced by `ManuallyDrop` as it became stable in Rust core. + * Add optimized `map`/`map_ref` and `zip`/`zip_ref` methods to `GenericArray` +* **`0.8.0`** + * Implement `AsRef`, `AsMut`, `Borrow`, `BorrowMut`, `Hash` for `GenericArray` + * Update `serde` to `1.0` + * Update `typenum` + * Make macro `arr!` non-cloning + * Implement `From<[T; N]>` up to `N=32` + * Fix #45 +* **`0.7.0`** + * Upgrade `serde` to `0.9` + * Make `serde` with `no_std` + * Implement `PartialOrd`/`Ord` for `GenericArray` +* **`0.6.0`** + * Fixed #30 + * Implement `Default` for `GenericArray` + * Implement `LowerHex` and `UpperHex` for `GenericArray` + * Use `precision` formatting field in hex representation + * Add `as_slice`, `as_mut_slice` + * Remove `GenericArray::new` in favor of `Default` trait + * Add `from_slice` and `from_mut_slice` + * `no_std` and `core` for crate. +* **`0.5.0`** + * Update `serde` + * remove `no_std` feature, fixed #19 +* **`0.4.0`** + * Re-export `typenum` +* **`0.3.0`** + * Implement `IntoIter` for `GenericArray` + * Add `map` method + * Add optional `serde` (de)serialization support feature. +* **`< 0.3.0`** + * Initial implementation in late 2015 diff --git a/vendor/generic-array-0.12.3/Cargo.toml b/vendor/generic-array-0.12.3/Cargo.toml new file mode 100644 index 0000000000..14b070c0b6 --- /dev/null +++ b/vendor/generic-array-0.12.3/Cargo.toml @@ -0,0 +1,40 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "generic-array" +version = "0.12.3" +authors = ["Bartłomiej Kamiński ", "Aaron Trent "] +description = "Generic types implementing functionality of arrays" +documentation = "http://fizyk20.github.io/generic-array/generic_array/" +readme = "README.md" +keywords = ["generic", "array"] +categories = ["data-structures", "no-std"] +license = "MIT" +repository = "https://github.com/fizyk20/generic-array.git" + +[lib] +name = "generic_array" +[dependencies.serde] +version = "1.0" +optional = true +default-features = false + +[dependencies.typenum] +version = "1.10" +[dev-dependencies.bincode] +version = "1.0" + +[dev-dependencies.serde_json] +version = "1.0" +[badges.travis-ci] +repository = "fizyk20/generic-array" diff --git a/vendor/generic-array-0.12.3/LICENSE b/vendor/generic-array-0.12.3/LICENSE new file mode 100644 index 0000000000..6d318946df --- /dev/null +++ b/vendor/generic-array-0.12.3/LICENSE @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2015 Bartłomiej Kamiński + +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. \ No newline at end of file diff --git a/vendor/generic-array-0.12.3/README.md b/vendor/generic-array-0.12.3/README.md new file mode 100644 index 0000000000..64dd84faaf --- /dev/null +++ b/vendor/generic-array-0.12.3/README.md @@ -0,0 +1,34 @@ +[![Crates.io](https://img.shields.io/crates/v/generic-array.svg)](https://crates.io/crates/generic-array) +[![Build Status](https://travis-ci.org/fizyk20/generic-array.svg?branch=master)](https://travis-ci.org/fizyk20/generic-array) +# generic-array + +This crate implements generic array types for Rust. + +[Documentation](http://fizyk20.github.io/generic-array/generic_array/) + +## Usage + +The Rust arrays `[T; N]` are problematic in that they can't be used generically with respect to `N`, so for example this won't work: + +```rust +struct Foo { + data: [i32; N] +} +``` + +**generic-array** defines a new trait `ArrayLength` and a struct `GenericArray>`, which let the above be implemented as: + +```rust +struct Foo> { + data: GenericArray +} +``` + +To actually define a type implementing `ArrayLength`, you can use unsigned integer types defined in [typenum](https://github.com/paholg/typenum) crate - for example, `GenericArray` would work almost like `[T; 5]` :) + +In version 0.1.1 an `arr!` macro was introduced, allowing for creation of arrays as shown below: + +```rust +let array = arr![u32; 1, 2, 3]; +assert_eq!(array[2], 3); +``` diff --git a/vendor/generic-array-0.12.3/rustfmt.toml b/vendor/generic-array-0.12.3/rustfmt.toml new file mode 100644 index 0000000000..a46e4b2bdb --- /dev/null +++ b/vendor/generic-array-0.12.3/rustfmt.toml @@ -0,0 +1,3 @@ +reorder_imports = true +reorder_imported_names = true +use_try_shorthand = true diff --git a/vendor/generic-array-0.12.3/src/arr.rs b/vendor/generic-array-0.12.3/src/arr.rs new file mode 100644 index 0000000000..a07d129ad3 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/arr.rs @@ -0,0 +1,57 @@ +//! Implementation for `arr!` macro. + +use super::ArrayLength; +use core::ops::Add; +use typenum::U1; + +/// Helper trait for `arr!` macro +pub trait AddLength>: ArrayLength { + /// Resulting length + type Output: ArrayLength; +} + +impl AddLength for N1 +where + N1: ArrayLength + Add, + N2: ArrayLength, + >::Output: ArrayLength, +{ + type Output = >::Output; +} + +/// Helper type for `arr!` macro +pub type Inc = >::Output; + +#[doc(hidden)] +#[macro_export] +macro_rules! arr_impl { + ($T:ty; $N:ty, [$($x:expr),*], []) => ({ + unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) } + }); + ($T:ty; $N:ty, [], [$x1:expr]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], []) + ); + ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+]) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], []) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( + arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($x),+]) + ); +} + +/// Macro allowing for easy generation of Generic Arrays. +/// Example: `let test = arr![u32; 1, 2, 3];` +#[macro_export] +macro_rules! arr { + ($T:ty; $(,)*) => ({ + unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) } + }); + ($T:ty; $($x:expr),* $(,)*) => ( + arr_impl!($T; $crate::typenum::U0, [], [$($x),*]) + ); + ($($x:expr,)+) => (arr![$($x),*]); + () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") +} diff --git a/vendor/generic-array-0.12.3/src/functional.rs b/vendor/generic-array-0.12.3/src/functional.rs new file mode 100644 index 0000000000..d161a83cac --- /dev/null +++ b/vendor/generic-array-0.12.3/src/functional.rs @@ -0,0 +1,94 @@ +//! Functional programming with generic sequences +//! +//! Please see `tests/generics.rs` for examples of how to best use these in your generic functions. + +use super::ArrayLength; +use core::iter::FromIterator; +use sequence::*; + +/// Defines the relationship between one generic sequence and another, +/// for operations such as `map` and `zip`. +pub unsafe trait MappedGenericSequence: GenericSequence +where + Self::Length: ArrayLength, +{ + /// Mapped sequence type + type Mapped: GenericSequence; +} + +unsafe impl<'a, T, U, S: MappedGenericSequence> MappedGenericSequence for &'a S +where + &'a S: GenericSequence, + S: GenericSequence>::Length>, + >::Length: ArrayLength, +{ + type Mapped = >::Mapped; +} + +unsafe impl<'a, T, U, S: MappedGenericSequence> MappedGenericSequence for &'a mut S +where + &'a mut S: GenericSequence, + S: GenericSequence>::Length>, + >::Length: ArrayLength, +{ + type Mapped = >::Mapped; +} + +/// Accessor type for a mapped generic sequence +pub type MappedSequence = + <>::Mapped as GenericSequence>::Sequence; + +/// Defines functional programming methods for generic sequences +pub unsafe trait FunctionalSequence: GenericSequence { + /// Maps a `GenericSequence` to another `GenericSequence`. + /// + /// If the mapping function panics, any already initialized elements in the new sequence + /// will be dropped, AND any unused elements in the source sequence will also be dropped. + fn map(self, f: F) -> MappedSequence + where + Self: MappedGenericSequence, + Self::Length: ArrayLength, + F: FnMut(Self::Item) -> U, + { + FromIterator::from_iter(self.into_iter().map(f)) + } + + /// Combines two `GenericSequence` instances and iterates through both of them, + /// initializing a new `GenericSequence` with the result of the zipped mapping function. + /// + /// If the mapping function panics, any already initialized elements in the new sequence + /// will be dropped, AND any unused elements in the source sequences will also be dropped. + #[inline] + fn zip(self, rhs: Rhs, f: F) -> MappedSequence + where + Self: MappedGenericSequence, + Rhs: MappedGenericSequence>, + Self::Length: ArrayLength + ArrayLength, + Rhs: GenericSequence, + F: FnMut(Self::Item, Rhs::Item) -> U, + { + rhs.inverted_zip2(self, f) + } + + /// Folds (or reduces) a sequence of data into a single value. + /// + /// If the fold function panics, any unused elements will be dropped. + fn fold(self, init: U, f: F) -> U + where + F: FnMut(U, Self::Item) -> U, + { + self.into_iter().fold(init, f) + } +} + +unsafe impl<'a, T, S: GenericSequence> FunctionalSequence for &'a S +where + &'a S: GenericSequence, +{ +} + +unsafe impl<'a, T, S: GenericSequence> FunctionalSequence for &'a mut S +where + &'a mut S: GenericSequence, +{ +} diff --git a/vendor/generic-array-0.12.3/src/hex.rs b/vendor/generic-array-0.12.3/src/hex.rs new file mode 100644 index 0000000000..09a6608e37 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/hex.rs @@ -0,0 +1,102 @@ +//! Generic array are commonly used as a return value for hash digests, so +//! it's a good idea to allow to hexlify them easily. This module implements +//! `std::fmt::LowerHex` and `std::fmt::UpperHex` traits. +//! +//! Example: +//! +//! ```rust +//! # #[macro_use] +//! # extern crate generic_array; +//! # extern crate typenum; +//! # fn main() { +//! let array = arr![u8; 10, 20, 30]; +//! assert_eq!(format!("{:x}", array), "0a141e"); +//! # } +//! ``` +//! + +use {ArrayLength, GenericArray}; +use core::cmp::min; +use core::fmt; +use core::ops::Add; +use core::str; +use typenum::*; + +static LOWER_CHARS: &'static [u8] = b"0123456789abcdef"; +static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF"; + +impl> fmt::LowerHex for GenericArray +where + T: Add, + >::Output: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); + let max_hex = (max_digits >> 1) + (max_digits & 1); + + if T::to_usize() < 1024 { + // For small arrays use a stack allocated + // buffer of 2x number of bytes + let mut res = GenericArray::>::default(); + + for (i, c) in self.iter().take(max_hex).enumerate() { + res[i * 2] = LOWER_CHARS[(c >> 4) as usize]; + res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; + } + f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; + } else { + // For large array use chunks of up to 1024 bytes (2048 hex chars) + let mut buf = [0u8; 2048]; + let mut digits_left = max_digits; + + for chunk in self[..max_hex].chunks(1024) { + for (i, c) in chunk.iter().enumerate() { + buf[i * 2] = LOWER_CHARS[(c >> 4) as usize]; + buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; + } + let n = min(chunk.len() * 2, digits_left); + f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; + digits_left -= n; + } + } + Ok(()) + } +} + +impl> fmt::UpperHex for GenericArray +where + T: Add, + >::Output: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); + let max_hex = (max_digits >> 1) + (max_digits & 1); + + if T::to_usize() < 1024 { + // For small arrays use a stack allocated + // buffer of 2x number of bytes + let mut res = GenericArray::>::default(); + + for (i, c) in self.iter().take(max_hex).enumerate() { + res[i * 2] = UPPER_CHARS[(c >> 4) as usize]; + res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; + } + f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; + } else { + // For large array use chunks of up to 1024 bytes (2048 hex chars) + let mut buf = [0u8; 2048]; + let mut digits_left = max_digits; + + for chunk in self[..max_hex].chunks(1024) { + for (i, c) in chunk.iter().enumerate() { + buf[i * 2] = UPPER_CHARS[(c >> 4) as usize]; + buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; + } + let n = min(chunk.len() * 2, digits_left); + f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; + digits_left -= n; + } + } + Ok(()) + } +} diff --git a/vendor/generic-array-0.12.3/src/impl_serde.rs b/vendor/generic-array-0.12.3/src/impl_serde.rs new file mode 100644 index 0000000000..7bf20ba013 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/impl_serde.rs @@ -0,0 +1,108 @@ +//! Serde serialization/deserialization implementation + +use core::fmt; +use core::marker::PhantomData; +use serde::de::{self, SeqAccess, Visitor}; +use serde::{ser::SerializeTuple, Deserialize, Deserializer, Serialize, Serializer}; +use {ArrayLength, GenericArray}; + +impl Serialize for GenericArray +where + T: Serialize, + N: ArrayLength, +{ + #[inline] + fn serialize(&self, serializer: S) -> Result + where + S: Serializer, + { + let mut tup = serializer.serialize_tuple(N::to_usize())?; + for el in self { + tup.serialize_element(el)?; + } + + tup.end() + } +} + +struct GAVisitor { + _t: PhantomData, + _n: PhantomData, +} + +impl<'de, T, N> Visitor<'de> for GAVisitor +where + T: Deserialize<'de> + Default, + N: ArrayLength, +{ + type Value = GenericArray; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("struct GenericArray") + } + + fn visit_seq(self, mut seq: A) -> Result, A::Error> + where + A: SeqAccess<'de>, + { + let mut result = GenericArray::default(); + for i in 0..N::to_usize() { + result[i] = seq + .next_element()? + .ok_or_else(|| de::Error::invalid_length(i, &self))?; + } + Ok(result) + } +} + +impl<'de, T, N> Deserialize<'de> for GenericArray +where + T: Deserialize<'de> + Default, + N: ArrayLength, +{ + fn deserialize(deserializer: D) -> Result, D::Error> + where + D: Deserializer<'de>, + { + let visitor = GAVisitor { + _t: PhantomData, + _n: PhantomData, + }; + deserializer.deserialize_tuple(N::to_usize(), visitor) + } +} + +#[cfg(test)] +mod tests { + use super::*; + use bincode; + use typenum; + + #[test] + fn test_serialize() { + let array = GenericArray::::default(); + let serialized = bincode::serialize(&array); + assert!(serialized.is_ok()); + } + + #[test] + fn test_deserialize() { + let mut array = GenericArray::::default(); + array[0] = 1; + array[1] = 2; + let serialized = bincode::serialize(&array).unwrap(); + let deserialized = bincode::deserialize::>(&array); + assert!(deserialized.is_ok()); + let array = deserialized.unwrap(); + assert_eq!(array[0], 1); + assert_eq!(array[1], 2); + } + + #[test] + fn test_serialized_size() { + let array = GenericArray::::default(); + let size = bincode::serialized_size(&array).unwrap(); + assert_eq!(size, 1); + } + +} diff --git a/vendor/generic-array-0.12.3/src/impls.rs b/vendor/generic-array-0.12.3/src/impls.rs new file mode 100644 index 0000000000..52896dfba3 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/impls.rs @@ -0,0 +1,182 @@ +use super::{ArrayLength, GenericArray}; +use core::borrow::{Borrow, BorrowMut}; +use core::cmp::Ordering; +use core::fmt::{self, Debug}; +use core::hash::{Hash, Hasher}; +use functional::*; +use sequence::*; + +impl Default for GenericArray +where + N: ArrayLength, +{ + #[inline] + fn default() -> Self { + Self::generate(|_| T::default()) + } +} + +impl Clone for GenericArray +where + N: ArrayLength, +{ + fn clone(&self) -> GenericArray { + self.map(Clone::clone) + } +} + +impl Copy for GenericArray +where + N: ArrayLength, + N::ArrayType: Copy, +{ +} + +impl PartialEq for GenericArray +where + N: ArrayLength, +{ + fn eq(&self, other: &Self) -> bool { + **self == **other + } +} +impl Eq for GenericArray +where + N: ArrayLength, +{ +} + +impl PartialOrd for GenericArray +where + N: ArrayLength, +{ + fn partial_cmp(&self, other: &GenericArray) -> Option { + PartialOrd::partial_cmp(self.as_slice(), other.as_slice()) + } +} + +impl Ord for GenericArray +where + N: ArrayLength, +{ + fn cmp(&self, other: &GenericArray) -> Ordering { + Ord::cmp(self.as_slice(), other.as_slice()) + } +} + +impl Debug for GenericArray +where + N: ArrayLength, +{ + fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { + self[..].fmt(fmt) + } +} + +impl Borrow<[T]> for GenericArray +where + N: ArrayLength, +{ + #[inline(always)] + fn borrow(&self) -> &[T] { + &self[..] + } +} + +impl BorrowMut<[T]> for GenericArray +where + N: ArrayLength, +{ + #[inline(always)] + fn borrow_mut(&mut self) -> &mut [T] { + &mut self[..] + } +} + +impl AsRef<[T]> for GenericArray +where + N: ArrayLength, +{ + #[inline(always)] + fn as_ref(&self) -> &[T] { + &self[..] + } +} + +impl AsMut<[T]> for GenericArray +where + N: ArrayLength, +{ + #[inline(always)] + fn as_mut(&mut self) -> &mut [T] { + &mut self[..] + } +} + +impl Hash for GenericArray +where + N: ArrayLength, +{ + fn hash(&self, state: &mut H) + where + H: Hasher, + { + Hash::hash(&self[..], state) + } +} + +macro_rules! impl_from { + ($($n: expr => $ty: ty),*) => { + $( + impl From<[T; $n]> for GenericArray { + #[inline(always)] + fn from(arr: [T; $n]) -> Self { + unsafe { $crate::transmute(arr) } + } + } + + impl Into<[T; $n]> for GenericArray { + #[inline(always)] + fn into(self) -> [T; $n] { + unsafe { $crate::transmute(self) } + } + } + )* + + } +} + +impl_from! { + 1 => ::typenum::U1, + 2 => ::typenum::U2, + 3 => ::typenum::U3, + 4 => ::typenum::U4, + 5 => ::typenum::U5, + 6 => ::typenum::U6, + 7 => ::typenum::U7, + 8 => ::typenum::U8, + 9 => ::typenum::U9, + 10 => ::typenum::U10, + 11 => ::typenum::U11, + 12 => ::typenum::U12, + 13 => ::typenum::U13, + 14 => ::typenum::U14, + 15 => ::typenum::U15, + 16 => ::typenum::U16, + 17 => ::typenum::U17, + 18 => ::typenum::U18, + 19 => ::typenum::U19, + 20 => ::typenum::U20, + 21 => ::typenum::U21, + 22 => ::typenum::U22, + 23 => ::typenum::U23, + 24 => ::typenum::U24, + 25 => ::typenum::U25, + 26 => ::typenum::U26, + 27 => ::typenum::U27, + 28 => ::typenum::U28, + 29 => ::typenum::U29, + 30 => ::typenum::U30, + 31 => ::typenum::U31, + 32 => ::typenum::U32 +} diff --git a/vendor/generic-array-0.12.3/src/iter.rs b/vendor/generic-array-0.12.3/src/iter.rs new file mode 100644 index 0000000000..46f3e768d7 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/iter.rs @@ -0,0 +1,190 @@ +//! `GenericArray` iterator implementation. + +use super::{ArrayLength, GenericArray}; +use core::{cmp, ptr, fmt, mem}; +use core::mem::ManuallyDrop; + +/// An iterator that moves out of a `GenericArray` +pub struct GenericArrayIter> { + // Invariants: index <= index_back <= N + // Only values in array[index..index_back] are alive at any given time. + // Values from array[..index] and array[index_back..] are already moved/dropped. + array: ManuallyDrop>, + index: usize, + index_back: usize, +} + +#[cfg(test)] +mod test { + use super::*; + + fn send(_iter: I) {} + + #[test] + fn test_send_iter() { + send(GenericArray::from([1, 2, 3, 4]).into_iter()); + } +} + +impl GenericArrayIter +where + N: ArrayLength, +{ + /// Returns the remaining items of this iterator as a slice + #[inline] + pub fn as_slice(&self) -> &[T] { + &self.array.as_slice()[self.index..self.index_back] + } + + /// Returns the remaining items of this iterator as a mutable slice + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + &mut self.array.as_mut_slice()[self.index..self.index_back] + } +} + +impl IntoIterator for GenericArray +where + N: ArrayLength, +{ + type Item = T; + type IntoIter = GenericArrayIter; + + fn into_iter(self) -> Self::IntoIter { + GenericArrayIter { + array: ManuallyDrop::new(self), + index: 0, + index_back: N::to_usize(), + } + } +} + +// Based on work in rust-lang/rust#49000 +impl fmt::Debug for GenericArrayIter +where + N: ArrayLength, +{ + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_tuple("GenericArrayIter") + .field(&self.as_slice()) + .finish() + } +} + +impl Drop for GenericArrayIter +where + N: ArrayLength, +{ + #[inline] + fn drop(&mut self) { + // Drop values that are still alive. + for p in self.as_mut_slice() { + unsafe { + ptr::drop_in_place(p); + } + } + } +} + +// Based on work in rust-lang/rust#49000 +impl Clone for GenericArrayIter +where + N: ArrayLength, +{ + fn clone(&self) -> Self { + // This places all cloned elements at the start of the new array iterator, + // not at their original indices. + unsafe { + let mut iter = GenericArrayIter { + array: ManuallyDrop::new(mem::uninitialized()), + index: 0, + index_back: 0, + }; + + for (dst, src) in iter.array.iter_mut().zip(self.as_slice()) { + ptr::write(dst, src.clone()); + + iter.index_back += 1; + } + + iter + } + } +} + +impl Iterator for GenericArrayIter +where + N: ArrayLength, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + if self.index < self.index_back { + let p = unsafe { Some(ptr::read(self.array.get_unchecked(self.index))) }; + + self.index += 1; + + p + } else { + None + } + } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + let len = self.len(); + (len, Some(len)) + } + + #[inline] + fn count(self) -> usize { + self.len() + } + + fn nth(&mut self, n: usize) -> Option { + // First consume values prior to the nth. + let ndrop = cmp::min(n, self.len()); + + for p in &mut self.array[self.index..self.index + ndrop] { + self.index += 1; + + unsafe { + ptr::drop_in_place(p); + } + } + + self.next() + } + + fn last(mut self) -> Option { + // Note, everything else will correctly drop first as `self` leaves scope. + self.next_back() + } +} + +impl DoubleEndedIterator for GenericArrayIter +where + N: ArrayLength, +{ + fn next_back(&mut self) -> Option { + if self.index < self.index_back { + self.index_back -= 1; + + unsafe { Some(ptr::read(self.array.get_unchecked(self.index_back))) } + } else { + None + } + } +} + +impl ExactSizeIterator for GenericArrayIter +where + N: ArrayLength, +{ + fn len(&self) -> usize { + self.index_back - self.index + } +} + +// TODO: Implement `FusedIterator` and `TrustedLen` when stabilized \ No newline at end of file diff --git a/vendor/generic-array-0.12.3/src/lib.rs b/vendor/generic-array-0.12.3/src/lib.rs new file mode 100644 index 0000000000..5b95805375 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/lib.rs @@ -0,0 +1,632 @@ +//! This crate implements a structure that can be used as a generic array type.use +//! Core Rust array types `[T; N]` can't be used generically with +//! respect to `N`, so for example this: +//! +//! ```{should_fail} +//! struct Foo { +//! data: [T; N] +//! } +//! ``` +//! +//! won't work. +//! +//! **generic-array** exports a `GenericArray` type, which lets +//! the above be implemented as: +//! +//! ``` +//! # use generic_array::{ArrayLength, GenericArray}; +//! struct Foo> { +//! data: GenericArray +//! } +//! ``` +//! +//! The `ArrayLength` trait is implemented by default for +//! [unsigned integer types](../typenum/uint/index.html) from +//! [typenum](../typenum/index.html). +//! +//! For ease of use, an `arr!` macro is provided - example below: +//! +//! ``` +//! # #[macro_use] +//! # extern crate generic_array; +//! # extern crate typenum; +//! # fn main() { +//! let array = arr![u32; 1, 2, 3]; +//! assert_eq!(array[2], 3); +//! # } +//! ``` + +#![deny(missing_docs)] +#![no_std] + +#[cfg(feature = "serde")] +extern crate serde; + +#[cfg(test)] +extern crate bincode; + +pub extern crate typenum; + +mod hex; +mod impls; + +#[cfg(feature = "serde")] +pub mod impl_serde; + +use core::iter::FromIterator; +use core::marker::PhantomData; +use core::mem::ManuallyDrop; +use core::ops::{Deref, DerefMut}; +use core::{mem, ptr, slice}; +use typenum::bit::{B0, B1}; +use typenum::uint::{UInt, UTerm, Unsigned}; + +#[cfg_attr(test, macro_use)] +pub mod arr; +pub mod functional; +pub mod iter; +pub mod sequence; + +use functional::*; +pub use iter::GenericArrayIter; +use sequence::*; + +/// Trait making `GenericArray` work, marking types to be used as length of an array +pub unsafe trait ArrayLength: Unsigned { + /// Associated type representing the array type for the number + type ArrayType; +} + +unsafe impl ArrayLength for UTerm { + #[doc(hidden)] + type ArrayType = (); +} + +/// Internal type used to generate a struct of appropriate size +#[allow(dead_code)] +#[repr(C)] +#[doc(hidden)] +pub struct GenericArrayImplEven { + parent1: U, + parent2: U, + _marker: PhantomData, +} + +impl Clone for GenericArrayImplEven { + fn clone(&self) -> GenericArrayImplEven { + GenericArrayImplEven { + parent1: self.parent1.clone(), + parent2: self.parent2.clone(), + _marker: PhantomData, + } + } +} + +impl Copy for GenericArrayImplEven {} + +/// Internal type used to generate a struct of appropriate size +#[allow(dead_code)] +#[repr(C)] +#[doc(hidden)] +pub struct GenericArrayImplOdd { + parent1: U, + parent2: U, + data: T, +} + +impl Clone for GenericArrayImplOdd { + fn clone(&self) -> GenericArrayImplOdd { + GenericArrayImplOdd { + parent1: self.parent1.clone(), + parent2: self.parent2.clone(), + data: self.data.clone(), + } + } +} + +impl Copy for GenericArrayImplOdd {} + +unsafe impl> ArrayLength for UInt { + #[doc(hidden)] + type ArrayType = GenericArrayImplEven; +} + +unsafe impl> ArrayLength for UInt { + #[doc(hidden)] + type ArrayType = GenericArrayImplOdd; +} + +/// Struct representing a generic array - `GenericArray` works like [T; N] +#[allow(dead_code)] +pub struct GenericArray> { + data: U::ArrayType, +} + +unsafe impl> Send for GenericArray {} +unsafe impl> Sync for GenericArray {} + +impl Deref for GenericArray +where + N: ArrayLength, +{ + type Target = [T]; + + #[inline(always)] + fn deref(&self) -> &[T] { + unsafe { slice::from_raw_parts(self as *const Self as *const T, N::to_usize()) } + } +} + +impl DerefMut for GenericArray +where + N: ArrayLength, +{ + #[inline(always)] + fn deref_mut(&mut self) -> &mut [T] { + unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, N::to_usize()) } + } +} + +/// Creates an array one element at a time using a mutable iterator +/// you can write to with `ptr::write`. +/// +/// Incremenent the position while iterating to mark off created elements, +/// which will be dropped if `into_inner` is not called. +#[doc(hidden)] +pub struct ArrayBuilder> { + array: ManuallyDrop>, + position: usize, +} + +impl> ArrayBuilder { + #[doc(hidden)] + #[inline] + pub unsafe fn new() -> ArrayBuilder { + ArrayBuilder { + array: ManuallyDrop::new(mem::uninitialized()), + position: 0, + } + } + + /// Creates a mutable iterator for writing to the array using `ptr::write`. + /// + /// Increment the position value given as a mutable reference as you iterate + /// to mark how many elements have been created. + #[doc(hidden)] + #[inline] + pub unsafe fn iter_position(&mut self) -> (slice::IterMut, &mut usize) { + (self.array.iter_mut(), &mut self.position) + } + + /// When done writing (assuming all elements have been written to), + /// get the inner array. + #[doc(hidden)] + #[inline] + pub unsafe fn into_inner(self) -> GenericArray { + let array = ptr::read(&self.array); + + mem::forget(self); + + ManuallyDrop::into_inner(array) + } +} + +impl> Drop for ArrayBuilder { + fn drop(&mut self) { + for value in &mut self.array[..self.position] { + unsafe { + ptr::drop_in_place(value); + } + } + } +} + +/// Consumes an array. +/// +/// Increment the position while iterating and any leftover elements +/// will be dropped if position does not go to N +#[doc(hidden)] +pub struct ArrayConsumer> { + array: ManuallyDrop>, + position: usize, +} + +impl> ArrayConsumer { + #[doc(hidden)] + #[inline] + pub unsafe fn new(array: GenericArray) -> ArrayConsumer { + ArrayConsumer { + array: ManuallyDrop::new(array), + position: 0, + } + } + + /// Creates an iterator and mutable reference to the internal position + /// to keep track of consumed elements. + /// + /// Increment the position as you iterate to mark off consumed elements + #[doc(hidden)] + #[inline] + pub unsafe fn iter_position(&mut self) -> (slice::Iter, &mut usize) { + (self.array.iter(), &mut self.position) + } +} + +impl> Drop for ArrayConsumer { + fn drop(&mut self) { + for value in &mut self.array[self.position..N::to_usize()] { + unsafe { + ptr::drop_in_place(value); + } + } + } +} + +impl<'a, T: 'a, N> IntoIterator for &'a GenericArray +where + N: ArrayLength, +{ + type IntoIter = slice::Iter<'a, T>; + type Item = &'a T; + + fn into_iter(self: &'a GenericArray) -> Self::IntoIter { + self.as_slice().iter() + } +} + +impl<'a, T: 'a, N> IntoIterator for &'a mut GenericArray +where + N: ArrayLength, +{ + type IntoIter = slice::IterMut<'a, T>; + type Item = &'a mut T; + + fn into_iter(self: &'a mut GenericArray) -> Self::IntoIter { + self.as_mut_slice().iter_mut() + } +} + +impl FromIterator for GenericArray +where + N: ArrayLength, +{ + fn from_iter(iter: I) -> GenericArray + where + I: IntoIterator, + { + unsafe { + let mut destination = ArrayBuilder::new(); + + { + let (destination_iter, position) = destination.iter_position(); + + for (src, dst) in iter.into_iter().zip(destination_iter) { + ptr::write(dst, src); + + *position += 1; + } + } + + if destination.position < N::to_usize() { + from_iter_length_fail(destination.position, N::to_usize()); + } + + destination.into_inner() + } + } +} + +#[inline(never)] +#[cold] +fn from_iter_length_fail(length: usize, expected: usize) -> ! { + panic!( + "GenericArray::from_iter received {} elements but expected {}", + length, expected + ); +} + +unsafe impl GenericSequence for GenericArray +where + N: ArrayLength, + Self: IntoIterator, +{ + type Length = N; + type Sequence = Self; + + fn generate(mut f: F) -> GenericArray + where + F: FnMut(usize) -> T, + { + unsafe { + let mut destination = ArrayBuilder::new(); + + { + let (destination_iter, position) = destination.iter_position(); + + for (i, dst) in destination_iter.enumerate() { + ptr::write(dst, f(i)); + + *position += 1; + } + } + + destination.into_inner() + } + } + + #[doc(hidden)] + fn inverted_zip( + self, + lhs: GenericArray, + mut f: F, + ) -> MappedSequence, B, U> + where + GenericArray: + GenericSequence + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(B, Self::Item) -> U, + { + unsafe { + let mut left = ArrayConsumer::new(lhs); + let mut right = ArrayConsumer::new(self); + + let (left_array_iter, left_position) = left.iter_position(); + let (right_array_iter, right_position) = right.iter_position(); + + FromIterator::from_iter(left_array_iter.zip(right_array_iter).map(|(l, r)| { + let left_value = ptr::read(l); + let right_value = ptr::read(r); + + *left_position += 1; + *right_position += 1; + + f(left_value, right_value) + })) + } + } + + #[doc(hidden)] + fn inverted_zip2(self, lhs: Lhs, mut f: F) -> MappedSequence + where + Lhs: GenericSequence + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(Lhs::Item, Self::Item) -> U, + { + unsafe { + let mut right = ArrayConsumer::new(self); + + let (right_array_iter, right_position) = right.iter_position(); + + FromIterator::from_iter( + lhs.into_iter() + .zip(right_array_iter) + .map(|(left_value, r)| { + let right_value = ptr::read(r); + + *right_position += 1; + + f(left_value, right_value) + }), + ) + } + } +} + +unsafe impl MappedGenericSequence for GenericArray +where + N: ArrayLength + ArrayLength, + GenericArray: GenericSequence, +{ + type Mapped = GenericArray; +} + +unsafe impl FunctionalSequence for GenericArray +where + N: ArrayLength, + Self: GenericSequence, +{ + fn map(self, mut f: F) -> MappedSequence + where + Self::Length: ArrayLength, + Self: MappedGenericSequence, + F: FnMut(T) -> U, + { + unsafe { + let mut source = ArrayConsumer::new(self); + + let (array_iter, position) = source.iter_position(); + + FromIterator::from_iter(array_iter.map(|src| { + let value = ptr::read(src); + + *position += 1; + + f(value) + })) + } + } + + #[inline] + fn zip(self, rhs: Rhs, f: F) -> MappedSequence + where + Self: MappedGenericSequence, + Rhs: MappedGenericSequence>, + Self::Length: ArrayLength + ArrayLength, + Rhs: GenericSequence, + F: FnMut(T, Rhs::Item) -> U, + { + rhs.inverted_zip(self, f) + } + + fn fold(self, init: U, mut f: F) -> U + where + F: FnMut(U, T) -> U, + { + unsafe { + let mut source = ArrayConsumer::new(self); + + let (array_iter, position) = source.iter_position(); + + array_iter.fold(init, |acc, src| { + let value = ptr::read(src); + + *position += 1; + + f(acc, value) + }) + } + } +} + +impl GenericArray +where + N: ArrayLength, +{ + /// Extracts a slice containing the entire array. + #[inline] + pub fn as_slice(&self) -> &[T] { + self.deref() + } + + /// Extracts a mutable slice containing the entire array. + #[inline] + pub fn as_mut_slice(&mut self) -> &mut [T] { + self.deref_mut() + } + + /// Converts slice to a generic array reference with inferred length; + /// + /// Length of the slice must be equal to the length of the array. + #[inline] + pub fn from_slice(slice: &[T]) -> &GenericArray { + slice.into() + } + + /// Converts mutable slice to a mutable generic array reference + /// + /// Length of the slice must be equal to the length of the array. + #[inline] + pub fn from_mut_slice(slice: &mut [T]) -> &mut GenericArray { + slice.into() + } +} + +impl<'a, T, N: ArrayLength> From<&'a [T]> for &'a GenericArray { + /// Converts slice to a generic array reference with inferred length; + /// + /// Length of the slice must be equal to the length of the array. + #[inline] + fn from(slice: &[T]) -> &GenericArray { + assert_eq!(slice.len(), N::to_usize()); + + unsafe { &*(slice.as_ptr() as *const GenericArray) } + } +} + +impl<'a, T, N: ArrayLength> From<&'a mut [T]> for &'a mut GenericArray { + /// Converts mutable slice to a mutable generic array reference + /// + /// Length of the slice must be equal to the length of the array. + #[inline] + fn from(slice: &mut [T]) -> &mut GenericArray { + assert_eq!(slice.len(), N::to_usize()); + + unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray) } + } +} + +impl GenericArray +where + N: ArrayLength, +{ + /// Construct a `GenericArray` from a slice by cloning its content + /// + /// Length of the slice must be equal to the length of the array + #[inline] + pub fn clone_from_slice(list: &[T]) -> GenericArray { + Self::from_exact_iter(list.iter().cloned()) + .expect("Slice must be the same length as the array") + } +} + +impl GenericArray +where + N: ArrayLength, +{ + /// Creates a new `GenericArray` instance from an iterator with a known exact size. + /// + /// Returns `None` if the size is not equal to the number of elements in the `GenericArray`. + pub fn from_exact_iter(iter: I) -> Option + where + I: IntoIterator, + ::IntoIter: ExactSizeIterator, + { + let iter = iter.into_iter(); + + if iter.len() == N::to_usize() { + unsafe { + let mut destination = ArrayBuilder::new(); + + { + let (destination_iter, position) = destination.iter_position(); + + for (dst, src) in destination_iter.zip(iter.into_iter()) { + ptr::write(dst, src); + + *position += 1; + } + } + + Some(destination.into_inner()) + } + } else { + None + } + } +} + +/// A reimplementation of the `transmute` function, avoiding problems +/// when the compiler can't prove equal sizes. +#[inline] +#[doc(hidden)] +pub unsafe fn transmute(a: A) -> B { + let b = ::core::ptr::read(&a as *const A as *const B); + ::core::mem::forget(a); + b +} + +#[cfg(test)] +mod test { + // Compile with: + // cargo rustc --lib --profile test --release -- + // -C target-cpu=native -C opt-level=3 --emit asm + // and view the assembly to make sure test_assembly generates + // SIMD instructions instead of a niave loop. + + #[inline(never)] + pub fn black_box(val: T) -> T { + use core::{mem, ptr}; + + let ret = unsafe { ptr::read_volatile(&val) }; + mem::forget(val); + ret + } + + #[test] + fn test_assembly() { + use functional::*; + + let a = black_box(arr![i32; 1, 3, 5, 7]); + let b = black_box(arr![i32; 2, 4, 6, 8]); + + let c = (&a).zip(b, |l, r| l + r); + + let d = a.fold(0, |a, x| a + x); + + assert_eq!(c, arr![i32; 3, 7, 11, 15]); + + assert_eq!(d, 16); + } +} diff --git a/vendor/generic-array-0.12.3/src/sequence.rs b/vendor/generic-array-0.12.3/src/sequence.rs new file mode 100644 index 0000000000..cec6601ba3 --- /dev/null +++ b/vendor/generic-array-0.12.3/src/sequence.rs @@ -0,0 +1,320 @@ +//! Useful traits for manipulating sequences of data stored in `GenericArray`s + +use super::*; +use core::{mem, ptr}; +use core::ops::{Add, Sub}; +use typenum::operator_aliases::*; + +/// Defines some sequence with an associated length and iteration capabilities. +/// +/// This is useful for passing N-length generic arrays as generics. +pub unsafe trait GenericSequence: Sized + IntoIterator { + /// `GenericArray` associated length + type Length: ArrayLength; + + /// Concrete sequence type used in conjuction with reference implementations of `GenericSequence` + type Sequence: GenericSequence + FromIterator; + + /// Initializes a new sequence instance using the given function. + /// + /// If the generator function panics while initializing the sequence, + /// any already initialized elements will be dropped. + fn generate(f: F) -> Self::Sequence + where + F: FnMut(usize) -> T; + + #[doc(hidden)] + fn inverted_zip( + self, + lhs: GenericArray, + mut f: F, + ) -> MappedSequence, B, U> + where + GenericArray: GenericSequence + + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(B, Self::Item) -> U, + { + unsafe { + let mut left = ArrayConsumer::new(lhs); + + let (left_array_iter, left_position) = left.iter_position(); + + FromIterator::from_iter( + left_array_iter + .zip(self.into_iter()) + .map(|(l, right_value)| { + let left_value = ptr::read(l); + + *left_position += 1; + + f(left_value, right_value) + }) + ) + } + } + + #[doc(hidden)] + fn inverted_zip2(self, lhs: Lhs, mut f: F) -> MappedSequence + where + Lhs: GenericSequence + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(Lhs::Item, Self::Item) -> U, + { + FromIterator::from_iter(lhs.into_iter().zip(self.into_iter()).map(|(l, r)| f(l, r))) + } +} + +/// Accessor for `GenericSequence` item type, which is really `IntoIterator::Item` +/// +/// For deeply nested generic mapped sequence types, like shown in `tests/generics.rs`, +/// this can be useful for keeping things organized. +pub type SequenceItem = ::Item; + +unsafe impl<'a, T: 'a, S: GenericSequence> GenericSequence for &'a S +where + &'a S: IntoIterator, +{ + type Length = S::Length; + type Sequence = S::Sequence; + + #[inline] + fn generate(f: F) -> Self::Sequence + where + F: FnMut(usize) -> T, + { + S::generate(f) + } +} + +unsafe impl<'a, T: 'a, S: GenericSequence> GenericSequence for &'a mut S +where + &'a mut S: IntoIterator, +{ + type Length = S::Length; + type Sequence = S::Sequence; + + #[inline] + fn generate(f: F) -> Self::Sequence + where + F: FnMut(usize) -> T, + { + S::generate(f) + } +} + +/// Defines any `GenericSequence` which can be lengthened or extended by appending +/// or prepending an element to it. +/// +/// Any lengthened sequence can be shortened back to the original using `pop_front` or `pop_back` +pub unsafe trait Lengthen: Sized + GenericSequence { + /// `GenericSequence` that has one more element than `Self` + type Longer: Shorten; + + /// Returns a new array with the given element appended to the end of it. + /// + /// Example: + /// + /// ```ignore + /// let a = arr![i32; 1, 2, 3]; + /// + /// let b = a.append(4); + /// + /// assert_eq!(b, arr![i32; 1, 2, 3, 4]); + /// ``` + fn append(self, last: T) -> Self::Longer; + + /// Returns a new array with the given element prepended to the front of it. + /// + /// Example: + /// + /// ```ignore + /// let a = arr![i32; 1, 2, 3]; + /// + /// let b = a.prepend(4); + /// + /// assert_eq!(b, arr![i32; 4, 1, 2, 3]); + /// ``` + fn prepend(self, first: T) -> Self::Longer; +} + +/// Defines a `GenericSequence` which can be shortened by removing the first or last element from it. +/// +/// Additionally, any shortened sequence can be lengthened by +/// appending or prepending an element to it. +pub unsafe trait Shorten: Sized + GenericSequence { + /// `GenericSequence` that has one less element than `Self` + type Shorter: Lengthen; + + /// Returns a new array without the last element, and the last element. + /// + /// Example: + /// + /// ```ignore + /// let a = arr![i32; 1, 2, 3, 4]; + /// + /// let (init, last) = a.pop_back(); + /// + /// assert_eq!(init, arr![i32; 1, 2, 3]); + /// assert_eq!(last, 4); + /// ``` + fn pop_back(self) -> (Self::Shorter, T); + + /// Returns a new array without the first element, and the first element. + /// Example: + /// + /// ```ignore + /// let a = arr![i32; 1, 2, 3, 4]; + /// + /// let (head, tail) = a.pop_front(); + /// + /// assert_eq!(head, 1); + /// assert_eq!(tail, arr![i32; 2, 3, 4]); + /// ``` + fn pop_front(self) -> (T, Self::Shorter); +} + +unsafe impl> Lengthen for GenericArray +where + N: Add, + Add1: ArrayLength, + Add1: Sub, + Sub1>: ArrayLength, +{ + type Longer = GenericArray>; + + fn append(self, last: T) -> Self::Longer { + let mut longer: Self::Longer = unsafe { mem::uninitialized() }; + + unsafe { + ptr::write(longer.as_mut_ptr() as *mut _, self); + ptr::write(&mut longer[N::to_usize()], last); + } + + longer + } + + fn prepend(self, first: T) -> Self::Longer { + let mut longer: Self::Longer = unsafe { mem::uninitialized() }; + + let longer_ptr = longer.as_mut_ptr(); + + unsafe { + ptr::write(longer_ptr as *mut _, first); + ptr::write(longer_ptr.offset(1) as *mut _, self); + } + + longer + } +} + +unsafe impl> Shorten for GenericArray +where + N: Sub, + Sub1: ArrayLength, + Sub1: Add, + Add1>: ArrayLength, +{ + type Shorter = GenericArray>; + + fn pop_back(self) -> (Self::Shorter, T) { + let init_ptr = self.as_ptr(); + let last_ptr = unsafe { init_ptr.offset(Sub1::::to_usize() as isize) }; + + let init = unsafe { ptr::read(init_ptr as _) }; + let last = unsafe { ptr::read(last_ptr as _) }; + + mem::forget(self); + + (init, last) + } + + fn pop_front(self) -> (T, Self::Shorter) { + let head_ptr = self.as_ptr(); + let tail_ptr = unsafe { head_ptr.offset(1) }; + + let head = unsafe { ptr::read(head_ptr as _) }; + let tail = unsafe { ptr::read(tail_ptr as _) }; + + mem::forget(self); + + (head, tail) + } +} + +/// Defines a `GenericSequence` that can be split into two parts at a given pivot index. +pub unsafe trait Split: GenericSequence +where + K: ArrayLength, +{ + /// First part of the resulting split array + type First: GenericSequence; + /// Second part of the resulting split array + type Second: GenericSequence; + + /// Splits an array at the given index, returning the separate parts of the array. + fn split(self) -> (Self::First, Self::Second); +} + +unsafe impl Split for GenericArray +where + N: ArrayLength, + K: ArrayLength, + N: Sub, + Diff: ArrayLength, +{ + type First = GenericArray; + type Second = GenericArray>; + + fn split(self) -> (Self::First, Self::Second) { + let head_ptr = self.as_ptr(); + let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) }; + + let head = unsafe { ptr::read(head_ptr as _) }; + let tail = unsafe { ptr::read(tail_ptr as _) }; + + mem::forget(self); + + (head, tail) + } +} + +/// Defines `GenericSequence`s which can be joined together, forming a larger array. +pub unsafe trait Concat: GenericSequence +where + M: ArrayLength, +{ + /// Sequence to be concatenated with `self` + type Rest: GenericSequence; + + /// Resulting sequence formed by the concatenation. + type Output: GenericSequence; + + /// Concatenate, or join, two sequences. + fn concat(self, rest: Self::Rest) -> Self::Output; +} + +unsafe impl Concat for GenericArray +where + N: ArrayLength + Add, + M: ArrayLength, + Sum: ArrayLength, +{ + type Rest = GenericArray; + type Output = GenericArray>; + + fn concat(self, rest: Self::Rest) -> Self::Output { + let mut output: Self::Output = unsafe { mem::uninitialized() }; + + let output_ptr = output.as_mut_ptr(); + + unsafe { + ptr::write(output_ptr as *mut _, self); + ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest); + } + + output + } +} diff --git a/vendor/generic-array-0.12.3/tests/arr.rs b/vendor/generic-array-0.12.3/tests/arr.rs new file mode 100644 index 0000000000..461805a501 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/arr.rs @@ -0,0 +1,27 @@ +#[macro_use] +extern crate generic_array; +extern crate typenum; + +#[test] +fn empty_without_trailing_comma() { + let ar = arr![u8; ]; + assert_eq!(format!("{:x}", ar), ""); +} + +#[test] +fn empty_with_trailing_comma() { + let ar = arr![u8; , ]; + assert_eq!(format!("{:x}", ar), ""); +} + +#[test] +fn without_trailing_comma() { + let ar = arr![u8; 10, 20, 30]; + assert_eq!(format!("{:x}", ar), "0a141e"); +} + +#[test] +fn with_trailing_comma() { + let ar = arr![u8; 10, 20, 30, ]; + assert_eq!(format!("{:x}", ar), "0a141e"); +} diff --git a/vendor/generic-array-0.12.3/tests/generics.rs b/vendor/generic-array-0.12.3/tests/generics.rs new file mode 100644 index 0000000000..952867b386 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/generics.rs @@ -0,0 +1,98 @@ +#![recursion_limit = "128"] + +#[macro_use] +extern crate generic_array; + +use generic_array::typenum::consts::U4; + +use std::fmt::Debug; +use std::ops::Add; + +use generic_array::{GenericArray, ArrayLength}; +use generic_array::sequence::*; +use generic_array::functional::*; + +/// Example function using generics to pass N-length sequences and map them +pub fn generic_map(s: S) +where + S: FunctionalSequence, // `.map` + S::Item: Add, // `x + 1` + S: MappedGenericSequence, // `i32` -> `i32` + MappedSequence: Debug, // println! +{ + let a = s.map(|x| x + 1); + + println!("{:?}", a); +} + +/// Complex example function using generics to pass N-length sequences, zip them, and then map that result. +/// +/// If used with `GenericArray` specifically this isn't necessary +pub fn generic_sequence_zip_sum(a: A, b: B) -> i32 +where + A: FunctionalSequence, // `.zip` + B: FunctionalSequence, // `.zip` + A: MappedGenericSequence, // `i32` -> `i32` + B: MappedGenericSequence>, // `i32` -> `i32`, prove A and B can map to the same output + A::Item: Add, // `l + r` + MappedSequence: MappedGenericSequence + FunctionalSequence, // `.map` + SequenceItem>: Add, // `x + 1` + MappedSequence, i32, i32>: Debug, // `println!` + MappedSequence, i32, i32>: FunctionalSequence, // `.fold` + SequenceItem, i32, i32>>: Add // `x + a`, note the order +{ + let c = a.zip(b, |l, r| l + r).map(|x| x + 1); + + println!("{:?}", c); + + c.fold(0, |a, x| x + a) +} + +/// Super-simple fixed-length i32 `GenericArray`s +pub fn generic_array_plain_zip_sum(a: GenericArray, b: GenericArray) -> i32 { + a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) +} + +pub fn generic_array_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 +where + N: ArrayLength, +{ + a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) +} + +pub fn generic_array_same_type_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 +where + N: ArrayLength + ArrayLength<>::Output>, + T: Add, +{ + a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) +} + +/// Complex example using fully generic `GenericArray`s with the same length. +/// +/// It's mostly just the repeated `Add` traits, which would be present in other systems anyway. +pub fn generic_array_zip_sum + ArrayLength>(a: GenericArray, b: GenericArray) -> i32 +where + A: Add, + N: ArrayLength<>::Output> + + ArrayLength<<>::Output as Add>::Output>, + >::Output: Add, + <>::Output as Add>::Output: Add, +{ + a.zip(b, |l, r| l + r).map(|x| x + 1).fold(0, |a, x| x + a) +} + +#[test] +fn test_generics() { + generic_map(arr![i32; 1, 2, 3, 4]); + + assert_eq!(generic_sequence_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); + + assert_eq!(generic_array_plain_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); + + assert_eq!(generic_array_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); + + assert_eq!(generic_array_same_type_variable_length_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); + + assert_eq!(generic_array_zip_sum(arr![i32; 1, 2, 3, 4], arr![i32; 2, 3, 4, 5]), 28); +} \ No newline at end of file diff --git a/vendor/generic-array-0.12.3/tests/hex.rs b/vendor/generic-array-0.12.3/tests/hex.rs new file mode 100644 index 0000000000..0c63391a64 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/hex.rs @@ -0,0 +1,61 @@ +#[macro_use] +extern crate generic_array; +extern crate typenum; + +use generic_array::GenericArray; +use std::str::from_utf8; +use typenum::U2048; + +#[test] +fn short_lower_hex() { + let ar = arr![u8; 10, 20, 30]; + assert_eq!(format!("{:x}", ar), "0a141e"); +} + +#[test] +fn short_upper_hex() { + let ar = arr![u8; 30, 20, 10]; + assert_eq!(format!("{:X}", ar), "1E140A"); +} + +#[test] +fn long_lower_hex() { + let ar = GenericArray::::default(); + assert_eq!(format!("{:x}", ar), from_utf8(&[b'0'; 4096]).unwrap()); +} + +#[test] +fn long_lower_hex_truncated() { + let ar = GenericArray::::default(); + assert_eq!(format!("{:.3001x}", ar), from_utf8(&[b'0'; 3001]).unwrap()); +} + +#[test] +fn long_upper_hex() { + let ar = GenericArray::::default(); + assert_eq!(format!("{:X}", ar), from_utf8(&[b'0'; 4096]).unwrap()); +} + +#[test] +fn long_upper_hex_truncated() { + let ar = GenericArray::::default(); + assert_eq!(format!("{:.2777X}", ar), from_utf8(&[b'0'; 2777]).unwrap()); +} + +#[test] +fn truncated_lower_hex() { + let ar = arr![u8; 10, 20, 30, 40, 50]; + assert_eq!(format!("{:.2x}", ar), "0a"); + assert_eq!(format!("{:.3x}", ar), "0a1"); + assert_eq!(format!("{:.4x}", ar), "0a14"); +} + +#[test] +fn truncated_upper_hex() { + let ar = arr![u8; 30, 20, 10, 17, 0]; + assert_eq!(format!("{:.4X}", ar), "1E14"); + assert_eq!(format!("{:.5X}", ar), "1E140"); + assert_eq!(format!("{:.6X}", ar), "1E140A"); + assert_eq!(format!("{:.7X}", ar), "1E140A1"); + assert_eq!(format!("{:.8X}", ar), "1E140A11"); +} diff --git a/vendor/generic-array-0.12.3/tests/import_name.rs b/vendor/generic-array-0.12.3/tests/import_name.rs new file mode 100644 index 0000000000..f59f1b6c56 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/import_name.rs @@ -0,0 +1,10 @@ +#[macro_use] +extern crate generic_array as gen_arr; + +use gen_arr::typenum; + +#[test] +fn test_different_crate_name() { + let _: gen_arr::GenericArray = arr![u32; 0, 1, 2, 3]; + let _: gen_arr::GenericArray = arr![u32;]; +} diff --git a/vendor/generic-array-0.12.3/tests/iter.rs b/vendor/generic-array-0.12.3/tests/iter.rs new file mode 100644 index 0000000000..19d198cb58 --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/iter.rs @@ -0,0 +1,164 @@ +#[macro_use] +extern crate generic_array; + +use std::cell::Cell; +use std::ops::Drop; + +use generic_array::GenericArray; +use generic_array::typenum::consts::U5; + +#[test] +fn test_into_iter_as_slice() { + let array = arr![char; 'a', 'b', 'c']; + let mut into_iter = array.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &['b', 'c']); + let _ = into_iter.next().unwrap(); + let _ = into_iter.next().unwrap(); + assert_eq!(into_iter.as_slice(), &[]); +} + +#[test] +fn test_into_iter_as_mut_slice() { + let array = arr![char; 'a', 'b', 'c']; + let mut into_iter = array.into_iter(); + assert_eq!(into_iter.as_slice(), &['a', 'b', 'c']); + into_iter.as_mut_slice()[0] = 'x'; + into_iter.as_mut_slice()[1] = 'y'; + assert_eq!(into_iter.next().unwrap(), 'x'); + assert_eq!(into_iter.as_slice(), &['y', 'c']); +} + +#[test] +fn test_into_iter_debug() { + let array = arr![char; 'a', 'b', 'c']; + let into_iter = array.into_iter(); + let debug = format!("{:?}", into_iter); + assert_eq!(debug, "GenericArrayIter(['a', 'b', 'c'])"); +} + +#[test] +fn test_into_iter_clone() { + fn iter_equal>(it: I, slice: &[i32]) { + let v: Vec = it.collect(); + assert_eq!(&v[..], slice); + } + let mut it = arr![i32; 1, 2, 3].into_iter(); + iter_equal(it.clone(), &[1, 2, 3]); + assert_eq!(it.next(), Some(1)); + let mut it = it.rev(); + iter_equal(it.clone(), &[3, 2]); + assert_eq!(it.next(), Some(3)); + iter_equal(it.clone(), &[2]); + assert_eq!(it.next(), Some(2)); + iter_equal(it.clone(), &[]); + assert_eq!(it.next(), None); +} + +#[test] +fn test_into_iter_nth() { + let v = arr![i32; 0, 1, 2, 3, 4]; + for i in 0..v.len() { + assert_eq!(v.clone().into_iter().nth(i).unwrap(), v[i]); + } + assert_eq!(v.clone().into_iter().nth(v.len()), None); + + let mut iter = v.into_iter(); + assert_eq!(iter.nth(2).unwrap(), v[2]); + assert_eq!(iter.nth(1).unwrap(), v[4]); +} + +#[test] +fn test_into_iter_last() { + let v = arr![i32; 0, 1, 2, 3, 4]; + assert_eq!(v.into_iter().last().unwrap(), 4); + assert_eq!(arr![i32; 0].into_iter().last().unwrap(), 0); +} + +#[test] +fn test_into_iter_count() { + let v = arr![i32; 0, 1, 2, 3, 4]; + assert_eq!(v.clone().into_iter().count(), 5); + + let mut iter2 = v.into_iter(); + iter2.next(); + iter2.next(); + assert_eq!(iter2.count(), 3); +} + +#[test] +fn test_into_iter_flat_map() { + assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10)); +} + +#[test] +fn test_into_iter_drops() { + struct R<'a> { + i: &'a Cell, + } + + impl<'a> Drop for R<'a> { + fn drop(&mut self) { + self.i.set(self.i.get() + 1); + } + } + + fn r(i: &Cell) -> R { + R { + i: i + } + } + + fn v(i: &Cell) -> GenericArray { + arr![R; r(i), r(i), r(i), r(i), r(i)] + } + + let i = Cell::new(0); + { + v(&i).into_iter(); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + { + let mut iter = v(&i).into_iter(); + let _x = iter.next(); + assert_eq!(i.get(), 0); + assert_eq!(iter.count(), 4); + assert_eq!(i.get(), 4); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + { + let mut iter = v(&i).into_iter(); + let _x = iter.nth(2); + assert_eq!(i.get(), 2); + let _y = iter.last(); + assert_eq!(i.get(), 3); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + for (index, _x) in v(&i).into_iter().enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); + + let i = Cell::new(0); + for (index, _x) in v(&i).into_iter().rev().enumerate() { + assert_eq!(i.get(), index); + } + assert_eq!(i.get(), 5); +} + +/* +//TODO: Cover this +#[allow(dead_code)] +fn assert_covariance() { + fn into_iter<'new>(i: GenericArrayIter<&'static str, U10>) -> GenericArrayIter<&'new str, U10> { + i + } +} +*/ \ No newline at end of file diff --git a/vendor/generic-array-0.12.3/tests/mod.rs b/vendor/generic-array-0.12.3/tests/mod.rs new file mode 100644 index 0000000000..c103f417ab --- /dev/null +++ b/vendor/generic-array-0.12.3/tests/mod.rs @@ -0,0 +1,287 @@ +#![recursion_limit = "128"] +#![no_std] +#[macro_use] +extern crate generic_array; +use core::cell::Cell; +use core::ops::{Add, Drop}; +use generic_array::GenericArray; +use generic_array::functional::*; +use generic_array::sequence::*; +use generic_array::typenum::{U1, U3, U4, U97}; + +#[test] +fn test() { + let mut list97 = [0; 97]; + for i in 0..97 { + list97[i] = i as i32; + } + let l: GenericArray = GenericArray::clone_from_slice(&list97); + assert_eq!(l[0], 0); + assert_eq!(l[1], 1); + assert_eq!(l[32], 32); + assert_eq!(l[56], 56); +} + +#[test] +fn test_drop() { + #[derive(Clone)] + struct TestDrop<'a>(&'a Cell); + + impl<'a> Drop for TestDrop<'a> { + fn drop(&mut self) { + self.0.set(self.0.get() + 1); + } + } + + let drop_counter = Cell::new(0); + { + let _: GenericArray = arr![TestDrop; TestDrop(&drop_counter), + TestDrop(&drop_counter), + TestDrop(&drop_counter)]; + } + assert_eq!(drop_counter.get(), 3); +} + +#[test] +fn test_arr() { + let test: GenericArray = arr![u32; 1, 2, 3]; + assert_eq!(test[1], 2); +} + +#[test] +fn test_copy() { + let test = arr![u32; 1, 2, 3]; + let test2 = test; + // if GenericArray is not copy, this should fail as a use of a moved value + assert_eq!(test[1], 2); + assert_eq!(test2[0], 1); +} + +#[derive(Debug, PartialEq, Eq)] +struct NoClone(T); + +#[test] +fn test_from_slice() { + let arr = [1, 2, 3, 4]; + let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]); + assert_eq!(&arr[..3], gen_arr.as_slice()); + let arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)]; + let gen_arr = GenericArray::<_, U3>::from_slice(&arr[..3]); + assert_eq!(&arr[..3], gen_arr.as_slice()); +} + +#[test] +fn test_from_mut_slice() { + let mut arr = [1, 2, 3, 4]; + { + let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]); + gen_arr[2] = 10; + } + assert_eq!(arr, [1, 2, 10, 4]); + let mut arr = [NoClone(1u32), NoClone(2), NoClone(3), NoClone(4)]; + { + let gen_arr = GenericArray::<_, U3>::from_mut_slice(&mut arr[..3]); + gen_arr[2] = NoClone(10); + } + assert_eq!(arr, [NoClone(1), NoClone(2), NoClone(10), NoClone(4)]); +} + +#[test] +fn test_default() { + let arr = GenericArray::::default(); + assert_eq!(arr[0], 0); +} + +#[test] +fn test_from() { + let data = [(1, 2, 3), (4, 5, 6), (7, 8, 9)]; + let garray: GenericArray<(usize, usize, usize), U3> = data.into(); + assert_eq!(&data, garray.as_slice()); +} + +#[test] +fn test_unit_macro() { + let arr = arr![f32; 3.14]; + assert_eq!(arr[0], 3.14); +} + +#[test] +fn test_empty_macro() { + let _arr = arr![f32;]; +} + +#[test] +fn test_cmp() { + arr![u8; 0x00].cmp(&arr![u8; 0x00]); +} + +/// This test should cause a helpful compile error if uncommented. +// #[test] +// fn test_empty_macro2(){ +// let arr = arr![]; +// } +#[cfg(feature = "serde")] +mod impl_serde { + extern crate serde_json; + + use generic_array::GenericArray; + use generic_array::typenum::U6; + + #[test] + fn test_serde_implementation() { + let array: GenericArray = arr![f64; 0.0, 5.0, 3.0, 7.07192, 76.0, -9.0]; + let string = serde_json::to_string(&array).unwrap(); + assert_eq!(string, "[0.0,5.0,3.0,7.07192,76.0,-9.0]"); + + let test_array: GenericArray = serde_json::from_str(&string).unwrap(); + assert_eq!(test_array, array); + } +} + +#[test] +fn test_map() { + let b: GenericArray = GenericArray::generate(|i| i as i32 * 4).map(|x| x - 3); + + assert_eq!(b, arr![i32; -3, 1, 5, 9]); +} + +#[test] +fn test_zip() { + let a: GenericArray<_, U4> = GenericArray::generate(|i| i + 1); + let b: GenericArray<_, U4> = GenericArray::generate(|i| i as i32 * 4); + + // Uses reference and non-reference arguments + let c = (&a).zip(b, |r, l| *r as i32 + l); + + assert_eq!(c, arr![i32; 1, 6, 11, 16]); +} + +#[test] +#[should_panic] +fn test_from_iter_short() { + use core::iter::repeat; + + let a: GenericArray<_, U4> = repeat(11).take(3).collect(); + + assert_eq!(a, arr![i32; 11, 11, 11, 0]); +} + +#[test] +fn test_from_iter() { + use core::iter::{once, repeat}; + + let a: GenericArray<_, U4> = repeat(11).take(3).chain(once(0)).collect(); + + assert_eq!(a, arr![i32; 11, 11, 11, 0]); +} + +#[test] +fn test_sizes() { + #![allow(dead_code)] + use core::mem::{size_of, size_of_val}; + + #[derive(Debug, Copy, Clone)] + #[repr(C)] + #[repr(packed)] + struct Test { + t: u16, + s: u32, + r: u16, + f: u16, + o: u32, + } + + assert_eq!(size_of::(), 14); + + assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::() * 3); + assert_eq!(size_of_val(&arr![u32; 1]), size_of::() * 1); + assert_eq!(size_of_val(&arr![u64; 1, 2, 3, 4]), size_of::() * 4); + + assert_eq!(size_of::>(), size_of::() * 97); +} + +#[test] +fn test_append() { + let a = arr![i32; 1, 2, 3]; + + let b = a.append(4); + + assert_eq!(b, arr![i32; 1, 2, 3, 4]); +} + +#[test] +fn test_prepend() { + let a = arr![i32; 1, 2, 3]; + + let b = a.prepend(4); + + assert_eq!(b, arr![i32; 4, 1, 2, 3]); +} + +#[test] +fn test_pop() { + let a = arr![i32; 1, 2, 3, 4]; + + let (init, last) = a.pop_back(); + + assert_eq!(init, arr![i32; 1, 2, 3]); + assert_eq!(last, 4); + + let (head, tail) = a.pop_front(); + + assert_eq!(head, 1); + assert_eq!(tail, arr![i32; 2, 3, 4]); +} + +#[test] +fn test_split() { + let a = arr![i32; 1, 2, 3, 4]; + + let (b, c) = a.split(); + + assert_eq!(b, arr![i32; 1]); + assert_eq!(c, arr![i32; 2, 3, 4]); + + let (e, f) = a.split(); + + assert_eq!(e, arr![i32; 1, 2]); + assert_eq!(f, arr![i32; 3, 4]); +} + +#[test] +fn test_concat() { + let a = arr![i32; 1, 2]; + let b = arr![i32; 3, 4]; + + let c = a.concat(b); + + assert_eq!(c, arr![i32; 1, 2, 3, 4]); + + let (d, e) = c.split(); + + assert_eq!(d, arr![i32; 1]); + assert_eq!(e, arr![i32; 2, 3, 4]); +} + +#[test] +fn test_fold() { + let a = arr![i32; 1, 2, 3, 4]; + + assert_eq!(10, a.fold(0, |a, x| a + x)); +} + +fn sum_generic(s: S) -> i32 +where + S: FunctionalSequence, + S::Item: Add, // `+` + i32: Add, // reflexive +{ + s.fold(0, |a, x| a + x) +} + +#[test] +fn test_sum() { + let a = sum_generic(arr![i32; 1, 2, 3, 4]); + + assert_eq!(a, 10); +} diff --git a/vendor/generic-array/.cargo-checksum.json b/vendor/generic-array/.cargo-checksum.json index 66e17ddfc4..9996cc4538 100644 --- a/vendor/generic-array/.cargo-checksum.json +++ b/vendor/generic-array/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"aa938a1a7581e59cbb554b44cc2dcf628cc1af9ddee6dccd53f557ed8d62775e","Cargo.toml":"6f83fe34b8c252299c537c8f5cdb22bffb583c5676d5353ad73bef7f4d6958fc","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"aad2a8508f8ae6b009d04d388bffb751875d4cfdcc6f3398212c65cc3c390d03","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"5fee5550800b890383c1dd80e00a0a568475a8599e7678e143740c941e98099d","src/functional.rs":"2437c360c645d8a9816a3b13531f23b005d1aed3ef7b1d9bcc9b2859b1d56826","src/hex.rs":"438288cf41fad3fd40ce60eb893cd038e9a88e450bab0189fe4dba8ce833a686","src/impl_serde.rs":"2cab2f808ba000c214a3ded9f43b4d5363114fe57c2c7abf545345b8b749f0db","src/impls.rs":"0472fc62d69e3e78b3f31e340cfc038bf12c3d7c4bdcd5fee064e7113d2f171d","src/iter.rs":"156f798c82bc0d5e2c9a0a7777acc156bfdda793b64295ad7495cc5daa5ecb97","src/lib.rs":"d2f4b74c7ac8f9a9d7a782089b95315ec6b1f1571d79a2b16bd76bcff2004bd4","src/sequence.rs":"63813c9e305b6642ac29f0ba3dd70d7db86e27fc58b31e7508c68ea52c060e82","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"edf27c43ed13bf8cba2cd01de2fd7b6451c1226c8ad8331880996248e7f14d12","tests/mod.rs":"fca2966183ccd1d1681f91a845773911ab61f618bd412470612fac240ecfe0db"},"package":"c68f0274ae0e023facc3c97b2e00f076be70e254bc851d972503b328db79b2ec"} \ No newline at end of file +{"files":{"CHANGELOG.md":"6fd290755dcbb7da68223425151b556fd76ab9998fe9cee81042acf1a47164e5","Cargo.toml":"a14186cc9cbb4d0446fcb8898439c24b5dd8acccc05dd27e3d829c069da97fa4","DESIGN.md":"8b745d89e634c48646202edfaa2151ee08a04a9c32271f4c2cc4afb63b4e952c","LICENSE":"c09aae9d3c77b531f56351a9947bc7446511d6b025b3255312d3e3442a9a7583","README.md":"9e86d03b400dc818f44df68b76dafd1d89e42a51221bcb0de4259a6529ab6d84","build.rs":"08fa30c4a2c1ad24fe5f987e721dfb20131f45ea5b5dc3e836dcf88a8e33248c","rustfmt.toml":"13d771354ddee15d5aa5a168fd6965c3c0ee7aa7ce75cdd5e3b82852cdac5123","src/arr.rs":"a898e3a37910bfc59d9caf71bf22eda02d3a4ad96c75f8a6d49ed1309531aa4e","src/functional.rs":"7dd6ddd5db3000054cbbd76959f745c7de73c8493cbfb745be80509b306e4a83","src/hex.rs":"091fb78f6d373a6ef1c467d85c461472fcdb1e91efc294039f4c870151c3ee9f","src/impl_serde.rs":"f046daba067522b4c3e79437d04f43a001e83353c81e6b2188c37a2e63dba7a3","src/impls.rs":"18b285821421eea0cdbbcfcc896eef67bd55d72f8d85b5827cca6687e9c0fc27","src/iter.rs":"5e5e92e86a18e747f6687f4b3853aa2eaaa1121af43f3833b940f074baa32302","src/lib.rs":"22af14d446ec5f67a99e350d4a0c95e070f4ff9537ac9e84ec1172f654f8b95a","src/sequence.rs":"26679cfec035bae7298f067f37e8d42a1eda8fe241e9cf2c2977ba4bddddab1d","tests/arr.rs":"22d332fcb5e0314980ddc952af0265125cf53bb9cb8b546a9dcaec2e29bfc3b0","tests/generics.rs":"491c9351fd973ff2b7bc72e78d3069cf3ed3fcd2f9180558ab027099605fa147","tests/hex.rs":"fd428c2558da2f1e2cf229af2e40e5b35a2094b3306312ac41943d25a85b7de1","tests/import_name.rs":"c9439c7d7531ce79419b0d413d729ea4321887c091bd9be8b18e6c2413021ed0","tests/iter.rs":"d9f18c7a280a938a63d382086450146206c5805804d4b62c7e55cd60ea0e2d0d","tests/mod.rs":"556a9cb6f6699c523ebfb1b167a18b30d909604339e929e9c874da92aae60bd3"},"package":"501466ecc8a30d1d3b7fc9229b122b2ce8ed6e9d9223f1138d4babb253e51817"} \ No newline at end of file diff --git a/vendor/generic-array/CHANGELOG.md b/vendor/generic-array/CHANGELOG.md index f8ee86b8e6..da20e891aa 100644 --- a/vendor/generic-array/CHANGELOG.md +++ b/vendor/generic-array/CHANGELOG.md @@ -1,3 +1,45 @@ +* **`0.14.4`** + * Update `typenum` to `1.12.0` + * Make `Drop` a no-op when the inner type does not require `Drop` (using `core::mem::needs_drop`) + +* **`0.14.3`** + * Improve behavior of `GenericArray::from_exact_iter` to assume `ExactIterator`s can lie. + * Fix alignment of zero-length `GenericArray`s + * Implement `From<&[T; N]> for &GenericArray` and its mutable variant + +* **`0.14.2`** + * Lower MSRV to `1.36.0` without `From<[T; N]>` implementations. + +* **`0.14.1`** + * Fix element conversions in `arr!` macro. + +* **`0.14.0`** + * Replace `Into` implementations with the more general `From`. + * Requires minumum Rust version of 1.41.0 + * Fix unsoundness in `arr!` macro. + * Fix meta variable misuse + * Fix Undefined Behavior across the crate by switching to `MaybeUninit` + * Improve some documentation and doctests + * Add `AsRef<[T; N]>` and `AsMut<[T; N]>` impls to `GenericArray` + * Add `Split` impl for `&GenericArray` and `&mut GenericArray` + +* **`0.13.2`** + * Add feature `more_lengths`, which adds more `From`/`Into` implementations for arrays of various lengths. + +* **`0.13.1`** + * Mark `GenericArray` as `#[repr(transparent)]` + * Implement `Into<[T; N]>` for `GenericArray` up to N=32 + +* **`0.13.0`** + * Allow `arr!` to be imported with use syntax. + * Requires minumum Rust version of 1.30.1 + +* **`0.12.2`** + * Implement `FusedIterator` for `GenericArrayIter` + +* **`0.12.1`** + * Use internal iteration where possible and provide more efficient internal iteration methods. + * **`0.12.0`** * Allow trailing commas in `arr!` macro. * **BREAKING**: Serialize `GenericArray` using `serde` tuples, instead of variable-length sequences. This may not be compatible with old serialized data. diff --git a/vendor/generic-array/Cargo.toml b/vendor/generic-array/Cargo.toml index 14b070c0b6..e802b576da 100644 --- a/vendor/generic-array/Cargo.toml +++ b/vendor/generic-array/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "generic-array" -version = "0.12.3" +version = "0.14.4" authors = ["Bartłomiej Kamiński ", "Aaron Trent "] description = "Generic types implementing functionality of arrays" documentation = "http://fizyk20.github.io/generic-array/generic_array/" @@ -30,11 +30,16 @@ optional = true default-features = false [dependencies.typenum] -version = "1.10" +version = "1.12" [dev-dependencies.bincode] version = "1.0" [dev-dependencies.serde_json] version = "1.0" +[build-dependencies.version_check] +version = "0.9" + +[features] +more_lengths = [] [badges.travis-ci] repository = "fizyk20/generic-array" diff --git a/vendor/generic-array/DESIGN.md b/vendor/generic-array/DESIGN.md new file mode 100644 index 0000000000..547bc7bd25 --- /dev/null +++ b/vendor/generic-array/DESIGN.md @@ -0,0 +1,585 @@ +Design and Usage Notes +====================== + +## Sections + +1. [How it Works](#how-it-works) +2. [Initialization](#initialization) +3. [Functional Programming](#functional-programming) +4. [Miscellaneous Utilities](#miscellaneous-utilities) +5. [Safety](#safety) +6. [Optimization](#optimization) +7. [The Future](#the-future) + +**NOTE**: This document uses `

    ` sections, so look out for collapsible parts with an arrow on the left. + +# How it works + +`generic-array` is a method of achieving fixed-length fixed-size stack-allocated generic arrays without needing const generics in stable Rust. + +That is to say this: + +```rust +struct Foo { + data: [i32; N], +} +``` + +or anything similar is not currently supported. + +However, Rust's type system is sufficiently advanced, and a "hack" for solving this was created in the form of the `typenum` crate, which recursively defines integer values in binary as nested types, and operations which can be applied to those type-numbers, such as `Add`, `Sub`, etc. + +e.g. `6` would be `UInt, B1>, B0>` + +Over time, I've come to see `typenum` as less of a hack and more as an elegant solution. + +The recursive binary nature of `typenum` is what makes `generic-array` possible, so: + +```rust +struct Foo> { + data: GenericArray, +} +``` + +is supported. + +I often see questions about why `ArrayLength` requires the element type `T` in it's signature, even though it's not used in the inner `ArrayType`. + +This is because `GenericArray` itself does not define the actual array. Rather, it is defined as: + +```rust +pub struct GenericArray> { + data: N::ArrayType, +} +``` + +The trait `ArrayLength` does all the real heavy lifting for defining the data, with implementations on `UInt`, `UInt` and `UTerm`, which correspond to even, odd and zero numeric values, respectively. + +`ArrayLength`'s implementations use type-level recursion to peel away each least significant bit and form sort of an opaque binary tree of contiguous data the correct physical size to store `N` elements of `T`. The tree, or block of data, is then stored inside of `GenericArray` to be reinterpreted as the array. + +For example, `GenericArray` more or less expands to (at compile time): + +
    +Expand for code + +```rust +GenericArray { + // UInt, B1>, B0> + data: EvenData { + // UInt, B1> + left: OddData { + // UInt + left: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 0 + }, + // UInt + right: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 1 + }, + data: T // Element 2 + }, + // UInt, B1> + right: OddData { + // UInt + left: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 3 + }, + // UInt + right: OddData { + left: (), // UTerm + right: (), // UTerm + data: T, // Element 4 + }, + data: T // Element 5 + } + } +} +``` + +
    + +This has the added benefit of only being `log2(N)` deep, which is important for things like `Drop`, which we'll go into later. + +Then, we take `data` and cast it to `*const T` or `*mut T` and use it as a slice like: + +```rust +unsafe { + slice::from_raw_parts( + self as *const Self as *const T, + N::to_usize() + ) +} +``` + +It is useful to note that because `typenum` is compile-time with nested generics, `to_usize`, even if it isn't a `const fn`, *does* expand to effectively `1 + 2 + 4 + 8 + ...` and so forth, which LLVM is smart enough to reduce to a single compile-time constant. This helps hint to the optimizers about things such as bounds checks. + +So, to reiterate, we're working with a raw block of contiguous memory the correct physical size to store `N` elements of `T`. It's really no different from how normal arrays are stored. + +## Pointer Safety + +Of course, casting pointers around and constructing blocks of data out of thin air is normal for C, but here in Rust we try to be a bit less prone to segfaults. Therefore, great care is taken to minimize casual `unsafe` usage and restrict `unsafe` to specific parts of the API, making heavy use those exposed safe APIs internally. + +For example, the above `slice::from_raw_parts` is only used twice in the entire library, once for `&[T]` and `slice::from_raw_parts_mut` once for `&mut [T]`. Everything else goes through those slices. + +# Initialization + +## Constant + +"Constant" initialization, that is to say - without dynamic values, can be done via the `arr![]` macro, which works almost exactly like `vec![]`, but with an additional type parameter. + +Example: + +```rust +let my_arr = arr![i32; 1, 2, 3, 4, 5, 6, 7, 8]; +``` + +## Dynamic + +Although some users have opted to use their own initializers, as of version `0.9` and beyond `generic-array` includes safe methods for initializing elements in the array. + +The `GenericSequence` trait defines a `generate` method which can be used like so: + +```rust +use generic_array::{GenericArray, sequence::GenericSequence}; + +let squares: GenericArray = + GenericArray::generate(|i: usize| i as i32 * 2); +``` + +and `GenericArray` additionally implements `FromIterator`, although `from_iter` ***will*** panic if the number of elements is not *at least* `N`. It will ignore extra items. + +The safety of these operations is described later. + +# Functional Programming + +In addition to `GenericSequence`, this crate provides a `FunctionalSequence`, which allows extremely efficient `map`, `zip` and `fold` operations on `GenericArray`s. + +As described at the end of the [Optimization](#optimization) section, `FunctionalSequence` uses clever specialization tactics to provide optimized methods wherever possible, while remaining perfectly safe. + +Some examples, taken from `tests/generic.rs`: + +
    + +and if you really want to go off the deep end and support any arbitrary *`GenericSequence`*: + +
    +Expand for code + +```rust +/// Complex example function using generics to pass N-length sequences, zip them, and then map that result. +/// +/// If used with `GenericArray` specifically this isn't necessary +pub fn generic_sequence_zip_sum(a: A, b: B) -> i32 +where + A: FunctionalSequence, // `.zip` + B: FunctionalSequence, // `.zip` + A: MappedGenericSequence, // `i32` -> `i32` + B: MappedGenericSequence>, // `i32` -> `i32`, prove A and B can map to the same output + A::Item: Add, // `l + r` + MappedSequence: MappedGenericSequence + FunctionalSequence, // `.map` + SequenceItem>: Add, // `x + 1` + MappedSequence, i32, i32>: Debug, // `println!` + MappedSequence, i32, i32>: FunctionalSequence, // `.fold` + SequenceItem, i32, i32>>: Add // `x + a`, note the order +{ + let c = a.zip(b, |l, r| l + r).map(|x| x + 1); + + println!("{:?}", c); + + c.fold(0, |a, x| x + a) +} +``` + +of course, as I stated before, that's almost never necessary, especially when you know the concrete types of all the components. + +
    + +The [`numeric-array`](https://crates.io/crates/numeric-array) crate uses these to apply numeric operations across all elements in a `GenericArray`, making full use of all the optimizations described in the last section here. + +# Miscellaneous Utilities + +Although not usually advertised, `generic-array` contains traits for lengthening, shortening, splitting and concatenating arrays. + +For example, these snippets are taken from `tests/mod.rs`: + +
    +Expand for code + +Appending and prepending elements: + +```rust +use generic_array::sequence::Lengthen; + +#[test] +fn test_append() { + let a = arr![i32; 1, 2, 3]; + + let b = a.append(4); + + assert_eq!(b, arr![i32; 1, 2, 3, 4]); +} + +#[test] +fn test_prepend() { + let a = arr![i32; 1, 2, 3]; + + let b = a.prepend(4); + + assert_eq!(b, arr![i32; 4, 1, 2, 3]); +} +``` + +Popping elements from the front of back of the array: + +```rust +use generic_array::sequence::Shorten; + +let a = arr![i32; 1, 2, 3, 4]; + +let (init, last) = a.pop_back(); + +assert_eq!(init, arr![i32; 1, 2, 3]); +assert_eq!(last, 4); + +let (head, tail) = a.pop_front(); + +assert_eq!(head, 1); +assert_eq!(tail, arr![i32; 2, 3, 4]); +``` + +and of course concatenating and splitting: + +```rust +use generic_array::sequence::{Concat, Split}; + +let a = arr![i32; 1, 2]; +let b = arr![i32; 3, 4]; + +let c = a.concat(b); + +assert_eq!(c, arr![i32; 1, 2, 3, 4]); + +let (d, e) = c.split(); + +assert_eq!(d, arr![i32; 1]); +assert_eq!(e, arr![i32; 2, 3, 4]); +``` +
    + +`Split` and `Concat` in these examples use type-inference to determine the lengths of the resulting arrays. + +# Safety + +As stated earlier, for raw reinterpretations such as this, safety is a must even while working with unsafe code. Great care is taken to reduce or eliminate undefined behavior. + +For most of the above code examples, the biggest potential undefined behavior hasn't even been applicable for one simple reason: they were all primitive values. + +The simplest way to lead into this is to post these questions: + +1. What if the element type of the array implements `Drop`? +2. What if `GenericArray::generate` opens a bunch of files? +3. What if halfway through opening each of the files, one is not found? +4. What if the resulting error is unwrapped, causing the generation function to panic? + +For a fully initialized `GenericArray`, the expanded structure as described in the [How It Works](#how-it-works) can implement `Drop` naturally, recursively dropping elements. As it is only `log2(N)` deep, the recursion is very small overall. + +In fact, I tested it while writing this, the size of the array itself overflows the stack before any recursive calls to `drop` can. + +However, ***partially*** initialized arrays, such as described in the above hypothetical, pose an issue where `drop` could be called on uninitialized data, which is undefined behavior. + +To solve this, `GenericArray` implements two components named `ArrayBuilder` and `ArrayConsumer`, which work very similarly. + +`ArrayBuilder` creates a block of wholly uninitialized memory via `mem::unintialized()`, and stores that in a `ManuallyDrop` wrapper. `ManuallyDrop` does exactly what it says on the tin, and simply doesn't drop the value unless manually requested to. + +So, as we're initializing our array, `ArrayBuilder` keeps track of the current position through it, and if something happens, `ArrayBuilder` itself will iteratively and manually `drop` all currently initialized elements, ignoring any uninitialized ones, because those are just raw memory and should be ignored. + +`ArrayConsumer` does almost the same, "moving" values out of the array and into something else, like user code. It uses `ptr::read` to "move" the value out, and increments a counter saying that value is no longer valid in the array. + +If a panic occurs in the user code with that element, it's dropped naturally as it was moved into that scope. `ArrayConsumer` then proceeds to iteratively and manually `drop` all *remaining* elements. + +Combined, these two systems provide a safe system for building and consuming `GenericArray`s. In fact, they are used extensively inside the library itself for `FromIterator`, `GenericSequence` and `FunctionalSequence`, among others. + +Even `GenericArray`s implementation of `Clone` makes use of this via: + +```rust +impl Clone for GenericArray +where + N: ArrayLength, +{ + fn clone(&self) -> GenericArray { + self.map(|x| x.clone()) + } +} +``` + +where `.map` is from the `FunctionalSequence`, and uses those builder and consumer structures to safely move and initialize values. Although, in this particular case, a consumer is not necessary as we're using references. More on how that is automatically deduced is described in the next section. + +# Optimization + +Rust and LLVM is smart. Crazy smart. However, it's not magic. + +In my experience, most of Rust's "zero-cost" abstractions stem more from the type system, rather than explicit optimizations. Most Rust code is very easily optimizable and inlinable by design, so it can be simplified and compacted rather well, as opposed to the spaghetti code of some other languages. + +Unfortunately, unless `rustc` or LLVM can "prove" things about code to simplify it, it must still be run, and can prevent further optimization. + +A great example of this, and why I created the `GenericSequence` and `FunctionalSequence` traits, are iterators. + +Custom iterators are slow. Not terribly slow, but slow enough to prevent some rather important optimizations. + +Take `GenericArrayIter` for example: + +
    +Expand for code + +```rust +pub struct GenericArrayIter> { + array: ManuallyDrop>, + index: usize, + index_back: usize, +} + +impl Iterator for GenericArrayIter +where + N: ArrayLength, +{ + type Item = T; + + #[inline] + fn next(&mut self) -> Option { + if self.index < self.index_back { + let p = unsafe { + Some(ptr::read(self.array.get_unchecked(self.index))) + }; + + self.index += 1; + + p + } else { + None + } + } + + //and more +} +``` +
    + +Seems simple enough, right? Move an element out of the array with `ptr::read` and increment the index. If the iterator is dropped, the remaining elements are dropped exactly as they would with `ArrayConsumer`. `index_back` is provided for `DoubleEndedIterator`. + +Unfortunately, that single `if` statement is terrible. In my mind, this is one of the biggest flaws of the iterator design. A conditional jump on a mutable variable unrelated to the data we are accessing on each call foils the optimizer and generates suboptimal code for the above iterator, even when we use `get_unchecked`. + +The optimizer is unable to see that we are simply accessing memory sequentially. In fact, almost all iterators are like this. Granted, this is usually fine and, especially if they have to handle errors, it's perfectly acceptable. + +However, there is one iterator in the standard library that is optimized perfectly: the slice iterator. So perfectly in fact that it allows the optimizer to do something even more special: **auto-vectorization**! We'll get to that later. + +It's a bit frustrating as to *why* slice iterators can be so perfectly optimized, and it basically boils down to that the iterator itself does not own the data the slice refers to, so it uses raw pointers to the array/sequence/etc. rather than having to use an index on a stack allocated and always moving array. It can check for if the iterator is empty by comparing some `front` and `back` pointers for equality, and because those directly correspond to the position in memory of the next element, LLVM can see that and make optimizations. + +So, the gist of that is: always use slice iterators where possible. + +Here comes the most important part of all of this: `ArrayBuilder` and `ArrayConsumer` don't iterate the arrays themselves. Instead, we use slice iterators (immutable and mutable), with `zip` or `enumerate`, to apply operations to the entire array, incrementing the position in both `ArrayBuilder` or `ArrayConsumer` to keep track. + +For example, `GenericSequence::generate` for `GenericArray` is: + +
    +Expand for code + +```rust +fn generate(mut f: F) -> GenericArray +where + F: FnMut(usize) -> T, +{ + unsafe { + let mut destination = ArrayBuilder::new(); + + { + let (destination_iter, position) = destination.iter_position(); + + for (i, dst) in destination_iter.enumerate() { + ptr::write(dst, f(i)); + + *position += 1; + } + } + + destination.into_inner() + } +} +``` + +where `ArrayBuilder::iter_position` is just an internal convenience function: + +```rust +pub unsafe fn iter_position(&mut self) -> (slice::IterMut, &mut usize) { + (self.array.iter_mut(), &mut self.position) +} +``` +
    + +Of course, this may appear to be redundant, if we're using an iterator that keeps track of the position itself, and the builder is also keeping track of the position. However, the two are decoupled. + +If the generation function doesn't have a chance at panicking, and/or the array element type doesn't implement `Drop`, the optimizer deems the `Drop` implementation on `ArrayBuilder` (and `ArrayConsumer`) dead code, and therefore `position` is never actually read from, so it becomes dead code as well, and is removed. + +So for simple non-`Drop`/non-panicking elements and generation functions, `generate` becomes a very simple loop that uses a slice iterator to write values to the array. + +Next, let's take a look at a more complex example where this *really* shines: `.zip` + +To cut down on excessively verbose code, `.zip` uses `FromIterator` for building the array, which has almost identical code to `generate`, so it will be omitted. + +The first implementation of `.zip` is defined as: + +
    +Expand for code + +```rust +fn inverted_zip( + self, + lhs: GenericArray, + mut f: F, +) -> MappedSequence, B, U> +where + GenericArray: + GenericSequence + MappedGenericSequence, + Self: MappedGenericSequence, + Self::Length: ArrayLength + ArrayLength, + F: FnMut(B, Self::Item) -> U, +{ + unsafe { + let mut left = ArrayConsumer::new(lhs); + let mut right = ArrayConsumer::new(self); + + let (left_array_iter, left_position) = left.iter_position(); + let (right_array_iter, right_position) = right.iter_position(); + + FromIterator::from_iter(left_array_iter.zip(right_array_iter).map(|(l, r)| { + let left_value = ptr::read(l); + let right_value = ptr::read(r); + + *left_position += 1; + *right_position += 1; + + f(left_value, right_value) + })) + } +} +``` +
    + +The gist of this is that we have two `GenericArray` instances that need to be zipped together and mapped to a new sequence. This employs two `ArrayConsumer`s, and more or less use the same pattern as the previous example. + +Again, the position values can be optimized out, and so can the slice iterator adapters. + +We can go a step further with this, however. + +Consider this: + +```rust +let a = arr![i32; 1, 3, 5, 7]; +let b = arr![i32; 2, 4, 6, 8]; + +let c = a.zip(b, |l, r| l + r); + +assert_eq!(c, arr![i32; 3, 7, 11, 15]); +``` + +when compiled with: + +``` +cargo rustc --lib --profile test --release -- -C target-cpu=native -C opt-level=3 --emit asm +``` + +will produce assembly with the following relevant instructions taken from the entire program: + +```asm +; Copy constant to register +vmovaps __xmm@00000007000000050000000300000001(%rip), %xmm0 + +; Copy constant to register +vmovaps __xmm@00000008000000060000000400000002(%rip), %xmm0 + +; Add the two values together +vpaddd 192(%rsp), %xmm0, %xmm1 + +; Copy constant to register +vmovaps __xmm@0000000f0000000b0000000700000003(%rip), %xmm0 + +; Compare result of the addition with the last constant +vpcmpeqb 128(%rsp), %xmm0, %xmm0 +``` + +so, aside from a bunch of obvious hygiene instructions around those selected instructions, +it seriously boils down that `.zip` call to a ***SINGLE*** SIMD instruction. In fact, it continues to do this for even larger arrays. Although it does fall back to individual additions for fewer than four elements, as it can't fit those into an SSE register evenly. + +Using this property of auto-vectorization without sacrificing safety, I created the [`numeric-array`](https://crates.io/crates/numeric-array) crate which makes use of this to wrap `GenericArray` and implement numeric traits so that almost *all* operations can be auto-vectorized, even complex ones like fused multiple-add. + +It doesn't end there, though. You may have noticed that the function name for zip above wasn't `zip`, but `inverted_zip`. + +This is because `generic-array` employs a clever specialization tactic to ensure `.zip` works corrects with: + +1. `a.zip(b, ...)` +2. `(&a).zip(b, ...)` +3. `(&a).zip(&b, ...)` +4. `a.zip(&b, ...)` + +wherein `GenericSequence` and `FunctionalSequence` have default implementations of `zip` variants, with concrete implementations for `GenericArray`. As `GenericSequence` is implemented for `&GenericArray`, where calling `into_iter` on produces a slice iterator, it can use "naive" iterator adapters to the same effect, while the specialized implementations use `ArrayConsumer`. + +The result is that any combination of move or reference calls to `.zip`, `.map` and `.fold` produce code that can be optimized, none of them falling back to slow non-slice iterators. All perfectly safe with the `ArrayBuilder` and `ArrayConsumer` systems. + +Honestly, `GenericArray` is better than standard arrays at this point. + +# The Future + +If/when const generics land in stable Rust, my intention is to reorient this crate or create a new crate to provide traits and wrappers for standard arrays to provide the same safety and performance discussed above. \ No newline at end of file diff --git a/vendor/generic-array/README.md b/vendor/generic-array/README.md index 64dd84faaf..cf54f40550 100644 --- a/vendor/generic-array/README.md +++ b/vendor/generic-array/README.md @@ -4,6 +4,8 @@ This crate implements generic array types for Rust. +**Requires minumum Rust version of 1.36.0, or 1.41.0 for `From<[T; N]>` implementations** + [Documentation](http://fizyk20.github.io/generic-array/generic_array/) ## Usage @@ -24,7 +26,33 @@ struct Foo> { } ``` -To actually define a type implementing `ArrayLength`, you can use unsigned integer types defined in [typenum](https://github.com/paholg/typenum) crate - for example, `GenericArray` would work almost like `[T; 5]` :) +The `ArrayLength` trait is implemented by default for [unsigned integer types](http://fizyk20.github.io/generic-array/typenum/uint/index.html) from [typenum](http://fizyk20.github.io/generic-array/typenum/index.html) crate: + +```rust +use generic_array::typenum::U5; + +struct Foo> { + data: GenericArray +} + +fn main() { + let foo = Foo::{data: GenericArray::default()}; +} +``` + +For example, `GenericArray` would work almost like `[T; 5]`: + +```rust +use generic_array::typenum::U5; + +struct Foo> { + data: GenericArray +} + +fn main() { + let foo = Foo::{data: GenericArray::default()}; +} +``` In version 0.1.1 an `arr!` macro was introduced, allowing for creation of arrays as shown below: diff --git a/vendor/generic-array/build.rs b/vendor/generic-array/build.rs new file mode 100644 index 0000000000..c27c7e3fa9 --- /dev/null +++ b/vendor/generic-array/build.rs @@ -0,0 +1,5 @@ +fn main() { + if version_check::is_min_version("1.41.0").unwrap_or(false) { + println!("cargo:rustc-cfg=relaxed_coherence"); + } +} diff --git a/vendor/generic-array/src/arr.rs b/vendor/generic-array/src/arr.rs index a07d129ad3..aed4999205 100644 --- a/vendor/generic-array/src/arr.rs +++ b/vendor/generic-array/src/arr.rs @@ -1,57 +1,125 @@ -//! Implementation for `arr!` macro. - -use super::ArrayLength; -use core::ops::Add; -use typenum::U1; - -/// Helper trait for `arr!` macro -pub trait AddLength>: ArrayLength { - /// Resulting length - type Output: ArrayLength; -} - -impl AddLength for N1 -where - N1: ArrayLength + Add, - N2: ArrayLength, - >::Output: ArrayLength, -{ - type Output = >::Output; -} - -/// Helper type for `arr!` macro -pub type Inc = >::Output; - -#[doc(hidden)] -#[macro_export] -macro_rules! arr_impl { - ($T:ty; $N:ty, [$($x:expr),*], []) => ({ - unsafe { $crate::transmute::<_, $crate::GenericArray<$T, $N>>([$($x),*]) } - }); - ($T:ty; $N:ty, [], [$x1:expr]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], []) - ); - ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1 as $T], [$($x),+]) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], []) - ); - ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( - arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1 as $T], [$($x),+]) - ); -} - -/// Macro allowing for easy generation of Generic Arrays. -/// Example: `let test = arr![u32; 1, 2, 3];` -#[macro_export] -macro_rules! arr { - ($T:ty; $(,)*) => ({ - unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) } - }); - ($T:ty; $($x:expr),* $(,)*) => ( - arr_impl!($T; $crate::typenum::U0, [], [$($x),*]) - ); - ($($x:expr,)+) => (arr![$($x),*]); - () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") -} +//! Implementation for `arr!` macro. + +use super::ArrayLength; +use core::ops::Add; +use typenum::U1; + +/// Helper trait for `arr!` macro +pub trait AddLength>: ArrayLength { + /// Resulting length + type Output: ArrayLength; +} + +impl AddLength for N1 +where + N1: ArrayLength + Add, + N2: ArrayLength, + >::Output: ArrayLength, +{ + type Output = >::Output; +} + +/// Helper type for `arr!` macro +pub type Inc = >::Output; + +#[doc(hidden)] +#[macro_export] +macro_rules! arr_impl { + (@replace_expr $e:expr) => { 1 }; + ($T:ty; $N:ty, [$($x:expr),*], []) => ({ + const __ARR_LENGTH: usize = 0 $(+ $crate::arr_impl!(@replace_expr $x) )*; + + #[inline(always)] + fn __do_transmute>(arr: [T; __ARR_LENGTH]) -> $crate::GenericArray { + unsafe { $crate::transmute(arr) } + } + + let _: [(); <$N as $crate::typenum::Unsigned>::USIZE] = [(); __ARR_LENGTH]; + + __do_transmute::<$T, $N>([$($x as $T),*]) + }); + ($T:ty; $N:ty, [], [$x1:expr]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], []) + ); + ($T:ty; $N:ty, [], [$x1:expr, $($x:expr),+]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$x1], [$($x),+]) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], []) + ); + ($T:ty; $N:ty, [$($y:expr),+], [$x1:expr, $($x:expr),+]) => ( + $crate::arr_impl!($T; $crate::arr::Inc<$T, $N>, [$($y),+, $x1], [$($x),+]) + ); +} + +/// Macro allowing for easy generation of Generic Arrays. +/// Example: `let test = arr![u32; 1, 2, 3];` +#[macro_export] +macro_rules! arr { + ($T:ty; $(,)*) => ({ + unsafe { $crate::transmute::<[$T; 0], $crate::GenericArray<$T, $crate::typenum::U0>>([]) } + }); + ($T:ty; $($x:expr),* $(,)*) => ( + $crate::arr_impl!($T; $crate::typenum::U0, [], [$($x),*]) + ); + ($($x:expr,)+) => (arr![$($x),+]); + () => ("""Macro requires a type, e.g. `let array = arr![u32; 1, 2, 3];`") +} + +mod doctests_only { + /// + /// # With ellision + /// + /// Testing that lifetimes aren't transmuted when they're ellided. + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&A; a][0] + /// } + /// } + /// ``` + /// + /// ```rust + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { + /// arr![&A; a][0] + /// } + /// } + /// ``` + /// + /// # Without ellision + /// + /// Testing that lifetimes aren't transmuted when they're specified explicitly. + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&'a A; a][0] + /// } + /// } + /// ``` + /// + /// ```compile_fail + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'static A { + /// arr![&'static A; a][0] + /// } + /// } + /// ``` + /// + /// ```rust + /// #[macro_use] extern crate generic_array; + /// fn main() { + /// fn unsound_lifetime_extension<'a, A>(a: &'a A) -> &'a A { + /// arr![&'a A; a][0] + /// } + /// } + /// ``` + #[allow(dead_code)] + pub enum DocTests {} +} diff --git a/vendor/generic-array/src/functional.rs b/vendor/generic-array/src/functional.rs index d161a83cac..2ddcc5c4c4 100644 --- a/vendor/generic-array/src/functional.rs +++ b/vendor/generic-array/src/functional.rs @@ -4,7 +4,8 @@ use super::ArrayLength; use core::iter::FromIterator; -use sequence::*; + +use crate::sequence::*; /// Defines the relationship between one generic sequence and another, /// for operations such as `map` and `zip`. diff --git a/vendor/generic-array/src/hex.rs b/vendor/generic-array/src/hex.rs index 09a6608e37..33c796f3c9 100644 --- a/vendor/generic-array/src/hex.rs +++ b/vendor/generic-array/src/hex.rs @@ -15,13 +15,12 @@ //! ``` //! -use {ArrayLength, GenericArray}; -use core::cmp::min; -use core::fmt; -use core::ops::Add; -use core::str; +use core::{fmt, str, ops::Add, cmp::min}; + use typenum::*; +use crate::{ArrayLength, GenericArray}; + static LOWER_CHARS: &'static [u8] = b"0123456789abcdef"; static UPPER_CHARS: &'static [u8] = b"0123456789ABCDEF"; @@ -30,19 +29,20 @@ where T: Add, >::Output: ArrayLength, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); let max_hex = (max_digits >> 1) + (max_digits & 1); - if T::to_usize() < 1024 { + if T::USIZE < 1024 { // For small arrays use a stack allocated // buffer of 2x number of bytes let mut res = GenericArray::>::default(); - for (i, c) in self.iter().take(max_hex).enumerate() { + self.iter().take(max_hex).enumerate().for_each(|(i, c)| { res[i * 2] = LOWER_CHARS[(c >> 4) as usize]; res[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; - } + }); + f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; } else { // For large array use chunks of up to 1024 bytes (2048 hex chars) @@ -50,10 +50,11 @@ where let mut digits_left = max_digits; for chunk in self[..max_hex].chunks(1024) { - for (i, c) in chunk.iter().enumerate() { + chunk.iter().enumerate().for_each(|(i, c)| { buf[i * 2] = LOWER_CHARS[(c >> 4) as usize]; buf[i * 2 + 1] = LOWER_CHARS[(c & 0xF) as usize]; - } + }); + let n = min(chunk.len() * 2, digits_left); f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; digits_left -= n; @@ -68,19 +69,20 @@ where T: Add, >::Output: ArrayLength, { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { let max_digits = f.precision().unwrap_or_else(|| self.len() * 2); let max_hex = (max_digits >> 1) + (max_digits & 1); - if T::to_usize() < 1024 { + if T::USIZE < 1024 { // For small arrays use a stack allocated // buffer of 2x number of bytes let mut res = GenericArray::>::default(); - for (i, c) in self.iter().take(max_hex).enumerate() { + self.iter().take(max_hex).enumerate().for_each(|(i, c)| { res[i * 2] = UPPER_CHARS[(c >> 4) as usize]; res[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; - } + }); + f.write_str(unsafe { str::from_utf8_unchecked(&res[..max_digits]) })?; } else { // For large array use chunks of up to 1024 bytes (2048 hex chars) @@ -88,10 +90,11 @@ where let mut digits_left = max_digits; for chunk in self[..max_hex].chunks(1024) { - for (i, c) in chunk.iter().enumerate() { + chunk.iter().enumerate().for_each(|(i, c)| { buf[i * 2] = UPPER_CHARS[(c >> 4) as usize]; buf[i * 2 + 1] = UPPER_CHARS[(c & 0xF) as usize]; - } + }); + let n = min(chunk.len() * 2, digits_left); f.write_str(unsafe { str::from_utf8_unchecked(&buf[..n]) })?; digits_left -= n; diff --git a/vendor/generic-array/src/impl_serde.rs b/vendor/generic-array/src/impl_serde.rs index 7bf20ba013..49c095a5de 100644 --- a/vendor/generic-array/src/impl_serde.rs +++ b/vendor/generic-array/src/impl_serde.rs @@ -16,7 +16,7 @@ where where S: Serializer, { - let mut tup = serializer.serialize_tuple(N::to_usize())?; + let mut tup = serializer.serialize_tuple(N::USIZE)?; for el in self { tup.serialize_element(el)?; } @@ -46,7 +46,7 @@ where A: SeqAccess<'de>, { let mut result = GenericArray::default(); - for i in 0..N::to_usize() { + for i in 0..N::USIZE { result[i] = seq .next_element()? .ok_or_else(|| de::Error::invalid_length(i, &self))?; @@ -68,7 +68,7 @@ where _t: PhantomData, _n: PhantomData, }; - deserializer.deserialize_tuple(N::to_usize(), visitor) + deserializer.deserialize_tuple(N::USIZE, visitor) } } @@ -91,7 +91,7 @@ mod tests { array[0] = 1; array[1] = 2; let serialized = bincode::serialize(&array).unwrap(); - let deserialized = bincode::deserialize::>(&array); + let deserialized = bincode::deserialize::>(&serialized); assert!(deserialized.is_ok()); let array = deserialized.unwrap(); assert_eq!(array[0], 1); diff --git a/vendor/generic-array/src/impls.rs b/vendor/generic-array/src/impls.rs index 52896dfba3..47ecc1d31d 100644 --- a/vendor/generic-array/src/impls.rs +++ b/vendor/generic-array/src/impls.rs @@ -1,16 +1,18 @@ -use super::{ArrayLength, GenericArray}; use core::borrow::{Borrow, BorrowMut}; use core::cmp::Ordering; use core::fmt::{self, Debug}; use core::hash::{Hash, Hasher}; -use functional::*; -use sequence::*; + +use super::{ArrayLength, GenericArray}; + +use crate::functional::*; +use crate::sequence::*; impl Default for GenericArray where N: ArrayLength, { - #[inline] + #[inline(always)] fn default() -> Self { Self::generate(|_| T::default()) } @@ -40,11 +42,7 @@ where **self == **other } } -impl Eq for GenericArray -where - N: ArrayLength, -{ -} +impl Eq for GenericArray where N: ArrayLength {} impl PartialOrd for GenericArray where @@ -135,14 +133,50 @@ macro_rules! impl_from { } } + #[cfg(relaxed_coherence)] + impl From> for [T; $n] { + #[inline(always)] + fn from(sel: GenericArray) -> [T; $n] { + unsafe { $crate::transmute(sel) } + } + } + + impl<'a, T> From<&'a [T; $n]> for &'a GenericArray { + #[inline] + fn from(slice: &[T; $n]) -> &GenericArray { + unsafe { &*(slice.as_ptr() as *const GenericArray) } + } + } + + impl<'a, T> From<&'a mut [T; $n]> for &'a mut GenericArray { + #[inline] + fn from(slice: &mut [T; $n]) -> &mut GenericArray { + unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray) } + } + } + + #[cfg(not(relaxed_coherence))] impl Into<[T; $n]> for GenericArray { #[inline(always)] fn into(self) -> [T; $n] { unsafe { $crate::transmute(self) } } } - )* + impl AsRef<[T; $n]> for GenericArray { + #[inline] + fn as_ref(&self) -> &[T; $n] { + unsafe { $crate::transmute(self) } + } + } + + impl AsMut<[T; $n]> for GenericArray { + #[inline] + fn as_mut(&mut self) -> &mut [T; $n] { + unsafe { $crate::transmute(self) } + } + } + )* } } @@ -180,3 +214,56 @@ impl_from! { 31 => ::typenum::U31, 32 => ::typenum::U32 } + +#[cfg(feature = "more_lengths")] +impl_from! { + 33 => ::typenum::U33, + 34 => ::typenum::U34, + 35 => ::typenum::U35, + 36 => ::typenum::U36, + 37 => ::typenum::U37, + 38 => ::typenum::U38, + 39 => ::typenum::U39, + 40 => ::typenum::U40, + 41 => ::typenum::U41, + 42 => ::typenum::U42, + 43 => ::typenum::U43, + 44 => ::typenum::U44, + 45 => ::typenum::U45, + 46 => ::typenum::U46, + 47 => ::typenum::U47, + 48 => ::typenum::U48, + 49 => ::typenum::U49, + 50 => ::typenum::U50, + 51 => ::typenum::U51, + 52 => ::typenum::U52, + 53 => ::typenum::U53, + 54 => ::typenum::U54, + 55 => ::typenum::U55, + 56 => ::typenum::U56, + 57 => ::typenum::U57, + 58 => ::typenum::U58, + 59 => ::typenum::U59, + 60 => ::typenum::U60, + 61 => ::typenum::U61, + 62 => ::typenum::U62, + 63 => ::typenum::U63, + 64 => ::typenum::U64, + + 70 => ::typenum::U70, + 80 => ::typenum::U80, + 90 => ::typenum::U90, + + 100 => ::typenum::U100, + 200 => ::typenum::U200, + 300 => ::typenum::U300, + 400 => ::typenum::U400, + 500 => ::typenum::U500, + + 128 => ::typenum::U128, + 256 => ::typenum::U256, + 512 => ::typenum::U512, + + 1000 => ::typenum::U1000, + 1024 => ::typenum::U1024 +} diff --git a/vendor/generic-array/src/iter.rs b/vendor/generic-array/src/iter.rs index 46f3e768d7..90e94fc6c1 100644 --- a/vendor/generic-array/src/iter.rs +++ b/vendor/generic-array/src/iter.rs @@ -1,8 +1,9 @@ //! `GenericArray` iterator implementation. use super::{ArrayLength, GenericArray}; -use core::{cmp, ptr, fmt, mem}; -use core::mem::ManuallyDrop; +use core::iter::FusedIterator; +use core::mem::{MaybeUninit, ManuallyDrop}; +use core::{cmp, fmt, ptr, mem}; /// An iterator that moves out of a `GenericArray` pub struct GenericArrayIter> { @@ -54,7 +55,7 @@ where GenericArrayIter { array: ManuallyDrop::new(self), index: 0, - index_back: N::to_usize(), + index_back: N::USIZE, } } } @@ -77,10 +78,12 @@ where { #[inline] fn drop(&mut self) { - // Drop values that are still alive. - for p in self.as_mut_slice() { - unsafe { - ptr::drop_in_place(p); + if mem::needs_drop::() { + // Drop values that are still alive. + for p in self.as_mut_slice() { + unsafe { + ptr::drop_in_place(p); + } } } } @@ -95,19 +98,20 @@ where // This places all cloned elements at the start of the new array iterator, // not at their original indices. unsafe { - let mut iter = GenericArrayIter { - array: ManuallyDrop::new(mem::uninitialized()), - index: 0, - index_back: 0, - }; + let mut array: MaybeUninit> = MaybeUninit::uninit(); + let mut index_back = 0; - for (dst, src) in iter.array.iter_mut().zip(self.as_slice()) { + for (dst, src) in (&mut *array.as_mut_ptr()).iter_mut().zip(self.as_slice()) { ptr::write(dst, src.clone()); - iter.index_back += 1; + index_back += 1; } - iter + GenericArrayIter { + array: ManuallyDrop::new(array.assume_init()), + index: 0, + index_back + } } } } @@ -131,6 +135,34 @@ where } } + fn fold(mut self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let ret = unsafe { + let GenericArrayIter { + ref array, + ref mut index, + index_back, + } = self; + + let remaining = &array[*index..index_back]; + + remaining.iter().fold(init, |acc, src| { + let value = ptr::read(src); + + *index += 1; + + f(acc, value) + }) + }; + + // ensure the drop happens here after iteration + drop(self); + + ret + } + #[inline] fn size_hint(&self) -> (usize, Option) { let len = self.len(); @@ -157,6 +189,7 @@ where self.next() } + #[inline] fn last(mut self) -> Option { // Note, everything else will correctly drop first as `self` leaves scope. self.next_back() @@ -176,6 +209,34 @@ where None } } + + fn rfold(mut self, init: B, mut f: F) -> B + where + F: FnMut(B, Self::Item) -> B, + { + let ret = unsafe { + let GenericArrayIter { + ref array, + index, + ref mut index_back, + } = self; + + let remaining = &array[index..*index_back]; + + remaining.iter().rfold(init, |acc, src| { + let value = ptr::read(src); + + *index_back -= 1; + + f(acc, value) + }) + }; + + // ensure the drop happens here after iteration + drop(self); + + ret + } } impl ExactSizeIterator for GenericArrayIter @@ -187,4 +248,10 @@ where } } -// TODO: Implement `FusedIterator` and `TrustedLen` when stabilized \ No newline at end of file +impl FusedIterator for GenericArrayIter +where + N: ArrayLength, +{ +} + +// TODO: Implement `TrustedLen` when stabilized diff --git a/vendor/generic-array/src/lib.rs b/vendor/generic-array/src/lib.rs index 5b95805375..4e634448a4 100644 --- a/vendor/generic-array/src/lib.rs +++ b/vendor/generic-array/src/lib.rs @@ -1,8 +1,8 @@ -//! This crate implements a structure that can be used as a generic array type.use +//! This crate implements a structure that can be used as a generic array type. //! Core Rust array types `[T; N]` can't be used generically with //! respect to `N`, so for example this: //! -//! ```{should_fail} +//! ```rust{compile_fail} //! struct Foo { //! data: [T; N] //! } @@ -13,8 +13,9 @@ //! **generic-array** exports a `GenericArray` type, which lets //! the above be implemented as: //! -//! ``` -//! # use generic_array::{ArrayLength, GenericArray}; +//! ```rust +//! use generic_array::{ArrayLength, GenericArray}; +//! //! struct Foo> { //! data: GenericArray //! } @@ -22,7 +23,35 @@ //! //! The `ArrayLength` trait is implemented by default for //! [unsigned integer types](../typenum/uint/index.html) from -//! [typenum](../typenum/index.html). +//! [typenum](../typenum/index.html): +//! +//! ```rust +//! # use generic_array::{ArrayLength, GenericArray}; +//! use generic_array::typenum::U5; +//! +//! struct Foo> { +//! data: GenericArray +//! } +//! +//! # fn main() { +//! let foo = Foo::{data: GenericArray::default()}; +//! # } +//! ``` +//! +//! For example, `GenericArray` would work almost like `[T; 5]`: +//! +//! ```rust +//! # use generic_array::{ArrayLength, GenericArray}; +//! use generic_array::typenum::U5; +//! +//! struct Foo> { +//! data: GenericArray +//! } +//! +//! # fn main() { +//! let foo = Foo::{data: GenericArray::default()}; +//! # } +//! ``` //! //! For ease of use, an `arr!` macro is provided - example below: //! @@ -37,6 +66,7 @@ //! ``` #![deny(missing_docs)] +#![deny(meta_variable_misuse)] #![no_std] #[cfg(feature = "serde")] @@ -51,11 +81,11 @@ mod hex; mod impls; #[cfg(feature = "serde")] -pub mod impl_serde; +mod impl_serde; use core::iter::FromIterator; use core::marker::PhantomData; -use core::mem::ManuallyDrop; +use core::mem::{MaybeUninit, ManuallyDrop}; use core::ops::{Deref, DerefMut}; use core::{mem, ptr, slice}; use typenum::bit::{B0, B1}; @@ -67,9 +97,9 @@ pub mod functional; pub mod iter; pub mod sequence; -use functional::*; -pub use iter::GenericArrayIter; -use sequence::*; +use self::functional::*; +pub use self::iter::GenericArrayIter; +use self::sequence::*; /// Trait making `GenericArray` work, marking types to be used as length of an array pub unsafe trait ArrayLength: Unsigned { @@ -79,7 +109,7 @@ pub unsafe trait ArrayLength: Unsigned { unsafe impl ArrayLength for UTerm { #[doc(hidden)] - type ArrayType = (); + type ArrayType = [T; 0]; } /// Internal type used to generate a struct of appropriate size @@ -138,6 +168,7 @@ unsafe impl> ArrayLength for UInt { /// Struct representing a generic array - `GenericArray` works like [T; N] #[allow(dead_code)] +#[repr(transparent)] pub struct GenericArray> { data: U::ArrayType, } @@ -153,7 +184,7 @@ where #[inline(always)] fn deref(&self) -> &[T] { - unsafe { slice::from_raw_parts(self as *const Self as *const T, N::to_usize()) } + unsafe { slice::from_raw_parts(self as *const Self as *const T, N::USIZE) } } } @@ -163,7 +194,7 @@ where { #[inline(always)] fn deref_mut(&mut self) -> &mut [T] { - unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, N::to_usize()) } + unsafe { slice::from_raw_parts_mut(self as *mut Self as *mut T, N::USIZE) } } } @@ -174,7 +205,7 @@ where /// which will be dropped if `into_inner` is not called. #[doc(hidden)] pub struct ArrayBuilder> { - array: ManuallyDrop>, + array: MaybeUninit>, position: usize, } @@ -183,7 +214,7 @@ impl> ArrayBuilder { #[inline] pub unsafe fn new() -> ArrayBuilder { ArrayBuilder { - array: ManuallyDrop::new(mem::uninitialized()), + array: MaybeUninit::uninit(), position: 0, } } @@ -195,7 +226,7 @@ impl> ArrayBuilder { #[doc(hidden)] #[inline] pub unsafe fn iter_position(&mut self) -> (slice::IterMut, &mut usize) { - (self.array.iter_mut(), &mut self.position) + ((&mut *self.array.as_mut_ptr()).iter_mut(), &mut self.position) } /// When done writing (assuming all elements have been written to), @@ -207,15 +238,17 @@ impl> ArrayBuilder { mem::forget(self); - ManuallyDrop::into_inner(array) + array.assume_init() } } impl> Drop for ArrayBuilder { fn drop(&mut self) { - for value in &mut self.array[..self.position] { + if mem::needs_drop::() { unsafe { - ptr::drop_in_place(value); + for value in &mut (&mut *self.array.as_mut_ptr())[..self.position] { + ptr::drop_in_place(value); + } } } } @@ -254,9 +287,11 @@ impl> ArrayConsumer { impl> Drop for ArrayConsumer { fn drop(&mut self) { - for value in &mut self.array[self.position..N::to_usize()] { - unsafe { - ptr::drop_in_place(value); + if mem::needs_drop::() { + for value in &mut self.array[self.position..N::USIZE] { + unsafe { + ptr::drop_in_place(value); + } } } } @@ -300,15 +335,17 @@ where { let (destination_iter, position) = destination.iter_position(); - for (src, dst) in iter.into_iter().zip(destination_iter) { - ptr::write(dst, src); + iter.into_iter() + .zip(destination_iter) + .for_each(|(src, dst)| { + ptr::write(dst, src); - *position += 1; - } + *position += 1; + }); } - if destination.position < N::to_usize() { - from_iter_length_fail(destination.position, N::to_usize()); + if destination.position < N::USIZE { + from_iter_length_fail(destination.position, N::USIZE); } destination.into_inner() @@ -343,11 +380,11 @@ where { let (destination_iter, position) = destination.iter_position(); - for (i, dst) in destination_iter.enumerate() { + destination_iter.enumerate().for_each(|(i, dst)| { ptr::write(dst, f(i)); *position += 1; - } + }); } destination.into_inner() @@ -519,7 +556,7 @@ impl<'a, T, N: ArrayLength> From<&'a [T]> for &'a GenericArray { /// Length of the slice must be equal to the length of the array. #[inline] fn from(slice: &[T]) -> &GenericArray { - assert_eq!(slice.len(), N::to_usize()); + assert_eq!(slice.len(), N::USIZE); unsafe { &*(slice.as_ptr() as *const GenericArray) } } @@ -531,7 +568,7 @@ impl<'a, T, N: ArrayLength> From<&'a mut [T]> for &'a mut GenericArray /// Length of the slice must be equal to the length of the array. #[inline] fn from(slice: &mut [T]) -> &mut GenericArray { - assert_eq!(slice.len(), N::to_usize()); + assert_eq!(slice.len(), N::USIZE); unsafe { &mut *(slice.as_mut_ptr() as *mut GenericArray) } } @@ -555,34 +592,39 @@ impl GenericArray where N: ArrayLength, { - /// Creates a new `GenericArray` instance from an iterator with a known exact size. + /// Creates a new `GenericArray` instance from an iterator with a specific size. /// /// Returns `None` if the size is not equal to the number of elements in the `GenericArray`. pub fn from_exact_iter(iter: I) -> Option where I: IntoIterator, - ::IntoIter: ExactSizeIterator, { - let iter = iter.into_iter(); + let mut iter = iter.into_iter(); - if iter.len() == N::to_usize() { - unsafe { - let mut destination = ArrayBuilder::new(); + unsafe { + let mut destination = ArrayBuilder::new(); - { - let (destination_iter, position) = destination.iter_position(); + { + let (destination_iter, position) = destination.iter_position(); - for (dst, src) in destination_iter.zip(iter.into_iter()) { - ptr::write(dst, src); + destination_iter.zip(&mut iter).for_each(|(dst, src)| { + ptr::write(dst, src); - *position += 1; - } + *position += 1; + }); + + // The iterator produced fewer than `N` elements. + if *position != N::USIZE { + return None; } - Some(destination.into_inner()) + // The iterator produced more than `N` elements. + if iter.next().is_some() { + return None; + } } - } else { - None + + Some(destination.into_inner()) } } } @@ -592,9 +634,8 @@ where #[inline] #[doc(hidden)] pub unsafe fn transmute(a: A) -> B { - let b = ::core::ptr::read(&a as *const A as *const B); - ::core::mem::forget(a); - b + let a = ManuallyDrop::new(a); + ::core::ptr::read(&*a as *const A as *const B) } #[cfg(test)] @@ -616,7 +657,7 @@ mod test { #[test] fn test_assembly() { - use functional::*; + use crate::functional::*; let a = black_box(arr![i32; 1, 3, 5, 7]); let b = black_box(arr![i32; 2, 4, 6, 8]); diff --git a/vendor/generic-array/src/sequence.rs b/vendor/generic-array/src/sequence.rs index cec6601ba3..0119d3db67 100644 --- a/vendor/generic-array/src/sequence.rs +++ b/vendor/generic-array/src/sequence.rs @@ -1,8 +1,9 @@ //! Useful traits for manipulating sequences of data stored in `GenericArray`s use super::*; -use core::{mem, ptr}; use core::ops::{Add, Sub}; +use core::mem::MaybeUninit; +use core::ptr; use typenum::operator_aliases::*; /// Defines some sequence with an associated length and iteration capabilities. @@ -41,17 +42,15 @@ pub unsafe trait GenericSequence: Sized + IntoIterator { let (left_array_iter, left_position) = left.iter_position(); - FromIterator::from_iter( - left_array_iter - .zip(self.into_iter()) - .map(|(l, right_value)| { + FromIterator::from_iter(left_array_iter.zip(self.into_iter()).map( + |(l, right_value)| { let left_value = ptr::read(l); *left_position += 1; f(left_value, right_value) - }) - ) + }, + )) } } @@ -117,12 +116,15 @@ pub unsafe trait Lengthen: Sized + GenericSequence { /// /// Example: /// - /// ```ignore + /// ```rust + /// # use generic_array::{arr, sequence::Lengthen}; + /// # fn main() { /// let a = arr![i32; 1, 2, 3]; /// /// let b = a.append(4); /// /// assert_eq!(b, arr![i32; 1, 2, 3, 4]); + /// # } /// ``` fn append(self, last: T) -> Self::Longer; @@ -130,12 +132,15 @@ pub unsafe trait Lengthen: Sized + GenericSequence { /// /// Example: /// - /// ```ignore + /// ```rust + /// # use generic_array::{arr, sequence::Lengthen}; + /// # fn main() { /// let a = arr![i32; 1, 2, 3]; /// /// let b = a.prepend(4); /// /// assert_eq!(b, arr![i32; 4, 1, 2, 3]); + /// # } /// ``` fn prepend(self, first: T) -> Self::Longer; } @@ -152,26 +157,32 @@ pub unsafe trait Shorten: Sized + GenericSequence { /// /// Example: /// - /// ```ignore + /// ```rust + /// # use generic_array::{arr, sequence::Shorten}; + /// # fn main() { /// let a = arr![i32; 1, 2, 3, 4]; /// /// let (init, last) = a.pop_back(); /// /// assert_eq!(init, arr![i32; 1, 2, 3]); /// assert_eq!(last, 4); + /// # } /// ``` fn pop_back(self) -> (Self::Shorter, T); /// Returns a new array without the first element, and the first element. /// Example: /// - /// ```ignore + /// ```rust + /// # use generic_array::{arr, sequence::Shorten}; + /// # fn main() { /// let a = arr![i32; 1, 2, 3, 4]; /// /// let (head, tail) = a.pop_front(); /// /// assert_eq!(head, 1); /// assert_eq!(tail, arr![i32; 2, 3, 4]); + /// # } /// ``` fn pop_front(self) -> (T, Self::Shorter); } @@ -186,27 +197,35 @@ where type Longer = GenericArray>; fn append(self, last: T) -> Self::Longer { - let mut longer: Self::Longer = unsafe { mem::uninitialized() }; + let mut longer: MaybeUninit = MaybeUninit::uninit(); + + // Note this is *mut Self, so add(1) increments by the whole array + let out_ptr = longer.as_mut_ptr() as *mut Self; unsafe { - ptr::write(longer.as_mut_ptr() as *mut _, self); - ptr::write(&mut longer[N::to_usize()], last); - } + // write self first + ptr::write(out_ptr, self); + // increment past self, then write the last + ptr::write(out_ptr.add(1) as *mut T, last); - longer + longer.assume_init() + } } fn prepend(self, first: T) -> Self::Longer { - let mut longer: Self::Longer = unsafe { mem::uninitialized() }; + let mut longer: MaybeUninit = MaybeUninit::uninit(); - let longer_ptr = longer.as_mut_ptr(); + // Note this is *mut T, so add(1) increments by a single T + let out_ptr = longer.as_mut_ptr() as *mut T; unsafe { - ptr::write(longer_ptr as *mut _, first); - ptr::write(longer_ptr.offset(1) as *mut _, self); - } + // write the first at the start + ptr::write(out_ptr, first); + // increment past the first, then write self + ptr::write(out_ptr.add(1) as *mut Self, self); - longer + longer.assume_init() + } } } @@ -220,27 +239,26 @@ where type Shorter = GenericArray>; fn pop_back(self) -> (Self::Shorter, T) { - let init_ptr = self.as_ptr(); - let last_ptr = unsafe { init_ptr.offset(Sub1::::to_usize() as isize) }; + let whole = ManuallyDrop::new(self); - let init = unsafe { ptr::read(init_ptr as _) }; - let last = unsafe { ptr::read(last_ptr as _) }; + unsafe { + let init = ptr::read(whole.as_ptr() as _); + let last = ptr::read(whole.as_ptr().add(Sub1::::USIZE) as _); - mem::forget(self); - - (init, last) + (init, last) + } } fn pop_front(self) -> (T, Self::Shorter) { - let head_ptr = self.as_ptr(); - let tail_ptr = unsafe { head_ptr.offset(1) }; + // ensure this doesn't get dropped + let whole = ManuallyDrop::new(self); - let head = unsafe { ptr::read(head_ptr as _) }; - let tail = unsafe { ptr::read(tail_ptr as _) }; + unsafe { + let head = ptr::read(whole.as_ptr() as _); + let tail = ptr::read(whole.as_ptr().offset(1) as _); - mem::forget(self); - - (head, tail) + (head, tail) + } } } @@ -269,15 +287,55 @@ where type Second = GenericArray>; fn split(self) -> (Self::First, Self::Second) { - let head_ptr = self.as_ptr(); - let tail_ptr = unsafe { head_ptr.offset(K::to_usize() as isize) }; + unsafe { + // ensure this doesn't get dropped + let whole = ManuallyDrop::new(self); - let head = unsafe { ptr::read(head_ptr as _) }; - let tail = unsafe { ptr::read(tail_ptr as _) }; + let head = ptr::read(whole.as_ptr() as *const _); + let tail = ptr::read(whole.as_ptr().add(K::USIZE) as *const _); - mem::forget(self); + (head, tail) + } + } +} - (head, tail) +unsafe impl<'a, T, N, K> Split for &'a GenericArray +where + N: ArrayLength, + K: ArrayLength + 'static, + N: Sub, + Diff: ArrayLength, +{ + type First = &'a GenericArray; + type Second = &'a GenericArray>; + + fn split(self) -> (Self::First, Self::Second) { + unsafe { + let ptr_to_first: *const T = self.as_ptr(); + let head = &*(ptr_to_first as *const _); + let tail = &*(ptr_to_first.add(K::USIZE) as *const _); + (head, tail) + } + } +} + +unsafe impl<'a, T, N, K> Split for &'a mut GenericArray +where + N: ArrayLength, + K: ArrayLength + 'static, + N: Sub, + Diff: ArrayLength, +{ + type First = &'a mut GenericArray; + type Second = &'a mut GenericArray>; + + fn split(self) -> (Self::First, Self::Second) { + unsafe { + let ptr_to_first: *mut T = self.as_mut_ptr(); + let head = &mut *(ptr_to_first as *mut _); + let tail = &mut *(ptr_to_first.add(K::USIZE) as *mut _); + (head, tail) + } } } @@ -306,15 +364,17 @@ where type Output = GenericArray>; fn concat(self, rest: Self::Rest) -> Self::Output { - let mut output: Self::Output = unsafe { mem::uninitialized() }; + let mut output: MaybeUninit = MaybeUninit::uninit(); - let output_ptr = output.as_mut_ptr(); + let out_ptr = output.as_mut_ptr() as *mut Self; unsafe { - ptr::write(output_ptr as *mut _, self); - ptr::write(output_ptr.offset(N::to_usize() as isize) as *mut _, rest); - } + // write all of self to the pointer + ptr::write(out_ptr, self); + // increment past self, then write the rest + ptr::write(out_ptr.add(1) as *mut _, rest); - output + output.assume_init() + } } } diff --git a/vendor/generic-array/tests/iter.rs b/vendor/generic-array/tests/iter.rs index 19d198cb58..d96f984147 100644 --- a/vendor/generic-array/tests/iter.rs +++ b/vendor/generic-array/tests/iter.rs @@ -4,8 +4,28 @@ extern crate generic_array; use std::cell::Cell; use std::ops::Drop; -use generic_array::GenericArray; use generic_array::typenum::consts::U5; +use generic_array::GenericArray; + +#[test] +fn test_from_iterator() { + struct BadExact(usize); + + impl Iterator for BadExact { + type Item = usize; + fn next(&mut self) -> Option { + if self.0 == 1 { + return None; + } + self.0 -= 1; + Some(self.0) + } + } + impl ExactSizeIterator for BadExact { + fn len(&self) -> usize { self.0 } + } + assert!(GenericArray::::from_exact_iter(BadExact(5)).is_none()); +} #[test] fn test_into_iter_as_slice() { @@ -92,22 +112,37 @@ fn test_into_iter_flat_map() { assert!((0..5).flat_map(|i| arr![i32; 2 * i, 2 * i + 1]).eq(0..10)); } +#[test] +fn test_into_iter_fold() { + assert_eq!( + arr![i32; 1, 2, 3, 4].into_iter().fold(0, |sum, x| sum + x), + 10 + ); + + let mut iter = arr![i32; 0, 1, 2, 3, 4, 5].into_iter(); + + iter.next(); + iter.next_back(); + + assert_eq!(iter.clone().fold(0, |sum, x| sum + x), 10); + + assert_eq!(iter.rfold(0, |sum, x| sum + x), 10); +} + #[test] fn test_into_iter_drops() { struct R<'a> { - i: &'a Cell, + i: &'a Cell, } impl<'a> Drop for R<'a> { - fn drop(&mut self) { + fn drop(&mut self) { self.i.set(self.i.get() + 1); } } fn r(i: &Cell) -> R { - R { - i: i - } + R { i: i } } fn v(i: &Cell) -> GenericArray { @@ -161,4 +196,4 @@ fn assert_covariance() { i } } -*/ \ No newline at end of file +*/ diff --git a/vendor/generic-array/tests/mod.rs b/vendor/generic-array/tests/mod.rs index c103f417ab..fb1a35f2ca 100644 --- a/vendor/generic-array/tests/mod.rs +++ b/vendor/generic-array/tests/mod.rs @@ -4,10 +4,10 @@ extern crate generic_array; use core::cell::Cell; use core::ops::{Add, Drop}; -use generic_array::GenericArray; use generic_array::functional::*; use generic_array::sequence::*; -use generic_array::typenum::{U1, U3, U4, U97}; +use generic_array::typenum::{U0, U3, U4, U97}; +use generic_array::GenericArray; #[test] fn test() { @@ -88,8 +88,8 @@ fn test_from_mut_slice() { #[test] fn test_default() { - let arr = GenericArray::::default(); - assert_eq!(arr[0], 0); + let arr = GenericArray::::default(); + assert_eq!(arr.as_slice(), &[0, 0, 0, 0]); } #[test] @@ -112,7 +112,7 @@ fn test_empty_macro() { #[test] fn test_cmp() { - arr![u8; 0x00].cmp(&arr![u8; 0x00]); + let _ = arr![u8; 0x00].cmp(&arr![u8; 0x00]); } /// This test should cause a helpful compile error if uncommented. @@ -124,8 +124,8 @@ fn test_cmp() { mod impl_serde { extern crate serde_json; - use generic_array::GenericArray; use generic_array::typenum::U6; + use generic_array::GenericArray; #[test] fn test_serde_implementation() { @@ -175,23 +175,40 @@ fn test_from_iter() { assert_eq!(a, arr![i32; 11, 11, 11, 0]); } +#[allow(unused)] +#[derive(Debug, Copy, Clone)] +enum E { + V, + V2(i32), + V3 { h: bool, i: i32 }, +} + +#[allow(unused)] +#[derive(Debug, Copy, Clone)] +#[repr(C)] +#[repr(packed)] +struct Test { + t: u16, + s: u32, + mm: bool, + r: u16, + f: u16, + p: (), + o: u32, + ff: *const extern "C" fn(*const char) -> *const core::ffi::c_void, + l: *const core::ffi::c_void, + w: bool, + q: bool, + v: E, +} + #[test] fn test_sizes() { - #![allow(dead_code)] use core::mem::{size_of, size_of_val}; - #[derive(Debug, Copy, Clone)] - #[repr(C)] - #[repr(packed)] - struct Test { - t: u16, - s: u32, - r: u16, - f: u16, - o: u32, - } + assert_eq!(size_of::(), 8); - assert_eq!(size_of::(), 14); + assert_eq!(size_of::(), 25 + size_of::() * 2); assert_eq!(size_of_val(&arr![u8; 1, 2, 3]), size_of::() * 3); assert_eq!(size_of_val(&arr![u32; 1]), size_of::() * 1); @@ -200,6 +217,15 @@ fn test_sizes() { assert_eq!(size_of::>(), size_of::() * 97); } +#[test] +fn test_alignment() { + use core::mem::align_of; + + assert_eq!(align_of::>(), align_of::<[u32; 0]>()); + assert_eq!(align_of::>(), align_of::<[u32; 3]>()); + assert_eq!(align_of::>(), align_of::<[Test; 3]>()); +} + #[test] fn test_append() { let a = arr![i32; 1, 2, 3]; @@ -248,19 +274,51 @@ fn test_split() { assert_eq!(f, arr![i32; 3, 4]); } +#[test] +fn test_split_ref() { + let a = arr![i32; 1, 2, 3, 4]; + let a_ref = &a; + + let (b_ref, c_ref) = a_ref.split(); + + assert_eq!(b_ref, &arr![i32; 1]); + assert_eq!(c_ref, &arr![i32; 2, 3, 4]); + + let (e_ref, f_ref) = a_ref.split(); + + assert_eq!(e_ref, &arr![i32; 1, 2]); + assert_eq!(f_ref, &arr![i32; 3, 4]); +} + +#[test] +fn test_split_mut() { + let mut a = arr![i32; 1, 2, 3, 4]; + let a_ref = &mut a; + + let (b_ref, c_ref) = a_ref.split(); + + assert_eq!(b_ref, &mut arr![i32; 1]); + assert_eq!(c_ref, &mut arr![i32; 2, 3, 4]); + + let (e_ref, f_ref) = a_ref.split(); + + assert_eq!(e_ref, &mut arr![i32; 1, 2]); + assert_eq!(f_ref, &mut arr![i32; 3, 4]); +} + #[test] fn test_concat() { let a = arr![i32; 1, 2]; - let b = arr![i32; 3, 4]; + let b = arr![i32; 3, 4, 5]; let c = a.concat(b); - assert_eq!(c, arr![i32; 1, 2, 3, 4]); + assert_eq!(c, arr![i32; 1, 2, 3, 4, 5]); let (d, e) = c.split(); - assert_eq!(d, arr![i32; 1]); - assert_eq!(e, arr![i32; 2, 3, 4]); + assert_eq!(d, arr![i32; 1, 2]); + assert_eq!(e, arr![i32; 3, 4, 5]); } #[test] @@ -285,3 +343,37 @@ fn test_sum() { assert_eq!(a, 10); } + +#[test] +fn test_as_ref() { + let a = arr![i32; 1, 2, 3, 4]; + let a_ref: &[i32; 4] = a.as_ref(); + assert_eq!(a_ref, &[1, 2, 3, 4]); +} + +#[test] +fn test_as_mut() { + let mut a = arr![i32; 1, 2, 3, 4]; + let a_mut: &mut [i32; 4] = a.as_mut(); + assert_eq!(a_mut, &mut [1, 2, 3, 4]); + a_mut[2] = 0; + assert_eq!(a_mut, &mut [1, 2, 0, 4]); + assert_eq!(a, arr![i32; 1, 2, 0, 4]); +} + +#[test] +fn test_from_array_ref() { + let a = arr![i32; 1, 2, 3, 4]; + let a_ref: &[i32; 4] = a.as_ref(); + let a_from: &GenericArray = a_ref.into(); + assert_eq!(&a, a_from); +} + +#[test] +fn test_from_array_mut() { + let mut a = arr![i32; 1, 2, 3, 4]; + let mut a_copy = a; + let a_mut: &mut [i32; 4] = a.as_mut(); + let a_from: &mut GenericArray = a_mut.into(); + assert_eq!(&mut a_copy, a_from); +} diff --git a/vendor/getrandom/.cargo-checksum.json b/vendor/getrandom-0.1.14/.cargo-checksum.json similarity index 100% rename from vendor/getrandom/.cargo-checksum.json rename to vendor/getrandom-0.1.14/.cargo-checksum.json diff --git a/vendor/getrandom/CHANGELOG.md b/vendor/getrandom-0.1.14/CHANGELOG.md similarity index 100% rename from vendor/getrandom/CHANGELOG.md rename to vendor/getrandom-0.1.14/CHANGELOG.md diff --git a/vendor/getrandom/Cargo.toml b/vendor/getrandom-0.1.14/Cargo.toml similarity index 100% rename from vendor/getrandom/Cargo.toml rename to vendor/getrandom-0.1.14/Cargo.toml diff --git a/vendor/getrandom/LICENSE-APACHE b/vendor/getrandom-0.1.14/LICENSE-APACHE similarity index 100% rename from vendor/getrandom/LICENSE-APACHE rename to vendor/getrandom-0.1.14/LICENSE-APACHE diff --git a/vendor/getrandom/LICENSE-MIT b/vendor/getrandom-0.1.14/LICENSE-MIT similarity index 100% rename from vendor/getrandom/LICENSE-MIT rename to vendor/getrandom-0.1.14/LICENSE-MIT diff --git a/vendor/getrandom/README.md b/vendor/getrandom-0.1.14/README.md similarity index 100% rename from vendor/getrandom/README.md rename to vendor/getrandom-0.1.14/README.md diff --git a/vendor/getrandom/benches/mod.rs b/vendor/getrandom-0.1.14/benches/mod.rs similarity index 100% rename from vendor/getrandom/benches/mod.rs rename to vendor/getrandom-0.1.14/benches/mod.rs diff --git a/vendor/getrandom/build.rs b/vendor/getrandom-0.1.14/build.rs similarity index 100% rename from vendor/getrandom/build.rs rename to vendor/getrandom-0.1.14/build.rs diff --git a/vendor/getrandom/src/bsd_arandom.rs b/vendor/getrandom-0.1.14/src/bsd_arandom.rs similarity index 100% rename from vendor/getrandom/src/bsd_arandom.rs rename to vendor/getrandom-0.1.14/src/bsd_arandom.rs diff --git a/vendor/getrandom/src/cloudabi.rs b/vendor/getrandom-0.1.14/src/cloudabi.rs similarity index 100% rename from vendor/getrandom/src/cloudabi.rs rename to vendor/getrandom-0.1.14/src/cloudabi.rs diff --git a/vendor/getrandom/src/dummy.rs b/vendor/getrandom-0.1.14/src/dummy.rs similarity index 100% rename from vendor/getrandom/src/dummy.rs rename to vendor/getrandom-0.1.14/src/dummy.rs diff --git a/vendor/getrandom/src/error.rs b/vendor/getrandom-0.1.14/src/error.rs similarity index 100% rename from vendor/getrandom/src/error.rs rename to vendor/getrandom-0.1.14/src/error.rs diff --git a/vendor/getrandom/src/error_impls.rs b/vendor/getrandom-0.1.14/src/error_impls.rs similarity index 100% rename from vendor/getrandom/src/error_impls.rs rename to vendor/getrandom-0.1.14/src/error_impls.rs diff --git a/vendor/getrandom/src/fuchsia.rs b/vendor/getrandom-0.1.14/src/fuchsia.rs similarity index 100% rename from vendor/getrandom/src/fuchsia.rs rename to vendor/getrandom-0.1.14/src/fuchsia.rs diff --git a/vendor/getrandom/src/ios.rs b/vendor/getrandom-0.1.14/src/ios.rs similarity index 100% rename from vendor/getrandom/src/ios.rs rename to vendor/getrandom-0.1.14/src/ios.rs diff --git a/vendor/getrandom/src/lib.rs b/vendor/getrandom-0.1.14/src/lib.rs similarity index 100% rename from vendor/getrandom/src/lib.rs rename to vendor/getrandom-0.1.14/src/lib.rs diff --git a/vendor/getrandom/src/linux_android.rs b/vendor/getrandom-0.1.14/src/linux_android.rs similarity index 100% rename from vendor/getrandom/src/linux_android.rs rename to vendor/getrandom-0.1.14/src/linux_android.rs diff --git a/vendor/getrandom/src/macos.rs b/vendor/getrandom-0.1.14/src/macos.rs similarity index 100% rename from vendor/getrandom/src/macos.rs rename to vendor/getrandom-0.1.14/src/macos.rs diff --git a/vendor/getrandom/src/openbsd.rs b/vendor/getrandom-0.1.14/src/openbsd.rs similarity index 100% rename from vendor/getrandom/src/openbsd.rs rename to vendor/getrandom-0.1.14/src/openbsd.rs diff --git a/vendor/getrandom/src/rdrand.rs b/vendor/getrandom-0.1.14/src/rdrand.rs similarity index 100% rename from vendor/getrandom/src/rdrand.rs rename to vendor/getrandom-0.1.14/src/rdrand.rs diff --git a/vendor/getrandom/src/solaris_illumos.rs b/vendor/getrandom-0.1.14/src/solaris_illumos.rs similarity index 100% rename from vendor/getrandom/src/solaris_illumos.rs rename to vendor/getrandom-0.1.14/src/solaris_illumos.rs diff --git a/vendor/getrandom/src/use_file.rs b/vendor/getrandom-0.1.14/src/use_file.rs similarity index 100% rename from vendor/getrandom/src/use_file.rs rename to vendor/getrandom-0.1.14/src/use_file.rs diff --git a/vendor/getrandom/src/util.rs b/vendor/getrandom-0.1.14/src/util.rs similarity index 100% rename from vendor/getrandom/src/util.rs rename to vendor/getrandom-0.1.14/src/util.rs diff --git a/vendor/getrandom/src/util_libc.rs b/vendor/getrandom-0.1.14/src/util_libc.rs similarity index 100% rename from vendor/getrandom/src/util_libc.rs rename to vendor/getrandom-0.1.14/src/util_libc.rs diff --git a/vendor/getrandom/src/vxworks.rs b/vendor/getrandom-0.1.14/src/vxworks.rs similarity index 100% rename from vendor/getrandom/src/vxworks.rs rename to vendor/getrandom-0.1.14/src/vxworks.rs diff --git a/vendor/getrandom/src/wasi.rs b/vendor/getrandom-0.1.14/src/wasi.rs similarity index 100% rename from vendor/getrandom/src/wasi.rs rename to vendor/getrandom-0.1.14/src/wasi.rs diff --git a/vendor/getrandom/src/wasm32_bindgen.rs b/vendor/getrandom-0.1.14/src/wasm32_bindgen.rs similarity index 100% rename from vendor/getrandom/src/wasm32_bindgen.rs rename to vendor/getrandom-0.1.14/src/wasm32_bindgen.rs diff --git a/vendor/getrandom/src/wasm32_stdweb.rs b/vendor/getrandom-0.1.14/src/wasm32_stdweb.rs similarity index 100% rename from vendor/getrandom/src/wasm32_stdweb.rs rename to vendor/getrandom-0.1.14/src/wasm32_stdweb.rs diff --git a/vendor/getrandom/src/windows.rs b/vendor/getrandom-0.1.14/src/windows.rs similarity index 100% rename from vendor/getrandom/src/windows.rs rename to vendor/getrandom-0.1.14/src/windows.rs diff --git a/vendor/getrandom/src/windows_uwp.rs b/vendor/getrandom-0.1.14/src/windows_uwp.rs similarity index 100% rename from vendor/getrandom/src/windows_uwp.rs rename to vendor/getrandom-0.1.14/src/windows_uwp.rs diff --git a/vendor/getrandom/tests/common.rs b/vendor/getrandom-0.1.14/tests/common.rs similarity index 100% rename from vendor/getrandom/tests/common.rs rename to vendor/getrandom-0.1.14/tests/common.rs diff --git a/vendor/hashbrown/.cargo-checksum.json b/vendor/hashbrown/.cargo-checksum.json index 53ccb357be..4811ac7d60 100644 --- a/vendor/hashbrown/.cargo-checksum.json +++ b/vendor/hashbrown/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"41956c7543a3c6688ef073100128201fb25b105c244c955f61a5970f82410e89","Cargo.toml":"b6a0baee0e7d34a00841ab3716bae87d723ede5cfe3f1f353474748e17100147","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"66f79e21927df369fccac1cfff147c6fe66e15b4fc003851a008b9cbac831ea9","benches/bench.rs":"a3f8426559ebf68d93e37edee0bf83c28f18572b394b22e47dbff33e25cac403","build.rs":"85096ca579db79e502f0af4521b62820b2b0efcfe0f3d4de2f8ec4965f13b61f","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"d4fbca4db924925548f8dab8eb94cf4a3955a53c5e1ff15f59c460546c394034","src/external_trait_impls/rayon/map.rs":"eee0d42bd8cd347d49cfb1332f15297ca63b864c3690299a3ccd6d52c22c67de","src/external_trait_impls/rayon/mod.rs":"156de9c1ad0123334ea3b7e5a17444faf1b8bf971aa88a1f23e2f2d1c3021141","src/external_trait_impls/rayon/raw.rs":"d1b2415a4c3c42279f99a23bcf45c80ddb9a641c7f7974d42ed4d55f57bf6854","src/external_trait_impls/rayon/set.rs":"59afc7b1cdc985a85952d456e34eada4ca2fedf90d2a14dccf98a69f8f496137","src/external_trait_impls/serde.rs":"9306fb6e0e339398dc23ba9e7400a9a28d713df248e8b260e3d4dc44f799e101","src/lib.rs":"d8d7f9de34b79cb3c8187ff74a4c91d99386da1c40486b0d3c762b70dc5626d9","src/macros.rs":"0b1e9a55e8f5232b82f7e56f352a98904b35ddfca015377cf71daa31939baabf","src/map.rs":"57a1da730c123fdd9dae08a90ca14c3c979627d0a92d102b6f3e970a0fdbbbd0","src/raw/bitmask.rs":"05e72c64957af7383001ca43a827cc5b3a8a39d00fac332ecea2fd7d2704099c","src/raw/generic.rs":"03d4d5cf5241dd32cfee55986381048bf5432957cdb7c48efd85538c0cf0523d","src/raw/mod.rs":"f3b5bc990cf032717e7308f509a9f93e97f8aba055279cef84281337f91b37f8","src/raw/sse2.rs":"963b7be51552eb18ea24eec8b8d8882d98ba0e798eef46f1813eb42311422ce3","src/rustc_entry.rs":"64e47870015a9f152340017b79e2262e5c70d0f42b4fc2dfa48dd25ca70465f7","src/scopeguard.rs":"337cde60c9e1109cd19d4fa53529014cef1e3d5900dffde82f647881df1505f7","src/set.rs":"e27abbe3863362c3d63899176a54443fb7df9598ebd250d73c6d80aec811e994","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/rayon.rs":"2286707a87b139f41902c82488c355b9fb402a3e734f392f3a73e87b9b932795","tests/serde.rs":"eed27382c0e43f67e402cd9eed20dea23ef5582e1a26a183e708ca9217a559e0","tests/set.rs":"374bd312c01a01cf8953bbbc9494f431b260c2657d7c79cc250e977b869a76ad"},"package":"e91b62f79061a0bc2e046024cb7ba44b08419ed238ecbd9adbd787434b9e8c25"} \ No newline at end of file +{"files":{"CHANGELOG.md":"32cf1068a2d6d82879e998892e4f474812bba744101404c4c70e1f9768f589de","Cargo.toml":"52c7504a9ff4eac66a7a8a20e7853d0316f73df711a559eb390477a6d05d8eac","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ff8f68cb076caf8cefe7a6430d4ac086ce6af2ca8ce2c4e5a2004d4552ef52a2","README.md":"66f79e21927df369fccac1cfff147c6fe66e15b4fc003851a008b9cbac831ea9","benches/bench.rs":"a3f8426559ebf68d93e37edee0bf83c28f18572b394b22e47dbff33e25cac403","clippy.toml":"7535949f908c6d9aea4f9a9f3a7625552c93fc29e963d059d40f4def9d77ea7b","src/external_trait_impls/mod.rs":"d69528827794524cfd9acbeacc1ac4f6131e3c7574311e6d919f818f65fbff07","src/external_trait_impls/rayon/helpers.rs":"d4fbca4db924925548f8dab8eb94cf4a3955a53c5e1ff15f59c460546c394034","src/external_trait_impls/rayon/map.rs":"eee0d42bd8cd347d49cfb1332f15297ca63b864c3690299a3ccd6d52c22c67de","src/external_trait_impls/rayon/mod.rs":"156de9c1ad0123334ea3b7e5a17444faf1b8bf971aa88a1f23e2f2d1c3021141","src/external_trait_impls/rayon/raw.rs":"d1b2415a4c3c42279f99a23bcf45c80ddb9a641c7f7974d42ed4d55f57bf6854","src/external_trait_impls/rayon/set.rs":"59afc7b1cdc985a85952d456e34eada4ca2fedf90d2a14dccf98a69f8f496137","src/external_trait_impls/serde.rs":"9306fb6e0e339398dc23ba9e7400a9a28d713df248e8b260e3d4dc44f799e101","src/lib.rs":"a455a0387b0133114247380659c2825713a4b91ef38a45f737007b47a2c30ee4","src/macros.rs":"0b1e9a55e8f5232b82f7e56f352a98904b35ddfca015377cf71daa31939baabf","src/map.rs":"51ec9f24aef15b80ee26a9f50c954ea5863aefda60ce75ae3646f378ab03163f","src/raw/bitmask.rs":"05e72c64957af7383001ca43a827cc5b3a8a39d00fac332ecea2fd7d2704099c","src/raw/generic.rs":"28da6bb3a722dcaa26cb5aba9e028111f32212dc9ce0c323e8f39ff5f367385e","src/raw/mod.rs":"723a66ce495d3a60b0039d32adf31ecf2626d6768d5ed61423fa40b3423df219","src/raw/sse2.rs":"ff332a9104558fe6a86b85ab975b6f43d4a042c634d5dc6cf70cf1d71d97ad7d","src/rustc_entry.rs":"64e47870015a9f152340017b79e2262e5c70d0f42b4fc2dfa48dd25ca70465f7","src/scopeguard.rs":"337cde60c9e1109cd19d4fa53529014cef1e3d5900dffde82f647881df1505f7","src/set.rs":"4ec68cf40a41bbc50da754047893640c62c55f612e03c43e3e3e837a23defc6d","tests/hasher.rs":"9a8fdf67e4415618e16729969c386eefe71408cded5d46cf7b67d969276a3452","tests/rayon.rs":"2286707a87b139f41902c82488c355b9fb402a3e734f392f3a73e87b9b932795","tests/serde.rs":"eed27382c0e43f67e402cd9eed20dea23ef5582e1a26a183e708ca9217a559e0","tests/set.rs":"374bd312c01a01cf8953bbbc9494f431b260c2657d7c79cc250e977b869a76ad"},"package":"00d63df3d41950fb462ed38308eea019113ad1508da725bbedcd0fa5a85ef5f7"} \ No newline at end of file diff --git a/vendor/hashbrown/CHANGELOG.md b/vendor/hashbrown/CHANGELOG.md index f95632d23b..e349925555 100644 --- a/vendor/hashbrown/CHANGELOG.md +++ b/vendor/hashbrown/CHANGELOG.md @@ -7,6 +7,24 @@ and this project adheres to [Semantic Versioning](http://semver.org/). ## [Unreleased] +## [v0.9.0] - 2020-09-03 + +### Fixed +- `drain_filter` now removes and yields items that do match the predicate, + rather than items that don't. This is a **breaking change** to match the + behavior of the `drain_filter` methods in `std`. (#187) + +### Added +- Added `replace_entry_with` to `OccupiedEntry`, and `and_replace_entry_with` to `Entry`. (#190) +- Implemented `FusedIterator` and `size_hint` for `DrainFilter`. (#188) + +### Changed +- The minimum Rust version has been bumped to 1.36 (due to `crossbeam` dependency). (#193) +- Updated `ahash` dependency to 0.4. (#198) +- `HashMap::with_hasher` and `HashSet::with_hasher` are now `const fn`. (#195) +- Removed `T: Hash + Eq` and `S: BuildHasher` bounds on `HashSet::new`, + `with_capacity`, `with_hasher`, and `with_capacity_and_hasher`. (#185) + ## [v0.8.2] - 2020-08-08 ### Changed @@ -231,7 +249,8 @@ This release was _yanked_ due to a breaking change for users of `no-default-feat - Initial release -[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...HEAD +[Unreleased]: https://github.com/rust-lang/hashbrown/compare/v0.9.0...HEAD +[v0.9.0]: https://github.com/rust-lang/hashbrown/compare/v0.8.2...v0.9.0 [v0.8.2]: https://github.com/rust-lang/hashbrown/compare/v0.8.1...v0.8.2 [v0.8.1]: https://github.com/rust-lang/hashbrown/compare/v0.8.0...v0.8.1 [v0.8.0]: https://github.com/rust-lang/hashbrown/compare/v0.7.2...v0.8.0 diff --git a/vendor/hashbrown/Cargo.toml b/vendor/hashbrown/Cargo.toml index 0a09938108..2367e873ad 100644 --- a/vendor/hashbrown/Cargo.toml +++ b/vendor/hashbrown/Cargo.toml @@ -13,9 +13,8 @@ [package] edition = "2018" name = "hashbrown" -version = "0.8.2" +version = "0.9.0" authors = ["Amanieu d'Antras "] -build = "build.rs" exclude = [".travis.yml", "bors.toml", "/ci/*"] description = "A Rust port of Google's SwissTable hash map" readme = "README.md" @@ -26,7 +25,7 @@ repository = "https://github.com/rust-lang/hashbrown" [package.metadata.docs.rs] features = ["nightly", "rayon", "serde", "raw"] [dependencies.ahash] -version = "0.3.2" +version = "0.4.4" optional = true default-features = false @@ -70,8 +69,6 @@ version = "=1.0" [dev-dependencies.serde_test] version = "1.0" -[build-dependencies.autocfg] -version = "1" [features] ahash-compile-time-rng = ["ahash/compile-time-rng"] diff --git a/vendor/hashbrown/build.rs b/vendor/hashbrown/build.rs deleted file mode 100644 index 818b20182f..0000000000 --- a/vendor/hashbrown/build.rs +++ /dev/null @@ -1,9 +0,0 @@ -fn main() { - println!("cargo:rerun-if-changed=build.rs"); - let nightly = std::env::var_os("CARGO_FEATURE_NIGHTLY").is_some(); - let has_stable_alloc = || autocfg::new().probe_rustc_version(1, 36); - - if nightly || has_stable_alloc() { - autocfg::emit("has_extern_crate_alloc") - } -} diff --git a/vendor/hashbrown/src/lib.rs b/vendor/hashbrown/src/lib.rs index 34b01d5d1d..3aff40a4ff 100644 --- a/vendor/hashbrown/src/lib.rs +++ b/vendor/hashbrown/src/lib.rs @@ -12,16 +12,7 @@ #![no_std] #![cfg_attr( feature = "nightly", - feature( - alloc_layout_extra, - allocator_api, - ptr_offset_from, - test, - core_intrinsics, - dropck_eyepatch, - min_specialization, - extend_one, - ) + feature(test, core_intrinsics, dropck_eyepatch, min_specialization, extend_one) )] #![allow( clippy::doc_markdown, @@ -36,11 +27,8 @@ #[macro_use] extern crate std; -#[cfg(has_extern_crate_alloc)] #[cfg_attr(test, macro_use)] extern crate alloc; -#[cfg(not(has_extern_crate_alloc))] -extern crate std as alloc; #[cfg(feature = "nightly")] #[cfg(doctest)] diff --git a/vendor/hashbrown/src/map.rs b/vendor/hashbrown/src/map.rs index 5ac8528c72..380d71a1d9 100644 --- a/vendor/hashbrown/src/map.rs +++ b/vendor/hashbrown/src/map.rs @@ -275,7 +275,7 @@ impl HashMap { /// /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html #[cfg_attr(feature = "inline-more", inline)] - pub fn with_hasher(hash_builder: S) -> Self { + pub const fn with_hasher(hash_builder: S) -> Self { Self { hash_builder, table: RawTable::new(), @@ -584,13 +584,13 @@ impl HashMap { } } - /// Drains elements which are false under the given predicate, + /// Drains elements which are true under the given predicate, /// and returns an iterator over the removed items. /// - /// In other words, move all pairs `(k, v)` such that `f(&k,&mut v)` returns `false` out + /// In other words, move all pairs `(k, v)` such that `f(&k,&mut v)` returns `true` out /// into another iterator. /// - /// When the returned DrainedFilter is dropped, the elements that don't satisfy + /// When the returned DrainedFilter is dropped, any remaining elements that satisfy /// the predicate are dropped from the table. /// /// # Examples @@ -598,10 +598,16 @@ impl HashMap { /// ``` /// use hashbrown::HashMap; /// - /// let mut map: HashMap = (0..8).map(|x|(x, x*10)).collect(); - /// let drained = map.drain_filter(|&k, _| k % 2 == 0); - /// assert_eq!(drained.count(), 4); - /// assert_eq!(map.len(), 4); + /// let mut map: HashMap = (0..8).map(|x| (x, x)).collect(); + /// let drained: HashMap = map.drain_filter(|k, _v| k % 2 == 0).collect(); + /// + /// let mut evens = drained.keys().cloned().collect::>(); + /// let mut odds = map.keys().cloned().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, K, V, F> @@ -764,6 +770,7 @@ where let hash = make_hash(&self.hash_builder, &key); if let Some(elem) = self.table.find(hash, |q| q.0.eq(&key)) { Entry::Occupied(OccupiedEntry { + hash, key: Some(key), elem, table: self, @@ -840,7 +847,7 @@ where Some(item) => unsafe { let &(ref key, ref value) = item.as_ref(); Some((key, value)) - } + }, None => None, } } @@ -880,7 +887,7 @@ where Some(item) => unsafe { let &mut (ref key, ref mut value) = item.as_mut(); Some((key, value)) - } + }, None => None, } } @@ -1384,8 +1391,15 @@ where fn next(&mut self) -> Option { self.inner.next(&mut self.f) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } } +impl FusedIterator for DrainFilter<'_, K, V, F> where F: FnMut(&K, &mut V) -> bool {} + /// Portions of `DrainFilter` shared with `set::DrainFilter` pub(super) struct DrainFilterInner<'a, K, V> { pub iter: RawIter<(K, V)>, @@ -1401,7 +1415,7 @@ impl DrainFilterInner<'_, K, V> { unsafe { while let Some(item) = self.iter.next() { let &mut (ref key, ref mut value) = item.as_mut(); - if !f(key, value) { + if f(key, value) { return Some(self.table.remove(item)); } } @@ -1443,7 +1457,7 @@ pub struct RawEntryBuilderMut<'a, K, V, S> { /// [`RawEntryBuilderMut`]: struct.RawEntryBuilderMut.html pub enum RawEntryMut<'a, K, V, S> { /// An occupied entry. - Occupied(RawOccupiedEntryMut<'a, K, V>), + Occupied(RawOccupiedEntryMut<'a, K, V, S>), /// A vacant entry. Vacant(RawVacantEntryMut<'a, K, V, S>), } @@ -1452,21 +1466,24 @@ pub enum RawEntryMut<'a, K, V, S> { /// It is part of the [`RawEntryMut`] enum. /// /// [`RawEntryMut`]: enum.RawEntryMut.html -pub struct RawOccupiedEntryMut<'a, K, V> { +pub struct RawOccupiedEntryMut<'a, K, V, S> { elem: Bucket<(K, V)>, table: &'a mut RawTable<(K, V)>, + hash_builder: &'a S, } -unsafe impl Send for RawOccupiedEntryMut<'_, K, V> +unsafe impl Send for RawOccupiedEntryMut<'_, K, V, S> where K: Send, V: Send, + S: Sync, { } -unsafe impl Sync for RawOccupiedEntryMut<'_, K, V> +unsafe impl Sync for RawOccupiedEntryMut<'_, K, V, S> where K: Sync, V: Sync, + S: Sync, { } @@ -1535,6 +1552,7 @@ impl<'a, K, V, S> RawEntryBuilderMut<'a, K, V, S> { Some(elem) => RawEntryMut::Occupied(RawOccupiedEntryMut { elem, table: &mut self.map.table, + hash_builder: &self.map.hash_builder, }), None => RawEntryMut::Vacant(RawVacantEntryMut { table: &mut self.map.table, @@ -1579,7 +1597,7 @@ impl<'a, K, V, S> RawEntryBuilder<'a, K, V, S> { Some(item) => unsafe { let &(ref key, ref value) = item.as_ref(); Some((key, value)) - } + }, None => None, } } @@ -1609,7 +1627,7 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { /// assert_eq!(entry.remove_entry(), ("horseyland", 37)); /// ``` #[cfg_attr(feature = "inline-more", inline)] - pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V> + pub fn insert(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S> where K: Hash, S: BuildHasher, @@ -1721,9 +1739,75 @@ impl<'a, K, V, S> RawEntryMut<'a, K, V, S> { RawEntryMut::Vacant(entry) => RawEntryMut::Vacant(entry), } } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::RawEntryMut; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// RawEntryMut::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// }, + /// RawEntryMut::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .raw_entry_mut() + /// .from_key("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// RawEntryMut::Vacant(_) => {}, + /// RawEntryMut::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + RawEntryMut::Occupied(entry) => entry.replace_entry_with(f), + RawEntryMut::Vacant(_) => self, + } + } } -impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { +impl<'a, K, V, S> RawOccupiedEntryMut<'a, K, V, S> { /// Gets a reference to the key in the entry. #[cfg_attr(feature = "inline-more", inline)] pub fn key(&self) -> &K { @@ -1813,6 +1897,32 @@ impl<'a, K, V> RawOccupiedEntryMut<'a, K, V> { pub fn remove_entry(self) -> (K, V) { unsafe { self.table.remove(self.elem) } } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> RawEntryMut<'a, K, V, S> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let still_occupied = self + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + f(&key, value).map(|new_value| (key, new_value)) + }); + + if still_occupied { + RawEntryMut::Occupied(self) + } else { + RawEntryMut::Vacant(RawVacantEntryMut { + table: self.table, + hash_builder: self.hash_builder, + }) + } + } + } } impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { @@ -1862,7 +1972,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { } #[cfg_attr(feature = "inline-more", inline)] - fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V> + fn insert_entry(self, key: K, value: V) -> RawOccupiedEntryMut<'a, K, V, S> where K: Hash, S: BuildHasher, @@ -1877,6 +1987,7 @@ impl<'a, K, V, S> RawVacantEntryMut<'a, K, V, S> { RawOccupiedEntryMut { elem, table: self.table, + hash_builder: self.hash_builder, } } } @@ -1896,7 +2007,7 @@ impl Debug for RawEntryMut<'_, K, V, S> { } } -impl Debug for RawOccupiedEntryMut<'_, K, V> { +impl Debug for RawOccupiedEntryMut<'_, K, V, S> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.debug_struct("RawOccupiedEntryMut") .field("key", self.key()) @@ -1945,6 +2056,7 @@ impl Debug for Entry<'_, K, V, S> { /// /// [`Entry`]: enum.Entry.html pub struct OccupiedEntry<'a, K, V, S> { + hash: u64, key: Option, elem: Bucket<(K, V)>, table: &'a mut HashMap, @@ -2049,7 +2161,7 @@ impl<'a, K, V> Iterator for Iter<'a, K, V> { Some(x) => unsafe { let r = x.as_ref(); Some((&r.0, &r.1)) - } + }, None => None, } } @@ -2077,7 +2189,7 @@ impl<'a, K, V> Iterator for IterMut<'a, K, V> { Some(x) => unsafe { let r = x.as_mut(); Some((&r.0, &mut r.1)) - } + }, None => None, } } @@ -2406,6 +2518,71 @@ impl<'a, K, V, S> Entry<'a, K, V, S> { Entry::Vacant(entry) => Entry::Vacant(entry), } } + + /// Provides shared access to the key and owned access to the value of + /// an occupied entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| panic!()); + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// map.insert("poneyland", 42); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }); + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = map + /// .entry("poneyland") + /// .and_replace_entry_with(|_k, _v| None); + /// + /// match entry { + /// Entry::Vacant(e) => assert_eq!(e.key(), &"poneyland"), + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn and_replace_entry_with(self, f: F) -> Self + where + F: FnOnce(&K, V) -> Option, + { + match self { + Entry::Occupied(entry) => entry.replace_entry_with(f), + Entry::Vacant(_) => self, + } + } } impl<'a, K, V: Default, S> Entry<'a, K, V, S> { @@ -2660,6 +2837,85 @@ impl<'a, K, V, S> OccupiedEntry<'a, K, V, S> { let entry = unsafe { self.elem.as_mut() }; mem::replace(&mut entry.0, self.key.unwrap()) } + + /// Provides shared access to the key and owned access to the value of + /// the entry and allows to replace or remove it based on the + /// value of the returned option. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashMap; + /// use hashbrown::hash_map::Entry; + /// + /// let mut map: HashMap<&str, u32> = HashMap::new(); + /// map.insert("poneyland", 42); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => { + /// e.replace_entry_with(|k, v| { + /// assert_eq!(k, &"poneyland"); + /// assert_eq!(v, 42); + /// Some(v + 1) + /// }) + /// } + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Occupied(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// assert_eq!(e.get(), &43); + /// } + /// Entry::Vacant(_) => panic!(), + /// } + /// + /// assert_eq!(map["poneyland"], 43); + /// + /// let entry = match map.entry("poneyland") { + /// Entry::Occupied(e) => e.replace_entry_with(|_k, _v| None), + /// Entry::Vacant(_) => panic!(), + /// }; + /// + /// match entry { + /// Entry::Vacant(e) => { + /// assert_eq!(e.key(), &"poneyland"); + /// } + /// Entry::Occupied(_) => panic!(), + /// } + /// + /// assert!(!map.contains_key("poneyland")); + /// ``` + #[cfg_attr(feature = "inline-more", inline)] + pub fn replace_entry_with(self, f: F) -> Entry<'a, K, V, S> + where + F: FnOnce(&K, V) -> Option, + { + unsafe { + let mut spare_key = None; + + self.table + .table + .replace_bucket_with(self.elem.clone(), |(key, value)| { + if let Some(new_value) = f(&key, value) { + Some((key, new_value)) + } else { + spare_key = Some(key); + None + } + }); + + if let Some(key) = spare_key { + Entry::Vacant(VacantEntry { + hash: self.hash, + key, + table: self.table, + }) + } else { + Entry::Occupied(self) + } + } + } } impl<'a, K, V, S> VacantEntry<'a, K, V, S> { @@ -2738,6 +2994,7 @@ impl<'a, K, V, S> VacantEntry<'a, K, V, S> { make_hash(hash_builder, &x.0) }); OccupiedEntry { + hash: self.hash, key: None, elem, table: self.table, @@ -3745,6 +4002,233 @@ mod test_map { assert_eq!(a[key], value); } + #[test] + fn test_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).insert(value).replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.entry(key) { + Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + Vacant(_) => panic!(), + }; + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a.entry(key).and_replace_entry_with(|_, _| panic!()); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a.entry(key).and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + Vacant(e) => assert_eq!(e.key(), &key), + Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_occupied_entry_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .insert(key, value) + .replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = match a.raw_entry_mut().from_key(&key) { + RawEntryMut::Occupied(e) => e.replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }), + RawEntryMut::Vacant(_) => panic!(), + }; + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_raw_entry_and_replace_entry_with() { + let mut a = HashMap::new(); + + let key = "a key"; + let value = "an initial value"; + let new_value = "a new value"; + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|_, _| panic!()); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + a.insert(key, value); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, value); + Some(new_value) + }); + + match entry { + RawEntryMut::Occupied(e) => { + assert_eq!(e.key(), &key); + assert_eq!(e.get(), &new_value); + } + RawEntryMut::Vacant(_) => panic!(), + } + + assert_eq!(a[key], new_value); + assert_eq!(a.len(), 1); + + let entry = a + .raw_entry_mut() + .from_key(&key) + .and_replace_entry_with(|k, v| { + assert_eq!(k, &key); + assert_eq!(v, new_value); + None + }); + + match entry { + RawEntryMut::Vacant(_) => {} + RawEntryMut::Occupied(_) => panic!(), + } + + assert!(!a.contains_key(key)); + assert_eq!(a.len(), 0); + } + + #[test] + fn test_replace_entry_with_doesnt_corrupt() { + #![allow(deprecated)] //rand + // Test for #19292 + fn check(m: &HashMap) { + for k in m.keys() { + assert!(m.contains_key(k), "{} is in keys() but not in the map?", k); + } + } + + let mut m = HashMap::new(); + + let mut rng = { + let seed = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; + SmallRng::from_seed(seed) + }; + + // Populate the map with some items. + for _ in 0..50 { + let x = rng.gen_range(-10, 10); + m.insert(x, ()); + } + + for _ in 0..1000 { + let x = rng.gen_range(-10, 10); + m.entry(x).and_replace_entry_with(|_, _| None); + check(&m); + } + } + #[test] fn test_retain() { let mut map: HashMap = (0..100).map(|x| (x, x * 10)).collect(); @@ -3763,7 +4247,7 @@ mod test_map { let drained = map.drain_filter(|&k, _| k % 2 == 0); let mut out = drained.collect::>(); out.sort_unstable(); - assert_eq!(vec![(1, 10), (3, 30), (5, 50), (7, 70)], out); + assert_eq!(vec![(0, 0), (2, 20), (4, 40), (6, 60)], out); assert_eq!(map.len(), 4); } { @@ -4016,4 +4500,28 @@ mod test_map { assert_eq!(m.table.len(), left); } } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::borrow::ToOwned; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_MAP: HashMap = + HashMap::with_hasher(MyHasher); + + let mut map = EMPTY_MAP.clone(); + map.insert(17, "seventeen".to_owned()); + assert_eq!("seventeen", map[&17]); + } } diff --git a/vendor/hashbrown/src/raw/generic.rs b/vendor/hashbrown/src/raw/generic.rs index 6f71900cee..26f8c58969 100644 --- a/vendor/hashbrown/src/raw/generic.rs +++ b/vendor/hashbrown/src/raw/generic.rs @@ -47,20 +47,20 @@ impl Group { pub const WIDTH: usize = mem::size_of::(); /// Returns a full group of empty bytes, suitable for use as the initial - /// value for an empty hash table. This value is explicitly declared as - /// a static variable to ensure the address is consistent across dylibs. + /// value for an empty hash table. /// /// This is guaranteed to be aligned to the group size. - #[inline] - pub fn static_empty() -> &'static [u8] { - union AlignedBytes { - _align: Group, + pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], bytes: [u8; Group::WIDTH], }; - static ALIGNED_BYTES: AlignedBytes = AlignedBytes { + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], bytes: [EMPTY; Group::WIDTH], }; - unsafe { &ALIGNED_BYTES.bytes } + &ALIGNED_BYTES.bytes } /// Loads a group of bytes starting at the given address. diff --git a/vendor/hashbrown/src/raw/mod.rs b/vendor/hashbrown/src/raw/mod.rs index 1ff0135382..fe95932f3d 100644 --- a/vendor/hashbrown/src/raw/mod.rs +++ b/vendor/hashbrown/src/raw/mod.rs @@ -382,10 +382,10 @@ impl RawTable { /// leave the data pointer dangling since that bucket is never written to /// due to our load factor forcing us to always have at least 1 free bucket. #[cfg_attr(feature = "inline-more", inline)] - pub fn new() -> Self { + pub const fn new() -> Self { Self { // Be careful to cast the entire slice to a raw pointer. - ctrl: unsafe { NonNull::new_unchecked(Group::static_empty().as_ptr() as *mut u8) }, + ctrl: unsafe { NonNull::new_unchecked(Group::static_empty() as *const _ as *mut u8) }, bucket_mask: 0, items: 0, growth_left: 0, @@ -406,7 +406,7 @@ impl RawTable { // Avoid `Option::ok_or_else` because it bloats LLVM IR. let (layout, ctrl_offset) = match calculate_layout::(buckets) { Some(lco) => lco, - None => return Err(fallability.capacity_overflow()) + None => return Err(fallability.capacity_overflow()), }; let ptr = match NonNull::new(alloc(layout)) { Some(ptr) => ptr, @@ -688,7 +688,10 @@ impl RawTable { *self = Self::with_capacity(min_size) } else { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - if self.resize(min_size, hasher, Fallibility::Infallible).is_err() { + if self + .resize(min_size, hasher, Fallibility::Infallible) + .is_err() + { unsafe { hint::unreachable_unchecked() } } } @@ -701,7 +704,10 @@ impl RawTable { pub fn reserve(&mut self, additional: usize, hasher: impl Fn(&T) -> u64) { if additional > self.growth_left { // Avoid `Result::unwrap_or_else` because it bloats LLVM IR. - if self.reserve_rehash(additional, hasher, Fallibility::Infallible).is_err() { + if self + .reserve_rehash(additional, hasher, Fallibility::Infallible) + .is_err() + { unsafe { hint::unreachable_unchecked() } } } @@ -954,6 +960,33 @@ impl RawTable { } } + /// Temporary removes a bucket, applying the given function to the removed + /// element and optionally put back the returned value in the same bucket. + /// + /// Returns `true` if the bucket still contains an element + /// + /// This does not check if the given bucket is actually occupied. + #[cfg_attr(feature = "inline-more", inline)] + pub unsafe fn replace_bucket_with(&mut self, bucket: Bucket, f: F) -> bool + where + F: FnOnce(T) -> Option, + { + let index = self.bucket_index(&bucket); + let old_ctrl = *self.ctrl(index); + debug_assert!(is_full(old_ctrl)); + let old_growth_left = self.growth_left; + let item = self.remove(bucket); + if let Some(new_item) = f(item) { + self.growth_left = old_growth_left; + self.set_ctrl(index, old_ctrl); + self.items += 1; + self.bucket(index).write(new_item); + true + } else { + false + } + } + /// Searches for an element in the table. #[inline] pub fn find(&self, hash: u64, mut eq: impl FnMut(&T) -> bool) -> Option> { @@ -1114,7 +1147,7 @@ impl Clone for RawTable { match Self::new_uninitialized(self.buckets(), Fallibility::Infallible) { Ok(table) => table, Err(_) => hint::unreachable_unchecked(), - } + }, ); new_table.clone_from_spec(self, |new_table| { @@ -1151,7 +1184,7 @@ impl Clone for RawTable { match Self::new_uninitialized(source.buckets(), Fallibility::Infallible) { Ok(table) => table, Err(_) => hint::unreachable_unchecked(), - } + }, ); } diff --git a/vendor/hashbrown/src/raw/sse2.rs b/vendor/hashbrown/src/raw/sse2.rs index 79b0aad42d..a27bc0910f 100644 --- a/vendor/hashbrown/src/raw/sse2.rs +++ b/vendor/hashbrown/src/raw/sse2.rs @@ -25,19 +25,20 @@ impl Group { pub const WIDTH: usize = mem::size_of::(); /// Returns a full group of empty bytes, suitable for use as the initial - /// value for an empty hash table. This value is explicitly declared as - /// a static variable to ensure the address is consistent across dylibs. + /// value for an empty hash table. /// /// This is guaranteed to be aligned to the group size. - pub fn static_empty() -> &'static [u8] { - union AlignedBytes { - _align: Group, + pub const fn static_empty() -> &'static [u8; Group::WIDTH] { + #[repr(C)] + struct AlignedBytes { + _align: [Group; 0], bytes: [u8; Group::WIDTH], }; - static ALIGNED_BYTES: AlignedBytes = AlignedBytes { + const ALIGNED_BYTES: AlignedBytes = AlignedBytes { + _align: [], bytes: [EMPTY; Group::WIDTH], }; - unsafe { &ALIGNED_BYTES.bytes } + &ALIGNED_BYTES.bytes } /// Loads a group of bytes starting at the given address. diff --git a/vendor/hashbrown/src/set.rs b/vendor/hashbrown/src/set.rs index eaae82ce7d..b8460fd3b6 100644 --- a/vendor/hashbrown/src/set.rs +++ b/vendor/hashbrown/src/set.rs @@ -100,11 +100,9 @@ use super::map::{self, ConsumeAllOnDrop, DefaultHashBuilder, DrainFilterInner, H /// ``` /// use hashbrown::HashSet; /// -/// fn main() { /// let viking_names: HashSet<&'static str> = /// [ "Einar", "Olaf", "Harald" ].iter().cloned().collect(); /// // use the values stored in the set -/// } /// ``` /// /// [`Cell`]: https://doc.rust-lang.org/std/cell/struct.Cell.html @@ -130,7 +128,7 @@ impl Clone for HashSet { } #[cfg(feature = "ahash")] -impl HashSet { +impl HashSet { /// Creates an empty `HashSet`. /// /// The hash set is initially created with a capacity of 0, so it will not allocate until it @@ -170,6 +168,72 @@ impl HashSet { } impl HashSet { + /// Creates a new empty hash set which will use the given hasher to hash + /// keys. + /// + /// The hash set is also created with the default initial capacity. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_hasher(s); + /// set.insert(2); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub const fn with_hasher(hasher: S) -> Self { + Self { + map: HashMap::with_hasher(hasher), + } + } + + /// Creates an empty `HashSet` with the specified capacity, using + /// `hasher` to hash the keys. + /// + /// The hash set will be able to hold at least `capacity` elements without + /// reallocating. If `capacity` is 0, the hash set will not allocate. + /// + /// Warning: `hasher` is normally randomly generated, and + /// is designed to allow `HashSet`s to be resistant to attacks that + /// cause many collisions and very poor performance. Setting it + /// manually using this function can expose a DoS attack vector. + /// + /// The `hash_builder` passed should implement the [`BuildHasher`] trait for + /// the HashMap to be useful, see its documentation for details. + /// + /// # Examples + /// + /// ``` + /// use hashbrown::HashSet; + /// use hashbrown::hash_map::DefaultHashBuilder; + /// + /// let s = DefaultHashBuilder::default(); + /// let mut set = HashSet::with_capacity_and_hasher(10, s); + /// set.insert(1); + /// ``` + /// + /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html + #[cfg_attr(feature = "inline-more", inline)] + pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { + Self { + map: HashMap::with_capacity_and_hasher(capacity, hasher), + } + } + /// Returns the number of elements the set can hold without reallocating. /// /// # Examples @@ -286,13 +350,13 @@ impl HashSet { self.map.retain(|k, _| f(k)); } - /// Drains elements which are false under the given predicate, + /// Drains elements which are true under the given predicate, /// and returns an iterator over the removed items. /// - /// In other words, move all elements `e` such that `f(&e)` returns `false` out + /// In other words, move all elements `e` such that `f(&e)` returns `true` out /// into another iterator. /// - /// When the returned DrainedFilter is dropped, the elements that don't satisfy + /// When the returned DrainedFilter is dropped, any remaining elements that satisfy /// the predicate are dropped from the set. /// /// # Examples @@ -301,9 +365,15 @@ impl HashSet { /// use hashbrown::HashSet; /// /// let mut set: HashSet = (0..8).collect(); - /// let drained = set.drain_filter(|&k| k % 2 == 0); - /// assert_eq!(drained.count(), 4); - /// assert_eq!(set.len(), 4); + /// let drained: HashSet = set.drain_filter(|v| v % 2 == 0).collect(); + /// + /// let mut evens = drained.into_iter().collect::>(); + /// let mut odds = set.into_iter().collect::>(); + /// evens.sort(); + /// odds.sort(); + /// + /// assert_eq!(evens, vec![0, 2, 4, 6]); + /// assert_eq!(odds, vec![1, 3, 5, 7]); /// ``` #[cfg_attr(feature = "inline-more", inline)] pub fn drain_filter(&mut self, f: F) -> DrainFilter<'_, T, F> @@ -335,78 +405,6 @@ impl HashSet { pub fn clear(&mut self) { self.map.clear() } -} - -impl HashSet -where - T: Eq + Hash, - S: BuildHasher, -{ - /// Creates a new empty hash set which will use the given hasher to hash - /// keys. - /// - /// The hash set is also created with the default initial capacity. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. - /// - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// use hashbrown::hash_map::DefaultHashBuilder; - /// - /// let s = DefaultHashBuilder::default(); - /// let mut set = HashSet::with_hasher(s); - /// set.insert(2); - /// ``` - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html - #[cfg_attr(feature = "inline-more", inline)] - pub fn with_hasher(hasher: S) -> Self { - Self { - map: HashMap::with_hasher(hasher), - } - } - - /// Creates an empty `HashSet` with the specified capacity, using - /// `hasher` to hash the keys. - /// - /// The hash set will be able to hold at least `capacity` elements without - /// reallocating. If `capacity` is 0, the hash set will not allocate. - /// - /// Warning: `hasher` is normally randomly generated, and - /// is designed to allow `HashSet`s to be resistant to attacks that - /// cause many collisions and very poor performance. Setting it - /// manually using this function can expose a DoS attack vector. - /// - /// The `hash_builder` passed should implement the [`BuildHasher`] trait for - /// the HashMap to be useful, see its documentation for details. - /// - /// # Examples - /// - /// ``` - /// use hashbrown::HashSet; - /// use hashbrown::hash_map::DefaultHashBuilder; - /// - /// let s = DefaultHashBuilder::default(); - /// let mut set = HashSet::with_capacity_and_hasher(10, s); - /// set.insert(1); - /// ``` - /// - /// [`BuildHasher`]: ../../std/hash/trait.BuildHasher.html - #[cfg_attr(feature = "inline-more", inline)] - pub fn with_capacity_and_hasher(capacity: usize, hasher: S) -> Self { - Self { - map: HashMap::with_capacity_and_hasher(capacity, hasher), - } - } /// Returns a reference to the set's [`BuildHasher`]. /// @@ -426,7 +424,13 @@ where pub fn hasher(&self) -> &S { self.map.hasher() } +} +impl HashSet +where + T: Eq + Hash, + S: BuildHasher, +{ /// Reserves capacity for at least `additional` more elements to be inserted /// in the `HashSet`. The collection may reserve more space to avoid /// frequent reallocations. @@ -1456,8 +1460,15 @@ where let (k, _) = self.inner.next(&mut |k, _| f(k))?; Some(k) } + + #[inline] + fn size_hint(&self) -> (usize, Option) { + (0, self.inner.iter.size_hint().1) + } } +impl FusedIterator for DrainFilter<'_, K, F> where F: FnMut(&K) -> bool {} + impl Clone for Intersection<'_, T, S> { #[cfg_attr(feature = "inline-more", inline)] fn clone(&self) -> Self { @@ -2074,7 +2085,7 @@ mod test_set { let drained = set.drain_filter(|&k| k % 2 == 0); let mut out = drained.collect::>(); out.sort_unstable(); - assert_eq!(vec![1, 3, 5, 7], out); + assert_eq!(vec![0, 2, 4, 6], out); assert_eq!(set.len(), 4); } { @@ -2083,4 +2094,26 @@ mod test_set { assert_eq!(set.len(), 4, "Removes non-matching items on drop"); } } + + #[test] + fn test_const_with_hasher() { + use core::hash::BuildHasher; + use std::collections::hash_map::DefaultHasher; + + #[derive(Clone)] + struct MyHasher; + impl BuildHasher for MyHasher { + type Hasher = DefaultHasher; + + fn build_hasher(&self) -> DefaultHasher { + DefaultHasher::new() + } + } + + const EMPTY_SET: HashSet = HashSet::with_hasher(MyHasher); + + let mut set = EMPTY_SET.clone(); + set.insert(19); + assert!(set.contains(&19)); + } } diff --git a/vendor/hex/.cargo-checksum.json b/vendor/hex/.cargo-checksum.json new file mode 100644 index 0000000000..2c9c1d0803 --- /dev/null +++ b/vendor/hex/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"3b509da1763642f9bd85382ae9d83a5f4355cf201b0fab9de719aa635ea0ff70","LICENSE-APACHE":"c6596eb7be8581c18be736c846fb9173b69eccf6ef94c5135893ec56bd92ba08","LICENSE-MIT":"f7bdb3426d045cd50efd4953026e3eb5a83d0199f458a075602611b9344da5b9","README.md":"4bbf89813cd9d2a04707299f34e1c906ed9e8247b910043f38d47b18a0d0641b","benches/hex.rs":"f1301fdaaf5f31cdd16e6988673201c9ce5b7dc65ae7cb7c69559b7adabf38bc","src/error.rs":"7c8af5efa9135fa24fc37dfcd973112c0766ccc7a4826078edb045df9a8efd79","src/lib.rs":"734506f5d604c7d7575d2c6bc31c75a10f628c7b41daa6be11656bd6f7117191","src/serde.rs":"8fb25650a850ae258ff9178bb8818145101dd3df40aa2725fc11b81bdd5d4567","tests/serde.rs":"28dca8a567daf9861413d1b1b5c2da13472f1c1b9c69db02598674cdbd633be2","tests/version-number.rs":"73301b7bfe500eada5ede66f0dce89bd3e354af50a8e7a123b02931cd5eb8e16"},"package":"644f9158b2f133fd50f5fb3242878846d9eb792e445c893805ff0e3824006e35"} \ No newline at end of file diff --git a/vendor/hex/Cargo.toml b/vendor/hex/Cargo.toml new file mode 100644 index 0000000000..6dd9a31a71 --- /dev/null +++ b/vendor/hex/Cargo.toml @@ -0,0 +1,62 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "hex" +version = "0.4.2" +authors = ["KokaKiwi "] +description = "Encoding and decoding data into/from hexadecimal representation." +documentation = "https://docs.rs/hex/" +readme = "README.md" +keywords = ["no_std", "hex"] +categories = ["encoding", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/KokaKiwi/rust-hex" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] + +[[bench]] +name = "hex" +harness = false +[dependencies.serde] +version = "1.0" +optional = true +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.faster-hex] +version = "0.4" + +[dev-dependencies.pretty_assertions] +version = "0.6" + +[dev-dependencies.rustc-hex] +version = "2.0" + +[dev-dependencies.serde] +version = "1.0" +features = ["derive"] + +[dev-dependencies.serde_json] +version = "1.0" + +[dev-dependencies.version-sync] +version = "0.8" + +[features] +default = ["std"] +std = [] +[badges.travis-ci] +branch = "master" +repository = "KokaKiwi/rust-hex" diff --git a/vendor/hex/LICENSE-APACHE b/vendor/hex/LICENSE-APACHE new file mode 100644 index 0000000000..8f71f43fee --- /dev/null +++ b/vendor/hex/LICENSE-APACHE @@ -0,0 +1,202 @@ + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "{}" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright {yyyy} {name of copyright owner} + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + diff --git a/vendor/hex/LICENSE-MIT b/vendor/hex/LICENSE-MIT new file mode 100644 index 0000000000..a7b461f97c --- /dev/null +++ b/vendor/hex/LICENSE-MIT @@ -0,0 +1,20 @@ +Copyright (c) 2013-2014 The Rust Project Developers. +Copyright (c) 2015-2020 The rust-hex Developers + +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 --git a/vendor/hex/README.md b/vendor/hex/README.md new file mode 100644 index 0000000000..9453cfa23b --- /dev/null +++ b/vendor/hex/README.md @@ -0,0 +1,67 @@ +hex +=== +[![Crates.io: hex](https://img.shields.io/crates/v/hex.svg)](https://crates.io/crates/hex) +[![Documentation](https://docs.rs/hex/badge.svg)](https://docs.rs/hex) +[![Build Status (Travis)](https://travis-ci.org/KokaKiwi/rust-hex.svg?branch=master)](https://travis-ci.org/KokaKiwi/rust-hex) +[![Build Status (Github Actions)](https://github.com/KokaKiwi/rust-hex/workflows/Test%20hex/badge.svg?master)](https://github.com/KokaKiwi/rust-hex/actions) + +Encoding and decoding data into/from hexadecimal representation. + +## Examples + +Encoding a `String` +```rust +let hex_string = hex::encode("Hello world!"); + +println!("{}", hex_string); // Prints "48656c6c6f20776f726c6421" +``` + +Decoding a `String` +```rust +let decoded_string = hex::decode("48656c6c6f20776f726c6421"); + +println!("{}", decoded_string); // Prints "Hello world!" +``` + +You can find the [documentation](https://docs.rs/hex) here. + +## Installation + +In order to use this crate, you have to add it under `[dependencies]` to your `Cargo.toml` +```toml +[dependencies] +hex = "0.4" +``` + +By default this will import `std`, if you are working in a +[`no_std`](https://rust-embedded.github.io/book/intro/no-std.html) +environment you can turn this off by adding the following + +```toml +[dependencies] +hex = { version = "0.4", default-features = false } +``` + +## Features + +- `std`: + Enabled by default. Add support for Rust's libstd types. +- `serde`: + Disabled by default. Add support for `serde` de/serializing library. + See the `serde` module documentation for usage. + +## License + +Licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally +submitted for inclusion in the work by you, as defined in the Apache-2.0 +license, shall be dual licensed as above, without any additional terms or +conditions. diff --git a/vendor/hex/benches/hex.rs b/vendor/hex/benches/hex.rs new file mode 100644 index 0000000000..56b121f3c1 --- /dev/null +++ b/vendor/hex/benches/hex.rs @@ -0,0 +1,70 @@ +use criterion::{criterion_group, criterion_main, Criterion}; +use rustc_hex::{FromHex, ToHex}; + +const DATA: &[u8] = include_bytes!("../src/lib.rs"); + +fn bench_encode(c: &mut Criterion) { + c.bench_function("hex_encode", |b| b.iter(|| hex::encode(DATA))); + + c.bench_function("rustc_hex_encode", |b| b.iter(|| DATA.to_hex::())); + + c.bench_function("faster_hex_encode", |b| { + b.iter(|| faster_hex::hex_string(DATA).unwrap()) + }); + + c.bench_function("faster_hex_encode_fallback", |b| { + b.iter(|| { + let mut dst = vec![0; DATA.len() * 2]; + faster_hex::hex_encode_fallback(DATA, &mut dst); + dst + }) + }); +} + +fn bench_decode(c: &mut Criterion) { + c.bench_function("hex_decode", |b| { + let hex = hex::encode(DATA); + b.iter(|| hex::decode(&hex).unwrap()) + }); + + c.bench_function("rustc_hex_decode", |b| { + let hex = DATA.to_hex::(); + b.iter(|| hex.from_hex::>().unwrap()) + }); + + c.bench_function("faster_hex_decode", move |b| { + let hex = faster_hex::hex_string(DATA).unwrap(); + let len = DATA.len(); + b.iter(|| { + let mut dst = Vec::with_capacity(len); + dst.resize(len, 0); + faster_hex::hex_decode(hex.as_bytes(), &mut dst).unwrap(); + dst + }) + }); + + c.bench_function("faster_hex_decode_unchecked", |b| { + let hex = faster_hex::hex_string(DATA).unwrap(); + let len = DATA.len(); + b.iter(|| { + let mut dst = Vec::with_capacity(len); + dst.resize(len, 0); + faster_hex::hex_decode_unchecked(hex.as_bytes(), &mut dst); + dst + }) + }); + + c.bench_function("faster_hex_decode_fallback", |b| { + let hex = faster_hex::hex_string(DATA).unwrap(); + let len = DATA.len(); + b.iter(|| { + let mut dst = Vec::with_capacity(len); + dst.resize(len, 0); + faster_hex::hex_decode_fallback(hex.as_bytes(), &mut dst); + dst + }) + }); +} + +criterion_group!(benches, bench_encode, bench_decode); +criterion_main!(benches); diff --git a/vendor/hex/src/error.rs b/vendor/hex/src/error.rs new file mode 100644 index 0000000000..b9f2acf650 --- /dev/null +++ b/vendor/hex/src/error.rs @@ -0,0 +1,55 @@ +use core::fmt; + +/// The error type for decoding a hex string into `Vec` or `[u8; N]`. +#[derive(Debug, Clone, Copy, PartialEq)] +pub enum FromHexError { + /// An invalid character was found. Valid ones are: `0...9`, `a...f` + /// or `A...F`. + InvalidHexCharacter { c: char, index: usize }, + + /// A hex string's length needs to be even, as two digits correspond to + /// one byte. + OddLength, + + /// If the hex string is decoded into a fixed sized container, such as an + /// array, the hex string's length * 2 has to match the container's + /// length. + InvalidStringLength, +} + +#[cfg(feature = "std")] +impl std::error::Error for FromHexError {} + +impl fmt::Display for FromHexError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + match *self { + FromHexError::InvalidHexCharacter { c, index } => { + write!(f, "Invalid character {:?} at position {}", c, index) + } + FromHexError::OddLength => write!(f, "Odd number of digits"), + FromHexError::InvalidStringLength => write!(f, "Invalid string length"), + } + } +} + +#[cfg(test)] +mod tests { + use super::*; + #[cfg(not(feature = "std"))] + use alloc::string::ToString; + use pretty_assertions::assert_eq; + + #[test] + fn test_display() { + assert_eq!( + FromHexError::InvalidHexCharacter { c: '\n', index: 5 }.to_string(), + "Invalid character '\\n' at position 5" + ); + + assert_eq!(FromHexError::OddLength.to_string(), "Odd number of digits"); + assert_eq!( + FromHexError::InvalidStringLength.to_string(), + "Invalid string length" + ); + } +} diff --git a/vendor/hex/src/lib.rs b/vendor/hex/src/lib.rs new file mode 100644 index 0000000000..19ee759c65 --- /dev/null +++ b/vendor/hex/src/lib.rs @@ -0,0 +1,485 @@ +// Copyright (c) 2013-2014 The Rust Project Developers. +// Copyright (c) 2015-2020 The rust-hex Developers. +// +// 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. +//! Encoding and decoding hex strings. +//! +//! For most cases, you can simply use the [`decode`], [`encode`] and +//! [`encode_upper`] functions. If you need a bit more control, use the traits +//! [`ToHex`] and [`FromHex`] instead. +//! +//! # Example +//! +//! ``` +//! let hex_string = hex::encode("Hello world!"); +//! +//! println!("{}", hex_string); // Prints "48656c6c6f20776f726c6421" +//! +//! # assert_eq!(hex_string, "48656c6c6f20776f726c6421"); +//! ``` + +#![doc(html_root_url = "https://docs.rs/hex/0.4.2")] +#![cfg_attr(not(feature = "std"), no_std)] +#![cfg_attr(docsrs, feature(doc_cfg))] +#![allow(clippy::unreadable_literal)] + +#[cfg(not(feature = "std"))] +extern crate alloc; +#[cfg(not(feature = "std"))] +use alloc::{string::String, vec::Vec}; + +use core::iter; + +mod error; +pub use crate::error::FromHexError; + +#[cfg(feature = "serde")] +#[cfg_attr(docsrs, doc(cfg(feature = "serde")))] +pub mod serde; +#[cfg(feature = "serde")] +pub use crate::serde::{deserialize, serialize, serialize_upper}; + +/// Encoding values as hex string. +/// +/// This trait is implemented for all `T` which implement `AsRef<[u8]>`. This +/// includes `String`, `str`, `Vec` and `[u8]`. +/// +/// # Example +/// +/// ``` +/// use hex::ToHex; +/// +/// println!("{}", "Hello world!".encode_hex::()); +/// # assert_eq!("Hello world!".encode_hex::(), "48656c6c6f20776f726c6421".to_string()); +/// ``` +/// +/// *Note*: instead of using this trait, you might want to use [`encode()`]. +pub trait ToHex { + /// Encode the hex strict representing `self` into the result.. Lower case + /// letters are used (e.g. `f9b4ca`) + fn encode_hex>(&self) -> T; + + /// Encode the hex strict representing `self` into the result.. Lower case + /// letters are used (e.g. `F9B4CA`) + fn encode_hex_upper>(&self) -> T; +} + +const HEX_CHARS_LOWER: &[u8; 16] = b"0123456789abcdef"; +const HEX_CHARS_UPPER: &[u8; 16] = b"0123456789ABCDEF"; + +struct BytesToHexChars<'a> { + inner: ::core::slice::Iter<'a, u8>, + table: &'static [u8; 16], + next: Option, +} + +impl<'a> BytesToHexChars<'a> { + fn new(inner: &'a [u8], table: &'static [u8; 16]) -> BytesToHexChars<'a> { + BytesToHexChars { + inner: inner.iter(), + table, + next: None, + } + } +} + +impl<'a> Iterator for BytesToHexChars<'a> { + type Item = char; + + fn next(&mut self) -> Option { + match self.next.take() { + Some(current) => Some(current), + None => self.inner.next().map(|byte| { + let current = self.table[(byte >> 4) as usize] as char; + self.next = Some(self.table[(byte & 0xf) as usize] as char); + current + }), + } + } + + fn size_hint(&self) -> (usize, Option) { + let length = self.len(); + (length, Some(length)) + } +} + +impl<'a> iter::ExactSizeIterator for BytesToHexChars<'a> { + fn len(&self) -> usize { + let mut length = self.inner.len() * 2; + if self.next.is_some() { + length += 1; + } + length + } +} + +fn encode_to_iter>(table: &'static [u8; 16], source: &[u8]) -> T { + BytesToHexChars::new(source, table).collect() +} + +impl> ToHex for T { + fn encode_hex>(&self) -> U { + encode_to_iter(HEX_CHARS_LOWER, self.as_ref()) + } + + fn encode_hex_upper>(&self) -> U { + encode_to_iter(HEX_CHARS_UPPER, self.as_ref()) + } +} + +/// Types that can be decoded from a hex string. +/// +/// This trait is implemented for `Vec` and small `u8`-arrays. +/// +/// # Example +/// +/// ``` +/// use hex::FromHex; +/// +/// match Vec::from_hex("48656c6c6f20776f726c6421") { +/// Ok(vec) => { +/// for b in vec { +/// println!("{}", b as char); +/// } +/// } +/// Err(e) => { +/// // Deal with the error ... +/// } +/// } +/// ``` +pub trait FromHex: Sized { + type Error; + + /// Creates an instance of type `Self` from the given hex string, or fails + /// with a custom error type. + /// + /// Both, upper and lower case characters are valid and can even be + /// mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). + fn from_hex>(hex: T) -> Result; +} + +fn val(c: u8, idx: usize) -> Result { + match c { + b'A'..=b'F' => Ok(c - b'A' + 10), + b'a'..=b'f' => Ok(c - b'a' + 10), + b'0'..=b'9' => Ok(c - b'0'), + _ => Err(FromHexError::InvalidHexCharacter { + c: c as char, + index: idx, + }), + } +} + +impl FromHex for Vec { + type Error = FromHexError; + + fn from_hex>(hex: T) -> Result { + let hex = hex.as_ref(); + if hex.len() % 2 != 0 { + return Err(FromHexError::OddLength); + } + + hex.chunks(2) + .enumerate() + .map(|(i, pair)| Ok(val(pair[0], 2 * i)? << 4 | val(pair[1], 2 * i + 1)?)) + .collect() + } +} + +// Helper macro to implement the trait for a few fixed sized arrays. Once Rust +// has type level integers, this should be removed. +macro_rules! from_hex_array_impl { + ($($len:expr)+) => {$( + impl FromHex for [u8; $len] { + type Error = FromHexError; + + fn from_hex>(hex: T) -> Result { + let mut out = [0u8; $len]; + decode_to_slice(hex, &mut out as &mut [u8])?; + Ok(out) + } + } + )+} +} + +from_hex_array_impl! { + 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 + 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 + 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 + 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 + 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 + 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 + 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 + 160 192 200 224 256 384 512 768 1024 2048 4096 8192 16384 32768 +} + +#[cfg(any(target_pointer_width = "32", target_pointer_width = "64"))] +from_hex_array_impl! { + 65536 131072 262144 524288 1048576 2097152 4194304 8388608 + 16777216 33554432 67108864 134217728 268435456 536870912 + 1073741824 2147483648 +} + +#[cfg(target_pointer_width = "64")] +from_hex_array_impl! { + 4294967296 +} + +/// Encodes `data` as hex string using lowercase characters. +/// +/// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's +/// length is always even, each byte in `data` is always encoded using two hex +/// digits. Thus, the resulting string contains exactly twice as many bytes as +/// the input data. +/// +/// # Example +/// +/// ``` +/// assert_eq!(hex::encode("Hello world!"), "48656c6c6f20776f726c6421"); +/// assert_eq!(hex::encode(vec![1, 2, 3, 15, 16]), "0102030f10"); +/// ``` +pub fn encode>(data: T) -> String { + data.encode_hex() +} + +/// Encodes `data` as hex string using uppercase characters. +/// +/// Apart from the characters' casing, this works exactly like `encode()`. +/// +/// # Example +/// +/// ``` +/// assert_eq!(hex::encode_upper("Hello world!"), "48656C6C6F20776F726C6421"); +/// assert_eq!(hex::encode_upper(vec![1, 2, 3, 15, 16]), "0102030F10"); +/// ``` +pub fn encode_upper>(data: T) -> String { + data.encode_hex_upper() +} + +/// Decodes a hex string into raw bytes. +/// +/// Both, upper and lower case characters are valid in the input string and can +/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). +/// +/// # Example +/// +/// ``` +/// assert_eq!( +/// hex::decode("48656c6c6f20776f726c6421"), +/// Ok("Hello world!".to_owned().into_bytes()) +/// ); +/// +/// assert_eq!(hex::decode("123"), Err(hex::FromHexError::OddLength)); +/// assert!(hex::decode("foo").is_err()); +/// ``` +pub fn decode>(data: T) -> Result, FromHexError> { + FromHex::from_hex(data) +} + +/// Decode a hex string into a mutable bytes slice. +/// +/// Both, upper and lower case characters are valid in the input string and can +/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). +/// +/// # Example +/// +/// ``` +/// let mut bytes = [0u8; 4]; +/// assert_eq!(hex::decode_to_slice("6b697769", &mut bytes as &mut [u8]), Ok(())); +/// assert_eq!(&bytes, b"kiwi"); +/// ``` +pub fn decode_to_slice>(data: T, out: &mut [u8]) -> Result<(), FromHexError> { + let data = data.as_ref(); + + if data.len() % 2 != 0 { + return Err(FromHexError::OddLength); + } + if data.len() / 2 != out.len() { + return Err(FromHexError::InvalidStringLength); + } + + for (i, byte) in out.iter_mut().enumerate() { + *byte = val(data[2 * i], 2 * i)? << 4 | val(data[2 * i + 1], 2 * i + 1)?; + } + + Ok(()) +} + +// generates an iterator like this +// (0, 1) +// (2, 3) +// (4, 5) +// (6, 7) +// ... +fn generate_iter(len: usize) -> impl Iterator { + (0..len).step_by(2).zip((0..len).skip(1).step_by(2)) +} + +// the inverse of `val`. +fn byte2hex(byte: u8, table: &[u8; 16]) -> (u8, u8) { + let high = table[((byte & 0xf0) >> 4) as usize]; + let low = table[(byte & 0x0f) as usize]; + + (high, low) +} + +/// Encodes some bytes into a mutable slice of bytes. +/// +/// The output buffer, has to be able to hold at least `input.len() * 2` bytes, +/// otherwise this function will return an error. +/// +/// # Example +/// +/// ``` +/// # use hex::FromHexError; +/// # fn main() -> Result<(), FromHexError> { +/// let mut bytes = [0u8; 4 * 2]; +/// +/// hex::encode_to_slice(b"kiwi", &mut bytes)?; +/// assert_eq!(&bytes, b"6b697769"); +/// # Ok(()) +/// # } +/// ``` +pub fn encode_to_slice>(input: T, output: &mut [u8]) -> Result<(), FromHexError> { + if input.as_ref().len() * 2 != output.len() { + return Err(FromHexError::InvalidStringLength); + } + + for (byte, (i, j)) in input.as_ref().iter().zip(generate_iter(input.as_ref().len() * 2)) { + let (high, low) = byte2hex(*byte, HEX_CHARS_LOWER); + output[i] = high; + output[j] = low; + } + + Ok(()) +} + +#[cfg(test)] +mod test { + use super::*; + #[cfg(not(feature = "std"))] + use alloc::string::ToString; + use pretty_assertions::assert_eq; + + #[test] + fn test_gen_iter() { + let mut result = Vec::new(); + result.push((0, 1)); + result.push((2, 3)); + + assert_eq!(generate_iter(5).collect::>(), result); + } + + #[test] + fn test_encode_to_slice() { + let mut output_1 = [0; 4 * 2]; + encode_to_slice(b"kiwi", &mut output_1).unwrap(); + assert_eq!(&output_1, b"6b697769"); + + let mut output_2 = [0; 5 * 2]; + encode_to_slice(b"kiwis", &mut output_2).unwrap(); + assert_eq!(&output_2, b"6b69776973"); + + let mut output_3 = [0; 100]; + + assert_eq!( + encode_to_slice(b"kiwis", &mut output_3), + Err(FromHexError::InvalidStringLength) + ); + } + + #[test] + fn test_decode_to_slice() { + let mut output_1 = [0; 4]; + decode_to_slice(b"6b697769", &mut output_1).unwrap(); + assert_eq!(&output_1, b"kiwi"); + + let mut output_2 = [0; 5]; + decode_to_slice(b"6b69776973", &mut output_2).unwrap(); + assert_eq!(&output_2, b"kiwis"); + + let mut output_3 = [0; 4]; + + assert_eq!(decode_to_slice(b"6", &mut output_3), Err(FromHexError::OddLength)); + } + + #[test] + fn test_encode() { + assert_eq!(encode("foobar"), "666f6f626172"); + } + + #[test] + fn test_decode() { + assert_eq!(decode("666f6f626172"), Ok(String::from("foobar").into_bytes())); + } + + #[test] + pub fn test_from_hex_okay_str() { + assert_eq!(Vec::from_hex("666f6f626172").unwrap(), b"foobar"); + assert_eq!(Vec::from_hex("666F6F626172").unwrap(), b"foobar"); + } + + #[test] + pub fn test_from_hex_okay_bytes() { + assert_eq!(Vec::from_hex(b"666f6f626172").unwrap(), b"foobar"); + assert_eq!(Vec::from_hex(b"666F6F626172").unwrap(), b"foobar"); + } + + #[test] + pub fn test_invalid_length() { + assert_eq!(Vec::from_hex("1").unwrap_err(), FromHexError::OddLength); + assert_eq!(Vec::from_hex("666f6f6261721").unwrap_err(), FromHexError::OddLength); + } + + #[test] + pub fn test_invalid_char() { + assert_eq!( + Vec::from_hex("66ag").unwrap_err(), + FromHexError::InvalidHexCharacter { c: 'g', index: 3 } + ); + } + + #[test] + pub fn test_empty() { + assert_eq!(Vec::from_hex("").unwrap(), b""); + } + + #[test] + pub fn test_from_hex_whitespace() { + assert_eq!( + Vec::from_hex("666f 6f62617").unwrap_err(), + FromHexError::InvalidHexCharacter { c: ' ', index: 4 } + ); + } + + #[test] + pub fn test_from_hex_array() { + assert_eq!( + <[u8; 6] as FromHex>::from_hex("666f6f626172"), + Ok([0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72]) + ); + + assert_eq!( + <[u8; 5] as FromHex>::from_hex("666f6f626172"), + Err(FromHexError::InvalidStringLength) + ); + } + + #[test] + fn test_to_hex() { + assert_eq!( + [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex::(), + "666f6f626172".to_string(), + ); + + assert_eq!( + [0x66, 0x6f, 0x6f, 0x62, 0x61, 0x72].encode_hex_upper::(), + "666F6F626172".to_string(), + ); + } +} diff --git a/vendor/hex/src/serde.rs b/vendor/hex/src/serde.rs new file mode 100644 index 0000000000..a90e36095b --- /dev/null +++ b/vendor/hex/src/serde.rs @@ -0,0 +1,88 @@ +//! Hex encoding with `serde`. +//! +//! # Example +//! +//! ``` +//! use serde::{Serialize, Deserialize}; +//! +//! #[derive(Serialize, Deserialize)] +//! struct Foo { +//! #[serde(with = "hex")] +//! bar: Vec, +//! } +//! ``` +//! +use serde::de::{Error, Visitor}; +use serde::{Deserializer, Serializer}; + +use std::fmt; +use std::marker::PhantomData; + +use crate::{FromHex, ToHex}; + +/// Serializes `data` as hex string using uppercase characters. +/// +/// Apart from the characters' casing, this works exactly like `serialize()`. +pub fn serialize_upper(data: T, serializer: S) -> Result +where + S: Serializer, + T: ToHex, +{ + let s = data.encode_hex_upper::(); + serializer.serialize_str(&s) +} + +/// Serializes `data` as hex string using lowercase characters. +/// +/// Lowercase characters are used (e.g. `f9b4ca`). The resulting string's length +/// is always even, each byte in data is always encoded using two hex digits. +/// Thus, the resulting string contains exactly twice as many bytes as the input data. +pub fn serialize(data: T, serializer: S) -> Result +where + S: Serializer, + T: ToHex, +{ + let s = data.encode_hex::(); + serializer.serialize_str(&s) +} + +/// Deserializes a hex string into raw bytes. +/// +/// Both, upper and lower case characters are valid in the input string and can +/// even be mixed (e.g. `f9b4ca`, `F9B4CA` and `f9B4Ca` are all valid strings). +pub fn deserialize<'de, D, T>(deserializer: D) -> Result +where + D: Deserializer<'de>, + T: FromHex, + ::Error: fmt::Display, +{ + struct HexStrVisitor(PhantomData); + + impl<'de, T> Visitor<'de> for HexStrVisitor + where + T: FromHex, + ::Error: fmt::Display, + { + type Value = T; + + fn expecting(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "a hex encoded string") + } + + fn visit_str(self, data: &str) -> Result + where + E: Error, + { + FromHex::from_hex(data).map_err(|e| Error::custom(e)) + } + + fn visit_borrowed_str(self, data: &'de str) -> Result + where + E: Error, + { + FromHex::from_hex(data).map_err(|e| Error::custom(e)) + } + } + + deserializer.deserialize_str(HexStrVisitor(PhantomData)) +} diff --git a/vendor/hex/tests/serde.rs b/vendor/hex/tests/serde.rs new file mode 100644 index 0000000000..aedf8c77c1 --- /dev/null +++ b/vendor/hex/tests/serde.rs @@ -0,0 +1,58 @@ +#![cfg(feature = "serde")] + +use serde::{Deserialize, Serialize}; + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +struct Foo { + #[serde(with = "hex")] + bar: Vec, +} + +#[test] +fn serialize() { + let foo = Foo { + bar: vec![1, 10, 100], + }; + + let ser = serde_json::to_string(&foo).expect("serialization failed"); + assert_eq!(ser, r#"{"bar":"010a64"}"#); +} + +#[test] +fn deserialize() { + let foo = Foo { + bar: vec![1, 10, 100], + }; + + let de: Foo = serde_json::from_str(r#"{"bar":"010a64"}"#).expect("deserialization failed"); + assert_eq!(de, foo); +} + +#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)] +struct Bar { + #[serde( + serialize_with = "hex::serialize_upper", + deserialize_with = "hex::deserialize" + )] + foo: Vec, +} + +#[test] +fn serialize_upper() { + let bar = Bar { + foo: vec![1, 10, 100], + }; + + let ser = serde_json::to_string(&bar).expect("serialization failed"); + assert_eq!(ser, r#"{"foo":"010A64"}"#); +} + +#[test] +fn deserialize_upper() { + let bar = Bar { + foo: vec![1, 10, 100], + }; + + let de: Bar = serde_json::from_str(r#"{"foo":"010A64"}"#).expect("deserialization failed"); + assert_eq!(de, bar); +} diff --git a/vendor/hex/tests/version-number.rs b/vendor/hex/tests/version-number.rs new file mode 100644 index 0000000000..288592d02f --- /dev/null +++ b/vendor/hex/tests/version-number.rs @@ -0,0 +1,9 @@ +#[test] +fn test_readme_deps() { + version_sync::assert_markdown_deps_updated!("README.md"); +} + +#[test] +fn test_html_root_url() { + version_sync::assert_html_root_url_updated!("src/lib.rs"); +} diff --git a/vendor/indexmap/.cargo-checksum.json b/vendor/indexmap/.cargo-checksum.json index 0a17817b83..7cf443999b 100644 --- a/vendor/indexmap/.cargo-checksum.json +++ b/vendor/indexmap/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"fcdee9f8eacd948e4ffc43c51e7b4e01cc44ab94076c59531ea0c85507fe7b11","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.rst":"1f0456806c90e69e673676e5444f3d1d588e63ab932663ad5c209346dcf300de","benches/bench.rs":"dda3c7e3cd68b8f5c74dbd60189e89f0e43339cdc25dae7b1e5a9d25b1fb80a9","benches/faststring.rs":"2472b9d0d52031988cd31401357908fd850d15f1efa9f9761aa6b6779aad1889","build.rs":"14e5731ffc7eb135b295312b87730554521b0621fe61b2a19c71dc8f98dfc6ff","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"4c4fa0d4882387d2c1681fa29a333354230de157101783bea2af6af04951d973","src/macros.rs":"cb2e9742b7e2bcadc4eb356a4ca4eb3317d1a80e293f37a3cd5a0155c5347c50","src/map.rs":"21c0c04acfb25d526da41b447b2e572d14e52778b84910514869d1cd2dce267c","src/map/core.rs":"9d9df231fbc02e3539429451c6f8cfd142c97d6e47b0c1f58672f75e3806d578","src/map/core/raw.rs":"9842320404357ec15e536240a9ab32d969e61f31508d3c485c0c76077618ef63","src/mutable_keys.rs":"99fdec7c0182902ba19524f342c220b51475bcd41c44c2cb2c3f62eacb029335","src/rayon/map.rs":"cdbe6cad8e5753aca3f07b621d2bb3b480f1ae3e10697568b8c16aeb865de65b","src/rayon/mod.rs":"bf2b0fc074f20135a6734db600b04828e88dd263b3e361606be4efe8e916eafc","src/rayon/set.rs":"789efd10d41f03fa73268bae8afdc3b6582767420218a4b28f3c83c528ef726c","src/serde.rs":"2f7ce29e63e92ddbe14d3ad0b7e83bdc9662b226565ec0aa707d5cd92cb1e263","src/set.rs":"a88c5e902e8c67d014c7c1680a7e4b9156af67d2ac58e7dcf96698b742abc88b","src/util.rs":"c415261cff9f610d7331192feba0839cb05e04d3d375a5fa2f8190a29661994e","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"6efe8c6dfa5bdd466b3f5c491d9dfbf57fd730301849a710abff9358968218c5","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"86b45e59b16c76b11bf9738fd5d38879d3bd28ad292d7b313608becb17ae2df9"} \ No newline at end of file +{"files":{"Cargo.toml":"b2e03e7a524d10bb253021375ccc06a3d2a060d2c7c045a1a60d8bb3739b46a9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"ecc269ef87fd38a1d98e30bfac9ba964a9dbd9315c3770fed98d4d7cb5882055","README.rst":"6751ed067142c9445ffb9c201457a40bb73af76aa3c7e525fb415508abec74b1","benches/bench.rs":"dda3c7e3cd68b8f5c74dbd60189e89f0e43339cdc25dae7b1e5a9d25b1fb80a9","benches/faststring.rs":"2472b9d0d52031988cd31401357908fd850d15f1efa9f9761aa6b6779aad1889","build.rs":"558b4d0b9e9b3a44f7e1a2b69f7a7567ea721cd45cb54f4e458e850bf702f35c","src/equivalent.rs":"2e6ae24ef09a09b917f4e2b0f6288f901878e42f5080f61b1bd1afdcc90aba87","src/lib.rs":"4c4fa0d4882387d2c1681fa29a333354230de157101783bea2af6af04951d973","src/macros.rs":"cb2e9742b7e2bcadc4eb356a4ca4eb3317d1a80e293f37a3cd5a0155c5347c50","src/map.rs":"21c0c04acfb25d526da41b447b2e572d14e52778b84910514869d1cd2dce267c","src/map/core.rs":"9d9df231fbc02e3539429451c6f8cfd142c97d6e47b0c1f58672f75e3806d578","src/map/core/raw.rs":"9842320404357ec15e536240a9ab32d969e61f31508d3c485c0c76077618ef63","src/mutable_keys.rs":"99fdec7c0182902ba19524f342c220b51475bcd41c44c2cb2c3f62eacb029335","src/rayon/map.rs":"cdbe6cad8e5753aca3f07b621d2bb3b480f1ae3e10697568b8c16aeb865de65b","src/rayon/mod.rs":"bf2b0fc074f20135a6734db600b04828e88dd263b3e361606be4efe8e916eafc","src/rayon/set.rs":"789efd10d41f03fa73268bae8afdc3b6582767420218a4b28f3c83c528ef726c","src/serde.rs":"2f7ce29e63e92ddbe14d3ad0b7e83bdc9662b226565ec0aa707d5cd92cb1e263","src/set.rs":"a88c5e902e8c67d014c7c1680a7e4b9156af67d2ac58e7dcf96698b742abc88b","src/util.rs":"c415261cff9f610d7331192feba0839cb05e04d3d375a5fa2f8190a29661994e","tests/equivalent_trait.rs":"efe9393069e3cfc893d2c9c0343679979578e437fdb98a10baefeced027ba310","tests/macros_full_path.rs":"c33c86d7341581fdd08e2e6375a4afca507fa603540c54a3b9e51c4cd011cd71","tests/quick.rs":"6efe8c6dfa5bdd466b3f5c491d9dfbf57fd730301849a710abff9358968218c5","tests/tests.rs":"f6dbeeb0e2950402b0e66ac52bf74c9e4197d3c5d9c0dde64a7998a2ef74d327"},"package":"55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2"} \ No newline at end of file diff --git a/vendor/indexmap/Cargo.toml b/vendor/indexmap/Cargo.toml index 0e42aa2659..96876f030e 100644 --- a/vendor/indexmap/Cargo.toml +++ b/vendor/indexmap/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "indexmap" -version = "1.5.1" +version = "1.6.0" authors = ["bluss", "Josh Stone "] build = "build.rs" description = "A hash table with consistent order and fast iteration.\n\nThe indexmap is a hash table where the iteration order of the key-value\npairs is independent of the hash values of the keys. It has the usual\nhash table functionality, it preserves insertion order except after\nremovals, and it allows lookup of its elements by either hash table key\nor numerical index. A corresponding hash set type is also provided.\n\nThis crate was initially published under the name ordermap, but it was renamed to\nindexmap.\n" @@ -34,7 +34,7 @@ debug = true [lib] bench = false [dependencies.hashbrown] -version = "0.8.1" +version = "0.9.0" features = ["raw"] default-features = false @@ -70,5 +70,6 @@ version = "1" [features] serde-1 = ["serde"] +std = [] test_debug = [] test_low_transition_point = [] diff --git a/vendor/indexmap/README.rst b/vendor/indexmap/README.rst index 5fbab927d7..2c489850df 100644 --- a/vendor/indexmap/README.rst +++ b/vendor/indexmap/README.rst @@ -66,6 +66,20 @@ which is roughly: Recent Changes ============== +- 1.6.0 + + - **MSRV**: Rust 1.36 or later is now required. + + - The ``hashbrown`` dependency has been updated to version 0.9. + +- 1.5.2 + + - The new "std" feature will force the use of ``std`` for users that explicitly + want the default ``S = RandomState``, bypassing the autodetection added in 1.3.0, + by @cuviper in PR 145_. + +.. _145: https://github.com/bluss/indexmap/pull/145 + - 1.5.1 - Values can now be indexed by their ``usize`` position by @cuviper in PR 132_. diff --git a/vendor/indexmap/build.rs b/vendor/indexmap/build.rs index 645c0f1c82..9f9fa054f8 100644 --- a/vendor/indexmap/build.rs +++ b/vendor/indexmap/build.rs @@ -1,5 +1,8 @@ fn main() { - let ac = autocfg::new(); - ac.emit_sysroot_crate("std"); + // If "std" is explicitly requested, don't bother probing the target for it. + match std::env::var_os("CARGO_FEATURE_STD") { + Some(_) => autocfg::emit("has_std"), + None => autocfg::new().emit_sysroot_crate("std"), + } autocfg::rerun_path("build.rs"); } diff --git a/vendor/itertools-0.8.2/.cargo-checksum.json b/vendor/itertools-0.8.2/.cargo-checksum.json deleted file mode 100644 index 4df07cd850..0000000000 --- a/vendor/itertools-0.8.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.lock":"bb03f756d39151fea8de875ac282889d4370443e6fee0c4edf5b33e53f983246","Cargo.toml":"e0c22789bdbb1efe1c80b861e7c00da2015b4d7eacb00fcf827ba28d82e36a2e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"7576269ea71f767b99297934c0b2367532690f8c4badc695edf8e04ab6a1e545","README.rst":"86c2f8499d778ff74de701ca291420c244bf4c7be94fb73bed32fcafc4cf467a","benches/bench1.rs":"126211884ea482d5176535ca0b35bfa4d28c62c3377db77aaf7b7c12f712577c","benches/combinations_with_replacement.rs":"b15e1694991a35936b5b4eb8525fbc2bfa3720ecebffb01684e7b4b72541c328","benches/extra/mod.rs":"4c5b03e74fc5b02383500c9da9fd6550262706ee569d70d085700f6d0b5749ba","benches/extra/zipslices.rs":"108dd488de366b2d83fb6bcc603ecbf9a017e165ac19d03440074fa244af3fb2","benches/fold_specialization.rs":"1b9753d6adaf6d1e979d9d2af535255e23a94bb0d4f27b57bb9005a944aaec81","benches/tree_fold1.rs":"84cddbabb1a681f3196430a8e27b060103366143a3ee4c42c3b0628fc00a7543","benches/tuple_combinations.rs":"6a4b89eb2e45fa0c99e5e5942b3196b76998213c66c44b3765b869be42016a82","benches/tuples.rs":"412a952f08bb03695952d5cfd57949dcf28be8b99e3c6653994bdb8af9654653","examples/iris.data":"596ffd580471ca4d4880f8e439c7281f3b50d8249a5960353cb200b1490f63a0","examples/iris.rs":"3996ca0a62762aec2b102f0f4244fe90d4b4354286d68d80cdc40e35f4352ba3","src/adaptors/mod.rs":"d4be18d69488b2c5dc6679f554c0a3eacc079bb9b55996505e56491be13d22cb","src/adaptors/multi_product.rs":"bb239555be38cde1f419bacfd09728f6ccaf51b6b4811c266b5677705175e685","src/combinations.rs":"bfbb4cb3975128b1a4daa96350be6b2f3de1d1a937d8351034a72f9f051cdd73","src/combinations_with_replacement.rs":"dc05611ab3f86a9ffe96dcb10c16d65c7619343d323f20e7142d094abe539bc2","src/concat_impl.rs":"276339b00588f54c25f8ffbe0ae3c0031f7e52fb53c6578554a0bde1681b58a5","src/cons_tuples_impl.rs":"87c620d2ffdd3475218f5f493dbef601491be9f6cdfe57c44929449b32e6709f","src/diff.rs":"921e2b867d7b32ffedc72a5eb780811322d14d1e0883a608b9028a2afcad0df2","src/either_or_both.rs":"b7bf810817795465d9e6e43fd0ba02eebbb58d19b62b2eaaebef10dc2a51e769","src/exactly_one_err.rs":"94aa8d7495dd138720863cfddd6da07ec6f85ea74d9af88d3f08805e7cae2310","src/format.rs":"412fbe02f12311c6fbcec1044f57ad6991783f5a3f323b9c391accfe4915106f","src/free.rs":"473d19906720eb2a1309c0505497658b1426f3ea0c845b40f41f3154194fff18","src/group_map.rs":"872d6e243e649ad30c94973c034596cc3377b10018e361bca07e11c612006de6","src/groupbylazy.rs":"a067a12671be9ae05a9152518103f39f7286fde09f758de8af75a1064a3b5567","src/impl_macros.rs":"eb0bb3f70ec1bcaffa6110ae4134c777951ed1e5f48d8c811dbf0a597dc48faa","src/intersperse.rs":"5ea6966e91b26d3e883a3a68b74c107c7ec47da8ccb5b3b95acd9cbb0bc66e2a","src/kmerge_impl.rs":"44c3645d864a00ae1ae6aa2f09ff8be704e7e2452da02e95d02cd3f588caa3ac","src/lazy_buffer.rs":"ed60449deb6d775b054f6165718ae1b70ee84d69ffc015df5b769b73c3133054","src/lib.rs":"359c00d77510384e3ed18647ecd8e2f618758ab7944ca31eb960dabcfa25fc2a","src/merge_join.rs":"98e6fcc761a558ad21789efe041c3f90e62f6c75e05840670df45ad4f9b07e1f","src/minmax.rs":"4668a7f824fbc133599f43ffb6f7283e5bd603e07df2d8176abc6f25d6af9db0","src/multipeek_impl.rs":"ebe9544d94d0bf7200f7625241a3b5a291b7b564091a08cad40ff08b51f1b1bf","src/pad_tail.rs":"078615a2892f8c6db665074cf6f1be1bef4cf5ee418bc174edcfd4dc703e163f","src/peeking_take_while.rs":"6aea3bb40fb480e9f3695ce2a7a3a2e2346d437ca846d20e6bb3c09beb0934f4","src/permutations.rs":"862a53d18e8f5d600da1c60befcda98978617ab01c744bd9baf1ed3dd74f1261","src/process_results_impl.rs":"5f454cf62ceb82cab7c08c0c190de3ae083e219a8acc7a1a22f17eec9cfcd65c","src/put_back_n_impl.rs":"d35858184c525372b22d14d42cdf63726cf0fd50f5bd42ec7a82d55a8e180e9f","src/rciter_impl.rs":"8f51abc7e1ae3320cc5d56fadd66f880a7a06773be656bd8c4712357f01ae1d9","src/repeatn.rs":"4bd1782364b16105fbef3f3de7bf62780710e5c996db44a00e4b5f16c2625d86","src/size_hint.rs":"c1d35b422a696cf3d63e7c90d8f9fdf01a304cf8156e914287c4ef48fea62dd3","src/sources.rs":"cb6ebe06b05f7da0ac1073ba486c45afaeebf8b558c0f5499f0eacd2cd1785da","src/tee.rs":"59cf9ef0b41882307ea1e3503a2ff351f401f4c43d95acf423a990b0bf0e29ae","src/tuple_impl.rs":"0c7f907e85d2ef0661583b36c7b8a7341b8feadafe28d10539a211dff5c028ea","src/unique_impl.rs":"63db2d720ff5e3d9c0d6c2b245ffff25d4040e4fcbcb2a6524b0f912826f86af","src/with_position.rs":"d922f045f6fa090a431be928f3221c6dc37ac6f9bb54461b3b84f99a7e91244a","src/zip_eq_impl.rs":"f857c69120255db16ad6ddec628c79cb573b1d5179fcebab1906bf5b762c02e3","src/zip_longest.rs":"375325ef069970e6fb83c6097c2824877bb0f06e4f1e664e4fe681804abe003c","src/ziptuple.rs":"d7ae7d3c33185ad74ab2bba750ac337b5c236750cc8341dd9883faf6465712a1","tests/adaptors_no_collect.rs":"2572c5555cc2e494a44714710dbaf5d62965d847f4e620ea09e52a7158371364","tests/fold_specialization.rs":"de403af575c6c77234bff2a5e56581159c5ceeff30eadaac14bfd8d405c16bec","tests/merge_join.rs":"546eaffae40010f15a7bcf95bc53f5e9b67424c5b93df6ffb0aaa1e48e8b90c0","tests/peeking_take_while.rs":"a2ae6474e09620a47bb8a6e3c62929261e72c52881370adb2d22e89aa9e9aec8","tests/quick.rs":"b0d36a7ab4aa8b7283c9440b8a4f4867acab951da9aaec59a7314e1b39782be8","tests/test_core.rs":"8d73cb165698dbfaf0d14e278fbd02bda4b92c2a552912ce1a67388a9fe54bcf","tests/test_std.rs":"40a7a001afbf79e08ec970e091799d7e35ee72fdad8baf16a850a1abecf4e921","tests/tuples.rs":"5323d15a7abf6545b2655167d3206b6cf6a947e9409a244ea6a8cf4ad8ceac64","tests/zip.rs":"fe213d70c4fa114cb4d1930a6b971f4af617a239041ddb87e6b5a9bbe62261b8"},"package":"f56a2d0bc861f9165be4eb3442afd3c236d8a98afd426f65d92324ae1091a484"} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/Cargo.lock b/vendor/itertools-0.8.2/Cargo.lock deleted file mode 100644 index a34644cf2c..0000000000 --- a/vendor/itertools-0.8.2/Cargo.lock +++ /dev/null @@ -1,227 +0,0 @@ -# This file is automatically @generated by Cargo. -# It is not intended for manual editing. -[[package]] -name = "autocfg" -version = "0.1.7" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "bitflags" -version = "1.2.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "cloudabi" -version = "0.0.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "either" -version = "1.5.3" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "fuchsia-cprng" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "itertools" -version = "0.8.2" -dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)", - "quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "libc" -version = "0.2.65" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "permutohedron" -version = "0.2.4" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "quickcheck" -version = "0.7.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.5.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand" -version = "0.6.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_chacha" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.2.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_core" -version = "0.4.2" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "rand_hc" -version = "0.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_isaac" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_jitter" -version = "0.1.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_os" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)", - "fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", - "rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_pcg" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", - "rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rand_xorshift" -version = "0.1.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "rdrand" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi" -version = "0.3.8" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - -[[package]] -name = "winapi-i686-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[[package]] -name = "winapi-x86_64-pc-windows-gnu" -version = "0.4.0" -source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" -"checksum cloudabi 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "ddfc5b9aa5d4507acaf872de71051dfd0e309860e88966e1051e462a077aac4f" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" -"checksum fuchsia-cprng 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a06f77d526c1a601b7c4cdd98f54b5eaabffc14d5f2f0296febdc7f357c6d3ba" -"checksum libc 0.2.65 (registry+https://github.com/rust-lang/crates.io-index)" = "1a31a0627fdf1f6a39ec0dd577e101440b7db22672c0901fe00a9a6fbb5c24e8" -"checksum permutohedron 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b687ff7b5da449d39e418ad391e5e08da53ec334903ddbb921db208908fc372c" -"checksum quickcheck 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "d4537d3e4edf73a15dd059b75bed1c292d17d3ea7517f583cebe716794fcf816" -"checksum rand 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c618c47cd3ebd209790115ab837de41425723956ad3ce2e6a7f09890947cacb9" -"checksum rand 0.6.5 (registry+https://github.com/rust-lang/crates.io-index)" = "6d71dacdc3c88c1fde3885a3be3fbab9f35724e6ce99467f7d9c5026132184ca" -"checksum rand_chacha 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "556d3a1ca6600bfcbab7c7c91ccb085ac7fbbcd70e008a98742e7847f4f7bcef" -"checksum rand_core 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "1961a422c4d189dfb50ffa9320bf1f2a9bd54ecb92792fb9477f99a1045f3372" -"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" -"checksum rand_core 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "9c33a3c44ca05fa6f1807d8e6743f3824e8509beca625669633be0acbdf509dc" -"checksum rand_hc 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7b40677c7be09ae76218dc623efbf7b18e34bced3f38883af07bb75630a21bc4" -"checksum rand_isaac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "ded997c9d5f13925be2a6fd7e66bf1872597f759fd9dd93513dd7e92e5a5ee08" -"checksum rand_jitter 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "1166d5c91dc97b88d1decc3285bb0a99ed84b05cfd0bc2341bdf2d43fc41e39b" -"checksum rand_os 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "7b75f676a1e053fc562eafbb47838d67c84801e38fc1ba459e8f180deabd5071" -"checksum rand_pcg 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "abf9b09b01790cfe0364f52bf32995ea3c39f4d2dd011eac241d2914146d0b44" -"checksum rand_xorshift 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cbf7e9e623549b0e21f6e97cf8ecf247c1a8fd2e8a992ae265314300b2455d5c" -"checksum rdrand 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "678054eb77286b51581ba43620cc911abf02758c91f93f479767aed0f90458b2" -"checksum winapi 0.3.8 (registry+https://github.com/rust-lang/crates.io-index)" = "8093091eeb260906a183e6ae1abdba2ef5ef2257a21801128899c3fc699229c6" -"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" -"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/itertools-0.8.2/Cargo.toml b/vendor/itertools-0.8.2/Cargo.toml deleted file mode 100644 index db22e36866..0000000000 --- a/vendor/itertools-0.8.2/Cargo.toml +++ /dev/null @@ -1,47 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -name = "itertools" -version = "0.8.2" -authors = ["bluss"] -exclude = ["/bors.toml"] -description = "Extra iterator adaptors, iterator methods, free functions, and macros." -documentation = "https://docs.rs/itertools/" -keywords = ["iterator", "data-structure", "zip", "product", "group-by"] -categories = ["algorithms", "rust-patterns"] -license = "MIT/Apache-2.0" -repository = "https://github.com/bluss/rust-itertools" -[package.metadata.release] -no-dev-version = true -[profile.bench] -debug = true - -[lib] -test = false -bench = false -[dependencies.either] -version = "1.0" -default-features = false -[dev-dependencies.permutohedron] -version = "0.2" - -[dev-dependencies.quickcheck] -version = "0.7" -default-features = false - -[dev-dependencies.rand] -version = "0.6" - -[features] -default = ["use_std"] -use_std = [] diff --git a/vendor/itertools-0.8.2/README.rst b/vendor/itertools-0.8.2/README.rst deleted file mode 100644 index b06751afef..0000000000 --- a/vendor/itertools-0.8.2/README.rst +++ /dev/null @@ -1,620 +0,0 @@ - -Itertools -========= - -Extra iterator adaptors, functions and macros. - -Please read the `API documentation here`__ - -__ https://docs.rs/itertools/ - -|build_status|_ |crates|_ - -.. |build_status| image:: https://travis-ci.org/rust-itertools/itertools.svg?branch=master -.. _build_status: https://travis-ci.org/rust-itertools/itertools - -.. |crates| image:: http://meritbadge.herokuapp.com/itertools -.. _crates: https://crates.io/crates/itertools - -How to use with cargo: - -.. code:: toml - - [dependencies] - itertools = "0.8" - -How to use in your crate: - -.. code:: rust - - #[macro_use] extern crate itertools; - - use itertools::Itertools; - -How to contribute ------------------ - -- Fix a bug or implement a new thing -- Include tests for your new feature, preferably a quickcheck test -- Make a Pull Request - -For new features, please first consider filing a PR to `rust-lang/rust `_, -adding your new feature to the `Iterator` trait of the standard library, if you believe it is reasonable. -If it isn't accepted there, proposing it for inclusion in ``itertools`` is a good idea. -The reason for doing is this is so that we avoid future breakage as with ``.flatten()``. -However, if your feature involves heap allocation, such as storing elements in a ``Vec``, -then it can't be accepted into ``libcore``, and you should propose it for ``itertools`` directly instead. - -Recent Changes --------------- -- 0.8.2 - - - Use :code:`slice::iter` instead of :code:`into_iter` to avoid future breakage (`#378 `_, by `@LukasKalbertodt `_) - -- 0.8.1 - - - Added a `.exactly_one() `_ - iterator method that, on success, extracts the single value of an - iterator - ; by `@Xaeroxe `_ - - - Added combinatory iterator adaptors: - - - `.permutations(k) `_: - - ``[0, 1, 2].iter().permutations(2)`` yields - - .. code:: rust - - [ - vec![0, 1], - vec![0, 2], - vec![1, 0], - vec![1, 2], - vec![2, 0], - vec![2, 1], - ] - - ; by `@tobz1000 `_ - - - `.combinations_with_replacement(k) `_: - - ``[0, 1, 2].iter().combinations_with_replacement(2)`` yields - - .. code:: rust - - [ - vec![0, 0], - vec![0, 1], - vec![0, 2], - vec![1, 1], - vec![1, 2], - vec![2, 2], - ] - - ; by `@tommilligan `_ - - - For reference, these methods join the already existing - `.combinations(k) `_: - - ``[0, 1, 2].iter().combinations(2)`` yields - - .. code:: rust - - [ - vec![0, 1], - vec![0, 2], - vec![1, 2], - ] - - - Improved the performance of `.fold() `_-based internal iteration for the - `.intersperse() `_ iterator - ; by `@jswrenn `_ - - - Added - `.dedup_by() `_, - `.merge_by() `_ - and `.kmerge_by() `_ - adaptors that work like - `.dedup() `_, - `.merge() `_ and - `.kmerge() `_, - but taking an additional custom comparison closure parameter. - ; by `@phimuemue `_ - - - Improved the performance of `.all_equal() `_ - ; by `@fyrchik `_ - - - Loosened the bounds on `.partition_map() `_ - to take just a ``FnMut`` closure rather than a ``Fn`` closure, and made its - implementation use internal iteration for better performance - ; by `@danielhenrymantilla `_ - - - Added convenience methods to - `EitherOrBoth `_ elements yielded from the - `.zip_longest() `_ iterator adaptor - ; by `@Avi-D-coder `_ - - - Added `.sum1() `_ - and `.product1() `_ - iterator methods that respectively try to return the sum and the product of - the elements of an iterator **when it is not empty**, otherwise they return - ``None`` - ; by `@Emerentius `_ - -- 0.8.0 - - - Added new adaptor ``.map_into()`` for conversions using ``Into`` by @vorner - - Improved ``Itertools`` docs by @JohnHeitmann - - The return type of ``.sorted/_by/_by_key()`` is now an iterator, not a Vec. - - The return type of the ``izip!(x, y)`` macro with exactly two arguments - is now the usual ``Iterator::zip``. - - Remove ``.flatten()`` in favour of std's ``.flatten()`` - - Deprecate ``.foreach()`` in favour of std's ``.for_each()`` - - Deprecate ``.step()`` in favour of std's ``.step_by()`` - - Deprecate ``repeat_call`` in favour of std's ``repeat_with`` - - Deprecate ``.fold_while()`` in favour of std's ``.try_fold()`` - - Require Rust 1.24 as minimal version. - -- 0.7.11 - - - Add convenience methods to ``EitherOrBoth``, making it more similar to ``Option`` - and ``Either`` by @jethrogb - -- 0.7.10 - - - No changes. - -- 0.7.9 - - - New inclusion policy: See the readme about suggesting features for std before - accepting them in itertools. - - The ``FoldWhile`` type now implements ``Eq`` and ``PartialEq`` by @jturner314 - -- 0.7.8 - - - Add new iterator method ``.tree_fold1()`` which is like ``.fold1()`` - except items are combined in a tree structure (see its docs). - By @scottmcm - - Add more ``Debug`` impls by @phimuemue: KMerge, KMergeBy, MergeJoinBy, - ConsTuples, Intersperse, ProcessResults, RcIter, Tee, TupleWindows, Tee, - ZipLongest, ZipEq, Zip. - -- 0.7.7 - - - Add new iterator method ``.into_group_map() -> HashMap>`` - which turns an iterator of ``(K, V)`` elements into such a hash table, - where values are grouped by key. By @tobz1000 - - Add new free function ``flatten`` for the ``.flatten()`` adaptor. - **NOTE:** recent Rust nightlies have ``Iterator::flatten`` and thus a clash - with our flatten adaptor. One workaround is to use the itertools ``flatten`` - free function. - -- 0.7.6 - - - Add new adaptor ``.multi_cartesian_product()`` which is an n-ary product - iterator by @tobz1000 - - Add new method ``.sorted_by_key()`` by @Xion - - Provide simpler and faster ``.count()`` for ``.unique()`` and ``.unique_by()`` - -- 0.7.5 - - - ``.multipeek()`` now implements ``PeekingNext``, by @nicopap. - -- 0.7.4 - - - Add new adaptor ``.update()`` by @lucasem; this adaptor is used - to modify an element before passing it on in an iterator chain. - -- 0.7.3 - - - Add new method ``.collect_tuple()`` by @matklad; it makes a tuple out of - the iterator's elements if the number of them matches **exactly**. - - Implement ``fold`` and ``collect`` for ``.map_results()`` which means - it reuses the code of the standard ``.map()`` for these methods. - -- 0.7.2 - - - Add new adaptor ``.merge_join_by`` by @srijs; a heterogeneous merge join - for two ordered sequences. - -- 0.7.1 - - - Iterator adaptors and iterators in itertools now use the same ``must_use`` - reminder that the standard library adaptors do, by @matematikaedit and @bluss - *“iterator adaptors are lazy and do nothing unless consumed”*. - -- 0.7.0 - - - Faster ``izip!()`` by @krdln - - - ``izip!()`` is now a wrapper for repeated regular ``.zip()`` and - a single ``.map()``. This means it optimizes as well as the standard - library ``.zip()`` it uses. - **Note:** ``multizip`` and ``izip!()`` are now different! The former - has a named type but the latter optimizes better. - - - Faster ``.unique()`` - - - ``no_std`` support, which is opt-in! - - - Many lovable features are still there without std, like ``izip!()`` - or ``.format()`` or ``.merge()``, but not those that use collections. - - - Trait bounds were required up front instead of just on the type: - ``group_by``'s ``PartialEq`` by @Phlosioneer and ``repeat_call``'s - ``FnMut``. - - Removed deprecated constructor ``Zip::new`` — use ``izip!()`` or ``multizip()`` - -- 0.6.5 - - - Fix bug in ``.cartesian_product()``'s fold (which only was visible for - unfused iterators). - -- 0.6.4 - - - Add specific ``fold`` implementations for ``.cartesian_product()`` and - ``cons_tuples()``, which improves their performance in fold, foreach, and - iterator consumers derived from them. - -- 0.6.3 - - - Add iterator adaptor ``.positions(predicate)`` by @tmccombs - -- 0.6.2 - - - Add function ``process_results`` which can “lift” a function of the regular - values of an iterator so that it can process the ``Ok`` values from an - iterator of ``Results`` instead, by @shepmaster - - Add iterator method ``.concat()`` which combines all iterator elements - into a single collection using the ``Extend`` trait, by @srijs - -- 0.6.1 - - - Better size hint testing and subsequent size hint bugfixes by @rkarp. - Fixes bugs in product, interleave_shortest size hints. - - New iterator method ``.all_equal()`` by @phimuemue - -- 0.6.0 - - - Deprecated names were removed in favour of their replacements - - ``.flatten()`` does not implement double ended iteration anymore - - ``.fold_while()`` uses ``&mut self`` and returns ``FoldWhile``, for - composability (#168) - - ``.foreach()`` and ``.fold1()`` use ``self``, like ``.fold()`` does. - - ``.combinations(0)`` now produces a single empty vector. (#174) - -- 0.5.10 - - - Add itertools method ``.kmerge_by()`` (and corresponding free function) - - Relaxed trait requirement of ``.kmerge()`` and ``.minmax()`` to PartialOrd. - -- 0.5.9 - - - Add multipeek method ``.reset_peek()`` - - Add categories - -- 0.5.8 - - - Add iterator adaptor ``.peeking_take_while()`` and its trait ``PeekingNext``. - -- 0.5.7 - - - Add iterator adaptor ``.with_position()`` - - Fix multipeek's performance for long peeks by using ``VecDeque``. - -- 0.5.6 - - - Add ``.map_results()`` - -- 0.5.5 - - - Many more adaptors now implement ``Debug`` - - Add free function constructor ``repeat_n``. ``RepeatN::new`` is now - deprecated. - -- 0.5.4 - - - Add infinite generator function ``iterate``, that takes a seed and a - closure. - -- 0.5.3 - - - Special-cased ``.fold()`` for flatten and put back. ``.foreach()`` - now uses fold on the iterator, to pick up any iterator specific loop - implementation. - - ``.combinations(n)`` asserts up front that ``n != 0``, instead of - running into an error on the second iterator element. - -- 0.5.2 - - - Add ``.tuples::()`` that iterates by two, three or four elements at - a time (where ``T`` is a tuple type). - - Add ``.tuple_windows::()`` that iterates using a window of the - two, three or four most recent elements. - - Add ``.next_tuple::()`` method, that picks the next two, three or four - elements in one go. - - ``.interleave()`` now has an accurate size hint. - -- 0.5.1 - - - Workaround module/function name clash that made racer crash on completing - itertools. Only internal changes needed. - -- 0.5.0 - - - `Release announcement `_ - - Renamed: - - - combinations is now tuple_combinations - - combinations_n to combinations - - group_by_lazy, chunks_lazy to group_by, chunks - - Unfold::new to unfold() - - RepeatCall::new to repeat_call() - - Zip::new to multizip - - PutBack::new, PutBackN::new to put_back, put_back_n - - PutBack::with_value is now a builder setter, not a constructor - - MultiPeek::new, .multipeek() to multipeek() - - format to format_with and format_default to format - - .into_rc() to rciter - - ``Partition`` enum is now ``Either`` - - - Module reorganization: - - - All iterator structs are under ``itertools::structs`` but also - reexported to the top level, for backwards compatibility - - All free functions are reexported at the root, ``itertools::free`` will - be removed in the next version - - - Removed: - - - ZipSlices, use .zip() instead - - .enumerate_from(), ZipTrusted, due to being unstable - - .mend_slices(), moved to crate odds - - Stride, StrideMut, moved to crate odds - - linspace(), moved to crate itertools-num - - .sort_by(), use .sorted_by() - - .is_empty_hint(), use .size_hint() - - .dropn(), use .dropping() - - .map_fn(), use .map() - - .slice(), use .take() / .skip() - - helper traits in misc - - ``new`` constructors on iterator structs, use Itertools trait or free - functions instead - - ``itertools::size_hint`` is now private - - - Behaviour changes: - - - format and format_with helpers now panic if you try to format them more - than once. - - ``repeat_call`` is not double ended anymore - - - New features: - - - tuple flattening iterator is constructible with ``cons_tuples`` - - itertools reexports ``Either`` from the ``either`` crate. ``Either`` - is an iterator when ``L, R`` are. - - ``MinMaxResult`` now implements Copy and Clone - - tuple_combinations supports 1-4 tuples of combinations (previously just 2) - -- 0.4.19 - - - Add ``.minmax_by()`` - - Add ``itertools::free::cloned`` - - Add ``itertools::free::rciter`` - - Improve ``.step(n)`` slightly to take advantage of specialized Fuse better. - -- 0.4.18 - - - Only changes related to the "unstable" crate feature. This feature is more - or less deprecated. - - - Use deprecated warnings when unstable is enabled. .enumerate_from() will - be removed imminently since it's using a deprecated libstd trait. - -- 0.4.17 - - - Fix bug in .kmerge() that caused it to often produce the wrong order (#134) - -- 0.4.16 - - - Improve precision of the interleave_shortest adaptor's size hint (it is - now computed exactly when possible). - -- 0.4.15 - - - Fixup on top of the workaround in 0.4.14. A function in itertools::free was - removed by mistake and now it is added back again. - -- 0.4.14 - - - Workaround an upstream regression in a rust nightly build that broke - compilation of of itertools::free::{interleave, merge} - -- 0.4.13 - - - Add .minmax() and .minmax_by_key(), iterator methods for finding both minimum - and maximum in one scan. - - Add .format_default(), a simpler version of .format() (lazy formatting - for iterators). - -- 0.4.12 - - - Add .zip_eq(), an adaptor like .zip() except it ensures iterators - of inequal length don't pass silently (instead it panics). - - Add .fold_while(), an iterator method that is a fold that - can short-circuit. - - Add .partition_map(), an iterator method that can separate elements - into two collections. - -- 0.4.11 - - - Add .get() for Stride{,Mut} and .get_mut() for StrideMut - -- 0.4.10 - - - Improve performance of .kmerge() - -- 0.4.9 - - - Add k-ary merge adaptor .kmerge() - - Fix a bug in .islice() with ranges a..b where a > b. - -- 0.4.8 - - - Implement Clone, Debug for Linspace - -- 0.4.7 - - - Add function diff_with() that compares two iterators - - Add .combinations_n(), an n-ary combinations iterator - - Add methods PutBack::with_value and PutBack::into_parts. - -- 0.4.6 - - - Add method .sorted() - - Add module ``itertools::free`` with free function variants of common - iterator adaptors and methods. - For example ``enumerate(iterable)``, ``rev(iterable)``, and so on. - -- 0.4.5 - - - Add .flatten() - -- 0.4.4 - - - Allow composing ZipSlices with itself - -- 0.4.3 - - - Write iproduct!() as a single expression; this allows temporary values - in its arguments. - -- 0.4.2 - - - Add .fold_options() - - Require Rust 1.1 or later - -- 0.4.1 - - - Update .dropping() to take advantage of .nth() - -- 0.4.0 - - - .merge(), .unique() and .dedup() now perform better due to not using - function pointers - - Add free functions enumerate() and rev() - - Breaking changes: - - - Return types of .merge() and .merge_by() renamed and changed - - Method Merge::new removed - - .merge_by() now takes a closure that returns bool. - - Return type of .dedup() changed - - Return type of .mend_slices() changed - - Return type of .unique() changed - - Removed function times(), struct Times: use a range instead - - Removed deprecated macro icompr!() - - Removed deprecated FnMap and method .fn_map(): use .map_fn() - - .interleave_shortest() is no longer guaranteed to act like fused - -- 0.3.25 - - - Rename .sort_by() to .sorted_by(). Old name is deprecated. - - Fix well-formedness warnings from RFC 1214, no user visible impact - -- 0.3.24 - - - Improve performance of .merge()'s ordering function slightly - -- 0.3.23 - - - Added .chunks(), similar to (and based on) .group_by_lazy(). - - Tweak linspace to match numpy.linspace and make it double ended. - -- 0.3.22 - - - Added ZipSlices, a fast zip for slices - -- 0.3.21 - - - Remove `Debug` impl for `Format`, it will have different use later - -- 0.3.20 - - - Optimize .group_by_lazy() - -- 0.3.19 - - - Added .group_by_lazy(), a possibly nonallocating group by - - Added .format(), a nonallocating formatting helper for iterators - - Remove uses of RandomAccessIterator since it has been deprecated in rust. - -- 0.3.17 - - - Added (adopted) Unfold from rust - -- 0.3.16 - - - Added adaptors .unique(), .unique_by() - -- 0.3.15 - - - Added method .sort_by() - -- 0.3.14 - - - Added adaptor .while_some() - -- 0.3.13 - - - Added adaptor .interleave_shortest() - - Added adaptor .pad_using() - -- 0.3.11 - - - Added assert_equal function - -- 0.3.10 - - - Bugfix .combinations() size_hint. - -- 0.3.8 - - - Added source RepeatCall - -- 0.3.7 - - - Added adaptor PutBackN - - Added adaptor .combinations() - -- 0.3.6 - - - Added itertools::partition, partition a sequence in place based on a predicate. - - Deprecate icompr!() with no replacement. - -- 0.3.5 - - - .map_fn() replaces deprecated .fn_map(). - -- 0.3.4 - - - .take_while_ref() *by-ref adaptor* - - .coalesce() *adaptor* - - .mend_slices() *adaptor* - -- 0.3.3 - - - .dropping_back() *method* - - .fold1() *method* - - .is_empty_hint() *method* - -License -------- - -Dual-licensed to be compatible with the Rust project. - -Licensed under the Apache License, Version 2.0 -http://www.apache.org/licenses/LICENSE-2.0 or the MIT license -http://opensource.org/licenses/MIT, at your -option. This file may not be copied, modified, or distributed -except according to those terms. diff --git a/vendor/itertools-0.8.2/benches/bench1.rs b/vendor/itertools-0.8.2/benches/bench1.rs deleted file mode 100644 index 5d2adcad40..0000000000 --- a/vendor/itertools-0.8.2/benches/bench1.rs +++ /dev/null @@ -1,806 +0,0 @@ -#![feature(test)] - -extern crate test; -#[macro_use] extern crate itertools; - -use test::{black_box}; -use itertools::Itertools; - -use itertools::free::cloned; -use itertools::Permutations; - -use std::iter::repeat; -use std::cmp; -use std::ops::{Add, Range}; - -mod extra; - -use extra::ZipSlices; - -#[bench] -fn slice_iter(b: &mut test::Bencher) -{ - let xs: Vec<_> = repeat(1i32).take(20).collect(); - b.iter(|| for elt in xs.iter() { - test::black_box(elt); - }) -} - -#[bench] -fn slice_iter_rev(b: &mut test::Bencher) -{ - let xs: Vec<_> = repeat(1i32).take(20).collect(); - b.iter(|| for elt in xs.iter().rev() { - test::black_box(elt); - }) -} - -#[bench] -fn zip_default_zip(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - for (&x, &y) in xs.iter().zip(&ys) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipdot_i32_default_zip(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0; - for (&x, &y) in xs.iter().zip(&ys) { - s += x * y; - } - s - }) -} - -#[bench] -fn zipdot_f32_default_zip(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0.; - for (&x, &y) in xs.iter().zip(&ys) { - s += x * y; - } - s - }) -} - -#[bench] -fn zip_default_zip3(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let zs = vec![0; 766]; - let xs = black_box(xs); - let ys = black_box(ys); - let zs = black_box(zs); - - b.iter(|| { - for ((&x, &y), &z) in xs.iter().zip(&ys).zip(&zs) { - test::black_box(x); - test::black_box(y); - test::black_box(z); - } - }) -} - -#[bench] -fn zip_slices_ziptuple(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - - b.iter(|| { - let xs = black_box(&xs); - let ys = black_box(&ys); - for (&x, &y) in itertools::multizip((xs, ys)) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipslices(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - for (&x, &y) in ZipSlices::new(&xs, &ys) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipslices_mut(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let mut ys = black_box(ys); - - b.iter(|| { - for (&x, &mut y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) { - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipdot_i32_zipslices(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0i32; - for (&x, &y) in ZipSlices::new(&xs, &ys) { - s += x * y; - } - s - }) -} - -#[bench] -fn zipdot_f32_zipslices(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let mut s = 0.; - for (&x, &y) in ZipSlices::new(&xs, &ys) { - s += x * y; - } - s - }) -} - - -#[bench] -fn zip_checked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let xs = &xs[..len]; - let ys = &ys[..len]; - - for i in 0..len { - let x = xs[i]; - let y = ys[i]; - test::black_box(x); - test::black_box(y); - } - }) -} - -#[bench] -fn zipdot_i32_checked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let xs = &xs[..len]; - let ys = &ys[..len]; - - let mut s = 0i32; - - for i in 0..len { - s += xs[i] * ys[i]; - } - s - }) -} - -#[bench] -fn zipdot_f32_checked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let xs = &xs[..len]; - let ys = &ys[..len]; - - let mut s = 0.; - - for i in 0..len { - s += xs[i] * ys[i]; - } - s - }) -} - -#[bench] -fn zipdot_f32_checked_counted_unrolled_loop(b: &mut test::Bencher) -{ - let xs = vec![2f32; 1024]; - let ys = vec![2f32; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - // Must slice to equal lengths, and then bounds checks are eliminated! - let len = cmp::min(xs.len(), ys.len()); - let mut xs = &xs[..len]; - let mut ys = &ys[..len]; - - let mut s = 0.; - let (mut p0, mut p1, mut p2, mut p3, mut p4, mut p5, mut p6, mut p7) = - (0., 0., 0., 0., 0., 0., 0., 0.); - - // how to unroll and have bounds checks eliminated (by cristicbz) - // split sum into eight parts to enable vectorization (by bluss) - while xs.len() >= 8 { - p0 += xs[0] * ys[0]; - p1 += xs[1] * ys[1]; - p2 += xs[2] * ys[2]; - p3 += xs[3] * ys[3]; - p4 += xs[4] * ys[4]; - p5 += xs[5] * ys[5]; - p6 += xs[6] * ys[6]; - p7 += xs[7] * ys[7]; - - xs = &xs[8..]; - ys = &ys[8..]; - } - s += p0 + p4; - s += p1 + p5; - s += p2 + p6; - s += p3 + p7; - - for i in 0..xs.len() { - s += xs[i] * ys[i]; - } - s - }) -} - -#[bench] -fn zip_unchecked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let len = cmp::min(xs.len(), ys.len()); - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - test::black_box(x); - test::black_box(y); - } - } - }) -} - -#[bench] -fn zipdot_i32_unchecked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2; 1024]; - let ys = vec![2; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let len = cmp::min(xs.len(), ys.len()); - let mut s = 0i32; - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - s += x * y; - } - } - s - }) -} - -#[bench] -fn zipdot_f32_unchecked_counted_loop(b: &mut test::Bencher) -{ - let xs = vec![2.; 1024]; - let ys = vec![2.; 768]; - let xs = black_box(xs); - let ys = black_box(ys); - - b.iter(|| { - let len = cmp::min(xs.len(), ys.len()); - let mut s = 0f32; - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - s += x * y; - } - } - s - }) -} - -#[bench] -fn zip_unchecked_counted_loop3(b: &mut test::Bencher) -{ - let xs = vec![0; 1024]; - let ys = vec![0; 768]; - let zs = vec![0; 766]; - let xs = black_box(xs); - let ys = black_box(ys); - let zs = black_box(zs); - - b.iter(|| { - let len = cmp::min(xs.len(), cmp::min(ys.len(), zs.len())); - for i in 0..len { - unsafe { - let x = *xs.get_unchecked(i); - let y = *ys.get_unchecked(i); - let z = *zs.get_unchecked(i); - test::black_box(x); - test::black_box(y); - test::black_box(z); - } - } - }) -} - -#[bench] -fn group_by_lazy_1(b: &mut test::Bencher) { - let mut data = vec![0; 1024]; - for (index, elt) in data.iter_mut().enumerate() { - *elt = index / 10; - } - - let data = test::black_box(data); - - b.iter(|| { - for (_key, group) in &data.iter().group_by(|elt| **elt) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn group_by_lazy_2(b: &mut test::Bencher) { - let mut data = vec![0; 1024]; - for (index, elt) in data.iter_mut().enumerate() { - *elt = index / 2; - } - - let data = test::black_box(data); - - b.iter(|| { - for (_key, group) in &data.iter().group_by(|elt| **elt) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn slice_chunks(b: &mut test::Bencher) { - let data = vec![0; 1024]; - - let data = test::black_box(data); - let sz = test::black_box(10); - - b.iter(|| { - for group in data.chunks(sz) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn chunks_lazy_1(b: &mut test::Bencher) { - let data = vec![0; 1024]; - - let data = test::black_box(data); - let sz = test::black_box(10); - - b.iter(|| { - for group in &data.iter().chunks(sz) { - for elt in group { - test::black_box(elt); - } - } - }) -} - -#[bench] -fn equal(b: &mut test::Bencher) { - let data = vec![7; 1024]; - let l = data.len(); - let alpha = test::black_box(&data[1..]); - let beta = test::black_box(&data[..l - 1]); - b.iter(|| { - itertools::equal(alpha, beta) - }) -} - -#[bench] -fn merge_default(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - b.iter(|| { - data1.iter().merge(&data2).count() - }) -} - -#[bench] -fn merge_by_cmp(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - b.iter(|| { - data1.iter().merge_by(&data2, PartialOrd::le).count() - }) -} - -#[bench] -fn merge_by_lt(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - b.iter(|| { - data1.iter().merge_by(&data2, |a, b| a <= b).count() - }) -} - -#[bench] -fn kmerge_default(b: &mut test::Bencher) { - let mut data1 = vec![0; 1024]; - let mut data2 = vec![0; 800]; - let mut x = 0; - for (_, elt) in data1.iter_mut().enumerate() { - *elt = x; - x += 1; - } - - let mut y = 0; - for (i, elt) in data2.iter_mut().enumerate() { - *elt += y; - if i % 3 == 0 { - y += 3; - } else { - y += 0; - } - } - let data1 = test::black_box(data1); - let data2 = test::black_box(data2); - let its = &[data1.iter(), data2.iter()]; - b.iter(|| { - its.iter().cloned().kmerge().count() - }) -} - -#[bench] -fn kmerge_tenway(b: &mut test::Bencher) { - let mut data = vec![0; 10240]; - - let mut state = 1729u16; - fn rng(state: &mut u16) -> u16 { - let new = state.wrapping_mul(31421) + 6927; - *state = new; - new - } - - for elt in &mut data { - *elt = rng(&mut state); - } - - let mut chunks = Vec::new(); - let mut rest = &mut data[..]; - while rest.len() > 0 { - let chunk_len = 1 + rng(&mut state) % 512; - let chunk_len = cmp::min(rest.len(), chunk_len as usize); - let (fst, tail) = {rest}.split_at_mut(chunk_len); - fst.sort(); - chunks.push(fst.iter().cloned()); - rest = tail; - } - - // println!("Chunk lengths: {}", chunks.iter().format_with(", ", |elt, f| f(&elt.len()))); - - b.iter(|| { - chunks.iter().cloned().kmerge().count() - }) -} - - -fn fast_integer_sum(iter: I) -> I::Item - where I: IntoIterator, - I::Item: Default + Add -{ - iter.into_iter().fold(<_>::default(), |x, y| x + y) -} - - -#[bench] -fn step_vec_2(b: &mut test::Bencher) { - let v = vec![0; 1024]; - b.iter(|| { - fast_integer_sum(cloned(v.iter().step(2))) - }); -} - -#[bench] -fn step_vec_10(b: &mut test::Bencher) { - let v = vec![0; 1024]; - b.iter(|| { - fast_integer_sum(cloned(v.iter().step(10))) - }); -} - -#[bench] -fn step_range_2(b: &mut test::Bencher) { - let v = black_box(0..1024); - b.iter(|| { - fast_integer_sum(v.clone().step(2)) - }); -} - -#[bench] -fn step_range_10(b: &mut test::Bencher) { - let v = black_box(0..1024); - b.iter(|| { - fast_integer_sum(v.clone().step(10)) - }); -} - -#[bench] -fn cartesian_product_iterator(b: &mut test::Bencher) -{ - let xs = vec![0; 16]; - - b.iter(|| { - let mut sum = 0; - for (&x, &y, &z) in iproduct!(&xs, &xs, &xs) { - sum += x; - sum += y; - sum += z; - } - sum - }) -} - -#[bench] -fn cartesian_product_fold(b: &mut test::Bencher) -{ - let xs = vec![0; 16]; - - b.iter(|| { - let mut sum = 0; - iproduct!(&xs, &xs, &xs).fold((), |(), (&x, &y, &z)| { - sum += x; - sum += y; - sum += z; - }); - sum - }) -} - -#[bench] -fn multi_cartesian_product_iterator(b: &mut test::Bencher) -{ - let xs = [vec![0; 16], vec![0; 16], vec![0; 16]]; - - b.iter(|| { - let mut sum = 0; - for x in xs.iter().multi_cartesian_product() { - sum += x[0]; - sum += x[1]; - sum += x[2]; - } - sum - }) -} - -#[bench] -fn multi_cartesian_product_fold(b: &mut test::Bencher) -{ - let xs = [vec![0; 16], vec![0; 16], vec![0; 16]]; - - b.iter(|| { - let mut sum = 0; - xs.iter().multi_cartesian_product().fold((), |(), x| { - sum += x[0]; - sum += x[1]; - sum += x[2]; - }); - sum - }) -} - -#[bench] -fn cartesian_product_nested_for(b: &mut test::Bencher) -{ - let xs = vec![0; 16]; - - b.iter(|| { - let mut sum = 0; - for &x in &xs { - for &y in &xs { - for &z in &xs { - sum += x; - sum += y; - sum += z; - } - } - } - sum - }) -} - -#[bench] -fn all_equal(b: &mut test::Bencher) { - let mut xs = vec![0; 5_000_000]; - xs.extend(vec![1; 5_000_000]); - - b.iter(|| xs.iter().all_equal()) -} - -#[bench] -fn all_equal_for(b: &mut test::Bencher) { - let mut xs = vec![0; 5_000_000]; - xs.extend(vec![1; 5_000_000]); - - b.iter(|| { - for &x in &xs { - if x != xs[0] { - return false; - } - } - true - }) -} - -#[bench] -fn all_equal_default(b: &mut test::Bencher) { - let mut xs = vec![0; 5_000_000]; - xs.extend(vec![1; 5_000_000]); - - b.iter(|| xs.iter().dedup().nth(1).is_none()) -} - -const PERM_COUNT: usize = 6; - -#[bench] -fn permutations_iter(b: &mut test::Bencher) { - struct NewIterator(Range); - - impl Iterator for NewIterator { - type Item = usize; - - fn next(&mut self) -> Option { - self.0.next() - } - } - - b.iter(|| { - for _ in NewIterator(0..PERM_COUNT).permutations(PERM_COUNT) { - - } - }) -} - -#[bench] -fn permutations_range(b: &mut test::Bencher) { - b.iter(|| { - for _ in (0..PERM_COUNT).permutations(PERM_COUNT) { - - } - }) -} - -#[bench] -fn permutations_slice(b: &mut test::Bencher) { - let v = (0..PERM_COUNT).collect_vec(); - - b.iter(|| { - for _ in v.as_slice().iter().permutations(PERM_COUNT) { - - } - }) -} diff --git a/vendor/itertools-0.8.2/benches/combinations_with_replacement.rs b/vendor/itertools-0.8.2/benches/combinations_with_replacement.rs deleted file mode 100644 index 0652e49e79..0000000000 --- a/vendor/itertools-0.8.2/benches/combinations_with_replacement.rs +++ /dev/null @@ -1,34 +0,0 @@ -#![feature(test)] - -extern crate itertools; -extern crate test; - -use itertools::Itertools; -use test::{black_box, Bencher}; - -#[bench] -fn comb_replacement_n10_k5(b: &mut Bencher) { - b.iter(|| { - for i in (0..10).combinations_with_replacement(5) { - black_box(i); - } - }); -} - -#[bench] -fn comb_replacement_n5_k10(b: &mut Bencher) { - b.iter(|| { - for i in (0..5).combinations_with_replacement(10) { - black_box(i); - } - }); -} - -#[bench] -fn comb_replacement_n10_k10(b: &mut Bencher) { - b.iter(|| { - for i in (0..10).combinations_with_replacement(10) { - black_box(i); - } - }); -} diff --git a/vendor/itertools-0.8.2/benches/extra/mod.rs b/vendor/itertools-0.8.2/benches/extra/mod.rs deleted file mode 100644 index 5ddb5772f4..0000000000 --- a/vendor/itertools-0.8.2/benches/extra/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ - - -pub use self::zipslices::ZipSlices; -mod zipslices; diff --git a/vendor/itertools-0.8.2/benches/extra/zipslices.rs b/vendor/itertools-0.8.2/benches/extra/zipslices.rs deleted file mode 100644 index 493a539fd6..0000000000 --- a/vendor/itertools-0.8.2/benches/extra/zipslices.rs +++ /dev/null @@ -1,189 +0,0 @@ -use std::cmp; - -// Note: There are different ways to implement ZipSlices. -// This version performed the best in benchmarks. -// -// I also implemented a version with three pointes (tptr, tend, uptr), -// that mimiced slice::Iter and only checked bounds by using tptr == tend, -// but that was inferior to this solution. - -/// An iterator which iterates two slices simultaneously. -/// -/// `ZipSlices` acts like a double-ended `.zip()` iterator. -/// -/// It was intended to be more efficient than `.zip()`, and it was, then -/// rustc changed how it optimizes so it can not promise improved performance -/// at this time. -/// -/// Note that elements past the end of the shortest of the two slices are ignored. -/// -/// Iterator element type for `ZipSlices` is `(T::Item, U::Item)`. For example, -/// for a `ZipSlices<&'a [A], &'b mut [B]>`, the element type is `(&'a A, &'b mut B)`. -#[derive(Clone)] -pub struct ZipSlices { - t: T, - u: U, - len: usize, - index: usize, -} - -impl<'a, 'b, A, B> ZipSlices<&'a [A], &'b [B]> { - /// Create a new `ZipSlices` from slices `a` and `b`. - /// - /// Act like a double-ended `.zip()` iterator, but more efficiently. - /// - /// Note that elements past the end of the shortest of the two slices are ignored. - #[inline(always)] - pub fn new(a: &'a [A], b: &'b [B]) -> Self { - let minl = cmp::min(a.len(), b.len()); - ZipSlices { - t: a, - u: b, - len: minl, - index: 0, - } - } -} - -impl ZipSlices - where T: Slice, - U: Slice -{ - /// Create a new `ZipSlices` from slices `a` and `b`. - /// - /// Act like a double-ended `.zip()` iterator, but more efficiently. - /// - /// Note that elements past the end of the shortest of the two slices are ignored. - #[inline(always)] - pub fn from_slices(a: T, b: U) -> Self { - let minl = cmp::min(a.len(), b.len()); - ZipSlices { - t: a, - u: b, - len: minl, - index: 0, - } - } -} - -impl Iterator for ZipSlices - where T: Slice, - U: Slice -{ - type Item = (T::Item, U::Item); - - #[inline(always)] - fn next(&mut self) -> Option { - unsafe { - if self.index >= self.len { - None - } else { - let i = self.index; - self.index += 1; - Some(( - self.t.get_unchecked(i), - self.u.get_unchecked(i))) - } - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let len = self.len - self.index; - (len, Some(len)) - } -} - -impl DoubleEndedIterator for ZipSlices - where T: Slice, - U: Slice -{ - #[inline(always)] - fn next_back(&mut self) -> Option { - unsafe { - if self.index >= self.len { - None - } else { - self.len -= 1; - let i = self.len; - Some(( - self.t.get_unchecked(i), - self.u.get_unchecked(i))) - } - } - } -} - -impl ExactSizeIterator for ZipSlices - where T: Slice, - U: Slice -{} - -unsafe impl Slice for ZipSlices - where T: Slice, - U: Slice -{ - type Item = (T::Item, U::Item); - - fn len(&self) -> usize { - self.len - self.index - } - - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item { - (self.t.get_unchecked(i), - self.u.get_unchecked(i)) - } -} - -/// A helper trait to let `ZipSlices` accept both `&[T]` and `&mut [T]`. -/// -/// Unsafe trait because: -/// -/// - Implementors must guarantee that `get_unchecked` is valid for all indices `0..len()`. -pub unsafe trait Slice { - /// The type of a reference to the slice's elements - type Item; - #[doc(hidden)] - fn len(&self) -> usize; - #[doc(hidden)] - unsafe fn get_unchecked(&mut self, i: usize) -> Self::Item; -} - -unsafe impl<'a, T> Slice for &'a [T] { - type Item = &'a T; - #[inline(always)] - fn len(&self) -> usize { (**self).len() } - #[inline(always)] - unsafe fn get_unchecked(&mut self, i: usize) -> &'a T { - debug_assert!(i < self.len()); - (**self).get_unchecked(i) - } -} - -unsafe impl<'a, T> Slice for &'a mut [T] { - type Item = &'a mut T; - #[inline(always)] - fn len(&self) -> usize { (**self).len() } - #[inline(always)] - unsafe fn get_unchecked(&mut self, i: usize) -> &'a mut T { - debug_assert!(i < self.len()); - // override the lifetime constraints of &mut &'a mut [T] - (*(*self as *mut [T])).get_unchecked_mut(i) - } -} - -#[test] -fn zipslices() { - - let xs = [1, 2, 3, 4, 5, 6]; - let ys = [1, 2, 3, 7]; - ::itertools::assert_equal(ZipSlices::new(&xs, &ys), xs.iter().zip(&ys)); - - let xs = [1, 2, 3, 4, 5, 6]; - let mut ys = [0; 6]; - for (x, y) in ZipSlices::from_slices(&xs[..], &mut ys[..]) { - *y = *x; - } - ::itertools::assert_equal(&xs, &ys); -} - diff --git a/vendor/itertools-0.8.2/benches/fold_specialization.rs b/vendor/itertools-0.8.2/benches/fold_specialization.rs deleted file mode 100644 index db3c995876..0000000000 --- a/vendor/itertools-0.8.2/benches/fold_specialization.rs +++ /dev/null @@ -1,66 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use itertools::Itertools; - -struct Unspecialized(I); - -impl Iterator for Unspecialized -where I: Iterator -{ - type Item = I::Item; - - #[inline(always)] - fn next(&mut self) -> Option { - self.0.next() - } - - #[inline(always)] - fn size_hint(&self) -> (usize, Option) { - self.0.size_hint() - } -} - -mod specialization { - use super::*; - - mod intersperse { - use super::*; - - #[bench] - fn external(b: &mut test::Bencher) - { - let arr = [1; 1024]; - - b.iter(|| { - let mut sum = 0; - for &x in arr.into_iter().intersperse(&0) { - sum += x; - } - sum - }) - } - - #[bench] - fn internal_specialized(b: &mut test::Bencher) - { - let arr = [1; 1024]; - - b.iter(|| { - arr.into_iter().intersperse(&0).fold(0, |acc, x| acc + x) - }) - } - - #[bench] - fn internal_unspecialized(b: &mut test::Bencher) - { - let arr = [1; 1024]; - - b.iter(|| { - Unspecialized(arr.into_iter().intersperse(&0)).fold(0, |acc, x| acc + x) - }) - } - } -} diff --git a/vendor/itertools-0.8.2/benches/tree_fold1.rs b/vendor/itertools-0.8.2/benches/tree_fold1.rs deleted file mode 100644 index b71589f3fe..0000000000 --- a/vendor/itertools-0.8.2/benches/tree_fold1.rs +++ /dev/null @@ -1,126 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use itertools::Itertools; -use itertools::cloned; -use test::Bencher; - -trait IterEx : Iterator { - // Another efficient implementation against which to compare, - // but needs `std` so is less desirable. - fn tree_fold1_vec(self, mut f: F) -> Option - where F: FnMut(Self::Item, Self::Item) -> Self::Item, - Self: Sized, - { - let hint = self.size_hint().0; - let cap = std::mem::size_of::() * 8 - hint.leading_zeros() as usize; - let mut stack = Vec::with_capacity(cap); - self.enumerate().foreach(|(mut i, mut x)| { - while (i & 1) != 0 { - x = f(stack.pop().unwrap(), x); - i >>= 1; - } - stack.push(x); - }); - stack.into_iter().fold1(f) - } -} -impl IterEx for T {} - -macro_rules! def_benchs { - ($N:expr, - $FUN:ident, - $BENCH_NAME:ident, - ) => ( - mod $BENCH_NAME { - use super::*; - - #[bench] - fn sum(b: &mut Bencher) { - let v: Vec = (0.. $N).collect(); - b.iter(|| { - cloned(&v).$FUN(|x, y| x + y) - }); - } - - #[bench] - fn complex_iter(b: &mut Bencher) { - let u = (3..).take($N / 2); - let v = (5..).take($N / 2); - let it = u.chain(v); - - b.iter(|| { - it.clone().map(|x| x as f32).$FUN(f32::atan2) - }); - } - - #[bench] - fn string_format(b: &mut Bencher) { - // This goes quadratic with linear `fold1`, so use a smaller - // size to not waste too much time in travis. The allocations - // in here are so expensive anyway that it'll still take - // way longer per iteration than the other two benchmarks. - let v: Vec = (0.. ($N/4)).collect(); - b.iter(|| { - cloned(&v).map(|x| x.to_string()).$FUN(|x, y| format!("{} + {}", x, y)) - }); - } - } - ) -} - -def_benchs!{ - 10_000, - fold1, - fold1_10k, -} - -def_benchs!{ - 10_000, - tree_fold1, - tree_fold1_stack_10k, -} - -def_benchs!{ - 10_000, - tree_fold1_vec, - tree_fold1_vec_10k, -} - -def_benchs!{ - 100, - fold1, - fold1_100, -} - -def_benchs!{ - 100, - tree_fold1, - tree_fold1_stack_100, -} - -def_benchs!{ - 100, - tree_fold1_vec, - tree_fold1_vec_100, -} - -def_benchs!{ - 8, - fold1, - fold1_08, -} - -def_benchs!{ - 8, - tree_fold1, - tree_fold1_stack_08, -} - -def_benchs!{ - 8, - tree_fold1_vec, - tree_fold1_vec_08, -} diff --git a/vendor/itertools-0.8.2/benches/tuple_combinations.rs b/vendor/itertools-0.8.2/benches/tuple_combinations.rs deleted file mode 100644 index 4a14b1d0bd..0000000000 --- a/vendor/itertools-0.8.2/benches/tuple_combinations.rs +++ /dev/null @@ -1,97 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use test::{black_box, Bencher}; -use itertools::Itertools; - -// approximate 100_000 iterations for each combination -const N1: usize = 100_000; -const N2: usize = 448; -const N3: usize = 86; -const N4: usize = 41; - -#[bench] -fn comb_for1(b: &mut Bencher) { - b.iter(|| { - for i in 0..N1 { - black_box(i); - } - }); -} - -#[bench] -fn comb_for2(b: &mut Bencher) { - b.iter(|| { - for i in 0..N2 { - for j in (i + 1)..N2 { - black_box(i + j); - } - } - }); -} - -#[bench] -fn comb_for3(b: &mut Bencher) { - b.iter(|| { - for i in 0..N3 { - for j in (i + 1)..N3 { - for k in (j + 1)..N3 { - black_box(i + j + k); - } - } - } - }); -} - -#[bench] -fn comb_for4(b: &mut Bencher) { - b.iter(|| { - for i in 0..N4 { - for j in (i + 1)..N4 { - for k in (j + 1)..N4 { - for l in (k + 1)..N4 { - black_box(i + j + k + l); - } - } - } - } - }); -} - -#[bench] -fn comb_c1(b: &mut Bencher) { - b.iter(|| { - for (i,) in (0..N1).tuple_combinations() { - black_box(i); - } - }); -} - -#[bench] -fn comb_c2(b: &mut Bencher) { - b.iter(|| { - for (i, j) in (0..N2).tuple_combinations() { - black_box(i + j); - } - }); -} - -#[bench] -fn comb_c3(b: &mut Bencher) { - b.iter(|| { - for (i, j, k) in (0..N3).tuple_combinations() { - black_box(i + j + k); - } - }); -} - -#[bench] -fn comb_c4(b: &mut Bencher) { - b.iter(|| { - for (i, j, k, l) in (0..N4).tuple_combinations() { - black_box(i + j + k + l); - } - }); -} diff --git a/vendor/itertools-0.8.2/benches/tuples.rs b/vendor/itertools-0.8.2/benches/tuples.rs deleted file mode 100644 index b0f2990fdf..0000000000 --- a/vendor/itertools-0.8.2/benches/tuples.rs +++ /dev/null @@ -1,190 +0,0 @@ -#![feature(test)] - -extern crate test; -extern crate itertools; - -use test::Bencher; -use itertools::Itertools; - -fn s1(a: u32) -> u32 { - a -} - -fn s2(a: u32, b: u32) -> u32 { - a + b -} - -fn s3(a: u32, b: u32, c: u32) -> u32 { - a + b + c -} - -fn s4(a: u32, b: u32, c: u32, d: u32) -> u32 { - a + b + c + d -} - -fn sum_s1(s: &[u32]) -> u32 { - s1(s[0]) -} - -fn sum_s2(s: &[u32]) -> u32 { - s2(s[0], s[1]) -} - -fn sum_s3(s: &[u32]) -> u32 { - s3(s[0], s[1], s[2]) -} - -fn sum_s4(s: &[u32]) -> u32 { - s4(s[0], s[1], s[2], s[3]) -} - -fn sum_t1(s: &(&u32, )) -> u32 { - s1(*s.0) -} - -fn sum_t2(s: &(&u32, &u32)) -> u32 { - s2(*s.0, *s.1) -} - -fn sum_t3(s: &(&u32, &u32, &u32)) -> u32 { - s3(*s.0, *s.1, *s.2) -} - -fn sum_t4(s: &(&u32, &u32, &u32, &u32)) -> u32 { - s4(*s.0, *s.1, *s.2, *s.3) -} - -macro_rules! def_benchs { - ($N:expr; - $TUPLE_FUN:ident, - $TUPLES:ident, - $TUPLE_WINDOWS:ident; - $SLICE_FUN:ident, - $CHUNKS:ident, - $WINDOWS:ident; - $FOR_CHUNKS:ident, - $FOR_WINDOWS:ident - ) => ( - #[bench] - fn $FOR_CHUNKS(b: &mut Bencher) { - let v: Vec = (0.. $N * 1_000).collect(); - let mut s = 0; - b.iter(|| { - let mut j = 0; - for _ in 0..1_000 { - s += $SLICE_FUN(&v[j..(j + $N)]); - j += $N; - } - s - }); - } - - #[bench] - fn $FOR_WINDOWS(b: &mut Bencher) { - let v: Vec = (0..1_000).collect(); - let mut s = 0; - b.iter(|| { - for i in 0..(1_000 - $N) { - s += $SLICE_FUN(&v[i..(i + $N)]); - } - s - }); - } - - #[bench] - fn $TUPLES(b: &mut Bencher) { - let v: Vec = (0.. $N * 1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.iter().tuples() { - s += $TUPLE_FUN(&x); - } - s - }); - } - - #[bench] - fn $CHUNKS(b: &mut Bencher) { - let v: Vec = (0.. $N * 1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.chunks($N) { - s += $SLICE_FUN(x); - } - s - }); - } - - #[bench] - fn $TUPLE_WINDOWS(b: &mut Bencher) { - let v: Vec = (0..1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.iter().tuple_windows() { - s += $TUPLE_FUN(&x); - } - s - }); - } - - #[bench] - fn $WINDOWS(b: &mut Bencher) { - let v: Vec = (0..1_000).collect(); - let mut s = 0; - b.iter(|| { - for x in v.windows($N) { - s += $SLICE_FUN(x); - } - s - }); - } - ) -} - -def_benchs!{ - 1; - sum_t1, - tuple_chunks_1, - tuple_windows_1; - sum_s1, - slice_chunks_1, - slice_windows_1; - for_chunks_1, - for_windows_1 -} - -def_benchs!{ - 2; - sum_t2, - tuple_chunks_2, - tuple_windows_2; - sum_s2, - slice_chunks_2, - slice_windows_2; - for_chunks_2, - for_windows_2 -} - -def_benchs!{ - 3; - sum_t3, - tuple_chunks_3, - tuple_windows_3; - sum_s3, - slice_chunks_3, - slice_windows_3; - for_chunks_3, - for_windows_3 -} - -def_benchs!{ - 4; - sum_t4, - tuple_chunks_4, - tuple_windows_4; - sum_s4, - slice_chunks_4, - slice_windows_4; - for_chunks_4, - for_windows_4 -} diff --git a/vendor/itertools-0.8.2/examples/iris.data b/vendor/itertools-0.8.2/examples/iris.data deleted file mode 100644 index a3490e0e07..0000000000 --- a/vendor/itertools-0.8.2/examples/iris.data +++ /dev/null @@ -1,150 +0,0 @@ -5.1,3.5,1.4,0.2,Iris-setosa -4.9,3.0,1.4,0.2,Iris-setosa -4.7,3.2,1.3,0.2,Iris-setosa -4.6,3.1,1.5,0.2,Iris-setosa -5.0,3.6,1.4,0.2,Iris-setosa -5.4,3.9,1.7,0.4,Iris-setosa -4.6,3.4,1.4,0.3,Iris-setosa -5.0,3.4,1.5,0.2,Iris-setosa -4.4,2.9,1.4,0.2,Iris-setosa -4.9,3.1,1.5,0.1,Iris-setosa -5.4,3.7,1.5,0.2,Iris-setosa -4.8,3.4,1.6,0.2,Iris-setosa -4.8,3.0,1.4,0.1,Iris-setosa -4.3,3.0,1.1,0.1,Iris-setosa -5.8,4.0,1.2,0.2,Iris-setosa -5.7,4.4,1.5,0.4,Iris-setosa -5.4,3.9,1.3,0.4,Iris-setosa -5.1,3.5,1.4,0.3,Iris-setosa -5.7,3.8,1.7,0.3,Iris-setosa -5.1,3.8,1.5,0.3,Iris-setosa -5.4,3.4,1.7,0.2,Iris-setosa -5.1,3.7,1.5,0.4,Iris-setosa -4.6,3.6,1.0,0.2,Iris-setosa -5.1,3.3,1.7,0.5,Iris-setosa -4.8,3.4,1.9,0.2,Iris-setosa -5.0,3.0,1.6,0.2,Iris-setosa -5.0,3.4,1.6,0.4,Iris-setosa -5.2,3.5,1.5,0.2,Iris-setosa -5.2,3.4,1.4,0.2,Iris-setosa -4.7,3.2,1.6,0.2,Iris-setosa -4.8,3.1,1.6,0.2,Iris-setosa -5.4,3.4,1.5,0.4,Iris-setosa -5.2,4.1,1.5,0.1,Iris-setosa -5.5,4.2,1.4,0.2,Iris-setosa -4.9,3.1,1.5,0.1,Iris-setosa -5.0,3.2,1.2,0.2,Iris-setosa -5.5,3.5,1.3,0.2,Iris-setosa -4.9,3.1,1.5,0.1,Iris-setosa -4.4,3.0,1.3,0.2,Iris-setosa -5.1,3.4,1.5,0.2,Iris-setosa -5.0,3.5,1.3,0.3,Iris-setosa -4.5,2.3,1.3,0.3,Iris-setosa -4.4,3.2,1.3,0.2,Iris-setosa -5.0,3.5,1.6,0.6,Iris-setosa -5.1,3.8,1.9,0.4,Iris-setosa -4.8,3.0,1.4,0.3,Iris-setosa -5.1,3.8,1.6,0.2,Iris-setosa -4.6,3.2,1.4,0.2,Iris-setosa -5.3,3.7,1.5,0.2,Iris-setosa -5.0,3.3,1.4,0.2,Iris-setosa -7.0,3.2,4.7,1.4,Iris-versicolor -6.4,3.2,4.5,1.5,Iris-versicolor -6.9,3.1,4.9,1.5,Iris-versicolor -5.5,2.3,4.0,1.3,Iris-versicolor -6.5,2.8,4.6,1.5,Iris-versicolor -5.7,2.8,4.5,1.3,Iris-versicolor -6.3,3.3,4.7,1.6,Iris-versicolor -4.9,2.4,3.3,1.0,Iris-versicolor -6.6,2.9,4.6,1.3,Iris-versicolor -5.2,2.7,3.9,1.4,Iris-versicolor -5.0,2.0,3.5,1.0,Iris-versicolor -5.9,3.0,4.2,1.5,Iris-versicolor -6.0,2.2,4.0,1.0,Iris-versicolor -6.1,2.9,4.7,1.4,Iris-versicolor -5.6,2.9,3.6,1.3,Iris-versicolor -6.7,3.1,4.4,1.4,Iris-versicolor -5.6,3.0,4.5,1.5,Iris-versicolor -5.8,2.7,4.1,1.0,Iris-versicolor -6.2,2.2,4.5,1.5,Iris-versicolor -5.6,2.5,3.9,1.1,Iris-versicolor -5.9,3.2,4.8,1.8,Iris-versicolor -6.1,2.8,4.0,1.3,Iris-versicolor -6.3,2.5,4.9,1.5,Iris-versicolor -6.1,2.8,4.7,1.2,Iris-versicolor -6.4,2.9,4.3,1.3,Iris-versicolor -6.6,3.0,4.4,1.4,Iris-versicolor -6.8,2.8,4.8,1.4,Iris-versicolor -6.7,3.0,5.0,1.7,Iris-versicolor -6.0,2.9,4.5,1.5,Iris-versicolor -5.7,2.6,3.5,1.0,Iris-versicolor -5.5,2.4,3.8,1.1,Iris-versicolor -5.5,2.4,3.7,1.0,Iris-versicolor -5.8,2.7,3.9,1.2,Iris-versicolor -6.0,2.7,5.1,1.6,Iris-versicolor -5.4,3.0,4.5,1.5,Iris-versicolor -6.0,3.4,4.5,1.6,Iris-versicolor -6.7,3.1,4.7,1.5,Iris-versicolor -6.3,2.3,4.4,1.3,Iris-versicolor -5.6,3.0,4.1,1.3,Iris-versicolor -5.5,2.5,4.0,1.3,Iris-versicolor -5.5,2.6,4.4,1.2,Iris-versicolor -6.1,3.0,4.6,1.4,Iris-versicolor -5.8,2.6,4.0,1.2,Iris-versicolor -5.0,2.3,3.3,1.0,Iris-versicolor -5.6,2.7,4.2,1.3,Iris-versicolor -5.7,3.0,4.2,1.2,Iris-versicolor -5.7,2.9,4.2,1.3,Iris-versicolor -6.2,2.9,4.3,1.3,Iris-versicolor -5.1,2.5,3.0,1.1,Iris-versicolor -5.7,2.8,4.1,1.3,Iris-versicolor -6.3,3.3,6.0,2.5,Iris-virginica -5.8,2.7,5.1,1.9,Iris-virginica -7.1,3.0,5.9,2.1,Iris-virginica -6.3,2.9,5.6,1.8,Iris-virginica -6.5,3.0,5.8,2.2,Iris-virginica -7.6,3.0,6.6,2.1,Iris-virginica -4.9,2.5,4.5,1.7,Iris-virginica -7.3,2.9,6.3,1.8,Iris-virginica -6.7,2.5,5.8,1.8,Iris-virginica -7.2,3.6,6.1,2.5,Iris-virginica -6.5,3.2,5.1,2.0,Iris-virginica -6.4,2.7,5.3,1.9,Iris-virginica -6.8,3.0,5.5,2.1,Iris-virginica -5.7,2.5,5.0,2.0,Iris-virginica -5.8,2.8,5.1,2.4,Iris-virginica -6.4,3.2,5.3,2.3,Iris-virginica -6.5,3.0,5.5,1.8,Iris-virginica -7.7,3.8,6.7,2.2,Iris-virginica -7.7,2.6,6.9,2.3,Iris-virginica -6.0,2.2,5.0,1.5,Iris-virginica -6.9,3.2,5.7,2.3,Iris-virginica -5.6,2.8,4.9,2.0,Iris-virginica -7.7,2.8,6.7,2.0,Iris-virginica -6.3,2.7,4.9,1.8,Iris-virginica -6.7,3.3,5.7,2.1,Iris-virginica -7.2,3.2,6.0,1.8,Iris-virginica -6.2,2.8,4.8,1.8,Iris-virginica -6.1,3.0,4.9,1.8,Iris-virginica -6.4,2.8,5.6,2.1,Iris-virginica -7.2,3.0,5.8,1.6,Iris-virginica -7.4,2.8,6.1,1.9,Iris-virginica -7.9,3.8,6.4,2.0,Iris-virginica -6.4,2.8,5.6,2.2,Iris-virginica -6.3,2.8,5.1,1.5,Iris-virginica -6.1,2.6,5.6,1.4,Iris-virginica -7.7,3.0,6.1,2.3,Iris-virginica -6.3,3.4,5.6,2.4,Iris-virginica -6.4,3.1,5.5,1.8,Iris-virginica -6.0,3.0,4.8,1.8,Iris-virginica -6.9,3.1,5.4,2.1,Iris-virginica -6.7,3.1,5.6,2.4,Iris-virginica -6.9,3.1,5.1,2.3,Iris-virginica -5.8,2.7,5.1,1.9,Iris-virginica -6.8,3.2,5.9,2.3,Iris-virginica -6.7,3.3,5.7,2.5,Iris-virginica -6.7,3.0,5.2,2.3,Iris-virginica -6.3,2.5,5.0,1.9,Iris-virginica -6.5,3.0,5.2,2.0,Iris-virginica -6.2,3.4,5.4,2.3,Iris-virginica -5.9,3.0,5.1,1.8,Iris-virginica diff --git a/vendor/itertools-0.8.2/examples/iris.rs b/vendor/itertools-0.8.2/examples/iris.rs deleted file mode 100644 index c09afbea0d..0000000000 --- a/vendor/itertools-0.8.2/examples/iris.rs +++ /dev/null @@ -1,141 +0,0 @@ -/// -/// This example parses, sorts and groups the iris dataset -/// and does some simple manipulations. -/// -/// Iterators and itertools functionality are used throughout. -/// -/// - -extern crate itertools; - -use itertools::Itertools; -use std::collections::HashMap; -use std::iter::repeat; -use std::num::ParseFloatError; -use std::str::FromStr; - -static DATA: &'static str = include_str!("iris.data"); - -#[derive(Clone, Debug)] -struct Iris { - name: String, - data: [f32; 4], -} - -#[derive(Clone, Debug)] -enum ParseError { - Numeric(ParseFloatError), - Other(&'static str), -} - -impl From for ParseError { - fn from(err: ParseFloatError) -> Self { - ParseError::Numeric(err) - } -} - -/// Parse an Iris from a comma-separated line -impl FromStr for Iris { - type Err = ParseError; - - fn from_str(s: &str) -> Result { - let mut iris = Iris { name: "".into(), data: [0.; 4] }; - let mut parts = s.split(",").map(str::trim); - - // using Iterator::by_ref() - for (index, part) in parts.by_ref().take(4).enumerate() { - iris.data[index] = try!(part.parse::()); - } - if let Some(name) = parts.next() { - iris.name = name.into(); - } else { - return Err(ParseError::Other("Missing name")) - } - Ok(iris) - } -} - -fn main() { - // using Itertools::fold_results to create the result of parsing - let irises = DATA.lines() - .map(str::parse) - .fold_results(Vec::new(), |mut v, iris: Iris| { - v.push(iris); - v - }); - let mut irises = match irises { - Err(e) => { - println!("Error parsing: {:?}", e); - std::process::exit(1); - } - Ok(data) => data, - }; - - // Sort them and group them - irises.sort_by(|a, b| Ord::cmp(&a.name, &b.name)); - - // using Iterator::cycle() - let mut plot_symbols = "+ox".chars().cycle(); - let mut symbolmap = HashMap::new(); - - // using Itertools::group_by - for (species, species_group) in &irises.iter().group_by(|iris| &iris.name) { - // assign a plot symbol - symbolmap.entry(species).or_insert_with(|| { - plot_symbols.next().unwrap() - }); - println!("{} (symbol={})", species, symbolmap[species]); - - for iris in species_group { - // using Itertools::format for lazy formatting - println!("{:>3.1}", iris.data.iter().format(", ")); - } - - } - - // Look at all combinations of the four columns - // - // See https://en.wikipedia.org/wiki/Iris_flower_data_set - // - let n = 30; // plot size - let mut plot = vec![' '; n * n]; - - // using Itertools::tuple_combinations - for (a, b) in (0..4).tuple_combinations() { - println!("Column {} vs {}:", a, b); - - // Clear plot - // - // using std::iter::repeat; - // using Itertools::set_from - plot.iter_mut().set_from(repeat(' ')); - - // using Itertools::minmax - let min_max = |data: &[Iris], col| { - data.iter() - .map(|iris| iris.data[col]) - .minmax() - .into_option() - .expect("Can't find min/max of empty iterator") - }; - let (min_x, max_x) = min_max(&irises, a); - let (min_y, max_y) = min_max(&irises, b); - - // Plot the data points - let round_to_grid = |x, min, max| ((x - min) / (max - min) * ((n - 1) as f32)) as usize; - let flip = |ix| n - 1 - ix; // reverse axis direction - - for iris in &irises { - let ix = round_to_grid(iris.data[a], min_x, max_x); - let iy = flip(round_to_grid(iris.data[b], min_y, max_y)); - plot[n * iy + ix] = symbolmap[&iris.name]; - } - - // render plot - // - // using Itertools::join - for line in plot.chunks(n) { - println!("{}", line.iter().join(" ")) - } - } -} diff --git a/vendor/itertools-0.8.2/src/adaptors/mod.rs b/vendor/itertools-0.8.2/src/adaptors/mod.rs deleted file mode 100644 index 4d0f5e1291..0000000000 --- a/vendor/itertools-0.8.2/src/adaptors/mod.rs +++ /dev/null @@ -1,1251 +0,0 @@ -//! Licensed under the Apache License, Version 2.0 -//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license -//! http://opensource.org/licenses/MIT, at your -//! option. This file may not be copied, modified, or distributed -//! except according to those terms. - -mod multi_product; -#[cfg(feature = "use_std")] -pub use self::multi_product::*; - -use std::fmt; -use std::mem::replace; -use std::iter::{Fuse, Peekable, FromIterator}; -use std::marker::PhantomData; -use size_hint; - -macro_rules! clone_fields { - ($name:ident, $base:expr, $($field:ident),+) => ( - $name { - $( - $field : $base . $field .clone() - ),* - } - ); -} - -/// An iterator adaptor that alternates elements from two iterators until both -/// run out. -/// -/// This iterator is *fused*. -/// -/// See [`.interleave()`](../trait.Itertools.html#method.interleave) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Interleave { - a: Fuse, - b: Fuse, - flag: bool, -} - -/// Create an iterator that interleaves elements in `i` and `j`. -/// -/// `IntoIterator` enabled version of `i.interleave(j)`. -/// -/// ``` -/// use itertools::interleave; -/// -/// for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { -/// /* loop body */ -/// } -/// ``` -pub fn interleave(i: I, j: J) -> Interleave<::IntoIter, ::IntoIter> - where I: IntoIterator, - J: IntoIterator -{ - Interleave { - a: i.into_iter().fuse(), - b: j.into_iter().fuse(), - flag: false, - } -} - -impl Iterator for Interleave - where I: Iterator, - J: Iterator -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - self.flag = !self.flag; - if self.flag { - match self.a.next() { - None => self.b.next(), - r => r, - } - } else { - match self.b.next() { - None => self.a.next(), - r => r, - } - } - } - - fn size_hint(&self) -> (usize, Option) { - size_hint::add(self.a.size_hint(), self.b.size_hint()) - } -} - -/// An iterator adaptor that alternates elements from the two iterators until -/// one of them runs out. -/// -/// This iterator is *fused*. -/// -/// See [`.interleave_shortest()`](../trait.Itertools.html#method.interleave_shortest) -/// for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct InterleaveShortest - where I: Iterator, - J: Iterator -{ - it0: I, - it1: J, - phase: bool, // false ==> it0, true ==> it1 -} - -/// Create a new `InterleaveShortest` iterator. -pub fn interleave_shortest(a: I, b: J) -> InterleaveShortest - where I: Iterator, - J: Iterator -{ - InterleaveShortest { - it0: a, - it1: b, - phase: false, - } -} - -impl Iterator for InterleaveShortest - where I: Iterator, - J: Iterator -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.phase { - false => match self.it0.next() { - None => None, - e => { - self.phase = true; - e - } - }, - true => match self.it1.next() { - None => None, - e => { - self.phase = false; - e - } - }, - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (curr_hint, next_hint) = { - let it0_hint = self.it0.size_hint(); - let it1_hint = self.it1.size_hint(); - if self.phase { - (it1_hint, it0_hint) - } else { - (it0_hint, it1_hint) - } - }; - let (curr_lower, curr_upper) = curr_hint; - let (next_lower, next_upper) = next_hint; - let (combined_lower, combined_upper) = - size_hint::mul_scalar(size_hint::min(curr_hint, next_hint), 2); - let lower = - if curr_lower > next_lower { - combined_lower + 1 - } else { - combined_lower - }; - let upper = { - let extra_elem = match (curr_upper, next_upper) { - (_, None) => false, - (None, Some(_)) => true, - (Some(curr_max), Some(next_max)) => curr_max > next_max, - }; - if extra_elem { - combined_upper.and_then(|x| x.checked_add(1)) - } else { - combined_upper - } - }; - (lower, upper) - } -} - -#[derive(Clone, Debug)] -/// An iterator adaptor that allows putting back a single -/// item to the front of the iterator. -/// -/// Iterator element type is `I::Item`. -pub struct PutBack - where I: Iterator -{ - top: Option, - iter: I, -} - -/// Create an iterator where you can put back a single item -pub fn put_back(iterable: I) -> PutBack - where I: IntoIterator -{ - PutBack { - top: None, - iter: iterable.into_iter(), - } -} - -impl PutBack - where I: Iterator -{ - /// put back value `value` (builder method) - pub fn with_value(mut self, value: I::Item) -> Self { - self.put_back(value); - self - } - - /// Split the `PutBack` into its parts. - #[inline] - pub fn into_parts(self) -> (Option, I) { - let PutBack{top, iter} = self; - (top, iter) - } - - /// Put back a single value to the front of the iterator. - /// - /// If a value is already in the put back slot, it is overwritten. - #[inline] - pub fn put_back(&mut self, x: I::Item) { - self.top = Some(x) - } -} - -impl Iterator for PutBack - where I: Iterator -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - match self.top { - None => self.iter.next(), - ref mut some => some.take(), - } - } - #[inline] - fn size_hint(&self) -> (usize, Option) { - // Not ExactSizeIterator because size may be larger than usize - size_hint::add_scalar(self.iter.size_hint(), self.top.is_some() as usize) - } - - fn all(&mut self, mut f: G) -> bool - where G: FnMut(Self::Item) -> bool - { - if let Some(elt) = self.top.take() { - if !f(elt) { - return false; - } - } - self.iter.all(f) - } - - fn fold(mut self, init: Acc, mut f: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - let mut accum = init; - if let Some(elt) = self.top.take() { - accum = f(accum, elt); - } - self.iter.fold(accum, f) - } -} - -#[derive(Debug, Clone)] -/// An iterator adaptor that iterates over the cartesian product of -/// the element sets of two iterators `I` and `J`. -/// -/// Iterator element type is `(I::Item, J::Item)`. -/// -/// See [`.cartesian_product()`](../trait.Itertools.html#method.cartesian_product) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Product - where I: Iterator -{ - a: I, - a_cur: Option, - b: J, - b_orig: J, -} - -/// Create a new cartesian product iterator -/// -/// Iterator element type is `(I::Item, J::Item)`. -pub fn cartesian_product(mut i: I, j: J) -> Product - where I: Iterator, - J: Clone + Iterator, - I::Item: Clone -{ - Product { - a_cur: i.next(), - a: i, - b: j.clone(), - b_orig: j, - } -} - - -impl Iterator for Product - where I: Iterator, - J: Clone + Iterator, - I::Item: Clone -{ - type Item = (I::Item, J::Item); - fn next(&mut self) -> Option<(I::Item, J::Item)> { - let elt_b = match self.b.next() { - None => { - self.b = self.b_orig.clone(); - match self.b.next() { - None => return None, - Some(x) => { - self.a_cur = self.a.next(); - x - } - } - } - Some(x) => x - }; - match self.a_cur { - None => None, - Some(ref a) => { - Some((a.clone(), elt_b)) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let has_cur = self.a_cur.is_some() as usize; - // Not ExactSizeIterator because size may be larger than usize - let (b_min, b_max) = self.b.size_hint(); - - // Compute a * b_orig + b for both lower and upper bound - size_hint::add( - size_hint::mul(self.a.size_hint(), self.b_orig.size_hint()), - (b_min * has_cur, b_max.map(move |x| x * has_cur))) - } - - fn fold(mut self, mut accum: Acc, mut f: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - // use a split loop to handle the loose a_cur as well as avoiding to - // clone b_orig at the end. - if let Some(mut a) = self.a_cur.take() { - let mut b = self.b; - loop { - accum = b.fold(accum, |acc, elt| f(acc, (a.clone(), elt))); - - // we can only continue iterating a if we had a first element; - if let Some(next_a) = self.a.next() { - b = self.b_orig.clone(); - a = next_a; - } else { - break; - } - } - } - accum - } -} - -/// A “meta iterator adaptor”. Its closure receives a reference to the iterator -/// and may pick off as many elements as it likes, to produce the next iterator element. -/// -/// Iterator element type is *X*, if the return type of `F` is *Option\*. -/// -/// See [`.batching()`](../trait.Itertools.html#method.batching) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Batching { - f: F, - iter: I, -} - -impl fmt::Debug for Batching where I: fmt::Debug { - debug_fmt_fields!(Batching, iter); -} - -/// Create a new Batching iterator. -pub fn batching(iter: I, f: F) -> Batching { - Batching { f: f, iter: iter } -} - -impl Iterator for Batching - where I: Iterator, - F: FnMut(&mut I) -> Option -{ - type Item = B; - #[inline] - fn next(&mut self) -> Option { - (self.f)(&mut self.iter) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // No information about closue behavior - (0, None) - } -} - -/// An iterator adaptor that steps a number elements in the base iterator -/// for each iteration. -/// -/// The iterator steps by yielding the next element from the base iterator, -/// then skipping forward *n-1* elements. -/// -/// See [`.step()`](../trait.Itertools.html#method.step) for more information. -#[deprecated(note="Use std .step_by() instead", since="0.8")] -#[allow(deprecated)] -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Step { - iter: Fuse, - skip: usize, -} - -/// Create a `Step` iterator. -/// -/// **Panics** if the step is 0. -#[allow(deprecated)] -pub fn step(iter: I, step: usize) -> Step - where I: Iterator -{ - assert!(step != 0); - Step { - iter: iter.fuse(), - skip: step - 1, - } -} - -#[allow(deprecated)] -impl Iterator for Step - where I: Iterator -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - let elt = self.iter.next(); - if self.skip > 0 { - self.iter.nth(self.skip - 1); - } - elt - } - - fn size_hint(&self) -> (usize, Option) { - let (low, high) = self.iter.size_hint(); - let div = |x: usize| { - if x == 0 { - 0 - } else { - 1 + (x - 1) / (self.skip + 1) - } - }; - (div(low), high.map(div)) - } -} - -// known size -#[allow(deprecated)] -impl ExactSizeIterator for Step - where I: ExactSizeIterator -{} - -pub trait MergePredicate { - fn merge_pred(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct MergeLte; - -impl MergePredicate for MergeLte { - fn merge_pred(&mut self, a: &T, b: &T) -> bool { - a <= b - } -} - -/// An iterator adaptor that merges the two base iterators in ascending order. -/// If both base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.merge()`](../trait.Itertools.html#method.merge_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub type Merge = MergeBy; - -/// Create an iterator that merges elements in `i` and `j`. -/// -/// `IntoIterator` enabled version of `i.merge(j)`. -/// -/// ``` -/// use itertools::merge; -/// -/// for elt in merge(&[1, 2, 3], &[2, 3, 4]) { -/// /* loop body */ -/// } -/// ``` -pub fn merge(i: I, j: J) -> Merge<::IntoIter, ::IntoIter> - where I: IntoIterator, - J: IntoIterator, - I::Item: PartialOrd -{ - merge_by_new(i, j, MergeLte) -} - -/// An iterator adaptor that merges the two base iterators in ascending order. -/// If both base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.merge_by()`](../trait.Itertools.html#method.merge_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MergeBy - where I: Iterator, - J: Iterator -{ - a: Peekable, - b: Peekable, - fused: Option, - cmp: F, -} - -impl fmt::Debug for MergeBy - where I: Iterator + fmt::Debug, J: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(MergeBy, a, b); -} - -implbool> MergePredicate for F { - fn merge_pred(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// Create a `MergeBy` iterator. -pub fn merge_by_new(a: I, b: J, cmp: F) -> MergeBy - where I: IntoIterator, - J: IntoIterator, - F: MergePredicate, -{ - MergeBy { - a: a.into_iter().peekable(), - b: b.into_iter().peekable(), - fused: None, - cmp: cmp, - } -} - -impl Clone for MergeBy - where I: Iterator, - J: Iterator, - Peekable: Clone, - Peekable: Clone, - F: Clone -{ - fn clone(&self) -> Self { - clone_fields!(MergeBy, self, a, b, fused, cmp) - } -} - -impl Iterator for MergeBy - where I: Iterator, - J: Iterator, - F: MergePredicate -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - let less_than = match self.fused { - Some(lt) => lt, - None => match (self.a.peek(), self.b.peek()) { - (Some(a), Some(b)) => self.cmp.merge_pred(a, b), - (Some(_), None) => { - self.fused = Some(true); - true - } - (None, Some(_)) => { - self.fused = Some(false); - false - } - (None, None) => return None, - } - }; - if less_than { - self.a.next() - } else { - self.b.next() - } - } - - fn size_hint(&self) -> (usize, Option) { - // Not ExactSizeIterator because size may be larger than usize - size_hint::add(self.a.size_hint(), self.b.size_hint()) - } -} - -#[derive(Clone, Debug)] -pub struct CoalesceCore - where I: Iterator -{ - iter: I, - last: Option, -} - -impl CoalesceCore - where I: Iterator -{ - fn next_with(&mut self, mut f: F) -> Option - where F: FnMut(I::Item, I::Item) -> Result - { - // this fuses the iterator - let mut last = match self.last.take() { - None => return None, - Some(x) => x, - }; - for next in &mut self.iter { - match f(last, next) { - Ok(joined) => last = joined, - Err((last_, next_)) => { - self.last = Some(next_); - return Some(last_); - } - } - } - - Some(last) - } - - fn size_hint(&self) -> (usize, Option) { - let (low, hi) = size_hint::add_scalar(self.iter.size_hint(), - self.last.is_some() as usize); - ((low > 0) as usize, hi) - } -} - -/// An iterator adaptor that may join together adjacent elements. -/// -/// See [`.coalesce()`](../trait.Itertools.html#method.coalesce) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Coalesce - where I: Iterator -{ - iter: CoalesceCore, - f: F, -} - -impl Clone for Coalesce - where I: Iterator, - I::Item: Clone -{ - fn clone(&self) -> Self { - clone_fields!(Coalesce, self, iter, f) - } -} - -impl fmt::Debug for Coalesce - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Coalesce, iter); -} - -/// Create a new `Coalesce`. -pub fn coalesce(mut iter: I, f: F) -> Coalesce - where I: Iterator -{ - Coalesce { - iter: CoalesceCore { - last: iter.next(), - iter: iter, - }, - f: f, - } -} - -impl Iterator for Coalesce - where I: Iterator, - F: FnMut(I::Item, I::Item) -> Result -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - self.iter.next_with(&mut self.f) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } -} - -/// An iterator adaptor that removes repeated duplicates, determining equality using a comparison function. -/// -/// See [`.dedup_by()`](../trait.Itertools.html#method.dedup_by) or [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct DedupBy - where I: Iterator -{ - iter: CoalesceCore, - dedup_pred: Pred, -} - -pub trait DedupPredicate { // TODO replace by Fn(&T, &T)->bool once Rust supports it - fn dedup_pair(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct DedupEq; - -impl DedupPredicate for DedupEq { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - a==b - } -} - -implbool> DedupPredicate for F { - fn dedup_pair(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// An iterator adaptor that removes repeated duplicates. -/// -/// See [`.dedup()`](../trait.Itertools.html#method.dedup) for more information. -pub type Dedup=DedupBy; - -impl Clone for DedupBy - where I: Iterator, - I::Item: Clone, -{ - fn clone(&self) -> Self { - clone_fields!(DedupBy, self, iter, dedup_pred) - } -} - -/// Create a new `DedupBy`. -pub fn dedup_by(mut iter: I, dedup_pred: Pred) -> DedupBy - where I: Iterator, -{ - DedupBy { - iter: CoalesceCore { - last: iter.next(), - iter: iter, - }, - dedup_pred, - } -} - -/// Create a new `Dedup`. -pub fn dedup(iter: I) -> Dedup - where I: Iterator -{ - dedup_by(iter, DedupEq) -} - -impl fmt::Debug for DedupBy - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Dedup, iter); -} - -impl Iterator for DedupBy - where I: Iterator, - I::Item: PartialEq, - Pred: DedupPredicate, -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - let ref mut dedup_pred = self.dedup_pred; - self.iter.next_with(|x, y| { - if dedup_pred.dedup_pair(&x, &y) { Ok(x) } else { Err((x, y)) } - }) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, mut accum: Acc, mut f: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - if let Some(mut last) = self.iter.last { - let mut dedup_pred = self.dedup_pred; - accum = self.iter.iter.fold(accum, |acc, elt| { - if dedup_pred.dedup_pair(&elt, &last) { - acc - } else { - f(acc, replace(&mut last, elt)) - } - }); - f(accum, last) - } else { - accum - } - } -} - -/// An iterator adaptor that borrows from a `Clone`-able iterator -/// to only pick off elements while the predicate returns `true`. -/// -/// See [`.take_while_ref()`](../trait.Itertools.html#method.take_while_ref) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct TakeWhileRef<'a, I: 'a, F> { - iter: &'a mut I, - f: F, -} - -impl<'a, I, F> fmt::Debug for TakeWhileRef<'a, I, F> - where I: Iterator + fmt::Debug, -{ - debug_fmt_fields!(TakeWhileRef, iter); -} - -/// Create a new `TakeWhileRef` from a reference to clonable iterator. -pub fn take_while_ref(iter: &mut I, f: F) -> TakeWhileRef - where I: Iterator + Clone -{ - TakeWhileRef { iter: iter, f: f } -} - -impl<'a, I, F> Iterator for TakeWhileRef<'a, I, F> - where I: Iterator + Clone, - F: FnMut(&I::Item) -> bool -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - let old = self.iter.clone(); - match self.iter.next() { - None => None, - Some(elt) => { - if (self.f)(&elt) { - Some(elt) - } else { - *self.iter = old; - None - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_, hi) = self.iter.size_hint(); - (0, hi) - } -} - -/// An iterator adaptor that filters `Option
    ` iterator elements -/// and produces `A`. Stops on the first `None` encountered. -/// -/// See [`.while_some()`](../trait.Itertools.html#method.while_some) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct WhileSome { - iter: I, -} - -/// Create a new `WhileSome`. -pub fn while_some(iter: I) -> WhileSome { - WhileSome { iter: iter } -} - -impl Iterator for WhileSome - where I: Iterator> -{ - type Item = A; - - fn next(&mut self) -> Option { - match self.iter.next() { - None | Some(None) => None, - Some(elt) => elt, - } - } - - fn size_hint(&self) -> (usize, Option) { - let sh = self.iter.size_hint(); - (0, sh.1) - } -} - -/// An iterator to iterate through all combinations in a `Clone`-able iterator that produces tuples -/// of a specific size. -/// -/// See [`.tuple_combinations()`](../trait.Itertools.html#method.tuple_combinations) for more -/// information. -#[derive(Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct TupleCombinations - where I: Iterator, - T: HasCombination -{ - iter: T::Combination, - _mi: PhantomData, - _mt: PhantomData -} - -pub trait HasCombination: Sized { - type Combination: From + Iterator; -} - -/// Create a new `TupleCombinations` from a clonable iterator. -pub fn tuple_combinations(iter: I) -> TupleCombinations - where I: Iterator + Clone, - I::Item: Clone, - T: HasCombination, -{ - TupleCombinations { - iter: T::Combination::from(iter), - _mi: PhantomData, - _mt: PhantomData, - } -} - -impl Iterator for TupleCombinations - where I: Iterator, - T: HasCombination, -{ - type Item = T; - - fn next(&mut self) -> Option { - self.iter.next() - } -} - -#[derive(Debug)] -pub struct Tuple1Combination { - iter: I, -} - -impl From for Tuple1Combination { - fn from(iter: I) -> Self { - Tuple1Combination { iter: iter } - } -} - -impl Iterator for Tuple1Combination { - type Item = (I::Item,); - - fn next(&mut self) -> Option { - self.iter.next().map(|x| (x,)) - } -} - -impl HasCombination for (I::Item,) { - type Combination = Tuple1Combination; -} - -macro_rules! impl_tuple_combination { - ($C:ident $P:ident ; $A:ident, $($I:ident),* ; $($X:ident)*) => ( - #[derive(Debug)] - pub struct $C { - item: Option, - iter: I, - c: $P, - } - - impl From for $C { - fn from(mut iter: I) -> Self { - $C { - item: iter.next(), - iter: iter.clone(), - c: $P::from(iter), - } - } - } - - impl From for $C> { - fn from(iter: I) -> Self { - let mut iter = iter.fuse(); - $C { - item: iter.next(), - iter: iter.clone(), - c: $P::from(iter), - } - } - } - - impl Iterator for $C - where I: Iterator + Clone, - I::Item: Clone - { - type Item = ($($I),*); - - fn next(&mut self) -> Option { - if let Some(($($X),*,)) = self.c.next() { - let z = self.item.clone().unwrap(); - Some((z, $($X),*)) - } else { - self.item = self.iter.next(); - self.item.clone().and_then(|z| { - self.c = $P::from(self.iter.clone()); - self.c.next().map(|($($X),*,)| (z, $($X),*)) - }) - } - } - } - - impl HasCombination for ($($I),*) - where I: Iterator + Clone, - I::Item: Clone - { - type Combination = $C>; - } - ) -} - -impl_tuple_combination!(Tuple2Combination Tuple1Combination ; A, A, A ; a); -impl_tuple_combination!(Tuple3Combination Tuple2Combination ; A, A, A, A ; a b); -impl_tuple_combination!(Tuple4Combination Tuple3Combination ; A, A, A, A, A; a b c); - -/// An iterator adapter to apply `Into` conversion to each element. -/// -/// See [`.map_into()`](../trait.Itertools.html#method.map_into) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapInto { - iter: I, - _res: PhantomData R>, -} - -/// Create a new [`MapInto`](struct.MapInto.html) iterator. -pub fn map_into(iter: I) -> MapInto { - MapInto { - iter: iter, - _res: PhantomData, - } -} - -impl Iterator for MapInto - where I: Iterator, - I::Item: Into, -{ - type Item = R; - - fn next(&mut self) -> Option { - self.iter - .next() - .map(|i| i.into()) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(init, move |acc, v| fold_f(acc, v.into())) - } -} - -impl DoubleEndedIterator for MapInto - where I: DoubleEndedIterator, - I::Item: Into, -{ - fn next_back(&mut self) -> Option { - self.iter - .next_back() - .map(|i| i.into()) - } -} - -impl ExactSizeIterator for MapInto -where - I: ExactSizeIterator, - I::Item: Into, -{} - -/// An iterator adapter to apply a transformation within a nested `Result`. -/// -/// See [`.map_results()`](../trait.Itertools.html#method.map_results) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MapResults { - iter: I, - f: F -} - -/// Create a new `MapResults` iterator. -pub fn map_results(iter: I, f: F) -> MapResults - where I: Iterator>, - F: FnMut(T) -> U, -{ - MapResults { - iter: iter, - f: f, - } -} - -impl Iterator for MapResults - where I: Iterator>, - F: FnMut(T) -> U, -{ - type Item = Result; - - fn next(&mut self) -> Option { - self.iter.next().map(|v| v.map(&mut self.f)) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut fold_f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, v| fold_f(acc, v.map(&mut f))) - } - - fn collect(self) -> C - where C: FromIterator - { - let mut f = self.f; - self.iter.map(move |v| v.map(&mut f)).collect() - } -} - -/// An iterator adapter to get the positions of each element that matches a predicate. -/// -/// See [`.positions()`](../trait.Itertools.html#method.positions) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Positions { - iter: I, - f: F, - count: usize, -} - -/// Create a new `Positions` iterator. -pub fn positions(iter: I, f: F) -> Positions - where I: Iterator, - F: FnMut(I::Item) -> bool, -{ - Positions { - iter: iter, - f: f, - count: 0 - } -} - -impl Iterator for Positions - where I: Iterator, - F: FnMut(I::Item) -> bool, -{ - type Item = usize; - - fn next(&mut self) -> Option { - while let Some(v) = self.iter.next() { - let i = self.count; - self.count = i + 1; - if (self.f)(v) { - return Some(i); - } - } - None - } - - fn size_hint(&self) -> (usize, Option) { - (0, self.iter.size_hint().1) - } -} - -impl DoubleEndedIterator for Positions - where I: DoubleEndedIterator + ExactSizeIterator, - F: FnMut(I::Item) -> bool, -{ - fn next_back(&mut self) -> Option { - while let Some(v) = self.iter.next_back() { - if (self.f)(v) { - return Some(self.count + self.iter.len()) - } - } - None - } -} - -/// An iterator adapter to apply a mutating function to each element before yielding it. -/// -/// See [`.update()`](../trait.Itertools.html#method.update) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Update { - iter: I, - f: F, -} - -/// Create a new `Update` iterator. -pub fn update(iter: I, f: F) -> Update -where - I: Iterator, - F: FnMut(&mut I::Item), -{ - Update { iter: iter, f: f } -} - -impl Iterator for Update -where - I: Iterator, - F: FnMut(&mut I::Item), -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - if let Some(mut v) = self.iter.next() { - (self.f)(&mut v); - Some(v) - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - - fn fold(self, init: Acc, mut g: G) -> Acc - where G: FnMut(Acc, Self::Item) -> Acc, - { - let mut f = self.f; - self.iter.fold(init, move |acc, mut v| { f(&mut v); g(acc, v) }) - } - - // if possible, re-use inner iterator specializations in collect - fn collect(self) -> C - where C: FromIterator - { - let mut f = self.f; - self.iter.map(move |mut v| { f(&mut v); v }).collect() - } -} - -impl ExactSizeIterator for Update -where - I: ExactSizeIterator, - F: FnMut(&mut I::Item), -{} - -impl DoubleEndedIterator for Update -where - I: DoubleEndedIterator, - F: FnMut(&mut I::Item), -{ - fn next_back(&mut self) -> Option { - if let Some(mut v) = self.iter.next_back() { - (self.f)(&mut v); - Some(v) - } else { - None - } - } -} diff --git a/vendor/itertools-0.8.2/src/adaptors/multi_product.rs b/vendor/itertools-0.8.2/src/adaptors/multi_product.rs deleted file mode 100644 index a6796386ed..0000000000 --- a/vendor/itertools-0.8.2/src/adaptors/multi_product.rs +++ /dev/null @@ -1,220 +0,0 @@ -#![cfg(feature = "use_std")] - -use size_hint; -use Itertools; - -#[derive(Clone)] -/// An iterator adaptor that iterates over the cartesian product of -/// multiple iterators of type `I`. -/// -/// An iterator element type is `Vec`. -/// -/// See [`.multi_cartesian_product()`](../trait.Itertools.html#method.multi_cartesian_product) -/// for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MultiProduct(Vec>) - where I: Iterator + Clone, - I::Item: Clone; - -/// Create a new cartesian product iterator over an arbitrary number -/// of iterators of the same type. -/// -/// Iterator element is of type `Vec`. -pub fn multi_cartesian_product(iters: H) -> MultiProduct<::IntoIter> - where H: Iterator, - H::Item: IntoIterator, - ::IntoIter: Clone, - ::Item: Clone -{ - MultiProduct(iters.map(|i| MultiProductIter::new(i.into_iter())).collect()) -} - -#[derive(Clone, Debug)] -/// Holds the state of a single iterator within a MultiProduct. -struct MultiProductIter - where I: Iterator + Clone, - I::Item: Clone -{ - cur: Option, - iter: I, - iter_orig: I, -} - -/// Holds the current state during an iteration of a MultiProduct. -#[derive(Debug)] -enum MultiProductIterState { - StartOfIter, - MidIter { on_first_iter: bool }, -} - -impl MultiProduct - where I: Iterator + Clone, - I::Item: Clone -{ - /// Iterates the rightmost iterator, then recursively iterates iterators - /// to the left if necessary. - /// - /// Returns true if the iteration succeeded, else false. - fn iterate_last( - multi_iters: &mut [MultiProductIter], - mut state: MultiProductIterState - ) -> bool { - use self::MultiProductIterState::*; - - if let Some((last, rest)) = multi_iters.split_last_mut() { - let on_first_iter = match state { - StartOfIter => { - let on_first_iter = !last.in_progress(); - state = MidIter { on_first_iter: on_first_iter }; - on_first_iter - }, - MidIter { on_first_iter } => on_first_iter - }; - - if !on_first_iter { - last.iterate(); - } - - if last.in_progress() { - true - } else if MultiProduct::iterate_last(rest, state) { - last.reset(); - last.iterate(); - // If iterator is None twice consecutively, then iterator is - // empty; whole product is empty. - last.in_progress() - } else { - false - } - } else { - // Reached end of iterator list. On initialisation, return true. - // At end of iteration (final iterator finishes), finish. - match state { - StartOfIter => false, - MidIter { on_first_iter } => on_first_iter - } - } - } - - /// Returns the unwrapped value of the next iteration. - fn curr_iterator(&self) -> Vec { - self.0.iter().map(|multi_iter| { - multi_iter.cur.clone().unwrap() - }).collect() - } - - /// Returns true if iteration has started and has not yet finished; false - /// otherwise. - fn in_progress(&self) -> bool { - if let Some(last) = self.0.last() { - last.in_progress() - } else { - false - } - } -} - -impl MultiProductIter - where I: Iterator + Clone, - I::Item: Clone -{ - fn new(iter: I) -> Self { - MultiProductIter { - cur: None, - iter: iter.clone(), - iter_orig: iter - } - } - - /// Iterate the managed iterator. - fn iterate(&mut self) { - self.cur = self.iter.next(); - } - - /// Reset the managed iterator. - fn reset(&mut self) { - self.iter = self.iter_orig.clone(); - } - - /// Returns true if the current iterator has been started and has not yet - /// finished; false otherwise. - fn in_progress(&self) -> bool { - self.cur.is_some() - } -} - -impl Iterator for MultiProduct - where I: Iterator + Clone, - I::Item: Clone -{ - type Item = Vec; - - fn next(&mut self) -> Option { - if MultiProduct::iterate_last( - &mut self.0, - MultiProductIterState::StartOfIter - ) { - Some(self.curr_iterator()) - } else { - None - } - } - - fn count(self) -> usize { - if self.0.len() == 0 { - return 0; - } - - if !self.in_progress() { - return self.0.into_iter().fold(1, |acc, multi_iter| { - acc * multi_iter.iter.count() - }); - } - - self.0.into_iter().fold( - 0, - |acc, MultiProductIter { iter, iter_orig, cur: _ }| { - let total_count = iter_orig.count(); - let cur_count = iter.count(); - acc * total_count + cur_count - } - ) - } - - fn size_hint(&self) -> (usize, Option) { - // Not ExactSizeIterator because size may be larger than usize - if self.0.len() == 0 { - return (0, Some(0)); - } - - if !self.in_progress() { - return self.0.iter().fold((1, Some(1)), |acc, multi_iter| { - size_hint::mul(acc, multi_iter.iter.size_hint()) - }); - } - - self.0.iter().fold( - (0, Some(0)), - |acc, &MultiProductIter { ref iter, ref iter_orig, cur: _ }| { - let cur_size = iter.size_hint(); - let total_size = iter_orig.size_hint(); - size_hint::add(size_hint::mul(acc, total_size), cur_size) - } - ) - } - - fn last(self) -> Option { - let iter_count = self.0.len(); - - let lasts: Self::Item = self.0.into_iter() - .map(|multi_iter| multi_iter.iter.last()) - .while_some() - .collect(); - - if lasts.len() == iter_count { - Some(lasts) - } else { - None - } - } -} diff --git a/vendor/itertools-0.8.2/src/combinations.rs b/vendor/itertools-0.8.2/src/combinations.rs deleted file mode 100644 index 61833cecd3..0000000000 --- a/vendor/itertools-0.8.2/src/combinations.rs +++ /dev/null @@ -1,100 +0,0 @@ -use std::fmt; - -use super::lazy_buffer::LazyBuffer; - -/// An iterator to iterate through all the `k`-length combinations in an iterator. -/// -/// See [`.combinations()`](../trait.Itertools.html#method.combinations) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Combinations { - k: usize, - indices: Vec, - pool: LazyBuffer, - first: bool, -} - -impl fmt::Debug for Combinations - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Combinations, k, indices, pool, first); -} - -/// Create a new `Combinations` from a clonable iterator. -pub fn combinations(iter: I, k: usize) -> Combinations - where I: Iterator -{ - let mut indices: Vec = Vec::with_capacity(k); - for i in 0..k { - indices.push(i); - } - let mut pool: LazyBuffer = LazyBuffer::new(iter); - - for _ in 0..k { - if !pool.get_next() { - break; - } - } - - Combinations { - k: k, - indices: indices, - pool: pool, - first: true, - } -} - -impl Iterator for Combinations - where I: Iterator, - I::Item: Clone -{ - type Item = Vec; - fn next(&mut self) -> Option { - let mut pool_len = self.pool.len(); - if self.pool.is_done() { - if pool_len == 0 || self.k > pool_len { - return None; - } - } - - if self.first { - self.first = false; - } else if self.k == 0 { - return None; - } else { - // Scan from the end, looking for an index to increment - let mut i: usize = self.k - 1; - - // Check if we need to consume more from the iterator - if self.indices[i] == pool_len - 1 && !self.pool.is_done() { - if self.pool.get_next() { - pool_len += 1; - } - } - - while self.indices[i] == i + pool_len - self.k { - if i > 0 { - i -= 1; - } else { - // Reached the last combination - return None; - } - } - - // Increment index, and reset the ones to its right - self.indices[i] += 1; - let mut j = i + 1; - while j < self.k { - self.indices[j] = self.indices[j - 1] + 1; - j += 1; - } - } - - // Create result vector based on the indices - let mut result = Vec::with_capacity(self.k); - for i in self.indices.iter() { - result.push(self.pool[*i].clone()); - } - Some(result) - } -} diff --git a/vendor/itertools-0.8.2/src/combinations_with_replacement.rs b/vendor/itertools-0.8.2/src/combinations_with_replacement.rs deleted file mode 100644 index 499ccf70d1..0000000000 --- a/vendor/itertools-0.8.2/src/combinations_with_replacement.rs +++ /dev/null @@ -1,108 +0,0 @@ -use std::fmt; - -use super::lazy_buffer::LazyBuffer; - -/// An iterator to iterate through all the `n`-length combinations in an iterator, with replacement. -/// -/// See [`.combinations_with_replacement()`](../trait.Itertools.html#method.combinations_with_replacement) for more information. -#[derive(Clone)] -pub struct CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - k: usize, - indices: Vec, - // The current known max index value. This increases as pool grows. - max_index: usize, - pool: LazyBuffer, - first: bool, -} - -impl fmt::Debug for CombinationsWithReplacement -where - I: Iterator + fmt::Debug, - I::Item: fmt::Debug + Clone, -{ - debug_fmt_fields!(Combinations, k, indices, max_index, pool, first); -} - -impl CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - /// Map the current mask over the pool to get an output combination - fn current(&self) -> Vec { - self.indices.iter().map(|i| self.pool[*i].clone()).collect() - } -} - -/// Create a new `CombinationsWithReplacement` from a clonable iterator. -pub fn combinations_with_replacement(iter: I, k: usize) -> CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - let indices: Vec = vec![0; k]; - let pool: LazyBuffer = LazyBuffer::new(iter); - - CombinationsWithReplacement { - k, - indices, - max_index: 0, - pool: pool, - first: true, - } -} - -impl Iterator for CombinationsWithReplacement -where - I: Iterator, - I::Item: Clone, -{ - type Item = Vec; - fn next(&mut self) -> Option { - // If this is the first iteration, return early - if self.first { - // In empty edge cases, stop iterating immediately - return if self.k == 0 || self.pool.is_done() { - None - // Otherwise, yield the initial state - } else { - self.first = false; - Some(self.current()) - }; - } - - // Check if we need to consume more from the iterator - // This will run while we increment our first index digit - if !self.pool.is_done() { - self.pool.get_next(); - self.max_index = self.pool.len() - 1; - } - - // Work out where we need to update our indices - let mut increment: Option<(usize, usize)> = None; - for (i, indices_int) in self.indices.iter().enumerate().rev() { - if indices_int < &self.max_index { - increment = Some((i, indices_int + 1)); - break; - } - } - - match increment { - // If we can update the indices further - Some((increment_from, increment_value)) => { - // We need to update the rightmost non-max value - // and all those to the right - for indices_index in increment_from..self.indices.len() { - self.indices[indices_index] = increment_value - } - Some(self.current()) - } - // Otherwise, we're done - None => None, - } - } -} diff --git a/vendor/itertools-0.8.2/src/concat_impl.rs b/vendor/itertools-0.8.2/src/concat_impl.rs deleted file mode 100644 index 05b370e1c6..0000000000 --- a/vendor/itertools-0.8.2/src/concat_impl.rs +++ /dev/null @@ -1,22 +0,0 @@ -use Itertools; - -/// Combine all an iterator's elements into one element by using `Extend`. -/// -/// `IntoIterator`-enabled version of `.concat()` -/// -/// This combinator will extend the first item with each of the rest of the -/// items of the iterator. If the iterator is empty, the default value of -/// `I::Item` is returned. -/// -/// ```rust -/// use itertools::concat; -/// -/// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]]; -/// assert_eq!(concat(input), vec![1, 2, 3, 4, 5, 6]); -/// ``` -pub fn concat(iterable: I) -> I::Item - where I: IntoIterator, - I::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default -{ - iterable.into_iter().fold1(|mut a, b| { a.extend(b); a }).unwrap_or_else(|| <_>::default()) -} diff --git a/vendor/itertools-0.8.2/src/cons_tuples_impl.rs b/vendor/itertools-0.8.2/src/cons_tuples_impl.rs deleted file mode 100644 index 9b27e7580f..0000000000 --- a/vendor/itertools-0.8.2/src/cons_tuples_impl.rs +++ /dev/null @@ -1,68 +0,0 @@ - -macro_rules! impl_cons_iter( - ($_A:ident, $_B:ident, ) => (); // stop - - ($A:ident, $($B:ident,)*) => ( - impl_cons_iter!($($B,)*); - #[allow(non_snake_case)] - impl Iterator for ConsTuples - where Iter: Iterator, - { - type Item = ($($B,)* X, ); - fn next(&mut self) -> Option { - self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, )) - } - - fn size_hint(&self) -> (usize, Option) { - self.iter.size_hint() - } - fn fold(self, accum: Acc, mut f: Fold) -> Acc - where Fold: FnMut(Acc, Self::Item) -> Acc, - { - self.iter.fold(accum, move |acc, (($($B,)*), x)| f(acc, ($($B,)* x, ))) - } - } - - #[allow(non_snake_case)] - impl DoubleEndedIterator for ConsTuples - where Iter: DoubleEndedIterator, - { - fn next_back(&mut self) -> Option { - self.iter.next().map(|(($($B,)*), x)| ($($B,)* x, )) - } - } - - ); -); - -impl_cons_iter!(A, B, C, D, E, F, G, H,); - -/// An iterator that maps an iterator of tuples like -/// `((A, B), C)` to an iterator of `(A, B, C)`. -/// -/// Used by the `iproduct!()` macro. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct ConsTuples - where I: Iterator, -{ - iter: I, -} - -impl Clone for ConsTuples - where I: Clone + Iterator, -{ - fn clone(&self) -> Self { - ConsTuples { - iter: self.iter.clone(), - } - } -} - -/// Create an iterator that maps for example iterators of -/// `((A, B), C)` to `(A, B, C)`. -pub fn cons_tuples(iterable: I) -> ConsTuples - where I: Iterator -{ - ConsTuples { iter: iterable.into_iter() } -} diff --git a/vendor/itertools-0.8.2/src/diff.rs b/vendor/itertools-0.8.2/src/diff.rs deleted file mode 100644 index 2951bc422e..0000000000 --- a/vendor/itertools-0.8.2/src/diff.rs +++ /dev/null @@ -1,61 +0,0 @@ -//! "Diff"ing iterators for caching elements to sequential collections without requiring the new -//! elements' iterator to be `Clone`. -//! -//! - [**Diff**](./enum.Diff.html) (produced by the [**diff_with**](./fn.diff_with.html) function) -//! describes the difference between two non-`Clone` iterators `I` and `J` after breaking ASAP from -//! a lock-step comparison. - -use free::put_back; -use structs::PutBack; - -/// A type returned by the [`diff_with`](./fn.diff_with.html) function. -/// -/// `Diff` represents the way in which the elements yielded by the iterator `I` differ to some -/// iterator `J`. -pub enum Diff - where I: Iterator, - J: Iterator -{ - /// The index of the first non-matching element along with both iterator's remaining elements - /// starting with the first mis-match. - FirstMismatch(usize, PutBack, PutBack), - /// The total number of elements that were in `J` along with the remaining elements of `I`. - Shorter(usize, PutBack), - /// The total number of elements that were in `I` along with the remaining elements of `J`. - Longer(usize, PutBack), -} - -/// Compares every element yielded by both `i` and `j` with the given function in lock-step and -/// returns a `Diff` which describes how `j` differs from `i`. -/// -/// If the number of elements yielded by `j` is less than the number of elements yielded by `i`, -/// the number of `j` elements yielded will be returned along with `i`'s remaining elements as -/// `Diff::Shorter`. -/// -/// If the two elements of a step differ, the index of those elements along with the remaining -/// elements of both `i` and `j` are returned as `Diff::FirstMismatch`. -/// -/// If `i` becomes exhausted before `j` becomes exhausted, the number of elements in `i` along with -/// the remaining `j` elements will be returned as `Diff::Longer`. -pub fn diff_with(i: I, j: J, is_equal: F) - -> Option> - where I: IntoIterator, - J: IntoIterator, - F: Fn(&I::Item, &J::Item) -> bool -{ - let mut i = i.into_iter(); - let mut j = j.into_iter(); - let mut idx = 0; - while let Some(i_elem) = i.next() { - match j.next() { - None => return Some(Diff::Shorter(idx, put_back(i).with_value(i_elem))), - Some(j_elem) => if !is_equal(&i_elem, &j_elem) { - let remaining_i = put_back(i).with_value(i_elem); - let remaining_j = put_back(j).with_value(j_elem); - return Some(Diff::FirstMismatch(idx, remaining_i, remaining_j)); - }, - } - idx += 1; - } - j.next().map(|j_elem| Diff::Longer(idx, put_back(j).with_value(j_elem))) -} diff --git a/vendor/itertools-0.8.2/src/either_or_both.rs b/vendor/itertools-0.8.2/src/either_or_both.rs deleted file mode 100644 index 03130b128c..0000000000 --- a/vendor/itertools-0.8.2/src/either_or_both.rs +++ /dev/null @@ -1,190 +0,0 @@ -use EitherOrBoth::*; - -use either::Either; - -/// Value that either holds a single A or B, or both. -#[derive(Clone, PartialEq, Eq, Debug)] -pub enum EitherOrBoth { - /// Both values are present. - Both(A, B), - /// Only the left value of type `A` is present. - Left(A), - /// Only the right value of type `B` is present. - Right(B), -} - -impl EitherOrBoth { - /// If `Left`, or `Both`, return true, otherwise, return false. - pub fn has_left(&self) -> bool { - self.as_ref().left().is_some() - } - - /// If `Right`, or `Both`, return true, otherwise, return false. - pub fn has_right(&self) -> bool { - self.as_ref().right().is_some() - } - - /// If Left, return true otherwise, return false. - /// Exclusive version of [`has_left`]. - pub fn is_left(&self) -> bool { - match *self { - Left(_) => true, - _ => false, - } - } - - /// If Right, return true otherwise, return false. - /// Exclusive version of [`has_right`]. - pub fn is_right(&self) -> bool { - match *self { - Right(_) => true, - _ => false, - } - } - - /// If Right, return true otherwise, return false. - /// Equivalent to `self.as_ref().both().is_some()`. - pub fn is_both(&self) -> bool { - self.as_ref().both().is_some() - } - - /// If `Left`, or `Both`, return `Some` with the left value, otherwise, return `None`. - pub fn left(self) -> Option { - match self { - Left(left) | Both(left, _) => Some(left), - _ => None, - } - } - - /// If `Right`, or `Both`, return `Some` with the right value, otherwise, return `None`. - pub fn right(self) -> Option { - match self { - Right(right) | Both(_, right) => Some(right), - _ => None, - } - } - - /// If Both, return `Some` tuple containing left and right. - pub fn both(self) -> Option<(A, B)> { - match self { - Both(a, b) => Some((a, b)), - _ => None, - } - } - - /// Converts from `&EitherOrBoth` to `EitherOrBoth<&A, &B>`. - pub fn as_ref(&self) -> EitherOrBoth<&A, &B> { - match *self { - Left(ref left) => Left(left), - Right(ref right) => Right(right), - Both(ref left, ref right) => Both(left, right), - } - } - - /// Converts from `&mut EitherOrBoth` to `EitherOrBoth<&mut A, &mut B>`. - pub fn as_mut(&mut self) -> EitherOrBoth<&mut A, &mut B> { - match *self { - Left(ref mut left) => Left(left), - Right(ref mut right) => Right(right), - Both(ref mut left, ref mut right) => Both(left, right), - } - } - - /// Convert `EitherOrBoth` to `EitherOrBoth`. - pub fn flip(self) -> EitherOrBoth { - match self { - Left(a) => Right(a), - Right(b) => Left(b), - Both(a, b) => Both(b, a), - } - } - - /// Apply the function `f` on the value `a` in `Left(a)` or `Both(a, b)` variants. If it is - /// present rewrapping the result in `self`'s original variant. - pub fn map_left(self, f: F) -> EitherOrBoth - where - F: FnOnce(A) -> M, - { - match self { - Both(a, b) => Both(f(a), b), - Left(a) => Left(f(a)), - Right(b) => Right(b), - } - } - - /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, b)` variants. - /// If it is present rewrapping the result in `self`'s original variant. - pub fn map_right(self, f: F) -> EitherOrBoth - where - F: FnOnce(B) -> M, - { - match self { - Left(a) => Left(a), - Right(b) => Right(f(b)), - Both(a, b) => Both(a, f(b)), - } - } - - /// Apply the functions `f` and `g` on the value `a` and `b` respectively; - /// found in `Left(a)`, `Right(b)`, or `Both(a, b)` variants. - /// The Result is rewrapped `self`'s original variant. - pub fn map_any(self, f: F, g: G) -> EitherOrBoth - where - F: FnOnce(A) -> L, - G: FnOnce(B) -> R, - { - match self { - Left(a) => Left(f(a)), - Right(b) => Right(g(b)), - Both(a, b) => Both(f(a), g(b)), - } - } - - /// Apply the function `f` on the value `b` in `Right(b)` or `Both(a, _)` variants if it is - /// present. - pub fn left_and_then(self, f: F) -> EitherOrBoth - where - F: FnOnce(A) -> EitherOrBoth, - { - match self { - Left(a) | Both(a, _) => f(a), - Right(b) => Right(b), - } - } - - /// Apply the function `f` on the value `a` - /// in `Left(a)` or `Both(a, _)` variants if it is present. - pub fn right_and_then(self, f: F) -> EitherOrBoth - where - F: FnOnce(B) -> EitherOrBoth, - { - match self { - Left(a) => Left(a), - Right(b) | Both(_, b) => f(b), - } - } -} - -impl EitherOrBoth { - /// Return either value of left, right, or the product of `f` applied where `Both` are present. - pub fn reduce(self, f: F) -> T - where - F: FnOnce(T, T) -> T, - { - match self { - Left(a) => a, - Right(b) => b, - Both(a, b) => f(a, b), - } - } -} - -impl Into>> for EitherOrBoth { - fn into(self) -> Option> { - match self { - EitherOrBoth::Left(l) => Some(Either::Left(l)), - EitherOrBoth::Right(r) => Some(Either::Right(r)), - _ => None, - } - } -} diff --git a/vendor/itertools-0.8.2/src/exactly_one_err.rs b/vendor/itertools-0.8.2/src/exactly_one_err.rs deleted file mode 100644 index 6b7bad56d2..0000000000 --- a/vendor/itertools-0.8.2/src/exactly_one_err.rs +++ /dev/null @@ -1,58 +0,0 @@ -use std::iter::ExactSizeIterator; - -use size_hint; - -/// Iterator returned for the error case of `IterTools::exactly_one()` -/// This iterator yields exactly the same elements as the input iterator. -/// -/// During the execution of exactly_one the iterator must be mutated. This wrapper -/// effectively "restores" the state of the input iterator when it's handed back. -/// -/// This is very similar to PutBackN except this iterator only supports 0-2 elements and does not -/// use a `Vec`. -#[derive(Debug, Clone)] -pub struct ExactlyOneError -where - I: Iterator, -{ - first_two: (Option, Option), - inner: I, -} - -impl ExactlyOneError -where - I: Iterator, -{ - /// Creates a new `ExactlyOneErr` iterator. - pub(crate) fn new(first_two: (Option, Option), inner: I) -> Self { - Self { first_two, inner } - } -} - -impl Iterator for ExactlyOneError -where - I: Iterator, -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - self.first_two - .0 - .take() - .or_else(|| self.first_two.1.take()) - .or_else(|| self.inner.next()) - } - - fn size_hint(&self) -> (usize, Option) { - let mut additional_len = 0; - if self.first_two.0.is_some() { - additional_len += 1; - } - if self.first_two.1.is_some() { - additional_len += 1; - } - size_hint::add_scalar(self.inner.size_hint(), additional_len) - } -} - -impl ExactSizeIterator for ExactlyOneError where I: ExactSizeIterator {} diff --git a/vendor/itertools-0.8.2/src/format.rs b/vendor/itertools-0.8.2/src/format.rs deleted file mode 100644 index c42806b01c..0000000000 --- a/vendor/itertools-0.8.2/src/format.rs +++ /dev/null @@ -1,113 +0,0 @@ -use std::fmt; -use std::cell::RefCell; - -/// Format all iterator elements lazily, separated by `sep`. -/// -/// The format value can only be formatted once, after that the iterator is -/// exhausted. -/// -/// See [`.format_with()`](../trait.Itertools.html#method.format_with) for more information. -pub struct FormatWith<'a, I, F> { - sep: &'a str, - /// FormatWith uses interior mutability because Display::fmt takes &self. - inner: RefCell>, -} - -/// Format all iterator elements lazily, separated by `sep`. -/// -/// The format value can only be formatted once, after that the iterator is -/// exhausted. -/// -/// See [`.format()`](../trait.Itertools.html#method.format) -/// for more information. -#[derive(Clone)] -pub struct Format<'a, I> { - sep: &'a str, - /// Format uses interior mutability because Display::fmt takes &self. - inner: RefCell>, -} - -pub fn new_format<'a, I, F>(iter: I, separator: &'a str, f: F) -> FormatWith<'a, I, F> - where I: Iterator, - F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result -{ - FormatWith { - sep: separator, - inner: RefCell::new(Some((iter, f))), - } -} - -pub fn new_format_default<'a, I>(iter: I, separator: &'a str) -> Format<'a, I> - where I: Iterator, -{ - Format { - sep: separator, - inner: RefCell::new(Some(iter)), - } -} - -impl<'a, I, F> fmt::Display for FormatWith<'a, I, F> - where I: Iterator, - F: FnMut(I::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result -{ - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (mut iter, mut format) = match self.inner.borrow_mut().take() { - Some(t) => t, - None => panic!("FormatWith: was already formatted once"), - }; - - if let Some(fst) = iter.next() { - try!(format(fst, &mut |disp: &fmt::Display| disp.fmt(f))); - for elt in iter { - if self.sep.len() > 0 { - - try!(f.write_str(self.sep)); - } - try!(format(elt, &mut |disp: &fmt::Display| disp.fmt(f))); - } - } - Ok(()) - } -} - -impl<'a, I> Format<'a, I> - where I: Iterator, -{ - fn format(&self, f: &mut fmt::Formatter, mut cb: F) -> fmt::Result - where F: FnMut(&I::Item, &mut fmt::Formatter) -> fmt::Result, - { - let mut iter = match self.inner.borrow_mut().take() { - Some(t) => t, - None => panic!("Format: was already formatted once"), - }; - - if let Some(fst) = iter.next() { - try!(cb(&fst, f)); - for elt in iter { - if self.sep.len() > 0 { - try!(f.write_str(self.sep)); - } - try!(cb(&elt, f)); - } - } - Ok(()) - } -} - -macro_rules! impl_format { - ($($fmt_trait:ident)*) => { - $( - impl<'a, I> fmt::$fmt_trait for Format<'a, I> - where I: Iterator, - I::Item: fmt::$fmt_trait, - { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.format(f, fmt::$fmt_trait::fmt) - } - } - )* - } -} - -impl_format!{Display Debug - UpperExp LowerExp UpperHex LowerHex Octal Binary Pointer} diff --git a/vendor/itertools-0.8.2/src/free.rs b/vendor/itertools-0.8.2/src/free.rs deleted file mode 100644 index 2bc72a9aa1..0000000000 --- a/vendor/itertools-0.8.2/src/free.rs +++ /dev/null @@ -1,236 +0,0 @@ -//! Free functions that create iterator adaptors or call iterator methods. -//! -//! The benefit of free functions is that they accept any `IntoIterator` as -//! argument, so the resulting code may be easier to read. - -#[cfg(feature = "use_std")] -use std::fmt::Display; -use std::iter::{self, Zip}; -#[cfg(feature = "use_std")] -type VecIntoIter = ::std::vec::IntoIter; - -#[cfg(feature = "use_std")] -use Itertools; - -pub use adaptors::{ - interleave, - merge, - put_back, -}; -#[cfg(feature = "use_std")] -pub use put_back_n_impl::put_back_n; -#[cfg(feature = "use_std")] -pub use multipeek_impl::multipeek; -#[cfg(feature = "use_std")] -pub use kmerge_impl::kmerge; -pub use zip_eq_impl::zip_eq; -pub use merge_join::merge_join_by; -#[cfg(feature = "use_std")] -pub use rciter_impl::rciter; - -/// Iterate `iterable` with a running index. -/// -/// `IntoIterator` enabled version of `.enumerate()`. -/// -/// ``` -/// use itertools::enumerate; -/// -/// for (i, elt) in enumerate(&[1, 2, 3]) { -/// /* loop body */ -/// } -/// ``` -pub fn enumerate(iterable: I) -> iter::Enumerate - where I: IntoIterator -{ - iterable.into_iter().enumerate() -} - -/// Iterate `iterable` in reverse. -/// -/// `IntoIterator` enabled version of `.rev()`. -/// -/// ``` -/// use itertools::rev; -/// -/// for elt in rev(&[1, 2, 3]) { -/// /* loop body */ -/// } -/// ``` -pub fn rev(iterable: I) -> iter::Rev - where I: IntoIterator, - I::IntoIter: DoubleEndedIterator -{ - iterable.into_iter().rev() -} - -/// Iterate `i` and `j` in lock step. -/// -/// `IntoIterator` enabled version of `i.zip(j)`. -/// -/// ``` -/// use itertools::zip; -/// -/// let data = [1, 2, 3, 4, 5]; -/// for (a, b) in zip(&data, &data[1..]) { -/// /* loop body */ -/// } -/// ``` -pub fn zip(i: I, j: J) -> Zip - where I: IntoIterator, - J: IntoIterator -{ - i.into_iter().zip(j) -} - -/// Create an iterator that first iterates `i` and then `j`. -/// -/// `IntoIterator` enabled version of `i.chain(j)`. -/// -/// ``` -/// use itertools::chain; -/// -/// for elt in chain(&[1, 2, 3], &[4]) { -/// /* loop body */ -/// } -/// ``` -pub fn chain(i: I, j: J) -> iter::Chain<::IntoIter, ::IntoIter> - where I: IntoIterator, - J: IntoIterator -{ - i.into_iter().chain(j) -} - -/// Create an iterator that clones each element from &T to T -/// -/// `IntoIterator` enabled version of `i.cloned()`. -/// -/// ``` -/// use itertools::cloned; -/// -/// assert_eq!(cloned(b"abc").next(), Some(b'a')); -/// ``` -pub fn cloned<'a, I, T: 'a>(iterable: I) -> iter::Cloned - where I: IntoIterator, - T: Clone, -{ - iterable.into_iter().cloned() -} - -/// Perform a fold operation over the iterable. -/// -/// `IntoIterator` enabled version of `i.fold(init, f)` -/// -/// ``` -/// use itertools::fold; -/// -/// assert_eq!(fold(&[1., 2., 3.], 0., |a, &b| f32::max(a, b)), 3.); -/// ``` -pub fn fold(iterable: I, init: B, f: F) -> B - where I: IntoIterator, - F: FnMut(B, I::Item) -> B -{ - iterable.into_iter().fold(init, f) -} - -/// Test whether the predicate holds for all elements in the iterable. -/// -/// `IntoIterator` enabled version of `i.all(f)` -/// -/// ``` -/// use itertools::all; -/// -/// assert!(all(&[1, 2, 3], |elt| *elt > 0)); -/// ``` -pub fn all(iterable: I, f: F) -> bool - where I: IntoIterator, - F: FnMut(I::Item) -> bool -{ - iterable.into_iter().all(f) -} - -/// Test whether the predicate holds for any elements in the iterable. -/// -/// `IntoIterator` enabled version of `i.any(f)` -/// -/// ``` -/// use itertools::any; -/// -/// assert!(any(&[0, -1, 2], |elt| *elt > 0)); -/// ``` -pub fn any(iterable: I, f: F) -> bool - where I: IntoIterator, - F: FnMut(I::Item) -> bool -{ - iterable.into_iter().any(f) -} - -/// Return the maximum value of the iterable. -/// -/// `IntoIterator` enabled version of `i.max()`. -/// -/// ``` -/// use itertools::max; -/// -/// assert_eq!(max(0..10), Some(9)); -/// ``` -pub fn max(iterable: I) -> Option - where I: IntoIterator, - I::Item: Ord -{ - iterable.into_iter().max() -} - -/// Return the minimum value of the iterable. -/// -/// `IntoIterator` enabled version of `i.min()`. -/// -/// ``` -/// use itertools::min; -/// -/// assert_eq!(min(0..10), Some(0)); -/// ``` -pub fn min(iterable: I) -> Option - where I: IntoIterator, - I::Item: Ord -{ - iterable.into_iter().min() -} - - -/// Combine all iterator elements into one String, seperated by `sep`. -/// -/// `IntoIterator` enabled version of `iterable.join(sep)`. -/// -/// ``` -/// use itertools::join; -/// -/// assert_eq!(join(&[1, 2, 3], ", "), "1, 2, 3"); -/// ``` -#[cfg(feature = "use_std")] -pub fn join(iterable: I, sep: &str) -> String - where I: IntoIterator, - I::Item: Display -{ - iterable.into_iter().join(sep) -} - -/// Sort all iterator elements into a new iterator in ascending order. -/// -/// `IntoIterator` enabled version of [`iterable.sorted()`][1]. -/// -/// [1]: trait.Itertools.html#method.sorted -/// -/// ``` -/// use itertools::sorted; -/// use itertools::assert_equal; -/// -/// assert_equal(sorted("rust".chars()), "rstu".chars()); -/// ``` -#[cfg(feature = "use_std")] -pub fn sorted(iterable: I) -> VecIntoIter - where I: IntoIterator, - I::Item: Ord -{ - iterable.into_iter().sorted() -} - diff --git a/vendor/itertools-0.8.2/src/group_map.rs b/vendor/itertools-0.8.2/src/group_map.rs deleted file mode 100644 index be9f8420d8..0000000000 --- a/vendor/itertools-0.8.2/src/group_map.rs +++ /dev/null @@ -1,22 +0,0 @@ -#![cfg(feature = "use_std")] - -use std::collections::HashMap; -use std::hash::Hash; -use std::iter::Iterator; - -/// Return a `HashMap` of keys mapped to a list of their corresponding values. -/// -/// See [`.into_group_map()`](../trait.Itertools.html#method.into_group_map) -/// for more information. -pub fn into_group_map(iter: I) -> HashMap> - where I: Iterator, - K: Hash + Eq, -{ - let mut lookup = HashMap::new(); - - for (key, val) in iter { - lookup.entry(key).or_insert(Vec::new()).push(val); - } - - lookup -} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/src/groupbylazy.rs b/vendor/itertools-0.8.2/src/groupbylazy.rs deleted file mode 100644 index ff253e845d..0000000000 --- a/vendor/itertools-0.8.2/src/groupbylazy.rs +++ /dev/null @@ -1,571 +0,0 @@ -use std::cell::{Cell, RefCell}; -use std::vec; - -/// A trait to unify FnMut for GroupBy with the chunk key in IntoChunks -trait KeyFunction { - type Key; - fn call_mut(&mut self, arg: A) -> Self::Key; -} - -impl<'a, A, K, F: ?Sized> KeyFunction for F - where F: FnMut(A) -> K -{ - type Key = K; - #[inline] - fn call_mut(&mut self, arg: A) -> Self::Key { - (*self)(arg) - } -} - - -/// ChunkIndex acts like the grouping key function for IntoChunks -#[derive(Debug)] -struct ChunkIndex { - size: usize, - index: usize, - key: usize, -} - -impl ChunkIndex { - #[inline(always)] - fn new(size: usize) -> Self { - ChunkIndex { - size: size, - index: 0, - key: 0, - } - } -} - -impl<'a, A> KeyFunction for ChunkIndex { - type Key = usize; - #[inline(always)] - fn call_mut(&mut self, _arg: A) -> Self::Key { - if self.index == self.size { - self.key += 1; - self.index = 0; - } - self.index += 1; - self.key - } -} - - -struct GroupInner - where I: Iterator -{ - key: F, - iter: I, - current_key: Option, - current_elt: Option, - /// flag set if iterator is exhausted - done: bool, - /// Index of group we are currently buffering or visiting - top_group: usize, - /// Least index for which we still have elements buffered - oldest_buffered_group: usize, - /// Group index for `buffer[0]` -- the slots - /// bottom_group..oldest_buffered_group are unused and will be erased when - /// that range is large enough. - bottom_group: usize, - /// Buffered groups, from `bottom_group` (index 0) to `top_group`. - buffer: Vec>, - /// index of last group iter that was dropped, usize::MAX == none - dropped_group: usize, -} - -impl GroupInner - where I: Iterator, - F: for<'a> KeyFunction<&'a I::Item, Key=K>, - K: PartialEq, -{ - /// `client`: Index of group that requests next element - #[inline(always)] - fn step(&mut self, client: usize) -> Option { - /* - println!("client={}, bottom_group={}, oldest_buffered_group={}, top_group={}, buffers=[{}]", - client, self.bottom_group, self.oldest_buffered_group, - self.top_group, - self.buffer.iter().map(|elt| elt.len()).format(", ")); - */ - if client < self.oldest_buffered_group { - None - } else if client < self.top_group || - (client == self.top_group && - self.buffer.len() > self.top_group - self.bottom_group) - { - self.lookup_buffer(client) - } else if self.done { - None - } else if self.top_group == client { - self.step_current() - } else { - self.step_buffering(client) - } - } - - #[inline(never)] - fn lookup_buffer(&mut self, client: usize) -> Option { - // if `bufidx` doesn't exist in self.buffer, it might be empty - let bufidx = client - self.bottom_group; - if client < self.oldest_buffered_group { - return None; - } - let elt = self.buffer.get_mut(bufidx).and_then(|queue| queue.next()); - if elt.is_none() && client == self.oldest_buffered_group { - // FIXME: VecDeque is unfortunately not zero allocation when empty, - // so we do this job manually. - // `bottom_group..oldest_buffered_group` is unused, and if it's large enough, erase it. - self.oldest_buffered_group += 1; - // skip forward further empty queues too - while self.buffer.get(self.oldest_buffered_group - self.bottom_group) - .map_or(false, |buf| buf.len() == 0) - { - self.oldest_buffered_group += 1; - } - - let nclear = self.oldest_buffered_group - self.bottom_group; - if nclear > 0 && nclear >= self.buffer.len() / 2 { - let mut i = 0; - self.buffer.retain(|buf| { - i += 1; - debug_assert!(buf.len() == 0 || i > nclear); - i > nclear - }); - self.bottom_group = self.oldest_buffered_group; - } - } - elt - } - - /// Take the next element from the iterator, and set the done - /// flag if exhausted. Must not be called after done. - #[inline(always)] - fn next_element(&mut self) -> Option { - debug_assert!(!self.done); - match self.iter.next() { - None => { self.done = true; None } - otherwise => otherwise, - } - } - - - #[inline(never)] - fn step_buffering(&mut self, client: usize) -> Option { - // requested a later group -- walk through the current group up to - // the requested group index, and buffer the elements (unless - // the group is marked as dropped). - // Because the `Groups` iterator is always the first to request - // each group index, client is the next index efter top_group. - debug_assert!(self.top_group + 1 == client); - let mut group = Vec::new(); - - if let Some(elt) = self.current_elt.take() { - if self.top_group != self.dropped_group { - group.push(elt); - } - } - let mut first_elt = None; // first element of the next group - - while let Some(elt) = self.next_element() { - let key = self.key.call_mut(&elt); - match self.current_key.take() { - None => {} - Some(old_key) => if old_key != key { - self.current_key = Some(key); - first_elt = Some(elt); - break; - }, - } - self.current_key = Some(key); - if self.top_group != self.dropped_group { - group.push(elt); - } - } - - if self.top_group != self.dropped_group { - self.push_next_group(group); - } - if first_elt.is_some() { - self.top_group += 1; - debug_assert!(self.top_group == client); - } - first_elt - } - - fn push_next_group(&mut self, group: Vec) { - // When we add a new buffered group, fill up slots between oldest_buffered_group and top_group - while self.top_group - self.bottom_group > self.buffer.len() { - if self.buffer.is_empty() { - self.bottom_group += 1; - self.oldest_buffered_group += 1; - } else { - self.buffer.push(Vec::new().into_iter()); - } - } - self.buffer.push(group.into_iter()); - debug_assert!(self.top_group + 1 - self.bottom_group == self.buffer.len()); - } - - /// This is the immediate case, where we use no buffering - #[inline] - fn step_current(&mut self) -> Option { - debug_assert!(!self.done); - if let elt @ Some(..) = self.current_elt.take() { - return elt; - } - match self.next_element() { - None => None, - Some(elt) => { - let key = self.key.call_mut(&elt); - match self.current_key.take() { - None => {} - Some(old_key) => if old_key != key { - self.current_key = Some(key); - self.current_elt = Some(elt); - self.top_group += 1; - return None; - }, - } - self.current_key = Some(key); - Some(elt) - } - } - } - - /// Request the just started groups' key. - /// - /// `client`: Index of group - /// - /// **Panics** if no group key is available. - fn group_key(&mut self, client: usize) -> K { - // This can only be called after we have just returned the first - // element of a group. - // Perform this by simply buffering one more element, grabbing the - // next key. - debug_assert!(!self.done); - debug_assert!(client == self.top_group); - debug_assert!(self.current_key.is_some()); - debug_assert!(self.current_elt.is_none()); - let old_key = self.current_key.take().unwrap(); - if let Some(elt) = self.next_element() { - let key = self.key.call_mut(&elt); - if old_key != key { - self.top_group += 1; - } - self.current_key = Some(key); - self.current_elt = Some(elt); - } - old_key - } -} - -impl GroupInner - where I: Iterator, -{ - /// Called when a group is dropped - fn drop_group(&mut self, client: usize) { - // It's only useful to track the maximal index - if self.dropped_group == !0 || client > self.dropped_group { - self.dropped_group = client; - } - } -} - -/// `GroupBy` is the storage for the lazy grouping operation. -/// -/// If the groups are consumed in their original order, or if each -/// group is dropped without keeping it around, then `GroupBy` uses -/// no allocations. It needs allocations only if several group iterators -/// are alive at the same time. -/// -/// This type implements `IntoIterator` (it is **not** an iterator -/// itself), because the group iterators need to borrow from this -/// value. It should be stored in a local variable or temporary and -/// iterated. -/// -/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct GroupBy - where I: Iterator, -{ - inner: RefCell>, - // the group iterator's current index. Keep this in the main value - // so that simultaneous iterators all use the same state. - index: Cell, -} - -/// Create a new -pub fn new(iter: J, f: F) -> GroupBy - where J: IntoIterator, - F: FnMut(&J::Item) -> K, -{ - GroupBy { - inner: RefCell::new(GroupInner { - key: f, - iter: iter.into_iter(), - current_key: None, - current_elt: None, - done: false, - top_group: 0, - oldest_buffered_group: 0, - bottom_group: 0, - buffer: Vec::new(), - dropped_group: !0, - }), - index: Cell::new(0), - } -} - -impl GroupBy - where I: Iterator, -{ - /// `client`: Index of group that requests next element - fn step(&self, client: usize) -> Option - where F: FnMut(&I::Item) -> K, - K: PartialEq, - { - self.inner.borrow_mut().step(client) - } - - /// `client`: Index of group - fn drop_group(&self, client: usize) { - self.inner.borrow_mut().drop_group(client) - } -} - -impl<'a, K, I, F> IntoIterator for &'a GroupBy - where I: Iterator, - I::Item: 'a, - F: FnMut(&I::Item) -> K, - K: PartialEq -{ - type Item = (K, Group<'a, K, I, F>); - type IntoIter = Groups<'a, K, I, F>; - - fn into_iter(self) -> Self::IntoIter { - Groups { parent: self } - } -} - - -/// An iterator that yields the Group iterators. -/// -/// Iterator element type is `(K, Group)`: -/// the group's key `K` and the group's iterator. -/// -/// See [`.group_by()`](../trait.Itertools.html#method.group_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Groups<'a, K: 'a, I: 'a, F: 'a> - where I: Iterator, - I::Item: 'a -{ - parent: &'a GroupBy, -} - -impl<'a, K, I, F> Iterator for Groups<'a, K, I, F> - where I: Iterator, - I::Item: 'a, - F: FnMut(&I::Item) -> K, - K: PartialEq -{ - type Item = (K, Group<'a, K, I, F>); - - #[inline] - fn next(&mut self) -> Option { - let index = self.parent.index.get(); - self.parent.index.set(index + 1); - let inner = &mut *self.parent.inner.borrow_mut(); - inner.step(index).map(|elt| { - let key = inner.group_key(index); - (key, Group { - parent: self.parent, - index: index, - first: Some(elt), - }) - }) - } -} - -/// An iterator for the elements in a single group. -/// -/// Iterator element type is `I::Item`. -pub struct Group<'a, K: 'a, I: 'a, F: 'a> - where I: Iterator, - I::Item: 'a, -{ - parent: &'a GroupBy, - index: usize, - first: Option, -} - -impl<'a, K, I, F> Drop for Group<'a, K, I, F> - where I: Iterator, - I::Item: 'a, -{ - fn drop(&mut self) { - self.parent.drop_group(self.index); - } -} - -impl<'a, K, I, F> Iterator for Group<'a, K, I, F> - where I: Iterator, - I::Item: 'a, - F: FnMut(&I::Item) -> K, - K: PartialEq, -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if let elt @ Some(..) = self.first.take() { - return elt; - } - self.parent.step(self.index) - } -} - -///// IntoChunks ///// - -/// Create a new -pub fn new_chunks(iter: J, size: usize) -> IntoChunks - where J: IntoIterator, -{ - IntoChunks { - inner: RefCell::new(GroupInner { - key: ChunkIndex::new(size), - iter: iter.into_iter(), - current_key: None, - current_elt: None, - done: false, - top_group: 0, - oldest_buffered_group: 0, - bottom_group: 0, - buffer: Vec::new(), - dropped_group: !0, - }), - index: Cell::new(0), - } -} - - -/// `ChunkLazy` is the storage for a lazy chunking operation. -/// -/// `IntoChunks` behaves just like `GroupBy`: it is iterable, and -/// it only buffers if several chunk iterators are alive at the same time. -/// -/// This type implements `IntoIterator` (it is **not** an iterator -/// itself), because the chunk iterators need to borrow from this -/// value. It should be stored in a local variable or temporary and -/// iterated. -/// -/// Iterator element type is `Chunk`, each chunk's iterator. -/// -/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct IntoChunks - where I: Iterator, -{ - inner: RefCell>, - // the chunk iterator's current index. Keep this in the main value - // so that simultaneous iterators all use the same state. - index: Cell, -} - - -impl IntoChunks - where I: Iterator, -{ - /// `client`: Index of chunk that requests next element - fn step(&self, client: usize) -> Option { - self.inner.borrow_mut().step(client) - } - - /// `client`: Index of chunk - fn drop_group(&self, client: usize) { - self.inner.borrow_mut().drop_group(client) - } -} - -impl<'a, I> IntoIterator for &'a IntoChunks - where I: Iterator, - I::Item: 'a, -{ - type Item = Chunk<'a, I>; - type IntoIter = Chunks<'a, I>; - - fn into_iter(self) -> Self::IntoIter { - Chunks { - parent: self, - } - } -} - - -/// An iterator that yields the Chunk iterators. -/// -/// Iterator element type is `Chunk`. -/// -/// See [`.chunks()`](../trait.Itertools.html#method.chunks) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Chunks<'a, I: 'a> - where I: Iterator, - I::Item: 'a, -{ - parent: &'a IntoChunks, -} - -impl<'a, I> Iterator for Chunks<'a, I> - where I: Iterator, - I::Item: 'a, -{ - type Item = Chunk<'a, I>; - - #[inline] - fn next(&mut self) -> Option { - let index = self.parent.index.get(); - self.parent.index.set(index + 1); - let inner = &mut *self.parent.inner.borrow_mut(); - inner.step(index).map(|elt| { - Chunk { - parent: self.parent, - index: index, - first: Some(elt), - } - }) - } -} - -/// An iterator for the elements in a single chunk. -/// -/// Iterator element type is `I::Item`. -pub struct Chunk<'a, I: 'a> - where I: Iterator, - I::Item: 'a, -{ - parent: &'a IntoChunks, - index: usize, - first: Option, -} - -impl<'a, I> Drop for Chunk<'a, I> - where I: Iterator, - I::Item: 'a, -{ - fn drop(&mut self) { - self.parent.drop_group(self.index); - } -} - -impl<'a, I> Iterator for Chunk<'a, I> - where I: Iterator, - I::Item: 'a, -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if let elt @ Some(..) = self.first.take() { - return elt; - } - self.parent.step(self.index) - } -} diff --git a/vendor/itertools-0.8.2/src/impl_macros.rs b/vendor/itertools-0.8.2/src/impl_macros.rs deleted file mode 100644 index b41760aee8..0000000000 --- a/vendor/itertools-0.8.2/src/impl_macros.rs +++ /dev/null @@ -1,14 +0,0 @@ -//! -//! Implementation's internal macros - -macro_rules! debug_fmt_fields { - ($tyname:ident, $($($field:ident).+),*) => { - fn fmt(&self, f: &mut ::std::fmt::Formatter) -> ::std::fmt::Result { - f.debug_struct(stringify!($tyname)) - $( - .field(stringify!($($field).+), &self.$($field).+) - )* - .finish() - } - } -} diff --git a/vendor/itertools-0.8.2/src/intersperse.rs b/vendor/itertools-0.8.2/src/intersperse.rs deleted file mode 100644 index f82544229c..0000000000 --- a/vendor/itertools-0.8.2/src/intersperse.rs +++ /dev/null @@ -1,79 +0,0 @@ -use std::iter::Fuse; -use super::size_hint; - -#[derive(Clone)] -/// An iterator adaptor to insert a particular value -/// between each element of the adapted iterator. -/// -/// Iterator element type is `I::Item` -/// -/// This iterator is *fused*. -/// -/// See [`.intersperse()`](../trait.Itertools.html#method.intersperse) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct Intersperse - where I: Iterator -{ - element: I::Item, - iter: Fuse, - peek: Option, -} - -/// Create a new Intersperse iterator -pub fn intersperse(iter: I, elt: I::Item) -> Intersperse - where I: Iterator -{ - let mut iter = iter.fuse(); - Intersperse { - peek: iter.next(), - iter: iter, - element: elt, - } -} - -impl Iterator for Intersperse - where I: Iterator, - I::Item: Clone -{ - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if self.peek.is_some() { - self.peek.take() - } else { - self.peek = self.iter.next(); - if self.peek.is_some() { - Some(self.element.clone()) - } else { - None - } - } - } - - fn size_hint(&self) -> (usize, Option) { - // 2 * SH + { 1 or 0 } - let has_peek = self.peek.is_some() as usize; - let sh = self.iter.size_hint(); - size_hint::add_scalar(size_hint::add(sh, sh), has_peek) - } - - fn fold(mut self, init: B, mut f: F) -> B where - Self: Sized, F: FnMut(B, Self::Item) -> B, - { - let mut accum = init; - - if let Some(x) = self.peek.take() { - accum = f(accum, x); - } - - let element = &self.element; - - self.iter.fold(accum, - |accum, x| { - let accum = f(accum, element.clone()); - let accum = f(accum, x); - accum - }) - } -} diff --git a/vendor/itertools-0.8.2/src/kmerge_impl.rs b/vendor/itertools-0.8.2/src/kmerge_impl.rs deleted file mode 100644 index a79b7bdace..0000000000 --- a/vendor/itertools-0.8.2/src/kmerge_impl.rs +++ /dev/null @@ -1,231 +0,0 @@ - -use size_hint; -use Itertools; - -use std::mem::replace; -use std::fmt; - -macro_rules! clone_fields { - ($name:ident, $base:expr, $($field:ident),+) => ( - $name { - $( - $field : $base . $field .clone() - ),* - } - ); -} - -/// Head element and Tail iterator pair -/// -/// `PartialEq`, `Eq`, `PartialOrd` and `Ord` are implemented by comparing sequences based on -/// first items (which are guaranteed to exist). -/// -/// The meanings of `PartialOrd` and `Ord` are reversed so as to turn the heap used in -/// `KMerge` into a min-heap. -#[derive(Debug)] -struct HeadTail - where I: Iterator -{ - head: I::Item, - tail: I, -} - -impl HeadTail - where I: Iterator -{ - /// Constructs a `HeadTail` from an `Iterator`. Returns `None` if the `Iterator` is empty. - fn new(mut it: I) -> Option> { - let head = it.next(); - head.map(|h| { - HeadTail { - head: h, - tail: it, - } - }) - } - - /// Get the next element and update `head`, returning the old head in `Some`. - /// - /// Returns `None` when the tail is exhausted (only `head` then remains). - fn next(&mut self) -> Option { - if let Some(next) = self.tail.next() { - Some(replace(&mut self.head, next)) - } else { - None - } - } - - /// Hints at the size of the sequence, same as the `Iterator` method. - fn size_hint(&self) -> (usize, Option) { - size_hint::add_scalar(self.tail.size_hint(), 1) - } -} - -impl Clone for HeadTail - where I: Iterator + Clone, - I::Item: Clone -{ - fn clone(&self) -> Self { - clone_fields!(HeadTail, self, head, tail) - } -} - -/// Make `data` a heap (min-heap w.r.t the sorting). -fn heapify(data: &mut [T], mut less_than: S) - where S: FnMut(&T, &T) -> bool -{ - for i in (0..data.len() / 2).rev() { - sift_down(data, i, &mut less_than); - } -} - -/// Sift down element at `index` (`heap` is a min-heap wrt the ordering) -fn sift_down(heap: &mut [T], index: usize, mut less_than: S) - where S: FnMut(&T, &T) -> bool -{ - debug_assert!(index <= heap.len()); - let mut pos = index; - let mut child = 2 * pos + 1; - // the `pos` conditional is to avoid a bounds check - while pos < heap.len() && child < heap.len() { - let right = child + 1; - - // pick the smaller of the two children - if right < heap.len() && less_than(&heap[right], &heap[child]) { - child = right; - } - - // sift down is done if we are already in order - if !less_than(&heap[child], &heap[pos]) { - return; - } - heap.swap(pos, child); - pos = child; - child = 2 * pos + 1; - } -} - -/// An iterator adaptor that merges an abitrary number of base iterators in ascending order. -/// If all base iterators are sorted (ascending), the result is sorted. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.kmerge()`](../trait.Itertools.html#method.kmerge) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub type KMerge = KMergeBy; - -pub trait KMergePredicate { - fn kmerge_pred(&mut self, a: &T, b: &T) -> bool; -} - -#[derive(Clone)] -pub struct KMergeByLt; - -impl KMergePredicate for KMergeByLt { - fn kmerge_pred(&mut self, a: &T, b: &T) -> bool { - a < b - } -} - -implbool> KMergePredicate for F { - fn kmerge_pred(&mut self, a: &T, b: &T) -> bool { - self(a, b) - } -} - -/// Create an iterator that merges elements of the contained iterators using -/// the ordering function. -/// -/// Equivalent to `iterable.into_iter().kmerge()`. -/// -/// ``` -/// use itertools::kmerge; -/// -/// for elt in kmerge(vec![vec![0, 2, 4], vec![1, 3, 5], vec![6, 7]]) { -/// /* loop body */ -/// } -/// ``` -pub fn kmerge(iterable: I) -> KMerge<::IntoIter> - where I: IntoIterator, - I::Item: IntoIterator, - <::Item as IntoIterator>::Item: PartialOrd -{ - kmerge_by(iterable, KMergeByLt) -} - -/// An iterator adaptor that merges an abitrary number of base iterators -/// according to an ordering function. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.kmerge_by()`](../trait.Itertools.html#method.kmerge_by) for more -/// information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct KMergeBy - where I: Iterator, -{ - heap: Vec>, - less_than: F, -} - -impl fmt::Debug for KMergeBy - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(KMergeBy, heap); -} - -/// Create an iterator that merges elements of the contained iterators. -/// -/// Equivalent to `iterable.into_iter().kmerge_by(less_than)`. -pub fn kmerge_by(iterable: I, mut less_than: F) - -> KMergeBy<::IntoIter, F> - where I: IntoIterator, - I::Item: IntoIterator, - F: KMergePredicate<<::Item as IntoIterator>::Item>, -{ - let iter = iterable.into_iter(); - let (lower, _) = iter.size_hint(); - let mut heap: Vec<_> = Vec::with_capacity(lower); - heap.extend(iter.filter_map(|it| HeadTail::new(it.into_iter()))); - heapify(&mut heap, |a, b| less_than.kmerge_pred(&a.head, &b.head)); - KMergeBy { heap: heap, less_than: less_than } -} - -impl Clone for KMergeBy - where I: Iterator + Clone, - I::Item: Clone, - F: Clone, -{ - fn clone(&self) -> KMergeBy { - clone_fields!(KMergeBy, self, heap, less_than) - } -} - -impl Iterator for KMergeBy - where I: Iterator, - F: KMergePredicate -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - if self.heap.is_empty() { - return None; - } - let result = if let Some(next) = self.heap[0].next() { - next - } else { - self.heap.swap_remove(0).head - }; - let less_than = &mut self.less_than; - sift_down(&mut self.heap, 0, |a, b| less_than.kmerge_pred(&a.head, &b.head)); - Some(result) - } - - fn size_hint(&self) -> (usize, Option) { - self.heap.iter() - .map(|i| i.size_hint()) - .fold1(size_hint::add) - .unwrap_or((0, Some(0))) - } -} diff --git a/vendor/itertools-0.8.2/src/lazy_buffer.rs b/vendor/itertools-0.8.2/src/lazy_buffer.rs deleted file mode 100644 index 09a8cd9569..0000000000 --- a/vendor/itertools-0.8.2/src/lazy_buffer.rs +++ /dev/null @@ -1,68 +0,0 @@ -use std::ops::Index; - -#[derive(Debug, Clone)] -pub struct LazyBuffer { - pub it: I, - done: bool, - buffer: Vec, -} - -impl LazyBuffer -where - I: Iterator, -{ - pub fn new(it: I) -> LazyBuffer { - let mut it = it; - let mut buffer = Vec::new(); - let done; - if let Some(first) = it.next() { - buffer.push(first); - done = false; - } else { - done = true; - } - LazyBuffer { - it: it, - done: done, - buffer: buffer, - } - } - - pub fn len(&self) -> usize { - self.buffer.len() - } - - pub fn is_done(&self) -> bool { - self.done - } - - pub fn get_next(&mut self) -> bool { - if self.done { - return false; - } - let next_item = self.it.next(); - match next_item { - Some(x) => { - self.buffer.push(x); - true - } - None => { - self.done = true; - false - } - } - } -} - -impl Index for LazyBuffer -where - I: Iterator, - I::Item: Sized, - Vec: Index -{ - type Output = as Index>::Output; - - fn index(&self, _index: J) -> &Self::Output { - self.buffer.index(_index) - } -} diff --git a/vendor/itertools-0.8.2/src/lib.rs b/vendor/itertools-0.8.2/src/lib.rs deleted file mode 100644 index d7c7960bb7..0000000000 --- a/vendor/itertools-0.8.2/src/lib.rs +++ /dev/null @@ -1,2391 +0,0 @@ -#![warn(missing_docs)] -#![crate_name="itertools"] -#![cfg_attr(not(feature = "use_std"), no_std)] - -//! Extra iterator adaptors, functions and macros. -//! -//! To extend [`Iterator`] with methods in this crate, import -//! the [`Itertools` trait](./trait.Itertools.html): -//! -//! ``` -//! use itertools::Itertools; -//! ``` -//! -//! Now, new methods like [`interleave`](./trait.Itertools.html#method.interleave) -//! are available on all iterators: -//! -//! ``` -//! use itertools::Itertools; -//! -//! let it = (1..3).interleave(vec![-1, -2]); -//! itertools::assert_equal(it, vec![1, -1, 2, -2]); -//! ``` -//! -//! Most iterator methods are also provided as functions (with the benefit -//! that they convert parameters using [`IntoIterator`]): -//! -//! ``` -//! use itertools::interleave; -//! -//! for elt in interleave(&[1, 2, 3], &[2, 3, 4]) { -//! /* loop body */ -//! } -//! ``` -//! -//! ## Crate Features -//! -//! - `use_std` -//! - Enabled by default. -//! - Disable to compile itertools using `#![no_std]`. This disables -//! any items that depend on collections (like `group_by`, `unique`, -//! `kmerge`, `join` and many more). -//! -//! ## Rust Version -//! -//! This version of itertools requires Rust 1.24 or later. -//! -//! [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html -#![doc(html_root_url="https://docs.rs/itertools/0.8/")] - -extern crate either; - -#[cfg(not(feature = "use_std"))] -extern crate core as std; - -pub use either::Either; - -#[cfg(feature = "use_std")] -use std::collections::HashMap; -use std::iter::{IntoIterator, once}; -use std::cmp::Ordering; -use std::fmt; -#[cfg(feature = "use_std")] -use std::hash::Hash; -#[cfg(feature = "use_std")] -use std::fmt::Write; -#[cfg(feature = "use_std")] -type VecIntoIter = ::std::vec::IntoIter; -#[cfg(feature = "use_std")] -use std::iter::FromIterator; - -#[macro_use] -mod impl_macros; - -// for compatibility with no std and macros -#[doc(hidden)] -pub use std::iter as __std_iter; - -/// The concrete iterator types. -pub mod structs { - pub use adaptors::{ - Dedup, - DedupBy, - Interleave, - InterleaveShortest, - Product, - PutBack, - Batching, - MapInto, - MapResults, - Merge, - MergeBy, - TakeWhileRef, - WhileSome, - Coalesce, - TupleCombinations, - Positions, - Update, - }; - #[allow(deprecated)] - pub use adaptors::Step; - #[cfg(feature = "use_std")] - pub use adaptors::MultiProduct; - #[cfg(feature = "use_std")] - pub use combinations::Combinations; - #[cfg(feature = "use_std")] - pub use combinations_with_replacement::CombinationsWithReplacement; - pub use cons_tuples_impl::ConsTuples; - pub use exactly_one_err::ExactlyOneError; - pub use format::{Format, FormatWith}; - #[cfg(feature = "use_std")] - pub use groupbylazy::{IntoChunks, Chunk, Chunks, GroupBy, Group, Groups}; - pub use intersperse::Intersperse; - #[cfg(feature = "use_std")] - pub use kmerge_impl::{KMerge, KMergeBy}; - pub use merge_join::MergeJoinBy; - #[cfg(feature = "use_std")] - pub use multipeek_impl::MultiPeek; - pub use pad_tail::PadUsing; - pub use peeking_take_while::PeekingTakeWhile; - #[cfg(feature = "use_std")] - pub use permutations::Permutations; - pub use process_results_impl::ProcessResults; - #[cfg(feature = "use_std")] - pub use put_back_n_impl::PutBackN; - #[cfg(feature = "use_std")] - pub use rciter_impl::RcIter; - pub use repeatn::RepeatN; - #[allow(deprecated)] - pub use sources::{RepeatCall, Unfold, Iterate}; - #[cfg(feature = "use_std")] - pub use tee::Tee; - pub use tuple_impl::{TupleBuffer, TupleWindows, Tuples}; - #[cfg(feature = "use_std")] - pub use unique_impl::{Unique, UniqueBy}; - pub use with_position::WithPosition; - pub use zip_eq_impl::ZipEq; - pub use zip_longest::ZipLongest; - pub use ziptuple::Zip; -} -#[allow(deprecated)] -pub use structs::*; -pub use concat_impl::concat; -pub use cons_tuples_impl::cons_tuples; -pub use diff::diff_with; -pub use diff::Diff; -#[cfg(feature = "use_std")] -pub use kmerge_impl::{kmerge_by}; -pub use minmax::MinMaxResult; -pub use peeking_take_while::PeekingNext; -pub use process_results_impl::process_results; -pub use repeatn::repeat_n; -#[allow(deprecated)] -pub use sources::{repeat_call, unfold, iterate}; -pub use with_position::Position; -pub use ziptuple::multizip; -mod adaptors; -mod either_or_both; -pub use either_or_both::EitherOrBoth; -#[doc(hidden)] -pub mod free; -#[doc(inline)] -pub use free::*; -mod concat_impl; -mod cons_tuples_impl; -#[cfg(feature = "use_std")] -mod combinations; -#[cfg(feature = "use_std")] -mod combinations_with_replacement; -mod exactly_one_err; -mod diff; -mod format; -#[cfg(feature = "use_std")] -mod group_map; -#[cfg(feature = "use_std")] -mod groupbylazy; -mod intersperse; -#[cfg(feature = "use_std")] -mod kmerge_impl; -#[cfg(feature = "use_std")] -mod lazy_buffer; -mod merge_join; -mod minmax; -#[cfg(feature = "use_std")] -mod multipeek_impl; -mod pad_tail; -mod peeking_take_while; -#[cfg(feature = "use_std")] -mod permutations; -mod process_results_impl; -#[cfg(feature = "use_std")] -mod put_back_n_impl; -#[cfg(feature = "use_std")] -mod rciter_impl; -mod repeatn; -mod size_hint; -mod sources; -#[cfg(feature = "use_std")] -mod tee; -mod tuple_impl; -#[cfg(feature = "use_std")] -mod unique_impl; -mod with_position; -mod zip_eq_impl; -mod zip_longest; -mod ziptuple; - -#[macro_export] -/// Create an iterator over the “cartesian product” of iterators. -/// -/// Iterator element type is like `(A, B, ..., E)` if formed -/// from iterators `(I, J, ..., M)` with element types `I::Item = A`, `J::Item = B`, etc. -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { -/// // Iterate over the coordinates of a 4 x 4 x 4 grid -/// // from (0, 0, 0), (0, 0, 1), .., (0, 1, 0), (0, 1, 1), .. etc until (3, 3, 3) -/// for (i, j, k) in iproduct!(0..4, 0..4, 0..4) { -/// // .. -/// } -/// # } -/// ``` -/// -/// **Note:** To enable the macros in this crate, use the `#[macro_use]` -/// attribute when importing the crate: -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { } -/// ``` -macro_rules! iproduct { - (@flatten $I:expr,) => ( - $I - ); - (@flatten $I:expr, $J:expr, $($K:expr,)*) => ( - iproduct!(@flatten $crate::cons_tuples(iproduct!($I, $J)), $($K,)*) - ); - ($I:expr) => ( - $crate::__std_iter::IntoIterator::into_iter($I) - ); - ($I:expr, $J:expr) => ( - $crate::Itertools::cartesian_product(iproduct!($I), iproduct!($J)) - ); - ($I:expr, $J:expr, $($K:expr),+) => ( - iproduct!(@flatten iproduct!($I, $J), $($K,)+) - ); -} - -#[macro_export] -/// Create an iterator running multiple iterators in lockstep. -/// -/// The `izip!` iterator yields elements until any subiterator -/// returns `None`. -/// -/// This is a version of the standard ``.zip()`` that's supporting more than -/// two iterators. The iterator element type is a tuple with one element -/// from each of the input iterators. Just like ``.zip()``, the iteration stops -/// when the shortest of the inputs reaches its end. -/// -/// **Note:** The result of this macro is in the general case an iterator -/// composed of repeated `.zip()` and a `.map()`; it has an anonymous type. -/// The special cases of one and two arguments produce the equivalent of -/// `$a.into_iter()` and `$a.into_iter().zip($b)` respectively. -/// -/// Prefer this macro `izip!()` over [`multizip`] for the performance benefits -/// of using the standard library `.zip()`. -/// -/// [`multizip`]: fn.multizip.html -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { -/// -/// // iterate over three sequences side-by-side -/// let mut results = [0, 0, 0, 0]; -/// let inputs = [3, 7, 9, 6]; -/// -/// for (r, index, input) in izip!(&mut results, 0..10, &inputs) { -/// *r = index * 10 + input; -/// } -/// -/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); -/// # } -/// ``` -/// -/// **Note:** To enable the macros in this crate, use the `#[macro_use]` -/// attribute when importing the crate: -/// -/// ``` -/// #[macro_use] extern crate itertools; -/// # fn main() { } -/// ``` -macro_rules! izip { - // @closure creates a tuple-flattening closure for .map() call. usage: - // @closure partial_pattern => partial_tuple , rest , of , iterators - // eg. izip!( @closure ((a, b), c) => (a, b, c) , dd , ee ) - ( @closure $p:pat => $tup:expr ) => { - |$p| $tup - }; - - // The "b" identifier is a different identifier on each recursion level thanks to hygiene. - ( @closure $p:pat => ( $($tup:tt)* ) , $_iter:expr $( , $tail:expr )* ) => { - izip!(@closure ($p, b) => ( $($tup)*, b ) $( , $tail )*) - }; - - // unary - ($first:expr $(,)*) => { - $crate::__std_iter::IntoIterator::into_iter($first) - }; - - // binary - ($first:expr, $second:expr $(,)*) => { - izip!($first) - .zip($second) - }; - - // n-ary where n > 2 - ( $first:expr $( , $rest:expr )* $(,)* ) => { - izip!($first) - $( - .zip($rest) - )* - .map( - izip!(@closure a => (a) $( , $rest )*) - ) - }; -} - -/// An [`Iterator`] blanket implementation that provides extra adaptors and -/// methods. -/// -/// This trait defines a number of methods. They are divided into two groups: -/// -/// * *Adaptors* take an iterator and parameter as input, and return -/// a new iterator value. These are listed first in the trait. An example -/// of an adaptor is [`.interleave()`](#method.interleave) -/// -/// * *Regular methods* are those that don't return iterators and instead -/// return a regular value of some other kind. -/// [`.next_tuple()`](#method.next_tuple) is an example and the first regular -/// method in the list. -/// -/// [`Iterator`]: https://doc.rust-lang.org/std/iter/trait.Iterator.html -pub trait Itertools : Iterator { - // adaptors - - /// Alternate elements from two iterators until both have run out. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..7).interleave(vec![-1, -2]); - /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3, 4, 5, 6]); - /// ``` - fn interleave(self, other: J) -> Interleave - where J: IntoIterator, - Self: Sized - { - interleave(self, other) - } - - /// Alternate elements from two iterators until at least one of them has run - /// out. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..7).interleave_shortest(vec![-1, -2]); - /// itertools::assert_equal(it, vec![1, -1, 2, -2, 3]); - /// ``` - fn interleave_shortest(self, other: J) -> InterleaveShortest - where J: IntoIterator, - Self: Sized - { - adaptors::interleave_shortest(self, other.into_iter()) - } - - /// An iterator adaptor to insert a particular value - /// between each element of the adapted iterator. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// itertools::assert_equal((0..3).intersperse(8), vec![0, 8, 1, 8, 2]); - /// ``` - fn intersperse(self, element: Self::Item) -> Intersperse - where Self: Sized, - Self::Item: Clone - { - intersperse::intersperse(self, element) - } - - /// Create an iterator which iterates over both this and the specified - /// iterator simultaneously, yielding pairs of two optional elements. - /// - /// This iterator is *fused*. - /// - /// As long as neither input iterator is exhausted yet, it yields two values - /// via `EitherOrBoth::Both`. - /// - /// When the parameter iterator is exhausted, it only yields a value from the - /// `self` iterator via `EitherOrBoth::Left`. - /// - /// When the `self` iterator is exhausted, it only yields a value from the - /// parameter iterator via `EitherOrBoth::Right`. - /// - /// When both iterators return `None`, all further invocations of `.next()` - /// will return `None`. - /// - /// Iterator element type is - /// [`EitherOrBoth`](enum.EitherOrBoth.html). - /// - /// ```rust - /// use itertools::EitherOrBoth::{Both, Right}; - /// use itertools::Itertools; - /// let it = (0..1).zip_longest(1..3); - /// itertools::assert_equal(it, vec![Both(0, 1), Right(2)]); - /// ``` - #[inline] - fn zip_longest(self, other: J) -> ZipLongest - where J: IntoIterator, - Self: Sized - { - zip_longest::zip_longest(self, other.into_iter()) - } - - /// Create an iterator which iterates over both this and the specified - /// iterator simultaneously, yielding pairs of elements. - /// - /// **Panics** if the iterators reach an end and they are not of equal - /// lengths. - #[inline] - fn zip_eq(self, other: J) -> ZipEq - where J: IntoIterator, - Self: Sized - { - zip_eq(self, other) - } - - /// A “meta iterator adaptor”. Its closure receives a reference to the - /// iterator and may pick off as many elements as it likes, to produce the - /// next iterator element. - /// - /// Iterator element type is `B`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // An adaptor that gathers elements in pairs - /// let pit = (0..4).batching(|it| { - /// match it.next() { - /// None => None, - /// Some(x) => match it.next() { - /// None => None, - /// Some(y) => Some((x, y)), - /// } - /// } - /// }); - /// - /// itertools::assert_equal(pit, vec![(0, 1), (2, 3)]); - /// ``` - /// - fn batching(self, f: F) -> Batching - where F: FnMut(&mut Self) -> Option, - Self: Sized - { - adaptors::batching(self, f) - } - - /// Return an *iterable* that can group iterator elements. - /// Consecutive elements that map to the same key (“runs”), are assigned - /// to the same group. - /// - /// `GroupBy` is the storage for the lazy grouping operation. - /// - /// If the groups are consumed in order, or if each group's iterator is - /// dropped without keeping it around, then `GroupBy` uses no - /// allocations. It needs allocations only if several group iterators - /// are alive at the same time. - /// - /// This type implements `IntoIterator` (it is **not** an iterator - /// itself), because the group iterators need to borrow from this - /// value. It should be stored in a local variable or temporary and - /// iterated. - /// - /// Iterator element type is `(K, Group)`: the group's key and the - /// group iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // group data into runs of larger than zero or not. - /// let data = vec![1, 3, -2, -2, 1, 0, 1, 2]; - /// // groups: |---->|------>|--------->| - /// - /// // Note: The `&` is significant here, `GroupBy` is iterable - /// // only by reference. You can also call `.into_iter()` explicitly. - /// for (key, group) in &data.into_iter().group_by(|elt| *elt >= 0) { - /// // Check that the sum of each group is +/- 4. - /// assert_eq!(4, group.sum::().abs()); - /// } - /// ``` - #[cfg(feature = "use_std")] - fn group_by(self, key: F) -> GroupBy - where Self: Sized, - F: FnMut(&Self::Item) -> K, - K: PartialEq, - { - groupbylazy::new(self, key) - } - - /// Return an *iterable* that can chunk the iterator. - /// - /// Yield subiterators (chunks) that each yield a fixed number elements, - /// determined by `size`. The last chunk will be shorter if there aren't - /// enough elements. - /// - /// `IntoChunks` is based on `GroupBy`: it is iterable (implements - /// `IntoIterator`, **not** `Iterator`), and it only buffers if several - /// chunk iterators are alive at the same time. - /// - /// Iterator element type is `Chunk`, each chunk's iterator. - /// - /// **Panics** if `size` is 0. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1, 1, 2, -2, 6, 0, 3, 1]; - /// //chunk size=3 |------->|-------->|--->| - /// - /// // Note: The `&` is significant here, `IntoChunks` is iterable - /// // only by reference. You can also call `.into_iter()` explicitly. - /// for chunk in &data.into_iter().chunks(3) { - /// // Check that the sum of each chunk is 4. - /// assert_eq!(4, chunk.sum()); - /// } - /// ``` - #[cfg(feature = "use_std")] - fn chunks(self, size: usize) -> IntoChunks - where Self: Sized, - { - assert!(size != 0); - groupbylazy::new_chunks(self, size) - } - - /// Return an iterator over all contiguous windows producing tuples of - /// a specific size (up to 4). - /// - /// `tuple_windows` clones the iterator elements so that they can be - /// part of successive windows, this makes it most suited for iterators - /// of references and other values that are cheap to copy. - /// - /// ``` - /// use itertools::Itertools; - /// let mut v = Vec::new(); - /// for (a, b) in (1..5).tuple_windows() { - /// v.push((a, b)); - /// } - /// assert_eq!(v, vec![(1, 2), (2, 3), (3, 4)]); - /// - /// let mut it = (1..5).tuple_windows(); - /// assert_eq!(Some((1, 2, 3)), it.next()); - /// assert_eq!(Some((2, 3, 4)), it.next()); - /// assert_eq!(None, it.next()); - /// - /// // this requires a type hint - /// let it = (1..5).tuple_windows::<(_, _, _)>(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]); - /// - /// // you can also specify the complete type - /// use itertools::TupleWindows; - /// use std::ops::Range; - /// - /// let it: TupleWindows, (u32, u32, u32)> = (1..5).tuple_windows(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (2, 3, 4)]); - /// ``` - fn tuple_windows(self) -> TupleWindows - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect, - T::Item: Clone - { - tuple_impl::tuple_windows(self) - } - - /// Return an iterator that groups the items in tuples of a specific size - /// (up to 4). - /// - /// See also the method [`.next_tuple()`](#method.next_tuple). - /// - /// ``` - /// use itertools::Itertools; - /// let mut v = Vec::new(); - /// for (a, b) in (1..5).tuples() { - /// v.push((a, b)); - /// } - /// assert_eq!(v, vec![(1, 2), (3, 4)]); - /// - /// let mut it = (1..7).tuples(); - /// assert_eq!(Some((1, 2, 3)), it.next()); - /// assert_eq!(Some((4, 5, 6)), it.next()); - /// assert_eq!(None, it.next()); - /// - /// // this requires a type hint - /// let it = (1..7).tuples::<(_, _, _)>(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]); - /// - /// // you can also specify the complete type - /// use itertools::Tuples; - /// use std::ops::Range; - /// - /// let it: Tuples, (u32, u32, u32)> = (1..7).tuples(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (4, 5, 6)]); - /// ``` - /// - /// See also [`Tuples::into_buffer`](structs/struct.Tuples.html#method.into_buffer). - fn tuples(self) -> Tuples - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect - { - tuple_impl::tuples(self) - } - - /// Split into an iterator pair that both yield all elements from - /// the original iterator. - /// - /// **Note:** If the iterator is clonable, prefer using that instead - /// of using this method. It is likely to be more efficient. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// let xs = vec![0, 1, 2, 3]; - /// - /// let (mut t1, t2) = xs.into_iter().tee(); - /// itertools::assert_equal(t1.next(), Some(0)); - /// itertools::assert_equal(t2, 0..4); - /// itertools::assert_equal(t1, 1..4); - /// ``` - #[cfg(feature = "use_std")] - fn tee(self) -> (Tee, Tee) - where Self: Sized, - Self::Item: Clone - { - tee::new(self) - } - - /// Return an iterator adaptor that steps `n` elements in the base iterator - /// for each iteration. - /// - /// The iterator steps by yielding the next element from the base iterator, - /// then skipping forward `n - 1` elements. - /// - /// Iterator element type is `Self::Item`. - /// - /// **Panics** if the step is 0. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (0..8).step(3); - /// itertools::assert_equal(it, vec![0, 3, 6]); - /// ``` - #[deprecated(note="Use std .step_by() instead", since="0.8")] - #[allow(deprecated)] - fn step(self, n: usize) -> Step - where Self: Sized - { - adaptors::step(self, n) - } - - /// Convert each item of the iterator using the `Into` trait. - /// - /// ```rust - /// use itertools::Itertools; - /// - /// (1i32..42i32).map_into::().collect_vec(); - /// ``` - fn map_into(self) -> MapInto - where Self: Sized, - Self::Item: Into, - { - adaptors::map_into(self) - } - - /// Return an iterator adaptor that applies the provided closure - /// to every `Result::Ok` value. `Result::Err` values are - /// unchanged. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let input = vec![Ok(41), Err(false), Ok(11)]; - /// let it = input.into_iter().map_results(|i| i + 1); - /// itertools::assert_equal(it, vec![Ok(42), Err(false), Ok(12)]); - /// ``` - fn map_results(self, f: F) -> MapResults - where Self: Iterator> + Sized, - F: FnMut(T) -> U, - { - adaptors::map_results(self, f) - } - - /// Return an iterator adaptor that merges the two base iterators in - /// ascending order. If both base iterators are sorted (ascending), the - /// result is sorted. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = (0..11).step(3); - /// let b = (0..11).step(5); - /// let it = a.merge(b); - /// itertools::assert_equal(it, vec![0, 0, 3, 5, 6, 9, 10]); - /// ``` - fn merge(self, other: J) -> Merge - where Self: Sized, - Self::Item: PartialOrd, - J: IntoIterator - { - merge(self, other) - } - - /// Return an iterator adaptor that merges the two base iterators in order. - /// This is much like `.merge()` but allows for a custom ordering. - /// - /// This can be especially useful for sequences of tuples. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = (0..).zip("bc".chars()); - /// let b = (0..).zip("ad".chars()); - /// let it = a.merge_by(b, |x, y| x.1 <= y.1); - /// itertools::assert_equal(it, vec![(0, 'a'), (0, 'b'), (1, 'c'), (1, 'd')]); - /// ``` - - fn merge_by(self, other: J, is_first: F) -> MergeBy - where Self: Sized, - J: IntoIterator, - F: FnMut(&Self::Item, &Self::Item) -> bool - { - adaptors::merge_by_new(self, other.into_iter(), is_first) - } - - /// Create an iterator that merges items from both this and the specified - /// iterator in ascending order. - /// - /// It chooses whether to pair elements based on the `Ordering` returned by the - /// specified compare function. At any point, inspecting the tip of the - /// iterators `I` and `J` as items `i` of type `I::Item` and `j` of type - /// `J::Item` respectively, the resulting iterator will: - /// - /// - Emit `EitherOrBoth::Left(i)` when `i < j`, - /// and remove `i` from its source iterator - /// - Emit `EitherOrBoth::Right(j)` when `i > j`, - /// and remove `j` from its source iterator - /// - Emit `EitherOrBoth::Both(i, j)` when `i == j`, - /// and remove both `i` and `j` from their respective source iterators - /// - /// ``` - /// use itertools::Itertools; - /// use itertools::EitherOrBoth::{Left, Right, Both}; - /// - /// let ki = (0..10).step(3); - /// let ku = (0..10).step(5); - /// let ki_ku = ki.merge_join_by(ku, |i, j| i.cmp(j)).map(|either| { - /// match either { - /// Left(_) => "Ki", - /// Right(_) => "Ku", - /// Both(_, _) => "KiKu" - /// } - /// }); - /// - /// itertools::assert_equal(ki_ku, vec!["KiKu", "Ki", "Ku", "Ki", "Ki"]); - /// ``` - #[inline] - fn merge_join_by(self, other: J, cmp_fn: F) -> MergeJoinBy - where J: IntoIterator, - F: FnMut(&Self::Item, &J::Item) -> std::cmp::Ordering, - Self: Sized - { - merge_join_by(self, other, cmp_fn) - } - - - /// Return an iterator adaptor that flattens an iterator of iterators by - /// merging them in ascending order. - /// - /// If all base iterators are sorted (ascending), the result is sorted. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = (0..6).step(3); - /// let b = (1..6).step(3); - /// let c = (2..6).step(3); - /// let it = vec![a, b, c].into_iter().kmerge(); - /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5]); - /// ``` - #[cfg(feature = "use_std")] - fn kmerge(self) -> KMerge<::IntoIter> - where Self: Sized, - Self::Item: IntoIterator, - ::Item: PartialOrd, - { - kmerge(self) - } - - /// Return an iterator adaptor that flattens an iterator of iterators by - /// merging them according to the given closure. - /// - /// The closure `first` is called with two elements *a*, *b* and should - /// return `true` if *a* is ordered before *b*. - /// - /// If all base iterators are sorted according to `first`, the result is - /// sorted. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let a = vec![-1f64, 2., 3., -5., 6., -7.]; - /// let b = vec![0., 2., -4.]; - /// let mut it = vec![a, b].into_iter().kmerge_by(|a, b| a.abs() < b.abs()); - /// assert_eq!(it.next(), Some(0.)); - /// assert_eq!(it.last(), Some(-7.)); - /// ``` - #[cfg(feature = "use_std")] - fn kmerge_by(self, first: F) - -> KMergeBy<::IntoIter, F> - where Self: Sized, - Self::Item: IntoIterator, - F: FnMut(&::Item, - &::Item) -> bool - { - kmerge_by(self, first) - } - - /// Return an iterator adaptor that iterates over the cartesian product of - /// the element sets of two iterators `self` and `J`. - /// - /// Iterator element type is `(Self::Item, J::Item)`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (0..2).cartesian_product("αβ".chars()); - /// itertools::assert_equal(it, vec![(0, 'α'), (0, 'β'), (1, 'α'), (1, 'β')]); - /// ``` - fn cartesian_product(self, other: J) -> Product - where Self: Sized, - Self::Item: Clone, - J: IntoIterator, - J::IntoIter: Clone - { - adaptors::cartesian_product(self, other.into_iter()) - } - - /// Return an iterator adaptor that iterates over the cartesian product of - /// all subiterators returned by meta-iterator `self`. - /// - /// All provided iterators must yield the same `Item` type. To generate - /// the product of iterators yielding multiple types, use the - /// [`iproduct`](macro.iproduct.html) macro instead. - /// - /// - /// The iterator element type is `Vec`, where `T` is the iterator element - /// of the subiterators. - /// - /// ``` - /// use itertools::Itertools; - /// let mut multi_prod = (0..3).map(|i| (i * 2)..(i * 2 + 2)) - /// .multi_cartesian_product(); - /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![0, 2, 5])); - /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![0, 3, 5])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 2, 5])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 4])); - /// assert_eq!(multi_prod.next(), Some(vec![1, 3, 5])); - /// assert_eq!(multi_prod.next(), None); - /// ``` - #[cfg(feature = "use_std")] - fn multi_cartesian_product(self) -> MultiProduct<::IntoIter> - where Self: Iterator + Sized, - Self::Item: IntoIterator, - ::IntoIter: Clone, - ::Item: Clone - { - adaptors::multi_cartesian_product(self) - } - - /// Return an iterator adaptor that uses the passed-in closure to - /// optionally merge together consecutive elements. - /// - /// The closure `f` is passed two elements, `previous` and `current` and may - /// return either (1) `Ok(combined)` to merge the two values or - /// (2) `Err((previous', current'))` to indicate they can't be merged. - /// In (2), the value `previous'` is emitted by the iterator. - /// Either (1) `combined` or (2) `current'` becomes the previous value - /// when coalesce continues with the next pair of elements to merge. The - /// value that remains at the end is also emitted by the iterator. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sum same-sign runs together - /// let data = vec![-1., -2., -3., 3., 1., 0., -1.]; - /// itertools::assert_equal(data.into_iter().coalesce(|x, y| - /// if (x >= 0.) == (y >= 0.) { - /// Ok(x + y) - /// } else { - /// Err((x, y)) - /// }), - /// vec![-6., 4., -1.]); - /// ``` - fn coalesce(self, f: F) -> Coalesce - where Self: Sized, - F: FnMut(Self::Item, Self::Item) - -> Result - { - adaptors::coalesce(self, f) - } - - /// Remove duplicates from sections of consecutive identical elements. - /// If the iterator is sorted, all elements will be unique. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1., 1., 2., 3., 3., 2., 2.]; - /// itertools::assert_equal(data.into_iter().dedup(), - /// vec![1., 2., 3., 2.]); - /// ``` - fn dedup(self) -> Dedup - where Self: Sized, - Self::Item: PartialEq, - { - adaptors::dedup(self) - } - - /// Remove duplicates from sections of consecutive identical elements, - /// determining equality using a comparison function. - /// If the iterator is sorted, all elements will be unique. - /// - /// Iterator element type is `Self::Item`. - /// - /// This iterator is *fused*. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![(0, 1.), (1, 1.), (0, 2.), (0, 3.), (1, 3.), (1, 2.), (2, 2.)]; - /// itertools::assert_equal(data.into_iter().dedup_by(|x, y| x.1==y.1), - /// vec![(0, 1.), (0, 2.), (0, 3.), (1, 2.)]); - /// ``` - fn dedup_by(self, cmp: Cmp) -> DedupBy - where Self: Sized, - Cmp: FnMut(&Self::Item, &Self::Item)->bool, - { - adaptors::dedup_by(self, cmp) - } - - /// Return an iterator adaptor that filters out elements that have - /// already been produced once during the iteration. Duplicates - /// are detected using hash and equality. - /// - /// Clones of visited elements are stored in a hash set in the - /// iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![10, 20, 30, 20, 40, 10, 50]; - /// itertools::assert_equal(data.into_iter().unique(), - /// vec![10, 20, 30, 40, 50]); - /// ``` - #[cfg(feature = "use_std")] - fn unique(self) -> Unique - where Self: Sized, - Self::Item: Clone + Eq + Hash - { - unique_impl::unique(self) - } - - /// Return an iterator adaptor that filters out elements that have - /// already been produced once during the iteration. - /// - /// Duplicates are detected by comparing the key they map to - /// with the keying function `f` by hash and equality. - /// The keys are stored in a hash set in the iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec!["a", "bb", "aa", "c", "ccc"]; - /// itertools::assert_equal(data.into_iter().unique_by(|s| s.len()), - /// vec!["a", "bb", "ccc"]); - /// ``` - #[cfg(feature = "use_std")] - fn unique_by(self, f: F) -> UniqueBy - where Self: Sized, - V: Eq + Hash, - F: FnMut(&Self::Item) -> V - { - unique_impl::unique_by(self, f) - } - - /// Return an iterator adaptor that borrows from this iterator and - /// takes items while the closure `accept` returns `true`. - /// - /// This adaptor can only be used on iterators that implement `PeekingNext` - /// like `.peekable()`, `put_back` and a few other collection iterators. - /// - /// The last and rejected element (first `false`) is still available when - /// `peeking_take_while` is done. - /// - /// - /// See also [`.take_while_ref()`](#method.take_while_ref) - /// which is a similar adaptor. - fn peeking_take_while(&mut self, accept: F) -> PeekingTakeWhile - where Self: Sized + PeekingNext, - F: FnMut(&Self::Item) -> bool, - { - peeking_take_while::peeking_take_while(self, accept) - } - - /// Return an iterator adaptor that borrows from a `Clone`-able iterator - /// to only pick off elements while the predicate `accept` returns `true`. - /// - /// It uses the `Clone` trait to restore the original iterator so that the - /// last and rejected element (first `false`) is still available when - /// `take_while_ref` is done. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut hexadecimals = "0123456789abcdef".chars(); - /// - /// let decimals = hexadecimals.take_while_ref(|c| c.is_numeric()) - /// .collect::(); - /// assert_eq!(decimals, "0123456789"); - /// assert_eq!(hexadecimals.next(), Some('a')); - /// - /// ``` - fn take_while_ref(&mut self, accept: F) -> TakeWhileRef - where Self: Clone, - F: FnMut(&Self::Item) -> bool - { - adaptors::take_while_ref(self, accept) - } - - /// Return an iterator adaptor that filters `Option` iterator elements - /// and produces `A`. Stops on the first `None` encountered. - /// - /// Iterator element type is `A`, the unwrapped element. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // List all hexadecimal digits - /// itertools::assert_equal( - /// (0..).map(|i| std::char::from_digit(i, 16)).while_some(), - /// "0123456789abcdef".chars()); - /// - /// ``` - fn while_some(self) -> WhileSome - where Self: Sized + Iterator> - { - adaptors::while_some(self) - } - - /// Return an iterator adaptor that iterates over the combinations of the - /// elements from an iterator. - /// - /// Iterator element can be any homogeneous tuple of type `Self::Item` with - /// size up to 4. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut v = Vec::new(); - /// for (a, b) in (1..5).tuple_combinations() { - /// v.push((a, b)); - /// } - /// assert_eq!(v, vec![(1, 2), (1, 3), (1, 4), (2, 3), (2, 4), (3, 4)]); - /// - /// let mut it = (1..5).tuple_combinations(); - /// assert_eq!(Some((1, 2, 3)), it.next()); - /// assert_eq!(Some((1, 2, 4)), it.next()); - /// assert_eq!(Some((1, 3, 4)), it.next()); - /// assert_eq!(Some((2, 3, 4)), it.next()); - /// assert_eq!(None, it.next()); - /// - /// // this requires a type hint - /// let it = (1..5).tuple_combinations::<(_, _, _)>(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]); - /// - /// // you can also specify the complete type - /// use itertools::TupleCombinations; - /// use std::ops::Range; - /// - /// let it: TupleCombinations, (u32, u32, u32)> = (1..5).tuple_combinations(); - /// itertools::assert_equal(it, vec![(1, 2, 3), (1, 2, 4), (1, 3, 4), (2, 3, 4)]); - /// ``` - fn tuple_combinations(self) -> TupleCombinations - where Self: Sized + Clone, - Self::Item: Clone, - T: adaptors::HasCombination, - { - adaptors::tuple_combinations(self) - } - - /// Return an iterator adaptor that iterates over the `k`-length combinations of - /// the elements from an iterator. - /// - /// Iterator element type is `Vec`. The iterator produces a new Vec per iteration, - /// and clones the iterator elements. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..5).combinations(3); - /// itertools::assert_equal(it, vec![ - /// vec![1, 2, 3], - /// vec![1, 2, 4], - /// vec![1, 3, 4], - /// vec![2, 3, 4], - /// ]); - /// ``` - /// - /// Note: Combinations does not take into account the equality of the iterated values. - /// ``` - /// use itertools::Itertools; - /// - /// let it = vec![1, 2, 2].into_iter().combinations(2); - /// itertools::assert_equal(it, vec![ - /// vec![1, 2], // Note: these are the same - /// vec![1, 2], // Note: these are the same - /// vec![2, 2], - /// ]); - /// ``` - #[cfg(feature = "use_std")] - fn combinations(self, k: usize) -> Combinations - where Self: Sized, - Self::Item: Clone - { - combinations::combinations(self, k) - } - - /// Return an iterator that iterates over the `k`-length combinations of - /// the elements from an iterator, with replacement. - /// - /// Iterator element type is `Vec`. The iterator produces a new Vec per iteration, - /// and clones the iterator elements. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (1..4).combinations_with_replacement(2); - /// itertools::assert_equal(it, vec![ - /// vec![1, 1], - /// vec![1, 2], - /// vec![1, 3], - /// vec![2, 2], - /// vec![2, 3], - /// vec![3, 3], - /// ]); - /// ``` - #[cfg(feature = "use_std")] - fn combinations_with_replacement(self, k: usize) -> CombinationsWithReplacement - where - Self: Sized, - Self::Item: Clone, - { - combinations_with_replacement::combinations_with_replacement(self, k) - } - - /// Return an iterator adaptor that iterates over all k-permutations of the - /// elements from an iterator. - /// - /// Iterator element type is `Vec` with length `k`. The iterator - /// produces a new Vec per iteration, and clones the iterator elements. - /// - /// If `k` is greater than the length of the input iterator, the resultant - /// iterator adaptor will be empty. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let perms = (5..8).permutations(2); - /// itertools::assert_equal(perms, vec![ - /// vec![5, 6], - /// vec![5, 7], - /// vec![6, 5], - /// vec![6, 7], - /// vec![7, 5], - /// vec![7, 6], - /// ]); - /// ``` - /// - /// Note: Permutations does not take into account the equality of the iterated values. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = vec![2, 2].into_iter().permutations(2); - /// itertools::assert_equal(it, vec![ - /// vec![2, 2], // Note: these are the same - /// vec![2, 2], // Note: these are the same - /// ]); - /// ``` - /// - /// Note: The source iterator is collected lazily, and will not be - /// re-iterated if the permutations adaptor is completed and re-iterated. - #[cfg(feature = "use_std")] - fn permutations(self, k: usize) -> Permutations - where Self: Sized, - Self::Item: Clone - { - permutations::permutations(self, k) - } - - /// Return an iterator adaptor that pads the sequence to a minimum length of - /// `min` by filling missing elements using a closure `f`. - /// - /// Iterator element type is `Self::Item`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let it = (0..5).pad_using(10, |i| 2*i); - /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 10, 12, 14, 16, 18]); - /// - /// let it = (0..10).pad_using(5, |i| 2*i); - /// itertools::assert_equal(it, vec![0, 1, 2, 3, 4, 5, 6, 7, 8, 9]); - /// - /// let it = (0..5).pad_using(10, |i| 2*i).rev(); - /// itertools::assert_equal(it, vec![18, 16, 14, 12, 10, 4, 3, 2, 1, 0]); - /// ``` - fn pad_using(self, min: usize, f: F) -> PadUsing - where Self: Sized, - F: FnMut(usize) -> Self::Item - { - pad_tail::pad_using(self, min, f) - } - - /// Return an iterator adaptor that wraps each element in a `Position` to - /// ease special-case handling of the first or last elements. - /// - /// Iterator element type is - /// [`Position`](enum.Position.html) - /// - /// ``` - /// use itertools::{Itertools, Position}; - /// - /// let it = (0..4).with_position(); - /// itertools::assert_equal(it, - /// vec![Position::First(0), - /// Position::Middle(1), - /// Position::Middle(2), - /// Position::Last(3)]); - /// - /// let it = (0..1).with_position(); - /// itertools::assert_equal(it, vec![Position::Only(0)]); - /// ``` - fn with_position(self) -> WithPosition - where Self: Sized, - { - with_position::with_position(self) - } - - /// Return an iterator adaptor that yields the indices of all elements - /// satisfying a predicate, counted from the start of the iterator. - /// - /// Equivalent to `iter.enumerate().filter(|(_, v)| predicate(v)).map(|(i, _)| i)`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1, 2, 3, 3, 4, 6, 7, 9]; - /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 0), vec![1, 4, 5]); - /// - /// itertools::assert_equal(data.iter().positions(|v| v % 2 == 1).rev(), vec![7, 6, 3, 2, 0]); - /// ``` - fn positions

    (self, predicate: P) -> Positions - where Self: Sized, - P: FnMut(Self::Item) -> bool, - { - adaptors::positions(self, predicate) - } - - /// Return an iterator adaptor that applies a mutating function - /// to each element before yielding it. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let input = vec![vec![1], vec![3, 2, 1]]; - /// let it = input.into_iter().update(|mut v| v.push(0)); - /// itertools::assert_equal(it, vec![vec![1, 0], vec![3, 2, 1, 0]]); - /// ``` - fn update(self, updater: F) -> Update - where Self: Sized, - F: FnMut(&mut Self::Item), - { - adaptors::update(self, updater) - } - - // non-adaptor methods - /// Advances the iterator and returns the next items grouped in a tuple of - /// a specific size (up to 4). - /// - /// If there are enough elements to be grouped in a tuple, then the tuple is - /// returned inside `Some`, otherwise `None` is returned. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut iter = 1..5; - /// - /// assert_eq!(Some((1, 2)), iter.next_tuple()); - /// ``` - fn next_tuple(&mut self) -> Option - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect - { - T::collect_from_iter_no_buf(self) - } - - /// Collects all items from the iterator into a tuple of a specific size - /// (up to 4). - /// - /// If the number of elements inside the iterator is **exactly** equal to - /// the tuple size, then the tuple is returned inside `Some`, otherwise - /// `None` is returned. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let iter = 1..3; - /// - /// if let Some((x, y)) = iter.collect_tuple() { - /// assert_eq!((x, y), (1, 2)) - /// } else { - /// panic!("Expected two elements") - /// } - /// ``` - fn collect_tuple(mut self) -> Option - where Self: Sized + Iterator, - T: tuple_impl::TupleCollect - { - match self.next_tuple() { - elt @ Some(_) => match self.next() { - Some(_) => None, - None => elt, - }, - _ => None - } - } - - - /// Find the position and value of the first element satisfying a predicate. - /// - /// The iterator is not advanced past the first element found. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let text = "Hα"; - /// assert_eq!(text.chars().find_position(|ch| ch.is_lowercase()), Some((1, 'α'))); - /// ``` - fn find_position

    (&mut self, mut pred: P) -> Option<(usize, Self::Item)> - where P: FnMut(&Self::Item) -> bool - { - let mut index = 0usize; - for elt in self { - if pred(&elt) { - return Some((index, elt)); - } - index += 1; - } - None - } - - /// Check whether all elements compare equal. - /// - /// Empty iterators are considered to have equal elements: - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![1, 1, 1, 2, 2, 3, 3, 3, 4, 5, 5]; - /// assert!(!data.iter().all_equal()); - /// assert!(data[0..3].iter().all_equal()); - /// assert!(data[3..5].iter().all_equal()); - /// assert!(data[5..8].iter().all_equal()); - /// - /// let data : Option = None; - /// assert!(data.into_iter().all_equal()); - /// ``` - fn all_equal(&mut self) -> bool - where Self: Sized, - Self::Item: PartialEq, - { - match self.next() { - None => true, - Some(a) => self.all(|x| a == x), - } - } - - /// Consume the first `n` elements from the iterator eagerly, - /// and return the same iterator again. - /// - /// It works similarly to *.skip(* `n` *)* except it is eager and - /// preserves the iterator type. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut iter = "αβγ".chars().dropping(2); - /// itertools::assert_equal(iter, "γ".chars()); - /// ``` - /// - /// *Fusing notes: if the iterator is exhausted by dropping, - /// the result of calling `.next()` again depends on the iterator implementation.* - fn dropping(mut self, n: usize) -> Self - where Self: Sized - { - if n > 0 { - self.nth(n - 1); - } - self - } - - /// Consume the last `n` elements from the iterator eagerly, - /// and return the same iterator again. - /// - /// This is only possible on double ended iterators. `n` may be - /// larger than the number of elements. - /// - /// Note: This method is eager, dropping the back elements immediately and - /// preserves the iterator type. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let init = vec![0, 3, 6, 9].into_iter().dropping_back(1); - /// itertools::assert_equal(init, vec![0, 3, 6]); - /// ``` - fn dropping_back(mut self, n: usize) -> Self - where Self: Sized, - Self: DoubleEndedIterator - { - if n > 0 { - (&mut self).rev().nth(n - 1); - } - self - } - - /// Run the closure `f` eagerly on each element of the iterator. - /// - /// Consumes the iterator until its end. - /// - /// ``` - /// use std::sync::mpsc::channel; - /// use itertools::Itertools; - /// - /// let (tx, rx) = channel(); - /// - /// // use .foreach() to apply a function to each value -- sending it - /// (0..5).map(|x| x * 2 + 1).foreach(|x| { tx.send(x).unwrap(); } ); - /// - /// drop(tx); - /// - /// itertools::assert_equal(rx.iter(), vec![1, 3, 5, 7, 9]); - /// ``` - #[deprecated(note="Use .for_each() instead", since="0.8")] - fn foreach(self, f: F) - where F: FnMut(Self::Item), - Self: Sized, - { - self.for_each(f) - } - - /// Combine all an iterator's elements into one element by using `Extend`. - /// - /// This combinator will extend the first item with each of the rest of the - /// items of the iterator. If the iterator is empty, the default value of - /// `I::Item` is returned. - /// - /// ```rust - /// use itertools::Itertools; - /// - /// let input = vec![vec![1], vec![2, 3], vec![4, 5, 6]]; - /// assert_eq!(input.into_iter().concat(), - /// vec![1, 2, 3, 4, 5, 6]); - /// ``` - fn concat(self) -> Self::Item - where Self: Sized, - Self::Item: Extend<<::Item as IntoIterator>::Item> + IntoIterator + Default - { - concat(self) - } - - /// `.collect_vec()` is simply a type specialization of `.collect()`, - /// for convenience. - #[cfg(feature = "use_std")] - fn collect_vec(self) -> Vec - where Self: Sized - { - self.collect() - } - - /// Assign to each reference in `self` from the `from` iterator, - /// stopping at the shortest of the two iterators. - /// - /// The `from` iterator is queried for its next element before the `self` - /// iterator, and if either is exhausted the method is done. - /// - /// Return the number of elements written. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut xs = [0; 4]; - /// xs.iter_mut().set_from(1..); - /// assert_eq!(xs, [1, 2, 3, 4]); - /// ``` - #[inline] - fn set_from<'a, A: 'a, J>(&mut self, from: J) -> usize - where Self: Iterator, - J: IntoIterator - { - let mut count = 0; - for elt in from { - match self.next() { - None => break, - Some(ptr) => *ptr = elt, - } - count += 1; - } - count - } - - /// Combine all iterator elements into one String, separated by `sep`. - /// - /// Use the `Display` implementation of each element. - /// - /// ``` - /// use itertools::Itertools; - /// - /// assert_eq!(["a", "b", "c"].iter().join(", "), "a, b, c"); - /// assert_eq!([1, 2, 3].iter().join(", "), "1, 2, 3"); - /// ``` - #[cfg(feature = "use_std")] - fn join(&mut self, sep: &str) -> String - where Self::Item: std::fmt::Display - { - match self.next() { - None => String::new(), - Some(first_elt) => { - // estimate lower bound of capacity needed - let (lower, _) = self.size_hint(); - let mut result = String::with_capacity(sep.len() * lower); - write!(&mut result, "{}", first_elt).unwrap(); - for elt in self { - result.push_str(sep); - write!(&mut result, "{}", elt).unwrap(); - } - result - } - } - } - - /// Format all iterator elements, separated by `sep`. - /// - /// All elements are formatted (any formatting trait) - /// with `sep` inserted between each element. - /// - /// **Panics** if the formatter helper is formatted more than once. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = [1.1, 2.71828, -3.]; - /// assert_eq!( - /// format!("{:.2}", data.iter().format(", ")), - /// "1.10, 2.72, -3.00"); - /// ``` - fn format(self, sep: &str) -> Format - where Self: Sized, - { - format::new_format_default(self, sep) - } - - /// Format all iterator elements, separated by `sep`. - /// - /// This is a customizable version of `.format()`. - /// - /// The supplied closure `format` is called once per iterator element, - /// with two arguments: the element and a callback that takes a - /// `&Display` value, i.e. any reference to type that implements `Display`. - /// - /// Using `&format_args!(...)` is the most versatile way to apply custom - /// element formatting. The callback can be called multiple times if needed. - /// - /// **Panics** if the formatter helper is formatted more than once. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = [1.1, 2.71828, -3.]; - /// let data_formatter = data.iter().format_with(", ", |elt, f| f(&format_args!("{:.2}", elt))); - /// assert_eq!(format!("{}", data_formatter), - /// "1.10, 2.72, -3.00"); - /// - /// // .format_with() is recursively composable - /// let matrix = [[1., 2., 3.], - /// [4., 5., 6.]]; - /// let matrix_formatter = matrix.iter().format_with("\n", |row, f| { - /// f(&row.iter().format_with(", ", |elt, g| g(&elt))) - /// }); - /// assert_eq!(format!("{}", matrix_formatter), - /// "1, 2, 3\n4, 5, 6"); - /// - /// - /// ``` - fn format_with(self, sep: &str, format: F) -> FormatWith - where Self: Sized, - F: FnMut(Self::Item, &mut FnMut(&fmt::Display) -> fmt::Result) -> fmt::Result, - { - format::new_format(self, sep, format) - } - - /// Fold `Result` values from an iterator. - /// - /// Only `Ok` values are folded. If no error is encountered, the folded - /// value is returned inside `Ok`. Otherwise, the operation terminates - /// and returns the first `Err` value it encounters. No iterator elements are - /// consumed after the first error. - /// - /// The first accumulator value is the `start` parameter. - /// Each iteration passes the accumulator value and the next value inside `Ok` - /// to the fold function `f` and its return value becomes the new accumulator value. - /// - /// For example the sequence *Ok(1), Ok(2), Ok(3)* will result in a - /// computation like this: - /// - /// ```ignore - /// let mut accum = start; - /// accum = f(accum, 1); - /// accum = f(accum, 2); - /// accum = f(accum, 3); - /// ``` - /// - /// With a `start` value of 0 and an addition as folding function, - /// this effectively results in *((0 + 1) + 2) + 3* - /// - /// ``` - /// use std::ops::Add; - /// use itertools::Itertools; - /// - /// let values = [1, 2, -2, -1, 2, 1]; - /// assert_eq!( - /// values.iter() - /// .map(Ok::<_, ()>) - /// .fold_results(0, Add::add), - /// Ok(3) - /// ); - /// assert!( - /// values.iter() - /// .map(|&x| if x >= 0 { Ok(x) } else { Err("Negative number") }) - /// .fold_results(0, Add::add) - /// .is_err() - /// ); - /// ``` - fn fold_results(&mut self, mut start: B, mut f: F) -> Result - where Self: Iterator>, - F: FnMut(B, A) -> B - { - for elt in self { - match elt { - Ok(v) => start = f(start, v), - Err(u) => return Err(u), - } - } - Ok(start) - } - - /// Fold `Option` values from an iterator. - /// - /// Only `Some` values are folded. If no `None` is encountered, the folded - /// value is returned inside `Some`. Otherwise, the operation terminates - /// and returns `None`. No iterator elements are consumed after the `None`. - /// - /// This is the `Option` equivalent to `fold_results`. - /// - /// ``` - /// use std::ops::Add; - /// use itertools::Itertools; - /// - /// let mut values = vec![Some(1), Some(2), Some(-2)].into_iter(); - /// assert_eq!(values.fold_options(5, Add::add), Some(5 + 1 + 2 - 2)); - /// - /// let mut more_values = vec![Some(2), None, Some(0)].into_iter(); - /// assert!(more_values.fold_options(0, Add::add).is_none()); - /// assert_eq!(more_values.next().unwrap(), Some(0)); - /// ``` - fn fold_options(&mut self, mut start: B, mut f: F) -> Option - where Self: Iterator>, - F: FnMut(B, A) -> B - { - for elt in self { - match elt { - Some(v) => start = f(start, v), - None => return None, - } - } - Some(start) - } - - /// Accumulator of the elements in the iterator. - /// - /// Like `.fold()`, without a base case. If the iterator is - /// empty, return `None`. With just one element, return it. - /// Otherwise elements are accumulated in sequence using the closure `f`. - /// - /// ``` - /// use itertools::Itertools; - /// - /// assert_eq!((0..10).fold1(|x, y| x + y).unwrap_or(0), 45); - /// assert_eq!((0..0).fold1(|x, y| x * y), None); - /// ``` - fn fold1(mut self, f: F) -> Option - where F: FnMut(Self::Item, Self::Item) -> Self::Item, - Self: Sized, - { - self.next().map(move |x| self.fold(x, f)) - } - - /// Accumulate the elements in the iterator in a tree-like manner. - /// - /// You can think of it as, while there's more than one item, repeatedly - /// combining adjacent items. It does so in bottom-up-merge-sort order, - /// however, so that it needs only logarithmic stack space. - /// - /// This produces a call tree like the following (where the calls under - /// an item are done after reading that item): - /// - /// ```text - /// 1 2 3 4 5 6 7 - /// │ │ │ │ │ │ │ - /// └─f └─f └─f │ - /// │ │ │ │ - /// └───f └─f - /// │ │ - /// └─────f - /// ``` - /// - /// Which, for non-associative functions, will typically produce a different - /// result than the linear call tree used by `fold1`: - /// - /// ```text - /// 1 2 3 4 5 6 7 - /// │ │ │ │ │ │ │ - /// └─f─f─f─f─f─f - /// ``` - /// - /// If `f` is associative, prefer the normal `fold1` instead. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // The same tree as above - /// let num_strings = (1..8).map(|x| x.to_string()); - /// assert_eq!(num_strings.tree_fold1(|x, y| format!("f({}, {})", x, y)), - /// Some(String::from("f(f(f(1, 2), f(3, 4)), f(f(5, 6), 7))"))); - /// - /// // Like fold1, an empty iterator produces None - /// assert_eq!((0..0).tree_fold1(|x, y| x * y), None); - /// - /// // tree_fold1 matches fold1 for associative operations... - /// assert_eq!((0..10).tree_fold1(|x, y| x + y), - /// (0..10).fold1(|x, y| x + y)); - /// // ...but not for non-associative ones - /// assert_ne!((0..10).tree_fold1(|x, y| x - y), - /// (0..10).fold1(|x, y| x - y)); - /// ``` - fn tree_fold1(mut self, mut f: F) -> Option - where F: FnMut(Self::Item, Self::Item) -> Self::Item, - Self: Sized, - { - type State = Result>; - - fn inner0(it: &mut II, f: &mut FF) -> State - where - II: Iterator, - FF: FnMut(T, T) -> T - { - // This function could be replaced with `it.next().ok_or(None)`, - // but half the useful tree_fold1 work is combining adjacent items, - // so put that in a form that LLVM is more likely to optimize well. - - let a = - if let Some(v) = it.next() { v } - else { return Err(None) }; - let b = - if let Some(v) = it.next() { v } - else { return Err(Some(a)) }; - Ok(f(a, b)) - } - - fn inner(stop: usize, it: &mut II, f: &mut FF) -> State - where - II: Iterator, - FF: FnMut(T, T) -> T - { - let mut x = try!(inner0(it, f)); - for height in 0..stop { - // Try to get another tree the same size with which to combine it, - // creating a new tree that's twice as big for next time around. - let next = - if height == 0 { - inner0(it, f) - } else { - inner(height, it, f) - }; - match next { - Ok(y) => x = f(x, y), - - // If we ran out of items, combine whatever we did manage - // to get. It's better combined with the current value - // than something in a parent frame, because the tree in - // the parent is always as least as big as this one. - Err(None) => return Err(Some(x)), - Err(Some(y)) => return Err(Some(f(x, y))), - } - } - Ok(x) - } - - match inner(usize::max_value(), &mut self, &mut f) { - Err(x) => x, - _ => unreachable!(), - } - } - - /// An iterator method that applies a function, producing a single, final value. - /// - /// `fold_while()` is basically equivalent to `fold()` but with additional support for - /// early exit via short-circuiting. - /// - /// ``` - /// use itertools::Itertools; - /// use itertools::FoldWhile::{Continue, Done}; - /// - /// let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - /// - /// let mut result = 0; - /// - /// // for loop: - /// for i in &numbers { - /// if *i > 5 { - /// break; - /// } - /// result = result + i; - /// } - /// - /// // fold: - /// let result2 = numbers.iter().fold(0, |acc, x| { - /// if *x > 5 { acc } else { acc + x } - /// }); - /// - /// // fold_while: - /// let result3 = numbers.iter().fold_while(0, |acc, x| { - /// if *x > 5 { Done(acc) } else { Continue(acc + x) } - /// }).into_inner(); - /// - /// // they're the same - /// assert_eq!(result, result2); - /// assert_eq!(result2, result3); - /// ``` - /// - /// The big difference between the computations of `result2` and `result3` is that while - /// `fold()` called the provided closure for every item of the callee iterator, - /// `fold_while()` actually stopped iterating as soon as it encountered `Fold::Done(_)`. - #[deprecated(note="Use .try_fold() instead", since="0.8")] - fn fold_while(&mut self, init: B, mut f: F) -> FoldWhile - where Self: Sized, - F: FnMut(B, Self::Item) -> FoldWhile - { - let mut acc = init; - while let Some(item) = self.next() { - match f(acc, item) { - FoldWhile::Continue(res) => acc = res, - res @ FoldWhile::Done(_) => return res, - } - } - FoldWhile::Continue(acc) - } - - /// Iterate over the entire iterator and add all the elements. - /// - /// An empty iterator returns `None`, otherwise `Some(sum)`. - /// - /// # Panics - /// - /// When calling `sum1()` and a primitive integer type is being returned, this - /// method will panic if the computation overflows and debug assertions are - /// enabled. - /// - /// # Examples - /// - /// ``` - /// use itertools::Itertools; - /// - /// let empty_sum = (1..1).sum1::(); - /// assert_eq!(empty_sum, None); - /// - /// let nonempty_sum = (1..11).sum1::(); - /// assert_eq!(nonempty_sum, Some(55)); - /// ``` - fn sum1(mut self) -> Option - where Self: Sized, - S: std::iter::Sum, - { - self.next() - .map(|first| once(first).chain(self).sum()) - } - - /// Iterate over the entire iterator and multiply all the elements. - /// - /// An empty iterator returns `None`, otherwise `Some(product)`. - /// - /// # Panics - /// - /// When calling `product1()` and a primitive integer type is being returned, - /// method will panic if the computation overflows and debug assertions are - /// enabled. - /// - /// # Examples - /// ``` - /// use itertools::Itertools; - /// - /// let empty_product = (1..1).product1::(); - /// assert_eq!(empty_product, None); - /// - /// let nonempty_product = (1..11).product1::(); - /// assert_eq!(nonempty_product, Some(3628800)); - /// ``` - fn product1

    (mut self) -> Option

    - where Self: Sized, - P: std::iter::Product, - { - self.next() - .map(|first| once(first).chain(self).product()) - } - - - /// Sort all iterator elements into a new iterator in ascending order. - /// - /// **Note:** This consumes the entire iterator, uses the - /// `slice::sort()` method and returns the result as a new - /// iterator that owns its elements. - /// - /// The sorted iterator, if directly collected to a `Vec`, is converted - /// without any extra copying or allocation cost. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sort the letters of the text in ascending order - /// let text = "bdacfe"; - /// itertools::assert_equal(text.chars().sorted(), - /// "abcdef".chars()); - /// ``` - #[cfg(feature = "use_std")] - fn sorted(self) -> VecIntoIter - where Self: Sized, - Self::Item: Ord - { - // Use .sort() directly since it is not quite identical with - // .sort_by(Ord::cmp) - let mut v = Vec::from_iter(self); - v.sort(); - v.into_iter() - } - - /// Sort all iterator elements into a new iterator in ascending order. - /// - /// **Note:** This consumes the entire iterator, uses the - /// `slice::sort_by()` method and returns the result as a new - /// iterator that owns its elements. - /// - /// The sorted iterator, if directly collected to a `Vec`, is converted - /// without any extra copying or allocation cost. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sort people in descending order by age - /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; - /// - /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by(|a, b| Ord::cmp(&b.1, &a.1)) - /// .map(|(person, _age)| person); - /// - /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); - /// ``` - #[cfg(feature = "use_std")] - fn sorted_by(self, cmp: F) -> VecIntoIter - where Self: Sized, - F: FnMut(&Self::Item, &Self::Item) -> Ordering, - { - let mut v = Vec::from_iter(self); - v.sort_by(cmp); - v.into_iter() - } - - /// Sort all iterator elements into a new iterator in ascending order. - /// - /// **Note:** This consumes the entire iterator, uses the - /// `slice::sort_by_key()` method and returns the result as a new - /// iterator that owns its elements. - /// - /// The sorted iterator, if directly collected to a `Vec`, is converted - /// without any extra copying or allocation cost. - /// - /// ``` - /// use itertools::Itertools; - /// - /// // sort people in descending order by age - /// let people = vec![("Jane", 20), ("John", 18), ("Jill", 30), ("Jack", 27)]; - /// - /// let oldest_people_first = people - /// .into_iter() - /// .sorted_by_key(|x| -x.1) - /// .map(|(person, _age)| person); - /// - /// itertools::assert_equal(oldest_people_first, - /// vec!["Jill", "Jack", "Jane", "John"]); - /// ``` - #[cfg(feature = "use_std")] - fn sorted_by_key(self, f: F) -> VecIntoIter - where Self: Sized, - K: Ord, - F: FnMut(&Self::Item) -> K, - { - let mut v = Vec::from_iter(self); - v.sort_by_key(f); - v.into_iter() - } - - /// Collect all iterator elements into one of two - /// partitions. Unlike `Iterator::partition`, each partition may - /// have a distinct type. - /// - /// ``` - /// use itertools::{Itertools, Either}; - /// - /// let successes_and_failures = vec![Ok(1), Err(false), Err(true), Ok(2)]; - /// - /// let (successes, failures): (Vec<_>, Vec<_>) = successes_and_failures - /// .into_iter() - /// .partition_map(|r| { - /// match r { - /// Ok(v) => Either::Left(v), - /// Err(v) => Either::Right(v), - /// } - /// }); - /// - /// assert_eq!(successes, [1, 2]); - /// assert_eq!(failures, [false, true]); - /// ``` - fn partition_map(self, mut predicate: F) -> (A, B) - where Self: Sized, - F: FnMut(Self::Item) -> Either, - A: Default + Extend, - B: Default + Extend, - { - let mut left = A::default(); - let mut right = B::default(); - - self.for_each(|val| match predicate(val) { - Either::Left(v) => left.extend(Some(v)), - Either::Right(v) => right.extend(Some(v)), - }); - - (left, right) - } - - /// Return a `HashMap` of keys mapped to `Vec`s of values. Keys and values - /// are taken from `(Key, Value)` tuple pairs yielded by the input iterator. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let data = vec![(0, 10), (2, 12), (3, 13), (0, 20), (3, 33), (2, 42)]; - /// let lookup = data.into_iter().into_group_map(); - /// - /// assert_eq!(lookup[&0], vec![10, 20]); - /// assert_eq!(lookup.get(&1), None); - /// assert_eq!(lookup[&2], vec![12, 42]); - /// assert_eq!(lookup[&3], vec![13, 33]); - /// ``` - #[cfg(feature = "use_std")] - fn into_group_map(self) -> HashMap> - where Self: Iterator + Sized, - K: Hash + Eq, - { - group_map::into_group_map(self) - } - - /// Return the minimum and maximum elements in the iterator. - /// - /// The return type `MinMaxResult` is an enum of three variants: - /// - /// - `NoElements` if the iterator is empty. - /// - `OneElement(x)` if the iterator has exactly one element. - /// - `MinMax(x, y)` is returned otherwise, where `x <= y`. Two - /// values are equal if and only if there is more than one - /// element in the iterator and all elements are equal. - /// - /// On an iterator of length `n`, `minmax` does `1.5 * n` comparisons, - /// and so is faster than calling `min` and `max` separately which does - /// `2 * n` comparisons. - /// - /// # Examples - /// - /// ``` - /// use itertools::Itertools; - /// use itertools::MinMaxResult::{NoElements, OneElement, MinMax}; - /// - /// let a: [i32; 0] = []; - /// assert_eq!(a.iter().minmax(), NoElements); - /// - /// let a = [1]; - /// assert_eq!(a.iter().minmax(), OneElement(&1)); - /// - /// let a = [1, 2, 3, 4, 5]; - /// assert_eq!(a.iter().minmax(), MinMax(&1, &5)); - /// - /// let a = [1, 1, 1, 1]; - /// assert_eq!(a.iter().minmax(), MinMax(&1, &1)); - /// ``` - /// - /// The elements can be floats but no particular result is guaranteed - /// if an element is NaN. - fn minmax(self) -> MinMaxResult - where Self: Sized, Self::Item: PartialOrd - { - minmax::minmax_impl(self, |_| (), |x, y, _, _| x < y) - } - - /// Return the minimum and maximum element of an iterator, as determined by - /// the specified function. - /// - /// The return value is a variant of `MinMaxResult` like for `minmax()`. - /// - /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard - /// `Iterator::min()` and `Iterator::max()` methods. - /// - /// The keys can be floats but no particular result is guaranteed - /// if a key is NaN. - fn minmax_by_key(self, key: F) -> MinMaxResult - where Self: Sized, K: PartialOrd, F: FnMut(&Self::Item) -> K - { - minmax::minmax_impl(self, key, |_, _, xk, yk| xk < yk) - } - - /// Return the minimum and maximum element of an iterator, as determined by - /// the specified comparison function. - /// - /// The return value is a variant of `MinMaxResult` like for `minmax()`. - /// - /// For the minimum, the first minimal element is returned. For the maximum, - /// the last maximal element wins. This matches the behavior of the standard - /// `Iterator::min()` and `Iterator::max()` methods. - fn minmax_by(self, mut compare: F) -> MinMaxResult - where Self: Sized, F: FnMut(&Self::Item, &Self::Item) -> Ordering - { - minmax::minmax_impl( - self, - |_| (), - |x, y, _, _| Ordering::Less == compare(x, y) - ) - } - - /// If the iterator yields exactly one element, that element will be returned, otherwise - /// an error will be returned containing an iterator that has the same output as the input - /// iterator. - /// - /// This provides an additional layer of validation over just calling `Iterator::next()`. - /// If your assumption that there should only be one element yielded is false this provides - /// the opportunity to detect and handle that, preventing errors at a distance. - /// - /// # Examples - /// ``` - /// use itertools::Itertools; - /// - /// assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2); - /// assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4)); - /// assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5)); - /// assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0)); - /// ``` - fn exactly_one(mut self) -> Result> - where - Self: Sized, - { - match self.next() { - Some(first) => { - match self.next() { - Some(second) => { - Err(ExactlyOneError::new((Some(first), Some(second)), self)) - } - None => { - Ok(first) - } - } - } - None => Err(ExactlyOneError::new((None, None), self)), - } - } -} - -impl Itertools for T where T: Iterator { } - -/// Return `true` if both iterables produce equal sequences -/// (elements pairwise equal and sequences of the same length), -/// `false` otherwise. -/// -/// This is an `IntoIterator` enabled function that is similar to the standard -/// library method `Iterator::eq`. -/// -/// ``` -/// assert!(itertools::equal(vec![1, 2, 3], 1..4)); -/// assert!(!itertools::equal(&[0, 0], &[0, 0, 0])); -/// ``` -pub fn equal(a: I, b: J) -> bool - where I: IntoIterator, - J: IntoIterator, - I::Item: PartialEq -{ - let mut ia = a.into_iter(); - let mut ib = b.into_iter(); - loop { - match ia.next() { - Some(x) => match ib.next() { - Some(y) => if x != y { return false; }, - None => return false, - }, - None => return ib.next().is_none() - } - } -} - -/// Assert that two iterables produce equal sequences, with the same -/// semantics as *equal(a, b)*. -/// -/// **Panics** on assertion failure with a message that shows the -/// two iteration elements. -/// -/// ```ignore -/// assert_equal("exceed".split('c'), "excess".split('c')); -/// // ^PANIC: panicked at 'Failed assertion Some("eed") == Some("ess") for iteration 1', -/// ``` -pub fn assert_equal(a: I, b: J) - where I: IntoIterator, - J: IntoIterator, - I::Item: fmt::Debug + PartialEq, - J::Item: fmt::Debug, -{ - let mut ia = a.into_iter(); - let mut ib = b.into_iter(); - let mut i = 0; - loop { - match (ia.next(), ib.next()) { - (None, None) => return, - (a, b) => { - let equal = match (&a, &b) { - (&Some(ref a), &Some(ref b)) => a == b, - _ => false, - }; - assert!(equal, "Failed assertion {a:?} == {b:?} for iteration {i}", - i=i, a=a, b=b); - i += 1; - } - } - } -} - -/// Partition a sequence using predicate `pred` so that elements -/// that map to `true` are placed before elements which map to `false`. -/// -/// The order within the partitions is arbitrary. -/// -/// Return the index of the split point. -/// -/// ``` -/// use itertools::partition; -/// -/// # // use repeated numbers to not promise any ordering -/// let mut data = [7, 1, 1, 7, 1, 1, 7]; -/// let split_index = partition(&mut data, |elt| *elt >= 3); -/// -/// assert_eq!(data, [7, 7, 7, 1, 1, 1, 1]); -/// assert_eq!(split_index, 3); -/// ``` -pub fn partition<'a, A: 'a, I, F>(iter: I, mut pred: F) -> usize - where I: IntoIterator, - I::IntoIter: DoubleEndedIterator, - F: FnMut(&A) -> bool -{ - let mut split_index = 0; - let mut iter = iter.into_iter(); - 'main: while let Some(front) = iter.next() { - if !pred(front) { - loop { - match iter.next_back() { - Some(back) => if pred(back) { - std::mem::swap(front, back); - break; - }, - None => break 'main, - } - } - } - split_index += 1; - } - split_index -} - -/// An enum used for controlling the execution of `.fold_while()`. -/// -/// See [`.fold_while()`](trait.Itertools.html#method.fold_while) for more information. -#[derive(Copy, Clone, Debug, Eq, PartialEq)] -pub enum FoldWhile { - /// Continue folding with this value - Continue(T), - /// Fold is complete and will return this value - Done(T), -} - -impl FoldWhile { - /// Return the value in the continue or done. - pub fn into_inner(self) -> T { - match self { - FoldWhile::Continue(x) | FoldWhile::Done(x) => x, - } - } - - /// Return true if `self` is `Done`, false if it is `Continue`. - pub fn is_done(&self) -> bool { - match *self { - FoldWhile::Continue(_) => false, - FoldWhile::Done(_) => true, - } - } -} diff --git a/vendor/itertools-0.8.2/src/merge_join.rs b/vendor/itertools-0.8.2/src/merge_join.rs deleted file mode 100644 index 5f9a0f4013..0000000000 --- a/vendor/itertools-0.8.2/src/merge_join.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::cmp::Ordering; -use std::iter::Fuse; -use std::fmt; - -use super::adaptors::{PutBack, put_back}; -use either_or_both::EitherOrBoth; - -/// Return an iterator adaptor that merge-joins items from the two base iterators in ascending order. -/// -/// See [`.merge_join_by()`](trait.Itertools.html#method.merge_join_by) for more information. -pub fn merge_join_by(left: I, right: J, cmp_fn: F) - -> MergeJoinBy - where I: IntoIterator, - J: IntoIterator, - F: FnMut(&I::Item, &J::Item) -> Ordering -{ - MergeJoinBy { - left: put_back(left.into_iter().fuse()), - right: put_back(right.into_iter().fuse()), - cmp_fn: cmp_fn - } -} - -/// An iterator adaptor that merge-joins items from the two base iterators in ascending order. -/// -/// See [`.merge_join_by()`](../trait.Itertools.html#method.merge_join_by) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct MergeJoinBy { - left: PutBack>, - right: PutBack>, - cmp_fn: F -} - -impl fmt::Debug for MergeJoinBy - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, - J: Iterator + fmt::Debug, - J::Item: fmt::Debug, -{ - debug_fmt_fields!(MergeJoinBy, left, right); -} - -impl Iterator for MergeJoinBy - where I: Iterator, - J: Iterator, - F: FnMut(&I::Item, &J::Item) -> Ordering -{ - type Item = EitherOrBoth; - - fn next(&mut self) -> Option { - match (self.left.next(), self.right.next()) { - (None, None) => None, - (Some(left), None) => - Some(EitherOrBoth::Left(left)), - (None, Some(right)) => - Some(EitherOrBoth::Right(right)), - (Some(left), Some(right)) => { - match (self.cmp_fn)(&left, &right) { - Ordering::Equal => - Some(EitherOrBoth::Both(left, right)), - Ordering::Less => { - self.right.put_back(right); - Some(EitherOrBoth::Left(left)) - }, - Ordering::Greater => { - self.left.put_back(left); - Some(EitherOrBoth::Right(right)) - } - } - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let (a_lower, a_upper) = self.left.size_hint(); - let (b_lower, b_upper) = self.right.size_hint(); - - let lower = ::std::cmp::max(a_lower, b_lower); - - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => Some(x + y), - _ => None, - }; - - (lower, upper) - } -} diff --git a/vendor/itertools-0.8.2/src/minmax.rs b/vendor/itertools-0.8.2/src/minmax.rs deleted file mode 100644 index 38180ef6d0..0000000000 --- a/vendor/itertools-0.8.2/src/minmax.rs +++ /dev/null @@ -1,114 +0,0 @@ - -/// `MinMaxResult` is an enum returned by `minmax`. See `Itertools::minmax()` for -/// more detail. -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum MinMaxResult { - /// Empty iterator - NoElements, - - /// Iterator with one element, so the minimum and maximum are the same - OneElement(T), - - /// More than one element in the iterator, the first element is not larger - /// than the second - MinMax(T, T) -} - -impl MinMaxResult { - /// `into_option` creates an `Option` of type `(T, T)`. The returned `Option` - /// has variant `None` if and only if the `MinMaxResult` has variant - /// `NoElements`. Otherwise `Some((x, y))` is returned where `x <= y`. - /// If the `MinMaxResult` has variant `OneElement(x)`, performing this - /// operation will make one clone of `x`. - /// - /// # Examples - /// - /// ``` - /// use itertools::MinMaxResult::{self, NoElements, OneElement, MinMax}; - /// - /// let r: MinMaxResult = NoElements; - /// assert_eq!(r.into_option(), None); - /// - /// let r = OneElement(1); - /// assert_eq!(r.into_option(), Some((1, 1))); - /// - /// let r = MinMax(1, 2); - /// assert_eq!(r.into_option(), Some((1, 2))); - /// ``` - pub fn into_option(self) -> Option<(T,T)> { - match self { - MinMaxResult::NoElements => None, - MinMaxResult::OneElement(x) => Some((x.clone(), x)), - MinMaxResult::MinMax(x, y) => Some((x, y)) - } - } -} - -/// Implementation guts for `minmax` and `minmax_by_key`. -pub fn minmax_impl(mut it: I, mut key_for: F, - mut lt: L) -> MinMaxResult - where I: Iterator, - F: FnMut(&I::Item) -> K, - L: FnMut(&I::Item, &I::Item, &K, &K) -> bool, -{ - let (mut min, mut max, mut min_key, mut max_key) = match it.next() { - None => return MinMaxResult::NoElements, - Some(x) => { - match it.next() { - None => return MinMaxResult::OneElement(x), - Some(y) => { - let xk = key_for(&x); - let yk = key_for(&y); - if !lt(&y, &x, &yk, &xk) {(x, y, xk, yk)} else {(y, x, yk, xk)} - } - } - } - }; - - loop { - // `first` and `second` are the two next elements we want to look - // at. We first compare `first` and `second` (#1). The smaller one - // is then compared to current minimum (#2). The larger one is - // compared to current maximum (#3). This way we do 3 comparisons - // for 2 elements. - let first = match it.next() { - None => break, - Some(x) => x - }; - let second = match it.next() { - None => { - let first_key = key_for(&first); - if lt(&first, &min, &first_key, &min_key) { - min = first; - } else if !lt(&first, &max, &first_key, &max_key) { - max = first; - } - break; - } - Some(x) => x - }; - let first_key = key_for(&first); - let second_key = key_for(&second); - if !lt(&second, &first, &second_key, &first_key) { - if lt(&first, &min, &first_key, &min_key) { - min = first; - min_key = first_key; - } - if !lt(&second, &max, &second_key, &max_key) { - max = second; - max_key = second_key; - } - } else { - if lt(&second, &min, &second_key, &min_key) { - min = second; - min_key = second_key; - } - if !lt(&first, &max, &first_key, &max_key) { - max = first; - max_key = first_key; - } - } - } - - MinMaxResult::MinMax(min, max) -} diff --git a/vendor/itertools-0.8.2/src/multipeek_impl.rs b/vendor/itertools-0.8.2/src/multipeek_impl.rs deleted file mode 100644 index a6a2fb33eb..0000000000 --- a/vendor/itertools-0.8.2/src/multipeek_impl.rs +++ /dev/null @@ -1,104 +0,0 @@ - - -use std::iter::Fuse; -use std::collections::VecDeque; -use size_hint; -use PeekingNext; - -/// See [`multipeek()`](../fn.multipeek.html) for more information. -#[derive(Clone, Debug)] -pub struct MultiPeek - where I: Iterator -{ - iter: Fuse, - buf: VecDeque, - index: usize, -} - -/// An iterator adaptor that allows the user to peek at multiple `.next()` -/// values without advancing the base iterator. -pub fn multipeek(iterable: I) -> MultiPeek - where I: IntoIterator -{ - MultiPeek { - iter: iterable.into_iter().fuse(), - buf: VecDeque::new(), - index: 0, - } -} - -impl MultiPeek - where I: Iterator -{ - /// Reset the peeking “cursor” - pub fn reset_peek(&mut self) { - self.index = 0; - } -} - -impl MultiPeek { - /// Works exactly like `.next()` with the only difference that it doesn't - /// advance itself. `.peek()` can be called multiple times, to peek - /// further ahead. - pub fn peek(&mut self) -> Option<&I::Item> { - let ret = if self.index < self.buf.len() { - Some(&self.buf[self.index]) - } else { - match self.iter.next() { - Some(x) => { - self.buf.push_back(x); - Some(&self.buf[self.index]) - } - None => return None, - } - }; - - self.index += 1; - ret - } -} - -impl PeekingNext for MultiPeek - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if self.buf.is_empty() { - if let Some(r) = self.peek() { - if !accept(r) { return None } - } - } else { - if let Some(r) = self.buf.get(0) { - if !accept(r) { return None } - } - } - self.next() - } -} - -impl Iterator for MultiPeek - where I: Iterator -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - self.index = 0; - if self.buf.is_empty() { - self.iter.next() - } else { - self.buf.pop_front() - } - } - - fn size_hint(&self) -> (usize, Option) { - size_hint::add_scalar(self.iter.size_hint(), self.buf.len()) - } -} - -// Same size -impl ExactSizeIterator for MultiPeek - where I: ExactSizeIterator -{} - - diff --git a/vendor/itertools-0.8.2/src/pad_tail.rs b/vendor/itertools-0.8.2/src/pad_tail.rs deleted file mode 100644 index c9cfe6af30..0000000000 --- a/vendor/itertools-0.8.2/src/pad_tail.rs +++ /dev/null @@ -1,83 +0,0 @@ -use std::iter::Fuse; -use size_hint; - -/// An iterator adaptor that pads a sequence to a minimum length by filling -/// missing elements using a closure. -/// -/// Iterator element type is `I::Item`. -/// -/// See [`.pad_using()`](../trait.Itertools.html#method.pad_using) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct PadUsing { - iter: Fuse, - min: usize, - pos: usize, - filler: F, -} - -/// Create a new **PadUsing** iterator. -pub fn pad_using(iter: I, min: usize, filler: F) -> PadUsing - where I: Iterator, - F: FnMut(usize) -> I::Item -{ - PadUsing { - iter: iter.fuse(), - min: min, - pos: 0, - filler: filler, - } -} - -impl Iterator for PadUsing - where I: Iterator, - F: FnMut(usize) -> I::Item -{ - type Item = I::Item; - - #[inline] - fn next(&mut self) -> Option { - match self.iter.next() { - None => { - if self.pos < self.min { - let e = Some((self.filler)(self.pos)); - self.pos += 1; - e - } else { - None - } - }, - e => { - self.pos += 1; - e - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let tail = self.min.saturating_sub(self.pos); - size_hint::max(self.iter.size_hint(), (tail, Some(tail))) - } -} - -impl DoubleEndedIterator for PadUsing - where I: DoubleEndedIterator + ExactSizeIterator, - F: FnMut(usize) -> I::Item -{ - fn next_back(&mut self) -> Option { - if self.min == 0 { - self.iter.next_back() - } else if self.iter.len() >= self.min { - self.min -= 1; - self.iter.next_back() - } else { - self.min -= 1; - Some((self.filler)(self.min)) - } - } -} - -impl ExactSizeIterator for PadUsing - where I: ExactSizeIterator, - F: FnMut(usize) -> I::Item -{} diff --git a/vendor/itertools-0.8.2/src/peeking_take_while.rs b/vendor/itertools-0.8.2/src/peeking_take_while.rs deleted file mode 100644 index 0b2291dfdd..0000000000 --- a/vendor/itertools-0.8.2/src/peeking_take_while.rs +++ /dev/null @@ -1,149 +0,0 @@ - -use std::iter::Peekable; -use PutBack; -#[cfg(feature = "use_std")] -use PutBackN; - -/// An iterator that allows peeking at an element before deciding to accept it. -/// -/// See [`.peeking_take_while()`](trait.Itertools.html#method.peeking_take_while) -/// for more information. -/// -/// This is implemented by peeking adaptors like peekable and put back, -/// but also by a few iterators that can be peeked natively, like the slice’s -/// by reference iterator (`std::slice::Iter`). -pub trait PeekingNext : Iterator { - /// Pass a reference to the next iterator element to the closure `accept`; - /// if `accept` returns true, return it as the next element, - /// else None. - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool; -} - -impl PeekingNext for Peekable - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if let Some(r) = self.peek() { - if !accept(r) { - return None; - } - } - self.next() - } -} - -impl PeekingNext for PutBack - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if let Some(r) = self.next() { - if !accept(&r) { - self.put_back(r); - return None; - } - Some(r) - } else { - None - } - } -} - -#[cfg(feature = "use_std")] -impl PeekingNext for PutBackN - where I: Iterator, -{ - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - if let Some(r) = self.next() { - if !accept(&r) { - self.put_back(r); - return None; - } - Some(r) - } else { - None - } - } -} - -/// An iterator adaptor that takes items while a closure returns `true`. -/// -/// See [`.peeking_take_while()`](../trait.Itertools.html#method.peeking_take_while) -/// for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct PeekingTakeWhile<'a, I: 'a, F> - where I: Iterator, -{ - iter: &'a mut I, - f: F, -} - -/// Create a PeekingTakeWhile -pub fn peeking_take_while(iter: &mut I, f: F) -> PeekingTakeWhile - where I: Iterator, -{ - PeekingTakeWhile { - iter: iter, - f: f, - } -} - -impl<'a, I, F> Iterator for PeekingTakeWhile<'a, I, F> - where I: PeekingNext, - F: FnMut(&I::Item) -> bool, - -{ - type Item = I::Item; - fn next(&mut self) -> Option { - self.iter.peeking_next(&mut self.f) - } - - fn size_hint(&self) -> (usize, Option) { - let (_, hi) = self.iter.size_hint(); - (0, hi) - } -} - -// Some iterators are so lightweight we can simply clone them to save their -// state and use that for peeking. -macro_rules! peeking_next_by_clone { - ([$($typarm:tt)*] $type_:ty) => { - impl<$($typarm)*> PeekingNext for $type_ { - fn peeking_next(&mut self, accept: F) -> Option - where F: FnOnce(&Self::Item) -> bool - { - let saved_state = self.clone(); - if let Some(r) = self.next() { - if !accept(&r) { - *self = saved_state; - } else { - return Some(r) - } - } - None - } - } - } -} - -peeking_next_by_clone! { ['a, T] ::std::slice::Iter<'a, T> } -peeking_next_by_clone! { ['a] ::std::str::Chars<'a> } -peeking_next_by_clone! { ['a] ::std::str::CharIndices<'a> } -peeking_next_by_clone! { ['a] ::std::str::Bytes<'a> } -peeking_next_by_clone! { ['a, T] ::std::option::Iter<'a, T> } -peeking_next_by_clone! { ['a, T] ::std::result::Iter<'a, T> } -peeking_next_by_clone! { [T] ::std::iter::Empty } -#[cfg(feature = "use_std")] -peeking_next_by_clone! { ['a, T] ::std::collections::linked_list::Iter<'a, T> } -#[cfg(feature = "use_std")] -peeking_next_by_clone! { ['a, T] ::std::collections::vec_deque::Iter<'a, T> } - -// cloning a Rev has no extra overhead; peekable and put backs are never DEI. -peeking_next_by_clone! { [I: Clone + PeekingNext + DoubleEndedIterator] - ::std::iter::Rev } diff --git a/vendor/itertools-0.8.2/src/permutations.rs b/vendor/itertools-0.8.2/src/permutations.rs deleted file mode 100644 index a9423375fd..0000000000 --- a/vendor/itertools-0.8.2/src/permutations.rs +++ /dev/null @@ -1,272 +0,0 @@ -use std::fmt; -use std::iter::once; - -use super::lazy_buffer::LazyBuffer; - -/// An iterator adaptor that iterates through all the `k`-permutations of the -/// elements from an iterator. -/// -/// See [`.permutations()`](../trait.Itertools.html#method.permutations) for -/// more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Permutations { - vals: LazyBuffer, - state: PermutationState, -} - -#[derive(Debug)] -enum PermutationState { - StartUnknownLen { - k: usize, - }, - OngoingUnknownLen { - k: usize, - min_n: usize, - }, - Complete(CompleteState), - Empty, -} - -#[derive(Debug)] -enum CompleteState { - Start { - n: usize, - k: usize, - }, - Ongoing { - indices: Vec, - cycles: Vec, - } -} - -enum CompleteStateRemaining { - Known(usize), - Overflow, -} - -impl fmt::Debug for Permutations - where I: Iterator + fmt::Debug, - I::Item: fmt::Debug, -{ - debug_fmt_fields!(Permutations, vals, state); -} - -pub fn permutations(iter: I, k: usize) -> Permutations { - let mut vals = LazyBuffer::new(iter); - - if k == 0 { - // Special case, yields single empty vec; `n` is irrelevant - let state = PermutationState::Complete(CompleteState::Start { n: 0, k: 0 }); - - return Permutations { - vals, - state - }; - } - - let mut enough_vals = true; - - while vals.len() < k { - if !vals.get_next() { - enough_vals = false; - break; - } - } - - let state = if enough_vals { - PermutationState::StartUnknownLen { k } - } else { - PermutationState::Empty - }; - - Permutations { - vals, - state - } -} - -impl Iterator for Permutations -where - I: Iterator, - I::Item: Clone -{ - type Item = Vec; - - fn next(&mut self) -> Option { - self.advance(); - - let &mut Permutations { ref vals, ref state } = self; - - match state { - &PermutationState::StartUnknownLen { .. } => panic!("unexpected iterator state"), - &PermutationState::OngoingUnknownLen { k, min_n } => { - let latest_idx = min_n - 1; - let indices = (0..(k - 1)).chain(once(latest_idx)); - - Some(indices.map(|i| vals[i].clone()).collect()) - } - &PermutationState::Complete(CompleteState::Start { .. }) => None, - &PermutationState::Complete(CompleteState::Ongoing { ref indices, ref cycles }) => { - let k = cycles.len(); - - Some(indices[0..k].iter().map(|&i| vals[i].clone()).collect()) - }, - &PermutationState::Empty => None - } - } - - fn count(self) -> usize { - let Permutations { vals, state } = self; - - fn from_complete(complete_state: CompleteState) -> usize { - match complete_state.remaining() { - CompleteStateRemaining::Known(count) => count, - CompleteStateRemaining::Overflow => { - panic!("Iterator count greater than usize::MAX"); - } - } - } - - match state { - PermutationState::StartUnknownLen { k } => { - let n = vals.len() + vals.it.count(); - let complete_state = CompleteState::Start { n, k }; - - from_complete(complete_state) - } - PermutationState::OngoingUnknownLen { k, min_n } => { - let prev_iteration_count = min_n - k + 1; - let n = vals.len() + vals.it.count(); - let complete_state = CompleteState::Start { n, k }; - - from_complete(complete_state) - prev_iteration_count - }, - PermutationState::Complete(state) => from_complete(state), - PermutationState::Empty => 0 - } - } - - fn size_hint(&self) -> (usize, Option) { - match self.state { - PermutationState::StartUnknownLen { .. } | - PermutationState::OngoingUnknownLen { .. } => (0, None), // TODO can we improve this lower bound? - PermutationState::Complete(ref state) => match state.remaining() { - CompleteStateRemaining::Known(count) => (count, Some(count)), - CompleteStateRemaining::Overflow => (::std::usize::MAX, None) - } - PermutationState::Empty => (0, Some(0)) - } - } -} - -impl Permutations -where - I: Iterator, - I::Item: Clone -{ - fn advance(&mut self) { - let &mut Permutations { ref mut vals, ref mut state } = self; - - *state = match state { - &mut PermutationState::StartUnknownLen { k } => { - PermutationState::OngoingUnknownLen { k, min_n: k } - } - &mut PermutationState::OngoingUnknownLen { k, min_n } => { - if vals.get_next() { - PermutationState::OngoingUnknownLen { k, min_n: min_n + 1 } - } else { - let n = min_n; - let prev_iteration_count = n - k + 1; - let mut complete_state = CompleteState::Start { n, k }; - - // Advance the complete-state iterator to the correct point - for _ in 0..(prev_iteration_count + 1) { - complete_state.advance(); - } - - PermutationState::Complete(complete_state) - } - } - &mut PermutationState::Complete(ref mut state) => { - state.advance(); - - return; - } - &mut PermutationState::Empty => { return; } - }; - } -} - -impl CompleteState { - fn advance(&mut self) { - *self = match self { - &mut CompleteState::Start { n, k } => { - let indices = (0..n).collect(); - let cycles = ((n - k)..n).rev().collect(); - - CompleteState::Ongoing { - cycles, - indices - } - }, - &mut CompleteState::Ongoing { ref mut indices, ref mut cycles } => { - let n = indices.len(); - let k = cycles.len(); - - for i in (0..k).rev() { - if cycles[i] == 0 { - cycles[i] = n - i - 1; - - let to_push = indices.remove(i); - indices.push(to_push); - } else { - let swap_index = n - cycles[i]; - indices.swap(i, swap_index); - - cycles[i] -= 1; - return; - } - } - - CompleteState::Start { n, k } - } - } - } - - fn remaining(&self) -> CompleteStateRemaining { - use self::CompleteStateRemaining::{Known, Overflow}; - - match self { - &CompleteState::Start { n, k } => { - if n < k { - return Known(0); - } - - let count: Option = (n - k + 1..n + 1).fold(Some(1), |acc, i| { - acc.and_then(|acc| acc.checked_mul(i)) - }); - - match count { - Some(count) => Known(count), - None => Overflow - } - } - &CompleteState::Ongoing { ref indices, ref cycles } => { - let mut count: usize = 0; - - for (i, &c) in cycles.iter().enumerate() { - let radix = indices.len() - i; - let next_count = count.checked_mul(radix) - .and_then(|count| count.checked_add(c)); - - count = match next_count { - Some(count) => count, - None => { return Overflow; } - }; - } - - Known(count) - } - } - } -} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/src/process_results_impl.rs b/vendor/itertools-0.8.2/src/process_results_impl.rs deleted file mode 100644 index f78515d77f..0000000000 --- a/vendor/itertools-0.8.2/src/process_results_impl.rs +++ /dev/null @@ -1,81 +0,0 @@ - -/// An iterator that produces only the `T` values as long as the -/// inner iterator produces `Ok(T)`. -/// -/// Used by [`process_results`](../fn.process_results.html), see its docs -/// for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct ProcessResults<'a, I, E: 'a> { - error: &'a mut Result<(), E>, - iter: I, -} - -impl<'a, I, T, E> Iterator for ProcessResults<'a, I, E> - where I: Iterator> -{ - type Item = T; - - fn next(&mut self) -> Option { - match self.iter.next() { - Some(Ok(x)) => Some(x), - Some(Err(e)) => { - *self.error = Err(e); - None - } - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - let (_, hi) = self.iter.size_hint(); - (0, hi) - } -} - -/// “Lift” a function of the values of an iterator so that it can process -/// an iterator of `Result` values instead. -/// -/// `iterable` is an iterator or iterable with `Result` elements, where -/// `T` is the value type and `E` the error type. -/// -/// `processor` is a closure that receives an adapted version of the iterable -/// as the only argument — the adapted iterator produces elements of type `T`, -/// as long as the original iterator produces `Ok` values. -/// -/// If the original iterable produces an error at any point, the adapted -/// iterator ends and the `process_results` function will return the -/// error iself. -/// -/// Otherwise, the return value from the closure is returned wrapped -/// inside `Ok`. -/// -/// # Example -/// -/// ``` -/// use itertools::process_results; -/// -/// type R = Result; -/// -/// let first_values: Vec = vec![Ok(1), Ok(0), Ok(3)]; -/// let second_values: Vec = vec![Ok(2), Ok(1), Err("overflow")]; -/// -/// // “Lift” the iterator .max() method to work on the values in Results using process_results -/// -/// let first_max = process_results(first_values, |iter| iter.max().unwrap_or(0)); -/// let second_max = process_results(second_values, |iter| iter.max().unwrap_or(0)); -/// -/// assert_eq!(first_max, Ok(3)); -/// assert!(second_max.is_err()); -/// ``` -pub fn process_results(iterable: I, processor: F) -> Result - where I: IntoIterator>, - F: FnOnce(ProcessResults) -> R -{ - let iter = iterable.into_iter(); - let mut error = Ok(()); - - let result = processor(ProcessResults { error: &mut error, iter: iter }); - - error.map(|_| result) -} diff --git a/vendor/itertools-0.8.2/src/put_back_n_impl.rs b/vendor/itertools-0.8.2/src/put_back_n_impl.rs deleted file mode 100644 index cc08320714..0000000000 --- a/vendor/itertools-0.8.2/src/put_back_n_impl.rs +++ /dev/null @@ -1,63 +0,0 @@ -use size_hint; - -/// An iterator adaptor that allows putting multiple -/// items in front of the iterator. -/// -/// Iterator element type is `I::Item`. -#[derive(Debug, Clone)] -pub struct PutBackN { - top: Vec, - iter: I, -} - -/// Create an iterator where you can put back multiple values to the front -/// of the iteration. -/// -/// Iterator element type is `I::Item`. -pub fn put_back_n(iterable: I) -> PutBackN - where I: IntoIterator -{ - PutBackN { - top: Vec::new(), - iter: iterable.into_iter(), - } -} - -impl PutBackN { - /// Puts x in front of the iterator. - /// The values are yielded in order of the most recently put back - /// values first. - /// - /// ```rust - /// use itertools::put_back_n; - /// - /// let mut it = put_back_n(1..5); - /// it.next(); - /// it.put_back(1); - /// it.put_back(0); - /// - /// assert!(itertools::equal(it, 0..5)); - /// ``` - #[inline] - pub fn put_back(&mut self, x: I::Item) { - self.top.push(x); - } -} - -impl Iterator for PutBackN { - type Item = I::Item; - #[inline] - fn next(&mut self) -> Option { - if self.top.is_empty() { - self.iter.next() - } else { - self.top.pop() - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - size_hint::add_scalar(self.iter.size_hint(), self.top.len()) - } -} - diff --git a/vendor/itertools-0.8.2/src/rciter_impl.rs b/vendor/itertools-0.8.2/src/rciter_impl.rs deleted file mode 100644 index 1c3b03b5bc..0000000000 --- a/vendor/itertools-0.8.2/src/rciter_impl.rs +++ /dev/null @@ -1,98 +0,0 @@ - -use std::iter::IntoIterator; -use std::rc::Rc; -use std::cell::RefCell; - -/// A wrapper for `Rc>`, that implements the `Iterator` trait. -#[derive(Debug)] -pub struct RcIter { - /// The boxed iterator. - pub rciter: Rc>, -} - -/// Return an iterator inside a `Rc>` wrapper. -/// -/// The returned `RcIter` can be cloned, and each clone will refer back to the -/// same original iterator. -/// -/// `RcIter` allows doing interesting things like using `.zip()` on an iterator with -/// itself, at the cost of runtime borrow checking which may have a performance -/// penalty. -/// -/// Iterator element type is `Self::Item`. -/// -/// ``` -/// use itertools::rciter; -/// use itertools::zip; -/// -/// // In this example a range iterator is created and we iterate it using -/// // three separate handles (two of them given to zip). -/// // We also use the IntoIterator implementation for `&RcIter`. -/// -/// let mut iter = rciter(0..9); -/// let mut z = zip(&iter, &iter); -/// -/// assert_eq!(z.next(), Some((0, 1))); -/// assert_eq!(z.next(), Some((2, 3))); -/// assert_eq!(z.next(), Some((4, 5))); -/// assert_eq!(iter.next(), Some(6)); -/// assert_eq!(z.next(), Some((7, 8))); -/// assert_eq!(z.next(), None); -/// ``` -/// -/// **Panics** in iterator methods if a borrow error is encountered in the -/// iterator methods. It can only happen if the `RcIter` is reentered in -/// `.next()`, i.e. if it somehow participates in an “iterator knot” -/// where it is an adaptor of itself. -pub fn rciter(iterable: I) -> RcIter - where I: IntoIterator -{ - RcIter { rciter: Rc::new(RefCell::new(iterable.into_iter())) } -} - -impl Clone for RcIter { - #[inline] - fn clone(&self) -> RcIter { - RcIter { rciter: self.rciter.clone() } - } -} - -impl Iterator for RcIter - where I: Iterator -{ - type Item = A; - #[inline] - fn next(&mut self) -> Option { - self.rciter.borrow_mut().next() - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // To work sanely with other API that assume they own an iterator, - // so it can't change in other places, we can't guarantee as much - // in our size_hint. Other clones may drain values under our feet. - let (_, hi) = self.rciter.borrow().size_hint(); - (0, hi) - } -} - -impl DoubleEndedIterator for RcIter - where I: DoubleEndedIterator -{ - #[inline] - fn next_back(&mut self) -> Option { - self.rciter.borrow_mut().next_back() - } -} - -/// Return an iterator from `&RcIter` (by simply cloning it). -impl<'a, I> IntoIterator for &'a RcIter - where I: Iterator -{ - type Item = I::Item; - type IntoIter = RcIter; - - fn into_iter(self) -> RcIter { - self.clone() - } -} diff --git a/vendor/itertools-0.8.2/src/repeatn.rs b/vendor/itertools-0.8.2/src/repeatn.rs deleted file mode 100644 index 1c7c310014..0000000000 --- a/vendor/itertools-0.8.2/src/repeatn.rs +++ /dev/null @@ -1,54 +0,0 @@ - -/// An iterator that produces *n* repetitions of an element. -/// -/// See [`repeat_n()`](../fn.repeat_n.html) for more information. -#[must_use = "iterators are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct RepeatN { - elt: Option, - n: usize, -} - -/// Create an iterator that produces `n` repetitions of `element`. -pub fn repeat_n(element: A, n: usize) -> RepeatN - where A: Clone, -{ - if n == 0 { - RepeatN { elt: None, n: n, } - } else { - RepeatN { elt: Some(element), n: n, } - } -} - -impl Iterator for RepeatN - where A: Clone -{ - type Item = A; - - fn next(&mut self) -> Option { - if self.n > 1 { - self.n -= 1; - self.elt.as_ref().cloned() - } else { - self.n = 0; - self.elt.take() - } - } - - fn size_hint(&self) -> (usize, Option) { - (self.n, Some(self.n)) - } -} - -impl DoubleEndedIterator for RepeatN - where A: Clone -{ - #[inline] - fn next_back(&mut self) -> Option { - self.next() - } -} - -impl ExactSizeIterator for RepeatN - where A: Clone -{} diff --git a/vendor/itertools-0.8.2/src/size_hint.rs b/vendor/itertools-0.8.2/src/size_hint.rs deleted file mode 100644 index be54443f29..0000000000 --- a/vendor/itertools-0.8.2/src/size_hint.rs +++ /dev/null @@ -1,104 +0,0 @@ -//! Arithmetic on **Iterator** *.size_hint()* values. -//! - -use std::usize; -use std::cmp; - -/// **SizeHint** is the return type of **Iterator::size_hint()**. -pub type SizeHint = (usize, Option); - -/// Add **SizeHint** correctly. -#[inline] -pub fn add(a: SizeHint, b: SizeHint) -> SizeHint { - let min = a.0.checked_add(b.0).unwrap_or(usize::MAX); - let max = match (a.1, b.1) { - (Some(x), Some(y)) => x.checked_add(y), - _ => None, - }; - - (min, max) -} - -/// Add **x** correctly to a **SizeHint**. -#[inline] -pub fn add_scalar(sh: SizeHint, x: usize) -> SizeHint { - let (mut low, mut hi) = sh; - low = low.saturating_add(x); - hi = hi.and_then(|elt| elt.checked_add(x)); - (low, hi) -} - -/// Sbb **x** correctly to a **SizeHint**. -#[inline] -#[allow(dead_code)] -pub fn sub_scalar(sh: SizeHint, x: usize) -> SizeHint { - let (mut low, mut hi) = sh; - low = low.saturating_sub(x); - hi = hi.map(|elt| elt.saturating_sub(x)); - (low, hi) -} - - -/// Multiply **SizeHint** correctly -/// -/// ```ignore -/// use std::usize; -/// use itertools::size_hint; -/// -/// assert_eq!(size_hint::mul((3, Some(4)), (3, Some(4))), -/// (9, Some(16))); -/// -/// assert_eq!(size_hint::mul((3, Some(4)), (usize::MAX, None)), -/// (usize::MAX, None)); -/// -/// assert_eq!(size_hint::mul((3, None), (0, Some(0))), -/// (0, Some(0))); -/// ``` -#[inline] -pub fn mul(a: SizeHint, b: SizeHint) -> SizeHint { - let low = a.0.checked_mul(b.0).unwrap_or(usize::MAX); - let hi = match (a.1, b.1) { - (Some(x), Some(y)) => x.checked_mul(y), - (Some(0), None) | (None, Some(0)) => Some(0), - _ => None, - }; - (low, hi) -} - -/// Multiply **x** correctly with a **SizeHint**. -#[inline] -pub fn mul_scalar(sh: SizeHint, x: usize) -> SizeHint { - let (mut low, mut hi) = sh; - low = low.saturating_mul(x); - hi = hi.and_then(|elt| elt.checked_mul(x)); - (low, hi) -} - -/// Return the maximum -#[inline] -pub fn max(a: SizeHint, b: SizeHint) -> SizeHint { - let (a_lower, a_upper) = a; - let (b_lower, b_upper) = b; - - let lower = cmp::max(a_lower, b_lower); - - let upper = match (a_upper, b_upper) { - (Some(x), Some(y)) => Some(cmp::max(x, y)), - _ => None, - }; - - (lower, upper) -} - -/// Return the minimum -#[inline] -pub fn min(a: SizeHint, b: SizeHint) -> SizeHint { - let (a_lower, a_upper) = a; - let (b_lower, b_upper) = b; - let lower = cmp::min(a_lower, b_lower); - let upper = match (a_upper, b_upper) { - (Some(u1), Some(u2)) => Some(cmp::min(u1, u2)), - _ => a_upper.or(b_upper), - }; - (lower, upper) -} diff --git a/vendor/itertools-0.8.2/src/sources.rs b/vendor/itertools-0.8.2/src/sources.rs deleted file mode 100644 index a579f3d9c2..0000000000 --- a/vendor/itertools-0.8.2/src/sources.rs +++ /dev/null @@ -1,190 +0,0 @@ -//! Iterators that are sources (produce elements from parameters, -//! not from another iterator). -#![allow(deprecated)] - -use std::fmt; -use std::mem; - -/// See [`repeat_call`](../fn.repeat_call.html) for more information. -#[deprecated(note="Use std repeat_with() instead", since="0.8")] -pub struct RepeatCall { - f: F, -} - -impl fmt::Debug for RepeatCall -{ - debug_fmt_fields!(RepeatCall, ); -} - -/// An iterator source that produces elements indefinitely by calling -/// a given closure. -/// -/// Iterator element type is the return type of the closure. -/// -/// ``` -/// use itertools::repeat_call; -/// use itertools::Itertools; -/// use std::collections::BinaryHeap; -/// -/// let mut heap = BinaryHeap::from(vec![2, 5, 3, 7, 8]); -/// -/// // extract each element in sorted order -/// for element in repeat_call(|| heap.pop()).while_some() { -/// print!("{}", element); -/// } -/// -/// itertools::assert_equal( -/// repeat_call(|| 1).take(5), -/// vec![1, 1, 1, 1, 1] -/// ); -/// ``` -#[deprecated(note="Use std repeat_with() instead", since="0.8")] -pub fn repeat_call(function: F) -> RepeatCall - where F: FnMut() -> A -{ - RepeatCall { f: function } -} - -impl Iterator for RepeatCall - where F: FnMut() -> A -{ - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - Some((self.f)()) - } - - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} - -/// Creates a new unfold source with the specified closure as the "iterator -/// function" and an initial state to eventually pass to the closure -/// -/// `unfold` is a general iterator builder: it has a mutable state value, -/// and a closure with access to the state that produces the next value. -/// -/// This more or less equivalent to a regular struct with an `Iterator` -/// implementation, and is useful for one-off iterators. -/// -/// ``` -/// // an iterator that yields sequential Fibonacci numbers, -/// // and stops at the maximum representable value. -/// -/// use itertools::unfold; -/// -/// let (mut x1, mut x2) = (1u32, 1u32); -/// let mut fibonacci = unfold((), move |_| { -/// // Attempt to get the next Fibonacci number -/// let next = x1.saturating_add(x2); -/// -/// // Shift left: ret <- x1 <- x2 <- next -/// let ret = x1; -/// x1 = x2; -/// x2 = next; -/// -/// // If addition has saturated at the maximum, we are finished -/// if ret == x1 && ret > 1 { -/// return None; -/// } -/// -/// Some(ret) -/// }); -/// -/// itertools::assert_equal(fibonacci.by_ref().take(8), -/// vec![1, 1, 2, 3, 5, 8, 13, 21]); -/// assert_eq!(fibonacci.last(), Some(2_971_215_073)) -/// ``` -pub fn unfold(initial_state: St, f: F) -> Unfold - where F: FnMut(&mut St) -> Option -{ - Unfold { - f: f, - state: initial_state, - } -} - -impl fmt::Debug for Unfold - where St: fmt::Debug, -{ - debug_fmt_fields!(Unfold, state); -} - -/// See [`unfold`](../fn.unfold.html) for more information. -#[derive(Clone)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct Unfold { - f: F, - /// Internal state that will be passed to the closure on the next iteration - pub state: St, -} - -impl Iterator for Unfold - where F: FnMut(&mut St) -> Option -{ - type Item = A; - - #[inline] - fn next(&mut self) -> Option { - (self.f)(&mut self.state) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - // no possible known bounds at this point - (0, None) - } -} - -/// An iterator that infinitely applies function to value and yields results. -/// -/// This `struct` is created by the [`iterate()`] function. See its documentation for more. -/// -/// [`iterate()`]: ../fn.iterate.html -#[derive(Clone)] -#[must_use = "iterators are lazy and do nothing unless consumed"] -pub struct Iterate { - state: St, - f: F, -} - -impl fmt::Debug for Iterate - where St: fmt::Debug, -{ - debug_fmt_fields!(Iterate, state); -} - -impl Iterator for Iterate - where F: FnMut(&St) -> St -{ - type Item = St; - - #[inline] - fn next(&mut self) -> Option { - let next_state = (self.f)(&self.state); - Some(mem::replace(&mut self.state, next_state)) - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - (usize::max_value(), None) - } -} - -/// Creates a new iterator that infinitely applies function to value and yields results. -/// -/// ``` -/// use itertools::iterate; -/// -/// itertools::assert_equal(iterate(1, |&i| i * 3).take(5), vec![1, 3, 9, 27, 81]); -/// ``` -pub fn iterate(initial_value: St, f: F) -> Iterate - where F: FnMut(&St) -> St -{ - Iterate { - state: initial_value, - f: f, - } -} diff --git a/vendor/itertools-0.8.2/src/tee.rs b/vendor/itertools-0.8.2/src/tee.rs deleted file mode 100644 index 77d261759d..0000000000 --- a/vendor/itertools-0.8.2/src/tee.rs +++ /dev/null @@ -1,78 +0,0 @@ -use super::size_hint; - -use std::cell::RefCell; -use std::collections::VecDeque; -use std::rc::Rc; - -/// Common buffer object for the two tee halves -#[derive(Debug)] -struct TeeBuffer { - backlog: VecDeque, - iter: I, - /// The owner field indicates which id should read from the backlog - owner: bool, -} - -/// One half of an iterator pair where both return the same elements. -/// -/// See [`.tee()`](../trait.Itertools.html#method.tee) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct Tee - where I: Iterator -{ - rcbuffer: Rc>>, - id: bool, -} - -pub fn new(iter: I) -> (Tee, Tee) - where I: Iterator -{ - let buffer = TeeBuffer{backlog: VecDeque::new(), iter: iter, owner: false}; - let t1 = Tee{rcbuffer: Rc::new(RefCell::new(buffer)), id: true}; - let t2 = Tee{rcbuffer: t1.rcbuffer.clone(), id: false}; - (t1, t2) -} - -impl Iterator for Tee - where I: Iterator, - I::Item: Clone -{ - type Item = I::Item; - fn next(&mut self) -> Option { - // .borrow_mut may fail here -- but only if the user has tied some kind of weird - // knot where the iterator refers back to itself. - let mut buffer = self.rcbuffer.borrow_mut(); - if buffer.owner == self.id { - match buffer.backlog.pop_front() { - None => {} - some_elt => return some_elt, - } - } - match buffer.iter.next() { - None => None, - Some(elt) => { - buffer.backlog.push_back(elt.clone()); - buffer.owner = !self.id; - Some(elt) - } - } - } - - fn size_hint(&self) -> (usize, Option) { - let buffer = self.rcbuffer.borrow(); - let sh = buffer.iter.size_hint(); - - if buffer.owner == self.id { - let log_len = buffer.backlog.len(); - size_hint::add_scalar(sh, log_len) - } else { - sh - } - } -} - -impl ExactSizeIterator for Tee - where I: ExactSizeIterator, - I::Item: Clone -{} diff --git a/vendor/itertools-0.8.2/src/tuple_impl.rs b/vendor/itertools-0.8.2/src/tuple_impl.rs deleted file mode 100644 index 0daa7800c1..0000000000 --- a/vendor/itertools-0.8.2/src/tuple_impl.rs +++ /dev/null @@ -1,266 +0,0 @@ -//! Some iterator that produces tuples - -use std::iter::Fuse; - -/// An iterator over a incomplete tuple. -/// -/// See [`.tuples()`](../trait.Itertools.html#method.tuples) and -/// [`Tuples::into_buffer()`](struct.Tuples.html#method.into_buffer). -#[derive(Debug)] -pub struct TupleBuffer - where T: TupleCollect -{ - cur: usize, - buf: T::Buffer, -} - -impl TupleBuffer - where T: TupleCollect -{ - fn new(buf: T::Buffer) -> Self { - TupleBuffer { - cur: 0, - buf: buf, - } - } -} - -impl Iterator for TupleBuffer - where T: TupleCollect -{ - type Item = T::Item; - - fn next(&mut self) -> Option { - let s = self.buf.as_mut(); - if let Some(ref mut item) = s.get_mut(self.cur) { - self.cur += 1; - item.take() - } else { - None - } - } - - fn size_hint(&self) -> (usize, Option) { - let buffer = &self.buf.as_ref()[self.cur..]; - let len = if buffer.len() == 0 { - 0 - } else { - buffer.iter() - .position(|x| x.is_none()) - .unwrap_or(buffer.len()) - }; - (len, Some(len)) - } -} - -impl ExactSizeIterator for TupleBuffer - where T: TupleCollect -{ -} - -/// An iterator that groups the items in tuples of a specific size. -/// -/// See [`.tuples()`](../trait.Itertools.html#method.tuples) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Tuples - where I: Iterator, - T: TupleCollect -{ - iter: Fuse, - buf: T::Buffer, -} - -/// Create a new tuples iterator. -pub fn tuples(iter: I) -> Tuples - where I: Iterator, - T: TupleCollect -{ - Tuples { - iter: iter.fuse(), - buf: Default::default(), - } -} - -impl Iterator for Tuples - where I: Iterator, - T: TupleCollect -{ - type Item = T; - - fn next(&mut self) -> Option { - T::collect_from_iter(&mut self.iter, &mut self.buf) - } -} - -impl Tuples - where I: Iterator, - T: TupleCollect -{ - /// Return a buffer with the produced items that was not enough to be grouped in a tuple. - /// - /// ``` - /// use itertools::Itertools; - /// - /// let mut iter = (0..5).tuples(); - /// assert_eq!(Some((0, 1, 2)), iter.next()); - /// assert_eq!(None, iter.next()); - /// itertools::assert_equal(vec![3, 4], iter.into_buffer()); - /// ``` - pub fn into_buffer(self) -> TupleBuffer { - TupleBuffer::new(self.buf) - } -} - - -/// An iterator over all contiguous windows that produces tuples of a specific size. -/// -/// See [`.tuple_windows()`](../trait.Itertools.html#method.tuple_windows) for more -/// information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -#[derive(Debug)] -pub struct TupleWindows - where I: Iterator, - T: TupleCollect -{ - iter: I, - last: Option, -} - -/// Create a new tuple windows iterator. -pub fn tuple_windows(mut iter: I) -> TupleWindows - where I: Iterator, - T: TupleCollect, - T::Item: Clone -{ - use std::iter::once; - - let mut last = None; - if T::num_items() != 1 { - // put in a duplicate item in front of the tuple; this simplifies - // .next() function. - if let Some(item) = iter.next() { - let iter = once(item.clone()).chain(once(item)).chain(&mut iter); - last = T::collect_from_iter_no_buf(iter); - } - } - - TupleWindows { - last: last, - iter: iter, - } -} - -impl Iterator for TupleWindows - where I: Iterator, - T: TupleCollect + Clone, - T::Item: Clone -{ - type Item = T; - - fn next(&mut self) -> Option { - if T::num_items() == 1 { - return T::collect_from_iter_no_buf(&mut self.iter) - } - if let Some(ref mut last) = self.last { - if let Some(new) = self.iter.next() { - last.left_shift_push(new); - return Some(last.clone()); - } - } - None - } -} - -pub trait TupleCollect: Sized { - type Item; - type Buffer: Default + AsRef<[Option]> + AsMut<[Option]>; - - fn collect_from_iter(iter: I, buf: &mut Self::Buffer) -> Option - where I: IntoIterator; - - fn collect_from_iter_no_buf(iter: I) -> Option - where I: IntoIterator; - - fn num_items() -> usize; - - fn left_shift_push(&mut self, item: Self::Item); -} - -macro_rules! impl_tuple_collect { - () => (); - ($N:expr; $A:ident ; $($X:ident),* ; $($Y:ident),* ; $($Y_rev:ident),*) => ( - impl<$A> TupleCollect for ($($X),*,) { - type Item = $A; - type Buffer = [Option<$A>; $N - 1]; - - #[allow(unused_assignments, unused_mut)] - fn collect_from_iter(iter: I, buf: &mut Self::Buffer) -> Option - where I: IntoIterator - { - let mut iter = iter.into_iter(); - $( - let mut $Y = None; - )* - - loop { - $( - $Y = iter.next(); - if $Y.is_none() { - break - } - )* - return Some(($($Y.unwrap()),*,)) - } - - let mut i = 0; - let mut s = buf.as_mut(); - $( - if i < s.len() { - s[i] = $Y; - i += 1; - } - )* - return None; - } - - #[allow(unused_assignments)] - fn collect_from_iter_no_buf(iter: I) -> Option - where I: IntoIterator - { - let mut iter = iter.into_iter(); - loop { - $( - let $Y = if let Some($Y) = iter.next() { - $Y - } else { - break; - }; - )* - return Some(($($Y),*,)) - } - - return None; - } - - fn num_items() -> usize { - $N - } - - fn left_shift_push(&mut self, item: $A) { - use std::mem::replace; - - let &mut ($(ref mut $Y),*,) = self; - let tmp = item; - $( - let tmp = replace($Y_rev, tmp); - )* - drop(tmp); - } - } - ) -} - -impl_tuple_collect!(1; A; A; a; a); -impl_tuple_collect!(2; A; A, A; a, b; b, a); -impl_tuple_collect!(3; A; A, A, A; a, b, c; c, b, a); -impl_tuple_collect!(4; A; A, A, A, A; a, b, c, d; d, c, b, a); diff --git a/vendor/itertools-0.8.2/src/unique_impl.rs b/vendor/itertools-0.8.2/src/unique_impl.rs deleted file mode 100644 index d9e7fd3dc8..0000000000 --- a/vendor/itertools-0.8.2/src/unique_impl.rs +++ /dev/null @@ -1,134 +0,0 @@ - -use std::collections::HashMap; -use std::collections::hash_map::{Entry}; -use std::hash::Hash; -use std::fmt; - -/// An iterator adapter to filter out duplicate elements. -/// -/// See [`.unique_by()`](../trait.Itertools.html#method.unique) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct UniqueBy { - iter: I, - // Use a hashmap for the entry API - used: HashMap, - f: F, -} - -impl fmt::Debug for UniqueBy - where I: Iterator + fmt::Debug, - V: fmt::Debug + Hash + Eq, -{ - debug_fmt_fields!(UniqueBy, iter, used); -} - -/// Create a new `UniqueBy` iterator. -pub fn unique_by(iter: I, f: F) -> UniqueBy - where V: Eq + Hash, - F: FnMut(&I::Item) -> V, - I: Iterator, -{ - UniqueBy { - iter: iter, - used: HashMap::new(), - f: f, - } -} - -// count the number of new unique keys in iterable (`used` is the set already seen) -fn count_new_keys(mut used: HashMap, iterable: I) -> usize - where I: IntoIterator, - K: Hash + Eq, -{ - let iter = iterable.into_iter(); - let current_used = used.len(); - used.extend(iter.map(|key| (key, ()))); - used.len() - current_used -} - -impl Iterator for UniqueBy - where I: Iterator, - V: Eq + Hash, - F: FnMut(&I::Item) -> V -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - while let Some(v) = self.iter.next() { - let key = (self.f)(&v); - if self.used.insert(key, ()).is_none() { - return Some(v); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, hi) = self.iter.size_hint(); - ((low > 0 && self.used.is_empty()) as usize, hi) - } - - fn count(self) -> usize { - let mut key_f = self.f; - count_new_keys(self.used, self.iter.map(move |elt| key_f(&elt))) - } -} - -impl Iterator for Unique - where I: Iterator, - I::Item: Eq + Hash + Clone -{ - type Item = I::Item; - - fn next(&mut self) -> Option { - while let Some(v) = self.iter.iter.next() { - if let Entry::Vacant(entry) = self.iter.used.entry(v) { - let elt = entry.key().clone(); - entry.insert(()); - return Some(elt); - } - } - None - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - let (low, hi) = self.iter.iter.size_hint(); - ((low > 0 && self.iter.used.is_empty()) as usize, hi) - } - - fn count(self) -> usize { - count_new_keys(self.iter.used, self.iter.iter) - } -} - -/// An iterator adapter to filter out duplicate elements. -/// -/// See [`.unique()`](../trait.Itertools.html#method.unique) for more information. -#[derive(Clone)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Unique { - iter: UniqueBy, -} - -impl fmt::Debug for Unique - where I: Iterator + fmt::Debug, - I::Item: Hash + Eq + fmt::Debug, -{ - debug_fmt_fields!(Unique, iter); -} - -pub fn unique(iter: I) -> Unique - where I: Iterator, - I::Item: Eq + Hash, -{ - Unique { - iter: UniqueBy { - iter: iter, - used: HashMap::new(), - f: (), - } - } -} diff --git a/vendor/itertools-0.8.2/src/with_position.rs b/vendor/itertools-0.8.2/src/with_position.rs deleted file mode 100644 index 2a7c2b8ad6..0000000000 --- a/vendor/itertools-0.8.2/src/with_position.rs +++ /dev/null @@ -1,90 +0,0 @@ -use std::iter::{Fuse,Peekable}; - -/// An iterator adaptor that wraps each element in an [`Position`](../enum.Position.html). -/// -/// Iterator element type is `Position`. -/// -/// See [`.with_position()`](../trait.Itertools.html#method.with_position) for more information. -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct WithPosition - where I: Iterator, -{ - handled_first: bool, - peekable: Peekable>, -} - -/// Create a new `WithPosition` iterator. -pub fn with_position(iter: I) -> WithPosition - where I: Iterator, -{ - WithPosition { - handled_first: false, - peekable: iter.fuse().peekable(), - } -} - -/// A value yielded by `WithPosition`. -/// Indicates the position of this element in the iterator results. -/// -/// See [`.with_position()`](trait.Itertools.html#method.with_position) for more information. -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Position { - /// This is the first element. - First(T), - /// This is neither the first nor the last element. - Middle(T), - /// This is the last element. - Last(T), - /// This is the only element. - Only(T), -} - -impl Position { - /// Return the inner value. - pub fn into_inner(self) -> T { - match self { - Position::First(x) | - Position::Middle(x) | - Position::Last(x) | - Position::Only(x) => x, - } - } -} - -impl Iterator for WithPosition { - type Item = Position; - - fn next(&mut self) -> Option { - match self.peekable.next() { - Some(item) => { - if !self.handled_first { - // Haven't seen the first item yet, and there is one to give. - self.handled_first = true; - // Peek to see if this is also the last item, - // in which case tag it as `Only`. - match self.peekable.peek() { - Some(_) => Some(Position::First(item)), - None => Some(Position::Only(item)), - } - } else { - // Have seen the first item, and there's something left. - // Peek to see if this is the last item. - match self.peekable.peek() { - Some(_) => Some(Position::Middle(item)), - None => Some(Position::Last(item)), - } - } - } - // Iterator is finished. - None => None, - } - } - - fn size_hint(&self) -> (usize, Option) { - self.peekable.size_hint() - } -} - -impl ExactSizeIterator for WithPosition - where I: ExactSizeIterator, -{ } diff --git a/vendor/itertools-0.8.2/src/zip_eq_impl.rs b/vendor/itertools-0.8.2/src/zip_eq_impl.rs deleted file mode 100644 index 857465da41..0000000000 --- a/vendor/itertools-0.8.2/src/zip_eq_impl.rs +++ /dev/null @@ -1,60 +0,0 @@ -use super::size_hint; - -/// An iterator which iterates two other iterators simultaneously -/// -/// See [`.zip_eq()`](../trait.Itertools.html#method.zip_eq) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct ZipEq { - a: I, - b: J, -} - -/// Iterate `i` and `j` in lock step. -/// -/// **Panics** if the iterators are not of the same length. -/// -/// `IntoIterator` enabled version of `i.zip_eq(j)`. -/// -/// ``` -/// use itertools::zip_eq; -/// -/// let data = [1, 2, 3, 4, 5]; -/// for (a, b) in zip_eq(&data[..data.len() - 1], &data[1..]) { -/// /* loop body */ -/// } -/// ``` -pub fn zip_eq(i: I, j: J) -> ZipEq - where I: IntoIterator, - J: IntoIterator -{ - ZipEq { - a: i.into_iter(), - b: j.into_iter(), - } -} - -impl Iterator for ZipEq - where I: Iterator, - J: Iterator -{ - type Item = (I::Item, J::Item); - - fn next(&mut self) -> Option { - match (self.a.next(), self.b.next()) { - (None, None) => None, - (Some(a), Some(b)) => Some((a, b)), - (None, Some(_)) | (Some(_), None) => - panic!("itertools: .zip_eq() reached end of one iterator before the other") - } - } - - fn size_hint(&self) -> (usize, Option) { - size_hint::min(self.a.size_hint(), self.b.size_hint()) - } -} - -impl ExactSizeIterator for ZipEq - where I: ExactSizeIterator, - J: ExactSizeIterator -{} diff --git a/vendor/itertools-0.8.2/src/zip_longest.rs b/vendor/itertools-0.8.2/src/zip_longest.rs deleted file mode 100644 index 68a381acee..0000000000 --- a/vendor/itertools-0.8.2/src/zip_longest.rs +++ /dev/null @@ -1,78 +0,0 @@ -use std::cmp::Ordering::{Equal, Greater, Less}; -use super::size_hint; -use std::iter::Fuse; - -use either_or_both::EitherOrBoth; - -// ZipLongest originally written by SimonSapin, -// and dedicated to itertools https://github.com/rust-lang/rust/pull/19283 - -/// An iterator which iterates two other iterators simultaneously -/// -/// This iterator is *fused*. -/// -/// See [`.zip_longest()`](../trait.Itertools.html#method.zip_longest) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct ZipLongest { - a: Fuse, - b: Fuse, -} - -/// Create a new `ZipLongest` iterator. -pub fn zip_longest(a: T, b: U) -> ZipLongest - where T: Iterator, - U: Iterator -{ - ZipLongest { - a: a.fuse(), - b: b.fuse(), - } -} - -impl Iterator for ZipLongest - where T: Iterator, - U: Iterator -{ - type Item = EitherOrBoth; - - #[inline] - fn next(&mut self) -> Option { - match (self.a.next(), self.b.next()) { - (None, None) => None, - (Some(a), None) => Some(EitherOrBoth::Left(a)), - (None, Some(b)) => Some(EitherOrBoth::Right(b)), - (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)), - } - } - - #[inline] - fn size_hint(&self) -> (usize, Option) { - size_hint::max(self.a.size_hint(), self.b.size_hint()) - } -} - -impl DoubleEndedIterator for ZipLongest - where T: DoubleEndedIterator + ExactSizeIterator, - U: DoubleEndedIterator + ExactSizeIterator -{ - #[inline] - fn next_back(&mut self) -> Option { - match self.a.len().cmp(&self.b.len()) { - Equal => match (self.a.next_back(), self.b.next_back()) { - (None, None) => None, - (Some(a), Some(b)) => Some(EitherOrBoth::Both(a, b)), - // These can only happen if .len() is inconsistent with .next_back() - (Some(a), None) => Some(EitherOrBoth::Left(a)), - (None, Some(b)) => Some(EitherOrBoth::Right(b)), - }, - Greater => self.a.next_back().map(EitherOrBoth::Left), - Less => self.b.next_back().map(EitherOrBoth::Right), - } - } -} - -impl ExactSizeIterator for ZipLongest - where T: ExactSizeIterator, - U: ExactSizeIterator -{} diff --git a/vendor/itertools-0.8.2/src/ziptuple.rs b/vendor/itertools-0.8.2/src/ziptuple.rs deleted file mode 100644 index 2dc3ea5e0b..0000000000 --- a/vendor/itertools-0.8.2/src/ziptuple.rs +++ /dev/null @@ -1,111 +0,0 @@ -use super::size_hint; - -/// See [`multizip`](../fn.multizip.html) for more information. -#[derive(Clone, Debug)] -#[must_use = "iterator adaptors are lazy and do nothing unless consumed"] -pub struct Zip { - t: T, -} - -/// An iterator that generalizes *.zip()* and allows running multiple iterators in lockstep. -/// -/// The iterator `Zip<(I, J, ..., M)>` is formed from a tuple of iterators (or values that -/// implement `IntoIterator`) and yields elements -/// until any of the subiterators yields `None`. -/// -/// The iterator element type is a tuple like like `(A, B, ..., E)` where `A` to `E` are the -/// element types of the subiterator. -/// -/// **Note:** The result of this macro is a value of a named type (`Zip<(I, J, -/// ..)>` of each component iterator `I, J, ...`) if each component iterator is -/// nameable. -/// -/// Prefer [`izip!()`] over `multizip` for the performance benefits of using the -/// standard library `.zip()`. Prefer `multizip` if a nameable type is needed. -/// -/// [`izip!()`]: macro.izip.html -/// -/// ``` -/// use itertools::multizip; -/// -/// // iterate over three sequences side-by-side -/// let mut results = [0, 0, 0, 0]; -/// let inputs = [3, 7, 9, 6]; -/// -/// for (r, index, input) in multizip((&mut results, 0..10, &inputs)) { -/// *r = index * 10 + input; -/// } -/// -/// assert_eq!(results, [0 + 3, 10 + 7, 29, 36]); -/// ``` -pub fn multizip(t: U) -> Zip - where Zip: From, - Zip: Iterator, -{ - Zip::from(t) -} - -macro_rules! impl_zip_iter { - ($($B:ident),*) => ( - #[allow(non_snake_case)] - impl<$($B: IntoIterator),*> From<($($B,)*)> for Zip<($($B::IntoIter,)*)> { - fn from(t: ($($B,)*)) -> Self { - let ($($B,)*) = t; - Zip { t: ($($B.into_iter(),)*) } - } - } - - #[allow(non_snake_case)] - #[allow(unused_assignments)] - impl<$($B),*> Iterator for Zip<($($B,)*)> - where - $( - $B: Iterator, - )* - { - type Item = ($($B::Item,)*); - - fn next(&mut self) -> Option - { - let ($(ref mut $B,)*) = self.t; - - // NOTE: Just like iter::Zip, we check the iterators - // for None in order. We may finish unevenly (some - // iterators gave n + 1 elements, some only n). - $( - let $B = match $B.next() { - None => return None, - Some(elt) => elt - }; - )* - Some(($($B,)*)) - } - - fn size_hint(&self) -> (usize, Option) - { - let sh = (::std::usize::MAX, None); - let ($(ref $B,)*) = self.t; - $( - let sh = size_hint::min($B.size_hint(), sh); - )* - sh - } - } - - #[allow(non_snake_case)] - impl<$($B),*> ExactSizeIterator for Zip<($($B,)*)> where - $( - $B: ExactSizeIterator, - )* - { } - ); -} - -impl_zip_iter!(A); -impl_zip_iter!(A, B); -impl_zip_iter!(A, B, C); -impl_zip_iter!(A, B, C, D); -impl_zip_iter!(A, B, C, D, E); -impl_zip_iter!(A, B, C, D, E, F); -impl_zip_iter!(A, B, C, D, E, F, G); -impl_zip_iter!(A, B, C, D, E, F, G, H); diff --git a/vendor/itertools-0.8.2/tests/adaptors_no_collect.rs b/vendor/itertools-0.8.2/tests/adaptors_no_collect.rs deleted file mode 100644 index 4da6fcf4e9..0000000000 --- a/vendor/itertools-0.8.2/tests/adaptors_no_collect.rs +++ /dev/null @@ -1,49 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; - -struct PanickingCounter { - curr: usize, - max: usize, -} - -impl Iterator for PanickingCounter { - type Item = (); - - fn next(&mut self) -> Option { - self.curr += 1; - - if self.curr == self.max { - panic!( - "Input iterator reached maximum of {} suggesting collection by adaptor", - self.max - ); - } - - Some(()) - } -} - -fn no_collect_test(to_adaptor: T) - where A: Iterator, T: Fn(PanickingCounter) -> A -{ - let counter = PanickingCounter { curr: 0, max: 10_000 }; - let adaptor = to_adaptor(counter); - - for _ in adaptor.take(5) {} -} - -#[test] -fn permutations_no_collect() { - no_collect_test(|iter| iter.permutations(5)) -} - -#[test] -fn combinations_no_collect() { - no_collect_test(|iter| iter.combinations(5)) -} - -#[test] -fn combinations_with_replacement_no_collect() { - no_collect_test(|iter| iter.combinations_with_replacement(5)) -} \ No newline at end of file diff --git a/vendor/itertools-0.8.2/tests/fold_specialization.rs b/vendor/itertools-0.8.2/tests/fold_specialization.rs deleted file mode 100644 index ac5d6a25dc..0000000000 --- a/vendor/itertools-0.8.2/tests/fold_specialization.rs +++ /dev/null @@ -1,15 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; - -#[test] -fn specialization_intersperse() { - let mut iter = (1..2).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); - - let mut iter = (1..3).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); - - let mut iter = (1..4).intersperse(0); - iter.clone().for_each(|x| assert_eq!(Some(x), iter.next())); -} diff --git a/vendor/itertools-0.8.2/tests/merge_join.rs b/vendor/itertools-0.8.2/tests/merge_join.rs deleted file mode 100644 index 41829202b8..0000000000 --- a/vendor/itertools-0.8.2/tests/merge_join.rs +++ /dev/null @@ -1,110 +0,0 @@ -extern crate itertools; - -use itertools::EitherOrBoth; -use itertools::free::merge_join_by; - -#[test] -fn empty() { - let left: Vec = vec![]; - let right: Vec = vec![]; - let expected_result: Vec> = vec![]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn left_only() { - let left: Vec = vec![1,2,3]; - let right: Vec = vec![]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Left(2), - EitherOrBoth::Left(3) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn right_only() { - let left: Vec = vec![]; - let right: Vec = vec![1,2,3]; - let expected_result: Vec> = vec![ - EitherOrBoth::Right(1), - EitherOrBoth::Right(2), - EitherOrBoth::Right(3) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn first_left_then_right() { - let left: Vec = vec![1,2,3]; - let right: Vec = vec![4,5,6]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Left(2), - EitherOrBoth::Left(3), - EitherOrBoth::Right(4), - EitherOrBoth::Right(5), - EitherOrBoth::Right(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn first_right_then_left() { - let left: Vec = vec![4,5,6]; - let right: Vec = vec![1,2,3]; - let expected_result: Vec> = vec![ - EitherOrBoth::Right(1), - EitherOrBoth::Right(2), - EitherOrBoth::Right(3), - EitherOrBoth::Left(4), - EitherOrBoth::Left(5), - EitherOrBoth::Left(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn interspersed_left_and_right() { - let left: Vec = vec![1,3,5]; - let right: Vec = vec![2,4,6]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Right(2), - EitherOrBoth::Left(3), - EitherOrBoth::Right(4), - EitherOrBoth::Left(5), - EitherOrBoth::Right(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} - -#[test] -fn overlapping_left_and_right() { - let left: Vec = vec![1,3,4,6]; - let right: Vec = vec![2,3,4,5]; - let expected_result: Vec> = vec![ - EitherOrBoth::Left(1), - EitherOrBoth::Right(2), - EitherOrBoth::Both(3, 3), - EitherOrBoth::Both(4, 4), - EitherOrBoth::Right(5), - EitherOrBoth::Left(6) - ]; - let actual_result = merge_join_by(left, right, |l, r| l.cmp(r)) - .collect::>(); - assert_eq!(expected_result, actual_result); -} diff --git a/vendor/itertools-0.8.2/tests/peeking_take_while.rs b/vendor/itertools-0.8.2/tests/peeking_take_while.rs deleted file mode 100644 index 45c76c2d5c..0000000000 --- a/vendor/itertools-0.8.2/tests/peeking_take_while.rs +++ /dev/null @@ -1,53 +0,0 @@ - -extern crate itertools; - -use itertools::Itertools; -use itertools::{put_back, put_back_n}; - -#[test] -fn peeking_take_while_peekable() { - let mut r = (0..10).peekable(); - r.peeking_take_while(|x| *x <= 3).count(); - assert_eq!(r.next(), Some(4)); -} - -#[test] -fn peeking_take_while_put_back() { - let mut r = put_back(0..10); - r.peeking_take_while(|x| *x <= 3).count(); - assert_eq!(r.next(), Some(4)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} - -#[test] -fn peeking_take_while_put_back_n() { - let mut r = put_back_n(6..10); - for elt in (0..6).rev() { - r.put_back(elt); - } - r.peeking_take_while(|x| *x <= 3).count(); - assert_eq!(r.next(), Some(4)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} - -#[test] -fn peeking_take_while_slice_iter() { - let v = [1, 2, 3, 4, 5, 6]; - let mut r = v.iter(); - r.peeking_take_while(|x| **x <= 3).count(); - assert_eq!(r.next(), Some(&4)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} - -#[test] -fn peeking_take_while_slice_iter_rev() { - let v = [1, 2, 3, 4, 5, 6]; - let mut r = v.iter().rev(); - r.peeking_take_while(|x| **x >= 3).count(); - assert_eq!(r.next(), Some(&2)); - r.peeking_take_while(|_| true).count(); - assert_eq!(r.next(), None); -} diff --git a/vendor/itertools-0.8.2/tests/quick.rs b/vendor/itertools-0.8.2/tests/quick.rs deleted file mode 100644 index 7767447268..0000000000 --- a/vendor/itertools-0.8.2/tests/quick.rs +++ /dev/null @@ -1,1161 +0,0 @@ -//! The purpose of these tests is to cover corner cases of iterators -//! and adaptors. -//! -//! In particular we test the tedious size_hint and exact size correctness. - -#[macro_use] extern crate itertools; - -extern crate quickcheck; -extern crate rand; - -use std::default::Default; - -use quickcheck as qc; -use std::ops::Range; -use std::cmp::{max, min, Ordering}; -use std::collections::HashSet; -use itertools::Itertools; -use itertools::{ - multizip, - EitherOrBoth, -}; -use itertools::free::{ - cloned, - enumerate, - multipeek, - put_back, - put_back_n, - rciter, - zip, - zip_eq, -}; - -use rand::Rng; -use rand::seq::SliceRandom; -use quickcheck::TestResult; - -/// Trait for size hint modifier types -trait HintKind: Copy + Send + qc::Arbitrary { - fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option); -} - -/// Exact size hint variant that leaves hints unchanged -#[derive(Clone, Copy, Debug)] -struct Exact {} - -impl HintKind for Exact { - fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option) { - org_hint - } -} - -impl qc::Arbitrary for Exact { - fn arbitrary(_: &mut G) -> Self { - Exact {} - } -} - -/// Inexact size hint variant to simulate imprecise (but valid) size hints -/// -/// Will always decrease the lower bound and increase the upper bound -/// of the size hint by set amounts. -#[derive(Clone, Copy, Debug)] -struct Inexact { - underestimate: usize, - overestimate: usize, -} - -impl HintKind for Inexact { - fn loosen_bounds(&self, org_hint: (usize, Option)) -> (usize, Option) { - let (org_lower, org_upper) = org_hint; - (org_lower.saturating_sub(self.underestimate), - org_upper.and_then(move |x| x.checked_add(self.overestimate))) - } -} - -impl qc::Arbitrary for Inexact { - fn arbitrary(g: &mut G) -> Self { - let ue_value = usize::arbitrary(g); - let oe_value = usize::arbitrary(g); - // Compensate for quickcheck using extreme values too rarely - let ue_choices = &[0, ue_value, usize::max_value()]; - let oe_choices = &[0, oe_value, usize::max_value()]; - Inexact { - underestimate: *ue_choices.choose(g).unwrap(), - overestimate: *oe_choices.choose(g).unwrap(), - } - } - - fn shrink(&self) -> Box> { - let underestimate_value = self.underestimate; - let overestimate_value = self.overestimate; - Box::new( - underestimate_value.shrink().flat_map(move |ue_value| - overestimate_value.shrink().map(move |oe_value| - Inexact { - underestimate: ue_value, - overestimate: oe_value, - } - ) - ) - ) - } -} - -/// Our base iterator that we can impl Arbitrary for -/// -/// By default we'll return inexact bounds estimates for size_hint -/// to make tests harder to pass. -/// -/// NOTE: Iter is tricky and is not fused, to help catch bugs. -/// At the end it will return None once, then return Some(0), -/// then return None again. -#[derive(Clone, Debug)] -struct Iter { - iterator: Range, - // fuse/done flag - fuse_flag: i32, - hint_kind: SK, -} - -impl Iter where HK: HintKind -{ - fn new(it: Range, hint_kind: HK) -> Self { - Iter { - iterator: it, - fuse_flag: 0, - hint_kind: hint_kind - } - } -} - -impl Iterator for Iter - where Range: Iterator, - as Iterator>::Item: Default, - HK: HintKind, -{ - type Item = as Iterator>::Item; - - fn next(&mut self) -> Option - { - let elt = self.iterator.next(); - if elt.is_none() { - self.fuse_flag += 1; - // check fuse flag - if self.fuse_flag == 2 { - return Some(Default::default()) - } - } - elt - } - - fn size_hint(&self) -> (usize, Option) - { - let org_hint = self.iterator.size_hint(); - self.hint_kind.loosen_bounds(org_hint) - } -} - -impl DoubleEndedIterator for Iter - where Range: DoubleEndedIterator, - as Iterator>::Item: Default, - HK: HintKind -{ - fn next_back(&mut self) -> Option { self.iterator.next_back() } -} - -impl ExactSizeIterator for Iter where Range: ExactSizeIterator, - as Iterator>::Item: Default, -{ } - -impl qc::Arbitrary for Iter - where T: qc::Arbitrary, - HK: HintKind, -{ - fn arbitrary(g: &mut G) -> Self - { - Iter::new(T::arbitrary(g)..T::arbitrary(g), HK::arbitrary(g)) - } - - fn shrink(&self) -> Box>> - { - let r = self.iterator.clone(); - let hint_kind = self.hint_kind; - Box::new( - r.start.shrink().flat_map(move |a| - r.end.shrink().map(move |b| - Iter::new(a.clone()..b, hint_kind) - ) - ) - ) - } -} - -/// A meta-iterator which yields `Iter`s whose start/endpoints are -/// increased or decreased linearly on each iteration. -#[derive(Clone, Debug)] -struct ShiftRange { - range_start: i32, - range_end: i32, - start_step: i32, - end_step: i32, - iter_count: u32, - hint_kind: HK, -} - -impl Iterator for ShiftRange where HK: HintKind { - type Item = Iter; - - fn next(&mut self) -> Option { - if self.iter_count == 0 { - return None; - } - - let iter = Iter::new(self.range_start..self.range_end, self.hint_kind); - - self.range_start += self.start_step; - self.range_end += self.end_step; - self.iter_count -= 1; - - Some(iter) - } -} - -impl ExactSizeIterator for ShiftRange { } - -impl qc::Arbitrary for ShiftRange - where HK: HintKind -{ - fn arbitrary(g: &mut G) -> Self { - const MAX_STARTING_RANGE_DIFF: i32 = 32; - const MAX_STEP_MODULO: i32 = 8; - const MAX_ITER_COUNT: u32 = 3; - - let range_start = qc::Arbitrary::arbitrary(g); - let range_end = range_start + g.gen_range(0, MAX_STARTING_RANGE_DIFF + 1); - let start_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1); - let end_step = g.gen_range(-MAX_STEP_MODULO, MAX_STEP_MODULO + 1); - let iter_count = g.gen_range(0, MAX_ITER_COUNT + 1); - let hint_kind = qc::Arbitrary::arbitrary(g); - - ShiftRange { - range_start: range_start, - range_end: range_end, - start_step: start_step, - end_step: end_step, - iter_count: iter_count, - hint_kind: hint_kind - } - } -} - -fn correct_count(get_it: F) -> bool -where - I: Iterator, - F: Fn() -> I -{ - let mut counts = vec![get_it().count()]; - - 'outer: loop { - let mut it = get_it(); - - for _ in 0..(counts.len() - 1) { - if let None = it.next() { - panic!("Iterator shouldn't be finished, may not be deterministic"); - } - } - - if let None = it.next() { - break 'outer; - } - - counts.push(it.count()); - } - - let total_actual_count = counts.len() - 1; - - for (i, returned_count) in counts.into_iter().enumerate() { - let actual_count = total_actual_count - i; - if actual_count != returned_count { - println!("Total iterations: {} True count: {} returned count: {}", i, actual_count, returned_count); - - return false; - } - } - - true -} - -fn correct_size_hint(mut it: I) -> bool { - // record size hint at each iteration - let initial_hint = it.size_hint(); - let mut hints = Vec::with_capacity(initial_hint.0 + 1); - hints.push(initial_hint); - while let Some(_) = it.next() { - hints.push(it.size_hint()) - } - - let mut true_count = hints.len(); // start off +1 too much - - // check all the size hints - for &(low, hi) in &hints { - true_count -= 1; - if low > true_count || - (hi.is_some() && hi.unwrap() < true_count) - { - println!("True size: {:?}, size hint: {:?}", true_count, (low, hi)); - //println!("All hints: {:?}", hints); - return false - } - } - true -} - -fn exact_size(mut it: I) -> bool { - // check every iteration - let (mut low, mut hi) = it.size_hint(); - if Some(low) != hi { return false; } - while let Some(_) = it.next() { - let (xlow, xhi) = it.size_hint(); - if low != xlow + 1 { return false; } - low = xlow; - hi = xhi; - if Some(low) != hi { return false; } - } - let (low, hi) = it.size_hint(); - low == 0 && hi == Some(0) -} - -// Exact size for this case, without ExactSizeIterator -fn exact_size_for_this(mut it: I) -> bool { - // check every iteration - let (mut low, mut hi) = it.size_hint(); - if Some(low) != hi { return false; } - while let Some(_) = it.next() { - let (xlow, xhi) = it.size_hint(); - if low != xlow + 1 { return false; } - low = xlow; - hi = xhi; - if Some(low) != hi { return false; } - } - let (low, hi) = it.size_hint(); - low == 0 && hi == Some(0) -} - -/* - * NOTE: Range is broken! - * (all signed ranges are) -#[quickcheck] -fn size_range_i8(a: Iter) -> bool { - exact_size(a) -} - -#[quickcheck] -fn size_range_i16(a: Iter) -> bool { - exact_size(a) -} - -#[quickcheck] -fn size_range_u8(a: Iter) -> bool { - exact_size(a) -} - */ - -macro_rules! quickcheck { - // accept several property function definitions - // The property functions can use pattern matching and `mut` as usual - // in the function arguments, but the functions can not be generic. - {$($(#$attr:tt)* fn $fn_name:ident($($arg:tt)*) -> $ret:ty { $($code:tt)* })*} => ( - $( - #[test] - $(#$attr)* - fn $fn_name() { - fn prop($($arg)*) -> $ret { - $($code)* - } - ::quickcheck::quickcheck(quickcheck!(@fn prop [] $($arg)*)); - } - )* - ); - // parse argument list (with patterns allowed) into prop as fn(_, _) -> _ - (@fn $f:ident [$($t:tt)*]) => { - $f as fn($($t),*) -> _ - }; - (@fn $f:ident [$($p:tt)*] : $($tail:tt)*) => { - quickcheck!(@fn $f [$($p)* _] $($tail)*) - }; - (@fn $f:ident [$($p:tt)*] $t:tt $($tail:tt)*) => { - quickcheck!(@fn $f [$($p)*] $($tail)*) - }; -} - -quickcheck! { - - fn size_product(a: Iter, b: Iter) -> bool { - correct_size_hint(a.cartesian_product(b)) - } - fn size_product3(a: Iter, b: Iter, c: Iter) -> bool { - correct_size_hint(iproduct!(a, b, c)) - } - - fn correct_cartesian_product3(a: Iter, b: Iter, c: Iter, - take_manual: usize) -> () - { - // test correctness of iproduct through regular iteration (take) - // and through fold. - let ac = a.clone(); - let br = &b.clone(); - let cr = &c.clone(); - let answer: Vec<_> = ac.flat_map(move |ea| br.clone().flat_map(move |eb| cr.clone().map(move |ec| (ea, eb, ec)))).collect(); - let mut product_iter = iproduct!(a, b, c); - let mut actual = Vec::new(); - - actual.extend((&mut product_iter).take(take_manual)); - if actual.len() == take_manual { - product_iter.fold((), |(), elt| actual.push(elt)); - } - assert_eq!(answer, actual); - } - - fn size_multi_product(a: ShiftRange) -> bool { - correct_size_hint(a.multi_cartesian_product()) - } - fn correct_multi_product3(a: ShiftRange, take_manual: usize) -> () { - // Fix no. of iterators at 3 - let a = ShiftRange { iter_count: 3, ..a }; - - // test correctness of MultiProduct through regular iteration (take) - // and through fold. - let mut iters = a.clone(); - let i0 = iters.next().unwrap(); - let i1r = &iters.next().unwrap(); - let i2r = &iters.next().unwrap(); - let answer: Vec<_> = i0.flat_map(move |ei0| i1r.clone().flat_map(move |ei1| i2r.clone().map(move |ei2| vec![ei0, ei1, ei2]))).collect(); - let mut multi_product = a.clone().multi_cartesian_product(); - let mut actual = Vec::new(); - - actual.extend((&mut multi_product).take(take_manual)); - if actual.len() == take_manual { - multi_product.fold((), |(), elt| actual.push(elt)); - } - assert_eq!(answer, actual); - - assert_eq!(answer.into_iter().last(), a.clone().multi_cartesian_product().last()); - } - - #[allow(deprecated)] - fn size_step(a: Iter, s: usize) -> bool { - let mut s = s; - if s == 0 { - s += 1; // never zero - } - let filt = a.clone().dedup(); - correct_size_hint(filt.step(s)) && - exact_size(a.step(s)) - } - - #[allow(deprecated)] - fn equal_step(a: Iter, s: usize) -> bool { - let mut s = s; - if s == 0 { - s += 1; // never zero - } - let mut i = 0; - itertools::equal(a.clone().step(s), a.filter(|_| { - let keep = i % s == 0; - i += 1; - keep - })) - } - - #[allow(deprecated)] - fn equal_step_vec(a: Vec, s: usize) -> bool { - let mut s = s; - if s == 0 { - s += 1; // never zero - } - let mut i = 0; - itertools::equal(a.iter().step(s), a.iter().filter(|_| { - let keep = i % s == 0; - i += 1; - keep - })) - } - - fn size_multipeek(a: Iter, s: u8) -> bool { - let mut it = multipeek(a); - // peek a few times - for _ in 0..s { - it.peek(); - } - exact_size(it) - } - - fn equal_merge(a: Vec, b: Vec) -> bool { - let mut sa = a.clone(); - let mut sb = b.clone(); - sa.sort(); - sb.sort(); - let mut merged = sa.clone(); - merged.extend(sb.iter().cloned()); - merged.sort(); - itertools::equal(&merged, sa.iter().merge(&sb)) - } - fn size_merge(a: Iter, b: Iter) -> bool { - correct_size_hint(a.merge(b)) - } - fn size_zip(a: Iter, b: Iter, c: Iter) -> bool { - let filt = a.clone().dedup(); - correct_size_hint(multizip((filt, b.clone(), c.clone()))) && - exact_size(multizip((a, b, c))) - } - fn size_zip_rc(a: Iter, b: Iter) -> bool { - let rc = rciter(a.clone()); - correct_size_hint(multizip((&rc, &rc, b))) - } - - fn size_zip_macro(a: Iter, b: Iter, c: Iter) -> bool { - let filt = a.clone().dedup(); - correct_size_hint(izip!(filt, b.clone(), c.clone())) && - exact_size(izip!(a, b, c)) - } - fn equal_kmerge(a: Vec, b: Vec, c: Vec) -> bool { - use itertools::free::kmerge; - let mut sa = a.clone(); - let mut sb = b.clone(); - let mut sc = c.clone(); - sa.sort(); - sb.sort(); - sc.sort(); - let mut merged = sa.clone(); - merged.extend(sb.iter().cloned()); - merged.extend(sc.iter().cloned()); - merged.sort(); - itertools::equal(merged.into_iter(), kmerge(vec![sa, sb, sc])) - } - - // Any number of input iterators - fn equal_kmerge_2(mut inputs: Vec>) -> bool { - use itertools::free::kmerge; - // sort the inputs - for input in &mut inputs { - input.sort(); - } - let mut merged = inputs.concat(); - merged.sort(); - itertools::equal(merged.into_iter(), kmerge(inputs)) - } - - // Any number of input iterators - fn equal_kmerge_by_ge(mut inputs: Vec>) -> bool { - // sort the inputs - for input in &mut inputs { - input.sort(); - input.reverse(); - } - let mut merged = inputs.concat(); - merged.sort(); - merged.reverse(); - itertools::equal(merged.into_iter(), - inputs.into_iter().kmerge_by(|x, y| x >= y)) - } - - // Any number of input iterators - fn equal_kmerge_by_lt(mut inputs: Vec>) -> bool { - // sort the inputs - for input in &mut inputs { - input.sort(); - } - let mut merged = inputs.concat(); - merged.sort(); - itertools::equal(merged.into_iter(), - inputs.into_iter().kmerge_by(|x, y| x < y)) - } - - // Any number of input iterators - fn equal_kmerge_by_le(mut inputs: Vec>) -> bool { - // sort the inputs - for input in &mut inputs { - input.sort(); - } - let mut merged = inputs.concat(); - merged.sort(); - itertools::equal(merged.into_iter(), - inputs.into_iter().kmerge_by(|x, y| x <= y)) - } - fn size_kmerge(a: Iter, b: Iter, c: Iter) -> bool { - use itertools::free::kmerge; - correct_size_hint(kmerge(vec![a, b, c])) - } - fn equal_zip_eq(a: Vec, b: Vec) -> bool { - let len = std::cmp::min(a.len(), b.len()); - let a = &a[..len]; - let b = &b[..len]; - itertools::equal(zip_eq(a, b), zip(a, b)) - } - fn size_zip_longest(a: Iter, b: Iter) -> bool { - let filt = a.clone().dedup(); - let filt2 = b.clone().dedup(); - correct_size_hint(filt.zip_longest(b.clone())) && - correct_size_hint(a.clone().zip_longest(filt2)) && - exact_size(a.zip_longest(b)) - } - fn size_2_zip_longest(a: Iter, b: Iter) -> bool { - let it = a.clone().zip_longest(b.clone()); - let jt = a.clone().zip_longest(b.clone()); - itertools::equal(a.clone(), - it.filter_map(|elt| match elt { - EitherOrBoth::Both(x, _) => Some(x), - EitherOrBoth::Left(x) => Some(x), - _ => None, - } - )) - && - itertools::equal(b.clone(), - jt.filter_map(|elt| match elt { - EitherOrBoth::Both(_, y) => Some(y), - EitherOrBoth::Right(y) => Some(y), - _ => None, - } - )) - } - fn size_interleave(a: Iter, b: Iter) -> bool { - correct_size_hint(a.interleave(b)) - } - fn exact_interleave(a: Iter, b: Iter) -> bool { - exact_size_for_this(a.interleave(b)) - } - fn size_interleave_shortest(a: Iter, b: Iter) -> bool { - correct_size_hint(a.interleave_shortest(b)) - } - fn exact_interleave_shortest(a: Vec<()>, b: Vec<()>) -> bool { - exact_size_for_this(a.iter().interleave_shortest(&b)) - } - fn size_intersperse(a: Iter, x: i16) -> bool { - correct_size_hint(a.intersperse(x)) - } - fn equal_intersperse(a: Vec, x: i32) -> bool { - let mut inter = false; - let mut i = 0; - for elt in a.iter().cloned().intersperse(x) { - if inter { - if elt != x { return false } - } else { - if elt != a[i] { return false } - i += 1; - } - inter = !inter; - } - true - } - - fn equal_combinations_2(a: Vec) -> bool { - let mut v = Vec::new(); - for (i, x) in enumerate(&a) { - for y in &a[i + 1..] { - v.push((x, y)); - } - } - itertools::equal(a.iter().tuple_combinations::<(_, _)>(), v) - } - - fn collect_tuple_matches_size(a: Iter) -> bool { - let size = a.clone().count(); - a.collect_tuple::<(_, _, _)>().is_some() == (size == 3) - } - - fn correct_permutations(vals: HashSet, k: usize) -> () { - // Test permutations only on iterators of distinct integers, to prevent - // false positives. - - const MAX_N: usize = 5; - - let n = min(vals.len(), MAX_N); - let vals: HashSet = vals.into_iter().take(n).collect(); - - let perms = vals.iter().permutations(k); - - let mut actual = HashSet::new(); - - for perm in perms { - assert_eq!(perm.len(), k); - - let all_items_valid = perm.iter().all(|p| vals.contains(p)); - assert!(all_items_valid, "perm contains value not from input: {:?}", perm); - - // Check that all perm items are distinct - let distinct_len = { - let perm_set: HashSet<_> = perm.iter().collect(); - perm_set.len() - }; - assert_eq!(perm.len(), distinct_len); - - // Check that the perm is new - assert!(actual.insert(perm.clone()), "perm already encountered: {:?}", perm); - } - } - - fn permutations_lexic_order(a: usize, b: usize) -> () { - let a = a % 6; - let b = b % 6; - - let n = max(a, b); - let k = min (a, b); - - let expected_first: Vec = (0..k).collect(); - let expected_last: Vec = ((n - k)..n).rev().collect(); - - let mut perms = (0..n).permutations(k); - - let mut curr_perm = match perms.next() { - Some(p) => p, - None => { return; } - }; - - assert_eq!(expected_first, curr_perm); - - while let Some(next_perm) = perms.next() { - assert!( - next_perm > curr_perm, - "next perm isn't greater-than current; next_perm={:?} curr_perm={:?} n={}", - next_perm, curr_perm, n - ); - - curr_perm = next_perm; - } - - assert_eq!(expected_last, curr_perm); - - } - - fn permutations_count(n: usize, k: usize) -> bool { - let n = n % 6; - - correct_count(|| (0..n).permutations(k)) - } - - fn permutations_size(a: Iter, k: usize) -> bool { - correct_size_hint(a.take(5).permutations(k)) - } - - fn permutations_k0_yields_once(n: usize) -> () { - let k = 0; - let expected: Vec> = vec![vec![]]; - let actual = (0..n).permutations(k).collect_vec(); - - assert_eq!(expected, actual); - } -} - -quickcheck! { - fn equal_dedup(a: Vec) -> bool { - let mut b = a.clone(); - b.dedup(); - itertools::equal(&b, a.iter().dedup()) - } -} - -quickcheck! { - fn equal_dedup_by(a: Vec<(i32, i32)>) -> bool { - let mut b = a.clone(); - b.dedup_by(|x, y| x.0==y.0); - itertools::equal(&b, a.iter().dedup_by(|x, y| x.0==y.0)) - } -} - -quickcheck! { - fn size_dedup(a: Vec) -> bool { - correct_size_hint(a.iter().dedup()) - } -} - -quickcheck! { - fn size_dedup_by(a: Vec<(i32, i32)>) -> bool { - correct_size_hint(a.iter().dedup_by(|x, y| x.0==y.0)) - } -} - -quickcheck! { - fn exact_repeatn((n, x): (usize, i32)) -> bool { - let it = itertools::repeat_n(x, n); - exact_size(it) - } -} - -quickcheck! { - fn size_put_back(a: Vec, x: Option) -> bool { - let mut it = put_back(a.into_iter()); - match x { - Some(t) => it.put_back(t), - None => {} - } - correct_size_hint(it) - } -} - -quickcheck! { - fn size_put_backn(a: Vec, b: Vec) -> bool { - let mut it = put_back_n(a.into_iter()); - for elt in b { - it.put_back(elt) - } - correct_size_hint(it) - } -} - -quickcheck! { - fn size_tee(a: Vec) -> bool { - let (mut t1, mut t2) = a.iter().tee(); - t1.next(); - t1.next(); - t2.next(); - exact_size(t1) && exact_size(t2) - } -} - -quickcheck! { - fn size_tee_2(a: Vec) -> bool { - let (mut t1, mut t2) = a.iter().dedup().tee(); - t1.next(); - t1.next(); - t2.next(); - correct_size_hint(t1) && correct_size_hint(t2) - } -} - -quickcheck! { - fn size_take_while_ref(a: Vec, stop: u8) -> bool { - correct_size_hint(a.iter().take_while_ref(|x| **x != stop)) - } -} - -quickcheck! { - fn equal_partition(a: Vec) -> bool { - let mut a = a; - let mut ap = a.clone(); - let split_index = itertools::partition(&mut ap, |x| *x >= 0); - let parted = (0..split_index).all(|i| ap[i] >= 0) && - (split_index..a.len()).all(|i| ap[i] < 0); - - a.sort(); - ap.sort(); - parted && (a == ap) - } -} - -quickcheck! { - fn size_combinations(it: Iter) -> bool { - correct_size_hint(it.tuple_combinations::<(_, _)>()) - } -} - -quickcheck! { - fn equal_combinations(it: Iter) -> bool { - let values = it.clone().collect_vec(); - let mut cmb = it.tuple_combinations(); - for i in 0..values.len() { - for j in i+1..values.len() { - let pair = (values[i], values[j]); - if pair != cmb.next().unwrap() { - return false; - } - } - } - cmb.next() == None - } -} - -quickcheck! { - fn size_pad_tail(it: Iter, pad: u8) -> bool { - correct_size_hint(it.clone().pad_using(pad as usize, |_| 0)) && - correct_size_hint(it.dropping(1).rev().pad_using(pad as usize, |_| 0)) - } -} - -quickcheck! { - fn size_pad_tail2(it: Iter, pad: u8) -> bool { - exact_size(it.pad_using(pad as usize, |_| 0)) - } -} - -quickcheck! { - fn size_unique(it: Iter) -> bool { - correct_size_hint(it.unique()) - } - - fn count_unique(it: Vec, take_first: u8) -> () { - let answer = { - let mut v = it.clone(); - v.sort(); v.dedup(); - v.len() - }; - let mut iter = cloned(&it).unique(); - let first_count = (&mut iter).take(take_first as usize).count(); - let rest_count = iter.count(); - assert_eq!(answer, first_count + rest_count); - } -} - -quickcheck! { - fn fuzz_group_by_lazy_1(it: Iter) -> bool { - let jt = it.clone(); - let groups = it.group_by(|k| *k); - let res = itertools::equal(jt, groups.into_iter().flat_map(|(_, x)| x)); - res - } -} - -quickcheck! { - fn fuzz_group_by_lazy_2(data: Vec) -> bool { - let groups = data.iter().group_by(|k| *k / 10); - let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x)); - res - } -} - -quickcheck! { - fn fuzz_group_by_lazy_3(data: Vec) -> bool { - let grouper = data.iter().group_by(|k| *k / 10); - let groups = grouper.into_iter().collect_vec(); - let res = itertools::equal(data.iter(), groups.into_iter().flat_map(|(_, x)| x)); - res - } -} - -quickcheck! { - fn fuzz_group_by_lazy_duo(data: Vec, order: Vec<(bool, bool)>) -> bool { - let grouper = data.iter().group_by(|k| *k / 3); - let mut groups1 = grouper.into_iter(); - let mut groups2 = grouper.into_iter(); - let mut elts = Vec::<&u8>::new(); - let mut old_groups = Vec::new(); - - let tup1 = |(_, b)| b; - for &(ord, consume_now) in &order { - let iter = &mut [&mut groups1, &mut groups2][ord as usize]; - match iter.next() { - Some((_, gr)) => if consume_now { - for og in old_groups.drain(..) { - elts.extend(og); - } - elts.extend(gr); - } else { - old_groups.push(gr); - }, - None => break, - } - } - for og in old_groups.drain(..) { - elts.extend(og); - } - for gr in groups1.map(&tup1) { elts.extend(gr); } - for gr in groups2.map(&tup1) { elts.extend(gr); } - itertools::assert_equal(&data, elts); - true - } -} - -quickcheck! { - fn equal_chunks_lazy(a: Vec, size: u8) -> bool { - let mut size = size; - if size == 0 { - size += 1; - } - let chunks = a.iter().chunks(size as usize); - let it = a.chunks(size as usize); - for (a, b) in chunks.into_iter().zip(it) { - if !itertools::equal(a, b) { - return false; - } - } - true - } -} - -quickcheck! { - fn equal_tuple_windows_1(a: Vec) -> bool { - let x = a.windows(1).map(|s| (&s[0], )); - let y = a.iter().tuple_windows::<(_,)>(); - itertools::equal(x, y) - } - - fn equal_tuple_windows_2(a: Vec) -> bool { - let x = a.windows(2).map(|s| (&s[0], &s[1])); - let y = a.iter().tuple_windows::<(_, _)>(); - itertools::equal(x, y) - } - - fn equal_tuple_windows_3(a: Vec) -> bool { - let x = a.windows(3).map(|s| (&s[0], &s[1], &s[2])); - let y = a.iter().tuple_windows::<(_, _, _)>(); - itertools::equal(x, y) - } - - fn equal_tuple_windows_4(a: Vec) -> bool { - let x = a.windows(4).map(|s| (&s[0], &s[1], &s[2], &s[3])); - let y = a.iter().tuple_windows::<(_, _, _, _)>(); - itertools::equal(x, y) - } - - fn equal_tuples_1(a: Vec) -> bool { - let x = a.chunks(1).map(|s| (&s[0], )); - let y = a.iter().tuples::<(_,)>(); - itertools::equal(x, y) - } - - fn equal_tuples_2(a: Vec) -> bool { - let x = a.chunks(2).filter(|s| s.len() == 2).map(|s| (&s[0], &s[1])); - let y = a.iter().tuples::<(_, _)>(); - itertools::equal(x, y) - } - - fn equal_tuples_3(a: Vec) -> bool { - let x = a.chunks(3).filter(|s| s.len() == 3).map(|s| (&s[0], &s[1], &s[2])); - let y = a.iter().tuples::<(_, _, _)>(); - itertools::equal(x, y) - } - - fn equal_tuples_4(a: Vec) -> bool { - let x = a.chunks(4).filter(|s| s.len() == 4).map(|s| (&s[0], &s[1], &s[2], &s[3])); - let y = a.iter().tuples::<(_, _, _, _)>(); - itertools::equal(x, y) - } - - fn exact_tuple_buffer(a: Vec) -> bool { - let mut iter = a.iter().tuples::<(_, _, _, _)>(); - (&mut iter).last(); - let buffer = iter.into_buffer(); - assert_eq!(buffer.len(), a.len() % 4); - exact_size(buffer) - } -} - -// with_position -quickcheck! { - fn with_position_exact_size_1(a: Vec) -> bool { - exact_size_for_this(a.iter().with_position()) - } - fn with_position_exact_size_2(a: Iter) -> bool { - exact_size_for_this(a.with_position()) - } -} - -quickcheck! { - fn correct_group_map_modulo_key(a: Vec, modulo: u8) -> () { - let modulo = if modulo == 0 { 1 } else { modulo }; // Avoid `% 0` - let count = a.len(); - let lookup = a.into_iter().map(|i| (i % modulo, i)).into_group_map(); - - assert_eq!(lookup.values().flat_map(|vals| vals.iter()).count(), count); - - for (&key, vals) in lookup.iter() { - assert!(vals.iter().all(|&val| val % modulo == key)); - } - } -} - -/// A peculiar type: Equality compares both tuple items, but ordering only the -/// first item. This is so we can check the stability property easily. -#[derive(Clone, Debug, PartialEq, Eq)] -struct Val(u32, u32); - -impl PartialOrd for Val { - fn partial_cmp(&self, other: &Val) -> Option { - self.0.partial_cmp(&other.0) - } -} - -impl Ord for Val { - fn cmp(&self, other: &Val) -> Ordering { - self.0.cmp(&other.0) - } -} - -impl qc::Arbitrary for Val { - fn arbitrary(g: &mut G) -> Self { - let (x, y) = <(u32, u32)>::arbitrary(g); - Val(x, y) - } - fn shrink(&self) -> Box> { - Box::new((self.0, self.1).shrink().map(|(x, y)| Val(x, y))) - } -} - -quickcheck! { - fn minmax(a: Vec) -> bool { - use itertools::MinMaxResult; - - - let minmax = a.iter().minmax(); - let expected = match a.len() { - 0 => MinMaxResult::NoElements, - 1 => MinMaxResult::OneElement(&a[0]), - _ => MinMaxResult::MinMax(a.iter().min().unwrap(), - a.iter().max().unwrap()), - }; - minmax == expected - } -} - -quickcheck! { - fn minmax_f64(a: Vec) -> TestResult { - use itertools::MinMaxResult; - - if a.iter().any(|x| x.is_nan()) { - return TestResult::discard(); - } - - let min = cloned(&a).fold1(f64::min); - let max = cloned(&a).fold1(f64::max); - - let minmax = cloned(&a).minmax(); - let expected = match a.len() { - 0 => MinMaxResult::NoElements, - 1 => MinMaxResult::OneElement(min.unwrap()), - _ => MinMaxResult::MinMax(min.unwrap(), max.unwrap()), - }; - TestResult::from_bool(minmax == expected) - } -} - -quickcheck! { - #[allow(deprecated)] - fn tree_fold1_f64(mut a: Vec) -> TestResult { - fn collapse_adjacent(x: Vec, mut f: F) -> Vec - where F: FnMut(f64, f64) -> f64 - { - let mut out = Vec::new(); - for i in (0..x.len()).step(2) { - if i == x.len()-1 { - out.push(x[i]) - } else { - out.push(f(x[i], x[i+1])); - } - } - out - } - - if a.iter().any(|x| x.is_nan()) { - return TestResult::discard(); - } - - let actual = a.iter().cloned().tree_fold1(f64::atan2); - - while a.len() > 1 { - a = collapse_adjacent(a, f64::atan2); - } - let expected = a.pop(); - - TestResult::from_bool(actual == expected) - } -} - -quickcheck! { - fn exactly_one_i32(a: Vec) -> TestResult { - let ret = a.iter().cloned().exactly_one(); - match a.len() { - 1 => TestResult::from_bool(ret.unwrap() == a[0]), - _ => TestResult::from_bool(ret.unwrap_err().eq(a.iter().cloned())), - } - } -} diff --git a/vendor/itertools-0.8.2/tests/test_core.rs b/vendor/itertools-0.8.2/tests/test_core.rs deleted file mode 100644 index b1e03cf672..0000000000 --- a/vendor/itertools-0.8.2/tests/test_core.rs +++ /dev/null @@ -1,272 +0,0 @@ -//! Licensed under the Apache License, Version 2.0 -//! http://www.apache.org/licenses/LICENSE-2.0 or the MIT license -//! http://opensource.org/licenses/MIT, at your -//! option. This file may not be copied, modified, or distributed -//! except according to those terms. -#![no_std] - -#[macro_use] extern crate itertools as it; - -use core::iter; - -use it::Itertools; -use it::interleave; -use it::multizip; -use it::free::put_back; - -#[test] -fn product2() { - let s = "αβ"; - - let mut prod = iproduct!(s.chars(), 0..2); - assert!(prod.next() == Some(('α', 0))); - assert!(prod.next() == Some(('α', 1))); - assert!(prod.next() == Some(('β', 0))); - assert!(prod.next() == Some(('β', 1))); - assert!(prod.next() == None); -} - -#[test] -fn product_temporary() { - for (_x, _y, _z) in iproduct!( - [0, 1, 2].iter().cloned(), - [0, 1, 2].iter().cloned(), - [0, 1, 2].iter().cloned()) - { - // ok - } -} - - -#[test] -fn izip_macro() { - let mut zip = izip!(2..3); - assert!(zip.next() == Some(2)); - assert!(zip.next().is_none()); - - let mut zip = izip!(0..3, 0..2, 0..2i8); - for i in 0..2 { - assert!((i as usize, i, i as i8) == zip.next().unwrap()); - } - assert!(zip.next().is_none()); - - let xs: [isize; 0] = []; - let mut zip = izip!(0..3, 0..2, 0..2i8, &xs); - assert!(zip.next().is_none()); -} - -#[test] -fn izip2() { - let _zip1: iter::Zip<_, _> = izip!(1.., 2..); - let _zip2: iter::Zip<_, _> = izip!(1.., 2.., ); -} - -#[test] -fn izip3() { - let mut zip: iter::Map, _> = izip!(0..3, 0..2, 0..2i8); - for i in 0..2 { - assert!((i as usize, i, i as i8) == zip.next().unwrap()); - } - assert!(zip.next().is_none()); -} - -#[test] -fn multizip3() { - let mut zip = multizip((0..3, 0..2, 0..2i8)); - for i in 0..2 { - assert!((i as usize, i, i as i8) == zip.next().unwrap()); - } - assert!(zip.next().is_none()); - - let xs: [isize; 0] = []; - let mut zip = multizip((0..3, 0..2, 0..2i8, xs.iter())); - assert!(zip.next().is_none()); - - for (_, _, _, _, _) in multizip((0..3, 0..2, xs.iter(), &xs, xs.to_vec())) { - /* test compiles */ - } -} - -#[test] -fn write_to() { - let xs = [7, 9, 8]; - let mut ys = [0; 5]; - let cnt = ys.iter_mut().set_from(xs.iter().map(|x| *x)); - assert!(cnt == xs.len()); - assert!(ys == [7, 9, 8, 0, 0]); - - let cnt = ys.iter_mut().set_from(0..10); - assert!(cnt == ys.len()); - assert!(ys == [0, 1, 2, 3, 4]); -} - -#[test] -fn test_interleave() { - let xs: [u8; 0] = []; - let ys = [7u8, 9, 8, 10]; - let zs = [2u8, 77]; - let it = interleave(xs.iter(), ys.iter()); - it::assert_equal(it, ys.iter()); - - let rs = [7u8, 2, 9, 77, 8, 10]; - let it = interleave(ys.iter(), zs.iter()); - it::assert_equal(it, rs.iter()); -} - -#[allow(deprecated)] -#[test] -fn foreach() { - let xs = [1i32, 2, 3]; - let mut sum = 0; - xs.iter().foreach(|elt| sum += *elt); - assert!(sum == 6); -} - -#[test] -fn dropping() { - let xs = [1, 2, 3]; - let mut it = xs.iter().dropping(2); - assert_eq!(it.next(), Some(&3)); - assert!(it.next().is_none()); - let mut it = xs.iter().dropping(5); - assert!(it.next().is_none()); -} - -#[test] -fn batching() { - let xs = [0, 1, 2, 1, 3]; - let ys = [(0, 1), (2, 1)]; - - // An iterator that gathers elements up in pairs - let pit = xs.iter().cloned().batching(|it| { - match it.next() { - None => None, - Some(x) => match it.next() { - None => None, - Some(y) => Some((x, y)), - } - } - }); - it::assert_equal(pit, ys.iter().cloned()); -} - -#[test] -fn test_put_back() { - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let mut pb = put_back(xs.iter().cloned()); - pb.next(); - pb.put_back(1); - pb.put_back(0); - it::assert_equal(pb, xs.iter().cloned()); -} - -#[allow(deprecated)] -#[test] -fn step() { - it::assert_equal((0..10).step(1), 0..10); - it::assert_equal((0..10).step(2), (0..10).filter(|x: &i32| *x % 2 == 0)); - it::assert_equal((0..10).step(10), 0..1); -} - -#[allow(deprecated)] -#[test] -fn merge() { - it::assert_equal((0..10).step(2).merge((1..10).step(2)), 0..10); -} - - -#[test] -fn repeatn() { - let s = "α"; - let mut it = it::repeat_n(s, 3); - assert_eq!(it.len(), 3); - assert_eq!(it.next(), Some(s)); - assert_eq!(it.next(), Some(s)); - assert_eq!(it.next(), Some(s)); - assert_eq!(it.next(), None); - assert_eq!(it.next(), None); -} - -#[test] -fn count_clones() { - // Check that RepeatN only clones N - 1 times. - - use core::cell::Cell; - #[derive(PartialEq, Debug)] - struct Foo { - n: Cell - } - - impl Clone for Foo - { - fn clone(&self) -> Self - { - let n = self.n.get(); - self.n.set(n + 1); - Foo { n: Cell::new(n + 1) } - } - } - - - for n in 0..10 { - let f = Foo{n: Cell::new(0)}; - let it = it::repeat_n(f, n); - // drain it - let last = it.last(); - if n == 0 { - assert_eq!(last, None); - } else { - assert_eq!(last, Some(Foo{n: Cell::new(n - 1)})); - } - } -} - -#[test] -fn part() { - let mut data = [7, 1, 1, 9, 1, 1, 3]; - let i = it::partition(&mut data, |elt| *elt >= 3); - assert_eq!(i, 3); - assert_eq!(data, [7, 3, 9, 1, 1, 1, 1]); - - let i = it::partition(&mut data, |elt| *elt == 1); - assert_eq!(i, 4); - assert_eq!(data, [1, 1, 1, 1, 9, 3, 7]); - - let mut data = [1, 2, 3, 4, 5, 6, 7, 8, 9]; - let i = it::partition(&mut data, |elt| *elt % 3 == 0); - assert_eq!(i, 3); - assert_eq!(data, [9, 6, 3, 4, 5, 2, 7, 8, 1]); -} - -#[test] -fn tree_fold1() { - for i in 0..100 { - assert_eq!((0..i).tree_fold1(|x, y| x + y), (0..i).fold1(|x, y| x + y)); - } -} - -#[test] -fn exactly_one() { - assert_eq!((0..10).filter(|&x| x == 2).exactly_one().unwrap(), 2); - assert!((0..10).filter(|&x| x > 1 && x < 4).exactly_one().unwrap_err().eq(2..4)); - assert!((0..10).filter(|&x| x > 1 && x < 5).exactly_one().unwrap_err().eq(2..5)); - assert!((0..10).filter(|&_| false).exactly_one().unwrap_err().eq(0..0)); -} - -#[test] -fn sum1() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..0].iter().cloned().sum1::(), None); - assert_eq!(v[1..2].iter().cloned().sum1::(), Some(1)); - assert_eq!(v[1..3].iter().cloned().sum1::(), Some(3)); - assert_eq!(v.iter().cloned().sum1::(), Some(55)); -} - -#[test] -fn product1() { - let v: &[i32] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - assert_eq!(v[..0].iter().cloned().product1::(), None); - assert_eq!(v[..1].iter().cloned().product1::(), Some(0)); - assert_eq!(v[1..3].iter().cloned().product1::(), Some(2)); - assert_eq!(v[1..5].iter().cloned().product1::(), Some(24)); -} diff --git a/vendor/itertools-0.8.2/tests/test_std.rs b/vendor/itertools-0.8.2/tests/test_std.rs deleted file mode 100644 index 4f48c55cf3..0000000000 --- a/vendor/itertools-0.8.2/tests/test_std.rs +++ /dev/null @@ -1,781 +0,0 @@ - -#[macro_use] extern crate itertools as it; -extern crate permutohedron; - -use it::Itertools; -use it::multizip; -use it::multipeek; -use it::free::rciter; -use it::free::put_back_n; -use it::FoldWhile; -use it::cloned; - -#[test] -fn product3() { - let prod = iproduct!(0..3, 0..2, 0..2); - assert_eq!(prod.size_hint(), (12, Some(12))); - let v = prod.collect_vec(); - for i in 0..3 { - for j in 0..2 { - for k in 0..2 { - assert!((i, j, k) == v[(i * 2 * 2 + j * 2 + k) as usize]); - } - } - } - for (_, _, _, _) in iproduct!(0..3, 0..2, 0..2, 0..3) { - /* test compiles */ - } -} - -#[test] -fn interleave_shortest() { - let v0: Vec = vec![0, 2, 4]; - let v1: Vec = vec![1, 3, 5, 7]; - let it = v0.into_iter().interleave_shortest(v1.into_iter()); - assert_eq!(it.size_hint(), (6, Some(6))); - assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5]); - - let v0: Vec = vec![0, 2, 4, 6, 8]; - let v1: Vec = vec![1, 3, 5]; - let it = v0.into_iter().interleave_shortest(v1.into_iter()); - assert_eq!(it.size_hint(), (7, Some(7))); - assert_eq!(it.collect_vec(), vec![0, 1, 2, 3, 4, 5, 6]); - - let i0 = ::std::iter::repeat(0); - let v1: Vec<_> = vec![1, 3, 5]; - let it = i0.interleave_shortest(v1.into_iter()); - assert_eq!(it.size_hint(), (7, Some(7))); - - let v0: Vec<_> = vec![0, 2, 4]; - let i1 = ::std::iter::repeat(1); - let it = v0.into_iter().interleave_shortest(i1); - assert_eq!(it.size_hint(), (6, Some(6))); -} - - -#[test] -fn unique_by() { - let xs = ["aaa", "bbbbb", "aa", "ccc", "bbbb", "aaaaa", "cccc"]; - let ys = ["aaa", "bbbbb", "ccc"]; - it::assert_equal(ys.iter(), xs.iter().unique_by(|x| x[..2].to_string())); -} - -#[test] -fn unique() { - let xs = [0, 1, 2, 3, 2, 1, 3]; - let ys = [0, 1, 2, 3]; - it::assert_equal(ys.iter(), xs.iter().unique()); - let xs = [0, 1]; - let ys = [0, 1]; - it::assert_equal(ys.iter(), xs.iter().unique()); -} - -#[test] -fn intersperse() { - let xs = ["a", "", "b", "c"]; - let v: Vec<&str> = xs.iter().map(|x| x.clone()).intersperse(", ").collect(); - let text: String = v.concat(); - assert_eq!(text, "a, , b, c".to_string()); - - let ys = [0, 1, 2, 3]; - let mut it = ys[..0].iter().map(|x| *x).intersperse(1); - assert!(it.next() == None); -} - -#[test] -fn dedup() { - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let ys = [0, 1, 2, 1, 3]; - it::assert_equal(ys.iter(), xs.iter().dedup()); - let xs = [0, 0, 0, 0, 0]; - let ys = [0]; - it::assert_equal(ys.iter(), xs.iter().dedup()); - - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let ys = [0, 1, 2, 1, 3]; - let mut xs_d = Vec::new(); - xs.iter().dedup().fold((), |(), &elt| xs_d.push(elt)); - assert_eq!(&xs_d, &ys); -} - -#[test] -fn dedup_by() { - let xs = [(0, 0), (0, 1), (1, 1), (2, 1), (0, 2), (3, 1), (0, 3), (1, 3)]; - let ys = [(0, 0), (0, 1), (0, 2), (3, 1), (0, 3)]; - it::assert_equal(ys.iter(), xs.iter().dedup_by(|x, y| x.1==y.1)); - let xs = [(0, 1), (0, 2), (0, 3), (0, 4), (0, 5)]; - let ys = [(0, 1)]; - it::assert_equal(ys.iter(), xs.iter().dedup_by(|x, y| x.0==y.0)); - - let xs = [(0, 0), (0, 1), (1, 1), (2, 1), (0, 2), (3, 1), (0, 3), (1, 3)]; - let ys = [(0, 0), (0, 1), (0, 2), (3, 1), (0, 3)]; - let mut xs_d = Vec::new(); - xs.iter().dedup_by(|x, y| x.1==y.1).fold((), |(), &elt| xs_d.push(elt)); - assert_eq!(&xs_d, &ys); -} - -#[test] -fn all_equal() { - assert!("".chars().all_equal()); - assert!("A".chars().all_equal()); - assert!(!"AABBCCC".chars().all_equal()); - assert!("AAAAAAA".chars().all_equal()); - for (_key, mut sub) in &"AABBCCC".chars().group_by(|&x| x) { - assert!(sub.all_equal()); - } -} - -#[test] -fn test_put_back_n() { - let xs = [0, 1, 1, 1, 2, 1, 3, 3]; - let mut pb = put_back_n(xs.iter().cloned()); - pb.next(); - pb.next(); - pb.put_back(1); - pb.put_back(0); - it::assert_equal(pb, xs.iter().cloned()); -} - -#[test] -fn tee() { - let xs = [0, 1, 2, 3]; - let (mut t1, mut t2) = xs.iter().cloned().tee(); - assert_eq!(t1.next(), Some(0)); - assert_eq!(t2.next(), Some(0)); - assert_eq!(t1.next(), Some(1)); - assert_eq!(t1.next(), Some(2)); - assert_eq!(t1.next(), Some(3)); - assert_eq!(t1.next(), None); - assert_eq!(t2.next(), Some(1)); - assert_eq!(t2.next(), Some(2)); - assert_eq!(t1.next(), None); - assert_eq!(t2.next(), Some(3)); - assert_eq!(t2.next(), None); - assert_eq!(t1.next(), None); - assert_eq!(t2.next(), None); - - let (t1, t2) = xs.iter().cloned().tee(); - it::assert_equal(t1, xs.iter().cloned()); - it::assert_equal(t2, xs.iter().cloned()); - - let (t1, t2) = xs.iter().cloned().tee(); - it::assert_equal(t1.zip(t2), xs.iter().cloned().zip(xs.iter().cloned())); -} - - -#[test] -fn test_rciter() { - let xs = [0, 1, 1, 1, 2, 1, 3, 5, 6]; - - let mut r1 = rciter(xs.iter().cloned()); - let mut r2 = r1.clone(); - assert_eq!(r1.next(), Some(0)); - assert_eq!(r2.next(), Some(1)); - let mut z = r1.zip(r2); - assert_eq!(z.next(), Some((1, 1))); - assert_eq!(z.next(), Some((2, 1))); - assert_eq!(z.next(), Some((3, 5))); - assert_eq!(z.next(), None); - - // test intoiterator - let r1 = rciter(0..5); - let mut z = izip!(&r1, r1); - assert_eq!(z.next(), Some((0, 1))); -} - -#[allow(deprecated)] -#[test] -fn trait_pointers() { - struct ByRef<'r, I: ?Sized>(&'r mut I) where I: 'r; - - impl<'r, X, I: ?Sized> Iterator for ByRef<'r, I> where - I: 'r + Iterator - { - type Item = X; - fn next(&mut self) -> Option - { - self.0.next() - } - } - - let mut it = Box::new(0..10) as Box>; - assert_eq!(it.next(), Some(0)); - - { - /* make sure foreach works on non-Sized */ - let jt: &mut Iterator = &mut *it; - assert_eq!(jt.next(), Some(1)); - - { - let mut r = ByRef(jt); - assert_eq!(r.next(), Some(2)); - } - - assert_eq!(jt.find_position(|x| *x == 4), Some((1, 4))); - jt.foreach(|_| ()); - } -} - -#[test] -fn merge_by() { - let odd : Vec<(u32, &str)> = vec![(1, "hello"), (3, "world"), (5, "!")]; - let even = vec![(2, "foo"), (4, "bar"), (6, "baz")]; - let expected = vec![(1, "hello"), (2, "foo"), (3, "world"), (4, "bar"), (5, "!"), (6, "baz")]; - let results = odd.iter().merge_by(even.iter(), |a, b| a.0 <= b.0); - it::assert_equal(results, expected.iter()); -} - -#[test] -fn merge_by_btree() { - use std::collections::BTreeMap; - let mut bt1 = BTreeMap::new(); - bt1.insert("hello", 1); - bt1.insert("world", 3); - let mut bt2 = BTreeMap::new(); - bt2.insert("foo", 2); - bt2.insert("bar", 4); - let results = bt1.into_iter().merge_by(bt2.into_iter(), |a, b| a.0 <= b.0 ); - let expected = vec![("bar", 4), ("foo", 2), ("hello", 1), ("world", 3)]; - it::assert_equal(results, expected.into_iter()); -} - -#[allow(deprecated)] -#[test] -fn kmerge() { - let its = (0..4).map(|s| (s..10).step(4)); - - it::assert_equal(its.kmerge(), 0..10); -} - -#[allow(deprecated)] -#[test] -fn kmerge_2() { - let its = vec![3, 2, 1, 0].into_iter().map(|s| (s..10).step(4)); - - it::assert_equal(its.kmerge(), 0..10); -} - -#[test] -fn kmerge_empty() { - let its = (0..4).map(|_| 0..0); - assert_eq!(its.kmerge().next(), None); -} - -#[test] -fn kmerge_size_hint() { - let its = (0..5).map(|_| (0..10)); - assert_eq!(its.kmerge().size_hint(), (50, Some(50))); -} - -#[test] -fn kmerge_empty_size_hint() { - let its = (0..5).map(|_| (0..0)); - assert_eq!(its.kmerge().size_hint(), (0, Some(0))); -} - -#[test] -fn join() { - let many = [1, 2, 3]; - let one = [1]; - let none: Vec = vec![]; - - assert_eq!(many.iter().join(", "), "1, 2, 3"); - assert_eq!( one.iter().join(", "), "1"); - assert_eq!(none.iter().join(", "), ""); -} - -#[test] -fn sorted_by() { - let sc = [3, 4, 1, 2].iter().cloned().sorted_by(|&a, &b| { - a.cmp(&b) - }); - it::assert_equal(sc, vec![1, 2, 3, 4]); - - let v = (0..5).sorted_by(|&a, &b| a.cmp(&b).reverse()); - it::assert_equal(v, vec![4, 3, 2, 1, 0]); -} - -#[test] -fn sorted_by_key() { - let sc = [3, 4, 1, 2].iter().cloned().sorted_by_key(|&x| x); - it::assert_equal(sc, vec![1, 2, 3, 4]); - - let v = (0..5).sorted_by_key(|&x| -x); - it::assert_equal(v, vec![4, 3, 2, 1, 0]); -} - -#[test] -fn test_multipeek() { - let nums = vec![1u8,2,3,4,5]; - - let mp = multipeek(nums.iter().map(|&x| x)); - assert_eq!(nums, mp.collect::>()); - - let mut mp = multipeek(nums.iter().map(|&x| x)); - assert_eq!(mp.peek(), Some(&1)); - assert_eq!(mp.next(), Some(1)); - assert_eq!(mp.peek(), Some(&2)); - assert_eq!(mp.peek(), Some(&3)); - assert_eq!(mp.next(), Some(2)); - assert_eq!(mp.peek(), Some(&3)); - assert_eq!(mp.peek(), Some(&4)); - assert_eq!(mp.peek(), Some(&5)); - assert_eq!(mp.peek(), None); - assert_eq!(mp.next(), Some(3)); - assert_eq!(mp.next(), Some(4)); - assert_eq!(mp.peek(), Some(&5)); - assert_eq!(mp.peek(), None); - assert_eq!(mp.next(), Some(5)); - assert_eq!(mp.next(), None); - assert_eq!(mp.peek(), None); - -} - -#[test] -fn test_multipeek_reset() { - let data = [1, 2, 3, 4]; - - let mut mp = multipeek(cloned(&data)); - assert_eq!(mp.peek(), Some(&1)); - assert_eq!(mp.next(), Some(1)); - assert_eq!(mp.peek(), Some(&2)); - assert_eq!(mp.peek(), Some(&3)); - mp.reset_peek(); - assert_eq!(mp.peek(), Some(&2)); - assert_eq!(mp.next(), Some(2)); -} - -#[test] -fn test_multipeek_peeking_next() { - use it::PeekingNext; - let nums = vec![1u8,2,3,4,5,6,7]; - - let mut mp = multipeek(nums.iter().map(|&x| x)); - assert_eq!(mp.peeking_next(|&x| x != 0), Some(1)); - assert_eq!(mp.next(), Some(2)); - assert_eq!(mp.peek(), Some(&3)); - assert_eq!(mp.peek(), Some(&4)); - assert_eq!(mp.peeking_next(|&x| x == 3), Some(3)); - assert_eq!(mp.peek(), Some(&4)); - assert_eq!(mp.peeking_next(|&x| x != 4), None); - assert_eq!(mp.peeking_next(|&x| x == 4), Some(4)); - assert_eq!(mp.peek(), Some(&5)); - assert_eq!(mp.peek(), Some(&6)); - assert_eq!(mp.peeking_next(|&x| x != 5), None); - assert_eq!(mp.peek(), Some(&7)); - assert_eq!(mp.peeking_next(|&x| x == 5), Some(5)); - assert_eq!(mp.peeking_next(|&x| x == 6), Some(6)); - assert_eq!(mp.peek(), Some(&7)); - assert_eq!(mp.peek(), None); - assert_eq!(mp.next(), Some(7)); - assert_eq!(mp.peek(), None); -} - -#[test] -fn pad_using() { - it::assert_equal((0..0).pad_using(1, |_| 1), 1..2); - - let v: Vec = vec![0, 1, 2]; - let r = v.into_iter().pad_using(5, |n| n); - it::assert_equal(r, vec![0, 1, 2, 3, 4]); - - let v: Vec = vec![0, 1, 2]; - let r = v.into_iter().pad_using(1, |_| panic!()); - it::assert_equal(r, vec![0, 1, 2]); -} - -#[test] -fn group_by() { - for (ch1, sub) in &"AABBCCC".chars().group_by(|&x| x) { - for ch2 in sub { - assert_eq!(ch1, ch2); - } - } - - for (ch1, sub) in &"AAABBBCCCCDDDD".chars().group_by(|&x| x) { - for ch2 in sub { - assert_eq!(ch1, ch2); - if ch1 == 'C' { - break; - } - } - } - - let toupper = |ch: &char| ch.to_uppercase().nth(0).unwrap(); - - // try all possible orderings - for indices in permutohedron::Heap::new(&mut [0, 1, 2, 3]) { - let groups = "AaaBbbccCcDDDD".chars().group_by(&toupper); - let mut subs = groups.into_iter().collect_vec(); - - for &idx in &indices[..] { - let (key, text) = match idx { - 0 => ('A', "Aaa".chars()), - 1 => ('B', "Bbb".chars()), - 2 => ('C', "ccCc".chars()), - 3 => ('D', "DDDD".chars()), - _ => unreachable!(), - }; - assert_eq!(key, subs[idx].0); - it::assert_equal(&mut subs[idx].1, text); - } - } - - let groups = "AAABBBCCCCDDDD".chars().group_by(|&x| x); - let mut subs = groups.into_iter().map(|(_, g)| g).collect_vec(); - - let sd = subs.pop().unwrap(); - let sc = subs.pop().unwrap(); - let sb = subs.pop().unwrap(); - let sa = subs.pop().unwrap(); - for (a, b, c, d) in multizip((sa, sb, sc, sd)) { - assert_eq!(a, 'A'); - assert_eq!(b, 'B'); - assert_eq!(c, 'C'); - assert_eq!(d, 'D'); - } - - // check that the key closure is called exactly n times - { - let mut ntimes = 0; - let text = "AABCCC"; - for (_, sub) in &text.chars().group_by(|&x| { ntimes += 1; x}) { - for _ in sub { - } - } - assert_eq!(ntimes, text.len()); - } - - { - let mut ntimes = 0; - let text = "AABCCC"; - for _ in &text.chars().group_by(|&x| { ntimes += 1; x}) { - } - assert_eq!(ntimes, text.len()); - } - - { - let text = "ABCCCDEEFGHIJJKK"; - let gr = text.chars().group_by(|&x| x); - it::assert_equal(gr.into_iter().flat_map(|(_, sub)| sub), text.chars()); - } -} - -#[test] -fn group_by_lazy_2() { - let data = vec![0, 1]; - let groups = data.iter().group_by(|k| *k); - let gs = groups.into_iter().collect_vec(); - it::assert_equal(data.iter(), gs.into_iter().flat_map(|(_k, g)| g)); - - let data = vec![0, 1, 1, 0, 0]; - let groups = data.iter().group_by(|k| *k); - let mut gs = groups.into_iter().collect_vec(); - gs[1..].reverse(); - it::assert_equal(&[0, 0, 0, 1, 1], gs.into_iter().flat_map(|(_, g)| g)); - - let grouper = data.iter().group_by(|k| *k); - let mut groups = Vec::new(); - for (k, group) in &grouper { - if *k == 1 { - groups.push(group); - } - } - it::assert_equal(&mut groups[0], &[1, 1]); - - let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; - let grouper = data.iter().group_by(|k| *k); - let mut groups = Vec::new(); - for (i, (_, group)) in grouper.into_iter().enumerate() { - if i < 2 { - groups.push(group); - } else if i < 4 { - for _ in group { - } - } else { - groups.push(group); - } - } - it::assert_equal(&mut groups[0], &[0, 0, 0]); - it::assert_equal(&mut groups[1], &[1, 1]); - it::assert_equal(&mut groups[2], &[3, 3]); - - // use groups as chunks - let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; - let mut i = 0; - let grouper = data.iter().group_by(move |_| { let k = i / 3; i += 1; k }); - for (i, group) in &grouper { - match i { - 0 => it::assert_equal(group, &[0, 0, 0]), - 1 => it::assert_equal(group, &[1, 1, 0]), - 2 => it::assert_equal(group, &[0, 2, 2]), - 3 => it::assert_equal(group, &[3, 3]), - _ => unreachable!(), - } - } -} - -#[test] -fn group_by_lazy_3() { - // test consuming each group on the lap after it was produced - let data = vec![0, 0, 0, 1, 1, 0, 0, 1, 1, 2, 2]; - let grouper = data.iter().group_by(|elt| *elt); - let mut last = None; - for (key, group) in &grouper { - if let Some(gr) = last.take() { - for elt in gr { - assert!(elt != key && i32::abs(elt - key) == 1); - } - } - last = Some(group); - } -} - -#[test] -fn chunks() { - let data = vec![0, 0, 0, 1, 1, 0, 0, 2, 2, 3, 3]; - let grouper = data.iter().chunks(3); - for (i, chunk) in grouper.into_iter().enumerate() { - match i { - 0 => it::assert_equal(chunk, &[0, 0, 0]), - 1 => it::assert_equal(chunk, &[1, 1, 0]), - 2 => it::assert_equal(chunk, &[0, 2, 2]), - 3 => it::assert_equal(chunk, &[3, 3]), - _ => unreachable!(), - } - } -} - -#[test] -fn concat_empty() { - let data: Vec> = Vec::new(); - assert_eq!(data.into_iter().concat(), Vec::new()) -} - -#[test] -fn concat_non_empty() { - let data = vec![vec![1,2,3], vec![4,5,6], vec![7,8,9]]; - assert_eq!(data.into_iter().concat(), vec![1,2,3,4,5,6,7,8,9]) -} - -#[test] -fn combinations() { - assert!((1..3).combinations(5).next().is_none()); - - let it = (1..3).combinations(2); - it::assert_equal(it, vec![ - vec![1, 2], - ]); - - let it = (1..5).combinations(2); - it::assert_equal(it, vec![ - vec![1, 2], - vec![1, 3], - vec![1, 4], - vec![2, 3], - vec![2, 4], - vec![3, 4], - ]); - - it::assert_equal((0..0).tuple_combinations::<(_, _)>(), >::new()); - it::assert_equal((0..1).tuple_combinations::<(_, _)>(), >::new()); - it::assert_equal((0..2).tuple_combinations::<(_, _)>(), vec![(0, 1)]); - - it::assert_equal((0..0).combinations(2), >>::new()); - it::assert_equal((0..1).combinations(1), vec![vec![0]]); - it::assert_equal((0..2).combinations(1), vec![vec![0], vec![1]]); - it::assert_equal((0..2).combinations(2), vec![vec![0, 1]]); -} - -#[test] -fn combinations_of_too_short() { - for i in 1..10 { - assert!((0..0).combinations(i).next().is_none()); - assert!((0..i - 1).combinations(i).next().is_none()); - } -} - - -#[test] -fn combinations_zero() { - it::assert_equal((1..3).combinations(0), vec![vec![]]); -} - -#[test] -fn combinations_with_replacement() { - // Pool smaller than n - it::assert_equal((0..1).combinations_with_replacement(2), vec![vec![0, 0]]); - // Pool larger than n - it::assert_equal( - (0..3).combinations_with_replacement(2), - vec![ - vec![0, 0], - vec![0, 1], - vec![0, 2], - vec![1, 1], - vec![1, 2], - vec![2, 2], - ], - ); - // Zero size - it::assert_equal( - (0..3).combinations_with_replacement(0), - >>::new(), - ); - // Empty pool - it::assert_equal( - (0..0).combinations_with_replacement(2), - >>::new(), - ); -} - -#[test] -fn diff_mismatch() { - let a = vec![1, 2, 3, 4]; - let b = vec![1.0, 5.0, 3.0, 4.0]; - let b_map = b.into_iter().map(|f| f as i32); - let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); - - assert!(match diff { - Some(it::Diff::FirstMismatch(1, _, from_diff)) => - from_diff.collect::>() == vec![5, 3, 4], - _ => false, - }); -} - -#[test] -fn diff_longer() { - let a = vec![1, 2, 3, 4]; - let b = vec![1.0, 2.0, 3.0, 4.0, 5.0, 6.0]; - let b_map = b.into_iter().map(|f| f as i32); - let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); - - assert!(match diff { - Some(it::Diff::Longer(_, remaining)) => - remaining.collect::>() == vec![5, 6], - _ => false, - }); -} - -#[test] -fn diff_shorter() { - let a = vec![1, 2, 3, 4]; - let b = vec![1.0, 2.0]; - let b_map = b.into_iter().map(|f| f as i32); - let diff = it::diff_with(a.iter(), b_map, |a, b| *a == b); - - assert!(match diff { - Some(it::Diff::Shorter(len, _)) => len == 2, - _ => false, - }); -} - -#[test] -fn minmax() { - use std::cmp::Ordering; - use it::MinMaxResult; - - // A peculiar type: Equality compares both tuple items, but ordering only the - // first item. This is so we can check the stability property easily. - #[derive(Clone, Debug, PartialEq, Eq)] - struct Val(u32, u32); - - impl PartialOrd for Val { - fn partial_cmp(&self, other: &Val) -> Option { - self.0.partial_cmp(&other.0) - } - } - - impl Ord for Val { - fn cmp(&self, other: &Val) -> Ordering { - self.0.cmp(&other.0) - } - } - - assert_eq!(None::>.iter().minmax(), MinMaxResult::NoElements); - - assert_eq!(Some(1u32).iter().minmax(), MinMaxResult::OneElement(&1)); - - let data = vec![Val(0, 1), Val(2, 0), Val(0, 2), Val(1, 0), Val(2, 1)]; - - let minmax = data.iter().minmax(); - assert_eq!(minmax, MinMaxResult::MinMax(&Val(0, 1), &Val(2, 1))); - - let (min, max) = data.iter().minmax_by_key(|v| v.1).into_option().unwrap(); - assert_eq!(min, &Val(2, 0)); - assert_eq!(max, &Val(0, 2)); - - let (min, max) = data.iter().minmax_by(|x, y| x.1.cmp(&y.1)).into_option().unwrap(); - assert_eq!(min, &Val(2, 0)); - assert_eq!(max, &Val(0, 2)); -} - -#[test] -fn format() { - let data = [0, 1, 2, 3]; - let ans1 = "0, 1, 2, 3"; - let ans2 = "0--1--2--3"; - - let t1 = format!("{}", data.iter().format(", ")); - assert_eq!(t1, ans1); - let t2 = format!("{:?}", data.iter().format("--")); - assert_eq!(t2, ans2); - - let dataf = [1.1, 2.71828, -22.]; - let t3 = format!("{:.2e}", dataf.iter().format(", ")); - assert_eq!(t3, "1.10e0, 2.72e0, -2.20e1"); -} - -#[test] -fn while_some() { - let ns = (1..10).map(|x| if x % 5 != 0 { Some(x) } else { None }) - .while_some(); - it::assert_equal(ns, vec![1, 2, 3, 4]); -} - -#[allow(deprecated)] -#[test] -fn fold_while() { - let mut iterations = 0; - let vec = vec![1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; - let sum = vec.into_iter().fold_while(0, |acc, item| { - iterations += 1; - let new_sum = acc.clone() + item; - if new_sum <= 20 { - FoldWhile::Continue(new_sum) - } else { - FoldWhile::Done(acc) - } - }).into_inner(); - assert_eq!(iterations, 6); - assert_eq!(sum, 15); -} - -#[test] -fn tree_fold1() { - let x = [ - "", - "0", - "0 1 x", - "0 1 x 2 x", - "0 1 x 2 3 x x", - "0 1 x 2 3 x x 4 x", - "0 1 x 2 3 x x 4 5 x x", - "0 1 x 2 3 x x 4 5 x 6 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x 14 x x x", - "0 1 x 2 3 x x 4 5 x 6 7 x x x 8 9 x 10 11 x x 12 13 x 14 15 x x x x", - ]; - for (i, &s) in x.iter().enumerate() { - let expected = if s == "" { None } else { Some(s.to_string()) }; - let num_strings = (0..i).map(|x| x.to_string()); - let actual = num_strings.tree_fold1(|a, b| format!("{} {} x", a, b)); - assert_eq!(actual, expected); - } -} diff --git a/vendor/itertools-0.8.2/tests/tuples.rs b/vendor/itertools-0.8.2/tests/tuples.rs deleted file mode 100644 index 07dba57fe6..0000000000 --- a/vendor/itertools-0.8.2/tests/tuples.rs +++ /dev/null @@ -1,88 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; - -#[test] -fn tuples() { - let v = [1, 2, 3, 4, 5]; - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1,)), iter.next()); - assert_eq!(Some((2,)), iter.next()); - assert_eq!(Some((3,)), iter.next()); - assert_eq!(Some((4,)), iter.next()); - assert_eq!(Some((5,)), iter.next()); - assert_eq!(None, iter.next()); - assert_eq!(None, iter.into_buffer().next()); - - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1, 2)), iter.next()); - assert_eq!(Some((3, 4)), iter.next()); - assert_eq!(None, iter.next()); - itertools::assert_equal(vec![5], iter.into_buffer()); - - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1, 2, 3)), iter.next()); - assert_eq!(None, iter.next()); - itertools::assert_equal(vec![4, 5], iter.into_buffer()); - - let mut iter = v.iter().cloned().tuples(); - assert_eq!(Some((1, 2, 3, 4)), iter.next()); - assert_eq!(None, iter.next()); - itertools::assert_equal(vec![5], iter.into_buffer()); -} - -#[test] -fn tuple_windows() { - let v = [1, 2, 3, 4, 5]; - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1,)), iter.next()); - assert_eq!(Some((2,)), iter.next()); - assert_eq!(Some((3,)), iter.next()); - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1, 2)), iter.next()); - assert_eq!(Some((2, 3)), iter.next()); - assert_eq!(Some((3, 4)), iter.next()); - assert_eq!(Some((4, 5)), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1, 2, 3)), iter.next()); - assert_eq!(Some((2, 3, 4)), iter.next()); - assert_eq!(Some((3, 4, 5)), iter.next()); - assert_eq!(None, iter.next()); - - let mut iter = v.iter().cloned().tuple_windows(); - assert_eq!(Some((1, 2, 3, 4)), iter.next()); - assert_eq!(Some((2, 3, 4, 5)), iter.next()); - assert_eq!(None, iter.next()); - - let v = [1, 2, 3]; - let mut iter = v.iter().cloned().tuple_windows::<(_, _, _, _)>(); - assert_eq!(None, iter.next()); -} - -#[test] -fn next_tuple() { - let v = [1, 2, 3, 4, 5]; - let mut iter = v.iter(); - assert_eq!(iter.next_tuple().map(|(&x, &y)| (x, y)), Some((1, 2))); - assert_eq!(iter.next_tuple().map(|(&x, &y)| (x, y)), Some((3, 4))); - assert_eq!(iter.next_tuple::<(_, _)>(), None); -} - -#[test] -fn collect_tuple() { - let v = [1, 2]; - let iter = v.iter().cloned(); - assert_eq!(iter.collect_tuple(), Some((1, 2))); - - let v = [1]; - let iter = v.iter().cloned(); - assert_eq!(iter.collect_tuple::<(_, _)>(), None); - - let v = [1, 2, 3]; - let iter = v.iter().cloned(); - assert_eq!(iter.collect_tuple::<(_, _)>(), None); -} diff --git a/vendor/itertools-0.8.2/tests/zip.rs b/vendor/itertools-0.8.2/tests/zip.rs deleted file mode 100644 index c5c51899b8..0000000000 --- a/vendor/itertools-0.8.2/tests/zip.rs +++ /dev/null @@ -1,65 +0,0 @@ -extern crate itertools; - -use itertools::Itertools; -use itertools::EitherOrBoth::{Both, Left, Right}; -use itertools::free::zip_eq; - -#[test] -fn zip_longest_fused() { - let a = [Some(1), None, Some(3), Some(4)]; - let b = [1, 2, 3]; - - let unfused = a.iter().batching(|it| *it.next().unwrap()) - .zip_longest(b.iter().cloned()); - itertools::assert_equal(unfused, - vec![Both(1, 1), Right(2), Right(3)]); -} - -#[test] -fn test_zip_longest_size_hint() { - let c = (1..10).cycle(); - let v: &[_] = &[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]; - let v2 = &[10, 11, 12]; - - assert_eq!(c.zip_longest(v.iter()).size_hint(), (std::usize::MAX, None)); - - assert_eq!(v.iter().zip_longest(v2.iter()).size_hint(), (10, Some(10))); -} - -#[test] -fn test_double_ended_zip_longest() { - let xs = [1, 2, 3, 4, 5, 6]; - let ys = [1, 2, 3, 7]; - let a = xs.iter().map(|&x| x); - let b = ys.iter().map(|&x| x); - let mut it = a.zip_longest(b); - assert_eq!(it.next(), Some(Both(1, 1))); - assert_eq!(it.next(), Some(Both(2, 2))); - assert_eq!(it.next_back(), Some(Left(6))); - assert_eq!(it.next_back(), Some(Left(5))); - assert_eq!(it.next_back(), Some(Both(4, 7))); - assert_eq!(it.next(), Some(Both(3, 3))); - assert_eq!(it.next(), None); -} - - -#[should_panic] -#[test] -fn zip_eq_panic1() -{ - let a = [1, 2]; - let b = [1, 2, 3]; - - zip_eq(&a, &b).count(); -} - -#[should_panic] -#[test] -fn zip_eq_panic2() -{ - let a: [i32; 0] = []; - let b = [1, 2, 3]; - - zip_eq(&a, &b).count(); -} - diff --git a/vendor/libc/.cargo-checksum.json b/vendor/libc/.cargo-checksum.json index 2233783fde..e2af23d0fa 100644 --- a/vendor/libc/.cargo-checksum.json +++ b/vendor/libc/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"3a9f0037ad5f1198eada74a9d0363925ef09db664380b0e5a2840f03da260476","Cargo.toml":"f21c12e9feff009e1694d41296471ff3d06a392ecc6088bd86e283e6432396ea","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"8d633db1fa838f24fb7ae854b31f37fc238b833d6f4044a1c3c077fe88a59e1f","build.rs":"e487789ca77b0015d75cecb253286d4a1406f11b1ae538929414fc0506842bef","rustfmt.toml":"8a654d5787585ca8f2c20580737336fc327f411a07b0dbd4870adf6e9bdf624f","src/cloudabi/aarch64.rs":"b8550bf1fd7344972aa4db29441486f39f31482d0327534981dbb75959c29114","src/cloudabi/arm.rs":"c197e2781c2839808bd6fcef219a29705b27b992d3ef920e9cf6ac96e2022bbf","src/cloudabi/mod.rs":"d5d4488e8c0b8227f516fe13810f550a2a72af3bdfe769200ad8687c8755bdf6","src/cloudabi/x86.rs":"33eb97f272d2201f3838ae74d444583c7de8f67856852ca375293b20bbd05636","src/cloudabi/x86_64.rs":"400d85d4fe39e26cf2e6ece9ee31c75fe9e88c4bcf4d836ca9f765c05c9c5be3","src/fixed_width_ints.rs":"34c60f12ec5eeb90f13ec3b954427532111c2446e69617616a97aefc1086a9f1","src/fuchsia/aarch64.rs":"378776a9e40766154a54c94c2a7b4675b5c302a38e6e42da99e67bfbaee60e56","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"61502b3d124759c7c1bae294c1662036a96718fb3bd329cfa2f12e1c61ac10ad","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"d3bfce41e4463d4be8020a2d063c9bfa8b665f45f1cc6cbf3163f5d01e7cb21f","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"d80f0a2f77d485601a218e0707474245636d8b23fb3d6c65c9dbd4302ea6674b","src/macros.rs":"83aed048c5053300345fca843b148928b91ed444188c479315ff6bcabaa0c4e9","src/psp.rs":"a621e34d2d31d9b29c725897b846122acce4763ac2017a1fe2200b133e5ad064","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"6a4ce300da0d2b0db04b18548286603ffe4b47d679a41cf60f1902895894aa1f","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"81254d89be1febc5bb20e787d014a624950d56e2e14973df5bbebfdabc95ae20","src/unix/bsd/apple/mod.rs":"5b9136a239e9893aaaa604b4499e5bb3e9899fd9ef76c0ed616a4d6b0fa4c3ba","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"ae5e8e6b0f610ec015dfcc2928609037d7ea7b94570c72bcc5bdd588424c6259","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"0e41b6202c7670ce27201095fc1a2826c9e9ccbbc751e97ae1568871ea481a62","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"14f0bd6693967d4fedec904f7042bd51f2138cb843ec4df18c911b357417cdd2","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"16dd3e1a09f123d0aa544b3fd7c123654b4906cac94838fbed7f34a64413c930","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"c6152ce3db241d99e350d34352f3f3d167953ef0ee08bfbe2685cb9ebde2e83b","src/unix/bsd/freebsdlike/freebsd/mod.rs":"1ed8971b7de3b0435341a9af1366493d0458e4a00507dd824c4c11f4ce2006af","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/x86.rs":"c5005e3249eb7c93cfbac72a9e9272320d80ce7983da990ceb05a447f59a02c5","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"6132aa0973454379674ea6cbc77e6eace1e1032dd9f38182071388a036f1bc08","src/unix/bsd/freebsdlike/mod.rs":"8ab67353a9bd2c5490a0bd734de3a70c90fa6b3c3160dccf18c690e70a44e1b8","src/unix/bsd/mod.rs":"4acdbc0148b672fe015ddd7cae952e5d77691df6941a20f8ca40fd996e6a37dd","src/unix/bsd/netbsdlike/mod.rs":"48dd60524119c1e09b255d5472d091e7e7b2b29eab04be51b4b1e740bd022859","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"b38fc046f9a40fea28bd26328b96629f4d5d63d7524936bd6af1865d401a8716","src/unix/bsd/netbsdlike/netbsd/arm.rs":"58cdbb70b0d6f536551f0f3bb3725d2d75c4690db12c26c034e7d6ec4a924452","src/unix/bsd/netbsdlike/netbsd/mod.rs":"16a9036b6a8b373cdf0576ae99c95430f3f111b6be906a1e1ecff8047e178a86","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"135509edeaf3fb3f102d89d51ff1a8f82323497336a8dc7e1f0f23b5c2434b73","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/mod.rs":"a2938e72d1c6e3f32fb51e896b63abd0d79e1e360dc53f9254fdac82b21206b9","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"e59b7fd65f68f8e857eec39e0c03bac1d3af6ddc26c9ba58494336b83659bb9b","src/unix/haiku/b32.rs":"69ae47fc52c6880e85416b4744500d5655c9ec6131cb737f3b649fceaadce15a","src/unix/haiku/b64.rs":"73e64db09275a8da8d50a13cce2cfa2b136036ddf3a930d2939f337fc995900b","src/unix/haiku/mod.rs":"4ff3c94cf2e046609c95822e99b2a72663ba72056aa3519c0189cc6197b23751","src/unix/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/unix/hermit/mod.rs":"fb7e14d0f46ffaa989b5ab68c85184efe6aa04b5381e46866299b1f3258ddce3","src/unix/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/unix/linux_like/android/b32/arm.rs":"155994121906903a2e0afad895f0b3b7546f6e54d6305a3336ce2c4dfafbfdfa","src/unix/linux_like/android/b32/mod.rs":"0325adf3364fed7157fff5b24fabe1b36d806c39ee04ec82dd29a606d28f91f6","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"5b1e9fcd77ca5f939acb7fb5f5da12f305b0377698d8b8989feb236e26360aa0","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/mod.rs":"655116966eb7846b933e5e28b073c329668588cd3c2120cc9ce60c697bd19978","src/unix/linux_like/android/b64/mod.rs":"6a71abfcbbcdae60c916de41cd4688d5f25bdbca83d1d9df49decd56ad726a06","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"e84176d838e663d351450bad218715db1fafbb531e47ea0e262cbb45829dae89","src/unix/linux_like/android/mod.rs":"a30a8bd58d6e9e330ed42af86db84a7dde7225262bc1197066cdb776cc1936a4","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/mod.rs":"55fb89f5a965a4ad81ee4d02498c32aaed69e6047ce708c2329a602171862a76","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"dde648468764a5deef5566b8016290150acf50ee6a0f8c0678cb2078658bc2fa","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"6d9ba242111c7be8173b7a7b8cf8c863ba23d839edc9d026c0fd37a4b64460b4","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"e2d2e51fea73210d9705b7eaa37de8baa7152b71ae3a10a316c277345c529b5c","src/unix/linux_like/linux/gnu/b32/mod.rs":"e224551fa50be726bc8a559da32a96294b18743fb5a5b67cdbee4bb6a9eeb796","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"39aae80d2c4ffa845592e16c0a6c910017de19e2b15c1e507c4df10e79ce3e38","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"3b4dd40b288788740d2b030171b21f9d0b076ce26d88e0ff62f5d87f09e7c787","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"927d1bd8cb2f053549fc5acfeb1315b7f80b35d7a1904cd76e99651ff32b141e","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"17e9cd23a14bd19700c05a154568fff5897788c0ae151c21dd3bba67aac829d9","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"0b5d94f3a2361742b6dd9eb3f543ddf675d3f70dab3402ad179faa6ddaae2218","src/unix/linux_like/linux/gnu/b64/mod.rs":"b90d87f76bff37707a1725551fe45d70d0c106e01b1dbbcd5f60460e0a19b4c3","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"2f279eb268c0aca9a6bd9b4c84139799cd039a64ca1cd2ded68b04c63397be1b","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"bb01828300f02c11c27689522454439d0d02f22d738df88a97367dc87eecf868","src/unix/linux_like/linux/gnu/b64/s390x.rs":"9c449b64b11cbf55d453b324cf9475acb3253f85cb9692f9873b777ed8978ff4","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"a2667a09e526878683fafa02474f81fbc212d861ceeabade17b0ff4d6d49ff9d","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"e6197537739cb8628cad25827081c8bf6b371c02ad4b2132b30b9ae74143b1ef","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"c1862036556262f076eda2008470b8a351b9c371d70664f54387c46890e8cd18","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"30f88d0fa9e7807ee4cbe89fd274061f810099567d5e68fa829277d7d27ba708","src/unix/linux_like/linux/gnu/mod.rs":"747a07b094dff07bbf77049ce1117098255de9be403a6f703219c1c6a174898c","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"3dc8b1980062117edd7bdfdf2279065737f8cdcdcb883f57f23f27a1d0bbb8b2","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"45062a178b382ab17341a69d027b5c83325c4e79fecf45729ba9c47b1bcdc3da","src/unix/linux_like/linux/musl/b32/hexagon.rs":"7c6c481f70da1fe6ca759f363784e130041f3d87906c45910fc1142b5ef17970","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"9eb0e4953be5afaa0b9e3ac54c85ed40583cfb8cc0b03264b9bc8f763a8f3254","src/unix/linux_like/linux/musl/b32/mod.rs":"8ede3985e6243882814ce91e8ce543e7edbafc0cee5932816072b6f14207a671","src/unix/linux_like/linux/musl/b32/powerpc.rs":"cf286cbf4d2076aaa82662ace2b5c333480410fa59af5cb4542d59f04da84b31","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"9c3b6e98e7710d6c877a4e31726d36416115a58f53fc469bb173b7fe660b39e5","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"22da1c030c254c511bc335c824d40b693904975a4633f8243a8777ca68ef1c65","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"7b3fb85a869e00aae3f6af9c36f82f9c70bf8c2b9cccbd931b923602846ea42c","src/unix/linux_like/linux/musl/b64/mips64.rs":"9d0158ac7a913222d0a62239ec043aa1aee73522a7a1e0e191d0642dde35c083","src/unix/linux_like/linux/musl/b64/mod.rs":"8b76e92a1505ad785d4aa0b7739e0b93647a1e81910949b49cedb6c88468be9c","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"ed9b879bb9cdc526ad83815875edeb4cad4e8829086dfba2578277c265336229","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"cfeb109c732ac6bc7d2be44069d3652e917a0509b8b545270b756ff2d52e27e8","src/unix/linux_like/linux/musl/mod.rs":"243e32b93641df7a77f970a32c0fb8e4fd4a13720e54e0e42a9da321fd169798","src/unix/linux_like/linux/no_align.rs":"c81ccd1942295d423b43a55b4aa19633c2096fb93bb381a6a29acb93e85aab07","src/unix/linux_like/mod.rs":"7fa57fd43b7429c29a34867a85b34f185ed8a05c4511749177c870d8cfafa0dd","src/unix/mod.rs":"48268482b43ab4bf82d6a6e67f64043279c7266032826ff25d3ccc14ac0ae1ed","src/unix/newlib/aarch64/mod.rs":"bb269c1468a9676442554600e87417079a787fe6220dfc23b3109639259e8710","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"c71be856bfd7f576b2db28af9f680211cbe6c1cac7d537bbc8020b39591af07c","src/unix/newlib/mod.rs":"2f771ab23df36ab0c7a117e854483a917aaf9c5cbb9eded1bdda35827cdaf734","src/unix/newlib/no_align.rs":"7123dcec13604a11b7765c380ff3a4d0da19c39f4b03919de7857723c0cf1502","src/unix/newlib/powerpc/mod.rs":"2d0f7af28b47f7a2a6c210ebd1c1f33ed8eac62e56b5af2b856de2ad3fdc5187","src/unix/newlib/xtensa/mod.rs":"4c72003c5e692e648c7e798358c49af6901e68850dbba0624af84c40baf208f5","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/redox/mod.rs":"89c31827cf348e9a7af387f9e708fc834d04da36cad415d3957d2faa70f2fcbe","src/unix/solarish/compat.rs":"3f13657fc072462b85b5f937f0db1427c41acb2a714cc4f78fefba1ea8036846","src/unix/solarish/illumos.rs":"1088c45b238e7d398dbb140d238257d5b5f93aeded98652c3f6747f0c07b4fa7","src/unix/solarish/mod.rs":"9f96e346d87296e2b0b87b9fe375d67fb66cd88ce61ea2905466c8c5891d3108","src/unix/solarish/solaris.rs":"6000d322ee9f691f38a2cd89b2b8838e51f64c01584143924962b0c598e0985c","src/unix/uclibc/align.rs":"a8540e1cce5913a45bc8d7422b79e86c0b12740e8a679478e0e4d863a31f8cc1","src/unix/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/arm/mod.rs":"d67dd46bc6f417169fc6a23832bde7ccdafc5d1bcb08b10debdd82edaf75d529","src/unix/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/mips/mips32/mod.rs":"a045ebc6619f540adf670b88a987abd2d6e42e440a552e8cfe9f8c77f397e873","src/unix/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/uclibc/mips/mips64/mod.rs":"e3085ba56cfbc528d7c3c55065880603238c333b6047ef51c58177508a487fcd","src/unix/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/uclibc/mips/mod.rs":"1054d0bfeb506b3346b9a4148564beced8a22da0d9c9a612101f6237756795fb","src/unix/uclibc/mod.rs":"18d6c2628ca458ba75e743bce75bda6614de99606af4e2e62daf2440d2878f18","src/unix/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/uclibc/x86_64/align.rs":"4e34cebb7955e9c98ae2f310be6f8ed16a861fc3817c08543867554aeec9524e","src/unix/uclibc/x86_64/l4re.rs":"bb31053d6403091e11f95ac2203982f279f8b984a19adf30796878c45fdd8c25","src/unix/uclibc/x86_64/mod.rs":"188fbaf06a8e23cac72718b1ef7eb4bd98bdfd946aa708151f3f7e3553b65876","src/unix/uclibc/x86_64/no_align.rs":"2ccc0107a6007c70dc49e656095b64a352ca5d8f9f3e65c1dba634effbc15636","src/unix/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"e78d05ff53cc6af0ae41ca0af8d7ee2b3ca1b1b05216a9e39db19d67e9f8f8c6","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"486a00bafb5b6bf0538c4d984dab021835295c431cb2ceb7a9a74b499f78ade6","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"c7ab9793baaa3b6854d25fdf44266b7953533009e4fa722ca717b71d3e5d2c9d","src/windows/mod.rs":"7b74bf885712d16a3557df33ef02799dc03d4a1af953c7e6b4648954ce7a20fc","src/windows/msvc.rs":"2c2bfce66027d88021e7289139ebf5b0db258a7b6443f18872c84dbd4ef57131","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"3a9f0037ad5f1198eada74a9d0363925ef09db664380b0e5a2840f03da260476","Cargo.toml":"d372dc49f9d6323c13f9aa079f463e435562b4ea1c73cc7de0bdd0134cdf0a15","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"a8d47ff51ca256f56a8932dba07660672dbfe3004257ca8de708aac1415937a1","README.md":"8d633db1fa838f24fb7ae854b31f37fc238b833d6f4044a1c3c077fe88a59e1f","build.rs":"e487789ca77b0015d75cecb253286d4a1406f11b1ae538929414fc0506842bef","rustfmt.toml":"8a654d5787585ca8f2c20580737336fc327f411a07b0dbd4870adf6e9bdf624f","src/cloudabi/aarch64.rs":"b8550bf1fd7344972aa4db29441486f39f31482d0327534981dbb75959c29114","src/cloudabi/arm.rs":"c197e2781c2839808bd6fcef219a29705b27b992d3ef920e9cf6ac96e2022bbf","src/cloudabi/mod.rs":"d5d4488e8c0b8227f516fe13810f550a2a72af3bdfe769200ad8687c8755bdf6","src/cloudabi/x86.rs":"33eb97f272d2201f3838ae74d444583c7de8f67856852ca375293b20bbd05636","src/cloudabi/x86_64.rs":"400d85d4fe39e26cf2e6ece9ee31c75fe9e88c4bcf4d836ca9f765c05c9c5be3","src/fixed_width_ints.rs":"34c60f12ec5eeb90f13ec3b954427532111c2446e69617616a97aefc1086a9f1","src/fuchsia/aarch64.rs":"378776a9e40766154a54c94c2a7b4675b5c302a38e6e42da99e67bfbaee60e56","src/fuchsia/align.rs":"ae1cf8f011a99737eabeb14ffff768e60f13b13363d7646744dbb0f443dab3d6","src/fuchsia/mod.rs":"61502b3d124759c7c1bae294c1662036a96718fb3bd329cfa2f12e1c61ac10ad","src/fuchsia/no_align.rs":"303f3f1b255e0088b5715094353cf00476131d8e94e6aebb3f469557771c8b8a","src/fuchsia/x86_64.rs":"93a3632b5cf67d2a6bcb7dc0a558605252d5fe689e0f38d8aa2ec5852255ac87","src/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/hermit/mod.rs":"d3bfce41e4463d4be8020a2d063c9bfa8b665f45f1cc6cbf3163f5d01e7cb21f","src/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/lib.rs":"d80f0a2f77d485601a218e0707474245636d8b23fb3d6c65c9dbd4302ea6674b","src/macros.rs":"f024ec4ccd3762d4da198f14718d15a3ef70207f63aa3dceabf0de480fe780e9","src/psp.rs":"a621e34d2d31d9b29c725897b846122acce4763ac2017a1fe2200b133e5ad064","src/sgx.rs":"16a95cdefc81c5ee00d8353a60db363c4cc3e0f75abcd5d0144723f2a306ed1b","src/switch.rs":"9da3dd39b3de45a7928789926e8572d00e1e11a39e6f7289a1349aadce90edba","src/unix/align.rs":"2cdc7c826ef7ae61f5171c5ae8c445a743d86f1a7f2d9d7e4ceeec56d6874f65","src/unix/bsd/apple/b32/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b32/mod.rs":"6a4ce300da0d2b0db04b18548286603ffe4b47d679a41cf60f1902895894aa1f","src/unix/bsd/apple/b64/align.rs":"ec833a747866fe19ca2d9b4d3c9ff0385faba5edf4bd0d15fa68884c40b0e26c","src/unix/bsd/apple/b64/mod.rs":"81254d89be1febc5bb20e787d014a624950d56e2e14973df5bbebfdabc95ae20","src/unix/bsd/apple/mod.rs":"41a54fb1f44b3d5bd79be9ecbb227c67c33caed5dcd80f9a8daf845222bee883","src/unix/bsd/freebsdlike/dragonfly/errno.rs":"63f22519f7f4b18152f912c03b860532114b8726832c40b5590def6f02eeb13a","src/unix/bsd/freebsdlike/dragonfly/mod.rs":"1f361fc8c73eef537b274ab126d641614f076a488acfbdb19dcc053c50bc5308","src/unix/bsd/freebsdlike/freebsd/aarch64.rs":"14f0bd6693967d4fedec904f7042bd51f2138cb843ec4df18c911b357417cdd2","src/unix/bsd/freebsdlike/freebsd/arm.rs":"59d6a670eea562fb87686e243e0a84603d29a2028a3d4b3f99ccc01bd04d2f47","src/unix/bsd/freebsdlike/freebsd/freebsd11/b64.rs":"9808d152c1196aa647f1b0f0cf84dac8c930da7d7f897a44975545e3d9d17681","src/unix/bsd/freebsdlike/freebsd/freebsd11/mod.rs":"16dd3e1a09f123d0aa544b3fd7c123654b4906cac94838fbed7f34a64413c930","src/unix/bsd/freebsdlike/freebsd/freebsd12/b64.rs":"61cbe45f8499bedb168106b686d4f8239472f25c7553b069eec2afe197ff2df6","src/unix/bsd/freebsdlike/freebsd/freebsd12/mod.rs":"c6152ce3db241d99e350d34352f3f3d167953ef0ee08bfbe2685cb9ebde2e83b","src/unix/bsd/freebsdlike/freebsd/mod.rs":"1d0e3411a757a6f3f533177dbd4058a2ce8fd062130734cea6a225210a8664ae","src/unix/bsd/freebsdlike/freebsd/powerpc64.rs":"2dae3ecc87eac3b11657aa98915def55fc4b5c0de11fe26aae23329a54628a9a","src/unix/bsd/freebsdlike/freebsd/x86.rs":"c5005e3249eb7c93cfbac72a9e9272320d80ce7983da990ceb05a447f59a02c5","src/unix/bsd/freebsdlike/freebsd/x86_64/align.rs":"0e1f69a88fca1c32874b1daf5db3d446fefbe518dca497f096cc9168c39dde70","src/unix/bsd/freebsdlike/freebsd/x86_64/mod.rs":"6132aa0973454379674ea6cbc77e6eace1e1032dd9f38182071388a036f1bc08","src/unix/bsd/freebsdlike/mod.rs":"9f123d0fbc452013ddc233e61f988ca22483beb21b01983b4754b9a1515205b4","src/unix/bsd/mod.rs":"92fb2e6f86189b7d56d9d02c44cdf35b964b982e439b806901de1637272d9df3","src/unix/bsd/netbsdlike/mod.rs":"48dd60524119c1e09b255d5472d091e7e7b2b29eab04be51b4b1e740bd022859","src/unix/bsd/netbsdlike/netbsd/aarch64.rs":"b38fc046f9a40fea28bd26328b96629f4d5d63d7524936bd6af1865d401a8716","src/unix/bsd/netbsdlike/netbsd/arm.rs":"58cdbb70b0d6f536551f0f3bb3725d2d75c4690db12c26c034e7d6ec4a924452","src/unix/bsd/netbsdlike/netbsd/mod.rs":"16a9036b6a8b373cdf0576ae99c95430f3f111b6be906a1e1ecff8047e178a86","src/unix/bsd/netbsdlike/netbsd/powerpc.rs":"ee7ff5d89d0ed22f531237b5059aa669df93a3b5c489fa641465ace8d405bf41","src/unix/bsd/netbsdlike/netbsd/sparc64.rs":"9489f4b3e4566f43bb12dfb92238960613dac7f6a45cc13068a8d152b902d7d9","src/unix/bsd/netbsdlike/netbsd/x86.rs":"20692320e36bfe028d1a34d16fe12ca77aa909cb02bda167376f98f1a09aefe7","src/unix/bsd/netbsdlike/netbsd/x86_64.rs":"135509edeaf3fb3f102d89d51ff1a8f82323497336a8dc7e1f0f23b5c2434b73","src/unix/bsd/netbsdlike/openbsd/aarch64.rs":"1dd5449dd1fd3d51e30ffdeeaece91d0aaf05c710e0ac699fecc5461cfa2c28e","src/unix/bsd/netbsdlike/openbsd/mod.rs":"a2938e72d1c6e3f32fb51e896b63abd0d79e1e360dc53f9254fdac82b21206b9","src/unix/bsd/netbsdlike/openbsd/sparc64.rs":"d04fd287afbaa2c5df9d48c94e8374a532a3ba491b424ddf018270c7312f4085","src/unix/bsd/netbsdlike/openbsd/x86.rs":"6f7f5c4fde2a2259eb547890cbd86570cea04ef85347d7569e94e679448bec87","src/unix/bsd/netbsdlike/openbsd/x86_64.rs":"e59b7fd65f68f8e857eec39e0c03bac1d3af6ddc26c9ba58494336b83659bb9b","src/unix/haiku/b32.rs":"69ae47fc52c6880e85416b4744500d5655c9ec6131cb737f3b649fceaadce15a","src/unix/haiku/b64.rs":"73e64db09275a8da8d50a13cce2cfa2b136036ddf3a930d2939f337fc995900b","src/unix/haiku/mod.rs":"449eabbfc0390282a3b7da5c1d22f5df88145a49f879e55ba99fda1092fb8312","src/unix/hermit/aarch64.rs":"86048676e335944c37a63d0083d0f368ae10ceccefeed9debb3bbe08777fc682","src/unix/hermit/mod.rs":"fb7e14d0f46ffaa989b5ab68c85184efe6aa04b5381e46866299b1f3258ddce3","src/unix/hermit/x86_64.rs":"ab832b7524e5fb15c49ff7431165ab1a37dc4667ae0b58e8306f4c539bfa110c","src/unix/linux_like/android/b32/arm.rs":"155994121906903a2e0afad895f0b3b7546f6e54d6305a3336ce2c4dfafbfdfa","src/unix/linux_like/android/b32/mod.rs":"0325adf3364fed7157fff5b24fabe1b36d806c39ee04ec82dd29a606d28f91f6","src/unix/linux_like/android/b32/x86/align.rs":"812914e4241df82e32b12375ca3374615dc3a4bdd4cf31f0423c5815320c0dab","src/unix/linux_like/android/b32/x86/mod.rs":"5b1e9fcd77ca5f939acb7fb5f5da12f305b0377698d8b8989feb236e26360aa0","src/unix/linux_like/android/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/android/b64/aarch64/mod.rs":"655116966eb7846b933e5e28b073c329668588cd3c2120cc9ce60c697bd19978","src/unix/linux_like/android/b64/mod.rs":"6a71abfcbbcdae60c916de41cd4688d5f25bdbca83d1d9df49decd56ad726a06","src/unix/linux_like/android/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/android/b64/x86_64/mod.rs":"e84176d838e663d351450bad218715db1fafbb531e47ea0e262cbb45829dae89","src/unix/linux_like/android/mod.rs":"a30a8bd58d6e9e330ed42af86db84a7dde7225262bc1197066cdb776cc1936a4","src/unix/linux_like/emscripten/align.rs":"86c95cbed7a7161b1f23ee06843e7b0e2340ad92b2cb86fe2a8ef3e0e8c36216","src/unix/linux_like/emscripten/mod.rs":"55fb89f5a965a4ad81ee4d02498c32aaed69e6047ce708c2329a602171862a76","src/unix/linux_like/emscripten/no_align.rs":"0128e4aa721a9902754828b61b5ec7d8a86619983ed1e0544a85d35b1051fad6","src/unix/linux_like/linux/align.rs":"dde648468764a5deef5566b8016290150acf50ee6a0f8c0678cb2078658bc2fa","src/unix/linux_like/linux/gnu/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/linux_like/linux/gnu/b32/arm/align.rs":"3fed009dc9af3cc81be7087da9d2d7d1f39845e4497e290259c5cdbae25f039d","src/unix/linux_like/linux/gnu/b32/arm/mod.rs":"6d9ba242111c7be8173b7a7b8cf8c863ba23d839edc9d026c0fd37a4b64460b4","src/unix/linux_like/linux/gnu/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/gnu/b32/mips/mod.rs":"e2d2e51fea73210d9705b7eaa37de8baa7152b71ae3a10a316c277345c529b5c","src/unix/linux_like/linux/gnu/b32/mod.rs":"e224551fa50be726bc8a559da32a96294b18743fb5a5b67cdbee4bb6a9eeb796","src/unix/linux_like/linux/gnu/b32/powerpc.rs":"39aae80d2c4ffa845592e16c0a6c910017de19e2b15c1e507c4df10e79ce3e38","src/unix/linux_like/linux/gnu/b32/sparc/align.rs":"21adbed27df73e2d1ed934aaf733a643003d7baf2bde9c48ea440895bcca6d41","src/unix/linux_like/linux/gnu/b32/sparc/mod.rs":"3b4dd40b288788740d2b030171b21f9d0b076ce26d88e0ff62f5d87f09e7c787","src/unix/linux_like/linux/gnu/b32/x86/align.rs":"e4bafdc4a519a7922a81b37a62bbfd1177a2f620890eef8f1fbc47162e9eb413","src/unix/linux_like/linux/gnu/b32/x86/mod.rs":"927d1bd8cb2f053549fc5acfeb1315b7f80b35d7a1904cd76e99651ff32b141e","src/unix/linux_like/linux/gnu/b64/aarch64/align.rs":"2179c3b1608fa4bf68840482bfc2b2fa3ee2faf6fcae3770f9e505cddca35c7b","src/unix/linux_like/linux/gnu/b64/aarch64/mod.rs":"17e9cd23a14bd19700c05a154568fff5897788c0ae151c21dd3bba67aac829d9","src/unix/linux_like/linux/gnu/b64/mips64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/mips64/mod.rs":"0b5d94f3a2361742b6dd9eb3f543ddf675d3f70dab3402ad179faa6ddaae2218","src/unix/linux_like/linux/gnu/b64/mod.rs":"b90d87f76bff37707a1725551fe45d70d0c106e01b1dbbcd5f60460e0a19b4c3","src/unix/linux_like/linux/gnu/b64/powerpc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/powerpc64/mod.rs":"2f279eb268c0aca9a6bd9b4c84139799cd039a64ca1cd2ded68b04c63397be1b","src/unix/linux_like/linux/gnu/b64/riscv64/mod.rs":"bb01828300f02c11c27689522454439d0d02f22d738df88a97367dc87eecf868","src/unix/linux_like/linux/gnu/b64/s390x.rs":"9c449b64b11cbf55d453b324cf9475acb3253f85cb9692f9873b777ed8978ff4","src/unix/linux_like/linux/gnu/b64/sparc64/align.rs":"e29c4868bbecfa4a6cd8a2ad06193f3bbc78a468cc1dc9df83f002f1268130d9","src/unix/linux_like/linux/gnu/b64/sparc64/mod.rs":"a2667a09e526878683fafa02474f81fbc212d861ceeabade17b0ff4d6d49ff9d","src/unix/linux_like/linux/gnu/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/gnu/b64/x86_64/mod.rs":"e6197537739cb8628cad25827081c8bf6b371c02ad4b2132b30b9ae74143b1ef","src/unix/linux_like/linux/gnu/b64/x86_64/not_x32.rs":"c1862036556262f076eda2008470b8a351b9c371d70664f54387c46890e8cd18","src/unix/linux_like/linux/gnu/b64/x86_64/x32.rs":"30f88d0fa9e7807ee4cbe89fd274061f810099567d5e68fa829277d7d27ba708","src/unix/linux_like/linux/gnu/mod.rs":"747a07b094dff07bbf77049ce1117098255de9be403a6f703219c1c6a174898c","src/unix/linux_like/linux/gnu/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/linux_like/linux/mod.rs":"34c5f6451bed8875b1db90b49260c0eba55aa67eadc77b82d2ba818750569602","src/unix/linux_like/linux/musl/b32/arm/align.rs":"3e8ac052c1043764776b54c93ba4260e061df998631737a897d9d47d54f7b80c","src/unix/linux_like/linux/musl/b32/arm/mod.rs":"45062a178b382ab17341a69d027b5c83325c4e79fecf45729ba9c47b1bcdc3da","src/unix/linux_like/linux/musl/b32/hexagon.rs":"7c6c481f70da1fe6ca759f363784e130041f3d87906c45910fc1142b5ef17970","src/unix/linux_like/linux/musl/b32/mips/align.rs":"429fb5e005cb7143602d430098b6ebfb7d360685b194f333dfd587472ae954ee","src/unix/linux_like/linux/musl/b32/mips/mod.rs":"9eb0e4953be5afaa0b9e3ac54c85ed40583cfb8cc0b03264b9bc8f763a8f3254","src/unix/linux_like/linux/musl/b32/mod.rs":"8ede3985e6243882814ce91e8ce543e7edbafc0cee5932816072b6f14207a671","src/unix/linux_like/linux/musl/b32/powerpc.rs":"cf286cbf4d2076aaa82662ace2b5c333480410fa59af5cb4542d59f04da84b31","src/unix/linux_like/linux/musl/b32/x86/align.rs":"08e77fbd7435d7dec2ff56932433bece3f02e47ce810f89004a275a86d39cbe1","src/unix/linux_like/linux/musl/b32/x86/mod.rs":"9c3b6e98e7710d6c877a4e31726d36416115a58f53fc469bb173b7fe660b39e5","src/unix/linux_like/linux/musl/b64/aarch64/align.rs":"22da1c030c254c511bc335c824d40b693904975a4633f8243a8777ca68ef1c65","src/unix/linux_like/linux/musl/b64/aarch64/mod.rs":"9870fd9a953c98b775c9e17a29a66bbe8019a6236eb69a0272f42232a226521d","src/unix/linux_like/linux/musl/b64/mips64.rs":"9d0158ac7a913222d0a62239ec043aa1aee73522a7a1e0e191d0642dde35c083","src/unix/linux_like/linux/musl/b64/mod.rs":"8b76e92a1505ad785d4aa0b7739e0b93647a1e81910949b49cedb6c88468be9c","src/unix/linux_like/linux/musl/b64/powerpc64.rs":"ed9b879bb9cdc526ad83815875edeb4cad4e8829086dfba2578277c265336229","src/unix/linux_like/linux/musl/b64/x86_64/align.rs":"7169d07a9fd4716f7512719aec9fda5d8bed306dc0720ffc1b21696c9951e3c6","src/unix/linux_like/linux/musl/b64/x86_64/mod.rs":"cfeb109c732ac6bc7d2be44069d3652e917a0509b8b545270b756ff2d52e27e8","src/unix/linux_like/linux/musl/mod.rs":"243e32b93641df7a77f970a32c0fb8e4fd4a13720e54e0e42a9da321fd169798","src/unix/linux_like/linux/no_align.rs":"c81ccd1942295d423b43a55b4aa19633c2096fb93bb381a6a29acb93e85aab07","src/unix/linux_like/mod.rs":"9db5a512b824c5ec124951ccefd1f78285d1549adce7798645b5fdef1643000b","src/unix/mod.rs":"48268482b43ab4bf82d6a6e67f64043279c7266032826ff25d3ccc14ac0ae1ed","src/unix/newlib/aarch64/mod.rs":"bb269c1468a9676442554600e87417079a787fe6220dfc23b3109639259e8710","src/unix/newlib/align.rs":"28aaf87fafbc6b312622719d472d8cf65f9e5467d15339df5f73e66d8502b28a","src/unix/newlib/arm/mod.rs":"c71be856bfd7f576b2db28af9f680211cbe6c1cac7d537bbc8020b39591af07c","src/unix/newlib/mod.rs":"2f771ab23df36ab0c7a117e854483a917aaf9c5cbb9eded1bdda35827cdaf734","src/unix/newlib/no_align.rs":"7123dcec13604a11b7765c380ff3a4d0da19c39f4b03919de7857723c0cf1502","src/unix/newlib/powerpc/mod.rs":"2d0f7af28b47f7a2a6c210ebd1c1f33ed8eac62e56b5af2b856de2ad3fdc5187","src/unix/newlib/xtensa/mod.rs":"4c72003c5e692e648c7e798358c49af6901e68850dbba0624af84c40baf208f5","src/unix/no_align.rs":"c06e95373b9088266e0b14bba0954eef95f93fb2b01d951855e382d22de78e53","src/unix/redox/mod.rs":"89c31827cf348e9a7af387f9e708fc834d04da36cad415d3957d2faa70f2fcbe","src/unix/solarish/compat.rs":"3f13657fc072462b85b5f937f0db1427c41acb2a714cc4f78fefba1ea8036846","src/unix/solarish/illumos.rs":"1088c45b238e7d398dbb140d238257d5b5f93aeded98652c3f6747f0c07b4fa7","src/unix/solarish/mod.rs":"a9e46c0eee970cb5b4bd910924141d223fad4aa45380d3df1ce4b25992a13037","src/unix/solarish/solaris.rs":"6000d322ee9f691f38a2cd89b2b8838e51f64c01584143924962b0c598e0985c","src/unix/uclibc/align.rs":"a8540e1cce5913a45bc8d7422b79e86c0b12740e8a679478e0e4d863a31f8cc1","src/unix/uclibc/arm/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/arm/mod.rs":"d67dd46bc6f417169fc6a23832bde7ccdafc5d1bcb08b10debdd82edaf75d529","src/unix/uclibc/arm/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips32/align.rs":"e4a3c27fe20a57b8d612c34cb05bc70646edb5cec7251957315afa53a7b9f936","src/unix/uclibc/mips/mips32/mod.rs":"a045ebc6619f540adf670b88a987abd2d6e42e440a552e8cfe9f8c77f397e873","src/unix/uclibc/mips/mips32/no_align.rs":"9cd223135de75315840ff9c3fd5441ba1cb632b96b5c85a76f8316c86653db25","src/unix/uclibc/mips/mips64/align.rs":"a7bdcb18a37a2d91e64d5fad83ea3edc78f5412adb28f77ab077dbb26dd08b2d","src/unix/uclibc/mips/mips64/mod.rs":"e3085ba56cfbc528d7c3c55065880603238c333b6047ef51c58177508a487fcd","src/unix/uclibc/mips/mips64/no_align.rs":"4a18e3875698c85229599225ac3401a2a40da87e77b2ad4ef47c6fcd5a24ed30","src/unix/uclibc/mips/mod.rs":"1054d0bfeb506b3346b9a4148564beced8a22da0d9c9a612101f6237756795fb","src/unix/uclibc/mod.rs":"18d6c2628ca458ba75e743bce75bda6614de99606af4e2e62daf2440d2878f18","src/unix/uclibc/no_align.rs":"3f28637046524618adaa1012e26cb7ffe94b9396e6b518cccdc69d59f274d709","src/unix/uclibc/x86_64/align.rs":"4e34cebb7955e9c98ae2f310be6f8ed16a861fc3817c08543867554aeec9524e","src/unix/uclibc/x86_64/l4re.rs":"bb31053d6403091e11f95ac2203982f279f8b984a19adf30796878c45fdd8c25","src/unix/uclibc/x86_64/mod.rs":"188fbaf06a8e23cac72718b1ef7eb4bd98bdfd946aa708151f3f7e3553b65876","src/unix/uclibc/x86_64/no_align.rs":"2ccc0107a6007c70dc49e656095b64a352ca5d8f9f3e65c1dba634effbc15636","src/unix/uclibc/x86_64/other.rs":"42c3f71e58cabba373f6a55a623f3c31b85049eb64824c09c2b082b3b2d6a0a8","src/vxworks/aarch64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/arm.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/mod.rs":"e78d05ff53cc6af0ae41ca0af8d7ee2b3ca1b1b05216a9e39db19d67e9f8f8c6","src/vxworks/powerpc.rs":"acb7968ce99fe3f4abdf39d98f8133d21a4fba435b8ef7084777cb181d788e88","src/vxworks/powerpc64.rs":"98f0afdc511cd02557e506c21fed6737585490a1dce7a9d4941d08c437762b99","src/vxworks/x86.rs":"552f007f38317620b23889cb7c49d1d115841252439060122f52f434fbc6e5ba","src/vxworks/x86_64.rs":"018d92be3ad628a129eff9f2f5dfbc0883d8b8e5f2fa917b900a7f98ed6b514a","src/wasi.rs":"91950f1e7a7bea35e715d4ae6fc851717ae84dbfbb7902c9724fe0e71045c63c","src/windows/gnu/align.rs":"b2c13ec1b9f3b39a75c452c80c951dff9d0215e31d77e883b4502afb31794647","src/windows/gnu/mod.rs":"c7ab9793baaa3b6854d25fdf44266b7953533009e4fa722ca717b71d3e5d2c9d","src/windows/mod.rs":"7b74bf885712d16a3557df33ef02799dc03d4a1af953c7e6b4648954ce7a20fc","src/windows/msvc.rs":"2c2bfce66027d88021e7289139ebf5b0db258a7b6443f18872c84dbd4ef57131","tests/const_fn.rs":"cb75a1f0864f926aebe79118fc34d51a0d1ade2c20a394e7774c7e545f21f1f4","triagebot.toml":"a135e10c777cd13459559bdf74fb704c1379af7c9b0f70bc49fa6f5a837daa81"},"package":"f2f96b10ec2560088a8e76961b00d47107b3a625fecb76dedb29ee7ccbf98235"} \ No newline at end of file diff --git a/vendor/libc/Cargo.toml b/vendor/libc/Cargo.toml index b7cb5eccb1..7ab5a99706 100644 --- a/vendor/libc/Cargo.toml +++ b/vendor/libc/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "libc" -version = "0.2.76" +version = "0.2.77" authors = ["The Rust Project Developers"] build = "build.rs" exclude = ["/ci/*", "/azure-pipelines.yml"] diff --git a/vendor/libc/src/macros.rs b/vendor/libc/src/macros.rs index 378da7ccfb..b314f60ff2 100644 --- a/vendor/libc/src/macros.rs +++ b/vendor/libc/src/macros.rs @@ -195,6 +195,21 @@ cfg_if! { )*) } + #[allow(unused_macros)] + macro_rules! safe_f { + ($(pub $({$constness:ident})* fn $i:ident( + $($arg:ident: $argty:ty),* + ) -> $ret:ty { + $($body:stmt);* + })*) => ($( + #[inline] + pub $($constness)* extern fn $i($($arg: $argty),* + ) -> $ret { + $($body);* + } + )*) + } + #[allow(unused_macros)] macro_rules! const_fn { ($($({$constness:ident})* fn $i:ident( @@ -226,6 +241,21 @@ cfg_if! { )*) } + #[allow(unused_macros)] + macro_rules! safe_f { + ($(pub $({$constness:ident})* fn $i:ident( + $($arg:ident: $argty:ty),* + ) -> $ret:ty { + $($body:stmt);* + })*) => ($( + #[inline] + pub extern fn $i($($arg: $argty),* + ) -> $ret { + $($body);* + } + )*) + } + #[allow(unused_macros)] macro_rules! const_fn { ($($({$constness:ident})* fn $i:ident( diff --git a/vendor/libc/src/unix/bsd/apple/mod.rs b/vendor/libc/src/unix/bsd/apple/mod.rs index 857a2badee..b6984ecd4c 100644 --- a/vendor/libc/src/unix/bsd/apple/mod.rs +++ b/vendor/libc/src/unix/bsd/apple/mod.rs @@ -1406,6 +1406,7 @@ pub const O_DSYNC: ::c_int = 0x400000; pub const O_NOCTTY: ::c_int = 0x20000; pub const O_CLOEXEC: ::c_int = 0x1000000; pub const O_DIRECTORY: ::c_int = 0x100000; +pub const O_SYMLINK: ::c_int = 0x200000; pub const S_IFIFO: mode_t = 4096; pub const S_IFCHR: mode_t = 8192; pub const S_IFBLK: mode_t = 24576; diff --git a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs index e9ad63b86b..434ac63a3c 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/errno.rs @@ -1,6 +1,7 @@ // DragonFlyBSD's __error function is declared with "static inline", so it must // be implemented in the libc crate, as a pointer to a static thread_local. f! { + #[deprecated(since = "0.2.77", "Use `__errno_location()` instead")] pub fn __error() -> *mut ::c_int { &mut errno } diff --git a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs index 5841947f33..47e3b7c152 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/dragonfly/mod.rs @@ -460,21 +460,6 @@ pub const RLIM_NLIMITS: ::rlim_t = 12; pub const Q_GETQUOTA: ::c_int = 0x300; pub const Q_SETQUOTA: ::c_int = 0x400; -pub const CLOCK_REALTIME: ::clockid_t = 0; -pub const CLOCK_VIRTUAL: ::clockid_t = 1; -pub const CLOCK_PROF: ::clockid_t = 2; -pub const CLOCK_MONOTONIC: ::clockid_t = 4; -pub const CLOCK_UPTIME: ::clockid_t = 5; -pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; -pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; -pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; -pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; -pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; -pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; -pub const CLOCK_SECOND: ::clockid_t = 13; -pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; -pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; - pub const CTL_UNSPEC: ::c_int = 0; pub const CTL_KERN: ::c_int = 1; pub const CTL_VM: ::c_int = 2; @@ -1059,18 +1044,13 @@ f! { } extern "C" { + pub fn __errno_location() -> *mut ::c_int; pub fn setgrent(); pub fn mprotect( addr: *mut ::c_void, len: ::size_t, prot: ::c_int, ) -> ::c_int; - pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_settime( - clk_id: ::clockid_t, - tp: *const ::timespec, - ) -> ::c_int; pub fn setutxdb(_type: ::c_uint, file: *mut ::c_char) -> ::c_int; diff --git a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs index 1ca003959c..6359196138 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/freebsd/mod.rs @@ -447,21 +447,6 @@ pub const NOTE_NSECONDS: u32 = 0x00000008; pub const MADV_PROTECT: ::c_int = 10; pub const RUSAGE_THREAD: ::c_int = 1; -pub const CLOCK_REALTIME: ::clockid_t = 0; -pub const CLOCK_VIRTUAL: ::clockid_t = 1; -pub const CLOCK_PROF: ::clockid_t = 2; -pub const CLOCK_MONOTONIC: ::clockid_t = 4; -pub const CLOCK_UPTIME: ::clockid_t = 5; -pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; -pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; -pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; -pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; -pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; -pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; -pub const CLOCK_SECOND: ::clockid_t = 13; -pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; -pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; - #[doc(hidden)] #[deprecated( since = "0.2.72", @@ -1222,13 +1207,6 @@ f! { extern "C" { pub fn __error() -> *mut ::c_int; - pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; - pub fn clock_settime( - clk_id: ::clockid_t, - tp: *const ::timespec, - ) -> ::c_int; - pub fn extattr_delete_fd( fd: ::c_int, attrnamespace: ::c_int, diff --git a/vendor/libc/src/unix/bsd/freebsdlike/mod.rs b/vendor/libc/src/unix/bsd/freebsdlike/mod.rs index e9f70579ea..f70b8a5e6e 100644 --- a/vendor/libc/src/unix/bsd/freebsdlike/mod.rs +++ b/vendor/libc/src/unix/bsd/freebsdlike/mod.rs @@ -638,6 +638,21 @@ pub const RLIM_INFINITY: rlim_t = 0x7fff_ffff_ffff_ffff; pub const RUSAGE_SELF: ::c_int = 0; pub const RUSAGE_CHILDREN: ::c_int = -1; +pub const CLOCK_REALTIME: ::clockid_t = 0; +pub const CLOCK_VIRTUAL: ::clockid_t = 1; +pub const CLOCK_PROF: ::clockid_t = 2; +pub const CLOCK_MONOTONIC: ::clockid_t = 4; +pub const CLOCK_UPTIME: ::clockid_t = 5; +pub const CLOCK_UPTIME_PRECISE: ::clockid_t = 7; +pub const CLOCK_UPTIME_FAST: ::clockid_t = 8; +pub const CLOCK_REALTIME_PRECISE: ::clockid_t = 9; +pub const CLOCK_REALTIME_FAST: ::clockid_t = 10; +pub const CLOCK_MONOTONIC_PRECISE: ::clockid_t = 11; +pub const CLOCK_MONOTONIC_FAST: ::clockid_t = 12; +pub const CLOCK_SECOND: ::clockid_t = 13; +pub const CLOCK_THREAD_CPUTIME_ID: ::clockid_t = 14; +pub const CLOCK_PROCESS_CPUTIME_ID: ::clockid_t = 15; + pub const MADV_NORMAL: ::c_int = 0; pub const MADV_RANDOM: ::c_int = 1; pub const MADV_SEQUENTIAL: ::c_int = 2; @@ -1242,6 +1257,18 @@ extern "C" { flags: ::c_ulong, atflag: ::c_int, ) -> ::c_int; + + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; + pub fn clock_settime( + clk_id: ::clockid_t, + tp: *const ::timespec, + ) -> ::c_int; + pub fn clock_getcpuclockid( + pid: ::pid_t, + clk_id: *mut ::clockid_t, + ) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; pub fn duplocale(base: ::locale_t) -> ::locale_t; pub fn endutxent(); diff --git a/vendor/libc/src/unix/bsd/mod.rs b/vendor/libc/src/unix/bsd/mod.rs index 1b55078d5a..e49703e0da 100644 --- a/vendor/libc/src/unix/bsd/mod.rs +++ b/vendor/libc/src/unix/bsd/mod.rs @@ -254,6 +254,8 @@ pub const FIOGETOWN: ::c_ulong = 0x4004667b; pub const PATH_MAX: ::c_int = 1024; +pub const IOV_MAX: ::c_int = 1024; + pub const SA_ONSTACK: ::c_int = 0x0001; pub const SA_SIGINFO: ::c_int = 0x0040; pub const SA_RESTART: ::c_int = 0x0002; @@ -504,6 +506,10 @@ pub const PRIO_PROCESS: ::c_int = 0; pub const PRIO_PGRP: ::c_int = 1; pub const PRIO_USER: ::c_int = 2; +pub const ITIMER_REAL: ::c_int = 0; +pub const ITIMER_VIRTUAL: ::c_int = 1; +pub const ITIMER_PROF: ::c_int = 2; + f! { pub fn CMSG_FIRSTHDR(mhdr: *const ::msghdr) -> *mut ::cmsghdr { if (*mhdr).msg_controllen as usize >= ::mem::size_of::<::cmsghdr>() { @@ -847,6 +853,23 @@ extern "C" { options: ::c_int, rusage: *mut ::rusage, ) -> ::pid_t; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "getitimer$UNIX2003" + )] + pub fn getitimer( + which: ::c_int, + curr_value: *mut ::itimerval + ) -> ::c_int; + #[cfg_attr( + all(target_os = "macos", target_arch = "x86"), + link_name = "setitimer$UNIX2003" + )] + pub fn setitimer( + which: ::c_int, + new_value: *const ::itimerval, + old_value: *mut ::itimerval, + ) -> ::c_int; pub fn regcomp( preg: *mut regex_t, diff --git a/vendor/libc/src/unix/haiku/mod.rs b/vendor/libc/src/unix/haiku/mod.rs index adcac2e5ae..ccd11380e7 100644 --- a/vendor/libc/src/unix/haiku/mod.rs +++ b/vendor/libc/src/unix/haiku/mod.rs @@ -1292,6 +1292,9 @@ f! { extern "C" { pub fn getrlimit(resource: ::c_int, rlim: *mut ::rlimit) -> ::c_int; pub fn setrlimit(resource: ::c_int, rlim: *const ::rlimit) -> ::c_int; + pub fn getpriority(which: ::c_int, who: id_t) -> ::c_int; + pub fn setpriority(which: ::c_int, who: id_t, priority: ::c_int) -> ::c_int; + pub fn utimensat( fd: ::c_int, path: *const ::c_char, diff --git a/vendor/libc/src/unix/linux_like/linux/mod.rs b/vendor/libc/src/unix/linux_like/linux/mod.rs index dc6512df1f..421e131ba4 100644 --- a/vendor/libc/src/unix/linux_like/linux/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/mod.rs @@ -2761,11 +2761,6 @@ extern "C" { sevp: *mut ::sigevent, ) -> ::c_int; - pub fn clock_getcpuclockid( - pid: ::pid_t, - clk_id: *mut ::clockid_t, - ) -> ::c_int; - pub fn lutimes(file: *const ::c_char, times: *const ::timeval) -> ::c_int; pub fn setpwent(); diff --git a/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs b/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs index d7e06cd21c..88c252ea6c 100644 --- a/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs +++ b/vendor/libc/src/unix/linux_like/linux/musl/b64/aarch64/mod.rs @@ -170,7 +170,7 @@ pub const MAP_POPULATE: ::c_int = 0x08000; pub const MAP_NONBLOCK: ::c_int = 0x010000; pub const MAP_STACK: ::c_int = 0x020000; pub const MAP_HUGETLB: ::c_int = 0x040000; -pub const MAP_SYNC : ::c_int = 0x080000; +pub const MAP_SYNC: ::c_int = 0x080000; pub const SOCK_STREAM: ::c_int = 1; pub const SOCK_DGRAM: ::c_int = 2; @@ -284,6 +284,10 @@ pub const SYS_umount2: ::c_long = 39; pub const SYS_mount: ::c_long = 40; pub const SYS_pivot_root: ::c_long = 41; pub const SYS_nfsservctl: ::c_long = 42; +pub const SYS_statfs: ::c_long = 43; +pub const SYS_fstatfs: ::c_long = 44; +pub const SYS_truncate: ::c_long = 45; +pub const SYS_ftruncate: ::c_long = 46; pub const SYS_fallocate: ::c_long = 47; pub const SYS_faccessat: ::c_long = 48; pub const SYS_chdir: ::c_long = 49; diff --git a/vendor/libc/src/unix/linux_like/mod.rs b/vendor/libc/src/unix/linux_like/mod.rs index a48c3aaaad..2fc872b565 100644 --- a/vendor/libc/src/unix/linux_like/mod.rs +++ b/vendor/libc/src/unix/linux_like/mod.rs @@ -847,6 +847,8 @@ pub const SS_DISABLE: ::c_int = 2; pub const PATH_MAX: ::c_int = 4096; +pub const UIO_MAXIOV: ::c_int = 1024; + pub const FD_SETSIZE: usize = 1024; pub const EPOLLIN: ::c_int = 0x1; @@ -1233,64 +1235,66 @@ f! { *slot = 0; } } +} - pub fn WIFSTOPPED(status: ::c_int) -> bool { +safe_f! { + pub {const} fn WIFSTOPPED(status: ::c_int) -> bool { (status & 0xff) == 0x7f } - pub fn WSTOPSIG(status: ::c_int) -> ::c_int { + pub {const} fn WSTOPSIG(status: ::c_int) -> ::c_int { (status >> 8) & 0xff } - pub fn WIFCONTINUED(status: ::c_int) -> bool { + pub {const} fn WIFCONTINUED(status: ::c_int) -> bool { status == 0xffff } - pub fn WIFSIGNALED(status: ::c_int) -> bool { + pub {const} fn WIFSIGNALED(status: ::c_int) -> bool { ((status & 0x7f) + 1) as i8 >= 2 } - pub fn WTERMSIG(status: ::c_int) -> ::c_int { + pub {const} fn WTERMSIG(status: ::c_int) -> ::c_int { status & 0x7f } - pub fn WIFEXITED(status: ::c_int) -> bool { + pub {const} fn WIFEXITED(status: ::c_int) -> bool { (status & 0x7f) == 0 } - pub fn WEXITSTATUS(status: ::c_int) -> ::c_int { + pub {const} fn WEXITSTATUS(status: ::c_int) -> ::c_int { (status >> 8) & 0xff } - pub fn WCOREDUMP(status: ::c_int) -> bool { + pub {const} fn WCOREDUMP(status: ::c_int) -> bool { (status & 0x80) != 0 } - pub fn W_EXITCODE(ret: ::c_int, sig: ::c_int) -> ::c_int { + pub {const} fn W_EXITCODE(ret: ::c_int, sig: ::c_int) -> ::c_int { (ret << 8) | sig } - pub fn W_STOPCODE(sig: ::c_int) -> ::c_int { + pub {const} fn W_STOPCODE(sig: ::c_int) -> ::c_int { (sig << 8) | 0x7f } - pub fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { + pub {const} fn QCMD(cmd: ::c_int, type_: ::c_int) -> ::c_int { (cmd << 8) | (type_ & 0x00ff) } - pub fn IPOPT_COPIED(o: u8) -> u8 { + pub {const} fn IPOPT_COPIED(o: u8) -> u8 { o & IPOPT_COPY } - pub fn IPOPT_CLASS(o: u8) -> u8 { + pub {const} fn IPOPT_CLASS(o: u8) -> u8 { o & IPOPT_CLASS_MASK } - pub fn IPOPT_NUMBER(o: u8) -> u8 { + pub {const} fn IPOPT_NUMBER(o: u8) -> u8 { o & IPOPT_NUMBER_MASK } - pub fn IPTOS_ECN(x: u8) -> u8 { + pub {const} fn IPTOS_ECN(x: u8) -> u8 { x & ::IPTOS_ECN_MASK } } @@ -1308,12 +1312,18 @@ extern "C" { len: ::size_t, vec: *mut ::c_uchar, ) -> ::c_int; + pub fn clock_getres(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; pub fn clock_gettime(clk_id: ::clockid_t, tp: *mut ::timespec) -> ::c_int; pub fn clock_settime( clk_id: ::clockid_t, tp: *const ::timespec, ) -> ::c_int; + pub fn clock_getcpuclockid( + pid: ::pid_t, + clk_id: *mut ::clockid_t, + ) -> ::c_int; + pub fn dirfd(dirp: *mut ::DIR) -> ::c_int; pub fn pthread_getattr_np( diff --git a/vendor/libc/src/unix/solarish/mod.rs b/vendor/libc/src/unix/solarish/mod.rs index 532e5aa6cf..9b1daeb659 100644 --- a/vendor/libc/src/unix/solarish/mod.rs +++ b/vendor/libc/src/unix/solarish/mod.rs @@ -2266,6 +2266,15 @@ extern "C" { f: extern "C" fn(*mut ::c_void) -> *mut ::c_void, value: *mut ::c_void, ) -> ::c_int; + pub fn pthread_getattr_np( + thread: ::pthread_t, + attr: *mut ::pthread_attr_t, + ) -> ::c_int; + pub fn pthread_attr_getstack( + attr: *const ::pthread_attr_t, + stackaddr: *mut *mut ::c_void, + stacksize: *mut ::size_t, + ) -> ::c_int; pub fn pthread_condattr_getclock( attr: *const pthread_condattr_t, clock_id: *mut clockid_t, diff --git a/vendor/libc/src/wasi.rs b/vendor/libc/src/wasi.rs index 6a26858694..12db506417 100644 --- a/vendor/libc/src/wasi.rs +++ b/vendor/libc/src/wasi.rs @@ -202,6 +202,7 @@ pub const O_SEARCH: c_int = 0x08000000; pub const O_WRONLY: c_int = 0x10000000; pub const O_RDWR: c_int = O_WRONLY | O_RDONLY; pub const O_ACCMODE: c_int = O_EXEC | O_RDWR | O_SEARCH; +pub const O_NOCTTY: c_int = 0x0; pub const POSIX_FADV_DONTNEED: c_int = 4; pub const POSIX_FADV_NOREUSE: c_int = 5; pub const POSIX_FADV_NORMAL: c_int = 0; @@ -230,6 +231,17 @@ pub const DT_REG: u8 = 4; pub const DT_LNK: u8 = 7; pub const FIONREAD: c_int = 1; pub const FIONBIO: c_int = 2; +pub const F_OK: ::c_int = 0; +pub const R_OK: ::c_int = 4; +pub const W_OK: ::c_int = 2; +pub const X_OK: ::c_int = 1; +pub const POLLIN: ::c_short = 0x1; +pub const POLLOUT: ::c_short = 0x2; +pub const POLLERR: ::c_short = 0x1000; +pub const POLLHUP: ::c_short = 0x2000; +pub const POLLNVAL: ::c_short = 0x4000; +pub const POLLRDNORM: ::c_short = 0x1; +pub const POLLWRNORM: ::c_short = 0x2; pub const E2BIG: c_int = 1; pub const EACCES: c_int = 2; diff --git a/vendor/libloading/.cargo-checksum.json b/vendor/libloading/.cargo-checksum.json index 2685cdd749..b13fbd8317 100644 --- a/vendor/libloading/.cargo-checksum.json +++ b/vendor/libloading/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"f6ff11a653f961e5ece86a28ad80d498a974cac8200d3a2d9c88abf9438070b4","LICENSE":"b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f","README.mkd":"1be1c69361f15ea2a555dfd9abb05fcef1b692019e4911cbfdaa4e734baa89e3","build.rs":"836e601b6f981ded849d531053a017fc9fa1fffbe7162f124fab0ca161142ab3","src/changelog.rs":"ad8371639d99571911f6e35142905ebd5eb9b520000e7f02989bdbebf5571eef","src/error.rs":"13c880ebc44626cd69f8a6c287ce81dd5ba2947ffa7913da727b8c2ad9910a3a","src/lib.rs":"55d9d61c6403b8634e128f0d0f64f5376b89b7bd75f459592660a471c88e9576","src/os/mod.rs":"51d733e5522dacd6069642ad66aa6d7acf6c82950c934eb040e8dfd112e6d610","src/os/unix/mod.rs":"ac04bbae9d42e74c128c4afd3581cc427b7109a16b968de3899522a4ce2e366f","src/os/windows/mod.rs":"4d0dd74b217a13efa99105c647de4fa807781343e15a3bc2554a1b3df7738d2e","src/test_helpers.rs":"3a55052e8cd5231e97d9282b43398c2f144c57ced2d2df64bde7f482f5c778e7","src/util.rs":"ce5da7b01f15c1d8d99a435079884d86abac861a0f2a1593df44fcb6478ad735","tests/functions.rs":"35132cb8057acb0abe73527872aa7f8d6b3b43773dd5c4d076dddf9d0d2d51a1","tests/markers.rs":"8e9c1b883404d9190e4f23ed39b3d6cbbccb3a07883f733b04aed4357b9c6aca","tests/nagisa32.dll":"5c69b2bd9c8a6ad04165c221075fc9fade1dd66ca697399ace528a5a62328e36","tests/nagisa64.dll":"e20b95e3036f3289421abd100760874d4f455afd33c3b5b64fec56b191f7d477","tests/windows.rs":"7711dfe19062d91356cd127546542b1b6e13aeef76ad3098f32c8a6ae319b66a"},"package":"2cadb8e769f070c45df05c78c7520eb4cd17061d4ab262e43cfc68b4d00ac71c"} \ No newline at end of file +{"files":{"Cargo.toml":"cbed52e85049d7bdb634eda426ab4219bc7cca2ebb8ad538c62367f9c02e4ea8","LICENSE":"b29f8b01452350c20dd1af16ef83b598fea3053578ccc1c7a0ef40e57be2620f","README.mkd":"a393e1f356cb808332ce9259dba73214b00595198bb8b6274e12f86c79ecfa5d","build.rs":"50f772ce98b73be6000de5477020bd84c1e99e6acbf66877876a4b3a4fb0d169","src/changelog.rs":"0b44d40939f95afa33118e41ae2d11762f089b55d29c9157b20bcd6ea7d485c7","src/error.rs":"42fba08d5af2a1d4822e933fb9158d21761bbbfa8b83b1a09389158544b63925","src/lib.rs":"93e856cc28233c187b8dc2e39fdf33291f0323e1716a94e0500f2508ddfac71d","src/os/mod.rs":"88ff3de01a3a2e2ddd45d11de37f765fde2f2afc043e79fa78271c3a266815d4","src/os/unix/consts.rs":"027cd1c54eadb7ae87d8451181c16d6560b68d20ef684c6e15daa4ce56417840","src/os/unix/mod.rs":"227d331c0fc7e8ae9ef1a80f80539b3795a80d7b17ff7ab04b18239be15a0914","src/os/windows/mod.rs":"cadf5983848565ad6581a3edc068f3a1047d871dfaf8c3bef5275413eb2f13f1","src/test_helpers.rs":"201403e143e5b3204864124cd38067cf8813d5273dc1a9099288a9dc4bdd15b6","src/util.rs":"571ce54e82c48bb4d678240da1f61c2c935248b4e5b3010b49174b32224b9542","tests/constants.rs":"f958b26be93bd26d37b25963f019b7856151cb18dd98d34923ddf968121f7f0a","tests/functions.rs":"7f488a5009d94be9f96d18c54af5b7f5bfd52535fb898fda1c74bc00b14b284c","tests/library_filename.rs":"b1481f0bb374687c5f24e25113426d2a95f08a45fb8bc41a41e8702bd5a7b4bf","tests/markers.rs":"0ebc8f807b92e39452d35732988012cdca7ce96231c57eaac9c3f4217225ad39","tests/nagisa32.dll":"5c69b2bd9c8a6ad04165c221075fc9fade1dd66ca697399ace528a5a62328e36","tests/nagisa64.dll":"e20b95e3036f3289421abd100760874d4f455afd33c3b5b64fec56b191f7d477","tests/windows.rs":"7711dfe19062d91356cd127546542b1b6e13aeef76ad3098f32c8a6ae319b66a"},"package":"2443d8f0478b16759158b2f66d525991a05491138bc05814ef52a250148ef4f9"} \ No newline at end of file diff --git a/vendor/libloading/Cargo.toml b/vendor/libloading/Cargo.toml index 630f1e7044..41ad4e7656 100644 --- a/vendor/libloading/Cargo.toml +++ b/vendor/libloading/Cargo.toml @@ -12,14 +12,26 @@ [package] name = "libloading" -version = "0.6.2" +version = "0.6.3" authors = ["Simonas Kazlauskas "] build = "build.rs" description = "A safer binding to platform’s dynamic library loading utilities" documentation = "https://docs.rs/libloading/" +readme = "README.mkd" keywords = ["dlopen", "load", "shared", "dylib"] +categories = ["api-bindings"] license = "ISC" repository = "https://github.com/nagisa/rust_libloading/" +[package.metadata.docs.rs] +all-features = true +rustdoc-args = ["--cfg", "docsrs"] +[dev-dependencies.libc] +version = "0.2" + +[dev-dependencies.static_assertions] +version = "1.1" +[target."cfg(unix)".dependencies.cfg-if] +version = "0.1" [target."cfg(windows)".dependencies.winapi] version = "0.3" features = ["winerror", "errhandlingapi", "libloaderapi"] diff --git a/vendor/libloading/README.mkd b/vendor/libloading/README.mkd index 006f172340..8f7d3427ce 100644 --- a/vendor/libloading/README.mkd +++ b/vendor/libloading/README.mkd @@ -1,6 +1,6 @@ # libloading -A memory-safer wrapper around system dynamic library loading primitives. The most important safety +Safer bindings around system dynamic library loading primitives. The most important safety guarantee by this library is prevention of dangling-`Symbol`s that may occur after a `Library` is unloaded. @@ -13,4 +13,4 @@ functions and static variables these libraries contain. [docs]: https://docs.rs/libloading/ [changelog]: https://docs.rs/libloading/*/libloading/changelog/index.html -libloading is distributed under ISC (MIT-like) license. +libloading is available to use under ISC (MIT-like) license. diff --git a/vendor/libloading/build.rs b/vendor/libloading/build.rs index fdc446d34b..e217f80128 100644 --- a/vendor/libloading/build.rs +++ b/vendor/libloading/build.rs @@ -61,4 +61,10 @@ fn main() { ::std::process::exit(0xfd); } } + + // For tests + println!( + "cargo:rustc-env=LIBLOADING_TEST_TARGET={}", + std::env::var("TARGET").expect("$TARGET is not set") + ); } diff --git a/vendor/libloading/src/changelog.rs b/vendor/libloading/src/changelog.rs index 952eb5ec2d..01c25ec483 100644 --- a/vendor/libloading/src/changelog.rs +++ b/vendor/libloading/src/changelog.rs @@ -1,6 +1,18 @@ //! Project changelog // TODO: for the next breaking release rename `Error::LoadLibraryW` to `Error::LoadLibraryExW`. +// TODO: for the next breaking release use `RTLD_LAZY | RTLD_LOCAL` by default on unix. + +/// Release 0.6.3 (2020-08-22) +/// +/// * Improve documentation, allowing to view all of the os-specific functionality from +/// documentation generated for any target; +/// * Add [`os::windows::Library::this`]; +/// * Added constants to use with OS-specific `Library::open`; +/// * Add [`library_filename`]. +/// +/// [`os::windows::Library::this`]: crate::os::windows::Library::this +/// [`library_filename`]: crate::library_filename /// Release 0.6.2 (2020-05-06) /// @@ -12,7 +24,7 @@ pub mod r0_6_2 {} /// * Introduced a new method [`os::windows::Library::load_with_flags`]; /// * Added support for the Illumos triple. /// -/// [`os::windows::Library::load_with_flags`]: ../../os/windows/struct.Library.html#method.load_with_flags +/// [`os::windows::Library::load_with_flags`]: crate::os::windows::Library::load_with_flags pub mod r0_6_1 {} /// Release 0.6.0 (2020-04-05) @@ -39,9 +51,9 @@ pub mod r0_6_1 {} /// `dlsym` returns a null pointer. For the use-cases where loading null pointers is necessary /// consider using [`os::unix::Library::get_singlethreaded`] instead. /// -/// [`Library::get`]: ../../struct.Library.html#method.get -/// [`os::unix::Library::get_singlethreaded`]: ../../os/unix/struct.Library.html#method.get_singlethreaded -/// [`Error`]: ../../enum.Error.html +/// [`Library::get`]: crate::Library::get +/// [`os::unix::Library::get_singlethreaded`]: crate::os::unix::Library::get_singlethreaded +/// [`Error`]: crate::Error pub mod r0_6_0 {} diff --git a/vendor/libloading/src/error.rs b/vendor/libloading/src/error.rs index dcbe2b1143..6ba536709d 100644 --- a/vendor/libloading/src/error.rs +++ b/vendor/libloading/src/error.rs @@ -1,5 +1,6 @@ use std::ffi::CString; +/// A `dlerror` error. pub struct DlDescription(pub(crate) CString); impl std::fmt::Debug for DlDescription { @@ -8,6 +9,7 @@ impl std::fmt::Debug for DlDescription { } } +/// A Windows API error. pub struct WindowsError(pub(crate) std::io::Error); impl std::fmt::Debug for WindowsError { @@ -16,39 +18,71 @@ impl std::fmt::Debug for WindowsError { } } +/// Errors. #[derive(Debug)] #[non_exhaustive] pub enum Error { /// The `dlopen` call failed. - DlOpen { desc: DlDescription }, + DlOpen { + /// The source error. + desc: DlDescription + }, /// The `dlopen` call failed and system did not report an error. DlOpenUnknown, /// The `dlsym` call failed. - DlSym { desc: DlDescription }, + DlSym { + /// The source error. + desc: DlDescription + }, /// The `dlsym` call failed and system did not report an error. DlSymUnknown, /// The `dlclose` call failed. - DlClose { desc: DlDescription }, + DlClose { + /// The source error. + desc: DlDescription + }, /// The `dlclose` call failed and system did not report an error. DlCloseUnknown, /// The `LoadLibraryW` call failed. - LoadLibraryW { source: WindowsError }, + LoadLibraryW { + /// The source error. + source: WindowsError + }, /// The `LoadLibraryW` call failed and system did not report an error. LoadLibraryWUnknown, + /// The `GetModuleHandleExW` call failed. + GetModuleHandleExW { + /// The source error. + source: WindowsError + }, + /// The `LoadLibraryW` call failed and system did not report an error. + GetModuleHandleExWUnknown, /// The `GetProcAddress` call failed. - GetProcAddress { source: WindowsError }, + GetProcAddress { + /// The source error. + source: WindowsError + }, /// The `GetProcAddressUnknown` call failed and system did not report an error. GetProcAddressUnknown, /// The `FreeLibrary` call failed. - FreeLibrary { source: WindowsError }, + FreeLibrary { + /// The source error. + source: WindowsError + }, /// The `FreeLibrary` call failed and system did not report an error. FreeLibraryUnknown, /// The requested type cannot possibly work. IncompatibleSize, /// Could not create a new CString. - CreateCString { source: std::ffi::NulError }, + CreateCString { + /// The source error. + source: std::ffi::NulError + }, /// Could not create a new CString from bytes with trailing null. - CreateCStringWithTrailing { source: std::ffi::FromBytesWithNulError }, + CreateCStringWithTrailing { + /// The source error. + source: std::ffi::FromBytesWithNulError + }, } impl std::error::Error for Error { @@ -75,9 +109,12 @@ impl std::fmt::Display for Error { DlSymUnknown => write!(f, "dlsym failed, but system did not report the error"), DlClose { ref desc } => write!(f, "{}", desc.0.to_string_lossy()), DlCloseUnknown => write!(f, "dlclose failed, but system did not report the error"), - LoadLibraryW { .. } => write!(f, "LoadLibraryW failed"), + LoadLibraryW { .. } => write!(f, "LoadLibraryExW failed"), LoadLibraryWUnknown => - write!(f, "LoadLibraryW failed, but system did not report the error"), + write!(f, "LoadLibraryExW failed, but system did not report the error"), + GetModuleHandleExW { .. } => write!(f, "GetModuleHandleExW failed"), + GetModuleHandleExWUnknown => + write!(f, "GetModuleHandleExWUnknown failed, but system did not report the error"), GetProcAddress { .. } => write!(f, "GetProcAddress failed"), GetProcAddressUnknown => write!(f, "GetProcAddress failed, but system did not report the error"), @@ -91,24 +128,3 @@ impl std::fmt::Display for Error { } } } - -#[cfg(test)] -mod tests { - #[test] - fn error_send() { - fn assert_send() {} - assert_send::(); - } - - #[test] - fn error_sync() { - fn assert_sync() {} - assert_sync::(); - } - - #[test] - fn error_display() { - fn assert_display() {} - assert_display::(); - } -} diff --git a/vendor/libloading/src/lib.rs b/vendor/libloading/src/lib.rs index fad7d63396..f6fc58d1ae 100644 --- a/vendor/libloading/src/lib.rs +++ b/vendor/libloading/src/lib.rs @@ -17,7 +17,7 @@ //! //! ```toml //! [dependencies] -//! libloading = "0.5" +//! libloading = "0.6" //! ``` //! //! Then inside your project @@ -36,7 +36,17 @@ //! //! The compiler will ensure that the loaded `function` will not outlive the `Library` it comes //! from, preventing a common cause of undefined behaviour and memory safety problems. -use std::ffi::OsStr; +#![deny( + missing_docs, + clippy::all, + unreachable_pub, + unused, +)] +#![cfg_attr(docsrs, deny(broken_intra_doc_links))] +#![cfg_attr(docsrs, feature(doc_cfg))] + +use std::env::consts::{DLL_PREFIX, DLL_SUFFIX}; +use std::ffi::{OsStr, OsString}; use std::fmt; use std::ops; use std::marker; @@ -64,7 +74,7 @@ impl Library { /// * Absolute path to the library; /// * Relative (to the current working directory) path to the library. /// - /// ## Thread-safety + /// # Thread-safety /// /// The implementation strives to be as MT-safe as sanely possible, however due to certain /// error-handling related resources not always being safe, this library is not MT-safe either. @@ -77,15 +87,17 @@ impl Library { /// [`SetErrorMode`]: https://msdn.microsoft.com/en-us/library/windows/desktop/ms680621(v=vs.85).aspx /// /// Calling this function from multiple threads is not safe if used in conjunction with - /// path-less filename and library search path is modified (`SetDllDirectory` function on + /// relative filenames and the library search path is modified (`SetDllDirectory` function on /// Windows, `{DY,}LD_LIBRARY_PATH` environment variable on UNIX). /// - /// ## Platform-specific behaviour + /// # Platform-specific behaviour /// /// When a plain library filename is supplied, locations where library is searched for is - /// platform specific and cannot be adjusted in a portable manner. + /// platform specific and cannot be adjusted in a portable manner. See documentation for + /// the platform specific [`os::unix::Library::new`] and [`os::windows::Library::new`] methods + /// for further information on library lookup behaviour. /// - /// ### Windows + /// ## Windows /// /// If the `filename` specifies a library filename without path and with extension omitted, /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a @@ -95,17 +107,18 @@ impl Library { /// `#[thread_local]` attributes), loading the library will fail on versions prior to Windows /// Vista. /// - /// ## Tips + /// # Tips /// /// Distributing your dynamic libraries under a filename common to all platforms (e.g. /// `awesome.module`) allows to avoid code which has to account for platform’s conventional /// library filenames. /// - /// Strive to specify absolute or relative path to your library, unless system-wide libraries - /// are being loaded. Platform-dependent library search locations combined with various quirks - /// related to path-less filenames may cause flaky code. + /// Strive to specify an absolute or at least a relative path to your library, unless + /// system-wide libraries are being loaded. Platform-dependent library search locations + /// combined with various quirks related to path-less filenames may cause flakiness in + /// programs. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::Library; @@ -126,16 +139,16 @@ impl Library { /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is /// undefined. /// - /// ## Platform-specific behaviour + /// # Platform-specific behaviour /// - /// On Linux and Windows, a TLS variable acts just like any regular global variable. OS X uses - /// some sort of lazy initialization scheme, which makes loading TLS variables this way - /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour. + /// Implementation of thread local variables is extremely platform specific and uses of these + /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems or + /// Windows. /// /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such /// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call @@ -143,7 +156,7 @@ impl Library { /// pointer without it being an error. If loading a null pointer is something you care about, /// consider using the [`os::unix::Library::get_singlethreaded`] call. /// - /// ## Examples + /// # Examples /// /// Given a loaded library: /// @@ -232,12 +245,13 @@ pub struct Symbol<'lib, T: 'lib> { impl<'lib, T> Symbol<'lib, T> { /// Extract the wrapped `os::platform::Symbol`. /// - /// ## Unsafety + /// # Safety + /// /// Using this function relinquishes all the lifetime guarantees. It is up to programmer to /// ensure the resulting `Symbol` is not used past the lifetime of the `Library` this symbol /// was loaded from. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::{Library, Symbol}; @@ -256,12 +270,12 @@ impl<'lib, T> Symbol<'lib, T> { /// Note that, in order to create association between the symbol and the library this symbol /// came from, this function requires reference to the library provided. /// - /// ## Unsafety + /// # Safety /// /// It is invalid to provide a reference to any other value other than the library the `sym` /// was loaded from. Doing so invalidates any lifetime guarantees. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::{Library, Symbol}; @@ -283,7 +297,7 @@ impl<'lib, T> Symbol<'lib, T> { impl<'lib, T> Symbol<'lib, Option> { /// Lift Option out of the symbol. /// - /// ## Examples + /// # Examples /// /// ```no_run /// # use ::libloading::{Library, Symbol}; @@ -326,3 +340,27 @@ impl<'lib, T> fmt::Debug for Symbol<'lib, T> { unsafe impl<'lib, T: Send> Send for Symbol<'lib, T> {} unsafe impl<'lib, T: Sync> Sync for Symbol<'lib, T> {} + +/// Converts a library name to a filename generally appropriate for use on the system. +/// +/// The function will prepend prefixes (such as `lib`) and suffixes (such as `.so`) to the library +/// `name` to construct the filename. +/// +/// # Examples +/// +/// It can be used to load global libraries in a platform independent manner: +/// +/// ``` +/// use libloading::{Library, library_filename}; +/// // Will attempt to load `libLLVM.so` on Linux, `libLLVM.dylib` on macOS and `LLVM.dll` on +/// // Windows. +/// let library = Library::new(library_filename("LLVM")); +/// ``` +pub fn library_filename>(name: S) -> OsString { + let name = name.as_ref(); + let mut string = OsString::with_capacity(name.len() + DLL_PREFIX.len() + DLL_SUFFIX.len()); + string.push(DLL_PREFIX); + string.push(name); + string.push(DLL_SUFFIX); + string +} diff --git a/vendor/libloading/src/os/mod.rs b/vendor/libloading/src/os/mod.rs index ccbc8e9778..40361c5f30 100644 --- a/vendor/libloading/src/os/mod.rs +++ b/vendor/libloading/src/os/mod.rs @@ -16,30 +16,12 @@ //! use libloading::os::windows::*; //! ``` -macro_rules! unix { - ($item: item) => { - /// UNIX implementation of dynamic library loading. - /// - /// This module should be expanded with more UNIX-specific functionality in the future. - $item - } -} +/// UNIX implementation of dynamic library loading. +#[cfg(any(unix, docsrs))] +#[cfg_attr(docsrs, doc(cfg(unix)))] +pub mod unix; -macro_rules! windows { - ($item: item) => { - /// Windows implementation of dynamic library loading. - /// - /// This module should be expanded with more Windows-specific functionality in the future. - $item - } -} - -#[cfg(unix)] -unix!(pub mod unix;); -#[cfg(unix)] -windows!(pub mod windows {}); - -#[cfg(windows)] -windows!(pub mod windows;); -#[cfg(windows)] -unix!(pub mod unix {}); +/// Windows implementation of dynamic library loading. +#[cfg(any(windows, docsrs))] +#[cfg_attr(docsrs, doc(cfg(windows)))] +pub mod windows; diff --git a/vendor/libloading/src/os/unix/consts.rs b/vendor/libloading/src/os/unix/consts.rs new file mode 100644 index 0000000000..823155e75f --- /dev/null +++ b/vendor/libloading/src/os/unix/consts.rs @@ -0,0 +1,230 @@ +use std::os::raw::c_int; + +/// Perform lazy binding. +/// +/// Relocations shall be performed at an implementation-defined time, ranging from the time +/// of the [`Library::open`] call until the first reference to a given symbol occurs. +/// Specifying `RTLD_LAZY` should improve performance on implementations supporting dynamic +/// symbol binding since a process might not reference all of the symbols in an executable +/// object file. And, for systems supporting dynamic symbol resolution for normal process +/// execution, this behavior mimics the normal handling of process execution. +/// +/// Conflicts with [`RTLD_NOW`]. +/// +/// [`Library::open`]: crate::os::unix::Library::open +pub const RTLD_LAZY: c_int = posix::RTLD_LAZY; + +/// Perform eager binding. +/// +/// All necessary relocations shall be performed when the executable object file is first +/// loaded. This may waste some processing if relocations are performed for symbols +/// that are never referenced. This behavior may be useful for applications that need to +/// know that all symbols referenced during execution will be available before +/// [`Library::open`] returns. +/// +/// Conflicts with [`RTLD_LAZY`]. +/// +/// [`Library::open`]: crate::os::unix::Library::open +pub const RTLD_NOW: c_int = posix::RTLD_NOW; + +/// Make loaded symbols available for resolution globally. +/// +/// The executable object file's symbols shall be made available for relocation processing of any +/// other executable object file. In addition, calls to [`Library::get`] on `Library` obtained from +/// [`Library::this`] allows executable object files loaded with this mode to be searched. +/// +/// [`Library::this`]: crate::os::unix::Library::this +/// [`Library::get`]: crate::os::unix::Library::get +pub const RTLD_GLOBAL: c_int = posix::RTLD_GLOBAL; + +/// Load symbols into an isolated namespace. +/// +/// The executable object file's symbols shall not be made available for relocation processing of +/// any other executable object file. This mode of operation is most appropriate for e.g. plugins. +pub const RTLD_LOCAL: c_int = posix::RTLD_LOCAL; + +#[cfg(docsrs)] +mod posix { + use super::c_int; + pub(super) const RTLD_LAZY: c_int = !0; + pub(super) const RTLD_NOW: c_int = !0; + pub(super) const RTLD_GLOBAL: c_int = !0; + pub(super) const RTLD_LOCAL: c_int = !0; +} + +#[cfg(not(docsrs))] +mod posix { + extern crate cfg_if; + use self::cfg_if::cfg_if; + use super::c_int; + cfg_if! { + if #[cfg(target_os = "haiku")] { + pub(super) const RTLD_LAZY: c_int = 0; + } else if #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_LAZY: c_int = 1; + } else { + compile_error!( + "Target has no known `RTLD_LAZY` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(target_os = "haiku")] { + pub(super) const RTLD_NOW: c_int = 1; + } else if #[cfg(any( + target_os = "linux", + all(target_os = "android", target_pointer_width = "64"), + target_os = "emscripten", + + target_os = "macos", + target_os = "ios", + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_NOW: c_int = 2; + } else if #[cfg(all(target_os = "android",target_pointer_width = "32"))] { + pub(super) const RTLD_NOW: c_int = 0; + } else { + compile_error!( + "Target has no known `RTLD_NOW` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(any( + target_os = "haiku", + all(target_os = "android",target_pointer_width = "32"), + ))] { + pub(super) const RTLD_GLOBAL: c_int = 2; + } else if #[cfg(any( + target_env = "uclibc", + all(target_os = "linux", target_arch = "mips"), + all(target_os = "linux", target_arch = "mips64"), + ))] { + pub(super) const RTLD_GLOBAL: c_int = 4; + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + ))] { + pub(super) const RTLD_GLOBAL: c_int = 8; + } else if #[cfg(any( + target_os = "linux", + all(target_os = "android", target_pointer_width = "64"), + target_os = "emscripten", + + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + target_os = "netbsd", + + target_os = "solaris", + target_os = "illumos", + + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_GLOBAL: c_int = 0x100; + } else { + compile_error!( + "Target has no known `RTLD_GLOBAL` value. Please submit an issue or PR adding it." + ); + } + } + + cfg_if! { + if #[cfg(target_os = "netbsd")] { + pub(super) const RTLD_LOCAL: c_int = 0x200; + } else if #[cfg(any( + target_os = "macos", + target_os = "ios", + ))] { + pub(super) const RTLD_LOCAL: c_int = 4; + } else if #[cfg(any( + target_os = "linux", + target_os = "android", + target_os = "emscripten", + + target_os = "freebsd", + target_os = "dragonfly", + target_os = "openbsd", + + target_os = "haiku", + + target_os = "solaris", + target_os = "illumos", + + target_env = "uclibc", + target_env = "newlib", + + target_os = "fuchsia", + target_os = "redox", + ))] { + pub(super) const RTLD_LOCAL: c_int = 0; + } else { + compile_error!( + "Target has no known `RTLD_LOCAL` value. Please submit an issue or PR adding it." + ); + } + } +} + +// Other constants that exist but are not bound because they are platform-specific (non-posix) +// extensions. Some of these constants are only relevant to `dlsym` or `dlmopen` calls. +// +// RTLD_CONFGEN +// RTLD_DEFAULT +// RTLD_DI_CONFIGADDR +// RTLD_DI_LINKMAP +// RTLD_DI_LMID +// RTLD_DI_ORIGIN +// RTLD_DI_PROFILENAME +// RTLD_DI_PROFILEOUT +// RTLD_DI_SERINFO +// RTLD_DI_SERINFOSIZE +// RTLD_DI_TLS_DATA +// RTLD_DI_TLS_MODID +// RTLD_FIRST +// RTLD_GROUP +// RTLD_NEXT +// RTLD_PARENT +// RTLD_PROBE +// RTLD_SELF +// RTLD_WORLD +// RTLD_NODELETE +// RTLD_NOLOAD +// RTLD_DEEPBIND diff --git a/vendor/libloading/src/os/unix/mod.rs b/vendor/libloading/src/os/unix/mod.rs index 29d2003659..785c58f264 100644 --- a/vendor/libloading/src/os/unix/mod.rs +++ b/vendor/libloading/src/os/unix/mod.rs @@ -1,9 +1,21 @@ -use util::{ensure_compatible_types, cstr_cow_from_bytes}; +// A hack for docs.rs to build documentation that has both windows and linux documentation in the +// same rustdoc build visible. +#[cfg(all(docsrs, not(unix)))] +mod unix_imports { +} +#[cfg(any(not(docsrs), unix))] +mod unix_imports { + pub(super) use std::os::unix::ffi::OsStrExt; +} +use self::unix_imports::*; +use util::{ensure_compatible_types, cstr_cow_from_bytes}; use std::ffi::{CStr, OsStr}; use std::{fmt, marker, mem, ptr}; use std::os::raw; -use std::os::unix::ffi::OsStrExt; +pub use self::consts::*; + +mod consts; // dl* family of functions did not have enough thought put into it. // @@ -61,7 +73,7 @@ where F: FnOnce() -> Option { }) } -/// A platform-specific equivalent of the cross-platform `Library`. +/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library). pub struct Library { handle: *mut raw::c_void } @@ -85,34 +97,45 @@ unsafe impl Send for Library {} unsafe impl Sync for Library {} impl Library { - /// Find and load a shared library (module). + /// Find and eagerly load a shared library (module). /// - /// Locations where library is searched for is platform specific and can’t be adjusted - /// portably. + /// If the `filename` contains a [path separator], the `filename` is interpreted as a `path` to + /// a file. Otherwise, platform-specific algorithms are employed to find a library with a + /// matching file name. /// - /// Corresponds to `dlopen(filename, RTLD_NOW)`. + /// This is equivalent to [`Library::open`]`(filename, RTLD_NOW)`. + /// + /// [path separator]: std::path::MAIN_SEPARATOR #[inline] pub fn new>(filename: P) -> Result { Library::open(Some(filename), RTLD_NOW) } - /// Load the dynamic libraries linked into main program. + /// Eagerly load the `Library` representing the current executable. /// - /// This allows retrieving symbols from any **dynamic** library linked into the program, - /// without specifying the exact library. + /// [`Library::get`] calls of the returned `Library` will look for symbols in following + /// locations in order: /// - /// Corresponds to `dlopen(NULL, RTLD_NOW)`. + /// 1. Original program image; + /// 2. Any executable object files (e.g. shared libraries) loaded at program startup; + /// 3. Executable object files loaded at runtime (e.g. via other `Library::new` calls or via + /// calls to the `dlopen` function) + /// + /// Note that behaviour of `Library` loaded with this method is different from + /// Libraries loaded with [`os::windows::Library::this`]. + /// + /// This is equivalent to [`Library::open`]`(None, RTLD_NOW)`. + /// + /// [`os::windows::Library::this`]: crate::os::windows::Library::this #[inline] pub fn this() -> Library { Library::open(None::<&OsStr>, RTLD_NOW).expect("this should never fail") } - /// Find and load a shared library (module). + /// Find and load an executable object file (shared library). /// - /// Locations where library is searched for is platform specific and can’t be adjusted - /// portably. - /// - /// If the `filename` is None, null pointer is passed to `dlopen`. + /// See documentation for [`Library::this`] for further description of behaviour + /// when the `filename` is `None`. Otherwise see [`Library::new`]. /// /// Corresponds to `dlopen(filename, flags)`. pub fn open

    (filename: Option

    , flags: raw::c_int) -> Result @@ -174,37 +197,33 @@ impl Library { /// Get a pointer to function or static variable by symbol name. /// /// The `symbol` may not contain any null bytes, with an exception of last byte. A null - /// terminated `symbol` may avoid a string allocation in some cases. + /// terminated `symbol` may avoid an allocation in some cases. /// /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// This function does not validate the type `T`. It is up to the user of this function to /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no - /// definied behaviour. + /// defined behaviour. /// + /// # Platform-specific behaviour /// - /// - /// ## Platform-specific behaviour - /// - /// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables - /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour. + /// Implementation of thread local variables is extremely platform specific and uses of these + /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems. /// /// On POSIX implementations where the `dlerror` function is not confirmed to be MT-safe (such - /// as FreeBSD), this function will unconditionally return an error the underlying `dlsym` call - /// returns a null pointer. There are rare situations where `dlsym` returns a genuine null - /// pointer without it being an error. If loading a null pointer is something you care about, - /// consider using the [`Library::get_singlethreaded`] call. + /// as FreeBSD), this function will unconditionally return an error when the underlying `dlsym` + /// call returns a null pointer. There are rare situations where `dlsym` returns a genuine null + /// pointer without it being an error. If loading a symbol at null address is something you + /// care about, consider using the [`Library::get_singlethreaded`] call. #[inline(always)] pub unsafe fn get(&self, symbol: &[u8]) -> Result, crate::Error> { #[cfg(mtsafe_dlerror)] - { return self.get_singlethreaded(symbol); } + { self.get_singlethreaded(symbol) } #[cfg(not(mtsafe_dlerror))] - { - return self.get_impl(symbol, || Err(crate::Error::DlSymUnknown)); - } + { self.get_impl(symbol, || Err(crate::Error::DlSymUnknown)) } } /// Get a pointer to function or static variable by symbol name. @@ -215,20 +234,20 @@ impl Library { /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// This function does not validate the type `T`. It is up to the user of this function to /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no - /// definied behaviour. + /// defined behaviour. /// /// It is up to the user of this library to ensure that no other calls to an MT-unsafe - /// implementation of `dlerror` occur while this function is executing. Failing that the - /// results of this function are not defined. + /// implementation of `dlerror` occur during execution of this function. Failing that, the + /// behaviour of this function is not defined. /// - /// ## Platform-specific behaviour + /// # Platform-specific behaviour /// - /// OS X uses some sort of lazy initialization scheme, which makes loading TLS variables - /// impossible. Using a TLS variable loaded this way on OS X is undefined behaviour. + /// Implementation of thread local variables is extremely platform specific and uses of these + /// variables that work on e.g. Linux may have unintended behaviour on other POSIX systems. #[inline(always)] pub unsafe fn get_singlethreaded(&self, symbol: &[u8]) -> Result, crate::Error> { self.get_impl(symbol, || Ok(Symbol { @@ -249,14 +268,14 @@ impl Library { /// Convert a raw handle returned by `dlopen`-family of calls to a `Library`. /// - /// ## Unsafety + /// # Safety /// /// The pointer shall be a result of a successful call of the `dlopen`-family of functions or a /// pointer previously returned by `Library::into_raw` call. It must be valid to call `dlclose` /// with this pointer as an argument. pub unsafe fn from_raw(handle: *mut raw::c_void) -> Library { Library { - handle: handle + handle } } @@ -266,8 +285,7 @@ impl Library { /// what library was opened or other platform specifics. /// /// You only need to call this if you are interested in handling any errors that may arise when - /// library is unloaded. Otherwise the implementation of `Drop` for `Library` will close the - /// library and ignore the errors were they arise. + /// library is unloaded. Otherwise this will be done when `Library` is dropped. pub fn close(self) -> Result<(), crate::Error> { let result = with_dlerror(|desc| crate::Error::DlClose { desc }, || { if unsafe { dlclose(self.handle) } == 0 { @@ -341,7 +359,7 @@ impl ::std::ops::Deref for Symbol { fn deref(&self) -> &T { unsafe { // Additional reference level for a dereference on `deref` return value. - mem::transmute(&self.pointer) + &*(&self.pointer as *const *mut _ as *const T) } } } @@ -369,7 +387,6 @@ impl fmt::Debug for Symbol { } // Platform specific things - extern { fn dlopen(filename: *const raw::c_char, flags: raw::c_int) -> *mut raw::c_void; fn dlclose(handle: *mut raw::c_void) -> raw::c_int; @@ -378,11 +395,6 @@ extern { fn dladdr(addr: *mut raw::c_void, info: *mut DlInfo) -> raw::c_int; } -#[cfg(not(target_os="android"))] -const RTLD_NOW: raw::c_int = 2; -#[cfg(target_os="android")] -const RTLD_NOW: raw::c_int = 0; - #[repr(C)] struct DlInfo { dli_fname: *const raw::c_char, @@ -390,11 +402,3 @@ struct DlInfo { dli_sname: *const raw::c_char, dli_saddr: *mut raw::c_void } - -#[cfg(test)] -mod tests { - #[test] - fn this() { - super::Library::this(); - } -} diff --git a/vendor/libloading/src/os/windows/mod.rs b/vendor/libloading/src/os/windows/mod.rs index 3620b3e383..a106234aff 100644 --- a/vendor/libloading/src/os/windows/mod.rs +++ b/vendor/libloading/src/os/windows/mod.rs @@ -1,17 +1,63 @@ -extern crate winapi; -use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC}; -use self::winapi::shared::ntdef::WCHAR; -use self::winapi::shared::winerror; -use self::winapi::um::{errhandlingapi, libloaderapi}; +// A hack for docs.rs to build documentation that has both windows and linux documentation in the +// same rustdoc build visible. +#[cfg(all(docsrs, not(windows)))] +mod windows_imports { + pub(super) enum WORD {} + pub(super) struct DWORD; + pub(super) enum HMODULE {} + pub(super) enum FARPROC {} + pub(super) mod consts { + use super::DWORD; + pub(crate) const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_DATAFILE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = DWORD; + pub(crate) const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = DWORD; + pub(crate) const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = DWORD; + } +} +#[cfg(any(not(docsrs), windows))] +mod windows_imports { + extern crate winapi; + pub(super) use self::winapi::shared::minwindef::{WORD, DWORD, HMODULE, FARPROC}; + pub(super) use self::winapi::shared::ntdef::WCHAR; + pub(super) use self::winapi::shared::winerror; + pub(super) use self::winapi::um::{errhandlingapi, libloaderapi}; + pub(super) use std::os::windows::ffi::{OsStrExt, OsStringExt}; + pub(super) const SEM_FAILCE: DWORD = 1; + + pub(super) mod consts { + pub(crate) use super::winapi::um::libloaderapi::{ + LOAD_IGNORE_CODE_AUTHZ_LEVEL, + LOAD_LIBRARY_AS_DATAFILE, + LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE, + LOAD_LIBRARY_AS_IMAGE_RESOURCE, + LOAD_LIBRARY_SEARCH_APPLICATION_DIR, + LOAD_LIBRARY_SEARCH_DEFAULT_DIRS, + LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR, + LOAD_LIBRARY_SEARCH_SYSTEM32, + LOAD_LIBRARY_SEARCH_USER_DIRS, + LOAD_WITH_ALTERED_SEARCH_PATH, + LOAD_LIBRARY_REQUIRE_SIGNED_TARGET, + LOAD_LIBRARY_SAFE_CURRENT_DIRS, + }; + } +} + +use self::windows_imports::*; use util::{ensure_compatible_types, cstr_cow_from_bytes}; - use std::ffi::{OsStr, OsString}; use std::{fmt, io, marker, mem, ptr}; -use std::os::windows::ffi::{OsStrExt, OsStringExt}; use std::sync::atomic::{AtomicBool, Ordering}; -/// A platform-specific equivalent of the cross-platform `Library`. +/// A platform-specific counterpart of the cross-platform [`Library`](crate::Library). pub struct Library(HMODULE); unsafe impl Send for Library {} @@ -31,20 +77,56 @@ unsafe impl Send for Library {} unsafe impl Sync for Library {} impl Library { - /// Find and load a shared library (module). + /// Find and load a module. /// - /// Corresponds to `LoadLibraryW(filename, reserved: NULL, flags: 0)` which is equivalent to `LoadLibraryW(filename)` + /// If the `filename` specifies a full path, the function only searches that path for the + /// module. Otherwise, if the `filename` specifies a relative path or a module name without a + /// path, the function uses a windows-specific search strategy to find the module; for more + /// information, see the [Remarks on MSDN][msdn]. + /// + /// If the `filename` specifies a library filename without path and with extension omitted, + /// `.dll` extension is implicitly added. This behaviour may be suppressed by appending a + /// trailing `.` to the `filename`. + /// + /// This is equivalent to [`Library::load_with_flags`]`(filename, 0)`. + /// + /// [msdn]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryw#remarks #[inline] pub fn new>(filename: P) -> Result { Library::load_with_flags(filename, 0) } - /// Find and load a shared library (module). + /// Load the `Library` representing the original program executable. /// - /// Locations where library is searched for is platform specific and can’t be adjusted - /// portably. + /// Note that behaviour of `Library` loaded with this method is different from + /// Libraries loaded with [`os::unix::Library::this`]. For more information refer to [MSDN]. /// - /// Corresponds to `LoadLibraryW(filename, reserved: NULL, flags)`. + /// Corresponds to `GetModuleHandleExW(0, NULL, _)`. + /// + /// [`os::unix::Library::this`]: crate::os::unix::Library::this + /// [MSDN]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-getmodulehandleexw + pub fn this() -> Result { + unsafe { + let mut handle: HMODULE = std::ptr::null_mut(); + with_get_last_error(|source| crate::Error::GetModuleHandleExW { source }, || { + let result = libloaderapi::GetModuleHandleExW(0, std::ptr::null_mut(), &mut handle); + if result == 0 { + None + } else { + Some(Library(handle)) + } + }).map_err(|e| e.unwrap_or(crate::Error::GetModuleHandleExWUnknown)) + } + } + + /// Find and load a module, additionally adjusting behaviour with flags. + /// + /// See [`Library::new`] for documentation on handling of the `filename` argument. See the + /// [flag table on MSDN][flags] for information on applicable values for the `flags` argument. + /// + /// Corresponds to `LoadLibraryExW(filename, reserved: NULL, flags)`. + /// + /// [flags]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters pub fn load_with_flags>(filename: P, flags: DWORD) -> Result { let wide_filename: Vec = filename.as_ref().encode_wide().chain(Some(0)).collect(); let _guard = ErrorModeGuard::new(); @@ -52,7 +134,9 @@ impl Library { let ret = with_get_last_error(|source| crate::Error::LoadLibraryW { source }, || { // Make sure no winapi calls as a result of drop happen inside this closure, because // otherwise that might change the return value of the GetLastError. - let handle = unsafe { libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags) }; + let handle = unsafe { + libloaderapi::LoadLibraryExW(wide_filename.as_ptr(), std::ptr::null_mut(), flags) + }; if handle.is_null() { None } else { @@ -72,7 +156,7 @@ impl Library { /// Symbol is interpreted as-is; no mangling is done. This means that symbols like `x::y` are /// most likely invalid. /// - /// ## Unsafety + /// # Safety /// /// This function does not validate the type `T`. It is up to the user of this function to /// ensure that the loaded symbol is in fact a `T`. Using a value with a wrong type has no @@ -95,7 +179,7 @@ impl Library { /// Get a pointer to function or static variable by ordinal number. /// - /// ## Unsafety + /// # Safety /// /// Pointer to a value of arbitrary type is returned. Using a value with wrong type is /// undefined. @@ -124,7 +208,7 @@ impl Library { /// Convert a raw handle to a `Library`. /// - /// ## Unsafety + /// # Safety /// /// The handle shall be a result of a successful call of `LoadLibraryW` or a /// handle previously returned by the `Library::into_raw` call. @@ -217,7 +301,7 @@ impl ::std::ops::Deref for Symbol { fn deref(&self) -> &T { unsafe { // Additional reference level for a dereference on `deref` return value. - mem::transmute(&self.pointer) + &*(&self.pointer as *const *mut _ as *const T) } } } @@ -228,13 +312,12 @@ impl fmt::Debug for Symbol { } } - static USE_ERRORMODE: AtomicBool = AtomicBool::new(false); struct ErrorModeGuard(DWORD); impl ErrorModeGuard { + #[allow(clippy::if_same_then_else)] fn new() -> Option { - const SEM_FAILCE: DWORD = 1; unsafe { if !USE_ERRORMODE.load(Ordering::Acquire) { let mut previous_mode = 0; @@ -302,31 +385,114 @@ where F: FnOnce() -> Option { }) } -#[cfg(test)] -mod tests { - use super::*; +/// Do not check AppLocker rules or apply Software Restriction Policies for the DLL. +/// +/// This action applies only to the DLL being loaded and not to its dependencies. This value is +/// recommended for use in setup programs that must run extracted DLLs during installation. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_IGNORE_CODE_AUTHZ_LEVEL: DWORD = consts::LOAD_IGNORE_CODE_AUTHZ_LEVEL; - #[test] - fn works_getlasterror() { - let lib = Library::new("kernel32.dll").unwrap(); - let gle: Symbol DWORD> = unsafe { - lib.get(b"GetLastError").unwrap() - }; - unsafe { - errhandlingapi::SetLastError(42); - assert_eq!(errhandlingapi::GetLastError(), gle()) - } - } +/// Map the file into the calling process’ virtual address space as if it were a data file. +/// +/// Nothing is done to execute or prepare to execute the mapped file. Therefore, you cannot call +/// functions like [`Library::get`] with this DLL. Using this value causes writes to read-only +/// memory to raise an access violation. Use this flag when you want to load a DLL only to extract +/// messages or resources from it. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_DATAFILE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE; - #[test] - fn works_getlasterror0() { - let lib = Library::new("kernel32.dll").unwrap(); - let gle: Symbol DWORD> = unsafe { - lib.get(b"GetLastError\0").unwrap() - }; - unsafe { - errhandlingapi::SetLastError(42); - assert_eq!(errhandlingapi::GetLastError(), gle()) - } - } -} +/// Map the file into the calling process’ virtual address space as if it were a data file. +/// +/// Similar to [`LOAD_LIBRARY_AS_DATAFILE`], except that the DLL file is opened with exclusive +/// write access for the calling process. Other processes cannot open the DLL file for write access +/// while it is in use. However, the DLL can still be opened by other processes. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE: DWORD = consts::LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE; + +/// Map the file into the process’ virtual address space as an image file. +/// +/// The loader does not load the static imports or perform the other usual initialization steps. +/// Use this flag when you want to load a DLL only to extract messages or resources from it. +/// +/// Unless the application depends on the file having the in-memory layout of an image, this value +/// should be used with either [`LOAD_LIBRARY_AS_DATAFILE_EXCLUSIVE`] or +/// [`LOAD_LIBRARY_AS_DATAFILE`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_AS_IMAGE_RESOURCE: DWORD = consts::LOAD_LIBRARY_AS_IMAGE_RESOURCE; + +/// Search application's installation directory for the DLL and its dependencies. +/// +/// Directories in the standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_APPLICATION_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_APPLICATION_DIR; + +/// Search default directories when looking for the DLL and its dependencies. +/// +/// This value is a combination of [`LOAD_LIBRARY_SEARCH_APPLICATION_DIR`], +/// [`LOAD_LIBRARY_SEARCH_SYSTEM32`], and [`LOAD_LIBRARY_SEARCH_USER_DIRS`]. Directories in the +/// standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_DEFAULT_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_DEFAULT_DIRS; + +/// Directory that contains the DLL is temporarily added to the beginning of the list of +/// directories that are searched for the DLL’s dependencies. +/// +/// Directories in the standard search path are not searched. +/// +/// The `filename` parameter must specify a fully qualified path. This value cannot be combined +/// with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR: DWORD = consts::LOAD_LIBRARY_SEARCH_DLL_LOAD_DIR; + +/// Search `%windows%\system32` for the DLL and its dependencies. +/// +/// Directories in the standard search path are not searched. This value cannot be combined with +/// [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_SYSTEM32: DWORD = consts::LOAD_LIBRARY_SEARCH_SYSTEM32; + +/// Directories added using the `AddDllDirectory` or the `SetDllDirectory` function are searched +/// for the DLL and its dependencies. +/// +/// If more than one directory has been added, the order in which the directories are searched is +/// unspecified. Directories in the standard search path are not searched. This value cannot be +/// combined with [`LOAD_WITH_ALTERED_SEARCH_PATH`]. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SEARCH_USER_DIRS: DWORD = consts::LOAD_LIBRARY_SEARCH_USER_DIRS; + +/// If `filename specifies an absolute path, the system uses the alternate file search strategy +/// discussed in the [Remarks section] to find associated executable modules that the specified +/// module causes to be loaded. +/// +/// If this value is used and `filename` specifies a relative path, the behavior is undefined. +/// +/// If this value is not used, or if `filename` does not specify a path, the system uses the +/// standard search strategy discussed in the [Remarks section] to find associated executable +/// modules that the specified module causes to be loaded. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +/// +/// [Remarks]: https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#remarks +pub const LOAD_WITH_ALTERED_SEARCH_PATH: DWORD = consts::LOAD_WITH_ALTERED_SEARCH_PATH; + +/// Specifies that the digital signature of the binary image must be checked at load time. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_REQUIRE_SIGNED_TARGET: DWORD = consts::LOAD_LIBRARY_REQUIRE_SIGNED_TARGET; + +/// Allow loading a DLL for execution from the current directory only if it is under a directory in +/// the Safe load list. +/// +/// See [flag documentation on MSDN](https://docs.microsoft.com/en-us/windows/win32/api/libloaderapi/nf-libloaderapi-loadlibraryexw#parameters). +pub const LOAD_LIBRARY_SAFE_CURRENT_DIRS: DWORD = consts::LOAD_LIBRARY_SAFE_CURRENT_DIRS; diff --git a/vendor/libloading/src/test_helpers.rs b/vendor/libloading/src/test_helpers.rs index 32f7023188..9e3e9924ff 100644 --- a/vendor/libloading/src/test_helpers.rs +++ b/vendor/libloading/src/test_helpers.rs @@ -1,7 +1,6 @@ //! This is a separate file containing helpers for tests of this library. It is built into a //! dynamic library by the build.rs script. -#![crate_type="dylib"] // FIXME: should become a cdylib in due time -#![cfg_attr(test_nightly, feature(thread_local))] +#![crate_type="cdylib"] #[no_mangle] pub static mut TEST_STATIC_U32: u32 = 0; @@ -9,11 +8,6 @@ pub static mut TEST_STATIC_U32: u32 = 0; #[no_mangle] pub static mut TEST_STATIC_PTR: *mut () = 0 as *mut _; -#[cfg(test_nightly)] -#[thread_local] -#[no_mangle] -pub static mut TEST_THREAD_LOCAL: u32 = 0; - #[no_mangle] pub extern "C" fn test_identity_u32(x: u32) -> u32 { x @@ -41,9 +35,3 @@ pub unsafe extern "C" fn test_get_static_u32() -> u32 { pub unsafe extern "C" fn test_check_static_ptr() -> bool { TEST_STATIC_PTR == (&mut TEST_STATIC_PTR as *mut *mut _ as *mut _) } - -#[cfg(test_nightly)] -#[no_mangle] -pub unsafe extern "C" fn test_get_thread_local() -> u32 { - TEST_THREAD_LOCAL -} diff --git a/vendor/libloading/src/util.rs b/vendor/libloading/src/util.rs index e5108c2d14..880b68927d 100644 --- a/vendor/libloading/src/util.rs +++ b/vendor/libloading/src/util.rs @@ -7,7 +7,7 @@ use crate::Error; /// Checks for last byte and avoids allocating if it is zero. /// /// Non-last null bytes still result in an error. -pub(crate) fn cstr_cow_from_bytes<'a>(slice: &'a [u8]) -> Result, Error> { +pub(crate) fn cstr_cow_from_bytes(slice: &[u8]) -> Result, Error> { static ZERO: raw::c_char = 0; Ok(match slice.last() { // Slice out of 0 elements diff --git a/vendor/libloading/tests/constants.rs b/vendor/libloading/tests/constants.rs new file mode 100644 index 0000000000..ad910c405e --- /dev/null +++ b/vendor/libloading/tests/constants.rs @@ -0,0 +1,13 @@ +extern crate libloading; +extern crate libc; +extern crate static_assertions; + +#[cfg(all(test, unix))] +mod unix { + use super::static_assertions::const_assert_eq; + + const_assert_eq!(libloading::os::unix::RTLD_LOCAL, libc::RTLD_LOCAL); + const_assert_eq!(libloading::os::unix::RTLD_GLOBAL, libc::RTLD_GLOBAL); + const_assert_eq!(libloading::os::unix::RTLD_NOW, libc::RTLD_NOW); + const_assert_eq!(libloading::os::unix::RTLD_LAZY, libc::RTLD_LAZY); +} diff --git a/vendor/libloading/tests/functions.rs b/vendor/libloading/tests/functions.rs index dece58c585..b642478244 100644 --- a/vendor/libloading/tests/functions.rs +++ b/vendor/libloading/tests/functions.rs @@ -1,19 +1,25 @@ +#[cfg(windows)] +extern crate winapi; + extern crate libloading; use libloading::{Symbol, Library}; -const LIBPATH: &'static str = concat!(env!("OUT_DIR"), "/libtest_helpers.dll"); +const LIBPATH: &'static str = concat!(env!("OUT_DIR"), "/libtest_helpers.module"); fn make_helpers() { static ONCE: ::std::sync::Once = ::std::sync::Once::new(); ONCE.call_once(|| { - let mut outpath = String::from(if let Some(od) = option_env!("OUT_DIR") { od } else { return }); let rustc = option_env!("RUSTC").unwrap_or_else(|| { "rustc".into() }); - outpath.push_str(&"/libtest_helpers.dll"); // extension for windows required, POSIX does not care. - let _ = ::std::process::Command::new(rustc) + let mut cmd = ::std::process::Command::new(rustc); + cmd .arg("src/test_helpers.rs") .arg("-o") - .arg(outpath) - .arg("-O") + .arg(LIBPATH) + .arg("--target") + .arg(env!("LIBLOADING_TEST_TARGET")) + .arg("-O"); + + cmd .output() .expect("could not compile the test helpers!"); }); @@ -136,20 +142,69 @@ fn test_static_ptr() { } } -#[cfg(any(windows, target_os="linux"))] -#[cfg(test_nightly)] +#[cfg(unix)] #[test] -fn test_tls_static() { +fn library_this_get() { + use libloading::os::unix::Library; make_helpers(); - let lib = Library::new(LIBPATH).unwrap(); + let _lib = Library::new(LIBPATH).unwrap(); + let this = Library::this(); + // SAFE: functions are never called unsafe { - let var: Symbol<*mut u32> = lib.get(b"TEST_THREAD_LOCAL\0").unwrap(); - **var = 84; - let help: Symbol u32> = lib.get(b"test_get_thread_local\0").unwrap(); - assert_eq!(84, help()); + // Library we loaded in `_lib` (should be RTLD_LOCAL). + // FIXME: inconsistent behaviour between macos and other posix systems + // assert!(this.get::(b"test_identity_u32").is_err()); + // Something obscure from libc... + assert!(this.get::(b"freopen").is_ok()); + } +} + +#[cfg(windows)] +#[test] +fn library_this() { + use libloading::os::windows::Library; + make_helpers(); + let _lib = Library::new(LIBPATH).unwrap(); + let this = Library::this().expect("this library"); + // SAFE: functions are never called + unsafe { + // Library we loaded in `_lib`. + assert!(this.get::(b"test_identity_u32").is_err()); + // Something "obscure" from kernel32... + assert!(this.get::(b"GetLastError").is_err()); + } +} + +#[cfg(windows)] +#[test] +fn works_getlasterror() { + use winapi::um::errhandlingapi; + use winapi::shared::minwindef::DWORD; + use libloading::os::windows::{Library, Symbol}; + + let lib = Library::new("kernel32.dll").unwrap(); + let gle: Symbol DWORD> = unsafe { + lib.get(b"GetLastError").unwrap() + }; + unsafe { + errhandlingapi::SetLastError(42); + assert_eq!(errhandlingapi::GetLastError(), gle()) + } +} + +#[cfg(windows)] +#[test] +fn works_getlasterror0() { + use winapi::um::errhandlingapi; + use winapi::shared::minwindef::DWORD; + use libloading::os::windows::{Library, Symbol}; + + let lib = Library::new("kernel32.dll").unwrap(); + let gle: Symbol DWORD> = unsafe { + lib.get(b"GetLastError\0").unwrap() + }; + unsafe { + errhandlingapi::SetLastError(42); + assert_eq!(errhandlingapi::GetLastError(), gle()) } - ::std::thread::spawn(move || unsafe { - let help: Symbol u32> = lib.get(b"test_get_thread_local\0").unwrap(); - assert_eq!(0, help()); - }).join().unwrap(); } diff --git a/vendor/libloading/tests/library_filename.rs b/vendor/libloading/tests/library_filename.rs new file mode 100644 index 0000000000..efe51b8656 --- /dev/null +++ b/vendor/libloading/tests/library_filename.rs @@ -0,0 +1,17 @@ +extern crate libloading; +use libloading::library_filename; +use std::path::Path; + +#[cfg(target_os = "windows")] +const EXPECTED: &str = "audioengine.dll"; +#[cfg(target_os = "linux")] +const EXPECTED: &str = "libaudioengine.so"; +#[cfg(target_os = "macos")] +const EXPECTED: &str = "libaudioengine.dylib"; + +#[test] +fn test_library_filename() { + let name = "audioengine"; + let resolved = library_filename(name); + assert!(Path::new(&resolved).ends_with(EXPECTED)); +} diff --git a/vendor/libloading/tests/markers.rs b/vendor/libloading/tests/markers.rs index 01da108c68..330c034ad5 100644 --- a/vendor/libloading/tests/markers.rs +++ b/vendor/libloading/tests/markers.rs @@ -4,6 +4,23 @@ extern crate libloading; fn assert_send() {} #[cfg(test)] fn assert_sync() {} +#[cfg(test)] +fn assert_display() {} + +#[test] +fn check_error_send() { + assert_send::(); +} + +#[test] +fn check_error_sync() { + assert_sync::(); +} + +#[test] +fn check_error_display() { + assert_display::(); +} #[test] fn check_library_send() { diff --git a/vendor/lsp-types/.cargo-checksum.json b/vendor/lsp-types/.cargo-checksum.json index 913e249cfa..adc51096b7 100644 --- a/vendor/lsp-types/.cargo-checksum.json +++ b/vendor/lsp-types/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"54cfa4a7a811c1d2275bf24f7fd1a119d934dd64c9ea4c8ca156b88ed8924122","Cargo.toml":"7ed745e1c0ba57f7bcf0d2cba289b562af677343e2883c98a0c7062dc11cdf39","LICENSE":"a11232911aa0d746688b560af367728021184084eeb6328a1922d60925c5eda0","README.md":"77acfc82fff7852e9608da342ddc033a52b980cc0edb618b3c642a12ece017f0","release.sh":"013c6c56e2f36d7c3ff9703ef0de3bd58e2cefa5d1e203a298c27a29df7076f1","release.toml":"11ae2978b700cff4279d509b896a09570654ce19de88cec6b6eb6c521f8b141a","src/lib.rs":"84b4198bfa0696f4bce9f740867e6f7581dedf7cd36a18df28af1a2e16d647f3","src/notification.rs":"d20bd5b9ff32935063d2020843ee7b376e66412cb8dca2ee89e220ac5e3d636f","src/request.rs":"47398a878833e5f4fce1b3a43afd125912affa214e97d0d1343374240f714bf0"},"package":"7f1f86677fdbe8df5f88b99131b1424e50aad27bbe3e5900d221bc414bd72e9b"} \ No newline at end of file +{"files":{"CHANGELOG.md":"75e3fa387ef6fce999638dc98ee790d7ea1f7a54c6de83840ef95ebcff4ea75d","Cargo.toml":"f6b7c905407aa0dbad06ba06d5da525405d60991b61d75d502450b59fd21e89d","LICENSE":"005b90a7238f92fd39eaef0b4329a47e1cab351958d9e9bbed9b9c60b76bb2bb","README.md":"0011ea934f9c4a40409204b440517023b53bd7325b4e6d56a3da0dec252ff07f","release.sh":"0fc7c0f74e261a3faf5f0dea05f7098110d41b249511a9f2a573657f787fac9a","release.toml":"d06137fb8b6e1048cf42f39c2f6925f2a806c5b782b46e20a990bb4a3449bb8d","src/lib.rs":"c10021aad2f090d847e86004ddf76ae12075aca27939963d991d1687626078ef","src/notification.rs":"0d6296c66eb4551ffcf31aedc01d5dae9db3b71d2a4b1e39ad9287b2b0967cd4","src/request.rs":"3f02c22951b113c05a746bf08846c40a5ad63c6206c24e93685f286525b595fa"},"package":"f4265e2715bdacbb4dad029fce525e420cd66dc0af24ff9cb996a8ab48ac92ef"} \ No newline at end of file diff --git a/vendor/lsp-types/CHANGELOG.md b/vendor/lsp-types/CHANGELOG.md index c35ac1e3e8..8c12067d85 100644 --- a/vendor/lsp-types/CHANGELOG.md +++ b/vendor/lsp-types/CHANGELOG.md @@ -1,92 +1,98 @@ - -## v0.79.0 (2020-07-26) + +## v0.80.0 (2020-09-02) - -## v0.77.0 (2020-07-15) - - - - - -### v0.76.1 (2020-07-14) - - - - - -### v0.74.2 (2020-05-30) - - - - - -### v0.74.1 (2020-05-01) - - - - - -## v0.74.0 (2020-04-26) - - - - - -## v0.74.0 (2020-04-26) - - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - - -## v0.72.0 (2020-03-02) - - -#### Features - -* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) - - - + +## v0.79.0 (2020-07-26) + + + + + +## v0.77.0 (2020-07-15) + + + + + +### v0.76.1 (2020-07-14) + + + + + +### v0.74.2 (2020-05-30) + + + + + +### v0.74.1 (2020-05-01) + + + + + +## v0.74.0 (2020-04-26) + + + + + +## v0.74.0 (2020-04-26) + + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + + +## v0.72.0 (2020-03-02) + + +#### Features + +* Add DeserializeOwned + Serialize bounds on request/notifications ([fb945a93](https://github.com/gluon-lang/lsp-types/commit/fb945a9347b353dd9bc5aab99a86731bebd94c15), closes [#140](https://github.com/gluon-lang/lsp-types/issues/140)) + + + diff --git a/vendor/lsp-types/Cargo.toml b/vendor/lsp-types/Cargo.toml index 4980f1da74..8a5cb6027a 100644 --- a/vendor/lsp-types/Cargo.toml +++ b/vendor/lsp-types/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "lsp-types" -version = "0.79.0" +version = "0.80.0" authors = ["Markus Westerlind ", "Bruno Medeiros "] description = "Types for interaction with a language server, using VSCode's Language Server Protocol" documentation = "https://docs.rs/lsp-types" diff --git a/vendor/lsp-types/LICENSE b/vendor/lsp-types/LICENSE index 32781d976c..968950bbb5 100644 --- a/vendor/lsp-types/LICENSE +++ b/vendor/lsp-types/LICENSE @@ -1,22 +1,22 @@ -The MIT License (MIT) - -Copyright (c) 2016 Markus Westerlind - -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. - +The MIT License (MIT) + +Copyright (c) 2016 Markus Westerlind + +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 --git a/vendor/lsp-types/README.md b/vendor/lsp-types/README.md index 2c29a1f63f..b6972e9759 100644 --- a/vendor/lsp-types/README.md +++ b/vendor/lsp-types/README.md @@ -1,9 +1,9 @@ -# lsp-types [![Build Status](https://travis-ci.org/gluon-lang/lsp-types.svg?branch=master)](https://travis-ci.org/gluon-lang/lsp-types) [![Documentation](https://docs.rs/lsp-types/badge.svg)](https://docs.rs/crate/lsp-types) - -Types useful for interacting with a [language server](https://code.visualstudio.com/blogs/2016/06/27/common-language-protocol). - -Supports Language Server Protocol (LSP) version 3.15.0. - -## Links - -[Protocol reference](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-15.md) +# lsp-types [![Build Status](https://travis-ci.org/gluon-lang/lsp-types.svg?branch=master)](https://travis-ci.org/gluon-lang/lsp-types) [![Documentation](https://docs.rs/lsp-types/badge.svg)](https://docs.rs/crate/lsp-types) + +Types useful for interacting with a [language server](https://code.visualstudio.com/blogs/2016/06/27/common-language-protocol). + +Supports Language Server Protocol (LSP) version 3.15.0. + +## Links + +[Protocol reference](https://github.com/microsoft/language-server-protocol/blob/gh-pages/_specifications/specification-3-15.md) diff --git a/vendor/lsp-types/release.sh b/vendor/lsp-types/release.sh old mode 100755 new mode 100644 index db6a709c1e..cede6f575e --- a/vendor/lsp-types/release.sh +++ b/vendor/lsp-types/release.sh @@ -1,15 +1,15 @@ -#!/bin/sh -set -ex - -LEVEL=$1 -if [ -z "$LEVEL" ]; then - echo "Expected patch, minor or major" - exit 1 -fi - -clog --$LEVEL - -git add CHANGELOG.md -git commit -m "Update changelog" - -cargo release $LEVEL +#!/bin/sh +set -ex + +LEVEL=$1 +if [ -z "$LEVEL" ]; then + echo "Expected patch, minor or major" + exit 1 +fi + +clog --$LEVEL + +git add CHANGELOG.md +git commit -m "Update changelog" + +cargo release $LEVEL diff --git a/vendor/lsp-types/release.toml b/vendor/lsp-types/release.toml index 5e7e4943cd..0e10206ed6 100644 --- a/vendor/lsp-types/release.toml +++ b/vendor/lsp-types/release.toml @@ -1,2 +1,2 @@ -no-dev-version = true -tag-message = "Version {{version}}" +no-dev-version = true +tag-message = "Version {{version}}" diff --git a/vendor/lsp-types/src/lib.rs b/vendor/lsp-types/src/lib.rs index c93ac7b7e5..ca1bd3b8c1 100644 --- a/vendor/lsp-types/src/lib.rs +++ b/vendor/lsp-types/src/lib.rs @@ -1,4856 +1,4888 @@ -/*! - -Language Server Protocol types for Rust. - -Based on: - -This library uses the URL crate for parsing URIs. Note that there is -some confusion on the meaning of URLs vs URIs: -. According to that -information, on the classical sense of "URLs", "URLs" are a subset of -URIs, But on the modern/new meaning of URLs, they are the same as -URIs. The important take-away aspect is that the URL crate should be -able to parse any URI, such as `urn:isbn:0451450523`. - - -*/ -#![allow(non_upper_case_globals)] -#![forbid(unsafe_code)] - -#[macro_use] -extern crate bitflags; - -use serde::{Deserialize, Serialize}; -use serde_json; -use serde_repr::{Deserialize_repr, Serialize_repr}; - -pub use url::Url; - -use std::borrow::Cow; - -#[cfg(feature = "proposed")] -use std::convert::TryFrom; - -use std::collections::HashMap; - -#[cfg(feature = "proposed")] -use base64; -use serde::de; -use serde::de::Error as Error_; -use serde_json::Value; - -#[cfg(feature = "proposed")] -use serde::ser::SerializeSeq; - -pub mod notification; -pub mod request; - -/* ----------------- Auxiliary types ----------------- */ - -#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum NumberOrString { - Number(u64), - String(String), -} - -/* ----------------- Cancel support ----------------- */ - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct CancelParams { - /// The request id to cancel. - pub id: NumberOrString, -} - -/* ----------------- Basic JSON Structures ----------------- */ - -/// Position in a text document expressed as zero-based line and character offset. -/// A position is between two characters like an 'insert' cursor in a editor. -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Default, Deserialize, Serialize)] -pub struct Position { - /// Line position in a document (zero-based). - pub line: u64, - /// Character offset on a line in a document (zero-based). - pub character: u64, -} - -impl Position { - pub fn new(line: u64, character: u64) -> Position { - Position { line, character } - } -} - -/// A range in a text document expressed as (zero-based) start and end positions. -/// A range is comparable to a selection in an editor. Therefore the end position is exclusive. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Deserialize, Serialize)] -pub struct Range { - /// The range's start position. - pub start: Position, - /// The range's end position. - pub end: Position, -} - -impl Range { - pub fn new(start: Position, end: Position) -> Range { - Range { start, end } - } -} - -/// Represents a location inside a resource, such as a line inside a text file. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct Location { - pub uri: Url, - pub range: Range, -} - -impl Location { - pub fn new(uri: Url, range: Range) -> Location { - Location { uri, range } - } -} - -/// Represents a link between a source and a target location. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct LocationLink { - /// Span of the origin of this link. - /// - /// Used as the underlined span for mouse interaction. Defaults to the word range at - /// the mouse position. - #[serde(skip_serializing_if = "Option::is_none")] - pub origin_selection_range: Option, - - /// The target resource identifier of this link. - pub target_uri: Url, - - /// The full target range of this link. - pub target_range: Range, - - /// The span of this link. - pub target_selection_range: Range, -} - -/// Represents a diagnostic, such as a compiler error or warning. -/// Diagnostic objects are only valid in the scope of a resource. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Diagnostic { - /// The range at which the message applies. - pub range: Range, - - /// The diagnostic's severity. Can be omitted. If omitted it is up to the - /// client to interpret diagnostics as error, warning, info or hint. - #[serde(skip_serializing_if = "Option::is_none")] - pub severity: Option, - - /// The diagnostic's code. Can be omitted. - #[serde(skip_serializing_if = "Option::is_none")] - pub code: Option, - // code?: number | string; - /// A human-readable string describing the source of this - /// diagnostic, e.g. 'typescript' or 'super lint'. - #[serde(skip_serializing_if = "Option::is_none")] - pub source: Option, - - /// The diagnostic's message. - pub message: String, - - /// An array of related diagnostic information, e.g. when symbol-names within - /// a scope collide all definitions can be marked via this property. - #[serde(skip_serializing_if = "Option::is_none")] - pub related_information: Option>, - - /// Additional metadata about the diagnostic. - #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option>, -} - -impl Diagnostic { - pub fn new( - range: Range, - severity: Option, - code: Option, - source: Option, - message: String, - related_information: Option>, - tags: Option>, - ) -> Diagnostic { - Diagnostic { - range, - severity, - code, - source, - message, - related_information, - tags, - } - } - - pub fn new_simple(range: Range, message: String) -> Diagnostic { - Self::new(range, None, None, None, message, None, None) - } - - pub fn new_with_code_number( - range: Range, - severity: DiagnosticSeverity, - code_number: u64, - source: Option, - message: String, - ) -> Diagnostic { - let code = Some(NumberOrString::Number(code_number)); - Self::new(range, Some(severity), code, source, message, None, None) - } -} - -/// The protocol currently supports the following diagnostic severities: -#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum DiagnosticSeverity { - /// Reports an error. - Error = 1, - /// Reports a warning. - Warning = 2, - /// Reports an information. - Information = 3, - /// Reports a hint. - Hint = 4, -} - -/// Represents a related message and source code location for a diagnostic. This -/// should be used to point to code locations that cause or related to a -/// diagnostics, e.g when duplicating a symbol in a scope. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DiagnosticRelatedInformation { - /// The location of this related diagnostic information. - pub location: Location, - - /// The message of this related diagnostic information. - pub message: String, -} - -/// The diagnostic tags. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum DiagnosticTag { - /// Unused or unnecessary code. - /// Clients are allowed to render diagnostics with this tag faded out instead of having - /// an error squiggle. - Unnecessary = 1, - - /// Deprecated or obsolete code. - /// Clients are allowed to rendered diagnostics with this tag strike through. - Deprecated = 2, -} - -/// Represents a reference to a command. Provides a title which will be used to represent a command in the UI. -/// Commands are identitifed using a string identifier and the protocol currently doesn't specify a set of -/// well known commands. So executing a command requires some tool extension code. -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct Command { - /// Title of the command, like `save`. - pub title: String, - /// The identifier of the actual command handler. - pub command: String, - /// Arguments that the command handler should be - /// invoked with. - #[serde(skip_serializing_if = "Option::is_none")] - pub arguments: Option>, -} - -impl Command { - pub fn new(title: String, command: String, arguments: Option>) -> Command { - Command { - title, - command, - arguments, - } - } -} - -/// A textual edit applicable to a text document. -/// -/// If n `TextEdit`s are applied to a text document all text edits describe changes to the initial document version. -/// Execution wise text edits should applied from the bottom to the top of the text document. Overlapping text edits -/// are not supported. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextEdit { - /// The range of the text document to be manipulated. To insert - /// text into a document create a range where start === end. - pub range: Range, - /// The string to be inserted. For delete operations use an - /// empty string. - pub new_text: String, -} - -impl TextEdit { - pub fn new(range: Range, new_text: String) -> TextEdit { - TextEdit { range, new_text } - } -} - -/// Describes textual changes on a single text document. The text document is referred to as a -/// `VersionedTextDocumentIdentifier` to allow clients to check the text document version before an -/// edit is applied. A `TextDocumentEdit` describes all changes on a version Si and after they are -/// applied move the document to version Si+1. So the creator of a `TextDocumentEdit` doesn't need to -/// sort the array or do any kind of ordering. However the edits must be non overlapping. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentEdit { - /// The text document to change. - pub text_document: VersionedTextDocumentIdentifier, - - /// The edits to be applied. - pub edits: Vec, -} - -/// A special text edit to provide an insert and a replace operation. -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct InsertReplaceEdit { - /// The string to be inserted. - pub new_text: String, - - /// The range if the insert is requested - pub insert: Range, - - /// The range if the replace is requested. - pub replace: Range, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum CompletionTextEdit { - Edit(TextEdit), - #[cfg(feature = "proposed")] - InsertAndReplace(InsertReplaceEdit), -} - -impl From for CompletionTextEdit { - fn from(edit: TextEdit) -> Self { - CompletionTextEdit::Edit(edit) - } -} - -#[cfg(feature = "proposed")] -impl From for CompletionTextEdit { - fn from(edit: InsertReplaceEdit) -> Self { - CompletionTextEdit::InsertAndReplace(edit) - } -} - -/// Options to create a file. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateFileOptions { - /// Overwrite existing file. Overwrite wins over `ignoreIfExists` - #[serde(skip_serializing_if = "Option::is_none")] - pub overwrite: Option, - /// Ignore if exists. - #[serde(skip_serializing_if = "Option::is_none")] - pub ignore_if_exists: Option, -} - -/// Create file operation -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CreateFile { - /// The resource to create. - pub uri: Url, - /// Additional options - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option, -} - -/// Rename file options -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameFileOptions { - /// Overwrite target if existing. Overwrite wins over `ignoreIfExists` - #[serde(skip_serializing_if = "Option::is_none")] - pub overwrite: Option, - /// Ignores if target exists. - #[serde(skip_serializing_if = "Option::is_none")] - pub ignore_if_exists: Option, -} - -/// Rename file operation -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameFile { - /// The old (existing) location. - pub old_uri: Url, - /// The new location. - pub new_uri: Url, - /// Rename options. - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option, -} - -/// Delete file options -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DeleteFileOptions { - /// Delete the content recursively if a folder is denoted. - #[serde(skip_serializing_if = "Option::is_none")] - pub recursive: Option, - /// Ignore the operation if the file doesn't exist. - #[serde(skip_serializing_if = "Option::is_none")] - pub ignore_if_not_exists: Option, -} - -/// Delete file operation -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DeleteFile { - /// The file to delete. - pub uri: Url, - /// Delete options. - #[serde(skip_serializing_if = "Option::is_none")] - pub options: Option, -} - -/// A workspace edit represents changes to many resources managed in the workspace. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceEdit { - /// Holds changes to existing resources. - #[serde(with = "url_map")] - #[serde(skip_serializing_if = "Option::is_none")] - #[serde(default)] - pub changes: Option>>, // changes?: { [uri: string]: TextEdit[]; }; - - /// Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes - /// are either an array of `TextDocumentEdit`s to express changes to n different text documents - /// where each text document edit addresses a specific version of a text document. Or it can contain - /// above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. - /// - /// Whether a client supports versioned document edits is expressed via - /// `workspace.workspaceEdit.documentChanges` client capability. - /// - /// If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then - /// only plain `TextEdit`s using the `changes` property are supported. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_changes: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum DocumentChanges { - Edits(Vec), - Operations(Vec), -} - -// TODO: Once https://github.com/serde-rs/serde/issues/912 is solved -// we can remove ResourceOp and switch to the following implementation -// of DocumentChangeOperation: -// -// #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -// #[serde(tag = "kind", rename_all="lowercase" )] -// pub enum DocumentChangeOperation { -// Create(CreateFile), -// Rename(RenameFile), -// Delete(DeleteFile), -// -// #[serde(other)] -// Edit(TextDocumentEdit), -// } - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged, rename_all = "lowercase")] -pub enum DocumentChangeOperation { - Op(ResourceOp), - Edit(TextDocumentEdit), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum ResourceOp { - Create(CreateFile), - Rename(RenameFile), - Delete(DeleteFile), -} - -#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ConfigurationParams { - pub items: Vec, -} - -#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ConfigurationItem { - /// The scope to get the configuration section for. - #[serde(skip_serializing_if = "Option::is_none")] - pub scope_uri: Option, - - ///The configuration section asked for. - #[serde(skip_serializing_if = "Option::is_none")] - pub section: Option, -} - -mod url_map { - use super::*; - - use std::fmt; - - pub fn deserialize<'de, D>( - deserializer: D, - ) -> Result>>, D::Error> - where - D: serde::Deserializer<'de>, - { - struct UrlMapVisitor; - impl<'de> de::Visitor<'de> for UrlMapVisitor { - type Value = HashMap>; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("map") - } - - fn visit_map(self, mut visitor: M) -> Result - where - M: de::MapAccess<'de>, - { - let mut values = HashMap::with_capacity(visitor.size_hint().unwrap_or(0)); - - // While there are entries remaining in the input, add them - // into our map. - while let Some((key, value)) = visitor.next_entry::()? { - values.insert(key, value); - } - - Ok(values) - } - } - - struct OptionUrlMapVisitor; - impl<'de> de::Visitor<'de> for OptionUrlMapVisitor { - type Value = Option>>; - - fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - formatter.write_str("option") - } - - #[inline] - fn visit_unit(self) -> Result - where - E: serde::de::Error, - { - Ok(None) - } - - #[inline] - fn visit_none(self) -> Result - where - E: serde::de::Error, - { - Ok(None) - } - - #[inline] - fn visit_some(self, deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - deserializer.deserialize_map(UrlMapVisitor).map(Some) - } - } - - // Instantiate our Visitor and ask the Deserializer to drive - // it over the input data, resulting in an instance of MyMap. - deserializer.deserialize_option(OptionUrlMapVisitor) - } - - pub fn serialize( - changes: &Option>>, - serializer: S, - ) -> Result - where - S: serde::Serializer, - { - use serde::ser::SerializeMap; - - match *changes { - Some(ref changes) => { - let mut map = serializer.serialize_map(Some(changes.len()))?; - for (k, v) in changes { - map.serialize_entry(k.as_str(), v)?; - } - map.end() - } - None => serializer.serialize_none(), - } - } -} - -impl WorkspaceEdit { - pub fn new(changes: HashMap>) -> WorkspaceEdit { - WorkspaceEdit { - changes: Some(changes), - document_changes: None, - } - } -} - -/// Text documents are identified using a URI. On the protocol level, URIs are passed as strings. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct TextDocumentIdentifier { - // !!!!!! Note: - // In the spec VersionedTextDocumentIdentifier extends TextDocumentIdentifier - // This modelled by "mixing-in" TextDocumentIdentifier in VersionedTextDocumentIdentifier, - // so any changes to this type must be effected in the sub-type as well. - /// The text document's URI. - pub uri: Url, -} - -impl TextDocumentIdentifier { - pub fn new(uri: Url) -> TextDocumentIdentifier { - TextDocumentIdentifier { uri } - } -} - -/// An item to transfer a text document from the client to the server. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentItem { - /// The text document's URI. - pub uri: Url, - - /// The text document's language identifier. - pub language_id: String, - - /// The version number of this document (it will strictly increase after each - /// change, including undo/redo). - pub version: i64, - - /// The content of the opened text document. - pub text: String, -} - -impl TextDocumentItem { - pub fn new(uri: Url, language_id: String, version: i64, text: String) -> TextDocumentItem { - TextDocumentItem { - uri, - language_id, - version, - text, - } - } -} - -/// An identifier to denote a specific version of a text document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct VersionedTextDocumentIdentifier { - // This field was "mixed-in" from TextDocumentIdentifier - /// The text document's URI. - pub uri: Url, - - /// The version number of this document. - pub version: Option, -} - -impl VersionedTextDocumentIdentifier { - pub fn new(uri: Url, version: i64) -> VersionedTextDocumentIdentifier { - VersionedTextDocumentIdentifier { - uri, - version: Some(version), - } - } -} - -/// A parameter literal used in requests to pass a text document and a position inside that document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentPositionParams { - // !!!!!! Note: - // In the spec ReferenceParams extends TextDocumentPositionParams - // This modelled by "mixing-in" TextDocumentPositionParams in ReferenceParams, - // so any changes to this type must be effected in sub-type as well. - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The position inside the text document. - pub position: Position, -} - -impl TextDocumentPositionParams { - pub fn new( - text_document: TextDocumentIdentifier, - position: Position, - ) -> TextDocumentPositionParams { - TextDocumentPositionParams { - text_document, - position, - } - } -} - -/// A document filter denotes a document through properties like language, schema or pattern. -/// Examples are a filter that applies to TypeScript files on disk or a filter the applies to JSON -/// files with name package.json: -/// -/// { language: 'typescript', scheme: 'file' } -/// { language: 'json', pattern: '**/package.json' } -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DocumentFilter { - /// A language id, like `typescript`. - #[serde(skip_serializing_if = "Option::is_none")] - pub language: Option, - - /// A Uri [scheme](#Uri.scheme), like `file` or `untitled`. - #[serde(skip_serializing_if = "Option::is_none")] - pub scheme: Option, - - /// A glob pattern, like `*.{ts,js}`. - #[serde(skip_serializing_if = "Option::is_none")] - pub pattern: Option, -} - -/// A document selector is the combination of one or many document filters. -pub type DocumentSelector = Vec; - -// ========================= Actual Protocol ========================= - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct InitializeParams { - /// The process Id of the parent process that started - /// the server. Is null if the process has not been started by another process. - /// If the parent process is not alive then the server should exit (see exit notification) its process. - pub process_id: Option, - - /// The rootPath of the workspace. Is null - /// if no folder is open. - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(note = "Use `root_uri` instead when possible")] - pub root_path: Option, - - /// The rootUri of the workspace. Is null if no - /// folder is open. If both `rootPath` and `rootUri` are set - /// `rootUri` wins. - #[serde(default)] - pub root_uri: Option, - - /// User provided initialization options. - #[serde(skip_serializing_if = "Option::is_none")] - pub initialization_options: Option, - - /// The capabilities provided by the client (editor) - pub capabilities: ClientCapabilities, - - /// The initial trace setting. If omitted trace is disabled ('off'). - #[serde(default)] - #[serde(skip_serializing_if = "Option::is_none")] - pub trace: Option, - - /// The workspace folders configured in the client when the server starts. - /// This property is only available if the client supports workspace folders. - /// It can be `null` if the client supports workspace folders but none are - /// configured. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_folders: Option>, - - /// Information about the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub client_info: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -pub struct ClientInfo { - /// The name of the client as defined by the client. - pub name: String, - /// The client's version as defined by the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, -} - -#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)] -pub struct InitializedParams {} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] -pub enum TraceOption { - #[serde(rename = "off")] - Off, - #[serde(rename = "messages")] - Messages, - #[serde(rename = "verbose")] - Verbose, -} - -impl Default for TraceOption { - fn default() -> TraceOption { - TraceOption::Off - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct GenericRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub options: GenericOptions, - - #[serde(flatten)] - pub static_registration_options: StaticRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct GenericOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct GenericParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GenericCapability { - /// This capability supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GotoCapability { - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports additional metadata in the form of definition links. - pub link_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceEditCapability { - /// The client supports versioned document changes in `WorkspaceEdit`s - #[serde(skip_serializing_if = "Option::is_none")] - pub document_changes: Option, - - /// The resource operations the client supports. Clients should at least - /// support 'create', 'rename' and 'delete' files and folders. - #[serde(skip_serializing_if = "Option::is_none")] - pub resource_operations: Option>, - - /// The failure handling strategy of a client if applying the workspace edit - /// failes. - #[serde(skip_serializing_if = "Option::is_none")] - pub failure_handling: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceCapability { - /// The server supports workspace folder. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_folders: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceFolderCapability { - #[serde(skip_serializing_if = "Option::is_none")] - pub supported: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub change_notifications: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum WorkspaceFolderCapabilityChangeNotifications { - Bool(bool), - Id(String), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceFolder { - /// The associated URI for this workspace folder. - pub uri: Url, - /// The name of the workspace folder. Defaults to the uri's basename. - pub name: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidChangeWorkspaceFoldersParams { - /// The actual workspace folder change event. - pub event: WorkspaceFoldersChangeEvent, -} - -/// The workspace folder change event. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceFoldersChangeEvent { - /// The array of added workspace folders - pub added: Vec, - - /// The array of the removed workspace folders - pub removed: Vec, -} - -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] -#[serde(rename_all = "lowercase")] -pub enum ResourceOperationKind { - Create, - Rename, - Delete, -} - -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] -#[serde(rename_all = "camelCase")] -pub enum FailureHandlingKind { - Abort, - Transactional, - TextOnlyTransactional, - Undo, -} - -/// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SymbolKindCapability { - /// The symbol kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - /// - /// If this property is not present the client only supports - /// the symbol kinds from `File` to `Array` as defined in - /// the initial version of the protocol. - pub value_set: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceSymbolClientCapabilities { - /// This capability supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub symbol_kind: Option, - - /// The client supports tags on `SymbolInformation`. - /// Clients supporting tags have to handle unknown tags gracefully. - /// - /// @since 3.16.0 - /// - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - #[cfg(feature = "proposed")] - pub tag_support: Option>, -} - -/// Workspace specific client capabilities. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WorkspaceClientCapabilities { - /// The client supports applying batch edits to the workspace by supporting - /// the request 'workspace/applyEdit' - #[serde(skip_serializing_if = "Option::is_none")] - pub apply_edit: Option, - - /// Capabilities specific to `WorkspaceEdit`s - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_edit: Option, - - /// Capabilities specific to the `workspace/didChangeConfiguration` notification. - #[serde(skip_serializing_if = "Option::is_none")] - pub did_change_configuration: Option, - - /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. - #[serde(skip_serializing_if = "Option::is_none")] - pub did_change_watched_files: Option, - - /// Capabilities specific to the `workspace/symbol` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub symbol: Option, - - /// Capabilities specific to the `workspace/executeCommand` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub execute_command: Option, - - /// The client has support for workspace folders. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_folders: Option, - - /// The client supports `workspace/configuration` requests. - #[serde(skip_serializing_if = "Option::is_none")] - pub configuration: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SynchronizationCapability { - /// Whether text document synchronization supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports sending will save notifications. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save: Option, - - /// The client supports sending a will save request and - /// waits for a response providing text edits which will - /// be applied to the document before it is saved. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save_wait_until: Option, - - /// The client supports did save notifications. - #[serde(skip_serializing_if = "Option::is_none")] - pub did_save: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionItemCapability { - /// Client supports snippets as insert text. - /// - /// A snippet can define tab stops and placeholders with `$1`, `$2` - /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to - /// the end of the snippet. Placeholders with equal identifiers are linked, - /// that is typing in one will update others too. - #[serde(skip_serializing_if = "Option::is_none")] - pub snippet_support: Option, - - /// Client supports commit characters on a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub commit_characters_support: Option, - - /// Client supports the follow content formats for the documentation - /// property. The order describes the preferred format of the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation_format: Option>, - - /// Client supports the deprecated property on a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated_support: Option, - - /// Client supports the preselect property on a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub preselect_support: Option, - - /// Client supports the tag property on a completion item. Clients supporting - /// tags have to handle unknown tags gracefully. Clients especially need to - /// preserve unknown tags when sending a completion item back to the server in - /// a resolve call. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - pub tag_support: Option>, - - /// Client support insert replace edit to control different behavior if a - /// completion item is inserted in the text or should replace text. - /// - /// @since 3.16.0 - Proposed state - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub insert_replace_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum CompletionItemTag { - Deprecated = 1, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionItemKindCapability { - /// The completion item kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - /// - /// If this property is not present the client only supports - /// the completion items kinds from `Text` to `Reference` as defined in - /// the initial version of the protocol. - #[serde(skip_serializing_if = "Option::is_none")] - pub value_set: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverCapability { - /// Whether completion supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Client supports the follow content formats for the content - /// property. The order describes the preferred format of the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub content_format: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionCapability { - /// Whether completion supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports the following `CompletionItem` specific - /// capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub completion_item: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub completion_item_kind: Option, - - /// The client supports to send additional context information for a - /// `textDocument/completion` requestion. - #[serde(skip_serializing_if = "Option::is_none")] - pub context_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureInformationSettings { - /// Client supports the follow content formats for the documentation - /// property. The order describes the preferred format of the client. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation_format: Option>, - - #[serde(skip_serializing_if = "Option::is_none")] - pub parameter_information: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ParameterInformationSettings { - /// The client supports processing label offsets instead of a - /// simple label string. - #[serde(skip_serializing_if = "Option::is_none")] - pub label_offset_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpCapability { - /// Whether completion supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client supports the following `SignatureInformation` - /// specific properties. - #[serde(skip_serializing_if = "Option::is_none")] - pub signature_information: Option, - - /// The client supports to send additional context information for a - /// `textDocument/signatureHelp` request. A client that opts into - /// contextSupport will also support the `retriggerCharacters` on - /// `SignatureHelpOptions`. - #[serde(skip_serializing_if = "Option::is_none")] - pub context_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct PublishDiagnosticsCapability { - /// Whether the clients accepts diagnostics with related information. - #[serde(skip_serializing_if = "Option::is_none")] - pub related_information: Option, - - /// Client supports the tag property to provide meta data about a diagnostic. - /// Clients supporting tags have to handle unknown tags gracefully. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - pub tag_support: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TagSupport { - /// The tags supported by the client. - pub value_set: Vec, -} - -impl TagSupport { - /// Support for deserializing a boolean tag Support, in case it's present. - /// - /// This is currently the case for vscode 1.41.1 - fn deserialize_compat<'de, S>(serializer: S) -> Result>, S::Error> - where - S: serde::Deserializer<'de>, - T: serde::Deserialize<'de>, - { - Ok( - match Option::::deserialize(serializer).map_err(serde::de::Error::custom)? { - Some(Value::Bool(false)) => None, - Some(Value::Bool(true)) => Some(TagSupport { value_set: vec![] }), - Some(other) => { - Some(TagSupport::::deserialize(other).map_err(serde::de::Error::custom)?) - } - None => None, - }, - ) - } -} - -/// Text document specific client capabilities. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentClientCapabilities { - #[serde(skip_serializing_if = "Option::is_none")] - pub synchronization: Option, - /// Capabilities specific to the `textDocument/completion` - #[serde(skip_serializing_if = "Option::is_none")] - pub completion: Option, - - /// Capabilities specific to the `textDocument/hover` - #[serde(skip_serializing_if = "Option::is_none")] - pub hover: Option, - - /// Capabilities specific to the `textDocument/signatureHelp` - #[serde(skip_serializing_if = "Option::is_none")] - pub signature_help: Option, - - /// Capabilities specific to the `textDocument/references` - #[serde(skip_serializing_if = "Option::is_none")] - pub references: Option, - - /// Capabilities specific to the `textDocument/documentHighlight` - #[serde(skip_serializing_if = "Option::is_none")] - pub document_highlight: Option, - - /// Capabilities specific to the `textDocument/documentSymbol` - #[serde(skip_serializing_if = "Option::is_none")] - pub document_symbol: Option, - /// Capabilities specific to the `textDocument/formatting` - #[serde(skip_serializing_if = "Option::is_none")] - pub formatting: Option, - - /// Capabilities specific to the `textDocument/rangeFormatting` - #[serde(skip_serializing_if = "Option::is_none")] - pub range_formatting: Option, - - /// Capabilities specific to the `textDocument/onTypeFormatting` - #[serde(skip_serializing_if = "Option::is_none")] - pub on_type_formatting: Option, - - /// Capabilities specific to the `textDocument/declaration` - #[serde(skip_serializing_if = "Option::is_none")] - pub declaration: Option, - - /// Capabilities specific to the `textDocument/definition` - #[serde(skip_serializing_if = "Option::is_none")] - pub definition: Option, - - /// Capabilities specific to the `textDocument/typeDefinition` - #[serde(skip_serializing_if = "Option::is_none")] - pub type_definition: Option, - - /// Capabilities specific to the `textDocument/implementation` - #[serde(skip_serializing_if = "Option::is_none")] - pub implementation: Option, - - /// Capabilities specific to the `textDocument/codeAction` - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action: Option, - - /// Capabilities specific to the `textDocument/codeLens` - #[serde(skip_serializing_if = "Option::is_none")] - pub code_lens: Option, - - /// Capabilities specific to the `textDocument/documentLink` - #[serde(skip_serializing_if = "Option::is_none")] - pub document_link: Option, - - /// Capabilities specific to the `textDocument/documentColor` and the - /// `textDocument/colorPresentation` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub color_provider: Option, - - /// Capabilities specific to the `textDocument/rename` - #[serde(skip_serializing_if = "Option::is_none")] - pub rename: Option, - - /// Capabilities specific to `textDocument/publishDiagnostics`. - #[serde(skip_serializing_if = "Option::is_none")] - pub publish_diagnostics: Option, - - /// Capabilities specific to `textDocument/foldingRange` requests. - #[serde(skip_serializing_if = "Option::is_none")] - pub folding_range: Option, - - /// The client's semantic highlighting capability. - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub semantic_highlighting_capabilities: Option, - - /// Capabilities specific to the `textDocument/semanticTokens` - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub semantic_tokens: Option, -} - -/// Window specific client capabilities. -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WindowClientCapabilities { - /// Whether client supports create a work done progress UI from the server side. - #[serde(skip_serializing_if = "Option::is_none")] - pub work_done_progress: Option, -} - -/// Where ClientCapabilities are currently empty: -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ClientCapabilities { - /// Workspace specific client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace: Option, - - /// Text document specific client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub text_document: Option, - - /// Window specific client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub window: Option, - - /// Experimental client capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub experimental: Option, -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct InitializeResult { - /// The capabilities the language server provides. - pub capabilities: ServerCapabilities, - - /// The capabilities the language server provides. - #[serde(skip_serializing_if = "Option::is_none")] - pub server_info: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct ServerInfo { - /// The name of the server as defined by the server. - pub name: String, - /// The servers's version as defined by the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct InitializeError { - /// Indicates whether the client should retry to send the - /// initilize request after showing the message provided - /// in the ResponseError. - pub retry: bool, -} - -// The server can signal the following capabilities: - -/// Defines how the host (editor) should sync document changes to the language server. -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum TextDocumentSyncKind { - /// Documents should not be synced at all. - None = 0, - - /// Documents are synced by always sending the full content of the document. - Full = 1, - - /// Documents are synced by sending the full content on open. After that only - /// incremental updates to the document are sent. - Incremental = 2, -} - -/// Completion options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionOptions { - /// The server provides support to resolve additional information for a completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub resolve_provider: Option, - - /// The characters that trigger completion automatically. - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_characters: Option>, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -/// Hover options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub hover_options: HoverOptions, -} - -/// Signature help options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpOptions { - /// The characters that trigger signature help automatically. - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_characters: Option>, - - /// List of characters that re-trigger signature help. - /// These trigger characters are only active when signature help is already showing. All trigger characters - /// are also counted as re-trigger characters. - #[serde(skip_serializing_if = "Option::is_none")] - pub retrigger_characters: Option>, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -/// Signature help options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct SignatureHelpRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, -} -/// Signature help options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum SignatureHelpTriggerKind { - /// Signature help was invoked manually by the user or by a command. - Invoked = 1, - /// Signature help was triggered by a trigger character. - TriggerCharacter = 2, - /// Signature help was triggered by the cursor moving or by the document content changing. - ContentChange = 3, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpParams { - /// The signature help context. This is only available if the client specifies - /// to send this using the client capability `textDocument.signatureHelp.contextSupport === true` - #[serde(skip_serializing_if = "Option::is_none")] - pub context: Option, - - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelpContext { - /// Action that caused signature help to be triggered. - pub trigger_kind: SignatureHelpTriggerKind, - - /// Character that caused signature help to be triggered. - /// This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_character: Option, - - /// `true` if signature help was already showing when it was triggered. - /// Retriggers occur when the signature help is already active and can be caused by actions such as - /// typing a trigger character, a cursor move, or document content changes. - pub is_retrigger: bool, - - /// The currently active `SignatureHelp`. - /// The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on - /// the user navigating through available signatures. - #[serde(skip_serializing_if = "Option::is_none")] - pub active_signature_help: Option, -} - -/// Code Lens options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeLensOptions { - /// Code lens has a resolve provider as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub resolve_provider: Option, -} - -/// Format document on type options -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentOnTypeFormattingOptions { - /// A character on which formatting should be triggered, like `}`. - pub first_trigger_character: String, - - /// More trigger characters. - #[serde(skip_serializing_if = "Option::is_none")] - pub more_trigger_character: Option>, -} - -/// Execute command options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct ExecuteCommandOptions { - /// The commands to be executed on the server - pub commands: Vec, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -/// Save options. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SaveOptions { - /// The client is supposed to include the content on save. - #[serde(skip_serializing_if = "Option::is_none")] - pub include_text: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum TextDocumentSyncSaveOptions { - Supported(bool), - SaveOptions(SaveOptions), -} - -impl From for TextDocumentSyncSaveOptions { - fn from(from: SaveOptions) -> Self { - Self::SaveOptions(from) - } -} - -impl From for TextDocumentSyncSaveOptions { - fn from(from: bool) -> Self { - Self::Supported(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentSyncOptions { - /// Open and close notifications are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub open_close: Option, - - /// Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full - /// and TextDocumentSyncKindIncremental. - #[serde(skip_serializing_if = "Option::is_none")] - pub change: Option, - - /// Will save notifications are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save: Option, - - /// Will save wait until requests are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub will_save_wait_until: Option, - - /// Save notifications are sent to the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub save: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum TextDocumentSyncCapability { - Kind(TextDocumentSyncKind), - Options(TextDocumentSyncOptions), -} - -impl From for TextDocumentSyncCapability { - fn from(from: TextDocumentSyncOptions) -> Self { - Self::Options(from) - } -} - -impl From for TextDocumentSyncCapability { - fn from(from: TextDocumentSyncKind) -> Self { - Self::Kind(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum ImplementationProviderCapability { - Simple(bool), - Options(StaticTextDocumentRegistrationOptions), -} - -impl From for ImplementationProviderCapability { - fn from(from: StaticTextDocumentRegistrationOptions) -> Self { - Self::Options(from) - } -} - -impl From for ImplementationProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum TypeDefinitionProviderCapability { - Simple(bool), - Options(StaticTextDocumentRegistrationOptions), -} - -impl From for TypeDefinitionProviderCapability { - fn from(from: StaticTextDocumentRegistrationOptions) -> Self { - Self::Options(from) - } -} - -impl From for TypeDefinitionProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum HoverProviderCapability { - Simple(bool), - Options(HoverOptions), -} - -impl From for HoverProviderCapability { - fn from(from: HoverOptions) -> Self { - Self::Options(from) - } -} - -impl From for HoverProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum ColorProviderCapability { - Simple(bool), - ColorProvider(ColorProviderOptions), - Options(StaticTextDocumentColorProviderOptions), -} - -impl From for ColorProviderCapability { - fn from(from: ColorProviderOptions) -> Self { - Self::ColorProvider(from) - } -} - -impl From for ColorProviderCapability { - fn from(from: StaticTextDocumentColorProviderOptions) -> Self { - Self::Options(from) - } -} - -impl From for ColorProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum CodeActionProviderCapability { - Simple(bool), - Options(CodeActionOptions), -} - -impl From for CodeActionProviderCapability { - fn from(from: CodeActionOptions) -> Self { - Self::Options(from) - } -} - -impl From for CodeActionProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionCapability { - /// - /// This capability supports dynamic registration. - /// - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The client support code action literals as a valid - /// response of the `textDocument/codeAction` request. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action_literal_support: Option, - - /// Whether code action supports the `isPreferred` property. - #[serde(skip_serializing_if = "Option::is_none")] - pub is_preferred_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionLiteralSupport { - /// The code action kind is support with the following value set. - pub code_action_kind: CodeActionKindLiteralSupport, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionKindLiteralSupport { - /// The code action kind values the client supports. When this - /// property exists the client also guarantees that it will - /// handle values outside its set gracefully and falls back - /// to a default value when unknown. - pub value_set: Vec, -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ServerCapabilities { - /// Defines how text documents are synced. - #[serde(skip_serializing_if = "Option::is_none")] - pub text_document_sync: Option, - - /// Capabilities specific to `textDocument/selectionRange` requests. - #[serde(skip_serializing_if = "Option::is_none")] - pub selection_range_provider: Option, - - /// The server provides hover support. - #[serde(skip_serializing_if = "Option::is_none")] - pub hover_provider: Option, - - /// The server provides completion support. - #[serde(skip_serializing_if = "Option::is_none")] - pub completion_provider: Option, - - /// The server provides signature help support. - #[serde(skip_serializing_if = "Option::is_none")] - pub signature_help_provider: Option, - - /// The server provides goto definition support. - #[serde(skip_serializing_if = "Option::is_none")] - pub definition_provider: Option, - - /// The server provides goto type definition support. - #[serde(skip_serializing_if = "Option::is_none")] - pub type_definition_provider: Option, - - /// the server provides goto implementation support. - #[serde(skip_serializing_if = "Option::is_none")] - pub implementation_provider: Option, - - /// The server provides find references support. - #[serde(skip_serializing_if = "Option::is_none")] - pub references_provider: Option, - - /// The server provides document highlight support. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_highlight_provider: Option, - - /// The server provides document symbol support. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_symbol_provider: Option, - - /// The server provides workspace symbol support. - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace_symbol_provider: Option, - - /// The server provides code actions. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action_provider: Option, - - /// The server provides code lens. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_lens_provider: Option, - - /// The server provides document formatting. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_formatting_provider: Option, - - /// The server provides document range formatting. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_range_formatting_provider: Option, - - /// The server provides document formatting on typing. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_on_type_formatting_provider: Option, - - /// The server provides rename support. - #[serde(skip_serializing_if = "Option::is_none")] - pub rename_provider: Option, - - /// The server provides document link support. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_link_provider: Option, - - /// The server provides color provider support. - #[serde(skip_serializing_if = "Option::is_none")] - pub color_provider: Option, - - /// The server provides folding provider support. - #[serde(skip_serializing_if = "Option::is_none")] - pub folding_range_provider: Option, - - /// The server provides go to declaration support. - #[serde(skip_serializing_if = "Option::is_none")] - pub declaration_provider: Option, - - /// The server provides execute command support. - #[serde(skip_serializing_if = "Option::is_none")] - pub execute_command_provider: Option, - - /// Workspace specific server capabilities - #[serde(skip_serializing_if = "Option::is_none")] - pub workspace: Option, - - /// Semantic highlighting server capabilities. - #[cfg(feature = "proposed")] - #[serde(skip_serializing_if = "Option::is_none")] - pub semantic_highlighting: Option, - - /// Call hierarchy provider capabilities. - #[cfg(feature = "proposed")] - #[serde(skip_serializing_if = "Option::is_none")] - pub call_hierarchy_provider: Option, - - /// Semantic tokens server capabilities. - #[cfg(feature = "proposed")] - #[serde(skip_serializing_if = "Option::is_none")] - pub semantic_tokens_provider: Option, - - /// Experimental server capabilities. - #[serde(skip_serializing_if = "Option::is_none")] - pub experimental: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentLinkCapabilities { - /// Whether document link supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Whether the client support the `tooltip` property on `DocumentLink`. - #[serde(skip_serializing_if = "Option::is_none")] - pub tooltip_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ShowMessageParams { - /// The message type. See {@link MessageType}. - #[serde(rename = "type")] - pub typ: MessageType, - - /// The actual message. - pub message: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum MessageType { - /// An error message. - Error = 1, - /// A warning message. - Warning = 2, - /// An information message. - Info = 3, - /// A log message. - Log = 4, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ShowMessageRequestParams { - /// The message type. See {@link MessageType} - #[serde(rename = "type")] - pub typ: MessageType, - - /// The actual message - pub message: String, - - /// The message action items to present. - #[serde(skip_serializing_if = "Option::is_none")] - pub actions: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct MessageActionItem { - /// A short title like 'Retry', 'Open Log' etc. - pub title: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct LogMessageParams { - /// The message type. See {@link MessageType} - #[serde(rename = "type")] - pub typ: MessageType, - - /// The actual message - pub message: String, -} - -/// General parameters to to register for a capability. -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Registration { - /// The id used to register the request. The id can be used to deregister - /// the request again. - pub id: String, - - /// The method / capability to register for. - pub method: String, - - /// Options necessary for the registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub register_options: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -pub struct RegistrationParams { - pub registrations: Vec, -} - -/// Since most of the registration options require to specify a document selector there is a base -/// interface that can be used. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct StaticRegistrationOptions { - #[serde(skip_serializing_if = "Option::is_none")] - pub id: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct StaticTextDocumentRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub id: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ColorProviderOptions {} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct StaticTextDocumentColorProviderOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - #[serde(skip_serializing_if = "Option::is_none")] - pub id: Option, -} - -/// General parameters to unregister a capability. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct Unregistration { - /// The id used to unregister the request or notification. Usually an id - /// provided during the register request. - pub id: String, - - /// The method / capability to unregister for. - pub method: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct UnregistrationParams { - pub unregisterations: Vec, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -pub struct DidChangeConfigurationParams { - /// The actual changed settings - pub settings: Value, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidOpenTextDocumentParams { - /// The document that was opened. - pub text_document: TextDocumentItem, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidChangeTextDocumentParams { - /// The document that did change. The version number points - /// to the version after all provided content changes have - /// been applied. - pub text_document: VersionedTextDocumentIdentifier, - /// The actual content changes. - pub content_changes: Vec, -} - -/// An event describing a change to a text document. If range and rangeLength are omitted -/// the new text is considered to be the full content of the document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentContentChangeEvent { - /// The range of the document that changed. - #[serde(skip_serializing_if = "Option::is_none")] - pub range: Option, - - /// The length of the range that got replaced. - /// NOTE: seems redundant, see: - #[serde(skip_serializing_if = "Option::is_none")] - pub range_length: Option, - - /// The new text of the document. - pub text: String, -} - -/// Descibe options to be used when registered for text document change events. -/// -/// Extends TextDocumentRegistrationOptions -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentChangeRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - /// How documents are synced to the server. See TextDocumentSyncKind.Full - /// and TextDocumentSyncKindIncremental. - pub sync_kind: i32, -} - -/// The parameters send in a will save text document notification. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct WillSaveTextDocumentParams { - /// The document that will be saved. - pub text_document: TextDocumentIdentifier, - - /// The 'TextDocumentSaveReason'. - pub reason: TextDocumentSaveReason, -} - -/// Represents reasons why a text document is saved. -#[derive(Copy, Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum TextDocumentSaveReason { - /// Manually triggered, e.g. by the user pressing save, by starting debugging, - /// or by an API call. - Manual = 1, - - /// Automatic after a delay. - AfterDelay = 2, - - /// When the editor lost focus. - FocusOut = 3, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidCloseTextDocumentParams { - /// The document that was closed. - pub text_document: TextDocumentIdentifier, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DidSaveTextDocumentParams { - /// The document that was saved. - pub text_document: TextDocumentIdentifier, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct TextDocumentSaveRegistrationOptions { - /// The client is supposed to include the content on save. - #[serde(skip_serializing_if = "Option::is_none")] - pub include_text: Option, - - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DidChangeWatchedFilesParams { - /// The actual file events. - pub changes: Vec, -} - -/// The file event type. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum FileChangeType { - /// The file got created. - Created = 1, - - /// The file got changed. - Changed = 2, - - /// The file got deleted. - Deleted = 3, -} - -/// An event describing a file change. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct FileEvent { - /// The file's URI. - pub uri: Url, - - /// The change type. - #[serde(rename = "type")] - pub typ: FileChangeType, -} - -impl FileEvent { - pub fn new(uri: Url, typ: FileChangeType) -> FileEvent { - FileEvent { uri, typ } - } -} - -/// Describe options to be used when registered for text document change events. -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] -pub struct DidChangeWatchedFilesRegistrationOptions { - /// The watchers to register. - pub watchers: Vec, -} - -#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FileSystemWatcher { - /// The glob pattern to watch - pub glob_pattern: String, - - /// The kind of events of interest. If omitted it defaults to WatchKind.Create | - /// WatchKind.Change | WatchKind.Delete which is 7. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, -} - -bitflags! { -pub struct WatchKind: u8 { - /// Interested in create events. - const Create = 1; - /// Interested in change events - const Change = 2; - /// Interested in delete events - const Delete = 4; -} -} - -impl<'de> serde::Deserialize<'de> for WatchKind { - fn deserialize(deserializer: D) -> Result - where - D: serde::Deserializer<'de>, - { - let i = u8::deserialize(deserializer)?; - WatchKind::from_bits(i).ok_or_else(|| { - D::Error::invalid_value(de::Unexpected::Unsigned(u64::from(i)), &"Unknown flag") - }) - } -} - -impl serde::Serialize for WatchKind { - fn serialize(&self, serializer: S) -> Result - where - S: serde::Serializer, - { - serializer.serialize_u8(self.bits()) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct PublishDiagnosticsParams { - /// The URI for which diagnostic information is reported. - pub uri: Url, - - /// An array of diagnostic information items. - pub diagnostics: Vec, - - /// Optional the version number of the document the diagnostics are published for. - #[serde(skip_serializing_if = "Option::is_none")] - pub version: Option, -} - -impl PublishDiagnosticsParams { - pub fn new( - uri: Url, - diagnostics: Vec, - version: Option, - ) -> PublishDiagnosticsParams { - PublishDiagnosticsParams { - uri, - diagnostics, - version, - } - } -} - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -pub struct CompletionRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub completion_options: CompletionOptions, -} - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum CompletionResponse { - Array(Vec), - List(CompletionList), -} - -impl From> for CompletionResponse { - fn from(items: Vec) -> Self { - CompletionResponse::Array(items) - } -} - -impl From for CompletionResponse { - fn from(list: CompletionList) -> Self { - CompletionResponse::List(list) - } -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionParams { - // This field was "mixed-in" from TextDocumentPositionParams - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - // CompletionParams properties: - #[serde(skip_serializing_if = "Option::is_none")] - pub context: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionContext { - /// How the completion was triggered. - pub trigger_kind: CompletionTriggerKind, - - /// The trigger character (a single character) that has trigger code complete. - /// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` - #[serde(skip_serializing_if = "Option::is_none")] - pub trigger_character: Option, -} - -/// How a completion was triggered. -#[derive(Debug, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum CompletionTriggerKind { - Invoked = 1, - TriggerCharacter = 2, - TriggerForIncompleteCompletions = 3, -} - -/// Represents a collection of [completion items](#CompletionItem) to be presented -/// in the editor. -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CompletionList { - /// This list it not complete. Further typing should result in recomputing - /// this list. - pub is_incomplete: bool, - - /// The completion items. - pub items: Vec, -} - -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -#[serde(untagged)] -pub enum Documentation { - String(String), - MarkupContent(MarkupContent), -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct CompletionItem { - /// The label of this completion item. By default - /// also the text that is inserted when selecting - /// this completion. - pub label: String, - - /// The kind of this completion item. Based of the kind - /// an icon is chosen by the editor. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, - - /// A human-readable string with additional information - /// about this item, like type or symbol information. - #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - - /// A human-readable string that represents a doc-comment. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation: Option, - - /// Indicates if this item is deprecated. - #[serde(skip_serializing_if = "Option::is_none")] - pub deprecated: Option, - - /// Select this item when showing. - #[serde(skip_serializing_if = "Option::is_none")] - pub preselect: Option, - - /// A string that shoud be used when comparing this item - /// with other items. When `falsy` the label is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub sort_text: Option, - - /// A string that should be used when filtering a set of - /// completion items. When `falsy` the label is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub filter_text: Option, - - /// A string that should be inserted a document when selecting - /// this completion. When `falsy` the label is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_text: Option, - - /// The format of the insert text. The format applies to both the `insertText` property - /// and the `newText` property of a provided `textEdit`. - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_text_format: Option, - - /// An edit which is applied to a document when selecting - /// this completion. When an edit is provided the value of - /// insertText is ignored. - /// - /// Most editors support two different operation when accepting a completion item. One is to insert a - /// completion text and the other is to replace an existing text with a competion text. Since this can - /// usually not predetermend by a server it can report both ranges. Clients need to signal support for - /// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability - /// property. - /// - /// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a - /// [single line] and they must contain the position at which completion has been requested. - /// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of - /// the edit's replace range, that means it must be contained and starting at the same position. - /// - /// @since 3.16.0 additional type `InsertReplaceEdit` - Proposed state - #[serde(skip_serializing_if = "Option::is_none")] - pub text_edit: Option, - - /// An optional array of additional text edits that are applied when - /// selecting this completion. Edits must not overlap with the main edit - /// nor with themselves. - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_text_edits: Option>, - - /// An optional command that is executed *after* inserting this completion. *Note* that - /// additional modifications to the current document should be described with the - /// additionalTextEdits-property. - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - - /// An data entry field that is preserved on a completion item between - /// a completion and a completion resolve request. - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, - - /// Tags for this completion item. - #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option>, -} - -impl CompletionItem { - /// Create a CompletionItem with the minimum possible info (label and detail). - pub fn new_simple(label: String, detail: String) -> CompletionItem { - CompletionItem { - label, - detail: Some(detail), - ..Self::default() - } - } -} - -/// The kind of a completion entry. -#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum CompletionItemKind { - Text = 1, - Method = 2, - Function = 3, - Constructor = 4, - Field = 5, - Variable = 6, - Class = 7, - Interface = 8, - Module = 9, - Property = 10, - Unit = 11, - Value = 12, - Enum = 13, - Keyword = 14, - Snippet = 15, - Color = 16, - File = 17, - Reference = 18, - Folder = 19, - EnumMember = 20, - Constant = 21, - Struct = 22, - Event = 23, - Operator = 24, - TypeParameter = 25, -} - -/// Defines how to interpret the insert text in a completion item -#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum InsertTextFormat { - PlainText = 1, - Snippet = 2, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct HoverParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -/// The result of a hover request. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct Hover { - /// The hover's content - pub contents: HoverContents, - /// An optional range is a range inside a text document - /// that is used to visualize a hover, e.g. by changing the background color. - #[serde(skip_serializing_if = "Option::is_none")] - pub range: Option, -} - -/// Hover contents could be single entry or multiple entries. -#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum HoverContents { - Scalar(MarkedString), - Array(Vec), - Markup(MarkupContent), -} - -/// The marked string is rendered: -/// - as markdown if it is represented as a string -/// - as code block of the given langauge if it is represented as a pair of a language and a value -/// -/// The pair of a language and a value is an equivalent to markdown: -/// ```${language} -/// ${value} -/// ``` -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum MarkedString { - String(String), - LanguageString(LanguageString), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct LanguageString { - pub language: String, - pub value: String, -} - -impl MarkedString { - pub fn from_markdown(markdown: String) -> MarkedString { - MarkedString::String(markdown) - } - - pub fn from_language_code(language: String, code_block: String) -> MarkedString { - MarkedString::LanguageString(LanguageString { - language, - value: code_block, - }) - } -} - -/// Signature help represents the signature of something -/// callable. There can be multiple signature but only one -/// active and only one active parameter. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SignatureHelp { - /// One or more signatures. - pub signatures: Vec, - - /// The active signature. - #[serde(skip_serializing_if = "Option::is_none")] - pub active_signature: Option, - - /// The active parameter of the active signature. - #[serde(skip_serializing_if = "Option::is_none")] - pub active_parameter: Option, -} - -/// Represents the signature of something callable. A signature -/// can have a label, like a function-name, a doc-comment, and -/// a set of parameters. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct SignatureInformation { - /// The label of this signature. Will be shown in - /// the UI. - pub label: String, - - /// The human-readable doc-comment of this signature. Will be shown - /// in the UI but can be omitted. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation: Option, - - /// The parameters of this signature. - #[serde(skip_serializing_if = "Option::is_none")] - pub parameters: Option>, -} - -/// Represents a parameter of a callable-signature. A parameter can -/// have a label and a doc-comment. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ParameterInformation { - /// The label of this parameter information. - /// - /// Either a string or an inclusive start and exclusive end offsets within its containing - /// signature label. (see SignatureInformation.label). *Note*: A label of type string must be - /// a substring of its containing signature label. - pub label: ParameterLabel, - - /// The human-readable doc-comment of this parameter. Will be shown - /// in the UI but can be omitted. - #[serde(skip_serializing_if = "Option::is_none")] - pub documentation: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum ParameterLabel { - Simple(String), - LabelOffsets([u64; 2]), -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct GotoDefinitionParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// GotoDefinition response can be single location, or multiple Locations or a link. -#[derive(Debug, PartialEq, Serialize, Deserialize)] -#[serde(untagged)] -pub enum GotoDefinitionResponse { - Scalar(Location), - Array(Vec), - Link(Vec), -} - -impl From for GotoDefinitionResponse { - fn from(location: Location) -> Self { - GotoDefinitionResponse::Scalar(location) - } -} - -impl From> for GotoDefinitionResponse { - fn from(locations: Vec) -> Self { - GotoDefinitionResponse::Array(locations) - } -} - -impl From> for GotoDefinitionResponse { - fn from(locations: Vec) -> Self { - GotoDefinitionResponse::Link(locations) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ReferenceParams { - // Text Document and Position fields - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - // ReferenceParams properties: - pub context: ReferenceContext, -} - -#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ReferenceContext { - /// Include the declaration of the current symbol. - pub include_declaration: bool, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentHighlightParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// A document highlight is a range inside a text document which deserves -/// special attention. Usually a document highlight is visualized by changing -/// the background color of its range. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DocumentHighlight { - /// The range this highlight applies to. - pub range: Range, - - /// The highlight kind, default is DocumentHighlightKind.Text. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, -} - -/// A document highlight kind. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -pub enum DocumentHighlightKind { - /// A textual occurrance. - Text = 1, - - /// Read-access of a symbol, like reading a variable. - Read = 2, - - /// Write-access of a symbol, like writing to a variable. - Write = 3, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentSymbolClientCapabilities { - /// This capability supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Specific capabilities for the `SymbolKind`. - #[serde(skip_serializing_if = "Option::is_none")] - pub symbol_kind: Option, - - /// The client support hierarchical document symbols. - #[serde(skip_serializing_if = "Option::is_none")] - pub hierarchical_document_symbol_support: Option, - - /// The client supports tags on `SymbolInformation`. Tags are supported on - /// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. - /// Clients supporting tags have to handle unknown tags gracefully. - /// - /// @since 3.16.0 - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "TagSupport::deserialize_compat" - )] - #[cfg(feature = "proposed")] - pub tag_support: Option>, -} - -#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] -#[serde(untagged)] -pub enum DocumentSymbolResponse { - Flat(Vec), - Nested(Vec), -} - -impl From> for DocumentSymbolResponse { - fn from(info: Vec) -> Self { - DocumentSymbolResponse::Flat(info) - } -} - -impl From> for DocumentSymbolResponse { - fn from(symbols: Vec) -> Self { - DocumentSymbolResponse::Nested(symbols) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentSymbolParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents programming constructs like variables, classes, interfaces etc. -/// that appear in a document. Document symbols can be hierarchical and they have two ranges: -/// one that encloses its definition and one that points to its most interesting range, -/// e.g. the range of an identifier. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentSymbol { - /// The name of this symbol. - pub name: String, - /// More detail for this symbol, e.g the signature of a function. If not provided the - /// name is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - /// The kind of this symbol. - pub kind: SymbolKind, - /// Tags for this completion item. - /// since 3.16.0 - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub tags: Option>, - /// Indicates if this symbol is deprecated. - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(note = "Use tags instead")] - pub deprecated: Option, - /// The range enclosing this symbol not including leading/trailing whitespace but everything else - /// like comments. This information is typically used to determine if the the clients cursor is - /// inside the symbol to reveal in the symbol in the UI. - pub range: Range, - /// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. - /// Must be contained by the the `range`. - pub selection_range: Range, - /// Children of this symbol, e.g. properties of a class. - #[serde(skip_serializing_if = "Option::is_none")] - pub children: Option>, -} - -/// Represents information about programming constructs like variables, classes, -/// interfaces etc. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SymbolInformation { - /// The name of this symbol. - pub name: String, - - /// The kind of this symbol. - pub kind: SymbolKind, - - /// Tags for this completion item. - /// since 3.16.0 - #[serde(skip_serializing_if = "Option::is_none")] - #[cfg(feature = "proposed")] - pub tags: Option>, - - /// Indicates if this symbol is deprecated. - #[serde(skip_serializing_if = "Option::is_none")] - #[deprecated(note = "Use tags instead")] - pub deprecated: Option, - - /// The location of this symbol. - pub location: Location, - - /// The name of the symbol containing this symbol. - #[serde(skip_serializing_if = "Option::is_none")] - pub container_name: Option, -} - -/// A symbol kind. -#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize_repr, Deserialize_repr)] -#[repr(u8)] -pub enum SymbolKind { - File = 1, - Module = 2, - Namespace = 3, - Package = 4, - Class = 5, - Method = 6, - Property = 7, - Field = 8, - Constructor = 9, - Enum = 10, - Interface = 11, - Function = 12, - Variable = 13, - Constant = 14, - String = 15, - Number = 16, - Boolean = 17, - Array = 18, - Object = 19, - Key = 20, - Null = 21, - EnumMember = 22, - Struct = 23, - Event = 24, - Operator = 25, - TypeParameter = 26, - - // Capturing all unknown enums by this lib. - Unknown = 255, -} - -/// The parameters of a Workspace Symbol Request. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct WorkspaceSymbolParams { - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - /// A non-empty query string - pub query: String, -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct ExecuteCommandParams { - /// The identifier of the actual command handler. - pub command: String, - /// Arguments that the command should be invoked with. - #[serde(default)] - pub arguments: Vec, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -/// Execute command registration options. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ExecuteCommandRegistrationOptions { - /// The commands to be executed on the server - pub commands: Vec, - - #[serde(flatten)] - pub execute_command_options: ExecuteCommandOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ApplyWorkspaceEditParams { - /// The edits to apply. - pub edit: WorkspaceEdit, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct ApplyWorkspaceEditResponse { - /// Indicates whether the edit was applied or not. - pub applied: bool, -} - -/// Params for the CodeActionRequest -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionParams { - /// The document in which the command was invoked. - pub text_document: TextDocumentIdentifier, - - /// The range for which the command was invoked. - pub range: Range, - - /// Context carrying additional information. - pub context: CodeActionContext, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// response for CodeActionRequest -pub type CodeActionResponse = Vec; - -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -#[serde(untagged)] -pub enum CodeActionOrCommand { - Command(Command), - CodeAction(CodeAction), -} - -impl From for CodeActionOrCommand { - fn from(comand: Command) -> Self { - CodeActionOrCommand::Command(comand) - } -} - -impl From for CodeActionOrCommand { - fn from(action: CodeAction) -> Self { - CodeActionOrCommand::CodeAction(action) - } -} - -#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] -pub struct CodeActionKind(Cow<'static, str>); - -impl CodeActionKind { - /// Empty kind. - pub const EMPTY: CodeActionKind = CodeActionKind::new(""); - - /// Base kind for quickfix actions: 'quickfix' - pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix"); - - /// Base kind for refactoring actions: 'refactor' - pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor"); - - /// Base kind for refactoring extraction actions: 'refactor.extract' - /// - /// Example extract actions: - /// - /// - Extract method - /// - Extract function - /// - Extract variable - /// - Extract interface from class - /// - ... - pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract"); - - /// Base kind for refactoring inline actions: 'refactor.inline' - /// - /// Example inline actions: - /// - /// - Inline function - /// - Inline variable - /// - Inline constant - /// - ... - pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline"); - - /// Base kind for refactoring rewrite actions: 'refactor.rewrite' - /// - /// Example rewrite actions: - /// - /// - Convert JavaScript function to class - /// - Add or remove parameter - /// - Encapsulate field - /// - Make method static - /// - Move method to base class - /// - ... - pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite"); - - /// Base kind for source actions: `source` - /// - /// Source code actions apply to the entire file. - pub const SOURCE: CodeActionKind = CodeActionKind::new("source"); - - /// Base kind for an organize imports source action: `source.organizeImports` - pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind = - CodeActionKind::new("source.organizeImports"); - - pub const fn new(tag: &'static str) -> Self { - CodeActionKind(Cow::Borrowed(tag)) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -impl From for CodeActionKind { - fn from(from: String) -> Self { - CodeActionKind(Cow::from(from)) - } -} - -impl From<&'static str> for CodeActionKind { - fn from(from: &'static str) -> Self { - CodeActionKind::new(from) - } -} - -#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeAction { - /// A short, human-readable, title for this code action. - pub title: String, - - /// The kind of the code action. - /// Used to filter code actions. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, - - /// The diagnostics that this code action resolves. - #[serde(skip_serializing_if = "Option::is_none")] - pub diagnostics: Option>, - - /// The workspace edit this code action performs. - #[serde(skip_serializing_if = "Option::is_none")] - pub edit: Option, - - /// A command this code action executes. If a code action - /// provides an edit and a command, first the edit is - /// executed and then the command. - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - - /// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted - /// by keybindings. - /// A quick fix should be marked preferred if it properly addresses the underlying error. - /// A refactoring should be marked preferred if it is the most reasonable choice of actions to take. - #[serde(skip_serializing_if = "Option::is_none")] - pub is_preferred: Option, -} - -/// Contains additional diagnostic information about the context in which -/// a code action is run. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct CodeActionContext { - /// An array of diagnostics. - pub diagnostics: Vec, - - /// Requested kind of actions to return. - /// - /// Actions not of this kind are filtered out by the client before being shown. So servers - /// can omit computing them. - #[serde(skip_serializing_if = "Option::is_none")] - pub only: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeActionOptions { - /// CodeActionKinds that this server may return. - /// - /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server - /// may list out every specific kind they provide. - #[serde(skip_serializing_if = "Option::is_none")] - pub code_action_kinds: Option>, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct CodeLensParams { - /// The document to request code lens for. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// A code lens represents a command that should be shown along with -/// source text, like the number of references, a way to run tests, etc. -/// -/// A code lens is _unresolved_ when no command is associated to it. For performance -/// reasons the creation of a code lens and resolving should be done in two stages. -#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] -pub struct CodeLens { - /// The range in which this code lens is valid. Should only span a single line. - pub range: Range, - - /// The command this code lens represents. - #[serde(skip_serializing_if = "Option::is_none")] - pub command: Option, - - /// A data entry field that is preserved on a code lens item between - /// a code lens and a code lens resolve request. - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentLinkParams { - /// The document to provide document links for. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// A document link is a range in a text document that links to an internal or external resource, like another -/// text document or a web site. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct DocumentLink { - /// The range this link applies to. - pub range: Range, - /// The uri this link points to. - #[serde(skip_serializing_if = "Option::is_none")] - pub target: Option, - - /// The tooltip text when you hover over this link. - /// - /// If a tooltip is provided, is will be displayed in a string that includes instructions on how to - /// trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, - /// user settings, and localization. - #[serde(skip_serializing_if = "Option::is_none")] - pub tooltip: Option, - - /// A data entry field that is preserved on a document link between a DocumentLinkRequest - /// and a DocumentLinkResolveRequest. - #[serde(skip_serializing_if = "Option::is_none")] - pub data: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentFormattingParams { - /// The document to format. - pub text_document: TextDocumentIdentifier, - - /// The format options. - pub options: FormattingOptions, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -/// Value-object describing what options formatting should use. -#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] -pub struct FormattingOptions { - /// Size of a tab in spaces. - pub tab_size: u64, - - /// Prefer spaces over tabs. - pub insert_spaces: bool, - - /// Signature for further properties. - #[serde(flatten)] - pub properties: HashMap, - - /// Trim trailing whitespaces on a line. - #[serde(skip_serializing_if = "Option::is_none")] - pub trim_trailing_whitespace: Option, - - /// Insert a newline character at the end of the file if one does not exist. - #[serde(skip_serializing_if = "Option::is_none")] - pub insert_final_newline: Option, - - /// Trim all newlines after the final newline at the end of the file. - #[serde(skip_serializing_if = "Option::is_none")] - pub trim_final_newlines: Option, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum FormattingProperty { - Bool(bool), - Number(f64), - String(String), -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentRangeFormattingParams { - /// The document to format. - pub text_document: TextDocumentIdentifier, - - /// The range to format - pub range: Range, - - /// The format options - pub options: FormattingOptions, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentOnTypeFormattingParams { - /// Text Document and Position fields. - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - /// The character that has been typed. - pub ch: String, - - /// The format options. - pub options: FormattingOptions, -} - -/// Extends TextDocumentRegistrationOptions -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentOnTypeFormattingRegistrationOptions { - /// A document selector to identify the scope of the registration. If set to null - /// the document selector provided on the client side will be used. - pub document_selector: Option, - - /// A character on which formatting should be triggered, like `}`. - pub first_trigger_character: String, - - /// More trigger characters. - #[serde(skip_serializing_if = "Option::is_none")] - pub more_trigger_character: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameParams { - /// Text Document and Position fields - #[serde(flatten)] - pub text_document_position: TextDocumentPositionParams, - - /// The new name of the symbol. If the given name is not valid the - /// request must return a [ResponseError](#ResponseError) with an - /// appropriate message set. - pub new_name: String, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum RenameProviderCapability { - Simple(bool), - Options(RenameOptions), -} - -impl From for RenameProviderCapability { - fn from(from: RenameOptions) -> Self { - Self::Options(from) - } -} - -impl From for RenameProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameOptions { - /// Renames should be checked and tested before being executed. - #[serde(skip_serializing_if = "Option::is_none")] - pub prepare_provider: Option, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct RenameCapability { - /// Whether rename supports dynamic registration. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// Client supports testing for validity of rename operations before execution. - #[serde(skip_serializing_if = "Option::is_none")] - pub prepare_support: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum PrepareRenameResponse { - Range(Range), - RangeWithPlaceholder { range: Range, placeholder: String }, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentLinkOptions { - /// Document links have a resolve provider as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub resolve_provider: Option, - - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct DocumentColorParams { - /// The text document - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ColorInformation { - /// The range in the document where this color appears. - pub range: Range, - /// The actual color value for this color range. - pub color: Color, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct Color { - /// The red component of this color in the range [0-1]. - pub red: f64, - /// The green component of this color in the range [0-1]. - pub green: f64, - /// The blue component of this color in the range [0-1]. - pub blue: f64, - /// The alpha component of this color in the range [0-1]. - pub alpha: f64, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct ColorPresentationParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The color information to request presentations for. - pub color: Color, - - /// The range where the color would be inserted. Serves as a context. - pub range: Range, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Default, Clone)] -#[serde(rename_all = "camelCase")] -pub struct ColorPresentation { - /// The label of this color presentation. It will be shown on the color - /// picker header. By default this is also the text that is inserted when selecting - /// this color presentation. - pub label: String, - - /// An [edit](#TextEdit) which is applied to a document when selecting - /// this presentation for the color. When `falsy` the [label](#ColorPresentation.label) - /// is used. - #[serde(skip_serializing_if = "Option::is_none")] - pub text_edit: Option, - - /// An optional array of additional [text edits](#TextEdit) that are applied when - /// selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. - #[serde(skip_serializing_if = "Option::is_none")] - pub additional_text_edits: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FoldingRangeParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum FoldingRangeProviderCapability { - Simple(bool), - FoldingProvider(FoldingProviderOptions), - Options(StaticTextDocumentColorProviderOptions), -} - -impl From for FoldingRangeProviderCapability { - fn from(from: StaticTextDocumentColorProviderOptions) -> Self { - Self::Options(from) - } -} - -impl From for FoldingRangeProviderCapability { - fn from(from: FoldingProviderOptions) -> Self { - Self::FoldingProvider(from) - } -} - -impl From for FoldingRangeProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct FoldingProviderOptions {} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FoldingRangeCapability { - /// Whether implementation supports dynamic registration for folding range providers. If this is set to `true` - /// the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` - /// return value for the corresponding server capability as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The maximum number of folding ranges that the client prefers to receive per document. The value serves as a - /// hint, servers are free to follow the limit. - #[serde(skip_serializing_if = "Option::is_none")] - pub range_limit: Option, - /// If set, the client signals that it only supports folding complete lines. If set, client will - /// ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. - #[serde(skip_serializing_if = "Option::is_none")] - pub line_folding_only: Option, -} - -/// Represents a folding range. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct FoldingRange { - /// The zero-based line number from where the folded range starts. - pub start_line: u64, - - /// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. - #[serde(skip_serializing_if = "Option::is_none")] - pub start_character: Option, - - /// The zero-based line number where the folded range ends. - pub end_line: u64, - - /// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. - #[serde(skip_serializing_if = "Option::is_none")] - pub end_character: Option, - - /// Describes the kind of the folding range such as `comment' or 'region'. The kind - /// is used to categorize folding ranges and used by commands like 'Fold all comments'. See - /// [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. - #[serde(skip_serializing_if = "Option::is_none")] - pub kind: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -pub struct SelectionRangeOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -pub struct SelectionRangeRegistrationOptions { - #[serde(flatten)] - pub selection_range_options: SelectionRangeOptions, - - #[serde(flatten)] - pub registration_options: StaticTextDocumentRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -pub enum SelectionRangeProviderCapability { - Simple(bool), - Options(SelectionRangeOptions), - RegistrationOptions(SelectionRangeRegistrationOptions), -} - -impl From for SelectionRangeProviderCapability { - fn from(from: SelectionRangeRegistrationOptions) -> Self { - Self::RegistrationOptions(from) - } -} - -impl From for SelectionRangeProviderCapability { - fn from(from: SelectionRangeOptions) -> Self { - Self::Options(from) - } -} - -impl From for SelectionRangeProviderCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -/// A parameter literal used in selection range requests. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SelectionRangeParams { - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The positions inside the text document. - pub positions: Vec, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents a selection range. -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -pub struct SelectionRange { - /// Range of the selection. - pub range: Range, - - /// The parent selection range containing this range. - #[serde(skip_serializing_if = "Option::is_none")] - pub parent: Option>, -} - -/// Enum of known range kinds -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "lowercase")] -pub enum FoldingRangeKind { - /// Folding range for a comment - Comment, - /// Folding range for a imports or includes - Imports, - /// Folding range for a region (e.g. `#region`) - Region, -} - -/// Describes the content type that a client supports in various -/// result literals like `Hover`, `ParameterInfo` or `CompletionItem`. -/// -/// Please note that `MarkupKinds` must not start with a `$`. This kinds -/// are reserved for internal usage. -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "lowercase")] -pub enum MarkupKind { - /// Plain text is supported as a content format - PlainText, - /// Markdown is supported as a content format - Markdown, -} - -/// A `MarkupContent` literal represents a string value which content is interpreted base on its -/// kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. -/// -/// If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. -/// See -/// -/// Here is an example how such a string can be constructed using JavaScript / TypeScript: -/// ```ignore -/// let markdown: MarkupContent = { -/// kind: MarkupKind::Markdown, -/// value: [ -/// "# Header", -/// "Some text", -/// "```typescript", -/// "someCode();", -/// "```" -/// ] -/// .join("\n"), -/// }; -/// ``` -/// -/// Please Note* that clients might sanitize the return markdown. A client could decide to -/// remove HTML from the markdown to avoid script execution. -#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] -pub struct MarkupContent { - pub kind: MarkupKind, - pub value: String, -} - -pub type ProgressToken = NumberOrString; - -/// The progress notification is sent from the server to the client to ask -/// the client to indicate progress. -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct ProgressParams { - /// The progress token provided by the client. - pub token: ProgressToken, - - /// The progress data. - pub value: ProgressParamsValue, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(untagged)] -pub enum ProgressParamsValue { - WorkDone(WorkDoneProgress), -} - -/// The `window/workDoneProgress/create` request is sent from the server -/// to the clientto ask the client to create a work done progress. -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressCreateParams { - /// The token to be used to report progress. - pub token: ProgressToken, -} - -/// The `window/workDoneProgress/cancel` notification is sent from the client -/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressCancelParams { - /// The token to be used to report progress. - pub token: ProgressToken, -} - -/// Options to signal work done progress support in server capabilities. -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressOptions { - #[serde(skip_serializing_if = "Option::is_none")] - pub work_done_progress: Option, -} - -/// An optional token that a server can use to report work done progress -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressParams { - #[serde(skip_serializing_if = "Option::is_none")] - pub work_done_token: Option, -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressBegin { - /// Mandatory title of the progress operation. Used to briefly inform - /// about the kind of operation being performed. - /// Examples: "Indexing" or "Linking dependencies". - pub title: String, - - /// Controls if a cancel button should show to allow the user to cancel the - /// long running operation. Clients that don't support cancellation are allowed - /// to ignore the setting. - #[serde(skip_serializing_if = "Option::is_none")] - pub cancellable: Option, - - /// Optional, more detailed associated progress message. Contains - /// complementary information to the `title`. - /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - /// If unset, the previous progress message (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, - - /// Optional progress percentage to display (value 100 is considered 100%). - /// If unset, the previous progress percentage (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub percentage: Option, -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressReport { - /// Controls if a cancel button should show to allow the user to cancel the - /// long running operation. Clients that don't support cancellation are allowed - /// to ignore the setting. - #[serde(skip_serializing_if = "Option::is_none")] - pub cancellable: Option, - - /// Optional, more detailed associated progress message. Contains - /// complementary information to the `title`. - /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - /// If unset, the previous progress message (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, - - /// Optional progress percentage to display (value 100 is considered 100%). - /// If unset, the previous progress percentage (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub percentage: Option, -} - -#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct WorkDoneProgressEnd { - /// Optional, more detailed associated progress message. Contains - /// complementary information to the `title`. - /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". - /// If unset, the previous progress message (if any) is still valid. - #[serde(skip_serializing_if = "Option::is_none")] - pub message: Option, -} - -#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] -#[serde(tag = "kind", rename_all = "lowercase")] -pub enum WorkDoneProgress { - Begin(WorkDoneProgressBegin), - Report(WorkDoneProgressReport), - End(WorkDoneProgressEnd), -} - -/// A parameter literal used to pass a partial result token. -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -pub struct PartialResultParams { - #[serde(skip_serializing_if = "Option::is_none")] - pub partial_result_token: Option, -} - -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingClientCapability { - /// `true` if the client supports semantic highlighting support text documents. Otherwise, `false`. It is `false` by default. - pub semantic_highlighting: bool, -} - -#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingServerCapability { - /// A "lookup table" of semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars) - /// supported by the language server. If not defined or empty, then the server does not support the semantic highlighting - /// feature. Otherwise, clients should reuse this "lookup table" when receiving semantic highlighting notifications from - /// the server. - #[serde(skip_serializing_if = "Option::is_none")] - pub scopes: Option>>, -} - -#[derive(Debug, Eq, PartialEq, Clone)] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingToken { - pub character: u32, - pub length: u16, - pub scope: u16, -} - -#[cfg(feature = "proposed")] -impl SemanticHighlightingToken { - /// Deserializes the tokens from a base64 encoded string - fn deserialize_tokens<'de, D>( - deserializer: D, - ) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - { - let opt_s = Option::::deserialize(deserializer)?; - - if let Some(s) = opt_s { - let bytes = base64::decode_config(s.as_str(), base64::STANDARD) - .map_err(|_| serde::de::Error::custom("Error parsing base64 string"))?; - let mut res = Vec::new(); - for chunk in bytes.chunks_exact(8) { - res.push(SemanticHighlightingToken { - character: u32::from_be_bytes(<[u8; 4]>::try_from(&chunk[0..4]).unwrap()), - length: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[4..6]).unwrap()), - scope: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[6..8]).unwrap()), - }); - } - Result::Ok(Some(res)) - } else { - Result::Ok(None) - } - } - - /// Serialize the tokens to a base64 encoded string - fn serialize_tokens( - tokens: &Option>, - serializer: S, - ) -> Result - where - S: serde::Serializer, - { - if let Some(tokens) = tokens { - let mut bytes = vec![]; - for token in tokens { - bytes.extend_from_slice(&token.character.to_be_bytes()); - bytes.extend_from_slice(&token.length.to_be_bytes()); - bytes.extend_from_slice(&token.scope.to_be_bytes()); - } - serializer.collect_str(&base64::display::Base64Display::with_config( - &bytes, - base64::STANDARD, - )) - } else { - serializer.serialize_none() - } - } -} - -/// Represents a semantic highlighting information that has to be applied on a specific line of the text document. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingInformation { - /// The zero-based line position in the text document. - pub line: i32, - - /// A base64 encoded string representing every single highlighted characters with its start position, length and the "lookup table" index of - /// of the semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars). - /// If the `tokens` is empty or not defined, then no highlighted positions are available for the line. - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "SemanticHighlightingToken::deserialize_tokens", - serialize_with = "SemanticHighlightingToken::serialize_tokens" - )] - pub tokens: Option>, -} - -/// Parameters for the semantic highlighting (server-side) push notification. -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticHighlightingParams { - /// The text document that has to be decorated with the semantic highlighting information. - pub text_document: VersionedTextDocumentIdentifier, - - /// An array of semantic highlighting information. - pub lines: Vec, -} - -/// A set of predefined token types. This set is not fixed -/// and clients can specify additional token types via the -/// corresponding client capabilities. -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] -#[cfg(feature = "proposed")] -pub struct SemanticTokenType(Cow<'static, str>); - -#[cfg(feature = "proposed")] -impl SemanticTokenType { - pub const COMMENT: SemanticTokenType = SemanticTokenType::new("comment"); - pub const KEYWORD: SemanticTokenType = SemanticTokenType::new("keyword"); - pub const STRING: SemanticTokenType = SemanticTokenType::new("string"); - pub const NUMBER: SemanticTokenType = SemanticTokenType::new("number"); - pub const REGEXP: SemanticTokenType = SemanticTokenType::new("regexp"); - pub const OPERATOR: SemanticTokenType = SemanticTokenType::new("operator"); - pub const NAMESPACE: SemanticTokenType = SemanticTokenType::new("namespace"); - pub const TYPE: SemanticTokenType = SemanticTokenType::new("type"); - pub const STRUCT: SemanticTokenType = SemanticTokenType::new("struct"); - pub const CLASS: SemanticTokenType = SemanticTokenType::new("class"); - pub const INTERFACE: SemanticTokenType = SemanticTokenType::new("interface"); - pub const ENUM: SemanticTokenType = SemanticTokenType::new("enum"); - pub const TYPE_PARAMETER: SemanticTokenType = SemanticTokenType::new("typeParameter"); - pub const FUNCTION: SemanticTokenType = SemanticTokenType::new("function"); - pub const MEMBER: SemanticTokenType = SemanticTokenType::new("member"); - pub const PROPERTY: SemanticTokenType = SemanticTokenType::new("property"); - pub const MACRO: SemanticTokenType = SemanticTokenType::new("macro"); - pub const VARIABLE: SemanticTokenType = SemanticTokenType::new("variable"); - pub const PARAMETER: SemanticTokenType = SemanticTokenType::new("parameter"); - pub const LABEL: SemanticTokenType = SemanticTokenType::new("label"); - - pub const fn new(tag: &'static str) -> Self { - SemanticTokenType(Cow::Borrowed(tag)) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokenType { - fn from(from: String) -> Self { - SemanticTokenType(Cow::from(from)) - } -} -#[cfg(feature = "proposed")] -impl From<&'static str> for SemanticTokenType { - fn from(from: &'static str) -> Self { - SemanticTokenType::new(from) - } -} - -/// A set of predefined token modifiers. This set is not fixed -/// and clients can specify additional token types via the -/// corresponding client capabilities. -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] -#[cfg(feature = "proposed")] -pub struct SemanticTokenModifier(Cow<'static, str>); - -#[cfg(feature = "proposed")] -impl SemanticTokenModifier { - pub const DOCUMENTATION: SemanticTokenModifier = SemanticTokenModifier::new("documentation"); - pub const DECLARATION: SemanticTokenModifier = SemanticTokenModifier::new("declaration"); - pub const DEFINITION: SemanticTokenModifier = SemanticTokenModifier::new("definition"); - pub const STATIC: SemanticTokenModifier = SemanticTokenModifier::new("static"); - pub const ABSTRACT: SemanticTokenModifier = SemanticTokenModifier::new("abstract"); - pub const DEPRECATED: SemanticTokenModifier = SemanticTokenModifier::new("deprecated"); - pub const READONLY: SemanticTokenModifier = SemanticTokenModifier::new("readonly"); - - pub const fn new(tag: &'static str) -> Self { - SemanticTokenModifier(Cow::Borrowed(tag)) - } - - pub fn as_str(&self) -> &str { - &self.0 - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokenModifier { - fn from(from: String) -> Self { - SemanticTokenModifier(Cow::from(from)) - } -} -#[cfg(feature = "proposed")] -impl From<&'static str> for SemanticTokenModifier { - fn from(from: &'static str) -> Self { - SemanticTokenModifier::new(from) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensLegend { - /// The token types a server uses. - pub token_types: Vec, - - /// The token modifiers a server uses. - pub token_modifiers: Vec, -} - -/// The actual tokens. For a detailed description about how the data is -/// structured please see -/// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 -#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] -#[cfg(feature = "proposed")] -pub struct SemanticToken { - pub delta_line: u32, - pub delta_start: u32, - pub length: u32, - pub token_type: u32, - pub token_modifiers_bitset: u32, -} - -#[cfg(feature = "proposed")] -impl SemanticToken { - fn deserialize_tokens<'de, D>(deserializer: D) -> Result, D::Error> - where - D: serde::Deserializer<'de>, - { - let data = Vec::::deserialize(deserializer)?; - let chunks = data.chunks_exact(5); - - if !chunks.remainder().is_empty() { - return Result::Err(serde::de::Error::custom("Length is not divisible by 5")); - } - - Result::Ok( - chunks - .map(|chunk| SemanticToken { - delta_line: chunk[0], - delta_start: chunk[1], - length: chunk[2], - token_type: chunk[3], - token_modifiers_bitset: chunk[4], - }) - .collect(), - ) - } - - fn serialize_tokens(tokens: &[SemanticToken], serializer: S) -> Result - where - S: serde::Serializer, - { - let mut seq = serializer.serialize_seq(Some(tokens.len() * 5))?; - for token in tokens.iter() { - seq.serialize_element(&token.delta_line)?; - seq.serialize_element(&token.delta_start)?; - seq.serialize_element(&token.length)?; - seq.serialize_element(&token.token_type)?; - seq.serialize_element(&token.token_modifiers_bitset)?; - } - seq.end() - } - - fn deserialize_tokens_opt<'de, D>( - deserializer: D, - ) -> Result>, D::Error> - where - D: serde::Deserializer<'de>, - { - #[derive(Deserialize)] - #[serde(transparent)] - struct Wrapper { - #[serde(deserialize_with = "SemanticToken::deserialize_tokens")] - tokens: Vec, - } - - Ok(Option::::deserialize(deserializer)?.map(|wrapper| wrapper.tokens)) - } - - fn serialize_tokens_opt( - data: &Option>, - serializer: S, - ) -> Result - where - S: serde::Serializer, - { - #[derive(Serialize)] - #[serde(transparent)] - struct Wrapper { - #[serde(serialize_with = "SemanticToken::serialize_tokens")] - tokens: Vec, - } - - let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() }); - - opt.serialize(serializer) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokens { - /// An optional result id. If provided and clients support delta updating - /// the client will include the result id in the next semantic token request. - /// A server can then instead of computing all sematic tokens again simply - /// send a delta. - #[serde(skip_serializing_if = "Option::is_none")] - pub result_id: Option, - - /// The actual tokens. For a detailed description about how the data is - /// structured please see - /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 - #[serde( - deserialize_with = "SemanticToken::deserialize_tokens", - serialize_with = "SemanticToken::serialize_tokens" - )] - pub data: Vec, -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensPartialResult { - #[serde( - deserialize_with = "SemanticToken::deserialize_tokens", - serialize_with = "SemanticToken::serialize_tokens" - )] - pub data: Vec, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensResult { - Tokens(SemanticTokens), - Partial(SemanticTokensPartialResult), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensResult { - fn from(from: SemanticTokens) -> Self { - SemanticTokensResult::Tokens(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensResult { - fn from(from: SemanticTokensPartialResult) -> Self { - SemanticTokensResult::Partial(from) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEdit { - pub start: u32, - pub delete_count: u32, - - #[serde( - default, - skip_serializing_if = "Option::is_none", - deserialize_with = "SemanticToken::deserialize_tokens_opt", - serialize_with = "SemanticToken::serialize_tokens_opt" - )] - pub data: Option>, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensEditResult { - Tokens(SemanticTokens), - TokensEdits(SemanticTokensEdits), - PartialTokens(SemanticTokensPartialResult), - PartialTokensEdit(SemanticTokensEditsPartialResult), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokens) -> Self { - SemanticTokensEditResult::Tokens(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokensEdits) -> Self { - SemanticTokensEditResult::TokensEdits(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokensPartialResult) -> Self { - SemanticTokensEditResult::PartialTokens(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensEditResult { - fn from(from: SemanticTokensEditsPartialResult) -> Self { - SemanticTokensEditResult::PartialTokensEdit(from) - } -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEdits { - #[serde(skip_serializing_if = "Option::is_none")] - pub result_id: Option, - /// For a detailed description how these edits are structured pls see - /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L131 - pub edits: Vec, -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEditsPartialResult { - pub edits: Vec, -} - -/// Capabilities specific to the `textDocument/semanticTokens` -/// -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensClientCapabilities { - /// Whether implementation supports dynamic registration. If this is set to `true` - /// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` - /// return value for the corresponding server capability as well. - #[serde(skip_serializing_if = "Option::is_none")] - pub dynamic_registration: Option, - - /// The token types known by the client. - pub token_types: Vec, - - /// The token modifiers known by the client. - pub token_modifiers: Vec, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensDocumentProvider { - Bool(bool), - - /// The server supports deltas for full documents. - Edits { - #[serde(skip_serializing_if = "Option::is_none")] - edits: Option, - }, -} - -/// @since 3.16.0 - Proposed state -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, - - /// The legend used by the server - pub legend: SemanticTokensLegend, - - /// Server supports providing semantic tokens for a sepcific range - /// of a document. - #[serde(skip_serializing_if = "Option::is_none")] - pub range_provider: Option, - - /// Server supports providing semantic tokens for a full document. - #[serde(skip_serializing_if = "Option::is_none")] - pub document_provider: Option, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensRegistrationOptions { - #[serde(flatten)] - pub text_document_registration_options: TextDocumentRegistrationOptions, - - #[serde(flatten)] - pub semantic_tokens_options: SemanticTokensOptions, - - #[serde(flatten)] - pub static_registration_options: StaticRegistrationOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensServerCapabilities { - SemanticTokensOptions(SemanticTokensOptions), - SemanticTokensRegistrationOptions(SemanticTokensRegistrationOptions), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensServerCapabilities { - fn from(from: SemanticTokensOptions) -> Self { - SemanticTokensServerCapabilities::SemanticTokensOptions(from) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensServerCapabilities { - fn from(from: SemanticTokensRegistrationOptions) -> Self { - SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensParams { - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - /// The text document. - pub text_document: TextDocumentIdentifier, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensEditsParams { - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The previous result id. - pub previous_result_id: String, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct SemanticTokensRangeParams { - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, - - /// The text document. - pub text_document: TextDocumentIdentifier, - - /// The range the semantic tokens are requested for. - pub range: Range, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum SemanticTokensRangeResult { - Tokens(SemanticTokens), - Partial(SemanticTokensPartialResult), -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensRangeResult { - fn from(tokens: SemanticTokens) -> Self { - SemanticTokensRangeResult::Tokens(tokens) - } -} - -#[cfg(feature = "proposed")] -impl From for SemanticTokensRangeResult { - fn from(partial: SemanticTokensPartialResult) -> Self { - SemanticTokensRangeResult::Partial(partial) - } -} - -/// Symbol tags are extra annotations that tweak the rendering of a symbol. -/// Since 3.15 -#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] -#[repr(u8)] -#[cfg(feature = "proposed")] -pub enum SymbolTag { - /// Render a symbol as obsolete, usually using a strike-out. - Deprecated = 1, -} - -#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyOptions { - #[serde(flatten)] - pub work_done_progress_options: WorkDoneProgressOptions, -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(untagged)] -#[cfg(feature = "proposed")] -pub enum CallHierarchyServerCapability { - Simple(bool), - Options(CallHierarchyOptions), -} - -#[cfg(feature = "proposed")] -impl From for CallHierarchyServerCapability { - fn from(from: CallHierarchyOptions) -> Self { - Self::Options(from) - } -} - -#[cfg(feature = "proposed")] -impl From for CallHierarchyServerCapability { - fn from(from: bool) -> Self { - Self::Simple(from) - } -} - -#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyPrepareParams { - #[serde(flatten)] - pub text_document_position_params: TextDocumentPositionParams, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, -} - -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyItem { - /// The name of this item. - pub name: String, - - /// The kind of this item. - pub kind: SymbolKind, - - /// Tags for this item. - #[serde(skip_serializing_if = "Option::is_none")] - pub tags: Option>, - - /// More detail for this item, e.g. the signature of a function. - #[serde(skip_serializing_if = "Option::is_none")] - pub detail: Option, - - /// The resource identifier of this item. - pub uri: Url, - - /// The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. - pub range: Range, - - /// The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. - /// Must be contained by the [`range`](#CallHierarchyItem.range). - pub selection_range: Range, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyIncomingCallsParams { - pub item: CallHierarchyItem, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents an incoming call, e.g. a caller of a method or constructor. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyIncomingCall { - /// The item that makes the call. - pub from: CallHierarchyItem, - - /// The range at which at which the calls appears. This is relative to the caller - /// denoted by [`this.from`](#CallHierarchyIncomingCall.from). - pub from_ranges: Vec, -} - -#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyOutgoingCallsParams { - pub item: CallHierarchyItem, - - #[serde(flatten)] - pub work_done_progress_params: WorkDoneProgressParams, - - #[serde(flatten)] - pub partial_result_params: PartialResultParams, -} - -/// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. -#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] -#[serde(rename_all = "camelCase")] -#[cfg(feature = "proposed")] -pub struct CallHierarchyOutgoingCall { - /// The item that is called. - pub to: CallHierarchyItem, - - /// The range at which this item is called. This is the range relative to the caller, e.g the item - /// passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls) - /// and not [`this.to`](#CallHierarchyOutgoingCall.to). - pub from_ranges: Vec, -} - -#[cfg(test)] -mod tests { - use super::*; - use serde::{Deserialize, Serialize}; - - fn test_serialization(ms: &SER, expected: &str) - where - SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, - { - let json_str = serde_json::to_string(ms).unwrap(); - assert_eq!(&json_str, expected); - let deserialized: SER = serde_json::from_str(&json_str).unwrap(); - assert_eq!(&deserialized, ms); - } - - fn test_deserialization(json: &str, expected: &T) - where - T: for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, - { - let value = serde_json::from_str::(json).unwrap(); - assert_eq!(&value, expected); - } - - #[test] - fn number_or_string() { - test_serialization(&NumberOrString::Number(123), r#"123"#); - - test_serialization(&NumberOrString::String("abcd".into()), r#""abcd""#); - } - - #[test] - fn marked_string() { - test_serialization(&MarkedString::from_markdown("xxx".into()), r#""xxx""#); - - test_serialization( - &MarkedString::from_language_code("lang".into(), "code".into()), - r#"{"language":"lang","value":"code"}"#, - ); - } - - #[test] - fn language_string() { - test_serialization( - &LanguageString { - language: "LL".into(), - value: "VV".into(), - }, - r#"{"language":"LL","value":"VV"}"#, - ); - } - - #[test] - fn workspace_edit() { - test_serialization( - &WorkspaceEdit { - changes: Some(vec![].into_iter().collect()), - document_changes: None, - }, - r#"{"changes":{}}"#, - ); - - test_serialization( - &WorkspaceEdit { - changes: None, - document_changes: None, - }, - r#"{}"#, - ); - - test_serialization( - &WorkspaceEdit { - changes: Some( - vec![(Url::parse("file://test").unwrap(), vec![])] - .into_iter() - .collect(), - ), - document_changes: None, - }, - r#"{"changes":{"file://test/":[]}}"#, - ); - } - - #[test] - fn formatting_options() { - test_serialization( - &FormattingOptions { - tab_size: 123, - insert_spaces: true, - properties: HashMap::new(), - trim_trailing_whitespace: None, - insert_final_newline: None, - trim_final_newlines: None, - }, - r#"{"tabSize":123,"insertSpaces":true}"#, - ); - - test_serialization( - &FormattingOptions { - tab_size: 123, - insert_spaces: true, - properties: vec![("prop".to_string(), FormattingProperty::Number(1.0))] - .into_iter() - .collect(), - trim_trailing_whitespace: None, - insert_final_newline: None, - trim_final_newlines: None, - }, - r#"{"tabSize":123,"insertSpaces":true,"prop":1.0}"#, - ); - } - - #[test] - fn root_uri_can_be_missing() { - serde_json::from_str::(r#"{ "capabilities": {} }"#).unwrap(); - } - - #[test] - fn test_watch_kind() { - test_serialization(&WatchKind::Create, "1"); - test_serialization(&(WatchKind::Create | WatchKind::Change), "3"); - test_serialization( - &(WatchKind::Create | WatchKind::Change | WatchKind::Delete), - "7", - ); - } - - #[test] - fn test_resource_operation_kind() { - test_serialization( - &vec![ - ResourceOperationKind::Create, - ResourceOperationKind::Rename, - ResourceOperationKind::Delete, - ], - r#"["create","rename","delete"]"#, - ); - } - - #[test] - fn test_code_action_response() { - test_serialization( - &vec![ - CodeActionOrCommand::Command(Command { - title: "title".to_string(), - command: "command".to_string(), - arguments: None, - }), - CodeActionOrCommand::CodeAction(CodeAction { - title: "title".to_string(), - kind: Some(CodeActionKind::QUICKFIX), - command: None, - diagnostics: None, - edit: None, - is_preferred: None, - }), - ], - r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#, - ) - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_highlighting_information_serialization() { - test_serialization( - &SemanticHighlightingInformation { - line: 10, - tokens: Some(vec![ - SemanticHighlightingToken { - character: 0x00000001, - length: 0x0002, - scope: 0x0003, - }, - SemanticHighlightingToken { - character: 0x00112222, - length: 0x0FF0, - scope: 0x0202, - }, - ]), - }, - r#"{"line":10,"tokens":"AAAAAQACAAMAESIiD/ACAg=="}"#, - ); - - test_serialization( - &SemanticHighlightingInformation { - line: 22, - tokens: None, - }, - r#"{"line":22}"#, - ); - } - - #[test] - fn test_tag_support_deserialization() { - let mut empty = CompletionItemCapability::default(); - empty.tag_support = None; - - test_deserialization(r#"{}"#, &empty); - test_deserialization(r#"{"tagSupport": false}"#, &empty); - - let mut t = CompletionItemCapability::default(); - t.tag_support = Some(TagSupport { value_set: vec![] }); - test_deserialization(r#"{"tagSupport": true}"#, &t); - - let mut t = CompletionItemCapability::default(); - t.tag_support = Some(TagSupport { - value_set: vec![CompletionItemTag::Deprecated], - }); - test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_support_serialization() { - test_serialization( - &SemanticTokens { - result_id: None, - data: vec![], - }, - r#"{"data":[]}"#, - ); - - test_serialization( - &SemanticTokens { - result_id: None, - data: vec![SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }], - }, - r#"{"data":[2,5,3,0,3]}"#, - ); - - test_serialization( - &SemanticTokens { - result_id: None, - data: vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ], - }, - r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, - ); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_support_deserialization() { - test_deserialization( - r#"{"data":[]}"#, - &SemanticTokens { - result_id: None, - data: vec![], - }, - ); - - test_deserialization( - r#"{"data":[2,5,3,0,3]}"#, - &SemanticTokens { - result_id: None, - data: vec![SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }], - }, - ); - - test_deserialization( - r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, - &SemanticTokens { - result_id: None, - data: vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ], - }, - ); - } - - #[cfg(feature = "proposed")] - #[test] - #[should_panic] - fn test_semantic_tokens_support_deserialization_err() { - test_deserialization( - r#"{"data":[1]}"#, - &SemanticTokens { - result_id: None, - data: vec![], - }, - ); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_edit_support_deserialization() { - test_deserialization( - r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: Some(vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ]), - }, - ); - - test_deserialization( - r#"{"start":0,"deleteCount":1}"#, - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: None, - }, - ); - } - - #[cfg(feature = "proposed")] - #[test] - fn test_semantic_tokens_edit_support_serialization() { - test_serialization( - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: Some(vec![ - SemanticToken { - delta_line: 2, - delta_start: 5, - length: 3, - token_type: 0, - token_modifiers_bitset: 3, - }, - SemanticToken { - delta_line: 0, - delta_start: 5, - length: 4, - token_type: 1, - token_modifiers_bitset: 0, - }, - ]), - }, - r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, - ); - - test_serialization( - &SemanticTokensEdit { - start: 0, - delete_count: 1, - data: None, - }, - r#"{"start":0,"deleteCount":1}"#, - ); - } -} +/*! + +Language Server Protocol types for Rust. + +Based on: + +This library uses the URL crate for parsing URIs. Note that there is +some confusion on the meaning of URLs vs URIs: +. According to that +information, on the classical sense of "URLs", "URLs" are a subset of +URIs, But on the modern/new meaning of URLs, they are the same as +URIs. The important take-away aspect is that the URL crate should be +able to parse any URI, such as `urn:isbn:0451450523`. + + +*/ +#![allow(non_upper_case_globals)] +#![forbid(unsafe_code)] + +#[macro_use] +extern crate bitflags; + +use serde::{Deserialize, Serialize}; +use serde_json; +use serde_repr::{Deserialize_repr, Serialize_repr}; + +pub use url::Url; + +use std::borrow::Cow; + +#[cfg(feature = "proposed")] +use std::convert::TryFrom; + +use std::collections::HashMap; + +#[cfg(feature = "proposed")] +use base64; +use serde::de; +use serde::de::Error as Error_; +use serde_json::Value; + +#[cfg(feature = "proposed")] +use serde::ser::SerializeSeq; + +pub mod notification; +pub mod request; + +/* ----------------- Auxiliary types ----------------- */ + +#[derive(Debug, Eq, Hash, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum NumberOrString { + Number(u64), + String(String), +} + +/* ----------------- Cancel support ----------------- */ + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct CancelParams { + /// The request id to cancel. + pub id: NumberOrString, +} + +/* ----------------- Basic JSON Structures ----------------- */ + +/// Position in a text document expressed as zero-based line and character offset. +/// A position is between two characters like an 'insert' cursor in a editor. +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Copy, Clone, Default, Deserialize, Serialize)] +pub struct Position { + /// Line position in a document (zero-based). + pub line: u64, + /// Character offset on a line in a document (zero-based). + pub character: u64, +} + +impl Position { + pub fn new(line: u64, character: u64) -> Position { + Position { line, character } + } +} + +/// A range in a text document expressed as (zero-based) start and end positions. +/// A range is comparable to a selection in an editor. Therefore the end position is exclusive. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Default, Deserialize, Serialize)] +pub struct Range { + /// The range's start position. + pub start: Position, + /// The range's end position. + pub end: Position, +} + +impl Range { + pub fn new(start: Position, end: Position) -> Range { + Range { start, end } + } +} + +/// Represents a location inside a resource, such as a line inside a text file. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Location { + pub uri: Url, + pub range: Range, +} + +impl Location { + pub fn new(uri: Url, range: Range) -> Location { + Location { uri, range } + } +} + +/// Represents a link between a source and a target location. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct LocationLink { + /// Span of the origin of this link. + /// + /// Used as the underlined span for mouse interaction. Defaults to the word range at + /// the mouse position. + #[serde(skip_serializing_if = "Option::is_none")] + pub origin_selection_range: Option, + + /// The target resource identifier of this link. + pub target_uri: Url, + + /// The full target range of this link. + pub target_range: Range, + + /// The span of this link. + pub target_selection_range: Range, +} + +/// Represents a diagnostic, such as a compiler error or warning. +/// Diagnostic objects are only valid in the scope of a resource. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Diagnostic { + /// The range at which the message applies. + pub range: Range, + + /// The diagnostic's severity. Can be omitted. If omitted it is up to the + /// client to interpret diagnostics as error, warning, info or hint. + #[serde(skip_serializing_if = "Option::is_none")] + pub severity: Option, + + /// The diagnostic's code. Can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub code: Option, + // code?: number | string; + /// A human-readable string describing the source of this + /// diagnostic, e.g. 'typescript' or 'super lint'. + #[serde(skip_serializing_if = "Option::is_none")] + pub source: Option, + + /// The diagnostic's message. + pub message: String, + + /// An array of related diagnostic information, e.g. when symbol-names within + /// a scope collide all definitions can be marked via this property. + #[serde(skip_serializing_if = "Option::is_none")] + pub related_information: Option>, + + /// Additional metadata about the diagnostic. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, +} + +impl Diagnostic { + pub fn new( + range: Range, + severity: Option, + code: Option, + source: Option, + message: String, + related_information: Option>, + tags: Option>, + ) -> Diagnostic { + Diagnostic { + range, + severity, + code, + source, + message, + related_information, + tags, + } + } + + pub fn new_simple(range: Range, message: String) -> Diagnostic { + Self::new(range, None, None, None, message, None, None) + } + + pub fn new_with_code_number( + range: Range, + severity: DiagnosticSeverity, + code_number: u64, + source: Option, + message: String, + ) -> Diagnostic { + let code = Some(NumberOrString::Number(code_number)); + Self::new(range, Some(severity), code, source, message, None, None) + } +} + +/// The protocol currently supports the following diagnostic severities: +#[derive(Debug, Eq, PartialEq, Ord, PartialOrd, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum DiagnosticSeverity { + /// Reports an error. + Error = 1, + /// Reports a warning. + Warning = 2, + /// Reports an information. + Information = 3, + /// Reports a hint. + Hint = 4, +} + +/// Represents a related message and source code location for a diagnostic. This +/// should be used to point to code locations that cause or related to a +/// diagnostics, e.g when duplicating a symbol in a scope. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DiagnosticRelatedInformation { + /// The location of this related diagnostic information. + pub location: Location, + + /// The message of this related diagnostic information. + pub message: String, +} + +/// The diagnostic tags. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum DiagnosticTag { + /// Unused or unnecessary code. + /// Clients are allowed to render diagnostics with this tag faded out instead of having + /// an error squiggle. + Unnecessary = 1, + + /// Deprecated or obsolete code. + /// Clients are allowed to rendered diagnostics with this tag strike through. + Deprecated = 2, +} + +/// Represents a reference to a command. Provides a title which will be used to represent a command in the UI. +/// Commands are identitifed using a string identifier and the protocol currently doesn't specify a set of +/// well known commands. So executing a command requires some tool extension code. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct Command { + /// Title of the command, like `save`. + pub title: String, + /// The identifier of the actual command handler. + pub command: String, + /// Arguments that the command handler should be + /// invoked with. + #[serde(skip_serializing_if = "Option::is_none")] + pub arguments: Option>, +} + +impl Command { + pub fn new(title: String, command: String, arguments: Option>) -> Command { + Command { + title, + command, + arguments, + } + } +} + +/// A textual edit applicable to a text document. +/// +/// If n `TextEdit`s are applied to a text document all text edits describe changes to the initial document version. +/// Execution wise text edits should applied from the bottom to the top of the text document. Overlapping text edits +/// are not supported. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextEdit { + /// The range of the text document to be manipulated. To insert + /// text into a document create a range where start === end. + pub range: Range, + /// The string to be inserted. For delete operations use an + /// empty string. + pub new_text: String, +} + +impl TextEdit { + pub fn new(range: Range, new_text: String) -> TextEdit { + TextEdit { range, new_text } + } +} + +/// Describes textual changes on a single text document. The text document is referred to as a +/// `VersionedTextDocumentIdentifier` to allow clients to check the text document version before an +/// edit is applied. A `TextDocumentEdit` describes all changes on a version Si and after they are +/// applied move the document to version Si+1. So the creator of a `TextDocumentEdit` doesn't need to +/// sort the array or do any kind of ordering. However the edits must be non overlapping. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentEdit { + /// The text document to change. + pub text_document: VersionedTextDocumentIdentifier, + + /// The edits to be applied. + pub edits: Vec, +} + +/// A special text edit to provide an insert and a replace operation. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct InsertReplaceEdit { + /// The string to be inserted. + pub new_text: String, + + /// The range if the insert is requested + pub insert: Range, + + /// The range if the replace is requested. + pub replace: Range, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CompletionTextEdit { + Edit(TextEdit), + #[cfg(feature = "proposed")] + InsertAndReplace(InsertReplaceEdit), +} + +impl From for CompletionTextEdit { + fn from(edit: TextEdit) -> Self { + CompletionTextEdit::Edit(edit) + } +} + +#[cfg(feature = "proposed")] +impl From for CompletionTextEdit { + fn from(edit: InsertReplaceEdit) -> Self { + CompletionTextEdit::InsertAndReplace(edit) + } +} + +/// Options to create a file. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateFileOptions { + /// Overwrite existing file. Overwrite wins over `ignoreIfExists` + #[serde(skip_serializing_if = "Option::is_none")] + pub overwrite: Option, + /// Ignore if exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_exists: Option, +} + +/// Create file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CreateFile { + /// The resource to create. + pub uri: Url, + /// Additional options + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// Rename file options +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameFileOptions { + /// Overwrite target if existing. Overwrite wins over `ignoreIfExists` + #[serde(skip_serializing_if = "Option::is_none")] + pub overwrite: Option, + /// Ignores if target exists. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_exists: Option, +} + +/// Rename file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameFile { + /// The old (existing) location. + pub old_uri: Url, + /// The new location. + pub new_uri: Url, + /// Rename options. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// Delete file options +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeleteFileOptions { + /// Delete the content recursively if a folder is denoted. + #[serde(skip_serializing_if = "Option::is_none")] + pub recursive: Option, + /// Ignore the operation if the file doesn't exist. + #[serde(skip_serializing_if = "Option::is_none")] + pub ignore_if_not_exists: Option, +} + +/// Delete file operation +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DeleteFile { + /// The file to delete. + pub uri: Url, + /// Delete options. + #[serde(skip_serializing_if = "Option::is_none")] + pub options: Option, +} + +/// A workspace edit represents changes to many resources managed in the workspace. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceEdit { + /// Holds changes to existing resources. + #[serde(with = "url_map")] + #[serde(skip_serializing_if = "Option::is_none")] + #[serde(default)] + pub changes: Option>>, // changes?: { [uri: string]: TextEdit[]; }; + + /// Depending on the client capability `workspace.workspaceEdit.resourceOperations` document changes + /// are either an array of `TextDocumentEdit`s to express changes to n different text documents + /// where each text document edit addresses a specific version of a text document. Or it can contain + /// above `TextDocumentEdit`s mixed with create, rename and delete file / folder operations. + /// + /// Whether a client supports versioned document edits is expressed via + /// `workspace.workspaceEdit.documentChanges` client capability. + /// + /// If a client neither supports `documentChanges` nor `workspace.workspaceEdit.resourceOperations` then + /// only plain `TextEdit`s using the `changes` property are supported. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_changes: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum DocumentChanges { + Edits(Vec), + Operations(Vec), +} + +// TODO: Once https://github.com/serde-rs/serde/issues/912 is solved +// we can remove ResourceOp and switch to the following implementation +// of DocumentChangeOperation: +// +// #[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +// #[serde(tag = "kind", rename_all="lowercase" )] +// pub enum DocumentChangeOperation { +// Create(CreateFile), +// Rename(RenameFile), +// Delete(DeleteFile), +// +// #[serde(other)] +// Edit(TextDocumentEdit), +// } + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged, rename_all = "lowercase")] +pub enum DocumentChangeOperation { + Op(ResourceOp), + Edit(TextDocumentEdit), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum ResourceOp { + Create(CreateFile), + Rename(RenameFile), + Delete(DeleteFile), +} + +#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfigurationParams { + pub items: Vec, +} + +#[derive(Debug, Default, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ConfigurationItem { + /// The scope to get the configuration section for. + #[serde(skip_serializing_if = "Option::is_none")] + pub scope_uri: Option, + + ///The configuration section asked for. + #[serde(skip_serializing_if = "Option::is_none")] + pub section: Option, +} + +mod url_map { + use super::*; + + use std::fmt; + + pub fn deserialize<'de, D>( + deserializer: D, + ) -> Result>>, D::Error> + where + D: serde::Deserializer<'de>, + { + struct UrlMapVisitor; + impl<'de> de::Visitor<'de> for UrlMapVisitor { + type Value = HashMap>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("map") + } + + fn visit_map(self, mut visitor: M) -> Result + where + M: de::MapAccess<'de>, + { + let mut values = HashMap::with_capacity(visitor.size_hint().unwrap_or(0)); + + // While there are entries remaining in the input, add them + // into our map. + while let Some((key, value)) = visitor.next_entry::()? { + values.insert(key, value); + } + + Ok(values) + } + } + + struct OptionUrlMapVisitor; + impl<'de> de::Visitor<'de> for OptionUrlMapVisitor { + type Value = Option>>; + + fn expecting(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.write_str("option") + } + + #[inline] + fn visit_unit(self) -> Result + where + E: serde::de::Error, + { + Ok(None) + } + + #[inline] + fn visit_none(self) -> Result + where + E: serde::de::Error, + { + Ok(None) + } + + #[inline] + fn visit_some(self, deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + deserializer.deserialize_map(UrlMapVisitor).map(Some) + } + } + + // Instantiate our Visitor and ask the Deserializer to drive + // it over the input data, resulting in an instance of MyMap. + deserializer.deserialize_option(OptionUrlMapVisitor) + } + + pub fn serialize( + changes: &Option>>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + use serde::ser::SerializeMap; + + match *changes { + Some(ref changes) => { + let mut map = serializer.serialize_map(Some(changes.len()))?; + for (k, v) in changes { + map.serialize_entry(k.as_str(), v)?; + } + map.end() + } + None => serializer.serialize_none(), + } + } +} + +impl WorkspaceEdit { + pub fn new(changes: HashMap>) -> WorkspaceEdit { + WorkspaceEdit { + changes: Some(changes), + document_changes: None, + } + } +} + +/// Text documents are identified using a URI. On the protocol level, URIs are passed as strings. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct TextDocumentIdentifier { + // !!!!!! Note: + // In the spec VersionedTextDocumentIdentifier extends TextDocumentIdentifier + // This modelled by "mixing-in" TextDocumentIdentifier in VersionedTextDocumentIdentifier, + // so any changes to this type must be effected in the sub-type as well. + /// The text document's URI. + pub uri: Url, +} + +impl TextDocumentIdentifier { + pub fn new(uri: Url) -> TextDocumentIdentifier { + TextDocumentIdentifier { uri } + } +} + +/// An item to transfer a text document from the client to the server. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentItem { + /// The text document's URI. + pub uri: Url, + + /// The text document's language identifier. + pub language_id: String, + + /// The version number of this document (it will strictly increase after each + /// change, including undo/redo). + pub version: i64, + + /// The content of the opened text document. + pub text: String, +} + +impl TextDocumentItem { + pub fn new(uri: Url, language_id: String, version: i64, text: String) -> TextDocumentItem { + TextDocumentItem { + uri, + language_id, + version, + text, + } + } +} + +/// An identifier to denote a specific version of a text document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct VersionedTextDocumentIdentifier { + // This field was "mixed-in" from TextDocumentIdentifier + /// The text document's URI. + pub uri: Url, + + /// The version number of this document. + pub version: Option, +} + +impl VersionedTextDocumentIdentifier { + pub fn new(uri: Url, version: i64) -> VersionedTextDocumentIdentifier { + VersionedTextDocumentIdentifier { + uri, + version: Some(version), + } + } +} + +/// A parameter literal used in requests to pass a text document and a position inside that document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentPositionParams { + // !!!!!! Note: + // In the spec ReferenceParams extends TextDocumentPositionParams + // This modelled by "mixing-in" TextDocumentPositionParams in ReferenceParams, + // so any changes to this type must be effected in sub-type as well. + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The position inside the text document. + pub position: Position, +} + +impl TextDocumentPositionParams { + pub fn new( + text_document: TextDocumentIdentifier, + position: Position, + ) -> TextDocumentPositionParams { + TextDocumentPositionParams { + text_document, + position, + } + } +} + +/// A document filter denotes a document through properties like language, schema or pattern. +/// Examples are a filter that applies to TypeScript files on disk or a filter the applies to JSON +/// files with name package.json: +/// +/// { language: 'typescript', scheme: 'file' } +/// { language: 'json', pattern: '**/package.json' } +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentFilter { + /// A language id, like `typescript`. + #[serde(skip_serializing_if = "Option::is_none")] + pub language: Option, + + /// A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + #[serde(skip_serializing_if = "Option::is_none")] + pub scheme: Option, + + /// A glob pattern, like `*.{ts,js}`. + #[serde(skip_serializing_if = "Option::is_none")] + pub pattern: Option, +} + +/// A document selector is the combination of one or many document filters. +pub type DocumentSelector = Vec; + +// ========================= Actual Protocol ========================= + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InitializeParams { + /// The process Id of the parent process that started + /// the server. Is null if the process has not been started by another process. + /// If the parent process is not alive then the server should exit (see exit notification) its process. + pub process_id: Option, + + /// The rootPath of the workspace. Is null + /// if no folder is open. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use `root_uri` instead when possible")] + pub root_path: Option, + + /// The rootUri of the workspace. Is null if no + /// folder is open. If both `rootPath` and `rootUri` are set + /// `rootUri` wins. + #[serde(default)] + pub root_uri: Option, + + /// User provided initialization options. + #[serde(skip_serializing_if = "Option::is_none")] + pub initialization_options: Option, + + /// The capabilities provided by the client (editor) + pub capabilities: ClientCapabilities, + + /// The initial trace setting. If omitted trace is disabled ('off'). + #[serde(default)] + #[serde(skip_serializing_if = "Option::is_none")] + pub trace: Option, + + /// The workspace folders configured in the client when the server starts. + /// This property is only available if the client supports workspace folders. + /// It can be `null` if the client supports workspace folders but none are + /// configured. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option>, + + /// Information about the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub client_info: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct ClientInfo { + /// The name of the client as defined by the client. + pub name: String, + /// The client's version as defined by the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, PartialEq, Clone, Copy, Deserialize, Serialize)] +pub struct InitializedParams {} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +pub enum TraceOption { + #[serde(rename = "off")] + Off, + #[serde(rename = "messages")] + Messages, + #[serde(rename = "verbose")] + Verbose, +} + +impl Default for TraceOption { + fn default() -> TraceOption { + TraceOption::Off + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub options: GenericOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct GenericParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GenericCapability { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GotoCapability { + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports additional metadata in the form of definition links. + pub link_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceEditCapability { + /// The client supports versioned document changes in `WorkspaceEdit`s + #[serde(skip_serializing_if = "Option::is_none")] + pub document_changes: Option, + + /// The resource operations the client supports. Clients should at least + /// support 'create', 'rename' and 'delete' files and folders. + #[serde(skip_serializing_if = "Option::is_none")] + pub resource_operations: Option>, + + /// The failure handling strategy of a client if applying the workspace edit + /// failes. + #[serde(skip_serializing_if = "Option::is_none")] + pub failure_handling: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceCapability { + /// The server supports workspace folder. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFolderCapability { + #[serde(skip_serializing_if = "Option::is_none")] + pub supported: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub change_notifications: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum WorkspaceFolderCapabilityChangeNotifications { + Bool(bool), + Id(String), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFolder { + /// The associated URI for this workspace folder. + pub uri: Url, + /// The name of the workspace folder. Defaults to the uri's basename. + pub name: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidChangeWorkspaceFoldersParams { + /// The actual workspace folder change event. + pub event: WorkspaceFoldersChangeEvent, +} + +/// The workspace folder change event. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceFoldersChangeEvent { + /// The array of added workspace folders + pub added: Vec, + + /// The array of the removed workspace folders + pub removed: Vec, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "lowercase")] +pub enum ResourceOperationKind { + Create, + Rename, + Delete, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Copy, Clone)] +#[serde(rename_all = "camelCase")] +pub enum FailureHandlingKind { + Abort, + Transactional, + TextOnlyTransactional, + Undo, +} + +/// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SymbolKindCapability { + /// The symbol kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// If this property is not present the client only supports + /// the symbol kinds from `File` to `Array` as defined in + /// the initial version of the protocol. + pub value_set: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceSymbolClientCapabilities { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol_kind: Option, + + /// The client supports tags on `SymbolInformation`. + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// @since 3.16.0 + /// + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + #[cfg(feature = "proposed")] + pub tag_support: Option>, +} + +/// Workspace specific client capabilities. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WorkspaceClientCapabilities { + /// The client supports applying batch edits to the workspace by supporting + /// the request 'workspace/applyEdit' + #[serde(skip_serializing_if = "Option::is_none")] + pub apply_edit: Option, + + /// Capabilities specific to `WorkspaceEdit`s + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_edit: Option, + + /// Capabilities specific to the `workspace/didChangeConfiguration` notification. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_change_configuration: Option, + + /// Capabilities specific to the `workspace/didChangeWatchedFiles` notification. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_change_watched_files: Option, + + /// Capabilities specific to the `workspace/symbol` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol: Option, + + /// Capabilities specific to the `workspace/executeCommand` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub execute_command: Option, + + /// The client has support for workspace folders. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_folders: Option, + + /// The client supports `workspace/configuration` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub configuration: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SynchronizationCapability { + /// Whether text document synchronization supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports sending will save notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save: Option, + + /// The client supports sending a will save request and + /// waits for a response providing text edits which will + /// be applied to the document before it is saved. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save_wait_until: Option, + + /// The client supports did save notifications. + #[serde(skip_serializing_if = "Option::is_none")] + pub did_save: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemCapability { + /// Client supports snippets as insert text. + /// + /// A snippet can define tab stops and placeholders with `$1`, `$2` + /// and `${3:foo}`. `$0` defines the final tab stop, it defaults to + /// the end of the snippet. Placeholders with equal identifiers are linked, + /// that is typing in one will update others too. + #[serde(skip_serializing_if = "Option::is_none")] + pub snippet_support: Option, + + /// Client supports commit characters on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub commit_characters_support: Option, + + /// Client supports the follow content formats for the documentation + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_format: Option>, + + /// Client supports the deprecated property on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated_support: Option, + + /// Client supports the preselect property on a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub preselect_support: Option, + + /// Client supports the tag property on a completion item. Clients supporting + /// tags have to handle unknown tags gracefully. Clients especially need to + /// preserve unknown tags when sending a completion item back to the server in + /// a resolve call. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, + + /// Client support insert replace edit to control different behavior if a + /// completion item is inserted in the text or should replace text. + /// + /// @since 3.16.0 - Proposed state + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub insert_replace_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum CompletionItemTag { + Deprecated = 1, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItemKindCapability { + /// The completion item kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + /// + /// If this property is not present the client only supports + /// the completion items kinds from `Text` to `Reference` as defined in + /// the initial version of the protocol. + #[serde(skip_serializing_if = "Option::is_none")] + pub value_set: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverCapability { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Client supports the follow content formats for the content + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub content_format: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionCapability { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports the following `CompletionItem` specific + /// capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_item: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_item_kind: Option, + + /// The client supports to send additional context information for a + /// `textDocument/completion` requestion. + #[serde(skip_serializing_if = "Option::is_none")] + pub context_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureInformationSettings { + /// Client supports the follow content formats for the documentation + /// property. The order describes the preferred format of the client. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation_format: Option>, + + #[serde(skip_serializing_if = "Option::is_none")] + pub parameter_information: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ParameterInformationSettings { + /// The client supports processing label offsets instead of a + /// simple label string. + #[serde(skip_serializing_if = "Option::is_none")] + pub label_offset_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpCapability { + /// Whether completion supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client supports the following `SignatureInformation` + /// specific properties. + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_information: Option, + + /// The client supports to send additional context information for a + /// `textDocument/signatureHelp` request. A client that opts into + /// contextSupport will also support the `retriggerCharacters` on + /// `SignatureHelpOptions`. + #[serde(skip_serializing_if = "Option::is_none")] + pub context_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct PublishDiagnosticsCapability { + /// Whether the clients accepts diagnostics with related information. + #[serde(skip_serializing_if = "Option::is_none")] + pub related_information: Option, + + /// Client supports the tag property to provide meta data about a diagnostic. + /// Clients supporting tags have to handle unknown tags gracefully. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + pub tag_support: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TagSupport { + /// The tags supported by the client. + pub value_set: Vec, +} + +impl TagSupport { + /// Support for deserializing a boolean tag Support, in case it's present. + /// + /// This is currently the case for vscode 1.41.1 + fn deserialize_compat<'de, S>(serializer: S) -> Result>, S::Error> + where + S: serde::Deserializer<'de>, + T: serde::Deserialize<'de>, + { + Ok( + match Option::::deserialize(serializer).map_err(serde::de::Error::custom)? { + Some(Value::Bool(false)) => None, + Some(Value::Bool(true)) => Some(TagSupport { value_set: vec![] }), + Some(other) => { + Some(TagSupport::::deserialize(other).map_err(serde::de::Error::custom)?) + } + None => None, + }, + ) + } +} + +/// Text document specific client capabilities. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentClientCapabilities { + #[serde(skip_serializing_if = "Option::is_none")] + pub synchronization: Option, + /// Capabilities specific to the `textDocument/completion` + #[serde(skip_serializing_if = "Option::is_none")] + pub completion: Option, + + /// Capabilities specific to the `textDocument/hover` + #[serde(skip_serializing_if = "Option::is_none")] + pub hover: Option, + + /// Capabilities specific to the `textDocument/signatureHelp` + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_help: Option, + + /// Capabilities specific to the `textDocument/references` + #[serde(skip_serializing_if = "Option::is_none")] + pub references: Option, + + /// Capabilities specific to the `textDocument/documentHighlight` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_highlight: Option, + + /// Capabilities specific to the `textDocument/documentSymbol` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_symbol: Option, + /// Capabilities specific to the `textDocument/formatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub formatting: Option, + + /// Capabilities specific to the `textDocument/rangeFormatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub range_formatting: Option, + + /// Capabilities specific to the `textDocument/onTypeFormatting` + #[serde(skip_serializing_if = "Option::is_none")] + pub on_type_formatting: Option, + + /// Capabilities specific to the `textDocument/declaration` + #[serde(skip_serializing_if = "Option::is_none")] + pub declaration: Option, + + /// Capabilities specific to the `textDocument/definition` + #[serde(skip_serializing_if = "Option::is_none")] + pub definition: Option, + + /// Capabilities specific to the `textDocument/typeDefinition` + #[serde(skip_serializing_if = "Option::is_none")] + pub type_definition: Option, + + /// Capabilities specific to the `textDocument/implementation` + #[serde(skip_serializing_if = "Option::is_none")] + pub implementation: Option, + + /// Capabilities specific to the `textDocument/codeAction` + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action: Option, + + /// Capabilities specific to the `textDocument/codeLens` + #[serde(skip_serializing_if = "Option::is_none")] + pub code_lens: Option, + + /// Capabilities specific to the `textDocument/documentLink` + #[serde(skip_serializing_if = "Option::is_none")] + pub document_link: Option, + + /// Capabilities specific to the `textDocument/documentColor` and the + /// `textDocument/colorPresentation` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub color_provider: Option, + + /// Capabilities specific to the `textDocument/rename` + #[serde(skip_serializing_if = "Option::is_none")] + pub rename: Option, + + /// Capabilities specific to `textDocument/publishDiagnostics`. + #[serde(skip_serializing_if = "Option::is_none")] + pub publish_diagnostics: Option, + + /// Capabilities specific to `textDocument/foldingRange` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range: Option, + + /// The client's semantic highlighting capability. + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub semantic_highlighting_capabilities: Option, + + /// Capabilities specific to the `textDocument/semanticTokens/*` requests. + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub semantic_tokens: Option, +} + +/// Window specific client capabilities. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WindowClientCapabilities { + /// Whether client supports create a work done progress UI from the server side. + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option, +} + +/// Where ClientCapabilities are currently empty: +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ClientCapabilities { + /// Workspace specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace: Option, + + /// Text document specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_document: Option, + + /// Window specific client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub window: Option, + + /// Experimental client capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub experimental: Option, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct InitializeResult { + /// The capabilities the language server provides. + pub capabilities: ServerCapabilities, + + /// The capabilities the language server provides. + #[serde(skip_serializing_if = "Option::is_none")] + pub server_info: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ServerInfo { + /// The name of the server as defined by the server. + pub name: String, + /// The servers's version as defined by the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct InitializeError { + /// Indicates whether the client should retry to send the + /// initilize request after showing the message provided + /// in the ResponseError. + pub retry: bool, +} + +// The server can signal the following capabilities: + +/// Defines how the host (editor) should sync document changes to the language server. +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum TextDocumentSyncKind { + /// Documents should not be synced at all. + None = 0, + + /// Documents are synced by always sending the full content of the document. + Full = 1, + + /// Documents are synced by sending the full content on open. After that only + /// incremental updates to the document are sent. + Incremental = 2, +} + +/// Completion options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionOptions { + /// The server provides support to resolve additional information for a completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, + + /// The characters that trigger completion automatically. + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_characters: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Hover options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub hover_options: HoverOptions, +} + +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpOptions { + /// The characters that trigger signature help automatically. + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_characters: Option>, + + /// List of characters that re-trigger signature help. + /// These trigger characters are only active when signature help is already showing. All trigger characters + /// are also counted as re-trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub retrigger_characters: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SignatureHelpRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, +} +/// Signature help options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum SignatureHelpTriggerKind { + /// Signature help was invoked manually by the user or by a command. + Invoked = 1, + /// Signature help was triggered by a trigger character. + TriggerCharacter = 2, + /// Signature help was triggered by the cursor moving or by the document content changing. + ContentChange = 3, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpParams { + /// The signature help context. This is only available if the client specifies + /// to send this using the client capability `textDocument.signatureHelp.contextSupport === true` + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, + + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelpContext { + /// Action that caused signature help to be triggered. + pub trigger_kind: SignatureHelpTriggerKind, + + /// Character that caused signature help to be triggered. + /// This is undefined when `triggerKind !== SignatureHelpTriggerKind.TriggerCharacter` + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_character: Option, + + /// `true` if signature help was already showing when it was triggered. + /// Retriggers occur when the signature help is already active and can be caused by actions such as + /// typing a trigger character, a cursor move, or document content changes. + pub is_retrigger: bool, + + /// The currently active `SignatureHelp`. + /// The `activeSignatureHelp` has its `SignatureHelp.activeSignature` field updated based on + /// the user navigating through available signatures. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_signature_help: Option, +} + +/// Code Lens options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeLensOptions { + /// Code lens has a resolve provider as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, +} + +/// Format document on type options +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingOptions { + /// A character on which formatting should be triggered, like `}`. + pub first_trigger_character: String, + + /// More trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub more_trigger_character: Option>, +} + +/// Execute command options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ExecuteCommandOptions { + /// The commands to be executed on the server + pub commands: Vec, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +/// Save options. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SaveOptions { + /// The client is supposed to include the content on save. + #[serde(skip_serializing_if = "Option::is_none")] + pub include_text: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TextDocumentSyncSaveOptions { + Supported(bool), + SaveOptions(SaveOptions), +} + +impl From for TextDocumentSyncSaveOptions { + fn from(from: SaveOptions) -> Self { + Self::SaveOptions(from) + } +} + +impl From for TextDocumentSyncSaveOptions { + fn from(from: bool) -> Self { + Self::Supported(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentSyncOptions { + /// Open and close notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub open_close: Option, + + /// Change notifications are sent to the server. See TextDocumentSyncKind.None, TextDocumentSyncKind.Full + /// and TextDocumentSyncKindIncremental. + #[serde(skip_serializing_if = "Option::is_none")] + pub change: Option, + + /// Will save notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save: Option, + + /// Will save wait until requests are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub will_save_wait_until: Option, + + /// Save notifications are sent to the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub save: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TextDocumentSyncCapability { + Kind(TextDocumentSyncKind), + Options(TextDocumentSyncOptions), +} + +impl From for TextDocumentSyncCapability { + fn from(from: TextDocumentSyncOptions) -> Self { + Self::Options(from) + } +} + +impl From for TextDocumentSyncCapability { + fn from(from: TextDocumentSyncKind) -> Self { + Self::Kind(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ImplementationProviderCapability { + Simple(bool), + Options(StaticTextDocumentRegistrationOptions), +} + +impl From for ImplementationProviderCapability { + fn from(from: StaticTextDocumentRegistrationOptions) -> Self { + Self::Options(from) + } +} + +impl From for ImplementationProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum TypeDefinitionProviderCapability { + Simple(bool), + Options(StaticTextDocumentRegistrationOptions), +} + +impl From for TypeDefinitionProviderCapability { + fn from(from: StaticTextDocumentRegistrationOptions) -> Self { + Self::Options(from) + } +} + +impl From for TypeDefinitionProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum HoverProviderCapability { + Simple(bool), + Options(HoverOptions), +} + +impl From for HoverProviderCapability { + fn from(from: HoverOptions) -> Self { + Self::Options(from) + } +} + +impl From for HoverProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ColorProviderCapability { + Simple(bool), + ColorProvider(ColorProviderOptions), + Options(StaticTextDocumentColorProviderOptions), +} + +impl From for ColorProviderCapability { + fn from(from: ColorProviderOptions) -> Self { + Self::ColorProvider(from) + } +} + +impl From for ColorProviderCapability { + fn from(from: StaticTextDocumentColorProviderOptions) -> Self { + Self::Options(from) + } +} + +impl From for ColorProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CodeActionProviderCapability { + Simple(bool), + Options(CodeActionOptions), +} + +impl From for CodeActionProviderCapability { + fn from(from: CodeActionOptions) -> Self { + Self::Options(from) + } +} + +impl From for CodeActionProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionCapability { + /// + /// This capability supports dynamic registration. + /// + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The client support code action literals as a valid + /// response of the `textDocument/codeAction` request. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_literal_support: Option, + + /// Whether code action supports the `isPreferred` property. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_preferred_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionLiteralSupport { + /// The code action kind is support with the following value set. + pub code_action_kind: CodeActionKindLiteralSupport, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionKindLiteralSupport { + /// The code action kind values the client supports. When this + /// property exists the client also guarantees that it will + /// handle values outside its set gracefully and falls back + /// to a default value when unknown. + pub value_set: Vec, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ServerCapabilities { + /// Defines how text documents are synced. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_document_sync: Option, + + /// Capabilities specific to `textDocument/selectionRange` requests. + #[serde(skip_serializing_if = "Option::is_none")] + pub selection_range_provider: Option, + + /// The server provides hover support. + #[serde(skip_serializing_if = "Option::is_none")] + pub hover_provider: Option, + + /// The server provides completion support. + #[serde(skip_serializing_if = "Option::is_none")] + pub completion_provider: Option, + + /// The server provides signature help support. + #[serde(skip_serializing_if = "Option::is_none")] + pub signature_help_provider: Option, + + /// The server provides goto definition support. + #[serde(skip_serializing_if = "Option::is_none")] + pub definition_provider: Option, + + /// The server provides goto type definition support. + #[serde(skip_serializing_if = "Option::is_none")] + pub type_definition_provider: Option, + + /// the server provides goto implementation support. + #[serde(skip_serializing_if = "Option::is_none")] + pub implementation_provider: Option, + + /// The server provides find references support. + #[serde(skip_serializing_if = "Option::is_none")] + pub references_provider: Option, + + /// The server provides document highlight support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_highlight_provider: Option, + + /// The server provides document symbol support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_symbol_provider: Option, + + /// The server provides workspace symbol support. + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace_symbol_provider: Option, + + /// The server provides code actions. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_provider: Option, + + /// The server provides code lens. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_lens_provider: Option, + + /// The server provides document formatting. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_formatting_provider: Option, + + /// The server provides document range formatting. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_range_formatting_provider: Option, + + /// The server provides document formatting on typing. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_on_type_formatting_provider: Option, + + /// The server provides rename support. + #[serde(skip_serializing_if = "Option::is_none")] + pub rename_provider: Option, + + /// The server provides document link support. + #[serde(skip_serializing_if = "Option::is_none")] + pub document_link_provider: Option, + + /// The server provides color provider support. + #[serde(skip_serializing_if = "Option::is_none")] + pub color_provider: Option, + + /// The server provides folding provider support. + #[serde(skip_serializing_if = "Option::is_none")] + pub folding_range_provider: Option, + + /// The server provides go to declaration support. + #[serde(skip_serializing_if = "Option::is_none")] + pub declaration_provider: Option, + + /// The server provides execute command support. + #[serde(skip_serializing_if = "Option::is_none")] + pub execute_command_provider: Option, + + /// Workspace specific server capabilities + #[serde(skip_serializing_if = "Option::is_none")] + pub workspace: Option, + + /// Semantic highlighting server capabilities. + #[cfg(feature = "proposed")] + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_highlighting: Option, + + /// Call hierarchy provider capabilities. + #[cfg(feature = "proposed")] + #[serde(skip_serializing_if = "Option::is_none")] + pub call_hierarchy_provider: Option, + + /// Semantic tokens server capabilities. + #[cfg(feature = "proposed")] + #[serde(skip_serializing_if = "Option::is_none")] + pub semantic_tokens_provider: Option, + + /// Experimental server capabilities. + #[serde(skip_serializing_if = "Option::is_none")] + pub experimental: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkCapabilities { + /// Whether document link supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Whether the client support the `tooltip` property on `DocumentLink`. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ShowMessageParams { + /// The message type. See {@link MessageType}. + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message. + pub message: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum MessageType { + /// An error message. + Error = 1, + /// A warning message. + Warning = 2, + /// An information message. + Info = 3, + /// A log message. + Log = 4, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ShowMessageRequestParams { + /// The message type. See {@link MessageType} + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message + pub message: String, + + /// The message action items to present. + #[serde(skip_serializing_if = "Option::is_none")] + pub actions: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct MessageActionItem { + /// A short title like 'Retry', 'Open Log' etc. + pub title: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct LogMessageParams { + /// The message type. See {@link MessageType} + #[serde(rename = "type")] + pub typ: MessageType, + + /// The actual message + pub message: String, +} + +/// General parameters to to register for a capability. +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Registration { + /// The id used to register the request. The id can be used to deregister + /// the request again. + pub id: String, + + /// The method / capability to register for. + pub method: String, + + /// Options necessary for the registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub register_options: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct RegistrationParams { + pub registrations: Vec, +} + +/// Since most of the registration options require to specify a document selector there is a base +/// interface that can be used. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticRegistrationOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticTextDocumentRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorProviderOptions {} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct StaticTextDocumentColorProviderOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + #[serde(skip_serializing_if = "Option::is_none")] + pub id: Option, +} + +/// General parameters to unregister a capability. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Unregistration { + /// The id used to unregister the request or notification. Usually an id + /// provided during the register request. + pub id: String, + + /// The method / capability to unregister for. + pub method: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct UnregistrationParams { + pub unregisterations: Vec, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +pub struct DidChangeConfigurationParams { + /// The actual changed settings + pub settings: Value, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidOpenTextDocumentParams { + /// The document that was opened. + pub text_document: TextDocumentItem, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidChangeTextDocumentParams { + /// The document that did change. The version number points + /// to the version after all provided content changes have + /// been applied. + pub text_document: VersionedTextDocumentIdentifier, + /// The actual content changes. + pub content_changes: Vec, +} + +/// An event describing a change to a text document. If range and rangeLength are omitted +/// the new text is considered to be the full content of the document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentContentChangeEvent { + /// The range of the document that changed. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// The length of the range that got replaced. + /// NOTE: seems redundant, see: + #[serde(skip_serializing_if = "Option::is_none")] + pub range_length: Option, + + /// The new text of the document. + pub text: String, +} + +/// Descibe options to be used when registered for text document change events. +/// +/// Extends TextDocumentRegistrationOptions +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentChangeRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + /// How documents are synced to the server. See TextDocumentSyncKind.Full + /// and TextDocumentSyncKindIncremental. + pub sync_kind: i32, +} + +/// The parameters send in a will save text document notification. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct WillSaveTextDocumentParams { + /// The document that will be saved. + pub text_document: TextDocumentIdentifier, + + /// The 'TextDocumentSaveReason'. + pub reason: TextDocumentSaveReason, +} + +/// Represents reasons why a text document is saved. +#[derive(Copy, Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum TextDocumentSaveReason { + /// Manually triggered, e.g. by the user pressing save, by starting debugging, + /// or by an API call. + Manual = 1, + + /// Automatic after a delay. + AfterDelay = 2, + + /// When the editor lost focus. + FocusOut = 3, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidCloseTextDocumentParams { + /// The document that was closed. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DidSaveTextDocumentParams { + /// The document that was saved. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct TextDocumentSaveRegistrationOptions { + /// The client is supposed to include the content on save. + #[serde(skip_serializing_if = "Option::is_none")] + pub include_text: Option, + + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DidChangeWatchedFilesParams { + /// The actual file events. + pub changes: Vec, +} + +/// The file event type. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum FileChangeType { + /// The file got created. + Created = 1, + + /// The file got changed. + Changed = 2, + + /// The file got deleted. + Deleted = 3, +} + +/// An event describing a file change. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct FileEvent { + /// The file's URI. + pub uri: Url, + + /// The change type. + #[serde(rename = "type")] + pub typ: FileChangeType, +} + +impl FileEvent { + pub fn new(uri: Url, typ: FileChangeType) -> FileEvent { + FileEvent { uri, typ } + } +} + +/// Describe options to be used when registered for text document change events. +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +pub struct DidChangeWatchedFilesRegistrationOptions { + /// The watchers to register. + pub watchers: Vec, +} + +#[derive(Debug, PartialEq, Eq, PartialOrd, Ord, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FileSystemWatcher { + /// The glob pattern to watch + pub glob_pattern: String, + + /// The kind of events of interest. If omitted it defaults to WatchKind.Create | + /// WatchKind.Change | WatchKind.Delete which is 7. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +bitflags! { +pub struct WatchKind: u8 { + /// Interested in create events. + const Create = 1; + /// Interested in change events + const Change = 2; + /// Interested in delete events + const Delete = 4; +} +} + +impl<'de> serde::Deserialize<'de> for WatchKind { + fn deserialize(deserializer: D) -> Result + where + D: serde::Deserializer<'de>, + { + let i = u8::deserialize(deserializer)?; + WatchKind::from_bits(i).ok_or_else(|| { + D::Error::invalid_value(de::Unexpected::Unsigned(u64::from(i)), &"Unknown flag") + }) + } +} + +impl serde::Serialize for WatchKind { + fn serialize(&self, serializer: S) -> Result + where + S: serde::Serializer, + { + serializer.serialize_u8(self.bits()) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct PublishDiagnosticsParams { + /// The URI for which diagnostic information is reported. + pub uri: Url, + + /// An array of diagnostic information items. + pub diagnostics: Vec, + + /// Optional the version number of the document the diagnostics are published for. + #[serde(skip_serializing_if = "Option::is_none")] + pub version: Option, +} + +impl PublishDiagnosticsParams { + pub fn new( + uri: Url, + diagnostics: Vec, + version: Option, + ) -> PublishDiagnosticsParams { + PublishDiagnosticsParams { + uri, + diagnostics, + version, + } + } +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +pub struct CompletionRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub completion_options: CompletionOptions, +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum CompletionResponse { + Array(Vec), + List(CompletionList), +} + +impl From> for CompletionResponse { + fn from(items: Vec) -> Self { + CompletionResponse::Array(items) + } +} + +impl From for CompletionResponse { + fn from(list: CompletionList) -> Self { + CompletionResponse::List(list) + } +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionParams { + // This field was "mixed-in" from TextDocumentPositionParams + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + // CompletionParams properties: + #[serde(skip_serializing_if = "Option::is_none")] + pub context: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionContext { + /// How the completion was triggered. + pub trigger_kind: CompletionTriggerKind, + + /// The trigger character (a single character) that has trigger code complete. + /// Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + #[serde(skip_serializing_if = "Option::is_none")] + pub trigger_character: Option, +} + +/// How a completion was triggered. +#[derive(Debug, PartialEq, Clone, Copy, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum CompletionTriggerKind { + Invoked = 1, + TriggerCharacter = 2, + TriggerForIncompleteCompletions = 3, +} + +/// Represents a collection of [completion items](#CompletionItem) to be presented +/// in the editor. +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CompletionList { + /// This list it not complete. Further typing should result in recomputing + /// this list. + pub is_incomplete: bool, + + /// The completion items. + pub items: Vec, +} + +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum Documentation { + String(String), + MarkupContent(MarkupContent), +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct CompletionItem { + /// The label of this completion item. By default + /// also the text that is inserted when selecting + /// this completion. + pub label: String, + + /// The kind of this completion item. Based of the kind + /// an icon is chosen by the editor. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// A human-readable string with additional information + /// about this item, like type or symbol information. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// A human-readable string that represents a doc-comment. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, + + /// Indicates if this item is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + pub deprecated: Option, + + /// Select this item when showing. + #[serde(skip_serializing_if = "Option::is_none")] + pub preselect: Option, + + /// A string that shoud be used when comparing this item + /// with other items. When `falsy` the label is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub sort_text: Option, + + /// A string that should be used when filtering a set of + /// completion items. When `falsy` the label is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub filter_text: Option, + + /// A string that should be inserted a document when selecting + /// this completion. When `falsy` the label is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text: Option, + + /// The format of the insert text. The format applies to both the `insertText` property + /// and the `newText` property of a provided `textEdit`. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_text_format: Option, + + /// An edit which is applied to a document when selecting + /// this completion. When an edit is provided the value of + /// insertText is ignored. + /// + /// Most editors support two different operation when accepting a completion item. One is to insert a + /// completion text and the other is to replace an existing text with a competion text. Since this can + /// usually not predetermend by a server it can report both ranges. Clients need to signal support for + /// `InsertReplaceEdits` via the `textDocument.completion.insertReplaceSupport` client capability + /// property. + /// + /// *Note 1:* The text edit's range as well as both ranges from a insert replace edit must be a + /// [single line] and they must contain the position at which completion has been requested. + /// *Note 2:* If an `InsertReplaceEdit` is returned the edit's insert range must be a prefix of + /// the edit's replace range, that means it must be contained and starting at the same position. + /// + /// @since 3.16.0 additional type `InsertReplaceEdit` - Proposed state + #[serde(skip_serializing_if = "Option::is_none")] + pub text_edit: Option, + + /// An optional array of additional text edits that are applied when + /// selecting this completion. Edits must not overlap with the main edit + /// nor with themselves. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_text_edits: Option>, + + /// An optional command that is executed *after* inserting this completion. *Note* that + /// additional modifications to the current document should be described with the + /// additionalTextEdits-property. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// An data entry field that is preserved on a completion item between + /// a completion and a completion resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, + + /// Tags for this completion item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, +} + +impl CompletionItem { + /// Create a CompletionItem with the minimum possible info (label and detail). + pub fn new_simple(label: String, detail: String) -> CompletionItem { + CompletionItem { + label, + detail: Some(detail), + ..Self::default() + } + } +} + +/// The kind of a completion entry. +#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum CompletionItemKind { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, +} + +/// Defines how to interpret the insert text in a completion item +#[derive(Debug, Eq, PartialEq, Clone, Copy, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum InsertTextFormat { + PlainText = 1, + Snippet = 2, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct HoverParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// The result of a hover request. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct Hover { + /// The hover's content + pub contents: HoverContents, + /// An optional range is a range inside a text document + /// that is used to visualize a hover, e.g. by changing the background color. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, +} + +/// Hover contents could be single entry or multiple entries. +#[derive(Debug, Eq, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum HoverContents { + Scalar(MarkedString), + Array(Vec), + Markup(MarkupContent), +} + +/// The marked string is rendered: +/// - as markdown if it is represented as a string +/// - as code block of the given langauge if it is represented as a pair of a language and a value +/// +/// The pair of a language and a value is an equivalent to markdown: +/// ```${language} +/// ${value} +/// ``` +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum MarkedString { + String(String), + LanguageString(LanguageString), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct LanguageString { + pub language: String, + pub value: String, +} + +impl MarkedString { + pub fn from_markdown(markdown: String) -> MarkedString { + MarkedString::String(markdown) + } + + pub fn from_language_code(language: String, code_block: String) -> MarkedString { + MarkedString::LanguageString(LanguageString { + language, + value: code_block, + }) + } +} + +/// Signature help represents the signature of something +/// callable. There can be multiple signature but only one +/// active and only one active parameter. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SignatureHelp { + /// One or more signatures. + pub signatures: Vec, + + /// The active signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_signature: Option, + + /// The active parameter of the active signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub active_parameter: Option, +} + +/// Represents the signature of something callable. A signature +/// can have a label, like a function-name, a doc-comment, and +/// a set of parameters. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SignatureInformation { + /// The label of this signature. Will be shown in + /// the UI. + pub label: String, + + /// The human-readable doc-comment of this signature. Will be shown + /// in the UI but can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, + + /// The parameters of this signature. + #[serde(skip_serializing_if = "Option::is_none")] + pub parameters: Option>, +} + +/// Represents a parameter of a callable-signature. A parameter can +/// have a label and a doc-comment. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ParameterInformation { + /// The label of this parameter information. + /// + /// Either a string or an inclusive start and exclusive end offsets within its containing + /// signature label. (see SignatureInformation.label). *Note*: A label of type string must be + /// a substring of its containing signature label. + pub label: ParameterLabel, + + /// The human-readable doc-comment of this parameter. Will be shown + /// in the UI but can be omitted. + #[serde(skip_serializing_if = "Option::is_none")] + pub documentation: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum ParameterLabel { + Simple(String), + LabelOffsets([u64; 2]), +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct GotoDefinitionParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// GotoDefinition response can be single location, or multiple Locations or a link. +#[derive(Debug, PartialEq, Serialize, Deserialize)] +#[serde(untagged)] +pub enum GotoDefinitionResponse { + Scalar(Location), + Array(Vec), + Link(Vec), +} + +impl From for GotoDefinitionResponse { + fn from(location: Location) -> Self { + GotoDefinitionResponse::Scalar(location) + } +} + +impl From> for GotoDefinitionResponse { + fn from(locations: Vec) -> Self { + GotoDefinitionResponse::Array(locations) + } +} + +impl From> for GotoDefinitionResponse { + fn from(locations: Vec) -> Self { + GotoDefinitionResponse::Link(locations) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceParams { + // Text Document and Position fields + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + // ReferenceParams properties: + pub context: ReferenceContext, +} + +#[derive(Debug, Eq, PartialEq, Clone, Copy, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ReferenceContext { + /// Include the declaration of the current symbol. + pub include_declaration: bool, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentHighlightParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A document highlight is a range inside a text document which deserves +/// special attention. Usually a document highlight is visualized by changing +/// the background color of its range. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentHighlight { + /// The range this highlight applies to. + pub range: Range, + + /// The highlight kind, default is DocumentHighlightKind.Text. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +/// A document highlight kind. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +pub enum DocumentHighlightKind { + /// A textual occurrance. + Text = 1, + + /// Read-access of a symbol, like reading a variable. + Read = 2, + + /// Write-access of a symbol, like writing to a variable. + Write = 3, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbolClientCapabilities { + /// This capability supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Specific capabilities for the `SymbolKind`. + #[serde(skip_serializing_if = "Option::is_none")] + pub symbol_kind: Option, + + /// The client support hierarchical document symbols. + #[serde(skip_serializing_if = "Option::is_none")] + pub hierarchical_document_symbol_support: Option, + + /// The client supports tags on `SymbolInformation`. Tags are supported on + /// `DocumentSymbol` if `hierarchicalDocumentSymbolSupport` is set to true. + /// Clients supporting tags have to handle unknown tags gracefully. + /// + /// @since 3.16.0 + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "TagSupport::deserialize_compat" + )] + #[cfg(feature = "proposed")] + pub tag_support: Option>, +} + +#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)] +#[serde(untagged)] +pub enum DocumentSymbolResponse { + Flat(Vec), + Nested(Vec), +} + +impl From> for DocumentSymbolResponse { + fn from(info: Vec) -> Self { + DocumentSymbolResponse::Flat(info) + } +} + +impl From> for DocumentSymbolResponse { + fn from(symbols: Vec) -> Self { + DocumentSymbolResponse::Nested(symbols) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbolParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents programming constructs like variables, classes, interfaces etc. +/// that appear in a document. Document symbols can be hierarchical and they have two ranges: +/// one that encloses its definition and one that points to its most interesting range, +/// e.g. the range of an identifier. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentSymbol { + /// The name of this symbol. + pub name: String, + /// More detail for this symbol, e.g the signature of a function. If not provided the + /// name is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + /// The kind of this symbol. + pub kind: SymbolKind, + /// Tags for this completion item. + /// since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub tags: Option>, + /// Indicates if this symbol is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tags instead")] + pub deprecated: Option, + /// The range enclosing this symbol not including leading/trailing whitespace but everything else + /// like comments. This information is typically used to determine if the the clients cursor is + /// inside the symbol to reveal in the symbol in the UI. + pub range: Range, + /// The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + /// Must be contained by the the `range`. + pub selection_range: Range, + /// Children of this symbol, e.g. properties of a class. + #[serde(skip_serializing_if = "Option::is_none")] + pub children: Option>, +} + +/// Represents information about programming constructs like variables, classes, +/// interfaces etc. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SymbolInformation { + /// The name of this symbol. + pub name: String, + + /// The kind of this symbol. + pub kind: SymbolKind, + + /// Tags for this completion item. + /// since 3.16.0 + #[serde(skip_serializing_if = "Option::is_none")] + #[cfg(feature = "proposed")] + pub tags: Option>, + + /// Indicates if this symbol is deprecated. + #[serde(skip_serializing_if = "Option::is_none")] + #[deprecated(note = "Use tags instead")] + pub deprecated: Option, + + /// The location of this symbol. + pub location: Location, + + /// The name of the symbol containing this symbol. + #[serde(skip_serializing_if = "Option::is_none")] + pub container_name: Option, +} + +/// A symbol kind. +#[derive(Debug, Eq, PartialEq, Copy, Clone, Serialize_repr, Deserialize_repr)] +#[repr(u8)] +pub enum SymbolKind { + File = 1, + Module = 2, + Namespace = 3, + Package = 4, + Class = 5, + Method = 6, + Property = 7, + Field = 8, + Constructor = 9, + Enum = 10, + Interface = 11, + Function = 12, + Variable = 13, + Constant = 14, + String = 15, + Number = 16, + Boolean = 17, + Array = 18, + Object = 19, + Key = 20, + Null = 21, + EnumMember = 22, + Struct = 23, + Event = 24, + Operator = 25, + TypeParameter = 26, + + // Capturing all unknown enums by this lib. + Unknown = 255, +} + +/// The parameters of a Workspace Symbol Request. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct WorkspaceSymbolParams { + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + /// A non-empty query string + pub query: String, +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct ExecuteCommandParams { + /// The identifier of the actual command handler. + pub command: String, + /// Arguments that the command should be invoked with. + #[serde(default)] + pub arguments: Vec, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// Execute command registration options. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ExecuteCommandRegistrationOptions { + /// The commands to be executed on the server + pub commands: Vec, + + #[serde(flatten)] + pub execute_command_options: ExecuteCommandOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ApplyWorkspaceEditParams { + /// The edits to apply. + pub edit: WorkspaceEdit, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct ApplyWorkspaceEditResponse { + /// Indicates whether the edit was applied or not. + pub applied: bool, +} + +/// Params for the CodeActionRequest +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionParams { + /// The document in which the command was invoked. + pub text_document: TextDocumentIdentifier, + + /// The range for which the command was invoked. + pub range: Range, + + /// Context carrying additional information. + pub context: CodeActionContext, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// response for CodeActionRequest +pub type CodeActionResponse = Vec; + +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +#[serde(untagged)] +pub enum CodeActionOrCommand { + Command(Command), + CodeAction(CodeAction), +} + +impl From for CodeActionOrCommand { + fn from(comand: Command) -> Self { + CodeActionOrCommand::Command(comand) + } +} + +impl From for CodeActionOrCommand { + fn from(action: CodeAction) -> Self { + CodeActionOrCommand::CodeAction(action) + } +} + +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +pub struct CodeActionKind(Cow<'static, str>); + +impl CodeActionKind { + /// Empty kind. + pub const EMPTY: CodeActionKind = CodeActionKind::new(""); + + /// Base kind for quickfix actions: 'quickfix' + pub const QUICKFIX: CodeActionKind = CodeActionKind::new("quickfix"); + + /// Base kind for refactoring actions: 'refactor' + pub const REFACTOR: CodeActionKind = CodeActionKind::new("refactor"); + + /// Base kind for refactoring extraction actions: 'refactor.extract' + /// + /// Example extract actions: + /// + /// - Extract method + /// - Extract function + /// - Extract variable + /// - Extract interface from class + /// - ... + pub const REFACTOR_EXTRACT: CodeActionKind = CodeActionKind::new("refactor.extract"); + + /// Base kind for refactoring inline actions: 'refactor.inline' + /// + /// Example inline actions: + /// + /// - Inline function + /// - Inline variable + /// - Inline constant + /// - ... + pub const REFACTOR_INLINE: CodeActionKind = CodeActionKind::new("refactor.inline"); + + /// Base kind for refactoring rewrite actions: 'refactor.rewrite' + /// + /// Example rewrite actions: + /// + /// - Convert JavaScript function to class + /// - Add or remove parameter + /// - Encapsulate field + /// - Make method static + /// - Move method to base class + /// - ... + pub const REFACTOR_REWRITE: CodeActionKind = CodeActionKind::new("refactor.rewrite"); + + /// Base kind for source actions: `source` + /// + /// Source code actions apply to the entire file. + pub const SOURCE: CodeActionKind = CodeActionKind::new("source"); + + /// Base kind for an organize imports source action: `source.organizeImports` + pub const SOURCE_ORGANIZE_IMPORTS: CodeActionKind = + CodeActionKind::new("source.organizeImports"); + + pub const fn new(tag: &'static str) -> Self { + CodeActionKind(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +impl From for CodeActionKind { + fn from(from: String) -> Self { + CodeActionKind(Cow::from(from)) + } +} + +impl From<&'static str> for CodeActionKind { + fn from(from: &'static str) -> Self { + CodeActionKind::new(from) + } +} + +#[derive(Debug, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeAction { + /// A short, human-readable, title for this code action. + pub title: String, + + /// The kind of the code action. + /// Used to filter code actions. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, + + /// The diagnostics that this code action resolves. + #[serde(skip_serializing_if = "Option::is_none")] + pub diagnostics: Option>, + + /// The workspace edit this code action performs. + #[serde(skip_serializing_if = "Option::is_none")] + pub edit: Option, + + /// A command this code action executes. If a code action + /// provides an edit and a command, first the edit is + /// executed and then the command. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// Marks this as a preferred action. Preferred actions are used by the `auto fix` command and can be targeted + /// by keybindings. + /// A quick fix should be marked preferred if it properly addresses the underlying error. + /// A refactoring should be marked preferred if it is the most reasonable choice of actions to take. + #[serde(skip_serializing_if = "Option::is_none")] + pub is_preferred: Option, +} + +/// Contains additional diagnostic information about the context in which +/// a code action is run. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct CodeActionContext { + /// An array of diagnostics. + pub diagnostics: Vec, + + /// Requested kind of actions to return. + /// + /// Actions not of this kind are filtered out by the client before being shown. So servers + /// can omit computing them. + #[serde(skip_serializing_if = "Option::is_none")] + pub only: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeActionOptions { + /// CodeActionKinds that this server may return. + /// + /// The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server + /// may list out every specific kind they provide. + #[serde(skip_serializing_if = "Option::is_none")] + pub code_action_kinds: Option>, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct CodeLensParams { + /// The document to request code lens for. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A code lens represents a command that should be shown along with +/// source text, like the number of references, a way to run tests, etc. +/// +/// A code lens is _unresolved_ when no command is associated to it. For performance +/// reasons the creation of a code lens and resolving should be done in two stages. +#[derive(Debug, Clone, PartialEq, Deserialize, Serialize)] +pub struct CodeLens { + /// The range in which this code lens is valid. Should only span a single line. + pub range: Range, + + /// The command this code lens represents. + #[serde(skip_serializing_if = "Option::is_none")] + pub command: Option, + + /// A data entry field that is preserved on a code lens item between + /// a code lens and a code lens resolve request. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkParams { + /// The document to provide document links for. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// A document link is a range in a text document that links to an internal or external resource, like another +/// text document or a web site. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct DocumentLink { + /// The range this link applies to. + pub range: Range, + /// The uri this link points to. + #[serde(skip_serializing_if = "Option::is_none")] + pub target: Option, + + /// The tooltip text when you hover over this link. + /// + /// If a tooltip is provided, is will be displayed in a string that includes instructions on how to + /// trigger the link, such as `{0} (ctrl + click)`. The specific instructions vary depending on OS, + /// user settings, and localization. + #[serde(skip_serializing_if = "Option::is_none")] + pub tooltip: Option, + + /// A data entry field that is preserved on a document link between a DocumentLinkRequest + /// and a DocumentLinkResolveRequest. + #[serde(skip_serializing_if = "Option::is_none")] + pub data: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentFormattingParams { + /// The document to format. + pub text_document: TextDocumentIdentifier, + + /// The format options. + pub options: FormattingOptions, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +/// Value-object describing what options formatting should use. +#[derive(Debug, PartialEq, Clone, Default, Serialize, Deserialize)] +#[serde(rename_all = "camelCase")] +pub struct FormattingOptions { + /// Size of a tab in spaces. + pub tab_size: u64, + + /// Prefer spaces over tabs. + pub insert_spaces: bool, + + /// Signature for further properties. + #[serde(flatten)] + pub properties: HashMap, + + /// Trim trailing whitespaces on a line. + #[serde(skip_serializing_if = "Option::is_none")] + pub trim_trailing_whitespace: Option, + + /// Insert a newline character at the end of the file if one does not exist. + #[serde(skip_serializing_if = "Option::is_none")] + pub insert_final_newline: Option, + + /// Trim all newlines after the final newline at the end of the file. + #[serde(skip_serializing_if = "Option::is_none")] + pub trim_final_newlines: Option, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum FormattingProperty { + Bool(bool), + Number(f64), + String(String), +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentRangeFormattingParams { + /// The document to format. + pub text_document: TextDocumentIdentifier, + + /// The range to format + pub range: Range, + + /// The format options + pub options: FormattingOptions, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingParams { + /// Text Document and Position fields. + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + /// The character that has been typed. + pub ch: String, + + /// The format options. + pub options: FormattingOptions, +} + +/// Extends TextDocumentRegistrationOptions +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentOnTypeFormattingRegistrationOptions { + /// A document selector to identify the scope of the registration. If set to null + /// the document selector provided on the client side will be used. + pub document_selector: Option, + + /// A character on which formatting should be triggered, like `}`. + pub first_trigger_character: String, + + /// More trigger characters. + #[serde(skip_serializing_if = "Option::is_none")] + pub more_trigger_character: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameParams { + /// Text Document and Position fields + #[serde(flatten)] + pub text_document_position: TextDocumentPositionParams, + + /// The new name of the symbol. If the given name is not valid the + /// request must return a [ResponseError](#ResponseError) with an + /// appropriate message set. + pub new_name: String, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum RenameProviderCapability { + Simple(bool), + Options(RenameOptions), +} + +impl From for RenameProviderCapability { + fn from(from: RenameOptions) -> Self { + Self::Options(from) + } +} + +impl From for RenameProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameOptions { + /// Renames should be checked and tested before being executed. + #[serde(skip_serializing_if = "Option::is_none")] + pub prepare_provider: Option, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct RenameCapability { + /// Whether rename supports dynamic registration. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Client supports testing for validity of rename operations before execution. + #[serde(skip_serializing_if = "Option::is_none")] + pub prepare_support: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum PrepareRenameResponse { + Range(Range), + RangeWithPlaceholder { range: Range, placeholder: String }, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentLinkOptions { + /// Document links have a resolve provider as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub resolve_provider: Option, + + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct DocumentColorParams { + /// The text document + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorInformation { + /// The range in the document where this color appears. + pub range: Range, + /// The actual color value for this color range. + pub color: Color, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct Color { + /// The red component of this color in the range [0-1]. + pub red: f64, + /// The green component of this color in the range [0-1]. + pub green: f64, + /// The blue component of this color in the range [0-1]. + pub blue: f64, + /// The alpha component of this color in the range [0-1]. + pub alpha: f64, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct ColorPresentationParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The color information to request presentations for. + pub color: Color, + + /// The range where the color would be inserted. Serves as a context. + pub range: Range, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, PartialEq, Eq, Deserialize, Serialize, Default, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ColorPresentation { + /// The label of this color presentation. It will be shown on the color + /// picker header. By default this is also the text that is inserted when selecting + /// this color presentation. + pub label: String, + + /// An [edit](#TextEdit) which is applied to a document when selecting + /// this presentation for the color. When `falsy` the [label](#ColorPresentation.label) + /// is used. + #[serde(skip_serializing_if = "Option::is_none")] + pub text_edit: Option, + + /// An optional array of additional [text edits](#TextEdit) that are applied when + /// selecting this color presentation. Edits must not overlap with the main [edit](#ColorPresentation.textEdit) nor with themselves. + #[serde(skip_serializing_if = "Option::is_none")] + pub additional_text_edits: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum FoldingRangeProviderCapability { + Simple(bool), + FoldingProvider(FoldingProviderOptions), + Options(StaticTextDocumentColorProviderOptions), +} + +impl From for FoldingRangeProviderCapability { + fn from(from: StaticTextDocumentColorProviderOptions) -> Self { + Self::Options(from) + } +} + +impl From for FoldingRangeProviderCapability { + fn from(from: FoldingProviderOptions) -> Self { + Self::FoldingProvider(from) + } +} + +impl From for FoldingRangeProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct FoldingProviderOptions {} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRangeCapability { + /// Whether implementation supports dynamic registration for folding range providers. If this is set to `true` + /// the client supports the new `(FoldingRangeProviderOptions & TextDocumentRegistrationOptions & StaticRegistrationOptions)` + /// return value for the corresponding server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// The maximum number of folding ranges that the client prefers to receive per document. The value serves as a + /// hint, servers are free to follow the limit. + #[serde(skip_serializing_if = "Option::is_none")] + pub range_limit: Option, + /// If set, the client signals that it only supports folding complete lines. If set, client will + /// ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. + #[serde(skip_serializing_if = "Option::is_none")] + pub line_folding_only: Option, +} + +/// Represents a folding range. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct FoldingRange { + /// The zero-based line number from where the folded range starts. + pub start_line: u64, + + /// The zero-based character offset from where the folded range starts. If not defined, defaults to the length of the start line. + #[serde(skip_serializing_if = "Option::is_none")] + pub start_character: Option, + + /// The zero-based line number where the folded range ends. + pub end_line: u64, + + /// The zero-based character offset before the folded range ends. If not defined, defaults to the length of the end line. + #[serde(skip_serializing_if = "Option::is_none")] + pub end_character: Option, + + /// Describes the kind of the folding range such as `comment' or 'region'. The kind + /// is used to categorize folding ranges and used by commands like 'Fold all comments'. See + /// [FoldingRangeKind](#FoldingRangeKind) for an enumeration of standardized kinds. + #[serde(skip_serializing_if = "Option::is_none")] + pub kind: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +pub struct SelectionRangeOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +pub struct SelectionRangeRegistrationOptions { + #[serde(flatten)] + pub selection_range_options: SelectionRangeOptions, + + #[serde(flatten)] + pub registration_options: StaticTextDocumentRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +pub enum SelectionRangeProviderCapability { + Simple(bool), + Options(SelectionRangeOptions), + RegistrationOptions(SelectionRangeRegistrationOptions), +} + +impl From for SelectionRangeProviderCapability { + fn from(from: SelectionRangeRegistrationOptions) -> Self { + Self::RegistrationOptions(from) + } +} + +impl From for SelectionRangeProviderCapability { + fn from(from: SelectionRangeOptions) -> Self { + Self::Options(from) + } +} + +impl From for SelectionRangeProviderCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +/// A parameter literal used in selection range requests. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SelectionRangeParams { + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The positions inside the text document. + pub positions: Vec, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents a selection range. +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +pub struct SelectionRange { + /// Range of the selection. + pub range: Range, + + /// The parent selection range containing this range. + #[serde(skip_serializing_if = "Option::is_none")] + pub parent: Option>, +} + +/// Enum of known range kinds +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum FoldingRangeKind { + /// Folding range for a comment + Comment, + /// Folding range for a imports or includes + Imports, + /// Folding range for a region (e.g. `#region`) + Region, +} + +/// Describes the content type that a client supports in various +/// result literals like `Hover`, `ParameterInfo` or `CompletionItem`. +/// +/// Please note that `MarkupKinds` must not start with a `$`. This kinds +/// are reserved for internal usage. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "lowercase")] +pub enum MarkupKind { + /// Plain text is supported as a content format + PlainText, + /// Markdown is supported as a content format + Markdown, +} + +/// A `MarkupContent` literal represents a string value which content is interpreted base on its +/// kind flag. Currently the protocol supports `plaintext` and `markdown` as markup kinds. +/// +/// If the kind is `markdown` then the value can contain fenced code blocks like in GitHub issues. +/// See +/// +/// Here is an example how such a string can be constructed using JavaScript / TypeScript: +/// ```ignore +/// let markdown: MarkupContent = { +/// kind: MarkupKind::Markdown, +/// value: [ +/// "# Header", +/// "Some text", +/// "```typescript", +/// "someCode();", +/// "```" +/// ] +/// .join("\n"), +/// }; +/// ``` +/// +/// Please Note* that clients might sanitize the return markdown. A client could decide to +/// remove HTML from the markdown to avoid script execution. +#[derive(Debug, Eq, PartialEq, Deserialize, Serialize, Clone)] +pub struct MarkupContent { + pub kind: MarkupKind, + pub value: String, +} + +pub type ProgressToken = NumberOrString; + +/// The progress notification is sent from the server to the client to ask +/// the client to indicate progress. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct ProgressParams { + /// The progress token provided by the client. + pub token: ProgressToken, + + /// The progress data. + pub value: ProgressParamsValue, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(untagged)] +pub enum ProgressParamsValue { + WorkDone(WorkDoneProgress), +} + +/// The `window/workDoneProgress/create` request is sent from the server +/// to the clientto ask the client to create a work done progress. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressCreateParams { + /// The token to be used to report progress. + pub token: ProgressToken, +} + +/// The `window/workDoneProgress/cancel` notification is sent from the client +/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressCancelParams { + /// The token to be used to report progress. + pub token: ProgressToken, +} + +/// Options to signal work done progress support in server capabilities. +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressOptions { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_progress: Option, +} + +/// An optional token that a server can use to report work done progress +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressParams { + #[serde(skip_serializing_if = "Option::is_none")] + pub work_done_token: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressBegin { + /// Mandatory title of the progress operation. Used to briefly inform + /// about the kind of operation being performed. + /// Examples: "Indexing" or "Linking dependencies". + pub title: String, + + /// Controls if a cancel button should show to allow the user to cancel the + /// long running operation. Clients that don't support cancellation are allowed + /// to ignore the setting. + #[serde(skip_serializing_if = "Option::is_none")] + pub cancellable: Option, + + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + + /// Optional progress percentage to display (value 100 is considered 100%). + /// If unset, the previous progress percentage (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressReport { + /// Controls if a cancel button should show to allow the user to cancel the + /// long running operation. Clients that don't support cancellation are allowed + /// to ignore the setting. + #[serde(skip_serializing_if = "Option::is_none")] + pub cancellable: Option, + + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, + + /// Optional progress percentage to display (value 100 is considered 100%). + /// If unset, the previous progress percentage (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub percentage: Option, +} + +#[derive(Debug, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct WorkDoneProgressEnd { + /// Optional, more detailed associated progress message. Contains + /// complementary information to the `title`. + /// Examples: "3/25 files", "project/src/module2", "node_modules/some_dep". + /// If unset, the previous progress message (if any) is still valid. + #[serde(skip_serializing_if = "Option::is_none")] + pub message: Option, +} + +#[derive(Debug, PartialEq, Deserialize, Serialize, Clone)] +#[serde(tag = "kind", rename_all = "lowercase")] +pub enum WorkDoneProgress { + Begin(WorkDoneProgressBegin), + Report(WorkDoneProgressReport), + End(WorkDoneProgressEnd), +} + +/// A parameter literal used to pass a partial result token. +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +pub struct PartialResultParams { + #[serde(skip_serializing_if = "Option::is_none")] + pub partial_result_token: Option, +} + +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingClientCapability { + /// `true` if the client supports semantic highlighting support text documents. Otherwise, `false`. It is `false` by default. + pub semantic_highlighting: bool, +} + +#[derive(Debug, Eq, PartialEq, Default, Deserialize, Serialize, Clone)] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingServerCapability { + /// A "lookup table" of semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars) + /// supported by the language server. If not defined or empty, then the server does not support the semantic highlighting + /// feature. Otherwise, clients should reuse this "lookup table" when receiving semantic highlighting notifications from + /// the server. + #[serde(skip_serializing_if = "Option::is_none")] + pub scopes: Option>>, +} + +#[derive(Debug, Eq, PartialEq, Clone)] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingToken { + pub character: u32, + pub length: u16, + pub scope: u16, +} + +#[cfg(feature = "proposed")] +impl SemanticHighlightingToken { + /// Deserializes the tokens from a base64 encoded string + fn deserialize_tokens<'de, D>( + deserializer: D, + ) -> Result>, D::Error> + where + D: serde::Deserializer<'de>, + { + let opt_s = Option::::deserialize(deserializer)?; + + if let Some(s) = opt_s { + let bytes = base64::decode_config(s.as_str(), base64::STANDARD) + .map_err(|_| serde::de::Error::custom("Error parsing base64 string"))?; + let mut res = Vec::new(); + for chunk in bytes.chunks_exact(8) { + res.push(SemanticHighlightingToken { + character: u32::from_be_bytes(<[u8; 4]>::try_from(&chunk[0..4]).unwrap()), + length: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[4..6]).unwrap()), + scope: u16::from_be_bytes(<[u8; 2]>::try_from(&chunk[6..8]).unwrap()), + }); + } + Result::Ok(Some(res)) + } else { + Result::Ok(None) + } + } + + /// Serialize the tokens to a base64 encoded string + fn serialize_tokens( + tokens: &Option>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + if let Some(tokens) = tokens { + let mut bytes = vec![]; + for token in tokens { + bytes.extend_from_slice(&token.character.to_be_bytes()); + bytes.extend_from_slice(&token.length.to_be_bytes()); + bytes.extend_from_slice(&token.scope.to_be_bytes()); + } + serializer.collect_str(&base64::display::Base64Display::with_config( + &bytes, + base64::STANDARD, + )) + } else { + serializer.serialize_none() + } + } +} + +/// Represents a semantic highlighting information that has to be applied on a specific line of the text document. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingInformation { + /// The zero-based line position in the text document. + pub line: i32, + + /// A base64 encoded string representing every single highlighted characters with its start position, length and the "lookup table" index of + /// of the semantic highlighting [TextMate scopes](https://manual.macromates.com/en/language_grammars). + /// If the `tokens` is empty or not defined, then no highlighted positions are available for the line. + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "SemanticHighlightingToken::deserialize_tokens", + serialize_with = "SemanticHighlightingToken::serialize_tokens" + )] + pub tokens: Option>, +} + +/// Parameters for the semantic highlighting (server-side) push notification. +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticHighlightingParams { + /// The text document that has to be decorated with the semantic highlighting information. + pub text_document: VersionedTextDocumentIdentifier, + + /// An array of semantic highlighting information. + pub lines: Vec, +} + +/// A set of predefined token types. This set is not fixed +/// and clients can specify additional token types via the +/// corresponding client capabilities. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct SemanticTokenType(Cow<'static, str>); + +#[cfg(feature = "proposed")] +impl SemanticTokenType { + pub const NAMESPACE: SemanticTokenType = SemanticTokenType::new("namespace"); + pub const TYPE: SemanticTokenType = SemanticTokenType::new("type"); + pub const CLASS: SemanticTokenType = SemanticTokenType::new("class"); + pub const ENUM: SemanticTokenType = SemanticTokenType::new("enum"); + pub const INTERFACE: SemanticTokenType = SemanticTokenType::new("interface"); + pub const STRUCT: SemanticTokenType = SemanticTokenType::new("struct"); + pub const TYPE_PARAMETER: SemanticTokenType = SemanticTokenType::new("typeParameter"); + pub const PARAMETER: SemanticTokenType = SemanticTokenType::new("parameter"); + pub const VARIABLE: SemanticTokenType = SemanticTokenType::new("variable"); + pub const PROPERTY: SemanticTokenType = SemanticTokenType::new("property"); + pub const ENUM_MEMBER: SemanticTokenType = SemanticTokenType::new("enumMember"); + pub const EVENT: SemanticTokenType = SemanticTokenType::new("event"); + pub const FUNCTION: SemanticTokenType = SemanticTokenType::new("function"); + pub const MEMBER: SemanticTokenType = SemanticTokenType::new("member"); + pub const MACRO: SemanticTokenType = SemanticTokenType::new("macro"); + pub const KEYWORD: SemanticTokenType = SemanticTokenType::new("keyword"); + pub const MODIFIER: SemanticTokenType = SemanticTokenType::new("modifier"); + pub const COMMENT: SemanticTokenType = SemanticTokenType::new("comment"); + pub const STRING: SemanticTokenType = SemanticTokenType::new("string"); + pub const NUMBER: SemanticTokenType = SemanticTokenType::new("number"); + pub const REGEXP: SemanticTokenType = SemanticTokenType::new("regexp"); + pub const OPERATOR: SemanticTokenType = SemanticTokenType::new("operator"); + + pub const fn new(tag: &'static str) -> Self { + SemanticTokenType(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokenType { + fn from(from: String) -> Self { + SemanticTokenType(Cow::from(from)) + } +} +#[cfg(feature = "proposed")] +impl From<&'static str> for SemanticTokenType { + fn from(from: &'static str) -> Self { + SemanticTokenType::new(from) + } +} + +/// A set of predefined token modifiers. This set is not fixed +/// and clients can specify additional token types via the +/// corresponding client capabilities. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct SemanticTokenModifier(Cow<'static, str>); + +#[cfg(feature = "proposed")] +impl SemanticTokenModifier { + pub const DECLARATION: SemanticTokenModifier = SemanticTokenModifier::new("declaration"); + pub const DEFINITION: SemanticTokenModifier = SemanticTokenModifier::new("definition"); + pub const READONLY: SemanticTokenModifier = SemanticTokenModifier::new("readonly"); + pub const STATIC: SemanticTokenModifier = SemanticTokenModifier::new("static"); + pub const DEPRECATED: SemanticTokenModifier = SemanticTokenModifier::new("deprecated"); + pub const ABSTRACT: SemanticTokenModifier = SemanticTokenModifier::new("abstract"); + pub const ASYNC: SemanticTokenModifier = SemanticTokenModifier::new("async"); + pub const MODIFICATION: SemanticTokenModifier = SemanticTokenModifier::new("modification"); + pub const DOCUMENTATION: SemanticTokenModifier = SemanticTokenModifier::new("documentation"); + pub const DEFAULT_LIBRARY: SemanticTokenModifier = SemanticTokenModifier::new("defaultLibrary"); + + pub const fn new(tag: &'static str) -> Self { + SemanticTokenModifier(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokenModifier { + fn from(from: String) -> Self { + SemanticTokenModifier(Cow::from(from)) + } +} +#[cfg(feature = "proposed")] +impl From<&'static str> for SemanticTokenModifier { + fn from(from: &'static str) -> Self { + SemanticTokenModifier::new(from) + } +} + +#[derive(Debug, Eq, PartialEq, Hash, PartialOrd, Clone, Deserialize, Serialize)] +#[cfg(feature = "proposed")] +pub struct TokenFormat(Cow<'static, str>); + +#[cfg(feature = "proposed")] +impl TokenFormat { + pub const RELATIVE: TokenFormat = TokenFormat::new("relative"); + + pub const fn new(tag: &'static str) -> Self { + TokenFormat(Cow::Borrowed(tag)) + } + + pub fn as_str(&self) -> &str { + &self.0 + } +} + +#[cfg(feature = "proposed")] +impl From for TokenFormat { + fn from(from: String) -> Self { + TokenFormat(Cow::from(from)) + } +} +#[cfg(feature = "proposed")] +impl From<&'static str> for TokenFormat { + fn from(from: &'static str) -> Self { + TokenFormat::new(from) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensLegend { + /// The token types a server uses. + pub token_types: Vec, + + /// The token modifiers a server uses. + pub token_modifiers: Vec, +} + +/// The actual tokens. For a detailed description about how the data is +/// structured please see +/// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 +#[derive(Debug, Eq, PartialEq, Copy, Clone, Default)] +#[cfg(feature = "proposed")] +pub struct SemanticToken { + pub delta_line: u32, + pub delta_start: u32, + pub length: u32, + pub token_type: u32, + pub token_modifiers_bitset: u32, +} + +#[cfg(feature = "proposed")] +impl SemanticToken { + fn deserialize_tokens<'de, D>(deserializer: D) -> Result, D::Error> + where + D: serde::Deserializer<'de>, + { + let data = Vec::::deserialize(deserializer)?; + let chunks = data.chunks_exact(5); + + if !chunks.remainder().is_empty() { + return Result::Err(serde::de::Error::custom("Length is not divisible by 5")); + } + + Result::Ok( + chunks + .map(|chunk| SemanticToken { + delta_line: chunk[0], + delta_start: chunk[1], + length: chunk[2], + token_type: chunk[3], + token_modifiers_bitset: chunk[4], + }) + .collect(), + ) + } + + fn serialize_tokens(tokens: &[SemanticToken], serializer: S) -> Result + where + S: serde::Serializer, + { + let mut seq = serializer.serialize_seq(Some(tokens.len() * 5))?; + for token in tokens.iter() { + seq.serialize_element(&token.delta_line)?; + seq.serialize_element(&token.delta_start)?; + seq.serialize_element(&token.length)?; + seq.serialize_element(&token.token_type)?; + seq.serialize_element(&token.token_modifiers_bitset)?; + } + seq.end() + } + + fn deserialize_tokens_opt<'de, D>( + deserializer: D, + ) -> Result>, D::Error> + where + D: serde::Deserializer<'de>, + { + #[derive(Deserialize)] + #[serde(transparent)] + struct Wrapper { + #[serde(deserialize_with = "SemanticToken::deserialize_tokens")] + tokens: Vec, + } + + Ok(Option::::deserialize(deserializer)?.map(|wrapper| wrapper.tokens)) + } + + fn serialize_tokens_opt( + data: &Option>, + serializer: S, + ) -> Result + where + S: serde::Serializer, + { + #[derive(Serialize)] + #[serde(transparent)] + struct Wrapper { + #[serde(serialize_with = "SemanticToken::serialize_tokens")] + tokens: Vec, + } + + let opt = data.as_ref().map(|t| Wrapper { tokens: t.to_vec() }); + + opt.serialize(serializer) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokens { + /// An optional result id. If provided and clients support delta updating + /// the client will include the result id in the next semantic token request. + /// A server can then instead of computing all semantic tokens again simply + /// send a delta. + #[serde(skip_serializing_if = "Option::is_none")] + pub result_id: Option, + + /// The actual tokens. For a detailed description about how the data is + /// structured please see + /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L71 + #[serde( + deserialize_with = "SemanticToken::deserialize_tokens", + serialize_with = "SemanticToken::serialize_tokens" + )] + pub data: Vec, +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensPartialResult { + #[serde( + deserialize_with = "SemanticToken::deserialize_tokens", + serialize_with = "SemanticToken::serialize_tokens" + )] + pub data: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensResult { + Tokens(SemanticTokens), + Partial(SemanticTokensPartialResult), +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensResult { + fn from(from: SemanticTokens) -> Self { + SemanticTokensResult::Tokens(from) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensResult { + fn from(from: SemanticTokensPartialResult) -> Self { + SemanticTokensResult::Partial(from) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensEdit { + pub start: u32, + pub delete_count: u32, + + #[serde( + default, + skip_serializing_if = "Option::is_none", + deserialize_with = "SemanticToken::deserialize_tokens_opt", + serialize_with = "SemanticToken::serialize_tokens_opt" + )] + pub data: Option>, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullDeltaResult { + Tokens(SemanticTokens), + TokensDelta(SemanticTokensDelta), + PartialTokensDelta { edits: Vec }, +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensFullDeltaResult { + fn from(from: SemanticTokens) -> Self { + SemanticTokensFullDeltaResult::Tokens(from) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensFullDeltaResult { + fn from(from: SemanticTokensDelta) -> Self { + SemanticTokensFullDeltaResult::TokensDelta(from) + } +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensDelta { + #[serde(skip_serializing_if = "Option::is_none")] + pub result_id: Option, + /// For a detailed description how these edits are structured pls see + /// https://github.com/microsoft/vscode-extension-samples/blob/5ae1f7787122812dcc84e37427ca90af5ee09f14/semantic-tokens-sample/vscode.proposed.d.ts#L131 + pub edits: Vec, +} + +/// Capabilities specific to the `textDocument/semanticTokens/*` requests. +/// +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensClientCapabilities { + /// Whether implementation supports dynamic registration. If this is set to `true` + /// the client supports the new `(TextDocumentRegistrationOptions & StaticRegistrationOptions)` + /// return value for the corresponding server capability as well. + #[serde(skip_serializing_if = "Option::is_none")] + pub dynamic_registration: Option, + + /// Which requests the client supports and might send to the server. + pub requests: SemanticTokensClientCapabilitiesRequests, + + /// The token types that the client supports. + pub token_types: Vec, + + /// The token modifiers that the client supports. + pub token_modifiers: Vec, + + /// The formats the clients supports. + pub formats: Vec, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensClientCapabilitiesRequests { + /// The client will send the `textDocument/semanticTokens/range` request if the server provides a corresponding handler. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// The client will send the `textDocument/semanticTokens/full` request if the server provides a corresponding handler. + #[serde(skip_serializing_if = "Option::is_none")] + pub full: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullOptions { + Bool(bool), + Delta { + /// The client will send the `textDocument/semanticTokens/full/delta` request if the server provides a corresponding handler. + /// The server supports deltas for full documents. + #[serde(skip_serializing_if = "Option::is_none")] + delta: Option, + }, +} + +/// @since 3.16.0 - Proposed state +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, + + /// The legend used by the server + pub legend: SemanticTokensLegend, + + /// Server supports providing semantic tokens for a sepcific range + /// of a document. + #[serde(skip_serializing_if = "Option::is_none")] + pub range: Option, + + /// Server supports providing semantic tokens for a full document. + #[serde(skip_serializing_if = "Option::is_none")] + pub full: Option, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensRegistrationOptions { + #[serde(flatten)] + pub text_document_registration_options: TextDocumentRegistrationOptions, + + #[serde(flatten)] + pub semantic_tokens_options: SemanticTokensOptions, + + #[serde(flatten)] + pub static_registration_options: StaticRegistrationOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensServerCapabilities { + SemanticTokensOptions(SemanticTokensOptions), + SemanticTokensRegistrationOptions(SemanticTokensRegistrationOptions), +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensServerCapabilities { + fn from(from: SemanticTokensOptions) -> Self { + SemanticTokensServerCapabilities::SemanticTokensOptions(from) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensServerCapabilities { + fn from(from: SemanticTokensRegistrationOptions) -> Self { + SemanticTokensServerCapabilities::SemanticTokensRegistrationOptions(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensDeltaParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The result id of a previous response. The result Id can either point to a full response + /// or a delta response depending on what was recevied last. + pub previous_result_id: String, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct SemanticTokensRangeParams { + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, + + /// The text document. + pub text_document: TextDocumentIdentifier, + + /// The range the semantic tokens are requested for. + pub range: Range, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum SemanticTokensRangeResult { + Tokens(SemanticTokens), + Partial(SemanticTokensPartialResult), +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensRangeResult { + fn from(tokens: SemanticTokens) -> Self { + SemanticTokensRangeResult::Tokens(tokens) + } +} + +#[cfg(feature = "proposed")] +impl From for SemanticTokensRangeResult { + fn from(partial: SemanticTokensPartialResult) -> Self { + SemanticTokensRangeResult::Partial(partial) + } +} + +/// Symbol tags are extra annotations that tweak the rendering of a symbol. +/// Since 3.15 +#[derive(Debug, Eq, PartialEq, Clone, Deserialize_repr, Serialize_repr)] +#[repr(u8)] +#[cfg(feature = "proposed")] +pub enum SymbolTag { + /// Render a symbol as obsolete, usually using a strike-out. + Deprecated = 1, +} + +#[derive(Debug, Eq, PartialEq, Clone, Default, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyOptions { + #[serde(flatten)] + pub work_done_progress_options: WorkDoneProgressOptions, +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(untagged)] +#[cfg(feature = "proposed")] +pub enum CallHierarchyServerCapability { + Simple(bool), + Options(CallHierarchyOptions), +} + +#[cfg(feature = "proposed")] +impl From for CallHierarchyServerCapability { + fn from(from: CallHierarchyOptions) -> Self { + Self::Options(from) + } +} + +#[cfg(feature = "proposed")] +impl From for CallHierarchyServerCapability { + fn from(from: bool) -> Self { + Self::Simple(from) + } +} + +#[derive(Debug, Eq, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyPrepareParams { + #[serde(flatten)] + pub text_document_position_params: TextDocumentPositionParams, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, +} + +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyItem { + /// The name of this item. + pub name: String, + + /// The kind of this item. + pub kind: SymbolKind, + + /// Tags for this item. + #[serde(skip_serializing_if = "Option::is_none")] + pub tags: Option>, + + /// More detail for this item, e.g. the signature of a function. + #[serde(skip_serializing_if = "Option::is_none")] + pub detail: Option, + + /// The resource identifier of this item. + pub uri: Url, + + /// The range enclosing this symbol not including leading/trailing whitespace but everything else, e.g. comments and code. + pub range: Range, + + /// The range that should be selected and revealed when this symbol is being picked, e.g. the name of a function. + /// Must be contained by the [`range`](#CallHierarchyItem.range). + pub selection_range: Range, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyIncomingCallsParams { + pub item: CallHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents an incoming call, e.g. a caller of a method or constructor. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyIncomingCall { + /// The item that makes the call. + pub from: CallHierarchyItem, + + /// The range at which at which the calls appears. This is relative to the caller + /// denoted by [`this.from`](#CallHierarchyIncomingCall.from). + pub from_ranges: Vec, +} + +#[derive(Debug, PartialEq, Clone, Deserialize, Serialize)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyOutgoingCallsParams { + pub item: CallHierarchyItem, + + #[serde(flatten)] + pub work_done_progress_params: WorkDoneProgressParams, + + #[serde(flatten)] + pub partial_result_params: PartialResultParams, +} + +/// Represents an outgoing call, e.g. calling a getter from a method or a method from a constructor etc. +#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)] +#[serde(rename_all = "camelCase")] +#[cfg(feature = "proposed")] +pub struct CallHierarchyOutgoingCall { + /// The item that is called. + pub to: CallHierarchyItem, + + /// The range at which this item is called. This is the range relative to the caller, e.g the item + /// passed to [`provideCallHierarchyOutgoingCalls`](#CallHierarchyItemProvider.provideCallHierarchyOutgoingCalls) + /// and not [`this.to`](#CallHierarchyOutgoingCall.to). + pub from_ranges: Vec, +} + +#[cfg(test)] +mod tests { + use super::*; + use serde::{Deserialize, Serialize}; + + fn test_serialization(ms: &SER, expected: &str) + where + SER: Serialize + for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, + { + let json_str = serde_json::to_string(ms).unwrap(); + assert_eq!(&json_str, expected); + let deserialized: SER = serde_json::from_str(&json_str).unwrap(); + assert_eq!(&deserialized, ms); + } + + fn test_deserialization(json: &str, expected: &T) + where + T: for<'de> Deserialize<'de> + PartialEq + std::fmt::Debug, + { + let value = serde_json::from_str::(json).unwrap(); + assert_eq!(&value, expected); + } + + #[test] + fn number_or_string() { + test_serialization(&NumberOrString::Number(123), r#"123"#); + + test_serialization(&NumberOrString::String("abcd".into()), r#""abcd""#); + } + + #[test] + fn marked_string() { + test_serialization(&MarkedString::from_markdown("xxx".into()), r#""xxx""#); + + test_serialization( + &MarkedString::from_language_code("lang".into(), "code".into()), + r#"{"language":"lang","value":"code"}"#, + ); + } + + #[test] + fn language_string() { + test_serialization( + &LanguageString { + language: "LL".into(), + value: "VV".into(), + }, + r#"{"language":"LL","value":"VV"}"#, + ); + } + + #[test] + fn workspace_edit() { + test_serialization( + &WorkspaceEdit { + changes: Some(vec![].into_iter().collect()), + document_changes: None, + }, + r#"{"changes":{}}"#, + ); + + test_serialization( + &WorkspaceEdit { + changes: None, + document_changes: None, + }, + r#"{}"#, + ); + + test_serialization( + &WorkspaceEdit { + changes: Some( + vec![(Url::parse("file://test").unwrap(), vec![])] + .into_iter() + .collect(), + ), + document_changes: None, + }, + r#"{"changes":{"file://test/":[]}}"#, + ); + } + + #[test] + fn formatting_options() { + test_serialization( + &FormattingOptions { + tab_size: 123, + insert_spaces: true, + properties: HashMap::new(), + trim_trailing_whitespace: None, + insert_final_newline: None, + trim_final_newlines: None, + }, + r#"{"tabSize":123,"insertSpaces":true}"#, + ); + + test_serialization( + &FormattingOptions { + tab_size: 123, + insert_spaces: true, + properties: vec![("prop".to_string(), FormattingProperty::Number(1.0))] + .into_iter() + .collect(), + trim_trailing_whitespace: None, + insert_final_newline: None, + trim_final_newlines: None, + }, + r#"{"tabSize":123,"insertSpaces":true,"prop":1.0}"#, + ); + } + + #[test] + fn root_uri_can_be_missing() { + serde_json::from_str::(r#"{ "capabilities": {} }"#).unwrap(); + } + + #[test] + fn test_watch_kind() { + test_serialization(&WatchKind::Create, "1"); + test_serialization(&(WatchKind::Create | WatchKind::Change), "3"); + test_serialization( + &(WatchKind::Create | WatchKind::Change | WatchKind::Delete), + "7", + ); + } + + #[test] + fn test_resource_operation_kind() { + test_serialization( + &vec![ + ResourceOperationKind::Create, + ResourceOperationKind::Rename, + ResourceOperationKind::Delete, + ], + r#"["create","rename","delete"]"#, + ); + } + + #[test] + fn test_code_action_response() { + test_serialization( + &vec![ + CodeActionOrCommand::Command(Command { + title: "title".to_string(), + command: "command".to_string(), + arguments: None, + }), + CodeActionOrCommand::CodeAction(CodeAction { + title: "title".to_string(), + kind: Some(CodeActionKind::QUICKFIX), + command: None, + diagnostics: None, + edit: None, + is_preferred: None, + }), + ], + r#"[{"title":"title","command":"command"},{"title":"title","kind":"quickfix"}]"#, + ) + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_highlighting_information_serialization() { + test_serialization( + &SemanticHighlightingInformation { + line: 10, + tokens: Some(vec![ + SemanticHighlightingToken { + character: 0x00000001, + length: 0x0002, + scope: 0x0003, + }, + SemanticHighlightingToken { + character: 0x00112222, + length: 0x0FF0, + scope: 0x0202, + }, + ]), + }, + r#"{"line":10,"tokens":"AAAAAQACAAMAESIiD/ACAg=="}"#, + ); + + test_serialization( + &SemanticHighlightingInformation { + line: 22, + tokens: None, + }, + r#"{"line":22}"#, + ); + } + + #[test] + fn test_tag_support_deserialization() { + let mut empty = CompletionItemCapability::default(); + empty.tag_support = None; + + test_deserialization(r#"{}"#, &empty); + test_deserialization(r#"{"tagSupport": false}"#, &empty); + + let mut t = CompletionItemCapability::default(); + t.tag_support = Some(TagSupport { value_set: vec![] }); + test_deserialization(r#"{"tagSupport": true}"#, &t); + + let mut t = CompletionItemCapability::default(); + t.tag_support = Some(TagSupport { + value_set: vec![CompletionItemTag::Deprecated], + }); + test_deserialization(r#"{"tagSupport": {"valueSet": [1]}}"#, &t); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_support_serialization() { + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![], + }, + r#"{"data":[]}"#, + ); + + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }], + }, + r#"{"data":[2,5,3,0,3]}"#, + ); + + test_serialization( + &SemanticTokens { + result_id: None, + data: vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ], + }, + r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, + ); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_support_deserialization() { + test_deserialization( + r#"{"data":[]}"#, + &SemanticTokens { + result_id: None, + data: vec![], + }, + ); + + test_deserialization( + r#"{"data":[2,5,3,0,3]}"#, + &SemanticTokens { + result_id: None, + data: vec![SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }], + }, + ); + + test_deserialization( + r#"{"data":[2,5,3,0,3,0,5,4,1,0]}"#, + &SemanticTokens { + result_id: None, + data: vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ], + }, + ); + } + + #[cfg(feature = "proposed")] + #[test] + #[should_panic] + fn test_semantic_tokens_support_deserialization_err() { + test_deserialization( + r#"{"data":[1]}"#, + &SemanticTokens { + result_id: None, + data: vec![], + }, + ); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_edit_support_deserialization() { + test_deserialization( + r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: Some(vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ]), + }, + ); + + test_deserialization( + r#"{"start":0,"deleteCount":1}"#, + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: None, + }, + ); + } + + #[cfg(feature = "proposed")] + #[test] + fn test_semantic_tokens_edit_support_serialization() { + test_serialization( + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: Some(vec![ + SemanticToken { + delta_line: 2, + delta_start: 5, + length: 3, + token_type: 0, + token_modifiers_bitset: 3, + }, + SemanticToken { + delta_line: 0, + delta_start: 5, + length: 4, + token_type: 1, + token_modifiers_bitset: 0, + }, + ]), + }, + r#"{"start":0,"deleteCount":1,"data":[2,5,3,0,3,0,5,4,1,0]}"#, + ); + + test_serialization( + &SemanticTokensEdit { + start: 0, + delete_count: 1, + data: None, + }, + r#"{"start":0,"deleteCount":1}"#, + ); + } +} diff --git a/vendor/lsp-types/src/notification.rs b/vendor/lsp-types/src/notification.rs index 272eb27c7f..3468cf1ed3 100644 --- a/vendor/lsp-types/src/notification.rs +++ b/vendor/lsp-types/src/notification.rs @@ -1,304 +1,304 @@ -use super::*; - -use serde::{de::DeserializeOwned, Serialize}; - -pub trait Notification { - type Params: DeserializeOwned + Serialize; - const METHOD: &'static str; -} - -#[macro_export] -macro_rules! lsp_notification { - ("$/cancelRequest") => { - $crate::notification::Cancel - }; - ("initialized") => { - $crate::notification::Initialized - }; - ("exit") => { - $crate::notification::Exit - }; - - ("window/showMessage") => { - $crate::notification::ShowMessage - }; - ("window/logMessage") => { - $crate::notification::LogMessage - }; - ("window/workDoneProgress/cancel") => { - $crate::notification::WorkDoneProgressCancel - }; - - ("telemetry/event") => { - $crate::notification::TelemetryEvent - }; - - ("textDocument/didOpen") => { - $crate::notification::DidOpenTextDocument - }; - ("textDocument/didChange") => { - $crate::notification::DidChangeTextDocument - }; - ("textDocument/willSave") => { - $crate::notification::WillSaveTextDocument - }; - ("textDocument/didSave") => { - $crate::notification::DidSaveTextDocument - }; - ("textDocument/didClose") => { - $crate::notification::DidCloseTextDocument - }; - ("textDocument/publishDiagnostics") => { - $crate::notification::PublishDiagnostics - }; - - ("workspace/didChangeConfiguration") => { - $crate::notification::DidChangeConfiguration - }; - ("workspace/didChangeWatchedFiles") => { - $crate::notification::DidChangeWatchedFiles - }; - ("workspace/didChangeWorkspaceFolders") => { - $crate::notification::DidChangeWorkspaceFolders - }; - ("$/progress") => { - $crate::notification::Progress - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticHighlighting") => { - $crate::notification::SemanticHighlighting - }; -} - -/// The base protocol now offers support for request cancellation. To cancel a request, -/// a notification message with the following properties is sent: -/// -/// A request that got canceled still needs to return from the server and send a response back. -/// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires -/// that every request sends a response back. In addition it allows for returning partial results on cancel. -#[derive(Debug)] -pub enum Cancel {} - -impl Notification for Cancel { - type Params = CancelParams; - const METHOD: &'static str = "$/cancelRequest"; -} - -/// The initialized notification is sent from the client to the server after the client received -/// the result of the initialize request but before the client is sending any other request or -/// notification to the server. The server can use the initialized notification for example to -/// dynamically register capabilities. -#[derive(Debug)] -pub enum Initialized {} - -impl Notification for Initialized { - type Params = InitializedParams; - const METHOD: &'static str = "initialized"; -} - -/// A notification to ask the server to exit its process. -/// The server should exit with success code 0 if the shutdown request has been received before; -/// otherwise with error code 1. -#[derive(Debug)] -pub enum Exit {} - -impl Notification for Exit { - type Params = (); - const METHOD: &'static str = "exit"; -} - -/// The show message notification is sent from a server to a client to ask the client to display a particular message -/// in the user interface. -#[derive(Debug)] -pub enum ShowMessage {} - -impl Notification for ShowMessage { - type Params = ShowMessageParams; - const METHOD: &'static str = "window/showMessage"; -} - -/// The log message notification is sent from the server to the client to ask the client to log a particular message. -#[derive(Debug)] -pub enum LogMessage {} - -impl Notification for LogMessage { - type Params = LogMessageParams; - const METHOD: &'static str = "window/logMessage"; -} - -/// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event. -#[derive(Debug)] -pub enum TelemetryEvent {} - -impl Notification for TelemetryEvent { - type Params = serde_json::Value; - const METHOD: &'static str = "telemetry/event"; -} - -/// A notification sent from the client to the server to signal the change of configuration settings. -#[derive(Debug)] -pub enum DidChangeConfiguration {} - -impl Notification for DidChangeConfiguration { - type Params = DidChangeConfigurationParams; - const METHOD: &'static str = "workspace/didChangeConfiguration"; -} - -/// The document open notification is sent from the client to the server to signal newly opened text documents. -/// The document's truth is now managed by the client and the server must not try to read the document's truth -/// using the document's uri. -#[derive(Debug)] -pub enum DidOpenTextDocument {} - -impl Notification for DidOpenTextDocument { - type Params = DidOpenTextDocumentParams; - const METHOD: &'static str = "textDocument/didOpen"; -} - -/// The document change notification is sent from the client to the server to signal changes to a text document. -/// In 2.0 the shape of the params has changed to include proper version numbers and language ids. -#[derive(Debug)] -pub enum DidChangeTextDocument {} - -impl Notification for DidChangeTextDocument { - type Params = DidChangeTextDocumentParams; - const METHOD: &'static str = "textDocument/didChange"; -} - -/// The document will save notification is sent from the client to the server before the document -/// is actually saved. -#[derive(Debug)] -pub enum WillSaveTextDocument {} - -impl Notification for WillSaveTextDocument { - type Params = WillSaveTextDocumentParams; - const METHOD: &'static str = "textDocument/willSave"; -} - -/// The document close notification is sent from the client to the server when the document got closed in the client. -/// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri -/// the truth now exists on disk). -#[derive(Debug)] -pub enum DidCloseTextDocument {} - -impl Notification for DidCloseTextDocument { - type Params = DidCloseTextDocumentParams; - const METHOD: &'static str = "textDocument/didClose"; -} - -/// The document save notification is sent from the client to the server when the document was saved in the client. -#[derive(Debug)] -pub enum DidSaveTextDocument {} - -impl Notification for DidSaveTextDocument { - type Params = DidSaveTextDocumentParams; - const METHOD: &'static str = "textDocument/didSave"; -} - -/// The watched files notification is sent from the client to the server when the client detects changes to files -/// watched by the language client. -#[derive(Debug)] -pub enum DidChangeWatchedFiles {} - -impl Notification for DidChangeWatchedFiles { - type Params = DidChangeWatchedFilesParams; - const METHOD: &'static str = "workspace/didChangeWatchedFiles"; -} - -/// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server -/// about workspace folder configuration changes -#[derive(Debug)] -pub enum DidChangeWorkspaceFolders {} - -impl Notification for DidChangeWorkspaceFolders { - type Params = DidChangeWorkspaceFoldersParams; - const METHOD: &'static str = "workspace/didChangeWorkspaceFolders"; -} - -/// Diagnostics notification are sent from the server to the client to signal results of validation runs. -#[derive(Debug)] -pub enum PublishDiagnostics {} - -impl Notification for PublishDiagnostics { - type Params = PublishDiagnosticsParams; - const METHOD: &'static str = "textDocument/publishDiagnostics"; -} - -/// The progress notification is sent from the server to the client to ask -/// the client to indicate progress. -#[derive(Debug)] -pub enum Progress {} - -impl Notification for Progress { - type Params = ProgressParams; - const METHOD: &'static str = "$/progress"; -} - -/// The `window/workDoneProgress/cancel` notification is sent from the client -/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. -#[derive(Debug)] -pub enum WorkDoneProgressCancel {} - -impl Notification for WorkDoneProgressCancel { - type Params = WorkDoneProgressCancelParams; - const METHOD: &'static str = "window/workDoneProgress/cancel"; -} - -#[cfg(feature = "proposed")] -/// Diagnostics notification are sent from the server to the client to signal results of validation runs. -#[derive(Debug)] -pub enum SemanticHighlighting {} - -#[cfg(feature = "proposed")] -impl Notification for SemanticHighlighting { - type Params = SemanticHighlightingParams; - const METHOD: &'static str = "textDocument/semanticHighlighting"; -} - -#[cfg(test)] -mod test { - use super::*; - - fn fake_call() - where - N: Notification, - N::Params: serde::Serialize, - { - } - - macro_rules! check_macro { - ($name:tt) => { - // check whether the macro name matches the method - assert_eq!(::METHOD, $name); - // test whether type checking passes for each component - fake_call::(); - }; - } - - #[test] - fn check_macro_definitions() { - check_macro!("$/cancelRequest"); - check_macro!("$/progress"); - check_macro!("initialized"); - check_macro!("exit"); - check_macro!("window/showMessage"); - check_macro!("window/logMessage"); - check_macro!("window/workDoneProgress/cancel"); - check_macro!("telemetry/event"); - check_macro!("textDocument/didOpen"); - check_macro!("textDocument/didChange"); - check_macro!("textDocument/willSave"); - check_macro!("textDocument/didSave"); - check_macro!("textDocument/didClose"); - check_macro!("textDocument/publishDiagnostics"); - check_macro!("workspace/didChangeConfiguration"); - check_macro!("workspace/didChangeWatchedFiles"); - check_macro!("workspace/didChangeWorkspaceFolders"); - } - - #[test] - #[cfg(feature = "proposed")] - fn check_proposed_macro_definitions() { - check_macro!("textDocument/semanticHighlighting"); - } -} +use super::*; + +use serde::{de::DeserializeOwned, Serialize}; + +pub trait Notification { + type Params: DeserializeOwned + Serialize; + const METHOD: &'static str; +} + +#[macro_export] +macro_rules! lsp_notification { + ("$/cancelRequest") => { + $crate::notification::Cancel + }; + ("initialized") => { + $crate::notification::Initialized + }; + ("exit") => { + $crate::notification::Exit + }; + + ("window/showMessage") => { + $crate::notification::ShowMessage + }; + ("window/logMessage") => { + $crate::notification::LogMessage + }; + ("window/workDoneProgress/cancel") => { + $crate::notification::WorkDoneProgressCancel + }; + + ("telemetry/event") => { + $crate::notification::TelemetryEvent + }; + + ("textDocument/didOpen") => { + $crate::notification::DidOpenTextDocument + }; + ("textDocument/didChange") => { + $crate::notification::DidChangeTextDocument + }; + ("textDocument/willSave") => { + $crate::notification::WillSaveTextDocument + }; + ("textDocument/didSave") => { + $crate::notification::DidSaveTextDocument + }; + ("textDocument/didClose") => { + $crate::notification::DidCloseTextDocument + }; + ("textDocument/publishDiagnostics") => { + $crate::notification::PublishDiagnostics + }; + + ("workspace/didChangeConfiguration") => { + $crate::notification::DidChangeConfiguration + }; + ("workspace/didChangeWatchedFiles") => { + $crate::notification::DidChangeWatchedFiles + }; + ("workspace/didChangeWorkspaceFolders") => { + $crate::notification::DidChangeWorkspaceFolders + }; + ("$/progress") => { + $crate::notification::Progress + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticHighlighting") => { + $crate::notification::SemanticHighlighting + }; +} + +/// The base protocol now offers support for request cancellation. To cancel a request, +/// a notification message with the following properties is sent: +/// +/// A request that got canceled still needs to return from the server and send a response back. +/// It can not be left open / hanging. This is in line with the JSON RPC protocol that requires +/// that every request sends a response back. In addition it allows for returning partial results on cancel. +#[derive(Debug)] +pub enum Cancel {} + +impl Notification for Cancel { + type Params = CancelParams; + const METHOD: &'static str = "$/cancelRequest"; +} + +/// The initialized notification is sent from the client to the server after the client received +/// the result of the initialize request but before the client is sending any other request or +/// notification to the server. The server can use the initialized notification for example to +/// dynamically register capabilities. +#[derive(Debug)] +pub enum Initialized {} + +impl Notification for Initialized { + type Params = InitializedParams; + const METHOD: &'static str = "initialized"; +} + +/// A notification to ask the server to exit its process. +/// The server should exit with success code 0 if the shutdown request has been received before; +/// otherwise with error code 1. +#[derive(Debug)] +pub enum Exit {} + +impl Notification for Exit { + type Params = (); + const METHOD: &'static str = "exit"; +} + +/// The show message notification is sent from a server to a client to ask the client to display a particular message +/// in the user interface. +#[derive(Debug)] +pub enum ShowMessage {} + +impl Notification for ShowMessage { + type Params = ShowMessageParams; + const METHOD: &'static str = "window/showMessage"; +} + +/// The log message notification is sent from the server to the client to ask the client to log a particular message. +#[derive(Debug)] +pub enum LogMessage {} + +impl Notification for LogMessage { + type Params = LogMessageParams; + const METHOD: &'static str = "window/logMessage"; +} + +/// The telemetry notification is sent from the server to the client to ask the client to log a telemetry event. +#[derive(Debug)] +pub enum TelemetryEvent {} + +impl Notification for TelemetryEvent { + type Params = serde_json::Value; + const METHOD: &'static str = "telemetry/event"; +} + +/// A notification sent from the client to the server to signal the change of configuration settings. +#[derive(Debug)] +pub enum DidChangeConfiguration {} + +impl Notification for DidChangeConfiguration { + type Params = DidChangeConfigurationParams; + const METHOD: &'static str = "workspace/didChangeConfiguration"; +} + +/// The document open notification is sent from the client to the server to signal newly opened text documents. +/// The document's truth is now managed by the client and the server must not try to read the document's truth +/// using the document's uri. +#[derive(Debug)] +pub enum DidOpenTextDocument {} + +impl Notification for DidOpenTextDocument { + type Params = DidOpenTextDocumentParams; + const METHOD: &'static str = "textDocument/didOpen"; +} + +/// The document change notification is sent from the client to the server to signal changes to a text document. +/// In 2.0 the shape of the params has changed to include proper version numbers and language ids. +#[derive(Debug)] +pub enum DidChangeTextDocument {} + +impl Notification for DidChangeTextDocument { + type Params = DidChangeTextDocumentParams; + const METHOD: &'static str = "textDocument/didChange"; +} + +/// The document will save notification is sent from the client to the server before the document +/// is actually saved. +#[derive(Debug)] +pub enum WillSaveTextDocument {} + +impl Notification for WillSaveTextDocument { + type Params = WillSaveTextDocumentParams; + const METHOD: &'static str = "textDocument/willSave"; +} + +/// The document close notification is sent from the client to the server when the document got closed in the client. +/// The document's truth now exists where the document's uri points to (e.g. if the document's uri is a file uri +/// the truth now exists on disk). +#[derive(Debug)] +pub enum DidCloseTextDocument {} + +impl Notification for DidCloseTextDocument { + type Params = DidCloseTextDocumentParams; + const METHOD: &'static str = "textDocument/didClose"; +} + +/// The document save notification is sent from the client to the server when the document was saved in the client. +#[derive(Debug)] +pub enum DidSaveTextDocument {} + +impl Notification for DidSaveTextDocument { + type Params = DidSaveTextDocumentParams; + const METHOD: &'static str = "textDocument/didSave"; +} + +/// The watched files notification is sent from the client to the server when the client detects changes to files +/// watched by the language client. +#[derive(Debug)] +pub enum DidChangeWatchedFiles {} + +impl Notification for DidChangeWatchedFiles { + type Params = DidChangeWatchedFilesParams; + const METHOD: &'static str = "workspace/didChangeWatchedFiles"; +} + +/// The workspace/didChangeWorkspaceFolders notification is sent from the client to the server to inform the server +/// about workspace folder configuration changes +#[derive(Debug)] +pub enum DidChangeWorkspaceFolders {} + +impl Notification for DidChangeWorkspaceFolders { + type Params = DidChangeWorkspaceFoldersParams; + const METHOD: &'static str = "workspace/didChangeWorkspaceFolders"; +} + +/// Diagnostics notification are sent from the server to the client to signal results of validation runs. +#[derive(Debug)] +pub enum PublishDiagnostics {} + +impl Notification for PublishDiagnostics { + type Params = PublishDiagnosticsParams; + const METHOD: &'static str = "textDocument/publishDiagnostics"; +} + +/// The progress notification is sent from the server to the client to ask +/// the client to indicate progress. +#[derive(Debug)] +pub enum Progress {} + +impl Notification for Progress { + type Params = ProgressParams; + const METHOD: &'static str = "$/progress"; +} + +/// The `window/workDoneProgress/cancel` notification is sent from the client +/// to the server to cancel a progress initiated on the server side using the `window/workDoneProgress/create`. +#[derive(Debug)] +pub enum WorkDoneProgressCancel {} + +impl Notification for WorkDoneProgressCancel { + type Params = WorkDoneProgressCancelParams; + const METHOD: &'static str = "window/workDoneProgress/cancel"; +} + +#[cfg(feature = "proposed")] +/// Diagnostics notification are sent from the server to the client to signal results of validation runs. +#[derive(Debug)] +pub enum SemanticHighlighting {} + +#[cfg(feature = "proposed")] +impl Notification for SemanticHighlighting { + type Params = SemanticHighlightingParams; + const METHOD: &'static str = "textDocument/semanticHighlighting"; +} + +#[cfg(test)] +mod test { + use super::*; + + fn fake_call() + where + N: Notification, + N::Params: serde::Serialize, + { + } + + macro_rules! check_macro { + ($name:tt) => { + // check whether the macro name matches the method + assert_eq!(::METHOD, $name); + // test whether type checking passes for each component + fake_call::(); + }; + } + + #[test] + fn check_macro_definitions() { + check_macro!("$/cancelRequest"); + check_macro!("$/progress"); + check_macro!("initialized"); + check_macro!("exit"); + check_macro!("window/showMessage"); + check_macro!("window/logMessage"); + check_macro!("window/workDoneProgress/cancel"); + check_macro!("telemetry/event"); + check_macro!("textDocument/didOpen"); + check_macro!("textDocument/didChange"); + check_macro!("textDocument/willSave"); + check_macro!("textDocument/didSave"); + check_macro!("textDocument/didClose"); + check_macro!("textDocument/publishDiagnostics"); + check_macro!("workspace/didChangeConfiguration"); + check_macro!("workspace/didChangeWatchedFiles"); + check_macro!("workspace/didChangeWorkspaceFolders"); + } + + #[test] + #[cfg(feature = "proposed")] + fn check_proposed_macro_definitions() { + check_macro!("textDocument/semanticHighlighting"); + } +} diff --git a/vendor/lsp-types/src/request.rs b/vendor/lsp-types/src/request.rs index 53073a96e4..3238697776 100644 --- a/vendor/lsp-types/src/request.rs +++ b/vendor/lsp-types/src/request.rs @@ -1,739 +1,739 @@ -use super::*; - -use serde::{de::DeserializeOwned, Serialize}; - -pub trait Request { - type Params: DeserializeOwned + Serialize; - type Result: DeserializeOwned + Serialize; - const METHOD: &'static str; -} - -#[macro_export] -macro_rules! lsp_request { - ("initialize") => { - $crate::request::Initialize - }; - ("shutdown") => { - $crate::request::Shutdown - }; - - ("window/showMessageRequest") => { - $crate::request::ShowMessageRequest - }; - - ("client/registerCapability") => { - $crate::request::RegisterCapability - }; - ("client/unregisterCapability") => { - $crate::request::UnregisterCapability - }; - - ("workspace/symbol") => { - $crate::request::WorkspaceSymbol - }; - ("workspace/executeCommand") => { - $crate::request::ExecuteCommand - }; - - ("textDocument/willSaveWaitUntil") => { - $crate::request::WillSaveWaitUntil - }; - - ("textDocument/completion") => { - $crate::request::Completion - }; - ("completionItem/resolve") => { - $crate::request::ResolveCompletionItem - }; - ("textDocument/hover") => { - $crate::request::HoverRequest - }; - ("textDocument/signatureHelp") => { - $crate::request::SignatureHelpRequest - }; - ("textDocument/declaration") => { - $crate::request::GotoDeclaration - }; - ("textDocument/definition") => { - $crate::request::GotoDefinition - }; - ("textDocument/references") => { - $crate::request::References - }; - ("textDocument/documentHighlight") => { - $crate::request::DocumentHighlightRequest - }; - ("textDocument/documentSymbol") => { - $crate::request::DocumentSymbolRequest - }; - ("textDocument/codeAction") => { - $crate::request::CodeActionRequest - }; - ("textDocument/codeLens") => { - $crate::request::CodeLensRequest - }; - ("codeLens/resolve") => { - $crate::request::CodeLensResolve - }; - ("textDocument/documentLink") => { - $crate::request::DocumentLinkRequest - }; - ("documentLink/resolve") => { - $crate::request::DocumentLinkResolve - }; - ("workspace/applyEdit") => { - $crate::request::ApplyWorkspaceEdit - }; - ("textDocument/rangeFormatting") => { - $crate::request::RangeFormatting - }; - ("textDocument/onTypeFormatting") => { - $crate::request::OnTypeFormatting - }; - ("textDocument/formatting") => { - $crate::request::Formatting - }; - ("textDocument/rename") => { - $crate::request::Rename - }; - ("textDocument/documentColor") => { - $crate::request::DocumentColor - }; - ("textDocument/colorPresentation") => { - $crate::request::ColorPresentationRequest - }; - ("textDocument/foldingRange") => { - $crate::request::FoldingRangeRequest - }; - ("textDocument/prepareRename") => { - $crate::request::PrepareRenameRequest - }; - ("textDocument/implementation") => { - $crate::request::GotoImplementation - }; - ("textDocument/typeDefinition") => { - $crate::request::GotoTypeDefinition - }; - ("textDocument/selectionRange") => { - $crate::request::SelectionRangeRequest - }; - ("workspace/workspaceFolders") => { - $crate::request::WorkspaceFoldersRequest - }; - ("workspace/configuration") => { - $crate::request::WorkspaceConfiguration - }; - ("window/workDoneProgress/create") => { - $crate::request::WorkDoneProgressCreate - }; - // Requires #[cfg(feature = "proposed")] - ("callHierarchy/incomingCalls") => { - $crate::request::CallHierarchyIncomingCalls - }; - // Requires #[cfg(feature = "proposed")] - ("callHierarchy/outgoingCalls") => { - $crate::request::CallHierarchyOutgoingCalls - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/prepareCallHierarchy") => { - $crate::request::CallHierarchyPrepare - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticTokens") => { - $crate::request::SemanticTokensRequest - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticTokens/edits") => { - $crate::request::SemanticTokensEditsRequest - }; - // Requires #[cfg(feature = "proposed")] - ("textDocument/semanticTokens/range") => { - $crate::request::SemanticTokensRangeRequest - }; -} - -/// The initialize request is sent as the first request from the client to the server. -/// If the server receives request or notification before the `initialize` request it should act as follows: -/// -/// * for a request the respond should be errored with `code: -32001`. The message can be picked by the server. -/// * notifications should be dropped. -#[derive(Debug)] -pub enum Initialize {} - -impl Request for Initialize { - type Params = InitializeParams; - type Result = InitializeResult; - const METHOD: &'static str = "initialize"; -} - -/// The shutdown request is sent from the client to the server. It asks the server to shut down, -/// but to not exit (otherwise the response might not be delivered correctly to the client). -/// There is a separate exit notification that asks the server to exit. -#[derive(Debug)] -pub enum Shutdown {} - -impl Request for Shutdown { - type Params = (); - type Result = (); - const METHOD: &'static str = "shutdown"; -} - -/// The show message request is sent from a server to a client to ask the client to display a particular message -/// in the user interface. In addition to the show message notification the request allows to pass actions and to -/// wait for an answer from the client. -#[derive(Debug)] -pub enum ShowMessageRequest {} - -impl Request for ShowMessageRequest { - type Params = ShowMessageRequestParams; - type Result = Option; - const METHOD: &'static str = "window/showMessageRequest"; -} - -/// The client/registerCapability request is sent from the server to the client to register for a new capability -/// on the client side. Not all clients need to support dynamic capability registration. A client opts in via the -/// ClientCapabilities.GenericCapability property. -#[derive(Debug)] -pub enum RegisterCapability {} - -impl Request for RegisterCapability { - type Params = RegistrationParams; - type Result = (); - const METHOD: &'static str = "client/registerCapability"; -} - -/// The client/unregisterCapability request is sent from the server to the client to unregister a -/// previously register capability. -#[derive(Debug)] -pub enum UnregisterCapability {} - -impl Request for UnregisterCapability { - type Params = UnregistrationParams; - type Result = (); - const METHOD: &'static str = "client/unregisterCapability"; -} - -/// The Completion request is sent from the client to the server to compute completion items at a given cursor position. -/// Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive, -/// servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve'). -/// This request is sent when a completion item is selected in the user interface. A typical use case is for example: -/// the 'textDocument/completion' request doesn’t fill in the documentation property for returned completion items -/// since it is expensive to compute. When the item is selected in the user interface then a ‘completionItem/resolve’ -/// request is sent with the selected completion item as a param. The returned completion item should have the -/// documentation property filled in. The request can delay the computation of the detail and documentation properties. -/// However, properties that are needed for the initial sorting and filtering, like sortText, filterText, insertText, -/// and textEdit must be provided in the textDocument/completion request and must not be changed during resolve. -#[derive(Debug)] -pub enum Completion {} - -impl Request for Completion { - type Params = CompletionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/completion"; -} - -/// The request is sent from the client to the server to resolve additional information for a given completion item. -#[derive(Debug)] -pub enum ResolveCompletionItem {} - -impl Request for ResolveCompletionItem { - type Params = CompletionItem; - type Result = CompletionItem; - const METHOD: &'static str = "completionItem/resolve"; -} - -/// The hover request is sent from the client to the server to request hover information at a given text -/// document position. -#[derive(Debug)] -pub enum HoverRequest {} - -impl Request for HoverRequest { - type Params = HoverParams; - type Result = Option; - const METHOD: &'static str = "textDocument/hover"; -} - -/// The signature help request is sent from the client to the server to request signature information at -/// a given cursor position. -#[derive(Debug)] -pub enum SignatureHelpRequest {} - -impl Request for SignatureHelpRequest { - type Params = SignatureHelpParams; - type Result = Option; - const METHOD: &'static str = "textDocument/signatureHelp"; -} - -#[derive(Debug)] -pub enum GotoDeclaration {} -pub type GotoDeclarationParams = GotoDefinitionParams; -pub type GotoDeclarationResponse = GotoDefinitionResponse; - -/// The goto declaration request is sent from the client to the server to resolve the declaration location of -/// a symbol at a given text document position. -impl Request for GotoDeclaration { - type Params = GotoDeclarationParams; - type Result = Option; - const METHOD: &'static str = "textDocument/declaration"; -} - -/// The goto definition request is sent from the client to the server to resolve the definition location of -/// a symbol at a given text document position. -#[derive(Debug)] -pub enum GotoDefinition {} - -impl Request for GotoDefinition { - type Params = GotoDefinitionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/definition"; -} - -/// The references request is sent from the client to the server to resolve project-wide references for the -/// symbol denoted by the given text document position. -#[derive(Debug)] -pub enum References {} - -impl Request for References { - type Params = ReferenceParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/references"; -} - -/// The goto type definition request is sent from the client to the -/// server to resolve the type definition location of a symbol at a -/// given text document position. -#[derive(Debug)] -pub enum GotoTypeDefinition {} - -pub type GotoTypeDefinitionParams = GotoDefinitionParams; -pub type GotoTypeDefinitionResponse = GotoDefinitionResponse; - -impl Request for GotoTypeDefinition { - type Params = GotoTypeDefinitionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/typeDefinition"; -} - -/// The goto implementation request is sent from the client to the -/// server to resolve the implementation location of a symbol at a -/// given text document position. -#[derive(Debug)] -pub enum GotoImplementation {} - -pub type GotoImplementationParams = GotoTypeDefinitionParams; -pub type GotoImplementationResponse = GotoDefinitionResponse; - -impl Request for GotoImplementation { - type Params = GotoImplementationParams; - type Result = Option; - const METHOD: &'static str = "textDocument/implementation"; -} - -/// The document highlight request is sent from the client to the server to resolve a document highlights -/// for a given text document position. -/// For programming languages this usually highlights all references to the symbol scoped to this file. -/// However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since -/// the first one is allowed to be more fuzzy. -/// Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches -/// use Text as the kind. -#[derive(Debug)] -pub enum DocumentHighlightRequest {} - -impl Request for DocumentHighlightRequest { - type Params = DocumentHighlightParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/documentHighlight"; -} - -/// The document symbol request is sent from the client to the server to list all symbols found in a given -/// text document. -#[derive(Debug)] -pub enum DocumentSymbolRequest {} - -impl Request for DocumentSymbolRequest { - type Params = DocumentSymbolParams; - type Result = Option; - const METHOD: &'static str = "textDocument/documentSymbol"; -} - -/// The workspace symbol request is sent from the client to the server to list project-wide symbols -/// matching the query string. -#[derive(Debug)] -pub enum WorkspaceSymbol {} - -impl Request for WorkspaceSymbol { - type Params = WorkspaceSymbolParams; - type Result = Option>; - const METHOD: &'static str = "workspace/symbol"; -} - -/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. -/// In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request -/// workspace/applyEdit which is sent from the server to the client. -#[derive(Debug)] -pub enum ExecuteCommand {} - -impl Request for ExecuteCommand { - type Params = ExecuteCommandParams; - type Result = Option; - const METHOD: &'static str = "workspace/executeCommand"; -} - -/// The document will save request is sent from the client to the server before the document is -/// actually saved. The request can return an array of TextEdits which will be applied to the text -/// document before it is saved. Please note that clients might drop results if computing the text -/// edits took too long or if a server constantly fails on this request. This is done to keep the -/// save fast and reliable. -#[derive(Debug)] -pub enum WillSaveWaitUntil {} - -impl Request for WillSaveWaitUntil { - type Params = WillSaveTextDocumentParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/willSaveWaitUntil"; -} - -/// The workspace/applyEdit request is sent from the server to the client to modify resource on the -/// client side. -#[derive(Debug)] -pub enum ApplyWorkspaceEdit {} - -impl Request for ApplyWorkspaceEdit { - type Params = ApplyWorkspaceEditParams; - type Result = ApplyWorkspaceEditResponse; - const METHOD: &'static str = "workspace/applyEdit"; -} - -/// The workspace/configuration request is sent from the server to the client to fetch configuration settings -/// from the client. The request can fetch several configuration settings in one roundtrip. -/// The order of the returned configuration settings correspond to the order of the passed ConfigurationItems -/// (e.g. the first item in the response is the result for the first configuration item in the params). -/// -/// A ConfigurationItem consists of the configuration section to ask for and an additional scope URI. -/// The configuration section ask for is defined by the server and doesn’t necessarily need to correspond to -/// the configuration store used be the client. So a server might ask for a configuration cpp.formatterOptions -/// but the client stores the configuration in a XML store layout differently. -/// It is up to the client to do the necessary conversion. If a scope URI is provided the client should return -/// the setting scoped to the provided resource. If the client for example uses EditorConfig to manage its -/// settings the configuration should be returned for the passed resource URI. If the client can’t provide a -/// configuration setting for a given scope then null need to be present in the returned array. -#[derive(Debug)] -pub enum WorkspaceConfiguration {} - -impl Request for WorkspaceConfiguration { - type Params = ConfigurationParams; - type Result = Vec; - const METHOD: &'static str = "workspace/configuration"; -} - -/// The code action request is sent from the client to the server to compute commands for a given text document -/// and range. The request is triggered when the user moves the cursor into a problem marker in the editor or -/// presses the lightbulb associated with a marker. -#[derive(Debug)] -pub enum CodeActionRequest {} - -impl Request for CodeActionRequest { - type Params = CodeActionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/codeAction"; -} - -/// The code lens request is sent from the client to the server to compute code lenses for a given text document. -#[derive(Debug)] -pub enum CodeLensRequest {} - -impl Request for CodeLensRequest { - type Params = CodeLensParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/codeLens"; -} - -/// The code lens resolve request is sent from the client to the server to resolve the command for a -/// given code lens item. -#[derive(Debug)] -pub enum CodeLensResolve {} - -impl Request for CodeLensResolve { - type Params = CodeLens; - type Result = CodeLens; - const METHOD: &'static str = "codeLens/resolve"; -} - -/// The document links request is sent from the client to the server to request the location of links in a document. -#[derive(Debug)] -pub enum DocumentLinkRequest {} - -impl Request for DocumentLinkRequest { - type Params = DocumentLinkParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/documentLink"; -} - -/// The document link resolve request is sent from the client to the server to resolve the target of -/// a given document link. -#[derive(Debug)] -pub enum DocumentLinkResolve {} - -impl Request for DocumentLinkResolve { - type Params = DocumentLink; - type Result = DocumentLink; - const METHOD: &'static str = "documentLink/resolve"; -} - -/// The document formatting request is sent from the server to the client to format a whole document. -#[derive(Debug)] -pub enum Formatting {} - -impl Request for Formatting { - type Params = DocumentFormattingParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/formatting"; -} - -/// The document range formatting request is sent from the client to the server to format a given range in a document. -#[derive(Debug)] -pub enum RangeFormatting {} - -impl Request for RangeFormatting { - type Params = DocumentRangeFormattingParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/rangeFormatting"; -} - -/// The document on type formatting request is sent from the client to the server to format parts of -/// the document during typing. -#[derive(Debug)] -pub enum OnTypeFormatting {} - -impl Request for OnTypeFormatting { - type Params = DocumentOnTypeFormattingParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/onTypeFormatting"; -} - -/// The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol. -#[derive(Debug)] -pub enum Rename {} - -impl Request for Rename { - type Params = RenameParams; - type Result = Option; - const METHOD: &'static str = "textDocument/rename"; -} - -/// The document color request is sent from the client to the server to list all color references found in a given text document. -/// Along with the range, a color value in RGB is returned. -#[derive(Debug)] -pub enum DocumentColor {} - -impl Request for DocumentColor { - type Params = DocumentColorParams; - type Result = Vec; - const METHOD: &'static str = "textDocument/documentColor"; -} - -/// The color presentation request is sent from the client to the server to obtain a list of presentations for a color value -/// at a given location. -#[derive(Debug)] -pub enum ColorPresentationRequest {} - -impl Request for ColorPresentationRequest { - type Params = ColorPresentationParams; - type Result = Vec; - const METHOD: &'static str = "textDocument/colorPresentation"; -} - -/// The folding range request is sent from the client to the server to return all folding ranges found in a given text document. -#[derive(Debug)] -pub enum FoldingRangeRequest {} - -impl Request for FoldingRangeRequest { - type Params = FoldingRangeParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/foldingRange"; -} - -/// The prepare rename request is sent from the client to the server to setup and test the validity of a rename operation -/// at a given location. -#[derive(Debug)] -pub enum PrepareRenameRequest {} - -impl Request for PrepareRenameRequest { - type Params = TextDocumentPositionParams; - type Result = Option; - const METHOD: &'static str = "textDocument/prepareRename"; -} - -/// The workspace/workspaceFolders request is sent from the server to the client to fetch the current open list of -/// workspace folders. Returns null in the response if only a single file is open in the tool. -/// Returns an empty array if a workspace is open but no folders are configured. -#[derive(Debug)] -pub enum WorkspaceFoldersRequest {} - -impl Request for WorkspaceFoldersRequest { - type Params = (); - type Result = Option>; - const METHOD: &'static str = "workspace/workspaceFolders"; -} - -/// The `window/workDoneProgress/create` request is sent from the server -/// to the clientto ask the client to create a work done progress. -#[derive(Debug)] -pub enum WorkDoneProgressCreate {} - -impl Request for WorkDoneProgressCreate { - type Params = WorkDoneProgressCreateParams; - type Result = (); - const METHOD: &'static str = "window/workDoneProgress/create"; -} - -/// The selection range request is sent from the client to the server to return -/// suggested selection ranges at given positions. A selection range is a range -/// around the cursor position which the user might be interested in selecting. -/// -/// A selection range in the return array is for the position in the provided parameters at the same index. -/// Therefore positions[i] must be contained in result[i].range. -/// -/// Typically, but not necessary, selection ranges correspond to the nodes of the -/// syntax tree. -pub enum SelectionRangeRequest {} - -impl Request for SelectionRangeRequest { - type Params = SelectionRangeParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/selectionRange"; -} - -#[cfg(feature = "proposed")] -pub enum CallHierarchyPrepare {} - -#[cfg(feature = "proposed")] -impl Request for CallHierarchyPrepare { - type Params = CallHierarchyPrepareParams; - type Result = Option>; - const METHOD: &'static str = "textDocument/prepareCallHierarchy"; -} - -#[cfg(feature = "proposed")] -pub enum CallHierarchyIncomingCalls {} - -#[cfg(feature = "proposed")] -impl Request for CallHierarchyIncomingCalls { - type Params = CallHierarchyIncomingCallsParams; - type Result = Option>; - const METHOD: &'static str = "callHierarchy/incomingCalls"; -} - -#[cfg(feature = "proposed")] -pub enum CallHierarchyOutgoingCalls {} - -#[cfg(feature = "proposed")] -impl Request for CallHierarchyOutgoingCalls { - type Params = CallHierarchyOutgoingCallsParams; - type Result = Option>; - const METHOD: &'static str = "callHierarchy/outgoingCalls"; -} - -#[cfg(feature = "proposed")] -pub enum SemanticTokensRequest {} - -#[cfg(feature = "proposed")] -impl Request for SemanticTokensRequest { - type Params = SemanticTokensParams; - type Result = Option; - const METHOD: &'static str = "textDocument/semanticTokens"; -} - -#[cfg(feature = "proposed")] -pub enum SemanticTokensEditsRequest {} - -#[cfg(feature = "proposed")] -impl Request for SemanticTokensEditsRequest { - type Params = SemanticTokensEditsParams; - type Result = Option; - const METHOD: &'static str = "textDocument/semanticTokens/edits"; -} - -#[cfg(feature = "proposed")] -pub enum SemanticTokensRangeRequest {} - -#[cfg(feature = "proposed")] -impl Request for SemanticTokensRangeRequest { - type Params = SemanticTokensRangeParams; - type Result = Option; - const METHOD: &'static str = "textDocument/semanticTokens/range"; -} - -#[cfg(test)] -mod test { - use super::*; - - fn fake_call() - where - R: Request, - R::Params: serde::Serialize, - R::Result: serde::de::DeserializeOwned, - { - } - - macro_rules! check_macro { - ($name:tt) => { - // check whethe the macro name matches the method - assert_eq!(::METHOD, $name); - // test whether type checking passes for each component - fake_call::(); - }; - } - - #[test] - fn check_macro_definitions() { - check_macro!("initialize"); - check_macro!("shutdown"); - check_macro!("window/showMessageRequest"); - check_macro!("window/workDoneProgress/create"); - check_macro!("client/registerCapability"); - check_macro!("client/unregisterCapability"); - check_macro!("workspace/symbol"); - check_macro!("workspace/executeCommand"); - check_macro!("textDocument/willSaveWaitUntil"); - check_macro!("textDocument/completion"); - check_macro!("completionItem/resolve"); - check_macro!("textDocument/hover"); - check_macro!("textDocument/signatureHelp"); - check_macro!("textDocument/declaration"); - check_macro!("textDocument/definition"); - check_macro!("textDocument/references"); - check_macro!("textDocument/documentHighlight"); - check_macro!("textDocument/documentSymbol"); - check_macro!("textDocument/codeAction"); - check_macro!("textDocument/codeLens"); - check_macro!("codeLens/resolve"); - check_macro!("textDocument/documentLink"); - check_macro!("documentLink/resolve"); - check_macro!("workspace/applyEdit"); - check_macro!("textDocument/rangeFormatting"); - check_macro!("textDocument/onTypeFormatting"); - check_macro!("textDocument/formatting"); - check_macro!("textDocument/rename"); - check_macro!("textDocument/documentColor"); - check_macro!("textDocument/colorPresentation"); - check_macro!("textDocument/foldingRange"); - check_macro!("textDocument/prepareRename"); - check_macro!("workspace/workspaceFolders"); - check_macro!("textDocument/implementation"); - check_macro!("textDocument/selectionRange"); - check_macro!("textDocument/typeDefinition"); - check_macro!("workspace/configuration"); - } - - #[test] - #[cfg(feature = "proposed")] - fn check_proposed_macro_definitions() { - check_macro!("callHierarchy/incomingCalls"); - check_macro!("callHierarchy/outgoingCalls"); - check_macro!("textDocument/prepareCallHierarchy"); - check_macro!("textDocument/semanticTokens"); - check_macro!("textDocument/semanticTokens/edits"); - check_macro!("textDocument/semanticTokens/range"); - } -} +use super::*; + +use serde::{de::DeserializeOwned, Serialize}; + +pub trait Request { + type Params: DeserializeOwned + Serialize; + type Result: DeserializeOwned + Serialize; + const METHOD: &'static str; +} + +#[macro_export] +macro_rules! lsp_request { + ("initialize") => { + $crate::request::Initialize + }; + ("shutdown") => { + $crate::request::Shutdown + }; + + ("window/showMessageRequest") => { + $crate::request::ShowMessageRequest + }; + + ("client/registerCapability") => { + $crate::request::RegisterCapability + }; + ("client/unregisterCapability") => { + $crate::request::UnregisterCapability + }; + + ("workspace/symbol") => { + $crate::request::WorkspaceSymbol + }; + ("workspace/executeCommand") => { + $crate::request::ExecuteCommand + }; + + ("textDocument/willSaveWaitUntil") => { + $crate::request::WillSaveWaitUntil + }; + + ("textDocument/completion") => { + $crate::request::Completion + }; + ("completionItem/resolve") => { + $crate::request::ResolveCompletionItem + }; + ("textDocument/hover") => { + $crate::request::HoverRequest + }; + ("textDocument/signatureHelp") => { + $crate::request::SignatureHelpRequest + }; + ("textDocument/declaration") => { + $crate::request::GotoDeclaration + }; + ("textDocument/definition") => { + $crate::request::GotoDefinition + }; + ("textDocument/references") => { + $crate::request::References + }; + ("textDocument/documentHighlight") => { + $crate::request::DocumentHighlightRequest + }; + ("textDocument/documentSymbol") => { + $crate::request::DocumentSymbolRequest + }; + ("textDocument/codeAction") => { + $crate::request::CodeActionRequest + }; + ("textDocument/codeLens") => { + $crate::request::CodeLensRequest + }; + ("codeLens/resolve") => { + $crate::request::CodeLensResolve + }; + ("textDocument/documentLink") => { + $crate::request::DocumentLinkRequest + }; + ("documentLink/resolve") => { + $crate::request::DocumentLinkResolve + }; + ("workspace/applyEdit") => { + $crate::request::ApplyWorkspaceEdit + }; + ("textDocument/rangeFormatting") => { + $crate::request::RangeFormatting + }; + ("textDocument/onTypeFormatting") => { + $crate::request::OnTypeFormatting + }; + ("textDocument/formatting") => { + $crate::request::Formatting + }; + ("textDocument/rename") => { + $crate::request::Rename + }; + ("textDocument/documentColor") => { + $crate::request::DocumentColor + }; + ("textDocument/colorPresentation") => { + $crate::request::ColorPresentationRequest + }; + ("textDocument/foldingRange") => { + $crate::request::FoldingRangeRequest + }; + ("textDocument/prepareRename") => { + $crate::request::PrepareRenameRequest + }; + ("textDocument/implementation") => { + $crate::request::GotoImplementation + }; + ("textDocument/typeDefinition") => { + $crate::request::GotoTypeDefinition + }; + ("textDocument/selectionRange") => { + $crate::request::SelectionRangeRequest + }; + ("workspace/workspaceFolders") => { + $crate::request::WorkspaceFoldersRequest + }; + ("workspace/configuration") => { + $crate::request::WorkspaceConfiguration + }; + ("window/workDoneProgress/create") => { + $crate::request::WorkDoneProgressCreate + }; + // Requires #[cfg(feature = "proposed")] + ("callHierarchy/incomingCalls") => { + $crate::request::CallHierarchyIncomingCalls + }; + // Requires #[cfg(feature = "proposed")] + ("callHierarchy/outgoingCalls") => { + $crate::request::CallHierarchyOutgoingCalls + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/prepareCallHierarchy") => { + $crate::request::CallHierarchyPrepare + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticTokens/full") => { + $crate::request::SemanticTokensFullRequest + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticTokens/full/delta") => { + $crate::request::SemanticTokensFullDeltaRequest + }; + // Requires #[cfg(feature = "proposed")] + ("textDocument/semanticTokens/range") => { + $crate::request::SemanticTokensRangeRequest + }; +} + +/// The initialize request is sent as the first request from the client to the server. +/// If the server receives request or notification before the `initialize` request it should act as follows: +/// +/// * for a request the respond should be errored with `code: -32001`. The message can be picked by the server. +/// * notifications should be dropped. +#[derive(Debug)] +pub enum Initialize {} + +impl Request for Initialize { + type Params = InitializeParams; + type Result = InitializeResult; + const METHOD: &'static str = "initialize"; +} + +/// The shutdown request is sent from the client to the server. It asks the server to shut down, +/// but to not exit (otherwise the response might not be delivered correctly to the client). +/// There is a separate exit notification that asks the server to exit. +#[derive(Debug)] +pub enum Shutdown {} + +impl Request for Shutdown { + type Params = (); + type Result = (); + const METHOD: &'static str = "shutdown"; +} + +/// The show message request is sent from a server to a client to ask the client to display a particular message +/// in the user interface. In addition to the show message notification the request allows to pass actions and to +/// wait for an answer from the client. +#[derive(Debug)] +pub enum ShowMessageRequest {} + +impl Request for ShowMessageRequest { + type Params = ShowMessageRequestParams; + type Result = Option; + const METHOD: &'static str = "window/showMessageRequest"; +} + +/// The client/registerCapability request is sent from the server to the client to register for a new capability +/// on the client side. Not all clients need to support dynamic capability registration. A client opts in via the +/// ClientCapabilities.GenericCapability property. +#[derive(Debug)] +pub enum RegisterCapability {} + +impl Request for RegisterCapability { + type Params = RegistrationParams; + type Result = (); + const METHOD: &'static str = "client/registerCapability"; +} + +/// The client/unregisterCapability request is sent from the server to the client to unregister a +/// previously register capability. +#[derive(Debug)] +pub enum UnregisterCapability {} + +impl Request for UnregisterCapability { + type Params = UnregistrationParams; + type Result = (); + const METHOD: &'static str = "client/unregisterCapability"; +} + +/// The Completion request is sent from the client to the server to compute completion items at a given cursor position. +/// Completion items are presented in the IntelliSense user interface. If computing full completion items is expensive, +/// servers can additionally provide a handler for the completion item resolve request ('completionItem/resolve'). +/// This request is sent when a completion item is selected in the user interface. A typical use case is for example: +/// the 'textDocument/completion' request doesn’t fill in the documentation property for returned completion items +/// since it is expensive to compute. When the item is selected in the user interface then a ‘completionItem/resolve’ +/// request is sent with the selected completion item as a param. The returned completion item should have the +/// documentation property filled in. The request can delay the computation of the detail and documentation properties. +/// However, properties that are needed for the initial sorting and filtering, like sortText, filterText, insertText, +/// and textEdit must be provided in the textDocument/completion request and must not be changed during resolve. +#[derive(Debug)] +pub enum Completion {} + +impl Request for Completion { + type Params = CompletionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/completion"; +} + +/// The request is sent from the client to the server to resolve additional information for a given completion item. +#[derive(Debug)] +pub enum ResolveCompletionItem {} + +impl Request for ResolveCompletionItem { + type Params = CompletionItem; + type Result = CompletionItem; + const METHOD: &'static str = "completionItem/resolve"; +} + +/// The hover request is sent from the client to the server to request hover information at a given text +/// document position. +#[derive(Debug)] +pub enum HoverRequest {} + +impl Request for HoverRequest { + type Params = HoverParams; + type Result = Option; + const METHOD: &'static str = "textDocument/hover"; +} + +/// The signature help request is sent from the client to the server to request signature information at +/// a given cursor position. +#[derive(Debug)] +pub enum SignatureHelpRequest {} + +impl Request for SignatureHelpRequest { + type Params = SignatureHelpParams; + type Result = Option; + const METHOD: &'static str = "textDocument/signatureHelp"; +} + +#[derive(Debug)] +pub enum GotoDeclaration {} +pub type GotoDeclarationParams = GotoDefinitionParams; +pub type GotoDeclarationResponse = GotoDefinitionResponse; + +/// The goto declaration request is sent from the client to the server to resolve the declaration location of +/// a symbol at a given text document position. +impl Request for GotoDeclaration { + type Params = GotoDeclarationParams; + type Result = Option; + const METHOD: &'static str = "textDocument/declaration"; +} + +/// The goto definition request is sent from the client to the server to resolve the definition location of +/// a symbol at a given text document position. +#[derive(Debug)] +pub enum GotoDefinition {} + +impl Request for GotoDefinition { + type Params = GotoDefinitionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/definition"; +} + +/// The references request is sent from the client to the server to resolve project-wide references for the +/// symbol denoted by the given text document position. +#[derive(Debug)] +pub enum References {} + +impl Request for References { + type Params = ReferenceParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/references"; +} + +/// The goto type definition request is sent from the client to the +/// server to resolve the type definition location of a symbol at a +/// given text document position. +#[derive(Debug)] +pub enum GotoTypeDefinition {} + +pub type GotoTypeDefinitionParams = GotoDefinitionParams; +pub type GotoTypeDefinitionResponse = GotoDefinitionResponse; + +impl Request for GotoTypeDefinition { + type Params = GotoTypeDefinitionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/typeDefinition"; +} + +/// The goto implementation request is sent from the client to the +/// server to resolve the implementation location of a symbol at a +/// given text document position. +#[derive(Debug)] +pub enum GotoImplementation {} + +pub type GotoImplementationParams = GotoTypeDefinitionParams; +pub type GotoImplementationResponse = GotoDefinitionResponse; + +impl Request for GotoImplementation { + type Params = GotoImplementationParams; + type Result = Option; + const METHOD: &'static str = "textDocument/implementation"; +} + +/// The document highlight request is sent from the client to the server to resolve a document highlights +/// for a given text document position. +/// For programming languages this usually highlights all references to the symbol scoped to this file. +/// However we kept 'textDocument/documentHighlight' and 'textDocument/references' separate requests since +/// the first one is allowed to be more fuzzy. +/// Symbol matches usually have a DocumentHighlightKind of Read or Write whereas fuzzy or textual matches +/// use Text as the kind. +#[derive(Debug)] +pub enum DocumentHighlightRequest {} + +impl Request for DocumentHighlightRequest { + type Params = DocumentHighlightParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/documentHighlight"; +} + +/// The document symbol request is sent from the client to the server to list all symbols found in a given +/// text document. +#[derive(Debug)] +pub enum DocumentSymbolRequest {} + +impl Request for DocumentSymbolRequest { + type Params = DocumentSymbolParams; + type Result = Option; + const METHOD: &'static str = "textDocument/documentSymbol"; +} + +/// The workspace symbol request is sent from the client to the server to list project-wide symbols +/// matching the query string. +#[derive(Debug)] +pub enum WorkspaceSymbol {} + +impl Request for WorkspaceSymbol { + type Params = WorkspaceSymbolParams; + type Result = Option>; + const METHOD: &'static str = "workspace/symbol"; +} + +/// The workspace/executeCommand request is sent from the client to the server to trigger command execution on the server. +/// In most cases the server creates a WorkspaceEdit structure and applies the changes to the workspace using the request +/// workspace/applyEdit which is sent from the server to the client. +#[derive(Debug)] +pub enum ExecuteCommand {} + +impl Request for ExecuteCommand { + type Params = ExecuteCommandParams; + type Result = Option; + const METHOD: &'static str = "workspace/executeCommand"; +} + +/// The document will save request is sent from the client to the server before the document is +/// actually saved. The request can return an array of TextEdits which will be applied to the text +/// document before it is saved. Please note that clients might drop results if computing the text +/// edits took too long or if a server constantly fails on this request. This is done to keep the +/// save fast and reliable. +#[derive(Debug)] +pub enum WillSaveWaitUntil {} + +impl Request for WillSaveWaitUntil { + type Params = WillSaveTextDocumentParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/willSaveWaitUntil"; +} + +/// The workspace/applyEdit request is sent from the server to the client to modify resource on the +/// client side. +#[derive(Debug)] +pub enum ApplyWorkspaceEdit {} + +impl Request for ApplyWorkspaceEdit { + type Params = ApplyWorkspaceEditParams; + type Result = ApplyWorkspaceEditResponse; + const METHOD: &'static str = "workspace/applyEdit"; +} + +/// The workspace/configuration request is sent from the server to the client to fetch configuration settings +/// from the client. The request can fetch several configuration settings in one roundtrip. +/// The order of the returned configuration settings correspond to the order of the passed ConfigurationItems +/// (e.g. the first item in the response is the result for the first configuration item in the params). +/// +/// A ConfigurationItem consists of the configuration section to ask for and an additional scope URI. +/// The configuration section ask for is defined by the server and doesn’t necessarily need to correspond to +/// the configuration store used be the client. So a server might ask for a configuration cpp.formatterOptions +/// but the client stores the configuration in a XML store layout differently. +/// It is up to the client to do the necessary conversion. If a scope URI is provided the client should return +/// the setting scoped to the provided resource. If the client for example uses EditorConfig to manage its +/// settings the configuration should be returned for the passed resource URI. If the client can’t provide a +/// configuration setting for a given scope then null need to be present in the returned array. +#[derive(Debug)] +pub enum WorkspaceConfiguration {} + +impl Request for WorkspaceConfiguration { + type Params = ConfigurationParams; + type Result = Vec; + const METHOD: &'static str = "workspace/configuration"; +} + +/// The code action request is sent from the client to the server to compute commands for a given text document +/// and range. The request is triggered when the user moves the cursor into a problem marker in the editor or +/// presses the lightbulb associated with a marker. +#[derive(Debug)] +pub enum CodeActionRequest {} + +impl Request for CodeActionRequest { + type Params = CodeActionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/codeAction"; +} + +/// The code lens request is sent from the client to the server to compute code lenses for a given text document. +#[derive(Debug)] +pub enum CodeLensRequest {} + +impl Request for CodeLensRequest { + type Params = CodeLensParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/codeLens"; +} + +/// The code lens resolve request is sent from the client to the server to resolve the command for a +/// given code lens item. +#[derive(Debug)] +pub enum CodeLensResolve {} + +impl Request for CodeLensResolve { + type Params = CodeLens; + type Result = CodeLens; + const METHOD: &'static str = "codeLens/resolve"; +} + +/// The document links request is sent from the client to the server to request the location of links in a document. +#[derive(Debug)] +pub enum DocumentLinkRequest {} + +impl Request for DocumentLinkRequest { + type Params = DocumentLinkParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/documentLink"; +} + +/// The document link resolve request is sent from the client to the server to resolve the target of +/// a given document link. +#[derive(Debug)] +pub enum DocumentLinkResolve {} + +impl Request for DocumentLinkResolve { + type Params = DocumentLink; + type Result = DocumentLink; + const METHOD: &'static str = "documentLink/resolve"; +} + +/// The document formatting request is sent from the server to the client to format a whole document. +#[derive(Debug)] +pub enum Formatting {} + +impl Request for Formatting { + type Params = DocumentFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/formatting"; +} + +/// The document range formatting request is sent from the client to the server to format a given range in a document. +#[derive(Debug)] +pub enum RangeFormatting {} + +impl Request for RangeFormatting { + type Params = DocumentRangeFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/rangeFormatting"; +} + +/// The document on type formatting request is sent from the client to the server to format parts of +/// the document during typing. +#[derive(Debug)] +pub enum OnTypeFormatting {} + +impl Request for OnTypeFormatting { + type Params = DocumentOnTypeFormattingParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/onTypeFormatting"; +} + +/// The rename request is sent from the client to the server to perform a workspace-wide rename of a symbol. +#[derive(Debug)] +pub enum Rename {} + +impl Request for Rename { + type Params = RenameParams; + type Result = Option; + const METHOD: &'static str = "textDocument/rename"; +} + +/// The document color request is sent from the client to the server to list all color references found in a given text document. +/// Along with the range, a color value in RGB is returned. +#[derive(Debug)] +pub enum DocumentColor {} + +impl Request for DocumentColor { + type Params = DocumentColorParams; + type Result = Vec; + const METHOD: &'static str = "textDocument/documentColor"; +} + +/// The color presentation request is sent from the client to the server to obtain a list of presentations for a color value +/// at a given location. +#[derive(Debug)] +pub enum ColorPresentationRequest {} + +impl Request for ColorPresentationRequest { + type Params = ColorPresentationParams; + type Result = Vec; + const METHOD: &'static str = "textDocument/colorPresentation"; +} + +/// The folding range request is sent from the client to the server to return all folding ranges found in a given text document. +#[derive(Debug)] +pub enum FoldingRangeRequest {} + +impl Request for FoldingRangeRequest { + type Params = FoldingRangeParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/foldingRange"; +} + +/// The prepare rename request is sent from the client to the server to setup and test the validity of a rename operation +/// at a given location. +#[derive(Debug)] +pub enum PrepareRenameRequest {} + +impl Request for PrepareRenameRequest { + type Params = TextDocumentPositionParams; + type Result = Option; + const METHOD: &'static str = "textDocument/prepareRename"; +} + +/// The workspace/workspaceFolders request is sent from the server to the client to fetch the current open list of +/// workspace folders. Returns null in the response if only a single file is open in the tool. +/// Returns an empty array if a workspace is open but no folders are configured. +#[derive(Debug)] +pub enum WorkspaceFoldersRequest {} + +impl Request for WorkspaceFoldersRequest { + type Params = (); + type Result = Option>; + const METHOD: &'static str = "workspace/workspaceFolders"; +} + +/// The `window/workDoneProgress/create` request is sent from the server +/// to the clientto ask the client to create a work done progress. +#[derive(Debug)] +pub enum WorkDoneProgressCreate {} + +impl Request for WorkDoneProgressCreate { + type Params = WorkDoneProgressCreateParams; + type Result = (); + const METHOD: &'static str = "window/workDoneProgress/create"; +} + +/// The selection range request is sent from the client to the server to return +/// suggested selection ranges at given positions. A selection range is a range +/// around the cursor position which the user might be interested in selecting. +/// +/// A selection range in the return array is for the position in the provided parameters at the same index. +/// Therefore positions[i] must be contained in result[i].range. +/// +/// Typically, but not necessary, selection ranges correspond to the nodes of the +/// syntax tree. +pub enum SelectionRangeRequest {} + +impl Request for SelectionRangeRequest { + type Params = SelectionRangeParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/selectionRange"; +} + +#[cfg(feature = "proposed")] +pub enum CallHierarchyPrepare {} + +#[cfg(feature = "proposed")] +impl Request for CallHierarchyPrepare { + type Params = CallHierarchyPrepareParams; + type Result = Option>; + const METHOD: &'static str = "textDocument/prepareCallHierarchy"; +} + +#[cfg(feature = "proposed")] +pub enum CallHierarchyIncomingCalls {} + +#[cfg(feature = "proposed")] +impl Request for CallHierarchyIncomingCalls { + type Params = CallHierarchyIncomingCallsParams; + type Result = Option>; + const METHOD: &'static str = "callHierarchy/incomingCalls"; +} + +#[cfg(feature = "proposed")] +pub enum CallHierarchyOutgoingCalls {} + +#[cfg(feature = "proposed")] +impl Request for CallHierarchyOutgoingCalls { + type Params = CallHierarchyOutgoingCallsParams; + type Result = Option>; + const METHOD: &'static str = "callHierarchy/outgoingCalls"; +} + +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullRequest {} + +#[cfg(feature = "proposed")] +impl Request for SemanticTokensFullRequest { + type Params = SemanticTokensParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/full"; +} + +#[cfg(feature = "proposed")] +pub enum SemanticTokensFullDeltaRequest {} + +#[cfg(feature = "proposed")] +impl Request for SemanticTokensFullDeltaRequest { + type Params = SemanticTokensDeltaParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/full/delta"; +} + +#[cfg(feature = "proposed")] +pub enum SemanticTokensRangeRequest {} + +#[cfg(feature = "proposed")] +impl Request for SemanticTokensRangeRequest { + type Params = SemanticTokensRangeParams; + type Result = Option; + const METHOD: &'static str = "textDocument/semanticTokens/range"; +} + +#[cfg(test)] +mod test { + use super::*; + + fn fake_call() + where + R: Request, + R::Params: serde::Serialize, + R::Result: serde::de::DeserializeOwned, + { + } + + macro_rules! check_macro { + ($name:tt) => { + // check whethe the macro name matches the method + assert_eq!(::METHOD, $name); + // test whether type checking passes for each component + fake_call::(); + }; + } + + #[test] + fn check_macro_definitions() { + check_macro!("initialize"); + check_macro!("shutdown"); + check_macro!("window/showMessageRequest"); + check_macro!("window/workDoneProgress/create"); + check_macro!("client/registerCapability"); + check_macro!("client/unregisterCapability"); + check_macro!("workspace/symbol"); + check_macro!("workspace/executeCommand"); + check_macro!("textDocument/willSaveWaitUntil"); + check_macro!("textDocument/completion"); + check_macro!("completionItem/resolve"); + check_macro!("textDocument/hover"); + check_macro!("textDocument/signatureHelp"); + check_macro!("textDocument/declaration"); + check_macro!("textDocument/definition"); + check_macro!("textDocument/references"); + check_macro!("textDocument/documentHighlight"); + check_macro!("textDocument/documentSymbol"); + check_macro!("textDocument/codeAction"); + check_macro!("textDocument/codeLens"); + check_macro!("codeLens/resolve"); + check_macro!("textDocument/documentLink"); + check_macro!("documentLink/resolve"); + check_macro!("workspace/applyEdit"); + check_macro!("textDocument/rangeFormatting"); + check_macro!("textDocument/onTypeFormatting"); + check_macro!("textDocument/formatting"); + check_macro!("textDocument/rename"); + check_macro!("textDocument/documentColor"); + check_macro!("textDocument/colorPresentation"); + check_macro!("textDocument/foldingRange"); + check_macro!("textDocument/prepareRename"); + check_macro!("workspace/workspaceFolders"); + check_macro!("textDocument/implementation"); + check_macro!("textDocument/selectionRange"); + check_macro!("textDocument/typeDefinition"); + check_macro!("workspace/configuration"); + } + + #[test] + #[cfg(feature = "proposed")] + fn check_proposed_macro_definitions() { + check_macro!("callHierarchy/incomingCalls"); + check_macro!("callHierarchy/outgoingCalls"); + check_macro!("textDocument/prepareCallHierarchy"); + check_macro!("textDocument/semanticTokens/full"); + check_macro!("textDocument/semanticTokens/full/delta"); + check_macro!("textDocument/semanticTokens/range"); + } +} diff --git a/vendor/mdbook/.cargo-checksum.json b/vendor/mdbook/.cargo-checksum.json index 682cfd4add..5de6dc20d4 100644 --- a/vendor/mdbook/.cargo-checksum.json +++ b/vendor/mdbook/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"3d8761959d40685fd6fb0040e47b35ca7bb7600e4efec94ab2b98bc245811dd6","CONTRIBUTING.md":"680cef0c70325c2e45ede352422ae249ed212c65fc5f502c2267243b89187595","Cargo.lock":"ba04f16c937de54f63f3c2ecb488ab905f0a8f522ddfa3c27f23dc775ccdf996","Cargo.toml":"444b724a463929eee770417b5364975bc9ac113175c35391f9a1396811f5d15b","LICENSE":"af175b9d96ee93c21a036152e1b905b0b95304d4ae8c2c921c7609100ba8df7e","README.md":"be135630660209986615180894b8f71ce865623cb7ecfb2c487c8a12ca9b59c5","ci/install-hub.sh":"ef529e66465dd624d502f4bd4a1092a741f788b948a98625b1f01375149f4ff7","ci/install-rust.sh":"c7b63b4aff867d6da241c23b45121f3efa9cf62b43f839f0eb0d4d0f86580dd6","ci/make-release.sh":"fcf307a3d28ebd60b4b339f960bc0533dfb1bafe37f3c041fac72b49c279bb3b","examples/nop-preprocessor.rs":"db48153fed353c761ec6a64774f4340a91b4ea8c07236ef571bd7601dc5bd17b","release.toml":"25e91966f4a77515244adf5775d638590916c550f9d25bba6024d629b71840e8","src/book/book.rs":"ea53860086d73d81dcbc72d2f3acddf66786ae4486674e0550396998bb10afa9","src/book/init.rs":"fad0ae98277a8b6e9eb4f79776316f2492be4866702ba32ea9745659f6087a05","src/book/mod.rs":"dcd8afc56ea9f018358a630e6ec7e14114099bc0b4f66155d9fcec2e0f530b3f","src/book/summary.rs":"7f5f0b45a5b31dbdfc70c4fbcde60a60d1a2a771b0f2130c2d62cb06a8af0f29","src/cmd/build.rs":"7a87f609ad245a808137c9ff67a92b14238c8b01c3afc834ce166f3ff161a58f","src/cmd/clean.rs":"411579d00103568b8e904db647b6360bd8f9b11d209f595d0a6de0a6e08f8915","src/cmd/init.rs":"3161219d9c4375d296c2f39fdb9cffdad09b373b46f1af5b9543173671a58e5b","src/cmd/mod.rs":"29116e5ca90e916a5f4ce62581a29508670ef184ec3e20569e2ad90b57472abe","src/cmd/serve.rs":"a15a0d7a7cbe9e0421fb2948e6e88e7c1206602dd211d666129e67bc973ad626","src/cmd/test.rs":"405e82cc63f212ec6f41e2017d34aba369c8d581b9c1431c8696d787aa2ee1cf","src/cmd/watch.rs":"86bcf487612c03a3d30c48094aa9b23350226e3e6fbb5850799e61d6f741b81e","src/config.rs":"9cfce3fab9df3705a4a08b02f4657b9eda4e5b5bd5c1cb939e6328ab6eb36a15","src/lib.rs":"5f14dc00233be5b80d41530dd44d09f46bff30fbdf418a97e8e237f53e14ea6a","src/main.rs":"867f696a76921341ab1f0664c20f3efb90c2c5cbdf8da34d5a52205b33481c84","src/preprocess/cmd.rs":"cf5a35406e0804df391c90a004e3f8624c518517a3e0b136c5341fac067068ea","src/preprocess/index.rs":"d6d34bc61165dd5f42005e5d601d6729c40cacd656358ede17798effa309e508","src/preprocess/links.rs":"ad161e8545ec7198afc98da2cb8935ed0eb242f88f36494738932c50ba0633ab","src/preprocess/mod.rs":"b699f993473abdf6e4abbe038c8286b14312003e5d4713d946b9ae87047270e7","src/renderer/html_handlebars/hbs_renderer.rs":"5c09eba4e304b898f309b275b25b88a2733a0655dfdacb7c831d8c69c224df23","src/renderer/html_handlebars/helpers/mod.rs":"d83520feecce350b03b7ffaa9f34d6db2fe7316a46562be694b8eef537124191","src/renderer/html_handlebars/helpers/navigation.rs":"51d6fed8f4af42af10a66bf24804337c87cf93daba893f2f3664b3683a24a9e1","src/renderer/html_handlebars/helpers/theme.rs":"06713b5de794eaf68538e929cce58fe55a6e48afd5e9d3bb211ef47809d18af2","src/renderer/html_handlebars/helpers/toc.rs":"2da068b91db3490d33f8798e0b10899f0bf75a24c3af1f573a66b6d626057864","src/renderer/html_handlebars/mod.rs":"b6be4801cf49040edc9dad216ed12c26dce87e2dc4724ee24729e4a8b67734b0","src/renderer/html_handlebars/search.rs":"626e3cbec3587b90a8209a314e555533cc9b3e98f54270aafc4ab9f471847599","src/renderer/markdown_renderer.rs":"319453627fa416d44e5459a3f9f4cf07b87a4133ff97df5fc962768c9235c65f","src/renderer/mod.rs":"56c11e129556e7f22750a1ad30785719f761ff98a1ca1409b5981e95a6986429","src/theme/FontAwesome/css/font-awesome.min.css":"799aeb25cc0373fdee0e1b1db7ad6c2f6a0e058dfadaa3379689f583213190bd","src/theme/FontAwesome/fonts/FontAwesome.otf":"444dd4366615ffc4a16d012b2fa90137065d3ccb410fa6fd5e4ddd7b5e4ffcd5","src/theme/FontAwesome/fonts/fontawesome-webfont.eot":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","src/theme/FontAwesome/fonts/fontawesome-webfont.svg":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","src/theme/FontAwesome/fonts/fontawesome-webfont.ttf":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","src/theme/FontAwesome/fonts/fontawesome-webfont.woff":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","src/theme/FontAwesome/fonts/fontawesome-webfont.woff2":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","src/theme/ayu-highlight.css":"c141251b5888ccc185c31976e6cb9234f7827ae6bc4975926cafc8bca5e8f83d","src/theme/book.js":"418a647fcdc6ed5388e5c669e10cb796a8d851c2b24d97c416bcb050fdaa9008","src/theme/clipboard.min.js":"1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44","src/theme/css/chrome.css":"576bd3d1e4748ab1a7e000eb110f83f1b643fa4f8339b90a9305302e5c68aaeb","src/theme/css/general.css":"4c89e3e531bc5ca322e4210c8d1868d5a97df0f2a2726a7d60c192f7d933fe19","src/theme/css/print.css":"a4278dff9af38765eb9d344aa56dcc652ac79c73afc408385b62a4b611b89c14","src/theme/css/variables.css":"ccf9aa3f3dcb79b967e13658d101b3f7b9efa914ae0c5e05ac5ed322af33c5bf","src/theme/favicon.png":"8114d1fc74f4b5621ad9afde7746ed9cf7e420be317a6e29023d2298d58aa15b","src/theme/favicon.svg":"de23e50b1c4dd6e052b3e21d444fcd4b13568b3840ac3c99d9be4e9263c0ef59","src/theme/fonts/OPEN-SANS-LICENSE.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","src/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt":"d1e6d465a83ba1a3be52db6484868cf5812ae9bbf91abdad3900ba0165afcf93","src/theme/fonts/fonts.css":"70d7fd9e9965df2995206106b3409b31b1455e5a5e1ef9c2db633d8c84a27622","src/theme/fonts/mod.rs":"9b97835fbc610c46245ac52f8d40df8f28ace0c4fe7aca0847835ee83cc21a15","src/theme/fonts/open-sans-v17-all-charsets-300.woff2":"7736aa3596c468515c3209f2f9d68cfae96d94c05689bcc11a5dce426a6ee2e8","src/theme/fonts/open-sans-v17-all-charsets-300italic.woff2":"2c7b95c08df0d228caec6d4bfed06da0f7ab6b76ea5cc3f75b5c6ae416bc571b","src/theme/fonts/open-sans-v17-all-charsets-600.woff2":"486c67592731a0b36a89dba1fd0b97aeb73f236bbf60dbf28d7c6b5723c07989","src/theme/fonts/open-sans-v17-all-charsets-600italic.woff2":"1a3e865977024f444834a75a1b33b89b93134c93007ae3d6e14f24e6c88d8dfb","src/theme/fonts/open-sans-v17-all-charsets-700.woff2":"c22fe8c70c36f1d862903b772eaed864d3a8fa849473c9caff224fdb852428e4","src/theme/fonts/open-sans-v17-all-charsets-700italic.woff2":"238ae9593944112bee8dd65f8ebc5f3d3862160a8a245fbe1ee3150bc9a2fd81","src/theme/fonts/open-sans-v17-all-charsets-800.woff2":"3d2c812adf74deb36fead3ff8469800d3c0b23eb2c858ae49310291f89490146","src/theme/fonts/open-sans-v17-all-charsets-800italic.woff2":"ba1521ec219db9bc5bfec0e3e7a897369d98b30d4e853ee4aa525322784428b8","src/theme/fonts/open-sans-v17-all-charsets-italic.woff2":"6c9463f7096c0b9d610e095ed248ac1e8a8da7e92d17e9be544f3baced7b62b2","src/theme/fonts/open-sans-v17-all-charsets-regular.woff2":"2e3b1d34ac67763ab50652da19305d4b3694c6b6e6bf35f4b98411ce4af646d2","src/theme/fonts/source-code-pro-v11-all-charsets-500.woff2":"2bdd9410b0141db3cbbf4cfc3818cc6fad279e8e63940940e06cd6af76ccbfcf","src/theme/head.hbs":"56b3ab3c6eabd4723d4794ecd0a7452aa8903c55a2106d60bceacc74d76311c3","src/theme/header.hbs":"1fd27c9ccd016060dc4d6e77f12bf58b26e7c604aebe2577a67097f95a3de70a","src/theme/highlight.css":"6ebb896cc720d92a56def939b787cb25a2facfcfa9d95eeac9f979b092f15716","src/theme/highlight.js":"5a2b5dadd60831dd1f82220223e2ab18e627061912cc89b5c450ab2c8f26ff90","src/theme/index.hbs":"4698beb607dd1c5571ecc60256bf6858265b4ac546548805f2345ea679dd5976","src/theme/mod.rs":"b8224089da80257f2a6550691ef4334b5f746520dfcbf61906224e4afbcf44ba","src/theme/playground_editor/ace.js":"2a3cd908c9619862b52f621ce2a40f76b772eb51c17308b14bd26d1809af8f87","src/theme/playground_editor/editor.js":"16ca416ca77428fe23cb8e18afbd3626a6a86723d6b6e189c47da95d9e9bdc31","src/theme/playground_editor/mod.rs":"b6b0f99f00ccb83cedfe5ce892834b46936a468611d056eae0f146e59711dc5c","src/theme/playground_editor/mode-rust.js":"2c9d5c9af5ae32612aef1ca5653e3473ed40747d36ecb4a97719ff14707d8535","src/theme/playground_editor/theme-dawn.js":"4493f9c88ed7185f7bb4195be77018d21cdc439a34bd4e5da64b566eb996fbe8","src/theme/playground_editor/theme-tomorrow_night.js":"9dbe62a913ebe3fd9667f41f69c0301bacd963081c69abb0219e4acac4710f60","src/theme/redirect.hbs":"c10b6e36dda1a4f222aa61cd1c6180a2f2937397379adba2c10b9b41e446709e","src/theme/searcher/elasticlunr.min.js":"ef4e11c157b1e2e89782d30bd726f2d5ff7834ea5e26ad02474325f8b1f126c9","src/theme/searcher/mark.min.js":"09e88c2cfaf23ea8a37b5681433eafea97033af632ecc948c8c1ee9944647743","src/theme/searcher/mod.rs":"36979040719b2fa39d1b78808e41cdb6e52e0ea5137c84820b437ed015278072","src/theme/searcher/searcher.js":"5fa8ef792186dcb36dea668de68d6472b899b56ddfb1a1aa8015f4dc7e16af09","src/theme/tomorrow-night.css":"243cb61aa526cef79b3545b1c7f2b681747dd346867c8ceb36c69487acc390fb","src/utils/fs.rs":"4d00080337802a355df25c85a378eae00fb3b8016f80fe71413d6e20463eca60","src/utils/mod.rs":"e4476a3afda9964cb57e29f87ee03f4d8860cdb17a7b3fe5b56e108420adc2f6","src/utils/string.rs":"34ac2235625b52530d335b318a2bea1007c6ae56f39d2e0e5f1013a23ec1ef6f","src/utils/toml_ext.rs":"77e7cb18786cdccf19983a25a3c1b44a18166fe440c3233ccb0303003f105bee","tests/alternative_backends.rs":"1453a25311e8da9d81809381f22382a93f4f2d16bb710b8c566831cea37b15ca","tests/build_process.rs":"a958404fc41ff5c00b08b4c69d26f0862160e20c781b4bea88977d85304b6ef5","tests/custom_preprocessors.rs":"22a5da0ed34ab2fe85d87ceb70e06c2a5065d66c363a39ce7d45715ae974ad1c","tests/dummy_book/mod.rs":"9b4353da9156697787cca654092c0509fec2a8bfa292bbe5d0a5414234c6f6af","tests/dummy_book/src/README.md":"2f6e578b9f31ff5e1d18ae40865355d59e56a23e02798bd8166751245ef4eb9b","tests/dummy_book/src/SUMMARY.md":"3384fd28e2974749eedf385bd3a996b71cc248abf545a696a3fda6180d22d31a","tests/dummy_book/src/conclusion.md":"eca0543344979e938b43debf3d310290a628e8b7b45d3d9bec63c21e61284a4c","tests/dummy_book/src/example.rs":"3be109d6faa3c6104c8fb5e8ffdfe3eba73d0a5ed4f537685fe2cf2c36e657d0","tests/dummy_book/src/first/includes.md":"747f8f1eb4d394c1fdb773acddb7ffdc641e3ad71b0d15afb0f4e2de13a729ed","tests/dummy_book/src/first/index.md":"e7d1af4cb454c0be73bf1e2f01a97541fba385cd04ac5c9a7acc99809adedee8","tests/dummy_book/src/first/markdown.md":"461753f7f5105e35bc246c752065a44ea1d238f6890bd01b7c34d0a5746f7902","tests/dummy_book/src/first/nested-test-with-anchors.rs":"6fdecb4c62201f2dae36ea7e35693238edca03dcfc42d33eaf1685bc957a6d1d","tests/dummy_book/src/first/nested-test.rs":"ca4cdf552842a957be49ffc753f7585dba3c0036a076fea68174719599d426fa","tests/dummy_book/src/first/nested.md":"485d24764340c0413939e52533ab304c07bb55bd23d0ad9e31151ff889425048","tests/dummy_book/src/first/partially-included-test-with-anchors.rs":"501d96562da17cbec46444a004340e711b3fac4b3384f12d7c4844909742c8c8","tests/dummy_book/src/first/partially-included-test.rs":"1bdd1a4f8fdc41ea10868f97de0fe315b2cc592d4cf4aabd784f17dc8c0a6e90","tests/dummy_book/src/first/recursive.md":"9b574239c94c24412dbd918d7b85f557a80cec44d245663cfe1ecdd8ed16765e","tests/dummy_book/src/first/unicode.md":"04a548a642ba5cbc346670a8b38c1aeb5ad23d5a967849783171c634b682de63","tests/dummy_book/src/intro.md":"2749920beee7f563f3ace2bbef204dc66382e052c7945bf27e66912351959a90","tests/dummy_book/src/second.md":"b1344cb47f69621ed68197b81652df1f86254b71b4e3dcbdcf707a4e1fee3340","tests/dummy_book/src/second/nested.md":"b0da2ce6ce1ac5fbda92b5cf7a6a09d39abd267095a29f177e44cd4e8d333d45","tests/dummy_book/src2/README.md":"1bcffb061e737e022f132f78a2dd3193fc0951d0b104e50ddc860d9bc260f505","tests/dummy_book/src2/SUMMARY.md":"4354bec1cae7db3c48dfe869e28e8e29958daef937b33da5e729211372ccb9c9","tests/dummy_book/src2/first/README.md":"ba505ed6c1e18c85ce2ca7070021c719933ce2cf9f28de8565c188c0e4a95d87","tests/dummy_book/src2/second/README.md":"2fb4a90a1359fe3725c3d95888452afd514b0b86bdc4e2768442a71bf5b642a0","tests/dummy_book/src2/second/index.md":"5bf990bec982b9e87d8dfb230fb2dfc96318d9065f97a3d3c5cf27bd134c8bdd","tests/init.rs":"087f4e2814ddc55b4726e2491c460191c387e930d86b2b9716f28baa8fa54ff9","tests/parse_existing_summary_files.rs":"f4b019e66ffc7f59efd7ec9da73bb70180e4cc23ff27904bf4dfd26491ef64a3","tests/rendered_output.rs":"79373359eaa8fd03e8bd278b576fd076d7d30450a13fa69fa40bf0f472100bdd","tests/searchindex_fixture.json":"3bedb596b17e0b74ac4e146de884594ea2a92e45ff2fe24d423c94bead8288d5","tests/summary_md_files/example_book.md":"e1dd09043d9548612b0bb4e607a8796317272aa1fe7a2bda55db6e6f47d3fc5a","tests/summary_md_files/rust_by_example.md":"c46c8eab64780297b851be196a04d573da69553f4d9c33e24fbd5fb2867efbfd","tests/summary_md_files/rust_ffi_guide.md":"26874d9ad22cfdc2a587e7a495a4404247821d2b6e8eabe07334cacc5a4ea365","tests/summary_md_files/the_book-2nd_edition.md":"7ae64929c45aa7d67560c77e5280a540c22d1b0d2f8fd85f8392ce064c2d5f0a","tests/testing.rs":"c80d579682b969045d0c067f7ae5ab425255f83642f9dfd11a42f3de75e1b4a8"},"package":"b75e31ae4eaa0e45e17ee2b6b9e3ed969c3c6ff12bb4c2e352c42493f4ebb706"} \ No newline at end of file +{"files":{"CHANGELOG.md":"01fe77b97e8d5a11bd70a48929efabbf2d29964a7ee55126fa2bdfbada00db8b","CONTRIBUTING.md":"680cef0c70325c2e45ede352422ae249ed212c65fc5f502c2267243b89187595","Cargo.lock":"b74e22f840ba0528d5f6b3118936fb26bce080216d6f3a3e57af278c89e2e0f1","Cargo.toml":"db76847db3a06a0b46319ed5d71a83fa0fb85c1cae97030b50e21ef0eeabfe0f","LICENSE":"af175b9d96ee93c21a036152e1b905b0b95304d4ae8c2c921c7609100ba8df7e","README.md":"00d699272528d6a208e8d03f5f99911340c130504aa3e6b04a1905f189433f14","ci/install-hub.sh":"ef529e66465dd624d502f4bd4a1092a741f788b948a98625b1f01375149f4ff7","ci/install-rust.sh":"c7b63b4aff867d6da241c23b45121f3efa9cf62b43f839f0eb0d4d0f86580dd6","ci/make-release.sh":"fcf307a3d28ebd60b4b339f960bc0533dfb1bafe37f3c041fac72b49c279bb3b","examples/nop-preprocessor.rs":"db48153fed353c761ec6a64774f4340a91b4ea8c07236ef571bd7601dc5bd17b","release.toml":"25e91966f4a77515244adf5775d638590916c550f9d25bba6024d629b71840e8","src/book/book.rs":"ea53860086d73d81dcbc72d2f3acddf66786ae4486674e0550396998bb10afa9","src/book/init.rs":"fad0ae98277a8b6e9eb4f79776316f2492be4866702ba32ea9745659f6087a05","src/book/mod.rs":"9f2e291b2110dd91dac88801520772122c0d9aa346c531686e9a541e935e01b2","src/book/summary.rs":"7f5f0b45a5b31dbdfc70c4fbcde60a60d1a2a771b0f2130c2d62cb06a8af0f29","src/cmd/build.rs":"7a87f609ad245a808137c9ff67a92b14238c8b01c3afc834ce166f3ff161a58f","src/cmd/clean.rs":"411579d00103568b8e904db647b6360bd8f9b11d209f595d0a6de0a6e08f8915","src/cmd/init.rs":"3161219d9c4375d296c2f39fdb9cffdad09b373b46f1af5b9543173671a58e5b","src/cmd/mod.rs":"29116e5ca90e916a5f4ce62581a29508670ef184ec3e20569e2ad90b57472abe","src/cmd/serve.rs":"a15a0d7a7cbe9e0421fb2948e6e88e7c1206602dd211d666129e67bc973ad626","src/cmd/test.rs":"405e82cc63f212ec6f41e2017d34aba369c8d581b9c1431c8696d787aa2ee1cf","src/cmd/watch.rs":"86bcf487612c03a3d30c48094aa9b23350226e3e6fbb5850799e61d6f741b81e","src/config.rs":"d2e10952cd4da18685b600aad5696cb41aa38d1c134e1d21a240f0b402e1286f","src/lib.rs":"5f14dc00233be5b80d41530dd44d09f46bff30fbdf418a97e8e237f53e14ea6a","src/main.rs":"867f696a76921341ab1f0664c20f3efb90c2c5cbdf8da34d5a52205b33481c84","src/preprocess/cmd.rs":"cf5a35406e0804df391c90a004e3f8624c518517a3e0b136c5341fac067068ea","src/preprocess/index.rs":"d6d34bc61165dd5f42005e5d601d6729c40cacd656358ede17798effa309e508","src/preprocess/links.rs":"ad161e8545ec7198afc98da2cb8935ed0eb242f88f36494738932c50ba0633ab","src/preprocess/mod.rs":"b699f993473abdf6e4abbe038c8286b14312003e5d4713d946b9ae87047270e7","src/renderer/html_handlebars/hbs_renderer.rs":"27bb7bb89f9f2abbe234f7266e9d2840f9f4f86711da1329e0033ef50e8ca189","src/renderer/html_handlebars/helpers/mod.rs":"d83520feecce350b03b7ffaa9f34d6db2fe7316a46562be694b8eef537124191","src/renderer/html_handlebars/helpers/navigation.rs":"51d6fed8f4af42af10a66bf24804337c87cf93daba893f2f3664b3683a24a9e1","src/renderer/html_handlebars/helpers/theme.rs":"06713b5de794eaf68538e929cce58fe55a6e48afd5e9d3bb211ef47809d18af2","src/renderer/html_handlebars/helpers/toc.rs":"b3d86fa13d1508eaae9f25a685802273048a5c22b6bf094abbad0b7c19cc0afc","src/renderer/html_handlebars/mod.rs":"b6be4801cf49040edc9dad216ed12c26dce87e2dc4724ee24729e4a8b67734b0","src/renderer/html_handlebars/search.rs":"626e3cbec3587b90a8209a314e555533cc9b3e98f54270aafc4ab9f471847599","src/renderer/markdown_renderer.rs":"319453627fa416d44e5459a3f9f4cf07b87a4133ff97df5fc962768c9235c65f","src/renderer/mod.rs":"56c11e129556e7f22750a1ad30785719f761ff98a1ca1409b5981e95a6986429","src/theme/FontAwesome/css/font-awesome.min.css":"799aeb25cc0373fdee0e1b1db7ad6c2f6a0e058dfadaa3379689f583213190bd","src/theme/FontAwesome/fonts/FontAwesome.otf":"444dd4366615ffc4a16d012b2fa90137065d3ccb410fa6fd5e4ddd7b5e4ffcd5","src/theme/FontAwesome/fonts/fontawesome-webfont.eot":"7bfcab6db99d5cfbf1705ca0536ddc78585432cc5fa41bbd7ad0f009033b2979","src/theme/FontAwesome/fonts/fontawesome-webfont.svg":"ad6157926c1622ba4e1d03d478f1541368524bfc46f51e42fe0d945f7ef323e4","src/theme/FontAwesome/fonts/fontawesome-webfont.ttf":"aa58f33f239a0fb02f5c7a6c45c043d7a9ac9a093335806694ecd6d4edc0d6a8","src/theme/FontAwesome/fonts/fontawesome-webfont.woff":"ba0c59deb5450f5cb41b3f93609ee2d0d995415877ddfa223e8a8a7533474f07","src/theme/FontAwesome/fonts/fontawesome-webfont.woff2":"2adefcbc041e7d18fcf2d417879dc5a09997aa64d675b7a3c4b6ce33da13f3fe","src/theme/ayu-highlight.css":"c141251b5888ccc185c31976e6cb9234f7827ae6bc4975926cafc8bca5e8f83d","src/theme/book.js":"418a647fcdc6ed5388e5c669e10cb796a8d851c2b24d97c416bcb050fdaa9008","src/theme/clipboard.min.js":"1626706afc88d95ebe1173b553ec732c6dc82a576989315fdf5e7779af738a44","src/theme/css/chrome.css":"576bd3d1e4748ab1a7e000eb110f83f1b643fa4f8339b90a9305302e5c68aaeb","src/theme/css/general.css":"4c89e3e531bc5ca322e4210c8d1868d5a97df0f2a2726a7d60c192f7d933fe19","src/theme/css/print.css":"a4278dff9af38765eb9d344aa56dcc652ac79c73afc408385b62a4b611b89c14","src/theme/css/variables.css":"ccf9aa3f3dcb79b967e13658d101b3f7b9efa914ae0c5e05ac5ed322af33c5bf","src/theme/favicon.png":"8114d1fc74f4b5621ad9afde7746ed9cf7e420be317a6e29023d2298d58aa15b","src/theme/favicon.svg":"de23e50b1c4dd6e052b3e21d444fcd4b13568b3840ac3c99d9be4e9263c0ef59","src/theme/fonts/OPEN-SANS-LICENSE.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","src/theme/fonts/SOURCE-CODE-PRO-LICENSE.txt":"d1e6d465a83ba1a3be52db6484868cf5812ae9bbf91abdad3900ba0165afcf93","src/theme/fonts/fonts.css":"2db113e6ebede8403c607db3dceb5acc53c247720d5955d22f7db56beb7139b6","src/theme/fonts/mod.rs":"9b97835fbc610c46245ac52f8d40df8f28ace0c4fe7aca0847835ee83cc21a15","src/theme/fonts/open-sans-v17-all-charsets-300.woff2":"7736aa3596c468515c3209f2f9d68cfae96d94c05689bcc11a5dce426a6ee2e8","src/theme/fonts/open-sans-v17-all-charsets-300italic.woff2":"2c7b95c08df0d228caec6d4bfed06da0f7ab6b76ea5cc3f75b5c6ae416bc571b","src/theme/fonts/open-sans-v17-all-charsets-600.woff2":"486c67592731a0b36a89dba1fd0b97aeb73f236bbf60dbf28d7c6b5723c07989","src/theme/fonts/open-sans-v17-all-charsets-600italic.woff2":"1a3e865977024f444834a75a1b33b89b93134c93007ae3d6e14f24e6c88d8dfb","src/theme/fonts/open-sans-v17-all-charsets-700.woff2":"c22fe8c70c36f1d862903b772eaed864d3a8fa849473c9caff224fdb852428e4","src/theme/fonts/open-sans-v17-all-charsets-700italic.woff2":"238ae9593944112bee8dd65f8ebc5f3d3862160a8a245fbe1ee3150bc9a2fd81","src/theme/fonts/open-sans-v17-all-charsets-800.woff2":"3d2c812adf74deb36fead3ff8469800d3c0b23eb2c858ae49310291f89490146","src/theme/fonts/open-sans-v17-all-charsets-800italic.woff2":"ba1521ec219db9bc5bfec0e3e7a897369d98b30d4e853ee4aa525322784428b8","src/theme/fonts/open-sans-v17-all-charsets-italic.woff2":"6c9463f7096c0b9d610e095ed248ac1e8a8da7e92d17e9be544f3baced7b62b2","src/theme/fonts/open-sans-v17-all-charsets-regular.woff2":"2e3b1d34ac67763ab50652da19305d4b3694c6b6e6bf35f4b98411ce4af646d2","src/theme/fonts/source-code-pro-v11-all-charsets-500.woff2":"2bdd9410b0141db3cbbf4cfc3818cc6fad279e8e63940940e06cd6af76ccbfcf","src/theme/head.hbs":"56b3ab3c6eabd4723d4794ecd0a7452aa8903c55a2106d60bceacc74d76311c3","src/theme/header.hbs":"1fd27c9ccd016060dc4d6e77f12bf58b26e7c604aebe2577a67097f95a3de70a","src/theme/highlight.css":"6ebb896cc720d92a56def939b787cb25a2facfcfa9d95eeac9f979b092f15716","src/theme/highlight.js":"5a2b5dadd60831dd1f82220223e2ab18e627061912cc89b5c450ab2c8f26ff90","src/theme/index.hbs":"4698beb607dd1c5571ecc60256bf6858265b4ac546548805f2345ea679dd5976","src/theme/mod.rs":"b8224089da80257f2a6550691ef4334b5f746520dfcbf61906224e4afbcf44ba","src/theme/playground_editor/ace.js":"2a3cd908c9619862b52f621ce2a40f76b772eb51c17308b14bd26d1809af8f87","src/theme/playground_editor/editor.js":"16ca416ca77428fe23cb8e18afbd3626a6a86723d6b6e189c47da95d9e9bdc31","src/theme/playground_editor/mod.rs":"b6b0f99f00ccb83cedfe5ce892834b46936a468611d056eae0f146e59711dc5c","src/theme/playground_editor/mode-rust.js":"2c9d5c9af5ae32612aef1ca5653e3473ed40747d36ecb4a97719ff14707d8535","src/theme/playground_editor/theme-dawn.js":"4493f9c88ed7185f7bb4195be77018d21cdc439a34bd4e5da64b566eb996fbe8","src/theme/playground_editor/theme-tomorrow_night.js":"9dbe62a913ebe3fd9667f41f69c0301bacd963081c69abb0219e4acac4710f60","src/theme/redirect.hbs":"c10b6e36dda1a4f222aa61cd1c6180a2f2937397379adba2c10b9b41e446709e","src/theme/searcher/elasticlunr.min.js":"ef4e11c157b1e2e89782d30bd726f2d5ff7834ea5e26ad02474325f8b1f126c9","src/theme/searcher/mark.min.js":"09e88c2cfaf23ea8a37b5681433eafea97033af632ecc948c8c1ee9944647743","src/theme/searcher/mod.rs":"36979040719b2fa39d1b78808e41cdb6e52e0ea5137c84820b437ed015278072","src/theme/searcher/searcher.js":"5fa8ef792186dcb36dea668de68d6472b899b56ddfb1a1aa8015f4dc7e16af09","src/theme/tomorrow-night.css":"243cb61aa526cef79b3545b1c7f2b681747dd346867c8ceb36c69487acc390fb","src/utils/fs.rs":"4d00080337802a355df25c85a378eae00fb3b8016f80fe71413d6e20463eca60","src/utils/mod.rs":"e4476a3afda9964cb57e29f87ee03f4d8860cdb17a7b3fe5b56e108420adc2f6","src/utils/string.rs":"34ac2235625b52530d335b318a2bea1007c6ae56f39d2e0e5f1013a23ec1ef6f","src/utils/toml_ext.rs":"77e7cb18786cdccf19983a25a3c1b44a18166fe440c3233ccb0303003f105bee","tests/alternative_backends.rs":"1453a25311e8da9d81809381f22382a93f4f2d16bb710b8c566831cea37b15ca","tests/build_process.rs":"a958404fc41ff5c00b08b4c69d26f0862160e20c781b4bea88977d85304b6ef5","tests/custom_preprocessors.rs":"22a5da0ed34ab2fe85d87ceb70e06c2a5065d66c363a39ce7d45715ae974ad1c","tests/dummy_book/mod.rs":"9b4353da9156697787cca654092c0509fec2a8bfa292bbe5d0a5414234c6f6af","tests/dummy_book/src/README.md":"2f6e578b9f31ff5e1d18ae40865355d59e56a23e02798bd8166751245ef4eb9b","tests/dummy_book/src/SUMMARY.md":"3384fd28e2974749eedf385bd3a996b71cc248abf545a696a3fda6180d22d31a","tests/dummy_book/src/conclusion.md":"eca0543344979e938b43debf3d310290a628e8b7b45d3d9bec63c21e61284a4c","tests/dummy_book/src/example.rs":"3be109d6faa3c6104c8fb5e8ffdfe3eba73d0a5ed4f537685fe2cf2c36e657d0","tests/dummy_book/src/first/includes.md":"747f8f1eb4d394c1fdb773acddb7ffdc641e3ad71b0d15afb0f4e2de13a729ed","tests/dummy_book/src/first/index.md":"e7d1af4cb454c0be73bf1e2f01a97541fba385cd04ac5c9a7acc99809adedee8","tests/dummy_book/src/first/markdown.md":"461753f7f5105e35bc246c752065a44ea1d238f6890bd01b7c34d0a5746f7902","tests/dummy_book/src/first/nested-test-with-anchors.rs":"6fdecb4c62201f2dae36ea7e35693238edca03dcfc42d33eaf1685bc957a6d1d","tests/dummy_book/src/first/nested-test.rs":"ca4cdf552842a957be49ffc753f7585dba3c0036a076fea68174719599d426fa","tests/dummy_book/src/first/nested.md":"485d24764340c0413939e52533ab304c07bb55bd23d0ad9e31151ff889425048","tests/dummy_book/src/first/partially-included-test-with-anchors.rs":"501d96562da17cbec46444a004340e711b3fac4b3384f12d7c4844909742c8c8","tests/dummy_book/src/first/partially-included-test.rs":"1bdd1a4f8fdc41ea10868f97de0fe315b2cc592d4cf4aabd784f17dc8c0a6e90","tests/dummy_book/src/first/recursive.md":"9b574239c94c24412dbd918d7b85f557a80cec44d245663cfe1ecdd8ed16765e","tests/dummy_book/src/first/unicode.md":"04a548a642ba5cbc346670a8b38c1aeb5ad23d5a967849783171c634b682de63","tests/dummy_book/src/intro.md":"2749920beee7f563f3ace2bbef204dc66382e052c7945bf27e66912351959a90","tests/dummy_book/src/second.md":"b1344cb47f69621ed68197b81652df1f86254b71b4e3dcbdcf707a4e1fee3340","tests/dummy_book/src/second/nested.md":"b0da2ce6ce1ac5fbda92b5cf7a6a09d39abd267095a29f177e44cd4e8d333d45","tests/dummy_book/src2/README.md":"1bcffb061e737e022f132f78a2dd3193fc0951d0b104e50ddc860d9bc260f505","tests/dummy_book/src2/SUMMARY.md":"4354bec1cae7db3c48dfe869e28e8e29958daef937b33da5e729211372ccb9c9","tests/dummy_book/src2/first/README.md":"ba505ed6c1e18c85ce2ca7070021c719933ce2cf9f28de8565c188c0e4a95d87","tests/dummy_book/src2/second/README.md":"2fb4a90a1359fe3725c3d95888452afd514b0b86bdc4e2768442a71bf5b642a0","tests/dummy_book/src2/second/index.md":"5bf990bec982b9e87d8dfb230fb2dfc96318d9065f97a3d3c5cf27bd134c8bdd","tests/init.rs":"087f4e2814ddc55b4726e2491c460191c387e930d86b2b9716f28baa8fa54ff9","tests/parse_existing_summary_files.rs":"f4b019e66ffc7f59efd7ec9da73bb70180e4cc23ff27904bf4dfd26491ef64a3","tests/rendered_output.rs":"79373359eaa8fd03e8bd278b576fd076d7d30450a13fa69fa40bf0f472100bdd","tests/searchindex_fixture.json":"3bedb596b17e0b74ac4e146de884594ea2a92e45ff2fe24d423c94bead8288d5","tests/summary_md_files/example_book.md":"e1dd09043d9548612b0bb4e607a8796317272aa1fe7a2bda55db6e6f47d3fc5a","tests/summary_md_files/rust_by_example.md":"c46c8eab64780297b851be196a04d573da69553f4d9c33e24fbd5fb2867efbfd","tests/summary_md_files/rust_ffi_guide.md":"26874d9ad22cfdc2a587e7a495a4404247821d2b6e8eabe07334cacc5a4ea365","tests/summary_md_files/the_book-2nd_edition.md":"7ae64929c45aa7d67560c77e5280a540c22d1b0d2f8fd85f8392ce064c2d5f0a","tests/testing.rs":"c80d579682b969045d0c067f7ae5ab425255f83642f9dfd11a42f3de75e1b4a8"},"package":"29be448fcafb00c5a8966c4020c2a5ffbbc333e5b96d0bb5ef54b5bd0524d9ff"} \ No newline at end of file diff --git a/vendor/mdbook/CHANGELOG.md b/vendor/mdbook/CHANGELOG.md index d6744dd26b..3f90557fce 100644 --- a/vendor/mdbook/CHANGELOG.md +++ b/vendor/mdbook/CHANGELOG.md @@ -1,5 +1,27 @@ # Changelog +## mdBook 0.4.3 +[9278b83...9278b83](https://github.com/rust-lang/mdBook/compare/9278b83...4df9ec9) + +### Added +- Added `output.html.cname` option to emit a `CNAME` file which is used by + GitHub Pages to know which domain is being used. + [#1311](https://github.com/rust-lang/mdBook/pull/1311) + +### Changed +- `mdbook test` no longer stops on the first test failure, but instead will + run all the tests. + [#1313](https://github.com/rust-lang/mdBook/pull/1313) +- Removed the `local` font source for Source Code Pro, as the locally + installed font may not render properly on FireFox on macOS. + [#1307](https://github.com/rust-lang/mdBook/pull/1307) + +### Fixed +- Added newline to end of `.nojekyll` file. + [#1310](https://github.com/rust-lang/mdBook/pull/1310) +- Fixed missing space before draft chapter titles. + [#1309](https://github.com/rust-lang/mdBook/pull/1309) + ## mdBook 0.4.2 [649f355...9278b83](https://github.com/rust-lang/mdBook/compare/649f355...9278b83) diff --git a/vendor/mdbook/Cargo.lock b/vendor/mdbook/Cargo.lock index 463a69efc9..f9619fabff 100644 --- a/vendor/mdbook/Cargo.lock +++ b/vendor/mdbook/Cargo.lock @@ -723,7 +723,7 @@ checksum = "7ffc5c5338469d4d3ea17d269fa8ea3512ad247247c30bd2df69e68309ed0a08" [[package]] name = "mdbook" -version = "0.4.2" +version = "0.4.3" dependencies = [ "ammonia", "anyhow", diff --git a/vendor/mdbook/Cargo.toml b/vendor/mdbook/Cargo.toml index c631d5a9b3..e7215f4d0c 100644 --- a/vendor/mdbook/Cargo.toml +++ b/vendor/mdbook/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "mdbook" -version = "0.4.2" +version = "0.4.3" authors = ["Mathieu David ", "Michael-F-Bryan ", "Matt Ickstadt "] exclude = ["/book-example/*"] description = "Creates a book from markdown files" diff --git a/vendor/mdbook/README.md b/vendor/mdbook/README.md index 6f839b86a3..392180dfd5 100644 --- a/vendor/mdbook/README.md +++ b/vendor/mdbook/README.md @@ -209,7 +209,7 @@ tagged [E-Easy] and **we will gladly mentor you** so that you can successfully go through the process of fixing a bug or adding a new feature! Let us know if you need any help. -For more info about contributing, check out our [contribution guide] who helps +For more info about contributing, check out our [contribution guide] which helps you go through the build and contribution process! There is also a [rendered version][master-docs] of the latest API docs diff --git a/vendor/mdbook/src/book/mod.rs b/vendor/mdbook/src/book/mod.rs index 71f0197fe4..0723578f8b 100644 --- a/vendor/mdbook/src/book/mod.rs +++ b/vendor/mdbook/src/book/mod.rs @@ -250,6 +250,7 @@ impl MDBook { // Index Preprocessor is disabled so that chapter paths continue to point to the // actual markdown files. + let mut failed = false; for item in book.iter() { if let BookItem::Chapter(ref ch) = *item { let chapter_path = match ch.path { @@ -282,7 +283,8 @@ impl MDBook { let output = cmd.output()?; if !output.status.success() { - bail!( + failed = true; + error!( "rustdoc returned an error:\n\ \n--- stdout\n{}\n--- stderr\n{}", String::from_utf8_lossy(&output.stdout), @@ -291,6 +293,9 @@ impl MDBook { } } } + if failed { + bail!("One or more tests failed"); + } Ok(()) } diff --git a/vendor/mdbook/src/config.rs b/vendor/mdbook/src/config.rs index 1389f13921..ef6bc6876e 100644 --- a/vendor/mdbook/src/config.rs +++ b/vendor/mdbook/src/config.rs @@ -508,6 +508,13 @@ pub struct HtmlConfig { pub input_404: Option, /// Absolute url to site, used to emit correct paths for the 404 page, which might be accessed in a deeply nested directory pub site_url: Option, + /// The DNS subdomain or apex domain at which your book will be hosted. This + /// string will be written to a file named CNAME in the root of your site, + /// as required by GitHub Pages (see [*Managing a custom domain for your + /// GitHub Pages site*][custom domain]). + /// + /// [custom domain]: https://docs.github.com/en/github/working-with-github-pages/managing-a-custom-domain-for-your-github-pages-site + pub cname: Option, /// This is used as a bit of a workaround for the `mdbook serve` command. /// Basically, because you set the websocket port from the command line, the /// `mdbook serve` command needs a way to let the HTML renderer know where @@ -541,6 +548,7 @@ impl Default for HtmlConfig { git_repository_icon: None, input_404: None, site_url: None, + cname: None, livereload_url: None, redirect: HashMap::new(), } diff --git a/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs b/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs index 7880817b1e..4992730e69 100644 --- a/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs +++ b/vendor/mdbook/src/renderer/html_handlebars/hbs_renderer.rs @@ -184,9 +184,13 @@ impl HtmlHandlebars { write_file( destination, ".nojekyll", - b"This file makes sure that Github Pages doesn't process mdBook's output.", + b"This file makes sure that Github Pages doesn't process mdBook's output.\n", )?; + if let Some(cname) = &html_config.cname { + write_file(destination, "CNAME", format!("{}\n", cname).as_bytes())?; + } + write_file(destination, "book.js", &theme.js)?; write_file(destination, "css/general.css", &theme.general_css)?; write_file(destination, "css/chrome.css", &theme.chrome_css)?; diff --git a/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs b/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs index 47eda59692..7a5d8a2844 100644 --- a/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs +++ b/vendor/mdbook/src/renderer/html_handlebars/helpers/toc.rs @@ -108,32 +108,32 @@ impl HelperDef for RenderToc { } // Link - let path_exists = if let Some(path) = item.get("path") { - if !path.is_empty() { - out.write("")?; - true - } else { - false + if path == ¤t_path { + out.write(" class=\"active\"")?; } + + out.write(">")?; + true } else { + out.write("

    ")?; } // Render expand/collapse toggle diff --git a/vendor/merge/.cargo-checksum.json b/vendor/merge/.cargo-checksum.json new file mode 100644 index 0000000000..f34d2c2360 --- /dev/null +++ b/vendor/merge/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"bd0078d7348a85fc7610eb3cb7da3bc4bad24f206fdf7a8dd7f8228edc7e5db0","Cargo.lock":"ad827835f7e148d5d6aae191c95d5a4d92c9636b9eacb22337d21c8e633fae9d","Cargo.toml":"15b331689931ce323547deebcafbbc3ce7b524bdb7a8b5add640784165a3095a","LICENSES/Apache-2.0.txt":"cfc7749b96f63bd31c3c42b5c471bf756814053e847c10f3eb003417bc523d30","LICENSES/CC0-1.0.txt":"6a573fb2f9082662978cf21fb153096df0a1981deaea7dbc10a11046fe005d9f","LICENSES/MIT.txt":"7bf39b72495d83b97bd314f9a58e1153455c427e5ea07e26437ac045aafa11d0","README.md":"34c55828910f5652951db174bc7d57fac0fc0fe527bf685fe3d78c41e3df2c97","examples/args.rs":"f3379155bc7f6b54db358ca1aac3728032322dc1d4e61066640c950443328e25","examples/user.rs":"bace343d99c6649f54049c04b55205a1e723662283087edf349316542e194863","src/lib.rs":"1c949876557448e8b33bbfece0f3d988344dfb661d554e438b5d3b0aaccbfcd4","tests/compile.rs":"064ca60baa606377d96c9b49d4ccb7984b1d5882557b4a36782e789486ee3ca6","tests/compile/derive-enum.rs":"602986493d04381346777a94d0bf0059ae4e318f1581aa60693f4b6bd449bdf8","tests/compile/derive-enum.stderr":"748c10c72984908503342ea915d06ac823532749a06256c0536c1b49878a602c","tests/compile/derive-invalid-attribute.rs":"41cdb984bb1bd9022191432244e1ccb53df0d4ebb9c9d34175320568dde32948","tests/compile/derive-invalid-attribute.stderr":"09ee6f8011169fbaaab8a5216012f7e04186132f16b788df6c7029405aac960d","tests/compile/derive-invalid-skip.rs":"1e6fe0b503793f1c50a0982c8a7a4e056916bf4ae3aa47e8ecdfae548f55f40c","tests/compile/derive-invalid-skip.stderr":"ad1b3febd8ad0fd6118e4c0e0bdb0accde707460bdc2b80fae7553dd8eb2cd6a","tests/compile/derive-invalid-strategy.rs":"89c17c0ed2349af3664dc6782d004385e52eb9d1210b01991668079837896fcc","tests/compile/derive-invalid-strategy.stderr":"78f45b8d3ebe8d992f6eac6091b63aac8319f2aaa9a6513fa2b48f616f49b3a9","tests/compile/derive-missing-strategy.rs":"04b44f96d788d158ceaf399c148073c4c41a0d98793d55941c8b4e15350e9354","tests/compile/derive-missing-strategy.stderr":"40155bf928c1e1a9abeba8d5161251937ed49f833cfc4859d0ed22df57a38a86","tests/compile/derive-no-strategy.rs":"31926a1b666d72b7f6bdadde5680a676ed2d39595714ed6467be4cf4a7fa5686","tests/compile/derive-no-strategy.stderr":"2006acac73f7d93bdc1f92cbd7218e69e1c0de67f41b0804280d086a6de01ecc","tests/compile/derive-u8.rs":"335ec5984150c216a7132b208b7426d5987af090c0f650bed183f9280bd51e6c","tests/compile/derive-u8.stderr":"dff1ef27d3a1fc4556daf614307c70fbca2d400dbacdf51af9b9d3570400a962","tests/derive.rs":"f3d6a11660129bc3957487b780976aadd7b674d2a2357630c071e4984fb23c97","tests/impls.rs":"50b3ed1f8ca43b9959d40326b6e8b79a34f045f79e676700cf1d06c195dd7e12","tests/strategies.rs":"3e6ddb9bbf46188552e6c6cb9cf6c6450e4d234a897837500e914477a592d92e"},"package":"10bbef93abb1da61525bbc45eeaff6473a41907d19f8f9aa5168d214e10693e9"} \ No newline at end of file diff --git a/vendor/merge/CHANGELOG.md b/vendor/merge/CHANGELOG.md new file mode 100644 index 0000000000..5e52de0991 --- /dev/null +++ b/vendor/merge/CHANGELOG.md @@ -0,0 +1,9 @@ + + +# v0.1.0 (2020-09-01) + +Initial release providing the `Merge` trait and some merge strategies in the +`bool`, `num`, `ord` and `vec` modules. diff --git a/vendor/merge/Cargo.lock b/vendor/merge/Cargo.lock new file mode 100644 index 0000000000..7ffd14e126 --- /dev/null +++ b/vendor/merge/Cargo.lock @@ -0,0 +1,372 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +# SPDX-FileCopyrightText: 2020 Robin Krahl +# SPDX-License-Identifier: CC0-1.0 +[[package]] +name = "ansi_term" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", + "vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "envy" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "glob" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "heck" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "hermit-abi" +version = "0.1.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.76" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "merge" +version = "0.1.0" +dependencies = [ + "envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "merge_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", + "trybuild 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "merge_derive" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-error" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro-error-attr" +version = "1.0.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", + "syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "proc-macro2" +version = "1.0.19" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "strsim" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "structopt" +version = "0.3.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "structopt-derive 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "structopt-derive" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.36" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn-mid" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "termcolor" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "toml" +version = "0.5.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "trybuild" +version = "1.0.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", + "termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-segmentation" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "vec_map" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[metadata] +"checksum ansi_term 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ee49baf6cb617b853aa8d93bf420db2383fab46d314482ca2803b40d5fde979b" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" +"checksum envy 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f938a4abd5b75fe3737902dbc2e79ca142cc1526827a9e40b829a086758531a9" +"checksum glob 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "9b919933a397b79c37e33b77bb2aa3dc8eb6e165ad809e58ff75bc7db2e34574" +"checksum heck 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "20564e78d53d2bb135c343b3f47714a56af2061f1c928fdb541dc7b9fdd94205" +"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" +"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" +"checksum merge_derive 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07" +"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +"checksum proc-macro-error 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fc175e9777c3116627248584e8f8b3e2987405cabe1c0adf7d1dd28f09dc7880" +"checksum proc-macro-error-attr 1.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3cc9795ca17eb581285ec44936da7fc2335a3f34f2ddd13118b6f4d515435c50" +"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" +"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" +"checksum strsim 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "8ea5119cdb4c55b55d432abb513a0429384878c15dde60cc77b1c99de1a95a6a" +"checksum structopt 0.3.17 (registry+https://github.com/rust-lang/crates.io-index)" = "6cc388d94ffabf39b5ed5fadddc40147cb21e605f53db6f8f36a625d27489ac5" +"checksum structopt-derive 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "5e2513111825077552a6751dfad9e11ce0fba07d7276a3943a037d7e93e64c5f" +"checksum syn 1.0.36 (registry+https://github.com/rust-lang/crates.io-index)" = "4cdb98bcb1f9d81d07b536179c269ea15999b5d14ea958196413869445bb5250" +"checksum syn-mid 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7be3539f6c128a931cf19dcee741c1af532c7fd387baa739c03dd2e96479338a" +"checksum termcolor 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "bb6bfa289a4d7c5766392812c0a1f4c1ba45afa1ad47803c11e1f407d846d75f" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum toml 0.5.6 (registry+https://github.com/rust-lang/crates.io-index)" = "ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a" +"checksum trybuild 1.0.30 (registry+https://github.com/rust-lang/crates.io-index)" = "bbe777c4e2060f44d83892be1189f96200be8ed3d99569d5c2d5ee26e62c0ea9" +"checksum unicode-segmentation 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e83e153d1053cbb5a118eeff7fd5be06ed99153f00dbcd8ae310c5fb2b22edc0" +"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +"checksum vec_map 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" diff --git a/vendor/merge/Cargo.toml b/vendor/merge/Cargo.toml new file mode 100644 index 0000000000..0ced55242a --- /dev/null +++ b/vendor/merge/Cargo.toml @@ -0,0 +1,51 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "merge" +version = "0.1.0" +authors = ["Robin Krahl "] +exclude = [".builds/*"] +description = "Merge multiple values into one" +keywords = ["merge", "macros", "derive"] +categories = ["rust-patterns"] +license = "Apache-2.0 OR MIT" +repository = "https://git.sr.ht/~ireas/merge-rs" +[dependencies.merge_derive] +version = "0.1.0" +optional = true + +[dependencies.num-traits] +version = "0.2.12" +optional = true +[dev-dependencies.envy] +version = "0.4" + +[dev-dependencies.serde] +version = "1.0" +features = ["derive"] + +[dev-dependencies.structopt] +version = "0.3" + +[dev-dependencies.toml] +version = "0.5" + +[dev-dependencies.trybuild] +version = "1.0" + +[features] +default = ["derive", "num", "std"] +derive = ["merge_derive"] +num = ["num-traits"] +std = [] diff --git a/vendor/merge/LICENSES/Apache-2.0.txt b/vendor/merge/LICENSES/Apache-2.0.txt new file mode 100644 index 0000000000..d645695673 --- /dev/null +++ b/vendor/merge/LICENSES/Apache-2.0.txt @@ -0,0 +1,202 @@ + + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. diff --git a/vendor/merge/LICENSES/CC0-1.0.txt b/vendor/merge/LICENSES/CC0-1.0.txt new file mode 100644 index 0000000000..a343ccd433 --- /dev/null +++ b/vendor/merge/LICENSES/CC0-1.0.txt @@ -0,0 +1,119 @@ +Creative Commons Legal Code + +CC0 1.0 Universal CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES +NOT PROVIDE LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE +AN ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS INFORMATION +ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES REGARDING THE USE +OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED HEREUNDER, AND DISCLAIMS +LIABILITY FOR DAMAGES RESULTING FROM THE USE OF THIS DOCUMENT OR THE INFORMATION +OR WORKS PROVIDED HEREUNDER. + +Statement of Purpose + +The laws of most jurisdictions throughout the world automatically confer exclusive +Copyright and Related Rights (defined below) upon the creator and subsequent +owner(s) (each and all, an "owner") of an original work of authorship and/or +a database (each, a "Work"). + +Certain owners wish to permanently relinquish those rights to a Work for the +purpose of contributing to a commons of creative, cultural and scientific +works ("Commons") that the public can reliably and without fear of later claims +of infringement build upon, modify, incorporate in other works, reuse and +redistribute as freely as possible in any form whatsoever and for any purposes, +including without limitation commercial purposes. These owners may contribute +to the Commons to promote the ideal of a free culture and the further production +of creative, cultural and scientific works, or to gain reputation or greater +distribution for their Work in part through the use and efforts of others. + +For these and/or other purposes and motivations, and without any expectation +of additional consideration or compensation, the person associating CC0 with +a Work (the "Affirmer"), to the extent that he or she is an owner of Copyright +and Related Rights in the Work, voluntarily elects to apply CC0 to the Work +and publicly distribute the Work under its terms, with knowledge of his or +her Copyright and Related Rights in the Work and the meaning and intended +legal effect of CC0 on those rights. + +1. Copyright and Related Rights. A Work made available under CC0 may be protected +by copyright and related or neighboring rights ("Copyright and Related Rights"). +Copyright and Related Rights include, but are not limited to, the following: + +i. the right to reproduce, adapt, distribute, perform, display, communicate, +and translate a Work; + + ii. moral rights retained by the original author(s) and/or performer(s); + +iii. publicity and privacy rights pertaining to a person's image or likeness +depicted in a Work; + +iv. rights protecting against unfair competition in regards to a Work, subject +to the limitations in paragraph 4(a), below; + +v. rights protecting the extraction, dissemination, use and reuse of data +in a Work; + +vi. database rights (such as those arising under Directive 96/9/EC of the +European Parliament and of the Council of 11 March 1996 on the legal protection +of databases, and under any national implementation thereof, including any +amended or successor version of such directive); and + +vii. other similar, equivalent or corresponding rights throughout the world +based on applicable law or treaty, and any national implementations thereof. + +2. Waiver. To the greatest extent permitted by, but not in contravention of, +applicable law, Affirmer hereby overtly, fully, permanently, irrevocably and +unconditionally waives, abandons, and surrenders all of Affirmer's Copyright +and Related Rights and associated claims and causes of action, whether now +known or unknown (including existing as well as future claims and causes of +action), in the Work (i) in all territories worldwide, (ii) for the maximum +duration provided by applicable law or treaty (including future time extensions), +(iii) in any current or future medium and for any number of copies, and (iv) +for any purpose whatsoever, including without limitation commercial, advertising +or promotional purposes (the "Waiver"). Affirmer makes the Waiver for the +benefit of each member of the public at large and to the detriment of Affirmer's +heirs and successors, fully intending that such Waiver shall not be subject +to revocation, rescission, cancellation, termination, or any other legal or +equitable action to disrupt the quiet enjoyment of the Work by the public +as contemplated by Affirmer's express Statement of Purpose. + +3. Public License Fallback. Should any part of the Waiver for any reason be +judged legally invalid or ineffective under applicable law, then the Waiver +shall be preserved to the maximum extent permitted taking into account Affirmer's +express Statement of Purpose. In addition, to the extent the Waiver is so +judged Affirmer hereby grants to each affected person a royalty-free, non +transferable, non sublicensable, non exclusive, irrevocable and unconditional +license to exercise Affirmer's Copyright and Related Rights in the Work (i) +in all territories worldwide, (ii) for the maximum duration provided by applicable +law or treaty (including future time extensions), (iii) in any current or +future medium and for any number of copies, and (iv) for any purpose whatsoever, +including without limitation commercial, advertising or promotional purposes +(the "License"). The License shall be deemed effective as of the date CC0 +was applied by Affirmer to the Work. Should any part of the License for any +reason be judged legally invalid or ineffective under applicable law, such +partial invalidity or ineffectiveness shall not invalidate the remainder of +the License, and in such case Affirmer hereby affirms that he or she will +not (i) exercise any of his or her remaining Copyright and Related Rights +in the Work or (ii) assert any associated claims and causes of action with +respect to the Work, in either case contrary to Affirmer's express Statement +of Purpose. + + 4. Limitations and Disclaimers. + +a. No trademark or patent rights held by Affirmer are waived, abandoned, surrendered, +licensed or otherwise affected by this document. + +b. Affirmer offers the Work as-is and makes no representations or warranties +of any kind concerning the Work, express, implied, statutory or otherwise, +including without limitation warranties of title, merchantability, fitness +for a particular purpose, non infringement, or the absence of latent or other +defects, accuracy, or the present or absence of errors, whether or not discoverable, +all to the greatest extent permissible under applicable law. + +c. Affirmer disclaims responsibility for clearing rights of other persons +that may apply to the Work or any use thereof, including without limitation +any person's Copyright and Related Rights in the Work. Further, Affirmer disclaims +responsibility for obtaining any necessary consents, permissions or other +rights required for any use of the Work. + +d. Affirmer understands and acknowledges that Creative Commons is not a party +to this document and has no duty or obligation with respect to this CC0 or +use of the Work. diff --git a/vendor/merge/LICENSES/MIT.txt b/vendor/merge/LICENSES/MIT.txt new file mode 100644 index 0000000000..741cbc3898 --- /dev/null +++ b/vendor/merge/LICENSES/MIT.txt @@ -0,0 +1,21 @@ +The MIT License (MIT) + +Copyright (c) 2019 Robin Krahl + +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 --git a/vendor/merge/README.md b/vendor/merge/README.md new file mode 100644 index 0000000000..1bdb16a242 --- /dev/null +++ b/vendor/merge/README.md @@ -0,0 +1,98 @@ + + +# merge-rs + +The `merge` crate provides the `Merge` trait that can be used to merge multiple +values into one: + +```rust +trait Merge { + fn merge(&mut self, other: Self); +} +``` + +`Merge` is implemented for `Option` and can be derived for structs: + + +```rust +use merge::Merge; + +#[derive(Merge)] +struct User { + // Fields with the skip attribute are skipped by Merge + #[merge(skip)] + pub name: &'static str, + + // The Merge implementation for Option replaces its value if it is None + pub location: Option<&'static str>, + + // The strategy attribute is used to customize the merge behavior + #[merge(strategy = merge::vec::append)] + pub groups: Vec<&'static str>, +} + +let defaults = User { + name: "", + location: Some("Internet"), + groups: vec!["rust"], +}; +let mut ferris = User { + name: "Ferris", + location: None, + groups: vec!["mascot"], +}; +ferris.merge(defaults); + +assert_eq!("Ferris", ferris.name); +assert_eq!(Some("Internet"), ferris.location); +assert_eq!(vec!["mascot", "rust"], ferris.groups); +``` + +A merge strategy is a function with the signature `fn merge(left: &mut T, +right: T)` that merges `right` into `left`. The `merge` crate provides +strategies for the most common types, but you can also define your own +strategies. + +The trait can be used to merge configuration from different sources, for +example environment variables, multiple configuration files and command-line +arguments, see the `args.rs` example. + +## Features + +This crate has the following features: + +- `derive` (default): Enables the derive macro for the `Merge` trait using the + `merge_derive` crate. +- `num` (default): Enables the merge strategies in the `num` module that + require the `num_traits` crate. +- `std` (default): Enables the merge strategies in the `vec` module that + require the standard library. If this feature is not set, `merge` is a + `no_std` library. + +## Minimum Supported Rust Version + +This crate supports Rust 1.36.0 or later. + +## Contact + +For bug reports, patches, feature requests and other messages, please send a +mail to [~ireas/public-inbox@lists.sr.ht][] using the `[merge-rs]` prefix in +the subject. + +## License + +This project is dual-licensed under the [Apache-2.0][] and [MIT][] licenses. +The documentation and configuration files contained in this repository are +licensed under the [Creative Commons Zero][CC0] license. You can find a copy +of the license texts in the `LICENSES` directory. + +`merge-rs` complies with [version 3.0 of the REUSE specification][reuse]. + +[~ireas/public-inbox@lists.sr.ht]: mailto:~ireas/public-inbox@lists.sr.ht +[Apache-2.0]: https://opensource.org/licenses/Apache-2.0 +[MIT]: https://opensource.org/licenses/MIT +[CC0]: https://creativecommons.org/publicdomain/zero/1.0/ +[reuse]: https://reuse.software/practices/3.0/ diff --git a/vendor/merge/examples/args.rs b/vendor/merge/examples/args.rs new file mode 100644 index 0000000000..616a1d47a8 --- /dev/null +++ b/vendor/merge/examples/args.rs @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: CC0-1.0 + +use merge::Merge; +use serde::Deserialize; +use structopt::StructOpt; + +#[derive(Debug, Default, Deserialize, Merge, StructOpt)] +#[serde(default)] +struct Args { + #[structopt(short, long)] + #[merge(strategy = merge::bool::overwrite_false)] + debug: bool, + + input: Option, + + output: Option, +} + +fn get_config() -> Option { + let path: &std::path::Path = "args.toml".as_ref(); + if path.is_file() { + let s = std::fs::read_to_string(path).expect("Could not read configuration file"); + Some(toml::from_str(&s).expect("Could not parse configuration")) + } else { + None + } +} + +fn get_env() -> Args { + envy::prefixed("ARGS_") + .from_env() + .expect("Could not read environment variables") +} + +fn main() { + let mut args = Args::from_args(); + args.merge(get_env()); + if let Some(config) = get_config() { + args.merge(config); + } + println!("{:?}", args); +} diff --git a/vendor/merge/examples/user.rs b/vendor/merge/examples/user.rs new file mode 100644 index 0000000000..60161d73f3 --- /dev/null +++ b/vendor/merge/examples/user.rs @@ -0,0 +1,31 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: CC0-1.0 + +use merge::Merge; + +#[derive(Merge)] +struct User { + #[merge(skip)] + pub name: &'static str, + pub location: Option<&'static str>, + #[merge(strategy = merge::vec::append)] + pub groups: Vec<&'static str>, +} + +fn main() { + let defaults = User { + name: "", + location: Some("Internet"), + groups: vec!["rust"], + }; + let mut ferris = User { + name: "Ferris", + location: None, + groups: vec!["mascot"], + }; + ferris.merge(defaults); + + assert_eq!("Ferris", ferris.name); + assert_eq!(Some("Internet"), ferris.location); + assert_eq!(vec!["mascot", "rust"], ferris.groups); +} diff --git a/vendor/merge/src/lib.rs b/vendor/merge/src/lib.rs new file mode 100644 index 0000000000..2deebca4a3 --- /dev/null +++ b/vendor/merge/src/lib.rs @@ -0,0 +1,223 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +//! Provides [`Merge`][], a trait for objects that can be merged. +//! +//! # Usage +//! +//! ``` +//! trait Merge { +//! fn merge(&mut self, other: Self); +//! } +//! ``` +//! +//! The [`Merge`][] trait can be used to merge two objects of the same type into one. The intended +//! use case is merging configuration from different sources, for example environment variables, +//! multiple configuration files and command-line arguments, see the [`args.rs`][] example. +//! +//! `Merge` is implemented for `Option` and can be derived for structs. When deriving the `Merge` +//! trait for a struct, you can provide custom merge strategies for the fields that don’t implement +//! `Merge`. A merge strategy is a function with the signature `fn merge(left: &mut T, right: +//! T)` that merges `right` into `left`. The submodules of this crate provide strategies for the +//! most common types, but you can also define your own strategies. +//! +//! ## Features +//! +//! This crate has the following features: +//! +//! - `derive` (default): Enables the derive macro for the `Merge` trait using the `merge_derive` +//! crate. +//! - `num` (default): Enables the merge strategies in the `num` module that require the +//! `num_traits` crate. +//! - `std` (default): Enables the merge strategies in the `vec` module that require the standard +//! library. If this feature is not set, `merge` is a `no_std` library. +//! +//! # Example +//! +//! ``` +//! use merge::Merge; +//! +//! #[derive(Merge)] +//! struct User { +//! // Fields with the skip attribute are skipped by Merge +//! #[merge(skip)] +//! pub name: &'static str, +//! +//! // The Merge implementation for Option replaces its value if it is None +//! pub location: Option<&'static str>, +//! +//! // The strategy attribute is used to customize the merge behavior +//! #[merge(strategy = merge::vec::append)] +//! pub groups: Vec<&'static str>, +//! } +//! +//! let defaults = User { +//! name: "", +//! location: Some("Internet"), +//! groups: vec!["rust"], +//! }; +//! let mut ferris = User { +//! name: "Ferris", +//! location: None, +//! groups: vec!["mascot"], +//! }; +//! ferris.merge(defaults); +//! +//! assert_eq!("Ferris", ferris.name); +//! assert_eq!(Some("Internet"), ferris.location); +//! assert_eq!(vec!["mascot", "rust"], ferris.groups); +//! ``` +//! +//! [`Merge`]: trait.Merge.html +//! [`args.rs`]: https://git.sr.ht/~ireas/merge-rs/tree/master/examples/args.rs + +#![cfg_attr(not(feature = "std"), no_std)] + +#[cfg(feature = "derive")] +pub use merge_derive::*; + +/// A trait for objects that can be merged. +/// +/// # Deriving +/// +/// `Merge` can be derived for structs if the `derive` feature is enabled. The generated +/// implementation calls the `merge` method for all fields, or the merge strategy function if set. +/// You can use these field attributes to configure the generated implementation: +/// - `skip`: Skip this field in the `merge` method. +/// - `strategy = f`: Call `f(self.field, other.field)` instead of calling the `merge` function for +/// this field. +/// +/// # Examples +/// +/// Using the `Merge` implementation for `Option`: +/// +/// ``` +/// use merge::Merge as _; +/// +/// let mut val = None; +/// val.merge(Some(42)); +/// assert_eq!(Some(42), val); +/// ``` +/// +/// Deriving `Merge` for a struct: +/// +/// ``` +/// use merge::Merge; +/// +/// #[derive(Debug, PartialEq, Merge)] +/// struct S { +/// option: Option, +/// +/// #[merge(skip)] +/// s: String, +/// +/// #[merge(strategy = merge::bool::overwrite_false)] +/// flag: bool, +/// } +/// +/// let mut val = S { +/// option: None, +/// s: "some ignored value".to_owned(), +/// flag: false, +/// }; +/// val.merge(S { +/// option: Some(42), +/// s: "some other ignored value".to_owned(), +/// flag: true, +/// }); +/// assert_eq!(S { +/// option: Some(42), +/// s: "some ignored value".to_owned(), +/// flag: true, +/// }, val); +/// ``` +pub trait Merge { + /// Merge another object into this object. + fn merge(&mut self, other: Self); +} + +impl Merge for Option { + fn merge(&mut self, mut other: Self) { + if !self.is_some() { + *self = other.take(); + } + } +} + +/// Merge strategies for boolean types. +pub mod bool { + /// Overwrite left with right if the value of left is false. + pub fn overwrite_false(left: &mut bool, right: bool) { + if !*left { + *left = right; + } + } + + /// Overwrite left with right if the value of left is true. + pub fn overwrite_true(left: &mut bool, right: bool) { + if *left { + *left = right; + } + } +} + +/// Merge strategies for numeric types. +/// +/// These strategies are only available if the `num` feature is enabled. +#[cfg(feature = "num")] +pub mod num { + /// Set left to the saturated some of left and right. + pub fn saturating_add(left: &mut T, right: T) { + *left = left.saturating_add(&right); + } + + /// Overwrite left with right if the value of left is zero. + pub fn overwrite_zero(left: &mut T, right: T) { + if left.is_zero() { + *left = right; + } + } +} + +/// Merge strategies for types that form a total order. +pub mod ord { + use core::cmp; + + /// Set left to the maximum of left and right. + pub fn max(left: &mut T, right: T) { + if cmp::Ord::cmp(left, &right) == cmp::Ordering::Less { + *left = right; + } + } + + /// Set left to the minimum of left and right. + pub fn min(left: &mut T, right: T) { + if cmp::Ord::cmp(left, &right) == cmp::Ordering::Greater { + *left = right; + } + } +} + +/// Merge strategies for vectors. +/// +/// These strategies are only available if the `std` feature is enabled. +#[cfg(feature = "std")] +pub mod vec { + /// Overwrite left with right if left is empty. + pub fn overwrite_empty(left: &mut Vec, mut right: Vec) { + if left.is_empty() { + left.append(&mut right); + } + } + + /// Append the contents of right to left. + pub fn append(left: &mut Vec, mut right: Vec) { + left.append(&mut right); + } + + /// Prepend the contents of right to left. + pub fn prepend(left: &mut Vec, mut right: Vec) { + right.append(left); + *left = right; + } +} diff --git a/vendor/merge/tests/compile.rs b/vendor/merge/tests/compile.rs new file mode 100644 index 0000000000..aa1bda72c7 --- /dev/null +++ b/vendor/merge/tests/compile.rs @@ -0,0 +1,9 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +#[test] +#[ignore] +fn test_compile_fail() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/compile/*.rs"); +} diff --git a/vendor/merge/tests/compile/derive-enum.rs b/vendor/merge/tests/compile/derive-enum.rs new file mode 100644 index 0000000000..6c4f9b2538 --- /dev/null +++ b/vendor/merge/tests/compile/derive-enum.rs @@ -0,0 +1,13 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +enum E { + V1, + V2, + V3, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-enum.stderr b/vendor/merge/tests/compile/derive-enum.stderr new file mode 100644 index 0000000000..47835492ab --- /dev/null +++ b/vendor/merge/tests/compile/derive-enum.stderr @@ -0,0 +1,7 @@ +error: merge::Merge can only be derived for structs + --> $DIR/derive-enum.rs:6:10 + | +6 | #[derive(Merge)] + | ^^^^^ + | + = note: this error originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/merge/tests/compile/derive-invalid-attribute.rs b/vendor/merge/tests/compile/derive-invalid-attribute.rs new file mode 100644 index 0000000000..cbc3e542c7 --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-attribute.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(ignore)] + field1: Option, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-invalid-attribute.stderr b/vendor/merge/tests/compile/derive-invalid-attribute.stderr new file mode 100644 index 0000000000..ee1b2c669e --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-attribute.stderr @@ -0,0 +1,5 @@ +error: Unexpected attribute: ignore + --> $DIR/derive-invalid-attribute.rs:8:13 + | +8 | #[merge(ignore)] + | ^^^^^^ diff --git a/vendor/merge/tests/compile/derive-invalid-skip.rs b/vendor/merge/tests/compile/derive-invalid-skip.rs new file mode 100644 index 0000000000..78ed93ca32 --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-skip.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(skip = true)] + field1: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-invalid-skip.stderr b/vendor/merge/tests/compile/derive-invalid-skip.stderr new file mode 100644 index 0000000000..65679f9595 --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-skip.stderr @@ -0,0 +1,5 @@ +error: expected `,` + --> $DIR/derive-invalid-skip.rs:8:18 + | +8 | #[merge(skip = true)] + | ^ diff --git a/vendor/merge/tests/compile/derive-invalid-strategy.rs b/vendor/merge/tests/compile/derive-invalid-strategy.rs new file mode 100644 index 0000000000..46dc2594dd --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-strategy.rs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(strategy = my_custom_merge_strategy)] + field1: u8, +} + +fn my_custom_merge_strategy(left: u8, right: u8) -> u8 { + left + right +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-invalid-strategy.stderr b/vendor/merge/tests/compile/derive-invalid-strategy.stderr new file mode 100644 index 0000000000..ecdd08504e --- /dev/null +++ b/vendor/merge/tests/compile/derive-invalid-strategy.stderr @@ -0,0 +1,13 @@ +error[E0308]: mismatched types + --> $DIR/derive-invalid-strategy.rs:8:24 + | +8 | #[merge(strategy = my_custom_merge_strategy)] + | ________________________^ +9 | | field1: u8, + | |__________^ expected `u8`, found `&mut u8` + | +help: consider removing the borrow + | +8 | #[merge(strategy = my_custom_merge_strategy)] +9 | field1: u8, + | diff --git a/vendor/merge/tests/compile/derive-missing-strategy.rs b/vendor/merge/tests/compile/derive-missing-strategy.rs new file mode 100644 index 0000000000..c9c107328e --- /dev/null +++ b/vendor/merge/tests/compile/derive-missing-strategy.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(strategy = my_custom_merge_strategy)] + field1: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-missing-strategy.stderr b/vendor/merge/tests/compile/derive-missing-strategy.stderr new file mode 100644 index 0000000000..9fb1a03681 --- /dev/null +++ b/vendor/merge/tests/compile/derive-missing-strategy.stderr @@ -0,0 +1,5 @@ +error[E0425]: cannot find function `my_custom_merge_strategy` in this scope + --> $DIR/derive-missing-strategy.rs:8:24 + | +8 | #[merge(strategy = my_custom_merge_strategy)] + | ^^^^^^^^^^^^^^^^^^^^^^^^ not found in this scope diff --git a/vendor/merge/tests/compile/derive-no-strategy.rs b/vendor/merge/tests/compile/derive-no-strategy.rs new file mode 100644 index 0000000000..10b95fa8a4 --- /dev/null +++ b/vendor/merge/tests/compile/derive-no-strategy.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + #[merge(strategy)] + field1: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-no-strategy.stderr b/vendor/merge/tests/compile/derive-no-strategy.stderr new file mode 100644 index 0000000000..9da8914c06 --- /dev/null +++ b/vendor/merge/tests/compile/derive-no-strategy.stderr @@ -0,0 +1,5 @@ +error: expected `=` + --> $DIR/derive-no-strategy.rs:8:12 + | +8 | #[merge(strategy)] + | ^^^^^^^^^^ diff --git a/vendor/merge/tests/compile/derive-u8.rs b/vendor/merge/tests/compile/derive-u8.rs new file mode 100644 index 0000000000..25bfd9b553 --- /dev/null +++ b/vendor/merge/tests/compile/derive-u8.rs @@ -0,0 +1,12 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +#[derive(Merge)] +struct S { + field1: Option, + field2: u8, +} + +fn main() {} diff --git a/vendor/merge/tests/compile/derive-u8.stderr b/vendor/merge/tests/compile/derive-u8.stderr new file mode 100644 index 0000000000..de3b5c224e --- /dev/null +++ b/vendor/merge/tests/compile/derive-u8.stderr @@ -0,0 +1,7 @@ +error[E0277]: the trait bound `u8: merge::Merge` is not satisfied + --> $DIR/derive-u8.rs:9:5 + | +9 | field2: u8, + | ^^^^^^ the trait `merge::Merge` is not implemented for `u8` + | + = note: required by `merge::Merge::merge` diff --git a/vendor/merge/tests/derive.rs b/vendor/merge/tests/derive.rs new file mode 100644 index 0000000000..0ac41638e7 --- /dev/null +++ b/vendor/merge/tests/derive.rs @@ -0,0 +1,540 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +#![cfg(feature = "derive")] + +use merge::Merge; + +fn test(expected: T, mut left: T, right: T) { + left.merge(right); + assert_eq!(expected, left); +} + +#[test] +fn test_one_option_field() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + } + + impl S { + pub fn new(field1: Option) -> S { + S { field1 } + } + } + + test(S::new(Some(1)), S::new(Some(1)), S::new(Some(2))); + test(S::new(Some(1)), S::new(Some(1)), S::new(None)); + test(S::new(Some(2)), S::new(None), S::new(Some(2))); + test(S::new(None), S::new(None), S::new(None)); +} + +#[test] +fn test_two_option_fields() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + field2: Option, + } + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S { field1, field2 } + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), Some(2)), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, Some(2)), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} + +#[test] +fn test_skip_valid() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + #[merge(skip)] + field2: Option, + } + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S { field1, field2 } + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, None), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} + +#[test] +fn test_skip_invalid() { + #[derive(Debug, Merge, PartialEq)] + struct S { + field1: Option, + #[merge(skip)] + field2: usize, + } + + impl S { + pub fn new(field1: Option, field2: usize) -> S { + S { field1, field2 } + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 2)); + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(Some(2), 0)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 2)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(Some(2), 0)); + + // left.field1 == Some(1) + // right.field1 == None + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 2)); + test(S::new(Some(1), 1), S::new(Some(1), 1), S::new(None, 0)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 2)); + test(S::new(Some(1), 0), S::new(Some(1), 0), S::new(None, 0)); + + // left.field1 == None + // right.field1 == Some(2) + test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 2)); + test(S::new(Some(2), 1), S::new(None, 1), S::new(Some(2), 0)); + test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 2)); + test(S::new(Some(2), 0), S::new(None, 0), S::new(Some(2), 0)); + + // left.field1 == None + // right.field1 == None + test(S::new(None, 1), S::new(None, 1), S::new(None, 2)); + test(S::new(None, 1), S::new(None, 1), S::new(None, 0)); + test(S::new(None, 0), S::new(None, 0), S::new(None, 2)); + test(S::new(None, 0), S::new(None, 0), S::new(None, 0)); +} + +#[test] +fn test_strategy_usize_add() { + #[derive(Debug, Merge, PartialEq)] + struct S { + #[merge(strategy = add)] + field1: usize, + } + + impl S { + pub fn new(field1: usize) -> S { + S { field1 } + } + } + + fn add(left: &mut usize, right: usize) { + *left = *left + right; + } + + test(S::new(0), S::new(0), S::new(0)); + test(S::new(1), S::new(1), S::new(0)); + test(S::new(1), S::new(0), S::new(1)); + test(S::new(2), S::new(1), S::new(1)); +} + +#[test] +fn test_strategy_vec_append() { + #[derive(Debug, Merge, PartialEq)] + struct S { + #[merge(strategy = append)] + field1: Vec, + } + + impl S { + pub fn new(field1: Vec) -> S { + S { field1 } + } + } + + fn append(left: &mut Vec, mut right: Vec) { + left.append(&mut right); + } + + test( + S::new(vec![0, 1, 2, 3]), + S::new(vec![0, 1]), + S::new(vec![2, 3]), + ); + test( + S::new(vec![0, 1, 2, 3]), + S::new(vec![0, 1, 2, 3]), + S::new(vec![]), + ); + test( + S::new(vec![0, 1, 2, 3]), + S::new(vec![]), + S::new(vec![0, 1, 2, 3]), + ); +} + +#[test] +fn test_unnamed_fields() { + #[derive(Debug, Merge, PartialEq)] + struct S(Option, Option); + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S(field1, field2) + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), Some(2)), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), Some(2)), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, Some(2)), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} + +#[test] +fn test_unnamed_fields_skip() { + #[derive(Debug, Merge, PartialEq)] + struct S(Option, #[merge(skip)] Option); + + impl S { + pub fn new(field1: Option, field2: Option) -> S { + S(field1, field2) + } + } + + // left.field1 == Some(1) + // right.field1 == Some(2) + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(Some(2), None), + ); + + // left.field1 == Some(1) + // right.field1 == None + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), Some(1)), + S::new(Some(1), Some(1)), + S::new(None, None), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, Some(2)), + ); + test( + S::new(Some(1), None), + S::new(Some(1), None), + S::new(None, None), + ); + + // left.field1 == None + // right.field1 == Some(2) + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), Some(1)), + S::new(None, Some(1)), + S::new(Some(2), None), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), Some(2)), + ); + test( + S::new(Some(2), None), + S::new(None, None), + S::new(Some(2), None), + ); + + // left.field1 == None + // right.field1 == None + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, Some(2)), + ); + test( + S::new(None, Some(1)), + S::new(None, Some(1)), + S::new(None, None), + ); + test( + S::new(None, None), + S::new(None, None), + S::new(None, Some(2)), + ); + test(S::new(None, None), S::new(None, None), S::new(None, None)); +} diff --git a/vendor/merge/tests/impls.rs b/vendor/merge/tests/impls.rs new file mode 100644 index 0000000000..d8378e538f --- /dev/null +++ b/vendor/merge/tests/impls.rs @@ -0,0 +1,16 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +use merge::Merge; + +fn test(expected: T, mut left: T, right: T) { + left.merge(right); + assert_eq!(expected, left); +} + +#[test] +fn test_option() { + test(Some(1), Some(1), Some(2)); + test(Some(2), None, Some(2)); + test(None::, None, None); +} diff --git a/vendor/merge/tests/strategies.rs b/vendor/merge/tests/strategies.rs new file mode 100644 index 0000000000..3a35ea2a65 --- /dev/null +++ b/vendor/merge/tests/strategies.rs @@ -0,0 +1,122 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +#![cfg(feature = "derive")] + +use merge::Merge; + +fn test(expected: T, mut left: T, right: T) { + left.merge(right); + assert_eq!(expected, left); +} + +#[test] +fn test_bool_overwrite_false() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::bool::overwrite_false)] bool); + + test(S(false), S(false), S(false)); + test(S(true), S(false), S(true)); + test(S(true), S(true), S(false)); + test(S(true), S(true), S(true)); +} + +#[test] +fn test_bool_overwrite_true() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::bool::overwrite_true)] bool); + + test(S(false), S(false), S(false)); + test(S(false), S(false), S(true)); + test(S(false), S(true), S(false)); + test(S(true), S(true), S(true)); +} + +#[cfg(feature = "num")] +#[test] +fn test_num_saturating_add() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::num::saturating_add)] u8); + + test(S(0), S(0), S(0)); + test(S(1), S(0), S(1)); + test(S(255), S(255), S(10)); + test(S(40), S(30), S(10)); +} + +#[cfg(feature = "num")] +#[test] +fn test_num_overwrite_zero() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::num::overwrite_zero)] u8); + + test(S(0), S(0), S(0)); + test(S(1), S(0), S(1)); + test(S(255), S(255), S(10)); +} + +#[test] +fn test_ord_max() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::ord::max)] u8); + + test(S(2), S(1), S(2)); + test(S(2), S(2), S(1)); + test(S(2), S(2), S(2)); + test(S(2), S(2), S(0)); + test(S(2), S(0), S(2)); + test(S(33), S(33), S(11)); +} + +#[test] +fn test_ord_min() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::ord::min)] u8); + + test(S(1), S(1), S(2)); + test(S(1), S(2), S(1)); + test(S(2), S(2), S(2)); + test(S(0), S(2), S(0)); + test(S(0), S(0), S(2)); + test(S(11), S(33), S(11)); +} + +#[cfg(feature = "std")] +#[test] +fn test_vec_overwrite_empty() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::vec::overwrite_empty)] Vec); + + test(S(vec![]), S(vec![]), S(vec![])); + test(S(vec![1]), S(vec![]), S(vec![1])); + test(S(vec![0]), S(vec![0]), S(vec![1])); + test(S(vec![255]), S(vec![255]), S(vec![10])); +} + +#[cfg(feature = "std")] +#[test] +fn test_vec_append() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::vec::append)] Vec); + + test(S(vec![]), S(vec![]), S(vec![])); + test(S(vec![1]), S(vec![]), S(vec![1])); + test(S(vec![0, 1]), S(vec![0]), S(vec![1])); + test(S(vec![255, 10]), S(vec![255]), S(vec![10])); + test(S(vec![0, 1, 2, 3, 4]), S(vec![0, 1, 2]), S(vec![3, 4])); + test(S(vec![3, 4, 0, 1, 2]), S(vec![3, 4]), S(vec![0, 1, 2])); +} + +#[cfg(feature = "std")] +#[test] +fn test_vec_prepend() { + #[derive(Debug, Merge, PartialEq)] + struct S(#[merge(strategy = merge::vec::prepend)] Vec); + + test(S(vec![]), S(vec![]), S(vec![])); + test(S(vec![1]), S(vec![]), S(vec![1])); + test(S(vec![1, 0]), S(vec![0]), S(vec![1])); + test(S(vec![10, 255]), S(vec![255]), S(vec![10])); + test(S(vec![3, 4, 0, 1, 2]), S(vec![0, 1, 2]), S(vec![3, 4])); + test(S(vec![0, 1, 2, 3, 4]), S(vec![3, 4]), S(vec![0, 1, 2])); +} diff --git a/vendor/merge_derive/.cargo-checksum.json b/vendor/merge_derive/.cargo-checksum.json new file mode 100644 index 0000000000..745acccf38 --- /dev/null +++ b/vendor/merge_derive/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"b02f58391ecb6521ed3f453f28ff0ed1e6c7935b51e4f1c4b346039725aeffd1","Cargo.toml":"3dec793dd43afad71233015d71f53422b106fe24969cc44c4421315693b514c3","README.md":"9e7e5b4de658b75295d7e0179a4828d3699d995fa766626c253c7df09f8bff5b","src/lib.rs":"22bd90be174c7228dab8d47809f7bc9a7fb28ba2091f78959c240f0a558cc3d6"},"package":"209d075476da2e63b4b29e72a2ef627b840589588e71400a25e3565c4f849d07"} \ No newline at end of file diff --git a/vendor/merge_derive/CHANGELOG.md b/vendor/merge_derive/CHANGELOG.md new file mode 100644 index 0000000000..954a87357a --- /dev/null +++ b/vendor/merge_derive/CHANGELOG.md @@ -0,0 +1,8 @@ + + +# v0.1.0 (2020-09-01) + +Initial release providing a derive macro for the `Merge` trait. diff --git a/vendor/merge_derive/Cargo.toml b/vendor/merge_derive/Cargo.toml new file mode 100644 index 0000000000..2e338716ca --- /dev/null +++ b/vendor/merge_derive/Cargo.toml @@ -0,0 +1,37 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "merge_derive" +version = "0.1.0" +authors = ["Robin Krahl "] +description = "Derive macro for the merge::Merge trait" +readme = "README.md" +keywords = ["merge", "macros", "derive"] +categories = ["rust-patterns"] +license = "Apache-2.0 OR MIT" +repository = "https://git.sr.ht/~ireas/merge-rs/tree/master/merge_derive" + +[lib] +proc-macro = true +[dependencies.proc-macro-error] +version = "1.0" + +[dependencies.proc-macro2] +version = "1.0" + +[dependencies.quote] +version = "1.0" + +[dependencies.syn] +version = "1.0" diff --git a/vendor/merge_derive/README.md b/vendor/merge_derive/README.md new file mode 100644 index 0000000000..7913ba4e06 --- /dev/null +++ b/vendor/merge_derive/README.md @@ -0,0 +1,11 @@ + + +# merge-derive-rs + +This crate provides a derive macro for the `merge::Merge` crate. See the +[`merge`][] crate for more information. + +[`merge`]: https://lib.rs/crates/merge diff --git a/vendor/merge_derive/src/lib.rs b/vendor/merge_derive/src/lib.rs new file mode 100644 index 0000000000..75732f9b6f --- /dev/null +++ b/vendor/merge_derive/src/lib.rs @@ -0,0 +1,150 @@ +// SPDX-FileCopyrightText: 2020 Robin Krahl +// SPDX-License-Identifier: Apache-2.0 or MIT + +//! A derive macro for the [`merge::Merge`][] trait. +//! +//! See the documentation for the [`merge`][] crate for more information. +//! +//! [`merge`]: https://lib.rs/crates/merge +//! [`merge::Merge`]: https://docs.rs/merge/latest/merge/trait.Merge.html + +extern crate proc_macro; + +use proc_macro2::TokenStream; +use proc_macro_error::{abort, abort_call_site, dummy::set_dummy, proc_macro_error, ResultExt}; +use quote::{quote, quote_spanned}; +use syn::Token; + +struct Field { + name: syn::Member, + span: proc_macro2::Span, + attrs: FieldAttrs, +} + +#[derive(Default)] +struct FieldAttrs { + skip: bool, + strategy: Option, +} + +enum FieldAttr { + Skip, + Strategy(syn::Path), +} + +#[proc_macro_derive(Merge, attributes(merge))] +#[proc_macro_error] +pub fn merge_derive(input: proc_macro::TokenStream) -> proc_macro::TokenStream { + let ast = syn::parse(input).unwrap(); + impl_merge(&ast).into() +} + +fn impl_merge(ast: &syn::DeriveInput) -> TokenStream { + let name = &ast.ident; + + set_dummy(quote! { + impl ::merge::Merge for #name { + fn merge(&mut self, other: Self) { + unimplemented!() + } + } + }); + + if let syn::Data::Struct(syn::DataStruct { ref fields, .. }) = ast.data { + impl_merge_for_struct(name, fields) + } else { + abort_call_site!("merge::Merge can only be derived for structs") + } +} + +fn impl_merge_for_struct(name: &syn::Ident, fields: &syn::Fields) -> TokenStream { + let assignments = gen_assignments(fields); + + quote! { + impl ::merge::Merge for #name { + fn merge(&mut self, other: Self) { + #assignments + } + } + } +} + +fn gen_assignments(fields: &syn::Fields) -> TokenStream { + let fields = fields.iter().enumerate().map(Field::from); + let assignments = fields.filter(|f| !f.attrs.skip).map(|f| gen_assignment(&f)); + quote! { + #( #assignments )* + } +} + +fn gen_assignment(field: &Field) -> TokenStream { + use syn::spanned::Spanned; + + let name = &field.name; + if let Some(strategy) = &field.attrs.strategy { + quote_spanned!(strategy.span()=> #strategy(&mut self.#name, other.#name);) + } else { + quote_spanned!(field.span=> ::merge::Merge::merge(&mut self.#name, other.#name);) + } +} + +impl From<(usize, &syn::Field)> for Field { + fn from(data: (usize, &syn::Field)) -> Self { + use syn::spanned::Spanned; + + let (index, field) = data; + Field { + name: if let Some(ident) = &field.ident { + syn::Member::Named(ident.clone()) + } else { + syn::Member::Unnamed(index.into()) + }, + span: field.span(), + attrs: field.attrs.iter().into(), + } + } +} + +impl FieldAttrs { + fn apply(&mut self, attr: FieldAttr) { + match attr { + FieldAttr::Skip => self.skip = true, + FieldAttr::Strategy(path) => self.strategy = Some(path), + } + } +} + +impl<'a, I: Iterator> From for FieldAttrs { + fn from(iter: I) -> Self { + let mut field_attrs = Self::default(); + + for attr in iter { + if !attr.path.is_ident("merge") { + continue; + } + + let parser = syn::punctuated::Punctuated::::parse_terminated; + for attr in attr.parse_args_with(parser).unwrap_or_abort() { + field_attrs.apply(attr); + } + } + + field_attrs + } +} + +impl syn::parse::Parse for FieldAttr { + fn parse(input: syn::parse::ParseStream) -> syn::parse::Result { + let name: syn::Ident = input.parse()?; + if name == "skip" { + // TODO check remaining stream + Ok(FieldAttr::Skip) + } else if name == "strategy" { + let _: Token![=] = input.parse()?; + let path: syn::Path = input.parse()?; + Ok(FieldAttr::Strategy(path)) + } else { + abort!(name, "Unexpected attribute: {}", name) + } + } +} diff --git a/vendor/miniz_oxide/.cargo-checksum.json b/vendor/miniz_oxide/.cargo-checksum.json index aeba06ecfb..fde8420c94 100644 --- a/vendor/miniz_oxide/.cargo-checksum.json +++ b/vendor/miniz_oxide/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"d302f27e8737cdcfe95db7dceb5672aa8380ed36459979c950b4735d284f667c","LICENSE":"e190940e8ad3cdd4fca962a6508ed6865d589d314b1cb055f86000e124b88d8d","Readme.md":"fca5f9500a8caf5a334dc53925fa3dda063a8a4de88fe107251998300b432c0d","src/deflate/buffer.rs":"2953214307677f33f901f8e52256b6e7a296f4234238179613168ddad106645c","src/deflate/core.rs":"db40c9a95f5a9ad72c17eef934e163d90768b2a0f8fa53cf37d71e550cdf84f9","src/deflate/mod.rs":"e6b6b114329c555bd8fc769d4e955b3a34663206b283092f13d0bc85424b56d4","src/deflate/stream.rs":"49120444fb12b58191c2bb0dda598cd3614cbc329eb3720a50ce8f5017c04838","src/inflate/core.rs":"a4d8c3cf20ec3b89b12f7ac1df37b521d29e910f854cb1ccb2b8c7bb23244b25","src/inflate/mod.rs":"c63e855ba72c44aa5df6ab199360d5cce20ec01caf5539d38c76295e076f39be","src/inflate/output_buffer.rs":"3948c26897a8d30a356fc8e9ce1df7513c21d186838220ad63a69b6b1d985eab","src/inflate/stream.rs":"b3108fb0c6ae935a27c56ac258abf6a2e47c69c6ba0d205afaa742f3b5010572","src/lib.rs":"9322a5e0d5af90c017d9ae44a502045fecfdc134bcbe946e72609835644e9b7d","src/shared.rs":"889b9d9d3b4bc0693f94c850806e9cf68ed9079e0ada2b2f51bfffe388e02c6a"},"package":"be0f75932c1f6cfae3c04000e40114adf955636e19040f9c0a2c380702aa1c7f"} \ No newline at end of file +{"files":{"Cargo.toml":"3b97eb92a60ed95a9db4a12ddc97093efc60666077c729363c902f7d37a9c2bd","LICENSE":"e190940e8ad3cdd4fca962a6508ed6865d589d314b1cb055f86000e124b88d8d","Readme.md":"fca5f9500a8caf5a334dc53925fa3dda063a8a4de88fe107251998300b432c0d","src/deflate/buffer.rs":"2953214307677f33f901f8e52256b6e7a296f4234238179613168ddad106645c","src/deflate/core.rs":"db40c9a95f5a9ad72c17eef934e163d90768b2a0f8fa53cf37d71e550cdf84f9","src/deflate/mod.rs":"d17cd7a576be570cf948d2fbf0ce535be35cc4ef94cbfbfaefc17c6641bd412a","src/deflate/stream.rs":"49120444fb12b58191c2bb0dda598cd3614cbc329eb3720a50ce8f5017c04838","src/inflate/core.rs":"a4d8c3cf20ec3b89b12f7ac1df37b521d29e910f854cb1ccb2b8c7bb23244b25","src/inflate/mod.rs":"f9c4626e2223b12352135c4359a9f4522fce625a45adff12991bd465509f4f46","src/inflate/output_buffer.rs":"3948c26897a8d30a356fc8e9ce1df7513c21d186838220ad63a69b6b1d985eab","src/inflate/stream.rs":"799424e68bbb11e99038c4f70f67d6298b738b443652be474018844bcd4e6996","src/lib.rs":"39feb2ac3d9d8000c387865fd8de60bdd6c91d7ad8ec040b35507d917bec9b94","src/shared.rs":"889b9d9d3b4bc0693f94c850806e9cf68ed9079e0ada2b2f51bfffe388e02c6a"},"package":"4d7559a8a40d0f97e1edea3220f698f78b1c5ab67532e49f68fde3910323b722"} \ No newline at end of file diff --git a/vendor/miniz_oxide/Cargo.toml b/vendor/miniz_oxide/Cargo.toml index 477df48342..712f7bc822 100644 --- a/vendor/miniz_oxide/Cargo.toml +++ b/vendor/miniz_oxide/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "miniz_oxide" -version = "0.4.0" +version = "0.4.1" authors = ["Frommi ", "oyvindln "] exclude = ["benches/*", "tests/*"] description = "DEFLATE compression and decompression library rewritten in Rust based on miniz" @@ -46,4 +46,5 @@ optional = true package = "rustc-std-workspace-core" [features] +no_extern_crate_alloc = [] rustc-dep-of-std = ["core", "alloc", "compiler_builtins", "adler/rustc-dep-of-std"] diff --git a/vendor/miniz_oxide/src/deflate/mod.rs b/vendor/miniz_oxide/src/deflate/mod.rs index ac8b5e5677..cc90ca6749 100644 --- a/vendor/miniz_oxide/src/deflate/mod.rs +++ b/vendor/miniz_oxide/src/deflate/mod.rs @@ -1,7 +1,7 @@ //! This module contains functionality for compression. -use alloc::vec; -use alloc::vec::Vec; +use crate::alloc::vec; +use crate::alloc::vec::Vec; mod buffer; pub mod core; diff --git a/vendor/miniz_oxide/src/inflate/mod.rs b/vendor/miniz_oxide/src/inflate/mod.rs index 5757016699..8edcbbe370 100644 --- a/vendor/miniz_oxide/src/inflate/mod.rs +++ b/vendor/miniz_oxide/src/inflate/mod.rs @@ -1,9 +1,10 @@ //! This module contains functionality for decompression. +use ::core::cmp::min; use ::core::usize; -use alloc::boxed::Box; -use alloc::vec; -use alloc::vec::Vec; +use crate::alloc::boxed::Box; +use crate::alloc::vec; +use crate::alloc::vec::Vec; pub mod core; mod output_buffer; @@ -61,7 +62,7 @@ impl TINFLStatus { /// Returns a status and an integer representing where the decompressor failed on failure. #[inline] pub fn decompress_to_vec(input: &[u8]) -> Result, TINFLStatus> { - decompress_to_vec_inner(input, 0) + decompress_to_vec_inner(input, 0, usize::max_value()) } /// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector. @@ -69,12 +70,43 @@ pub fn decompress_to_vec(input: &[u8]) -> Result, TINFLStatus> { /// Returns a status and an integer representing where the decompressor failed on failure. #[inline] pub fn decompress_to_vec_zlib(input: &[u8]) -> Result, TINFLStatus> { - decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER) + decompress_to_vec_inner( + input, + inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, + usize::max_value(), + ) } -fn decompress_to_vec_inner(input: &[u8], flags: u32) -> Result, TINFLStatus> { +/// Decompress the deflate-encoded data in `input` to a vector. +/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size, +/// `TINFLStatus::HasMoreOutput` error is returned. +/// +/// Returns a status and an integer representing where the decompressor failed on failure. +#[inline] +pub fn decompress_to_vec_with_limit(input: &[u8], max_size: usize) -> Result, TINFLStatus> { + decompress_to_vec_inner(input, 0, max_size) +} + +/// Decompress the deflate-encoded data (with a zlib wrapper) in `input` to a vector. +/// The vector is grown to at most `max_size` bytes; if the data does not fit in that size, +/// `TINFLStatus::HasMoreOutput` error is returned. +/// +/// Returns a status and an integer representing where the decompressor failed on failure. +#[inline] +pub fn decompress_to_vec_zlib_with_limit( + input: &[u8], + max_size: usize, +) -> Result, TINFLStatus> { + decompress_to_vec_inner(input, inflate_flags::TINFL_FLAG_PARSE_ZLIB_HEADER, max_size) +} + +fn decompress_to_vec_inner( + input: &[u8], + flags: u32, + max_output_size: usize, +) -> Result, TINFLStatus> { let flags = flags | inflate_flags::TINFL_FLAG_USING_NON_WRAPPING_OUTPUT_BUF; - let mut ret: Vec = vec![0; input.len() * 2]; + let mut ret: Vec = vec![0; min(input.len().saturating_mul(2), max_output_size)]; let mut decomp = Box::::default(); @@ -95,8 +127,15 @@ fn decompress_to_vec_inner(input: &[u8], flags: u32) -> Result, TINFLSta } TINFLStatus::HasMoreOutput => { - // We need more space so resize the buffer. - ret.resize(ret.len() + out_pos, 0); + // We need more space, so check if we can resize the buffer and do it. + let new_len = ret + .len() + .checked_add(out_pos) + .ok_or(TINFLStatus::HasMoreOutput)?; + if new_len > max_output_size { + return Err(TINFLStatus::HasMoreOutput); + }; + ret.resize(new_len, 0); } _ => return Err(status), @@ -106,14 +145,30 @@ fn decompress_to_vec_inner(input: &[u8], flags: u32) -> Result, TINFLSta #[cfg(test)] mod test { - use super::decompress_to_vec_zlib; + use super::TINFLStatus; + use super::{decompress_to_vec_zlib, decompress_to_vec_zlib_with_limit}; + const encoded: [u8; 20] = [ + 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19, + ]; #[test] fn decompress_vec() { - let encoded = [ - 120, 156, 243, 72, 205, 201, 201, 215, 81, 168, 202, 201, 76, 82, 4, 0, 27, 101, 4, 19, - ]; let res = decompress_to_vec_zlib(&encoded[..]).unwrap(); assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]); } + + #[test] + fn decompress_vec_with_high_limit() { + let res = decompress_to_vec_zlib_with_limit(&encoded[..], 100_000).unwrap(); + assert_eq!(res.as_slice(), &b"Hello, zlib!"[..]); + } + + #[test] + fn fail_to_decompress_with_limit() { + let res = decompress_to_vec_zlib_with_limit(&encoded[..], 8); + match res { + Err(TINFLStatus::HasMoreOutput) => (), // expected result + _ => panic!("Decompression output size limit was not enforced"), + } + } } diff --git a/vendor/miniz_oxide/src/inflate/stream.rs b/vendor/miniz_oxide/src/inflate/stream.rs index 39c602f331..8823218387 100644 --- a/vendor/miniz_oxide/src/inflate/stream.rs +++ b/vendor/miniz_oxide/src/inflate/stream.rs @@ -1,13 +1,59 @@ //! Extra streaming decompression functionality. //! //! As of now this is mainly inteded for use to build a higher-level wrapper. -use alloc::boxed::Box; +use crate::alloc::boxed::Box; use core::{cmp, mem}; use crate::inflate::core::{decompress, inflate_flags, DecompressorOxide, TINFL_LZ_DICT_SIZE}; use crate::inflate::TINFLStatus; use crate::{DataFormat, MZError, MZFlush, MZResult, MZStatus, StreamResult}; +/// Tag that determines reset policy of [InflateState](struct.InflateState.html) +pub trait ResetPolicy { + /// Performs reset + fn reset(&self, state: &mut InflateState); +} + +/// Resets state, without performing expensive ops (e.g. zeroing buffer) +/// +/// Note that not zeroing buffer can lead to security issues when dealing with untrusted input. +pub struct MinReset; + +impl ResetPolicy for MinReset { + fn reset(&self, state: &mut InflateState) { + state.decompressor().init(); + state.dict_ofs = 0; + state.dict_avail = 0; + state.first_call = true; + state.has_flushed = false; + state.last_status = TINFLStatus::NeedsMoreInput; + } +} + +/// Resets state and zero memory, continuing to use the same data format. +pub struct ZeroReset; + +impl ResetPolicy for ZeroReset { + #[inline] + fn reset(&self, state: &mut InflateState) { + MinReset.reset(state); + state.dict = [0; TINFL_LZ_DICT_SIZE]; + } +} + +/// Full reset of the state, including zeroing memory. +/// +/// Requires to provide new data format. +pub struct FullReset(DataFormat); + +impl ResetPolicy for FullReset { + #[inline] + fn reset(&self, state: &mut InflateState) { + ZeroReset.reset(state); + state.data_format = self.0; + } +} + /// A struct that compbines a decompressor with extra data for streaming decompression. /// pub struct InflateState { @@ -95,17 +141,17 @@ impl InflateState { b } + #[inline] /// Reset the decompressor without re-allocating memory, using the given /// data format. pub fn reset(&mut self, data_format: DataFormat) { - self.decompressor().init(); - self.dict = [0; TINFL_LZ_DICT_SIZE]; - self.dict_ofs = 0; - self.dict_avail = 0; - self.first_call = true; - self.has_flushed = false; - self.data_format = data_format; - self.last_status = TINFLStatus::NeedsMoreInput; + self.reset_as(FullReset(data_format)); + } + + #[inline] + /// Resets the state according to specified policy. + pub fn reset_as(&mut self, policy: T) { + policy.reset(self) } } @@ -314,7 +360,17 @@ mod test { assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); assert_eq!(res.bytes_consumed, encoded.len()); - state.reset(DataFormat::Zlib); + state.reset_as(super::ZeroReset); + out.iter_mut().map(|x| *x = 0).count(); + let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); + let status = res.status.expect("Failed to decompress!"); + assert_eq!(status, MZStatus::StreamEnd); + assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); + assert_eq!(res.bytes_consumed, encoded.len()); + + state.reset_as(super::MinReset); + out.iter_mut().map(|x| *x = 0).count(); + let res = inflate(&mut state, &encoded, &mut out, MZFlush::Finish); let status = res.status.expect("Failed to decompress!"); assert_eq!(status, MZStatus::StreamEnd); assert_eq!(out[..res.bytes_written as usize], b"Hello, zlib!"[..]); diff --git a/vendor/miniz_oxide/src/lib.rs b/vendor/miniz_oxide/src/lib.rs index 4ae3d76c72..0b4c60787d 100644 --- a/vendor/miniz_oxide/src/lib.rs +++ b/vendor/miniz_oxide/src/lib.rs @@ -23,9 +23,12 @@ #![allow(warnings)] #![forbid(unsafe_code)] -#![no_std] +#![cfg_attr(not(feature = "no_extern_crate_alloc"), no_std)] +#[cfg(not(feature = "no_extern_crate_alloc"))] extern crate alloc; +#[cfg(feature = "no_extern_crate_alloc")] +use std as alloc; #[cfg(test)] extern crate std; diff --git a/vendor/net2/.cargo-checksum.json b/vendor/net2/.cargo-checksum.json new file mode 100644 index 0000000000..47e9b93c1d --- /dev/null +++ b/vendor/net2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"6b8d2fe4e5dd3065446c4df3d226b6582ec8c9d6349d1c07a0446638c11f1d3b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"a99cb0401bd49e68c945f6a249175dd5c4a5117b2c8cc5d5fb7dea369002574e","src/ext.rs":"fd072307ebbaa01cfe1fd7553d7f42d27093b2bd32dd81d419d2e1c9423495a0","src/lib.rs":"a5e429c904fa13291dee5ed5df6c20adcebbaa56fc0312d475fd2056e9974153","src/socket.rs":"fda3d134345dd9b6178399c9173f42775b7620b9eaa802bf2d56dd9b798c5ca8","src/sys/redox/impls.rs":"90059116f0514bd44dbf282a3e8d7b192c99e1a78a34ebacb00f2d325ca0f8b0","src/sys/redox/mod.rs":"137013d409fd174fed0ceb3eceb2c17d15f34a3af70c7d237c06dd3a144affc1","src/sys/unix/impls.rs":"05f123226e8fe7559317d50864021650b2455d25d01a9aff1c65c01ae26cf4ef","src/sys/unix/mod.rs":"e06b26bad48c815b9a2af4509d1873333e2aad0031980f6d2625f72542698d56","src/sys/wasi/impls.rs":"da4e95a27a765b64fbbebce55b860020ac891456085ed706d5f8f391e0d1cddf","src/sys/wasi/mod.rs":"e88b02f4d5e0ae558f093d49cc0bb1b3cdf86ede625d00ed9231f0ab414e483f","src/sys/windows/impls.rs":"bee70b7cd45055c4eaa1967f7aad7ec46639de458c71ed6f3e97a2f7b2c49281","src/sys/windows/mod.rs":"0706f1587af0f693f75e8597e4196075a3f673c89727dd865447da306974bf35","src/tcp.rs":"0bebf5cca75714151de30c8f2d7697ca519c57da065e93ba81796bce04673f8d","src/udp.rs":"8af5a55a4ae5e4120ffe18dcc4dc24072e18da34bf3591a02b18653e5d3e8ac8","src/unix.rs":"1156707694cb1f002a2eb2144bf205a73412e1661fd196a8a2a7bc8ea5aaad2d","src/utils.rs":"d31de5333a6fa2f5c99b64cc937be596888d9863264632e6bc6b36b30197fa5b"},"package":"3ebc3ec692ed7c9a255596c67808dee269f64655d8baf7b4f0638e51ba1d6853"} \ No newline at end of file diff --git a/vendor/net2/Cargo.toml b/vendor/net2/Cargo.toml new file mode 100644 index 0000000000..3ccf701bd2 --- /dev/null +++ b/vendor/net2/Cargo.toml @@ -0,0 +1,35 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "net2" +version = "0.2.35" +authors = ["Alex Crichton "] +include = ["Cargo.toml", "LICENSE-APACHE", "LICENSE-MIT", "README.md", "src/**/*.rs"] +description = "Extensions to the standard library's networking types as proposed in RFC 1158.\n" +homepage = "https://github.com/deprecrated/net2-rs" +documentation = "https://docs.rs/net2/~0.2" +readme = "README.md" +license = "MIT/Apache-2.0" +repository = "https://github.com/deprecrated/net2-rs" +[dependencies.cfg-if] +version = "0.1" + +[features] +default = ["duration"] +duration = [] +nightly = [] +[target."cfg(any(target_os=\"redox\", unix, target_os=\"wasi\"))".dependencies.libc] +version = "0.2.54" +[target."cfg(windows)".dependencies.winapi] +version = "0.3" +features = ["handleapi", "winsock2", "ws2def", "ws2ipdef", "ws2tcpip"] diff --git a/vendor/parking_lot-0.10.2/LICENSE-APACHE b/vendor/net2/LICENSE-APACHE similarity index 100% rename from vendor/parking_lot-0.10.2/LICENSE-APACHE rename to vendor/net2/LICENSE-APACHE diff --git a/vendor/net2/LICENSE-MIT b/vendor/net2/LICENSE-MIT new file mode 100644 index 0000000000..39d4bdb5ac --- /dev/null +++ b/vendor/net2/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2014 The Rust Project Developers + +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 --git a/vendor/net2/README.md b/vendor/net2/README.md new file mode 100644 index 0000000000..9818422220 --- /dev/null +++ b/vendor/net2/README.md @@ -0,0 +1,31 @@ +# net2 + +Extensions to the standard library's networking types, proposed in [RFC 1158][rfc]. + +[rfc]: https://github.com/alexcrichton/rfcs/blob/net2.1/text/0000-io-net-2.1.md + +[![Build Status](https://github.com/deprecrated/net2-rs/workflows/CI/badge.svg)](https://github.com/deprecrated/net2-rs/actions?query=workflow%3ACI+branch%3Amaster) +[![Documentation](https://docs.rs/net2/badge.svg?version=0.2)](https://docs.rs/net2/~0.2) + +# net2 is Deprecated + +Prospective and existing consumers are encouraged to consider +[socket2](https://crates.io/crates/socket2) instead. + + +# License + +This project is licensed under either of + + * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or + http://www.apache.org/licenses/LICENSE-2.0) + * MIT license ([LICENSE-MIT](LICENSE-MIT) or + http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in Serde by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. diff --git a/vendor/net2/src/ext.rs b/vendor/net2/src/ext.rs new file mode 100644 index 0000000000..ca64bef3bb --- /dev/null +++ b/vendor/net2/src/ext.rs @@ -0,0 +1,1561 @@ +// 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. + +#![allow(bad_style, dead_code)] + +use std::io; +use std::mem; +use std::net::{TcpStream, TcpListener, UdpSocket, Ipv4Addr, Ipv6Addr}; +use std::net::ToSocketAddrs; + +use {TcpBuilder, UdpBuilder, FromInner}; +use sys; +use sys::c; +use socket; + +cfg_if! { + if #[cfg(any(target_os = "dragonfly", + target_os = "freebsd", + target_os = "haiku", + target_os = "ios", + target_os = "macos", + target_os = "netbsd", + target_os = "openbsd", + target_os = "solaris", + target_os = "illumos", + target_env = "uclibc"))] { + use libc::IPV6_JOIN_GROUP as IPV6_ADD_MEMBERSHIP; + use libc::IPV6_LEAVE_GROUP as IPV6_DROP_MEMBERSHIP; + } else { + // ... + } +} + +use std::time::Duration; + +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] use libc::*; +#[cfg(any(unix, target_os = "redox"))] use std::os::unix::prelude::*; +#[cfg(target_os = "wasi")] use std::os::wasi::prelude::*; +#[cfg(target_os = "redox")] pub type Socket = usize; +#[cfg(unix)] pub type Socket = c_int; +#[cfg(target_os = "wasi")] pub type Socket = std::os::wasi::io::RawFd; +#[cfg(windows)] pub type Socket = SOCKET; +#[cfg(windows)] use std::os::windows::prelude::*; +#[cfg(any(windows, target_os = "wasi"))] use sys::c::*; + +#[cfg(windows)] const SIO_KEEPALIVE_VALS: DWORD = 0x98000004; +#[cfg(windows)] +#[repr(C)] +struct tcp_keepalive { + onoff: c_ulong, + keepalivetime: c_ulong, + keepaliveinterval: c_ulong, +} + +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] fn v(opt: c_int) -> c_int { opt } +#[cfg(windows)] fn v(opt: IPPROTO) -> c_int { opt as c_int } + +#[cfg(target_os = "wasi")] +pub fn set_opt(_sock: Socket, _opt: c_int, _val: c_int, + _payload: T) -> io::Result<()> { + Ok(()) +} + +#[cfg(not(target_os = "wasi"))] +pub fn set_opt(sock: Socket, opt: c_int, val: c_int, + payload: T) -> io::Result<()> { + unsafe { + let payload = &payload as *const T as *const c_void; + #[cfg(target_os = "redox")] + let sock = sock as c_int; + try!(::cvt(setsockopt(sock, opt, val, payload as *const _, + mem::size_of::() as socklen_t))); + } + Ok(()) +} + +#[cfg(target_os = "wasi")] +pub fn get_opt(_sock: Socket, _opt: c_int, _val: c_int) -> io::Result { + unimplemented!() +} +#[cfg(not(target_os = "wasi"))] +pub fn get_opt(sock: Socket, opt: c_int, val: c_int) -> io::Result { + unsafe { + let mut slot: T = mem::zeroed(); + let mut len = mem::size_of::() as socklen_t; + #[cfg(target_os = "redox")] + let sock = sock as c_int; + try!(::cvt(getsockopt(sock, opt, val, + &mut slot as *mut _ as *mut _, + &mut len))); + assert_eq!(len as usize, mem::size_of::()); + Ok(slot) + } +} + +/// Extension methods for the standard [`TcpStream` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.TcpStream.html +pub trait TcpStreamExt { + /// Sets the value of the `TCP_NODELAY` option on this socket. + /// + /// If set, this option disables the Nagle algorithm. This means that + /// segments are always sent as soon as possible, even if there is only a + /// small amount of data. When not set, data is buffered until there is a + /// sufficient amount to send out, thereby avoiding the frequent sending of + /// small packets. + fn set_nodelay(&self, nodelay: bool) -> io::Result<()>; + + /// Gets the value of the `TCP_NODELAY` option on this socket. + /// + /// For more information about this option, see [`set_nodelay`][link]. + /// + /// [link]: #tymethod.set_nodelay + fn nodelay(&self) -> io::Result; + + /// Sets the value of the `SO_RCVBUF` option on this socket. + /// + /// Changes the size of the operating system's receive buffer associated with the socket. + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_RCVBUF` option on this socket. + /// + /// For more information about this option, see [`set_recv_buffer_size`][link]. + /// + /// [link]: #tymethod.set_recv_buffer_size + fn recv_buffer_size(&self) -> io::Result; + + /// Sets the value of the `SO_SNDBUF` option on this socket. + /// + /// Changes the size of the operating system's send buffer associated with the socket. + fn set_send_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_SNDBUF` option on this socket. + /// + /// For more information about this option, see [`set_send_buffer`][link]. + /// + /// [link]: #tymethod.set_send_buffer + fn send_buffer_size(&self) -> io::Result; + + /// Sets whether keepalive messages are enabled to be sent on this socket. + /// + /// On Unix, this option will set the `SO_KEEPALIVE` as well as the + /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). + /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. + /// + /// If `None` is specified then keepalive messages are disabled, otherwise + /// the number of milliseconds specified will be the time to remain idle + /// before sending a TCP keepalive probe. + /// + /// Some platforms specify this value in seconds, so sub-second millisecond + /// specifications may be omitted. + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()>; + + /// Returns whether keepalive messages are enabled on this socket, and if so + /// the amount of milliseconds between them. + /// + /// For more information about this option, see [`set_keepalive_ms`][link]. + /// + /// [link]: #tymethod.set_keepalive_ms + fn keepalive_ms(&self) -> io::Result>; + + /// Sets whether keepalive messages are enabled to be sent on this socket. + /// + /// On Unix, this option will set the `SO_KEEPALIVE` as well as the + /// `TCP_KEEPALIVE` or `TCP_KEEPIDLE` option (depending on your platform). + /// On Windows, this will set the `SIO_KEEPALIVE_VALS` option. + /// + /// If `None` is specified then keepalive messages are disabled, otherwise + /// the duration specified will be the time to remain idle before sending a + /// TCP keepalive probe. + /// + /// Some platforms specify this value in seconds, so sub-second + /// specifications may be omitted. + fn set_keepalive(&self, keepalive: Option) -> io::Result<()>; + + /// Returns whether keepalive messages are enabled on this socket, and if so + /// the duration of time between them. + /// + /// For more information about this option, see [`set_keepalive`][link]. + /// + /// [link]: #tymethod.set_keepalive + fn keepalive(&self) -> io::Result>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `read` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_read_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `read` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the number of duration of the timeout. + fn set_read_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_read_timeout_ms + fn read_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout`][link]. + /// + /// [link]: #tymethod.set_read_timeout + fn read_timeout(&self) -> io::Result>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `write` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_write_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `write` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the duration of the timeout. + fn set_write_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_write_timeout_ms + fn write_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout`][link]. + /// + /// [link]: #tymethod.set_write_timeout + fn write_timeout(&self) -> io::Result>; + + /// 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 + /// from this socket. + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see [`set_ttl`][link]. + /// + /// [link]: #tymethod.set_ttl + fn ttl(&self) -> io::Result; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// If this is set to `true` then the socket is restricted to sending and + /// receiving IPv6 packets only. In this case two IPv4 and IPv6 applications + /// can bind the same port at the same time. + /// + /// If this is set to `false` then the socket can be used to send and + /// receive packets from an IPv4-mapped IPv6 address. + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see [`set_only_v6`][link]. + /// + /// [link]: #tymethod.set_only_v6 + fn only_v6(&self) -> io::Result; + + /// Executes a `connect` operation on this socket, establishing a connection + /// to the host specified by `addr`. + /// + /// Note that this normally does not need to be called on a `TcpStream`, + /// it's typically automatically done as part of a normal + /// `TcpStream::connect` function call or `TcpBuilder::connect` method call. + /// + /// This should only be necessary if an unconnected socket was extracted + /// from a `TcpBuilder` and then needs to be connected. + fn connect(&self, addr: T) -> io::Result<()>; + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + fn take_error(&self) -> io::Result>; + + /// Moves this TCP stream into or out of nonblocking mode. + /// + /// On Unix this corresponds to calling fcntl, and on Windows this + /// corresponds to calling ioctlsocket. + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; + + /// Sets the linger duration of this socket by setting the SO_LINGER option + fn set_linger(&self, dur: Option) -> io::Result<()>; + + /// reads the linger duration for this socket by getting the SO_LINGER option + fn linger(&self) -> io::Result>; +} + +/// Extension methods for the standard [`TcpListener` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.TcpListener.html +pub trait TcpListenerExt { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_ttl`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl + fn ttl(&self) -> io::Result; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn only_v6(&self) -> io::Result; + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + fn take_error(&self) -> io::Result>; + + /// Moves this TCP listener into or out of nonblocking mode. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_nonblocking`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; + + /// Sets the linger duration of this socket by setting the SO_LINGER option + fn set_linger(&self, dur: Option) -> io::Result<()>; + + /// reads the linger duration for this socket by getting the SO_LINGER option + fn linger(&self) -> io::Result>; +} + +/// Extension methods for the standard [`UdpSocket` type][link] in `std::net`. +/// +/// [link]: https://doc.rust-lang.org/std/net/struct.UdpSocket.html +pub trait UdpSocketExt { + /// Sets the value of the `SO_RCVBUF` option on this socket. + /// + /// Changes the size of the operating system's receive buffer associated with the socket. + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_RCVBUF` option on this socket. + /// + /// For more information about this option, see [`set_recv_buffer_size`][link]. + /// + /// [link]: #tymethod.set_recv_buffer_size + fn recv_buffer_size(&self) -> io::Result; + + /// Sets the value of the `SO_SNDBUF` option on this socket. + /// + /// Changes the size of the operating system's send buffer associated with the socket. + fn set_send_buffer_size(&self, size: usize) -> io::Result<()>; + + /// Gets the value of the `SO_SNDBUF` option on this socket. + /// + /// For more information about this option, see [`set_send_buffer`][link]. + /// + /// [link]: #tymethod.set_send_buffer + fn send_buffer_size(&self) -> io::Result; + + /// Sets the value of the `SO_BROADCAST` option for this socket. + /// + /// When enabled, this socket is allowed to send packets to a broadcast + /// address. + fn set_broadcast(&self, broadcast: bool) -> io::Result<()>; + + /// Gets the value of the `SO_BROADCAST` option for this socket. + /// + /// For more information about this option, see + /// [`set_broadcast`][link]. + /// + /// [link]: #tymethod.set_broadcast + fn broadcast(&self) -> io::Result; + + /// Sets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// If enabled, multicast packets will be looped back to the local socket. + /// Note that this may not have any affect on IPv6 sockets. + fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()>; + + /// Gets the value of the `IP_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v4`][link]. + /// + /// [link]: #tymethod.set_multicast_loop_v4 + fn multicast_loop_v4(&self) -> io::Result; + + /// Sets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// Indicates the time-to-live value of outgoing multicast packets for + /// this socket. The default value is 1 which means that multicast packets + /// don't leave the local network unless explicitly requested. + /// + /// Note that this may not have any affect on IPv6 sockets. + fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()>; + + /// Gets the value of the `IP_MULTICAST_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_ttl_v4`][link]. + /// + /// [link]: #tymethod.set_multicast_ttl_v4 + fn multicast_ttl_v4(&self) -> io::Result; + + /// Sets the value of the `IPV6_MULTICAST_HOPS` option for this socket + fn set_multicast_hops_v6(&self, hops: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_HOPS` option for this socket + fn multicast_hops_v6(&self) -> io::Result; + + /// Sets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// Controls whether this socket sees the multicast packets it sends itself. + /// Note that this may not have any affect on IPv4 sockets. + fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_LOOP` option for this socket. + /// + /// For more information about this option, see + /// [`set_multicast_loop_v6`][link]. + /// + /// [link]: #tymethod.set_multicast_loop_v6 + fn multicast_loop_v6(&self) -> io::Result; + + /// Sets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. + fn set_multicast_if_v4(&self, interface: &Ipv4Addr) -> io::Result<()>; + + /// Gets the value of the `IP_MULTICAST_IF` option for this socket. + /// + /// Returns the interface to use for routing multicast packets. + fn multicast_if_v4(&self) -> io::Result; + + + /// Sets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// Specifies the interface to use for routing multicast packets. + fn set_multicast_if_v6(&self, interface: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_MULTICAST_IF` option for this socket. + /// + /// Returns the interface to use for routing multicast packets. + fn multicast_if_v6(&self) -> io::Result; + + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + fn set_ttl(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IP_TTL` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_ttl`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_ttl + fn ttl(&self) -> io::Result; + + /// Sets the value for the `IPV6_UNICAST_HOPS` option on this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + fn set_unicast_hops_v6(&self, ttl: u32) -> io::Result<()>; + + /// Gets the value of the `IPV6_UNICAST_HOPS` option for this socket. + /// + /// Specifies the hop limit for ipv6 unicast packets + fn unicast_hops_v6(&self) -> io::Result; + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn set_only_v6(&self, only_v6: bool) -> io::Result<()>; + + /// Gets the value of the `IPV6_V6ONLY` option for this socket. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_only_v6`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_only_v6 + fn only_v6(&self) -> io::Result; + + /// Executes an operation of the `IP_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// address of the local interface with which the system should join the + /// multicast group. If it's equal to `INADDR_ANY` then an appropriate + /// interface is chosen by the system. + fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()>; + + /// Executes an operation of the `IPV6_ADD_MEMBERSHIP` type. + /// + /// This function specifies a new multicast group for this socket to join. + /// The address must be a valid multicast address, and `interface` is the + /// index of the interface to join/leave (or 0 to indicate any interface). + fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()>; + + /// Executes an operation of the `IP_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v4`][link]. + /// + /// [link]: #tymethod.join_multicast_v4 + fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()>; + + /// Executes an operation of the `IPV6_DROP_MEMBERSHIP` type. + /// + /// For more information about this option, see + /// [`join_multicast_v6`][link]. + /// + /// [link]: #tymethod.join_multicast_v6 + fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `read` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_read_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_RCVTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `read` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the number of duration of the timeout. + fn set_read_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_read_timeout_ms + fn read_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_RCVTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_read_timeout`][link]. + /// + /// [link]: #tymethod.set_read_timeout + fn read_timeout(&self) -> io::Result>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout, in milliseconds, of how long calls to + /// this socket's `write` function will wait before returning a timeout. A + /// value of `None` means that no read timeout should be specified and + /// otherwise `Some` indicates the number of milliseconds for the timeout. + fn set_write_timeout_ms(&self, val: Option) -> io::Result<()>; + + /// Sets the `SO_SNDTIMEO` option for this socket. + /// + /// This option specifies the timeout of how long calls to this socket's + /// `write` function will wait before returning a timeout. A value of `None` + /// means that no read timeout should be specified and otherwise `Some` + /// indicates the duration of the timeout. + fn set_write_timeout(&self, val: Option) -> io::Result<()>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout_ms`][link]. + /// + /// [link]: #tymethod.set_write_timeout_ms + fn write_timeout_ms(&self) -> io::Result>; + + /// Gets the value of the `SO_SNDTIMEO` option for this socket. + /// + /// For more information about this option, see [`set_write_timeout`][link]. + /// + /// [link]: #tymethod.set_write_timeout + fn write_timeout(&self) -> io::Result>; + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + fn take_error(&self) -> io::Result>; + + /// Connects this UDP socket to a remote address, allowing the `send` and + /// `recv` syscalls to be used to send data and also applies filters to only + /// receive data from the specified address. + fn connect(&self, addr: A) -> io::Result<()>; + + /// Sends data on the socket to the remote address to which it is connected. + /// + /// The `connect` method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + fn send(&self, buf: &[u8]) -> io::Result; + + /// Receives data on the socket from the remote address to which it is + /// connected. + /// + /// The `connect` method will connect this socket to a remote address. This + /// method will fail if the socket is not connected. + fn recv(&self, buf: &mut [u8]) -> io::Result; + + /// Moves this UDP socket into or out of nonblocking mode. + /// + /// For more information about this option, see + /// [`TcpStreamExt::set_nonblocking`][link]. + /// + /// [link]: trait.TcpStreamExt.html#tymethod.set_nonblocking + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()>; +} + +#[doc(hidden)] +pub trait AsSock { + fn as_sock(&self) -> Socket; +} + +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] +impl AsSock for T { + fn as_sock(&self) -> Socket { self.as_raw_fd() } +} +#[cfg(windows)] +impl AsSock for T { + fn as_sock(&self) -> Socket { self.as_raw_socket() as Socket } +} + +cfg_if! { + if #[cfg(any(target_os = "macos", target_os = "ios"))] { + use libc::TCP_KEEPALIVE as KEEPALIVE_OPTION; + } else if #[cfg(any(target_os = "haiku", target_os = "netbsd", target_os = "openbsd"))] { + use libc::SO_KEEPALIVE as KEEPALIVE_OPTION; + } else if #[cfg(unix)] { + use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; + } else if #[cfg(target_os = "redox")] { + use libc::TCP_KEEPIDLE as KEEPALIVE_OPTION; + } else { + // ... + } +} + +impl TcpStreamExt for TcpStream { + + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + // TODO: casting usize to a c_int should be a checked cast + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int) + } + + fn recv_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize) + } + + fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int) + } + + fn send_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize) + } + + fn set_nodelay(&self, nodelay: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY, + nodelay as c_int) + } + fn nodelay(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_TCP), TCP_NODELAY) + .map(int2bool) + } + + fn set_keepalive(&self, keepalive: Option) -> io::Result<()> { + self.set_keepalive_ms(keepalive.map(dur2ms)) + } + + fn keepalive(&self) -> io::Result> { + self.keepalive_ms().map(|o| o.map(ms2dur)) + } + + #[cfg(target_os = "redox")] + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()> { + try!(set_opt(self.as_sock(), SOL_SOCKET, SO_KEEPALIVE, + keepalive.is_some() as c_int)); + if let Some(dur) = keepalive { + try!(set_opt(self.as_sock(), v(IPPROTO_TCP), KEEPALIVE_OPTION, + (dur / 1000) as c_int)); + } + Ok(()) + } + + #[cfg(target_os = "redox")] + fn keepalive_ms(&self) -> io::Result> { + let keepalive = try!(get_opt::(self.as_sock(), SOL_SOCKET, + SO_KEEPALIVE)); + if keepalive == 0 { + return Ok(None) + } + let secs = try!(get_opt::(self.as_sock(), v(IPPROTO_TCP), + KEEPALIVE_OPTION)); + Ok(Some((secs as u32) * 1000)) + } + + #[cfg(unix)] + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()> { + try!(set_opt(self.as_sock(), SOL_SOCKET, SO_KEEPALIVE, + keepalive.is_some() as c_int)); + if let Some(dur) = keepalive { + try!(set_opt(self.as_sock(), v(IPPROTO_TCP), KEEPALIVE_OPTION, + (dur / 1000) as c_int)); + } + Ok(()) + } + + #[cfg(unix)] + fn keepalive_ms(&self) -> io::Result> { + let keepalive = try!(get_opt::(self.as_sock(), SOL_SOCKET, + SO_KEEPALIVE)); + if keepalive == 0 { + return Ok(None) + } + let secs = try!(get_opt::(self.as_sock(), v(IPPROTO_TCP), + KEEPALIVE_OPTION)); + Ok(Some((secs as u32) * 1000)) + } + + #[cfg(target_os = "wasi")] + fn set_keepalive_ms(&self, _keepalive: Option) -> io::Result<()> { + unimplemented!() + } + + #[cfg(target_os = "wasi")] + fn keepalive_ms(&self) -> io::Result> { + unimplemented!() + } + + #[cfg(windows)] + fn set_keepalive_ms(&self, keepalive: Option) -> io::Result<()> { + let ms = keepalive.unwrap_or(INFINITE); + let ka = tcp_keepalive { + onoff: keepalive.is_some() as c_ulong, + keepalivetime: ms as c_ulong, + keepaliveinterval: ms as c_ulong, + }; + unsafe { + ::cvt_win(WSAIoctl(self.as_sock(), + SIO_KEEPALIVE_VALS, + &ka as *const _ as *mut _, + mem::size_of_val(&ka) as DWORD, + 0 as *mut _, + 0, + 0 as *mut _, + 0 as *mut _, + None)).map(|_| ()) + } + } + + #[cfg(windows)] + fn keepalive_ms(&self) -> io::Result> { + let mut ka = tcp_keepalive { + onoff: 0, + keepalivetime: 0, + keepaliveinterval: 0, + }; + unsafe { + try!(::cvt_win(WSAIoctl(self.as_sock(), + SIO_KEEPALIVE_VALS, + 0 as *mut _, + 0, + &mut ka as *mut _ as *mut _, + mem::size_of_val(&ka) as DWORD, + 0 as *mut _, + 0 as *mut _, + None))); + } + Ok({ + if ka.onoff == 0 { + None + } else { + timeout2ms(ka.keepaliveinterval as DWORD) + } + }) + } + + fn set_read_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO, + ms2timeout(dur)) + } + + fn read_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO) + .map(timeout2ms) + } + + fn set_write_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO, + ms2timeout(dur)) + } + + fn write_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO) + .map(timeout2ms) + } + + fn set_read_timeout(&self, dur: Option) -> io::Result<()> { + self.set_read_timeout_ms(dur.map(dur2ms)) + } + + fn read_timeout(&self) -> io::Result> { + self.read_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_write_timeout(&self, dur: Option) -> io::Result<()> { + self.set_write_timeout_ms(dur.map(dur2ms)) + } + + fn write_timeout(&self) -> io::Result> { + self.write_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn connect(&self, addr: T) -> io::Result<()> { + do_connect(self.as_sock(), addr) + } + + fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } + + fn set_linger(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + fn linger(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +#[cfg(any(target_os = "redox", unix, target_os = "wasi"))] +fn ms2timeout(dur: Option) -> timeval { + // TODO: be more rigorous + match dur { + Some(d) => timeval { + tv_sec: (d / 1000) as time_t, + tv_usec: (d % 1000) as suseconds_t, + }, + None => timeval { tv_sec: 0, tv_usec: 0 }, + } +} + +#[cfg(any(target_os = "redox", unix, target_os = "wasi"))] +fn timeout2ms(dur: timeval) -> Option { + if dur.tv_sec == 0 && dur.tv_usec == 0 { + None + } else { + Some(dur.tv_sec as u32 * 1000 + dur.tv_usec as u32 / 1000) + } +} + +#[cfg(windows)] +fn ms2timeout(dur: Option) -> DWORD { + dur.unwrap_or(0) +} + +#[cfg(windows)] +fn timeout2ms(dur: DWORD) -> Option { + if dur == 0 { + None + } else { + Some(dur) + } +} + +fn linger2dur(linger_opt: linger) -> Option { + if linger_opt.l_onoff == 0 { + None + } + else { + Some(Duration::from_secs(linger_opt.l_linger as u64)) + } +} + +#[cfg(windows)] +fn dur2linger(dur: Option) -> linger { + match dur { + Some(d) => { + linger { + l_onoff: 1, + l_linger: d.as_secs() as u16, + } + }, + None => linger { l_onoff: 0, l_linger: 0 }, + } +} + +#[cfg(any(target_os = "redox", unix, target_os = "wasi"))] +fn dur2linger(dur: Option) -> linger { + match dur { + Some(d) => { + linger { + l_onoff: 1, + l_linger: d.as_secs() as c_int, + } + }, + None => linger { l_onoff: 0, l_linger: 0 }, + } +} + +fn ms2dur(ms: u32) -> Duration { + Duration::new((ms as u64) / 1000, (ms as u32) % 1000 * 1_000_000) +} + +fn dur2ms(dur: Duration) -> u32 { + (dur.as_secs() as u32 * 1000) + (dur.subsec_nanos() / 1_000_000) +} + +pub fn int2bool(n: c_int) -> bool { + if n == 0 {false} else {true} +} + +pub fn int2usize(n: c_int) -> usize { + // TODO: casting c_int to a usize should be a checked cast + n as usize +} + +pub fn int2err(n: c_int) -> Option { + if n == 0 { + None + } else { + Some(io::Error::from_raw_os_error(n as i32)) + } +} + +impl UdpSocketExt for UdpSocket { + + fn set_recv_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF, size as c_int) + } + + fn recv_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVBUF).map(int2usize) + } + + fn set_send_buffer_size(&self, size: usize) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF, size as c_int) + } + + fn send_buffer_size(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDBUF).map(int2usize) + } + + fn set_broadcast(&self, broadcast: bool) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST, + broadcast as c_int) + } + fn broadcast(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_BROADCAST) + .map(int2bool) + } + fn set_multicast_loop_v4(&self, multicast_loop_v4: bool) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP, + multicast_loop_v4 as c_int) + } + fn multicast_loop_v4(&self) -> io::Result { + get_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_LOOP) + .map(int2bool) + } + + fn set_multicast_ttl_v4(&self, multicast_ttl_v4: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL, + multicast_ttl_v4 as c_int) + } + + fn multicast_ttl_v4(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_MULTICAST_TTL) + .map(|b| b as u32) + } + + fn set_multicast_hops_v6(&self, _hops: u32) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_HOPS, + _hops as c_int) + } + + fn multicast_hops_v6(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt::(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_HOPS) + .map(|b| b as u32) + } + + fn set_multicast_loop_v6(&self, multicast_loop_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP, + multicast_loop_v6 as c_int) + } + fn multicast_loop_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_LOOP) + .map(int2bool) + } + + fn set_multicast_if_v4(&self, _interface: &Ipv4Addr) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_IF, ip2in_addr(_interface)) + } + + fn multicast_if_v4(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt(self.as_sock(), IPPROTO_IP, IP_MULTICAST_IF).map(in_addr2ip) + } + + fn set_multicast_if_v6(&self, _interface: u32) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_IF, to_ipv6mr_interface(_interface)) + } + + fn multicast_if_v6(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt::(self.as_sock(), v(IPPROTO_IPV6), IPV6_MULTICAST_IF).map(|b| b as u32) + } + + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_unicast_hops_v6(&self, _ttl: u32) -> io::Result<()> { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_UNICAST_HOPS, _ttl as c_int) + } + + fn unicast_hops_v6(&self) -> io::Result { + #[cfg(target_os = "redox")] + return Err(io::Error::new(io::ErrorKind::Other, "Not implemented yet")); + #[cfg(not(target_os = "redox"))] + get_opt::(self.as_sock(), IPPROTO_IP, IPV6_UNICAST_HOPS) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn join_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()> { + let mreq = ip_mreq { + imr_multiaddr: ip2in_addr(multiaddr), + imr_interface: ip2in_addr(interface), + }; + set_opt(self.as_sock(), IPPROTO_IP, IP_ADD_MEMBERSHIP, mreq) + } + + fn join_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()> { + let mreq = ipv6_mreq { + ipv6mr_multiaddr: ip2in6_addr(multiaddr), + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_ADD_MEMBERSHIP, + mreq) + } + + fn leave_multicast_v4(&self, multiaddr: &Ipv4Addr, interface: &Ipv4Addr) + -> io::Result<()> { + let mreq = ip_mreq { + imr_multiaddr: ip2in_addr(multiaddr), + imr_interface: ip2in_addr(interface), + }; + set_opt(self.as_sock(), IPPROTO_IP, IP_DROP_MEMBERSHIP, mreq) + } + + fn leave_multicast_v6(&self, multiaddr: &Ipv6Addr, interface: u32) + -> io::Result<()> { + let mreq = ipv6_mreq { + ipv6mr_multiaddr: ip2in6_addr(multiaddr), + ipv6mr_interface: to_ipv6mr_interface(interface), + }; + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_DROP_MEMBERSHIP, + mreq) + } + + fn set_read_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO, + ms2timeout(dur)) + } + + fn read_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_RCVTIMEO) + .map(timeout2ms) + } + + fn set_write_timeout_ms(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO, + ms2timeout(dur)) + } + + fn write_timeout_ms(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_SNDTIMEO) + .map(timeout2ms) + } + + fn set_read_timeout(&self, dur: Option) -> io::Result<()> { + self.set_read_timeout_ms(dur.map(dur2ms)) + } + + fn read_timeout(&self) -> io::Result> { + self.read_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn set_write_timeout(&self, dur: Option) -> io::Result<()> { + self.set_write_timeout_ms(dur.map(dur2ms)) + } + + fn write_timeout(&self) -> io::Result> { + self.write_timeout_ms().map(|o| o.map(ms2dur)) + } + + fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn connect(&self, addr: A) -> io::Result<()> { + do_connect(self.as_sock(), addr) + } + + #[cfg(target_os = "redox")] + fn send(&self, buf: &[u8]) -> io::Result { + unsafe { + ::cvt(write(self.as_sock() as c_int, buf.as_ptr() as *const _, buf.len())).map(|n| n as usize) + } + } + + #[cfg(unix)] + fn send(&self, buf: &[u8]) -> io::Result { + unsafe { + ::cvt(send(self.as_sock() as c_int, buf.as_ptr() as *const _, buf.len(), 0)).map(|n| n as usize) + } + } + + #[cfg(target_os = "wasi")] + fn send(&self, buf: &[u8]) -> io::Result { + let _so_datalen: *mut sys::c::size_t = &mut 0; + unsafe { + let _errno = libc::__wasi_sock_send( + self.as_sock() as libc::__wasi_fd_t, + buf.as_ptr() as *const _, + buf.len(), + 0, + _so_datalen, + ); + // TODO: handle errno + Ok((*_so_datalen) as usize) + } + } + + #[cfg(windows)] + fn send(&self, buf: &[u8]) -> io::Result { + let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize); + let buf = &buf[..len]; + unsafe { + ::cvt(send(self.as_sock(), buf.as_ptr() as *const _, len as c_int, 0)) + .map(|n| n as usize) + } + } + + #[cfg(target_os = "redox")] + fn recv(&self, buf: &mut [u8]) -> io::Result { + unsafe { + ::cvt(read(self.as_sock() as c_int, buf.as_mut_ptr() as *mut _, buf.len())) + .map(|n| n as usize) + } + } + + #[cfg(unix)] + fn recv(&self, buf: &mut [u8]) -> io::Result { + unsafe { + ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len(), 0)) + .map(|n| n as usize) + } + } + + #[cfg(target_os = "wasi")] + fn recv(&self, buf: &mut [u8]) -> io::Result { + let _ro_datalen: *mut sys::c::size_t = &mut 0; + let _ro_flags: *mut sys::c::__wasi_roflags_t = &mut 0; + unsafe { + let _errno = __wasi_sock_recv( + self.as_sock(), + buf.as_mut_ptr() as *mut _, + buf.len(), + 0, + _ro_datalen, + _ro_flags, + ); + // TODO: handle errno + Ok((*_ro_datalen) as usize) + } + } + + #[cfg(windows)] + fn recv(&self, buf: &mut [u8]) -> io::Result { + let len = ::std::cmp::min(buf.len(), c_int::max_value() as usize); + let buf = &mut buf[..len]; + unsafe { + ::cvt(recv(self.as_sock(), buf.as_mut_ptr() as *mut _, buf.len() as c_int, 0)) + .map(|n| n as usize) + } + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } +} + +fn do_connect(sock: Socket, addr: A) -> io::Result<()> { + let err = io::Error::new(io::ErrorKind::Other, + "no socket addresses resolved"); + let addrs = try!(addr.to_socket_addrs()); + let sys = sys::Socket::from_inner(sock); + let sock = socket::Socket::from_inner(sys); + let ret = addrs.fold(Err(err), |prev, addr| { + prev.or_else(|_| sock.connect(&addr)) + }); + mem::forget(sock); + return ret +} + +#[cfg(target_os = "redox")] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut flags = ::cvt(unsafe { + fcntl(sock as c_int, F_GETFL) + })?; + if nonblocking { + flags |= O_NONBLOCK; + } else { + flags &= !O_NONBLOCK; + } + ::cvt(unsafe { + fcntl(sock as c_int, F_SETFL, flags) + }).and(Ok(())) +} + +#[cfg(unix)] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_ulong; + ::cvt(unsafe { + ioctl(sock, FIONBIO, &mut nonblocking) + }).map(|_| ()) +} + +#[cfg(target_os = "wasi")] +fn set_nonblocking(_sock: Socket, _nonblocking: bool) -> io::Result<()> { + Ok(()) +} + +#[cfg(windows)] +fn set_nonblocking(sock: Socket, nonblocking: bool) -> io::Result<()> { + let mut nonblocking = nonblocking as c_ulong; + ::cvt(unsafe { + ioctlsocket(sock, FIONBIO as c_int, &mut nonblocking) + }).map(|_| ()) +} + +#[cfg(target_os = "redox")] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + in_addr { + s_addr: ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)), + } +} + +#[cfg(any(unix, target_os = "wasi"))] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + in_addr { + s_addr: ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)), + } +} + +#[cfg(windows)] +fn ip2in_addr(ip: &Ipv4Addr) -> in_addr { + let oct = ip.octets(); + unsafe { + let mut S_un: in_addr_S_un = mem::zeroed(); + *S_un.S_addr_mut() = ::hton(((oct[0] as u32) << 24) | + ((oct[1] as u32) << 16) | + ((oct[2] as u32) << 8) | + ((oct[3] as u32) << 0)); + in_addr { + S_un: S_un, + } + } +} + +fn in_addr2ip(ip: &in_addr) -> Ipv4Addr { + let h_addr = c::in_addr_to_u32(ip); + + let a: u8 = (h_addr >> 24) as u8; + let b: u8 = (h_addr >> 16) as u8; + let c: u8 = (h_addr >> 8) as u8; + let d: u8 = (h_addr >> 0) as u8; + + Ipv4Addr::new(a,b,c,d) +} + +#[cfg(target_os = "android")] +fn to_ipv6mr_interface(value: u32) -> c_int { + value as c_int +} + +#[cfg(not(target_os = "android"))] +fn to_ipv6mr_interface(value: u32) -> c_uint { + value as c_uint +} + +fn ip2in6_addr(ip: &Ipv6Addr) -> in6_addr { + let mut ret: in6_addr = unsafe { mem::zeroed() }; + let seg = ip.segments(); + let bytes = [ + (seg[0] >> 8) as u8, + (seg[0] >> 0) as u8, + (seg[1] >> 8) as u8, + (seg[1] >> 0) as u8, + (seg[2] >> 8) as u8, + (seg[2] >> 0) as u8, + (seg[3] >> 8) as u8, + (seg[3] >> 0) as u8, + (seg[4] >> 8) as u8, + (seg[4] >> 0) as u8, + (seg[5] >> 8) as u8, + (seg[5] >> 0) as u8, + (seg[6] >> 8) as u8, + (seg[6] >> 0) as u8, + (seg[7] >> 8) as u8, + (seg[7] >> 0) as u8, + ]; + #[cfg(windows)] unsafe { *ret.u.Byte_mut() = bytes; } + #[cfg(not(windows))] { ret.s6_addr = bytes; } + + return ret +} + +impl TcpListenerExt for TcpListener { + fn set_ttl(&self, ttl: u32) -> io::Result<()> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + } + + fn ttl(&self) -> io::Result { + get_opt::(self.as_sock(), IPPROTO_IP, IP_TTL) + .map(|b| b as u32) + } + + fn set_only_v6(&self, only_v6: bool) -> io::Result<()> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + } + + fn only_v6(&self) -> io::Result { + get_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY).map(int2bool) + } + + fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + fn set_nonblocking(&self, nonblocking: bool) -> io::Result<()> { + set_nonblocking(self.as_sock(), nonblocking) + } + + fn set_linger(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + fn linger(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +impl TcpBuilder { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + pub fn ttl(&self, ttl: u32) -> io::Result<&Self> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + .map(|()| self) + } + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_only_v6`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_only_v6 + pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + .map(|()| self) + } + + /// Set value for the `SO_REUSEADDR` option on this socket. + /// + /// This indicates that further calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR, + reuse as c_int).map(|()| self) + } + + /// Check the `SO_REUSEADDR` option on this socket. + pub fn get_reuse_address(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool) + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + pub fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } + + /// Sets the linger option for this socket + fn set_linger(&self, dur: Option) -> io::Result<()> { + set_opt(self.as_sock(), SOL_SOCKET, SO_LINGER, dur2linger(dur)) + } + + /// Gets the linger option for this socket + fn linger(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_LINGER).map(linger2dur) + } +} + +impl UdpBuilder { + /// Sets the value for the `IP_TTL` option on this socket. + /// + /// This is the same as [`TcpStreamExt::set_ttl`][other]. + /// + /// [other]: trait.TcpStreamExt.html#tymethod.set_ttl + pub fn ttl(&self, ttl: u32) -> io::Result<&Self> { + set_opt(self.as_sock(), IPPROTO_IP, IP_TTL, ttl as c_int) + .map(|()| self) + } + + /// Sets the value for the `IPV6_V6ONLY` option on this socket. + /// + /// This is the same as [`TcpStream::only_v6`][other]. + /// + /// [other]: struct.TcpBuilder.html#method.only_v6 + pub fn only_v6(&self, only_v6: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), v(IPPROTO_IPV6), IPV6_V6ONLY, only_v6 as c_int) + .map(|()| self) + } + + /// Set value for the `SO_REUSEADDR` option on this socket. + /// + /// This is the same as [`TcpBuilder::reuse_address`][other]. + /// + /// [other]: struct.TcpBuilder.html#method.reuse_address + pub fn reuse_address(&self, reuse: bool) -> io::Result<&Self> { + set_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR, + reuse as c_int).map(|()| self) + } + + /// Check the `SO_REUSEADDR` option on this socket. + pub fn get_reuse_address(&self) -> io::Result { + get_opt(self.as_sock(), SOL_SOCKET, SO_REUSEADDR).map(int2bool) + } + + /// Get the value of the `SO_ERROR` option on this socket. + /// + /// This will retrieve the stored error in the underlying socket, clearing + /// the field in the process. This can be useful for checking errors between + /// calls. + pub fn take_error(&self) -> io::Result> { + get_opt(self.as_sock(), SOL_SOCKET, SO_ERROR).map(int2err) + } +} diff --git a/vendor/net2/src/lib.rs b/vendor/net2/src/lib.rs new file mode 100644 index 0000000000..fcbb7b454c --- /dev/null +++ b/vendor/net2/src/lib.rs @@ -0,0 +1,127 @@ +// 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. + +//! Extensions to `std::net` networking types. +//! +//! This crate implements a number of extensions to the standard `std::net` +//! networking types, hopefully being slated for inclusion into the standard +//! library in the future. The goal of this crate is to expose all sorts of +//! cross-platform and platform-specific configuration options of UDP/TCP +//! sockets. System APIs are wrapped with as thin a layer as possible instead of +//! bundling multiple actions into one API call. +//! +//! More information about the design of this crate can be found in the +//! [associated rfc][rfc] +//! +//! [rfc]: https://github.com/rust-lang/rfcs/pull/1158 +//! +//! # Examples +//! +//! ```no_run +//! use net2::TcpBuilder; +//! +//! let tcp = TcpBuilder::new_v4().unwrap(); +//! tcp.reuse_address(true).unwrap() +//! .only_v6(false).unwrap(); +//! +//! let mut stream = tcp.connect("127.0.0.1:80").unwrap(); +//! +//! // use `stream` as a TcpStream +//! ``` + +#![doc(html_logo_url = "https://www.rust-lang.org/logos/rust-logo-128x128-blk-v2.png", + html_favicon_url = "https://doc.rust-lang.org/favicon.ico", + html_root_url = "https://doc.rust-lang.org/net2-rs")] +#![deny(missing_docs, warnings)] + +// Silence warnings about deprecated try!() usage +#![allow(deprecated)] + +#![cfg_attr(target_os = "wasi", feature(wasi_ext))] + +#[cfg(any(target_os = "redox", target_os = "wasi", unix))] extern crate libc; + +#[cfg(windows)] extern crate winapi; + +#[macro_use] extern crate cfg_if; + +use std::io; +use std::ops::Neg; +use std::net::{ToSocketAddrs, SocketAddr}; + +use utils::{One, NetInt}; + +mod tcp; +mod udp; +mod socket; +mod ext; +mod utils; + +#[cfg(target_os="redox")] #[path = "sys/redox/mod.rs"] mod sys; +#[cfg(unix)] #[path = "sys/unix/mod.rs"] mod sys; +#[cfg(windows)] #[path = "sys/windows/mod.rs"] mod sys; +#[cfg(target_os = "wasi")] #[path = "sys/wasi/mod.rs"] mod sys; +#[cfg(all(unix, not(any(target_os = "solaris", target_os = "illumos"))))] pub mod unix; + +pub use tcp::TcpBuilder; +pub use udp::UdpBuilder; +pub use ext::{TcpStreamExt, TcpListenerExt, UdpSocketExt}; + +fn one_addr(tsa: T) -> io::Result { + let mut addrs = try!(tsa.to_socket_addrs()); + let addr = match addrs.next() { + Some(addr) => addr, + None => return Err(io::Error::new(io::ErrorKind::Other, + "no socket addresses could be resolved")) + }; + if addrs.next().is_none() { + Ok(addr) + } else { + Err(io::Error::new(io::ErrorKind::Other, + "more than one address resolved")) + } +} + +fn cvt>(t: T) -> io::Result { + let one: T = T::one(); + if t == -one { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +#[cfg(windows)] +fn cvt_win(t: T) -> io::Result { + if t == T::zero() { + Err(io::Error::last_os_error()) + } else { + Ok(t) + } +} + +fn hton(i: I) -> I { i.to_be() } + +fn ntoh(i: I) -> I { I::from_be(i) } + +trait AsInner { + type Inner; + fn as_inner(&self) -> &Self::Inner; +} + +trait FromInner { + type Inner; + fn from_inner(inner: Self::Inner) -> Self; +} + +trait IntoInner { + type Inner; + fn into_inner(self) -> Self::Inner; +} diff --git a/vendor/net2/src/socket.rs b/vendor/net2/src/socket.rs new file mode 100644 index 0000000000..2b4a48ce38 --- /dev/null +++ b/vendor/net2/src/socket.rs @@ -0,0 +1,142 @@ +// 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. + +use std::fmt; +use std::io; +use std::mem; +use std::net::{Ipv4Addr, Ipv6Addr, SocketAddr, SocketAddrV4, SocketAddrV6}; +#[cfg(any(unix, target_os = "redox", target_os = "wasi"))] +use libc::c_int; +#[cfg(windows)] +use winapi::ctypes::c_int; + +use sys; +use sys::c; + +pub struct Socket { + inner: sys::Socket, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result { + Ok(Socket { inner: try!(sys::Socket::new(family, ty)) }) + } + + pub fn bind(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr2raw(addr); + unsafe { + ::cvt(c::bind(self.inner.raw(), addr, len as c::socklen_t)).map(|_| ()) + } + } + + pub fn listen(&self, backlog: i32) -> io::Result<()> { + unsafe { + ::cvt(c::listen(self.inner.raw(), backlog)).map(|_| ()) + } + } + + pub fn connect(&self, addr: &SocketAddr) -> io::Result<()> { + let (addr, len) = addr2raw(addr); + unsafe { + ::cvt(c::connect(self.inner.raw(), addr, len)).map(|_| ()) + } + } + + pub fn getsockname(&self) -> io::Result { + unsafe { + let mut storage: c::sockaddr_storage = mem::zeroed(); + let mut len = mem::size_of_val(&storage) as c::socklen_t; + try!(::cvt(c::getsockname(self.inner.raw(), + &mut storage as *mut _ as *mut _, + &mut len))); + raw2addr(&storage, len) + } + } +} + +impl fmt::Debug for Socket { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.inner.raw().fmt(f) + } +} + +impl ::AsInner for Socket { + type Inner = sys::Socket; + fn as_inner(&self) -> &sys::Socket { &self.inner } +} + +impl ::FromInner for Socket { + type Inner = sys::Socket; + fn from_inner(sock: sys::Socket) -> Socket { + Socket { inner: sock } + } +} + +impl ::IntoInner for Socket { + type Inner = sys::Socket; + fn into_inner(self) -> sys::Socket { self.inner } +} + +fn addr2raw(addr: &SocketAddr) -> (*const c::sockaddr, c::socklen_t) { + match *addr { + SocketAddr::V4(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) + } + SocketAddr::V6(ref a) => { + (a as *const _ as *const _, mem::size_of_val(a) as c::socklen_t) + } + } +} + +fn raw2addr(storage: &c::sockaddr_storage, len: c::socklen_t) -> io::Result { + match storage.ss_family as c_int { + c::AF_INET => { + unsafe { + assert!(len as usize >= mem::size_of::()); + let sa = storage as *const _ as *const c::sockaddr_in; + let bits = c::sockaddr_in_u32(&(*sa)); + let ip = Ipv4Addr::new((bits >> 24) as u8, + (bits >> 16) as u8, + (bits >> 8) as u8, + bits as u8); + Ok(SocketAddr::V4(SocketAddrV4::new(ip, ::ntoh((*sa).sin_port)))) + } + } + c::AF_INET6 => { + unsafe { + assert!(len as usize >= mem::size_of::()); + + let sa = storage as *const _ as *const c::sockaddr_in6; + #[cfg(windows)] let arr = (*sa).sin6_addr.u.Byte(); + #[cfg(not(windows))] let arr = (*sa).sin6_addr.s6_addr; + + let ip = Ipv6Addr::new( + (arr[0] as u16) << 8 | (arr[1] as u16), + (arr[2] as u16) << 8 | (arr[3] as u16), + (arr[4] as u16) << 8 | (arr[5] as u16), + (arr[6] as u16) << 8 | (arr[7] as u16), + (arr[8] as u16) << 8 | (arr[9] as u16), + (arr[10] as u16) << 8 | (arr[11] as u16), + (arr[12] as u16) << 8 | (arr[13] as u16), + (arr[14] as u16) << 8 | (arr[15] as u16), + ); + + #[cfg(windows)] let sin6_scope_id = *(*sa).u.sin6_scope_id(); + #[cfg(not(windows))] let sin6_scope_id = (*sa).sin6_scope_id; + + Ok(SocketAddr::V6(SocketAddrV6::new(ip, + ::ntoh((*sa).sin6_port), + (*sa).sin6_flowinfo, + sin6_scope_id))) + } + } + _ => Err(io::Error::new(io::ErrorKind::InvalidInput, "invalid argument")), + } +} diff --git a/vendor/net2/src/sys/redox/impls.rs b/vendor/net2/src/sys/redox/impls.rs new file mode 100644 index 0000000000..388ec69241 --- /dev/null +++ b/vendor/net2/src/sys/redox/impls.rs @@ -0,0 +1,43 @@ +// 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. + +use std::os::unix::io::{FromRawFd, AsRawFd}; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: usize) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> usize { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as usize + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: usize) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> usize { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as usize + } +} diff --git a/vendor/net2/src/sys/redox/mod.rs b/vendor/net2/src/sys/redox/mod.rs new file mode 100644 index 0000000000..9fd9b1f20e --- /dev/null +++ b/vendor/net2/src/sys/redox/mod.rs @@ -0,0 +1,81 @@ +// 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. + + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::unix::io::FromRawFd; +use libc::{self, c_int}; + +mod impls; + +pub mod c { + pub use libc::*; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: c_int, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result { + unsafe { + let fd = ::cvt(libc::socket(family, ty, 0))?; + let mut flags = ::cvt(libc::fcntl(fd, libc::F_GETFD))?; + flags |= libc::O_CLOEXEC; + ::cvt(libc::fcntl(fd, libc::F_SETFD, flags))?; + Ok(Socket { fd: fd }) + } + } + + pub fn raw(&self) -> c_int { self.fd } + + fn into_fd(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd() as usize) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd() as usize) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd() as usize) } + } +} + +impl ::FromInner for Socket { + type Inner = usize; + fn from_inner(fd: usize) -> Socket { + Socket { fd: fd as c_int } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = libc::close(self.fd); + } + } +} diff --git a/vendor/net2/src/sys/unix/impls.rs b/vendor/net2/src/sys/unix/impls.rs new file mode 100644 index 0000000000..95c2fb8081 --- /dev/null +++ b/vendor/net2/src/sys/unix/impls.rs @@ -0,0 +1,44 @@ +// 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. + +use std::os::unix::io::{FromRawFd, AsRawFd}; +use libc::c_int; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: c_int) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> c_int { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: c_int) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> c_int { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() + } +} diff --git a/vendor/net2/src/sys/unix/mod.rs b/vendor/net2/src/sys/unix/mod.rs new file mode 100644 index 0000000000..cc8a60d01e --- /dev/null +++ b/vendor/net2/src/sys/unix/mod.rs @@ -0,0 +1,104 @@ +// 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. + + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::unix::io::FromRawFd; +use libc::{self, c_int}; +#[cfg(not(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris")))] +use libc::{ioctl, FIOCLEX}; + +mod impls; + +pub mod c { + pub use libc::*; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: c_int, +} + +impl Socket { + #[cfg(not(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris")))] + pub fn new(family: c_int, ty: c_int) -> io::Result { + unsafe { + // Linux >2.6.26 overloads the type argument to accept SOCK_CLOEXEC, + // avoiding a race with another thread running fork/exec between + // socket() and ioctl() + #[cfg(any(target_os = "linux", target_os = "android"))] + match ::cvt(libc::socket(family, ty | libc::SOCK_CLOEXEC, 0)) { + Ok(fd) => return Ok(Socket { fd: fd }), + // Older versions of Linux return EINVAL; fall back to ioctl + Err(ref e) if e.raw_os_error() == Some(libc::EINVAL) => {} + Err(e) => return Err(e), + } + + let fd = try!(::cvt(libc::socket(family, ty, 0))); + ioctl(fd, FIOCLEX); + Ok(Socket { fd: fd }) + } + } + + // ioctl(FIOCLEX) is not supported by Solaris/illumos or emscripten, + // use fcntl(FD_CLOEXEC) instead + #[cfg(any(target_os = "emscripten", target_os = "haiku", target_os = "illumos", target_os = "solaris"))] + pub fn new(family: c_int, ty: c_int) -> io::Result { + unsafe { + let fd = try!(::cvt(libc::socket(family, ty, 0))); + libc::fcntl(fd, libc::FD_CLOEXEC); + Ok(Socket { fd: fd }) + } + } + + pub fn raw(&self) -> c_int { self.fd } + + fn into_fd(self) -> c_int { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd()) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd()) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd()) } + } +} + +impl ::FromInner for Socket { + type Inner = c_int; + fn from_inner(fd: c_int) -> Socket { + Socket { fd: fd } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = libc::close(self.fd); + } + } +} diff --git a/vendor/net2/src/sys/wasi/impls.rs b/vendor/net2/src/sys/wasi/impls.rs new file mode 100644 index 0000000000..eef8094b60 --- /dev/null +++ b/vendor/net2/src/sys/wasi/impls.rs @@ -0,0 +1,33 @@ +use std::os::wasi::io::{FromRawFd, AsRawFd}; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys::{self, c::__wasi_fd_t}; + +impl FromRawFd for TcpBuilder { + unsafe fn from_raw_fd(fd: __wasi_fd_t) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for TcpBuilder { + fn as_raw_fd(&self) -> __wasi_fd_t { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as __wasi_fd_t + } +} + +impl FromRawFd for UdpBuilder { + unsafe fn from_raw_fd(fd: __wasi_fd_t) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawFd for UdpBuilder { + fn as_raw_fd(&self) -> __wasi_fd_t { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as __wasi_fd_t + } +} diff --git a/vendor/net2/src/sys/wasi/mod.rs b/vendor/net2/src/sys/wasi/mod.rs new file mode 100644 index 0000000000..bbc507ed68 --- /dev/null +++ b/vendor/net2/src/sys/wasi/mod.rs @@ -0,0 +1,185 @@ +// 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. + +#![allow(non_camel_case_types)] +use libc::{self, c_int, __wasi_fd_t}; +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::wasi::io::FromRawFd; + +mod impls; + +pub mod c { + pub use libc::*; + + pub type sa_family_t = u16; + pub type socklen_t = u32; + pub type in_port_t = u16; + + pub const SOCK_DGRAM: c_int = 0x00; + pub const SOL_SOCKET: c_int = 0x00; + pub const SO_RCVBUF: c_int = 0x00; + pub const SO_SNDBUF: c_int = 0x00; + pub const TCP_NODELAY: c_int = 0x00; + pub const IPPROTO_TCP: c_int = 0x00; + pub const SO_RCVTIMEO: c_int = 0x00; + pub const SO_SNDTIMEO: c_int = 0x00; + pub const IPPROTO_IP: c_int = 0x00; + pub const IP_TTL: c_int = 0x00; + pub const IPPROTO_IPV6: c_int = 0x00; + pub const IPV6_V6ONLY: c_int = 0x00; + pub const SO_ERROR: c_int = 0x00; + pub const SO_LINGER: c_int = 0x00; + pub const SO_BROADCAST: c_int = 0x00; + pub const IP_MULTICAST_LOOP: c_int = 0x00; + pub const IP_MULTICAST_TTL: c_int = 0x00; + pub const IPV6_MULTICAST_HOPS: c_int = 0x00; + pub const IPV6_MULTICAST_LOOP: c_int = 0x00; + pub const IP_MULTICAST_IF: c_int = 0x00; + pub const IPV6_MULTICAST_IF: c_int = 0x00; + pub const IPV6_UNICAST_HOPS: c_int = 0x00; + pub const IP_ADD_MEMBERSHIP: c_int = 0x00; + pub const IPV6_ADD_MEMBERSHIP: c_int = 0x00; + pub const IP_DROP_MEMBERSHIP: c_int = 0x00; + pub const IPV6_DROP_MEMBERSHIP: c_int = 0x00; + pub const SO_REUSEADDR: c_int = 0x00; + pub const SOCK_STREAM: c_int = 0x00; + pub const AF_INET: c_int = 0x00; + pub const AF_INET6: c_int = 0x01; + + #[repr(C)] + pub struct sockaddr_storage { + pub ss_family: sa_family_t, + } + #[repr(C)] + pub struct sockaddr { + pub sa_family: sa_family_t, + pub sa_data: [c_char; 14], + } + + #[repr(C)] + pub struct sockaddr_in6 { + 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)] + pub struct sockaddr_in { + pub sin_family: sa_family_t, + pub sin_port: in_port_t, + pub sin_addr: in_addr, + pub sin_zero: [u8; 8], + } + + #[repr(align(4))] + #[derive(Copy, Clone)] + pub struct in6_addr { + pub s6_addr: [u8; 16], + } + + #[derive(Copy, Clone)] + pub struct ipv6_mreq { + pub ipv6mr_multiaddr: in6_addr, + pub ipv6mr_interface: c_uint, + } + + pub type in_addr_t = u32; + #[derive(Copy, Clone)] + pub struct in_addr { + pub s_addr: in_addr_t, + } + + #[derive(Copy, Clone)] + pub struct linger { + pub l_onoff: c_int, + pub l_linger: c_int, + } + + #[derive(Copy, Clone)] + pub struct ip_mreq { + pub imr_multiaddr: in_addr, + pub imr_interface: in_addr, + } + + pub unsafe fn getsockname(_socket: __wasi_fd_t, _address: *mut sockaddr, + _address_len: *mut socklen_t) -> c_int { + unimplemented!() + } + pub unsafe fn connect(_socket: __wasi_fd_t, _address: *const sockaddr, + _len: socklen_t) -> c_int { + unimplemented!() + } + pub unsafe fn listen(_socket: __wasi_fd_t, _backlog: c_int) -> c_int { + unimplemented!() + } + pub unsafe fn bind(_socket: __wasi_fd_t, _address: *const sockaddr, + _address_len: socklen_t) -> c_int { + unimplemented!() + } + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh((*sa).sin_addr.s_addr) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(addr.s_addr) + } +} + +pub struct Socket { + fd: __wasi_fd_t, +} + +impl Socket { + pub fn new(_family: c_int, _ty: c_int) -> io::Result { + unimplemented!() + } + + pub fn raw(&self) -> libc::__wasi_fd_t { + self.fd + } + + fn into_fd(self) -> libc::__wasi_fd_t { + let fd = self.fd; + mem::forget(self); + fd + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_fd(self.into_fd()) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_fd(self.into_fd()) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_fd(self.into_fd()) } + } +} + +impl ::FromInner for Socket { + type Inner = libc::__wasi_fd_t; + fn from_inner(fd: libc::__wasi_fd_t) -> Socket { + Socket { fd: fd } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + // unsafe { + // let _ = libc::close(self.fd); + // } + } +} \ No newline at end of file diff --git a/vendor/net2/src/sys/windows/impls.rs b/vendor/net2/src/sys/windows/impls.rs new file mode 100644 index 0000000000..48e787ca20 --- /dev/null +++ b/vendor/net2/src/sys/windows/impls.rs @@ -0,0 +1,44 @@ +// 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. + +use std::os::windows::io::{FromRawSocket, RawSocket, AsRawSocket}; +use winapi::um::winsock2::SOCKET; + +use {TcpBuilder, UdpBuilder, FromInner, AsInner}; +use socket::Socket; +use sys; + +impl FromRawSocket for TcpBuilder { + unsafe fn from_raw_socket(fd: RawSocket) -> TcpBuilder { + let sock = sys::Socket::from_inner(fd as SOCKET); + TcpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawSocket for TcpBuilder { + fn as_raw_socket(&self) -> RawSocket { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as RawSocket + } +} + +impl FromRawSocket for UdpBuilder { + unsafe fn from_raw_socket(fd: RawSocket) -> UdpBuilder { + let sock = sys::Socket::from_inner(fd as SOCKET); + UdpBuilder::from_inner(Socket::from_inner(sock)) + } +} + +impl AsRawSocket for UdpBuilder { + fn as_raw_socket(&self) -> RawSocket { + // TODO: this unwrap() is very bad + self.as_inner().borrow().as_ref().unwrap().as_inner().raw() as RawSocket + } +} diff --git a/vendor/net2/src/sys/windows/mod.rs b/vendor/net2/src/sys/windows/mod.rs new file mode 100644 index 0000000000..b2da96d2f9 --- /dev/null +++ b/vendor/net2/src/sys/windows/mod.rs @@ -0,0 +1,124 @@ +// 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. + +#![allow(bad_style)] + +use std::io; +use std::mem; +use std::net::{TcpListener, TcpStream, UdpSocket}; +use std::os::windows::io::{RawSocket, FromRawSocket}; +use std::sync::{Once, ONCE_INIT}; + +const HANDLE_FLAG_INHERIT: DWORD = 0x00000001; + +pub mod c { + pub use winapi::ctypes::*; + pub use winapi::um::handleapi::*; + pub use winapi::um::winbase::*; + pub use winapi::um::winsock2::*; + pub use winapi::um::ws2tcpip::*; + + pub use winapi::shared::inaddr::*; + pub use winapi::shared::in6addr::*; + pub use winapi::shared::minwindef::*; + pub use winapi::shared::ntdef::*; + pub use winapi::shared::ws2def::*; + pub use winapi::shared::ws2def::{SOCK_STREAM, SOCK_DGRAM}; + pub use winapi::shared::ws2def::SOCKADDR as sockaddr; + pub use winapi::shared::ws2def::SOCKADDR_STORAGE as sockaddr_storage; + pub use winapi::shared::ws2def::SOCKADDR_IN as sockaddr_in; + pub use winapi::shared::ws2ipdef::*; + pub use winapi::shared::ws2ipdef::SOCKADDR_IN6_LH as sockaddr_in6; + pub use winapi::shared::ws2ipdef::IP_MREQ as ip_mreq; + pub use winapi::shared::ws2ipdef::IPV6_MREQ as ipv6_mreq; + + pub fn sockaddr_in_u32(sa: &sockaddr_in) -> u32 { + ::ntoh(unsafe { *sa.sin_addr.S_un.S_addr() }) + } + + pub fn in_addr_to_u32(addr: &in_addr) -> u32 { + ::ntoh(unsafe { *addr.S_un.S_addr() }) + } +} + +use self::c::*; + +mod impls; + +fn init() { + static INIT: Once = ONCE_INIT; + + INIT.call_once(|| { + // Initialize winsock through the standard library by just creating a + // dummy socket. Whether this is successful or not we drop the result as + // libstd will be sure to have initialized winsock. + let _ = UdpSocket::bind("127.0.0.1:34254"); + }); +} + +pub struct Socket { + socket: SOCKET, +} + +impl Socket { + pub fn new(family: c_int, ty: c_int) -> io::Result { + init(); + let socket = try!(unsafe { + match WSASocketW(family, ty, 0, 0 as *mut _, 0, + WSA_FLAG_OVERLAPPED) { + INVALID_SOCKET => Err(io::Error::last_os_error()), + n => Ok(Socket { socket: n }), + } + }); + try!(socket.set_no_inherit()); + Ok(socket) + } + + pub fn raw(&self) -> SOCKET { self.socket } + + fn into_socket(self) -> SOCKET { + let socket = self.socket; + mem::forget(self); + socket + } + + pub fn into_tcp_listener(self) -> TcpListener { + unsafe { TcpListener::from_raw_socket(self.into_socket() as RawSocket) } + } + + pub fn into_tcp_stream(self) -> TcpStream { + unsafe { TcpStream::from_raw_socket(self.into_socket() as RawSocket) } + } + + pub fn into_udp_socket(self) -> UdpSocket { + unsafe { UdpSocket::from_raw_socket(self.into_socket() as RawSocket) } + } + + fn set_no_inherit(&self) -> io::Result<()> { + ::cvt_win(unsafe { + SetHandleInformation(self.socket as HANDLE, HANDLE_FLAG_INHERIT, 0) + }).map(|_| ()) + } +} + +impl ::FromInner for Socket { + type Inner = SOCKET; + fn from_inner(socket: SOCKET) -> Socket { + Socket { socket: socket } + } +} + +impl Drop for Socket { + fn drop(&mut self) { + unsafe { + let _ = closesocket(self.socket); + } + } +} diff --git a/vendor/net2/src/tcp.rs b/vendor/net2/src/tcp.rs new file mode 100644 index 0000000000..5a535dbb5c --- /dev/null +++ b/vendor/net2/src/tcp.rs @@ -0,0 +1,161 @@ +// 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. + +use std::cell::RefCell; +use std::io; +use std::net::{SocketAddr, ToSocketAddrs, TcpListener, TcpStream}; +use std::fmt; + +use IntoInner; +use socket::Socket; +use sys::c; + +/// An "in progress" TCP socket which has not yet been connected or listened. +/// +/// Allows configuration of a socket before one of these operations is executed. +pub struct TcpBuilder { + socket: RefCell>, +} + +impl TcpBuilder { + /// Constructs a new TcpBuilder with the `AF_INET` domain, the `SOCK_STREAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v4() -> io::Result { + Socket::new(c::AF_INET, c::SOCK_STREAM).map(::FromInner::from_inner) + } + + /// Constructs a new TcpBuilder with the `AF_INET6` domain, the `SOCK_STREAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v6() -> io::Result { + Socket::new(c::AF_INET6, c::SOCK_STREAM).map(::FromInner::from_inner) + } + + /// Binds this socket to the specified address. + /// + /// This function directly corresponds to the bind(2) function on Windows + /// and Unix. + pub fn bind(&self, addr: T) -> io::Result<&TcpBuilder> + where T: ToSocketAddrs + { + self.with_socket(|sock| { + let addr = try!(::one_addr(addr)); + sock.bind(&addr) + }).map(|()| self) + } + + /// Mark a socket as ready to accept incoming connection requests using + /// accept() + /// + /// This function directly corresponds to the listen(2) function on Windows + /// and Unix. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn listen(&self, backlog: i32) -> io::Result { + self.with_socket(|sock| { + sock.listen(backlog) + }).and_then(|()| { + self.to_tcp_listener() + }) + } + + /// Initiate a connection on this socket to the specified address. + /// + /// This function directly corresponds to the connect(2) function on Windows + /// and Unix. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn connect(&self, addr: T) -> io::Result + where T: ToSocketAddrs + { + self.with_socket(|sock| { + let err = io::Error::new(io::ErrorKind::Other, + "no socket addresses resolved"); + try!(addr.to_socket_addrs()).fold(Err(err), |prev, addr| { + prev.or_else(|_| sock.connect(&addr)) + }) + }).and_then(|()| { + self.to_tcp_stream() + }) + } + + /// Converts this builder into a `TcpStream` + /// + /// This function will consume the internal socket and return it re-wrapped + /// as a `TcpStream`. An error will be returned if the internal socket has + /// already been consumed from a successful call to `connect`, `listen`, + /// etc. + pub fn to_tcp_stream(&self) -> io::Result { + self.socket.borrow_mut().take().map(|s| s.into_inner().into_tcp_stream()) + .ok_or(io::Error::new(io::ErrorKind::Other, + "socket has already been consumed")) + } + + /// Converts this builder into a `TcpListener` + /// + /// This function will consume the internal socket and return it re-wrapped + /// as a `TcpListener`. An error will be returned if the internal socket has + /// already been consumed from a successful call to `connect`, `listen`, + /// etc. + pub fn to_tcp_listener(&self) -> io::Result { + self.socket.borrow_mut().take() + .map(|s| s.into_inner().into_tcp_listener()) + .ok_or(io::Error::new(io::ErrorKind::Other, + "socket has already been consumed")) + } + + /// Returns the address of the local half of this TCP socket. + /// + /// An error will be returned if `listen` or `connect` has already been + /// called on this builder. + pub fn local_addr(&self) -> io::Result { + match *self.socket.borrow() { + Some(ref s) => s.getsockname(), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } + + fn with_socket(&self, f: F) -> io::Result<()> + where F: FnOnce(&Socket) -> io::Result<()> + { + match *self.socket.borrow() { + Some(ref s) => f(s), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } +} + +impl fmt::Debug for TcpBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "TcpBuilder {{ socket: {:?} }}", + self.socket.borrow().as_ref().unwrap()) + } +} + +impl ::AsInner for TcpBuilder { + type Inner = RefCell>; + fn as_inner(&self) -> &RefCell> { &self.socket } +} + +impl ::FromInner for TcpBuilder { + type Inner = Socket; + fn from_inner(sock: Socket) -> TcpBuilder { + TcpBuilder { socket: RefCell::new(Some(sock)) } + } +} diff --git a/vendor/net2/src/udp.rs b/vendor/net2/src/udp.rs new file mode 100644 index 0000000000..d061ab5c6f --- /dev/null +++ b/vendor/net2/src/udp.rs @@ -0,0 +1,89 @@ +// 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. + +use std::cell::RefCell; +use std::fmt; +use std::io; +use std::net::{ToSocketAddrs, UdpSocket}; + +use IntoInner; +use socket::Socket; +use sys::c; + +/// An "in progress" UDP socket which has not yet been connected. +/// +/// Allows configuration of a socket before the socket is connected. +pub struct UdpBuilder { + socket: RefCell>, +} + +impl UdpBuilder { + /// Constructs a new UdpBuilder with the `AF_INET` domain, the `SOCK_DGRAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v4() -> io::Result { + Socket::new(c::AF_INET, c::SOCK_DGRAM).map(::FromInner::from_inner) + } + + /// Constructs a new UdpBuilder with the `AF_INET6` domain, the `SOCK_DGRAM` + /// type, and with a protocol argument of 0. + /// + /// Note that passing other kinds of flags or arguments can be done through + /// the `FromRaw{Fd,Socket}` implementation. + pub fn new_v6() -> io::Result { + Socket::new(c::AF_INET6, c::SOCK_DGRAM).map(::FromInner::from_inner) + } + + /// Binds this socket to the specified address. + /// + /// This function directly corresponds to the bind(2) function on Windows + /// and Unix. + pub fn bind(&self, addr: T) -> io::Result + where T: ToSocketAddrs + { + try!(self.with_socket(|sock| { + let addr = try!(::one_addr(addr)); + sock.bind(&addr) + })); + Ok(self.socket.borrow_mut().take().unwrap().into_inner().into_udp_socket()) + } + + fn with_socket(&self, f: F) -> io::Result<()> + where F: FnOnce(&Socket) -> io::Result<()> + { + match *self.socket.borrow() { + Some(ref s) => f(s), + None => Err(io::Error::new(io::ErrorKind::Other, + "builder has already finished its socket")), + } + } +} + +impl fmt::Debug for UdpBuilder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "UdpBuilder {{ socket: {:?} }}", + self.socket.borrow().as_ref().unwrap()) + } +} + +impl ::AsInner for UdpBuilder { + type Inner = RefCell>; + fn as_inner(&self) -> &RefCell> { &self.socket } +} + +impl ::FromInner for UdpBuilder { + type Inner = Socket; + fn from_inner(sock: Socket) -> UdpBuilder { + UdpBuilder { socket: RefCell::new(Some(sock)) } + } +} + diff --git a/vendor/net2/src/unix.rs b/vendor/net2/src/unix.rs new file mode 100644 index 0000000000..a1e1c6f5e9 --- /dev/null +++ b/vendor/net2/src/unix.rs @@ -0,0 +1,57 @@ +//! Unix-specific extensions to the `std::net` types. + +use std::io; +use sys::c::{self, c_int}; + +use {TcpBuilder, UdpBuilder}; +use ext::{self, AsSock}; + +/// Unix-specific extensions for the `TcpBuilder` type in this library. +pub trait UnixTcpBuilderExt { + /// Set value for the `SO_REUSEPORT` option on this socket. + /// + /// This indicates that further calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + fn reuse_port(&self, reuse: bool) -> io::Result<&Self>; + + /// Check the value of the `SO_REUSEPORT` option on this socket. + fn get_reuse_port(&self) -> io::Result; +} + +impl UnixTcpBuilderExt for TcpBuilder { + fn reuse_port(&self, reuse: bool) -> io::Result<&Self> { + ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT, + reuse as c_int).map(|()| self) + } + + fn get_reuse_port(&self) -> io::Result { + ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT) + .map(ext::int2bool) + } +} + +/// Unix-specific extensions for the `UdpBuilder` type in this library. +pub trait UnixUdpBuilderExt { + /// Set value for the `SO_REUSEPORT` option on this socket. + /// + /// This indicates that further calls to `bind` may allow reuse of local + /// addresses. For IPv4 sockets this means that a socket may bind even when + /// there's a socket already listening on this port. + fn reuse_port(&self, reuse: bool) -> io::Result<&Self>; + + /// Check the value of the `SO_REUSEPORT` option on this socket. + fn get_reuse_port(&self) -> io::Result; +} + +impl UnixUdpBuilderExt for UdpBuilder { + fn reuse_port(&self, reuse: bool) -> io::Result<&Self> { + ext::set_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT, + reuse as c_int).map(|()| self) + } + + fn get_reuse_port(&self) -> io::Result { + ext::get_opt(self.as_sock(), c::SOL_SOCKET, c::SO_REUSEPORT) + .map(ext::int2bool) + } +} diff --git a/vendor/net2/src/utils.rs b/vendor/net2/src/utils.rs new file mode 100644 index 0000000000..21fe9d61fc --- /dev/null +++ b/vendor/net2/src/utils.rs @@ -0,0 +1,51 @@ +// 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. + + +#[doc(hidden)] +pub trait NetInt { + fn from_be(i: Self) -> Self; + fn to_be(&self) -> Self; +} +macro_rules! doit { + ($($t:ident)*) => ($(impl NetInt for $t { + fn from_be(i: Self) -> Self { <$t>::from_be(i) } + fn to_be(&self) -> Self { <$t>::to_be(*self) } + })*) +} +doit! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + +#[doc(hidden)] +pub trait One { + fn one() -> Self; +} + +macro_rules! one { + ($($t:ident)*) => ($( + impl One for $t { fn one() -> $t { 1 } } + )*) +} + +one! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + + +#[doc(hidden)] +pub trait Zero { + fn zero() -> Self; +} + +macro_rules! zero { + ($($t:ident)*) => ($( + impl Zero for $t { fn zero() -> $t { 0 } } + )*) +} + +zero! { i8 i16 i32 i64 isize u8 u16 u32 u64 usize } + diff --git a/vendor/opaque-debug-0.2.3/.cargo-checksum.json b/vendor/opaque-debug-0.2.3/.cargo-checksum.json new file mode 100644 index 0000000000..e431ffb85c --- /dev/null +++ b/vendor/opaque-debug-0.2.3/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"316df812f280ae0c584b6132630119bea8de32864c29772100f9bb8352196381","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"2d7d563f4a4df4b0583d6370046642103e4909f0ec2002768308f951f2d7e05c"},"package":"2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"} \ No newline at end of file diff --git a/vendor/opaque-debug-0.2.3/Cargo.toml b/vendor/opaque-debug-0.2.3/Cargo.toml new file mode 100644 index 0000000000..a2f9f1736d --- /dev/null +++ b/vendor/opaque-debug-0.2.3/Cargo.toml @@ -0,0 +1,22 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +name = "opaque-debug" +version = "0.2.3" +authors = ["RustCrypto Developers"] +description = "Macro for opaque Debug trait implementation" +documentation = "https://docs.rs/opaque-debug" +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/utils" + +[dependencies] diff --git a/vendor/opaque-debug-0.2.3/LICENSE-APACHE b/vendor/opaque-debug-0.2.3/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/opaque-debug-0.2.3/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/opaque-debug-0.2.3/LICENSE-MIT b/vendor/opaque-debug-0.2.3/LICENSE-MIT new file mode 100644 index 0000000000..502cee6e85 --- /dev/null +++ b/vendor/opaque-debug-0.2.3/LICENSE-MIT @@ -0,0 +1,25 @@ +Copyright (c) 2018-2019 The RustCrypto Project Developers + +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 --git a/vendor/opaque-debug-0.2.3/src/lib.rs b/vendor/opaque-debug-0.2.3/src/lib.rs new file mode 100644 index 0000000000..618626ead7 --- /dev/null +++ b/vendor/opaque-debug-0.2.3/src/lib.rs @@ -0,0 +1,24 @@ +//! Macro for opaque `Debug` trait implementation. +#![no_std] + +#[doc(hidden)] +pub extern crate core as __core; + +/// Macro for defining opaque `Debug` implementation. +/// +/// It will use the following format: "StructName { ... }". While it's +/// convinient to have it (e.g. for including into other structs), it could be +/// undesirable to leak internall state, which can happen for example through +/// uncareful logging. +#[macro_export] +macro_rules! impl_opaque_debug { + ($struct:ty) => { + impl $crate::__core::fmt::Debug for $struct { + fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) + -> Result<(), $crate::__core::fmt::Error> + { + write!(f, concat!(stringify!($struct), " {{ ... }}")) + } + } + } +} diff --git a/vendor/opaque-debug/.cargo-checksum.json b/vendor/opaque-debug/.cargo-checksum.json index e431ffb85c..737800c677 100644 --- a/vendor/opaque-debug/.cargo-checksum.json +++ b/vendor/opaque-debug/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"316df812f280ae0c584b6132630119bea8de32864c29772100f9bb8352196381","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"2d7d563f4a4df4b0583d6370046642103e4909f0ec2002768308f951f2d7e05c"},"package":"2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c"} \ No newline at end of file +{"files":{"Cargo.toml":"6eed73941bd5295d09d546b5690ef723a88c022947461f68e246299466bf779d","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"d5c22aa3118d240e877ad41c5d9fa232f9c77d757d4aac0c2f943afc0a95e0ef","src/lib.rs":"b7f7f6a9dd862dd8d132ae35cc3fd131938f64c9a8e0e5fab42bb5a1ed0f459b","tests/mod.rs":"8db1fbb5043e175e9f780e78a34a3e6d22f2010cfd2a8b26fcfdec1b71c0a75d"},"package":"624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5"} \ No newline at end of file diff --git a/vendor/opaque-debug/Cargo.toml b/vendor/opaque-debug/Cargo.toml index a2f9f1736d..9650c91794 100644 --- a/vendor/opaque-debug/Cargo.toml +++ b/vendor/opaque-debug/Cargo.toml @@ -11,12 +11,11 @@ # will likely look very different (and much more reasonable) [package] +edition = "2018" name = "opaque-debug" -version = "0.2.3" +version = "0.3.0" authors = ["RustCrypto Developers"] description = "Macro for opaque Debug trait implementation" documentation = "https://docs.rs/opaque-debug" license = "MIT OR Apache-2.0" repository = "https://github.com/RustCrypto/utils" - -[dependencies] diff --git a/vendor/opaque-debug/src/lib.rs b/vendor/opaque-debug/src/lib.rs index 618626ead7..6d564a3bf4 100644 --- a/vendor/opaque-debug/src/lib.rs +++ b/vendor/opaque-debug/src/lib.rs @@ -8,10 +8,10 @@ pub extern crate core as __core; /// /// It will use the following format: "StructName { ... }". While it's /// convinient to have it (e.g. for including into other structs), it could be -/// undesirable to leak internall state, which can happen for example through +/// undesirable to leak internal state, which can happen for example through /// uncareful logging. #[macro_export] -macro_rules! impl_opaque_debug { +macro_rules! implement { ($struct:ty) => { impl $crate::__core::fmt::Debug for $struct { fn fmt(&self, f: &mut $crate::__core::fmt::Formatter) diff --git a/vendor/opaque-debug/tests/mod.rs b/vendor/opaque-debug/tests/mod.rs new file mode 100644 index 0000000000..bcd575767a --- /dev/null +++ b/vendor/opaque-debug/tests/mod.rs @@ -0,0 +1,13 @@ +#![allow(dead_code)] + +struct Foo { + secret: u64, +} + +opaque_debug::implement!(Foo); + +#[test] +fn debug_formatting() { + let s = format!("{:?}", Foo { secret: 42 }); + assert_eq!(s, "Foo { ... }"); +} diff --git a/vendor/parking_lot-0.10.2/.cargo-checksum.json b/vendor/parking_lot-0.10.2/.cargo-checksum.json deleted file mode 100644 index 784094cd6f..0000000000 --- a/vendor/parking_lot-0.10.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"CHANGELOG.md":"18a3b6c2a59fb59450362712afae444070b23c2697cf20aa9ee3911dd9f6d981","Cargo.toml":"c0d17dd8decba5afb1495577e0ded39c0228eeb2eb14be4f4d4d5d9c96ebc0c3","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","README.md":"0f1b45638eb0d2b3f142baec830319a5790f3f2004eac5bc5f3e95bc632bdaed","appveyor.yml":"e2416e65e27442dd8e17c773deee1e45ee96157221bc81b03d9a6d25bfa570e2","bors.toml":"1c81ede536a37edd30fe4e622ff0531b25372403ac9475a5d6c50f14156565a2","src/condvar.rs":"510f96e94b56f0cb0d200a8e94b0487d0799e13b9e126b9b416f22d8dc11b643","src/deadlock.rs":"7d3ebb5b4f63658435df277bb983e352e4bc651a92c4fd48ae68bf103e452d0d","src/elision.rs":"9aceb0b27fd3cdaf4ef76bda63435a96ec2fdef24be098b9e4edbc39db000765","src/fair_mutex.rs":"d0a032e8207919da04b85f1422dfb14aa2af7aad78843c708d2fe3e0478e401a","src/lib.rs":"3d89619878f3c8b6190261321a4e430e0514c97b65e8c911c0764ea57c0605f2","src/mutex.rs":"afc25db5c45da63c743029ee3cb22e262ea7a32b533245b441c0a5835f9f525f","src/once.rs":"a1c38a5d87077e3d112d57e065ee126a24ab19f04fba9cb1f2cb43bc82caf33c","src/raw_fair_mutex.rs":"a7415aa6cbc040a2f886d06dd6c0c0b3be9963936a31f60f1494e718c9d18acb","src/raw_mutex.rs":"f3507478c34b49bd725dfaed6bf4847fc3aec28700960a7823af9e15b06b5e24","src/raw_rwlock.rs":"f8ce7c4f92299cf64cb6e7b69cd46d9ddefd1211535729b6455e82f7c4eb3eae","src/remutex.rs":"7a0de55161cd57497bb52d3aecca69a89eff2e71cdb2d762df53579e0607b489","src/rwlock.rs":"1a782ab4fafc0c542d1c42151b98475829c96da168d2d0e8947181b7f2d7cb07","src/util.rs":"37a2c8b5c9254df83e8f3a5cd831558c1045061a76c2571bdc4d78eb86e467f2","tests/issue_203.rs":"5fbdf6ec63f391d86457df949678c203a1e81e8aa32d4e10037fa76e768702c0"},"package":"d3a704eb390aafdc107b0e392f56a82b668e3a71366993b5340f5833fd62505e"} \ No newline at end of file diff --git a/vendor/parking_lot-0.10.2/CHANGELOG.md b/vendor/parking_lot-0.10.2/CHANGELOG.md deleted file mode 100644 index c187e4d157..0000000000 --- a/vendor/parking_lot-0.10.2/CHANGELOG.md +++ /dev/null @@ -1,120 +0,0 @@ -## parking_lot 0.10.2 (2020-04-10) - -- Update minimum version of `lock_api`. - -## parking_lot 0.10.1, parking_lot_core 0.7.1, lock_api 0.3.4 (2020-04-10) - -- Add methods to construct `Mutex`, `RwLock`, etc in a `const` context. (#217) -- Add `FairMutex` which always uses fair unlocking. (#204) -- Fixed panic with deadlock detection on macOS. (#203) -- Fixed incorrect synchronization in `create_hashtable`. (#210) -- Use `llvm_asm!` instead of the deprecated `asm!`. (#223) - -## lock_api 0.3.3 (2020-01-04) - -- Deprecate unsound `MappedRwLockWriteGuard::downgrade` (#198) - -## parking_lot 0.10.0, parking_lot_core 0.7.0, lock_api 0.3.2 (2019-11-25) - -- Upgrade smallvec dependency to 1.0 in parking_lot_core. -- Replace all usage of `mem::uninitialized` with `mem::MaybeUninit`. -- The minimum required Rust version is bumped to 1.36. Because of the above two changes. -- Make methods on `WaitTimeoutResult` and `OnceState` take `self` by value instead of reference. - -## parking_lot_core 0.6.2 (2019-07-22) - -- Fixed compile error on Windows with old cfg_if version. (#164) - -## parking_lot_core 0.6.1 (2019-07-17) - -- Fixed Android build. (#163) - -## parking_lot 0.9.0, parking_lot_core 0.6.0, lock_api 0.3.1 (2019-07-14) - -- Re-export lock_api (0.3.1) from parking_lot (#150) -- Removed (non-dev) dependency on rand crate for fairness mechanism, by - including a simple xorshift PRNG in core (#144) -- Android now uses the futex-based ThreadParker. (#140) -- Fixed CloudABI ThreadParker. (#140) -- Fix race condition in lock_api::ReentrantMutex (da16c2c7) - -## lock_api 0.3.0 (2019-07-03, _yanked_) - -- Use NonZeroUsize in GetThreadId::nonzero_thread_id (#148) -- Debug assert lock_count in ReentrantMutex (#148) -- Tag as `unsafe` and document some internal methods (#148) -- This release was _yanked_ due to a regression in ReentrantMutex (da16c2c7) - -## parking_lot 0.8.1 (2019-07-03, _yanked_) - -- Re-export lock_api (0.3.0) from parking_lot (#150) -- This release was _yanked_ from crates.io due to unexpected breakage (#156) - -## parking_lot 0.8.0, parking_lot_core 0.5.0, lock_api 0.2.0 (2019-05-04) - -- Fix race conditions in deadlock detection. -- Support for more platforms by adding ThreadParker implementations for - Wasm, Redox, SGX and CloudABI. -- Drop support for older Rust. parking_lot now requires 1.31 and is a - Rust 2018 edition crate (#122). -- Disable the owning_ref feature by default. -- Fix was_last_thread value in the timeout callback of park() (#129). -- Support single byte Mutex/Once on stable Rust when compiler is at least - version 1.34. -- Make Condvar::new and Once::new const fns on stable Rust and remove - ONCE_INIT (#134). -- Add optional Serde support (#135). - -## parking_lot 0.7.1 (2019-01-01) - -- Fixed potential deadlock when upgrading a RwLock. -- Fixed overflow panic on very long timeouts (#111). - -## parking_lot 0.7.0, parking_lot_core 0.4.0 (2018-11-26) - -- Return if or how many threads were notified from `Condvar::notify_*` - -## parking_lot 0.6.3 (2018-07-18) - -- Export `RawMutex`, `RawRwLock` and `RawThreadId`. - -## parking_lot 0.6.2 (2018-06-18) - -- Enable `lock_api/nightly` feature from `parking_lot/nightly` (#79) - -## parking_lot 0.6.1 (2018-06-08) - -Added missing typedefs for mapped lock guards: - -- `MappedMutexGuard` -- `MappedReentrantMutexGuard` -- `MappedRwLockReadGuard` -- `MappedRwLockWriteGuard` - -## parking_lot 0.6.0 (2018-06-08) - -This release moves most of the code for type-safe `Mutex` and `RwLock` types -into a separate crate called `lock_api`. This new crate is compatible with -`no_std` and provides `Mutex` and `RwLock` type-safe wrapper types from a raw -mutex type which implements the `RawMutex` or `RawRwLock` trait. The API -provided by the wrapper types can be extended by implementing more traits on -the raw mutex type which provide more functionality (e.g. `RawMutexTimed`). See -the crate documentation for more details. - -There are also several major changes: - -- The minimum required Rust version is bumped to 1.26. -- All methods on `MutexGuard` (and other guard types) are no longer inherent - methods and must be called as `MutexGuard::method(self)`. This avoids - conflicts with methods from the inner type. -- `MutexGuard` (and other guard types) add the `unlocked` method which - temporarily unlocks a mutex, runs the given closure, and then re-locks the - mutex. -- `MutexGuard` (and other guard types) add the `bump` method which gives a - chance for other threads to acquire the mutex by temporarily unlocking it and - re-locking it. However this is optimized for the common case where there are - no threads waiting on the lock, in which case no unlocking is performed. -- `MutexGuard` (and other guard types) add the `map` method which returns a - `MappedMutexGuard` which holds only a subset of the original locked type. The - `MappedMutexGuard` type is identical to `MutexGuard` except that it does not - support the `unlocked` and `bump` methods, and can't be used with `CondVar`. diff --git a/vendor/parking_lot-0.10.2/Cargo.toml b/vendor/parking_lot-0.10.2/Cargo.toml deleted file mode 100644 index 57940fff19..0000000000 --- a/vendor/parking_lot-0.10.2/Cargo.toml +++ /dev/null @@ -1,40 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "parking_lot" -version = "0.10.2" -authors = ["Amanieu d'Antras "] -description = "More compact and efficient implementations of the standard synchronization primitives." -readme = "README.md" -keywords = ["mutex", "condvar", "rwlock", "once", "thread"] -categories = ["concurrency"] -license = "Apache-2.0/MIT" -repository = "https://github.com/Amanieu/parking_lot" -[dependencies.lock_api] -version = "0.3.4" - -[dependencies.parking_lot_core] -version = "0.7.1" -[dev-dependencies.bincode] -version = "1.1.3" - -[dev-dependencies.rand] -version = "0.7" - -[features] -deadlock_detection = ["parking_lot_core/deadlock_detection"] -default = [] -nightly = ["parking_lot_core/nightly", "lock_api/nightly"] -owning_ref = ["lock_api/owning_ref"] -serde = ["lock_api/serde"] diff --git a/vendor/parking_lot-0.10.2/README.md b/vendor/parking_lot-0.10.2/README.md deleted file mode 100644 index 3ec4cb0418..0000000000 --- a/vendor/parking_lot-0.10.2/README.md +++ /dev/null @@ -1,140 +0,0 @@ -parking_lot -============ - -[![Build Status](https://travis-ci.org/Amanieu/parking_lot.svg?branch=master)](https://travis-ci.org/Amanieu/parking_lot) [![Build status](https://ci.appveyor.com/api/projects/status/wppcc32ttpud0a30/branch/master?svg=true)](https://ci.appveyor.com/project/Amanieu/parking-lot/branch/master) [![Crates.io](https://img.shields.io/crates/v/parking_lot.svg)](https://crates.io/crates/parking_lot) - -[Documentation (synchronization primitives)](https://docs.rs/parking_lot/) - -[Documentation (core parking lot API)](https://docs.rs/parking_lot_core/) - -[Documentation (type-safe lock API)](https://docs.rs/lock_api/) - -This library provides implementations of `Mutex`, `RwLock`, `Condvar` and -`Once` that are smaller, faster and more flexible than those in the Rust -standard library, as well as a `ReentrantMutex` type which supports recursive -locking. It also exposes a low-level API for creating your own efficient -synchronization primitives. - -When tested on x86_64 Linux, `parking_lot::Mutex` was found to be 1.5x -faster than `std::sync::Mutex` when uncontended, and up to 5x faster when -contended from multiple threads. The numbers for `RwLock` vary depending on -the number of reader and writer threads, but are almost always faster than -the standard library `RwLock`, and even up to 50x faster in some cases. - -## Features - -The primitives provided by this library have several advantages over those -in the Rust standard library: - -1. `Mutex` and `Once` only require 1 byte of storage space, while `Condvar` - and `RwLock` only require 1 word of storage space. On the other hand the - standard library primitives require a dynamically allocated `Box` to hold - OS-specific synchronization primitives. The small size of `Mutex` in - particular encourages the use of fine-grained locks to increase - parallelism. -2. Since they consist of just a single atomic variable, have constant - initializers and don't need destructors, these primitives can be used as - `static` global variables. The standard library primitives require - dynamic initialization and thus need to be lazily initialized with - `lazy_static!`. -3. Uncontended lock acquisition and release is done through fast inline - paths which only require a single atomic operation. -4. Microcontention (a contended lock with a short critical section) is - efficiently handled by spinning a few times while trying to acquire a - lock. -5. The locks are adaptive and will suspend a thread after a few failed spin - attempts. This makes the locks suitable for both long and short critical - sections. -6. `Condvar`, `RwLock` and `Once` work on Windows XP, unlike the standard - library versions of those types. -7. `RwLock` takes advantage of hardware lock elision on processors that - support it, which can lead to huge performance wins with many readers. -8. `RwLock` uses a task-fair locking policy, which avoids reader and writer - starvation, whereas the standard library version makes no guarantees. -9. `Condvar` is guaranteed not to produce spurious wakeups. A thread will - only be woken up if it timed out or it was woken up by a notification. -10. `Condvar::notify_all` will only wake up a single thread and requeue the - rest to wait on the associated `Mutex`. This avoids a thundering herd - problem where all threads try to acquire the lock at the same time. -11. `RwLock` supports atomically downgrading a write lock into a read lock. -12. `Mutex` and `RwLock` allow raw unlocking without a RAII guard object. -13. `Mutex<()>` and `RwLock<()>` allow raw locking without a RAII guard - object. -14. `Mutex` and `RwLock` support [eventual fairness](https://trac.webkit.org/changeset/203350) - which allows them to be fair on average without sacrificing performance. -15. A `ReentrantMutex` type which supports recursive locking. -16. An *experimental* deadlock detector that works for `Mutex`, - `RwLock` and `ReentrantMutex`. This feature is disabled by default and - can be enabled via the `deadlock_detection` feature. -17. `RwLock` supports atomically upgrading an "upgradable" read lock into a - write lock. -18. Optional support for [serde](https://docs.serde.rs/serde/). Enable via the - feature `serde`. **NOTE!** this support is for `Mutex`, `ReentrantMutex`, - and `RwLock` only; `Condvar` and `Once` are not currently supported. - -## The parking lot - -To keep these primitives small, all thread queuing and suspending -functionality is offloaded to the *parking lot*. The idea behind this is -based on the Webkit [`WTF::ParkingLot`](https://webkit.org/blog/6161/locking-in-webkit/) -class, which essentially consists of a hash table mapping of lock addresses -to queues of parked (sleeping) threads. The Webkit parking lot was itself -inspired by Linux [futexes](http://man7.org/linux/man-pages/man2/futex.2.html), -but it is more powerful since it allows invoking callbacks while holding a queue -lock. - -## Nightly vs stable - -There are a few restrictions when using this library on stable Rust: - -- You will have to use the `const_*` functions (e.g. `const_mutex(val)`) to - statically initialize the locking primitives. Using e.g. `Mutex::new(val)` - does not work on stable Rust yet. -- `RwLock` will not be able to take advantage of hardware lock elision for - readers, which improves performance when there are multiple readers. - -To enable nightly-only functionality, you need to enable the `nightly` feature -in Cargo (see below). - -## Usage - -Add this to your `Cargo.toml`: - -```toml -[dependencies] -parking_lot = "0.10" -``` - -To enable nightly-only features, add this to your `Cargo.toml` instead: - -```toml -[dependencies] -parking_lot = { version = "0.10", features = ["nightly"] } -``` - -The experimental deadlock detector can be enabled with the -`deadlock_detection` Cargo feature. - -The core parking lot API is provided by the `parking_lot_core` crate. It is -separate from the synchronization primitives in the `parking_lot` crate so that -changes to the core API do not cause breaking changes for users of `parking_lot`. - -## Minimum Rust version - -The current minimum required Rust version is 1.36. Any change to this is -considered a breaking change and will require a major version bump. - -## License - -Licensed under either of - - * Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE) or http://www.apache.org/licenses/LICENSE-2.0) - * MIT license ([LICENSE-MIT](LICENSE-MIT) or http://opensource.org/licenses/MIT) - -at your option. - -### Contribution - -Unless you explicitly state otherwise, any contribution intentionally submitted -for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any -additional terms or conditions. diff --git a/vendor/parking_lot-0.10.2/appveyor.yml b/vendor/parking_lot-0.10.2/appveyor.yml deleted file mode 100644 index a7eb5cfc98..0000000000 --- a/vendor/parking_lot-0.10.2/appveyor.yml +++ /dev/null @@ -1,59 +0,0 @@ -environment: - TRAVIS_CARGO_NIGHTLY_FEATURE: nightly - RUST_TEST_THREADS: 1 - matrix: - - TARGET: x86_64-pc-windows-msvc - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: i686-pc-windows-msvc - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: x86_64-pc-windows-gnu - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: i686-pc-windows-gnu - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: nightly - FEATURES: nightly - - TARGET: x86_64-pc-windows-msvc - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: 1.36.0 - - TARGET: i686-pc-windows-msvc - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: 1.36.0 - - TARGET: x86_64-pc-windows-gnu - MSYSTEM: MINGW64 - CPU: x86_64 - TOOLCHAIN: 1.36.0 - - TARGET: i686-pc-windows-gnu - MSYSTEM: MINGW32 - CPU: i686 - TOOLCHAIN: 1.36.0 - -install: - - set PATH=C:\msys64\%MSYSTEM%\bin;c:\msys64\usr\bin;%PATH% - - pacman --noconfirm -Syu mingw-w64-%CPU%-make - - appveyor-retry appveyor DownloadFile https://win.rustup.rs/ -FileName rustup-init.exe - - rustup-init.exe -y --default-host %TARGET% --default-toolchain %TOOLCHAIN% - - set PATH=%PATH%;C:\Users\appveyor\.cargo\bin - - rustc -vV - - cargo -vV - -build_script: - - cargo build --features "%FEATURES%" - -test_script: - - cargo test --all --features "%FEATURES%" - - cargo doc --all - - cd benchmark - - cargo run --release --bin mutex -- 2 1 0 1 2 - - cargo run --release --bin rwlock -- 1 1 1 0 1 2 diff --git a/vendor/parking_lot-0.10.2/bors.toml b/vendor/parking_lot-0.10.2/bors.toml deleted file mode 100644 index ca08e818bf..0000000000 --- a/vendor/parking_lot-0.10.2/bors.toml +++ /dev/null @@ -1,3 +0,0 @@ -status = [ - "continuous-integration/travis-ci/push", -] diff --git a/vendor/parking_lot-0.10.2/src/condvar.rs b/vendor/parking_lot-0.10.2/src/condvar.rs deleted file mode 100644 index 0afda3a5b1..0000000000 --- a/vendor/parking_lot-0.10.2/src/condvar.rs +++ /dev/null @@ -1,1052 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::mutex::MutexGuard; -use crate::raw_mutex::{RawMutex, TOKEN_HANDOFF, TOKEN_NORMAL}; -use crate::{deadlock, util}; -use core::{ - fmt, ptr, - sync::atomic::{AtomicPtr, Ordering}, -}; -use lock_api::RawMutex as RawMutex_; -use parking_lot_core::{self, ParkResult, RequeueOp, UnparkResult, DEFAULT_PARK_TOKEN}; -use std::time::{Duration, Instant}; - -/// A type indicating whether a timed wait on a condition variable returned -/// due to a time out or not. -#[derive(Debug, PartialEq, Eq, Copy, Clone)] -pub struct WaitTimeoutResult(bool); - -impl WaitTimeoutResult { - /// Returns whether the wait was known to have timed out. - #[inline] - pub fn timed_out(self) -> bool { - self.0 - } -} - -/// A Condition Variable -/// -/// Condition variables represent the ability to block a thread such that it -/// consumes no CPU time while waiting for an event to occur. Condition -/// variables are typically associated with a boolean predicate (a condition) -/// and a mutex. The predicate is always verified inside of the mutex before -/// determining that thread must block. -/// -/// Note that this module places one additional restriction over the system -/// condition variables: each condvar can be used with only one mutex at a -/// time. Any attempt to use multiple mutexes on the same condition variable -/// simultaneously will result in a runtime panic. However it is possible to -/// switch to a different mutex if there are no threads currently waiting on -/// the condition variable. -/// -/// # Differences from the standard library `Condvar` -/// -/// - No spurious wakeups: A wait will only return a non-timeout result if it -/// was woken up by `notify_one` or `notify_all`. -/// - `Condvar::notify_all` will only wake up a single thread, the rest are -/// requeued to wait for the `Mutex` to be unlocked by the thread that was -/// woken up. -/// - Only requires 1 word of space, whereas the standard library boxes the -/// `Condvar` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::{Mutex, Condvar}; -/// use std::sync::Arc; -/// use std::thread; -/// -/// let pair = Arc::new((Mutex::new(false), Condvar::new())); -/// let pair2 = pair.clone(); -/// -/// // Inside of our lock, spawn a new thread, and then wait for it to start -/// thread::spawn(move|| { -/// let &(ref lock, ref cvar) = &*pair2; -/// let mut started = lock.lock(); -/// *started = true; -/// cvar.notify_one(); -/// }); -/// -/// // wait for the thread to start up -/// let &(ref lock, ref cvar) = &*pair; -/// let mut started = lock.lock(); -/// if !*started { -/// cvar.wait(&mut started); -/// } -/// // Note that we used an if instead of a while loop above. This is only -/// // possible because parking_lot's Condvar will never spuriously wake up. -/// // This means that wait() will only return after notify_one or notify_all is -/// // called. -/// ``` -pub struct Condvar { - state: AtomicPtr, -} - -impl Condvar { - /// Creates a new condition variable which is ready to be waited on and - /// notified. - #[inline] - pub const fn new() -> Condvar { - Condvar { - state: AtomicPtr::new(ptr::null_mut()), - } - } - - /// Wakes up one blocked thread on this condvar. - /// - /// Returns whether a thread was woken up. - /// - /// If there is a blocked thread on this condition variable, then it will - /// be woken up from its call to `wait` or `wait_timeout`. Calls to - /// `notify_one` are not buffered in any way. - /// - /// To wake up all threads, see `notify_all()`. - /// - /// # Examples - /// - /// ``` - /// use parking_lot::Condvar; - /// - /// let condvar = Condvar::new(); - /// - /// // do something with condvar, share it with other threads - /// - /// if !condvar.notify_one() { - /// println!("Nobody was listening for this."); - /// } - /// ``` - #[inline] - pub fn notify_one(&self) -> bool { - // Nothing to do if there are no waiting threads - let state = self.state.load(Ordering::Relaxed); - if state.is_null() { - return false; - } - - self.notify_one_slow(state) - } - - #[cold] - fn notify_one_slow(&self, mutex: *mut RawMutex) -> bool { - unsafe { - // Unpark one thread and requeue the rest onto the mutex - let from = self as *const _ as usize; - let to = mutex as usize; - let validate = || { - // Make sure that our atomic state still points to the same - // mutex. If not then it means that all threads on the current - // mutex were woken up and a new waiting thread switched to a - // different mutex. In that case we can get away with doing - // nothing. - if self.state.load(Ordering::Relaxed) != mutex { - return RequeueOp::Abort; - } - - // Unpark one thread if the mutex is unlocked, otherwise just - // requeue everything to the mutex. This is safe to do here - // since unlocking the mutex when the parked bit is set requires - // locking the queue. There is the possibility of a race if the - // mutex gets locked after we check, but that doesn't matter in - // this case. - if (*mutex).mark_parked_if_locked() { - RequeueOp::RequeueOne - } else { - RequeueOp::UnparkOne - } - }; - let callback = |_op, result: UnparkResult| { - // Clear our state if there are no more waiting threads - if !result.have_more_threads { - self.state.store(ptr::null_mut(), Ordering::Relaxed); - } - TOKEN_NORMAL - }; - let res = parking_lot_core::unpark_requeue(from, to, validate, callback); - - res.unparked_threads + res.requeued_threads != 0 - } - } - - /// Wakes up all blocked threads on this condvar. - /// - /// Returns the number of threads woken up. - /// - /// This method will ensure that any current waiters on the condition - /// variable are awoken. Calls to `notify_all()` are not buffered in any - /// way. - /// - /// To wake up only one thread, see `notify_one()`. - #[inline] - pub fn notify_all(&self) -> usize { - // Nothing to do if there are no waiting threads - let state = self.state.load(Ordering::Relaxed); - if state.is_null() { - return 0; - } - - self.notify_all_slow(state) - } - - #[cold] - fn notify_all_slow(&self, mutex: *mut RawMutex) -> usize { - unsafe { - // Unpark one thread and requeue the rest onto the mutex - let from = self as *const _ as usize; - let to = mutex as usize; - let validate = || { - // Make sure that our atomic state still points to the same - // mutex. If not then it means that all threads on the current - // mutex were woken up and a new waiting thread switched to a - // different mutex. In that case we can get away with doing - // nothing. - if self.state.load(Ordering::Relaxed) != mutex { - return RequeueOp::Abort; - } - - // Clear our state since we are going to unpark or requeue all - // threads. - self.state.store(ptr::null_mut(), Ordering::Relaxed); - - // Unpark one thread if the mutex is unlocked, otherwise just - // requeue everything to the mutex. This is safe to do here - // since unlocking the mutex when the parked bit is set requires - // locking the queue. There is the possibility of a race if the - // mutex gets locked after we check, but that doesn't matter in - // this case. - if (*mutex).mark_parked_if_locked() { - RequeueOp::RequeueAll - } else { - RequeueOp::UnparkOneRequeueRest - } - }; - let callback = |op, result: UnparkResult| { - // If we requeued threads to the mutex, mark it as having - // parked threads. The RequeueAll case is already handled above. - if op == RequeueOp::UnparkOneRequeueRest && result.requeued_threads != 0 { - (*mutex).mark_parked(); - } - TOKEN_NORMAL - }; - let res = parking_lot_core::unpark_requeue(from, to, validate, callback); - - res.unparked_threads + res.requeued_threads - } - } - - /// Blocks the current thread until this condition variable receives a - /// notification. - /// - /// This function will atomically unlock the mutex specified (represented by - /// `mutex_guard`) and block the current thread. This means that any calls - /// to `notify_*()` which happen logically after the mutex is unlocked are - /// candidates to wake this thread up. When this function call returns, the - /// lock specified will have been re-acquired. - /// - /// # Panics - /// - /// This function will panic if another thread is waiting on the `Condvar` - /// with a different `Mutex` object. - #[inline] - pub fn wait(&self, mutex_guard: &mut MutexGuard<'_, T>) { - self.wait_until_internal(unsafe { MutexGuard::mutex(mutex_guard).raw() }, None); - } - - /// Waits on this condition variable for a notification, timing out after - /// the specified time instant. - /// - /// The semantics of this function are equivalent to `wait()` except that - /// the thread will be blocked roughly until `timeout` is reached. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `timeout`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned `WaitTimeoutResult` value indicates if the timeout is - /// known to have elapsed. - /// - /// Like `wait`, the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// # Panics - /// - /// This function will panic if another thread is waiting on the `Condvar` - /// with a different `Mutex` object. - #[inline] - pub fn wait_until( - &self, - mutex_guard: &mut MutexGuard<'_, T>, - timeout: Instant, - ) -> WaitTimeoutResult { - self.wait_until_internal( - unsafe { MutexGuard::mutex(mutex_guard).raw() }, - Some(timeout), - ) - } - - // This is a non-generic function to reduce the monomorphization cost of - // using `wait_until`. - fn wait_until_internal(&self, mutex: &RawMutex, timeout: Option) -> WaitTimeoutResult { - unsafe { - let result; - let mut bad_mutex = false; - let mut requeued = false; - { - let addr = self as *const _ as usize; - let lock_addr = mutex as *const _ as *mut _; - let validate = || { - // Ensure we don't use two different mutexes with the same - // Condvar at the same time. This is done while locked to - // avoid races with notify_one - let state = self.state.load(Ordering::Relaxed); - if state.is_null() { - self.state.store(lock_addr, Ordering::Relaxed); - } else if state != lock_addr { - bad_mutex = true; - return false; - } - true - }; - let before_sleep = || { - // Unlock the mutex before sleeping... - mutex.unlock(); - }; - let timed_out = |k, was_last_thread| { - // If we were requeued to a mutex, then we did not time out. - // We'll just park ourselves on the mutex again when we try - // to lock it later. - requeued = k != addr; - - // If we were the last thread on the queue then we need to - // clear our state. This is normally done by the - // notify_{one,all} functions when not timing out. - if !requeued && was_last_thread { - self.state.store(ptr::null_mut(), Ordering::Relaxed); - } - }; - result = parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - timeout, - ); - } - - // Panic if we tried to use multiple mutexes with a Condvar. Note - // that at this point the MutexGuard is still locked. It will be - // unlocked by the unwinding logic. - if bad_mutex { - panic!("attempted to use a condition variable with more than one mutex"); - } - - // ... and re-lock it once we are done sleeping - if result == ParkResult::Unparked(TOKEN_HANDOFF) { - deadlock::acquire_resource(mutex as *const _ as usize); - } else { - mutex.lock(); - } - - WaitTimeoutResult(!(result.is_unparked() || requeued)) - } - } - - /// Waits on this condition variable for a notification, timing out after a - /// specified duration. - /// - /// The semantics of this function are equivalent to `wait()` except that - /// the thread will be blocked for roughly no longer than `timeout`. This - /// method should not be used for precise timing due to anomalies such as - /// preemption or platform differences that may not cause the maximum - /// amount of time waited to be precisely `timeout`. - /// - /// Note that the best effort is made to ensure that the time waited is - /// measured with a monotonic clock, and not affected by the changes made to - /// the system time. - /// - /// The returned `WaitTimeoutResult` value indicates if the timeout is - /// known to have elapsed. - /// - /// Like `wait`, the lock specified will be re-acquired when this function - /// returns, regardless of whether the timeout elapsed or not. - /// - /// # Panics - /// - /// Panics if the given `timeout` is so large that it can't be added to the current time. - /// This panic is not possible if the crate is built with the `nightly` feature, then a too - /// large `timeout` becomes equivalent to just calling `wait`. - #[inline] - pub fn wait_for( - &self, - mutex_guard: &mut MutexGuard<'_, T>, - timeout: Duration, - ) -> WaitTimeoutResult { - let deadline = util::to_deadline(timeout); - self.wait_until_internal(unsafe { MutexGuard::mutex(mutex_guard).raw() }, deadline) - } -} - -impl Default for Condvar { - #[inline] - fn default() -> Condvar { - Condvar::new() - } -} - -impl fmt::Debug for Condvar { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.pad("Condvar { .. }") - } -} - -#[cfg(test)] -mod tests { - use crate::{Condvar, Mutex, MutexGuard}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - use std::time::{Duration, Instant}; - - #[test] - fn smoke() { - let c = Condvar::new(); - c.notify_one(); - c.notify_all(); - } - - #[test] - fn notify_one() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - c.wait(&mut g); - } - - #[test] - fn notify_all() { - const N: usize = 10; - - let data = Arc::new((Mutex::new(0), Condvar::new())); - let (tx, rx) = channel(); - for _ in 0..N { - let data = data.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock(); - *cnt += 1; - if *cnt == N { - tx.send(()).unwrap(); - } - while *cnt != 0 { - cond.wait(&mut cnt); - } - tx.send(()).unwrap(); - }); - } - drop(tx); - - let &(ref lock, ref cond) = &*data; - rx.recv().unwrap(); - let mut cnt = lock.lock(); - *cnt = 0; - cond.notify_all(); - drop(cnt); - - for _ in 0..N { - rx.recv().unwrap(); - } - } - - #[test] - fn notify_one_return_true() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let _t = thread::spawn(move || { - let _g = m2.lock(); - assert!(c2.notify_one()); - }); - c.wait(&mut g); - } - - #[test] - fn notify_one_return_false() { - let m = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - - let _t = thread::spawn(move || { - let _g = m.lock(); - assert!(!c.notify_one()); - }); - } - - #[test] - fn notify_all_return() { - const N: usize = 10; - - let data = Arc::new((Mutex::new(0), Condvar::new())); - let (tx, rx) = channel(); - for _ in 0..N { - let data = data.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let &(ref lock, ref cond) = &*data; - let mut cnt = lock.lock(); - *cnt += 1; - if *cnt == N { - tx.send(()).unwrap(); - } - while *cnt != 0 { - cond.wait(&mut cnt); - } - tx.send(()).unwrap(); - }); - } - drop(tx); - - let &(ref lock, ref cond) = &*data; - rx.recv().unwrap(); - let mut cnt = lock.lock(); - *cnt = 0; - assert_eq!(cond.notify_all(), N); - drop(cnt); - - for _ in 0..N { - rx.recv().unwrap(); - } - - assert_eq!(cond.notify_all(), 0); - } - - #[test] - fn wait_for() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let no_timeout = c.wait_for(&mut g, Duration::from_millis(1)); - assert!(no_timeout.timed_out()); - - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - // Non-nightly panics on too large timeouts. Nightly treats it as indefinite wait. - let very_long_timeout = if cfg!(feature = "nightly") { - Duration::from_secs(u64::max_value()) - } else { - Duration::from_millis(u32::max_value() as u64) - }; - - let timeout_res = c.wait_for(&mut g, very_long_timeout); - assert!(!timeout_res.timed_out()); - - drop(g); - } - - #[test] - fn wait_until() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let no_timeout = c.wait_until(&mut g, Instant::now() + Duration::from_millis(1)); - assert!(no_timeout.timed_out()); - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - let timeout_res = c.wait_until( - &mut g, - Instant::now() + Duration::from_millis(u32::max_value() as u64), - ); - assert!(!timeout_res.timed_out()); - drop(g); - } - - #[test] - #[should_panic] - fn two_mutexes() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let m3 = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - // Make sure we don't leave the child thread dangling - struct PanicGuard<'a>(&'a Condvar); - impl<'a> Drop for PanicGuard<'a> { - fn drop(&mut self) { - self.0.notify_one(); - } - } - - let (tx, rx) = channel(); - let g = m.lock(); - let _t = thread::spawn(move || { - let mut g = m2.lock(); - tx.send(()).unwrap(); - c2.wait(&mut g); - }); - drop(g); - rx.recv().unwrap(); - let _g = m.lock(); - let _guard = PanicGuard(&*c); - c.wait(&mut m3.lock()); - } - - #[test] - fn two_mutexes_disjoint() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let m3 = Arc::new(Mutex::new(())); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - - let mut g = m.lock(); - let _t = thread::spawn(move || { - let _g = m2.lock(); - c2.notify_one(); - }); - c.wait(&mut g); - drop(g); - - let _ = c.wait_for(&mut m3.lock(), Duration::from_millis(1)); - } - - #[test] - fn test_debug_condvar() { - let c = Condvar::new(); - assert_eq!(format!("{:?}", c), "Condvar { .. }"); - } - - #[test] - fn test_condvar_requeue() { - let m = Arc::new(Mutex::new(())); - let m2 = m.clone(); - let c = Arc::new(Condvar::new()); - let c2 = c.clone(); - let t = thread::spawn(move || { - let mut g = m2.lock(); - c2.wait(&mut g); - }); - - let mut g = m.lock(); - while !c.notify_one() { - // Wait for the thread to get into wait() - MutexGuard::bump(&mut g); - } - // The thread should have been requeued to the mutex, which we wake up now. - drop(g); - t.join().unwrap(); - } - - #[test] - fn test_issue_129() { - let locks = Arc::new((Mutex::new(()), Condvar::new())); - - let (tx, rx) = channel(); - for _ in 0..4 { - let locks = locks.clone(); - let tx = tx.clone(); - thread::spawn(move || { - let mut guard = locks.0.lock(); - locks.1.wait(&mut guard); - locks.1.wait_for(&mut guard, Duration::from_millis(1)); - locks.1.notify_one(); - tx.send(()).unwrap(); - }); - } - - thread::sleep(Duration::from_millis(100)); - locks.1.notify_one(); - - for _ in 0..4 { - assert_eq!(rx.recv_timeout(Duration::from_millis(500)), Ok(())); - } - } -} - -/// This module contains an integration test that is heavily inspired from WebKit's own integration -/// tests for it's own Condvar. -#[cfg(test)] -mod webkit_queue_test { - use crate::{Condvar, Mutex, MutexGuard}; - use std::{collections::VecDeque, sync::Arc, thread, time::Duration}; - - #[derive(Clone, Copy)] - enum Timeout { - Bounded(Duration), - Forever, - } - - #[derive(Clone, Copy)] - enum NotifyStyle { - One, - All, - } - - struct Queue { - items: VecDeque, - should_continue: bool, - } - - impl Queue { - fn new() -> Self { - Self { - items: VecDeque::new(), - should_continue: true, - } - } - } - - fn wait( - condition: &Condvar, - lock: &mut MutexGuard<'_, T>, - predicate: impl Fn(&mut MutexGuard<'_, T>) -> bool, - timeout: &Timeout, - ) { - while !predicate(lock) { - match timeout { - Timeout::Forever => condition.wait(lock), - Timeout::Bounded(bound) => { - condition.wait_for(lock, *bound); - } - } - } - } - - fn notify(style: NotifyStyle, condition: &Condvar, should_notify: bool) { - match style { - NotifyStyle::One => { - condition.notify_one(); - } - NotifyStyle::All => { - if should_notify { - condition.notify_all(); - } - } - } - } - - fn run_queue_test( - num_producers: usize, - num_consumers: usize, - max_queue_size: usize, - messages_per_producer: usize, - notify_style: NotifyStyle, - timeout: Timeout, - delay: Duration, - ) { - let input_queue = Arc::new(Mutex::new(Queue::new())); - let empty_condition = Arc::new(Condvar::new()); - let full_condition = Arc::new(Condvar::new()); - - let output_vec = Arc::new(Mutex::new(vec![])); - - let consumers = (0..num_consumers) - .map(|_| { - consumer_thread( - input_queue.clone(), - empty_condition.clone(), - full_condition.clone(), - timeout, - notify_style, - output_vec.clone(), - max_queue_size, - ) - }) - .collect::>(); - let producers = (0..num_producers) - .map(|_| { - producer_thread( - messages_per_producer, - input_queue.clone(), - empty_condition.clone(), - full_condition.clone(), - timeout, - notify_style, - max_queue_size, - ) - }) - .collect::>(); - - thread::sleep(delay); - - for producer in producers.into_iter() { - producer.join().expect("Producer thread panicked"); - } - - { - let mut input_queue = input_queue.lock(); - input_queue.should_continue = false; - } - empty_condition.notify_all(); - - for consumer in consumers.into_iter() { - consumer.join().expect("Consumer thread panicked"); - } - - let mut output_vec = output_vec.lock(); - assert_eq!(output_vec.len(), num_producers * messages_per_producer); - output_vec.sort(); - for msg_idx in 0..messages_per_producer { - for producer_idx in 0..num_producers { - assert_eq!(msg_idx, output_vec[msg_idx * num_producers + producer_idx]); - } - } - } - - fn consumer_thread( - input_queue: Arc>, - empty_condition: Arc, - full_condition: Arc, - timeout: Timeout, - notify_style: NotifyStyle, - output_queue: Arc>>, - max_queue_size: usize, - ) -> thread::JoinHandle<()> { - thread::spawn(move || loop { - let (should_notify, result) = { - let mut queue = input_queue.lock(); - wait( - &*empty_condition, - &mut queue, - |state| -> bool { !state.items.is_empty() || !state.should_continue }, - &timeout, - ); - if queue.items.is_empty() && !queue.should_continue { - return; - } - let should_notify = queue.items.len() == max_queue_size; - let result = queue.items.pop_front(); - std::mem::drop(queue); - (should_notify, result) - }; - notify(notify_style, &*full_condition, should_notify); - - if let Some(result) = result { - output_queue.lock().push(result); - } - }) - } - - fn producer_thread( - num_messages: usize, - queue: Arc>, - empty_condition: Arc, - full_condition: Arc, - timeout: Timeout, - notify_style: NotifyStyle, - max_queue_size: usize, - ) -> thread::JoinHandle<()> { - thread::spawn(move || { - for message in 0..num_messages { - let should_notify = { - let mut queue = queue.lock(); - wait( - &*full_condition, - &mut queue, - |state| state.items.len() < max_queue_size, - &timeout, - ); - let should_notify = queue.items.is_empty(); - queue.items.push_back(message); - std::mem::drop(queue); - should_notify - }; - notify(notify_style, &*empty_condition, should_notify); - } - }) - } - - macro_rules! run_queue_tests { - ( $( $name:ident( - num_producers: $num_producers:expr, - num_consumers: $num_consumers:expr, - max_queue_size: $max_queue_size:expr, - messages_per_producer: $messages_per_producer:expr, - notification_style: $notification_style:expr, - timeout: $timeout:expr, - delay_seconds: $delay_seconds:expr); - )* ) => { - $(#[test] - fn $name() { - let delay = Duration::from_secs($delay_seconds); - run_queue_test( - $num_producers, - $num_consumers, - $max_queue_size, - $messages_per_producer, - $notification_style, - $timeout, - delay, - ); - })* - }; - } - - run_queue_tests! { - sanity_check_queue( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Bounded(Duration::from_secs(1)), - delay_seconds: 0 - ); - sanity_check_queue_timeout( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - new_test_without_timeout_5( - num_producers: 1, - num_consumers: 5, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_one_consumer_one_slot( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_one_consumer_one_slot_timeout( - num_producers: 1, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 1 - ); - one_producer_one_consumer_hundred_slots( - num_producers: 1, - num_consumers: 1, - max_queue_size: 100, - messages_per_producer: 1_000_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_one_consumer_one_slot( - num_producers: 10, - num_consumers: 1, - max_queue_size: 1, - messages_per_producer: 10000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_one_consumer_hundred_slots_notify_all( - num_producers: 10, - num_consumers: 1, - max_queue_size: 100, - messages_per_producer: 10000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_one_consumer_hundred_slots_notify_one( - num_producers: 10, - num_consumers: 1, - max_queue_size: 100, - messages_per_producer: 10000, - notification_style: NotifyStyle::One, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_ten_consumers_one_slot( - num_producers: 1, - num_consumers: 10, - max_queue_size: 1, - messages_per_producer: 10000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_ten_consumers_hundred_slots_notify_all( - num_producers: 1, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 100_000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - one_producer_ten_consumers_hundred_slots_notify_one( - num_producers: 1, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 100_000, - notification_style: NotifyStyle::One, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_ten_consumers_one_slot( - num_producers: 10, - num_consumers: 10, - max_queue_size: 1, - messages_per_producer: 50000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_ten_consumers_hundred_slots_notify_all( - num_producers: 10, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 50000, - notification_style: NotifyStyle::All, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - ten_producers_ten_consumers_hundred_slots_notify_one( - num_producers: 10, - num_consumers: 10, - max_queue_size: 100, - messages_per_producer: 50000, - notification_style: NotifyStyle::One, - timeout: Timeout::Forever, - delay_seconds: 0 - ); - } -} diff --git a/vendor/parking_lot-0.10.2/src/deadlock.rs b/vendor/parking_lot-0.10.2/src/deadlock.rs deleted file mode 100644 index 0fab7228c9..0000000000 --- a/vendor/parking_lot-0.10.2/src/deadlock.rs +++ /dev/null @@ -1,232 +0,0 @@ -//! \[Experimental\] Deadlock detection -//! -//! This feature is optional and can be enabled via the `deadlock_detection` feature flag. -//! -//! # Example -//! -//! ``` -//! #[cfg(feature = "deadlock_detection")] -//! { // only for #[cfg] -//! use std::thread; -//! use std::time::Duration; -//! use parking_lot::deadlock; -//! -//! // Create a background thread which checks for deadlocks every 10s -//! thread::spawn(move || { -//! loop { -//! thread::sleep(Duration::from_secs(10)); -//! let deadlocks = deadlock::check_deadlock(); -//! if deadlocks.is_empty() { -//! continue; -//! } -//! -//! println!("{} deadlocks detected", deadlocks.len()); -//! for (i, threads) in deadlocks.iter().enumerate() { -//! println!("Deadlock #{}", i); -//! for t in threads { -//! println!("Thread Id {:#?}", t.thread_id()); -//! println!("{:#?}", t.backtrace()); -//! } -//! } -//! } -//! }); -//! } // only for #[cfg] -//! ``` - -#[cfg(feature = "deadlock_detection")] -pub use parking_lot_core::deadlock::check_deadlock; -pub(crate) use parking_lot_core::deadlock::{acquire_resource, release_resource}; - -#[cfg(test)] -#[cfg(feature = "deadlock_detection")] -mod tests { - use crate::{Mutex, ReentrantMutex, RwLock}; - use std::sync::{Arc, Barrier}; - use std::thread::{self, sleep}; - use std::time::Duration; - - // We need to serialize these tests since deadlock detection uses global state - static DEADLOCK_DETECTION_LOCK: Mutex<()> = crate::const_mutex(()); - - fn check_deadlock() -> bool { - use parking_lot_core::deadlock::check_deadlock; - !check_deadlock().is_empty() - } - - #[test] - fn test_mutex_deadlock() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - let m2: Arc> = Default::default(); - let m3: Arc> = Default::default(); - let b = Arc::new(Barrier::new(4)); - - let m1_ = m1.clone(); - let m2_ = m2.clone(); - let m3_ = m3.clone(); - let b1 = b.clone(); - let b2 = b.clone(); - let b3 = b.clone(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.lock(); - b1.wait(); - let _ = m2_.lock(); - }); - - let _t2 = thread::spawn(move || { - let _g = m2.lock(); - b2.wait(); - let _ = m3_.lock(); - }); - - let _t3 = thread::spawn(move || { - let _g = m3.lock(); - b3.wait(); - let _ = m1_.lock(); - }); - - assert!(!check_deadlock()); - - b.wait(); - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[test] - fn test_mutex_deadlock_reentrant() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.lock(); - let _ = m1.lock(); - }); - - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[test] - fn test_remutex_deadlock() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - let m2: Arc> = Default::default(); - let m3: Arc> = Default::default(); - let b = Arc::new(Barrier::new(4)); - - let m1_ = m1.clone(); - let m2_ = m2.clone(); - let m3_ = m3.clone(); - let b1 = b.clone(); - let b2 = b.clone(); - let b3 = b.clone(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.lock(); - let _g = m1.lock(); - b1.wait(); - let _ = m2_.lock(); - }); - - let _t2 = thread::spawn(move || { - let _g = m2.lock(); - let _g = m2.lock(); - b2.wait(); - let _ = m3_.lock(); - }); - - let _t3 = thread::spawn(move || { - let _g = m3.lock(); - let _g = m3.lock(); - b3.wait(); - let _ = m1_.lock(); - }); - - assert!(!check_deadlock()); - - b.wait(); - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[test] - fn test_rwlock_deadlock() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - let m2: Arc> = Default::default(); - let m3: Arc> = Default::default(); - let b = Arc::new(Barrier::new(4)); - - let m1_ = m1.clone(); - let m2_ = m2.clone(); - let m3_ = m3.clone(); - let b1 = b.clone(); - let b2 = b.clone(); - let b3 = b.clone(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.read(); - b1.wait(); - let _g = m2_.write(); - }); - - let _t2 = thread::spawn(move || { - let _g = m2.read(); - b2.wait(); - let _g = m3_.write(); - }); - - let _t3 = thread::spawn(move || { - let _g = m3.read(); - b3.wait(); - let _ = m1_.write(); - }); - - assert!(!check_deadlock()); - - b.wait(); - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } - - #[cfg(rwlock_deadlock_detection_not_supported)] - #[test] - fn test_rwlock_deadlock_reentrant() { - let _guard = DEADLOCK_DETECTION_LOCK.lock(); - - let m1: Arc> = Default::default(); - - assert!(!check_deadlock()); - - let _t1 = thread::spawn(move || { - let _g = m1.read(); - let _ = m1.write(); - }); - - sleep(Duration::from_millis(50)); - assert!(check_deadlock()); - - assert!(!check_deadlock()); - } -} diff --git a/vendor/parking_lot-0.10.2/src/elision.rs b/vendor/parking_lot-0.10.2/src/elision.rs deleted file mode 100644 index 68cfa63c3e..0000000000 --- a/vendor/parking_lot-0.10.2/src/elision.rs +++ /dev/null @@ -1,116 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use std::sync::atomic::AtomicUsize; - -// Extension trait to add lock elision primitives to atomic types -pub trait AtomicElisionExt { - type IntType; - - // Perform a compare_exchange and start a transaction - fn elision_compare_exchange_acquire( - &self, - current: Self::IntType, - new: Self::IntType, - ) -> Result; - - // Perform a fetch_sub and end a transaction - fn elision_fetch_sub_release(&self, val: Self::IntType) -> Self::IntType; -} - -// Indicates whether the target architecture supports lock elision -#[inline] -pub fn have_elision() -> bool { - cfg!(all( - feature = "nightly", - any(target_arch = "x86", target_arch = "x86_64"), - )) -} - -// This implementation is never actually called because it is guarded by -// have_elision(). -#[cfg(not(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64"))))] -impl AtomicElisionExt for AtomicUsize { - type IntType = usize; - - #[inline] - fn elision_compare_exchange_acquire(&self, _: usize, _: usize) -> Result { - unreachable!(); - } - - #[inline] - fn elision_fetch_sub_release(&self, _: usize) -> usize { - unreachable!(); - } -} - -#[cfg(all(feature = "nightly", any(target_arch = "x86", target_arch = "x86_64")))] -impl AtomicElisionExt for AtomicUsize { - type IntType = usize; - - #[cfg(target_pointer_width = "32")] - #[inline] - fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result { - unsafe { - let prev: usize; - llvm_asm!("xacquire; lock; cmpxchgl $2, $1" - : "={eax}" (prev), "+*m" (self) - : "r" (new), "{eax}" (current) - : "memory" - : "volatile"); - if prev == current { - Ok(prev) - } else { - Err(prev) - } - } - } - #[cfg(target_pointer_width = "64")] - #[inline] - fn elision_compare_exchange_acquire(&self, current: usize, new: usize) -> Result { - unsafe { - let prev: usize; - llvm_asm!("xacquire; lock; cmpxchgq $2, $1" - : "={rax}" (prev), "+*m" (self) - : "r" (new), "{rax}" (current) - : "memory" - : "volatile"); - if prev == current { - Ok(prev) - } else { - Err(prev) - } - } - } - - #[cfg(target_pointer_width = "32")] - #[inline] - fn elision_fetch_sub_release(&self, val: usize) -> usize { - unsafe { - let prev: usize; - llvm_asm!("xrelease; lock; xaddl $2, $1" - : "=r" (prev), "+*m" (self) - : "0" (val.wrapping_neg()) - : "memory" - : "volatile"); - prev - } - } - #[cfg(target_pointer_width = "64")] - #[inline] - fn elision_fetch_sub_release(&self, val: usize) -> usize { - unsafe { - let prev: usize; - llvm_asm!("xrelease; lock; xaddq $2, $1" - : "=r" (prev), "+*m" (self) - : "0" (val.wrapping_neg()) - : "memory" - : "volatile"); - prev - } - } -} diff --git a/vendor/parking_lot-0.10.2/src/fair_mutex.rs b/vendor/parking_lot-0.10.2/src/fair_mutex.rs deleted file mode 100644 index 449c53b051..0000000000 --- a/vendor/parking_lot-0.10.2/src/fair_mutex.rs +++ /dev/null @@ -1,278 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::raw_fair_mutex::RawFairMutex; -use lock_api; - -/// A mutual exclusive primitive that is always fair, useful for protecting shared data -/// -/// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a `new` -/// constructor. Each mutex has a type parameter which represents the data that -/// it is protecting. The data can only be accessed through the RAII guards -/// returned from `lock` and `try_lock`, which guarantees that the data is only -/// ever accessed when the mutex is locked. -/// -/// The regular mutex provided by `parking_lot` uses eventual locking fairness -/// (after some time it will default to the fair algorithm), but eventual -/// fairness does not provide the same garantees a always fair method would. -/// Fair mutexes are generally slower, but sometimes needed. This wrapper was -/// created to avoid using a unfair protocol when it's forbidden by mistake. -/// -/// In a fair mutex the lock is provided to whichever thread asked first, -/// they form a queue and always follow the first-in first-out order. This -/// means some thread in the queue won't be able to steal the lock and use it fast -/// to increase throughput, at the cost of latency. Since the response time will grow -/// for some threads that are waiting for the lock and losing to faster but later ones, -/// but it may make sending more responses possible. -/// -/// A fair mutex may not be interesting if threads have different priorities (this is known as -/// priority inversion). -/// -/// # Differences from the standard library `Mutex` -/// -/// - No poisoning, the lock is released normally on panic. -/// - Only requires 1 byte of space, whereas the standard library boxes the -/// `FairMutex` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// - Efficient handling of micro-contention using adaptive spinning. -/// - Allows raw locking & unlocking without a guard. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::FairMutex; -/// use std::sync::{Arc, mpsc::channel}; -/// use std::thread; -/// -/// const N: usize = 10; -/// -/// // Spawn a few threads to increment a shared variable (non-atomically), and -/// // let the main thread know once all increments are done. -/// // -/// // Here we're using an Arc to share memory among threads, and the data inside -/// // the Arc is protected with a mutex. -/// let data = Arc::new(FairMutex::new(0)); -/// -/// let (tx, rx) = channel(); -/// for _ in 0..10 { -/// let (data, tx) = (Arc::clone(&data), tx.clone()); -/// thread::spawn(move || { -/// // The shared state can only be accessed once the lock is held. -/// // Our non-atomic increment is safe because we're the only thread -/// // which can access the shared state when the lock is held. -/// let mut data = data.lock(); -/// *data += 1; -/// if *data == N { -/// tx.send(()).unwrap(); -/// } -/// // the lock is unlocked here when `data` goes out of scope. -/// }); -/// } -/// -/// rx.recv().unwrap(); -/// ``` -pub type FairMutex = lock_api::Mutex; - -/// Creates a new fair mutex in an unlocked state ready for use. -/// -/// This allows creating a fair mutex in a constant context on stable Rust. -pub const fn const_fair_mutex(val: T) -> FairMutex { - FairMutex::const_new(::INIT, val) -} - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// `Deref` and `DerefMut` implementations. -pub type FairMutexGuard<'a, T> = lock_api::MutexGuard<'a, RawFairMutex, T>; - -/// An RAII mutex guard returned by `FairMutexGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedFairMutexGuard` and `FairMutexGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedFairMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawFairMutex, T>; - -#[cfg(test)] -mod tests { - use crate::FairMutex; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let m = FairMutex::new(()); - drop(m.lock()); - drop(m.lock()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(FairMutex::new(0)); - - fn inc(m: &FairMutex) { - for _ in 0..J { - *m.lock() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = FairMutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = FairMutex::new(NonCopy(10)); - assert_eq!(m.into_inner(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = FairMutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_get_mut() { - let mut m = FairMutex::new(NonCopy(10)); - *m.get_mut() = NonCopy(20); - assert_eq!(m.into_inner(), NonCopy(20)); - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(FairMutex::new(1)); - let arc2 = Arc::new(FairMutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let lock = arc2.lock(); - let lock2 = lock.lock(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(FairMutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.lock(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &FairMutex<[i32]> = &FairMutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock(), comp); - } - - #[test] - fn test_mutexguard_sync() { - fn sync(_: T) {} - - let mutex = FairMutex::new(()); - sync(mutex.lock()); - } - - #[test] - fn test_mutex_debug() { - let mutex = FairMutex::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }"); - let _lock = mutex.lock(); - assert_eq!(format!("{:?}", mutex), "Mutex { data: }"); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = FairMutex::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: FairMutex> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.lock()), *(deserialized.lock())); - assert_eq!(contents, *(deserialized.lock())); - } -} diff --git a/vendor/parking_lot-0.10.2/src/lib.rs b/vendor/parking_lot-0.10.2/src/lib.rs deleted file mode 100644 index 73246c2e76..0000000000 --- a/vendor/parking_lot-0.10.2/src/lib.rs +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -//! This library provides implementations of `Mutex`, `RwLock`, `Condvar` and -//! `Once` that are smaller, faster and more flexible than those in the Rust -//! standard library. It also provides a `ReentrantMutex` type. - -#![warn(missing_docs)] -#![warn(rust_2018_idioms)] -#![cfg_attr(feature = "nightly", feature(llvm_asm))] - -mod condvar; -mod elision; -mod fair_mutex; -mod mutex; -mod once; -mod raw_fair_mutex; -mod raw_mutex; -mod raw_rwlock; -mod remutex; -mod rwlock; -mod util; - -#[cfg(feature = "deadlock_detection")] -pub mod deadlock; -#[cfg(not(feature = "deadlock_detection"))] -mod deadlock; - -pub use self::condvar::{Condvar, WaitTimeoutResult}; -pub use self::fair_mutex::{const_fair_mutex, FairMutex, FairMutexGuard, MappedFairMutexGuard}; -pub use self::mutex::{const_mutex, MappedMutexGuard, Mutex, MutexGuard}; -pub use self::once::{Once, OnceState}; -pub use self::raw_fair_mutex::RawFairMutex; -pub use self::raw_mutex::RawMutex; -pub use self::raw_rwlock::RawRwLock; -pub use self::remutex::{ - const_reentrant_mutex, MappedReentrantMutexGuard, RawThreadId, ReentrantMutex, - ReentrantMutexGuard, -}; -pub use self::rwlock::{ - const_rwlock, MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, - RwLockUpgradableReadGuard, RwLockWriteGuard, -}; -pub use ::lock_api; diff --git a/vendor/parking_lot-0.10.2/src/mutex.rs b/vendor/parking_lot-0.10.2/src/mutex.rs deleted file mode 100644 index 36e5ea7ec5..0000000000 --- a/vendor/parking_lot-0.10.2/src/mutex.rs +++ /dev/null @@ -1,312 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::raw_mutex::RawMutex; -use lock_api; - -/// A mutual exclusion primitive useful for protecting shared data -/// -/// This mutex will block threads waiting for the lock to become available. The -/// mutex can also be statically initialized or created via a `new` -/// constructor. Each mutex has a type parameter which represents the data that -/// it is protecting. The data can only be accessed through the RAII guards -/// returned from `lock` and `try_lock`, which guarantees that the data is only -/// ever accessed when the mutex is locked. -/// -/// # Fairness -/// -/// A typical unfair lock can often end up in a situation where a single thread -/// quickly acquires and releases the same mutex in succession, which can starve -/// other threads waiting to acquire the mutex. While this improves performance -/// because it doesn't force a context switch when a thread tries to re-acquire -/// a mutex it has just released, this can starve other threads. -/// -/// This mutex uses [eventual fairness](https://trac.webkit.org/changeset/203350) -/// to ensure that the lock will be fair on average without sacrificing -/// performance. This is done by forcing a fair unlock on average every 0.5ms, -/// which will force the lock to go to the next thread waiting for the mutex. -/// -/// Additionally, any critical section longer than 1ms will always use a fair -/// unlock, which has a negligible performance impact compared to the length of -/// the critical section. -/// -/// You can also force a fair unlock by calling `MutexGuard::unlock_fair` when -/// unlocking a mutex instead of simply dropping the `MutexGuard`. -/// -/// # Differences from the standard library `Mutex` -/// -/// - No poisoning, the lock is released normally on panic. -/// - Only requires 1 byte of space, whereas the standard library boxes the -/// `Mutex` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// - Efficient handling of micro-contention using adaptive spinning. -/// - Allows raw locking & unlocking without a guard. -/// - Supports eventual fairness so that the mutex is fair on average. -/// - Optionally allows making the mutex fair by calling `MutexGuard::unlock_fair`. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::Mutex; -/// use std::sync::{Arc, mpsc::channel}; -/// use std::thread; -/// -/// const N: usize = 10; -/// -/// // Spawn a few threads to increment a shared variable (non-atomically), and -/// // let the main thread know once all increments are done. -/// // -/// // Here we're using an Arc to share memory among threads, and the data inside -/// // the Arc is protected with a mutex. -/// let data = Arc::new(Mutex::new(0)); -/// -/// let (tx, rx) = channel(); -/// for _ in 0..10 { -/// let (data, tx) = (Arc::clone(&data), tx.clone()); -/// thread::spawn(move || { -/// // The shared state can only be accessed once the lock is held. -/// // Our non-atomic increment is safe because we're the only thread -/// // which can access the shared state when the lock is held. -/// let mut data = data.lock(); -/// *data += 1; -/// if *data == N { -/// tx.send(()).unwrap(); -/// } -/// // the lock is unlocked here when `data` goes out of scope. -/// }); -/// } -/// -/// rx.recv().unwrap(); -/// ``` -pub type Mutex = lock_api::Mutex; - -/// Creates a new mutex in an unlocked state ready for use. -/// -/// This allows creating a mutex in a constant context on stable Rust. -pub const fn const_mutex(val: T) -> Mutex { - Mutex::const_new(::INIT, val) -} - -/// An RAII implementation of a "scoped lock" of a mutex. When this structure is -/// dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// `Deref` and `DerefMut` implementations. -pub type MutexGuard<'a, T> = lock_api::MutexGuard<'a, RawMutex, T>; - -/// An RAII mutex guard returned by `MutexGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedMutexGuard` and `MutexGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedMutexGuard<'a, T> = lock_api::MappedMutexGuard<'a, RawMutex, T>; - -#[cfg(test)] -mod tests { - use crate::{Condvar, Mutex}; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - struct Packet(Arc<(Mutex, Condvar)>); - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - unsafe impl Send for Packet {} - unsafe impl Sync for Packet {} - - #[test] - fn smoke() { - let m = Mutex::new(()); - drop(m.lock()); - drop(m.lock()); - } - - #[test] - fn lots_and_lots() { - const J: u32 = 1000; - const K: u32 = 3; - - let m = Arc::new(Mutex::new(0)); - - fn inc(m: &Mutex) { - for _ in 0..J { - *m.lock() += 1; - } - } - - let (tx, rx) = channel(); - for _ in 0..K { - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - let tx2 = tx.clone(); - let m2 = m.clone(); - thread::spawn(move || { - inc(&m2); - tx2.send(()).unwrap(); - }); - } - - drop(tx); - for _ in 0..2 * K { - rx.recv().unwrap(); - } - assert_eq!(*m.lock(), J * K * 2); - } - - #[test] - fn try_lock() { - let m = Mutex::new(()); - *m.try_lock().unwrap() = (); - } - - #[test] - fn test_into_inner() { - let m = Mutex::new(NonCopy(10)); - assert_eq!(m.into_inner(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = Mutex::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_get_mut() { - let mut m = Mutex::new(NonCopy(10)); - *m.get_mut() = NonCopy(20); - assert_eq!(m.into_inner(), NonCopy(20)); - } - - #[test] - fn test_mutex_arc_condvar() { - let packet = Packet(Arc::new((Mutex::new(false), Condvar::new()))); - let packet2 = Packet(packet.0.clone()); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - // wait until parent gets in - rx.recv().unwrap(); - let &(ref lock, ref cvar) = &*packet2.0; - let mut lock = lock.lock(); - *lock = true; - cvar.notify_one(); - }); - - let &(ref lock, ref cvar) = &*packet.0; - let mut lock = lock.lock(); - tx.send(()).unwrap(); - assert!(!*lock); - while !*lock { - cvar.wait(&mut lock); - } - } - - #[test] - fn test_mutex_arc_nested() { - // Tests nested mutexes and access - // to underlying data. - let arc = Arc::new(Mutex::new(1)); - let arc2 = Arc::new(Mutex::new(arc)); - let (tx, rx) = channel(); - let _t = thread::spawn(move || { - let lock = arc2.lock(); - let lock2 = lock.lock(); - assert_eq!(*lock2, 1); - tx.send(()).unwrap(); - }); - rx.recv().unwrap(); - } - - #[test] - fn test_mutex_arc_access_in_unwind() { - let arc = Arc::new(Mutex::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - *self.i.lock() += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.lock(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_mutex_unsized() { - let mutex: &Mutex<[i32]> = &Mutex::new([1, 2, 3]); - { - let b = &mut *mutex.lock(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*mutex.lock(), comp); - } - - #[test] - fn test_mutexguard_sync() { - fn sync(_: T) {} - - let mutex = Mutex::new(()); - sync(mutex.lock()); - } - - #[test] - fn test_mutex_debug() { - let mutex = Mutex::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", mutex), "Mutex { data: [0, 10] }"); - let _lock = mutex.lock(); - assert_eq!(format!("{:?}", mutex), "Mutex { data: }"); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = Mutex::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: Mutex> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.lock()), *(deserialized.lock())); - assert_eq!(contents, *(deserialized.lock())); - } -} diff --git a/vendor/parking_lot-0.10.2/src/once.rs b/vendor/parking_lot-0.10.2/src/once.rs deleted file mode 100644 index f458c9c04b..0000000000 --- a/vendor/parking_lot-0.10.2/src/once.rs +++ /dev/null @@ -1,458 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::util::UncheckedOptionExt; -use core::{ - fmt, mem, - sync::atomic::{fence, AtomicU8, Ordering}, -}; -use parking_lot_core::{self, SpinWait, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN}; - -const DONE_BIT: u8 = 1; -const POISON_BIT: u8 = 2; -const LOCKED_BIT: u8 = 4; -const PARKED_BIT: u8 = 8; - -/// Current state of a `Once`. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum OnceState { - /// A closure has not been executed yet - New, - - /// A closure was executed but panicked. - Poisoned, - - /// A thread is currently executing a closure. - InProgress, - - /// A closure has completed successfully. - Done, -} - -impl OnceState { - /// Returns whether the associated `Once` has been poisoned. - /// - /// Once an initialization routine for a `Once` has panicked it will forever - /// indicate to future forced initialization routines that it is poisoned. - #[inline] - pub fn poisoned(self) -> bool { - match self { - OnceState::Poisoned => true, - _ => false, - } - } - - /// Returns whether the associated `Once` has successfully executed a - /// closure. - #[inline] - pub fn done(self) -> bool { - match self { - OnceState::Done => true, - _ => false, - } - } -} - -/// A synchronization primitive which can be used to run a one-time -/// initialization. Useful for one-time initialization for globals, FFI or -/// related functionality. -/// -/// # Differences from the standard library `Once` -/// -/// - Only requires 1 byte of space, instead of 1 word. -/// - Not required to be `'static`. -/// - Relaxed memory barriers in the fast path, which can significantly improve -/// performance on some architectures. -/// - Efficient handling of micro-contention using adaptive spinning. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::Once; -/// -/// static START: Once = Once::new(); -/// -/// START.call_once(|| { -/// // run initialization here -/// }); -/// ``` -pub struct Once(AtomicU8); - -impl Once { - /// Creates a new `Once` value. - #[inline] - pub const fn new() -> Once { - Once(AtomicU8::new(0)) - } - - /// Returns the current state of this `Once`. - #[inline] - pub fn state(&self) -> OnceState { - let state = self.0.load(Ordering::Acquire); - if state & DONE_BIT != 0 { - OnceState::Done - } else if state & LOCKED_BIT != 0 { - OnceState::InProgress - } else if state & POISON_BIT != 0 { - OnceState::Poisoned - } else { - OnceState::New - } - } - - /// Performs an initialization routine once and only once. The given closure - /// will be executed if this is the first time `call_once` has been called, - /// and otherwise the routine will *not* be invoked. - /// - /// This method will block the calling thread if another initialization - /// routine is currently running. - /// - /// When this function returns, it is guaranteed that some initialization - /// has run and completed (it may not be the closure specified). It is also - /// guaranteed that any memory writes performed by the executed closure can - /// be reliably observed by other threads at this point (there is a - /// happens-before relation between the closure and code executing after the - /// return). - /// - /// # Examples - /// - /// ``` - /// use parking_lot::Once; - /// - /// static mut VAL: usize = 0; - /// static INIT: Once = Once::new(); - /// - /// // Accessing a `static mut` is unsafe much of the time, but if we do so - /// // in a synchronized fashion (e.g. write once or read all) then we're - /// // good to go! - /// // - /// // This function will only call `expensive_computation` once, and will - /// // otherwise always return the value returned from the first invocation. - /// fn get_cached_val() -> usize { - /// unsafe { - /// INIT.call_once(|| { - /// VAL = expensive_computation(); - /// }); - /// VAL - /// } - /// } - /// - /// fn expensive_computation() -> usize { - /// // ... - /// # 2 - /// } - /// ``` - /// - /// # Panics - /// - /// The closure `f` will only be executed once if this is called - /// concurrently amongst many threads. If that closure panics, however, then - /// it will *poison* this `Once` instance, causing all future invocations of - /// `call_once` to also panic. - #[inline] - pub fn call_once(&self, f: F) - where - F: FnOnce(), - { - if self.0.load(Ordering::Acquire) == DONE_BIT { - return; - } - - let mut f = Some(f); - self.call_once_slow(false, &mut |_| unsafe { f.take().unchecked_unwrap()() }); - } - - /// Performs the same function as `call_once` except ignores poisoning. - /// - /// If this `Once` has been poisoned (some initialization panicked) then - /// this function will continue to attempt to call initialization functions - /// until one of them doesn't panic. - /// - /// The closure `f` is yielded a structure which can be used to query the - /// state of this `Once` (whether initialization has previously panicked or - /// not). - #[inline] - pub fn call_once_force(&self, f: F) - where - F: FnOnce(OnceState), - { - if self.0.load(Ordering::Acquire) == DONE_BIT { - return; - } - - let mut f = Some(f); - self.call_once_slow(true, &mut |state| unsafe { - f.take().unchecked_unwrap()(state) - }); - } - - // This is a non-generic function to reduce the monomorphization cost of - // using `call_once` (this isn't exactly a trivial or small implementation). - // - // Additionally, this is tagged with `#[cold]` as it should indeed be cold - // and it helps let LLVM know that calls to this function should be off the - // fast path. Essentially, this should help generate more straight line code - // in LLVM. - // - // Finally, this takes an `FnMut` instead of a `FnOnce` because there's - // currently no way to take an `FnOnce` and call it via virtual dispatch - // without some allocation overhead. - #[cold] - fn call_once_slow(&self, ignore_poison: bool, f: &mut dyn FnMut(OnceState)) { - let mut spinwait = SpinWait::new(); - let mut state = self.0.load(Ordering::Relaxed); - loop { - // If another thread called the closure, we're done - if state & DONE_BIT != 0 { - // An acquire fence is needed here since we didn't load the - // state with Ordering::Acquire. - fence(Ordering::Acquire); - return; - } - - // If the state has been poisoned and we aren't forcing, then panic - if state & POISON_BIT != 0 && !ignore_poison { - // Need the fence here as well for the same reason - fence(Ordering::Acquire); - panic!("Once instance has previously been poisoned"); - } - - // Grab the lock if it isn't locked, even if there is a queue on it. - // We also clear the poison bit since we are going to try running - // the closure again. - if state & LOCKED_BIT == 0 { - match self.0.compare_exchange_weak( - state, - (state | LOCKED_BIT) & !POISON_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(x) => state = x, - } - continue; - } - - // If there is no queue, try spinning a few times - if state & PARKED_BIT == 0 && spinwait.spin() { - state = self.0.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & PARKED_BIT == 0 { - if let Err(x) = self.0.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by the thread that owns the - // lock. - unsafe { - let addr = self as *const _ as usize; - let validate = || self.0.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT; - let before_sleep = || {}; - let timed_out = |_, _| unreachable!(); - parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - None, - ); - } - - // Loop back and check if the done bit was set - spinwait.reset(); - state = self.0.load(Ordering::Relaxed); - } - - struct PanicGuard<'a>(&'a Once); - impl<'a> Drop for PanicGuard<'a> { - fn drop(&mut self) { - // Mark the state as poisoned, unlock it and unpark all threads. - let once = self.0; - let state = once.0.swap(POISON_BIT, Ordering::Release); - if state & PARKED_BIT != 0 { - unsafe { - let addr = once as *const _ as usize; - parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN); - } - } - } - } - - // At this point we have the lock, so run the closure. Make sure we - // properly clean up if the closure panicks. - let guard = PanicGuard(self); - let once_state = if state & POISON_BIT != 0 { - OnceState::Poisoned - } else { - OnceState::New - }; - f(once_state); - mem::forget(guard); - - // Now unlock the state, set the done bit and unpark all threads - let state = self.0.swap(DONE_BIT, Ordering::Release); - if state & PARKED_BIT != 0 { - unsafe { - let addr = self as *const _ as usize; - parking_lot_core::unpark_all(addr, DEFAULT_UNPARK_TOKEN); - } - } - } -} - -impl Default for Once { - #[inline] - fn default() -> Once { - Once::new() - } -} - -impl fmt::Debug for Once { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - f.debug_struct("Once") - .field("state", &self.state()) - .finish() - } -} - -#[cfg(test)] -mod tests { - use crate::Once; - use std::panic; - use std::sync::mpsc::channel; - use std::thread; - - #[test] - fn smoke_once() { - static O: Once = Once::new(); - let mut a = 0; - O.call_once(|| a += 1); - assert_eq!(a, 1); - O.call_once(|| a += 1); - assert_eq!(a, 1); - } - - #[test] - fn stampede_once() { - static O: Once = Once::new(); - static mut RUN: bool = false; - - let (tx, rx) = channel(); - for _ in 0..10 { - let tx = tx.clone(); - thread::spawn(move || { - for _ in 0..4 { - thread::yield_now() - } - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - tx.send(()).unwrap(); - }); - } - - unsafe { - O.call_once(|| { - assert!(!RUN); - RUN = true; - }); - assert!(RUN); - } - - for _ in 0..10 { - rx.recv().unwrap(); - } - } - - #[test] - fn poison_bad() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // poisoning propagates - let t = panic::catch_unwind(|| { - O.call_once(|| {}); - }); - assert!(t.is_err()); - - // we can subvert poisoning, however - let mut called = false; - O.call_once_force(|p| { - called = true; - assert!(p.poisoned()) - }); - assert!(called); - - // once any success happens, we stop propagating the poison - O.call_once(|| {}); - } - - #[test] - fn wait_for_force_to_finish() { - static O: Once = Once::new(); - - // poison the once - let t = panic::catch_unwind(|| { - O.call_once(|| panic!()); - }); - assert!(t.is_err()); - - // make sure someone's waiting inside the once via a force - let (tx1, rx1) = channel(); - let (tx2, rx2) = channel(); - let t1 = thread::spawn(move || { - O.call_once_force(|p| { - assert!(p.poisoned()); - tx1.send(()).unwrap(); - rx2.recv().unwrap(); - }); - }); - - rx1.recv().unwrap(); - - // put another waiter on the once - let t2 = thread::spawn(|| { - let mut called = false; - O.call_once(|| { - called = true; - }); - assert!(!called); - }); - - tx2.send(()).unwrap(); - - assert!(t1.join().is_ok()); - assert!(t2.join().is_ok()); - } - - #[test] - fn test_once_debug() { - static O: Once = Once::new(); - - assert_eq!(format!("{:?}", O), "Once { state: New }"); - } -} diff --git a/vendor/parking_lot-0.10.2/src/raw_fair_mutex.rs b/vendor/parking_lot-0.10.2/src/raw_fair_mutex.rs deleted file mode 100644 index 3eb7ddb779..0000000000 --- a/vendor/parking_lot-0.10.2/src/raw_fair_mutex.rs +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::raw_mutex::RawMutex; -use lock_api::RawMutexFair; - -/// Raw fair mutex type backed by the parking lot. -pub struct RawFairMutex(RawMutex); - -unsafe impl lock_api::RawMutex for RawFairMutex { - const INIT: Self = RawFairMutex(::INIT); - - type GuardMarker = ::GuardMarker; - - #[inline] - fn lock(&self) { - self.0.lock() - } - - #[inline] - fn try_lock(&self) -> bool { - self.0.try_lock() - } - - #[inline] - fn unlock(&self) { - self.unlock_fair() - } -} - -unsafe impl lock_api::RawMutexFair for RawFairMutex { - #[inline] - fn unlock_fair(&self) { - self.0.unlock_fair() - } - - #[inline] - fn bump(&self) { - self.0.bump() - } -} - -unsafe impl lock_api::RawMutexTimed for RawFairMutex { - type Duration = ::Duration; - type Instant = ::Instant; - - #[inline] - fn try_lock_until(&self, timeout: Self::Instant) -> bool { - self.0.try_lock_until(timeout) - } - - #[inline] - fn try_lock_for(&self, timeout: Self::Duration) -> bool { - self.0.try_lock_for(timeout) - } -} diff --git a/vendor/parking_lot-0.10.2/src/raw_mutex.rs b/vendor/parking_lot-0.10.2/src/raw_mutex.rs deleted file mode 100644 index ee39c3bd96..0000000000 --- a/vendor/parking_lot-0.10.2/src/raw_mutex.rs +++ /dev/null @@ -1,325 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::{deadlock, util}; -use core::{ - sync::atomic::{AtomicU8, Ordering}, - time::Duration, -}; -use lock_api::{GuardNoSend, RawMutex as RawMutex_}; -use parking_lot_core::{self, ParkResult, SpinWait, UnparkResult, UnparkToken, DEFAULT_PARK_TOKEN}; -use std::time::Instant; - -// UnparkToken used to indicate that that the target thread should attempt to -// lock the mutex again as soon as it is unparked. -pub(crate) const TOKEN_NORMAL: UnparkToken = UnparkToken(0); - -// UnparkToken used to indicate that the mutex is being handed off to the target -// thread directly without unlocking it. -pub(crate) const TOKEN_HANDOFF: UnparkToken = UnparkToken(1); - -/// This bit is set in the `state` of a `RawMutex` when that mutex is locked by some thread. -const LOCKED_BIT: u8 = 0b01; -/// This bit is set in the `state` of a `RawMutex` just before parking a thread. A thread is being -/// parked if it wants to lock the mutex, but it is currently being held by some other thread. -const PARKED_BIT: u8 = 0b10; - -/// Raw mutex type backed by the parking lot. -pub struct RawMutex { - /// This atomic integer holds the current state of the mutex instance. Only the two lowest bits - /// are used. See `LOCKED_BIT` and `PARKED_BIT` for the bitmask for these bits. - /// - /// # State table: - /// - /// PARKED_BIT | LOCKED_BIT | Description - /// 0 | 0 | The mutex is not locked, nor is anyone waiting for it. - /// -----------+------------+------------------------------------------------------------------ - /// 0 | 1 | The mutex is locked by exactly one thread. No other thread is - /// | | waiting for it. - /// -----------+------------+------------------------------------------------------------------ - /// 1 | 0 | The mutex is not locked. One or more thread is parked or about to - /// | | park. At least one of the parked threads are just about to be - /// | | unparked, or a thread heading for parking might abort the park. - /// -----------+------------+------------------------------------------------------------------ - /// 1 | 1 | The mutex is locked by exactly one thread. One or more thread is - /// | | parked or about to park, waiting for the lock to become available. - /// | | In this state, PARKED_BIT is only ever cleared when a bucket lock - /// | | is held (i.e. in a parking_lot_core callback). This ensures that - /// | | we never end up in a situation where there are parked threads but - /// | | PARKED_BIT is not set (which would result in those threads - /// | | potentially never getting woken up). - state: AtomicU8, -} - -unsafe impl lock_api::RawMutex for RawMutex { - const INIT: RawMutex = RawMutex { - state: AtomicU8::new(0), - }; - - type GuardMarker = GuardNoSend; - - #[inline] - fn lock(&self) { - if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_err() - { - self.lock_slow(None); - } - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - } - - #[inline] - fn try_lock(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - if state & LOCKED_BIT != 0 { - return false; - } - match self.state.compare_exchange_weak( - state, - state | LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - return true; - } - Err(x) => state = x, - } - } - } - - #[inline] - fn unlock(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - if self - .state - .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_slow(false); - } -} - -unsafe impl lock_api::RawMutexFair for RawMutex { - #[inline] - fn unlock_fair(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - if self - .state - .compare_exchange(LOCKED_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_slow(true); - } - - #[inline] - fn bump(&self) { - if self.state.load(Ordering::Relaxed) & PARKED_BIT != 0 { - self.bump_slow(); - } - } -} - -unsafe impl lock_api::RawMutexTimed for RawMutex { - type Duration = Duration; - type Instant = Instant; - - #[inline] - fn try_lock_until(&self, timeout: Instant) -> bool { - let result = if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_slow(Some(timeout)) - }; - if result { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - } - result - } - - #[inline] - fn try_lock_for(&self, timeout: Duration) -> bool { - let result = if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_slow(util::to_deadline(timeout)) - }; - if result { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - } - result - } -} - -impl RawMutex { - // Used by Condvar when requeuing threads to us, must be called while - // holding the queue lock. - #[inline] - pub(crate) fn mark_parked_if_locked(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - if state & LOCKED_BIT == 0 { - return false; - } - match self.state.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - - // Used by Condvar when requeuing threads to us, must be called while - // holding the queue lock. - #[inline] - pub(crate) fn mark_parked(&self) { - self.state.fetch_or(PARKED_BIT, Ordering::Relaxed); - } - - #[cold] - fn lock_slow(&self, timeout: Option) -> bool { - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - loop { - // Grab the lock if it isn't locked, even if there is a queue on it - if state & LOCKED_BIT == 0 { - match self.state.compare_exchange_weak( - state, - state | LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - continue; - } - - // If there is no queue, try spinning a few times - if state & PARKED_BIT == 0 && spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & PARKED_BIT == 0 { - if let Err(x) = self.state.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by an unlock - let addr = self as *const _ as usize; - let validate = || self.state.load(Ordering::Relaxed) == LOCKED_BIT | PARKED_BIT; - let before_sleep = || {}; - let timed_out = |_, was_last_thread| { - // Clear the parked bit if we were the last parked thread - if was_last_thread { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - }; - // SAFETY: - // * `addr` is an address we control. - // * `validate`/`timed_out` does not panic or call into any function of `parking_lot`. - // * `before_sleep` does not call `park`, nor does it panic. - match unsafe { - parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - timeout, - ) - } { - // The thread that unparked us passed the lock on to us - // directly without unlocking it. - ParkResult::Unparked(TOKEN_HANDOFF) => return true, - - // We were unparked normally, try acquiring the lock again - ParkResult::Unparked(_) => (), - - // The validation function failed, try locking again - ParkResult::Invalid => (), - - // Timeout expired - ParkResult::TimedOut => return false, - } - - // Loop back and try locking again - spinwait.reset(); - state = self.state.load(Ordering::Relaxed); - } - } - - #[cold] - fn unlock_slow(&self, force_fair: bool) { - // Unpark one thread and leave the parked bit set if there might - // still be parked threads on this address. - let addr = self as *const _ as usize; - let callback = |result: UnparkResult| { - // If we are using a fair unlock then we should keep the - // mutex locked and hand it off to the unparked thread. - if result.unparked_threads != 0 && (force_fair || result.be_fair) { - // Clear the parked bit if there are no more parked - // threads. - if !result.have_more_threads { - self.state.store(LOCKED_BIT, Ordering::Relaxed); - } - return TOKEN_HANDOFF; - } - - // Clear the locked bit, and the parked bit as well if there - // are no more parked threads. - if result.have_more_threads { - self.state.store(PARKED_BIT, Ordering::Release); - } else { - self.state.store(0, Ordering::Release); - } - TOKEN_NORMAL - }; - // SAFETY: - // * `addr` is an address we control. - // * `callback` does not panic or call into any function of `parking_lot`. - unsafe { - parking_lot_core::unpark_one(addr, callback); - } - } - - #[cold] - fn bump_slow(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - self.unlock_slow(true); - self.lock(); - } -} diff --git a/vendor/parking_lot-0.10.2/src/raw_rwlock.rs b/vendor/parking_lot-0.10.2/src/raw_rwlock.rs deleted file mode 100644 index 8c1ad11256..0000000000 --- a/vendor/parking_lot-0.10.2/src/raw_rwlock.rs +++ /dev/null @@ -1,1137 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::elision::{have_elision, AtomicElisionExt}; -use crate::raw_mutex::{TOKEN_HANDOFF, TOKEN_NORMAL}; -use crate::util; -use core::{ - cell::Cell, - sync::atomic::{AtomicUsize, Ordering}, -}; -use lock_api::{GuardNoSend, RawRwLock as RawRwLock_, RawRwLockUpgrade}; -use parking_lot_core::{ - self, deadlock, FilterOp, ParkResult, ParkToken, SpinWait, UnparkResult, UnparkToken, -}; -use std::time::{Duration, Instant}; - -// This reader-writer lock implementation is based on Boost's upgrade_mutex: -// https://github.com/boostorg/thread/blob/fc08c1fe2840baeeee143440fba31ef9e9a813c8/include/boost/thread/v2/shared_mutex.hpp#L432 -// -// This implementation uses 2 wait queues, one at key [addr] and one at key -// [addr + 1]. The primary queue is used for all new waiting threads, and the -// secondary queue is used by the thread which has acquired WRITER_BIT but is -// waiting for the remaining readers to exit the lock. -// -// This implementation is fair between readers and writers since it uses the -// order in which threads first started queuing to alternate between read phases -// and write phases. In particular is it not vulnerable to write starvation -// since readers will block if there is a pending writer. - -// There is at least one thread in the main queue. -const PARKED_BIT: usize = 0b0001; -// There is a parked thread holding WRITER_BIT. WRITER_BIT must be set. -const WRITER_PARKED_BIT: usize = 0b0010; -// A reader is holding an upgradable lock. The reader count must be non-zero and -// WRITER_BIT must not be set. -const UPGRADABLE_BIT: usize = 0b0100; -// If the reader count is zero: a writer is currently holding an exclusive lock. -// Otherwise: a writer is waiting for the remaining readers to exit the lock. -const WRITER_BIT: usize = 0b1000; -// Mask of bits used to count readers. -const READERS_MASK: usize = !0b1111; -// Base unit for counting readers. -const ONE_READER: usize = 0b10000; - -// Token indicating what type of lock a queued thread is trying to acquire -const TOKEN_SHARED: ParkToken = ParkToken(ONE_READER); -const TOKEN_EXCLUSIVE: ParkToken = ParkToken(WRITER_BIT); -const TOKEN_UPGRADABLE: ParkToken = ParkToken(ONE_READER | UPGRADABLE_BIT); - -/// Raw reader-writer lock type backed by the parking lot. -pub struct RawRwLock { - state: AtomicUsize, -} - -unsafe impl lock_api::RawRwLock for RawRwLock { - const INIT: RawRwLock = RawRwLock { - state: AtomicUsize::new(0), - }; - - type GuardMarker = GuardNoSend; - - #[inline] - fn lock_exclusive(&self) { - if self - .state - .compare_exchange_weak(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_err() - { - let result = self.lock_exclusive_slow(None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_exclusive(&self) -> bool { - if self - .state - .compare_exchange(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - self.deadlock_acquire(); - true - } else { - false - } - } - - #[inline] - fn unlock_exclusive(&self) { - self.deadlock_release(); - if self - .state - .compare_exchange(WRITER_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_exclusive_slow(false); - } - - #[inline] - fn lock_shared(&self) { - if !self.try_lock_shared_fast(false) { - let result = self.lock_shared_slow(false, None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_shared(&self) -> bool { - let result = if self.try_lock_shared_fast(false) { - true - } else { - self.try_lock_shared_slow(false) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn unlock_shared(&self) { - self.deadlock_release(); - let state = if have_elision() { - self.state.elision_fetch_sub_release(ONE_READER) - } else { - self.state.fetch_sub(ONE_READER, Ordering::Release) - }; - if state & (READERS_MASK | WRITER_PARKED_BIT) == (ONE_READER | WRITER_PARKED_BIT) { - self.unlock_shared_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockFair for RawRwLock { - #[inline] - fn unlock_shared_fair(&self) { - // Shared unlocking is always fair in this implementation. - self.unlock_shared(); - } - - #[inline] - fn unlock_exclusive_fair(&self) { - self.deadlock_release(); - if self - .state - .compare_exchange(WRITER_BIT, 0, Ordering::Release, Ordering::Relaxed) - .is_ok() - { - return; - } - self.unlock_exclusive_slow(true); - } - - #[inline] - fn bump_shared(&self) { - if self.state.load(Ordering::Relaxed) & (READERS_MASK | WRITER_BIT) - == ONE_READER | WRITER_BIT - { - self.bump_shared_slow(); - } - } - - #[inline] - fn bump_exclusive(&self) { - if self.state.load(Ordering::Relaxed) & PARKED_BIT != 0 { - self.bump_exclusive_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockDowngrade for RawRwLock { - #[inline] - fn downgrade(&self) { - let state = self - .state - .fetch_add(ONE_READER - WRITER_BIT, Ordering::Release); - - // Wake up parked shared and upgradable threads if there are any - if state & PARKED_BIT != 0 { - self.downgrade_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockTimed for RawRwLock { - type Duration = Duration; - type Instant = Instant; - - #[inline] - fn try_lock_shared_for(&self, timeout: Self::Duration) -> bool { - let result = if self.try_lock_shared_fast(false) { - true - } else { - self.lock_shared_slow(false, util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_shared_until(&self, timeout: Self::Instant) -> bool { - let result = if self.try_lock_shared_fast(false) { - true - } else { - self.lock_shared_slow(false, Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_exclusive_for(&self, timeout: Duration) -> bool { - let result = if self - .state - .compare_exchange_weak(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_exclusive_slow(util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_exclusive_until(&self, timeout: Instant) -> bool { - let result = if self - .state - .compare_exchange_weak(0, WRITER_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - true - } else { - self.lock_exclusive_slow(Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } -} - -unsafe impl lock_api::RawRwLockRecursive for RawRwLock { - #[inline] - fn lock_shared_recursive(&self) { - if !self.try_lock_shared_fast(true) { - let result = self.lock_shared_slow(true, None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_shared_recursive(&self) -> bool { - let result = if self.try_lock_shared_fast(true) { - true - } else { - self.try_lock_shared_slow(true) - }; - if result { - self.deadlock_acquire(); - } - result - } -} - -unsafe impl lock_api::RawRwLockRecursiveTimed for RawRwLock { - #[inline] - fn try_lock_shared_recursive_for(&self, timeout: Self::Duration) -> bool { - let result = if self.try_lock_shared_fast(true) { - true - } else { - self.lock_shared_slow(true, util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_shared_recursive_until(&self, timeout: Self::Instant) -> bool { - let result = if self.try_lock_shared_fast(true) { - true - } else { - self.lock_shared_slow(true, Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } -} - -unsafe impl lock_api::RawRwLockUpgrade for RawRwLock { - #[inline] - fn lock_upgradable(&self) { - if !self.try_lock_upgradable_fast() { - let result = self.lock_upgradable_slow(None); - debug_assert!(result); - } - self.deadlock_acquire(); - } - - #[inline] - fn try_lock_upgradable(&self) -> bool { - let result = if self.try_lock_upgradable_fast() { - true - } else { - self.try_lock_upgradable_slow() - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn unlock_upgradable(&self) { - self.deadlock_release(); - let state = self.state.load(Ordering::Relaxed); - if state & PARKED_BIT == 0 { - if self - .state - .compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT), - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - return; - } - } - self.unlock_upgradable_slow(false); - } - - #[inline] - fn upgrade(&self) { - let state = self.state.fetch_sub( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Relaxed, - ); - if state & READERS_MASK != ONE_READER { - let result = self.upgrade_slow(None); - debug_assert!(result); - } - } - - #[inline] - fn try_upgrade(&self) -> bool { - if self - .state - .compare_exchange_weak( - ONE_READER | UPGRADABLE_BIT, - WRITER_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) - .is_ok() - { - true - } else { - self.try_upgrade_slow() - } - } -} - -unsafe impl lock_api::RawRwLockUpgradeFair for RawRwLock { - #[inline] - fn unlock_upgradable_fair(&self) { - self.deadlock_release(); - let state = self.state.load(Ordering::Relaxed); - if state & PARKED_BIT == 0 { - if self - .state - .compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT), - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - return; - } - } - self.unlock_upgradable_slow(false); - } - - #[inline] - fn bump_upgradable(&self) { - if self.state.load(Ordering::Relaxed) == ONE_READER | UPGRADABLE_BIT | PARKED_BIT { - self.bump_upgradable_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockUpgradeDowngrade for RawRwLock { - #[inline] - fn downgrade_upgradable(&self) { - let state = self.state.fetch_sub(UPGRADABLE_BIT, Ordering::Relaxed); - - // Wake up parked upgradable threads if there are any - if state & PARKED_BIT != 0 { - self.downgrade_slow(); - } - } - - #[inline] - fn downgrade_to_upgradable(&self) { - let state = self.state.fetch_add( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Release, - ); - - // Wake up parked shared threads if there are any - if state & PARKED_BIT != 0 { - self.downgrade_to_upgradable_slow(); - } - } -} - -unsafe impl lock_api::RawRwLockUpgradeTimed for RawRwLock { - #[inline] - fn try_lock_upgradable_until(&self, timeout: Instant) -> bool { - let result = if self.try_lock_upgradable_fast() { - true - } else { - self.lock_upgradable_slow(Some(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_lock_upgradable_for(&self, timeout: Duration) -> bool { - let result = if self.try_lock_upgradable_fast() { - true - } else { - self.lock_upgradable_slow(util::to_deadline(timeout)) - }; - if result { - self.deadlock_acquire(); - } - result - } - - #[inline] - fn try_upgrade_until(&self, timeout: Instant) -> bool { - let state = self.state.fetch_sub( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Relaxed, - ); - if state & READERS_MASK == ONE_READER { - true - } else { - self.upgrade_slow(Some(timeout)) - } - } - - #[inline] - fn try_upgrade_for(&self, timeout: Duration) -> bool { - let state = self.state.fetch_sub( - (ONE_READER | UPGRADABLE_BIT) - WRITER_BIT, - Ordering::Relaxed, - ); - if state & READERS_MASK == ONE_READER { - true - } else { - self.upgrade_slow(util::to_deadline(timeout)) - } - } -} - -impl RawRwLock { - #[inline(always)] - fn try_lock_shared_fast(&self, recursive: bool) -> bool { - let state = self.state.load(Ordering::Relaxed); - - // We can't allow grabbing a shared lock if there is a writer, even if - // the writer is still waiting for the remaining readers to exit. - if state & WRITER_BIT != 0 { - // To allow recursive locks, we make an exception and allow readers - // to skip ahead of a pending writer to avoid deadlocking, at the - // cost of breaking the fairness guarantees. - if !recursive || state & READERS_MASK == 0 { - return false; - } - } - - // Use hardware lock elision to avoid cache conflicts when multiple - // readers try to acquire the lock. We only do this if the lock is - // completely empty since elision handles conflicts poorly. - if have_elision() && state == 0 { - self.state - .elision_compare_exchange_acquire(0, ONE_READER) - .is_ok() - } else if let Some(new_state) = state.checked_add(ONE_READER) { - self.state - .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - } else { - false - } - } - - #[cold] - fn try_lock_shared_slow(&self, recursive: bool) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - // This mirrors the condition in try_lock_shared_fast - if state & WRITER_BIT != 0 { - if !recursive || state & READERS_MASK == 0 { - return false; - } - } - if have_elision() && state == 0 { - match self.state.elision_compare_exchange_acquire(0, ONE_READER) { - Ok(_) => return true, - Err(x) => state = x, - } - } else { - match self.state.compare_exchange_weak( - state, - state - .checked_add(ONE_READER) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - } - - #[inline(always)] - fn try_lock_upgradable_fast(&self) -> bool { - let state = self.state.load(Ordering::Relaxed); - - // We can't grab an upgradable lock if there is already a writer or - // upgradable reader. - if state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - if let Some(new_state) = state.checked_add(ONE_READER | UPGRADABLE_BIT) { - self.state - .compare_exchange_weak(state, new_state, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - } else { - false - } - } - - #[cold] - fn try_lock_upgradable_slow(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - // This mirrors the condition in try_lock_upgradable_fast - if state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - match self.state.compare_exchange_weak( - state, - state - .checked_add(ONE_READER | UPGRADABLE_BIT) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - - #[cold] - fn lock_exclusive_slow(&self, timeout: Option) -> bool { - let try_lock = |state: &mut usize| { - loop { - if *state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - // Grab WRITER_BIT if it isn't set, even if there are parked threads. - match self.state.compare_exchange_weak( - *state, - *state | WRITER_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => *state = x, - } - } - }; - - // Step 1: grab exclusive ownership of WRITER_BIT - let timed_out = !self.lock_common( - timeout, - TOKEN_EXCLUSIVE, - try_lock, - WRITER_BIT | UPGRADABLE_BIT, - ); - if timed_out { - return false; - } - - // Step 2: wait for all remaining readers to exit the lock. - self.wait_for_readers(timeout, 0) - } - - #[cold] - fn unlock_exclusive_slow(&self, force_fair: bool) { - // There are threads to unpark. Try to unpark as many as we can. - let callback = |mut new_state, result: UnparkResult| { - // If we are using a fair unlock then we should keep the - // rwlock locked and hand it off to the unparked threads. - if result.unparked_threads != 0 && (force_fair || result.be_fair) { - if result.have_more_threads { - new_state |= PARKED_BIT; - } - self.state.store(new_state, Ordering::Release); - TOKEN_HANDOFF - } else { - // Clear the parked bit if there are no more parked threads. - if result.have_more_threads { - self.state.store(PARKED_BIT, Ordering::Release); - } else { - self.state.store(0, Ordering::Release); - } - TOKEN_NORMAL - } - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(0, callback); - } - } - - #[cold] - fn lock_shared_slow(&self, recursive: bool, timeout: Option) -> bool { - let try_lock = |state: &mut usize| { - let mut spinwait_shared = SpinWait::new(); - loop { - // Use hardware lock elision to avoid cache conflicts when multiple - // readers try to acquire the lock. We only do this if the lock is - // completely empty since elision handles conflicts poorly. - if have_elision() && *state == 0 { - match self.state.elision_compare_exchange_acquire(0, ONE_READER) { - Ok(_) => return true, - Err(x) => *state = x, - } - } - - // This is the same condition as try_lock_shared_fast - if *state & WRITER_BIT != 0 { - if !recursive || *state & READERS_MASK == 0 { - return false; - } - } - - if self - .state - .compare_exchange_weak( - *state, - state - .checked_add(ONE_READER) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) - .is_ok() - { - return true; - } - - // If there is high contention on the reader count then we want - // to leave some time between attempts to acquire the lock to - // let other threads make progress. - spinwait_shared.spin_no_yield(); - *state = self.state.load(Ordering::Relaxed); - } - }; - self.lock_common(timeout, TOKEN_SHARED, try_lock, WRITER_BIT) - } - - #[cold] - fn unlock_shared_slow(&self) { - // At this point WRITER_PARKED_BIT is set and READER_MASK is empty. We - // just need to wake up a potentially sleeping pending writer. - // Using the 2nd key at addr + 1 - let addr = self as *const _ as usize + 1; - let callback = |_result: UnparkResult| { - // Clear the WRITER_PARKED_BIT here since there can only be one - // parked writer thread. - self.state.fetch_and(!WRITER_PARKED_BIT, Ordering::Relaxed); - TOKEN_NORMAL - }; - // SAFETY: - // * `addr` is an address we control. - // * `callback` does not panic or call into any function of `parking_lot`. - unsafe { - parking_lot_core::unpark_one(addr, callback); - } - } - - #[cold] - fn lock_upgradable_slow(&self, timeout: Option) -> bool { - let try_lock = |state: &mut usize| { - let mut spinwait_shared = SpinWait::new(); - loop { - if *state & (WRITER_BIT | UPGRADABLE_BIT) != 0 { - return false; - } - - if self - .state - .compare_exchange_weak( - *state, - state - .checked_add(ONE_READER | UPGRADABLE_BIT) - .expect("RwLock reader count overflow"), - Ordering::Acquire, - Ordering::Relaxed, - ) - .is_ok() - { - return true; - } - - // If there is high contention on the reader count then we want - // to leave some time between attempts to acquire the lock to - // let other threads make progress. - spinwait_shared.spin_no_yield(); - *state = self.state.load(Ordering::Relaxed); - } - }; - self.lock_common( - timeout, - TOKEN_UPGRADABLE, - try_lock, - WRITER_BIT | UPGRADABLE_BIT, - ) - } - - #[cold] - fn unlock_upgradable_slow(&self, force_fair: bool) { - // Just release the lock if there are no parked threads. - let mut state = self.state.load(Ordering::Relaxed); - while state & PARKED_BIT == 0 { - match self.state.compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT), - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => return, - Err(x) => state = x, - } - } - - // There are threads to unpark. Try to unpark as many as we can. - let callback = |new_state, result: UnparkResult| { - // If we are using a fair unlock then we should keep the - // rwlock locked and hand it off to the unparked threads. - let mut state = self.state.load(Ordering::Relaxed); - if force_fair || result.be_fair { - // Fall back to normal unpark on overflow. Panicking is - // not allowed in parking_lot callbacks. - while let Some(mut new_state) = - (state - (ONE_READER | UPGRADABLE_BIT)).checked_add(new_state) - { - if result.have_more_threads { - new_state |= PARKED_BIT; - } else { - new_state &= !PARKED_BIT; - } - match self.state.compare_exchange_weak( - state, - new_state, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return TOKEN_HANDOFF, - Err(x) => state = x, - } - } - } - - // Otherwise just release the upgradable lock and update PARKED_BIT. - loop { - let mut new_state = state - (ONE_READER | UPGRADABLE_BIT); - if result.have_more_threads { - new_state |= PARKED_BIT; - } else { - new_state &= !PARKED_BIT; - } - match self.state.compare_exchange_weak( - state, - new_state, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return TOKEN_NORMAL, - Err(x) => state = x, - } - } - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(0, callback); - } - } - - #[cold] - fn try_upgrade_slow(&self) -> bool { - let mut state = self.state.load(Ordering::Relaxed); - loop { - if state & READERS_MASK != ONE_READER { - return false; - } - match self.state.compare_exchange_weak( - state, - state - (ONE_READER | UPGRADABLE_BIT) + WRITER_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - Ok(_) => return true, - Err(x) => state = x, - } - } - } - - #[cold] - fn upgrade_slow(&self, timeout: Option) -> bool { - self.wait_for_readers(timeout, ONE_READER | UPGRADABLE_BIT) - } - - #[cold] - fn downgrade_slow(&self) { - // We only reach this point if PARKED_BIT is set. - let callback = |_, result: UnparkResult| { - // Clear the parked bit if there no more parked threads - if !result.have_more_threads { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - TOKEN_NORMAL - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(ONE_READER, callback); - } - } - - #[cold] - fn downgrade_to_upgradable_slow(&self) { - // We only reach this point if PARKED_BIT is set. - let callback = |_, result: UnparkResult| { - // Clear the parked bit if there no more parked threads - if !result.have_more_threads { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - TOKEN_NORMAL - }; - // SAFETY: `callback` does not panic or call into any function of `parking_lot`. - unsafe { - self.wake_parked_threads(ONE_READER | UPGRADABLE_BIT, callback); - } - } - - #[cold] - fn bump_shared_slow(&self) { - self.unlock_shared(); - self.lock_shared(); - } - - #[cold] - fn bump_exclusive_slow(&self) { - self.deadlock_release(); - self.unlock_exclusive_slow(true); - self.lock_exclusive(); - } - - #[cold] - fn bump_upgradable_slow(&self) { - self.deadlock_release(); - self.unlock_upgradable_slow(true); - self.lock_upgradable(); - } - - /// Common code for waking up parked threads after releasing WRITER_BIT or - /// UPGRADABLE_BIT. - /// - /// # Safety - /// - /// `callback` must uphold the requirements of the `callback` parameter to - /// `parking_lot_core::unpark_filter`. Meaning no panics or calls into any function in - /// `parking_lot`. - #[inline] - unsafe fn wake_parked_threads( - &self, - new_state: usize, - callback: impl FnOnce(usize, UnparkResult) -> UnparkToken, - ) { - // We must wake up at least one upgrader or writer if there is one, - // otherwise they may end up parked indefinitely since unlock_shared - // does not call wake_parked_threads. - let new_state = Cell::new(new_state); - let addr = self as *const _ as usize; - let filter = |ParkToken(token)| { - let s = new_state.get(); - - // If we are waking up a writer, don't wake anything else. - if s & WRITER_BIT != 0 { - return FilterOp::Stop; - } - - // Otherwise wake *all* readers and one upgrader/writer. - if token & (UPGRADABLE_BIT | WRITER_BIT) != 0 && s & UPGRADABLE_BIT != 0 { - // Skip writers and upgradable readers if we already have - // a writer/upgradable reader. - FilterOp::Skip - } else { - new_state.set(s + token); - FilterOp::Unpark - } - }; - let callback = |result| callback(new_state.get(), result); - // SAFETY: - // * `addr` is an address we control. - // * `filter` does not panic or call into any function of `parking_lot`. - // * `callback` safety responsibility is on caller - parking_lot_core::unpark_filter(addr, filter, callback); - } - - // Common code for waiting for readers to exit the lock after acquiring - // WRITER_BIT. - #[inline] - fn wait_for_readers(&self, timeout: Option, prev_value: usize) -> bool { - // At this point WRITER_BIT is already set, we just need to wait for the - // remaining readers to exit the lock. - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - while state & READERS_MASK != 0 { - // Spin a few times to wait for readers to exit - if spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & WRITER_PARKED_BIT == 0 { - if let Err(x) = self.state.compare_exchange_weak( - state, - state | WRITER_PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by an unlock - // Using the 2nd key at addr + 1 - let addr = self as *const _ as usize + 1; - let validate = || { - let state = self.state.load(Ordering::Relaxed); - state & READERS_MASK != 0 && state & WRITER_PARKED_BIT != 0 - }; - let before_sleep = || {}; - let timed_out = |_, _| {}; - // SAFETY: - // * `addr` is an address we control. - // * `validate`/`timed_out` does not panic or call into any function of `parking_lot`. - // * `before_sleep` does not call `park`, nor does it panic. - let park_result = unsafe { - parking_lot_core::park( - addr, - validate, - before_sleep, - timed_out, - TOKEN_EXCLUSIVE, - timeout, - ) - }; - match park_result { - // We still need to re-check the state if we are unparked - // since a previous writer timing-out could have allowed - // another reader to sneak in before we parked. - ParkResult::Unparked(_) | ParkResult::Invalid => { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Timeout expired - ParkResult::TimedOut => { - // We need to release WRITER_BIT and revert back to - // our previous value. We also wake up any threads that - // might be waiting on WRITER_BIT. - let state = self.state.fetch_add( - prev_value.wrapping_sub(WRITER_BIT | WRITER_PARKED_BIT), - Ordering::Relaxed, - ); - if state & PARKED_BIT != 0 { - let callback = |_, result: UnparkResult| { - // Clear the parked bit if there no more parked threads - if !result.have_more_threads { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - TOKEN_NORMAL - }; - // SAFETY: `callback` does not panic or call any function of `parking_lot`. - unsafe { - self.wake_parked_threads(ONE_READER | UPGRADABLE_BIT, callback); - } - } - return false; - } - } - } - true - } - - /// Common code for acquiring a lock - #[inline] - fn lock_common( - &self, - timeout: Option, - token: ParkToken, - mut try_lock: impl FnMut(&mut usize) -> bool, - validate_flags: usize, - ) -> bool { - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - loop { - // Attempt to grab the lock - if try_lock(&mut state) { - return true; - } - - // If there are no parked threads, try spinning a few times. - if state & (PARKED_BIT | WRITER_PARKED_BIT) == 0 && spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Set the parked bit - if state & PARKED_BIT == 0 { - if let Err(x) = self.state.compare_exchange_weak( - state, - state | PARKED_BIT, - Ordering::Relaxed, - Ordering::Relaxed, - ) { - state = x; - continue; - } - } - - // Park our thread until we are woken up by an unlock - let addr = self as *const _ as usize; - let validate = || { - let state = self.state.load(Ordering::Relaxed); - state & PARKED_BIT != 0 && (state & validate_flags != 0) - }; - let before_sleep = || {}; - let timed_out = |_, was_last_thread| { - // Clear the parked bit if we were the last parked thread - if was_last_thread { - self.state.fetch_and(!PARKED_BIT, Ordering::Relaxed); - } - }; - - // SAFETY: - // * `addr` is an address we control. - // * `validate`/`timed_out` does not panic or call into any function of `parking_lot`. - // * `before_sleep` does not call `park`, nor does it panic. - let park_result = unsafe { - parking_lot_core::park(addr, validate, before_sleep, timed_out, token, timeout) - }; - match park_result { - // The thread that unparked us passed the lock on to us - // directly without unlocking it. - ParkResult::Unparked(TOKEN_HANDOFF) => return true, - - // We were unparked normally, try acquiring the lock again - ParkResult::Unparked(_) => (), - - // The validation function failed, try locking again - ParkResult::Invalid => (), - - // Timeout expired - ParkResult::TimedOut => return false, - } - - // Loop back and try locking again - spinwait.reset(); - state = self.state.load(Ordering::Relaxed); - } - } - - #[inline] - fn deadlock_acquire(&self) { - unsafe { deadlock::acquire_resource(self as *const _ as usize) }; - unsafe { deadlock::acquire_resource(self as *const _ as usize + 1) }; - } - - #[inline] - fn deadlock_release(&self) { - unsafe { deadlock::release_resource(self as *const _ as usize) }; - unsafe { deadlock::release_resource(self as *const _ as usize + 1) }; - } -} diff --git a/vendor/parking_lot-0.10.2/src/remutex.rs b/vendor/parking_lot-0.10.2/src/remutex.rs deleted file mode 100644 index 1037923018..0000000000 --- a/vendor/parking_lot-0.10.2/src/remutex.rs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::raw_mutex::RawMutex; -use core::num::NonZeroUsize; -use lock_api::{self, GetThreadId}; - -/// Implementation of the `GetThreadId` trait for `lock_api::ReentrantMutex`. -pub struct RawThreadId; - -unsafe impl GetThreadId for RawThreadId { - const INIT: RawThreadId = RawThreadId; - - fn nonzero_thread_id(&self) -> NonZeroUsize { - // The address of a thread-local variable is guaranteed to be unique to the - // current thread, and is also guaranteed to be non-zero. The variable has to have a - // non-zero size to guarantee it has a unique address for each thread. - thread_local!(static KEY: u8 = 0); - KEY.with(|x| { - NonZeroUsize::new(x as *const _ as usize) - .expect("thread-local variable address is null") - }) - } -} - -/// A mutex which can be recursively locked by a single thread. -/// -/// This type is identical to `Mutex` except for the following points: -/// -/// - Locking multiple times from the same thread will work correctly instead of -/// deadlocking. -/// - `ReentrantMutexGuard` does not give mutable references to the locked data. -/// Use a `RefCell` if you need this. -/// -/// See [`Mutex`](type.Mutex.html) for more details about the underlying mutex -/// primitive. -pub type ReentrantMutex = lock_api::ReentrantMutex; - -/// Creates a new reentrant mutex in an unlocked state ready for use. -/// -/// This allows creating a reentrant mutex in a constant context on stable Rust. -pub const fn const_reentrant_mutex(val: T) -> ReentrantMutex { - ReentrantMutex::const_new( - ::INIT, - ::INIT, - val, - ) -} - -/// An RAII implementation of a "scoped lock" of a reentrant mutex. When this structure -/// is dropped (falls out of scope), the lock will be unlocked. -/// -/// The data protected by the mutex can be accessed through this guard via its -/// `Deref` implementation. -pub type ReentrantMutexGuard<'a, T> = lock_api::ReentrantMutexGuard<'a, RawMutex, RawThreadId, T>; - -/// An RAII mutex guard returned by `ReentrantMutexGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedReentrantMutexGuard` and `ReentrantMutexGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedReentrantMutexGuard<'a, T> = - lock_api::MappedReentrantMutexGuard<'a, RawMutex, RawThreadId, T>; - -#[cfg(test)] -mod tests { - use crate::ReentrantMutex; - use std::cell::RefCell; - use std::sync::Arc; - use std::thread; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - #[test] - fn smoke() { - let m = ReentrantMutex::new(2); - { - let a = m.lock(); - { - let b = m.lock(); - { - let c = m.lock(); - assert_eq!(*c, 2); - } - assert_eq!(*b, 2); - } - assert_eq!(*a, 2); - } - } - - #[test] - fn is_mutex() { - let m = Arc::new(ReentrantMutex::new(RefCell::new(0))); - let m2 = m.clone(); - let lock = m.lock(); - let child = thread::spawn(move || { - let lock = m2.lock(); - assert_eq!(*lock.borrow(), 4950); - }); - for i in 0..100 { - let lock = m.lock(); - *lock.borrow_mut() += i; - } - drop(lock); - child.join().unwrap(); - } - - #[test] - fn trylock_works() { - let m = Arc::new(ReentrantMutex::new(())); - let m2 = m.clone(); - let _lock = m.try_lock(); - let _lock2 = m.try_lock(); - thread::spawn(move || { - let lock = m2.try_lock(); - assert!(lock.is_none()); - }) - .join() - .unwrap(); - let _lock3 = m.try_lock(); - } - - #[test] - fn test_reentrant_mutex_debug() { - let mutex = ReentrantMutex::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", mutex), "ReentrantMutex { data: [0, 10] }"); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = ReentrantMutex::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: ReentrantMutex> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.lock()), *(deserialized.lock())); - assert_eq!(contents, *(deserialized.lock())); - } -} diff --git a/vendor/parking_lot-0.10.2/src/rwlock.rs b/vendor/parking_lot-0.10.2/src/rwlock.rs deleted file mode 100644 index 0381316eaa..0000000000 --- a/vendor/parking_lot-0.10.2/src/rwlock.rs +++ /dev/null @@ -1,613 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::raw_rwlock::RawRwLock; -use lock_api; - -/// A reader-writer lock -/// -/// This type of lock allows a number of readers or at most one writer at any -/// point in time. The write portion of this lock typically allows modification -/// of the underlying data (exclusive access) and the read portion of this lock -/// typically allows for read-only access (shared access). -/// -/// This lock uses a task-fair locking policy which avoids both reader and -/// writer starvation. This means that readers trying to acquire the lock will -/// block even if the lock is unlocked when there are writers waiting to acquire -/// the lock. Because of this, attempts to recursively acquire a read lock -/// within a single thread may result in a deadlock. -/// -/// The type parameter `T` represents the data that this lock protects. It is -/// required that `T` satisfies `Send` to be shared across threads and `Sync` to -/// allow concurrent access through readers. The RAII guards returned from the -/// locking methods implement `Deref` (and `DerefMut` for the `write` methods) -/// to allow access to the contained of the lock. -/// -/// # Fairness -/// -/// A typical unfair lock can often end up in a situation where a single thread -/// quickly acquires and releases the same lock in succession, which can starve -/// other threads waiting to acquire the rwlock. While this improves performance -/// because it doesn't force a context switch when a thread tries to re-acquire -/// a rwlock it has just released, this can starve other threads. -/// -/// This rwlock uses [eventual fairness](https://trac.webkit.org/changeset/203350) -/// to ensure that the lock will be fair on average without sacrificing -/// performance. This is done by forcing a fair unlock on average every 0.5ms, -/// which will force the lock to go to the next thread waiting for the rwlock. -/// -/// Additionally, any critical section longer than 1ms will always use a fair -/// unlock, which has a negligible performance impact compared to the length of -/// the critical section. -/// -/// You can also force a fair unlock by calling `RwLockReadGuard::unlock_fair` -/// or `RwLockWriteGuard::unlock_fair` when unlocking a mutex instead of simply -/// dropping the guard. -/// -/// # Differences from the standard library `RwLock` -/// -/// - Supports atomically downgrading a write lock into a read lock. -/// - Task-fair locking policy instead of an unspecified platform default. -/// - No poisoning, the lock is released normally on panic. -/// - Only requires 1 word of space, whereas the standard library boxes the -/// `RwLock` due to platform limitations. -/// - Can be statically constructed (requires the `const_fn` nightly feature). -/// - Does not require any drop glue when dropped. -/// - Inline fast path for the uncontended case. -/// - Efficient handling of micro-contention using adaptive spinning. -/// - Allows raw locking & unlocking without a guard. -/// - Supports eventual fairness so that the rwlock is fair on average. -/// - Optionally allows making the rwlock fair by calling -/// `RwLockReadGuard::unlock_fair` and `RwLockWriteGuard::unlock_fair`. -/// -/// # Examples -/// -/// ``` -/// use parking_lot::RwLock; -/// -/// let lock = RwLock::new(5); -/// -/// // many reader locks can be held at once -/// { -/// let r1 = lock.read(); -/// let r2 = lock.read(); -/// assert_eq!(*r1, 5); -/// assert_eq!(*r2, 5); -/// } // read locks are dropped at this point -/// -/// // only one write lock may be held, however -/// { -/// let mut w = lock.write(); -/// *w += 1; -/// assert_eq!(*w, 6); -/// } // write lock is dropped here -/// ``` -pub type RwLock = lock_api::RwLock; - -/// Creates a new instance of an `RwLock` which is unlocked. -/// -/// This allows creating a `RwLock` in a constant context on stable Rust. -pub const fn const_rwlock(val: T) -> RwLock { - RwLock::const_new(::INIT, val) -} - -/// RAII structure used to release the shared read access of a lock when -/// dropped. -pub type RwLockReadGuard<'a, T> = lock_api::RwLockReadGuard<'a, RawRwLock, T>; - -/// RAII structure used to release the exclusive write access of a lock when -/// dropped. -pub type RwLockWriteGuard<'a, T> = lock_api::RwLockWriteGuard<'a, RawRwLock, T>; - -/// An RAII read lock guard returned by `RwLockReadGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedRwLockReadGuard` and `RwLockReadGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedRwLockReadGuard<'a, T> = lock_api::MappedRwLockReadGuard<'a, RawRwLock, T>; - -/// An RAII write lock guard returned by `RwLockWriteGuard::map`, which can point to a -/// subfield of the protected data. -/// -/// The main difference between `MappedRwLockWriteGuard` and `RwLockWriteGuard` is that the -/// former doesn't support temporarily unlocking and re-locking, since that -/// could introduce soundness issues if the locked object is modified by another -/// thread. -pub type MappedRwLockWriteGuard<'a, T> = lock_api::MappedRwLockWriteGuard<'a, RawRwLock, T>; - -/// RAII structure used to release the upgradable read access of a lock when -/// dropped. -pub type RwLockUpgradableReadGuard<'a, T> = lock_api::RwLockUpgradableReadGuard<'a, RawRwLock, T>; - -#[cfg(test)] -mod tests { - use crate::{RwLock, RwLockUpgradableReadGuard, RwLockWriteGuard}; - use rand::Rng; - use std::sync::atomic::{AtomicUsize, Ordering}; - use std::sync::mpsc::channel; - use std::sync::Arc; - use std::thread; - use std::time::Duration; - - #[cfg(feature = "serde")] - use bincode::{deserialize, serialize}; - - #[derive(Eq, PartialEq, Debug)] - struct NonCopy(i32); - - #[test] - fn smoke() { - let l = RwLock::new(()); - drop(l.read()); - drop(l.write()); - drop(l.upgradable_read()); - drop((l.read(), l.read())); - drop((l.read(), l.upgradable_read())); - drop(l.write()); - } - - #[test] - fn frob() { - const N: u32 = 10; - const M: u32 = 1000; - - let r = Arc::new(RwLock::new(())); - - let (tx, rx) = channel::<()>(); - for _ in 0..N { - let tx = tx.clone(); - let r = r.clone(); - thread::spawn(move || { - let mut rng = rand::thread_rng(); - for _ in 0..M { - if rng.gen_bool(1.0 / N as f64) { - drop(r.write()); - } else { - drop(r.read()); - } - } - drop(tx); - }); - } - drop(tx); - let _ = rx.recv(); - } - - #[test] - fn test_rw_arc_no_poison_wr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write(); - panic!(); - }) - .join(); - let lock = arc.read(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc_no_poison_ww() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.write(); - panic!(); - }) - .join(); - let lock = arc.write(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc_no_poison_rr() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read(); - panic!(); - }) - .join(); - let lock = arc.read(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_rw_arc_no_poison_rw() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _: Result<(), _> = thread::spawn(move || { - let _lock = arc2.read(); - panic!() - }) - .join(); - let lock = arc.write(); - assert_eq!(*lock, 1); - } - - #[test] - fn test_ruw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - for _ in 0..10 { - let mut lock = arc2.write(); - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - let mut children = Vec::new(); - - // Upgradable readers try to catch the writer in the act and also - // try to touch the value - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.upgradable_read(); - let tmp = *lock; - assert!(tmp >= 0); - thread::yield_now(); - let mut lock = RwLockUpgradableReadGuard::upgrade(lock); - assert_eq!(tmp, *lock); - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - })); - } - - // Readers try to catch the writers in the act - for _ in 0..5 { - let arc4 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc4.read(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read(); - assert_eq!(*lock, 15); - } - - #[test] - fn test_rw_arc() { - let arc = Arc::new(RwLock::new(0)); - let arc2 = arc.clone(); - let (tx, rx) = channel(); - - thread::spawn(move || { - let mut lock = arc2.write(); - for _ in 0..10 { - let tmp = *lock; - *lock = -1; - thread::yield_now(); - *lock = tmp + 1; - } - tx.send(()).unwrap(); - }); - - // Readers try to catch the writer in the act - let mut children = Vec::new(); - for _ in 0..5 { - let arc3 = arc.clone(); - children.push(thread::spawn(move || { - let lock = arc3.read(); - assert!(*lock >= 0); - })); - } - - // Wait for children to pass their asserts - for r in children { - assert!(r.join().is_ok()); - } - - // Wait for writer to finish - rx.recv().unwrap(); - let lock = arc.read(); - assert_eq!(*lock, 10); - } - - #[test] - fn test_rw_arc_access_in_unwind() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _ = thread::spawn(move || { - struct Unwinder { - i: Arc>, - } - impl Drop for Unwinder { - fn drop(&mut self) { - let mut lock = self.i.write(); - *lock += 1; - } - } - let _u = Unwinder { i: arc2 }; - panic!(); - }) - .join(); - let lock = arc.read(); - assert_eq!(*lock, 2); - } - - #[test] - fn test_rwlock_unsized() { - let rw: &RwLock<[i32]> = &RwLock::new([1, 2, 3]); - { - let b = &mut *rw.write(); - b[0] = 4; - b[2] = 5; - } - let comp: &[i32] = &[4, 2, 5]; - assert_eq!(&*rw.read(), comp); - } - - #[test] - fn test_rwlock_try_read() { - let lock = RwLock::new(0isize); - { - let read_guard = lock.read(); - - let read_result = lock.try_read(); - assert!( - read_result.is_some(), - "try_read should succeed while read_guard is in scope" - ); - - drop(read_guard); - } - { - let upgrade_guard = lock.upgradable_read(); - - let read_result = lock.try_read(); - assert!( - read_result.is_some(), - "try_read should succeed while upgrade_guard is in scope" - ); - - drop(upgrade_guard); - } - { - let write_guard = lock.write(); - - let read_result = lock.try_read(); - assert!( - read_result.is_none(), - "try_read should fail while write_guard is in scope" - ); - - drop(write_guard); - } - } - - #[test] - fn test_rwlock_try_write() { - let lock = RwLock::new(0isize); - { - let read_guard = lock.read(); - - let write_result = lock.try_write(); - assert!( - write_result.is_none(), - "try_write should fail while read_guard is in scope" - ); - - drop(read_guard); - } - { - let upgrade_guard = lock.upgradable_read(); - - let write_result = lock.try_write(); - assert!( - write_result.is_none(), - "try_write should fail while upgrade_guard is in scope" - ); - - drop(upgrade_guard); - } - { - let write_guard = lock.write(); - - let write_result = lock.try_write(); - assert!( - write_result.is_none(), - "try_write should fail while write_guard is in scope" - ); - - drop(write_guard); - } - } - - #[test] - fn test_rwlock_try_upgrade() { - let lock = RwLock::new(0isize); - { - let read_guard = lock.read(); - - let upgrade_result = lock.try_upgradable_read(); - assert!( - upgrade_result.is_some(), - "try_upgradable_read should succeed while read_guard is in scope" - ); - - drop(read_guard); - } - { - let upgrade_guard = lock.upgradable_read(); - - let upgrade_result = lock.try_upgradable_read(); - assert!( - upgrade_result.is_none(), - "try_upgradable_read should fail while upgrade_guard is in scope" - ); - - drop(upgrade_guard); - } - { - let write_guard = lock.write(); - - let upgrade_result = lock.try_upgradable_read(); - assert!( - upgrade_result.is_none(), - "try_upgradable should fail while write_guard is in scope" - ); - - drop(write_guard); - } - } - - #[test] - fn test_into_inner() { - let m = RwLock::new(NonCopy(10)); - assert_eq!(m.into_inner(), NonCopy(10)); - } - - #[test] - fn test_into_inner_drop() { - struct Foo(Arc); - impl Drop for Foo { - fn drop(&mut self) { - self.0.fetch_add(1, Ordering::SeqCst); - } - } - let num_drops = Arc::new(AtomicUsize::new(0)); - let m = RwLock::new(Foo(num_drops.clone())); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - { - let _inner = m.into_inner(); - assert_eq!(num_drops.load(Ordering::SeqCst), 0); - } - assert_eq!(num_drops.load(Ordering::SeqCst), 1); - } - - #[test] - fn test_get_mut() { - let mut m = RwLock::new(NonCopy(10)); - *m.get_mut() = NonCopy(20); - assert_eq!(m.into_inner(), NonCopy(20)); - } - - #[test] - fn test_rwlockguard_sync() { - fn sync(_: T) {} - - let rwlock = RwLock::new(()); - sync(rwlock.read()); - sync(rwlock.write()); - } - - #[test] - fn test_rwlock_downgrade() { - let x = Arc::new(RwLock::new(0)); - let mut handles = Vec::new(); - for _ in 0..8 { - let x = x.clone(); - handles.push(thread::spawn(move || { - for _ in 0..100 { - let mut writer = x.write(); - *writer += 1; - let cur_val = *writer; - let reader = RwLockWriteGuard::downgrade(writer); - assert_eq!(cur_val, *reader); - } - })); - } - for handle in handles { - handle.join().unwrap() - } - assert_eq!(*x.read(), 800); - } - - #[test] - fn test_rwlock_recursive() { - let arc = Arc::new(RwLock::new(1)); - let arc2 = arc.clone(); - let _lock1 = arc.read(); - thread::spawn(move || { - let _lock = arc2.write(); - }); - - if cfg!(not(all(target_env = "sgx", target_vendor = "fortanix"))) { - thread::sleep(Duration::from_millis(100)); - } else { - // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - for _ in 0..100 { - thread::yield_now(); - } - } - - // A normal read would block here since there is a pending writer - let _lock2 = arc.read_recursive(); - } - - #[test] - fn test_rwlock_debug() { - let x = RwLock::new(vec![0u8, 10]); - - assert_eq!(format!("{:?}", x), "RwLock { data: [0, 10] }"); - let _lock = x.write(); - assert_eq!(format!("{:?}", x), "RwLock { data: }"); - } - - #[test] - fn test_clone() { - let rwlock = RwLock::new(Arc::new(1)); - let a = rwlock.read_recursive(); - let b = a.clone(); - assert_eq!(Arc::strong_count(&b), 2); - } - - #[cfg(feature = "serde")] - #[test] - fn test_serde() { - let contents: Vec = vec![0, 1, 2]; - let mutex = RwLock::new(contents.clone()); - - let serialized = serialize(&mutex).unwrap(); - let deserialized: RwLock> = deserialize(&serialized).unwrap(); - - assert_eq!(*(mutex.read()), *(deserialized.read())); - assert_eq!(contents, *(deserialized.read())); - } - - #[test] - fn test_issue_203() { - struct Bar(RwLock<()>); - - impl Drop for Bar { - fn drop(&mut self) { - let _n = self.0.write(); - } - } - - thread_local! { - static B: Bar = Bar(RwLock::new(())); - } - - thread::spawn(|| { - B.with(|_| ()); - - let a = RwLock::new(()); - let _a = a.read(); - }) - .join() - .unwrap(); - } -} diff --git a/vendor/parking_lot-0.10.2/src/util.rs b/vendor/parking_lot-0.10.2/src/util.rs deleted file mode 100644 index c5496fc00b..0000000000 --- a/vendor/parking_lot-0.10.2/src/util.rs +++ /dev/null @@ -1,38 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use std::time::{Duration, Instant}; - -// Option::unchecked_unwrap -pub trait UncheckedOptionExt { - unsafe fn unchecked_unwrap(self) -> T; -} - -impl UncheckedOptionExt for Option { - #[inline] - unsafe fn unchecked_unwrap(self) -> T { - match self { - Some(x) => x, - None => unreachable(), - } - } -} - -// hint::unreachable_unchecked() in release mode -#[inline] -unsafe fn unreachable() -> ! { - if cfg!(debug_assertions) { - unreachable!(); - } else { - core::hint::unreachable_unchecked() - } -} - -#[inline] -pub fn to_deadline(timeout: Duration) -> Option { - Instant::now().checked_add(timeout) -} diff --git a/vendor/parking_lot-0.10.2/tests/issue_203.rs b/vendor/parking_lot-0.10.2/tests/issue_203.rs deleted file mode 100644 index a77a95f8ae..0000000000 --- a/vendor/parking_lot-0.10.2/tests/issue_203.rs +++ /dev/null @@ -1,26 +0,0 @@ -use parking_lot::RwLock; -use std::thread; - -struct Bar(RwLock<()>); - -impl Drop for Bar { - fn drop(&mut self) { - let _n = self.0.write(); - } -} - -thread_local! { - static B: Bar = Bar(RwLock::new(())); -} - -#[test] -fn main() { - thread::spawn(|| { - B.with(|_| ()); - - let a = RwLock::new(()); - let _a = a.read(); - }) - .join() - .unwrap(); -} diff --git a/vendor/parking_lot_core-0.7.2/.cargo-checksum.json b/vendor/parking_lot_core-0.7.2/.cargo-checksum.json deleted file mode 100644 index 2b1d6d8132..0000000000 --- a/vendor/parking_lot_core-0.7.2/.cargo-checksum.json +++ /dev/null @@ -1 +0,0 @@ -{"files":{"Cargo.toml":"8230dddab7c73aa75c9fcb9647c57af37c015e57223ac1706cf7e73e810559dc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"c9a75f18b9ab2927829a208fc6aa2cf4e63b8420887ba29cdb265d6619ae82d5","src/lib.rs":"058dddad16d91c8d0160fa2a78bb5f7c2f801f2fd9770fc387c5843395bf0379","src/parking_lot.rs":"15c2c91f05ca117bb47fbaeb65e19cb039aab0064301c5113c2a48c86b76f5da","src/spinwait.rs":"d568d8a81f9144ec4c4a139dc934d7d04ee1656a4a221eb548742fe7aba09ab1","src/thread_parker/cloudabi.rs":"0668b50898c20e7267ac6cc977e7ad376a18958e2d07faeca8199794d873d2eb","src/thread_parker/generic.rs":"2f501c6e46fcff434ba9e13ae8859e66de3327f601ed92989b310124e4129ff4","src/thread_parker/linux.rs":"853fd22f51215d1f553ad6461ad3c92c4ec9c294e607e69ed5f53b2e8c7a11d7","src/thread_parker/mod.rs":"5bc2100d2f575608b5b76e626ca92ce3ba4830176ecc773c5594cda6ca0905e9","src/thread_parker/redox.rs":"081c76af1e24be12da45d8093e261c48d558342ac2ac64dc3f7dd95eaaa1bf11","src/thread_parker/sgx.rs":"3fd71a7066db58189f302d2344e4e425320f82c298ca482ca4318bae44ae37fd","src/thread_parker/unix.rs":"77e1f049207b7e89b22ef05e5134c7538b31fff99aa9660784136f96fec1845a","src/thread_parker/wasm.rs":"b4c9f9e9c1fd636b235a0e8e0227c954b1e7432d8394b58af77b348cdfa2141e","src/thread_parker/wasm_atomic.rs":"a1ab05981a833e72d8d353350ab2b95e6f833cd7224591e595ccdb3692968c23","src/thread_parker/windows/keyed_event.rs":"34fc4693e7afd69a5c426ae7face83b8363f114a44dece44197cd03861cfdded","src/thread_parker/windows/mod.rs":"7702ff9b72ac647ec998a9b205ace961a28839fcd94631fb750ca459e4804260","src/thread_parker/windows/waitaddress.rs":"06d994633006e237dc940f377432ea00cf1609e56096d69d46f7bb3b80eeb857","src/util.rs":"285e6133150645525f2ca1ece41f6d35bad4e7c5e08b42b20c99d2a97e04a974","src/word_lock.rs":"2c030aedb340ae8ca564365206452c298fe29986d005d6a40e808c9760f91c95"},"package":"d58c7c768d4ba344e3e8d72518ac13e259d7c7ade24167003b8488e10b6740a3"} \ No newline at end of file diff --git a/vendor/parking_lot_core-0.7.2/Cargo.toml b/vendor/parking_lot_core-0.7.2/Cargo.toml deleted file mode 100644 index d24a5cacb7..0000000000 --- a/vendor/parking_lot_core-0.7.2/Cargo.toml +++ /dev/null @@ -1,52 +0,0 @@ -# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO -# -# When uploading crates to the registry Cargo will automatically -# "normalize" Cargo.toml files for maximal compatibility -# with all versions of Cargo and also rewrite `path` dependencies -# to registry (e.g., crates.io) dependencies -# -# If you believe there's an error in this file please file an -# issue against the rust-lang/cargo repository. If you're -# editing this file be aware that the upstream Cargo.toml -# will likely look very different (and much more reasonable) - -[package] -edition = "2018" -name = "parking_lot_core" -version = "0.7.2" -authors = ["Amanieu d'Antras "] -description = "An advanced API for creating custom synchronization primitives." -keywords = ["mutex", "condvar", "rwlock", "once", "thread"] -categories = ["concurrency"] -license = "Apache-2.0/MIT" -repository = "https://github.com/Amanieu/parking_lot" -[dependencies.backtrace] -version = "0.3.2" -optional = true - -[dependencies.cfg-if] -version = "0.1.5" - -[dependencies.petgraph] -version = "0.5" -optional = true - -[dependencies.smallvec] -version = "1.0" - -[dependencies.thread-id] -version = "3.2.0" -optional = true - -[features] -deadlock_detection = ["petgraph", "thread-id", "backtrace"] -nightly = [] -[target."cfg(target_os = \"cloudabi\")".dependencies.cloudabi] -version = "0.0.3" -[target."cfg(target_os = \"redox\")".dependencies.redox_syscall] -version = "0.1" -[target."cfg(unix)".dependencies.libc] -version = "0.2.55" -[target."cfg(windows)".dependencies.winapi] -version = "0.3" -features = ["winnt", "ntstatus", "minwindef", "winerror", "winbase", "errhandlingapi", "handleapi"] diff --git a/vendor/parking_lot_core-0.7.2/src/lib.rs b/vendor/parking_lot_core-0.7.2/src/lib.rs deleted file mode 100644 index ba4cb1e8c9..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/lib.rs +++ /dev/null @@ -1,71 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -//! This library exposes a low-level API for creating your own efficient -//! synchronization primitives. -//! -//! # The parking lot -//! -//! To keep synchronization primitives small, all thread queuing and suspending -//! functionality is offloaded to the *parking lot*. The idea behind this is based -//! on the Webkit [`WTF::ParkingLot`](https://webkit.org/blog/6161/locking-in-webkit/) -//! class, which essentially consists of a hash table mapping of lock addresses -//! to queues of parked (sleeping) threads. The Webkit parking lot was itself -//! inspired by Linux [futexes](http://man7.org/linux/man-pages/man2/futex.2.html), -//! but it is more powerful since it allows invoking callbacks while holding a -//! queue lock. -//! -//! There are two main operations that can be performed on the parking lot: -//! -//! - *Parking* refers to suspending the thread while simultaneously enqueuing it -//! on a queue keyed by some address. -//! - *Unparking* refers to dequeuing a thread from a queue keyed by some address -//! and resuming it. -//! -//! See the documentation of the individual functions for more details. -//! -//! # Building custom synchronization primitives -//! -//! Building custom synchronization primitives is very simple since the parking -//! lot takes care of all the hard parts for you. A simple example for a -//! custom primitive would be to integrate a `Mutex` inside another data type. -//! Since a mutex only requires 2 bits, it can share space with other data. -//! For example, one could create an `ArcMutex` type that combines the atomic -//! reference count and the two mutex bits in the same atomic word. - -#![warn(missing_docs)] -#![warn(rust_2018_idioms)] -#![cfg_attr( - all(target_env = "sgx", target_vendor = "fortanix"), - feature(sgx_platform) -)] -#![cfg_attr( - all( - feature = "nightly", - target_arch = "wasm32", - target_feature = "atomics" - ), - feature(stdsimd) -)] -#![cfg_attr( - all(feature = "nightly", target_os = "cloudabi",), - feature(thread_local) -)] - -mod parking_lot; -mod spinwait; -mod thread_parker; -mod util; -mod word_lock; - -pub use self::parking_lot::deadlock; -pub use self::parking_lot::{park, unpark_all, unpark_filter, unpark_one, unpark_requeue}; -pub use self::parking_lot::{ - FilterOp, ParkResult, ParkToken, RequeueOp, UnparkResult, UnparkToken, -}; -pub use self::parking_lot::{DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN}; -pub use self::spinwait::SpinWait; diff --git a/vendor/parking_lot_core-0.7.2/src/parking_lot.rs b/vendor/parking_lot_core-0.7.2/src/parking_lot.rs deleted file mode 100644 index 440b7c7063..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/parking_lot.rs +++ /dev/null @@ -1,1708 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. -use cfg_if::cfg_if; -use crate::thread_parker::{ThreadParker, ThreadParkerT, UnparkHandleT}; -use crate::util::UncheckedOptionExt; -use crate::word_lock::WordLock; -use core::{ - cell::{Cell, UnsafeCell}, - ptr, - sync::atomic::{AtomicPtr, AtomicUsize, Ordering}, -}; -use smallvec::SmallVec; -use std::time::{Duration, Instant}; - -cfg_if! { - if #[cfg(all( - target_arch = "wasm32", - target_os = "unknown", - target_vendor = "unknown" - ))] { - use core::ops::Add; - - #[derive(Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug, Hash)] - struct DummyInstant(Duration); - - impl DummyInstant { - pub fn now() -> DummyInstant { - DummyInstant::zero() - } - - const fn zero() -> DummyInstant { - DummyInstant(Duration::from_secs(0)) - } - } - - impl Add for DummyInstant { - type Output = DummyInstant; - - fn add(self, _rhs: Duration) -> DummyInstant { - DummyInstant::zero() - } - } - - // Use dummy implementation for `Instant` on `wasm32`. The reason for this is - // that `Instant::now()` will always panic because time is currently not implemented - // on wasm32-unknown-unknown. - // See https://github.com/rust-lang/rust/blob/master/src/libstd/sys/wasm/time.rs - type InstantType = DummyInstant; - } else { - // Otherwise use `std::time::Instant` - type InstantType = Instant; - } -} - -static NUM_THREADS: AtomicUsize = AtomicUsize::new(0); - -/// Holds the pointer to the currently active `HashTable`. -/// -/// # Safety -/// -/// Except for the initial value of null, it must always point to a valid `HashTable` instance. -/// Any `HashTable` this global static has ever pointed to must never be freed. -static HASHTABLE: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -// Even with 3x more buckets than threads, the memory overhead per thread is -// still only a few hundred bytes per thread. -const LOAD_FACTOR: usize = 3; - -struct HashTable { - // Hash buckets for the table - entries: Box<[Bucket]>, - - // Number of bits used for the hash function - hash_bits: u32, - - // Previous table. This is only kept to keep leak detectors happy. - _prev: *const HashTable, -} - -impl HashTable { - #[inline] - fn new(num_threads: usize, prev: *const HashTable) -> Box { - let new_size = (num_threads * LOAD_FACTOR).next_power_of_two(); - let hash_bits = 0usize.leading_zeros() - new_size.leading_zeros() - 1; - - let now = InstantType::now(); - let mut entries = Vec::with_capacity(new_size); - for i in 0..new_size { - // We must ensure the seed is not zero - entries.push(Bucket::new(now, i as u32 + 1)); - } - - Box::new(HashTable { - entries: entries.into_boxed_slice(), - hash_bits, - _prev: prev, - }) - } -} - -#[repr(align(64))] -struct Bucket { - // Lock protecting the queue - mutex: WordLock, - - // Linked list of threads waiting on this bucket - queue_head: Cell<*const ThreadData>, - queue_tail: Cell<*const ThreadData>, - - // Next time at which point be_fair should be set - fair_timeout: UnsafeCell, -} - -impl Bucket { - #[inline] - pub fn new(timeout: InstantType, seed: u32) -> Self { - Self { - mutex: WordLock::new(), - queue_head: Cell::new(ptr::null()), - queue_tail: Cell::new(ptr::null()), - fair_timeout: UnsafeCell::new(FairTimeout::new(timeout, seed)), - } - } -} - -struct FairTimeout { - // Next time at which point be_fair should be set - timeout: InstantType, - - // the PRNG state for calculating the next timeout - seed: u32, -} - -impl FairTimeout { - #[inline] - fn new(timeout: InstantType, seed: u32) -> FairTimeout { - FairTimeout { timeout, seed } - } - - // Determine whether we should force a fair unlock, and update the timeout - #[inline] - fn should_timeout(&mut self) -> bool { - let now = InstantType::now(); - if now > self.timeout { - // Time between 0 and 1ms. - let nanos = self.gen_u32() % 1_000_000; - self.timeout = now + Duration::new(0, nanos); - true - } else { - false - } - } - - // Pseudorandom number generator from the "Xorshift RNGs" paper by George Marsaglia. - fn gen_u32(&mut self) -> u32 { - self.seed ^= self.seed << 13; - self.seed ^= self.seed >> 17; - self.seed ^= self.seed << 5; - self.seed - } -} - -struct ThreadData { - parker: ThreadParker, - - // Key that this thread is sleeping on. This may change if the thread is - // requeued to a different key. - key: AtomicUsize, - - // Linked list of parked threads in a bucket - next_in_queue: Cell<*const ThreadData>, - - // UnparkToken passed to this thread when it is unparked - unpark_token: Cell, - - // ParkToken value set by the thread when it was parked - park_token: Cell, - - // Is the thread parked with a timeout? - parked_with_timeout: Cell, - - // Extra data for deadlock detection - #[cfg(feature = "deadlock_detection")] - deadlock_data: deadlock::DeadlockData, -} - -impl ThreadData { - fn new() -> ThreadData { - // Keep track of the total number of live ThreadData objects and resize - // the hash table accordingly. - let num_threads = NUM_THREADS.fetch_add(1, Ordering::Relaxed) + 1; - grow_hashtable(num_threads); - - ThreadData { - parker: ThreadParker::new(), - key: AtomicUsize::new(0), - next_in_queue: Cell::new(ptr::null()), - unpark_token: Cell::new(DEFAULT_UNPARK_TOKEN), - park_token: Cell::new(DEFAULT_PARK_TOKEN), - parked_with_timeout: Cell::new(false), - #[cfg(feature = "deadlock_detection")] - deadlock_data: deadlock::DeadlockData::new(), - } - } -} - -// Invokes the given closure with a reference to the current thread `ThreadData`. -#[inline(always)] -fn with_thread_data(f: impl FnOnce(&ThreadData) -> T) -> T { - // Unlike word_lock::ThreadData, parking_lot::ThreadData is always expensive - // to construct. Try to use a thread-local version if possible. Otherwise just - // create a ThreadData on the stack - let mut thread_data_storage = None; - thread_local!(static THREAD_DATA: ThreadData = ThreadData::new()); - let thread_data_ptr = THREAD_DATA - .try_with(|x| x as *const ThreadData) - .unwrap_or_else(|_| thread_data_storage.get_or_insert_with(ThreadData::new)); - - f(unsafe { &*thread_data_ptr }) -} - -impl Drop for ThreadData { - fn drop(&mut self) { - NUM_THREADS.fetch_sub(1, Ordering::Relaxed); - } -} - -/// Returns a reference to the latest hash table, creating one if it doesn't exist yet. -/// The reference is valid forever. However, the `HashTable` it references might become stale -/// at any point. Meaning it still exists, but it is not the instance in active use. -#[inline] -fn get_hashtable() -> &'static HashTable { - let table = HASHTABLE.load(Ordering::Acquire); - - // If there is no table, create one - if table.is_null() { - create_hashtable() - } else { - // SAFETY: when not null, `HASHTABLE` always points to a `HashTable` that is never freed. - unsafe { &*table } - } -} - -/// Returns a reference to the latest hash table, creating one if it doesn't exist yet. -/// The reference is valid forever. However, the `HashTable` it references might become stale -/// at any point. Meaning it still exists, but it is not the instance in active use. -#[cold] -fn create_hashtable() -> &'static HashTable { - let new_table = Box::into_raw(HashTable::new(LOAD_FACTOR, ptr::null())); - - // If this fails then it means some other thread created the hash table first. - let table = match HASHTABLE.compare_exchange( - ptr::null_mut(), - new_table, - Ordering::AcqRel, - Ordering::Acquire, - ) { - Ok(_) => new_table, - Err(old_table) => { - // Free the table we created - // SAFETY: `new_table` is created from `Box::into_raw` above and only freed here. - unsafe { - Box::from_raw(new_table); - } - old_table - } - }; - // SAFETY: The `HashTable` behind `table` is never freed. It is either the table pointer we - // created here, or it is one loaded from `HASHTABLE`. - unsafe { &*table } -} - -// Grow the hash table so that it is big enough for the given number of threads. -// This isn't performance-critical since it is only done when a ThreadData is -// created, which only happens once per thread. -fn grow_hashtable(num_threads: usize) { - // Lock all buckets in the existing table and get a reference to it - let old_table = loop { - let table = get_hashtable(); - - // Check if we need to resize the existing table - if table.entries.len() >= LOAD_FACTOR * num_threads { - return; - } - - // Lock all buckets in the old table - for bucket in &table.entries[..] { - bucket.mutex.lock(); - } - - // Now check if our table is still the latest one. Another thread could - // have grown the hash table between us reading HASHTABLE and locking - // the buckets. - if HASHTABLE.load(Ordering::Relaxed) == table as *const _ as *mut _ { - break table; - } - - // Unlock buckets and try again - for bucket in &table.entries[..] { - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } - }; - - // Create the new table - let mut new_table = HashTable::new(num_threads, old_table); - - // Move the entries from the old table to the new one - for bucket in &old_table.entries[..] { - // SAFETY: The park, unpark* and check_wait_graph_fast functions create only correct linked - // lists. All `ThreadData` instances in these lists will remain valid as long as they are - // present in the lists, meaning as long as their threads are parked. - unsafe { rehash_bucket_into(bucket, &mut new_table) }; - } - - // Publish the new table. No races are possible at this point because - // any other thread trying to grow the hash table is blocked on the bucket - // locks in the old table. - HASHTABLE.store(Box::into_raw(new_table), Ordering::Release); - - // Unlock all buckets in the old table - for bucket in &old_table.entries[..] { - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } -} - -/// Iterate through all `ThreadData` objects in the bucket and insert them into the given table -/// in the bucket their key correspond to for this table. -/// -/// # Safety -/// -/// The given `bucket` must have a correctly constructed linked list under `queue_head`, containing -/// `ThreadData` instances that must stay valid at least as long as the given `table` is in use. -/// -/// The given `table` must only contain buckets with correctly constructed linked lists. -unsafe fn rehash_bucket_into(bucket: &'static Bucket, table: &mut HashTable) { - let mut current: *const ThreadData = bucket.queue_head.get(); - while !current.is_null() { - let next = (*current).next_in_queue.get(); - let hash = hash((*current).key.load(Ordering::Relaxed), table.hash_bits); - if table.entries[hash].queue_tail.get().is_null() { - table.entries[hash].queue_head.set(current); - } else { - (*table.entries[hash].queue_tail.get()) - .next_in_queue - .set(current); - } - table.entries[hash].queue_tail.set(current); - (*current).next_in_queue.set(ptr::null()); - current = next; - } -} - -// Hash function for addresses -#[cfg(target_pointer_width = "32")] -#[inline] -fn hash(key: usize, bits: u32) -> usize { - key.wrapping_mul(0x9E3779B9) >> (32 - bits) -} -#[cfg(target_pointer_width = "64")] -#[inline] -fn hash(key: usize, bits: u32) -> usize { - key.wrapping_mul(0x9E3779B97F4A7C15) >> (64 - bits) -} - -/// Locks the bucket for the given key and returns a reference to it. -/// The returned bucket must be unlocked again in order to not cause deadlocks. -#[inline] -fn lock_bucket(key: usize) -> &'static Bucket { - loop { - let hashtable = get_hashtable(); - - let hash = hash(key, hashtable.hash_bits); - let bucket = &hashtable.entries[hash]; - - // Lock the bucket - bucket.mutex.lock(); - - // If no other thread has rehashed the table before we grabbed the lock - // then we are good to go! The lock we grabbed prevents any rehashes. - if HASHTABLE.load(Ordering::Relaxed) == hashtable as *const _ as *mut _ { - return bucket; - } - - // Unlock the bucket and try again - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } -} - -/// Locks the bucket for the given key and returns a reference to it. But checks that the key -/// hasn't been changed in the meantime due to a requeue. -/// The returned bucket must be unlocked again in order to not cause deadlocks. -#[inline] -fn lock_bucket_checked(key: &AtomicUsize) -> (usize, &'static Bucket) { - loop { - let hashtable = get_hashtable(); - let current_key = key.load(Ordering::Relaxed); - - let hash = hash(current_key, hashtable.hash_bits); - let bucket = &hashtable.entries[hash]; - - // Lock the bucket - bucket.mutex.lock(); - - // Check that both the hash table and key are correct while the bucket - // is locked. Note that the key can't change once we locked the proper - // bucket for it, so we just keep trying until we have the correct key. - if HASHTABLE.load(Ordering::Relaxed) == hashtable as *const _ as *mut _ - && key.load(Ordering::Relaxed) == current_key - { - return (current_key, bucket); - } - - // Unlock the bucket and try again - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } -} - -/// Locks the two buckets for the given pair of keys and returns references to them. -/// The returned buckets must be unlocked again in order to not cause deadlocks. -/// -/// If both keys hash to the same value, both returned references will be to the same bucket. Be -/// careful to only unlock it once in this case, always use `unlock_bucket_pair`. -#[inline] -fn lock_bucket_pair(key1: usize, key2: usize) -> (&'static Bucket, &'static Bucket) { - loop { - let hashtable = get_hashtable(); - - let hash1 = hash(key1, hashtable.hash_bits); - let hash2 = hash(key2, hashtable.hash_bits); - - // Get the bucket at the lowest hash/index first - let bucket1 = if hash1 <= hash2 { - &hashtable.entries[hash1] - } else { - &hashtable.entries[hash2] - }; - - // Lock the first bucket - bucket1.mutex.lock(); - - // If no other thread has rehashed the table before we grabbed the lock - // then we are good to go! The lock we grabbed prevents any rehashes. - if HASHTABLE.load(Ordering::Relaxed) == hashtable as *const _ as *mut _ { - // Now lock the second bucket and return the two buckets - if hash1 == hash2 { - return (bucket1, bucket1); - } else if hash1 < hash2 { - let bucket2 = &hashtable.entries[hash2]; - bucket2.mutex.lock(); - return (bucket1, bucket2); - } else { - let bucket2 = &hashtable.entries[hash1]; - bucket2.mutex.lock(); - return (bucket2, bucket1); - } - } - - // Unlock the bucket and try again - // SAFETY: We hold the lock here, as required - unsafe { bucket1.mutex.unlock() }; - } -} - -/// Unlock a pair of buckets -/// -/// # Safety -/// -/// Both buckets must be locked -#[inline] -unsafe fn unlock_bucket_pair(bucket1: &Bucket, bucket2: &Bucket) { - bucket1.mutex.unlock(); - if !ptr::eq(bucket1, bucket2) { - bucket2.mutex.unlock(); - } -} - -/// Result of a park operation. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum ParkResult { - /// We were unparked by another thread with the given token. - Unparked(UnparkToken), - - /// The validation callback returned false. - Invalid, - - /// The timeout expired. - TimedOut, -} - -impl ParkResult { - /// Returns true if we were unparked by another thread. - #[inline] - pub fn is_unparked(self) -> bool { - if let ParkResult::Unparked(_) = self { - true - } else { - false - } - } -} - -/// Result of an unpark operation. -#[derive(Copy, Clone, Default, Eq, PartialEq, Debug)] -pub struct UnparkResult { - /// The number of threads that were unparked. - pub unparked_threads: usize, - - /// The number of threads that were requeued. - pub requeued_threads: usize, - - /// Whether there are any threads remaining in the queue. This only returns - /// true if a thread was unparked. - pub have_more_threads: bool, - - /// This is set to true on average once every 0.5ms for any given key. It - /// should be used to switch to a fair unlocking mechanism for a particular - /// unlock. - pub be_fair: bool, - - /// Private field so new fields can be added without breakage. - _sealed: (), -} - -/// Operation that `unpark_requeue` should perform. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum RequeueOp { - /// Abort the operation without doing anything. - Abort, - - /// Unpark one thread and requeue the rest onto the target queue. - UnparkOneRequeueRest, - - /// Requeue all threads onto the target queue. - RequeueAll, - - /// Unpark one thread and leave the rest parked. No requeuing is done. - UnparkOne, - - /// Requeue one thread and leave the rest parked on the original queue. - RequeueOne, -} - -/// Operation that `unpark_filter` should perform for each thread. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub enum FilterOp { - /// Unpark the thread and continue scanning the list of parked threads. - Unpark, - - /// Don't unpark the thread and continue scanning the list of parked threads. - Skip, - - /// Don't unpark the thread and stop scanning the list of parked threads. - Stop, -} - -/// A value which is passed from an unparker to a parked thread. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct UnparkToken(pub usize); - -/// A value associated with a parked thread which can be used by `unpark_filter`. -#[derive(Copy, Clone, Eq, PartialEq, Debug)] -pub struct ParkToken(pub usize); - -/// A default unpark token to use. -pub const DEFAULT_UNPARK_TOKEN: UnparkToken = UnparkToken(0); - -/// A default park token to use. -pub const DEFAULT_PARK_TOKEN: ParkToken = ParkToken(0); - -/// Parks the current thread in the queue associated with the given key. -/// -/// The `validate` function is called while the queue is locked and can abort -/// the operation by returning false. If `validate` returns true then the -/// current thread is appended to the queue and the queue is unlocked. -/// -/// The `before_sleep` function is called after the queue is unlocked but before -/// the thread is put to sleep. The thread will then sleep until it is unparked -/// or the given timeout is reached. -/// -/// The `timed_out` function is also called while the queue is locked, but only -/// if the timeout was reached. It is passed the key of the queue it was in when -/// it timed out, which may be different from the original key if -/// `unpark_requeue` was called. It is also passed a bool which indicates -/// whether it was the last thread in the queue. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `validate` and `timed_out` functions are called while the queue is -/// locked and must not panic or call into any function in `parking_lot`. -/// -/// The `before_sleep` function is called outside the queue lock and is allowed -/// to call `unpark_one`, `unpark_all`, `unpark_requeue` or `unpark_filter`, but -/// it is not allowed to call `park` or panic. -#[inline] -pub unsafe fn park( - key: usize, - validate: impl FnOnce() -> bool, - before_sleep: impl FnOnce(), - timed_out: impl FnOnce(usize, bool), - park_token: ParkToken, - timeout: Option, -) -> ParkResult { - // Grab our thread data, this also ensures that the hash table exists - with_thread_data(|thread_data| { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // If the validation function fails, just return - if !validate() { - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - return ParkResult::Invalid; - } - - // Append our thread data to the queue and unlock the bucket - thread_data.parked_with_timeout.set(timeout.is_some()); - thread_data.next_in_queue.set(ptr::null()); - thread_data.key.store(key, Ordering::Relaxed); - thread_data.park_token.set(park_token); - thread_data.parker.prepare_park(); - if !bucket.queue_head.get().is_null() { - (*bucket.queue_tail.get()).next_in_queue.set(thread_data); - } else { - bucket.queue_head.set(thread_data); - } - bucket.queue_tail.set(thread_data); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - - // Invoke the pre-sleep callback - before_sleep(); - - // Park our thread and determine whether we were woken up by an unpark - // or by our timeout. Note that this isn't precise: we can still be - // unparked since we are still in the queue. - let unparked = match timeout { - Some(timeout) => thread_data.parker.park_until(timeout), - None => { - thread_data.parker.park(); - // call deadlock detection on_unpark hook - deadlock::on_unpark(thread_data); - true - } - }; - - // If we were unparked, return now - if unparked { - return ParkResult::Unparked(thread_data.unpark_token.get()); - } - - // Lock our bucket again. Note that the hashtable may have been rehashed in - // the meantime. Our key may also have changed if we were requeued. - let (key, bucket) = lock_bucket_checked(&thread_data.key); - - // Now we need to check again if we were unparked or timed out. Unlike the - // last check this is precise because we hold the bucket lock. - if !thread_data.parker.timed_out() { - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - return ParkResult::Unparked(thread_data.unpark_token.get()); - } - - // We timed out, so we now need to remove our thread from the queue - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut was_last_thread = true; - while !current.is_null() { - if current == thread_data { - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } else { - // Scan the rest of the queue to see if there are any other - // entries with the given key. - let mut scan = next; - while !scan.is_null() { - if (*scan).key.load(Ordering::Relaxed) == key { - was_last_thread = false; - break; - } - scan = (*scan).next_in_queue.get(); - } - } - - // Callback to indicate that we timed out, and whether we were the - // last thread on the queue. - timed_out(key, was_last_thread); - break; - } else { - if (*current).key.load(Ordering::Relaxed) == key { - was_last_thread = false; - } - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // There should be no way for our thread to have been removed from the queue - // if we timed out. - debug_assert!(!current.is_null()); - - // Unlock the bucket, we are done - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - ParkResult::TimedOut - }) -} - -/// Unparks one thread from the queue associated with the given key. -/// -/// The `callback` function is called while the queue is locked and before the -/// target thread is woken up. The `UnparkResult` argument to the function -/// indicates whether a thread was found in the queue and whether this was the -/// last thread in the queue. This value is also returned by `unpark_one`. -/// -/// The `callback` function should return an `UnparkToken` value which will be -/// passed to the thread that is unparked. If no thread is unparked then the -/// returned value is ignored. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `callback` function is called while the queue is locked and must not -/// panic or call into any function in `parking_lot`. -#[inline] -pub unsafe fn unpark_one( - key: usize, - callback: impl FnOnce(UnparkResult) -> UnparkToken, -) -> UnparkResult { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // Find a thread with a matching key and remove it from the queue - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut result = UnparkResult::default(); - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key { - // Remove the thread from the queue - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } else { - // Scan the rest of the queue to see if there are any other - // entries with the given key. - let mut scan = next; - while !scan.is_null() { - if (*scan).key.load(Ordering::Relaxed) == key { - result.have_more_threads = true; - break; - } - scan = (*scan).next_in_queue.get(); - } - } - - // Invoke the callback before waking up the thread - result.unparked_threads = 1; - result.be_fair = (*bucket.fair_timeout.get()).should_timeout(); - let token = callback(result); - - // Set the token for the target thread - (*current).unpark_token.set(token); - - // This is a bit tricky: we first lock the ThreadParker to prevent - // the thread from exiting and freeing its ThreadData if its wait - // times out. Then we unlock the queue since we don't want to keep - // the queue locked while we perform a system call. Finally we wake - // up the parked thread. - let handle = (*current).parker.unpark_lock(); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - handle.unpark(); - - return result; - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // No threads with a matching key were found in the bucket - callback(result); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - result -} - -/// Unparks all threads in the queue associated with the given key. -/// -/// The given `UnparkToken` is passed to all unparked threads. -/// -/// This function returns the number of threads that were unparked. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -#[inline] -pub unsafe fn unpark_all(key: usize, unpark_token: UnparkToken) -> usize { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // Remove all threads with the given key in the bucket - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut threads = SmallVec::<[_; 8]>::new(); - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key { - // Remove the thread from the queue - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } - - // Set the token for the target thread - (*current).unpark_token.set(unpark_token); - - // Don't wake up threads while holding the queue lock. See comment - // in unpark_one. For now just record which threads we need to wake - // up. - threads.push((*current).parker.unpark_lock()); - current = next; - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // Unlock the bucket - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - - // Now that we are outside the lock, wake up all the threads that we removed - // from the queue. - let num_threads = threads.len(); - for handle in threads.into_iter() { - handle.unpark(); - } - - num_threads -} - -/// Removes all threads from the queue associated with `key_from`, optionally -/// unparks the first one and requeues the rest onto the queue associated with -/// `key_to`. -/// -/// The `validate` function is called while both queues are locked. Its return -/// value will determine which operation is performed, or whether the operation -/// should be aborted. See `RequeueOp` for details about the different possible -/// return values. -/// -/// The `callback` function is also called while both queues are locked. It is -/// passed the `RequeueOp` returned by `validate` and an `UnparkResult` -/// indicating whether a thread was unparked and whether there are threads still -/// parked in the new queue. This `UnparkResult` value is also returned by -/// `unpark_requeue`. -/// -/// The `callback` function should return an `UnparkToken` value which will be -/// passed to the thread that is unparked. If no thread is unparked then the -/// returned value is ignored. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `validate` and `callback` functions are called while the queue is locked -/// and must not panic or call into any function in `parking_lot`. -#[inline] -pub unsafe fn unpark_requeue( - key_from: usize, - key_to: usize, - validate: impl FnOnce() -> RequeueOp, - callback: impl FnOnce(RequeueOp, UnparkResult) -> UnparkToken, -) -> UnparkResult { - // Lock the two buckets for the given key - let (bucket_from, bucket_to) = lock_bucket_pair(key_from, key_to); - - // If the validation function fails, just return - let mut result = UnparkResult::default(); - let op = validate(); - if op == RequeueOp::Abort { - // SAFETY: Both buckets are locked, as required. - unlock_bucket_pair(bucket_from, bucket_to); - return result; - } - - // Remove all threads with the given key in the source bucket - let mut link = &bucket_from.queue_head; - let mut current = bucket_from.queue_head.get(); - let mut previous = ptr::null(); - let mut requeue_threads: *const ThreadData = ptr::null(); - let mut requeue_threads_tail: *const ThreadData = ptr::null(); - let mut wakeup_thread = None; - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key_from { - // Remove the thread from the queue - let next = (*current).next_in_queue.get(); - link.set(next); - if bucket_from.queue_tail.get() == current { - bucket_from.queue_tail.set(previous); - } - - // Prepare the first thread for wakeup and requeue the rest. - if (op == RequeueOp::UnparkOneRequeueRest || op == RequeueOp::UnparkOne) - && wakeup_thread.is_none() - { - wakeup_thread = Some(current); - result.unparked_threads = 1; - } else { - if !requeue_threads.is_null() { - (*requeue_threads_tail).next_in_queue.set(current); - } else { - requeue_threads = current; - } - requeue_threads_tail = current; - (*current).key.store(key_to, Ordering::Relaxed); - result.requeued_threads += 1; - } - if op == RequeueOp::UnparkOne || op == RequeueOp::RequeueOne { - // Scan the rest of the queue to see if there are any other - // entries with the given key. - let mut scan = next; - while !scan.is_null() { - if (*scan).key.load(Ordering::Relaxed) == key_from { - result.have_more_threads = true; - break; - } - scan = (*scan).next_in_queue.get(); - } - break; - } - current = next; - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // Add the requeued threads to the destination bucket - if !requeue_threads.is_null() { - (*requeue_threads_tail).next_in_queue.set(ptr::null()); - if !bucket_to.queue_head.get().is_null() { - (*bucket_to.queue_tail.get()) - .next_in_queue - .set(requeue_threads); - } else { - bucket_to.queue_head.set(requeue_threads); - } - bucket_to.queue_tail.set(requeue_threads_tail); - } - - // Invoke the callback before waking up the thread - if result.unparked_threads != 0 { - result.be_fair = (*bucket_from.fair_timeout.get()).should_timeout(); - } - let token = callback(op, result); - - // See comment in unpark_one for why we mess with the locking - if let Some(wakeup_thread) = wakeup_thread { - (*wakeup_thread).unpark_token.set(token); - let handle = (*wakeup_thread).parker.unpark_lock(); - // SAFETY: Both buckets are locked, as required. - unlock_bucket_pair(bucket_from, bucket_to); - handle.unpark(); - } else { - // SAFETY: Both buckets are locked, as required. - unlock_bucket_pair(bucket_from, bucket_to); - } - - result -} - -/// Unparks a number of threads from the front of the queue associated with -/// `key` depending on the results of a filter function which inspects the -/// `ParkToken` associated with each thread. -/// -/// The `filter` function is called for each thread in the queue or until -/// `FilterOp::Stop` is returned. This function is passed the `ParkToken` -/// associated with a particular thread, which is unparked if `FilterOp::Unpark` -/// is returned. -/// -/// The `callback` function is also called while both queues are locked. It is -/// passed an `UnparkResult` indicating the number of threads that were unparked -/// and whether there are still parked threads in the queue. This `UnparkResult` -/// value is also returned by `unpark_filter`. -/// -/// The `callback` function should return an `UnparkToken` value which will be -/// passed to all threads that are unparked. If no thread is unparked then the -/// returned value is ignored. -/// -/// # Safety -/// -/// You should only call this function with an address that you control, since -/// you could otherwise interfere with the operation of other synchronization -/// primitives. -/// -/// The `filter` and `callback` functions are called while the queue is locked -/// and must not panic or call into any function in `parking_lot`. -#[inline] -pub unsafe fn unpark_filter( - key: usize, - mut filter: impl FnMut(ParkToken) -> FilterOp, - callback: impl FnOnce(UnparkResult) -> UnparkToken, -) -> UnparkResult { - // Lock the bucket for the given key - let bucket = lock_bucket(key); - - // Go through the queue looking for threads with a matching key - let mut link = &bucket.queue_head; - let mut current = bucket.queue_head.get(); - let mut previous = ptr::null(); - let mut threads = SmallVec::<[_; 8]>::new(); - let mut result = UnparkResult::default(); - while !current.is_null() { - if (*current).key.load(Ordering::Relaxed) == key { - // Call the filter function with the thread's ParkToken - let next = (*current).next_in_queue.get(); - match filter((*current).park_token.get()) { - FilterOp::Unpark => { - // Remove the thread from the queue - link.set(next); - if bucket.queue_tail.get() == current { - bucket.queue_tail.set(previous); - } - - // Add the thread to our list of threads to unpark - threads.push((current, None)); - - current = next; - } - FilterOp::Skip => { - result.have_more_threads = true; - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - FilterOp::Stop => { - result.have_more_threads = true; - break; - } - } - } else { - link = &(*current).next_in_queue; - previous = current; - current = link.get(); - } - } - - // Invoke the callback before waking up the threads - result.unparked_threads = threads.len(); - if result.unparked_threads != 0 { - result.be_fair = (*bucket.fair_timeout.get()).should_timeout(); - } - let token = callback(result); - - // Pass the token to all threads that are going to be unparked and prepare - // them for unparking. - for t in threads.iter_mut() { - (*t.0).unpark_token.set(token); - t.1 = Some((*t.0).parker.unpark_lock()); - } - - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - - // Now that we are outside the lock, wake up all the threads that we removed - // from the queue. - for (_, handle) in threads.into_iter() { - handle.unchecked_unwrap().unpark(); - } - - result -} - -/// \[Experimental\] Deadlock detection -/// -/// Enabled via the `deadlock_detection` feature flag. -pub mod deadlock { - #[cfg(feature = "deadlock_detection")] - use super::deadlock_impl; - - #[cfg(feature = "deadlock_detection")] - pub(super) use super::deadlock_impl::DeadlockData; - - /// Acquire a resource identified by key in the deadlock detector - /// Noop if deadlock_detection feature isn't enabled. - /// - /// # Safety - /// - /// Call after the resource is acquired - #[inline] - pub unsafe fn acquire_resource(_key: usize) { - #[cfg(feature = "deadlock_detection")] - deadlock_impl::acquire_resource(_key); - } - - /// Release a resource identified by key in the deadlock detector. - /// Noop if deadlock_detection feature isn't enabled. - /// - /// # Panics - /// - /// Panics if the resource was already released or wasn't acquired in this thread. - /// - /// # Safety - /// - /// Call before the resource is released - #[inline] - pub unsafe fn release_resource(_key: usize) { - #[cfg(feature = "deadlock_detection")] - deadlock_impl::release_resource(_key); - } - - /// Returns all deadlocks detected *since* the last call. - /// Each cycle consist of a vector of `DeadlockedThread`. - #[cfg(feature = "deadlock_detection")] - #[inline] - pub fn check_deadlock() -> Vec> { - deadlock_impl::check_deadlock() - } - - #[inline] - pub(super) unsafe fn on_unpark(_td: &super::ThreadData) { - #[cfg(feature = "deadlock_detection")] - deadlock_impl::on_unpark(_td); - } -} - -#[cfg(feature = "deadlock_detection")] -mod deadlock_impl { - use super::{get_hashtable, lock_bucket, with_thread_data, ThreadData, NUM_THREADS}; - use crate::thread_parker::{ThreadParkerT, UnparkHandleT}; - use crate::word_lock::WordLock; - use backtrace::Backtrace; - use petgraph; - use petgraph::graphmap::DiGraphMap; - use std::cell::{Cell, UnsafeCell}; - use std::collections::HashSet; - use std::sync::atomic::Ordering; - use std::sync::mpsc; - use thread_id; - - /// Representation of a deadlocked thread - pub struct DeadlockedThread { - thread_id: usize, - backtrace: Backtrace, - } - - impl DeadlockedThread { - /// The system thread id - pub fn thread_id(&self) -> usize { - self.thread_id - } - - /// The thread backtrace - pub fn backtrace(&self) -> &Backtrace { - &self.backtrace - } - } - - pub struct DeadlockData { - // Currently owned resources (keys) - resources: UnsafeCell>, - - // Set when there's a pending callstack request - deadlocked: Cell, - - // Sender used to report the backtrace - backtrace_sender: UnsafeCell>>, - - // System thread id - thread_id: usize, - } - - impl DeadlockData { - pub fn new() -> Self { - DeadlockData { - resources: UnsafeCell::new(Vec::new()), - deadlocked: Cell::new(false), - backtrace_sender: UnsafeCell::new(None), - thread_id: thread_id::get(), - } - } - } - - pub(super) unsafe fn on_unpark(td: &ThreadData) { - if td.deadlock_data.deadlocked.get() { - let sender = (*td.deadlock_data.backtrace_sender.get()).take().unwrap(); - sender - .send(DeadlockedThread { - thread_id: td.deadlock_data.thread_id, - backtrace: Backtrace::new(), - }) - .unwrap(); - // make sure to close this sender - drop(sender); - - // park until the end of the time - td.parker.prepare_park(); - td.parker.park(); - unreachable!("unparked deadlocked thread!"); - } - } - - pub unsafe fn acquire_resource(key: usize) { - with_thread_data(|thread_data| { - (*thread_data.deadlock_data.resources.get()).push(key); - }); - } - - pub unsafe fn release_resource(key: usize) { - with_thread_data(|thread_data| { - let resources = &mut (*thread_data.deadlock_data.resources.get()); - - // There is only one situation where we can fail to find the - // resource: we are currently running TLS destructors and our - // ThreadData has already been freed. There isn't much we can do - // about it at this point, so just ignore it. - if let Some(p) = resources.iter().rposition(|x| *x == key) { - resources.swap_remove(p); - } - }); - } - - pub fn check_deadlock() -> Vec> { - unsafe { - // fast pass - if check_wait_graph_fast() { - // double check - check_wait_graph_slow() - } else { - Vec::new() - } - } - } - - // Simple algorithm that builds a wait graph f the threads and the resources, - // then checks for the presence of cycles (deadlocks). - // This variant isn't precise as it doesn't lock the entire table before checking - unsafe fn check_wait_graph_fast() -> bool { - let table = get_hashtable(); - let thread_count = NUM_THREADS.load(Ordering::Relaxed); - let mut graph = DiGraphMap::::with_capacity(thread_count * 2, thread_count * 2); - - for b in &(*table).entries[..] { - b.mutex.lock(); - let mut current = b.queue_head.get(); - while !current.is_null() { - if !(*current).parked_with_timeout.get() - && !(*current).deadlock_data.deadlocked.get() - { - // .resources are waiting for their owner - for &resource in &(*(*current).deadlock_data.resources.get()) { - graph.add_edge(resource, current as usize, ()); - } - // owner waits for resource .key - graph.add_edge(current as usize, (*current).key.load(Ordering::Relaxed), ()); - } - current = (*current).next_in_queue.get(); - } - // SAFETY: We hold the lock here, as required - b.mutex.unlock(); - } - - petgraph::algo::is_cyclic_directed(&graph) - } - - #[derive(Hash, PartialEq, Eq, PartialOrd, Ord, Copy, Clone)] - enum WaitGraphNode { - Thread(*const ThreadData), - Resource(usize), - } - - use self::WaitGraphNode::*; - - // Contrary to the _fast variant this locks the entries table before looking for cycles. - // Returns all detected thread wait cycles. - // Note that once a cycle is reported it's never reported again. - unsafe fn check_wait_graph_slow() -> Vec> { - static DEADLOCK_DETECTION_LOCK: WordLock = WordLock::new(); - DEADLOCK_DETECTION_LOCK.lock(); - - let mut table = get_hashtable(); - loop { - // Lock all buckets in the old table - for b in &table.entries[..] { - b.mutex.lock(); - } - - // Now check if our table is still the latest one. Another thread could - // have grown the hash table between us getting and locking the hash table. - let new_table = get_hashtable(); - if new_table as *const _ == table as *const _ { - break; - } - - // Unlock buckets and try again - for b in &table.entries[..] { - // SAFETY: We hold the lock here, as required - b.mutex.unlock(); - } - - table = new_table; - } - - let thread_count = NUM_THREADS.load(Ordering::Relaxed); - let mut graph = - DiGraphMap::::with_capacity(thread_count * 2, thread_count * 2); - - for b in &table.entries[..] { - let mut current = b.queue_head.get(); - while !current.is_null() { - if !(*current).parked_with_timeout.get() - && !(*current).deadlock_data.deadlocked.get() - { - // .resources are waiting for their owner - for &resource in &(*(*current).deadlock_data.resources.get()) { - graph.add_edge(Resource(resource), Thread(current), ()); - } - // owner waits for resource .key - graph.add_edge( - Thread(current), - Resource((*current).key.load(Ordering::Relaxed)), - (), - ); - } - current = (*current).next_in_queue.get(); - } - } - - for b in &table.entries[..] { - // SAFETY: We hold the lock here, as required - b.mutex.unlock(); - } - - // find cycles - let cycles = graph_cycles(&graph); - - let mut results = Vec::with_capacity(cycles.len()); - - for cycle in cycles { - let (sender, receiver) = mpsc::channel(); - for td in cycle { - let bucket = lock_bucket((*td).key.load(Ordering::Relaxed)); - (*td).deadlock_data.deadlocked.set(true); - *(*td).deadlock_data.backtrace_sender.get() = Some(sender.clone()); - let handle = (*td).parker.unpark_lock(); - // SAFETY: We hold the lock here, as required - bucket.mutex.unlock(); - // unpark the deadlocked thread! - // on unpark it'll notice the deadlocked flag and report back - handle.unpark(); - } - // make sure to drop our sender before collecting results - drop(sender); - results.push(receiver.iter().collect()); - } - - DEADLOCK_DETECTION_LOCK.unlock(); - - results - } - - // normalize a cycle to start with the "smallest" node - fn normalize_cycle(input: &[T]) -> Vec { - let min_pos = input - .iter() - .enumerate() - .min_by_key(|&(_, &t)| t) - .map(|(p, _)| p) - .unwrap_or(0); - input - .iter() - .cycle() - .skip(min_pos) - .take(input.len()) - .cloned() - .collect() - } - - // returns all thread cycles in the wait graph - fn graph_cycles(g: &DiGraphMap) -> Vec> { - use petgraph::visit::depth_first_search; - use petgraph::visit::DfsEvent; - use petgraph::visit::NodeIndexable; - - let mut cycles = HashSet::new(); - let mut path = Vec::with_capacity(g.node_bound()); - // start from threads to get the correct threads cycle - let threads = g - .nodes() - .filter(|n| if let &Thread(_) = n { true } else { false }); - - depth_first_search(g, threads, |e| match e { - DfsEvent::Discover(Thread(n), _) => path.push(n), - DfsEvent::Finish(Thread(_), _) => { - path.pop(); - } - DfsEvent::BackEdge(_, Thread(n)) => { - let from = path.iter().rposition(|&i| i == n).unwrap(); - cycles.insert(normalize_cycle(&path[from..])); - } - _ => (), - }); - - cycles.iter().cloned().collect() - } -} - -#[cfg(test)] -mod tests { - use super::{ThreadData, DEFAULT_PARK_TOKEN, DEFAULT_UNPARK_TOKEN}; - use std::{ - ptr, - sync::{ - atomic::{AtomicIsize, AtomicPtr, AtomicUsize, Ordering}, - Arc, - }, - thread, - time::Duration, - }; - - /// Calls a closure for every `ThreadData` currently parked on a given key - fn for_each(key: usize, mut f: impl FnMut(&ThreadData)) { - let bucket = super::lock_bucket(key); - - let mut current: *const ThreadData = bucket.queue_head.get(); - while !current.is_null() { - let current_ref = unsafe { &*current }; - if current_ref.key.load(Ordering::Relaxed) == key { - f(current_ref); - } - current = current_ref.next_in_queue.get(); - } - - // SAFETY: We hold the lock here, as required - unsafe { bucket.mutex.unlock() }; - } - - macro_rules! test { - ( $( $name:ident( - repeats: $repeats:expr, - latches: $latches:expr, - delay: $delay:expr, - threads: $threads:expr, - single_unparks: $single_unparks:expr); - )* ) => { - $(#[test] - fn $name() { - let delay = Duration::from_micros($delay); - for _ in 0..$repeats { - run_parking_test($latches, delay, $threads, $single_unparks); - } - })* - }; - } - - test! { - unpark_all_one_fast( - repeats: 10000, latches: 1, delay: 0, threads: 1, single_unparks: 0 - ); - unpark_all_hundred_fast( - repeats: 100, latches: 1, delay: 0, threads: 100, single_unparks: 0 - ); - unpark_one_one_fast( - repeats: 1000, latches: 1, delay: 0, threads: 1, single_unparks: 1 - ); - unpark_one_hundred_fast( - repeats: 20, latches: 1, delay: 0, threads: 100, single_unparks: 100 - ); - unpark_one_fifty_then_fifty_all_fast( - repeats: 50, latches: 1, delay: 0, threads: 100, single_unparks: 50 - ); - unpark_all_one( - repeats: 100, latches: 1, delay: 10000, threads: 1, single_unparks: 0 - ); - unpark_all_hundred( - repeats: 100, latches: 1, delay: 10000, threads: 100, single_unparks: 0 - ); - unpark_one_one( - repeats: 10, latches: 1, delay: 10000, threads: 1, single_unparks: 1 - ); - unpark_one_fifty( - repeats: 1, latches: 1, delay: 10000, threads: 50, single_unparks: 50 - ); - unpark_one_fifty_then_fifty_all( - repeats: 2, latches: 1, delay: 10000, threads: 100, single_unparks: 50 - ); - hundred_unpark_all_one_fast( - repeats: 100, latches: 100, delay: 0, threads: 1, single_unparks: 0 - ); - hundred_unpark_all_one( - repeats: 1, latches: 100, delay: 10000, threads: 1, single_unparks: 0 - ); - } - - fn run_parking_test( - num_latches: usize, - delay: Duration, - num_threads: usize, - num_single_unparks: usize, - ) { - let mut tests = Vec::with_capacity(num_latches); - - for _ in 0..num_latches { - let test = Arc::new(SingleLatchTest::new(num_threads)); - let mut threads = Vec::with_capacity(num_threads); - for _ in 0..num_threads { - let test = test.clone(); - threads.push(thread::spawn(move || test.run())); - } - tests.push((test, threads)); - } - - for unpark_index in 0..num_single_unparks { - thread::sleep(delay); - for (test, _) in &tests { - test.unpark_one(unpark_index); - } - } - - for (test, threads) in tests { - test.finish(num_single_unparks); - for thread in threads { - thread.join().expect("Test thread panic"); - } - } - } - - struct SingleLatchTest { - semaphore: AtomicIsize, - num_awake: AtomicUsize, - /// Holds the pointer to the last *unprocessed* woken up thread. - last_awoken: AtomicPtr, - /// Total number of threads participating in this test. - num_threads: usize, - } - - impl SingleLatchTest { - pub fn new(num_threads: usize) -> Self { - Self { - // This implements a fair (FIFO) semaphore, and it starts out unavailable. - semaphore: AtomicIsize::new(0), - num_awake: AtomicUsize::new(0), - last_awoken: AtomicPtr::new(ptr::null_mut()), - num_threads, - } - } - - pub fn run(&self) { - // Get one slot from the semaphore - self.down(); - - // Report back to the test verification code that this thread woke up - let this_thread_ptr = super::with_thread_data(|t| t as *const _ as *mut _); - self.last_awoken.store(this_thread_ptr, Ordering::SeqCst); - self.num_awake.fetch_add(1, Ordering::SeqCst); - } - - pub fn unpark_one(&self, single_unpark_index: usize) { - // last_awoken should be null at all times except between self.up() and at the bottom - // of this method where it's reset to null again - assert!(self.last_awoken.load(Ordering::SeqCst).is_null()); - - let mut queue: Vec<*mut ThreadData> = Vec::with_capacity(self.num_threads); - for_each(self.semaphore_addr(), |thread_data| { - queue.push(thread_data as *const _ as *mut _); - }); - assert!(queue.len() <= self.num_threads - single_unpark_index); - - let num_awake_before_up = self.num_awake.load(Ordering::SeqCst); - - self.up(); - - // Wait for a parked thread to wake up and update num_awake + last_awoken. - while self.num_awake.load(Ordering::SeqCst) != num_awake_before_up + 1 { - thread::yield_now(); - } - - // At this point the other thread should have set last_awoken inside the run() method - let last_awoken = self.last_awoken.load(Ordering::SeqCst); - assert!(!last_awoken.is_null()); - if !queue.is_empty() && queue[0] != last_awoken { - panic!( - "Woke up wrong thread:\n\tqueue: {:?}\n\tlast awoken: {:?}", - queue, last_awoken - ); - } - self.last_awoken.store(ptr::null_mut(), Ordering::SeqCst); - } - - pub fn finish(&self, num_single_unparks: usize) { - // The amount of threads not unparked via unpark_one - let mut num_threads_left = self.num_threads.checked_sub(num_single_unparks).unwrap(); - - // Wake remaining threads up with unpark_all. Has to be in a loop, because there might - // still be threads that has not yet parked. - while num_threads_left > 0 { - let mut num_waiting_on_address = 0; - for_each(self.semaphore_addr(), |_thread_data| { - num_waiting_on_address += 1; - }); - assert!(num_waiting_on_address <= num_threads_left); - - let num_awake_before_unpark = self.num_awake.load(Ordering::SeqCst); - - let num_unparked = - unsafe { super::unpark_all(self.semaphore_addr(), DEFAULT_UNPARK_TOKEN) }; - assert!(num_unparked >= num_waiting_on_address); - assert!(num_unparked <= num_threads_left); - - // Wait for all unparked threads to wake up and update num_awake + last_awoken. - while self.num_awake.load(Ordering::SeqCst) - != num_awake_before_unpark + num_unparked - { - thread::yield_now() - } - - num_threads_left = num_threads_left.checked_sub(num_unparked).unwrap(); - } - // By now, all threads should have been woken up - assert_eq!(self.num_awake.load(Ordering::SeqCst), self.num_threads); - - // Make sure no thread is parked on our semaphore address - let mut num_waiting_on_address = 0; - for_each(self.semaphore_addr(), |_thread_data| { - num_waiting_on_address += 1; - }); - assert_eq!(num_waiting_on_address, 0); - } - - pub fn down(&self) { - let old_semaphore_value = self.semaphore.fetch_sub(1, Ordering::SeqCst); - - if old_semaphore_value > 0 { - // We acquired the semaphore. Done. - return; - } - - // We need to wait. - let validate = || true; - let before_sleep = || {}; - let timed_out = |_, _| {}; - unsafe { - super::park( - self.semaphore_addr(), - validate, - before_sleep, - timed_out, - DEFAULT_PARK_TOKEN, - None, - ); - } - } - - pub fn up(&self) { - let old_semaphore_value = self.semaphore.fetch_add(1, Ordering::SeqCst); - - // Check if anyone was waiting on the semaphore. If they were, then pass ownership to them. - if old_semaphore_value < 0 { - // We need to continue until we have actually unparked someone. It might be that - // the thread we want to pass ownership to has decremented the semaphore counter, - // but not yet parked. - loop { - match unsafe { - super::unpark_one(self.semaphore_addr(), |_| DEFAULT_UNPARK_TOKEN) - .unparked_threads - } { - 1 => break, - 0 => (), - i => panic!("Should not wake up {} threads", i), - } - } - } - } - - fn semaphore_addr(&self) -> usize { - &self.semaphore as *const _ as usize - } - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/spinwait.rs b/vendor/parking_lot_core-0.7.2/src/spinwait.rs deleted file mode 100644 index ad0327a3ae..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/spinwait.rs +++ /dev/null @@ -1,74 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::thread_parker; -use std::sync::atomic::spin_loop_hint; - -// Wastes some CPU time for the given number of iterations, -// using a hint to indicate to the CPU that we are spinning. -#[inline] -fn cpu_relax(iterations: u32) { - for _ in 0..iterations { - spin_loop_hint() - } -} - -/// A counter used to perform exponential backoff in spin loops. -#[derive(Default)] -pub struct SpinWait { - counter: u32, -} - -impl SpinWait { - /// Creates a new `SpinWait`. - #[inline] - pub fn new() -> Self { - Self::default() - } - - /// Resets a `SpinWait` to its initial state. - #[inline] - pub fn reset(&mut self) { - self.counter = 0; - } - - /// Spins until the sleep threshold has been reached. - /// - /// This function returns whether the sleep threshold has been reached, at - /// which point further spinning has diminishing returns and the thread - /// should be parked instead. - /// - /// The spin strategy will initially use a CPU-bound loop but will fall back - /// to yielding the CPU to the OS after a few iterations. - #[inline] - pub fn spin(&mut self) -> bool { - if self.counter >= 10 { - return false; - } - self.counter += 1; - if self.counter <= 3 { - cpu_relax(1 << self.counter); - } else { - thread_parker::thread_yield(); - } - true - } - - /// Spins without yielding the thread to the OS. - /// - /// Instead, the backoff is simply capped at a maximum value. This can be - /// used to improve throughput in `compare_exchange` loops that have high - /// contention. - #[inline] - pub fn spin_no_yield(&mut self) { - self.counter += 1; - if self.counter > 10 { - self.counter = 10; - } - cpu_relax(1 << self.counter); - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/cloudabi.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/cloudabi.rs deleted file mode 100644 index 520cc72990..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/cloudabi.rs +++ /dev/null @@ -1,304 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use cloudabi as abi; -use core::{ - cell::Cell, - mem::{self, MaybeUninit}, - sync::atomic::{AtomicU32, Ordering}, -}; -use std::{convert::TryFrom, thread, time::Instant}; - -extern "C" { - #[thread_local] - static __pthread_thread_id: abi::tid; -} - -struct Lock { - lock: AtomicU32, -} - -impl Lock { - pub fn new() -> Self { - Lock { - lock: AtomicU32::new(abi::LOCK_UNLOCKED.0), - } - } - - /// # Safety - /// - /// See `Lock::lock`. - unsafe fn try_lock(&self) -> Option { - // Attempt to acquire the lock. - if let Err(old) = self.lock.compare_exchange( - abi::LOCK_UNLOCKED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - Ordering::Acquire, - Ordering::Relaxed, - ) { - // Failure. Crash upon recursive acquisition. - debug_assert_ne!( - old & !abi::LOCK_KERNEL_MANAGED.0, - __pthread_thread_id.0 | abi::LOCK_WRLOCKED.0, - "Attempted to recursive write-lock a lock", - ); - None - } else { - Some(LockGuard { lock: &self.lock }) - } - } - - /// # Safety - /// - /// This method is unsafe because the `LockGuard` has a raw pointer into this `Lock` - /// that it will access on drop to unlock the lock. So make sure the `LockGuard` goes - /// out of scope before the `Lock` it came from moves or goes out of scope. - pub unsafe fn lock(&self) -> LockGuard { - self.try_lock().unwrap_or_else(|| { - // Call into the kernel to acquire a write lock. - let subscription = abi::subscription { - type_: abi::eventtype::LOCK_WRLOCK, - union: abi::subscription_union { - lock: abi::subscription_lock { - lock: self.ptr(), - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event = MaybeUninit::::uninit(); - let mut nevents: usize = 0; - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, &mut nevents); - debug_assert_eq!(ret, abi::errno::SUCCESS); - debug_assert_eq!(event.assume_init().error, abi::errno::SUCCESS); - - LockGuard { lock: &self.lock } - }) - } - - fn ptr(&self) -> *mut abi::lock { - &self.lock as *const AtomicU32 as *mut abi::lock - } -} - -struct LockGuard { - lock: *const AtomicU32, -} - -impl LockGuard { - fn ptr(&self) -> *mut abi::lock { - self.lock as *mut abi::lock - } -} - -impl Drop for LockGuard { - fn drop(&mut self) { - let lock = unsafe { &*self.lock }; - debug_assert_eq!( - lock.load(Ordering::Relaxed) & !abi::LOCK_KERNEL_MANAGED.0, - unsafe { __pthread_thread_id.0 } | abi::LOCK_WRLOCKED.0, - "This lock is not write-locked by this thread" - ); - - if !lock - .compare_exchange( - unsafe { __pthread_thread_id.0 } | abi::LOCK_WRLOCKED.0, - abi::LOCK_UNLOCKED.0, - Ordering::Release, - Ordering::Relaxed, - ) - .is_ok() - { - // Lock is managed by kernelspace. Call into the kernel - // to unblock waiting threads. - let ret = unsafe { abi::lock_unlock(self.lock as *mut abi::lock, abi::scope::PRIVATE) }; - debug_assert_eq!(ret, abi::errno::SUCCESS); - } - } -} - -struct Condvar { - condvar: AtomicU32, -} - -impl Condvar { - pub fn new() -> Self { - Condvar { - condvar: AtomicU32::new(abi::CONDVAR_HAS_NO_WAITERS.0), - } - } - - pub fn wait(&self, lock: &LockGuard) { - unsafe { - let subscription = abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: self.ptr(), - condvar_scope: abi::scope::PRIVATE, - lock: lock.ptr(), - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }; - let mut event = MaybeUninit::::uninit(); - let mut nevents: usize = 0; - - let ret = abi::poll(&subscription, event.as_mut_ptr(), 1, &mut nevents); - debug_assert_eq!(ret, abi::errno::SUCCESS); - debug_assert_eq!(event.assume_init().error, abi::errno::SUCCESS); - } - } - - /// Waits for a signal on the condvar. - /// Returns false if it times out before anyone notified us. - pub fn wait_timeout(&self, lock: &LockGuard, timeout: abi::timestamp) -> bool { - unsafe { - let subscriptions = [ - abi::subscription { - type_: abi::eventtype::CONDVAR, - union: abi::subscription_union { - condvar: abi::subscription_condvar { - condvar: self.ptr(), - condvar_scope: abi::scope::PRIVATE, - lock: lock.ptr(), - lock_scope: abi::scope::PRIVATE, - }, - }, - ..mem::zeroed() - }, - abi::subscription { - type_: abi::eventtype::CLOCK, - union: abi::subscription_union { - clock: abi::subscription_clock { - clock_id: abi::clockid::MONOTONIC, - timeout, - ..mem::zeroed() - }, - }, - ..mem::zeroed() - }, - ]; - let mut events = MaybeUninit::<[abi::event; 2]>::uninit(); - let mut nevents: usize = 0; - - let ret = abi::poll( - subscriptions.as_ptr(), - events.as_mut_ptr() as *mut _, - 2, - &mut nevents, - ); - debug_assert_eq!(ret, abi::errno::SUCCESS); - let events = events.assume_init(); - for i in 0..nevents { - debug_assert_eq!(events[i].error, abi::errno::SUCCESS); - if events[i].type_ == abi::eventtype::CONDVAR { - return true; - } - } - } - false - } - - pub fn notify(&self) { - let ret = unsafe { abi::condvar_signal(self.ptr(), abi::scope::PRIVATE, 1) }; - debug_assert_eq!(ret, abi::errno::SUCCESS); - } - - fn ptr(&self) -> *mut abi::condvar { - &self.condvar as *const AtomicU32 as *mut abi::condvar - } -} - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - should_park: Cell, - lock: Lock, - condvar: Condvar, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - fn new() -> ThreadParker { - ThreadParker { - should_park: Cell::new(false), - lock: Lock::new(), - condvar: Condvar::new(), - } - } - - unsafe fn prepare_park(&self) { - self.should_park.set(true); - } - - unsafe fn timed_out(&self) -> bool { - // We need to grab the lock here because another thread may be - // concurrently executing UnparkHandle::unpark, which is done without - // holding the queue lock. - let _guard = self.lock.lock(); - self.should_park.get() - } - - unsafe fn park(&self) { - let guard = self.lock.lock(); - while self.should_park.get() { - self.condvar.wait(&guard); - } - } - - unsafe fn park_until(&self, timeout: Instant) -> bool { - let guard = self.lock.lock(); - while self.should_park.get() { - if let Some(duration_left) = timeout.checked_duration_since(Instant::now()) { - if let Ok(nanos_left) = abi::timestamp::try_from(duration_left.as_nanos()) { - self.condvar.wait_timeout(&guard, nanos_left); - } else { - // remaining timeout overflows an abi::timestamp. Sleep indefinitely - self.condvar.wait(&guard); - } - } else { - // We timed out - return false; - } - } - true - } - - unsafe fn unpark_lock(&self) -> UnparkHandle { - let _lock_guard = self.lock.lock(); - - UnparkHandle { - thread_parker: self, - _lock_guard, - } - } -} - -pub struct UnparkHandle { - thread_parker: *const ThreadParker, - _lock_guard: LockGuard, -} - -impl super::UnparkHandleT for UnparkHandle { - unsafe fn unpark(self) { - (*self.thread_parker).should_park.set(false); - - // We notify while holding the lock here to avoid races with the target - // thread. In particular, the thread could exit after we unlock the - // mutex, which would make the condvar access invalid memory. - (*self.thread_parker).condvar.notify(); - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/generic.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/generic.rs deleted file mode 100644 index 3ee837ac6f..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/generic.rs +++ /dev/null @@ -1,77 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -//! A simple spin lock based thread parker. Used on platforms without better -//! parking facilities available. - -use core::sync::atomic::{spin_loop_hint, AtomicBool, Ordering}; -use std::{thread, time::Instant}; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - parked: AtomicBool, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - parked: AtomicBool::new(false), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.parked.store(true, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.parked.load(Ordering::Relaxed) != false - } - - #[inline] - unsafe fn park(&self) { - while self.parked.load(Ordering::Acquire) != false { - spin_loop_hint(); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.parked.load(Ordering::Acquire) != false { - if Instant::now() >= timeout { - return false; - } - spin_loop_hint(); - } - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.parked.store(false, Ordering::Release); - UnparkHandle(()) - } -} - -pub struct UnparkHandle(()); - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) {} -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/linux.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/linux.rs deleted file mode 100644 index 04f66a737f..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/linux.rs +++ /dev/null @@ -1,155 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use core::{ - ptr, - sync::atomic::{AtomicI32, Ordering}, -}; -use libc; -use std::{thread, time::Instant}; - -// x32 Linux uses a non-standard type for tv_nsec in timespec. -// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -#[allow(non_camel_case_types)] -type tv_nsec_t = i64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -#[allow(non_camel_case_types)] -type tv_nsec_t = libc::c_long; - -fn errno() -> libc::c_int { - #[cfg(target_os = "linux")] - unsafe { - *libc::__errno_location() - } - #[cfg(target_os = "android")] - unsafe { - *libc::__errno() - } -} - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - futex: AtomicI32, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - futex: AtomicI32::new(0), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.futex.store(1, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.futex.load(Ordering::Relaxed) != 0 - } - - #[inline] - unsafe fn park(&self) { - while self.futex.load(Ordering::Acquire) != 0 { - self.futex_wait(None); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.futex.load(Ordering::Acquire) != 0 { - let now = Instant::now(); - if timeout <= now { - return false; - } - let diff = timeout - now; - if diff.as_secs() as libc::time_t as u64 != diff.as_secs() { - // Timeout overflowed, just sleep indefinitely - self.park(); - return true; - } - let ts = libc::timespec { - tv_sec: diff.as_secs() as libc::time_t, - tv_nsec: diff.subsec_nanos() as tv_nsec_t, - }; - self.futex_wait(Some(ts)); - } - true - } - - // Locks the parker to prevent the target thread from exiting. This is - // necessary to ensure that thread-local ThreadData objects remain valid. - // This should be called while holding the queue lock. - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.futex.store(0, Ordering::Release); - - UnparkHandle { futex: &self.futex } - } -} - -impl ThreadParker { - #[inline] - fn futex_wait(&self, ts: Option) { - let ts_ptr = ts - .as_ref() - .map(|ts_ref| ts_ref as *const _) - .unwrap_or(ptr::null()); - let r = unsafe { - libc::syscall( - libc::SYS_futex, - &self.futex, - libc::FUTEX_WAIT | libc::FUTEX_PRIVATE_FLAG, - 1, - ts_ptr, - ) - }; - debug_assert!(r == 0 || r == -1); - if r == -1 { - debug_assert!( - errno() == libc::EINTR - || errno() == libc::EAGAIN - || (ts.is_some() && errno() == libc::ETIMEDOUT) - ); - } - } -} - -pub struct UnparkHandle { - futex: *const AtomicI32, -} - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - // The thread data may have been freed at this point, but it doesn't - // matter since the syscall will just return EFAULT in that case. - let r = libc::syscall( - libc::SYS_futex, - self.futex, - libc::FUTEX_WAKE | libc::FUTEX_PRIVATE_FLAG, - 1, - ); - debug_assert!(r == 0 || r == 1 || r == -1); - if r == -1 { - debug_assert_eq!(errno(), libc::EFAULT); - } - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/mod.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/mod.rs deleted file mode 100644 index 4c721c3da9..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/mod.rs +++ /dev/null @@ -1,88 +0,0 @@ -use cfg_if::cfg_if; -use std::time::Instant; - -/// Trait for the platform thread parker implementation. -/// -/// All unsafe methods are unsafe because the Unix thread parker is based on -/// pthread mutexes and condvars. Those primitives must not be moved and used -/// from any other memory address than the one they were located at when they -/// were initialized. As such, it's UB to call any unsafe method on -/// `ThreadParkerT` if the implementing instance has moved since the last -/// call to any of the unsafe methods. -pub trait ThreadParkerT { - type UnparkHandle: UnparkHandleT; - - const IS_CHEAP_TO_CONSTRUCT: bool; - - fn new() -> Self; - - /// Prepares the parker. This should be called before adding it to the queue. - unsafe fn prepare_park(&self); - - /// Checks if the park timed out. This should be called while holding the - /// queue lock after park_until has returned false. - unsafe fn timed_out(&self) -> bool; - - /// Parks the thread until it is unparked. This should be called after it has - /// been added to the queue, after unlocking the queue. - unsafe fn park(&self); - - /// Parks the thread until it is unparked or the timeout is reached. This - /// should be called after it has been added to the queue, after unlocking - /// the queue. Returns true if we were unparked and false if we timed out. - unsafe fn park_until(&self, timeout: Instant) -> bool; - - /// Locks the parker to prevent the target thread from exiting. This is - /// necessary to ensure that thread-local ThreadData objects remain valid. - /// This should be called while holding the queue lock. - unsafe fn unpark_lock(&self) -> Self::UnparkHandle; -} - -/// Handle for a thread that is about to be unparked. We need to mark the thread -/// as unparked while holding the queue lock, but we delay the actual unparking -/// until after the queue lock is released. -pub trait UnparkHandleT { - /// Wakes up the parked thread. This should be called after the queue lock is - /// released to avoid blocking the queue for too long. - /// - /// This method is unsafe for the same reason as the unsafe methods in - /// `ThreadParkerT`. - unsafe fn unpark(self); -} - -cfg_if! { - if #[cfg(any(target_os = "linux", target_os = "android"))] { - #[path = "linux.rs"] - mod imp; - } else if #[cfg(unix)] { - #[path = "unix.rs"] - mod imp; - } else if #[cfg(windows)] { - #[path = "windows/mod.rs"] - mod imp; - } else if #[cfg(target_os = "redox")] { - #[path = "redox.rs"] - mod imp; - } else if #[cfg(all(target_env = "sgx", target_vendor = "fortanix"))] { - #[path = "sgx.rs"] - mod imp; - } else if #[cfg(all( - feature = "nightly", - target_arch = "wasm32", - target_feature = "atomics" - ))] { - #[path = "wasm_atomic.rs"] - mod imp; - } else if #[cfg(target_arch = "wasm32")] { - #[path = "wasm.rs"] - mod imp; - } else if #[cfg(all(feature = "nightly", target_os = "cloudabi"))] { - #[path = "cloudabi.rs"] - mod imp; - } else { - #[path = "generic.rs"] - mod imp; - } -} - -pub use self::imp::{thread_yield, ThreadParker, UnparkHandle}; diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/redox.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/redox.rs deleted file mode 100644 index 97ffc8adc0..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/redox.rs +++ /dev/null @@ -1,138 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use core::{ - ptr, - sync::atomic::{AtomicI32, Ordering}, -}; -use std::{thread, time::Instant}; -use syscall::{ - call::futex, - data::TimeSpec, - error::{Error, EAGAIN, EFAULT, EINTR, ETIMEDOUT}, - flag::{FUTEX_WAIT, FUTEX_WAKE}, -}; - -const UNPARKED: i32 = 0; -const PARKED: i32 = 1; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - futex: AtomicI32, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - futex: AtomicI32::new(UNPARKED), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.futex.store(PARKED, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.futex.load(Ordering::Relaxed) != UNPARKED - } - - #[inline] - unsafe fn park(&self) { - while self.futex.load(Ordering::Acquire) != UNPARKED { - self.futex_wait(None); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.futex.load(Ordering::Acquire) != UNPARKED { - let now = Instant::now(); - if timeout <= now { - return false; - } - let diff = timeout - now; - if diff.as_secs() > i64::max_value() as u64 { - // Timeout overflowed, just sleep indefinitely - self.park(); - return true; - } - let ts = TimeSpec { - tv_sec: diff.as_secs() as i64, - tv_nsec: diff.subsec_nanos() as i32, - }; - self.futex_wait(Some(ts)); - } - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.futex.store(UNPARKED, Ordering::Release); - - UnparkHandle { futex: self.ptr() } - } -} - -impl ThreadParker { - #[inline] - fn futex_wait(&self, ts: Option) { - let ts_ptr = ts - .as_ref() - .map(|ts_ref| ts_ref as *const _) - .unwrap_or(ptr::null()); - let r = unsafe { - futex( - self.ptr(), - FUTEX_WAIT, - PARKED, - ts_ptr as usize, - ptr::null_mut(), - ) - }; - match r { - Ok(r) => debug_assert_eq!(r, 0), - Err(Error { errno }) => { - debug_assert!(errno == EINTR || errno == EAGAIN || errno == ETIMEDOUT); - } - } - } - - #[inline] - fn ptr(&self) -> *mut i32 { - &self.futex as *const AtomicI32 as *mut i32 - } -} - -pub struct UnparkHandle { - futex: *mut i32, -} - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - // The thread data may have been freed at this point, but it doesn't - // matter since the syscall will just return EFAULT in that case. - let r = futex(self.futex, FUTEX_WAKE, PARKED, 0, ptr::null_mut()); - match r { - Ok(num_woken) => debug_assert!(num_woken == 0 || num_woken == 1), - Err(Error { errno }) => debug_assert_eq!(errno, EFAULT), - } - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/sgx.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/sgx.rs deleted file mode 100644 index 56fc65a208..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/sgx.rs +++ /dev/null @@ -1,94 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use core::sync::atomic::{AtomicBool, Ordering}; -use std::{ - io, - os::fortanix_sgx::{ - thread::current as current_tcs, - usercalls::{ - self, - raw::{Tcs, EV_UNPARK, WAIT_INDEFINITE}, - }, - }, - thread, - time::Instant, -}; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - parked: AtomicBool, - tcs: Tcs, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - parked: AtomicBool::new(false), - tcs: current_tcs(), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.parked.store(true, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.parked.load(Ordering::Relaxed) - } - - #[inline] - unsafe fn park(&self) { - while self.parked.load(Ordering::Acquire) { - let result = usercalls::wait(EV_UNPARK, WAIT_INDEFINITE); - debug_assert_eq!(result.expect("wait returned error") & EV_UNPARK, EV_UNPARK); - } - } - - #[inline] - unsafe fn park_until(&self, _timeout: Instant) -> bool { - // FIXME: https://github.com/fortanix/rust-sgx/issues/31 - panic!("timeout not supported in SGX"); - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.parked.store(false, Ordering::Release); - UnparkHandle(self.tcs) - } -} - -pub struct UnparkHandle(Tcs); - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - let result = usercalls::send(EV_UNPARK, Some(self.0)); - if cfg!(debug_assertions) { - if let Err(error) = result { - // `InvalidInput` may be returned if the thread we send to has - // already been unparked and exited. - if error.kind() != io::ErrorKind::InvalidInput { - panic!("send returned an unexpected error: {:?}", error); - } - } - } - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/unix.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/unix.rs deleted file mode 100644 index e61ab623ef..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/unix.rs +++ /dev/null @@ -1,252 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -#[cfg(any(target_os = "macos", target_os = "ios"))] -use core::ptr; -use core::{ - cell::{Cell, UnsafeCell}, - mem::MaybeUninit, -}; -use libc; -use std::{ - thread, - time::{Duration, Instant}, -}; - -// x32 Linux uses a non-standard type for tv_nsec in timespec. -// See https://sourceware.org/bugzilla/show_bug.cgi?id=16437 -#[cfg(all(target_arch = "x86_64", target_pointer_width = "32"))] -#[allow(non_camel_case_types)] -type tv_nsec_t = i64; -#[cfg(not(all(target_arch = "x86_64", target_pointer_width = "32")))] -#[allow(non_camel_case_types)] -type tv_nsec_t = libc::c_long; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - should_park: Cell, - mutex: UnsafeCell, - condvar: UnsafeCell, - initialized: Cell, -} - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = false; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - should_park: Cell::new(false), - mutex: UnsafeCell::new(libc::PTHREAD_MUTEX_INITIALIZER), - condvar: UnsafeCell::new(libc::PTHREAD_COND_INITIALIZER), - initialized: Cell::new(false), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.should_park.set(true); - if !self.initialized.get() { - self.init(); - self.initialized.set(true); - } - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - // We need to grab the mutex here because another thread may be - // concurrently executing UnparkHandle::unpark, which is done without - // holding the queue lock. - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - let should_park = self.should_park.get(); - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - should_park - } - - #[inline] - unsafe fn park(&self) { - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - while self.should_park.get() { - let r = libc::pthread_cond_wait(self.condvar.get(), self.mutex.get()); - debug_assert_eq!(r, 0); - } - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - while self.should_park.get() { - let now = Instant::now(); - if timeout <= now { - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - return false; - } - - if let Some(ts) = timeout_to_timespec(timeout - now) { - let r = libc::pthread_cond_timedwait(self.condvar.get(), self.mutex.get(), &ts); - if ts.tv_sec < 0 { - // On some systems, negative timeouts will return EINVAL. In - // that case we won't sleep and will just busy loop instead, - // which is the best we can do. - debug_assert!(r == 0 || r == libc::ETIMEDOUT || r == libc::EINVAL); - } else { - debug_assert!(r == 0 || r == libc::ETIMEDOUT); - } - } else { - // Timeout calculation overflowed, just sleep indefinitely - let r = libc::pthread_cond_wait(self.condvar.get(), self.mutex.get()); - debug_assert_eq!(r, 0); - } - } - let r = libc::pthread_mutex_unlock(self.mutex.get()); - debug_assert_eq!(r, 0); - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - let r = libc::pthread_mutex_lock(self.mutex.get()); - debug_assert_eq!(r, 0); - - UnparkHandle { - thread_parker: self, - } - } -} - -impl ThreadParker { - /// Initializes the condvar to use CLOCK_MONOTONIC instead of CLOCK_REALTIME. - #[cfg(any(target_os = "macos", target_os = "ios", target_os = "android"))] - #[inline] - unsafe fn init(&self) {} - - /// Initializes the condvar to use CLOCK_MONOTONIC instead of CLOCK_REALTIME. - #[cfg(not(any(target_os = "macos", target_os = "ios", target_os = "android")))] - #[inline] - unsafe fn init(&self) { - let mut attr = MaybeUninit::::uninit(); - let r = libc::pthread_condattr_init(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_condattr_setclock(attr.as_mut_ptr(), libc::CLOCK_MONOTONIC); - debug_assert_eq!(r, 0); - let r = libc::pthread_cond_init(self.condvar.get(), attr.as_ptr()); - debug_assert_eq!(r, 0); - let r = libc::pthread_condattr_destroy(attr.as_mut_ptr()); - debug_assert_eq!(r, 0); - } -} - -impl Drop for ThreadParker { - #[inline] - fn drop(&mut self) { - // On DragonFly pthread_mutex_destroy() returns EINVAL if called on a - // mutex that was just initialized with libc::PTHREAD_MUTEX_INITIALIZER. - // Once it is used (locked/unlocked) or pthread_mutex_init() is called, - // this behaviour no longer occurs. The same applies to condvars. - unsafe { - let r = libc::pthread_mutex_destroy(self.mutex.get()); - if cfg!(target_os = "dragonfly") { - debug_assert!(r == 0 || r == libc::EINVAL); - } else { - debug_assert_eq!(r, 0); - } - let r = libc::pthread_cond_destroy(self.condvar.get()); - if cfg!(target_os = "dragonfly") { - debug_assert!(r == 0 || r == libc::EINVAL); - } else { - debug_assert_eq!(r, 0); - } - } - } -} - -pub struct UnparkHandle { - thread_parker: *const ThreadParker, -} - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - (*self.thread_parker).should_park.set(false); - - // We notify while holding the lock here to avoid races with the target - // thread. In particular, the thread could exit after we unlock the - // mutex, which would make the condvar access invalid memory. - let r = libc::pthread_cond_signal((*self.thread_parker).condvar.get()); - debug_assert_eq!(r, 0); - let r = libc::pthread_mutex_unlock((*self.thread_parker).mutex.get()); - debug_assert_eq!(r, 0); - } -} - -// Returns the current time on the clock used by pthread_cond_t as a timespec. -#[cfg(any(target_os = "macos", target_os = "ios"))] -#[inline] -fn timespec_now() -> libc::timespec { - let mut now = MaybeUninit::::uninit(); - let r = unsafe { libc::gettimeofday(now.as_mut_ptr(), ptr::null_mut()) }; - debug_assert_eq!(r, 0); - // SAFETY: We know `libc::gettimeofday` has initialized the value. - let now = unsafe { now.assume_init() }; - libc::timespec { - tv_sec: now.tv_sec, - tv_nsec: now.tv_usec as tv_nsec_t * 1000, - } -} -#[cfg(not(any(target_os = "macos", target_os = "ios")))] -#[inline] -fn timespec_now() -> libc::timespec { - let mut now = MaybeUninit::::uninit(); - let clock = if cfg!(target_os = "android") { - // Android doesn't support pthread_condattr_setclock, so we need to - // specify the timeout in CLOCK_REALTIME. - libc::CLOCK_REALTIME - } else { - libc::CLOCK_MONOTONIC - }; - let r = unsafe { libc::clock_gettime(clock, now.as_mut_ptr()) }; - debug_assert_eq!(r, 0); - // SAFETY: We know `libc::clock_gettime` has initialized the value. - unsafe { now.assume_init() } -} - -// Converts a relative timeout into an absolute timeout in the clock used by -// pthread_cond_t. -#[inline] -fn timeout_to_timespec(timeout: Duration) -> Option { - // Handle overflows early on - if timeout.as_secs() > libc::time_t::max_value() as u64 { - return None; - } - - let now = timespec_now(); - let mut nsec = now.tv_nsec + timeout.subsec_nanos() as tv_nsec_t; - let mut sec = now.tv_sec.checked_add(timeout.as_secs() as libc::time_t); - if nsec >= 1_000_000_000 { - nsec -= 1_000_000_000; - sec = sec.and_then(|sec| sec.checked_add(1)); - } - - sec.map(|sec| libc::timespec { - tv_nsec: nsec, - tv_sec: sec, - }) -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm.rs deleted file mode 100644 index f91a218cfe..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm.rs +++ /dev/null @@ -1,53 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -//! The wasm platform can't park when atomic support is not available. -//! So this ThreadParker just panics on any attempt to park. - -use std::{thread, time::Instant}; - -pub struct ThreadParker(()); - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - fn new() -> ThreadParker { - ThreadParker(()) - } - - unsafe fn prepare_park(&self) { - panic!("Parking not supported on this platform"); - } - - unsafe fn timed_out(&self) -> bool { - panic!("Parking not supported on this platform"); - } - - unsafe fn park(&self) { - panic!("Parking not supported on this platform"); - } - - unsafe fn park_until(&self, _timeout: Instant) -> bool { - panic!("Parking not supported on this platform"); - } - - unsafe fn unpark_lock(&self) -> UnparkHandle { - panic!("Parking not supported on this platform"); - } -} - -pub struct UnparkHandle(()); - -impl super::UnparkHandleT for UnparkHandle { - unsafe fn unpark(self) {} -} - -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm_atomic.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm_atomic.rs deleted file mode 100644 index 37f302708f..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/wasm_atomic.rs +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use core::{ - arch::wasm32, - sync::atomic::{AtomicI32, Ordering}, -}; -use std::{convert::TryFrom, thread, time::Instant}; - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - parked: AtomicI32, -} - -const UNPARKED: i32 = 0; -const PARKED: i32 = 1; - -impl super::ThreadParkerT for ThreadParker { - type UnparkHandle = UnparkHandle; - - const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - fn new() -> ThreadParker { - ThreadParker { - parked: AtomicI32::new(UNPARKED), - } - } - - #[inline] - unsafe fn prepare_park(&self) { - self.parked.store(PARKED, Ordering::Relaxed); - } - - #[inline] - unsafe fn timed_out(&self) -> bool { - self.parked.load(Ordering::Relaxed) == PARKED - } - - #[inline] - unsafe fn park(&self) { - while self.parked.load(Ordering::Acquire) == PARKED { - let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, -1) }; - // we should have either woken up (0) or got a not-equal due to a - // race (1). We should never time out (2) - debug_assert!(r == 0 || r == 1); - } - } - - #[inline] - unsafe fn park_until(&self, timeout: Instant) -> bool { - while self.parked.load(Ordering::Acquire) == PARKED { - if let Some(left) = timeout.checked_duration_since(Instant::now()) { - let nanos_left = i64::try_from(left.as_nanos()).unwrap_or(i64::max_value()); - let r = unsafe { wasm32::i32_atomic_wait(self.ptr(), PARKED, nanos_left) }; - debug_assert!(r == 0 || r == 1 || r == 2); - } else { - return false; - } - } - true - } - - #[inline] - unsafe fn unpark_lock(&self) -> UnparkHandle { - // We don't need to lock anything, just clear the state - self.parked.store(UNPARKED, Ordering::Release); - UnparkHandle(self.ptr()) - } -} - -impl ThreadParker { - #[inline] - fn ptr(&self) -> *mut i32 { - &self.parked as *const AtomicI32 as *mut i32 - } -} - -pub struct UnparkHandle(*mut i32); - -impl super::UnparkHandleT for UnparkHandle { - #[inline] - unsafe fn unpark(self) { - let num_notified = unsafe { wasm32::atomic_notify(self.0 as *mut i32, 1) }; - debug_assert!(num_notified == 0 || num_notified == 1); - } -} - -#[inline] -pub fn thread_yield() { - thread::yield_now(); -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/keyed_event.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/keyed_event.rs deleted file mode 100644 index 7b516fe196..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/keyed_event.rs +++ /dev/null @@ -1,220 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use core::{ - mem::{self, MaybeUninit}, - ptr, -}; -use std::{ - sync::atomic::{AtomicUsize, Ordering}, - time::Instant, -}; -use winapi::{ - shared::{ - minwindef::{TRUE, ULONG}, - ntdef::NTSTATUS, - ntstatus::{STATUS_SUCCESS, STATUS_TIMEOUT}, - }, - um::{ - handleapi::CloseHandle, - libloaderapi::{GetModuleHandleA, GetProcAddress}, - winnt::{ - ACCESS_MASK, BOOLEAN, GENERIC_READ, GENERIC_WRITE, HANDLE, LARGE_INTEGER, LPCSTR, - PHANDLE, PLARGE_INTEGER, PVOID, - }, - }, -}; - -const STATE_UNPARKED: usize = 0; -const STATE_PARKED: usize = 1; -const STATE_TIMED_OUT: usize = 2; - -#[allow(non_snake_case)] -pub struct KeyedEvent { - handle: HANDLE, - NtReleaseKeyedEvent: extern "system" fn( - EventHandle: HANDLE, - Key: PVOID, - Alertable: BOOLEAN, - Timeout: PLARGE_INTEGER, - ) -> NTSTATUS, - NtWaitForKeyedEvent: extern "system" fn( - EventHandle: HANDLE, - Key: PVOID, - Alertable: BOOLEAN, - Timeout: PLARGE_INTEGER, - ) -> NTSTATUS, -} - -impl KeyedEvent { - #[inline] - unsafe fn wait_for(&self, key: PVOID, timeout: PLARGE_INTEGER) -> NTSTATUS { - (self.NtWaitForKeyedEvent)(self.handle, key, 0, timeout) - } - - #[inline] - unsafe fn release(&self, key: PVOID) -> NTSTATUS { - (self.NtReleaseKeyedEvent)(self.handle, key, 0, ptr::null_mut()) - } - - #[allow(non_snake_case)] - pub fn create() -> Option { - unsafe { - let ntdll = GetModuleHandleA(b"ntdll.dll\0".as_ptr() as LPCSTR); - if ntdll.is_null() { - return None; - } - - let NtCreateKeyedEvent = - GetProcAddress(ntdll, b"NtCreateKeyedEvent\0".as_ptr() as LPCSTR); - if NtCreateKeyedEvent.is_null() { - return None; - } - let NtReleaseKeyedEvent = - GetProcAddress(ntdll, b"NtReleaseKeyedEvent\0".as_ptr() as LPCSTR); - if NtReleaseKeyedEvent.is_null() { - return None; - } - let NtWaitForKeyedEvent = - GetProcAddress(ntdll, b"NtWaitForKeyedEvent\0".as_ptr() as LPCSTR); - if NtWaitForKeyedEvent.is_null() { - return None; - } - - let NtCreateKeyedEvent: extern "system" fn( - KeyedEventHandle: PHANDLE, - DesiredAccess: ACCESS_MASK, - ObjectAttributes: PVOID, - Flags: ULONG, - ) -> NTSTATUS = mem::transmute(NtCreateKeyedEvent); - let mut handle = MaybeUninit::uninit(); - let status = NtCreateKeyedEvent( - handle.as_mut_ptr(), - GENERIC_READ | GENERIC_WRITE, - ptr::null_mut(), - 0, - ); - if status != STATUS_SUCCESS { - return None; - } - - Some(KeyedEvent { - handle: handle.assume_init(), - NtReleaseKeyedEvent: mem::transmute(NtReleaseKeyedEvent), - NtWaitForKeyedEvent: mem::transmute(NtWaitForKeyedEvent), - }) - } - } - - #[inline] - pub fn prepare_park(&'static self, key: &AtomicUsize) { - key.store(STATE_PARKED, Ordering::Relaxed); - } - - #[inline] - pub fn timed_out(&'static self, key: &AtomicUsize) -> bool { - key.load(Ordering::Relaxed) == STATE_TIMED_OUT - } - - #[inline] - pub unsafe fn park(&'static self, key: &AtomicUsize) { - let status = self.wait_for(key as *const _ as PVOID, ptr::null_mut()); - debug_assert_eq!(status, STATUS_SUCCESS); - } - - #[inline] - pub unsafe fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool { - let now = Instant::now(); - if timeout <= now { - // If another thread unparked us, we need to call - // NtWaitForKeyedEvent otherwise that thread will stay stuck at - // NtReleaseKeyedEvent. - if key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED { - self.park(key); - return true; - } - return false; - } - - // NT uses a timeout in units of 100ns. We use a negative value to - // indicate a relative timeout based on a monotonic clock. - let mut nt_timeout: LARGE_INTEGER = mem::zeroed(); - let diff = timeout - now; - let value = (diff.as_secs() as i64) - .checked_mul(-10000000) - .and_then(|x| x.checked_sub((diff.subsec_nanos() as i64 + 99) / 100)); - - match value { - Some(x) => *nt_timeout.QuadPart_mut() = x, - None => { - // Timeout overflowed, just sleep indefinitely - self.park(key); - return true; - } - }; - - let status = self.wait_for(key as *const _ as PVOID, &mut nt_timeout); - if status == STATUS_SUCCESS { - return true; - } - debug_assert_eq!(status, STATUS_TIMEOUT); - - // If another thread unparked us, we need to call NtWaitForKeyedEvent - // otherwise that thread will stay stuck at NtReleaseKeyedEvent. - if key.swap(STATE_TIMED_OUT, Ordering::Relaxed) == STATE_UNPARKED { - self.park(key); - return true; - } - false - } - - #[inline] - pub unsafe fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle { - // If the state was STATE_PARKED then we need to wake up the thread - if key.swap(STATE_UNPARKED, Ordering::Relaxed) == STATE_PARKED { - UnparkHandle { - key: key, - keyed_event: self, - } - } else { - UnparkHandle { - key: ptr::null(), - keyed_event: self, - } - } - } -} - -impl Drop for KeyedEvent { - #[inline] - fn drop(&mut self) { - unsafe { - let ok = CloseHandle(self.handle); - debug_assert_eq!(ok, TRUE); - } - } -} - -// Handle for a thread that is about to be unparked. We need to mark the thread -// as unparked while holding the queue lock, but we delay the actual unparking -// until after the queue lock is released. -pub struct UnparkHandle { - key: *const AtomicUsize, - keyed_event: &'static KeyedEvent, -} - -impl UnparkHandle { - // Wakes up the parked thread. This should be called after the queue lock is - // released to avoid blocking the queue for too long. - #[inline] - pub unsafe fn unpark(self) { - if !self.key.is_null() { - let status = self.keyed_event.release(self.key as PVOID); - debug_assert_eq!(status, STATUS_SUCCESS); - } - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/mod.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/mod.rs deleted file mode 100644 index 9db1652445..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/mod.rs +++ /dev/null @@ -1,188 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use core::{ - ptr, - sync::atomic::{AtomicPtr, AtomicUsize, Ordering}, -}; -use std::time::Instant; - -mod keyed_event; -mod waitaddress; - -enum Backend { - KeyedEvent(keyed_event::KeyedEvent), - WaitAddress(waitaddress::WaitAddress), -} - -static BACKEND: AtomicPtr = AtomicPtr::new(ptr::null_mut()); - -impl Backend { - #[inline] - fn get() -> &'static Backend { - // Fast path: use the existing object - let backend_ptr = BACKEND.load(Ordering::Acquire); - if !backend_ptr.is_null() { - return unsafe { &*backend_ptr }; - }; - - Backend::create() - } - - #[cold] - fn create() -> &'static Backend { - // Try to create a new Backend - let backend; - if let Some(waitaddress) = waitaddress::WaitAddress::create() { - backend = Backend::WaitAddress(waitaddress); - } else if let Some(keyed_event) = keyed_event::KeyedEvent::create() { - backend = Backend::KeyedEvent(keyed_event); - } else { - panic!( - "parking_lot requires either NT Keyed Events (WinXP+) or \ - WaitOnAddress/WakeByAddress (Win8+)" - ); - } - - // Try to set our new Backend as the global one - let backend_ptr = Box::into_raw(Box::new(backend)); - match BACKEND.compare_exchange( - ptr::null_mut(), - backend_ptr, - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => unsafe { &*backend_ptr }, - Err(global_backend_ptr) => { - unsafe { - // We lost the race, free our object and return the global one - Box::from_raw(backend_ptr); - &*global_backend_ptr - } - } - } - } -} - -// Helper type for putting a thread to sleep until some other thread wakes it up -pub struct ThreadParker { - key: AtomicUsize, - backend: &'static Backend, -} - -impl ThreadParker { - pub const IS_CHEAP_TO_CONSTRUCT: bool = true; - - #[inline] - pub fn new() -> ThreadParker { - // Initialize the backend here to ensure we don't get any panics - // later on, which could leave synchronization primitives in a broken - // state. - ThreadParker { - key: AtomicUsize::new(0), - backend: Backend::get(), - } - } - - // Prepares the parker. This should be called before adding it to the queue. - #[inline] - pub fn prepare_park(&self) { - match *self.backend { - Backend::KeyedEvent(ref x) => x.prepare_park(&self.key), - Backend::WaitAddress(ref x) => x.prepare_park(&self.key), - } - } - - // Checks if the park timed out. This should be called while holding the - // queue lock after park_until has returned false. - #[inline] - pub fn timed_out(&self) -> bool { - match *self.backend { - Backend::KeyedEvent(ref x) => x.timed_out(&self.key), - Backend::WaitAddress(ref x) => x.timed_out(&self.key), - } - } - - // Parks the thread until it is unparked. This should be called after it has - // been added to the queue, after unlocking the queue. - #[inline] - pub unsafe fn park(&self) { - match *self.backend { - Backend::KeyedEvent(ref x) => x.park(&self.key), - Backend::WaitAddress(ref x) => x.park(&self.key), - } - } - - // Parks the thread until it is unparked or the timeout is reached. This - // should be called after it has been added to the queue, after unlocking - // the queue. Returns true if we were unparked and false if we timed out. - #[inline] - pub unsafe fn park_until(&self, timeout: Instant) -> bool { - match *self.backend { - Backend::KeyedEvent(ref x) => x.park_until(&self.key, timeout), - Backend::WaitAddress(ref x) => x.park_until(&self.key, timeout), - } - } - - // Locks the parker to prevent the target thread from exiting. This is - // necessary to ensure that thread-local ThreadData objects remain valid. - // This should be called while holding the queue lock. - #[inline] - pub unsafe fn unpark_lock(&self) -> UnparkHandle { - match *self.backend { - Backend::KeyedEvent(ref x) => UnparkHandle::KeyedEvent(x.unpark_lock(&self.key)), - Backend::WaitAddress(ref x) => UnparkHandle::WaitAddress(x.unpark_lock(&self.key)), - } - } -} - -// Handle for a thread that is about to be unparked. We need to mark the thread -// as unparked while holding the queue lock, but we delay the actual unparking -// until after the queue lock is released. -pub enum UnparkHandle { - KeyedEvent(keyed_event::UnparkHandle), - WaitAddress(waitaddress::UnparkHandle), -} - -impl UnparkHandle { - // Wakes up the parked thread. This should be called after the queue lock is - // released to avoid blocking the queue for too long. - #[inline] - pub unsafe fn unpark(self) { - match self { - UnparkHandle::KeyedEvent(x) => x.unpark(), - UnparkHandle::WaitAddress(x) => x.unpark(), - } - } -} - -// Yields the rest of the current timeslice to the OS -#[inline] -pub fn thread_yield() { - // Note that this is manually defined here rather than using the definition - // through `winapi`. The `winapi` definition comes from the `synchapi` - // header which enables the "synchronization.lib" library. It turns out, - // however that `Sleep` comes from `kernel32.dll` so this activation isn't - // necessary. - // - // This was originally identified in rust-lang/rust where on MinGW the - // libsynchronization.a library pulls in a dependency on a newer DLL not - // present in older versions of Windows. (see rust-lang/rust#49438) - // - // This is a bit of a hack for now and ideally we'd fix MinGW's own import - // libraries, but that'll probably take a lot longer than patching this here - // and avoiding the `synchapi` feature entirely. - extern "system" { - fn Sleep(a: winapi::shared::minwindef::DWORD); - } - unsafe { - // We don't use SwitchToThread here because it doesn't consider all - // threads in the system and the thread we are waiting for may not get - // selected. - Sleep(0); - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/waitaddress.rs b/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/waitaddress.rs deleted file mode 100644 index 0ec780404d..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/thread_parker/windows/waitaddress.rs +++ /dev/null @@ -1,149 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use core::{ - mem, - sync::atomic::{AtomicUsize, Ordering}, -}; -use std::time::Instant; -use winapi::{ - shared::{ - basetsd::SIZE_T, - minwindef::{BOOL, DWORD, FALSE, TRUE}, - winerror::ERROR_TIMEOUT, - }, - um::{ - errhandlingapi::GetLastError, - libloaderapi::{GetModuleHandleA, GetProcAddress}, - winbase::INFINITE, - winnt::{LPCSTR, PVOID}, - }, -}; - -#[allow(non_snake_case)] -pub struct WaitAddress { - WaitOnAddress: extern "system" fn( - Address: PVOID, - CompareAddress: PVOID, - AddressSize: SIZE_T, - dwMilliseconds: DWORD, - ) -> BOOL, - WakeByAddressSingle: extern "system" fn(Address: PVOID), -} - -impl WaitAddress { - #[allow(non_snake_case)] - pub fn create() -> Option { - unsafe { - // MSDN claims that that WaitOnAddress and WakeByAddressSingle are - // located in kernel32.dll, but they are lying... - let synch_dll = - GetModuleHandleA(b"api-ms-win-core-synch-l1-2-0.dll\0".as_ptr() as LPCSTR); - if synch_dll.is_null() { - return None; - } - - let WaitOnAddress = GetProcAddress(synch_dll, b"WaitOnAddress\0".as_ptr() as LPCSTR); - if WaitOnAddress.is_null() { - return None; - } - let WakeByAddressSingle = - GetProcAddress(synch_dll, b"WakeByAddressSingle\0".as_ptr() as LPCSTR); - if WakeByAddressSingle.is_null() { - return None; - } - Some(WaitAddress { - WaitOnAddress: mem::transmute(WaitOnAddress), - WakeByAddressSingle: mem::transmute(WakeByAddressSingle), - }) - } - } - - #[inline] - pub fn prepare_park(&'static self, key: &AtomicUsize) { - key.store(1, Ordering::Relaxed); - } - - #[inline] - pub fn timed_out(&'static self, key: &AtomicUsize) -> bool { - key.load(Ordering::Relaxed) != 0 - } - - #[inline] - pub fn park(&'static self, key: &AtomicUsize) { - while key.load(Ordering::Acquire) != 0 { - let r = self.wait_on_address(key, INFINITE); - debug_assert!(r == TRUE); - } - } - - #[inline] - pub fn park_until(&'static self, key: &AtomicUsize, timeout: Instant) -> bool { - while key.load(Ordering::Acquire) != 0 { - let now = Instant::now(); - if timeout <= now { - return false; - } - let diff = timeout - now; - let timeout = diff - .as_secs() - .checked_mul(1000) - .and_then(|x| x.checked_add((diff.subsec_nanos() as u64 + 999999) / 1000000)) - .map(|ms| { - if ms > ::max_value() as u64 { - INFINITE - } else { - ms as DWORD - } - }) - .unwrap_or(INFINITE); - if self.wait_on_address(key, timeout) == FALSE { - debug_assert_eq!(unsafe { GetLastError() }, ERROR_TIMEOUT); - } - } - true - } - - #[inline] - pub fn unpark_lock(&'static self, key: &AtomicUsize) -> UnparkHandle { - // We don't need to lock anything, just clear the state - key.store(0, Ordering::Release); - - UnparkHandle { - key: key, - waitaddress: self, - } - } - - #[inline] - fn wait_on_address(&'static self, key: &AtomicUsize, timeout: DWORD) -> BOOL { - let cmp = 1usize; - (self.WaitOnAddress)( - key as *const _ as PVOID, - &cmp as *const _ as PVOID, - mem::size_of::() as SIZE_T, - timeout, - ) - } -} - -// Handle for a thread that is about to be unparked. We need to mark the thread -// as unparked while holding the queue lock, but we delay the actual unparking -// until after the queue lock is released. -pub struct UnparkHandle { - key: *const AtomicUsize, - waitaddress: &'static WaitAddress, -} - -impl UnparkHandle { - // Wakes up the parked thread. This should be called after the queue lock is - // released to avoid blocking the queue for too long. - #[inline] - pub fn unpark(self) { - (self.waitaddress.WakeByAddressSingle)(self.key as PVOID); - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/util.rs b/vendor/parking_lot_core-0.7.2/src/util.rs deleted file mode 100644 index d7aaa87155..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/util.rs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -// Option::unchecked_unwrap -pub trait UncheckedOptionExt { - unsafe fn unchecked_unwrap(self) -> T; -} - -impl UncheckedOptionExt for Option { - #[inline] - unsafe fn unchecked_unwrap(self) -> T { - match self { - Some(x) => x, - None => unreachable(), - } - } -} - -// hint::unreachable_unchecked() in release mode -#[inline] -unsafe fn unreachable() -> ! { - if cfg!(debug_assertions) { - unreachable!(); - } else { - core::hint::unreachable_unchecked() - } -} diff --git a/vendor/parking_lot_core-0.7.2/src/word_lock.rs b/vendor/parking_lot_core-0.7.2/src/word_lock.rs deleted file mode 100644 index 450e98556c..0000000000 --- a/vendor/parking_lot_core-0.7.2/src/word_lock.rs +++ /dev/null @@ -1,316 +0,0 @@ -// Copyright 2016 Amanieu d'Antras -// -// 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. - -use crate::spinwait::SpinWait; -use crate::thread_parker::{ThreadParker, ThreadParkerT, UnparkHandleT}; -use core::{ - cell::Cell, - mem, ptr, - sync::atomic::{fence, AtomicUsize, Ordering}, -}; - -struct ThreadData { - parker: ThreadParker, - - // Linked list of threads in the queue. The queue is split into two parts: - // the processed part and the unprocessed part. When new nodes are added to - // the list, they only have the next pointer set, and queue_tail is null. - // - // Nodes are processed with the queue lock held, which consists of setting - // the prev pointer for each node and setting the queue_tail pointer on the - // first processed node of the list. - // - // This setup allows nodes to be added to the queue without a lock, while - // still allowing O(1) removal of nodes from the processed part of the list. - // The only cost is the O(n) processing, but this only needs to be done - // once for each node, and therefore isn't too expensive. - queue_tail: Cell<*const ThreadData>, - prev: Cell<*const ThreadData>, - next: Cell<*const ThreadData>, -} - -impl ThreadData { - #[inline] - fn new() -> ThreadData { - assert!(mem::align_of::() > !QUEUE_MASK); - ThreadData { - parker: ThreadParker::new(), - queue_tail: Cell::new(ptr::null()), - prev: Cell::new(ptr::null()), - next: Cell::new(ptr::null()), - } - } -} - -// Invokes the given closure with a reference to the current thread `ThreadData`. -#[inline] -fn with_thread_data(f: impl FnOnce(&ThreadData) -> T) -> T { - let mut thread_data_ptr = ptr::null(); - // If ThreadData is expensive to construct, then we want to use a cached - // version in thread-local storage if possible. - if !ThreadParker::IS_CHEAP_TO_CONSTRUCT { - thread_local!(static THREAD_DATA: ThreadData = ThreadData::new()); - if let Ok(tls_thread_data) = THREAD_DATA.try_with(|x| x as *const ThreadData) { - thread_data_ptr = tls_thread_data; - } - } - // Otherwise just create a ThreadData on the stack - let mut thread_data_storage = None; - if thread_data_ptr.is_null() { - thread_data_ptr = thread_data_storage.get_or_insert_with(ThreadData::new); - } - - f(unsafe { &*thread_data_ptr }) -} - -const LOCKED_BIT: usize = 1; -const QUEUE_LOCKED_BIT: usize = 2; -const QUEUE_MASK: usize = !3; - -// Word-sized lock that is used to implement the parking_lot API. Since this -// can't use parking_lot, it instead manages its own queue of waiting threads. -pub struct WordLock { - state: AtomicUsize, -} - -impl WordLock { - /// Returns a new, unlocked, WordLock. - pub const fn new() -> Self { - WordLock { - state: AtomicUsize::new(0), - } - } - - #[inline] - pub fn lock(&self) { - if self - .state - .compare_exchange_weak(0, LOCKED_BIT, Ordering::Acquire, Ordering::Relaxed) - .is_ok() - { - return; - } - self.lock_slow(); - } - - /// Must not be called on an already unlocked `WordLock`! - #[inline] - pub unsafe fn unlock(&self) { - let state = self.state.fetch_sub(LOCKED_BIT, Ordering::Release); - if state.is_queue_locked() || state.queue_head().is_null() { - return; - } - self.unlock_slow(); - } - - #[cold] - fn lock_slow(&self) { - let mut spinwait = SpinWait::new(); - let mut state = self.state.load(Ordering::Relaxed); - loop { - // Grab the lock if it isn't locked, even if there is a queue on it - if !state.is_locked() { - match self.state.compare_exchange_weak( - state, - state | LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => return, - Err(x) => state = x, - } - continue; - } - - // If there is no queue, try spinning a few times - if state.queue_head().is_null() && spinwait.spin() { - state = self.state.load(Ordering::Relaxed); - continue; - } - - // Get our thread data and prepare it for parking - state = with_thread_data(|thread_data| { - // The pthread implementation is still unsafe, so we need to surround `prepare_park` - // with `unsafe {}`. - #[allow(unused_unsafe)] - unsafe { - thread_data.parker.prepare_park(); - } - - // Add our thread to the front of the queue - let queue_head = state.queue_head(); - if queue_head.is_null() { - thread_data.queue_tail.set(thread_data); - thread_data.prev.set(ptr::null()); - } else { - thread_data.queue_tail.set(ptr::null()); - thread_data.prev.set(ptr::null()); - thread_data.next.set(queue_head); - } - if let Err(x) = self.state.compare_exchange_weak( - state, - state.with_queue_head(thread_data), - Ordering::Release, - Ordering::Relaxed, - ) { - return x; - } - - // Sleep until we are woken up by an unlock - // Ignoring unused unsafe, since it's only a few platforms where this is unsafe. - #[allow(unused_unsafe)] - unsafe { - thread_data.parker.park(); - } - - // Loop back and try locking again - spinwait.reset(); - self.state.load(Ordering::Relaxed) - }); - } - } - - #[cold] - fn unlock_slow(&self) { - let mut state = self.state.load(Ordering::Relaxed); - loop { - // We just unlocked the WordLock. Just check if there is a thread - // to wake up. If the queue is locked then another thread is already - // taking care of waking up a thread. - if state.is_queue_locked() || state.queue_head().is_null() { - return; - } - - // Try to grab the queue lock - match self.state.compare_exchange_weak( - state, - state | QUEUE_LOCKED_BIT, - Ordering::Acquire, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(x) => state = x, - } - } - - // Now we have the queue lock and the queue is non-empty - 'outer: loop { - // First, we need to fill in the prev pointers for any newly added - // threads. We do this until we reach a node that we previously - // processed, which has a non-null queue_tail pointer. - let queue_head = state.queue_head(); - let mut queue_tail; - let mut current = queue_head; - loop { - queue_tail = unsafe { (*current).queue_tail.get() }; - if !queue_tail.is_null() { - break; - } - unsafe { - let next = (*current).next.get(); - (*next).prev.set(current); - current = next; - } - } - - // Set queue_tail on the queue head to indicate that the whole list - // has prev pointers set correctly. - unsafe { - (*queue_head).queue_tail.set(queue_tail); - } - - // If the WordLock is locked, then there is no point waking up a - // thread now. Instead we let the next unlocker take care of waking - // up a thread. - if state.is_locked() { - match self.state.compare_exchange_weak( - state, - state & !QUEUE_LOCKED_BIT, - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => return, - Err(x) => state = x, - } - - // Need an acquire fence before reading the new queue - fence(Ordering::Acquire); - continue; - } - - // Remove the last thread from the queue and unlock the queue - let new_tail = unsafe { (*queue_tail).prev.get() }; - if new_tail.is_null() { - loop { - match self.state.compare_exchange_weak( - state, - state & LOCKED_BIT, - Ordering::Release, - Ordering::Relaxed, - ) { - Ok(_) => break, - Err(x) => state = x, - } - - // If the compare_exchange failed because a new thread was - // added to the queue then we need to re-scan the queue to - // find the previous element. - if state.queue_head().is_null() { - continue; - } else { - // Need an acquire fence before reading the new queue - fence(Ordering::Acquire); - continue 'outer; - } - } - } else { - unsafe { - (*queue_head).queue_tail.set(new_tail); - } - self.state.fetch_and(!QUEUE_LOCKED_BIT, Ordering::Release); - } - - // Finally, wake up the thread we removed from the queue. Note that - // we don't need to worry about any races here since the thread is - // guaranteed to be sleeping right now and we are the only one who - // can wake it up. - unsafe { - (*queue_tail).parker.unpark_lock().unpark(); - } - break; - } - } -} - -trait LockState { - fn is_locked(self) -> bool; - fn is_queue_locked(self) -> bool; - fn queue_head(self) -> *const ThreadData; - fn with_queue_head(self, thread_data: *const ThreadData) -> Self; -} - -impl LockState for usize { - #[inline] - fn is_locked(self) -> bool { - self & LOCKED_BIT != 0 - } - - #[inline] - fn is_queue_locked(self) -> bool { - self & QUEUE_LOCKED_BIT != 0 - } - - #[inline] - fn queue_head(self) -> *const ThreadData { - (self & QUEUE_MASK) as *const ThreadData - } - - #[inline] - fn with_queue_head(self, thread_data: *const ThreadData) -> Self { - (self & !QUEUE_MASK) | thread_data as *const _ as usize - } -} diff --git a/vendor/perf-event-open-sys/.cargo-checksum.json b/vendor/perf-event-open-sys/.cargo-checksum.json index 119b79c89e..94c12b528d 100644 --- a/vendor/perf-event-open-sys/.cargo-checksum.json +++ b/vendor/perf-event-open-sys/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"14708662285df53727379173710830d7cb206c1c2fe500cf58708cd0a5f90be2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"383389744bfd0cd720224f8a01fb6dd28be093ba4965363dcd0d6ae8da3d087b","regenerate.sh":"75c81d43681cd44c961da0399605a8cfe1b05b6d3a8659e11e9984f9f7c88618","src/bindings.rs":"ee0d5d224dfeae4feefbbfbf2ce46b7617ba109fa1b7f88ab886a99131d41bab","src/lib.rs":"3e95e8889d74376321caa6ff2d8ff634e08bb34d70a3ba63a6b1737de01c3e24","wrapper.h":"22abab03fcdb32f39c72756da8c45dd4d4b6cbf3de24d8922dbc3a460bccf27a"},"package":"66f37842e29d92d05872a3c0271ba6717842695ecb896cb2e147a825c804b207"} \ No newline at end of file +{"files":{"Cargo.toml":"43d4960bd26abbc5e6682924a3a35cd5b96ddde703f8578e1b304dcbfcc77a7a","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"383389744bfd0cd720224f8a01fb6dd28be093ba4965363dcd0d6ae8da3d087b","regenerate.sh":"75c81d43681cd44c961da0399605a8cfe1b05b6d3a8659e11e9984f9f7c88618","src/bindings.rs":"ee0d5d224dfeae4feefbbfbf2ce46b7617ba109fa1b7f88ab886a99131d41bab","src/lib.rs":"42c2107446f81663e4c59a11148ebc8df5241b62a58f0712133382667bc35176","wrapper.h":"22abab03fcdb32f39c72756da8c45dd4d4b6cbf3de24d8922dbc3a460bccf27a"},"package":"ce9bedf5da2c234fdf2391ede2b90fabf585355f33100689bc364a3ea558561a"} \ No newline at end of file diff --git a/vendor/perf-event-open-sys/Cargo.toml b/vendor/perf-event-open-sys/Cargo.toml index 650f36bb27..1fd0b9dd4c 100644 --- a/vendor/perf-event-open-sys/Cargo.toml +++ b/vendor/perf-event-open-sys/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "perf-event-open-sys" -version = "1.0.0" +version = "1.0.1" authors = ["Jim Blandy "] description = "Unsafe, direct bindings for Linux's perf_event_open system call, with associated\ntypes and constants.\n" readme = "README.md" diff --git a/vendor/perf-event-open-sys/src/lib.rs b/vendor/perf-event-open-sys/src/lib.rs index 468c3727df..3144280457 100644 --- a/vendor/perf-event-open-sys/src/lib.rs +++ b/vendor/perf-event-open-sys/src/lib.rs @@ -16,6 +16,9 @@ //! There are several ioctls for use with `perf_event_open` file descriptors; //! see the [`ioctls`] module for those. //! +//! For a safe and convenient interface to this functionality, see the +//! [`perf_event`] crate. +//! //! ## Using the raw API //! //! As the kernel interface evolves, the struct and union types from the @@ -52,55 +55,19 @@ //! ``` //! //! It is not necessary to adjust `size` to what the running kernel expects: -//! older kernels can accept newer `perf_event_attr` structs, and vice versa. -//! The kernel simply checks that any fields it doesn't know about are zero, and -//! pads smaller-than-expected structs with zeros. +//! older kernels can accept newer `perf_event_attr` structs, and vice versa. As +//! long as the `size` field was properly initialized, an error result of +//! `E2BIG` indicates that the `attrs` structure has requested behavior the +//! kernel is too old to support. //! -//! If the `size` field was properly initialized, an error result of `E2BIG` -//! indicates that the `attrs` structure has requested behavior the kernel is -//! too old to support. When this error code is returned, the kernel writes the -//! size it expected back to the `size` field of the `attrs` struct. +//! When `E2BIG` is returned, the kernel writes the size it expected back to the +//! `size` field of the `attrs` struct. Again, if you want to retry the call, it +//! is not necessary to adjust the size you pass to match what the kernel passed +//! back. The size from the kernel just indicates which version of the API the +//! kernel supports; see the documentation for the `PERF_EVENT_ATTR_SIZE_VER...` +//! constants for details. //! -//! This approach works nicely with Linux system call conventions. As a general -//! principle, old fields are never removed from a struct, for backwards -//! compatibility. New fields are always added to the end, and are defined to -//! have no effect when their value is zero. Each system call indicates, through -//! one means or another, the size of the struct being passed (in the case of -//! `perf_event_attr`, the `size` field does this), and this size is used to -//! indicate which version of the API userspace thinks it's using. There are -//! three cases: -//! -//! - The kernel's own definition of the struct has the same size as the -//! struct passed from userspace. This means that userspace is using the -//! same version of the header files as the kernel, so all is well. -//! -//! - The kernel's struct is larger than the one passed from userspace. This -//! means the kernel is newer than the userspace program. The kernel copies -//! the userspace data into the initial bytes of its own struct, and zeros -//! the remaining bytes. Since zeroed fields have no effect, the resulting -//! struct properly reflects the user's intent. -//! -//! - The kernel's struct is smaller than the one passed from userspace. This -//! means that an executable built on a newer kernel is running on an older -//! kernel. The kernel checks that the excess bytes in the userspace struct -//! are all zero; if they are not, the system call returns `E2BIG`, -//! indicating that userspace has requested a feature the kernel doesn't -//! support. If they are all zero, then the kernel initializes its own -//! struct with the bytes from the start of the userspace struct, and drops -//! the rest. Since the dropped bytes were all zero, they did not affect the -//! requested behavior, and the resulting struct reflects the user's intent. -//! -//! This approach is explained by the kernel comments for -//! `copy_struct_from_user` in `include/linux/uaccess.h`. The upshot is that -//! older code can run against newer kernels and vice versa, and errors are only -//! returned when the call actually requests functionality that the kernel -//! doesn't support. -//! -//! You can find one example of using `perf_event_open` in the [`perf_event`] -//! crate, which provides a safe interface to a subset of `perf_event_open`'s -//! functionality. -//! -//! ### Kernel versions +//! ## Kernel versions //! //! The bindings in this crate are generated from the Linux kernel headers //! packaged by Fedora as `kernel-headers-5.6.11-100.fc30.x86_64`, which @@ -119,6 +86,84 @@ //! If you need features that are available only in a more recent version of the //! types than this crate provides, please file an issue. //! +//! ## Linux API Backward/Forward Compatibility Strategy +//! +//! (This is more detail than necessary if you just want to use the crate. I +//! want to write this down somewhere so that I have something to refer to when +//! I forget the details.) +//! +//! It is an important principle of Linux kernel development that new versions +//! of the kernel should not break userspace. If upgrading your kernel breaks a +//! user program, then that's a bug in the kernel. (This refers to the run-time +//! interface. I don't know what the stability rules are for the kernel headers: +//! can new headers cause old code to fail to compile? Anyway, run time is our +//! concern here.) +//! +//! But when you have an open-ended, complex system call like `perf_event_open`, +//! it's really important for the interface to be able to evolve. Certainly, old +//! programs must run properly on new kernels, but ideally, it should work the +//! other way, too: a program built against a newer version of the kernel +//! headers should run on an older kernel, as long as it only requests features +//! the old kernel actually supports. That is, simply compiling against newer +//! headers should not be disqualifying - only using those new headers to +//! request features the running kernel can't provide should cause an error. +//! +//! Consider the specific case of passing a struct like `perf_event_attr` to a +//! system call like `perf_event_open`. In general, there are two versions of +//! the struct in play: the version the user program was compiled against, and +//! the version the running kernel was compiled against. How can we let old +//! programs call `perf_event_open` on new kernels, and vice versa? +//! +//! Linux has a neat strategy for making this work. There are four rules: +//! +//! - Every system call that passes a struct to the kernel includes some +//! indication of how large userspace thinks that struct is. For +//! `perf_event_open`, it's the `size` field of the `perf_event_attr` +//! struct. For `ioctl`s that pass a struct, it's a bitfield of the +//! `request` value. +//! +//! - Fields are never deleted from structs. At most, newer kernel headers may +//! rename them to '__reserved_foo' or something like that, but once a field +//! has been placed, its layout in the struct never changes. +//! +//! - New fields are added to the end of structs. +//! +//! - New fields' semantics are chosen such that filling them with zeros +//! preserves the old behavior. That is, turning an old struct into a new +//! struct by extending it with zero bytes should always give you a new +//! struct with the same meaning the old struct had. +//! +//! Then, the kernel's strategy for receiving structs from userspace (explained +//! by the kernel comments for `copy_struct_from_user` in +//! `include/linux/uaccess.h`) is as follows: +//! +//! - If the kernel's struct is larger than the one passed from userspace, +//! then that means the kernel is newer than the userspace program. The +//! kernel copies the userspace data into the initial bytes of its own +//! struct, and zeros the remaining bytes. Since zeroed fields have no +//! effect, the resulting struct properly reflects the user's intent. +//! +//! - If the kernel's struct is smaller than the one passed from userspace, +//! then that means that a userspace program compiled against newer kernel +//! headers is running on an older kernel. The kernel checks that the excess +//! bytes in the userspace struct are all zero; if they are not, the system +//! call returns `E2BIG`, indicating that userspace has requested a feature +//! the kernel doesn't support. If they are all zero, then the kernel +//! initializes its own struct with the bytes from the start of the +//! userspace struct, and drops the rest. Since the dropped bytes were all +//! zero, they did not affect the requested behavior, and the resulting +//! struct reflects the user's intent. +//! +//! - In either case, the kernel verifies that any `__reserved_foo` fields in +//! its own version of the struct are zero. +//! +//! This covers both the old-on-new and new-on-old cases, and returns an error +//! only when the call requests functionality the kernel doesn't support. +//! +//! You can find one example of using `perf_event_open` in the [`perf_event`] +//! crate, which provides a safe interface to a subset of `perf_event_open`'s +//! functionality. +//! //! [`bindings`]: bindings/index.html //! [`ioctls`]: ioctls/index.html //! [man]: http://man7.org/linux/man-pages/man2/perf_event_open.2.html diff --git a/vendor/proc-macro-error-attr/.cargo-checksum.json b/vendor/proc-macro-error-attr/.cargo-checksum.json new file mode 100644 index 0000000000..c30b5418a8 --- /dev/null +++ b/vendor/proc-macro-error-attr/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"Cargo.toml":"fbd3ce928441a0b43859bbbe36549f05e7a1ebfee62e5982710671a8f41de527","LICENSE-APACHE":"6fd0f3522047150ca7c1939f02bc4a15662a4741a89bc03ae784eefa18caa299","LICENSE-MIT":"544b3aed1fd723d0cadea567affdcfe0431e43e18d997a718f9d67256b814fde","build.rs":"37b0aca3c4a14dfc050c2df38ae633311d7a1532cdbb8eb57182802c4a1983eb","src/lib.rs":"9e3d13c266376b688642572bb4091e094ff5277fce4bee72bcc3c5f982dd831c","src/parse.rs":"2d8f220f91235be8ed0ddcab55ec3699b9d3b28d538ed24197797cc20194c473","src/settings.rs":"be9382479d7a857b55e5a0b1014f72150c9ee7f2bbb5a5bdeabc0f8de2d95c26"},"package":"a1be40180e52ecc98ad80b184934baf3d0d29f979574e439af5a55274b35f869"} \ No newline at end of file diff --git a/vendor/proc-macro-error-attr/Cargo.toml b/vendor/proc-macro-error-attr/Cargo.toml new file mode 100644 index 0000000000..a2c766de9b --- /dev/null +++ b/vendor/proc-macro-error-attr/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "proc-macro-error-attr" +version = "1.0.4" +authors = ["CreepySkeleton "] +build = "build.rs" +description = "Attribute macro for proc-macro-error crate" +license = "MIT OR Apache-2.0" +repository = "https://gitlab.com/CreepySkeleton/proc-macro-error" +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] + +[lib] +proc-macro = true +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" +[build-dependencies.version_check] +version = "0.9" diff --git a/vendor/proc-macro-error-attr/LICENSE-APACHE b/vendor/proc-macro-error-attr/LICENSE-APACHE new file mode 100644 index 0000000000..658240a840 --- /dev/null +++ b/vendor/proc-macro-error-attr/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2019-2020 CreepySkeleton + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/proc-macro-error-attr/LICENSE-MIT b/vendor/proc-macro-error-attr/LICENSE-MIT new file mode 100644 index 0000000000..fc73e591d7 --- /dev/null +++ b/vendor/proc-macro-error-attr/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 CreepySkeleton + +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 --git a/vendor/proc-macro-error-attr/build.rs b/vendor/proc-macro-error-attr/build.rs new file mode 100644 index 0000000000..f2ac6a70ee --- /dev/null +++ b/vendor/proc-macro-error-attr/build.rs @@ -0,0 +1,5 @@ +fn main() { + if version_check::is_max_version("1.36.0").unwrap_or(false) { + println!("cargo:rustc-cfg=always_assert_unwind"); + } +} diff --git a/vendor/proc-macro-error-attr/src/lib.rs b/vendor/proc-macro-error-attr/src/lib.rs new file mode 100644 index 0000000000..ac0ac21a26 --- /dev/null +++ b/vendor/proc-macro-error-attr/src/lib.rs @@ -0,0 +1,121 @@ +//! This is `#[proc_macro_error]` attribute to be used with +//! [`proc-macro-error`](https://docs.rs/proc-macro-error/). There you go. + +extern crate proc_macro; + +use crate::parse::parse_input; +use crate::parse::Attribute; +use proc_macro::TokenStream; +use proc_macro2::{Literal, Span, TokenStream as TokenStream2, TokenTree}; +use quote::{quote, quote_spanned}; + +use crate::settings::{Setting::*, *}; + +mod parse; +mod settings; + +type Result = std::result::Result; + +struct Error { + span: Span, + message: String, +} + +impl Error { + fn new(span: Span, message: String) -> Self { + Error { span, message } + } + + fn into_compile_error(self) -> TokenStream2 { + let mut message = Literal::string(&self.message); + message.set_span(self.span); + quote_spanned!(self.span=> compile_error!{#message}) + } +} + +#[proc_macro_attribute] +pub fn proc_macro_error(attr: TokenStream, input: TokenStream) -> TokenStream { + match impl_proc_macro_error(attr.into(), input.clone().into()) { + Ok(ts) => ts, + Err(e) => { + let error = e.into_compile_error(); + let input = TokenStream2::from(input); + + quote!(#input #error).into() + } + } +} + +fn impl_proc_macro_error(attr: TokenStream2, input: TokenStream2) -> Result { + let (attrs, signature, body) = parse_input(input)?; + let mut settings = parse_settings(attr)?; + + let is_proc_macro = is_proc_macro(&attrs); + if is_proc_macro { + settings.set(AssertUnwindSafe); + } + + if detect_proc_macro_hack(&attrs) { + settings.set(ProcMacroHack); + } + + if settings.is_set(ProcMacroHack) { + settings.set(AllowNotMacro); + } + + if !(settings.is_set(AllowNotMacro) || is_proc_macro) { + return Err(Error::new( + Span::call_site(), + "#[proc_macro_error] attribute can be used only with procedural macros\n\n \ + = hint: if you are really sure that #[proc_macro_error] should be applied \ + to this exact function, use #[proc_macro_error(allow_not_macro)]\n" + .into(), + )); + } + + let body = gen_body(body, settings); + + let res = quote! { + #(#attrs)* + #(#signature)* + { #body } + }; + Ok(res.into()) +} + +#[cfg(not(always_assert_unwind))] +fn gen_body(block: TokenTree, settings: Settings) -> proc_macro2::TokenStream { + let is_proc_macro_hack = settings.is_set(ProcMacroHack); + let closure = if settings.is_set(AssertUnwindSafe) { + quote!(::std::panic::AssertUnwindSafe(|| #block )) + } else { + quote!(|| #block) + }; + + quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) ) +} + +// FIXME: +// proc_macro::TokenStream does not implement UnwindSafe until 1.37.0. +// Considering this is the closure's return type the unwind safety check would fail +// for virtually every closure possible, the check is meaningless. +#[cfg(always_assert_unwind)] +fn gen_body(block: TokenTree, settings: Settings) -> proc_macro2::TokenStream { + let is_proc_macro_hack = settings.is_set(ProcMacroHack); + let closure = quote!(::std::panic::AssertUnwindSafe(|| #block )); + quote!( ::proc_macro_error::entry_point(#closure, #is_proc_macro_hack) ) +} + +fn detect_proc_macro_hack(attrs: &[Attribute]) -> bool { + attrs + .iter() + .any(|attr| attr.path_is_ident("proc_macro_hack")) +} + +fn is_proc_macro(attrs: &[Attribute]) -> bool { + attrs.iter().any(|attr| { + attr.path_is_ident("proc_macro") + || attr.path_is_ident("proc_macro_derive") + || attr.path_is_ident("proc_macro_attribute") + }) +} diff --git a/vendor/proc-macro-error-attr/src/parse.rs b/vendor/proc-macro-error-attr/src/parse.rs new file mode 100644 index 0000000000..6f4663f80e --- /dev/null +++ b/vendor/proc-macro-error-attr/src/parse.rs @@ -0,0 +1,89 @@ +use crate::{Error, Result}; +use proc_macro2::{Delimiter, Ident, Span, TokenStream, TokenTree}; +use quote::ToTokens; +use std::iter::Peekable; + +pub(crate) fn parse_input( + input: TokenStream, +) -> Result<(Vec, Vec, TokenTree)> { + let mut input = input.into_iter().peekable(); + let mut attrs = Vec::new(); + + while let Some(attr) = parse_next_attr(&mut input)? { + attrs.push(attr); + } + + let sig = parse_signature(&mut input); + let body = input.next().ok_or_else(|| { + Error::new( + Span::call_site(), + "`#[proc_macro_error]` can be applied only to functions".to_string(), + ) + })?; + + Ok((attrs, sig, body)) +} + +fn parse_next_attr( + input: &mut Peekable>, +) -> Result> { + let shebang = match input.peek() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == '#' => input.next().unwrap(), + _ => return Ok(None), + }; + + let group = match input.peek() { + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Bracket => { + let res = group.clone(); + input.next(); + res + } + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected `[`".to_string())); + } + }; + + let path = match group.stream().into_iter().next() { + Some(TokenTree::Ident(ident)) => Some(ident), + _ => None, + }; + + Ok(Some(Attribute { + shebang, + group: TokenTree::Group(group), + path, + })) +} + +fn parse_signature(input: &mut Peekable>) -> Vec { + let mut sig = Vec::new(); + loop { + match input.peek() { + Some(TokenTree::Group(ref group)) if group.delimiter() == Delimiter::Brace => { + return sig; + } + None => return sig, + _ => sig.push(input.next().unwrap()), + } + } +} + +pub(crate) struct Attribute { + pub(crate) shebang: TokenTree, + pub(crate) group: TokenTree, + pub(crate) path: Option, +} + +impl Attribute { + pub(crate) fn path_is_ident(&self, ident: &str) -> bool { + self.path.as_ref().map_or(false, |p| *p == ident) + } +} + +impl ToTokens for Attribute { + fn to_tokens(&self, ts: &mut TokenStream) { + self.shebang.to_tokens(ts); + self.group.to_tokens(ts); + } +} diff --git a/vendor/proc-macro-error-attr/src/settings.rs b/vendor/proc-macro-error-attr/src/settings.rs new file mode 100644 index 0000000000..0b7ec766f6 --- /dev/null +++ b/vendor/proc-macro-error-attr/src/settings.rs @@ -0,0 +1,72 @@ +use crate::{Error, Result}; +use proc_macro2::{Ident, Span, TokenStream, TokenTree}; + +macro_rules! decl_settings { + ($($val:expr => $variant:ident),+ $(,)*) => { + #[derive(PartialEq)] + pub(crate) enum Setting { + $($variant),* + } + + fn ident_to_setting(ident: Ident) -> Result { + match &*ident.to_string() { + $($val => Ok(Setting::$variant),)* + _ => { + let possible_vals = [$($val),*] + .iter() + .map(|v| format!("`{}`", v)) + .collect::>() + .join(", "); + + Err(Error::new( + ident.span(), + format!("unknown setting `{}`, expected one of {}", ident, possible_vals))) + } + } + } + }; +} + +decl_settings! { + "assert_unwind_safe" => AssertUnwindSafe, + "allow_not_macro" => AllowNotMacro, + "proc_macro_hack" => ProcMacroHack, +} + +pub(crate) fn parse_settings(input: TokenStream) -> Result { + let mut input = input.into_iter(); + let mut res = Settings(Vec::new()); + loop { + match input.next() { + Some(TokenTree::Ident(ident)) => { + res.0.push(ident_to_setting(ident)?); + } + None => return Ok(res), + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected identifier".to_string())); + } + } + + match input.next() { + Some(TokenTree::Punct(ref punct)) if punct.as_char() == ',' => {} + None => return Ok(res), + other => { + let span = other.map_or(Span::call_site(), |tt| tt.span()); + return Err(Error::new(span, "expected `,`".to_string())); + } + } + } +} + +pub(crate) struct Settings(Vec); + +impl Settings { + pub(crate) fn is_set(&self, setting: Setting) -> bool { + self.0.iter().any(|s| *s == setting) + } + + pub(crate) fn set(&mut self, setting: Setting) { + self.0.push(setting) + } +} diff --git a/vendor/proc-macro-error/.cargo-checksum.json b/vendor/proc-macro-error/.cargo-checksum.json new file mode 100644 index 0000000000..79bcfa696f --- /dev/null +++ b/vendor/proc-macro-error/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"b84c4baa5fb093c6aaca44b98f9f28ef54d399ef6dd43c91f1dca618ab366b45","Cargo.toml":"50db093e1a4617606939dfb1f098cb59babbea0d7b390e973a3ed6bb1406170d","LICENSE-APACHE":"4665f973ccb9393807a7fb1264add6b3513d19abc6b357e4cb52c6fe59cc6a3b","LICENSE-MIT":"544b3aed1fd723d0cadea567affdcfe0431e43e18d997a718f9d67256b814fde","README.md":"72d59787d0a1f7bf161e292d0bc1bc25fdfb08cd6ad379a34cc3ed1b388d11fa","build.rs":"6238a0ad4f1146fbf55112419609e6449986154cf7ded1b5fdc978b06f4413b3","src/diagnostic.rs":"cb8724bb0bf9d2eee2f7119d0960fd5349edaa80e147abdef060ebf4572eca01","src/dummy.rs":"b44728091ddcdf9786523c01178efcedd83462bfe8bac6b97b1c2ffb19c96d09","src/imp/delegate.rs":"81da3a602a883240161dd98deb52b3b4ae29e626bfd2e1e07ef5e38d1be00679","src/imp/fallback.rs":"c3d333aba1122ac7e26f038f69750aa02e6a1222433a7cffd1c2f961befedd93","src/lib.rs":"e563d5dceaeb81551a5cb2610c1a3ad1a46200a6cbf8c3c3b394d8ac307b8cfa","src/macros.rs":"3be6feccd343cd9dc4bf03780f3107909bf70e02c6c7c72912e4b160dc6a68fc","src/sealed.rs":"dcf569c4c7ce1d372ff51b0fa73fa67f995bdca8e520cb225cde789c71276439","tests/macro-errors.rs":"7f793921dfbec692bfb2bbb067faf0480c0e7eeec83982b5e9fcddd817817616","tests/ok.rs":"a8c1925ac8647d185c7490ed1e33e3ce3203f5945bd3db4dcaf50ea55078df29","tests/runtime-errors.rs":"e53aa7d8e6c0e5128a90e856105eb05e4e7e72ea6db1bd580f3fe439bff62f24","tests/ui/abort.rs":"e209c8dd9dde6bde7440f8795624ad84b0f8486f563c8fe838238818f459bb67","tests/ui/abort.stderr":"dd0605e79be0309f92b251d055f087b0375c48ec60da978df354b48e8563fa10","tests/ui/append_dummy.rs":"ecaf939c8aabd94eef2dd1c10e9515489ba78e4db5b25195e19833b020d2483c","tests/ui/append_dummy.stderr":"ef03b01fc823aba8cfb9eb6d116640ca953fec569e61ed6ed6b7b7fa3bbad686","tests/ui/children_messages.rs":"32299679804133cb5295ed7a9341bf1ab86a4f1277679ee9738a83115c6b1d2b","tests/ui/children_messages.stderr":"dadeb86e1c7094d5fb38664b1766212b3d083fbe04962c137f8281fb3f5d162e","tests/ui/dummy.rs":"ba51c9158cef88ff2ddf0185be26fcd35a641d73c7124fab9ace0bbd546de847","tests/ui/dummy.stderr":"0635fd563d26691d07a2a875111f0b5e155caa45c37ad9cbaefe5fe617eac703","tests/ui/emit.rs":"82aaf06bcee56b7e139bbcba3a92c29448af14974d6806a28c9961aa764026e5","tests/ui/emit.stderr":"d3daa6d304453d436317495b7fc1d9d36bbebb7705bef75a5260d6d8fcfad5b1","tests/ui/explicit_span_range.rs":"3c37d5fc75b2bd460a091acd97a19acc80a40ba8d1d4ac7f36cd2f0e171bf5e7","tests/ui/explicit_span_range.stderr":"d7562847c326badbce2df8546e6f625eef0725b1dd2c786a037cc46357e4d2e8","tests/ui/misuse.rs":"0d66c61ab5c9723cf2f85cd12216751ab09722e9386cc27928034ee17f1c34e3","tests/ui/misuse.stderr":"52568a2208423e8e4050774559f269e79181a350f0805a34880bfa208e08c6bb","tests/ui/multiple_tokens.rs":"74997da1fdd3bce88a04ab42866c651723861fba4f59e826ee602d905398dcca","tests/ui/multiple_tokens.stderr":"e347ef1c18949711ce41957848e255095132f855c94db1e7e28d32e7d2c79a74","tests/ui/not_proc_macro.rs":"ca448d832ccf0cfdcda6f04281d8134a76c61b3ad96437e972b2cb5c6e0844c4","tests/ui/not_proc_macro.stderr":"a22c53a7dd5a03ddfaee5a7fb7fe5d61cb588b2d81a30c1e935b789baf0d2676","tests/ui/option_ext.rs":"1db81c17172f155c0ca8bcf92d55b5852b92107a3ba1d4b2ae6d14020df67f96","tests/ui/option_ext.stderr":"3b363759db60ee4f249dfde4d4571963032d5f0043249de40bd3b38eecc65404","tests/ui/proc_macro_hack.rs":"1d08c3e2c4c331e230c7cdaa2635ca1e43077252f90d3a430dcd091c646a842c","tests/ui/proc_macro_hack.stderr":"65e887dc208b92bfcd44405e76d5d05e315c3c5c5f637070954b7d593c723731","tests/ui/result_ext.rs":"ef398e76aab82a574ca5a988a91353e1a87fcfcb459d30314eceed3cbcf6fcd8","tests/ui/result_ext.stderr":"9e1e387b1378d9ec40ccb29be9f8cdaa5b42060c3f4f9b3c09fb307d5dcf7d85","tests/ui/to_tokens_span.rs":"d017a3c4cd583defe9806cdc51220bde89ced871ddd4d65b7cd089882feb1f61","tests/ui/to_tokens_span.stderr":"0b88e659ab214d6c7dfcd99274d327fe72da4b9bd009477e0e65165ddde65e02","tests/ui/unknown_setting.rs":"16fe9631b51023909497e857a6c674cd216ba9802fbdba360bb8273d6e00fa31","tests/ui/unknown_setting.stderr":"d605f151ce8eba5b2f867667394bd2d2adf0a233145516a9d6b801817521e587","tests/ui/unrelated_panic.rs":"438db25f8f14f1263152545a1c5135e20b3f5063dc4ab223fd8145b891039b24","tests/ui/unrelated_panic.stderr":"04cd814f2bd57d5271f93f90f0dd078b09ee3fd73137245a914d698e4a33ed57"},"package":"da25490ff9892aab3fcf7c36f08cfb902dd3e71ca0f9f9517bea02a73a5ce38c"} \ No newline at end of file diff --git a/vendor/proc-macro-error/CHANGELOG.md b/vendor/proc-macro-error/CHANGELOG.md new file mode 100644 index 0000000000..3c422f1c45 --- /dev/null +++ b/vendor/proc-macro-error/CHANGELOG.md @@ -0,0 +1,162 @@ +# v1.0.4 (2020-7-31) + +* `SpanRange` facility is now public. +* Docs have been improved. +* Introduced the `syn-error` feature so you can opt-out from the `syn` dependency. + +# v1.0.3 (2020-6-26) + +* Corrected a few typos. +* Fixed the `emit_call_site_warning` macro. + +# v1.0.2 (2020-4-9) + +* An obsolete note was removed from documentation. + +# v1.0.1 (2020-4-9) + +* `proc-macro-hack` is now well tested and supported. Not sure about `proc-macro-nested`, + please fill a request if you need it. +* Fixed `emit_call_site_error`. +* Documentation improvements. + +# v1.0.0 (2020-3-25) + +I believe the API can be considered stable because it's been a few months without +breaking changes, and I also don't think this crate will receive much further evolution. +It's perfect, admit it. + +Hence, meet the new, stable release! + +### Improvements + +* Supported nested `#[proc_macro_error]` attributes. Well, you aren't supposed to do that, + but I caught myself doing it by accident on one occasion and the behavior was... surprising. + Better to handle this smooth. + +# v0.4.12 (2020-3-23) + +* Error message on macros' misuse is now a bit more understandable. + +# v0.4.11 (2020-3-02) + +* `build.rs` no longer fails when `rustc` date could not be determined, + (thanks to [`Fabian Möller`](https://gitlab.com/CreepySkeleton/proc-macro-error/issues/8) + for noticing and to [`Igor Gnatenko`](https://gitlab.com/CreepySkeleton/proc-macro-error/-/merge_requests/25) + for fixing). + +# v0.4.10 (2020-2-29) + +* `proc-macro-error` doesn't depend on syn\[full\] anymore, the compilation + is \~30secs faster. + +# v0.4.9 (2020-2-13) + +* New function: `append_dummy`. + +# v0.4.8 (2020-2-01) + +* Support for children messages + +# v0.4.7 (2020-1-31) + +* Now any type that implements `quote::ToTokens` can be used instead of spans. + This allows for high quality error messages. + +# v0.4.6 (2020-1-31) + +* `From` implementation doesn't lose span info anymore, see + [#6](https://gitlab.com/CreepySkeleton/proc-macro-error/issues/6). + +# v0.4.5 (2020-1-20) +Just a small intermediate release. + +* Fix some bugs. +* Populate license files into subfolders. + +# v0.4.4 (2019-11-13) +* Fix `abort_if_dirty` + warnings bug +* Allow trailing commas in macros + +# v0.4.2 (2019-11-7) +* FINALLY fixed `__pme__suggestions not found` bug + +# v0.4.1 (2019-11-7) YANKED +* Fixed `__pme__suggestions not found` bug +* Documentation improvements, links checked + +# v0.4.0 (2019-11-6) YANKED + +## New features +* "help" messages that can have their own span on nightly, they + inherit parent span on stable. + ```rust + let cond_help = if condition { Some("some help message") else { None } }; + abort!( + span, // parent span + "something's wrong, {} wrongs in total", 10; // main message + help = "here's a help for you, {}", "take it"; // unconditional help message + help =? cond_help; // conditional help message, must be Option + note = note_span => "don't forget the note, {}", "would you?" // notes can have their own span but it's effective only on nightly + ) + ``` +* Warnings via `emit_warning` and `emit_warning_call_site`. Nightly only, they're ignored on stable. +* Now `proc-macro-error` delegates to `proc_macro::Diagnostic` on nightly. + +## Breaking changes +* `MacroError` is now replaced by `Diagnostic`. Its API resembles `proc_macro::Diagnostic`. +* `Diagnostic` does not implement `From<&str/String>` so `Result::abort_or_exit()` + won't work anymore (nobody used it anyway). +* `macro_error!` macro is replaced with `diagnostic!`. + +## Improvements +* Now `proc-macro-error` renders notes exactly just like rustc does. +* We don't parse a body of a function annotated with `#[proc_macro_error]` anymore, + only looking at the signature. This should somewhat decrease expansion time for large functions. + +# v0.3.3 (2019-10-16) +* Now you can use any word instead of "help", undocumented. + +# v0.3.2 (2019-10-16) +* Introduced support for "help" messages, undocumented. + +# v0.3.0 (2019-10-8) + +## The crate has been completely rewritten from scratch! + +## Changes (most are breaking): +* Renamed macros: + * `span_error` => `abort` + * `call_site_error` => `abort_call_site` +* `filter_macro_errors` was replaced by `#[proc_macro_error]` attribute. +* `set_dummy` now takes `TokenStream` instead of `Option` +* Support for multiple errors via `emit_error` and `emit_call_site_error` +* New `macro_error` macro for building errors in format=like style. +* `MacroError` API had been reconsidered. It also now implements `quote::ToTokens`. + +# v0.2.6 (2019-09-02) +* Introduce support for dummy implementations via `dummy::set_dummy` +* `multi::*` is now deprecated, will be completely rewritten in v0.3 + +# v0.2.0 (2019-08-15) + +## Breaking changes +* `trigger_error` replaced with `MacroError::trigger` and `filter_macro_error_panics` + is hidden from docs. + This is not quite a breaking change since users weren't supposed to use these functions directly anyway. +* All dependencies are updated to `v1.*`. + +## New features +* Ability to stack multiple errors via `multi::MultiMacroErrors` and emit them at once. + +## Improvements +* Now `MacroError` implements `std::fmt::Display` instead of `std::string::ToString`. +* `MacroError::span` inherent method. +* `From for proc_macro/proc_macro2::TokenStream` implementations. +* `AsRef/AsMut for MacroError` implementations. + +# v0.1.x (2019-07-XX) + +## New features +* An easy way to report errors inside within a proc-macro via `span_error`, + `call_site_error` and `filter_macro_errors`. diff --git a/vendor/proc-macro-error/Cargo.toml b/vendor/proc-macro-error/Cargo.toml new file mode 100644 index 0000000000..869585ffc2 --- /dev/null +++ b/vendor/proc-macro-error/Cargo.toml @@ -0,0 +1,56 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "proc-macro-error" +version = "1.0.4" +authors = ["CreepySkeleton "] +build = "build.rs" +description = "Almost drop-in replacement to panics in proc-macros" +readme = "README.md" +keywords = ["proc-macro", "error", "errors"] +categories = ["development-tools::procedural-macro-helpers"] +license = "MIT OR Apache-2.0" +repository = "https://gitlab.com/CreepySkeleton/proc-macro-error" +[package.metadata.docs.rs] +targets = ["x86_64-unknown-linux-gnu"] +[dependencies.proc-macro-error-attr] +version = "=1.0.4" + +[dependencies.proc-macro2] +version = "1" + +[dependencies.quote] +version = "1" + +[dependencies.syn] +version = "1" +optional = true +default-features = false +[dev-dependencies.serde_derive] +version = "=1.0.107" + +[dev-dependencies.toml] +version = "=0.5.2" + +[dev-dependencies.trybuild] +version = "1.0.19" +features = ["diff"] +[build-dependencies.version_check] +version = "0.9" + +[features] +default = ["syn-error"] +syn-error = ["syn"] +[badges.maintenance] +status = "passively-maintained" diff --git a/vendor/proc-macro-error/LICENSE-APACHE b/vendor/proc-macro-error/LICENSE-APACHE new file mode 100644 index 0000000000..cc17374b25 --- /dev/null +++ b/vendor/proc-macro-error/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright 2019-2020 CreepySkeleton + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/proc-macro-error/LICENSE-MIT b/vendor/proc-macro-error/LICENSE-MIT new file mode 100644 index 0000000000..fc73e591d7 --- /dev/null +++ b/vendor/proc-macro-error/LICENSE-MIT @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019-2020 CreepySkeleton + +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 --git a/vendor/proc-macro-error/README.md b/vendor/proc-macro-error/README.md new file mode 100644 index 0000000000..7fbe07c53a --- /dev/null +++ b/vendor/proc-macro-error/README.md @@ -0,0 +1,258 @@ +# Makes error reporting in procedural macros nice and easy + +[![travis ci](https://travis-ci.org/CreepySkeleton/proc-macro-error.svg?branch=master)](https://travis-ci.org/CreepySkeleton/proc-macro-error) +[![docs.rs](https://docs.rs/proc-macro-error/badge.svg)](https://docs.rs/proc-macro-error) +[![unsafe forbidden](https://img.shields.io/badge/unsafe-forbidden-success.svg)](https://github.com/rust-secure-code/safety-dance/) + +This crate aims to make error reporting in proc-macros simple and easy to use. +Migrate from `panic!`-based errors for as little effort as possible! + +Also, you can explicitly [append a dummy token stream][crate::dummy] to your errors. + +To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and +`compile_error!`. It detects the most preferable way to emit errors based on compiler's version. +When the underlying diagnostic type is finally stabilized, this crate will be simply +delegating to it, requiring no changes in your code! + +So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality +available on stable ahead of time and your error-reporting code future-proof. + +```toml +[dependencies] +proc-macro-error = "1.0" +``` + +*Supports rustc 1.31 and up* + +[Documentation and guide][guide] + +## Quick example + +Code: + +```rust +#[proc_macro] +#[proc_macro_error] +pub fn make_fn(input: TokenStream) -> TokenStream { + let mut input = TokenStream2::from(input).into_iter(); + let name = input.next().unwrap(); + if let Some(second) = input.next() { + abort! { second, + "I don't like this part!"; + note = "I see what you did there..."; + help = "I need only one part, you know?"; + } + } + + quote!( fn #name() {} ).into() +} +``` + +This is how the error is rendered in a terminal: + +

    + +

    + +And this is what your users will see in their IDE: + +

    + +

    + +## Examples + +### Panic-like usage + +```rust +use proc_macro_error::{ + proc_macro_error, + abort, + abort_call_site, + ResultExt, + OptionExt, +}; +use proc_macro::TokenStream; +use syn::{DeriveInput, parse_macro_input}; +use quote::quote; + +// This is your main entry point +#[proc_macro] +// This attribute *MUST* be placed on top of the #[proc_macro] function +#[proc_macro_error] +pub fn make_answer(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as DeriveInput); + + if let Err(err) = some_logic(&input) { + // we've got a span to blame, let's use it + // This immediately aborts the proc-macro and shows the error + // + // You can use `proc_macro::Span`, `proc_macro2::Span`, and + // anything that implements `quote::ToTokens` (almost every type from + // `syn` and `proc_macro2`) + abort!(err, "You made an error, go fix it: {}", err.msg); + } + + // `Result` has some handy shortcuts if your error type implements + // `Into`. `Option` has one unconditionally. + more_logic(&input).expect_or_abort("What a careless user, behave!"); + + if !more_logic_for_logic_god(&input) { + // We don't have an exact location this time, + // so just highlight the proc-macro invocation itself + abort_call_site!( + "Bad, bad user! Now go stand in the corner and think about what you did!"); + } + + // Now all the processing is done, return `proc_macro::TokenStream` + quote!(/* stuff */).into() +} +``` + +### `proc_macro::Diagnostic`-like usage + +```rust +use proc_macro_error::*; +use proc_macro::TokenStream; +use syn::{spanned::Spanned, DeriveInput, ItemStruct, Fields, Attribute , parse_macro_input}; +use quote::quote; + +fn process_attrs(attrs: &[Attribute]) -> Vec { + attrs + .iter() + .filter_map(|attr| match process_attr(attr) { + Ok(res) => Some(res), + Err(msg) => { + emit_error!(attr, "Invalid attribute: {}", msg); + None + } + }) + .collect() +} + +fn process_fields(_attrs: &Fields) -> Vec { + // processing fields in pretty much the same way as attributes + unimplemented!() +} + +#[proc_macro] +#[proc_macro_error] +pub fn make_answer(input: TokenStream) -> TokenStream { + let input = parse_macro_input!(input as ItemStruct); + let attrs = process_attrs(&input.attrs); + + // abort right now if some errors were encountered + // at the attributes processing stage + abort_if_dirty(); + + let fields = process_fields(&input.fields); + + // no need to think about emitted errors + // #[proc_macro_error] will handle them for you + // + // just return a TokenStream as you normally would + quote!(/* stuff */).into() +} +``` + +## Real world examples + +* [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive) + (abort-like usage) +* [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage) + +## Limitations + +- Warnings are emitted only on nightly, they are ignored on stable. +- "help" suggestions can't have their own span info on stable, + (essentially inheriting the parent span). +- If your macro happens to trigger a panic, no errors will be displayed. This is not a + technical limitation but rather intentional design. `panic` is not for error reporting. + +## MSRV policy + +`proc_macro_error` will always be compatible with proc-macro Holy Trinity: +`proc_macro2`, `syn`, `quote` crates. In other words, if the Trinity is available +to you - `proc_macro_error` is available too. + +> **Important!** +> +> If you want to use `#[proc_macro_error]` with `synstructure`, you're going +> to have to put the attribute inside the `decl_derive!` invocation. Unfortunately, +> due to some bug in pre-1.34 rustc, putting proc-macro attributes inside macro +> invocations doesn't work, so your MSRV is effectively 1.34. + +## Motivation + +Error handling in proc-macros sucks. There's not much of a choice today: +you either "bubble up" the error up to the top-level of the macro and convert it to +a [`compile_error!`][compl_err] invocation or just use a good old panic. Both these ways suck: + +- Former sucks because it's quite redundant to unroll a proper error handling + just for critical errors that will crash the macro anyway; so people mostly + choose not to bother with it at all and use panic. Simple `.expect` is too tempting. + + Also, if you do decide to implement this `Result`-based architecture in your macro + you're going to have to rewrite it entirely once [`proc_macro::Diagnostic`][] is finally + stable. Not cool. + +- Later sucks because there's no way to carry out the span info via `panic!`. + `rustc` will highlight the invocation itself but not some specific token inside it. + + Furthermore, panics aren't for error-reporting at all; panics are for bug-detecting + (like unwrapping on `None` or out-of-range indexing) or for early development stages + when you need a prototype ASAP so error handling can wait. Mixing these usages only + messes things up. + +- There is [`proc_macro::Diagnostic`][] which is awesome but it has been experimental + for more than a year and is unlikely to be stabilized any time soon. + + This crate's API is intentionally designed to be compatible with `proc_macro::Diagnostic` + and delegates to it whenever possible. Once `Diagnostics` is stable this crate + will **always** delegate to it, no code changes will be required on user side. + +That said, we need a solution, but this solution must meet these conditions: + +- It must be better than `panic!`. The main point: it must offer a way to carry the span information + over to user. +- It must take as little effort as possible to migrate from `panic!`. Ideally, a new + macro with similar semantics plus ability to carry out span info. +- It must maintain compatibility with [`proc_macro::Diagnostic`][] . +- **It must be usable on stable**. + +This crate aims to provide such a mechanism. All you have to do is annotate your top-level +`#[proc_macro]` function with `#[proc_macro_error]` attribute and change panics to +[`abort!`]/[`abort_call_site!`] where appropriate, see [the Guide][guide]. + +## Disclaimer +Please note that **this crate is not intended to be used in any way other +than error reporting in procedural macros**, use `Result` and `?` (possibly along with one of the +many helpers out there) for anything else. + +
    + +#### License + + +Licensed under either of Apache License, Version +2.0 or MIT license at your option. + + +
    + + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this crate by you, as defined in the Apache-2.0 license, shall +be dual licensed as above, without any additional terms or conditions. + + + +[compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html +[`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html + +[crate::dummy]: https://docs.rs/proc-macro-error/1/proc_macro_error/dummy/index.html +[crate::multi]: https://docs.rs/proc-macro-error/1/proc_macro_error/multi/index.html + +[`abort_call_site!`]: https://docs.rs/proc-macro-error/1/proc_macro_error/macro.abort_call_site.html +[`abort!`]: https://docs.rs/proc-macro-error/1/proc_macro_error/macro.abort.html +[guide]: https://docs.rs/proc-macro-error diff --git a/vendor/proc-macro-error/build.rs b/vendor/proc-macro-error/build.rs new file mode 100644 index 0000000000..3c1196f269 --- /dev/null +++ b/vendor/proc-macro-error/build.rs @@ -0,0 +1,11 @@ +fn main() { + if !version_check::is_feature_flaggable().unwrap_or(false) { + println!("cargo:rustc-cfg=use_fallback"); + } + + if version_check::is_max_version("1.38.0").unwrap_or(false) + || !version_check::Channel::read().unwrap().is_stable() + { + println!("cargo:rustc-cfg=skip_ui_tests"); + } +} diff --git a/vendor/proc-macro-error/src/diagnostic.rs b/vendor/proc-macro-error/src/diagnostic.rs new file mode 100644 index 0000000000..983e6174fe --- /dev/null +++ b/vendor/proc-macro-error/src/diagnostic.rs @@ -0,0 +1,349 @@ +use crate::{abort_now, check_correctness, sealed::Sealed, SpanRange}; +use proc_macro2::Span; +use proc_macro2::TokenStream; + +use quote::{quote_spanned, ToTokens}; + +/// Represents a diagnostic level +/// +/// # Warnings +/// +/// Warnings are ignored on stable/beta +#[derive(Debug, PartialEq)] +pub enum Level { + Error, + Warning, + #[doc(hidden)] + NonExhaustive, +} + +/// Represents a single diagnostic message +#[derive(Debug)] +pub struct Diagnostic { + pub(crate) level: Level, + pub(crate) span_range: SpanRange, + pub(crate) msg: String, + pub(crate) suggestions: Vec<(SuggestionKind, String, Option)>, + pub(crate) children: Vec<(SpanRange, String)>, +} + +/// A collection of methods that do not exist in `proc_macro::Diagnostic` +/// but still useful to have around. +/// +/// This trait is sealed and cannot be implemented outside of `proc_macro_error`. +pub trait DiagnosticExt: Sealed { + /// Create a new diagnostic message that points to the `span_range`. + /// + /// This function is the same as `Diagnostic::spanned` but produces considerably + /// better error messages for multi-token spans on stable. + fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self; + + /// Add another error message to self such that it will be emitted right after + /// the main message. + /// + /// This function is the same as `Diagnostic::span_error` but produces considerably + /// better error messages for multi-token spans on stable. + fn span_range_error(self, span_range: SpanRange, msg: String) -> Self; + + /// Attach a "help" note to your main message, the note will have it's own span on nightly. + /// + /// This function is the same as `Diagnostic::span_help` but produces considerably + /// better error messages for multi-token spans on stable. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + fn span_range_help(self, span_range: SpanRange, msg: String) -> Self; + + /// Attach a note to your main message, the note will have it's own span on nightly. + /// + /// This function is the same as `Diagnostic::span_note` but produces considerably + /// better error messages for multi-token spans on stable. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + fn span_range_note(self, span_range: SpanRange, msg: String) -> Self; +} + +impl DiagnosticExt for Diagnostic { + fn spanned_range(span_range: SpanRange, level: Level, message: String) -> Self { + Diagnostic { + level, + span_range, + msg: message, + suggestions: vec![], + children: vec![], + } + } + + fn span_range_error(mut self, span_range: SpanRange, msg: String) -> Self { + self.children.push((span_range, msg)); + self + } + + fn span_range_help(mut self, span_range: SpanRange, msg: String) -> Self { + self.suggestions + .push((SuggestionKind::Help, msg, Some(span_range))); + self + } + + fn span_range_note(mut self, span_range: SpanRange, msg: String) -> Self { + self.suggestions + .push((SuggestionKind::Note, msg, Some(span_range))); + self + } +} + +impl Diagnostic { + /// Create a new diagnostic message that points to `Span::call_site()` + pub fn new(level: Level, message: String) -> Self { + Diagnostic::spanned(Span::call_site(), level, message) + } + + /// Create a new diagnostic message that points to the `span` + pub fn spanned(span: Span, level: Level, message: String) -> Self { + Diagnostic::spanned_range( + SpanRange { + first: span, + last: span, + }, + level, + message, + ) + } + + /// Add another error message to self such that it will be emitted right after + /// the main message. + pub fn span_error(self, span: Span, msg: String) -> Self { + self.span_range_error( + SpanRange { + first: span, + last: span, + }, + msg, + ) + } + + /// Attach a "help" note to your main message, the note will have it's own span on nightly. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + pub fn span_help(self, span: Span, msg: String) -> Self { + self.span_range_help( + SpanRange { + first: span, + last: span, + }, + msg, + ) + } + + /// Attach a "help" note to your main message. + pub fn help(mut self, msg: String) -> Self { + self.suggestions.push((SuggestionKind::Help, msg, None)); + self + } + + /// Attach a note to your main message, the note will have it's own span on nightly. + /// + /// # Span + /// + /// The span is ignored on stable, the note effectively inherits its parent's (main message) span + pub fn span_note(self, span: Span, msg: String) -> Self { + self.span_range_note( + SpanRange { + first: span, + last: span, + }, + msg, + ) + } + + /// Attach a note to your main message + pub fn note(mut self, msg: String) -> Self { + self.suggestions.push((SuggestionKind::Note, msg, None)); + self + } + + /// The message of main warning/error (no notes attached) + pub fn message(&self) -> &str { + &self.msg + } + + /// Abort the proc-macro's execution and display the diagnostic. + /// + /// # Warnings + /// + /// Warnings are not emitted on stable and beta, but this function will abort anyway. + pub fn abort(self) -> ! { + self.emit(); + abort_now() + } + + /// Display the diagnostic while not aborting macro execution. + /// + /// # Warnings + /// + /// Warnings are ignored on stable/beta + pub fn emit(self) { + check_correctness(); + crate::imp::emit_diagnostic(self); + } +} + +/// **NOT PUBLIC API! NOTHING TO SEE HERE!!!** +#[doc(hidden)] +impl Diagnostic { + pub fn span_suggestion(self, span: Span, suggestion: &str, msg: String) -> Self { + match suggestion { + "help" | "hint" => self.span_help(span, msg), + _ => self.span_note(span, msg), + } + } + + pub fn suggestion(self, suggestion: &str, msg: String) -> Self { + match suggestion { + "help" | "hint" => self.help(msg), + _ => self.note(msg), + } + } +} + +impl ToTokens for Diagnostic { + fn to_tokens(&self, ts: &mut TokenStream) { + use std::borrow::Cow; + + fn ensure_lf(buf: &mut String, s: &str) { + if s.ends_with('\n') { + buf.push_str(s); + } else { + buf.push_str(s); + buf.push('\n'); + } + } + + fn diag_to_tokens( + span_range: SpanRange, + level: &Level, + msg: &str, + suggestions: &[(SuggestionKind, String, Option)], + ) -> TokenStream { + if *level == Level::Warning { + return TokenStream::new(); + } + + let message = if suggestions.is_empty() { + Cow::Borrowed(msg) + } else { + let mut message = String::new(); + ensure_lf(&mut message, msg); + message.push('\n'); + + for (kind, note, _span) in suggestions { + message.push_str(" = "); + message.push_str(kind.name()); + message.push_str(": "); + ensure_lf(&mut message, note); + } + message.push('\n'); + + Cow::Owned(message) + }; + + let mut msg = proc_macro2::Literal::string(&message); + msg.set_span(span_range.last); + let group = quote_spanned!(span_range.last=> { #msg } ); + quote_spanned!(span_range.first=> compile_error!#group) + } + + ts.extend(diag_to_tokens( + self.span_range, + &self.level, + &self.msg, + &self.suggestions, + )); + ts.extend( + self.children + .iter() + .map(|(span_range, msg)| diag_to_tokens(*span_range, &Level::Error, &msg, &[])), + ); + } +} + +#[derive(Debug)] +pub(crate) enum SuggestionKind { + Help, + Note, +} + +impl SuggestionKind { + fn name(&self) -> &'static str { + match self { + SuggestionKind::Note => "note", + SuggestionKind::Help => "help", + } + } +} + +#[cfg(feature = "syn-error")] +impl From for Diagnostic { + fn from(err: syn::Error) -> Self { + use proc_macro2::{Delimiter, TokenTree}; + + fn gut_error(ts: &mut impl Iterator) -> Option<(SpanRange, String)> { + let first = match ts.next() { + // compile_error + None => return None, + Some(tt) => tt.span(), + }; + ts.next().unwrap(); // ! + + let lit = match ts.next().unwrap() { + TokenTree::Group(group) => { + // Currently `syn` builds `compile_error!` invocations + // exclusively in `ident{"..."}` (braced) form which is not + // followed by `;` (semicolon). + // + // But if it changes to `ident("...");` (parenthesized) + // or `ident["..."];` (bracketed) form, + // we will need to skip the `;` as well. + // Highly unlikely, but better safe than sorry. + + if group.delimiter() == Delimiter::Parenthesis + || group.delimiter() == Delimiter::Bracket + { + ts.next().unwrap(); // ; + } + + match group.stream().into_iter().next().unwrap() { + TokenTree::Literal(lit) => lit, + _ => unreachable!(), + } + } + _ => unreachable!(), + }; + + let last = lit.span(); + let mut msg = lit.to_string(); + + // "abc" => abc + msg.pop(); + msg.remove(0); + + Some((SpanRange { first, last }, msg)) + } + + let mut ts = err.to_compile_error().into_iter(); + + let (span_range, msg) = gut_error(&mut ts).unwrap(); + let mut res = Diagnostic::spanned_range(span_range, Level::Error, msg); + + while let Some((span_range, msg)) = gut_error(&mut ts) { + res = res.span_range_error(span_range, msg); + } + + res + } +} diff --git a/vendor/proc-macro-error/src/dummy.rs b/vendor/proc-macro-error/src/dummy.rs new file mode 100644 index 0000000000..571a595aa9 --- /dev/null +++ b/vendor/proc-macro-error/src/dummy.rs @@ -0,0 +1,150 @@ +//! Facility to emit dummy implementations (or whatever) in case +//! an error happen. +//! +//! `compile_error!` does not abort a compilation right away. This means +//! `rustc` doesn't just show you the error and abort, it carries on the +//! compilation process looking for other errors to report. +//! +//! Let's consider an example: +//! +//! ```rust,ignore +//! use proc_macro::TokenStream; +//! use proc_macro_error::*; +//! +//! trait MyTrait { +//! fn do_thing(); +//! } +//! +//! // this proc macro is supposed to generate MyTrait impl +//! #[proc_macro_derive(MyTrait)] +//! #[proc_macro_error] +//! fn example(input: TokenStream) -> TokenStream { +//! // somewhere deep inside +//! abort!(span, "something's wrong"); +//! +//! // this implementation will be generated if no error happened +//! quote! { +//! impl MyTrait for #name { +//! fn do_thing() {/* whatever */} +//! } +//! } +//! } +//! +//! // ================ +//! // in main.rs +//! +//! // this derive triggers an error +//! #[derive(MyTrait)] // first BOOM! +//! struct Foo; +//! +//! fn main() { +//! Foo::do_thing(); // second BOOM! +//! } +//! ``` +//! +//! The problem is: the generated token stream contains only `compile_error!` +//! invocation, the impl was not generated. That means user will see two compilation +//! errors: +//! +//! ```text +//! error: something's wrong +//! --> $DIR/probe.rs:9:10 +//! | +//! 9 |#[proc_macro_derive(MyTrait)] +//! | ^^^^^^^ +//! +//! error[E0599]: no function or associated item named `do_thing` found for type `Foo` in the current scope +//! --> src\main.rs:3:10 +//! | +//! 1 | struct Foo; +//! | ----------- function or associated item `do_thing` not found for this +//! 2 | fn main() { +//! 3 | Foo::do_thing(); // second BOOM! +//! | ^^^^^^^^ function or associated item not found in `Foo` +//! ``` +//! +//! But the second error is meaningless! We definitely need to fix this. +//! +//! Most used approach in cases like this is "dummy implementation" - +//! omit `impl MyTrait for #name` and fill functions bodies with `unimplemented!()`. +//! +//! This is how you do it: +//! +//! ```rust,ignore +//! use proc_macro::TokenStream; +//! use proc_macro_error::*; +//! +//! trait MyTrait { +//! fn do_thing(); +//! } +//! +//! // this proc macro is supposed to generate MyTrait impl +//! #[proc_macro_derive(MyTrait)] +//! #[proc_macro_error] +//! fn example(input: TokenStream) -> TokenStream { +//! // first of all - we set a dummy impl which will be appended to +//! // `compile_error!` invocations in case a trigger does happen +//! set_dummy(quote! { +//! impl MyTrait for #name { +//! fn do_thing() { unimplemented!() } +//! } +//! }); +//! +//! // somewhere deep inside +//! abort!(span, "something's wrong"); +//! +//! // this implementation will be generated if no error happened +//! quote! { +//! impl MyTrait for #name { +//! fn do_thing() {/* whatever */} +//! } +//! } +//! } +//! +//! // ================ +//! // in main.rs +//! +//! // this derive triggers an error +//! #[derive(MyTrait)] // first BOOM! +//! struct Foo; +//! +//! fn main() { +//! Foo::do_thing(); // no more errors! +//! } +//! ``` + +use proc_macro2::TokenStream; +use std::cell::RefCell; + +use crate::check_correctness; + +thread_local! { + static DUMMY_IMPL: RefCell> = RefCell::new(None); +} + +/// Sets dummy token stream which will be appended to `compile_error!(msg);...` +/// invocations in case you'll emit any errors. +/// +/// See [guide](../index.html#guide). +pub fn set_dummy(dummy: TokenStream) -> Option { + check_correctness(); + DUMMY_IMPL.with(|old_dummy| old_dummy.replace(Some(dummy))) +} + +/// Same as [`set_dummy`] but, instead of resetting, appends tokens to the +/// existing dummy (if any). Behaves as `set_dummy` if no dummy is present. +pub fn append_dummy(dummy: TokenStream) { + check_correctness(); + DUMMY_IMPL.with(|old_dummy| { + let mut cell = old_dummy.borrow_mut(); + if let Some(ts) = cell.as_mut() { + ts.extend(dummy); + } else { + *cell = Some(dummy); + } + }); +} + +pub(crate) fn cleanup() -> Option { + DUMMY_IMPL.with(|old_dummy| old_dummy.replace(None)) +} diff --git a/vendor/proc-macro-error/src/imp/delegate.rs b/vendor/proc-macro-error/src/imp/delegate.rs new file mode 100644 index 0000000000..07def2b98e --- /dev/null +++ b/vendor/proc-macro-error/src/imp/delegate.rs @@ -0,0 +1,69 @@ +//! This implementation uses [`proc_macro::Diagnostic`], nightly only. + +use std::cell::Cell; + +use proc_macro::{Diagnostic as PDiag, Level as PLevel}; + +use crate::{ + abort_now, check_correctness, + diagnostic::{Diagnostic, Level, SuggestionKind}, +}; + +pub fn abort_if_dirty() { + check_correctness(); + if IS_DIRTY.with(|c| c.get()) { + abort_now() + } +} + +pub(crate) fn cleanup() -> Vec { + IS_DIRTY.with(|c| c.set(false)); + vec![] +} + +pub(crate) fn emit_diagnostic(diag: Diagnostic) { + let Diagnostic { + level, + span_range, + msg, + suggestions, + children, + } = diag; + + let span = span_range.collapse().unwrap(); + + let level = match level { + Level::Warning => PLevel::Warning, + Level::Error => { + IS_DIRTY.with(|c| c.set(true)); + PLevel::Error + } + _ => unreachable!(), + }; + + let mut res = PDiag::spanned(span, level, msg); + + for (kind, msg, span) in suggestions { + res = match (kind, span) { + (SuggestionKind::Note, Some(span_range)) => { + res.span_note(span_range.collapse().unwrap(), msg) + } + (SuggestionKind::Help, Some(span_range)) => { + res.span_help(span_range.collapse().unwrap(), msg) + } + (SuggestionKind::Note, None) => res.note(msg), + (SuggestionKind::Help, None) => res.help(msg), + } + } + + for (span_range, msg) in children { + let span = span_range.collapse().unwrap(); + res = res.span_error(span, msg); + } + + res.emit() +} + +thread_local! { + static IS_DIRTY: Cell = Cell::new(false); +} diff --git a/vendor/proc-macro-error/src/imp/fallback.rs b/vendor/proc-macro-error/src/imp/fallback.rs new file mode 100644 index 0000000000..ad1f730bfc --- /dev/null +++ b/vendor/proc-macro-error/src/imp/fallback.rs @@ -0,0 +1,30 @@ +//! This implementation uses self-written stable facilities. + +use crate::{ + abort_now, check_correctness, + diagnostic::{Diagnostic, Level}, +}; +use std::cell::RefCell; + +pub fn abort_if_dirty() { + check_correctness(); + ERR_STORAGE.with(|storage| { + if !storage.borrow().is_empty() { + abort_now() + } + }); +} + +pub(crate) fn cleanup() -> Vec { + ERR_STORAGE.with(|storage| storage.replace(Vec::new())) +} + +pub(crate) fn emit_diagnostic(diag: Diagnostic) { + if diag.level == Level::Error { + ERR_STORAGE.with(|storage| storage.borrow_mut().push(diag)); + } +} + +thread_local! { + static ERR_STORAGE: RefCell> = RefCell::new(Vec::new()); +} diff --git a/vendor/proc-macro-error/src/lib.rs b/vendor/proc-macro-error/src/lib.rs new file mode 100644 index 0000000000..fb867fdc03 --- /dev/null +++ b/vendor/proc-macro-error/src/lib.rs @@ -0,0 +1,560 @@ +//! # proc-macro-error +//! +//! This crate aims to make error reporting in proc-macros simple and easy to use. +//! Migrate from `panic!`-based errors for as little effort as possible! +//! +//! (Also, you can explicitly [append a dummy token stream](dummy/index.html) to your errors). +//! +//! To achieve his, this crate serves as a tiny shim around `proc_macro::Diagnostic` and +//! `compile_error!`. It detects the best way of emitting available based on compiler's version. +//! When the underlying diagnostic type is finally stabilized, this crate will simply be +//! delegating to it requiring no changes in your code! +//! +//! So you can just use this crate and have *both* some of `proc_macro::Diagnostic` functionality +//! available on stable ahead of time *and* your error-reporting code future-proof. +//! +//! ## Cargo features +//! +//! This crate provides *enabled by default* `syn-error` feature that gates +//! `impl From for Diagnostic` conversion. If you don't use `syn` and want +//! to cut off some of compilation time, you can disable it via +//! +//! ```toml +//! [dependencies] +//! proc-macro-error = { version = "1", default-features = false } +//! ``` +//! +//! ***Please note that disabling this feature makes sense only if you don't depend on `syn` +//! directly or indirectly, and you very likely do.** +//! +//! ## Real world examples +//! +//! * [`structopt-derive`](https://github.com/TeXitoi/structopt/tree/master/structopt-derive) +//! (abort-like usage) +//! * [`auto-impl`](https://github.com/auto-impl-rs/auto_impl/) (emit-like usage) +//! +//! ## Limitations +//! +//! - Warnings are emitted only on nightly, they are ignored on stable. +//! - "help" suggestions can't have their own span info on stable, +//! (essentially inheriting the parent span). +//! - If a panic occurs somewhere in your macro no errors will be displayed. This is not a +//! technical limitation but rather intentional design. `panic` is not for error reporting. +//! +//! ### `#[proc_macro_error]` attribute +//! +//! **This attribute MUST be present on the top level of your macro** (the function +//! annotated with any of `#[proc_macro]`, `#[proc_macro_derive]`, `#[proc_macro_attribute]`). +//! +//! This attribute performs the setup and cleanup necessary to make things work. +//! +//! In most cases you'll need the simple `#[proc_macro_error]` form without any +//! additional settings. Feel free to [skip the "Syntax" section](#macros). +//! +//! #### Syntax +//! +//! `#[proc_macro_error]` or `#[proc_macro_error(settings...)]`, where `settings...` +//! is a comma-separated list of: +//! +//! - `proc_macro_hack`: +//! +//! In order to correctly cooperate with `#[proc_macro_hack]`, `#[proc_macro_error]` +//! attribute must be placed *before* (above) it, like this: +//! +//! ```no_run +//! # use proc_macro2::TokenStream; +//! # const IGNORE: &str = " +//! #[proc_macro_error] +//! #[proc_macro_hack] +//! #[proc_macro] +//! # "; +//! fn my_macro(input: TokenStream) -> TokenStream { +//! unimplemented!() +//! } +//! ``` +//! +//! If, for some reason, you can't place it like that you can use +//! `#[proc_macro_error(proc_macro_hack)]` instead. +//! +//! # Note +//! +//! If `proc-macro-hack` was detected (by any means) `allow_not_macro` +//! and `assert_unwind_safe` will be applied automatically. +//! +//! - `allow_not_macro`: +//! +//! By default, the attribute checks that it's applied to a proc-macro. +//! If none of `#[proc_macro]`, `#[proc_macro_derive]` nor `#[proc_macro_attribute]` are +//! present it will panic. It's the intention - this crate is supposed to be used only with +//! proc-macros. +//! +//! This setting is made to bypass the check, useful in certain circumstances. +//! +//! Pay attention: the function this attribute is applied to must return +//! `proc_macro::TokenStream`. +//! +//! This setting is implied if `proc-macro-hack` was detected. +//! +//! - `assert_unwind_safe`: +//! +//! By default, your code must be [unwind safe]. If your code is not unwind safe, +//! but you believe it's correct, you can use this setting to bypass the check. +//! You would need this for code that uses `lazy_static` or `thread_local` with +//! `Cell/RefCell` inside (and the like). +//! +//! This setting is implied if `#[proc_macro_error]` is applied to a function +//! marked as `#[proc_macro]`, `#[proc_macro_derive]` or `#[proc_macro_attribute]`. +//! +//! This setting is also implied if `proc-macro-hack` was detected. +//! +//! ## Macros +//! +//! Most of the time you want to use the macros. Syntax is described in the next section below. +//! +//! You'll need to decide how you want to emit errors: +//! +//! * Emit the error and abort. Very much panic-like usage. Served by [`abort!`] and +//! [`abort_call_site!`]. +//! * Emit the error but do not abort right away, looking for other errors to report. +//! Served by [`emit_error!`] and [`emit_call_site_error!`]. +//! +//! You **can** mix these usages. +//! +//! `abort` and `emit_error` take a "source span" as the first argument. This source +//! will be used to highlight the place the error originates from. It must be one of: +//! +//! * *Something* that implements [`ToTokens`] (most types in `syn` and `proc-macro2` do). +//! This source is the preferable one since it doesn't lose span information on multi-token +//! spans, see [this issue](https://gitlab.com/CreepySkeleton/proc-macro-error/-/issues/6) +//! for details. +//! * [`proc_macro::Span`] +//! * [`proc-macro2::Span`] +//! +//! The rest is your message in format-like style. +//! +//! See [the next section](#syntax-1) for detailed syntax. +//! +//! - [`abort!`]: +//! +//! Very much panic-like usage - abort right away and show the error. +//! Expands to [`!`] (never type). +//! +//! - [`abort_call_site!`]: +//! +//! Shortcut for `abort!(Span::call_site(), ...)`. Expands to [`!`] (never type). +//! +//! - [`emit_error!`]: +//! +//! [`proc_macro::Diagnostic`]-like usage - emit the error but keep going, +//! looking for other errors to report. +//! The compilation will fail nonetheless. Expands to [`()`] (unit type). +//! +//! - [`emit_call_site_error!`]: +//! +//! Shortcut for `emit_error!(Span::call_site(), ...)`. Expands to [`()`] (unit type). +//! +//! - [`emit_warning!`]: +//! +//! Like `emit_error!` but emit a warning instead of error. The compilation won't fail +//! because of warnings. +//! Expands to [`()`] (unit type). +//! +//! **Beware**: warnings are nightly only, they are completely ignored on stable. +//! +//! - [`emit_call_site_warning!`]: +//! +//! Shortcut for `emit_warning!(Span::call_site(), ...)`. Expands to [`()`] (unit type). +//! +//! - [`diagnostic`]: +//! +//! Build an instance of `Diagnostic` in format-like style. +//! +//! #### Syntax +//! +//! All the macros have pretty much the same syntax: +//! +//! 1. ```ignore +//! abort!(single_expr) +//! ``` +//! Shortcut for `Diagnostic::from(expr).abort()`. +//! +//! 2. ```ignore +//! abort!(span, message) +//! ``` +//! The first argument is an expression the span info should be taken from. +//! +//! The second argument is the error message, it must implement [`ToString`]. +//! +//! 3. ```ignore +//! abort!(span, format_literal, format_args...) +//! ``` +//! +//! This form is pretty much the same as 2, except `format!(format_literal, format_args...)` +//! will be used to for the message instead of [`ToString`]. +//! +//! That's it. `abort!`, `emit_warning`, `emit_error` share this exact syntax. +//! +//! `abort_call_site!`, `emit_call_site_warning`, `emit_call_site_error` lack 1 form +//! and do not take span in 2'th and 3'th forms. Those are essentially shortcuts for +//! `macro!(Span::call_site(), args...)`. +//! +//! `diagnostic!` requires a [`Level`] instance between `span` and second argument +//! (1'th form is the same). +//! +//! > **Important!** +//! > +//! > If you have some type from `proc_macro` or `syn` to point to, do not call `.span()` +//! > on it but rather use it directly: +//! > ```no_run +//! > # use proc_macro_error::abort; +//! > # let input = proc_macro2::TokenStream::new(); +//! > let ty: syn::Type = syn::parse2(input).unwrap(); +//! > abort!(ty, "BOOM"); +//! > // ^^ <-- avoid .span() +//! > ``` +//! > +//! > `.span()` calls work too, but you may experience regressions in message quality. +//! +//! #### Note attachments +//! +//! 3. Every macro can have "note" attachments (only 2 and 3 form). +//! ```ignore +//! let opt_help = if have_some_info { Some("did you mean `this`?") } else { None }; +//! +//! abort!( +//! span, message; // <--- attachments start with `;` (semicolon) +//! +//! help = "format {} {}", "arg1", "arg2"; // <--- every attachment ends with `;`, +//! // maybe except the last one +//! +//! note = "to_string"; // <--- one arg uses `.to_string()` instead of `format!()` +//! +//! yay = "I see what {} did here", "you"; // <--- "help =" and "hint =" are mapped +//! // to Diagnostic::help, +//! // anything else is Diagnostic::note +//! +//! wow = note_span => "custom span"; // <--- attachments can have their own span +//! // it takes effect only on nightly though +//! +//! hint =? opt_help; // <-- "optional" attachment, get displayed only if `Some` +//! // must be single `Option` expression +//! +//! note =? note_span => opt_help // <-- optional attachments can have custom spans too +//! ); +//! ``` +//! + +//! ### Diagnostic type +//! +//! [`Diagnostic`] type is intentionally designed to be API compatible with [`proc_macro::Diagnostic`]. +//! Not all API is implemented, only the part that can be reasonably implemented on stable. +//! +//! +//! [`abort!`]: macro.abort.html +//! [`abort_call_site!`]: macro.abort_call_site.html +//! [`emit_warning!`]: macro.emit_warning.html +//! [`emit_error!`]: macro.emit_error.html +//! [`emit_call_site_warning!`]: macro.emit_call_site_error.html +//! [`emit_call_site_error!`]: macro.emit_call_site_warning.html +//! [`diagnostic!`]: macro.diagnostic.html +//! [`Diagnostic`]: struct.Diagnostic.html +//! +//! [`proc_macro::Span`]: https://doc.rust-lang.org/proc_macro/struct.Span.html +//! [`proc_macro::Diagnostic`]: https://doc.rust-lang.org/proc_macro/struct.Diagnostic.html +//! +//! [unwind safe]: https://doc.rust-lang.org/std/panic/trait.UnwindSafe.html#what-is-unwind-safety +//! [`!`]: https://doc.rust-lang.org/std/primitive.never.html +//! [`()`]: https://doc.rust-lang.org/std/primitive.unit.html +//! [`ToString`]: https://doc.rust-lang.org/std/string/trait.ToString.html +//! +//! [`proc-macro2::Span`]: https://docs.rs/proc-macro2/1.0.10/proc_macro2/struct.Span.html +//! [`ToTokens`]: https://docs.rs/quote/1.0.3/quote/trait.ToTokens.html +//! + +#![cfg_attr(not(use_fallback), feature(proc_macro_diagnostic))] +#![forbid(unsafe_code)] +#![allow(clippy::needless_doctest_main)] + +extern crate proc_macro; + +pub use crate::{ + diagnostic::{Diagnostic, DiagnosticExt, Level}, + dummy::{append_dummy, set_dummy}, +}; +pub use proc_macro_error_attr::proc_macro_error; + +use proc_macro2::Span; +use quote::{quote, ToTokens}; + +use std::cell::Cell; +use std::panic::{catch_unwind, resume_unwind, UnwindSafe}; + +pub mod dummy; + +mod diagnostic; +mod macros; +mod sealed; + +#[cfg(use_fallback)] +#[path = "imp/fallback.rs"] +mod imp; + +#[cfg(not(use_fallback))] +#[path = "imp/delegate.rs"] +mod imp; + +#[derive(Debug, Clone, Copy)] +pub struct SpanRange { + pub first: Span, + pub last: Span, +} + +impl SpanRange { + /// Create a range with the `first` and `last` spans being the same. + pub fn single_span(span: Span) -> Self { + SpanRange { + first: span, + last: span, + } + } + + /// Create a `SpanRange` resolving at call site. + pub fn call_site() -> Self { + SpanRange::single_span(Span::call_site()) + } + + /// Construct span range from a `TokenStream`. This method always preserves all the + /// range. + /// + /// ### Note + /// + /// If the stream is empty, the result is `SpanRange::call_site()`. If the stream + /// consists of only one `TokenTree`, the result is `SpanRange::single_span(tt.span())` + /// that doesn't lose anything. + pub fn from_tokens(ts: &dyn ToTokens) -> Self { + let mut spans = ts.to_token_stream().into_iter().map(|tt| tt.span()); + let first = spans.next().unwrap_or_else(|| Span::call_site()); + let last = spans.last().unwrap_or(first); + + SpanRange { first, last } + } + + /// Join two span ranges. The resulting range will start at `self.first` and end at + /// `other.last`. + pub fn join_range(self, other: SpanRange) -> Self { + SpanRange { + first: self.first, + last: other.last, + } + } + + /// Collapse the range into single span, preserving as much information as possible. + pub fn collapse(self) -> Span { + self.first.join(self.last).unwrap_or(self.first) + } +} + +/// This traits expands `Result>` with some handy shortcuts. +pub trait ResultExt { + type Ok; + + /// Behaves like `Result::unwrap`: if self is `Ok` yield the contained value, + /// otherwise abort macro execution via `abort!`. + fn unwrap_or_abort(self) -> Self::Ok; + + /// Behaves like `Result::expect`: if self is `Ok` yield the contained value, + /// otherwise abort macro execution via `abort!`. + /// If it aborts then resulting error message will be preceded with `message`. + fn expect_or_abort(self, msg: &str) -> Self::Ok; +} + +/// This traits expands `Option` with some handy shortcuts. +pub trait OptionExt { + type Some; + + /// Behaves like `Option::expect`: if self is `Some` yield the contained value, + /// otherwise abort macro execution via `abort_call_site!`. + /// If it aborts the `message` will be used for [`compile_error!`][compl_err] invocation. + /// + /// [compl_err]: https://doc.rust-lang.org/std/macro.compile_error.html + fn expect_or_abort(self, msg: &str) -> Self::Some; +} + +/// Abort macro execution and display all the emitted errors, if any. +/// +/// Does nothing if no errors were emitted (warnings do not count). +pub fn abort_if_dirty() { + imp::abort_if_dirty(); +} + +impl> ResultExt for Result { + type Ok = T; + + fn unwrap_or_abort(self) -> T { + match self { + Ok(res) => res, + Err(e) => e.into().abort(), + } + } + + fn expect_or_abort(self, message: &str) -> T { + match self { + Ok(res) => res, + Err(e) => { + let mut e = e.into(); + e.msg = format!("{}: {}", message, e.msg); + e.abort() + } + } + } +} + +impl OptionExt for Option { + type Some = T; + + fn expect_or_abort(self, message: &str) -> T { + match self { + Some(res) => res, + None => abort_call_site!(message), + } + } +} + +/// This is the entry point for a proc-macro. +/// +/// **NOT PUBLIC API, SUBJECT TO CHANGE WITHOUT ANY NOTICE** +#[doc(hidden)] +pub fn entry_point(f: F, proc_macro_hack: bool) -> proc_macro::TokenStream +where + F: FnOnce() -> proc_macro::TokenStream + UnwindSafe, +{ + ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() + 1)); + let caught = catch_unwind(f); + let dummy = dummy::cleanup(); + let err_storage = imp::cleanup(); + ENTERED_ENTRY_POINT.with(|flag| flag.set(flag.get() - 1)); + + let gen_error = || { + if proc_macro_hack { + quote! {{ + macro_rules! proc_macro_call { + () => ( unimplemented!() ) + } + + #(#err_storage)* + #dummy + + unimplemented!() + }} + } else { + quote!( #(#err_storage)* #dummy ) + } + }; + + match caught { + Ok(ts) => { + if err_storage.is_empty() { + ts + } else { + gen_error().into() + } + } + + Err(boxed) => match boxed.downcast::() { + Ok(_) => gen_error().into(), + Err(boxed) => resume_unwind(boxed), + }, + } +} + +fn abort_now() -> ! { + check_correctness(); + panic!(AbortNow) +} + +thread_local! { + static ENTERED_ENTRY_POINT: Cell = Cell::new(0); +} + +struct AbortNow; + +fn check_correctness() { + if ENTERED_ENTRY_POINT.with(|flag| flag.get()) == 0 { + panic!( + "proc-macro-error API cannot be used outside of `entry_point` invocation, \ + perhaps you forgot to annotate your #[proc_macro] function with `#[proc_macro_error]" + ); + } +} + +/// **ALL THE STUFF INSIDE IS NOT PUBLIC API!!!** +#[doc(hidden)] +pub mod __export { + // reexports for use in macros + pub extern crate proc_macro; + pub extern crate proc_macro2; + + use proc_macro2::Span; + use quote::ToTokens; + + use crate::SpanRange; + + // inspired by + // https://github.com/dtolnay/case-studies/blob/master/autoref-specialization/README.md#simple-application + + pub trait SpanAsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + pub trait Span2AsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + pub trait ToTokensAsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + pub trait SpanRangeAsSpanRange { + #[allow(non_snake_case)] + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange; + } + + impl ToTokensAsSpanRange for &T { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + let mut ts = self.to_token_stream().into_iter(); + let first = ts + .next() + .map(|tt| tt.span()) + .unwrap_or_else(Span::call_site); + let last = ts.last().map(|tt| tt.span()).unwrap_or(first); + SpanRange { first, last } + } + } + + impl Span2AsSpanRange for Span { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + SpanRange { + first: *self, + last: *self, + } + } + } + + impl SpanAsSpanRange for proc_macro::Span { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + SpanRange { + first: self.clone().into(), + last: self.clone().into(), + } + } + } + + impl SpanRangeAsSpanRange for SpanRange { + fn FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(&self) -> SpanRange { + *self + } + } +} diff --git a/vendor/proc-macro-error/src/macros.rs b/vendor/proc-macro-error/src/macros.rs new file mode 100644 index 0000000000..747b684d56 --- /dev/null +++ b/vendor/proc-macro-error/src/macros.rs @@ -0,0 +1,288 @@ +// FIXME: this can be greatly simplified via $()? +// as soon as MRSV hits 1.32 + +/// Build [`Diagnostic`](struct.Diagnostic.html) instance from provided arguments. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! diagnostic { + // from alias + ($err:expr) => { $crate::Diagnostic::from($err) }; + + // span, message, help + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+ ; $($rest:tt)+) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + let diag = $crate::Diagnostic::spanned_range( + span_range, + $level, + format!($fmt, $($args),*) + ); + $crate::__pme__suggestions!(diag $($rest)*); + diag + }}; + + ($span:expr, $level:expr, $msg:expr ; $($rest:tt)+) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + let diag = $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string()); + $crate::__pme__suggestions!(diag $($rest)*); + diag + }}; + + // span, message, no help + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + $crate::Diagnostic::spanned_range( + span_range, + $level, + format!($fmt, $($args),*) + ) + }}; + + ($span:expr, $level:expr, $msg:expr) => {{ + #[allow(unused_imports)] + use $crate::__export::{ + ToTokensAsSpanRange, + Span2AsSpanRange, + SpanAsSpanRange, + SpanRangeAsSpanRange + }; + use $crate::DiagnosticExt; + let span_range = (&$span).FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange(); + + $crate::Diagnostic::spanned_range(span_range, $level, $msg.to_string()) + }}; + + + // trailing commas + + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+, ; $($rest:tt)+) => { + $crate::diagnostic!($span, $level, $fmt, $($args),* ; $($rest)*) + }; + ($span:expr, $level:expr, $msg:expr, ; $($rest:tt)+) => { + $crate::diagnostic!($span, $level, $msg ; $($rest)*) + }; + ($span:expr, $level:expr, $fmt:expr, $($args:expr),+,) => { + $crate::diagnostic!($span, $level, $fmt, $($args),*) + }; + ($span:expr, $level:expr, $msg:expr,) => { + $crate::diagnostic!($span, $level, $msg) + }; + // ($err:expr,) => { $crate::diagnostic!($err) }; +} + +/// Abort proc-macro execution right now and display the error. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +#[macro_export] +macro_rules! abort { + ($err:expr) => { + $crate::diagnostic!($err).abort() + }; + + ($span:expr, $($tts:tt)*) => { + $crate::diagnostic!($span, $crate::Level::Error, $($tts)*).abort() + }; +} + +/// Shortcut for `abort!(Span::call_site(), msg...)`. This macro +/// is still preferable over plain panic, panics are not for error reporting. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! abort_call_site { + ($($tts:tt)*) => { + $crate::abort!($crate::__export::proc_macro2::Span::call_site(), $($tts)*) + }; +} + +/// Emit an error while not aborting the proc-macro right away. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_error { + ($err:expr) => { + $crate::diagnostic!($err).emit() + }; + + ($span:expr, $($tts:tt)*) => {{ + let level = $crate::Level::Error; + $crate::diagnostic!($span, level, $($tts)*).emit() + }}; +} + +/// Shortcut for `emit_error!(Span::call_site(), ...)`. This macro +/// is still preferable over plain panic, panics are not for error reporting.. +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_call_site_error { + ($($tts:tt)*) => { + $crate::emit_error!($crate::__export::proc_macro2::Span::call_site(), $($tts)*) + }; +} + +/// Emit a warning. Warnings are not errors and compilation won't fail because of them. +/// +/// **Does nothing on stable** +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_warning { + ($span:expr, $($tts:tt)*) => { + $crate::diagnostic!($span, $crate::Level::Warning, $($tts)*).emit() + }; +} + +/// Shortcut for `emit_warning!(Span::call_site(), ...)`. +/// +/// **Does nothing on stable** +/// +/// # Syntax +/// +/// See [the guide](index.html#guide). +/// +#[macro_export] +macro_rules! emit_call_site_warning { + ($($tts:tt)*) => {{ + $crate::emit_warning!($crate::__export::proc_macro2::Span::call_site(), $($tts)*) + }}; +} + +#[doc(hidden)] +#[macro_export] +macro_rules! __pme__suggestions { + ($var:ident) => (); + + ($var:ident $help:ident =? $msg:expr) => { + let $var = if let Some(msg) = $msg { + $var.suggestion(stringify!($help), msg.to_string()) + } else { + $var + }; + }; + ($var:ident $help:ident =? $span:expr => $msg:expr) => { + let $var = if let Some(msg) = $msg { + $var.span_suggestion($span.into(), stringify!($help), msg.to_string()) + } else { + $var + }; + }; + + ($var:ident $help:ident =? $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help =? $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident =? $span:expr => $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help =? $span => $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + + + ($var:ident $help:ident = $msg:expr) => { + let $var = $var.suggestion(stringify!($help), $msg.to_string()); + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+) => { + let $var = $var.suggestion( + stringify!($help), + format!($fmt, $($args),*) + ); + }; + ($var:ident $help:ident = $span:expr => $msg:expr) => { + let $var = $var.span_suggestion($span.into(), stringify!($help), $msg.to_string()); + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+) => { + let $var = $var.span_suggestion( + $span.into(), + stringify!($help), + format!($fmt, $($args),*) + ); + }; + + ($var:ident $help:ident = $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $fmt, $($args),*); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident = $span:expr => $msg:expr ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $msg); + $crate::__pme__suggestions!($var $($rest)*); + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+ ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*); + $crate::__pme__suggestions!($var $($rest)*); + }; + + // trailing commas + + ($var:ident $help:ident = $msg:expr,) => { + $crate::__pme__suggestions!($var $help = $msg) + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+,) => { + $crate::__pme__suggestions!($var $help = $fmt, $($args)*) + }; + ($var:ident $help:ident = $span:expr => $msg:expr,) => { + $crate::__pme__suggestions!($var $help = $span => $msg) + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),*,) => { + $crate::__pme__suggestions!($var $help = $span => $fmt, $($args)*) + }; + ($var:ident $help:ident = $msg:expr, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $msg; $($rest)*) + }; + ($var:ident $help:ident = $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $fmt, $($args),*; $($rest)*) + }; + ($var:ident $help:ident = $span:expr => $msg:expr, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $msg; $($rest)*) + }; + ($var:ident $help:ident = $span:expr => $fmt:expr, $($args:expr),+, ; $($rest:tt)*) => { + $crate::__pme__suggestions!($var $help = $span => $fmt, $($args),*; $($rest)*) + }; +} diff --git a/vendor/proc-macro-error/src/sealed.rs b/vendor/proc-macro-error/src/sealed.rs new file mode 100644 index 0000000000..a2d5081e55 --- /dev/null +++ b/vendor/proc-macro-error/src/sealed.rs @@ -0,0 +1,3 @@ +pub trait Sealed {} + +impl Sealed for crate::Diagnostic {} diff --git a/vendor/proc-macro-error/tests/macro-errors.rs b/vendor/proc-macro-error/tests/macro-errors.rs new file mode 100644 index 0000000000..dd60f88a80 --- /dev/null +++ b/vendor/proc-macro-error/tests/macro-errors.rs @@ -0,0 +1,8 @@ +extern crate trybuild; + +#[cfg_attr(skip_ui_tests, ignore)] +#[test] +fn ui() { + let t = trybuild::TestCases::new(); + t.compile_fail("tests/ui/*.rs"); +} diff --git a/vendor/proc-macro-error/tests/ok.rs b/vendor/proc-macro-error/tests/ok.rs new file mode 100644 index 0000000000..cf64c027f8 --- /dev/null +++ b/vendor/proc-macro-error/tests/ok.rs @@ -0,0 +1,10 @@ +extern crate test_crate; + +use test_crate::*; + +ok!(it_works); + +#[test] +fn check_it_works() { + it_works(); +} diff --git a/vendor/proc-macro-error/tests/runtime-errors.rs b/vendor/proc-macro-error/tests/runtime-errors.rs new file mode 100644 index 0000000000..13108a2d91 --- /dev/null +++ b/vendor/proc-macro-error/tests/runtime-errors.rs @@ -0,0 +1,13 @@ +use proc_macro_error::*; + +#[test] +#[should_panic = "proc-macro-error API cannot be used outside of"] +fn missing_attr_emit() { + emit_call_site_error!("You won't see me"); +} + +#[test] +#[should_panic = "proc-macro-error API cannot be used outside of"] +fn missing_attr_abort() { + abort_call_site!("You won't see me"); +} diff --git a/vendor/proc-macro-error/tests/ui/abort.rs b/vendor/proc-macro-error/tests/ui/abort.rs new file mode 100644 index 0000000000..f63118251e --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/abort.rs @@ -0,0 +1,11 @@ +extern crate test_crate; +use test_crate::*; + +abort_from!(one, two); +abort_to_string!(one, two); +abort_format!(one, two); +direct_abort!(one, two); +abort_notes!(one, two); +abort_call_site_test!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/abort.stderr b/vendor/proc-macro-error/tests/ui/abort.stderr new file mode 100644 index 0000000000..c5399d9d91 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/abort.stderr @@ -0,0 +1,48 @@ +error: abort!(span, from) test + --> $DIR/abort.rs:4:13 + | +4 | abort_from!(one, two); + | ^^^ + +error: abort!(span, single_expr) test + --> $DIR/abort.rs:5:18 + | +5 | abort_to_string!(one, two); + | ^^^ + +error: abort!(span, expr1, expr2) test + --> $DIR/abort.rs:6:15 + | +6 | abort_format!(one, two); + | ^^^ + +error: Diagnostic::abort() test + --> $DIR/abort.rs:7:15 + | +7 | direct_abort!(one, two); + | ^^^ + +error: This is an error + + = note: simple note + = help: simple help + = help: simple hint + = note: simple yay + = note: format note + = note: Some note + = note: spanned simple note + = note: spanned format note + = note: Some note + + --> $DIR/abort.rs:8:14 + | +8 | abort_notes!(one, two); + | ^^^ + +error: abort_call_site! test + --> $DIR/abort.rs:9:1 + | +9 | abort_call_site_test!(one, two); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/append_dummy.rs b/vendor/proc-macro-error/tests/ui/append_dummy.rs new file mode 100644 index 0000000000..53d6feacc1 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/append_dummy.rs @@ -0,0 +1,13 @@ +extern crate test_crate; +use test_crate::*; + +enum NeedDefault { + A, + B +} + +append_dummy!(need_default); + +fn main() { + let _ = NeedDefault::default(); +} diff --git a/vendor/proc-macro-error/tests/ui/append_dummy.stderr b/vendor/proc-macro-error/tests/ui/append_dummy.stderr new file mode 100644 index 0000000000..8a47ddaac4 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/append_dummy.stderr @@ -0,0 +1,5 @@ +error: append_dummy test + --> $DIR/append_dummy.rs:9:15 + | +9 | append_dummy!(need_default); + | ^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/children_messages.rs b/vendor/proc-macro-error/tests/ui/children_messages.rs new file mode 100644 index 0000000000..fb9e6dc697 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/children_messages.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +children_messages!(one, two, three, four); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/children_messages.stderr b/vendor/proc-macro-error/tests/ui/children_messages.stderr new file mode 100644 index 0000000000..3b49d83165 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/children_messages.stderr @@ -0,0 +1,23 @@ +error: main macro message + --> $DIR/children_messages.rs:4:20 + | +4 | children_messages!(one, two, three, four); + | ^^^ + +error: child message + --> $DIR/children_messages.rs:4:25 + | +4 | children_messages!(one, two, three, four); + | ^^^ + +error: main syn::Error + --> $DIR/children_messages.rs:4:30 + | +4 | children_messages!(one, two, three, four); + | ^^^^^ + +error: child syn::Error + --> $DIR/children_messages.rs:4:37 + | +4 | children_messages!(one, two, three, four); + | ^^^^ diff --git a/vendor/proc-macro-error/tests/ui/dummy.rs b/vendor/proc-macro-error/tests/ui/dummy.rs new file mode 100644 index 0000000000..caa4827886 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/dummy.rs @@ -0,0 +1,13 @@ +extern crate test_crate; +use test_crate::*; + +enum NeedDefault { + A, + B +} + +dummy!(need_default); + +fn main() { + let _ = NeedDefault::default(); +} diff --git a/vendor/proc-macro-error/tests/ui/dummy.stderr b/vendor/proc-macro-error/tests/ui/dummy.stderr new file mode 100644 index 0000000000..bae078afa8 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/dummy.stderr @@ -0,0 +1,5 @@ +error: set_dummy test + --> $DIR/dummy.rs:9:8 + | +9 | dummy!(need_default); + | ^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/emit.rs b/vendor/proc-macro-error/tests/ui/emit.rs new file mode 100644 index 0000000000..c5c7db095f --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/emit.rs @@ -0,0 +1,7 @@ +extern crate test_crate; +use test_crate::*; + +emit!(one, two, three, four, five); +emit_notes!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/emit.stderr b/vendor/proc-macro-error/tests/ui/emit.stderr new file mode 100644 index 0000000000..9484bd628b --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/emit.stderr @@ -0,0 +1,48 @@ +error: emit!(span, from) test + --> $DIR/emit.rs:4:7 + | +4 | emit!(one, two, three, four, five); + | ^^^ + +error: emit!(span, expr1, expr2) test + --> $DIR/emit.rs:4:12 + | +4 | emit!(one, two, three, four, five); + | ^^^ + +error: emit!(span, single_expr) test + --> $DIR/emit.rs:4:17 + | +4 | emit!(one, two, three, four, five); + | ^^^^^ + +error: Diagnostic::emit() test + --> $DIR/emit.rs:4:24 + | +4 | emit!(one, two, three, four, five); + | ^^^^ + +error: emit_call_site_error!(expr) test + --> $DIR/emit.rs:4:1 + | +4 | emit!(one, two, three, four, five); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: This is an error + + = note: simple note + = help: simple help + = help: simple hint + = note: simple yay + = note: format note + = note: Some note + = note: spanned simple note + = note: spanned format note + = note: Some note + + --> $DIR/emit.rs:5:13 + | +5 | emit_notes!(one, two); + | ^^^ diff --git a/vendor/proc-macro-error/tests/ui/explicit_span_range.rs b/vendor/proc-macro-error/tests/ui/explicit_span_range.rs new file mode 100644 index 0000000000..82bbebcc55 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/explicit_span_range.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +explicit_span_range!(one, two, three, four); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/explicit_span_range.stderr b/vendor/proc-macro-error/tests/ui/explicit_span_range.stderr new file mode 100644 index 0000000000..781a71e76a --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/explicit_span_range.stderr @@ -0,0 +1,5 @@ +error: explicit SpanRange + --> $DIR/explicit_span_range.rs:4:22 + | +4 | explicit_span_range!(one, two, three, four); + | ^^^^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/misuse.rs b/vendor/proc-macro-error/tests/ui/misuse.rs new file mode 100644 index 0000000000..e6d2d24971 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/misuse.rs @@ -0,0 +1,11 @@ +extern crate proc_macro_error; +use proc_macro_error::abort; + +struct Foo; + +#[allow(unused)] +fn foo() { + abort!(Foo, "BOOM"); +} + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/misuse.stderr b/vendor/proc-macro-error/tests/ui/misuse.stderr new file mode 100644 index 0000000000..8eaf6456fd --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/misuse.stderr @@ -0,0 +1,13 @@ +error[E0599]: no method named `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange` found for reference `&Foo` in the current scope + --> $DIR/misuse.rs:8:5 + | +4 | struct Foo; + | ----------- doesn't satisfy `Foo: quote::to_tokens::ToTokens` +... +8 | abort!(Foo, "BOOM"); + | ^^^^^^^^^^^^^^^^^^^^ method not found in `&Foo` + | + = note: the method `FIRST_ARG_MUST_EITHER_BE_Span_OR_IMPLEMENT_ToTokens_OR_BE_SpanRange` exists but the following trait bounds were not satisfied: + `Foo: quote::to_tokens::ToTokens` + which is required by `&Foo: proc_macro_error::__export::ToTokensAsSpanRange` + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/multiple_tokens.rs b/vendor/proc-macro-error/tests/ui/multiple_tokens.rs new file mode 100644 index 0000000000..215928f6f4 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/multiple_tokens.rs @@ -0,0 +1,6 @@ +extern crate test_crate; + +#[test_crate::multiple_tokens] +type T = (); + +fn main() {} \ No newline at end of file diff --git a/vendor/proc-macro-error/tests/ui/multiple_tokens.stderr b/vendor/proc-macro-error/tests/ui/multiple_tokens.stderr new file mode 100644 index 0000000000..c6172c6cc6 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/multiple_tokens.stderr @@ -0,0 +1,5 @@ +error: ... + --> $DIR/multiple_tokens.rs:4:1 + | +4 | type T = (); + | ^^^^^^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/not_proc_macro.rs b/vendor/proc-macro-error/tests/ui/not_proc_macro.rs new file mode 100644 index 0000000000..e241c5cd28 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/not_proc_macro.rs @@ -0,0 +1,4 @@ +use proc_macro_error::proc_macro_error; + +#[proc_macro_error] +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/not_proc_macro.stderr b/vendor/proc-macro-error/tests/ui/not_proc_macro.stderr new file mode 100644 index 0000000000..f19f01bd8e --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/not_proc_macro.stderr @@ -0,0 +1,10 @@ +error: #[proc_macro_error] attribute can be used only with procedural macros + + = hint: if you are really sure that #[proc_macro_error] should be applied to this exact function, use #[proc_macro_error(allow_not_macro)] + + --> $DIR/not_proc_macro.rs:3:1 + | +3 | #[proc_macro_error] + | ^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in an attribute macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/option_ext.rs b/vendor/proc-macro-error/tests/ui/option_ext.rs new file mode 100644 index 0000000000..dfbfc03835 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/option_ext.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +option_ext!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/option_ext.stderr b/vendor/proc-macro-error/tests/ui/option_ext.stderr new file mode 100644 index 0000000000..91b151ec2f --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/option_ext.stderr @@ -0,0 +1,7 @@ +error: Option::expect_or_abort() test + --> $DIR/option_ext.rs:4:1 + | +4 | option_ext!(one, two); + | ^^^^^^^^^^^^^^^^^^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/proc_macro_hack.rs b/vendor/proc-macro-error/tests/ui/proc_macro_hack.rs new file mode 100644 index 0000000000..2504bdd401 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/proc_macro_hack.rs @@ -0,0 +1,10 @@ +// Adapted from https://github.com/dtolnay/proc-macro-hack/blob/master/example/src/main.rs +// Licensed under either of Apache License, Version 2.0 or MIT license at your option. + +use proc_macro_hack_test::add_one; + +fn main() { + let two = 2; + let nine = add_one!(two) + add_one!(2 + 3); + println!("nine = {}", nine); +} diff --git a/vendor/proc-macro-error/tests/ui/proc_macro_hack.stderr b/vendor/proc-macro-error/tests/ui/proc_macro_hack.stderr new file mode 100644 index 0000000000..0e984f918d --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/proc_macro_hack.stderr @@ -0,0 +1,26 @@ +error: BOOM + --> $DIR/proc_macro_hack.rs:8:25 + | +8 | let nine = add_one!(two) + add_one!(2 + 3); + | ^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +error: BOOM + --> $DIR/proc_macro_hack.rs:8:41 + | +8 | let nine = add_one!(two) + add_one!(2 + 3); + | ^^^^^ + | + = note: this error originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: unreachable expression + --> $DIR/proc_macro_hack.rs:8:32 + | +8 | let nine = add_one!(two) + add_one!(2 + 3); + | ------------- ^^^^^^^^^^^^^^^ unreachable expression + | | + | any code following this expression is unreachable + | + = note: `#[warn(unreachable_code)]` on by default + = note: this warning originates in a macro (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/vendor/proc-macro-error/tests/ui/result_ext.rs b/vendor/proc-macro-error/tests/ui/result_ext.rs new file mode 100644 index 0000000000..bdd560dba9 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/result_ext.rs @@ -0,0 +1,7 @@ +extern crate test_crate; +use test_crate::*; + +result_unwrap_or_abort!(one, two); +result_expect_or_abort!(one, two); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/result_ext.stderr b/vendor/proc-macro-error/tests/ui/result_ext.stderr new file mode 100644 index 0000000000..f2dc0e4235 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/result_ext.stderr @@ -0,0 +1,11 @@ +error: Result::unwrap_or_abort() test + --> $DIR/result_ext.rs:4:25 + | +4 | result_unwrap_or_abort!(one, two); + | ^^^ + +error: BOOM: Result::expect_or_abort() test + --> $DIR/result_ext.rs:5:25 + | +5 | result_expect_or_abort!(one, two); + | ^^^ diff --git a/vendor/proc-macro-error/tests/ui/to_tokens_span.rs b/vendor/proc-macro-error/tests/ui/to_tokens_span.rs new file mode 100644 index 0000000000..a7c3fc976c --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/to_tokens_span.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +to_tokens_span!(std::option::Option); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/to_tokens_span.stderr b/vendor/proc-macro-error/tests/ui/to_tokens_span.stderr new file mode 100644 index 0000000000..b8c4968263 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/to_tokens_span.stderr @@ -0,0 +1,11 @@ +error: whole type + --> $DIR/to_tokens_span.rs:4:17 + | +4 | to_tokens_span!(std::option::Option); + | ^^^^^^^^^^^^^^^^^^^ + +error: explicit .span() + --> $DIR/to_tokens_span.rs:4:17 + | +4 | to_tokens_span!(std::option::Option); + | ^^^ diff --git a/vendor/proc-macro-error/tests/ui/unknown_setting.rs b/vendor/proc-macro-error/tests/ui/unknown_setting.rs new file mode 100644 index 0000000000..d8e58eaf87 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unknown_setting.rs @@ -0,0 +1,4 @@ +use proc_macro_error::proc_macro_error; + +#[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)] +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/unknown_setting.stderr b/vendor/proc-macro-error/tests/ui/unknown_setting.stderr new file mode 100644 index 0000000000..a55de0b31b --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unknown_setting.stderr @@ -0,0 +1,5 @@ +error: unknown setting `trololo`, expected one of `assert_unwind_safe`, `allow_not_macro`, `proc_macro_hack` + --> $DIR/unknown_setting.rs:3:57 + | +3 | #[proc_macro_error(allow_not_macro, assert_unwind_safe, trololo)] + | ^^^^^^^ diff --git a/vendor/proc-macro-error/tests/ui/unrelated_panic.rs b/vendor/proc-macro-error/tests/ui/unrelated_panic.rs new file mode 100644 index 0000000000..c74e3e0623 --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unrelated_panic.rs @@ -0,0 +1,6 @@ +extern crate test_crate; +use test_crate::*; + +unrelated_panic!(); + +fn main() {} diff --git a/vendor/proc-macro-error/tests/ui/unrelated_panic.stderr b/vendor/proc-macro-error/tests/ui/unrelated_panic.stderr new file mode 100644 index 0000000000..d46d689f2f --- /dev/null +++ b/vendor/proc-macro-error/tests/ui/unrelated_panic.stderr @@ -0,0 +1,7 @@ +error: proc macro panicked + --> $DIR/unrelated_panic.rs:4:1 + | +4 | unrelated_panic!(); + | ^^^^^^^^^^^^^^^^^^^ + | + = help: message: unrelated panic test diff --git a/vendor/proc-macro2/.cargo-checksum.json b/vendor/proc-macro2/.cargo-checksum.json index f0198b7ab4..b4cb5b04a5 100644 --- a/vendor/proc-macro2/.cargo-checksum.json +++ b/vendor/proc-macro2/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"3f9b01260486dd920150d3052c5db2cb068ef8dba56e506f9d97881911b24c72","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e1f9d4fc22cff2c049f166a403b41458632a94357890d31cf0e3ad83807fb430","build.rs":"332185d7ad4c859210f5edd7a76bc95146c8277726a2f81417f34927c4424d68","src/detection.rs":"9d25d896889e65330858f2d6f6223c1b98cd1dad189813ad4161ff189fbda2b8","src/fallback.rs":"ddb8137cb6e8b95e99ed179a17a5cae47b29bda5aa24ab48673a2ab18a629020","src/lib.rs":"cd064d760cd68f0b52ea275677daf192dffbf99be2e0b31ca0fbe0e8f59f1630","src/parse.rs":"500edee9773132e27e44d0fdaa042b1cb9451e29e65124493986f51710c0664c","src/strnom.rs":"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855","src/wrapper.rs":"d36c0dced7ec0e7585c1f935cda836080bcae6de1de3d7851d962e9e11a3ac48","tests/comments.rs":"ea6cbe6f4c8852e6a0612893c7d4f2c144a2e6a134a6c3db641a320cbfc3c800","tests/features.rs":"a86deb8644992a4eb64d9fd493eff16f9cf9c5cb6ade3a634ce0c990cf87d559","tests/marker.rs":"c2652e3ae1dfcb94d2e6313b29712c5dcbd0fe62026913e67bb7cebd7560aade","tests/test.rs":"310c856e27ff61c9ec7f0a5cd96031aac02971557b1621f5e17b089d58e79bcd"},"package":"04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12"} \ No newline at end of file +{"files":{"Cargo.toml":"f0e7f7d56e81b261ade37919ec982db131758e2c5f3b59f293e5c8071400e467","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e1f9d4fc22cff2c049f166a403b41458632a94357890d31cf0e3ad83807fb430","build.rs":"4ebf65b1e910e05f1b570e62b012384ef3752c052ef4df65aa70f37cc6635015","src/detection.rs":"9d25d896889e65330858f2d6f6223c1b98cd1dad189813ad4161ff189fbda2b8","src/fallback.rs":"239f9a25c0f2ab57592288d944c7f1a0f887536b6d4dc2428a17640af8d10a41","src/lib.rs":"690f1afba55506e0c9cdbd17a9601ff79cbe88ac3253afaf2f10f725b8926a7c","src/marker.rs":"87fce2d0357f5b7998b6d9dfb064f4a0cbc9dabb19e33d4b514a446243ebe2e8","src/parse.rs":"500edee9773132e27e44d0fdaa042b1cb9451e29e65124493986f51710c0664c","src/wrapper.rs":"d36c0dced7ec0e7585c1f935cda836080bcae6de1de3d7851d962e9e11a3ac48","tests/comments.rs":"ea6cbe6f4c8852e6a0612893c7d4f2c144a2e6a134a6c3db641a320cbfc3c800","tests/features.rs":"a86deb8644992a4eb64d9fd493eff16f9cf9c5cb6ade3a634ce0c990cf87d559","tests/marker.rs":"652db9f25c69ffc65baa60cdca8f195aa2e254d4de0a9ddc85de4dc2470544b6","tests/test.rs":"310c856e27ff61c9ec7f0a5cd96031aac02971557b1621f5e17b089d58e79bcd","tests/test_fmt.rs":"745dfdc41d09c5308c221395eb43f2041f0a1413d2927a813bc2ad4554438fe2"},"package":"36e28516df94f3dd551a587da5357459d9b36d945a7c37c3557928c1c2ff2a2c"} \ No newline at end of file diff --git a/vendor/proc-macro2/Cargo.toml b/vendor/proc-macro2/Cargo.toml index 4e258b1011..2583e71547 100644 --- a/vendor/proc-macro2/Cargo.toml +++ b/vendor/proc-macro2/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "proc-macro2" -version = "1.0.19" +version = "1.0.21" authors = ["Alex Crichton ", "David Tolnay "] description = "A substitute implementation of the compiler's `proc_macro` API to decouple\ntoken-based libraries from the procedural macro use case.\n" documentation = "https://docs.rs/proc-macro2" diff --git a/vendor/proc-macro2/build.rs b/vendor/proc-macro2/build.rs index 153e13f509..edc0db7a54 100644 --- a/vendor/proc-macro2/build.rs +++ b/vendor/proc-macro2/build.rs @@ -61,6 +61,10 @@ fn main() { println!("cargo:rustc-cfg=span_locations"); } + if version.minor < 32 { + println!("cargo:rustc-cfg=no_libprocmacro_unwind_safe"); + } + if version.minor < 39 { println!("cargo:rustc-cfg=no_bind_by_move_pattern_guard"); } diff --git a/vendor/proc-macro2/src/fallback.rs b/vendor/proc-macro2/src/fallback.rs index 23250c972c..949b9a5ff1 100644 --- a/vendor/proc-macro2/src/fallback.rs +++ b/vendor/proc-macro2/src/fallback.rs @@ -157,29 +157,14 @@ impl Display for TokenStream { } joint = false; match tt { - TokenTree::Group(tt) => { - let (start, end) = match tt.delimiter() { - Delimiter::Parenthesis => ("(", ")"), - Delimiter::Brace => ("{", "}"), - Delimiter::Bracket => ("[", "]"), - Delimiter::None => ("", ""), - }; - if tt.stream().into_iter().next().is_none() { - write!(f, "{} {}", start, end)? - } else { - write!(f, "{} {} {}", start, tt.stream(), end)? - } - } - TokenTree::Ident(tt) => write!(f, "{}", tt)?, + TokenTree::Group(tt) => Display::fmt(tt, f), + TokenTree::Ident(tt) => Display::fmt(tt, f), TokenTree::Punct(tt) => { - write!(f, "{}", tt.as_char())?; - match tt.spacing() { - Spacing::Alone => {} - Spacing::Joint => joint = true, - } + joint = tt.spacing() == Spacing::Joint; + Display::fmt(tt, f) } - TokenTree::Literal(tt) => write!(f, "{}", tt)?, - } + TokenTree::Literal(tt) => Display::fmt(tt, f), + }? } Ok(()) @@ -588,17 +573,27 @@ impl Group { } impl Display for Group { + // We attempt to match libproc_macro's formatting. + // Empty parens: () + // Nonempty parens: (...) + // Empty brackets: [] + // Nonempty brackets: [...] + // Empty braces: { } + // Nonempty braces: { ... } fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let (left, right) = match self.delimiter { + let (open, close) = match self.delimiter { Delimiter::Parenthesis => ("(", ")"), - Delimiter::Brace => ("{", "}"), + Delimiter::Brace => ("{ ", "}"), Delimiter::Bracket => ("[", "]"), Delimiter::None => ("", ""), }; - f.write_str(left)?; + f.write_str(open)?; Display::fmt(&self.stream, f)?; - f.write_str(right)?; + if self.delimiter == Delimiter::Brace && !self.stream.inner.is_empty() { + f.write_str(" ")?; + } + f.write_str(close)?; Ok(()) } diff --git a/vendor/proc-macro2/src/lib.rs b/vendor/proc-macro2/src/lib.rs index e23fc6a84a..891d7d7984 100644 --- a/vendor/proc-macro2/src/lib.rs +++ b/vendor/proc-macro2/src/lib.rs @@ -78,7 +78,7 @@ //! a different thread. // Proc-macro2 types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.19")] +#![doc(html_root_url = "https://docs.rs/proc-macro2/1.0.21")] #![cfg_attr(any(proc_macro_span, super_unstable), feature(proc_macro_span))] #![cfg_attr(super_unstable, feature(proc_macro_raw_ident, proc_macro_def_site))] #![allow(clippy::needless_doctest_main)] @@ -86,17 +86,7 @@ #[cfg(use_proc_macro)] extern crate proc_macro; -use std::cmp::Ordering; -use std::fmt::{self, Debug, Display}; -use std::hash::{Hash, Hasher}; -use std::iter::FromIterator; -use std::marker; -use std::ops::RangeBounds; -#[cfg(procmacro2_semver_exempt)] -use std::path::PathBuf; -use std::rc::Rc; -use std::str::FromStr; - +mod marker; mod parse; #[cfg(wrap_proc_macro)] @@ -113,6 +103,16 @@ use crate::fallback as imp; #[cfg(wrap_proc_macro)] mod imp; +use crate::marker::Marker; +use std::cmp::Ordering; +use std::fmt::{self, Debug, Display}; +use std::hash::{Hash, Hasher}; +use std::iter::FromIterator; +use std::ops::RangeBounds; +#[cfg(procmacro2_semver_exempt)] +use std::path::PathBuf; +use std::str::FromStr; + /// An abstract stream of tokens, or more concretely a sequence of token trees. /// /// This type provides interfaces for iterating over token trees and for @@ -123,27 +123,27 @@ mod imp; #[derive(Clone)] pub struct TokenStream { inner: imp::TokenStream, - _marker: marker::PhantomData>, + _marker: Marker, } /// Error returned from `TokenStream::from_str`. pub struct LexError { inner: imp::LexError, - _marker: marker::PhantomData>, + _marker: Marker, } impl TokenStream { fn _new(inner: imp::TokenStream) -> TokenStream { TokenStream { inner, - _marker: marker::PhantomData, + _marker: Marker, } } fn _new_stable(inner: fallback::TokenStream) -> TokenStream { TokenStream { inner: inner.into(), - _marker: marker::PhantomData, + _marker: Marker, } } @@ -180,7 +180,7 @@ impl FromStr for TokenStream { fn from_str(src: &str) -> Result { let e = src.parse().map_err(|e| LexError { inner: e, - _marker: marker::PhantomData, + _marker: Marker, })?; Ok(TokenStream::_new(e)) } @@ -261,7 +261,7 @@ impl Debug for LexError { #[derive(Clone, PartialEq, Eq)] pub struct SourceFile { inner: imp::SourceFile, - _marker: marker::PhantomData>, + _marker: Marker, } #[cfg(procmacro2_semver_exempt)] @@ -269,7 +269,7 @@ impl SourceFile { fn _new(inner: imp::SourceFile) -> Self { SourceFile { inner, - _marker: marker::PhantomData, + _marker: Marker, } } @@ -338,21 +338,21 @@ impl PartialOrd for LineColumn { #[derive(Copy, Clone)] pub struct Span { inner: imp::Span, - _marker: marker::PhantomData>, + _marker: Marker, } impl Span { fn _new(inner: imp::Span) -> Span { Span { inner, - _marker: marker::PhantomData, + _marker: Marker, } } fn _new_stable(inner: fallback::Span) -> Span { Span { inner: inner.into(), - _marker: marker::PhantomData, + _marker: Marker, } } @@ -840,14 +840,14 @@ impl Debug for Punct { #[derive(Clone)] pub struct Ident { inner: imp::Ident, - _marker: marker::PhantomData>, + _marker: Marker, } impl Ident { fn _new(inner: imp::Ident) -> Ident { Ident { inner, - _marker: marker::PhantomData, + _marker: Marker, } } @@ -968,7 +968,7 @@ impl Debug for Ident { #[derive(Clone)] pub struct Literal { inner: imp::Literal, - _marker: marker::PhantomData>, + _marker: Marker, } macro_rules! suffixed_int_literals { @@ -1015,14 +1015,14 @@ impl Literal { fn _new(inner: imp::Literal) -> Literal { Literal { inner, - _marker: marker::PhantomData, + _marker: Marker, } } fn _new_stable(inner: fallback::Literal) -> Literal { Literal { inner: inner.into(), - _marker: marker::PhantomData, + _marker: Marker, } } @@ -1181,10 +1181,9 @@ impl Display for Literal { /// Public implementation details for the `TokenStream` type, such as iterators. pub mod token_stream { + use crate::marker::Marker; use crate::{imp, TokenTree}; use std::fmt::{self, Debug}; - use std::marker; - use std::rc::Rc; pub use crate::TokenStream; @@ -1195,7 +1194,7 @@ pub mod token_stream { #[derive(Clone)] pub struct IntoIter { inner: imp::TokenTreeIter, - _marker: marker::PhantomData>, + _marker: Marker, } impl Iterator for IntoIter { @@ -1219,7 +1218,7 @@ pub mod token_stream { fn into_iter(self) -> IntoIter { IntoIter { inner: self.inner.into_iter(), - _marker: marker::PhantomData, + _marker: Marker, } } } diff --git a/vendor/proc-macro2/src/marker.rs b/vendor/proc-macro2/src/marker.rs new file mode 100644 index 0000000000..58729baf4a --- /dev/null +++ b/vendor/proc-macro2/src/marker.rs @@ -0,0 +1,18 @@ +use std::marker::PhantomData; +use std::panic::{RefUnwindSafe, UnwindSafe}; +use std::rc::Rc; + +// Zero sized marker with the correct set of autotrait impls we want all proc +// macro types to have. +pub(crate) type Marker = PhantomData; + +pub(crate) use self::value::*; + +mod value { + pub(crate) use std::marker::PhantomData as Marker; +} + +pub(crate) struct ProcMacroAutoTraits(Rc<()>); + +impl UnwindSafe for ProcMacroAutoTraits {} +impl RefUnwindSafe for ProcMacroAutoTraits {} diff --git a/vendor/proc-macro2/src/strnom.rs b/vendor/proc-macro2/src/strnom.rs deleted file mode 100644 index e69de29bb2..0000000000 diff --git a/vendor/proc-macro2/tests/marker.rs b/vendor/proc-macro2/tests/marker.rs index 7af2539c1a..70e57677cd 100644 --- a/vendor/proc-macro2/tests/marker.rs +++ b/vendor/proc-macro2/tests/marker.rs @@ -57,3 +57,36 @@ mod semver_exempt { assert_impl!(SourceFile is not Send or Sync); } + +#[cfg(not(no_libprocmacro_unwind_safe))] +mod unwind_safe { + use super::*; + use std::panic::{RefUnwindSafe, UnwindSafe}; + + macro_rules! assert_unwind_safe { + ($($types:ident)*) => { + $( + assert_impl!($types is UnwindSafe and RefUnwindSafe); + )* + }; + } + + assert_unwind_safe! { + Delimiter + Group + Ident + LexError + Literal + Punct + Spacing + Span + TokenStream + TokenTree + } + + #[cfg(procmacro2_semver_exempt)] + assert_unwind_safe! { + LineColumn + SourceFile + } +} diff --git a/vendor/proc-macro2/tests/test_fmt.rs b/vendor/proc-macro2/tests/test_fmt.rs new file mode 100644 index 0000000000..99a0aee5c8 --- /dev/null +++ b/vendor/proc-macro2/tests/test_fmt.rs @@ -0,0 +1,26 @@ +use proc_macro2::{Delimiter, Group, Ident, Span, TokenStream, TokenTree}; +use std::iter::{self, FromIterator}; + +#[test] +fn test_fmt_group() { + let ident = Ident::new("x", Span::call_site()); + let inner = TokenStream::from_iter(iter::once(TokenTree::Ident(ident))); + let parens_empty = Group::new(Delimiter::Parenthesis, TokenStream::new()); + let parens_nonempty = Group::new(Delimiter::Parenthesis, inner.clone()); + let brackets_empty = Group::new(Delimiter::Bracket, TokenStream::new()); + let brackets_nonempty = Group::new(Delimiter::Bracket, inner.clone()); + let braces_empty = Group::new(Delimiter::Brace, TokenStream::new()); + let braces_nonempty = Group::new(Delimiter::Brace, inner.clone()); + let none_empty = Group::new(Delimiter::None, TokenStream::new()); + let none_nonempty = Group::new(Delimiter::None, inner.clone()); + + // Matches libproc_macro. + assert_eq!("()", parens_empty.to_string()); + assert_eq!("(x)", parens_nonempty.to_string()); + assert_eq!("[]", brackets_empty.to_string()); + assert_eq!("[x]", brackets_nonempty.to_string()); + assert_eq!("{ }", braces_empty.to_string()); + assert_eq!("{ x }", braces_nonempty.to_string()); + assert_eq!("", none_empty.to_string()); + assert_eq!("x", none_nonempty.to_string()); +} diff --git a/vendor/pulldown-cmark-0.7.2/.cargo-checksum.json b/vendor/pulldown-cmark-0.7.2/.cargo-checksum.json new file mode 100644 index 0000000000..956e4ad354 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CONTRIBUTING.md":"ad9613136aef42ccaca15f131ecb7bb697adbd05cb2d38062e40581d570e5005","Cargo.lock":"0cce438e59390e1c92b9cf168212d1c4a7390e5de715e432e4204118fb10113c","Cargo.toml":"4a791d5e9478bf3fdfb1e85d14aebcafc85d6ed07f73dcf4e742a47981d596d6","LICENSE":"2afc41ab83a8e715bf57b2b0d9d3ca3da1a0afc4cdadefd72f3a1ba537c5213f","README.md":"2a6061d89f6232ed5e444878668bcd819508519a90966945b1f774a14fd247a1","benches/html_rendering.rs":"9dd749395295e3c27e2dbdd784e34e0d797f150665b3e0af7803217e44902a80","benches/lib.rs":"8d66217a7712baae45d1101042284ddbe99508cc240b461781b0d25da185c108","build.rs":"ea58b69966ea4d7849d1053555b9c8631aefcc977cebdc5e412541527eb6baff","examples/event-filter.rs":"625cb8218e46b97f2553c3dd85a75b3b09bdcc8055c2ef670fa3930f924f5d75","examples/string-to-string.rs":"94cf4c6e1027186b73042fb9971e1469652682398c53e2dffe60d3dc30e72629","src/entities.rs":"08f6499fd2ed5ed5be89506f04e785b33eecb3b304418f812267dd8f01bbc6b6","src/escape.rs":"b5b073435e507e3d2897ea89f6143b5cf47d6cb140948450a255cc13fc2a3c5e","src/html.rs":"25ca58d7397209a9c4048efa647940e2ead21350de567c1c1013d3540438f678","src/lib.rs":"0e9ae448b1a5ff10add1aa6d9db3339e12f7da2bac438b39fb90f98880337c4e","src/linklabel.rs":"f174a9020c23770fe14eb377e85da8280e1ecc9ec4175108ebe38f507270bfeb","src/main.rs":"a009df64cf1f559ebc7b1768bd5842b42df01a7865ef75b8f92ee476360b3db7","src/parse.rs":"05d1023a36893f72b3d9208cfc5f3c42c4af58a3c9f88c7755efdc0a39a86a1b","src/puncttable.rs":"ff83b70b65d1666712cbba1c9949f65ea69d72b25a2aa960a7c8c8d1b5fbed08","src/scanners.rs":"7bebfde06556b74391dba5e9f9e2a12995a6e62816b414d4a8d6b610e6bf307c","src/simd.rs":"6b386b1bd224d10cd8203e7162dd9ed242970de2ce5c1583635285337f4a266f","src/strings.rs":"f19ebad46ab498eef93091d4c90ba9e673c85e848ddde82bf2aa5e1dc5fdc3ea","src/tree.rs":"7c3402a077ff8dd321967e9ac685ecf2038c51601afa38fe75f329ff9564a7f0","tests/errors.rs":"59199be255a0edd7cb9a8fd988738603ec82de3b6d3ec6d331d1c43e2957f5fc","tests/html.rs":"d305de4e8b209af0db749be4bf1137d446a6b3953c01af31ef7c0a807701d022","tests/lib.rs":"02bd5825bfc3d1ec24415049914774e84169bd2f7173475b050157f5539be781","tests/suite/footnotes.rs":"aa1471b4bbaf52efdd870ab078907c95c961bbfe9e2beddbe4dddb3f0bba1c7f","tests/suite/gfm_strikethrough.rs":"a43f9578651faf6f7a4488d4e6a31f371dea8fefa4892a1de63f6dad6ad7827a","tests/suite/gfm_table.rs":"de092e0542b418fb358116aa57810805a84cefe0710e9cf0df9018f37beedc30","tests/suite/gfm_tasklist.rs":"30f9c584eaaeae31cae5a915bc84da91202de2bfceec19faa46778bb87f88cab","tests/suite/mod.rs":"7bf32170c9662f76870139b47596643a60d105427b6a6f85dd15044caf82c6c8","tests/suite/regression.rs":"c3b3975e82167a6301adb9f4ac337f1fb7cf864bf49f7adde8bd80aeadb7d226","tests/suite/spec.rs":"de043bdf7cc81120ca779bf0c38e802c865ec632870f4efa0a30bfd47590426a","tests/suite/table.rs":"f65dd8530e39b846ca6a0eb40dadf850ab266e9925dd331531f404c1cc9d422e"},"package":"ca36dea94d187597e104a5c8e4b07576a8a45aa5db48a65e12940d3eb7461f55"} \ No newline at end of file diff --git a/vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md b/vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md new file mode 100644 index 0000000000..8572568675 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/CONTRIBUTING.md @@ -0,0 +1,21 @@ +Want to contribute? Great! First, read this page. + +### Before you contribute + +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Getting familiar with the project + +**The architecture** is somewhat unique, it was originally inspired by [XML pull parsers](http://www.xmlpull.org), but ended up going in somewhat its own direction. to get familiar with it, +- start my reading the [README](README.md) page, which gives some details on the design of the parser (pull-based events) and some rationalization for it ; +- read the [blog post](https://fullyfaithful.eu/pulldown-cmark) about the release of Pulldown-cmark 0.3 by Marcus Klaas de Vries. + +**The source code** can be approached by skimming the [API documentation](https://docs.rs/pulldown-cmark/latest/pulldown_cmark) first, then explore the code for the main struct, [`Parser`](https://docs.rs/pulldown-cmark/latest/pulldown_cmark/struct.Parser.html) + +### Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. diff --git a/vendor/pulldown-cmark-0.7.2/Cargo.lock b/vendor/pulldown-cmark-0.7.2/Cargo.lock new file mode 100644 index 0000000000..2c8e742e09 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/Cargo.lock @@ -0,0 +1,918 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "aho-corasick" +version = "0.7.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "atty" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "autocfg" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bitflags" +version = "1.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "bstr" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "bumpalo" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "cast" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "clap" +version = "2.33.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", + "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "oorandom 11.1.2 (registry+https://github.com/rust-lang/crates.io-index)", + "plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "criterion-plot" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-deque" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-epoch" +version = "0.8.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", + "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-queue" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "crossbeam-utils" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv" +version = "1.1.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)", + "csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "csv-core" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "either" +version = "1.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "futf" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getopts" +version = "0.2.21" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "getrandom" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "half" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "hermit-abi" +version = "0.1.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "html5ever" +version = "0.25.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itertools" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "itoa" +version = "0.4.6" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "js-sys" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "log" +version = "0.4.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "mac" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "markup5ever" +version = "0.10.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "markup5ever_rcdom" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "xml5ever 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "maybe-uninit" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memchr" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "memoffset" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "new_debug_unreachable" +version = "1.0.4" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "num-traits" +version = "0.2.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "num_cpus" +version = "1.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "oorandom" +version = "11.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "phf" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_codegen" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_generator" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "phf_shared" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "plotters" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ppv-lite86" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "precomputed-hash" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "proc-macro2" +version = "1.0.18" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "pulldown-cmark" +version = "0.7.2" +dependencies = [ + "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", + "criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)", + "html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever_rcdom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", + "unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "quote" +version = "1.0.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_chacha" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_core" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_hc" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rand_pcg" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon" +version = "1.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "rayon-core" +version = "1.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex" +version = "1.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)", + "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", + "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", + "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-automata" +version = "0.1.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "regex-syntax" +version = "0.6.18" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "rustc_version" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "ryu" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "scopeguard" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "semver" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "semver-parser" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "serde_cbor" +version = "0.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_derive" +version = "1.0.114" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "serde_json" +version = "1.0.56" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", + "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "siphasher" +version = "0.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "string_cache" +version = "0.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "string_cache_codegen" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "syn" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tendril" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "textwrap" +version = "0.11.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "thread_local" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "time" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "tinytemplate" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicase" +version = "2.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "unicode-width" +version = "0.1.8" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "unicode-xid" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "utf-8" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "walkdir" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "wasm-bindgen" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-backend" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-macro-support" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "wasm-bindgen-shared" +version = "0.2.64" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "web-sys" +version = "0.3.41" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", + "winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-i686-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "winapi-util" +version = "0.1.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[[package]] +name = "winapi-x86_64-pc-windows-gnu" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" + +[[package]] +name = "xml5ever" +version = "0.16.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", + "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", +] + +[metadata] +"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +"checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" +"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" +"checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" +"checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" +"checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" +"checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" +"checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +"checksum criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8" +"checksum criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +"checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" +"checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" +"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" +"checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" +"checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" +"checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" +"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" +"checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" +"checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" +"checksum half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" +"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +"checksum html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" +"checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" +"checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" +"checksum js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916" +"checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" +"checksum markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab" +"checksum markup5ever_rcdom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f015da43bcd8d4f144559a3423f4591d69b8ce0652c905374da7205df336ae2b" +"checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" +"checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" +"checksum memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" +"checksum new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "e4a24736216ec316047a1fc4252e27dabb04218aa4a3f37c6e7ddbf1f9782b54" +"checksum num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)" = "ac267bcc07f48ee5f8935ab0d24f316fb722d7a1292e2913f0cc196b29ffd611" +"checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" +"checksum oorandom 11.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "a170cebd8021a008ea92e4db85a72f80b35df514ec664b296fdcbb654eac0b2c" +"checksum phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3dfb61232e34fcb633f43d12c58f83c1df82962dcdfa565a4e866ffc17dafe12" +"checksum phf_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cbffee61585b0411840d3ece935cce9cb6321f01c45477d30066498cd5e1a815" +"checksum phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" +"checksum phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" +"checksum plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb" +"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +"checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" +"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" +"checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" +"checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" +"checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" +"checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" +"checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" +"checksum rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080" +"checksum rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +"checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" +"checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" +"checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" +"checksum rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a" +"checksum ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" +"checksum same-file 1.0.6 (registry+https://github.com/rust-lang/crates.io-index)" = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +"checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" +"checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" +"checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" +"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +"checksum serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" +"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" +"checksum serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +"checksum siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" +"checksum string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a" +"checksum string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" +"checksum syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +"checksum tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b" +"checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" +"checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" +"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +"checksum tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" +"checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" +"checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" +"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" +"checksum utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" +"checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" +"checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +"checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" +"checksum wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2" +"checksum wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" +"checksum wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8" +"checksum wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75" +"checksum wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae" +"checksum web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d" +"checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" +"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" +"checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" +"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" +"checksum xml5ever 0.16.1 (registry+https://github.com/rust-lang/crates.io-index)" = "0b1b52e6e8614d4a58b8e70cf51ec0cc21b256ad8206708bcff8139b5bbd6a59" diff --git a/vendor/pulldown-cmark-0.7.2/Cargo.toml b/vendor/pulldown-cmark-0.7.2/Cargo.toml new file mode 100644 index 0000000000..c85952d7fa --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/Cargo.toml @@ -0,0 +1,68 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "pulldown-cmark" +version = "0.7.2" +authors = ["Raph Levien ", "Marcus Klaas de Vries "] +build = "build.rs" +exclude = ["/third_party/**/*", "/tools/**/*", "/specs/**/*", "/fuzzer/**/*", "/azure-pipelines.yml"] +description = "A pull parser for CommonMark" +readme = "README.md" +keywords = ["markdown", "commonmark"] +categories = ["text-processing"] +license = "MIT" +repository = "https://github.com/raphlinus/pulldown-cmark" + +[[bin]] +name = "pulldown-cmark" +doc = false +required-features = ["getopts"] + +[[bench]] +name = "html_rendering" +harness = false +[dependencies.bitflags] +version = "1.2" + +[dependencies.getopts] +version = "0.2" +optional = true + +[dependencies.memchr] +version = "2.3" + +[dependencies.unicase] +version = "2.6" +[dev-dependencies.criterion] +version = "0.3" + +[dev-dependencies.html5ever] +version = "0.25" + +[dev-dependencies.lazy_static] +version = "1.4" + +[dev-dependencies.markup5ever_rcdom] +version = "0.1" + +[dev-dependencies.regex] +version = "1.3" + +[dev-dependencies.tendril] +version = "0.4" + +[features] +default = ["getopts"] +gen-tests = [] +simd = [] diff --git a/vendor/pulldown-cmark-0.7.2/LICENSE b/vendor/pulldown-cmark-0.7.2/LICENSE new file mode 100644 index 0000000000..c10685cc3d --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/LICENSE @@ -0,0 +1,21 @@ +The MIT License + +Copyright 2015 Google Inc. All rights reserved. + +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 --git a/vendor/pulldown-cmark-0.7.2/README.md b/vendor/pulldown-cmark-0.7.2/README.md new file mode 100644 index 0000000000..96e3437902 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/README.md @@ -0,0 +1,152 @@ +# pulldown-cmark + +[![Build Status](https://dev.azure.com/raphlinus/pulldown-cmark/_apis/build/status/pulldown-cmark-CI?branchName=master)](https://dev.azure.com/raphlinus/pulldown-cmark/_build/latest?definitionId=2&branchName=master) +[![Docs](https://docs.rs/pulldown-cmark/badge.svg)](https://docs.rs/pulldown-cmark) +[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark.svg?maxAge=2592000)](https://crates.io/crates/pulldown-cmark) + +[Documentation](https://docs.rs/pulldown-cmark/) + +This library is a pull parser for [CommonMark](http://commonmark.org/), written +in [Rust](http://www.rust-lang.org/). It comes with a simple command-line tool, +useful for rendering to HTML, and is also designed to be easy to use from as +a library. + +It is designed to be: + +* Fast; a bare minimum of allocation and copying +* Safe; written in pure Rust with no unsafe blocks +* Versatile; in particular source-maps are supported +* Correct; the goal is 100% compliance with the [CommonMark spec](http://spec.commonmark.org/) + +Further, it optionally supports parsing footnotes, +[Github flavored tables](https://github.github.com/gfm/#tables-extension-), +[Github flavored task lists](https://github.github.com/gfm/#task-list-items-extension-) and +[strikethrough](https://github.github.com/gfm/#strikethrough-extension-). + +Rustc 1.34 or newer is required to build the crate. + +## Why a pull parser? + +There are many parsers for Markdown and its variants, but to my knowledge none +use pull parsing. Pull parsing has become popular for XML, especially for +memory-conscious applications, because it uses dramatically less memory than +constructing a document tree, but is much easier to use than push parsers. Push +parsers are notoriously difficult to use, and also often error-prone because of +the need for user to delicately juggle state in a series of callbacks. + +In a clean design, the parsing and rendering stages are neatly separated, but +this is often sacrificed in the name of performance and expedience. Many Markdown +implementations mix parsing and rendering together, and even designs that try +to separate them (such as the popular [hoedown](https://github.com/hoedown/hoedown)), +make the assumption that the rendering process can be fully represented as a +serialized string. + +Pull parsing is in some sense the most versatile architecture. It's possible to +drive a push interface, also with minimal memory, and quite straightforward to +construct an AST. Another advantage is that source-map information (the mapping +between parsed blocks and offsets within the source text) is readily available; +you can call `into_offset_iter()` to create an iterator that yields `(Event, Range)` +pairs, where the second element is the event's corresponding range in the source +document. + +While manipulating ASTs is the most flexible way to transform documents, +operating on iterators is surprisingly easy, and quite efficient. Here, for +example, is the code to transform soft line breaks into hard breaks: + +```rust +let parser = parser.map(|event| match event { + Event::SoftBreak => Event::HardBreak, + _ => event +}); +``` + +Or expanding an abbreviation in text: + +```rust +let parser = parser.map(|event| match event { + Event::Text(text) => Event::Text(text.replace("abbr", "abbreviation").into()), + _ => event +}); +``` + +Another simple example is code to determine the max nesting level: + +```rust +let mut max_nesting = 0; +let mut level = 0; +for event in parser { + match event { + Event::Start(_) => { + level += 1; + max_nesting = std::cmp::max(max_nesting, level); + } + Event::End(_) => level -= 1, + _ => () + } +} +``` + +There are some basic but fully functional examples of the usage of the crate in the +`examples` directory of this repository. + +## Using Rust idiomatically + +A lot of the internal scanning code is written at a pretty low level (it +pretty much scans byte patterns for the bits of syntax), but the external +interface is designed to be idiomatic Rust. + +Pull parsers are at heart an iterator of events (start and end tags, text, +and other bits and pieces). The parser data structure implements the +Rust Iterator trait directly, and Event is an enum. Thus, you can use the +full power and expressivity of Rust's iterator infrastructure, including +for loops and `map` (as in the examples above), collecting the events into +a vector (for recording, playback, and manipulation), and more. + +Further, the `Text` event (representing text) is a small copy-on-write string. +The vast majority of text fragments are just +slices of the source document. For these, copy-on-write gives a convenient +representation that requires no allocation or copying, but allocated +strings are available when they're needed. Thus, when rendering text to +HTML, most text is copied just once, from the source document to the +HTML buffer. + +When using the pulldown-cmark's own HTML renderer, make sure to write to a buffered +target like a `Vec` or `String`. Since it performs many (very) small writes, writing +directly to stdout, files, or sockets is detrimental to performance. Such writers can +be wrapped in a [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html). + +## Build options + +By default, the binary is built as well. If you don't want/need it, then build like this: + +```bash +> cargo build --no-default-features +``` + +Or put in your `Cargo.toml` file: + +```toml +pulldown-cmark = { version = "0.7", default-features = false } +``` + +SIMD accelerated scanners are available for the x64 platform from version 0.5 onwards. To +enable them, build with simd feature: + +```bash +> cargo build --release --features simd +``` + +Or add the feature to your project's `Cargo.toml`: + +```toml +pulldown-cmark = { version = "0.7", default-features = false, features = ["simd"] } +``` + +## Authors + +The main author is Raph Levien. The implementation of the new design (v0.3+) was completed by Marcus Klaas de Vries. + +## Contributions + +We gladly accept contributions via GitHub pull requests. Please see +[CONTRIBUTING.md](CONTRIBUTING.md) for more details. diff --git a/vendor/pulldown-cmark-0.7.2/benches/html_rendering.rs b/vendor/pulldown-cmark-0.7.2/benches/html_rendering.rs new file mode 100644 index 0000000000..4a2202843d --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/benches/html_rendering.rs @@ -0,0 +1,77 @@ +#[macro_use] +extern crate criterion; +extern crate pulldown_cmark; + +use criterion::Criterion; +use pulldown_cmark::{html, Options, Parser}; +use std::str::from_utf8; + +static CRDT_BYTES: &[u8] = include_bytes!("../third_party/xi-editor/crdt.md"); + +fn criterion_benchmark(c: &mut Criterion) { + c.bench_function("crdt_total", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, Parser::new_ext(input, Options::empty())); + }) + }); + + c.bench_function("crdt_html", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let events: Vec<_> = Parser::new_ext(input, Options::empty()).collect(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, events.clone().into_iter()); + }) + }); + + c.bench_function("crdt_parse", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()) + }); + + c.bench_function("links_n_emphasis", |b| { + let input = r#"""This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** +"""#; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("unescapes", |b| { + let input = "This is by far my favourite unicode code point: પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ"; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("autolinks_n_html", |b| { + let input = "Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! "; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/vendor/pulldown-cmark-0.7.2/benches/lib.rs b/vendor/pulldown-cmark-0.7.2/benches/lib.rs new file mode 100644 index 0000000000..392aa4e12f --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/benches/lib.rs @@ -0,0 +1,49 @@ +#![feature(test)] + +extern crate pulldown_cmark; +extern crate test; + +mod to_html { + use pulldown_cmark::{html, Options, Parser}; + + fn render_html(text: &str, opts: Options) -> String { + let mut s = String::with_capacity(text.len() * 3 / 2); + let p = Parser::new_ext(text, opts); + html::push_html(&mut s, p); + s + } + + #[bench] + fn pathological_codeblocks1(b: &mut test::Bencher) { + // Note that `buf` grows quadratically with number of + // iterations. The point here is that the render time shouldn't + // grow faster than that. + let mut buf = String::new(); + for i in 1..1000 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + } + + b.iter(|| render_html(&buf, Options::empty())); + } + + #[bench] + fn advanced_pathological_codeblocks(b: &mut test::Bencher) { + let mut buf = String::new(); + let mut i = 1; + while buf.len() < 1250 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + i += 1; + } + for _ in 0..buf.len() { + buf.push_str("*a* "); + } + + b.iter(|| render_html(&buf, Options::empty())); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/build.rs b/vendor/pulldown-cmark-0.7.2/build.rs new file mode 100644 index 0000000000..68f5689976 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/build.rs @@ -0,0 +1,187 @@ +fn main() { + generate_tests_from_spec() +} + +// If the "gen-tests" feature is absent, +// this function will be compiled down to nothing +#[cfg(not(feature = "gen-tests"))] +fn generate_tests_from_spec() {} + +// If the feature is present, generate tests +// from any .txt file present in the specs/ directory +// +// Test cases are present in the files in the +// following format: +// +// ```````````````````````````````` example +// markdown +// . +// expected html output +// ```````````````````````````````` +#[cfg(feature = "gen-tests")] +fn generate_tests_from_spec() { + use std::fs::{self, File}; + use std::io::{Read, Write}; + use std::path::PathBuf; + + // This is a hardcoded path to the CommonMark spec because it is not situated in + // the specs/ directory. It's in an array to easily chain it to the other iterator + // and make it easy to eventually add other hardcoded paths in the future if needed + let hardcoded = [ + "./third_party/CommonMark/spec.txt", + "./third_party/GitHub/gfm_table.txt", + "./third_party/GitHub/gfm_strikethrough.txt", + "./third_party/GitHub/gfm_tasklist.txt", + ]; + let hardcoded_iter = hardcoded.into_iter().map(PathBuf::from); + + // Create an iterator over the files in the specs/ directory that have a .txt extension + let spec_files = fs::read_dir("./specs") + .expect("Could not find the 'specs' directory") + .filter_map(Result::ok) + .map(|d| d.path()) + .filter(|p| p.extension().map(|e| e.to_owned()).is_some()) + .chain(hardcoded_iter) + .collect::>(); + + for file_path in &spec_files { + let mut raw_spec = String::new(); + + File::open(&file_path) + .and_then(|mut f| f.read_to_string(&mut raw_spec)) + .expect("Could not read the spec file"); + + let rs_test_file = PathBuf::from("./tests/suite/") + .join(file_path.file_name().expect("Invalid filename")) + .with_extension("rs"); + + let mut spec_rs = + File::create(&rs_test_file).expect(&format!("Could not create {:?}", rs_test_file)); + + let spec_name = file_path.file_stem().unwrap().to_str().unwrap(); + + let spec = Spec::new(&raw_spec); + let mut n_tests = 0; + + spec_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + spec_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + spec_rs + .write(b"\nuse super::test_markdown_html;\n") + .unwrap(); + + for (i, testcase) in spec.enumerate() { + spec_rs + .write_fmt(format_args!( + r###" +#[test] +fn {}_test_{i}() {{ + let original = r##"{original}"##; + let expected = r##"{expected}"##; + + test_markdown_html(original, expected); +}} +"###, + spec_name, + i = i + 1, + original = testcase.original, + expected = testcase.expected + )) + .unwrap(); + + n_tests += 1; + } + + println!( + "cargo:warning=Generated {} tests in {:?}", + n_tests, rs_test_file + ); + } + + // write mods to suite/mod.rs + let suite_mod_file = PathBuf::from("./tests/suite/mod").with_extension("rs"); + + let mut mod_rs = + File::create(&suite_mod_file).expect(&format!("Could not create {:?}", &suite_mod_file)); + + mod_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + mod_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + mod_rs + .write(b"\npub use super::test_markdown_html;\n\n") + .unwrap(); + + for file_path in &spec_files { + let mod_name = file_path.file_stem().unwrap().to_str().unwrap(); + mod_rs.write(b"mod ").unwrap(); + mod_rs.write(mod_name.as_bytes()).unwrap(); + mod_rs.write(b";\n").unwrap(); + } +} + +#[cfg(feature = "gen-tests")] +pub struct Spec<'a> { + spec: &'a str, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Spec<'a> { + pub fn new(spec: &'a str) -> Self { + Spec { spec: spec } + } +} + +#[cfg(feature = "gen-tests")] +pub struct TestCase { + pub original: String, + pub expected: String, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Iterator for Spec<'a> { + type Item = TestCase; + + fn next(&mut self) -> Option { + let spec = self.spec; + + let i_start = match self + .spec + .find("```````````````````````````````` example\n") + .map(|pos| pos + 41) + { + Some(pos) => pos, + None => return None, + }; + + let i_end = match self.spec[i_start..] + .find("\n.\n") + .map(|pos| (pos + 1) + i_start) + { + Some(pos) => pos, + None => return None, + }; + + let e_end = match self.spec[i_end + 2..] + .find("````````````````````````````````\n") + .map(|pos| pos + i_end + 2) + { + Some(pos) => pos, + None => return None, + }; + + self.spec = &self.spec[e_end + 33..]; + + let test_case = TestCase { + original: spec[i_start..i_end].to_string().replace("→", "\t"), + expected: spec[i_end + 2..e_end].to_string().replace("→", "\t"), + }; + + Some(test_case) + } +} diff --git a/vendor/pulldown-cmark-0.7.2/examples/event-filter.rs b/vendor/pulldown-cmark-0.7.2/examples/event-filter.rs new file mode 100644 index 0000000000..86af851f9e --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/examples/event-filter.rs @@ -0,0 +1,29 @@ +extern crate pulldown_cmark; + +use std::io::Write as _; + +use pulldown_cmark::{html, Event, Options, Parser, Tag}; + +fn main() { + let markdown_input: &str = "This is Peter on ![holiday in Greece](pearl_beach.jpg)."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up parser. We can treat is as any other iterator. We replace Peter by John + // and image by its alt text. + let parser = Parser::new_ext(markdown_input, Options::empty()) + .map(|event| match event { + Event::Text(text) => Event::Text(text.replace("Peter", "John").into()), + _ => event, + }) + .filter(|event| match event { + Event::Start(Tag::Image(..)) | Event::End(Tag::Image(..)) => false, + _ => true, + }); + + // Write to anything implementing the `Write` trait. This could also be a file + // or network socket. + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); + handle.write_all(b"\nHTML output:\n").unwrap(); + html::write_html(&mut handle, parser).unwrap(); +} diff --git a/vendor/pulldown-cmark-0.7.2/examples/string-to-string.rs b/vendor/pulldown-cmark-0.7.2/examples/string-to-string.rs new file mode 100644 index 0000000000..ac08823334 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/examples/string-to-string.rs @@ -0,0 +1,26 @@ +extern crate pulldown_cmark; + +use pulldown_cmark::{html, Options, Parser}; + +fn main() { + let markdown_input: &str = "Hello world, this is a ~~complicated~~ *very simple* example."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up options and parser. Strikethroughs are not part of the CommonMark standard + // and we therefore must enable it explicitly. + let mut options = Options::empty(); + options.insert(Options::ENABLE_STRIKETHROUGH); + let parser = Parser::new_ext(markdown_input, options); + + // Write to String buffer. + let mut html_output: String = String::with_capacity(markdown_input.len() * 3 / 2); + html::push_html(&mut html_output, parser); + + // Check that the output is what we expected. + let expected_html: &str = + "

    Hello world, this is a complicated very simple example.

    \n"; + assert_eq!(expected_html, &html_output); + + // Write result to stdout. + println!("\nHTML output:\n{}", &html_output); +} diff --git a/vendor/pulldown-cmark-0.7.2/src/entities.rs b/vendor/pulldown-cmark-0.7.2/src/entities.rs new file mode 100644 index 0000000000..152342957f --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/entities.rs @@ -0,0 +1,2158 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Expansions of HTML5 entities + +// Autogenerated by mk_entities.py + +const ENTITIES: [(&[u8], &str); 2125] = [ + (b"AElig", "\u{00C6}"), + (b"AMP", "\u{0026}"), + (b"Aacute", "\u{00C1}"), + (b"Abreve", "\u{0102}"), + (b"Acirc", "\u{00C2}"), + (b"Acy", "\u{0410}"), + (b"Afr", "\u{1D504}"), + (b"Agrave", "\u{00C0}"), + (b"Alpha", "\u{0391}"), + (b"Amacr", "\u{0100}"), + (b"And", "\u{2A53}"), + (b"Aogon", "\u{0104}"), + (b"Aopf", "\u{1D538}"), + (b"ApplyFunction", "\u{2061}"), + (b"Aring", "\u{00C5}"), + (b"Ascr", "\u{1D49C}"), + (b"Assign", "\u{2254}"), + (b"Atilde", "\u{00C3}"), + (b"Auml", "\u{00C4}"), + (b"Backslash", "\u{2216}"), + (b"Barv", "\u{2AE7}"), + (b"Barwed", "\u{2306}"), + (b"Bcy", "\u{0411}"), + (b"Because", "\u{2235}"), + (b"Bernoullis", "\u{212C}"), + (b"Beta", "\u{0392}"), + (b"Bfr", "\u{1D505}"), + (b"Bopf", "\u{1D539}"), + (b"Breve", "\u{02D8}"), + (b"Bscr", "\u{212C}"), + (b"Bumpeq", "\u{224E}"), + (b"CHcy", "\u{0427}"), + (b"COPY", "\u{00A9}"), + (b"Cacute", "\u{0106}"), + (b"Cap", "\u{22D2}"), + (b"CapitalDifferentialD", "\u{2145}"), + (b"Cayleys", "\u{212D}"), + (b"Ccaron", "\u{010C}"), + (b"Ccedil", "\u{00C7}"), + (b"Ccirc", "\u{0108}"), + (b"Cconint", "\u{2230}"), + (b"Cdot", "\u{010A}"), + (b"Cedilla", "\u{00B8}"), + (b"CenterDot", "\u{00B7}"), + (b"Cfr", "\u{212D}"), + (b"Chi", "\u{03A7}"), + (b"CircleDot", "\u{2299}"), + (b"CircleMinus", "\u{2296}"), + (b"CirclePlus", "\u{2295}"), + (b"CircleTimes", "\u{2297}"), + (b"ClockwiseContourIntegral", "\u{2232}"), + (b"CloseCurlyDoubleQuote", "\u{201D}"), + (b"CloseCurlyQuote", "\u{2019}"), + (b"Colon", "\u{2237}"), + (b"Colone", "\u{2A74}"), + (b"Congruent", "\u{2261}"), + (b"Conint", "\u{222F}"), + (b"ContourIntegral", "\u{222E}"), + (b"Copf", "\u{2102}"), + (b"Coproduct", "\u{2210}"), + (b"CounterClockwiseContourIntegral", "\u{2233}"), + (b"Cross", "\u{2A2F}"), + (b"Cscr", "\u{1D49E}"), + (b"Cup", "\u{22D3}"), + (b"CupCap", "\u{224D}"), + (b"DD", "\u{2145}"), + (b"DDotrahd", "\u{2911}"), + (b"DJcy", "\u{0402}"), + (b"DScy", "\u{0405}"), + (b"DZcy", "\u{040F}"), + (b"Dagger", "\u{2021}"), + (b"Darr", "\u{21A1}"), + (b"Dashv", "\u{2AE4}"), + (b"Dcaron", "\u{010E}"), + (b"Dcy", "\u{0414}"), + (b"Del", "\u{2207}"), + (b"Delta", "\u{0394}"), + (b"Dfr", "\u{1D507}"), + (b"DiacriticalAcute", "\u{00B4}"), + (b"DiacriticalDot", "\u{02D9}"), + (b"DiacriticalDoubleAcute", "\u{02DD}"), + (b"DiacriticalGrave", "\u{0060}"), + (b"DiacriticalTilde", "\u{02DC}"), + (b"Diamond", "\u{22C4}"), + (b"DifferentialD", "\u{2146}"), + (b"Dopf", "\u{1D53B}"), + (b"Dot", "\u{00A8}"), + (b"DotDot", "\u{20DC}"), + (b"DotEqual", "\u{2250}"), + (b"DoubleContourIntegral", "\u{222F}"), + (b"DoubleDot", "\u{00A8}"), + (b"DoubleDownArrow", "\u{21D3}"), + (b"DoubleLeftArrow", "\u{21D0}"), + (b"DoubleLeftRightArrow", "\u{21D4}"), + (b"DoubleLeftTee", "\u{2AE4}"), + (b"DoubleLongLeftArrow", "\u{27F8}"), + (b"DoubleLongLeftRightArrow", "\u{27FA}"), + (b"DoubleLongRightArrow", "\u{27F9}"), + (b"DoubleRightArrow", "\u{21D2}"), + (b"DoubleRightTee", "\u{22A8}"), + (b"DoubleUpArrow", "\u{21D1}"), + (b"DoubleUpDownArrow", "\u{21D5}"), + (b"DoubleVerticalBar", "\u{2225}"), + (b"DownArrow", "\u{2193}"), + (b"DownArrowBar", "\u{2913}"), + (b"DownArrowUpArrow", "\u{21F5}"), + (b"DownBreve", "\u{0311}"), + (b"DownLeftRightVector", "\u{2950}"), + (b"DownLeftTeeVector", "\u{295E}"), + (b"DownLeftVector", "\u{21BD}"), + (b"DownLeftVectorBar", "\u{2956}"), + (b"DownRightTeeVector", "\u{295F}"), + (b"DownRightVector", "\u{21C1}"), + (b"DownRightVectorBar", "\u{2957}"), + (b"DownTee", "\u{22A4}"), + (b"DownTeeArrow", "\u{21A7}"), + (b"Downarrow", "\u{21D3}"), + (b"Dscr", "\u{1D49F}"), + (b"Dstrok", "\u{0110}"), + (b"ENG", "\u{014A}"), + (b"ETH", "\u{00D0}"), + (b"Eacute", "\u{00C9}"), + (b"Ecaron", "\u{011A}"), + (b"Ecirc", "\u{00CA}"), + (b"Ecy", "\u{042D}"), + (b"Edot", "\u{0116}"), + (b"Efr", "\u{1D508}"), + (b"Egrave", "\u{00C8}"), + (b"Element", "\u{2208}"), + (b"Emacr", "\u{0112}"), + (b"EmptySmallSquare", "\u{25FB}"), + (b"EmptyVerySmallSquare", "\u{25AB}"), + (b"Eogon", "\u{0118}"), + (b"Eopf", "\u{1D53C}"), + (b"Epsilon", "\u{0395}"), + (b"Equal", "\u{2A75}"), + (b"EqualTilde", "\u{2242}"), + (b"Equilibrium", "\u{21CC}"), + (b"Escr", "\u{2130}"), + (b"Esim", "\u{2A73}"), + (b"Eta", "\u{0397}"), + (b"Euml", "\u{00CB}"), + (b"Exists", "\u{2203}"), + (b"ExponentialE", "\u{2147}"), + (b"Fcy", "\u{0424}"), + (b"Ffr", "\u{1D509}"), + (b"FilledSmallSquare", "\u{25FC}"), + (b"FilledVerySmallSquare", "\u{25AA}"), + (b"Fopf", "\u{1D53D}"), + (b"ForAll", "\u{2200}"), + (b"Fouriertrf", "\u{2131}"), + (b"Fscr", "\u{2131}"), + (b"GJcy", "\u{0403}"), + (b"GT", "\u{003E}"), + (b"Gamma", "\u{0393}"), + (b"Gammad", "\u{03DC}"), + (b"Gbreve", "\u{011E}"), + (b"Gcedil", "\u{0122}"), + (b"Gcirc", "\u{011C}"), + (b"Gcy", "\u{0413}"), + (b"Gdot", "\u{0120}"), + (b"Gfr", "\u{1D50A}"), + (b"Gg", "\u{22D9}"), + (b"Gopf", "\u{1D53E}"), + (b"GreaterEqual", "\u{2265}"), + (b"GreaterEqualLess", "\u{22DB}"), + (b"GreaterFullEqual", "\u{2267}"), + (b"GreaterGreater", "\u{2AA2}"), + (b"GreaterLess", "\u{2277}"), + (b"GreaterSlantEqual", "\u{2A7E}"), + (b"GreaterTilde", "\u{2273}"), + (b"Gscr", "\u{1D4A2}"), + (b"Gt", "\u{226B}"), + (b"HARDcy", "\u{042A}"), + (b"Hacek", "\u{02C7}"), + (b"Hat", "\u{005E}"), + (b"Hcirc", "\u{0124}"), + (b"Hfr", "\u{210C}"), + (b"HilbertSpace", "\u{210B}"), + (b"Hopf", "\u{210D}"), + (b"HorizontalLine", "\u{2500}"), + (b"Hscr", "\u{210B}"), + (b"Hstrok", "\u{0126}"), + (b"HumpDownHump", "\u{224E}"), + (b"HumpEqual", "\u{224F}"), + (b"IEcy", "\u{0415}"), + (b"IJlig", "\u{0132}"), + (b"IOcy", "\u{0401}"), + (b"Iacute", "\u{00CD}"), + (b"Icirc", "\u{00CE}"), + (b"Icy", "\u{0418}"), + (b"Idot", "\u{0130}"), + (b"Ifr", "\u{2111}"), + (b"Igrave", "\u{00CC}"), + (b"Im", "\u{2111}"), + (b"Imacr", "\u{012A}"), + (b"ImaginaryI", "\u{2148}"), + (b"Implies", "\u{21D2}"), + (b"Int", "\u{222C}"), + (b"Integral", "\u{222B}"), + (b"Intersection", "\u{22C2}"), + (b"InvisibleComma", "\u{2063}"), + (b"InvisibleTimes", "\u{2062}"), + (b"Iogon", "\u{012E}"), + (b"Iopf", "\u{1D540}"), + (b"Iota", "\u{0399}"), + (b"Iscr", "\u{2110}"), + (b"Itilde", "\u{0128}"), + (b"Iukcy", "\u{0406}"), + (b"Iuml", "\u{00CF}"), + (b"Jcirc", "\u{0134}"), + (b"Jcy", "\u{0419}"), + (b"Jfr", "\u{1D50D}"), + (b"Jopf", "\u{1D541}"), + (b"Jscr", "\u{1D4A5}"), + (b"Jsercy", "\u{0408}"), + (b"Jukcy", "\u{0404}"), + (b"KHcy", "\u{0425}"), + (b"KJcy", "\u{040C}"), + (b"Kappa", "\u{039A}"), + (b"Kcedil", "\u{0136}"), + (b"Kcy", "\u{041A}"), + (b"Kfr", "\u{1D50E}"), + (b"Kopf", "\u{1D542}"), + (b"Kscr", "\u{1D4A6}"), + (b"LJcy", "\u{0409}"), + (b"LT", "\u{003C}"), + (b"Lacute", "\u{0139}"), + (b"Lambda", "\u{039B}"), + (b"Lang", "\u{27EA}"), + (b"Laplacetrf", "\u{2112}"), + (b"Larr", "\u{219E}"), + (b"Lcaron", "\u{013D}"), + (b"Lcedil", "\u{013B}"), + (b"Lcy", "\u{041B}"), + (b"LeftAngleBracket", "\u{27E8}"), + (b"LeftArrow", "\u{2190}"), + (b"LeftArrowBar", "\u{21E4}"), + (b"LeftArrowRightArrow", "\u{21C6}"), + (b"LeftCeiling", "\u{2308}"), + (b"LeftDoubleBracket", "\u{27E6}"), + (b"LeftDownTeeVector", "\u{2961}"), + (b"LeftDownVector", "\u{21C3}"), + (b"LeftDownVectorBar", "\u{2959}"), + (b"LeftFloor", "\u{230A}"), + (b"LeftRightArrow", "\u{2194}"), + (b"LeftRightVector", "\u{294E}"), + (b"LeftTee", "\u{22A3}"), + (b"LeftTeeArrow", "\u{21A4}"), + (b"LeftTeeVector", "\u{295A}"), + (b"LeftTriangle", "\u{22B2}"), + (b"LeftTriangleBar", "\u{29CF}"), + (b"LeftTriangleEqual", "\u{22B4}"), + (b"LeftUpDownVector", "\u{2951}"), + (b"LeftUpTeeVector", "\u{2960}"), + (b"LeftUpVector", "\u{21BF}"), + (b"LeftUpVectorBar", "\u{2958}"), + (b"LeftVector", "\u{21BC}"), + (b"LeftVectorBar", "\u{2952}"), + (b"Leftarrow", "\u{21D0}"), + (b"Leftrightarrow", "\u{21D4}"), + (b"LessEqualGreater", "\u{22DA}"), + (b"LessFullEqual", "\u{2266}"), + (b"LessGreater", "\u{2276}"), + (b"LessLess", "\u{2AA1}"), + (b"LessSlantEqual", "\u{2A7D}"), + (b"LessTilde", "\u{2272}"), + (b"Lfr", "\u{1D50F}"), + (b"Ll", "\u{22D8}"), + (b"Lleftarrow", "\u{21DA}"), + (b"Lmidot", "\u{013F}"), + (b"LongLeftArrow", "\u{27F5}"), + (b"LongLeftRightArrow", "\u{27F7}"), + (b"LongRightArrow", "\u{27F6}"), + (b"Longleftarrow", "\u{27F8}"), + (b"Longleftrightarrow", "\u{27FA}"), + (b"Longrightarrow", "\u{27F9}"), + (b"Lopf", "\u{1D543}"), + (b"LowerLeftArrow", "\u{2199}"), + (b"LowerRightArrow", "\u{2198}"), + (b"Lscr", "\u{2112}"), + (b"Lsh", "\u{21B0}"), + (b"Lstrok", "\u{0141}"), + (b"Lt", "\u{226A}"), + (b"Map", "\u{2905}"), + (b"Mcy", "\u{041C}"), + (b"MediumSpace", "\u{205F}"), + (b"Mellintrf", "\u{2133}"), + (b"Mfr", "\u{1D510}"), + (b"MinusPlus", "\u{2213}"), + (b"Mopf", "\u{1D544}"), + (b"Mscr", "\u{2133}"), + (b"Mu", "\u{039C}"), + (b"NJcy", "\u{040A}"), + (b"Nacute", "\u{0143}"), + (b"Ncaron", "\u{0147}"), + (b"Ncedil", "\u{0145}"), + (b"Ncy", "\u{041D}"), + (b"NegativeMediumSpace", "\u{200B}"), + (b"NegativeThickSpace", "\u{200B}"), + (b"NegativeThinSpace", "\u{200B}"), + (b"NegativeVeryThinSpace", "\u{200B}"), + (b"NestedGreaterGreater", "\u{226B}"), + (b"NestedLessLess", "\u{226A}"), + (b"NewLine", "\u{000A}"), + (b"Nfr", "\u{1D511}"), + (b"NoBreak", "\u{2060}"), + (b"NonBreakingSpace", "\u{00A0}"), + (b"Nopf", "\u{2115}"), + (b"Not", "\u{2AEC}"), + (b"NotCongruent", "\u{2262}"), + (b"NotCupCap", "\u{226D}"), + (b"NotDoubleVerticalBar", "\u{2226}"), + (b"NotElement", "\u{2209}"), + (b"NotEqual", "\u{2260}"), + (b"NotEqualTilde", "\u{2242}\u{0338}"), + (b"NotExists", "\u{2204}"), + (b"NotGreater", "\u{226F}"), + (b"NotGreaterEqual", "\u{2271}"), + (b"NotGreaterFullEqual", "\u{2267}\u{0338}"), + (b"NotGreaterGreater", "\u{226B}\u{0338}"), + (b"NotGreaterLess", "\u{2279}"), + (b"NotGreaterSlantEqual", "\u{2A7E}\u{0338}"), + (b"NotGreaterTilde", "\u{2275}"), + (b"NotHumpDownHump", "\u{224E}\u{0338}"), + (b"NotHumpEqual", "\u{224F}\u{0338}"), + (b"NotLeftTriangle", "\u{22EA}"), + (b"NotLeftTriangleBar", "\u{29CF}\u{0338}"), + (b"NotLeftTriangleEqual", "\u{22EC}"), + (b"NotLess", "\u{226E}"), + (b"NotLessEqual", "\u{2270}"), + (b"NotLessGreater", "\u{2278}"), + (b"NotLessLess", "\u{226A}\u{0338}"), + (b"NotLessSlantEqual", "\u{2A7D}\u{0338}"), + (b"NotLessTilde", "\u{2274}"), + (b"NotNestedGreaterGreater", "\u{2AA2}\u{0338}"), + (b"NotNestedLessLess", "\u{2AA1}\u{0338}"), + (b"NotPrecedes", "\u{2280}"), + (b"NotPrecedesEqual", "\u{2AAF}\u{0338}"), + (b"NotPrecedesSlantEqual", "\u{22E0}"), + (b"NotReverseElement", "\u{220C}"), + (b"NotRightTriangle", "\u{22EB}"), + (b"NotRightTriangleBar", "\u{29D0}\u{0338}"), + (b"NotRightTriangleEqual", "\u{22ED}"), + (b"NotSquareSubset", "\u{228F}\u{0338}"), + (b"NotSquareSubsetEqual", "\u{22E2}"), + (b"NotSquareSuperset", "\u{2290}\u{0338}"), + (b"NotSquareSupersetEqual", "\u{22E3}"), + (b"NotSubset", "\u{2282}\u{20D2}"), + (b"NotSubsetEqual", "\u{2288}"), + (b"NotSucceeds", "\u{2281}"), + (b"NotSucceedsEqual", "\u{2AB0}\u{0338}"), + (b"NotSucceedsSlantEqual", "\u{22E1}"), + (b"NotSucceedsTilde", "\u{227F}\u{0338}"), + (b"NotSuperset", "\u{2283}\u{20D2}"), + (b"NotSupersetEqual", "\u{2289}"), + (b"NotTilde", "\u{2241}"), + (b"NotTildeEqual", "\u{2244}"), + (b"NotTildeFullEqual", "\u{2247}"), + (b"NotTildeTilde", "\u{2249}"), + (b"NotVerticalBar", "\u{2224}"), + (b"Nscr", "\u{1D4A9}"), + (b"Ntilde", "\u{00D1}"), + (b"Nu", "\u{039D}"), + (b"OElig", "\u{0152}"), + (b"Oacute", "\u{00D3}"), + (b"Ocirc", "\u{00D4}"), + (b"Ocy", "\u{041E}"), + (b"Odblac", "\u{0150}"), + (b"Ofr", "\u{1D512}"), + (b"Ograve", "\u{00D2}"), + (b"Omacr", "\u{014C}"), + (b"Omega", "\u{03A9}"), + (b"Omicron", "\u{039F}"), + (b"Oopf", "\u{1D546}"), + (b"OpenCurlyDoubleQuote", "\u{201C}"), + (b"OpenCurlyQuote", "\u{2018}"), + (b"Or", "\u{2A54}"), + (b"Oscr", "\u{1D4AA}"), + (b"Oslash", "\u{00D8}"), + (b"Otilde", "\u{00D5}"), + (b"Otimes", "\u{2A37}"), + (b"Ouml", "\u{00D6}"), + (b"OverBar", "\u{203E}"), + (b"OverBrace", "\u{23DE}"), + (b"OverBracket", "\u{23B4}"), + (b"OverParenthesis", "\u{23DC}"), + (b"PartialD", "\u{2202}"), + (b"Pcy", "\u{041F}"), + (b"Pfr", "\u{1D513}"), + (b"Phi", "\u{03A6}"), + (b"Pi", "\u{03A0}"), + (b"PlusMinus", "\u{00B1}"), + (b"Poincareplane", "\u{210C}"), + (b"Popf", "\u{2119}"), + (b"Pr", "\u{2ABB}"), + (b"Precedes", "\u{227A}"), + (b"PrecedesEqual", "\u{2AAF}"), + (b"PrecedesSlantEqual", "\u{227C}"), + (b"PrecedesTilde", "\u{227E}"), + (b"Prime", "\u{2033}"), + (b"Product", "\u{220F}"), + (b"Proportion", "\u{2237}"), + (b"Proportional", "\u{221D}"), + (b"Pscr", "\u{1D4AB}"), + (b"Psi", "\u{03A8}"), + (b"QUOT", "\u{0022}"), + (b"Qfr", "\u{1D514}"), + (b"Qopf", "\u{211A}"), + (b"Qscr", "\u{1D4AC}"), + (b"RBarr", "\u{2910}"), + (b"REG", "\u{00AE}"), + (b"Racute", "\u{0154}"), + (b"Rang", "\u{27EB}"), + (b"Rarr", "\u{21A0}"), + (b"Rarrtl", "\u{2916}"), + (b"Rcaron", "\u{0158}"), + (b"Rcedil", "\u{0156}"), + (b"Rcy", "\u{0420}"), + (b"Re", "\u{211C}"), + (b"ReverseElement", "\u{220B}"), + (b"ReverseEquilibrium", "\u{21CB}"), + (b"ReverseUpEquilibrium", "\u{296F}"), + (b"Rfr", "\u{211C}"), + (b"Rho", "\u{03A1}"), + (b"RightAngleBracket", "\u{27E9}"), + (b"RightArrow", "\u{2192}"), + (b"RightArrowBar", "\u{21E5}"), + (b"RightArrowLeftArrow", "\u{21C4}"), + (b"RightCeiling", "\u{2309}"), + (b"RightDoubleBracket", "\u{27E7}"), + (b"RightDownTeeVector", "\u{295D}"), + (b"RightDownVector", "\u{21C2}"), + (b"RightDownVectorBar", "\u{2955}"), + (b"RightFloor", "\u{230B}"), + (b"RightTee", "\u{22A2}"), + (b"RightTeeArrow", "\u{21A6}"), + (b"RightTeeVector", "\u{295B}"), + (b"RightTriangle", "\u{22B3}"), + (b"RightTriangleBar", "\u{29D0}"), + (b"RightTriangleEqual", "\u{22B5}"), + (b"RightUpDownVector", "\u{294F}"), + (b"RightUpTeeVector", "\u{295C}"), + (b"RightUpVector", "\u{21BE}"), + (b"RightUpVectorBar", "\u{2954}"), + (b"RightVector", "\u{21C0}"), + (b"RightVectorBar", "\u{2953}"), + (b"Rightarrow", "\u{21D2}"), + (b"Ropf", "\u{211D}"), + (b"RoundImplies", "\u{2970}"), + (b"Rrightarrow", "\u{21DB}"), + (b"Rscr", "\u{211B}"), + (b"Rsh", "\u{21B1}"), + (b"RuleDelayed", "\u{29F4}"), + (b"SHCHcy", "\u{0429}"), + (b"SHcy", "\u{0428}"), + (b"SOFTcy", "\u{042C}"), + (b"Sacute", "\u{015A}"), + (b"Sc", "\u{2ABC}"), + (b"Scaron", "\u{0160}"), + (b"Scedil", "\u{015E}"), + (b"Scirc", "\u{015C}"), + (b"Scy", "\u{0421}"), + (b"Sfr", "\u{1D516}"), + (b"ShortDownArrow", "\u{2193}"), + (b"ShortLeftArrow", "\u{2190}"), + (b"ShortRightArrow", "\u{2192}"), + (b"ShortUpArrow", "\u{2191}"), + (b"Sigma", "\u{03A3}"), + (b"SmallCircle", "\u{2218}"), + (b"Sopf", "\u{1D54A}"), + (b"Sqrt", "\u{221A}"), + (b"Square", "\u{25A1}"), + (b"SquareIntersection", "\u{2293}"), + (b"SquareSubset", "\u{228F}"), + (b"SquareSubsetEqual", "\u{2291}"), + (b"SquareSuperset", "\u{2290}"), + (b"SquareSupersetEqual", "\u{2292}"), + (b"SquareUnion", "\u{2294}"), + (b"Sscr", "\u{1D4AE}"), + (b"Star", "\u{22C6}"), + (b"Sub", "\u{22D0}"), + (b"Subset", "\u{22D0}"), + (b"SubsetEqual", "\u{2286}"), + (b"Succeeds", "\u{227B}"), + (b"SucceedsEqual", "\u{2AB0}"), + (b"SucceedsSlantEqual", "\u{227D}"), + (b"SucceedsTilde", "\u{227F}"), + (b"SuchThat", "\u{220B}"), + (b"Sum", "\u{2211}"), + (b"Sup", "\u{22D1}"), + (b"Superset", "\u{2283}"), + (b"SupersetEqual", "\u{2287}"), + (b"Supset", "\u{22D1}"), + (b"THORN", "\u{00DE}"), + (b"TRADE", "\u{2122}"), + (b"TSHcy", "\u{040B}"), + (b"TScy", "\u{0426}"), + (b"Tab", "\u{0009}"), + (b"Tau", "\u{03A4}"), + (b"Tcaron", "\u{0164}"), + (b"Tcedil", "\u{0162}"), + (b"Tcy", "\u{0422}"), + (b"Tfr", "\u{1D517}"), + (b"Therefore", "\u{2234}"), + (b"Theta", "\u{0398}"), + (b"ThickSpace", "\u{205F}\u{200A}"), + (b"ThinSpace", "\u{2009}"), + (b"Tilde", "\u{223C}"), + (b"TildeEqual", "\u{2243}"), + (b"TildeFullEqual", "\u{2245}"), + (b"TildeTilde", "\u{2248}"), + (b"Topf", "\u{1D54B}"), + (b"TripleDot", "\u{20DB}"), + (b"Tscr", "\u{1D4AF}"), + (b"Tstrok", "\u{0166}"), + (b"Uacute", "\u{00DA}"), + (b"Uarr", "\u{219F}"), + (b"Uarrocir", "\u{2949}"), + (b"Ubrcy", "\u{040E}"), + (b"Ubreve", "\u{016C}"), + (b"Ucirc", "\u{00DB}"), + (b"Ucy", "\u{0423}"), + (b"Udblac", "\u{0170}"), + (b"Ufr", "\u{1D518}"), + (b"Ugrave", "\u{00D9}"), + (b"Umacr", "\u{016A}"), + (b"UnderBar", "\u{005F}"), + (b"UnderBrace", "\u{23DF}"), + (b"UnderBracket", "\u{23B5}"), + (b"UnderParenthesis", "\u{23DD}"), + (b"Union", "\u{22C3}"), + (b"UnionPlus", "\u{228E}"), + (b"Uogon", "\u{0172}"), + (b"Uopf", "\u{1D54C}"), + (b"UpArrow", "\u{2191}"), + (b"UpArrowBar", "\u{2912}"), + (b"UpArrowDownArrow", "\u{21C5}"), + (b"UpDownArrow", "\u{2195}"), + (b"UpEquilibrium", "\u{296E}"), + (b"UpTee", "\u{22A5}"), + (b"UpTeeArrow", "\u{21A5}"), + (b"Uparrow", "\u{21D1}"), + (b"Updownarrow", "\u{21D5}"), + (b"UpperLeftArrow", "\u{2196}"), + (b"UpperRightArrow", "\u{2197}"), + (b"Upsi", "\u{03D2}"), + (b"Upsilon", "\u{03A5}"), + (b"Uring", "\u{016E}"), + (b"Uscr", "\u{1D4B0}"), + (b"Utilde", "\u{0168}"), + (b"Uuml", "\u{00DC}"), + (b"VDash", "\u{22AB}"), + (b"Vbar", "\u{2AEB}"), + (b"Vcy", "\u{0412}"), + (b"Vdash", "\u{22A9}"), + (b"Vdashl", "\u{2AE6}"), + (b"Vee", "\u{22C1}"), + (b"Verbar", "\u{2016}"), + (b"Vert", "\u{2016}"), + (b"VerticalBar", "\u{2223}"), + (b"VerticalLine", "\u{007C}"), + (b"VerticalSeparator", "\u{2758}"), + (b"VerticalTilde", "\u{2240}"), + (b"VeryThinSpace", "\u{200A}"), + (b"Vfr", "\u{1D519}"), + (b"Vopf", "\u{1D54D}"), + (b"Vscr", "\u{1D4B1}"), + (b"Vvdash", "\u{22AA}"), + (b"Wcirc", "\u{0174}"), + (b"Wedge", "\u{22C0}"), + (b"Wfr", "\u{1D51A}"), + (b"Wopf", "\u{1D54E}"), + (b"Wscr", "\u{1D4B2}"), + (b"Xfr", "\u{1D51B}"), + (b"Xi", "\u{039E}"), + (b"Xopf", "\u{1D54F}"), + (b"Xscr", "\u{1D4B3}"), + (b"YAcy", "\u{042F}"), + (b"YIcy", "\u{0407}"), + (b"YUcy", "\u{042E}"), + (b"Yacute", "\u{00DD}"), + (b"Ycirc", "\u{0176}"), + (b"Ycy", "\u{042B}"), + (b"Yfr", "\u{1D51C}"), + (b"Yopf", "\u{1D550}"), + (b"Yscr", "\u{1D4B4}"), + (b"Yuml", "\u{0178}"), + (b"ZHcy", "\u{0416}"), + (b"Zacute", "\u{0179}"), + (b"Zcaron", "\u{017D}"), + (b"Zcy", "\u{0417}"), + (b"Zdot", "\u{017B}"), + (b"ZeroWidthSpace", "\u{200B}"), + (b"Zeta", "\u{0396}"), + (b"Zfr", "\u{2128}"), + (b"Zopf", "\u{2124}"), + (b"Zscr", "\u{1D4B5}"), + (b"aacute", "\u{00E1}"), + (b"abreve", "\u{0103}"), + (b"ac", "\u{223E}"), + (b"acE", "\u{223E}\u{0333}"), + (b"acd", "\u{223F}"), + (b"acirc", "\u{00E2}"), + (b"acute", "\u{00B4}"), + (b"acy", "\u{0430}"), + (b"aelig", "\u{00E6}"), + (b"af", "\u{2061}"), + (b"afr", "\u{1D51E}"), + (b"agrave", "\u{00E0}"), + (b"alefsym", "\u{2135}"), + (b"aleph", "\u{2135}"), + (b"alpha", "\u{03B1}"), + (b"amacr", "\u{0101}"), + (b"amalg", "\u{2A3F}"), + (b"amp", "\u{0026}"), + (b"and", "\u{2227}"), + (b"andand", "\u{2A55}"), + (b"andd", "\u{2A5C}"), + (b"andslope", "\u{2A58}"), + (b"andv", "\u{2A5A}"), + (b"ang", "\u{2220}"), + (b"ange", "\u{29A4}"), + (b"angle", "\u{2220}"), + (b"angmsd", "\u{2221}"), + (b"angmsdaa", "\u{29A8}"), + (b"angmsdab", "\u{29A9}"), + (b"angmsdac", "\u{29AA}"), + (b"angmsdad", "\u{29AB}"), + (b"angmsdae", "\u{29AC}"), + (b"angmsdaf", "\u{29AD}"), + (b"angmsdag", "\u{29AE}"), + (b"angmsdah", "\u{29AF}"), + (b"angrt", "\u{221F}"), + (b"angrtvb", "\u{22BE}"), + (b"angrtvbd", "\u{299D}"), + (b"angsph", "\u{2222}"), + (b"angst", "\u{00C5}"), + (b"angzarr", "\u{237C}"), + (b"aogon", "\u{0105}"), + (b"aopf", "\u{1D552}"), + (b"ap", "\u{2248}"), + (b"apE", "\u{2A70}"), + (b"apacir", "\u{2A6F}"), + (b"ape", "\u{224A}"), + (b"apid", "\u{224B}"), + (b"apos", "\u{0027}"), + (b"approx", "\u{2248}"), + (b"approxeq", "\u{224A}"), + (b"aring", "\u{00E5}"), + (b"ascr", "\u{1D4B6}"), + (b"ast", "\u{002A}"), + (b"asymp", "\u{2248}"), + (b"asympeq", "\u{224D}"), + (b"atilde", "\u{00E3}"), + (b"auml", "\u{00E4}"), + (b"awconint", "\u{2233}"), + (b"awint", "\u{2A11}"), + (b"bNot", "\u{2AED}"), + (b"backcong", "\u{224C}"), + (b"backepsilon", "\u{03F6}"), + (b"backprime", "\u{2035}"), + (b"backsim", "\u{223D}"), + (b"backsimeq", "\u{22CD}"), + (b"barvee", "\u{22BD}"), + (b"barwed", "\u{2305}"), + (b"barwedge", "\u{2305}"), + (b"bbrk", "\u{23B5}"), + (b"bbrktbrk", "\u{23B6}"), + (b"bcong", "\u{224C}"), + (b"bcy", "\u{0431}"), + (b"bdquo", "\u{201E}"), + (b"becaus", "\u{2235}"), + (b"because", "\u{2235}"), + (b"bemptyv", "\u{29B0}"), + (b"bepsi", "\u{03F6}"), + (b"bernou", "\u{212C}"), + (b"beta", "\u{03B2}"), + (b"beth", "\u{2136}"), + (b"between", "\u{226C}"), + (b"bfr", "\u{1D51F}"), + (b"bigcap", "\u{22C2}"), + (b"bigcirc", "\u{25EF}"), + (b"bigcup", "\u{22C3}"), + (b"bigodot", "\u{2A00}"), + (b"bigoplus", "\u{2A01}"), + (b"bigotimes", "\u{2A02}"), + (b"bigsqcup", "\u{2A06}"), + (b"bigstar", "\u{2605}"), + (b"bigtriangledown", "\u{25BD}"), + (b"bigtriangleup", "\u{25B3}"), + (b"biguplus", "\u{2A04}"), + (b"bigvee", "\u{22C1}"), + (b"bigwedge", "\u{22C0}"), + (b"bkarow", "\u{290D}"), + (b"blacklozenge", "\u{29EB}"), + (b"blacksquare", "\u{25AA}"), + (b"blacktriangle", "\u{25B4}"), + (b"blacktriangledown", "\u{25BE}"), + (b"blacktriangleleft", "\u{25C2}"), + (b"blacktriangleright", "\u{25B8}"), + (b"blank", "\u{2423}"), + (b"blk12", "\u{2592}"), + (b"blk14", "\u{2591}"), + (b"blk34", "\u{2593}"), + (b"block", "\u{2588}"), + (b"bne", "\u{003D}\u{20E5}"), + (b"bnequiv", "\u{2261}\u{20E5}"), + (b"bnot", "\u{2310}"), + (b"bopf", "\u{1D553}"), + (b"bot", "\u{22A5}"), + (b"bottom", "\u{22A5}"), + (b"bowtie", "\u{22C8}"), + (b"boxDL", "\u{2557}"), + (b"boxDR", "\u{2554}"), + (b"boxDl", "\u{2556}"), + (b"boxDr", "\u{2553}"), + (b"boxH", "\u{2550}"), + (b"boxHD", "\u{2566}"), + (b"boxHU", "\u{2569}"), + (b"boxHd", "\u{2564}"), + (b"boxHu", "\u{2567}"), + (b"boxUL", "\u{255D}"), + (b"boxUR", "\u{255A}"), + (b"boxUl", "\u{255C}"), + (b"boxUr", "\u{2559}"), + (b"boxV", "\u{2551}"), + (b"boxVH", "\u{256C}"), + (b"boxVL", "\u{2563}"), + (b"boxVR", "\u{2560}"), + (b"boxVh", "\u{256B}"), + (b"boxVl", "\u{2562}"), + (b"boxVr", "\u{255F}"), + (b"boxbox", "\u{29C9}"), + (b"boxdL", "\u{2555}"), + (b"boxdR", "\u{2552}"), + (b"boxdl", "\u{2510}"), + (b"boxdr", "\u{250C}"), + (b"boxh", "\u{2500}"), + (b"boxhD", "\u{2565}"), + (b"boxhU", "\u{2568}"), + (b"boxhd", "\u{252C}"), + (b"boxhu", "\u{2534}"), + (b"boxminus", "\u{229F}"), + (b"boxplus", "\u{229E}"), + (b"boxtimes", "\u{22A0}"), + (b"boxuL", "\u{255B}"), + (b"boxuR", "\u{2558}"), + (b"boxul", "\u{2518}"), + (b"boxur", "\u{2514}"), + (b"boxv", "\u{2502}"), + (b"boxvH", "\u{256A}"), + (b"boxvL", "\u{2561}"), + (b"boxvR", "\u{255E}"), + (b"boxvh", "\u{253C}"), + (b"boxvl", "\u{2524}"), + (b"boxvr", "\u{251C}"), + (b"bprime", "\u{2035}"), + (b"breve", "\u{02D8}"), + (b"brvbar", "\u{00A6}"), + (b"bscr", "\u{1D4B7}"), + (b"bsemi", "\u{204F}"), + (b"bsim", "\u{223D}"), + (b"bsime", "\u{22CD}"), + (b"bsol", "\u{005C}"), + (b"bsolb", "\u{29C5}"), + (b"bsolhsub", "\u{27C8}"), + (b"bull", "\u{2022}"), + (b"bullet", "\u{2022}"), + (b"bump", "\u{224E}"), + (b"bumpE", "\u{2AAE}"), + (b"bumpe", "\u{224F}"), + (b"bumpeq", "\u{224F}"), + (b"cacute", "\u{0107}"), + (b"cap", "\u{2229}"), + (b"capand", "\u{2A44}"), + (b"capbrcup", "\u{2A49}"), + (b"capcap", "\u{2A4B}"), + (b"capcup", "\u{2A47}"), + (b"capdot", "\u{2A40}"), + (b"caps", "\u{2229}\u{FE00}"), + (b"caret", "\u{2041}"), + (b"caron", "\u{02C7}"), + (b"ccaps", "\u{2A4D}"), + (b"ccaron", "\u{010D}"), + (b"ccedil", "\u{00E7}"), + (b"ccirc", "\u{0109}"), + (b"ccups", "\u{2A4C}"), + (b"ccupssm", "\u{2A50}"), + (b"cdot", "\u{010B}"), + (b"cedil", "\u{00B8}"), + (b"cemptyv", "\u{29B2}"), + (b"cent", "\u{00A2}"), + (b"centerdot", "\u{00B7}"), + (b"cfr", "\u{1D520}"), + (b"chcy", "\u{0447}"), + (b"check", "\u{2713}"), + (b"checkmark", "\u{2713}"), + (b"chi", "\u{03C7}"), + (b"cir", "\u{25CB}"), + (b"cirE", "\u{29C3}"), + (b"circ", "\u{02C6}"), + (b"circeq", "\u{2257}"), + (b"circlearrowleft", "\u{21BA}"), + (b"circlearrowright", "\u{21BB}"), + (b"circledR", "\u{00AE}"), + (b"circledS", "\u{24C8}"), + (b"circledast", "\u{229B}"), + (b"circledcirc", "\u{229A}"), + (b"circleddash", "\u{229D}"), + (b"cire", "\u{2257}"), + (b"cirfnint", "\u{2A10}"), + (b"cirmid", "\u{2AEF}"), + (b"cirscir", "\u{29C2}"), + (b"clubs", "\u{2663}"), + (b"clubsuit", "\u{2663}"), + (b"colon", "\u{003A}"), + (b"colone", "\u{2254}"), + (b"coloneq", "\u{2254}"), + (b"comma", "\u{002C}"), + (b"commat", "\u{0040}"), + (b"comp", "\u{2201}"), + (b"compfn", "\u{2218}"), + (b"complement", "\u{2201}"), + (b"complexes", "\u{2102}"), + (b"cong", "\u{2245}"), + (b"congdot", "\u{2A6D}"), + (b"conint", "\u{222E}"), + (b"copf", "\u{1D554}"), + (b"coprod", "\u{2210}"), + (b"copy", "\u{00A9}"), + (b"copysr", "\u{2117}"), + (b"crarr", "\u{21B5}"), + (b"cross", "\u{2717}"), + (b"cscr", "\u{1D4B8}"), + (b"csub", "\u{2ACF}"), + (b"csube", "\u{2AD1}"), + (b"csup", "\u{2AD0}"), + (b"csupe", "\u{2AD2}"), + (b"ctdot", "\u{22EF}"), + (b"cudarrl", "\u{2938}"), + (b"cudarrr", "\u{2935}"), + (b"cuepr", "\u{22DE}"), + (b"cuesc", "\u{22DF}"), + (b"cularr", "\u{21B6}"), + (b"cularrp", "\u{293D}"), + (b"cup", "\u{222A}"), + (b"cupbrcap", "\u{2A48}"), + (b"cupcap", "\u{2A46}"), + (b"cupcup", "\u{2A4A}"), + (b"cupdot", "\u{228D}"), + (b"cupor", "\u{2A45}"), + (b"cups", "\u{222A}\u{FE00}"), + (b"curarr", "\u{21B7}"), + (b"curarrm", "\u{293C}"), + (b"curlyeqprec", "\u{22DE}"), + (b"curlyeqsucc", "\u{22DF}"), + (b"curlyvee", "\u{22CE}"), + (b"curlywedge", "\u{22CF}"), + (b"curren", "\u{00A4}"), + (b"curvearrowleft", "\u{21B6}"), + (b"curvearrowright", "\u{21B7}"), + (b"cuvee", "\u{22CE}"), + (b"cuwed", "\u{22CF}"), + (b"cwconint", "\u{2232}"), + (b"cwint", "\u{2231}"), + (b"cylcty", "\u{232D}"), + (b"dArr", "\u{21D3}"), + (b"dHar", "\u{2965}"), + (b"dagger", "\u{2020}"), + (b"daleth", "\u{2138}"), + (b"darr", "\u{2193}"), + (b"dash", "\u{2010}"), + (b"dashv", "\u{22A3}"), + (b"dbkarow", "\u{290F}"), + (b"dblac", "\u{02DD}"), + (b"dcaron", "\u{010F}"), + (b"dcy", "\u{0434}"), + (b"dd", "\u{2146}"), + (b"ddagger", "\u{2021}"), + (b"ddarr", "\u{21CA}"), + (b"ddotseq", "\u{2A77}"), + (b"deg", "\u{00B0}"), + (b"delta", "\u{03B4}"), + (b"demptyv", "\u{29B1}"), + (b"dfisht", "\u{297F}"), + (b"dfr", "\u{1D521}"), + (b"dharl", "\u{21C3}"), + (b"dharr", "\u{21C2}"), + (b"diam", "\u{22C4}"), + (b"diamond", "\u{22C4}"), + (b"diamondsuit", "\u{2666}"), + (b"diams", "\u{2666}"), + (b"die", "\u{00A8}"), + (b"digamma", "\u{03DD}"), + (b"disin", "\u{22F2}"), + (b"div", "\u{00F7}"), + (b"divide", "\u{00F7}"), + (b"divideontimes", "\u{22C7}"), + (b"divonx", "\u{22C7}"), + (b"djcy", "\u{0452}"), + (b"dlcorn", "\u{231E}"), + (b"dlcrop", "\u{230D}"), + (b"dollar", "\u{0024}"), + (b"dopf", "\u{1D555}"), + (b"dot", "\u{02D9}"), + (b"doteq", "\u{2250}"), + (b"doteqdot", "\u{2251}"), + (b"dotminus", "\u{2238}"), + (b"dotplus", "\u{2214}"), + (b"dotsquare", "\u{22A1}"), + (b"doublebarwedge", "\u{2306}"), + (b"downarrow", "\u{2193}"), + (b"downdownarrows", "\u{21CA}"), + (b"downharpoonleft", "\u{21C3}"), + (b"downharpoonright", "\u{21C2}"), + (b"drbkarow", "\u{2910}"), + (b"drcorn", "\u{231F}"), + (b"drcrop", "\u{230C}"), + (b"dscr", "\u{1D4B9}"), + (b"dscy", "\u{0455}"), + (b"dsol", "\u{29F6}"), + (b"dstrok", "\u{0111}"), + (b"dtdot", "\u{22F1}"), + (b"dtri", "\u{25BF}"), + (b"dtrif", "\u{25BE}"), + (b"duarr", "\u{21F5}"), + (b"duhar", "\u{296F}"), + (b"dwangle", "\u{29A6}"), + (b"dzcy", "\u{045F}"), + (b"dzigrarr", "\u{27FF}"), + (b"eDDot", "\u{2A77}"), + (b"eDot", "\u{2251}"), + (b"eacute", "\u{00E9}"), + (b"easter", "\u{2A6E}"), + (b"ecaron", "\u{011B}"), + (b"ecir", "\u{2256}"), + (b"ecirc", "\u{00EA}"), + (b"ecolon", "\u{2255}"), + (b"ecy", "\u{044D}"), + (b"edot", "\u{0117}"), + (b"ee", "\u{2147}"), + (b"efDot", "\u{2252}"), + (b"efr", "\u{1D522}"), + (b"eg", "\u{2A9A}"), + (b"egrave", "\u{00E8}"), + (b"egs", "\u{2A96}"), + (b"egsdot", "\u{2A98}"), + (b"el", "\u{2A99}"), + (b"elinters", "\u{23E7}"), + (b"ell", "\u{2113}"), + (b"els", "\u{2A95}"), + (b"elsdot", "\u{2A97}"), + (b"emacr", "\u{0113}"), + (b"empty", "\u{2205}"), + (b"emptyset", "\u{2205}"), + (b"emptyv", "\u{2205}"), + (b"emsp", "\u{2003}"), + (b"emsp13", "\u{2004}"), + (b"emsp14", "\u{2005}"), + (b"eng", "\u{014B}"), + (b"ensp", "\u{2002}"), + (b"eogon", "\u{0119}"), + (b"eopf", "\u{1D556}"), + (b"epar", "\u{22D5}"), + (b"eparsl", "\u{29E3}"), + (b"eplus", "\u{2A71}"), + (b"epsi", "\u{03B5}"), + (b"epsilon", "\u{03B5}"), + (b"epsiv", "\u{03F5}"), + (b"eqcirc", "\u{2256}"), + (b"eqcolon", "\u{2255}"), + (b"eqsim", "\u{2242}"), + (b"eqslantgtr", "\u{2A96}"), + (b"eqslantless", "\u{2A95}"), + (b"equals", "\u{003D}"), + (b"equest", "\u{225F}"), + (b"equiv", "\u{2261}"), + (b"equivDD", "\u{2A78}"), + (b"eqvparsl", "\u{29E5}"), + (b"erDot", "\u{2253}"), + (b"erarr", "\u{2971}"), + (b"escr", "\u{212F}"), + (b"esdot", "\u{2250}"), + (b"esim", "\u{2242}"), + (b"eta", "\u{03B7}"), + (b"eth", "\u{00F0}"), + (b"euml", "\u{00EB}"), + (b"euro", "\u{20AC}"), + (b"excl", "\u{0021}"), + (b"exist", "\u{2203}"), + (b"expectation", "\u{2130}"), + (b"exponentiale", "\u{2147}"), + (b"fallingdotseq", "\u{2252}"), + (b"fcy", "\u{0444}"), + (b"female", "\u{2640}"), + (b"ffilig", "\u{FB03}"), + (b"fflig", "\u{FB00}"), + (b"ffllig", "\u{FB04}"), + (b"ffr", "\u{1D523}"), + (b"filig", "\u{FB01}"), + (b"fjlig", "\u{0066}\u{006A}"), + (b"flat", "\u{266D}"), + (b"fllig", "\u{FB02}"), + (b"fltns", "\u{25B1}"), + (b"fnof", "\u{0192}"), + (b"fopf", "\u{1D557}"), + (b"forall", "\u{2200}"), + (b"fork", "\u{22D4}"), + (b"forkv", "\u{2AD9}"), + (b"fpartint", "\u{2A0D}"), + (b"frac12", "\u{00BD}"), + (b"frac13", "\u{2153}"), + (b"frac14", "\u{00BC}"), + (b"frac15", "\u{2155}"), + (b"frac16", "\u{2159}"), + (b"frac18", "\u{215B}"), + (b"frac23", "\u{2154}"), + (b"frac25", "\u{2156}"), + (b"frac34", "\u{00BE}"), + (b"frac35", "\u{2157}"), + (b"frac38", "\u{215C}"), + (b"frac45", "\u{2158}"), + (b"frac56", "\u{215A}"), + (b"frac58", "\u{215D}"), + (b"frac78", "\u{215E}"), + (b"frasl", "\u{2044}"), + (b"frown", "\u{2322}"), + (b"fscr", "\u{1D4BB}"), + (b"gE", "\u{2267}"), + (b"gEl", "\u{2A8C}"), + (b"gacute", "\u{01F5}"), + (b"gamma", "\u{03B3}"), + (b"gammad", "\u{03DD}"), + (b"gap", "\u{2A86}"), + (b"gbreve", "\u{011F}"), + (b"gcirc", "\u{011D}"), + (b"gcy", "\u{0433}"), + (b"gdot", "\u{0121}"), + (b"ge", "\u{2265}"), + (b"gel", "\u{22DB}"), + (b"geq", "\u{2265}"), + (b"geqq", "\u{2267}"), + (b"geqslant", "\u{2A7E}"), + (b"ges", "\u{2A7E}"), + (b"gescc", "\u{2AA9}"), + (b"gesdot", "\u{2A80}"), + (b"gesdoto", "\u{2A82}"), + (b"gesdotol", "\u{2A84}"), + (b"gesl", "\u{22DB}\u{FE00}"), + (b"gesles", "\u{2A94}"), + (b"gfr", "\u{1D524}"), + (b"gg", "\u{226B}"), + (b"ggg", "\u{22D9}"), + (b"gimel", "\u{2137}"), + (b"gjcy", "\u{0453}"), + (b"gl", "\u{2277}"), + (b"glE", "\u{2A92}"), + (b"gla", "\u{2AA5}"), + (b"glj", "\u{2AA4}"), + (b"gnE", "\u{2269}"), + (b"gnap", "\u{2A8A}"), + (b"gnapprox", "\u{2A8A}"), + (b"gne", "\u{2A88}"), + (b"gneq", "\u{2A88}"), + (b"gneqq", "\u{2269}"), + (b"gnsim", "\u{22E7}"), + (b"gopf", "\u{1D558}"), + (b"grave", "\u{0060}"), + (b"gscr", "\u{210A}"), + (b"gsim", "\u{2273}"), + (b"gsime", "\u{2A8E}"), + (b"gsiml", "\u{2A90}"), + (b"gt", "\u{003E}"), + (b"gtcc", "\u{2AA7}"), + (b"gtcir", "\u{2A7A}"), + (b"gtdot", "\u{22D7}"), + (b"gtlPar", "\u{2995}"), + (b"gtquest", "\u{2A7C}"), + (b"gtrapprox", "\u{2A86}"), + (b"gtrarr", "\u{2978}"), + (b"gtrdot", "\u{22D7}"), + (b"gtreqless", "\u{22DB}"), + (b"gtreqqless", "\u{2A8C}"), + (b"gtrless", "\u{2277}"), + (b"gtrsim", "\u{2273}"), + (b"gvertneqq", "\u{2269}\u{FE00}"), + (b"gvnE", "\u{2269}\u{FE00}"), + (b"hArr", "\u{21D4}"), + (b"hairsp", "\u{200A}"), + (b"half", "\u{00BD}"), + (b"hamilt", "\u{210B}"), + (b"hardcy", "\u{044A}"), + (b"harr", "\u{2194}"), + (b"harrcir", "\u{2948}"), + (b"harrw", "\u{21AD}"), + (b"hbar", "\u{210F}"), + (b"hcirc", "\u{0125}"), + (b"hearts", "\u{2665}"), + (b"heartsuit", "\u{2665}"), + (b"hellip", "\u{2026}"), + (b"hercon", "\u{22B9}"), + (b"hfr", "\u{1D525}"), + (b"hksearow", "\u{2925}"), + (b"hkswarow", "\u{2926}"), + (b"hoarr", "\u{21FF}"), + (b"homtht", "\u{223B}"), + (b"hookleftarrow", "\u{21A9}"), + (b"hookrightarrow", "\u{21AA}"), + (b"hopf", "\u{1D559}"), + (b"horbar", "\u{2015}"), + (b"hscr", "\u{1D4BD}"), + (b"hslash", "\u{210F}"), + (b"hstrok", "\u{0127}"), + (b"hybull", "\u{2043}"), + (b"hyphen", "\u{2010}"), + (b"iacute", "\u{00ED}"), + (b"ic", "\u{2063}"), + (b"icirc", "\u{00EE}"), + (b"icy", "\u{0438}"), + (b"iecy", "\u{0435}"), + (b"iexcl", "\u{00A1}"), + (b"iff", "\u{21D4}"), + (b"ifr", "\u{1D526}"), + (b"igrave", "\u{00EC}"), + (b"ii", "\u{2148}"), + (b"iiiint", "\u{2A0C}"), + (b"iiint", "\u{222D}"), + (b"iinfin", "\u{29DC}"), + (b"iiota", "\u{2129}"), + (b"ijlig", "\u{0133}"), + (b"imacr", "\u{012B}"), + (b"image", "\u{2111}"), + (b"imagline", "\u{2110}"), + (b"imagpart", "\u{2111}"), + (b"imath", "\u{0131}"), + (b"imof", "\u{22B7}"), + (b"imped", "\u{01B5}"), + (b"in", "\u{2208}"), + (b"incare", "\u{2105}"), + (b"infin", "\u{221E}"), + (b"infintie", "\u{29DD}"), + (b"inodot", "\u{0131}"), + (b"int", "\u{222B}"), + (b"intcal", "\u{22BA}"), + (b"integers", "\u{2124}"), + (b"intercal", "\u{22BA}"), + (b"intlarhk", "\u{2A17}"), + (b"intprod", "\u{2A3C}"), + (b"iocy", "\u{0451}"), + (b"iogon", "\u{012F}"), + (b"iopf", "\u{1D55A}"), + (b"iota", "\u{03B9}"), + (b"iprod", "\u{2A3C}"), + (b"iquest", "\u{00BF}"), + (b"iscr", "\u{1D4BE}"), + (b"isin", "\u{2208}"), + (b"isinE", "\u{22F9}"), + (b"isindot", "\u{22F5}"), + (b"isins", "\u{22F4}"), + (b"isinsv", "\u{22F3}"), + (b"isinv", "\u{2208}"), + (b"it", "\u{2062}"), + (b"itilde", "\u{0129}"), + (b"iukcy", "\u{0456}"), + (b"iuml", "\u{00EF}"), + (b"jcirc", "\u{0135}"), + (b"jcy", "\u{0439}"), + (b"jfr", "\u{1D527}"), + (b"jmath", "\u{0237}"), + (b"jopf", "\u{1D55B}"), + (b"jscr", "\u{1D4BF}"), + (b"jsercy", "\u{0458}"), + (b"jukcy", "\u{0454}"), + (b"kappa", "\u{03BA}"), + (b"kappav", "\u{03F0}"), + (b"kcedil", "\u{0137}"), + (b"kcy", "\u{043A}"), + (b"kfr", "\u{1D528}"), + (b"kgreen", "\u{0138}"), + (b"khcy", "\u{0445}"), + (b"kjcy", "\u{045C}"), + (b"kopf", "\u{1D55C}"), + (b"kscr", "\u{1D4C0}"), + (b"lAarr", "\u{21DA}"), + (b"lArr", "\u{21D0}"), + (b"lAtail", "\u{291B}"), + (b"lBarr", "\u{290E}"), + (b"lE", "\u{2266}"), + (b"lEg", "\u{2A8B}"), + (b"lHar", "\u{2962}"), + (b"lacute", "\u{013A}"), + (b"laemptyv", "\u{29B4}"), + (b"lagran", "\u{2112}"), + (b"lambda", "\u{03BB}"), + (b"lang", "\u{27E8}"), + (b"langd", "\u{2991}"), + (b"langle", "\u{27E8}"), + (b"lap", "\u{2A85}"), + (b"laquo", "\u{00AB}"), + (b"larr", "\u{2190}"), + (b"larrb", "\u{21E4}"), + (b"larrbfs", "\u{291F}"), + (b"larrfs", "\u{291D}"), + (b"larrhk", "\u{21A9}"), + (b"larrlp", "\u{21AB}"), + (b"larrpl", "\u{2939}"), + (b"larrsim", "\u{2973}"), + (b"larrtl", "\u{21A2}"), + (b"lat", "\u{2AAB}"), + (b"latail", "\u{2919}"), + (b"late", "\u{2AAD}"), + (b"lates", "\u{2AAD}\u{FE00}"), + (b"lbarr", "\u{290C}"), + (b"lbbrk", "\u{2772}"), + (b"lbrace", "\u{007B}"), + (b"lbrack", "\u{005B}"), + (b"lbrke", "\u{298B}"), + (b"lbrksld", "\u{298F}"), + (b"lbrkslu", "\u{298D}"), + (b"lcaron", "\u{013E}"), + (b"lcedil", "\u{013C}"), + (b"lceil", "\u{2308}"), + (b"lcub", "\u{007B}"), + (b"lcy", "\u{043B}"), + (b"ldca", "\u{2936}"), + (b"ldquo", "\u{201C}"), + (b"ldquor", "\u{201E}"), + (b"ldrdhar", "\u{2967}"), + (b"ldrushar", "\u{294B}"), + (b"ldsh", "\u{21B2}"), + (b"le", "\u{2264}"), + (b"leftarrow", "\u{2190}"), + (b"leftarrowtail", "\u{21A2}"), + (b"leftharpoondown", "\u{21BD}"), + (b"leftharpoonup", "\u{21BC}"), + (b"leftleftarrows", "\u{21C7}"), + (b"leftrightarrow", "\u{2194}"), + (b"leftrightarrows", "\u{21C6}"), + (b"leftrightharpoons", "\u{21CB}"), + (b"leftrightsquigarrow", "\u{21AD}"), + (b"leftthreetimes", "\u{22CB}"), + (b"leg", "\u{22DA}"), + (b"leq", "\u{2264}"), + (b"leqq", "\u{2266}"), + (b"leqslant", "\u{2A7D}"), + (b"les", "\u{2A7D}"), + (b"lescc", "\u{2AA8}"), + (b"lesdot", "\u{2A7F}"), + (b"lesdoto", "\u{2A81}"), + (b"lesdotor", "\u{2A83}"), + (b"lesg", "\u{22DA}\u{FE00}"), + (b"lesges", "\u{2A93}"), + (b"lessapprox", "\u{2A85}"), + (b"lessdot", "\u{22D6}"), + (b"lesseqgtr", "\u{22DA}"), + (b"lesseqqgtr", "\u{2A8B}"), + (b"lessgtr", "\u{2276}"), + (b"lesssim", "\u{2272}"), + (b"lfisht", "\u{297C}"), + (b"lfloor", "\u{230A}"), + (b"lfr", "\u{1D529}"), + (b"lg", "\u{2276}"), + (b"lgE", "\u{2A91}"), + (b"lhard", "\u{21BD}"), + (b"lharu", "\u{21BC}"), + (b"lharul", "\u{296A}"), + (b"lhblk", "\u{2584}"), + (b"ljcy", "\u{0459}"), + (b"ll", "\u{226A}"), + (b"llarr", "\u{21C7}"), + (b"llcorner", "\u{231E}"), + (b"llhard", "\u{296B}"), + (b"lltri", "\u{25FA}"), + (b"lmidot", "\u{0140}"), + (b"lmoust", "\u{23B0}"), + (b"lmoustache", "\u{23B0}"), + (b"lnE", "\u{2268}"), + (b"lnap", "\u{2A89}"), + (b"lnapprox", "\u{2A89}"), + (b"lne", "\u{2A87}"), + (b"lneq", "\u{2A87}"), + (b"lneqq", "\u{2268}"), + (b"lnsim", "\u{22E6}"), + (b"loang", "\u{27EC}"), + (b"loarr", "\u{21FD}"), + (b"lobrk", "\u{27E6}"), + (b"longleftarrow", "\u{27F5}"), + (b"longleftrightarrow", "\u{27F7}"), + (b"longmapsto", "\u{27FC}"), + (b"longrightarrow", "\u{27F6}"), + (b"looparrowleft", "\u{21AB}"), + (b"looparrowright", "\u{21AC}"), + (b"lopar", "\u{2985}"), + (b"lopf", "\u{1D55D}"), + (b"loplus", "\u{2A2D}"), + (b"lotimes", "\u{2A34}"), + (b"lowast", "\u{2217}"), + (b"lowbar", "\u{005F}"), + (b"loz", "\u{25CA}"), + (b"lozenge", "\u{25CA}"), + (b"lozf", "\u{29EB}"), + (b"lpar", "\u{0028}"), + (b"lparlt", "\u{2993}"), + (b"lrarr", "\u{21C6}"), + (b"lrcorner", "\u{231F}"), + (b"lrhar", "\u{21CB}"), + (b"lrhard", "\u{296D}"), + (b"lrm", "\u{200E}"), + (b"lrtri", "\u{22BF}"), + (b"lsaquo", "\u{2039}"), + (b"lscr", "\u{1D4C1}"), + (b"lsh", "\u{21B0}"), + (b"lsim", "\u{2272}"), + (b"lsime", "\u{2A8D}"), + (b"lsimg", "\u{2A8F}"), + (b"lsqb", "\u{005B}"), + (b"lsquo", "\u{2018}"), + (b"lsquor", "\u{201A}"), + (b"lstrok", "\u{0142}"), + (b"lt", "\u{003C}"), + (b"ltcc", "\u{2AA6}"), + (b"ltcir", "\u{2A79}"), + (b"ltdot", "\u{22D6}"), + (b"lthree", "\u{22CB}"), + (b"ltimes", "\u{22C9}"), + (b"ltlarr", "\u{2976}"), + (b"ltquest", "\u{2A7B}"), + (b"ltrPar", "\u{2996}"), + (b"ltri", "\u{25C3}"), + (b"ltrie", "\u{22B4}"), + (b"ltrif", "\u{25C2}"), + (b"lurdshar", "\u{294A}"), + (b"luruhar", "\u{2966}"), + (b"lvertneqq", "\u{2268}\u{FE00}"), + (b"lvnE", "\u{2268}\u{FE00}"), + (b"mDDot", "\u{223A}"), + (b"macr", "\u{00AF}"), + (b"male", "\u{2642}"), + (b"malt", "\u{2720}"), + (b"maltese", "\u{2720}"), + (b"map", "\u{21A6}"), + (b"mapsto", "\u{21A6}"), + (b"mapstodown", "\u{21A7}"), + (b"mapstoleft", "\u{21A4}"), + (b"mapstoup", "\u{21A5}"), + (b"marker", "\u{25AE}"), + (b"mcomma", "\u{2A29}"), + (b"mcy", "\u{043C}"), + (b"mdash", "\u{2014}"), + (b"measuredangle", "\u{2221}"), + (b"mfr", "\u{1D52A}"), + (b"mho", "\u{2127}"), + (b"micro", "\u{00B5}"), + (b"mid", "\u{2223}"), + (b"midast", "\u{002A}"), + (b"midcir", "\u{2AF0}"), + (b"middot", "\u{00B7}"), + (b"minus", "\u{2212}"), + (b"minusb", "\u{229F}"), + (b"minusd", "\u{2238}"), + (b"minusdu", "\u{2A2A}"), + (b"mlcp", "\u{2ADB}"), + (b"mldr", "\u{2026}"), + (b"mnplus", "\u{2213}"), + (b"models", "\u{22A7}"), + (b"mopf", "\u{1D55E}"), + (b"mp", "\u{2213}"), + (b"mscr", "\u{1D4C2}"), + (b"mstpos", "\u{223E}"), + (b"mu", "\u{03BC}"), + (b"multimap", "\u{22B8}"), + (b"mumap", "\u{22B8}"), + (b"nGg", "\u{22D9}\u{0338}"), + (b"nGt", "\u{226B}\u{20D2}"), + (b"nGtv", "\u{226B}\u{0338}"), + (b"nLeftarrow", "\u{21CD}"), + (b"nLeftrightarrow", "\u{21CE}"), + (b"nLl", "\u{22D8}\u{0338}"), + (b"nLt", "\u{226A}\u{20D2}"), + (b"nLtv", "\u{226A}\u{0338}"), + (b"nRightarrow", "\u{21CF}"), + (b"nVDash", "\u{22AF}"), + (b"nVdash", "\u{22AE}"), + (b"nabla", "\u{2207}"), + (b"nacute", "\u{0144}"), + (b"nang", "\u{2220}\u{20D2}"), + (b"nap", "\u{2249}"), + (b"napE", "\u{2A70}\u{0338}"), + (b"napid", "\u{224B}\u{0338}"), + (b"napos", "\u{0149}"), + (b"napprox", "\u{2249}"), + (b"natur", "\u{266E}"), + (b"natural", "\u{266E}"), + (b"naturals", "\u{2115}"), + (b"nbsp", "\u{00A0}"), + (b"nbump", "\u{224E}\u{0338}"), + (b"nbumpe", "\u{224F}\u{0338}"), + (b"ncap", "\u{2A43}"), + (b"ncaron", "\u{0148}"), + (b"ncedil", "\u{0146}"), + (b"ncong", "\u{2247}"), + (b"ncongdot", "\u{2A6D}\u{0338}"), + (b"ncup", "\u{2A42}"), + (b"ncy", "\u{043D}"), + (b"ndash", "\u{2013}"), + (b"ne", "\u{2260}"), + (b"neArr", "\u{21D7}"), + (b"nearhk", "\u{2924}"), + (b"nearr", "\u{2197}"), + (b"nearrow", "\u{2197}"), + (b"nedot", "\u{2250}\u{0338}"), + (b"nequiv", "\u{2262}"), + (b"nesear", "\u{2928}"), + (b"nesim", "\u{2242}\u{0338}"), + (b"nexist", "\u{2204}"), + (b"nexists", "\u{2204}"), + (b"nfr", "\u{1D52B}"), + (b"ngE", "\u{2267}\u{0338}"), + (b"nge", "\u{2271}"), + (b"ngeq", "\u{2271}"), + (b"ngeqq", "\u{2267}\u{0338}"), + (b"ngeqslant", "\u{2A7E}\u{0338}"), + (b"nges", "\u{2A7E}\u{0338}"), + (b"ngsim", "\u{2275}"), + (b"ngt", "\u{226F}"), + (b"ngtr", "\u{226F}"), + (b"nhArr", "\u{21CE}"), + (b"nharr", "\u{21AE}"), + (b"nhpar", "\u{2AF2}"), + (b"ni", "\u{220B}"), + (b"nis", "\u{22FC}"), + (b"nisd", "\u{22FA}"), + (b"niv", "\u{220B}"), + (b"njcy", "\u{045A}"), + (b"nlArr", "\u{21CD}"), + (b"nlE", "\u{2266}\u{0338}"), + (b"nlarr", "\u{219A}"), + (b"nldr", "\u{2025}"), + (b"nle", "\u{2270}"), + (b"nleftarrow", "\u{219A}"), + (b"nleftrightarrow", "\u{21AE}"), + (b"nleq", "\u{2270}"), + (b"nleqq", "\u{2266}\u{0338}"), + (b"nleqslant", "\u{2A7D}\u{0338}"), + (b"nles", "\u{2A7D}\u{0338}"), + (b"nless", "\u{226E}"), + (b"nlsim", "\u{2274}"), + (b"nlt", "\u{226E}"), + (b"nltri", "\u{22EA}"), + (b"nltrie", "\u{22EC}"), + (b"nmid", "\u{2224}"), + (b"nopf", "\u{1D55F}"), + (b"not", "\u{00AC}"), + (b"notin", "\u{2209}"), + (b"notinE", "\u{22F9}\u{0338}"), + (b"notindot", "\u{22F5}\u{0338}"), + (b"notinva", "\u{2209}"), + (b"notinvb", "\u{22F7}"), + (b"notinvc", "\u{22F6}"), + (b"notni", "\u{220C}"), + (b"notniva", "\u{220C}"), + (b"notnivb", "\u{22FE}"), + (b"notnivc", "\u{22FD}"), + (b"npar", "\u{2226}"), + (b"nparallel", "\u{2226}"), + (b"nparsl", "\u{2AFD}\u{20E5}"), + (b"npart", "\u{2202}\u{0338}"), + (b"npolint", "\u{2A14}"), + (b"npr", "\u{2280}"), + (b"nprcue", "\u{22E0}"), + (b"npre", "\u{2AAF}\u{0338}"), + (b"nprec", "\u{2280}"), + (b"npreceq", "\u{2AAF}\u{0338}"), + (b"nrArr", "\u{21CF}"), + (b"nrarr", "\u{219B}"), + (b"nrarrc", "\u{2933}\u{0338}"), + (b"nrarrw", "\u{219D}\u{0338}"), + (b"nrightarrow", "\u{219B}"), + (b"nrtri", "\u{22EB}"), + (b"nrtrie", "\u{22ED}"), + (b"nsc", "\u{2281}"), + (b"nsccue", "\u{22E1}"), + (b"nsce", "\u{2AB0}\u{0338}"), + (b"nscr", "\u{1D4C3}"), + (b"nshortmid", "\u{2224}"), + (b"nshortparallel", "\u{2226}"), + (b"nsim", "\u{2241}"), + (b"nsime", "\u{2244}"), + (b"nsimeq", "\u{2244}"), + (b"nsmid", "\u{2224}"), + (b"nspar", "\u{2226}"), + (b"nsqsube", "\u{22E2}"), + (b"nsqsupe", "\u{22E3}"), + (b"nsub", "\u{2284}"), + (b"nsubE", "\u{2AC5}\u{0338}"), + (b"nsube", "\u{2288}"), + (b"nsubset", "\u{2282}\u{20D2}"), + (b"nsubseteq", "\u{2288}"), + (b"nsubseteqq", "\u{2AC5}\u{0338}"), + (b"nsucc", "\u{2281}"), + (b"nsucceq", "\u{2AB0}\u{0338}"), + (b"nsup", "\u{2285}"), + (b"nsupE", "\u{2AC6}\u{0338}"), + (b"nsupe", "\u{2289}"), + (b"nsupset", "\u{2283}\u{20D2}"), + (b"nsupseteq", "\u{2289}"), + (b"nsupseteqq", "\u{2AC6}\u{0338}"), + (b"ntgl", "\u{2279}"), + (b"ntilde", "\u{00F1}"), + (b"ntlg", "\u{2278}"), + (b"ntriangleleft", "\u{22EA}"), + (b"ntrianglelefteq", "\u{22EC}"), + (b"ntriangleright", "\u{22EB}"), + (b"ntrianglerighteq", "\u{22ED}"), + (b"nu", "\u{03BD}"), + (b"num", "\u{0023}"), + (b"numero", "\u{2116}"), + (b"numsp", "\u{2007}"), + (b"nvDash", "\u{22AD}"), + (b"nvHarr", "\u{2904}"), + (b"nvap", "\u{224D}\u{20D2}"), + (b"nvdash", "\u{22AC}"), + (b"nvge", "\u{2265}\u{20D2}"), + (b"nvgt", "\u{003E}\u{20D2}"), + (b"nvinfin", "\u{29DE}"), + (b"nvlArr", "\u{2902}"), + (b"nvle", "\u{2264}\u{20D2}"), + (b"nvlt", "\u{003C}\u{20D2}"), + (b"nvltrie", "\u{22B4}\u{20D2}"), + (b"nvrArr", "\u{2903}"), + (b"nvrtrie", "\u{22B5}\u{20D2}"), + (b"nvsim", "\u{223C}\u{20D2}"), + (b"nwArr", "\u{21D6}"), + (b"nwarhk", "\u{2923}"), + (b"nwarr", "\u{2196}"), + (b"nwarrow", "\u{2196}"), + (b"nwnear", "\u{2927}"), + (b"oS", "\u{24C8}"), + (b"oacute", "\u{00F3}"), + (b"oast", "\u{229B}"), + (b"ocir", "\u{229A}"), + (b"ocirc", "\u{00F4}"), + (b"ocy", "\u{043E}"), + (b"odash", "\u{229D}"), + (b"odblac", "\u{0151}"), + (b"odiv", "\u{2A38}"), + (b"odot", "\u{2299}"), + (b"odsold", "\u{29BC}"), + (b"oelig", "\u{0153}"), + (b"ofcir", "\u{29BF}"), + (b"ofr", "\u{1D52C}"), + (b"ogon", "\u{02DB}"), + (b"ograve", "\u{00F2}"), + (b"ogt", "\u{29C1}"), + (b"ohbar", "\u{29B5}"), + (b"ohm", "\u{03A9}"), + (b"oint", "\u{222E}"), + (b"olarr", "\u{21BA}"), + (b"olcir", "\u{29BE}"), + (b"olcross", "\u{29BB}"), + (b"oline", "\u{203E}"), + (b"olt", "\u{29C0}"), + (b"omacr", "\u{014D}"), + (b"omega", "\u{03C9}"), + (b"omicron", "\u{03BF}"), + (b"omid", "\u{29B6}"), + (b"ominus", "\u{2296}"), + (b"oopf", "\u{1D560}"), + (b"opar", "\u{29B7}"), + (b"operp", "\u{29B9}"), + (b"oplus", "\u{2295}"), + (b"or", "\u{2228}"), + (b"orarr", "\u{21BB}"), + (b"ord", "\u{2A5D}"), + (b"order", "\u{2134}"), + (b"orderof", "\u{2134}"), + (b"ordf", "\u{00AA}"), + (b"ordm", "\u{00BA}"), + (b"origof", "\u{22B6}"), + (b"oror", "\u{2A56}"), + (b"orslope", "\u{2A57}"), + (b"orv", "\u{2A5B}"), + (b"oscr", "\u{2134}"), + (b"oslash", "\u{00F8}"), + (b"osol", "\u{2298}"), + (b"otilde", "\u{00F5}"), + (b"otimes", "\u{2297}"), + (b"otimesas", "\u{2A36}"), + (b"ouml", "\u{00F6}"), + (b"ovbar", "\u{233D}"), + (b"par", "\u{2225}"), + (b"para", "\u{00B6}"), + (b"parallel", "\u{2225}"), + (b"parsim", "\u{2AF3}"), + (b"parsl", "\u{2AFD}"), + (b"part", "\u{2202}"), + (b"pcy", "\u{043F}"), + (b"percnt", "\u{0025}"), + (b"period", "\u{002E}"), + (b"permil", "\u{2030}"), + (b"perp", "\u{22A5}"), + (b"pertenk", "\u{2031}"), + (b"pfr", "\u{1D52D}"), + (b"phi", "\u{03C6}"), + (b"phiv", "\u{03D5}"), + (b"phmmat", "\u{2133}"), + (b"phone", "\u{260E}"), + (b"pi", "\u{03C0}"), + (b"pitchfork", "\u{22D4}"), + (b"piv", "\u{03D6}"), + (b"planck", "\u{210F}"), + (b"planckh", "\u{210E}"), + (b"plankv", "\u{210F}"), + (b"plus", "\u{002B}"), + (b"plusacir", "\u{2A23}"), + (b"plusb", "\u{229E}"), + (b"pluscir", "\u{2A22}"), + (b"plusdo", "\u{2214}"), + (b"plusdu", "\u{2A25}"), + (b"pluse", "\u{2A72}"), + (b"plusmn", "\u{00B1}"), + (b"plussim", "\u{2A26}"), + (b"plustwo", "\u{2A27}"), + (b"pm", "\u{00B1}"), + (b"pointint", "\u{2A15}"), + (b"popf", "\u{1D561}"), + (b"pound", "\u{00A3}"), + (b"pr", "\u{227A}"), + (b"prE", "\u{2AB3}"), + (b"prap", "\u{2AB7}"), + (b"prcue", "\u{227C}"), + (b"pre", "\u{2AAF}"), + (b"prec", "\u{227A}"), + (b"precapprox", "\u{2AB7}"), + (b"preccurlyeq", "\u{227C}"), + (b"preceq", "\u{2AAF}"), + (b"precnapprox", "\u{2AB9}"), + (b"precneqq", "\u{2AB5}"), + (b"precnsim", "\u{22E8}"), + (b"precsim", "\u{227E}"), + (b"prime", "\u{2032}"), + (b"primes", "\u{2119}"), + (b"prnE", "\u{2AB5}"), + (b"prnap", "\u{2AB9}"), + (b"prnsim", "\u{22E8}"), + (b"prod", "\u{220F}"), + (b"profalar", "\u{232E}"), + (b"profline", "\u{2312}"), + (b"profsurf", "\u{2313}"), + (b"prop", "\u{221D}"), + (b"propto", "\u{221D}"), + (b"prsim", "\u{227E}"), + (b"prurel", "\u{22B0}"), + (b"pscr", "\u{1D4C5}"), + (b"psi", "\u{03C8}"), + (b"puncsp", "\u{2008}"), + (b"qfr", "\u{1D52E}"), + (b"qint", "\u{2A0C}"), + (b"qopf", "\u{1D562}"), + (b"qprime", "\u{2057}"), + (b"qscr", "\u{1D4C6}"), + (b"quaternions", "\u{210D}"), + (b"quatint", "\u{2A16}"), + (b"quest", "\u{003F}"), + (b"questeq", "\u{225F}"), + (b"quot", "\u{0022}"), + (b"rAarr", "\u{21DB}"), + (b"rArr", "\u{21D2}"), + (b"rAtail", "\u{291C}"), + (b"rBarr", "\u{290F}"), + (b"rHar", "\u{2964}"), + (b"race", "\u{223D}\u{0331}"), + (b"racute", "\u{0155}"), + (b"radic", "\u{221A}"), + (b"raemptyv", "\u{29B3}"), + (b"rang", "\u{27E9}"), + (b"rangd", "\u{2992}"), + (b"range", "\u{29A5}"), + (b"rangle", "\u{27E9}"), + (b"raquo", "\u{00BB}"), + (b"rarr", "\u{2192}"), + (b"rarrap", "\u{2975}"), + (b"rarrb", "\u{21E5}"), + (b"rarrbfs", "\u{2920}"), + (b"rarrc", "\u{2933}"), + (b"rarrfs", "\u{291E}"), + (b"rarrhk", "\u{21AA}"), + (b"rarrlp", "\u{21AC}"), + (b"rarrpl", "\u{2945}"), + (b"rarrsim", "\u{2974}"), + (b"rarrtl", "\u{21A3}"), + (b"rarrw", "\u{219D}"), + (b"ratail", "\u{291A}"), + (b"ratio", "\u{2236}"), + (b"rationals", "\u{211A}"), + (b"rbarr", "\u{290D}"), + (b"rbbrk", "\u{2773}"), + (b"rbrace", "\u{007D}"), + (b"rbrack", "\u{005D}"), + (b"rbrke", "\u{298C}"), + (b"rbrksld", "\u{298E}"), + (b"rbrkslu", "\u{2990}"), + (b"rcaron", "\u{0159}"), + (b"rcedil", "\u{0157}"), + (b"rceil", "\u{2309}"), + (b"rcub", "\u{007D}"), + (b"rcy", "\u{0440}"), + (b"rdca", "\u{2937}"), + (b"rdldhar", "\u{2969}"), + (b"rdquo", "\u{201D}"), + (b"rdquor", "\u{201D}"), + (b"rdsh", "\u{21B3}"), + (b"real", "\u{211C}"), + (b"realine", "\u{211B}"), + (b"realpart", "\u{211C}"), + (b"reals", "\u{211D}"), + (b"rect", "\u{25AD}"), + (b"reg", "\u{00AE}"), + (b"rfisht", "\u{297D}"), + (b"rfloor", "\u{230B}"), + (b"rfr", "\u{1D52F}"), + (b"rhard", "\u{21C1}"), + (b"rharu", "\u{21C0}"), + (b"rharul", "\u{296C}"), + (b"rho", "\u{03C1}"), + (b"rhov", "\u{03F1}"), + (b"rightarrow", "\u{2192}"), + (b"rightarrowtail", "\u{21A3}"), + (b"rightharpoondown", "\u{21C1}"), + (b"rightharpoonup", "\u{21C0}"), + (b"rightleftarrows", "\u{21C4}"), + (b"rightleftharpoons", "\u{21CC}"), + (b"rightrightarrows", "\u{21C9}"), + (b"rightsquigarrow", "\u{219D}"), + (b"rightthreetimes", "\u{22CC}"), + (b"ring", "\u{02DA}"), + (b"risingdotseq", "\u{2253}"), + (b"rlarr", "\u{21C4}"), + (b"rlhar", "\u{21CC}"), + (b"rlm", "\u{200F}"), + (b"rmoust", "\u{23B1}"), + (b"rmoustache", "\u{23B1}"), + (b"rnmid", "\u{2AEE}"), + (b"roang", "\u{27ED}"), + (b"roarr", "\u{21FE}"), + (b"robrk", "\u{27E7}"), + (b"ropar", "\u{2986}"), + (b"ropf", "\u{1D563}"), + (b"roplus", "\u{2A2E}"), + (b"rotimes", "\u{2A35}"), + (b"rpar", "\u{0029}"), + (b"rpargt", "\u{2994}"), + (b"rppolint", "\u{2A12}"), + (b"rrarr", "\u{21C9}"), + (b"rsaquo", "\u{203A}"), + (b"rscr", "\u{1D4C7}"), + (b"rsh", "\u{21B1}"), + (b"rsqb", "\u{005D}"), + (b"rsquo", "\u{2019}"), + (b"rsquor", "\u{2019}"), + (b"rthree", "\u{22CC}"), + (b"rtimes", "\u{22CA}"), + (b"rtri", "\u{25B9}"), + (b"rtrie", "\u{22B5}"), + (b"rtrif", "\u{25B8}"), + (b"rtriltri", "\u{29CE}"), + (b"ruluhar", "\u{2968}"), + (b"rx", "\u{211E}"), + (b"sacute", "\u{015B}"), + (b"sbquo", "\u{201A}"), + (b"sc", "\u{227B}"), + (b"scE", "\u{2AB4}"), + (b"scap", "\u{2AB8}"), + (b"scaron", "\u{0161}"), + (b"sccue", "\u{227D}"), + (b"sce", "\u{2AB0}"), + (b"scedil", "\u{015F}"), + (b"scirc", "\u{015D}"), + (b"scnE", "\u{2AB6}"), + (b"scnap", "\u{2ABA}"), + (b"scnsim", "\u{22E9}"), + (b"scpolint", "\u{2A13}"), + (b"scsim", "\u{227F}"), + (b"scy", "\u{0441}"), + (b"sdot", "\u{22C5}"), + (b"sdotb", "\u{22A1}"), + (b"sdote", "\u{2A66}"), + (b"seArr", "\u{21D8}"), + (b"searhk", "\u{2925}"), + (b"searr", "\u{2198}"), + (b"searrow", "\u{2198}"), + (b"sect", "\u{00A7}"), + (b"semi", "\u{003B}"), + (b"seswar", "\u{2929}"), + (b"setminus", "\u{2216}"), + (b"setmn", "\u{2216}"), + (b"sext", "\u{2736}"), + (b"sfr", "\u{1D530}"), + (b"sfrown", "\u{2322}"), + (b"sharp", "\u{266F}"), + (b"shchcy", "\u{0449}"), + (b"shcy", "\u{0448}"), + (b"shortmid", "\u{2223}"), + (b"shortparallel", "\u{2225}"), + (b"shy", "\u{00AD}"), + (b"sigma", "\u{03C3}"), + (b"sigmaf", "\u{03C2}"), + (b"sigmav", "\u{03C2}"), + (b"sim", "\u{223C}"), + (b"simdot", "\u{2A6A}"), + (b"sime", "\u{2243}"), + (b"simeq", "\u{2243}"), + (b"simg", "\u{2A9E}"), + (b"simgE", "\u{2AA0}"), + (b"siml", "\u{2A9D}"), + (b"simlE", "\u{2A9F}"), + (b"simne", "\u{2246}"), + (b"simplus", "\u{2A24}"), + (b"simrarr", "\u{2972}"), + (b"slarr", "\u{2190}"), + (b"smallsetminus", "\u{2216}"), + (b"smashp", "\u{2A33}"), + (b"smeparsl", "\u{29E4}"), + (b"smid", "\u{2223}"), + (b"smile", "\u{2323}"), + (b"smt", "\u{2AAA}"), + (b"smte", "\u{2AAC}"), + (b"smtes", "\u{2AAC}\u{FE00}"), + (b"softcy", "\u{044C}"), + (b"sol", "\u{002F}"), + (b"solb", "\u{29C4}"), + (b"solbar", "\u{233F}"), + (b"sopf", "\u{1D564}"), + (b"spades", "\u{2660}"), + (b"spadesuit", "\u{2660}"), + (b"spar", "\u{2225}"), + (b"sqcap", "\u{2293}"), + (b"sqcaps", "\u{2293}\u{FE00}"), + (b"sqcup", "\u{2294}"), + (b"sqcups", "\u{2294}\u{FE00}"), + (b"sqsub", "\u{228F}"), + (b"sqsube", "\u{2291}"), + (b"sqsubset", "\u{228F}"), + (b"sqsubseteq", "\u{2291}"), + (b"sqsup", "\u{2290}"), + (b"sqsupe", "\u{2292}"), + (b"sqsupset", "\u{2290}"), + (b"sqsupseteq", "\u{2292}"), + (b"squ", "\u{25A1}"), + (b"square", "\u{25A1}"), + (b"squarf", "\u{25AA}"), + (b"squf", "\u{25AA}"), + (b"srarr", "\u{2192}"), + (b"sscr", "\u{1D4C8}"), + (b"ssetmn", "\u{2216}"), + (b"ssmile", "\u{2323}"), + (b"sstarf", "\u{22C6}"), + (b"star", "\u{2606}"), + (b"starf", "\u{2605}"), + (b"straightepsilon", "\u{03F5}"), + (b"straightphi", "\u{03D5}"), + (b"strns", "\u{00AF}"), + (b"sub", "\u{2282}"), + (b"subE", "\u{2AC5}"), + (b"subdot", "\u{2ABD}"), + (b"sube", "\u{2286}"), + (b"subedot", "\u{2AC3}"), + (b"submult", "\u{2AC1}"), + (b"subnE", "\u{2ACB}"), + (b"subne", "\u{228A}"), + (b"subplus", "\u{2ABF}"), + (b"subrarr", "\u{2979}"), + (b"subset", "\u{2282}"), + (b"subseteq", "\u{2286}"), + (b"subseteqq", "\u{2AC5}"), + (b"subsetneq", "\u{228A}"), + (b"subsetneqq", "\u{2ACB}"), + (b"subsim", "\u{2AC7}"), + (b"subsub", "\u{2AD5}"), + (b"subsup", "\u{2AD3}"), + (b"succ", "\u{227B}"), + (b"succapprox", "\u{2AB8}"), + (b"succcurlyeq", "\u{227D}"), + (b"succeq", "\u{2AB0}"), + (b"succnapprox", "\u{2ABA}"), + (b"succneqq", "\u{2AB6}"), + (b"succnsim", "\u{22E9}"), + (b"succsim", "\u{227F}"), + (b"sum", "\u{2211}"), + (b"sung", "\u{266A}"), + (b"sup", "\u{2283}"), + (b"sup1", "\u{00B9}"), + (b"sup2", "\u{00B2}"), + (b"sup3", "\u{00B3}"), + (b"supE", "\u{2AC6}"), + (b"supdot", "\u{2ABE}"), + (b"supdsub", "\u{2AD8}"), + (b"supe", "\u{2287}"), + (b"supedot", "\u{2AC4}"), + (b"suphsol", "\u{27C9}"), + (b"suphsub", "\u{2AD7}"), + (b"suplarr", "\u{297B}"), + (b"supmult", "\u{2AC2}"), + (b"supnE", "\u{2ACC}"), + (b"supne", "\u{228B}"), + (b"supplus", "\u{2AC0}"), + (b"supset", "\u{2283}"), + (b"supseteq", "\u{2287}"), + (b"supseteqq", "\u{2AC6}"), + (b"supsetneq", "\u{228B}"), + (b"supsetneqq", "\u{2ACC}"), + (b"supsim", "\u{2AC8}"), + (b"supsub", "\u{2AD4}"), + (b"supsup", "\u{2AD6}"), + (b"swArr", "\u{21D9}"), + (b"swarhk", "\u{2926}"), + (b"swarr", "\u{2199}"), + (b"swarrow", "\u{2199}"), + (b"swnwar", "\u{292A}"), + (b"szlig", "\u{00DF}"), + (b"target", "\u{2316}"), + (b"tau", "\u{03C4}"), + (b"tbrk", "\u{23B4}"), + (b"tcaron", "\u{0165}"), + (b"tcedil", "\u{0163}"), + (b"tcy", "\u{0442}"), + (b"tdot", "\u{20DB}"), + (b"telrec", "\u{2315}"), + (b"tfr", "\u{1D531}"), + (b"there4", "\u{2234}"), + (b"therefore", "\u{2234}"), + (b"theta", "\u{03B8}"), + (b"thetasym", "\u{03D1}"), + (b"thetav", "\u{03D1}"), + (b"thickapprox", "\u{2248}"), + (b"thicksim", "\u{223C}"), + (b"thinsp", "\u{2009}"), + (b"thkap", "\u{2248}"), + (b"thksim", "\u{223C}"), + (b"thorn", "\u{00FE}"), + (b"tilde", "\u{02DC}"), + (b"times", "\u{00D7}"), + (b"timesb", "\u{22A0}"), + (b"timesbar", "\u{2A31}"), + (b"timesd", "\u{2A30}"), + (b"tint", "\u{222D}"), + (b"toea", "\u{2928}"), + (b"top", "\u{22A4}"), + (b"topbot", "\u{2336}"), + (b"topcir", "\u{2AF1}"), + (b"topf", "\u{1D565}"), + (b"topfork", "\u{2ADA}"), + (b"tosa", "\u{2929}"), + (b"tprime", "\u{2034}"), + (b"trade", "\u{2122}"), + (b"triangle", "\u{25B5}"), + (b"triangledown", "\u{25BF}"), + (b"triangleleft", "\u{25C3}"), + (b"trianglelefteq", "\u{22B4}"), + (b"triangleq", "\u{225C}"), + (b"triangleright", "\u{25B9}"), + (b"trianglerighteq", "\u{22B5}"), + (b"tridot", "\u{25EC}"), + (b"trie", "\u{225C}"), + (b"triminus", "\u{2A3A}"), + (b"triplus", "\u{2A39}"), + (b"trisb", "\u{29CD}"), + (b"tritime", "\u{2A3B}"), + (b"trpezium", "\u{23E2}"), + (b"tscr", "\u{1D4C9}"), + (b"tscy", "\u{0446}"), + (b"tshcy", "\u{045B}"), + (b"tstrok", "\u{0167}"), + (b"twixt", "\u{226C}"), + (b"twoheadleftarrow", "\u{219E}"), + (b"twoheadrightarrow", "\u{21A0}"), + (b"uArr", "\u{21D1}"), + (b"uHar", "\u{2963}"), + (b"uacute", "\u{00FA}"), + (b"uarr", "\u{2191}"), + (b"ubrcy", "\u{045E}"), + (b"ubreve", "\u{016D}"), + (b"ucirc", "\u{00FB}"), + (b"ucy", "\u{0443}"), + (b"udarr", "\u{21C5}"), + (b"udblac", "\u{0171}"), + (b"udhar", "\u{296E}"), + (b"ufisht", "\u{297E}"), + (b"ufr", "\u{1D532}"), + (b"ugrave", "\u{00F9}"), + (b"uharl", "\u{21BF}"), + (b"uharr", "\u{21BE}"), + (b"uhblk", "\u{2580}"), + (b"ulcorn", "\u{231C}"), + (b"ulcorner", "\u{231C}"), + (b"ulcrop", "\u{230F}"), + (b"ultri", "\u{25F8}"), + (b"umacr", "\u{016B}"), + (b"uml", "\u{00A8}"), + (b"uogon", "\u{0173}"), + (b"uopf", "\u{1D566}"), + (b"uparrow", "\u{2191}"), + (b"updownarrow", "\u{2195}"), + (b"upharpoonleft", "\u{21BF}"), + (b"upharpoonright", "\u{21BE}"), + (b"uplus", "\u{228E}"), + (b"upsi", "\u{03C5}"), + (b"upsih", "\u{03D2}"), + (b"upsilon", "\u{03C5}"), + (b"upuparrows", "\u{21C8}"), + (b"urcorn", "\u{231D}"), + (b"urcorner", "\u{231D}"), + (b"urcrop", "\u{230E}"), + (b"uring", "\u{016F}"), + (b"urtri", "\u{25F9}"), + (b"uscr", "\u{1D4CA}"), + (b"utdot", "\u{22F0}"), + (b"utilde", "\u{0169}"), + (b"utri", "\u{25B5}"), + (b"utrif", "\u{25B4}"), + (b"uuarr", "\u{21C8}"), + (b"uuml", "\u{00FC}"), + (b"uwangle", "\u{29A7}"), + (b"vArr", "\u{21D5}"), + (b"vBar", "\u{2AE8}"), + (b"vBarv", "\u{2AE9}"), + (b"vDash", "\u{22A8}"), + (b"vangrt", "\u{299C}"), + (b"varepsilon", "\u{03F5}"), + (b"varkappa", "\u{03F0}"), + (b"varnothing", "\u{2205}"), + (b"varphi", "\u{03D5}"), + (b"varpi", "\u{03D6}"), + (b"varpropto", "\u{221D}"), + (b"varr", "\u{2195}"), + (b"varrho", "\u{03F1}"), + (b"varsigma", "\u{03C2}"), + (b"varsubsetneq", "\u{228A}\u{FE00}"), + (b"varsubsetneqq", "\u{2ACB}\u{FE00}"), + (b"varsupsetneq", "\u{228B}\u{FE00}"), + (b"varsupsetneqq", "\u{2ACC}\u{FE00}"), + (b"vartheta", "\u{03D1}"), + (b"vartriangleleft", "\u{22B2}"), + (b"vartriangleright", "\u{22B3}"), + (b"vcy", "\u{0432}"), + (b"vdash", "\u{22A2}"), + (b"vee", "\u{2228}"), + (b"veebar", "\u{22BB}"), + (b"veeeq", "\u{225A}"), + (b"vellip", "\u{22EE}"), + (b"verbar", "\u{007C}"), + (b"vert", "\u{007C}"), + (b"vfr", "\u{1D533}"), + (b"vltri", "\u{22B2}"), + (b"vnsub", "\u{2282}\u{20D2}"), + (b"vnsup", "\u{2283}\u{20D2}"), + (b"vopf", "\u{1D567}"), + (b"vprop", "\u{221D}"), + (b"vrtri", "\u{22B3}"), + (b"vscr", "\u{1D4CB}"), + (b"vsubnE", "\u{2ACB}\u{FE00}"), + (b"vsubne", "\u{228A}\u{FE00}"), + (b"vsupnE", "\u{2ACC}\u{FE00}"), + (b"vsupne", "\u{228B}\u{FE00}"), + (b"vzigzag", "\u{299A}"), + (b"wcirc", "\u{0175}"), + (b"wedbar", "\u{2A5F}"), + (b"wedge", "\u{2227}"), + (b"wedgeq", "\u{2259}"), + (b"weierp", "\u{2118}"), + (b"wfr", "\u{1D534}"), + (b"wopf", "\u{1D568}"), + (b"wp", "\u{2118}"), + (b"wr", "\u{2240}"), + (b"wreath", "\u{2240}"), + (b"wscr", "\u{1D4CC}"), + (b"xcap", "\u{22C2}"), + (b"xcirc", "\u{25EF}"), + (b"xcup", "\u{22C3}"), + (b"xdtri", "\u{25BD}"), + (b"xfr", "\u{1D535}"), + (b"xhArr", "\u{27FA}"), + (b"xharr", "\u{27F7}"), + (b"xi", "\u{03BE}"), + (b"xlArr", "\u{27F8}"), + (b"xlarr", "\u{27F5}"), + (b"xmap", "\u{27FC}"), + (b"xnis", "\u{22FB}"), + (b"xodot", "\u{2A00}"), + (b"xopf", "\u{1D569}"), + (b"xoplus", "\u{2A01}"), + (b"xotime", "\u{2A02}"), + (b"xrArr", "\u{27F9}"), + (b"xrarr", "\u{27F6}"), + (b"xscr", "\u{1D4CD}"), + (b"xsqcup", "\u{2A06}"), + (b"xuplus", "\u{2A04}"), + (b"xutri", "\u{25B3}"), + (b"xvee", "\u{22C1}"), + (b"xwedge", "\u{22C0}"), + (b"yacute", "\u{00FD}"), + (b"yacy", "\u{044F}"), + (b"ycirc", "\u{0177}"), + (b"ycy", "\u{044B}"), + (b"yen", "\u{00A5}"), + (b"yfr", "\u{1D536}"), + (b"yicy", "\u{0457}"), + (b"yopf", "\u{1D56A}"), + (b"yscr", "\u{1D4CE}"), + (b"yucy", "\u{044E}"), + (b"yuml", "\u{00FF}"), + (b"zacute", "\u{017A}"), + (b"zcaron", "\u{017E}"), + (b"zcy", "\u{0437}"), + (b"zdot", "\u{017C}"), + (b"zeetrf", "\u{2128}"), + (b"zeta", "\u{03B6}"), + (b"zfr", "\u{1D537}"), + (b"zhcy", "\u{0436}"), + (b"zigrarr", "\u{21DD}"), + (b"zopf", "\u{1D56B}"), + (b"zscr", "\u{1D4CF}"), + (b"zwj", "\u{200D}"), + (b"zwnj", "\u{200C}"), +]; + +pub(crate) fn get_entity(bytes: &[u8]) -> Option<&'static str> { + ENTITIES + .binary_search_by_key(&bytes, |&(key, _value)| key) + .ok() + .map(|i| ENTITIES[i].1) +} diff --git a/vendor/pulldown-cmark-0.7.2/src/escape.rs b/vendor/pulldown-cmark-0.7.2/src/escape.rs new file mode 100644 index 0000000000..7b31cef614 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/escape.rs @@ -0,0 +1,297 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Utility functions for HTML escaping + +use std::io; +use std::str::from_utf8; + +use crate::html::StrWrite; + +#[rustfmt::skip] +static HREF_SAFE: [u8; 128] = [ + 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, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 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, 0, 0, 0, 0, 1, + 0, 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, 0, 0, 0, 0, 0, +]; + +static HEX_CHARS: &[u8] = b"0123456789ABCDEF"; +static AMP_ESCAPE: &str = "&"; +static SLASH_ESCAPE: &str = "'"; + +pub(crate) fn escape_href(mut w: W, s: &str) -> io::Result<()> +where + W: StrWrite, +{ + let bytes = s.as_bytes(); + let mut mark = 0; + for i in 0..bytes.len() { + let c = bytes[i]; + if c >= 0x80 || HREF_SAFE[c as usize] == 0 { + // character needing escape + + // write partial substring up to mark + if mark < i { + w.write_str(&s[mark..i])?; + } + match c { + b'&' => { + w.write_str(AMP_ESCAPE)?; + } + b'\'' => { + w.write_str(SLASH_ESCAPE)?; + } + _ => { + let mut buf = [0u8; 3]; + buf[0] = b'%'; + buf[1] = HEX_CHARS[((c as usize) >> 4) & 0xF]; + buf[2] = HEX_CHARS[(c as usize) & 0xF]; + let escaped = from_utf8(&buf).unwrap(); + w.write_str(escaped)?; + } + } + mark = i + 1; // all escaped characters are ASCII + } + } + w.write_str(&s[mark..]) +} + +const fn create_html_escape_table() -> [u8; 256] { + let mut table = [0; 256]; + table[b'"' as usize] = 1; + table[b'&' as usize] = 2; + table[b'<' as usize] = 3; + table[b'>' as usize] = 4; + table +} + +static HTML_ESCAPE_TABLE: [u8; 256] = create_html_escape_table(); + +static HTML_ESCAPES: [&'static str; 5] = ["", """, "&", "<", ">"]; + +/// Writes the given string to the Write sink, replacing special HTML bytes +/// (<, >, &, ") by escape sequences. +pub(crate) fn escape_html(w: W, s: &str) -> io::Result<()> { + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + simd::escape_html(w, s) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + escape_html_scalar(w, s) + } +} + +fn escape_html_scalar(mut w: W, s: &str) -> io::Result<()> { + let bytes = s.as_bytes(); + let mut mark = 0; + let mut i = 0; + while i < s.len() { + match bytes[i..] + .iter() + .position(|&c| HTML_ESCAPE_TABLE[c as usize] != 0) + { + Some(pos) => { + i += pos; + } + None => break, + } + let c = bytes[i]; + let escape = HTML_ESCAPE_TABLE[c as usize]; + let escape_seq = HTML_ESCAPES[escape as usize]; + w.write_str(&s[mark..i])?; + w.write_str(escape_seq)?; + i += 1; + mark = i; // all escaped characters are ASCII + } + w.write_str(&s[mark..]) +} + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd { + use crate::html::StrWrite; + use std::arch::x86_64::*; + use std::io; + use std::mem::size_of; + + const VECTOR_SIZE: usize = size_of::<__m128i>(); + + pub(crate) fn escape_html(mut w: W, s: &str) -> io::Result<()> { + // The SIMD accelerated code uses the PSHUFB instruction, which is part + // of the SSSE3 instruction set. Further, we can only use this code if + // the buffer is at least one VECTOR_SIZE in length to prevent reading + // out of bounds. If either of these conditions is not met, we fall back + // to scalar code. + if is_x86_feature_detected!("ssse3") && s.len() >= VECTOR_SIZE { + let bytes = s.as_bytes(); + let mut mark = 0; + + unsafe { + foreach_special_simd(bytes, 0, |i| { + let escape_ix = *bytes.get_unchecked(i) as usize; + let replacement = + super::HTML_ESCAPES[super::HTML_ESCAPE_TABLE[escape_ix] as usize]; + w.write_str(&s.get_unchecked(mark..i))?; + mark = i + 1; // all escaped characters are ASCII + w.write_str(replacement) + })?; + w.write_str(&s.get_unchecked(mark..)) + } + } else { + super::escape_html_scalar(w, s) + } + } + + /// Creates the lookup table for use in `compute_mask`. + const fn create_lookup() -> [u8; 16] { + let mut table = [0; 16]; + table[(b'<' & 0x0f) as usize] = b'<'; + table[(b'>' & 0x0f) as usize] = b'>'; + table[(b'&' & 0x0f) as usize] = b'&'; + table[(b'"' & 0x0f) as usize] = b'"'; + table[0] = 0b0111_1111; + table + } + + #[target_feature(enable = "ssse3")] + /// Computes a byte mask at given offset in the byte buffer. Its first 16 (least significant) + /// bits correspond to whether there is an HTML special byte (&, <, ", >) at the 16 bytes + /// `bytes[offset..]`. For example, the mask `(1 << 3)` states that there is an HTML byte + /// at `offset + 3`. It is only safe to call this function when + /// `bytes.len() >= offset + VECTOR_SIZE`. + unsafe fn compute_mask(bytes: &[u8], offset: usize) -> i32 { + debug_assert!(bytes.len() >= offset + VECTOR_SIZE); + + let table = create_lookup(); + let lookup = _mm_loadu_si128(table.as_ptr() as *const __m128i); + let raw_ptr = bytes.as_ptr().offset(offset as isize) as *const __m128i; + + // Load the vector from memory. + let vector = _mm_loadu_si128(raw_ptr); + // We take the least significant 4 bits of every byte and use them as indices + // to map into the lookup vector. + // Note that shuffle maps bytes with their most significant bit set to lookup[0]. + // Bytes that share their lower nibble with an HTML special byte get mapped to that + // corresponding special byte. Note that all HTML special bytes have distinct lower + // nibbles. Other bytes either get mapped to 0 or 127. + let expected = _mm_shuffle_epi8(lookup, vector); + // We compare the original vector to the mapped output. Bytes that shared a lower + // nibble with an HTML special byte match *only* if they are that special byte. Bytes + // that have either a 0 lower nibble or their most significant bit set were mapped to + // 127 and will hence never match. All other bytes have non-zero lower nibbles but + // were mapped to 0 and will therefore also not match. + let matches = _mm_cmpeq_epi8(expected, vector); + + // Translate matches to a bitmask, where every 1 corresponds to a HTML special character + // and a 0 is a non-HTML byte. + _mm_movemask_epi8(matches) + } + + /// Calls the given function with the index of every byte in the given byteslice + /// that is either ", &, <, or > and for no other byte. + /// Make sure to only call this when `bytes.len() >= 16`, undefined behaviour may + /// occur otherwise. + #[target_feature(enable = "ssse3")] + unsafe fn foreach_special_simd( + bytes: &[u8], + mut offset: usize, + mut callback: F, + ) -> io::Result<()> + where + F: FnMut(usize) -> io::Result<()>, + { + // The strategy here is to walk the byte buffer in chunks of VECTOR_SIZE (16) + // bytes at a time starting at the given offset. For each chunk, we compute a + // a bitmask indicating whether the corresponding byte is a HTML special byte. + // We then iterate over all the 1 bits in this mask and call the callback function + // with the corresponding index in the buffer. + // When the number of HTML special bytes in the buffer is relatively low, this + // allows us to quickly go through the buffer without a lookup and for every + // single byte. + + debug_assert!(bytes.len() >= VECTOR_SIZE); + let upperbound = bytes.len() - VECTOR_SIZE; + while offset < upperbound { + let mut mask = compute_mask(bytes, offset); + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + offset += VECTOR_SIZE; + } + + // Final iteration. We align the read with the end of the slice and + // shift off the bytes at start we have already scanned. + let mut mask = compute_mask(bytes, upperbound); + mask >>= offset - upperbound; + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + Ok(()) + } + + #[cfg(test)] + mod html_scan_tests { + #[test] + fn multichunk() { + let mut vec = Vec::new(); + unsafe { + super::foreach_special_simd("&aXaaaa.a'aa9a<>aab&".as_bytes(), 0, |ix| { + Ok(vec.push(ix)) + }) + .unwrap(); + } + assert_eq!(vec, vec![0, 14, 15, 19]); + } + + // only match these bytes, and when we match them, match them VECTOR_SIZE times + #[test] + fn only_right_bytes_matched() { + for b in 0..255u8 { + let right_byte = b == b'&' || b == b'<' || b == b'>' || b == b'"'; + let vek = vec![b; super::VECTOR_SIZE]; + let mut match_count = 0; + unsafe { + super::foreach_special_simd(&vek, 0, |_| { + match_count += 1; + Ok(()) + }) + .unwrap(); + } + assert!((match_count > 0) == (match_count == super::VECTOR_SIZE)); + assert_eq!( + (match_count == super::VECTOR_SIZE), + right_byte, + "match_count: {}, byte: {:?}", + match_count, + b as char + ); + } + } + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/html.rs b/vendor/pulldown-cmark-0.7.2/src/html.rs new file mode 100644 index 0000000000..06e5dc68b6 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/html.rs @@ -0,0 +1,520 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! HTML renderer that takes an iterator of events as input. + +use std::collections::HashMap; +use std::fmt::{Arguments, Write as FmtWrite}; +use std::io::{self, ErrorKind, Write}; + +use crate::escape::{escape_href, escape_html}; +use crate::parse::Event::*; +use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, Tag}; +use crate::strings::CowStr; + +enum TableState { + Head, + Body, +} + +/// This wrapper exists because we can't have both a blanket implementation +/// for all types implementing `Write` and types of the for `&mut W` where +/// `W: StrWrite`. Since we need the latter a lot, we choose to wrap +/// `Write` types. +struct WriteWrapper(W); + +/// Trait that allows writing string slices. This is basically an extension +/// of `std::io::Write` in order to include `String`. +pub(crate) trait StrWrite { + fn write_str(&mut self, s: &str) -> io::Result<()>; + + fn write_fmt(&mut self, args: Arguments) -> io::Result<()>; +} + +impl StrWrite for WriteWrapper +where + W: Write, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.0.write_all(s.as_bytes()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + self.0.write_fmt(args) + } +} + +impl<'w> StrWrite for String { + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.push_str(s); + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + // FIXME: translate fmt error to io error? + FmtWrite::write_fmt(self, args).map_err(|_| ErrorKind::Other.into()) + } +} + +impl StrWrite for &'_ mut W +where + W: StrWrite, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + (**self).write_str(s) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + (**self).write_fmt(args) + } +} + +struct HtmlWriter<'a, I, W> { + /// Iterator supplying events. + iter: I, + + /// Writer to write to. + writer: W, + + /// Whether or not the last write wrote a newline. + end_newline: bool, + + table_state: TableState, + table_alignments: Vec, + table_cell_index: usize, + numbers: HashMap, usize>, +} + +impl<'a, I, W> HtmlWriter<'a, I, W> +where + I: Iterator>, + W: StrWrite, +{ + fn new(iter: I, writer: W) -> Self { + Self { + iter, + writer, + end_newline: true, + table_state: TableState::Head, + table_alignments: vec![], + table_cell_index: 0, + numbers: HashMap::new(), + } + } + + /// Writes a new line. + fn write_newline(&mut self) -> io::Result<()> { + self.end_newline = true; + self.writer.write_str("\n") + } + + /// Writes a buffer, and tracks whether or not a newline was written. + #[inline] + fn write(&mut self, s: &str) -> io::Result<()> { + self.writer.write_str(s)?; + + if !s.is_empty() { + self.end_newline = s.ends_with('\n'); + } + Ok(()) + } + + pub fn run(mut self) -> io::Result<()> { + while let Some(event) = self.iter.next() { + match event { + Start(tag) => { + self.start_tag(tag)?; + } + End(tag) => { + self.end_tag(tag)?; + } + Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + Code(text) => { + self.write("")?; + escape_html(&mut self.writer, &text)?; + self.write("")?; + } + Html(html) => { + self.write(&html)?; + } + SoftBreak => { + self.write_newline()?; + } + HardBreak => { + self.write("
    \n")?; + } + Rule => { + if self.end_newline { + self.write("
    \n")?; + } else { + self.write("\n
    \n")?; + } + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + self.write("")?; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "{}", number)?; + self.write("")?; + } + TaskListMarker(true) => { + self.write("\n")?; + } + TaskListMarker(false) => { + self.write("\n")?; + } + } + } + Ok(()) + } + + /// Writes the start of an HTML tag. + fn start_tag(&mut self, tag: Tag<'a>) -> io::Result<()> { + match tag { + Tag::Paragraph => { + if self.end_newline { + self.write("

    ") + } else { + self.write("\n

    ") + } + } + Tag::Heading(level) => { + if self.end_newline { + self.end_newline = false; + write!(&mut self.writer, "", level) + } else { + write!(&mut self.writer, "\n", level) + } + } + Tag::Table(alignments) => { + self.table_alignments = alignments; + self.write("") + } + Tag::TableHead => { + self.table_state = TableState::Head; + self.table_cell_index = 0; + self.write("") + } + Tag::TableRow => { + self.table_cell_index = 0; + self.write("") + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write(" { + self.write(" self.write(" align=\"left\">"), + Some(&Alignment::Center) => self.write(" align=\"center\">"), + Some(&Alignment::Right) => self.write(" align=\"right\">"), + _ => self.write(">"), + } + } + Tag::BlockQuote => { + if self.end_newline { + self.write("
    \n") + } else { + self.write("\n
    \n") + } + } + Tag::CodeBlock(info) => { + if !self.end_newline { + self.write_newline()?; + } + match info { + CodeBlockKind::Fenced(info) => { + let lang = info.split(' ').next().unwrap(); + if lang.is_empty() { + self.write("
    ")
    +                        } else {
    +                            self.write("
    ")
    +                        }
    +                    }
    +                    CodeBlockKind::Indented => self.write("
    "),
    +                }
    +            }
    +            Tag::List(Some(1)) => {
    +                if self.end_newline {
    +                    self.write("
      \n") + } else { + self.write("\n
        \n") + } + } + Tag::List(Some(start)) => { + if self.end_newline { + self.write("
          \n") + } + Tag::List(None) => { + if self.end_newline { + self.write("
    \n")?; + } + Tag::TableHead => { + self.write("\n")?; + self.table_state = TableState::Body; + } + Tag::TableRow => { + self.write("\n")?; + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write("")?; + } + TableState::Body => { + self.write("")?; + } + } + self.table_cell_index += 1; + } + Tag::BlockQuote => { + self.write("\n")?; + } + Tag::CodeBlock(_) => { + self.write("\n")?; + } + Tag::List(Some(_)) => { + self.write("\n")?; + } + Tag::List(None) => { + self.write("\n")?; + } + Tag::Item => { + self.write("\n")?; + } + Tag::Emphasis => { + self.write("")?; + } + Tag::Strong => { + self.write("")?; + } + Tag::Strikethrough => { + self.write("")?; + } + Tag::Link(_, _, _) => { + self.write("")?; + } + Tag::Image(_, _, _) => (), // shouldn't happen, handled in start + Tag::FootnoteDefinition(_) => { + self.write("\n")?; + } + } + Ok(()) + } + + // run raw text, consuming end tag + fn raw_text(&mut self) -> io::Result<()> { + let mut nest = 0; + while let Some(event) = self.iter.next() { + match event { + Start(_) => nest += 1, + End(_) => { + if nest == 0 { + break; + } + nest -= 1; + } + Html(text) | Code(text) | Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + SoftBreak | HardBreak | Rule => { + self.write(" ")?; + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "[{}]", number)?; + } + TaskListMarker(true) => self.write("[x]")?, + TaskListMarker(false) => self.write("[ ]")?, + } + } + Ok(()) + } +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// push it to a `String`. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let parser = Parser::new(markdown_str); +/// +/// let mut html_buf = String::new(); +/// html::push_html(&mut html_buf, parser); +/// +/// assert_eq!(html_buf, r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn push_html<'a, I>(s: &mut String, iter: I) +where + I: Iterator>, +{ + HtmlWriter::new(iter, s).run().unwrap(); +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// write it out to a writable stream. +/// +/// **Note**: using this function with an unbuffered writer like a file or socket +/// will result in poor performance. Wrap these in a +/// [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html) to +/// prevent unnecessary slowdowns. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// use std::io::Cursor; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let mut bytes = Vec::new(); +/// let parser = Parser::new(markdown_str); +/// +/// html::write_html(Cursor::new(&mut bytes), parser); +/// +/// assert_eq!(&String::from_utf8_lossy(&bytes)[..], r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn write_html<'a, I, W>(writer: W, iter: I) -> io::Result<()> +where + I: Iterator>, + W: Write, +{ + HtmlWriter::new(iter, WriteWrapper(writer)).run() +} diff --git a/vendor/pulldown-cmark-0.7.2/src/lib.rs b/vendor/pulldown-cmark-0.7.2/src/lib.rs new file mode 100644 index 0000000000..f3f16b3dab --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/lib.rs @@ -0,0 +1,76 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Pull parser for [CommonMark](https://commonmark.org). This crate provides a [Parser](struct.Parser.html) struct +//! which is an iterator over [Event](enum.Event.html)s. This iterator can be used +//! directly, or to output HTML using the [HTML module](html/index.html). +//! +//! By default, only CommonMark features are enabled. To use extensions like tables, +//! footnotes or task lists, enable them by setting the corresponding flags in the +//! [Options](struct.Options.html) struct. +//! +//! # Example +//! ```rust +//! use pulldown_cmark::{Parser, Options, html}; +//! +//! let markdown_input = "Hello world, this is a ~~complicated~~ *very simple* example."; +//! +//! // Set up options and parser. Strikethroughs are not part of the CommonMark standard +//! // and we therefore must enable it explicitly. +//! let mut options = Options::empty(); +//! options.insert(Options::ENABLE_STRIKETHROUGH); +//! let parser = Parser::new_ext(markdown_input, options); +//! +//! // Write to String buffer. +//! let mut html_output = String::new(); +//! html::push_html(&mut html_output, parser); +//! +//! // Check that the output is what we expected. +//! let expected_html = "

    Hello world, this is a complicated very simple example.

    \n"; +//! assert_eq!(expected_html, &html_output); +//! ``` + +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate. +#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +pub mod html; + +#[macro_use] +extern crate bitflags; +extern crate unicase; + +mod entities; +mod escape; +mod linklabel; +mod parse; +mod puncttable; +mod scanners; +mod strings; +mod tree; + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd; + +pub use crate::parse::{ + Alignment, CodeBlockKind, Event, LinkType, OffsetIter, Options, Parser, Tag, +}; +pub use crate::strings::{CowStr, InlineStr}; diff --git a/vendor/pulldown-cmark-0.7.2/src/linklabel.rs b/vendor/pulldown-cmark-0.7.2/src/linklabel.rs new file mode 100644 index 0000000000..cfb9c2706b --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/linklabel.rs @@ -0,0 +1,135 @@ +// Copyright 2018 Google LLC +// +// 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. + +//! Link label parsing and matching. + +use unicase::UniCase; + +use crate::scanners::{is_ascii_whitespace, scan_eol}; +use crate::strings::CowStr; + +pub enum ReferenceLabel<'a> { + Link(CowStr<'a>), + Footnote(CowStr<'a>), +} + +pub type LinkLabel<'a> = UniCase>; + +/// Assumes the opening bracket has already been scanned. +/// The line break handler determines what happens when a linebreak +/// is found. It is passed the bytes following the line break and +/// either returns `Some(k)`, where `k` is the number of bytes to skip, +/// or `None` to abort parsing the label. +/// Returns the number of bytes read (including closing bracket) and label on success. +pub(crate) fn scan_link_label_rest<'t>( + text: &'t str, + linebreak_handler: &dyn Fn(&[u8]) -> Option, +) -> Option<(usize, CowStr<'t>)> { + let bytes = text.as_bytes(); + let mut ix = 0; + let mut only_white_space = true; + let mut codepoints = 0; + // no worries, doesnt allocate until we push things onto it + let mut label = String::new(); + let mut mark = 0; + + loop { + if codepoints >= 1000 { + return None; + } + match *bytes.get(ix)? { + b'[' => return None, + b']' => break, + b'\\' => { + ix += 2; + codepoints += 2; + only_white_space = false; + } + b if is_ascii_whitespace(b) => { + // normalize labels by collapsing whitespaces, including linebreaks + let mut whitespaces = 0; + let mut linebreaks = 0; + let whitespace_start = ix; + + while ix < bytes.len() && is_ascii_whitespace(bytes[ix]) { + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + linebreaks += 1; + if linebreaks > 1 { + return None; + } + ix += eol_bytes; + ix += linebreak_handler(&bytes[ix..])?; + whitespaces += 2; // indicate that we need to replace + } else { + whitespaces += if bytes[ix] == b' ' { 1 } else { 2 }; + ix += 1; + } + } + if whitespaces > 1 { + label.push_str(&text[mark..whitespace_start]); + label.push(' '); + mark = ix; + codepoints += ix - whitespace_start; + } else { + codepoints += 1; + } + } + b => { + only_white_space = false; + ix += 1; + if b & 0b1000_0000 != 0 { + codepoints += 1; + } + } + } + } + + if only_white_space { + None + } else { + let cow = if mark == 0 { + text[..ix].into() + } else { + label.push_str(&text[mark..ix]); + label.into() + }; + Some((ix + 1, cow)) + } +} + +#[cfg(test)] +mod test { + use super::scan_link_label_rest; + + #[test] + fn whitespace_normalization() { + let input = "«\t\tBlurry Eyes\t\t»][blurry_eyes]"; + let expected_output = "« Blurry Eyes »"; // regular spaces! + + let (_bytes, normalized_label) = scan_link_label_rest(input, &|_| None).unwrap(); + assert_eq!(expected_output, normalized_label.as_ref()); + } + + #[test] + fn return_carriage_linefeed_ok() { + let input = "hello\r\nworld\r\n]"; + assert!(scan_link_label_rest(input, &|_| Some(0)).is_some()); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/main.rs b/vendor/pulldown-cmark-0.7.2/src/main.rs new file mode 100644 index 0000000000..d0225a4ce7 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/main.rs @@ -0,0 +1,109 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Command line tool to exercise pulldown-cmark. + +use pulldown_cmark::{html, Options, Parser}; + +use std::env; +use std::io::{self, Read}; +use std::mem; + +fn dry_run(text: &str, opts: Options) { + let p = Parser::new_ext(text, opts); + let count = p.count(); + println!("{} events", count); +} + +fn print_events(text: &str, opts: Options) { + let parser = Parser::new_ext(text, opts).into_offset_iter(); + for (event, range) in parser { + println!("{:?}: {:?}", range, event); + } + println!("EOF"); +} + +fn brief(program: &str) -> String { + format!( + "Usage: {} [options]\n\n{}", + program, "Reads markdown from standard input and emits HTML.", + ) +} + +pub fn main() -> std::io::Result<()> { + let args: Vec<_> = env::args().collect(); + let mut opts = getopts::Options::new(); + opts.optflag("h", "help", "this help message"); + opts.optflag("d", "dry-run", "dry run, produce no output"); + opts.optflag("e", "events", "print event sequence instead of rendering"); + opts.optflag("T", "enable-tables", "enable GitHub-style tables"); + opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes"); + opts.optflag( + "S", + "enable-strikethrough", + "enable GitHub-style strikethrough", + ); + opts.optflag("L", "enable-tasklists", "enable GitHub-style task lists"); + + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => { + eprintln!("{}\n{}", f, opts.usage(&brief(&args[0]))); + std::process::exit(1); + } + }; + if matches.opt_present("help") { + println!("{}", opts.usage(&brief(&args[0]))); + return Ok(()); + } + let mut opts = Options::empty(); + if matches.opt_present("enable-tables") { + opts.insert(Options::ENABLE_TABLES); + } + if matches.opt_present("enable-footnotes") { + opts.insert(Options::ENABLE_FOOTNOTES); + } + if matches.opt_present("enable-strikethrough") { + opts.insert(Options::ENABLE_STRIKETHROUGH); + } + if matches.opt_present("enable-tasklists") { + opts.insert(Options::ENABLE_TASKLISTS); + } + + let mut input = String::new(); + io::stdin().lock().read_to_string(&mut input)?; + if matches.opt_present("events") { + print_events(&input, opts); + } else if matches.opt_present("dry-run") { + dry_run(&input, opts); + } else { + let mut p = Parser::new_ext(&input, opts); + let stdio = io::stdout(); + let buffer = std::io::BufWriter::with_capacity(1024 * 1024, stdio.lock()); + html::write_html(buffer, &mut p)?; + // Since the program will now terminate and the memory will be returned + // to the operating system anyway, there is no point in tidely cleaning + // up all the datastructures we have used. We shouldn't do this if we'd + // do other things after this, because this is basically intentionally + // leaking data. Skipping cleanup lets us return a bit (~5%) faster. + mem::forget(p); + } + Ok(()) +} diff --git a/vendor/pulldown-cmark-0.7.2/src/parse.rs b/vendor/pulldown-cmark-0.7.2/src/parse.rs new file mode 100644 index 0000000000..ab50679f9e --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/parse.rs @@ -0,0 +1,3138 @@ +// Copyright 2017 Google Inc. All rights reserved. +// +// 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. + +//! Tree-based two pass parser. + +use std::cmp::{max, min}; +use std::collections::{HashMap, VecDeque}; +use std::ops::{Index, Range}; + +use unicase::UniCase; + +use crate::linklabel::{scan_link_label_rest, LinkLabel, ReferenceLabel}; +use crate::scanners::*; +use crate::strings::CowStr; +use crate::tree::{Tree, TreeIndex}; + +// Allowing arbitrary depth nested parentheses inside link destinations +// can create denial of service vulnerabilities if we're not careful. +// The simplest countermeasure is to limit their depth, which is +// explicitly allowed by the spec as long as the limit is at least 3: +// https://spec.commonmark.org/0.29/#link-destination +const LINK_MAX_NESTED_PARENS: usize = 5; + +/// Codeblock kind. +#[derive(Clone, Debug, PartialEq)] +pub enum CodeBlockKind<'a> { + Indented, + /// The value contained in the tag describes the language of the code, which may be empty. + Fenced(CowStr<'a>), +} + +impl<'a> CodeBlockKind<'a> { + pub fn is_indented(&self) -> bool { + match *self { + CodeBlockKind::Indented => true, + _ => false, + } + } + + pub fn is_fenced(&self) -> bool { + match *self { + CodeBlockKind::Fenced(_) => true, + _ => false, + } + } +} + +/// Tags for elements that can contain other elements. +#[derive(Clone, Debug, PartialEq)] +pub enum Tag<'a> { + /// A paragraph of text and other inline elements. + Paragraph, + + /// A heading. The field indicates the level of the heading. + Heading(u32), + + BlockQuote, + /// A code block. + CodeBlock(CodeBlockKind<'a>), + + /// A list. If the list is ordered the field indicates the number of the first item. + /// Contains only list items. + List(Option), // TODO: add delim and tight for ast (not needed for html) + /// A list item. + Item, + /// A footnote definition. The value contained is the footnote's label by which it can + /// be referred to. + FootnoteDefinition(CowStr<'a>), + + /// A table. Contains a vector describing the text-alignment for each of its columns. + Table(Vec), + /// A table header. Contains only `TableRow`s. Note that the table body starts immediately + /// after the closure of the `TableHead` tag. There is no `TableBody` tag. + TableHead, + /// A table row. Is used both for header rows as body rows. Contains only `TableCell`s. + TableRow, + TableCell, + + // span-level tags + Emphasis, + Strong, + Strikethrough, + + /// A link. The first field is the link type, the second the destination URL and the third is a title. + Link(LinkType, CowStr<'a>, CowStr<'a>), + + /// An image. The first field is the link type, the second the destination URL and the third is a title. + Image(LinkType, CowStr<'a>, CowStr<'a>), +} + +/// Type specifier for inline links. See [the Tag::Link](enum.Tag.html#variant.Link) for more information. +#[derive(Clone, Debug, PartialEq, Copy)] +pub enum LinkType { + /// Inline link like `[foo](bar)` + Inline, + /// Reference link like `[foo][bar]` + Reference, + /// Reference without destination in the document, but resolved by the broken_link_callback + ReferenceUnknown, + /// Collapsed link like `[foo][]` + Collapsed, + /// Collapsed link without destination in the document, but resolved by the broken_link_callback + CollapsedUnknown, + /// Shortcut link like `[foo]` + Shortcut, + /// Shortcut without destination in the document, but resolved by the broken_link_callback + ShortcutUnknown, + /// Autolink like `` + Autolink, + /// Email address in autolink like `` + Email, +} + +impl LinkType { + fn to_unknown(self) -> Self { + match self { + LinkType::Reference => LinkType::ReferenceUnknown, + LinkType::Collapsed => LinkType::CollapsedUnknown, + LinkType::Shortcut => LinkType::ShortcutUnknown, + _ => unreachable!(), + } + } +} + +/// Markdown events that are generated in a preorder traversal of the document +/// tree, with additional `End` events whenever all of an inner node's children +/// have been visited. +#[derive(Clone, Debug, PartialEq)] +pub enum Event<'a> { + /// Start of a tagged element. Events that are yielded after this event + /// and before its corresponding `End` event are inside this element. + /// Start and end events are guaranteed to be balanced. + Start(Tag<'a>), + /// End of a tagged element. + End(Tag<'a>), + /// A text node. + Text(CowStr<'a>), + /// An inline code node. + Code(CowStr<'a>), + /// An HTML node. + Html(CowStr<'a>), + /// A reference to a footnote with given label, which may or may not be defined + /// by an event with a `Tag::FootnoteDefinition` tag. Definitions and references to them may + /// occur in any order. + FootnoteReference(CowStr<'a>), + /// A soft line break. + SoftBreak, + /// A hard line break. + HardBreak, + /// A horizontal ruler. + Rule, + /// A task list marker, rendered as a checkbox in HTML. Contains a true when it is checked. + TaskListMarker(bool), +} + +/// Table column text alignment. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Alignment { + /// Default text alignment. + None, + Left, + Center, + Right, +} + +bitflags! { + /// Option struct containing flags for enabling extra features + /// that are not part of the CommonMark spec. + pub struct Options: u32 { + const ENABLE_TABLES = 1 << 1; + const ENABLE_FOOTNOTES = 1 << 2; + const ENABLE_STRIKETHROUGH = 1 << 3; + const ENABLE_TASKLISTS = 1 << 4; + } +} + +#[derive(Debug, Default, Clone, Copy)] +struct Item { + start: usize, + end: usize, + body: ItemBody, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +enum ItemBody { + Paragraph, + Text, + SoftBreak, + HardBreak, + + // These are possible inline items, need to be resolved in second pass. + + // repeats, can_open, can_close + MaybeEmphasis(usize, bool, bool), + MaybeCode(usize, bool), // number of backticks, preceeded by backslash + MaybeHtml, + MaybeLinkOpen, + MaybeLinkClose, + MaybeImage, + + // These are inline items after resolution. + Emphasis, + Strong, + Strikethrough, + Code(CowIndex), + Link(LinkIndex), + Image(LinkIndex), + FootnoteReference(CowIndex), + TaskListMarker(bool), // true for checked + + Rule, + Heading(u32), // heading level + FencedCodeBlock(CowIndex), + IndentCodeBlock, + Html, + BlockQuote, + List(bool, u8, u64), // is_tight, list character, list start index + ListItem(usize), // indent level + SynthesizeText(CowIndex), + FootnoteDefinition(CowIndex), + + // Tables + Table(AlignmentIndex), + TableHead, + TableRow, + TableCell, + + // Dummy node at the top of the tree - should not be used otherwise! + Root, +} + +impl<'a> ItemBody { + fn is_inline(&self) -> bool { + match *self { + ItemBody::MaybeEmphasis(..) + | ItemBody::MaybeHtml + | ItemBody::MaybeCode(..) + | ItemBody::MaybeLinkOpen + | ItemBody::MaybeLinkClose + | ItemBody::MaybeImage => true, + _ => false, + } + } +} + +impl<'a> Default for ItemBody { + fn default() -> Self { + ItemBody::Root + } +} + +/// Scanning modes for `Parser`'s `parse_line` method. +#[derive(PartialEq, Eq, Copy, Clone)] +enum TableParseMode { + /// Inside a paragraph, scanning for table headers. + Scan, + /// Inside a table. + Active, + /// Inside a paragraph, not scanning for table headers. + Disabled, +} + +/// State for the first parsing pass. +/// +/// The first pass resolves all block structure, generating an AST. Within a block, items +/// are in a linear chain with potential inline markup identified. +struct FirstPass<'a> { + text: &'a str, + tree: Tree, + begin_list_item: bool, + last_line_blank: bool, + allocs: Allocations<'a>, + options: Options, + list_nesting: usize, +} + +impl<'a> FirstPass<'a> { + fn new(text: &'a str, options: Options) -> FirstPass { + // This is a very naive heuristic for the number of nodes + // we'll need. + let start_capacity = max(128, text.len() / 32); + let tree = Tree::with_capacity(start_capacity); + let begin_list_item = false; + let last_line_blank = false; + let allocs = Allocations::new(); + FirstPass { + text, + tree, + begin_list_item, + last_line_blank, + allocs, + options, + list_nesting: 0, + } + } + + fn run(mut self) -> (Tree, Allocations<'a>) { + let mut ix = 0; + while ix < self.text.len() { + ix = self.parse_block(ix); + } + for _ in 0..self.tree.spine_len() { + self.pop(ix); + } + (self.tree, self.allocs) + } + + /// Returns offset after block. + fn parse_block(&mut self, mut start_ix: usize) -> usize { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[start_ix..]); + + let i = scan_containers(&self.tree, &mut line_start); + for _ in i..self.tree.spine_len() { + self.pop(start_ix); + } + + if self.options.contains(Options::ENABLE_FOOTNOTES) { + // finish footnote if it's still open and was preceeded by blank line + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::FootnoteDefinition(..) = self.tree[node_ix].item.body { + if self.last_line_blank { + self.pop(start_ix); + } + } + } + + // Footnote definitions of the form + // [^bar]: + // * anything really + let container_start = start_ix + line_start.bytes_scanned(); + if let Some(bytecount) = self.parse_footnote(container_start) { + start_ix = container_start + bytecount; + start_ix += scan_blank_line(&bytes[start_ix..]).unwrap_or(0); + line_start = LineStart::new(&bytes[start_ix..]); + } + } + + // Process new containers + loop { + let container_start = start_ix + line_start.bytes_scanned(); + if let Some((ch, index, indent)) = line_start.scan_list_marker() { + let after_marker_index = start_ix + line_start.bytes_scanned(); + self.continue_list(container_start, ch, index); + self.tree.append(Item { + start: container_start, + end: after_marker_index, // will get updated later if item not empty + body: ItemBody::ListItem(indent), + }); + self.tree.push(); + if let Some(n) = scan_blank_line(&bytes[after_marker_index..]) { + self.begin_list_item = true; + return after_marker_index + n; + } + if self.options.contains(Options::ENABLE_TASKLISTS) { + if let Some(is_checked) = line_start.scan_task_list_marker() { + self.tree.append(Item { + start: after_marker_index, + end: start_ix + line_start.bytes_scanned(), + body: ItemBody::TaskListMarker(is_checked), + }); + } + } + } else if line_start.scan_blockquote_marker() { + self.finish_list(start_ix); + self.tree.append(Item { + start: container_start, + end: 0, // will get set later + body: ItemBody::BlockQuote, + }); + self.tree.push(); + } else { + break; + } + } + + let ix = start_ix + line_start.bytes_scanned(); + + if let Some(n) = scan_blank_line(&bytes[ix..]) { + if let Some(node_ix) = self.tree.peek_up() { + match self.tree[node_ix].item.body { + ItemBody::BlockQuote => (), + _ => { + if self.begin_list_item { + // A list item can begin with at most one blank line. + self.pop(start_ix); + } + self.last_line_blank = true; + } + } + } + return ix + n; + } + + self.begin_list_item = false; + self.finish_list(start_ix); + + // Save `remaining_space` here to avoid needing to backtrack `line_start` for HTML blocks + let remaining_space = line_start.remaining_space(); + + let indent = line_start.scan_space_upto(4); + if indent == 4 { + let ix = start_ix + line_start.bytes_scanned(); + let remaining_space = line_start.remaining_space(); + return self.parse_indented_code_block(ix, remaining_space); + } + + let ix = start_ix + line_start.bytes_scanned(); + + // HTML Blocks + if bytes[ix] == b'<' { + // Types 1-5 are all detected by one function and all end with the same + // pattern + if let Some(html_end_tag) = get_html_end_tag(&bytes[(ix + 1)..]) { + return self.parse_html_block_type_1_to_5(ix, html_end_tag, remaining_space); + } + + // Detect type 6 + let possible_tag = scan_html_block_tag(&bytes[(ix + 1)..]).1; + if is_html_tag(possible_tag) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + + // Detect type 7 + if let Some(_html_bytes) = scan_html_type_7(&bytes[(ix + 1)..]) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + } + + if let Ok(n) = scan_hrule(&bytes[ix..]) { + return self.parse_hrule(n, ix); + } + + if let Some(atx_size) = scan_atx_heading(&bytes[ix..]) { + return self.parse_atx_heading(ix, atx_size); + } + + // parse refdef + if let Some((bytecount, label, link_def)) = self.parse_refdef_total(ix) { + self.allocs.refdefs.entry(label).or_insert(link_def); + let ix = ix + bytecount; + // try to read trailing whitespace or it will register as a completely blank line + // TODO: shouldn't we do this for all block level items? + return ix + scan_blank_line(&bytes[ix..]).unwrap_or(0); + } + + if let Some((n, fence_ch)) = scan_code_fence(&bytes[ix..]) { + return self.parse_fenced_code_block(ix, indent, fence_ch, n); + } + self.parse_paragraph(ix) + } + + /// Returns the offset of the first line after the table. + /// Assumptions: current focus is a table element and the table header + /// matches the separator line (same number of columns). + fn parse_table(&mut self, table_cols: usize, head_start: usize, body_start: usize) -> usize { + // parse header. this shouldn't fail because we made sure the table header is ok + let (_sep_start, thead_ix) = self.parse_table_row_inner(head_start, table_cols); + self.tree[thead_ix].item.body = ItemBody::TableHead; + + // parse body + let mut ix = body_start; + while let Some((next_ix, _row_ix)) = self.parse_table_row(ix, table_cols) { + ix = next_ix; + } + + self.pop(ix); + ix + } + + /// Call this when containers are taken care of. + /// Returns bytes scanned, row_ix + fn parse_table_row_inner(&mut self, mut ix: usize, row_cells: usize) -> (usize, TreeIndex) { + let bytes = self.text.as_bytes(); + let mut cells = 0; + let mut final_cell_ix = None; + + let row_ix = self.tree.append(Item { + start: ix, + end: 0, // set at end of this function + body: ItemBody::TableRow, + }); + self.tree.push(); + + loop { + ix += scan_ch(&bytes[ix..], b'|'); + ix += scan_whitespace_no_nl(&bytes[ix..]); + + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + ix += eol_bytes; + break; + } + + let cell_ix = self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + self.tree.push(); + let (next_ix, _brk) = self.parse_line(ix, TableParseMode::Active); + let trailing_whitespace = scan_rev_while(&bytes[..next_ix], is_ascii_whitespace); + + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= trailing_whitespace; + } + + self.tree[cell_ix].item.end = next_ix - trailing_whitespace; + self.tree.pop(); + + ix = next_ix; + cells += 1; + + if cells == row_cells { + final_cell_ix = Some(cell_ix); + } + } + + // fill empty cells if needed + // note: this is where GFM and commonmark-extra diverge. we follow + // GFM here + for _ in cells..row_cells { + self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + } + + // drop excess cells + if let Some(cell_ix) = final_cell_ix { + self.tree[cell_ix].next = None; + } + + self.pop(ix); + + (ix, row_ix) + } + + /// Returns first offset after the row and the tree index of the row. + fn parse_table_row(&mut self, mut ix: usize, row_cells: usize) -> Option<(usize, TreeIndex)> { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[ix..]); + let containers = scan_containers(&self.tree, &mut line_start); + if containers != self.tree.spine_len() { + return None; + } + line_start.scan_all_space(); + ix += line_start.bytes_scanned(); + if scan_paragraph_interrupt(&bytes[ix..]) { + return None; + } + + let (ix, row_ix) = self.parse_table_row_inner(ix, row_cells); + Some((ix, row_ix)) + } + + /// Returns offset of line start after paragraph. + fn parse_paragraph(&mut self, start_ix: usize) -> usize { + let node_ix = self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::Paragraph, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + + let mut ix = start_ix; + loop { + let scan_mode = if self.options.contains(Options::ENABLE_TABLES) && ix == start_ix { + TableParseMode::Scan + } else { + TableParseMode::Disabled + }; + let (next_ix, brk) = self.parse_line(ix, scan_mode); + + // break out when we find a table + if let Some(Item { + body: ItemBody::Table(alignment_ix), + .. + }) = brk + { + let table_cols = self.allocs[alignment_ix].len(); + self.tree[node_ix].item.body = ItemBody::Table(alignment_ix); + // this clears out any stuff we may have appended - but there may + // be a cleaner way + self.tree[node_ix].child = None; + self.tree.pop(); + self.tree.push(); + return self.parse_table(table_cols, ix, next_ix); + } + + ix = next_ix; + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if !line_start.scan_space(4) { + let ix_new = ix + line_start.bytes_scanned(); + if n_containers == self.tree.spine_len() { + if let Some(ix_setext) = self.parse_setext_heading(ix_new, node_ix) { + if let Some(Item { + start, + body: ItemBody::HardBreak, + .. + }) = brk + { + if bytes[start] == b'\\' { + self.tree.append_text(start, start + 1); + } + } + ix = ix_setext; + break; + } + } + // first check for non-empty lists, then for other interrupts + let suffix = &bytes[ix_new..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + break; + } + } + line_start.scan_all_space(); + if line_start.is_at_eol() { + break; + } + ix = next_ix + line_start.bytes_scanned(); + if let Some(item) = brk { + self.tree.append(item); + } + } + + self.pop(ix); + ix + } + + /// Returns end ix of setext_heading on success. + fn parse_setext_heading(&mut self, ix: usize, node_ix: TreeIndex) -> Option { + let bytes = self.text.as_bytes(); + let (n, level) = scan_setext_heading(&bytes[ix..])?; + self.tree[node_ix].item.body = ItemBody::Heading(level); + + // strip trailing whitespace + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= scan_rev_while( + &bytes[..self.tree[cur_ix].item.end], + is_ascii_whitespace_no_nl, + ); + } + + Some(ix + n) + } + + /// Parse a line of input, appending text and items to tree. + /// + /// Returns: index after line and an item representing the break. + fn parse_line(&mut self, start: usize, mode: TableParseMode) -> (usize, Option) { + let bytes = &self.text.as_bytes(); + let mut pipes = 0; + let mut last_pipe_ix = start; + let mut begin_text = start; + + let (final_ix, brk) = iterate_special_bytes(bytes, start, |ix, byte| { + match byte { + b'\n' | b'\r' => { + if let TableParseMode::Active = mode { + return LoopInstruction::BreakAtWith(ix, None); + } + + let mut i = ix; + let eol_bytes = scan_eol(&bytes[ix..]).unwrap(); + if mode == TableParseMode::Scan && pipes > 0 { + // check if we may be parsing a table + let next_line_ix = ix + eol_bytes; + let mut line_start = LineStart::new(&bytes[next_line_ix..]); + if scan_containers(&self.tree, &mut line_start) == self.tree.spine_len() { + let table_head_ix = next_line_ix + line_start.bytes_scanned(); + let (table_head_bytes, alignment) = + scan_table_head(&bytes[table_head_ix..]); + + if table_head_bytes > 0 { + // computing header count from number of pipes + let header_count = + count_header_cols(bytes, pipes, start, last_pipe_ix); + + // make sure they match the number of columns we find in separator line + if alignment.len() == header_count { + let alignment_ix = self.allocs.allocate_alignment(alignment); + let end_ix = table_head_ix + table_head_bytes; + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, // must update later + body: ItemBody::Table(alignment_ix), + }), + ); + } + } + } + } + + let end_ix = ix + eol_bytes; + let trailing_backslashes = scan_rev_while(&bytes[..ix], |b| b == b'\\'); + if trailing_backslashes % 2 == 1 && end_ix < self.text.len() { + i -= 1; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + let trailing_whitespace = + scan_rev_while(&bytes[..ix], is_ascii_whitespace_no_nl); + if trailing_whitespace >= 2 { + i -= trailing_whitespace; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + + self.tree.append_text(begin_text, ix); + LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::SoftBreak, + }), + ) + } + b'\\' => { + if ix + 1 < self.text.len() && is_ascii_punctuation(bytes[ix + 1]) { + self.tree.append_text(begin_text, ix); + if bytes[ix + 1] == b'`' { + let count = 1 + scan_ch_repeat(&bytes[(ix + 2)..], b'`'); + self.tree.append(Item { + start: ix + 1, + end: ix + count + 1, + body: ItemBody::MaybeCode(count, true), + }); + begin_text = ix + 1 + count; + LoopInstruction::ContinueAndSkip(count) + } else { + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(1) + } + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + c @ b'*' | c @ b'_' | c @ b'~' => { + let string_suffix = &self.text[ix..]; + let count = 1 + scan_ch_repeat(&string_suffix.as_bytes()[1..], c); + let can_open = delim_run_can_open(self.text, string_suffix, count, ix); + let can_close = delim_run_can_close(self.text, string_suffix, count, ix); + let is_valid_seq = c != b'~' + || count == 2 && self.options.contains(Options::ENABLE_STRIKETHROUGH); + + if (can_open || can_close) && is_valid_seq { + self.tree.append_text(begin_text, ix); + for i in 0..count { + self.tree.append(Item { + start: ix + i, + end: ix + i + 1, + body: ItemBody::MaybeEmphasis(count - i, can_open, can_close), + }); + } + begin_text = ix + count; + } + LoopInstruction::ContinueAndSkip(count - 1) + } + b'`' => { + self.tree.append_text(begin_text, ix); + let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'`'); + self.tree.append(Item { + start: ix, + end: ix + count, + body: ItemBody::MaybeCode(count, false), + }); + begin_text = ix + count; + LoopInstruction::ContinueAndSkip(count - 1) + } + b'<' => { + // Note: could detect some non-HTML cases and early escape here, but not + // clear that's a win. + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeHtml, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'!' => { + if ix + 1 < self.text.len() && bytes[ix + 1] == b'[' { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 2, + body: ItemBody::MaybeImage, + }); + begin_text = ix + 2; + LoopInstruction::ContinueAndSkip(1) + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + b'[' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkOpen, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b']' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkClose, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'&' => match scan_entity(&bytes[ix..]) { + (n, Some(value)) => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + n, + body: ItemBody::SynthesizeText(self.allocs.allocate_cow(value)), + }); + begin_text = ix + n; + LoopInstruction::ContinueAndSkip(n - 1) + } + _ => LoopInstruction::ContinueAndSkip(0), + }, + b'|' => { + if let TableParseMode::Active = mode { + LoopInstruction::BreakAtWith(ix, None) + } else { + last_pipe_ix = ix; + pipes += 1; + LoopInstruction::ContinueAndSkip(0) + } + } + _ => LoopInstruction::ContinueAndSkip(0), + } + }); + + if brk.is_none() { + // need to close text at eof + self.tree.append_text(begin_text, final_ix); + } + (final_ix, brk) + } + + /// Check whether we should allow a paragraph interrupt by lists. Only non-empty + /// lists are allowed. + fn interrupt_paragraph_by_list(&self, suffix: &[u8]) -> bool { + scan_listitem(suffix).map_or(false, |(ix, delim, index, _)| { + self.list_nesting > 0 || + // we don't allow interruption by either empty lists or + // numbered lists starting at an index other than 1 + !scan_empty_list(&suffix[ix..]) && (delim == b'*' || delim == b'-' || index == 1) + }) + } + + /// When start_ix is at the beginning of an HTML block of type 1 to 5, + /// this will find the end of the block, adding the block itself to the + /// tree and also keeping track of the lines of HTML within the block. + /// + /// The html_end_tag is the tag that must be found on a line to end the block. + fn parse_html_block_type_1_to_5( + &mut self, + start_ix: usize, + html_end_tag: &str, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + + if (&self.text[line_start_ix..ix]).contains(html_end_tag) { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + /// When start_ix is at the beginning of an HTML block of type 6 or 7, + /// this will consume lines until there is a blank line and keep track of + /// the HTML within the block. + fn parse_html_block_type_6_or_7( + &mut self, + start_ix: usize, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() || line_start.is_at_eol() { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() || scan_blank_line(&bytes[next_line_ix..]).is_some() + { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + fn parse_indented_code_block(&mut self, start_ix: usize, mut remaining_space: usize) -> usize { + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::IndentCodeBlock, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + let mut last_nonblank_child = None; + let mut last_nonblank_ix = 0; + let mut end_ix = 0; + let mut last_line_blank = false; + + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, line_start_ix, ix); + // TODO(spec clarification): should we synthesize newline at EOF? + + if !last_line_blank { + last_nonblank_child = self.tree.cur(); + last_nonblank_ix = ix; + end_ix = ix; + } + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() + || !(line_start.scan_space(4) || line_start.is_at_eol()) + { + break; + } + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + last_line_blank = scan_blank_line(&bytes[ix..]).is_some(); + } + + // Trim trailing blank lines. + if let Some(child) = last_nonblank_child { + self.tree[child].next = None; + self.tree[child].item.end = last_nonblank_ix; + } + self.pop(end_ix); + ix + } + + fn parse_fenced_code_block( + &mut self, + start_ix: usize, + indent: usize, + fence_ch: u8, + n_fence_char: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut info_start = start_ix + n_fence_char; + info_start += scan_whitespace_no_nl(&bytes[info_start..]); + // TODO: info strings are typically very short. wouldnt it be faster + // to just do a forward scan here? + let mut ix = info_start + scan_nextline(&bytes[info_start..]); + let info_end = ix - scan_rev_while(&bytes[info_start..ix], is_ascii_whitespace); + let info_string = unescape(&self.text[info_start..info_end]); + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::FencedCodeBlock(self.allocs.allocate_cow(info_string)), + }); + self.tree.push(); + loop { + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + line_start.scan_space(indent); + let mut close_line_start = line_start.clone(); + if !close_line_start.scan_space(4) { + let close_ix = ix + close_line_start.bytes_scanned(); + if let Some(n) = scan_closing_code_fence(&bytes[close_ix..], fence_ch, n_fence_char) + { + ix = close_ix + n; + break; + } + } + let remaining_space = line_start.remaining_space(); + ix += line_start.bytes_scanned(); + let next_ix = ix + scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, ix, next_ix); + ix = next_ix; + } + + self.pop(ix); + + // try to read trailing whitespace or it will register as a completely blank line + ix + scan_blank_line(&bytes[ix..]).unwrap_or(0) + } + + fn append_code_text(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append_text(start, end - 2); + self.tree.append_text(end - 1, end); + } else { + self.tree.append_text(start, end); + } + } + + /// Appends a line of HTML to the tree. + fn append_html_line(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + // TODO: maybe this should synthesize to html rather than text? + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append(Item { + start, + end: end - 2, + body: ItemBody::Html, + }); + self.tree.append(Item { + start: end - 1, + end, + body: ItemBody::Html, + }); + } else { + self.tree.append(Item { + start, + end, + body: ItemBody::Html, + }); + } + } + + /// Pop a container, setting its end. + fn pop(&mut self, ix: usize) { + let cur_ix = self.tree.pop().unwrap(); + self.tree[cur_ix].item.end = ix; + if let ItemBody::List(true, _, _) = self.tree[cur_ix].item.body { + surgerize_tight_list(&mut self.tree, cur_ix); + } + } + + /// Close a list if it's open. Also set loose if last line was blank + fn finish_list(&mut self, ix: usize) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(_, _, _) = self.tree[node_ix].item.body { + self.pop(ix); + self.list_nesting -= 1; + } + } + if self.last_line_blank { + if let Some(node_ix) = self.tree.peek_grandparent() { + if let ItemBody::List(ref mut is_tight, _, _) = self.tree[node_ix].item.body { + *is_tight = false; + } + } + self.last_line_blank = false; + } + } + + /// Continue an existing list or start a new one if there's not an open + /// list that matches. + fn continue_list(&mut self, start: usize, ch: u8, index: u64) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(ref mut is_tight, existing_ch, _) = self.tree[node_ix].item.body { + if existing_ch == ch { + if self.last_line_blank { + *is_tight = false; + self.last_line_blank = false; + } + return; + } + } + // TODO: this is not the best choice for end; maybe get end from last list item. + self.finish_list(start); + } + self.tree.append(Item { + start, + end: 0, // will get set later + body: ItemBody::List(true, ch, index), + }); + self.list_nesting += 1; + self.tree.push(); + self.last_line_blank = false; + } + + /// Parse a thematic break. + /// + /// Returns index of start of next line. + fn parse_hrule(&mut self, hrule_size: usize, ix: usize) -> usize { + self.tree.append(Item { + start: ix, + end: ix + hrule_size, + body: ItemBody::Rule, + }); + ix + hrule_size + } + + /// Parse an ATX heading. + /// + /// Returns index of start of next line. + fn parse_atx_heading(&mut self, mut ix: usize, atx_size: usize) -> usize { + let heading_ix = self.tree.append(Item { + start: ix, + end: 0, // set later + body: ItemBody::Heading(atx_size as u32), + }); + ix += atx_size; + // next char is space or eol (guaranteed by scan_atx_heading) + let bytes = self.text.as_bytes(); + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + self.tree[heading_ix].item.end = ix + eol_bytes; + return ix + eol_bytes; + } + // skip leading spaces + let skip_spaces = scan_whitespace_no_nl(&bytes[ix..]); + ix += skip_spaces; + + // now handle the header text + let header_start = ix; + let header_node_idx = self.tree.push(); // so that we can set the endpoint later + ix = self.parse_line(ix, TableParseMode::Disabled).0; + self.tree[header_node_idx].item.end = ix; + + // remove trailing matter from header text + if let Some(cur_ix) = self.tree.cur() { + let header_text = &bytes[header_start..ix]; + let mut limit = header_text + .iter() + .rposition(|&b| !(b == b'\n' || b == b'\r' || b == b' ')) + .map_or(0, |i| i + 1); + let closer = header_text[..limit] + .iter() + .rposition(|&b| b != b'#') + .map_or(0, |i| i + 1); + if closer == 0 { + limit = closer; + } else { + let spaces = scan_rev_while(&header_text[..closer], |b| b == b' '); + if spaces > 0 { + limit = closer - spaces; + } + } + self.tree[cur_ix].item.end = limit + header_start; + } + + self.tree.pop(); + ix + } + + /// Returns the number of bytes scanned on success. + fn parse_footnote(&mut self, start: usize) -> Option { + let bytes = &self.text.as_bytes()[start..]; + if !bytes.starts_with(b"[^") { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 2)?; + i += 2; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + self.finish_list(start); + self.tree.append(Item { + start, + end: 0, // will get set later + // TODO: check whether the label here is strictly necessary + body: ItemBody::FootnoteDefinition(self.allocs.allocate_cow(label)), + }); + self.tree.push(); + Some(i) + } + + /// Tries to parse a reference label, which can be interrupted by new blocks. + /// On success, returns the number of bytes of the label and the label itself. + fn parse_refdef_label(&self, start: usize) -> Option<(usize, CowStr<'a>)> { + scan_link_label_rest(&self.text[start..], &|bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + let bytes_scanned = line_start.bytes_scanned(); + + let suffix = &bytes[bytes_scanned..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + None + } else { + Some(bytes_scanned) + } + }) + } + + /// Returns number of bytes scanned, label and definition on success. + fn parse_refdef_total(&mut self, start: usize) -> Option<(usize, LinkLabel<'a>, LinkDef<'a>)> { + let bytes = &self.text.as_bytes()[start..]; + if scan_ch(bytes, b'[') == 0 { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 1)?; + i += 1; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + let (bytecount, link_def) = self.scan_refdef(start + i)?; + Some((bytecount + i, UniCase::new(label), link_def)) + } + + /// Returns number of bytes and number of newlines + fn scan_refdef_space(&self, bytes: &[u8], mut i: usize) -> Option<(usize, usize)> { + let mut newlines = 0; + loop { + let whitespaces = scan_whitespace_no_nl(&bytes[i..]); + i += whitespaces; + if let Some(eol_bytes) = scan_eol(&bytes[i..]) { + i += eol_bytes; + newlines += 1; + if newlines > 1 { + return None; + } + } else { + break; + } + let mut line_start = LineStart::new(&bytes[i..]); + if self.tree.spine_len() != scan_containers(&self.tree, &mut line_start) { + return None; + } + i += line_start.bytes_scanned(); + } + Some((i, newlines)) + } + + /// Returns # of bytes and definition. + /// Assumes the label of the reference including colon has already been scanned. + fn scan_refdef(&self, start: usize) -> Option<(usize, LinkDef<'a>)> { + let bytes = self.text.as_bytes(); + + // whitespace between label and url (including up to one newline) + let (mut i, _newlines) = self.scan_refdef_space(bytes, start)?; + + // scan link dest + let (dest_length, dest) = scan_link_dest(self.text, i, 1)?; + if dest_length == 0 { + return None; + } + let dest = unescape(dest); + i += dest_length; + + // no title + let mut backup = (i - start, LinkDef { dest, title: None }); + + // scan whitespace between dest and label + let (mut i, newlines) = + if let Some((new_i, mut newlines)) = self.scan_refdef_space(bytes, i) { + if i == self.text.len() { + newlines += 1; + } + if new_i == i && newlines == 0 { + return None; + } + if newlines > 1 { + return Some(backup); + }; + (new_i, newlines) + } else { + return Some(backup); + }; + + // scan title + // if this fails but newline == 1, return also a refdef without title + if let Some((title_length, title)) = scan_refdef_title(&self.text[i..]) { + i += title_length; + backup.1.title = Some(unescape(title)); + } else if newlines > 0 { + return Some(backup); + } else { + return None; + }; + + // scan EOL + if let Some(bytes) = scan_blank_line(&bytes[i..]) { + backup.0 = i + bytes - start; + Some(backup) + } else if newlines > 0 { + Some(backup) + } else { + None + } + } +} + +/// Returns number of containers scanned. +fn scan_containers(tree: &Tree, line_start: &mut LineStart) -> usize { + let mut i = 0; + for &node_ix in tree.walk_spine() { + match tree[node_ix].item.body { + ItemBody::BlockQuote => { + let save = line_start.clone(); + if !line_start.scan_blockquote_marker() { + *line_start = save; + break; + } + } + ItemBody::ListItem(indent) => { + let save = line_start.clone(); + if !line_start.scan_space(indent) { + if !line_start.is_at_eol() { + *line_start = save; + break; + } + } + } + _ => (), + } + i += 1; + } + i +} + +/// Computes the number of header columns in a table line by computing the number of dividing pipes +/// that aren't followed or preceeded by whitespace. +fn count_header_cols( + bytes: &[u8], + mut pipes: usize, + mut start: usize, + last_pipe_ix: usize, +) -> usize { + // was first pipe preceeded by whitespace? if so, subtract one + start += scan_whitespace_no_nl(&bytes[start..]); + if bytes[start] == b'|' { + pipes -= 1; + } + + // was last pipe followed by whitespace? if so, sub one + if scan_blank_line(&bytes[(last_pipe_ix + 1)..]).is_some() { + pipes + } else { + pipes + 1 + } +} + +impl<'a> Tree { + fn append_text(&mut self, start: usize, end: usize) { + if end > start { + if let Some(ix) = self.cur() { + if ItemBody::Text == self[ix].item.body && self[ix].item.end == start { + self[ix].item.end = end; + return; + } + } + self.append(Item { + start, + end, + body: ItemBody::Text, + }); + } + } +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims). +/// suffix is &s[ix..], which is passed in as an optimization, since taking +/// a string subslice is O(n). +fn delim_run_can_open(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return false; + }; + if next_char.is_whitespace() { + return false; + } + if ix == 0 { + return true; + } + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(next_char) { + return true; + } + + let prev_char = s[..ix].chars().last().unwrap(); + + prev_char.is_whitespace() || is_punctuation(prev_char) +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims) +fn delim_run_can_close(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + if ix == 0 { + return false; + } + let prev_char = s[..ix].chars().last().unwrap(); + if prev_char.is_whitespace() { + return false; + } + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return true; + }; + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(prev_char) { + return true; + } + + next_char.is_whitespace() || is_punctuation(next_char) +} + +/// Checks whether we should break a paragraph on the given input. +/// Note: lists are dealt with in `interrupt_paragraph_by_list`, because determing +/// whether to break on a list requires additional context. +fn scan_paragraph_interrupt(bytes: &[u8]) -> bool { + if scan_eol(bytes).is_some() + || scan_hrule(bytes).is_ok() + || scan_atx_heading(bytes).is_some() + || scan_code_fence(bytes).is_some() + || scan_blockquote_start(bytes).is_some() + { + return true; + } + bytes.starts_with(b"<") + && (get_html_end_tag(&bytes[1..]).is_some() + || is_html_tag(scan_html_block_tag(&bytes[1..]).1)) +} + +/// Assumes `text_bytes` is preceded by `<`. +fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> { + static BEGIN_TAGS: &[&[u8]; 3] = &[b"pre", b"style", b"script"]; + static ST_BEGIN_TAGS: &[&[u8]; 3] = &[b"!--", b"?", b"![CDATA["]; + + for (beg_tag, end_tag) in BEGIN_TAGS + .iter() + .zip(["", "", ""].iter()) + { + let tag_len = beg_tag.len(); + + if text_bytes.len() < tag_len { + // begin tags are increasing in size + break; + } + + if !text_bytes[..tag_len].eq_ignore_ascii_case(beg_tag) { + continue; + } + + // Must either be the end of the line... + if text_bytes.len() == tag_len { + return Some(end_tag); + } + + // ...or be followed by whitespace, newline, or '>'. + let s = text_bytes[tag_len]; + if is_ascii_whitespace(s) || s == b'>' { + return Some(end_tag); + } + } + + for (beg_tag, end_tag) in ST_BEGIN_TAGS.iter().zip(["-->", "?>", "]]>"].iter()) { + if text_bytes.starts_with(beg_tag) { + return Some(end_tag); + } + } + + if text_bytes.len() > 1 + && text_bytes[0] == b'!' + && text_bytes[1] >= b'A' + && text_bytes[1] <= b'Z' + { + Some(">") + } else { + None + } +} + +#[derive(Copy, Clone, Debug)] +struct InlineEl { + start: TreeIndex, // offset of tree node + count: usize, + c: u8, // b'*' or b'_' + both: bool, // can both open and close +} + +#[derive(Debug, Clone, Default)] +struct InlineStack { + stack: Vec, + // Lower bounds for matching indices in the stack. For example + // a strikethrough delimiter will never match with any element + // in the stack with index smaller than + // `lower_bounds[InlineStack::TILDES]`. + lower_bounds: [usize; 7], +} + +impl InlineStack { + /// These are indices into the lower bounds array. + /// Not both refers to the property that the delimiter can not both + /// be opener as a closer. + const UNDERSCORE_NOT_BOTH: usize = 0; + const ASTERISK_NOT_BOTH: usize = 1; + const ASTERISK_BASE: usize = 2; + const TILDES: usize = 5; + const UNDERSCORE_BOTH: usize = 6; + + fn pop_all(&mut self, tree: &mut Tree) { + for el in self.stack.drain(..) { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.lower_bounds = [0; 7]; + } + + fn get_lowerbound(&self, c: u8, count: usize, both: bool) -> usize { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] + } + } else if c == b'*' { + let mod3_lower = self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3]; + if both { + mod3_lower + } else { + min( + mod3_lower, + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH], + ) + } + } else { + self.lower_bounds[InlineStack::TILDES] + } + } + + fn set_lowerbound(&mut self, c: u8, count: usize, both: bool, new_bound: usize) { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] = new_bound; + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] = new_bound; + } + } else if c == b'*' { + self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3] = new_bound; + if !both { + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH] = new_bound; + } + } else { + self.lower_bounds[InlineStack::TILDES] = new_bound; + } + } + + fn find_match( + &mut self, + tree: &mut Tree, + c: u8, + count: usize, + both: bool, + ) -> Option { + let lowerbound = min(self.stack.len(), self.get_lowerbound(c, count, both)); + let res = self.stack[lowerbound..] + .iter() + .cloned() + .enumerate() + .rfind(|(_, el)| { + el.c == c && (!both && !el.both || (count + el.count) % 3 != 0 || count % 3 == 0) + }); + + if let Some((matching_ix, matching_el)) = res { + let matching_ix = matching_ix + lowerbound; + for el in &self.stack[(matching_ix + 1)..] { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.stack.truncate(matching_ix); + Some(matching_el) + } else { + self.set_lowerbound(c, count, both, self.stack.len()); + None + } + } + + fn push(&mut self, el: InlineEl) { + self.stack.push(el) + } +} + +#[derive(Debug, Clone)] +enum RefScan<'a> { + // label, next node index, source ix of label end + LinkLabel(CowStr<'a>, Option, usize), + // contains next node index + Collapsed(Option), + Failed, +} + +/// Skips forward within a block to a node which spans (ends inclusive) the given +/// index into the source. +fn scan_nodes_to_ix( + tree: &Tree, + mut node: Option, + ix: usize, +) -> Option { + while let Some(node_ix) = node { + if tree[node_ix].item.end <= ix { + node = tree[node_ix].next; + } else { + break; + } + } + node +} + +/// Scans an inline link label, which cannot be interrupted. +/// Returns number of bytes (including brackets) and label on success. +fn scan_link_label<'text, 'tree>( + tree: &'tree Tree, + text: &'text str, +) -> Option<(usize, ReferenceLabel<'text>)> { + let bytes = &text.as_bytes(); + if bytes.len() < 2 || bytes[0] != b'[' { + return None; + } + let linebreak_handler = |bytes: &[u8]| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(tree, &mut line_start); + Some(line_start.bytes_scanned()) + }; + let pair = if b'^' == bytes[1] { + let (byte_index, cow) = scan_link_label_rest(&text[2..], &linebreak_handler)?; + (byte_index + 2, ReferenceLabel::Footnote(cow)) + } else { + let (byte_index, cow) = scan_link_label_rest(&text[1..], &linebreak_handler)?; + (byte_index + 1, ReferenceLabel::Link(cow)) + }; + Some(pair) +} + +fn scan_reference<'a, 'b>( + tree: &'a Tree, + text: &'b str, + cur: Option, +) -> RefScan<'b> { + let cur_ix = match cur { + None => return RefScan::Failed, + Some(cur_ix) => cur_ix, + }; + let start = tree[cur_ix].item.start; + let tail = &text.as_bytes()[start..]; + + if tail.starts_with(b"[]") { + let closing_node = tree[cur_ix].next.unwrap(); + RefScan::Collapsed(tree[closing_node].next) + } else if let Some((ix, ReferenceLabel::Link(label))) = scan_link_label(tree, &text[start..]) { + let next_node = scan_nodes_to_ix(tree, cur, start + ix); + RefScan::LinkLabel(label, next_node, start + ix) + } else { + RefScan::Failed + } +} + +#[derive(Clone, Default)] +struct LinkStack { + inner: Vec, + disabled_ix: usize, +} + +impl LinkStack { + fn push(&mut self, el: LinkStackEl) { + self.inner.push(el); + } + + fn pop(&mut self) -> Option { + let el = self.inner.pop(); + self.disabled_ix = std::cmp::min(self.disabled_ix, self.inner.len()); + el + } + + fn clear(&mut self) { + self.inner.clear(); + self.disabled_ix = 0; + } + + fn disable_all_links(&mut self) { + for el in &mut self.inner[self.disabled_ix..] { + if el.ty == LinkStackTy::Link { + el.ty = LinkStackTy::Disabled; + } + } + self.disabled_ix = self.inner.len(); + } +} + +#[derive(Clone, Debug)] +struct LinkStackEl { + node: TreeIndex, + ty: LinkStackTy, +} + +#[derive(PartialEq, Clone, Debug)] +enum LinkStackTy { + Link, + Image, + Disabled, +} + +#[derive(Clone)] +struct LinkDef<'a> { + dest: CowStr<'a>, + title: Option>, +} + +/// Tracks tree indices of code span delimiters of each length. It should prevent +/// quadratic scanning behaviours by providing (amortized) constant time lookups. +struct CodeDelims { + inner: HashMap>, + seen_first: bool, +} + +impl CodeDelims { + fn new() -> Self { + Self { + inner: Default::default(), + seen_first: false, + } + } + + fn insert(&mut self, count: usize, ix: TreeIndex) { + if self.seen_first { + self.inner + .entry(count) + .or_insert_with(Default::default) + .push_back(ix); + } else { + // Skip the first insert, since that delimiter will always + // be an opener and not a closer. + self.seen_first = true; + } + } + + fn is_populated(&self) -> bool { + !self.inner.is_empty() + } + + fn find(&mut self, open_ix: TreeIndex, count: usize) -> Option { + while let Some(ix) = self.inner.get_mut(&count)?.pop_front() { + if ix > open_ix { + return Some(ix); + } + } + None + } + + fn clear(&mut self) { + self.inner.clear(); + self.seen_first = false; + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct LinkIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct CowIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct AlignmentIndex(usize); + +#[derive(Clone)] +struct Allocations<'a> { + refdefs: HashMap, LinkDef<'a>>, + links: Vec<(LinkType, CowStr<'a>, CowStr<'a>)>, + cows: Vec>, + alignments: Vec>, +} + +impl<'a> Allocations<'a> { + fn new() -> Self { + Self { + refdefs: HashMap::new(), + links: Vec::with_capacity(128), + cows: Vec::new(), + alignments: Vec::new(), + } + } + + fn allocate_cow(&mut self, cow: CowStr<'a>) -> CowIndex { + let ix = self.cows.len(); + self.cows.push(cow); + CowIndex(ix) + } + + fn allocate_link(&mut self, ty: LinkType, url: CowStr<'a>, title: CowStr<'a>) -> LinkIndex { + let ix = self.links.len(); + self.links.push((ty, url, title)); + LinkIndex(ix) + } + + fn allocate_alignment(&mut self, alignment: Vec) -> AlignmentIndex { + let ix = self.alignments.len(); + self.alignments.push(alignment); + AlignmentIndex(ix) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = CowStr<'a>; + + fn index(&self, ix: CowIndex) -> &Self::Output { + self.cows.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = (LinkType, CowStr<'a>, CowStr<'a>); + + fn index(&self, ix: LinkIndex) -> &Self::Output { + self.links.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = Vec; + + fn index(&self, ix: AlignmentIndex) -> &Self::Output { + self.alignments.index(ix.0) + } +} + +/// A struct containing information on the reachability of certain inline HTML +/// elements. In particular, for cdata elements (` { + text: &'a str, + tree: Tree, + allocs: Allocations<'a>, + broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, + html_scan_guard: HtmlScanGuard, + + // used by inline passes. store them here for reuse + inline_stack: InlineStack, + link_stack: LinkStack, +} + +impl<'a> Parser<'a> { + /// Creates a new event iterator for a markdown string without any options enabled. + pub fn new(text: &'a str) -> Parser<'a> { + Parser::new_ext(text, Options::empty()) + } + + /// Creates a new event iterator for a markdown string with given options. + pub fn new_ext(text: &'a str, options: Options) -> Parser<'a> { + Parser::new_with_broken_link_callback(text, options, None) + } + + /// In case the parser encounters any potential links that have a broken + /// reference (e.g `[foo]` when there is no `[foo]: ` entry at the bottom) + /// the provided callback will be called with the reference name, + /// and the returned pair will be used as the link name and title if it is not + /// `None`. + pub fn new_with_broken_link_callback( + text: &'a str, + options: Options, + broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, + ) -> Parser<'a> { + let first_pass = FirstPass::new(text, options); + let (mut tree, allocs) = first_pass.run(); + tree.reset(); + let inline_stack = Default::default(); + let link_stack = Default::default(); + let html_scan_guard = Default::default(); + Parser { + text, + tree, + allocs, + broken_link_callback, + inline_stack, + link_stack, + html_scan_guard, + } + } + + /// Handle inline markup. + /// + /// When the parser encounters any item indicating potential inline markup, all + /// inline markup passes are run on the remainder of the chain. + /// + /// Note: there's some potential for optimization here, but that's future work. + fn handle_inline(&mut self) { + self.handle_inline_pass1(); + self.handle_emphasis(); + } + + /// Handle inline HTML, code spans, and links. + /// + /// This function handles both inline HTML and code spans, because they have + /// the same precedence. It also handles links, even though they have lower + /// precedence, because the URL of links must not be processed. + fn handle_inline_pass1(&mut self) { + let mut code_delims = CodeDelims::new(); + let mut cur = self.tree.cur(); + let mut prev = None; + + let block_end = self.tree[self.tree.peek_up().unwrap()].item.end; + let block_text = &self.text[..block_end]; + + while let Some(mut cur_ix) = cur { + match self.tree[cur_ix].item.body { + ItemBody::MaybeHtml => { + let next = self.tree[cur_ix].next; + let autolink = if let Some(next_ix) = next { + scan_autolink(block_text, self.tree[next_ix].item.start) + } else { + None + }; + + if let Some((ix, uri, link_type)) = autolink { + let node = scan_nodes_to_ix(&self.tree, next, ix); + let text_node = self.tree.create_node(Item { + start: self.tree[cur_ix].item.start + 1, + end: ix - 1, + body: ItemBody::Text, + }); + let link_ix = self.allocs.allocate_link(link_type, uri, "".into()); + self.tree[cur_ix].item.body = ItemBody::Link(link_ix); + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + self.tree[cur_ix].child = Some(text_node); + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = max(self.tree[node_ix].item.start, ix); + } + continue; + } else { + let inline_html = if let Some(next_ix) = next { + self.scan_inline_html( + block_text.as_bytes(), + self.tree[next_ix].item.start, + ) + } else { + None + }; + if let Some(ix) = inline_html { + let node = scan_nodes_to_ix(&self.tree, next, ix); + self.tree[cur_ix].item.body = ItemBody::Html; + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = + max(self.tree[node_ix].item.start, ix); + } + continue; + } + } + self.tree[cur_ix].item.body = ItemBody::Text; + } + ItemBody::MaybeCode(mut search_count, preceded_by_backslash) => { + if preceded_by_backslash { + search_count -= 1; + if search_count == 0 { + self.tree[cur_ix].item.body = ItemBody::Text; + prev = cur; + cur = self.tree[cur_ix].next; + continue; + } + } + + if code_delims.is_populated() { + // we have previously scanned all codeblock delimiters, + // so we can reuse that work + if let Some(scan_ix) = code_delims.find(cur_ix, search_count) { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + } else { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } else { + // we haven't previously scanned all codeblock delimiters, + // so walk the AST + let mut scan = if search_count > 0 { + self.tree[cur_ix].next + } else { + None + }; + while let Some(scan_ix) = scan { + if let ItemBody::MaybeCode(delim_count, _) = + self.tree[scan_ix].item.body + { + if search_count == delim_count { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + code_delims.clear(); + break; + } else { + code_delims.insert(delim_count, scan_ix); + } + } + scan = self.tree[scan_ix].next; + } + if scan == None { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } + } + ItemBody::MaybeLinkOpen => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Link, + }); + } + ItemBody::MaybeImage => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Image, + }); + } + ItemBody::MaybeLinkClose => { + self.tree[cur_ix].item.body = ItemBody::Text; + if let Some(tos) = self.link_stack.pop() { + if tos.ty == LinkStackTy::Disabled { + continue; + } + let next = self.tree[cur_ix].next; + if let Some((next_ix, url, title)) = + self.scan_inline_link(block_text, self.tree[cur_ix].item.end, next) + { + let next_node = scan_nodes_to_ix(&self.tree, next, next_ix); + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + cur = Some(tos.node); + cur_ix = tos.node; + let link_ix = self.allocs.allocate_link(LinkType::Inline, url, title); + self.tree[cur_ix].item.body = if tos.ty == LinkStackTy::Image { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + self.tree[cur_ix].child = self.tree[cur_ix].next; + self.tree[cur_ix].next = next_node; + self.tree[cur_ix].item.end = next_ix; + if let Some(next_node_ix) = next_node { + self.tree[next_node_ix].item.start = + max(self.tree[next_node_ix].item.start, next_ix); + } + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } else { + // ok, so its not an inline link. maybe it is a reference + // to a defined link? + let scan_result = scan_reference(&self.tree, block_text, next); + let (node_after_link, link_type) = match scan_result { + // [label][reference] + RefScan::LinkLabel(_, next_node, _) => { + (next_node, LinkType::Reference) + } + // [] + RefScan::Collapsed(next_node) => (next_node, LinkType::Collapsed), + // [shortcut] + // + // [shortcut]: /blah + RefScan::Failed => (next, LinkType::Shortcut), + }; + + // (label, source_ix end) + let label: Option<(ReferenceLabel<'a>, usize)> = match scan_result { + RefScan::LinkLabel(l, _, end_ix) => { + Some((ReferenceLabel::Link(l), end_ix)) + } + RefScan::Collapsed(..) | RefScan::Failed => { + // No label? maybe it is a shortcut reference + let label_start = self.tree[tos.node].item.end - 1; + scan_link_label( + &self.tree, + &self.text[label_start..self.tree[cur_ix].item.end], + ) + .map(|(ix, label)| (label, label_start + ix)) + } + }; + + // see if it's a footnote reference + if let Some((ReferenceLabel::Footnote(l), end)) = label { + self.tree[tos.node].next = node_after_link; + self.tree[tos.node].child = None; + self.tree[tos.node].item.body = + ItemBody::FootnoteReference(self.allocs.allocate_cow(l)); + self.tree[tos.node].item.end = end; + prev = Some(tos.node); + cur = node_after_link; + self.link_stack.clear(); + continue; + } else if let Some((ReferenceLabel::Link(link_label), end)) = label { + let type_url_title = self + .allocs + .refdefs + .get(&UniCase::new(link_label.as_ref().into())) + .map(|matching_def| { + // found a matching definition! + let title = matching_def + .title + .as_ref() + .cloned() + .unwrap_or_else(|| "".into()); + let url = matching_def.dest.clone(); + (link_type, url, title) + }) + .or_else(|| { + self.broken_link_callback + .and_then(|callback| { + // looked for matching definition, but didn't find it. try to fix + // link with callback, if it is defined + callback(link_label.as_ref(), link_label.as_ref()) + }) + .map(|(url, title)| { + (link_type.to_unknown(), url.into(), title.into()) + }) + }); + + if let Some((def_link_type, url, title)) = type_url_title { + let link_ix = + self.allocs.allocate_link(def_link_type, url, title); + self.tree[tos.node].item.body = if tos.ty == LinkStackTy::Image + { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + let label_node = self.tree[tos.node].next; + + // lets do some tree surgery to add the link to the tree + // 1st: skip the label node and close node + self.tree[tos.node].next = node_after_link; + + // then, if it exists, add the label node as a child to the link node + if label_node != cur { + self.tree[tos.node].child = label_node; + + // finally: disconnect list of children + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + } + + self.tree[tos.node].item.end = end; + + // set up cur so next node will be node_after_link + cur = Some(tos.node); + cur_ix = tos.node; + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } + } + } + } + } + _ => (), + } + prev = cur; + cur = self.tree[cur_ix].next; + } + self.link_stack.clear(); + } + + fn handle_emphasis(&mut self) { + let mut prev = None; + let mut prev_ix: TreeIndex; + let mut cur = self.tree.cur(); + while let Some(mut cur_ix) = cur { + if let ItemBody::MaybeEmphasis(mut count, can_open, can_close) = + self.tree[cur_ix].item.body + { + let c = self.text.as_bytes()[self.tree[cur_ix].item.start]; + let both = can_open && can_close; + if can_close { + while let Some(el) = + self.inline_stack.find_match(&mut self.tree, c, count, both) + { + // have a match! + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + let match_count = min(count, el.count); + // start, end are tree node indices + let mut end = cur_ix - 1; + let mut start = el.start + el.count; + + // work from the inside out + while start > el.start + el.count - match_count { + let (inc, ty) = if c == b'~' { + (2, ItemBody::Strikethrough) + } else if start > el.start + el.count - match_count + 1 { + (2, ItemBody::Strong) + } else { + (1, ItemBody::Emphasis) + }; + + let root = start - inc; + end = end + inc; + self.tree[root].item.body = ty; + self.tree[root].item.end = self.tree[end].item.end; + self.tree[root].child = Some(start); + self.tree[root].next = None; + start = root; + } + + // set next for top most emph level + prev_ix = el.start + el.count - match_count; + prev = Some(prev_ix); + cur = self.tree[cur_ix + match_count - 1].next; + self.tree[prev_ix].next = cur; + + if el.count > match_count { + self.inline_stack.push(InlineEl { + start: el.start, + count: el.count - match_count, + c: el.c, + both, + }) + } + count -= match_count; + if count > 0 { + cur_ix = cur.unwrap(); + } else { + break; + } + } + } + if count > 0 { + if can_open { + self.inline_stack.push(InlineEl { + start: cur_ix, + count, + c, + both, + }); + } else { + for i in 0..count { + self.tree[cur_ix + i].item.body = ItemBody::Text; + } + } + prev_ix = cur_ix + count - 1; + prev = Some(prev_ix); + cur = self.tree[prev_ix].next; + } + } else { + prev = cur; + cur = self.tree[cur_ix].next; + } + } + self.inline_stack.pop_all(&mut self.tree); + } + + /// Returns next byte index, url and title. + fn scan_inline_link( + &self, + underlying: &'a str, + mut ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>, CowStr<'a>)> { + if scan_ch(&underlying.as_bytes()[ix..], b'(') == 0 { + return None; + } + ix += 1; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let (dest_length, dest) = scan_link_dest(underlying, ix, LINK_MAX_NESTED_PARENS)?; + let dest = unescape(dest); + ix += dest_length; + + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let title = if let Some((bytes_scanned, t)) = self.scan_link_title(underlying, ix, node) { + ix += bytes_scanned; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + t + } else { + "".into() + }; + if scan_ch(&underlying.as_bytes()[ix..], b')') == 0 { + return None; + } + ix += 1; + + Some((ix, dest, title)) + } + + // returns (bytes scanned, title cow) + fn scan_link_title( + &self, + text: &'a str, + start_ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>)> { + let bytes = text.as_bytes(); + let open = match bytes.get(start_ix) { + Some(b @ b'\'') | Some(b @ b'\"') | Some(b @ b'(') => *b, + _ => return None, + }; + let close = if open == b'(' { b')' } else { open }; + + let mut title = String::new(); + let mut mark = start_ix + 1; + let mut i = start_ix + 1; + + while i < bytes.len() { + let c = bytes[i]; + + if c == close { + let cow = if mark == 1 { + (i - start_ix + 1, text[mark..i].into()) + } else { + title.push_str(&text[mark..i]); + (i - start_ix + 1, title.into()) + }; + + return Some(cow); + } + if c == open { + return None; + } + + if c == b'\n' || c == b'\r' { + if let Some(node_ix) = scan_nodes_to_ix(&self.tree, node, i + 1) { + if self.tree[node_ix].item.start > i { + title.push_str(&text[mark..i]); + title.push('\n'); + i = self.tree[node_ix].item.start; + mark = i; + continue; + } + } + } + if c == b'&' { + if let (n, Some(value)) = scan_entity(&bytes[i..]) { + title.push_str(&text[mark..i]); + title.push_str(&value); + i += n; + mark = i; + continue; + } + } + if c == b'\\' && i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) { + title.push_str(&text[mark..i]); + i += 1; + mark = i; + } + + i += 1; + } + + None + } + + /// Make a code span. + /// + /// Both `open` and `close` are matching MaybeCode items. + fn make_code_span(&mut self, open: TreeIndex, close: TreeIndex, preceding_backslash: bool) { + let first_ix = open + 1; + let last_ix = close - 1; + let bytes = self.text.as_bytes(); + let mut span_start = self.tree[open].item.end; + let mut span_end = self.tree[close].item.start; + let mut buf: Option = None; + + // detect all-space sequences, since they are kept as-is as of commonmark 0.29 + if !bytes[span_start..span_end].iter().all(|&b| b == b' ') { + let opening = match bytes[span_start] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let closing = match bytes[span_end - 1] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let drop_enclosing_whitespace = opening && closing; + + if drop_enclosing_whitespace { + span_start += 1; + if span_start < span_end { + span_end -= 1; + } + } + + let mut ix = first_ix; + + while ix < close { + if let ItemBody::HardBreak | ItemBody::SoftBreak = self.tree[ix].item.body { + if drop_enclosing_whitespace { + // check whether break should be ignored + if ix == first_ix { + ix = ix + 1; + span_start = min(span_end, self.tree[ix].item.start); + continue; + } else if ix == last_ix && last_ix > first_ix { + ix = ix + 1; + continue; + } + } + + let end = bytes[self.tree[ix].item.start..] + .iter() + .position(|&b| b == b'\r' || b == b'\n') + .unwrap() + + self.tree[ix].item.start; + if let Some(ref mut buf) = buf { + buf.push_str(&self.text[self.tree[ix].item.start..end]); + buf.push(' '); + } else { + let mut new_buf = String::with_capacity(span_end - span_start); + new_buf.push_str(&self.text[span_start..end]); + new_buf.push(' '); + buf = Some(new_buf); + } + } else if let Some(ref mut buf) = buf { + let end = if ix == last_ix { + span_end + } else { + self.tree[ix].item.end + }; + buf.push_str(&self.text[self.tree[ix].item.start..end]); + } + ix = ix + 1; + } + } + + let cow = if let Some(buf) = buf { + buf.into() + } else { + self.text[span_start..span_end].into() + }; + if preceding_backslash { + self.tree[open].item.body = ItemBody::Text; + self.tree[open].item.end = self.tree[open].item.start + 1; + self.tree[open].next = Some(close); + self.tree[close].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[close].item.start = self.tree[open].item.start + 1; + } else { + self.tree[open].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[open].item.end = self.tree[close].item.end; + self.tree[open].next = self.tree[close].next; + } + } + + /// Returns the next byte offset on success. + fn scan_inline_html(&mut self, bytes: &[u8], ix: usize) -> Option { + let c = *bytes.get(ix)?; + if c == b'!' { + scan_inline_html_comment(bytes, ix + 1, &mut self.html_scan_guard) + } else if c == b'?' { + scan_inline_html_processing(bytes, ix + 1, &mut self.html_scan_guard) + } else { + let i = scan_html_block_inner( + &bytes[ix..], + Some(&|_bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + line_start.bytes_scanned() + }), + )?; + Some(i + ix) + } + } + + /// Consumes the event iterator and produces an iterator that produces + /// `(Event, Range)` pairs, where the `Range` value maps to the corresponding + /// range in the markdown source. + pub fn into_offset_iter(self) -> OffsetIter<'a> { + OffsetIter { inner: self } + } +} + +pub(crate) enum LoopInstruction { + /// Continue looking for more special bytes, but skip next few bytes. + ContinueAndSkip(usize), + /// Break looping immediately, returning with the given index and value. + BreakAtWith(usize, T), +} + +/// This function walks the byte slices from the given index and +/// calls the callback function on all bytes (and their indices) that are in the following set: +/// `` ` ``, `\`, `&`, `*`, `_`, `~`, `!`, `<`, `[`, `]`, `|`, `\r`, `\n` +/// It is guaranteed not call the callback on other bytes. +/// Whenever `callback(ix, byte)` returns a `ContinueAndSkip(n)` value, the callback +/// will not be called with an index that is less than `ix + n + 1`. +/// When the callback returns a `BreakAtWith(end_ix, opt+val)`, no more callbacks will be +/// called and the function returns immediately with the return value `(end_ix, opt_val)`. +/// If `BreakAtWith(..)` is never returned, this function will return the first +/// index that is outside the byteslice bound and a `None` value. +fn iterate_special_bytes(bytes: &[u8], ix: usize, callback: F) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + crate::simd::iterate_special_bytes(bytes, ix, callback) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + scalar_iterate_special_bytes(bytes, ix, callback) + } +} + +const fn special_bytes() -> [bool; 256] { + let mut bytes = [false; 256]; + bytes[b'<' as usize] = true; + bytes[b'!' as usize] = true; + bytes[b'[' as usize] = true; + bytes[b'~' as usize] = true; + bytes[b'`' as usize] = true; + bytes[b'|' as usize] = true; + bytes[b'\\' as usize] = true; + bytes[b'*' as usize] = true; + bytes[b'_' as usize] = true; + bytes[b'\r' as usize] = true; + bytes[b'\n' as usize] = true; + bytes[b']' as usize] = true; + bytes[b'&' as usize] = true; + bytes +} + +pub(crate) fn scalar_iterate_special_bytes( + bytes: &[u8], + mut ix: usize, + mut callback: F, +) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + let special_bytes = special_bytes(); + + while ix < bytes.len() { + let b = bytes[ix]; + if special_bytes[b as usize] { + match callback(ix, b) { + LoopInstruction::ContinueAndSkip(skip) => { + ix += skip; + } + LoopInstruction::BreakAtWith(ix, val) => { + return (ix, val); + } + } + } + ix += 1; + } + + (ix, None) +} + +/// Markdown event and source range iterator. +/// +/// Generates tuples where the first element is the markdown event and the second +/// is a the corresponding range in the source string. +/// +/// Constructed from a `Parser` using its +/// [`into_offset_iter`](struct.Parser.html#method.into_offset_iter) method. +pub struct OffsetIter<'a> { + inner: Parser<'a>, +} + +impl<'a> Iterator for OffsetIter<'a> { + type Item = (Event<'a>, Range); + + fn next(&mut self) -> Option { + match self.inner.tree.cur() { + None => { + let ix = self.inner.tree.pop()?; + let tag = item_to_tag(&self.inner.tree[ix].item, &self.inner.allocs); + self.inner.tree.next_sibling(ix); + Some(( + Event::End(tag), + self.inner.tree[ix].item.start..self.inner.tree[ix].item.end, + )) + } + Some(cur_ix) => { + if self.inner.tree[cur_ix].item.body.is_inline() { + self.inner.handle_inline(); + } + + let node = self.inner.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.inner.text, &self.inner.allocs); + if let Event::Start(..) = event { + self.inner.tree.push(); + } else { + self.inner.tree.next_sibling(cur_ix); + } + Some((event, item.start..item.end)) + } + } + } +} + +fn item_to_tag<'a>(item: &Item, allocs: &Allocations<'a>) -> Tag<'a> { + match item.body { + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + } +} + +fn item_to_event<'a>(item: Item, text: &'a str, allocs: &Allocations<'a>) -> Event<'a> { + let tag = match item.body { + ItemBody::Text => return Event::Text(text[item.start..item.end].into()), + ItemBody::Code(cow_ix) => return Event::Code(allocs[cow_ix].clone()), + ItemBody::SynthesizeText(cow_ix) => return Event::Text(allocs[cow_ix].clone()), + ItemBody::Html => return Event::Html(text[item.start..item.end].into()), + ItemBody::SoftBreak => return Event::SoftBreak, + ItemBody::HardBreak => return Event::HardBreak, + ItemBody::FootnoteReference(cow_ix) => { + return Event::FootnoteReference(allocs[cow_ix].clone()) + } + ItemBody::TaskListMarker(checked) => return Event::TaskListMarker(checked), + ItemBody::Rule => return Event::Rule, + + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + }; + + Event::Start(tag) +} + +// https://english.stackexchange.com/a/285573 +fn surgerize_tight_list(tree: &mut Tree, list_ix: TreeIndex) { + let mut list_item = tree[list_ix].child; + while let Some(listitem_ix) = list_item { + // first child is special, controls how we repoint list_item.child + let list_item_firstborn = tree[listitem_ix].child; + + // Check that list item has children - this is not necessarily the case! + if let Some(firstborn_ix) = list_item_firstborn { + if let ItemBody::Paragraph = tree[firstborn_ix].item.body { + tree[listitem_ix].child = tree[firstborn_ix].child; + } + + let mut list_item_child = Some(firstborn_ix); + let mut node_to_repoint = None; + while let Some(child_ix) = list_item_child { + // surgerize paragraphs + let repoint_ix = if let ItemBody::Paragraph = tree[child_ix].item.body { + if let Some(child_firstborn) = tree[child_ix].child { + if let Some(repoint_ix) = node_to_repoint { + tree[repoint_ix].next = Some(child_firstborn); + } + let mut child_lastborn = child_firstborn; + while let Some(lastborn_next_ix) = tree[child_lastborn].next { + child_lastborn = lastborn_next_ix; + } + child_lastborn + } else { + child_ix + } + } else { + child_ix + }; + + node_to_repoint = Some(repoint_ix); + tree[repoint_ix].next = tree[child_ix].next; + list_item_child = tree[child_ix].next; + } + } + + list_item = tree[listitem_ix].next; + } +} + +impl<'a> Iterator for Parser<'a> { + type Item = Event<'a>; + + fn next(&mut self) -> Option> { + match self.tree.cur() { + None => { + let ix = self.tree.pop()?; + let tag = item_to_tag(&self.tree[ix].item, &self.allocs); + self.tree.next_sibling(ix); + Some(Event::End(tag)) + } + Some(cur_ix) => { + if self.tree[cur_ix].item.body.is_inline() { + self.handle_inline(); + } + + let node = self.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.text, &self.allocs); + if let Event::Start(..) = event { + self.tree.push(); + } else { + self.tree.next_sibling(cur_ix); + } + Some(event) + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::tree::Node; + + // TODO: move these tests to tests/html.rs? + + fn parser_with_extensions(text: &str) -> Parser<'_> { + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + + Parser::new_ext(text, opts) + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn node_size() { + let node_size = std::mem::size_of::>(); + assert_eq!(48, node_size); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn body_size() { + let body_size = std::mem::size_of::(); + assert_eq!(16, body_size); + } + + #[test] + fn single_open_fish_bracket() { + // dont crash + assert_eq!(3, Parser::new("<").count()); + } + + #[test] + fn lone_hashtag() { + // dont crash + assert_eq!(2, Parser::new("#").count()); + } + + #[test] + fn lots_of_backslashes() { + // dont crash + Parser::new("\\\\\r\r").count(); + Parser::new("\\\r\r\\.\\\\\r\r\\.\\").count(); + } + + #[test] + fn issue_320() { + // dont crash + parser_with_extensions(":\r\t> |\r:\r\t> |\r").count(); + } + + #[test] + fn issue_319() { + // dont crash + parser_with_extensions("|\r-]([^|\r-]([^").count(); + parser_with_extensions("|\r\r=][^|\r\r=][^car").count(); + } + + #[test] + fn issue_303() { + // dont crash + parser_with_extensions("[^\r\ra]").count(); + parser_with_extensions("\r\r]Z[^\x00\r\r]Z[^\x00").count(); + } + + #[test] + fn issue_313() { + // dont crash + parser_with_extensions("*]0[^\r\r*]0[^").count(); + parser_with_extensions("[^\r> `][^\r> `][^\r> `][").count(); + } + + #[test] + fn issue_311() { + // dont crash + parser_with_extensions("\\\u{0d}-\u{09}\\\u{0d}-\u{09}").count(); + } + + #[test] + fn issue_283() { + let input = std::str::from_utf8(b"\xf0\x9b\xb2\x9f - \\\n> - ").count(); + parser_with_extensions("- \n\n").count(); + } + + #[test] + fn issue_306() { + // dont crash + parser_with_extensions("*\r_<__*\r_<__*\r_<__*\r_<__").count(); + } + + #[test] + fn issue_305() { + // dont crash + parser_with_extensions("_6**6*_*").count(); + } + + #[test] + fn another_emphasis_panic() { + parser_with_extensions("*__#_#__*").count(); + } + + #[test] + fn offset_iter() { + let event_offsets: Vec<_> = Parser::new("*hello* world") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..13), (0..7), (1..6), (0..7), (7..13), (0..13)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn reference_link_offsets() { + let range = + Parser::new("# H1\n[testing][Some reference]\n\n[Some reference]: https://github.com") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::Start(Tag::Link(LinkType::Reference, ..), ..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(5..30, range); + } + + #[test] + fn footnote_offsets() { + let range = Parser::new("Testing this[^1] out.\n\n[^1]: Footnote.") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::FootnoteReference(..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(12..16, range); + } + + #[test] + fn table_offset() { + let markdown = "a\n\nTesting|This|Outtt\n--|:--:|--:\nSome Data|Other data|asdf"; + let event_offset = parser_with_extensions(markdown) + .into_offset_iter() + .map(|(_ev, range)| range) + .nth(3) + .unwrap(); + let expected_offset = 3..59; + assert_eq!(expected_offset, event_offset); + } + + #[test] + fn offset_iter_issue_378() { + let event_offsets: Vec<_> = Parser::new("a [b](c) d") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..10), (0..2), (2..8), (3..4), (2..8), (8..10), (0..10)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn offset_iter_issue_404() { + let event_offsets: Vec<_> = Parser::new("###\n") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..4), (0..4)]; + assert_eq!(expected_offsets, event_offsets); + } + + // FIXME: add this one regression suite + #[test] + fn link_def_at_eof() { + let test_str = "[My site][world]\n\n[world]: https://vincentprouillet.com"; + let expected = "

    My site

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_at_eof() { + let test_str = "[test]:\\"; + let expected = ""; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_cr_lf() { + let test_str = "[a]: /u\r\n\n[a]"; + let expected = "

    a

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn no_dest_refdef() { + let test_str = "[a]:"; + let expected = "

    [a]:

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn simple_broken_link_callback() { + let test_str = "This is a link w/o def: [hello][world]"; + let parser = Parser::new_with_broken_link_callback( + test_str, + Options::empty(), + Some(&|norm, raw| { + assert_eq!("world", raw); + assert_eq!("world", norm); + Some(("YOLO".to_owned(), "SWAG".to_owned())) + }), + ); + let mut link_tag_count = 0; + for (typ, url, title) in parser.filter_map(|event| match event { + Event::Start(tag) | Event::End(tag) => match tag { + Tag::Link(typ, url, title) => Some((typ, url, title)), + _ => None, + }, + _ => None, + }) { + link_tag_count += 1; + assert_eq!(typ, LinkType::ReferenceUnknown); + assert_eq!(url.as_ref(), "YOLO"); + assert_eq!(title.as_ref(), "SWAG"); + } + assert!(link_tag_count > 0); + } + + #[test] + fn code_block_kind_check_fenced() { + let parser = Parser::new("hello\n```test\ntadam\n```"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(syntax))) => { + assert_eq!(syntax.as_ref(), "test"); + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } + + #[test] + fn code_block_kind_check_indented() { + let parser = Parser::new("hello\n\n ```test\n tadam\nhello"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => { + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/puncttable.rs b/vendor/pulldown-cmark-0.7.2/src/puncttable.rs new file mode 100644 index 0000000000..a1b0751a54 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/puncttable.rs @@ -0,0 +1,351 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! CommonMark punctuation set based on spec and Unicode properties. + +// Autogenerated by mk_puncttable.py + +const PUNCT_MASKS_ASCII: [u16; 8] = [ + 0x0000, // U+0000...U+000F + 0x0000, // U+0010...U+001F + 0xfffe, // U+0020...U+002F + 0xfc00, // U+0030...U+003F + 0x0001, // U+0040...U+004F + 0xf800, // U+0050...U+005F + 0x0001, // U+0060...U+006F + 0x7800, // U+0070...U+007F +]; + +const PUNCT_TAB: [u16; 132] = [ + 10, // U+00A0...U+00AF + 11, // U+00B0...U+00BF + 55, // U+0370...U+037F + 56, // U+0380...U+038F + 85, // U+0550...U+055F + 88, // U+0580...U+058F + 91, // U+05B0...U+05BF + 92, // U+05C0...U+05CF + 95, // U+05F0...U+05FF + 96, // U+0600...U+060F + 97, // U+0610...U+061F + 102, // U+0660...U+066F + 109, // U+06D0...U+06DF + 112, // U+0700...U+070F + 127, // U+07F0...U+07FF + 131, // U+0830...U+083F + 133, // U+0850...U+085F + 150, // U+0960...U+096F + 151, // U+0970...U+097F + 175, // U+0AF0...U+0AFF + 223, // U+0DF0...U+0DFF + 228, // U+0E40...U+0E4F + 229, // U+0E50...U+0E5F + 240, // U+0F00...U+0F0F + 241, // U+0F10...U+0F1F + 243, // U+0F30...U+0F3F + 248, // U+0F80...U+0F8F + 253, // U+0FD0...U+0FDF + 260, // U+1040...U+104F + 271, // U+10F0...U+10FF + 310, // U+1360...U+136F + 320, // U+1400...U+140F + 358, // U+1660...U+166F + 361, // U+1690...U+169F + 366, // U+16E0...U+16EF + 371, // U+1730...U+173F + 381, // U+17D0...U+17DF + 384, // U+1800...U+180F + 404, // U+1940...U+194F + 417, // U+1A10...U+1A1F + 426, // U+1AA0...U+1AAF + 437, // U+1B50...U+1B5F + 438, // U+1B60...U+1B6F + 447, // U+1BF0...U+1BFF + 451, // U+1C30...U+1C3F + 455, // U+1C70...U+1C7F + 460, // U+1CC0...U+1CCF + 461, // U+1CD0...U+1CDF + 513, // U+2010...U+201F + 514, // U+2020...U+202F + 515, // U+2030...U+203F + 516, // U+2040...U+204F + 517, // U+2050...U+205F + 519, // U+2070...U+207F + 520, // U+2080...U+208F + 560, // U+2300...U+230F + 562, // U+2320...U+232F + 630, // U+2760...U+276F + 631, // U+2770...U+277F + 636, // U+27C0...U+27CF + 638, // U+27E0...U+27EF + 664, // U+2980...U+298F + 665, // U+2990...U+299F + 669, // U+29D0...U+29DF + 671, // U+29F0...U+29FF + 719, // U+2CF0...U+2CFF + 727, // U+2D70...U+2D7F + 736, // U+2E00...U+2E0F + 737, // U+2E10...U+2E1F + 738, // U+2E20...U+2E2F + 739, // U+2E30...U+2E3F + 740, // U+2E40...U+2E4F + 768, // U+3000...U+300F + 769, // U+3010...U+301F + 771, // U+3030...U+303F + 778, // U+30A0...U+30AF + 783, // U+30F0...U+30FF + 2639, // U+A4F0...U+A4FF + 2656, // U+A600...U+A60F + 2663, // U+A670...U+A67F + 2671, // U+A6F0...U+A6FF + 2695, // U+A870...U+A87F + 2700, // U+A8C0...U+A8CF + 2703, // U+A8F0...U+A8FF + 2706, // U+A920...U+A92F + 2709, // U+A950...U+A95F + 2716, // U+A9C0...U+A9CF + 2717, // U+A9D0...U+A9DF + 2725, // U+AA50...U+AA5F + 2733, // U+AAD0...U+AADF + 2735, // U+AAF0...U+AAFF + 2750, // U+ABE0...U+ABEF + 4051, // U+FD30...U+FD3F + 4065, // U+FE10...U+FE1F + 4067, // U+FE30...U+FE3F + 4068, // U+FE40...U+FE4F + 4069, // U+FE50...U+FE5F + 4070, // U+FE60...U+FE6F + 4080, // U+FF00...U+FF0F + 4081, // U+FF10...U+FF1F + 4082, // U+FF20...U+FF2F + 4083, // U+FF30...U+FF3F + 4085, // U+FF50...U+FF5F + 4086, // U+FF60...U+FF6F + 4112, // U+10100...U+1010F + 4153, // U+10390...U+1039F + 4157, // U+103D0...U+103DF + 4182, // U+10560...U+1056F + 4229, // U+10850...U+1085F + 4241, // U+10910...U+1091F + 4243, // U+10930...U+1093F + 4261, // U+10A50...U+10A5F + 4263, // U+10A70...U+10A7F + 4271, // U+10AF0...U+10AFF + 4275, // U+10B30...U+10B3F + 4281, // U+10B90...U+10B9F + 4356, // U+11040...U+1104F + 4363, // U+110B0...U+110BF + 4364, // U+110C0...U+110CF + 4372, // U+11140...U+1114F + 4375, // U+11170...U+1117F + 4380, // U+111C0...U+111CF + 4387, // U+11230...U+1123F + 4428, // U+114C0...U+114CF + 4444, // U+115C0...U+115CF + 4452, // U+11640...U+1164F + 4679, // U+12470...U+1247F + 5798, // U+16A60...U+16A6F + 5807, // U+16AF0...U+16AFF + 5811, // U+16B30...U+16B3F + 5812, // U+16B40...U+16B4F + 7113, // U+1BC90...U+1BC9F +]; + +const PUNCT_MASKS: [u16; 132] = [ + 0x0882, // U+00A0...U+00AF + 0x88c0, // U+00B0...U+00BF + 0x4000, // U+0370...U+037F + 0x0080, // U+0380...U+038F + 0xfc00, // U+0550...U+055F + 0x0600, // U+0580...U+058F + 0x4000, // U+05B0...U+05BF + 0x0049, // U+05C0...U+05CF + 0x0018, // U+05F0...U+05FF + 0x3600, // U+0600...U+060F + 0xc800, // U+0610...U+061F + 0x3c00, // U+0660...U+066F + 0x0010, // U+06D0...U+06DF + 0x3fff, // U+0700...U+070F + 0x0380, // U+07F0...U+07FF + 0x7fff, // U+0830...U+083F + 0x4000, // U+0850...U+085F + 0x0030, // U+0960...U+096F + 0x0001, // U+0970...U+097F + 0x0001, // U+0AF0...U+0AFF + 0x0010, // U+0DF0...U+0DFF + 0x8000, // U+0E40...U+0E4F + 0x0c00, // U+0E50...U+0E5F + 0xfff0, // U+0F00...U+0F0F + 0x0017, // U+0F10...U+0F1F + 0x3c00, // U+0F30...U+0F3F + 0x0020, // U+0F80...U+0F8F + 0x061f, // U+0FD0...U+0FDF + 0xfc00, // U+1040...U+104F + 0x0800, // U+10F0...U+10FF + 0x01ff, // U+1360...U+136F + 0x0001, // U+1400...U+140F + 0x6000, // U+1660...U+166F + 0x1800, // U+1690...U+169F + 0x3800, // U+16E0...U+16EF + 0x0060, // U+1730...U+173F + 0x0770, // U+17D0...U+17DF + 0x07ff, // U+1800...U+180F + 0x0030, // U+1940...U+194F + 0xc000, // U+1A10...U+1A1F + 0x3f7f, // U+1AA0...U+1AAF + 0xfc00, // U+1B50...U+1B5F + 0x0001, // U+1B60...U+1B6F + 0xf000, // U+1BF0...U+1BFF + 0xf800, // U+1C30...U+1C3F + 0xc000, // U+1C70...U+1C7F + 0x00ff, // U+1CC0...U+1CCF + 0x0008, // U+1CD0...U+1CDF + 0xffff, // U+2010...U+201F + 0x00ff, // U+2020...U+202F + 0xffff, // U+2030...U+203F + 0xffef, // U+2040...U+204F + 0x7ffb, // U+2050...U+205F + 0x6000, // U+2070...U+207F + 0x6000, // U+2080...U+208F + 0x0f00, // U+2300...U+230F + 0x0600, // U+2320...U+232F + 0xff00, // U+2760...U+276F + 0x003f, // U+2770...U+277F + 0x0060, // U+27C0...U+27CF + 0xffc0, // U+27E0...U+27EF + 0xfff8, // U+2980...U+298F + 0x01ff, // U+2990...U+299F + 0x0f00, // U+29D0...U+29DF + 0x3000, // U+29F0...U+29FF + 0xde00, // U+2CF0...U+2CFF + 0x0001, // U+2D70...U+2D7F + 0xffff, // U+2E00...U+2E0F + 0xffff, // U+2E10...U+2E1F + 0x7fff, // U+2E20...U+2E2F + 0xffff, // U+2E30...U+2E3F + 0x0007, // U+2E40...U+2E4F + 0xff0e, // U+3000...U+300F + 0xfff3, // U+3010...U+301F + 0x2001, // U+3030...U+303F + 0x0001, // U+30A0...U+30AF + 0x0800, // U+30F0...U+30FF + 0xc000, // U+A4F0...U+A4FF + 0xe000, // U+A600...U+A60F + 0x4008, // U+A670...U+A67F + 0x00fc, // U+A6F0...U+A6FF + 0x00f0, // U+A870...U+A87F + 0xc000, // U+A8C0...U+A8CF + 0x0700, // U+A8F0...U+A8FF + 0xc000, // U+A920...U+A92F + 0x8000, // U+A950...U+A95F + 0x3ffe, // U+A9C0...U+A9CF + 0xc000, // U+A9D0...U+A9DF + 0xf000, // U+AA50...U+AA5F + 0xc000, // U+AAD0...U+AADF + 0x0003, // U+AAF0...U+AAFF + 0x0800, // U+ABE0...U+ABEF + 0xc000, // U+FD30...U+FD3F + 0x03ff, // U+FE10...U+FE1F + 0xffff, // U+FE30...U+FE3F + 0xffff, // U+FE40...U+FE4F + 0xfff7, // U+FE50...U+FE5F + 0x0d0b, // U+FE60...U+FE6F + 0xf7ee, // U+FF00...U+FF0F + 0x8c00, // U+FF10...U+FF1F + 0x0001, // U+FF20...U+FF2F + 0xb800, // U+FF30...U+FF3F + 0xa800, // U+FF50...U+FF5F + 0x003f, // U+FF60...U+FF6F + 0x0007, // U+10100...U+1010F + 0x8000, // U+10390...U+1039F + 0x0001, // U+103D0...U+103DF + 0x8000, // U+10560...U+1056F + 0x0080, // U+10850...U+1085F + 0x8000, // U+10910...U+1091F + 0x8000, // U+10930...U+1093F + 0x01ff, // U+10A50...U+10A5F + 0x8000, // U+10A70...U+10A7F + 0x007f, // U+10AF0...U+10AFF + 0xfe00, // U+10B30...U+10B3F + 0x1e00, // U+10B90...U+10B9F + 0x3f80, // U+11040...U+1104F + 0xd800, // U+110B0...U+110BF + 0x0003, // U+110C0...U+110CF + 0x000f, // U+11140...U+1114F + 0x0030, // U+11170...U+1117F + 0x21e0, // U+111C0...U+111CF + 0x3f00, // U+11230...U+1123F + 0x0040, // U+114C0...U+114CF + 0x03fe, // U+115C0...U+115CF + 0x000e, // U+11640...U+1164F + 0x001f, // U+12470...U+1247F + 0xc000, // U+16A60...U+16A6F + 0x0020, // U+16AF0...U+16AFF + 0x0f80, // U+16B30...U+16B3F + 0x0010, // U+16B40...U+16B4F + 0x8000, // U+1BC90...U+1BC9F +]; + +pub fn is_ascii_punctuation(c: u8) -> bool { + c < 128 && (PUNCT_MASKS_ASCII[(c / 16) as usize] & (1 << (c & 15))) != 0 +} + +pub fn is_punctuation(c: char) -> bool { + let cp = c as u32; + if cp < 128 { + return is_ascii_punctuation(cp as u8); + } + if cp > 0x1BC9F { + return false; + } + let high = (cp / 16) as u16; + match PUNCT_TAB.binary_search(&high) { + Ok(index) => (PUNCT_MASKS[index] & (1 << (cp & 15))) != 0, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use super::{is_ascii_punctuation, is_punctuation}; + + #[test] + fn test_ascii() { + assert!(is_ascii_punctuation(b'!')); + assert!(is_ascii_punctuation(b'@')); + assert!(is_ascii_punctuation(b'~')); + assert!(!is_ascii_punctuation(b' ')); + assert!(!is_ascii_punctuation(b'0')); + assert!(!is_ascii_punctuation(b'A')); + assert!(!is_ascii_punctuation(0xA1)); + } + + #[test] + fn test_unicode() { + assert!(is_punctuation('~')); + assert!(!is_punctuation(' ')); + + assert!(is_punctuation('\u{00A1}')); + assert!(is_punctuation('\u{060C}')); + assert!(is_punctuation('\u{FF65}')); + assert!(is_punctuation('\u{1BC9F}')); + assert!(!is_punctuation('\u{1BCA0}')); + } +} diff --git a/vendor/pulldown-cmark-0.7.2/src/scanners.rs b/vendor/pulldown-cmark-0.7.2/src/scanners.rs new file mode 100644 index 0000000000..884d4e49f2 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/src/scanners.rs @@ -0,0 +1,1247 @@ +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Scanners for fragments of CommonMark syntax + +use std::char; +use std::convert::TryInto; + +use crate::entities; +use crate::parse::{Alignment, HtmlScanGuard, LinkType}; +pub use crate::puncttable::{is_ascii_punctuation, is_punctuation}; +use crate::strings::CowStr; + +use memchr::memchr; + +// sorted for binary search +const HTML_TAGS: [&str; 62] = [ + "address", + "article", + "aside", + "base", + "basefont", + "blockquote", + "body", + "caption", + "center", + "col", + "colgroup", + "dd", + "details", + "dialog", + "dir", + "div", + "dl", + "dt", + "fieldset", + "figcaption", + "figure", + "footer", + "form", + "frame", + "frameset", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "head", + "header", + "hr", + "html", + "iframe", + "legend", + "li", + "link", + "main", + "menu", + "menuitem", + "nav", + "noframes", + "ol", + "optgroup", + "option", + "p", + "param", + "section", + "source", + "summary", + "table", + "tbody", + "td", + "tfoot", + "th", + "thead", + "title", + "tr", + "track", + "ul", +]; + +/// Analysis of the beginning of a line, including indentation and container +/// markers. +#[derive(Clone)] +pub struct LineStart<'a> { + bytes: &'a [u8], + tab_start: usize, + ix: usize, + spaces_remaining: usize, + // no thematic breaks can occur before this offset. + // this prevents scanning over and over up to a certain point + min_hrule_offset: usize, +} + +impl<'a> LineStart<'a> { + pub(crate) fn new(bytes: &[u8]) -> LineStart { + LineStart { + bytes, + tab_start: 0, + ix: 0, + spaces_remaining: 0, + min_hrule_offset: 0, + } + } + + /// Try to scan a number of spaces. + /// + /// Returns true if all spaces were consumed. + /// + /// Note: consumes some spaces even if not successful. + pub(crate) fn scan_space(&mut self, n_space: usize) -> bool { + self.scan_space_inner(n_space) == 0 + } + + /// Scan a number of spaces up to a maximum. + /// + /// Returns number of spaces scanned. + pub(crate) fn scan_space_upto(&mut self, n_space: usize) -> usize { + n_space - self.scan_space_inner(n_space) + } + + /// Returns unused remainder of spaces. + fn scan_space_inner(&mut self, mut n_space: usize) -> usize { + let n_from_remaining = self.spaces_remaining.min(n_space); + self.spaces_remaining -= n_from_remaining; + n_space -= n_from_remaining; + while n_space > 0 && self.ix < self.bytes.len() { + match self.bytes[self.ix] { + b' ' => { + self.ix += 1; + n_space -= 1; + } + b'\t' => { + let spaces = 4 - (self.ix - self.tab_start) % 4; + self.ix += 1; + self.tab_start = self.ix; + let n = spaces.min(n_space); + n_space -= n; + self.spaces_remaining = spaces - n; + } + _ => break, + } + } + n_space + } + + /// Scan all available ASCII whitespace (not including eol). + pub(crate) fn scan_all_space(&mut self) { + self.spaces_remaining = 0; + self.ix += self.bytes[self.ix..] + .iter() + .take_while(|&&b| b == b' ' || b == b'\t') + .count(); + } + + /// Determine whether we're at end of line (includes end of file). + pub(crate) fn is_at_eol(&self) -> bool { + self.bytes + .get(self.ix) + .map(|&c| c == b'\r' || c == b'\n') + .unwrap_or(true) + } + + fn scan_ch(&mut self, c: u8) -> bool { + if self.ix < self.bytes.len() && self.bytes[self.ix] == c { + self.ix += 1; + true + } else { + false + } + } + + pub(crate) fn scan_blockquote_marker(&mut self) -> bool { + let save = self.clone(); + let _ = self.scan_space(3); + if self.scan_ch(b'>') { + let _ = self.scan_space(1); + true + } else { + *self = save; + false + } + } + + /// Scan a list marker. + /// + /// Return value is the character, the start index, and the indent in spaces. + /// For ordered list markers, the character will be one of b'.' or b')'. For + /// bullet list markers, it will be one of b'-', b'+', or b'*'. + pub(crate) fn scan_list_marker(&mut self) -> Option<(u8, u64, usize)> { + let save = self.clone(); + let indent = self.scan_space_upto(3); + if self.ix < self.bytes.len() { + let c = self.bytes[self.ix]; + if c == b'-' || c == b'+' || c == b'*' { + if self.ix >= self.min_hrule_offset { + // there could be an hrule here + if let Err(min_offset) = scan_hrule(&self.bytes[self.ix..]) { + self.min_hrule_offset = min_offset; + } else { + *self = save; + return None; + } + } + self.ix += 1; + if self.scan_space(1) || self.is_at_eol() { + return self.finish_list_marker(c, 0, indent + 2); + } + } else if c >= b'0' && c <= b'9' { + let start_ix = self.ix; + let mut ix = self.ix + 1; + let mut val = u64::from(c - b'0'); + while ix < self.bytes.len() && ix - start_ix < 10 { + let c = self.bytes[ix]; + ix += 1; + if c >= b'0' && c <= b'9' { + val = val * 10 + u64::from(c - b'0'); + } else if c == b')' || c == b'.' { + self.ix = ix; + if self.scan_space(1) || self.is_at_eol() { + return self.finish_list_marker(c, val, indent + self.ix - start_ix); + } else { + break; + } + } else { + break; + } + } + } + } + *self = save; + None + } + + fn finish_list_marker( + &mut self, + c: u8, + start: u64, + mut indent: usize, + ) -> Option<(u8, u64, usize)> { + let save = self.clone(); + + // skip the rest of the line if it's blank + if scan_blank_line(&self.bytes[self.ix..]).is_some() { + return Some((c, start, indent)); + } + + let post_indent = self.scan_space_upto(4); + if post_indent < 4 { + indent += post_indent; + } else { + *self = save; + } + Some((c, start, indent)) + } + + /// Returns Some(is_checked) when a task list marker was found. Resets itself + /// to original state otherwise. + pub(crate) fn scan_task_list_marker(&mut self) -> Option { + let save = self.clone(); + self.scan_space_upto(3); + + if !self.scan_ch(b'[') { + *self = save; + return None; + } + let is_checked = match self.bytes.get(self.ix) { + Some(&c) if is_ascii_whitespace_no_nl(c) => { + self.ix += 1; + false + } + Some(b'x') | Some(b'X') => { + self.ix += 1; + true + } + _ => { + *self = save; + return None; + } + }; + if !self.scan_ch(b']') { + *self = save; + return None; + } + if !self + .bytes + .get(self.ix) + .map(|&b| is_ascii_whitespace_no_nl(b)) + .unwrap_or(false) + { + *self = save; + return None; + } + Some(is_checked) + } + + pub(crate) fn bytes_scanned(&self) -> usize { + self.ix + } + + pub(crate) fn remaining_space(&self) -> usize { + self.spaces_remaining + } +} + +pub(crate) fn is_ascii_whitespace(c: u8) -> bool { + (c >= 0x09 && c <= 0x0d) || c == b' ' +} + +pub(crate) fn is_ascii_whitespace_no_nl(c: u8) -> bool { + c == b'\t' || c == 0x0b || c == 0x0c || c == b' ' +} + +fn is_ascii_alpha(c: u8) -> bool { + match c { + b'a'..=b'z' | b'A'..=b'Z' => true, + _ => false, + } +} + +fn is_ascii_alphanumeric(c: u8) -> bool { + match c { + b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => true, + _ => false, + } +} + +fn is_ascii_letterdigitdash(c: u8) -> bool { + c == b'-' || is_ascii_alphanumeric(c) +} + +fn is_digit(c: u8) -> bool { + b'0' <= c && c <= b'9' +} + +fn is_valid_unquoted_attr_value_char(c: u8) -> bool { + match c { + b'\'' | b'"' | b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => false, + _ => true, + } +} + +// scan a single character +pub(crate) fn scan_ch(data: &[u8], c: u8) -> usize { + if !data.is_empty() && data[0] == c { + 1 + } else { + 0 + } +} + +pub(crate) fn scan_while(data: &[u8], mut f: F) -> usize +where + F: FnMut(u8) -> bool, +{ + data.iter().take_while(|&&c| f(c)).count() +} + +pub(crate) fn scan_rev_while(data: &[u8], mut f: F) -> usize +where + F: FnMut(u8) -> bool, +{ + data.iter().rev().take_while(|&&c| f(c)).count() +} + +pub(crate) fn scan_ch_repeat(data: &[u8], c: u8) -> usize { + scan_while(data, |x| x == c) +} + +// Note: this scans ASCII whitespace only, for Unicode whitespace use +// a different function. +pub(crate) fn scan_whitespace_no_nl(data: &[u8]) -> usize { + scan_while(data, is_ascii_whitespace_no_nl) +} + +fn scan_attr_value_chars(data: &[u8]) -> usize { + scan_while(data, is_valid_unquoted_attr_value_char) +} + +pub(crate) fn scan_eol(bytes: &[u8]) -> Option { + if bytes.is_empty() { + return Some(0); + } + match bytes[0] { + b'\n' => Some(1), + b'\r' => Some(if bytes.get(1) == Some(&b'\n') { 2 } else { 1 }), + _ => None, + } +} + +pub(crate) fn scan_blank_line(bytes: &[u8]) -> Option { + let i = scan_whitespace_no_nl(bytes); + scan_eol(&bytes[i..]).map(|n| i + n) +} + +pub(crate) fn scan_nextline(bytes: &[u8]) -> usize { + memchr(b'\n', bytes).map_or(bytes.len(), |x| x + 1) +} + +// return: end byte for closing code fence, or None +// if the line is not a closing code fence +pub(crate) fn scan_closing_code_fence( + bytes: &[u8], + fence_char: u8, + n_fence_char: usize, +) -> Option { + if bytes.is_empty() { + return Some(0); + } + let mut i = 0; + let num_fence_chars_found = scan_ch_repeat(&bytes[i..], fence_char); + if num_fence_chars_found < n_fence_char { + return None; + } + i += num_fence_chars_found; + let num_trailing_spaces = scan_ch_repeat(&bytes[i..], b' '); + i += num_trailing_spaces; + scan_eol(&bytes[i..]).map(|_| i) +} + +// returned pair is (number of bytes, number of spaces) +fn calc_indent(text: &[u8], max: usize) -> (usize, usize) { + let mut spaces = 0; + let mut offset = 0; + + for (i, &b) in text.iter().enumerate() { + match b { + b' ' => { + spaces += 1; + if spaces == max { + break; + } + } + b'\t' => { + let new_spaces = spaces + 4 - (spaces & 3); + if new_spaces > max { + break; + } + spaces = new_spaces; + } + _ => break, + } + offset = i; + } + + (offset, spaces) +} + +/// Scan hrule opening sequence. +/// +/// Returns Ok(x) when it finds an hrule, where x is the +/// size of line containing the hrule, including the trailing newline. +/// +/// Returns Err(x) when it does not find an hrule and x is +/// the offset in data before no hrule can appear. +pub(crate) fn scan_hrule(bytes: &[u8]) -> Result { + if bytes.len() < 3 { + return Err(0); + } + let c = bytes[0]; + if !(c == b'*' || c == b'-' || c == b'_') { + return Err(0); + } + let mut n = 0; + let mut i = 0; + + while i < bytes.len() { + match bytes[i] { + b'\n' | b'\r' => { + i += scan_eol(&bytes[i..]).unwrap_or(0); + break; + } + c2 if c2 == c => { + n += 1; + } + b' ' | b'\t' => (), + _ => return Err(i), + } + i += 1; + } + if n >= 3 { + Ok(i) + } else { + Err(i) + } +} + +/// Scan an ATX heading opening sequence. +/// +/// Returns number of bytes in prefix and level. +pub(crate) fn scan_atx_heading(data: &[u8]) -> Option { + let level = scan_ch_repeat(data, b'#'); + if level >= 1 && level <= 6 && data.get(level).cloned().map_or(true, is_ascii_whitespace) { + Some(level) + } else { + None + } +} + +/// Scan a setext heading underline. +/// +/// Returns number of bytes in line (including trailing newline) and level. +pub(crate) fn scan_setext_heading(data: &[u8]) -> Option<(usize, u32)> { + let c = *data.get(0)?; + if !(c == b'-' || c == b'=') { + return None; + } + let mut i = 1 + scan_ch_repeat(&data[1..], c); + i += scan_blank_line(&data[i..])?; + let level = if c == b'=' { 1 } else { 2 }; + Some((i, level)) +} + +// returns number of bytes in line (including trailing +// newline) and column alignments +pub(crate) fn scan_table_head(data: &[u8]) -> (usize, Vec) { + let (mut i, spaces) = calc_indent(data, 4); + if spaces > 3 || i == data.len() { + return (0, vec![]); + } + let mut cols = vec![]; + let mut active_col = Alignment::None; + let mut start_col = true; + if data[i] == b'|' { + i += 1; + } + for c in &data[i..] { + if let Some(n) = scan_eol(&data[i..]) { + i += n; + break; + } + match *c { + b' ' => (), + b':' => { + active_col = match (start_col, active_col) { + (true, Alignment::None) => Alignment::Left, + (false, Alignment::Left) => Alignment::Center, + (false, Alignment::None) => Alignment::Right, + _ => active_col, + }; + start_col = false; + } + b'-' => { + start_col = false; + } + b'|' => { + start_col = true; + cols.push(active_col); + active_col = Alignment::None; + } + _ => { + cols = vec![]; + start_col = true; + break; + } + } + i += 1; + } + + if !start_col { + cols.push(active_col); + } + + (i, cols) +} + +/// Scan code fence. +/// +/// Returns number of bytes scanned and the char that is repeated to make the code fence. +pub(crate) fn scan_code_fence(data: &[u8]) -> Option<(usize, u8)> { + let c = *data.get(0)?; + if !(c == b'`' || c == b'~') { + return None; + } + let i = 1 + scan_ch_repeat(&data[1..], c); + if i >= 3 { + if c == b'`' { + let suffix = &data[i..]; + let next_line = i + scan_nextline(suffix); + // FIXME: make sure this is correct + if suffix[..(next_line - i)].iter().any(|&b| b == b'`') { + return None; + } + } + Some((i, c)) + } else { + None + } +} + +pub(crate) fn scan_blockquote_start(data: &[u8]) -> Option { + if data.starts_with(b"> ") { + Some(2) + } else { + None + } +} + +/// This already assumes the list item has been scanned. +pub(crate) fn scan_empty_list(data: &[u8]) -> bool { + let mut ix = 0; + for _ in 0..2 { + if let Some(bytes) = scan_blank_line(&data[ix..]) { + ix += bytes; + } else { + return false; + } + } + true +} + +// return number of bytes scanned, delimiter, start index, and indent +pub(crate) fn scan_listitem(bytes: &[u8]) -> Option<(usize, u8, usize, usize)> { + let mut c = *bytes.get(0)?; + let (w, start) = match c { + b'-' | b'+' | b'*' => (1, 0), + b'0'..=b'9' => { + let (length, start) = parse_decimal(bytes); + c = *bytes.get(length)?; + if !(c == b'.' || c == b')') { + return None; + } + (length + 1, start) + } + _ => { + return None; + } + }; + // TODO: replace calc_indent with scan_leading_whitespace, for tab correctness + let (mut postn, mut postindent) = calc_indent(&bytes[w..], 5); + if postindent == 0 { + scan_eol(&bytes[w..])?; + postindent += 1; + } else if postindent > 4 { + postn = 1; + postindent = 1; + } + if scan_blank_line(&bytes[w..]).is_some() { + postn = 0; + postindent = 1; + } + Some((w + postn, c, start, w + postindent)) +} + +// returns (number of bytes, parsed decimal) +fn parse_decimal(bytes: &[u8]) -> (usize, usize) { + match bytes + .iter() + .take_while(|&&b| is_digit(b)) + .try_fold((0, 0usize), |(count, acc), c| { + let digit = usize::from(c - b'0'); + match acc + .checked_mul(10) + .and_then(|ten_acc| ten_acc.checked_add(digit)) + { + Some(number) => Ok((count + 1, number)), + // stop early on overflow + None => Err((count, acc)), + } + }) { + Ok(p) | Err(p) => p, + } +} + +// returns (number of bytes, parsed hex) +fn parse_hex(bytes: &[u8]) -> (usize, usize) { + match bytes.iter().try_fold((0, 0usize), |(count, acc), c| { + let mut c = *c; + let digit = if c >= b'0' && c <= b'9' { + usize::from(c - b'0') + } else { + // make lower case + c |= 0x20; + if c >= b'a' && c <= b'f' { + usize::from(c - b'a' + 10) + } else { + return Err((count, acc)); + } + }; + match acc + .checked_mul(16) + .and_then(|sixteen_acc| sixteen_acc.checked_add(digit)) + { + Some(number) => Ok((count + 1, number)), + // stop early on overflow + None => Err((count, acc)), + } + }) { + Ok(p) | Err(p) => p, + } +} + +fn char_from_codepoint(input: usize) -> Option { + let mut codepoint = input.try_into().ok()?; + if codepoint == 0 { + codepoint = 0xFFFD; + } + char::from_u32(codepoint) +} + +// doesn't bother to check data[0] == '&' +pub(crate) fn scan_entity(bytes: &[u8]) -> (usize, Option>) { + let mut end = 1; + if scan_ch(&bytes[end..], b'#') == 1 { + end += 1; + let (bytecount, codepoint) = if end < bytes.len() && bytes[end] | 0x20 == b'x' { + end += 1; + parse_hex(&bytes[end..]) + } else { + parse_decimal(&bytes[end..]) + }; + end += bytecount; + return if bytecount == 0 || scan_ch(&bytes[end..], b';') == 0 { + (0, None) + } else if let Some(c) = char_from_codepoint(codepoint) { + (end + 1, Some(c.into())) + } else { + (0, None) + }; + } + end += scan_while(&bytes[end..], is_ascii_alphanumeric); + if scan_ch(&bytes[end..], b';') == 1 { + if let Some(value) = entities::get_entity(&bytes[1..end]) { + return (end + 1, Some(value.into())); + } + } + (0, None) +} + +// FIXME: we can most likely re-use other scanners +// returns (bytelength, title_str) +pub(crate) fn scan_refdef_title(text: &str) -> Option<(usize, &str)> { + let mut chars = text.chars().peekable(); + let closing_delim = match chars.next()? { + '\'' => '\'', + '"' => '"', + '(' => ')', + _ => return None, + }; + let mut bytecount = 1; + + while let Some(c) = chars.next() { + match c { + '\n' => { + bytecount += 1; + let mut next = *chars.peek()?; + while is_ascii_whitespace_no_nl(next as u8) { + bytecount += chars.next()?.len_utf8(); + next = *chars.peek()?; + } + if *chars.peek()? == '\n' { + // blank line - not allowed + return None; + } + } + '\\' => { + let next_char = chars.next()?; + bytecount += 1 + next_char.len_utf8(); + } + c if c == closing_delim => { + return Some((bytecount + 1, &text[1..bytecount])); + } + c => { + bytecount += c.len_utf8(); + } + } + } + None +} + +// note: dest returned is raw, still needs to be unescaped +// TODO: check that nested parens are really not allowed for refdefs +// TODO(performance): this func should probably its own unescaping +pub(crate) fn scan_link_dest( + data: &str, + start_ix: usize, + max_next: usize, +) -> Option<(usize, &str)> { + let bytes = &data.as_bytes()[start_ix..]; + let mut i = scan_ch(bytes, b'<'); + + if i != 0 { + // pointy links + while i < bytes.len() { + match bytes[i] { + b'\n' | b'\r' | b'<' => return None, + b'>' => return Some((i + 1, &data[(start_ix + 1)..(start_ix + i)])), + b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { + i += 1; + } + _ => {} + } + i += 1; + } + None + } else { + // non-pointy links + let mut nest = 0; + while i < bytes.len() { + match bytes[i] { + 0x0..=0x20 => { + break; + } + b'(' => { + if nest > max_next { + return None; + } + nest += 1; + } + b')' => { + if nest == 0 { + break; + } + nest -= 1; + } + b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { + i += 1; + } + _ => {} + } + i += 1; + } + Some((i, &data[start_ix..(start_ix + i)])) + } +} + +/// Returns bytes scanned +fn scan_attribute_name(data: &[u8]) -> Option { + let (&c, tail) = data.split_first()?; + if is_ascii_alpha(c) || c == b'_' || c == b':' { + Some( + 1 + scan_while(tail, |c| { + is_ascii_alphanumeric(c) || c == b'_' || c == b'.' || c == b':' || c == b'-' + }), + ) + } else { + None + } +} + +/// Returns byte scanned (TODO: should it return new offset?) +// TODO: properly use the newline handler here +fn scan_attribute(data: &[u8], newline_handler: Option<&dyn Fn(&[u8]) -> usize>) -> Option { + let allow_newline = newline_handler.is_some(); + let whitespace_scanner = + |c| is_ascii_whitespace(c) && (allow_newline || c != b'\n' && c != b'\r'); + let mut ix = scan_attribute_name(data)?; + let n_whitespace = scan_while(&data[ix..], whitespace_scanner); + ix += n_whitespace; + if scan_ch(&data[ix..], b'=') == 1 { + ix += 1; + ix += scan_while(&data[ix..], whitespace_scanner); + ix += scan_attribute_value(&data[ix..], newline_handler)?; + } else if n_whitespace > 0 { + // Leave whitespace for next attribute. + ix -= 1; + } + Some(ix) +} + +fn scan_attribute_value( + data: &[u8], + newline_handler: Option<&dyn Fn(&[u8]) -> usize>, +) -> Option { + let mut i = 0; + match *data.get(0)? { + b @ b'"' | b @ b'\'' => { + i += 1; + while i < data.len() { + if data[i] == b { + return Some(i + 1); + } + if let Some(eol_bytes) = scan_eol(&data[i..]) { + let handler = newline_handler?; + i += eol_bytes; + i += handler(&data[i..]); + } else { + i += 1; + } + } + return None; + } + b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => { + return None; + } + _ => { + // unquoted attribute value + i += scan_attr_value_chars(&data[i..]); + } + } + Some(i) +} + +// Remove backslash escapes and resolve entities +pub(crate) fn unescape(input: &str) -> CowStr<'_> { + let mut result = String::new(); + let mut mark = 0; + let mut i = 0; + let bytes = input.as_bytes(); + while i < bytes.len() { + match bytes[i] { + b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { + result.push_str(&input[mark..i]); + mark = i + 1; + i += 2; + } + b'&' => match scan_entity(&bytes[i..]) { + (n, Some(value)) => { + result.push_str(&input[mark..i]); + result.push_str(&value); + i += n; + mark = i; + } + _ => i += 1, + }, + b'\r' => { + result.push_str(&input[mark..i]); + i += 1; + mark = i; + } + _ => i += 1, + } + } + if mark == 0 { + input.into() + } else { + result.push_str(&input[mark..]); + result.into() + } +} + +/// Assumes `data` is preceded by `<`. +pub(crate) fn scan_html_block_tag(data: &[u8]) -> (usize, &[u8]) { + let i = scan_ch(data, b'/'); + let n = scan_while(&data[i..], is_ascii_alphanumeric); + // TODO: scan attributes and > + (i + n, &data[i..i + n]) +} + +pub(crate) fn is_html_tag(tag: &[u8]) -> bool { + HTML_TAGS + .binary_search_by(|probe| { + let probe_bytes_iter = probe.as_bytes().iter(); + let tag_bytes_iter = tag.iter(); + + probe_bytes_iter + .zip(tag_bytes_iter) + .find_map(|(&a, &b)| { + // We can compare case insensitively because the probes are + // all lower case alpha strings. + match a.cmp(&(b | 0x20)) { + std::cmp::Ordering::Equal => None, + inequality => Some(inequality), + } + }) + .unwrap_or_else(|| probe.len().cmp(&tag.len())) + }) + .is_ok() +} + +/// Assumes that `data` is preceded by `<`. +pub(crate) fn scan_html_type_7(data: &[u8]) -> Option { + // Block type html does not allow for newlines, so we + // do not pass a newline handler. + let i = scan_html_block_inner(data, None)?; + scan_blank_line(&data[i..])?; + Some(i) +} + +// FIXME: instead of a newline handler, maybe this should receive +// a whitespace handler instead. +// With signature `&dyn Fn(&[u8]) -> Option`. +// We currently need to implement whitespace handling in all of +// this function's dependencies as well. +pub(crate) fn scan_html_block_inner( + data: &[u8], + newline_handler: Option<&dyn Fn(&[u8]) -> usize>, +) -> Option { + let close_tag_bytes = scan_ch(data, b'/'); + let l = scan_while(&data[close_tag_bytes..], is_ascii_alpha); + if l == 0 { + return None; + } + let mut i = close_tag_bytes + l; + i += scan_while(&data[i..], is_ascii_letterdigitdash); + + if close_tag_bytes == 0 { + loop { + let old_i = i; + loop { + i += scan_whitespace_no_nl(&data[i..]); + if let Some(eol_bytes) = scan_eol(&data[i..]) { + if eol_bytes == 0 { + return None; + } + if let Some(handler) = newline_handler { + i += eol_bytes; + i += handler(&data[i..]); + } else { + return None; + } + } else { + break; + } + } + if let Some(b'/') | Some(b'>') = data.get(i) { + break; + } + if old_i == i { + // No whitespace, which is mandatory. + return None; + } + i += scan_attribute(&data[i..], newline_handler)?; + } + } + + i += scan_whitespace_no_nl(&data[i..]); + + if close_tag_bytes == 0 { + i += scan_ch(&data[i..], b'/'); + } + + if scan_ch(&data[i..], b'>') == 0 { + None + } else { + Some(i + 1) + } +} + +/// Returns (next_byte_offset, uri, type) +pub(crate) fn scan_autolink(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>, LinkType)> { + scan_uri(text, start_ix) + .map(|(bytes, uri)| (bytes, uri, LinkType::Autolink)) + .or_else(|| scan_email(text, start_ix).map(|(bytes, uri)| (bytes, uri, LinkType::Email))) +} + +/// Returns (next_byte_offset, uri) +fn scan_uri(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { + let bytes = &text.as_bytes()[start_ix..]; + + // scheme's first byte must be an ascii letter + if bytes.is_empty() || !is_ascii_alpha(bytes[0]) { + return None; + } + + let mut i = 1; + + while i < bytes.len() { + let c = bytes[i]; + i += 1; + match c { + c if is_ascii_alphanumeric(c) => (), + b'.' | b'-' | b'+' => (), + b':' => break, + _ => return None, + } + } + + // scheme length must be between 2 and 32 characters long. scheme + // must be followed by colon + if i < 3 || i > 33 { + return None; + } + + while i < bytes.len() { + match bytes[i] { + b'>' => return Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())), + b'\0'..=b' ' | b'<' => return None, + _ => (), + } + i += 1; + } + + None +} + +/// Returns (next_byte_offset, email) +fn scan_email(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { + // using a regex library would be convenient, but doing it by hand is not too bad + let bytes = &text.as_bytes()[start_ix..]; + let mut i = 0; + + while i < bytes.len() { + let c = bytes[i]; + i += 1; + match c { + c if is_ascii_alphanumeric(c) => (), + b'.' | b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' | b'/' | b'=' | b'?' + | b'^' | b'_' | b'`' | b'{' | b'|' | b'}' | b'~' | b'-' => (), + b'@' => break, + _ => return None, + } + } + + loop { + let label_start_ix = i; + let mut fresh_label = true; + + while i < bytes.len() { + match bytes[i] { + c if is_ascii_alphanumeric(c) => (), + b'-' if fresh_label => { + return None; + } + b'-' => (), + _ => break, + } + fresh_label = false; + i += 1; + } + + if i == label_start_ix || i - label_start_ix > 63 || bytes[i - 1] == b'-' { + return None; + } + + if scan_ch(&bytes[i..], b'.') == 0 { + break; + } + i += 1; + } + + if scan_ch(&bytes[i..], b'>') == 0 { + return None; + } + + Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())) +} + +/// Scan comment, declaration, or CDATA section, with initial " Option { + let c = *bytes.get(ix)?; + ix += 1; + match c { + b'-' => { + let dashes = scan_ch_repeat(&bytes[ix..], b'-'); + if dashes < 1 { + return None; + } + // Saw ""##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_5() { + let original = r##"Little header + + +

    Useless

    +]]>"##; + let expected = r##"

    Little header

    + +

    Useless

    +]]>"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_6() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_7() { + let original = r##"Little header +----------- + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_8() { + let original = "A | B\n---|---\nfoo | bar"; + let expected = r##" + +
    AB
    foobar
    +"##; + + let mut s = String::new(); + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + html::push_html(&mut s, Parser::new_ext(&original, opts)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_9() { + let original = "---"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_10() { + let original = "* * *"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +// TODO: add broken link callback feature +/* +#[test] +fn html_test_broken_callback() { + let original = r##"[foo], +[bar], +[baz], + + [baz]: https://example.org +"##; + + let expected = r##"

    foo, +[bar], +baz,

    +"##; + + use pulldown_cmark::{Options, Parser, html}; + + let mut s = String::new(); + + let callback = |reference: &str, _normalized: &str| -> Option<(String, String)> { + if reference == "foo" || reference == "baz" { + Some(("https://replaced.example.org".into(), "some title".into())) + } else { + None + } + }; + + let p = Parser::new_with_broken_link_callback(&original, Options::empty(), Some(&callback)); + html::push_html(&mut s, p); + + assert_eq!(expected, s); +} +*/ diff --git a/vendor/pulldown-cmark-0.7.2/tests/lib.rs b/vendor/pulldown-cmark-0.7.2/tests/lib.rs new file mode 100644 index 0000000000..11be5bcd09 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/lib.rs @@ -0,0 +1,422 @@ +#[macro_use] +extern crate html5ever; +#[macro_use] +extern crate lazy_static; + +use html5ever::serialize::{serialize, SerializeOpts}; +use html5ever::{driver as html, QualName}; +use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle}; +use pulldown_cmark::{Options, Parser}; + +use regex::Regex; +use std::collections::HashSet; +use std::mem; +use std::rc::{Rc, Weak}; +use tendril::stream::TendrilSink; + +mod suite; + +#[inline(never)] +pub fn test_markdown_html(input: &str, output: &str) { + let mut s = String::new(); + + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + + let p = Parser::new_ext(input, opts); + pulldown_cmark::html::push_html(&mut s, p); + + assert_eq!(normalize_html(output), normalize_html(&s)); +} + +lazy_static! { + static ref WHITESPACE_RE: Regex = Regex::new(r"\s+").unwrap(); + static ref LEADING_WHITESPACE_RE: Regex = Regex::new(r"\A\s+").unwrap(); + static ref TRAILING_WHITESPACE_RE: Regex = Regex::new(r"\s+\z").unwrap(); + static ref BLOCK_TAGS: HashSet<&'static str> = [ + "article", + "header", + "aside", + "hgroup", + "blockquote", + "hr", + "iframe", + "body", + "li", + "map", + "button", + "object", + "canvas", + "ol", + "caption", + "output", + "col", + "p", + "colgroup", + "pre", + "dd", + "progress", + "div", + "section", + "dl", + "table", + "td", + "dt", + "tbody", + "embed", + "textarea", + "fieldset", + "tfoot", + "figcaption", + "th", + "figure", + "thead", + "footer", + "tr", + "form", + "ul", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "video", + "script", + "style" + ] + .iter() + .cloned() + .collect(); + static ref WHITESPACE_SENSITIVE_TAGS: HashSet<&'static str> = + ["pre", "code", "h1", "h2", "h3", "h4", "h5", "h6"] + .iter() + .cloned() + .collect(); + static ref TABLE_TAGS: HashSet<&'static str> = ["table", "thead", "tbody", "tr", "td"] + .iter() + .cloned() + .collect(); +} + +fn make_html_parser() -> html::Parser { + html::parse_fragment( + RcDom::default(), + html::ParseOpts::default(), + QualName::new(None, ns!(html), local_name!("div")), + vec![], + ) +} + +fn normalize_html(s: &str) -> String { + let parser = make_html_parser(); + let dom = parser.one(s); + let body: SerializableHandle = normalize_dom(&dom).into(); + let opts = SerializeOpts::default(); + let mut ret_val = Vec::new(); + serialize(&mut ret_val, &body, opts) + .expect("Writing to a string shouldn't fail (expect on OOM)"); + String::from_utf8(ret_val).expect("html5ever should always produce UTF8") +} + +fn normalize_dom(dom: &RcDom) -> Handle { + let body = { + let children = dom.document.children.borrow(); + children[0].clone() + }; + let mut current_level = Vec::new(); + let mut next_level = Vec::new(); + current_level.extend(body.children.borrow().iter().cloned().rev()); + loop { + while let Some(mut node) = current_level.pop() { + let parent = node.parent.replace(None); + node.parent.replace(parent.clone()); + let parent = parent + .expect("a node in the DOM will have a parent, except the root, which is not processed") + .upgrade().expect("a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped"); + let retain = normalize_node(&parent, &mut node); + if !retain { + let mut siblings = parent.children.borrow_mut(); + siblings.retain(|s| !Rc::ptr_eq(&node, s)); + } else { + next_level.extend(node.children.borrow().iter().cloned().rev()); + } + } + if next_level.is_empty() { + break; + }; + mem::swap(&mut next_level, &mut current_level); + } + body +} + +// Returns false if node is an empty text node or an empty tbody. +// Returns true otherwise. +fn normalize_node(parent: &Handle, node: &mut Handle) -> bool { + match node.data { + NodeData::Comment { .. } + | NodeData::Doctype { .. } + | NodeData::Document + | NodeData::ProcessingInstruction { .. } => true, + NodeData::Text { ref contents, .. } => { + let mut contents = contents.borrow_mut(); + let is_pre = { + let mut parent = parent.clone(); + loop { + let is_pre = if let NodeData::Element { ref name, .. } = parent.data { + WHITESPACE_SENSITIVE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + if is_pre { + break true; + }; + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_ + } else { + break false; + }; + } + }; + if !is_pre { + let (is_first_in_block, is_last_in_block) = { + let mut is_first_in_block = true; + let mut is_last_in_block = true; + let mut parent = parent.clone(); + let mut node = node.clone(); + loop { + let reached_block = if let NodeData::Element { ref name, .. } = parent.data + { + BLOCK_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let (is_first, is_last) = { + let siblings = parent.children.borrow(); + let n = &node; + ( + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false), + siblings.len() > 0 + && siblings + .get(siblings.len() - 1) + .map(|s| Rc::ptr_eq(s, n)) + .unwrap_or(false), + ) + }; + is_first_in_block = is_first_in_block && is_first; + is_last_in_block = is_last_in_block && is_last; + if (is_first_in_block || is_last_in_block) && !reached_block { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break (is_first_in_block, is_last_in_block); + } + } else { + break (is_first_in_block, is_last_in_block); + } + } + }; + let is_preceeded_by_ws = { + let mut parent = parent.clone(); + let mut node = node.clone(); + 'ascent: loop { + let is_first = { + let siblings = parent.children.borrow(); + let n = &node; + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false) + }; + if is_first { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break 'ascent false; + } + } else { + let siblings = parent.children.borrow(); + let n = &node; + let mut pos = !0; + 'search: for (i, s) in siblings.iter().enumerate() { + if Rc::ptr_eq(s, n) { + pos = i; + break 'search; + } + } + assert!( + pos != !0, + "The list of node's parent's children shall contain node" + ); + assert!( + pos != 0, + "If node is not first, then node's position shall not be zero" + ); + let mut preceeding = siblings[pos - 1].clone(); + 'descent: loop { + if let NodeData::Text { .. } = preceeding.data { + break 'descent; + } + preceeding = { + let ch = preceeding.children.borrow(); + if ch.len() == 0 { + break 'descent; + } + if let Some(preceeding_) = ch.get(ch.len() - 1) { + preceeding_.clone() + } else { + break 'descent; + } + }; + } + if let NodeData::Text { ref contents, .. } = preceeding.data { + break 'ascent TRAILING_WHITESPACE_RE.is_match(&*contents.borrow()); + } else { + break 'ascent false; + } + } + } + }; + + let is_in_table = if let NodeData::Element { ref name, .. } = parent.data { + TABLE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let whitespace_replacement = if is_in_table { "" } else { " " }; + *contents = WHITESPACE_RE + .replace_all(&*contents, whitespace_replacement) + .as_ref() + .into(); + + if is_first_in_block || is_preceeded_by_ws { + *contents = LEADING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + if is_last_in_block { + *contents = TRAILING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + // TODO: collapse whitespace when adjacent to whitespace. + // For example, the whitespace in the span should be collapsed in all of these cases: + // + // " q " + // "q q" + // "q q" + // "q q" + // "q q" + } + &**contents != "" + } + NodeData::Element { + ref attrs, + ref name, + .. + } => { + let mut attrs = attrs.borrow_mut(); + for a in attrs.iter_mut() { + a.name.local = a.name.local.to_ascii_lowercase().into(); + } + attrs.sort_by(|a: &html5ever::Attribute, b: &html5ever::Attribute| { + (&*a.name.local).cmp(&*b.name.local) + }); + let ascii_name = &*name.local.to_ascii_lowercase(); + // drop empty tbody's + ascii_name != "tbody" + || node.children.borrow().len() > 1 + || node + .children + .borrow() + .iter() + .next() + .map(|only_child| match only_child.data { + NodeData::Text { ref contents, .. } => { + !contents.borrow().chars().all(|c| c.is_whitespace()) + } + _ => true, + }) + .unwrap_or(false) + } + } +} + +#[test] +fn strip_div_newline() { + assert_eq!("
    ", normalize_html("
    \n
    ")); +} + +#[test] +fn strip_end_newline() { + assert_eq!("test", normalize_html("test\n")); +} + +#[test] +fn strip_double_space() { + assert_eq!("test mess", normalize_html("test mess")); +} + +#[test] +fn strip_inline_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn strip_inline_block_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn leaves_necessary_whitespace_alone() { + assert_eq!("a b c", normalize_html("a b c")) +} + +#[test] +fn leaves_necessary_whitespace_alone_weird() { + assert_eq!( + "a b c", + normalize_html(" a b c") + ) +} + +#[test] +fn leaves_necessary_whitespace_all_nested() { + assert_eq!( + "", + normalize_html(" ") + ) +} + +#[test] +fn drops_empty_tbody() { + assert_eq!( + "
    hi
    ", + normalize_html("
    hi
    ") + ) +} + +#[test] +fn leaves_nonempty_tbody() { + let input = "
    hi
    "; + assert_eq!(input, normalize_html(input)) +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/footnotes.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/footnotes.rs new file mode 100644 index 0000000000..e31eff54b6 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/footnotes.rs @@ -0,0 +1,165 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn footnotes_test_1() { + let original = r##"Lorem ipsum.[^a] + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_2() { + let original = r##"> This is the song that never ends.\ +> Yes it goes on and on my friends.[^lambchops] +> +> [^lambchops]: +"##; + let expected = r##"
    +

    This is the song that never ends.
    +Yes it goes on and on my friends.1

    + +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_3() { + let original = r##"Songs that simply loop are a popular way to annoy people. [^examples] + +[^examples]: + * [The song that never ends](https://www.youtube.com/watch?v=0U2zJOryHKQ) + * [I know a song that gets on everybody's nerves](https://www.youtube.com/watch?v=TehWI09qxls) + * [Ninety-nine bottles of beer on the wall](https://www.youtube.com/watch?v=qVjCag8XoHQ) +"##; + let expected = r##"

    Songs that simply loop are a popular way to annoy people. 1

    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_4() { + let original = r##"[^lorem]: If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research. + +I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp. +"##; + let expected = r##"
    1 +

    If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research.

    +
    +

    I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_5() { + let original = r##"[^ipsum]: How much wood would a woodchuck chuck. + +If a woodchuck could chuck wood. + + +# Forms of entertainment that aren't childish +"##; + let expected = r##"
    1 +

    How much wood would a woodchuck chuck.

    +
    +

    If a woodchuck could chuck wood.

    +

    Forms of entertainment that aren't childish

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_6() { + let original = r##"> He's also really stupid. [^why] +> +> [^why]: Because your mamma! + +As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet. +"##; + let expected = r##"
    +

    He's also really stupid. 1

    +
    1 +

    Because your mamma!

    +
    +
    +

    As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_7() { + let original = r##"Nested footnotes are considered poor style. [^a] [^xkcd] + +[^a]: This does not mean that footnotes cannot reference each other. [^b] + +[^b]: This means that a footnote definition cannot be directly inside another footnote definition. +> This means that a footnote cannot be directly inside another footnote's body. [^e] +> +> [^e]: They can, however, be inside anything else. + +[^xkcd]: [The other kind of nested footnote is, however, considered poor style.](https://xkcd.com/1208/) +"##; + let expected = r##"

    Nested footnotes are considered poor style. 1 2

    +
    1 +

    This does not mean that footnotes cannot reference each other. 3

    +
    +
    3 +

    This means that a footnote definition cannot be directly inside another footnote definition.

    +
    +

    This means that a footnote cannot be directly inside another footnote's body. 4

    +
    4 +

    They can, however, be inside anything else.

    +
    +
    +
    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn footnotes_test_8() { + let original = r##"[^Doh] Ray Me Fa So La Te Do! [^1] + +[^Doh]: I know. Wrong Doe. And it won't render right. +[^1]: Common for people practicing music. +"##; + let expected = r##"

    1 Ray Me Fa So La Te Do! 2

    +
    1 +

    I know. Wrong Doe. And it won't render right. +2: Common for people practicing music.

    +
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_strikethrough.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_strikethrough.rs new file mode 100644 index 0000000000..b8fd293980 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_strikethrough.rs @@ -0,0 +1,27 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_strikethrough_test_1() { + let original = r##"~~Hi~~ Hello, world! +"##; + let expected = r##"

    Hi Hello, world!

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_strikethrough_test_2() { + let original = r##"This ~~has a + +new paragraph~~. +"##; + let expected = r##"

    This ~~has a

    +

    new paragraph~~.

    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_table.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_table.rs new file mode 100644 index 0000000000..0e286b6b77 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_table.rs @@ -0,0 +1,205 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_table_test_1() { + let original = r##"| foo | bar | +| --- | --- | +| baz | bim | +"##; + let expected = r##" + + + + + + + + + + + + +
    foobar
    bazbim
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_2() { + let original = r##"| abc | defghi | +:-: | -----------: +bar | baz +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdefghi
    barbaz
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_3() { + let original = r##"| f\|oo | +| ------ | +| b `\|` az | +| b **\|** im | +"##; + let expected = r##" + + + + + + + + + + + + + +
    f|oo
    b \| az
    b | im
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_4() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +> bar +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdef
    barbaz
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_5() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +bar + +bar +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    barbaz
    bar
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_6() { + let original = r##"| abc | def | +| --- | +| bar | +"##; + let expected = r##"

    | abc | def | +| --- | +| bar |

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_7() { + let original = r##"| abc | def | +| --- | --- | +| bar | +| bar | baz | boo | +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    bar
    barbaz
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_table_test_8() { + let original = r##"| abc | def | +| --- | --- | +"##; + let expected = r##" + + + + + + +
    abcdef
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_tasklist.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_tasklist.rs new file mode 100644 index 0000000000..ca80369f99 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/gfm_tasklist.rs @@ -0,0 +1,39 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_tasklist_test_1() { + let original = r##"- [ ] foo +- [x] bar +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn gfm_tasklist_test_2() { + let original = r##"- [x] foo + - [ ] bar + - [x] baz +- [ ] bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar
      • +
      • baz
      • +
      +
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/mod.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/mod.rs new file mode 100644 index 0000000000..aa05206085 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/mod.rs @@ -0,0 +1,12 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +pub use super::test_markdown_html; + +mod footnotes; +mod regression; +mod table; +mod spec; +mod gfm_table; +mod gfm_strikethrough; +mod gfm_tasklist; diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/regression.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/regression.rs new file mode 100644 index 0000000000..5c723aacf1 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/regression.rs @@ -0,0 +1,904 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn regression_test_1() { + let original = r##"
    Testing 1..2..3.. + +This is a test of the details element. + +
    +"##; + let expected = r##"
    Testing 1..2..3.. +

    This is a test of the details element.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_2() { + let original = r##"see the [many] [articles] [on] [QuickCheck]. + +[many]: https://medium.com/@jlouis666/quickcheck-advice-c357efb4e7e6 +[articles]: http://www.quviq.com/products/erlang-quickcheck/ +[on]: https://wiki.haskell.org/Introduction_to_QuickCheck1 +[QuickCheck]: https://hackage.haskell.org/package/QuickCheck +"##; + let expected = r##"

    see the + many + articles + on + QuickCheck. +

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_3() { + let original = r##"[![debug-stub-derive on crates.io][cratesio-image]][cratesio] +[![debug-stub-derive on docs.rs][docsrs-image]][docsrs] + +[cratesio-image]: https://img.shields.io/crates/v/debug_stub_derive.svg +[cratesio]: https://crates.io/crates/debug_stub_derive +[docsrs-image]: https://docs.rs/debug_stub_derive/badge.svg?version=0.3.0 +[docsrs]: https://docs.rs/debug_stub_derive/0.3.0/ +"##; + let expected = r##"

    debug-stub-derive on crates.io +debug-stub-derive on docs.rs

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_4() { + let original = r##"| Title A | Title B | +| --------- | --------- | +| Content | Content | + +| Title A | Title B | Title C | Title D | +| --------- | --------- | --------- | ---------:| +| Content | Content | Conent | Content | +"##; + let expected = r##" + +
    Title A Title B
    Content Content
    + + +
    Title A Title B Title C Title D
    Content Content Conent Content
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_5() { + let original = r##"foo§__(bar)__ +"##; + let expected = r##"

    foo§(bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_6() { + let original = r##" hello +"##; + let expected = r##"

    https://example.com hello

    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_7() { + let original = r##"[foo][bar] + + +[bar]: a +"##; + let expected = r##"

    foo

    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_8() { + let original = r##" +- **foo** (u8, u8) + + make something + +- **bar** (u16, u16) + + make something +"##; + let expected = r##" +
      +
    • +

      foo (u8, u8)

      +

      make something

      +
    • +
    • +

      bar (u16, u16)

      +

      make something

      +
    • +
    + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_9() { + let original = r##"[` +i8 +`]( +../../../std/primitive.i8.html +) +"##; + let expected = r##"

    i8

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_10() { + let original = r##"[a] + +[a]: /url (title\\*) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_11() { + let original = r##"[a] + +[a]: /url (title\)) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_12() { + let original = r##"[a] + +[a]: /url (title)) +"##; + let expected = r##"

    [a]

    +

    [a]: /url (title))

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_13() { + let original = r##"a +"##; + let expected = r##"

    a <?php this is not a valid processing tag

    +

    b

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_14() { + let original = r##"[a]: u\ +foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_15() { + let original = r##"\`foo` +"##; + let expected = r##"

    `foo`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_16() { + let original = r##"foo\\ +bar +"##; + let expected = r##"

    foo\ +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_17() { + let original = r##"1\. foo + +1\) bar +"##; + let expected = r##"

    1. foo

    +

    1) bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_18() { + let original = r##"1... + +1.2.3. + +1 2 3 . + +1.|2.-3. + +1)2)3) +"##; + let expected = r##"

    1...

    +

    1.2.3.

    +

    1 2 3 .

    +

    1.|2.-3.

    +

    1)2)3)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_19() { + let original = r##"[](<<>) +"##; + let expected = r##"

    [](<<>)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_20() { + let original = r##"\``foo``bar` +"##; + let expected = r##"

    `foo``bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_21() { + let original = r##"\\`foo` +"##; + let expected = r##"

    \foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_22() { + let original = r##"[\\]: x + +YOLO +"##; + let expected = r##"

    YOLO

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_23() { + let original = r##"lorem ipsum +A | B +---|--- +foo | bar +"##; + let expected = r##"

    lorem ipsum +A | B +---|--- +foo | bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_24() { + let original = r##"foo|bar +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar
    foobar
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_25() { + let original = r##"foo|bar\\ +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar\
    foobar
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_26() { + let original = r##"[](url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_27() { + let original = r##"[bar](url) +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_28() { + let original = r##"![](http://example.com/logo.png) +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_29() { + let original = r##"[ ](url) +"##; + let expected = r##"

    http://one http://two

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_30() { + let original = r##"Markdown | Less | Pretty +--- | --- | --- + +some text +"##; + let expected = r##" +
    Markdown Less Pretty
    +

    some text

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_31() { + let original = r##"1. > foo +2. > +"##; + let expected = r##"
      +
    1. +
      +

      foo

      +
      +
    2. +
    3. +
      +
      +
    4. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_32() { + let original = r##"[ +x + +]: f +"##; + let expected = r##"

    [ +x

    +

    ]: f

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_33() { + let original = r##"[foo]: +"##; + let expected = r##"

    [foo]:

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_34() { + let original = r##"> foo | bar +> --- | --- +yolo | swag +"##; + let expected = r##"
    +
    foobar
    +
    +

    yolo | swag

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_35() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_36() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_37() { + let original = r##"~~*_**__ + +__a__ +"##; + let expected = r##"

    ~~*_**__

    +

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_38() { + let original = r##"> ` +> ` +"##; + let expected = r##"
    +

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_39() { + let original = r##"`\|` +"##; + let expected = r##"

    \|

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_40() { + let original = r##"Paragraph 1 + +Paragraph 2 +"##; + let expected = r##"

    Paragraph 1

    +

    Paragraph 2

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_41() { + let original = r##"\[[link text](https://www.google.com/)\] +"##; + let expected = r##"

    [link text]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_42() { + let original = r##"foo | bar +--- | --- +[a](< | url>) +"##; + let expected = r##"
    foobar
    [a](<url>)
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_43() { + let original = r##"[a](url " +- - - +") +"##; + let expected = r##"

    [a](url "

    +
    +

    ")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_44() { + let original = r##"[a](url + +) +"##; + let expected = r##"

    [a](url

    +

    )

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_45() { + let original = r##"[a](b " + +") +"##; + let expected = r##"

    [a](b "

    +

    ")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_46() { + let original = r##" +"##; + let expected = r##"

    <http:// >

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_47() { + let original = r##" +"##; + let expected = r##"

    <http://>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_48() { + let original = r##"foo | bar +--- | --- + + +foobar + + +<http://baz + + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_49() { + let original = r##"foo | bar +--- | --- + +"##; + let expected = r##" + + + + + + +
    foobar
    <http://>
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_50() { + let original = r##"\*hi\_ +"##; + let expected = r##"

    *hi_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_51() { + let original = r##"email: \_ +"##; + let expected = r##"

    email: john@example.com_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_52() { + let original = r##"> [link](/url 'foo +> bar') +"##; + let expected = r##"
    +

    link

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_53() { + let original = r##"> [foo +> bar]: /url +> +> [foo bar] +"##; + let expected = r##"
    +

    foo bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_54() { + let original = r##"> [foo bar]: /url +> +> [foo +> bar] +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_55() { + let original = r##"> - [a +> b c]: /foo + +[a b c] +"##; + let expected = r##"
    +
      +
    • +
    +
    +

    a b c

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_56() { + let original = r##"[a +> b]: /foo + +[a b] [a > b] +"##; + let expected = r##"

    [a

    +
    +

    b]: /foo

    +
    +

    [a b] [a > b]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_57() { + let original = r##"[`cargo +package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"

    cargo package

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_58() { + let original = r##"> [`cargo +> package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"
    +

    cargo package

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_59() { + let original = r##"> `cargo +> package` +"##; + let expected = r##"
    +

    cargo package

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_60() { + let original = r##"Lorem ipsum.[^a] + +An unordered list before the footnotes: +* Ipsum +* Lorem + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +

    An unordered list before the footnotes:

    +
      +
    • Ipsum
    • +
    • Lorem
    • +
    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_61() { + let original = r##"[][a] + +[a]: b + +# assimp-rs [![][crates-badge]][crates] + +[crates]: https://crates.io/crates/assimp +[crates-badge]: http://meritbadge.herokuapp.com/assimp +"##; + let expected = r##"

    + +

    assimp-rs

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_62() { + let original = r##"* A list. + + * A sublist. + + * Another sublist. + + +* A list. + + * A sublist. + + * Another sublist. + +"##; + let expected = r##"
      +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn regression_test_63() { + let original = r##"<foo

    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/spec.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/spec.rs new file mode 100644 index 0000000000..0215dd4b89 --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/spec.rs @@ -0,0 +1,8447 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn spec_test_1() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_2() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_3() { + let original = r##" a a + ὐ a +"##; + let expected = r##"
    a	a
    +ὐ	a
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_4() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_5() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
        bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_6() { + let original = r##"> foo +"##; + let expected = r##"
    +
      foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_7() { + let original = r##"- foo +"##; + let expected = r##"
      +
    • +
        foo
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_8() { + let original = r##" foo + bar +"##; + let expected = r##"
    foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_9() { + let original = r##" - foo + - bar + - baz +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_10() { + let original = r##"# Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_11() { + let original = r##"* * * +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_12() { + let original = r##"- `one +- two` +"##; + let expected = r##"
      +
    • `one
    • +
    • two`
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_13() { + let original = r##"*** +--- +___ +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_14() { + let original = r##"+++ +"##; + let expected = r##"

    +++

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_15() { + let original = r##"=== +"##; + let expected = r##"

    ===

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_16() { + let original = r##"-- +** +__ +"##; + let expected = r##"

    -- +** +__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_17() { + let original = r##" *** + *** + *** +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_18() { + let original = r##" *** +"##; + let expected = r##"
    ***
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_19() { + let original = r##"Foo + *** +"##; + let expected = r##"

    Foo +***

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_20() { + let original = r##"_____________________________________ +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_21() { + let original = r##" - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_22() { + let original = r##" ** * ** * ** * ** +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_23() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_24() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_25() { + let original = r##"_ _ _ _ a + +a------ + +---a--- +"##; + let expected = r##"

    _ _ _ _ a

    +

    a------

    +

    ---a---

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_26() { + let original = r##" *-* +"##; + let expected = r##"

    -

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_27() { + let original = r##"- foo +*** +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_28() { + let original = r##"Foo +*** +bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_29() { + let original = r##"Foo +--- +bar +"##; + let expected = r##"

    Foo

    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_30() { + let original = r##"* Foo +* * * +* Bar +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +
      +
    • Bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_31() { + let original = r##"- Foo +- * * * +"##; + let expected = r##"
      +
    • Foo
    • +
    • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_32() { + let original = r##"# foo +## foo +### foo +#### foo +##### foo +###### foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +

    foo

    +
    foo
    +
    foo
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_33() { + let original = r##"####### foo +"##; + let expected = r##"

    ####### foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_34() { + let original = r##"#5 bolt + +#hashtag +"##; + let expected = r##"

    #5 bolt

    +

    #hashtag

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_35() { + let original = r##"\## foo +"##; + let expected = r##"

    ## foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_36() { + let original = r##"# foo *bar* \*baz\* +"##; + let expected = r##"

    foo bar *baz*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_37() { + let original = r##"# foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_38() { + let original = r##" ### foo + ## foo + # foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_39() { + let original = r##" # foo +"##; + let expected = r##"
    # foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_40() { + let original = r##"foo + # bar +"##; + let expected = r##"

    foo +# bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_41() { + let original = r##"## foo ## + ### bar ### +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_42() { + let original = r##"# foo ################################## +##### foo ## +"##; + let expected = r##"

    foo

    +
    foo
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_43() { + let original = r##"### foo ### +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_44() { + let original = r##"### foo ### b +"##; + let expected = r##"

    foo ### b

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_45() { + let original = r##"# foo# +"##; + let expected = r##"

    foo#

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_46() { + let original = r##"### foo \### +## foo #\## +# foo \# +"##; + let expected = r##"

    foo ###

    +

    foo ###

    +

    foo #

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_47() { + let original = r##"**** +## foo +**** +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_48() { + let original = r##"Foo bar +# baz +Bar foo +"##; + let expected = r##"

    Foo bar

    +

    baz

    +

    Bar foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_49() { + let original = r##"## +# +### ### +"##; + let expected = r##"

    +

    +

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_50() { + let original = r##"Foo *bar* +========= + +Foo *bar* +--------- +"##; + let expected = r##"

    Foo bar

    +

    Foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_51() { + let original = r##"Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_52() { + let original = r##" Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_53() { + let original = r##"Foo +------------------------- + +Foo += +"##; + let expected = r##"

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_54() { + let original = r##" Foo +--- + + Foo +----- + + Foo + === +"##; + let expected = r##"

    Foo

    +

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_55() { + let original = r##" Foo + --- + + Foo +--- +"##; + let expected = r##"
    Foo
    +---
    +
    +Foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_56() { + let original = r##"Foo + ---- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_57() { + let original = r##"Foo + --- +"##; + let expected = r##"

    Foo +---

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_58() { + let original = r##"Foo += = + +Foo +--- - +"##; + let expected = r##"

    Foo += =

    +

    Foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_59() { + let original = r##"Foo +----- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_60() { + let original = r##"Foo\ +---- +"##; + let expected = r##"

    Foo\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_61() { + let original = r##"`Foo +---- +` + + +"##; + let expected = r##"

    `Foo

    +

    `

    +

    <a title="a lot

    +

    of dashes"/>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_62() { + let original = r##"> Foo +--- +"##; + let expected = r##"
    +

    Foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_63() { + let original = r##"> foo +bar +=== +"##; + let expected = r##"
    +

    foo +bar +===

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_64() { + let original = r##"- Foo +--- +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_65() { + let original = r##"Foo +Bar +--- +"##; + let expected = r##"

    Foo +Bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_66() { + let original = r##"--- +Foo +--- +Bar +--- +Baz +"##; + let expected = r##"
    +

    Foo

    +

    Bar

    +

    Baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_67() { + let original = r##" +==== +"##; + let expected = r##"

    ====

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_68() { + let original = r##"--- +--- +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_69() { + let original = r##"- foo +----- +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_70() { + let original = r##" foo +--- +"##; + let expected = r##"
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_71() { + let original = r##"> foo +----- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_72() { + let original = r##"\> foo +------ +"##; + let expected = r##"

    > foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_73() { + let original = r##"Foo + +bar +--- +baz +"##; + let expected = r##"

    Foo

    +

    bar

    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_74() { + let original = r##"Foo +bar + +--- + +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_75() { + let original = r##"Foo +bar +* * * +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_76() { + let original = r##"Foo +bar +\--- +baz +"##; + let expected = r##"

    Foo +bar +--- +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_77() { + let original = r##" a simple + indented code block +"##; + let expected = r##"
    a simple
    +  indented code block
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_78() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_79() { + let original = r##"1. foo + + - bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_80() { + let original = r##"
    + *hi* + + - one +"##; + let expected = r##"
    <a/>
    +*hi*
    +
    +- one
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_81() { + let original = r##" chunk1 + + chunk2 + + + + chunk3 +"##; + let expected = r##"
    chunk1
    +
    +chunk2
    +
    +
    +
    +chunk3
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_82() { + let original = r##" chunk1 + + chunk2 +"##; + let expected = r##"
    chunk1
    +  
    +  chunk2
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_83() { + let original = r##"Foo + bar + +"##; + let expected = r##"

    Foo +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_84() { + let original = r##" foo +bar +"##; + let expected = r##"
    foo
    +
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_85() { + let original = r##"# Heading + foo +Heading +------ + foo +---- +"##; + let expected = r##"

    Heading

    +
    foo
    +
    +

    Heading

    +
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_86() { + let original = r##" foo + bar +"##; + let expected = r##"
        foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_87() { + let original = r##" + + foo + + +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_88() { + let original = r##" foo +"##; + let expected = r##"
    foo  
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_89() { + let original = r##"``` +< + > +``` +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_90() { + let original = r##"~~~ +< + > +~~~ +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_91() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_92() { + let original = r##"``` +aaa +~~~ +``` +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_93() { + let original = r##"~~~ +aaa +``` +~~~ +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_94() { + let original = r##"```` +aaa +``` +`````` +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_95() { + let original = r##"~~~~ +aaa +~~~ +~~~~ +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_96() { + let original = r##"``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_97() { + let original = r##"````` + +``` +aaa +"##; + let expected = r##"
    
    +```
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_98() { + let original = r##"> ``` +> aaa + +bbb +"##; + let expected = r##"
    +
    aaa
    +
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_99() { + let original = r##"``` + + +``` +"##; + let expected = r##"
    
    +  
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_100() { + let original = r##"``` +``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_101() { + let original = r##" ``` + aaa +aaa +``` +"##; + let expected = r##"
    aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_102() { + let original = r##" ``` +aaa + aaa +aaa + ``` +"##; + let expected = r##"
    aaa
    +aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_103() { + let original = r##" ``` + aaa + aaa + aaa + ``` +"##; + let expected = r##"
    aaa
    + aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_104() { + let original = r##" ``` + aaa + ``` +"##; + let expected = r##"
    ```
    +aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_105() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_106() { + let original = r##" ``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_107() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +    ```
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_108() { + let original = r##"``` ``` +aaa +"##; + let expected = r##"

    +aaa

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_109() { + let original = r##"~~~~~~ +aaa +~~~ ~~ +"##; + let expected = r##"
    aaa
    +~~~ ~~
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_110() { + let original = r##"foo +``` +bar +``` +baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_111() { + let original = r##"foo +--- +~~~ +bar +~~~ +# baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_112() { + let original = r##"```ruby +def foo(x) + return 3 +end +``` +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_113() { + let original = r##"~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_114() { + let original = r##"````; +```` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_115() { + let original = r##"``` aa ``` +foo +"##; + let expected = r##"

    aa +foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_116() { + let original = r##"~~~ aa ``` ~~~ +foo +~~~ +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_117() { + let original = r##"``` +``` aaa +``` +"##; + let expected = r##"
    ``` aaa
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_118() { + let original = r##"
    +
    +**Hello**,
    +
    +_world_.
    +
    +
    +"##; + let expected = r##"
    +
    +**Hello**,
    +

    world. +

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_119() { + let original = r##" + + + +
    + hi +
    + +okay. +"##; + let expected = r##" + + + +
    + hi +
    +

    okay.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_120() { + let original = r##"
    +*foo* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_122() { + let original = r##"
    + +*Markdown* + +
    +"##; + let expected = r##"
    +

    Markdown

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_123() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_124() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_125() { + let original = r##"
    +*foo* + +*bar* +"##; + let expected = r##"
    +*foo* +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_126() { + let original = r##"
    +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_130() { + let original = r##"
    +foo +
    +"##; + let expected = r##"
    +foo +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_131() { + let original = r##"
    +``` c +int x = 33; +``` +"##; + let expected = r##"
    +``` c +int x = 33; +``` +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_132() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_133() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_134() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_135() { + let original = r##" +*bar* +"##; + let expected = r##" +*bar* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_136() { + let original = r##" +*foo* + +"##; + let expected = r##" +*foo* + +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_137() { + let original = r##" + +*foo* + + +"##; + let expected = r##" +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_138() { + let original = r##"*foo* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_139() { + let original = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +okay +"##; + let expected = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_140() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_141() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_142() { + let original = r##" +*foo* +"##; + let expected = r##" +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_146() { + let original = r##"*bar* +*baz* +"##; + let expected = r##"*bar* +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_147() { + let original = r##"1. *bar* +"##; + let expected = r##"1. *bar* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_148() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_149() { + let original = r##"'; + +?> +okay +"##; + let expected = r##"'; + +?> +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_150() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_151() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_152() { + let original = r##" + + +"##; + let expected = r##" +
    <!-- foo -->
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_153() { + let original = r##"
    + +
    +"##; + let expected = r##"
    +
    <div>
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_154() { + let original = r##"Foo +
    +bar +
    +"##; + let expected = r##"

    Foo

    +
    +bar +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_155() { + let original = r##"
    +bar +
    +*foo* +"##; + let expected = r##"
    +bar +
    +*foo* +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_156() { + let original = r##"Foo + +baz +"##; + let expected = r##"

    Foo + +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_157() { + let original = r##"
    + +*Emphasized* text. + +
    +"##; + let expected = r##"
    +

    Emphasized text.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_158() { + let original = r##"
    +*Emphasized* text. +
    +"##; + let expected = r##"
    +*Emphasized* text. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_159() { + let original = r##" + + + + + + + +
    +Hi +
    +"##; + let expected = r##" + + + +
    +Hi +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_160() { + let original = r##" + + + + + + + +
    + Hi +
    +"##; + let expected = r##" + +
    <td>
    +  Hi
    +</td>
    +
    + +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_161() { + let original = r##"[foo]: /url "title" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_162() { + let original = r##" [foo]: + /url + 'the title' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_163() { + let original = r##"[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +"##; + let expected = r##"

    Foo*bar]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_164() { + let original = r##"[Foo bar]: + +'title' + +[Foo bar] +"##; + let expected = r##"

    Foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_165() { + let original = r##"[foo]: /url ' +title +line1 +line2 +' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_166() { + let original = r##"[foo]: /url 'title + +with blank line' + +[foo] +"##; + let expected = r##"

    [foo]: /url 'title

    +

    with blank line'

    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_167() { + let original = r##"[foo]: +/url + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_168() { + let original = r##"[foo]: + +[foo] +"##; + let expected = r##"

    [foo]:

    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_169() { + let original = r##"[foo]: <> + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_170() { + let original = r##"[foo]: (baz) + +[foo] +"##; + let expected = r##"

    [foo]: (baz)

    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_171() { + let original = r##"[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_172() { + let original = r##"[foo] + +[foo]: url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_173() { + let original = r##"[foo] + +[foo]: first +[foo]: second +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_174() { + let original = r##"[FOO]: /url + +[Foo] +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_175() { + let original = r##"[ΑΓΩ]: /φου + +[αγω] +"##; + let expected = r##"

    αγω

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_176() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_177() { + let original = r##"[ +foo +]: /url +bar +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_178() { + let original = r##"[foo]: /url "title" ok +"##; + let expected = r##"

    [foo]: /url "title" ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_179() { + let original = r##"[foo]: /url +"title" ok +"##; + let expected = r##"

    "title" ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_180() { + let original = r##" [foo]: /url "title" + +[foo] +"##; + let expected = r##"
    [foo]: /url "title"
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_181() { + let original = r##"``` +[foo]: /url +``` + +[foo] +"##; + let expected = r##"
    [foo]: /url
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_182() { + let original = r##"Foo +[bar]: /baz + +[bar] +"##; + let expected = r##"

    Foo +[bar]: /baz

    +

    [bar]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_183() { + let original = r##"# [Foo] +[foo]: /url +> bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_184() { + let original = r##"[foo]: /url +bar +=== +[foo] +"##; + let expected = r##"

    bar

    +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_185() { + let original = r##"[foo]: /url +=== +[foo] +"##; + let expected = r##"

    === +foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_186() { + let original = r##"[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +"##; + let expected = r##"

    foo, +bar, +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_187() { + let original = r##"[foo] + +> [foo]: /url +"##; + let expected = r##"

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_188() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_189() { + let original = r##"aaa + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_190() { + let original = r##"aaa +bbb + +ccc +ddd +"##; + let expected = r##"

    aaa +bbb

    +

    ccc +ddd

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_191() { + let original = r##"aaa + + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_192() { + let original = r##" aaa + bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_193() { + let original = r##"aaa + bbb + ccc +"##; + let expected = r##"

    aaa +bbb +ccc

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_194() { + let original = r##" aaa +bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_195() { + let original = r##" aaa +bbb +"##; + let expected = r##"
    aaa
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_196() { + let original = r##"aaa +bbb +"##; + let expected = r##"

    aaa
    +bbb

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_197() { + let original = r##" + +aaa + + +# aaa + + +"##; + let expected = r##"

    aaa

    +

    aaa

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_198() { + let original = r##"> # Foo +> bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_199() { + let original = r##"># Foo +>bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_200() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_201() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    > # Foo
    +> bar
    +> baz
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_202() { + let original = r##"> # Foo +> bar +baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_203() { + let original = r##"> bar +baz +> foo +"##; + let expected = r##"
    +

    bar +baz +foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_204() { + let original = r##"> foo +--- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_205() { + let original = r##"> - foo +- bar +"##; + let expected = r##"
    +
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_206() { + let original = r##"> foo + bar +"##; + let expected = r##"
    +
    foo
    +
    +
    +
    bar
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_207() { + let original = r##"> ``` +foo +``` +"##; + let expected = r##"
    +
    +
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_208() { + let original = r##"> foo + - bar +"##; + let expected = r##"
    +

    foo +- bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_209() { + let original = r##"> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_210() { + let original = r##"> +> +> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_211() { + let original = r##"> +> foo +> +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_212() { + let original = r##"> foo + +> bar +"##; + let expected = r##"
    +

    foo

    +
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_213() { + let original = r##"> foo +> bar +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_214() { + let original = r##"> foo +> +> bar +"##; + let expected = r##"
    +

    foo

    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_215() { + let original = r##"foo +> bar +"##; + let expected = r##"

    foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_216() { + let original = r##"> aaa +*** +> bbb +"##; + let expected = r##"
    +

    aaa

    +
    +
    +
    +

    bbb

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_217() { + let original = r##"> bar +baz +"##; + let expected = r##"
    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_218() { + let original = r##"> bar + +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_219() { + let original = r##"> bar +> +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_220() { + let original = r##"> > > foo +bar +"##; + let expected = r##"
    +
    +
    +

    foo +bar

    +
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_221() { + let original = r##">>> foo +> bar +>>baz +"##; + let expected = r##"
    +
    +
    +

    foo +bar +baz

    +
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_222() { + let original = r##"> code + +> not code +"##; + let expected = r##"
    +
    code
    +
    +
    +
    +

    not code

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_223() { + let original = r##"A paragraph +with two lines. + + indented code + +> A block quote. +"##; + let expected = r##"

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_224() { + let original = r##"1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_225() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +

    two

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_226() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_227() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +
     two
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_228() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_229() { + let original = r##" > > 1. one +>> +>> two +"##; + let expected = r##"
    +
    +
      +
    1. +

      one

      +

      two

      +
    2. +
    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_230() { + let original = r##">>- one +>> + > > two +"##; + let expected = r##"
    +
    +
      +
    • one
    • +
    +

    two

    +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_231() { + let original = r##"-one + +2.two +"##; + let expected = r##"

    -one

    +

    2.two

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_232() { + let original = r##"- foo + + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_233() { + let original = r##"1. foo + + ``` + bar + ``` + + baz + + > bam +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +

      baz

      +
      +

      bam

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_234() { + let original = r##"- Foo + + bar + + + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
      bar
      +
      +
      +baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_235() { + let original = r##"123456789. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_236() { + let original = r##"1234567890. not ok +"##; + let expected = r##"

    1234567890. not ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_237() { + let original = r##"0. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_238() { + let original = r##"003. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_239() { + let original = r##"-1. not ok +"##; + let expected = r##"

    -1. not ok

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_240() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
      bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_241() { + let original = r##" 10. foo + + bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_242() { + let original = r##" indented code + +paragraph + + more code +"##; + let expected = r##"
    indented code
    +
    +

    paragraph

    +
    more code
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_243() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
      indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_244() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
       indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_245() { + let original = r##" foo + +bar +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_246() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • foo
    • +
    +

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_247() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_248() { + let original = r##"- + foo +- + ``` + bar + ``` +- + baz +"##; + let expected = r##"
      +
    • foo
    • +
    • +
      bar
      +
      +
    • +
    • +
      baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_249() { + let original = r##"- + foo +"##; + let expected = r##"
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_250() { + let original = r##"- + + foo +"##; + let expected = r##"
      +
    • +
    +

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_251() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_252() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_253() { + let original = r##"1. foo +2. +3. bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. +
    4. bar
    5. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_254() { + let original = r##"* +"##; + let expected = r##"
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_255() { + let original = r##"foo +* + +foo +1. +"##; + let expected = r##"

    foo +*

    +

    foo +1.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_256() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_257() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_258() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_259() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
    1.  A paragraph
    +    with two lines.
    +
    +        indented code
    +
    +    > A block quote.
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_260() { + let original = r##" 1. A paragraph +with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_261() { + let original = r##" 1. A paragraph + with two lines. +"##; + let expected = r##"
      +
    1. A paragraph +with two lines.
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_262() { + let original = r##"> 1. > Blockquote +continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_263() { + let original = r##"> 1. > Blockquote +> continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_264() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz +
            +
          • boo
          • +
          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_265() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    • baz
    • +
    • boo
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_266() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_267() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_268() { + let original = r##"- - foo +"##; + let expected = r##"
      +
    • +
        +
      • foo
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_269() { + let original = r##"1. - 2. foo +"##; + let expected = r##"
      +
    1. +
        +
      • +
          +
        1. foo
        2. +
        +
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_270() { + let original = r##"- # Foo +- Bar + --- + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
    • +
    • +

      Bar

      +baz
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_271() { + let original = r##"- foo +- bar ++ baz +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +
      +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_272() { + let original = r##"1. foo +2. bar +3) baz +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. bar
    4. +
    +
      +
    1. baz
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_273() { + let original = r##"Foo +- bar +- baz +"##; + let expected = r##"

    Foo

    +
      +
    • bar
    • +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_274() { + let original = r##"The number of windows in my house is +14. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is +14. The number of doors is 6.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_275() { + let original = r##"The number of windows in my house is +1. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is

    +
      +
    1. The number of doors is 6.
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_276() { + let original = r##"- foo + +- bar + + +- baz +"##; + let expected = r##"
      +
    • +

      foo

      +
    • +
    • +

      bar

      +
    • +
    • +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_277() { + let original = r##"- foo + - bar + - baz + + + bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • +

          baz

          +

          bim

          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_278() { + let original = r##"- foo +- bar + + + +- baz +- bim +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    + +
      +
    • baz
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_279() { + let original = r##"- foo + + notcode + +- foo + + + + code +"##; + let expected = r##"
      +
    • +

      foo

      +

      notcode

      +
    • +
    • +

      foo

      +
    • +
    + +
    code
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_280() { + let original = r##"- a + - b + - c + - d + - e + - f +- g +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d
    • +
    • e
    • +
    • f
    • +
    • g
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_281() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    5. +

      c

      +
    6. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_282() { + let original = r##"- a + - b + - c + - d + - e +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d +- e
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_283() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    +
    3. c
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_284() { + let original = r##"- a +- b + +- c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_285() { + let original = r##"* a +* + +* c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_286() { + let original = r##"- a +- b + + c +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +

      c

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_287() { + let original = r##"- a +- b + + [ref]: /url +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_288() { + let original = r##"- a +- ``` + b + + + ``` +- c +"##; + let expected = r##"
      +
    • a
    • +
    • +
      b
      +
      +
      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_289() { + let original = r##"- a + - b + + c +- d +"##; + let expected = r##"
      +
    • a +
        +
      • +

        b

        +

        c

        +
      • +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_290() { + let original = r##"* a + > b + > +* c +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_291() { + let original = r##"- a + > b + ``` + c + ``` +- d +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
      c
      +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_292() { + let original = r##"- a +"##; + let expected = r##"
      +
    • a
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_293() { + let original = r##"- a + - b +"##; + let expected = r##"
      +
    • a +
        +
      • b
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_294() { + let original = r##"1. ``` + foo + ``` + + bar +"##; + let expected = r##"
      +
    1. +
      foo
      +
      +

      bar

      +
    2. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_295() { + let original = r##"* foo + * bar + + baz +"##; + let expected = r##"
      +
    • +

      foo

      +
        +
      • bar
      • +
      +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_296() { + let original = r##"- a + - b + - c + +- d + - e + - f +"##; + let expected = r##"
      +
    • +

      a

      +
        +
      • b
      • +
      • c
      • +
      +
    • +
    • +

      d

      +
        +
      • e
      • +
      • f
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_297() { + let original = r##"`hi`lo` +"##; + let expected = r##"

    hilo`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_298() { + let original = r##"\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +"##; + let expected = r##"

    !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_299() { + let original = r##"\ \A\a\ \3\φ\« +"##; + let expected = r##"

    \ \A\a\ \3\φ\«

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_300() { + let original = r##"\*not emphasized* +\
    not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +\ö not a character entity +"##; + let expected = r##"

    *not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference" +&ouml; not a character entity

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_301() { + let original = r##"\\*emphasis* +"##; + let expected = r##"

    \emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_302() { + let original = r##"foo\ +bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_303() { + let original = r##"`` \[\` `` +"##; + let expected = r##"

    \[\`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_304() { + let original = r##" \[\] +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_305() { + let original = r##"~~~ +\[\] +~~~ +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_306() { + let original = r##" +"##; + let expected = r##"

    http://example.com?find=\*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_307() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_308() { + let original = r##"[foo](/bar\* "ti\*tle") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_309() { + let original = r##"[foo] + +[foo]: /bar\* "ti\*tle" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_310() { + let original = r##"``` foo\+bar +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_311() { + let original = r##"  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +"##; + let expected = r##"

      & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_312() { + let original = r##"# Ӓ Ϡ � +"##; + let expected = r##"

    # Ӓ Ϡ �

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_313() { + let original = r##"" ആ ಫ +"##; + let expected = r##"

    " ആ ಫ

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_314() { + let original = r##"  &x; &#; &#x; +� +&#abcdef0; +&ThisIsNotDefined; &hi?; +"##; + let expected = r##"

    &nbsp &x; &#; &#x; +&#87654321; +&#abcdef0; +&ThisIsNotDefined; &hi?;

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_315() { + let original = r##"© +"##; + let expected = r##"

    &copy

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_316() { + let original = r##"&MadeUpEntity; +"##; + let expected = r##"

    &MadeUpEntity;

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_317() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_318() { + let original = r##"[foo](/föö "föö") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_319() { + let original = r##"[foo] + +[foo]: /föö "föö" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_320() { + let original = r##"``` föö +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_321() { + let original = r##"`föö` +"##; + let expected = r##"

    f&ouml;&ouml;

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_322() { + let original = r##" föfö +"##; + let expected = r##"
    f&ouml;f&ouml;
    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_323() { + let original = r##"*foo* +*foo* +"##; + let expected = r##"

    *foo* +foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_324() { + let original = r##"* foo + +* foo +"##; + let expected = r##"

    * foo

    +
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_325() { + let original = r##"foo bar +"##; + let expected = r##"

    foo + +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_326() { + let original = r##" foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_327() { + let original = r##"[a](url "tit") +"##; + let expected = r##"

    [a](url "tit")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_328() { + let original = r##"`foo` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_329() { + let original = r##"`` foo ` bar `` +"##; + let expected = r##"

    foo ` bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_330() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_331() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_332() { + let original = r##"` a` +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_333() { + let original = r##"` b ` +"##; + let expected = r##"

     b 

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_334() { + let original = r##"` ` +` ` +"##; + let expected = r##"

      +

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_335() { + let original = r##"`` +foo +bar +baz +`` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_336() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_337() { + let original = r##"`foo bar +baz` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_338() { + let original = r##"`foo\`bar` +"##; + let expected = r##"

    foo\bar`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_339() { + let original = r##"``foo`bar`` +"##; + let expected = r##"

    foo`bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_340() { + let original = r##"` foo `` bar ` +"##; + let expected = r##"

    foo `` bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_341() { + let original = r##"*foo`*` +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_342() { + let original = r##"[not a `link](/foo`) +"##; + let expected = r##"

    [not a link](/foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_343() { + let original = r##"`` +"##; + let expected = r##"

    <a href="">`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_344() { + let original = r##"
    ` +"##; + let expected = r##"

    `

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_345() { + let original = r##"`` +"##; + let expected = r##"

    <http://foo.bar.baz>`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_346() { + let original = r##"` +"##; + let expected = r##"

    http://foo.bar.`baz`

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_347() { + let original = r##"```foo`` +"##; + let expected = r##"

    ```foo``

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_348() { + let original = r##"`foo +"##; + let expected = r##"

    `foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_349() { + let original = r##"`foo``bar`` +"##; + let expected = r##"

    `foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_350() { + let original = r##"*foo bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_351() { + let original = r##"a * foo bar* +"##; + let expected = r##"

    a * foo bar*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_352() { + let original = r##"a*"foo"* +"##; + let expected = r##"

    a*"foo"*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_353() { + let original = r##"* a * +"##; + let expected = r##"

    * a *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_354() { + let original = r##"foo*bar* +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_355() { + let original = r##"5*6*78 +"##; + let expected = r##"

    5678

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_356() { + let original = r##"_foo bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_357() { + let original = r##"_ foo bar_ +"##; + let expected = r##"

    _ foo bar_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_358() { + let original = r##"a_"foo"_ +"##; + let expected = r##"

    a_"foo"_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_359() { + let original = r##"foo_bar_ +"##; + let expected = r##"

    foo_bar_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_360() { + let original = r##"5_6_78 +"##; + let expected = r##"

    5_6_78

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_361() { + let original = r##"пристаням_стремятся_ +"##; + let expected = r##"

    пристаням_стремятся_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_362() { + let original = r##"aa_"bb"_cc +"##; + let expected = r##"

    aa_"bb"_cc

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_363() { + let original = r##"foo-_(bar)_ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_364() { + let original = r##"_foo* +"##; + let expected = r##"

    _foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_365() { + let original = r##"*foo bar * +"##; + let expected = r##"

    *foo bar *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_366() { + let original = r##"*foo bar +* +"##; + let expected = r##"

    *foo bar +*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_367() { + let original = r##"*(*foo) +"##; + let expected = r##"

    *(*foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_368() { + let original = r##"*(*foo*)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_369() { + let original = r##"*foo*bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_370() { + let original = r##"_foo bar _ +"##; + let expected = r##"

    _foo bar _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_371() { + let original = r##"_(_foo) +"##; + let expected = r##"

    _(_foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_372() { + let original = r##"_(_foo_)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_373() { + let original = r##"_foo_bar +"##; + let expected = r##"

    _foo_bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_374() { + let original = r##"_пристаням_стремятся +"##; + let expected = r##"

    _пристаням_стремятся

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_375() { + let original = r##"_foo_bar_baz_ +"##; + let expected = r##"

    foo_bar_baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_376() { + let original = r##"_(bar)_. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_377() { + let original = r##"**foo bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_378() { + let original = r##"** foo bar** +"##; + let expected = r##"

    ** foo bar**

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_379() { + let original = r##"a**"foo"** +"##; + let expected = r##"

    a**"foo"**

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_380() { + let original = r##"foo**bar** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_381() { + let original = r##"__foo bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_382() { + let original = r##"__ foo bar__ +"##; + let expected = r##"

    __ foo bar__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_383() { + let original = r##"__ +foo bar__ +"##; + let expected = r##"

    __ +foo bar__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_384() { + let original = r##"a__"foo"__ +"##; + let expected = r##"

    a__"foo"__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_385() { + let original = r##"foo__bar__ +"##; + let expected = r##"

    foo__bar__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_386() { + let original = r##"5__6__78 +"##; + let expected = r##"

    5__6__78

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_387() { + let original = r##"пристаням__стремятся__ +"##; + let expected = r##"

    пристаням__стремятся__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_388() { + let original = r##"__foo, __bar__, baz__ +"##; + let expected = r##"

    foo, bar, baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_389() { + let original = r##"foo-__(bar)__ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_390() { + let original = r##"**foo bar ** +"##; + let expected = r##"

    **foo bar **

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_391() { + let original = r##"**(**foo) +"##; + let expected = r##"

    **(**foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_392() { + let original = r##"*(**foo**)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_393() { + let original = r##"**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +"##; + let expected = r##"

    Gomphocarpus (Gomphocarpus physocarpus, syn. +Asclepias physocarpa)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_394() { + let original = r##"**foo "*bar*" foo** +"##; + let expected = r##"

    foo "bar" foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_395() { + let original = r##"**foo**bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_396() { + let original = r##"__foo bar __ +"##; + let expected = r##"

    __foo bar __

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_397() { + let original = r##"__(__foo) +"##; + let expected = r##"

    __(__foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_398() { + let original = r##"_(__foo__)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_399() { + let original = r##"__foo__bar +"##; + let expected = r##"

    __foo__bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_400() { + let original = r##"__пристаням__стремятся +"##; + let expected = r##"

    __пристаням__стремятся

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_401() { + let original = r##"__foo__bar__baz__ +"##; + let expected = r##"

    foo__bar__baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_402() { + let original = r##"__(bar)__. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_403() { + let original = r##"*foo [bar](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_404() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_405() { + let original = r##"_foo __bar__ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_406() { + let original = r##"_foo _bar_ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_407() { + let original = r##"__foo_ bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_408() { + let original = r##"*foo *bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_409() { + let original = r##"*foo **bar** baz* +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_410() { + let original = r##"*foo**bar**baz* +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_411() { + let original = r##"*foo**bar* +"##; + let expected = r##"

    foo**bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_412() { + let original = r##"***foo** bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_413() { + let original = r##"*foo **bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_414() { + let original = r##"*foo**bar*** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_415() { + let original = r##"foo***bar***baz +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_416() { + let original = r##"foo******bar*********baz +"##; + let expected = r##"

    foobar***baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_417() { + let original = r##"*foo **bar *baz* bim** bop* +"##; + let expected = r##"

    foo bar baz bim bop

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_418() { + let original = r##"*foo [*bar*](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_419() { + let original = r##"** is not an empty emphasis +"##; + let expected = r##"

    ** is not an empty emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_420() { + let original = r##"**** is not an empty strong emphasis +"##; + let expected = r##"

    **** is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_421() { + let original = r##"**foo [bar](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_422() { + let original = r##"**foo +bar** +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_423() { + let original = r##"__foo _bar_ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_424() { + let original = r##"__foo __bar__ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_425() { + let original = r##"____foo__ bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_426() { + let original = r##"**foo **bar**** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_427() { + let original = r##"**foo *bar* baz** +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_428() { + let original = r##"**foo*bar*baz** +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_429() { + let original = r##"***foo* bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_430() { + let original = r##"**foo *bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_431() { + let original = r##"**foo *bar **baz** +bim* bop** +"##; + let expected = r##"

    foo bar baz +bim bop

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_432() { + let original = r##"**foo [*bar*](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_433() { + let original = r##"__ is not an empty emphasis +"##; + let expected = r##"

    __ is not an empty emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_434() { + let original = r##"____ is not an empty strong emphasis +"##; + let expected = r##"

    ____ is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_435() { + let original = r##"foo *** +"##; + let expected = r##"

    foo ***

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_436() { + let original = r##"foo *\** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_437() { + let original = r##"foo *_* +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_438() { + let original = r##"foo ***** +"##; + let expected = r##"

    foo *****

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_439() { + let original = r##"foo **\*** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_440() { + let original = r##"foo **_** +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_441() { + let original = r##"**foo* +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_442() { + let original = r##"*foo** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_443() { + let original = r##"***foo** +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_444() { + let original = r##"****foo* +"##; + let expected = r##"

    ***foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_445() { + let original = r##"**foo*** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_446() { + let original = r##"*foo**** +"##; + let expected = r##"

    foo***

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_447() { + let original = r##"foo ___ +"##; + let expected = r##"

    foo ___

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_448() { + let original = r##"foo _\__ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_449() { + let original = r##"foo _*_ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_450() { + let original = r##"foo _____ +"##; + let expected = r##"

    foo _____

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_451() { + let original = r##"foo __\___ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_452() { + let original = r##"foo __*__ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_453() { + let original = r##"__foo_ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_454() { + let original = r##"_foo__ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_455() { + let original = r##"___foo__ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_456() { + let original = r##"____foo_ +"##; + let expected = r##"

    ___foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_457() { + let original = r##"__foo___ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_458() { + let original = r##"_foo____ +"##; + let expected = r##"

    foo___

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_459() { + let original = r##"**foo** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_460() { + let original = r##"*_foo_* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_461() { + let original = r##"__foo__ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_462() { + let original = r##"_*foo*_ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_463() { + let original = r##"****foo**** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_464() { + let original = r##"____foo____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_465() { + let original = r##"******foo****** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_466() { + let original = r##"***foo*** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_467() { + let original = r##"_____foo_____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_468() { + let original = r##"*foo _bar* baz_ +"##; + let expected = r##"

    foo _bar baz_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_469() { + let original = r##"*foo __bar *baz bim__ bam* +"##; + let expected = r##"

    foo bar *baz bim bam

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_470() { + let original = r##"**foo **bar baz** +"##; + let expected = r##"

    **foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_471() { + let original = r##"*foo *bar baz* +"##; + let expected = r##"

    *foo bar baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_472() { + let original = r##"*[bar*](/url) +"##; + let expected = r##"

    *bar*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_473() { + let original = r##"_foo [bar_](/url) +"##; + let expected = r##"

    _foo bar_

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_474() { + let original = r##"* +"##; + let expected = r##"

    *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_475() { + let original = r##"** +"##; + let expected = r##"

    **

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_476() { + let original = r##"__ +"##; + let expected = r##"

    __

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_477() { + let original = r##"*a `*`* +"##; + let expected = r##"

    a *

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_478() { + let original = r##"_a `_`_ +"##; + let expected = r##"

    a _

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_479() { + let original = r##"**a +"##; + let expected = r##"

    **ahttp://foo.bar/?q=**

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_480() { + let original = r##"__a +"##; + let expected = r##"

    __ahttp://foo.bar/?q=__

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_481() { + let original = r##"[link](/uri "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_482() { + let original = r##"[link](/uri) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_483() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_484() { + let original = r##"[link](<>) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_485() { + let original = r##"[link](/my uri) +"##; + let expected = r##"

    [link](/my uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_486() { + let original = r##"[link](
    ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_487() { + let original = r##"[link](foo +bar) +"##; + let expected = r##"

    [link](foo +bar)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_488() { + let original = r##"[link]() +"##; + let expected = r##"

    [link]()

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_489() { + let original = r##"[a]() +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_490() { + let original = r##"[link]() +"##; + let expected = r##"

    [link](<foo>)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_491() { + let original = r##"[a]( +[a](c) +"##; + let expected = r##"

    [a](<b)c +[a](<b)c> +[a](c)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_492() { + let original = r##"[link](\(foo\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_493() { + let original = r##"[link](foo(and(bar))) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_494() { + let original = r##"[link](foo\(and\(bar\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_495() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_496() { + let original = r##"[link](foo\)\:) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_497() { + let original = r##"[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +"##; + let expected = r##"

    link

    +

    link

    +

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_498() { + let original = r##"[link](foo\bar) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_499() { + let original = r##"[link](foo%20bä) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_500() { + let original = r##"[link]("title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_501() { + let original = r##"[link](/url "title") +[link](/url 'title') +[link](/url (title)) +"##; + let expected = r##"

    link +link +link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_502() { + let original = r##"[link](/url "title \""") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_503() { + let original = r##"[link](/url "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_504() { + let original = r##"[link](/url "title "and" title") +"##; + let expected = r##"

    [link](/url "title "and" title")

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_505() { + let original = r##"[link](/url 'title "and" title') +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_506() { + let original = r##"[link]( /uri + "title" ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_507() { + let original = r##"[link] (/uri) +"##; + let expected = r##"

    [link] (/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_508() { + let original = r##"[link [foo [bar]]](/uri) +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_509() { + let original = r##"[link] bar](/uri) +"##; + let expected = r##"

    [link] bar](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_510() { + let original = r##"[link [bar](/uri) +"##; + let expected = r##"

    [link bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_511() { + let original = r##"[link \[bar](/uri) +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_512() { + let original = r##"[link *foo **bar** `#`*](/uri) +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_513() { + let original = r##"[![moon](moon.jpg)](/uri) +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_514() { + let original = r##"[foo [bar](/uri)](/uri) +"##; + let expected = r##"

    [foo bar](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_515() { + let original = r##"[foo *[bar [baz](/uri)](/uri)*](/uri) +"##; + let expected = r##"

    [foo [bar baz](/uri)](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_516() { + let original = r##"![[[foo](uri1)](uri2)](uri3) +"##; + let expected = r##"

    [foo](uri2)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_517() { + let original = r##"*[foo*](/uri) +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_518() { + let original = r##"[foo *bar](baz*) +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_519() { + let original = r##"*foo [bar* baz] +"##; + let expected = r##"

    foo [bar baz]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_520() { + let original = r##"[foo +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_521() { + let original = r##"[foo`](/uri)` +"##; + let expected = r##"

    [foo](/uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_522() { + let original = r##"[foo +"##; + let expected = r##"

    [foohttp://example.com/?search=](uri)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_523() { + let original = r##"[foo][bar] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_524() { + let original = r##"[link [foo [bar]]][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_525() { + let original = r##"[link \[bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_526() { + let original = r##"[link *foo **bar** `#`*][ref] + +[ref]: /uri +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_527() { + let original = r##"[![moon](moon.jpg)][ref] + +[ref]: /uri +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_528() { + let original = r##"[foo [bar](/uri)][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar]ref

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_529() { + let original = r##"[foo *bar [baz][ref]*][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar baz]ref

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_530() { + let original = r##"*[foo*][ref] + +[ref]: /uri +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_531() { + let original = r##"[foo *bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_532() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_533() { + let original = r##"[foo`][ref]` + +[ref]: /uri +"##; + let expected = r##"

    [foo][ref]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_534() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foohttp://example.com/?search=][ref]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_535() { + let original = r##"[foo][BaR] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_536() { + let original = r##"[Толпой][Толпой] is a Russian word. + +[ТОЛПОЙ]: /url +"##; + let expected = r##"

    Толпой is a Russian word.

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_537() { + let original = r##"[Foo + bar]: /url + +[Baz][Foo bar] +"##; + let expected = r##"

    Baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_538() { + let original = r##"[foo] [bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_539() { + let original = r##"[foo] +[bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_540() { + let original = r##"[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_541() { + let original = r##"[bar][foo\!] + +[foo!]: /url +"##; + let expected = r##"

    [bar][foo!]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_542() { + let original = r##"[foo][ref[] + +[ref[]: /uri +"##; + let expected = r##"

    [foo][ref[]

    +

    [ref[]: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_543() { + let original = r##"[foo][ref[bar]] + +[ref[bar]]: /uri +"##; + let expected = r##"

    [foo][ref[bar]]

    +

    [ref[bar]]: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_544() { + let original = r##"[[[foo]]] + +[[[foo]]]: /url +"##; + let expected = r##"

    [[[foo]]]

    +

    [[[foo]]]: /url

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_545() { + let original = r##"[foo][ref\[] + +[ref\[]: /uri +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_546() { + let original = r##"[bar\\]: /uri + +[bar\\] +"##; + let expected = r##"

    bar\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_547() { + let original = r##"[] + +[]: /uri +"##; + let expected = r##"

    []

    +

    []: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_548() { + let original = r##"[ + ] + +[ + ]: /uri +"##; + let expected = r##"

    [ +]

    +

    [ +]: /uri

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_549() { + let original = r##"[foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_550() { + let original = r##"[*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_551() { + let original = r##"[Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_552() { + let original = r##"[foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_553() { + let original = r##"[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_554() { + let original = r##"[*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_555() { + let original = r##"[[*foo* bar]] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    [foo bar]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_556() { + let original = r##"[[bar [foo] + +[foo]: /url +"##; + let expected = r##"

    [[bar foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_557() { + let original = r##"[Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_558() { + let original = r##"[foo] bar + +[foo]: /url +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_559() { + let original = r##"\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    [foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_560() { + let original = r##"[foo*]: /url + +*[foo*] +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_561() { + let original = r##"[foo][bar] + +[foo]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_562() { + let original = r##"[foo][] + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_563() { + let original = r##"[foo]() + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_564() { + let original = r##"[foo](not a link) + +[foo]: /url1 +"##; + let expected = r##"

    foo(not a link)

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_565() { + let original = r##"[foo][bar][baz] + +[baz]: /url +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_566() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foobaz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_567() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_568() { + let original = r##"![foo](/url "title") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_569() { + let original = r##"![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_570() { + let original = r##"![foo ![bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_571() { + let original = r##"![foo [bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_572() { + let original = r##"![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_573() { + let original = r##"![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_574() { + let original = r##"![foo](train.jpg) +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_575() { + let original = r##"My ![foo bar](/path/to/train.jpg "title" ) +"##; + let expected = r##"

    My foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_576() { + let original = r##"![foo]() +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_577() { + let original = r##"![](/url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_578() { + let original = r##"![foo][bar] + +[bar]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_579() { + let original = r##"![foo][bar] + +[BAR]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_580() { + let original = r##"![foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_581() { + let original = r##"![*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_582() { + let original = r##"![Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_583() { + let original = r##"![foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_584() { + let original = r##"![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_585() { + let original = r##"![*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_586() { + let original = r##"![[foo]] + +[[foo]]: /url "title" +"##; + let expected = r##"

    ![[foo]]

    +

    [[foo]]: /url "title"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_587() { + let original = r##"![Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_588() { + let original = r##"!\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    ![foo]

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_589() { + let original = r##"\![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    !foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_590() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_591() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz/test?q=hello&id=22&boolean

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_592() { + let original = r##" +"##; + let expected = r##"

    irc://foo.bar:2233/baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_593() { + let original = r##" +"##; + let expected = r##"

    MAILTO:FOO@BAR.BAZ

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_594() { + let original = r##" +"##; + let expected = r##"

    a+b+c:d

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_595() { + let original = r##" +"##; + let expected = r##"

    made-up-scheme://foo,bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_596() { + let original = r##" +"##; + let expected = r##"

    http://../

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_597() { + let original = r##" +"##; + let expected = r##"

    localhost:5001/foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_598() { + let original = r##" +"##; + let expected = r##"

    <http://foo.bar/baz bim>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_599() { + let original = r##" +"##; + let expected = r##"

    http://example.com/\[\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_600() { + let original = r##" +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_601() { + let original = r##" +"##; + let expected = r##"

    foo+special@Bar.baz-bar0.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_602() { + let original = r##" +"##; + let expected = r##"

    <foo+@bar.example.com>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_603() { + let original = r##"<> +"##; + let expected = r##"

    <>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_604() { + let original = r##"< http://foo.bar > +"##; + let expected = r##"

    < http://foo.bar >

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_605() { + let original = r##" +"##; + let expected = r##"

    <m:abc>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_606() { + let original = r##" +"##; + let expected = r##"

    <foo.bar.baz>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_607() { + let original = r##"http://example.com +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_608() { + let original = r##"foo@bar.example.com +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_609() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_610() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_611() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_612() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_613() { + let original = r##"Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_614() { + let original = r##"<33> <__> +"##; + let expected = r##"

    <33> <__>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_615() { + let original = r##"
    +"##; + let expected = r##"

    <a h*#ref="hi">

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_616() { + let original = r##"
    <a href="hi'> <a href=hi'>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_617() { + let original = r##"< a>< +foo> + +"##; + let expected = r##"

    < a>< +foo><bar/ > +<foo bar=baz +bim!bop />

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_618() { + let original = r##"
    +"##; + let expected = r##"

    <a href='bar'title=title>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_619() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_620() { + let original = r##" +"##; + let expected = r##"

    </a href="foo">

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_621() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_622() { + let original = r##"foo +"##; + let expected = r##"

    foo <!-- not a comment -- two hyphens -->

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_623() { + let original = r##"foo foo --> + +foo +"##; + let expected = r##"

    foo <!--> foo -->

    +

    foo <!-- foo--->

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_624() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_625() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_626() { + let original = r##"foo &<]]> +"##; + let expected = r##"

    foo &<]]>

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_627() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_628() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_629() { + let original = r##" +"##; + let expected = r##"

    <a href=""">

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_630() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_631() { + let original = r##"foo\ +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_632() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_633() { + let original = r##"foo + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_634() { + let original = r##"foo\ + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_635() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_636() { + let original = r##"*foo\ +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_637() { + let original = r##"`code +span` +"##; + let expected = r##"

    code span

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_638() { + let original = r##"`code\ +span` +"##; + let expected = r##"

    code\ span

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_639() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_640() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_641() { + let original = r##"foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_642() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_643() { + let original = r##"### foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_644() { + let original = r##"### foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_645() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_646() { + let original = r##"foo + baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_647() { + let original = r##"hello $.;'there +"##; + let expected = r##"

    hello $.;'there

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_648() { + let original = r##"Foo χρῆν +"##; + let expected = r##"

    Foo χρῆν

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn spec_test_649() { + let original = r##"Multiple spaces +"##; + let expected = r##"

    Multiple spaces

    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-0.7.2/tests/suite/table.rs b/vendor/pulldown-cmark-0.7.2/tests/suite/table.rs new file mode 100644 index 0000000000..de4d2f65dc --- /dev/null +++ b/vendor/pulldown-cmark-0.7.2/tests/suite/table.rs @@ -0,0 +1,205 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn table_test_1() { + let original = r##"Test header +----------- +"##; + let expected = r##"

    Test header

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_2() { + let original = r##"Test|Table +----|----- +"##; + let expected = r##" +
    TestTable
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_3() { + let original = r##"> Test | Table +> ------|------ +> Row 1 | Every +> Row 2 | Day +> +> Paragraph +"##; + let expected = r##"
    + + + +
    Test Table
    Row 1 Every
    Row 2 Day
    +

    Paragraph

    +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_4() { + let original = r##" 1. First entry + 2. Second entry + + Col 1|Col 2 + -|- + Row 1|Part 2 + Row 2|Part 2 +"##; + let expected = r##"
      +
    1. +

      First entry

      +
    2. +
    3. +

      Second entry

      + + + +
      Col 1Col 2
      Row 1Part 2
      Row 2Part 2
      +
    4. +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_5() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|R1C1 |R1C2 | +|R2C1 |R2C2 | +"##; + let expected = r##" + + +
    Col 1Col 2
    R1C1 R1C2
    R2C1 R2C2
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_6() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| | | +| | | +"##; + let expected = r##" + + +
    Col 1 Col 2
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_7() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| x | | +| | x | +"##; + let expected = r##" + + +
    Col 1 Col 2
    x
    x
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_8() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|✓ |✓ | +|✓ |✓ | +"##; + let expected = r##" + + +
    Col 1Col 2
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_9() { + let original = r##"| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | +| `arm-linux-androideabi` | ✓ | | | ARM Android | +| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | +| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | +| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | +"##; + let expected = r##" + + + + + + + +
    Target std rustccargo notes
    x86_64-unknown-linux-musl 64-bit Linux with MUSL
    arm-linux-androideabi ARM Android
    arm-unknown-linux-gnueabi ARM Linux (2.6.18+)
    arm-unknown-linux-gnueabihf ARM Linux (2.6.18+)
    aarch64-unknown-linux-gnu ARM64 Linux (2.6.18+)
    mips-unknown-linux-gnu MIPS Linux (2.6.18+)
    mipsel-unknown-linux-gnu MIPS (LE) Linux (2.6.18+)
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_10() { + let original = r##"|-|-| +|ぃ|い| +"##; + let expected = r##"

    |-|-| +|ぃ|い|

    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_11() { + let original = r##"|ぁ|ぃ| +|-|-| +|ぃ|ぃ| +"##; + let expected = r##" + +
    +"##; + + test_markdown_html(original, expected); +} + +#[test] +fn table_test_12() { + let original = r##"|Колонка 1|Колонка 2| +|---------|---------| +|Ячейка 1 |Ячейка 2 | +"##; + let expected = r##" + +
    Колонка 1Колонка 2
    Ячейка 1 Ячейка 2
    +"##; + + test_markdown_html(original, expected); +} diff --git a/vendor/pulldown-cmark-to-cmark/.cargo-checksum.json b/vendor/pulldown-cmark-to-cmark/.cargo-checksum.json new file mode 100644 index 0000000000..48a835273e --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"e4a28a39450d75604a5def32aa4e2fe3eeb6774fc066735ef39f29d4dbbc844c","Cargo.toml":"86724eb5838df65639c5a6e369f226b05bace8c099f742d2c8e5181557a3292d","README.md":"cacc5c1dc25396fe63717b4acfb2dd13ac3fb4c28108647aaeb37f26f4120322","src/lib.rs":"62aafecee2c9c812144c48439c55a881443441c41f987af42a8b6ef05791a6fe"},"package":"32accf4473121d8c0b508ca5673363703762d6cc59cf25af1df48f653346f736"} \ No newline at end of file diff --git a/vendor/pulldown-cmark-to-cmark/CHANGELOG.md b/vendor/pulldown-cmark-to-cmark/CHANGELOG.md new file mode 100644 index 0000000000..1cbb432de7 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/CHANGELOG.md @@ -0,0 +1,28 @@ +### v5.0.0 (2020-08-02) + +* Allow configuring the [amount of backticks used in code blocks](https://github.com/Byron/pulldown-cmark-to-cmark/pull/18). + May **break** code relying on the amount of fields in the configuration struct. + +### v4.0.2 (2020-04-22) + +* Fixed table header handling ([see PR for details](https://github.com/Byron/pulldown-cmark-to-cmark/pull/15)) + +### v4.0.0 (2020-04-22) + +* BREAKING: Move all types from `pulldown_cmark_to_cmark::fmt::*` into `pulldown_cmark_to_cmark::*` for simplicity. + For most common use-cases, this means that users of `pulldown_cmark_to_cmark::fmt::cmark` now use `pulldown_cmark_to_cmark::cmark` instead. + +### v3.0.1 (2020-04-22) + +* support for markdown embedded in HTML tags, like + + ```markdown +
    + + * list + * list + + **bold** + +
    + ``` diff --git a/vendor/pulldown-cmark-to-cmark/Cargo.toml b/vendor/pulldown-cmark-to-cmark/Cargo.toml new file mode 100644 index 0000000000..6fef63e0a4 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/Cargo.toml @@ -0,0 +1,33 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "pulldown-cmark-to-cmark" +version = "5.0.0" +authors = ["Sebastian Thiel ", "Dylan Owen "] +include = ["src/lib.rs", "README.md", "CHANGELOG.md"] +description = "Convert pulldown-cmark Events back to the string they were parsed from" +homepage = "https://github.com/Byron/pulldown-cmark-to-cmark" +documentation = "https://docs.rs/crate/pulldown-cmark-to-cmark" +readme = "README.md" +keywords = ["markdown", "common-mark", "render", "converter"] +license = "Apache-2.0" +repository = "https://github.com/Byron/pulldown-cmark-to-cmark" +[dependencies.pulldown-cmark] +version = "0.7.0" +default-features = false +[dev-dependencies.indoc] +version = "0.3.4" + +[dev-dependencies.pretty_assertions] +version = "0.6.1" diff --git a/vendor/pulldown-cmark-to-cmark/README.md b/vendor/pulldown-cmark-to-cmark/README.md new file mode 100644 index 0000000000..263f5bdd26 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/README.md @@ -0,0 +1,41 @@ +[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark-to-cmark)](https://crates.io/crates/pulldown-cmark-to-cmark) +![Rust](https://github.com/Byron/pulldown-cmark-to-cmark/workflows/Rust/badge.svg) + +A utility library which translates [`Event`][pdcm-event] back to markdown. +It's the prerequisite for writing markdown filters which can work as +[mdbook-preprocessors][mdbook-prep]. + +This library takes great pride in supporting **everything that `pulldown-cmark`** supports, +including *tables* and *footnotes* and *codeblocks in codeblocks*, +while assuring *quality* with a powerful test suite. + +[pdcm-event]: https://docs.rs/pulldown-cmark/0.1.0/pulldown_cmark/enum.Event.html +[mdbook-prep]: https://rust-lang-nursery.github.io/mdBook/for_developers/preprocessors.html + +### How to use + +Please have a look at the [`stupicat`-example][sc-example] for a complete tour +of the API, or have a look at the [api-docs][api]. + +It's easiest to get this library into your `Cargo.toml` using `cargo-add`: +``` +cargo add pulldown-cmark-to-cmark +``` + +[sc-example]: https://github.com/Byron/pulldown-cmark-to-cmark/blob/76667725b61be24890fbdfed5e7ecdb4c1ad1dc8/examples/stupicat.rs#L21 +[api]: https://docs.rs/crate/pulldown-cmark-to-cmark + +### Friends of this project + + * [**termbook**](https://github.com/Byron/termbook) + * A runner for `mdbooks` to keep your documentation tested. + * [**Share Secrets Safely**](https://github.com/Byron/share-secrets-safely) + * share secrets within teams to avoid plain-text secrets from day one + +### Maintenance Guide + +#### Making a new release + + * **Assure all documentation is up-to-date and tests are green** + * update the `version` in `Cargo.toml` and `git commit` + * run `cargo release --no-dev-version` diff --git a/vendor/pulldown-cmark-to-cmark/src/lib.rs b/vendor/pulldown-cmark-to-cmark/src/lib.rs new file mode 100644 index 0000000000..058f0eb7f3 --- /dev/null +++ b/vendor/pulldown-cmark-to-cmark/src/lib.rs @@ -0,0 +1,482 @@ +use pulldown_cmark::{Alignment as TableAlignment, Event}; +use std::{borrow::Borrow, borrow::Cow, fmt}; + +pub const SPECIAL_CHARACTERS: &[u8; 9] = br#"#\_*<>`|["#; + +/// Similar to [Pulldown-Cmark-Alignment][pd-alignment], but with required +/// traits for comparison to allow testing. +/// +/// [pd-alignment]: https://docs.rs/pulldown-cmark/*/pulldown_cmark/enum.Alignment.html +#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub enum Alignment { + None, + Left, + Center, + Right, +} + +impl<'a> From<&'a TableAlignment> for Alignment { + fn from(s: &'a TableAlignment) -> Self { + match *s { + TableAlignment::None => Alignment::None, + TableAlignment::Left => Alignment::Left, + TableAlignment::Center => Alignment::Center, + TableAlignment::Right => Alignment::Right, + } + } +} + +/// The state of the `cmark` function. +/// This does not only allow introspection, but enables the user +/// to halt the serialization at any time, and resume it later. +#[derive(Clone, Default, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct State<'a> { + /// The amount of newlines to insert after `Event::Start(...)` + pub newlines_before_start: usize, + /// The lists and their types for which we have seen a `Event::Start(List(...))` tag + pub list_stack: Vec>, + /// The computed padding and prefix to print after each newline. + /// This changes with the level of `BlockQuote` and `List` events. + pub padding: Vec>, + /// Keeps the current table alignments, if we are currently serializing a table. + pub table_alignments: Vec, + /// Keeps the current table headers, if we are currently serializing a table. + pub table_headers: Vec, + /// If set, the next 'text' will be stored for later use + pub store_next_text: bool, + /// The last seen text when serializing a header + pub text_for_header: Option, + /// Is set while we are handling text in a code block + pub is_in_code_block: bool, + /// True if the last event was html. Used to inject additional newlines to support markdown inside of HTML tags. + pub last_was_html: bool, +} + +/// Configuration for the `cmark` function. +/// The defaults should provide decent spacing and most importantly, will +/// provide a faithful rendering of your markdown document particularly when +/// rendering it to HTML. +/// +/// It's best used with its `Options::default()` implementation. +#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] +pub struct Options { + pub newlines_after_headline: usize, + pub newlines_after_paragraph: usize, + pub newlines_after_codeblock: usize, + pub newlines_after_table: usize, + pub newlines_after_rule: usize, + pub newlines_after_list: usize, + pub newlines_after_blockquote: usize, + pub newlines_after_rest: usize, + pub code_block_backticks: usize, +} + +impl Default for Options { + fn default() -> Self { + Options { + newlines_after_headline: 2, + newlines_after_paragraph: 2, + newlines_after_codeblock: 2, + newlines_after_table: 2, + newlines_after_rule: 2, + newlines_after_list: 2, + newlines_after_blockquote: 2, + newlines_after_rest: 1, + code_block_backticks: 4, + } + } +} + +/// Serialize a stream of [pulldown-cmark-Events][pd-event] into a string-backed buffer. +/// +/// 1. **events** +/// * An iterator over [`Events`][pd-event], for example as returned by the [`Parser`][pd-parser] +/// 1. **formatter** +/// * A format writer, can be a `String`. +/// 1. **state** +/// * The optional initial state of the serialization. +/// 1. **options** +/// * Customize the appearance of the serialization. All otherwise magic values are contained +/// here. +/// +/// *Returns* the `State` of the serialization on success. You can use it as initial state in the +/// next call if you are halting event serialization. +/// *Errors* are only happening if the underlying buffer fails, which is unlikely. +/// +/// [pd-event]: https://docs.rs/pulldown-cmark/*/pulldown_cmark/enum.Event.html +/// [pd-parser]: https://docs.rs/pulldown-cmark/*/pulldown_cmark/struct.Parser.html +pub fn cmark_with_options<'a, I, E, F>( + events: I, + mut formatter: F, + state: Option>, + options: Options, +) -> Result, fmt::Error> +where + I: Iterator, + E: Borrow>, + F: fmt::Write, +{ + let mut state = state.unwrap_or_default(); + fn padding<'a, F>(f: &mut F, p: &[Cow<'a, str>]) -> fmt::Result + where + F: fmt::Write, + { + for padding in p { + write!(f, "{}", padding)?; + } + Ok(()) + } + fn consume_newlines(f: &mut F, s: &mut State) -> fmt::Result + where + F: fmt::Write, + { + while s.newlines_before_start != 0 { + s.newlines_before_start -= 1; + f.write_char('\n')?; + padding(f, &s.padding)?; + } + Ok(()) + } + + fn escape_leading_special_characters(t: &str, is_in_block_quote: bool) -> Cow<'_, str> { + if is_in_block_quote || t.is_empty() { + return Cow::Borrowed(t); + } + + use std::convert::TryFrom; + let first = t.as_bytes()[0]; + if SPECIAL_CHARACTERS.contains(&first) { + let mut s = String::with_capacity(t.len() + 1); + s.push('\\'); + s.push(char::try_from(first as u32).expect("we know it's valid utf8")); + s.push_str(&t[1..]); + Cow::Owned(s) + } else { + Cow::Borrowed(t) + } + } + + fn print_text_without_trailing_newline<'a, F>( + t: &str, + f: &mut F, + p: &[Cow<'a, str>], + ) -> fmt::Result + where + F: fmt::Write, + { + if t.contains('\n') { + let line_count = t.split('\n').count(); + for (tid, token) in t.split('\n').enumerate() { + f.write_str(token).and(if tid + 1 == line_count { + Ok(()) + } else { + f.write_char('\n').and(padding(f, p)) + })?; + } + Ok(()) + } else { + f.write_str(t) + } + } + + fn padding_of(l: Option) -> Cow<'static, str> { + match l { + None => " ".into(), + Some(n) => format!("{}. ", n) + .chars() + .map(|_| ' ') + .collect::() + .into(), + } + } + + for event in events { + use pulldown_cmark::CodeBlockKind; + use pulldown_cmark::Event::*; + use pulldown_cmark::Tag::*; + + let event = event.borrow(); + + // Markdown allows for HTML elements, into which further markdown formatting is nested. + // However only if the HTML element is spaced by an additional newline. + // + // Relevant spec: https://spec.commonmark.org/0.28/#html-blocks + if state.last_was_html { + match event { + Html(_) => { /* no newlines if HTML continues */ } + Text(_) => { /* no newlines for inline HTML */ } + _ => { + // Ensure next Markdown block is rendered properly + // by adding a newline after an HTML element. + formatter.write_char('\n')?; + } + } + } + + state.last_was_html = false; + match *event { + Rule => { + consume_newlines(&mut formatter, &mut state)?; + if state.newlines_before_start < options.newlines_after_rule { + state.newlines_before_start = options.newlines_after_rule; + } + formatter.write_str("---") + } + Code(ref text) => { + if state.store_next_text { + state.store_next_text = false; + let code = format!("`{}`", text); + state.text_for_header = Some(code) + } + formatter + .write_char('`') + .and_then(|_| formatter.write_str(text)) + .and_then(|_| formatter.write_char('`')) + } + Start(ref tag) => { + match *tag { + List(ref list_type) => { + state.list_stack.push(list_type.clone()); + if state.list_stack.len() > 1 { + if state.newlines_before_start < options.newlines_after_rest { + state.newlines_before_start = options.newlines_after_rest; + } + } + } + _ => {} + } + let consumed_newlines = state.newlines_before_start != 0; + consume_newlines(&mut formatter, &mut state)?; + match tag { + Item => match state.list_stack.last() { + Some(inner) => { + state.padding.push(padding_of(*inner)); + match inner { + &Some(n) => write!(formatter, "{}. ", n), + &None => formatter.write_str("* "), + } + } + None => Ok(()), + }, + Table(ref alignments) => { + state.table_alignments = alignments.iter().map(From::from).collect(); + Ok(()) + } + TableHead => Ok(()), + TableRow => Ok(()), + TableCell => { + state.store_next_text = true; + formatter.write_char('|') + } + Link(..) => formatter.write_char('['), + Image(..) => formatter.write_str("!["), + Emphasis => formatter.write_char('*'), + Strong => formatter.write_str("**"), + FootnoteDefinition(ref name) => write!(formatter, "[^{}]: ", name), + Paragraph => Ok(()), + Heading(n) => { + for _ in 0..*n { + formatter.write_char('#')?; + } + formatter.write_char(' ') + } + BlockQuote => { + state.padding.push(" > ".into()); + state.newlines_before_start = 1; + + // if we consumed some newlines, we know that we can just write out the next + // level in our blockquote. This should work regardless if we have other + // padding or if we're in a list + if consumed_newlines { + formatter.write_str(" > ") + } else { + formatter + .write_char('\n') + .and(padding(&mut formatter, &state.padding)) + } + } + CodeBlock(CodeBlockKind::Indented) => { + state.is_in_code_block = true; + formatter + .write_str(&"`".repeat(options.code_block_backticks)) + .and(formatter.write_char('\n')) + .and(padding(&mut formatter, &state.padding)) + } + CodeBlock(CodeBlockKind::Fenced(ref info)) => { + state.is_in_code_block = true; + let s = if !consumed_newlines { + formatter + .write_char('\n') + .and_then(|_| padding(&mut formatter, &state.padding)) + } else { + Ok(()) + }; + + s.and_then(|_| formatter.write_str(&"`".repeat(options.code_block_backticks))) + .and_then(|_| formatter.write_str(info)) + .and_then(|_| formatter.write_char('\n')) + .and_then(|_| padding(&mut formatter, &state.padding)) + } + List(_) => Ok(()), + Strikethrough => formatter.write_str("~~"), + } + } + End(ref tag) => match tag { + Image(_, ref uri, ref title) | Link(_, ref uri, ref title) => { + if title.is_empty() { + write!(formatter, "]({})", uri) + } else { + write!(formatter, "]({uri} \"{title}\")", uri = uri, title = title) + } + } + Emphasis => formatter.write_char('*'), + Strong => formatter.write_str("**"), + Heading(_) => { + if state.newlines_before_start < options.newlines_after_headline { + state.newlines_before_start = options.newlines_after_headline; + } + Ok(()) + } + Paragraph => { + if state.newlines_before_start < options.newlines_after_paragraph { + state.newlines_before_start = options.newlines_after_paragraph; + } + Ok(()) + } + CodeBlock(_) => { + if state.newlines_before_start < options.newlines_after_codeblock { + state.newlines_before_start = options.newlines_after_codeblock; + } + state.is_in_code_block = false; + formatter.write_str(&"`".repeat(options.code_block_backticks)) + } + Table(_) => { + if state.newlines_before_start < options.newlines_after_table { + state.newlines_before_start = options.newlines_after_table; + } + state.table_alignments.clear(); + state.table_headers.clear(); + Ok(()) + } + TableCell => { + state + .table_headers + .push(match state.text_for_header.take() { + Some(text) => text, + None => " ".into(), + }); + Ok(()) + } + ref t @ TableRow | ref t @ TableHead => { + if state.newlines_before_start < options.newlines_after_rest { + state.newlines_before_start = options.newlines_after_rest; + } + formatter.write_char('|')?; + + if let &TableHead = t { + formatter + .write_char('\n') + .and(padding(&mut formatter, &state.padding))?; + for (alignment, name) in state + .table_alignments + .iter() + .zip(state.table_headers.iter()) + { + formatter.write_char('|')?; + // NOTE: For perfect counting, count grapheme clusters. + // The reason this is not done is to avoid the dependency. + let last_minus_one = name.chars().count().saturating_sub(1); + for c in 0..name.len() { + formatter.write_char( + if (c == 0 + && (alignment == &Alignment::Center + || alignment == &Alignment::Left)) + || (c == last_minus_one + && (alignment == &Alignment::Center + || alignment == &Alignment::Right)) + { + ':' + } else { + '-' + }, + )?; + } + } + formatter.write_char('|')?; + } + Ok(()) + } + Item => { + state.padding.pop(); + if state.newlines_before_start < options.newlines_after_rest { + state.newlines_before_start = options.newlines_after_rest; + } + Ok(()) + } + List(_) => { + state.list_stack.pop(); + if state.list_stack.len() == 0 + && state.newlines_before_start < options.newlines_after_list + { + state.newlines_before_start = options.newlines_after_list; + } + Ok(()) + } + BlockQuote => { + state.padding.pop(); + + if state.newlines_before_start < options.newlines_after_blockquote { + state.newlines_before_start = options.newlines_after_blockquote; + } + + Ok(()) + } + FootnoteDefinition(_) => Ok(()), + Strikethrough => formatter.write_str("~~"), + }, + HardBreak => formatter + .write_str(" \n") + .and(padding(&mut formatter, &state.padding)), + SoftBreak => formatter + .write_char('\n') + .and(padding(&mut formatter, &state.padding)), + Text(ref text) => { + if state.store_next_text { + state.store_next_text = false; + state.text_for_header = Some(text.to_owned().into_string()) + } + consume_newlines(&mut formatter, &mut state)?; + print_text_without_trailing_newline( + &escape_leading_special_characters(text, state.is_in_code_block), + &mut formatter, + &state.padding, + ) + } + Html(ref text) => { + state.last_was_html = true; + consume_newlines(&mut formatter, &mut state)?; + print_text_without_trailing_newline(text, &mut formatter, &state.padding) + } + FootnoteReference(ref name) => write!(formatter, "[^{}]", name), + TaskListMarker(checked) => { + let check = if checked { "x" } else { " " }; + write!(formatter, "[{}] ", check) + } + }? + } + Ok(state) +} + +/// As `cmark_with_options`, but with default `Options`. +pub fn cmark<'a, I, E, F>( + events: I, + formatter: F, + state: Option>, +) -> Result, fmt::Error> +where + I: Iterator, + E: Borrow>, + F: fmt::Write, +{ + cmark_with_options(events, formatter, state, Options::default()) +} diff --git a/vendor/pulldown-cmark/.cargo-checksum.json b/vendor/pulldown-cmark/.cargo-checksum.json index 956e4ad354..c5a3efcd17 100644 --- a/vendor/pulldown-cmark/.cargo-checksum.json +++ b/vendor/pulldown-cmark/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CONTRIBUTING.md":"ad9613136aef42ccaca15f131ecb7bb697adbd05cb2d38062e40581d570e5005","Cargo.lock":"0cce438e59390e1c92b9cf168212d1c4a7390e5de715e432e4204118fb10113c","Cargo.toml":"4a791d5e9478bf3fdfb1e85d14aebcafc85d6ed07f73dcf4e742a47981d596d6","LICENSE":"2afc41ab83a8e715bf57b2b0d9d3ca3da1a0afc4cdadefd72f3a1ba537c5213f","README.md":"2a6061d89f6232ed5e444878668bcd819508519a90966945b1f774a14fd247a1","benches/html_rendering.rs":"9dd749395295e3c27e2dbdd784e34e0d797f150665b3e0af7803217e44902a80","benches/lib.rs":"8d66217a7712baae45d1101042284ddbe99508cc240b461781b0d25da185c108","build.rs":"ea58b69966ea4d7849d1053555b9c8631aefcc977cebdc5e412541527eb6baff","examples/event-filter.rs":"625cb8218e46b97f2553c3dd85a75b3b09bdcc8055c2ef670fa3930f924f5d75","examples/string-to-string.rs":"94cf4c6e1027186b73042fb9971e1469652682398c53e2dffe60d3dc30e72629","src/entities.rs":"08f6499fd2ed5ed5be89506f04e785b33eecb3b304418f812267dd8f01bbc6b6","src/escape.rs":"b5b073435e507e3d2897ea89f6143b5cf47d6cb140948450a255cc13fc2a3c5e","src/html.rs":"25ca58d7397209a9c4048efa647940e2ead21350de567c1c1013d3540438f678","src/lib.rs":"0e9ae448b1a5ff10add1aa6d9db3339e12f7da2bac438b39fb90f98880337c4e","src/linklabel.rs":"f174a9020c23770fe14eb377e85da8280e1ecc9ec4175108ebe38f507270bfeb","src/main.rs":"a009df64cf1f559ebc7b1768bd5842b42df01a7865ef75b8f92ee476360b3db7","src/parse.rs":"05d1023a36893f72b3d9208cfc5f3c42c4af58a3c9f88c7755efdc0a39a86a1b","src/puncttable.rs":"ff83b70b65d1666712cbba1c9949f65ea69d72b25a2aa960a7c8c8d1b5fbed08","src/scanners.rs":"7bebfde06556b74391dba5e9f9e2a12995a6e62816b414d4a8d6b610e6bf307c","src/simd.rs":"6b386b1bd224d10cd8203e7162dd9ed242970de2ce5c1583635285337f4a266f","src/strings.rs":"f19ebad46ab498eef93091d4c90ba9e673c85e848ddde82bf2aa5e1dc5fdc3ea","src/tree.rs":"7c3402a077ff8dd321967e9ac685ecf2038c51601afa38fe75f329ff9564a7f0","tests/errors.rs":"59199be255a0edd7cb9a8fd988738603ec82de3b6d3ec6d331d1c43e2957f5fc","tests/html.rs":"d305de4e8b209af0db749be4bf1137d446a6b3953c01af31ef7c0a807701d022","tests/lib.rs":"02bd5825bfc3d1ec24415049914774e84169bd2f7173475b050157f5539be781","tests/suite/footnotes.rs":"aa1471b4bbaf52efdd870ab078907c95c961bbfe9e2beddbe4dddb3f0bba1c7f","tests/suite/gfm_strikethrough.rs":"a43f9578651faf6f7a4488d4e6a31f371dea8fefa4892a1de63f6dad6ad7827a","tests/suite/gfm_table.rs":"de092e0542b418fb358116aa57810805a84cefe0710e9cf0df9018f37beedc30","tests/suite/gfm_tasklist.rs":"30f9c584eaaeae31cae5a915bc84da91202de2bfceec19faa46778bb87f88cab","tests/suite/mod.rs":"7bf32170c9662f76870139b47596643a60d105427b6a6f85dd15044caf82c6c8","tests/suite/regression.rs":"c3b3975e82167a6301adb9f4ac337f1fb7cf864bf49f7adde8bd80aeadb7d226","tests/suite/spec.rs":"de043bdf7cc81120ca779bf0c38e802c865ec632870f4efa0a30bfd47590426a","tests/suite/table.rs":"f65dd8530e39b846ca6a0eb40dadf850ab266e9925dd331531f404c1cc9d422e"},"package":"ca36dea94d187597e104a5c8e4b07576a8a45aa5db48a65e12940d3eb7461f55"} \ No newline at end of file +{"files":{"CONTRIBUTING.md":"a5bbc113fdcb8101367da47daba32ab10aa2377a825040c78d847d870108d849","Cargo.lock":"93c21661f9a1ff503e962bfbd03cfa2b81593950f4fe03d27be7ec12cc0e7283","Cargo.toml":"1357ee8e0c7af73f5fc6ef3af6bf6a690d881a2ec901747716156837f4d44b8d","LICENSE":"c4f10f55904bdb9f27d3fbf94c354926d6cfe8b982276e556238c258941b243b","README.md":"80716579bccdb6698bba46478533414de7730422ed1572248ded8e8600ca16fd","benches/html_rendering.rs":"59d9ad8ec6c61c26bf98aa81f35387b923be01f54209cc11ed9b21902e57b58a","benches/lib.rs":"e7a2ac16b4fd024d4da03221083ed48e00404b6e79ef1f8b449dec9a96776304","build.rs":"67314d695536299ac029099ac6b7be226befbae1aa6b9acf84d83cac5eb6abe1","examples/broken-link-callbacks.rs":"c7c124b5a5b81ad312204b2df7b0e4bc423b7bb92e9b45dc8e92d333ee1c790d","examples/event-filter.rs":"85ba4695e8e83c9c59b7b675a2fb8eb40ed5e2b56bc05679732f6e2f9589106d","examples/string-to-string.rs":"864aed51aaa8ffd556995fa937ea99b98d78feeb7bf7ae4b2872c749fb02b386","src/entities.rs":"1602f3c4d22c0b0e3a4a08467a50bf9d0c27aadf2e5661b15a2cda20da0895a9","src/escape.rs":"995eb646795e40b18da4220d750d5367abeb16d71a75e0b5f8fdb29ec1ebd527","src/html.rs":"a6d8312d761151f6dc99c46a543e7ca2562ccc9cb03969b782bb87c878027a85","src/lib.rs":"faeb88e98e8ebaa8dd04ec0e653ff046157fee96540bc21d0db9f6770ad98264","src/linklabel.rs":"503710b7c540ea025b22ed2c9378cd0a741d56cb957fdd962515dd3c054fcd30","src/main.rs":"5603394cb0c1bfe9b9d33c8098a6f14e9df2100038dab225f008f45c66d894e5","src/parse.rs":"3f1df87e634b4cf49abb5f07cd05110f55570bc35cb7694f3729cab760d988b7","src/puncttable.rs":"ddb35138b537c00dd2003daba2d07f1bc8154059a745d4e18b74732614b20f1c","src/scanners.rs":"fbc3d07881240bc033f6434875201a295d733f6bf4398bccf1fff424030d4893","src/simd.rs":"926e978a509d9be8722dad894ce39fb82398150aaba715ff6070cdb933477fb7","src/strings.rs":"06a7ee24e93d536238602ce909a8a9d1c854446abaab44368a3630f7f5c5eb00","src/tree.rs":"baed43da5de244cce9409fb4008ea9c1e858aac97907674530497ec5af13f840","tests/errors.rs":"3677dc76c0ec85b3b65389fe39a82cd7ab9420dd5e2cc5b5b11f490fde2f5fbf","tests/html.rs":"370f6d1f3aa5c872ec3fdd5506d732e2c4b93ca613fe5d4a62f3e5343c4909c9","tests/lib.rs":"3d049d013ca32bb2d4308fd444afc328b177457a08cf83d8f012ec8c6c1b88bf","tests/suite/footnotes.rs":"ce4e79abdcb63f5b7c1b508af7b7be96f82e1c7c11e6b43bd5e4a288db7e9cfa","tests/suite/gfm_strikethrough.rs":"452b050235dc61024661a635107d7a94c0dd8490c1720424035e0d15ee1b97c8","tests/suite/gfm_table.rs":"21e8e5e21922e99ad7f0669dea06671b8cdea8fa4b7ee728d211f18addde1644","tests/suite/gfm_tasklist.rs":"ac19d6b7cae67de503d89a51a9e7c6a2027a375c1d60d18322ff58cd6bef3193","tests/suite/mod.rs":"3341b8f910bb3911b548858ac1770050c517a41d95573bfe6dbd1ba02d1396ff","tests/suite/regression.rs":"b22dd8089a1801ed252ae59ffa1fdd12d974b23759e1131e612462ec76afe391","tests/suite/smart_punct.rs":"6ef4168ed33e62b2f0fafd0ed68f47abfd908f298f3fa1b9dcec7ddcf0f70d5c","tests/suite/spec.rs":"6ccf4eebbafb55d5cc9716b4d61d6abb50fda54a11f634e742d6db2df1cf99d9","tests/suite/table.rs":"a77c626892b335932fc3960d5c59228d60407b35a686f1a19ea560b272f13f32"},"package":"ffade02495f22453cd593159ea2f59827aae7f53fa8323f756799b670881dcf8"} \ No newline at end of file diff --git a/vendor/pulldown-cmark/CONTRIBUTING.md b/vendor/pulldown-cmark/CONTRIBUTING.md index 8572568675..5200aa4720 100644 --- a/vendor/pulldown-cmark/CONTRIBUTING.md +++ b/vendor/pulldown-cmark/CONTRIBUTING.md @@ -1,21 +1,21 @@ -Want to contribute? Great! First, read this page. - -### Before you contribute - -Before you start working on a larger contribution, you should get in touch with -us first through the issue tracker with your idea so that we can help out and -possibly guide you. Coordinating up front makes it much easier to avoid -frustration later on. - -### Getting familiar with the project - -**The architecture** is somewhat unique, it was originally inspired by [XML pull parsers](http://www.xmlpull.org), but ended up going in somewhat its own direction. to get familiar with it, -- start my reading the [README](README.md) page, which gives some details on the design of the parser (pull-based events) and some rationalization for it ; -- read the [blog post](https://fullyfaithful.eu/pulldown-cmark) about the release of Pulldown-cmark 0.3 by Marcus Klaas de Vries. - -**The source code** can be approached by skimming the [API documentation](https://docs.rs/pulldown-cmark/latest/pulldown_cmark) first, then explore the code for the main struct, [`Parser`](https://docs.rs/pulldown-cmark/latest/pulldown_cmark/struct.Parser.html) - -### Code reviews - -All submissions, including submissions by project members, require review. We -use GitHub pull requests for this purpose. +Want to contribute? Great! First, read this page. + +### Before you contribute + +Before you start working on a larger contribution, you should get in touch with +us first through the issue tracker with your idea so that we can help out and +possibly guide you. Coordinating up front makes it much easier to avoid +frustration later on. + +### Getting familiar with the project + +**The architecture** is somewhat unique, it was originally inspired by [XML pull parsers](http://www.xmlpull.org), but ended up going in somewhat its own direction. to get familiar with it, +- start my reading the [README](README.md) page, which gives some details on the design of the parser (pull-based events) and some rationalization for it ; +- read the [blog post](https://fullyfaithful.eu/pulldown-cmark) about the release of Pulldown-cmark 0.3 by Marcus Klaas de Vries. + +**The source code** can be approached by skimming the [API documentation](https://docs.rs/pulldown-cmark/latest/pulldown_cmark) first, then explore the code for the main struct, [`Parser`](https://docs.rs/pulldown-cmark/latest/pulldown_cmark/struct.Parser.html) + +### Code reviews + +All submissions, including submissions by project members, require review. We +use GitHub pull requests for this purpose. diff --git a/vendor/pulldown-cmark/Cargo.lock b/vendor/pulldown-cmark/Cargo.lock index 2c8e742e09..7a646e9f84 100644 --- a/vendor/pulldown-cmark/Cargo.lock +++ b/vendor/pulldown-cmark/Cargo.lock @@ -13,14 +13,14 @@ name = "atty" version = "0.2.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -36,7 +36,7 @@ dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -64,7 +64,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "clap" -version = "2.33.1" +version = "2.33.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -79,7 +79,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)", "cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", - "clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)", + "clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)", "criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)", "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -87,12 +87,12 @@ dependencies = [ "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", "oorandom 11.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", "serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", "tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -106,6 +106,15 @@ dependencies = [ "itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)", ] +[[package]] +name = "crossbeam-channel" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.7.3" @@ -121,7 +130,7 @@ name = "crossbeam-epoch" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -130,22 +139,12 @@ dependencies = [ "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -159,7 +158,7 @@ dependencies = [ "csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -172,7 +171,7 @@ dependencies = [ [[package]] name = "either" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -198,7 +197,7 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -209,10 +208,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -220,12 +219,12 @@ name = "html5ever" version = "0.25.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -233,7 +232,7 @@ name = "itertools" version = "0.9.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -243,10 +242,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "js-sys" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -256,12 +255,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "log" -version = "0.4.8" +version = "0.4.11" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", @@ -277,12 +276,12 @@ name = "markup5ever" version = "0.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "phf 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf_codegen 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -314,7 +313,7 @@ name = "memoffset" version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -327,7 +326,7 @@ name = "num-traits" version = "0.2.12" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -335,8 +334,8 @@ name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -383,15 +382,15 @@ name = "plotters" version = "0.2.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", "num-traits 0.2.12 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "web-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -401,7 +400,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -409,7 +408,7 @@ dependencies = [ [[package]] name = "pulldown-cmark" -version = "0.7.2" +version = "0.8.0" dependencies = [ "bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)", "criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -428,7 +427,7 @@ name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -437,7 +436,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -449,7 +448,7 @@ name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -479,22 +478,22 @@ dependencies = [ [[package]] name = "rayon" -version = "1.3.1" +version = "1.4.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "crossbeam-channel 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -565,7 +564,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -574,27 +573,27 @@ version = "0.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.114" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_json" -version = "1.0.56" +version = "1.0.57" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "ryu 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -611,7 +610,7 @@ dependencies = [ "new_debug_unreachable 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -621,16 +620,16 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", "phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "syn" -version = "1.0.33" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -663,10 +662,11 @@ dependencies = [ [[package]] name = "time" -version = "0.1.43" +version = "0.1.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", + "wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", "winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -675,8 +675,8 @@ name = "tinytemplate" version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -722,62 +722,67 @@ name = "wasi" version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "wasi" +version = "0.10.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" + [[package]] name = "wasm-bindgen" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-backend" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-macro-support 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-macro-support" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-backend 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "wasm-bindgen-shared" -version = "0.2.64" +version = "0.2.67" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "web-sys" -version = "0.3.41" +version = "0.3.44" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)", - "wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)", + "js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)", + "wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -812,44 +817,44 @@ name = "xml5ever" version = "0.16.1" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)", + "log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)", "mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)", "markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)", - "time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)", + "time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)", ] [metadata] "checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" "checksum atty 0.2.14 (registry+https://github.com/rust-lang/crates.io-index)" = "d9b39be18770d11421cdb1b9947a45dd3f37e93092cbf377614828a319d5fee8" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" "checksum bitflags 1.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cf1de2fe8c75bc145a2f577add951f8134889b4795d47466a54a5c846d691693" "checksum bstr 0.2.13 (registry+https://github.com/rust-lang/crates.io-index)" = "31accafdb70df7871592c058eca3985b71104e15ac32f64706022c58867da931" "checksum bumpalo 3.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2e8c087f005730276d1096a652e92a8bacee2e2472bcc9715a74d2bec38b5820" "checksum byteorder 1.3.4 (registry+https://github.com/rust-lang/crates.io-index)" = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" "checksum cast 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "4b9434b9a5aa1450faa3f9cb14ea0e8c53bb5d2b3c1bfd1ab4fc03e9f33fbfb0" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" -"checksum clap 2.33.1 (registry+https://github.com/rust-lang/crates.io-index)" = "bdfa80d47f954d53a35a64987ca1422f495b8d6483c0fe9f7117b36c2a792129" +"checksum clap 2.33.3 (registry+https://github.com/rust-lang/crates.io-index)" = "37e58ac78573c40708d45522f0d80fa2f01cc4f9b4e2bf749807255454312002" "checksum criterion 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "70daa7ceec6cf143990669a04c7df13391d55fb27bd4079d252fca774ba244d8" "checksum criterion-plot 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "e022feadec601fba1649cfa83586381a4ad31c6bf3a9ab7d408118b05dd9889d" +"checksum crossbeam-channel 0.4.3 (registry+https://github.com/rust-lang/crates.io-index)" = "09ee0cc8804d5393478d743b035099520087a5186f3b93fa58cec08fa62407b6" "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum csv 1.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "00affe7f6ab566df61b4be3ce8cf16bc2576bca0963ceb0955e45d514bf9a279" "checksum csv-core 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "2b2466559f260f48ad25fe6317b3c8dac77b5bdb5763ac7d9d6103530663bc90" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" "checksum futf 0.1.4 (registry+https://github.com/rust-lang/crates.io-index)" = "7c9c1ce3fa9336301af935ab852c437817d14cd33690446569392e65170aac3b" "checksum getopts 0.2.21 (registry+https://github.com/rust-lang/crates.io-index)" = "14dbbfd5c71d70241ecf9e6f13737f7b5ce823821063188d7e46c41d371eebd5" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" "checksum half 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d36fab90f82edc3c747f9d438e06cf0a491055896f2a279638bb5beed6c40177" -"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" "checksum html5ever 0.25.1 (registry+https://github.com/rust-lang/crates.io-index)" = "aafcf38a1a36118242d29b92e1b08ef84e67e4a5ed06e0a80be20e6a32bfed6b" "checksum itertools 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "284f18f85651fe11e8a991b2adb42cb078325c996ed026d994719efcfca1d54b" "checksum itoa 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" -"checksum js-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "c4b9172132a62451e56142bff9afc91c8e4a4500aa5b847da36815b63bfda916" +"checksum js-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "85a7e2c92a4804dd459b86c339278d0fe87cf93757fae222c3fa3ae75458bc73" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" -"checksum log 0.4.8 (registry+https://github.com/rust-lang/crates.io-index)" = "14b6052be84e6b71ab17edffc2eeabf5c2c3ae1fdb464aae35ac50c67a44e1f7" +"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" +"checksum log 0.4.11 (registry+https://github.com/rust-lang/crates.io-index)" = "4fabed175da42fed1fa0746b0ea71f412aa9d35e76e95e59b192c64b9dc2bf8b" "checksum mac 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "c41e0c4fef86961ac6d6f8a82609f55f31b05e4fce149ac5710e439df7619ba4" "checksum markup5ever 0.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "aae38d669396ca9b707bfc3db254bc382ddb94f57cc5c235f34623a669a01dab" "checksum markup5ever_rcdom 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f015da43bcd8d4f144559a3423f4591d69b8ce0652c905374da7205df336ae2b" @@ -865,17 +870,17 @@ dependencies = [ "checksum phf_generator 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "17367f0cc86f2d25802b2c26ee58a7b23faeccf78a396094c13dced0d0182526" "checksum phf_shared 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c00cf8b9eafe68dde5e9eaa2cef8ee84a9336a47d566ec55ca16589633b65af7" "checksum plotters 0.2.15 (registry+https://github.com/rust-lang/crates.io-index)" = "0d1685fbe7beba33de0330629da9d955ac75bd54f33d7b79f9a895590124f6bb" -"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" +"checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" "checksum precomputed-hash 0.1.1 (registry+https://github.com/rust-lang/crates.io-index)" = "925383efa346730478fb4838dbe9137d2a47675ad789c546d150a6e1dd4ab31c" -"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_pcg 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "16abd0c1b639e9eb4d7c50c0b8100b0d0f849be2349829c740fe8e6eb4816429" -"checksum rayon 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080" -"checksum rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +"checksum rayon 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270" +"checksum rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-automata 0.1.9 (registry+https://github.com/rust-lang/crates.io-index)" = "ae1ded71d66a4a97f5e961fd0cb25a5f366a42a41570d16a763a69c092c26ae4" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" @@ -885,18 +890,18 @@ dependencies = [ "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" "checksum semver 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)" = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403" "checksum semver-parser 0.7.0 (registry+https://github.com/rust-lang/crates.io-index)" = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3" -"checksum serde 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "5317f7588f0a5078ee60ef675ef96735a1442132dc645eb1d12c018620ed8cd3" +"checksum serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" "checksum serde_cbor 0.11.1 (registry+https://github.com/rust-lang/crates.io-index)" = "1e18acfa2f90e8b735b2836ab8d538de304cbb6729a7360729ea5a895d15a622" -"checksum serde_derive 1.0.114 (registry+https://github.com/rust-lang/crates.io-index)" = "2a0be94b04690fbaed37cddffc5c134bf537c8e3329d53e982fe04c374978f8e" -"checksum serde_json 1.0.56 (registry+https://github.com/rust-lang/crates.io-index)" = "3433e879a558dde8b5e8feb2a04899cf34fdde1fafb894687e52105fc1162ac3" +"checksum serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" +"checksum serde_json 1.0.57 (registry+https://github.com/rust-lang/crates.io-index)" = "164eacbdb13512ec2745fb09d51fd5b22b0d65ed294a1dcf7285a360c80a675c" "checksum siphasher 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "fa8f3741c7372e75519bd9346068370c9cdaabcc1f9599cbcf2a2719352286b7" "checksum string_cache 0.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "2940c75beb4e3bf3a494cef919a747a2cb81e52571e212bfbd185074add7208a" "checksum string_cache_codegen 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f24c8e5e19d22a726626f1a5e16fe15b132dcf21d10177fa5a45ce7962996b97" -"checksum syn 1.0.33 (registry+https://github.com/rust-lang/crates.io-index)" = "e8d5d96e8cbb005d6959f119f773bfaebb5684296108fb32600c00cde305b2cd" +"checksum syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" "checksum tendril 0.4.1 (registry+https://github.com/rust-lang/crates.io-index)" = "707feda9f2582d5d680d733e38755547a3e8fb471e7ba11452ecfd9ce93a5d3b" "checksum textwrap 0.11.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d326610f408c7a4eb6f51c37c330e496b08506c9457c9d34287ecc38809fb060" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum time 0.1.43 (registry+https://github.com/rust-lang/crates.io-index)" = "ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438" +"checksum time 0.1.44 (registry+https://github.com/rust-lang/crates.io-index)" = "6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255" "checksum tinytemplate 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "6d3dc76004a03cec1c5932bca4cdc2e39aaa798e3f82363dd94f9adf6098c12f" "checksum unicase 2.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "50f37be617794602aabbeee0be4f259dc1778fabe05e2d67ee8f79326d5cb4f6" "checksum unicode-width 0.1.8 (registry+https://github.com/rust-lang/crates.io-index)" = "9337591893a19b88d8d87f2cec1e73fad5cdfd10e5a6f349f498ad6ea2ffb1e3" @@ -904,13 +909,14 @@ dependencies = [ "checksum utf-8 0.7.5 (registry+https://github.com/rust-lang/crates.io-index)" = "05e42f7c18b8f902290b009cde6d651262f956c98bc51bca4cd1d511c9cd85c7" "checksum version_check 0.9.2 (registry+https://github.com/rust-lang/crates.io-index)" = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" "checksum walkdir 2.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "777182bc735b6424e1a57516d35ed72cb8019d85c8c9bf536dccb3445c1a2f7d" +"checksum wasi 0.10.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" -"checksum wasm-bindgen 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "6a634620115e4a229108b71bde263bb4220c483b3f07f5ba514ee8d15064c4c2" -"checksum wasm-bindgen-backend 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3e53963b583d18a5aa3aaae4b4c1cb535218246131ba22a71f05b518098571df" -"checksum wasm-bindgen-macro 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "3fcfd5ef6eec85623b4c6e844293d4516470d8f19cd72d0d12246017eb9060b8" -"checksum wasm-bindgen-macro-support 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "9adff9ee0e94b926ca81b57f57f86d5545cdcb1d259e21ec9bdd95b901754c75" -"checksum wasm-bindgen-shared 0.2.64 (registry+https://github.com/rust-lang/crates.io-index)" = "7f7b90ea6c632dd06fd765d44542e234d5e63d9bb917ecd64d79778a13bd79ae" -"checksum web-sys 0.3.41 (registry+https://github.com/rust-lang/crates.io-index)" = "863539788676619aac1a23e2df3655e96b32b0e05eb72ca34ba045ad573c625d" +"checksum wasm-bindgen 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "f0563a9a4b071746dd5aedbc3a28c6fe9be4586fb3fbadb67c400d4f53c6b16c" +"checksum wasm-bindgen-backend 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "bc71e4c5efa60fb9e74160e89b93353bc24059999c0ae0fb03affc39770310b0" +"checksum wasm-bindgen-macro 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "97c57cefa5fa80e2ba15641578b44d36e7a64279bc5ed43c6dbaf329457a2ed2" +"checksum wasm-bindgen-macro-support 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "841a6d1c35c6f596ccea1f82504a192a60378f64b3bb0261904ad8f2f5657556" +"checksum wasm-bindgen-shared 0.2.67 (registry+https://github.com/rust-lang/crates.io-index)" = "93b162580e34310e5931c4b792560108b10fd14d64915d7fff8ff00180e70092" +"checksum web-sys 0.3.44 (registry+https://github.com/rust-lang/crates.io-index)" = "dda38f4e5ca63eda02c059d243aa25b5f35ab98451e518c51612cd0f1bd19a47" "checksum winapi 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419" "checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6" "checksum winapi-util 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "70ec6ce85bb158151cae5e5c87f95a8e97d2c0c4b001223f33a334e3ce5de178" diff --git a/vendor/pulldown-cmark/Cargo.toml b/vendor/pulldown-cmark/Cargo.toml index c85952d7fa..973a2130db 100644 --- a/vendor/pulldown-cmark/Cargo.toml +++ b/vendor/pulldown-cmark/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "pulldown-cmark" -version = "0.7.2" +version = "0.8.0" authors = ["Raph Levien ", "Marcus Klaas de Vries "] build = "build.rs" exclude = ["/third_party/**/*", "/tools/**/*", "/specs/**/*", "/fuzzer/**/*", "/azure-pipelines.yml"] diff --git a/vendor/pulldown-cmark/LICENSE b/vendor/pulldown-cmark/LICENSE index c10685cc3d..cd8655ebdb 100644 --- a/vendor/pulldown-cmark/LICENSE +++ b/vendor/pulldown-cmark/LICENSE @@ -1,21 +1,21 @@ -The MIT License - -Copyright 2015 Google Inc. All rights reserved. - -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. +The MIT License + +Copyright 2015 Google Inc. All rights reserved. + +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 --git a/vendor/pulldown-cmark/README.md b/vendor/pulldown-cmark/README.md index 96e3437902..a84ebcc442 100644 --- a/vendor/pulldown-cmark/README.md +++ b/vendor/pulldown-cmark/README.md @@ -1,152 +1,152 @@ -# pulldown-cmark - -[![Build Status](https://dev.azure.com/raphlinus/pulldown-cmark/_apis/build/status/pulldown-cmark-CI?branchName=master)](https://dev.azure.com/raphlinus/pulldown-cmark/_build/latest?definitionId=2&branchName=master) -[![Docs](https://docs.rs/pulldown-cmark/badge.svg)](https://docs.rs/pulldown-cmark) -[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark.svg?maxAge=2592000)](https://crates.io/crates/pulldown-cmark) - -[Documentation](https://docs.rs/pulldown-cmark/) - -This library is a pull parser for [CommonMark](http://commonmark.org/), written -in [Rust](http://www.rust-lang.org/). It comes with a simple command-line tool, -useful for rendering to HTML, and is also designed to be easy to use from as -a library. - -It is designed to be: - -* Fast; a bare minimum of allocation and copying -* Safe; written in pure Rust with no unsafe blocks -* Versatile; in particular source-maps are supported -* Correct; the goal is 100% compliance with the [CommonMark spec](http://spec.commonmark.org/) - -Further, it optionally supports parsing footnotes, -[Github flavored tables](https://github.github.com/gfm/#tables-extension-), -[Github flavored task lists](https://github.github.com/gfm/#task-list-items-extension-) and -[strikethrough](https://github.github.com/gfm/#strikethrough-extension-). - -Rustc 1.34 or newer is required to build the crate. - -## Why a pull parser? - -There are many parsers for Markdown and its variants, but to my knowledge none -use pull parsing. Pull parsing has become popular for XML, especially for -memory-conscious applications, because it uses dramatically less memory than -constructing a document tree, but is much easier to use than push parsers. Push -parsers are notoriously difficult to use, and also often error-prone because of -the need for user to delicately juggle state in a series of callbacks. - -In a clean design, the parsing and rendering stages are neatly separated, but -this is often sacrificed in the name of performance and expedience. Many Markdown -implementations mix parsing and rendering together, and even designs that try -to separate them (such as the popular [hoedown](https://github.com/hoedown/hoedown)), -make the assumption that the rendering process can be fully represented as a -serialized string. - -Pull parsing is in some sense the most versatile architecture. It's possible to -drive a push interface, also with minimal memory, and quite straightforward to -construct an AST. Another advantage is that source-map information (the mapping -between parsed blocks and offsets within the source text) is readily available; -you can call `into_offset_iter()` to create an iterator that yields `(Event, Range)` -pairs, where the second element is the event's corresponding range in the source -document. - -While manipulating ASTs is the most flexible way to transform documents, -operating on iterators is surprisingly easy, and quite efficient. Here, for -example, is the code to transform soft line breaks into hard breaks: - -```rust -let parser = parser.map(|event| match event { - Event::SoftBreak => Event::HardBreak, - _ => event -}); -``` - -Or expanding an abbreviation in text: - -```rust -let parser = parser.map(|event| match event { - Event::Text(text) => Event::Text(text.replace("abbr", "abbreviation").into()), - _ => event -}); -``` - -Another simple example is code to determine the max nesting level: - -```rust -let mut max_nesting = 0; -let mut level = 0; -for event in parser { - match event { - Event::Start(_) => { - level += 1; - max_nesting = std::cmp::max(max_nesting, level); - } - Event::End(_) => level -= 1, - _ => () - } -} -``` - -There are some basic but fully functional examples of the usage of the crate in the -`examples` directory of this repository. - -## Using Rust idiomatically - -A lot of the internal scanning code is written at a pretty low level (it -pretty much scans byte patterns for the bits of syntax), but the external -interface is designed to be idiomatic Rust. - -Pull parsers are at heart an iterator of events (start and end tags, text, -and other bits and pieces). The parser data structure implements the -Rust Iterator trait directly, and Event is an enum. Thus, you can use the -full power and expressivity of Rust's iterator infrastructure, including -for loops and `map` (as in the examples above), collecting the events into -a vector (for recording, playback, and manipulation), and more. - -Further, the `Text` event (representing text) is a small copy-on-write string. -The vast majority of text fragments are just -slices of the source document. For these, copy-on-write gives a convenient -representation that requires no allocation or copying, but allocated -strings are available when they're needed. Thus, when rendering text to -HTML, most text is copied just once, from the source document to the -HTML buffer. - -When using the pulldown-cmark's own HTML renderer, make sure to write to a buffered -target like a `Vec` or `String`. Since it performs many (very) small writes, writing -directly to stdout, files, or sockets is detrimental to performance. Such writers can -be wrapped in a [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html). - -## Build options - -By default, the binary is built as well. If you don't want/need it, then build like this: - -```bash -> cargo build --no-default-features -``` - -Or put in your `Cargo.toml` file: - -```toml -pulldown-cmark = { version = "0.7", default-features = false } -``` - -SIMD accelerated scanners are available for the x64 platform from version 0.5 onwards. To -enable them, build with simd feature: - -```bash -> cargo build --release --features simd -``` - -Or add the feature to your project's `Cargo.toml`: - -```toml -pulldown-cmark = { version = "0.7", default-features = false, features = ["simd"] } -``` - -## Authors - -The main author is Raph Levien. The implementation of the new design (v0.3+) was completed by Marcus Klaas de Vries. - -## Contributions - -We gladly accept contributions via GitHub pull requests. Please see -[CONTRIBUTING.md](CONTRIBUTING.md) for more details. +# pulldown-cmark + +[![Build Status](https://dev.azure.com/raphlinus/pulldown-cmark/_apis/build/status/pulldown-cmark-CI?branchName=master)](https://dev.azure.com/raphlinus/pulldown-cmark/_build/latest?definitionId=2&branchName=master) +[![Docs](https://docs.rs/pulldown-cmark/badge.svg)](https://docs.rs/pulldown-cmark) +[![Crates.io](https://img.shields.io/crates/v/pulldown-cmark.svg?maxAge=2592000)](https://crates.io/crates/pulldown-cmark) + +[Documentation](https://docs.rs/pulldown-cmark/) + +This library is a pull parser for [CommonMark](http://commonmark.org/), written +in [Rust](http://www.rust-lang.org/). It comes with a simple command-line tool, +useful for rendering to HTML, and is also designed to be easy to use from as +a library. + +It is designed to be: + +* Fast; a bare minimum of allocation and copying +* Safe; written in pure Rust with no unsafe blocks +* Versatile; in particular source-maps are supported +* Correct; the goal is 100% compliance with the [CommonMark spec](http://spec.commonmark.org/) + +Further, it optionally supports parsing footnotes, +[Github flavored tables](https://github.github.com/gfm/#tables-extension-), +[Github flavored task lists](https://github.github.com/gfm/#task-list-items-extension-) and +[strikethrough](https://github.github.com/gfm/#strikethrough-extension-). + +Rustc 1.36 or newer is required to build the crate. + +## Why a pull parser? + +There are many parsers for Markdown and its variants, but to my knowledge none +use pull parsing. Pull parsing has become popular for XML, especially for +memory-conscious applications, because it uses dramatically less memory than +constructing a document tree, but is much easier to use than push parsers. Push +parsers are notoriously difficult to use, and also often error-prone because of +the need for user to delicately juggle state in a series of callbacks. + +In a clean design, the parsing and rendering stages are neatly separated, but +this is often sacrificed in the name of performance and expedience. Many Markdown +implementations mix parsing and rendering together, and even designs that try +to separate them (such as the popular [hoedown](https://github.com/hoedown/hoedown)), +make the assumption that the rendering process can be fully represented as a +serialized string. + +Pull parsing is in some sense the most versatile architecture. It's possible to +drive a push interface, also with minimal memory, and quite straightforward to +construct an AST. Another advantage is that source-map information (the mapping +between parsed blocks and offsets within the source text) is readily available; +you can call `into_offset_iter()` to create an iterator that yields `(Event, Range)` +pairs, where the second element is the event's corresponding range in the source +document. + +While manipulating ASTs is the most flexible way to transform documents, +operating on iterators is surprisingly easy, and quite efficient. Here, for +example, is the code to transform soft line breaks into hard breaks: + +```rust +let parser = parser.map(|event| match event { + Event::SoftBreak => Event::HardBreak, + _ => event +}); +``` + +Or expanding an abbreviation in text: + +```rust +let parser = parser.map(|event| match event { + Event::Text(text) => Event::Text(text.replace("abbr", "abbreviation").into()), + _ => event +}); +``` + +Another simple example is code to determine the max nesting level: + +```rust +let mut max_nesting = 0; +let mut level = 0; +for event in parser { + match event { + Event::Start(_) => { + level += 1; + max_nesting = std::cmp::max(max_nesting, level); + } + Event::End(_) => level -= 1, + _ => () + } +} +``` + +There are some basic but fully functional examples of the usage of the crate in the +`examples` directory of this repository. + +## Using Rust idiomatically + +A lot of the internal scanning code is written at a pretty low level (it +pretty much scans byte patterns for the bits of syntax), but the external +interface is designed to be idiomatic Rust. + +Pull parsers are at heart an iterator of events (start and end tags, text, +and other bits and pieces). The parser data structure implements the +Rust Iterator trait directly, and Event is an enum. Thus, you can use the +full power and expressivity of Rust's iterator infrastructure, including +for loops and `map` (as in the examples above), collecting the events into +a vector (for recording, playback, and manipulation), and more. + +Further, the `Text` event (representing text) is a small copy-on-write string. +The vast majority of text fragments are just +slices of the source document. For these, copy-on-write gives a convenient +representation that requires no allocation or copying, but allocated +strings are available when they're needed. Thus, when rendering text to +HTML, most text is copied just once, from the source document to the +HTML buffer. + +When using the pulldown-cmark's own HTML renderer, make sure to write to a buffered +target like a `Vec` or `String`. Since it performs many (very) small writes, writing +directly to stdout, files, or sockets is detrimental to performance. Such writers can +be wrapped in a [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html). + +## Build options + +By default, the binary is built as well. If you don't want/need it, then build like this: + +```bash +> cargo build --no-default-features +``` + +Or put in your `Cargo.toml` file: + +```toml +pulldown-cmark = { version = "0.8", default-features = false } +``` + +SIMD accelerated scanners are available for the x64 platform from version 0.5 onwards. To +enable them, build with simd feature: + +```bash +> cargo build --release --features simd +``` + +Or add the feature to your project's `Cargo.toml`: + +```toml +pulldown-cmark = { version = "0.8", default-features = false, features = ["simd"] } +``` + +## Authors + +The main author is Raph Levien. The implementation of the new design (v0.3+) was completed by Marcus Klaas de Vries. + +## Contributions + +We gladly accept contributions via GitHub pull requests. Please see +[CONTRIBUTING.md](CONTRIBUTING.md) for more details. diff --git a/vendor/pulldown-cmark/benches/html_rendering.rs b/vendor/pulldown-cmark/benches/html_rendering.rs index 4a2202843d..45695ddb11 100644 --- a/vendor/pulldown-cmark/benches/html_rendering.rs +++ b/vendor/pulldown-cmark/benches/html_rendering.rs @@ -1,77 +1,101 @@ -#[macro_use] -extern crate criterion; -extern crate pulldown_cmark; - -use criterion::Criterion; -use pulldown_cmark::{html, Options, Parser}; -use std::str::from_utf8; - -static CRDT_BYTES: &[u8] = include_bytes!("../third_party/xi-editor/crdt.md"); - -fn criterion_benchmark(c: &mut Criterion) { - c.bench_function("crdt_total", |b| { - let input = from_utf8(CRDT_BYTES).unwrap(); - let mut buf = String::with_capacity(input.len() * 3 / 2); - - b.iter(|| { - buf.clear(); - html::push_html(&mut buf, Parser::new_ext(input, Options::empty())); - }) - }); - - c.bench_function("crdt_html", |b| { - let input = from_utf8(CRDT_BYTES).unwrap(); - let events: Vec<_> = Parser::new_ext(input, Options::empty()).collect(); - let mut buf = String::with_capacity(input.len() * 3 / 2); - - b.iter(|| { - buf.clear(); - html::push_html(&mut buf, events.clone().into_iter()); - }) - }); - - c.bench_function("crdt_parse", |b| { - let input = from_utf8(CRDT_BYTES).unwrap(); - - b.iter(|| Parser::new_ext(input, Options::empty()).count()) - }); - - c.bench_function("links_n_emphasis", |b| { - let input = r#"""This is a [link](example.com). **Cool!** - -This is a [link](example.com). **Cool!** - -This is a [link](example.com). **Cool!** - -This is a [link](example.com). **Cool!** -"""#; - - b.iter(|| Parser::new_ext(input, Options::empty()).count()); - }); - - c.bench_function("unescapes", |b| { - let input = "This is by far my favourite unicode code point: પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ - પ પ પ પ પ પ પ પ પ પ પ પ પ પ"; - - b.iter(|| Parser::new_ext(input, Options::empty()).count()); - }); - - c.bench_function("autolinks_n_html", |b| { - let input = "Drop me a line at . Thanks! - Drop me a line at . Thanks! - Drop me a line at . Thanks! - Drop me a line at . Thanks! - Drop me a line at . Thanks! "; - - b.iter(|| Parser::new_ext(input, Options::empty()).count()); - }); -} - -criterion_group!(benches, criterion_benchmark); -criterion_main!(benches); +#[macro_use] +extern crate criterion; +extern crate pulldown_cmark; + +use criterion::Criterion; +use pulldown_cmark::{html, Options, Parser}; +use std::str::from_utf8; + +static CRDT_BYTES: &[u8] = include_bytes!("../third_party/xi-editor/crdt.md"); + +fn criterion_benchmark(c: &mut Criterion) { + let mut full_opts = Options::empty(); + full_opts.insert(Options::ENABLE_TABLES); + full_opts.insert(Options::ENABLE_FOOTNOTES); + full_opts.insert(Options::ENABLE_STRIKETHROUGH); + full_opts.insert(Options::ENABLE_TASKLISTS); + full_opts.insert(Options::ENABLE_SMART_PUNCTUATION); + + c.bench_function("crdt_total", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, Parser::new_ext(input, Options::empty())); + }) + }); + + c.bench_function("crdt_html", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + let events: Vec<_> = Parser::new_ext(input, Options::empty()).collect(); + let mut buf = String::with_capacity(input.len() * 3 / 2); + + b.iter(|| { + buf.clear(); + html::push_html(&mut buf, events.clone().into_iter()); + }) + }); + + c.bench_function("crdt_all_options_parse", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + + b.iter(|| Parser::new_ext(input, full_opts).count()) + }); + + c.bench_function("crdt_parse", |b| { + let input = from_utf8(CRDT_BYTES).unwrap(); + + b.iter(|| Parser::new_ext(input, Options::empty()).count()) + }); + + c.bench_function("smart_punctuation", |b| { + let input = r#"""'This here a real "quote"' + +And -- if you're interested -- some em-dashes. Wait --- she actually said that? + +Wow... Becky is so 'mean'! +"""#; + + b.iter(|| Parser::new_ext(input, full_opts).count()); + }); + + c.bench_function("links_n_emphasis", |b| { + let input = r#"""This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** + +This is a [link](example.com). **Cool!** +"""#; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("unescapes", |b| { + let input = "This is by far my favourite unicode code point: પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ + પ પ પ પ પ પ પ પ પ પ પ પ પ પ"; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); + + c.bench_function("autolinks_n_html", |b| { + let input = "Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! + Drop me a line at . Thanks! "; + + b.iter(|| Parser::new_ext(input, Options::empty()).count()); + }); +} + +criterion_group!(benches, criterion_benchmark); +criterion_main!(benches); diff --git a/vendor/pulldown-cmark/benches/lib.rs b/vendor/pulldown-cmark/benches/lib.rs index 392aa4e12f..d0b8dfcb80 100644 --- a/vendor/pulldown-cmark/benches/lib.rs +++ b/vendor/pulldown-cmark/benches/lib.rs @@ -1,49 +1,49 @@ -#![feature(test)] - -extern crate pulldown_cmark; -extern crate test; - -mod to_html { - use pulldown_cmark::{html, Options, Parser}; - - fn render_html(text: &str, opts: Options) -> String { - let mut s = String::with_capacity(text.len() * 3 / 2); - let p = Parser::new_ext(text, opts); - html::push_html(&mut s, p); - s - } - - #[bench] - fn pathological_codeblocks1(b: &mut test::Bencher) { - // Note that `buf` grows quadratically with number of - // iterations. The point here is that the render time shouldn't - // grow faster than that. - let mut buf = String::new(); - for i in 1..1000 { - for _ in 0..i { - buf.push('`'); - } - buf.push(' '); - } - - b.iter(|| render_html(&buf, Options::empty())); - } - - #[bench] - fn advanced_pathological_codeblocks(b: &mut test::Bencher) { - let mut buf = String::new(); - let mut i = 1; - while buf.len() < 1250 { - for _ in 0..i { - buf.push('`'); - } - buf.push(' '); - i += 1; - } - for _ in 0..buf.len() { - buf.push_str("*a* "); - } - - b.iter(|| render_html(&buf, Options::empty())); - } -} +#![feature(test)] + +extern crate pulldown_cmark; +extern crate test; + +mod to_html { + use pulldown_cmark::{html, Options, Parser}; + + fn render_html(text: &str, opts: Options) -> String { + let mut s = String::with_capacity(text.len() * 3 / 2); + let p = Parser::new_ext(text, opts); + html::push_html(&mut s, p); + s + } + + #[bench] + fn pathological_codeblocks1(b: &mut test::Bencher) { + // Note that `buf` grows quadratically with number of + // iterations. The point here is that the render time shouldn't + // grow faster than that. + let mut buf = String::new(); + for i in 1..1000 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + } + + b.iter(|| render_html(&buf, Options::empty())); + } + + #[bench] + fn advanced_pathological_codeblocks(b: &mut test::Bencher) { + let mut buf = String::new(); + let mut i = 1; + while buf.len() < 1250 { + for _ in 0..i { + buf.push('`'); + } + buf.push(' '); + i += 1; + } + for _ in 0..buf.len() { + buf.push_str("*a* "); + } + + b.iter(|| render_html(&buf, Options::empty())); + } +} diff --git a/vendor/pulldown-cmark/build.rs b/vendor/pulldown-cmark/build.rs index 68f5689976..97ce420ddd 100644 --- a/vendor/pulldown-cmark/build.rs +++ b/vendor/pulldown-cmark/build.rs @@ -1,187 +1,186 @@ -fn main() { - generate_tests_from_spec() -} - -// If the "gen-tests" feature is absent, -// this function will be compiled down to nothing -#[cfg(not(feature = "gen-tests"))] -fn generate_tests_from_spec() {} - -// If the feature is present, generate tests -// from any .txt file present in the specs/ directory -// -// Test cases are present in the files in the -// following format: -// -// ```````````````````````````````` example -// markdown -// . -// expected html output -// ```````````````````````````````` -#[cfg(feature = "gen-tests")] -fn generate_tests_from_spec() { - use std::fs::{self, File}; - use std::io::{Read, Write}; - use std::path::PathBuf; - - // This is a hardcoded path to the CommonMark spec because it is not situated in - // the specs/ directory. It's in an array to easily chain it to the other iterator - // and make it easy to eventually add other hardcoded paths in the future if needed - let hardcoded = [ - "./third_party/CommonMark/spec.txt", - "./third_party/GitHub/gfm_table.txt", - "./third_party/GitHub/gfm_strikethrough.txt", - "./third_party/GitHub/gfm_tasklist.txt", - ]; - let hardcoded_iter = hardcoded.into_iter().map(PathBuf::from); - - // Create an iterator over the files in the specs/ directory that have a .txt extension - let spec_files = fs::read_dir("./specs") - .expect("Could not find the 'specs' directory") - .filter_map(Result::ok) - .map(|d| d.path()) - .filter(|p| p.extension().map(|e| e.to_owned()).is_some()) - .chain(hardcoded_iter) - .collect::>(); - - for file_path in &spec_files { - let mut raw_spec = String::new(); - - File::open(&file_path) - .and_then(|mut f| f.read_to_string(&mut raw_spec)) - .expect("Could not read the spec file"); - - let rs_test_file = PathBuf::from("./tests/suite/") - .join(file_path.file_name().expect("Invalid filename")) - .with_extension("rs"); - - let mut spec_rs = - File::create(&rs_test_file).expect(&format!("Could not create {:?}", rs_test_file)); - - let spec_name = file_path.file_stem().unwrap().to_str().unwrap(); - - let spec = Spec::new(&raw_spec); - let mut n_tests = 0; - - spec_rs - .write(b"// This file is auto-generated by the build script\n") - .unwrap(); - spec_rs - .write(b"// Please, do not modify it manually\n") - .unwrap(); - spec_rs - .write(b"\nuse super::test_markdown_html;\n") - .unwrap(); - - for (i, testcase) in spec.enumerate() { - spec_rs - .write_fmt(format_args!( - r###" -#[test] -fn {}_test_{i}() {{ - let original = r##"{original}"##; - let expected = r##"{expected}"##; - - test_markdown_html(original, expected); -}} -"###, - spec_name, - i = i + 1, - original = testcase.original, - expected = testcase.expected - )) - .unwrap(); - - n_tests += 1; - } - - println!( - "cargo:warning=Generated {} tests in {:?}", - n_tests, rs_test_file - ); - } - - // write mods to suite/mod.rs - let suite_mod_file = PathBuf::from("./tests/suite/mod").with_extension("rs"); - - let mut mod_rs = - File::create(&suite_mod_file).expect(&format!("Could not create {:?}", &suite_mod_file)); - - mod_rs - .write(b"// This file is auto-generated by the build script\n") - .unwrap(); - mod_rs - .write(b"// Please, do not modify it manually\n") - .unwrap(); - mod_rs - .write(b"\npub use super::test_markdown_html;\n\n") - .unwrap(); - - for file_path in &spec_files { - let mod_name = file_path.file_stem().unwrap().to_str().unwrap(); - mod_rs.write(b"mod ").unwrap(); - mod_rs.write(mod_name.as_bytes()).unwrap(); - mod_rs.write(b";\n").unwrap(); - } -} - -#[cfg(feature = "gen-tests")] -pub struct Spec<'a> { - spec: &'a str, -} - -#[cfg(feature = "gen-tests")] -impl<'a> Spec<'a> { - pub fn new(spec: &'a str) -> Self { - Spec { spec: spec } - } -} - -#[cfg(feature = "gen-tests")] -pub struct TestCase { - pub original: String, - pub expected: String, -} - -#[cfg(feature = "gen-tests")] -impl<'a> Iterator for Spec<'a> { - type Item = TestCase; - - fn next(&mut self) -> Option { - let spec = self.spec; - - let i_start = match self - .spec - .find("```````````````````````````````` example\n") - .map(|pos| pos + 41) - { - Some(pos) => pos, - None => return None, - }; - - let i_end = match self.spec[i_start..] - .find("\n.\n") - .map(|pos| (pos + 1) + i_start) - { - Some(pos) => pos, - None => return None, - }; - - let e_end = match self.spec[i_end + 2..] - .find("````````````````````````````````\n") - .map(|pos| pos + i_end + 2) - { - Some(pos) => pos, - None => return None, - }; - - self.spec = &self.spec[e_end + 33..]; - - let test_case = TestCase { - original: spec[i_start..i_end].to_string().replace("→", "\t"), - expected: spec[i_end + 2..e_end].to_string().replace("→", "\t"), - }; - - Some(test_case) - } -} +fn main() { + generate_tests_from_spec() +} + +// If the "gen-tests" feature is absent, +// this function will be compiled down to nothing +#[cfg(not(feature = "gen-tests"))] +fn generate_tests_from_spec() {} + +// If the feature is present, generate tests +// from any .txt file present in the specs/ directory +// +// Test cases are present in the files in the +// following format: +// +// ```````````````````````````````` example +// markdown +// . +// expected html output +// ```````````````````````````````` +#[cfg(feature = "gen-tests")] +fn generate_tests_from_spec() { + use std::fs::{self, File}; + use std::io::{Read, Write}; + use std::path::PathBuf; + + // This is a hardcoded path to the CommonMark spec because it is not situated in + // the specs/ directory. It's in an array to easily chain it to the other iterator + // and make it easy to eventually add other hardcoded paths in the future if needed + let hardcoded = [ + "./third_party/CommonMark/spec.txt", + "./third_party/CommonMark/smart_punct.txt", + "./third_party/GitHub/gfm_table.txt", + "./third_party/GitHub/gfm_strikethrough.txt", + "./third_party/GitHub/gfm_tasklist.txt", + ]; + let hardcoded_iter = hardcoded.iter().map(PathBuf::from); + + // Create an iterator over the files in the specs/ directory that have a .txt extension + let spec_files = fs::read_dir("./specs") + .expect("Could not find the 'specs' directory") + .filter_map(Result::ok) + .map(|d| d.path()) + .filter(|p| p.extension().map(|e| e.to_owned()).is_some()) + .chain(hardcoded_iter) + .collect::>(); + + for file_path in &spec_files { + let mut raw_spec = String::new(); + + File::open(&file_path) + .and_then(|mut f| f.read_to_string(&mut raw_spec)) + .expect("Could not read the spec file"); + + let rs_test_file = PathBuf::from("./tests/suite/") + .join(file_path.file_name().expect("Invalid filename")) + .with_extension("rs"); + + let mut spec_rs = + File::create(&rs_test_file).expect(&format!("Could not create {:?}", rs_test_file)); + + let spec_name = file_path.file_stem().unwrap().to_str().unwrap(); + + let spec = Spec::new(&raw_spec); + let mut n_tests = 0; + + spec_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + spec_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + spec_rs + .write(b"\nuse super::test_markdown_html;\n") + .unwrap(); + + for (i, testcase) in spec.enumerate() { + spec_rs + .write_fmt(format_args!( + r###" +#[test] +fn {}_test_{i}() {{ + let original = r##"{original}"##; + let expected = r##"{expected}"##; + + test_markdown_html(original, expected, {smart_punct}); +}} +"###, + spec_name, + i = i + 1, + original = testcase.original, + expected = testcase.expected, + smart_punct = testcase.smart_punct, + )) + .unwrap(); + + n_tests += 1; + } + + println!( + "cargo:warning=Generated {} tests in {:?}", + n_tests, rs_test_file + ); + } + + // write mods to suite/mod.rs + let suite_mod_file = PathBuf::from("./tests/suite/mod").with_extension("rs"); + + let mut mod_rs = + File::create(&suite_mod_file).expect(&format!("Could not create {:?}", &suite_mod_file)); + + mod_rs + .write(b"// This file is auto-generated by the build script\n") + .unwrap(); + mod_rs + .write(b"// Please, do not modify it manually\n") + .unwrap(); + mod_rs + .write(b"\npub use super::test_markdown_html;\n\n") + .unwrap(); + + for file_path in &spec_files { + let mod_name = file_path.file_stem().unwrap().to_str().unwrap(); + mod_rs.write(b"mod ").unwrap(); + mod_rs.write(mod_name.as_bytes()).unwrap(); + mod_rs.write(b";\n").unwrap(); + } +} + +#[cfg(feature = "gen-tests")] +pub struct Spec<'a> { + spec: &'a str, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Spec<'a> { + pub fn new(spec: &'a str) -> Self { + Spec { spec } + } +} + +#[cfg(feature = "gen-tests")] +pub struct TestCase { + pub original: String, + pub expected: String, + pub smart_punct: bool, +} + +#[cfg(feature = "gen-tests")] +impl<'a> Iterator for Spec<'a> { + type Item = TestCase; + + fn next(&mut self) -> Option { + let spec = self.spec; + let prefix = "```````````````````````````````` example"; + + let (i_start, smart_punct) = self.spec.find(prefix).and_then(|pos| { + let suffix = "_smartpunct\n"; + if spec[(pos + prefix.len())..].starts_with(suffix) { + Some((pos + prefix.len() + suffix.len(), true)) + } else if spec[(pos + prefix.len())..].starts_with('\n') { + Some((pos + prefix.len() + 1, false)) + } else { + None + } + })?; + + let i_end = self.spec[i_start..] + .find("\n.\n") + .map(|pos| (pos + 1) + i_start)?; + + let e_end = self.spec[i_end + 2..] + .find("````````````````````````````````\n") + .map(|pos| pos + i_end + 2)?; + + self.spec = &self.spec[e_end + 33..]; + + let test_case = TestCase { + original: spec[i_start..i_end].to_string().replace("→", "\t"), + expected: spec[i_end + 2..e_end].to_string().replace("→", "\t"), + smart_punct, + }; + + Some(test_case) + } +} diff --git a/vendor/pulldown-cmark/examples/broken-link-callbacks.rs b/vendor/pulldown-cmark/examples/broken-link-callbacks.rs new file mode 100644 index 0000000000..73cdac118b --- /dev/null +++ b/vendor/pulldown-cmark/examples/broken-link-callbacks.rs @@ -0,0 +1,37 @@ +extern crate pulldown_cmark; + +use pulldown_cmark::{html, BrokenLink, Options, Parser}; + +fn main() { + let input: &str = "Hello world, check out [my website][]."; + println!("Parsing the following markdown string:\n{}", input); + + // Setup callback that sets the URL and title when it encounters + // a reference to our home page. + let callback = &mut |broken_link: BrokenLink| { + if broken_link.reference == "my website" { + println!( + "Replacing the markdown `{}` of type {:?} with a working link", + &input[broken_link.span], broken_link.link_type, + ); + Some(("http://example.com".into(), "my example website".into())) + } else { + None + } + }; + + // Create a parser with our callback function for broken links. + let parser = Parser::new_with_broken_link_callback(input, Options::empty(), Some(callback)); + + // Write to String buffer. + let mut html_output: String = String::with_capacity(input.len() * 3 / 2); + html::push_html(&mut html_output, parser); + + // Check that the output is what we expected. + let expected_html: &str = + "

    Hello world, check out my website.

    \n"; + assert_eq!(expected_html, &html_output); + + // Write result to stdout. + println!("\nHTML output:\n{}", &html_output); +} diff --git a/vendor/pulldown-cmark/examples/event-filter.rs b/vendor/pulldown-cmark/examples/event-filter.rs index 86af851f9e..7b1e9ed545 100644 --- a/vendor/pulldown-cmark/examples/event-filter.rs +++ b/vendor/pulldown-cmark/examples/event-filter.rs @@ -1,29 +1,29 @@ -extern crate pulldown_cmark; - -use std::io::Write as _; - -use pulldown_cmark::{html, Event, Options, Parser, Tag}; - -fn main() { - let markdown_input: &str = "This is Peter on ![holiday in Greece](pearl_beach.jpg)."; - println!("Parsing the following markdown string:\n{}", markdown_input); - - // Set up parser. We can treat is as any other iterator. We replace Peter by John - // and image by its alt text. - let parser = Parser::new_ext(markdown_input, Options::empty()) - .map(|event| match event { - Event::Text(text) => Event::Text(text.replace("Peter", "John").into()), - _ => event, - }) - .filter(|event| match event { - Event::Start(Tag::Image(..)) | Event::End(Tag::Image(..)) => false, - _ => true, - }); - - // Write to anything implementing the `Write` trait. This could also be a file - // or network socket. - let stdout = std::io::stdout(); - let mut handle = stdout.lock(); - handle.write_all(b"\nHTML output:\n").unwrap(); - html::write_html(&mut handle, parser).unwrap(); -} +extern crate pulldown_cmark; + +use std::io::Write as _; + +use pulldown_cmark::{html, Event, Options, Parser, Tag}; + +fn main() { + let markdown_input: &str = "This is Peter on ![holiday in Greece](pearl_beach.jpg)."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up parser. We can treat is as any other iterator. We replace Peter by John + // and image by its alt text. + let parser = Parser::new_ext(markdown_input, Options::empty()) + .map(|event| match event { + Event::Text(text) => Event::Text(text.replace("Peter", "John").into()), + _ => event, + }) + .filter(|event| match event { + Event::Start(Tag::Image(..)) | Event::End(Tag::Image(..)) => false, + _ => true, + }); + + // Write to anything implementing the `Write` trait. This could also be a file + // or network socket. + let stdout = std::io::stdout(); + let mut handle = stdout.lock(); + handle.write_all(b"\nHTML output:\n").unwrap(); + html::write_html(&mut handle, parser).unwrap(); +} diff --git a/vendor/pulldown-cmark/examples/string-to-string.rs b/vendor/pulldown-cmark/examples/string-to-string.rs index ac08823334..af1664b44e 100644 --- a/vendor/pulldown-cmark/examples/string-to-string.rs +++ b/vendor/pulldown-cmark/examples/string-to-string.rs @@ -1,26 +1,26 @@ -extern crate pulldown_cmark; - -use pulldown_cmark::{html, Options, Parser}; - -fn main() { - let markdown_input: &str = "Hello world, this is a ~~complicated~~ *very simple* example."; - println!("Parsing the following markdown string:\n{}", markdown_input); - - // Set up options and parser. Strikethroughs are not part of the CommonMark standard - // and we therefore must enable it explicitly. - let mut options = Options::empty(); - options.insert(Options::ENABLE_STRIKETHROUGH); - let parser = Parser::new_ext(markdown_input, options); - - // Write to String buffer. - let mut html_output: String = String::with_capacity(markdown_input.len() * 3 / 2); - html::push_html(&mut html_output, parser); - - // Check that the output is what we expected. - let expected_html: &str = - "

    Hello world, this is a complicated very simple example.

    \n"; - assert_eq!(expected_html, &html_output); - - // Write result to stdout. - println!("\nHTML output:\n{}", &html_output); -} +extern crate pulldown_cmark; + +use pulldown_cmark::{html, Options, Parser}; + +fn main() { + let markdown_input: &str = "Hello world, this is a ~~complicated~~ *very simple* example."; + println!("Parsing the following markdown string:\n{}", markdown_input); + + // Set up options and parser. Strikethroughs are not part of the CommonMark standard + // and we therefore must enable it explicitly. + let mut options = Options::empty(); + options.insert(Options::ENABLE_STRIKETHROUGH); + let parser = Parser::new_ext(markdown_input, options); + + // Write to String buffer. + let mut html_output: String = String::with_capacity(markdown_input.len() * 3 / 2); + html::push_html(&mut html_output, parser); + + // Check that the output is what we expected. + let expected_html: &str = + "

    Hello world, this is a complicated very simple example.

    \n"; + assert_eq!(expected_html, &html_output); + + // Write result to stdout. + println!("\nHTML output:\n{}", &html_output); +} diff --git a/vendor/pulldown-cmark/src/entities.rs b/vendor/pulldown-cmark/src/entities.rs index 152342957f..042c9bccc7 100644 --- a/vendor/pulldown-cmark/src/entities.rs +++ b/vendor/pulldown-cmark/src/entities.rs @@ -1,2158 +1,2158 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Expansions of HTML5 entities - -// Autogenerated by mk_entities.py - -const ENTITIES: [(&[u8], &str); 2125] = [ - (b"AElig", "\u{00C6}"), - (b"AMP", "\u{0026}"), - (b"Aacute", "\u{00C1}"), - (b"Abreve", "\u{0102}"), - (b"Acirc", "\u{00C2}"), - (b"Acy", "\u{0410}"), - (b"Afr", "\u{1D504}"), - (b"Agrave", "\u{00C0}"), - (b"Alpha", "\u{0391}"), - (b"Amacr", "\u{0100}"), - (b"And", "\u{2A53}"), - (b"Aogon", "\u{0104}"), - (b"Aopf", "\u{1D538}"), - (b"ApplyFunction", "\u{2061}"), - (b"Aring", "\u{00C5}"), - (b"Ascr", "\u{1D49C}"), - (b"Assign", "\u{2254}"), - (b"Atilde", "\u{00C3}"), - (b"Auml", "\u{00C4}"), - (b"Backslash", "\u{2216}"), - (b"Barv", "\u{2AE7}"), - (b"Barwed", "\u{2306}"), - (b"Bcy", "\u{0411}"), - (b"Because", "\u{2235}"), - (b"Bernoullis", "\u{212C}"), - (b"Beta", "\u{0392}"), - (b"Bfr", "\u{1D505}"), - (b"Bopf", "\u{1D539}"), - (b"Breve", "\u{02D8}"), - (b"Bscr", "\u{212C}"), - (b"Bumpeq", "\u{224E}"), - (b"CHcy", "\u{0427}"), - (b"COPY", "\u{00A9}"), - (b"Cacute", "\u{0106}"), - (b"Cap", "\u{22D2}"), - (b"CapitalDifferentialD", "\u{2145}"), - (b"Cayleys", "\u{212D}"), - (b"Ccaron", "\u{010C}"), - (b"Ccedil", "\u{00C7}"), - (b"Ccirc", "\u{0108}"), - (b"Cconint", "\u{2230}"), - (b"Cdot", "\u{010A}"), - (b"Cedilla", "\u{00B8}"), - (b"CenterDot", "\u{00B7}"), - (b"Cfr", "\u{212D}"), - (b"Chi", "\u{03A7}"), - (b"CircleDot", "\u{2299}"), - (b"CircleMinus", "\u{2296}"), - (b"CirclePlus", "\u{2295}"), - (b"CircleTimes", "\u{2297}"), - (b"ClockwiseContourIntegral", "\u{2232}"), - (b"CloseCurlyDoubleQuote", "\u{201D}"), - (b"CloseCurlyQuote", "\u{2019}"), - (b"Colon", "\u{2237}"), - (b"Colone", "\u{2A74}"), - (b"Congruent", "\u{2261}"), - (b"Conint", "\u{222F}"), - (b"ContourIntegral", "\u{222E}"), - (b"Copf", "\u{2102}"), - (b"Coproduct", "\u{2210}"), - (b"CounterClockwiseContourIntegral", "\u{2233}"), - (b"Cross", "\u{2A2F}"), - (b"Cscr", "\u{1D49E}"), - (b"Cup", "\u{22D3}"), - (b"CupCap", "\u{224D}"), - (b"DD", "\u{2145}"), - (b"DDotrahd", "\u{2911}"), - (b"DJcy", "\u{0402}"), - (b"DScy", "\u{0405}"), - (b"DZcy", "\u{040F}"), - (b"Dagger", "\u{2021}"), - (b"Darr", "\u{21A1}"), - (b"Dashv", "\u{2AE4}"), - (b"Dcaron", "\u{010E}"), - (b"Dcy", "\u{0414}"), - (b"Del", "\u{2207}"), - (b"Delta", "\u{0394}"), - (b"Dfr", "\u{1D507}"), - (b"DiacriticalAcute", "\u{00B4}"), - (b"DiacriticalDot", "\u{02D9}"), - (b"DiacriticalDoubleAcute", "\u{02DD}"), - (b"DiacriticalGrave", "\u{0060}"), - (b"DiacriticalTilde", "\u{02DC}"), - (b"Diamond", "\u{22C4}"), - (b"DifferentialD", "\u{2146}"), - (b"Dopf", "\u{1D53B}"), - (b"Dot", "\u{00A8}"), - (b"DotDot", "\u{20DC}"), - (b"DotEqual", "\u{2250}"), - (b"DoubleContourIntegral", "\u{222F}"), - (b"DoubleDot", "\u{00A8}"), - (b"DoubleDownArrow", "\u{21D3}"), - (b"DoubleLeftArrow", "\u{21D0}"), - (b"DoubleLeftRightArrow", "\u{21D4}"), - (b"DoubleLeftTee", "\u{2AE4}"), - (b"DoubleLongLeftArrow", "\u{27F8}"), - (b"DoubleLongLeftRightArrow", "\u{27FA}"), - (b"DoubleLongRightArrow", "\u{27F9}"), - (b"DoubleRightArrow", "\u{21D2}"), - (b"DoubleRightTee", "\u{22A8}"), - (b"DoubleUpArrow", "\u{21D1}"), - (b"DoubleUpDownArrow", "\u{21D5}"), - (b"DoubleVerticalBar", "\u{2225}"), - (b"DownArrow", "\u{2193}"), - (b"DownArrowBar", "\u{2913}"), - (b"DownArrowUpArrow", "\u{21F5}"), - (b"DownBreve", "\u{0311}"), - (b"DownLeftRightVector", "\u{2950}"), - (b"DownLeftTeeVector", "\u{295E}"), - (b"DownLeftVector", "\u{21BD}"), - (b"DownLeftVectorBar", "\u{2956}"), - (b"DownRightTeeVector", "\u{295F}"), - (b"DownRightVector", "\u{21C1}"), - (b"DownRightVectorBar", "\u{2957}"), - (b"DownTee", "\u{22A4}"), - (b"DownTeeArrow", "\u{21A7}"), - (b"Downarrow", "\u{21D3}"), - (b"Dscr", "\u{1D49F}"), - (b"Dstrok", "\u{0110}"), - (b"ENG", "\u{014A}"), - (b"ETH", "\u{00D0}"), - (b"Eacute", "\u{00C9}"), - (b"Ecaron", "\u{011A}"), - (b"Ecirc", "\u{00CA}"), - (b"Ecy", "\u{042D}"), - (b"Edot", "\u{0116}"), - (b"Efr", "\u{1D508}"), - (b"Egrave", "\u{00C8}"), - (b"Element", "\u{2208}"), - (b"Emacr", "\u{0112}"), - (b"EmptySmallSquare", "\u{25FB}"), - (b"EmptyVerySmallSquare", "\u{25AB}"), - (b"Eogon", "\u{0118}"), - (b"Eopf", "\u{1D53C}"), - (b"Epsilon", "\u{0395}"), - (b"Equal", "\u{2A75}"), - (b"EqualTilde", "\u{2242}"), - (b"Equilibrium", "\u{21CC}"), - (b"Escr", "\u{2130}"), - (b"Esim", "\u{2A73}"), - (b"Eta", "\u{0397}"), - (b"Euml", "\u{00CB}"), - (b"Exists", "\u{2203}"), - (b"ExponentialE", "\u{2147}"), - (b"Fcy", "\u{0424}"), - (b"Ffr", "\u{1D509}"), - (b"FilledSmallSquare", "\u{25FC}"), - (b"FilledVerySmallSquare", "\u{25AA}"), - (b"Fopf", "\u{1D53D}"), - (b"ForAll", "\u{2200}"), - (b"Fouriertrf", "\u{2131}"), - (b"Fscr", "\u{2131}"), - (b"GJcy", "\u{0403}"), - (b"GT", "\u{003E}"), - (b"Gamma", "\u{0393}"), - (b"Gammad", "\u{03DC}"), - (b"Gbreve", "\u{011E}"), - (b"Gcedil", "\u{0122}"), - (b"Gcirc", "\u{011C}"), - (b"Gcy", "\u{0413}"), - (b"Gdot", "\u{0120}"), - (b"Gfr", "\u{1D50A}"), - (b"Gg", "\u{22D9}"), - (b"Gopf", "\u{1D53E}"), - (b"GreaterEqual", "\u{2265}"), - (b"GreaterEqualLess", "\u{22DB}"), - (b"GreaterFullEqual", "\u{2267}"), - (b"GreaterGreater", "\u{2AA2}"), - (b"GreaterLess", "\u{2277}"), - (b"GreaterSlantEqual", "\u{2A7E}"), - (b"GreaterTilde", "\u{2273}"), - (b"Gscr", "\u{1D4A2}"), - (b"Gt", "\u{226B}"), - (b"HARDcy", "\u{042A}"), - (b"Hacek", "\u{02C7}"), - (b"Hat", "\u{005E}"), - (b"Hcirc", "\u{0124}"), - (b"Hfr", "\u{210C}"), - (b"HilbertSpace", "\u{210B}"), - (b"Hopf", "\u{210D}"), - (b"HorizontalLine", "\u{2500}"), - (b"Hscr", "\u{210B}"), - (b"Hstrok", "\u{0126}"), - (b"HumpDownHump", "\u{224E}"), - (b"HumpEqual", "\u{224F}"), - (b"IEcy", "\u{0415}"), - (b"IJlig", "\u{0132}"), - (b"IOcy", "\u{0401}"), - (b"Iacute", "\u{00CD}"), - (b"Icirc", "\u{00CE}"), - (b"Icy", "\u{0418}"), - (b"Idot", "\u{0130}"), - (b"Ifr", "\u{2111}"), - (b"Igrave", "\u{00CC}"), - (b"Im", "\u{2111}"), - (b"Imacr", "\u{012A}"), - (b"ImaginaryI", "\u{2148}"), - (b"Implies", "\u{21D2}"), - (b"Int", "\u{222C}"), - (b"Integral", "\u{222B}"), - (b"Intersection", "\u{22C2}"), - (b"InvisibleComma", "\u{2063}"), - (b"InvisibleTimes", "\u{2062}"), - (b"Iogon", "\u{012E}"), - (b"Iopf", "\u{1D540}"), - (b"Iota", "\u{0399}"), - (b"Iscr", "\u{2110}"), - (b"Itilde", "\u{0128}"), - (b"Iukcy", "\u{0406}"), - (b"Iuml", "\u{00CF}"), - (b"Jcirc", "\u{0134}"), - (b"Jcy", "\u{0419}"), - (b"Jfr", "\u{1D50D}"), - (b"Jopf", "\u{1D541}"), - (b"Jscr", "\u{1D4A5}"), - (b"Jsercy", "\u{0408}"), - (b"Jukcy", "\u{0404}"), - (b"KHcy", "\u{0425}"), - (b"KJcy", "\u{040C}"), - (b"Kappa", "\u{039A}"), - (b"Kcedil", "\u{0136}"), - (b"Kcy", "\u{041A}"), - (b"Kfr", "\u{1D50E}"), - (b"Kopf", "\u{1D542}"), - (b"Kscr", "\u{1D4A6}"), - (b"LJcy", "\u{0409}"), - (b"LT", "\u{003C}"), - (b"Lacute", "\u{0139}"), - (b"Lambda", "\u{039B}"), - (b"Lang", "\u{27EA}"), - (b"Laplacetrf", "\u{2112}"), - (b"Larr", "\u{219E}"), - (b"Lcaron", "\u{013D}"), - (b"Lcedil", "\u{013B}"), - (b"Lcy", "\u{041B}"), - (b"LeftAngleBracket", "\u{27E8}"), - (b"LeftArrow", "\u{2190}"), - (b"LeftArrowBar", "\u{21E4}"), - (b"LeftArrowRightArrow", "\u{21C6}"), - (b"LeftCeiling", "\u{2308}"), - (b"LeftDoubleBracket", "\u{27E6}"), - (b"LeftDownTeeVector", "\u{2961}"), - (b"LeftDownVector", "\u{21C3}"), - (b"LeftDownVectorBar", "\u{2959}"), - (b"LeftFloor", "\u{230A}"), - (b"LeftRightArrow", "\u{2194}"), - (b"LeftRightVector", "\u{294E}"), - (b"LeftTee", "\u{22A3}"), - (b"LeftTeeArrow", "\u{21A4}"), - (b"LeftTeeVector", "\u{295A}"), - (b"LeftTriangle", "\u{22B2}"), - (b"LeftTriangleBar", "\u{29CF}"), - (b"LeftTriangleEqual", "\u{22B4}"), - (b"LeftUpDownVector", "\u{2951}"), - (b"LeftUpTeeVector", "\u{2960}"), - (b"LeftUpVector", "\u{21BF}"), - (b"LeftUpVectorBar", "\u{2958}"), - (b"LeftVector", "\u{21BC}"), - (b"LeftVectorBar", "\u{2952}"), - (b"Leftarrow", "\u{21D0}"), - (b"Leftrightarrow", "\u{21D4}"), - (b"LessEqualGreater", "\u{22DA}"), - (b"LessFullEqual", "\u{2266}"), - (b"LessGreater", "\u{2276}"), - (b"LessLess", "\u{2AA1}"), - (b"LessSlantEqual", "\u{2A7D}"), - (b"LessTilde", "\u{2272}"), - (b"Lfr", "\u{1D50F}"), - (b"Ll", "\u{22D8}"), - (b"Lleftarrow", "\u{21DA}"), - (b"Lmidot", "\u{013F}"), - (b"LongLeftArrow", "\u{27F5}"), - (b"LongLeftRightArrow", "\u{27F7}"), - (b"LongRightArrow", "\u{27F6}"), - (b"Longleftarrow", "\u{27F8}"), - (b"Longleftrightarrow", "\u{27FA}"), - (b"Longrightarrow", "\u{27F9}"), - (b"Lopf", "\u{1D543}"), - (b"LowerLeftArrow", "\u{2199}"), - (b"LowerRightArrow", "\u{2198}"), - (b"Lscr", "\u{2112}"), - (b"Lsh", "\u{21B0}"), - (b"Lstrok", "\u{0141}"), - (b"Lt", "\u{226A}"), - (b"Map", "\u{2905}"), - (b"Mcy", "\u{041C}"), - (b"MediumSpace", "\u{205F}"), - (b"Mellintrf", "\u{2133}"), - (b"Mfr", "\u{1D510}"), - (b"MinusPlus", "\u{2213}"), - (b"Mopf", "\u{1D544}"), - (b"Mscr", "\u{2133}"), - (b"Mu", "\u{039C}"), - (b"NJcy", "\u{040A}"), - (b"Nacute", "\u{0143}"), - (b"Ncaron", "\u{0147}"), - (b"Ncedil", "\u{0145}"), - (b"Ncy", "\u{041D}"), - (b"NegativeMediumSpace", "\u{200B}"), - (b"NegativeThickSpace", "\u{200B}"), - (b"NegativeThinSpace", "\u{200B}"), - (b"NegativeVeryThinSpace", "\u{200B}"), - (b"NestedGreaterGreater", "\u{226B}"), - (b"NestedLessLess", "\u{226A}"), - (b"NewLine", "\u{000A}"), - (b"Nfr", "\u{1D511}"), - (b"NoBreak", "\u{2060}"), - (b"NonBreakingSpace", "\u{00A0}"), - (b"Nopf", "\u{2115}"), - (b"Not", "\u{2AEC}"), - (b"NotCongruent", "\u{2262}"), - (b"NotCupCap", "\u{226D}"), - (b"NotDoubleVerticalBar", "\u{2226}"), - (b"NotElement", "\u{2209}"), - (b"NotEqual", "\u{2260}"), - (b"NotEqualTilde", "\u{2242}\u{0338}"), - (b"NotExists", "\u{2204}"), - (b"NotGreater", "\u{226F}"), - (b"NotGreaterEqual", "\u{2271}"), - (b"NotGreaterFullEqual", "\u{2267}\u{0338}"), - (b"NotGreaterGreater", "\u{226B}\u{0338}"), - (b"NotGreaterLess", "\u{2279}"), - (b"NotGreaterSlantEqual", "\u{2A7E}\u{0338}"), - (b"NotGreaterTilde", "\u{2275}"), - (b"NotHumpDownHump", "\u{224E}\u{0338}"), - (b"NotHumpEqual", "\u{224F}\u{0338}"), - (b"NotLeftTriangle", "\u{22EA}"), - (b"NotLeftTriangleBar", "\u{29CF}\u{0338}"), - (b"NotLeftTriangleEqual", "\u{22EC}"), - (b"NotLess", "\u{226E}"), - (b"NotLessEqual", "\u{2270}"), - (b"NotLessGreater", "\u{2278}"), - (b"NotLessLess", "\u{226A}\u{0338}"), - (b"NotLessSlantEqual", "\u{2A7D}\u{0338}"), - (b"NotLessTilde", "\u{2274}"), - (b"NotNestedGreaterGreater", "\u{2AA2}\u{0338}"), - (b"NotNestedLessLess", "\u{2AA1}\u{0338}"), - (b"NotPrecedes", "\u{2280}"), - (b"NotPrecedesEqual", "\u{2AAF}\u{0338}"), - (b"NotPrecedesSlantEqual", "\u{22E0}"), - (b"NotReverseElement", "\u{220C}"), - (b"NotRightTriangle", "\u{22EB}"), - (b"NotRightTriangleBar", "\u{29D0}\u{0338}"), - (b"NotRightTriangleEqual", "\u{22ED}"), - (b"NotSquareSubset", "\u{228F}\u{0338}"), - (b"NotSquareSubsetEqual", "\u{22E2}"), - (b"NotSquareSuperset", "\u{2290}\u{0338}"), - (b"NotSquareSupersetEqual", "\u{22E3}"), - (b"NotSubset", "\u{2282}\u{20D2}"), - (b"NotSubsetEqual", "\u{2288}"), - (b"NotSucceeds", "\u{2281}"), - (b"NotSucceedsEqual", "\u{2AB0}\u{0338}"), - (b"NotSucceedsSlantEqual", "\u{22E1}"), - (b"NotSucceedsTilde", "\u{227F}\u{0338}"), - (b"NotSuperset", "\u{2283}\u{20D2}"), - (b"NotSupersetEqual", "\u{2289}"), - (b"NotTilde", "\u{2241}"), - (b"NotTildeEqual", "\u{2244}"), - (b"NotTildeFullEqual", "\u{2247}"), - (b"NotTildeTilde", "\u{2249}"), - (b"NotVerticalBar", "\u{2224}"), - (b"Nscr", "\u{1D4A9}"), - (b"Ntilde", "\u{00D1}"), - (b"Nu", "\u{039D}"), - (b"OElig", "\u{0152}"), - (b"Oacute", "\u{00D3}"), - (b"Ocirc", "\u{00D4}"), - (b"Ocy", "\u{041E}"), - (b"Odblac", "\u{0150}"), - (b"Ofr", "\u{1D512}"), - (b"Ograve", "\u{00D2}"), - (b"Omacr", "\u{014C}"), - (b"Omega", "\u{03A9}"), - (b"Omicron", "\u{039F}"), - (b"Oopf", "\u{1D546}"), - (b"OpenCurlyDoubleQuote", "\u{201C}"), - (b"OpenCurlyQuote", "\u{2018}"), - (b"Or", "\u{2A54}"), - (b"Oscr", "\u{1D4AA}"), - (b"Oslash", "\u{00D8}"), - (b"Otilde", "\u{00D5}"), - (b"Otimes", "\u{2A37}"), - (b"Ouml", "\u{00D6}"), - (b"OverBar", "\u{203E}"), - (b"OverBrace", "\u{23DE}"), - (b"OverBracket", "\u{23B4}"), - (b"OverParenthesis", "\u{23DC}"), - (b"PartialD", "\u{2202}"), - (b"Pcy", "\u{041F}"), - (b"Pfr", "\u{1D513}"), - (b"Phi", "\u{03A6}"), - (b"Pi", "\u{03A0}"), - (b"PlusMinus", "\u{00B1}"), - (b"Poincareplane", "\u{210C}"), - (b"Popf", "\u{2119}"), - (b"Pr", "\u{2ABB}"), - (b"Precedes", "\u{227A}"), - (b"PrecedesEqual", "\u{2AAF}"), - (b"PrecedesSlantEqual", "\u{227C}"), - (b"PrecedesTilde", "\u{227E}"), - (b"Prime", "\u{2033}"), - (b"Product", "\u{220F}"), - (b"Proportion", "\u{2237}"), - (b"Proportional", "\u{221D}"), - (b"Pscr", "\u{1D4AB}"), - (b"Psi", "\u{03A8}"), - (b"QUOT", "\u{0022}"), - (b"Qfr", "\u{1D514}"), - (b"Qopf", "\u{211A}"), - (b"Qscr", "\u{1D4AC}"), - (b"RBarr", "\u{2910}"), - (b"REG", "\u{00AE}"), - (b"Racute", "\u{0154}"), - (b"Rang", "\u{27EB}"), - (b"Rarr", "\u{21A0}"), - (b"Rarrtl", "\u{2916}"), - (b"Rcaron", "\u{0158}"), - (b"Rcedil", "\u{0156}"), - (b"Rcy", "\u{0420}"), - (b"Re", "\u{211C}"), - (b"ReverseElement", "\u{220B}"), - (b"ReverseEquilibrium", "\u{21CB}"), - (b"ReverseUpEquilibrium", "\u{296F}"), - (b"Rfr", "\u{211C}"), - (b"Rho", "\u{03A1}"), - (b"RightAngleBracket", "\u{27E9}"), - (b"RightArrow", "\u{2192}"), - (b"RightArrowBar", "\u{21E5}"), - (b"RightArrowLeftArrow", "\u{21C4}"), - (b"RightCeiling", "\u{2309}"), - (b"RightDoubleBracket", "\u{27E7}"), - (b"RightDownTeeVector", "\u{295D}"), - (b"RightDownVector", "\u{21C2}"), - (b"RightDownVectorBar", "\u{2955}"), - (b"RightFloor", "\u{230B}"), - (b"RightTee", "\u{22A2}"), - (b"RightTeeArrow", "\u{21A6}"), - (b"RightTeeVector", "\u{295B}"), - (b"RightTriangle", "\u{22B3}"), - (b"RightTriangleBar", "\u{29D0}"), - (b"RightTriangleEqual", "\u{22B5}"), - (b"RightUpDownVector", "\u{294F}"), - (b"RightUpTeeVector", "\u{295C}"), - (b"RightUpVector", "\u{21BE}"), - (b"RightUpVectorBar", "\u{2954}"), - (b"RightVector", "\u{21C0}"), - (b"RightVectorBar", "\u{2953}"), - (b"Rightarrow", "\u{21D2}"), - (b"Ropf", "\u{211D}"), - (b"RoundImplies", "\u{2970}"), - (b"Rrightarrow", "\u{21DB}"), - (b"Rscr", "\u{211B}"), - (b"Rsh", "\u{21B1}"), - (b"RuleDelayed", "\u{29F4}"), - (b"SHCHcy", "\u{0429}"), - (b"SHcy", "\u{0428}"), - (b"SOFTcy", "\u{042C}"), - (b"Sacute", "\u{015A}"), - (b"Sc", "\u{2ABC}"), - (b"Scaron", "\u{0160}"), - (b"Scedil", "\u{015E}"), - (b"Scirc", "\u{015C}"), - (b"Scy", "\u{0421}"), - (b"Sfr", "\u{1D516}"), - (b"ShortDownArrow", "\u{2193}"), - (b"ShortLeftArrow", "\u{2190}"), - (b"ShortRightArrow", "\u{2192}"), - (b"ShortUpArrow", "\u{2191}"), - (b"Sigma", "\u{03A3}"), - (b"SmallCircle", "\u{2218}"), - (b"Sopf", "\u{1D54A}"), - (b"Sqrt", "\u{221A}"), - (b"Square", "\u{25A1}"), - (b"SquareIntersection", "\u{2293}"), - (b"SquareSubset", "\u{228F}"), - (b"SquareSubsetEqual", "\u{2291}"), - (b"SquareSuperset", "\u{2290}"), - (b"SquareSupersetEqual", "\u{2292}"), - (b"SquareUnion", "\u{2294}"), - (b"Sscr", "\u{1D4AE}"), - (b"Star", "\u{22C6}"), - (b"Sub", "\u{22D0}"), - (b"Subset", "\u{22D0}"), - (b"SubsetEqual", "\u{2286}"), - (b"Succeeds", "\u{227B}"), - (b"SucceedsEqual", "\u{2AB0}"), - (b"SucceedsSlantEqual", "\u{227D}"), - (b"SucceedsTilde", "\u{227F}"), - (b"SuchThat", "\u{220B}"), - (b"Sum", "\u{2211}"), - (b"Sup", "\u{22D1}"), - (b"Superset", "\u{2283}"), - (b"SupersetEqual", "\u{2287}"), - (b"Supset", "\u{22D1}"), - (b"THORN", "\u{00DE}"), - (b"TRADE", "\u{2122}"), - (b"TSHcy", "\u{040B}"), - (b"TScy", "\u{0426}"), - (b"Tab", "\u{0009}"), - (b"Tau", "\u{03A4}"), - (b"Tcaron", "\u{0164}"), - (b"Tcedil", "\u{0162}"), - (b"Tcy", "\u{0422}"), - (b"Tfr", "\u{1D517}"), - (b"Therefore", "\u{2234}"), - (b"Theta", "\u{0398}"), - (b"ThickSpace", "\u{205F}\u{200A}"), - (b"ThinSpace", "\u{2009}"), - (b"Tilde", "\u{223C}"), - (b"TildeEqual", "\u{2243}"), - (b"TildeFullEqual", "\u{2245}"), - (b"TildeTilde", "\u{2248}"), - (b"Topf", "\u{1D54B}"), - (b"TripleDot", "\u{20DB}"), - (b"Tscr", "\u{1D4AF}"), - (b"Tstrok", "\u{0166}"), - (b"Uacute", "\u{00DA}"), - (b"Uarr", "\u{219F}"), - (b"Uarrocir", "\u{2949}"), - (b"Ubrcy", "\u{040E}"), - (b"Ubreve", "\u{016C}"), - (b"Ucirc", "\u{00DB}"), - (b"Ucy", "\u{0423}"), - (b"Udblac", "\u{0170}"), - (b"Ufr", "\u{1D518}"), - (b"Ugrave", "\u{00D9}"), - (b"Umacr", "\u{016A}"), - (b"UnderBar", "\u{005F}"), - (b"UnderBrace", "\u{23DF}"), - (b"UnderBracket", "\u{23B5}"), - (b"UnderParenthesis", "\u{23DD}"), - (b"Union", "\u{22C3}"), - (b"UnionPlus", "\u{228E}"), - (b"Uogon", "\u{0172}"), - (b"Uopf", "\u{1D54C}"), - (b"UpArrow", "\u{2191}"), - (b"UpArrowBar", "\u{2912}"), - (b"UpArrowDownArrow", "\u{21C5}"), - (b"UpDownArrow", "\u{2195}"), - (b"UpEquilibrium", "\u{296E}"), - (b"UpTee", "\u{22A5}"), - (b"UpTeeArrow", "\u{21A5}"), - (b"Uparrow", "\u{21D1}"), - (b"Updownarrow", "\u{21D5}"), - (b"UpperLeftArrow", "\u{2196}"), - (b"UpperRightArrow", "\u{2197}"), - (b"Upsi", "\u{03D2}"), - (b"Upsilon", "\u{03A5}"), - (b"Uring", "\u{016E}"), - (b"Uscr", "\u{1D4B0}"), - (b"Utilde", "\u{0168}"), - (b"Uuml", "\u{00DC}"), - (b"VDash", "\u{22AB}"), - (b"Vbar", "\u{2AEB}"), - (b"Vcy", "\u{0412}"), - (b"Vdash", "\u{22A9}"), - (b"Vdashl", "\u{2AE6}"), - (b"Vee", "\u{22C1}"), - (b"Verbar", "\u{2016}"), - (b"Vert", "\u{2016}"), - (b"VerticalBar", "\u{2223}"), - (b"VerticalLine", "\u{007C}"), - (b"VerticalSeparator", "\u{2758}"), - (b"VerticalTilde", "\u{2240}"), - (b"VeryThinSpace", "\u{200A}"), - (b"Vfr", "\u{1D519}"), - (b"Vopf", "\u{1D54D}"), - (b"Vscr", "\u{1D4B1}"), - (b"Vvdash", "\u{22AA}"), - (b"Wcirc", "\u{0174}"), - (b"Wedge", "\u{22C0}"), - (b"Wfr", "\u{1D51A}"), - (b"Wopf", "\u{1D54E}"), - (b"Wscr", "\u{1D4B2}"), - (b"Xfr", "\u{1D51B}"), - (b"Xi", "\u{039E}"), - (b"Xopf", "\u{1D54F}"), - (b"Xscr", "\u{1D4B3}"), - (b"YAcy", "\u{042F}"), - (b"YIcy", "\u{0407}"), - (b"YUcy", "\u{042E}"), - (b"Yacute", "\u{00DD}"), - (b"Ycirc", "\u{0176}"), - (b"Ycy", "\u{042B}"), - (b"Yfr", "\u{1D51C}"), - (b"Yopf", "\u{1D550}"), - (b"Yscr", "\u{1D4B4}"), - (b"Yuml", "\u{0178}"), - (b"ZHcy", "\u{0416}"), - (b"Zacute", "\u{0179}"), - (b"Zcaron", "\u{017D}"), - (b"Zcy", "\u{0417}"), - (b"Zdot", "\u{017B}"), - (b"ZeroWidthSpace", "\u{200B}"), - (b"Zeta", "\u{0396}"), - (b"Zfr", "\u{2128}"), - (b"Zopf", "\u{2124}"), - (b"Zscr", "\u{1D4B5}"), - (b"aacute", "\u{00E1}"), - (b"abreve", "\u{0103}"), - (b"ac", "\u{223E}"), - (b"acE", "\u{223E}\u{0333}"), - (b"acd", "\u{223F}"), - (b"acirc", "\u{00E2}"), - (b"acute", "\u{00B4}"), - (b"acy", "\u{0430}"), - (b"aelig", "\u{00E6}"), - (b"af", "\u{2061}"), - (b"afr", "\u{1D51E}"), - (b"agrave", "\u{00E0}"), - (b"alefsym", "\u{2135}"), - (b"aleph", "\u{2135}"), - (b"alpha", "\u{03B1}"), - (b"amacr", "\u{0101}"), - (b"amalg", "\u{2A3F}"), - (b"amp", "\u{0026}"), - (b"and", "\u{2227}"), - (b"andand", "\u{2A55}"), - (b"andd", "\u{2A5C}"), - (b"andslope", "\u{2A58}"), - (b"andv", "\u{2A5A}"), - (b"ang", "\u{2220}"), - (b"ange", "\u{29A4}"), - (b"angle", "\u{2220}"), - (b"angmsd", "\u{2221}"), - (b"angmsdaa", "\u{29A8}"), - (b"angmsdab", "\u{29A9}"), - (b"angmsdac", "\u{29AA}"), - (b"angmsdad", "\u{29AB}"), - (b"angmsdae", "\u{29AC}"), - (b"angmsdaf", "\u{29AD}"), - (b"angmsdag", "\u{29AE}"), - (b"angmsdah", "\u{29AF}"), - (b"angrt", "\u{221F}"), - (b"angrtvb", "\u{22BE}"), - (b"angrtvbd", "\u{299D}"), - (b"angsph", "\u{2222}"), - (b"angst", "\u{00C5}"), - (b"angzarr", "\u{237C}"), - (b"aogon", "\u{0105}"), - (b"aopf", "\u{1D552}"), - (b"ap", "\u{2248}"), - (b"apE", "\u{2A70}"), - (b"apacir", "\u{2A6F}"), - (b"ape", "\u{224A}"), - (b"apid", "\u{224B}"), - (b"apos", "\u{0027}"), - (b"approx", "\u{2248}"), - (b"approxeq", "\u{224A}"), - (b"aring", "\u{00E5}"), - (b"ascr", "\u{1D4B6}"), - (b"ast", "\u{002A}"), - (b"asymp", "\u{2248}"), - (b"asympeq", "\u{224D}"), - (b"atilde", "\u{00E3}"), - (b"auml", "\u{00E4}"), - (b"awconint", "\u{2233}"), - (b"awint", "\u{2A11}"), - (b"bNot", "\u{2AED}"), - (b"backcong", "\u{224C}"), - (b"backepsilon", "\u{03F6}"), - (b"backprime", "\u{2035}"), - (b"backsim", "\u{223D}"), - (b"backsimeq", "\u{22CD}"), - (b"barvee", "\u{22BD}"), - (b"barwed", "\u{2305}"), - (b"barwedge", "\u{2305}"), - (b"bbrk", "\u{23B5}"), - (b"bbrktbrk", "\u{23B6}"), - (b"bcong", "\u{224C}"), - (b"bcy", "\u{0431}"), - (b"bdquo", "\u{201E}"), - (b"becaus", "\u{2235}"), - (b"because", "\u{2235}"), - (b"bemptyv", "\u{29B0}"), - (b"bepsi", "\u{03F6}"), - (b"bernou", "\u{212C}"), - (b"beta", "\u{03B2}"), - (b"beth", "\u{2136}"), - (b"between", "\u{226C}"), - (b"bfr", "\u{1D51F}"), - (b"bigcap", "\u{22C2}"), - (b"bigcirc", "\u{25EF}"), - (b"bigcup", "\u{22C3}"), - (b"bigodot", "\u{2A00}"), - (b"bigoplus", "\u{2A01}"), - (b"bigotimes", "\u{2A02}"), - (b"bigsqcup", "\u{2A06}"), - (b"bigstar", "\u{2605}"), - (b"bigtriangledown", "\u{25BD}"), - (b"bigtriangleup", "\u{25B3}"), - (b"biguplus", "\u{2A04}"), - (b"bigvee", "\u{22C1}"), - (b"bigwedge", "\u{22C0}"), - (b"bkarow", "\u{290D}"), - (b"blacklozenge", "\u{29EB}"), - (b"blacksquare", "\u{25AA}"), - (b"blacktriangle", "\u{25B4}"), - (b"blacktriangledown", "\u{25BE}"), - (b"blacktriangleleft", "\u{25C2}"), - (b"blacktriangleright", "\u{25B8}"), - (b"blank", "\u{2423}"), - (b"blk12", "\u{2592}"), - (b"blk14", "\u{2591}"), - (b"blk34", "\u{2593}"), - (b"block", "\u{2588}"), - (b"bne", "\u{003D}\u{20E5}"), - (b"bnequiv", "\u{2261}\u{20E5}"), - (b"bnot", "\u{2310}"), - (b"bopf", "\u{1D553}"), - (b"bot", "\u{22A5}"), - (b"bottom", "\u{22A5}"), - (b"bowtie", "\u{22C8}"), - (b"boxDL", "\u{2557}"), - (b"boxDR", "\u{2554}"), - (b"boxDl", "\u{2556}"), - (b"boxDr", "\u{2553}"), - (b"boxH", "\u{2550}"), - (b"boxHD", "\u{2566}"), - (b"boxHU", "\u{2569}"), - (b"boxHd", "\u{2564}"), - (b"boxHu", "\u{2567}"), - (b"boxUL", "\u{255D}"), - (b"boxUR", "\u{255A}"), - (b"boxUl", "\u{255C}"), - (b"boxUr", "\u{2559}"), - (b"boxV", "\u{2551}"), - (b"boxVH", "\u{256C}"), - (b"boxVL", "\u{2563}"), - (b"boxVR", "\u{2560}"), - (b"boxVh", "\u{256B}"), - (b"boxVl", "\u{2562}"), - (b"boxVr", "\u{255F}"), - (b"boxbox", "\u{29C9}"), - (b"boxdL", "\u{2555}"), - (b"boxdR", "\u{2552}"), - (b"boxdl", "\u{2510}"), - (b"boxdr", "\u{250C}"), - (b"boxh", "\u{2500}"), - (b"boxhD", "\u{2565}"), - (b"boxhU", "\u{2568}"), - (b"boxhd", "\u{252C}"), - (b"boxhu", "\u{2534}"), - (b"boxminus", "\u{229F}"), - (b"boxplus", "\u{229E}"), - (b"boxtimes", "\u{22A0}"), - (b"boxuL", "\u{255B}"), - (b"boxuR", "\u{2558}"), - (b"boxul", "\u{2518}"), - (b"boxur", "\u{2514}"), - (b"boxv", "\u{2502}"), - (b"boxvH", "\u{256A}"), - (b"boxvL", "\u{2561}"), - (b"boxvR", "\u{255E}"), - (b"boxvh", "\u{253C}"), - (b"boxvl", "\u{2524}"), - (b"boxvr", "\u{251C}"), - (b"bprime", "\u{2035}"), - (b"breve", "\u{02D8}"), - (b"brvbar", "\u{00A6}"), - (b"bscr", "\u{1D4B7}"), - (b"bsemi", "\u{204F}"), - (b"bsim", "\u{223D}"), - (b"bsime", "\u{22CD}"), - (b"bsol", "\u{005C}"), - (b"bsolb", "\u{29C5}"), - (b"bsolhsub", "\u{27C8}"), - (b"bull", "\u{2022}"), - (b"bullet", "\u{2022}"), - (b"bump", "\u{224E}"), - (b"bumpE", "\u{2AAE}"), - (b"bumpe", "\u{224F}"), - (b"bumpeq", "\u{224F}"), - (b"cacute", "\u{0107}"), - (b"cap", "\u{2229}"), - (b"capand", "\u{2A44}"), - (b"capbrcup", "\u{2A49}"), - (b"capcap", "\u{2A4B}"), - (b"capcup", "\u{2A47}"), - (b"capdot", "\u{2A40}"), - (b"caps", "\u{2229}\u{FE00}"), - (b"caret", "\u{2041}"), - (b"caron", "\u{02C7}"), - (b"ccaps", "\u{2A4D}"), - (b"ccaron", "\u{010D}"), - (b"ccedil", "\u{00E7}"), - (b"ccirc", "\u{0109}"), - (b"ccups", "\u{2A4C}"), - (b"ccupssm", "\u{2A50}"), - (b"cdot", "\u{010B}"), - (b"cedil", "\u{00B8}"), - (b"cemptyv", "\u{29B2}"), - (b"cent", "\u{00A2}"), - (b"centerdot", "\u{00B7}"), - (b"cfr", "\u{1D520}"), - (b"chcy", "\u{0447}"), - (b"check", "\u{2713}"), - (b"checkmark", "\u{2713}"), - (b"chi", "\u{03C7}"), - (b"cir", "\u{25CB}"), - (b"cirE", "\u{29C3}"), - (b"circ", "\u{02C6}"), - (b"circeq", "\u{2257}"), - (b"circlearrowleft", "\u{21BA}"), - (b"circlearrowright", "\u{21BB}"), - (b"circledR", "\u{00AE}"), - (b"circledS", "\u{24C8}"), - (b"circledast", "\u{229B}"), - (b"circledcirc", "\u{229A}"), - (b"circleddash", "\u{229D}"), - (b"cire", "\u{2257}"), - (b"cirfnint", "\u{2A10}"), - (b"cirmid", "\u{2AEF}"), - (b"cirscir", "\u{29C2}"), - (b"clubs", "\u{2663}"), - (b"clubsuit", "\u{2663}"), - (b"colon", "\u{003A}"), - (b"colone", "\u{2254}"), - (b"coloneq", "\u{2254}"), - (b"comma", "\u{002C}"), - (b"commat", "\u{0040}"), - (b"comp", "\u{2201}"), - (b"compfn", "\u{2218}"), - (b"complement", "\u{2201}"), - (b"complexes", "\u{2102}"), - (b"cong", "\u{2245}"), - (b"congdot", "\u{2A6D}"), - (b"conint", "\u{222E}"), - (b"copf", "\u{1D554}"), - (b"coprod", "\u{2210}"), - (b"copy", "\u{00A9}"), - (b"copysr", "\u{2117}"), - (b"crarr", "\u{21B5}"), - (b"cross", "\u{2717}"), - (b"cscr", "\u{1D4B8}"), - (b"csub", "\u{2ACF}"), - (b"csube", "\u{2AD1}"), - (b"csup", "\u{2AD0}"), - (b"csupe", "\u{2AD2}"), - (b"ctdot", "\u{22EF}"), - (b"cudarrl", "\u{2938}"), - (b"cudarrr", "\u{2935}"), - (b"cuepr", "\u{22DE}"), - (b"cuesc", "\u{22DF}"), - (b"cularr", "\u{21B6}"), - (b"cularrp", "\u{293D}"), - (b"cup", "\u{222A}"), - (b"cupbrcap", "\u{2A48}"), - (b"cupcap", "\u{2A46}"), - (b"cupcup", "\u{2A4A}"), - (b"cupdot", "\u{228D}"), - (b"cupor", "\u{2A45}"), - (b"cups", "\u{222A}\u{FE00}"), - (b"curarr", "\u{21B7}"), - (b"curarrm", "\u{293C}"), - (b"curlyeqprec", "\u{22DE}"), - (b"curlyeqsucc", "\u{22DF}"), - (b"curlyvee", "\u{22CE}"), - (b"curlywedge", "\u{22CF}"), - (b"curren", "\u{00A4}"), - (b"curvearrowleft", "\u{21B6}"), - (b"curvearrowright", "\u{21B7}"), - (b"cuvee", "\u{22CE}"), - (b"cuwed", "\u{22CF}"), - (b"cwconint", "\u{2232}"), - (b"cwint", "\u{2231}"), - (b"cylcty", "\u{232D}"), - (b"dArr", "\u{21D3}"), - (b"dHar", "\u{2965}"), - (b"dagger", "\u{2020}"), - (b"daleth", "\u{2138}"), - (b"darr", "\u{2193}"), - (b"dash", "\u{2010}"), - (b"dashv", "\u{22A3}"), - (b"dbkarow", "\u{290F}"), - (b"dblac", "\u{02DD}"), - (b"dcaron", "\u{010F}"), - (b"dcy", "\u{0434}"), - (b"dd", "\u{2146}"), - (b"ddagger", "\u{2021}"), - (b"ddarr", "\u{21CA}"), - (b"ddotseq", "\u{2A77}"), - (b"deg", "\u{00B0}"), - (b"delta", "\u{03B4}"), - (b"demptyv", "\u{29B1}"), - (b"dfisht", "\u{297F}"), - (b"dfr", "\u{1D521}"), - (b"dharl", "\u{21C3}"), - (b"dharr", "\u{21C2}"), - (b"diam", "\u{22C4}"), - (b"diamond", "\u{22C4}"), - (b"diamondsuit", "\u{2666}"), - (b"diams", "\u{2666}"), - (b"die", "\u{00A8}"), - (b"digamma", "\u{03DD}"), - (b"disin", "\u{22F2}"), - (b"div", "\u{00F7}"), - (b"divide", "\u{00F7}"), - (b"divideontimes", "\u{22C7}"), - (b"divonx", "\u{22C7}"), - (b"djcy", "\u{0452}"), - (b"dlcorn", "\u{231E}"), - (b"dlcrop", "\u{230D}"), - (b"dollar", "\u{0024}"), - (b"dopf", "\u{1D555}"), - (b"dot", "\u{02D9}"), - (b"doteq", "\u{2250}"), - (b"doteqdot", "\u{2251}"), - (b"dotminus", "\u{2238}"), - (b"dotplus", "\u{2214}"), - (b"dotsquare", "\u{22A1}"), - (b"doublebarwedge", "\u{2306}"), - (b"downarrow", "\u{2193}"), - (b"downdownarrows", "\u{21CA}"), - (b"downharpoonleft", "\u{21C3}"), - (b"downharpoonright", "\u{21C2}"), - (b"drbkarow", "\u{2910}"), - (b"drcorn", "\u{231F}"), - (b"drcrop", "\u{230C}"), - (b"dscr", "\u{1D4B9}"), - (b"dscy", "\u{0455}"), - (b"dsol", "\u{29F6}"), - (b"dstrok", "\u{0111}"), - (b"dtdot", "\u{22F1}"), - (b"dtri", "\u{25BF}"), - (b"dtrif", "\u{25BE}"), - (b"duarr", "\u{21F5}"), - (b"duhar", "\u{296F}"), - (b"dwangle", "\u{29A6}"), - (b"dzcy", "\u{045F}"), - (b"dzigrarr", "\u{27FF}"), - (b"eDDot", "\u{2A77}"), - (b"eDot", "\u{2251}"), - (b"eacute", "\u{00E9}"), - (b"easter", "\u{2A6E}"), - (b"ecaron", "\u{011B}"), - (b"ecir", "\u{2256}"), - (b"ecirc", "\u{00EA}"), - (b"ecolon", "\u{2255}"), - (b"ecy", "\u{044D}"), - (b"edot", "\u{0117}"), - (b"ee", "\u{2147}"), - (b"efDot", "\u{2252}"), - (b"efr", "\u{1D522}"), - (b"eg", "\u{2A9A}"), - (b"egrave", "\u{00E8}"), - (b"egs", "\u{2A96}"), - (b"egsdot", "\u{2A98}"), - (b"el", "\u{2A99}"), - (b"elinters", "\u{23E7}"), - (b"ell", "\u{2113}"), - (b"els", "\u{2A95}"), - (b"elsdot", "\u{2A97}"), - (b"emacr", "\u{0113}"), - (b"empty", "\u{2205}"), - (b"emptyset", "\u{2205}"), - (b"emptyv", "\u{2205}"), - (b"emsp", "\u{2003}"), - (b"emsp13", "\u{2004}"), - (b"emsp14", "\u{2005}"), - (b"eng", "\u{014B}"), - (b"ensp", "\u{2002}"), - (b"eogon", "\u{0119}"), - (b"eopf", "\u{1D556}"), - (b"epar", "\u{22D5}"), - (b"eparsl", "\u{29E3}"), - (b"eplus", "\u{2A71}"), - (b"epsi", "\u{03B5}"), - (b"epsilon", "\u{03B5}"), - (b"epsiv", "\u{03F5}"), - (b"eqcirc", "\u{2256}"), - (b"eqcolon", "\u{2255}"), - (b"eqsim", "\u{2242}"), - (b"eqslantgtr", "\u{2A96}"), - (b"eqslantless", "\u{2A95}"), - (b"equals", "\u{003D}"), - (b"equest", "\u{225F}"), - (b"equiv", "\u{2261}"), - (b"equivDD", "\u{2A78}"), - (b"eqvparsl", "\u{29E5}"), - (b"erDot", "\u{2253}"), - (b"erarr", "\u{2971}"), - (b"escr", "\u{212F}"), - (b"esdot", "\u{2250}"), - (b"esim", "\u{2242}"), - (b"eta", "\u{03B7}"), - (b"eth", "\u{00F0}"), - (b"euml", "\u{00EB}"), - (b"euro", "\u{20AC}"), - (b"excl", "\u{0021}"), - (b"exist", "\u{2203}"), - (b"expectation", "\u{2130}"), - (b"exponentiale", "\u{2147}"), - (b"fallingdotseq", "\u{2252}"), - (b"fcy", "\u{0444}"), - (b"female", "\u{2640}"), - (b"ffilig", "\u{FB03}"), - (b"fflig", "\u{FB00}"), - (b"ffllig", "\u{FB04}"), - (b"ffr", "\u{1D523}"), - (b"filig", "\u{FB01}"), - (b"fjlig", "\u{0066}\u{006A}"), - (b"flat", "\u{266D}"), - (b"fllig", "\u{FB02}"), - (b"fltns", "\u{25B1}"), - (b"fnof", "\u{0192}"), - (b"fopf", "\u{1D557}"), - (b"forall", "\u{2200}"), - (b"fork", "\u{22D4}"), - (b"forkv", "\u{2AD9}"), - (b"fpartint", "\u{2A0D}"), - (b"frac12", "\u{00BD}"), - (b"frac13", "\u{2153}"), - (b"frac14", "\u{00BC}"), - (b"frac15", "\u{2155}"), - (b"frac16", "\u{2159}"), - (b"frac18", "\u{215B}"), - (b"frac23", "\u{2154}"), - (b"frac25", "\u{2156}"), - (b"frac34", "\u{00BE}"), - (b"frac35", "\u{2157}"), - (b"frac38", "\u{215C}"), - (b"frac45", "\u{2158}"), - (b"frac56", "\u{215A}"), - (b"frac58", "\u{215D}"), - (b"frac78", "\u{215E}"), - (b"frasl", "\u{2044}"), - (b"frown", "\u{2322}"), - (b"fscr", "\u{1D4BB}"), - (b"gE", "\u{2267}"), - (b"gEl", "\u{2A8C}"), - (b"gacute", "\u{01F5}"), - (b"gamma", "\u{03B3}"), - (b"gammad", "\u{03DD}"), - (b"gap", "\u{2A86}"), - (b"gbreve", "\u{011F}"), - (b"gcirc", "\u{011D}"), - (b"gcy", "\u{0433}"), - (b"gdot", "\u{0121}"), - (b"ge", "\u{2265}"), - (b"gel", "\u{22DB}"), - (b"geq", "\u{2265}"), - (b"geqq", "\u{2267}"), - (b"geqslant", "\u{2A7E}"), - (b"ges", "\u{2A7E}"), - (b"gescc", "\u{2AA9}"), - (b"gesdot", "\u{2A80}"), - (b"gesdoto", "\u{2A82}"), - (b"gesdotol", "\u{2A84}"), - (b"gesl", "\u{22DB}\u{FE00}"), - (b"gesles", "\u{2A94}"), - (b"gfr", "\u{1D524}"), - (b"gg", "\u{226B}"), - (b"ggg", "\u{22D9}"), - (b"gimel", "\u{2137}"), - (b"gjcy", "\u{0453}"), - (b"gl", "\u{2277}"), - (b"glE", "\u{2A92}"), - (b"gla", "\u{2AA5}"), - (b"glj", "\u{2AA4}"), - (b"gnE", "\u{2269}"), - (b"gnap", "\u{2A8A}"), - (b"gnapprox", "\u{2A8A}"), - (b"gne", "\u{2A88}"), - (b"gneq", "\u{2A88}"), - (b"gneqq", "\u{2269}"), - (b"gnsim", "\u{22E7}"), - (b"gopf", "\u{1D558}"), - (b"grave", "\u{0060}"), - (b"gscr", "\u{210A}"), - (b"gsim", "\u{2273}"), - (b"gsime", "\u{2A8E}"), - (b"gsiml", "\u{2A90}"), - (b"gt", "\u{003E}"), - (b"gtcc", "\u{2AA7}"), - (b"gtcir", "\u{2A7A}"), - (b"gtdot", "\u{22D7}"), - (b"gtlPar", "\u{2995}"), - (b"gtquest", "\u{2A7C}"), - (b"gtrapprox", "\u{2A86}"), - (b"gtrarr", "\u{2978}"), - (b"gtrdot", "\u{22D7}"), - (b"gtreqless", "\u{22DB}"), - (b"gtreqqless", "\u{2A8C}"), - (b"gtrless", "\u{2277}"), - (b"gtrsim", "\u{2273}"), - (b"gvertneqq", "\u{2269}\u{FE00}"), - (b"gvnE", "\u{2269}\u{FE00}"), - (b"hArr", "\u{21D4}"), - (b"hairsp", "\u{200A}"), - (b"half", "\u{00BD}"), - (b"hamilt", "\u{210B}"), - (b"hardcy", "\u{044A}"), - (b"harr", "\u{2194}"), - (b"harrcir", "\u{2948}"), - (b"harrw", "\u{21AD}"), - (b"hbar", "\u{210F}"), - (b"hcirc", "\u{0125}"), - (b"hearts", "\u{2665}"), - (b"heartsuit", "\u{2665}"), - (b"hellip", "\u{2026}"), - (b"hercon", "\u{22B9}"), - (b"hfr", "\u{1D525}"), - (b"hksearow", "\u{2925}"), - (b"hkswarow", "\u{2926}"), - (b"hoarr", "\u{21FF}"), - (b"homtht", "\u{223B}"), - (b"hookleftarrow", "\u{21A9}"), - (b"hookrightarrow", "\u{21AA}"), - (b"hopf", "\u{1D559}"), - (b"horbar", "\u{2015}"), - (b"hscr", "\u{1D4BD}"), - (b"hslash", "\u{210F}"), - (b"hstrok", "\u{0127}"), - (b"hybull", "\u{2043}"), - (b"hyphen", "\u{2010}"), - (b"iacute", "\u{00ED}"), - (b"ic", "\u{2063}"), - (b"icirc", "\u{00EE}"), - (b"icy", "\u{0438}"), - (b"iecy", "\u{0435}"), - (b"iexcl", "\u{00A1}"), - (b"iff", "\u{21D4}"), - (b"ifr", "\u{1D526}"), - (b"igrave", "\u{00EC}"), - (b"ii", "\u{2148}"), - (b"iiiint", "\u{2A0C}"), - (b"iiint", "\u{222D}"), - (b"iinfin", "\u{29DC}"), - (b"iiota", "\u{2129}"), - (b"ijlig", "\u{0133}"), - (b"imacr", "\u{012B}"), - (b"image", "\u{2111}"), - (b"imagline", "\u{2110}"), - (b"imagpart", "\u{2111}"), - (b"imath", "\u{0131}"), - (b"imof", "\u{22B7}"), - (b"imped", "\u{01B5}"), - (b"in", "\u{2208}"), - (b"incare", "\u{2105}"), - (b"infin", "\u{221E}"), - (b"infintie", "\u{29DD}"), - (b"inodot", "\u{0131}"), - (b"int", "\u{222B}"), - (b"intcal", "\u{22BA}"), - (b"integers", "\u{2124}"), - (b"intercal", "\u{22BA}"), - (b"intlarhk", "\u{2A17}"), - (b"intprod", "\u{2A3C}"), - (b"iocy", "\u{0451}"), - (b"iogon", "\u{012F}"), - (b"iopf", "\u{1D55A}"), - (b"iota", "\u{03B9}"), - (b"iprod", "\u{2A3C}"), - (b"iquest", "\u{00BF}"), - (b"iscr", "\u{1D4BE}"), - (b"isin", "\u{2208}"), - (b"isinE", "\u{22F9}"), - (b"isindot", "\u{22F5}"), - (b"isins", "\u{22F4}"), - (b"isinsv", "\u{22F3}"), - (b"isinv", "\u{2208}"), - (b"it", "\u{2062}"), - (b"itilde", "\u{0129}"), - (b"iukcy", "\u{0456}"), - (b"iuml", "\u{00EF}"), - (b"jcirc", "\u{0135}"), - (b"jcy", "\u{0439}"), - (b"jfr", "\u{1D527}"), - (b"jmath", "\u{0237}"), - (b"jopf", "\u{1D55B}"), - (b"jscr", "\u{1D4BF}"), - (b"jsercy", "\u{0458}"), - (b"jukcy", "\u{0454}"), - (b"kappa", "\u{03BA}"), - (b"kappav", "\u{03F0}"), - (b"kcedil", "\u{0137}"), - (b"kcy", "\u{043A}"), - (b"kfr", "\u{1D528}"), - (b"kgreen", "\u{0138}"), - (b"khcy", "\u{0445}"), - (b"kjcy", "\u{045C}"), - (b"kopf", "\u{1D55C}"), - (b"kscr", "\u{1D4C0}"), - (b"lAarr", "\u{21DA}"), - (b"lArr", "\u{21D0}"), - (b"lAtail", "\u{291B}"), - (b"lBarr", "\u{290E}"), - (b"lE", "\u{2266}"), - (b"lEg", "\u{2A8B}"), - (b"lHar", "\u{2962}"), - (b"lacute", "\u{013A}"), - (b"laemptyv", "\u{29B4}"), - (b"lagran", "\u{2112}"), - (b"lambda", "\u{03BB}"), - (b"lang", "\u{27E8}"), - (b"langd", "\u{2991}"), - (b"langle", "\u{27E8}"), - (b"lap", "\u{2A85}"), - (b"laquo", "\u{00AB}"), - (b"larr", "\u{2190}"), - (b"larrb", "\u{21E4}"), - (b"larrbfs", "\u{291F}"), - (b"larrfs", "\u{291D}"), - (b"larrhk", "\u{21A9}"), - (b"larrlp", "\u{21AB}"), - (b"larrpl", "\u{2939}"), - (b"larrsim", "\u{2973}"), - (b"larrtl", "\u{21A2}"), - (b"lat", "\u{2AAB}"), - (b"latail", "\u{2919}"), - (b"late", "\u{2AAD}"), - (b"lates", "\u{2AAD}\u{FE00}"), - (b"lbarr", "\u{290C}"), - (b"lbbrk", "\u{2772}"), - (b"lbrace", "\u{007B}"), - (b"lbrack", "\u{005B}"), - (b"lbrke", "\u{298B}"), - (b"lbrksld", "\u{298F}"), - (b"lbrkslu", "\u{298D}"), - (b"lcaron", "\u{013E}"), - (b"lcedil", "\u{013C}"), - (b"lceil", "\u{2308}"), - (b"lcub", "\u{007B}"), - (b"lcy", "\u{043B}"), - (b"ldca", "\u{2936}"), - (b"ldquo", "\u{201C}"), - (b"ldquor", "\u{201E}"), - (b"ldrdhar", "\u{2967}"), - (b"ldrushar", "\u{294B}"), - (b"ldsh", "\u{21B2}"), - (b"le", "\u{2264}"), - (b"leftarrow", "\u{2190}"), - (b"leftarrowtail", "\u{21A2}"), - (b"leftharpoondown", "\u{21BD}"), - (b"leftharpoonup", "\u{21BC}"), - (b"leftleftarrows", "\u{21C7}"), - (b"leftrightarrow", "\u{2194}"), - (b"leftrightarrows", "\u{21C6}"), - (b"leftrightharpoons", "\u{21CB}"), - (b"leftrightsquigarrow", "\u{21AD}"), - (b"leftthreetimes", "\u{22CB}"), - (b"leg", "\u{22DA}"), - (b"leq", "\u{2264}"), - (b"leqq", "\u{2266}"), - (b"leqslant", "\u{2A7D}"), - (b"les", "\u{2A7D}"), - (b"lescc", "\u{2AA8}"), - (b"lesdot", "\u{2A7F}"), - (b"lesdoto", "\u{2A81}"), - (b"lesdotor", "\u{2A83}"), - (b"lesg", "\u{22DA}\u{FE00}"), - (b"lesges", "\u{2A93}"), - (b"lessapprox", "\u{2A85}"), - (b"lessdot", "\u{22D6}"), - (b"lesseqgtr", "\u{22DA}"), - (b"lesseqqgtr", "\u{2A8B}"), - (b"lessgtr", "\u{2276}"), - (b"lesssim", "\u{2272}"), - (b"lfisht", "\u{297C}"), - (b"lfloor", "\u{230A}"), - (b"lfr", "\u{1D529}"), - (b"lg", "\u{2276}"), - (b"lgE", "\u{2A91}"), - (b"lhard", "\u{21BD}"), - (b"lharu", "\u{21BC}"), - (b"lharul", "\u{296A}"), - (b"lhblk", "\u{2584}"), - (b"ljcy", "\u{0459}"), - (b"ll", "\u{226A}"), - (b"llarr", "\u{21C7}"), - (b"llcorner", "\u{231E}"), - (b"llhard", "\u{296B}"), - (b"lltri", "\u{25FA}"), - (b"lmidot", "\u{0140}"), - (b"lmoust", "\u{23B0}"), - (b"lmoustache", "\u{23B0}"), - (b"lnE", "\u{2268}"), - (b"lnap", "\u{2A89}"), - (b"lnapprox", "\u{2A89}"), - (b"lne", "\u{2A87}"), - (b"lneq", "\u{2A87}"), - (b"lneqq", "\u{2268}"), - (b"lnsim", "\u{22E6}"), - (b"loang", "\u{27EC}"), - (b"loarr", "\u{21FD}"), - (b"lobrk", "\u{27E6}"), - (b"longleftarrow", "\u{27F5}"), - (b"longleftrightarrow", "\u{27F7}"), - (b"longmapsto", "\u{27FC}"), - (b"longrightarrow", "\u{27F6}"), - (b"looparrowleft", "\u{21AB}"), - (b"looparrowright", "\u{21AC}"), - (b"lopar", "\u{2985}"), - (b"lopf", "\u{1D55D}"), - (b"loplus", "\u{2A2D}"), - (b"lotimes", "\u{2A34}"), - (b"lowast", "\u{2217}"), - (b"lowbar", "\u{005F}"), - (b"loz", "\u{25CA}"), - (b"lozenge", "\u{25CA}"), - (b"lozf", "\u{29EB}"), - (b"lpar", "\u{0028}"), - (b"lparlt", "\u{2993}"), - (b"lrarr", "\u{21C6}"), - (b"lrcorner", "\u{231F}"), - (b"lrhar", "\u{21CB}"), - (b"lrhard", "\u{296D}"), - (b"lrm", "\u{200E}"), - (b"lrtri", "\u{22BF}"), - (b"lsaquo", "\u{2039}"), - (b"lscr", "\u{1D4C1}"), - (b"lsh", "\u{21B0}"), - (b"lsim", "\u{2272}"), - (b"lsime", "\u{2A8D}"), - (b"lsimg", "\u{2A8F}"), - (b"lsqb", "\u{005B}"), - (b"lsquo", "\u{2018}"), - (b"lsquor", "\u{201A}"), - (b"lstrok", "\u{0142}"), - (b"lt", "\u{003C}"), - (b"ltcc", "\u{2AA6}"), - (b"ltcir", "\u{2A79}"), - (b"ltdot", "\u{22D6}"), - (b"lthree", "\u{22CB}"), - (b"ltimes", "\u{22C9}"), - (b"ltlarr", "\u{2976}"), - (b"ltquest", "\u{2A7B}"), - (b"ltrPar", "\u{2996}"), - (b"ltri", "\u{25C3}"), - (b"ltrie", "\u{22B4}"), - (b"ltrif", "\u{25C2}"), - (b"lurdshar", "\u{294A}"), - (b"luruhar", "\u{2966}"), - (b"lvertneqq", "\u{2268}\u{FE00}"), - (b"lvnE", "\u{2268}\u{FE00}"), - (b"mDDot", "\u{223A}"), - (b"macr", "\u{00AF}"), - (b"male", "\u{2642}"), - (b"malt", "\u{2720}"), - (b"maltese", "\u{2720}"), - (b"map", "\u{21A6}"), - (b"mapsto", "\u{21A6}"), - (b"mapstodown", "\u{21A7}"), - (b"mapstoleft", "\u{21A4}"), - (b"mapstoup", "\u{21A5}"), - (b"marker", "\u{25AE}"), - (b"mcomma", "\u{2A29}"), - (b"mcy", "\u{043C}"), - (b"mdash", "\u{2014}"), - (b"measuredangle", "\u{2221}"), - (b"mfr", "\u{1D52A}"), - (b"mho", "\u{2127}"), - (b"micro", "\u{00B5}"), - (b"mid", "\u{2223}"), - (b"midast", "\u{002A}"), - (b"midcir", "\u{2AF0}"), - (b"middot", "\u{00B7}"), - (b"minus", "\u{2212}"), - (b"minusb", "\u{229F}"), - (b"minusd", "\u{2238}"), - (b"minusdu", "\u{2A2A}"), - (b"mlcp", "\u{2ADB}"), - (b"mldr", "\u{2026}"), - (b"mnplus", "\u{2213}"), - (b"models", "\u{22A7}"), - (b"mopf", "\u{1D55E}"), - (b"mp", "\u{2213}"), - (b"mscr", "\u{1D4C2}"), - (b"mstpos", "\u{223E}"), - (b"mu", "\u{03BC}"), - (b"multimap", "\u{22B8}"), - (b"mumap", "\u{22B8}"), - (b"nGg", "\u{22D9}\u{0338}"), - (b"nGt", "\u{226B}\u{20D2}"), - (b"nGtv", "\u{226B}\u{0338}"), - (b"nLeftarrow", "\u{21CD}"), - (b"nLeftrightarrow", "\u{21CE}"), - (b"nLl", "\u{22D8}\u{0338}"), - (b"nLt", "\u{226A}\u{20D2}"), - (b"nLtv", "\u{226A}\u{0338}"), - (b"nRightarrow", "\u{21CF}"), - (b"nVDash", "\u{22AF}"), - (b"nVdash", "\u{22AE}"), - (b"nabla", "\u{2207}"), - (b"nacute", "\u{0144}"), - (b"nang", "\u{2220}\u{20D2}"), - (b"nap", "\u{2249}"), - (b"napE", "\u{2A70}\u{0338}"), - (b"napid", "\u{224B}\u{0338}"), - (b"napos", "\u{0149}"), - (b"napprox", "\u{2249}"), - (b"natur", "\u{266E}"), - (b"natural", "\u{266E}"), - (b"naturals", "\u{2115}"), - (b"nbsp", "\u{00A0}"), - (b"nbump", "\u{224E}\u{0338}"), - (b"nbumpe", "\u{224F}\u{0338}"), - (b"ncap", "\u{2A43}"), - (b"ncaron", "\u{0148}"), - (b"ncedil", "\u{0146}"), - (b"ncong", "\u{2247}"), - (b"ncongdot", "\u{2A6D}\u{0338}"), - (b"ncup", "\u{2A42}"), - (b"ncy", "\u{043D}"), - (b"ndash", "\u{2013}"), - (b"ne", "\u{2260}"), - (b"neArr", "\u{21D7}"), - (b"nearhk", "\u{2924}"), - (b"nearr", "\u{2197}"), - (b"nearrow", "\u{2197}"), - (b"nedot", "\u{2250}\u{0338}"), - (b"nequiv", "\u{2262}"), - (b"nesear", "\u{2928}"), - (b"nesim", "\u{2242}\u{0338}"), - (b"nexist", "\u{2204}"), - (b"nexists", "\u{2204}"), - (b"nfr", "\u{1D52B}"), - (b"ngE", "\u{2267}\u{0338}"), - (b"nge", "\u{2271}"), - (b"ngeq", "\u{2271}"), - (b"ngeqq", "\u{2267}\u{0338}"), - (b"ngeqslant", "\u{2A7E}\u{0338}"), - (b"nges", "\u{2A7E}\u{0338}"), - (b"ngsim", "\u{2275}"), - (b"ngt", "\u{226F}"), - (b"ngtr", "\u{226F}"), - (b"nhArr", "\u{21CE}"), - (b"nharr", "\u{21AE}"), - (b"nhpar", "\u{2AF2}"), - (b"ni", "\u{220B}"), - (b"nis", "\u{22FC}"), - (b"nisd", "\u{22FA}"), - (b"niv", "\u{220B}"), - (b"njcy", "\u{045A}"), - (b"nlArr", "\u{21CD}"), - (b"nlE", "\u{2266}\u{0338}"), - (b"nlarr", "\u{219A}"), - (b"nldr", "\u{2025}"), - (b"nle", "\u{2270}"), - (b"nleftarrow", "\u{219A}"), - (b"nleftrightarrow", "\u{21AE}"), - (b"nleq", "\u{2270}"), - (b"nleqq", "\u{2266}\u{0338}"), - (b"nleqslant", "\u{2A7D}\u{0338}"), - (b"nles", "\u{2A7D}\u{0338}"), - (b"nless", "\u{226E}"), - (b"nlsim", "\u{2274}"), - (b"nlt", "\u{226E}"), - (b"nltri", "\u{22EA}"), - (b"nltrie", "\u{22EC}"), - (b"nmid", "\u{2224}"), - (b"nopf", "\u{1D55F}"), - (b"not", "\u{00AC}"), - (b"notin", "\u{2209}"), - (b"notinE", "\u{22F9}\u{0338}"), - (b"notindot", "\u{22F5}\u{0338}"), - (b"notinva", "\u{2209}"), - (b"notinvb", "\u{22F7}"), - (b"notinvc", "\u{22F6}"), - (b"notni", "\u{220C}"), - (b"notniva", "\u{220C}"), - (b"notnivb", "\u{22FE}"), - (b"notnivc", "\u{22FD}"), - (b"npar", "\u{2226}"), - (b"nparallel", "\u{2226}"), - (b"nparsl", "\u{2AFD}\u{20E5}"), - (b"npart", "\u{2202}\u{0338}"), - (b"npolint", "\u{2A14}"), - (b"npr", "\u{2280}"), - (b"nprcue", "\u{22E0}"), - (b"npre", "\u{2AAF}\u{0338}"), - (b"nprec", "\u{2280}"), - (b"npreceq", "\u{2AAF}\u{0338}"), - (b"nrArr", "\u{21CF}"), - (b"nrarr", "\u{219B}"), - (b"nrarrc", "\u{2933}\u{0338}"), - (b"nrarrw", "\u{219D}\u{0338}"), - (b"nrightarrow", "\u{219B}"), - (b"nrtri", "\u{22EB}"), - (b"nrtrie", "\u{22ED}"), - (b"nsc", "\u{2281}"), - (b"nsccue", "\u{22E1}"), - (b"nsce", "\u{2AB0}\u{0338}"), - (b"nscr", "\u{1D4C3}"), - (b"nshortmid", "\u{2224}"), - (b"nshortparallel", "\u{2226}"), - (b"nsim", "\u{2241}"), - (b"nsime", "\u{2244}"), - (b"nsimeq", "\u{2244}"), - (b"nsmid", "\u{2224}"), - (b"nspar", "\u{2226}"), - (b"nsqsube", "\u{22E2}"), - (b"nsqsupe", "\u{22E3}"), - (b"nsub", "\u{2284}"), - (b"nsubE", "\u{2AC5}\u{0338}"), - (b"nsube", "\u{2288}"), - (b"nsubset", "\u{2282}\u{20D2}"), - (b"nsubseteq", "\u{2288}"), - (b"nsubseteqq", "\u{2AC5}\u{0338}"), - (b"nsucc", "\u{2281}"), - (b"nsucceq", "\u{2AB0}\u{0338}"), - (b"nsup", "\u{2285}"), - (b"nsupE", "\u{2AC6}\u{0338}"), - (b"nsupe", "\u{2289}"), - (b"nsupset", "\u{2283}\u{20D2}"), - (b"nsupseteq", "\u{2289}"), - (b"nsupseteqq", "\u{2AC6}\u{0338}"), - (b"ntgl", "\u{2279}"), - (b"ntilde", "\u{00F1}"), - (b"ntlg", "\u{2278}"), - (b"ntriangleleft", "\u{22EA}"), - (b"ntrianglelefteq", "\u{22EC}"), - (b"ntriangleright", "\u{22EB}"), - (b"ntrianglerighteq", "\u{22ED}"), - (b"nu", "\u{03BD}"), - (b"num", "\u{0023}"), - (b"numero", "\u{2116}"), - (b"numsp", "\u{2007}"), - (b"nvDash", "\u{22AD}"), - (b"nvHarr", "\u{2904}"), - (b"nvap", "\u{224D}\u{20D2}"), - (b"nvdash", "\u{22AC}"), - (b"nvge", "\u{2265}\u{20D2}"), - (b"nvgt", "\u{003E}\u{20D2}"), - (b"nvinfin", "\u{29DE}"), - (b"nvlArr", "\u{2902}"), - (b"nvle", "\u{2264}\u{20D2}"), - (b"nvlt", "\u{003C}\u{20D2}"), - (b"nvltrie", "\u{22B4}\u{20D2}"), - (b"nvrArr", "\u{2903}"), - (b"nvrtrie", "\u{22B5}\u{20D2}"), - (b"nvsim", "\u{223C}\u{20D2}"), - (b"nwArr", "\u{21D6}"), - (b"nwarhk", "\u{2923}"), - (b"nwarr", "\u{2196}"), - (b"nwarrow", "\u{2196}"), - (b"nwnear", "\u{2927}"), - (b"oS", "\u{24C8}"), - (b"oacute", "\u{00F3}"), - (b"oast", "\u{229B}"), - (b"ocir", "\u{229A}"), - (b"ocirc", "\u{00F4}"), - (b"ocy", "\u{043E}"), - (b"odash", "\u{229D}"), - (b"odblac", "\u{0151}"), - (b"odiv", "\u{2A38}"), - (b"odot", "\u{2299}"), - (b"odsold", "\u{29BC}"), - (b"oelig", "\u{0153}"), - (b"ofcir", "\u{29BF}"), - (b"ofr", "\u{1D52C}"), - (b"ogon", "\u{02DB}"), - (b"ograve", "\u{00F2}"), - (b"ogt", "\u{29C1}"), - (b"ohbar", "\u{29B5}"), - (b"ohm", "\u{03A9}"), - (b"oint", "\u{222E}"), - (b"olarr", "\u{21BA}"), - (b"olcir", "\u{29BE}"), - (b"olcross", "\u{29BB}"), - (b"oline", "\u{203E}"), - (b"olt", "\u{29C0}"), - (b"omacr", "\u{014D}"), - (b"omega", "\u{03C9}"), - (b"omicron", "\u{03BF}"), - (b"omid", "\u{29B6}"), - (b"ominus", "\u{2296}"), - (b"oopf", "\u{1D560}"), - (b"opar", "\u{29B7}"), - (b"operp", "\u{29B9}"), - (b"oplus", "\u{2295}"), - (b"or", "\u{2228}"), - (b"orarr", "\u{21BB}"), - (b"ord", "\u{2A5D}"), - (b"order", "\u{2134}"), - (b"orderof", "\u{2134}"), - (b"ordf", "\u{00AA}"), - (b"ordm", "\u{00BA}"), - (b"origof", "\u{22B6}"), - (b"oror", "\u{2A56}"), - (b"orslope", "\u{2A57}"), - (b"orv", "\u{2A5B}"), - (b"oscr", "\u{2134}"), - (b"oslash", "\u{00F8}"), - (b"osol", "\u{2298}"), - (b"otilde", "\u{00F5}"), - (b"otimes", "\u{2297}"), - (b"otimesas", "\u{2A36}"), - (b"ouml", "\u{00F6}"), - (b"ovbar", "\u{233D}"), - (b"par", "\u{2225}"), - (b"para", "\u{00B6}"), - (b"parallel", "\u{2225}"), - (b"parsim", "\u{2AF3}"), - (b"parsl", "\u{2AFD}"), - (b"part", "\u{2202}"), - (b"pcy", "\u{043F}"), - (b"percnt", "\u{0025}"), - (b"period", "\u{002E}"), - (b"permil", "\u{2030}"), - (b"perp", "\u{22A5}"), - (b"pertenk", "\u{2031}"), - (b"pfr", "\u{1D52D}"), - (b"phi", "\u{03C6}"), - (b"phiv", "\u{03D5}"), - (b"phmmat", "\u{2133}"), - (b"phone", "\u{260E}"), - (b"pi", "\u{03C0}"), - (b"pitchfork", "\u{22D4}"), - (b"piv", "\u{03D6}"), - (b"planck", "\u{210F}"), - (b"planckh", "\u{210E}"), - (b"plankv", "\u{210F}"), - (b"plus", "\u{002B}"), - (b"plusacir", "\u{2A23}"), - (b"plusb", "\u{229E}"), - (b"pluscir", "\u{2A22}"), - (b"plusdo", "\u{2214}"), - (b"plusdu", "\u{2A25}"), - (b"pluse", "\u{2A72}"), - (b"plusmn", "\u{00B1}"), - (b"plussim", "\u{2A26}"), - (b"plustwo", "\u{2A27}"), - (b"pm", "\u{00B1}"), - (b"pointint", "\u{2A15}"), - (b"popf", "\u{1D561}"), - (b"pound", "\u{00A3}"), - (b"pr", "\u{227A}"), - (b"prE", "\u{2AB3}"), - (b"prap", "\u{2AB7}"), - (b"prcue", "\u{227C}"), - (b"pre", "\u{2AAF}"), - (b"prec", "\u{227A}"), - (b"precapprox", "\u{2AB7}"), - (b"preccurlyeq", "\u{227C}"), - (b"preceq", "\u{2AAF}"), - (b"precnapprox", "\u{2AB9}"), - (b"precneqq", "\u{2AB5}"), - (b"precnsim", "\u{22E8}"), - (b"precsim", "\u{227E}"), - (b"prime", "\u{2032}"), - (b"primes", "\u{2119}"), - (b"prnE", "\u{2AB5}"), - (b"prnap", "\u{2AB9}"), - (b"prnsim", "\u{22E8}"), - (b"prod", "\u{220F}"), - (b"profalar", "\u{232E}"), - (b"profline", "\u{2312}"), - (b"profsurf", "\u{2313}"), - (b"prop", "\u{221D}"), - (b"propto", "\u{221D}"), - (b"prsim", "\u{227E}"), - (b"prurel", "\u{22B0}"), - (b"pscr", "\u{1D4C5}"), - (b"psi", "\u{03C8}"), - (b"puncsp", "\u{2008}"), - (b"qfr", "\u{1D52E}"), - (b"qint", "\u{2A0C}"), - (b"qopf", "\u{1D562}"), - (b"qprime", "\u{2057}"), - (b"qscr", "\u{1D4C6}"), - (b"quaternions", "\u{210D}"), - (b"quatint", "\u{2A16}"), - (b"quest", "\u{003F}"), - (b"questeq", "\u{225F}"), - (b"quot", "\u{0022}"), - (b"rAarr", "\u{21DB}"), - (b"rArr", "\u{21D2}"), - (b"rAtail", "\u{291C}"), - (b"rBarr", "\u{290F}"), - (b"rHar", "\u{2964}"), - (b"race", "\u{223D}\u{0331}"), - (b"racute", "\u{0155}"), - (b"radic", "\u{221A}"), - (b"raemptyv", "\u{29B3}"), - (b"rang", "\u{27E9}"), - (b"rangd", "\u{2992}"), - (b"range", "\u{29A5}"), - (b"rangle", "\u{27E9}"), - (b"raquo", "\u{00BB}"), - (b"rarr", "\u{2192}"), - (b"rarrap", "\u{2975}"), - (b"rarrb", "\u{21E5}"), - (b"rarrbfs", "\u{2920}"), - (b"rarrc", "\u{2933}"), - (b"rarrfs", "\u{291E}"), - (b"rarrhk", "\u{21AA}"), - (b"rarrlp", "\u{21AC}"), - (b"rarrpl", "\u{2945}"), - (b"rarrsim", "\u{2974}"), - (b"rarrtl", "\u{21A3}"), - (b"rarrw", "\u{219D}"), - (b"ratail", "\u{291A}"), - (b"ratio", "\u{2236}"), - (b"rationals", "\u{211A}"), - (b"rbarr", "\u{290D}"), - (b"rbbrk", "\u{2773}"), - (b"rbrace", "\u{007D}"), - (b"rbrack", "\u{005D}"), - (b"rbrke", "\u{298C}"), - (b"rbrksld", "\u{298E}"), - (b"rbrkslu", "\u{2990}"), - (b"rcaron", "\u{0159}"), - (b"rcedil", "\u{0157}"), - (b"rceil", "\u{2309}"), - (b"rcub", "\u{007D}"), - (b"rcy", "\u{0440}"), - (b"rdca", "\u{2937}"), - (b"rdldhar", "\u{2969}"), - (b"rdquo", "\u{201D}"), - (b"rdquor", "\u{201D}"), - (b"rdsh", "\u{21B3}"), - (b"real", "\u{211C}"), - (b"realine", "\u{211B}"), - (b"realpart", "\u{211C}"), - (b"reals", "\u{211D}"), - (b"rect", "\u{25AD}"), - (b"reg", "\u{00AE}"), - (b"rfisht", "\u{297D}"), - (b"rfloor", "\u{230B}"), - (b"rfr", "\u{1D52F}"), - (b"rhard", "\u{21C1}"), - (b"rharu", "\u{21C0}"), - (b"rharul", "\u{296C}"), - (b"rho", "\u{03C1}"), - (b"rhov", "\u{03F1}"), - (b"rightarrow", "\u{2192}"), - (b"rightarrowtail", "\u{21A3}"), - (b"rightharpoondown", "\u{21C1}"), - (b"rightharpoonup", "\u{21C0}"), - (b"rightleftarrows", "\u{21C4}"), - (b"rightleftharpoons", "\u{21CC}"), - (b"rightrightarrows", "\u{21C9}"), - (b"rightsquigarrow", "\u{219D}"), - (b"rightthreetimes", "\u{22CC}"), - (b"ring", "\u{02DA}"), - (b"risingdotseq", "\u{2253}"), - (b"rlarr", "\u{21C4}"), - (b"rlhar", "\u{21CC}"), - (b"rlm", "\u{200F}"), - (b"rmoust", "\u{23B1}"), - (b"rmoustache", "\u{23B1}"), - (b"rnmid", "\u{2AEE}"), - (b"roang", "\u{27ED}"), - (b"roarr", "\u{21FE}"), - (b"robrk", "\u{27E7}"), - (b"ropar", "\u{2986}"), - (b"ropf", "\u{1D563}"), - (b"roplus", "\u{2A2E}"), - (b"rotimes", "\u{2A35}"), - (b"rpar", "\u{0029}"), - (b"rpargt", "\u{2994}"), - (b"rppolint", "\u{2A12}"), - (b"rrarr", "\u{21C9}"), - (b"rsaquo", "\u{203A}"), - (b"rscr", "\u{1D4C7}"), - (b"rsh", "\u{21B1}"), - (b"rsqb", "\u{005D}"), - (b"rsquo", "\u{2019}"), - (b"rsquor", "\u{2019}"), - (b"rthree", "\u{22CC}"), - (b"rtimes", "\u{22CA}"), - (b"rtri", "\u{25B9}"), - (b"rtrie", "\u{22B5}"), - (b"rtrif", "\u{25B8}"), - (b"rtriltri", "\u{29CE}"), - (b"ruluhar", "\u{2968}"), - (b"rx", "\u{211E}"), - (b"sacute", "\u{015B}"), - (b"sbquo", "\u{201A}"), - (b"sc", "\u{227B}"), - (b"scE", "\u{2AB4}"), - (b"scap", "\u{2AB8}"), - (b"scaron", "\u{0161}"), - (b"sccue", "\u{227D}"), - (b"sce", "\u{2AB0}"), - (b"scedil", "\u{015F}"), - (b"scirc", "\u{015D}"), - (b"scnE", "\u{2AB6}"), - (b"scnap", "\u{2ABA}"), - (b"scnsim", "\u{22E9}"), - (b"scpolint", "\u{2A13}"), - (b"scsim", "\u{227F}"), - (b"scy", "\u{0441}"), - (b"sdot", "\u{22C5}"), - (b"sdotb", "\u{22A1}"), - (b"sdote", "\u{2A66}"), - (b"seArr", "\u{21D8}"), - (b"searhk", "\u{2925}"), - (b"searr", "\u{2198}"), - (b"searrow", "\u{2198}"), - (b"sect", "\u{00A7}"), - (b"semi", "\u{003B}"), - (b"seswar", "\u{2929}"), - (b"setminus", "\u{2216}"), - (b"setmn", "\u{2216}"), - (b"sext", "\u{2736}"), - (b"sfr", "\u{1D530}"), - (b"sfrown", "\u{2322}"), - (b"sharp", "\u{266F}"), - (b"shchcy", "\u{0449}"), - (b"shcy", "\u{0448}"), - (b"shortmid", "\u{2223}"), - (b"shortparallel", "\u{2225}"), - (b"shy", "\u{00AD}"), - (b"sigma", "\u{03C3}"), - (b"sigmaf", "\u{03C2}"), - (b"sigmav", "\u{03C2}"), - (b"sim", "\u{223C}"), - (b"simdot", "\u{2A6A}"), - (b"sime", "\u{2243}"), - (b"simeq", "\u{2243}"), - (b"simg", "\u{2A9E}"), - (b"simgE", "\u{2AA0}"), - (b"siml", "\u{2A9D}"), - (b"simlE", "\u{2A9F}"), - (b"simne", "\u{2246}"), - (b"simplus", "\u{2A24}"), - (b"simrarr", "\u{2972}"), - (b"slarr", "\u{2190}"), - (b"smallsetminus", "\u{2216}"), - (b"smashp", "\u{2A33}"), - (b"smeparsl", "\u{29E4}"), - (b"smid", "\u{2223}"), - (b"smile", "\u{2323}"), - (b"smt", "\u{2AAA}"), - (b"smte", "\u{2AAC}"), - (b"smtes", "\u{2AAC}\u{FE00}"), - (b"softcy", "\u{044C}"), - (b"sol", "\u{002F}"), - (b"solb", "\u{29C4}"), - (b"solbar", "\u{233F}"), - (b"sopf", "\u{1D564}"), - (b"spades", "\u{2660}"), - (b"spadesuit", "\u{2660}"), - (b"spar", "\u{2225}"), - (b"sqcap", "\u{2293}"), - (b"sqcaps", "\u{2293}\u{FE00}"), - (b"sqcup", "\u{2294}"), - (b"sqcups", "\u{2294}\u{FE00}"), - (b"sqsub", "\u{228F}"), - (b"sqsube", "\u{2291}"), - (b"sqsubset", "\u{228F}"), - (b"sqsubseteq", "\u{2291}"), - (b"sqsup", "\u{2290}"), - (b"sqsupe", "\u{2292}"), - (b"sqsupset", "\u{2290}"), - (b"sqsupseteq", "\u{2292}"), - (b"squ", "\u{25A1}"), - (b"square", "\u{25A1}"), - (b"squarf", "\u{25AA}"), - (b"squf", "\u{25AA}"), - (b"srarr", "\u{2192}"), - (b"sscr", "\u{1D4C8}"), - (b"ssetmn", "\u{2216}"), - (b"ssmile", "\u{2323}"), - (b"sstarf", "\u{22C6}"), - (b"star", "\u{2606}"), - (b"starf", "\u{2605}"), - (b"straightepsilon", "\u{03F5}"), - (b"straightphi", "\u{03D5}"), - (b"strns", "\u{00AF}"), - (b"sub", "\u{2282}"), - (b"subE", "\u{2AC5}"), - (b"subdot", "\u{2ABD}"), - (b"sube", "\u{2286}"), - (b"subedot", "\u{2AC3}"), - (b"submult", "\u{2AC1}"), - (b"subnE", "\u{2ACB}"), - (b"subne", "\u{228A}"), - (b"subplus", "\u{2ABF}"), - (b"subrarr", "\u{2979}"), - (b"subset", "\u{2282}"), - (b"subseteq", "\u{2286}"), - (b"subseteqq", "\u{2AC5}"), - (b"subsetneq", "\u{228A}"), - (b"subsetneqq", "\u{2ACB}"), - (b"subsim", "\u{2AC7}"), - (b"subsub", "\u{2AD5}"), - (b"subsup", "\u{2AD3}"), - (b"succ", "\u{227B}"), - (b"succapprox", "\u{2AB8}"), - (b"succcurlyeq", "\u{227D}"), - (b"succeq", "\u{2AB0}"), - (b"succnapprox", "\u{2ABA}"), - (b"succneqq", "\u{2AB6}"), - (b"succnsim", "\u{22E9}"), - (b"succsim", "\u{227F}"), - (b"sum", "\u{2211}"), - (b"sung", "\u{266A}"), - (b"sup", "\u{2283}"), - (b"sup1", "\u{00B9}"), - (b"sup2", "\u{00B2}"), - (b"sup3", "\u{00B3}"), - (b"supE", "\u{2AC6}"), - (b"supdot", "\u{2ABE}"), - (b"supdsub", "\u{2AD8}"), - (b"supe", "\u{2287}"), - (b"supedot", "\u{2AC4}"), - (b"suphsol", "\u{27C9}"), - (b"suphsub", "\u{2AD7}"), - (b"suplarr", "\u{297B}"), - (b"supmult", "\u{2AC2}"), - (b"supnE", "\u{2ACC}"), - (b"supne", "\u{228B}"), - (b"supplus", "\u{2AC0}"), - (b"supset", "\u{2283}"), - (b"supseteq", "\u{2287}"), - (b"supseteqq", "\u{2AC6}"), - (b"supsetneq", "\u{228B}"), - (b"supsetneqq", "\u{2ACC}"), - (b"supsim", "\u{2AC8}"), - (b"supsub", "\u{2AD4}"), - (b"supsup", "\u{2AD6}"), - (b"swArr", "\u{21D9}"), - (b"swarhk", "\u{2926}"), - (b"swarr", "\u{2199}"), - (b"swarrow", "\u{2199}"), - (b"swnwar", "\u{292A}"), - (b"szlig", "\u{00DF}"), - (b"target", "\u{2316}"), - (b"tau", "\u{03C4}"), - (b"tbrk", "\u{23B4}"), - (b"tcaron", "\u{0165}"), - (b"tcedil", "\u{0163}"), - (b"tcy", "\u{0442}"), - (b"tdot", "\u{20DB}"), - (b"telrec", "\u{2315}"), - (b"tfr", "\u{1D531}"), - (b"there4", "\u{2234}"), - (b"therefore", "\u{2234}"), - (b"theta", "\u{03B8}"), - (b"thetasym", "\u{03D1}"), - (b"thetav", "\u{03D1}"), - (b"thickapprox", "\u{2248}"), - (b"thicksim", "\u{223C}"), - (b"thinsp", "\u{2009}"), - (b"thkap", "\u{2248}"), - (b"thksim", "\u{223C}"), - (b"thorn", "\u{00FE}"), - (b"tilde", "\u{02DC}"), - (b"times", "\u{00D7}"), - (b"timesb", "\u{22A0}"), - (b"timesbar", "\u{2A31}"), - (b"timesd", "\u{2A30}"), - (b"tint", "\u{222D}"), - (b"toea", "\u{2928}"), - (b"top", "\u{22A4}"), - (b"topbot", "\u{2336}"), - (b"topcir", "\u{2AF1}"), - (b"topf", "\u{1D565}"), - (b"topfork", "\u{2ADA}"), - (b"tosa", "\u{2929}"), - (b"tprime", "\u{2034}"), - (b"trade", "\u{2122}"), - (b"triangle", "\u{25B5}"), - (b"triangledown", "\u{25BF}"), - (b"triangleleft", "\u{25C3}"), - (b"trianglelefteq", "\u{22B4}"), - (b"triangleq", "\u{225C}"), - (b"triangleright", "\u{25B9}"), - (b"trianglerighteq", "\u{22B5}"), - (b"tridot", "\u{25EC}"), - (b"trie", "\u{225C}"), - (b"triminus", "\u{2A3A}"), - (b"triplus", "\u{2A39}"), - (b"trisb", "\u{29CD}"), - (b"tritime", "\u{2A3B}"), - (b"trpezium", "\u{23E2}"), - (b"tscr", "\u{1D4C9}"), - (b"tscy", "\u{0446}"), - (b"tshcy", "\u{045B}"), - (b"tstrok", "\u{0167}"), - (b"twixt", "\u{226C}"), - (b"twoheadleftarrow", "\u{219E}"), - (b"twoheadrightarrow", "\u{21A0}"), - (b"uArr", "\u{21D1}"), - (b"uHar", "\u{2963}"), - (b"uacute", "\u{00FA}"), - (b"uarr", "\u{2191}"), - (b"ubrcy", "\u{045E}"), - (b"ubreve", "\u{016D}"), - (b"ucirc", "\u{00FB}"), - (b"ucy", "\u{0443}"), - (b"udarr", "\u{21C5}"), - (b"udblac", "\u{0171}"), - (b"udhar", "\u{296E}"), - (b"ufisht", "\u{297E}"), - (b"ufr", "\u{1D532}"), - (b"ugrave", "\u{00F9}"), - (b"uharl", "\u{21BF}"), - (b"uharr", "\u{21BE}"), - (b"uhblk", "\u{2580}"), - (b"ulcorn", "\u{231C}"), - (b"ulcorner", "\u{231C}"), - (b"ulcrop", "\u{230F}"), - (b"ultri", "\u{25F8}"), - (b"umacr", "\u{016B}"), - (b"uml", "\u{00A8}"), - (b"uogon", "\u{0173}"), - (b"uopf", "\u{1D566}"), - (b"uparrow", "\u{2191}"), - (b"updownarrow", "\u{2195}"), - (b"upharpoonleft", "\u{21BF}"), - (b"upharpoonright", "\u{21BE}"), - (b"uplus", "\u{228E}"), - (b"upsi", "\u{03C5}"), - (b"upsih", "\u{03D2}"), - (b"upsilon", "\u{03C5}"), - (b"upuparrows", "\u{21C8}"), - (b"urcorn", "\u{231D}"), - (b"urcorner", "\u{231D}"), - (b"urcrop", "\u{230E}"), - (b"uring", "\u{016F}"), - (b"urtri", "\u{25F9}"), - (b"uscr", "\u{1D4CA}"), - (b"utdot", "\u{22F0}"), - (b"utilde", "\u{0169}"), - (b"utri", "\u{25B5}"), - (b"utrif", "\u{25B4}"), - (b"uuarr", "\u{21C8}"), - (b"uuml", "\u{00FC}"), - (b"uwangle", "\u{29A7}"), - (b"vArr", "\u{21D5}"), - (b"vBar", "\u{2AE8}"), - (b"vBarv", "\u{2AE9}"), - (b"vDash", "\u{22A8}"), - (b"vangrt", "\u{299C}"), - (b"varepsilon", "\u{03F5}"), - (b"varkappa", "\u{03F0}"), - (b"varnothing", "\u{2205}"), - (b"varphi", "\u{03D5}"), - (b"varpi", "\u{03D6}"), - (b"varpropto", "\u{221D}"), - (b"varr", "\u{2195}"), - (b"varrho", "\u{03F1}"), - (b"varsigma", "\u{03C2}"), - (b"varsubsetneq", "\u{228A}\u{FE00}"), - (b"varsubsetneqq", "\u{2ACB}\u{FE00}"), - (b"varsupsetneq", "\u{228B}\u{FE00}"), - (b"varsupsetneqq", "\u{2ACC}\u{FE00}"), - (b"vartheta", "\u{03D1}"), - (b"vartriangleleft", "\u{22B2}"), - (b"vartriangleright", "\u{22B3}"), - (b"vcy", "\u{0432}"), - (b"vdash", "\u{22A2}"), - (b"vee", "\u{2228}"), - (b"veebar", "\u{22BB}"), - (b"veeeq", "\u{225A}"), - (b"vellip", "\u{22EE}"), - (b"verbar", "\u{007C}"), - (b"vert", "\u{007C}"), - (b"vfr", "\u{1D533}"), - (b"vltri", "\u{22B2}"), - (b"vnsub", "\u{2282}\u{20D2}"), - (b"vnsup", "\u{2283}\u{20D2}"), - (b"vopf", "\u{1D567}"), - (b"vprop", "\u{221D}"), - (b"vrtri", "\u{22B3}"), - (b"vscr", "\u{1D4CB}"), - (b"vsubnE", "\u{2ACB}\u{FE00}"), - (b"vsubne", "\u{228A}\u{FE00}"), - (b"vsupnE", "\u{2ACC}\u{FE00}"), - (b"vsupne", "\u{228B}\u{FE00}"), - (b"vzigzag", "\u{299A}"), - (b"wcirc", "\u{0175}"), - (b"wedbar", "\u{2A5F}"), - (b"wedge", "\u{2227}"), - (b"wedgeq", "\u{2259}"), - (b"weierp", "\u{2118}"), - (b"wfr", "\u{1D534}"), - (b"wopf", "\u{1D568}"), - (b"wp", "\u{2118}"), - (b"wr", "\u{2240}"), - (b"wreath", "\u{2240}"), - (b"wscr", "\u{1D4CC}"), - (b"xcap", "\u{22C2}"), - (b"xcirc", "\u{25EF}"), - (b"xcup", "\u{22C3}"), - (b"xdtri", "\u{25BD}"), - (b"xfr", "\u{1D535}"), - (b"xhArr", "\u{27FA}"), - (b"xharr", "\u{27F7}"), - (b"xi", "\u{03BE}"), - (b"xlArr", "\u{27F8}"), - (b"xlarr", "\u{27F5}"), - (b"xmap", "\u{27FC}"), - (b"xnis", "\u{22FB}"), - (b"xodot", "\u{2A00}"), - (b"xopf", "\u{1D569}"), - (b"xoplus", "\u{2A01}"), - (b"xotime", "\u{2A02}"), - (b"xrArr", "\u{27F9}"), - (b"xrarr", "\u{27F6}"), - (b"xscr", "\u{1D4CD}"), - (b"xsqcup", "\u{2A06}"), - (b"xuplus", "\u{2A04}"), - (b"xutri", "\u{25B3}"), - (b"xvee", "\u{22C1}"), - (b"xwedge", "\u{22C0}"), - (b"yacute", "\u{00FD}"), - (b"yacy", "\u{044F}"), - (b"ycirc", "\u{0177}"), - (b"ycy", "\u{044B}"), - (b"yen", "\u{00A5}"), - (b"yfr", "\u{1D536}"), - (b"yicy", "\u{0457}"), - (b"yopf", "\u{1D56A}"), - (b"yscr", "\u{1D4CE}"), - (b"yucy", "\u{044E}"), - (b"yuml", "\u{00FF}"), - (b"zacute", "\u{017A}"), - (b"zcaron", "\u{017E}"), - (b"zcy", "\u{0437}"), - (b"zdot", "\u{017C}"), - (b"zeetrf", "\u{2128}"), - (b"zeta", "\u{03B6}"), - (b"zfr", "\u{1D537}"), - (b"zhcy", "\u{0436}"), - (b"zigrarr", "\u{21DD}"), - (b"zopf", "\u{1D56B}"), - (b"zscr", "\u{1D4CF}"), - (b"zwj", "\u{200D}"), - (b"zwnj", "\u{200C}"), -]; - -pub(crate) fn get_entity(bytes: &[u8]) -> Option<&'static str> { - ENTITIES - .binary_search_by_key(&bytes, |&(key, _value)| key) - .ok() - .map(|i| ENTITIES[i].1) -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Expansions of HTML5 entities + +// Autogenerated by mk_entities.py + +const ENTITIES: [(&[u8], &str); 2125] = [ + (b"AElig", "\u{00C6}"), + (b"AMP", "\u{0026}"), + (b"Aacute", "\u{00C1}"), + (b"Abreve", "\u{0102}"), + (b"Acirc", "\u{00C2}"), + (b"Acy", "\u{0410}"), + (b"Afr", "\u{1D504}"), + (b"Agrave", "\u{00C0}"), + (b"Alpha", "\u{0391}"), + (b"Amacr", "\u{0100}"), + (b"And", "\u{2A53}"), + (b"Aogon", "\u{0104}"), + (b"Aopf", "\u{1D538}"), + (b"ApplyFunction", "\u{2061}"), + (b"Aring", "\u{00C5}"), + (b"Ascr", "\u{1D49C}"), + (b"Assign", "\u{2254}"), + (b"Atilde", "\u{00C3}"), + (b"Auml", "\u{00C4}"), + (b"Backslash", "\u{2216}"), + (b"Barv", "\u{2AE7}"), + (b"Barwed", "\u{2306}"), + (b"Bcy", "\u{0411}"), + (b"Because", "\u{2235}"), + (b"Bernoullis", "\u{212C}"), + (b"Beta", "\u{0392}"), + (b"Bfr", "\u{1D505}"), + (b"Bopf", "\u{1D539}"), + (b"Breve", "\u{02D8}"), + (b"Bscr", "\u{212C}"), + (b"Bumpeq", "\u{224E}"), + (b"CHcy", "\u{0427}"), + (b"COPY", "\u{00A9}"), + (b"Cacute", "\u{0106}"), + (b"Cap", "\u{22D2}"), + (b"CapitalDifferentialD", "\u{2145}"), + (b"Cayleys", "\u{212D}"), + (b"Ccaron", "\u{010C}"), + (b"Ccedil", "\u{00C7}"), + (b"Ccirc", "\u{0108}"), + (b"Cconint", "\u{2230}"), + (b"Cdot", "\u{010A}"), + (b"Cedilla", "\u{00B8}"), + (b"CenterDot", "\u{00B7}"), + (b"Cfr", "\u{212D}"), + (b"Chi", "\u{03A7}"), + (b"CircleDot", "\u{2299}"), + (b"CircleMinus", "\u{2296}"), + (b"CirclePlus", "\u{2295}"), + (b"CircleTimes", "\u{2297}"), + (b"ClockwiseContourIntegral", "\u{2232}"), + (b"CloseCurlyDoubleQuote", "\u{201D}"), + (b"CloseCurlyQuote", "\u{2019}"), + (b"Colon", "\u{2237}"), + (b"Colone", "\u{2A74}"), + (b"Congruent", "\u{2261}"), + (b"Conint", "\u{222F}"), + (b"ContourIntegral", "\u{222E}"), + (b"Copf", "\u{2102}"), + (b"Coproduct", "\u{2210}"), + (b"CounterClockwiseContourIntegral", "\u{2233}"), + (b"Cross", "\u{2A2F}"), + (b"Cscr", "\u{1D49E}"), + (b"Cup", "\u{22D3}"), + (b"CupCap", "\u{224D}"), + (b"DD", "\u{2145}"), + (b"DDotrahd", "\u{2911}"), + (b"DJcy", "\u{0402}"), + (b"DScy", "\u{0405}"), + (b"DZcy", "\u{040F}"), + (b"Dagger", "\u{2021}"), + (b"Darr", "\u{21A1}"), + (b"Dashv", "\u{2AE4}"), + (b"Dcaron", "\u{010E}"), + (b"Dcy", "\u{0414}"), + (b"Del", "\u{2207}"), + (b"Delta", "\u{0394}"), + (b"Dfr", "\u{1D507}"), + (b"DiacriticalAcute", "\u{00B4}"), + (b"DiacriticalDot", "\u{02D9}"), + (b"DiacriticalDoubleAcute", "\u{02DD}"), + (b"DiacriticalGrave", "\u{0060}"), + (b"DiacriticalTilde", "\u{02DC}"), + (b"Diamond", "\u{22C4}"), + (b"DifferentialD", "\u{2146}"), + (b"Dopf", "\u{1D53B}"), + (b"Dot", "\u{00A8}"), + (b"DotDot", "\u{20DC}"), + (b"DotEqual", "\u{2250}"), + (b"DoubleContourIntegral", "\u{222F}"), + (b"DoubleDot", "\u{00A8}"), + (b"DoubleDownArrow", "\u{21D3}"), + (b"DoubleLeftArrow", "\u{21D0}"), + (b"DoubleLeftRightArrow", "\u{21D4}"), + (b"DoubleLeftTee", "\u{2AE4}"), + (b"DoubleLongLeftArrow", "\u{27F8}"), + (b"DoubleLongLeftRightArrow", "\u{27FA}"), + (b"DoubleLongRightArrow", "\u{27F9}"), + (b"DoubleRightArrow", "\u{21D2}"), + (b"DoubleRightTee", "\u{22A8}"), + (b"DoubleUpArrow", "\u{21D1}"), + (b"DoubleUpDownArrow", "\u{21D5}"), + (b"DoubleVerticalBar", "\u{2225}"), + (b"DownArrow", "\u{2193}"), + (b"DownArrowBar", "\u{2913}"), + (b"DownArrowUpArrow", "\u{21F5}"), + (b"DownBreve", "\u{0311}"), + (b"DownLeftRightVector", "\u{2950}"), + (b"DownLeftTeeVector", "\u{295E}"), + (b"DownLeftVector", "\u{21BD}"), + (b"DownLeftVectorBar", "\u{2956}"), + (b"DownRightTeeVector", "\u{295F}"), + (b"DownRightVector", "\u{21C1}"), + (b"DownRightVectorBar", "\u{2957}"), + (b"DownTee", "\u{22A4}"), + (b"DownTeeArrow", "\u{21A7}"), + (b"Downarrow", "\u{21D3}"), + (b"Dscr", "\u{1D49F}"), + (b"Dstrok", "\u{0110}"), + (b"ENG", "\u{014A}"), + (b"ETH", "\u{00D0}"), + (b"Eacute", "\u{00C9}"), + (b"Ecaron", "\u{011A}"), + (b"Ecirc", "\u{00CA}"), + (b"Ecy", "\u{042D}"), + (b"Edot", "\u{0116}"), + (b"Efr", "\u{1D508}"), + (b"Egrave", "\u{00C8}"), + (b"Element", "\u{2208}"), + (b"Emacr", "\u{0112}"), + (b"EmptySmallSquare", "\u{25FB}"), + (b"EmptyVerySmallSquare", "\u{25AB}"), + (b"Eogon", "\u{0118}"), + (b"Eopf", "\u{1D53C}"), + (b"Epsilon", "\u{0395}"), + (b"Equal", "\u{2A75}"), + (b"EqualTilde", "\u{2242}"), + (b"Equilibrium", "\u{21CC}"), + (b"Escr", "\u{2130}"), + (b"Esim", "\u{2A73}"), + (b"Eta", "\u{0397}"), + (b"Euml", "\u{00CB}"), + (b"Exists", "\u{2203}"), + (b"ExponentialE", "\u{2147}"), + (b"Fcy", "\u{0424}"), + (b"Ffr", "\u{1D509}"), + (b"FilledSmallSquare", "\u{25FC}"), + (b"FilledVerySmallSquare", "\u{25AA}"), + (b"Fopf", "\u{1D53D}"), + (b"ForAll", "\u{2200}"), + (b"Fouriertrf", "\u{2131}"), + (b"Fscr", "\u{2131}"), + (b"GJcy", "\u{0403}"), + (b"GT", "\u{003E}"), + (b"Gamma", "\u{0393}"), + (b"Gammad", "\u{03DC}"), + (b"Gbreve", "\u{011E}"), + (b"Gcedil", "\u{0122}"), + (b"Gcirc", "\u{011C}"), + (b"Gcy", "\u{0413}"), + (b"Gdot", "\u{0120}"), + (b"Gfr", "\u{1D50A}"), + (b"Gg", "\u{22D9}"), + (b"Gopf", "\u{1D53E}"), + (b"GreaterEqual", "\u{2265}"), + (b"GreaterEqualLess", "\u{22DB}"), + (b"GreaterFullEqual", "\u{2267}"), + (b"GreaterGreater", "\u{2AA2}"), + (b"GreaterLess", "\u{2277}"), + (b"GreaterSlantEqual", "\u{2A7E}"), + (b"GreaterTilde", "\u{2273}"), + (b"Gscr", "\u{1D4A2}"), + (b"Gt", "\u{226B}"), + (b"HARDcy", "\u{042A}"), + (b"Hacek", "\u{02C7}"), + (b"Hat", "\u{005E}"), + (b"Hcirc", "\u{0124}"), + (b"Hfr", "\u{210C}"), + (b"HilbertSpace", "\u{210B}"), + (b"Hopf", "\u{210D}"), + (b"HorizontalLine", "\u{2500}"), + (b"Hscr", "\u{210B}"), + (b"Hstrok", "\u{0126}"), + (b"HumpDownHump", "\u{224E}"), + (b"HumpEqual", "\u{224F}"), + (b"IEcy", "\u{0415}"), + (b"IJlig", "\u{0132}"), + (b"IOcy", "\u{0401}"), + (b"Iacute", "\u{00CD}"), + (b"Icirc", "\u{00CE}"), + (b"Icy", "\u{0418}"), + (b"Idot", "\u{0130}"), + (b"Ifr", "\u{2111}"), + (b"Igrave", "\u{00CC}"), + (b"Im", "\u{2111}"), + (b"Imacr", "\u{012A}"), + (b"ImaginaryI", "\u{2148}"), + (b"Implies", "\u{21D2}"), + (b"Int", "\u{222C}"), + (b"Integral", "\u{222B}"), + (b"Intersection", "\u{22C2}"), + (b"InvisibleComma", "\u{2063}"), + (b"InvisibleTimes", "\u{2062}"), + (b"Iogon", "\u{012E}"), + (b"Iopf", "\u{1D540}"), + (b"Iota", "\u{0399}"), + (b"Iscr", "\u{2110}"), + (b"Itilde", "\u{0128}"), + (b"Iukcy", "\u{0406}"), + (b"Iuml", "\u{00CF}"), + (b"Jcirc", "\u{0134}"), + (b"Jcy", "\u{0419}"), + (b"Jfr", "\u{1D50D}"), + (b"Jopf", "\u{1D541}"), + (b"Jscr", "\u{1D4A5}"), + (b"Jsercy", "\u{0408}"), + (b"Jukcy", "\u{0404}"), + (b"KHcy", "\u{0425}"), + (b"KJcy", "\u{040C}"), + (b"Kappa", "\u{039A}"), + (b"Kcedil", "\u{0136}"), + (b"Kcy", "\u{041A}"), + (b"Kfr", "\u{1D50E}"), + (b"Kopf", "\u{1D542}"), + (b"Kscr", "\u{1D4A6}"), + (b"LJcy", "\u{0409}"), + (b"LT", "\u{003C}"), + (b"Lacute", "\u{0139}"), + (b"Lambda", "\u{039B}"), + (b"Lang", "\u{27EA}"), + (b"Laplacetrf", "\u{2112}"), + (b"Larr", "\u{219E}"), + (b"Lcaron", "\u{013D}"), + (b"Lcedil", "\u{013B}"), + (b"Lcy", "\u{041B}"), + (b"LeftAngleBracket", "\u{27E8}"), + (b"LeftArrow", "\u{2190}"), + (b"LeftArrowBar", "\u{21E4}"), + (b"LeftArrowRightArrow", "\u{21C6}"), + (b"LeftCeiling", "\u{2308}"), + (b"LeftDoubleBracket", "\u{27E6}"), + (b"LeftDownTeeVector", "\u{2961}"), + (b"LeftDownVector", "\u{21C3}"), + (b"LeftDownVectorBar", "\u{2959}"), + (b"LeftFloor", "\u{230A}"), + (b"LeftRightArrow", "\u{2194}"), + (b"LeftRightVector", "\u{294E}"), + (b"LeftTee", "\u{22A3}"), + (b"LeftTeeArrow", "\u{21A4}"), + (b"LeftTeeVector", "\u{295A}"), + (b"LeftTriangle", "\u{22B2}"), + (b"LeftTriangleBar", "\u{29CF}"), + (b"LeftTriangleEqual", "\u{22B4}"), + (b"LeftUpDownVector", "\u{2951}"), + (b"LeftUpTeeVector", "\u{2960}"), + (b"LeftUpVector", "\u{21BF}"), + (b"LeftUpVectorBar", "\u{2958}"), + (b"LeftVector", "\u{21BC}"), + (b"LeftVectorBar", "\u{2952}"), + (b"Leftarrow", "\u{21D0}"), + (b"Leftrightarrow", "\u{21D4}"), + (b"LessEqualGreater", "\u{22DA}"), + (b"LessFullEqual", "\u{2266}"), + (b"LessGreater", "\u{2276}"), + (b"LessLess", "\u{2AA1}"), + (b"LessSlantEqual", "\u{2A7D}"), + (b"LessTilde", "\u{2272}"), + (b"Lfr", "\u{1D50F}"), + (b"Ll", "\u{22D8}"), + (b"Lleftarrow", "\u{21DA}"), + (b"Lmidot", "\u{013F}"), + (b"LongLeftArrow", "\u{27F5}"), + (b"LongLeftRightArrow", "\u{27F7}"), + (b"LongRightArrow", "\u{27F6}"), + (b"Longleftarrow", "\u{27F8}"), + (b"Longleftrightarrow", "\u{27FA}"), + (b"Longrightarrow", "\u{27F9}"), + (b"Lopf", "\u{1D543}"), + (b"LowerLeftArrow", "\u{2199}"), + (b"LowerRightArrow", "\u{2198}"), + (b"Lscr", "\u{2112}"), + (b"Lsh", "\u{21B0}"), + (b"Lstrok", "\u{0141}"), + (b"Lt", "\u{226A}"), + (b"Map", "\u{2905}"), + (b"Mcy", "\u{041C}"), + (b"MediumSpace", "\u{205F}"), + (b"Mellintrf", "\u{2133}"), + (b"Mfr", "\u{1D510}"), + (b"MinusPlus", "\u{2213}"), + (b"Mopf", "\u{1D544}"), + (b"Mscr", "\u{2133}"), + (b"Mu", "\u{039C}"), + (b"NJcy", "\u{040A}"), + (b"Nacute", "\u{0143}"), + (b"Ncaron", "\u{0147}"), + (b"Ncedil", "\u{0145}"), + (b"Ncy", "\u{041D}"), + (b"NegativeMediumSpace", "\u{200B}"), + (b"NegativeThickSpace", "\u{200B}"), + (b"NegativeThinSpace", "\u{200B}"), + (b"NegativeVeryThinSpace", "\u{200B}"), + (b"NestedGreaterGreater", "\u{226B}"), + (b"NestedLessLess", "\u{226A}"), + (b"NewLine", "\u{000A}"), + (b"Nfr", "\u{1D511}"), + (b"NoBreak", "\u{2060}"), + (b"NonBreakingSpace", "\u{00A0}"), + (b"Nopf", "\u{2115}"), + (b"Not", "\u{2AEC}"), + (b"NotCongruent", "\u{2262}"), + (b"NotCupCap", "\u{226D}"), + (b"NotDoubleVerticalBar", "\u{2226}"), + (b"NotElement", "\u{2209}"), + (b"NotEqual", "\u{2260}"), + (b"NotEqualTilde", "\u{2242}\u{0338}"), + (b"NotExists", "\u{2204}"), + (b"NotGreater", "\u{226F}"), + (b"NotGreaterEqual", "\u{2271}"), + (b"NotGreaterFullEqual", "\u{2267}\u{0338}"), + (b"NotGreaterGreater", "\u{226B}\u{0338}"), + (b"NotGreaterLess", "\u{2279}"), + (b"NotGreaterSlantEqual", "\u{2A7E}\u{0338}"), + (b"NotGreaterTilde", "\u{2275}"), + (b"NotHumpDownHump", "\u{224E}\u{0338}"), + (b"NotHumpEqual", "\u{224F}\u{0338}"), + (b"NotLeftTriangle", "\u{22EA}"), + (b"NotLeftTriangleBar", "\u{29CF}\u{0338}"), + (b"NotLeftTriangleEqual", "\u{22EC}"), + (b"NotLess", "\u{226E}"), + (b"NotLessEqual", "\u{2270}"), + (b"NotLessGreater", "\u{2278}"), + (b"NotLessLess", "\u{226A}\u{0338}"), + (b"NotLessSlantEqual", "\u{2A7D}\u{0338}"), + (b"NotLessTilde", "\u{2274}"), + (b"NotNestedGreaterGreater", "\u{2AA2}\u{0338}"), + (b"NotNestedLessLess", "\u{2AA1}\u{0338}"), + (b"NotPrecedes", "\u{2280}"), + (b"NotPrecedesEqual", "\u{2AAF}\u{0338}"), + (b"NotPrecedesSlantEqual", "\u{22E0}"), + (b"NotReverseElement", "\u{220C}"), + (b"NotRightTriangle", "\u{22EB}"), + (b"NotRightTriangleBar", "\u{29D0}\u{0338}"), + (b"NotRightTriangleEqual", "\u{22ED}"), + (b"NotSquareSubset", "\u{228F}\u{0338}"), + (b"NotSquareSubsetEqual", "\u{22E2}"), + (b"NotSquareSuperset", "\u{2290}\u{0338}"), + (b"NotSquareSupersetEqual", "\u{22E3}"), + (b"NotSubset", "\u{2282}\u{20D2}"), + (b"NotSubsetEqual", "\u{2288}"), + (b"NotSucceeds", "\u{2281}"), + (b"NotSucceedsEqual", "\u{2AB0}\u{0338}"), + (b"NotSucceedsSlantEqual", "\u{22E1}"), + (b"NotSucceedsTilde", "\u{227F}\u{0338}"), + (b"NotSuperset", "\u{2283}\u{20D2}"), + (b"NotSupersetEqual", "\u{2289}"), + (b"NotTilde", "\u{2241}"), + (b"NotTildeEqual", "\u{2244}"), + (b"NotTildeFullEqual", "\u{2247}"), + (b"NotTildeTilde", "\u{2249}"), + (b"NotVerticalBar", "\u{2224}"), + (b"Nscr", "\u{1D4A9}"), + (b"Ntilde", "\u{00D1}"), + (b"Nu", "\u{039D}"), + (b"OElig", "\u{0152}"), + (b"Oacute", "\u{00D3}"), + (b"Ocirc", "\u{00D4}"), + (b"Ocy", "\u{041E}"), + (b"Odblac", "\u{0150}"), + (b"Ofr", "\u{1D512}"), + (b"Ograve", "\u{00D2}"), + (b"Omacr", "\u{014C}"), + (b"Omega", "\u{03A9}"), + (b"Omicron", "\u{039F}"), + (b"Oopf", "\u{1D546}"), + (b"OpenCurlyDoubleQuote", "\u{201C}"), + (b"OpenCurlyQuote", "\u{2018}"), + (b"Or", "\u{2A54}"), + (b"Oscr", "\u{1D4AA}"), + (b"Oslash", "\u{00D8}"), + (b"Otilde", "\u{00D5}"), + (b"Otimes", "\u{2A37}"), + (b"Ouml", "\u{00D6}"), + (b"OverBar", "\u{203E}"), + (b"OverBrace", "\u{23DE}"), + (b"OverBracket", "\u{23B4}"), + (b"OverParenthesis", "\u{23DC}"), + (b"PartialD", "\u{2202}"), + (b"Pcy", "\u{041F}"), + (b"Pfr", "\u{1D513}"), + (b"Phi", "\u{03A6}"), + (b"Pi", "\u{03A0}"), + (b"PlusMinus", "\u{00B1}"), + (b"Poincareplane", "\u{210C}"), + (b"Popf", "\u{2119}"), + (b"Pr", "\u{2ABB}"), + (b"Precedes", "\u{227A}"), + (b"PrecedesEqual", "\u{2AAF}"), + (b"PrecedesSlantEqual", "\u{227C}"), + (b"PrecedesTilde", "\u{227E}"), + (b"Prime", "\u{2033}"), + (b"Product", "\u{220F}"), + (b"Proportion", "\u{2237}"), + (b"Proportional", "\u{221D}"), + (b"Pscr", "\u{1D4AB}"), + (b"Psi", "\u{03A8}"), + (b"QUOT", "\u{0022}"), + (b"Qfr", "\u{1D514}"), + (b"Qopf", "\u{211A}"), + (b"Qscr", "\u{1D4AC}"), + (b"RBarr", "\u{2910}"), + (b"REG", "\u{00AE}"), + (b"Racute", "\u{0154}"), + (b"Rang", "\u{27EB}"), + (b"Rarr", "\u{21A0}"), + (b"Rarrtl", "\u{2916}"), + (b"Rcaron", "\u{0158}"), + (b"Rcedil", "\u{0156}"), + (b"Rcy", "\u{0420}"), + (b"Re", "\u{211C}"), + (b"ReverseElement", "\u{220B}"), + (b"ReverseEquilibrium", "\u{21CB}"), + (b"ReverseUpEquilibrium", "\u{296F}"), + (b"Rfr", "\u{211C}"), + (b"Rho", "\u{03A1}"), + (b"RightAngleBracket", "\u{27E9}"), + (b"RightArrow", "\u{2192}"), + (b"RightArrowBar", "\u{21E5}"), + (b"RightArrowLeftArrow", "\u{21C4}"), + (b"RightCeiling", "\u{2309}"), + (b"RightDoubleBracket", "\u{27E7}"), + (b"RightDownTeeVector", "\u{295D}"), + (b"RightDownVector", "\u{21C2}"), + (b"RightDownVectorBar", "\u{2955}"), + (b"RightFloor", "\u{230B}"), + (b"RightTee", "\u{22A2}"), + (b"RightTeeArrow", "\u{21A6}"), + (b"RightTeeVector", "\u{295B}"), + (b"RightTriangle", "\u{22B3}"), + (b"RightTriangleBar", "\u{29D0}"), + (b"RightTriangleEqual", "\u{22B5}"), + (b"RightUpDownVector", "\u{294F}"), + (b"RightUpTeeVector", "\u{295C}"), + (b"RightUpVector", "\u{21BE}"), + (b"RightUpVectorBar", "\u{2954}"), + (b"RightVector", "\u{21C0}"), + (b"RightVectorBar", "\u{2953}"), + (b"Rightarrow", "\u{21D2}"), + (b"Ropf", "\u{211D}"), + (b"RoundImplies", "\u{2970}"), + (b"Rrightarrow", "\u{21DB}"), + (b"Rscr", "\u{211B}"), + (b"Rsh", "\u{21B1}"), + (b"RuleDelayed", "\u{29F4}"), + (b"SHCHcy", "\u{0429}"), + (b"SHcy", "\u{0428}"), + (b"SOFTcy", "\u{042C}"), + (b"Sacute", "\u{015A}"), + (b"Sc", "\u{2ABC}"), + (b"Scaron", "\u{0160}"), + (b"Scedil", "\u{015E}"), + (b"Scirc", "\u{015C}"), + (b"Scy", "\u{0421}"), + (b"Sfr", "\u{1D516}"), + (b"ShortDownArrow", "\u{2193}"), + (b"ShortLeftArrow", "\u{2190}"), + (b"ShortRightArrow", "\u{2192}"), + (b"ShortUpArrow", "\u{2191}"), + (b"Sigma", "\u{03A3}"), + (b"SmallCircle", "\u{2218}"), + (b"Sopf", "\u{1D54A}"), + (b"Sqrt", "\u{221A}"), + (b"Square", "\u{25A1}"), + (b"SquareIntersection", "\u{2293}"), + (b"SquareSubset", "\u{228F}"), + (b"SquareSubsetEqual", "\u{2291}"), + (b"SquareSuperset", "\u{2290}"), + (b"SquareSupersetEqual", "\u{2292}"), + (b"SquareUnion", "\u{2294}"), + (b"Sscr", "\u{1D4AE}"), + (b"Star", "\u{22C6}"), + (b"Sub", "\u{22D0}"), + (b"Subset", "\u{22D0}"), + (b"SubsetEqual", "\u{2286}"), + (b"Succeeds", "\u{227B}"), + (b"SucceedsEqual", "\u{2AB0}"), + (b"SucceedsSlantEqual", "\u{227D}"), + (b"SucceedsTilde", "\u{227F}"), + (b"SuchThat", "\u{220B}"), + (b"Sum", "\u{2211}"), + (b"Sup", "\u{22D1}"), + (b"Superset", "\u{2283}"), + (b"SupersetEqual", "\u{2287}"), + (b"Supset", "\u{22D1}"), + (b"THORN", "\u{00DE}"), + (b"TRADE", "\u{2122}"), + (b"TSHcy", "\u{040B}"), + (b"TScy", "\u{0426}"), + (b"Tab", "\u{0009}"), + (b"Tau", "\u{03A4}"), + (b"Tcaron", "\u{0164}"), + (b"Tcedil", "\u{0162}"), + (b"Tcy", "\u{0422}"), + (b"Tfr", "\u{1D517}"), + (b"Therefore", "\u{2234}"), + (b"Theta", "\u{0398}"), + (b"ThickSpace", "\u{205F}\u{200A}"), + (b"ThinSpace", "\u{2009}"), + (b"Tilde", "\u{223C}"), + (b"TildeEqual", "\u{2243}"), + (b"TildeFullEqual", "\u{2245}"), + (b"TildeTilde", "\u{2248}"), + (b"Topf", "\u{1D54B}"), + (b"TripleDot", "\u{20DB}"), + (b"Tscr", "\u{1D4AF}"), + (b"Tstrok", "\u{0166}"), + (b"Uacute", "\u{00DA}"), + (b"Uarr", "\u{219F}"), + (b"Uarrocir", "\u{2949}"), + (b"Ubrcy", "\u{040E}"), + (b"Ubreve", "\u{016C}"), + (b"Ucirc", "\u{00DB}"), + (b"Ucy", "\u{0423}"), + (b"Udblac", "\u{0170}"), + (b"Ufr", "\u{1D518}"), + (b"Ugrave", "\u{00D9}"), + (b"Umacr", "\u{016A}"), + (b"UnderBar", "\u{005F}"), + (b"UnderBrace", "\u{23DF}"), + (b"UnderBracket", "\u{23B5}"), + (b"UnderParenthesis", "\u{23DD}"), + (b"Union", "\u{22C3}"), + (b"UnionPlus", "\u{228E}"), + (b"Uogon", "\u{0172}"), + (b"Uopf", "\u{1D54C}"), + (b"UpArrow", "\u{2191}"), + (b"UpArrowBar", "\u{2912}"), + (b"UpArrowDownArrow", "\u{21C5}"), + (b"UpDownArrow", "\u{2195}"), + (b"UpEquilibrium", "\u{296E}"), + (b"UpTee", "\u{22A5}"), + (b"UpTeeArrow", "\u{21A5}"), + (b"Uparrow", "\u{21D1}"), + (b"Updownarrow", "\u{21D5}"), + (b"UpperLeftArrow", "\u{2196}"), + (b"UpperRightArrow", "\u{2197}"), + (b"Upsi", "\u{03D2}"), + (b"Upsilon", "\u{03A5}"), + (b"Uring", "\u{016E}"), + (b"Uscr", "\u{1D4B0}"), + (b"Utilde", "\u{0168}"), + (b"Uuml", "\u{00DC}"), + (b"VDash", "\u{22AB}"), + (b"Vbar", "\u{2AEB}"), + (b"Vcy", "\u{0412}"), + (b"Vdash", "\u{22A9}"), + (b"Vdashl", "\u{2AE6}"), + (b"Vee", "\u{22C1}"), + (b"Verbar", "\u{2016}"), + (b"Vert", "\u{2016}"), + (b"VerticalBar", "\u{2223}"), + (b"VerticalLine", "\u{007C}"), + (b"VerticalSeparator", "\u{2758}"), + (b"VerticalTilde", "\u{2240}"), + (b"VeryThinSpace", "\u{200A}"), + (b"Vfr", "\u{1D519}"), + (b"Vopf", "\u{1D54D}"), + (b"Vscr", "\u{1D4B1}"), + (b"Vvdash", "\u{22AA}"), + (b"Wcirc", "\u{0174}"), + (b"Wedge", "\u{22C0}"), + (b"Wfr", "\u{1D51A}"), + (b"Wopf", "\u{1D54E}"), + (b"Wscr", "\u{1D4B2}"), + (b"Xfr", "\u{1D51B}"), + (b"Xi", "\u{039E}"), + (b"Xopf", "\u{1D54F}"), + (b"Xscr", "\u{1D4B3}"), + (b"YAcy", "\u{042F}"), + (b"YIcy", "\u{0407}"), + (b"YUcy", "\u{042E}"), + (b"Yacute", "\u{00DD}"), + (b"Ycirc", "\u{0176}"), + (b"Ycy", "\u{042B}"), + (b"Yfr", "\u{1D51C}"), + (b"Yopf", "\u{1D550}"), + (b"Yscr", "\u{1D4B4}"), + (b"Yuml", "\u{0178}"), + (b"ZHcy", "\u{0416}"), + (b"Zacute", "\u{0179}"), + (b"Zcaron", "\u{017D}"), + (b"Zcy", "\u{0417}"), + (b"Zdot", "\u{017B}"), + (b"ZeroWidthSpace", "\u{200B}"), + (b"Zeta", "\u{0396}"), + (b"Zfr", "\u{2128}"), + (b"Zopf", "\u{2124}"), + (b"Zscr", "\u{1D4B5}"), + (b"aacute", "\u{00E1}"), + (b"abreve", "\u{0103}"), + (b"ac", "\u{223E}"), + (b"acE", "\u{223E}\u{0333}"), + (b"acd", "\u{223F}"), + (b"acirc", "\u{00E2}"), + (b"acute", "\u{00B4}"), + (b"acy", "\u{0430}"), + (b"aelig", "\u{00E6}"), + (b"af", "\u{2061}"), + (b"afr", "\u{1D51E}"), + (b"agrave", "\u{00E0}"), + (b"alefsym", "\u{2135}"), + (b"aleph", "\u{2135}"), + (b"alpha", "\u{03B1}"), + (b"amacr", "\u{0101}"), + (b"amalg", "\u{2A3F}"), + (b"amp", "\u{0026}"), + (b"and", "\u{2227}"), + (b"andand", "\u{2A55}"), + (b"andd", "\u{2A5C}"), + (b"andslope", "\u{2A58}"), + (b"andv", "\u{2A5A}"), + (b"ang", "\u{2220}"), + (b"ange", "\u{29A4}"), + (b"angle", "\u{2220}"), + (b"angmsd", "\u{2221}"), + (b"angmsdaa", "\u{29A8}"), + (b"angmsdab", "\u{29A9}"), + (b"angmsdac", "\u{29AA}"), + (b"angmsdad", "\u{29AB}"), + (b"angmsdae", "\u{29AC}"), + (b"angmsdaf", "\u{29AD}"), + (b"angmsdag", "\u{29AE}"), + (b"angmsdah", "\u{29AF}"), + (b"angrt", "\u{221F}"), + (b"angrtvb", "\u{22BE}"), + (b"angrtvbd", "\u{299D}"), + (b"angsph", "\u{2222}"), + (b"angst", "\u{00C5}"), + (b"angzarr", "\u{237C}"), + (b"aogon", "\u{0105}"), + (b"aopf", "\u{1D552}"), + (b"ap", "\u{2248}"), + (b"apE", "\u{2A70}"), + (b"apacir", "\u{2A6F}"), + (b"ape", "\u{224A}"), + (b"apid", "\u{224B}"), + (b"apos", "\u{0027}"), + (b"approx", "\u{2248}"), + (b"approxeq", "\u{224A}"), + (b"aring", "\u{00E5}"), + (b"ascr", "\u{1D4B6}"), + (b"ast", "\u{002A}"), + (b"asymp", "\u{2248}"), + (b"asympeq", "\u{224D}"), + (b"atilde", "\u{00E3}"), + (b"auml", "\u{00E4}"), + (b"awconint", "\u{2233}"), + (b"awint", "\u{2A11}"), + (b"bNot", "\u{2AED}"), + (b"backcong", "\u{224C}"), + (b"backepsilon", "\u{03F6}"), + (b"backprime", "\u{2035}"), + (b"backsim", "\u{223D}"), + (b"backsimeq", "\u{22CD}"), + (b"barvee", "\u{22BD}"), + (b"barwed", "\u{2305}"), + (b"barwedge", "\u{2305}"), + (b"bbrk", "\u{23B5}"), + (b"bbrktbrk", "\u{23B6}"), + (b"bcong", "\u{224C}"), + (b"bcy", "\u{0431}"), + (b"bdquo", "\u{201E}"), + (b"becaus", "\u{2235}"), + (b"because", "\u{2235}"), + (b"bemptyv", "\u{29B0}"), + (b"bepsi", "\u{03F6}"), + (b"bernou", "\u{212C}"), + (b"beta", "\u{03B2}"), + (b"beth", "\u{2136}"), + (b"between", "\u{226C}"), + (b"bfr", "\u{1D51F}"), + (b"bigcap", "\u{22C2}"), + (b"bigcirc", "\u{25EF}"), + (b"bigcup", "\u{22C3}"), + (b"bigodot", "\u{2A00}"), + (b"bigoplus", "\u{2A01}"), + (b"bigotimes", "\u{2A02}"), + (b"bigsqcup", "\u{2A06}"), + (b"bigstar", "\u{2605}"), + (b"bigtriangledown", "\u{25BD}"), + (b"bigtriangleup", "\u{25B3}"), + (b"biguplus", "\u{2A04}"), + (b"bigvee", "\u{22C1}"), + (b"bigwedge", "\u{22C0}"), + (b"bkarow", "\u{290D}"), + (b"blacklozenge", "\u{29EB}"), + (b"blacksquare", "\u{25AA}"), + (b"blacktriangle", "\u{25B4}"), + (b"blacktriangledown", "\u{25BE}"), + (b"blacktriangleleft", "\u{25C2}"), + (b"blacktriangleright", "\u{25B8}"), + (b"blank", "\u{2423}"), + (b"blk12", "\u{2592}"), + (b"blk14", "\u{2591}"), + (b"blk34", "\u{2593}"), + (b"block", "\u{2588}"), + (b"bne", "\u{003D}\u{20E5}"), + (b"bnequiv", "\u{2261}\u{20E5}"), + (b"bnot", "\u{2310}"), + (b"bopf", "\u{1D553}"), + (b"bot", "\u{22A5}"), + (b"bottom", "\u{22A5}"), + (b"bowtie", "\u{22C8}"), + (b"boxDL", "\u{2557}"), + (b"boxDR", "\u{2554}"), + (b"boxDl", "\u{2556}"), + (b"boxDr", "\u{2553}"), + (b"boxH", "\u{2550}"), + (b"boxHD", "\u{2566}"), + (b"boxHU", "\u{2569}"), + (b"boxHd", "\u{2564}"), + (b"boxHu", "\u{2567}"), + (b"boxUL", "\u{255D}"), + (b"boxUR", "\u{255A}"), + (b"boxUl", "\u{255C}"), + (b"boxUr", "\u{2559}"), + (b"boxV", "\u{2551}"), + (b"boxVH", "\u{256C}"), + (b"boxVL", "\u{2563}"), + (b"boxVR", "\u{2560}"), + (b"boxVh", "\u{256B}"), + (b"boxVl", "\u{2562}"), + (b"boxVr", "\u{255F}"), + (b"boxbox", "\u{29C9}"), + (b"boxdL", "\u{2555}"), + (b"boxdR", "\u{2552}"), + (b"boxdl", "\u{2510}"), + (b"boxdr", "\u{250C}"), + (b"boxh", "\u{2500}"), + (b"boxhD", "\u{2565}"), + (b"boxhU", "\u{2568}"), + (b"boxhd", "\u{252C}"), + (b"boxhu", "\u{2534}"), + (b"boxminus", "\u{229F}"), + (b"boxplus", "\u{229E}"), + (b"boxtimes", "\u{22A0}"), + (b"boxuL", "\u{255B}"), + (b"boxuR", "\u{2558}"), + (b"boxul", "\u{2518}"), + (b"boxur", "\u{2514}"), + (b"boxv", "\u{2502}"), + (b"boxvH", "\u{256A}"), + (b"boxvL", "\u{2561}"), + (b"boxvR", "\u{255E}"), + (b"boxvh", "\u{253C}"), + (b"boxvl", "\u{2524}"), + (b"boxvr", "\u{251C}"), + (b"bprime", "\u{2035}"), + (b"breve", "\u{02D8}"), + (b"brvbar", "\u{00A6}"), + (b"bscr", "\u{1D4B7}"), + (b"bsemi", "\u{204F}"), + (b"bsim", "\u{223D}"), + (b"bsime", "\u{22CD}"), + (b"bsol", "\u{005C}"), + (b"bsolb", "\u{29C5}"), + (b"bsolhsub", "\u{27C8}"), + (b"bull", "\u{2022}"), + (b"bullet", "\u{2022}"), + (b"bump", "\u{224E}"), + (b"bumpE", "\u{2AAE}"), + (b"bumpe", "\u{224F}"), + (b"bumpeq", "\u{224F}"), + (b"cacute", "\u{0107}"), + (b"cap", "\u{2229}"), + (b"capand", "\u{2A44}"), + (b"capbrcup", "\u{2A49}"), + (b"capcap", "\u{2A4B}"), + (b"capcup", "\u{2A47}"), + (b"capdot", "\u{2A40}"), + (b"caps", "\u{2229}\u{FE00}"), + (b"caret", "\u{2041}"), + (b"caron", "\u{02C7}"), + (b"ccaps", "\u{2A4D}"), + (b"ccaron", "\u{010D}"), + (b"ccedil", "\u{00E7}"), + (b"ccirc", "\u{0109}"), + (b"ccups", "\u{2A4C}"), + (b"ccupssm", "\u{2A50}"), + (b"cdot", "\u{010B}"), + (b"cedil", "\u{00B8}"), + (b"cemptyv", "\u{29B2}"), + (b"cent", "\u{00A2}"), + (b"centerdot", "\u{00B7}"), + (b"cfr", "\u{1D520}"), + (b"chcy", "\u{0447}"), + (b"check", "\u{2713}"), + (b"checkmark", "\u{2713}"), + (b"chi", "\u{03C7}"), + (b"cir", "\u{25CB}"), + (b"cirE", "\u{29C3}"), + (b"circ", "\u{02C6}"), + (b"circeq", "\u{2257}"), + (b"circlearrowleft", "\u{21BA}"), + (b"circlearrowright", "\u{21BB}"), + (b"circledR", "\u{00AE}"), + (b"circledS", "\u{24C8}"), + (b"circledast", "\u{229B}"), + (b"circledcirc", "\u{229A}"), + (b"circleddash", "\u{229D}"), + (b"cire", "\u{2257}"), + (b"cirfnint", "\u{2A10}"), + (b"cirmid", "\u{2AEF}"), + (b"cirscir", "\u{29C2}"), + (b"clubs", "\u{2663}"), + (b"clubsuit", "\u{2663}"), + (b"colon", "\u{003A}"), + (b"colone", "\u{2254}"), + (b"coloneq", "\u{2254}"), + (b"comma", "\u{002C}"), + (b"commat", "\u{0040}"), + (b"comp", "\u{2201}"), + (b"compfn", "\u{2218}"), + (b"complement", "\u{2201}"), + (b"complexes", "\u{2102}"), + (b"cong", "\u{2245}"), + (b"congdot", "\u{2A6D}"), + (b"conint", "\u{222E}"), + (b"copf", "\u{1D554}"), + (b"coprod", "\u{2210}"), + (b"copy", "\u{00A9}"), + (b"copysr", "\u{2117}"), + (b"crarr", "\u{21B5}"), + (b"cross", "\u{2717}"), + (b"cscr", "\u{1D4B8}"), + (b"csub", "\u{2ACF}"), + (b"csube", "\u{2AD1}"), + (b"csup", "\u{2AD0}"), + (b"csupe", "\u{2AD2}"), + (b"ctdot", "\u{22EF}"), + (b"cudarrl", "\u{2938}"), + (b"cudarrr", "\u{2935}"), + (b"cuepr", "\u{22DE}"), + (b"cuesc", "\u{22DF}"), + (b"cularr", "\u{21B6}"), + (b"cularrp", "\u{293D}"), + (b"cup", "\u{222A}"), + (b"cupbrcap", "\u{2A48}"), + (b"cupcap", "\u{2A46}"), + (b"cupcup", "\u{2A4A}"), + (b"cupdot", "\u{228D}"), + (b"cupor", "\u{2A45}"), + (b"cups", "\u{222A}\u{FE00}"), + (b"curarr", "\u{21B7}"), + (b"curarrm", "\u{293C}"), + (b"curlyeqprec", "\u{22DE}"), + (b"curlyeqsucc", "\u{22DF}"), + (b"curlyvee", "\u{22CE}"), + (b"curlywedge", "\u{22CF}"), + (b"curren", "\u{00A4}"), + (b"curvearrowleft", "\u{21B6}"), + (b"curvearrowright", "\u{21B7}"), + (b"cuvee", "\u{22CE}"), + (b"cuwed", "\u{22CF}"), + (b"cwconint", "\u{2232}"), + (b"cwint", "\u{2231}"), + (b"cylcty", "\u{232D}"), + (b"dArr", "\u{21D3}"), + (b"dHar", "\u{2965}"), + (b"dagger", "\u{2020}"), + (b"daleth", "\u{2138}"), + (b"darr", "\u{2193}"), + (b"dash", "\u{2010}"), + (b"dashv", "\u{22A3}"), + (b"dbkarow", "\u{290F}"), + (b"dblac", "\u{02DD}"), + (b"dcaron", "\u{010F}"), + (b"dcy", "\u{0434}"), + (b"dd", "\u{2146}"), + (b"ddagger", "\u{2021}"), + (b"ddarr", "\u{21CA}"), + (b"ddotseq", "\u{2A77}"), + (b"deg", "\u{00B0}"), + (b"delta", "\u{03B4}"), + (b"demptyv", "\u{29B1}"), + (b"dfisht", "\u{297F}"), + (b"dfr", "\u{1D521}"), + (b"dharl", "\u{21C3}"), + (b"dharr", "\u{21C2}"), + (b"diam", "\u{22C4}"), + (b"diamond", "\u{22C4}"), + (b"diamondsuit", "\u{2666}"), + (b"diams", "\u{2666}"), + (b"die", "\u{00A8}"), + (b"digamma", "\u{03DD}"), + (b"disin", "\u{22F2}"), + (b"div", "\u{00F7}"), + (b"divide", "\u{00F7}"), + (b"divideontimes", "\u{22C7}"), + (b"divonx", "\u{22C7}"), + (b"djcy", "\u{0452}"), + (b"dlcorn", "\u{231E}"), + (b"dlcrop", "\u{230D}"), + (b"dollar", "\u{0024}"), + (b"dopf", "\u{1D555}"), + (b"dot", "\u{02D9}"), + (b"doteq", "\u{2250}"), + (b"doteqdot", "\u{2251}"), + (b"dotminus", "\u{2238}"), + (b"dotplus", "\u{2214}"), + (b"dotsquare", "\u{22A1}"), + (b"doublebarwedge", "\u{2306}"), + (b"downarrow", "\u{2193}"), + (b"downdownarrows", "\u{21CA}"), + (b"downharpoonleft", "\u{21C3}"), + (b"downharpoonright", "\u{21C2}"), + (b"drbkarow", "\u{2910}"), + (b"drcorn", "\u{231F}"), + (b"drcrop", "\u{230C}"), + (b"dscr", "\u{1D4B9}"), + (b"dscy", "\u{0455}"), + (b"dsol", "\u{29F6}"), + (b"dstrok", "\u{0111}"), + (b"dtdot", "\u{22F1}"), + (b"dtri", "\u{25BF}"), + (b"dtrif", "\u{25BE}"), + (b"duarr", "\u{21F5}"), + (b"duhar", "\u{296F}"), + (b"dwangle", "\u{29A6}"), + (b"dzcy", "\u{045F}"), + (b"dzigrarr", "\u{27FF}"), + (b"eDDot", "\u{2A77}"), + (b"eDot", "\u{2251}"), + (b"eacute", "\u{00E9}"), + (b"easter", "\u{2A6E}"), + (b"ecaron", "\u{011B}"), + (b"ecir", "\u{2256}"), + (b"ecirc", "\u{00EA}"), + (b"ecolon", "\u{2255}"), + (b"ecy", "\u{044D}"), + (b"edot", "\u{0117}"), + (b"ee", "\u{2147}"), + (b"efDot", "\u{2252}"), + (b"efr", "\u{1D522}"), + (b"eg", "\u{2A9A}"), + (b"egrave", "\u{00E8}"), + (b"egs", "\u{2A96}"), + (b"egsdot", "\u{2A98}"), + (b"el", "\u{2A99}"), + (b"elinters", "\u{23E7}"), + (b"ell", "\u{2113}"), + (b"els", "\u{2A95}"), + (b"elsdot", "\u{2A97}"), + (b"emacr", "\u{0113}"), + (b"empty", "\u{2205}"), + (b"emptyset", "\u{2205}"), + (b"emptyv", "\u{2205}"), + (b"emsp", "\u{2003}"), + (b"emsp13", "\u{2004}"), + (b"emsp14", "\u{2005}"), + (b"eng", "\u{014B}"), + (b"ensp", "\u{2002}"), + (b"eogon", "\u{0119}"), + (b"eopf", "\u{1D556}"), + (b"epar", "\u{22D5}"), + (b"eparsl", "\u{29E3}"), + (b"eplus", "\u{2A71}"), + (b"epsi", "\u{03B5}"), + (b"epsilon", "\u{03B5}"), + (b"epsiv", "\u{03F5}"), + (b"eqcirc", "\u{2256}"), + (b"eqcolon", "\u{2255}"), + (b"eqsim", "\u{2242}"), + (b"eqslantgtr", "\u{2A96}"), + (b"eqslantless", "\u{2A95}"), + (b"equals", "\u{003D}"), + (b"equest", "\u{225F}"), + (b"equiv", "\u{2261}"), + (b"equivDD", "\u{2A78}"), + (b"eqvparsl", "\u{29E5}"), + (b"erDot", "\u{2253}"), + (b"erarr", "\u{2971}"), + (b"escr", "\u{212F}"), + (b"esdot", "\u{2250}"), + (b"esim", "\u{2242}"), + (b"eta", "\u{03B7}"), + (b"eth", "\u{00F0}"), + (b"euml", "\u{00EB}"), + (b"euro", "\u{20AC}"), + (b"excl", "\u{0021}"), + (b"exist", "\u{2203}"), + (b"expectation", "\u{2130}"), + (b"exponentiale", "\u{2147}"), + (b"fallingdotseq", "\u{2252}"), + (b"fcy", "\u{0444}"), + (b"female", "\u{2640}"), + (b"ffilig", "\u{FB03}"), + (b"fflig", "\u{FB00}"), + (b"ffllig", "\u{FB04}"), + (b"ffr", "\u{1D523}"), + (b"filig", "\u{FB01}"), + (b"fjlig", "\u{0066}\u{006A}"), + (b"flat", "\u{266D}"), + (b"fllig", "\u{FB02}"), + (b"fltns", "\u{25B1}"), + (b"fnof", "\u{0192}"), + (b"fopf", "\u{1D557}"), + (b"forall", "\u{2200}"), + (b"fork", "\u{22D4}"), + (b"forkv", "\u{2AD9}"), + (b"fpartint", "\u{2A0D}"), + (b"frac12", "\u{00BD}"), + (b"frac13", "\u{2153}"), + (b"frac14", "\u{00BC}"), + (b"frac15", "\u{2155}"), + (b"frac16", "\u{2159}"), + (b"frac18", "\u{215B}"), + (b"frac23", "\u{2154}"), + (b"frac25", "\u{2156}"), + (b"frac34", "\u{00BE}"), + (b"frac35", "\u{2157}"), + (b"frac38", "\u{215C}"), + (b"frac45", "\u{2158}"), + (b"frac56", "\u{215A}"), + (b"frac58", "\u{215D}"), + (b"frac78", "\u{215E}"), + (b"frasl", "\u{2044}"), + (b"frown", "\u{2322}"), + (b"fscr", "\u{1D4BB}"), + (b"gE", "\u{2267}"), + (b"gEl", "\u{2A8C}"), + (b"gacute", "\u{01F5}"), + (b"gamma", "\u{03B3}"), + (b"gammad", "\u{03DD}"), + (b"gap", "\u{2A86}"), + (b"gbreve", "\u{011F}"), + (b"gcirc", "\u{011D}"), + (b"gcy", "\u{0433}"), + (b"gdot", "\u{0121}"), + (b"ge", "\u{2265}"), + (b"gel", "\u{22DB}"), + (b"geq", "\u{2265}"), + (b"geqq", "\u{2267}"), + (b"geqslant", "\u{2A7E}"), + (b"ges", "\u{2A7E}"), + (b"gescc", "\u{2AA9}"), + (b"gesdot", "\u{2A80}"), + (b"gesdoto", "\u{2A82}"), + (b"gesdotol", "\u{2A84}"), + (b"gesl", "\u{22DB}\u{FE00}"), + (b"gesles", "\u{2A94}"), + (b"gfr", "\u{1D524}"), + (b"gg", "\u{226B}"), + (b"ggg", "\u{22D9}"), + (b"gimel", "\u{2137}"), + (b"gjcy", "\u{0453}"), + (b"gl", "\u{2277}"), + (b"glE", "\u{2A92}"), + (b"gla", "\u{2AA5}"), + (b"glj", "\u{2AA4}"), + (b"gnE", "\u{2269}"), + (b"gnap", "\u{2A8A}"), + (b"gnapprox", "\u{2A8A}"), + (b"gne", "\u{2A88}"), + (b"gneq", "\u{2A88}"), + (b"gneqq", "\u{2269}"), + (b"gnsim", "\u{22E7}"), + (b"gopf", "\u{1D558}"), + (b"grave", "\u{0060}"), + (b"gscr", "\u{210A}"), + (b"gsim", "\u{2273}"), + (b"gsime", "\u{2A8E}"), + (b"gsiml", "\u{2A90}"), + (b"gt", "\u{003E}"), + (b"gtcc", "\u{2AA7}"), + (b"gtcir", "\u{2A7A}"), + (b"gtdot", "\u{22D7}"), + (b"gtlPar", "\u{2995}"), + (b"gtquest", "\u{2A7C}"), + (b"gtrapprox", "\u{2A86}"), + (b"gtrarr", "\u{2978}"), + (b"gtrdot", "\u{22D7}"), + (b"gtreqless", "\u{22DB}"), + (b"gtreqqless", "\u{2A8C}"), + (b"gtrless", "\u{2277}"), + (b"gtrsim", "\u{2273}"), + (b"gvertneqq", "\u{2269}\u{FE00}"), + (b"gvnE", "\u{2269}\u{FE00}"), + (b"hArr", "\u{21D4}"), + (b"hairsp", "\u{200A}"), + (b"half", "\u{00BD}"), + (b"hamilt", "\u{210B}"), + (b"hardcy", "\u{044A}"), + (b"harr", "\u{2194}"), + (b"harrcir", "\u{2948}"), + (b"harrw", "\u{21AD}"), + (b"hbar", "\u{210F}"), + (b"hcirc", "\u{0125}"), + (b"hearts", "\u{2665}"), + (b"heartsuit", "\u{2665}"), + (b"hellip", "\u{2026}"), + (b"hercon", "\u{22B9}"), + (b"hfr", "\u{1D525}"), + (b"hksearow", "\u{2925}"), + (b"hkswarow", "\u{2926}"), + (b"hoarr", "\u{21FF}"), + (b"homtht", "\u{223B}"), + (b"hookleftarrow", "\u{21A9}"), + (b"hookrightarrow", "\u{21AA}"), + (b"hopf", "\u{1D559}"), + (b"horbar", "\u{2015}"), + (b"hscr", "\u{1D4BD}"), + (b"hslash", "\u{210F}"), + (b"hstrok", "\u{0127}"), + (b"hybull", "\u{2043}"), + (b"hyphen", "\u{2010}"), + (b"iacute", "\u{00ED}"), + (b"ic", "\u{2063}"), + (b"icirc", "\u{00EE}"), + (b"icy", "\u{0438}"), + (b"iecy", "\u{0435}"), + (b"iexcl", "\u{00A1}"), + (b"iff", "\u{21D4}"), + (b"ifr", "\u{1D526}"), + (b"igrave", "\u{00EC}"), + (b"ii", "\u{2148}"), + (b"iiiint", "\u{2A0C}"), + (b"iiint", "\u{222D}"), + (b"iinfin", "\u{29DC}"), + (b"iiota", "\u{2129}"), + (b"ijlig", "\u{0133}"), + (b"imacr", "\u{012B}"), + (b"image", "\u{2111}"), + (b"imagline", "\u{2110}"), + (b"imagpart", "\u{2111}"), + (b"imath", "\u{0131}"), + (b"imof", "\u{22B7}"), + (b"imped", "\u{01B5}"), + (b"in", "\u{2208}"), + (b"incare", "\u{2105}"), + (b"infin", "\u{221E}"), + (b"infintie", "\u{29DD}"), + (b"inodot", "\u{0131}"), + (b"int", "\u{222B}"), + (b"intcal", "\u{22BA}"), + (b"integers", "\u{2124}"), + (b"intercal", "\u{22BA}"), + (b"intlarhk", "\u{2A17}"), + (b"intprod", "\u{2A3C}"), + (b"iocy", "\u{0451}"), + (b"iogon", "\u{012F}"), + (b"iopf", "\u{1D55A}"), + (b"iota", "\u{03B9}"), + (b"iprod", "\u{2A3C}"), + (b"iquest", "\u{00BF}"), + (b"iscr", "\u{1D4BE}"), + (b"isin", "\u{2208}"), + (b"isinE", "\u{22F9}"), + (b"isindot", "\u{22F5}"), + (b"isins", "\u{22F4}"), + (b"isinsv", "\u{22F3}"), + (b"isinv", "\u{2208}"), + (b"it", "\u{2062}"), + (b"itilde", "\u{0129}"), + (b"iukcy", "\u{0456}"), + (b"iuml", "\u{00EF}"), + (b"jcirc", "\u{0135}"), + (b"jcy", "\u{0439}"), + (b"jfr", "\u{1D527}"), + (b"jmath", "\u{0237}"), + (b"jopf", "\u{1D55B}"), + (b"jscr", "\u{1D4BF}"), + (b"jsercy", "\u{0458}"), + (b"jukcy", "\u{0454}"), + (b"kappa", "\u{03BA}"), + (b"kappav", "\u{03F0}"), + (b"kcedil", "\u{0137}"), + (b"kcy", "\u{043A}"), + (b"kfr", "\u{1D528}"), + (b"kgreen", "\u{0138}"), + (b"khcy", "\u{0445}"), + (b"kjcy", "\u{045C}"), + (b"kopf", "\u{1D55C}"), + (b"kscr", "\u{1D4C0}"), + (b"lAarr", "\u{21DA}"), + (b"lArr", "\u{21D0}"), + (b"lAtail", "\u{291B}"), + (b"lBarr", "\u{290E}"), + (b"lE", "\u{2266}"), + (b"lEg", "\u{2A8B}"), + (b"lHar", "\u{2962}"), + (b"lacute", "\u{013A}"), + (b"laemptyv", "\u{29B4}"), + (b"lagran", "\u{2112}"), + (b"lambda", "\u{03BB}"), + (b"lang", "\u{27E8}"), + (b"langd", "\u{2991}"), + (b"langle", "\u{27E8}"), + (b"lap", "\u{2A85}"), + (b"laquo", "\u{00AB}"), + (b"larr", "\u{2190}"), + (b"larrb", "\u{21E4}"), + (b"larrbfs", "\u{291F}"), + (b"larrfs", "\u{291D}"), + (b"larrhk", "\u{21A9}"), + (b"larrlp", "\u{21AB}"), + (b"larrpl", "\u{2939}"), + (b"larrsim", "\u{2973}"), + (b"larrtl", "\u{21A2}"), + (b"lat", "\u{2AAB}"), + (b"latail", "\u{2919}"), + (b"late", "\u{2AAD}"), + (b"lates", "\u{2AAD}\u{FE00}"), + (b"lbarr", "\u{290C}"), + (b"lbbrk", "\u{2772}"), + (b"lbrace", "\u{007B}"), + (b"lbrack", "\u{005B}"), + (b"lbrke", "\u{298B}"), + (b"lbrksld", "\u{298F}"), + (b"lbrkslu", "\u{298D}"), + (b"lcaron", "\u{013E}"), + (b"lcedil", "\u{013C}"), + (b"lceil", "\u{2308}"), + (b"lcub", "\u{007B}"), + (b"lcy", "\u{043B}"), + (b"ldca", "\u{2936}"), + (b"ldquo", "\u{201C}"), + (b"ldquor", "\u{201E}"), + (b"ldrdhar", "\u{2967}"), + (b"ldrushar", "\u{294B}"), + (b"ldsh", "\u{21B2}"), + (b"le", "\u{2264}"), + (b"leftarrow", "\u{2190}"), + (b"leftarrowtail", "\u{21A2}"), + (b"leftharpoondown", "\u{21BD}"), + (b"leftharpoonup", "\u{21BC}"), + (b"leftleftarrows", "\u{21C7}"), + (b"leftrightarrow", "\u{2194}"), + (b"leftrightarrows", "\u{21C6}"), + (b"leftrightharpoons", "\u{21CB}"), + (b"leftrightsquigarrow", "\u{21AD}"), + (b"leftthreetimes", "\u{22CB}"), + (b"leg", "\u{22DA}"), + (b"leq", "\u{2264}"), + (b"leqq", "\u{2266}"), + (b"leqslant", "\u{2A7D}"), + (b"les", "\u{2A7D}"), + (b"lescc", "\u{2AA8}"), + (b"lesdot", "\u{2A7F}"), + (b"lesdoto", "\u{2A81}"), + (b"lesdotor", "\u{2A83}"), + (b"lesg", "\u{22DA}\u{FE00}"), + (b"lesges", "\u{2A93}"), + (b"lessapprox", "\u{2A85}"), + (b"lessdot", "\u{22D6}"), + (b"lesseqgtr", "\u{22DA}"), + (b"lesseqqgtr", "\u{2A8B}"), + (b"lessgtr", "\u{2276}"), + (b"lesssim", "\u{2272}"), + (b"lfisht", "\u{297C}"), + (b"lfloor", "\u{230A}"), + (b"lfr", "\u{1D529}"), + (b"lg", "\u{2276}"), + (b"lgE", "\u{2A91}"), + (b"lhard", "\u{21BD}"), + (b"lharu", "\u{21BC}"), + (b"lharul", "\u{296A}"), + (b"lhblk", "\u{2584}"), + (b"ljcy", "\u{0459}"), + (b"ll", "\u{226A}"), + (b"llarr", "\u{21C7}"), + (b"llcorner", "\u{231E}"), + (b"llhard", "\u{296B}"), + (b"lltri", "\u{25FA}"), + (b"lmidot", "\u{0140}"), + (b"lmoust", "\u{23B0}"), + (b"lmoustache", "\u{23B0}"), + (b"lnE", "\u{2268}"), + (b"lnap", "\u{2A89}"), + (b"lnapprox", "\u{2A89}"), + (b"lne", "\u{2A87}"), + (b"lneq", "\u{2A87}"), + (b"lneqq", "\u{2268}"), + (b"lnsim", "\u{22E6}"), + (b"loang", "\u{27EC}"), + (b"loarr", "\u{21FD}"), + (b"lobrk", "\u{27E6}"), + (b"longleftarrow", "\u{27F5}"), + (b"longleftrightarrow", "\u{27F7}"), + (b"longmapsto", "\u{27FC}"), + (b"longrightarrow", "\u{27F6}"), + (b"looparrowleft", "\u{21AB}"), + (b"looparrowright", "\u{21AC}"), + (b"lopar", "\u{2985}"), + (b"lopf", "\u{1D55D}"), + (b"loplus", "\u{2A2D}"), + (b"lotimes", "\u{2A34}"), + (b"lowast", "\u{2217}"), + (b"lowbar", "\u{005F}"), + (b"loz", "\u{25CA}"), + (b"lozenge", "\u{25CA}"), + (b"lozf", "\u{29EB}"), + (b"lpar", "\u{0028}"), + (b"lparlt", "\u{2993}"), + (b"lrarr", "\u{21C6}"), + (b"lrcorner", "\u{231F}"), + (b"lrhar", "\u{21CB}"), + (b"lrhard", "\u{296D}"), + (b"lrm", "\u{200E}"), + (b"lrtri", "\u{22BF}"), + (b"lsaquo", "\u{2039}"), + (b"lscr", "\u{1D4C1}"), + (b"lsh", "\u{21B0}"), + (b"lsim", "\u{2272}"), + (b"lsime", "\u{2A8D}"), + (b"lsimg", "\u{2A8F}"), + (b"lsqb", "\u{005B}"), + (b"lsquo", "\u{2018}"), + (b"lsquor", "\u{201A}"), + (b"lstrok", "\u{0142}"), + (b"lt", "\u{003C}"), + (b"ltcc", "\u{2AA6}"), + (b"ltcir", "\u{2A79}"), + (b"ltdot", "\u{22D6}"), + (b"lthree", "\u{22CB}"), + (b"ltimes", "\u{22C9}"), + (b"ltlarr", "\u{2976}"), + (b"ltquest", "\u{2A7B}"), + (b"ltrPar", "\u{2996}"), + (b"ltri", "\u{25C3}"), + (b"ltrie", "\u{22B4}"), + (b"ltrif", "\u{25C2}"), + (b"lurdshar", "\u{294A}"), + (b"luruhar", "\u{2966}"), + (b"lvertneqq", "\u{2268}\u{FE00}"), + (b"lvnE", "\u{2268}\u{FE00}"), + (b"mDDot", "\u{223A}"), + (b"macr", "\u{00AF}"), + (b"male", "\u{2642}"), + (b"malt", "\u{2720}"), + (b"maltese", "\u{2720}"), + (b"map", "\u{21A6}"), + (b"mapsto", "\u{21A6}"), + (b"mapstodown", "\u{21A7}"), + (b"mapstoleft", "\u{21A4}"), + (b"mapstoup", "\u{21A5}"), + (b"marker", "\u{25AE}"), + (b"mcomma", "\u{2A29}"), + (b"mcy", "\u{043C}"), + (b"mdash", "\u{2014}"), + (b"measuredangle", "\u{2221}"), + (b"mfr", "\u{1D52A}"), + (b"mho", "\u{2127}"), + (b"micro", "\u{00B5}"), + (b"mid", "\u{2223}"), + (b"midast", "\u{002A}"), + (b"midcir", "\u{2AF0}"), + (b"middot", "\u{00B7}"), + (b"minus", "\u{2212}"), + (b"minusb", "\u{229F}"), + (b"minusd", "\u{2238}"), + (b"minusdu", "\u{2A2A}"), + (b"mlcp", "\u{2ADB}"), + (b"mldr", "\u{2026}"), + (b"mnplus", "\u{2213}"), + (b"models", "\u{22A7}"), + (b"mopf", "\u{1D55E}"), + (b"mp", "\u{2213}"), + (b"mscr", "\u{1D4C2}"), + (b"mstpos", "\u{223E}"), + (b"mu", "\u{03BC}"), + (b"multimap", "\u{22B8}"), + (b"mumap", "\u{22B8}"), + (b"nGg", "\u{22D9}\u{0338}"), + (b"nGt", "\u{226B}\u{20D2}"), + (b"nGtv", "\u{226B}\u{0338}"), + (b"nLeftarrow", "\u{21CD}"), + (b"nLeftrightarrow", "\u{21CE}"), + (b"nLl", "\u{22D8}\u{0338}"), + (b"nLt", "\u{226A}\u{20D2}"), + (b"nLtv", "\u{226A}\u{0338}"), + (b"nRightarrow", "\u{21CF}"), + (b"nVDash", "\u{22AF}"), + (b"nVdash", "\u{22AE}"), + (b"nabla", "\u{2207}"), + (b"nacute", "\u{0144}"), + (b"nang", "\u{2220}\u{20D2}"), + (b"nap", "\u{2249}"), + (b"napE", "\u{2A70}\u{0338}"), + (b"napid", "\u{224B}\u{0338}"), + (b"napos", "\u{0149}"), + (b"napprox", "\u{2249}"), + (b"natur", "\u{266E}"), + (b"natural", "\u{266E}"), + (b"naturals", "\u{2115}"), + (b"nbsp", "\u{00A0}"), + (b"nbump", "\u{224E}\u{0338}"), + (b"nbumpe", "\u{224F}\u{0338}"), + (b"ncap", "\u{2A43}"), + (b"ncaron", "\u{0148}"), + (b"ncedil", "\u{0146}"), + (b"ncong", "\u{2247}"), + (b"ncongdot", "\u{2A6D}\u{0338}"), + (b"ncup", "\u{2A42}"), + (b"ncy", "\u{043D}"), + (b"ndash", "\u{2013}"), + (b"ne", "\u{2260}"), + (b"neArr", "\u{21D7}"), + (b"nearhk", "\u{2924}"), + (b"nearr", "\u{2197}"), + (b"nearrow", "\u{2197}"), + (b"nedot", "\u{2250}\u{0338}"), + (b"nequiv", "\u{2262}"), + (b"nesear", "\u{2928}"), + (b"nesim", "\u{2242}\u{0338}"), + (b"nexist", "\u{2204}"), + (b"nexists", "\u{2204}"), + (b"nfr", "\u{1D52B}"), + (b"ngE", "\u{2267}\u{0338}"), + (b"nge", "\u{2271}"), + (b"ngeq", "\u{2271}"), + (b"ngeqq", "\u{2267}\u{0338}"), + (b"ngeqslant", "\u{2A7E}\u{0338}"), + (b"nges", "\u{2A7E}\u{0338}"), + (b"ngsim", "\u{2275}"), + (b"ngt", "\u{226F}"), + (b"ngtr", "\u{226F}"), + (b"nhArr", "\u{21CE}"), + (b"nharr", "\u{21AE}"), + (b"nhpar", "\u{2AF2}"), + (b"ni", "\u{220B}"), + (b"nis", "\u{22FC}"), + (b"nisd", "\u{22FA}"), + (b"niv", "\u{220B}"), + (b"njcy", "\u{045A}"), + (b"nlArr", "\u{21CD}"), + (b"nlE", "\u{2266}\u{0338}"), + (b"nlarr", "\u{219A}"), + (b"nldr", "\u{2025}"), + (b"nle", "\u{2270}"), + (b"nleftarrow", "\u{219A}"), + (b"nleftrightarrow", "\u{21AE}"), + (b"nleq", "\u{2270}"), + (b"nleqq", "\u{2266}\u{0338}"), + (b"nleqslant", "\u{2A7D}\u{0338}"), + (b"nles", "\u{2A7D}\u{0338}"), + (b"nless", "\u{226E}"), + (b"nlsim", "\u{2274}"), + (b"nlt", "\u{226E}"), + (b"nltri", "\u{22EA}"), + (b"nltrie", "\u{22EC}"), + (b"nmid", "\u{2224}"), + (b"nopf", "\u{1D55F}"), + (b"not", "\u{00AC}"), + (b"notin", "\u{2209}"), + (b"notinE", "\u{22F9}\u{0338}"), + (b"notindot", "\u{22F5}\u{0338}"), + (b"notinva", "\u{2209}"), + (b"notinvb", "\u{22F7}"), + (b"notinvc", "\u{22F6}"), + (b"notni", "\u{220C}"), + (b"notniva", "\u{220C}"), + (b"notnivb", "\u{22FE}"), + (b"notnivc", "\u{22FD}"), + (b"npar", "\u{2226}"), + (b"nparallel", "\u{2226}"), + (b"nparsl", "\u{2AFD}\u{20E5}"), + (b"npart", "\u{2202}\u{0338}"), + (b"npolint", "\u{2A14}"), + (b"npr", "\u{2280}"), + (b"nprcue", "\u{22E0}"), + (b"npre", "\u{2AAF}\u{0338}"), + (b"nprec", "\u{2280}"), + (b"npreceq", "\u{2AAF}\u{0338}"), + (b"nrArr", "\u{21CF}"), + (b"nrarr", "\u{219B}"), + (b"nrarrc", "\u{2933}\u{0338}"), + (b"nrarrw", "\u{219D}\u{0338}"), + (b"nrightarrow", "\u{219B}"), + (b"nrtri", "\u{22EB}"), + (b"nrtrie", "\u{22ED}"), + (b"nsc", "\u{2281}"), + (b"nsccue", "\u{22E1}"), + (b"nsce", "\u{2AB0}\u{0338}"), + (b"nscr", "\u{1D4C3}"), + (b"nshortmid", "\u{2224}"), + (b"nshortparallel", "\u{2226}"), + (b"nsim", "\u{2241}"), + (b"nsime", "\u{2244}"), + (b"nsimeq", "\u{2244}"), + (b"nsmid", "\u{2224}"), + (b"nspar", "\u{2226}"), + (b"nsqsube", "\u{22E2}"), + (b"nsqsupe", "\u{22E3}"), + (b"nsub", "\u{2284}"), + (b"nsubE", "\u{2AC5}\u{0338}"), + (b"nsube", "\u{2288}"), + (b"nsubset", "\u{2282}\u{20D2}"), + (b"nsubseteq", "\u{2288}"), + (b"nsubseteqq", "\u{2AC5}\u{0338}"), + (b"nsucc", "\u{2281}"), + (b"nsucceq", "\u{2AB0}\u{0338}"), + (b"nsup", "\u{2285}"), + (b"nsupE", "\u{2AC6}\u{0338}"), + (b"nsupe", "\u{2289}"), + (b"nsupset", "\u{2283}\u{20D2}"), + (b"nsupseteq", "\u{2289}"), + (b"nsupseteqq", "\u{2AC6}\u{0338}"), + (b"ntgl", "\u{2279}"), + (b"ntilde", "\u{00F1}"), + (b"ntlg", "\u{2278}"), + (b"ntriangleleft", "\u{22EA}"), + (b"ntrianglelefteq", "\u{22EC}"), + (b"ntriangleright", "\u{22EB}"), + (b"ntrianglerighteq", "\u{22ED}"), + (b"nu", "\u{03BD}"), + (b"num", "\u{0023}"), + (b"numero", "\u{2116}"), + (b"numsp", "\u{2007}"), + (b"nvDash", "\u{22AD}"), + (b"nvHarr", "\u{2904}"), + (b"nvap", "\u{224D}\u{20D2}"), + (b"nvdash", "\u{22AC}"), + (b"nvge", "\u{2265}\u{20D2}"), + (b"nvgt", "\u{003E}\u{20D2}"), + (b"nvinfin", "\u{29DE}"), + (b"nvlArr", "\u{2902}"), + (b"nvle", "\u{2264}\u{20D2}"), + (b"nvlt", "\u{003C}\u{20D2}"), + (b"nvltrie", "\u{22B4}\u{20D2}"), + (b"nvrArr", "\u{2903}"), + (b"nvrtrie", "\u{22B5}\u{20D2}"), + (b"nvsim", "\u{223C}\u{20D2}"), + (b"nwArr", "\u{21D6}"), + (b"nwarhk", "\u{2923}"), + (b"nwarr", "\u{2196}"), + (b"nwarrow", "\u{2196}"), + (b"nwnear", "\u{2927}"), + (b"oS", "\u{24C8}"), + (b"oacute", "\u{00F3}"), + (b"oast", "\u{229B}"), + (b"ocir", "\u{229A}"), + (b"ocirc", "\u{00F4}"), + (b"ocy", "\u{043E}"), + (b"odash", "\u{229D}"), + (b"odblac", "\u{0151}"), + (b"odiv", "\u{2A38}"), + (b"odot", "\u{2299}"), + (b"odsold", "\u{29BC}"), + (b"oelig", "\u{0153}"), + (b"ofcir", "\u{29BF}"), + (b"ofr", "\u{1D52C}"), + (b"ogon", "\u{02DB}"), + (b"ograve", "\u{00F2}"), + (b"ogt", "\u{29C1}"), + (b"ohbar", "\u{29B5}"), + (b"ohm", "\u{03A9}"), + (b"oint", "\u{222E}"), + (b"olarr", "\u{21BA}"), + (b"olcir", "\u{29BE}"), + (b"olcross", "\u{29BB}"), + (b"oline", "\u{203E}"), + (b"olt", "\u{29C0}"), + (b"omacr", "\u{014D}"), + (b"omega", "\u{03C9}"), + (b"omicron", "\u{03BF}"), + (b"omid", "\u{29B6}"), + (b"ominus", "\u{2296}"), + (b"oopf", "\u{1D560}"), + (b"opar", "\u{29B7}"), + (b"operp", "\u{29B9}"), + (b"oplus", "\u{2295}"), + (b"or", "\u{2228}"), + (b"orarr", "\u{21BB}"), + (b"ord", "\u{2A5D}"), + (b"order", "\u{2134}"), + (b"orderof", "\u{2134}"), + (b"ordf", "\u{00AA}"), + (b"ordm", "\u{00BA}"), + (b"origof", "\u{22B6}"), + (b"oror", "\u{2A56}"), + (b"orslope", "\u{2A57}"), + (b"orv", "\u{2A5B}"), + (b"oscr", "\u{2134}"), + (b"oslash", "\u{00F8}"), + (b"osol", "\u{2298}"), + (b"otilde", "\u{00F5}"), + (b"otimes", "\u{2297}"), + (b"otimesas", "\u{2A36}"), + (b"ouml", "\u{00F6}"), + (b"ovbar", "\u{233D}"), + (b"par", "\u{2225}"), + (b"para", "\u{00B6}"), + (b"parallel", "\u{2225}"), + (b"parsim", "\u{2AF3}"), + (b"parsl", "\u{2AFD}"), + (b"part", "\u{2202}"), + (b"pcy", "\u{043F}"), + (b"percnt", "\u{0025}"), + (b"period", "\u{002E}"), + (b"permil", "\u{2030}"), + (b"perp", "\u{22A5}"), + (b"pertenk", "\u{2031}"), + (b"pfr", "\u{1D52D}"), + (b"phi", "\u{03C6}"), + (b"phiv", "\u{03D5}"), + (b"phmmat", "\u{2133}"), + (b"phone", "\u{260E}"), + (b"pi", "\u{03C0}"), + (b"pitchfork", "\u{22D4}"), + (b"piv", "\u{03D6}"), + (b"planck", "\u{210F}"), + (b"planckh", "\u{210E}"), + (b"plankv", "\u{210F}"), + (b"plus", "\u{002B}"), + (b"plusacir", "\u{2A23}"), + (b"plusb", "\u{229E}"), + (b"pluscir", "\u{2A22}"), + (b"plusdo", "\u{2214}"), + (b"plusdu", "\u{2A25}"), + (b"pluse", "\u{2A72}"), + (b"plusmn", "\u{00B1}"), + (b"plussim", "\u{2A26}"), + (b"plustwo", "\u{2A27}"), + (b"pm", "\u{00B1}"), + (b"pointint", "\u{2A15}"), + (b"popf", "\u{1D561}"), + (b"pound", "\u{00A3}"), + (b"pr", "\u{227A}"), + (b"prE", "\u{2AB3}"), + (b"prap", "\u{2AB7}"), + (b"prcue", "\u{227C}"), + (b"pre", "\u{2AAF}"), + (b"prec", "\u{227A}"), + (b"precapprox", "\u{2AB7}"), + (b"preccurlyeq", "\u{227C}"), + (b"preceq", "\u{2AAF}"), + (b"precnapprox", "\u{2AB9}"), + (b"precneqq", "\u{2AB5}"), + (b"precnsim", "\u{22E8}"), + (b"precsim", "\u{227E}"), + (b"prime", "\u{2032}"), + (b"primes", "\u{2119}"), + (b"prnE", "\u{2AB5}"), + (b"prnap", "\u{2AB9}"), + (b"prnsim", "\u{22E8}"), + (b"prod", "\u{220F}"), + (b"profalar", "\u{232E}"), + (b"profline", "\u{2312}"), + (b"profsurf", "\u{2313}"), + (b"prop", "\u{221D}"), + (b"propto", "\u{221D}"), + (b"prsim", "\u{227E}"), + (b"prurel", "\u{22B0}"), + (b"pscr", "\u{1D4C5}"), + (b"psi", "\u{03C8}"), + (b"puncsp", "\u{2008}"), + (b"qfr", "\u{1D52E}"), + (b"qint", "\u{2A0C}"), + (b"qopf", "\u{1D562}"), + (b"qprime", "\u{2057}"), + (b"qscr", "\u{1D4C6}"), + (b"quaternions", "\u{210D}"), + (b"quatint", "\u{2A16}"), + (b"quest", "\u{003F}"), + (b"questeq", "\u{225F}"), + (b"quot", "\u{0022}"), + (b"rAarr", "\u{21DB}"), + (b"rArr", "\u{21D2}"), + (b"rAtail", "\u{291C}"), + (b"rBarr", "\u{290F}"), + (b"rHar", "\u{2964}"), + (b"race", "\u{223D}\u{0331}"), + (b"racute", "\u{0155}"), + (b"radic", "\u{221A}"), + (b"raemptyv", "\u{29B3}"), + (b"rang", "\u{27E9}"), + (b"rangd", "\u{2992}"), + (b"range", "\u{29A5}"), + (b"rangle", "\u{27E9}"), + (b"raquo", "\u{00BB}"), + (b"rarr", "\u{2192}"), + (b"rarrap", "\u{2975}"), + (b"rarrb", "\u{21E5}"), + (b"rarrbfs", "\u{2920}"), + (b"rarrc", "\u{2933}"), + (b"rarrfs", "\u{291E}"), + (b"rarrhk", "\u{21AA}"), + (b"rarrlp", "\u{21AC}"), + (b"rarrpl", "\u{2945}"), + (b"rarrsim", "\u{2974}"), + (b"rarrtl", "\u{21A3}"), + (b"rarrw", "\u{219D}"), + (b"ratail", "\u{291A}"), + (b"ratio", "\u{2236}"), + (b"rationals", "\u{211A}"), + (b"rbarr", "\u{290D}"), + (b"rbbrk", "\u{2773}"), + (b"rbrace", "\u{007D}"), + (b"rbrack", "\u{005D}"), + (b"rbrke", "\u{298C}"), + (b"rbrksld", "\u{298E}"), + (b"rbrkslu", "\u{2990}"), + (b"rcaron", "\u{0159}"), + (b"rcedil", "\u{0157}"), + (b"rceil", "\u{2309}"), + (b"rcub", "\u{007D}"), + (b"rcy", "\u{0440}"), + (b"rdca", "\u{2937}"), + (b"rdldhar", "\u{2969}"), + (b"rdquo", "\u{201D}"), + (b"rdquor", "\u{201D}"), + (b"rdsh", "\u{21B3}"), + (b"real", "\u{211C}"), + (b"realine", "\u{211B}"), + (b"realpart", "\u{211C}"), + (b"reals", "\u{211D}"), + (b"rect", "\u{25AD}"), + (b"reg", "\u{00AE}"), + (b"rfisht", "\u{297D}"), + (b"rfloor", "\u{230B}"), + (b"rfr", "\u{1D52F}"), + (b"rhard", "\u{21C1}"), + (b"rharu", "\u{21C0}"), + (b"rharul", "\u{296C}"), + (b"rho", "\u{03C1}"), + (b"rhov", "\u{03F1}"), + (b"rightarrow", "\u{2192}"), + (b"rightarrowtail", "\u{21A3}"), + (b"rightharpoondown", "\u{21C1}"), + (b"rightharpoonup", "\u{21C0}"), + (b"rightleftarrows", "\u{21C4}"), + (b"rightleftharpoons", "\u{21CC}"), + (b"rightrightarrows", "\u{21C9}"), + (b"rightsquigarrow", "\u{219D}"), + (b"rightthreetimes", "\u{22CC}"), + (b"ring", "\u{02DA}"), + (b"risingdotseq", "\u{2253}"), + (b"rlarr", "\u{21C4}"), + (b"rlhar", "\u{21CC}"), + (b"rlm", "\u{200F}"), + (b"rmoust", "\u{23B1}"), + (b"rmoustache", "\u{23B1}"), + (b"rnmid", "\u{2AEE}"), + (b"roang", "\u{27ED}"), + (b"roarr", "\u{21FE}"), + (b"robrk", "\u{27E7}"), + (b"ropar", "\u{2986}"), + (b"ropf", "\u{1D563}"), + (b"roplus", "\u{2A2E}"), + (b"rotimes", "\u{2A35}"), + (b"rpar", "\u{0029}"), + (b"rpargt", "\u{2994}"), + (b"rppolint", "\u{2A12}"), + (b"rrarr", "\u{21C9}"), + (b"rsaquo", "\u{203A}"), + (b"rscr", "\u{1D4C7}"), + (b"rsh", "\u{21B1}"), + (b"rsqb", "\u{005D}"), + (b"rsquo", "\u{2019}"), + (b"rsquor", "\u{2019}"), + (b"rthree", "\u{22CC}"), + (b"rtimes", "\u{22CA}"), + (b"rtri", "\u{25B9}"), + (b"rtrie", "\u{22B5}"), + (b"rtrif", "\u{25B8}"), + (b"rtriltri", "\u{29CE}"), + (b"ruluhar", "\u{2968}"), + (b"rx", "\u{211E}"), + (b"sacute", "\u{015B}"), + (b"sbquo", "\u{201A}"), + (b"sc", "\u{227B}"), + (b"scE", "\u{2AB4}"), + (b"scap", "\u{2AB8}"), + (b"scaron", "\u{0161}"), + (b"sccue", "\u{227D}"), + (b"sce", "\u{2AB0}"), + (b"scedil", "\u{015F}"), + (b"scirc", "\u{015D}"), + (b"scnE", "\u{2AB6}"), + (b"scnap", "\u{2ABA}"), + (b"scnsim", "\u{22E9}"), + (b"scpolint", "\u{2A13}"), + (b"scsim", "\u{227F}"), + (b"scy", "\u{0441}"), + (b"sdot", "\u{22C5}"), + (b"sdotb", "\u{22A1}"), + (b"sdote", "\u{2A66}"), + (b"seArr", "\u{21D8}"), + (b"searhk", "\u{2925}"), + (b"searr", "\u{2198}"), + (b"searrow", "\u{2198}"), + (b"sect", "\u{00A7}"), + (b"semi", "\u{003B}"), + (b"seswar", "\u{2929}"), + (b"setminus", "\u{2216}"), + (b"setmn", "\u{2216}"), + (b"sext", "\u{2736}"), + (b"sfr", "\u{1D530}"), + (b"sfrown", "\u{2322}"), + (b"sharp", "\u{266F}"), + (b"shchcy", "\u{0449}"), + (b"shcy", "\u{0448}"), + (b"shortmid", "\u{2223}"), + (b"shortparallel", "\u{2225}"), + (b"shy", "\u{00AD}"), + (b"sigma", "\u{03C3}"), + (b"sigmaf", "\u{03C2}"), + (b"sigmav", "\u{03C2}"), + (b"sim", "\u{223C}"), + (b"simdot", "\u{2A6A}"), + (b"sime", "\u{2243}"), + (b"simeq", "\u{2243}"), + (b"simg", "\u{2A9E}"), + (b"simgE", "\u{2AA0}"), + (b"siml", "\u{2A9D}"), + (b"simlE", "\u{2A9F}"), + (b"simne", "\u{2246}"), + (b"simplus", "\u{2A24}"), + (b"simrarr", "\u{2972}"), + (b"slarr", "\u{2190}"), + (b"smallsetminus", "\u{2216}"), + (b"smashp", "\u{2A33}"), + (b"smeparsl", "\u{29E4}"), + (b"smid", "\u{2223}"), + (b"smile", "\u{2323}"), + (b"smt", "\u{2AAA}"), + (b"smte", "\u{2AAC}"), + (b"smtes", "\u{2AAC}\u{FE00}"), + (b"softcy", "\u{044C}"), + (b"sol", "\u{002F}"), + (b"solb", "\u{29C4}"), + (b"solbar", "\u{233F}"), + (b"sopf", "\u{1D564}"), + (b"spades", "\u{2660}"), + (b"spadesuit", "\u{2660}"), + (b"spar", "\u{2225}"), + (b"sqcap", "\u{2293}"), + (b"sqcaps", "\u{2293}\u{FE00}"), + (b"sqcup", "\u{2294}"), + (b"sqcups", "\u{2294}\u{FE00}"), + (b"sqsub", "\u{228F}"), + (b"sqsube", "\u{2291}"), + (b"sqsubset", "\u{228F}"), + (b"sqsubseteq", "\u{2291}"), + (b"sqsup", "\u{2290}"), + (b"sqsupe", "\u{2292}"), + (b"sqsupset", "\u{2290}"), + (b"sqsupseteq", "\u{2292}"), + (b"squ", "\u{25A1}"), + (b"square", "\u{25A1}"), + (b"squarf", "\u{25AA}"), + (b"squf", "\u{25AA}"), + (b"srarr", "\u{2192}"), + (b"sscr", "\u{1D4C8}"), + (b"ssetmn", "\u{2216}"), + (b"ssmile", "\u{2323}"), + (b"sstarf", "\u{22C6}"), + (b"star", "\u{2606}"), + (b"starf", "\u{2605}"), + (b"straightepsilon", "\u{03F5}"), + (b"straightphi", "\u{03D5}"), + (b"strns", "\u{00AF}"), + (b"sub", "\u{2282}"), + (b"subE", "\u{2AC5}"), + (b"subdot", "\u{2ABD}"), + (b"sube", "\u{2286}"), + (b"subedot", "\u{2AC3}"), + (b"submult", "\u{2AC1}"), + (b"subnE", "\u{2ACB}"), + (b"subne", "\u{228A}"), + (b"subplus", "\u{2ABF}"), + (b"subrarr", "\u{2979}"), + (b"subset", "\u{2282}"), + (b"subseteq", "\u{2286}"), + (b"subseteqq", "\u{2AC5}"), + (b"subsetneq", "\u{228A}"), + (b"subsetneqq", "\u{2ACB}"), + (b"subsim", "\u{2AC7}"), + (b"subsub", "\u{2AD5}"), + (b"subsup", "\u{2AD3}"), + (b"succ", "\u{227B}"), + (b"succapprox", "\u{2AB8}"), + (b"succcurlyeq", "\u{227D}"), + (b"succeq", "\u{2AB0}"), + (b"succnapprox", "\u{2ABA}"), + (b"succneqq", "\u{2AB6}"), + (b"succnsim", "\u{22E9}"), + (b"succsim", "\u{227F}"), + (b"sum", "\u{2211}"), + (b"sung", "\u{266A}"), + (b"sup", "\u{2283}"), + (b"sup1", "\u{00B9}"), + (b"sup2", "\u{00B2}"), + (b"sup3", "\u{00B3}"), + (b"supE", "\u{2AC6}"), + (b"supdot", "\u{2ABE}"), + (b"supdsub", "\u{2AD8}"), + (b"supe", "\u{2287}"), + (b"supedot", "\u{2AC4}"), + (b"suphsol", "\u{27C9}"), + (b"suphsub", "\u{2AD7}"), + (b"suplarr", "\u{297B}"), + (b"supmult", "\u{2AC2}"), + (b"supnE", "\u{2ACC}"), + (b"supne", "\u{228B}"), + (b"supplus", "\u{2AC0}"), + (b"supset", "\u{2283}"), + (b"supseteq", "\u{2287}"), + (b"supseteqq", "\u{2AC6}"), + (b"supsetneq", "\u{228B}"), + (b"supsetneqq", "\u{2ACC}"), + (b"supsim", "\u{2AC8}"), + (b"supsub", "\u{2AD4}"), + (b"supsup", "\u{2AD6}"), + (b"swArr", "\u{21D9}"), + (b"swarhk", "\u{2926}"), + (b"swarr", "\u{2199}"), + (b"swarrow", "\u{2199}"), + (b"swnwar", "\u{292A}"), + (b"szlig", "\u{00DF}"), + (b"target", "\u{2316}"), + (b"tau", "\u{03C4}"), + (b"tbrk", "\u{23B4}"), + (b"tcaron", "\u{0165}"), + (b"tcedil", "\u{0163}"), + (b"tcy", "\u{0442}"), + (b"tdot", "\u{20DB}"), + (b"telrec", "\u{2315}"), + (b"tfr", "\u{1D531}"), + (b"there4", "\u{2234}"), + (b"therefore", "\u{2234}"), + (b"theta", "\u{03B8}"), + (b"thetasym", "\u{03D1}"), + (b"thetav", "\u{03D1}"), + (b"thickapprox", "\u{2248}"), + (b"thicksim", "\u{223C}"), + (b"thinsp", "\u{2009}"), + (b"thkap", "\u{2248}"), + (b"thksim", "\u{223C}"), + (b"thorn", "\u{00FE}"), + (b"tilde", "\u{02DC}"), + (b"times", "\u{00D7}"), + (b"timesb", "\u{22A0}"), + (b"timesbar", "\u{2A31}"), + (b"timesd", "\u{2A30}"), + (b"tint", "\u{222D}"), + (b"toea", "\u{2928}"), + (b"top", "\u{22A4}"), + (b"topbot", "\u{2336}"), + (b"topcir", "\u{2AF1}"), + (b"topf", "\u{1D565}"), + (b"topfork", "\u{2ADA}"), + (b"tosa", "\u{2929}"), + (b"tprime", "\u{2034}"), + (b"trade", "\u{2122}"), + (b"triangle", "\u{25B5}"), + (b"triangledown", "\u{25BF}"), + (b"triangleleft", "\u{25C3}"), + (b"trianglelefteq", "\u{22B4}"), + (b"triangleq", "\u{225C}"), + (b"triangleright", "\u{25B9}"), + (b"trianglerighteq", "\u{22B5}"), + (b"tridot", "\u{25EC}"), + (b"trie", "\u{225C}"), + (b"triminus", "\u{2A3A}"), + (b"triplus", "\u{2A39}"), + (b"trisb", "\u{29CD}"), + (b"tritime", "\u{2A3B}"), + (b"trpezium", "\u{23E2}"), + (b"tscr", "\u{1D4C9}"), + (b"tscy", "\u{0446}"), + (b"tshcy", "\u{045B}"), + (b"tstrok", "\u{0167}"), + (b"twixt", "\u{226C}"), + (b"twoheadleftarrow", "\u{219E}"), + (b"twoheadrightarrow", "\u{21A0}"), + (b"uArr", "\u{21D1}"), + (b"uHar", "\u{2963}"), + (b"uacute", "\u{00FA}"), + (b"uarr", "\u{2191}"), + (b"ubrcy", "\u{045E}"), + (b"ubreve", "\u{016D}"), + (b"ucirc", "\u{00FB}"), + (b"ucy", "\u{0443}"), + (b"udarr", "\u{21C5}"), + (b"udblac", "\u{0171}"), + (b"udhar", "\u{296E}"), + (b"ufisht", "\u{297E}"), + (b"ufr", "\u{1D532}"), + (b"ugrave", "\u{00F9}"), + (b"uharl", "\u{21BF}"), + (b"uharr", "\u{21BE}"), + (b"uhblk", "\u{2580}"), + (b"ulcorn", "\u{231C}"), + (b"ulcorner", "\u{231C}"), + (b"ulcrop", "\u{230F}"), + (b"ultri", "\u{25F8}"), + (b"umacr", "\u{016B}"), + (b"uml", "\u{00A8}"), + (b"uogon", "\u{0173}"), + (b"uopf", "\u{1D566}"), + (b"uparrow", "\u{2191}"), + (b"updownarrow", "\u{2195}"), + (b"upharpoonleft", "\u{21BF}"), + (b"upharpoonright", "\u{21BE}"), + (b"uplus", "\u{228E}"), + (b"upsi", "\u{03C5}"), + (b"upsih", "\u{03D2}"), + (b"upsilon", "\u{03C5}"), + (b"upuparrows", "\u{21C8}"), + (b"urcorn", "\u{231D}"), + (b"urcorner", "\u{231D}"), + (b"urcrop", "\u{230E}"), + (b"uring", "\u{016F}"), + (b"urtri", "\u{25F9}"), + (b"uscr", "\u{1D4CA}"), + (b"utdot", "\u{22F0}"), + (b"utilde", "\u{0169}"), + (b"utri", "\u{25B5}"), + (b"utrif", "\u{25B4}"), + (b"uuarr", "\u{21C8}"), + (b"uuml", "\u{00FC}"), + (b"uwangle", "\u{29A7}"), + (b"vArr", "\u{21D5}"), + (b"vBar", "\u{2AE8}"), + (b"vBarv", "\u{2AE9}"), + (b"vDash", "\u{22A8}"), + (b"vangrt", "\u{299C}"), + (b"varepsilon", "\u{03F5}"), + (b"varkappa", "\u{03F0}"), + (b"varnothing", "\u{2205}"), + (b"varphi", "\u{03D5}"), + (b"varpi", "\u{03D6}"), + (b"varpropto", "\u{221D}"), + (b"varr", "\u{2195}"), + (b"varrho", "\u{03F1}"), + (b"varsigma", "\u{03C2}"), + (b"varsubsetneq", "\u{228A}\u{FE00}"), + (b"varsubsetneqq", "\u{2ACB}\u{FE00}"), + (b"varsupsetneq", "\u{228B}\u{FE00}"), + (b"varsupsetneqq", "\u{2ACC}\u{FE00}"), + (b"vartheta", "\u{03D1}"), + (b"vartriangleleft", "\u{22B2}"), + (b"vartriangleright", "\u{22B3}"), + (b"vcy", "\u{0432}"), + (b"vdash", "\u{22A2}"), + (b"vee", "\u{2228}"), + (b"veebar", "\u{22BB}"), + (b"veeeq", "\u{225A}"), + (b"vellip", "\u{22EE}"), + (b"verbar", "\u{007C}"), + (b"vert", "\u{007C}"), + (b"vfr", "\u{1D533}"), + (b"vltri", "\u{22B2}"), + (b"vnsub", "\u{2282}\u{20D2}"), + (b"vnsup", "\u{2283}\u{20D2}"), + (b"vopf", "\u{1D567}"), + (b"vprop", "\u{221D}"), + (b"vrtri", "\u{22B3}"), + (b"vscr", "\u{1D4CB}"), + (b"vsubnE", "\u{2ACB}\u{FE00}"), + (b"vsubne", "\u{228A}\u{FE00}"), + (b"vsupnE", "\u{2ACC}\u{FE00}"), + (b"vsupne", "\u{228B}\u{FE00}"), + (b"vzigzag", "\u{299A}"), + (b"wcirc", "\u{0175}"), + (b"wedbar", "\u{2A5F}"), + (b"wedge", "\u{2227}"), + (b"wedgeq", "\u{2259}"), + (b"weierp", "\u{2118}"), + (b"wfr", "\u{1D534}"), + (b"wopf", "\u{1D568}"), + (b"wp", "\u{2118}"), + (b"wr", "\u{2240}"), + (b"wreath", "\u{2240}"), + (b"wscr", "\u{1D4CC}"), + (b"xcap", "\u{22C2}"), + (b"xcirc", "\u{25EF}"), + (b"xcup", "\u{22C3}"), + (b"xdtri", "\u{25BD}"), + (b"xfr", "\u{1D535}"), + (b"xhArr", "\u{27FA}"), + (b"xharr", "\u{27F7}"), + (b"xi", "\u{03BE}"), + (b"xlArr", "\u{27F8}"), + (b"xlarr", "\u{27F5}"), + (b"xmap", "\u{27FC}"), + (b"xnis", "\u{22FB}"), + (b"xodot", "\u{2A00}"), + (b"xopf", "\u{1D569}"), + (b"xoplus", "\u{2A01}"), + (b"xotime", "\u{2A02}"), + (b"xrArr", "\u{27F9}"), + (b"xrarr", "\u{27F6}"), + (b"xscr", "\u{1D4CD}"), + (b"xsqcup", "\u{2A06}"), + (b"xuplus", "\u{2A04}"), + (b"xutri", "\u{25B3}"), + (b"xvee", "\u{22C1}"), + (b"xwedge", "\u{22C0}"), + (b"yacute", "\u{00FD}"), + (b"yacy", "\u{044F}"), + (b"ycirc", "\u{0177}"), + (b"ycy", "\u{044B}"), + (b"yen", "\u{00A5}"), + (b"yfr", "\u{1D536}"), + (b"yicy", "\u{0457}"), + (b"yopf", "\u{1D56A}"), + (b"yscr", "\u{1D4CE}"), + (b"yucy", "\u{044E}"), + (b"yuml", "\u{00FF}"), + (b"zacute", "\u{017A}"), + (b"zcaron", "\u{017E}"), + (b"zcy", "\u{0437}"), + (b"zdot", "\u{017C}"), + (b"zeetrf", "\u{2128}"), + (b"zeta", "\u{03B6}"), + (b"zfr", "\u{1D537}"), + (b"zhcy", "\u{0436}"), + (b"zigrarr", "\u{21DD}"), + (b"zopf", "\u{1D56B}"), + (b"zscr", "\u{1D4CF}"), + (b"zwj", "\u{200D}"), + (b"zwnj", "\u{200C}"), +]; + +pub(crate) fn get_entity(bytes: &[u8]) -> Option<&'static str> { + ENTITIES + .binary_search_by_key(&bytes, |&(key, _value)| key) + .ok() + .map(|i| ENTITIES[i].1) +} diff --git a/vendor/pulldown-cmark/src/escape.rs b/vendor/pulldown-cmark/src/escape.rs index 7b31cef614..af9066dc19 100644 --- a/vendor/pulldown-cmark/src/escape.rs +++ b/vendor/pulldown-cmark/src/escape.rs @@ -1,297 +1,356 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Utility functions for HTML escaping - -use std::io; -use std::str::from_utf8; - -use crate::html::StrWrite; - -#[rustfmt::skip] -static HREF_SAFE: [u8; 128] = [ - 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, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 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, 0, 0, 0, 0, 1, - 0, 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, 0, 0, 0, 0, 0, -]; - -static HEX_CHARS: &[u8] = b"0123456789ABCDEF"; -static AMP_ESCAPE: &str = "&"; -static SLASH_ESCAPE: &str = "'"; - -pub(crate) fn escape_href(mut w: W, s: &str) -> io::Result<()> -where - W: StrWrite, -{ - let bytes = s.as_bytes(); - let mut mark = 0; - for i in 0..bytes.len() { - let c = bytes[i]; - if c >= 0x80 || HREF_SAFE[c as usize] == 0 { - // character needing escape - - // write partial substring up to mark - if mark < i { - w.write_str(&s[mark..i])?; - } - match c { - b'&' => { - w.write_str(AMP_ESCAPE)?; - } - b'\'' => { - w.write_str(SLASH_ESCAPE)?; - } - _ => { - let mut buf = [0u8; 3]; - buf[0] = b'%'; - buf[1] = HEX_CHARS[((c as usize) >> 4) & 0xF]; - buf[2] = HEX_CHARS[(c as usize) & 0xF]; - let escaped = from_utf8(&buf).unwrap(); - w.write_str(escaped)?; - } - } - mark = i + 1; // all escaped characters are ASCII - } - } - w.write_str(&s[mark..]) -} - -const fn create_html_escape_table() -> [u8; 256] { - let mut table = [0; 256]; - table[b'"' as usize] = 1; - table[b'&' as usize] = 2; - table[b'<' as usize] = 3; - table[b'>' as usize] = 4; - table -} - -static HTML_ESCAPE_TABLE: [u8; 256] = create_html_escape_table(); - -static HTML_ESCAPES: [&'static str; 5] = ["", """, "&", "<", ">"]; - -/// Writes the given string to the Write sink, replacing special HTML bytes -/// (<, >, &, ") by escape sequences. -pub(crate) fn escape_html(w: W, s: &str) -> io::Result<()> { - #[cfg(all(target_arch = "x86_64", feature = "simd"))] - { - simd::escape_html(w, s) - } - #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] - { - escape_html_scalar(w, s) - } -} - -fn escape_html_scalar(mut w: W, s: &str) -> io::Result<()> { - let bytes = s.as_bytes(); - let mut mark = 0; - let mut i = 0; - while i < s.len() { - match bytes[i..] - .iter() - .position(|&c| HTML_ESCAPE_TABLE[c as usize] != 0) - { - Some(pos) => { - i += pos; - } - None => break, - } - let c = bytes[i]; - let escape = HTML_ESCAPE_TABLE[c as usize]; - let escape_seq = HTML_ESCAPES[escape as usize]; - w.write_str(&s[mark..i])?; - w.write_str(escape_seq)?; - i += 1; - mark = i; // all escaped characters are ASCII - } - w.write_str(&s[mark..]) -} - -#[cfg(all(target_arch = "x86_64", feature = "simd"))] -mod simd { - use crate::html::StrWrite; - use std::arch::x86_64::*; - use std::io; - use std::mem::size_of; - - const VECTOR_SIZE: usize = size_of::<__m128i>(); - - pub(crate) fn escape_html(mut w: W, s: &str) -> io::Result<()> { - // The SIMD accelerated code uses the PSHUFB instruction, which is part - // of the SSSE3 instruction set. Further, we can only use this code if - // the buffer is at least one VECTOR_SIZE in length to prevent reading - // out of bounds. If either of these conditions is not met, we fall back - // to scalar code. - if is_x86_feature_detected!("ssse3") && s.len() >= VECTOR_SIZE { - let bytes = s.as_bytes(); - let mut mark = 0; - - unsafe { - foreach_special_simd(bytes, 0, |i| { - let escape_ix = *bytes.get_unchecked(i) as usize; - let replacement = - super::HTML_ESCAPES[super::HTML_ESCAPE_TABLE[escape_ix] as usize]; - w.write_str(&s.get_unchecked(mark..i))?; - mark = i + 1; // all escaped characters are ASCII - w.write_str(replacement) - })?; - w.write_str(&s.get_unchecked(mark..)) - } - } else { - super::escape_html_scalar(w, s) - } - } - - /// Creates the lookup table for use in `compute_mask`. - const fn create_lookup() -> [u8; 16] { - let mut table = [0; 16]; - table[(b'<' & 0x0f) as usize] = b'<'; - table[(b'>' & 0x0f) as usize] = b'>'; - table[(b'&' & 0x0f) as usize] = b'&'; - table[(b'"' & 0x0f) as usize] = b'"'; - table[0] = 0b0111_1111; - table - } - - #[target_feature(enable = "ssse3")] - /// Computes a byte mask at given offset in the byte buffer. Its first 16 (least significant) - /// bits correspond to whether there is an HTML special byte (&, <, ", >) at the 16 bytes - /// `bytes[offset..]`. For example, the mask `(1 << 3)` states that there is an HTML byte - /// at `offset + 3`. It is only safe to call this function when - /// `bytes.len() >= offset + VECTOR_SIZE`. - unsafe fn compute_mask(bytes: &[u8], offset: usize) -> i32 { - debug_assert!(bytes.len() >= offset + VECTOR_SIZE); - - let table = create_lookup(); - let lookup = _mm_loadu_si128(table.as_ptr() as *const __m128i); - let raw_ptr = bytes.as_ptr().offset(offset as isize) as *const __m128i; - - // Load the vector from memory. - let vector = _mm_loadu_si128(raw_ptr); - // We take the least significant 4 bits of every byte and use them as indices - // to map into the lookup vector. - // Note that shuffle maps bytes with their most significant bit set to lookup[0]. - // Bytes that share their lower nibble with an HTML special byte get mapped to that - // corresponding special byte. Note that all HTML special bytes have distinct lower - // nibbles. Other bytes either get mapped to 0 or 127. - let expected = _mm_shuffle_epi8(lookup, vector); - // We compare the original vector to the mapped output. Bytes that shared a lower - // nibble with an HTML special byte match *only* if they are that special byte. Bytes - // that have either a 0 lower nibble or their most significant bit set were mapped to - // 127 and will hence never match. All other bytes have non-zero lower nibbles but - // were mapped to 0 and will therefore also not match. - let matches = _mm_cmpeq_epi8(expected, vector); - - // Translate matches to a bitmask, where every 1 corresponds to a HTML special character - // and a 0 is a non-HTML byte. - _mm_movemask_epi8(matches) - } - - /// Calls the given function with the index of every byte in the given byteslice - /// that is either ", &, <, or > and for no other byte. - /// Make sure to only call this when `bytes.len() >= 16`, undefined behaviour may - /// occur otherwise. - #[target_feature(enable = "ssse3")] - unsafe fn foreach_special_simd( - bytes: &[u8], - mut offset: usize, - mut callback: F, - ) -> io::Result<()> - where - F: FnMut(usize) -> io::Result<()>, - { - // The strategy here is to walk the byte buffer in chunks of VECTOR_SIZE (16) - // bytes at a time starting at the given offset. For each chunk, we compute a - // a bitmask indicating whether the corresponding byte is a HTML special byte. - // We then iterate over all the 1 bits in this mask and call the callback function - // with the corresponding index in the buffer. - // When the number of HTML special bytes in the buffer is relatively low, this - // allows us to quickly go through the buffer without a lookup and for every - // single byte. - - debug_assert!(bytes.len() >= VECTOR_SIZE); - let upperbound = bytes.len() - VECTOR_SIZE; - while offset < upperbound { - let mut mask = compute_mask(bytes, offset); - while mask != 0 { - let ix = mask.trailing_zeros(); - callback(offset + ix as usize)?; - mask ^= mask & -mask; - } - offset += VECTOR_SIZE; - } - - // Final iteration. We align the read with the end of the slice and - // shift off the bytes at start we have already scanned. - let mut mask = compute_mask(bytes, upperbound); - mask >>= offset - upperbound; - while mask != 0 { - let ix = mask.trailing_zeros(); - callback(offset + ix as usize)?; - mask ^= mask & -mask; - } - Ok(()) - } - - #[cfg(test)] - mod html_scan_tests { - #[test] - fn multichunk() { - let mut vec = Vec::new(); - unsafe { - super::foreach_special_simd("&aXaaaa.a'aa9a<>aab&".as_bytes(), 0, |ix| { - Ok(vec.push(ix)) - }) - .unwrap(); - } - assert_eq!(vec, vec![0, 14, 15, 19]); - } - - // only match these bytes, and when we match them, match them VECTOR_SIZE times - #[test] - fn only_right_bytes_matched() { - for b in 0..255u8 { - let right_byte = b == b'&' || b == b'<' || b == b'>' || b == b'"'; - let vek = vec![b; super::VECTOR_SIZE]; - let mut match_count = 0; - unsafe { - super::foreach_special_simd(&vek, 0, |_| { - match_count += 1; - Ok(()) - }) - .unwrap(); - } - assert!((match_count > 0) == (match_count == super::VECTOR_SIZE)); - assert_eq!( - (match_count == super::VECTOR_SIZE), - right_byte, - "match_count: {}, byte: {:?}", - match_count, - b as char - ); - } - } - } -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Utility functions for HTML escaping. Only useful when building your own +//! HTML renderer. + +use std::fmt::{Arguments, Write as FmtWrite}; +use std::io::{self, ErrorKind, Write}; +use std::str::from_utf8; + +#[rustfmt::skip] +static HREF_SAFE: [u8; 128] = [ + 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, 1, 0, 1, 1, 1, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 1, 0, 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, 0, 0, 0, 0, 1, + 0, 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, 0, 0, 0, 0, 0, +]; + +static HEX_CHARS: &[u8] = b"0123456789ABCDEF"; +static AMP_ESCAPE: &str = "&"; +static SLASH_ESCAPE: &str = "'"; + +/// This wrapper exists because we can't have both a blanket implementation +/// for all types implementing `Write` and types of the for `&mut W` where +/// `W: StrWrite`. Since we need the latter a lot, we choose to wrap +/// `Write` types. +pub struct WriteWrapper(pub W); + +/// Trait that allows writing string slices. This is basically an extension +/// of `std::io::Write` in order to include `String`. +pub trait StrWrite { + fn write_str(&mut self, s: &str) -> io::Result<()>; + + fn write_fmt(&mut self, args: Arguments) -> io::Result<()>; +} + +impl StrWrite for WriteWrapper +where + W: Write, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.0.write_all(s.as_bytes()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + self.0.write_fmt(args) + } +} + +impl<'w> StrWrite for String { + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + self.push_str(s); + Ok(()) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + // FIXME: translate fmt error to io error? + FmtWrite::write_fmt(self, args).map_err(|_| ErrorKind::Other.into()) + } +} + +impl StrWrite for &'_ mut W +where + W: StrWrite, +{ + #[inline] + fn write_str(&mut self, s: &str) -> io::Result<()> { + (**self).write_str(s) + } + + #[inline] + fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { + (**self).write_fmt(args) + } +} + +/// Writes an href to the buffer, escaping href unsafe bytes. +pub fn escape_href(mut w: W, s: &str) -> io::Result<()> +where + W: StrWrite, +{ + let bytes = s.as_bytes(); + let mut mark = 0; + for i in 0..bytes.len() { + let c = bytes[i]; + if c >= 0x80 || HREF_SAFE[c as usize] == 0 { + // character needing escape + + // write partial substring up to mark + if mark < i { + w.write_str(&s[mark..i])?; + } + match c { + b'&' => { + w.write_str(AMP_ESCAPE)?; + } + b'\'' => { + w.write_str(SLASH_ESCAPE)?; + } + _ => { + let mut buf = [0u8; 3]; + buf[0] = b'%'; + buf[1] = HEX_CHARS[((c as usize) >> 4) & 0xF]; + buf[2] = HEX_CHARS[(c as usize) & 0xF]; + let escaped = from_utf8(&buf).unwrap(); + w.write_str(escaped)?; + } + } + mark = i + 1; // all escaped characters are ASCII + } + } + w.write_str(&s[mark..]) +} + +const fn create_html_escape_table() -> [u8; 256] { + let mut table = [0; 256]; + table[b'"' as usize] = 1; + table[b'&' as usize] = 2; + table[b'<' as usize] = 3; + table[b'>' as usize] = 4; + table +} + +static HTML_ESCAPE_TABLE: [u8; 256] = create_html_escape_table(); + +static HTML_ESCAPES: [&'static str; 5] = ["", """, "&", "<", ">"]; + +/// Writes the given string to the Write sink, replacing special HTML bytes +/// (<, >, &, ") by escape sequences. +pub fn escape_html(w: W, s: &str) -> io::Result<()> { + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + simd::escape_html(w, s) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + escape_html_scalar(w, s) + } +} + +fn escape_html_scalar(mut w: W, s: &str) -> io::Result<()> { + let bytes = s.as_bytes(); + let mut mark = 0; + let mut i = 0; + while i < s.len() { + match bytes[i..] + .iter() + .position(|&c| HTML_ESCAPE_TABLE[c as usize] != 0) + { + Some(pos) => { + i += pos; + } + None => break, + } + let c = bytes[i]; + let escape = HTML_ESCAPE_TABLE[c as usize]; + let escape_seq = HTML_ESCAPES[escape as usize]; + w.write_str(&s[mark..i])?; + w.write_str(escape_seq)?; + i += 1; + mark = i; // all escaped characters are ASCII + } + w.write_str(&s[mark..]) +} + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd { + use super::StrWrite; + use std::arch::x86_64::*; + use std::io; + use std::mem::size_of; + + const VECTOR_SIZE: usize = size_of::<__m128i>(); + + pub(crate) fn escape_html(mut w: W, s: &str) -> io::Result<()> { + // The SIMD accelerated code uses the PSHUFB instruction, which is part + // of the SSSE3 instruction set. Further, we can only use this code if + // the buffer is at least one VECTOR_SIZE in length to prevent reading + // out of bounds. If either of these conditions is not met, we fall back + // to scalar code. + if is_x86_feature_detected!("ssse3") && s.len() >= VECTOR_SIZE { + let bytes = s.as_bytes(); + let mut mark = 0; + + unsafe { + foreach_special_simd(bytes, 0, |i| { + let escape_ix = *bytes.get_unchecked(i) as usize; + let replacement = + super::HTML_ESCAPES[super::HTML_ESCAPE_TABLE[escape_ix] as usize]; + w.write_str(&s.get_unchecked(mark..i))?; + mark = i + 1; // all escaped characters are ASCII + w.write_str(replacement) + })?; + w.write_str(&s.get_unchecked(mark..)) + } + } else { + super::escape_html_scalar(w, s) + } + } + + /// Creates the lookup table for use in `compute_mask`. + const fn create_lookup() -> [u8; 16] { + let mut table = [0; 16]; + table[(b'<' & 0x0f) as usize] = b'<'; + table[(b'>' & 0x0f) as usize] = b'>'; + table[(b'&' & 0x0f) as usize] = b'&'; + table[(b'"' & 0x0f) as usize] = b'"'; + table[0] = 0b0111_1111; + table + } + + #[target_feature(enable = "ssse3")] + /// Computes a byte mask at given offset in the byte buffer. Its first 16 (least significant) + /// bits correspond to whether there is an HTML special byte (&, <, ", >) at the 16 bytes + /// `bytes[offset..]`. For example, the mask `(1 << 3)` states that there is an HTML byte + /// at `offset + 3`. It is only safe to call this function when + /// `bytes.len() >= offset + VECTOR_SIZE`. + unsafe fn compute_mask(bytes: &[u8], offset: usize) -> i32 { + debug_assert!(bytes.len() >= offset + VECTOR_SIZE); + + let table = create_lookup(); + let lookup = _mm_loadu_si128(table.as_ptr() as *const __m128i); + let raw_ptr = bytes.as_ptr().offset(offset as isize) as *const __m128i; + + // Load the vector from memory. + let vector = _mm_loadu_si128(raw_ptr); + // We take the least significant 4 bits of every byte and use them as indices + // to map into the lookup vector. + // Note that shuffle maps bytes with their most significant bit set to lookup[0]. + // Bytes that share their lower nibble with an HTML special byte get mapped to that + // corresponding special byte. Note that all HTML special bytes have distinct lower + // nibbles. Other bytes either get mapped to 0 or 127. + let expected = _mm_shuffle_epi8(lookup, vector); + // We compare the original vector to the mapped output. Bytes that shared a lower + // nibble with an HTML special byte match *only* if they are that special byte. Bytes + // that have either a 0 lower nibble or their most significant bit set were mapped to + // 127 and will hence never match. All other bytes have non-zero lower nibbles but + // were mapped to 0 and will therefore also not match. + let matches = _mm_cmpeq_epi8(expected, vector); + + // Translate matches to a bitmask, where every 1 corresponds to a HTML special character + // and a 0 is a non-HTML byte. + _mm_movemask_epi8(matches) + } + + /// Calls the given function with the index of every byte in the given byteslice + /// that is either ", &, <, or > and for no other byte. + /// Make sure to only call this when `bytes.len() >= 16`, undefined behaviour may + /// occur otherwise. + #[target_feature(enable = "ssse3")] + unsafe fn foreach_special_simd( + bytes: &[u8], + mut offset: usize, + mut callback: F, + ) -> io::Result<()> + where + F: FnMut(usize) -> io::Result<()>, + { + // The strategy here is to walk the byte buffer in chunks of VECTOR_SIZE (16) + // bytes at a time starting at the given offset. For each chunk, we compute a + // a bitmask indicating whether the corresponding byte is a HTML special byte. + // We then iterate over all the 1 bits in this mask and call the callback function + // with the corresponding index in the buffer. + // When the number of HTML special bytes in the buffer is relatively low, this + // allows us to quickly go through the buffer without a lookup and for every + // single byte. + + debug_assert!(bytes.len() >= VECTOR_SIZE); + let upperbound = bytes.len() - VECTOR_SIZE; + while offset < upperbound { + let mut mask = compute_mask(bytes, offset); + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + offset += VECTOR_SIZE; + } + + // Final iteration. We align the read with the end of the slice and + // shift off the bytes at start we have already scanned. + let mut mask = compute_mask(bytes, upperbound); + mask >>= offset - upperbound; + while mask != 0 { + let ix = mask.trailing_zeros(); + callback(offset + ix as usize)?; + mask ^= mask & -mask; + } + Ok(()) + } + + #[cfg(test)] + mod html_scan_tests { + #[test] + fn multichunk() { + let mut vec = Vec::new(); + unsafe { + super::foreach_special_simd("&aXaaaa.a'aa9a<>aab&".as_bytes(), 0, |ix| { + Ok(vec.push(ix)) + }) + .unwrap(); + } + assert_eq!(vec, vec![0, 14, 15, 19]); + } + + // only match these bytes, and when we match them, match them VECTOR_SIZE times + #[test] + fn only_right_bytes_matched() { + for b in 0..255u8 { + let right_byte = b == b'&' || b == b'<' || b == b'>' || b == b'"'; + let vek = vec![b; super::VECTOR_SIZE]; + let mut match_count = 0; + unsafe { + super::foreach_special_simd(&vek, 0, |_| { + match_count += 1; + Ok(()) + }) + .unwrap(); + } + assert!((match_count > 0) == (match_count == super::VECTOR_SIZE)); + assert_eq!( + (match_count == super::VECTOR_SIZE), + right_byte, + "match_count: {}, byte: {:?}", + match_count, + b as char + ); + } + } + } +} diff --git a/vendor/pulldown-cmark/src/html.rs b/vendor/pulldown-cmark/src/html.rs index 06e5dc68b6..7b8b630896 100644 --- a/vendor/pulldown-cmark/src/html.rs +++ b/vendor/pulldown-cmark/src/html.rs @@ -1,520 +1,461 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! HTML renderer that takes an iterator of events as input. - -use std::collections::HashMap; -use std::fmt::{Arguments, Write as FmtWrite}; -use std::io::{self, ErrorKind, Write}; - -use crate::escape::{escape_href, escape_html}; -use crate::parse::Event::*; -use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, Tag}; -use crate::strings::CowStr; - -enum TableState { - Head, - Body, -} - -/// This wrapper exists because we can't have both a blanket implementation -/// for all types implementing `Write` and types of the for `&mut W` where -/// `W: StrWrite`. Since we need the latter a lot, we choose to wrap -/// `Write` types. -struct WriteWrapper(W); - -/// Trait that allows writing string slices. This is basically an extension -/// of `std::io::Write` in order to include `String`. -pub(crate) trait StrWrite { - fn write_str(&mut self, s: &str) -> io::Result<()>; - - fn write_fmt(&mut self, args: Arguments) -> io::Result<()>; -} - -impl StrWrite for WriteWrapper -where - W: Write, -{ - #[inline] - fn write_str(&mut self, s: &str) -> io::Result<()> { - self.0.write_all(s.as_bytes()) - } - - #[inline] - fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { - self.0.write_fmt(args) - } -} - -impl<'w> StrWrite for String { - #[inline] - fn write_str(&mut self, s: &str) -> io::Result<()> { - self.push_str(s); - Ok(()) - } - - #[inline] - fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { - // FIXME: translate fmt error to io error? - FmtWrite::write_fmt(self, args).map_err(|_| ErrorKind::Other.into()) - } -} - -impl StrWrite for &'_ mut W -where - W: StrWrite, -{ - #[inline] - fn write_str(&mut self, s: &str) -> io::Result<()> { - (**self).write_str(s) - } - - #[inline] - fn write_fmt(&mut self, args: Arguments) -> io::Result<()> { - (**self).write_fmt(args) - } -} - -struct HtmlWriter<'a, I, W> { - /// Iterator supplying events. - iter: I, - - /// Writer to write to. - writer: W, - - /// Whether or not the last write wrote a newline. - end_newline: bool, - - table_state: TableState, - table_alignments: Vec, - table_cell_index: usize, - numbers: HashMap, usize>, -} - -impl<'a, I, W> HtmlWriter<'a, I, W> -where - I: Iterator>, - W: StrWrite, -{ - fn new(iter: I, writer: W) -> Self { - Self { - iter, - writer, - end_newline: true, - table_state: TableState::Head, - table_alignments: vec![], - table_cell_index: 0, - numbers: HashMap::new(), - } - } - - /// Writes a new line. - fn write_newline(&mut self) -> io::Result<()> { - self.end_newline = true; - self.writer.write_str("\n") - } - - /// Writes a buffer, and tracks whether or not a newline was written. - #[inline] - fn write(&mut self, s: &str) -> io::Result<()> { - self.writer.write_str(s)?; - - if !s.is_empty() { - self.end_newline = s.ends_with('\n'); - } - Ok(()) - } - - pub fn run(mut self) -> io::Result<()> { - while let Some(event) = self.iter.next() { - match event { - Start(tag) => { - self.start_tag(tag)?; - } - End(tag) => { - self.end_tag(tag)?; - } - Text(text) => { - escape_html(&mut self.writer, &text)?; - self.end_newline = text.ends_with('\n'); - } - Code(text) => { - self.write("")?; - escape_html(&mut self.writer, &text)?; - self.write("")?; - } - Html(html) => { - self.write(&html)?; - } - SoftBreak => { - self.write_newline()?; - } - HardBreak => { - self.write("
    \n")?; - } - Rule => { - if self.end_newline { - self.write("
    \n")?; - } else { - self.write("\n
    \n")?; - } - } - FootnoteReference(name) => { - let len = self.numbers.len() + 1; - self.write("")?; - let number = *self.numbers.entry(name).or_insert(len); - write!(&mut self.writer, "{}", number)?; - self.write("")?; - } - TaskListMarker(true) => { - self.write("\n")?; - } - TaskListMarker(false) => { - self.write("\n")?; - } - } - } - Ok(()) - } - - /// Writes the start of an HTML tag. - fn start_tag(&mut self, tag: Tag<'a>) -> io::Result<()> { - match tag { - Tag::Paragraph => { - if self.end_newline { - self.write("

    ") - } else { - self.write("\n

    ") - } - } - Tag::Heading(level) => { - if self.end_newline { - self.end_newline = false; - write!(&mut self.writer, "", level) - } else { - write!(&mut self.writer, "\n", level) - } - } - Tag::Table(alignments) => { - self.table_alignments = alignments; - self.write("") - } - Tag::TableHead => { - self.table_state = TableState::Head; - self.table_cell_index = 0; - self.write("") - } - Tag::TableRow => { - self.table_cell_index = 0; - self.write("") - } - Tag::TableCell => { - match self.table_state { - TableState::Head => { - self.write(" { - self.write(" self.write(" align=\"left\">"), - Some(&Alignment::Center) => self.write(" align=\"center\">"), - Some(&Alignment::Right) => self.write(" align=\"right\">"), - _ => self.write(">"), - } - } - Tag::BlockQuote => { - if self.end_newline { - self.write("
    \n") - } else { - self.write("\n
    \n") - } - } - Tag::CodeBlock(info) => { - if !self.end_newline { - self.write_newline()?; - } - match info { - CodeBlockKind::Fenced(info) => { - let lang = info.split(' ').next().unwrap(); - if lang.is_empty() { - self.write("
    ")
    -                        } else {
    -                            self.write("
    ")
    -                        }
    -                    }
    -                    CodeBlockKind::Indented => self.write("
    "),
    -                }
    -            }
    -            Tag::List(Some(1)) => {
    -                if self.end_newline {
    -                    self.write("
      \n") - } else { - self.write("\n
        \n") - } - } - Tag::List(Some(start)) => { - if self.end_newline { - self.write("
          \n") - } - Tag::List(None) => { - if self.end_newline { - self.write("
    \n")?; - } - Tag::TableHead => { - self.write("\n")?; - self.table_state = TableState::Body; - } - Tag::TableRow => { - self.write("\n")?; - } - Tag::TableCell => { - match self.table_state { - TableState::Head => { - self.write("")?; - } - TableState::Body => { - self.write("")?; - } - } - self.table_cell_index += 1; - } - Tag::BlockQuote => { - self.write("

    \n")?; - } - Tag::CodeBlock(_) => { - self.write("\n")?; - } - Tag::List(Some(_)) => { - self.write("\n")?; - } - Tag::List(None) => { - self.write("\n")?; - } - Tag::Item => { - self.write("\n")?; - } - Tag::Emphasis => { - self.write("")?; - } - Tag::Strong => { - self.write("")?; - } - Tag::Strikethrough => { - self.write("")?; - } - Tag::Link(_, _, _) => { - self.write("")?; - } - Tag::Image(_, _, _) => (), // shouldn't happen, handled in start - Tag::FootnoteDefinition(_) => { - self.write("\n")?; - } - } - Ok(()) - } - - // run raw text, consuming end tag - fn raw_text(&mut self) -> io::Result<()> { - let mut nest = 0; - while let Some(event) = self.iter.next() { - match event { - Start(_) => nest += 1, - End(_) => { - if nest == 0 { - break; - } - nest -= 1; - } - Html(text) | Code(text) | Text(text) => { - escape_html(&mut self.writer, &text)?; - self.end_newline = text.ends_with('\n'); - } - SoftBreak | HardBreak | Rule => { - self.write(" ")?; - } - FootnoteReference(name) => { - let len = self.numbers.len() + 1; - let number = *self.numbers.entry(name).or_insert(len); - write!(&mut self.writer, "[{}]", number)?; - } - TaskListMarker(true) => self.write("[x]")?, - TaskListMarker(false) => self.write("[ ]")?, - } - } - Ok(()) - } -} - -/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and -/// push it to a `String`. -/// -/// # Examples -/// -/// ``` -/// use pulldown_cmark::{html, Parser}; -/// -/// let markdown_str = r#" -/// hello -/// ===== -/// -/// * alpha -/// * beta -/// "#; -/// let parser = Parser::new(markdown_str); -/// -/// let mut html_buf = String::new(); -/// html::push_html(&mut html_buf, parser); -/// -/// assert_eq!(html_buf, r#"

    hello

    -///
      -///
    • alpha
    • -///
    • beta
    • -///
    -/// "#); -/// ``` -pub fn push_html<'a, I>(s: &mut String, iter: I) -where - I: Iterator>, -{ - HtmlWriter::new(iter, s).run().unwrap(); -} - -/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and -/// write it out to a writable stream. -/// -/// **Note**: using this function with an unbuffered writer like a file or socket -/// will result in poor performance. Wrap these in a -/// [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html) to -/// prevent unnecessary slowdowns. -/// -/// # Examples -/// -/// ``` -/// use pulldown_cmark::{html, Parser}; -/// use std::io::Cursor; -/// -/// let markdown_str = r#" -/// hello -/// ===== -/// -/// * alpha -/// * beta -/// "#; -/// let mut bytes = Vec::new(); -/// let parser = Parser::new(markdown_str); -/// -/// html::write_html(Cursor::new(&mut bytes), parser); -/// -/// assert_eq!(&String::from_utf8_lossy(&bytes)[..], r#"

    hello

    -///
      -///
    • alpha
    • -///
    • beta
    • -///
    -/// "#); -/// ``` -pub fn write_html<'a, I, W>(writer: W, iter: I) -> io::Result<()> -where - I: Iterator>, - W: Write, -{ - HtmlWriter::new(iter, WriteWrapper(writer)).run() -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! HTML renderer that takes an iterator of events as input. + +use std::collections::HashMap; +use std::io::{self, Write}; + +use crate::escape::{escape_href, escape_html, StrWrite, WriteWrapper}; +use crate::parse::Event::*; +use crate::parse::{Alignment, CodeBlockKind, Event, LinkType, Tag}; +use crate::strings::CowStr; + +enum TableState { + Head, + Body, +} + +struct HtmlWriter<'a, I, W> { + /// Iterator supplying events. + iter: I, + + /// Writer to write to. + writer: W, + + /// Whether or not the last write wrote a newline. + end_newline: bool, + + table_state: TableState, + table_alignments: Vec, + table_cell_index: usize, + numbers: HashMap, usize>, +} + +impl<'a, I, W> HtmlWriter<'a, I, W> +where + I: Iterator>, + W: StrWrite, +{ + fn new(iter: I, writer: W) -> Self { + Self { + iter, + writer, + end_newline: true, + table_state: TableState::Head, + table_alignments: vec![], + table_cell_index: 0, + numbers: HashMap::new(), + } + } + + /// Writes a new line. + fn write_newline(&mut self) -> io::Result<()> { + self.end_newline = true; + self.writer.write_str("\n") + } + + /// Writes a buffer, and tracks whether or not a newline was written. + #[inline] + fn write(&mut self, s: &str) -> io::Result<()> { + self.writer.write_str(s)?; + + if !s.is_empty() { + self.end_newline = s.ends_with('\n'); + } + Ok(()) + } + + pub fn run(mut self) -> io::Result<()> { + while let Some(event) = self.iter.next() { + match event { + Start(tag) => { + self.start_tag(tag)?; + } + End(tag) => { + self.end_tag(tag)?; + } + Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + Code(text) => { + self.write("")?; + escape_html(&mut self.writer, &text)?; + self.write("")?; + } + Html(html) => { + self.write(&html)?; + } + SoftBreak => { + self.write_newline()?; + } + HardBreak => { + self.write("
    \n")?; + } + Rule => { + if self.end_newline { + self.write("
    \n")?; + } else { + self.write("\n
    \n")?; + } + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + self.write("")?; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "{}", number)?; + self.write("")?; + } + TaskListMarker(true) => { + self.write("\n")?; + } + TaskListMarker(false) => { + self.write("\n")?; + } + } + } + Ok(()) + } + + /// Writes the start of an HTML tag. + fn start_tag(&mut self, tag: Tag<'a>) -> io::Result<()> { + match tag { + Tag::Paragraph => { + if self.end_newline { + self.write("

    ") + } else { + self.write("\n

    ") + } + } + Tag::Heading(level) => { + if self.end_newline { + self.end_newline = false; + write!(&mut self.writer, "", level) + } else { + write!(&mut self.writer, "\n", level) + } + } + Tag::Table(alignments) => { + self.table_alignments = alignments; + self.write("") + } + Tag::TableHead => { + self.table_state = TableState::Head; + self.table_cell_index = 0; + self.write("") + } + Tag::TableRow => { + self.table_cell_index = 0; + self.write("") + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write(" { + self.write(" self.write(" align=\"left\">"), + Some(&Alignment::Center) => self.write(" align=\"center\">"), + Some(&Alignment::Right) => self.write(" align=\"right\">"), + _ => self.write(">"), + } + } + Tag::BlockQuote => { + if self.end_newline { + self.write("
    \n") + } else { + self.write("\n
    \n") + } + } + Tag::CodeBlock(info) => { + if !self.end_newline { + self.write_newline()?; + } + match info { + CodeBlockKind::Fenced(info) => { + let lang = info.split(' ').next().unwrap(); + if lang.is_empty() { + self.write("
    ")
    +                        } else {
    +                            self.write("
    ")
    +                        }
    +                    }
    +                    CodeBlockKind::Indented => self.write("
    "),
    +                }
    +            }
    +            Tag::List(Some(1)) => {
    +                if self.end_newline {
    +                    self.write("
      \n") + } else { + self.write("\n
        \n") + } + } + Tag::List(Some(start)) => { + if self.end_newline { + self.write("
          \n") + } + Tag::List(None) => { + if self.end_newline { + self.write("
    \n")?; + } + Tag::TableHead => { + self.write("\n")?; + self.table_state = TableState::Body; + } + Tag::TableRow => { + self.write("\n")?; + } + Tag::TableCell => { + match self.table_state { + TableState::Head => { + self.write("")?; + } + TableState::Body => { + self.write("")?; + } + } + self.table_cell_index += 1; + } + Tag::BlockQuote => { + self.write("\n")?; + } + Tag::CodeBlock(_) => { + self.write("\n")?; + } + Tag::List(Some(_)) => { + self.write("\n")?; + } + Tag::List(None) => { + self.write("\n")?; + } + Tag::Item => { + self.write("\n")?; + } + Tag::Emphasis => { + self.write("")?; + } + Tag::Strong => { + self.write("")?; + } + Tag::Strikethrough => { + self.write("")?; + } + Tag::Link(_, _, _) => { + self.write("")?; + } + Tag::Image(_, _, _) => (), // shouldn't happen, handled in start + Tag::FootnoteDefinition(_) => { + self.write("\n")?; + } + } + Ok(()) + } + + // run raw text, consuming end tag + fn raw_text(&mut self) -> io::Result<()> { + let mut nest = 0; + while let Some(event) = self.iter.next() { + match event { + Start(_) => nest += 1, + End(_) => { + if nest == 0 { + break; + } + nest -= 1; + } + Html(text) | Code(text) | Text(text) => { + escape_html(&mut self.writer, &text)?; + self.end_newline = text.ends_with('\n'); + } + SoftBreak | HardBreak | Rule => { + self.write(" ")?; + } + FootnoteReference(name) => { + let len = self.numbers.len() + 1; + let number = *self.numbers.entry(name).or_insert(len); + write!(&mut self.writer, "[{}]", number)?; + } + TaskListMarker(true) => self.write("[x]")?, + TaskListMarker(false) => self.write("[ ]")?, + } + } + Ok(()) + } +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// push it to a `String`. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let parser = Parser::new(markdown_str); +/// +/// let mut html_buf = String::new(); +/// html::push_html(&mut html_buf, parser); +/// +/// assert_eq!(html_buf, r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn push_html<'a, I>(s: &mut String, iter: I) +where + I: Iterator>, +{ + HtmlWriter::new(iter, s).run().unwrap(); +} + +/// Iterate over an `Iterator` of `Event`s, generate HTML for each `Event`, and +/// write it out to a writable stream. +/// +/// **Note**: using this function with an unbuffered writer like a file or socket +/// will result in poor performance. Wrap these in a +/// [`BufWriter`](https://doc.rust-lang.org/std/io/struct.BufWriter.html) to +/// prevent unnecessary slowdowns. +/// +/// # Examples +/// +/// ``` +/// use pulldown_cmark::{html, Parser}; +/// use std::io::Cursor; +/// +/// let markdown_str = r#" +/// hello +/// ===== +/// +/// * alpha +/// * beta +/// "#; +/// let mut bytes = Vec::new(); +/// let parser = Parser::new(markdown_str); +/// +/// html::write_html(Cursor::new(&mut bytes), parser); +/// +/// assert_eq!(&String::from_utf8_lossy(&bytes)[..], r#"

    hello

    +///
      +///
    • alpha
    • +///
    • beta
    • +///
    +/// "#); +/// ``` +pub fn write_html<'a, I, W>(writer: W, iter: I) -> io::Result<()> +where + I: Iterator>, + W: Write, +{ + HtmlWriter::new(iter, WriteWrapper(writer)).run() +} diff --git a/vendor/pulldown-cmark/src/lib.rs b/vendor/pulldown-cmark/src/lib.rs index f3f16b3dab..e3618573a4 100644 --- a/vendor/pulldown-cmark/src/lib.rs +++ b/vendor/pulldown-cmark/src/lib.rs @@ -1,76 +1,76 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Pull parser for [CommonMark](https://commonmark.org). This crate provides a [Parser](struct.Parser.html) struct -//! which is an iterator over [Event](enum.Event.html)s. This iterator can be used -//! directly, or to output HTML using the [HTML module](html/index.html). -//! -//! By default, only CommonMark features are enabled. To use extensions like tables, -//! footnotes or task lists, enable them by setting the corresponding flags in the -//! [Options](struct.Options.html) struct. -//! -//! # Example -//! ```rust -//! use pulldown_cmark::{Parser, Options, html}; -//! -//! let markdown_input = "Hello world, this is a ~~complicated~~ *very simple* example."; -//! -//! // Set up options and parser. Strikethroughs are not part of the CommonMark standard -//! // and we therefore must enable it explicitly. -//! let mut options = Options::empty(); -//! options.insert(Options::ENABLE_STRIKETHROUGH); -//! let parser = Parser::new_ext(markdown_input, options); -//! -//! // Write to String buffer. -//! let mut html_output = String::new(); -//! html::push_html(&mut html_output, parser); -//! -//! // Check that the output is what we expected. -//! let expected_html = "

    Hello world, this is a complicated very simple example.

    \n"; -//! assert_eq!(expected_html, &html_output); -//! ``` - -// When compiled for the rustc compiler itself we want to make sure that this is -// an unstable crate. -#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] -#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] - -pub mod html; - -#[macro_use] -extern crate bitflags; -extern crate unicase; - -mod entities; -mod escape; -mod linklabel; -mod parse; -mod puncttable; -mod scanners; -mod strings; -mod tree; - -#[cfg(all(target_arch = "x86_64", feature = "simd"))] -mod simd; - -pub use crate::parse::{ - Alignment, CodeBlockKind, Event, LinkType, OffsetIter, Options, Parser, Tag, -}; -pub use crate::strings::{CowStr, InlineStr}; +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Pull parser for [CommonMark](https://commonmark.org). This crate provides a [Parser](struct.Parser.html) struct +//! which is an iterator over [Event](enum.Event.html)s. This iterator can be used +//! directly, or to output HTML using the [HTML module](html/index.html). +//! +//! By default, only CommonMark features are enabled. To use extensions like tables, +//! footnotes or task lists, enable them by setting the corresponding flags in the +//! [Options](struct.Options.html) struct. +//! +//! # Example +//! ```rust +//! use pulldown_cmark::{Parser, Options, html}; +//! +//! let markdown_input = "Hello world, this is a ~~complicated~~ *very simple* example."; +//! +//! // Set up options and parser. Strikethroughs are not part of the CommonMark standard +//! // and we therefore must enable it explicitly. +//! let mut options = Options::empty(); +//! options.insert(Options::ENABLE_STRIKETHROUGH); +//! let parser = Parser::new_ext(markdown_input, options); +//! +//! // Write to String buffer. +//! let mut html_output = String::new(); +//! html::push_html(&mut html_output, parser); +//! +//! // Check that the output is what we expected. +//! let expected_html = "

    Hello world, this is a complicated very simple example.

    \n"; +//! assert_eq!(expected_html, &html_output); +//! ``` + +// When compiled for the rustc compiler itself we want to make sure that this is +// an unstable crate. +#![cfg_attr(rustbuild, feature(staged_api, rustc_private))] +#![cfg_attr(rustbuild, unstable(feature = "rustc_private", issue = "27812"))] + +pub mod html; + +#[macro_use] +extern crate bitflags; +extern crate unicase; + +mod entities; +pub mod escape; +mod linklabel; +mod parse; +mod puncttable; +mod scanners; +mod strings; +mod tree; + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +mod simd; + +pub use crate::parse::{ + Alignment, BrokenLink, CodeBlockKind, Event, LinkType, OffsetIter, Options, Parser, Tag, +}; +pub use crate::strings::{CowStr, InlineStr}; diff --git a/vendor/pulldown-cmark/src/linklabel.rs b/vendor/pulldown-cmark/src/linklabel.rs index cfb9c2706b..846210f040 100644 --- a/vendor/pulldown-cmark/src/linklabel.rs +++ b/vendor/pulldown-cmark/src/linklabel.rs @@ -1,135 +1,135 @@ -// Copyright 2018 Google LLC -// -// 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. - -//! Link label parsing and matching. - -use unicase::UniCase; - -use crate::scanners::{is_ascii_whitespace, scan_eol}; -use crate::strings::CowStr; - -pub enum ReferenceLabel<'a> { - Link(CowStr<'a>), - Footnote(CowStr<'a>), -} - -pub type LinkLabel<'a> = UniCase>; - -/// Assumes the opening bracket has already been scanned. -/// The line break handler determines what happens when a linebreak -/// is found. It is passed the bytes following the line break and -/// either returns `Some(k)`, where `k` is the number of bytes to skip, -/// or `None` to abort parsing the label. -/// Returns the number of bytes read (including closing bracket) and label on success. -pub(crate) fn scan_link_label_rest<'t>( - text: &'t str, - linebreak_handler: &dyn Fn(&[u8]) -> Option, -) -> Option<(usize, CowStr<'t>)> { - let bytes = text.as_bytes(); - let mut ix = 0; - let mut only_white_space = true; - let mut codepoints = 0; - // no worries, doesnt allocate until we push things onto it - let mut label = String::new(); - let mut mark = 0; - - loop { - if codepoints >= 1000 { - return None; - } - match *bytes.get(ix)? { - b'[' => return None, - b']' => break, - b'\\' => { - ix += 2; - codepoints += 2; - only_white_space = false; - } - b if is_ascii_whitespace(b) => { - // normalize labels by collapsing whitespaces, including linebreaks - let mut whitespaces = 0; - let mut linebreaks = 0; - let whitespace_start = ix; - - while ix < bytes.len() && is_ascii_whitespace(bytes[ix]) { - if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { - linebreaks += 1; - if linebreaks > 1 { - return None; - } - ix += eol_bytes; - ix += linebreak_handler(&bytes[ix..])?; - whitespaces += 2; // indicate that we need to replace - } else { - whitespaces += if bytes[ix] == b' ' { 1 } else { 2 }; - ix += 1; - } - } - if whitespaces > 1 { - label.push_str(&text[mark..whitespace_start]); - label.push(' '); - mark = ix; - codepoints += ix - whitespace_start; - } else { - codepoints += 1; - } - } - b => { - only_white_space = false; - ix += 1; - if b & 0b1000_0000 != 0 { - codepoints += 1; - } - } - } - } - - if only_white_space { - None - } else { - let cow = if mark == 0 { - text[..ix].into() - } else { - label.push_str(&text[mark..ix]); - label.into() - }; - Some((ix + 1, cow)) - } -} - -#[cfg(test)] -mod test { - use super::scan_link_label_rest; - - #[test] - fn whitespace_normalization() { - let input = "«\t\tBlurry Eyes\t\t»][blurry_eyes]"; - let expected_output = "« Blurry Eyes »"; // regular spaces! - - let (_bytes, normalized_label) = scan_link_label_rest(input, &|_| None).unwrap(); - assert_eq!(expected_output, normalized_label.as_ref()); - } - - #[test] - fn return_carriage_linefeed_ok() { - let input = "hello\r\nworld\r\n]"; - assert!(scan_link_label_rest(input, &|_| Some(0)).is_some()); - } -} +// Copyright 2018 Google LLC +// +// 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. + +//! Link label parsing and matching. + +use unicase::UniCase; + +use crate::scanners::{is_ascii_whitespace, scan_eol}; +use crate::strings::CowStr; + +pub enum ReferenceLabel<'a> { + Link(CowStr<'a>), + Footnote(CowStr<'a>), +} + +pub type LinkLabel<'a> = UniCase>; + +/// Assumes the opening bracket has already been scanned. +/// The line break handler determines what happens when a linebreak +/// is found. It is passed the bytes following the line break and +/// either returns `Some(k)`, where `k` is the number of bytes to skip, +/// or `None` to abort parsing the label. +/// Returns the number of bytes read (including closing bracket) and label on success. +pub(crate) fn scan_link_label_rest<'t>( + text: &'t str, + linebreak_handler: &dyn Fn(&[u8]) -> Option, +) -> Option<(usize, CowStr<'t>)> { + let bytes = text.as_bytes(); + let mut ix = 0; + let mut only_white_space = true; + let mut codepoints = 0; + // no worries, doesnt allocate until we push things onto it + let mut label = String::new(); + let mut mark = 0; + + loop { + if codepoints >= 1000 { + return None; + } + match *bytes.get(ix)? { + b'[' => return None, + b']' => break, + b'\\' => { + ix += 2; + codepoints += 2; + only_white_space = false; + } + b if is_ascii_whitespace(b) => { + // normalize labels by collapsing whitespaces, including linebreaks + let mut whitespaces = 0; + let mut linebreaks = 0; + let whitespace_start = ix; + + while ix < bytes.len() && is_ascii_whitespace(bytes[ix]) { + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + linebreaks += 1; + if linebreaks > 1 { + return None; + } + ix += eol_bytes; + ix += linebreak_handler(&bytes[ix..])?; + whitespaces += 2; // indicate that we need to replace + } else { + whitespaces += if bytes[ix] == b' ' { 1 } else { 2 }; + ix += 1; + } + } + if whitespaces > 1 { + label.push_str(&text[mark..whitespace_start]); + label.push(' '); + mark = ix; + codepoints += ix - whitespace_start; + } else { + codepoints += 1; + } + } + b => { + only_white_space = false; + ix += 1; + if b & 0b1000_0000 != 0 { + codepoints += 1; + } + } + } + } + + if only_white_space { + None + } else { + let cow = if mark == 0 { + text[..ix].into() + } else { + label.push_str(&text[mark..ix]); + label.into() + }; + Some((ix + 1, cow)) + } +} + +#[cfg(test)] +mod test { + use super::scan_link_label_rest; + + #[test] + fn whitespace_normalization() { + let input = "«\t\tBlurry Eyes\t\t»][blurry_eyes]"; + let expected_output = "« Blurry Eyes »"; // regular spaces! + + let (_bytes, normalized_label) = scan_link_label_rest(input, &|_| None).unwrap(); + assert_eq!(expected_output, normalized_label.as_ref()); + } + + #[test] + fn return_carriage_linefeed_ok() { + let input = "hello\r\nworld\r\n]"; + assert!(scan_link_label_rest(input, &|_| Some(0)).is_some()); + } +} diff --git a/vendor/pulldown-cmark/src/main.rs b/vendor/pulldown-cmark/src/main.rs index d0225a4ce7..1a7ea77bc2 100644 --- a/vendor/pulldown-cmark/src/main.rs +++ b/vendor/pulldown-cmark/src/main.rs @@ -1,109 +1,109 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Command line tool to exercise pulldown-cmark. - -use pulldown_cmark::{html, Options, Parser}; - -use std::env; -use std::io::{self, Read}; -use std::mem; - -fn dry_run(text: &str, opts: Options) { - let p = Parser::new_ext(text, opts); - let count = p.count(); - println!("{} events", count); -} - -fn print_events(text: &str, opts: Options) { - let parser = Parser::new_ext(text, opts).into_offset_iter(); - for (event, range) in parser { - println!("{:?}: {:?}", range, event); - } - println!("EOF"); -} - -fn brief(program: &str) -> String { - format!( - "Usage: {} [options]\n\n{}", - program, "Reads markdown from standard input and emits HTML.", - ) -} - -pub fn main() -> std::io::Result<()> { - let args: Vec<_> = env::args().collect(); - let mut opts = getopts::Options::new(); - opts.optflag("h", "help", "this help message"); - opts.optflag("d", "dry-run", "dry run, produce no output"); - opts.optflag("e", "events", "print event sequence instead of rendering"); - opts.optflag("T", "enable-tables", "enable GitHub-style tables"); - opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes"); - opts.optflag( - "S", - "enable-strikethrough", - "enable GitHub-style strikethrough", - ); - opts.optflag("L", "enable-tasklists", "enable GitHub-style task lists"); - - let matches = match opts.parse(&args[1..]) { - Ok(m) => m, - Err(f) => { - eprintln!("{}\n{}", f, opts.usage(&brief(&args[0]))); - std::process::exit(1); - } - }; - if matches.opt_present("help") { - println!("{}", opts.usage(&brief(&args[0]))); - return Ok(()); - } - let mut opts = Options::empty(); - if matches.opt_present("enable-tables") { - opts.insert(Options::ENABLE_TABLES); - } - if matches.opt_present("enable-footnotes") { - opts.insert(Options::ENABLE_FOOTNOTES); - } - if matches.opt_present("enable-strikethrough") { - opts.insert(Options::ENABLE_STRIKETHROUGH); - } - if matches.opt_present("enable-tasklists") { - opts.insert(Options::ENABLE_TASKLISTS); - } - - let mut input = String::new(); - io::stdin().lock().read_to_string(&mut input)?; - if matches.opt_present("events") { - print_events(&input, opts); - } else if matches.opt_present("dry-run") { - dry_run(&input, opts); - } else { - let mut p = Parser::new_ext(&input, opts); - let stdio = io::stdout(); - let buffer = std::io::BufWriter::with_capacity(1024 * 1024, stdio.lock()); - html::write_html(buffer, &mut p)?; - // Since the program will now terminate and the memory will be returned - // to the operating system anyway, there is no point in tidely cleaning - // up all the datastructures we have used. We shouldn't do this if we'd - // do other things after this, because this is basically intentionally - // leaking data. Skipping cleanup lets us return a bit (~5%) faster. - mem::forget(p); - } - Ok(()) -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! Command line tool to exercise pulldown-cmark. + +use pulldown_cmark::{html, Options, Parser}; + +use std::env; +use std::io::{self, Read}; +use std::mem; + +fn dry_run(text: &str, opts: Options) { + let p = Parser::new_ext(text, opts); + let count = p.count(); + println!("{} events", count); +} + +fn print_events(text: &str, opts: Options) { + let parser = Parser::new_ext(text, opts).into_offset_iter(); + for (event, range) in parser { + println!("{:?}: {:?}", range, event); + } + println!("EOF"); +} + +fn brief(program: &str) -> String { + format!( + "Usage: {} [options]\n\n{}", + program, "Reads markdown from standard input and emits HTML.", + ) +} + +pub fn main() -> std::io::Result<()> { + let args: Vec<_> = env::args().collect(); + let mut opts = getopts::Options::new(); + opts.optflag("h", "help", "this help message"); + opts.optflag("d", "dry-run", "dry run, produce no output"); + opts.optflag("e", "events", "print event sequence instead of rendering"); + opts.optflag("T", "enable-tables", "enable GitHub-style tables"); + opts.optflag("F", "enable-footnotes", "enable Hoedown-style footnotes"); + opts.optflag( + "S", + "enable-strikethrough", + "enable GitHub-style strikethrough", + ); + opts.optflag("L", "enable-tasklists", "enable GitHub-style task lists"); + + let matches = match opts.parse(&args[1..]) { + Ok(m) => m, + Err(f) => { + eprintln!("{}\n{}", f, opts.usage(&brief(&args[0]))); + std::process::exit(1); + } + }; + if matches.opt_present("help") { + println!("{}", opts.usage(&brief(&args[0]))); + return Ok(()); + } + let mut opts = Options::empty(); + if matches.opt_present("enable-tables") { + opts.insert(Options::ENABLE_TABLES); + } + if matches.opt_present("enable-footnotes") { + opts.insert(Options::ENABLE_FOOTNOTES); + } + if matches.opt_present("enable-strikethrough") { + opts.insert(Options::ENABLE_STRIKETHROUGH); + } + if matches.opt_present("enable-tasklists") { + opts.insert(Options::ENABLE_TASKLISTS); + } + + let mut input = String::new(); + io::stdin().lock().read_to_string(&mut input)?; + if matches.opt_present("events") { + print_events(&input, opts); + } else if matches.opt_present("dry-run") { + dry_run(&input, opts); + } else { + let mut p = Parser::new_ext(&input, opts); + let stdio = io::stdout(); + let buffer = std::io::BufWriter::with_capacity(1024 * 1024, stdio.lock()); + html::write_html(buffer, &mut p)?; + // Since the program will now terminate and the memory will be returned + // to the operating system anyway, there is no point in tidely cleaning + // up all the datastructures we have used. We shouldn't do this if we'd + // do other things after this, because this is basically intentionally + // leaking data. Skipping cleanup lets us return a bit (~5%) faster. + mem::forget(p); + } + Ok(()) +} diff --git a/vendor/pulldown-cmark/src/parse.rs b/vendor/pulldown-cmark/src/parse.rs index ab50679f9e..eda6a1906e 100644 --- a/vendor/pulldown-cmark/src/parse.rs +++ b/vendor/pulldown-cmark/src/parse.rs @@ -1,3138 +1,3374 @@ -// Copyright 2017 Google Inc. All rights reserved. -// -// 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. - -//! Tree-based two pass parser. - -use std::cmp::{max, min}; -use std::collections::{HashMap, VecDeque}; -use std::ops::{Index, Range}; - -use unicase::UniCase; - -use crate::linklabel::{scan_link_label_rest, LinkLabel, ReferenceLabel}; -use crate::scanners::*; -use crate::strings::CowStr; -use crate::tree::{Tree, TreeIndex}; - -// Allowing arbitrary depth nested parentheses inside link destinations -// can create denial of service vulnerabilities if we're not careful. -// The simplest countermeasure is to limit their depth, which is -// explicitly allowed by the spec as long as the limit is at least 3: -// https://spec.commonmark.org/0.29/#link-destination -const LINK_MAX_NESTED_PARENS: usize = 5; - -/// Codeblock kind. -#[derive(Clone, Debug, PartialEq)] -pub enum CodeBlockKind<'a> { - Indented, - /// The value contained in the tag describes the language of the code, which may be empty. - Fenced(CowStr<'a>), -} - -impl<'a> CodeBlockKind<'a> { - pub fn is_indented(&self) -> bool { - match *self { - CodeBlockKind::Indented => true, - _ => false, - } - } - - pub fn is_fenced(&self) -> bool { - match *self { - CodeBlockKind::Fenced(_) => true, - _ => false, - } - } -} - -/// Tags for elements that can contain other elements. -#[derive(Clone, Debug, PartialEq)] -pub enum Tag<'a> { - /// A paragraph of text and other inline elements. - Paragraph, - - /// A heading. The field indicates the level of the heading. - Heading(u32), - - BlockQuote, - /// A code block. - CodeBlock(CodeBlockKind<'a>), - - /// A list. If the list is ordered the field indicates the number of the first item. - /// Contains only list items. - List(Option), // TODO: add delim and tight for ast (not needed for html) - /// A list item. - Item, - /// A footnote definition. The value contained is the footnote's label by which it can - /// be referred to. - FootnoteDefinition(CowStr<'a>), - - /// A table. Contains a vector describing the text-alignment for each of its columns. - Table(Vec), - /// A table header. Contains only `TableRow`s. Note that the table body starts immediately - /// after the closure of the `TableHead` tag. There is no `TableBody` tag. - TableHead, - /// A table row. Is used both for header rows as body rows. Contains only `TableCell`s. - TableRow, - TableCell, - - // span-level tags - Emphasis, - Strong, - Strikethrough, - - /// A link. The first field is the link type, the second the destination URL and the third is a title. - Link(LinkType, CowStr<'a>, CowStr<'a>), - - /// An image. The first field is the link type, the second the destination URL and the third is a title. - Image(LinkType, CowStr<'a>, CowStr<'a>), -} - -/// Type specifier for inline links. See [the Tag::Link](enum.Tag.html#variant.Link) for more information. -#[derive(Clone, Debug, PartialEq, Copy)] -pub enum LinkType { - /// Inline link like `[foo](bar)` - Inline, - /// Reference link like `[foo][bar]` - Reference, - /// Reference without destination in the document, but resolved by the broken_link_callback - ReferenceUnknown, - /// Collapsed link like `[foo][]` - Collapsed, - /// Collapsed link without destination in the document, but resolved by the broken_link_callback - CollapsedUnknown, - /// Shortcut link like `[foo]` - Shortcut, - /// Shortcut without destination in the document, but resolved by the broken_link_callback - ShortcutUnknown, - /// Autolink like `` - Autolink, - /// Email address in autolink like `` - Email, -} - -impl LinkType { - fn to_unknown(self) -> Self { - match self { - LinkType::Reference => LinkType::ReferenceUnknown, - LinkType::Collapsed => LinkType::CollapsedUnknown, - LinkType::Shortcut => LinkType::ShortcutUnknown, - _ => unreachable!(), - } - } -} - -/// Markdown events that are generated in a preorder traversal of the document -/// tree, with additional `End` events whenever all of an inner node's children -/// have been visited. -#[derive(Clone, Debug, PartialEq)] -pub enum Event<'a> { - /// Start of a tagged element. Events that are yielded after this event - /// and before its corresponding `End` event are inside this element. - /// Start and end events are guaranteed to be balanced. - Start(Tag<'a>), - /// End of a tagged element. - End(Tag<'a>), - /// A text node. - Text(CowStr<'a>), - /// An inline code node. - Code(CowStr<'a>), - /// An HTML node. - Html(CowStr<'a>), - /// A reference to a footnote with given label, which may or may not be defined - /// by an event with a `Tag::FootnoteDefinition` tag. Definitions and references to them may - /// occur in any order. - FootnoteReference(CowStr<'a>), - /// A soft line break. - SoftBreak, - /// A hard line break. - HardBreak, - /// A horizontal ruler. - Rule, - /// A task list marker, rendered as a checkbox in HTML. Contains a true when it is checked. - TaskListMarker(bool), -} - -/// Table column text alignment. -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum Alignment { - /// Default text alignment. - None, - Left, - Center, - Right, -} - -bitflags! { - /// Option struct containing flags for enabling extra features - /// that are not part of the CommonMark spec. - pub struct Options: u32 { - const ENABLE_TABLES = 1 << 1; - const ENABLE_FOOTNOTES = 1 << 2; - const ENABLE_STRIKETHROUGH = 1 << 3; - const ENABLE_TASKLISTS = 1 << 4; - } -} - -#[derive(Debug, Default, Clone, Copy)] -struct Item { - start: usize, - end: usize, - body: ItemBody, -} - -#[derive(Debug, PartialEq, Clone, Copy)] -enum ItemBody { - Paragraph, - Text, - SoftBreak, - HardBreak, - - // These are possible inline items, need to be resolved in second pass. - - // repeats, can_open, can_close - MaybeEmphasis(usize, bool, bool), - MaybeCode(usize, bool), // number of backticks, preceeded by backslash - MaybeHtml, - MaybeLinkOpen, - MaybeLinkClose, - MaybeImage, - - // These are inline items after resolution. - Emphasis, - Strong, - Strikethrough, - Code(CowIndex), - Link(LinkIndex), - Image(LinkIndex), - FootnoteReference(CowIndex), - TaskListMarker(bool), // true for checked - - Rule, - Heading(u32), // heading level - FencedCodeBlock(CowIndex), - IndentCodeBlock, - Html, - BlockQuote, - List(bool, u8, u64), // is_tight, list character, list start index - ListItem(usize), // indent level - SynthesizeText(CowIndex), - FootnoteDefinition(CowIndex), - - // Tables - Table(AlignmentIndex), - TableHead, - TableRow, - TableCell, - - // Dummy node at the top of the tree - should not be used otherwise! - Root, -} - -impl<'a> ItemBody { - fn is_inline(&self) -> bool { - match *self { - ItemBody::MaybeEmphasis(..) - | ItemBody::MaybeHtml - | ItemBody::MaybeCode(..) - | ItemBody::MaybeLinkOpen - | ItemBody::MaybeLinkClose - | ItemBody::MaybeImage => true, - _ => false, - } - } -} - -impl<'a> Default for ItemBody { - fn default() -> Self { - ItemBody::Root - } -} - -/// Scanning modes for `Parser`'s `parse_line` method. -#[derive(PartialEq, Eq, Copy, Clone)] -enum TableParseMode { - /// Inside a paragraph, scanning for table headers. - Scan, - /// Inside a table. - Active, - /// Inside a paragraph, not scanning for table headers. - Disabled, -} - -/// State for the first parsing pass. -/// -/// The first pass resolves all block structure, generating an AST. Within a block, items -/// are in a linear chain with potential inline markup identified. -struct FirstPass<'a> { - text: &'a str, - tree: Tree, - begin_list_item: bool, - last_line_blank: bool, - allocs: Allocations<'a>, - options: Options, - list_nesting: usize, -} - -impl<'a> FirstPass<'a> { - fn new(text: &'a str, options: Options) -> FirstPass { - // This is a very naive heuristic for the number of nodes - // we'll need. - let start_capacity = max(128, text.len() / 32); - let tree = Tree::with_capacity(start_capacity); - let begin_list_item = false; - let last_line_blank = false; - let allocs = Allocations::new(); - FirstPass { - text, - tree, - begin_list_item, - last_line_blank, - allocs, - options, - list_nesting: 0, - } - } - - fn run(mut self) -> (Tree, Allocations<'a>) { - let mut ix = 0; - while ix < self.text.len() { - ix = self.parse_block(ix); - } - for _ in 0..self.tree.spine_len() { - self.pop(ix); - } - (self.tree, self.allocs) - } - - /// Returns offset after block. - fn parse_block(&mut self, mut start_ix: usize) -> usize { - let bytes = self.text.as_bytes(); - let mut line_start = LineStart::new(&bytes[start_ix..]); - - let i = scan_containers(&self.tree, &mut line_start); - for _ in i..self.tree.spine_len() { - self.pop(start_ix); - } - - if self.options.contains(Options::ENABLE_FOOTNOTES) { - // finish footnote if it's still open and was preceeded by blank line - if let Some(node_ix) = self.tree.peek_up() { - if let ItemBody::FootnoteDefinition(..) = self.tree[node_ix].item.body { - if self.last_line_blank { - self.pop(start_ix); - } - } - } - - // Footnote definitions of the form - // [^bar]: - // * anything really - let container_start = start_ix + line_start.bytes_scanned(); - if let Some(bytecount) = self.parse_footnote(container_start) { - start_ix = container_start + bytecount; - start_ix += scan_blank_line(&bytes[start_ix..]).unwrap_or(0); - line_start = LineStart::new(&bytes[start_ix..]); - } - } - - // Process new containers - loop { - let container_start = start_ix + line_start.bytes_scanned(); - if let Some((ch, index, indent)) = line_start.scan_list_marker() { - let after_marker_index = start_ix + line_start.bytes_scanned(); - self.continue_list(container_start, ch, index); - self.tree.append(Item { - start: container_start, - end: after_marker_index, // will get updated later if item not empty - body: ItemBody::ListItem(indent), - }); - self.tree.push(); - if let Some(n) = scan_blank_line(&bytes[after_marker_index..]) { - self.begin_list_item = true; - return after_marker_index + n; - } - if self.options.contains(Options::ENABLE_TASKLISTS) { - if let Some(is_checked) = line_start.scan_task_list_marker() { - self.tree.append(Item { - start: after_marker_index, - end: start_ix + line_start.bytes_scanned(), - body: ItemBody::TaskListMarker(is_checked), - }); - } - } - } else if line_start.scan_blockquote_marker() { - self.finish_list(start_ix); - self.tree.append(Item { - start: container_start, - end: 0, // will get set later - body: ItemBody::BlockQuote, - }); - self.tree.push(); - } else { - break; - } - } - - let ix = start_ix + line_start.bytes_scanned(); - - if let Some(n) = scan_blank_line(&bytes[ix..]) { - if let Some(node_ix) = self.tree.peek_up() { - match self.tree[node_ix].item.body { - ItemBody::BlockQuote => (), - _ => { - if self.begin_list_item { - // A list item can begin with at most one blank line. - self.pop(start_ix); - } - self.last_line_blank = true; - } - } - } - return ix + n; - } - - self.begin_list_item = false; - self.finish_list(start_ix); - - // Save `remaining_space` here to avoid needing to backtrack `line_start` for HTML blocks - let remaining_space = line_start.remaining_space(); - - let indent = line_start.scan_space_upto(4); - if indent == 4 { - let ix = start_ix + line_start.bytes_scanned(); - let remaining_space = line_start.remaining_space(); - return self.parse_indented_code_block(ix, remaining_space); - } - - let ix = start_ix + line_start.bytes_scanned(); - - // HTML Blocks - if bytes[ix] == b'<' { - // Types 1-5 are all detected by one function and all end with the same - // pattern - if let Some(html_end_tag) = get_html_end_tag(&bytes[(ix + 1)..]) { - return self.parse_html_block_type_1_to_5(ix, html_end_tag, remaining_space); - } - - // Detect type 6 - let possible_tag = scan_html_block_tag(&bytes[(ix + 1)..]).1; - if is_html_tag(possible_tag) { - return self.parse_html_block_type_6_or_7(ix, remaining_space); - } - - // Detect type 7 - if let Some(_html_bytes) = scan_html_type_7(&bytes[(ix + 1)..]) { - return self.parse_html_block_type_6_or_7(ix, remaining_space); - } - } - - if let Ok(n) = scan_hrule(&bytes[ix..]) { - return self.parse_hrule(n, ix); - } - - if let Some(atx_size) = scan_atx_heading(&bytes[ix..]) { - return self.parse_atx_heading(ix, atx_size); - } - - // parse refdef - if let Some((bytecount, label, link_def)) = self.parse_refdef_total(ix) { - self.allocs.refdefs.entry(label).or_insert(link_def); - let ix = ix + bytecount; - // try to read trailing whitespace or it will register as a completely blank line - // TODO: shouldn't we do this for all block level items? - return ix + scan_blank_line(&bytes[ix..]).unwrap_or(0); - } - - if let Some((n, fence_ch)) = scan_code_fence(&bytes[ix..]) { - return self.parse_fenced_code_block(ix, indent, fence_ch, n); - } - self.parse_paragraph(ix) - } - - /// Returns the offset of the first line after the table. - /// Assumptions: current focus is a table element and the table header - /// matches the separator line (same number of columns). - fn parse_table(&mut self, table_cols: usize, head_start: usize, body_start: usize) -> usize { - // parse header. this shouldn't fail because we made sure the table header is ok - let (_sep_start, thead_ix) = self.parse_table_row_inner(head_start, table_cols); - self.tree[thead_ix].item.body = ItemBody::TableHead; - - // parse body - let mut ix = body_start; - while let Some((next_ix, _row_ix)) = self.parse_table_row(ix, table_cols) { - ix = next_ix; - } - - self.pop(ix); - ix - } - - /// Call this when containers are taken care of. - /// Returns bytes scanned, row_ix - fn parse_table_row_inner(&mut self, mut ix: usize, row_cells: usize) -> (usize, TreeIndex) { - let bytes = self.text.as_bytes(); - let mut cells = 0; - let mut final_cell_ix = None; - - let row_ix = self.tree.append(Item { - start: ix, - end: 0, // set at end of this function - body: ItemBody::TableRow, - }); - self.tree.push(); - - loop { - ix += scan_ch(&bytes[ix..], b'|'); - ix += scan_whitespace_no_nl(&bytes[ix..]); - - if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { - ix += eol_bytes; - break; - } - - let cell_ix = self.tree.append(Item { - start: ix, - end: ix, - body: ItemBody::TableCell, - }); - self.tree.push(); - let (next_ix, _brk) = self.parse_line(ix, TableParseMode::Active); - let trailing_whitespace = scan_rev_while(&bytes[..next_ix], is_ascii_whitespace); - - if let Some(cur_ix) = self.tree.cur() { - self.tree[cur_ix].item.end -= trailing_whitespace; - } - - self.tree[cell_ix].item.end = next_ix - trailing_whitespace; - self.tree.pop(); - - ix = next_ix; - cells += 1; - - if cells == row_cells { - final_cell_ix = Some(cell_ix); - } - } - - // fill empty cells if needed - // note: this is where GFM and commonmark-extra diverge. we follow - // GFM here - for _ in cells..row_cells { - self.tree.append(Item { - start: ix, - end: ix, - body: ItemBody::TableCell, - }); - } - - // drop excess cells - if let Some(cell_ix) = final_cell_ix { - self.tree[cell_ix].next = None; - } - - self.pop(ix); - - (ix, row_ix) - } - - /// Returns first offset after the row and the tree index of the row. - fn parse_table_row(&mut self, mut ix: usize, row_cells: usize) -> Option<(usize, TreeIndex)> { - let bytes = self.text.as_bytes(); - let mut line_start = LineStart::new(&bytes[ix..]); - let containers = scan_containers(&self.tree, &mut line_start); - if containers != self.tree.spine_len() { - return None; - } - line_start.scan_all_space(); - ix += line_start.bytes_scanned(); - if scan_paragraph_interrupt(&bytes[ix..]) { - return None; - } - - let (ix, row_ix) = self.parse_table_row_inner(ix, row_cells); - Some((ix, row_ix)) - } - - /// Returns offset of line start after paragraph. - fn parse_paragraph(&mut self, start_ix: usize) -> usize { - let node_ix = self.tree.append(Item { - start: start_ix, - end: 0, // will get set later - body: ItemBody::Paragraph, - }); - self.tree.push(); - let bytes = self.text.as_bytes(); - - let mut ix = start_ix; - loop { - let scan_mode = if self.options.contains(Options::ENABLE_TABLES) && ix == start_ix { - TableParseMode::Scan - } else { - TableParseMode::Disabled - }; - let (next_ix, brk) = self.parse_line(ix, scan_mode); - - // break out when we find a table - if let Some(Item { - body: ItemBody::Table(alignment_ix), - .. - }) = brk - { - let table_cols = self.allocs[alignment_ix].len(); - self.tree[node_ix].item.body = ItemBody::Table(alignment_ix); - // this clears out any stuff we may have appended - but there may - // be a cleaner way - self.tree[node_ix].child = None; - self.tree.pop(); - self.tree.push(); - return self.parse_table(table_cols, ix, next_ix); - } - - ix = next_ix; - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if !line_start.scan_space(4) { - let ix_new = ix + line_start.bytes_scanned(); - if n_containers == self.tree.spine_len() { - if let Some(ix_setext) = self.parse_setext_heading(ix_new, node_ix) { - if let Some(Item { - start, - body: ItemBody::HardBreak, - .. - }) = brk - { - if bytes[start] == b'\\' { - self.tree.append_text(start, start + 1); - } - } - ix = ix_setext; - break; - } - } - // first check for non-empty lists, then for other interrupts - let suffix = &bytes[ix_new..]; - if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { - break; - } - } - line_start.scan_all_space(); - if line_start.is_at_eol() { - break; - } - ix = next_ix + line_start.bytes_scanned(); - if let Some(item) = brk { - self.tree.append(item); - } - } - - self.pop(ix); - ix - } - - /// Returns end ix of setext_heading on success. - fn parse_setext_heading(&mut self, ix: usize, node_ix: TreeIndex) -> Option { - let bytes = self.text.as_bytes(); - let (n, level) = scan_setext_heading(&bytes[ix..])?; - self.tree[node_ix].item.body = ItemBody::Heading(level); - - // strip trailing whitespace - if let Some(cur_ix) = self.tree.cur() { - self.tree[cur_ix].item.end -= scan_rev_while( - &bytes[..self.tree[cur_ix].item.end], - is_ascii_whitespace_no_nl, - ); - } - - Some(ix + n) - } - - /// Parse a line of input, appending text and items to tree. - /// - /// Returns: index after line and an item representing the break. - fn parse_line(&mut self, start: usize, mode: TableParseMode) -> (usize, Option) { - let bytes = &self.text.as_bytes(); - let mut pipes = 0; - let mut last_pipe_ix = start; - let mut begin_text = start; - - let (final_ix, brk) = iterate_special_bytes(bytes, start, |ix, byte| { - match byte { - b'\n' | b'\r' => { - if let TableParseMode::Active = mode { - return LoopInstruction::BreakAtWith(ix, None); - } - - let mut i = ix; - let eol_bytes = scan_eol(&bytes[ix..]).unwrap(); - if mode == TableParseMode::Scan && pipes > 0 { - // check if we may be parsing a table - let next_line_ix = ix + eol_bytes; - let mut line_start = LineStart::new(&bytes[next_line_ix..]); - if scan_containers(&self.tree, &mut line_start) == self.tree.spine_len() { - let table_head_ix = next_line_ix + line_start.bytes_scanned(); - let (table_head_bytes, alignment) = - scan_table_head(&bytes[table_head_ix..]); - - if table_head_bytes > 0 { - // computing header count from number of pipes - let header_count = - count_header_cols(bytes, pipes, start, last_pipe_ix); - - // make sure they match the number of columns we find in separator line - if alignment.len() == header_count { - let alignment_ix = self.allocs.allocate_alignment(alignment); - let end_ix = table_head_ix + table_head_bytes; - return LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, // must update later - body: ItemBody::Table(alignment_ix), - }), - ); - } - } - } - } - - let end_ix = ix + eol_bytes; - let trailing_backslashes = scan_rev_while(&bytes[..ix], |b| b == b'\\'); - if trailing_backslashes % 2 == 1 && end_ix < self.text.len() { - i -= 1; - self.tree.append_text(begin_text, i); - return LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, - body: ItemBody::HardBreak, - }), - ); - } - let trailing_whitespace = - scan_rev_while(&bytes[..ix], is_ascii_whitespace_no_nl); - if trailing_whitespace >= 2 { - i -= trailing_whitespace; - self.tree.append_text(begin_text, i); - return LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, - body: ItemBody::HardBreak, - }), - ); - } - - self.tree.append_text(begin_text, ix); - LoopInstruction::BreakAtWith( - end_ix, - Some(Item { - start: i, - end: end_ix, - body: ItemBody::SoftBreak, - }), - ) - } - b'\\' => { - if ix + 1 < self.text.len() && is_ascii_punctuation(bytes[ix + 1]) { - self.tree.append_text(begin_text, ix); - if bytes[ix + 1] == b'`' { - let count = 1 + scan_ch_repeat(&bytes[(ix + 2)..], b'`'); - self.tree.append(Item { - start: ix + 1, - end: ix + count + 1, - body: ItemBody::MaybeCode(count, true), - }); - begin_text = ix + 1 + count; - LoopInstruction::ContinueAndSkip(count) - } else { - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(1) - } - } else { - LoopInstruction::ContinueAndSkip(0) - } - } - c @ b'*' | c @ b'_' | c @ b'~' => { - let string_suffix = &self.text[ix..]; - let count = 1 + scan_ch_repeat(&string_suffix.as_bytes()[1..], c); - let can_open = delim_run_can_open(self.text, string_suffix, count, ix); - let can_close = delim_run_can_close(self.text, string_suffix, count, ix); - let is_valid_seq = c != b'~' - || count == 2 && self.options.contains(Options::ENABLE_STRIKETHROUGH); - - if (can_open || can_close) && is_valid_seq { - self.tree.append_text(begin_text, ix); - for i in 0..count { - self.tree.append(Item { - start: ix + i, - end: ix + i + 1, - body: ItemBody::MaybeEmphasis(count - i, can_open, can_close), - }); - } - begin_text = ix + count; - } - LoopInstruction::ContinueAndSkip(count - 1) - } - b'`' => { - self.tree.append_text(begin_text, ix); - let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'`'); - self.tree.append(Item { - start: ix, - end: ix + count, - body: ItemBody::MaybeCode(count, false), - }); - begin_text = ix + count; - LoopInstruction::ContinueAndSkip(count - 1) - } - b'<' => { - // Note: could detect some non-HTML cases and early escape here, but not - // clear that's a win. - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 1, - body: ItemBody::MaybeHtml, - }); - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(0) - } - b'!' => { - if ix + 1 < self.text.len() && bytes[ix + 1] == b'[' { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 2, - body: ItemBody::MaybeImage, - }); - begin_text = ix + 2; - LoopInstruction::ContinueAndSkip(1) - } else { - LoopInstruction::ContinueAndSkip(0) - } - } - b'[' => { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 1, - body: ItemBody::MaybeLinkOpen, - }); - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(0) - } - b']' => { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + 1, - body: ItemBody::MaybeLinkClose, - }); - begin_text = ix + 1; - LoopInstruction::ContinueAndSkip(0) - } - b'&' => match scan_entity(&bytes[ix..]) { - (n, Some(value)) => { - self.tree.append_text(begin_text, ix); - self.tree.append(Item { - start: ix, - end: ix + n, - body: ItemBody::SynthesizeText(self.allocs.allocate_cow(value)), - }); - begin_text = ix + n; - LoopInstruction::ContinueAndSkip(n - 1) - } - _ => LoopInstruction::ContinueAndSkip(0), - }, - b'|' => { - if let TableParseMode::Active = mode { - LoopInstruction::BreakAtWith(ix, None) - } else { - last_pipe_ix = ix; - pipes += 1; - LoopInstruction::ContinueAndSkip(0) - } - } - _ => LoopInstruction::ContinueAndSkip(0), - } - }); - - if brk.is_none() { - // need to close text at eof - self.tree.append_text(begin_text, final_ix); - } - (final_ix, brk) - } - - /// Check whether we should allow a paragraph interrupt by lists. Only non-empty - /// lists are allowed. - fn interrupt_paragraph_by_list(&self, suffix: &[u8]) -> bool { - scan_listitem(suffix).map_or(false, |(ix, delim, index, _)| { - self.list_nesting > 0 || - // we don't allow interruption by either empty lists or - // numbered lists starting at an index other than 1 - !scan_empty_list(&suffix[ix..]) && (delim == b'*' || delim == b'-' || index == 1) - }) - } - - /// When start_ix is at the beginning of an HTML block of type 1 to 5, - /// this will find the end of the block, adding the block itself to the - /// tree and also keeping track of the lines of HTML within the block. - /// - /// The html_end_tag is the tag that must be found on a line to end the block. - fn parse_html_block_type_1_to_5( - &mut self, - start_ix: usize, - html_end_tag: &str, - mut remaining_space: usize, - ) -> usize { - let bytes = self.text.as_bytes(); - let mut ix = start_ix; - loop { - let line_start_ix = ix; - ix += scan_nextline(&bytes[ix..]); - self.append_html_line(remaining_space, line_start_ix, ix); - - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() { - break; - } - - if (&self.text[line_start_ix..ix]).contains(html_end_tag) { - break; - } - - let next_line_ix = ix + line_start.bytes_scanned(); - if next_line_ix == self.text.len() { - break; - } - ix = next_line_ix; - remaining_space = line_start.remaining_space(); - } - ix - } - - /// When start_ix is at the beginning of an HTML block of type 6 or 7, - /// this will consume lines until there is a blank line and keep track of - /// the HTML within the block. - fn parse_html_block_type_6_or_7( - &mut self, - start_ix: usize, - mut remaining_space: usize, - ) -> usize { - let bytes = self.text.as_bytes(); - let mut ix = start_ix; - loop { - let line_start_ix = ix; - ix += scan_nextline(&bytes[ix..]); - self.append_html_line(remaining_space, line_start_ix, ix); - - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() || line_start.is_at_eol() { - break; - } - - let next_line_ix = ix + line_start.bytes_scanned(); - if next_line_ix == self.text.len() || scan_blank_line(&bytes[next_line_ix..]).is_some() - { - break; - } - ix = next_line_ix; - remaining_space = line_start.remaining_space(); - } - ix - } - - fn parse_indented_code_block(&mut self, start_ix: usize, mut remaining_space: usize) -> usize { - self.tree.append(Item { - start: start_ix, - end: 0, // will get set later - body: ItemBody::IndentCodeBlock, - }); - self.tree.push(); - let bytes = self.text.as_bytes(); - let mut last_nonblank_child = None; - let mut last_nonblank_ix = 0; - let mut end_ix = 0; - let mut last_line_blank = false; - - let mut ix = start_ix; - loop { - let line_start_ix = ix; - ix += scan_nextline(&bytes[ix..]); - self.append_code_text(remaining_space, line_start_ix, ix); - // TODO(spec clarification): should we synthesize newline at EOF? - - if !last_line_blank { - last_nonblank_child = self.tree.cur(); - last_nonblank_ix = ix; - end_ix = ix; - } - - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() - || !(line_start.scan_space(4) || line_start.is_at_eol()) - { - break; - } - let next_line_ix = ix + line_start.bytes_scanned(); - if next_line_ix == self.text.len() { - break; - } - ix = next_line_ix; - remaining_space = line_start.remaining_space(); - last_line_blank = scan_blank_line(&bytes[ix..]).is_some(); - } - - // Trim trailing blank lines. - if let Some(child) = last_nonblank_child { - self.tree[child].next = None; - self.tree[child].item.end = last_nonblank_ix; - } - self.pop(end_ix); - ix - } - - fn parse_fenced_code_block( - &mut self, - start_ix: usize, - indent: usize, - fence_ch: u8, - n_fence_char: usize, - ) -> usize { - let bytes = self.text.as_bytes(); - let mut info_start = start_ix + n_fence_char; - info_start += scan_whitespace_no_nl(&bytes[info_start..]); - // TODO: info strings are typically very short. wouldnt it be faster - // to just do a forward scan here? - let mut ix = info_start + scan_nextline(&bytes[info_start..]); - let info_end = ix - scan_rev_while(&bytes[info_start..ix], is_ascii_whitespace); - let info_string = unescape(&self.text[info_start..info_end]); - self.tree.append(Item { - start: start_ix, - end: 0, // will get set later - body: ItemBody::FencedCodeBlock(self.allocs.allocate_cow(info_string)), - }); - self.tree.push(); - loop { - let mut line_start = LineStart::new(&bytes[ix..]); - let n_containers = scan_containers(&self.tree, &mut line_start); - if n_containers < self.tree.spine_len() { - break; - } - line_start.scan_space(indent); - let mut close_line_start = line_start.clone(); - if !close_line_start.scan_space(4) { - let close_ix = ix + close_line_start.bytes_scanned(); - if let Some(n) = scan_closing_code_fence(&bytes[close_ix..], fence_ch, n_fence_char) - { - ix = close_ix + n; - break; - } - } - let remaining_space = line_start.remaining_space(); - ix += line_start.bytes_scanned(); - let next_ix = ix + scan_nextline(&bytes[ix..]); - self.append_code_text(remaining_space, ix, next_ix); - ix = next_ix; - } - - self.pop(ix); - - // try to read trailing whitespace or it will register as a completely blank line - ix + scan_blank_line(&bytes[ix..]).unwrap_or(0) - } - - fn append_code_text(&mut self, remaining_space: usize, start: usize, end: usize) { - if remaining_space > 0 { - let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); - self.tree.append(Item { - start, - end: start, - body: ItemBody::SynthesizeText(cow_ix), - }); - } - if self.text.as_bytes()[end - 2] == b'\r' { - // Normalize CRLF to LF - self.tree.append_text(start, end - 2); - self.tree.append_text(end - 1, end); - } else { - self.tree.append_text(start, end); - } - } - - /// Appends a line of HTML to the tree. - fn append_html_line(&mut self, remaining_space: usize, start: usize, end: usize) { - if remaining_space > 0 { - let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); - self.tree.append(Item { - start, - end: start, - // TODO: maybe this should synthesize to html rather than text? - body: ItemBody::SynthesizeText(cow_ix), - }); - } - if self.text.as_bytes()[end - 2] == b'\r' { - // Normalize CRLF to LF - self.tree.append(Item { - start, - end: end - 2, - body: ItemBody::Html, - }); - self.tree.append(Item { - start: end - 1, - end, - body: ItemBody::Html, - }); - } else { - self.tree.append(Item { - start, - end, - body: ItemBody::Html, - }); - } - } - - /// Pop a container, setting its end. - fn pop(&mut self, ix: usize) { - let cur_ix = self.tree.pop().unwrap(); - self.tree[cur_ix].item.end = ix; - if let ItemBody::List(true, _, _) = self.tree[cur_ix].item.body { - surgerize_tight_list(&mut self.tree, cur_ix); - } - } - - /// Close a list if it's open. Also set loose if last line was blank - fn finish_list(&mut self, ix: usize) { - if let Some(node_ix) = self.tree.peek_up() { - if let ItemBody::List(_, _, _) = self.tree[node_ix].item.body { - self.pop(ix); - self.list_nesting -= 1; - } - } - if self.last_line_blank { - if let Some(node_ix) = self.tree.peek_grandparent() { - if let ItemBody::List(ref mut is_tight, _, _) = self.tree[node_ix].item.body { - *is_tight = false; - } - } - self.last_line_blank = false; - } - } - - /// Continue an existing list or start a new one if there's not an open - /// list that matches. - fn continue_list(&mut self, start: usize, ch: u8, index: u64) { - if let Some(node_ix) = self.tree.peek_up() { - if let ItemBody::List(ref mut is_tight, existing_ch, _) = self.tree[node_ix].item.body { - if existing_ch == ch { - if self.last_line_blank { - *is_tight = false; - self.last_line_blank = false; - } - return; - } - } - // TODO: this is not the best choice for end; maybe get end from last list item. - self.finish_list(start); - } - self.tree.append(Item { - start, - end: 0, // will get set later - body: ItemBody::List(true, ch, index), - }); - self.list_nesting += 1; - self.tree.push(); - self.last_line_blank = false; - } - - /// Parse a thematic break. - /// - /// Returns index of start of next line. - fn parse_hrule(&mut self, hrule_size: usize, ix: usize) -> usize { - self.tree.append(Item { - start: ix, - end: ix + hrule_size, - body: ItemBody::Rule, - }); - ix + hrule_size - } - - /// Parse an ATX heading. - /// - /// Returns index of start of next line. - fn parse_atx_heading(&mut self, mut ix: usize, atx_size: usize) -> usize { - let heading_ix = self.tree.append(Item { - start: ix, - end: 0, // set later - body: ItemBody::Heading(atx_size as u32), - }); - ix += atx_size; - // next char is space or eol (guaranteed by scan_atx_heading) - let bytes = self.text.as_bytes(); - if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { - self.tree[heading_ix].item.end = ix + eol_bytes; - return ix + eol_bytes; - } - // skip leading spaces - let skip_spaces = scan_whitespace_no_nl(&bytes[ix..]); - ix += skip_spaces; - - // now handle the header text - let header_start = ix; - let header_node_idx = self.tree.push(); // so that we can set the endpoint later - ix = self.parse_line(ix, TableParseMode::Disabled).0; - self.tree[header_node_idx].item.end = ix; - - // remove trailing matter from header text - if let Some(cur_ix) = self.tree.cur() { - let header_text = &bytes[header_start..ix]; - let mut limit = header_text - .iter() - .rposition(|&b| !(b == b'\n' || b == b'\r' || b == b' ')) - .map_or(0, |i| i + 1); - let closer = header_text[..limit] - .iter() - .rposition(|&b| b != b'#') - .map_or(0, |i| i + 1); - if closer == 0 { - limit = closer; - } else { - let spaces = scan_rev_while(&header_text[..closer], |b| b == b' '); - if spaces > 0 { - limit = closer - spaces; - } - } - self.tree[cur_ix].item.end = limit + header_start; - } - - self.tree.pop(); - ix - } - - /// Returns the number of bytes scanned on success. - fn parse_footnote(&mut self, start: usize) -> Option { - let bytes = &self.text.as_bytes()[start..]; - if !bytes.starts_with(b"[^") { - return None; - } - let (mut i, label) = self.parse_refdef_label(start + 2)?; - i += 2; - if scan_ch(&bytes[i..], b':') == 0 { - return None; - } - i += 1; - self.finish_list(start); - self.tree.append(Item { - start, - end: 0, // will get set later - // TODO: check whether the label here is strictly necessary - body: ItemBody::FootnoteDefinition(self.allocs.allocate_cow(label)), - }); - self.tree.push(); - Some(i) - } - - /// Tries to parse a reference label, which can be interrupted by new blocks. - /// On success, returns the number of bytes of the label and the label itself. - fn parse_refdef_label(&self, start: usize) -> Option<(usize, CowStr<'a>)> { - scan_link_label_rest(&self.text[start..], &|bytes| { - let mut line_start = LineStart::new(bytes); - let _ = scan_containers(&self.tree, &mut line_start); - let bytes_scanned = line_start.bytes_scanned(); - - let suffix = &bytes[bytes_scanned..]; - if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { - None - } else { - Some(bytes_scanned) - } - }) - } - - /// Returns number of bytes scanned, label and definition on success. - fn parse_refdef_total(&mut self, start: usize) -> Option<(usize, LinkLabel<'a>, LinkDef<'a>)> { - let bytes = &self.text.as_bytes()[start..]; - if scan_ch(bytes, b'[') == 0 { - return None; - } - let (mut i, label) = self.parse_refdef_label(start + 1)?; - i += 1; - if scan_ch(&bytes[i..], b':') == 0 { - return None; - } - i += 1; - let (bytecount, link_def) = self.scan_refdef(start + i)?; - Some((bytecount + i, UniCase::new(label), link_def)) - } - - /// Returns number of bytes and number of newlines - fn scan_refdef_space(&self, bytes: &[u8], mut i: usize) -> Option<(usize, usize)> { - let mut newlines = 0; - loop { - let whitespaces = scan_whitespace_no_nl(&bytes[i..]); - i += whitespaces; - if let Some(eol_bytes) = scan_eol(&bytes[i..]) { - i += eol_bytes; - newlines += 1; - if newlines > 1 { - return None; - } - } else { - break; - } - let mut line_start = LineStart::new(&bytes[i..]); - if self.tree.spine_len() != scan_containers(&self.tree, &mut line_start) { - return None; - } - i += line_start.bytes_scanned(); - } - Some((i, newlines)) - } - - /// Returns # of bytes and definition. - /// Assumes the label of the reference including colon has already been scanned. - fn scan_refdef(&self, start: usize) -> Option<(usize, LinkDef<'a>)> { - let bytes = self.text.as_bytes(); - - // whitespace between label and url (including up to one newline) - let (mut i, _newlines) = self.scan_refdef_space(bytes, start)?; - - // scan link dest - let (dest_length, dest) = scan_link_dest(self.text, i, 1)?; - if dest_length == 0 { - return None; - } - let dest = unescape(dest); - i += dest_length; - - // no title - let mut backup = (i - start, LinkDef { dest, title: None }); - - // scan whitespace between dest and label - let (mut i, newlines) = - if let Some((new_i, mut newlines)) = self.scan_refdef_space(bytes, i) { - if i == self.text.len() { - newlines += 1; - } - if new_i == i && newlines == 0 { - return None; - } - if newlines > 1 { - return Some(backup); - }; - (new_i, newlines) - } else { - return Some(backup); - }; - - // scan title - // if this fails but newline == 1, return also a refdef without title - if let Some((title_length, title)) = scan_refdef_title(&self.text[i..]) { - i += title_length; - backup.1.title = Some(unescape(title)); - } else if newlines > 0 { - return Some(backup); - } else { - return None; - }; - - // scan EOL - if let Some(bytes) = scan_blank_line(&bytes[i..]) { - backup.0 = i + bytes - start; - Some(backup) - } else if newlines > 0 { - Some(backup) - } else { - None - } - } -} - -/// Returns number of containers scanned. -fn scan_containers(tree: &Tree, line_start: &mut LineStart) -> usize { - let mut i = 0; - for &node_ix in tree.walk_spine() { - match tree[node_ix].item.body { - ItemBody::BlockQuote => { - let save = line_start.clone(); - if !line_start.scan_blockquote_marker() { - *line_start = save; - break; - } - } - ItemBody::ListItem(indent) => { - let save = line_start.clone(); - if !line_start.scan_space(indent) { - if !line_start.is_at_eol() { - *line_start = save; - break; - } - } - } - _ => (), - } - i += 1; - } - i -} - -/// Computes the number of header columns in a table line by computing the number of dividing pipes -/// that aren't followed or preceeded by whitespace. -fn count_header_cols( - bytes: &[u8], - mut pipes: usize, - mut start: usize, - last_pipe_ix: usize, -) -> usize { - // was first pipe preceeded by whitespace? if so, subtract one - start += scan_whitespace_no_nl(&bytes[start..]); - if bytes[start] == b'|' { - pipes -= 1; - } - - // was last pipe followed by whitespace? if so, sub one - if scan_blank_line(&bytes[(last_pipe_ix + 1)..]).is_some() { - pipes - } else { - pipes + 1 - } -} - -impl<'a> Tree { - fn append_text(&mut self, start: usize, end: usize) { - if end > start { - if let Some(ix) = self.cur() { - if ItemBody::Text == self[ix].item.body && self[ix].item.end == start { - self[ix].item.end = end; - return; - } - } - self.append(Item { - start, - end, - body: ItemBody::Text, - }); - } - } -} - -/// Determines whether the delimiter run starting at given index is -/// left-flanking, as defined by the commonmark spec (and isn't intraword -/// for _ delims). -/// suffix is &s[ix..], which is passed in as an optimization, since taking -/// a string subslice is O(n). -fn delim_run_can_open(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { - let next_char = if let Some(c) = suffix.chars().nth(run_len) { - c - } else { - return false; - }; - if next_char.is_whitespace() { - return false; - } - if ix == 0 { - return true; - } - let delim = suffix.chars().next().unwrap(); - if delim == '*' && !is_punctuation(next_char) { - return true; - } - - let prev_char = s[..ix].chars().last().unwrap(); - - prev_char.is_whitespace() || is_punctuation(prev_char) -} - -/// Determines whether the delimiter run starting at given index is -/// left-flanking, as defined by the commonmark spec (and isn't intraword -/// for _ delims) -fn delim_run_can_close(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { - if ix == 0 { - return false; - } - let prev_char = s[..ix].chars().last().unwrap(); - if prev_char.is_whitespace() { - return false; - } - let next_char = if let Some(c) = suffix.chars().nth(run_len) { - c - } else { - return true; - }; - let delim = suffix.chars().next().unwrap(); - if delim == '*' && !is_punctuation(prev_char) { - return true; - } - - next_char.is_whitespace() || is_punctuation(next_char) -} - -/// Checks whether we should break a paragraph on the given input. -/// Note: lists are dealt with in `interrupt_paragraph_by_list`, because determing -/// whether to break on a list requires additional context. -fn scan_paragraph_interrupt(bytes: &[u8]) -> bool { - if scan_eol(bytes).is_some() - || scan_hrule(bytes).is_ok() - || scan_atx_heading(bytes).is_some() - || scan_code_fence(bytes).is_some() - || scan_blockquote_start(bytes).is_some() - { - return true; - } - bytes.starts_with(b"<") - && (get_html_end_tag(&bytes[1..]).is_some() - || is_html_tag(scan_html_block_tag(&bytes[1..]).1)) -} - -/// Assumes `text_bytes` is preceded by `<`. -fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> { - static BEGIN_TAGS: &[&[u8]; 3] = &[b"pre", b"style", b"script"]; - static ST_BEGIN_TAGS: &[&[u8]; 3] = &[b"!--", b"?", b"![CDATA["]; - - for (beg_tag, end_tag) in BEGIN_TAGS - .iter() - .zip(["", "", ""].iter()) - { - let tag_len = beg_tag.len(); - - if text_bytes.len() < tag_len { - // begin tags are increasing in size - break; - } - - if !text_bytes[..tag_len].eq_ignore_ascii_case(beg_tag) { - continue; - } - - // Must either be the end of the line... - if text_bytes.len() == tag_len { - return Some(end_tag); - } - - // ...or be followed by whitespace, newline, or '>'. - let s = text_bytes[tag_len]; - if is_ascii_whitespace(s) || s == b'>' { - return Some(end_tag); - } - } - - for (beg_tag, end_tag) in ST_BEGIN_TAGS.iter().zip(["-->", "?>", "]]>"].iter()) { - if text_bytes.starts_with(beg_tag) { - return Some(end_tag); - } - } - - if text_bytes.len() > 1 - && text_bytes[0] == b'!' - && text_bytes[1] >= b'A' - && text_bytes[1] <= b'Z' - { - Some(">") - } else { - None - } -} - -#[derive(Copy, Clone, Debug)] -struct InlineEl { - start: TreeIndex, // offset of tree node - count: usize, - c: u8, // b'*' or b'_' - both: bool, // can both open and close -} - -#[derive(Debug, Clone, Default)] -struct InlineStack { - stack: Vec, - // Lower bounds for matching indices in the stack. For example - // a strikethrough delimiter will never match with any element - // in the stack with index smaller than - // `lower_bounds[InlineStack::TILDES]`. - lower_bounds: [usize; 7], -} - -impl InlineStack { - /// These are indices into the lower bounds array. - /// Not both refers to the property that the delimiter can not both - /// be opener as a closer. - const UNDERSCORE_NOT_BOTH: usize = 0; - const ASTERISK_NOT_BOTH: usize = 1; - const ASTERISK_BASE: usize = 2; - const TILDES: usize = 5; - const UNDERSCORE_BOTH: usize = 6; - - fn pop_all(&mut self, tree: &mut Tree) { - for el in self.stack.drain(..) { - for i in 0..el.count { - tree[el.start + i].item.body = ItemBody::Text; - } - } - self.lower_bounds = [0; 7]; - } - - fn get_lowerbound(&self, c: u8, count: usize, both: bool) -> usize { - if c == b'_' { - if both { - self.lower_bounds[InlineStack::UNDERSCORE_BOTH] - } else { - self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] - } - } else if c == b'*' { - let mod3_lower = self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3]; - if both { - mod3_lower - } else { - min( - mod3_lower, - self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH], - ) - } - } else { - self.lower_bounds[InlineStack::TILDES] - } - } - - fn set_lowerbound(&mut self, c: u8, count: usize, both: bool, new_bound: usize) { - if c == b'_' { - if both { - self.lower_bounds[InlineStack::UNDERSCORE_BOTH] = new_bound; - } else { - self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] = new_bound; - } - } else if c == b'*' { - self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3] = new_bound; - if !both { - self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH] = new_bound; - } - } else { - self.lower_bounds[InlineStack::TILDES] = new_bound; - } - } - - fn find_match( - &mut self, - tree: &mut Tree, - c: u8, - count: usize, - both: bool, - ) -> Option { - let lowerbound = min(self.stack.len(), self.get_lowerbound(c, count, both)); - let res = self.stack[lowerbound..] - .iter() - .cloned() - .enumerate() - .rfind(|(_, el)| { - el.c == c && (!both && !el.both || (count + el.count) % 3 != 0 || count % 3 == 0) - }); - - if let Some((matching_ix, matching_el)) = res { - let matching_ix = matching_ix + lowerbound; - for el in &self.stack[(matching_ix + 1)..] { - for i in 0..el.count { - tree[el.start + i].item.body = ItemBody::Text; - } - } - self.stack.truncate(matching_ix); - Some(matching_el) - } else { - self.set_lowerbound(c, count, both, self.stack.len()); - None - } - } - - fn push(&mut self, el: InlineEl) { - self.stack.push(el) - } -} - -#[derive(Debug, Clone)] -enum RefScan<'a> { - // label, next node index, source ix of label end - LinkLabel(CowStr<'a>, Option, usize), - // contains next node index - Collapsed(Option), - Failed, -} - -/// Skips forward within a block to a node which spans (ends inclusive) the given -/// index into the source. -fn scan_nodes_to_ix( - tree: &Tree, - mut node: Option, - ix: usize, -) -> Option { - while let Some(node_ix) = node { - if tree[node_ix].item.end <= ix { - node = tree[node_ix].next; - } else { - break; - } - } - node -} - -/// Scans an inline link label, which cannot be interrupted. -/// Returns number of bytes (including brackets) and label on success. -fn scan_link_label<'text, 'tree>( - tree: &'tree Tree, - text: &'text str, -) -> Option<(usize, ReferenceLabel<'text>)> { - let bytes = &text.as_bytes(); - if bytes.len() < 2 || bytes[0] != b'[' { - return None; - } - let linebreak_handler = |bytes: &[u8]| { - let mut line_start = LineStart::new(bytes); - let _ = scan_containers(tree, &mut line_start); - Some(line_start.bytes_scanned()) - }; - let pair = if b'^' == bytes[1] { - let (byte_index, cow) = scan_link_label_rest(&text[2..], &linebreak_handler)?; - (byte_index + 2, ReferenceLabel::Footnote(cow)) - } else { - let (byte_index, cow) = scan_link_label_rest(&text[1..], &linebreak_handler)?; - (byte_index + 1, ReferenceLabel::Link(cow)) - }; - Some(pair) -} - -fn scan_reference<'a, 'b>( - tree: &'a Tree, - text: &'b str, - cur: Option, -) -> RefScan<'b> { - let cur_ix = match cur { - None => return RefScan::Failed, - Some(cur_ix) => cur_ix, - }; - let start = tree[cur_ix].item.start; - let tail = &text.as_bytes()[start..]; - - if tail.starts_with(b"[]") { - let closing_node = tree[cur_ix].next.unwrap(); - RefScan::Collapsed(tree[closing_node].next) - } else if let Some((ix, ReferenceLabel::Link(label))) = scan_link_label(tree, &text[start..]) { - let next_node = scan_nodes_to_ix(tree, cur, start + ix); - RefScan::LinkLabel(label, next_node, start + ix) - } else { - RefScan::Failed - } -} - -#[derive(Clone, Default)] -struct LinkStack { - inner: Vec, - disabled_ix: usize, -} - -impl LinkStack { - fn push(&mut self, el: LinkStackEl) { - self.inner.push(el); - } - - fn pop(&mut self) -> Option { - let el = self.inner.pop(); - self.disabled_ix = std::cmp::min(self.disabled_ix, self.inner.len()); - el - } - - fn clear(&mut self) { - self.inner.clear(); - self.disabled_ix = 0; - } - - fn disable_all_links(&mut self) { - for el in &mut self.inner[self.disabled_ix..] { - if el.ty == LinkStackTy::Link { - el.ty = LinkStackTy::Disabled; - } - } - self.disabled_ix = self.inner.len(); - } -} - -#[derive(Clone, Debug)] -struct LinkStackEl { - node: TreeIndex, - ty: LinkStackTy, -} - -#[derive(PartialEq, Clone, Debug)] -enum LinkStackTy { - Link, - Image, - Disabled, -} - -#[derive(Clone)] -struct LinkDef<'a> { - dest: CowStr<'a>, - title: Option>, -} - -/// Tracks tree indices of code span delimiters of each length. It should prevent -/// quadratic scanning behaviours by providing (amortized) constant time lookups. -struct CodeDelims { - inner: HashMap>, - seen_first: bool, -} - -impl CodeDelims { - fn new() -> Self { - Self { - inner: Default::default(), - seen_first: false, - } - } - - fn insert(&mut self, count: usize, ix: TreeIndex) { - if self.seen_first { - self.inner - .entry(count) - .or_insert_with(Default::default) - .push_back(ix); - } else { - // Skip the first insert, since that delimiter will always - // be an opener and not a closer. - self.seen_first = true; - } - } - - fn is_populated(&self) -> bool { - !self.inner.is_empty() - } - - fn find(&mut self, open_ix: TreeIndex, count: usize) -> Option { - while let Some(ix) = self.inner.get_mut(&count)?.pop_front() { - if ix > open_ix { - return Some(ix); - } - } - None - } - - fn clear(&mut self) { - self.inner.clear(); - self.seen_first = false; - } -} - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct LinkIndex(usize); - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct CowIndex(usize); - -#[derive(Copy, Clone, PartialEq, Eq, Debug)] -struct AlignmentIndex(usize); - -#[derive(Clone)] -struct Allocations<'a> { - refdefs: HashMap, LinkDef<'a>>, - links: Vec<(LinkType, CowStr<'a>, CowStr<'a>)>, - cows: Vec>, - alignments: Vec>, -} - -impl<'a> Allocations<'a> { - fn new() -> Self { - Self { - refdefs: HashMap::new(), - links: Vec::with_capacity(128), - cows: Vec::new(), - alignments: Vec::new(), - } - } - - fn allocate_cow(&mut self, cow: CowStr<'a>) -> CowIndex { - let ix = self.cows.len(); - self.cows.push(cow); - CowIndex(ix) - } - - fn allocate_link(&mut self, ty: LinkType, url: CowStr<'a>, title: CowStr<'a>) -> LinkIndex { - let ix = self.links.len(); - self.links.push((ty, url, title)); - LinkIndex(ix) - } - - fn allocate_alignment(&mut self, alignment: Vec) -> AlignmentIndex { - let ix = self.alignments.len(); - self.alignments.push(alignment); - AlignmentIndex(ix) - } -} - -impl<'a> Index for Allocations<'a> { - type Output = CowStr<'a>; - - fn index(&self, ix: CowIndex) -> &Self::Output { - self.cows.index(ix.0) - } -} - -impl<'a> Index for Allocations<'a> { - type Output = (LinkType, CowStr<'a>, CowStr<'a>); - - fn index(&self, ix: LinkIndex) -> &Self::Output { - self.links.index(ix.0) - } -} - -impl<'a> Index for Allocations<'a> { - type Output = Vec; - - fn index(&self, ix: AlignmentIndex) -> &Self::Output { - self.alignments.index(ix.0) - } -} - -/// A struct containing information on the reachability of certain inline HTML -/// elements. In particular, for cdata elements (` { - text: &'a str, - tree: Tree, - allocs: Allocations<'a>, - broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, - html_scan_guard: HtmlScanGuard, - - // used by inline passes. store them here for reuse - inline_stack: InlineStack, - link_stack: LinkStack, -} - -impl<'a> Parser<'a> { - /// Creates a new event iterator for a markdown string without any options enabled. - pub fn new(text: &'a str) -> Parser<'a> { - Parser::new_ext(text, Options::empty()) - } - - /// Creates a new event iterator for a markdown string with given options. - pub fn new_ext(text: &'a str, options: Options) -> Parser<'a> { - Parser::new_with_broken_link_callback(text, options, None) - } - - /// In case the parser encounters any potential links that have a broken - /// reference (e.g `[foo]` when there is no `[foo]: ` entry at the bottom) - /// the provided callback will be called with the reference name, - /// and the returned pair will be used as the link name and title if it is not - /// `None`. - pub fn new_with_broken_link_callback( - text: &'a str, - options: Options, - broken_link_callback: Option<&'a dyn Fn(&str, &str) -> Option<(String, String)>>, - ) -> Parser<'a> { - let first_pass = FirstPass::new(text, options); - let (mut tree, allocs) = first_pass.run(); - tree.reset(); - let inline_stack = Default::default(); - let link_stack = Default::default(); - let html_scan_guard = Default::default(); - Parser { - text, - tree, - allocs, - broken_link_callback, - inline_stack, - link_stack, - html_scan_guard, - } - } - - /// Handle inline markup. - /// - /// When the parser encounters any item indicating potential inline markup, all - /// inline markup passes are run on the remainder of the chain. - /// - /// Note: there's some potential for optimization here, but that's future work. - fn handle_inline(&mut self) { - self.handle_inline_pass1(); - self.handle_emphasis(); - } - - /// Handle inline HTML, code spans, and links. - /// - /// This function handles both inline HTML and code spans, because they have - /// the same precedence. It also handles links, even though they have lower - /// precedence, because the URL of links must not be processed. - fn handle_inline_pass1(&mut self) { - let mut code_delims = CodeDelims::new(); - let mut cur = self.tree.cur(); - let mut prev = None; - - let block_end = self.tree[self.tree.peek_up().unwrap()].item.end; - let block_text = &self.text[..block_end]; - - while let Some(mut cur_ix) = cur { - match self.tree[cur_ix].item.body { - ItemBody::MaybeHtml => { - let next = self.tree[cur_ix].next; - let autolink = if let Some(next_ix) = next { - scan_autolink(block_text, self.tree[next_ix].item.start) - } else { - None - }; - - if let Some((ix, uri, link_type)) = autolink { - let node = scan_nodes_to_ix(&self.tree, next, ix); - let text_node = self.tree.create_node(Item { - start: self.tree[cur_ix].item.start + 1, - end: ix - 1, - body: ItemBody::Text, - }); - let link_ix = self.allocs.allocate_link(link_type, uri, "".into()); - self.tree[cur_ix].item.body = ItemBody::Link(link_ix); - self.tree[cur_ix].item.end = ix; - self.tree[cur_ix].next = node; - self.tree[cur_ix].child = Some(text_node); - prev = cur; - cur = node; - if let Some(node_ix) = cur { - self.tree[node_ix].item.start = max(self.tree[node_ix].item.start, ix); - } - continue; - } else { - let inline_html = if let Some(next_ix) = next { - self.scan_inline_html( - block_text.as_bytes(), - self.tree[next_ix].item.start, - ) - } else { - None - }; - if let Some(ix) = inline_html { - let node = scan_nodes_to_ix(&self.tree, next, ix); - self.tree[cur_ix].item.body = ItemBody::Html; - self.tree[cur_ix].item.end = ix; - self.tree[cur_ix].next = node; - prev = cur; - cur = node; - if let Some(node_ix) = cur { - self.tree[node_ix].item.start = - max(self.tree[node_ix].item.start, ix); - } - continue; - } - } - self.tree[cur_ix].item.body = ItemBody::Text; - } - ItemBody::MaybeCode(mut search_count, preceded_by_backslash) => { - if preceded_by_backslash { - search_count -= 1; - if search_count == 0 { - self.tree[cur_ix].item.body = ItemBody::Text; - prev = cur; - cur = self.tree[cur_ix].next; - continue; - } - } - - if code_delims.is_populated() { - // we have previously scanned all codeblock delimiters, - // so we can reuse that work - if let Some(scan_ix) = code_delims.find(cur_ix, search_count) { - self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); - } else { - self.tree[cur_ix].item.body = ItemBody::Text; - } - } else { - // we haven't previously scanned all codeblock delimiters, - // so walk the AST - let mut scan = if search_count > 0 { - self.tree[cur_ix].next - } else { - None - }; - while let Some(scan_ix) = scan { - if let ItemBody::MaybeCode(delim_count, _) = - self.tree[scan_ix].item.body - { - if search_count == delim_count { - self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); - code_delims.clear(); - break; - } else { - code_delims.insert(delim_count, scan_ix); - } - } - scan = self.tree[scan_ix].next; - } - if scan == None { - self.tree[cur_ix].item.body = ItemBody::Text; - } - } - } - ItemBody::MaybeLinkOpen => { - self.tree[cur_ix].item.body = ItemBody::Text; - self.link_stack.push(LinkStackEl { - node: cur_ix, - ty: LinkStackTy::Link, - }); - } - ItemBody::MaybeImage => { - self.tree[cur_ix].item.body = ItemBody::Text; - self.link_stack.push(LinkStackEl { - node: cur_ix, - ty: LinkStackTy::Image, - }); - } - ItemBody::MaybeLinkClose => { - self.tree[cur_ix].item.body = ItemBody::Text; - if let Some(tos) = self.link_stack.pop() { - if tos.ty == LinkStackTy::Disabled { - continue; - } - let next = self.tree[cur_ix].next; - if let Some((next_ix, url, title)) = - self.scan_inline_link(block_text, self.tree[cur_ix].item.end, next) - { - let next_node = scan_nodes_to_ix(&self.tree, next, next_ix); - if let Some(prev_ix) = prev { - self.tree[prev_ix].next = None; - } - cur = Some(tos.node); - cur_ix = tos.node; - let link_ix = self.allocs.allocate_link(LinkType::Inline, url, title); - self.tree[cur_ix].item.body = if tos.ty == LinkStackTy::Image { - ItemBody::Image(link_ix) - } else { - ItemBody::Link(link_ix) - }; - self.tree[cur_ix].child = self.tree[cur_ix].next; - self.tree[cur_ix].next = next_node; - self.tree[cur_ix].item.end = next_ix; - if let Some(next_node_ix) = next_node { - self.tree[next_node_ix].item.start = - max(self.tree[next_node_ix].item.start, next_ix); - } - - if tos.ty == LinkStackTy::Link { - self.link_stack.disable_all_links(); - } - } else { - // ok, so its not an inline link. maybe it is a reference - // to a defined link? - let scan_result = scan_reference(&self.tree, block_text, next); - let (node_after_link, link_type) = match scan_result { - // [label][reference] - RefScan::LinkLabel(_, next_node, _) => { - (next_node, LinkType::Reference) - } - // [] - RefScan::Collapsed(next_node) => (next_node, LinkType::Collapsed), - // [shortcut] - // - // [shortcut]: /blah - RefScan::Failed => (next, LinkType::Shortcut), - }; - - // (label, source_ix end) - let label: Option<(ReferenceLabel<'a>, usize)> = match scan_result { - RefScan::LinkLabel(l, _, end_ix) => { - Some((ReferenceLabel::Link(l), end_ix)) - } - RefScan::Collapsed(..) | RefScan::Failed => { - // No label? maybe it is a shortcut reference - let label_start = self.tree[tos.node].item.end - 1; - scan_link_label( - &self.tree, - &self.text[label_start..self.tree[cur_ix].item.end], - ) - .map(|(ix, label)| (label, label_start + ix)) - } - }; - - // see if it's a footnote reference - if let Some((ReferenceLabel::Footnote(l), end)) = label { - self.tree[tos.node].next = node_after_link; - self.tree[tos.node].child = None; - self.tree[tos.node].item.body = - ItemBody::FootnoteReference(self.allocs.allocate_cow(l)); - self.tree[tos.node].item.end = end; - prev = Some(tos.node); - cur = node_after_link; - self.link_stack.clear(); - continue; - } else if let Some((ReferenceLabel::Link(link_label), end)) = label { - let type_url_title = self - .allocs - .refdefs - .get(&UniCase::new(link_label.as_ref().into())) - .map(|matching_def| { - // found a matching definition! - let title = matching_def - .title - .as_ref() - .cloned() - .unwrap_or_else(|| "".into()); - let url = matching_def.dest.clone(); - (link_type, url, title) - }) - .or_else(|| { - self.broken_link_callback - .and_then(|callback| { - // looked for matching definition, but didn't find it. try to fix - // link with callback, if it is defined - callback(link_label.as_ref(), link_label.as_ref()) - }) - .map(|(url, title)| { - (link_type.to_unknown(), url.into(), title.into()) - }) - }); - - if let Some((def_link_type, url, title)) = type_url_title { - let link_ix = - self.allocs.allocate_link(def_link_type, url, title); - self.tree[tos.node].item.body = if tos.ty == LinkStackTy::Image - { - ItemBody::Image(link_ix) - } else { - ItemBody::Link(link_ix) - }; - let label_node = self.tree[tos.node].next; - - // lets do some tree surgery to add the link to the tree - // 1st: skip the label node and close node - self.tree[tos.node].next = node_after_link; - - // then, if it exists, add the label node as a child to the link node - if label_node != cur { - self.tree[tos.node].child = label_node; - - // finally: disconnect list of children - if let Some(prev_ix) = prev { - self.tree[prev_ix].next = None; - } - } - - self.tree[tos.node].item.end = end; - - // set up cur so next node will be node_after_link - cur = Some(tos.node); - cur_ix = tos.node; - - if tos.ty == LinkStackTy::Link { - self.link_stack.disable_all_links(); - } - } - } - } - } - } - _ => (), - } - prev = cur; - cur = self.tree[cur_ix].next; - } - self.link_stack.clear(); - } - - fn handle_emphasis(&mut self) { - let mut prev = None; - let mut prev_ix: TreeIndex; - let mut cur = self.tree.cur(); - while let Some(mut cur_ix) = cur { - if let ItemBody::MaybeEmphasis(mut count, can_open, can_close) = - self.tree[cur_ix].item.body - { - let c = self.text.as_bytes()[self.tree[cur_ix].item.start]; - let both = can_open && can_close; - if can_close { - while let Some(el) = - self.inline_stack.find_match(&mut self.tree, c, count, both) - { - // have a match! - if let Some(prev_ix) = prev { - self.tree[prev_ix].next = None; - } - let match_count = min(count, el.count); - // start, end are tree node indices - let mut end = cur_ix - 1; - let mut start = el.start + el.count; - - // work from the inside out - while start > el.start + el.count - match_count { - let (inc, ty) = if c == b'~' { - (2, ItemBody::Strikethrough) - } else if start > el.start + el.count - match_count + 1 { - (2, ItemBody::Strong) - } else { - (1, ItemBody::Emphasis) - }; - - let root = start - inc; - end = end + inc; - self.tree[root].item.body = ty; - self.tree[root].item.end = self.tree[end].item.end; - self.tree[root].child = Some(start); - self.tree[root].next = None; - start = root; - } - - // set next for top most emph level - prev_ix = el.start + el.count - match_count; - prev = Some(prev_ix); - cur = self.tree[cur_ix + match_count - 1].next; - self.tree[prev_ix].next = cur; - - if el.count > match_count { - self.inline_stack.push(InlineEl { - start: el.start, - count: el.count - match_count, - c: el.c, - both, - }) - } - count -= match_count; - if count > 0 { - cur_ix = cur.unwrap(); - } else { - break; - } - } - } - if count > 0 { - if can_open { - self.inline_stack.push(InlineEl { - start: cur_ix, - count, - c, - both, - }); - } else { - for i in 0..count { - self.tree[cur_ix + i].item.body = ItemBody::Text; - } - } - prev_ix = cur_ix + count - 1; - prev = Some(prev_ix); - cur = self.tree[prev_ix].next; - } - } else { - prev = cur; - cur = self.tree[cur_ix].next; - } - } - self.inline_stack.pop_all(&mut self.tree); - } - - /// Returns next byte index, url and title. - fn scan_inline_link( - &self, - underlying: &'a str, - mut ix: usize, - node: Option, - ) -> Option<(usize, CowStr<'a>, CowStr<'a>)> { - if scan_ch(&underlying.as_bytes()[ix..], b'(') == 0 { - return None; - } - ix += 1; - ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); - - let (dest_length, dest) = scan_link_dest(underlying, ix, LINK_MAX_NESTED_PARENS)?; - let dest = unescape(dest); - ix += dest_length; - - ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); - - let title = if let Some((bytes_scanned, t)) = self.scan_link_title(underlying, ix, node) { - ix += bytes_scanned; - ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); - t - } else { - "".into() - }; - if scan_ch(&underlying.as_bytes()[ix..], b')') == 0 { - return None; - } - ix += 1; - - Some((ix, dest, title)) - } - - // returns (bytes scanned, title cow) - fn scan_link_title( - &self, - text: &'a str, - start_ix: usize, - node: Option, - ) -> Option<(usize, CowStr<'a>)> { - let bytes = text.as_bytes(); - let open = match bytes.get(start_ix) { - Some(b @ b'\'') | Some(b @ b'\"') | Some(b @ b'(') => *b, - _ => return None, - }; - let close = if open == b'(' { b')' } else { open }; - - let mut title = String::new(); - let mut mark = start_ix + 1; - let mut i = start_ix + 1; - - while i < bytes.len() { - let c = bytes[i]; - - if c == close { - let cow = if mark == 1 { - (i - start_ix + 1, text[mark..i].into()) - } else { - title.push_str(&text[mark..i]); - (i - start_ix + 1, title.into()) - }; - - return Some(cow); - } - if c == open { - return None; - } - - if c == b'\n' || c == b'\r' { - if let Some(node_ix) = scan_nodes_to_ix(&self.tree, node, i + 1) { - if self.tree[node_ix].item.start > i { - title.push_str(&text[mark..i]); - title.push('\n'); - i = self.tree[node_ix].item.start; - mark = i; - continue; - } - } - } - if c == b'&' { - if let (n, Some(value)) = scan_entity(&bytes[i..]) { - title.push_str(&text[mark..i]); - title.push_str(&value); - i += n; - mark = i; - continue; - } - } - if c == b'\\' && i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) { - title.push_str(&text[mark..i]); - i += 1; - mark = i; - } - - i += 1; - } - - None - } - - /// Make a code span. - /// - /// Both `open` and `close` are matching MaybeCode items. - fn make_code_span(&mut self, open: TreeIndex, close: TreeIndex, preceding_backslash: bool) { - let first_ix = open + 1; - let last_ix = close - 1; - let bytes = self.text.as_bytes(); - let mut span_start = self.tree[open].item.end; - let mut span_end = self.tree[close].item.start; - let mut buf: Option = None; - - // detect all-space sequences, since they are kept as-is as of commonmark 0.29 - if !bytes[span_start..span_end].iter().all(|&b| b == b' ') { - let opening = match bytes[span_start] { - b' ' | b'\r' | b'\n' => true, - _ => false, - }; - let closing = match bytes[span_end - 1] { - b' ' | b'\r' | b'\n' => true, - _ => false, - }; - let drop_enclosing_whitespace = opening && closing; - - if drop_enclosing_whitespace { - span_start += 1; - if span_start < span_end { - span_end -= 1; - } - } - - let mut ix = first_ix; - - while ix < close { - if let ItemBody::HardBreak | ItemBody::SoftBreak = self.tree[ix].item.body { - if drop_enclosing_whitespace { - // check whether break should be ignored - if ix == first_ix { - ix = ix + 1; - span_start = min(span_end, self.tree[ix].item.start); - continue; - } else if ix == last_ix && last_ix > first_ix { - ix = ix + 1; - continue; - } - } - - let end = bytes[self.tree[ix].item.start..] - .iter() - .position(|&b| b == b'\r' || b == b'\n') - .unwrap() - + self.tree[ix].item.start; - if let Some(ref mut buf) = buf { - buf.push_str(&self.text[self.tree[ix].item.start..end]); - buf.push(' '); - } else { - let mut new_buf = String::with_capacity(span_end - span_start); - new_buf.push_str(&self.text[span_start..end]); - new_buf.push(' '); - buf = Some(new_buf); - } - } else if let Some(ref mut buf) = buf { - let end = if ix == last_ix { - span_end - } else { - self.tree[ix].item.end - }; - buf.push_str(&self.text[self.tree[ix].item.start..end]); - } - ix = ix + 1; - } - } - - let cow = if let Some(buf) = buf { - buf.into() - } else { - self.text[span_start..span_end].into() - }; - if preceding_backslash { - self.tree[open].item.body = ItemBody::Text; - self.tree[open].item.end = self.tree[open].item.start + 1; - self.tree[open].next = Some(close); - self.tree[close].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); - self.tree[close].item.start = self.tree[open].item.start + 1; - } else { - self.tree[open].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); - self.tree[open].item.end = self.tree[close].item.end; - self.tree[open].next = self.tree[close].next; - } - } - - /// Returns the next byte offset on success. - fn scan_inline_html(&mut self, bytes: &[u8], ix: usize) -> Option { - let c = *bytes.get(ix)?; - if c == b'!' { - scan_inline_html_comment(bytes, ix + 1, &mut self.html_scan_guard) - } else if c == b'?' { - scan_inline_html_processing(bytes, ix + 1, &mut self.html_scan_guard) - } else { - let i = scan_html_block_inner( - &bytes[ix..], - Some(&|_bytes| { - let mut line_start = LineStart::new(bytes); - let _ = scan_containers(&self.tree, &mut line_start); - line_start.bytes_scanned() - }), - )?; - Some(i + ix) - } - } - - /// Consumes the event iterator and produces an iterator that produces - /// `(Event, Range)` pairs, where the `Range` value maps to the corresponding - /// range in the markdown source. - pub fn into_offset_iter(self) -> OffsetIter<'a> { - OffsetIter { inner: self } - } -} - -pub(crate) enum LoopInstruction { - /// Continue looking for more special bytes, but skip next few bytes. - ContinueAndSkip(usize), - /// Break looping immediately, returning with the given index and value. - BreakAtWith(usize, T), -} - -/// This function walks the byte slices from the given index and -/// calls the callback function on all bytes (and their indices) that are in the following set: -/// `` ` ``, `\`, `&`, `*`, `_`, `~`, `!`, `<`, `[`, `]`, `|`, `\r`, `\n` -/// It is guaranteed not call the callback on other bytes. -/// Whenever `callback(ix, byte)` returns a `ContinueAndSkip(n)` value, the callback -/// will not be called with an index that is less than `ix + n + 1`. -/// When the callback returns a `BreakAtWith(end_ix, opt+val)`, no more callbacks will be -/// called and the function returns immediately with the return value `(end_ix, opt_val)`. -/// If `BreakAtWith(..)` is never returned, this function will return the first -/// index that is outside the byteslice bound and a `None` value. -fn iterate_special_bytes(bytes: &[u8], ix: usize, callback: F) -> (usize, Option) -where - F: FnMut(usize, u8) -> LoopInstruction>, -{ - #[cfg(all(target_arch = "x86_64", feature = "simd"))] - { - crate::simd::iterate_special_bytes(bytes, ix, callback) - } - #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] - { - scalar_iterate_special_bytes(bytes, ix, callback) - } -} - -const fn special_bytes() -> [bool; 256] { - let mut bytes = [false; 256]; - bytes[b'<' as usize] = true; - bytes[b'!' as usize] = true; - bytes[b'[' as usize] = true; - bytes[b'~' as usize] = true; - bytes[b'`' as usize] = true; - bytes[b'|' as usize] = true; - bytes[b'\\' as usize] = true; - bytes[b'*' as usize] = true; - bytes[b'_' as usize] = true; - bytes[b'\r' as usize] = true; - bytes[b'\n' as usize] = true; - bytes[b']' as usize] = true; - bytes[b'&' as usize] = true; - bytes -} - -pub(crate) fn scalar_iterate_special_bytes( - bytes: &[u8], - mut ix: usize, - mut callback: F, -) -> (usize, Option) -where - F: FnMut(usize, u8) -> LoopInstruction>, -{ - let special_bytes = special_bytes(); - - while ix < bytes.len() { - let b = bytes[ix]; - if special_bytes[b as usize] { - match callback(ix, b) { - LoopInstruction::ContinueAndSkip(skip) => { - ix += skip; - } - LoopInstruction::BreakAtWith(ix, val) => { - return (ix, val); - } - } - } - ix += 1; - } - - (ix, None) -} - -/// Markdown event and source range iterator. -/// -/// Generates tuples where the first element is the markdown event and the second -/// is a the corresponding range in the source string. -/// -/// Constructed from a `Parser` using its -/// [`into_offset_iter`](struct.Parser.html#method.into_offset_iter) method. -pub struct OffsetIter<'a> { - inner: Parser<'a>, -} - -impl<'a> Iterator for OffsetIter<'a> { - type Item = (Event<'a>, Range); - - fn next(&mut self) -> Option { - match self.inner.tree.cur() { - None => { - let ix = self.inner.tree.pop()?; - let tag = item_to_tag(&self.inner.tree[ix].item, &self.inner.allocs); - self.inner.tree.next_sibling(ix); - Some(( - Event::End(tag), - self.inner.tree[ix].item.start..self.inner.tree[ix].item.end, - )) - } - Some(cur_ix) => { - if self.inner.tree[cur_ix].item.body.is_inline() { - self.inner.handle_inline(); - } - - let node = self.inner.tree[cur_ix]; - let item = node.item; - let event = item_to_event(item, self.inner.text, &self.inner.allocs); - if let Event::Start(..) = event { - self.inner.tree.push(); - } else { - self.inner.tree.next_sibling(cur_ix); - } - Some((event, item.start..item.end)) - } - } - } -} - -fn item_to_tag<'a>(item: &Item, allocs: &Allocations<'a>) -> Tag<'a> { - match item.body { - ItemBody::Paragraph => Tag::Paragraph, - ItemBody::Emphasis => Tag::Emphasis, - ItemBody::Strong => Tag::Strong, - ItemBody::Strikethrough => Tag::Strikethrough, - ItemBody::Link(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Link(*link_type, url.clone(), title.clone()) - } - ItemBody::Image(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Image(*link_type, url.clone(), title.clone()) - } - ItemBody::Heading(level) => Tag::Heading(level), - ItemBody::FencedCodeBlock(cow_ix) => { - Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) - } - ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), - ItemBody::BlockQuote => Tag::BlockQuote, - ItemBody::List(_, c, listitem_start) => { - if c == b'.' || c == b')' { - Tag::List(Some(listitem_start)) - } else { - Tag::List(None) - } - } - ItemBody::ListItem(_) => Tag::Item, - ItemBody::TableHead => Tag::TableHead, - ItemBody::TableCell => Tag::TableCell, - ItemBody::TableRow => Tag::TableRow, - ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), - ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), - _ => panic!("unexpected item body {:?}", item.body), - } -} - -fn item_to_event<'a>(item: Item, text: &'a str, allocs: &Allocations<'a>) -> Event<'a> { - let tag = match item.body { - ItemBody::Text => return Event::Text(text[item.start..item.end].into()), - ItemBody::Code(cow_ix) => return Event::Code(allocs[cow_ix].clone()), - ItemBody::SynthesizeText(cow_ix) => return Event::Text(allocs[cow_ix].clone()), - ItemBody::Html => return Event::Html(text[item.start..item.end].into()), - ItemBody::SoftBreak => return Event::SoftBreak, - ItemBody::HardBreak => return Event::HardBreak, - ItemBody::FootnoteReference(cow_ix) => { - return Event::FootnoteReference(allocs[cow_ix].clone()) - } - ItemBody::TaskListMarker(checked) => return Event::TaskListMarker(checked), - ItemBody::Rule => return Event::Rule, - - ItemBody::Paragraph => Tag::Paragraph, - ItemBody::Emphasis => Tag::Emphasis, - ItemBody::Strong => Tag::Strong, - ItemBody::Strikethrough => Tag::Strikethrough, - ItemBody::Link(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Link(*link_type, url.clone(), title.clone()) - } - ItemBody::Image(link_ix) => { - let &(ref link_type, ref url, ref title) = allocs.index(link_ix); - Tag::Image(*link_type, url.clone(), title.clone()) - } - ItemBody::Heading(level) => Tag::Heading(level), - ItemBody::FencedCodeBlock(cow_ix) => { - Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) - } - ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), - ItemBody::BlockQuote => Tag::BlockQuote, - ItemBody::List(_, c, listitem_start) => { - if c == b'.' || c == b')' { - Tag::List(Some(listitem_start)) - } else { - Tag::List(None) - } - } - ItemBody::ListItem(_) => Tag::Item, - ItemBody::TableHead => Tag::TableHead, - ItemBody::TableCell => Tag::TableCell, - ItemBody::TableRow => Tag::TableRow, - ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), - ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), - _ => panic!("unexpected item body {:?}", item.body), - }; - - Event::Start(tag) -} - -// https://english.stackexchange.com/a/285573 -fn surgerize_tight_list(tree: &mut Tree, list_ix: TreeIndex) { - let mut list_item = tree[list_ix].child; - while let Some(listitem_ix) = list_item { - // first child is special, controls how we repoint list_item.child - let list_item_firstborn = tree[listitem_ix].child; - - // Check that list item has children - this is not necessarily the case! - if let Some(firstborn_ix) = list_item_firstborn { - if let ItemBody::Paragraph = tree[firstborn_ix].item.body { - tree[listitem_ix].child = tree[firstborn_ix].child; - } - - let mut list_item_child = Some(firstborn_ix); - let mut node_to_repoint = None; - while let Some(child_ix) = list_item_child { - // surgerize paragraphs - let repoint_ix = if let ItemBody::Paragraph = tree[child_ix].item.body { - if let Some(child_firstborn) = tree[child_ix].child { - if let Some(repoint_ix) = node_to_repoint { - tree[repoint_ix].next = Some(child_firstborn); - } - let mut child_lastborn = child_firstborn; - while let Some(lastborn_next_ix) = tree[child_lastborn].next { - child_lastborn = lastborn_next_ix; - } - child_lastborn - } else { - child_ix - } - } else { - child_ix - }; - - node_to_repoint = Some(repoint_ix); - tree[repoint_ix].next = tree[child_ix].next; - list_item_child = tree[child_ix].next; - } - } - - list_item = tree[listitem_ix].next; - } -} - -impl<'a> Iterator for Parser<'a> { - type Item = Event<'a>; - - fn next(&mut self) -> Option> { - match self.tree.cur() { - None => { - let ix = self.tree.pop()?; - let tag = item_to_tag(&self.tree[ix].item, &self.allocs); - self.tree.next_sibling(ix); - Some(Event::End(tag)) - } - Some(cur_ix) => { - if self.tree[cur_ix].item.body.is_inline() { - self.handle_inline(); - } - - let node = self.tree[cur_ix]; - let item = node.item; - let event = item_to_event(item, self.text, &self.allocs); - if let Event::Start(..) = event { - self.tree.push(); - } else { - self.tree.next_sibling(cur_ix); - } - Some(event) - } - } - } -} - -#[cfg(test)] -mod test { - use super::*; - use crate::tree::Node; - - // TODO: move these tests to tests/html.rs? - - fn parser_with_extensions(text: &str) -> Parser<'_> { - let mut opts = Options::empty(); - opts.insert(Options::ENABLE_TABLES); - opts.insert(Options::ENABLE_FOOTNOTES); - opts.insert(Options::ENABLE_STRIKETHROUGH); - opts.insert(Options::ENABLE_TASKLISTS); - - Parser::new_ext(text, opts) - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn node_size() { - let node_size = std::mem::size_of::>(); - assert_eq!(48, node_size); - } - - #[test] - #[cfg(target_pointer_width = "64")] - fn body_size() { - let body_size = std::mem::size_of::(); - assert_eq!(16, body_size); - } - - #[test] - fn single_open_fish_bracket() { - // dont crash - assert_eq!(3, Parser::new("<").count()); - } - - #[test] - fn lone_hashtag() { - // dont crash - assert_eq!(2, Parser::new("#").count()); - } - - #[test] - fn lots_of_backslashes() { - // dont crash - Parser::new("\\\\\r\r").count(); - Parser::new("\\\r\r\\.\\\\\r\r\\.\\").count(); - } - - #[test] - fn issue_320() { - // dont crash - parser_with_extensions(":\r\t> |\r:\r\t> |\r").count(); - } - - #[test] - fn issue_319() { - // dont crash - parser_with_extensions("|\r-]([^|\r-]([^").count(); - parser_with_extensions("|\r\r=][^|\r\r=][^car").count(); - } - - #[test] - fn issue_303() { - // dont crash - parser_with_extensions("[^\r\ra]").count(); - parser_with_extensions("\r\r]Z[^\x00\r\r]Z[^\x00").count(); - } - - #[test] - fn issue_313() { - // dont crash - parser_with_extensions("*]0[^\r\r*]0[^").count(); - parser_with_extensions("[^\r> `][^\r> `][^\r> `][").count(); - } - - #[test] - fn issue_311() { - // dont crash - parser_with_extensions("\\\u{0d}-\u{09}\\\u{0d}-\u{09}").count(); - } - - #[test] - fn issue_283() { - let input = std::str::from_utf8(b"\xf0\x9b\xb2\x9f - \\\n> - ").count(); - parser_with_extensions("- \n\n").count(); - } - - #[test] - fn issue_306() { - // dont crash - parser_with_extensions("*\r_<__*\r_<__*\r_<__*\r_<__").count(); - } - - #[test] - fn issue_305() { - // dont crash - parser_with_extensions("_6**6*_*").count(); - } - - #[test] - fn another_emphasis_panic() { - parser_with_extensions("*__#_#__*").count(); - } - - #[test] - fn offset_iter() { - let event_offsets: Vec<_> = Parser::new("*hello* world") - .into_offset_iter() - .map(|(_ev, range)| range) - .collect(); - let expected_offsets = vec![(0..13), (0..7), (1..6), (0..7), (7..13), (0..13)]; - assert_eq!(expected_offsets, event_offsets); - } - - #[test] - fn reference_link_offsets() { - let range = - Parser::new("# H1\n[testing][Some reference]\n\n[Some reference]: https://github.com") - .into_offset_iter() - .filter_map(|(ev, range)| match ev { - Event::Start(Tag::Link(LinkType::Reference, ..), ..) => Some(range), - _ => None, - }) - .next() - .unwrap(); - assert_eq!(5..30, range); - } - - #[test] - fn footnote_offsets() { - let range = Parser::new("Testing this[^1] out.\n\n[^1]: Footnote.") - .into_offset_iter() - .filter_map(|(ev, range)| match ev { - Event::FootnoteReference(..) => Some(range), - _ => None, - }) - .next() - .unwrap(); - assert_eq!(12..16, range); - } - - #[test] - fn table_offset() { - let markdown = "a\n\nTesting|This|Outtt\n--|:--:|--:\nSome Data|Other data|asdf"; - let event_offset = parser_with_extensions(markdown) - .into_offset_iter() - .map(|(_ev, range)| range) - .nth(3) - .unwrap(); - let expected_offset = 3..59; - assert_eq!(expected_offset, event_offset); - } - - #[test] - fn offset_iter_issue_378() { - let event_offsets: Vec<_> = Parser::new("a [b](c) d") - .into_offset_iter() - .map(|(_ev, range)| range) - .collect(); - let expected_offsets = vec![(0..10), (0..2), (2..8), (3..4), (2..8), (8..10), (0..10)]; - assert_eq!(expected_offsets, event_offsets); - } - - #[test] - fn offset_iter_issue_404() { - let event_offsets: Vec<_> = Parser::new("###\n") - .into_offset_iter() - .map(|(_ev, range)| range) - .collect(); - let expected_offsets = vec![(0..4), (0..4)]; - assert_eq!(expected_offsets, event_offsets); - } - - // FIXME: add this one regression suite - #[test] - fn link_def_at_eof() { - let test_str = "[My site][world]\n\n[world]: https://vincentprouillet.com"; - let expected = "

    My site

    \n"; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn ref_def_at_eof() { - let test_str = "[test]:\\"; - let expected = ""; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn ref_def_cr_lf() { - let test_str = "[a]: /u\r\n\n[a]"; - let expected = "

    a

    \n"; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn no_dest_refdef() { - let test_str = "[a]:"; - let expected = "

    [a]:

    \n"; - - let mut buf = String::new(); - crate::html::push_html(&mut buf, Parser::new(test_str)); - assert_eq!(expected, buf); - } - - #[test] - fn simple_broken_link_callback() { - let test_str = "This is a link w/o def: [hello][world]"; - let parser = Parser::new_with_broken_link_callback( - test_str, - Options::empty(), - Some(&|norm, raw| { - assert_eq!("world", raw); - assert_eq!("world", norm); - Some(("YOLO".to_owned(), "SWAG".to_owned())) - }), - ); - let mut link_tag_count = 0; - for (typ, url, title) in parser.filter_map(|event| match event { - Event::Start(tag) | Event::End(tag) => match tag { - Tag::Link(typ, url, title) => Some((typ, url, title)), - _ => None, - }, - _ => None, - }) { - link_tag_count += 1; - assert_eq!(typ, LinkType::ReferenceUnknown); - assert_eq!(url.as_ref(), "YOLO"); - assert_eq!(title.as_ref(), "SWAG"); - } - assert!(link_tag_count > 0); - } - - #[test] - fn code_block_kind_check_fenced() { - let parser = Parser::new("hello\n```test\ntadam\n```"); - let mut found = 0; - for (ev, _range) in parser.into_offset_iter() { - match ev { - Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(syntax))) => { - assert_eq!(syntax.as_ref(), "test"); - found += 1; - } - _ => {} - } - } - assert_eq!(found, 1); - } - - #[test] - fn code_block_kind_check_indented() { - let parser = Parser::new("hello\n\n ```test\n tadam\nhello"); - let mut found = 0; - for (ev, _range) in parser.into_offset_iter() { - match ev { - Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => { - found += 1; - } - _ => {} - } - } - assert_eq!(found, 1); - } -} +// Copyright 2017 Google Inc. All rights reserved. +// +// 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. + +//! Tree-based two pass parser. + +use std::cmp::{max, min}; +use std::collections::{HashMap, VecDeque}; +use std::ops::{Index, Range}; + +use unicase::UniCase; + +use crate::linklabel::{scan_link_label_rest, LinkLabel, ReferenceLabel}; +use crate::scanners::*; +use crate::strings::CowStr; +use crate::tree::{Tree, TreeIndex}; + +// Allowing arbitrary depth nested parentheses inside link destinations +// can create denial of service vulnerabilities if we're not careful. +// The simplest countermeasure is to limit their depth, which is +// explicitly allowed by the spec as long as the limit is at least 3: +// https://spec.commonmark.org/0.29/#link-destination +const LINK_MAX_NESTED_PARENS: usize = 5; + +/// Codeblock kind. +#[derive(Clone, Debug, PartialEq)] +pub enum CodeBlockKind<'a> { + Indented, + /// The value contained in the tag describes the language of the code, which may be empty. + Fenced(CowStr<'a>), +} + +impl<'a> CodeBlockKind<'a> { + pub fn is_indented(&self) -> bool { + match *self { + CodeBlockKind::Indented => true, + _ => false, + } + } + + pub fn is_fenced(&self) -> bool { + match *self { + CodeBlockKind::Fenced(_) => true, + _ => false, + } + } +} + +/// Tags for elements that can contain other elements. +#[derive(Clone, Debug, PartialEq)] +pub enum Tag<'a> { + /// A paragraph of text and other inline elements. + Paragraph, + + /// A heading. The field indicates the level of the heading. + Heading(u32), + + BlockQuote, + /// A code block. + CodeBlock(CodeBlockKind<'a>), + + /// A list. If the list is ordered the field indicates the number of the first item. + /// Contains only list items. + List(Option), // TODO: add delim and tight for ast (not needed for html) + /// A list item. + Item, + /// A footnote definition. The value contained is the footnote's label by which it can + /// be referred to. + FootnoteDefinition(CowStr<'a>), + + /// A table. Contains a vector describing the text-alignment for each of its columns. + Table(Vec), + /// A table header. Contains only `TableRow`s. Note that the table body starts immediately + /// after the closure of the `TableHead` tag. There is no `TableBody` tag. + TableHead, + /// A table row. Is used both for header rows as body rows. Contains only `TableCell`s. + TableRow, + TableCell, + + // span-level tags + Emphasis, + Strong, + Strikethrough, + + /// A link. The first field is the link type, the second the destination URL and the third is a title. + Link(LinkType, CowStr<'a>, CowStr<'a>), + + /// An image. The first field is the link type, the second the destination URL and the third is a title. + Image(LinkType, CowStr<'a>, CowStr<'a>), +} + +/// Type specifier for inline links. See [the Tag::Link](enum.Tag.html#variant.Link) for more information. +#[derive(Clone, Debug, PartialEq, Copy)] +pub enum LinkType { + /// Inline link like `[foo](bar)` + Inline, + /// Reference link like `[foo][bar]` + Reference, + /// Reference without destination in the document, but resolved by the broken_link_callback + ReferenceUnknown, + /// Collapsed link like `[foo][]` + Collapsed, + /// Collapsed link without destination in the document, but resolved by the broken_link_callback + CollapsedUnknown, + /// Shortcut link like `[foo]` + Shortcut, + /// Shortcut without destination in the document, but resolved by the broken_link_callback + ShortcutUnknown, + /// Autolink like `` + Autolink, + /// Email address in autolink like `` + Email, +} + +impl LinkType { + fn to_unknown(self) -> Self { + match self { + LinkType::Reference => LinkType::ReferenceUnknown, + LinkType::Collapsed => LinkType::CollapsedUnknown, + LinkType::Shortcut => LinkType::ShortcutUnknown, + _ => unreachable!(), + } + } +} + +/// Markdown events that are generated in a preorder traversal of the document +/// tree, with additional `End` events whenever all of an inner node's children +/// have been visited. +#[derive(Clone, Debug, PartialEq)] +pub enum Event<'a> { + /// Start of a tagged element. Events that are yielded after this event + /// and before its corresponding `End` event are inside this element. + /// Start and end events are guaranteed to be balanced. + Start(Tag<'a>), + /// End of a tagged element. + End(Tag<'a>), + /// A text node. + Text(CowStr<'a>), + /// An inline code node. + Code(CowStr<'a>), + /// An HTML node. + Html(CowStr<'a>), + /// A reference to a footnote with given label, which may or may not be defined + /// by an event with a `Tag::FootnoteDefinition` tag. Definitions and references to them may + /// occur in any order. + FootnoteReference(CowStr<'a>), + /// A soft line break. + SoftBreak, + /// A hard line break. + HardBreak, + /// A horizontal ruler. + Rule, + /// A task list marker, rendered as a checkbox in HTML. Contains a true when it is checked. + TaskListMarker(bool), +} + +/// Table column text alignment. +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum Alignment { + /// Default text alignment. + None, + Left, + Center, + Right, +} + +bitflags! { + /// Option struct containing flags for enabling extra features + /// that are not part of the CommonMark spec. + pub struct Options: u32 { + const ENABLE_TABLES = 1 << 1; + const ENABLE_FOOTNOTES = 1 << 2; + const ENABLE_STRIKETHROUGH = 1 << 3; + const ENABLE_TASKLISTS = 1 << 4; + const ENABLE_SMART_PUNCTUATION = 1 << 5; + } +} + +#[derive(Debug, Default, Clone, Copy)] +struct Item { + start: usize, + end: usize, + body: ItemBody, +} + +#[derive(Debug, PartialEq, Clone, Copy)] +enum ItemBody { + Paragraph, + Text, + SoftBreak, + HardBreak, + + // These are possible inline items, need to be resolved in second pass. + + // repeats, can_open, can_close + MaybeEmphasis(usize, bool, bool), + // quote byte, can_open, can_close + MaybeSmartQuote(u8, bool, bool), + MaybeCode(usize, bool), // number of backticks, preceeded by backslash + MaybeHtml, + MaybeLinkOpen, + // bool indicates whether or not the preceeding section could be a reference + MaybeLinkClose(bool), + MaybeImage, + + // These are inline items after resolution. + Emphasis, + Strong, + Strikethrough, + Code(CowIndex), + Link(LinkIndex), + Image(LinkIndex), + FootnoteReference(CowIndex), + TaskListMarker(bool), // true for checked + + Rule, + Heading(u32), // heading level + FencedCodeBlock(CowIndex), + IndentCodeBlock, + Html, + OwnedHtml(CowIndex), + BlockQuote, + List(bool, u8, u64), // is_tight, list character, list start index + ListItem(usize), // indent level + SynthesizeText(CowIndex), + SynthesizeChar(char), + FootnoteDefinition(CowIndex), + + // Tables + Table(AlignmentIndex), + TableHead, + TableRow, + TableCell, + + // Dummy node at the top of the tree - should not be used otherwise! + Root, +} + +impl<'a> ItemBody { + fn is_inline(&self) -> bool { + match *self { + ItemBody::MaybeEmphasis(..) + | ItemBody::MaybeSmartQuote(..) + | ItemBody::MaybeHtml + | ItemBody::MaybeCode(..) + | ItemBody::MaybeLinkOpen + | ItemBody::MaybeLinkClose(..) + | ItemBody::MaybeImage => true, + _ => false, + } + } +} + +impl<'a> Default for ItemBody { + fn default() -> Self { + ItemBody::Root + } +} + +/// Scanning modes for `Parser`'s `parse_line` method. +#[derive(PartialEq, Eq, Copy, Clone)] +enum TableParseMode { + /// Inside a paragraph, scanning for table headers. + Scan, + /// Inside a table. + Active, + /// Inside a paragraph, not scanning for table headers. + Disabled, +} + +pub struct BrokenLink<'a> { + pub span: std::ops::Range, + pub link_type: LinkType, + pub reference: &'a str, +} + +/// State for the first parsing pass. +/// +/// The first pass resolves all block structure, generating an AST. Within a block, items +/// are in a linear chain with potential inline markup identified. +struct FirstPass<'a, 'b> { + text: &'a str, + tree: Tree, + begin_list_item: bool, + last_line_blank: bool, + allocs: Allocations<'a>, + options: Options, + list_nesting: usize, + lookup_table: &'b LookupTable, +} + +impl<'a, 'b> FirstPass<'a, 'b> { + fn new(text: &'a str, options: Options, lookup_table: &'b LookupTable) -> FirstPass<'a, 'b> { + // This is a very naive heuristic for the number of nodes + // we'll need. + let start_capacity = max(128, text.len() / 32); + let tree = Tree::with_capacity(start_capacity); + FirstPass { + text, + tree, + begin_list_item: false, + last_line_blank: false, + allocs: Allocations::new(), + options, + list_nesting: 0, + lookup_table, + } + } + + fn run(mut self) -> (Tree, Allocations<'a>) { + let mut ix = 0; + while ix < self.text.len() { + ix = self.parse_block(ix); + } + for _ in 0..self.tree.spine_len() { + self.pop(ix); + } + (self.tree, self.allocs) + } + + /// Returns offset after block. + fn parse_block(&mut self, mut start_ix: usize) -> usize { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[start_ix..]); + + let i = scan_containers(&self.tree, &mut line_start); + for _ in i..self.tree.spine_len() { + self.pop(start_ix); + } + + if self.options.contains(Options::ENABLE_FOOTNOTES) { + // finish footnote if it's still open and was preceeded by blank line + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::FootnoteDefinition(..) = self.tree[node_ix].item.body { + if self.last_line_blank { + self.pop(start_ix); + } + } + } + + // Footnote definitions of the form + // [^bar]: + // * anything really + let container_start = start_ix + line_start.bytes_scanned(); + if let Some(bytecount) = self.parse_footnote(container_start) { + start_ix = container_start + bytecount; + start_ix += scan_blank_line(&bytes[start_ix..]).unwrap_or(0); + line_start = LineStart::new(&bytes[start_ix..]); + } + } + + // Process new containers + loop { + let container_start = start_ix + line_start.bytes_scanned(); + if let Some((ch, index, indent)) = line_start.scan_list_marker() { + let after_marker_index = start_ix + line_start.bytes_scanned(); + self.continue_list(container_start, ch, index); + self.tree.append(Item { + start: container_start, + end: after_marker_index, // will get updated later if item not empty + body: ItemBody::ListItem(indent), + }); + self.tree.push(); + if let Some(n) = scan_blank_line(&bytes[after_marker_index..]) { + self.begin_list_item = true; + return after_marker_index + n; + } + if self.options.contains(Options::ENABLE_TASKLISTS) { + if let Some(is_checked) = line_start.scan_task_list_marker() { + self.tree.append(Item { + start: after_marker_index, + end: start_ix + line_start.bytes_scanned(), + body: ItemBody::TaskListMarker(is_checked), + }); + } + } + } else if line_start.scan_blockquote_marker() { + self.finish_list(start_ix); + self.tree.append(Item { + start: container_start, + end: 0, // will get set later + body: ItemBody::BlockQuote, + }); + self.tree.push(); + } else { + break; + } + } + + let ix = start_ix + line_start.bytes_scanned(); + + if let Some(n) = scan_blank_line(&bytes[ix..]) { + if let Some(node_ix) = self.tree.peek_up() { + match self.tree[node_ix].item.body { + ItemBody::BlockQuote => (), + _ => { + if self.begin_list_item { + // A list item can begin with at most one blank line. + self.pop(start_ix); + } + self.last_line_blank = true; + } + } + } + return ix + n; + } + + self.begin_list_item = false; + self.finish_list(start_ix); + + // Save `remaining_space` here to avoid needing to backtrack `line_start` for HTML blocks + let remaining_space = line_start.remaining_space(); + + let indent = line_start.scan_space_upto(4); + if indent == 4 { + let ix = start_ix + line_start.bytes_scanned(); + let remaining_space = line_start.remaining_space(); + return self.parse_indented_code_block(ix, remaining_space); + } + + let ix = start_ix + line_start.bytes_scanned(); + + // HTML Blocks + if bytes[ix] == b'<' { + // Types 1-5 are all detected by one function and all end with the same + // pattern + if let Some(html_end_tag) = get_html_end_tag(&bytes[(ix + 1)..]) { + return self.parse_html_block_type_1_to_5(ix, html_end_tag, remaining_space); + } + + // Detect type 6 + let possible_tag = scan_html_block_tag(&bytes[(ix + 1)..]).1; + if is_html_tag(possible_tag) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + + // Detect type 7 + if let Some(_html_bytes) = scan_html_type_7(&bytes[ix..]) { + return self.parse_html_block_type_6_or_7(ix, remaining_space); + } + } + + if let Ok(n) = scan_hrule(&bytes[ix..]) { + return self.parse_hrule(n, ix); + } + + if let Some(atx_size) = scan_atx_heading(&bytes[ix..]) { + return self.parse_atx_heading(ix, atx_size); + } + + // parse refdef + if let Some((bytecount, label, link_def)) = self.parse_refdef_total(ix) { + self.allocs.refdefs.entry(label).or_insert(link_def); + let ix = ix + bytecount; + // try to read trailing whitespace or it will register as a completely blank line + // TODO: shouldn't we do this for all block level items? + return ix + scan_blank_line(&bytes[ix..]).unwrap_or(0); + } + + if let Some((n, fence_ch)) = scan_code_fence(&bytes[ix..]) { + return self.parse_fenced_code_block(ix, indent, fence_ch, n); + } + self.parse_paragraph(ix) + } + + /// Returns the offset of the first line after the table. + /// Assumptions: current focus is a table element and the table header + /// matches the separator line (same number of columns). + fn parse_table(&mut self, table_cols: usize, head_start: usize, body_start: usize) -> usize { + // parse header. this shouldn't fail because we made sure the table header is ok + let (_sep_start, thead_ix) = self.parse_table_row_inner(head_start, table_cols); + self.tree[thead_ix].item.body = ItemBody::TableHead; + + // parse body + let mut ix = body_start; + while let Some((next_ix, _row_ix)) = self.parse_table_row(ix, table_cols) { + ix = next_ix; + } + + self.pop(ix); + ix + } + + /// Call this when containers are taken care of. + /// Returns bytes scanned, row_ix + fn parse_table_row_inner(&mut self, mut ix: usize, row_cells: usize) -> (usize, TreeIndex) { + let bytes = self.text.as_bytes(); + let mut cells = 0; + let mut final_cell_ix = None; + + let row_ix = self.tree.append(Item { + start: ix, + end: 0, // set at end of this function + body: ItemBody::TableRow, + }); + self.tree.push(); + + loop { + ix += scan_ch(&bytes[ix..], b'|'); + ix += scan_whitespace_no_nl(&bytes[ix..]); + + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + ix += eol_bytes; + break; + } + + let cell_ix = self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + self.tree.push(); + let (next_ix, _brk) = self.parse_line(ix, TableParseMode::Active); + let trailing_whitespace = scan_rev_while(&bytes[..next_ix], is_ascii_whitespace); + + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= trailing_whitespace; + } + + self.tree[cell_ix].item.end = next_ix - trailing_whitespace; + self.tree.pop(); + + ix = next_ix; + cells += 1; + + if cells == row_cells { + final_cell_ix = Some(cell_ix); + } + } + + // fill empty cells if needed + // note: this is where GFM and commonmark-extra diverge. we follow + // GFM here + for _ in cells..row_cells { + self.tree.append(Item { + start: ix, + end: ix, + body: ItemBody::TableCell, + }); + } + + // drop excess cells + if let Some(cell_ix) = final_cell_ix { + self.tree[cell_ix].next = None; + } + + self.pop(ix); + + (ix, row_ix) + } + + /// Returns first offset after the row and the tree index of the row. + fn parse_table_row(&mut self, mut ix: usize, row_cells: usize) -> Option<(usize, TreeIndex)> { + let bytes = self.text.as_bytes(); + let mut line_start = LineStart::new(&bytes[ix..]); + let containers = scan_containers(&self.tree, &mut line_start); + if containers != self.tree.spine_len() { + return None; + } + line_start.scan_all_space(); + ix += line_start.bytes_scanned(); + if scan_paragraph_interrupt(&bytes[ix..]) { + return None; + } + + let (ix, row_ix) = self.parse_table_row_inner(ix, row_cells); + Some((ix, row_ix)) + } + + /// Returns offset of line start after paragraph. + fn parse_paragraph(&mut self, start_ix: usize) -> usize { + let node_ix = self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::Paragraph, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + + let mut ix = start_ix; + loop { + let scan_mode = if self.options.contains(Options::ENABLE_TABLES) && ix == start_ix { + TableParseMode::Scan + } else { + TableParseMode::Disabled + }; + let (next_ix, brk) = self.parse_line(ix, scan_mode); + + // break out when we find a table + if let Some(Item { + body: ItemBody::Table(alignment_ix), + .. + }) = brk + { + let table_cols = self.allocs[alignment_ix].len(); + self.tree[node_ix].item.body = ItemBody::Table(alignment_ix); + // this clears out any stuff we may have appended - but there may + // be a cleaner way + self.tree[node_ix].child = None; + self.tree.pop(); + self.tree.push(); + return self.parse_table(table_cols, ix, next_ix); + } + + ix = next_ix; + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if !line_start.scan_space(4) { + let ix_new = ix + line_start.bytes_scanned(); + if n_containers == self.tree.spine_len() { + if let Some(ix_setext) = self.parse_setext_heading(ix_new, node_ix) { + if let Some(Item { + start, + body: ItemBody::HardBreak, + .. + }) = brk + { + if bytes[start] == b'\\' { + self.tree.append_text(start, start + 1); + } + } + ix = ix_setext; + break; + } + } + // first check for non-empty lists, then for other interrupts + let suffix = &bytes[ix_new..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + break; + } + } + line_start.scan_all_space(); + if line_start.is_at_eol() { + break; + } + ix = next_ix + line_start.bytes_scanned(); + if let Some(item) = brk { + self.tree.append(item); + } + } + + self.pop(ix); + ix + } + + /// Returns end ix of setext_heading on success. + fn parse_setext_heading(&mut self, ix: usize, node_ix: TreeIndex) -> Option { + let bytes = self.text.as_bytes(); + let (n, level) = scan_setext_heading(&bytes[ix..])?; + self.tree[node_ix].item.body = ItemBody::Heading(level); + + // strip trailing whitespace + if let Some(cur_ix) = self.tree.cur() { + self.tree[cur_ix].item.end -= scan_rev_while( + &bytes[..self.tree[cur_ix].item.end], + is_ascii_whitespace_no_nl, + ); + } + + Some(ix + n) + } + + /// Parse a line of input, appending text and items to tree. + /// + /// Returns: index after line and an item representing the break. + fn parse_line(&mut self, start: usize, mode: TableParseMode) -> (usize, Option) { + let bytes = &self.text.as_bytes(); + let mut pipes = 0; + let mut last_pipe_ix = start; + let mut begin_text = start; + + let (final_ix, brk) = + iterate_special_bytes(&self.lookup_table, bytes, start, |ix, byte| { + match byte { + b'\n' | b'\r' => { + if let TableParseMode::Active = mode { + return LoopInstruction::BreakAtWith(ix, None); + } + + let mut i = ix; + let eol_bytes = scan_eol(&bytes[ix..]).unwrap(); + if mode == TableParseMode::Scan && pipes > 0 { + // check if we may be parsing a table + let next_line_ix = ix + eol_bytes; + let mut line_start = LineStart::new(&bytes[next_line_ix..]); + if scan_containers(&self.tree, &mut line_start) == self.tree.spine_len() + { + let table_head_ix = next_line_ix + line_start.bytes_scanned(); + let (table_head_bytes, alignment) = + scan_table_head(&bytes[table_head_ix..]); + + if table_head_bytes > 0 { + // computing header count from number of pipes + let header_count = + count_header_cols(bytes, pipes, start, last_pipe_ix); + + // make sure they match the number of columns we find in separator line + if alignment.len() == header_count { + let alignment_ix = + self.allocs.allocate_alignment(alignment); + let end_ix = table_head_ix + table_head_bytes; + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, // must update later + body: ItemBody::Table(alignment_ix), + }), + ); + } + } + } + } + + let end_ix = ix + eol_bytes; + let trailing_backslashes = scan_rev_while(&bytes[..ix], |b| b == b'\\'); + if trailing_backslashes % 2 == 1 && end_ix < self.text.len() { + i -= 1; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + let trailing_whitespace = + scan_rev_while(&bytes[..ix], is_ascii_whitespace_no_nl); + if trailing_whitespace >= 2 { + i -= trailing_whitespace; + self.tree.append_text(begin_text, i); + return LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::HardBreak, + }), + ); + } + + self.tree.append_text(begin_text, ix); + LoopInstruction::BreakAtWith( + end_ix, + Some(Item { + start: i, + end: end_ix, + body: ItemBody::SoftBreak, + }), + ) + } + b'\\' => { + if ix + 1 < self.text.len() && is_ascii_punctuation(bytes[ix + 1]) { + self.tree.append_text(begin_text, ix); + if bytes[ix + 1] == b'`' { + let count = 1 + scan_ch_repeat(&bytes[(ix + 2)..], b'`'); + self.tree.append(Item { + start: ix + 1, + end: ix + count + 1, + body: ItemBody::MaybeCode(count, true), + }); + begin_text = ix + 1 + count; + LoopInstruction::ContinueAndSkip(count) + } else { + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(1) + } + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + c @ b'*' | c @ b'_' | c @ b'~' => { + let string_suffix = &self.text[ix..]; + let count = 1 + scan_ch_repeat(&string_suffix.as_bytes()[1..], c); + let can_open = delim_run_can_open(self.text, string_suffix, count, ix); + let can_close = delim_run_can_close(self.text, string_suffix, count, ix); + let is_valid_seq = c != b'~' || count == 2; + + if (can_open || can_close) && is_valid_seq { + self.tree.append_text(begin_text, ix); + for i in 0..count { + self.tree.append(Item { + start: ix + i, + end: ix + i + 1, + body: ItemBody::MaybeEmphasis(count - i, can_open, can_close), + }); + } + begin_text = ix + count; + } + LoopInstruction::ContinueAndSkip(count - 1) + } + b'`' => { + self.tree.append_text(begin_text, ix); + let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'`'); + self.tree.append(Item { + start: ix, + end: ix + count, + body: ItemBody::MaybeCode(count, false), + }); + begin_text = ix + count; + LoopInstruction::ContinueAndSkip(count - 1) + } + b'<' => { + // Note: could detect some non-HTML cases and early escape here, but not + // clear that's a win. + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeHtml, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'!' => { + if ix + 1 < self.text.len() && bytes[ix + 1] == b'[' { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 2, + body: ItemBody::MaybeImage, + }); + begin_text = ix + 2; + LoopInstruction::ContinueAndSkip(1) + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + b'[' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkOpen, + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b']' => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeLinkClose(true), + }); + begin_text = ix + 1; + LoopInstruction::ContinueAndSkip(0) + } + b'&' => match scan_entity(&bytes[ix..]) { + (n, Some(value)) => { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + n, + body: ItemBody::SynthesizeText(self.allocs.allocate_cow(value)), + }); + begin_text = ix + n; + LoopInstruction::ContinueAndSkip(n - 1) + } + _ => LoopInstruction::ContinueAndSkip(0), + }, + b'|' => { + if let TableParseMode::Active = mode { + LoopInstruction::BreakAtWith(ix, None) + } else { + last_pipe_ix = ix; + pipes += 1; + LoopInstruction::ContinueAndSkip(0) + } + } + b'.' => { + if ix + 2 < bytes.len() && bytes[ix + 1] == b'.' && bytes[ix + 2] == b'.' { + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 3, + body: ItemBody::SynthesizeChar('…'), + }); + begin_text = ix + 3; + LoopInstruction::ContinueAndSkip(2) + } else { + LoopInstruction::ContinueAndSkip(0) + } + } + b'-' => { + let count = 1 + scan_ch_repeat(&bytes[(ix + 1)..], b'-'); + if count == 1 { + LoopInstruction::ContinueAndSkip(0) + } else { + let itembody = if count == 2 { + ItemBody::SynthesizeChar('–') + } else if count == 3 { + ItemBody::SynthesizeChar('—') + } else { + let (ems, ens) = match count % 6 { + 0 | 3 => (count / 3, 0), + 2 | 4 => (0, count / 2), + 1 => (count / 3 - 1, 2), + _ => (count / 3, 1), + }; + // – and — are 3 bytes each in utf8 + let mut buf = String::with_capacity(3 * (ems + ens)); + for _ in 0..ems { + buf.push('—'); + } + for _ in 0..ens { + buf.push('–'); + } + ItemBody::SynthesizeText(self.allocs.allocate_cow(buf.into())) + }; + + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + count, + body: itembody, + }); + begin_text = ix + count; + LoopInstruction::ContinueAndSkip(count - 1) + } + } + c @ b'\'' | c @ b'"' => { + let string_suffix = &self.text[ix..]; + let can_open = delim_run_can_open(self.text, string_suffix, 1, ix); + let can_close = delim_run_can_close(self.text, string_suffix, 1, ix); + + self.tree.append_text(begin_text, ix); + self.tree.append(Item { + start: ix, + end: ix + 1, + body: ItemBody::MaybeSmartQuote(c, can_open, can_close), + }); + begin_text = ix + 1; + + LoopInstruction::ContinueAndSkip(0) + } + _ => LoopInstruction::ContinueAndSkip(0), + } + }); + + if brk.is_none() { + // need to close text at eof + self.tree.append_text(begin_text, final_ix); + } + (final_ix, brk) + } + + /// Check whether we should allow a paragraph interrupt by lists. Only non-empty + /// lists are allowed. + fn interrupt_paragraph_by_list(&self, suffix: &[u8]) -> bool { + scan_listitem(suffix).map_or(false, |(ix, delim, index, _)| { + self.list_nesting > 0 || + // we don't allow interruption by either empty lists or + // numbered lists starting at an index other than 1 + !scan_empty_list(&suffix[ix..]) && (delim == b'*' || delim == b'-' || index == 1) + }) + } + + /// When start_ix is at the beginning of an HTML block of type 1 to 5, + /// this will find the end of the block, adding the block itself to the + /// tree and also keeping track of the lines of HTML within the block. + /// + /// The html_end_tag is the tag that must be found on a line to end the block. + fn parse_html_block_type_1_to_5( + &mut self, + start_ix: usize, + html_end_tag: &str, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + + if (&self.text[line_start_ix..ix]).contains(html_end_tag) { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + /// When start_ix is at the beginning of an HTML block of type 6 or 7, + /// this will consume lines until there is a blank line and keep track of + /// the HTML within the block. + fn parse_html_block_type_6_or_7( + &mut self, + start_ix: usize, + mut remaining_space: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_html_line(remaining_space, line_start_ix, ix); + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() || line_start.is_at_eol() { + break; + } + + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() || scan_blank_line(&bytes[next_line_ix..]).is_some() + { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + } + ix + } + + fn parse_indented_code_block(&mut self, start_ix: usize, mut remaining_space: usize) -> usize { + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::IndentCodeBlock, + }); + self.tree.push(); + let bytes = self.text.as_bytes(); + let mut last_nonblank_child = None; + let mut last_nonblank_ix = 0; + let mut end_ix = 0; + let mut last_line_blank = false; + + let mut ix = start_ix; + loop { + let line_start_ix = ix; + ix += scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, line_start_ix, ix); + // TODO(spec clarification): should we synthesize newline at EOF? + + if !last_line_blank { + last_nonblank_child = self.tree.cur(); + last_nonblank_ix = ix; + end_ix = ix; + } + + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() + || !(line_start.scan_space(4) || line_start.is_at_eol()) + { + break; + } + let next_line_ix = ix + line_start.bytes_scanned(); + if next_line_ix == self.text.len() { + break; + } + ix = next_line_ix; + remaining_space = line_start.remaining_space(); + last_line_blank = scan_blank_line(&bytes[ix..]).is_some(); + } + + // Trim trailing blank lines. + if let Some(child) = last_nonblank_child { + self.tree[child].next = None; + self.tree[child].item.end = last_nonblank_ix; + } + self.pop(end_ix); + ix + } + + fn parse_fenced_code_block( + &mut self, + start_ix: usize, + indent: usize, + fence_ch: u8, + n_fence_char: usize, + ) -> usize { + let bytes = self.text.as_bytes(); + let mut info_start = start_ix + n_fence_char; + info_start += scan_whitespace_no_nl(&bytes[info_start..]); + // TODO: info strings are typically very short. wouldnt it be faster + // to just do a forward scan here? + let mut ix = info_start + scan_nextline(&bytes[info_start..]); + let info_end = ix - scan_rev_while(&bytes[info_start..ix], is_ascii_whitespace); + let info_string = unescape(&self.text[info_start..info_end]); + self.tree.append(Item { + start: start_ix, + end: 0, // will get set later + body: ItemBody::FencedCodeBlock(self.allocs.allocate_cow(info_string)), + }); + self.tree.push(); + loop { + let mut line_start = LineStart::new(&bytes[ix..]); + let n_containers = scan_containers(&self.tree, &mut line_start); + if n_containers < self.tree.spine_len() { + break; + } + line_start.scan_space(indent); + let mut close_line_start = line_start.clone(); + if !close_line_start.scan_space(4) { + let close_ix = ix + close_line_start.bytes_scanned(); + if let Some(n) = scan_closing_code_fence(&bytes[close_ix..], fence_ch, n_fence_char) + { + ix = close_ix + n; + break; + } + } + let remaining_space = line_start.remaining_space(); + ix += line_start.bytes_scanned(); + let next_ix = ix + scan_nextline(&bytes[ix..]); + self.append_code_text(remaining_space, ix, next_ix); + ix = next_ix; + } + + self.pop(ix); + + // try to read trailing whitespace or it will register as a completely blank line + ix + scan_blank_line(&bytes[ix..]).unwrap_or(0) + } + + fn append_code_text(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append_text(start, end - 2); + self.tree.append_text(end - 1, end); + } else { + self.tree.append_text(start, end); + } + } + + /// Appends a line of HTML to the tree. + fn append_html_line(&mut self, remaining_space: usize, start: usize, end: usize) { + if remaining_space > 0 { + let cow_ix = self.allocs.allocate_cow(" "[..remaining_space].into()); + self.tree.append(Item { + start, + end: start, + // TODO: maybe this should synthesize to html rather than text? + body: ItemBody::SynthesizeText(cow_ix), + }); + } + if self.text.as_bytes()[end - 2] == b'\r' { + // Normalize CRLF to LF + self.tree.append(Item { + start, + end: end - 2, + body: ItemBody::Html, + }); + self.tree.append(Item { + start: end - 1, + end, + body: ItemBody::Html, + }); + } else { + self.tree.append(Item { + start, + end, + body: ItemBody::Html, + }); + } + } + + /// Pop a container, setting its end. + fn pop(&mut self, ix: usize) { + let cur_ix = self.tree.pop().unwrap(); + self.tree[cur_ix].item.end = ix; + if let ItemBody::List(true, _, _) = self.tree[cur_ix].item.body { + surgerize_tight_list(&mut self.tree, cur_ix); + } + } + + /// Close a list if it's open. Also set loose if last line was blank + fn finish_list(&mut self, ix: usize) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(_, _, _) = self.tree[node_ix].item.body { + self.pop(ix); + self.list_nesting -= 1; + } + } + if self.last_line_blank { + if let Some(node_ix) = self.tree.peek_grandparent() { + if let ItemBody::List(ref mut is_tight, _, _) = self.tree[node_ix].item.body { + *is_tight = false; + } + } + self.last_line_blank = false; + } + } + + /// Continue an existing list or start a new one if there's not an open + /// list that matches. + fn continue_list(&mut self, start: usize, ch: u8, index: u64) { + if let Some(node_ix) = self.tree.peek_up() { + if let ItemBody::List(ref mut is_tight, existing_ch, _) = self.tree[node_ix].item.body { + if existing_ch == ch { + if self.last_line_blank { + *is_tight = false; + self.last_line_blank = false; + } + return; + } + } + // TODO: this is not the best choice for end; maybe get end from last list item. + self.finish_list(start); + } + self.tree.append(Item { + start, + end: 0, // will get set later + body: ItemBody::List(true, ch, index), + }); + self.list_nesting += 1; + self.tree.push(); + self.last_line_blank = false; + } + + /// Parse a thematic break. + /// + /// Returns index of start of next line. + fn parse_hrule(&mut self, hrule_size: usize, ix: usize) -> usize { + self.tree.append(Item { + start: ix, + end: ix + hrule_size, + body: ItemBody::Rule, + }); + ix + hrule_size + } + + /// Parse an ATX heading. + /// + /// Returns index of start of next line. + fn parse_atx_heading(&mut self, mut ix: usize, atx_size: usize) -> usize { + let heading_ix = self.tree.append(Item { + start: ix, + end: 0, // set later + body: ItemBody::Heading(atx_size as u32), + }); + ix += atx_size; + // next char is space or eol (guaranteed by scan_atx_heading) + let bytes = self.text.as_bytes(); + if let Some(eol_bytes) = scan_eol(&bytes[ix..]) { + self.tree[heading_ix].item.end = ix + eol_bytes; + return ix + eol_bytes; + } + // skip leading spaces + let skip_spaces = scan_whitespace_no_nl(&bytes[ix..]); + ix += skip_spaces; + + // now handle the header text + let header_start = ix; + let header_node_idx = self.tree.push(); // so that we can set the endpoint later + ix = self.parse_line(ix, TableParseMode::Disabled).0; + self.tree[header_node_idx].item.end = ix; + + // remove trailing matter from header text + if let Some(cur_ix) = self.tree.cur() { + let header_text = &bytes[header_start..ix]; + let mut limit = header_text + .iter() + .rposition(|&b| !(b == b'\n' || b == b'\r' || b == b' ')) + .map_or(0, |i| i + 1); + let closer = header_text[..limit] + .iter() + .rposition(|&b| b != b'#') + .map_or(0, |i| i + 1); + if closer == 0 { + limit = closer; + } else { + let spaces = scan_rev_while(&header_text[..closer], |b| b == b' '); + if spaces > 0 { + limit = closer - spaces; + } + } + self.tree[cur_ix].item.end = limit + header_start; + } + + self.tree.pop(); + ix + } + + /// Returns the number of bytes scanned on success. + fn parse_footnote(&mut self, start: usize) -> Option { + let bytes = &self.text.as_bytes()[start..]; + if !bytes.starts_with(b"[^") { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 2)?; + i += 2; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + self.finish_list(start); + self.tree.append(Item { + start, + end: 0, // will get set later + // TODO: check whether the label here is strictly necessary + body: ItemBody::FootnoteDefinition(self.allocs.allocate_cow(label)), + }); + self.tree.push(); + Some(i) + } + + /// Tries to parse a reference label, which can be interrupted by new blocks. + /// On success, returns the number of bytes of the label and the label itself. + fn parse_refdef_label(&self, start: usize) -> Option<(usize, CowStr<'a>)> { + scan_link_label_rest(&self.text[start..], &|bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + let bytes_scanned = line_start.bytes_scanned(); + + let suffix = &bytes[bytes_scanned..]; + if self.interrupt_paragraph_by_list(suffix) || scan_paragraph_interrupt(suffix) { + None + } else { + Some(bytes_scanned) + } + }) + } + + /// Returns number of bytes scanned, label and definition on success. + fn parse_refdef_total(&mut self, start: usize) -> Option<(usize, LinkLabel<'a>, LinkDef<'a>)> { + let bytes = &self.text.as_bytes()[start..]; + if scan_ch(bytes, b'[') == 0 { + return None; + } + let (mut i, label) = self.parse_refdef_label(start + 1)?; + i += 1; + if scan_ch(&bytes[i..], b':') == 0 { + return None; + } + i += 1; + let (bytecount, link_def) = self.scan_refdef(start + i)?; + Some((bytecount + i, UniCase::new(label), link_def)) + } + + /// Returns number of bytes and number of newlines + fn scan_refdef_space(&self, bytes: &[u8], mut i: usize) -> Option<(usize, usize)> { + let mut newlines = 0; + loop { + let whitespaces = scan_whitespace_no_nl(&bytes[i..]); + i += whitespaces; + if let Some(eol_bytes) = scan_eol(&bytes[i..]) { + i += eol_bytes; + newlines += 1; + if newlines > 1 { + return None; + } + } else { + break; + } + let mut line_start = LineStart::new(&bytes[i..]); + if self.tree.spine_len() != scan_containers(&self.tree, &mut line_start) { + return None; + } + i += line_start.bytes_scanned(); + } + Some((i, newlines)) + } + + /// Returns # of bytes and definition. + /// Assumes the label of the reference including colon has already been scanned. + fn scan_refdef(&self, start: usize) -> Option<(usize, LinkDef<'a>)> { + let bytes = self.text.as_bytes(); + + // whitespace between label and url (including up to one newline) + let (mut i, _newlines) = self.scan_refdef_space(bytes, start)?; + + // scan link dest + let (dest_length, dest) = scan_link_dest(self.text, i, 1)?; + if dest_length == 0 { + return None; + } + let dest = unescape(dest); + i += dest_length; + + // no title + let mut backup = (i - start, LinkDef { dest, title: None }); + + // scan whitespace between dest and label + let (mut i, newlines) = + if let Some((new_i, mut newlines)) = self.scan_refdef_space(bytes, i) { + if i == self.text.len() { + newlines += 1; + } + if new_i == i && newlines == 0 { + return None; + } + if newlines > 1 { + return Some(backup); + }; + (new_i, newlines) + } else { + return Some(backup); + }; + + // scan title + // if this fails but newline == 1, return also a refdef without title + if let Some((title_length, title)) = scan_refdef_title(&self.text[i..]) { + i += title_length; + backup.1.title = Some(unescape(title)); + } else if newlines > 0 { + return Some(backup); + } else { + return None; + }; + + // scan EOL + if let Some(bytes) = scan_blank_line(&bytes[i..]) { + backup.0 = i + bytes - start; + Some(backup) + } else if newlines > 0 { + Some(backup) + } else { + None + } + } +} + +/// Returns number of containers scanned. +fn scan_containers(tree: &Tree, line_start: &mut LineStart) -> usize { + let mut i = 0; + for &node_ix in tree.walk_spine() { + match tree[node_ix].item.body { + ItemBody::BlockQuote => { + let save = line_start.clone(); + if !line_start.scan_blockquote_marker() { + *line_start = save; + break; + } + } + ItemBody::ListItem(indent) => { + let save = line_start.clone(); + if !line_start.scan_space(indent) { + if !line_start.is_at_eol() { + *line_start = save; + break; + } + } + } + _ => (), + } + i += 1; + } + i +} + +/// Computes the number of header columns in a table line by computing the number of dividing pipes +/// that aren't followed or preceeded by whitespace. +fn count_header_cols( + bytes: &[u8], + mut pipes: usize, + mut start: usize, + last_pipe_ix: usize, +) -> usize { + // was first pipe preceeded by whitespace? if so, subtract one + start += scan_whitespace_no_nl(&bytes[start..]); + if bytes[start] == b'|' { + pipes -= 1; + } + + // was last pipe followed by whitespace? if so, sub one + if scan_blank_line(&bytes[(last_pipe_ix + 1)..]).is_some() { + pipes + } else { + pipes + 1 + } +} + +impl<'a> Tree { + fn append_text(&mut self, start: usize, end: usize) { + if end > start { + if let Some(ix) = self.cur() { + if ItemBody::Text == self[ix].item.body && self[ix].item.end == start { + self[ix].item.end = end; + return; + } + } + self.append(Item { + start, + end, + body: ItemBody::Text, + }); + } + } +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims). +/// suffix is &s[ix..], which is passed in as an optimization, since taking +/// a string subslice is O(n). +fn delim_run_can_open(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return false; + }; + if next_char.is_whitespace() { + return false; + } + if ix == 0 { + return true; + } + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(next_char) { + return true; + } + + let prev_char = s[..ix].chars().last().unwrap(); + + prev_char.is_whitespace() + || is_punctuation(prev_char) && (delim != '\'' || ![']', ')'].contains(&prev_char)) +} + +/// Determines whether the delimiter run starting at given index is +/// left-flanking, as defined by the commonmark spec (and isn't intraword +/// for _ delims) +fn delim_run_can_close(s: &str, suffix: &str, run_len: usize, ix: usize) -> bool { + if ix == 0 { + return false; + } + let prev_char = s[..ix].chars().last().unwrap(); + if prev_char.is_whitespace() { + return false; + } + let next_char = if let Some(c) = suffix.chars().nth(run_len) { + c + } else { + return true; + }; + let delim = suffix.chars().next().unwrap(); + if delim == '*' && !is_punctuation(prev_char) { + return true; + } + + next_char.is_whitespace() || is_punctuation(next_char) +} + +/// Checks whether we should break a paragraph on the given input. +/// Note: lists are dealt with in `interrupt_paragraph_by_list`, because determing +/// whether to break on a list requires additional context. +fn scan_paragraph_interrupt(bytes: &[u8]) -> bool { + if scan_eol(bytes).is_some() + || scan_hrule(bytes).is_ok() + || scan_atx_heading(bytes).is_some() + || scan_code_fence(bytes).is_some() + || scan_blockquote_start(bytes).is_some() + { + return true; + } + bytes.starts_with(b"<") + && (get_html_end_tag(&bytes[1..]).is_some() + || is_html_tag(scan_html_block_tag(&bytes[1..]).1)) +} + +/// Assumes `text_bytes` is preceded by `<`. +fn get_html_end_tag(text_bytes: &[u8]) -> Option<&'static str> { + static BEGIN_TAGS: &[&[u8]; 3] = &[b"pre", b"style", b"script"]; + static ST_BEGIN_TAGS: &[&[u8]; 3] = &[b"!--", b"?", b"![CDATA["]; + + for (beg_tag, end_tag) in BEGIN_TAGS + .iter() + .zip(["", "", ""].iter()) + { + let tag_len = beg_tag.len(); + + if text_bytes.len() < tag_len { + // begin tags are increasing in size + break; + } + + if !text_bytes[..tag_len].eq_ignore_ascii_case(beg_tag) { + continue; + } + + // Must either be the end of the line... + if text_bytes.len() == tag_len { + return Some(end_tag); + } + + // ...or be followed by whitespace, newline, or '>'. + let s = text_bytes[tag_len]; + if is_ascii_whitespace(s) || s == b'>' { + return Some(end_tag); + } + } + + for (beg_tag, end_tag) in ST_BEGIN_TAGS.iter().zip(["-->", "?>", "]]>"].iter()) { + if text_bytes.starts_with(beg_tag) { + return Some(end_tag); + } + } + + if text_bytes.len() > 1 + && text_bytes[0] == b'!' + && text_bytes[1] >= b'A' + && text_bytes[1] <= b'Z' + { + Some(">") + } else { + None + } +} + +#[derive(Copy, Clone, Debug)] +struct InlineEl { + start: TreeIndex, // offset of tree node + count: usize, + c: u8, // b'*' or b'_' + both: bool, // can both open and close +} + +#[derive(Debug, Clone, Default)] +struct InlineStack { + stack: Vec, + // Lower bounds for matching indices in the stack. For example + // a strikethrough delimiter will never match with any element + // in the stack with index smaller than + // `lower_bounds[InlineStack::TILDES]`. + lower_bounds: [usize; 7], +} + +impl InlineStack { + /// These are indices into the lower bounds array. + /// Not both refers to the property that the delimiter can not both + /// be opener as a closer. + const UNDERSCORE_NOT_BOTH: usize = 0; + const ASTERISK_NOT_BOTH: usize = 1; + const ASTERISK_BASE: usize = 2; + const TILDES: usize = 5; + const UNDERSCORE_BOTH: usize = 6; + + fn pop_all(&mut self, tree: &mut Tree) { + for el in self.stack.drain(..) { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.lower_bounds = [0; 7]; + } + + fn get_lowerbound(&self, c: u8, count: usize, both: bool) -> usize { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] + } + } else if c == b'*' { + let mod3_lower = self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3]; + if both { + mod3_lower + } else { + min( + mod3_lower, + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH], + ) + } + } else { + self.lower_bounds[InlineStack::TILDES] + } + } + + fn set_lowerbound(&mut self, c: u8, count: usize, both: bool, new_bound: usize) { + if c == b'_' { + if both { + self.lower_bounds[InlineStack::UNDERSCORE_BOTH] = new_bound; + } else { + self.lower_bounds[InlineStack::UNDERSCORE_NOT_BOTH] = new_bound; + } + } else if c == b'*' { + self.lower_bounds[InlineStack::ASTERISK_BASE + count % 3] = new_bound; + if !both { + self.lower_bounds[InlineStack::ASTERISK_NOT_BOTH] = new_bound; + } + } else { + self.lower_bounds[InlineStack::TILDES] = new_bound; + } + } + + fn find_match( + &mut self, + tree: &mut Tree, + c: u8, + count: usize, + both: bool, + ) -> Option { + let lowerbound = min(self.stack.len(), self.get_lowerbound(c, count, both)); + let res = self.stack[lowerbound..] + .iter() + .cloned() + .enumerate() + .rfind(|(_, el)| { + el.c == c && (!both && !el.both || (count + el.count) % 3 != 0 || count % 3 == 0) + }); + + if let Some((matching_ix, matching_el)) = res { + let matching_ix = matching_ix + lowerbound; + for el in &self.stack[(matching_ix + 1)..] { + for i in 0..el.count { + tree[el.start + i].item.body = ItemBody::Text; + } + } + self.stack.truncate(matching_ix); + Some(matching_el) + } else { + self.set_lowerbound(c, count, both, self.stack.len()); + None + } + } + + fn push(&mut self, el: InlineEl) { + self.stack.push(el) + } +} + +#[derive(Debug, Clone)] +enum RefScan<'a> { + // label, source ix of label end + LinkLabel(CowStr<'a>, usize), + // contains next node index + Collapsed(Option), + Failed, +} + +/// Skips forward within a block to a node which spans (ends inclusive) the given +/// index into the source. +fn scan_nodes_to_ix( + tree: &Tree, + mut node: Option, + ix: usize, +) -> Option { + while let Some(node_ix) = node { + if tree[node_ix].item.end <= ix { + node = tree[node_ix].next; + } else { + break; + } + } + node +} + +/// Scans an inline link label, which cannot be interrupted. +/// Returns number of bytes (including brackets) and label on success. +fn scan_link_label<'text, 'tree>( + tree: &'tree Tree, + text: &'text str, + allow_footnote_refs: bool, +) -> Option<(usize, ReferenceLabel<'text>)> { + let bytes = &text.as_bytes(); + if bytes.len() < 2 || bytes[0] != b'[' { + return None; + } + let linebreak_handler = |bytes: &[u8]| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(tree, &mut line_start); + Some(line_start.bytes_scanned()) + }; + let pair = if allow_footnote_refs && b'^' == bytes[1] { + let (byte_index, cow) = scan_link_label_rest(&text[2..], &linebreak_handler)?; + (byte_index + 2, ReferenceLabel::Footnote(cow)) + } else { + let (byte_index, cow) = scan_link_label_rest(&text[1..], &linebreak_handler)?; + (byte_index + 1, ReferenceLabel::Link(cow)) + }; + Some(pair) +} + +fn scan_reference<'a, 'b>( + tree: &'a Tree, + text: &'b str, + cur: Option, + allow_footnote_refs: bool, +) -> RefScan<'b> { + let cur_ix = match cur { + None => return RefScan::Failed, + Some(cur_ix) => cur_ix, + }; + let start = tree[cur_ix].item.start; + let tail = &text.as_bytes()[start..]; + + if tail.starts_with(b"[]") { + let closing_node = tree[cur_ix].next.unwrap(); + RefScan::Collapsed(tree[closing_node].next) + } else if let Some((ix, ReferenceLabel::Link(label))) = + scan_link_label(tree, &text[start..], allow_footnote_refs) + { + RefScan::LinkLabel(label, start + ix) + } else { + RefScan::Failed + } +} + +#[derive(Clone, Default)] +struct LinkStack { + inner: Vec, + disabled_ix: usize, +} + +impl LinkStack { + fn push(&mut self, el: LinkStackEl) { + self.inner.push(el); + } + + fn pop(&mut self) -> Option { + let el = self.inner.pop(); + self.disabled_ix = std::cmp::min(self.disabled_ix, self.inner.len()); + el + } + + fn clear(&mut self) { + self.inner.clear(); + self.disabled_ix = 0; + } + + fn disable_all_links(&mut self) { + for el in &mut self.inner[self.disabled_ix..] { + if el.ty == LinkStackTy::Link { + el.ty = LinkStackTy::Disabled; + } + } + self.disabled_ix = self.inner.len(); + } +} + +#[derive(Clone, Debug)] +struct LinkStackEl { + node: TreeIndex, + ty: LinkStackTy, +} + +#[derive(PartialEq, Clone, Debug)] +enum LinkStackTy { + Link, + Image, + Disabled, +} + +#[derive(Clone)] +struct LinkDef<'a> { + dest: CowStr<'a>, + title: Option>, +} + +/// Tracks tree indices of code span delimiters of each length. It should prevent +/// quadratic scanning behaviours by providing (amortized) constant time lookups. +struct CodeDelims { + inner: HashMap>, + seen_first: bool, +} + +impl CodeDelims { + fn new() -> Self { + Self { + inner: Default::default(), + seen_first: false, + } + } + + fn insert(&mut self, count: usize, ix: TreeIndex) { + if self.seen_first { + self.inner + .entry(count) + .or_insert_with(Default::default) + .push_back(ix); + } else { + // Skip the first insert, since that delimiter will always + // be an opener and not a closer. + self.seen_first = true; + } + } + + fn is_populated(&self) -> bool { + !self.inner.is_empty() + } + + fn find(&mut self, open_ix: TreeIndex, count: usize) -> Option { + while let Some(ix) = self.inner.get_mut(&count)?.pop_front() { + if ix > open_ix { + return Some(ix); + } + } + None + } + + fn clear(&mut self) { + self.inner.clear(); + self.seen_first = false; + } +} + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct LinkIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct CowIndex(usize); + +#[derive(Copy, Clone, PartialEq, Eq, Debug)] +struct AlignmentIndex(usize); + +#[derive(Clone)] +struct Allocations<'a> { + refdefs: HashMap, LinkDef<'a>>, + links: Vec<(LinkType, CowStr<'a>, CowStr<'a>)>, + cows: Vec>, + alignments: Vec>, +} + +impl<'a> Allocations<'a> { + fn new() -> Self { + Self { + refdefs: HashMap::new(), + links: Vec::with_capacity(128), + cows: Vec::new(), + alignments: Vec::new(), + } + } + + fn allocate_cow(&mut self, cow: CowStr<'a>) -> CowIndex { + let ix = self.cows.len(); + self.cows.push(cow); + CowIndex(ix) + } + + fn allocate_link(&mut self, ty: LinkType, url: CowStr<'a>, title: CowStr<'a>) -> LinkIndex { + let ix = self.links.len(); + self.links.push((ty, url, title)); + LinkIndex(ix) + } + + fn allocate_alignment(&mut self, alignment: Vec) -> AlignmentIndex { + let ix = self.alignments.len(); + self.alignments.push(alignment); + AlignmentIndex(ix) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = CowStr<'a>; + + fn index(&self, ix: CowIndex) -> &Self::Output { + self.cows.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = (LinkType, CowStr<'a>, CowStr<'a>); + + fn index(&self, ix: LinkIndex) -> &Self::Output { + self.links.index(ix.0) + } +} + +impl<'a> Index for Allocations<'a> { + type Output = Vec; + + fn index(&self, ix: AlignmentIndex) -> &Self::Output { + self.alignments.index(ix.0) + } +} + +/// A struct containing information on the reachability of certain inline HTML +/// elements. In particular, for cdata elements (` [bool; 256] { + let mut bytes = [false; 256]; + let standard_bytes = [ + b'\n', b'\r', b'*', b'_', b'&', b'\\', b'[', b']', b'<', b'!', b'`', + ]; + + for &byte in &standard_bytes { + bytes[byte as usize] = true; + } + if options.contains(Options::ENABLE_TABLES) { + bytes[b'|' as usize] = true; + } + if options.contains(Options::ENABLE_STRIKETHROUGH) { + bytes[b'~' as usize] = true; + } + if options.contains(Options::ENABLE_SMART_PUNCTUATION) { + for &byte in &[b'.', b'-', b'"', b'\''] { + bytes[byte as usize] = true; + } + } + + bytes +} + +pub(crate) fn create_lut(options: &Options) -> LookupTable { + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + LookupTable { + simd: crate::simd::compute_lookup(options), + scalar: special_bytes(options), + } + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + special_bytes(options) + } +} + +pub type BrokenLinkCallback<'a> = + Option<&'a mut dyn FnMut(BrokenLink) -> Option<(CowStr<'a>, CowStr<'a>)>>; + +/// Markdown event iterator. +pub struct Parser<'a> { + text: &'a str, + options: Options, + tree: Tree, + allocs: Allocations<'a>, + broken_link_callback: BrokenLinkCallback<'a>, + html_scan_guard: HtmlScanGuard, + + // used by inline passes. store them here for reuse + inline_stack: InlineStack, + link_stack: LinkStack, +} + +impl<'a> Parser<'a> { + /// Creates a new event iterator for a markdown string without any options enabled. + pub fn new(text: &'a str) -> Parser<'a> { + Parser::new_ext(text, Options::empty()) + } + + /// Creates a new event iterator for a markdown string with given options. + pub fn new_ext(text: &'a str, options: Options) -> Parser<'a> { + Parser::new_with_broken_link_callback(text, options, None) + } + + /// In case the parser encounters any potential links that have a broken + /// reference (e.g `[foo]` when there is no `[foo]: ` entry at the bottom) + /// the provided callback will be called with the reference name, + /// and the returned pair will be used as the link name and title if it is not + /// `None`. + pub fn new_with_broken_link_callback( + text: &'a str, + options: Options, + broken_link_callback: BrokenLinkCallback<'a>, + ) -> Parser<'a> { + let lut = create_lut(&options); + let first_pass = FirstPass::new(text, options, &lut); + let (mut tree, allocs) = first_pass.run(); + tree.reset(); + let inline_stack = Default::default(); + let link_stack = Default::default(); + let html_scan_guard = Default::default(); + Parser { + text, + options, + tree, + allocs, + broken_link_callback, + inline_stack, + link_stack, + html_scan_guard, + } + } + + /// Handle inline markup. + /// + /// When the parser encounters any item indicating potential inline markup, all + /// inline markup passes are run on the remainder of the chain. + /// + /// Note: there's some potential for optimization here, but that's future work. + fn handle_inline(&mut self) { + self.handle_inline_pass1(); + self.handle_emphasis(); + } + + /// Handle inline HTML, code spans, and links. + /// + /// This function handles both inline HTML and code spans, because they have + /// the same precedence. It also handles links, even though they have lower + /// precedence, because the URL of links must not be processed. + fn handle_inline_pass1(&mut self) { + let mut code_delims = CodeDelims::new(); + let mut cur = self.tree.cur(); + let mut prev = None; + + let block_end = self.tree[self.tree.peek_up().unwrap()].item.end; + let block_text = &self.text[..block_end]; + + while let Some(mut cur_ix) = cur { + match self.tree[cur_ix].item.body { + ItemBody::MaybeHtml => { + let next = self.tree[cur_ix].next; + let autolink = if let Some(next_ix) = next { + scan_autolink(block_text, self.tree[next_ix].item.start) + } else { + None + }; + + if let Some((ix, uri, link_type)) = autolink { + let node = scan_nodes_to_ix(&self.tree, next, ix); + let text_node = self.tree.create_node(Item { + start: self.tree[cur_ix].item.start + 1, + end: ix - 1, + body: ItemBody::Text, + }); + let link_ix = self.allocs.allocate_link(link_type, uri, "".into()); + self.tree[cur_ix].item.body = ItemBody::Link(link_ix); + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + self.tree[cur_ix].child = Some(text_node); + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = max(self.tree[node_ix].item.start, ix); + } + continue; + } else { + let inline_html = next.and_then(|next_ix| { + self.scan_inline_html( + block_text.as_bytes(), + self.tree[next_ix].item.start, + ) + }); + if let Some((span, ix)) = inline_html { + let node = scan_nodes_to_ix(&self.tree, next, ix); + self.tree[cur_ix].item.body = if !span.is_empty() { + let converted_string = + String::from_utf8(span).expect("invalid utf8"); + ItemBody::OwnedHtml( + self.allocs.allocate_cow(converted_string.into()), + ) + } else { + ItemBody::Html + }; + self.tree[cur_ix].item.end = ix; + self.tree[cur_ix].next = node; + prev = cur; + cur = node; + if let Some(node_ix) = cur { + self.tree[node_ix].item.start = + max(self.tree[node_ix].item.start, ix); + } + continue; + } + } + self.tree[cur_ix].item.body = ItemBody::Text; + } + ItemBody::MaybeCode(mut search_count, preceded_by_backslash) => { + if preceded_by_backslash { + search_count -= 1; + if search_count == 0 { + self.tree[cur_ix].item.body = ItemBody::Text; + prev = cur; + cur = self.tree[cur_ix].next; + continue; + } + } + + if code_delims.is_populated() { + // we have previously scanned all codeblock delimiters, + // so we can reuse that work + if let Some(scan_ix) = code_delims.find(cur_ix, search_count) { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + } else { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } else { + // we haven't previously scanned all codeblock delimiters, + // so walk the AST + let mut scan = if search_count > 0 { + self.tree[cur_ix].next + } else { + None + }; + while let Some(scan_ix) = scan { + if let ItemBody::MaybeCode(delim_count, _) = + self.tree[scan_ix].item.body + { + if search_count == delim_count { + self.make_code_span(cur_ix, scan_ix, preceded_by_backslash); + code_delims.clear(); + break; + } else { + code_delims.insert(delim_count, scan_ix); + } + } + scan = self.tree[scan_ix].next; + } + if scan == None { + self.tree[cur_ix].item.body = ItemBody::Text; + } + } + } + ItemBody::MaybeLinkOpen => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Link, + }); + } + ItemBody::MaybeImage => { + self.tree[cur_ix].item.body = ItemBody::Text; + self.link_stack.push(LinkStackEl { + node: cur_ix, + ty: LinkStackTy::Image, + }); + } + ItemBody::MaybeLinkClose(could_be_ref) => { + self.tree[cur_ix].item.body = ItemBody::Text; + if let Some(tos) = self.link_stack.pop() { + if tos.ty == LinkStackTy::Disabled { + continue; + } + let next = self.tree[cur_ix].next; + if let Some((next_ix, url, title)) = + self.scan_inline_link(block_text, self.tree[cur_ix].item.end, next) + { + let next_node = scan_nodes_to_ix(&self.tree, next, next_ix); + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + cur = Some(tos.node); + cur_ix = tos.node; + let link_ix = self.allocs.allocate_link(LinkType::Inline, url, title); + self.tree[cur_ix].item.body = if tos.ty == LinkStackTy::Image { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + self.tree[cur_ix].child = self.tree[cur_ix].next; + self.tree[cur_ix].next = next_node; + self.tree[cur_ix].item.end = next_ix; + if let Some(next_node_ix) = next_node { + self.tree[next_node_ix].item.start = + max(self.tree[next_node_ix].item.start, next_ix); + } + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } else { + // ok, so its not an inline link. maybe it is a reference + // to a defined link? + let scan_result = scan_reference( + &self.tree, + block_text, + next, + self.options.contains(Options::ENABLE_FOOTNOTES), + ); + let (node_after_link, link_type) = match scan_result { + // [label][reference] + RefScan::LinkLabel(_, end_ix) => { + // Toggle reference viability of the last closing bracket, + // so that we can skip it on future iterations in case + // it fails in this one. In particular, we won't call + // the broken link callback twice on one reference. + let reference_close_node = + scan_nodes_to_ix(&self.tree, next, end_ix - 1).unwrap(); + self.tree[reference_close_node].item.body = + ItemBody::MaybeLinkClose(false); + let next_node = self.tree[reference_close_node].next; + + (next_node, LinkType::Reference) + } + // [reference][] + RefScan::Collapsed(next_node) => { + // This reference has already been tried, and it's not + // valid. Skip it. + if !could_be_ref { + continue; + } + (next_node, LinkType::Collapsed) + } + // [shortcut] + // + // [shortcut]: /blah + RefScan::Failed => { + if !could_be_ref { + continue; + } + (next, LinkType::Shortcut) + } + }; + + // FIXME: references and labels are mixed in the naming of variables + // below. Disambiguate! + + // (label, source_ix end) + let label: Option<(ReferenceLabel<'a>, usize)> = match scan_result { + RefScan::LinkLabel(l, end_ix) => { + Some((ReferenceLabel::Link(l), end_ix)) + } + RefScan::Collapsed(..) | RefScan::Failed => { + // No label? maybe it is a shortcut reference + let label_start = self.tree[tos.node].item.end - 1; + scan_link_label( + &self.tree, + &self.text[label_start..self.tree[cur_ix].item.end], + self.options.contains(Options::ENABLE_FOOTNOTES), + ) + .map(|(ix, label)| (label, label_start + ix)) + } + }; + + // see if it's a footnote reference + if let Some((ReferenceLabel::Footnote(l), end)) = label { + self.tree[tos.node].next = node_after_link; + self.tree[tos.node].child = None; + self.tree[tos.node].item.body = + ItemBody::FootnoteReference(self.allocs.allocate_cow(l)); + self.tree[tos.node].item.end = end; + prev = Some(tos.node); + cur = node_after_link; + self.link_stack.clear(); + continue; + } else if let Some((ReferenceLabel::Link(link_label), end)) = label { + let type_url_title = self + .allocs + .refdefs + .get(&UniCase::new(link_label.as_ref().into())) + .map(|matching_def| { + // found a matching definition! + let title = matching_def + .title + .as_ref() + .cloned() + .unwrap_or_else(|| "".into()); + let url = matching_def.dest.clone(); + (link_type, url, title) + }) + .or_else(|| { + match self.broken_link_callback.as_mut() { + Some(callback) => { + // Construct a BrokenLink struct, which will be passed to the callback + let broken_link = BrokenLink { + span: (self.tree[tos.node].item.start)..end, + link_type: link_type, + reference: link_label.as_ref(), + }; + + callback(broken_link).map(|(url, title)| { + (link_type.to_unknown(), url, title) + }) + } + None => None, + } + }); + + if let Some((def_link_type, url, title)) = type_url_title { + let link_ix = + self.allocs.allocate_link(def_link_type, url, title); + self.tree[tos.node].item.body = if tos.ty == LinkStackTy::Image + { + ItemBody::Image(link_ix) + } else { + ItemBody::Link(link_ix) + }; + let label_node = self.tree[tos.node].next; + + // lets do some tree surgery to add the link to the tree + // 1st: skip the label node and close node + self.tree[tos.node].next = node_after_link; + + // then, if it exists, add the label node as a child to the link node + if label_node != cur { + self.tree[tos.node].child = label_node; + + // finally: disconnect list of children + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + } + + self.tree[tos.node].item.end = end; + + // set up cur so next node will be node_after_link + cur = Some(tos.node); + cur_ix = tos.node; + + if tos.ty == LinkStackTy::Link { + self.link_stack.disable_all_links(); + } + } + } + } + } + } + _ => (), + } + prev = cur; + cur = self.tree[cur_ix].next; + } + self.link_stack.clear(); + } + + fn handle_emphasis(&mut self) { + let mut prev = None; + let mut prev_ix: TreeIndex; + let mut cur = self.tree.cur(); + + let mut single_quote_open: Option = None; + let mut double_quote_open: bool = false; + + while let Some(mut cur_ix) = cur { + match self.tree[cur_ix].item.body { + ItemBody::MaybeEmphasis(mut count, can_open, can_close) => { + let c = self.text.as_bytes()[self.tree[cur_ix].item.start]; + let both = can_open && can_close; + if can_close { + while let Some(el) = + self.inline_stack.find_match(&mut self.tree, c, count, both) + { + // have a match! + if let Some(prev_ix) = prev { + self.tree[prev_ix].next = None; + } + let match_count = min(count, el.count); + // start, end are tree node indices + let mut end = cur_ix - 1; + let mut start = el.start + el.count; + + // work from the inside out + while start > el.start + el.count - match_count { + let (inc, ty) = if c == b'~' { + (2, ItemBody::Strikethrough) + } else if start > el.start + el.count - match_count + 1 { + (2, ItemBody::Strong) + } else { + (1, ItemBody::Emphasis) + }; + + let root = start - inc; + end = end + inc; + self.tree[root].item.body = ty; + self.tree[root].item.end = self.tree[end].item.end; + self.tree[root].child = Some(start); + self.tree[root].next = None; + start = root; + } + + // set next for top most emph level + prev_ix = el.start + el.count - match_count; + prev = Some(prev_ix); + cur = self.tree[cur_ix + match_count - 1].next; + self.tree[prev_ix].next = cur; + + if el.count > match_count { + self.inline_stack.push(InlineEl { + start: el.start, + count: el.count - match_count, + c: el.c, + both, + }) + } + count -= match_count; + if count > 0 { + cur_ix = cur.unwrap(); + } else { + break; + } + } + } + if count > 0 { + if can_open { + self.inline_stack.push(InlineEl { + start: cur_ix, + count, + c, + both, + }); + } else { + for i in 0..count { + self.tree[cur_ix + i].item.body = ItemBody::Text; + } + } + prev_ix = cur_ix + count - 1; + prev = Some(prev_ix); + cur = self.tree[prev_ix].next; + } + } + ItemBody::MaybeSmartQuote(c, can_open, can_close) => { + self.tree[cur_ix].item.body = match c { + b'\'' => { + if let (Some(open_ix), true) = (single_quote_open, can_close) { + self.tree[open_ix].item.body = ItemBody::SynthesizeChar('‘'); + single_quote_open = None; + } else if can_open { + single_quote_open = Some(cur_ix); + } + ItemBody::SynthesizeChar('’') + } + _ /* double quote */ => { + if can_close && double_quote_open { + double_quote_open = false; + ItemBody::SynthesizeChar('”') + } else { + if can_open && !double_quote_open { + double_quote_open = true; + } + ItemBody::SynthesizeChar('“') + } + } + }; + prev = cur; + cur = self.tree[cur_ix].next; + } + _ => { + prev = cur; + cur = self.tree[cur_ix].next; + } + } + } + self.inline_stack.pop_all(&mut self.tree); + } + + /// Returns next byte index, url and title. + fn scan_inline_link( + &self, + underlying: &'a str, + mut ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>, CowStr<'a>)> { + if scan_ch(&underlying.as_bytes()[ix..], b'(') == 0 { + return None; + } + ix += 1; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let (dest_length, dest) = scan_link_dest(underlying, ix, LINK_MAX_NESTED_PARENS)?; + let dest = unescape(dest); + ix += dest_length; + + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + + let title = if let Some((bytes_scanned, t)) = self.scan_link_title(underlying, ix, node) { + ix += bytes_scanned; + ix += scan_while(&underlying.as_bytes()[ix..], is_ascii_whitespace); + t + } else { + "".into() + }; + if scan_ch(&underlying.as_bytes()[ix..], b')') == 0 { + return None; + } + ix += 1; + + Some((ix, dest, title)) + } + + // returns (bytes scanned, title cow) + fn scan_link_title( + &self, + text: &'a str, + start_ix: usize, + node: Option, + ) -> Option<(usize, CowStr<'a>)> { + let bytes = text.as_bytes(); + let open = match bytes.get(start_ix) { + Some(b @ b'\'') | Some(b @ b'\"') | Some(b @ b'(') => *b, + _ => return None, + }; + let close = if open == b'(' { b')' } else { open }; + + let mut title = String::new(); + let mut mark = start_ix + 1; + let mut i = start_ix + 1; + + while i < bytes.len() { + let c = bytes[i]; + + if c == close { + let cow = if mark == 1 { + (i - start_ix + 1, text[mark..i].into()) + } else { + title.push_str(&text[mark..i]); + (i - start_ix + 1, title.into()) + }; + + return Some(cow); + } + if c == open { + return None; + } + + if c == b'\n' || c == b'\r' { + if let Some(node_ix) = scan_nodes_to_ix(&self.tree, node, i + 1) { + if self.tree[node_ix].item.start > i { + title.push_str(&text[mark..i]); + title.push('\n'); + i = self.tree[node_ix].item.start; + mark = i; + continue; + } + } + } + if c == b'&' { + if let (n, Some(value)) = scan_entity(&bytes[i..]) { + title.push_str(&text[mark..i]); + title.push_str(&value); + i += n; + mark = i; + continue; + } + } + if c == b'\\' && i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) { + title.push_str(&text[mark..i]); + i += 1; + mark = i; + } + + i += 1; + } + + None + } + + /// Make a code span. + /// + /// Both `open` and `close` are matching MaybeCode items. + fn make_code_span(&mut self, open: TreeIndex, close: TreeIndex, preceding_backslash: bool) { + let first_ix = open + 1; + let last_ix = close - 1; + let bytes = self.text.as_bytes(); + let mut span_start = self.tree[open].item.end; + let mut span_end = self.tree[close].item.start; + let mut buf: Option = None; + + // detect all-space sequences, since they are kept as-is as of commonmark 0.29 + if !bytes[span_start..span_end].iter().all(|&b| b == b' ') { + let opening = match bytes[span_start] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let closing = match bytes[span_end - 1] { + b' ' | b'\r' | b'\n' => true, + _ => false, + }; + let drop_enclosing_whitespace = opening && closing; + + if drop_enclosing_whitespace { + span_start += 1; + if span_start < span_end { + span_end -= 1; + } + } + + let mut ix = first_ix; + + while ix < close { + if let ItemBody::HardBreak | ItemBody::SoftBreak = self.tree[ix].item.body { + if drop_enclosing_whitespace { + // check whether break should be ignored + if ix == first_ix { + ix = ix + 1; + span_start = min(span_end, self.tree[ix].item.start); + continue; + } else if ix == last_ix && last_ix > first_ix { + ix = ix + 1; + continue; + } + } + + let end = bytes[self.tree[ix].item.start..] + .iter() + .position(|&b| b == b'\r' || b == b'\n') + .unwrap() + + self.tree[ix].item.start; + if let Some(ref mut buf) = buf { + buf.push_str(&self.text[self.tree[ix].item.start..end]); + buf.push(' '); + } else { + let mut new_buf = String::with_capacity(span_end - span_start); + new_buf.push_str(&self.text[span_start..end]); + new_buf.push(' '); + buf = Some(new_buf); + } + } else if let Some(ref mut buf) = buf { + let end = if ix == last_ix { + span_end + } else { + self.tree[ix].item.end + }; + buf.push_str(&self.text[self.tree[ix].item.start..end]); + } + ix = ix + 1; + } + } + + let cow = if let Some(buf) = buf { + buf.into() + } else { + self.text[span_start..span_end].into() + }; + if preceding_backslash { + self.tree[open].item.body = ItemBody::Text; + self.tree[open].item.end = self.tree[open].item.start + 1; + self.tree[open].next = Some(close); + self.tree[close].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[close].item.start = self.tree[open].item.start + 1; + } else { + self.tree[open].item.body = ItemBody::Code(self.allocs.allocate_cow(cow)); + self.tree[open].item.end = self.tree[close].item.end; + self.tree[open].next = self.tree[close].next; + } + } + + /// On success, returns a buffer containing the inline html and byte offset. + /// When no bytes were skipped, the buffer will be empty and the html can be + /// represented as a subslice of the input string. + fn scan_inline_html(&mut self, bytes: &[u8], ix: usize) -> Option<(Vec, usize)> { + let c = *bytes.get(ix)?; + if c == b'!' { + Some(( + vec![], + scan_inline_html_comment(bytes, ix + 1, &mut self.html_scan_guard)?, + )) + } else if c == b'?' { + Some(( + vec![], + scan_inline_html_processing(bytes, ix + 1, &mut self.html_scan_guard)?, + )) + } else { + let (span, i) = scan_html_block_inner( + // Subtract 1 to include the < character + &bytes[(ix - 1)..], + Some(&|_bytes| { + let mut line_start = LineStart::new(bytes); + let _ = scan_containers(&self.tree, &mut line_start); + line_start.bytes_scanned() + }), + )?; + Some((span, i + ix - 1)) + } + } + + /// Consumes the event iterator and produces an iterator that produces + /// `(Event, Range)` pairs, where the `Range` value maps to the corresponding + /// range in the markdown source. + pub fn into_offset_iter(self) -> OffsetIter<'a> { + OffsetIter { inner: self } + } +} + +pub(crate) enum LoopInstruction { + /// Continue looking for more special bytes, but skip next few bytes. + ContinueAndSkip(usize), + /// Break looping immediately, returning with the given index and value. + BreakAtWith(usize, T), +} + +#[cfg(all(target_arch = "x86_64", feature = "simd"))] +pub(crate) struct LookupTable { + pub simd: [u8; 16], + pub scalar: [bool; 256], +} + +#[cfg(not(all(target_arch = "x86_64", feature = "simd")))] +type LookupTable = [bool; 256]; + +/// This function walks the byte slices from the given index and +/// calls the callback function on all bytes (and their indices) that are in the following set: +/// `` ` ``, `\`, `&`, `*`, `_`, `~`, `!`, `<`, `[`, `]`, `|`, `\r`, `\n` +/// It is guaranteed not call the callback on other bytes. +/// Whenever `callback(ix, byte)` returns a `ContinueAndSkip(n)` value, the callback +/// will not be called with an index that is less than `ix + n + 1`. +/// When the callback returns a `BreakAtWith(end_ix, opt+val)`, no more callbacks will be +/// called and the function returns immediately with the return value `(end_ix, opt_val)`. +/// If `BreakAtWith(..)` is never returned, this function will return the first +/// index that is outside the byteslice bound and a `None` value. +fn iterate_special_bytes( + lut: &LookupTable, + bytes: &[u8], + ix: usize, + callback: F, +) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + #[cfg(all(target_arch = "x86_64", feature = "simd"))] + { + crate::simd::iterate_special_bytes(lut, bytes, ix, callback) + } + #[cfg(not(all(target_arch = "x86_64", feature = "simd")))] + { + scalar_iterate_special_bytes(lut, bytes, ix, callback) + } +} + +pub(crate) fn scalar_iterate_special_bytes( + lut: &[bool; 256], + bytes: &[u8], + mut ix: usize, + mut callback: F, +) -> (usize, Option) +where + F: FnMut(usize, u8) -> LoopInstruction>, +{ + while ix < bytes.len() { + let b = bytes[ix]; + if lut[b as usize] { + match callback(ix, b) { + LoopInstruction::ContinueAndSkip(skip) => { + ix += skip; + } + LoopInstruction::BreakAtWith(ix, val) => { + return (ix, val); + } + } + } + ix += 1; + } + + (ix, None) +} + +/// Markdown event and source range iterator. +/// +/// Generates tuples where the first element is the markdown event and the second +/// is a the corresponding range in the source string. +/// +/// Constructed from a `Parser` using its +/// [`into_offset_iter`](struct.Parser.html#method.into_offset_iter) method. +pub struct OffsetIter<'a> { + inner: Parser<'a>, +} + +impl<'a> Iterator for OffsetIter<'a> { + type Item = (Event<'a>, Range); + + fn next(&mut self) -> Option { + match self.inner.tree.cur() { + None => { + let ix = self.inner.tree.pop()?; + let tag = item_to_tag(&self.inner.tree[ix].item, &self.inner.allocs); + self.inner.tree.next_sibling(ix); + Some(( + Event::End(tag), + self.inner.tree[ix].item.start..self.inner.tree[ix].item.end, + )) + } + Some(cur_ix) => { + if self.inner.tree[cur_ix].item.body.is_inline() { + self.inner.handle_inline(); + } + + let node = self.inner.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.inner.text, &self.inner.allocs); + if let Event::Start(..) = event { + self.inner.tree.push(); + } else { + self.inner.tree.next_sibling(cur_ix); + } + Some((event, item.start..item.end)) + } + } + } +} + +fn item_to_tag<'a>(item: &Item, allocs: &Allocations<'a>) -> Tag<'a> { + match item.body { + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + } +} + +fn item_to_event<'a>(item: Item, text: &'a str, allocs: &Allocations<'a>) -> Event<'a> { + let tag = match item.body { + ItemBody::Text => return Event::Text(text[item.start..item.end].into()), + ItemBody::Code(cow_ix) => return Event::Code(allocs[cow_ix].clone()), + ItemBody::SynthesizeText(cow_ix) => return Event::Text(allocs[cow_ix].clone()), + ItemBody::SynthesizeChar(c) => return Event::Text(c.into()), + ItemBody::Html => return Event::Html(text[item.start..item.end].into()), + ItemBody::OwnedHtml(cow_ix) => return Event::Html(allocs[cow_ix].clone()), + ItemBody::SoftBreak => return Event::SoftBreak, + ItemBody::HardBreak => return Event::HardBreak, + ItemBody::FootnoteReference(cow_ix) => { + return Event::FootnoteReference(allocs[cow_ix].clone()) + } + ItemBody::TaskListMarker(checked) => return Event::TaskListMarker(checked), + ItemBody::Rule => return Event::Rule, + + ItemBody::Paragraph => Tag::Paragraph, + ItemBody::Emphasis => Tag::Emphasis, + ItemBody::Strong => Tag::Strong, + ItemBody::Strikethrough => Tag::Strikethrough, + ItemBody::Link(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Link(*link_type, url.clone(), title.clone()) + } + ItemBody::Image(link_ix) => { + let &(ref link_type, ref url, ref title) = allocs.index(link_ix); + Tag::Image(*link_type, url.clone(), title.clone()) + } + ItemBody::Heading(level) => Tag::Heading(level), + ItemBody::FencedCodeBlock(cow_ix) => { + Tag::CodeBlock(CodeBlockKind::Fenced(allocs[cow_ix].clone())) + } + ItemBody::IndentCodeBlock => Tag::CodeBlock(CodeBlockKind::Indented), + ItemBody::BlockQuote => Tag::BlockQuote, + ItemBody::List(_, c, listitem_start) => { + if c == b'.' || c == b')' { + Tag::List(Some(listitem_start)) + } else { + Tag::List(None) + } + } + ItemBody::ListItem(_) => Tag::Item, + ItemBody::TableHead => Tag::TableHead, + ItemBody::TableCell => Tag::TableCell, + ItemBody::TableRow => Tag::TableRow, + ItemBody::Table(alignment_ix) => Tag::Table(allocs[alignment_ix].clone()), + ItemBody::FootnoteDefinition(cow_ix) => Tag::FootnoteDefinition(allocs[cow_ix].clone()), + _ => panic!("unexpected item body {:?}", item.body), + }; + + Event::Start(tag) +} + +// https://english.stackexchange.com/a/285573 +fn surgerize_tight_list(tree: &mut Tree, list_ix: TreeIndex) { + let mut list_item = tree[list_ix].child; + while let Some(listitem_ix) = list_item { + // first child is special, controls how we repoint list_item.child + let list_item_firstborn = tree[listitem_ix].child; + + // Check that list item has children - this is not necessarily the case! + if let Some(firstborn_ix) = list_item_firstborn { + if let ItemBody::Paragraph = tree[firstborn_ix].item.body { + tree[listitem_ix].child = tree[firstborn_ix].child; + } + + let mut list_item_child = Some(firstborn_ix); + let mut node_to_repoint = None; + while let Some(child_ix) = list_item_child { + // surgerize paragraphs + let repoint_ix = if let ItemBody::Paragraph = tree[child_ix].item.body { + if let Some(child_firstborn) = tree[child_ix].child { + if let Some(repoint_ix) = node_to_repoint { + tree[repoint_ix].next = Some(child_firstborn); + } + let mut child_lastborn = child_firstborn; + while let Some(lastborn_next_ix) = tree[child_lastborn].next { + child_lastborn = lastborn_next_ix; + } + child_lastborn + } else { + child_ix + } + } else { + child_ix + }; + + node_to_repoint = Some(repoint_ix); + tree[repoint_ix].next = tree[child_ix].next; + list_item_child = tree[child_ix].next; + } + } + + list_item = tree[listitem_ix].next; + } +} + +impl<'a> Iterator for Parser<'a> { + type Item = Event<'a>; + + fn next(&mut self) -> Option> { + match self.tree.cur() { + None => { + let ix = self.tree.pop()?; + let tag = item_to_tag(&self.tree[ix].item, &self.allocs); + self.tree.next_sibling(ix); + Some(Event::End(tag)) + } + Some(cur_ix) => { + if self.tree[cur_ix].item.body.is_inline() { + self.handle_inline(); + } + + let node = self.tree[cur_ix]; + let item = node.item; + let event = item_to_event(item, self.text, &self.allocs); + if let Event::Start(..) = event { + self.tree.push(); + } else { + self.tree.next_sibling(cur_ix); + } + Some(event) + } + } + } +} + +#[cfg(test)] +mod test { + use super::*; + use crate::tree::Node; + + // TODO: move these tests to tests/html.rs? + + fn parser_with_extensions(text: &str) -> Parser<'_> { + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + + Parser::new_ext(text, opts) + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn node_size() { + let node_size = std::mem::size_of::>(); + assert_eq!(48, node_size); + } + + #[test] + #[cfg(target_pointer_width = "64")] + fn body_size() { + let body_size = std::mem::size_of::(); + assert_eq!(16, body_size); + } + + #[test] + fn single_open_fish_bracket() { + // dont crash + assert_eq!(3, Parser::new("<").count()); + } + + #[test] + fn lone_hashtag() { + // dont crash + assert_eq!(2, Parser::new("#").count()); + } + + #[test] + fn lots_of_backslashes() { + // dont crash + Parser::new("\\\\\r\r").count(); + Parser::new("\\\r\r\\.\\\\\r\r\\.\\").count(); + } + + #[test] + fn issue_320() { + // dont crash + parser_with_extensions(":\r\t> |\r:\r\t> |\r").count(); + } + + #[test] + fn issue_319() { + // dont crash + parser_with_extensions("|\r-]([^|\r-]([^").count(); + parser_with_extensions("|\r\r=][^|\r\r=][^car").count(); + } + + #[test] + fn issue_303() { + // dont crash + parser_with_extensions("[^\r\ra]").count(); + parser_with_extensions("\r\r]Z[^\x00\r\r]Z[^\x00").count(); + } + + #[test] + fn issue_313() { + // dont crash + parser_with_extensions("*]0[^\r\r*]0[^").count(); + parser_with_extensions("[^\r> `][^\r> `][^\r> `][").count(); + } + + #[test] + fn issue_311() { + // dont crash + parser_with_extensions("\\\u{0d}-\u{09}\\\u{0d}-\u{09}").count(); + } + + #[test] + fn issue_283() { + let input = std::str::from_utf8(b"\xf0\x9b\xb2\x9f - \\\n> - ").count(); + parser_with_extensions("- \n\n").count(); + } + + #[test] + fn issue_306() { + // dont crash + parser_with_extensions("*\r_<__*\r_<__*\r_<__*\r_<__").count(); + } + + #[test] + fn issue_305() { + // dont crash + parser_with_extensions("_6**6*_*").count(); + } + + #[test] + fn another_emphasis_panic() { + parser_with_extensions("*__#_#__*").count(); + } + + #[test] + fn offset_iter() { + let event_offsets: Vec<_> = Parser::new("*hello* world") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..13), (0..7), (1..6), (0..7), (7..13), (0..13)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn reference_link_offsets() { + let range = + Parser::new("# H1\n[testing][Some reference]\n\n[Some reference]: https://github.com") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::Start(Tag::Link(LinkType::Reference, ..), ..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(5..30, range); + } + + #[test] + fn footnote_offsets() { + let range = parser_with_extensions("Testing this[^1] out.\n\n[^1]: Footnote.") + .into_offset_iter() + .filter_map(|(ev, range)| match ev { + Event::FootnoteReference(..) => Some(range), + _ => None, + }) + .next() + .unwrap(); + assert_eq!(12..16, range); + } + + #[test] + fn table_offset() { + let markdown = "a\n\nTesting|This|Outtt\n--|:--:|--:\nSome Data|Other data|asdf"; + let event_offset = parser_with_extensions(markdown) + .into_offset_iter() + .map(|(_ev, range)| range) + .nth(3) + .unwrap(); + let expected_offset = 3..59; + assert_eq!(expected_offset, event_offset); + } + + #[test] + fn offset_iter_issue_378() { + let event_offsets: Vec<_> = Parser::new("a [b](c) d") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..10), (0..2), (2..8), (3..4), (2..8), (8..10), (0..10)]; + assert_eq!(expected_offsets, event_offsets); + } + + #[test] + fn offset_iter_issue_404() { + let event_offsets: Vec<_> = Parser::new("###\n") + .into_offset_iter() + .map(|(_ev, range)| range) + .collect(); + let expected_offsets = vec![(0..4), (0..4)]; + assert_eq!(expected_offsets, event_offsets); + } + + // FIXME: add this one regression suite + #[test] + fn link_def_at_eof() { + let test_str = "[My site][world]\n\n[world]: https://vincentprouillet.com"; + let expected = "

    My site

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn no_footnote_refs_without_option() { + let test_str = "a [^a]\n\n[^a]: yolo"; + let expected = "

    a ^a

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_at_eof() { + let test_str = "[test]:\\"; + let expected = ""; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn ref_def_cr_lf() { + let test_str = "[a]: /u\r\n\n[a]"; + let expected = "

    a

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn no_dest_refdef() { + let test_str = "[a]:"; + let expected = "

    [a]:

    \n"; + + let mut buf = String::new(); + crate::html::push_html(&mut buf, Parser::new(test_str)); + assert_eq!(expected, buf); + } + + #[test] + fn broken_links_called_only_once() { + for &(markdown, expected) in &[ + ("See also [`g()`][crate::g].", 1), + ("See also [`g()`][crate::g][].", 1), + ("[brokenlink1] some other node [brokenlink2]", 2), + ] { + let mut times_called = 0; + let callback = &mut |_broken_link: BrokenLink| { + times_called += 1; + None + }; + let parser = + Parser::new_with_broken_link_callback(markdown, Options::empty(), Some(callback)); + for _ in parser {} + assert_eq!(times_called, expected); + } + } + + #[test] + fn simple_broken_link_callback() { + let test_str = "This is a link w/o def: [hello][world]"; + let mut callback = |broken_link: BrokenLink| { + assert_eq!("world", broken_link.reference); + assert_eq!(&test_str[broken_link.span], "[hello][world]"); + let url = "YOLO".into(); + let title = "SWAG".to_owned().into(); + Some((url, title)) + }; + let parser = + Parser::new_with_broken_link_callback(test_str, Options::empty(), Some(&mut callback)); + let mut link_tag_count = 0; + for (typ, url, title) in parser.filter_map(|event| match event { + Event::Start(tag) | Event::End(tag) => match tag { + Tag::Link(typ, url, title) => Some((typ, url, title)), + _ => None, + }, + _ => None, + }) { + link_tag_count += 1; + assert_eq!(typ, LinkType::ReferenceUnknown); + assert_eq!(url.as_ref(), "YOLO"); + assert_eq!(title.as_ref(), "SWAG"); + } + assert!(link_tag_count > 0); + } + + #[test] + fn code_block_kind_check_fenced() { + let parser = Parser::new("hello\n```test\ntadam\n```"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Fenced(syntax))) => { + assert_eq!(syntax.as_ref(), "test"); + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } + + #[test] + fn code_block_kind_check_indented() { + let parser = Parser::new("hello\n\n ```test\n tadam\nhello"); + let mut found = 0; + for (ev, _range) in parser.into_offset_iter() { + match ev { + Event::Start(Tag::CodeBlock(CodeBlockKind::Indented)) => { + found += 1; + } + _ => {} + } + } + assert_eq!(found, 1); + } +} diff --git a/vendor/pulldown-cmark/src/puncttable.rs b/vendor/pulldown-cmark/src/puncttable.rs index a1b0751a54..f46464b64f 100644 --- a/vendor/pulldown-cmark/src/puncttable.rs +++ b/vendor/pulldown-cmark/src/puncttable.rs @@ -1,351 +1,351 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! CommonMark punctuation set based on spec and Unicode properties. - -// Autogenerated by mk_puncttable.py - -const PUNCT_MASKS_ASCII: [u16; 8] = [ - 0x0000, // U+0000...U+000F - 0x0000, // U+0010...U+001F - 0xfffe, // U+0020...U+002F - 0xfc00, // U+0030...U+003F - 0x0001, // U+0040...U+004F - 0xf800, // U+0050...U+005F - 0x0001, // U+0060...U+006F - 0x7800, // U+0070...U+007F -]; - -const PUNCT_TAB: [u16; 132] = [ - 10, // U+00A0...U+00AF - 11, // U+00B0...U+00BF - 55, // U+0370...U+037F - 56, // U+0380...U+038F - 85, // U+0550...U+055F - 88, // U+0580...U+058F - 91, // U+05B0...U+05BF - 92, // U+05C0...U+05CF - 95, // U+05F0...U+05FF - 96, // U+0600...U+060F - 97, // U+0610...U+061F - 102, // U+0660...U+066F - 109, // U+06D0...U+06DF - 112, // U+0700...U+070F - 127, // U+07F0...U+07FF - 131, // U+0830...U+083F - 133, // U+0850...U+085F - 150, // U+0960...U+096F - 151, // U+0970...U+097F - 175, // U+0AF0...U+0AFF - 223, // U+0DF0...U+0DFF - 228, // U+0E40...U+0E4F - 229, // U+0E50...U+0E5F - 240, // U+0F00...U+0F0F - 241, // U+0F10...U+0F1F - 243, // U+0F30...U+0F3F - 248, // U+0F80...U+0F8F - 253, // U+0FD0...U+0FDF - 260, // U+1040...U+104F - 271, // U+10F0...U+10FF - 310, // U+1360...U+136F - 320, // U+1400...U+140F - 358, // U+1660...U+166F - 361, // U+1690...U+169F - 366, // U+16E0...U+16EF - 371, // U+1730...U+173F - 381, // U+17D0...U+17DF - 384, // U+1800...U+180F - 404, // U+1940...U+194F - 417, // U+1A10...U+1A1F - 426, // U+1AA0...U+1AAF - 437, // U+1B50...U+1B5F - 438, // U+1B60...U+1B6F - 447, // U+1BF0...U+1BFF - 451, // U+1C30...U+1C3F - 455, // U+1C70...U+1C7F - 460, // U+1CC0...U+1CCF - 461, // U+1CD0...U+1CDF - 513, // U+2010...U+201F - 514, // U+2020...U+202F - 515, // U+2030...U+203F - 516, // U+2040...U+204F - 517, // U+2050...U+205F - 519, // U+2070...U+207F - 520, // U+2080...U+208F - 560, // U+2300...U+230F - 562, // U+2320...U+232F - 630, // U+2760...U+276F - 631, // U+2770...U+277F - 636, // U+27C0...U+27CF - 638, // U+27E0...U+27EF - 664, // U+2980...U+298F - 665, // U+2990...U+299F - 669, // U+29D0...U+29DF - 671, // U+29F0...U+29FF - 719, // U+2CF0...U+2CFF - 727, // U+2D70...U+2D7F - 736, // U+2E00...U+2E0F - 737, // U+2E10...U+2E1F - 738, // U+2E20...U+2E2F - 739, // U+2E30...U+2E3F - 740, // U+2E40...U+2E4F - 768, // U+3000...U+300F - 769, // U+3010...U+301F - 771, // U+3030...U+303F - 778, // U+30A0...U+30AF - 783, // U+30F0...U+30FF - 2639, // U+A4F0...U+A4FF - 2656, // U+A600...U+A60F - 2663, // U+A670...U+A67F - 2671, // U+A6F0...U+A6FF - 2695, // U+A870...U+A87F - 2700, // U+A8C0...U+A8CF - 2703, // U+A8F0...U+A8FF - 2706, // U+A920...U+A92F - 2709, // U+A950...U+A95F - 2716, // U+A9C0...U+A9CF - 2717, // U+A9D0...U+A9DF - 2725, // U+AA50...U+AA5F - 2733, // U+AAD0...U+AADF - 2735, // U+AAF0...U+AAFF - 2750, // U+ABE0...U+ABEF - 4051, // U+FD30...U+FD3F - 4065, // U+FE10...U+FE1F - 4067, // U+FE30...U+FE3F - 4068, // U+FE40...U+FE4F - 4069, // U+FE50...U+FE5F - 4070, // U+FE60...U+FE6F - 4080, // U+FF00...U+FF0F - 4081, // U+FF10...U+FF1F - 4082, // U+FF20...U+FF2F - 4083, // U+FF30...U+FF3F - 4085, // U+FF50...U+FF5F - 4086, // U+FF60...U+FF6F - 4112, // U+10100...U+1010F - 4153, // U+10390...U+1039F - 4157, // U+103D0...U+103DF - 4182, // U+10560...U+1056F - 4229, // U+10850...U+1085F - 4241, // U+10910...U+1091F - 4243, // U+10930...U+1093F - 4261, // U+10A50...U+10A5F - 4263, // U+10A70...U+10A7F - 4271, // U+10AF0...U+10AFF - 4275, // U+10B30...U+10B3F - 4281, // U+10B90...U+10B9F - 4356, // U+11040...U+1104F - 4363, // U+110B0...U+110BF - 4364, // U+110C0...U+110CF - 4372, // U+11140...U+1114F - 4375, // U+11170...U+1117F - 4380, // U+111C0...U+111CF - 4387, // U+11230...U+1123F - 4428, // U+114C0...U+114CF - 4444, // U+115C0...U+115CF - 4452, // U+11640...U+1164F - 4679, // U+12470...U+1247F - 5798, // U+16A60...U+16A6F - 5807, // U+16AF0...U+16AFF - 5811, // U+16B30...U+16B3F - 5812, // U+16B40...U+16B4F - 7113, // U+1BC90...U+1BC9F -]; - -const PUNCT_MASKS: [u16; 132] = [ - 0x0882, // U+00A0...U+00AF - 0x88c0, // U+00B0...U+00BF - 0x4000, // U+0370...U+037F - 0x0080, // U+0380...U+038F - 0xfc00, // U+0550...U+055F - 0x0600, // U+0580...U+058F - 0x4000, // U+05B0...U+05BF - 0x0049, // U+05C0...U+05CF - 0x0018, // U+05F0...U+05FF - 0x3600, // U+0600...U+060F - 0xc800, // U+0610...U+061F - 0x3c00, // U+0660...U+066F - 0x0010, // U+06D0...U+06DF - 0x3fff, // U+0700...U+070F - 0x0380, // U+07F0...U+07FF - 0x7fff, // U+0830...U+083F - 0x4000, // U+0850...U+085F - 0x0030, // U+0960...U+096F - 0x0001, // U+0970...U+097F - 0x0001, // U+0AF0...U+0AFF - 0x0010, // U+0DF0...U+0DFF - 0x8000, // U+0E40...U+0E4F - 0x0c00, // U+0E50...U+0E5F - 0xfff0, // U+0F00...U+0F0F - 0x0017, // U+0F10...U+0F1F - 0x3c00, // U+0F30...U+0F3F - 0x0020, // U+0F80...U+0F8F - 0x061f, // U+0FD0...U+0FDF - 0xfc00, // U+1040...U+104F - 0x0800, // U+10F0...U+10FF - 0x01ff, // U+1360...U+136F - 0x0001, // U+1400...U+140F - 0x6000, // U+1660...U+166F - 0x1800, // U+1690...U+169F - 0x3800, // U+16E0...U+16EF - 0x0060, // U+1730...U+173F - 0x0770, // U+17D0...U+17DF - 0x07ff, // U+1800...U+180F - 0x0030, // U+1940...U+194F - 0xc000, // U+1A10...U+1A1F - 0x3f7f, // U+1AA0...U+1AAF - 0xfc00, // U+1B50...U+1B5F - 0x0001, // U+1B60...U+1B6F - 0xf000, // U+1BF0...U+1BFF - 0xf800, // U+1C30...U+1C3F - 0xc000, // U+1C70...U+1C7F - 0x00ff, // U+1CC0...U+1CCF - 0x0008, // U+1CD0...U+1CDF - 0xffff, // U+2010...U+201F - 0x00ff, // U+2020...U+202F - 0xffff, // U+2030...U+203F - 0xffef, // U+2040...U+204F - 0x7ffb, // U+2050...U+205F - 0x6000, // U+2070...U+207F - 0x6000, // U+2080...U+208F - 0x0f00, // U+2300...U+230F - 0x0600, // U+2320...U+232F - 0xff00, // U+2760...U+276F - 0x003f, // U+2770...U+277F - 0x0060, // U+27C0...U+27CF - 0xffc0, // U+27E0...U+27EF - 0xfff8, // U+2980...U+298F - 0x01ff, // U+2990...U+299F - 0x0f00, // U+29D0...U+29DF - 0x3000, // U+29F0...U+29FF - 0xde00, // U+2CF0...U+2CFF - 0x0001, // U+2D70...U+2D7F - 0xffff, // U+2E00...U+2E0F - 0xffff, // U+2E10...U+2E1F - 0x7fff, // U+2E20...U+2E2F - 0xffff, // U+2E30...U+2E3F - 0x0007, // U+2E40...U+2E4F - 0xff0e, // U+3000...U+300F - 0xfff3, // U+3010...U+301F - 0x2001, // U+3030...U+303F - 0x0001, // U+30A0...U+30AF - 0x0800, // U+30F0...U+30FF - 0xc000, // U+A4F0...U+A4FF - 0xe000, // U+A600...U+A60F - 0x4008, // U+A670...U+A67F - 0x00fc, // U+A6F0...U+A6FF - 0x00f0, // U+A870...U+A87F - 0xc000, // U+A8C0...U+A8CF - 0x0700, // U+A8F0...U+A8FF - 0xc000, // U+A920...U+A92F - 0x8000, // U+A950...U+A95F - 0x3ffe, // U+A9C0...U+A9CF - 0xc000, // U+A9D0...U+A9DF - 0xf000, // U+AA50...U+AA5F - 0xc000, // U+AAD0...U+AADF - 0x0003, // U+AAF0...U+AAFF - 0x0800, // U+ABE0...U+ABEF - 0xc000, // U+FD30...U+FD3F - 0x03ff, // U+FE10...U+FE1F - 0xffff, // U+FE30...U+FE3F - 0xffff, // U+FE40...U+FE4F - 0xfff7, // U+FE50...U+FE5F - 0x0d0b, // U+FE60...U+FE6F - 0xf7ee, // U+FF00...U+FF0F - 0x8c00, // U+FF10...U+FF1F - 0x0001, // U+FF20...U+FF2F - 0xb800, // U+FF30...U+FF3F - 0xa800, // U+FF50...U+FF5F - 0x003f, // U+FF60...U+FF6F - 0x0007, // U+10100...U+1010F - 0x8000, // U+10390...U+1039F - 0x0001, // U+103D0...U+103DF - 0x8000, // U+10560...U+1056F - 0x0080, // U+10850...U+1085F - 0x8000, // U+10910...U+1091F - 0x8000, // U+10930...U+1093F - 0x01ff, // U+10A50...U+10A5F - 0x8000, // U+10A70...U+10A7F - 0x007f, // U+10AF0...U+10AFF - 0xfe00, // U+10B30...U+10B3F - 0x1e00, // U+10B90...U+10B9F - 0x3f80, // U+11040...U+1104F - 0xd800, // U+110B0...U+110BF - 0x0003, // U+110C0...U+110CF - 0x000f, // U+11140...U+1114F - 0x0030, // U+11170...U+1117F - 0x21e0, // U+111C0...U+111CF - 0x3f00, // U+11230...U+1123F - 0x0040, // U+114C0...U+114CF - 0x03fe, // U+115C0...U+115CF - 0x000e, // U+11640...U+1164F - 0x001f, // U+12470...U+1247F - 0xc000, // U+16A60...U+16A6F - 0x0020, // U+16AF0...U+16AFF - 0x0f80, // U+16B30...U+16B3F - 0x0010, // U+16B40...U+16B4F - 0x8000, // U+1BC90...U+1BC9F -]; - -pub fn is_ascii_punctuation(c: u8) -> bool { - c < 128 && (PUNCT_MASKS_ASCII[(c / 16) as usize] & (1 << (c & 15))) != 0 -} - -pub fn is_punctuation(c: char) -> bool { - let cp = c as u32; - if cp < 128 { - return is_ascii_punctuation(cp as u8); - } - if cp > 0x1BC9F { - return false; - } - let high = (cp / 16) as u16; - match PUNCT_TAB.binary_search(&high) { - Ok(index) => (PUNCT_MASKS[index] & (1 << (cp & 15))) != 0, - _ => false, - } -} - -#[cfg(test)] -mod tests { - use super::{is_ascii_punctuation, is_punctuation}; - - #[test] - fn test_ascii() { - assert!(is_ascii_punctuation(b'!')); - assert!(is_ascii_punctuation(b'@')); - assert!(is_ascii_punctuation(b'~')); - assert!(!is_ascii_punctuation(b' ')); - assert!(!is_ascii_punctuation(b'0')); - assert!(!is_ascii_punctuation(b'A')); - assert!(!is_ascii_punctuation(0xA1)); - } - - #[test] - fn test_unicode() { - assert!(is_punctuation('~')); - assert!(!is_punctuation(' ')); - - assert!(is_punctuation('\u{00A1}')); - assert!(is_punctuation('\u{060C}')); - assert!(is_punctuation('\u{FF65}')); - assert!(is_punctuation('\u{1BC9F}')); - assert!(!is_punctuation('\u{1BCA0}')); - } -} +// Copyright 2015 Google Inc. All rights reserved. +// +// 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. + +//! CommonMark punctuation set based on spec and Unicode properties. + +// Autogenerated by mk_puncttable.py + +const PUNCT_MASKS_ASCII: [u16; 8] = [ + 0x0000, // U+0000...U+000F + 0x0000, // U+0010...U+001F + 0xfffe, // U+0020...U+002F + 0xfc00, // U+0030...U+003F + 0x0001, // U+0040...U+004F + 0xf800, // U+0050...U+005F + 0x0001, // U+0060...U+006F + 0x7800, // U+0070...U+007F +]; + +const PUNCT_TAB: [u16; 132] = [ + 10, // U+00A0...U+00AF + 11, // U+00B0...U+00BF + 55, // U+0370...U+037F + 56, // U+0380...U+038F + 85, // U+0550...U+055F + 88, // U+0580...U+058F + 91, // U+05B0...U+05BF + 92, // U+05C0...U+05CF + 95, // U+05F0...U+05FF + 96, // U+0600...U+060F + 97, // U+0610...U+061F + 102, // U+0660...U+066F + 109, // U+06D0...U+06DF + 112, // U+0700...U+070F + 127, // U+07F0...U+07FF + 131, // U+0830...U+083F + 133, // U+0850...U+085F + 150, // U+0960...U+096F + 151, // U+0970...U+097F + 175, // U+0AF0...U+0AFF + 223, // U+0DF0...U+0DFF + 228, // U+0E40...U+0E4F + 229, // U+0E50...U+0E5F + 240, // U+0F00...U+0F0F + 241, // U+0F10...U+0F1F + 243, // U+0F30...U+0F3F + 248, // U+0F80...U+0F8F + 253, // U+0FD0...U+0FDF + 260, // U+1040...U+104F + 271, // U+10F0...U+10FF + 310, // U+1360...U+136F + 320, // U+1400...U+140F + 358, // U+1660...U+166F + 361, // U+1690...U+169F + 366, // U+16E0...U+16EF + 371, // U+1730...U+173F + 381, // U+17D0...U+17DF + 384, // U+1800...U+180F + 404, // U+1940...U+194F + 417, // U+1A10...U+1A1F + 426, // U+1AA0...U+1AAF + 437, // U+1B50...U+1B5F + 438, // U+1B60...U+1B6F + 447, // U+1BF0...U+1BFF + 451, // U+1C30...U+1C3F + 455, // U+1C70...U+1C7F + 460, // U+1CC0...U+1CCF + 461, // U+1CD0...U+1CDF + 513, // U+2010...U+201F + 514, // U+2020...U+202F + 515, // U+2030...U+203F + 516, // U+2040...U+204F + 517, // U+2050...U+205F + 519, // U+2070...U+207F + 520, // U+2080...U+208F + 560, // U+2300...U+230F + 562, // U+2320...U+232F + 630, // U+2760...U+276F + 631, // U+2770...U+277F + 636, // U+27C0...U+27CF + 638, // U+27E0...U+27EF + 664, // U+2980...U+298F + 665, // U+2990...U+299F + 669, // U+29D0...U+29DF + 671, // U+29F0...U+29FF + 719, // U+2CF0...U+2CFF + 727, // U+2D70...U+2D7F + 736, // U+2E00...U+2E0F + 737, // U+2E10...U+2E1F + 738, // U+2E20...U+2E2F + 739, // U+2E30...U+2E3F + 740, // U+2E40...U+2E4F + 768, // U+3000...U+300F + 769, // U+3010...U+301F + 771, // U+3030...U+303F + 778, // U+30A0...U+30AF + 783, // U+30F0...U+30FF + 2639, // U+A4F0...U+A4FF + 2656, // U+A600...U+A60F + 2663, // U+A670...U+A67F + 2671, // U+A6F0...U+A6FF + 2695, // U+A870...U+A87F + 2700, // U+A8C0...U+A8CF + 2703, // U+A8F0...U+A8FF + 2706, // U+A920...U+A92F + 2709, // U+A950...U+A95F + 2716, // U+A9C0...U+A9CF + 2717, // U+A9D0...U+A9DF + 2725, // U+AA50...U+AA5F + 2733, // U+AAD0...U+AADF + 2735, // U+AAF0...U+AAFF + 2750, // U+ABE0...U+ABEF + 4051, // U+FD30...U+FD3F + 4065, // U+FE10...U+FE1F + 4067, // U+FE30...U+FE3F + 4068, // U+FE40...U+FE4F + 4069, // U+FE50...U+FE5F + 4070, // U+FE60...U+FE6F + 4080, // U+FF00...U+FF0F + 4081, // U+FF10...U+FF1F + 4082, // U+FF20...U+FF2F + 4083, // U+FF30...U+FF3F + 4085, // U+FF50...U+FF5F + 4086, // U+FF60...U+FF6F + 4112, // U+10100...U+1010F + 4153, // U+10390...U+1039F + 4157, // U+103D0...U+103DF + 4182, // U+10560...U+1056F + 4229, // U+10850...U+1085F + 4241, // U+10910...U+1091F + 4243, // U+10930...U+1093F + 4261, // U+10A50...U+10A5F + 4263, // U+10A70...U+10A7F + 4271, // U+10AF0...U+10AFF + 4275, // U+10B30...U+10B3F + 4281, // U+10B90...U+10B9F + 4356, // U+11040...U+1104F + 4363, // U+110B0...U+110BF + 4364, // U+110C0...U+110CF + 4372, // U+11140...U+1114F + 4375, // U+11170...U+1117F + 4380, // U+111C0...U+111CF + 4387, // U+11230...U+1123F + 4428, // U+114C0...U+114CF + 4444, // U+115C0...U+115CF + 4452, // U+11640...U+1164F + 4679, // U+12470...U+1247F + 5798, // U+16A60...U+16A6F + 5807, // U+16AF0...U+16AFF + 5811, // U+16B30...U+16B3F + 5812, // U+16B40...U+16B4F + 7113, // U+1BC90...U+1BC9F +]; + +const PUNCT_MASKS: [u16; 132] = [ + 0x0882, // U+00A0...U+00AF + 0x88c0, // U+00B0...U+00BF + 0x4000, // U+0370...U+037F + 0x0080, // U+0380...U+038F + 0xfc00, // U+0550...U+055F + 0x0600, // U+0580...U+058F + 0x4000, // U+05B0...U+05BF + 0x0049, // U+05C0...U+05CF + 0x0018, // U+05F0...U+05FF + 0x3600, // U+0600...U+060F + 0xc800, // U+0610...U+061F + 0x3c00, // U+0660...U+066F + 0x0010, // U+06D0...U+06DF + 0x3fff, // U+0700...U+070F + 0x0380, // U+07F0...U+07FF + 0x7fff, // U+0830...U+083F + 0x4000, // U+0850...U+085F + 0x0030, // U+0960...U+096F + 0x0001, // U+0970...U+097F + 0x0001, // U+0AF0...U+0AFF + 0x0010, // U+0DF0...U+0DFF + 0x8000, // U+0E40...U+0E4F + 0x0c00, // U+0E50...U+0E5F + 0xfff0, // U+0F00...U+0F0F + 0x0017, // U+0F10...U+0F1F + 0x3c00, // U+0F30...U+0F3F + 0x0020, // U+0F80...U+0F8F + 0x061f, // U+0FD0...U+0FDF + 0xfc00, // U+1040...U+104F + 0x0800, // U+10F0...U+10FF + 0x01ff, // U+1360...U+136F + 0x0001, // U+1400...U+140F + 0x6000, // U+1660...U+166F + 0x1800, // U+1690...U+169F + 0x3800, // U+16E0...U+16EF + 0x0060, // U+1730...U+173F + 0x0770, // U+17D0...U+17DF + 0x07ff, // U+1800...U+180F + 0x0030, // U+1940...U+194F + 0xc000, // U+1A10...U+1A1F + 0x3f7f, // U+1AA0...U+1AAF + 0xfc00, // U+1B50...U+1B5F + 0x0001, // U+1B60...U+1B6F + 0xf000, // U+1BF0...U+1BFF + 0xf800, // U+1C30...U+1C3F + 0xc000, // U+1C70...U+1C7F + 0x00ff, // U+1CC0...U+1CCF + 0x0008, // U+1CD0...U+1CDF + 0xffff, // U+2010...U+201F + 0x00ff, // U+2020...U+202F + 0xffff, // U+2030...U+203F + 0xffef, // U+2040...U+204F + 0x7ffb, // U+2050...U+205F + 0x6000, // U+2070...U+207F + 0x6000, // U+2080...U+208F + 0x0f00, // U+2300...U+230F + 0x0600, // U+2320...U+232F + 0xff00, // U+2760...U+276F + 0x003f, // U+2770...U+277F + 0x0060, // U+27C0...U+27CF + 0xffc0, // U+27E0...U+27EF + 0xfff8, // U+2980...U+298F + 0x01ff, // U+2990...U+299F + 0x0f00, // U+29D0...U+29DF + 0x3000, // U+29F0...U+29FF + 0xde00, // U+2CF0...U+2CFF + 0x0001, // U+2D70...U+2D7F + 0xffff, // U+2E00...U+2E0F + 0xffff, // U+2E10...U+2E1F + 0x7fff, // U+2E20...U+2E2F + 0xffff, // U+2E30...U+2E3F + 0x0007, // U+2E40...U+2E4F + 0xff0e, // U+3000...U+300F + 0xfff3, // U+3010...U+301F + 0x2001, // U+3030...U+303F + 0x0001, // U+30A0...U+30AF + 0x0800, // U+30F0...U+30FF + 0xc000, // U+A4F0...U+A4FF + 0xe000, // U+A600...U+A60F + 0x4008, // U+A670...U+A67F + 0x00fc, // U+A6F0...U+A6FF + 0x00f0, // U+A870...U+A87F + 0xc000, // U+A8C0...U+A8CF + 0x0700, // U+A8F0...U+A8FF + 0xc000, // U+A920...U+A92F + 0x8000, // U+A950...U+A95F + 0x3ffe, // U+A9C0...U+A9CF + 0xc000, // U+A9D0...U+A9DF + 0xf000, // U+AA50...U+AA5F + 0xc000, // U+AAD0...U+AADF + 0x0003, // U+AAF0...U+AAFF + 0x0800, // U+ABE0...U+ABEF + 0xc000, // U+FD30...U+FD3F + 0x03ff, // U+FE10...U+FE1F + 0xffff, // U+FE30...U+FE3F + 0xffff, // U+FE40...U+FE4F + 0xfff7, // U+FE50...U+FE5F + 0x0d0b, // U+FE60...U+FE6F + 0xf7ee, // U+FF00...U+FF0F + 0x8c00, // U+FF10...U+FF1F + 0x0001, // U+FF20...U+FF2F + 0xb800, // U+FF30...U+FF3F + 0xa800, // U+FF50...U+FF5F + 0x003f, // U+FF60...U+FF6F + 0x0007, // U+10100...U+1010F + 0x8000, // U+10390...U+1039F + 0x0001, // U+103D0...U+103DF + 0x8000, // U+10560...U+1056F + 0x0080, // U+10850...U+1085F + 0x8000, // U+10910...U+1091F + 0x8000, // U+10930...U+1093F + 0x01ff, // U+10A50...U+10A5F + 0x8000, // U+10A70...U+10A7F + 0x007f, // U+10AF0...U+10AFF + 0xfe00, // U+10B30...U+10B3F + 0x1e00, // U+10B90...U+10B9F + 0x3f80, // U+11040...U+1104F + 0xd800, // U+110B0...U+110BF + 0x0003, // U+110C0...U+110CF + 0x000f, // U+11140...U+1114F + 0x0030, // U+11170...U+1117F + 0x21e0, // U+111C0...U+111CF + 0x3f00, // U+11230...U+1123F + 0x0040, // U+114C0...U+114CF + 0x03fe, // U+115C0...U+115CF + 0x000e, // U+11640...U+1164F + 0x001f, // U+12470...U+1247F + 0xc000, // U+16A60...U+16A6F + 0x0020, // U+16AF0...U+16AFF + 0x0f80, // U+16B30...U+16B3F + 0x0010, // U+16B40...U+16B4F + 0x8000, // U+1BC90...U+1BC9F +]; + +pub fn is_ascii_punctuation(c: u8) -> bool { + c < 128 && (PUNCT_MASKS_ASCII[(c / 16) as usize] & (1 << (c & 15))) != 0 +} + +pub fn is_punctuation(c: char) -> bool { + let cp = c as u32; + if cp < 128 { + return is_ascii_punctuation(cp as u8); + } + if cp > 0x1BC9F { + return false; + } + let high = (cp / 16) as u16; + match PUNCT_TAB.binary_search(&high) { + Ok(index) => (PUNCT_MASKS[index] & (1 << (cp & 15))) != 0, + _ => false, + } +} + +#[cfg(test)] +mod tests { + use super::{is_ascii_punctuation, is_punctuation}; + + #[test] + fn test_ascii() { + assert!(is_ascii_punctuation(b'!')); + assert!(is_ascii_punctuation(b'@')); + assert!(is_ascii_punctuation(b'~')); + assert!(!is_ascii_punctuation(b' ')); + assert!(!is_ascii_punctuation(b'0')); + assert!(!is_ascii_punctuation(b'A')); + assert!(!is_ascii_punctuation(0xA1)); + } + + #[test] + fn test_unicode() { + assert!(is_punctuation('~')); + assert!(!is_punctuation(' ')); + + assert!(is_punctuation('\u{00A1}')); + assert!(is_punctuation('\u{060C}')); + assert!(is_punctuation('\u{FF65}')); + assert!(is_punctuation('\u{1BC9F}')); + assert!(!is_punctuation('\u{1BCA0}')); + } +} diff --git a/vendor/pulldown-cmark/src/scanners.rs b/vendor/pulldown-cmark/src/scanners.rs index 884d4e49f2..21a37c8ad6 100644 --- a/vendor/pulldown-cmark/src/scanners.rs +++ b/vendor/pulldown-cmark/src/scanners.rs @@ -1,1247 +1,1308 @@ -// Copyright 2015 Google Inc. All rights reserved. -// -// 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. - -//! Scanners for fragments of CommonMark syntax - -use std::char; -use std::convert::TryInto; - -use crate::entities; -use crate::parse::{Alignment, HtmlScanGuard, LinkType}; -pub use crate::puncttable::{is_ascii_punctuation, is_punctuation}; -use crate::strings::CowStr; - -use memchr::memchr; - -// sorted for binary search -const HTML_TAGS: [&str; 62] = [ - "address", - "article", - "aside", - "base", - "basefont", - "blockquote", - "body", - "caption", - "center", - "col", - "colgroup", - "dd", - "details", - "dialog", - "dir", - "div", - "dl", - "dt", - "fieldset", - "figcaption", - "figure", - "footer", - "form", - "frame", - "frameset", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "head", - "header", - "hr", - "html", - "iframe", - "legend", - "li", - "link", - "main", - "menu", - "menuitem", - "nav", - "noframes", - "ol", - "optgroup", - "option", - "p", - "param", - "section", - "source", - "summary", - "table", - "tbody", - "td", - "tfoot", - "th", - "thead", - "title", - "tr", - "track", - "ul", -]; - -/// Analysis of the beginning of a line, including indentation and container -/// markers. -#[derive(Clone)] -pub struct LineStart<'a> { - bytes: &'a [u8], - tab_start: usize, - ix: usize, - spaces_remaining: usize, - // no thematic breaks can occur before this offset. - // this prevents scanning over and over up to a certain point - min_hrule_offset: usize, -} - -impl<'a> LineStart<'a> { - pub(crate) fn new(bytes: &[u8]) -> LineStart { - LineStart { - bytes, - tab_start: 0, - ix: 0, - spaces_remaining: 0, - min_hrule_offset: 0, - } - } - - /// Try to scan a number of spaces. - /// - /// Returns true if all spaces were consumed. - /// - /// Note: consumes some spaces even if not successful. - pub(crate) fn scan_space(&mut self, n_space: usize) -> bool { - self.scan_space_inner(n_space) == 0 - } - - /// Scan a number of spaces up to a maximum. - /// - /// Returns number of spaces scanned. - pub(crate) fn scan_space_upto(&mut self, n_space: usize) -> usize { - n_space - self.scan_space_inner(n_space) - } - - /// Returns unused remainder of spaces. - fn scan_space_inner(&mut self, mut n_space: usize) -> usize { - let n_from_remaining = self.spaces_remaining.min(n_space); - self.spaces_remaining -= n_from_remaining; - n_space -= n_from_remaining; - while n_space > 0 && self.ix < self.bytes.len() { - match self.bytes[self.ix] { - b' ' => { - self.ix += 1; - n_space -= 1; - } - b'\t' => { - let spaces = 4 - (self.ix - self.tab_start) % 4; - self.ix += 1; - self.tab_start = self.ix; - let n = spaces.min(n_space); - n_space -= n; - self.spaces_remaining = spaces - n; - } - _ => break, - } - } - n_space - } - - /// Scan all available ASCII whitespace (not including eol). - pub(crate) fn scan_all_space(&mut self) { - self.spaces_remaining = 0; - self.ix += self.bytes[self.ix..] - .iter() - .take_while(|&&b| b == b' ' || b == b'\t') - .count(); - } - - /// Determine whether we're at end of line (includes end of file). - pub(crate) fn is_at_eol(&self) -> bool { - self.bytes - .get(self.ix) - .map(|&c| c == b'\r' || c == b'\n') - .unwrap_or(true) - } - - fn scan_ch(&mut self, c: u8) -> bool { - if self.ix < self.bytes.len() && self.bytes[self.ix] == c { - self.ix += 1; - true - } else { - false - } - } - - pub(crate) fn scan_blockquote_marker(&mut self) -> bool { - let save = self.clone(); - let _ = self.scan_space(3); - if self.scan_ch(b'>') { - let _ = self.scan_space(1); - true - } else { - *self = save; - false - } - } - - /// Scan a list marker. - /// - /// Return value is the character, the start index, and the indent in spaces. - /// For ordered list markers, the character will be one of b'.' or b')'. For - /// bullet list markers, it will be one of b'-', b'+', or b'*'. - pub(crate) fn scan_list_marker(&mut self) -> Option<(u8, u64, usize)> { - let save = self.clone(); - let indent = self.scan_space_upto(3); - if self.ix < self.bytes.len() { - let c = self.bytes[self.ix]; - if c == b'-' || c == b'+' || c == b'*' { - if self.ix >= self.min_hrule_offset { - // there could be an hrule here - if let Err(min_offset) = scan_hrule(&self.bytes[self.ix..]) { - self.min_hrule_offset = min_offset; - } else { - *self = save; - return None; - } - } - self.ix += 1; - if self.scan_space(1) || self.is_at_eol() { - return self.finish_list_marker(c, 0, indent + 2); - } - } else if c >= b'0' && c <= b'9' { - let start_ix = self.ix; - let mut ix = self.ix + 1; - let mut val = u64::from(c - b'0'); - while ix < self.bytes.len() && ix - start_ix < 10 { - let c = self.bytes[ix]; - ix += 1; - if c >= b'0' && c <= b'9' { - val = val * 10 + u64::from(c - b'0'); - } else if c == b')' || c == b'.' { - self.ix = ix; - if self.scan_space(1) || self.is_at_eol() { - return self.finish_list_marker(c, val, indent + self.ix - start_ix); - } else { - break; - } - } else { - break; - } - } - } - } - *self = save; - None - } - - fn finish_list_marker( - &mut self, - c: u8, - start: u64, - mut indent: usize, - ) -> Option<(u8, u64, usize)> { - let save = self.clone(); - - // skip the rest of the line if it's blank - if scan_blank_line(&self.bytes[self.ix..]).is_some() { - return Some((c, start, indent)); - } - - let post_indent = self.scan_space_upto(4); - if post_indent < 4 { - indent += post_indent; - } else { - *self = save; - } - Some((c, start, indent)) - } - - /// Returns Some(is_checked) when a task list marker was found. Resets itself - /// to original state otherwise. - pub(crate) fn scan_task_list_marker(&mut self) -> Option { - let save = self.clone(); - self.scan_space_upto(3); - - if !self.scan_ch(b'[') { - *self = save; - return None; - } - let is_checked = match self.bytes.get(self.ix) { - Some(&c) if is_ascii_whitespace_no_nl(c) => { - self.ix += 1; - false - } - Some(b'x') | Some(b'X') => { - self.ix += 1; - true - } - _ => { - *self = save; - return None; - } - }; - if !self.scan_ch(b']') { - *self = save; - return None; - } - if !self - .bytes - .get(self.ix) - .map(|&b| is_ascii_whitespace_no_nl(b)) - .unwrap_or(false) - { - *self = save; - return None; - } - Some(is_checked) - } - - pub(crate) fn bytes_scanned(&self) -> usize { - self.ix - } - - pub(crate) fn remaining_space(&self) -> usize { - self.spaces_remaining - } -} - -pub(crate) fn is_ascii_whitespace(c: u8) -> bool { - (c >= 0x09 && c <= 0x0d) || c == b' ' -} - -pub(crate) fn is_ascii_whitespace_no_nl(c: u8) -> bool { - c == b'\t' || c == 0x0b || c == 0x0c || c == b' ' -} - -fn is_ascii_alpha(c: u8) -> bool { - match c { - b'a'..=b'z' | b'A'..=b'Z' => true, - _ => false, - } -} - -fn is_ascii_alphanumeric(c: u8) -> bool { - match c { - b'0'..=b'9' | b'a'..=b'z' | b'A'..=b'Z' => true, - _ => false, - } -} - -fn is_ascii_letterdigitdash(c: u8) -> bool { - c == b'-' || is_ascii_alphanumeric(c) -} - -fn is_digit(c: u8) -> bool { - b'0' <= c && c <= b'9' -} - -fn is_valid_unquoted_attr_value_char(c: u8) -> bool { - match c { - b'\'' | b'"' | b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => false, - _ => true, - } -} - -// scan a single character -pub(crate) fn scan_ch(data: &[u8], c: u8) -> usize { - if !data.is_empty() && data[0] == c { - 1 - } else { - 0 - } -} - -pub(crate) fn scan_while(data: &[u8], mut f: F) -> usize -where - F: FnMut(u8) -> bool, -{ - data.iter().take_while(|&&c| f(c)).count() -} - -pub(crate) fn scan_rev_while(data: &[u8], mut f: F) -> usize -where - F: FnMut(u8) -> bool, -{ - data.iter().rev().take_while(|&&c| f(c)).count() -} - -pub(crate) fn scan_ch_repeat(data: &[u8], c: u8) -> usize { - scan_while(data, |x| x == c) -} - -// Note: this scans ASCII whitespace only, for Unicode whitespace use -// a different function. -pub(crate) fn scan_whitespace_no_nl(data: &[u8]) -> usize { - scan_while(data, is_ascii_whitespace_no_nl) -} - -fn scan_attr_value_chars(data: &[u8]) -> usize { - scan_while(data, is_valid_unquoted_attr_value_char) -} - -pub(crate) fn scan_eol(bytes: &[u8]) -> Option { - if bytes.is_empty() { - return Some(0); - } - match bytes[0] { - b'\n' => Some(1), - b'\r' => Some(if bytes.get(1) == Some(&b'\n') { 2 } else { 1 }), - _ => None, - } -} - -pub(crate) fn scan_blank_line(bytes: &[u8]) -> Option { - let i = scan_whitespace_no_nl(bytes); - scan_eol(&bytes[i..]).map(|n| i + n) -} - -pub(crate) fn scan_nextline(bytes: &[u8]) -> usize { - memchr(b'\n', bytes).map_or(bytes.len(), |x| x + 1) -} - -// return: end byte for closing code fence, or None -// if the line is not a closing code fence -pub(crate) fn scan_closing_code_fence( - bytes: &[u8], - fence_char: u8, - n_fence_char: usize, -) -> Option { - if bytes.is_empty() { - return Some(0); - } - let mut i = 0; - let num_fence_chars_found = scan_ch_repeat(&bytes[i..], fence_char); - if num_fence_chars_found < n_fence_char { - return None; - } - i += num_fence_chars_found; - let num_trailing_spaces = scan_ch_repeat(&bytes[i..], b' '); - i += num_trailing_spaces; - scan_eol(&bytes[i..]).map(|_| i) -} - -// returned pair is (number of bytes, number of spaces) -fn calc_indent(text: &[u8], max: usize) -> (usize, usize) { - let mut spaces = 0; - let mut offset = 0; - - for (i, &b) in text.iter().enumerate() { - match b { - b' ' => { - spaces += 1; - if spaces == max { - break; - } - } - b'\t' => { - let new_spaces = spaces + 4 - (spaces & 3); - if new_spaces > max { - break; - } - spaces = new_spaces; - } - _ => break, - } - offset = i; - } - - (offset, spaces) -} - -/// Scan hrule opening sequence. -/// -/// Returns Ok(x) when it finds an hrule, where x is the -/// size of line containing the hrule, including the trailing newline. -/// -/// Returns Err(x) when it does not find an hrule and x is -/// the offset in data before no hrule can appear. -pub(crate) fn scan_hrule(bytes: &[u8]) -> Result { - if bytes.len() < 3 { - return Err(0); - } - let c = bytes[0]; - if !(c == b'*' || c == b'-' || c == b'_') { - return Err(0); - } - let mut n = 0; - let mut i = 0; - - while i < bytes.len() { - match bytes[i] { - b'\n' | b'\r' => { - i += scan_eol(&bytes[i..]).unwrap_or(0); - break; - } - c2 if c2 == c => { - n += 1; - } - b' ' | b'\t' => (), - _ => return Err(i), - } - i += 1; - } - if n >= 3 { - Ok(i) - } else { - Err(i) - } -} - -/// Scan an ATX heading opening sequence. -/// -/// Returns number of bytes in prefix and level. -pub(crate) fn scan_atx_heading(data: &[u8]) -> Option { - let level = scan_ch_repeat(data, b'#'); - if level >= 1 && level <= 6 && data.get(level).cloned().map_or(true, is_ascii_whitespace) { - Some(level) - } else { - None - } -} - -/// Scan a setext heading underline. -/// -/// Returns number of bytes in line (including trailing newline) and level. -pub(crate) fn scan_setext_heading(data: &[u8]) -> Option<(usize, u32)> { - let c = *data.get(0)?; - if !(c == b'-' || c == b'=') { - return None; - } - let mut i = 1 + scan_ch_repeat(&data[1..], c); - i += scan_blank_line(&data[i..])?; - let level = if c == b'=' { 1 } else { 2 }; - Some((i, level)) -} - -// returns number of bytes in line (including trailing -// newline) and column alignments -pub(crate) fn scan_table_head(data: &[u8]) -> (usize, Vec) { - let (mut i, spaces) = calc_indent(data, 4); - if spaces > 3 || i == data.len() { - return (0, vec![]); - } - let mut cols = vec![]; - let mut active_col = Alignment::None; - let mut start_col = true; - if data[i] == b'|' { - i += 1; - } - for c in &data[i..] { - if let Some(n) = scan_eol(&data[i..]) { - i += n; - break; - } - match *c { - b' ' => (), - b':' => { - active_col = match (start_col, active_col) { - (true, Alignment::None) => Alignment::Left, - (false, Alignment::Left) => Alignment::Center, - (false, Alignment::None) => Alignment::Right, - _ => active_col, - }; - start_col = false; - } - b'-' => { - start_col = false; - } - b'|' => { - start_col = true; - cols.push(active_col); - active_col = Alignment::None; - } - _ => { - cols = vec![]; - start_col = true; - break; - } - } - i += 1; - } - - if !start_col { - cols.push(active_col); - } - - (i, cols) -} - -/// Scan code fence. -/// -/// Returns number of bytes scanned and the char that is repeated to make the code fence. -pub(crate) fn scan_code_fence(data: &[u8]) -> Option<(usize, u8)> { - let c = *data.get(0)?; - if !(c == b'`' || c == b'~') { - return None; - } - let i = 1 + scan_ch_repeat(&data[1..], c); - if i >= 3 { - if c == b'`' { - let suffix = &data[i..]; - let next_line = i + scan_nextline(suffix); - // FIXME: make sure this is correct - if suffix[..(next_line - i)].iter().any(|&b| b == b'`') { - return None; - } - } - Some((i, c)) - } else { - None - } -} - -pub(crate) fn scan_blockquote_start(data: &[u8]) -> Option { - if data.starts_with(b"> ") { - Some(2) - } else { - None - } -} - -/// This already assumes the list item has been scanned. -pub(crate) fn scan_empty_list(data: &[u8]) -> bool { - let mut ix = 0; - for _ in 0..2 { - if let Some(bytes) = scan_blank_line(&data[ix..]) { - ix += bytes; - } else { - return false; - } - } - true -} - -// return number of bytes scanned, delimiter, start index, and indent -pub(crate) fn scan_listitem(bytes: &[u8]) -> Option<(usize, u8, usize, usize)> { - let mut c = *bytes.get(0)?; - let (w, start) = match c { - b'-' | b'+' | b'*' => (1, 0), - b'0'..=b'9' => { - let (length, start) = parse_decimal(bytes); - c = *bytes.get(length)?; - if !(c == b'.' || c == b')') { - return None; - } - (length + 1, start) - } - _ => { - return None; - } - }; - // TODO: replace calc_indent with scan_leading_whitespace, for tab correctness - let (mut postn, mut postindent) = calc_indent(&bytes[w..], 5); - if postindent == 0 { - scan_eol(&bytes[w..])?; - postindent += 1; - } else if postindent > 4 { - postn = 1; - postindent = 1; - } - if scan_blank_line(&bytes[w..]).is_some() { - postn = 0; - postindent = 1; - } - Some((w + postn, c, start, w + postindent)) -} - -// returns (number of bytes, parsed decimal) -fn parse_decimal(bytes: &[u8]) -> (usize, usize) { - match bytes - .iter() - .take_while(|&&b| is_digit(b)) - .try_fold((0, 0usize), |(count, acc), c| { - let digit = usize::from(c - b'0'); - match acc - .checked_mul(10) - .and_then(|ten_acc| ten_acc.checked_add(digit)) - { - Some(number) => Ok((count + 1, number)), - // stop early on overflow - None => Err((count, acc)), - } - }) { - Ok(p) | Err(p) => p, - } -} - -// returns (number of bytes, parsed hex) -fn parse_hex(bytes: &[u8]) -> (usize, usize) { - match bytes.iter().try_fold((0, 0usize), |(count, acc), c| { - let mut c = *c; - let digit = if c >= b'0' && c <= b'9' { - usize::from(c - b'0') - } else { - // make lower case - c |= 0x20; - if c >= b'a' && c <= b'f' { - usize::from(c - b'a' + 10) - } else { - return Err((count, acc)); - } - }; - match acc - .checked_mul(16) - .and_then(|sixteen_acc| sixteen_acc.checked_add(digit)) - { - Some(number) => Ok((count + 1, number)), - // stop early on overflow - None => Err((count, acc)), - } - }) { - Ok(p) | Err(p) => p, - } -} - -fn char_from_codepoint(input: usize) -> Option { - let mut codepoint = input.try_into().ok()?; - if codepoint == 0 { - codepoint = 0xFFFD; - } - char::from_u32(codepoint) -} - -// doesn't bother to check data[0] == '&' -pub(crate) fn scan_entity(bytes: &[u8]) -> (usize, Option>) { - let mut end = 1; - if scan_ch(&bytes[end..], b'#') == 1 { - end += 1; - let (bytecount, codepoint) = if end < bytes.len() && bytes[end] | 0x20 == b'x' { - end += 1; - parse_hex(&bytes[end..]) - } else { - parse_decimal(&bytes[end..]) - }; - end += bytecount; - return if bytecount == 0 || scan_ch(&bytes[end..], b';') == 0 { - (0, None) - } else if let Some(c) = char_from_codepoint(codepoint) { - (end + 1, Some(c.into())) - } else { - (0, None) - }; - } - end += scan_while(&bytes[end..], is_ascii_alphanumeric); - if scan_ch(&bytes[end..], b';') == 1 { - if let Some(value) = entities::get_entity(&bytes[1..end]) { - return (end + 1, Some(value.into())); - } - } - (0, None) -} - -// FIXME: we can most likely re-use other scanners -// returns (bytelength, title_str) -pub(crate) fn scan_refdef_title(text: &str) -> Option<(usize, &str)> { - let mut chars = text.chars().peekable(); - let closing_delim = match chars.next()? { - '\'' => '\'', - '"' => '"', - '(' => ')', - _ => return None, - }; - let mut bytecount = 1; - - while let Some(c) = chars.next() { - match c { - '\n' => { - bytecount += 1; - let mut next = *chars.peek()?; - while is_ascii_whitespace_no_nl(next as u8) { - bytecount += chars.next()?.len_utf8(); - next = *chars.peek()?; - } - if *chars.peek()? == '\n' { - // blank line - not allowed - return None; - } - } - '\\' => { - let next_char = chars.next()?; - bytecount += 1 + next_char.len_utf8(); - } - c if c == closing_delim => { - return Some((bytecount + 1, &text[1..bytecount])); - } - c => { - bytecount += c.len_utf8(); - } - } - } - None -} - -// note: dest returned is raw, still needs to be unescaped -// TODO: check that nested parens are really not allowed for refdefs -// TODO(performance): this func should probably its own unescaping -pub(crate) fn scan_link_dest( - data: &str, - start_ix: usize, - max_next: usize, -) -> Option<(usize, &str)> { - let bytes = &data.as_bytes()[start_ix..]; - let mut i = scan_ch(bytes, b'<'); - - if i != 0 { - // pointy links - while i < bytes.len() { - match bytes[i] { - b'\n' | b'\r' | b'<' => return None, - b'>' => return Some((i + 1, &data[(start_ix + 1)..(start_ix + i)])), - b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { - i += 1; - } - _ => {} - } - i += 1; - } - None - } else { - // non-pointy links - let mut nest = 0; - while i < bytes.len() { - match bytes[i] { - 0x0..=0x20 => { - break; - } - b'(' => { - if nest > max_next { - return None; - } - nest += 1; - } - b')' => { - if nest == 0 { - break; - } - nest -= 1; - } - b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { - i += 1; - } - _ => {} - } - i += 1; - } - Some((i, &data[start_ix..(start_ix + i)])) - } -} - -/// Returns bytes scanned -fn scan_attribute_name(data: &[u8]) -> Option { - let (&c, tail) = data.split_first()?; - if is_ascii_alpha(c) || c == b'_' || c == b':' { - Some( - 1 + scan_while(tail, |c| { - is_ascii_alphanumeric(c) || c == b'_' || c == b'.' || c == b':' || c == b'-' - }), - ) - } else { - None - } -} - -/// Returns byte scanned (TODO: should it return new offset?) -// TODO: properly use the newline handler here -fn scan_attribute(data: &[u8], newline_handler: Option<&dyn Fn(&[u8]) -> usize>) -> Option { - let allow_newline = newline_handler.is_some(); - let whitespace_scanner = - |c| is_ascii_whitespace(c) && (allow_newline || c != b'\n' && c != b'\r'); - let mut ix = scan_attribute_name(data)?; - let n_whitespace = scan_while(&data[ix..], whitespace_scanner); - ix += n_whitespace; - if scan_ch(&data[ix..], b'=') == 1 { - ix += 1; - ix += scan_while(&data[ix..], whitespace_scanner); - ix += scan_attribute_value(&data[ix..], newline_handler)?; - } else if n_whitespace > 0 { - // Leave whitespace for next attribute. - ix -= 1; - } - Some(ix) -} - -fn scan_attribute_value( - data: &[u8], - newline_handler: Option<&dyn Fn(&[u8]) -> usize>, -) -> Option { - let mut i = 0; - match *data.get(0)? { - b @ b'"' | b @ b'\'' => { - i += 1; - while i < data.len() { - if data[i] == b { - return Some(i + 1); - } - if let Some(eol_bytes) = scan_eol(&data[i..]) { - let handler = newline_handler?; - i += eol_bytes; - i += handler(&data[i..]); - } else { - i += 1; - } - } - return None; - } - b' ' | b'=' | b'>' | b'<' | b'`' | b'\n' | b'\r' => { - return None; - } - _ => { - // unquoted attribute value - i += scan_attr_value_chars(&data[i..]); - } - } - Some(i) -} - -// Remove backslash escapes and resolve entities -pub(crate) fn unescape(input: &str) -> CowStr<'_> { - let mut result = String::new(); - let mut mark = 0; - let mut i = 0; - let bytes = input.as_bytes(); - while i < bytes.len() { - match bytes[i] { - b'\\' if i + 1 < bytes.len() && is_ascii_punctuation(bytes[i + 1]) => { - result.push_str(&input[mark..i]); - mark = i + 1; - i += 2; - } - b'&' => match scan_entity(&bytes[i..]) { - (n, Some(value)) => { - result.push_str(&input[mark..i]); - result.push_str(&value); - i += n; - mark = i; - } - _ => i += 1, - }, - b'\r' => { - result.push_str(&input[mark..i]); - i += 1; - mark = i; - } - _ => i += 1, - } - } - if mark == 0 { - input.into() - } else { - result.push_str(&input[mark..]); - result.into() - } -} - -/// Assumes `data` is preceded by `<`. -pub(crate) fn scan_html_block_tag(data: &[u8]) -> (usize, &[u8]) { - let i = scan_ch(data, b'/'); - let n = scan_while(&data[i..], is_ascii_alphanumeric); - // TODO: scan attributes and > - (i + n, &data[i..i + n]) -} - -pub(crate) fn is_html_tag(tag: &[u8]) -> bool { - HTML_TAGS - .binary_search_by(|probe| { - let probe_bytes_iter = probe.as_bytes().iter(); - let tag_bytes_iter = tag.iter(); - - probe_bytes_iter - .zip(tag_bytes_iter) - .find_map(|(&a, &b)| { - // We can compare case insensitively because the probes are - // all lower case alpha strings. - match a.cmp(&(b | 0x20)) { - std::cmp::Ordering::Equal => None, - inequality => Some(inequality), - } - }) - .unwrap_or_else(|| probe.len().cmp(&tag.len())) - }) - .is_ok() -} - -/// Assumes that `data` is preceded by `<`. -pub(crate) fn scan_html_type_7(data: &[u8]) -> Option { - // Block type html does not allow for newlines, so we - // do not pass a newline handler. - let i = scan_html_block_inner(data, None)?; - scan_blank_line(&data[i..])?; - Some(i) -} - -// FIXME: instead of a newline handler, maybe this should receive -// a whitespace handler instead. -// With signature `&dyn Fn(&[u8]) -> Option`. -// We currently need to implement whitespace handling in all of -// this function's dependencies as well. -pub(crate) fn scan_html_block_inner( - data: &[u8], - newline_handler: Option<&dyn Fn(&[u8]) -> usize>, -) -> Option { - let close_tag_bytes = scan_ch(data, b'/'); - let l = scan_while(&data[close_tag_bytes..], is_ascii_alpha); - if l == 0 { - return None; - } - let mut i = close_tag_bytes + l; - i += scan_while(&data[i..], is_ascii_letterdigitdash); - - if close_tag_bytes == 0 { - loop { - let old_i = i; - loop { - i += scan_whitespace_no_nl(&data[i..]); - if let Some(eol_bytes) = scan_eol(&data[i..]) { - if eol_bytes == 0 { - return None; - } - if let Some(handler) = newline_handler { - i += eol_bytes; - i += handler(&data[i..]); - } else { - return None; - } - } else { - break; - } - } - if let Some(b'/') | Some(b'>') = data.get(i) { - break; - } - if old_i == i { - // No whitespace, which is mandatory. - return None; - } - i += scan_attribute(&data[i..], newline_handler)?; - } - } - - i += scan_whitespace_no_nl(&data[i..]); - - if close_tag_bytes == 0 { - i += scan_ch(&data[i..], b'/'); - } - - if scan_ch(&data[i..], b'>') == 0 { - None - } else { - Some(i + 1) - } -} - -/// Returns (next_byte_offset, uri, type) -pub(crate) fn scan_autolink(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>, LinkType)> { - scan_uri(text, start_ix) - .map(|(bytes, uri)| (bytes, uri, LinkType::Autolink)) - .or_else(|| scan_email(text, start_ix).map(|(bytes, uri)| (bytes, uri, LinkType::Email))) -} - -/// Returns (next_byte_offset, uri) -fn scan_uri(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { - let bytes = &text.as_bytes()[start_ix..]; - - // scheme's first byte must be an ascii letter - if bytes.is_empty() || !is_ascii_alpha(bytes[0]) { - return None; - } - - let mut i = 1; - - while i < bytes.len() { - let c = bytes[i]; - i += 1; - match c { - c if is_ascii_alphanumeric(c) => (), - b'.' | b'-' | b'+' => (), - b':' => break, - _ => return None, - } - } - - // scheme length must be between 2 and 32 characters long. scheme - // must be followed by colon - if i < 3 || i > 33 { - return None; - } - - while i < bytes.len() { - match bytes[i] { - b'>' => return Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())), - b'\0'..=b' ' | b'<' => return None, - _ => (), - } - i += 1; - } - - None -} - -/// Returns (next_byte_offset, email) -fn scan_email(text: &str, start_ix: usize) -> Option<(usize, CowStr<'_>)> { - // using a regex library would be convenient, but doing it by hand is not too bad - let bytes = &text.as_bytes()[start_ix..]; - let mut i = 0; - - while i < bytes.len() { - let c = bytes[i]; - i += 1; - match c { - c if is_ascii_alphanumeric(c) => (), - b'.' | b'!' | b'#' | b'$' | b'%' | b'&' | b'\'' | b'*' | b'+' | b'/' | b'=' | b'?' - | b'^' | b'_' | b'`' | b'{' | b'|' | b'}' | b'~' | b'-' => (), - b'@' => break, - _ => return None, - } - } - - loop { - let label_start_ix = i; - let mut fresh_label = true; - - while i < bytes.len() { - match bytes[i] { - c if is_ascii_alphanumeric(c) => (), - b'-' if fresh_label => { - return None; - } - b'-' => (), - _ => break, - } - fresh_label = false; - i += 1; - } - - if i == label_start_ix || i - label_start_ix > 63 || bytes[i - 1] == b'-' { - return None; - } - - if scan_ch(&bytes[i..], b'.') == 0 { - break; - } - i += 1; - } - - if scan_ch(&bytes[i..], b'>') == 0 { - return None; - } - - Some((start_ix + i + 1, text[start_ix..(start_ix + i)].into())) -} - -/// Scan comment, declaration, or CDATA section, with initial " Option { - let c = *bytes.get(ix)?; - ix += 1; - match c { - b'-' => { - let dashes = scan_ch_repeat(&bytes[ix..], b'-'); - if dashes < 1 { - return None; - } - // Saw ""##; - let expected = r##"

    Little header

    -"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_5() { - let original = r##"Little header - - -

    Useless

    -]]>"##; - let expected = r##"

    Little header

    - -

    Useless

    -]]>"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_6() { - let original = r##"Little header - -"##; - let expected = r##"

    Little header

    -"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_7() { - let original = r##"Little header ------------ - -"##; - let expected = r##"

    Little header

    -"##; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_8() { - let original = "A | B\n---|---\nfoo | bar"; - let expected = r##" - -
    AB
    foobar
    -"##; - - let mut s = String::new(); - let mut opts = Options::empty(); - opts.insert(Options::ENABLE_TABLES); - html::push_html(&mut s, Parser::new_ext(&original, opts)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_9() { - let original = "---"; - let expected = "
    \n"; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -#[test] -fn html_test_10() { - let original = "* * *"; - let expected = "
    \n"; - - let mut s = String::new(); - html::push_html(&mut s, Parser::new(&original)); - assert_eq!(expected, s); -} - -// TODO: add broken link callback feature -/* -#[test] -fn html_test_broken_callback() { - let original = r##"[foo], -[bar], -[baz], - - [baz]: https://example.org -"##; - - let expected = r##"

    foo, -[bar], -baz,

    -"##; - - use pulldown_cmark::{Options, Parser, html}; - - let mut s = String::new(); - - let callback = |reference: &str, _normalized: &str| -> Option<(String, String)> { - if reference == "foo" || reference == "baz" { - Some(("https://replaced.example.org".into(), "some title".into())) - } else { - None - } - }; - - let p = Parser::new_with_broken_link_callback(&original, Options::empty(), Some(&callback)); - html::push_html(&mut s, p); - - assert_eq!(expected, s); -} -*/ +// Tests for HTML spec. + +extern crate pulldown_cmark; + +use pulldown_cmark::{html, BrokenLink, Options, Parser}; + +#[test] +fn html_test_1() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_2() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_3() { + let original = r##"Little header + + +

    Useless

    +?>"##; + let expected = r##"

    Little header

    + +

    Useless

    +?>"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_4() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_5() { + let original = r##"Little header + + +

    Useless

    +]]>"##; + let expected = r##"

    Little header

    + +

    Useless

    +]]>"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_6() { + let original = r##"Little header + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_7() { + let original = r##"Little header +----------- + +"##; + let expected = r##"

    Little header

    +"##; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_8() { + let original = "A | B\n---|---\nfoo | bar"; + let expected = r##" + +
    AB
    foobar
    +"##; + + let mut s = String::new(); + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + html::push_html(&mut s, Parser::new_ext(&original, opts)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_9() { + let original = "---"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_10() { + let original = "* * *"; + let expected = "
    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_11() { + let original = "hi ~~no~~"; + let expected = "

    hi ~~no~~

    \n"; + + let mut s = String::new(); + html::push_html(&mut s, Parser::new(&original)); + assert_eq!(expected, s); +} + +#[test] +fn html_test_broken_callback() { + let original = r##"[foo], +[bar], +[baz], + + [baz]: https://example.org +"##; + + let expected = r##"

    foo, +[bar], +baz,

    +"##; + + use pulldown_cmark::{html, Options, Parser}; + + let mut s = String::new(); + + let mut callback = |broken_link: BrokenLink| { + if broken_link.reference == "foo" || broken_link.reference == "baz" { + Some(("https://replaced.example.org".into(), "some title".into())) + } else { + None + } + }; + + let p = Parser::new_with_broken_link_callback(&original, Options::empty(), Some(&mut callback)); + html::push_html(&mut s, p); + + assert_eq!(expected, s); +} diff --git a/vendor/pulldown-cmark/tests/lib.rs b/vendor/pulldown-cmark/tests/lib.rs index 11be5bcd09..6457625d07 100644 --- a/vendor/pulldown-cmark/tests/lib.rs +++ b/vendor/pulldown-cmark/tests/lib.rs @@ -1,422 +1,425 @@ -#[macro_use] -extern crate html5ever; -#[macro_use] -extern crate lazy_static; - -use html5ever::serialize::{serialize, SerializeOpts}; -use html5ever::{driver as html, QualName}; -use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle}; -use pulldown_cmark::{Options, Parser}; - -use regex::Regex; -use std::collections::HashSet; -use std::mem; -use std::rc::{Rc, Weak}; -use tendril::stream::TendrilSink; - -mod suite; - -#[inline(never)] -pub fn test_markdown_html(input: &str, output: &str) { - let mut s = String::new(); - - let mut opts = Options::empty(); - opts.insert(Options::ENABLE_TABLES); - opts.insert(Options::ENABLE_FOOTNOTES); - opts.insert(Options::ENABLE_STRIKETHROUGH); - opts.insert(Options::ENABLE_TASKLISTS); - - let p = Parser::new_ext(input, opts); - pulldown_cmark::html::push_html(&mut s, p); - - assert_eq!(normalize_html(output), normalize_html(&s)); -} - -lazy_static! { - static ref WHITESPACE_RE: Regex = Regex::new(r"\s+").unwrap(); - static ref LEADING_WHITESPACE_RE: Regex = Regex::new(r"\A\s+").unwrap(); - static ref TRAILING_WHITESPACE_RE: Regex = Regex::new(r"\s+\z").unwrap(); - static ref BLOCK_TAGS: HashSet<&'static str> = [ - "article", - "header", - "aside", - "hgroup", - "blockquote", - "hr", - "iframe", - "body", - "li", - "map", - "button", - "object", - "canvas", - "ol", - "caption", - "output", - "col", - "p", - "colgroup", - "pre", - "dd", - "progress", - "div", - "section", - "dl", - "table", - "td", - "dt", - "tbody", - "embed", - "textarea", - "fieldset", - "tfoot", - "figcaption", - "th", - "figure", - "thead", - "footer", - "tr", - "form", - "ul", - "h1", - "h2", - "h3", - "h4", - "h5", - "h6", - "video", - "script", - "style" - ] - .iter() - .cloned() - .collect(); - static ref WHITESPACE_SENSITIVE_TAGS: HashSet<&'static str> = - ["pre", "code", "h1", "h2", "h3", "h4", "h5", "h6"] - .iter() - .cloned() - .collect(); - static ref TABLE_TAGS: HashSet<&'static str> = ["table", "thead", "tbody", "tr", "td"] - .iter() - .cloned() - .collect(); -} - -fn make_html_parser() -> html::Parser { - html::parse_fragment( - RcDom::default(), - html::ParseOpts::default(), - QualName::new(None, ns!(html), local_name!("div")), - vec![], - ) -} - -fn normalize_html(s: &str) -> String { - let parser = make_html_parser(); - let dom = parser.one(s); - let body: SerializableHandle = normalize_dom(&dom).into(); - let opts = SerializeOpts::default(); - let mut ret_val = Vec::new(); - serialize(&mut ret_val, &body, opts) - .expect("Writing to a string shouldn't fail (expect on OOM)"); - String::from_utf8(ret_val).expect("html5ever should always produce UTF8") -} - -fn normalize_dom(dom: &RcDom) -> Handle { - let body = { - let children = dom.document.children.borrow(); - children[0].clone() - }; - let mut current_level = Vec::new(); - let mut next_level = Vec::new(); - current_level.extend(body.children.borrow().iter().cloned().rev()); - loop { - while let Some(mut node) = current_level.pop() { - let parent = node.parent.replace(None); - node.parent.replace(parent.clone()); - let parent = parent - .expect("a node in the DOM will have a parent, except the root, which is not processed") - .upgrade().expect("a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped"); - let retain = normalize_node(&parent, &mut node); - if !retain { - let mut siblings = parent.children.borrow_mut(); - siblings.retain(|s| !Rc::ptr_eq(&node, s)); - } else { - next_level.extend(node.children.borrow().iter().cloned().rev()); - } - } - if next_level.is_empty() { - break; - }; - mem::swap(&mut next_level, &mut current_level); - } - body -} - -// Returns false if node is an empty text node or an empty tbody. -// Returns true otherwise. -fn normalize_node(parent: &Handle, node: &mut Handle) -> bool { - match node.data { - NodeData::Comment { .. } - | NodeData::Doctype { .. } - | NodeData::Document - | NodeData::ProcessingInstruction { .. } => true, - NodeData::Text { ref contents, .. } => { - let mut contents = contents.borrow_mut(); - let is_pre = { - let mut parent = parent.clone(); - loop { - let is_pre = if let NodeData::Element { ref name, .. } = parent.data { - WHITESPACE_SENSITIVE_TAGS.contains(&&*name.local.to_ascii_lowercase()) - } else { - false - }; - if is_pre { - break true; - }; - let parent_ = parent.parent.replace(None); - parent.parent.replace(parent_.clone()); - let parent_ = parent_.as_ref().and_then(Weak::upgrade); - if let Some(parent_) = parent_ { - parent = parent_ - } else { - break false; - }; - } - }; - if !is_pre { - let (is_first_in_block, is_last_in_block) = { - let mut is_first_in_block = true; - let mut is_last_in_block = true; - let mut parent = parent.clone(); - let mut node = node.clone(); - loop { - let reached_block = if let NodeData::Element { ref name, .. } = parent.data - { - BLOCK_TAGS.contains(&&*name.local.to_ascii_lowercase()) - } else { - false - }; - let (is_first, is_last) = { - let siblings = parent.children.borrow(); - let n = &node; - ( - siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false), - siblings.len() > 0 - && siblings - .get(siblings.len() - 1) - .map(|s| Rc::ptr_eq(s, n)) - .unwrap_or(false), - ) - }; - is_first_in_block = is_first_in_block && is_first; - is_last_in_block = is_last_in_block && is_last; - if (is_first_in_block || is_last_in_block) && !reached_block { - node = parent.clone(); - let parent_ = parent.parent.replace(None); - parent.parent.replace(parent_.clone()); - let parent_ = parent_.as_ref().and_then(Weak::upgrade); - if let Some(parent_) = parent_ { - parent = parent_; - } else { - break (is_first_in_block, is_last_in_block); - } - } else { - break (is_first_in_block, is_last_in_block); - } - } - }; - let is_preceeded_by_ws = { - let mut parent = parent.clone(); - let mut node = node.clone(); - 'ascent: loop { - let is_first = { - let siblings = parent.children.borrow(); - let n = &node; - siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false) - }; - if is_first { - node = parent.clone(); - let parent_ = parent.parent.replace(None); - parent.parent.replace(parent_.clone()); - let parent_ = parent_.as_ref().and_then(Weak::upgrade); - if let Some(parent_) = parent_ { - parent = parent_; - } else { - break 'ascent false; - } - } else { - let siblings = parent.children.borrow(); - let n = &node; - let mut pos = !0; - 'search: for (i, s) in siblings.iter().enumerate() { - if Rc::ptr_eq(s, n) { - pos = i; - break 'search; - } - } - assert!( - pos != !0, - "The list of node's parent's children shall contain node" - ); - assert!( - pos != 0, - "If node is not first, then node's position shall not be zero" - ); - let mut preceeding = siblings[pos - 1].clone(); - 'descent: loop { - if let NodeData::Text { .. } = preceeding.data { - break 'descent; - } - preceeding = { - let ch = preceeding.children.borrow(); - if ch.len() == 0 { - break 'descent; - } - if let Some(preceeding_) = ch.get(ch.len() - 1) { - preceeding_.clone() - } else { - break 'descent; - } - }; - } - if let NodeData::Text { ref contents, .. } = preceeding.data { - break 'ascent TRAILING_WHITESPACE_RE.is_match(&*contents.borrow()); - } else { - break 'ascent false; - } - } - } - }; - - let is_in_table = if let NodeData::Element { ref name, .. } = parent.data { - TABLE_TAGS.contains(&&*name.local.to_ascii_lowercase()) - } else { - false - }; - let whitespace_replacement = if is_in_table { "" } else { " " }; - *contents = WHITESPACE_RE - .replace_all(&*contents, whitespace_replacement) - .as_ref() - .into(); - - if is_first_in_block || is_preceeded_by_ws { - *contents = LEADING_WHITESPACE_RE - .replace_all(&*contents, "") - .as_ref() - .into(); - } - if is_last_in_block { - *contents = TRAILING_WHITESPACE_RE - .replace_all(&*contents, "") - .as_ref() - .into(); - } - // TODO: collapse whitespace when adjacent to whitespace. - // For example, the whitespace in the span should be collapsed in all of these cases: - // - // " q " - // "q q" - // "q q" - // "q q" - // "q q" - } - &**contents != "" - } - NodeData::Element { - ref attrs, - ref name, - .. - } => { - let mut attrs = attrs.borrow_mut(); - for a in attrs.iter_mut() { - a.name.local = a.name.local.to_ascii_lowercase().into(); - } - attrs.sort_by(|a: &html5ever::Attribute, b: &html5ever::Attribute| { - (&*a.name.local).cmp(&*b.name.local) - }); - let ascii_name = &*name.local.to_ascii_lowercase(); - // drop empty tbody's - ascii_name != "tbody" - || node.children.borrow().len() > 1 - || node - .children - .borrow() - .iter() - .next() - .map(|only_child| match only_child.data { - NodeData::Text { ref contents, .. } => { - !contents.borrow().chars().all(|c| c.is_whitespace()) - } - _ => true, - }) - .unwrap_or(false) - } - } -} - -#[test] -fn strip_div_newline() { - assert_eq!("
    ", normalize_html("
    \n
    ")); -} - -#[test] -fn strip_end_newline() { - assert_eq!("test", normalize_html("test\n")); -} - -#[test] -fn strip_double_space() { - assert_eq!("test mess", normalize_html("test mess")); -} - -#[test] -fn strip_inline_internal_text() { - assert_eq!( - "a b c", - normalize_html(" a b c ") - ) -} - -#[test] -fn strip_inline_block_internal_text() { - assert_eq!( - "a b c", - normalize_html(" a b c ") - ) -} - -#[test] -fn leaves_necessary_whitespace_alone() { - assert_eq!("a b c", normalize_html("a b c")) -} - -#[test] -fn leaves_necessary_whitespace_alone_weird() { - assert_eq!( - "a b c", - normalize_html(" a b c") - ) -} - -#[test] -fn leaves_necessary_whitespace_all_nested() { - assert_eq!( - "", - normalize_html(" ") - ) -} - -#[test] -fn drops_empty_tbody() { - assert_eq!( - "
    hi
    ", - normalize_html("
    hi
    ") - ) -} - -#[test] -fn leaves_nonempty_tbody() { - let input = "
    hi
    "; - assert_eq!(input, normalize_html(input)) -} +#[macro_use] +extern crate html5ever; +#[macro_use] +extern crate lazy_static; + +use html5ever::serialize::{serialize, SerializeOpts}; +use html5ever::{driver as html, QualName}; +use markup5ever_rcdom::{Handle, NodeData, RcDom, SerializableHandle}; +use pulldown_cmark::{Options, Parser}; + +use regex::Regex; +use std::collections::HashSet; +use std::mem; +use std::rc::{Rc, Weak}; +use tendril::stream::TendrilSink; + +mod suite; + +#[inline(never)] +pub fn test_markdown_html(input: &str, output: &str, smart_punct: bool) { + let mut s = String::new(); + + let mut opts = Options::empty(); + opts.insert(Options::ENABLE_TABLES); + opts.insert(Options::ENABLE_FOOTNOTES); + opts.insert(Options::ENABLE_STRIKETHROUGH); + opts.insert(Options::ENABLE_TASKLISTS); + if smart_punct { + opts.insert(Options::ENABLE_SMART_PUNCTUATION); + } + + let p = Parser::new_ext(input, opts); + pulldown_cmark::html::push_html(&mut s, p); + + assert_eq!(normalize_html(output), normalize_html(&s)); +} + +lazy_static! { + static ref WHITESPACE_RE: Regex = Regex::new(r"\s+").unwrap(); + static ref LEADING_WHITESPACE_RE: Regex = Regex::new(r"\A\s+").unwrap(); + static ref TRAILING_WHITESPACE_RE: Regex = Regex::new(r"\s+\z").unwrap(); + static ref BLOCK_TAGS: HashSet<&'static str> = [ + "article", + "header", + "aside", + "hgroup", + "blockquote", + "hr", + "iframe", + "body", + "li", + "map", + "button", + "object", + "canvas", + "ol", + "caption", + "output", + "col", + "p", + "colgroup", + "pre", + "dd", + "progress", + "div", + "section", + "dl", + "table", + "td", + "dt", + "tbody", + "embed", + "textarea", + "fieldset", + "tfoot", + "figcaption", + "th", + "figure", + "thead", + "footer", + "tr", + "form", + "ul", + "h1", + "h2", + "h3", + "h4", + "h5", + "h6", + "video", + "script", + "style" + ] + .iter() + .cloned() + .collect(); + static ref WHITESPACE_SENSITIVE_TAGS: HashSet<&'static str> = + ["pre", "code", "h1", "h2", "h3", "h4", "h5", "h6"] + .iter() + .cloned() + .collect(); + static ref TABLE_TAGS: HashSet<&'static str> = ["table", "thead", "tbody", "tr", "td"] + .iter() + .cloned() + .collect(); +} + +fn make_html_parser() -> html::Parser { + html::parse_fragment( + RcDom::default(), + html::ParseOpts::default(), + QualName::new(None, ns!(html), local_name!("div")), + vec![], + ) +} + +fn normalize_html(s: &str) -> String { + let parser = make_html_parser(); + let dom = parser.one(s); + let body: SerializableHandle = normalize_dom(&dom).into(); + let opts = SerializeOpts::default(); + let mut ret_val = Vec::new(); + serialize(&mut ret_val, &body, opts) + .expect("Writing to a string shouldn't fail (expect on OOM)"); + String::from_utf8(ret_val).expect("html5ever should always produce UTF8") +} + +fn normalize_dom(dom: &RcDom) -> Handle { + let body = { + let children = dom.document.children.borrow(); + children[0].clone() + }; + let mut current_level = Vec::new(); + let mut next_level = Vec::new(); + current_level.extend(body.children.borrow().iter().cloned().rev()); + loop { + while let Some(mut node) = current_level.pop() { + let parent = node.parent.replace(None); + node.parent.replace(parent.clone()); + let parent = parent + .expect("a node in the DOM will have a parent, except the root, which is not processed") + .upgrade().expect("a node's parent will be pointed to by its parent (or the root pointer), and will not be dropped"); + let retain = normalize_node(&parent, &mut node); + if !retain { + let mut siblings = parent.children.borrow_mut(); + siblings.retain(|s| !Rc::ptr_eq(&node, s)); + } else { + next_level.extend(node.children.borrow().iter().cloned().rev()); + } + } + if next_level.is_empty() { + break; + }; + mem::swap(&mut next_level, &mut current_level); + } + body +} + +// Returns false if node is an empty text node or an empty tbody. +// Returns true otherwise. +fn normalize_node(parent: &Handle, node: &mut Handle) -> bool { + match node.data { + NodeData::Comment { .. } + | NodeData::Doctype { .. } + | NodeData::Document + | NodeData::ProcessingInstruction { .. } => true, + NodeData::Text { ref contents, .. } => { + let mut contents = contents.borrow_mut(); + let is_pre = { + let mut parent = parent.clone(); + loop { + let is_pre = if let NodeData::Element { ref name, .. } = parent.data { + WHITESPACE_SENSITIVE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + if is_pre { + break true; + }; + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_ + } else { + break false; + }; + } + }; + if !is_pre { + let (is_first_in_block, is_last_in_block) = { + let mut is_first_in_block = true; + let mut is_last_in_block = true; + let mut parent = parent.clone(); + let mut node = node.clone(); + loop { + let reached_block = if let NodeData::Element { ref name, .. } = parent.data + { + BLOCK_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let (is_first, is_last) = { + let siblings = parent.children.borrow(); + let n = &node; + ( + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false), + siblings.len() > 0 + && siblings + .get(siblings.len() - 1) + .map(|s| Rc::ptr_eq(s, n)) + .unwrap_or(false), + ) + }; + is_first_in_block = is_first_in_block && is_first; + is_last_in_block = is_last_in_block && is_last; + if (is_first_in_block || is_last_in_block) && !reached_block { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break (is_first_in_block, is_last_in_block); + } + } else { + break (is_first_in_block, is_last_in_block); + } + } + }; + let is_preceeded_by_ws = { + let mut parent = parent.clone(); + let mut node = node.clone(); + 'ascent: loop { + let is_first = { + let siblings = parent.children.borrow(); + let n = &node; + siblings.get(0).map(|s| Rc::ptr_eq(s, n)).unwrap_or(false) + }; + if is_first { + node = parent.clone(); + let parent_ = parent.parent.replace(None); + parent.parent.replace(parent_.clone()); + let parent_ = parent_.as_ref().and_then(Weak::upgrade); + if let Some(parent_) = parent_ { + parent = parent_; + } else { + break 'ascent false; + } + } else { + let siblings = parent.children.borrow(); + let n = &node; + let mut pos = !0; + 'search: for (i, s) in siblings.iter().enumerate() { + if Rc::ptr_eq(s, n) { + pos = i; + break 'search; + } + } + assert!( + pos != !0, + "The list of node's parent's children shall contain node" + ); + assert!( + pos != 0, + "If node is not first, then node's position shall not be zero" + ); + let mut preceeding = siblings[pos - 1].clone(); + 'descent: loop { + if let NodeData::Text { .. } = preceeding.data { + break 'descent; + } + preceeding = { + let ch = preceeding.children.borrow(); + if ch.len() == 0 { + break 'descent; + } + if let Some(preceeding_) = ch.get(ch.len() - 1) { + preceeding_.clone() + } else { + break 'descent; + } + }; + } + if let NodeData::Text { ref contents, .. } = preceeding.data { + break 'ascent TRAILING_WHITESPACE_RE.is_match(&*contents.borrow()); + } else { + break 'ascent false; + } + } + } + }; + + let is_in_table = if let NodeData::Element { ref name, .. } = parent.data { + TABLE_TAGS.contains(&&*name.local.to_ascii_lowercase()) + } else { + false + }; + let whitespace_replacement = if is_in_table { "" } else { " " }; + *contents = WHITESPACE_RE + .replace_all(&*contents, whitespace_replacement) + .as_ref() + .into(); + + if is_first_in_block || is_preceeded_by_ws { + *contents = LEADING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + if is_last_in_block { + *contents = TRAILING_WHITESPACE_RE + .replace_all(&*contents, "") + .as_ref() + .into(); + } + // TODO: collapse whitespace when adjacent to whitespace. + // For example, the whitespace in the span should be collapsed in all of these cases: + // + // " q " + // "q q" + // "q q" + // "q q" + // "q q" + } + &**contents != "" + } + NodeData::Element { + ref attrs, + ref name, + .. + } => { + let mut attrs = attrs.borrow_mut(); + for a in attrs.iter_mut() { + a.name.local = a.name.local.to_ascii_lowercase().into(); + } + attrs.sort_by(|a: &html5ever::Attribute, b: &html5ever::Attribute| { + (&*a.name.local).cmp(&*b.name.local) + }); + let ascii_name = &*name.local.to_ascii_lowercase(); + // drop empty tbody's + ascii_name != "tbody" + || node.children.borrow().len() > 1 + || node + .children + .borrow() + .iter() + .next() + .map(|only_child| match only_child.data { + NodeData::Text { ref contents, .. } => { + !contents.borrow().chars().all(|c| c.is_whitespace()) + } + _ => true, + }) + .unwrap_or(false) + } + } +} + +#[test] +fn strip_div_newline() { + assert_eq!("
    ", normalize_html("
    \n
    ")); +} + +#[test] +fn strip_end_newline() { + assert_eq!("test", normalize_html("test\n")); +} + +#[test] +fn strip_double_space() { + assert_eq!("test mess", normalize_html("test mess")); +} + +#[test] +fn strip_inline_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn strip_inline_block_internal_text() { + assert_eq!( + "a b c", + normalize_html(" a b c ") + ) +} + +#[test] +fn leaves_necessary_whitespace_alone() { + assert_eq!("a b c", normalize_html("a b c")) +} + +#[test] +fn leaves_necessary_whitespace_alone_weird() { + assert_eq!( + "a b c", + normalize_html(" a b c") + ) +} + +#[test] +fn leaves_necessary_whitespace_all_nested() { + assert_eq!( + "", + normalize_html(" ") + ) +} + +#[test] +fn drops_empty_tbody() { + assert_eq!( + "
    hi
    ", + normalize_html("
    hi
    ") + ) +} + +#[test] +fn leaves_nonempty_tbody() { + let input = "
    hi
    "; + assert_eq!(input, normalize_html(input)) +} diff --git a/vendor/pulldown-cmark/tests/suite/footnotes.rs b/vendor/pulldown-cmark/tests/suite/footnotes.rs index e31eff54b6..5e5c49bb78 100644 --- a/vendor/pulldown-cmark/tests/suite/footnotes.rs +++ b/vendor/pulldown-cmark/tests/suite/footnotes.rs @@ -1,165 +1,165 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn footnotes_test_1() { - let original = r##"Lorem ipsum.[^a] - -[^a]: Cool. -"##; - let expected = r##"

    Lorem ipsum.1

    -
    1 -

    Cool.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_2() { - let original = r##"> This is the song that never ends.\ -> Yes it goes on and on my friends.[^lambchops] -> -> [^lambchops]: -"##; - let expected = r##"
    -

    This is the song that never ends.
    -Yes it goes on and on my friends.1

    - -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_3() { - let original = r##"Songs that simply loop are a popular way to annoy people. [^examples] - -[^examples]: - * [The song that never ends](https://www.youtube.com/watch?v=0U2zJOryHKQ) - * [I know a song that gets on everybody's nerves](https://www.youtube.com/watch?v=TehWI09qxls) - * [Ninety-nine bottles of beer on the wall](https://www.youtube.com/watch?v=qVjCag8XoHQ) -"##; - let expected = r##"

    Songs that simply loop are a popular way to annoy people. 1

    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_4() { - let original = r##"[^lorem]: If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research. - -I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp. -"##; - let expected = r##"
    1 -

    If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research.

    -
    -

    I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_5() { - let original = r##"[^ipsum]: How much wood would a woodchuck chuck. - -If a woodchuck could chuck wood. - - -# Forms of entertainment that aren't childish -"##; - let expected = r##"
    1 -

    How much wood would a woodchuck chuck.

    -
    -

    If a woodchuck could chuck wood.

    -

    Forms of entertainment that aren't childish

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_6() { - let original = r##"> He's also really stupid. [^why] -> -> [^why]: Because your mamma! - -As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet. -"##; - let expected = r##"
    -

    He's also really stupid. 1

    -
    1 -

    Because your mamma!

    -
    -
    -

    As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_7() { - let original = r##"Nested footnotes are considered poor style. [^a] [^xkcd] - -[^a]: This does not mean that footnotes cannot reference each other. [^b] - -[^b]: This means that a footnote definition cannot be directly inside another footnote definition. -> This means that a footnote cannot be directly inside another footnote's body. [^e] -> -> [^e]: They can, however, be inside anything else. - -[^xkcd]: [The other kind of nested footnote is, however, considered poor style.](https://xkcd.com/1208/) -"##; - let expected = r##"

    Nested footnotes are considered poor style. 1 2

    -
    1 -

    This does not mean that footnotes cannot reference each other. 3

    -
    -
    3 -

    This means that a footnote definition cannot be directly inside another footnote definition.

    -
    -

    This means that a footnote cannot be directly inside another footnote's body. 4

    -
    4 -

    They can, however, be inside anything else.

    -
    -
    -
    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn footnotes_test_8() { - let original = r##"[^Doh] Ray Me Fa So La Te Do! [^1] - -[^Doh]: I know. Wrong Doe. And it won't render right. -[^1]: Common for people practicing music. -"##; - let expected = r##"

    1 Ray Me Fa So La Te Do! 2

    -
    1 -

    I know. Wrong Doe. And it won't render right. -2: Common for people practicing music.

    -
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn footnotes_test_1() { + let original = r##"Lorem ipsum.[^a] + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_2() { + let original = r##"> This is the song that never ends.\ +> Yes it goes on and on my friends.[^lambchops] +> +> [^lambchops]: +"##; + let expected = r##"
    +

    This is the song that never ends.
    +Yes it goes on and on my friends.1

    + +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_3() { + let original = r##"Songs that simply loop are a popular way to annoy people. [^examples] + +[^examples]: + * [The song that never ends](https://www.youtube.com/watch?v=0U2zJOryHKQ) + * [I know a song that gets on everybody's nerves](https://www.youtube.com/watch?v=TehWI09qxls) + * [Ninety-nine bottles of beer on the wall](https://www.youtube.com/watch?v=qVjCag8XoHQ) +"##; + let expected = r##"

    Songs that simply loop are a popular way to annoy people. 1

    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_4() { + let original = r##"[^lorem]: If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research. + +I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp. +"##; + let expected = r##"
    1 +

    If heaven ever wishes to grant me a boon, it will be a total effacing of the results of a mere chance which fixed my eye on a certain stray piece of shelf-paper. It was nothing on which I would naturally have stumbled in the course of my daily round, for it was an old number of an Australian journal, the Sydney Bulletin for April 18, 1925. It had escaped even the cutting bureau which had at the time of its issuance been avidly collecting material for my uncle's research.

    +
    +

    I had largely given over my inquiries into what Professor Angell called the "Cthulhu Cult", and was visiting a learned friend in Paterson, New Jersey; the curator of a local museum and a mineralogist of note. Examining one day the reserve specimens roughly set on the storage shelves in a rear room of the museum, my eye was caught by an odd picture in one of the old papers spread beneath the stones. It was the Sydney Bulletin I have mentioned, for my friend had wide affiliations in all conceivable foreign parts; and the picture was a half-tone cut of a hideous stone image almost identical with that which Legrasse had found in the swamp.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_5() { + let original = r##"[^ipsum]: How much wood would a woodchuck chuck. + +If a woodchuck could chuck wood. + + +# Forms of entertainment that aren't childish +"##; + let expected = r##"
    1 +

    How much wood would a woodchuck chuck.

    +
    +

    If a woodchuck could chuck wood.

    +

    Forms of entertainment that aren't childish

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_6() { + let original = r##"> He's also really stupid. [^why] +> +> [^why]: Because your mamma! + +As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet. +"##; + let expected = r##"
    +

    He's also really stupid. 1

    +
    1 +

    Because your mamma!

    +
    +
    +

    As such, we can guarantee that the non-childish forms of entertainment are probably more entertaining to adults, since, having had a whole childhood doing the childish ones, the non-childish ones are merely the ones that haven't gotten boring yet.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_7() { + let original = r##"Nested footnotes are considered poor style. [^a] [^xkcd] + +[^a]: This does not mean that footnotes cannot reference each other. [^b] + +[^b]: This means that a footnote definition cannot be directly inside another footnote definition. +> This means that a footnote cannot be directly inside another footnote's body. [^e] +> +> [^e]: They can, however, be inside anything else. + +[^xkcd]: [The other kind of nested footnote is, however, considered poor style.](https://xkcd.com/1208/) +"##; + let expected = r##"

    Nested footnotes are considered poor style. 1 2

    +
    1 +

    This does not mean that footnotes cannot reference each other. 3

    +
    +
    3 +

    This means that a footnote definition cannot be directly inside another footnote definition.

    +
    +

    This means that a footnote cannot be directly inside another footnote's body. 4

    +
    4 +

    They can, however, be inside anything else.

    +
    +
    +
    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn footnotes_test_8() { + let original = r##"[^Doh] Ray Me Fa So La Te Do! [^1] + +[^Doh]: I know. Wrong Doe. And it won't render right. +[^1]: Common for people practicing music. +"##; + let expected = r##"

    1 Ray Me Fa So La Te Do! 2

    +
    1 +

    I know. Wrong Doe. And it won't render right. +2: Common for people practicing music.

    +
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs b/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs index b8fd293980..92413c3068 100644 --- a/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs +++ b/vendor/pulldown-cmark/tests/suite/gfm_strikethrough.rs @@ -1,27 +1,27 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn gfm_strikethrough_test_1() { - let original = r##"~~Hi~~ Hello, world! -"##; - let expected = r##"

    Hi Hello, world!

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_strikethrough_test_2() { - let original = r##"This ~~has a - -new paragraph~~. -"##; - let expected = r##"

    This ~~has a

    -

    new paragraph~~.

    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_strikethrough_test_1() { + let original = r##"~~Hi~~ Hello, world! +"##; + let expected = r##"

    Hi Hello, world!

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_strikethrough_test_2() { + let original = r##"This ~~has a + +new paragraph~~. +"##; + let expected = r##"

    This ~~has a

    +

    new paragraph~~.

    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/gfm_table.rs b/vendor/pulldown-cmark/tests/suite/gfm_table.rs index 0e286b6b77..8ffadbd62e 100644 --- a/vendor/pulldown-cmark/tests/suite/gfm_table.rs +++ b/vendor/pulldown-cmark/tests/suite/gfm_table.rs @@ -1,205 +1,205 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn gfm_table_test_1() { - let original = r##"| foo | bar | -| --- | --- | -| baz | bim | -"##; - let expected = r##" - - - - - - - - - - - - -
    foobar
    bazbim
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_2() { - let original = r##"| abc | defghi | -:-: | -----------: -bar | baz -"##; - let expected = r##" - - - - - - - - - - - - -
    abcdefghi
    barbaz
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_3() { - let original = r##"| f\|oo | -| ------ | -| b `\|` az | -| b **\|** im | -"##; - let expected = r##" - - - - - - - - - - - - - -
    f|oo
    b \| az
    b | im
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_4() { - let original = r##"| abc | def | -| --- | --- | -| bar | baz | -> bar -"##; - let expected = r##" - - - - - - - - - - - - -
    abcdef
    barbaz
    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_5() { - let original = r##"| abc | def | -| --- | --- | -| bar | baz | -bar - -bar -"##; - let expected = r##" - - - - - - - - - - - - - - - - -
    abcdef
    barbaz
    bar
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_6() { - let original = r##"| abc | def | -| --- | -| bar | -"##; - let expected = r##"

    | abc | def | -| --- | -| bar |

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_7() { - let original = r##"| abc | def | -| --- | --- | -| bar | -| bar | baz | boo | -"##; - let expected = r##" - - - - - - - - - - - - - - - - -
    abcdef
    bar
    barbaz
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_table_test_8() { - let original = r##"| abc | def | -| --- | --- | -"##; - let expected = r##" - - - - - - -
    abcdef
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_table_test_1() { + let original = r##"| foo | bar | +| --- | --- | +| baz | bim | +"##; + let expected = r##" + + + + + + + + + + + + +
    foobar
    bazbim
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_2() { + let original = r##"| abc | defghi | +:-: | -----------: +bar | baz +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdefghi
    barbaz
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_3() { + let original = r##"| f\|oo | +| ------ | +| b `\|` az | +| b **\|** im | +"##; + let expected = r##" + + + + + + + + + + + + + +
    f|oo
    b \| az
    b | im
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_4() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +> bar +"##; + let expected = r##" + + + + + + + + + + + + +
    abcdef
    barbaz
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_5() { + let original = r##"| abc | def | +| --- | --- | +| bar | baz | +bar + +bar +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    barbaz
    bar
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_6() { + let original = r##"| abc | def | +| --- | +| bar | +"##; + let expected = r##"

    | abc | def | +| --- | +| bar |

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_7() { + let original = r##"| abc | def | +| --- | --- | +| bar | +| bar | baz | boo | +"##; + let expected = r##" + + + + + + + + + + + + + + + + +
    abcdef
    bar
    barbaz
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_table_test_8() { + let original = r##"| abc | def | +| --- | --- | +"##; + let expected = r##" + + + + + + +
    abcdef
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs b/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs index ca80369f99..2962d545b7 100644 --- a/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs +++ b/vendor/pulldown-cmark/tests/suite/gfm_tasklist.rs @@ -1,39 +1,39 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn gfm_tasklist_test_1() { - let original = r##"- [ ] foo -- [x] bar -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn gfm_tasklist_test_2() { - let original = r##"- [x] foo - - [ ] bar - - [x] baz -- [ ] bim -"##; - let expected = r##"
      -
    • foo -
        -
      • bar
      • -
      • baz
      • -
      -
    • -
    • bim
    • -
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn gfm_tasklist_test_1() { + let original = r##"- [ ] foo +- [x] bar +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn gfm_tasklist_test_2() { + let original = r##"- [x] foo + - [ ] bar + - [x] baz +- [ ] bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar
      • +
      • baz
      • +
      +
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/mod.rs b/vendor/pulldown-cmark/tests/suite/mod.rs index aa05206085..b355328a0b 100644 --- a/vendor/pulldown-cmark/tests/suite/mod.rs +++ b/vendor/pulldown-cmark/tests/suite/mod.rs @@ -1,12 +1,13 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -pub use super::test_markdown_html; - -mod footnotes; -mod regression; -mod table; -mod spec; -mod gfm_table; -mod gfm_strikethrough; -mod gfm_tasklist; +// This file is auto-generated by the build script +// Please, do not modify it manually + +pub use super::test_markdown_html; + +mod footnotes; +mod gfm_strikethrough; +mod gfm_table; +mod gfm_tasklist; +mod regression; +mod smart_punct; +mod spec; +mod table; diff --git a/vendor/pulldown-cmark/tests/suite/regression.rs b/vendor/pulldown-cmark/tests/suite/regression.rs index 5c723aacf1..722f0555c4 100644 --- a/vendor/pulldown-cmark/tests/suite/regression.rs +++ b/vendor/pulldown-cmark/tests/suite/regression.rs @@ -1,904 +1,953 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn regression_test_1() { - let original = r##"
    Testing 1..2..3.. - -This is a test of the details element. - -
    -"##; - let expected = r##"
    Testing 1..2..3.. -

    This is a test of the details element.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_2() { - let original = r##"see the [many] [articles] [on] [QuickCheck]. - -[many]: https://medium.com/@jlouis666/quickcheck-advice-c357efb4e7e6 -[articles]: http://www.quviq.com/products/erlang-quickcheck/ -[on]: https://wiki.haskell.org/Introduction_to_QuickCheck1 -[QuickCheck]: https://hackage.haskell.org/package/QuickCheck -"##; - let expected = r##"

    see the - many - articles - on - QuickCheck. -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_3() { - let original = r##"[![debug-stub-derive on crates.io][cratesio-image]][cratesio] -[![debug-stub-derive on docs.rs][docsrs-image]][docsrs] - -[cratesio-image]: https://img.shields.io/crates/v/debug_stub_derive.svg -[cratesio]: https://crates.io/crates/debug_stub_derive -[docsrs-image]: https://docs.rs/debug_stub_derive/badge.svg?version=0.3.0 -[docsrs]: https://docs.rs/debug_stub_derive/0.3.0/ -"##; - let expected = r##"

    debug-stub-derive on crates.io -debug-stub-derive on docs.rs

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_4() { - let original = r##"| Title A | Title B | -| --------- | --------- | -| Content | Content | - -| Title A | Title B | Title C | Title D | -| --------- | --------- | --------- | ---------:| -| Content | Content | Conent | Content | -"##; - let expected = r##" - -
    Title A Title B
    Content Content
    - - -
    Title A Title B Title C Title D
    Content Content Conent Content
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_5() { - let original = r##"foo§__(bar)__ -"##; - let expected = r##"

    foo§(bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_6() { - let original = r##" hello -"##; - let expected = r##"

    https://example.com hello

    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_7() { - let original = r##"[foo][bar] - - -[bar]: a -"##; - let expected = r##"

    foo

    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_8() { - let original = r##" -- **foo** (u8, u8) - - make something - -- **bar** (u16, u16) - - make something -"##; - let expected = r##" -
      -
    • -

      foo (u8, u8)

      -

      make something

      -
    • -
    • -

      bar (u16, u16)

      -

      make something

      -
    • -
    - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_9() { - let original = r##"[` -i8 -`]( -../../../std/primitive.i8.html -) -"##; - let expected = r##"

    i8

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_10() { - let original = r##"[a] - -[a]: /url (title\\*) -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_11() { - let original = r##"[a] - -[a]: /url (title\)) -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_12() { - let original = r##"[a] - -[a]: /url (title)) -"##; - let expected = r##"

    [a]

    -

    [a]: /url (title))

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_13() { - let original = r##"a -"##; - let expected = r##"

    a <?php this is not a valid processing tag

    -

    b

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_14() { - let original = r##"[a]: u\ -foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_15() { - let original = r##"\`foo` -"##; - let expected = r##"

    `foo`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_16() { - let original = r##"foo\\ -bar -"##; - let expected = r##"

    foo\ -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_17() { - let original = r##"1\. foo - -1\) bar -"##; - let expected = r##"

    1. foo

    -

    1) bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_18() { - let original = r##"1... - -1.2.3. - -1 2 3 . - -1.|2.-3. - -1)2)3) -"##; - let expected = r##"

    1...

    -

    1.2.3.

    -

    1 2 3 .

    -

    1.|2.-3.

    -

    1)2)3)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_19() { - let original = r##"[](<<>) -"##; - let expected = r##"

    [](<<>)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_20() { - let original = r##"\``foo``bar` -"##; - let expected = r##"

    `foo``bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_21() { - let original = r##"\\`foo` -"##; - let expected = r##"

    \foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_22() { - let original = r##"[\\]: x - -YOLO -"##; - let expected = r##"

    YOLO

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_23() { - let original = r##"lorem ipsum -A | B ----|--- -foo | bar -"##; - let expected = r##"

    lorem ipsum -A | B ----|--- -foo | bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_24() { - let original = r##"foo|bar ----|--- -foo|bar -"##; - let expected = r##" - -
    foobar
    foobar
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_25() { - let original = r##"foo|bar\\ ----|--- -foo|bar -"##; - let expected = r##" - -
    foobar\
    foobar
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_26() { - let original = r##"[](url) -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_27() { - let original = r##"[bar](url) -"##; - let expected = r##"

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_28() { - let original = r##"![](http://example.com/logo.png) -"##; - let expected = r##"

    http://example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_29() { - let original = r##"[ ](url) -"##; - let expected = r##"

    http://one http://two

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_30() { - let original = r##"Markdown | Less | Pretty ---- | --- | --- - -some text -"##; - let expected = r##" -
    Markdown Less Pretty
    -

    some text

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_31() { - let original = r##"1. > foo -2. > -"##; - let expected = r##"
      -
    1. -
      -

      foo

      -
      -
    2. -
    3. -
      -
      -
    4. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_32() { - let original = r##"[ -x - -]: f -"##; - let expected = r##"

    [ -x

    -

    ]: f

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_33() { - let original = r##"[foo]: -"##; - let expected = r##"

    [foo]:

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_34() { - let original = r##"> foo | bar -> --- | --- -yolo | swag -"##; - let expected = r##"
    -
    foobar
    -
    -

    yolo | swag

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_35() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_36() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_37() { - let original = r##"~~*_**__ - -__a__ -"##; - let expected = r##"

    ~~*_**__

    -

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_38() { - let original = r##"> ` -> ` -"##; - let expected = r##"
    -

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_39() { - let original = r##"`\|` -"##; - let expected = r##"

    \|

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_40() { - let original = r##"Paragraph 1 - -Paragraph 2 -"##; - let expected = r##"

    Paragraph 1

    -

    Paragraph 2

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_41() { - let original = r##"\[[link text](https://www.google.com/)\] -"##; - let expected = r##"

    [link text]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_42() { - let original = r##"foo | bar ---- | --- -[a](< | url>) -"##; - let expected = r##"
    foobar
    [a](<url>)
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_43() { - let original = r##"[a](url " -- - - -") -"##; - let expected = r##"

    [a](url "

    -
    -

    ")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_44() { - let original = r##"[a](url - -) -"##; - let expected = r##"

    [a](url

    -

    )

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_45() { - let original = r##"[a](b " - -") -"##; - let expected = r##"

    [a](b "

    -

    ")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_46() { - let original = r##" -"##; - let expected = r##"

    <http:// >

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_47() { - let original = r##" -"##; - let expected = r##"

    <http://>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_48() { - let original = r##"foo | bar ---- | --- - - -foobar - - -<http://baz - - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_49() { - let original = r##"foo | bar ---- | --- - -"##; - let expected = r##" - - - - - - -
    foobar
    <http://>
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_50() { - let original = r##"\*hi\_ -"##; - let expected = r##"

    *hi_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_51() { - let original = r##"email: \_ -"##; - let expected = r##"

    email: john@example.com_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_52() { - let original = r##"> [link](/url 'foo -> bar') -"##; - let expected = r##"
    -

    link

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_53() { - let original = r##"> [foo -> bar]: /url -> -> [foo bar] -"##; - let expected = r##"
    -

    foo bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_54() { - let original = r##"> [foo bar]: /url -> -> [foo -> bar] -"##; - let expected = r##"
    -

    foo -bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_55() { - let original = r##"> - [a -> b c]: /foo - -[a b c] -"##; - let expected = r##"
    -
      -
    • -
    -
    -

    a b c

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_56() { - let original = r##"[a -> b]: /foo - -[a b] [a > b] -"##; - let expected = r##"

    [a

    -
    -

    b]: /foo

    -
    -

    [a b] [a > b]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_57() { - let original = r##"[`cargo -package`] - -[`cargo package`]: https://example.com -"##; - let expected = r##"

    cargo package

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_58() { - let original = r##"> [`cargo -> package`] - -[`cargo package`]: https://example.com -"##; - let expected = r##"
    -

    cargo package

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_59() { - let original = r##"> `cargo -> package` -"##; - let expected = r##"
    -

    cargo package

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_60() { - let original = r##"Lorem ipsum.[^a] - -An unordered list before the footnotes: -* Ipsum -* Lorem - -[^a]: Cool. -"##; - let expected = r##"

    Lorem ipsum.1

    -

    An unordered list before the footnotes:

    -
      -
    • Ipsum
    • -
    • Lorem
    • -
    -
    1 -

    Cool.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_61() { - let original = r##"[][a] - -[a]: b - -# assimp-rs [![][crates-badge]][crates] - -[crates]: https://crates.io/crates/assimp -[crates-badge]: http://meritbadge.herokuapp.com/assimp -"##; - let expected = r##"

    - -

    assimp-rs

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_62() { - let original = r##"* A list. - - * A sublist. - - * Another sublist. - - -* A list. - - * A sublist. - - * Another sublist. - -"##; - let expected = r##"
      -
    • -

      A list.

      -
        -
      • -

        A sublist.

        -
      • -
      • -

        Another sublist.

        -
      • -
      -
    • -
    • -

      A list.

      -
        -
      • -

        A sublist.

        -
      • -
      • -

        Another sublist.

        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn regression_test_63() { - let original = r##"<foo

    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn regression_test_1() { + let original = r##"
    Testing 1..2..3.. + +This is a test of the details element. + +
    +"##; + let expected = r##"
    Testing 1..2..3.. +

    This is a test of the details element.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_2() { + let original = r##"see the [many] [articles] [on] [QuickCheck]. + +[many]: https://medium.com/@jlouis666/quickcheck-advice-c357efb4e7e6 +[articles]: http://www.quviq.com/products/erlang-quickcheck/ +[on]: https://wiki.haskell.org/Introduction_to_QuickCheck1 +[QuickCheck]: https://hackage.haskell.org/package/QuickCheck +"##; + let expected = r##"

    see the + many + articles + on + QuickCheck. +

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_3() { + let original = r##"[![debug-stub-derive on crates.io][cratesio-image]][cratesio] +[![debug-stub-derive on docs.rs][docsrs-image]][docsrs] + +[cratesio-image]: https://img.shields.io/crates/v/debug_stub_derive.svg +[cratesio]: https://crates.io/crates/debug_stub_derive +[docsrs-image]: https://docs.rs/debug_stub_derive/badge.svg?version=0.3.0 +[docsrs]: https://docs.rs/debug_stub_derive/0.3.0/ +"##; + let expected = r##"

    debug-stub-derive on crates.io +debug-stub-derive on docs.rs

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_4() { + let original = r##"| Title A | Title B | +| --------- | --------- | +| Content | Content | + +| Title A | Title B | Title C | Title D | +| --------- | --------- | --------- | ---------:| +| Content | Content | Conent | Content | +"##; + let expected = r##" + +
    Title A Title B
    Content Content
    + + +
    Title A Title B Title C Title D
    Content Content Conent Content
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_5() { + let original = r##"foo§__(bar)__ +"##; + let expected = r##"

    foo§(bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_6() { + let original = r##" hello +"##; + let expected = r##"

    https://example.com hello

    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_7() { + let original = r##"[foo][bar] + + +[bar]: a +"##; + let expected = r##"

    foo

    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_8() { + let original = r##" +- **foo** (u8, u8) + + make something + +- **bar** (u16, u16) + + make something +"##; + let expected = r##" +
      +
    • +

      foo (u8, u8)

      +

      make something

      +
    • +
    • +

      bar (u16, u16)

      +

      make something

      +
    • +
    + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_9() { + let original = r##"[` +i8 +`]( +../../../std/primitive.i8.html +) +"##; + let expected = r##"

    i8

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_10() { + let original = r##"[a] + +[a]: /url (title\\*) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_11() { + let original = r##"[a] + +[a]: /url (title\)) +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_12() { + let original = r##"[a] + +[a]: /url (title)) +"##; + let expected = r##"

    [a]

    +

    [a]: /url (title))

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_13() { + let original = r##"a +"##; + let expected = r##"

    a <?php this is not a valid processing tag

    +

    b

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_14() { + let original = r##"[a]: u\ +foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_15() { + let original = r##"\`foo` +"##; + let expected = r##"

    `foo`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_16() { + let original = r##"foo\\ +bar +"##; + let expected = r##"

    foo\ +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_17() { + let original = r##"1\. foo + +1\) bar +"##; + let expected = r##"

    1. foo

    +

    1) bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_18() { + let original = r##"1... + +1.2.3. + +1 2 3 . + +1.|2.-3. + +1)2)3) +"##; + let expected = r##"

    1...

    +

    1.2.3.

    +

    1 2 3 .

    +

    1.|2.-3.

    +

    1)2)3)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_19() { + let original = r##"[](<<>) +"##; + let expected = r##"

    [](<<>)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_20() { + let original = r##"\``foo``bar` +"##; + let expected = r##"

    `foo``bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_21() { + let original = r##"\\`foo` +"##; + let expected = r##"

    \foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_22() { + let original = r##"[\\]: x + +YOLO +"##; + let expected = r##"

    YOLO

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_23() { + let original = r##"lorem ipsum +A | B +---|--- +foo | bar +"##; + let expected = r##"

    lorem ipsum +A | B +---|--- +foo | bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_24() { + let original = r##"foo|bar +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar
    foobar
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_25() { + let original = r##"foo|bar\\ +---|--- +foo|bar +"##; + let expected = r##" + +
    foobar\
    foobar
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_26() { + let original = r##"[](url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_27() { + let original = r##"[bar](url) +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_28() { + let original = r##"![](http://example.com/logo.png) +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_29() { + let original = r##"[ ](url) +"##; + let expected = r##"

    http://one http://two

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_30() { + let original = r##"Markdown | Less | Pretty +--- | --- | --- + +some text +"##; + let expected = r##" +
    Markdown Less Pretty
    +

    some text

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_31() { + let original = r##"1. > foo +2. > +"##; + let expected = r##"
      +
    1. +
      +

      foo

      +
      +
    2. +
    3. +
      +
      +
    4. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_32() { + let original = r##"[ +x + +]: f +"##; + let expected = r##"

    [ +x

    +

    ]: f

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_33() { + let original = r##"[foo]: +"##; + let expected = r##"

    [foo]:

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_34() { + let original = r##"> [foo +> bar]: /url +> +> [foo bar] +"##; + let expected = r##"
    +

    foo bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_35() { + let original = r##"> foo | bar +> --- | --- +yolo | swag +"##; + let expected = r##"
    +
    foobar
    +
    +

    yolo | swag

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_36() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_37() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_38() { + let original = r##"~~*_**__ + +__a__ +"##; + let expected = r##"

    ~~*_**__

    +

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_39() { + let original = r##"> ` +> ` +"##; + let expected = r##"
    +

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_40() { + let original = r##"`\|` +"##; + let expected = r##"

    \|

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_41() { + let original = r##"Paragraph 1 + +Paragraph 2 +"##; + let expected = r##"

    Paragraph 1

    +

    Paragraph 2

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_42() { + let original = r##"\[[link text](https://www.google.com/)\] +"##; + let expected = r##"

    [link text]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_43() { + let original = r##"foo | bar +--- | --- +[a](< | url>) +"##; + let expected = r##"
    foobar
    [a](<url>)
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_44() { + let original = r##"[a](url " +- - - +") +"##; + let expected = r##"

    [a](url "

    +
    +

    ")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_45() { + let original = r##"[a](url + +) +"##; + let expected = r##"

    [a](url

    +

    )

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_46() { + let original = r##"[a](b " + +") +"##; + let expected = r##"

    [a](b "

    +

    ")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_47() { + let original = r##" +"##; + let expected = r##"

    <http:// >

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_48() { + let original = r##" +"##; + let expected = r##"

    <http://>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_49() { + let original = r##"foo | bar +--- | --- + + +foobar + + +<http://baz + + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_50() { + let original = r##"foo | bar +--- | --- + +"##; + let expected = r##" + + + + + + +
    foobar
    <http://>
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_51() { + let original = r##"\*hi\_ +"##; + let expected = r##"

    *hi_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_52() { + let original = r##"email: \_ +"##; + let expected = r##"

    email: john@example.com_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_53() { + let original = r##"> [link](/url 'foo +> bar') +"##; + let expected = r##"
    +

    link

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_54() { + let original = r##"> [foo +> bar]: /url +> +> [foo bar] +"##; + let expected = r##"
    +

    foo bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_55() { + let original = r##"> [foo bar]: /url +> +> [foo +> bar] +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_56() { + let original = r##"> - [a +> b c]: /foo + +[a b c] +"##; + let expected = r##"
    +
      +
    • +
    +
    +

    a b c

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_57() { + let original = r##"[a +> b]: /foo + +[a b] [a > b] +"##; + let expected = r##"

    [a

    +
    +

    b]: /foo

    +
    +

    [a b] [a > b]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_58() { + let original = r##"[`cargo +package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"

    cargo package

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_59() { + let original = r##"> [`cargo +> package`] + +[`cargo package`]: https://example.com +"##; + let expected = r##"
    +

    cargo package

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_60() { + let original = r##"> `cargo +> package` +"##; + let expected = r##"
    +

    cargo package

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_61() { + let original = r##"> Note: Though you should not rely on this, all pointers to title="Dynamically Sized Types">DSTs are currently twice the size of +> the size of `usize` and have the same alignment. +"##; + let expected = r##"
    +

    Note: Though you should not rely on this, all pointers to +DSTs are currently twice the size of +the size of usize and have the same alignment.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_62() { + let original = r##"Lorem ipsum.[^a] + +An unordered list before the footnotes: +* Ipsum +* Lorem + +[^a]: Cool. +"##; + let expected = r##"

    Lorem ipsum.1

    +

    An unordered list before the footnotes:

    +
      +
    • Ipsum
    • +
    • Lorem
    • +
    +
    1 +

    Cool.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_63() { + let original = r##"[][a] + +[a]: b + +# assimp-rs [![][crates-badge]][crates] + +[crates]: https://crates.io/crates/assimp +[crates-badge]: http://meritbadge.herokuapp.com/assimp +"##; + let expected = r##"

    + +

    assimp-rs

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_64() { + let original = r##"* A list. + + * A sublist. + + * Another sublist. + + +* A list. + + * A sublist. + + * Another sublist. + +"##; + let expected = r##"
      +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    • +

      A list.

      +
        +
      • +

        A sublist.

        +
      • +
      • +

        Another sublist.

        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_65() { + let original = r##"<foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn regression_test_66() { + let original = r##"> > a > ="yo +> > lo"> +"##; + let expected = r##"
    +
    +

    a

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/smart_punct.rs b/vendor/pulldown-cmark/tests/suite/smart_punct.rs new file mode 100644 index 0000000000..62681b6489 --- /dev/null +++ b/vendor/pulldown-cmark/tests/suite/smart_punct.rs @@ -0,0 +1,201 @@ +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn smart_punct_test_1() { + let original = r##""Hello," said the spider. +"'Shelob' is my name." +"##; + let expected = r##"

    “Hello,” said the spider. +“‘Shelob’ is my name.”

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_2() { + let original = r##"'A', 'B', and 'C' are letters. +"##; + let expected = r##"

    ‘A’, ‘B’, and ‘C’ are letters.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_3() { + let original = r##"'Oak,' 'elm,' and 'beech' are names of trees. +So is 'pine.' +"##; + let expected = r##"

    ‘Oak,’ ‘elm,’ and ‘beech’ are names of trees. +So is ‘pine.’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_4() { + let original = r##"'He said, "I want to go."' +"##; + let expected = r##"

    ‘He said, “I want to go.”’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_5() { + let original = r##"Were you alive in the 70's? +"##; + let expected = r##"

    Were you alive in the 70’s?

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_6() { + let original = r##"Here is some quoted '`code`' and a "[quoted link](url)". +"##; + let expected = r##"

    Here is some quoted ‘code’ and a “quoted link”.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_7() { + let original = r##"'tis the season to be 'jolly' +"##; + let expected = r##"

    ’tis the season to be ‘jolly’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_8() { + let original = r##"'We'll use Jane's boat and John's truck,' Jenna said. +"##; + let expected = r##"

    ‘We’ll use Jane’s boat and John’s truck,’ Jenna said.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_9() { + let original = r##""A paragraph with no closing quote. + +"Second paragraph by same speaker, in fiction." +"##; + let expected = r##"

    “A paragraph with no closing quote.

    +

    “Second paragraph by same speaker, in fiction.”

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_10() { + let original = r##"[a]'s b' +"##; + let expected = r##"

    [a]’s b’

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_11() { + let original = r##"\"This is not smart.\" +This isn\'t either. +5\'8\" +"##; + let expected = r##"

    "This is not smart." +This isn't either. +5'8"

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_12() { + let original = r##"Some dashes: em---em +en--en +em --- em +en -- en +2--3 +"##; + let expected = r##"

    Some dashes: em—em +en–en +em — em +en – en +2–3

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_13() { + let original = r##"one- +two-- +three--- +four---- +five----- +six------ +seven------- +eight-------- +nine--------- +thirteen-------------. +"##; + let expected = r##"

    one- +two– +three— +four–– +five—– +six—— +seven—–– +eight–––– +nine——— +thirteen———––.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_14() { + let original = r##"Escaped hyphens: \-- \-\-\-. +"##; + let expected = r##"

    Escaped hyphens: -- ---.

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_15() { + let original = r##"Ellipses...and...and.... +"##; + let expected = r##"

    Ellipses…and…and….

    +"##; + + test_markdown_html(original, expected, true); +} + +#[test] +fn smart_punct_test_16() { + let original = r##"No ellipses\.\.\. +"##; + let expected = r##"

    No ellipses...

    +"##; + + test_markdown_html(original, expected, true); +} diff --git a/vendor/pulldown-cmark/tests/suite/spec.rs b/vendor/pulldown-cmark/tests/suite/spec.rs index 0215dd4b89..6a3f4d9dfc 100644 --- a/vendor/pulldown-cmark/tests/suite/spec.rs +++ b/vendor/pulldown-cmark/tests/suite/spec.rs @@ -1,8447 +1,8447 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn spec_test_1() { - let original = r##" foo baz bim -"##; - let expected = r##"
    foo	baz		bim
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_2() { - let original = r##" foo baz bim -"##; - let expected = r##"
    foo	baz		bim
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_3() { - let original = r##" a a - ὐ a -"##; - let expected = r##"
    a	a
    -ὐ	a
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_4() { - let original = r##" - foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_5() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -
        bar
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_6() { - let original = r##"> foo -"##; - let expected = r##"
    -
      foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_7() { - let original = r##"- foo -"##; - let expected = r##"
      -
    • -
        foo
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_8() { - let original = r##" foo - bar -"##; - let expected = r##"
    foo
    -bar
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_9() { - let original = r##" - foo - - bar - - baz -"##; - let expected = r##"
      -
    • foo -
        -
      • bar -
          -
        • baz
        • -
        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_10() { - let original = r##"# Foo -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_11() { - let original = r##"* * * -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_12() { - let original = r##"- `one -- two` -"##; - let expected = r##"
      -
    • `one
    • -
    • two`
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_13() { - let original = r##"*** ---- -___ -"##; - let expected = r##"
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_14() { - let original = r##"+++ -"##; - let expected = r##"

    +++

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_15() { - let original = r##"=== -"##; - let expected = r##"

    ===

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_16() { - let original = r##"-- -** -__ -"##; - let expected = r##"

    -- -** -__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_17() { - let original = r##" *** - *** - *** -"##; - let expected = r##"
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_18() { - let original = r##" *** -"##; - let expected = r##"
    ***
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_19() { - let original = r##"Foo - *** -"##; - let expected = r##"

    Foo -***

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_20() { - let original = r##"_____________________________________ -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_21() { - let original = r##" - - - -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_22() { - let original = r##" ** * ** * ** * ** -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_23() { - let original = r##"- - - - -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_24() { - let original = r##"- - - - -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_25() { - let original = r##"_ _ _ _ a - -a------ - ----a--- -"##; - let expected = r##"

    _ _ _ _ a

    -

    a------

    -

    ---a---

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_26() { - let original = r##" *-* -"##; - let expected = r##"

    -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_27() { - let original = r##"- foo -*** -- bar -"##; - let expected = r##"
      -
    • foo
    • -
    -
    -
      -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_28() { - let original = r##"Foo -*** -bar -"##; - let expected = r##"

    Foo

    -
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_29() { - let original = r##"Foo ---- -bar -"##; - let expected = r##"

    Foo

    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_30() { - let original = r##"* Foo -* * * -* Bar -"##; - let expected = r##"
      -
    • Foo
    • -
    -
    -
      -
    • Bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_31() { - let original = r##"- Foo -- * * * -"##; - let expected = r##"
      -
    • Foo
    • -
    • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_32() { - let original = r##"# foo -## foo -### foo -#### foo -##### foo -###### foo -"##; - let expected = r##"

    foo

    -

    foo

    -

    foo

    -

    foo

    -
    foo
    -
    foo
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_33() { - let original = r##"####### foo -"##; - let expected = r##"

    ####### foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_34() { - let original = r##"#5 bolt - -#hashtag -"##; - let expected = r##"

    #5 bolt

    -

    #hashtag

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_35() { - let original = r##"\## foo -"##; - let expected = r##"

    ## foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_36() { - let original = r##"# foo *bar* \*baz\* -"##; - let expected = r##"

    foo bar *baz*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_37() { - let original = r##"# foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_38() { - let original = r##" ### foo - ## foo - # foo -"##; - let expected = r##"

    foo

    -

    foo

    -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_39() { - let original = r##" # foo -"##; - let expected = r##"
    # foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_40() { - let original = r##"foo - # bar -"##; - let expected = r##"

    foo -# bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_41() { - let original = r##"## foo ## - ### bar ### -"##; - let expected = r##"

    foo

    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_42() { - let original = r##"# foo ################################## -##### foo ## -"##; - let expected = r##"

    foo

    -
    foo
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_43() { - let original = r##"### foo ### -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_44() { - let original = r##"### foo ### b -"##; - let expected = r##"

    foo ### b

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_45() { - let original = r##"# foo# -"##; - let expected = r##"

    foo#

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_46() { - let original = r##"### foo \### -## foo #\## -# foo \# -"##; - let expected = r##"

    foo ###

    -

    foo ###

    -

    foo #

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_47() { - let original = r##"**** -## foo -**** -"##; - let expected = r##"
    -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_48() { - let original = r##"Foo bar -# baz -Bar foo -"##; - let expected = r##"

    Foo bar

    -

    baz

    -

    Bar foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_49() { - let original = r##"## -# -### ### -"##; - let expected = r##"

    -

    -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_50() { - let original = r##"Foo *bar* -========= - -Foo *bar* ---------- -"##; - let expected = r##"

    Foo bar

    -

    Foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_51() { - let original = r##"Foo *bar -baz* -==== -"##; - let expected = r##"

    Foo bar -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_52() { - let original = r##" Foo *bar -baz* -==== -"##; - let expected = r##"

    Foo bar -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_53() { - let original = r##"Foo -------------------------- - -Foo -= -"##; - let expected = r##"

    Foo

    -

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_54() { - let original = r##" Foo ---- - - Foo ------ - - Foo - === -"##; - let expected = r##"

    Foo

    -

    Foo

    -

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_55() { - let original = r##" Foo - --- - - Foo ---- -"##; - let expected = r##"
    Foo
    ----
    -
    -Foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_56() { - let original = r##"Foo - ---- -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_57() { - let original = r##"Foo - --- -"##; - let expected = r##"

    Foo ----

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_58() { - let original = r##"Foo -= = - -Foo ---- - -"##; - let expected = r##"

    Foo -= =

    -

    Foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_59() { - let original = r##"Foo ------ -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_60() { - let original = r##"Foo\ ----- -"##; - let expected = r##"

    Foo\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_61() { - let original = r##"`Foo ----- -` - - -"##; - let expected = r##"

    `Foo

    -

    `

    -

    <a title="a lot

    -

    of dashes"/>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_62() { - let original = r##"> Foo ---- -"##; - let expected = r##"
    -

    Foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_63() { - let original = r##"> foo -bar -=== -"##; - let expected = r##"
    -

    foo -bar -===

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_64() { - let original = r##"- Foo ---- -"##; - let expected = r##"
      -
    • Foo
    • -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_65() { - let original = r##"Foo -Bar ---- -"##; - let expected = r##"

    Foo -Bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_66() { - let original = r##"--- -Foo ---- -Bar ---- -Baz -"##; - let expected = r##"
    -

    Foo

    -

    Bar

    -

    Baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_67() { - let original = r##" -==== -"##; - let expected = r##"

    ====

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_68() { - let original = r##"--- ---- -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_69() { - let original = r##"- foo ------ -"##; - let expected = r##"
      -
    • foo
    • -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_70() { - let original = r##" foo ---- -"##; - let expected = r##"
    foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_71() { - let original = r##"> foo ------ -"##; - let expected = r##"
    -

    foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_72() { - let original = r##"\> foo ------- -"##; - let expected = r##"

    > foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_73() { - let original = r##"Foo - -bar ---- -baz -"##; - let expected = r##"

    Foo

    -

    bar

    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_74() { - let original = r##"Foo -bar - ---- - -baz -"##; - let expected = r##"

    Foo -bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_75() { - let original = r##"Foo -bar -* * * -baz -"##; - let expected = r##"

    Foo -bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_76() { - let original = r##"Foo -bar -\--- -baz -"##; - let expected = r##"

    Foo -bar ---- -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_77() { - let original = r##" a simple - indented code block -"##; - let expected = r##"
    a simple
    -  indented code block
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_78() { - let original = r##" - foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_79() { - let original = r##"1. foo - - - bar -"##; - let expected = r##"
      -
    1. -

      foo

      -
        -
      • bar
      • -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_80() { - let original = r##"
    - *hi* - - - one -"##; - let expected = r##"
    <a/>
    -*hi*
    -
    -- one
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_81() { - let original = r##" chunk1 - - chunk2 - - - - chunk3 -"##; - let expected = r##"
    chunk1
    -
    -chunk2
    -
    -
    -
    -chunk3
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_82() { - let original = r##" chunk1 - - chunk2 -"##; - let expected = r##"
    chunk1
    -  
    -  chunk2
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_83() { - let original = r##"Foo - bar - -"##; - let expected = r##"

    Foo -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_84() { - let original = r##" foo -bar -"##; - let expected = r##"
    foo
    -
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_85() { - let original = r##"# Heading - foo -Heading ------- - foo ----- -"##; - let expected = r##"

    Heading

    -
    foo
    -
    -

    Heading

    -
    foo
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_86() { - let original = r##" foo - bar -"##; - let expected = r##"
        foo
    -bar
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_87() { - let original = r##" - - foo - - -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_88() { - let original = r##" foo -"##; - let expected = r##"
    foo  
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_89() { - let original = r##"``` -< - > -``` -"##; - let expected = r##"
    <
    - >
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_90() { - let original = r##"~~~ -< - > -~~~ -"##; - let expected = r##"
    <
    - >
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_91() { - let original = r##"`` -foo -`` -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_92() { - let original = r##"``` -aaa -~~~ -``` -"##; - let expected = r##"
    aaa
    -~~~
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_93() { - let original = r##"~~~ -aaa -``` -~~~ -"##; - let expected = r##"
    aaa
    -```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_94() { - let original = r##"```` -aaa -``` -`````` -"##; - let expected = r##"
    aaa
    -```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_95() { - let original = r##"~~~~ -aaa -~~~ -~~~~ -"##; - let expected = r##"
    aaa
    -~~~
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_96() { - let original = r##"``` -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_97() { - let original = r##"````` - -``` -aaa -"##; - let expected = r##"
    
    -```
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_98() { - let original = r##"> ``` -> aaa - -bbb -"##; - let expected = r##"
    -
    aaa
    -
    -
    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_99() { - let original = r##"``` - - -``` -"##; - let expected = r##"
    
    -  
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_100() { - let original = r##"``` -``` -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_101() { - let original = r##" ``` - aaa -aaa -``` -"##; - let expected = r##"
    aaa
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_102() { - let original = r##" ``` -aaa - aaa -aaa - ``` -"##; - let expected = r##"
    aaa
    -aaa
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_103() { - let original = r##" ``` - aaa - aaa - aaa - ``` -"##; - let expected = r##"
    aaa
    - aaa
    -aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_104() { - let original = r##" ``` - aaa - ``` -"##; - let expected = r##"
    ```
    -aaa
    -```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_105() { - let original = r##"``` -aaa - ``` -"##; - let expected = r##"
    aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_106() { - let original = r##" ``` -aaa - ``` -"##; - let expected = r##"
    aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_107() { - let original = r##"``` -aaa - ``` -"##; - let expected = r##"
    aaa
    -    ```
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_108() { - let original = r##"``` ``` -aaa -"##; - let expected = r##"

    -aaa

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_109() { - let original = r##"~~~~~~ -aaa -~~~ ~~ -"##; - let expected = r##"
    aaa
    -~~~ ~~
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_110() { - let original = r##"foo -``` -bar -``` -baz -"##; - let expected = r##"

    foo

    -
    bar
    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_111() { - let original = r##"foo ---- -~~~ -bar -~~~ -# baz -"##; - let expected = r##"

    foo

    -
    bar
    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_112() { - let original = r##"```ruby -def foo(x) - return 3 -end -``` -"##; - let expected = r##"
    def foo(x)
    -  return 3
    -end
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_113() { - let original = r##"~~~~ ruby startline=3 $%@#$ -def foo(x) - return 3 -end -~~~~~~~ -"##; - let expected = r##"
    def foo(x)
    -  return 3
    -end
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_114() { - let original = r##"````; -```` -"##; - let expected = r##"
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_115() { - let original = r##"``` aa ``` -foo -"##; - let expected = r##"

    aa -foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_116() { - let original = r##"~~~ aa ``` ~~~ -foo -~~~ -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_117() { - let original = r##"``` -``` aaa -``` -"##; - let expected = r##"
    ``` aaa
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_118() { - let original = r##"
    -
    -**Hello**,
    -
    -_world_.
    -
    -
    -"##; - let expected = r##"
    -
    -**Hello**,
    -

    world. -

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_119() { - let original = r##" - - - -
    - hi -
    - -okay. -"##; - let expected = r##" - - - -
    - hi -
    -

    okay.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_120() { - let original = r##"
    -*foo* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_122() { - let original = r##"
    - -*Markdown* - -
    -"##; - let expected = r##"
    -

    Markdown

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_123() { - let original = r##"
    -
    -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_124() { - let original = r##"
    -
    -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_125() { - let original = r##"
    -*foo* - -*bar* -"##; - let expected = r##"
    -*foo* -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_126() { - let original = r##"
    -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_130() { - let original = r##"
    -foo -
    -"##; - let expected = r##"
    -foo -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_131() { - let original = r##"
    -``` c -int x = 33; -``` -"##; - let expected = r##"
    -``` c -int x = 33; -``` -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_132() { - let original = r##" -*bar* - -"##; - let expected = r##" -*bar* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_133() { - let original = r##" -*bar* - -"##; - let expected = r##" -*bar* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_134() { - let original = r##" -*bar* - -"##; - let expected = r##" -*bar* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_135() { - let original = r##" -*bar* -"##; - let expected = r##" -*bar* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_136() { - let original = r##" -*foo* - -"##; - let expected = r##" -*foo* - -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_137() { - let original = r##" - -*foo* - - -"##; - let expected = r##" -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_138() { - let original = r##"*foo* -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_139() { - let original = r##"
    
    -import Text.HTML.TagSoup
    -
    -main :: IO ()
    -main = print $ parseTags tags
    -
    -okay -"##; - let expected = r##"
    
    -import Text.HTML.TagSoup
    -
    -main :: IO ()
    -main = print $ parseTags tags
    -
    -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_140() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_141() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_142() { - let original = r##" -*foo* -"##; - let expected = r##" -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_146() { - let original = r##"*bar* -*baz* -"##; - let expected = r##"*bar* -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_147() { - let original = r##"1. *bar* -"##; - let expected = r##"1. *bar* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_148() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_149() { - let original = r##"'; - -?> -okay -"##; - let expected = r##"'; - -?> -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_150() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_151() { - let original = r##" -okay -"##; - let expected = r##" -

    okay

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_152() { - let original = r##" - - -"##; - let expected = r##" -
    <!-- foo -->
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_153() { - let original = r##"
    - -
    -"##; - let expected = r##"
    -
    <div>
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_154() { - let original = r##"Foo -
    -bar -
    -"##; - let expected = r##"

    Foo

    -
    -bar -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_155() { - let original = r##"
    -bar -
    -*foo* -"##; - let expected = r##"
    -bar -
    -*foo* -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_156() { - let original = r##"Foo - -baz -"##; - let expected = r##"

    Foo - -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_157() { - let original = r##"
    - -*Emphasized* text. - -
    -"##; - let expected = r##"
    -

    Emphasized text.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_158() { - let original = r##"
    -*Emphasized* text. -
    -"##; - let expected = r##"
    -*Emphasized* text. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_159() { - let original = r##" - - - - - - - -
    -Hi -
    -"##; - let expected = r##" - - - -
    -Hi -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_160() { - let original = r##" - - - - - - - -
    - Hi -
    -"##; - let expected = r##" - -
    <td>
    -  Hi
    -</td>
    -
    - -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_161() { - let original = r##"[foo]: /url "title" - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_162() { - let original = r##" [foo]: - /url - 'the title' - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_163() { - let original = r##"[Foo*bar\]]:my_(url) 'title (with parens)' - -[Foo*bar\]] -"##; - let expected = r##"

    Foo*bar]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_164() { - let original = r##"[Foo bar]: - -'title' - -[Foo bar] -"##; - let expected = r##"

    Foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_165() { - let original = r##"[foo]: /url ' -title -line1 -line2 -' - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_166() { - let original = r##"[foo]: /url 'title - -with blank line' - -[foo] -"##; - let expected = r##"

    [foo]: /url 'title

    -

    with blank line'

    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_167() { - let original = r##"[foo]: -/url - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_168() { - let original = r##"[foo]: - -[foo] -"##; - let expected = r##"

    [foo]:

    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_169() { - let original = r##"[foo]: <> - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_170() { - let original = r##"[foo]: (baz) - -[foo] -"##; - let expected = r##"

    [foo]: (baz)

    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_171() { - let original = r##"[foo]: /url\bar\*baz "foo\"bar\baz" - -[foo] -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_172() { - let original = r##"[foo] - -[foo]: url -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_173() { - let original = r##"[foo] - -[foo]: first -[foo]: second -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_174() { - let original = r##"[FOO]: /url - -[Foo] -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_175() { - let original = r##"[ΑΓΩ]: /φου - -[αγω] -"##; - let expected = r##"

    αγω

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_176() { - let original = r##"[foo]: /url -"##; - let expected = r##""##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_177() { - let original = r##"[ -foo -]: /url -bar -"##; - let expected = r##"

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_178() { - let original = r##"[foo]: /url "title" ok -"##; - let expected = r##"

    [foo]: /url "title" ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_179() { - let original = r##"[foo]: /url -"title" ok -"##; - let expected = r##"

    "title" ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_180() { - let original = r##" [foo]: /url "title" - -[foo] -"##; - let expected = r##"
    [foo]: /url "title"
    -
    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_181() { - let original = r##"``` -[foo]: /url -``` - -[foo] -"##; - let expected = r##"
    [foo]: /url
    -
    -

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_182() { - let original = r##"Foo -[bar]: /baz - -[bar] -"##; - let expected = r##"

    Foo -[bar]: /baz

    -

    [bar]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_183() { - let original = r##"# [Foo] -[foo]: /url -> bar -"##; - let expected = r##"

    Foo

    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_184() { - let original = r##"[foo]: /url -bar -=== -[foo] -"##; - let expected = r##"

    bar

    -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_185() { - let original = r##"[foo]: /url -=== -[foo] -"##; - let expected = r##"

    === -foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_186() { - let original = r##"[foo]: /foo-url "foo" -[bar]: /bar-url - "bar" -[baz]: /baz-url - -[foo], -[bar], -[baz] -"##; - let expected = r##"

    foo, -bar, -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_187() { - let original = r##"[foo] - -> [foo]: /url -"##; - let expected = r##"

    foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_188() { - let original = r##"[foo]: /url -"##; - let expected = r##""##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_189() { - let original = r##"aaa - -bbb -"##; - let expected = r##"

    aaa

    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_190() { - let original = r##"aaa -bbb - -ccc -ddd -"##; - let expected = r##"

    aaa -bbb

    -

    ccc -ddd

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_191() { - let original = r##"aaa - - -bbb -"##; - let expected = r##"

    aaa

    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_192() { - let original = r##" aaa - bbb -"##; - let expected = r##"

    aaa -bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_193() { - let original = r##"aaa - bbb - ccc -"##; - let expected = r##"

    aaa -bbb -ccc

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_194() { - let original = r##" aaa -bbb -"##; - let expected = r##"

    aaa -bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_195() { - let original = r##" aaa -bbb -"##; - let expected = r##"
    aaa
    -
    -

    bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_196() { - let original = r##"aaa -bbb -"##; - let expected = r##"

    aaa
    -bbb

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_197() { - let original = r##" - -aaa - - -# aaa - - -"##; - let expected = r##"

    aaa

    -

    aaa

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_198() { - let original = r##"> # Foo -> bar -> baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_199() { - let original = r##"># Foo ->bar -> baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_200() { - let original = r##" > # Foo - > bar - > baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_201() { - let original = r##" > # Foo - > bar - > baz -"##; - let expected = r##"
    > # Foo
    -> bar
    -> baz
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_202() { - let original = r##"> # Foo -> bar -baz -"##; - let expected = r##"
    -

    Foo

    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_203() { - let original = r##"> bar -baz -> foo -"##; - let expected = r##"
    -

    bar -baz -foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_204() { - let original = r##"> foo ---- -"##; - let expected = r##"
    -

    foo

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_205() { - let original = r##"> - foo -- bar -"##; - let expected = r##"
    -
      -
    • foo
    • -
    -
    -
      -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_206() { - let original = r##"> foo - bar -"##; - let expected = r##"
    -
    foo
    -
    -
    -
    bar
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_207() { - let original = r##"> ``` -foo -``` -"##; - let expected = r##"
    -
    -
    -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_208() { - let original = r##"> foo - - bar -"##; - let expected = r##"
    -

    foo -- bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_209() { - let original = r##"> -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_210() { - let original = r##"> -> -> -"##; - let expected = r##"
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_211() { - let original = r##"> -> foo -> -"##; - let expected = r##"
    -

    foo

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_212() { - let original = r##"> foo - -> bar -"##; - let expected = r##"
    -

    foo

    -
    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_213() { - let original = r##"> foo -> bar -"##; - let expected = r##"
    -

    foo -bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_214() { - let original = r##"> foo -> -> bar -"##; - let expected = r##"
    -

    foo

    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_215() { - let original = r##"foo -> bar -"##; - let expected = r##"

    foo

    -
    -

    bar

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_216() { - let original = r##"> aaa -*** -> bbb -"##; - let expected = r##"
    -

    aaa

    -
    -
    -
    -

    bbb

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_217() { - let original = r##"> bar -baz -"##; - let expected = r##"
    -

    bar -baz

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_218() { - let original = r##"> bar - -baz -"##; - let expected = r##"
    -

    bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_219() { - let original = r##"> bar -> -baz -"##; - let expected = r##"
    -

    bar

    -
    -

    baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_220() { - let original = r##"> > > foo -bar -"##; - let expected = r##"
    -
    -
    -

    foo -bar

    -
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_221() { - let original = r##">>> foo -> bar ->>baz -"##; - let expected = r##"
    -
    -
    -

    foo -bar -baz

    -
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_222() { - let original = r##"> code - -> not code -"##; - let expected = r##"
    -
    code
    -
    -
    -
    -

    not code

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_223() { - let original = r##"A paragraph -with two lines. - - indented code - -> A block quote. -"##; - let expected = r##"

    A paragraph -with two lines.

    -
    indented code
    -
    -
    -

    A block quote.

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_224() { - let original = r##"1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_225() { - let original = r##"- one - - two -"##; - let expected = r##"
      -
    • one
    • -
    -

    two

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_226() { - let original = r##"- one - - two -"##; - let expected = r##"
      -
    • -

      one

      -

      two

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_227() { - let original = r##" - one - - two -"##; - let expected = r##"
      -
    • one
    • -
    -
     two
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_228() { - let original = r##" - one - - two -"##; - let expected = r##"
      -
    • -

      one

      -

      two

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_229() { - let original = r##" > > 1. one ->> ->> two -"##; - let expected = r##"
    -
    -
      -
    1. -

      one

      -

      two

      -
    2. -
    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_230() { - let original = r##">>- one ->> - > > two -"##; - let expected = r##"
    -
    -
      -
    • one
    • -
    -

    two

    -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_231() { - let original = r##"-one - -2.two -"##; - let expected = r##"

    -one

    -

    2.two

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_232() { - let original = r##"- foo - - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_233() { - let original = r##"1. foo - - ``` - bar - ``` - - baz - - > bam -"##; - let expected = r##"
      -
    1. -

      foo

      -
      bar
      -
      -

      baz

      -
      -

      bam

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_234() { - let original = r##"- Foo - - bar - - - baz -"##; - let expected = r##"
      -
    • -

      Foo

      -
      bar
      -
      -
      -baz
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_235() { - let original = r##"123456789. ok -"##; - let expected = r##"
      -
    1. ok
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_236() { - let original = r##"1234567890. not ok -"##; - let expected = r##"

    1234567890. not ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_237() { - let original = r##"0. ok -"##; - let expected = r##"
      -
    1. ok
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_238() { - let original = r##"003. ok -"##; - let expected = r##"
      -
    1. ok
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_239() { - let original = r##"-1. not ok -"##; - let expected = r##"

    -1. not ok

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_240() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -
      bar
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_241() { - let original = r##" 10. foo - - bar -"##; - let expected = r##"
      -
    1. -

      foo

      -
      bar
      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_242() { - let original = r##" indented code - -paragraph - - more code -"##; - let expected = r##"
    indented code
    -
    -

    paragraph

    -
    more code
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_243() { - let original = r##"1. indented code - - paragraph - - more code -"##; - let expected = r##"
      -
    1. -
      indented code
      -
      -

      paragraph

      -
      more code
      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_244() { - let original = r##"1. indented code - - paragraph - - more code -"##; - let expected = r##"
      -
    1. -
       indented code
      -
      -

      paragraph

      -
      more code
      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_245() { - let original = r##" foo - -bar -"##; - let expected = r##"

    foo

    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_246() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • foo
    • -
    -

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_247() { - let original = r##"- foo - - bar -"##; - let expected = r##"
      -
    • -

      foo

      -

      bar

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_248() { - let original = r##"- - foo -- - ``` - bar - ``` -- - baz -"##; - let expected = r##"
      -
    • foo
    • -
    • -
      bar
      -
      -
    • -
    • -
      baz
      -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_249() { - let original = r##"- - foo -"##; - let expected = r##"
      -
    • foo
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_250() { - let original = r##"- - - foo -"##; - let expected = r##"
      -
    • -
    -

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_251() { - let original = r##"- foo -- -- bar -"##; - let expected = r##"
      -
    • foo
    • -
    • -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_252() { - let original = r##"- foo -- -- bar -"##; - let expected = r##"
      -
    • foo
    • -
    • -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_253() { - let original = r##"1. foo -2. -3. bar -"##; - let expected = r##"
      -
    1. foo
    2. -
    3. -
    4. bar
    5. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_254() { - let original = r##"* -"##; - let expected = r##"
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_255() { - let original = r##"foo -* - -foo -1. -"##; - let expected = r##"

    foo -*

    -

    foo -1.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_256() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_257() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_258() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_259() { - let original = r##" 1. A paragraph - with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
    1.  A paragraph
    -    with two lines.
    -
    -        indented code
    -
    -    > A block quote.
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_260() { - let original = r##" 1. A paragraph -with two lines. - - indented code - - > A block quote. -"##; - let expected = r##"
      -
    1. -

      A paragraph -with two lines.

      -
      indented code
      -
      -
      -

      A block quote.

      -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_261() { - let original = r##" 1. A paragraph - with two lines. -"##; - let expected = r##"
      -
    1. A paragraph -with two lines.
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_262() { - let original = r##"> 1. > Blockquote -continued here. -"##; - let expected = r##"
    -
      -
    1. -
      -

      Blockquote -continued here.

      -
      -
    2. -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_263() { - let original = r##"> 1. > Blockquote -> continued here. -"##; - let expected = r##"
    -
      -
    1. -
      -

      Blockquote -continued here.

      -
      -
    2. -
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_264() { - let original = r##"- foo - - bar - - baz - - boo -"##; - let expected = r##"
      -
    • foo -
        -
      • bar -
          -
        • baz -
            -
          • boo
          • -
          -
        • -
        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_265() { - let original = r##"- foo - - bar - - baz - - boo -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    • baz
    • -
    • boo
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_266() { - let original = r##"10) foo - - bar -"##; - let expected = r##"
      -
    1. foo -
        -
      • bar
      • -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_267() { - let original = r##"10) foo - - bar -"##; - let expected = r##"
      -
    1. foo
    2. -
    -
      -
    • bar
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_268() { - let original = r##"- - foo -"##; - let expected = r##"
      -
    • -
        -
      • foo
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_269() { - let original = r##"1. - 2. foo -"##; - let expected = r##"
      -
    1. -
        -
      • -
          -
        1. foo
        2. -
        -
      • -
      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_270() { - let original = r##"- # Foo -- Bar - --- - baz -"##; - let expected = r##"
      -
    • -

      Foo

      -
    • -
    • -

      Bar

      -baz
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_271() { - let original = r##"- foo -- bar -+ baz -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    -
      -
    • baz
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_272() { - let original = r##"1. foo -2. bar -3) baz -"##; - let expected = r##"
      -
    1. foo
    2. -
    3. bar
    4. -
    -
      -
    1. baz
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_273() { - let original = r##"Foo -- bar -- baz -"##; - let expected = r##"

    Foo

    -
      -
    • bar
    • -
    • baz
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_274() { - let original = r##"The number of windows in my house is -14. The number of doors is 6. -"##; - let expected = r##"

    The number of windows in my house is -14. The number of doors is 6.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_275() { - let original = r##"The number of windows in my house is -1. The number of doors is 6. -"##; - let expected = r##"

    The number of windows in my house is

    -
      -
    1. The number of doors is 6.
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_276() { - let original = r##"- foo - -- bar - - -- baz -"##; - let expected = r##"
      -
    • -

      foo

      -
    • -
    • -

      bar

      -
    • -
    • -

      baz

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_277() { - let original = r##"- foo - - bar - - baz - - - bim -"##; - let expected = r##"
      -
    • foo -
        -
      • bar -
          -
        • -

          baz

          -

          bim

          -
        • -
        -
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_278() { - let original = r##"- foo -- bar - - - -- baz -- bim -"##; - let expected = r##"
      -
    • foo
    • -
    • bar
    • -
    - -
      -
    • baz
    • -
    • bim
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_279() { - let original = r##"- foo - - notcode - -- foo - - - - code -"##; - let expected = r##"
      -
    • -

      foo

      -

      notcode

      -
    • -
    • -

      foo

      -
    • -
    - -
    code
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_280() { - let original = r##"- a - - b - - c - - d - - e - - f -- g -"##; - let expected = r##"
      -
    • a
    • -
    • b
    • -
    • c
    • -
    • d
    • -
    • e
    • -
    • f
    • -
    • g
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_281() { - let original = r##"1. a - - 2. b - - 3. c -"##; - let expected = r##"
      -
    1. -

      a

      -
    2. -
    3. -

      b

      -
    4. -
    5. -

      c

      -
    6. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_282() { - let original = r##"- a - - b - - c - - d - - e -"##; - let expected = r##"
      -
    • a
    • -
    • b
    • -
    • c
    • -
    • d -- e
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_283() { - let original = r##"1. a - - 2. b - - 3. c -"##; - let expected = r##"
      -
    1. -

      a

      -
    2. -
    3. -

      b

      -
    4. -
    -
    3. c
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_284() { - let original = r##"- a -- b - -- c -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -

      b

      -
    • -
    • -

      c

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_285() { - let original = r##"* a -* - -* c -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -
    • -

      c

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_286() { - let original = r##"- a -- b - - c -- d -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -

      b

      -

      c

      -
    • -
    • -

      d

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_287() { - let original = r##"- a -- b - - [ref]: /url -- d -"##; - let expected = r##"
      -
    • -

      a

      -
    • -
    • -

      b

      -
    • -
    • -

      d

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_288() { - let original = r##"- a -- ``` - b - - - ``` -- c -"##; - let expected = r##"
      -
    • a
    • -
    • -
      b
      -
      -
      -
      -
    • -
    • c
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_289() { - let original = r##"- a - - b - - c -- d -"##; - let expected = r##"
      -
    • a -
        -
      • -

        b

        -

        c

        -
      • -
      -
    • -
    • d
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_290() { - let original = r##"* a - > b - > -* c -"##; - let expected = r##"
      -
    • a -
      -

      b

      -
      -
    • -
    • c
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_291() { - let original = r##"- a - > b - ``` - c - ``` -- d -"##; - let expected = r##"
      -
    • a -
      -

      b

      -
      -
      c
      -
      -
    • -
    • d
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_292() { - let original = r##"- a -"##; - let expected = r##"
      -
    • a
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_293() { - let original = r##"- a - - b -"##; - let expected = r##"
      -
    • a -
        -
      • b
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_294() { - let original = r##"1. ``` - foo - ``` - - bar -"##; - let expected = r##"
      -
    1. -
      foo
      -
      -

      bar

      -
    2. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_295() { - let original = r##"* foo - * bar - - baz -"##; - let expected = r##"
      -
    • -

      foo

      -
        -
      • bar
      • -
      -

      baz

      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_296() { - let original = r##"- a - - b - - c - -- d - - e - - f -"##; - let expected = r##"
      -
    • -

      a

      -
        -
      • b
      • -
      • c
      • -
      -
    • -
    • -

      d

      -
        -
      • e
      • -
      • f
      • -
      -
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_297() { - let original = r##"`hi`lo` -"##; - let expected = r##"

    hilo`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_298() { - let original = r##"\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ -"##; - let expected = r##"

    !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_299() { - let original = r##"\ \A\a\ \3\φ\« -"##; - let expected = r##"

    \ \A\a\ \3\φ\«

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_300() { - let original = r##"\*not emphasized* -\
    not a tag -\[not a link](/foo) -\`not code` -1\. not a list -\* not a list -\# not a heading -\[foo]: /url "not a reference" -\ö not a character entity -"##; - let expected = r##"

    *not emphasized* -<br/> not a tag -[not a link](/foo) -`not code` -1. not a list -* not a list -# not a heading -[foo]: /url "not a reference" -&ouml; not a character entity

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_301() { - let original = r##"\\*emphasis* -"##; - let expected = r##"

    \emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_302() { - let original = r##"foo\ -bar -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_303() { - let original = r##"`` \[\` `` -"##; - let expected = r##"

    \[\`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_304() { - let original = r##" \[\] -"##; - let expected = r##"
    \[\]
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_305() { - let original = r##"~~~ -\[\] -~~~ -"##; - let expected = r##"
    \[\]
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_306() { - let original = r##" -"##; - let expected = r##"

    http://example.com?find=\*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_307() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_308() { - let original = r##"[foo](/bar\* "ti\*tle") -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_309() { - let original = r##"[foo] - -[foo]: /bar\* "ti\*tle" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_310() { - let original = r##"``` foo\+bar -foo -``` -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_311() { - let original = r##"  & © Æ Ď -¾ ℋ ⅆ -∲ ≧̸ -"##; - let expected = r##"

      & © Æ Ď -¾ ℋ ⅆ -∲ ≧̸

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_312() { - let original = r##"# Ӓ Ϡ � -"##; - let expected = r##"

    # Ӓ Ϡ �

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_313() { - let original = r##"" ആ ಫ -"##; - let expected = r##"

    " ആ ಫ

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_314() { - let original = r##"  &x; &#; &#x; -� -&#abcdef0; -&ThisIsNotDefined; &hi?; -"##; - let expected = r##"

    &nbsp &x; &#; &#x; -&#87654321; -&#abcdef0; -&ThisIsNotDefined; &hi?;

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_315() { - let original = r##"© -"##; - let expected = r##"

    &copy

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_316() { - let original = r##"&MadeUpEntity; -"##; - let expected = r##"

    &MadeUpEntity;

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_317() { - let original = r##" -"##; - let expected = r##" -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_318() { - let original = r##"[foo](/föö "föö") -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_319() { - let original = r##"[foo] - -[foo]: /föö "föö" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_320() { - let original = r##"``` föö -foo -``` -"##; - let expected = r##"
    foo
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_321() { - let original = r##"`föö` -"##; - let expected = r##"

    f&ouml;&ouml;

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_322() { - let original = r##" föfö -"##; - let expected = r##"
    f&ouml;f&ouml;
    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_323() { - let original = r##"*foo* -*foo* -"##; - let expected = r##"

    *foo* -foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_324() { - let original = r##"* foo - -* foo -"##; - let expected = r##"

    * foo

    -
      -
    • foo
    • -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_325() { - let original = r##"foo bar -"##; - let expected = r##"

    foo - -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_326() { - let original = r##" foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_327() { - let original = r##"[a](url "tit") -"##; - let expected = r##"

    [a](url "tit")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_328() { - let original = r##"`foo` -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_329() { - let original = r##"`` foo ` bar `` -"##; - let expected = r##"

    foo ` bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_330() { - let original = r##"` `` ` -"##; - let expected = r##"

    ``

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_331() { - let original = r##"` `` ` -"##; - let expected = r##"

    ``

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_332() { - let original = r##"` a` -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_333() { - let original = r##"` b ` -"##; - let expected = r##"

     b 

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_334() { - let original = r##"` ` -` ` -"##; - let expected = r##"

      -

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_335() { - let original = r##"`` -foo -bar -baz -`` -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_336() { - let original = r##"`` -foo -`` -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_337() { - let original = r##"`foo bar -baz` -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_338() { - let original = r##"`foo\`bar` -"##; - let expected = r##"

    foo\bar`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_339() { - let original = r##"``foo`bar`` -"##; - let expected = r##"

    foo`bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_340() { - let original = r##"` foo `` bar ` -"##; - let expected = r##"

    foo `` bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_341() { - let original = r##"*foo`*` -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_342() { - let original = r##"[not a `link](/foo`) -"##; - let expected = r##"

    [not a link](/foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_343() { - let original = r##"`` -"##; - let expected = r##"

    <a href="">`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_344() { - let original = r##"
    ` -"##; - let expected = r##"

    `

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_345() { - let original = r##"`` -"##; - let expected = r##"

    <http://foo.bar.baz>`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_346() { - let original = r##"` -"##; - let expected = r##"

    http://foo.bar.`baz`

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_347() { - let original = r##"```foo`` -"##; - let expected = r##"

    ```foo``

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_348() { - let original = r##"`foo -"##; - let expected = r##"

    `foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_349() { - let original = r##"`foo``bar`` -"##; - let expected = r##"

    `foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_350() { - let original = r##"*foo bar* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_351() { - let original = r##"a * foo bar* -"##; - let expected = r##"

    a * foo bar*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_352() { - let original = r##"a*"foo"* -"##; - let expected = r##"

    a*"foo"*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_353() { - let original = r##"* a * -"##; - let expected = r##"

    * a *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_354() { - let original = r##"foo*bar* -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_355() { - let original = r##"5*6*78 -"##; - let expected = r##"

    5678

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_356() { - let original = r##"_foo bar_ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_357() { - let original = r##"_ foo bar_ -"##; - let expected = r##"

    _ foo bar_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_358() { - let original = r##"a_"foo"_ -"##; - let expected = r##"

    a_"foo"_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_359() { - let original = r##"foo_bar_ -"##; - let expected = r##"

    foo_bar_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_360() { - let original = r##"5_6_78 -"##; - let expected = r##"

    5_6_78

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_361() { - let original = r##"пристаням_стремятся_ -"##; - let expected = r##"

    пристаням_стремятся_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_362() { - let original = r##"aa_"bb"_cc -"##; - let expected = r##"

    aa_"bb"_cc

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_363() { - let original = r##"foo-_(bar)_ -"##; - let expected = r##"

    foo-(bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_364() { - let original = r##"_foo* -"##; - let expected = r##"

    _foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_365() { - let original = r##"*foo bar * -"##; - let expected = r##"

    *foo bar *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_366() { - let original = r##"*foo bar -* -"##; - let expected = r##"

    *foo bar -*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_367() { - let original = r##"*(*foo) -"##; - let expected = r##"

    *(*foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_368() { - let original = r##"*(*foo*)* -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_369() { - let original = r##"*foo*bar -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_370() { - let original = r##"_foo bar _ -"##; - let expected = r##"

    _foo bar _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_371() { - let original = r##"_(_foo) -"##; - let expected = r##"

    _(_foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_372() { - let original = r##"_(_foo_)_ -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_373() { - let original = r##"_foo_bar -"##; - let expected = r##"

    _foo_bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_374() { - let original = r##"_пристаням_стремятся -"##; - let expected = r##"

    _пристаням_стремятся

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_375() { - let original = r##"_foo_bar_baz_ -"##; - let expected = r##"

    foo_bar_baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_376() { - let original = r##"_(bar)_. -"##; - let expected = r##"

    (bar).

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_377() { - let original = r##"**foo bar** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_378() { - let original = r##"** foo bar** -"##; - let expected = r##"

    ** foo bar**

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_379() { - let original = r##"a**"foo"** -"##; - let expected = r##"

    a**"foo"**

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_380() { - let original = r##"foo**bar** -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_381() { - let original = r##"__foo bar__ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_382() { - let original = r##"__ foo bar__ -"##; - let expected = r##"

    __ foo bar__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_383() { - let original = r##"__ -foo bar__ -"##; - let expected = r##"

    __ -foo bar__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_384() { - let original = r##"a__"foo"__ -"##; - let expected = r##"

    a__"foo"__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_385() { - let original = r##"foo__bar__ -"##; - let expected = r##"

    foo__bar__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_386() { - let original = r##"5__6__78 -"##; - let expected = r##"

    5__6__78

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_387() { - let original = r##"пристаням__стремятся__ -"##; - let expected = r##"

    пристаням__стремятся__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_388() { - let original = r##"__foo, __bar__, baz__ -"##; - let expected = r##"

    foo, bar, baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_389() { - let original = r##"foo-__(bar)__ -"##; - let expected = r##"

    foo-(bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_390() { - let original = r##"**foo bar ** -"##; - let expected = r##"

    **foo bar **

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_391() { - let original = r##"**(**foo) -"##; - let expected = r##"

    **(**foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_392() { - let original = r##"*(**foo**)* -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_393() { - let original = r##"**Gomphocarpus (*Gomphocarpus physocarpus*, syn. -*Asclepias physocarpa*)** -"##; - let expected = r##"

    Gomphocarpus (Gomphocarpus physocarpus, syn. -Asclepias physocarpa)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_394() { - let original = r##"**foo "*bar*" foo** -"##; - let expected = r##"

    foo "bar" foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_395() { - let original = r##"**foo**bar -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_396() { - let original = r##"__foo bar __ -"##; - let expected = r##"

    __foo bar __

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_397() { - let original = r##"__(__foo) -"##; - let expected = r##"

    __(__foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_398() { - let original = r##"_(__foo__)_ -"##; - let expected = r##"

    (foo)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_399() { - let original = r##"__foo__bar -"##; - let expected = r##"

    __foo__bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_400() { - let original = r##"__пристаням__стремятся -"##; - let expected = r##"

    __пристаням__стремятся

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_401() { - let original = r##"__foo__bar__baz__ -"##; - let expected = r##"

    foo__bar__baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_402() { - let original = r##"__(bar)__. -"##; - let expected = r##"

    (bar).

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_403() { - let original = r##"*foo [bar](/url)* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_404() { - let original = r##"*foo -bar* -"##; - let expected = r##"

    foo -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_405() { - let original = r##"_foo __bar__ baz_ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_406() { - let original = r##"_foo _bar_ baz_ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_407() { - let original = r##"__foo_ bar_ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_408() { - let original = r##"*foo *bar** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_409() { - let original = r##"*foo **bar** baz* -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_410() { - let original = r##"*foo**bar**baz* -"##; - let expected = r##"

    foobarbaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_411() { - let original = r##"*foo**bar* -"##; - let expected = r##"

    foo**bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_412() { - let original = r##"***foo** bar* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_413() { - let original = r##"*foo **bar*** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_414() { - let original = r##"*foo**bar*** -"##; - let expected = r##"

    foobar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_415() { - let original = r##"foo***bar***baz -"##; - let expected = r##"

    foobarbaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_416() { - let original = r##"foo******bar*********baz -"##; - let expected = r##"

    foobar***baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_417() { - let original = r##"*foo **bar *baz* bim** bop* -"##; - let expected = r##"

    foo bar baz bim bop

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_418() { - let original = r##"*foo [*bar*](/url)* -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_419() { - let original = r##"** is not an empty emphasis -"##; - let expected = r##"

    ** is not an empty emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_420() { - let original = r##"**** is not an empty strong emphasis -"##; - let expected = r##"

    **** is not an empty strong emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_421() { - let original = r##"**foo [bar](/url)** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_422() { - let original = r##"**foo -bar** -"##; - let expected = r##"

    foo -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_423() { - let original = r##"__foo _bar_ baz__ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_424() { - let original = r##"__foo __bar__ baz__ -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_425() { - let original = r##"____foo__ bar__ -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_426() { - let original = r##"**foo **bar**** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_427() { - let original = r##"**foo *bar* baz** -"##; - let expected = r##"

    foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_428() { - let original = r##"**foo*bar*baz** -"##; - let expected = r##"

    foobarbaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_429() { - let original = r##"***foo* bar** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_430() { - let original = r##"**foo *bar*** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_431() { - let original = r##"**foo *bar **baz** -bim* bop** -"##; - let expected = r##"

    foo bar baz -bim bop

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_432() { - let original = r##"**foo [*bar*](/url)** -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_433() { - let original = r##"__ is not an empty emphasis -"##; - let expected = r##"

    __ is not an empty emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_434() { - let original = r##"____ is not an empty strong emphasis -"##; - let expected = r##"

    ____ is not an empty strong emphasis

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_435() { - let original = r##"foo *** -"##; - let expected = r##"

    foo ***

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_436() { - let original = r##"foo *\** -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_437() { - let original = r##"foo *_* -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_438() { - let original = r##"foo ***** -"##; - let expected = r##"

    foo *****

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_439() { - let original = r##"foo **\*** -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_440() { - let original = r##"foo **_** -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_441() { - let original = r##"**foo* -"##; - let expected = r##"

    *foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_442() { - let original = r##"*foo** -"##; - let expected = r##"

    foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_443() { - let original = r##"***foo** -"##; - let expected = r##"

    *foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_444() { - let original = r##"****foo* -"##; - let expected = r##"

    ***foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_445() { - let original = r##"**foo*** -"##; - let expected = r##"

    foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_446() { - let original = r##"*foo**** -"##; - let expected = r##"

    foo***

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_447() { - let original = r##"foo ___ -"##; - let expected = r##"

    foo ___

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_448() { - let original = r##"foo _\__ -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_449() { - let original = r##"foo _*_ -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_450() { - let original = r##"foo _____ -"##; - let expected = r##"

    foo _____

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_451() { - let original = r##"foo __\___ -"##; - let expected = r##"

    foo _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_452() { - let original = r##"foo __*__ -"##; - let expected = r##"

    foo *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_453() { - let original = r##"__foo_ -"##; - let expected = r##"

    _foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_454() { - let original = r##"_foo__ -"##; - let expected = r##"

    foo_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_455() { - let original = r##"___foo__ -"##; - let expected = r##"

    _foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_456() { - let original = r##"____foo_ -"##; - let expected = r##"

    ___foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_457() { - let original = r##"__foo___ -"##; - let expected = r##"

    foo_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_458() { - let original = r##"_foo____ -"##; - let expected = r##"

    foo___

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_459() { - let original = r##"**foo** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_460() { - let original = r##"*_foo_* -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_461() { - let original = r##"__foo__ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_462() { - let original = r##"_*foo*_ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_463() { - let original = r##"****foo**** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_464() { - let original = r##"____foo____ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_465() { - let original = r##"******foo****** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_466() { - let original = r##"***foo*** -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_467() { - let original = r##"_____foo_____ -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_468() { - let original = r##"*foo _bar* baz_ -"##; - let expected = r##"

    foo _bar baz_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_469() { - let original = r##"*foo __bar *baz bim__ bam* -"##; - let expected = r##"

    foo bar *baz bim bam

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_470() { - let original = r##"**foo **bar baz** -"##; - let expected = r##"

    **foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_471() { - let original = r##"*foo *bar baz* -"##; - let expected = r##"

    *foo bar baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_472() { - let original = r##"*[bar*](/url) -"##; - let expected = r##"

    *bar*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_473() { - let original = r##"_foo [bar_](/url) -"##; - let expected = r##"

    _foo bar_

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_474() { - let original = r##"* -"##; - let expected = r##"

    *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_475() { - let original = r##"** -"##; - let expected = r##"

    **

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_476() { - let original = r##"__ -"##; - let expected = r##"

    __

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_477() { - let original = r##"*a `*`* -"##; - let expected = r##"

    a *

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_478() { - let original = r##"_a `_`_ -"##; - let expected = r##"

    a _

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_479() { - let original = r##"**a -"##; - let expected = r##"

    **ahttp://foo.bar/?q=**

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_480() { - let original = r##"__a -"##; - let expected = r##"

    __ahttp://foo.bar/?q=__

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_481() { - let original = r##"[link](/uri "title") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_482() { - let original = r##"[link](/uri) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_483() { - let original = r##"[link]() -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_484() { - let original = r##"[link](<>) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_485() { - let original = r##"[link](/my uri) -"##; - let expected = r##"

    [link](/my uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_486() { - let original = r##"[link](
    ) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_487() { - let original = r##"[link](foo -bar) -"##; - let expected = r##"

    [link](foo -bar)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_488() { - let original = r##"[link]() -"##; - let expected = r##"

    [link]()

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_489() { - let original = r##"[a]() -"##; - let expected = r##"

    a

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_490() { - let original = r##"[link]() -"##; - let expected = r##"

    [link](<foo>)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_491() { - let original = r##"[a]( -[a](c) -"##; - let expected = r##"

    [a](<b)c -[a](<b)c> -[a](c)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_492() { - let original = r##"[link](\(foo\)) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_493() { - let original = r##"[link](foo(and(bar))) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_494() { - let original = r##"[link](foo\(and\(bar\)) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_495() { - let original = r##"[link]() -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_496() { - let original = r##"[link](foo\)\:) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_497() { - let original = r##"[link](#fragment) - -[link](http://example.com#fragment) - -[link](http://example.com?foo=3#frag) -"##; - let expected = r##"

    link

    -

    link

    -

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_498() { - let original = r##"[link](foo\bar) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_499() { - let original = r##"[link](foo%20bä) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_500() { - let original = r##"[link]("title") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_501() { - let original = r##"[link](/url "title") -[link](/url 'title') -[link](/url (title)) -"##; - let expected = r##"

    link -link -link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_502() { - let original = r##"[link](/url "title \""") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_503() { - let original = r##"[link](/url "title") -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_504() { - let original = r##"[link](/url "title "and" title") -"##; - let expected = r##"

    [link](/url "title "and" title")

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_505() { - let original = r##"[link](/url 'title "and" title') -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_506() { - let original = r##"[link]( /uri - "title" ) -"##; - let expected = r##"

    link

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_507() { - let original = r##"[link] (/uri) -"##; - let expected = r##"

    [link] (/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_508() { - let original = r##"[link [foo [bar]]](/uri) -"##; - let expected = r##"

    link [foo [bar]]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_509() { - let original = r##"[link] bar](/uri) -"##; - let expected = r##"

    [link] bar](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_510() { - let original = r##"[link [bar](/uri) -"##; - let expected = r##"

    [link bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_511() { - let original = r##"[link \[bar](/uri) -"##; - let expected = r##"

    link [bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_512() { - let original = r##"[link *foo **bar** `#`*](/uri) -"##; - let expected = r##"

    link foo bar #

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_513() { - let original = r##"[![moon](moon.jpg)](/uri) -"##; - let expected = r##"

    moon

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_514() { - let original = r##"[foo [bar](/uri)](/uri) -"##; - let expected = r##"

    [foo bar](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_515() { - let original = r##"[foo *[bar [baz](/uri)](/uri)*](/uri) -"##; - let expected = r##"

    [foo [bar baz](/uri)](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_516() { - let original = r##"![[[foo](uri1)](uri2)](uri3) -"##; - let expected = r##"

    [foo](uri2)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_517() { - let original = r##"*[foo*](/uri) -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_518() { - let original = r##"[foo *bar](baz*) -"##; - let expected = r##"

    foo *bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_519() { - let original = r##"*foo [bar* baz] -"##; - let expected = r##"

    foo [bar baz]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_520() { - let original = r##"[foo -"##; - let expected = r##"

    [foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_521() { - let original = r##"[foo`](/uri)` -"##; - let expected = r##"

    [foo](/uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_522() { - let original = r##"[foo -"##; - let expected = r##"

    [foohttp://example.com/?search=](uri)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_523() { - let original = r##"[foo][bar] - -[bar]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_524() { - let original = r##"[link [foo [bar]]][ref] - -[ref]: /uri -"##; - let expected = r##"

    link [foo [bar]]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_525() { - let original = r##"[link \[bar][ref] - -[ref]: /uri -"##; - let expected = r##"

    link [bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_526() { - let original = r##"[link *foo **bar** `#`*][ref] - -[ref]: /uri -"##; - let expected = r##"

    link foo bar #

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_527() { - let original = r##"[![moon](moon.jpg)][ref] - -[ref]: /uri -"##; - let expected = r##"

    moon

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_528() { - let original = r##"[foo [bar](/uri)][ref] - -[ref]: /uri -"##; - let expected = r##"

    [foo bar]ref

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_529() { - let original = r##"[foo *bar [baz][ref]*][ref] - -[ref]: /uri -"##; - let expected = r##"

    [foo bar baz]ref

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_530() { - let original = r##"*[foo*][ref] - -[ref]: /uri -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_531() { - let original = r##"[foo *bar][ref] - -[ref]: /uri -"##; - let expected = r##"

    foo *bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_532() { - let original = r##"[foo - -[ref]: /uri -"##; - let expected = r##"

    [foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_533() { - let original = r##"[foo`][ref]` - -[ref]: /uri -"##; - let expected = r##"

    [foo][ref]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_534() { - let original = r##"[foo - -[ref]: /uri -"##; - let expected = r##"

    [foohttp://example.com/?search=][ref]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_535() { - let original = r##"[foo][BaR] - -[bar]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_536() { - let original = r##"[Толпой][Толпой] is a Russian word. - -[ТОЛПОЙ]: /url -"##; - let expected = r##"

    Толпой is a Russian word.

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_537() { - let original = r##"[Foo - bar]: /url - -[Baz][Foo bar] -"##; - let expected = r##"

    Baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_538() { - let original = r##"[foo] [bar] - -[bar]: /url "title" -"##; - let expected = r##"

    [foo] bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_539() { - let original = r##"[foo] -[bar] - -[bar]: /url "title" -"##; - let expected = r##"

    [foo] -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_540() { - let original = r##"[foo]: /url1 - -[foo]: /url2 - -[bar][foo] -"##; - let expected = r##"

    bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_541() { - let original = r##"[bar][foo\!] - -[foo!]: /url -"##; - let expected = r##"

    [bar][foo!]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_542() { - let original = r##"[foo][ref[] - -[ref[]: /uri -"##; - let expected = r##"

    [foo][ref[]

    -

    [ref[]: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_543() { - let original = r##"[foo][ref[bar]] - -[ref[bar]]: /uri -"##; - let expected = r##"

    [foo][ref[bar]]

    -

    [ref[bar]]: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_544() { - let original = r##"[[[foo]]] - -[[[foo]]]: /url -"##; - let expected = r##"

    [[[foo]]]

    -

    [[[foo]]]: /url

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_545() { - let original = r##"[foo][ref\[] - -[ref\[]: /uri -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_546() { - let original = r##"[bar\\]: /uri - -[bar\\] -"##; - let expected = r##"

    bar\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_547() { - let original = r##"[] - -[]: /uri -"##; - let expected = r##"

    []

    -

    []: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_548() { - let original = r##"[ - ] - -[ - ]: /uri -"##; - let expected = r##"

    [ -]

    -

    [ -]: /uri

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_549() { - let original = r##"[foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_550() { - let original = r##"[*foo* bar][] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_551() { - let original = r##"[Foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_552() { - let original = r##"[foo] -[] - -[foo]: /url "title" -"##; - let expected = r##"

    foo -[]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_553() { - let original = r##"[foo] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_554() { - let original = r##"[*foo* bar] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_555() { - let original = r##"[[*foo* bar]] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    [foo bar]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_556() { - let original = r##"[[bar [foo] - -[foo]: /url -"##; - let expected = r##"

    [[bar foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_557() { - let original = r##"[Foo] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_558() { - let original = r##"[foo] bar - -[foo]: /url -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_559() { - let original = r##"\[foo] - -[foo]: /url "title" -"##; - let expected = r##"

    [foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_560() { - let original = r##"[foo*]: /url - -*[foo*] -"##; - let expected = r##"

    *foo*

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_561() { - let original = r##"[foo][bar] - -[foo]: /url1 -[bar]: /url2 -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_562() { - let original = r##"[foo][] - -[foo]: /url1 -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_563() { - let original = r##"[foo]() - -[foo]: /url1 -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_564() { - let original = r##"[foo](not a link) - -[foo]: /url1 -"##; - let expected = r##"

    foo(not a link)

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_565() { - let original = r##"[foo][bar][baz] - -[baz]: /url -"##; - let expected = r##"

    [foo]bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_566() { - let original = r##"[foo][bar][baz] - -[baz]: /url1 -[bar]: /url2 -"##; - let expected = r##"

    foobaz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_567() { - let original = r##"[foo][bar][baz] - -[baz]: /url1 -[foo]: /url2 -"##; - let expected = r##"

    [foo]bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_568() { - let original = r##"![foo](/url "title") -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_569() { - let original = r##"![foo *bar*] - -[foo *bar*]: train.jpg "train & tracks" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_570() { - let original = r##"![foo ![bar](/url)](/url2) -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_571() { - let original = r##"![foo [bar](/url)](/url2) -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_572() { - let original = r##"![foo *bar*][] - -[foo *bar*]: train.jpg "train & tracks" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_573() { - let original = r##"![foo *bar*][foobar] - -[FOOBAR]: train.jpg "train & tracks" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_574() { - let original = r##"![foo](train.jpg) -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_575() { - let original = r##"My ![foo bar](/path/to/train.jpg "title" ) -"##; - let expected = r##"

    My foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_576() { - let original = r##"![foo]() -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_577() { - let original = r##"![](/url) -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_578() { - let original = r##"![foo][bar] - -[bar]: /url -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_579() { - let original = r##"![foo][bar] - -[BAR]: /url -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_580() { - let original = r##"![foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_581() { - let original = r##"![*foo* bar][] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_582() { - let original = r##"![Foo][] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_583() { - let original = r##"![foo] -[] - -[foo]: /url "title" -"##; - let expected = r##"

    foo -[]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_584() { - let original = r##"![foo] - -[foo]: /url "title" -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_585() { - let original = r##"![*foo* bar] - -[*foo* bar]: /url "title" -"##; - let expected = r##"

    foo bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_586() { - let original = r##"![[foo]] - -[[foo]]: /url "title" -"##; - let expected = r##"

    ![[foo]]

    -

    [[foo]]: /url "title"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_587() { - let original = r##"![Foo] - -[foo]: /url "title" -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_588() { - let original = r##"!\[foo] - -[foo]: /url "title" -"##; - let expected = r##"

    ![foo]

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_589() { - let original = r##"\![foo] - -[foo]: /url "title" -"##; - let expected = r##"

    !foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_590() { - let original = r##" -"##; - let expected = r##"

    http://foo.bar.baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_591() { - let original = r##" -"##; - let expected = r##"

    http://foo.bar.baz/test?q=hello&id=22&boolean

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_592() { - let original = r##" -"##; - let expected = r##"

    irc://foo.bar:2233/baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_593() { - let original = r##" -"##; - let expected = r##"

    MAILTO:FOO@BAR.BAZ

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_594() { - let original = r##" -"##; - let expected = r##"

    a+b+c:d

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_595() { - let original = r##" -"##; - let expected = r##"

    made-up-scheme://foo,bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_596() { - let original = r##" -"##; - let expected = r##"

    http://../

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_597() { - let original = r##" -"##; - let expected = r##"

    localhost:5001/foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_598() { - let original = r##" -"##; - let expected = r##"

    <http://foo.bar/baz bim>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_599() { - let original = r##" -"##; - let expected = r##"

    http://example.com/\[\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_600() { - let original = r##" -"##; - let expected = r##"

    foo@bar.example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_601() { - let original = r##" -"##; - let expected = r##"

    foo+special@Bar.baz-bar0.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_602() { - let original = r##" -"##; - let expected = r##"

    <foo+@bar.example.com>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_603() { - let original = r##"<> -"##; - let expected = r##"

    <>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_604() { - let original = r##"< http://foo.bar > -"##; - let expected = r##"

    < http://foo.bar >

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_605() { - let original = r##" -"##; - let expected = r##"

    <m:abc>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_606() { - let original = r##" -"##; - let expected = r##"

    <foo.bar.baz>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_607() { - let original = r##"http://example.com -"##; - let expected = r##"

    http://example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_608() { - let original = r##"foo@bar.example.com -"##; - let expected = r##"

    foo@bar.example.com

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_609() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_610() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_611() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_612() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_613() { - let original = r##"Foo -"##; - let expected = r##"

    Foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_614() { - let original = r##"<33> <__> -"##; - let expected = r##"

    <33> <__>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_615() { - let original = r##"
    -"##; - let expected = r##"

    <a h*#ref="hi">

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_616() { - let original = r##"
    <a href="hi'> <a href=hi'>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_617() { - let original = r##"< a>< -foo> - -"##; - let expected = r##"

    < a>< -foo><bar/ > -<foo bar=baz -bim!bop />

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_618() { - let original = r##"
    -"##; - let expected = r##"

    <a href='bar'title=title>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_619() { - let original = r##"
    -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_620() { - let original = r##" -"##; - let expected = r##"

    </a href="foo">

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_621() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_622() { - let original = r##"foo -"##; - let expected = r##"

    foo <!-- not a comment -- two hyphens -->

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_623() { - let original = r##"foo foo --> - -foo -"##; - let expected = r##"

    foo <!--> foo -->

    -

    foo <!-- foo--->

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_624() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_625() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_626() { - let original = r##"foo &<]]> -"##; - let expected = r##"

    foo &<]]>

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_627() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_628() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_629() { - let original = r##" -"##; - let expected = r##"

    <a href=""">

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_630() { - let original = r##"foo -baz -"##; - let expected = r##"

    foo
    -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_631() { - let original = r##"foo\ -baz -"##; - let expected = r##"

    foo
    -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_632() { - let original = r##"foo -baz -"##; - let expected = r##"

    foo
    -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_633() { - let original = r##"foo - bar -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_634() { - let original = r##"foo\ - bar -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_635() { - let original = r##"*foo -bar* -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_636() { - let original = r##"*foo\ -bar* -"##; - let expected = r##"

    foo
    -bar

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_637() { - let original = r##"`code -span` -"##; - let expected = r##"

    code span

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_638() { - let original = r##"`code\ -span` -"##; - let expected = r##"

    code\ span

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_639() { - let original = r##"
    -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_640() { - let original = r##" -"##; - let expected = r##"

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_641() { - let original = r##"foo\ -"##; - let expected = r##"

    foo\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_642() { - let original = r##"foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_643() { - let original = r##"### foo\ -"##; - let expected = r##"

    foo\

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_644() { - let original = r##"### foo -"##; - let expected = r##"

    foo

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_645() { - let original = r##"foo -baz -"##; - let expected = r##"

    foo -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_646() { - let original = r##"foo - baz -"##; - let expected = r##"

    foo -baz

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_647() { - let original = r##"hello $.;'there -"##; - let expected = r##"

    hello $.;'there

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_648() { - let original = r##"Foo χρῆν -"##; - let expected = r##"

    Foo χρῆν

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn spec_test_649() { - let original = r##"Multiple spaces -"##; - let expected = r##"

    Multiple spaces

    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn spec_test_1() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_2() { + let original = r##" foo baz bim +"##; + let expected = r##"
    foo	baz		bim
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_3() { + let original = r##" a a + ὐ a +"##; + let expected = r##"
    a	a
    +ὐ	a
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_4() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_5() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
        bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_6() { + let original = r##"> foo +"##; + let expected = r##"
    +
      foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_7() { + let original = r##"- foo +"##; + let expected = r##"
      +
    • +
        foo
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_8() { + let original = r##" foo + bar +"##; + let expected = r##"
    foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_9() { + let original = r##" - foo + - bar + - baz +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_10() { + let original = r##"# Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_11() { + let original = r##"* * * +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_12() { + let original = r##"- `one +- two` +"##; + let expected = r##"
      +
    • `one
    • +
    • two`
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_13() { + let original = r##"*** +--- +___ +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_14() { + let original = r##"+++ +"##; + let expected = r##"

    +++

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_15() { + let original = r##"=== +"##; + let expected = r##"

    ===

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_16() { + let original = r##"-- +** +__ +"##; + let expected = r##"

    -- +** +__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_17() { + let original = r##" *** + *** + *** +"##; + let expected = r##"
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_18() { + let original = r##" *** +"##; + let expected = r##"
    ***
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_19() { + let original = r##"Foo + *** +"##; + let expected = r##"

    Foo +***

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_20() { + let original = r##"_____________________________________ +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_21() { + let original = r##" - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_22() { + let original = r##" ** * ** * ** * ** +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_23() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_24() { + let original = r##"- - - - +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_25() { + let original = r##"_ _ _ _ a + +a------ + +---a--- +"##; + let expected = r##"

    _ _ _ _ a

    +

    a------

    +

    ---a---

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_26() { + let original = r##" *-* +"##; + let expected = r##"

    -

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_27() { + let original = r##"- foo +*** +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_28() { + let original = r##"Foo +*** +bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_29() { + let original = r##"Foo +--- +bar +"##; + let expected = r##"

    Foo

    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_30() { + let original = r##"* Foo +* * * +* Bar +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +
      +
    • Bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_31() { + let original = r##"- Foo +- * * * +"##; + let expected = r##"
      +
    • Foo
    • +
    • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_32() { + let original = r##"# foo +## foo +### foo +#### foo +##### foo +###### foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +

    foo

    +
    foo
    +
    foo
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_33() { + let original = r##"####### foo +"##; + let expected = r##"

    ####### foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_34() { + let original = r##"#5 bolt + +#hashtag +"##; + let expected = r##"

    #5 bolt

    +

    #hashtag

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_35() { + let original = r##"\## foo +"##; + let expected = r##"

    ## foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_36() { + let original = r##"# foo *bar* \*baz\* +"##; + let expected = r##"

    foo bar *baz*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_37() { + let original = r##"# foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_38() { + let original = r##" ### foo + ## foo + # foo +"##; + let expected = r##"

    foo

    +

    foo

    +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_39() { + let original = r##" # foo +"##; + let expected = r##"
    # foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_40() { + let original = r##"foo + # bar +"##; + let expected = r##"

    foo +# bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_41() { + let original = r##"## foo ## + ### bar ### +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_42() { + let original = r##"# foo ################################## +##### foo ## +"##; + let expected = r##"

    foo

    +
    foo
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_43() { + let original = r##"### foo ### +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_44() { + let original = r##"### foo ### b +"##; + let expected = r##"

    foo ### b

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_45() { + let original = r##"# foo# +"##; + let expected = r##"

    foo#

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_46() { + let original = r##"### foo \### +## foo #\## +# foo \# +"##; + let expected = r##"

    foo ###

    +

    foo ###

    +

    foo #

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_47() { + let original = r##"**** +## foo +**** +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_48() { + let original = r##"Foo bar +# baz +Bar foo +"##; + let expected = r##"

    Foo bar

    +

    baz

    +

    Bar foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_49() { + let original = r##"## +# +### ### +"##; + let expected = r##"

    +

    +

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_50() { + let original = r##"Foo *bar* +========= + +Foo *bar* +--------- +"##; + let expected = r##"

    Foo bar

    +

    Foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_51() { + let original = r##"Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_52() { + let original = r##" Foo *bar +baz* +==== +"##; + let expected = r##"

    Foo bar +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_53() { + let original = r##"Foo +------------------------- + +Foo += +"##; + let expected = r##"

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_54() { + let original = r##" Foo +--- + + Foo +----- + + Foo + === +"##; + let expected = r##"

    Foo

    +

    Foo

    +

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_55() { + let original = r##" Foo + --- + + Foo +--- +"##; + let expected = r##"
    Foo
    +---
    +
    +Foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_56() { + let original = r##"Foo + ---- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_57() { + let original = r##"Foo + --- +"##; + let expected = r##"

    Foo +---

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_58() { + let original = r##"Foo += = + +Foo +--- - +"##; + let expected = r##"

    Foo += =

    +

    Foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_59() { + let original = r##"Foo +----- +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_60() { + let original = r##"Foo\ +---- +"##; + let expected = r##"

    Foo\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_61() { + let original = r##"`Foo +---- +` + +
    +"##; + let expected = r##"

    `Foo

    +

    `

    +

    <a title="a lot

    +

    of dashes"/>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_62() { + let original = r##"> Foo +--- +"##; + let expected = r##"
    +

    Foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_63() { + let original = r##"> foo +bar +=== +"##; + let expected = r##"
    +

    foo +bar +===

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_64() { + let original = r##"- Foo +--- +"##; + let expected = r##"
      +
    • Foo
    • +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_65() { + let original = r##"Foo +Bar +--- +"##; + let expected = r##"

    Foo +Bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_66() { + let original = r##"--- +Foo +--- +Bar +--- +Baz +"##; + let expected = r##"
    +

    Foo

    +

    Bar

    +

    Baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_67() { + let original = r##" +==== +"##; + let expected = r##"

    ====

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_68() { + let original = r##"--- +--- +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_69() { + let original = r##"- foo +----- +"##; + let expected = r##"
      +
    • foo
    • +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_70() { + let original = r##" foo +--- +"##; + let expected = r##"
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_71() { + let original = r##"> foo +----- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_72() { + let original = r##"\> foo +------ +"##; + let expected = r##"

    > foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_73() { + let original = r##"Foo + +bar +--- +baz +"##; + let expected = r##"

    Foo

    +

    bar

    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_74() { + let original = r##"Foo +bar + +--- + +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_75() { + let original = r##"Foo +bar +* * * +baz +"##; + let expected = r##"

    Foo +bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_76() { + let original = r##"Foo +bar +\--- +baz +"##; + let expected = r##"

    Foo +bar +--- +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_77() { + let original = r##" a simple + indented code block +"##; + let expected = r##"
    a simple
    +  indented code block
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_78() { + let original = r##" - foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_79() { + let original = r##"1. foo + + - bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_80() { + let original = r##"
    + *hi* + + - one +"##; + let expected = r##"
    <a/>
    +*hi*
    +
    +- one
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_81() { + let original = r##" chunk1 + + chunk2 + + + + chunk3 +"##; + let expected = r##"
    chunk1
    +
    +chunk2
    +
    +
    +
    +chunk3
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_82() { + let original = r##" chunk1 + + chunk2 +"##; + let expected = r##"
    chunk1
    +  
    +  chunk2
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_83() { + let original = r##"Foo + bar + +"##; + let expected = r##"

    Foo +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_84() { + let original = r##" foo +bar +"##; + let expected = r##"
    foo
    +
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_85() { + let original = r##"# Heading + foo +Heading +------ + foo +---- +"##; + let expected = r##"

    Heading

    +
    foo
    +
    +

    Heading

    +
    foo
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_86() { + let original = r##" foo + bar +"##; + let expected = r##"
        foo
    +bar
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_87() { + let original = r##" + + foo + + +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_88() { + let original = r##" foo +"##; + let expected = r##"
    foo  
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_89() { + let original = r##"``` +< + > +``` +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_90() { + let original = r##"~~~ +< + > +~~~ +"##; + let expected = r##"
    <
    + >
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_91() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_92() { + let original = r##"``` +aaa +~~~ +``` +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_93() { + let original = r##"~~~ +aaa +``` +~~~ +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_94() { + let original = r##"```` +aaa +``` +`````` +"##; + let expected = r##"
    aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_95() { + let original = r##"~~~~ +aaa +~~~ +~~~~ +"##; + let expected = r##"
    aaa
    +~~~
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_96() { + let original = r##"``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_97() { + let original = r##"````` + +``` +aaa +"##; + let expected = r##"
    
    +```
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_98() { + let original = r##"> ``` +> aaa + +bbb +"##; + let expected = r##"
    +
    aaa
    +
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_99() { + let original = r##"``` + + +``` +"##; + let expected = r##"
    
    +  
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_100() { + let original = r##"``` +``` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_101() { + let original = r##" ``` + aaa +aaa +``` +"##; + let expected = r##"
    aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_102() { + let original = r##" ``` +aaa + aaa +aaa + ``` +"##; + let expected = r##"
    aaa
    +aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_103() { + let original = r##" ``` + aaa + aaa + aaa + ``` +"##; + let expected = r##"
    aaa
    + aaa
    +aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_104() { + let original = r##" ``` + aaa + ``` +"##; + let expected = r##"
    ```
    +aaa
    +```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_105() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_106() { + let original = r##" ``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_107() { + let original = r##"``` +aaa + ``` +"##; + let expected = r##"
    aaa
    +    ```
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_108() { + let original = r##"``` ``` +aaa +"##; + let expected = r##"

    +aaa

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_109() { + let original = r##"~~~~~~ +aaa +~~~ ~~ +"##; + let expected = r##"
    aaa
    +~~~ ~~
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_110() { + let original = r##"foo +``` +bar +``` +baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_111() { + let original = r##"foo +--- +~~~ +bar +~~~ +# baz +"##; + let expected = r##"

    foo

    +
    bar
    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_112() { + let original = r##"```ruby +def foo(x) + return 3 +end +``` +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_113() { + let original = r##"~~~~ ruby startline=3 $%@#$ +def foo(x) + return 3 +end +~~~~~~~ +"##; + let expected = r##"
    def foo(x)
    +  return 3
    +end
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_114() { + let original = r##"````; +```` +"##; + let expected = r##"
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_115() { + let original = r##"``` aa ``` +foo +"##; + let expected = r##"

    aa +foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_116() { + let original = r##"~~~ aa ``` ~~~ +foo +~~~ +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_117() { + let original = r##"``` +``` aaa +``` +"##; + let expected = r##"
    ``` aaa
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_118() { + let original = r##"
    +
    +**Hello**,
    +
    +_world_.
    +
    +
    +"##; + let expected = r##"
    +
    +**Hello**,
    +

    world. +

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_119() { + let original = r##" + + + +
    + hi +
    + +okay. +"##; + let expected = r##" + + + +
    + hi +
    +

    okay.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_120() { + let original = r##"
    +*foo* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_122() { + let original = r##"
    + +*Markdown* + +
    +"##; + let expected = r##"
    +

    Markdown

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_123() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_124() { + let original = r##"
    +
    +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_125() { + let original = r##"
    +*foo* + +*bar* +"##; + let expected = r##"
    +*foo* +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_126() { + let original = r##"
    +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_130() { + let original = r##"
    +foo +
    +"##; + let expected = r##"
    +foo +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_131() { + let original = r##"
    +``` c +int x = 33; +``` +"##; + let expected = r##"
    +``` c +int x = 33; +``` +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_132() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_133() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_134() { + let original = r##" +*bar* + +"##; + let expected = r##" +*bar* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_135() { + let original = r##" +*bar* +"##; + let expected = r##" +*bar* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_136() { + let original = r##" +*foo* + +"##; + let expected = r##" +*foo* + +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_137() { + let original = r##" + +*foo* + + +"##; + let expected = r##" +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_138() { + let original = r##"*foo* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_139() { + let original = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +okay +"##; + let expected = r##"
    
    +import Text.HTML.TagSoup
    +
    +main :: IO ()
    +main = print $ parseTags tags
    +
    +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_140() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_141() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_142() { + let original = r##" +*foo* +"##; + let expected = r##" +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_146() { + let original = r##"*bar* +*baz* +"##; + let expected = r##"*bar* +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_147() { + let original = r##"1. *bar* +"##; + let expected = r##"1. *bar* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_148() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_149() { + let original = r##"'; + +?> +okay +"##; + let expected = r##"'; + +?> +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_150() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_151() { + let original = r##" +okay +"##; + let expected = r##" +

    okay

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_152() { + let original = r##" + + +"##; + let expected = r##" +
    <!-- foo -->
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_153() { + let original = r##"
    + +
    +"##; + let expected = r##"
    +
    <div>
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_154() { + let original = r##"Foo +
    +bar +
    +"##; + let expected = r##"

    Foo

    +
    +bar +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_155() { + let original = r##"
    +bar +
    +*foo* +"##; + let expected = r##"
    +bar +
    +*foo* +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_156() { + let original = r##"Foo + +baz +"##; + let expected = r##"

    Foo + +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_157() { + let original = r##"
    + +*Emphasized* text. + +
    +"##; + let expected = r##"
    +

    Emphasized text.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_158() { + let original = r##"
    +*Emphasized* text. +
    +"##; + let expected = r##"
    +*Emphasized* text. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_159() { + let original = r##" + + + + + + + +
    +Hi +
    +"##; + let expected = r##" + + + +
    +Hi +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_160() { + let original = r##" + + + + + + + +
    + Hi +
    +"##; + let expected = r##" + +
    <td>
    +  Hi
    +</td>
    +
    + +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_161() { + let original = r##"[foo]: /url "title" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_162() { + let original = r##" [foo]: + /url + 'the title' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_163() { + let original = r##"[Foo*bar\]]:my_(url) 'title (with parens)' + +[Foo*bar\]] +"##; + let expected = r##"

    Foo*bar]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_164() { + let original = r##"[Foo bar]: + +'title' + +[Foo bar] +"##; + let expected = r##"

    Foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_165() { + let original = r##"[foo]: /url ' +title +line1 +line2 +' + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_166() { + let original = r##"[foo]: /url 'title + +with blank line' + +[foo] +"##; + let expected = r##"

    [foo]: /url 'title

    +

    with blank line'

    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_167() { + let original = r##"[foo]: +/url + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_168() { + let original = r##"[foo]: + +[foo] +"##; + let expected = r##"

    [foo]:

    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_169() { + let original = r##"[foo]: <> + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_170() { + let original = r##"[foo]: (baz) + +[foo] +"##; + let expected = r##"

    [foo]: (baz)

    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_171() { + let original = r##"[foo]: /url\bar\*baz "foo\"bar\baz" + +[foo] +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_172() { + let original = r##"[foo] + +[foo]: url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_173() { + let original = r##"[foo] + +[foo]: first +[foo]: second +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_174() { + let original = r##"[FOO]: /url + +[Foo] +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_175() { + let original = r##"[ΑΓΩ]: /φου + +[αγω] +"##; + let expected = r##"

    αγω

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_176() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_177() { + let original = r##"[ +foo +]: /url +bar +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_178() { + let original = r##"[foo]: /url "title" ok +"##; + let expected = r##"

    [foo]: /url "title" ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_179() { + let original = r##"[foo]: /url +"title" ok +"##; + let expected = r##"

    "title" ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_180() { + let original = r##" [foo]: /url "title" + +[foo] +"##; + let expected = r##"
    [foo]: /url "title"
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_181() { + let original = r##"``` +[foo]: /url +``` + +[foo] +"##; + let expected = r##"
    [foo]: /url
    +
    +

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_182() { + let original = r##"Foo +[bar]: /baz + +[bar] +"##; + let expected = r##"

    Foo +[bar]: /baz

    +

    [bar]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_183() { + let original = r##"# [Foo] +[foo]: /url +> bar +"##; + let expected = r##"

    Foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_184() { + let original = r##"[foo]: /url +bar +=== +[foo] +"##; + let expected = r##"

    bar

    +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_185() { + let original = r##"[foo]: /url +=== +[foo] +"##; + let expected = r##"

    === +foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_186() { + let original = r##"[foo]: /foo-url "foo" +[bar]: /bar-url + "bar" +[baz]: /baz-url + +[foo], +[bar], +[baz] +"##; + let expected = r##"

    foo, +bar, +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_187() { + let original = r##"[foo] + +> [foo]: /url +"##; + let expected = r##"

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_188() { + let original = r##"[foo]: /url +"##; + let expected = r##""##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_189() { + let original = r##"aaa + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_190() { + let original = r##"aaa +bbb + +ccc +ddd +"##; + let expected = r##"

    aaa +bbb

    +

    ccc +ddd

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_191() { + let original = r##"aaa + + +bbb +"##; + let expected = r##"

    aaa

    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_192() { + let original = r##" aaa + bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_193() { + let original = r##"aaa + bbb + ccc +"##; + let expected = r##"

    aaa +bbb +ccc

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_194() { + let original = r##" aaa +bbb +"##; + let expected = r##"

    aaa +bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_195() { + let original = r##" aaa +bbb +"##; + let expected = r##"
    aaa
    +
    +

    bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_196() { + let original = r##"aaa +bbb +"##; + let expected = r##"

    aaa
    +bbb

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_197() { + let original = r##" + +aaa + + +# aaa + + +"##; + let expected = r##"

    aaa

    +

    aaa

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_198() { + let original = r##"> # Foo +> bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_199() { + let original = r##"># Foo +>bar +> baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_200() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_201() { + let original = r##" > # Foo + > bar + > baz +"##; + let expected = r##"
    > # Foo
    +> bar
    +> baz
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_202() { + let original = r##"> # Foo +> bar +baz +"##; + let expected = r##"
    +

    Foo

    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_203() { + let original = r##"> bar +baz +> foo +"##; + let expected = r##"
    +

    bar +baz +foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_204() { + let original = r##"> foo +--- +"##; + let expected = r##"
    +

    foo

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_205() { + let original = r##"> - foo +- bar +"##; + let expected = r##"
    +
      +
    • foo
    • +
    +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_206() { + let original = r##"> foo + bar +"##; + let expected = r##"
    +
    foo
    +
    +
    +
    bar
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_207() { + let original = r##"> ``` +foo +``` +"##; + let expected = r##"
    +
    +
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_208() { + let original = r##"> foo + - bar +"##; + let expected = r##"
    +

    foo +- bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_209() { + let original = r##"> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_210() { + let original = r##"> +> +> +"##; + let expected = r##"
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_211() { + let original = r##"> +> foo +> +"##; + let expected = r##"
    +

    foo

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_212() { + let original = r##"> foo + +> bar +"##; + let expected = r##"
    +

    foo

    +
    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_213() { + let original = r##"> foo +> bar +"##; + let expected = r##"
    +

    foo +bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_214() { + let original = r##"> foo +> +> bar +"##; + let expected = r##"
    +

    foo

    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_215() { + let original = r##"foo +> bar +"##; + let expected = r##"

    foo

    +
    +

    bar

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_216() { + let original = r##"> aaa +*** +> bbb +"##; + let expected = r##"
    +

    aaa

    +
    +
    +
    +

    bbb

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_217() { + let original = r##"> bar +baz +"##; + let expected = r##"
    +

    bar +baz

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_218() { + let original = r##"> bar + +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_219() { + let original = r##"> bar +> +baz +"##; + let expected = r##"
    +

    bar

    +
    +

    baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_220() { + let original = r##"> > > foo +bar +"##; + let expected = r##"
    +
    +
    +

    foo +bar

    +
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_221() { + let original = r##">>> foo +> bar +>>baz +"##; + let expected = r##"
    +
    +
    +

    foo +bar +baz

    +
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_222() { + let original = r##"> code + +> not code +"##; + let expected = r##"
    +
    code
    +
    +
    +
    +

    not code

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_223() { + let original = r##"A paragraph +with two lines. + + indented code + +> A block quote. +"##; + let expected = r##"

    A paragraph +with two lines.

    +
    indented code
    +
    +
    +

    A block quote.

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_224() { + let original = r##"1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_225() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +

    two

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_226() { + let original = r##"- one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_227() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • one
    • +
    +
     two
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_228() { + let original = r##" - one + + two +"##; + let expected = r##"
      +
    • +

      one

      +

      two

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_229() { + let original = r##" > > 1. one +>> +>> two +"##; + let expected = r##"
    +
    +
      +
    1. +

      one

      +

      two

      +
    2. +
    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_230() { + let original = r##">>- one +>> + > > two +"##; + let expected = r##"
    +
    +
      +
    • one
    • +
    +

    two

    +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_231() { + let original = r##"-one + +2.two +"##; + let expected = r##"

    -one

    +

    2.two

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_232() { + let original = r##"- foo + + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_233() { + let original = r##"1. foo + + ``` + bar + ``` + + baz + + > bam +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +

      baz

      +
      +

      bam

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_234() { + let original = r##"- Foo + + bar + + + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
      bar
      +
      +
      +baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_235() { + let original = r##"123456789. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_236() { + let original = r##"1234567890. not ok +"##; + let expected = r##"

    1234567890. not ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_237() { + let original = r##"0. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_238() { + let original = r##"003. ok +"##; + let expected = r##"
      +
    1. ok
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_239() { + let original = r##"-1. not ok +"##; + let expected = r##"

    -1. not ok

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_240() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +
      bar
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_241() { + let original = r##" 10. foo + + bar +"##; + let expected = r##"
      +
    1. +

      foo

      +
      bar
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_242() { + let original = r##" indented code + +paragraph + + more code +"##; + let expected = r##"
    indented code
    +
    +

    paragraph

    +
    more code
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_243() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
      indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_244() { + let original = r##"1. indented code + + paragraph + + more code +"##; + let expected = r##"
      +
    1. +
       indented code
      +
      +

      paragraph

      +
      more code
      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_245() { + let original = r##" foo + +bar +"##; + let expected = r##"

    foo

    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_246() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • foo
    • +
    +

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_247() { + let original = r##"- foo + + bar +"##; + let expected = r##"
      +
    • +

      foo

      +

      bar

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_248() { + let original = r##"- + foo +- + ``` + bar + ``` +- + baz +"##; + let expected = r##"
      +
    • foo
    • +
    • +
      bar
      +
      +
    • +
    • +
      baz
      +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_249() { + let original = r##"- + foo +"##; + let expected = r##"
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_250() { + let original = r##"- + + foo +"##; + let expected = r##"
      +
    • +
    +

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_251() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_252() { + let original = r##"- foo +- +- bar +"##; + let expected = r##"
      +
    • foo
    • +
    • +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_253() { + let original = r##"1. foo +2. +3. bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. +
    4. bar
    5. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_254() { + let original = r##"* +"##; + let expected = r##"
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_255() { + let original = r##"foo +* + +foo +1. +"##; + let expected = r##"

    foo +*

    +

    foo +1.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_256() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_257() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_258() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_259() { + let original = r##" 1. A paragraph + with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
    1.  A paragraph
    +    with two lines.
    +
    +        indented code
    +
    +    > A block quote.
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_260() { + let original = r##" 1. A paragraph +with two lines. + + indented code + + > A block quote. +"##; + let expected = r##"
      +
    1. +

      A paragraph +with two lines.

      +
      indented code
      +
      +
      +

      A block quote.

      +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_261() { + let original = r##" 1. A paragraph + with two lines. +"##; + let expected = r##"
      +
    1. A paragraph +with two lines.
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_262() { + let original = r##"> 1. > Blockquote +continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_263() { + let original = r##"> 1. > Blockquote +> continued here. +"##; + let expected = r##"
    +
      +
    1. +
      +

      Blockquote +continued here.

      +
      +
    2. +
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_264() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • baz +
            +
          • boo
          • +
          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_265() { + let original = r##"- foo + - bar + - baz + - boo +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    • baz
    • +
    • boo
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_266() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo +
        +
      • bar
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_267() { + let original = r##"10) foo + - bar +"##; + let expected = r##"
      +
    1. foo
    2. +
    +
      +
    • bar
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_268() { + let original = r##"- - foo +"##; + let expected = r##"
      +
    • +
        +
      • foo
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_269() { + let original = r##"1. - 2. foo +"##; + let expected = r##"
      +
    1. +
        +
      • +
          +
        1. foo
        2. +
        +
      • +
      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_270() { + let original = r##"- # Foo +- Bar + --- + baz +"##; + let expected = r##"
      +
    • +

      Foo

      +
    • +
    • +

      Bar

      +baz
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_271() { + let original = r##"- foo +- bar ++ baz +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    +
      +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_272() { + let original = r##"1. foo +2. bar +3) baz +"##; + let expected = r##"
      +
    1. foo
    2. +
    3. bar
    4. +
    +
      +
    1. baz
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_273() { + let original = r##"Foo +- bar +- baz +"##; + let expected = r##"

    Foo

    +
      +
    • bar
    • +
    • baz
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_274() { + let original = r##"The number of windows in my house is +14. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is +14. The number of doors is 6.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_275() { + let original = r##"The number of windows in my house is +1. The number of doors is 6. +"##; + let expected = r##"

    The number of windows in my house is

    +
      +
    1. The number of doors is 6.
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_276() { + let original = r##"- foo + +- bar + + +- baz +"##; + let expected = r##"
      +
    • +

      foo

      +
    • +
    • +

      bar

      +
    • +
    • +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_277() { + let original = r##"- foo + - bar + - baz + + + bim +"##; + let expected = r##"
      +
    • foo +
        +
      • bar +
          +
        • +

          baz

          +

          bim

          +
        • +
        +
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_278() { + let original = r##"- foo +- bar + + + +- baz +- bim +"##; + let expected = r##"
      +
    • foo
    • +
    • bar
    • +
    + +
      +
    • baz
    • +
    • bim
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_279() { + let original = r##"- foo + + notcode + +- foo + + + + code +"##; + let expected = r##"
      +
    • +

      foo

      +

      notcode

      +
    • +
    • +

      foo

      +
    • +
    + +
    code
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_280() { + let original = r##"- a + - b + - c + - d + - e + - f +- g +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d
    • +
    • e
    • +
    • f
    • +
    • g
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_281() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    5. +

      c

      +
    6. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_282() { + let original = r##"- a + - b + - c + - d + - e +"##; + let expected = r##"
      +
    • a
    • +
    • b
    • +
    • c
    • +
    • d +- e
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_283() { + let original = r##"1. a + + 2. b + + 3. c +"##; + let expected = r##"
      +
    1. +

      a

      +
    2. +
    3. +

      b

      +
    4. +
    +
    3. c
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_284() { + let original = r##"- a +- b + +- c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_285() { + let original = r##"* a +* + +* c +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +
    • +

      c

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_286() { + let original = r##"- a +- b + + c +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +

      c

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_287() { + let original = r##"- a +- b + + [ref]: /url +- d +"##; + let expected = r##"
      +
    • +

      a

      +
    • +
    • +

      b

      +
    • +
    • +

      d

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_288() { + let original = r##"- a +- ``` + b + + + ``` +- c +"##; + let expected = r##"
      +
    • a
    • +
    • +
      b
      +
      +
      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_289() { + let original = r##"- a + - b + + c +- d +"##; + let expected = r##"
      +
    • a +
        +
      • +

        b

        +

        c

        +
      • +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_290() { + let original = r##"* a + > b + > +* c +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
    • +
    • c
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_291() { + let original = r##"- a + > b + ``` + c + ``` +- d +"##; + let expected = r##"
      +
    • a +
      +

      b

      +
      +
      c
      +
      +
    • +
    • d
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_292() { + let original = r##"- a +"##; + let expected = r##"
      +
    • a
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_293() { + let original = r##"- a + - b +"##; + let expected = r##"
      +
    • a +
        +
      • b
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_294() { + let original = r##"1. ``` + foo + ``` + + bar +"##; + let expected = r##"
      +
    1. +
      foo
      +
      +

      bar

      +
    2. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_295() { + let original = r##"* foo + * bar + + baz +"##; + let expected = r##"
      +
    • +

      foo

      +
        +
      • bar
      • +
      +

      baz

      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_296() { + let original = r##"- a + - b + - c + +- d + - e + - f +"##; + let expected = r##"
      +
    • +

      a

      +
        +
      • b
      • +
      • c
      • +
      +
    • +
    • +

      d

      +
        +
      • e
      • +
      • f
      • +
      +
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_297() { + let original = r##"`hi`lo` +"##; + let expected = r##"

    hilo`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_298() { + let original = r##"\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~ +"##; + let expected = r##"

    !"#$%&'()*+,-./:;<=>?@[\]^_`{|}~

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_299() { + let original = r##"\ \A\a\ \3\φ\« +"##; + let expected = r##"

    \ \A\a\ \3\φ\«

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_300() { + let original = r##"\*not emphasized* +\
    not a tag +\[not a link](/foo) +\`not code` +1\. not a list +\* not a list +\# not a heading +\[foo]: /url "not a reference" +\ö not a character entity +"##; + let expected = r##"

    *not emphasized* +<br/> not a tag +[not a link](/foo) +`not code` +1. not a list +* not a list +# not a heading +[foo]: /url "not a reference" +&ouml; not a character entity

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_301() { + let original = r##"\\*emphasis* +"##; + let expected = r##"

    \emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_302() { + let original = r##"foo\ +bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_303() { + let original = r##"`` \[\` `` +"##; + let expected = r##"

    \[\`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_304() { + let original = r##" \[\] +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_305() { + let original = r##"~~~ +\[\] +~~~ +"##; + let expected = r##"
    \[\]
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_306() { + let original = r##" +"##; + let expected = r##"

    http://example.com?find=\*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_307() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_308() { + let original = r##"[foo](/bar\* "ti\*tle") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_309() { + let original = r##"[foo] + +[foo]: /bar\* "ti\*tle" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_310() { + let original = r##"``` foo\+bar +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_311() { + let original = r##"  & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸ +"##; + let expected = r##"

      & © Æ Ď +¾ ℋ ⅆ +∲ ≧̸

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_312() { + let original = r##"# Ӓ Ϡ � +"##; + let expected = r##"

    # Ӓ Ϡ �

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_313() { + let original = r##"" ആ ಫ +"##; + let expected = r##"

    " ആ ಫ

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_314() { + let original = r##"  &x; &#; &#x; +� +&#abcdef0; +&ThisIsNotDefined; &hi?; +"##; + let expected = r##"

    &nbsp &x; &#; &#x; +&#87654321; +&#abcdef0; +&ThisIsNotDefined; &hi?;

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_315() { + let original = r##"© +"##; + let expected = r##"

    &copy

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_316() { + let original = r##"&MadeUpEntity; +"##; + let expected = r##"

    &MadeUpEntity;

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_317() { + let original = r##" +"##; + let expected = r##" +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_318() { + let original = r##"[foo](/föö "föö") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_319() { + let original = r##"[foo] + +[foo]: /föö "föö" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_320() { + let original = r##"``` föö +foo +``` +"##; + let expected = r##"
    foo
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_321() { + let original = r##"`föö` +"##; + let expected = r##"

    f&ouml;&ouml;

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_322() { + let original = r##" föfö +"##; + let expected = r##"
    f&ouml;f&ouml;
    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_323() { + let original = r##"*foo* +*foo* +"##; + let expected = r##"

    *foo* +foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_324() { + let original = r##"* foo + +* foo +"##; + let expected = r##"

    * foo

    +
      +
    • foo
    • +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_325() { + let original = r##"foo bar +"##; + let expected = r##"

    foo + +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_326() { + let original = r##" foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_327() { + let original = r##"[a](url "tit") +"##; + let expected = r##"

    [a](url "tit")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_328() { + let original = r##"`foo` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_329() { + let original = r##"`` foo ` bar `` +"##; + let expected = r##"

    foo ` bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_330() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_331() { + let original = r##"` `` ` +"##; + let expected = r##"

    ``

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_332() { + let original = r##"` a` +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_333() { + let original = r##"` b ` +"##; + let expected = r##"

     b 

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_334() { + let original = r##"` ` +` ` +"##; + let expected = r##"

      +

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_335() { + let original = r##"`` +foo +bar +baz +`` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_336() { + let original = r##"`` +foo +`` +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_337() { + let original = r##"`foo bar +baz` +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_338() { + let original = r##"`foo\`bar` +"##; + let expected = r##"

    foo\bar`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_339() { + let original = r##"``foo`bar`` +"##; + let expected = r##"

    foo`bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_340() { + let original = r##"` foo `` bar ` +"##; + let expected = r##"

    foo `` bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_341() { + let original = r##"*foo`*` +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_342() { + let original = r##"[not a `link](/foo`) +"##; + let expected = r##"

    [not a link](/foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_343() { + let original = r##"`` +"##; + let expected = r##"

    <a href="">`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_344() { + let original = r##"
    ` +"##; + let expected = r##"

    `

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_345() { + let original = r##"`` +"##; + let expected = r##"

    <http://foo.bar.baz>`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_346() { + let original = r##"` +"##; + let expected = r##"

    http://foo.bar.`baz`

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_347() { + let original = r##"```foo`` +"##; + let expected = r##"

    ```foo``

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_348() { + let original = r##"`foo +"##; + let expected = r##"

    `foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_349() { + let original = r##"`foo``bar`` +"##; + let expected = r##"

    `foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_350() { + let original = r##"*foo bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_351() { + let original = r##"a * foo bar* +"##; + let expected = r##"

    a * foo bar*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_352() { + let original = r##"a*"foo"* +"##; + let expected = r##"

    a*"foo"*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_353() { + let original = r##"* a * +"##; + let expected = r##"

    * a *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_354() { + let original = r##"foo*bar* +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_355() { + let original = r##"5*6*78 +"##; + let expected = r##"

    5678

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_356() { + let original = r##"_foo bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_357() { + let original = r##"_ foo bar_ +"##; + let expected = r##"

    _ foo bar_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_358() { + let original = r##"a_"foo"_ +"##; + let expected = r##"

    a_"foo"_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_359() { + let original = r##"foo_bar_ +"##; + let expected = r##"

    foo_bar_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_360() { + let original = r##"5_6_78 +"##; + let expected = r##"

    5_6_78

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_361() { + let original = r##"пристаням_стремятся_ +"##; + let expected = r##"

    пристаням_стремятся_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_362() { + let original = r##"aa_"bb"_cc +"##; + let expected = r##"

    aa_"bb"_cc

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_363() { + let original = r##"foo-_(bar)_ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_364() { + let original = r##"_foo* +"##; + let expected = r##"

    _foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_365() { + let original = r##"*foo bar * +"##; + let expected = r##"

    *foo bar *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_366() { + let original = r##"*foo bar +* +"##; + let expected = r##"

    *foo bar +*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_367() { + let original = r##"*(*foo) +"##; + let expected = r##"

    *(*foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_368() { + let original = r##"*(*foo*)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_369() { + let original = r##"*foo*bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_370() { + let original = r##"_foo bar _ +"##; + let expected = r##"

    _foo bar _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_371() { + let original = r##"_(_foo) +"##; + let expected = r##"

    _(_foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_372() { + let original = r##"_(_foo_)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_373() { + let original = r##"_foo_bar +"##; + let expected = r##"

    _foo_bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_374() { + let original = r##"_пристаням_стремятся +"##; + let expected = r##"

    _пристаням_стремятся

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_375() { + let original = r##"_foo_bar_baz_ +"##; + let expected = r##"

    foo_bar_baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_376() { + let original = r##"_(bar)_. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_377() { + let original = r##"**foo bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_378() { + let original = r##"** foo bar** +"##; + let expected = r##"

    ** foo bar**

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_379() { + let original = r##"a**"foo"** +"##; + let expected = r##"

    a**"foo"**

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_380() { + let original = r##"foo**bar** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_381() { + let original = r##"__foo bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_382() { + let original = r##"__ foo bar__ +"##; + let expected = r##"

    __ foo bar__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_383() { + let original = r##"__ +foo bar__ +"##; + let expected = r##"

    __ +foo bar__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_384() { + let original = r##"a__"foo"__ +"##; + let expected = r##"

    a__"foo"__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_385() { + let original = r##"foo__bar__ +"##; + let expected = r##"

    foo__bar__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_386() { + let original = r##"5__6__78 +"##; + let expected = r##"

    5__6__78

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_387() { + let original = r##"пристаням__стремятся__ +"##; + let expected = r##"

    пристаням__стремятся__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_388() { + let original = r##"__foo, __bar__, baz__ +"##; + let expected = r##"

    foo, bar, baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_389() { + let original = r##"foo-__(bar)__ +"##; + let expected = r##"

    foo-(bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_390() { + let original = r##"**foo bar ** +"##; + let expected = r##"

    **foo bar **

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_391() { + let original = r##"**(**foo) +"##; + let expected = r##"

    **(**foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_392() { + let original = r##"*(**foo**)* +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_393() { + let original = r##"**Gomphocarpus (*Gomphocarpus physocarpus*, syn. +*Asclepias physocarpa*)** +"##; + let expected = r##"

    Gomphocarpus (Gomphocarpus physocarpus, syn. +Asclepias physocarpa)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_394() { + let original = r##"**foo "*bar*" foo** +"##; + let expected = r##"

    foo "bar" foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_395() { + let original = r##"**foo**bar +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_396() { + let original = r##"__foo bar __ +"##; + let expected = r##"

    __foo bar __

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_397() { + let original = r##"__(__foo) +"##; + let expected = r##"

    __(__foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_398() { + let original = r##"_(__foo__)_ +"##; + let expected = r##"

    (foo)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_399() { + let original = r##"__foo__bar +"##; + let expected = r##"

    __foo__bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_400() { + let original = r##"__пристаням__стремятся +"##; + let expected = r##"

    __пристаням__стремятся

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_401() { + let original = r##"__foo__bar__baz__ +"##; + let expected = r##"

    foo__bar__baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_402() { + let original = r##"__(bar)__. +"##; + let expected = r##"

    (bar).

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_403() { + let original = r##"*foo [bar](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_404() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_405() { + let original = r##"_foo __bar__ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_406() { + let original = r##"_foo _bar_ baz_ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_407() { + let original = r##"__foo_ bar_ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_408() { + let original = r##"*foo *bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_409() { + let original = r##"*foo **bar** baz* +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_410() { + let original = r##"*foo**bar**baz* +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_411() { + let original = r##"*foo**bar* +"##; + let expected = r##"

    foo**bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_412() { + let original = r##"***foo** bar* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_413() { + let original = r##"*foo **bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_414() { + let original = r##"*foo**bar*** +"##; + let expected = r##"

    foobar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_415() { + let original = r##"foo***bar***baz +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_416() { + let original = r##"foo******bar*********baz +"##; + let expected = r##"

    foobar***baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_417() { + let original = r##"*foo **bar *baz* bim** bop* +"##; + let expected = r##"

    foo bar baz bim bop

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_418() { + let original = r##"*foo [*bar*](/url)* +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_419() { + let original = r##"** is not an empty emphasis +"##; + let expected = r##"

    ** is not an empty emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_420() { + let original = r##"**** is not an empty strong emphasis +"##; + let expected = r##"

    **** is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_421() { + let original = r##"**foo [bar](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_422() { + let original = r##"**foo +bar** +"##; + let expected = r##"

    foo +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_423() { + let original = r##"__foo _bar_ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_424() { + let original = r##"__foo __bar__ baz__ +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_425() { + let original = r##"____foo__ bar__ +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_426() { + let original = r##"**foo **bar**** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_427() { + let original = r##"**foo *bar* baz** +"##; + let expected = r##"

    foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_428() { + let original = r##"**foo*bar*baz** +"##; + let expected = r##"

    foobarbaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_429() { + let original = r##"***foo* bar** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_430() { + let original = r##"**foo *bar*** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_431() { + let original = r##"**foo *bar **baz** +bim* bop** +"##; + let expected = r##"

    foo bar baz +bim bop

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_432() { + let original = r##"**foo [*bar*](/url)** +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_433() { + let original = r##"__ is not an empty emphasis +"##; + let expected = r##"

    __ is not an empty emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_434() { + let original = r##"____ is not an empty strong emphasis +"##; + let expected = r##"

    ____ is not an empty strong emphasis

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_435() { + let original = r##"foo *** +"##; + let expected = r##"

    foo ***

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_436() { + let original = r##"foo *\** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_437() { + let original = r##"foo *_* +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_438() { + let original = r##"foo ***** +"##; + let expected = r##"

    foo *****

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_439() { + let original = r##"foo **\*** +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_440() { + let original = r##"foo **_** +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_441() { + let original = r##"**foo* +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_442() { + let original = r##"*foo** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_443() { + let original = r##"***foo** +"##; + let expected = r##"

    *foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_444() { + let original = r##"****foo* +"##; + let expected = r##"

    ***foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_445() { + let original = r##"**foo*** +"##; + let expected = r##"

    foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_446() { + let original = r##"*foo**** +"##; + let expected = r##"

    foo***

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_447() { + let original = r##"foo ___ +"##; + let expected = r##"

    foo ___

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_448() { + let original = r##"foo _\__ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_449() { + let original = r##"foo _*_ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_450() { + let original = r##"foo _____ +"##; + let expected = r##"

    foo _____

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_451() { + let original = r##"foo __\___ +"##; + let expected = r##"

    foo _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_452() { + let original = r##"foo __*__ +"##; + let expected = r##"

    foo *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_453() { + let original = r##"__foo_ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_454() { + let original = r##"_foo__ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_455() { + let original = r##"___foo__ +"##; + let expected = r##"

    _foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_456() { + let original = r##"____foo_ +"##; + let expected = r##"

    ___foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_457() { + let original = r##"__foo___ +"##; + let expected = r##"

    foo_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_458() { + let original = r##"_foo____ +"##; + let expected = r##"

    foo___

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_459() { + let original = r##"**foo** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_460() { + let original = r##"*_foo_* +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_461() { + let original = r##"__foo__ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_462() { + let original = r##"_*foo*_ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_463() { + let original = r##"****foo**** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_464() { + let original = r##"____foo____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_465() { + let original = r##"******foo****** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_466() { + let original = r##"***foo*** +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_467() { + let original = r##"_____foo_____ +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_468() { + let original = r##"*foo _bar* baz_ +"##; + let expected = r##"

    foo _bar baz_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_469() { + let original = r##"*foo __bar *baz bim__ bam* +"##; + let expected = r##"

    foo bar *baz bim bam

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_470() { + let original = r##"**foo **bar baz** +"##; + let expected = r##"

    **foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_471() { + let original = r##"*foo *bar baz* +"##; + let expected = r##"

    *foo bar baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_472() { + let original = r##"*[bar*](/url) +"##; + let expected = r##"

    *bar*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_473() { + let original = r##"_foo [bar_](/url) +"##; + let expected = r##"

    _foo bar_

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_474() { + let original = r##"* +"##; + let expected = r##"

    *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_475() { + let original = r##"** +"##; + let expected = r##"

    **

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_476() { + let original = r##"__ +"##; + let expected = r##"

    __

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_477() { + let original = r##"*a `*`* +"##; + let expected = r##"

    a *

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_478() { + let original = r##"_a `_`_ +"##; + let expected = r##"

    a _

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_479() { + let original = r##"**a +"##; + let expected = r##"

    **ahttp://foo.bar/?q=**

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_480() { + let original = r##"__a +"##; + let expected = r##"

    __ahttp://foo.bar/?q=__

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_481() { + let original = r##"[link](/uri "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_482() { + let original = r##"[link](/uri) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_483() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_484() { + let original = r##"[link](<>) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_485() { + let original = r##"[link](/my uri) +"##; + let expected = r##"

    [link](/my uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_486() { + let original = r##"[link](
    ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_487() { + let original = r##"[link](foo +bar) +"##; + let expected = r##"

    [link](foo +bar)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_488() { + let original = r##"[link]() +"##; + let expected = r##"

    [link]()

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_489() { + let original = r##"[a]() +"##; + let expected = r##"

    a

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_490() { + let original = r##"[link]() +"##; + let expected = r##"

    [link](<foo>)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_491() { + let original = r##"[a]( +[a](c) +"##; + let expected = r##"

    [a](<b)c +[a](<b)c> +[a](c)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_492() { + let original = r##"[link](\(foo\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_493() { + let original = r##"[link](foo(and(bar))) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_494() { + let original = r##"[link](foo\(and\(bar\)) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_495() { + let original = r##"[link]() +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_496() { + let original = r##"[link](foo\)\:) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_497() { + let original = r##"[link](#fragment) + +[link](http://example.com#fragment) + +[link](http://example.com?foo=3#frag) +"##; + let expected = r##"

    link

    +

    link

    +

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_498() { + let original = r##"[link](foo\bar) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_499() { + let original = r##"[link](foo%20bä) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_500() { + let original = r##"[link]("title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_501() { + let original = r##"[link](/url "title") +[link](/url 'title') +[link](/url (title)) +"##; + let expected = r##"

    link +link +link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_502() { + let original = r##"[link](/url "title \""") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_503() { + let original = r##"[link](/url "title") +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_504() { + let original = r##"[link](/url "title "and" title") +"##; + let expected = r##"

    [link](/url "title "and" title")

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_505() { + let original = r##"[link](/url 'title "and" title') +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_506() { + let original = r##"[link]( /uri + "title" ) +"##; + let expected = r##"

    link

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_507() { + let original = r##"[link] (/uri) +"##; + let expected = r##"

    [link] (/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_508() { + let original = r##"[link [foo [bar]]](/uri) +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_509() { + let original = r##"[link] bar](/uri) +"##; + let expected = r##"

    [link] bar](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_510() { + let original = r##"[link [bar](/uri) +"##; + let expected = r##"

    [link bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_511() { + let original = r##"[link \[bar](/uri) +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_512() { + let original = r##"[link *foo **bar** `#`*](/uri) +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_513() { + let original = r##"[![moon](moon.jpg)](/uri) +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_514() { + let original = r##"[foo [bar](/uri)](/uri) +"##; + let expected = r##"

    [foo bar](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_515() { + let original = r##"[foo *[bar [baz](/uri)](/uri)*](/uri) +"##; + let expected = r##"

    [foo [bar baz](/uri)](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_516() { + let original = r##"![[[foo](uri1)](uri2)](uri3) +"##; + let expected = r##"

    [foo](uri2)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_517() { + let original = r##"*[foo*](/uri) +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_518() { + let original = r##"[foo *bar](baz*) +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_519() { + let original = r##"*foo [bar* baz] +"##; + let expected = r##"

    foo [bar baz]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_520() { + let original = r##"[foo +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_521() { + let original = r##"[foo`](/uri)` +"##; + let expected = r##"

    [foo](/uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_522() { + let original = r##"[foo +"##; + let expected = r##"

    [foohttp://example.com/?search=](uri)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_523() { + let original = r##"[foo][bar] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_524() { + let original = r##"[link [foo [bar]]][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [foo [bar]]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_525() { + let original = r##"[link \[bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    link [bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_526() { + let original = r##"[link *foo **bar** `#`*][ref] + +[ref]: /uri +"##; + let expected = r##"

    link foo bar #

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_527() { + let original = r##"[![moon](moon.jpg)][ref] + +[ref]: /uri +"##; + let expected = r##"

    moon

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_528() { + let original = r##"[foo [bar](/uri)][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar]ref

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_529() { + let original = r##"[foo *bar [baz][ref]*][ref] + +[ref]: /uri +"##; + let expected = r##"

    [foo bar baz]ref

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_530() { + let original = r##"*[foo*][ref] + +[ref]: /uri +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_531() { + let original = r##"[foo *bar][ref] + +[ref]: /uri +"##; + let expected = r##"

    foo *bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_532() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_533() { + let original = r##"[foo`][ref]` + +[ref]: /uri +"##; + let expected = r##"

    [foo][ref]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_534() { + let original = r##"[foo + +[ref]: /uri +"##; + let expected = r##"

    [foohttp://example.com/?search=][ref]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_535() { + let original = r##"[foo][BaR] + +[bar]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_536() { + let original = r##"[Толпой][Толпой] is a Russian word. + +[ТОЛПОЙ]: /url +"##; + let expected = r##"

    Толпой is a Russian word.

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_537() { + let original = r##"[Foo + bar]: /url + +[Baz][Foo bar] +"##; + let expected = r##"

    Baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_538() { + let original = r##"[foo] [bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_539() { + let original = r##"[foo] +[bar] + +[bar]: /url "title" +"##; + let expected = r##"

    [foo] +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_540() { + let original = r##"[foo]: /url1 + +[foo]: /url2 + +[bar][foo] +"##; + let expected = r##"

    bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_541() { + let original = r##"[bar][foo\!] + +[foo!]: /url +"##; + let expected = r##"

    [bar][foo!]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_542() { + let original = r##"[foo][ref[] + +[ref[]: /uri +"##; + let expected = r##"

    [foo][ref[]

    +

    [ref[]: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_543() { + let original = r##"[foo][ref[bar]] + +[ref[bar]]: /uri +"##; + let expected = r##"

    [foo][ref[bar]]

    +

    [ref[bar]]: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_544() { + let original = r##"[[[foo]]] + +[[[foo]]]: /url +"##; + let expected = r##"

    [[[foo]]]

    +

    [[[foo]]]: /url

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_545() { + let original = r##"[foo][ref\[] + +[ref\[]: /uri +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_546() { + let original = r##"[bar\\]: /uri + +[bar\\] +"##; + let expected = r##"

    bar\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_547() { + let original = r##"[] + +[]: /uri +"##; + let expected = r##"

    []

    +

    []: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_548() { + let original = r##"[ + ] + +[ + ]: /uri +"##; + let expected = r##"

    [ +]

    +

    [ +]: /uri

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_549() { + let original = r##"[foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_550() { + let original = r##"[*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_551() { + let original = r##"[Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_552() { + let original = r##"[foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_553() { + let original = r##"[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_554() { + let original = r##"[*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_555() { + let original = r##"[[*foo* bar]] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    [foo bar]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_556() { + let original = r##"[[bar [foo] + +[foo]: /url +"##; + let expected = r##"

    [[bar foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_557() { + let original = r##"[Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_558() { + let original = r##"[foo] bar + +[foo]: /url +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_559() { + let original = r##"\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    [foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_560() { + let original = r##"[foo*]: /url + +*[foo*] +"##; + let expected = r##"

    *foo*

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_561() { + let original = r##"[foo][bar] + +[foo]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_562() { + let original = r##"[foo][] + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_563() { + let original = r##"[foo]() + +[foo]: /url1 +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_564() { + let original = r##"[foo](not a link) + +[foo]: /url1 +"##; + let expected = r##"

    foo(not a link)

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_565() { + let original = r##"[foo][bar][baz] + +[baz]: /url +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_566() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[bar]: /url2 +"##; + let expected = r##"

    foobaz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_567() { + let original = r##"[foo][bar][baz] + +[baz]: /url1 +[foo]: /url2 +"##; + let expected = r##"

    [foo]bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_568() { + let original = r##"![foo](/url "title") +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_569() { + let original = r##"![foo *bar*] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_570() { + let original = r##"![foo ![bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_571() { + let original = r##"![foo [bar](/url)](/url2) +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_572() { + let original = r##"![foo *bar*][] + +[foo *bar*]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_573() { + let original = r##"![foo *bar*][foobar] + +[FOOBAR]: train.jpg "train & tracks" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_574() { + let original = r##"![foo](train.jpg) +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_575() { + let original = r##"My ![foo bar](/path/to/train.jpg "title" ) +"##; + let expected = r##"

    My foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_576() { + let original = r##"![foo]() +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_577() { + let original = r##"![](/url) +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_578() { + let original = r##"![foo][bar] + +[bar]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_579() { + let original = r##"![foo][bar] + +[BAR]: /url +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_580() { + let original = r##"![foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_581() { + let original = r##"![*foo* bar][] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_582() { + let original = r##"![Foo][] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_583() { + let original = r##"![foo] +[] + +[foo]: /url "title" +"##; + let expected = r##"

    foo +[]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_584() { + let original = r##"![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_585() { + let original = r##"![*foo* bar] + +[*foo* bar]: /url "title" +"##; + let expected = r##"

    foo bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_586() { + let original = r##"![[foo]] + +[[foo]]: /url "title" +"##; + let expected = r##"

    ![[foo]]

    +

    [[foo]]: /url "title"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_587() { + let original = r##"![Foo] + +[foo]: /url "title" +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_588() { + let original = r##"!\[foo] + +[foo]: /url "title" +"##; + let expected = r##"

    ![foo]

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_589() { + let original = r##"\![foo] + +[foo]: /url "title" +"##; + let expected = r##"

    !foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_590() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_591() { + let original = r##" +"##; + let expected = r##"

    http://foo.bar.baz/test?q=hello&id=22&boolean

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_592() { + let original = r##" +"##; + let expected = r##"

    irc://foo.bar:2233/baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_593() { + let original = r##" +"##; + let expected = r##"

    MAILTO:FOO@BAR.BAZ

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_594() { + let original = r##" +"##; + let expected = r##"

    a+b+c:d

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_595() { + let original = r##" +"##; + let expected = r##"

    made-up-scheme://foo,bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_596() { + let original = r##" +"##; + let expected = r##"

    http://../

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_597() { + let original = r##" +"##; + let expected = r##"

    localhost:5001/foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_598() { + let original = r##" +"##; + let expected = r##"

    <http://foo.bar/baz bim>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_599() { + let original = r##" +"##; + let expected = r##"

    http://example.com/\[\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_600() { + let original = r##" +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_601() { + let original = r##" +"##; + let expected = r##"

    foo+special@Bar.baz-bar0.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_602() { + let original = r##" +"##; + let expected = r##"

    <foo+@bar.example.com>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_603() { + let original = r##"<> +"##; + let expected = r##"

    <>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_604() { + let original = r##"< http://foo.bar > +"##; + let expected = r##"

    < http://foo.bar >

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_605() { + let original = r##" +"##; + let expected = r##"

    <m:abc>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_606() { + let original = r##" +"##; + let expected = r##"

    <foo.bar.baz>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_607() { + let original = r##"http://example.com +"##; + let expected = r##"

    http://example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_608() { + let original = r##"foo@bar.example.com +"##; + let expected = r##"

    foo@bar.example.com

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_609() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_610() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_611() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_612() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_613() { + let original = r##"Foo +"##; + let expected = r##"

    Foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_614() { + let original = r##"<33> <__> +"##; + let expected = r##"

    <33> <__>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_615() { + let original = r##"
    +"##; + let expected = r##"

    <a h*#ref="hi">

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_616() { + let original = r##"
    <a href="hi'> <a href=hi'>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_617() { + let original = r##"< a>< +foo> + +"##; + let expected = r##"

    < a>< +foo><bar/ > +<foo bar=baz +bim!bop />

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_618() { + let original = r##"
    +"##; + let expected = r##"

    <a href='bar'title=title>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_619() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_620() { + let original = r##" +"##; + let expected = r##"

    </a href="foo">

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_621() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_622() { + let original = r##"foo +"##; + let expected = r##"

    foo <!-- not a comment -- two hyphens -->

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_623() { + let original = r##"foo foo --> + +foo +"##; + let expected = r##"

    foo <!--> foo -->

    +

    foo <!-- foo--->

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_624() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_625() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_626() { + let original = r##"foo &<]]> +"##; + let expected = r##"

    foo &<]]>

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_627() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_628() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_629() { + let original = r##" +"##; + let expected = r##"

    <a href=""">

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_630() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_631() { + let original = r##"foo\ +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_632() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo
    +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_633() { + let original = r##"foo + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_634() { + let original = r##"foo\ + bar +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_635() { + let original = r##"*foo +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_636() { + let original = r##"*foo\ +bar* +"##; + let expected = r##"

    foo
    +bar

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_637() { + let original = r##"`code +span` +"##; + let expected = r##"

    code span

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_638() { + let original = r##"`code\ +span` +"##; + let expected = r##"

    code\ span

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_639() { + let original = r##"
    +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_640() { + let original = r##" +"##; + let expected = r##"

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_641() { + let original = r##"foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_642() { + let original = r##"foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_643() { + let original = r##"### foo\ +"##; + let expected = r##"

    foo\

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_644() { + let original = r##"### foo +"##; + let expected = r##"

    foo

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_645() { + let original = r##"foo +baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_646() { + let original = r##"foo + baz +"##; + let expected = r##"

    foo +baz

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_647() { + let original = r##"hello $.;'there +"##; + let expected = r##"

    hello $.;'there

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_648() { + let original = r##"Foo χρῆν +"##; + let expected = r##"

    Foo χρῆν

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn spec_test_649() { + let original = r##"Multiple spaces +"##; + let expected = r##"

    Multiple spaces

    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/pulldown-cmark/tests/suite/table.rs b/vendor/pulldown-cmark/tests/suite/table.rs index de4d2f65dc..c034955e1d 100644 --- a/vendor/pulldown-cmark/tests/suite/table.rs +++ b/vendor/pulldown-cmark/tests/suite/table.rs @@ -1,205 +1,205 @@ -// This file is auto-generated by the build script -// Please, do not modify it manually - -use super::test_markdown_html; - -#[test] -fn table_test_1() { - let original = r##"Test header ------------ -"##; - let expected = r##"

    Test header

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_2() { - let original = r##"Test|Table -----|----- -"##; - let expected = r##" -
    TestTable
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_3() { - let original = r##"> Test | Table -> ------|------ -> Row 1 | Every -> Row 2 | Day -> -> Paragraph -"##; - let expected = r##"
    - - - -
    Test Table
    Row 1 Every
    Row 2 Day
    -

    Paragraph

    -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_4() { - let original = r##" 1. First entry - 2. Second entry - - Col 1|Col 2 - -|- - Row 1|Part 2 - Row 2|Part 2 -"##; - let expected = r##"
      -
    1. -

      First entry

      -
    2. -
    3. -

      Second entry

      - - - -
      Col 1Col 2
      Row 1Part 2
      Row 2Part 2
      -
    4. -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_5() { - let original = r##"|Col 1|Col 2| -|-----|-----| -|R1C1 |R1C2 | -|R2C1 |R2C2 | -"##; - let expected = r##" - - -
    Col 1Col 2
    R1C1 R1C2
    R2C1 R2C2
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_6() { - let original = r##"| Col 1 | Col 2 | -|-------|-------| -| | | -| | | -"##; - let expected = r##" - - -
    Col 1 Col 2
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_7() { - let original = r##"| Col 1 | Col 2 | -|-------|-------| -| x | | -| | x | -"##; - let expected = r##" - - -
    Col 1 Col 2
    x
    x
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_8() { - let original = r##"|Col 1|Col 2| -|-----|-----| -|✓ |✓ | -|✓ |✓ | -"##; - let expected = r##" - - -
    Col 1Col 2
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_9() { - let original = r##"| Target | std |rustc|cargo| notes | -|-------------------------------|-----|-----|-----|----------------------------| -| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | -| `arm-linux-androideabi` | ✓ | | | ARM Android | -| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | -| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | -| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | -| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | -| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | -"##; - let expected = r##" - - - - - - - -
    Target std rustccargo notes
    x86_64-unknown-linux-musl 64-bit Linux with MUSL
    arm-linux-androideabi ARM Android
    arm-unknown-linux-gnueabi ARM Linux (2.6.18+)
    arm-unknown-linux-gnueabihf ARM Linux (2.6.18+)
    aarch64-unknown-linux-gnu ARM64 Linux (2.6.18+)
    mips-unknown-linux-gnu MIPS Linux (2.6.18+)
    mipsel-unknown-linux-gnu MIPS (LE) Linux (2.6.18+)
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_10() { - let original = r##"|-|-| -|ぃ|い| -"##; - let expected = r##"

    |-|-| -|ぃ|い|

    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_11() { - let original = r##"|ぁ|ぃ| -|-|-| -|ぃ|ぃ| -"##; - let expected = r##" - -
    -"##; - - test_markdown_html(original, expected); -} - -#[test] -fn table_test_12() { - let original = r##"|Колонка 1|Колонка 2| -|---------|---------| -|Ячейка 1 |Ячейка 2 | -"##; - let expected = r##" - -
    Колонка 1Колонка 2
    Ячейка 1 Ячейка 2
    -"##; - - test_markdown_html(original, expected); -} +// This file is auto-generated by the build script +// Please, do not modify it manually + +use super::test_markdown_html; + +#[test] +fn table_test_1() { + let original = r##"Test header +----------- +"##; + let expected = r##"

    Test header

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_2() { + let original = r##"Test|Table +----|----- +"##; + let expected = r##" +
    TestTable
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_3() { + let original = r##"> Test | Table +> ------|------ +> Row 1 | Every +> Row 2 | Day +> +> Paragraph +"##; + let expected = r##"
    + + + +
    Test Table
    Row 1 Every
    Row 2 Day
    +

    Paragraph

    +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_4() { + let original = r##" 1. First entry + 2. Second entry + + Col 1|Col 2 + -|- + Row 1|Part 2 + Row 2|Part 2 +"##; + let expected = r##"
      +
    1. +

      First entry

      +
    2. +
    3. +

      Second entry

      + + + +
      Col 1Col 2
      Row 1Part 2
      Row 2Part 2
      +
    4. +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_5() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|R1C1 |R1C2 | +|R2C1 |R2C2 | +"##; + let expected = r##" + + +
    Col 1Col 2
    R1C1 R1C2
    R2C1 R2C2
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_6() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| | | +| | | +"##; + let expected = r##" + + +
    Col 1 Col 2
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_7() { + let original = r##"| Col 1 | Col 2 | +|-------|-------| +| x | | +| | x | +"##; + let expected = r##" + + +
    Col 1 Col 2
    x
    x
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_8() { + let original = r##"|Col 1|Col 2| +|-----|-----| +|✓ |✓ | +|✓ |✓ | +"##; + let expected = r##" + + +
    Col 1Col 2
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_9() { + let original = r##"| Target | std |rustc|cargo| notes | +|-------------------------------|-----|-----|-----|----------------------------| +| `x86_64-unknown-linux-musl` | ✓ | | | 64-bit Linux with MUSL | +| `arm-linux-androideabi` | ✓ | | | ARM Android | +| `arm-unknown-linux-gnueabi` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `arm-unknown-linux-gnueabihf` | ✓ | ✓ | | ARM Linux (2.6.18+) | +| `aarch64-unknown-linux-gnu` | ✓ | | | ARM64 Linux (2.6.18+) | +| `mips-unknown-linux-gnu` | ✓ | | | MIPS Linux (2.6.18+) | +| `mipsel-unknown-linux-gnu` | ✓ | | | MIPS (LE) Linux (2.6.18+) | +"##; + let expected = r##" + + + + + + + +
    Target std rustccargo notes
    x86_64-unknown-linux-musl 64-bit Linux with MUSL
    arm-linux-androideabi ARM Android
    arm-unknown-linux-gnueabi ARM Linux (2.6.18+)
    arm-unknown-linux-gnueabihf ARM Linux (2.6.18+)
    aarch64-unknown-linux-gnu ARM64 Linux (2.6.18+)
    mips-unknown-linux-gnu MIPS Linux (2.6.18+)
    mipsel-unknown-linux-gnu MIPS (LE) Linux (2.6.18+)
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_10() { + let original = r##"|-|-| +|ぃ|い| +"##; + let expected = r##"

    |-|-| +|ぃ|い|

    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_11() { + let original = r##"|ぁ|ぃ| +|-|-| +|ぃ|ぃ| +"##; + let expected = r##" + +
    +"##; + + test_markdown_html(original, expected, false); +} + +#[test] +fn table_test_12() { + let original = r##"|Колонка 1|Колонка 2| +|---------|---------| +|Ячейка 1 |Ячейка 2 | +"##; + let expected = r##" + +
    Колонка 1Колонка 2
    Ячейка 1 Ячейка 2
    +"##; + + test_markdown_html(original, expected, false); +} diff --git a/vendor/rayon-core/.cargo-checksum.json b/vendor/rayon-core/.cargo-checksum.json index 7599f18f25..f770100278 100644 --- a/vendor/rayon-core/.cargo-checksum.json +++ b/vendor/rayon-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"a83d5bb197e911851b02a0f9335e627a445f3241e380f405e75a67f1f7682b51","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"32fe5dcb2c1d89c475ea8bf098477fef95863c3551b7633f4071eaf1bd039de4","build.rs":"fa31cb198b772600d100a7c403ddedccef637d2e6b2da431fa7f02ca41307fc6","src/compile_fail/mod.rs":"4d70256295bd64691a8c1994b323559cda1888e85f0b45ca55711541c257dcb6","src/compile_fail/quicksort_race1.rs":"35f498cda38f4eb6e00117f78ed68e0fe5a3fa61c25303d9c08a19bda345bc6c","src/compile_fail/quicksort_race2.rs":"cbb40030c7867cae34bb373b6ec5d97c2ac6de39bc917f47879b30eb423924bc","src/compile_fail/quicksort_race3.rs":"8403643e64c969306b1a9b1243378e6ccdd313b57e1878dbd31393618082fd35","src/compile_fail/rc_return.rs":"b6f1f821ef30086e2990db1ac58a92adaf31e57c23c587c7746d6303865c5c0f","src/compile_fail/rc_upvar.rs":"92a799b313fb88a0eb83fc1aaaea4b61604222b45e20f1c22ff5b092a03f8620","src/compile_fail/scope_join_bad.rs":"892959949f77cadfc07458473e7a290301182027ca64428df5a8ce887be0892b","src/job.rs":"8477aa1041881e6e0256c2d138c0731f6881a6f7dbe619db61e6f8c668a87790","src/join/mod.rs":"cde5393089286f606e45c5e0a735ca45e715a57b5ea0e50d00b784a010b01be3","src/join/test.rs":"9fbb741f97e38f7b69e63d81183e96dadb585bf5694335fed13af3090b1d3f76","src/latch.rs":"f99f146b34ab22e700abeda39d8f44d8ab8d6deefcb4ef134a1ea4155c5bc69d","src/lib.rs":"9fc60649122276044cc4f5733a253c76f03fd69ea39416bf79eb9f1fd9f3e6c8","src/log.rs":"d628635e157e36f5f6107015d660948392af30a76795674ab8a781f297c3b1c6","src/private.rs":"702ff02a2d0846d6d97b4164c7b4c2fbab2157ba5ba9c31fea5f1775ff3c9597","src/registry.rs":"51461cbc64b1e5eb9880e843a800f1b1daed7ebb8b6e6f0f8de53e3bea2298fb","src/scope/mod.rs":"00e4566dfb6e76cda555b02af18670820ee568a941946b9da9034c160653109f","src/scope/test.rs":"2980222cfabc132483333e4c8bae10ce2e8cc3770079cdc0ec79486ba05499ca","src/sleep/README.md":"34a83cd8a0f84e58472af5c40744794139fbfe22a392f0dc6eb90cfdf9389119","src/sleep/mod.rs":"de97a2f92166eec84380addddce530fc3eb8fa29f1af7824457d0823aa369a68","src/spawn/mod.rs":"60b71a325bfd90a334c7c7fa331463eab67e72375709161ef68448b9db76d296","src/spawn/test.rs":"463e39211a1b3829954ed0e486145c510d4dcf6718c2daf9a2594ae05c3eb98f","src/test.rs":"edf421670c2b3b440971fdfa20139c11e7506a4cca14c4e36ccb76d073027521","src/thread_pool/mod.rs":"252fb18f5fe9e3a7971a6bad2878168224f2d6016f5c991685e8a5c6e571da8b","src/thread_pool/test.rs":"d201a19541be093adcdcde9b8e659f3d4f018296b0d1abe7c0cbc4aa14625755","src/unwind.rs":"7baa4511467d008b14856ea8de7ced92b9251c9df4854f69c81f7efc3cf0cd6c","src/util.rs":"7b58c4aeb37b5e8a38f1028a673f06e712f6e9976a6fe938c05e06ead1c22469","tests/double_init_fail.rs":"f6f6e1b45bdba6ef8f18d1981e5356a6d5ef2f3bbecd0c8ce4341c126a3a6f1d","tests/init_zero_threads.rs":"57f66d1662f7782848d45942faa613a608188eb400943e4efa4c3ec3375e1dac","tests/scope_join.rs":"56f570c4b6a01704aacf93e7f17f89fe0f40f46ed6f9ede517abfe9adaf91f83","tests/scoped_threadpool.rs":"0f6475f440a57b6f91ecdd720228395f4feaa6165b136558f65267e185fd7127","tests/simple_panic.rs":"916d40d36c1a0fad3e1dfb31550f0672641feab4b03d480f039143dbe2f2445f","tests/stack_overflow_crash.rs":"e8865d33d51a58f5c6639f457d91f82f2a4379cf5129094eaa521e95bad72d51"},"package":"e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280"} \ No newline at end of file +{"files":{"Cargo.toml":"68535b85775c95dca419153c119059a13b3c2720ff219ca264c3928592743dde","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"32fe5dcb2c1d89c475ea8bf098477fef95863c3551b7633f4071eaf1bd039de4","build.rs":"fa31cb198b772600d100a7c403ddedccef637d2e6b2da431fa7f02ca41307fc6","src/compile_fail/mod.rs":"4d70256295bd64691a8c1994b323559cda1888e85f0b45ca55711541c257dcb6","src/compile_fail/quicksort_race1.rs":"35f498cda38f4eb6e00117f78ed68e0fe5a3fa61c25303d9c08a19bda345bc6c","src/compile_fail/quicksort_race2.rs":"cbb40030c7867cae34bb373b6ec5d97c2ac6de39bc917f47879b30eb423924bc","src/compile_fail/quicksort_race3.rs":"8403643e64c969306b1a9b1243378e6ccdd313b57e1878dbd31393618082fd35","src/compile_fail/rc_return.rs":"b6f1f821ef30086e2990db1ac58a92adaf31e57c23c587c7746d6303865c5c0f","src/compile_fail/rc_upvar.rs":"92a799b313fb88a0eb83fc1aaaea4b61604222b45e20f1c22ff5b092a03f8620","src/compile_fail/scope_join_bad.rs":"892959949f77cadfc07458473e7a290301182027ca64428df5a8ce887be0892b","src/job.rs":"f6b439551ea723f8657be9971ce5f42660e1a2bb743e226e3255887056770264","src/join/mod.rs":"91f58385a3fc5a62187df32338595a479df5aee08f8af08e5066dbc2488bacf4","src/join/test.rs":"9fbb741f97e38f7b69e63d81183e96dadb585bf5694335fed13af3090b1d3f76","src/latch.rs":"7a5fed3838d2446c7cd5608a6c3e2ff682cf5f9c8c84d0e902008f700f5ef39d","src/lib.rs":"aa8eb221c63a02b9bccb3314b1be24fe55e644e0e2e413360a5b875ecbc27442","src/log.rs":"8a25ed8661f5ae3317085a108f78bb5f5a2e40827dbde9b16d6b8a560a5f2c39","src/private.rs":"152f6d65ce4741616a1dec796b9442f78a018d38bb040f76c4cd85008333a3bb","src/registry.rs":"b4e2a2d6f577564924c3d8c56083a270f78845f344f7d287f39b4bfe232ce369","src/scope/mod.rs":"5aad3a6dcb0e4e1c19699357f0db52186b0f711d1a455e135dd0423b13315c39","src/scope/test.rs":"2fb3f2a5011a29a6d5619368bfd517c447200839296094ff4b6605950973ab3c","src/sleep/README.md":"4714cd03a8c2be7648b5f48d85b121cc3bc39af6b65c025bfa34640d85af18d6","src/sleep/counters.rs":"b7c50ac0bd035d4b0342da92b0d422bf1f69e07b7a4b025af7d01b8a9b47ce46","src/sleep/mod.rs":"091da1b21c49559f0f3af9475340249d48534310f18051ed358b27fccf52b4a3","src/spawn/mod.rs":"255ea058f7b45f8f1d488fe3d4ae6b34669f294d174e2b8b9fb7a99450896491","src/spawn/test.rs":"463e39211a1b3829954ed0e486145c510d4dcf6718c2daf9a2594ae05c3eb98f","src/test.rs":"edf421670c2b3b440971fdfa20139c11e7506a4cca14c4e36ccb76d073027521","src/thread_pool/mod.rs":"f3389baf5500896fab4c41281b9f94c298d1e2db3c1d96938e5b604614d23934","src/thread_pool/test.rs":"737d5b77c8191ba3a103a7a09d8db253ca148edac9e040e688974f2ca4a5be18","src/unwind.rs":"7baa4511467d008b14856ea8de7ced92b9251c9df4854f69c81f7efc3cf0cd6c","src/util.rs":"7b58c4aeb37b5e8a38f1028a673f06e712f6e9976a6fe938c05e06ead1c22469","tests/double_init_fail.rs":"f6f6e1b45bdba6ef8f18d1981e5356a6d5ef2f3bbecd0c8ce4341c126a3a6f1d","tests/init_zero_threads.rs":"57f66d1662f7782848d45942faa613a608188eb400943e4efa4c3ec3375e1dac","tests/scope_join.rs":"56f570c4b6a01704aacf93e7f17f89fe0f40f46ed6f9ede517abfe9adaf91f83","tests/scoped_threadpool.rs":"0f6475f440a57b6f91ecdd720228395f4feaa6165b136558f65267e185fd7127","tests/simple_panic.rs":"916d40d36c1a0fad3e1dfb31550f0672641feab4b03d480f039143dbe2f2445f","tests/stack_overflow_crash.rs":"e8865d33d51a58f5c6639f457d91f82f2a4379cf5129094eaa521e95bad72d51"},"package":"91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0"} \ No newline at end of file diff --git a/vendor/rayon-core/Cargo.toml b/vendor/rayon-core/Cargo.toml index a04e4aeda5..4e78ab9893 100644 --- a/vendor/rayon-core/Cargo.toml +++ b/vendor/rayon-core/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "rayon-core" -version = "1.7.1" +version = "1.8.0" authors = ["Niko Matsakis ", "Josh Stone "] build = "build.rs" links = "rayon-core" @@ -49,12 +49,12 @@ path = "tests/simple_panic.rs" [[test]] name = "scoped_threadpool" path = "tests/scoped_threadpool.rs" +[dependencies.crossbeam-channel] +version = "0.4.2" + [dependencies.crossbeam-deque] version = "0.7.2" -[dependencies.crossbeam-queue] -version = "0.2" - [dependencies.crossbeam-utils] version = "0.7" diff --git a/vendor/rayon-core/src/job.rs b/vendor/rayon-core/src/job.rs index 27510cff23..a71f1b0e96 100644 --- a/vendor/rayon-core/src/job.rs +++ b/vendor/rayon-core/src/job.rs @@ -1,6 +1,6 @@ use crate::latch::Latch; use crate::unwind; -use crossbeam_queue::SegQueue; +use crossbeam_deque::{Injector, Steal}; use std::any::Any; use std::cell::UnsafeCell; use std::mem; @@ -184,13 +184,13 @@ impl JobResult { /// Indirect queue to provide FIFO job priority. pub(super) struct JobFifo { - inner: SegQueue, + inner: Injector, } impl JobFifo { pub(super) fn new() -> Self { JobFifo { - inner: SegQueue::new(), + inner: Injector::new(), } } @@ -206,6 +206,12 @@ impl JobFifo { impl Job for JobFifo { unsafe fn execute(this: *const Self) { // We "execute" a queue by executing its first job, FIFO. - (*this).inner.pop().expect("job in fifo queue").execute() + loop { + match (*this).inner.steal() { + Steal::Success(job_ref) => break job_ref.execute(), + Steal::Empty => panic!("FIFO is empty"), + Steal::Retry => {} + } + } } } diff --git a/vendor/rayon-core/src/join/mod.rs b/vendor/rayon-core/src/join/mod.rs index 295f97bc22..d72c7e61c7 100644 --- a/vendor/rayon-core/src/join/mod.rs +++ b/vendor/rayon-core/src/join/mod.rs @@ -1,6 +1,5 @@ use crate::job::StackJob; -use crate::latch::{LatchProbe, SpinLatch}; -use crate::log::Event::*; +use crate::latch::SpinLatch; use crate::registry::{self, WorkerThread}; use crate::unwind; use std::any::Any; @@ -131,14 +130,10 @@ where } registry::in_worker(|worker_thread, injected| unsafe { - log!(Join { - worker: worker_thread.index() - }); - // Create virtual wrapper for task b; this all has to be // done here so that the stack frame can keep it all live // long enough. - let job_b = StackJob::new(call_b(oper_b), SpinLatch::new()); + let job_b = StackJob::new(call_b(oper_b), SpinLatch::new(worker_thread)); let job_b_ref = job_b.as_job_ref(); worker_thread.push(job_b_ref); @@ -160,23 +155,14 @@ where // Found it! Let's run it. // // Note that this could panic, but it's ok if we unwind here. - log!(PoppedRhs { - worker: worker_thread.index() - }); let result_b = job_b.run_inline(injected); return (result_a, result_b); } else { - log!(PoppedJob { - worker: worker_thread.index() - }); worker_thread.execute(job); } } else { // Local deque is empty. Time to steal from other // threads. - log!(LostJob { - worker: worker_thread.index() - }); worker_thread.wait_until(&job_b.latch); debug_assert!(job_b.latch.probe()); break; @@ -193,7 +179,7 @@ where #[cold] // cold path unsafe fn join_recover_from_panic( worker_thread: &WorkerThread, - job_b_latch: &SpinLatch, + job_b_latch: &SpinLatch<'_>, err: Box, ) -> ! { worker_thread.wait_until(job_b_latch); diff --git a/vendor/rayon-core/src/latch.rs b/vendor/rayon-core/src/latch.rs index fb6e44b00b..0965bb95a7 100644 --- a/vendor/rayon-core/src/latch.rs +++ b/vendor/rayon-core/src/latch.rs @@ -1,7 +1,8 @@ -use std::sync::atomic::{AtomicBool, AtomicUsize, Ordering}; +use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::{Arc, Condvar, Mutex}; +use std::usize; -use crate::registry::Registry; +use crate::registry::{Registry, WorkerThread}; /// We define various kinds of latches, which are all a primitive signaling /// mechanism. A latch starts as false. Eventually someone calls `set()` and @@ -29,43 +30,189 @@ use crate::registry::Registry; /// - Once `set()` occurs, the next `probe()` *will* observe it. This /// typically requires a seq-cst ordering. See [the "tickle-then-get-sleepy" scenario in the sleep /// README](/src/sleep/README.md#tickle-then-get-sleepy) for details. -pub(super) trait Latch: LatchProbe { +pub(super) trait Latch { /// Set the latch, signalling others. + /// + /// # WARNING + /// + /// Setting a latch triggers other threads to wake up and (in some + /// cases) complete. This may, in turn, cause memory to be + /// allocated and so forth. One must be very careful about this, + /// and it's typically better to read all the fields you will need + /// to access *before* a latch is set! fn set(&self); } -pub(super) trait LatchProbe { - /// Test if the latch is set. - fn probe(&self) -> bool; +pub(super) trait AsCoreLatch { + fn as_core_latch(&self) -> &CoreLatch; +} + +/// Latch is not set, owning thread is awake +const UNSET: usize = 0; + +/// Latch is not set, owning thread is going to sleep on this latch +/// (but has not yet fallen asleep). +const SLEEPY: usize = 1; + +/// Latch is not set, owning thread is asleep on this latch and +/// must be awoken. +const SLEEPING: usize = 2; + +/// Latch is set. +const SET: usize = 3; + +/// Spin latches are the simplest, most efficient kind, but they do +/// not support a `wait()` operation. They just have a boolean flag +/// that becomes true when `set()` is called. +#[derive(Debug)] +pub(super) struct CoreLatch { + state: AtomicUsize, +} + +impl CoreLatch { + #[inline] + fn new() -> Self { + Self { + state: AtomicUsize::new(0), + } + } + + /// Returns the address of this core latch as an integer. Used + /// for logging. + #[inline] + pub(super) fn addr(&self) -> usize { + self as *const CoreLatch as usize + } + + /// Invoked by owning thread as it prepares to sleep. Returns true + /// if the owning thread may proceed to fall asleep, false if the + /// latch was set in the meantime. + #[inline] + pub(super) fn get_sleepy(&self) -> bool { + self.state + .compare_exchange(UNSET, SLEEPY, Ordering::SeqCst, Ordering::Relaxed) + .is_ok() + } + + /// Invoked by owning thread as it falls asleep sleep. Returns + /// true if the owning thread should block, or false if the latch + /// was set in the meantime. + #[inline] + pub(super) fn fall_asleep(&self) -> bool { + self.state + .compare_exchange(SLEEPY, SLEEPING, Ordering::SeqCst, Ordering::Relaxed) + .is_ok() + } + + /// Invoked by owning thread as it falls asleep sleep. Returns + /// true if the owning thread should block, or false if the latch + /// was set in the meantime. + #[inline] + pub(super) fn wake_up(&self) { + if !self.probe() { + let _ = + self.state + .compare_exchange(SLEEPING, UNSET, Ordering::SeqCst, Ordering::Relaxed); + } + } + + /// Set the latch. If this returns true, the owning thread was sleeping + /// and must be awoken. + /// + /// This is private because, typically, setting a latch involves + /// doing some wakeups; those are encapsulated in the surrounding + /// latch code. + #[inline] + fn set(&self) -> bool { + let old_state = self.state.swap(SET, Ordering::AcqRel); + old_state == SLEEPING + } + + /// Test if this latch has been set. + #[inline] + pub(super) fn probe(&self) -> bool { + self.state.load(Ordering::Acquire) == SET + } } /// Spin latches are the simplest, most efficient kind, but they do /// not support a `wait()` operation. They just have a boolean flag /// that becomes true when `set()` is called. -pub(super) struct SpinLatch { - b: AtomicBool, +pub(super) struct SpinLatch<'r> { + core_latch: CoreLatch, + registry: &'r Arc, + target_worker_index: usize, + cross: bool, } -impl SpinLatch { +impl<'r> SpinLatch<'r> { + /// Creates a new spin latch that is owned by `thread`. This means + /// that `thread` is the only thread that should be blocking on + /// this latch -- it also means that when the latch is set, we + /// will wake `thread` if it is sleeping. #[inline] - pub(super) fn new() -> SpinLatch { + pub(super) fn new(thread: &'r WorkerThread) -> SpinLatch<'r> { SpinLatch { - b: AtomicBool::new(false), + core_latch: CoreLatch::new(), + registry: thread.registry(), + target_worker_index: thread.index(), + cross: false, } } -} -impl LatchProbe for SpinLatch { + /// Creates a new spin latch for cross-threadpool blocking. Notably, we + /// need to make sure the registry is kept alive after setting, so we can + /// safely call the notification. #[inline] - fn probe(&self) -> bool { - self.b.load(Ordering::SeqCst) + pub(super) fn cross(thread: &'r WorkerThread) -> SpinLatch<'r> { + SpinLatch { + cross: true, + ..SpinLatch::new(thread) + } + } + + #[inline] + pub(super) fn probe(&self) -> bool { + self.core_latch.probe() } } -impl Latch for SpinLatch { +impl<'r> AsCoreLatch for SpinLatch<'r> { + #[inline] + fn as_core_latch(&self) -> &CoreLatch { + &self.core_latch + } +} + +impl<'r> Latch for SpinLatch<'r> { #[inline] fn set(&self) { - self.b.store(true, Ordering::SeqCst); + let cross_registry; + + let registry = if self.cross { + // Ensure the registry stays alive while we notify it. + // Otherwise, it would be possible that we set the spin + // latch and the other thread sees it and exits, causing + // the registry to be deallocated, all before we get a + // chance to invoke `registry.notify_worker_latch_is_set`. + cross_registry = Arc::clone(self.registry); + &cross_registry + } else { + // If this is not a "cross-registry" spin-latch, then the + // thread which is performing `set` is itself ensuring + // that the registry stays alive. + self.registry + }; + let target_worker_index = self.target_worker_index; + + // NOTE: Once we `set`, the target may proceed and invalidate `&self`! + if self.core_latch.set() { + // Subtle: at this point, we can no longer read from + // `self`, because the thread owning this spin latch may + // have awoken and deallocated the latch. Therefore, we + // only use fields whose values we already read. + registry.notify_worker_latch_is_set(target_worker_index); + } } } @@ -103,15 +250,6 @@ impl LockLatch { } } -impl LatchProbe for LockLatch { - #[inline] - fn probe(&self) -> bool { - // Not particularly efficient, but we don't really use this operation - let guard = self.m.lock().unwrap(); - *guard - } -} - impl Latch for LockLatch { #[inline] fn set(&self) { @@ -126,8 +264,19 @@ impl Latch for LockLatch { /// necessarily make the latch be considered `set()`; instead, it just /// decrements the counter. The latch is only "set" (in the sense that /// `probe()` returns true) once the counter reaches zero. +/// +/// Note: like a `SpinLatch`, count laches are always associated with +/// some registry that is probing them, which must be tickled when +/// they are set. *Unlike* a `SpinLatch`, they don't themselves hold a +/// reference to that registry. This is because in some cases the +/// registry owns the count-latch, and that would create a cycle. So a +/// `CountLatch` must be given a reference to its owning registry when +/// it is set. For this reason, it does not implement the `Latch` +/// trait (but it doesn't have to, as it is not used in those generic +/// contexts). #[derive(Debug)] pub(super) struct CountLatch { + core_latch: CoreLatch, counter: AtomicUsize, } @@ -135,77 +284,47 @@ impl CountLatch { #[inline] pub(super) fn new() -> CountLatch { CountLatch { + core_latch: CoreLatch::new(), counter: AtomicUsize::new(1), } } #[inline] pub(super) fn increment(&self) { - debug_assert!(!self.probe()); + debug_assert!(!self.core_latch.probe()); self.counter.fetch_add(1, Ordering::Relaxed); } -} -impl LatchProbe for CountLatch { + /// Decrements the latch counter by one. If this is the final + /// count, then the latch is **set**, and calls to `probe()` will + /// return true. Returns whether the latch was set. This is an + /// internal operation, as it does not tickle, and to fail to + /// tickle would lead to deadlock. #[inline] - fn probe(&self) -> bool { - // Need to acquire any memory reads before latch was set: - self.counter.load(Ordering::SeqCst) == 0 + fn set(&self) -> bool { + if self.counter.fetch_sub(1, Ordering::SeqCst) == 1 { + self.core_latch.set(); + true + } else { + false + } } -} -impl Latch for CountLatch { - /// Set the latch to true, releasing all threads who are waiting. + /// Decrements the latch counter by one and possibly set it. If + /// the latch is set, then the specific worker thread is tickled, + /// which should be the one that owns this latch. #[inline] - fn set(&self) { - self.counter.fetch_sub(1, Ordering::SeqCst); - } -} - -/// A tickling latch wraps another latch type, and will also awaken a thread -/// pool when it is set. This is useful for jobs injected between thread pools, -/// so the source pool can continue processing its own work while waiting. -pub(super) struct TickleLatch<'a, L: Latch> { - inner: L, - registry: &'a Arc, -} - -impl<'a, L: Latch> TickleLatch<'a, L> { - #[inline] - pub(super) fn new(latch: L, registry: &'a Arc) -> Self { - registry.increment_terminate_count(); - TickleLatch { - inner: latch, - registry, + pub(super) fn set_and_tickle_one(&self, registry: &Registry, target_worker_index: usize) { + if self.set() { + registry.notify_worker_latch_is_set(target_worker_index); } } } -impl<'a, L: Latch> LatchProbe for TickleLatch<'a, L> { +impl AsCoreLatch for CountLatch { #[inline] - fn probe(&self) -> bool { - self.inner.probe() - } -} - -impl<'a, L: Latch> Latch for TickleLatch<'a, L> { - #[inline] - fn set(&self) { - // Ensure the registry stays alive while we tickle it. - let registry = Arc::clone(self.registry); - - // NOTE: Once we `set`, the target may proceed and invalidate `&self`! - self.inner.set(); - registry.tickle(); - } -} - -impl<'a, L> LatchProbe for &'a L -where - L: LatchProbe, -{ - fn probe(&self) -> bool { - L::probe(self) + fn as_core_latch(&self) -> &CoreLatch { + &self.core_latch } } @@ -213,6 +332,7 @@ impl<'a, L> Latch for &'a L where L: Latch, { + #[inline] fn set(&self) { L::set(self); } diff --git a/vendor/rayon-core/src/lib.rs b/vendor/rayon-core/src/lib.rs index 639386ce2e..3c8a91a7cf 100644 --- a/vendor/rayon-core/src/lib.rs +++ b/vendor/rayon-core/src/lib.rs @@ -19,10 +19,11 @@ //! conflicting requirements will need to be resolved before the build will //! succeed. -#![doc(html_root_url = "https://docs.rs/rayon-core/1.7")] +#![doc(html_root_url = "https://docs.rs/rayon-core/1.8")] #![deny(missing_debug_implementations)] #![deny(missing_docs)] #![deny(unreachable_pub)] +#![warn(rust_2018_idioms)] use std::any::Any; use std::env; diff --git a/vendor/rayon-core/src/log.rs b/vendor/rayon-core/src/log.rs index 687370d0b5..e1ff827dfd 100644 --- a/vendor/rayon-core/src/log.rs +++ b/vendor/rayon-core/src/log.rs @@ -1,116 +1,423 @@ //! Debug Logging //! -//! To use in a debug build, set the env var `RAYON_LOG=1`. In a -//! release build, logs are compiled out. You will have to change -//! `DUMP_LOGS` to be `true`. +//! To use in a debug build, set the env var `RAYON_LOG` as +//! described below. In a release build, logs are compiled out by +//! default unless Rayon is built with `--cfg rayon_rs_log` (try +//! `RUSTFLAGS="--cfg rayon_rs_log"`). //! -//! **Old environment variable:** `RAYON_LOG` is a one-to-one -//! replacement of the now deprecated `RAYON_RS_LOG` environment -//! variable, which is still supported for backwards compatibility. +//! Note that logs are an internally debugging tool and their format +//! is considered unstable, as are the details of how to enable them. +//! +//! # Valid values for RAYON_LOG +//! +//! The `RAYON_LOG` variable can take on the following values: +//! +//! * `tail:` -- dumps the last 10,000 events into the given file; +//! useful for tracking down deadlocks +//! * `profile:` -- dumps only those events needed to reconstruct how +//! many workers are active at a given time +//! * `all:` -- dumps every event to the file; useful for debugging -#[cfg(debug_assertions)] +use crossbeam_channel::{self, Receiver, Sender}; +use std::collections::VecDeque; use std::env; +use std::fs::File; +use std::io::{self, BufWriter, Write}; -#[cfg_attr(debug_assertions, derive(Debug))] -#[cfg_attr(not(debug_assertions), allow(dead_code))] +/// True if logs are compiled in. +pub(super) const LOG_ENABLED: bool = cfg!(any(rayon_rs_log, debug_assertions)); + +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] pub(super) enum Event { - Tickle { + /// Flushes events to disk, used to terminate benchmarking. + Flush, + + /// Indicates that a worker thread started execution. + ThreadStart { worker: usize, - old_state: usize, + terminate_addr: usize, }, - GetSleepy { + + /// Indicates that a worker thread started execution. + ThreadTerminate { worker: usize }, + + /// Indicates that a worker thread became idle, blocked on `latch_addr`. + ThreadIdle { worker: usize, latch_addr: usize }, + + /// Indicates that an idle worker thread found work to do, after + /// yield rounds. It should no longer be considered idle. + ThreadFoundWork { worker: usize, yields: u32 }, + + /// Indicates that a worker blocked on a latch observed that it was set. + /// + /// Internal debugging event that does not affect the state + /// machine. + ThreadSawLatchSet { worker: usize, latch_addr: usize }, + + /// Indicates that an idle worker is getting sleepy. `sleepy_counter` is the internal + /// sleep state that we saw at the time. + ThreadSleepy { worker: usize, jobs_counter: usize }, + + /// Indicates that the thread's attempt to fall asleep was + /// interrupted because the latch was set. (This is not, in and of + /// itself, a change to the thread state.) + ThreadSleepInterruptedByLatch { worker: usize, latch_addr: usize }, + + /// Indicates that the thread's attempt to fall asleep was + /// interrupted because a job was posted. (This is not, in and of + /// itself, a change to the thread state.) + ThreadSleepInterruptedByJob { worker: usize }, + + /// Indicates that an idle worker has gone to sleep. + ThreadSleeping { worker: usize, latch_addr: usize }, + + /// Indicates that a sleeping worker has awoken. + ThreadAwoken { worker: usize, latch_addr: usize }, + + /// Indicates that the given worker thread was notified it should + /// awaken. + ThreadNotify { worker: usize }, + + /// The given worker has pushed a job to its local deque. + JobPushed { worker: usize }, + + /// The given worker has popped a job from its local deque. + JobPopped { worker: usize }, + + /// The given worker has stolen a job from the deque of another. + JobStolen { worker: usize, victim: usize }, + + /// N jobs were injected into the global queue. + JobsInjected { count: usize }, + + /// A job was removed from the global queue. + JobUninjected { worker: usize }, + + /// When announcing a job, this was the value of the counters we observed. + /// + /// No effect on thread state, just a debugging event. + JobThreadCounts { worker: usize, - state: usize, - }, - GotSleepy { - worker: usize, - old_state: usize, - new_state: usize, - }, - GotAwoken { - worker: usize, - }, - FellAsleep { - worker: usize, - }, - GotInterrupted { - worker: usize, - }, - FoundWork { - worker: usize, - yields: usize, - }, - DidNotFindWork { - worker: usize, - yields: usize, - }, - StoleWork { - worker: usize, - victim: usize, - }, - UninjectedWork { - worker: usize, - }, - WaitUntil { - worker: usize, - }, - LatchSet { - worker: usize, - }, - InjectJobs { - count: usize, - }, - Join { - worker: usize, - }, - PoppedJob { - worker: usize, - }, - PoppedRhs { - worker: usize, - }, - LostJob { - worker: usize, - }, - JobCompletedOk { - owner_thread: usize, - }, - JobPanickedErrorStored { - owner_thread: usize, - }, - JobPanickedErrorNotStored { - owner_thread: usize, - }, - ScopeCompletePanicked { - owner_thread: usize, - }, - ScopeCompleteNoPanic { - owner_thread: usize, + num_idle: u16, + num_sleepers: u16, }, } -#[cfg(debug_assertions)] -lazy_static::lazy_static! { - pub(super) static ref LOG_ENV: bool = - env::var("RAYON_LOG").is_ok() || env::var("RAYON_RS_LOG").is_ok(); +/// Handle to the logging thread, if any. You can use this to deliver +/// logs. You can also clone it freely. +#[derive(Clone)] +pub(super) struct Logger { + sender: Option>, } -#[cfg(debug_assertions)] -macro_rules! log { - ($event:expr) => { - if *$crate::log::LOG_ENV { - eprintln!("{:?}", $event); +impl Logger { + pub(super) fn new(num_workers: usize) -> Logger { + if !LOG_ENABLED { + return Self::disabled(); } - }; + + // see the doc comment for the format + let env_log = match env::var("RAYON_LOG") { + Ok(s) => s, + Err(_) => return Self::disabled(), + }; + + let (sender, receiver) = crossbeam_channel::unbounded(); + + if env_log.starts_with("tail:") { + let filename = env_log["tail:".len()..].to_string(); + ::std::thread::spawn(move || { + Self::tail_logger_thread(num_workers, filename, 10_000, receiver) + }); + } else if env_log == "all" { + ::std::thread::spawn(move || Self::all_logger_thread(num_workers, receiver)); + } else if env_log.starts_with("profile:") { + let filename = env_log["profile:".len()..].to_string(); + ::std::thread::spawn(move || { + Self::profile_logger_thread(num_workers, filename, 10_000, receiver) + }); + } else { + panic!("RAYON_LOG should be 'tail:' or 'profile:'"); + } + + return Logger { + sender: Some(sender), + }; + } + + fn disabled() -> Logger { + Logger { sender: None } + } + + #[inline] + pub(super) fn log(&self, event: impl FnOnce() -> Event) { + if !LOG_ENABLED { + return; + } + + if let Some(sender) = &self.sender { + sender.send(event()).unwrap(); + } + } + + fn profile_logger_thread( + num_workers: usize, + log_filename: String, + capacity: usize, + receiver: Receiver, + ) { + let file = File::create(&log_filename) + .unwrap_or_else(|err| panic!("failed to open `{}`: {}", log_filename, err)); + + let mut writer = BufWriter::new(file); + let mut events = Vec::with_capacity(capacity); + let mut state = SimulatorState::new(num_workers); + let timeout = std::time::Duration::from_secs(30); + + loop { + loop { + match receiver.recv_timeout(timeout) { + Ok(event) => { + if let Event::Flush = event { + break; + } else { + events.push(event); + } + } + + Err(_) => break, + } + + if events.len() == capacity { + break; + } + } + + for event in events.drain(..) { + if state.simulate(&event) { + state.dump(&mut writer, &event).unwrap(); + } + } + + writer.flush().unwrap(); + } + } + + fn tail_logger_thread( + num_workers: usize, + log_filename: String, + capacity: usize, + receiver: Receiver, + ) { + let file = File::create(&log_filename) + .unwrap_or_else(|err| panic!("failed to open `{}`: {}", log_filename, err)); + + let mut writer = BufWriter::new(file); + let mut events: VecDeque = VecDeque::with_capacity(capacity); + let mut state = SimulatorState::new(num_workers); + let timeout = std::time::Duration::from_secs(30); + let mut skipped = false; + + loop { + loop { + match receiver.recv_timeout(timeout) { + Ok(event) => { + if let Event::Flush = event { + // We ignore Flush events in tail mode -- + // we're really just looking for + // deadlocks. + continue; + } else { + if events.len() == capacity { + let event = events.pop_front().unwrap(); + state.simulate(&event); + skipped = true; + } + + events.push_back(event); + } + } + + Err(_) => break, + } + } + + if skipped { + write!(writer, "...\n").unwrap(); + skipped = false; + } + + for event in events.drain(..) { + // In tail mode, we dump *all* events out, whether or + // not they were 'interesting' to the state machine. + state.simulate(&event); + state.dump(&mut writer, &event).unwrap(); + } + + writer.flush().unwrap(); + } + } + + fn all_logger_thread(num_workers: usize, receiver: Receiver) { + let stderr = std::io::stderr(); + let mut state = SimulatorState::new(num_workers); + + for event in receiver { + let mut writer = BufWriter::new(stderr.lock()); + state.simulate(&event); + state.dump(&mut writer, &event).unwrap(); + writer.flush().unwrap(); + } + } } -#[cfg(not(debug_assertions))] -macro_rules! log { - ($event:expr) => { - if false { - // Expand `$event` so it still appears used, but without - // any of the formatting code to be optimized away. - $event; - } - }; +#[derive(Copy, Clone, PartialOrd, Ord, PartialEq, Eq, Debug)] +enum State { + Working, + Idle, + Notified, + Sleeping, + Terminated, +} + +impl State { + fn letter(&self) -> char { + match self { + State::Working => 'W', + State::Idle => 'I', + State::Notified => 'N', + State::Sleeping => 'S', + State::Terminated => 'T', + } + } +} + +struct SimulatorState { + local_queue_size: Vec, + thread_states: Vec, + injector_size: usize, +} + +impl SimulatorState { + fn new(num_workers: usize) -> Self { + Self { + local_queue_size: (0..num_workers).map(|_| 0).collect(), + thread_states: (0..num_workers).map(|_| State::Working).collect(), + injector_size: 0, + } + } + + fn simulate(&mut self, event: &Event) -> bool { + match *event { + Event::ThreadIdle { worker, .. } => { + assert_eq!(self.thread_states[worker], State::Working); + self.thread_states[worker] = State::Idle; + true + } + + Event::ThreadStart { worker, .. } | Event::ThreadFoundWork { worker, .. } => { + self.thread_states[worker] = State::Working; + true + } + + Event::ThreadTerminate { worker, .. } => { + self.thread_states[worker] = State::Terminated; + true + } + + Event::ThreadSleeping { worker, .. } => { + assert_eq!(self.thread_states[worker], State::Idle); + self.thread_states[worker] = State::Sleeping; + true + } + + Event::ThreadAwoken { worker, .. } => { + assert_eq!(self.thread_states[worker], State::Notified); + self.thread_states[worker] = State::Idle; + true + } + + Event::JobPushed { worker } => { + self.local_queue_size[worker] += 1; + true + } + + Event::JobPopped { worker } => { + self.local_queue_size[worker] -= 1; + true + } + + Event::JobStolen { victim, .. } => { + self.local_queue_size[victim] -= 1; + true + } + + Event::JobsInjected { count } => { + self.injector_size += count; + true + } + + Event::JobUninjected { .. } => { + self.injector_size -= 1; + true + } + + Event::ThreadNotify { worker } => { + // Currently, this log event occurs while holding the + // thread lock, so we should *always* see it before + // the worker awakens. + assert_eq!(self.thread_states[worker], State::Sleeping); + self.thread_states[worker] = State::Notified; + true + } + + // remaining events are no-ops from pov of simulating the + // thread state + _ => false, + } + } + + fn dump(&mut self, w: &mut impl Write, event: &Event) -> io::Result<()> { + let num_idle_threads = self + .thread_states + .iter() + .filter(|s| **s == State::Idle) + .count(); + + let num_sleeping_threads = self + .thread_states + .iter() + .filter(|s| **s == State::Sleeping) + .count(); + + let num_notified_threads = self + .thread_states + .iter() + .filter(|s| **s == State::Notified) + .count(); + + let num_pending_jobs: usize = self.local_queue_size.iter().sum(); + + write!(w, "{:2},", num_idle_threads)?; + write!(w, "{:2},", num_sleeping_threads)?; + write!(w, "{:2},", num_notified_threads)?; + write!(w, "{:4},", num_pending_jobs)?; + write!(w, "{:4},", self.injector_size)?; + + let event_str = format!("{:?}", event); + write!(w, r#""{:60}","#, event_str)?; + + for ((i, state), queue_size) in (0..).zip(&self.thread_states).zip(&self.local_queue_size) { + write!(w, " T{:02},{}", i, state.letter(),)?; + + if *queue_size > 0 { + write!(w, ",{:03},", queue_size)?; + } else { + write!(w, ", ,")?; + } + } + + write!(w, "\n")?; + Ok(()) + } } diff --git a/vendor/rayon-core/src/private.rs b/vendor/rayon-core/src/private.rs index a99dd11fb2..c85e77b9cb 100644 --- a/vendor/rayon-core/src/private.rs +++ b/vendor/rayon-core/src/private.rs @@ -14,7 +14,7 @@ macro_rules! private_decl { /// impossible to implement outside the crate. #[doc(hidden)] fn __rayon_private__(&self) -> crate::private::PrivateMarker; - } + }; } macro_rules! private_impl { @@ -22,5 +22,5 @@ macro_rules! private_impl { fn __rayon_private__(&self) -> crate::private::PrivateMarker { crate::private::PrivateMarker } - } + }; } diff --git a/vendor/rayon-core/src/registry.rs b/vendor/rayon-core/src/registry.rs index 5ef77e09d8..46ae10a20f 100644 --- a/vendor/rayon-core/src/registry.rs +++ b/vendor/rayon-core/src/registry.rs @@ -1,14 +1,14 @@ use crate::job::{JobFifo, JobRef, StackJob}; -use crate::latch::{CountLatch, Latch, LatchProbe, LockLatch, SpinLatch, TickleLatch}; +use crate::latch::{AsCoreLatch, CoreLatch, CountLatch, Latch, LockLatch, SpinLatch}; use crate::log::Event::*; +use crate::log::Logger; use crate::sleep::Sleep; use crate::unwind; use crate::util::leak; use crate::{ ErrorKind, ExitHandler, PanicHandler, StartHandler, ThreadPoolBuildError, ThreadPoolBuilder, }; -use crossbeam_deque::{Steal, Stealer, Worker}; -use crossbeam_queue::SegQueue; +use crossbeam_deque::{Injector, Steal, Stealer, Worker}; use std::any::Any; use std::cell::Cell; use std::collections::hash_map::DefaultHasher; @@ -132,9 +132,10 @@ where } pub(super) struct Registry { + logger: Logger, thread_infos: Vec, sleep: Sleep, - injected_jobs: SegQueue, + injected_jobs: Injector, panic_handler: Option>, start_handler: Option>, exit_handler: Option>, @@ -152,7 +153,7 @@ pub(super) struct Registry { // - when `join()` or `scope()` is invoked, similarly, no adjustments are needed. // These are always owned by some other job (e.g., one injected by `ThreadPool::install()`) // and that job will keep the pool alive. - terminate_latch: CountLatch, + terminate_count: AtomicUsize, } /// //////////////////////////////////////////////////////////////////////// @@ -233,11 +234,13 @@ impl Registry { }) .unzip(); + let logger = Logger::new(n_threads); let registry = Arc::new(Registry { + logger: logger.clone(), thread_infos: stealers.into_iter().map(ThreadInfo::new).collect(), - sleep: Sleep::new(), - injected_jobs: SegQueue::new(), - terminate_latch: CountLatch::new(), + sleep: Sleep::new(logger, n_threads), + injected_jobs: Injector::new(), + terminate_count: AtomicUsize::new(1), panic_handler: builder.take_panic_handler(), start_handler: builder.take_start_handler(), exit_handler: builder.take_exit_handler(), @@ -311,6 +314,11 @@ impl Registry { } } + #[inline] + pub(super) fn log(&self, event: impl FnOnce() -> crate::log::Event) { + self.logger.log(event) + } + pub(super) fn num_threads(&self) -> usize { self.thread_infos.len() } @@ -374,8 +382,8 @@ impl Registry { /// whatever worker has nothing to do. Use this is you know that /// you are not on a worker of this registry. pub(super) fn inject(&self, injected_jobs: &[JobRef]) { - log!(InjectJobs { - count: injected_jobs.len() + self.log(|| JobsInjected { + count: injected_jobs.len(), }); // It should not be possible for `state.terminate` to be true @@ -383,25 +391,39 @@ impl Registry { // drops) a `ThreadPool`; and, in that case, they cannot be // calling `inject()` later, since they dropped their // `ThreadPool`. - assert!( - !self.terminate_latch.probe(), + debug_assert_ne!( + self.terminate_count.load(Ordering::Acquire), + 0, "inject() sees state.terminate as true" ); + let queue_was_empty = self.injected_jobs.is_empty(); + for &job_ref in injected_jobs { self.injected_jobs.push(job_ref); } - self.sleep.tickle(usize::MAX); + + self.sleep + .new_injected_jobs(usize::MAX, injected_jobs.len() as u32, queue_was_empty); + } + + fn has_injected_job(&self) -> bool { + !self.injected_jobs.is_empty() } fn pop_injected_job(&self, worker_index: usize) -> Option { - let job = self.injected_jobs.pop().ok(); - if job.is_some() { - log!(UninjectedWork { - worker: worker_index - }); + loop { + match self.injected_jobs.steal() { + Steal::Success(job) => { + self.log(|| JobUninjected { + worker: worker_index, + }); + return Some(job); + } + Steal::Empty => return None, + Steal::Retry => {} + } } - job } /// If already in a worker-thread of this registry, just execute `op`. @@ -450,6 +472,10 @@ impl Registry { ); self.inject(&[job.as_job_ref()]); job.latch.wait_and_reset(); // Make sure we can use the same latch again next time. + + // flush accumulated logs as we exit the thread + self.logger.log(|| Flush); + job.into_result() }) } @@ -463,7 +489,7 @@ impl Registry { // This thread is a member of a different pool, so let it process // other work while waiting for this `op` to complete. debug_assert!(current_thread.registry().id() != self.id()); - let latch = TickleLatch::new(SpinLatch::new(), current_thread.registry()); + let latch = SpinLatch::cross(current_thread); let job = StackJob::new( |injected| { let worker_thread = WorkerThread::current(); @@ -498,19 +524,28 @@ impl Registry { /// terminate count and is responsible for invoking `terminate()` /// when finished. pub(super) fn increment_terminate_count(&self) { - self.terminate_latch.increment(); + let previous = self.terminate_count.fetch_add(1, Ordering::AcqRel); + debug_assert!(previous != 0, "registry ref count incremented from zero"); + assert!( + previous != std::usize::MAX, + "overflow in registry ref count" + ); } /// Signals that the thread-pool which owns this registry has been /// dropped. The worker threads will gradually terminate, once any /// extant work is completed. pub(super) fn terminate(&self) { - self.terminate_latch.set(); - self.sleep.tickle(usize::MAX); + if self.terminate_count.fetch_sub(1, Ordering::AcqRel) == 1 { + for (i, thread_info) in self.thread_infos.iter().enumerate() { + thread_info.terminate.set_and_tickle_one(self, i); + } + } } - pub(super) fn tickle(&self) { - self.sleep.tickle(usize::MAX); + /// Notify the worker that the latch they are sleeping on has been "set". + pub(super) fn notify_worker_latch_is_set(&self, target_worker_index: usize) { + self.sleep.notify_worker_latch_is_set(target_worker_index); } } @@ -529,6 +564,15 @@ struct ThreadInfo { /// until workers have stopped; only used for tests. stopped: LockLatch, + /// The latch used to signal that terminated has been requested. + /// This latch is *set* by the `terminate` method on the + /// `Registry`, once the registry's main "terminate" counter + /// reaches zero. + /// + /// NB. We use a `CountLatch` here because it has no lifetimes and is + /// meant for async use, but the count never gets higher than one. + terminate: CountLatch, + /// the "stealer" half of the worker's deque stealer: Stealer, } @@ -538,6 +582,7 @@ impl ThreadInfo { ThreadInfo { primed: LockLatch::new(), stopped: LockLatch::new(), + terminate: CountLatch::new(), stealer, } } @@ -599,10 +644,16 @@ impl WorkerThread { } /// Returns the registry that owns this worker thread. + #[inline] pub(super) fn registry(&self) -> &Arc { &self.registry } + #[inline] + pub(super) fn log(&self, event: impl FnOnce() -> crate::log::Event) { + self.registry.logger.log(event) + } + /// Our index amongst the worker threads (ranges from `0..self.num_threads()`). #[inline] pub(super) fn index(&self) -> usize { @@ -611,8 +662,12 @@ impl WorkerThread { #[inline] pub(super) unsafe fn push(&self, job: JobRef) { + self.log(|| JobPushed { worker: self.index }); + let queue_was_empty = self.worker.is_empty(); self.worker.push(job); - self.registry.sleep.tickle(self.index); + self.registry + .sleep + .new_internal_jobs(self.index, 1, queue_was_empty); } #[inline] @@ -631,21 +686,27 @@ impl WorkerThread { /// bottom. #[inline] pub(super) unsafe fn take_local_job(&self) -> Option { - self.worker.pop() + let popped_job = self.worker.pop(); + + if popped_job.is_some() { + self.log(|| JobPopped { worker: self.index }); + } + + popped_job } /// Wait until the latch is set. Try to keep busy by popping and /// stealing tasks as necessary. #[inline] - pub(super) unsafe fn wait_until(&self, latch: &L) { - log!(WaitUntil { worker: self.index }); + pub(super) unsafe fn wait_until(&self, latch: &L) { + let latch = latch.as_core_latch(); if !latch.probe() { self.wait_until_cold(latch); } } #[cold] - unsafe fn wait_until_cold(&self, latch: &L) { + unsafe fn wait_until_cold(&self, latch: &CoreLatch) { // the code below should swallow all panics and hence never // unwind; but if something does wrong, we want to abort, // because otherwise other code in rayon may assume that the @@ -653,7 +714,7 @@ impl WorkerThread { // accesses, which would be *very bad* let abort_guard = unwind::AbortIfPanic; - let mut yields = 0; + let mut idle_state = self.registry.sleep.start_looking(self.index, latch); while !latch.probe() { // Try to find some work to do. We give preference first // to things in our local deque, then in other workers @@ -665,30 +726,31 @@ impl WorkerThread { .or_else(|| self.steal()) .or_else(|| self.registry.pop_injected_job(self.index)) { - yields = self.registry.sleep.work_found(self.index, yields); + self.registry.sleep.work_found(idle_state); self.execute(job); + idle_state = self.registry.sleep.start_looking(self.index, latch); } else { - yields = self.registry.sleep.no_work_found(self.index, yields); + self.registry + .sleep + .no_work_found(&mut idle_state, latch, || self.registry.has_injected_job()) } } // If we were sleepy, we are not anymore. We "found work" -- // whatever the surrounding thread was doing before it had to // wait. - self.registry.sleep.work_found(self.index, yields); + self.registry.sleep.work_found(idle_state); - log!(LatchSet { worker: self.index }); + self.log(|| ThreadSawLatchSet { + worker: self.index, + latch_addr: latch.addr(), + }); mem::forget(abort_guard); // successful execution, do not abort } + #[inline] pub(super) unsafe fn execute(&self, job: JobRef) { job.execute(); - - // Subtle: executing this job will have `set()` some of its - // latches. This may mean that a sleepy (or sleeping) worker - // can now make progress. So we have to tickle them to let - // them know. - self.registry.sleep.tickle(self.index); } /// Try to steal a single job and return it. @@ -700,32 +762,39 @@ impl WorkerThread { debug_assert!(self.local_deque_is_empty()); // otherwise, try to steal - let num_threads = self.registry.thread_infos.len(); + let thread_infos = &self.registry.thread_infos.as_slice(); + let num_threads = thread_infos.len(); if num_threads <= 1 { return None; } - let start = self.rng.next_usize(num_threads); - (start..num_threads) - .chain(0..start) - .filter(|&i| i != self.index) - .filter_map(|victim_index| { - let victim = &self.registry.thread_infos[victim_index]; - loop { + loop { + let mut retry = false; + let start = self.rng.next_usize(num_threads); + let job = (start..num_threads) + .chain(0..start) + .filter(move |&i| i != self.index) + .find_map(|victim_index| { + let victim = &thread_infos[victim_index]; match victim.stealer.steal() { - Steal::Empty => return None, - Steal::Success(d) => { - log!(StoleWork { + Steal::Success(job) => { + self.log(|| JobStolen { worker: self.index, - victim: victim_index + victim: victim_index, }); - return Some(d); + Some(job) + } + Steal::Empty => None, + Steal::Retry => { + retry = true; + None } - Steal::Retry => {} } - } - }) - .next() + }); + if job.is_some() || !retry { + return job; + } + } } } @@ -760,7 +829,12 @@ unsafe fn main_loop(worker: Worker, registry: Arc, index: usiz } } - worker_thread.wait_until(®istry.terminate_latch); + let my_terminate_latch = ®istry.thread_infos[index].terminate; + worker_thread.log(|| ThreadStart { + worker: index, + terminate_addr: my_terminate_latch.as_core_latch().addr(), + }); + worker_thread.wait_until(my_terminate_latch); // Should not be any work left in our queue. debug_assert!(worker_thread.take_local_job().is_none()); @@ -771,6 +845,8 @@ unsafe fn main_loop(worker: Worker, registry: Arc, index: usiz // Normal termination, do not abort. mem::forget(abort_guard); + worker_thread.log(|| ThreadTerminate { worker: index }); + // Inform a user callback that we exited a thread. if let Some(ref handler) = registry.exit_handler { let registry = registry.clone(); diff --git a/vendor/rayon-core/src/scope/mod.rs b/vendor/rayon-core/src/scope/mod.rs index 7c1333d005..a41d408e1e 100644 --- a/vendor/rayon-core/src/scope/mod.rs +++ b/vendor/rayon-core/src/scope/mod.rs @@ -5,8 +5,7 @@ //! [`join()`]: ../join/join.fn.html use crate::job::{HeapJob, JobFifo}; -use crate::latch::{CountLatch, Latch}; -use crate::log::Event::*; +use crate::latch::CountLatch; use crate::registry::{in_worker, Registry, WorkerThread}; use crate::unwind; use std::any::Any; @@ -286,7 +285,7 @@ struct ScopeBase<'scope> { /// propagated at that point. pub fn scope<'scope, OP, R>(op: OP) -> R where - OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send, + OP: FnOnce(&Scope<'scope>) -> R + Send, R: Send, { in_worker(|owner_thread, _| { @@ -377,7 +376,7 @@ where /// panics are propagated at that point. pub fn scope_fifo<'scope, OP, R>(op: OP) -> R where - OP: for<'s> FnOnce(&'s ScopeFifo<'scope>) -> R + 'scope + Send, + OP: FnOnce(&ScopeFifo<'scope>) -> R + Send, R: Send, { in_worker(|owner_thread, _| { @@ -580,24 +579,16 @@ impl<'scope> ScopeBase<'scope> { .compare_exchange(nil, &mut *err, Ordering::Release, Ordering::Relaxed) .is_ok() { - log!(JobPanickedErrorStored { - owner_thread: self.owner_thread_index - }); mem::forget(err); // ownership now transferred into self.panic - } else { - log!(JobPanickedErrorNotStored { - owner_thread: self.owner_thread_index - }); } - self.job_completed_latch.set(); + self.job_completed_latch + .set_and_tickle_one(&self.registry, self.owner_thread_index); } unsafe fn job_completed_ok(&self) { - log!(JobCompletedOk { - owner_thread: self.owner_thread_index - }); - self.job_completed_latch.set(); + self.job_completed_latch + .set_and_tickle_one(&self.registry, self.owner_thread_index); } unsafe fn steal_till_jobs_complete(&self, owner_thread: &WorkerThread) { @@ -609,15 +600,8 @@ impl<'scope> ScopeBase<'scope> { // ordering: let panic = self.panic.swap(ptr::null_mut(), Ordering::Relaxed); if !panic.is_null() { - log!(ScopeCompletePanicked { - owner_thread: owner_thread.index() - }); let value: Box> = mem::transmute(panic); unwind::resume_unwinding(*value); - } else { - log!(ScopeCompleteNoPanic { - owner_thread: owner_thread.index() - }); } } } diff --git a/vendor/rayon-core/src/scope/test.rs b/vendor/rayon-core/src/scope/test.rs index 3d855ecda7..8cb82b6153 100644 --- a/vendor/rayon-core/src/scope/test.rs +++ b/vendor/rayon-core/src/scope/test.rs @@ -1,6 +1,6 @@ use crate::unwind; use crate::ThreadPoolBuilder; -use crate::{scope, scope_fifo, Scope}; +use crate::{scope, scope_fifo, Scope, ScopeFifo}; use rand::{Rng, SeedableRng}; use rand_xorshift::XorShiftRng; use std::cmp; @@ -433,3 +433,83 @@ fn mixed_fifo_lifo_order() { let expected = vec![-3, 0, -2, 1, -1, 2, 3]; assert_eq!(vec, expected); } + +#[test] +fn static_scope() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let mut range = 0..100; + let sum = range.clone().sum(); + let iter = &mut range; + + COUNTER.store(0, Ordering::Relaxed); + scope(|s: &Scope<'static>| { + // While we're allowed the locally borrowed iterator, + // the spawns must be static. + for i in iter { + s.spawn(move |_| { + COUNTER.fetch_add(i, Ordering::Relaxed); + }); + } + }); + + assert_eq!(COUNTER.load(Ordering::Relaxed), sum); +} + +#[test] +fn static_scope_fifo() { + static COUNTER: AtomicUsize = AtomicUsize::new(0); + + let mut range = 0..100; + let sum = range.clone().sum(); + let iter = &mut range; + + COUNTER.store(0, Ordering::Relaxed); + scope_fifo(|s: &ScopeFifo<'static>| { + // While we're allowed the locally borrowed iterator, + // the spawns must be static. + for i in iter { + s.spawn_fifo(move |_| { + COUNTER.fetch_add(i, Ordering::Relaxed); + }); + } + }); + + assert_eq!(COUNTER.load(Ordering::Relaxed), sum); +} + +#[test] +fn mixed_lifetime_scope() { + fn increment<'slice, 'counter>(counters: &'slice [&'counter AtomicUsize]) { + scope(move |s: &Scope<'counter>| { + // We can borrow 'slice here, but the spawns can only borrow 'counter. + for &c in counters { + s.spawn(move |_| { + c.fetch_add(1, Ordering::Relaxed); + }); + } + }); + } + + let counter = AtomicUsize::new(0); + increment(&[&counter; 100]); + assert_eq!(counter.into_inner(), 100); +} + +#[test] +fn mixed_lifetime_scope_fifo() { + fn increment<'slice, 'counter>(counters: &'slice [&'counter AtomicUsize]) { + scope_fifo(move |s: &ScopeFifo<'counter>| { + // We can borrow 'slice here, but the spawns can only borrow 'counter. + for &c in counters { + s.spawn_fifo(move |_| { + c.fetch_add(1, Ordering::Relaxed); + }); + } + }); + } + + let counter = AtomicUsize::new(0); + increment(&[&counter; 100]); + assert_eq!(counter.into_inner(), 100); +} diff --git a/vendor/rayon-core/src/sleep/README.md b/vendor/rayon-core/src/sleep/README.md index bc2af869ff..c62c3975d9 100644 --- a/vendor/rayon-core/src/sleep/README.md +++ b/vendor/rayon-core/src/sleep/README.md @@ -1,388 +1,219 @@ # Introduction: the sleep module The code in this module governs when worker threads should go to -sleep. This is a tricky topic -- the work-stealing algorithm relies on -having active worker threads running around stealing from one -another. But, if there isn't a lot of work, this can be a bit of a -drag, because it requires high CPU usage. +sleep. The system used in this code was introduced in [Rayon RFC #5]. +There is also a [video walkthrough] available. Both of those may be +valuable resources to understanding the code, though naturally they +will also grow stale over time. The comments in this file are +extracted from the RFC and meant to be kept up to date. -The code in this module takes a fairly simple approach to the -problem. It allows worker threads to fall asleep if they have failed -to steal work after various thresholds; however, whenever new work -appears, they will wake up briefly and try to steal again. There are some -shortcomings in this current approach: +[Rayon RFC #5]: https://github.com/rayon-rs/rfcs/pull/5 +[video walkthrough]: https://youtu.be/HvmQsE5M4cY -- it can (to some extent) scale *down* the amount of threads, but they - can never be scaled *up*. The latter might be useful in the case of - user tasks that must (perhaps very occasionally and unpredictably) - block for long periods of time. - - however, the preferred approach to this is for users to adopt futures - instead (and indeed this sleeping work is intended to enable future - integration). -- we have no way to wake up threads in a fine-grained or targeted - manner. The current system wakes up *all* sleeping threads whenever - *any* of them might be interested in an event. This means that while - we can scale CPU usage down, we do is in a fairly "bursty" manner, - where everyone comes online, then some of them go back offline. +# The `Sleep` struct -# The interface for workers +The `Sleep` struct is embedded into each registry. It performs several functions: -Workers interact with the sleep module by invoking three methods: +* It tracks when workers are awake or asleep. +* It decides how long a worker should look for work before it goes to sleep, + via a callback that is invoked periodically from the worker's search loop. +* It is notified when latches are set, jobs are published, or other + events occur, and it will go and wake the appropriate threads if + they are sleeping. -- `work_found()`: signals that the worker found some work and is about - to execute it. -- `no_work_found()`: signals that the worker searched all available sources - for work and found none. - - It is important for the coherence of the algorithm that if work - was available **before the search started**, it would have been - found. If work was made available during the search, then it's ok that - it might have been overlooked. -- `tickle()`: indicates that new work is available (e.g., a job has - been pushed to the local deque) or that some other blocking - condition has been resolved (e.g., a latch has been set). Wakes up any - sleeping workers. +# Thread states -When in a loop searching for work, Workers also have to maintain an -integer `yields` that they provide to the `sleep` module (which will -return a new value for the next time). Thus the basic worker "find -work" loop looks like this (this is `wait_until()`, basically): +There are three main thread states: -```rust -let mut yields = 0; -while /* not done */ { - if let Some(job) = search_for_work() { - yields = work_found(self.index, yields); - } else { - yields = no_work_found(self.index, yields); - } -} -``` +* An **active** thread is one that is actively executing a job. +* An **idle** thread is one that is searching for work to do. It will be + trying to steal work or pop work from the global injector queue. +* A **sleeping** thread is one that is blocked on a condition variable, + waiting to be awoken. -# Getting sleepy and falling asleep +We sometimes refer to the final two states collectively as **inactive**. +Threads begin as idle but transition to idle and finally sleeping when +they're unable to find work to do. -The basic idea here is that every worker goes through three states: +## Sleepy threads -- **Awake:** actively hunting for tasks. -- **Sleepy:** still actively hunting for tasks, but we have signaled that - we might go to sleep soon if we don't find any. -- **Asleep:** actually asleep (blocked on a condition variable). +There is one other special state worth mentioning. During the idle state, +threads can get **sleepy**. A sleepy thread is still idle, in that it is still +searching for work, but it is *about* to go to sleep after it does one more +search (or some other number, potentially). When a thread enters the sleepy +state, it signals (via the **jobs event counter**, described below) that it is +about to go to sleep. If new work is published, this will lead to the counter +being adjusted. When the thread actually goes to sleep, it will (hopefully, but +not guaranteed) see that the counter has changed and elect not to sleep, but +instead to search again. See the section on the **jobs event counter** for more +details. -At any given time, only **one** worker can be in the sleepy -state. This allows us to coordinate the entire sleep protocol using a -single `AtomicUsize` and without the need of epoch counters or other -things that might rollover and so forth. +# The counters -Whenever a worker invokes `work_found()`, it transitions back to the -**awake** state. In other words, if it was sleepy, it stops being -sleepy. (`work_found()` cannot be invoked when the worker is asleep, -since then it is not doing anything.) +One of the key structs in the sleep module is `AtomicCounters`, found in +`counters.rs`. It packs three counters into one atomically managed value: -On the other hand, whenever a worker invokes `no_work_found()`, it -*may* transition to a more sleepy state. To track this, we use the -counter `yields` that is maintained by the worker's steal loop. This -counter starts at 0. Whenever work is found, the counter is returned -to 0. But each time that **no** work is found, the counter is -incremented. Eventually it will reach a threshold -`ROUNDS_UNTIL_SLEEPY`. At this point, the worker will try to become -the sleepy one. It does this by executing a CAS into the global -registry state (details on this below). If that attempt is successful, -then the counter is incremented again, so that it is equal to -`ROUNDS_UNTIL_SLEEPY + 1`. Otherwise, the counter stays the same (and -hence we will keep trying to become sleepy until either work is found -or we are successful). +* Two **thread counters**, which track the number of threads in a particular state. +* The **jobs event counter**, which is used to signal when new work is available. + It (sort of) tracks the number of jobs posted, but not quite, and it can rollover. -Becoming sleepy does not put us to sleep immediately. Instead, we keep -iterating and looking for work for some further number of rounds. If -during this search we **do** find work, then we will return the -counter to 0 and also reset the global state to indicate we are no -longer sleepy. +## Thread counters -But if again no work is found, `yields` will eventually reach the -value `ROUNDS_UNTIL_ASLEEP`. At that point, we will try to transition -from **sleepy** to **asleep**. This is done by the helper fn -`sleep()`, which executes another CAS on the global state that removes -our worker as the sleepy worker and instead sets a flag to indicate -that there are sleeping workers present (the flag may already have -been set, that's ok). Assuming that CAS succeeds, we will block on a -condition variable. +There are two thread counters, one that tracks **inactive** threads and one that +tracks **sleeping** threads. From this, one can deduce the number of threads +that are idle by subtracting sleeping threads from inactive threads. We track +the counters in this way because it permits simpler atomic operations. One can +increment the number of sleeping threads (and thus decrease the number of idle +threads) simply by doing one atomic increment, for example. Similarly, one can +decrease the number of sleeping threads (and increase the number of idle +threads) through one atomic decrement. -# Tickling workers +These counters are adjusted as follows: -Of course, while all the stuff in the previous section is happening, -other workers are (hopefully) producing new work. There are three kinds of -events that can allow a blocked worker to make progress: +* When a thread enters the idle state: increment the inactive thread counter. +* When a thread enters the sleeping state: increment the sleeping thread counter. +* When a thread awakens a sleeping thread: decrement the sleeping thread counter. + * Subtle point: the thread that *awakens* the sleeping thread decrements the + counter, not the thread that is *sleeping*. This is because there is a delay + between siganling a thread to wake and the thread actually waking: + decrementing the counter when awakening the thread means that other threads + that may be posting work will see the up-to-date value that much faster. +* When a thread finds work, exiting the idle state: decrement the inactive + thread counter. -1. A new task is pushed onto a worker's deque. This task could be stolen. -2. A new task is injected into the thread-pool from the outside. This - task could be uninjected and executed. -3. A latch is set. One of the sleeping workers might have been waiting for - that before it could go on. +## Jobs event counter -Whenever one of these things happens, the worker (or thread, more generally) -responsible must invoke `tickle()`. Tickle will basically wake up **all** -the workers: +The final counter is the **jobs event counter**. The role of this counter is to +help sleepy threads detect when new work is posted in a lightweight fashion. In +its simplest form, we would simply have a counter that gets incremented each +time a new job is posted. This way, when a thread gets sleepy, it could read the +counter, and then compare to see if the value has changed before it actually +goes to sleep. But this [turns out to be too expensive] in practice, so we use a +somewhat more complex scheme. -- If any worker was the sleepy one, then the global state is changed - so that there is no sleepy worker. The sleepy one will notice this - when it next invokes `no_work_found()` and return to the *awake* state - (with a yield counter of zero). -- If any workers were actually **asleep**, then we invoke - `notify_all()` on the condition variable, which will cause them to - awaken and start over from the awake state (with a yield counter of - zero). +[turns out to be too expensive]: https://github.com/rayon-rs/rayon/pull/746#issuecomment-624802747 -Because `tickle()` is invoked very frequently -- and hopefully most of -the time it is not needed, because the workers are already actively -stealing -- it is important that it be very cheap. The current design -requires, in the case where nobody is even sleepy, just a load and a -compare. If there are sleepy workers, a swap is needed. If there -workers *asleep*, we must naturally acquire the lock and signal the -condition variable. +The idea is that the counter toggles between two states, depending on whether +its value is even or odd (or, equivalently, on the value of its low bit): -# The global state +* Even -- If the low bit is zero, then it means that there has been no new work + since the last thread got sleepy. +* Odd -- If the low bit is one, then it means that new work was posted since + the last thread got sleepy. -We manage all of the above state transitions using a small bit of global -state (well, global to the registry). This is stored in the `Sleep` struct. -The primary thing is a single `AtomicUsize`. The value in this usize packs -in two pieces of information: +### New work is posted -1. **Are any workers asleep?** This is just one bit (yes or no). -2. **Which worker is the sleepy worker, if any?** This is a worker id. +When new work is posted, we check the value of the counter: if it is even, +then we increment it by one, so that it becomes odd. -We use bit 0 to indicate whether any workers are asleep. So if `state -& 1` is zero, then no workers are sleeping. But if `state & 1` is 1, -then some workers are either sleeping or on their way to falling -asleep (i.e., they have acquired the lock). +### Worker thread gets sleepy -The remaining bits are used to store if there is a sleepy worker. We -want `0` to indicate that there is no sleepy worker. If there a sleepy -worker with index `worker_index`, we would store `(worker_index + 1) -<< 1` . The `+1` is there because worker indices are 0-based, so this -ensures that the value is non-zero, and the shift skips over the -sleepy bit. +When a worker thread gets sleepy, it will read the value of the counter. If the +counter is odd, it will increment the counter so that it is even. Either way, it +remembers the final value of the counter. The final value will be used later, +when the thread is going to sleep. If at that time the counter has not changed, +then we can assume no new jobs have been posted (though note the remote +possibility of rollover, discussed in detail below). -Some examples: +# Protocol for a worker thread to post work -- `0`: everyone is awake, nobody is sleepy -- `1`: some workers are asleep, no sleepy worker -- `2`: no workers are asleep, but worker 0 is sleepy (`(0 + 1) << 1 == 2`). -- `3`: some workers are asleep, and worker 0 is sleepy. +The full protocol for a thread to post work is as follows -# Correctness level 1: avoiding deadlocks etc +* If the work is posted into the injection queue, then execute a seq-cst fence (see below). +* Load the counters, incrementing the JEC if it is even so that it is odd. +* Check if there are idle threads available to handle this new job. If not, + and there are sleeping threads, then wake one or more threads. -In general, we do not want to miss wakeups. Two bad things could happen: +# Protocol for a worker thread to fall asleep -- **Suboptimal performance**: If this is a wakeup about a new job being - pushed into a local deque, it won't deadlock, but it will cause - things to run slowly. The reason that it won't deadlock is that we - know at least one thread is active (the one doing the pushing), and - it will (sooner or later) try to pop this item from its own local - deque. -- **Deadlocks:** If this is a wakeup about an injected job or a latch that got set, however, - this can cause deadlocks. In the former case, if a job is injected but no thread ever - wakes to process it, the injector will likely block forever. In the latter case, - imagine this scenario: - - thread A calls join, forking a task T1, then executing task T2 - - thread B steals T1, forks a task T3, and executes T4. - - thread A completes task T2 and blocks on T1 - - thread A steals task T3 from thread B - - thread B finishes T4 and goes to sleep, blocking on T3 - - thread A completes task T3 and makes a wakeup, but it gets lost - At this point, thread B is still asleep and will never signal T2, so thread A will itself - go to sleep. Bad. +The full protocol for a thread to fall asleep is as follows: -It turns out that guaranteeing we don't miss a wakeup while retaining -good performance is fairly tricky. This is because of some details of -the C++11 memory model. But let's ignore those for now and generally -assume sequential consistency. In that case, our scheme should work -perfectly. +* After completing all its jobs, the worker goes idle and begins to + search for work. As it searches, it counts "rounds". In each round, + it searches all other work threads' queues, plus the 'injector queue' for + work injected from the outside. If work is found in this search, the thread + becomes active again and hence restarts this protocol from the top. +* After a certain number of rounds, the thread "gets sleepy" and executes `get_sleepy` + above, remembering the `final_value` of the JEC. It does one more search for work. +* If no work is found, the thread atomically: + * Checks the JEC to see that it has not changed from `final_value`. + * If it has, then the thread goes back to searchin for work. We reset to + just before we got sleepy, so that we will do one more search + before attending to sleep again (rather than searching for many rounds). + * Increments the number of sleeping threads by 1. +* The thread then executes a seq-cst fence operation (see below). +* The thread then does one final check for injected jobs (see below). If any + are available, it returns to the 'pre-sleepy' state as if the JEC had changed. +* The thread waits to be signaled. Once signaled, it returns to the idle state. -Even if you assume seqcst, though, ensuring that you don't miss -wakeups can be fairly tricky in the absence of a central queue. For -example, consider the simplest scheme: imagine we just had a boolean -flag indicating whether anyone was asleep. Then you could imagine that -when workers find no work, they flip this flag to true. When work is -published, if the flag is true, we issue a wakeup. +# The jobs event counter and deadlock -The problem here is that checking for new work is not an atomic -action. So it's possible that worker 1 could start looking for work -and (say) see that worker 0's queue is empty and then search workers -2..N. While that searching is taking place, worker 0 publishes some -new work. At the time when the new work is published, the "anyone -sleeping?" flag is still false, so nothing happens. Then worker 1, who -failed to find any work, goes to sleep --- completely missing the wakeup! +As described in the section on the JEC, the main concern around going to sleep +is avoiding a race condition wherein: -We use the "sleepy worker" idea to sidestep this problem. Under our -scheme, instead of going right to sleep at the end, worker 1 would -become sleepy. Worker 1 would then do **at least** one additional -scan. During this scan, they should find the work published by worker -0, so they will stop being sleepy and go back to work (here of course -we are assuming that no one else has stolen the worker 0 work yet; if -someone else stole it, worker 1 may still go to sleep, but that's ok, -since there is no more work to be had). +* Thread A looks for work, finds none. +* Thread B posts work but sees no sleeping threads. +* Thread A goes to sleep. -Now you may be wondering -- how does being sleepy help? What if, -instead of publishing its job right before worker 1 became sleepy, -worker 0 wait until right before worker 1 was going to go to sleep? In -other words, the sequence was like this: +The JEC protocol largely prevents this, but due to rollover, this prevention is +not complete. It is possible -- if unlikely -- that enough activity occurs for +Thread A to observe the same JEC value that it saw when getting sleepy. If the +new work being published came from *inside* the thread-pool, then this race +condition isn't too harmful. It means that we have fewer workers processing the +work then we should, but we won't deadlock. This seems like an acceptable risk +given that this is unlikely in practice. -- worker 1 gets sleepy -- worker 1 starts its scan, scanning worker 0's deque -- worker 0 publishes its job, but nobody is sleeping yet, so no wakeups occur -- worker 1 finshes its scan, goes to sleep, missing the wakeup +However, if the work was posted as an *external* job, that is a problem. In that +case, it's possible that all of our workers could go to sleep, and the external +job would never get processed. To prevent that, the sleeping protocol includes +one final check to see if the injector queue is empty before fully falling +asleep. Note that this final check occurs **after** the number of sleeping +threads has been incremented. We are not concerned therefore with races against +injections that occur after that increment, only before. -The reason that this doesn't occur is because, when worker 0 publishes -its job, it will see that there is a sleepy worker. It will clear the -global state to 0. Then, when worker 1 its scan, it will notice that -it is no longer sleepy, and hence it will not go to sleep. Instead it -will awaken and keep searching for work. +Unfortunately, there is one rather subtle point concerning this final check: +we wish to avoid the possibility that: -The sleepy worker phase thus also serves as a cheap way to signal that -work is around: instead of doing the whole dance of acquiring a lock -and issuing notifications, when we publish work we can just swap a -single atomic counter and let the sleepy worker notice that on their -own. +* work is pushed into the injection queue by an outside thread X, +* the sleepy thread S sees the JEC but it has rolled over and is equal +* the sleepy thread S reads the injection queue but does not see the work posted by X. -## Beyond seq-cst +This is possible because the C++ memory model typically offers guarantees of the +form "if you see the access A, then you must see those other accesses" -- but it +doesn't guarantee that you will see the access A (i.e., if you think of +processors with independent caches, you may be operating on very out of date +cache state). -Unfortunately, the C++11 memory model doesn't generally guarantee -seq-cst. And, somewhat annoyingly, it's not easy for the sleep module -**in isolation** to guarantee the properties the need. The key -challenge has to do with the *synchronized-with* relation. Typically, -we try to use acquire-release reasoning, and in that case the idea is -that **if** a load observes a store, it will also observe those writes -that preceded the store. But nothing says that the load **must** -observe the store -- at least not right away. +## Using seq-cst fences to prevent deadlock -The place that this is most relevant is the load in the `tickle()` -routine. The routine begins by reading from the global state. If it -sees anything other than 0, it then does a swap and -- if necessary -- -acquires a lock and does a notify. This load is a seq-cst load (as are -the other accesses in tickle). This ensures that it is sensible to -talk about a tickle happening *before* a worker gets sleepy and so -forth. +To overcome this problem, we have inserted two sequentially consistent fence +operations into the protocols above: -It turns out that to get things right, if we use the current tickle -routine, we have to use seq-cst operations **both in the sleep module -and when publishing work**. We'll walk through two scenarios to -show what I mean. +* One fence occurs after work is posted into the injection queue, but before the + counters are read (including the number of sleeping threads). + * Note that no fence is needed for work posted to internal queues, since it is ok + to overlook work in that case. +* One fence occurs after the number of sleeping threads is incremented, but + before the injection queue is read. -### Scenario 1: get-sleepy-then-get-tickled +### Proof sketch -This scenario shows why the operations in sleep must be seq-cst. We -want to ensure that once a worker gets sleepy, any other worker that -does a tickle will observe that. In other words, we want to ensure -that the following scenario **cannot happen**: +What follows is a "proof sketch" that the protocol is deadlock free. We model +two relevant bits of memory, the job injector queue J and the atomic counters C. -1. worker 1 is blocked on latch L -2. worker 1 becomes sleepy - - becoming sleepy involves a CAS on the global state to set it to 4 ("worker 1 is sleepy") -3. worker 0 sets latch L -4. worker 0 tickles **but does not see that worker 0 is sleepy** +Consider the actions of the injecting thread: -Let's diagram this. The notation `read_xxx(A) = V` means that a read -of location `A` was executed with the result `V`. The `xxx` is the -ordering and the location `A` is either `L` (latch) or `S` (global -state). I will leave the ordering on the latch as `xxx` as it is not -relevant here. The numbers correspond to the steps above. +* PushJob: Job is injected, which can be modeled as an atomic write to J with release semantics. +* PushFence: A sequentially consistent fence is executed. +* ReadSleepers: The counters C are read (they may also be incremented, but we just consider the read that comes first). -``` - worker 0 worker 1 - | +- 2: cas_sc(S, 4) -s| 3: write_xxx(L) + -b| 4: read_sc(S) = ??? <-sc-+ - v -``` +Meanwhile, the sleepy thread does the following: -Clearly, this cannot happen with sc orderings, because read 4 will -always return `4` here. However, if we tried to use acquire-release -orderings on the global state, then there would be **no guarantee** -that the tickle will observe that a sleepy worker occurred. We would -be guaranteed only that worker 0 would **eventually** observe that -worker 1 had become sleepy (and, at that time, that it would see other -writes). But it could take time -- and if we indeed miss that worker 1 -is sleepy, it could lead to deadlock or loss of efficiency, as -explained earlier. +* IncSleepers: The number of sleeping threads is incremented, which is atomic exchange to C. +* SleepFence: A sequentially consistent fence is executed. +* ReadJob: We look to see if the queue is empty, which is a read of J with acquire semantics. -### Scenario 2: tickle-then-get-sleepy +Either PushFence or SleepFence must come first: -
    - -This scenario shows why latch operations must *also* be seq-cst (and, -more generally, any operations that publish work before a tickle). We -wish to ensure that this ordering of events **cannot occur**: - -1. worker 1 is blocked on latch L -2. worker 1 reads latch L, sees false, starts searching for work -3. worker 0 sets latch L -4. worker 0 tickles - - the tickle reads from the global state, sees 0 -5. worker 1 finishes searching, becomes sleepy - - becoming sleepy involves a CAS on the global state to set it to 4 ("worker 1 is sleepy") -6. worker 1 reads latch L **but does not see that worker 0 set it** -7. worker 1 may then proceed to become sleepy - -In other words, we want to ensure that if worker 0 sets a latch and -does a tickle *before worker 1 gets sleepy*, then worker 1 will -observe that latch as set when it calls probe. We'll see that, with -the current scheme, this implies that the latch memory orderings must -be seq-cst as well. - -Here is the diagram: - -``` - worker 0 worker 1 - | 2: read_xxx(L) = false -s| 3: write_xxx(L, true) -b| 4: read_sc(S) = 0 -+ - | +-sc---> 5: cas_sc(S, 4) - v 6: read_xxx(L) = ??? -``` - -The diagram shows that each thread's actions are related by -*sequenced-before* (sb). Moreover the read and write of `S` are -related by `sc` (the seq-cst ordering). However, and this is crucial, -this **does not** imply that oper 4 *synchronizes-with* oper 5. This -is because a read never synchronizes-with a store, only the -reverse. Hence, if the latch were using acq-rel orderings, it would be -legal for oper 6 to return false. But if the latch were to use an -**sc** ordering itself, then we know that oper 6 must return true, -since `3 -sc-> 4 -sc-> 5 -sc-> 6`. - -**Note** that this means that, before we tickle, we must execute some -seq-cst stores to publish our work (and during the scan we must load -from those same locations) **if we wish to guarantee that the work we -published WILL be seen by the other threads** (as opposed to -*may*). This is true for setting a latch -- if a latch is set but -another thread misses it, then the system could deadlock. However, in -the case of pushing new work to a deque, we choose not to use a seqcst -ordering. This is for several reasons: - -- If we miss a wakeup, the consequences are less dire: we simply run - less efficiently (after all, the current thread will eventually - complete its current task and pop the new task off the deque). -- It is inconvenient: The deque code is beyond our control (it lies in another package). However, - we could create a dummy `AtomicBool` for each deque and do a seqcst write to it - (with whatever value) after we push to the deque, and a seqcst load whenever - we steal from the deque. -- The cost of using a dummy variable was found to be quite high for some benchmarks: - - 8-10% overhead on nbody-parreduce - - 15% overhead on increment-all - - 40% overhead on join-recursively - -### Alternative solutions - -In both cases above, our problems arose because tickle is merely -performing a seq-cst read. If we instead had tickle perform a release -*swap*, that would be a write action of the global state. No matter -the ordering mode, all writes to the same memory location have a total -ordering, and hence we would not have to worry about others storing a -value that we fail to read (as in scenario 1). Similarly, as a release -write, a swap during tickle would synchronize-with a later cas and so -scenario 2 should be averted. So you might wonder why we don't do -that. The simple reason was that it didn't perform as well! In my -measurements, many benchmarks were unaffected by using a swap, but -some of them were hit hard: - - 8-10% overhead on nbody-parreduce - - 35% overhead on increment-all - - 245% overhead on join-recursively +* If PushFence comes first, then PushJob must be visible to ReadJob. +* If SleepFence comes first, then IncSleepers is visible to ReadSleepers. \ No newline at end of file diff --git a/vendor/rayon-core/src/sleep/counters.rs b/vendor/rayon-core/src/sleep/counters.rs new file mode 100644 index 0000000000..626e24f1e2 --- /dev/null +++ b/vendor/rayon-core/src/sleep/counters.rs @@ -0,0 +1,269 @@ +use std::sync::atomic::{AtomicUsize, Ordering}; + +pub(super) struct AtomicCounters { + /// Packs together a number of counters. The counters are ordered as + /// follows, from least to most significant bits (here, we assuming + /// that [`THREADS_BITS`] is equal to 10): + /// + /// * Bits 0..10: Stores the number of **sleeping threads** + /// * Bits 10..20: Stores the number of **inactive threads** + /// * Bits 20..: Stores the **job event counter** (JEC) + /// + /// This uses 10 bits ([`THREADS_BITS`]) to encode the number of threads. Note + /// that the total number of bits (and hence the number of bits used for the + /// JEC) will depend on whether we are using a 32- or 64-bit architecture. + value: AtomicUsize, +} + +#[derive(Copy, Clone)] +pub(super) struct Counters { + word: usize, +} + +/// A value read from the **Jobs Event Counter**. +/// See the [`README.md`](README.md) for more +/// coverage of how the jobs event counter works. +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub(super) struct JobsEventCounter(usize); + +impl JobsEventCounter { + pub(super) const DUMMY: JobsEventCounter = JobsEventCounter(std::usize::MAX); + + #[inline] + pub(super) fn as_usize(self) -> usize { + self.0 + } + + /// The JEC "is sleepy" if the last thread to increment it was in the + /// process of becoming sleepy. This is indicated by its value being *even*. + /// When new jobs are posted, they check if the JEC is sleepy, and if so + /// they incremented it. + #[inline] + pub(super) fn is_sleepy(self) -> bool { + (self.as_usize() & 1) == 0 + } + + /// The JEC "is active" if the last thread to increment it was posting new + /// work. This is indicated by its value being *odd*. When threads get + /// sleepy, they will check if the JEC is active, and increment it. + #[inline] + pub(super) fn is_active(self) -> bool { + !self.is_sleepy() + } +} + +/// Number of bits used for the thread counters. +const THREADS_BITS: usize = 10; + +/// Bits to shift to select the sleeping threads +/// (used with `select_bits`). +const SLEEPING_SHIFT: usize = 0 * THREADS_BITS; + +/// Bits to shift to select the inactive threads +/// (used with `select_bits`). +const INACTIVE_SHIFT: usize = 1 * THREADS_BITS; + +/// Bits to shift to select the JEC +/// (use JOBS_BITS). +const JEC_SHIFT: usize = 2 * THREADS_BITS; + +/// Max value for the thread counters. +const THREADS_MAX: usize = (1 << THREADS_BITS) - 1; + +/// Constant that can be added to add one sleeping thread. +const ONE_SLEEPING: usize = 1; + +/// Constant that can be added to add one inactive thread. +/// An inactive thread is either idle, sleepy, or sleeping. +const ONE_INACTIVE: usize = 1 << INACTIVE_SHIFT; + +/// Constant that can be added to add one to the JEC. +const ONE_JEC: usize = 1 << JEC_SHIFT; + +impl AtomicCounters { + #[inline] + pub(super) fn new() -> AtomicCounters { + AtomicCounters { + value: AtomicUsize::new(0), + } + } + + /// Load and return the current value of the various counters. + /// This value can then be given to other method which will + /// attempt to update the counters via compare-and-swap. + #[inline] + pub(super) fn load(&self, ordering: Ordering) -> Counters { + Counters::new(self.value.load(ordering)) + } + + #[inline] + fn try_exchange(&self, old_value: Counters, new_value: Counters, ordering: Ordering) -> bool { + self.value + .compare_exchange(old_value.word, new_value.word, ordering, Ordering::Relaxed) + .is_ok() + } + + /// Adds an inactive thread. This cannot fail. + /// + /// This should be invoked when a thread enters its idle loop looking + /// for work. It is decremented when work is found. Note that it is + /// not decremented if the thread transitions from idle to sleepy or sleeping; + /// so the number of inactive threads is always greater-than-or-equal + /// to the number of sleeping threads. + #[inline] + pub(super) fn add_inactive_thread(&self) { + self.value.fetch_add(ONE_INACTIVE, Ordering::SeqCst); + } + + /// Increments the jobs event counter if `increment_when`, when applied to + /// the current value, is true. Used to toggle the JEC from even (sleepy) to + /// odd (active) or vice versa. Returns the final value of the counters, for + /// which `increment_when` is guaranteed to return false. + pub(super) fn increment_jobs_event_counter_if( + &self, + increment_when: impl Fn(JobsEventCounter) -> bool, + ) -> Counters { + loop { + let old_value = self.load(Ordering::SeqCst); + if increment_when(old_value.jobs_counter()) { + let new_value = old_value.plus(ONE_JEC); + if self.try_exchange(old_value, new_value, Ordering::SeqCst) { + return new_value; + } + } else { + return old_value; + } + } + } + + /// Subtracts an inactive thread. This cannot fail. It is invoked + /// when a thread finds work and hence becomes active. It returns the + /// number of sleeping threads to wake up (if any). + /// + /// See `add_inactive_thread`. + #[inline] + pub(super) fn sub_inactive_thread(&self) -> usize { + let old_value = Counters::new(self.value.fetch_sub(ONE_INACTIVE, Ordering::SeqCst)); + debug_assert!( + old_value.inactive_threads() > 0, + "sub_inactive_thread: old_value {:?} has no inactive threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() <= old_value.inactive_threads(), + "sub_inactive_thread: old_value {:?} had {} sleeping threads and {} inactive threads", + old_value, + old_value.sleeping_threads(), + old_value.inactive_threads(), + ); + + // Current heuristic: whenever an inactive thread goes away, if + // there are any sleeping threads, wake 'em up. + let sleeping_threads = old_value.sleeping_threads(); + std::cmp::min(sleeping_threads, 2) + } + + /// Subtracts a sleeping thread. This cannot fail, but it is only + /// safe to do if you you know the number of sleeping threads is + /// non-zero (i.e., because you have just awoken a sleeping + /// thread). + #[inline] + pub(super) fn sub_sleeping_thread(&self) { + let old_value = Counters::new(self.value.fetch_sub(ONE_SLEEPING, Ordering::SeqCst)); + debug_assert!( + old_value.sleeping_threads() > 0, + "sub_sleeping_thread: old_value {:?} had no sleeping threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() <= old_value.inactive_threads(), + "sub_sleeping_thread: old_value {:?} had {} sleeping threads and {} inactive threads", + old_value, + old_value.sleeping_threads(), + old_value.inactive_threads(), + ); + } + + #[inline] + pub(super) fn try_add_sleeping_thread(&self, old_value: Counters) -> bool { + debug_assert!( + old_value.inactive_threads() > 0, + "try_add_sleeping_thread: old_value {:?} has no inactive threads", + old_value, + ); + debug_assert!( + old_value.sleeping_threads() < THREADS_MAX, + "try_add_sleeping_thread: old_value {:?} has too many sleeping threads", + old_value, + ); + + let mut new_value = old_value; + new_value.word += ONE_SLEEPING; + + self.try_exchange(old_value, new_value, Ordering::SeqCst) + } +} + +#[inline] +fn select_thread(word: usize, shift: usize) -> usize { + ((word >> shift) as usize) & THREADS_MAX +} + +#[inline] +fn select_jec(word: usize) -> usize { + (word >> JEC_SHIFT) as usize +} + +impl Counters { + #[inline] + fn new(word: usize) -> Counters { + Counters { word } + } + + #[inline] + fn plus(self, word: usize) -> Counters { + Counters { + word: self.word + word, + } + } + + #[inline] + pub(super) fn jobs_counter(self) -> JobsEventCounter { + JobsEventCounter(select_jec(self.word)) + } + + /// The number of threads that are not actively + /// executing work. They may be idle, sleepy, or asleep. + #[inline] + pub(super) fn inactive_threads(self) -> usize { + select_thread(self.word, INACTIVE_SHIFT) + } + + #[inline] + pub(super) fn awake_but_idle_threads(self) -> usize { + debug_assert!( + self.sleeping_threads() <= self.inactive_threads(), + "sleeping threads: {} > raw idle threads {}", + self.sleeping_threads(), + self.inactive_threads() + ); + self.inactive_threads() - self.sleeping_threads() + } + + #[inline] + pub(super) fn sleeping_threads(self) -> usize { + select_thread(self.word, SLEEPING_SHIFT) + } +} + +impl std::fmt::Debug for Counters { + fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + let word = format!("{:016x}", self.word); + fmt.debug_struct("Counters") + .field("word", &word) + .field("jobs", &self.jobs_counter().0) + .field("inactive", &self.inactive_threads()) + .field("sleeping", &self.sleeping_threads()) + .finish() + } +} diff --git a/vendor/rayon-core/src/sleep/mod.rs b/vendor/rayon-core/src/sleep/mod.rs index 5e125ed2a5..2aa262c51c 100644 --- a/vendor/rayon-core/src/sleep/mod.rs +++ b/vendor/rayon-core/src/sleep/mod.rs @@ -1,281 +1,392 @@ //! Code that decides when workers should go to sleep. See README.md //! for an overview. +use crate::latch::CoreLatch; use crate::log::Event::*; -use std::sync::atomic::{AtomicUsize, Ordering}; +use crate::log::Logger; +use crossbeam_utils::CachePadded; +use std::sync::atomic::Ordering; use std::sync::{Condvar, Mutex}; use std::thread; use std::usize; +mod counters; +use self::counters::{AtomicCounters, JobsEventCounter}; + +/// The `Sleep` struct is embedded into each registry. It governs the waking and sleeping +/// of workers. It has callbacks that are invoked periodically at significant events, +/// such as when workers are looping and looking for work, when latches are set, or when +/// jobs are published, and it either blocks threads or wakes them in response to these +/// events. See the [`README.md`] in this module for more details. +/// +/// [`README.md`] README.md pub(super) struct Sleep { - state: AtomicUsize, - data: Mutex<()>, - tickle: Condvar, + logger: Logger, + + /// One "sleep state" per worker. Used to track if a worker is sleeping and to have + /// them block. + worker_sleep_states: Vec>, + + counters: AtomicCounters, } -const AWAKE: usize = 0; -const SLEEPING: usize = 1; +/// An instance of this struct is created when a thread becomes idle. +/// It is consumed when the thread finds work, and passed by `&mut` +/// reference for operations that preserve the idle state. (In other +/// words, producing one of these structs is evidence the thread is +/// idle.) It tracks state such as how long the thread has been idle. +pub(super) struct IdleState { + /// What is worker index of the idle thread? + worker_index: usize, -const ROUNDS_UNTIL_SLEEPY: usize = 32; -const ROUNDS_UNTIL_ASLEEP: usize = 64; + /// How many rounds have we been circling without sleeping? + rounds: u32, + + /// Once we become sleepy, what was the sleepy counter value? + /// Set to `INVALID_SLEEPY_COUNTER` otherwise. + jobs_counter: JobsEventCounter, +} + +/// The "sleep state" for an individual worker. +#[derive(Default)] +struct WorkerSleepState { + /// Set to true when the worker goes to sleep; set to false when + /// the worker is notified or when it wakes. + is_blocked: Mutex, + + condvar: Condvar, +} + +const ROUNDS_UNTIL_SLEEPY: u32 = 32; +const ROUNDS_UNTIL_SLEEPING: u32 = ROUNDS_UNTIL_SLEEPY + 1; impl Sleep { - pub(super) fn new() -> Sleep { + pub(super) fn new(logger: Logger, n_threads: usize) -> Sleep { Sleep { - state: AtomicUsize::new(AWAKE), - data: Mutex::new(()), - tickle: Condvar::new(), + logger, + worker_sleep_states: (0..n_threads).map(|_| Default::default()).collect(), + counters: AtomicCounters::new(), } } - fn anyone_sleeping(&self, state: usize) -> bool { - state & SLEEPING != 0 - } - - fn any_worker_is_sleepy(&self, state: usize) -> bool { - (state >> 1) != 0 - } - - fn worker_is_sleepy(&self, state: usize, worker_index: usize) -> bool { - (state >> 1) == (worker_index + 1) - } - - fn with_sleepy_worker(&self, state: usize, worker_index: usize) -> usize { - debug_assert!(state == AWAKE || state == SLEEPING); - ((worker_index + 1) << 1) + state - } - #[inline] - pub(super) fn work_found(&self, worker_index: usize, yields: usize) -> usize { - log!(FoundWork { + pub(super) fn start_looking(&self, worker_index: usize, latch: &CoreLatch) -> IdleState { + self.logger.log(|| ThreadIdle { worker: worker_index, - yields: yields, + latch_addr: latch.addr(), }); - if yields > ROUNDS_UNTIL_SLEEPY { - // FIXME tickling here is a bit extreme; mostly we want to "release the lock" - // from us being sleepy, we don't necessarily need to wake others - // who are sleeping - self.tickle(worker_index); + + self.counters.add_inactive_thread(); + + IdleState { + worker_index, + rounds: 0, + jobs_counter: JobsEventCounter::DUMMY, } - 0 } #[inline] - pub(super) fn no_work_found(&self, worker_index: usize, yields: usize) -> usize { - log!(DidNotFindWork { - worker: worker_index, - yields: yields, + pub(super) fn work_found(&self, idle_state: IdleState) { + self.logger.log(|| ThreadFoundWork { + worker: idle_state.worker_index, + yields: idle_state.rounds, }); - if yields < ROUNDS_UNTIL_SLEEPY { + + // If we were the last idle thread and other threads are still sleeping, + // then we should wake up another thread. + let threads_to_wake = self.counters.sub_inactive_thread(); + self.wake_any_threads(threads_to_wake as u32); + } + + #[inline] + pub(super) fn no_work_found( + &self, + idle_state: &mut IdleState, + latch: &CoreLatch, + has_injected_jobs: impl FnOnce() -> bool, + ) { + if idle_state.rounds < ROUNDS_UNTIL_SLEEPY { thread::yield_now(); - yields + 1 - } else if yields == ROUNDS_UNTIL_SLEEPY { + idle_state.rounds += 1; + } else if idle_state.rounds == ROUNDS_UNTIL_SLEEPY { + idle_state.jobs_counter = self.announce_sleepy(idle_state.worker_index); + idle_state.rounds += 1; thread::yield_now(); - if self.get_sleepy(worker_index) { - yields + 1 - } else { - yields - } - } else if yields < ROUNDS_UNTIL_ASLEEP { + } else if idle_state.rounds < ROUNDS_UNTIL_SLEEPING { + idle_state.rounds += 1; thread::yield_now(); - if self.still_sleepy(worker_index) { - yields + 1 - } else { - log!(GotInterrupted { - worker: worker_index - }); - 0 - } } else { - debug_assert_eq!(yields, ROUNDS_UNTIL_ASLEEP); - self.sleep(worker_index); - 0 - } - } - - pub(super) fn tickle(&self, worker_index: usize) { - // As described in README.md, this load must be SeqCst so as to ensure that: - // - if anyone is sleepy or asleep, we *definitely* see that now (and not eventually); - // - if anyone after us becomes sleepy or asleep, they see memory events that - // precede the call to `tickle()`, even though we did not do a write. - let old_state = self.state.load(Ordering::SeqCst); - if old_state != AWAKE { - self.tickle_cold(worker_index); + debug_assert_eq!(idle_state.rounds, ROUNDS_UNTIL_SLEEPING); + self.sleep(idle_state, latch, has_injected_jobs); } } #[cold] - fn tickle_cold(&self, worker_index: usize) { - // The `Release` ordering here suffices. The reasoning is that - // the atomic's own natural ordering ensure that any attempt - // to become sleepy/asleep either will come before/after this - // swap. If it comes *after*, then Release is good because we - // want it to see the action that generated this tickle. If it - // comes *before*, then we will see it here (but not other - // memory writes from that thread). If the other worker was - // becoming sleepy, the other writes don't matter. If they - // were were going to sleep, we will acquire lock and hence - // acquire their reads. - let old_state = self.state.swap(AWAKE, Ordering::Release); - log!(Tickle { + fn announce_sleepy(&self, worker_index: usize) -> JobsEventCounter { + let counters = self + .counters + .increment_jobs_event_counter_if(JobsEventCounter::is_active); + let jobs_counter = counters.jobs_counter(); + self.logger.log(|| ThreadSleepy { worker: worker_index, - old_state: old_state, + jobs_counter: jobs_counter.as_usize(), }); - if self.anyone_sleeping(old_state) { - let _data = self.data.lock().unwrap(); - self.tickle.notify_all(); - } + jobs_counter } - fn get_sleepy(&self, worker_index: usize) -> bool { - loop { - // Acquire ordering suffices here. If some other worker - // was sleepy but no longer is, we will eventually see - // that, and until then it doesn't hurt to spin. - // Otherwise, we will do a compare-exchange which will - // assert a stronger order and acquire any reads etc that - // we must see. - let state = self.state.load(Ordering::Acquire); - log!(GetSleepy { + #[cold] + fn sleep( + &self, + idle_state: &mut IdleState, + latch: &CoreLatch, + has_injected_jobs: impl FnOnce() -> bool, + ) { + let worker_index = idle_state.worker_index; + + if !latch.get_sleepy() { + self.logger.log(|| ThreadSleepInterruptedByLatch { worker: worker_index, - state: state, + latch_addr: latch.addr(), }); - if self.any_worker_is_sleepy(state) { - // somebody else is already sleepy, so we'll just wait our turn - debug_assert!( - !self.worker_is_sleepy(state, worker_index), - "worker {} called `is_sleepy()`, \ - but they are already sleepy (state={})", - worker_index, - state - ); - return false; - } else { - // make ourselves the sleepy one - let new_state = self.with_sleepy_worker(state, worker_index); - // This must be SeqCst on success because we want to - // ensure: - // - // - That we observe any writes that preceded - // some prior tickle, and that tickle may have only - // done a SeqCst load on `self.state`. - // - That any subsequent tickle *definitely* sees this store. - // - // See the section on "Ensuring Sequentially - // Consistency" in README.md for more details. - // - // The failure ordering doesn't matter since we are - // about to spin around and do a fresh load. - if self - .state - .compare_exchange(state, new_state, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() - { - log!(GotSleepy { - worker: worker_index, - old_state: state, - new_state: new_state, - }); - return true; - } - } + return; } - } - fn still_sleepy(&self, worker_index: usize) -> bool { - let state = self.state.load(Ordering::SeqCst); - self.worker_is_sleepy(state, worker_index) - } + let sleep_state = &self.worker_sleep_states[worker_index]; + let mut is_blocked = sleep_state.is_blocked.lock().unwrap(); + debug_assert!(!*is_blocked); + + // Our latch was signalled. We should wake back up fully as we + // wil have some stuff to do. + if !latch.fall_asleep() { + self.logger.log(|| ThreadSleepInterruptedByLatch { + worker: worker_index, + latch_addr: latch.addr(), + }); + + idle_state.wake_fully(); + return; + } - fn sleep(&self, worker_index: usize) { loop { - // Acquire here suffices. If we observe that the current worker is still - // sleepy, then in fact we know that no writes have occurred, and anyhow - // we are going to do a CAS which will synchronize. - // - // If we observe that the state has changed, it must be - // due to a tickle, and then the Acquire means we also see - // any events that occured before that. - let state = self.state.load(Ordering::Acquire); - if self.worker_is_sleepy(state, worker_index) { - // It is important that we hold the lock when we do - // the CAS. Otherwise, if we were to CAS first, then - // the following sequence of events could occur: - // - // - Thread A (us) sets state to SLEEPING. - // - Thread B sets state to AWAKE. - // - Thread C sets state to SLEEPY(C). - // - Thread C sets state to SLEEPING. - // - Thread A reawakens, acquires lock, and goes to sleep. - // - // Now we missed the wake-up from thread B! But since - // we have the lock when we set the state to sleeping, - // that cannot happen. Note that the swap `tickle()` - // is not part of the lock, though, so let's play that - // out: - // - // # Scenario 1 - // - // - A loads state and see SLEEPY(A) - // - B swaps to AWAKE. - // - A locks, fails CAS - // - // # Scenario 2 - // - // - A loads state and see SLEEPY(A) - // - A locks, performs CAS - // - B swaps to AWAKE. - // - A waits (releasing lock) - // - B locks, notifies - // - // In general, acquiring the lock inside the loop - // seems like it could lead to bad performance, but - // actually it should be ok. This is because the only - // reason for the `compare_exchange` to fail is if an - // awaken comes, in which case the next cycle around - // the loop will just return. - let data = self.data.lock().unwrap(); + let counters = self.counters.load(Ordering::SeqCst); - // This must be SeqCst on success because we want to - // ensure: - // - // - That we observe any writes that preceded - // some prior tickle, and that tickle may have only - // done a SeqCst load on `self.state`. - // - That any subsequent tickle *definitely* sees this store. - // - // See the section on "Ensuring Sequentially - // Consistency" in README.md for more details. - // - // The failure ordering doesn't matter since we are - // about to spin around and do a fresh load. - if self - .state - .compare_exchange(state, SLEEPING, Ordering::SeqCst, Ordering::Relaxed) - .is_ok() - { - // Don't do this in a loop. If we do it in a loop, we need - // some way to distinguish the ABA scenario where the pool - // was awoken but before we could process it somebody went - // to sleep. Note that if we get a false wakeup it's not a - // problem for us, we'll just loop around and maybe get - // sleepy again. - log!(FellAsleep { - worker: worker_index - }); - let _ = self.tickle.wait(data).unwrap(); - log!(GotAwoken { - worker: worker_index - }); - return; - } - } else { - log!(GotInterrupted { - worker: worker_index + // Check if the JEC has changed since we got sleepy. + debug_assert!(idle_state.jobs_counter.is_sleepy()); + if counters.jobs_counter() != idle_state.jobs_counter { + // JEC has changed, so a new job was posted, but for some reason + // we didn't see it. We should return to just before the SLEEPY + // state so we can do another search and (if we fail to find + // work) go back to sleep. + self.logger.log(|| ThreadSleepInterruptedByJob { + worker: worker_index, }); + + idle_state.wake_partly(); + latch.wake_up(); return; } + + // Otherwise, let's move from IDLE to SLEEPING. + if self.counters.try_add_sleeping_thread(counters) { + break; + } + } + + // Successfully registered as asleep. + + self.logger.log(|| ThreadSleeping { + worker: worker_index, + latch_addr: latch.addr(), + }); + + // We have one last check for injected jobs to do. This protects against + // deadlock in the very unlikely event that + // + // - an external job is being injected while we are sleepy + // - that job triggers the rollover over the JEC such that we don't see it + // - we are the last active worker thread + std::sync::atomic::fence(Ordering::SeqCst); + if has_injected_jobs() { + // If we see an externally injected job, then we have to 'wake + // ourselves up'. (Ordinarily, `sub_sleeping_thread` is invoked by + // the one that wakes us.) + self.counters.sub_sleeping_thread(); + } else { + // If we don't see an injected job (the normal case), then flag + // ourselves as asleep and wait till we are notified. + // + // (Note that `is_blocked` is held under a mutex and the mutex was + // acquired *before* we incremented the "sleepy counter". This means + // that whomever is coming to wake us will have to wait until we + // release the mutex in the call to `wait`, so they will see this + // boolean as true.) + *is_blocked = true; + while *is_blocked { + is_blocked = sleep_state.condvar.wait(is_blocked).unwrap(); + } + } + + // Update other state: + idle_state.wake_fully(); + latch.wake_up(); + + self.logger.log(|| ThreadAwoken { + worker: worker_index, + latch_addr: latch.addr(), + }); + } + + /// Notify the given thread that it should wake up (if it is + /// sleeping). When this method is invoked, we typically know the + /// thread is asleep, though in rare cases it could have been + /// awoken by (e.g.) new work having been posted. + pub(super) fn notify_worker_latch_is_set(&self, target_worker_index: usize) { + self.wake_specific_thread(target_worker_index); + } + + /// Signals that `num_jobs` new jobs were injected into the thread + /// pool from outside. This function will ensure that there are + /// threads available to process them, waking threads from sleep + /// if necessary. + /// + /// # Parameters + /// + /// - `source_worker_index` -- index of the thread that did the + /// push, or `usize::MAX` if this came from outside the thread + /// pool -- it is used only for logging. + /// - `num_jobs` -- lower bound on number of jobs available for stealing. + /// We'll try to get at least one thread per job. + #[inline] + pub(super) fn new_injected_jobs( + &self, + source_worker_index: usize, + num_jobs: u32, + queue_was_empty: bool, + ) { + // This fence is needed to guarantee that threads + // as they are about to fall asleep, observe any + // new jobs that may have been injected. + std::sync::atomic::fence(Ordering::SeqCst); + + self.new_jobs(source_worker_index, num_jobs, queue_was_empty) + } + + /// Signals that `num_jobs` new jobs were pushed onto a thread's + /// local deque. This function will try to ensure that there are + /// threads available to process them, waking threads from sleep + /// if necessary. However, this is not guaranteed: under certain + /// race conditions, the function may fail to wake any new + /// threads; in that case the existing thread should eventually + /// pop the job. + /// + /// # Parameters + /// + /// - `source_worker_index` -- index of the thread that did the + /// push, or `usize::MAX` if this came from outside the thread + /// pool -- it is used only for logging. + /// - `num_jobs` -- lower bound on number of jobs available for stealing. + /// We'll try to get at least one thread per job. + #[inline] + pub(super) fn new_internal_jobs( + &self, + source_worker_index: usize, + num_jobs: u32, + queue_was_empty: bool, + ) { + self.new_jobs(source_worker_index, num_jobs, queue_was_empty) + } + + /// Common helper for `new_injected_jobs` and `new_internal_jobs`. + #[inline] + fn new_jobs(&self, source_worker_index: usize, num_jobs: u32, queue_was_empty: bool) { + // Read the counters and -- if sleepy workers have announced themselves + // -- announce that there is now work available. The final value of `counters` + // with which we exit the loop thus corresponds to a state when + let counters = self + .counters + .increment_jobs_event_counter_if(JobsEventCounter::is_sleepy); + let num_awake_but_idle = counters.awake_but_idle_threads(); + let num_sleepers = counters.sleeping_threads(); + + self.logger.log(|| JobThreadCounts { + worker: source_worker_index, + num_idle: num_awake_but_idle as u16, + num_sleepers: num_sleepers as u16, + }); + + if num_sleepers == 0 { + // nobody to wake + return; + } + + // Promote from u16 to u32 so we can interoperate with + // num_jobs more easily. + let num_awake_but_idle = num_awake_but_idle as u32; + let num_sleepers = num_sleepers as u32; + + // If the queue is non-empty, then we always wake up a worker + // -- clearly the existing idle jobs aren't enough. Otherwise, + // check to see if we have enough idle workers. + if !queue_was_empty { + let num_to_wake = std::cmp::min(num_jobs, num_sleepers); + self.wake_any_threads(num_to_wake); + } else if num_awake_but_idle < num_jobs { + let num_to_wake = std::cmp::min(num_jobs - num_awake_but_idle, num_sleepers); + self.wake_any_threads(num_to_wake); + } + } + + #[cold] + fn wake_any_threads(&self, mut num_to_wake: u32) { + if num_to_wake > 0 { + for i in 0..self.worker_sleep_states.len() { + if self.wake_specific_thread(i) { + num_to_wake -= 1; + if num_to_wake == 0 { + return; + } + } + } + } + } + + fn wake_specific_thread(&self, index: usize) -> bool { + let sleep_state = &self.worker_sleep_states[index]; + + let mut is_blocked = sleep_state.is_blocked.lock().unwrap(); + if *is_blocked { + *is_blocked = false; + sleep_state.condvar.notify_one(); + + // When the thread went to sleep, it will have incremented + // this value. When we wake it, its our job to decrement + // it. We could have the thread do it, but that would + // introduce a delay between when the thread was + // *notified* and when this counter was decremented. That + // might mislead people with new work into thinking that + // there are sleeping threads that they should try to + // wake, when in fact there is nothing left for them to + // do. + self.counters.sub_sleeping_thread(); + + self.logger.log(|| ThreadNotify { worker: index }); + + true + } else { + false } } } + +impl IdleState { + fn wake_fully(&mut self) { + self.rounds = 0; + self.jobs_counter = JobsEventCounter::DUMMY; + } + + fn wake_partly(&mut self) { + self.rounds = ROUNDS_UNTIL_SLEEPY; + self.jobs_counter = JobsEventCounter::DUMMY; + } +} diff --git a/vendor/rayon-core/src/spawn/mod.rs b/vendor/rayon-core/src/spawn/mod.rs index d9eb2ed55b..00061037a6 100644 --- a/vendor/rayon-core/src/spawn/mod.rs +++ b/vendor/rayon-core/src/spawn/mod.rs @@ -21,8 +21,7 @@ use std::sync::Arc; /// /// This API assumes that the closure is executed purely for its /// side-effects (i.e., it might send messages, modify data protected -/// by a mutex, or some such thing). If you want to compute a result, -/// consider `spawn_future()`. +/// by a mutex, or some such thing). /// /// There is no guaranteed order of execution for spawns, given that /// other threads may steal tasks at any time. However, they are diff --git a/vendor/rayon-core/src/thread_pool/mod.rs b/vendor/rayon-core/src/thread_pool/mod.rs index 065d236e00..2209f63046 100644 --- a/vendor/rayon-core/src/thread_pool/mod.rs +++ b/vendor/rayon-core/src/thread_pool/mod.rs @@ -200,7 +200,7 @@ impl ThreadPool { /// [scope]: fn.scope.html pub fn scope<'scope, OP, R>(&self, op: OP) -> R where - OP: for<'s> FnOnce(&'s Scope<'scope>) -> R + 'scope + Send, + OP: FnOnce(&Scope<'scope>) -> R + Send, R: Send, { self.install(|| scope(op)) @@ -215,7 +215,7 @@ impl ThreadPool { /// [scope_fifo]: fn.scope_fifo.html pub fn scope_fifo<'scope, OP, R>(&self, op: OP) -> R where - OP: for<'s> FnOnce(&'s ScopeFifo<'scope>) -> R + 'scope + Send, + OP: FnOnce(&ScopeFifo<'scope>) -> R + Send, R: Send, { self.install(|| scope_fifo(op)) diff --git a/vendor/rayon-core/src/thread_pool/test.rs b/vendor/rayon-core/src/thread_pool/test.rs index 0d6815e129..8d1c90ca18 100644 --- a/vendor/rayon-core/src/thread_pool/test.rs +++ b/vendor/rayon-core/src/thread_pool/test.rs @@ -4,12 +4,9 @@ use std::sync::atomic::{AtomicUsize, Ordering}; use std::sync::mpsc::channel; use std::sync::{Arc, Mutex}; -use crate::join; -use crate::thread_pool::ThreadPool; - #[allow(deprecated)] use crate::Configuration; -use crate::ThreadPoolBuilder; +use crate::{join, Scope, ScopeFifo, ThreadPool, ThreadPoolBuilder}; #[test] #[should_panic(expected = "Hello, world!")] @@ -267,3 +264,75 @@ fn spawn_fifo_order() { let expected: Vec = (0..10).collect(); // FIFO -> natural order assert_eq!(vec, expected); } + +#[test] +fn nested_scopes() { + // Create matching scopes for every thread pool. + fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&Scope<'scope>>, op: OP) + where + OP: FnOnce(&[&Scope<'scope>]) + Send, + { + if let Some((pool, tail)) = pools.split_first() { + pool.scope(move |s| { + // This move reduces the reference lifetimes by variance to match s, + // but the actual scopes are still tied to the invariant 'scope. + let mut scopes = scopes; + scopes.push(s); + nest(tail, scopes, op) + }) + } else { + (op)(&scopes) + } + } + + let pools: Vec<_> = (0..10) + .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) + .collect(); + + let counter = AtomicUsize::new(0); + nest(&pools, vec![], |scopes| { + for &s in scopes { + s.spawn(|_| { + // Our 'scope lets us borrow the counter in every pool. + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + assert_eq!(counter.into_inner(), pools.len()); +} + +#[test] +fn nested_fifo_scopes() { + // Create matching fifo scopes for every thread pool. + fn nest<'scope, OP>(pools: &[ThreadPool], scopes: Vec<&ScopeFifo<'scope>>, op: OP) + where + OP: FnOnce(&[&ScopeFifo<'scope>]) + Send, + { + if let Some((pool, tail)) = pools.split_first() { + pool.scope_fifo(move |s| { + // This move reduces the reference lifetimes by variance to match s, + // but the actual scopes are still tied to the invariant 'scope. + let mut scopes = scopes; + scopes.push(s); + nest(tail, scopes, op) + }) + } else { + (op)(&scopes) + } + } + + let pools: Vec<_> = (0..10) + .map(|_| ThreadPoolBuilder::new().num_threads(1).build().unwrap()) + .collect(); + + let counter = AtomicUsize::new(0); + nest(&pools, vec![], |scopes| { + for &s in scopes { + s.spawn_fifo(|_| { + // Our 'scope lets us borrow the counter in every pool. + counter.fetch_add(1, Ordering::Relaxed); + }); + } + }); + assert_eq!(counter.into_inner(), pools.len()); +} diff --git a/vendor/rayon/.cargo-checksum.json b/vendor/rayon/.cargo-checksum.json index 516afd63a0..37426500c5 100644 --- a/vendor/rayon/.cargo-checksum.json +++ b/vendor/rayon/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"917614b366caa797c3f6c185f2a9057339eedb21fd6e1426fdedd31be85640fe","Cargo.toml":"6ef35fc372f85b755a234e465f05c703ad1776905e634aa273f9db0b688c44c9","FAQ.md":"23e5c1ac0158e9e33dae4d3f48bb6b63037ee16e55c476da4cbeedcabe0be0fc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"443319f333d92d6ad50ade54334c49609e5b116442639b4134b2dd95b49f8d8f","RELEASES.md":"025aec0504abf151a1353f8cf1fa2e899ef2ab66602ff2755038721ed3ae0236","build.rs":"2ec988611a2efa7aa89a1835731edcd15d019787d8184e1dac3126756121c586","examples/README.md":"537e6fe9cf696fd4ada9c08bf31055ed6e366ed65668a523e7c5fde77f97c8d3","examples/cpu_monitor.rs":"cc21a2635059ab2d86622d86508ce360c105417522b7bd1f8e0b3ac845ed484a","src/collections/binary_heap.rs":"55f2d9de4b53ce1e9e353362dc344f432e4ee0400dff6d5ea85a06a41eaa6b3e","src/collections/btree_map.rs":"d3094ed5c54620f81a86133f52e74164bae9f0137745eb66e6d31db2e942bcab","src/collections/btree_set.rs":"7de12e388d36cb2f8672bc3b68aed5b44d047c9f5fe262a7260584634299480f","src/collections/hash_map.rs":"f196ff806a334093d8f4d2d72f6e257517209996f5a6a2031b183d5130720bb4","src/collections/hash_set.rs":"2c0a8a91523a076d9153e6b7c19d2aabecc4706253b25fd6b20a0bd389253e60","src/collections/linked_list.rs":"bef7f32da49b55db76cfefa0afa4789a6979e08a69427e49bab2874967163fef","src/collections/mod.rs":"037660cbdd5907808f7df59fa69993582bf978ecaf125a83a1205452bb505a53","src/collections/vec_deque.rs":"51b3f019c05fcaff9916e258312146c540635cb38941291748f01926d4955a72","src/compile_fail/cannot_collect_filtermap_data.rs":"6a141076c14f95e31bed3433d531bc05d806eed9e0018d1b21420d7ab2fc7eb9","src/compile_fail/cannot_zip_filtered_data.rs":"a28cfb3d00b8d277bfa77a10ca132f972e8f100080ef602fdd3c6fd36ad2a156","src/compile_fail/cell_par_iter.rs":"4f076862d9c66ed42a642a5be97116ca5982608ab76816a8f8305182bf463e9e","src/compile_fail/mod.rs":"2c346e4b52941fe0ac2667eeb753c0c21a1f998a544bb9d9167f200caba0a7bb","src/compile_fail/must_use.rs":"8f26766396842fd83790f1afdc20a926bbc1ed9b5cede8d6bec172c1e7d42ed2","src/compile_fail/no_send_par_iter.rs":"e78cd466a61081a0738f63b4e74249e40c37b95240e47e3faeab6ffdb6a8f14c","src/compile_fail/rc_par_iter.rs":"0faf3d26a665c3e2acc2f2f1d66ee234e561d24442efa4980a5e946e1cb2eba3","src/delegate.rs":"897b9118443a50f1690b2506bc349cd233496eea05fa38f0bce821809a23e528","src/iter/chain.rs":"f82a25577ca36bac93b5a13e75dcd70e8cee381b9baa5993dd645f0714fb9eb6","src/iter/chunks.rs":"8ab345783cb7412438eed33264d7db79873801784af7dab25291c349c678085f","src/iter/cloned.rs":"35e1c864f99f7bc93c258c4976d15ccfc1d04df969dc878fd03d35f6799377f7","src/iter/collect/consumer.rs":"cb6f17f46fc56a782afb2a0e023338ebedefe3e7968a84fa8e513c6b89344a64","src/iter/collect/mod.rs":"cf1a50ae7bb6f13578635a61e7bfd996de3c27c184c5ff674d3f3014cc3de519","src/iter/collect/test.rs":"7fcf412afa8461312f7893a36e0a50baca0e495a1fe20885dc62b52d8f68b978","src/iter/copied.rs":"4a5de15719de5e6337925f993e0a55c87d8a62b8bbf6c0a4e2bd877136581afc","src/iter/empty.rs":"3cb2d05721aab1a4d9e9c5813473e1646116c1ea570e26d9ac81e083688a0b7d","src/iter/enumerate.rs":"3204255723a93b3275cf0f208939de8960b13a9b13b8c2ba6b664e65da21cd87","src/iter/extend.rs":"11c46e4cab6b1f3f3d82e1555f92c79b2ea9a833258b88142f14dc6d3eed4e15","src/iter/filter.rs":"c8ceea2f71afd1ffc7c713d8683e337e2c4bc3327f47d25116039ab7d950376f","src/iter/filter_map.rs":"18b2fa2d5119297ed6218e353ebb50e7cf4c853e76b9feffd2f332a885d8811d","src/iter/find.rs":"73b11b97eae7234099a05b5f59c937fe488e6a8574b9c9e4e852a7fa86341117","src/iter/find_first_last/mod.rs":"fa7d7692d81ecdbecb178606ad3b1b00c80e5e4159c57d34929b012b0bea0c82","src/iter/find_first_last/test.rs":"2052eb8b87c5a0a0d49a76c83d9d74f81be18aad52ceb1b06d7e209f4fefba94","src/iter/flat_map.rs":"073f67369d2e8b8ed217174bed5ad427e9ddc1b55e57f2c0e5e8b22a61a59b71","src/iter/flatten.rs":"a9144e37855b33d1c08f1c4179e0089ed6bc7d4b645fcf36c46a8ed687961d07","src/iter/fold.rs":"874259b408d7f8cdc376d34276d37c1837950c035ff780de8281d1edf65ded9f","src/iter/for_each.rs":"7af0e21ed8479eec65831d1409f61a88d45a31764f2385ec759eda1a46d388b2","src/iter/from_par_iter.rs":"9439b1ae01db2c7545d6416108700dfbafcff3f584e81704cf985ab1d986b660","src/iter/inspect.rs":"d4f5c031e4a79c01b8439b5e3c78b637ecb4bcf191c8d98ec9f31a0b51977abc","src/iter/interleave.rs":"dcda8d2bd46de25227ac88243ff6ca97fcf1dbb89f935b651fd04c1ecf1abe8a","src/iter/interleave_shortest.rs":"a2b1f31ea4cb29f4761d3724feddcf5a96e1f21fd623f95c85a8659294a6745a","src/iter/intersperse.rs":"6b5d3d826ed3499ba78f0ff07468d96a0e104c7ee142a2ced6be8143b43241a5","src/iter/len.rs":"427548a874aa3036adbaf12034f5065382a8e98f9131b13c6a8c92c7b97e596d","src/iter/map.rs":"66e6db399de12327fec29d069462347dd16fd96d450b121ba8227e32e51552d1","src/iter/map_with.rs":"f83950016bb02addecec049fda73663861c80232477a7b89b7e8718291a4b481","src/iter/mod.rs":"6018cee2df11c5615a028ad97539206fda3c0a92f640f4de24244b85bf63f90e","src/iter/multizip.rs":"10ec107f6673c9bc6d1d611e11b716c37e8601ab2f4257a460c4bc4962771347","src/iter/noop.rs":"5be6332ddfbb8fdbae1ffdb00983950a8b37a295bcb58e9a265b33806ee504e6","src/iter/once.rs":"fcebffc374dcdd206d13311dcc2e7d7a04da5687658b2f3ec3409f03ed12774b","src/iter/panic_fuse.rs":"2a4d43fa4e717629de7f69eb180f13db90ef95004975cfa20dcfaacc80435015","src/iter/par_bridge.rs":"26cd2dbc57e5dd2c1b99b19f8ee66900e5ad7e99a5d8b22e947426f944f72b37","src/iter/plumbing/README.md":"d9ae3d57a37af5645b1c79029dd808933279d6853b30163cd0d71ead2a9a5002","src/iter/plumbing/mod.rs":"1156c55a15b651d161f463cb86b2f602f6246a3c7f8a82fb484db12aa6a60091","src/iter/product.rs":"da69f4781c2275c4a176432994c3fd80ea1f296afe47b329de61b1d733d990df","src/iter/reduce.rs":"2f5d6e07d7c0de2360505fa5d9198c31fd43ba7e58a6ec40f79edec19319e502","src/iter/repeat.rs":"ed46b17b79d8569f9d67b50585b116ee0293e1d6c17c0dc683c66644f6a58fd5","src/iter/rev.rs":"c4c796d7cb6398e74bef043a080403acccdf70f6a4e74b242e530d1718969b8f","src/iter/skip.rs":"f1566b395a2b2e95ee14a056b28cf2532f2f9c4d2abc379a1d313ff5a837a51f","src/iter/splitter.rs":"0024db04b4430c2a1e8c921cec86af641f612f877f3675b15df0da9122de5f00","src/iter/step_by.rs":"7e02b9c18a2dc14f637959d0f90dabe877dd51d6dcd085a01c536be59c2bbcdb","src/iter/sum.rs":"cf11d996507ceba39524a102559b84289e776f8fe5772114e00ae2112b38c47c","src/iter/take.rs":"e47eeca1249553b0dfaf54cd8f99026be68db76b42f1f29e09c07a98c165c50a","src/iter/test.rs":"52ab229c2d8c4d4baf0d0cb439accbced982da088d66c3b404c97ef6bc0e136c","src/iter/try_fold.rs":"585d5a69480e1510f3d006c3bff810c98dd009ab44fa9a15a76beeea4fd8c3f2","src/iter/try_reduce.rs":"747f46db1f2d7178b40735828d877b06802296f0d69662d176062920e9a64067","src/iter/try_reduce_with.rs":"1958debdc53fab22b0d0eb603f22647fd96af44a4308549a56dd71256edd1525","src/iter/unzip.rs":"1d617107bd04cd944e64bd83482206ebfdb894a1778dcbbfc9021addf02234e6","src/iter/update.rs":"08a222cf7f8f2f82389ca48d89ecef3a88e205d21ce249f2ba15a4ff85134473","src/iter/while_some.rs":"a514891d7a07031354b48e377c239ff330d0955f184abc57a69d2a193e7fcb45","src/iter/zip.rs":"4d908f75a10b5e9b68d012bbba289f3e5e9d6a9570ce0f56fc1b4f9d96860499","src/iter/zip_eq.rs":"4c18d8f7a78e197a3268c9ef74d16690f8c960407c18bb63dc6905a2fe2bde62","src/lib.rs":"1d7a4967235467de2668c1cd94597dea339a7c20acedad6ca17f1f5126c085a0","src/math.rs":"181859dc38d787143016ce2952b6e45c5ec085d942a591bd5eaf6fe8905711a9","src/option.rs":"00979a9bb8f42629f2b956a6cfbd286fc8a41ffbbec85f1b5d0f0da5615dac9c","src/par_either.rs":"afa4b04ba6ea1d37aed2d68eca44d7ba0d1d09ea985c9091540dd8d3c51974f1","src/prelude.rs":"95b936c390cbfbbdeeca25adf81ea0db49f38ba46bbb82b9a1ebc42eed673abb","src/private.rs":"702ff02a2d0846d6d97b4164c7b4c2fbab2157ba5ba9c31fea5f1775ff3c9597","src/range.rs":"1e3ecf36f9d7c183f83952c76a9e7f9be40fe9b4a28a5b8a5083221c07f68cf3","src/range_inclusive.rs":"deccd7e2595f725ac7078a034cd774014b731653b376404b67622a7c3ad99eed","src/result.rs":"0656f0000efcea10e571df90247925dfd00a0c2194043fcbc009711fb2f7af02","src/slice/mergesort.rs":"36862f9ae70e35b905212a3c9374b5409fe32855aa067128537ad06578bb582f","src/slice/mod.rs":"c13c41176483a0251cfd1f6f92a59f6dec1ffd43f3e5d15caffb626115d6e9c7","src/slice/quicksort.rs":"874359bd23b90ebe78b2c5f9d5887c9fb063e765c905efb97c88669a6aadd88d","src/slice/test.rs":"d7aa8dbae27ef16687e673c64cde854238c37697a6ff2ce64984ec6381388006","src/split_producer.rs":"2b143e16bc6540792f861e215a86cfea7f4ee500d4faca2476d4165619eac90d","src/str.rs":"084d1e5b14f9b366519441065af7a4361ac0a96e5bfd5140c8e881c947448afc","src/vec.rs":"8f6529ec4842dec8b115f0563e5faf81f47530565685ce773416751724b86678","tests/clones.rs":"3a1a29eab0efb960fce3d0c32c8d105cc076ce6cf342d3468af2510ee941bf59","tests/collect.rs":"27173f932d5c65932ad63c215c561ecf06fcbeb7253a7bb175b819e0a40107aa","tests/cross-pool.rs":"103c121c8684eef0868e3982219e406500009c26d7602167f5a514b1dfd3b4cc","tests/debug.rs":"6672ec732f46fb9fdc62d034bda14069ac9db4bfecae7700e400fafabb584741","tests/intersperse.rs":"bda4fb2179086e32c77c8293b9bb85d55509c282441837ba1849c2d3aa3186a7","tests/issue671-unzip.rs":"d5eb38d8a6d8f66fdf1c40293abbf58f3ac42b5acfc5dca62b02c7ace5bfc1a4","tests/issue671.rs":"52914cac517074deaedcb81bd76b867f0b99cc7b65c3e01cfe12dc9fe38c0266","tests/iter_panic.rs":"376faac33739e3479b5eb744bb2c810c27f8fdda5eeb9ad96d8b93619bf11d1c","tests/named-threads.rs":"48dd0fa0de13b4554dfc1fc0adaee093e19df8b1fc601f5b9b4f15b1fc705249","tests/octillion.rs":"c136ae4612e0d964fc9cb0bcc058a04d0a59c35ba53e0304cdf1d7a0678502fc","tests/producer_split_at.rs":"a6769ac158d810cc292c23a3ee0d583f2fa77ff547f43a40f20f309764c3fb88","tests/sort-panic-safe.rs":"62391908ced36ea8f9fb69ade25bae6c07d6edc7e1cc492b0ade7b85e1b1e920","tests/str.rs":"ef7d7d4a187ab37d23f528adb3b6dcf819e82fadd8fc9ad807afb4e7771a41d9"},"package":"62f02856753d04e03e26929f820d0a0a337ebe71f849801eea335d464b349080"} \ No newline at end of file +{"files":{"Cargo.lock":"411792dbebe7caa62510806303525467bf8caf2006017b8c0e4f032d12596425","Cargo.toml":"e92f7c0946b14cdff3bbc013060b49ed335619361704287666f7884391d76d8d","FAQ.md":"23e5c1ac0158e9e33dae4d3f48bb6b63037ee16e55c476da4cbeedcabe0be0fc","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"0621878e61f0d0fda054bcbe02df75192c28bde1ecc8289cbd86aeba2dd72720","README.md":"443319f333d92d6ad50ade54334c49609e5b116442639b4134b2dd95b49f8d8f","RELEASES.md":"8aec36d41d35b65212b100bd76ef3102f2872f3cfe5fad8fac59a1c76ad1e9b9","build.rs":"2ec988611a2efa7aa89a1835731edcd15d019787d8184e1dac3126756121c586","examples/README.md":"537e6fe9cf696fd4ada9c08bf31055ed6e366ed65668a523e7c5fde77f97c8d3","examples/cpu_monitor.rs":"cc21a2635059ab2d86622d86508ce360c105417522b7bd1f8e0b3ac845ed484a","src/collections/binary_heap.rs":"55f2d9de4b53ce1e9e353362dc344f432e4ee0400dff6d5ea85a06a41eaa6b3e","src/collections/btree_map.rs":"d3094ed5c54620f81a86133f52e74164bae9f0137745eb66e6d31db2e942bcab","src/collections/btree_set.rs":"7de12e388d36cb2f8672bc3b68aed5b44d047c9f5fe262a7260584634299480f","src/collections/hash_map.rs":"f196ff806a334093d8f4d2d72f6e257517209996f5a6a2031b183d5130720bb4","src/collections/hash_set.rs":"2c0a8a91523a076d9153e6b7c19d2aabecc4706253b25fd6b20a0bd389253e60","src/collections/linked_list.rs":"bef7f32da49b55db76cfefa0afa4789a6979e08a69427e49bab2874967163fef","src/collections/mod.rs":"037660cbdd5907808f7df59fa69993582bf978ecaf125a83a1205452bb505a53","src/collections/vec_deque.rs":"51b3f019c05fcaff9916e258312146c540635cb38941291748f01926d4955a72","src/compile_fail/cannot_collect_filtermap_data.rs":"6a141076c14f95e31bed3433d531bc05d806eed9e0018d1b21420d7ab2fc7eb9","src/compile_fail/cannot_zip_filtered_data.rs":"a28cfb3d00b8d277bfa77a10ca132f972e8f100080ef602fdd3c6fd36ad2a156","src/compile_fail/cell_par_iter.rs":"4f076862d9c66ed42a642a5be97116ca5982608ab76816a8f8305182bf463e9e","src/compile_fail/mod.rs":"2c346e4b52941fe0ac2667eeb753c0c21a1f998a544bb9d9167f200caba0a7bb","src/compile_fail/must_use.rs":"8f26766396842fd83790f1afdc20a926bbc1ed9b5cede8d6bec172c1e7d42ed2","src/compile_fail/no_send_par_iter.rs":"e78cd466a61081a0738f63b4e74249e40c37b95240e47e3faeab6ffdb6a8f14c","src/compile_fail/rc_par_iter.rs":"0faf3d26a665c3e2acc2f2f1d66ee234e561d24442efa4980a5e946e1cb2eba3","src/delegate.rs":"897b9118443a50f1690b2506bc349cd233496eea05fa38f0bce821809a23e528","src/iter/chain.rs":"f82a25577ca36bac93b5a13e75dcd70e8cee381b9baa5993dd645f0714fb9eb6","src/iter/chunks.rs":"8ab345783cb7412438eed33264d7db79873801784af7dab25291c349c678085f","src/iter/cloned.rs":"35e1c864f99f7bc93c258c4976d15ccfc1d04df969dc878fd03d35f6799377f7","src/iter/collect/consumer.rs":"cb6f17f46fc56a782afb2a0e023338ebedefe3e7968a84fa8e513c6b89344a64","src/iter/collect/mod.rs":"bd2996860b205315df560e01900232e6a82940a62c4c9ad99c41f0a2423ef2a2","src/iter/collect/test.rs":"7fcf412afa8461312f7893a36e0a50baca0e495a1fe20885dc62b52d8f68b978","src/iter/copied.rs":"4a5de15719de5e6337925f993e0a55c87d8a62b8bbf6c0a4e2bd877136581afc","src/iter/empty.rs":"3cb2d05721aab1a4d9e9c5813473e1646116c1ea570e26d9ac81e083688a0b7d","src/iter/enumerate.rs":"3204255723a93b3275cf0f208939de8960b13a9b13b8c2ba6b664e65da21cd87","src/iter/extend.rs":"11c46e4cab6b1f3f3d82e1555f92c79b2ea9a833258b88142f14dc6d3eed4e15","src/iter/filter.rs":"c8ceea2f71afd1ffc7c713d8683e337e2c4bc3327f47d25116039ab7d950376f","src/iter/filter_map.rs":"18b2fa2d5119297ed6218e353ebb50e7cf4c853e76b9feffd2f332a885d8811d","src/iter/find.rs":"73b11b97eae7234099a05b5f59c937fe488e6a8574b9c9e4e852a7fa86341117","src/iter/find_first_last/mod.rs":"fa7d7692d81ecdbecb178606ad3b1b00c80e5e4159c57d34929b012b0bea0c82","src/iter/find_first_last/test.rs":"2052eb8b87c5a0a0d49a76c83d9d74f81be18aad52ceb1b06d7e209f4fefba94","src/iter/flat_map.rs":"073f67369d2e8b8ed217174bed5ad427e9ddc1b55e57f2c0e5e8b22a61a59b71","src/iter/flatten.rs":"a9144e37855b33d1c08f1c4179e0089ed6bc7d4b645fcf36c46a8ed687961d07","src/iter/fold.rs":"874259b408d7f8cdc376d34276d37c1837950c035ff780de8281d1edf65ded9f","src/iter/for_each.rs":"7af0e21ed8479eec65831d1409f61a88d45a31764f2385ec759eda1a46d388b2","src/iter/from_par_iter.rs":"9439b1ae01db2c7545d6416108700dfbafcff3f584e81704cf985ab1d986b660","src/iter/inspect.rs":"d4f5c031e4a79c01b8439b5e3c78b637ecb4bcf191c8d98ec9f31a0b51977abc","src/iter/interleave.rs":"dcda8d2bd46de25227ac88243ff6ca97fcf1dbb89f935b651fd04c1ecf1abe8a","src/iter/interleave_shortest.rs":"a2b1f31ea4cb29f4761d3724feddcf5a96e1f21fd623f95c85a8659294a6745a","src/iter/intersperse.rs":"6b5d3d826ed3499ba78f0ff07468d96a0e104c7ee142a2ced6be8143b43241a5","src/iter/len.rs":"427548a874aa3036adbaf12034f5065382a8e98f9131b13c6a8c92c7b97e596d","src/iter/map.rs":"66e6db399de12327fec29d069462347dd16fd96d450b121ba8227e32e51552d1","src/iter/map_with.rs":"f83950016bb02addecec049fda73663861c80232477a7b89b7e8718291a4b481","src/iter/mod.rs":"31a1625080d04e7447163f6e12c24e51db00526c5c598b1832ebaee7b4f9b73d","src/iter/multizip.rs":"10ec107f6673c9bc6d1d611e11b716c37e8601ab2f4257a460c4bc4962771347","src/iter/noop.rs":"5be6332ddfbb8fdbae1ffdb00983950a8b37a295bcb58e9a265b33806ee504e6","src/iter/once.rs":"fcebffc374dcdd206d13311dcc2e7d7a04da5687658b2f3ec3409f03ed12774b","src/iter/panic_fuse.rs":"2a4d43fa4e717629de7f69eb180f13db90ef95004975cfa20dcfaacc80435015","src/iter/par_bridge.rs":"26cd2dbc57e5dd2c1b99b19f8ee66900e5ad7e99a5d8b22e947426f944f72b37","src/iter/plumbing/README.md":"d9ae3d57a37af5645b1c79029dd808933279d6853b30163cd0d71ead2a9a5002","src/iter/plumbing/mod.rs":"1156c55a15b651d161f463cb86b2f602f6246a3c7f8a82fb484db12aa6a60091","src/iter/product.rs":"da69f4781c2275c4a176432994c3fd80ea1f296afe47b329de61b1d733d990df","src/iter/reduce.rs":"2f5d6e07d7c0de2360505fa5d9198c31fd43ba7e58a6ec40f79edec19319e502","src/iter/repeat.rs":"ed46b17b79d8569f9d67b50585b116ee0293e1d6c17c0dc683c66644f6a58fd5","src/iter/rev.rs":"c4c796d7cb6398e74bef043a080403acccdf70f6a4e74b242e530d1718969b8f","src/iter/skip.rs":"f1566b395a2b2e95ee14a056b28cf2532f2f9c4d2abc379a1d313ff5a837a51f","src/iter/splitter.rs":"0024db04b4430c2a1e8c921cec86af641f612f877f3675b15df0da9122de5f00","src/iter/step_by.rs":"7e02b9c18a2dc14f637959d0f90dabe877dd51d6dcd085a01c536be59c2bbcdb","src/iter/sum.rs":"cf11d996507ceba39524a102559b84289e776f8fe5772114e00ae2112b38c47c","src/iter/take.rs":"e47eeca1249553b0dfaf54cd8f99026be68db76b42f1f29e09c07a98c165c50a","src/iter/test.rs":"52ab229c2d8c4d4baf0d0cb439accbced982da088d66c3b404c97ef6bc0e136c","src/iter/try_fold.rs":"585d5a69480e1510f3d006c3bff810c98dd009ab44fa9a15a76beeea4fd8c3f2","src/iter/try_reduce.rs":"747f46db1f2d7178b40735828d877b06802296f0d69662d176062920e9a64067","src/iter/try_reduce_with.rs":"1958debdc53fab22b0d0eb603f22647fd96af44a4308549a56dd71256edd1525","src/iter/unzip.rs":"1d617107bd04cd944e64bd83482206ebfdb894a1778dcbbfc9021addf02234e6","src/iter/update.rs":"08a222cf7f8f2f82389ca48d89ecef3a88e205d21ce249f2ba15a4ff85134473","src/iter/while_some.rs":"a514891d7a07031354b48e377c239ff330d0955f184abc57a69d2a193e7fcb45","src/iter/zip.rs":"4d908f75a10b5e9b68d012bbba289f3e5e9d6a9570ce0f56fc1b4f9d96860499","src/iter/zip_eq.rs":"4c18d8f7a78e197a3268c9ef74d16690f8c960407c18bb63dc6905a2fe2bde62","src/lib.rs":"5181dcfb4ffd2149868982ed0b2c465b6199fadb61b3558e68232b9735b25435","src/math.rs":"181859dc38d787143016ce2952b6e45c5ec085d942a591bd5eaf6fe8905711a9","src/option.rs":"00979a9bb8f42629f2b956a6cfbd286fc8a41ffbbec85f1b5d0f0da5615dac9c","src/par_either.rs":"afa4b04ba6ea1d37aed2d68eca44d7ba0d1d09ea985c9091540dd8d3c51974f1","src/prelude.rs":"95b936c390cbfbbdeeca25adf81ea0db49f38ba46bbb82b9a1ebc42eed673abb","src/private.rs":"152f6d65ce4741616a1dec796b9442f78a018d38bb040f76c4cd85008333a3bb","src/range.rs":"f0174450758ecf75812e2687a59324640da19e0518bb5cdce538bd93bd5e6e03","src/range_inclusive.rs":"e20a077d6e934e37822269ff06fb16926397cb725b790d8cf0d0ef58674a9c69","src/result.rs":"0656f0000efcea10e571df90247925dfd00a0c2194043fcbc009711fb2f7af02","src/slice/mergesort.rs":"36862f9ae70e35b905212a3c9374b5409fe32855aa067128537ad06578bb582f","src/slice/mod.rs":"1b60de0ecd6e143bc729d18a2710f493ed040fcc398de992dba1836fab9ad4b3","src/slice/quicksort.rs":"874359bd23b90ebe78b2c5f9d5887c9fb063e765c905efb97c88669a6aadd88d","src/slice/test.rs":"d7aa8dbae27ef16687e673c64cde854238c37697a6ff2ce64984ec6381388006","src/split_producer.rs":"2b143e16bc6540792f861e215a86cfea7f4ee500d4faca2476d4165619eac90d","src/str.rs":"084d1e5b14f9b366519441065af7a4361ac0a96e5bfd5140c8e881c947448afc","src/vec.rs":"8f6529ec4842dec8b115f0563e5faf81f47530565685ce773416751724b86678","tests/chars.rs":"5a2bef1cd8a7d1740a4e5403830da7bbdd584e97d602a07645c4986ee34c2ad3","tests/clones.rs":"3a1a29eab0efb960fce3d0c32c8d105cc076ce6cf342d3468af2510ee941bf59","tests/collect.rs":"27173f932d5c65932ad63c215c561ecf06fcbeb7253a7bb175b819e0a40107aa","tests/cross-pool.rs":"103c121c8684eef0868e3982219e406500009c26d7602167f5a514b1dfd3b4cc","tests/debug.rs":"6672ec732f46fb9fdc62d034bda14069ac9db4bfecae7700e400fafabb584741","tests/intersperse.rs":"bda4fb2179086e32c77c8293b9bb85d55509c282441837ba1849c2d3aa3186a7","tests/issue671-unzip.rs":"d5eb38d8a6d8f66fdf1c40293abbf58f3ac42b5acfc5dca62b02c7ace5bfc1a4","tests/issue671.rs":"52914cac517074deaedcb81bd76b867f0b99cc7b65c3e01cfe12dc9fe38c0266","tests/iter_panic.rs":"376faac33739e3479b5eb744bb2c810c27f8fdda5eeb9ad96d8b93619bf11d1c","tests/named-threads.rs":"48dd0fa0de13b4554dfc1fc0adaee093e19df8b1fc601f5b9b4f15b1fc705249","tests/octillion.rs":"c136ae4612e0d964fc9cb0bcc058a04d0a59c35ba53e0304cdf1d7a0678502fc","tests/producer_split_at.rs":"a6769ac158d810cc292c23a3ee0d583f2fa77ff547f43a40f20f309764c3fb88","tests/sort-panic-safe.rs":"62391908ced36ea8f9fb69ade25bae6c07d6edc7e1cc492b0ade7b85e1b1e920","tests/str.rs":"ef7d7d4a187ab37d23f528adb3b6dcf819e82fadd8fc9ad807afb4e7771a41d9"},"package":"cfd016f0c045ad38b5251be2c9c0ab806917f82da4d36b2a327e5166adad9270"} \ No newline at end of file diff --git a/vendor/rayon/Cargo.lock b/vendor/rayon/Cargo.lock index 7de29b8ff1..829b7d2d0c 100644 --- a/vendor/rayon/Cargo.lock +++ b/vendor/rayon/Cargo.lock @@ -2,7 +2,7 @@ # It is not intended for manual editing. [[package]] name = "aho-corasick" -version = "0.7.10" +version = "0.7.13" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", @@ -10,7 +10,7 @@ dependencies = [ [[package]] name = "autocfg" -version = "1.0.0" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -18,6 +18,15 @@ name = "cfg-if" version = "0.1.10" source = "registry+https://github.com/rust-lang/crates.io-index" +[[package]] +name = "crossbeam-channel" +version = "0.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +dependencies = [ + "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", + "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", +] + [[package]] name = "crossbeam-deque" version = "0.7.3" @@ -33,31 +42,21 @@ name = "crossbeam-epoch" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)", + "memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)", "scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", ] -[[package]] -name = "crossbeam-queue" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -dependencies = [ - "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", - "maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)", -] - [[package]] name = "crossbeam-utils" version = "0.7.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -69,13 +68,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", "strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "either" -version = "1.5.3" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -84,16 +83,16 @@ version = "0.1.14" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "hermit-abi" -version = "0.1.14" +version = "0.1.15" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -103,7 +102,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "libc" -version = "0.2.71" +version = "0.2.76" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -118,10 +117,10 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "memoffset" -version = "0.5.4" +version = "0.5.5" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -129,21 +128,21 @@ name = "num_cpus" version = "1.13.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "ppv-lite86" -version = "0.2.8" +version = "0.2.9" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "proc-macro2" -version = "1.0.18" +version = "1.0.19" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -151,7 +150,7 @@ name = "quote" version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -160,7 +159,7 @@ version = "0.7.3" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ "getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)", - "libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)", + "libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)", "rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", "rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -171,7 +170,7 @@ name = "rand_chacha" version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)", + "ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)", "rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)", ] @@ -201,26 +200,26 @@ dependencies = [ [[package]] name = "rayon" -version = "1.3.1" +version = "1.4.0" dependencies = [ - "autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "docopt 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)", - "either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)", + "either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", "rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", - "rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)", + "serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "rayon-core" -version = "1.7.1" +version = "1.8.0" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ + "crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)", - "crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)", "num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)", @@ -231,7 +230,7 @@ name = "regex" version = "1.3.9" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)", + "aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)", "memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)", "thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", @@ -249,20 +248,20 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "serde" -version = "1.0.112" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)", + "serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] name = "serde_derive" -version = "1.0.112" +version = "1.0.115" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)", + "syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -272,12 +271,12 @@ source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] name = "syn" -version = "1.0.31" +version = "1.0.39" source = "registry+https://github.com/rust-lang/crates.io-index" dependencies = [ - "proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)", "quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)", ] [[package]] @@ -290,7 +289,7 @@ dependencies = [ [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" [[package]] @@ -299,39 +298,39 @@ version = "0.9.0+wasi-snapshot-preview1" source = "registry+https://github.com/rust-lang/crates.io-index" [metadata] -"checksum aho-corasick 0.7.10 (registry+https://github.com/rust-lang/crates.io-index)" = "8716408b8bc624ed7f65d223ddb9ac2d044c0547b6fa4b0d554f3a9540496ada" -"checksum autocfg 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f8aac770f1885fd7e387acedd76065302551364496e46b3dd00860b2f8359b9d" +"checksum aho-corasick 0.7.13 (registry+https://github.com/rust-lang/crates.io-index)" = "043164d8ba5c4c3035fec9bbee8647c0261d788f3474306f93bb65901cae0e86" +"checksum autocfg 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" "checksum cfg-if 0.1.10 (registry+https://github.com/rust-lang/crates.io-index)" = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" +"checksum crossbeam-channel 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)" = "cced8691919c02aac3cb0a1bc2e9b73d89e832bf9a06fc579d4e71b68a2da061" "checksum crossbeam-deque 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "9f02af974daeee82218205558e51ec8768b48cf524bd01d550abe5573a608285" "checksum crossbeam-epoch 0.8.2 (registry+https://github.com/rust-lang/crates.io-index)" = "058ed274caafc1f60c4997b5fc07bf7dc7cca454af7c6e81edffe5f33f70dace" -"checksum crossbeam-queue 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)" = "774ba60a54c213d409d5353bda12d49cd68d14e45036a285234c8d6f91f92570" "checksum crossbeam-utils 0.7.2 (registry+https://github.com/rust-lang/crates.io-index)" = "c3c7c73a2d1e9fc0886a08b93e98eb643461230d5f1925e4036204d5f2e261a8" "checksum docopt 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "7f525a586d310c87df72ebcd98009e57f1cc030c8c268305287a476beb653969" -"checksum either 1.5.3 (registry+https://github.com/rust-lang/crates.io-index)" = "bb1f6b1ce1c140482ea30ddd3335fc0024ac7ee112895426e0a629a6c20adfe3" +"checksum either 1.6.0 (registry+https://github.com/rust-lang/crates.io-index)" = "cd56b59865bce947ac5958779cfa508f6c3b9497cc762b7e24a12d11ccde2c4f" "checksum getrandom 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "7abc8dd8451921606d809ba32e95b6111925cd2906060d2dcc29c070220503eb" -"checksum hermit-abi 0.1.14 (registry+https://github.com/rust-lang/crates.io-index)" = "b9586eedd4ce6b3c498bc3b4dd92fc9f11166aa908a914071953768066c67909" +"checksum hermit-abi 0.1.15 (registry+https://github.com/rust-lang/crates.io-index)" = "3deed196b6e7f9e44a2ae8d94225d80302d81208b1bb673fd21fe634645c85a9" "checksum lazy_static 1.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" -"checksum libc 0.2.71 (registry+https://github.com/rust-lang/crates.io-index)" = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" +"checksum libc 0.2.76 (registry+https://github.com/rust-lang/crates.io-index)" = "755456fae044e6fa1ebbbd1b3e902ae19e73097ed4ed87bb79934a867c007bc3" "checksum maybe-uninit 2.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "60302e4db3a61da70c0cb7991976248362f30319e88850c487b9b95bbf059e00" "checksum memchr 2.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3728d817d99e5ac407411fa471ff9800a778d88a24685968b36824eaf4bee400" -"checksum memoffset 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "b4fc2c02a7e374099d4ee95a193111f72d2110197fe200272371758f6c3643d8" +"checksum memoffset 0.5.5 (registry+https://github.com/rust-lang/crates.io-index)" = "c198b026e1bbf08a937e94c6c60f9ec4a2267f5b0d2eec9c1b21b061ce2be55f" "checksum num_cpus 1.13.0 (registry+https://github.com/rust-lang/crates.io-index)" = "05499f3756671c15885fee9034446956fff3f243d6077b91e5767df161f766b3" -"checksum ppv-lite86 0.2.8 (registry+https://github.com/rust-lang/crates.io-index)" = "237a5ed80e274dbc66f86bd59c1e25edc039660be53194b5fe0a482e0f2612ea" -"checksum proc-macro2 1.0.18 (registry+https://github.com/rust-lang/crates.io-index)" = "beae6331a816b1f65d04c45b078fd8e6c93e8071771f41b8163255bbd8d7c8fa" +"checksum ppv-lite86 0.2.9 (registry+https://github.com/rust-lang/crates.io-index)" = "c36fa947111f5c62a733b652544dd0016a43ce89619538a8ef92724a6f501a20" +"checksum proc-macro2 1.0.19 (registry+https://github.com/rust-lang/crates.io-index)" = "04f5f085b5d71e2188cb8271e5da0161ad52c3f227a661a3c135fdf28e258b12" "checksum quote 1.0.7 (registry+https://github.com/rust-lang/crates.io-index)" = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" "checksum rand 0.7.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6a6b1679d49b24bbfe0c803429aa1874472f50d9b363131f0e89fc356b544d03" "checksum rand_chacha 0.2.2 (registry+https://github.com/rust-lang/crates.io-index)" = "f4c8ed856279c9737206bf725bf36935d8666ead7aa69b52be55af369d193402" "checksum rand_core 0.5.1 (registry+https://github.com/rust-lang/crates.io-index)" = "90bde5296fc891b0cef12a6d03ddccc162ce7b2aff54160af9338f8d40df6d19" "checksum rand_hc 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ca3129af7b92a17112d59ad498c6f81eaf463253766b90396d39ea7a39d6613c" "checksum rand_xorshift 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "77d416b86801d23dde1aa643023b775c3a462efc0ed96443add11546cdf1dca8" -"checksum rayon-core 1.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "e92e15d89083484e11353891f1af602cc661426deb9564c298b270c726973280" +"checksum rayon-core 1.8.0 (registry+https://github.com/rust-lang/crates.io-index)" = "91739a34c4355b5434ce54c9086c5895604a9c278586d1f1aa95e04f66b525a0" "checksum regex 1.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "9c3780fcf44b193bc4d09f36d2a3c87b251da4a046c87795a0d35f4f927ad8e6" "checksum regex-syntax 0.6.18 (registry+https://github.com/rust-lang/crates.io-index)" = "26412eb97c6b088a6997e05f69403a802a92d520de2f8e63c2b65f9e0f47c4e8" "checksum scopeguard 1.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd" -"checksum serde 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "736aac72d1eafe8e5962d1d1c3d99b0df526015ba40915cb3c49d042e92ec243" -"checksum serde_derive 1.0.112 (registry+https://github.com/rust-lang/crates.io-index)" = "bf0343ce212ac0d3d6afd9391ac8e9c9efe06b533c8d33f660f6390cc4093f57" +"checksum serde 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5" +"checksum serde_derive 1.0.115 (registry+https://github.com/rust-lang/crates.io-index)" = "609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48" "checksum strsim 0.9.3 (registry+https://github.com/rust-lang/crates.io-index)" = "6446ced80d6c486436db5c078dde11a9f73d42b57fb273121e160b84f63d894c" -"checksum syn 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "b5304cfdf27365b7585c25d4af91b35016ed21ef88f17ced89c7093b43dba8b6" +"checksum syn 1.0.39 (registry+https://github.com/rust-lang/crates.io-index)" = "891d8d6567fe7c7f8835a3a98af4208f3846fba258c1bc3c31d6e506239f11f9" "checksum thread_local 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "d40c6d1b69745a6ec6fb1ca717914848da4b44ae29d9b3080cbee91d72a69b14" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +"checksum unicode-xid 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" "checksum wasi 0.9.0+wasi-snapshot-preview1 (registry+https://github.com/rust-lang/crates.io-index)" = "cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519" diff --git a/vendor/rayon/Cargo.toml b/vendor/rayon/Cargo.toml index 4acbf210c5..14f3441a3a 100644 --- a/vendor/rayon/Cargo.toml +++ b/vendor/rayon/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "rayon" -version = "1.3.1" +version = "1.4.0" authors = ["Niko Matsakis ", "Josh Stone "] exclude = ["/ci/*", "/scripts/*", "/.github/*", "/bors.toml"] description = "Simple work-stealing parallelism for Rust" @@ -31,7 +31,7 @@ version = "1.0" default-features = false [dependencies.rayon-core] -version = "1.7.1" +version = "1.8.0" [dev-dependencies.docopt] version = "1" diff --git a/vendor/rayon/RELEASES.md b/vendor/rayon/RELEASES.md index 329c8fecc9..0d45357cc1 100644 --- a/vendor/rayon/RELEASES.md +++ b/vendor/rayon/RELEASES.md @@ -1,3 +1,25 @@ +# Release rayon 1.4.0 / rayon-core 1.8.0 (2020-08-24) + +- Implemented a new thread scheduler, [RFC 5], which uses targeted wakeups for + new work and for notifications of completed stolen work, reducing wasteful + CPU usage in idle threads. +- Implemented `IntoParallelIterator for Range` and `RangeInclusive` + with the same iteration semantics as Rust 1.45. +- Relaxed the lifetime requirements of the initial `scope` closure. + +[RFC 5]: https://github.com/rayon-rs/rfcs/pull/5 + +## Contributors + +Thanks to all of the contributors for this release! + +- @CAD97 +- @cuviper +- @kmaork +- @nikomatsakis +- @SuperFluffy + + # Release rayon 1.3.1 / rayon-core 1.7.1 (2020-06-15) - Fixed a use-after-free race in calls blocked between two rayon thread pools. diff --git a/vendor/rayon/src/iter/collect/mod.rs b/vendor/rayon/src/iter/collect/mod.rs index c6bd60f041..e18298e310 100644 --- a/vendor/rayon/src/iter/collect/mod.rs +++ b/vendor/rayon/src/iter/collect/mod.rs @@ -86,7 +86,7 @@ impl<'c, T: Send + 'c> Collect<'c, T> { /// the vector is complete with the collected result. fn with_consumer(mut self, scope_fn: F) where - F: FnOnce(CollectConsumer) -> CollectResult, + F: FnOnce(CollectConsumer<'_, T>) -> CollectResult<'_, T>, { unsafe { let slice = Self::reserve_get_tail_slice(&mut self.vec, self.len); diff --git a/vendor/rayon/src/iter/mod.rs b/vendor/rayon/src/iter/mod.rs index 3c05de957b..ff4c5dd82a 100644 --- a/vendor/rayon/src/iter/mod.rs +++ b/vendor/rayon/src/iter/mod.rs @@ -1864,10 +1864,15 @@ pub trait ParallelIterator: Sized + Send { /// Creates a fresh collection containing all the elements produced /// by this parallel iterator. /// - /// You may prefer to use `collect_into_vec()`, which allocates more - /// efficiently with precise knowledge of how many elements the - /// iterator contains, and even allows you to reuse an existing - /// vector's backing store rather than allocating a fresh vector. + /// You may prefer [`collect_into_vec()`] implemented on + /// [`IndexedParallelIterator`], if your underlying iterator also implements + /// it. [`collect_into_vec()`] allocates efficiently with precise knowledge + /// of how many elements the iterator contains, and even allows you to reuse + /// an existing vector's backing store rather than allocating a fresh vector. + /// + /// [`IndexedParallelIterator`]: trait.IndexedParallelIterator.html + /// [`collect_into_vec()`]: + /// trait.IndexedParallelIterator.html#method.collect_into_vec /// /// # Examples /// diff --git a/vendor/rayon/src/lib.rs b/vendor/rayon/src/lib.rs index 6f7b0274e4..043fa4c468 100644 --- a/vendor/rayon/src/lib.rs +++ b/vendor/rayon/src/lib.rs @@ -1,7 +1,8 @@ -#![doc(html_root_url = "https://docs.rs/rayon/1.3")] +#![doc(html_root_url = "https://docs.rs/rayon/1.4")] #![deny(missing_debug_implementations)] #![deny(missing_docs)] #![deny(unreachable_pub)] +#![warn(rust_2018_idioms)] //! Data-parallelism library that makes it easy to convert sequential //! computations into parallel diff --git a/vendor/rayon/src/private.rs b/vendor/rayon/src/private.rs index a99dd11fb2..c85e77b9cb 100644 --- a/vendor/rayon/src/private.rs +++ b/vendor/rayon/src/private.rs @@ -14,7 +14,7 @@ macro_rules! private_decl { /// impossible to implement outside the crate. #[doc(hidden)] fn __rayon_private__(&self) -> crate::private::PrivateMarker; - } + }; } macro_rules! private_impl { @@ -22,5 +22,5 @@ macro_rules! private_impl { fn __rayon_private__(&self) -> crate::private::PrivateMarker { crate::private::PrivateMarker } - } + }; } diff --git a/vendor/rayon/src/range.rs b/vendor/rayon/src/range.rs index f3b0c5181c..09ba25ec95 100644 --- a/vendor/rayon/src/range.rs +++ b/vendor/rayon/src/range.rs @@ -18,6 +18,7 @@ use crate::iter::plumbing::*; use crate::iter::*; +use std::char; use std::ops::Range; use std::usize; @@ -223,6 +224,75 @@ unindexed_range_impl! {i64, u64} unindexed_range_impl! {u128, u128} unindexed_range_impl! {i128, u128} +// char is special because of the surrogate range hole +macro_rules! convert_char { + ( $self:ident . $method:ident ( $( $arg:expr ),* ) ) => {{ + let start = $self.range.start as u32; + let end = $self.range.end as u32; + if start < 0xD800 && 0xE000 < end { + // chain the before and after surrogate range fragments + (start..0xD800) + .into_par_iter() + .chain(0xE000..end) + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } else { + // no surrogate range to worry about + (start..end) + .into_par_iter() + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } + }}; +} + +impl ParallelIterator for Iter { + type Item = char; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + convert_char!(self.drive(consumer)) + } + + fn opt_len(&self) -> Option { + Some(self.len()) + } +} + +impl IndexedParallelIterator for Iter { + // Split at the surrogate range first if we're allowed to + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + convert_char!(self.drive(consumer)) + } + + fn len(&self) -> usize { + // Taken from ::steps_between + let start = self.range.start as u32; + let end = self.range.end as u32; + if start < end { + let mut count = end - start; + if start < 0xD800 && 0xE000 <= end { + count -= 0x800 + } + count as usize + } else { + 0 + } + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + convert_char!(self.with_producer(callback)) + } +} + #[test] fn check_range_split_at_overflow() { // Note, this split index overflows i8! diff --git a/vendor/rayon/src/range_inclusive.rs b/vendor/rayon/src/range_inclusive.rs index c1757701a5..c802b6c61d 100644 --- a/vendor/rayon/src/range_inclusive.rs +++ b/vendor/rayon/src/range_inclusive.rs @@ -18,6 +18,7 @@ use crate::iter::plumbing::*; use crate::iter::*; +use std::char; use std::ops::RangeInclusive; /// Parallel iterator over an inclusive range, implemented for all integer types. @@ -48,7 +49,8 @@ pub struct Iter { impl Iter where - RangeInclusive: Clone + Iterator + DoubleEndedIterator, + RangeInclusive: Eq, + T: Ord + Copy, { /// Returns `Some((start, end))` for `start..=end`, or `None` if it is exhausted. /// @@ -56,7 +58,16 @@ where /// so this is a way for us to figure out what we've got. Thankfully, all of the /// integer types we care about can be trivially cloned. fn bounds(&self) -> Option<(T, T)> { - Some((self.range.clone().next()?, self.range.clone().next_back()?)) + let start = *self.range.start(); + let end = *self.range.end(); + if start <= end && self.range == (start..=end) { + // If the range is still nonempty, this is obviously true + // If the range is exhausted, either start > end or + // the range does not equal start..=end. + Some((start, end)) + } else { + None + } } } @@ -147,6 +158,80 @@ parallel_range_impl! {i64} parallel_range_impl! {u128} parallel_range_impl! {i128} +// char is special +macro_rules! convert_char { + ( $self:ident . $method:ident ( $( $arg:expr ),* ) ) => { + if let Some((start, end)) = $self.bounds() { + let start = start as u32; + let end = end as u32; + if start < 0xD800 && 0xE000 <= end { + // chain the before and after surrogate range fragments + (start..0xD800) + .into_par_iter() + .chain(0xE000..end + 1) // cannot use RangeInclusive, so add one to end + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } else { + // no surrogate range to worry about + (start..end + 1) // cannot use RangeInclusive, so add one to end + .into_par_iter() + .map(|codepoint| unsafe { char::from_u32_unchecked(codepoint) }) + .$method($( $arg ),*) + } + } else { + empty().into_par_iter().$method($( $arg ),*) + } + }; +} + +impl ParallelIterator for Iter { + type Item = char; + + fn drive_unindexed(self, consumer: C) -> C::Result + where + C: UnindexedConsumer, + { + convert_char!(self.drive(consumer)) + } + + fn opt_len(&self) -> Option { + Some(self.len()) + } +} + +// Range is broken on 16 bit platforms, may as well benefit from it +impl IndexedParallelIterator for Iter { + // Split at the surrogate range first if we're allowed to + fn drive(self, consumer: C) -> C::Result + where + C: Consumer, + { + convert_char!(self.drive(consumer)) + } + + fn len(&self) -> usize { + if let Some((start, end)) = self.bounds() { + // Taken from ::steps_between + let start = start as u32; + let end = end as u32; + let mut count = end - start; + if start < 0xD800 && 0xE000 <= end { + count -= 0x800 + } + (count + 1) as usize // add one for inclusive + } else { + 0 + } + } + + fn with_producer(self, callback: CB) -> CB::Output + where + CB: ProducerCallback, + { + convert_char!(self.with_producer(callback)) + } +} + #[test] #[cfg(target_pointer_width = "64")] fn test_u32_opt_len() { diff --git a/vendor/rayon/src/slice/mod.rs b/vendor/rayon/src/slice/mod.rs index e01fb11f5e..b80125f549 100644 --- a/vendor/rayon/src/slice/mod.rs +++ b/vendor/rayon/src/slice/mod.rs @@ -110,7 +110,7 @@ pub trait ParallelSlice { let len = slice.len() - rem; let (fst, snd) = slice.split_at(len); ChunksExact { - chunk_size: chunk_size, + chunk_size, slice: fst, rem: snd, } @@ -199,7 +199,7 @@ pub trait ParallelSliceMut { let len = slice.len() - rem; let (fst, snd) = slice.split_at_mut(len); ChunksExactMut { - chunk_size: chunk_size, + chunk_size, slice: fst, rem: snd, } diff --git a/vendor/rayon/tests/chars.rs b/vendor/rayon/tests/chars.rs new file mode 100644 index 0000000000..ac8e3f3046 --- /dev/null +++ b/vendor/rayon/tests/chars.rs @@ -0,0 +1,39 @@ +use rayon::prelude::*; +use std::char; + +#[test] +fn half_open_correctness() { + let low = char::from_u32(0xD800 - 0x7).unwrap(); + let high = char::from_u32(0xE000 + 0x7).unwrap(); + + let range = low..high; + let mut chars: Vec = range.into_par_iter().collect(); + chars.sort(); + + assert_eq!( + chars, + vec![ + '\u{D7F9}', '\u{D7FA}', '\u{D7FB}', '\u{D7FC}', '\u{D7FD}', '\u{D7FE}', '\u{D7FF}', + '\u{E000}', '\u{E001}', '\u{E002}', '\u{E003}', '\u{E004}', '\u{E005}', '\u{E006}', + ] + ); +} + +#[test] +fn closed_correctness() { + let low = char::from_u32(0xD800 - 0x7).unwrap(); + let high = char::from_u32(0xE000 + 0x7).unwrap(); + + let range = low..=high; + let mut chars: Vec = range.into_par_iter().collect(); + chars.sort(); + + assert_eq!( + chars, + vec![ + '\u{D7F9}', '\u{D7FA}', '\u{D7FB}', '\u{D7FC}', '\u{D7FD}', '\u{D7FE}', '\u{D7FF}', + '\u{E000}', '\u{E001}', '\u{E002}', '\u{E003}', '\u{E004}', '\u{E005}', '\u{E006}', + '\u{E007}', + ] + ); +} diff --git a/vendor/rustc-ap-rustc_lexer/.cargo-checksum.json b/vendor/rustc-ap-rustc_lexer-673.0.0/.cargo-checksum.json similarity index 100% rename from vendor/rustc-ap-rustc_lexer/.cargo-checksum.json rename to vendor/rustc-ap-rustc_lexer-673.0.0/.cargo-checksum.json diff --git a/vendor/rustc-ap-rustc_lexer/Cargo.toml b/vendor/rustc-ap-rustc_lexer-673.0.0/Cargo.toml similarity index 100% rename from vendor/rustc-ap-rustc_lexer/Cargo.toml rename to vendor/rustc-ap-rustc_lexer-673.0.0/Cargo.toml diff --git a/vendor/rustc-ap-rustc_lexer/src/cursor.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/cursor.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/cursor.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/cursor.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/lib.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/lib.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/lib.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/lib.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/tests.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/tests.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/tests.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/tests.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/unescape.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/unescape.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape.rs diff --git a/vendor/rustc-ap-rustc_lexer/src/unescape/tests.rs b/vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape/tests.rs similarity index 100% rename from vendor/rustc-ap-rustc_lexer/src/unescape/tests.rs rename to vendor/rustc-ap-rustc_lexer-673.0.0/src/unescape/tests.rs diff --git a/vendor/serde/.cargo-checksum.json b/vendor/serde/.cargo-checksum.json index efb497c91a..ce86133bd3 100644 --- a/vendor/serde/.cargo-checksum.json +++ b/vendor/serde/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"482c1bf9407c9f37a9faf753cd6fc27227a8f8fb2c0f68d4f72391e21999087e","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"d6af5a05be728765c2d98d960406ba648333745ed8644be311d2a1f52d7075f0","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/de/from_primitive.rs":"058fa17313ed3a9c29ec04c6ec67f21a756f6f28cdeb4b0dfcd7012b3e702d0b","src/de/ignored_any.rs":"6a0527edd497a56a103ae65f5e73da675b3f99094d6dcad3c335c8d932daaf40","src/de/impls.rs":"3534fafb62bfbd1f043ebbcd5abb1a1f9cf26e0f5443e7125f72928a4a7dc61e","src/de/mod.rs":"0dd0c8bdefa86f621fdeba8f7b5575463c111bf034b0297e80d3aa8fedf40955","src/de/utf8.rs":"f17524ee0af98ec3abcfd7d0b812fbd1033263bd8e2ce2f57c1e1999ce153558","src/de/value.rs":"a878f6bdd57d25b0b93bfc6288ed1e46c50870dc8703748b6fbb8c0965a6b586","src/export.rs":"2ebdf0eccaa64c5e98c6dfd13b4980474f627fc3fae90cfc2c741acf860afd5d","src/integer128.rs":"b213ec6c1ecf8c8228d9591e0b2c31b78d972cd4c6a0b231468090f15784f6f6","src/lib.rs":"40b75a05fff22e4de29a214b75f729988fa9a91c7cc2384706ec2ddfe743c235","src/macros.rs":"f18fc25c5fb857238bf119cdee5c7987a8584dea69c51f27ca718b7dfd871d0f","src/private/de.rs":"bce814fa2f2fd689c6d4a354839f38d7ea260509339181ce83d9b0fdbe0e1b3b","src/private/macros.rs":"ebb6affd4c89e3b5f9a42e03f8b7d966bc588875e9b44e962d0b7aba7f80a10f","src/private/mod.rs":"f8f2cd5edbfc26c268b34cdb89db1b34e6348f81384f03d18532e7568575006d","src/private/ser.rs":"96a1e23ad7f3c8ee51a02d799d92780e19dd3c18fa0f1ad791abef7cb346e224","src/ser/fmt.rs":"7827ed07fd8897e6324f75625ba0c926a4c4e7ec2914cd067391ce54d942ac7b","src/ser/impls.rs":"ce9996998c6485c88bbc77516611e9f5a9a92cbb12d34bb4f8ae022530be85e0","src/ser/impossible.rs":"3dd0e165b88fc67e698e675f16569b91fab9e054caa4c3e1997f929ba364fe90","src/ser/mod.rs":"d1811b0c4002bf89f0b24b6647cd5b489c27738b42acbef8207990b49dd44a74","src/std_error.rs":"3aac687856c035517fae44ed2906dd4a1e3184bae4bf613adcdeb73f74126c57"},"package":"e54c9a88f2da7238af84b5101443f0c0d0a3bbdc455e34a5c9497b1903ed55d5"} \ No newline at end of file +{"files":{"Cargo.toml":"736542df95689176d660863d0493740313de4a030a09ffa2b5559c80223769ac","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"d6af5a05be728765c2d98d960406ba648333745ed8644be311d2a1f52d7075f0","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/de/from_primitive.rs":"058fa17313ed3a9c29ec04c6ec67f21a756f6f28cdeb4b0dfcd7012b3e702d0b","src/de/ignored_any.rs":"6a0527edd497a56a103ae65f5e73da675b3f99094d6dcad3c335c8d932daaf40","src/de/impls.rs":"077487d2bacd1fd2093e3ef2fa0d52abe7b9530a84d1ccf9eefb4ad81b6bbad1","src/de/mod.rs":"b59c365b05e4e09a7467c958f85b2c64435514c59c17275be019397ad7ccb00e","src/de/utf8.rs":"f17524ee0af98ec3abcfd7d0b812fbd1033263bd8e2ce2f57c1e1999ce153558","src/de/value.rs":"a878f6bdd57d25b0b93bfc6288ed1e46c50870dc8703748b6fbb8c0965a6b586","src/export.rs":"2ebdf0eccaa64c5e98c6dfd13b4980474f627fc3fae90cfc2c741acf860afd5d","src/integer128.rs":"b213ec6c1ecf8c8228d9591e0b2c31b78d972cd4c6a0b231468090f15784f6f6","src/lib.rs":"c8b0d22a63c9250342fbd3a3b263435e7bca98d9091a3bad5db026eac4877ef9","src/macros.rs":"f18fc25c5fb857238bf119cdee5c7987a8584dea69c51f27ca718b7dfd871d0f","src/private/de.rs":"bce814fa2f2fd689c6d4a354839f38d7ea260509339181ce83d9b0fdbe0e1b3b","src/private/macros.rs":"ebb6affd4c89e3b5f9a42e03f8b7d966bc588875e9b44e962d0b7aba7f80a10f","src/private/mod.rs":"f8f2cd5edbfc26c268b34cdb89db1b34e6348f81384f03d18532e7568575006d","src/private/ser.rs":"96a1e23ad7f3c8ee51a02d799d92780e19dd3c18fa0f1ad791abef7cb346e224","src/ser/fmt.rs":"7827ed07fd8897e6324f75625ba0c926a4c4e7ec2914cd067391ce54d942ac7b","src/ser/impls.rs":"ce9996998c6485c88bbc77516611e9f5a9a92cbb12d34bb4f8ae022530be85e0","src/ser/impossible.rs":"3dd0e165b88fc67e698e675f16569b91fab9e054caa4c3e1997f929ba364fe90","src/ser/mod.rs":"9c26100d8058a5c39aea72512fb78de959e4ed9199481eef47996f0864df0f2c","src/std_error.rs":"3aac687856c035517fae44ed2906dd4a1e3184bae4bf613adcdeb73f74126c57"},"package":"96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5"} \ No newline at end of file diff --git a/vendor/serde/Cargo.toml b/vendor/serde/Cargo.toml index 437c270c99..4e6fa348f2 100644 --- a/vendor/serde/Cargo.toml +++ b/vendor/serde/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "serde" -version = "1.0.115" +version = "1.0.116" authors = ["Erick Tryzelaar ", "David Tolnay "] build = "build.rs" include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] @@ -30,7 +30,7 @@ targets = ["x86_64-unknown-linux-gnu"] [package.metadata.playground] features = ["derive", "rc"] [dependencies.serde_derive] -version = "=1.0.115" +version = "=1.0.116" optional = true [dev-dependencies.serde_derive] version = "1.0" diff --git a/vendor/serde/src/de/impls.rs b/vendor/serde/src/de/impls.rs index e460a40d6c..ae4f9dc806 100644 --- a/vendor/serde/src/de/impls.rs +++ b/vendor/serde/src/de/impls.rs @@ -1313,7 +1313,7 @@ macro_rules! variant_identifier { formatter.write_str($expecting_message) } - fn visit_u32(self, value: u32) -> Result + fn visit_u64(self, value: u64) -> Result where E: Error, { @@ -1321,7 +1321,7 @@ macro_rules! variant_identifier { $( $index => Ok($name_kind :: $variant), )* - _ => Err(Error::invalid_value(Unexpected::Unsigned(value as u64), &self),), + _ => Err(Error::invalid_value(Unexpected::Unsigned(value), &self),), } } @@ -2326,7 +2326,7 @@ where formatter.write_str("`Unbounded`, `Included` or `Excluded`") } - fn visit_u32(self, value: u32) -> Result + fn visit_u64(self, value: u64) -> Result where E: Error, { @@ -2335,7 +2335,7 @@ where 1 => Ok(Field::Included), 2 => Ok(Field::Excluded), _ => Err(Error::invalid_value( - Unexpected::Unsigned(value as u64), + Unexpected::Unsigned(value), &self, )), } @@ -2492,7 +2492,7 @@ where formatter.write_str("`Ok` or `Err`") } - fn visit_u32(self, value: u32) -> Result + fn visit_u64(self, value: u64) -> Result where E: Error, { @@ -2500,7 +2500,7 @@ where 0 => Ok(Field::Ok), 1 => Ok(Field::Err), _ => Err(Error::invalid_value( - Unexpected::Unsigned(value as u64), + Unexpected::Unsigned(value), &self, )), } diff --git a/vendor/serde/src/de/mod.rs b/vendor/serde/src/de/mod.rs index f1b8b3129a..6d39473633 100644 --- a/vendor/serde/src/de/mod.rs +++ b/vendor/serde/src/de/mod.rs @@ -104,7 +104,7 @@ //! [`Deserialize`]: ../trait.Deserialize.html //! [`Deserializer`]: ../trait.Deserializer.html //! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html -//! [`bincode`]: https://github.com/TyOverby/bincode +//! [`bincode`]: https://github.com/servo/bincode //! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map //! [`serde_derive`]: https://crates.io/crates/serde_derive //! [`serde_json`]: https://github.com/serde-rs/json diff --git a/vendor/serde/src/lib.rs b/vendor/serde/src/lib.rs index 7c4733c23f..fe40eb1ca8 100644 --- a/vendor/serde/src/lib.rs +++ b/vendor/serde/src/lib.rs @@ -48,7 +48,7 @@ //! definition. //! - [JSON5], A superset of JSON including some productions from ES5. //! - [Postcard], a no\_std and embedded-systems friendly compact binary format. -//! - [URL], the x-www-form-urlencoded format. +//! - [URL] query strings, in the x-www-form-urlencoded format. //! - [Envy], a way to deserialize environment variables into Rust structs. //! *(deserialization only)* //! - [Envy Store], a way to deserialize [AWS Parameter Store] parameters into @@ -59,7 +59,7 @@ //! - [FlexBuffers], the schemaless cousin of Google's FlatBuffers zero-copy serialization format. //! //! [JSON]: https://github.com/serde-rs/json -//! [Bincode]: https://github.com/TyOverby/bincode +//! [Bincode]: https://github.com/servo/bincode //! [CBOR]: https://github.com/pyfisch/cbor //! [YAML]: https://github.com/dtolnay/serde-yaml //! [MessagePack]: https://github.com/3Hren/msgpack-rust @@ -70,7 +70,7 @@ //! [Avro]: https://github.com/flavray/avro-rs //! [JSON5]: https://github.com/callum-oakley/json5-rs //! [Postcard]: https://github.com/jamesmunns/postcard -//! [URL]: https://github.com/nox/serde_urlencoded +//! [URL]: https://docs.rs/serde_qs //! [Envy]: https://github.com/softprops/envy //! [Envy Store]: https://github.com/softprops/envy-store //! [Cargo]: http://doc.crates.io/manifest.html @@ -82,7 +82,7 @@ //////////////////////////////////////////////////////////////////////////////// // Serde types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/serde/1.0.115")] +#![doc(html_root_url = "https://docs.rs/serde/1.0.116")] // Support using Serde without the standard library! #![cfg_attr(not(feature = "std"), no_std)] // Unstable functionality only if the user asks for it. For tracking and diff --git a/vendor/serde/src/ser/mod.rs b/vendor/serde/src/ser/mod.rs index 676b0e2f70..8a4b2e3669 100644 --- a/vendor/serde/src/ser/mod.rs +++ b/vendor/serde/src/ser/mod.rs @@ -99,7 +99,7 @@ //! [`LinkedHashMap`]: https://docs.rs/linked-hash-map/*/linked_hash_map/struct.LinkedHashMap.html //! [`Serialize`]: ../trait.Serialize.html //! [`Serializer`]: ../trait.Serializer.html -//! [`bincode`]: https://github.com/TyOverby/bincode +//! [`bincode`]: https://github.com/servo/bincode //! [`linked-hash-map`]: https://crates.io/crates/linked-hash-map //! [`serde_derive`]: https://crates.io/crates/serde_derive //! [`serde_json`]: https://github.com/serde-rs/json diff --git a/vendor/serde_derive/.cargo-checksum.json b/vendor/serde_derive/.cargo-checksum.json index 88dab0b2c5..915ba422d6 100644 --- a/vendor/serde_derive/.cargo-checksum.json +++ b/vendor/serde_derive/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"14b95c381d691c061057f9941709d277b8f6082a2cbe86a0b967c02d965ceb8f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"17fac4a28904e90c1e46b517839bd17fd54dbc69cfbff7451f695ecf7bab34ef","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/bound.rs":"66643d6cd044a2167b2bb8a1970e5b2a07069e362ce1326a4b00fef7bcfcd5c8","src/de.rs":"8bea1aa8057c824264bb4700fa6531747bfaed88be2d1f90bb6455600aa8e222","src/dummy.rs":"7bc4267039808046fe0a7fbeb462b301ac30ea1152fcbde8a3b934dc143fe468","src/fragment.rs":"5548ba65a53d90a296f60c1328a7a7fb040db467f59c2f5210b2fb320457145d","src/internals/ast.rs":"f1a1b13cf6b68e2bf27c5cdcdbde6883f86cde1ba8c0595dffdbf2e11c4ec8b1","src/internals/attr.rs":"554bf48da8fb4e8a5ac2d16143cc9dc05e9bc493b4a4c8a196ace360bce110d5","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"9a01a0db1fc3086891e998f544836e7498ebfc7cc5e1956199d0526e6a8d9a3c","src/internals/ctxt.rs":"6fa544ae52914498a62a395818ebdc1b36ac2fb5903c60afb741a864ad559f1c","src/internals/mod.rs":"989df41dae7a9066eec3e5afd5b262fd94a12281df30f4c03f319370811beea0","src/internals/symbol.rs":"9f2b4b9cd83dc09def75165187c97d0050bffa4218782c27b478bcf93f925a74","src/lib.rs":"5a3e1bb473b8f69a69402fec64e4c673865fa6dde2f6dfcccaa934ddad538a77","src/pretend.rs":"ffeb23da4c2abc4e501c378cffa8b776bab506735ea70d4ed10f4c0f3755321b","src/ser.rs":"4ac3d23e5a84b72137d42eaa38ef8ec1516c4d4d9ca040dc5ce2abbf33126443","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":"609feed1d0a73cc36a0182a840a9b37b4a82f0b1150369f0536a9e3f2a31dc48"} \ No newline at end of file +{"files":{"Cargo.toml":"74677f4031ffe40137aad8407d240dfe0bd3ed5d07c518afb1983b384f4ee283","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"5cf9d2158d70048a2916360ad59d9079f6233c6f68781a7a792e70f8b772d8ce","build.rs":"17fac4a28904e90c1e46b517839bd17fd54dbc69cfbff7451f695ecf7bab34ef","crates-io.md":"25ed421fe25d0f6f74c4b78674144bef2843a5f78bf552d0a8ec633be69d282b","src/bound.rs":"66643d6cd044a2167b2bb8a1970e5b2a07069e362ce1326a4b00fef7bcfcd5c8","src/de.rs":"8bea1aa8057c824264bb4700fa6531747bfaed88be2d1f90bb6455600aa8e222","src/dummy.rs":"7bc4267039808046fe0a7fbeb462b301ac30ea1152fcbde8a3b934dc143fe468","src/fragment.rs":"5548ba65a53d90a296f60c1328a7a7fb040db467f59c2f5210b2fb320457145d","src/internals/ast.rs":"f1a1b13cf6b68e2bf27c5cdcdbde6883f86cde1ba8c0595dffdbf2e11c4ec8b1","src/internals/attr.rs":"554bf48da8fb4e8a5ac2d16143cc9dc05e9bc493b4a4c8a196ace360bce110d5","src/internals/case.rs":"b2024f414f5d832bafa53b9ae7924b2d43a29175b19bb3da36f15c9071666558","src/internals/check.rs":"9a01a0db1fc3086891e998f544836e7498ebfc7cc5e1956199d0526e6a8d9a3c","src/internals/ctxt.rs":"6fa544ae52914498a62a395818ebdc1b36ac2fb5903c60afb741a864ad559f1c","src/internals/mod.rs":"989df41dae7a9066eec3e5afd5b262fd94a12281df30f4c03f319370811beea0","src/internals/symbol.rs":"9f2b4b9cd83dc09def75165187c97d0050bffa4218782c27b478bcf93f925a74","src/lib.rs":"ae786031bb024d49a73e8c0aee126441a9e61dd2bc50ddf7aad4a586fa89081d","src/pretend.rs":"ffeb23da4c2abc4e501c378cffa8b776bab506735ea70d4ed10f4c0f3755321b","src/ser.rs":"4ac3d23e5a84b72137d42eaa38ef8ec1516c4d4d9ca040dc5ce2abbf33126443","src/try.rs":"b9a10c8690d442a57fc7097d42c9a4f13034c7b4a30b7eb02d538fdbf8ae0a8d"},"package":"f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8"} \ No newline at end of file diff --git a/vendor/serde_derive/Cargo.toml b/vendor/serde_derive/Cargo.toml index 92f772de82..d06a1bb40a 100644 --- a/vendor/serde_derive/Cargo.toml +++ b/vendor/serde_derive/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "serde_derive" -version = "1.0.115" +version = "1.0.116" authors = ["Erick Tryzelaar ", "David Tolnay "] include = ["build.rs", "src/**/*.rs", "crates-io.md", "README.md", "LICENSE-APACHE", "LICENSE-MIT"] description = "Macros 1.1 implementation of #[derive(Serialize, Deserialize)]" diff --git a/vendor/serde_derive/src/lib.rs b/vendor/serde_derive/src/lib.rs index 650c519d3d..9307ae8147 100644 --- a/vendor/serde_derive/src/lib.rs +++ b/vendor/serde_derive/src/lib.rs @@ -13,7 +13,7 @@ //! //! [https://serde.rs/derive.html]: https://serde.rs/derive.html -#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.115")] +#![doc(html_root_url = "https://docs.rs/serde_derive/1.0.116")] #![allow(unknown_lints, bare_trait_objects)] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints diff --git a/vendor/sha2/.cargo-checksum.json b/vendor/sha2/.cargo-checksum.json new file mode 100644 index 0000000000..2651a75ba8 --- /dev/null +++ b/vendor/sha2/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CHANGELOG.md":"5eac381cb8af4e38b5cffa5cac4364e59c07a6fe322e7c3a0376b6e9dce80f2a","Cargo.lock":"7fd4a53f4adea010f107fe8e6bcc0bd6b2116fb37e0bca9a53293f61a24bc4ab","Cargo.toml":"9ca349cad4ce237ef6df97dacf6cd5d9095feffa52a900efd2393266dce5de90","LICENSE-APACHE":"a9040321c3712d8fd0b09cf52b17445de04a23a10165049ae187cd39e5c86be5","LICENSE-MIT":"b4eb00df6e2a4d22518fcaa6a2b4646f249b3a3c9814509b22bd2091f1392ff1","README.md":"7f4a6be652e4fe713de1df5d3e2f7e243244ebfe6fcda5839e75e720c15f73ee","benches/sha256.rs":"b4c350e12041ba0bd9b99bac401dedb26d6429570787cc3562467e7a129e4f75","benches/sha512.rs":"7550ba0ed7915193977e19a426ba39a6825fc7337beaac6538155f0486d1d1af","examples/sha256sum.rs":"93ecb1972af2193ff88d57644d1807be9ee90f9142f1508fb3fec95a5277dbc3","examples/sha512sum.rs":"385a40d67c9637b220d90820a921c4eb57a5a4f752dcfaf2a4737a8d051c790d","src/consts.rs":"fda715379ca4b68f2deb7413328c91d018221d0af2f592d43871b4ce8a8b2b51","src/lib.rs":"9c5ac8ae7cb85c70edcb94f3af7818777324b6053e7207b05a456477a7383835","src/sha256.rs":"1b4d37bccdeb226e03bcb05621a905ea0d97295062eddc26ab6e00f90e18cd57","src/sha256/aarch64.rs":"3ce2b975a0f26a666e7449bbdd9454353f6506c4cefc1231da6f4572e2dc54c0","src/sha256/soft.rs":"b7f78d833f231996598f69086de25fcaf268faed1466e40075a6ec3d822ee8d1","src/sha256/x86.rs":"fa342ddf524eb172b0f5afd93e825c21b06c8f7b997b4711fc7ac05f73587f81","src/sha512.rs":"56d78bc095c0481027367a1036049251a81aeedf5f8cadbaf6b6f562f753fa9c","src/sha512/soft.rs":"87caece42b26b532ff7ebca8776ac34a0bc51ccd82a3416ef6e04257c510456d","tests/data/sha224.blb":"b20c77259744a50b96e73c602e8473bf811f820f072cf3313d3f254d1d532f30","tests/data/sha256.blb":"9f984fbe1f9b89115db731d9058036dcdaf450d03d732a0a8cf6fb16c7e08a92","tests/data/sha256_one_million_a.bin":"80d1189477563e1b5206b2749f1afe4807e5705e8bd77887a60187a712156688","tests/data/sha384.blb":"305f96c4237a2aeb5d9b66cf30a13d5b41b749c6c8cb079192f45bd81ad404e3","tests/data/sha512.blb":"e3c964b9a735473cf14e64953a0dfee9d98e445ba242d439ffef216e9cfe36e6","tests/data/sha512_224.blb":"8baa081f40124f5a69892d8f1e06867acba094358ad6304b60405210af27160b","tests/data/sha512_256.blb":"f1f15c1040958ed32bc1c44d2947c7827f55e53107e026535343840176cb3608","tests/data/sha512_one_million_a.bin":"a872d736156b28b7784fcc124cfb9993ed31707f1754a0a448d26bf84f5cc7f5","tests/lib.rs":"c7e5067377c91e64c76e6c7f5872f6bb491be8c1eaf2f77be4f10b38d730db24"},"package":"2933378ddfeda7ea26f48c555bdad8bb446bf8a3d17832dc83e380d444cfb8c1"} \ No newline at end of file diff --git a/vendor/sha2/CHANGELOG.md b/vendor/sha2/CHANGELOG.md new file mode 100644 index 0000000000..9c6d5895e7 --- /dev/null +++ b/vendor/sha2/CHANGELOG.md @@ -0,0 +1,70 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## 0.9.1 (2020-06-24) +### Added +- x86 hardware acceleration of SHA-256 via SHA extension instrinsics. ([#167]) + +[#167]: https://github.com/RustCrypto/hashes/pull/167 + +## 0.9.0 (2020-06-09) +### Changed +- Update to `digest` v0.9 release; MSRV 1.41+ ([#155]) +- Use new `*Dirty` traits from the `digest` crate ([#153]) +- Bump `block-buffer` to v0.8 release ([#151]) +- Rename `*result*` to `finalize` ([#148]) +- Upgrade to Rust 2018 edition ([#133]) + +[#155]: https://github.com/RustCrypto/hashes/pull/155 +[#153]: https://github.com/RustCrypto/hashes/pull/153 +[#151]: https://github.com/RustCrypto/hashes/pull/151 +[#148]: https://github.com/RustCrypto/hashes/pull/148 +[#133]: https://github.com/RustCrypto/hashes/pull/133 + +## 0.8.2 (2020-05-23) +### Added +- Expose compression function under the `compress` feature flag ([#108]) + +### Changed +- Use `libc` crate for `aarch64` consts ([#109]) +- Minor code cleanups ([#94]) + +[#109]: https://github.com/RustCrypto/hashes/pull/109 +[#108]: https://github.com/RustCrypto/hashes/pull/108 +[#94]: https://github.com/RustCrypto/hashes/pull/94 + +## 0.8.1 (2020-01-05) + +## 0.8.0 (2018-10-02) + +## 0.7.1 (2018-04-27) + +## 0.6.0 (2017-06-12) + +## 0.5.3 (2017-06-03) + +## 0.5.2 (2017-05-08) + +## 0.5.1 (2017-05-01) + +## 0.5.0 (2017-04-06) + +## 0.4.2 (2017-01-23) + +## 0.4.1 (2017-01-20) + +## 0.4.0 (2016-12-24) + +## 0.3.0 (2016-11-17) + +## 0.2.0 (2016-10-26) + +## 0.1.2 (2016-05-06) + +## 0.1.1 (2016-05-06) + +## 0.1.0 (2016-05-06) diff --git a/vendor/sha2/Cargo.lock b/vendor/sha2/Cargo.lock new file mode 100644 index 0000000000..30c940334a --- /dev/null +++ b/vendor/sha2/Cargo.lock @@ -0,0 +1,135 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "blobby" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6fe5f8c2940b65859ece4b3b2ba02d2b12c87cab455fd42dee2556a187bb2cf6" +dependencies = [ + "byteorder", +] + +[[package]] +name = "block-buffer" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4152116fd6e9dadb291ae18fc1ec3575ed6d84c29642d97890f4b4a3417297e4" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.3.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "08c48aae112d48ed9f069b33538ea9e3e90aa263cfa3d1c24309612b1f7472de" + +[[package]] +name = "cc" +version = "1.0.54" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7bbb73db36c1246e9034e307d0fba23f9a2e251faa47ade70c1bd252220c8311" + +[[package]] +name = "cfg-if" +version = "0.1.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4785bdd1c96b2a846b2bd7cc02e86b6b3dbf14e7e53446c4f54c92a361040822" + +[[package]] +name = "cpuid-bool" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6d375c433320f6c5057ae04a04376eef4d04ce2801448cf8863a78da99107be4" + +[[package]] +name = "digest" +version = "0.9.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3dd60d1080a57a05ab032377049e0591415d2b31afd7028356dbf3cc6dcb066" +dependencies = [ + "blobby", + "generic-array", +] + +[[package]] +name = "generic-array" +version = "0.14.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac746a5f3bbfdadd6106868134545e684693d54d9d44f6e9588a7d54af0bf980" +dependencies = [ + "typenum", + "version_check", +] + +[[package]] +name = "hex-literal" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "961de220ec9a91af2e1e5bd80d02109155695e516771762381ef8581317066e0" +dependencies = [ + "hex-literal-impl", + "proc-macro-hack", +] + +[[package]] +name = "hex-literal-impl" +version = "0.2.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "853f769599eb31de176303197b7ba4973299c38c7a7604a6bc88c3eef05b9b46" +dependencies = [ + "proc-macro-hack", +] + +[[package]] +name = "libc" +version = "0.2.71" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9457b06509d27052635f90d6466700c65095fdf75409b3fbdd903e988b886f49" + +[[package]] +name = "opaque-debug" +version = "0.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "624a8340c38c1b80fd549087862da4ba43e08858af025b236e509b6649fc13d5" + +[[package]] +name = "proc-macro-hack" +version = "0.5.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7e0456befd48169b9f13ef0f0ad46d492cf9d2dbb918bcf38e01eed4ce3ec5e4" + +[[package]] +name = "sha2" +version = "0.9.1" +dependencies = [ + "block-buffer", + "cfg-if", + "cpuid-bool", + "digest", + "hex-literal", + "libc", + "opaque-debug", + "sha2-asm", +] + +[[package]] +name = "sha2-asm" +version = "0.5.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "92cfa120723b595090343400d71e4921ba4fbc7d0d48718d72c20b3348469678" +dependencies = [ + "cc", +] + +[[package]] +name = "typenum" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "373c8a200f9e67a0c95e62a4f52fbf80c23b4381c05a17845531982fa99e6b33" + +[[package]] +name = "version_check" +version = "0.9.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed" diff --git a/vendor/sha2/Cargo.toml b/vendor/sha2/Cargo.toml new file mode 100644 index 0000000000..39fe22351b --- /dev/null +++ b/vendor/sha2/Cargo.toml @@ -0,0 +1,57 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "sha2" +version = "0.9.1" +authors = ["RustCrypto Developers"] +description = "Pure Rust implementation of the SHA-2 hash function family\nincluding SHA-224, SHA-256, SHA-384, and SHA-512.\n" +documentation = "https://docs.rs/sha2" +readme = "README.md" +keywords = ["crypto", "sha2", "hash", "digest"] +categories = ["cryptography", "no-std"] +license = "MIT OR Apache-2.0" +repository = "https://github.com/RustCrypto/hashes" +[dependencies.block-buffer] +version = "0.9" + +[dependencies.cfg-if] +version = "0.1" + +[dependencies.digest] +version = "0.9" + +[dependencies.opaque-debug] +version = "0.3" + +[dependencies.sha2-asm] +version = "0.5" +optional = true +[dev-dependencies.digest] +version = "0.9" +features = ["dev"] + +[dev-dependencies.hex-literal] +version = "0.2" + +[features] +asm = ["sha2-asm", "libc"] +asm-aarch64 = ["asm"] +compress = [] +default = ["std"] +std = ["digest/std"] +[target."cfg(all(target_arch = \"aarch64\", target_os = \"linux\"))".dependencies.libc] +version = "0.2.68" +optional = true +[target."cfg(any(target_arch = \"x86\", target_arch = \"x86_64\"))".dependencies.cpuid-bool] +version = "0.1" diff --git a/vendor/sha2/LICENSE-APACHE b/vendor/sha2/LICENSE-APACHE new file mode 100644 index 0000000000..78173fa2e7 --- /dev/null +++ b/vendor/sha2/LICENSE-APACHE @@ -0,0 +1,201 @@ + 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 + +APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + +Copyright [yyyy] [name of copyright owner] + +Licensed under the Apache License, Version 2.0 (the "License"); +you may not use this file except in compliance with the License. +You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + +Unless required by applicable law or agreed to in writing, software +distributed under the License is distributed on an "AS IS" BASIS, +WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +See the License for the specific language governing permissions and +limitations under the License. diff --git a/vendor/sha2/LICENSE-MIT b/vendor/sha2/LICENSE-MIT new file mode 100644 index 0000000000..66cf75563b --- /dev/null +++ b/vendor/sha2/LICENSE-MIT @@ -0,0 +1,27 @@ +Copyright (c) 2006-2009 Graydon Hoare +Copyright (c) 2009-2013 Mozilla Foundation +Copyright (c) 2016 Artyom Pavlov + +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 --git a/vendor/sha2/README.md b/vendor/sha2/README.md new file mode 100644 index 0000000000..cbcde5eaab --- /dev/null +++ b/vendor/sha2/README.md @@ -0,0 +1,56 @@ +# RustCrypto: SHA-2 + +[![crate][crate-image]][crate-link] +[![Docs][docs-image]][docs-link] +![Apache2/MIT licensed][license-image] +![Rust Version][rustc-image] +[![Build Status][build-image]][build-link] + +Pure Rust implementation of the [SHA-2 hash function family][1] +including SHA-224, SHA-256, SHA-384, and SHA-512. + +[Documentation][docs-link] + + + +## Minimum Supported Rust Version + +Rust **1.41** or higher. + +Minimum supported Rust version can be changed in the future, but it will be +done with a minor version bump. + +## SemVer Policy + +- All on-by-default features of this library are covered by SemVer +- MSRV is considered exempt from SemVer as noted above + +## License + +Licensed under either of: + + * [Apache License, Version 2.0](http://www.apache.org/licenses/LICENSE-2.0) + * [MIT license](http://opensource.org/licenses/MIT) + +at your option. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in the work by you, as defined in the Apache-2.0 license, shall be +dual licensed as above, without any additional terms or conditions. + +[//]: # (badges) + +[crate-image]: https://img.shields.io/crates/v/sha2.svg +[crate-link]: https://crates.io/crates/sha2 +[docs-image]: https://docs.rs/sha2/badge.svg +[docs-link]: https://docs.rs/sha2/ +[license-image]: https://img.shields.io/badge/license-Apache2.0/MIT-blue.svg +[rustc-image]: https://img.shields.io/badge/rustc-1.41+-blue.svg +[build-image]: https://github.com/RustCrypto/hashes/workflows/sha2/badge.svg?branch=master +[build-link]: https://github.com/RustCrypto/hashes/actions?query=workflow%3Asha2 + +[//]: # (general links) + +[1]: https://en.wikipedia.org/wiki/SHA-2 diff --git a/vendor/sha2/benches/sha256.rs b/vendor/sha2/benches/sha256.rs new file mode 100644 index 0000000000..181a68c406 --- /dev/null +++ b/vendor/sha2/benches/sha256.rs @@ -0,0 +1,4 @@ +#![no_std] +#![feature(test)] + +digest::bench!(sha2::Sha256); diff --git a/vendor/sha2/benches/sha512.rs b/vendor/sha2/benches/sha512.rs new file mode 100644 index 0000000000..88708b383d --- /dev/null +++ b/vendor/sha2/benches/sha512.rs @@ -0,0 +1,4 @@ +#![no_std] +#![feature(test)] + +digest::bench!(sha2::Sha512); diff --git a/vendor/sha2/examples/sha256sum.rs b/vendor/sha2/examples/sha256sum.rs new file mode 100644 index 0000000000..31ee979290 --- /dev/null +++ b/vendor/sha2/examples/sha256sum.rs @@ -0,0 +1,47 @@ +use sha2::{Digest, Sha256}; +use std::env; +use std::fs; +use std::io::{self, Read}; + +const BUFFER_SIZE: usize = 1024; + +/// Print digest result as hex string and name pair +fn print_result(sum: &[u8], name: &str) { + for byte in sum { + print!("{:02x}", byte); + } + println!("\t{}", name); +} + +/// Compute digest value for given `Reader` and print it +/// On any error simply return without doing anything +fn process(reader: &mut R, name: &str) { + let mut sh = D::default(); + let mut buffer = [0u8; BUFFER_SIZE]; + loop { + let n = match reader.read(&mut buffer) { + Ok(n) => n, + Err(_) => return, + }; + sh.update(&buffer[..n]); + if n == 0 || n < BUFFER_SIZE { + break; + } + } + print_result(&sh.finalize(), name); +} + +fn main() { + let args = env::args(); + // Process files listed in command line arguments one by one + // If no files provided process input from stdin + if args.len() > 1 { + for path in args.skip(1) { + if let Ok(mut file) = fs::File::open(&path) { + process::(&mut file, &path); + } + } + } else { + process::(&mut io::stdin(), "-"); + } +} diff --git a/vendor/sha2/examples/sha512sum.rs b/vendor/sha2/examples/sha512sum.rs new file mode 100644 index 0000000000..9d4785acdb --- /dev/null +++ b/vendor/sha2/examples/sha512sum.rs @@ -0,0 +1,47 @@ +use sha2::{Digest, Sha512}; +use std::env; +use std::fs; +use std::io::{self, Read}; + +const BUFFER_SIZE: usize = 1024; + +/// Print digest result as hex string and name pair +fn print_result(sum: &[u8], name: &str) { + for byte in sum { + print!("{:02x}", byte); + } + println!("\t{}", name); +} + +/// Compute digest value for given `Reader` and print it +/// On any error simply return without doing anything +fn process(reader: &mut R, name: &str) { + let mut sh = D::default(); + let mut buffer = [0u8; BUFFER_SIZE]; + loop { + let n = match reader.read(&mut buffer) { + Ok(n) => n, + Err(_) => return, + }; + sh.update(&buffer[..n]); + if n == 0 || n < BUFFER_SIZE { + break; + } + } + print_result(&sh.finalize(), name); +} + +fn main() { + let args = env::args(); + // Process files listed in command line arguments one by one + // If no files provided process input from stdin + if args.len() > 1 { + for path in args.skip(1) { + if let Ok(mut file) = fs::File::open(&path) { + process::(&mut file, &path); + } + } + } else { + process::(&mut io::stdin(), "-"); + } +} diff --git a/vendor/sha2/src/consts.rs b/vendor/sha2/src/consts.rs new file mode 100644 index 0000000000..f126dc616c --- /dev/null +++ b/vendor/sha2/src/consts.rs @@ -0,0 +1,216 @@ +#![allow(dead_code, clippy::unreadable_literal)] + +pub const STATE_LEN: usize = 8; +pub const BLOCK_LEN: usize = 16; + +/// Constants necessary for SHA-256 family of digests. +pub const K32: [u32; 64] = [ + 0x428a2f98, 0x71374491, 0xb5c0fbcf, 0xe9b5dba5, 0x3956c25b, 0x59f111f1, 0x923f82a4, 0xab1c5ed5, + 0xd807aa98, 0x12835b01, 0x243185be, 0x550c7dc3, 0x72be5d74, 0x80deb1fe, 0x9bdc06a7, 0xc19bf174, + 0xe49b69c1, 0xefbe4786, 0x0fc19dc6, 0x240ca1cc, 0x2de92c6f, 0x4a7484aa, 0x5cb0a9dc, 0x76f988da, + 0x983e5152, 0xa831c66d, 0xb00327c8, 0xbf597fc7, 0xc6e00bf3, 0xd5a79147, 0x06ca6351, 0x14292967, + 0x27b70a85, 0x2e1b2138, 0x4d2c6dfc, 0x53380d13, 0x650a7354, 0x766a0abb, 0x81c2c92e, 0x92722c85, + 0xa2bfe8a1, 0xa81a664b, 0xc24b8b70, 0xc76c51a3, 0xd192e819, 0xd6990624, 0xf40e3585, 0x106aa070, + 0x19a4c116, 0x1e376c08, 0x2748774c, 0x34b0bcb5, 0x391c0cb3, 0x4ed8aa4a, 0x5b9cca4f, 0x682e6ff3, + 0x748f82ee, 0x78a5636f, 0x84c87814, 0x8cc70208, 0x90befffa, 0xa4506ceb, 0xbef9a3f7, 0xc67178f2, +]; + +/// Constants necessary for SHA-256 family of digests. +pub const K32X4: [[u32; 4]; 16] = [ + [K32[3], K32[2], K32[1], K32[0]], + [K32[7], K32[6], K32[5], K32[4]], + [K32[11], K32[10], K32[9], K32[8]], + [K32[15], K32[14], K32[13], K32[12]], + [K32[19], K32[18], K32[17], K32[16]], + [K32[23], K32[22], K32[21], K32[20]], + [K32[27], K32[26], K32[25], K32[24]], + [K32[31], K32[30], K32[29], K32[28]], + [K32[35], K32[34], K32[33], K32[32]], + [K32[39], K32[38], K32[37], K32[36]], + [K32[43], K32[42], K32[41], K32[40]], + [K32[47], K32[46], K32[45], K32[44]], + [K32[51], K32[50], K32[49], K32[48]], + [K32[55], K32[54], K32[53], K32[52]], + [K32[59], K32[58], K32[57], K32[56]], + [K32[63], K32[62], K32[61], K32[60]], +]; + +/// Constants necessary for SHA-512 family of digests. +pub const K64: [u64; 80] = [ + 0x428a2f98d728ae22, + 0x7137449123ef65cd, + 0xb5c0fbcfec4d3b2f, + 0xe9b5dba58189dbbc, + 0x3956c25bf348b538, + 0x59f111f1b605d019, + 0x923f82a4af194f9b, + 0xab1c5ed5da6d8118, + 0xd807aa98a3030242, + 0x12835b0145706fbe, + 0x243185be4ee4b28c, + 0x550c7dc3d5ffb4e2, + 0x72be5d74f27b896f, + 0x80deb1fe3b1696b1, + 0x9bdc06a725c71235, + 0xc19bf174cf692694, + 0xe49b69c19ef14ad2, + 0xefbe4786384f25e3, + 0x0fc19dc68b8cd5b5, + 0x240ca1cc77ac9c65, + 0x2de92c6f592b0275, + 0x4a7484aa6ea6e483, + 0x5cb0a9dcbd41fbd4, + 0x76f988da831153b5, + 0x983e5152ee66dfab, + 0xa831c66d2db43210, + 0xb00327c898fb213f, + 0xbf597fc7beef0ee4, + 0xc6e00bf33da88fc2, + 0xd5a79147930aa725, + 0x06ca6351e003826f, + 0x142929670a0e6e70, + 0x27b70a8546d22ffc, + 0x2e1b21385c26c926, + 0x4d2c6dfc5ac42aed, + 0x53380d139d95b3df, + 0x650a73548baf63de, + 0x766a0abb3c77b2a8, + 0x81c2c92e47edaee6, + 0x92722c851482353b, + 0xa2bfe8a14cf10364, + 0xa81a664bbc423001, + 0xc24b8b70d0f89791, + 0xc76c51a30654be30, + 0xd192e819d6ef5218, + 0xd69906245565a910, + 0xf40e35855771202a, + 0x106aa07032bbd1b8, + 0x19a4c116b8d2d0c8, + 0x1e376c085141ab53, + 0x2748774cdf8eeb99, + 0x34b0bcb5e19b48a8, + 0x391c0cb3c5c95a63, + 0x4ed8aa4ae3418acb, + 0x5b9cca4f7763e373, + 0x682e6ff3d6b2b8a3, + 0x748f82ee5defb2fc, + 0x78a5636f43172f60, + 0x84c87814a1f0ab72, + 0x8cc702081a6439ec, + 0x90befffa23631e28, + 0xa4506cebde82bde9, + 0xbef9a3f7b2c67915, + 0xc67178f2e372532b, + 0xca273eceea26619c, + 0xd186b8c721c0c207, + 0xeada7dd6cde0eb1e, + 0xf57d4f7fee6ed178, + 0x06f067aa72176fba, + 0x0a637dc5a2c898a6, + 0x113f9804bef90dae, + 0x1b710b35131c471b, + 0x28db77f523047d84, + 0x32caab7b40c72493, + 0x3c9ebe0a15c9bebc, + 0x431d67c49c100d4c, + 0x4cc5d4becb3e42b6, + 0x597f299cfc657e2a, + 0x5fcb6fab3ad6faec, + 0x6c44198c4a475817, +]; + +/// Constants necessary for SHA-512 family of digests. +pub const K64X2: [[u64; 2]; 40] = [ + [K64[1], K64[0]], + [K64[3], K64[2]], + [K64[5], K64[4]], + [K64[7], K64[6]], + [K64[9], K64[8]], + [K64[11], K64[10]], + [K64[13], K64[12]], + [K64[15], K64[14]], + [K64[17], K64[16]], + [K64[19], K64[18]], + [K64[21], K64[20]], + [K64[23], K64[22]], + [K64[25], K64[24]], + [K64[27], K64[26]], + [K64[29], K64[28]], + [K64[31], K64[30]], + [K64[33], K64[32]], + [K64[35], K64[34]], + [K64[37], K64[36]], + [K64[39], K64[38]], + [K64[41], K64[40]], + [K64[43], K64[42]], + [K64[45], K64[44]], + [K64[47], K64[46]], + [K64[49], K64[48]], + [K64[51], K64[50]], + [K64[53], K64[52]], + [K64[55], K64[54]], + [K64[57], K64[56]], + [K64[59], K64[58]], + [K64[61], K64[60]], + [K64[63], K64[62]], + [K64[65], K64[64]], + [K64[67], K64[66]], + [K64[69], K64[68]], + [K64[71], K64[70]], + [K64[73], K64[72]], + [K64[75], K64[74]], + [K64[77], K64[76]], + [K64[79], K64[78]], +]; + +pub static H224: [u32; STATE_LEN] = [ + 0xc1059ed8, 0x367cd507, 0x3070dd17, 0xf70e5939, 0xffc00b31, 0x68581511, 0x64f98fa7, 0xbefa4fa4, +]; + +pub static H256: [u32; STATE_LEN] = [ + 0x6a09e667, 0xbb67ae85, 0x3c6ef372, 0xa54ff53a, 0x510e527f, 0x9b05688c, 0x1f83d9ab, 0x5be0cd19, +]; + +pub static H384: [u64; STATE_LEN] = [ + 0xcbbb9d5dc1059ed8, + 0x629a292a367cd507, + 0x9159015a3070dd17, + 0x152fecd8f70e5939, + 0x67332667ffc00b31, + 0x8eb44a8768581511, + 0xdb0c2e0d64f98fa7, + 0x47b5481dbefa4fa4, +]; + +pub static H512: [u64; STATE_LEN] = [ + 0x6a09e667f3bcc908, + 0xbb67ae8584caa73b, + 0x3c6ef372fe94f82b, + 0xa54ff53a5f1d36f1, + 0x510e527fade682d1, + 0x9b05688c2b3e6c1f, + 0x1f83d9abfb41bd6b, + 0x5be0cd19137e2179, +]; + +pub static H512_TRUNC_224: [u64; STATE_LEN] = [ + 0x8c3d37c819544da2, + 0x73e1996689dcd4d6, + 0x1dfab7ae32ff9c82, + 0x679dd514582f9fcf, + 0x0f6d2b697bd44da8, + 0x77e36f7304c48942, + 0x3f9d85a86a1d36c8, + 0x1112e6ad91d692a1, +]; + +pub static H512_TRUNC_256: [u64; STATE_LEN] = [ + 0x22312194fc2bf72c, + 0x9f555fa3c84c64c2, + 0x2393b86b6f53b151, + 0x963877195940eabd, + 0x96283ee2a88effe3, + 0xbe5e1e2553863992, + 0x2b0199fc2c85b8aa, + 0x0eb72ddc81c52ca2, +]; diff --git a/vendor/sha2/src/lib.rs b/vendor/sha2/src/lib.rs new file mode 100644 index 0000000000..08829eab2a --- /dev/null +++ b/vendor/sha2/src/lib.rs @@ -0,0 +1,72 @@ +//! An implementation of the [SHA-2][1] cryptographic hash algorithms. +//! +//! There are 6 standard algorithms specified in the SHA-2 standard: +//! +//! * `Sha224`, which is the 32-bit `Sha256` algorithm with the result truncated +//! to 224 bits. +//! * `Sha256`, which is the 32-bit `Sha256` algorithm. +//! * `Sha384`, which is the 64-bit `Sha512` algorithm with the result truncated +//! to 384 bits. +//! * `Sha512`, which is the 64-bit `Sha512` algorithm. +//! * `Sha512Trunc224`, which is the 64-bit `Sha512` algorithm with the result +//! truncated to 224 bits. +//! * `Sha512Trunc256`, which is the 64-bit `Sha512` algorithm with the result +//! truncated to 256 bits. +//! +//! Algorithmically, there are only 2 core algorithms: `Sha256` and `Sha512`. +//! All other algorithms are just applications of these with different initial +//! hash values, and truncated to different digest bit lengths. +//! +//! # Usage +//! +//! ```rust +//! use hex_literal::hex; +//! use sha2::{Sha256, Sha512, Digest}; +//! +//! // create a Sha256 object +//! let mut hasher = Sha256::new(); +//! +//! // write input message +//! hasher.update(b"hello world"); +//! +//! // read hash digest and consume hasher +//! let result = hasher.finalize(); +//! +//! assert_eq!(result[..], hex!(" +//! b94d27b9934d3e08a52e52d7da7dabfac484efe37a5380ee9088f7ace2efcde9 +//! ")[..]); +//! +//! // same for Sha512 +//! let mut hasher = Sha512::new(); +//! hasher.update(b"hello world"); +//! let result = hasher.finalize(); +//! +//! assert_eq!(result[..], hex!(" +//! 309ecc489c12d6eb4cc40f50c902f2b4d0ed77ee511a7c7a9bcd3ca86d4cd86f +//! 989dd35bc5ff499670da34255b45b0cfd830e81f605dcf7dc5542e93ae9cd76f +//! ")[..]); +//! ``` +//! +//! Also see [RustCrypto/hashes][2] readme. +//! +//! [1]: https://en.wikipedia.org/wiki/SHA-2 +//! [2]: https://github.com/RustCrypto/hashes + +#![no_std] +#![doc(html_logo_url = "https://raw.githubusercontent.com/RustCrypto/meta/master/logo_small.png")] +#![warn(missing_docs, rust_2018_idioms)] + +#[cfg(feature = "std")] +extern crate std; + +mod consts; +mod sha256; +mod sha512; + +pub use digest::{self, Digest}; +#[cfg(feature = "compress")] +pub use sha256::compress256; +pub use sha256::{Sha224, Sha256}; +#[cfg(feature = "compress")] +pub use sha512::compress512; +pub use sha512::{Sha384, Sha512, Sha512Trunc224, Sha512Trunc256}; diff --git a/vendor/sha2/src/sha256.rs b/vendor/sha2/src/sha256.rs new file mode 100644 index 0000000000..8ee97beddd --- /dev/null +++ b/vendor/sha2/src/sha256.rs @@ -0,0 +1,169 @@ +//! SHA-256 +use crate::consts::{H224, H256, STATE_LEN}; +use block_buffer::BlockBuffer; +use core::slice::from_ref; +use digest::consts::{U28, U32, U64}; +use digest::generic_array::GenericArray; +use digest::{BlockInput, FixedOutputDirty, Reset, Update}; + +type BlockSize = U64; + +/// Structure that keeps state of the Sha-256 operation and +/// contains the logic necessary to perform the final calculations. +#[derive(Clone)] +struct Engine256 { + len: u64, + buffer: BlockBuffer, + state: [u32; 8], +} + +impl Engine256 { + fn new(h: &[u32; STATE_LEN]) -> Engine256 { + Engine256 { + len: 0, + buffer: Default::default(), + state: *h, + } + } + + fn update(&mut self, input: &[u8]) { + // Assumes that input.len() can be converted to u64 without overflow + self.len += (input.len() as u64) << 3; + let s = &mut self.state; + self.buffer.input_blocks(input, |b| compress256(s, b)); + } + + fn finish(&mut self) { + let s = &mut self.state; + let l = self.len; + self.buffer + .len64_padding_be(l, |b| compress256(s, from_ref(b))); + } + + fn reset(&mut self, h: &[u32; STATE_LEN]) { + self.len = 0; + self.buffer.reset(); + self.state = *h; + } +} + +/// The SHA-256 hash algorithm with the SHA-256 initial hash value. +#[derive(Clone)] +pub struct Sha256 { + engine: Engine256, +} + +impl Default for Sha256 { + fn default() -> Self { + Sha256 { + engine: Engine256::new(&H256), + } + } +} + +impl BlockInput for Sha256 { + type BlockSize = BlockSize; +} + +impl Update for Sha256 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha256 { + type OutputSize = U32; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = self.engine.state; + for (chunk, v) in out.chunks_exact_mut(4).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha256 { + fn reset(&mut self) { + self.engine.reset(&H256); + } +} + +/// The SHA-256 hash algorithm with the SHA-224 initial hash value. The result +/// is truncated to 224 bits. +#[derive(Clone)] +pub struct Sha224 { + engine: Engine256, +} + +impl Default for Sha224 { + fn default() -> Self { + Sha224 { + engine: Engine256::new(&H224), + } + } +} + +impl BlockInput for Sha224 { + type BlockSize = BlockSize; +} + +impl Update for Sha224 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha224 { + type OutputSize = U28; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state[..7]; + for (chunk, v) in out.chunks_exact_mut(4).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha224 { + fn reset(&mut self) { + self.engine.reset(&H224); + } +} + +opaque_debug::implement!(Sha224); +opaque_debug::implement!(Sha256); + +digest::impl_write!(Sha224); +digest::impl_write!(Sha256); + +cfg_if::cfg_if! { + if #[cfg(all(feature = "asm", target_arch = "aarch64", target_os = "linux"))] { + mod soft; + mod aarch64; + use aarch64::compress; + } else if #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] { + // TODO: replace after sha2-asm rework + fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + for block in blocks { + sha2_asm::compress256(state, block); + } + } + } else if #[cfg(any(target_arch = "x86", target_arch = "x86_64"))] { + mod soft; + mod x86; + use x86::compress; + } else { + mod soft; + use soft::compress; + } +} + +pub fn compress256(state: &mut [u32; 8], blocks: &[GenericArray]) { + // SAFETY: GenericArray and [u8; 64] have + // exactly the same memory layout + #[allow(unsafe_code)] + let blocks: &[[u8; 64]] = unsafe { &*(blocks as *const _ as *const [[u8; 64]]) }; + compress(state, blocks) +} diff --git a/vendor/sha2/src/sha256/aarch64.rs b/vendor/sha2/src/sha256/aarch64.rs new file mode 100644 index 0000000000..a5967ca0c4 --- /dev/null +++ b/vendor/sha2/src/sha256/aarch64.rs @@ -0,0 +1,20 @@ +use libc::{getauxval, AT_HWCAP, HWCAP_SHA2}; + +#[inline(always)] +pub fn sha2_supported() -> bool { + let hwcaps: u64 = unsafe { getauxval(AT_HWCAP) }; + (hwcaps & HWCAP_SHA2) != 0 +} + +pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + // TODO: Replace with https://github.com/rust-lang/rfcs/pull/2725 + // after stabilization + if sha2_supported() { + // TODO: replace after sha2-asm rework + for block in blocks { + sha2_asm::compress256(&mut self.h, block); + } + } else { + super::soft::compress(&mut self.h, block); + } +} diff --git a/vendor/sha2/src/sha256/soft.rs b/vendor/sha2/src/sha256/soft.rs new file mode 100644 index 0000000000..d7be01dc62 --- /dev/null +++ b/vendor/sha2/src/sha256/soft.rs @@ -0,0 +1,219 @@ +#![allow(clippy::many_single_char_names)] +use crate::consts::BLOCK_LEN; +use core::convert::TryInto; + +#[inline(always)] +fn shl(v: [u32; 4], o: u32) -> [u32; 4] { + [v[0] >> o, v[1] >> o, v[2] >> o, v[3] >> o] +} + +#[inline(always)] +fn shr(v: [u32; 4], o: u32) -> [u32; 4] { + [v[0] << o, v[1] << o, v[2] << o, v[3] << o] +} + +#[inline(always)] +fn or(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { + [a[0] | b[0], a[1] | b[1], a[2] | b[2], a[3] | b[3]] +} + +#[inline(always)] +fn xor(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { + [a[0] ^ b[0], a[1] ^ b[1], a[2] ^ b[2], a[3] ^ b[3]] +} + +#[inline(always)] +fn add(a: [u32; 4], b: [u32; 4]) -> [u32; 4] { + [ + a[0].wrapping_add(b[0]), + a[1].wrapping_add(b[1]), + a[2].wrapping_add(b[2]), + a[3].wrapping_add(b[3]), + ] +} + +fn sha256load(v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] { + [v3[3], v2[0], v2[1], v2[2]] +} + +fn sha256swap(v0: [u32; 4]) -> [u32; 4] { + [v0[2], v0[3], v0[0], v0[1]] +} + +fn sha256msg1(v0: [u32; 4], v1: [u32; 4]) -> [u32; 4] { + // sigma 0 on vectors + #[inline] + fn sigma0x4(x: [u32; 4]) -> [u32; 4] { + let t1 = or(shl(x, 7), shr(x, 25)); + let t2 = or(shl(x, 18), shr(x, 14)); + let t3 = shl(x, 3); + xor(xor(t1, t2), t3) + } + + add(v0, sigma0x4(sha256load(v0, v1))) +} + +fn sha256msg2(v4: [u32; 4], v3: [u32; 4]) -> [u32; 4] { + macro_rules! sigma1 { + ($a:expr) => { + $a.rotate_right(17) ^ $a.rotate_right(19) ^ ($a >> 10) + }; + } + + let [x3, x2, x1, x0] = v4; + let [w15, w14, _, _] = v3; + + let w16 = x0.wrapping_add(sigma1!(w14)); + let w17 = x1.wrapping_add(sigma1!(w15)); + let w18 = x2.wrapping_add(sigma1!(w16)); + let w19 = x3.wrapping_add(sigma1!(w17)); + + [w19, w18, w17, w16] +} + +fn sha256_digest_round_x2(cdgh: [u32; 4], abef: [u32; 4], wk: [u32; 4]) -> [u32; 4] { + macro_rules! big_sigma0 { + ($a:expr) => { + ($a.rotate_right(2) ^ $a.rotate_right(13) ^ $a.rotate_right(22)) + }; + } + macro_rules! big_sigma1 { + ($a:expr) => { + ($a.rotate_right(6) ^ $a.rotate_right(11) ^ $a.rotate_right(25)) + }; + } + macro_rules! bool3ary_202 { + ($a:expr, $b:expr, $c:expr) => { + $c ^ ($a & ($b ^ $c)) + }; + } // Choose, MD5F, SHA1C + macro_rules! bool3ary_232 { + ($a:expr, $b:expr, $c:expr) => { + ($a & $b) ^ ($a & $c) ^ ($b & $c) + }; + } // Majority, SHA1M + + let [_, _, wk1, wk0] = wk; + let [a0, b0, e0, f0] = abef; + let [c0, d0, g0, h0] = cdgh; + + // a round + let x0 = big_sigma1!(e0) + .wrapping_add(bool3ary_202!(e0, f0, g0)) + .wrapping_add(wk0) + .wrapping_add(h0); + let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0)); + let (a1, b1, c1, d1, e1, f1, g1, h1) = ( + x0.wrapping_add(y0), + a0, + b0, + c0, + x0.wrapping_add(d0), + e0, + f0, + g0, + ); + + // a round + let x1 = big_sigma1!(e1) + .wrapping_add(bool3ary_202!(e1, f1, g1)) + .wrapping_add(wk1) + .wrapping_add(h1); + let y1 = big_sigma0!(a1).wrapping_add(bool3ary_232!(a1, b1, c1)); + let (a2, b2, _, _, e2, f2, _, _) = ( + x1.wrapping_add(y1), + a1, + b1, + c1, + x1.wrapping_add(d1), + e1, + f1, + g1, + ); + + [a2, b2, e2, f2] +} + +fn schedule(v0: [u32; 4], v1: [u32; 4], v2: [u32; 4], v3: [u32; 4]) -> [u32; 4] { + let t1 = sha256msg1(v0, v1); + let t2 = sha256load(v2, v3); + let t3 = add(t1, t2); + sha256msg2(t3, v3) +} + +macro_rules! rounds4 { + ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{ + let t1 = add($rest, crate::consts::K32X4[$i]); + $cdgh = sha256_digest_round_x2($cdgh, $abef, t1); + let t2 = sha256swap(t1); + $abef = sha256_digest_round_x2($abef, $cdgh, t2); + }}; +} + +macro_rules! schedule_rounds4 { + ( + $abef:ident, $cdgh:ident, + $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr, + $i: expr + ) => {{ + $w4 = schedule($w0, $w1, $w2, $w3); + rounds4!($abef, $cdgh, $w4, $i); + }}; +} + +/// Process a block with the SHA-256 algorithm. +fn sha256_digest_block_u32(state: &mut [u32; 8], block: &[u32; 16]) { + let mut abef = [state[0], state[1], state[4], state[5]]; + let mut cdgh = [state[2], state[3], state[6], state[7]]; + + + // Rounds 0..64 + let mut w0 = [block[3], block[2], block[1], block[0]]; + let mut w1 = [block[7], block[6], block[5], block[4]]; + let mut w2 = [block[11], block[10], block[9], block[8]]; + let mut w3 = [block[15], block[14], block[13], block[12]]; + let mut w4; + + rounds4!(abef, cdgh, w0, 0); + rounds4!(abef, cdgh, w1, 1); + rounds4!(abef, cdgh, w2, 2); + rounds4!(abef, cdgh, w3, 3); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15); + + let [a, b, e, f] = abef; + let [c, d, g, h] = cdgh; + + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); + state[5] = state[5].wrapping_add(f); + state[6] = state[6].wrapping_add(g); + state[7] = state[7].wrapping_add(h); +} + +pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + let mut block_u32 = [0u32; BLOCK_LEN]; + // since LLVM can't properly use aliasing yet it will make + // unnecessary state stores without this copy + let mut state_cpy = *state; + for block in blocks { + for (o, chunk) in block_u32.iter_mut().zip(block.chunks_exact(4)) { + *o = u32::from_be_bytes(chunk.try_into().unwrap()); + } + sha256_digest_block_u32(&mut state_cpy, &block_u32); + } + *state = state_cpy; +} diff --git a/vendor/sha2/src/sha256/x86.rs b/vendor/sha2/src/sha256/x86.rs new file mode 100644 index 0000000000..04a7d26d07 --- /dev/null +++ b/vendor/sha2/src/sha256/x86.rs @@ -0,0 +1,108 @@ +#![allow(clippy::many_single_char_names)] + +#[cfg(target_arch = "x86_64")] +use core::arch::x86_64::*; +#[cfg(target_arch = "x86")] +use core::arch::x86::*; + +unsafe fn schedule(v0: __m128i, v1: __m128i, v2: __m128i, v3: __m128i) -> __m128i { + let t1 = _mm_sha256msg1_epu32(v0, v1); + let t2 = _mm_alignr_epi8(v3, v2, 4); + let t3 = _mm_add_epi32(t1, t2); + _mm_sha256msg2_epu32(t3, v3) +} + +macro_rules! rounds4 { + ($abef:ident, $cdgh:ident, $rest:expr, $i:expr) => {{ + let k = crate::consts::K32X4[$i]; + let kv = _mm_set_epi32(k[0] as i32, k[1] as i32, k[2] as i32, k[3] as i32); + let t1 = _mm_add_epi32($rest, kv); + $cdgh = _mm_sha256rnds2_epu32($cdgh, $abef, t1); + let t2 = _mm_shuffle_epi32(t1, 0x0E); + $abef = _mm_sha256rnds2_epu32($abef, $cdgh, t2); + }}; +} + +macro_rules! schedule_rounds4 { + ( + $abef:ident, $cdgh:ident, + $w0:expr, $w1:expr, $w2:expr, $w3:expr, $w4:expr, + $i: expr + ) => {{ + $w4 = schedule($w0, $w1, $w2, $w3); + rounds4!($abef, $cdgh, $w4, $i); + }}; +} + +// we use unaligned loads with `__m128i` pointers +#[allow(clippy::cast_ptr_alignment)] +#[target_feature(enable = "sha,sse2,ssse3,sse4.1")] +unsafe fn digest_blocks(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + #[allow(non_snake_case)] + let MASK: __m128i = _mm_set_epi64x( + 0x0C0D_0E0F_0809_0A0Bu64 as i64, + 0x0405_0607_0001_0203u64 as i64, + ); + + let state_ptr = state.as_ptr() as *const __m128i; + let dcba = _mm_loadu_si128(state_ptr.add(0)); + let efgh = _mm_loadu_si128(state_ptr.add(1)); + + let cdab = _mm_shuffle_epi32(dcba, 0xB1); + let efgh = _mm_shuffle_epi32(efgh, 0x1B); + let mut abef = _mm_alignr_epi8(cdab, efgh, 8); + let mut cdgh = _mm_blend_epi16(efgh, cdab, 0xF0); + + for block in blocks { + let abef_save = abef; + let cdgh_save = cdgh; + + let data_ptr = block.as_ptr() as *const __m128i; + let mut w0 = _mm_shuffle_epi8(_mm_loadu_si128(data_ptr.add(0)), MASK); + let mut w1 = _mm_shuffle_epi8(_mm_loadu_si128(data_ptr.add(1)), MASK); + let mut w2 = _mm_shuffle_epi8(_mm_loadu_si128(data_ptr.add(2)), MASK); + let mut w3 = _mm_shuffle_epi8( _mm_loadu_si128(data_ptr.add(3)), MASK); + let mut w4; + + rounds4!(abef, cdgh, w0, 0); + rounds4!(abef, cdgh, w1, 1); + rounds4!(abef, cdgh, w2, 2); + rounds4!(abef, cdgh, w3, 3); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 4); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 5); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 6); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 7); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 8); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 9); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 10); + schedule_rounds4!(abef, cdgh, w2, w3, w4, w0, w1, 11); + schedule_rounds4!(abef, cdgh, w3, w4, w0, w1, w2, 12); + schedule_rounds4!(abef, cdgh, w4, w0, w1, w2, w3, 13); + schedule_rounds4!(abef, cdgh, w0, w1, w2, w3, w4, 14); + schedule_rounds4!(abef, cdgh, w1, w2, w3, w4, w0, 15); + + abef = _mm_add_epi32(abef, abef_save); + cdgh = _mm_add_epi32(cdgh, cdgh_save); + } + + let feba = _mm_shuffle_epi32(abef, 0x1B); + let dchg = _mm_shuffle_epi32(cdgh, 0xB1); + let dcba = _mm_blend_epi16(feba, dchg, 0xF0); + let hgef = _mm_alignr_epi8(dchg, feba, 8); + + let state_ptr_mut = state.as_mut_ptr() as *mut __m128i; + _mm_storeu_si128(state_ptr_mut.add(0), dcba); + _mm_storeu_si128(state_ptr_mut.add(1), hgef); +} + +pub fn compress(state: &mut [u32; 8], blocks: &[[u8; 64]]) { + // TODO: Replace with https://github.com/rust-lang/rfcs/pull/2725 + // after stabilization + if cpuid_bool::cpuid_bool!("sha", "sse2", "ssse3", "sse4.1") { + unsafe { + digest_blocks(state, blocks); + } + } else { + super::soft::compress(state, blocks); + } +} diff --git a/vendor/sha2/src/sha512.rs b/vendor/sha2/src/sha512.rs new file mode 100644 index 0000000000..de115d4426 --- /dev/null +++ b/vendor/sha2/src/sha512.rs @@ -0,0 +1,250 @@ +//! SHA-512 +use crate::consts::{H384, H512, H512_TRUNC_224, H512_TRUNC_256, STATE_LEN}; +use block_buffer::BlockBuffer; +use core::slice::from_ref; +use digest::consts::{U128, U28, U32, U48, U64}; +use digest::generic_array::GenericArray; +use digest::{BlockInput, FixedOutputDirty, Reset, Update}; + +type BlockSize = U128; + +/// Structure that keeps state of the Sha-512 operation and +/// contains the logic necessary to perform the final calculations. +#[derive(Clone)] +struct Engine512 { + len: u128, + buffer: BlockBuffer, + state: [u64; 8], +} + +impl Engine512 { + fn new(h: &[u64; STATE_LEN]) -> Engine512 { + Engine512 { + len: 0, + buffer: Default::default(), + state: *h, + } + } + + fn update(&mut self, input: &[u8]) { + self.len += (input.len() as u128) << 3; + let s = &mut self.state; + self.buffer.input_blocks(input, |b| compress512(s, b)); + } + + fn finish(&mut self) { + let s = &mut self.state; + self.buffer + .len128_padding_be(self.len, |d| compress512(s, from_ref(d))); + } + + fn reset(&mut self, h: &[u64; STATE_LEN]) { + self.len = 0; + self.buffer.reset(); + self.state = *h; + } +} + +/// The SHA-512 hash algorithm with the SHA-512 initial hash value. +#[derive(Clone)] +pub struct Sha512 { + engine: Engine512, +} + +impl Default for Sha512 { + fn default() -> Self { + Sha512 { + engine: Engine512::new(&H512), + } + } +} + +impl BlockInput for Sha512 { + type BlockSize = BlockSize; +} + +impl Update for Sha512 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha512 { + type OutputSize = U64; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = self.engine.state; + for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha512 { + fn reset(&mut self) { + self.engine.reset(&H512); + } +} + +/// The SHA-512 hash algorithm with the SHA-384 initial hash value. The result +/// is truncated to 384 bits. +#[derive(Clone)] +pub struct Sha384 { + engine: Engine512, +} + +impl Default for Sha384 { + fn default() -> Self { + Sha384 { + engine: Engine512::new(&H384), + } + } +} + +impl BlockInput for Sha384 { + type BlockSize = BlockSize; +} + +impl Update for Sha384 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha384 { + type OutputSize = U48; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state[..6]; + for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha384 { + fn reset(&mut self) { + self.engine.reset(&H384); + } +} + +/// The SHA-512 hash algorithm with the SHA-512/256 initial hash value. The +/// result is truncated to 256 bits. +#[derive(Clone)] +pub struct Sha512Trunc256 { + engine: Engine512, +} + +impl Default for Sha512Trunc256 { + fn default() -> Self { + Sha512Trunc256 { + engine: Engine512::new(&H512_TRUNC_256), + } + } +} + +impl BlockInput for Sha512Trunc256 { + type BlockSize = BlockSize; +} + +impl Update for Sha512Trunc256 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha512Trunc256 { + type OutputSize = U32; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state[..4]; + for (chunk, v) in out.chunks_exact_mut(8).zip(s.iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + } +} + +impl Reset for Sha512Trunc256 { + fn reset(&mut self) { + self.engine.reset(&H512_TRUNC_256); + } +} + +/// The SHA-512 hash algorithm with the SHA-512/224 initial hash value. +/// The result is truncated to 224 bits. +#[derive(Clone)] +pub struct Sha512Trunc224 { + engine: Engine512, +} + +impl Default for Sha512Trunc224 { + fn default() -> Self { + Sha512Trunc224 { + engine: Engine512::new(&H512_TRUNC_224), + } + } +} + +impl BlockInput for Sha512Trunc224 { + type BlockSize = BlockSize; +} + +impl Update for Sha512Trunc224 { + fn update(&mut self, input: impl AsRef<[u8]>) { + self.engine.update(input.as_ref()); + } +} + +impl FixedOutputDirty for Sha512Trunc224 { + type OutputSize = U28; + + fn finalize_into_dirty(&mut self, out: &mut digest::Output) { + self.engine.finish(); + let s = &self.engine.state; + for (chunk, v) in out.chunks_exact_mut(8).zip(s[..3].iter()) { + chunk.copy_from_slice(&v.to_be_bytes()); + } + out[24..28].copy_from_slice(&s[3].to_be_bytes()[..4]); + } +} + +impl Reset for Sha512Trunc224 { + fn reset(&mut self) { + self.engine.reset(&H512_TRUNC_224); + } +} + +opaque_debug::implement!(Sha384); +opaque_debug::implement!(Sha512); +opaque_debug::implement!(Sha512Trunc224); +opaque_debug::implement!(Sha512Trunc256); + +digest::impl_write!(Sha384); +digest::impl_write!(Sha512); +digest::impl_write!(Sha512Trunc224); +digest::impl_write!(Sha512Trunc256); + +cfg_if::cfg_if! { + if #[cfg(all(feature = "asm", any(target_arch = "x86", target_arch = "x86_64")))] { + // TODO: replace after sha2-asm rework + fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { + for block in blocks { + sha2_asm::compress512(state, block); + } + } + } else { + mod soft; + use soft::compress; + } +} + +pub fn compress512(state: &mut [u64; 8], blocks: &[GenericArray]) { + // SAFETY: GenericArray and [u8; 128] have + // exactly the same memory layout + #[allow(unsafe_code)] + let blocks: &[[u8; 128]] = unsafe { &*(blocks as *const _ as *const [[u8; 128]]) }; + compress(state, blocks) +} diff --git a/vendor/sha2/src/sha512/soft.rs b/vendor/sha2/src/sha512/soft.rs new file mode 100644 index 0000000000..f307f0e548 --- /dev/null +++ b/vendor/sha2/src/sha512/soft.rs @@ -0,0 +1,216 @@ +#![allow(clippy::many_single_char_names)] +use crate::consts::{BLOCK_LEN, K64X2}; +use core::convert::TryInto; + +fn add(a: [u64; 2], b: [u64; 2]) -> [u64; 2] { + [a[0].wrapping_add(b[0]), a[1].wrapping_add(b[1])] +} + +/// Not an intrinsic, but works like an unaligned load. +fn sha512load(v0: [u64; 2], v1: [u64; 2]) -> [u64; 2] { + [v1[1], v0[0]] +} + +/// Performs 2 rounds of the SHA-512 message schedule update. +pub fn sha512_schedule_x2(v0: [u64; 2], v1: [u64; 2], v4to5: [u64; 2], v7: [u64; 2]) -> [u64; 2] { + // sigma 0 + fn sigma0(x: u64) -> u64 { + ((x << 63) | (x >> 1)) ^ ((x << 56) | (x >> 8)) ^ (x >> 7) + } + + // sigma 1 + fn sigma1(x: u64) -> u64 { + ((x << 45) | (x >> 19)) ^ ((x << 3) | (x >> 61)) ^ (x >> 6) + } + + let [w1, w0] = v0; + let [_, w2] = v1; + let [w10, w9] = v4to5; + let [w15, w14] = v7; + + let w16 = sigma1(w14) + .wrapping_add(w9) + .wrapping_add(sigma0(w1)) + .wrapping_add(w0); + let w17 = sigma1(w15) + .wrapping_add(w10) + .wrapping_add(sigma0(w2)) + .wrapping_add(w1); + + [w17, w16] +} + +/// Performs one round of the SHA-512 message block digest. +pub fn sha512_digest_round( + ae: [u64; 2], + bf: [u64; 2], + cg: [u64; 2], + dh: [u64; 2], + wk0: u64, +) -> [u64; 2] { + macro_rules! big_sigma0 { + ($a:expr) => { + ($a.rotate_right(28) ^ $a.rotate_right(34) ^ $a.rotate_right(39)) + }; + } + macro_rules! big_sigma1 { + ($a:expr) => { + ($a.rotate_right(14) ^ $a.rotate_right(18) ^ $a.rotate_right(41)) + }; + } + macro_rules! bool3ary_202 { + ($a:expr, $b:expr, $c:expr) => { + $c ^ ($a & ($b ^ $c)) + }; + } // Choose, MD5F, SHA1C + macro_rules! bool3ary_232 { + ($a:expr, $b:expr, $c:expr) => { + ($a & $b) ^ ($a & $c) ^ ($b & $c) + }; + } // Majority, SHA1M + + let [a0, e0] = ae; + let [b0, f0] = bf; + let [c0, g0] = cg; + let [d0, h0] = dh; + + // a round + let x0 = big_sigma1!(e0) + .wrapping_add(bool3ary_202!(e0, f0, g0)) + .wrapping_add(wk0) + .wrapping_add(h0); + let y0 = big_sigma0!(a0).wrapping_add(bool3ary_232!(a0, b0, c0)); + let (a1, _, _, _, e1, _, _, _) = ( + x0.wrapping_add(y0), + a0, + b0, + c0, + x0.wrapping_add(d0), + e0, + f0, + g0, + ); + + [a1, e1] +} + +/// Process a block with the SHA-512 algorithm. +pub fn sha512_digest_block_u64(state: &mut [u64; 8], block: &[u64; 16]) { + let k = &K64X2; + + macro_rules! schedule { + ($v0:expr, $v1:expr, $v4:expr, $v5:expr, $v7:expr) => { + sha512_schedule_x2($v0, $v1, sha512load($v4, $v5), $v7) + }; + } + + macro_rules! rounds4 { + ($ae:ident, $bf:ident, $cg:ident, $dh:ident, $wk0:expr, $wk1:expr) => {{ + let [u, t] = $wk0; + let [w, v] = $wk1; + + $dh = sha512_digest_round($ae, $bf, $cg, $dh, t); + $cg = sha512_digest_round($dh, $ae, $bf, $cg, u); + $bf = sha512_digest_round($cg, $dh, $ae, $bf, v); + $ae = sha512_digest_round($bf, $cg, $dh, $ae, w); + }}; + } + + let mut ae = [state[0], state[4]]; + let mut bf = [state[1], state[5]]; + let mut cg = [state[2], state[6]]; + let mut dh = [state[3], state[7]]; + + // Rounds 0..20 + let (mut w1, mut w0) = ([block[3], block[2]], [block[1], block[0]]); + rounds4!(ae, bf, cg, dh, add(k[0], w0), add(k[1], w1)); + let (mut w3, mut w2) = ([block[7], block[6]], [block[5], block[4]]); + rounds4!(ae, bf, cg, dh, add(k[2], w2), add(k[3], w3)); + let (mut w5, mut w4) = ([block[11], block[10]], [block[9], block[8]]); + rounds4!(ae, bf, cg, dh, add(k[4], w4), add(k[5], w5)); + let (mut w7, mut w6) = ([block[15], block[14]], [block[13], block[12]]); + rounds4!(ae, bf, cg, dh, add(k[6], w6), add(k[7], w7)); + let mut w8 = schedule!(w0, w1, w4, w5, w7); + let mut w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[8], w8), add(k[9], w9)); + + // Rounds 20..40 + w0 = schedule!(w2, w3, w6, w7, w9); + w1 = schedule!(w3, w4, w7, w8, w0); + rounds4!(ae, bf, cg, dh, add(k[10], w0), add(k[11], w1)); + w2 = schedule!(w4, w5, w8, w9, w1); + w3 = schedule!(w5, w6, w9, w0, w2); + rounds4!(ae, bf, cg, dh, add(k[12], w2), add(k[13], w3)); + w4 = schedule!(w6, w7, w0, w1, w3); + w5 = schedule!(w7, w8, w1, w2, w4); + rounds4!(ae, bf, cg, dh, add(k[14], w4), add(k[15], w5)); + w6 = schedule!(w8, w9, w2, w3, w5); + w7 = schedule!(w9, w0, w3, w4, w6); + rounds4!(ae, bf, cg, dh, add(k[16], w6), add(k[17], w7)); + w8 = schedule!(w0, w1, w4, w5, w7); + w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[18], w8), add(k[19], w9)); + + // Rounds 40..60 + w0 = schedule!(w2, w3, w6, w7, w9); + w1 = schedule!(w3, w4, w7, w8, w0); + rounds4!(ae, bf, cg, dh, add(k[20], w0), add(k[21], w1)); + w2 = schedule!(w4, w5, w8, w9, w1); + w3 = schedule!(w5, w6, w9, w0, w2); + rounds4!(ae, bf, cg, dh, add(k[22], w2), add(k[23], w3)); + w4 = schedule!(w6, w7, w0, w1, w3); + w5 = schedule!(w7, w8, w1, w2, w4); + rounds4!(ae, bf, cg, dh, add(k[24], w4), add(k[25], w5)); + w6 = schedule!(w8, w9, w2, w3, w5); + w7 = schedule!(w9, w0, w3, w4, w6); + rounds4!(ae, bf, cg, dh, add(k[26], w6), add(k[27], w7)); + w8 = schedule!(w0, w1, w4, w5, w7); + w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[28], w8), add(k[29], w9)); + + // Rounds 60..80 + w0 = schedule!(w2, w3, w6, w7, w9); + w1 = schedule!(w3, w4, w7, w8, w0); + rounds4!(ae, bf, cg, dh, add(k[30], w0), add(k[31], w1)); + w2 = schedule!(w4, w5, w8, w9, w1); + w3 = schedule!(w5, w6, w9, w0, w2); + rounds4!(ae, bf, cg, dh, add(k[32], w2), add(k[33], w3)); + w4 = schedule!(w6, w7, w0, w1, w3); + w5 = schedule!(w7, w8, w1, w2, w4); + rounds4!(ae, bf, cg, dh, add(k[34], w4), add(k[35], w5)); + w6 = schedule!(w8, w9, w2, w3, w5); + w7 = schedule!(w9, w0, w3, w4, w6); + rounds4!(ae, bf, cg, dh, add(k[36], w6), add(k[37], w7)); + w8 = schedule!(w0, w1, w4, w5, w7); + w9 = schedule!(w1, w2, w5, w6, w8); + rounds4!(ae, bf, cg, dh, add(k[38], w8), add(k[39], w9)); + + let [a, e] = ae; + let [b, f] = bf; + let [c, g] = cg; + let [d, h] = dh; + + state[0] = state[0].wrapping_add(a); + state[1] = state[1].wrapping_add(b); + state[2] = state[2].wrapping_add(c); + state[3] = state[3].wrapping_add(d); + state[4] = state[4].wrapping_add(e); + state[5] = state[5].wrapping_add(f); + state[6] = state[6].wrapping_add(g); + state[7] = state[7].wrapping_add(h); +} + + +pub fn compress(state: &mut [u64; 8], blocks: &[[u8; 128]]) { + let mut block_u32 = [0u64; BLOCK_LEN]; + // since LLVM can't properly use aliasing yet it will make + // unnecessary state stores without this copy + let mut state_cpy = *state; + for block in blocks { + for (o, chunk) in block_u32.iter_mut().zip(block.chunks_exact(8)) { + *o = u64::from_be_bytes(chunk.try_into().unwrap()); + } + sha512_digest_block_u64(&mut state_cpy, &block_u32); + } + *state = state_cpy; +} diff --git a/vendor/sha2/tests/data/sha224.blb b/vendor/sha2/tests/data/sha224.blb new file mode 100644 index 0000000000..50759c294c Binary files /dev/null and b/vendor/sha2/tests/data/sha224.blb differ diff --git a/vendor/sha2/tests/data/sha256.blb b/vendor/sha2/tests/data/sha256.blb new file mode 100644 index 0000000000..2096fd4ec0 Binary files /dev/null and b/vendor/sha2/tests/data/sha256.blb differ diff --git a/vendor/sha2/tests/data/sha256_one_million_a.bin b/vendor/sha2/tests/data/sha256_one_million_a.bin new file mode 100644 index 0000000000..59757633dd --- /dev/null +++ b/vendor/sha2/tests/data/sha256_one_million_a.bin @@ -0,0 +1 @@ +n\>gH m9, \ No newline at end of file diff --git a/vendor/sha2/tests/data/sha384.blb b/vendor/sha2/tests/data/sha384.blb new file mode 100644 index 0000000000..7e9062497c Binary files /dev/null and b/vendor/sha2/tests/data/sha384.blb differ diff --git a/vendor/sha2/tests/data/sha512.blb b/vendor/sha2/tests/data/sha512.blb new file mode 100644 index 0000000000..b073a77cb7 Binary files /dev/null and b/vendor/sha2/tests/data/sha512.blb differ diff --git a/vendor/sha2/tests/data/sha512_224.blb b/vendor/sha2/tests/data/sha512_224.blb new file mode 100644 index 0000000000..4d2ef87ff0 Binary files /dev/null and b/vendor/sha2/tests/data/sha512_224.blb differ diff --git a/vendor/sha2/tests/data/sha512_256.blb b/vendor/sha2/tests/data/sha512_256.blb new file mode 100644 index 0000000000..5346c9494d Binary files /dev/null and b/vendor/sha2/tests/data/sha512_256.blb differ diff --git a/vendor/sha2/tests/data/sha512_one_million_a.bin b/vendor/sha2/tests/data/sha512_one_million_a.bin new file mode 100644 index 0000000000..6edb1d6cf2 Binary files /dev/null and b/vendor/sha2/tests/data/sha512_one_million_a.bin differ diff --git a/vendor/sha2/tests/lib.rs b/vendor/sha2/tests/lib.rs new file mode 100644 index 0000000000..b9cb8628a8 --- /dev/null +++ b/vendor/sha2/tests/lib.rs @@ -0,0 +1,31 @@ +use digest::dev::{digest_test, one_million_a}; +use digest::new_test; + +new_test!(sha224_main, "sha224", sha2::Sha224, digest_test); +new_test!(sha256_main, "sha256", sha2::Sha256, digest_test); +new_test!(sha384_main, "sha384", sha2::Sha384, digest_test); +new_test!(sha512_main, "sha512", sha2::Sha512, digest_test); +new_test!( + sha512_224_main, + "sha512_224", + sha2::Sha512Trunc224, + digest_test +); +new_test!( + sha512_256_main, + "sha512_256", + sha2::Sha512Trunc256, + digest_test +); + +#[test] +fn sha256_1million_a() { + let output = include_bytes!("data/sha256_one_million_a.bin"); + one_million_a::(output); +} + +#[test] +fn sha512_1million_a() { + let output = include_bytes!("data/sha512_one_million_a.bin"); + one_million_a::(output); +} diff --git a/vendor/snap/.cargo-checksum.json b/vendor/snap/.cargo-checksum.json new file mode 100644 index 0000000000..ac228fc235 --- /dev/null +++ b/vendor/snap/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"COPYING":"7ca1297d23644e30bd489193a82a33f324e5fe33f25df4195649b91b883df967","Cargo.lock":"3c9f949b07c311204734ecba573b32e03821593dac9eec193f69b2204639d10a","Cargo.toml":"1728234f0e2d3cc184e54016115612e70efa9272de59c4af0a9c4d614d69bbc7","README.md":"5be873fd869130fb1d6f55d3c66854b234b08558b3f06903482717df086bc63c","build.rs":"afae7dd3c45a9a46bcce096e9e0aa9e36ade171e8fd00309969478025b82cac1","data/COPYING":"c355b53211bfbbefc0ec641ee43a2fa1ec926966f1276698b4b9125d73c70b18","data/Mark.Twain-Tom.Sawyer.txt":"bd8df876d2a05017bb302f506883a37817d256f16f2205a932399276e08a81af","data/Mark.Twain-Tom.Sawyer.txt.rawsnappy":"7f1f5878f128aec6140fb135f7ed7e2c29575c7eb5c44431ffc65b22f7a19738","data/alice29.txt":"7467306ee0feed4971260f3c87421154a05be571d944e9cb021a5713700c38f0","data/asyoulik.txt":"eaa3526fe53859f34ecdf255712f9ecf0b2c903451d4755b2edaa2e2599cb0fc","data/baddata1.snappy":"ca84adbcd5b4b784c3405fcdd4fa88f88a6614f2d5e5d4a527838785f1806623","data/baddata2.snappy":"06f0ca34f0de885d6a849e1c8df95391d4494bf430d3784ea2167113d6ca8947","data/baddata3.snappy":"2f60f8c9b5f3b9b0e3b4ff9aef983946552cdd1fdecdfad122292882894163bd","data/fireworks.jpeg":"93b986ce7d7e361f0d3840f9d531b5f40fb6ca8c14d6d74364150e255f126512","data/geo.protodata":"7c2875cd6d06c954240ba644618d1e1f2a167e4541731f019de5b4c1f8080f24","data/html":"5912445a6d50df1079f022d7e01fa615f5d128d53bad88acbf4f49e62a7ea759","data/html_x_4":"ce3b0ceece9a0c0f66a352fd65b87a8e06357b136e99a2a85fcb3b0689ff6671","data/kppkn.gtb":"1df7e44e4ec9bad952e7716fbdba0a2208665091866ded43407d03ed9ce23c24","data/lcet10.txt":"5314ba1dbb03f471df88bec6cd120a938ef60d0fd3511c5c1dce61bf7463245f","data/paper-100k.pdf":"60f73a051b7ca35bfec44734b2eed7736cb5c0b7f728beb7b97ade6c5e44849b","data/plrabn12.txt":"07e2e0b461af78c7c647cb53dab39de560198e16f799b4516eccf0fbd69f764c","data/urls.10K":"0319ce7fe1f51b14eace3de879fe7da15418d1525d3176c2b26c5985943a3cad","examples/compress-escaped.rs":"cef1933dbc5d9b496587c4c1a596f26e326e73799ab9a0ede1c3d76b00676090","examples/compress.rs":"34bad60450e768ed4ac27edf8622abc4d918b17e57b8c286030203e2b3590c24","examples/decompress.rs":"87aa11875ec98f253c8b48ce3a202ac3412063ce2f64387074194151c11fff5e","rustfmt.toml":"1ca600239a27401c4a43f363cf3f38183a212affc1f31bff3ae93234bbaec228","src/bytes.rs":"2eb9783acdf949ef96a9031d2bd43ead65db50a41a60ad98dc117cd61655c7c4","src/compress.rs":"e6f3160be400c2a4869d71210a2558ba8b438b835b632a12b7ff487660db093f","src/crc32.rs":"9f3858bef802640c595705c496f462d0343c4adcff9bdf333a43306fb67db7ae","src/crc32_table.rs":"e999470ca10bb7914887747be838d05d0f5059ae99a8b8c57b0be7de3931e72a","src/decompress.rs":"05c4d0c0922b1ad084cf32f224722f2fe9d63128d6a4da0c44333742d681b80f","src/error.rs":"683e609ae19f0acacfccb5ce7bcd8bd107a0b6639cdd2308a7768a632a993f4e","src/frame.rs":"4f69a9526a5dd0367631fc7a764bea877f7f0b4c33ee30d4ece62913c42ea48d","src/lib.rs":"4534bc8b5bf0f83dc1852629362d2d392397f1b1fc4f8bdb8f638bfd3cc89b22","src/raw.rs":"a7048da3a4b76b75e4b3d071ee9959dbf12c5b3a36dabb2f7878513507c80cb9","src/read.rs":"66ceb455e451d14964eff77743e8003d58de16ec90c9ba37e03fda51da7b94c9","src/tag.rs":"9ac94977c5ab3ea687b9441ea3c615f64a23eac11a4bade19cfa3be5968cb718","src/varint.rs":"6d63fca6323c91f193628a41b6e75f5b3443777467e6a5665907bbbba549e6c7","src/write.rs":"086edd9fb1442b6bc8bf8c6a80023eccc4ca627de57ccc62279691c9ff7f0786"},"package":"da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e"} \ No newline at end of file diff --git a/vendor/snap/COPYING b/vendor/snap/COPYING new file mode 100644 index 0000000000..a42659dccd --- /dev/null +++ b/vendor/snap/COPYING @@ -0,0 +1,27 @@ +Copyright 2011, The Snappy-Rust Authors. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are +met: + + * Redistributions of source code must retain the above copyright +notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above +copyright notice, this list of conditions and the following disclaimer +in the documentation and/or other materials provided with the +distribution. + * Neither the name of the copyright holder nor the names of its +contributors may be used to endorse or promote products derived from +this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS +"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT +OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, +SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT +LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, +DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY +THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/vendor/snap/Cargo.lock b/vendor/snap/Cargo.lock new file mode 100644 index 0000000000..6eb826d6e9 --- /dev/null +++ b/vendor/snap/Cargo.lock @@ -0,0 +1,14 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +[[package]] +name = "doc-comment" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "923dea538cea0aa3025e8685b20d6ee21ef99c4f77e954a30febbaac5ec73a97" + +[[package]] +name = "snap" +version = "1.0.1" +dependencies = [ + "doc-comment", +] diff --git a/vendor/snap/Cargo.toml b/vendor/snap/Cargo.toml new file mode 100644 index 0000000000..4cdc45a344 --- /dev/null +++ b/vendor/snap/Cargo.toml @@ -0,0 +1,34 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "snap" +version = "1.0.1" +authors = ["Andrew Gallant "] +description = "A pure Rust implementation of the Snappy compression algorithm. Includes\nstreaming compression and decompression.\n" +homepage = "https://github.com/BurntSushi/rust-snappy" +documentation = "https://docs.rs/snap" +readme = "README.md" +keywords = ["snappy", "compress", "compression", "decompress", "decompression"] +license = "BSD-3-Clause" +repository = "https://github.com/BurntSushi/rust-snappy" +[profile.release] +debug = true + +[profile.test] +opt-level = 3 + +[lib] +bench = false +[dev-dependencies.doc-comment] +version = "0.3.1" diff --git a/vendor/snap/README.md b/vendor/snap/README.md new file mode 100644 index 0000000000..af06b2055b --- /dev/null +++ b/vendor/snap/README.md @@ -0,0 +1,229 @@ +snap +==== +A pure Rust implementation of the +[Snappy compression algorithm](http://google.github.io/snappy/). +Includes streaming compression and decompression using the Snappy frame format. +This implementation is ported from both the +[reference C++ implementation](https://github.com/google/snappy) +and the +[Go implementation](https://github.com/golang/snappy). + +[![Build status](https://github.com/BurntSushi/rust-snappy/workflows/ci/badge.svg)](https://github.com/BurntSushi/rust-snappy/actions) +[![](http://meritbadge.herokuapp.com/snap)](https://crates.io/crates/snap) + +Licensed under the BSD 3-Clause. + + +### Documentation + +https://docs.rs/snap + + +### Usage + +Add this to your `Cargo.toml`: + +```toml +[dependencies] +snap = "1" +``` + + +### Example: compress data on `stdin` + +This program reads data from `stdin`, compresses it and emits it to `stdout`. +This example can be found in `examples/compress.rs`: + +```rust +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + let mut rdr = stdin.lock(); + // Wrap the stdout writer in a Snappy writer. + let mut wtr = snap::write::FrameEncoder::new(stdout.lock()); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} +``` + + +### Example: decompress data on `stdin` + +This program reads data from `stdin`, decompresses it and emits it to `stdout`. +This example can be found in `examples/decompress.rs`: + +```rust +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + // Wrap the stdin reader in a Snappy reader. + let mut rdr = snap::read::FrameDecoder::new(stdin.lock()); + let mut wtr = stdout.lock(); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} +``` + + +### Example: the szip tool + +`szip` is a tool with similar behavior as `gzip`, except it uses Snappy +compression. It can be installed with Cargo: + +``` +$ cargo install szip +``` + +To compress a file, run `szip file`. To decompress a file, run +`szip -d file.sz`. See `szip --help` for more details. + + +### Testing + +This crate is tested against the reference C++ implementation of Snappy. +Currently, compression is byte-for-byte equivalent with the C++ implementation. +This seems like a reasonable starting point, although it is not necessarily +a goal to always maintain byte-for-byte equivalence. + +Tests against the reference C++ implementation can be run with +`cargo test --features cpp`. Note that you will need to have the C++ Snappy +library in your `LD_LIBRARY_PATH` (or equivalent). + +To run tests, you'll need to explicitly run the `test` crate: + +``` +$ cargo test --manifest-path test/Cargo.toml +``` + +To test that this library matches the output of the reference C++ library, use: + +``` +$ cargo test --manifest-path test/Cargo.toml --features cpp +``` + +Tests are in a separate crate because of the dependency on the C++ reference +library. Namely, Cargo does not yet permit optional dev dependencies. + + +### Minimum Rust version policy + +This crate's minimum supported `rustc` version is `1.39.0`. + +The current policy is that the minimum Rust version required to use this crate +can be increased in minor version updates. For example, if `crate 1.0` requires +Rust 1.20.0, then `crate 1.0.z` for all values of `z` will also require Rust +1.20.0 or newer. However, `crate 1.y` for `y > 0` may require a newer minimum +version of Rust. + +In general, this crate will be conservative with respect to the minimum +supported version of Rust. + + +### Performance + +The performance of this implementation should roughly match the performance of +the C++ implementation on x86_64. Below are the results of the microbenchmarks +(as defined in the C++ library): + +``` +group snappy/cpp/ snappy/snap/ +----- ----------- ------------ +compress/zflat00_html 1.00 94.5±0.62µs 1033.1 MB/sec 1.02 96.1±0.74µs 1016.2 MB/sec +compress/zflat01_urls 1.00 1182.3±8.89µs 566.3 MB/sec 1.04 1235.3±11.99µs 542.0 MB/sec +compress/zflat02_jpg 1.00 7.2±0.11µs 15.9 GB/sec 1.01 7.3±0.06µs 15.8 GB/sec +compress/zflat03_jpg_200 1.10 262.4±1.84ns 727.0 MB/sec 1.00 237.5±2.95ns 803.2 MB/sec +compress/zflat04_pdf 1.02 10.3±0.18µs 9.2 GB/sec 1.00 10.1±0.16µs 9.4 GB/sec +compress/zflat05_html4 1.00 399.2±5.36µs 978.4 MB/sec 1.01 404.0±2.46µs 966.8 MB/sec +compress/zflat06_txt1 1.00 397.3±2.61µs 365.1 MB/sec 1.00 398.5±3.06µs 364.0 MB/sec +compress/zflat07_txt2 1.00 352.8±3.20µs 338.4 MB/sec 1.01 355.2±5.01µs 336.1 MB/sec +compress/zflat08_txt3 1.01 1058.8±6.85µs 384.4 MB/sec 1.00 1051.8±6.74µs 386.9 MB/sec +compress/zflat09_txt4 1.00 1444.1±8.10µs 318.2 MB/sec 1.00 1450.0±13.36µs 316.9 MB/sec +compress/zflat10_pb 1.00 85.1±0.58µs 1328.6 MB/sec 1.02 87.0±0.90µs 1300.2 MB/sec +compress/zflat11_gaviota 1.07 311.9±4.27µs 563.5 MB/sec 1.00 291.9±1.86µs 602.3 MB/sec +decompress/uflat00_html 1.03 36.9±0.28µs 2.6 GB/sec 1.00 36.0±0.25µs 2.7 GB/sec +decompress/uflat01_urls 1.04 437.4±2.89µs 1530.7 MB/sec 1.00 419.9±3.10µs 1594.6 MB/sec +decompress/uflat02_jpg 1.00 4.6±0.05µs 24.9 GB/sec 1.00 4.6±0.03µs 25.0 GB/sec +decompress/uflat03_jpg_200 1.08 122.4±1.06ns 1558.6 MB/sec 1.00 112.8±1.35ns 1690.8 MB/sec +decompress/uflat04_pdf 1.00 5.7±0.05µs 16.8 GB/sec 1.10 6.2±0.07µs 15.3 GB/sec +decompress/uflat05_html4 1.01 164.1±1.71µs 2.3 GB/sec 1.00 162.6±2.16µs 2.3 GB/sec +decompress/uflat06_txt1 1.08 146.6±1.01µs 989.5 MB/sec 1.00 135.3±1.11µs 1072.0 MB/sec +decompress/uflat07_txt2 1.09 130.2±0.93µs 916.6 MB/sec 1.00 119.2±0.96µs 1001.8 MB/sec +decompress/uflat08_txt3 1.07 387.2±2.30µs 1051.0 MB/sec 1.00 361.9±6.29µs 1124.7 MB/sec +decompress/uflat09_txt4 1.09 536.1±3.47µs 857.2 MB/sec 1.00 494.0±5.05µs 930.2 MB/sec +decompress/uflat10_pb 1.00 32.5±0.19µs 3.4 GB/sec 1.05 34.0±0.48µs 3.2 GB/sec +decompress/uflat11_gaviota 1.00 142.1±2.05µs 1236.7 MB/sec 1.00 141.5±0.92µs 1242.3 MB/sec +``` + +Notes: These benchmarks were run with Snappy/C++ 1.1.8. Both the C++ and Rust +benchmarks were run with the same benchmark harness. Benchmarks were run on an +Intel i7-6900K. + +Additionally, here are the benchmarks run on the same machine from the Go +implementation of Snappy (which has a hand rolled implementation in Assembly). +Note that these were run using Go's microbenchmark tool, so the numbers may not +be directly comparable, but they should serve as a useful signpost: + +``` +Benchmark_UFlat0 25040 45180 ns/op 2266.49 MB/s +Benchmark_UFlat1 2648 451475 ns/op 1555.10 MB/s +Benchmark_UFlat2 229965 4788 ns/op 25709.01 MB/s +Benchmark_UFlat3 11355555 101 ns/op 1973.65 MB/s +Benchmark_UFlat4 196551 6055 ns/op 16912.64 MB/s +Benchmark_UFlat5 6016 189219 ns/op 2164.68 MB/s +Benchmark_UFlat6 6914 166371 ns/op 914.16 MB/s +Benchmark_UFlat7 8173 142506 ns/op 878.41 MB/s +Benchmark_UFlat8 2744 436424 ns/op 977.84 MB/s +Benchmark_UFlat9 1999 591141 ns/op 815.14 MB/s +Benchmark_UFlat10 28885 37291 ns/op 3180.04 MB/s +Benchmark_UFlat11 7308 163366 ns/op 1128.26 MB/s +Benchmark_ZFlat0 12902 91231 ns/op 1122.43 MB/s +Benchmark_ZFlat1 997 1200579 ns/op 584.79 MB/s +Benchmark_ZFlat2 136762 7832 ns/op 15716.53 MB/s +Benchmark_ZFlat3 4896124 245 ns/op 817.27 MB/s +Benchmark_ZFlat4 117643 10129 ns/op 10109.44 MB/s +Benchmark_ZFlat5 2934 394742 ns/op 1037.64 MB/s +Benchmark_ZFlat6 3008 382877 ns/op 397.23 MB/s +Benchmark_ZFlat7 3411 344916 ns/op 362.93 MB/s +Benchmark_ZFlat8 966 1057985 ns/op 403.36 MB/s +Benchmark_ZFlat9 854 1429024 ns/op 337.20 MB/s +Benchmark_ZFlat10 13861 83040 ns/op 1428.08 MB/s +Benchmark_ZFlat11 4070 293952 ns/op 627.04 MB/s +``` + +To run benchmarks, including the reference C++ implementation, do the +following: + +``` +$ cd bench +$ cargo bench --features cpp -- --save-baseline snappy +``` + +To compare them, as shown above, install +[`critcmp`](https://github.com/BurntSushi/critcmp) +and run (assuming you saved the baseline above under the name `snappy`): + +``` +$ critcmp snappy -g '.*?/(.*$)' +``` + +Finally, the Go benchmarks were run with the following command on commit +`ff6b7dc8`: + +``` +$ go test -cpu 1 -bench Flat -download +``` + + +### Comparison with other Snappy crates + +* `snappy` - These are bindings to the C++ library. No support for the Snappy + frame format. +* `snappy_framed` - Implements the Snappy frame format on top of the `snappy` + crate. +* `rsnappy` - Written in pure Rust, but lacks documentation and the Snappy + frame format. Performance is unclear and tests appear incomplete. +* `snzip` - Was created and immediately yanked from crates.io. diff --git a/vendor/snap/build.rs b/vendor/snap/build.rs new file mode 100644 index 0000000000..283164f2e2 --- /dev/null +++ b/vendor/snap/build.rs @@ -0,0 +1,124 @@ +use std::env; +use std::fs::File; +use std::io::{self, Write}; +use std::path::{Path, PathBuf}; + +const CASTAGNOLI_POLY: u32 = 0x82f63b78; + +type Result = std::result::Result>; + +fn main() { + if let Err(err) = try_main() { + panic!("{}", err); + } +} + +fn try_main() -> Result<()> { + let out_dir = match env::var_os("OUT_DIR") { + None => { + return Err(From::from("OUT_DIR environment variable not defined")) + } + Some(out_dir) => PathBuf::from(out_dir), + }; + write_tag_lookup_table(&out_dir)?; + write_crc_tables(&out_dir)?; + Ok(()) +} + +fn write_tag_lookup_table(out_dir: &Path) -> Result<()> { + let out_path = out_dir.join("tag.rs"); + let mut out = io::BufWriter::new(File::create(out_path)?); + + writeln!(out, "pub const TAG_LOOKUP_TABLE: [u16; 256] = [")?; + for b in 0u8..=255 { + writeln!(out, " {},", tag_entry(b))?; + } + writeln!(out, "];")?; + Ok(()) +} + +fn tag_entry(b: u8) -> u16 { + let b = b as u16; + match b & 0b00000011 { + 0b00 => { + let lit_len = (b >> 2) + 1; + if lit_len <= 60 { + lit_len + } else { + assert!(lit_len <= 64); + (lit_len - 60) << 11 + } + } + 0b01 => { + let len = 4 + ((b >> 2) & 0b111); + let offset = (b >> 5) & 0b111; + (1 << 11) | (offset << 8) | len + } + 0b10 => { + let len = 1 + (b >> 2); + (2 << 11) | len + } + 0b11 => { + let len = 1 + (b >> 2); + (4 << 11) | len + } + _ => unreachable!(), + } +} + +fn write_crc_tables(out_dir: &Path) -> Result<()> { + let out_path = out_dir.join("crc32_table.rs"); + let mut out = io::BufWriter::new(File::create(out_path)?); + + let table = make_table(CASTAGNOLI_POLY); + let table16 = make_table16(CASTAGNOLI_POLY); + + writeln!(out, "pub const TABLE: [u32; 256] = [")?; + for &x in table.iter() { + writeln!(out, " {},", x)?; + } + writeln!(out, "];\n")?; + + writeln!(out, "pub const TABLE16: [[u32; 256]; 16] = [")?; + for table in table16.iter() { + writeln!(out, " [")?; + for &x in table.iter() { + writeln!(out, " {},", x)?; + } + writeln!(out, " ],")?; + } + writeln!(out, "];")?; + + out.flush()?; + + Ok(()) +} + +fn make_table16(poly: u32) -> [[u32; 256]; 16] { + let mut tab = [[0; 256]; 16]; + tab[0] = make_table(poly); + for i in 0..256 { + let mut crc = tab[0][i]; + for j in 1..16 { + crc = (crc >> 8) ^ tab[0][crc as u8 as usize]; + tab[j][i] = crc; + } + } + tab +} + +fn make_table(poly: u32) -> [u32; 256] { + let mut tab = [0; 256]; + for i in 0u32..256u32 { + let mut crc = i; + for _ in 0..8 { + if crc & 1 == 1 { + crc = (crc >> 1) ^ poly; + } else { + crc >>= 1; + } + } + tab[i as usize] = crc; + } + tab +} diff --git a/vendor/snap/data/COPYING b/vendor/snap/data/COPYING new file mode 100644 index 0000000000..ae69a7b309 --- /dev/null +++ b/vendor/snap/data/COPYING @@ -0,0 +1,23 @@ +Some of the benchmark data in in this directory is licensed thusly: + + - fireworks.jpeg is Copyright 2013 Steinar H. Gunderson, and + is licensed under the Creative Commons Attribution 3.0 license + (CC-BY-3.0). See https://creativecommons.org/licenses/by/3.0/ + for more information. + + - kppkn.gtb is taken from the Gaviota chess tablebase set, and + is licensed under the MIT License. See + https://sites.google.com/site/gaviotachessengine/Home/endgame-tablebases-1 + for more information. + + - paper-100k.pdf is an excerpt (bytes 92160 to 194560) from the paper + “Combinatorial Modeling of Chromatin Features Quantitatively Predicts DNA + Replication Timing in _Drosophila_” by Federico Comoglio and Renato Paro, + which is licensed under the CC-BY license. See + http://www.ploscompbiol.org/static/license for more ifnormation. + + - alice29.txt, asyoulik.txt, plrabn12.txt and lcet10.txt are from Project + Gutenberg. The first three have expired copyrights and are in the public + domain; the latter does not have expired copyright, but is still in the + public domain according to the license information + (http://www.gutenberg.org/ebooks/53). diff --git a/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt b/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt new file mode 100644 index 0000000000..86a18750bf --- /dev/null +++ b/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt @@ -0,0 +1,396 @@ +Produced by David Widger. The previous edition was updated by Jose +Menendez. + + + + + + THE ADVENTURES OF TOM SAWYER + BY + MARK TWAIN + (Samuel Langhorne Clemens) + + + + + P R E F A C E + +MOST of the adventures recorded in this book really occurred; one or +two were experiences of my own, the rest those of boys who were +schoolmates of mine. Huck Finn is drawn from life; Tom Sawyer also, but +not from an individual--he is a combination of the characteristics of +three boys whom I knew, and therefore belongs to the composite order of +architecture. + +The odd superstitions touched upon were all prevalent among children +and slaves in the West at the period of this story--that is to say, +thirty or forty years ago. + +Although my book is intended mainly for the entertainment of boys and +girls, I hope it will not be shunned by men and women on that account, +for part of my plan has been to try to pleasantly remind adults of what +they once were themselves, and of how they felt and thought and talked, +and what queer enterprises they sometimes engaged in. + + THE AUTHOR. + +HARTFORD, 1876. + + + + T O M S A W Y E R + + + +CHAPTER I + +"TOM!" + +No answer. + +"TOM!" + +No answer. + +"What's gone with that boy, I wonder? You TOM!" + +No answer. + +The old lady pulled her spectacles down and looked over them about the +room; then she put them up and looked out under them. She seldom or +never looked THROUGH them for so small a thing as a boy; they were her +state pair, the pride of her heart, and were built for "style," not +service--she could have seen through a pair of stove-lids just as well. +She looked perplexed for a moment, and then said, not fiercely, but +still loud enough for the furniture to hear: + +"Well, I lay if I get hold of you I'll--" + +She did not finish, for by this time she was bending down and punching +under the bed with the broom, and so she needed breath to punctuate the +punches with. She resurrected nothing but the cat. + +"I never did see the beat of that boy!" + +She went to the open door and stood in it and looked out among the +tomato vines and "jimpson" weeds that constituted the garden. No Tom. +So she lifted up her voice at an angle calculated for distance and +shouted: + +"Y-o-u-u TOM!" + +There was a slight noise behind her and she turned just in time to +seize a small boy by the slack of his roundabout and arrest his flight. + +"There! I might 'a' thought of that closet. What you been doing in +there?" + +"Nothing." + +"Nothing! Look at your hands. And look at your mouth. What IS that +truck?" + +"I don't know, aunt." + +"Well, I know. It's jam--that's what it is. Forty times I've said if +you didn't let that jam alone I'd skin you. Hand me that switch." + +The switch hovered in the air--the peril was desperate-- + +"My! Look behind you, aunt!" + +The old lady whirled round, and snatched her skirts out of danger. The +lad fled on the instant, scrambled up the high board-fence, and +disappeared over it. + +His aunt Polly stood surprised a moment, and then broke into a gentle +laugh. + +"Hang the boy, can't I never learn anything? Ain't he played me tricks +enough like that for me to be looking out for him by this time? But old +fools is the biggest fools there is. Can't learn an old dog new tricks, +as the saying is. But my goodness, he never plays them alike, two days, +and how is a body to know what's coming? He 'pears to know just how +long he can torment me before I get my dander up, and he knows if he +can make out to put me off for a minute or make me laugh, it's all down +again and I can't hit him a lick. I ain't doing my duty by that boy, +and that's the Lord's truth, goodness knows. Spare the rod and spile +the child, as the Good Book says. I'm a laying up sin and suffering for +us both, I know. He's full of the Old Scratch, but laws-a-me! he's my +own dead sister's boy, poor thing, and I ain't got the heart to lash +him, somehow. Every time I let him off, my conscience does hurt me so, +and every time I hit him my old heart most breaks. Well-a-well, man +that is born of woman is of few days and full of trouble, as the +Scripture says, and I reckon it's so. He'll play hookey this evening, * +and [* Southwestern for "afternoon"] I'll just be obleeged to make him +work, to-morrow, to punish him. It's mighty hard to make him work +Saturdays, when all the boys is having holiday, but he hates work more +than he hates anything else, and I've GOT to do some of my duty by him, +or I'll be the ruination of the child." + +Tom did play hookey, and he had a very good time. He got back home +barely in season to help Jim, the small colored boy, saw next-day's +wood and split the kindlings before supper--at least he was there in +time to tell his adventures to Jim while Jim did three-fourths of the +work. Tom's younger brother (or rather half-brother) Sid was already +through with his part of the work (picking up chips), for he was a +quiet boy, and had no adventurous, troublesome ways. + +While Tom was eating his supper, and stealing sugar as opportunity +offered, Aunt Polly asked him questions that were full of guile, and +very deep--for she wanted to trap him into damaging revealments. Like +many other simple-hearted souls, it was her pet vanity to believe she +was endowed with a talent for dark and mysterious diplomacy, and she +loved to contemplate her most transparent devices as marvels of low +cunning. Said she: + +"Tom, it was middling warm in school, warn't it?" + +"Yes'm." + +"Powerful warm, warn't it?" + +"Yes'm." + +"Didn't you want to go in a-swimming, Tom?" + +A bit of a scare shot through Tom--a touch of uncomfortable suspicion. +He searched Aunt Polly's face, but it told him nothing. So he said: + +"No'm--well, not very much." + +The old lady reached out her hand and felt Tom's shirt, and said: + +"But you ain't too warm now, though." And it flattered her to reflect +that she had discovered that the shirt was dry without anybody knowing +that that was what she had in her mind. But in spite of her, Tom knew +where the wind lay, now. So he forestalled what might be the next move: + +"Some of us pumped on our heads--mine's damp yet. See?" + +Aunt Polly was vexed to think she had overlooked that bit of +circumstantial evidence, and missed a trick. Then she had a new +inspiration: + +"Tom, you didn't have to undo your shirt collar where I sewed it, to +pump on your head, did you? Unbutton your jacket!" + +The trouble vanished out of Tom's face. He opened his jacket. His +shirt collar was securely sewed. + +"Bother! Well, go 'long with you. I'd made sure you'd played hookey +and been a-swimming. But I forgive ye, Tom. I reckon you're a kind of a +singed cat, as the saying is--better'n you look. THIS time." + +She was half sorry her sagacity had miscarried, and half glad that Tom +had stumbled into obedient conduct for once. + +But Sidney said: + +"Well, now, if I didn't think you sewed his collar with white thread, +but it's black." + +"Why, I did sew it with white! Tom!" + +But Tom did not wait for the rest. As he went out at the door he said: + +"Siddy, I'll lick you for that." + +In a safe place Tom examined two large needles which were thrust into +the lapels of his jacket, and had thread bound about them--one needle +carried white thread and the other black. He said: + +"She'd never noticed if it hadn't been for Sid. Confound it! sometimes +she sews it with white, and sometimes she sews it with black. I wish to +geeminy she'd stick to one or t'other--I can't keep the run of 'em. But +I bet you I'll lam Sid for that. I'll learn him!" + +He was not the Model Boy of the village. He knew the model boy very +well though--and loathed him. + +Within two minutes, or even less, he had forgotten all his troubles. +Not because his troubles were one whit less heavy and bitter to him +than a man's are to a man, but because a new and powerful interest bore +them down and drove them out of his mind for the time--just as men's +misfortunes are forgotten in the excitement of new enterprises. This +new interest was a valued novelty in whistling, which he had just +acquired from a negro, and he was suffering to practise it undisturbed. +It consisted in a peculiar bird-like turn, a sort of liquid warble, +produced by touching the tongue to the roof of the mouth at short +intervals in the midst of the music--the reader probably remembers how +to do it, if he has ever been a boy. Diligence and attention soon gave +him the knack of it, and he strode down the street with his mouth full +of harmony and his soul full of gratitude. He felt much as an +astronomer feels who has discovered a new planet--no doubt, as far as +strong, deep, unalloyed pleasure is concerned, the advantage was with +the boy, not the astronomer. + +The summer evenings were long. It was not dark, yet. Presently Tom +checked his whistle. A stranger was before him--a boy a shade larger +than himself. A new-comer of any age or either sex was an impressive +curiosity in the poor little shabby village of St. Petersburg. This boy +was well dressed, too--well dressed on a week-day. This was simply +astounding. His cap was a dainty thing, his close-buttoned blue cloth +roundabout was new and natty, and so were his pantaloons. He had shoes +on--and it was only Friday. He even wore a necktie, a bright bit of +ribbon. He had a citified air about him that ate into Tom's vitals. The +more Tom stared at the splendid marvel, the higher he turned up his +nose at his finery and the shabbier and shabbier his own outfit seemed +to him to grow. Neither boy spoke. If one moved, the other moved--but +only sidewise, in a circle; they kept face to face and eye to eye all +the time. Finally Tom said: + +"I can lick you!" + +"I'd like to see you try it." + +"Well, I can do it." + +"No you can't, either." + +"Yes I can." + +"No you can't." + +"I can." + +"You can't." + +"Can!" + +"Can't!" + +An uncomfortable pause. Then Tom said: + +"What's your name?" + +"'Tisn't any of your business, maybe." + +"Well I 'low I'll MAKE it my business." + +"Well why don't you?" + +"If you say much, I will." + +"Much--much--MUCH. There now." + +"Oh, you think you're mighty smart, DON'T you? I could lick you with +one hand tied behind me, if I wanted to." + +"Well why don't you DO it? You SAY you can do it." + +"Well I WILL, if you fool with me." + +"Oh yes--I've seen whole families in the same fix." + +"Smarty! You think you're SOME, now, DON'T you? Oh, what a hat!" + +"You can lump that hat if you don't like it. I dare you to knock it +off--and anybody that'll take a dare will suck eggs." + +"You're a liar!" + +"You're another." + +"You're a fighting liar and dasn't take it up." + +"Aw--take a walk!" + +"Say--if you give me much more of your sass I'll take and bounce a +rock off'n your head." + +"Oh, of COURSE you will." + +"Well I WILL." + +"Well why don't you DO it then? What do you keep SAYING you will for? +Why don't you DO it? It's because you're afraid." + +"I AIN'T afraid." + +"You are." + +"I ain't." + +"You are." + +Another pause, and more eying and sidling around each other. Presently +they were shoulder to shoulder. Tom said: + +"Get away from here!" + +"Go away yourself!" + +"I won't." + +"I won't either." + +So they stood, each with a foot placed at an angle as a brace, and +both shoving with might and main, and glowering at each other with +hate. But neither could get an advantage. After struggling till both +were hot and flushed, each relaxed his strain with watchful caution, +and Tom said: + +"You're a coward and a pup. I'll tell my big brother on you, and he +can thrash you with his little finger, and I'll make him do it, too." + +"What do I care for your big brother? I've got a brother that's bigger +than he is--and what's more, he can throw him over that fence, too." +[Both brothers were imaginary.] + +"That's a lie." + +"YOUR saying so don't make it so." + +Tom drew a line in the dust with his big toe, and said: + +"I dare you to step over that, and I'll lick you till you can't stand +up. Anybody that'll take a dare will steal sheep." + +The new boy stepped over promptly, and said: + +"Now you said you'd do it, now let's see you do it." + +"Don't you crowd me now; you better look out." + +"Well, you SAID you'd do it--why don't you do it?" + +"By jingo! for two cents I WILL do it." + +The new boy took two broad coppers out of his pocket and held them out +with derision. Tom struck them to the ground. In an instant both boys +were rolling and tumbling in the dirt, gripped together like cats; and +for the space of a minute they tugged and tore at each other's hair and +clothes, punched and scratched each other's nose, and covered +themselves with dust and glory. Presently the confusion took form, and +through the fog of battle Tom appeared, seated astride the new boy, and +pounding him with his fists. "Holler 'nuff!" said he. + +The boy only struggled to free himself. He was crying--mainly from rage. + +"Holler 'nuff!"--and the pounding went on. + +At last the stranger got out a smothered "'Nuff!" and Tom let him up +and said: + +"Now that'll learn you. Better look out who you're fooling with next +time." + +The new boy went off brushing the dust from his clothes, sobbing, +snuffling, and occasionally looking back and shaking his head and +threatening what he would do to Tom the "next time he caught him out." +To which Tom responded with jeers, and started off in high feather, and +as soon as his back was turned the new boy snatched up a stone, threw +it and hit him between the shoulders and then turned tail and ran like +an antelope. Tom chased the traitor home, and thus found out where he +lived. He then held a position at the gate for some time, daring the +enemy to come outside, but the enemy only made faces at him through the +window and declined. At last the enemy's mother appeared, and called +Tom a bad, vicious, vulgar child, and ordered him away. So he went +away; but he said he "'lowed" to "lay" for that boy. + +He got home pretty late that night, and when he climbed cautiously in +at the window, he uncovered an ambuscade, in the person of his aunt; +and when she saw the state his clothes were in her resolution to turn +his Saturday holiday into captivity at hard labor became adamantine in +its firmness. diff --git a/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt.rawsnappy b/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt.rawsnappy new file mode 100644 index 0000000000..9c56d98588 Binary files /dev/null and b/vendor/snap/data/Mark.Twain-Tom.Sawyer.txt.rawsnappy differ diff --git a/vendor/snap/data/alice29.txt b/vendor/snap/data/alice29.txt new file mode 100644 index 0000000000..703365523b --- /dev/null +++ b/vendor/snap/data/alice29.txt @@ -0,0 +1,3609 @@ + + + + + ALICE'S ADVENTURES IN WONDERLAND + + Lewis Carroll + + THE MILLENNIUM FULCRUM EDITION 2.9 + + + + + CHAPTER I + + Down the Rabbit-Hole + + + Alice was beginning to get very tired of sitting by her sister +on the bank, and of having nothing to do: once or twice she had +peeped into the book her sister was reading, but it had no +pictures or conversations in it, `and what is the use of a book,' +thought Alice `without pictures or conversation?' + + So she was considering in her own mind (as well as she could, +for the hot day made her feel very sleepy and stupid), whether +the pleasure of making a daisy-chain would be worth the trouble +of getting up and picking the daisies, when suddenly a White +Rabbit with pink eyes ran close by her. + + There was nothing so VERY remarkable in that; nor did Alice +think it so VERY much out of the way to hear the Rabbit say to +itself, `Oh dear! Oh dear! I shall be late!' (when she thought +it over afterwards, it occurred to her that she ought to have +wondered at this, but at the time it all seemed quite natural); +but when the Rabbit actually TOOK A WATCH OUT OF ITS WAISTCOAT- +POCKET, and looked at it, and then hurried on, Alice started to +her feet, for it flashed across her mind that she had never +before seen a rabbit with either a waistcoat-pocket, or a watch to +take out of it, and burning with curiosity, she ran across the +field after it, and fortunately was just in time to see it pop +down a large rabbit-hole under the hedge. + + In another moment down went Alice after it, never once +considering how in the world she was to get out again. + + The rabbit-hole went straight on like a tunnel for some way, +and then dipped suddenly down, so suddenly that Alice had not a +moment to think about stopping herself before she found herself +falling down a very deep well. + + Either the well was very deep, or she fell very slowly, for she +had plenty of time as she went down to look about her and to +wonder what was going to happen next. First, she tried to look +down and make out what she was coming to, but it was too dark to +see anything; then she looked at the sides of the well, and +noticed that they were filled with cupboards and book-shelves; +here and there she saw maps and pictures hung upon pegs. She +took down a jar from one of the shelves as she passed; it was +labelled `ORANGE MARMALADE', but to her great disappointment it +was empty: she did not like to drop the jar for fear of killing +somebody, so managed to put it into one of the cupboards as she +fell past it. + + `Well!' thought Alice to herself, `after such a fall as this, I +shall think nothing of tumbling down stairs! How brave they'll +all think me at home! Why, I wouldn't say anything about it, +even if I fell off the top of the house!' (Which was very likely +true.) + + Down, down, down. Would the fall NEVER come to an end! `I +wonder how many miles I've fallen by this time?' she said aloud. +`I must be getting somewhere near the centre of the earth. Let +me see: that would be four thousand miles down, I think--' (for, +you see, Alice had learnt several things of this sort in her +lessons in the schoolroom, and though this was not a VERY good +opportunity for showing off her knowledge, as there was no one to +listen to her, still it was good practice to say it over) `--yes, +that's about the right distance--but then I wonder what Latitude +or Longitude I've got to?' (Alice had no idea what Latitude was, +or Longitude either, but thought they were nice grand words to +say.) + + Presently she began again. `I wonder if I shall fall right +THROUGH the earth! How funny it'll seem to come out among the +people that walk with their heads downward! The Antipathies, I +think--' (she was rather glad there WAS no one listening, this +time, as it didn't sound at all the right word) `--but I shall +have to ask them what the name of the country is, you know. +Please, Ma'am, is this New Zealand or Australia?' (and she tried +to curtsey as she spoke--fancy CURTSEYING as you're falling +through the air! Do you think you could manage it?) `And what +an ignorant little girl she'll think me for asking! No, it'll +never do to ask: perhaps I shall see it written up somewhere.' + + Down, down, down. There was nothing else to do, so Alice soon +began talking again. `Dinah'll miss me very much to-night, I +should think!' (Dinah was the cat.) `I hope they'll remember +her saucer of milk at tea-time. Dinah my dear! I wish you were +down here with me! There are no mice in the air, I'm afraid, but +you might catch a bat, and that's very like a mouse, you know. +But do cats eat bats, I wonder?' And here Alice began to get +rather sleepy, and went on saying to herself, in a dreamy sort of +way, `Do cats eat bats? Do cats eat bats?' and sometimes, `Do +bats eat cats?' for, you see, as she couldn't answer either +question, it didn't much matter which way she put it. She felt +that she was dozing off, and had just begun to dream that she +was walking hand in hand with Dinah, and saying to her very +earnestly, `Now, Dinah, tell me the truth: did you ever eat a +bat?' when suddenly, thump! thump! down she came upon a heap of +sticks and dry leaves, and the fall was over. + + Alice was not a bit hurt, and she jumped up on to her feet in a +moment: she looked up, but it was all dark overhead; before her +was another long passage, and the White Rabbit was still in +sight, hurrying down it. There was not a moment to be lost: +away went Alice like the wind, and was just in time to hear it +say, as it turned a corner, `Oh my ears and whiskers, how late +it's getting!' She was close behind it when she turned the +corner, but the Rabbit was no longer to be seen: she found +herself in a long, low hall, which was lit up by a row of lamps +hanging from the roof. + + There were doors all round the hall, but they were all locked; +and when Alice had been all the way down one side and up the +other, trying every door, she walked sadly down the middle, +wondering how she was ever to get out again. + + Suddenly she came upon a little three-legged table, all made of +solid glass; there was nothing on it except a tiny golden key, +and Alice's first thought was that it might belong to one of the +doors of the hall; but, alas! either the locks were too large, or +the key was too small, but at any rate it would not open any of +them. However, on the second time round, she came upon a low +curtain she had not noticed before, and behind it was a little +door about fifteen inches high: she tried the little golden key +in the lock, and to her great delight it fitted! + + Alice opened the door and found that it led into a small +passage, not much larger than a rat-hole: she knelt down and +looked along the passage into the loveliest garden you ever saw. +How she longed to get out of that dark hall, and wander about +among those beds of bright flowers and those cool fountains, but +she could not even get her head though the doorway; `and even if +my head would go through,' thought poor Alice, `it would be of +very little use without my shoulders. Oh, how I wish +I could shut up like a telescope! I think I could, if I only +know how to begin.' For, you see, so many out-of-the-way things +had happened lately, that Alice had begun to think that very few +things indeed were really impossible. + + There seemed to be no use in waiting by the little door, so she +went back to the table, half hoping she might find another key on +it, or at any rate a book of rules for shutting people up like +telescopes: this time she found a little bottle on it, (`which +certainly was not here before,' said Alice,) and round the neck +of the bottle was a paper label, with the words `DRINK ME' +beautifully printed on it in large letters. + + It was all very well to say `Drink me,' but the wise little +Alice was not going to do THAT in a hurry. `No, I'll look +first,' she said, `and see whether it's marked "poison" or not'; +for she had read several nice little histories about children who +had got burnt, and eaten up by wild beasts and other unpleasant +things, all because they WOULD not remember the simple rules +their friends had taught them: such as, that a red-hot poker +will burn you if you hold it too long; and that if you cut your +finger VERY deeply with a knife, it usually bleeds; and she had +never forgotten that, if you drink much from a bottle marked +`poison,' it is almost certain to disagree with you, sooner or +later. + + However, this bottle was NOT marked `poison,' so Alice ventured +to taste it, and finding it very nice, (it had, in fact, a sort +of mixed flavour of cherry-tart, custard, pine-apple, roast +turkey, toffee, and hot buttered toast,) she very soon finished +it off. + + * * * * * * * + + * * * * * * + + * * * * * * * + + `What a curious feeling!' said Alice; `I must be shutting up +like a telescope.' + + And so it was indeed: she was now only ten inches high, and +her face brightened up at the thought that she was now the right +size for going though the little door into that lovely garden. +First, however, she waited for a few minutes to see if she was +going to shrink any further: she felt a little nervous about +this; `for it might end, you know,' said Alice to herself, `in my +going out altogether, like a candle. I wonder what I should be +like then?' And she tried to fancy what the flame of a candle is +like after the candle is blown out, for she could not remember +ever having seen such a thing. + + After a while, finding that nothing more happened, she decided +on going into the garden at once; but, alas for poor Alice! when +she got to the door, she found he had forgotten the little golden +key, and when she went back to the table for it, she found she +could not possibly reach it: she could see it quite plainly +through the glass, and she tried her best to climb up one of the +legs of the table, but it was too slippery; and when she had +tired herself out with trying, the poor little thing sat down and +cried. + + `Come, there's no use in crying like that!' said Alice to +herself, rather sharply; `I advise you to leave off this minute!' +She generally gave herself very good advice, (though she very +seldom followed it), and sometimes she scolded herself so +severely as to bring tears into her eyes; and once she remembered +trying to box her own ears for having cheated herself in a game +of croquet she was playing against herself, for this curious +child was very fond of pretending to be two people. `But it's no +use now,' thought poor Alice, `to pretend to be two people! Why, +there's hardly enough of me left to make ONE respectable +person!' + + Soon her eye fell on a little glass box that was lying under +the table: she opened it, and found in it a very small cake, on +which the words `EAT ME' were beautifully marked in currants. +`Well, I'll eat it,' said Alice, `and if it makes me grow larger, +I can reach the key; and if it makes me grow smaller, I can creep +under the door; so either way I'll get into the garden, and I +don't care which happens!' + + She ate a little bit, and said anxiously to herself, `Which +way? Which way?', holding her hand on the top of her head to +feel which way it was growing, and she was quite surprised to +find that she remained the same size: to be sure, this generally +happens when one eats cake, but Alice had got so much into the +way of expecting nothing but out-of-the-way things to happen, +that it seemed quite dull and stupid for life to go on in the +common way. + + So she set to work, and very soon finished off the cake. + + * * * * * * * + + * * * * * * + + * * * * * * * + + + + + CHAPTER II + + The Pool of Tears + + + `Curiouser and curiouser!' cried Alice (she was so much +surprised, that for the moment she quite forgot how to speak good +English); `now I'm opening out like the largest telescope that +ever was! Good-bye, feet!' (for when she looked down at her +feet, they seemed to be almost out of sight, they were getting so +far off). `Oh, my poor little feet, I wonder who will put on +your shoes and stockings for you now, dears? I'm sure _I_ shan't +be able! I shall be a great deal too far off to trouble myself +about you: you must manage the best way you can; --but I must be +kind to them,' thought Alice, `or perhaps they won't walk the +way I want to go! Let me see: I'll give them a new pair of +boots every Christmas.' + + And she went on planning to herself how she would manage it. +`They must go by the carrier,' she thought; `and how funny it'll +seem, sending presents to one's own feet! And how odd the +directions will look! + + ALICE'S RIGHT FOOT, ESQ. + HEARTHRUG, + NEAR THE FENDER, + (WITH ALICE'S LOVE). + +Oh dear, what nonsense I'm talking!' + + Just then her head struck against the roof of the hall: in +fact she was now more than nine feet high, and she at once took +up the little golden key and hurried off to the garden door. + + Poor Alice! It was as much as she could do, lying down on one +side, to look through into the garden with one eye; but to get +through was more hopeless than ever: she sat down and began to +cry again. + + `You ought to be ashamed of yourself,' said Alice, `a great +girl like you,' (she might well say this), `to go on crying in +this way! Stop this moment, I tell you!' But she went on all +the same, shedding gallons of tears, until there was a large pool +all round her, about four inches deep and reaching half down the +hall. + + After a time she heard a little pattering of feet in the +distance, and she hastily dried her eyes to see what was coming. +It was the White Rabbit returning, splendidly dressed, with a +pair of white kid gloves in one hand and a large fan in the +other: he came trotting along in a great hurry, muttering to +himself as he came, `Oh! the Duchess, the Duchess! Oh! won't she +be savage if I've kept her waiting!' Alice felt so desperate +that she was ready to ask help of any one; so, when the Rabbit +came near her, she began, in a low, timid voice, `If you please, +sir--' The Rabbit started violently, dropped the white kid +gloves and the fan, and skurried away into the darkness as hard +as he could go. + + Alice took up the fan and gloves, and, as the hall was very +hot, she kept fanning herself all the time she went on talking: +`Dear, dear! How queer everything is to-day! And yesterday +things went on just as usual. I wonder if I've been changed in +the night? Let me think: was I the same when I got up this +morning? I almost think I can remember feeling a little +different. But if I'm not the same, the next question is, Who in +the world am I? Ah, THAT'S the great puzzle!' And she began +thinking over all the children she knew that were of the same age +as herself, to see if she could have been changed for any of +them. + + `I'm sure I'm not Ada,' she said, `for her hair goes in such +long ringlets, and mine doesn't go in ringlets at all; and I'm +sure I can't be Mabel, for I know all sorts of things, and she, +oh! she knows such a very little! Besides, SHE'S she, and I'm I, +and--oh dear, how puzzling it all is! I'll try if I know all the +things I used to know. Let me see: four times five is twelve, +and four times six is thirteen, and four times seven is--oh dear! +I shall never get to twenty at that rate! However, the +Multiplication Table doesn't signify: let's try Geography. +London is the capital of Paris, and Paris is the capital of Rome, +and Rome--no, THAT'S all wrong, I'm certain! I must have been +changed for Mabel! I'll try and say "How doth the little--"' +and she crossed her hands on her lap as if she were saying lessons, +and began to repeat it, but her voice sounded hoarse and +strange, and the words did not come the same as they used to do:-- + + `How doth the little crocodile + Improve his shining tail, + And pour the waters of the Nile + On every golden scale! + + `How cheerfully he seems to grin, + How neatly spread his claws, + And welcome little fishes in + With gently smiling jaws!' + + `I'm sure those are not the right words,' said poor Alice, and +her eyes filled with tears again as she went on, `I must be Mabel +after all, and I shall have to go and live in that poky little +house, and have next to no toys to play with, and oh! ever so +many lessons to learn! No, I've made up my mind about it; if I'm +Mabel, I'll stay down here! It'll be no use their putting their +heads down and saying "Come up again, dear!" I shall only look +up and say "Who am I then? Tell me that first, and then, if I +like being that person, I'll come up: if not, I'll stay down +here till I'm somebody else"--but, oh dear!' cried Alice, with a +sudden burst of tears, `I do wish they WOULD put their heads +down! I am so VERY tired of being all alone here!' + + As she said this she looked down at her hands, and was +surprised to see that she had put on one of the Rabbit's little +white kid gloves while she was talking. `How CAN I have done +that?' she thought. `I must be growing small again.' She got up +and went to the table to measure herself by it, and found that, +as nearly as she could guess, she was now about two feet high, +and was going on shrinking rapidly: she soon found out that the +cause of this was the fan she was holding, and she dropped it +hastily, just in time to avoid shrinking away altogether. + +`That WAS a narrow escape!' said Alice, a good deal frightened at +the sudden change, but very glad to find herself still in +existence; `and now for the garden!' and she ran with all speed +back to the little door: but, alas! the little door was shut +again, and the little golden key was lying on the glass table as +before, `and things are worse than ever,' thought the poor child, +`for I never was so small as this before, never! And I declare +it's too bad, that it is!' + + As she said these words her foot slipped, and in another +moment, splash! she was up to her chin in salt water. He first +idea was that she had somehow fallen into the sea, `and in that +case I can go back by railway,' she said to herself. (Alice had +been to the seaside once in her life, and had come to the general +conclusion, that wherever you go to on the English coast you find +a number of bathing machines in the sea, some children digging in +the sand with wooden spades, then a row of lodging houses, and +behind them a railway station.) However, she soon made out that +she was in the pool of tears which she had wept when she was nine +feet high. + + `I wish I hadn't cried so much!' said Alice, as she swam about, +trying to find her way out. `I shall be punished for it now, I +suppose, by being drowned in my own tears! That WILL be a queer +thing, to be sure! However, everything is queer to-day.' + + Just then she heard something splashing about in the pool a +little way off, and she swam nearer to make out what it was: at +first she thought it must be a walrus or hippopotamus, but then +she remembered how small she was now, and she soon made out that +it was only a mouse that had slipped in like herself. + + `Would it be of any use, now,' thought Alice, `to speak to this +mouse? Everything is so out-of-the-way down here, that I should +think very likely it can talk: at any rate, there's no harm in +trying.' So she began: `O Mouse, do you know the way out of +this pool? I am very tired of swimming about here, O Mouse!' +(Alice thought this must be the right way of speaking to a mouse: +she had never done such a thing before, but she remembered having +seen in her brother's Latin Grammar, `A mouse--of a mouse--to a +mouse--a mouse--O mouse!' The Mouse looked at her rather +inquisitively, and seemed to her to wink with one of its little +eyes, but it said nothing. + + `Perhaps it doesn't understand English,' thought Alice; `I +daresay it's a French mouse, come over with William the +Conqueror.' (For, with all her knowledge of history, Alice had +no very clear notion how long ago anything had happened.) So she +began again: `Ou est ma chatte?' which was the first sentence in +her French lesson-book. The Mouse gave a sudden leap out of the +water, and seemed to quiver all over with fright. `Oh, I beg +your pardon!' cried Alice hastily, afraid that she had hurt the +poor animal's feelings. `I quite forgot you didn't like cats.' + + `Not like cats!' cried the Mouse, in a shrill, passionate +voice. `Would YOU like cats if you were me?' + + `Well, perhaps not,' said Alice in a soothing tone: `don't be +angry about it. And yet I wish I could show you our cat Dinah: +I think you'd take a fancy to cats if you could only see her. +She is such a dear quiet thing,' Alice went on, half to herself, +as she swam lazily about in the pool, `and she sits purring so +nicely by the fire, licking her paws and washing her face--and +she is such a nice soft thing to nurse--and she's such a capital +one for catching mice--oh, I beg your pardon!' cried Alice again, +for this time the Mouse was bristling all over, and she felt +certain it must be really offended. `We won't talk about her any +more if you'd rather not.' + + `We indeed!' cried the Mouse, who was trembling down to the end +of his tail. `As if I would talk on such a subject! Our family +always HATED cats: nasty, low, vulgar things! Don't let me hear +the name again!' + + `I won't indeed!' said Alice, in a great hurry to change the +subject of conversation. `Are you--are you fond--of--of dogs?' +The Mouse did not answer, so Alice went on eagerly: `There is +such a nice little dog near our house I should like to show you! +A little bright-eyed terrier, you know, with oh, such long curly +brown hair! And it'll fetch things when you throw them, and +it'll sit up and beg for its dinner, and all sorts of things--I +can't remember half of them--and it belongs to a farmer, you +know, and he says it's so useful, it's worth a hundred pounds! +He says it kills all the rats and--oh dear!' cried Alice in a +sorrowful tone, `I'm afraid I've offended it again!' For the +Mouse was swimming away from her as hard as it could go, and +making quite a commotion in the pool as it went. + + So she called softly after it, `Mouse dear! Do come back +again, and we won't talk about cats or dogs either, if you don't +like them!' When the Mouse heard this, it turned round and swam +slowly back to her: its face was quite pale (with passion, Alice +thought), and it said in a low trembling voice, `Let us get to +the shore, and then I'll tell you my history, and you'll +understand why it is I hate cats and dogs.' + + It was high time to go, for the pool was getting quite crowded +with the birds and animals that had fallen into it: there were a +Duck and a Dodo, a Lory and an Eaglet, and several other curious +creatures. Alice led the way, and the whole party swam to the +shore. + + + + CHAPTER III + + A Caucus-Race and a Long Tale + + + They were indeed a queer-looking party that assembled on the +bank--the birds with draggled feathers, the animals with their +fur clinging close to them, and all dripping wet, cross, and +uncomfortable. + + The first question of course was, how to get dry again: they +had a consultation about this, and after a few minutes it seemed +quite natural to Alice to find herself talking familiarly with +them, as if she had known them all her life. Indeed, she had +quite a long argument with the Lory, who at last turned sulky, +and would only say, `I am older than you, and must know better'; +and this Alice would not allow without knowing how old it was, +and, as the Lory positively refused to tell its age, there was no +more to be said. + + At last the Mouse, who seemed to be a person of authority among +them, called out, `Sit down, all of you, and listen to me! I'LL +soon make you dry enough!' They all sat down at once, in a large +ring, with the Mouse in the middle. Alice kept her eyes +anxiously fixed on it, for she felt sure she would catch a bad +cold if she did not get dry very soon. + + `Ahem!' said the Mouse with an important air, `are you all ready? +This is the driest thing I know. Silence all round, if you please! +"William the Conqueror, whose cause was favoured by the pope, was +soon submitted to by the English, who wanted leaders, and had been +of late much accustomed to usurpation and conquest. Edwin and +Morcar, the earls of Mercia and Northumbria--"' + + `Ugh!' said the Lory, with a shiver. + + `I beg your pardon!' said the Mouse, frowning, but very +politely: `Did you speak?' + + `Not I!' said the Lory hastily. + + `I thought you did,' said the Mouse. `--I proceed. "Edwin and +Morcar, the earls of Mercia and Northumbria, declared for him: +and even Stigand, the patriotic archbishop of Canterbury, found +it advisable--"' + + `Found WHAT?' said the Duck. + + `Found IT,' the Mouse replied rather crossly: `of course you +know what "it" means.' + + `I know what "it" means well enough, when I find a thing,' said +the Duck: `it's generally a frog or a worm. The question is, +what did the archbishop find?' + + The Mouse did not notice this question, but hurriedly went on, +`"--found it advisable to go with Edgar Atheling to meet William +and offer him the crown. William's conduct at first was +moderate. But the insolence of his Normans--" How are you +getting on now, my dear?' it continued, turning to Alice as it +spoke. + + `As wet as ever,' said Alice in a melancholy tone: `it doesn't +seem to dry me at all.' + + `In that case,' said the Dodo solemnly, rising to its feet, `I +move that the meeting adjourn, for the immediate adoption of more +energetic remedies--' + + `Speak English!' said the Eaglet. `I don't know the meaning of +half those long words, and, what's more, I don't believe you do +either!' And the Eaglet bent down its head to hide a smile: +some of the other birds tittered audibly. + + `What I was going to say,' said the Dodo in an offended tone, +`was, that the best thing to get us dry would be a Caucus-race.' + + `What IS a Caucus-race?' said Alice; not that she wanted much +to know, but the Dodo had paused as if it thought that SOMEBODY +ought to speak, and no one else seemed inclined to say anything. + + `Why,' said the Dodo, `the best way to explain it is to do it.' +(And, as you might like to try the thing yourself, some winter +day, I will tell you how the Dodo managed it.) + + First it marked out a race-course, in a sort of circle, (`the +exact shape doesn't matter,' it said,) and then all the party +were placed along the course, here and there. There was no `One, +two, three, and away,' but they began running when they liked, +and left off when they liked, so that it was not easy to know +when the race was over. However, when they had been running half +an hour or so, and were quite dry again, the Dodo suddenly called +out `The race is over!' and they all crowded round it, panting, +and asking, `But who has won?' + + This question the Dodo could not answer without a great deal of +thought, and it sat for a long time with one finger pressed upon +its forehead (the position in which you usually see Shakespeare, +in the pictures of him), while the rest waited in silence. At +last the Dodo said, `EVERYBODY has won, and all must have +prizes.' + + `But who is to give the prizes?' quite a chorus of voices +asked. + + `Why, SHE, of course,' said the Dodo, pointing to Alice with +one finger; and the whole party at once crowded round her, +calling out in a confused way, `Prizes! Prizes!' + + Alice had no idea what to do, and in despair she put her hand +in her pocket, and pulled out a box of comfits, (luckily the salt +water had not got into it), and handed them round as prizes. +There was exactly one a-piece all round. + + `But she must have a prize herself, you know,' said the Mouse. + + `Of course,' the Dodo replied very gravely. `What else have +you got in your pocket?' he went on, turning to Alice. + + `Only a thimble,' said Alice sadly. + + `Hand it over here,' said the Dodo. + + Then they all crowded round her once more, while the Dodo +solemnly presented the thimble, saying `We beg your acceptance of +this elegant thimble'; and, when it had finished this short +speech, they all cheered. + + Alice thought the whole thing very absurd, but they all looked +so grave that she did not dare to laugh; and, as she could not +think of anything to say, she simply bowed, and took the thimble, +looking as solemn as she could. + + The next thing was to eat the comfits: this caused some noise +and confusion, as the large birds complained that they could not +taste theirs, and the small ones choked and had to be patted on +the back. However, it was over at last, and they sat down again +in a ring, and begged the Mouse to tell them something more. + + `You promised to tell me your history, you know,' said Alice, +`and why it is you hate--C and D,' she added in a whisper, half +afraid that it would be offended again. + + `Mine is a long and a sad tale!' said the Mouse, turning to +Alice, and sighing. + + `It IS a long tail, certainly,' said Alice, looking down with +wonder at the Mouse's tail; `but why do you call it sad?' And +she kept on puzzling about it while the Mouse was speaking, so +that her idea of the tale was something like this:-- + + `Fury said to a + mouse, That he + met in the + house, + "Let us + both go to + law: I will + prosecute + YOU. --Come, + I'll take no + denial; We + must have a + trial: For + really this + morning I've + nothing + to do." + Said the + mouse to the + cur, "Such + a trial, + dear Sir, + With + no jury + or judge, + would be + wasting + our + breath." + "I'll be + judge, I'll + be jury," + Said + cunning + old Fury: + "I'll + try the + whole + cause, + and + condemn + you + to + death."' + + + `You are not attending!' said the Mouse to Alice severely. +`What are you thinking of?' + + `I beg your pardon,' said Alice very humbly: `you had got to +the fifth bend, I think?' + + `I had NOT!' cried the Mouse, sharply and very angrily. + + `A knot!' said Alice, always ready to make herself useful, and +looking anxiously about her. `Oh, do let me help to undo it!' + + `I shall do nothing of the sort,' said the Mouse, getting up +and walking away. `You insult me by talking such nonsense!' + + `I didn't mean it!' pleaded poor Alice. `But you're so easily +offended, you know!' + + The Mouse only growled in reply. + + `Please come back and finish your story!' Alice called after +it; and the others all joined in chorus, `Yes, please do!' but +the Mouse only shook its head impatiently, and walked a little +quicker. + + `What a pity it wouldn't stay!' sighed the Lory, as soon as it +was quite out of sight; and an old Crab took the opportunity of +saying to her daughter `Ah, my dear! Let this be a lesson to you +never to lose YOUR temper!' `Hold your tongue, Ma!' said the +young Crab, a little snappishly. `You're enough to try the +patience of an oyster!' + + `I wish I had our Dinah here, I know I do!' said Alice aloud, +addressing nobody in particular. `She'd soon fetch it back!' + + `And who is Dinah, if I might venture to ask the question?' +said the Lory. + + Alice replied eagerly, for she was always ready to talk about +her pet: `Dinah's our cat. And she's such a capital one for +catching mice you can't think! And oh, I wish you could see her +after the birds! Why, she'll eat a little bird as soon as look +at it!' + + This speech caused a remarkable sensation among the party. +Some of the birds hurried off at once: one the old Magpie began +wrapping itself up very carefully, remarking, `I really must be +getting home; the night-air doesn't suit my throat!' and a Canary +called out in a trembling voice to its children, `Come away, my +dears! It's high time you were all in bed!' On various pretexts +they all moved off, and Alice was soon left alone. + + `I wish I hadn't mentioned Dinah!' she said to herself in a +melancholy tone. `Nobody seems to like her, down here, and I'm +sure she's the best cat in the world! Oh, my dear Dinah! I +wonder if I shall ever see you any more!' And here poor Alice +began to cry again, for she felt very lonely and low-spirited. +In a little while, however, she again heard a little pattering of +footsteps in the distance, and she looked up eagerly, half hoping +that the Mouse had changed his mind, and was coming back to +finish his story. + + + + CHAPTER IV + + The Rabbit Sends in a Little Bill + + + It was the White Rabbit, trotting slowly back again, and +looking anxiously about as it went, as if it had lost something; +and she heard it muttering to itself `The Duchess! The Duchess! +Oh my dear paws! Oh my fur and whiskers! She'll get me +executed, as sure as ferrets are ferrets! Where CAN I have +dropped them, I wonder?' Alice guessed in a moment that it was +looking for the fan and the pair of white kid gloves, and she +very good-naturedly began hunting about for them, but they were +nowhere to be seen--everything seemed to have changed since her +swim in the pool, and the great hall, with the glass table and +the little door, had vanished completely. + + Very soon the Rabbit noticed Alice, as she went hunting about, +and called out to her in an angry tone, `Why, Mary Ann, what ARE +you doing out here? Run home this moment, and fetch me a pair of +gloves and a fan! Quick, now!' And Alice was so much frightened +that she ran off at once in the direction it pointed to, without +trying to explain the mistake it had made. + + `He took me for his housemaid,' she said to herself as she ran. +`How surprised he'll be when he finds out who I am! But I'd +better take him his fan and gloves--that is, if I can find them.' +As she said this, she came upon a neat little house, on the door +of which was a bright brass plate with the name `W. RABBIT' +engraved upon it. She went in without knocking, and hurried +upstairs, in great fear lest she should meet the real Mary Ann, +and be turned out of the house before she had found the fan and +gloves. + + `How queer it seems,' Alice said to herself, `to be going +messages for a rabbit! I suppose Dinah'll be sending me on +messages next!' And she began fancying the sort of thing that +would happen: `"Miss Alice! Come here directly, and get ready +for your walk!" "Coming in a minute, nurse! But I've got to see +that the mouse doesn't get out." Only I don't think,' Alice went +on, `that they'd let Dinah stop in the house if it began ordering +people about like that!' + + By this time she had found her way into a tidy little room with +a table in the window, and on it (as she had hoped) a fan and two +or three pairs of tiny white kid gloves: she took up the fan and +a pair of the gloves, and was just going to leave the room, when +her eye fell upon a little bottle that stood near the looking- +glass. There was no label this time with the words `DRINK ME,' +but nevertheless she uncorked it and put it to her lips. `I know +SOMETHING interesting is sure to happen,' she said to herself, +`whenever I eat or drink anything; so I'll just see what this +bottle does. I do hope it'll make me grow large again, for +really I'm quite tired of being such a tiny little thing!' + + It did so indeed, and much sooner than she had expected: +before she had drunk half the bottle, she found her head pressing +against the ceiling, and had to stoop to save her neck from being +broken. She hastily put down the bottle, saying to herself +`That's quite enough--I hope I shan't grow any more--As it is, I +can't get out at the door--I do wish I hadn't drunk quite so +much!' + + Alas! it was too late to wish that! She went on growing, and +growing, and very soon had to kneel down on the floor: in +another minute there was not even room for this, and she tried +the effect of lying down with one elbow against the door, and the +other arm curled round her head. Still she went on growing, and, +as a last resource, she put one arm out of the window, and one +foot up the chimney, and said to herself `Now I can do no more, +whatever happens. What WILL become of me?' + + Luckily for Alice, the little magic bottle had now had its full +effect, and she grew no larger: still it was very uncomfortable, +and, as there seemed to be no sort of chance of her ever getting +out of the room again, no wonder she felt unhappy. + + `It was much pleasanter at home,' thought poor Alice, `when one +wasn't always growing larger and smaller, and being ordered about +by mice and rabbits. I almost wish I hadn't gone down that +rabbit-hole--and yet--and yet--it's rather curious, you know, +this sort of life! I do wonder what CAN have happened to me! +When I used to read fairy-tales, I fancied that kind of thing +never happened, and now here I am in the middle of one! There +ought to be a book written about me, that there ought! And when +I grow up, I'll write one--but I'm grown up now,' she added in a +sorrowful tone; `at least there's no room to grow up any more +HERE.' + + `But then,' thought Alice, `shall I NEVER get any older than I +am now? That'll be a comfort, one way--never to be an old woman- +-but then--always to have lessons to learn! Oh, I shouldn't like +THAT!' + + `Oh, you foolish Alice!' she answered herself. `How can you +learn lessons in here? Why, there's hardly room for YOU, and no +room at all for any lesson-books!' + + And so she went on, taking first one side and then the other, +and making quite a conversation of it altogether; but after a few +minutes she heard a voice outside, and stopped to listen. + + `Mary Ann! Mary Ann!' said the voice. `Fetch me my gloves +this moment!' Then came a little pattering of feet on the +stairs. Alice knew it was the Rabbit coming to look for her, and +she trembled till she shook the house, quite forgetting that she +was now about a thousand times as large as the Rabbit, and had no +reason to be afraid of it. + + Presently the Rabbit came up to the door, and tried to open it; +but, as the door opened inwards, and Alice's elbow was pressed +hard against it, that attempt proved a failure. Alice heard it +say to itself `Then I'll go round and get in at the window.' + + `THAT you won't' thought Alice, and, after waiting till she +fancied she heard the Rabbit just under the window, she suddenly +spread out her hand, and made a snatch in the air. She did not +get hold of anything, but she heard a little shriek and a fall, +and a crash of broken glass, from which she concluded that it was +just possible it had fallen into a cucumber-frame, or something +of the sort. + + Next came an angry voice--the Rabbit's--`Pat! Pat! Where are +you?' And then a voice she had never heard before, `Sure then +I'm here! Digging for apples, yer honour!' + + `Digging for apples, indeed!' said the Rabbit angrily. `Here! +Come and help me out of THIS!' (Sounds of more broken glass.) + + `Now tell me, Pat, what's that in the window?' + + `Sure, it's an arm, yer honour!' (He pronounced it `arrum.') + + `An arm, you goose! Who ever saw one that size? Why, it +fills the whole window!' + + `Sure, it does, yer honour: but it's an arm for all that.' + + `Well, it's got no business there, at any rate: go and take it +away!' + + There was a long silence after this, and Alice could only hear +whispers now and then; such as, `Sure, I don't like it, yer +honour, at all, at all!' `Do as I tell you, you coward!' and at +last she spread out her hand again, and made another snatch in +the air. This time there were TWO little shrieks, and more +sounds of broken glass. `What a number of cucumber-frames there +must be!' thought Alice. `I wonder what they'll do next! As for +pulling me out of the window, I only wish they COULD! I'm sure I +don't want to stay in here any longer!' + + She waited for some time without hearing anything more: at +last came a rumbling of little cartwheels, and the sound of a +good many voice all talking together: she made out the words: +`Where's the other ladder?--Why, I hadn't to bring but one; +Bill's got the other--Bill! fetch it here, lad!--Here, put 'em up +at this corner--No, tie 'em together first--they don't reach half +high enough yet--Oh! they'll do well enough; don't be particular- +-Here, Bill! catch hold of this rope--Will the roof bear?--Mind +that loose slate--Oh, it's coming down! Heads below!' (a loud +crash)--`Now, who did that?--It was Bill, I fancy--Who's to go +down the chimney?--Nay, I shan't! YOU do it!--That I won't, +then!--Bill's to go down--Here, Bill! the master says you're to +go down the chimney!' + + `Oh! So Bill's got to come down the chimney, has he?' said +Alice to herself. `Shy, they seem to put everything upon Bill! +I wouldn't be in Bill's place for a good deal: this fireplace is +narrow, to be sure; but I THINK I can kick a little!' + + She drew her foot as far down the chimney as she could, and +waited till she heard a little animal (she couldn't guess of what +sort it was) scratching and scrambling about in the chimney close +above her: then, saying to herself `This is Bill,' she gave one +sharp kick, and waited to see what would happen next. + + The first thing she heard was a general chorus of `There goes +Bill!' then the Rabbit's voice along--`Catch him, you by the +hedge!' then silence, and then another confusion of voices--`Hold +up his head--Brandy now--Don't choke him--How was it, old fellow? +What happened to you? Tell us all about it!' + + Last came a little feeble, squeaking voice, (`That's Bill,' +thought Alice,) `Well, I hardly know--No more, thank ye; I'm +better now--but I'm a deal too flustered to tell you--all I know +is, something comes at me like a Jack-in-the-box, and up I goes +like a sky-rocket!' + + `So you did, old fellow!' said the others. + + `We must burn the house down!' said the Rabbit's voice; and +Alice called out as loud as she could, `If you do. I'll set +Dinah at you!' + + There was a dead silence instantly, and Alice thought to +herself, `I wonder what they WILL do next! If they had any +sense, they'd take the roof off.' After a minute or two, they +began moving about again, and Alice heard the Rabbit say, `A +barrowful will do, to begin with.' + + `A barrowful of WHAT?' thought Alice; but she had not long to +doubt, for the next moment a shower of little pebbles came +rattling in at the window, and some of them hit her in the face. +`I'll put a stop to this,' she said to herself, and shouted out, +`You'd better not do that again!' which produced another dead +silence. + + Alice noticed with some surprise that the pebbles were all +turning into little cakes as they lay on the floor, and a bright +idea came into her head. `If I eat one of these cakes,' she +thought, `it's sure to make SOME change in my size; and as it +can't possibly make me larger, it must make me smaller, I +suppose.' + + So she swallowed one of the cakes, and was delighted to find +that she began shrinking directly. As soon as she was small +enough to get through the door, she ran out of the house, and +found quite a crowd of little animals and birds waiting outside. +The poor little Lizard, Bill, was in the middle, being held up by +two guinea-pigs, who were giving it something out of a bottle. +They all made a rush at Alice the moment she appeared; but she +ran off as hard as she could, and soon found herself safe in a +thick wood. + + `The first thing I've got to do,' said Alice to herself, as she +wandered about in the wood, `is to grow to my right size again; +and the second thing is to find my way into that lovely garden. +I think that will be the best plan.' + + It sounded an excellent plan, no doubt, and very neatly and +simply arranged; the only difficulty was, that she had not the +smallest idea how to set about it; and while she was peering +about anxiously among the trees, a little sharp bark just over +her head made her look up in a great hurry. + + An enormous puppy was looking down at her with large round +eyes, and feebly stretching out one paw, trying to touch her. +`Poor little thing!' said Alice, in a coaxing tone, and she tried +hard to whistle to it; but she was terribly frightened all the +time at the thought that it might be hungry, in which case it +would be very likely to eat her up in spite of all her coaxing. + + Hardly knowing what she did, she picked up a little bit of +stick, and held it out to the puppy; whereupon the puppy jumped +into the air off all its feet at once, with a yelp of delight, +and rushed at the stick, and made believe to worry it; then Alice +dodged behind a great thistle, to keep herself from being run +over; and the moment she appeared on the other side, the puppy +made another rush at the stick, and tumbled head over heels in +its hurry to get hold of it; then Alice, thinking it was very +like having a game of play with a cart-horse, and expecting every +moment to be trampled under its feet, ran round the thistle +again; then the puppy began a series of short charges at the +stick, running a very little way forwards each time and a long +way back, and barking hoarsely all the while, till at last it sat +down a good way off, panting, with its tongue hanging out of its +mouth, and its great eyes half shut. + + This seemed to Alice a good opportunity for making her escape; +so she set off at once, and ran till she was quite tired and out +of breath, and till the puppy's bark sounded quite faint in the +distance. + + `And yet what a dear little puppy it was!' said Alice, as she +leant against a buttercup to rest herself, and fanned herself +with one of the leaves: `I should have liked teaching it tricks +very much, if--if I'd only been the right size to do it! Oh +dear! I'd nearly forgotten that I've got to grow up again! Let +me see--how IS it to be managed? I suppose I ought to eat or +drink something or other; but the great question is, what?' + + The great question certainly was, what? Alice looked all round +her at the flowers and the blades of grass, but she did not see +anything that looked like the right thing to eat or drink under +the circumstances. There was a large mushroom growing near her, +about the same height as herself; and when she had looked under +it, and on both sides of it, and behind it, it occurred to her +that she might as well look and see what was on the top of it. + + She stretched herself up on tiptoe, and peeped over the edge of +the mushroom, and her eyes immediately met those of a large +caterpillar, that was sitting on the top with its arms folded, +quietly smoking a long hookah, and taking not the smallest notice +of her or of anything else. + + + + CHAPTER V + + Advice from a Caterpillar + + + The Caterpillar and Alice looked at each other for some time in +silence: at last the Caterpillar took the hookah out of its +mouth, and addressed her in a languid, sleepy voice. + + `Who are YOU?' said the Caterpillar. + + This was not an encouraging opening for a conversation. Alice +replied, rather shyly, `I--I hardly know, sir, just at present-- +at least I know who I WAS when I got up this morning, but I think +I must have been changed several times since then.' + + `What do you mean by that?' said the Caterpillar sternly. +`Explain yourself!' + + `I can't explain MYSELF, I'm afraid, sir' said Alice, `because +I'm not myself, you see.' + + `I don't see,' said the Caterpillar. + + `I'm afraid I can't put it more clearly,' Alice replied very +politely, `for I can't understand it myself to begin with; and +being so many different sizes in a day is very confusing.' + + `It isn't,' said the Caterpillar. + + `Well, perhaps you haven't found it so yet,' said Alice; `but +when you have to turn into a chrysalis--you will some day, you +know--and then after that into a butterfly, I should think you'll +feel it a little queer, won't you?' + + `Not a bit,' said the Caterpillar. + + `Well, perhaps your feelings may be different,' said Alice; +`all I know is, it would feel very queer to ME.' + + `You!' said the Caterpillar contemptuously. `Who are YOU?' + + Which brought them back again to the beginning of the +conversation. Alice felt a little irritated at the Caterpillar's +making such VERY short remarks, and she drew herself up and said, +very gravely, `I think, you ought to tell me who YOU are, first.' + + `Why?' said the Caterpillar. + + Here was another puzzling question; and as Alice could not +think of any good reason, and as the Caterpillar seemed to be in +a VERY unpleasant state of mind, she turned away. + + `Come back!' the Caterpillar called after her. `I've something +important to say!' + + This sounded promising, certainly: Alice turned and came back +again. + + `Keep your temper,' said the Caterpillar. + + `Is that all?' said Alice, swallowing down her anger as well as +she could. + + `No,' said the Caterpillar. + + Alice thought she might as well wait, as she had nothing else +to do, and perhaps after all it might tell her something worth +hearing. For some minutes it puffed away without speaking, but +at last it unfolded its arms, took the hookah out of its mouth +again, and said, `So you think you're changed, do you?' + + `I'm afraid I am, sir,' said Alice; `I can't remember things as +I used--and I don't keep the same size for ten minutes together!' + + `Can't remember WHAT things?' said the Caterpillar. + + `Well, I've tried to say "HOW DOTH THE LITTLE BUSY BEE," but it +all came different!' Alice replied in a very melancholy voice. + + `Repeat, "YOU ARE OLD, FATHER WILLIAM,"' said the Caterpillar. + + Alice folded her hands, and began:-- + + `You are old, Father William,' the young man said, + `And your hair has become very white; + And yet you incessantly stand on your head-- + Do you think, at your age, it is right?' + + `In my youth,' Father William replied to his son, + `I feared it might injure the brain; + But, now that I'm perfectly sure I have none, + Why, I do it again and again.' + + `You are old,' said the youth, `as I mentioned before, + And have grown most uncommonly fat; + Yet you turned a back-somersault in at the door-- + Pray, what is the reason of that?' + + `In my youth,' said the sage, as he shook his grey locks, + `I kept all my limbs very supple + By the use of this ointment--one shilling the box-- + Allow me to sell you a couple?' + + `You are old,' said the youth, `and your jaws are too weak + For anything tougher than suet; + Yet you finished the goose, with the bones and the beak-- + Pray how did you manage to do it?' + + `In my youth,' said his father, `I took to the law, + And argued each case with my wife; + And the muscular strength, which it gave to my jaw, + Has lasted the rest of my life.' + + `You are old,' said the youth, `one would hardly suppose + That your eye was as steady as ever; + Yet you balanced an eel on the end of your nose-- + What made you so awfully clever?' + + `I have answered three questions, and that is enough,' + Said his father; `don't give yourself airs! + Do you think I can listen all day to such stuff? + Be off, or I'll kick you down stairs!' + + + `That is not said right,' said the Caterpillar. + + `Not QUITE right, I'm afraid,' said Alice, timidly; `some of the +words have got altered.' + + `It is wrong from beginning to end,' said the Caterpillar +decidedly, and there was silence for some minutes. + + The Caterpillar was the first to speak. + + `What size do you want to be?' it asked. + + `Oh, I'm not particular as to size,' Alice hastily replied; +`only one doesn't like changing so often, you know.' + + `I DON'T know,' said the Caterpillar. + + Alice said nothing: she had never been so much contradicted in +her life before, and she felt that she was losing her temper. + + `Are you content now?' said the Caterpillar. + + `Well, I should like to be a LITTLE larger, sir, if you +wouldn't mind,' said Alice: `three inches is such a wretched +height to be.' + + `It is a very good height indeed!' said the Caterpillar +angrily, rearing itself upright as it spoke (it was exactly three +inches high). + + `But I'm not used to it!' pleaded poor Alice in a piteous tone. +And she thought of herself, `I wish the creatures wouldn't be so +easily offended!' + + `You'll get used to it in time,' said the Caterpillar; and it +put the hookah into its mouth and began smoking again. + + This time Alice waited patiently until it chose to speak again. +In a minute or two the Caterpillar took the hookah out of its +mouth and yawned once or twice, and shook itself. Then it got +down off the mushroom, and crawled away in the grass, merely +remarking as it went, `One side will make you grow taller, and +the other side will make you grow shorter.' + + `One side of WHAT? The other side of WHAT?' thought Alice to +herself. + + `Of the mushroom,' said the Caterpillar, just as if she had +asked it aloud; and in another moment it was out of sight. + + Alice remained looking thoughtfully at the mushroom for a +minute, trying to make out which were the two sides of it; and as +it was perfectly round, she found this a very difficult question. +However, at last she stretched her arms round it as far as they +would go, and broke off a bit of the edge with each hand. + + `And now which is which?' she said to herself, and nibbled a +little of the right-hand bit to try the effect: the next moment +she felt a violent blow underneath her chin: it had struck her +foot! + + She was a good deal frightened by this very sudden change, but +she felt that there was no time to be lost, as she was shrinking +rapidly; so she set to work at once to eat some of the other bit. +Her chin was pressed so closely against her foot, that there was +hardly room to open her mouth; but she did it at last, and +managed to swallow a morsel of the lefthand bit. + + + * * * * * * * + + * * * * * * + + * * * * * * * + + `Come, my head's free at last!' said Alice in a tone of +delight, which changed into alarm in another moment, when she +found that her shoulders were nowhere to be found: all she could +see, when she looked down, was an immense length of neck, which +seemed to rise like a stalk out of a sea of green leaves that lay +far below her. + + `What CAN all that green stuff be?' said Alice. `And where +HAVE my shoulders got to? And oh, my poor hands, how is it I +can't see you?' She was moving them about as she spoke, but no +result seemed to follow, except a little shaking among the +distant green leaves. + + As there seemed to be no chance of getting her hands up to her +head, she tried to get her head down to them, and was delighted +to find that her neck would bend about easily in any direction, +like a serpent. She had just succeeded in curving it down into a +graceful zigzag, and was going to dive in among the leaves, which +she found to be nothing but the tops of the trees under which she +had been wandering, when a sharp hiss made her draw back in a +hurry: a large pigeon had flown into her face, and was beating +her violently with its wings. + + `Serpent!' screamed the Pigeon. + + `I'm NOT a serpent!' said Alice indignantly. `Let me alone!' + + `Serpent, I say again!' repeated the Pigeon, but in a more +subdued tone, and added with a kind of sob, `I've tried every +way, and nothing seems to suit them!' + + `I haven't the least idea what you're talking about,' said +Alice. + + `I've tried the roots of trees, and I've tried banks, and I've +tried hedges,' the Pigeon went on, without attending to her; `but +those serpents! There's no pleasing them!' + + Alice was more and more puzzled, but she thought there was no +use in saying anything more till the Pigeon had finished. + + `As if it wasn't trouble enough hatching the eggs,' said the +Pigeon; `but I must be on the look-out for serpents night and +day! Why, I haven't had a wink of sleep these three weeks!' + + `I'm very sorry you've been annoyed,' said Alice, who was +beginning to see its meaning. + + `And just as I'd taken the highest tree in the wood,' continued +the Pigeon, raising its voice to a shriek, `and just as I was +thinking I should be free of them at last, they must needs come +wriggling down from the sky! Ugh, Serpent!' + + `But I'm NOT a serpent, I tell you!' said Alice. `I'm a--I'm +a--' + + `Well! WHAT are you?' said the Pigeon. `I can see you're +trying to invent something!' + + `I--I'm a little girl,' said Alice, rather doubtfully, as she +remembered the number of changes she had gone through that day. + + `A likely story indeed!' said the Pigeon in a tone of the +deepest contempt. `I've seen a good many little girls in my +time, but never ONE with such a neck as that! No, no! You're a +serpent; and there's no use denying it. I suppose you'll be +telling me next that you never tasted an egg!' + + `I HAVE tasted eggs, certainly,' said Alice, who was a very +truthful child; `but little girls eat eggs quite as much as +serpents do, you know.' + + `I don't believe it,' said the Pigeon; `but if they do, why +then they're a kind of serpent, that's all I can say.' + + This was such a new idea to Alice, that she was quite silent +for a minute or two, which gave the Pigeon the opportunity of +adding, `You're looking for eggs, I know THAT well enough; and +what does it matter to me whether you're a little girl or a +serpent?' + + `It matters a good deal to ME,' said Alice hastily; `but I'm +not looking for eggs, as it happens; and if I was, I shouldn't +want YOURS: I don't like them raw.' + + `Well, be off, then!' said the Pigeon in a sulky tone, as it +settled down again into its nest. Alice crouched down among the +trees as well as she could, for her neck kept getting entangled +among the branches, and every now and then she had to stop and +untwist it. After a while she remembered that she still held the +pieces of mushroom in her hands, and she set to work very +carefully, nibbling first at one and then at the other, and +growing sometimes taller and sometimes shorter, until she had +succeeded in bringing herself down to her usual height. + + It was so long since she had been anything near the right size, +that it felt quite strange at first; but she got used to it in a +few minutes, and began talking to herself, as usual. `Come, +there's half my plan done now! How puzzling all these changes +are! I'm never sure what I'm going to be, from one minute to +another! However, I've got back to my right size: the next +thing is, to get into that beautiful garden--how IS that to be +done, I wonder?' As she said this, she came suddenly upon an +open place, with a little house in it about four feet high. +`Whoever lives there,' thought Alice, `it'll never do to come +upon them THIS size: why, I should frighten them out of their +wits!' So she began nibbling at the righthand bit again, and did +not venture to go near the house till she had brought herself +down to nine inches high. + + + + CHAPTER VI + + Pig and Pepper + + + For a minute or two she stood looking at the house, and +wondering what to do next, when suddenly a footman in livery came +running out of the wood--(she considered him to be a footman +because he was in livery: otherwise, judging by his face only, +she would have called him a fish)--and rapped loudly at the door +with his knuckles. It was opened by another footman in livery, +with a round face, and large eyes like a frog; and both footmen, +Alice noticed, had powdered hair that curled all over their +heads. She felt very curious to know what it was all about, and +crept a little way out of the wood to listen. + + The Fish-Footman began by producing from under his arm a great +letter, nearly as large as himself, and this he handed over to +the other, saying, in a solemn tone, `For the Duchess. An +invitation from the Queen to play croquet.' The Frog-Footman +repeated, in the same solemn tone, only changing the order of the +words a little, `From the Queen. An invitation for the Duchess +to play croquet.' + + Then they both bowed low, and their curls got entangled +together. + + Alice laughed so much at this, that she had to run back into +the wood for fear of their hearing her; and when she next peeped +out the Fish-Footman was gone, and the other was sitting on the +ground near the door, staring stupidly up into the sky. + + Alice went timidly up to the door, and knocked. + + `There's no sort of use in knocking,' said the Footman, `and +that for two reasons. First, because I'm on the same side of the +door as you are; secondly, because they're making such a noise +inside, no one could possibly hear you.' And certainly there was +a most extraordinary noise going on within--a constant howling +and sneezing, and every now and then a great crash, as if a dish +or kettle had been broken to pieces. + + `Please, then,' said Alice, `how am I to get in?' + + `There might be some sense in your knocking,' the Footman went +on without attending to her, `if we had the door between us. For +instance, if you were INSIDE, you might knock, and I could let +you out, you know.' He was looking up into the sky all the time +he was speaking, and this Alice thought decidedly uncivil. `But +perhaps he can't help it,' she said to herself; `his eyes are so +VERY nearly at the top of his head. But at any rate he might +answer questions.--How am I to get in?' she repeated, aloud. + + `I shall sit here,' the Footman remarked, `till tomorrow--' + + At this moment the door of the house opened, and a large plate +came skimming out, straight at the Footman's head: it just +grazed his nose, and broke to pieces against one of the trees +behind him. + + `--or next day, maybe,' the Footman continued in the same tone, +exactly as if nothing had happened. + + `How am I to get in?' asked Alice again, in a louder tone. + + `ARE you to get in at all?' said the Footman. `That's the +first question, you know.' + + It was, no doubt: only Alice did not like to be told so. +`It's really dreadful,' she muttered to herself, `the way all the +creatures argue. It's enough to drive one crazy!' + + The Footman seemed to think this a good opportunity for +repeating his remark, with variations. `I shall sit here,' he +said, `on and off, for days and days.' + + `But what am I to do?' said Alice. + + `Anything you like,' said the Footman, and began whistling. + + `Oh, there's no use in talking to him,' said Alice desperately: +`he's perfectly idiotic!' And she opened the door and went in. + + The door led right into a large kitchen, which was full of +smoke from one end to the other: the Duchess was sitting on a +three-legged stool in the middle, nursing a baby; the cook was +leaning over the fire, stirring a large cauldron which seemed to +be full of soup. + + `There's certainly too much pepper in that soup!' Alice said to +herself, as well as she could for sneezing. + + There was certainly too much of it in the air. Even the +Duchess sneezed occasionally; and as for the baby, it was +sneezing and howling alternately without a moment's pause. The +only things in the kitchen that did not sneeze, were the cook, +and a large cat which was sitting on the hearth and grinning from +ear to ear. + + `Please would you tell me,' said Alice, a little timidly, for +she was not quite sure whether it was good manners for her to +speak first, `why your cat grins like that?' + + `It's a Cheshire cat,' said the Duchess, `and that's why. +Pig!' + + She said the last word with such sudden violence that Alice +quite jumped; but she saw in another moment that it was addressed +to the baby, and not to her, so she took courage, and went on +again:-- + + `I didn't know that Cheshire cats always grinned; in fact, I +didn't know that cats COULD grin.' + + `They all can,' said the Duchess; `and most of 'em do.' + + `I don't know of any that do,' Alice said very politely, +feeling quite pleased to have got into a conversation. + + `You don't know much,' said the Duchess; `and that's a fact.' + + Alice did not at all like the tone of this remark, and thought +it would be as well to introduce some other subject of +conversation. While she was trying to fix on one, the cook took +the cauldron of soup off the fire, and at once set to work +throwing everything within her reach at the Duchess and the baby +--the fire-irons came first; then followed a shower of saucepans, +plates, and dishes. The Duchess took no notice of them even when +they hit her; and the baby was howling so much already, that it +was quite impossible to say whether the blows hurt it or not. + + `Oh, PLEASE mind what you're doing!' cried Alice, jumping up +and down in an agony of terror. `Oh, there goes his PRECIOUS +nose'; as an unusually large saucepan flew close by it, and very +nearly carried it off. + + `If everybody minded their own business,' the Duchess said in a +hoarse growl, `the world would go round a deal faster than it +does.' + + `Which would NOT be an advantage,' said Alice, who felt very +glad to get an opportunity of showing off a little of her +knowledge. `Just think of what work it would make with the day +and night! You see the earth takes twenty-four hours to turn +round on its axis--' + + `Talking of axes,' said the Duchess, `chop off her head!' + + Alice glanced rather anxiously at the cook, to see if she meant +to take the hint; but the cook was busily stirring the soup, and +seemed not to be listening, so she went on again: `Twenty-four +hours, I THINK; or is it twelve? I--' + + `Oh, don't bother ME,' said the Duchess; `I never could abide +figures!' And with that she began nursing her child again, +singing a sort of lullaby to it as she did so, and giving it a +violent shake at the end of every line: + + `Speak roughly to your little boy, + And beat him when he sneezes: + He only does it to annoy, + Because he knows it teases.' + + CHORUS. + + (In which the cook and the baby joined):-- + + `Wow! wow! wow!' + + While the Duchess sang the second verse of the song, she kept +tossing the baby violently up and down, and the poor little thing +howled so, that Alice could hardly hear the words:-- + + `I speak severely to my boy, + I beat him when he sneezes; + For he can thoroughly enjoy + The pepper when he pleases!' + + CHORUS. + + `Wow! wow! wow!' + + `Here! you may nurse it a bit, if you like!' the Duchess said +to Alice, flinging the baby at her as she spoke. `I must go and +get ready to play croquet with the Queen,' and she hurried out of +the room. The cook threw a frying-pan after her as she went out, +but it just missed her. + + Alice caught the baby with some difficulty, as it was a queer- +shaped little creature, and held out its arms and legs in all +directions, `just like a star-fish,' thought Alice. The poor +little thing was snorting like a steam-engine when she caught it, +and kept doubling itself up and straightening itself out again, +so that altogether, for the first minute or two, it was as much +as she could do to hold it. + + As soon as she had made out the proper way of nursing it, +(which was to twist it up into a sort of knot, and then keep +tight hold of its right ear and left foot, so as to prevent its +undoing itself,) she carried it out into the open air. `IF I +don't take this child away with me,' thought Alice, `they're sure +to kill it in a day or two: wouldn't it be murder to leave it +behind?' She said the last words out loud, and the little thing +grunted in reply (it had left off sneezing by this time). `Don't +grunt,' said Alice; `that's not at all a proper way of expressing +yourself.' + + The baby grunted again, and Alice looked very anxiously into +its face to see what was the matter with it. There could be no +doubt that it had a VERY turn-up nose, much more like a snout +than a real nose; also its eyes were getting extremely small for +a baby: altogether Alice did not like the look of the thing at +all. `But perhaps it was only sobbing,' she thought, and looked +into its eyes again, to see if there were any tears. + + No, there were no tears. `If you're going to turn into a pig, +my dear,' said Alice, seriously, `I'll have nothing more to do +with you. Mind now!' The poor little thing sobbed again (or +grunted, it was impossible to say which), and they went on for +some while in silence. + + Alice was just beginning to think to herself, `Now, what am I +to do with this creature when I get it home?' when it grunted +again, so violently, that she looked down into its face in some +alarm. This time there could be NO mistake about it: it was +neither more nor less than a pig, and she felt that it would be +quite absurd for her to carry it further. + + So she set the little creature down, and felt quite relieved to +see it trot away quietly into the wood. `If it had grown up,' +she said to herself, `it would have made a dreadfully ugly child: +but it makes rather a handsome pig, I think.' And she began +thinking over other children she knew, who might do very well as +pigs, and was just saying to herself, `if one only knew the right +way to change them--' when she was a little startled by seeing +the Cheshire Cat sitting on a bough of a tree a few yards off. + + The Cat only grinned when it saw Alice. It looked good- +natured, she thought: still it had VERY long claws and a great +many teeth, so she felt that it ought to be treated with respect. + + `Cheshire Puss,' she began, rather timidly, as she did not at +all know whether it would like the name: however, it only +grinned a little wider. `Come, it's pleased so far,' thought +Alice, and she went on. `Would you tell me, please, which way I +ought to go from here?' + + `That depends a good deal on where you want to get to,' said +the Cat. + + `I don't much care where--' said Alice. + + `Then it doesn't matter which way you go,' said the Cat. + + `--so long as I get SOMEWHERE,' Alice added as an explanation. + + `Oh, you're sure to do that,' said the Cat, `if you only walk +long enough.' + + Alice felt that this could not be denied, so she tried another +question. `What sort of people live about here?' + + `In THAT direction,' the Cat said, waving its right paw round, +`lives a Hatter: and in THAT direction,' waving the other paw, +`lives a March Hare. Visit either you like: they're both mad.' + + `But I don't want to go among mad people,' Alice remarked. + + `Oh, you can't help that,' said the Cat: `we're all mad here. +I'm mad. You're mad.' + + `How do you know I'm mad?' said Alice. + + `You must be,' said the Cat, `or you wouldn't have come here.' + + Alice didn't think that proved it at all; however, she went on +`And how do you know that you're mad?' + + `To begin with,' said the Cat, `a dog's not mad. You grant +that?' + + `I suppose so,' said Alice. + + `Well, then,' the Cat went on, `you see, a dog growls when it's +angry, and wags its tail when it's pleased. Now I growl when I'm +pleased, and wag my tail when I'm angry. Therefore I'm mad.' + + `I call it purring, not growling,' said Alice. + + `Call it what you like,' said the Cat. `Do you play croquet +with the Queen to-day?' + + `I should like it very much,' said Alice, `but I haven't been +invited yet.' + + `You'll see me there,' said the Cat, and vanished. + + Alice was not much surprised at this, she was getting so used +to queer things happening. While she was looking at the place +where it had been, it suddenly appeared again. + + `By-the-bye, what became of the baby?' said the Cat. `I'd +nearly forgotten to ask.' + + `It turned into a pig,' Alice quietly said, just as if it had +come back in a natural way. + + `I thought it would,' said the Cat, and vanished again. + + Alice waited a little, half expecting to see it again, but it +did not appear, and after a minute or two she walked on in the +direction in which the March Hare was said to live. `I've seen +hatters before,' she said to herself; `the March Hare will be +much the most interesting, and perhaps as this is May it won't be +raving mad--at least not so mad as it was in March.' As she said +this, she looked up, and there was the Cat again, sitting on a +branch of a tree. + + `Did you say pig, or fig?' said the Cat. + + `I said pig,' replied Alice; `and I wish you wouldn't keep +appearing and vanishing so suddenly: you make one quite giddy.' + + `All right,' said the Cat; and this time it vanished quite +slowly, beginning with the end of the tail, and ending with the +grin, which remained some time after the rest of it had gone. + + `Well! I've often seen a cat without a grin,' thought Alice; +`but a grin without a cat! It's the most curious thing I ever +say in my life!' + + She had not gone much farther before she came in sight of the +house of the March Hare: she thought it must be the right house, +because the chimneys were shaped like ears and the roof was +thatched with fur. It was so large a house, that she did not +like to go nearer till she had nibbled some more of the lefthand +bit of mushroom, and raised herself to about two feet high: even +then she walked up towards it rather timidly, saying to herself +`Suppose it should be raving mad after all! I almost wish I'd +gone to see the Hatter instead!' + + + + CHAPTER VII + + A Mad Tea-Party + + + There was a table set out under a tree in front of the house, +and the March Hare and the Hatter were having tea at it: a +Dormouse was sitting between them, fast asleep, and the other two +were using it as a cushion, resting their elbows on it, and the +talking over its head. `Very uncomfortable for the Dormouse,' +thought Alice; `only, as it's asleep, I suppose it doesn't mind.' + + The table was a large one, but the three were all crowded +together at one corner of it: `No room! No room!' they cried +out when they saw Alice coming. `There's PLENTY of room!' said +Alice indignantly, and she sat down in a large arm-chair at one +end of the table. + + `Have some wine,' the March Hare said in an encouraging tone. + + Alice looked all round the table, but there was nothing on it +but tea. `I don't see any wine,' she remarked. + + `There isn't any,' said the March Hare. + + `Then it wasn't very civil of you to offer it,' said Alice +angrily. + + `It wasn't very civil of you to sit down without being +invited,' said the March Hare. + + `I didn't know it was YOUR table,' said Alice; `it's laid for a +great many more than three.' + + `Your hair wants cutting,' said the Hatter. He had been +looking at Alice for some time with great curiosity, and this was +his first speech. + + `You should learn not to make personal remarks,' Alice said +with some severity; `it's very rude.' + + The Hatter opened his eyes very wide on hearing this; but all +he SAID was, `Why is a raven like a writing-desk?' + + `Come, we shall have some fun now!' thought Alice. `I'm glad +they've begun asking riddles.--I believe I can guess that,' she +added aloud. + + `Do you mean that you think you can find out the answer to it?' +said the March Hare. + + `Exactly so,' said Alice. + + `Then you should say what you mean,' the March Hare went on. + + `I do,' Alice hastily replied; `at least--at least I mean what +I say--that's the same thing, you know.' + + `Not the same thing a bit!' said the Hatter. `You might just +as well say that "I see what I eat" is the same thing as "I eat +what I see"!' + + `You might just as well say,' added the March Hare, `that "I +like what I get" is the same thing as "I get what I like"!' + + `You might just as well say,' added the Dormouse, who seemed to +be talking in his sleep, `that "I breathe when I sleep" is the +same thing as "I sleep when I breathe"!' + + `It IS the same thing with you,' said the Hatter, and here the +conversation dropped, and the party sat silent for a minute, +while Alice thought over all she could remember about ravens and +writing-desks, which wasn't much. + + The Hatter was the first to break the silence. `What day of +the month is it?' he said, turning to Alice: he had taken his +watch out of his pocket, and was looking at it uneasily, shaking +it every now and then, and holding it to his ear. + + Alice considered a little, and then said `The fourth.' + + `Two days wrong!' sighed the Hatter. `I told you butter +wouldn't suit the works!' he added looking angrily at the March +Hare. + + `It was the BEST butter,' the March Hare meekly replied. + + `Yes, but some crumbs must have got in as well,' the Hatter +grumbled: `you shouldn't have put it in with the bread-knife.' + + The March Hare took the watch and looked at it gloomily: then +he dipped it into his cup of tea, and looked at it again: but he +could think of nothing better to say than his first remark, `It +was the BEST butter, you know.' + + Alice had been looking over his shoulder with some curiosity. +`What a funny watch!' she remarked. `It tells the day of the +month, and doesn't tell what o'clock it is!' + + `Why should it?' muttered the Hatter. `Does YOUR watch tell +you what year it is?' + + `Of course not,' Alice replied very readily: `but that's +because it stays the same year for such a long time together.' + + `Which is just the case with MINE,' said the Hatter. + + Alice felt dreadfully puzzled. The Hatter's remark seemed to +have no sort of meaning in it, and yet it was certainly English. +`I don't quite understand you,' she said, as politely as she +could. + + `The Dormouse is asleep again,' said the Hatter, and he poured +a little hot tea upon its nose. + + The Dormouse shook its head impatiently, and said, without +opening its eyes, `Of course, of course; just what I was going to +remark myself.' + + `Have you guessed the riddle yet?' the Hatter said, turning to +Alice again. + + `No, I give it up,' Alice replied: `what's the answer?' + + `I haven't the slightest idea,' said the Hatter. + + `Nor I,' said the March Hare. + + Alice sighed wearily. `I think you might do something better +with the time,' she said, `than waste it in asking riddles that +have no answers.' + + `If you knew Time as well as I do,' said the Hatter, `you +wouldn't talk about wasting IT. It's HIM.' + + `I don't know what you mean,' said Alice. + + `Of course you don't!' the Hatter said, tossing his head +contemptuously. `I dare say you never even spoke to Time!' + + `Perhaps not,' Alice cautiously replied: `but I know I have to +beat time when I learn music.' + + `Ah! that accounts for it,' said the Hatter. `He won't stand +beating. Now, if you only kept on good terms with him, he'd do +almost anything you liked with the clock. For instance, suppose +it were nine o'clock in the morning, just time to begin lessons: +you'd only have to whisper a hint to Time, and round goes the +clock in a twinkling! Half-past one, time for dinner!' + + (`I only wish it was,' the March Hare said to itself in a +whisper.) + + `That would be grand, certainly,' said Alice thoughtfully: +`but then--I shouldn't be hungry for it, you know.' + + `Not at first, perhaps,' said the Hatter: `but you could keep +it to half-past one as long as you liked.' + + `Is that the way YOU manage?' Alice asked. + + The Hatter shook his head mournfully. `Not I!' he replied. +`We quarrelled last March--just before HE went mad, you know--' +(pointing with his tea spoon at the March Hare,) `--it was at the +great concert given by the Queen of Hearts, and I had to sing + + "Twinkle, twinkle, little bat! + How I wonder what you're at!" + +You know the song, perhaps?' + + `I've heard something like it,' said Alice. + + `It goes on, you know,' the Hatter continued, `in this way:-- + + "Up above the world you fly, + Like a tea-tray in the sky. + Twinkle, twinkle--"' + +Here the Dormouse shook itself, and began singing in its sleep +`Twinkle, twinkle, twinkle, twinkle--' and went on so long that +they had to pinch it to make it stop. + + `Well, I'd hardly finished the first verse,' said the Hatter, +`when the Queen jumped up and bawled out, "He's murdering the +time! Off with his head!"' + + `How dreadfully savage!' exclaimed Alice. + + `And ever since that,' the Hatter went on in a mournful tone, +`he won't do a thing I ask! It's always six o'clock now.' + + A bright idea came into Alice's head. `Is that the reason so +many tea-things are put out here?' she asked. + + `Yes, that's it,' said the Hatter with a sigh: `it's always +tea-time, and we've no time to wash the things between whiles.' + + `Then you keep moving round, I suppose?' said Alice. + + `Exactly so,' said the Hatter: `as the things get used up.' + + `But what happens when you come to the beginning again?' Alice +ventured to ask. + + `Suppose we change the subject,' the March Hare interrupted, +yawning. `I'm getting tired of this. I vote the young lady +tells us a story.' + + `I'm afraid I don't know one,' said Alice, rather alarmed at +the proposal. + + `Then the Dormouse shall!' they both cried. `Wake up, +Dormouse!' And they pinched it on both sides at once. + + The Dormouse slowly opened his eyes. `I wasn't asleep,' he +said in a hoarse, feeble voice: `I heard every word you fellows +were saying.' + + `Tell us a story!' said the March Hare. + + `Yes, please do!' pleaded Alice. + + `And be quick about it,' added the Hatter, `or you'll be asleep +again before it's done.' + + `Once upon a time there were three little sisters,' the +Dormouse began in a great hurry; `and their names were Elsie, +Lacie, and Tillie; and they lived at the bottom of a well--' + + `What did they live on?' said Alice, who always took a great +interest in questions of eating and drinking. + + `They lived on treacle,' said the Dormouse, after thinking a +minute or two. + + `They couldn't have done that, you know,' Alice gently +remarked; `they'd have been ill.' + + `So they were,' said the Dormouse; `VERY ill.' + + Alice tried to fancy to herself what such an extraordinary ways +of living would be like, but it puzzled her too much, so she went +on: `But why did they live at the bottom of a well?' + + `Take some more tea,' the March Hare said to Alice, very +earnestly. + + `I've had nothing yet,' Alice replied in an offended tone, `so +I can't take more.' + + `You mean you can't take LESS,' said the Hatter: `it's very +easy to take MORE than nothing.' + + `Nobody asked YOUR opinion,' said Alice. + + `Who's making personal remarks now?' the Hatter asked +triumphantly. + + Alice did not quite know what to say to this: so she helped +herself to some tea and bread-and-butter, and then turned to the +Dormouse, and repeated her question. `Why did they live at the +bottom of a well?' + + The Dormouse again took a minute or two to think about it, and +then said, `It was a treacle-well.' + + `There's no such thing!' Alice was beginning very angrily, but +the Hatter and the March Hare went `Sh! sh!' and the Dormouse +sulkily remarked, `If you can't be civil, you'd better finish the +story for yourself.' + + `No, please go on!' Alice said very humbly; `I won't interrupt +again. I dare say there may be ONE.' + + `One, indeed!' said the Dormouse indignantly. However, he +consented to go on. `And so these three little sisters--they +were learning to draw, you know--' + + `What did they draw?' said Alice, quite forgetting her promise. + + `Treacle,' said the Dormouse, without considering at all this +time. + + `I want a clean cup,' interrupted the Hatter: `let's all move +one place on.' + + He moved on as he spoke, and the Dormouse followed him: the +March Hare moved into the Dormouse's place, and Alice rather +unwillingly took the place of the March Hare. The Hatter was the +only one who got any advantage from the change: and Alice was a +good deal worse off than before, as the March Hare had just upset +the milk-jug into his plate. + + Alice did not wish to offend the Dormouse again, so she began +very cautiously: `But I don't understand. Where did they draw +the treacle from?' + + `You can draw water out of a water-well,' said the Hatter; `so +I should think you could draw treacle out of a treacle-well--eh, +stupid?' + + `But they were IN the well,' Alice said to the Dormouse, not +choosing to notice this last remark. + + `Of course they were', said the Dormouse; `--well in.' + + This answer so confused poor Alice, that she let the Dormouse +go on for some time without interrupting it. + + `They were learning to draw,' the Dormouse went on, yawning and +rubbing its eyes, for it was getting very sleepy; `and they drew +all manner of things--everything that begins with an M--' + + `Why with an M?' said Alice. + + `Why not?' said the March Hare. + + Alice was silent. + + The Dormouse had closed its eyes by this time, and was going +off into a doze; but, on being pinched by the Hatter, it woke up +again with a little shriek, and went on: `--that begins with an +M, such as mouse-traps, and the moon, and memory, and muchness-- +you know you say things are "much of a muchness"--did you ever +see such a thing as a drawing of a muchness?' + + `Really, now you ask me,' said Alice, very much confused, `I +don't think--' + + `Then you shouldn't talk,' said the Hatter. + + This piece of rudeness was more than Alice could bear: she got +up in great disgust, and walked off; the Dormouse fell asleep +instantly, and neither of the others took the least notice of her +going, though she looked back once or twice, half hoping that +they would call after her: the last time she saw them, they were +trying to put the Dormouse into the teapot. + + `At any rate I'll never go THERE again!' said Alice as she +picked her way through the wood. `It's the stupidest tea-party I +ever was at in all my life!' + + Just as she said this, she noticed that one of the trees had a +door leading right into it. `That's very curious!' she thought. +`But everything's curious today. I think I may as well go in at +once.' And in she went. + + Once more she found herself in the long hall, and close to the +little glass table. `Now, I'll manage better this time,' she +said to herself, and began by taking the little golden key, and +unlocking the door that led into the garden. Then she went to +work nibbling at the mushroom (she had kept a piece of it in her +pocked) till she was about a foot high: then she walked down the +little passage: and THEN--she found herself at last in the +beautiful garden, among the bright flower-beds and the cool +fountains. + + + + CHAPTER VIII + + The Queen's Croquet-Ground + + + A large rose-tree stood near the entrance of the garden: the +roses growing on it were white, but there were three gardeners at +it, busily painting them red. Alice thought this a very curious +thing, and she went nearer to watch them, and just as she came up +to them she heard one of them say, `Look out now, Five! Don't go +splashing paint over me like that!' + + `I couldn't help it,' said Five, in a sulky tone; `Seven jogged +my elbow.' + + On which Seven looked up and said, `That's right, Five! Always +lay the blame on others!' + + `YOU'D better not talk!' said Five. `I heard the Queen say only +yesterday you deserved to be beheaded!' + + `What for?' said the one who had spoken first. + + `That's none of YOUR business, Two!' said Seven. + + `Yes, it IS his business!' said Five, `and I'll tell him--it +was for bringing the cook tulip-roots instead of onions.' + + Seven flung down his brush, and had just begun `Well, of all +the unjust things--' when his eye chanced to fall upon Alice, as +she stood watching them, and he checked himself suddenly: the +others looked round also, and all of them bowed low. + + `Would you tell me,' said Alice, a little timidly, `why you are +painting those roses?' + + Five and Seven said nothing, but looked at Two. Two began in a +low voice, `Why the fact is, you see, Miss, this here ought to +have been a RED rose-tree, and we put a white one in by mistake; +and if the Queen was to find it out, we should all have our heads +cut off, you know. So you see, Miss, we're doing our best, afore +she comes, to--' At this moment Five, who had been anxiously +looking across the garden, called out `The Queen! The Queen!' +and the three gardeners instantly threw themselves flat upon +their faces. There was a sound of many footsteps, and Alice +looked round, eager to see the Queen. + + First came ten soldiers carrying clubs; these were all shaped +like the three gardeners, oblong and flat, with their hands and +feet at the corners: next the ten courtiers; these were +ornamented all over with diamonds, and walked two and two, as the +soldiers did. After these came the royal children; there were +ten of them, and the little dears came jumping merrily along hand +in hand, in couples: they were all ornamented with hearts. Next +came the guests, mostly Kings and Queens, and among them Alice +recognised the White Rabbit: it was talking in a hurried nervous +manner, smiling at everything that was said, and went by without +noticing her. Then followed the Knave of Hearts, carrying the +King's crown on a crimson velvet cushion; and, last of all this +grand procession, came THE KING AND QUEEN OF HEARTS. + + Alice was rather doubtful whether she ought not to lie down on +her face like the three gardeners, but she could not remember +every having heard of such a rule at processions; `and besides, +what would be the use of a procession,' thought she, `if people +had all to lie down upon their faces, so that they couldn't see +it?' So she stood still where she was, and waited. + + When the procession came opposite to Alice, they all stopped +and looked at her, and the Queen said severely `Who is this?' +She said it to the Knave of Hearts, who only bowed and smiled in +reply. + + `Idiot!' said the Queen, tossing her head impatiently; and, +turning to Alice, she went on, `What's your name, child?' + + `My name is Alice, so please your Majesty,' said Alice very +politely; but she added, to herself, `Why, they're only a pack of +cards, after all. I needn't be afraid of them!' + + `And who are THESE?' said the Queen, pointing to the three +gardeners who were lying round the rosetree; for, you see, as +they were lying on their faces, and the pattern on their backs +was the same as the rest of the pack, she could not tell whether +they were gardeners, or soldiers, or courtiers, or three of her +own children. + + `How should I know?' said Alice, surprised at her own courage. +`It's no business of MINE.' + + The Queen turned crimson with fury, and, after glaring at her +for a moment like a wild beast, screamed `Off with her head! +Off--' + + `Nonsense!' said Alice, very loudly and decidedly, and the +Queen was silent. + + The King laid his hand upon her arm, and timidly said +`Consider, my dear: she is only a child!' + + The Queen turned angrily away from him, and said to the Knave +`Turn them over!' + + The Knave did so, very carefully, with one foot. + + `Get up!' said the Queen, in a shrill, loud voice, and the +three gardeners instantly jumped up, and began bowing to the +King, the Queen, the royal children, and everybody else. + + `Leave off that!' screamed the Queen. `You make me giddy.' +And then, turning to the rose-tree, she went on, `What HAVE you +been doing here?' + + `May it please your Majesty,' said Two, in a very humble tone, +going down on one knee as he spoke, `we were trying--' + + `I see!' said the Queen, who had meanwhile been examining the +roses. `Off with their heads!' and the procession moved on, +three of the soldiers remaining behind to execute the unfortunate +gardeners, who ran to Alice for protection. + + `You shan't be beheaded!' said Alice, and she put them into a +large flower-pot that stood near. The three soldiers wandered +about for a minute or two, looking for them, and then quietly +marched off after the others. + + `Are their heads off?' shouted the Queen. + + `Their heads are gone, if it please your Majesty!' the soldiers +shouted in reply. + + `That's right!' shouted the Queen. `Can you play croquet?' + + The soldiers were silent, and looked at Alice, as the question +was evidently meant for her. + + `Yes!' shouted Alice. + + `Come on, then!' roared the Queen, and Alice joined the +procession, wondering very much what would happen next. + + `It's--it's a very fine day!' said a timid voice at her side. +She was walking by the White Rabbit, who was peeping anxiously +into her face. + + `Very,' said Alice: `--where's the Duchess?' + + `Hush! Hush!' said the Rabbit in a low, hurried tone. He +looked anxiously over his shoulder as he spoke, and then raised +himself upon tiptoe, put his mouth close to her ear, and +whispered `She's under sentence of execution.' + + `What for?' said Alice. + + `Did you say "What a pity!"?' the Rabbit asked. + + `No, I didn't,' said Alice: `I don't think it's at all a pity. +I said "What for?"' + + `She boxed the Queen's ears--' the Rabbit began. Alice gave a +little scream of laughter. `Oh, hush!' the Rabbit whispered in a +frightened tone. `The Queen will hear you! You see, she came +rather late, and the Queen said--' + + `Get to your places!' shouted the Queen in a voice of thunder, +and people began running about in all directions, tumbling up +against each other; however, they got settled down in a minute or +two, and the game began. Alice thought she had never seen such a +curious croquet-ground in her life; it was all ridges and +furrows; the balls were live hedgehogs, the mallets live +flamingoes, and the soldiers had to double themselves up and to +stand on their hands and feet, to make the arches. + + The chief difficulty Alice found at first was in managing her +flamingo: she succeeded in getting its body tucked away, +comfortably enough, under her arm, with its legs hanging down, +but generally, just as she had got its neck nicely straightened +out, and was going to give the hedgehog a blow with its head, it +WOULD twist itself round and look up in her face, with such a +puzzled expression that she could not help bursting out laughing: +and when she had got its head down, and was going to begin again, +it was very provoking to find that the hedgehog had unrolled +itself, and was in the act of crawling away: besides all this, +there was generally a ridge or furrow in the way wherever she +wanted to send the hedgehog to, and, as the doubled-up soldiers +were always getting up and walking off to other parts of the +ground, Alice soon came to the conclusion that it was a very +difficult game indeed. + + The players all played at once without waiting for turns, +quarrelling all the while, and fighting for the hedgehogs; and in +a very short time the Queen was in a furious passion, and went +stamping about, and shouting `Off with his head!' or `Off with +her head!' about once in a minute. + + Alice began to feel very uneasy: to be sure, she had not as +yet had any dispute with the Queen, but she knew that it might +happen any minute, `and then,' thought she, `what would become of +me? They're dreadfully fond of beheading people here; the great +wonder is, that there's any one left alive!' + + She was looking about for some way of escape, and wondering +whether she could get away without being seen, when she noticed a +curious appearance in the air: it puzzled her very much at +first, but, after watching it a minute or two, she made it out to +be a grin, and she said to herself `It's the Cheshire Cat: now I +shall have somebody to talk to.' + + `How are you getting on?' said the Cat, as soon as there was +mouth enough for it to speak with. + + Alice waited till the eyes appeared, and then nodded. `It's no +use speaking to it,' she thought, `till its ears have come, or at +least one of them.' In another minute the whole head appeared, +and then Alice put down her flamingo, and began an account of the +game, feeling very glad she had someone to listen to her. The +Cat seemed to think that there was enough of it now in sight, and +no more of it appeared. + + `I don't think they play at all fairly,' Alice began, in rather +a complaining tone, `and they all quarrel so dreadfully one can't +hear oneself speak--and they don't seem to have any rules in +particular; at least, if there are, nobody attends to them--and +you've no idea how confusing it is all the things being alive; +for instance, there's the arch I've got to go through next +walking about at the other end of the ground--and I should have +croqueted the Queen's hedgehog just now, only it ran away when it +saw mine coming!' + + `How do you like the Queen?' said the Cat in a low voice. + + `Not at all,' said Alice: `she's so extremely--' Just then +she noticed that the Queen was close behind her, listening: so +she went on, `--likely to win, that it's hardly worth while +finishing the game.' + + The Queen smiled and passed on. + + `Who ARE you talking to?' said the King, going up to Alice, and +looking at the Cat's head with great curiosity. + + `It's a friend of mine--a Cheshire Cat,' said Alice: `allow me +to introduce it.' + + `I don't like the look of it at all,' said the King: `however, +it may kiss my hand if it likes.' + + `I'd rather not,' the Cat remarked. + + `Don't be impertinent,' said the King, `and don't look at me +like that!' He got behind Alice as he spoke. + + `A cat may look at a king,' said Alice. `I've read that in +some book, but I don't remember where.' + + `Well, it must be removed,' said the King very decidedly, and +he called the Queen, who was passing at the moment, `My dear! I +wish you would have this cat removed!' + + The Queen had only one way of settling all difficulties, great +or small. `Off with his head!' she said, without even looking +round. + + `I'll fetch the executioner myself,' said the King eagerly, and +he hurried off. + + Alice thought she might as well go back, and see how the game +was going on, as she heard the Queen's voice in the distance, +screaming with passion. She had already heard her sentence three +of the players to be executed for having missed their turns, and +she did not like the look of things at all, as the game was in +such confusion that she never knew whether it was her turn or +not. So she went in search of her hedgehog. + + The hedgehog was engaged in a fight with another hedgehog, +which seemed to Alice an excellent opportunity for croqueting one +of them with the other: the only difficulty was, that her +flamingo was gone across to the other side of the garden, where +Alice could see it trying in a helpless sort of way to fly up +into a tree. + + By the time she had caught the flamingo and brought it back, +the fight was over, and both the hedgehogs were out of sight: +`but it doesn't matter much,' thought Alice, `as all the arches +are gone from this side of the ground.' So she tucked it away +under her arm, that it might not escape again, and went back for +a little more conversation with her friend. + + When she got back to the Cheshire Cat, she was surprised to +find quite a large crowd collected round it: there was a dispute +going on between the executioner, the King, and the Queen, who +were all talking at once, while all the rest were quite silent, +and looked very uncomfortable. + + The moment Alice appeared, she was appealed to by all three to +settle the question, and they repeated their arguments to her, +though, as they all spoke at once, she found it very hard indeed +to make out exactly what they said. + + The executioner's argument was, that you couldn't cut off a +head unless there was a body to cut it off from: that he had +never had to do such a thing before, and he wasn't going to begin +at HIS time of life. + + The King's argument was, that anything that had a head could be +beheaded, and that you weren't to talk nonsense. + + The Queen's argument was, that if something wasn't done about +it in less than no time she'd have everybody executed, all round. +(It was this last remark that had made the whole party look so +grave and anxious.) + + Alice could think of nothing else to say but `It belongs to the +Duchess: you'd better ask HER about it.' + + `She's in prison,' the Queen said to the executioner: `fetch +her here.' And the executioner went off like an arrow. + + The Cat's head began fading away the moment he was gone, and, +by the time he had come back with the Dutchess, it had entirely +disappeared; so the King and the executioner ran wildly up and +down looking for it, while the rest of the party went back to the game. + + + + CHAPTER IX + + The Mock Turtle's Story + + + `You can't think how glad I am to see you again, you dear old +thing!' said the Duchess, as she tucked her arm affectionately +into Alice's, and they walked off together. + + Alice was very glad to find her in such a pleasant temper, and +thought to herself that perhaps it was only the pepper that had +made her so savage when they met in the kitchen. + + `When I'M a Duchess,' she said to herself, (not in a very +hopeful tone though), `I won't have any pepper in my kitchen AT +ALL. Soup does very well without--Maybe it's always pepper that +makes people hot-tempered,' she went on, very much pleased at +having found out a new kind of rule, `and vinegar that makes them +sour--and camomile that makes them bitter--and--and barley-sugar +and such things that make children sweet-tempered. I only wish +people knew that: then they wouldn't be so stingy about it, you +know--' + + She had quite forgotten the Duchess by this time, and was a +little startled when she heard her voice close to her ear. +`You're thinking about something, my dear, and that makes you +forget to talk. I can't tell you just now what the moral of that +is, but I shall remember it in a bit.' + + `Perhaps it hasn't one,' Alice ventured to remark. + + `Tut, tut, child!' said the Duchess. `Everything's got a +moral, if only you can find it.' And she squeezed herself up +closer to Alice's side as she spoke. + + Alice did not much like keeping so close to her: first, +because the Duchess was VERY ugly; and secondly, because she was +exactly the right height to rest her chin upon Alice's shoulder, +and it was an uncomfortably sharp chin. However, she did not +like to be rude, so she bore it as well as she could. + + `The game's going on rather better now,' she said, by way of +keeping up the conversation a little. + + `'Tis so,' said the Duchess: `and the moral of that is--"Oh, +'tis love, 'tis love, that makes the world go round!"' + + `Somebody said,' Alice whispered, `that it's done by everybody +minding their own business!' + + `Ah, well! It means much the same thing,' said the Duchess, +digging her sharp little chin into Alice's shoulder as she added, +`and the moral of THAT is--"Take care of the sense, and the +sounds will take care of themselves."' + + `How fond she is of finding morals in things!' Alice thought to +herself. + + `I dare say you're wondering why I don't put my arm round your +waist,' the Duchess said after a pause: `the reason is, that I'm +doubtful about the temper of your flamingo. Shall I try the +experiment?' + + `HE might bite,' Alice cautiously replied, not feeling at all +anxious to have the experiment tried. + + `Very true,' said the Duchess: `flamingoes and mustard both +bite. And the moral of that is--"Birds of a feather flock +together."' + + `Only mustard isn't a bird,' Alice remarked. + + `Right, as usual,' said the Duchess: `what a clear way you +have of putting things!' + + `It's a mineral, I THINK,' said Alice. + + `Of course it is,' said the Duchess, who seemed ready to agree +to everything that Alice said; `there's a large mustard-mine near +here. And the moral of that is--"The more there is of mine, the +less there is of yours."' + + `Oh, I know!' exclaimed Alice, who had not attended to this +last remark, `it's a vegetable. It doesn't look like one, but it +is.' + + `I quite agree with you,' said the Duchess; `and the moral of +that is--"Be what you would seem to be"--or if you'd like it put +more simply--"Never imagine yourself not to be otherwise than +what it might appear to others that what you were or might have +been was not otherwise than what you had been would have appeared +to them to be otherwise."' + + `I think I should understand that better,' Alice said very +politely, `if I had it written down: but I can't quite follow it +as you say it.' + + `That's nothing to what I could say if I chose,' the Duchess +replied, in a pleased tone. + + `Pray don't trouble yourself to say it any longer than that,' +said Alice. + + `Oh, don't talk about trouble!' said the Duchess. `I make you +a present of everything I've said as yet.' + + `A cheap sort of present!' thought Alice. `I'm glad they don't +give birthday presents like that!' But she did not venture to +say it out loud. + + `Thinking again?' the Duchess asked, with another dig of her +sharp little chin. + + `I've a right to think,' said Alice sharply, for she was +beginning to feel a little worried. + + `Just about as much right,' said the Duchess, `as pigs have to +fly; and the m--' + + But here, to Alice's great surprise, the Duchess's voice died +away, even in the middle of her favourite word `moral,' and the +arm that was linked into hers began to tremble. Alice looked up, +and there stood the Queen in front of them, with her arms folded, +frowning like a thunderstorm. + + `A fine day, your Majesty!' the Duchess began in a low, weak +voice. + + `Now, I give you fair warning,' shouted the Queen, stamping on +the ground as she spoke; `either you or your head must be off, +and that in about half no time! Take your choice!' + + The Duchess took her choice, and was gone in a moment. + + `Let's go on with the game,' the Queen said to Alice; and Alice +was too much frightened to say a word, but slowly followed her +back to the croquet-ground. + + The other guests had taken advantage of the Queen's absence, +and were resting in the shade: however, the moment they saw her, +they hurried back to the game, the Queen merely remarking that a +moment's delay would cost them their lives. + + All the time they were playing the Queen never left off +quarrelling with the other players, and shouting `Off with his +head!' or `Off with her head!' Those whom she sentenced were +taken into custody by the soldiers, who of course had to leave +off being arches to do this, so that by the end of half an hour +or so there were no arches left, and all the players, except the +King, the Queen, and Alice, were in custody and under sentence of +execution. + + Then the Queen left off, quite out of breath, and said to +Alice, `Have you seen the Mock Turtle yet?' + + `No,' said Alice. `I don't even know what a Mock Turtle is.' + + `It's the thing Mock Turtle Soup is made from,' said the Queen. + + `I never saw one, or heard of one,' said Alice. + + `Come on, then,' said the Queen, `and he shall tell you his +history,' + + As they walked off together, Alice heard the King say in a low +voice, to the company generally, `You are all pardoned.' `Come, +THAT'S a good thing!' she said to herself, for she had felt quite +unhappy at the number of executions the Queen had ordered. + + They very soon came upon a Gryphon, lying fast asleep in the +sun. (IF you don't know what a Gryphon is, look at the picture.) +`Up, lazy thing!' said the Queen, `and take this young lady to +see the Mock Turtle, and to hear his history. I must go back and +see after some executions I have ordered'; and she walked off, +leaving Alice alone with the Gryphon. Alice did not quite like +the look of the creature, but on the whole she thought it would +be quite as safe to stay with it as to go after that savage +Queen: so she waited. + + The Gryphon sat up and rubbed its eyes: then it watched the +Queen till she was out of sight: then it chuckled. `What fun!' +said the Gryphon, half to itself, half to Alice. + + `What IS the fun?' said Alice. + + `Why, SHE,' said the Gryphon. `It's all her fancy, that: they +never executes nobody, you know. Come on!' + + `Everybody says "come on!" here,' thought Alice, as she went +slowly after it: `I never was so ordered about in all my life, +never!' + + They had not gone far before they saw the Mock Turtle in the +distance, sitting sad and lonely on a little ledge of rock, and, +as they came nearer, Alice could hear him sighing as if his heart +would break. She pitied him deeply. `What is his sorrow?' she +asked the Gryphon, and the Gryphon answered, very nearly in the +same words as before, `It's all his fancy, that: he hasn't got +no sorrow, you know. Come on!' + + So they went up to the Mock Turtle, who looked at them with +large eyes full of tears, but said nothing. + + `This here young lady,' said the Gryphon, `she wants for to +know your history, she do.' + + `I'll tell it her,' said the Mock Turtle in a deep, hollow +tone: `sit down, both of you, and don't speak a word till I've +finished.' + + So they sat down, and nobody spoke for some minutes. Alice +thought to herself, `I don't see how he can EVEN finish, if he +doesn't begin.' But she waited patiently. + + `Once,' said the Mock Turtle at last, with a deep sigh, `I was +a real Turtle.' + + These words were followed by a very long silence, broken only +by an occasional exclamation of `Hjckrrh!' from the Gryphon, and +the constant heavy sobbing of the Mock Turtle. Alice was very +nearly getting up and saying, `Thank you, sir, for your +interesting story,' but she could not help thinking there MUST be +more to come, so she sat still and said nothing. + + `When we were little,' the Mock Turtle went on at last, more +calmly, though still sobbing a little now and then, `we went to +school in the sea. The master was an old Turtle--we used to call +him Tortoise--' + + `Why did you call him Tortoise, if he wasn't one?' Alice asked. + + `We called him Tortoise because he taught us,' said the Mock +Turtle angrily: `really you are very dull!' + + `You ought to be ashamed of yourself for asking such a simple +question,' added the Gryphon; and then they both sat silent and +looked at poor Alice, who felt ready to sink into the earth. At +last the Gryphon said to the Mock Turtle, `Drive on, old fellow! +Don't be all day about it!' and he went on in these words: + + `Yes, we went to school in the sea, though you mayn't believe +it--' + + `I never said I didn't!' interrupted Alice. + + `You did,' said the Mock Turtle. + + `Hold your tongue!' added the Gryphon, before Alice could speak +again. The Mock Turtle went on. + + `We had the best of educations--in fact, we went to school +every day--' + + `I'VE been to a day-school, too,' said Alice; `you needn't be +so proud as all that.' + + `With extras?' asked the Mock Turtle a little anxiously. + + `Yes,' said Alice, `we learned French and music.' + + `And washing?' said the Mock Turtle. + + `Certainly not!' said Alice indignantly. + + `Ah! then yours wasn't a really good school,' said the Mock +Turtle in a tone of great relief. `Now at OURS they had at the +end of the bill, "French, music, AND WASHING--extra."' + + `You couldn't have wanted it much,' said Alice; `living at the +bottom of the sea.' + + `I couldn't afford to learn it.' said the Mock Turtle with a +sigh. `I only took the regular course.' + + `What was that?' inquired Alice. + + `Reeling and Writhing, of course, to begin with,' the Mock +Turtle replied; `and then the different branches of Arithmetic-- +Ambition, Distraction, Uglification, and Derision.' + + `I never heard of "Uglification,"' Alice ventured to say. `What +is it?' + + The Gryphon lifted up both its paws in surprise. `What! Never +heard of uglifying!' it exclaimed. `You know what to beautify +is, I suppose?' + + `Yes,' said Alice doubtfully: `it means--to--make--anything-- +prettier.' + + `Well, then,' the Gryphon went on, `if you don't know what to +uglify is, you ARE a simpleton.' + + Alice did not feel encouraged to ask any more questions about +it, so she turned to the Mock Turtle, and said `What else had you +to learn?' + + `Well, there was Mystery,' the Mock Turtle replied, counting +off the subjects on his flappers, `--Mystery, ancient and modern, +with Seaography: then Drawling--the Drawling-master was an old +conger-eel, that used to come once a week: HE taught us +Drawling, Stretching, and Fainting in Coils.' + + `What was THAT like?' said Alice. + + `Well, I can't show it you myself,' the Mock Turtle said: `I'm +too stiff. And the Gryphon never learnt it.' + + `Hadn't time,' said the Gryphon: `I went to the Classics +master, though. He was an old crab, HE was.' + + `I never went to him,' the Mock Turtle said with a sigh: `he +taught Laughing and Grief, they used to say.' + + `So he did, so he did,' said the Gryphon, sighing in his turn; +and both creatures hid their faces in their paws. + + `And how many hours a day did you do lessons?' said Alice, in a +hurry to change the subject. + + `Ten hours the first day,' said the Mock Turtle: `nine the +next, and so on.' + + `What a curious plan!' exclaimed Alice. + + `That's the reason they're called lessons,' the Gryphon +remarked: `because they lessen from day to day.' + + This was quite a new idea to Alice, and she thought it over a +little before she made her next remark. `Then the eleventh day +must have been a holiday?' + + `Of course it was,' said the Mock Turtle. + + `And how did you manage on the twelfth?' Alice went on eagerly. + + `That's enough about lessons,' the Gryphon interrupted in a +very decided tone: `tell her something about the games now.' + + + + CHAPTER X + + The Lobster Quadrille + + + The Mock Turtle sighed deeply, and drew the back of one flapper +across his eyes. He looked at Alice, and tried to speak, but for +a minute or two sobs choked his voice. `Same as if he had a bone +in his throat,' said the Gryphon: and it set to work shaking him +and punching him in the back. At last the Mock Turtle recovered +his voice, and, with tears running down his cheeks, he went on +again:-- + + `You may not have lived much under the sea--' (`I haven't,' +said Alice)--`and perhaps you were never even introduced to a lobster--' +(Alice began to say `I once tasted--' but checked herself hastily, +and said `No, never') `--so you can have no idea what a delightful +thing a Lobster Quadrille is!' + + `No, indeed,' said Alice. `What sort of a dance is it?' + + `Why,' said the Gryphon, `you first form into a line along the +sea-shore--' + + `Two lines!' cried the Mock Turtle. `Seals, turtles, salmon, +and so on; then, when you've cleared all the jelly-fish out of +the way--' + + `THAT generally takes some time,' interrupted the Gryphon. + + `--you advance twice--' + + `Each with a lobster as a partner!' cried the Gryphon. + + `Of course,' the Mock Turtle said: `advance twice, set to +partners--' + + `--change lobsters, and retire in same order,' continued the +Gryphon. + + `Then, you know,' the Mock Turtle went on, `you throw the--' + + `The lobsters!' shouted the Gryphon, with a bound into the air. + + `--as far out to sea as you can--' + + `Swim after them!' screamed the Gryphon. + + `Turn a somersault in the sea!' cried the Mock Turtle, +capering wildly about. + + `Back to land again, and that's all the first figure,' said the +Mock Turtle, suddenly dropping his voice; and the two creatures, +who had been jumping about like mad things all this time, sat +down again very sadly and quietly, and looked at Alice. + + `It must be a very pretty dance,' said Alice timidly. + + `Would you like to see a little of it?' said the Mock Turtle. + + `Very much indeed,' said Alice. + + `Come, let's try the first figure!' said the Mock Turtle to the +Gryphon. `We can do without lobsters, you know. Which shall +sing?' + + `Oh, YOU sing,' said the Gryphon. `I've forgotten the words.' + + So they began solemnly dancing round and round Alice, every now +and then treading on her toes when they passed too close, and +waving their forepaws to mark the time, while the Mock Turtle +sang this, very slowly and sadly:-- + + +`"Will you walk a little faster?" said a whiting to a snail. +"There's a porpoise close behind us, and he's treading on my + tail. +See how eagerly the lobsters and the turtles all advance! +They are waiting on the shingle--will you come and join the +dance? + +Will you, won't you, will you, won't you, will you join the +dance? +Will you, won't you, will you, won't you, won't you join the +dance? + + +"You can really have no notion how delightful it will be +When they take us up and throw us, with the lobsters, out to + sea!" +But the snail replied "Too far, too far!" and gave a look + askance-- +Said he thanked the whiting kindly, but he would not join the + dance. + Would not, could not, would not, could not, would not join + the dance. + Would not, could not, would not, could not, could not join + the dance. + +`"What matters it how far we go?" his scaly friend replied. +"There is another shore, you know, upon the other side. +The further off from England the nearer is to France-- +Then turn not pale, beloved snail, but come and join the dance. + + Will you, won't you, will you, won't you, will you join the + dance? + Will you, won't you, will you, won't you, won't you join the + dance?"' + + + + `Thank you, it's a very interesting dance to watch,' said +Alice, feeling very glad that it was over at last: `and I do so +like that curious song about the whiting!' + + `Oh, as to the whiting,' said the Mock Turtle, `they--you've +seen them, of course?' + + `Yes,' said Alice, `I've often seen them at dinn--' she +checked herself hastily. + + `I don't know where Dinn may be,' said the Mock Turtle, `but +if you've seen them so often, of course you know what they're +like.' + + `I believe so,' Alice replied thoughtfully. `They have their +tails in their mouths--and they're all over crumbs.' + + `You're wrong about the crumbs,' said the Mock Turtle: +`crumbs would all wash off in the sea. But they HAVE their tails +in their mouths; and the reason is--' here the Mock Turtle +yawned and shut his eyes.--`Tell her about the reason and all +that,' he said to the Gryphon. + + `The reason is,' said the Gryphon, `that they WOULD go with +the lobsters to the dance. So they got thrown out to sea. So +they had to fall a long way. So they got their tails fast in +their mouths. So they couldn't get them out again. That's all.' + + `Thank you,' said Alice, `it's very interesting. I never knew +so much about a whiting before.' + + `I can tell you more than that, if you like,' said the +Gryphon. `Do you know why it's called a whiting?' + + `I never thought about it,' said Alice. `Why?' + + `IT DOES THE BOOTS AND SHOES.' the Gryphon replied very +solemnly. + + Alice was thoroughly puzzled. `Does the boots and shoes!' she +repeated in a wondering tone. + + `Why, what are YOUR shoes done with?' said the Gryphon. `I +mean, what makes them so shiny?' + + Alice looked down at them, and considered a little before she +gave her answer. `They're done with blacking, I believe.' + + `Boots and shoes under the sea,' the Gryphon went on in a deep +voice, `are done with a whiting. Now you know.' + + `And what are they made of?' Alice asked in a tone of great +curiosity. + + `Soles and eels, of course,' the Gryphon replied rather +impatiently: `any shrimp could have told you that.' + + `If I'd been the whiting,' said Alice, whose thoughts were +still running on the song, `I'd have said to the porpoise, "Keep +back, please: we don't want YOU with us!"' + + `They were obliged to have him with them,' the Mock Turtle +said: `no wise fish would go anywhere without a porpoise.' + + `Wouldn't it really?' said Alice in a tone of great surprise. + + `Of course not,' said the Mock Turtle: `why, if a fish came +to ME, and told me he was going a journey, I should say "With +what porpoise?"' + + `Don't you mean "purpose"?' said Alice. + + `I mean what I say,' the Mock Turtle replied in an offended +tone. And the Gryphon added `Come, let's hear some of YOUR +adventures.' + + `I could tell you my adventures--beginning from this morning,' +said Alice a little timidly: `but it's no use going back to +yesterday, because I was a different person then.' + + `Explain all that,' said the Mock Turtle. + + `No, no! The adventures first,' said the Gryphon in an +impatient tone: `explanations take such a dreadful time.' + + So Alice began telling them her adventures from the time when +she first saw the White Rabbit. She was a little nervous about +it just at first, the two creatures got so close to her, one on +each side, and opened their eyes and mouths so VERY wide, but she +gained courage as she went on. Her listeners were perfectly +quiet till she got to the part about her repeating `YOU ARE OLD, +FATHER WILLIAM,' to the Caterpillar, and the words all coming +different, and then the Mock Turtle drew a long breath, and said +`That's very curious.' + + `It's all about as curious as it can be,' said the Gryphon. + + `It all came different!' the Mock Turtle repeated +thoughtfully. `I should like to hear her try and repeat +something now. Tell her to begin.' He looked at the Gryphon as +if he thought it had some kind of authority over Alice. + + `Stand up and repeat "'TIS THE VOICE OF THE SLUGGARD,"' said +the Gryphon. + + `How the creatures order one about, and make one repeat +lessons!' thought Alice; `I might as well be at school at once.' +However, she got up, and began to repeat it, but her head was so +full of the Lobster Quadrille, that she hardly knew what she was +saying, and the words came very queer indeed:-- + + `'Tis the voice of the Lobster; I heard him declare, + "You have baked me too brown, I must sugar my hair." + As a duck with its eyelids, so he with his nose + Trims his belt and his buttons, and turns out his toes.' + + [later editions continued as follows + When the sands are all dry, he is gay as a lark, + And will talk in contemptuous tones of the Shark, + But, when the tide rises and sharks are around, + His voice has a timid and tremulous sound.] + + `That's different from what I used to say when I was a child,' +said the Gryphon. + + `Well, I never heard it before,' said the Mock Turtle; `but it +sounds uncommon nonsense.' + + Alice said nothing; she had sat down with her face in her +hands, wondering if anything would EVER happen in a natural way +again. + + `I should like to have it explained,' said the Mock Turtle. + + `She can't explain it,' said the Gryphon hastily. `Go on with +the next verse.' + + `But about his toes?' the Mock Turtle persisted. `How COULD +he turn them out with his nose, you know?' + + `It's the first position in dancing.' Alice said; but was +dreadfully puzzled by the whole thing, and longed to change the +subject. + + `Go on with the next verse,' the Gryphon repeated impatiently: +`it begins "I passed by his garden."' + + Alice did not dare to disobey, though she felt sure it would +all come wrong, and she went on in a trembling voice:-- + + `I passed by his garden, and marked, with one eye, + How the Owl and the Panther were sharing a pie--' + + [later editions continued as follows + The Panther took pie-crust, and gravy, and meat, + While the Owl had the dish as its share of the treat. + When the pie was all finished, the Owl, as a boon, + Was kindly permitted to pocket the spoon: + While the Panther received knife and fork with a growl, + And concluded the banquet--] + + `What IS the use of repeating all that stuff,' the Mock Turtle +interrupted, `if you don't explain it as you go on? It's by far +the most confusing thing I ever heard!' + + `Yes, I think you'd better leave off,' said the Gryphon: and +Alice was only too glad to do so. + + `Shall we try another figure of the Lobster Quadrille?' the +Gryphon went on. `Or would you like the Mock Turtle to sing you +a song?' + + `Oh, a song, please, if the Mock Turtle would be so kind,' +Alice replied, so eagerly that the Gryphon said, in a rather +offended tone, `Hm! No accounting for tastes! Sing her "Turtle +Soup," will you, old fellow?' + + The Mock Turtle sighed deeply, and began, in a voice sometimes +choked with sobs, to sing this:-- + + + `Beautiful Soup, so rich and green, + Waiting in a hot tureen! + Who for such dainties would not stoop? + Soup of the evening, beautiful Soup! + Soup of the evening, beautiful Soup! + Beau--ootiful Soo--oop! + Beau--ootiful Soo--oop! + Soo--oop of the e--e--evening, + Beautiful, beautiful Soup! + + `Beautiful Soup! Who cares for fish, + Game, or any other dish? + Who would not give all else for two p + ennyworth only of beautiful Soup? + Pennyworth only of beautiful Soup? + Beau--ootiful Soo--oop! + Beau--ootiful Soo--oop! + Soo--oop of the e--e--evening, + Beautiful, beauti--FUL SOUP!' + + `Chorus again!' cried the Gryphon, and the Mock Turtle had +just begun to repeat it, when a cry of `The trial's beginning!' +was heard in the distance. + + `Come on!' cried the Gryphon, and, taking Alice by the hand, +it hurried off, without waiting for the end of the song. + + `What trial is it?' Alice panted as she ran; but the Gryphon +only answered `Come on!' and ran the faster, while more and more +faintly came, carried on the breeze that followed them, the +melancholy words:-- + + `Soo--oop of the e--e--evening, + Beautiful, beautiful Soup!' + + + + CHAPTER XI + + Who Stole the Tarts? + + + The King and Queen of Hearts were seated on their throne when +they arrived, with a great crowd assembled about them--all sorts +of little birds and beasts, as well as the whole pack of cards: +the Knave was standing before them, in chains, with a soldier on +each side to guard him; and near the King was the White Rabbit, +with a trumpet in one hand, and a scroll of parchment in the +other. In the very middle of the court was a table, with a large +dish of tarts upon it: they looked so good, that it made Alice +quite hungry to look at them--`I wish they'd get the trial done,' +she thought, `and hand round the refreshments!' But there seemed +to be no chance of this, so she began looking at everything about +her, to pass away the time. + + Alice had never been in a court of justice before, but she had +read about them in books, and she was quite pleased to find that +she knew the name of nearly everything there. `That's the +judge,' she said to herself, `because of his great wig.' + + The judge, by the way, was the King; and as he wore his crown +over the wig, (look at the frontispiece if you want to see how he +did it,) he did not look at all comfortable, and it was certainly +not becoming. + + `And that's the jury-box,' thought Alice, `and those twelve +creatures,' (she was obliged to say `creatures,' you see, because +some of them were animals, and some were birds,) `I suppose they +are the jurors.' She said this last word two or three times over +to herself, being rather proud of it: for she thought, and +rightly too, that very few little girls of her age knew the +meaning of it at all. However, `jury-men' would have done just +as well. + + The twelve jurors were all writing very busily on slates. +`What are they doing?' Alice whispered to the Gryphon. `They +can't have anything to put down yet, before the trial's begun.' + + `They're putting down their names,' the Gryphon whispered in +reply, `for fear they should forget them before the end of the +trial.' + + `Stupid things!' Alice began in a loud, indignant voice, but +she stopped hastily, for the White Rabbit cried out, `Silence in +the court!' and the King put on his spectacles and looked +anxiously round, to make out who was talking. + + Alice could see, as well as if she were looking over their +shoulders, that all the jurors were writing down `stupid things!' +on their slates, and she could even make out that one of them +didn't know how to spell `stupid,' and that he had to ask his +neighbour to tell him. `A nice muddle their slates'll be in +before the trial's over!' thought Alice. + + One of the jurors had a pencil that squeaked. This of course, +Alice could not stand, and she went round the court and got +behind him, and very soon found an opportunity of taking it +away. She did it so quickly that the poor little juror (it was +Bill, the Lizard) could not make out at all what had become of +it; so, after hunting all about for it, he was obliged to write +with one finger for the rest of the day; and this was of very +little use, as it left no mark on the slate. + + `Herald, read the accusation!' said the King. + + On this the White Rabbit blew three blasts on the trumpet, and +then unrolled the parchment scroll, and read as follows:-- + + `The Queen of Hearts, she made some tarts, + All on a summer day: + The Knave of Hearts, he stole those tarts, + And took them quite away!' + + `Consider your verdict,' the King said to the jury. + + `Not yet, not yet!' the Rabbit hastily interrupted. `There's +a great deal to come before that!' + + `Call the first witness,' said the King; and the White Rabbit +blew three blasts on the trumpet, and called out, `First +witness!' + + The first witness was the Hatter. He came in with a teacup in +one hand and a piece of bread-and-butter in the other. `I beg +pardon, your Majesty,' he began, `for bringing these in: but I +hadn't quite finished my tea when I was sent for.' + + `You ought to have finished,' said the King. `When did you +begin?' + + The Hatter looked at the March Hare, who had followed him into +the court, arm-in-arm with the Dormouse. `Fourteenth of March, I +think it was,' he said. + + `Fifteenth,' said the March Hare. + + `Sixteenth,' added the Dormouse. + + `Write that down,' the King said to the jury, and the jury +eagerly wrote down all three dates on their slates, and then +added them up, and reduced the answer to shillings and pence. + + `Take off your hat,' the King said to the Hatter. + + `It isn't mine,' said the Hatter. + + `Stolen!' the King exclaimed, turning to the jury, who +instantly made a memorandum of the fact. + + `I keep them to sell,' the Hatter added as an explanation; +`I've none of my own. I'm a hatter.' + + Here the Queen put on her spectacles, and began staring at the +Hatter, who turned pale and fidgeted. + + `Give your evidence,' said the King; `and don't be nervous, or +I'll have you executed on the spot.' + + This did not seem to encourage the witness at all: he kept +shifting from one foot to the other, looking uneasily at the +Queen, and in his confusion he bit a large piece out of his +teacup instead of the bread-and-butter. + + Just at this moment Alice felt a very curious sensation, which +puzzled her a good deal until she made out what it was: she was +beginning to grow larger again, and she thought at first she +would get up and leave the court; but on second thoughts she +decided to remain where she was as long as there was room for +her. + + `I wish you wouldn't squeeze so.' said the Dormouse, who was +sitting next to her. `I can hardly breathe.' + + `I can't help it,' said Alice very meekly: `I'm growing.' + + `You've no right to grow here,' said the Dormouse. + + `Don't talk nonsense,' said Alice more boldly: `you know +you're growing too.' + + `Yes, but I grow at a reasonable pace,' said the Dormouse: +`not in that ridiculous fashion.' And he got up very sulkily +and crossed over to the other side of the court. + + All this time the Queen had never left off staring at the +Hatter, and, just as the Dormouse crossed the court, she said to +one of the officers of the court, `Bring me the list of the +singers in the last concert!' on which the wretched Hatter +trembled so, that he shook both his shoes off. + + `Give your evidence,' the King repeated angrily, `or I'll have +you executed, whether you're nervous or not.' + + `I'm a poor man, your Majesty,' the Hatter began, in a +trembling voice, `--and I hadn't begun my tea--not above a week +or so--and what with the bread-and-butter getting so thin--and +the twinkling of the tea--' + + `The twinkling of the what?' said the King. + + `It began with the tea,' the Hatter replied. + + `Of course twinkling begins with a T!' said the King sharply. +`Do you take me for a dunce? Go on!' + + `I'm a poor man,' the Hatter went on, `and most things +twinkled after that--only the March Hare said--' + + `I didn't!' the March Hare interrupted in a great hurry. + + `You did!' said the Hatter. + + `I deny it!' said the March Hare. + + `He denies it,' said the King: `leave out that part.' + + `Well, at any rate, the Dormouse said--' the Hatter went on, +looking anxiously round to see if he would deny it too: but the +Dormouse denied nothing, being fast asleep. + + `After that,' continued the Hatter, `I cut some more bread- +and-butter--' + + `But what did the Dormouse say?' one of the jury asked. + + `That I can't remember,' said the Hatter. + + `You MUST remember,' remarked the King, `or I'll have you +executed.' + + The miserable Hatter dropped his teacup and bread-and-butter, +and went down on one knee. `I'm a poor man, your Majesty,' he +began. + + `You're a very poor speaker,' said the King. + + Here one of the guinea-pigs cheered, and was immediately +suppressed by the officers of the court. (As that is rather a +hard word, I will just explain to you how it was done. They had +a large canvas bag, which tied up at the mouth with strings: +into this they slipped the guinea-pig, head first, and then sat +upon it.) + + `I'm glad I've seen that done,' thought Alice. `I've so often +read in the newspapers, at the end of trials, "There was some +attempts at applause, which was immediately suppressed by the +officers of the court," and I never understood what it meant +till now.' + + `If that's all you know about it, you may stand down,' +continued the King. + + `I can't go no lower,' said the Hatter: `I'm on the floor, as +it is.' + + `Then you may SIT down,' the King replied. + + Here the other guinea-pig cheered, and was suppressed. + + `Come, that finished the guinea-pigs!' thought Alice. `Now we +shall get on better.' + + `I'd rather finish my tea,' said the Hatter, with an anxious +look at the Queen, who was reading the list of singers. + + `You may go,' said the King, and the Hatter hurriedly left the +court, without even waiting to put his shoes on. + + `--and just take his head off outside,' the Queen added to one +of the officers: but the Hatter was out of sight before the +officer could get to the door. + + `Call the next witness!' said the King. + + The next witness was the Duchess's cook. She carried the +pepper-box in her hand, and Alice guessed who it was, even before +she got into the court, by the way the people near the door began +sneezing all at once. + + `Give your evidence,' said the King. + + `Shan't,' said the cook. + + The King looked anxiously at the White Rabbit, who said in a +low voice, `Your Majesty must cross-examine THIS witness.' + + `Well, if I must, I must,' the King said, with a melancholy +air, and, after folding his arms and frowning at the cook till +his eyes were nearly out of sight, he said in a deep voice, `What +are tarts made of?' + + `Pepper, mostly,' said the cook. + + `Treacle,' said a sleepy voice behind her. + + `Collar that Dormouse,' the Queen shrieked out. `Behead that +Dormouse! Turn that Dormouse out of court! Suppress him! Pinch +him! Off with his whiskers!' + + For some minutes the whole court was in confusion, getting the +Dormouse turned out, and, by the time they had settled down +again, the cook had disappeared. + + `Never mind!' said the King, with an air of great relief. +`Call the next witness.' And he added in an undertone to the +Queen, `Really, my dear, YOU must cross-examine the next witness. +It quite makes my forehead ache!' + + Alice watched the White Rabbit as he fumbled over the list, +feeling very curious to see what the next witness would be like, +`--for they haven't got much evidence YET,' she said to herself. +Imagine her surprise, when the White Rabbit read out, at the top +of his shrill little voice, the name `Alice!' + + + + CHAPTER XII + + Alice's Evidence + + + `Here!' cried Alice, quite forgetting in the flurry of the +moment how large she had grown in the last few minutes, and she +jumped up in such a hurry that she tipped over the jury-box with +the edge of her skirt, upsetting all the jurymen on to the heads +of the crowd below, and there they lay sprawling about, reminding +her very much of a globe of goldfish she had accidentally upset +the week before. + + `Oh, I BEG your pardon!' she exclaimed in a tone of great +dismay, and began picking them up again as quickly as she could, +for the accident of the goldfish kept running in her head, and +she had a vague sort of idea that they must be collected at once +and put back into the jury-box, or they would die. + + `The trial cannot proceed,' said the King in a very grave +voice, `until all the jurymen are back in their proper places-- +ALL,' he repeated with great emphasis, looking hard at Alice as +he said do. + + Alice looked at the jury-box, and saw that, in her haste, she +had put the Lizard in head downwards, and the poor little thing +was waving its tail about in a melancholy way, being quite unable +to move. She soon got it out again, and put it right; `not that +it signifies much,' she said to herself; `I should think it +would be QUITE as much use in the trial one way up as the other.' + + As soon as the jury had a little recovered from the shock of +being upset, and their slates and pencils had been found and +handed back to them, they set to work very diligently to write +out a history of the accident, all except the Lizard, who seemed +too much overcome to do anything but sit with its mouth open, +gazing up into the roof of the court. + + `What do you know about this business?' the King said to +Alice. + + `Nothing,' said Alice. + + `Nothing WHATEVER?' persisted the King. + + `Nothing whatever,' said Alice. + + `That's very important,' the King said, turning to the jury. +They were just beginning to write this down on their slates, when +the White Rabbit interrupted: `UNimportant, your Majesty means, +of course,' he said in a very respectful tone, but frowning and +making faces at him as he spoke. + + `UNimportant, of course, I meant,' the King hastily said, and +went on to himself in an undertone, `important--unimportant-- +unimportant--important--' as if he were trying which word +sounded best. + + Some of the jury wrote it down `important,' and some +`unimportant.' Alice could see this, as she was near enough to +look over their slates; `but it doesn't matter a bit,' she +thought to herself. + + At this moment the King, who had been for some time busily +writing in his note-book, cackled out `Silence!' and read out +from his book, `Rule Forty-two. ALL PERSONS MORE THAN A MILE +HIGH TO LEAVE THE COURT.' + + Everybody looked at Alice. + + `I'M not a mile high,' said Alice. + + `You are,' said the King. + + `Nearly two miles high,' added the Queen. + + `Well, I shan't go, at any rate,' said Alice: `besides, +that's not a regular rule: you invented it just now.' + + `It's the oldest rule in the book,' said the King. + + `Then it ought to be Number One,' said Alice. + + The King turned pale, and shut his note-book hastily. +`Consider your verdict,' he said to the jury, in a low, trembling +voice. + + `There's more evidence to come yet, please your Majesty,' said +the White Rabbit, jumping up in a great hurry; `this paper has +just been picked up.' + + `What's in it?' said the Queen. + + `I haven't opened it yet,' said the White Rabbit, `but it seems +to be a letter, written by the prisoner to--to somebody.' + + `It must have been that,' said the King, `unless it was +written to nobody, which isn't usual, you know.' + + `Who is it directed to?' said one of the jurymen. + + `It isn't directed at all,' said the White Rabbit; `in fact, +there's nothing written on the OUTSIDE.' He unfolded the paper +as he spoke, and added `It isn't a letter, after all: it's a set +of verses.' + + `Are they in the prisoner's handwriting?' asked another of +they jurymen. + + `No, they're not,' said the White Rabbit, `and that's the +queerest thing about it.' (The jury all looked puzzled.) + + `He must have imitated somebody else's hand,' said the King. +(The jury all brightened up again.) + + `Please your Majesty,' said the Knave, `I didn't write it, and +they can't prove I did: there's no name signed at the end.' + + `If you didn't sign it,' said the King, `that only makes the +matter worse. You MUST have meant some mischief, or else you'd +have signed your name like an honest man.' + + There was a general clapping of hands at this: it was the +first really clever thing the King had said that day. + + `That PROVES his guilt,' said the Queen. + + `It proves nothing of the sort!' said Alice. `Why, you don't +even know what they're about!' + + `Read them,' said the King. + + The White Rabbit put on his spectacles. `Where shall I begin, +please your Majesty?' he asked. + + `Begin at the beginning,' the King said gravely, `and go on +till you come to the end: then stop.' + + These were the verses the White Rabbit read:-- + + `They told me you had been to her, + And mentioned me to him: + She gave me a good character, + But said I could not swim. + + He sent them word I had not gone + (We know it to be true): + If she should push the matter on, + What would become of you? + + I gave her one, they gave him two, + You gave us three or more; + They all returned from him to you, + Though they were mine before. + + If I or she should chance to be + Involved in this affair, + He trusts to you to set them free, + Exactly as we were. + + My notion was that you had been + (Before she had this fit) + An obstacle that came between + Him, and ourselves, and it. + + Don't let him know she liked them best, + For this must ever be + A secret, kept from all the rest, + Between yourself and me.' + + `That's the most important piece of evidence we've heard yet,' +said the King, rubbing his hands; `so now let the jury--' + + `If any one of them can explain it,' said Alice, (she had +grown so large in the last few minutes that she wasn't a bit +afraid of interrupting him,) `I'll give him sixpence. _I_ don't +believe there's an atom of meaning in it.' + + The jury all wrote down on their slates, `SHE doesn't believe +there's an atom of meaning in it,' but none of them attempted to +explain the paper. + + `If there's no meaning in it,' said the King, `that saves a +world of trouble, you know, as we needn't try to find any. And +yet I don't know,' he went on, spreading out the verses on his +knee, and looking at them with one eye; `I seem to see some +meaning in them, after all. "--SAID I COULD NOT SWIM--" you +can't swim, can you?' he added, turning to the Knave. + + The Knave shook his head sadly. `Do I look like it?' he said. +(Which he certainly did NOT, being made entirely of cardboard.) + + `All right, so far,' said the King, and he went on muttering +over the verses to himself: `"WE KNOW IT TO BE TRUE--" that's +the jury, of course-- "I GAVE HER ONE, THEY GAVE HIM TWO--" why, +that must be what he did with the tarts, you know--' + + `But, it goes on "THEY ALL RETURNED FROM HIM TO YOU,"' said +Alice. + + `Why, there they are!' said the King triumphantly, pointing to +the tarts on the table. `Nothing can be clearer than THAT. +Then again--"BEFORE SHE HAD THIS FIT--" you never had fits, my +dear, I think?' he said to the Queen. + + `Never!' said the Queen furiously, throwing an inkstand at the +Lizard as she spoke. (The unfortunate little Bill had left off +writing on his slate with one finger, as he found it made no +mark; but he now hastily began again, using the ink, that was +trickling down his face, as long as it lasted.) + + `Then the words don't FIT you,' said the King, looking round +the court with a smile. There was a dead silence. + + `It's a pun!' the King added in an offended tone, and +everybody laughed, `Let the jury consider their verdict,' the +King said, for about the twentieth time that day. + + `No, no!' said the Queen. `Sentence first--verdict afterwards.' + + `Stuff and nonsense!' said Alice loudly. `The idea of having +the sentence first!' + + `Hold your tongue!' said the Queen, turning purple. + + `I won't!' said Alice. + + `Off with her head!' the Queen shouted at the top of her voice. +Nobody moved. + + `Who cares for you?' said Alice, (she had grown to her full +size by this time.) `You're nothing but a pack of cards!' + + At this the whole pack rose up into the air, and came flying +down upon her: she gave a little scream, half of fright and half +of anger, and tried to beat them off, and found herself lying on +the bank, with her head in the lap of her sister, who was gently +brushing away some dead leaves that had fluttered down from the +trees upon her face. + + `Wake up, Alice dear!' said her sister; `Why, what a long +sleep you've had!' + + `Oh, I've had such a curious dream!' said Alice, and she told +her sister, as well as she could remember them, all these strange +Adventures of hers that you have just been reading about; and +when she had finished, her sister kissed her, and said, `It WAS a +curious dream, dear, certainly: but now run in to your tea; it's +getting late.' So Alice got up and ran off, thinking while she +ran, as well she might, what a wonderful dream it had been. + + But her sister sat still just as she left her, leaning her +head on her hand, watching the setting sun, and thinking of +little Alice and all her wonderful Adventures, till she too began +dreaming after a fashion, and this was her dream:-- + + First, she dreamed of little Alice herself, and once again the +tiny hands were clasped upon her knee, and the bright eager eyes +were looking up into hers--she could hear the very tones of her +voice, and see that queer little toss of her head to keep back +the wandering hair that WOULD always get into her eyes--and +still as she listened, or seemed to listen, the whole place +around her became alive the strange creatures of her little +sister's dream. + + The long grass rustled at her feet as the White Rabbit hurried +by--the frightened Mouse splashed his way through the +neighbouring pool--she could hear the rattle of the teacups as +the March Hare and his friends shared their never-ending meal, +and the shrill voice of the Queen ordering off her unfortunate +guests to execution--once more the pig-baby was sneezing on the +Duchess's knee, while plates and dishes crashed around it--once +more the shriek of the Gryphon, the squeaking of the Lizard's +slate-pencil, and the choking of the suppressed guinea-pigs, +filled the air, mixed up with the distant sobs of the miserable +Mock Turtle. + + So she sat on, with closed eyes, and half believed herself in +Wonderland, though she knew she had but to open them again, and +all would change to dull reality--the grass would be only +rustling in the wind, and the pool rippling to the waving of the +reeds--the rattling teacups would change to tinkling sheep- +bells, and the Queen's shrill cries to the voice of the shepherd +boy--and the sneeze of the baby, the shriek of the Gryphon, and +all thy other queer noises, would change (she knew) to the +confused clamour of the busy farm-yard--while the lowing of the +cattle in the distance would take the place of the Mock Turtle's +heavy sobs. + + Lastly, she pictured to herself how this same little sister of +hers would, in the after-time, be herself a grown woman; and how +she would keep, through all her riper years, the simple and +loving heart of her childhood: and how she would gather about +her other little children, and make THEIR eyes bright and eager +with many a strange tale, perhaps even with the dream of +Wonderland of long ago: and how she would feel with all their +simple sorrows, and find a pleasure in all their simple joys, +remembering her own child-life, and the happy summer days. + + THE END + \ No newline at end of file diff --git a/vendor/snap/data/asyoulik.txt b/vendor/snap/data/asyoulik.txt new file mode 100644 index 0000000000..88dc7b60fe --- /dev/null +++ b/vendor/snap/data/asyoulik.txt @@ -0,0 +1,4122 @@ + AS YOU LIKE IT + + + DRAMATIS PERSONAE + + +DUKE SENIOR living in banishment. + +DUKE FREDERICK his brother, an usurper of his dominions. + + +AMIENS | + | lords attending on the banished duke. +JAQUES | + + +LE BEAU a courtier attending upon Frederick. + +CHARLES wrestler to Frederick. + + +OLIVER | + | +JAQUES (JAQUES DE BOYS:) | sons of Sir Rowland de Boys. + | +ORLANDO | + + +ADAM | + | servants to Oliver. +DENNIS | + + +TOUCHSTONE a clown. + +SIR OLIVER MARTEXT a vicar. + + +CORIN | + | shepherds. +SILVIUS | + + +WILLIAM a country fellow in love with Audrey. + + A person representing HYMEN. (HYMEN:) + +ROSALIND daughter to the banished duke. + +CELIA daughter to Frederick. + +PHEBE a shepherdess. + +AUDREY a country wench. + + Lords, pages, and attendants, &c. + (Forester:) + (A Lord:) + (First Lord:) + (Second Lord:) + (First Page:) + (Second Page:) + + +SCENE Oliver's house; Duke Frederick's court; and the + Forest of Arden. + + + + + AS YOU LIKE IT + + +ACT I + + + +SCENE I Orchard of Oliver's house. + + + [Enter ORLANDO and ADAM] + +ORLANDO As I remember, Adam, it was upon this fashion + bequeathed me by will but poor a thousand crowns, + and, as thou sayest, charged my brother, on his + blessing, to breed me well: and there begins my + sadness. My brother Jaques he keeps at school, and + report speaks goldenly of his profit: for my part, + he keeps me rustically at home, or, to speak more + properly, stays me here at home unkept; for call you + that keeping for a gentleman of my birth, that + differs not from the stalling of an ox? His horses + are bred better; for, besides that they are fair + with their feeding, they are taught their manage, + and to that end riders dearly hired: but I, his + brother, gain nothing under him but growth; for the + which his animals on his dunghills are as much + bound to him as I. Besides this nothing that he so + plentifully gives me, the something that nature gave + me his countenance seems to take from me: he lets + me feed with his hinds, bars me the place of a + brother, and, as much as in him lies, mines my + gentility with my education. This is it, Adam, that + grieves me; and the spirit of my father, which I + think is within me, begins to mutiny against this + servitude: I will no longer endure it, though yet I + know no wise remedy how to avoid it. + +ADAM Yonder comes my master, your brother. + +ORLANDO Go apart, Adam, and thou shalt hear how he will + shake me up. + + [Enter OLIVER] + +OLIVER Now, sir! what make you here? + +ORLANDO Nothing: I am not taught to make any thing. + +OLIVER What mar you then, sir? + +ORLANDO Marry, sir, I am helping you to mar that which God + made, a poor unworthy brother of yours, with idleness. + +OLIVER Marry, sir, be better employed, and be naught awhile. + +ORLANDO Shall I keep your hogs and eat husks with them? + What prodigal portion have I spent, that I should + come to such penury? + +OLIVER Know you where your are, sir? + +ORLANDO O, sir, very well; here in your orchard. + +OLIVER Know you before whom, sir? + +ORLANDO Ay, better than him I am before knows me. I know + you are my eldest brother; and, in the gentle + condition of blood, you should so know me. The + courtesy of nations allows you my better, in that + you are the first-born; but the same tradition + takes not away my blood, were there twenty brothers + betwixt us: I have as much of my father in me as + you; albeit, I confess, your coming before me is + nearer to his reverence. + +OLIVER What, boy! + +ORLANDO Come, come, elder brother, you are too young in this. + +OLIVER Wilt thou lay hands on me, villain? + +ORLANDO I am no villain; I am the youngest son of Sir + Rowland de Boys; he was my father, and he is thrice + a villain that says such a father begot villains. + Wert thou not my brother, I would not take this hand + from thy throat till this other had pulled out thy + tongue for saying so: thou hast railed on thyself. + +ADAM Sweet masters, be patient: for your father's + remembrance, be at accord. + +OLIVER Let me go, I say. + +ORLANDO I will not, till I please: you shall hear me. My + father charged you in his will to give me good + education: you have trained me like a peasant, + obscuring and hiding from me all gentleman-like + qualities. The spirit of my father grows strong in + me, and I will no longer endure it: therefore allow + me such exercises as may become a gentleman, or + give me the poor allottery my father left me by + testament; with that I will go buy my fortunes. + +OLIVER And what wilt thou do? beg, when that is spent? + Well, sir, get you in: I will not long be troubled + with you; you shall have some part of your will: I + pray you, leave me. + +ORLANDO I will no further offend you than becomes me for my good. + +OLIVER Get you with him, you old dog. + +ADAM Is 'old dog' my reward? Most true, I have lost my + teeth in your service. God be with my old master! + he would not have spoke such a word. + + [Exeunt ORLANDO and ADAM] + +OLIVER Is it even so? begin you to grow upon me? I will + physic your rankness, and yet give no thousand + crowns neither. Holla, Dennis! + + [Enter DENNIS] + +DENNIS Calls your worship? + +OLIVER Was not Charles, the duke's wrestler, here to speak with me? + +DENNIS So please you, he is here at the door and importunes + access to you. + +OLIVER Call him in. + + [Exit DENNIS] + + 'Twill be a good way; and to-morrow the wrestling is. + + [Enter CHARLES] + +CHARLES Good morrow to your worship. + +OLIVER Good Monsieur Charles, what's the new news at the + new court? + +CHARLES There's no news at the court, sir, but the old news: + that is, the old duke is banished by his younger + brother the new duke; and three or four loving lords + have put themselves into voluntary exile with him, + whose lands and revenues enrich the new duke; + therefore he gives them good leave to wander. + +OLIVER Can you tell if Rosalind, the duke's daughter, be + banished with her father? + +CHARLES O, no; for the duke's daughter, her cousin, so loves + her, being ever from their cradles bred together, + that she would have followed her exile, or have died + to stay behind her. She is at the court, and no + less beloved of her uncle than his own daughter; and + never two ladies loved as they do. + +OLIVER Where will the old duke live? + +CHARLES They say he is already in the forest of Arden, and + a many merry men with him; and there they live like + the old Robin Hood of England: they say many young + gentlemen flock to him every day, and fleet the time + carelessly, as they did in the golden world. + +OLIVER What, you wrestle to-morrow before the new duke? + +CHARLES Marry, do I, sir; and I came to acquaint you with a + matter. I am given, sir, secretly to understand + that your younger brother Orlando hath a disposition + to come in disguised against me to try a fall. + To-morrow, sir, I wrestle for my credit; and he that + escapes me without some broken limb shall acquit him + well. Your brother is but young and tender; and, + for your love, I would be loath to foil him, as I + must, for my own honour, if he come in: therefore, + out of my love to you, I came hither to acquaint you + withal, that either you might stay him from his + intendment or brook such disgrace well as he shall + run into, in that it is a thing of his own search + and altogether against my will. + +OLIVER Charles, I thank thee for thy love to me, which + thou shalt find I will most kindly requite. I had + myself notice of my brother's purpose herein and + have by underhand means laboured to dissuade him from + it, but he is resolute. I'll tell thee, Charles: + it is the stubbornest young fellow of France, full + of ambition, an envious emulator of every man's + good parts, a secret and villanous contriver against + me his natural brother: therefore use thy + discretion; I had as lief thou didst break his neck + as his finger. And thou wert best look to't; for if + thou dost him any slight disgrace or if he do not + mightily grace himself on thee, he will practise + against thee by poison, entrap thee by some + treacherous device and never leave thee till he + hath ta'en thy life by some indirect means or other; + for, I assure thee, and almost with tears I speak + it, there is not one so young and so villanous this + day living. I speak but brotherly of him; but + should I anatomize him to thee as he is, I must + blush and weep and thou must look pale and wonder. + +CHARLES I am heartily glad I came hither to you. If he come + to-morrow, I'll give him his payment: if ever he go + alone again, I'll never wrestle for prize more: and + so God keep your worship! + +OLIVER Farewell, good Charles. + + [Exit CHARLES] + + Now will I stir this gamester: I hope I shall see + an end of him; for my soul, yet I know not why, + hates nothing more than he. Yet he's gentle, never + schooled and yet learned, full of noble device, of + all sorts enchantingly beloved, and indeed so much + in the heart of the world, and especially of my own + people, who best know him, that I am altogether + misprised: but it shall not be so long; this + wrestler shall clear all: nothing remains but that + I kindle the boy thither; which now I'll go about. + + [Exit] + + + + + AS YOU LIKE IT + + +ACT I + + + +SCENE II Lawn before the Duke's palace. + + + [Enter CELIA and ROSALIND] + +CELIA I pray thee, Rosalind, sweet my coz, be merry. + +ROSALIND Dear Celia, I show more mirth than I am mistress of; + and would you yet I were merrier? Unless you could + teach me to forget a banished father, you must not + learn me how to remember any extraordinary pleasure. + +CELIA Herein I see thou lovest me not with the full weight + that I love thee. If my uncle, thy banished father, + had banished thy uncle, the duke my father, so thou + hadst been still with me, I could have taught my + love to take thy father for mine: so wouldst thou, + if the truth of thy love to me were so righteously + tempered as mine is to thee. + +ROSALIND Well, I will forget the condition of my estate, to + rejoice in yours. + +CELIA You know my father hath no child but I, nor none is + like to have: and, truly, when he dies, thou shalt + be his heir, for what he hath taken away from thy + father perforce, I will render thee again in + affection; by mine honour, I will; and when I break + that oath, let me turn monster: therefore, my + sweet Rose, my dear Rose, be merry. + +ROSALIND From henceforth I will, coz, and devise sports. Let + me see; what think you of falling in love? + +CELIA Marry, I prithee, do, to make sport withal: but + love no man in good earnest; nor no further in sport + neither than with safety of a pure blush thou mayst + in honour come off again. + +ROSALIND What shall be our sport, then? + +CELIA Let us sit and mock the good housewife Fortune from + her wheel, that her gifts may henceforth be bestowed equally. + +ROSALIND I would we could do so, for her benefits are + mightily misplaced, and the bountiful blind woman + doth most mistake in her gifts to women. + +CELIA 'Tis true; for those that she makes fair she scarce + makes honest, and those that she makes honest she + makes very ill-favouredly. + +ROSALIND Nay, now thou goest from Fortune's office to + Nature's: Fortune reigns in gifts of the world, + not in the lineaments of Nature. + + [Enter TOUCHSTONE] + +CELIA No? when Nature hath made a fair creature, may she + not by Fortune fall into the fire? Though Nature + hath given us wit to flout at Fortune, hath not + Fortune sent in this fool to cut off the argument? + +ROSALIND Indeed, there is Fortune too hard for Nature, when + Fortune makes Nature's natural the cutter-off of + Nature's wit. + +CELIA Peradventure this is not Fortune's work neither, but + Nature's; who perceiveth our natural wits too dull + to reason of such goddesses and hath sent this + natural for our whetstone; for always the dulness of + the fool is the whetstone of the wits. How now, + wit! whither wander you? + +TOUCHSTONE Mistress, you must come away to your father. + +CELIA Were you made the messenger? + +TOUCHSTONE No, by mine honour, but I was bid to come for you. + +ROSALIND Where learned you that oath, fool? + +TOUCHSTONE Of a certain knight that swore by his honour they + were good pancakes and swore by his honour the + mustard was naught: now I'll stand to it, the + pancakes were naught and the mustard was good, and + yet was not the knight forsworn. + +CELIA How prove you that, in the great heap of your + knowledge? + +ROSALIND Ay, marry, now unmuzzle your wisdom. + +TOUCHSTONE Stand you both forth now: stroke your chins, and + swear by your beards that I am a knave. + +CELIA By our beards, if we had them, thou art. + +TOUCHSTONE By my knavery, if I had it, then I were; but if you + swear by that that is not, you are not forsworn: no + more was this knight swearing by his honour, for he + never had any; or if he had, he had sworn it away + before ever he saw those pancakes or that mustard. + +CELIA Prithee, who is't that thou meanest? + +TOUCHSTONE One that old Frederick, your father, loves. + +CELIA My father's love is enough to honour him: enough! + speak no more of him; you'll be whipped for taxation + one of these days. + +TOUCHSTONE The more pity, that fools may not speak wisely what + wise men do foolishly. + +CELIA By my troth, thou sayest true; for since the little + wit that fools have was silenced, the little foolery + that wise men have makes a great show. Here comes + Monsieur Le Beau. + +ROSALIND With his mouth full of news. + +CELIA Which he will put on us, as pigeons feed their young. + +ROSALIND Then shall we be news-crammed. + +CELIA All the better; we shall be the more marketable. + + [Enter LE BEAU] + + Bon jour, Monsieur Le Beau: what's the news? + +LE BEAU Fair princess, you have lost much good sport. + +CELIA Sport! of what colour? + +LE BEAU What colour, madam! how shall I answer you? + +ROSALIND As wit and fortune will. + +TOUCHSTONE Or as the Destinies decree. + +CELIA Well said: that was laid on with a trowel. + +TOUCHSTONE Nay, if I keep not my rank,-- + +ROSALIND Thou losest thy old smell. + +LE BEAU You amaze me, ladies: I would have told you of good + wrestling, which you have lost the sight of. + +ROSALIND You tell us the manner of the wrestling. + +LE BEAU I will tell you the beginning; and, if it please + your ladyships, you may see the end; for the best is + yet to do; and here, where you are, they are coming + to perform it. + +CELIA Well, the beginning, that is dead and buried. + +LE BEAU There comes an old man and his three sons,-- + +CELIA I could match this beginning with an old tale. + +LE BEAU Three proper young men, of excellent growth and presence. + +ROSALIND With bills on their necks, 'Be it known unto all men + by these presents.' + +LE BEAU The eldest of the three wrestled with Charles, the + duke's wrestler; which Charles in a moment threw him + and broke three of his ribs, that there is little + hope of life in him: so he served the second, and + so the third. Yonder they lie; the poor old man, + their father, making such pitiful dole over them + that all the beholders take his part with weeping. + +ROSALIND Alas! + +TOUCHSTONE But what is the sport, monsieur, that the ladies + have lost? + +LE BEAU Why, this that I speak of. + +TOUCHSTONE Thus men may grow wiser every day: it is the first + time that ever I heard breaking of ribs was sport + for ladies. + +CELIA Or I, I promise thee. + +ROSALIND But is there any else longs to see this broken music + in his sides? is there yet another dotes upon + rib-breaking? Shall we see this wrestling, cousin? + +LE BEAU You must, if you stay here; for here is the place + appointed for the wrestling, and they are ready to + perform it. + +CELIA Yonder, sure, they are coming: let us now stay and see it. + + [Flourish. Enter DUKE FREDERICK, Lords, ORLANDO, + CHARLES, and Attendants] + +DUKE FREDERICK Come on: since the youth will not be entreated, his + own peril on his forwardness. + +ROSALIND Is yonder the man? + +LE BEAU Even he, madam. + +CELIA Alas, he is too young! yet he looks successfully. + +DUKE FREDERICK How now, daughter and cousin! are you crept hither + to see the wrestling? + +ROSALIND Ay, my liege, so please you give us leave. + +DUKE FREDERICK You will take little delight in it, I can tell you; + there is such odds in the man. In pity of the + challenger's youth I would fain dissuade him, but he + will not be entreated. Speak to him, ladies; see if + you can move him. + +CELIA Call him hither, good Monsieur Le Beau. + +DUKE FREDERICK Do so: I'll not be by. + +LE BEAU Monsieur the challenger, the princesses call for you. + +ORLANDO I attend them with all respect and duty. + +ROSALIND Young man, have you challenged Charles the wrestler? + +ORLANDO No, fair princess; he is the general challenger: I + come but in, as others do, to try with him the + strength of my youth. + +CELIA Young gentleman, your spirits are too bold for your + years. You have seen cruel proof of this man's + strength: if you saw yourself with your eyes or + knew yourself with your judgment, the fear of your + adventure would counsel you to a more equal + enterprise. We pray you, for your own sake, to + embrace your own safety and give over this attempt. + +ROSALIND Do, young sir; your reputation shall not therefore + be misprised: we will make it our suit to the duke + that the wrestling might not go forward. + +ORLANDO I beseech you, punish me not with your hard + thoughts; wherein I confess me much guilty, to deny + so fair and excellent ladies any thing. But let + your fair eyes and gentle wishes go with me to my + trial: wherein if I be foiled, there is but one + shamed that was never gracious; if killed, but one + dead that was willing to be so: I shall do my + friends no wrong, for I have none to lament me, the + world no injury, for in it I have nothing; only in + the world I fill up a place, which may be better + supplied when I have made it empty. + +ROSALIND The little strength that I have, I would it were with you. + +CELIA And mine, to eke out hers. + +ROSALIND Fare you well: pray heaven I be deceived in you! + +CELIA Your heart's desires be with you! + +CHARLES Come, where is this young gallant that is so + desirous to lie with his mother earth? + +ORLANDO Ready, sir; but his will hath in it a more modest working. + +DUKE FREDERICK You shall try but one fall. + +CHARLES No, I warrant your grace, you shall not entreat him + to a second, that have so mightily persuaded him + from a first. + +ORLANDO An you mean to mock me after, you should not have + mocked me before: but come your ways. + +ROSALIND Now Hercules be thy speed, young man! + +CELIA I would I were invisible, to catch the strong + fellow by the leg. + + [They wrestle] + +ROSALIND O excellent young man! + +CELIA If I had a thunderbolt in mine eye, I can tell who + should down. + + [Shout. CHARLES is thrown] + +DUKE FREDERICK No more, no more. + +ORLANDO Yes, I beseech your grace: I am not yet well breathed. + +DUKE FREDERICK How dost thou, Charles? + +LE BEAU He cannot speak, my lord. + +DUKE FREDERICK Bear him away. What is thy name, young man? + +ORLANDO Orlando, my liege; the youngest son of Sir Rowland de Boys. + +DUKE FREDERICK I would thou hadst been son to some man else: + The world esteem'd thy father honourable, + But I did find him still mine enemy: + Thou shouldst have better pleased me with this deed, + Hadst thou descended from another house. + But fare thee well; thou art a gallant youth: + I would thou hadst told me of another father. + + [Exeunt DUKE FREDERICK, train, and LE BEAU] + +CELIA Were I my father, coz, would I do this? + +ORLANDO I am more proud to be Sir Rowland's son, + His youngest son; and would not change that calling, + To be adopted heir to Frederick. + +ROSALIND My father loved Sir Rowland as his soul, + And all the world was of my father's mind: + Had I before known this young man his son, + I should have given him tears unto entreaties, + Ere he should thus have ventured. + +CELIA Gentle cousin, + Let us go thank him and encourage him: + My father's rough and envious disposition + Sticks me at heart. Sir, you have well deserved: + If you do keep your promises in love + But justly, as you have exceeded all promise, + Your mistress shall be happy. + +ROSALIND Gentleman, + + [Giving him a chain from her neck] + + Wear this for me, one out of suits with fortune, + That could give more, but that her hand lacks means. + Shall we go, coz? + +CELIA Ay. Fare you well, fair gentleman. + +ORLANDO Can I not say, I thank you? My better parts + Are all thrown down, and that which here stands up + Is but a quintain, a mere lifeless block. + +ROSALIND He calls us back: my pride fell with my fortunes; + I'll ask him what he would. Did you call, sir? + Sir, you have wrestled well and overthrown + More than your enemies. + +CELIA Will you go, coz? + +ROSALIND Have with you. Fare you well. + + [Exeunt ROSALIND and CELIA] + +ORLANDO What passion hangs these weights upon my tongue? + I cannot speak to her, yet she urged conference. + O poor Orlando, thou art overthrown! + Or Charles or something weaker masters thee. + + [Re-enter LE BEAU] + +LE BEAU Good sir, I do in friendship counsel you + To leave this place. Albeit you have deserved + High commendation, true applause and love, + Yet such is now the duke's condition + That he misconstrues all that you have done. + The duke is humorous; what he is indeed, + More suits you to conceive than I to speak of. + +ORLANDO I thank you, sir: and, pray you, tell me this: + Which of the two was daughter of the duke + That here was at the wrestling? + +LE BEAU Neither his daughter, if we judge by manners; + But yet indeed the lesser is his daughter + The other is daughter to the banish'd duke, + And here detain'd by her usurping uncle, + To keep his daughter company; whose loves + Are dearer than the natural bond of sisters. + But I can tell you that of late this duke + Hath ta'en displeasure 'gainst his gentle niece, + Grounded upon no other argument + But that the people praise her for her virtues + And pity her for her good father's sake; + And, on my life, his malice 'gainst the lady + Will suddenly break forth. Sir, fare you well: + Hereafter, in a better world than this, + I shall desire more love and knowledge of you. + +ORLANDO I rest much bounden to you: fare you well. + + [Exit LE BEAU] + + Thus must I from the smoke into the smother; + From tyrant duke unto a tyrant brother: + But heavenly Rosalind! + + [Exit] + + + + + AS YOU LIKE IT + + +ACT I + + + +SCENE III A room in the palace. + + + [Enter CELIA and ROSALIND] + +CELIA Why, cousin! why, Rosalind! Cupid have mercy! not a word? + +ROSALIND Not one to throw at a dog. + +CELIA No, thy words are too precious to be cast away upon + curs; throw some of them at me; come, lame me with reasons. + +ROSALIND Then there were two cousins laid up; when the one + should be lamed with reasons and the other mad + without any. + +CELIA But is all this for your father? + +ROSALIND No, some of it is for my child's father. O, how + full of briers is this working-day world! + +CELIA They are but burs, cousin, thrown upon thee in + holiday foolery: if we walk not in the trodden + paths our very petticoats will catch them. + +ROSALIND I could shake them off my coat: these burs are in my heart. + +CELIA Hem them away. + +ROSALIND I would try, if I could cry 'hem' and have him. + +CELIA Come, come, wrestle with thy affections. + +ROSALIND O, they take the part of a better wrestler than myself! + +CELIA O, a good wish upon you! you will try in time, in + despite of a fall. But, turning these jests out of + service, let us talk in good earnest: is it + possible, on such a sudden, you should fall into so + strong a liking with old Sir Rowland's youngest son? + +ROSALIND The duke my father loved his father dearly. + +CELIA Doth it therefore ensue that you should love his son + dearly? By this kind of chase, I should hate him, + for my father hated his father dearly; yet I hate + not Orlando. + +ROSALIND No, faith, hate him not, for my sake. + +CELIA Why should I not? doth he not deserve well? + +ROSALIND Let me love him for that, and do you love him + because I do. Look, here comes the duke. + +CELIA With his eyes full of anger. + + [Enter DUKE FREDERICK, with Lords] + +DUKE FREDERICK Mistress, dispatch you with your safest haste + And get you from our court. + +ROSALIND Me, uncle? + +DUKE FREDERICK You, cousin + Within these ten days if that thou be'st found + So near our public court as twenty miles, + Thou diest for it. + +ROSALIND I do beseech your grace, + Let me the knowledge of my fault bear with me: + If with myself I hold intelligence + Or have acquaintance with mine own desires, + If that I do not dream or be not frantic,-- + As I do trust I am not--then, dear uncle, + Never so much as in a thought unborn + Did I offend your highness. + +DUKE FREDERICK Thus do all traitors: + If their purgation did consist in words, + They are as innocent as grace itself: + Let it suffice thee that I trust thee not. + +ROSALIND Yet your mistrust cannot make me a traitor: + Tell me whereon the likelihood depends. + +DUKE FREDERICK Thou art thy father's daughter; there's enough. + +ROSALIND So was I when your highness took his dukedom; + So was I when your highness banish'd him: + Treason is not inherited, my lord; + Or, if we did derive it from our friends, + What's that to me? my father was no traitor: + Then, good my liege, mistake me not so much + To think my poverty is treacherous. + +CELIA Dear sovereign, hear me speak. + +DUKE FREDERICK Ay, Celia; we stay'd her for your sake, + Else had she with her father ranged along. + +CELIA I did not then entreat to have her stay; + It was your pleasure and your own remorse: + I was too young that time to value her; + But now I know her: if she be a traitor, + Why so am I; we still have slept together, + Rose at an instant, learn'd, play'd, eat together, + And wheresoever we went, like Juno's swans, + Still we went coupled and inseparable. + +DUKE FREDERICK She is too subtle for thee; and her smoothness, + Her very silence and her patience + Speak to the people, and they pity her. + Thou art a fool: she robs thee of thy name; + And thou wilt show more bright and seem more virtuous + When she is gone. Then open not thy lips: + Firm and irrevocable is my doom + Which I have pass'd upon her; she is banish'd. + +CELIA Pronounce that sentence then on me, my liege: + I cannot live out of her company. + +DUKE FREDERICK You are a fool. You, niece, provide yourself: + If you outstay the time, upon mine honour, + And in the greatness of my word, you die. + + [Exeunt DUKE FREDERICK and Lords] + +CELIA O my poor Rosalind, whither wilt thou go? + Wilt thou change fathers? I will give thee mine. + I charge thee, be not thou more grieved than I am. + +ROSALIND I have more cause. + +CELIA Thou hast not, cousin; + Prithee be cheerful: know'st thou not, the duke + Hath banish'd me, his daughter? + +ROSALIND That he hath not. + +CELIA No, hath not? Rosalind lacks then the love + Which teacheth thee that thou and I am one: + Shall we be sunder'd? shall we part, sweet girl? + No: let my father seek another heir. + Therefore devise with me how we may fly, + Whither to go and what to bear with us; + And do not seek to take your change upon you, + To bear your griefs yourself and leave me out; + For, by this heaven, now at our sorrows pale, + Say what thou canst, I'll go along with thee. + +ROSALIND Why, whither shall we go? + +CELIA To seek my uncle in the forest of Arden. + +ROSALIND Alas, what danger will it be to us, + Maids as we are, to travel forth so far! + Beauty provoketh thieves sooner than gold. + +CELIA I'll put myself in poor and mean attire + And with a kind of umber smirch my face; + The like do you: so shall we pass along + And never stir assailants. + +ROSALIND Were it not better, + Because that I am more than common tall, + That I did suit me all points like a man? + A gallant curtle-axe upon my thigh, + A boar-spear in my hand; and--in my heart + Lie there what hidden woman's fear there will-- + We'll have a swashing and a martial outside, + As many other mannish cowards have + That do outface it with their semblances. + +CELIA What shall I call thee when thou art a man? + +ROSALIND I'll have no worse a name than Jove's own page; + And therefore look you call me Ganymede. + But what will you be call'd? + +CELIA Something that hath a reference to my state + No longer Celia, but Aliena. + +ROSALIND But, cousin, what if we assay'd to steal + The clownish fool out of your father's court? + Would he not be a comfort to our travel? + +CELIA He'll go along o'er the wide world with me; + Leave me alone to woo him. Let's away, + And get our jewels and our wealth together, + Devise the fittest time and safest way + To hide us from pursuit that will be made + After my flight. Now go we in content + To liberty and not to banishment. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT II + + + +SCENE I The Forest of Arden. + + + [Enter DUKE SENIOR, AMIENS, and two or three Lords, + like foresters] + +DUKE SENIOR Now, my co-mates and brothers in exile, + Hath not old custom made this life more sweet + Than that of painted pomp? Are not these woods + More free from peril than the envious court? + Here feel we but the penalty of Adam, + The seasons' difference, as the icy fang + And churlish chiding of the winter's wind, + Which, when it bites and blows upon my body, + Even till I shrink with cold, I smile and say + 'This is no flattery: these are counsellors + That feelingly persuade me what I am.' + Sweet are the uses of adversity, + Which, like the toad, ugly and venomous, + Wears yet a precious jewel in his head; + And this our life exempt from public haunt + Finds tongues in trees, books in the running brooks, + Sermons in stones and good in every thing. + I would not change it. + +AMIENS Happy is your grace, + That can translate the stubbornness of fortune + Into so quiet and so sweet a style. + +DUKE SENIOR Come, shall we go and kill us venison? + And yet it irks me the poor dappled fools, + Being native burghers of this desert city, + Should in their own confines with forked heads + Have their round haunches gored. + +First Lord Indeed, my lord, + The melancholy Jaques grieves at that, + And, in that kind, swears you do more usurp + Than doth your brother that hath banish'd you. + To-day my Lord of Amiens and myself + Did steal behind him as he lay along + Under an oak whose antique root peeps out + Upon the brook that brawls along this wood: + To the which place a poor sequester'd stag, + That from the hunter's aim had ta'en a hurt, + Did come to languish, and indeed, my lord, + The wretched animal heaved forth such groans + That their discharge did stretch his leathern coat + Almost to bursting, and the big round tears + Coursed one another down his innocent nose + In piteous chase; and thus the hairy fool + Much marked of the melancholy Jaques, + Stood on the extremest verge of the swift brook, + Augmenting it with tears. + +DUKE SENIOR But what said Jaques? + Did he not moralize this spectacle? + +First Lord O, yes, into a thousand similes. + First, for his weeping into the needless stream; + 'Poor deer,' quoth he, 'thou makest a testament + As worldlings do, giving thy sum of more + To that which had too much:' then, being there alone, + Left and abandon'd of his velvet friends, + ''Tis right:' quoth he; 'thus misery doth part + The flux of company:' anon a careless herd, + Full of the pasture, jumps along by him + And never stays to greet him; 'Ay' quoth Jaques, + 'Sweep on, you fat and greasy citizens; + 'Tis just the fashion: wherefore do you look + Upon that poor and broken bankrupt there?' + Thus most invectively he pierceth through + The body of the country, city, court, + Yea, and of this our life, swearing that we + Are mere usurpers, tyrants and what's worse, + To fright the animals and to kill them up + In their assign'd and native dwelling-place. + +DUKE SENIOR And did you leave him in this contemplation? + +Second Lord We did, my lord, weeping and commenting + Upon the sobbing deer. + +DUKE SENIOR Show me the place: + I love to cope him in these sullen fits, + For then he's full of matter. + +First Lord I'll bring you to him straight. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT II + + + +SCENE II A room in the palace. + + + [Enter DUKE FREDERICK, with Lords] + +DUKE FREDERICK Can it be possible that no man saw them? + It cannot be: some villains of my court + Are of consent and sufferance in this. + +First Lord I cannot hear of any that did see her. + The ladies, her attendants of her chamber, + Saw her abed, and in the morning early + They found the bed untreasured of their mistress. + +Second Lord My lord, the roynish clown, at whom so oft + Your grace was wont to laugh, is also missing. + Hisperia, the princess' gentlewoman, + Confesses that she secretly o'erheard + Your daughter and her cousin much commend + The parts and graces of the wrestler + That did but lately foil the sinewy Charles; + And she believes, wherever they are gone, + That youth is surely in their company. + +DUKE FREDERICK Send to his brother; fetch that gallant hither; + If he be absent, bring his brother to me; + I'll make him find him: do this suddenly, + And let not search and inquisition quail + To bring again these foolish runaways. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT II + + + +SCENE III Before OLIVER'S house. + + + [Enter ORLANDO and ADAM, meeting] + +ORLANDO Who's there? + +ADAM What, my young master? O, my gentle master! + O my sweet master! O you memory + Of old Sir Rowland! why, what make you here? + Why are you virtuous? why do people love you? + And wherefore are you gentle, strong and valiant? + Why would you be so fond to overcome + The bonny priser of the humorous duke? + Your praise is come too swiftly home before you. + Know you not, master, to some kind of men + Their graces serve them but as enemies? + No more do yours: your virtues, gentle master, + Are sanctified and holy traitors to you. + O, what a world is this, when what is comely + Envenoms him that bears it! + +ORLANDO Why, what's the matter? + +ADAM O unhappy youth! + Come not within these doors; within this roof + The enemy of all your graces lives: + Your brother--no, no brother; yet the son-- + Yet not the son, I will not call him son + Of him I was about to call his father-- + Hath heard your praises, and this night he means + To burn the lodging where you use to lie + And you within it: if he fail of that, + He will have other means to cut you off. + I overheard him and his practises. + This is no place; this house is but a butchery: + Abhor it, fear it, do not enter it. + +ORLANDO Why, whither, Adam, wouldst thou have me go? + +ADAM No matter whither, so you come not here. + +ORLANDO What, wouldst thou have me go and beg my food? + Or with a base and boisterous sword enforce + A thievish living on the common road? + This I must do, or know not what to do: + Yet this I will not do, do how I can; + I rather will subject me to the malice + Of a diverted blood and bloody brother. + +ADAM But do not so. I have five hundred crowns, + The thrifty hire I saved under your father, + Which I did store to be my foster-nurse + When service should in my old limbs lie lame + And unregarded age in corners thrown: + Take that, and He that doth the ravens feed, + Yea, providently caters for the sparrow, + Be comfort to my age! Here is the gold; + And all this I give you. Let me be your servant: + Though I look old, yet I am strong and lusty; + For in my youth I never did apply + Hot and rebellious liquors in my blood, + Nor did not with unbashful forehead woo + The means of weakness and debility; + Therefore my age is as a lusty winter, + Frosty, but kindly: let me go with you; + I'll do the service of a younger man + In all your business and necessities. + +ORLANDO O good old man, how well in thee appears + The constant service of the antique world, + When service sweat for duty, not for meed! + Thou art not for the fashion of these times, + Where none will sweat but for promotion, + And having that, do choke their service up + Even with the having: it is not so with thee. + But, poor old man, thou prunest a rotten tree, + That cannot so much as a blossom yield + In lieu of all thy pains and husbandry + But come thy ways; well go along together, + And ere we have thy youthful wages spent, + We'll light upon some settled low content. + +ADAM Master, go on, and I will follow thee, + To the last gasp, with truth and loyalty. + From seventeen years till now almost fourscore + Here lived I, but now live here no more. + At seventeen years many their fortunes seek; + But at fourscore it is too late a week: + Yet fortune cannot recompense me better + Than to die well and not my master's debtor. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT II + + + +SCENE IV The Forest of Arden. + + + [Enter ROSALIND for Ganymede, CELIA for Aliena, + and TOUCHSTONE] + +ROSALIND O Jupiter, how weary are my spirits! + +TOUCHSTONE I care not for my spirits, if my legs were not weary. + +ROSALIND I could find in my heart to disgrace my man's + apparel and to cry like a woman; but I must comfort + the weaker vessel, as doublet and hose ought to show + itself courageous to petticoat: therefore courage, + good Aliena! + +CELIA I pray you, bear with me; I cannot go no further. + +TOUCHSTONE For my part, I had rather bear with you than bear + you; yet I should bear no cross if I did bear you, + for I think you have no money in your purse. + +ROSALIND Well, this is the forest of Arden. + +TOUCHSTONE Ay, now am I in Arden; the more fool I; when I was + at home, I was in a better place: but travellers + must be content. + +ROSALIND Ay, be so, good Touchstone. + + [Enter CORIN and SILVIUS] + + Look you, who comes here; a young man and an old in + solemn talk. + +CORIN That is the way to make her scorn you still. + +SILVIUS O Corin, that thou knew'st how I do love her! + +CORIN I partly guess; for I have loved ere now. + +SILVIUS No, Corin, being old, thou canst not guess, + Though in thy youth thou wast as true a lover + As ever sigh'd upon a midnight pillow: + But if thy love were ever like to mine-- + As sure I think did never man love so-- + How many actions most ridiculous + Hast thou been drawn to by thy fantasy? + +CORIN Into a thousand that I have forgotten. + +SILVIUS O, thou didst then ne'er love so heartily! + If thou remember'st not the slightest folly + That ever love did make thee run into, + Thou hast not loved: + Or if thou hast not sat as I do now, + Wearying thy hearer in thy mistress' praise, + Thou hast not loved: + Or if thou hast not broke from company + Abruptly, as my passion now makes me, + Thou hast not loved. + O Phebe, Phebe, Phebe! + + [Exit] + +ROSALIND Alas, poor shepherd! searching of thy wound, + I have by hard adventure found mine own. + +TOUCHSTONE And I mine. I remember, when I was in love I broke + my sword upon a stone and bid him take that for + coming a-night to Jane Smile; and I remember the + kissing of her batlet and the cow's dugs that her + pretty chopt hands had milked; and I remember the + wooing of a peascod instead of her, from whom I took + two cods and, giving her them again, said with + weeping tears 'Wear these for my sake.' We that are + true lovers run into strange capers; but as all is + mortal in nature, so is all nature in love mortal in folly. + +ROSALIND Thou speakest wiser than thou art ware of. + +TOUCHSTONE Nay, I shall ne'er be ware of mine own wit till I + break my shins against it. + +ROSALIND Jove, Jove! this shepherd's passion + Is much upon my fashion. + +TOUCHSTONE And mine; but it grows something stale with me. + +CELIA I pray you, one of you question yond man + If he for gold will give us any food: + I faint almost to death. + +TOUCHSTONE Holla, you clown! + +ROSALIND Peace, fool: he's not thy kinsman. + +CORIN Who calls? + +TOUCHSTONE Your betters, sir. + +CORIN Else are they very wretched. + +ROSALIND Peace, I say. Good even to you, friend. + +CORIN And to you, gentle sir, and to you all. + +ROSALIND I prithee, shepherd, if that love or gold + Can in this desert place buy entertainment, + Bring us where we may rest ourselves and feed: + Here's a young maid with travel much oppress'd + And faints for succor. + +CORIN Fair sir, I pity her + And wish, for her sake more than for mine own, + My fortunes were more able to relieve her; + But I am shepherd to another man + And do not shear the fleeces that I graze: + My master is of churlish disposition + And little recks to find the way to heaven + By doing deeds of hospitality: + Besides, his cote, his flocks and bounds of feed + Are now on sale, and at our sheepcote now, + By reason of his absence, there is nothing + That you will feed on; but what is, come see. + And in my voice most welcome shall you be. + +ROSALIND What is he that shall buy his flock and pasture? + +CORIN That young swain that you saw here but erewhile, + That little cares for buying any thing. + +ROSALIND I pray thee, if it stand with honesty, + Buy thou the cottage, pasture and the flock, + And thou shalt have to pay for it of us. + +CELIA And we will mend thy wages. I like this place. + And willingly could waste my time in it. + +CORIN Assuredly the thing is to be sold: + Go with me: if you like upon report + The soil, the profit and this kind of life, + I will your very faithful feeder be + And buy it with your gold right suddenly. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT II + + + +SCENE V The Forest. + + + [Enter AMIENS, JAQUES, and others] + + SONG. +AMIENS Under the greenwood tree + Who loves to lie with me, + And turn his merry note + Unto the sweet bird's throat, + Come hither, come hither, come hither: + Here shall he see No enemy + But winter and rough weather. + +JAQUES More, more, I prithee, more. + +AMIENS It will make you melancholy, Monsieur Jaques. + +JAQUES I thank it. More, I prithee, more. I can suck + melancholy out of a song, as a weasel sucks eggs. + More, I prithee, more. + +AMIENS My voice is ragged: I know I cannot please you. + +JAQUES I do not desire you to please me; I do desire you to + sing. Come, more; another stanzo: call you 'em stanzos? + +AMIENS What you will, Monsieur Jaques. + +JAQUES Nay, I care not for their names; they owe me + nothing. Will you sing? + +AMIENS More at your request than to please myself. + +JAQUES Well then, if ever I thank any man, I'll thank you; + but that they call compliment is like the encounter + of two dog-apes, and when a man thanks me heartily, + methinks I have given him a penny and he renders me + the beggarly thanks. Come, sing; and you that will + not, hold your tongues. + +AMIENS Well, I'll end the song. Sirs, cover the while; the + duke will drink under this tree. He hath been all + this day to look you. + +JAQUES And I have been all this day to avoid him. He is + too disputable for my company: I think of as many + matters as he, but I give heaven thanks and make no + boast of them. Come, warble, come. + + SONG. + Who doth ambition shun + + [All together here] + + And loves to live i' the sun, + Seeking the food he eats + And pleased with what he gets, + Come hither, come hither, come hither: + Here shall he see No enemy + But winter and rough weather. + +JAQUES I'll give you a verse to this note that I made + yesterday in despite of my invention. + +AMIENS And I'll sing it. + +JAQUES Thus it goes:-- + + If it do come to pass + That any man turn ass, + Leaving his wealth and ease, + A stubborn will to please, + Ducdame, ducdame, ducdame: + Here shall he see + Gross fools as he, + An if he will come to me. + +AMIENS What's that 'ducdame'? + +JAQUES 'Tis a Greek invocation, to call fools into a + circle. I'll go sleep, if I can; if I cannot, I'll + rail against all the first-born of Egypt. + +AMIENS And I'll go seek the duke: his banquet is prepared. + + [Exeunt severally] + + + + + AS YOU LIKE IT + + +ACT II + + + +SCENE VI The forest. + + + [Enter ORLANDO and ADAM] + +ADAM Dear master, I can go no further. O, I die for food! + Here lie I down, and measure out my grave. Farewell, + kind master. + +ORLANDO Why, how now, Adam! no greater heart in thee? Live + a little; comfort a little; cheer thyself a little. + If this uncouth forest yield any thing savage, I + will either be food for it or bring it for food to + thee. Thy conceit is nearer death than thy powers. + For my sake be comfortable; hold death awhile at + the arm's end: I will here be with thee presently; + and if I bring thee not something to eat, I will + give thee leave to die: but if thou diest before I + come, thou art a mocker of my labour. Well said! + thou lookest cheerly, and I'll be with thee quickly. + Yet thou liest in the bleak air: come, I will bear + thee to some shelter; and thou shalt not die for + lack of a dinner, if there live any thing in this + desert. Cheerly, good Adam! + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT II + + + +SCENE VII The forest. + + + [A table set out. Enter DUKE SENIOR, AMIENS, and + Lords like outlaws] + +DUKE SENIOR I think he be transform'd into a beast; + For I can no where find him like a man. + +First Lord My lord, he is but even now gone hence: + Here was he merry, hearing of a song. + +DUKE SENIOR If he, compact of jars, grow musical, + We shall have shortly discord in the spheres. + Go, seek him: tell him I would speak with him. + + [Enter JAQUES] + +First Lord He saves my labour by his own approach. + +DUKE SENIOR Why, how now, monsieur! what a life is this, + That your poor friends must woo your company? + What, you look merrily! + +JAQUES A fool, a fool! I met a fool i' the forest, + A motley fool; a miserable world! + As I do live by food, I met a fool + Who laid him down and bask'd him in the sun, + And rail'd on Lady Fortune in good terms, + In good set terms and yet a motley fool. + 'Good morrow, fool,' quoth I. 'No, sir,' quoth he, + 'Call me not fool till heaven hath sent me fortune:' + And then he drew a dial from his poke, + And, looking on it with lack-lustre eye, + Says very wisely, 'It is ten o'clock: + Thus we may see,' quoth he, 'how the world wags: + 'Tis but an hour ago since it was nine, + And after one hour more 'twill be eleven; + And so, from hour to hour, we ripe and ripe, + And then, from hour to hour, we rot and rot; + And thereby hangs a tale.' When I did hear + The motley fool thus moral on the time, + My lungs began to crow like chanticleer, + That fools should be so deep-contemplative, + And I did laugh sans intermission + An hour by his dial. O noble fool! + A worthy fool! Motley's the only wear. + +DUKE SENIOR What fool is this? + +JAQUES O worthy fool! One that hath been a courtier, + And says, if ladies be but young and fair, + They have the gift to know it: and in his brain, + Which is as dry as the remainder biscuit + After a voyage, he hath strange places cramm'd + With observation, the which he vents + In mangled forms. O that I were a fool! + I am ambitious for a motley coat. + +DUKE SENIOR Thou shalt have one. + +JAQUES It is my only suit; + Provided that you weed your better judgments + Of all opinion that grows rank in them + That I am wise. I must have liberty + Withal, as large a charter as the wind, + To blow on whom I please; for so fools have; + And they that are most galled with my folly, + They most must laugh. And why, sir, must they so? + The 'why' is plain as way to parish church: + He that a fool doth very wisely hit + Doth very foolishly, although he smart, + Not to seem senseless of the bob: if not, + The wise man's folly is anatomized + Even by the squandering glances of the fool. + Invest me in my motley; give me leave + To speak my mind, and I will through and through + Cleanse the foul body of the infected world, + If they will patiently receive my medicine. + +DUKE SENIOR Fie on thee! I can tell what thou wouldst do. + +JAQUES What, for a counter, would I do but good? + +DUKE SENIOR Most mischievous foul sin, in chiding sin: + For thou thyself hast been a libertine, + As sensual as the brutish sting itself; + And all the embossed sores and headed evils, + That thou with licence of free foot hast caught, + Wouldst thou disgorge into the general world. + +JAQUES Why, who cries out on pride, + That can therein tax any private party? + Doth it not flow as hugely as the sea, + Till that the weary very means do ebb? + What woman in the city do I name, + When that I say the city-woman bears + The cost of princes on unworthy shoulders? + Who can come in and say that I mean her, + When such a one as she such is her neighbour? + Or what is he of basest function + That says his bravery is not of my cost, + Thinking that I mean him, but therein suits + His folly to the mettle of my speech? + There then; how then? what then? Let me see wherein + My tongue hath wrong'd him: if it do him right, + Then he hath wrong'd himself; if he be free, + Why then my taxing like a wild-goose flies, + Unclaim'd of any man. But who comes here? + + [Enter ORLANDO, with his sword drawn] + +ORLANDO Forbear, and eat no more. + +JAQUES Why, I have eat none yet. + +ORLANDO Nor shalt not, till necessity be served. + +JAQUES Of what kind should this cock come of? + +DUKE SENIOR Art thou thus bolden'd, man, by thy distress, + Or else a rude despiser of good manners, + That in civility thou seem'st so empty? + +ORLANDO You touch'd my vein at first: the thorny point + Of bare distress hath ta'en from me the show + Of smooth civility: yet am I inland bred + And know some nurture. But forbear, I say: + He dies that touches any of this fruit + Till I and my affairs are answered. + +JAQUES An you will not be answered with reason, I must die. + +DUKE SENIOR What would you have? Your gentleness shall force + More than your force move us to gentleness. + +ORLANDO I almost die for food; and let me have it. + +DUKE SENIOR Sit down and feed, and welcome to our table. + +ORLANDO Speak you so gently? Pardon me, I pray you: + I thought that all things had been savage here; + And therefore put I on the countenance + Of stern commandment. But whate'er you are + That in this desert inaccessible, + Under the shade of melancholy boughs, + Lose and neglect the creeping hours of time + If ever you have look'd on better days, + If ever been where bells have knoll'd to church, + If ever sat at any good man's feast, + If ever from your eyelids wiped a tear + And know what 'tis to pity and be pitied, + Let gentleness my strong enforcement be: + In the which hope I blush, and hide my sword. + +DUKE SENIOR True is it that we have seen better days, + And have with holy bell been knoll'd to church + And sat at good men's feasts and wiped our eyes + Of drops that sacred pity hath engender'd: + And therefore sit you down in gentleness + And take upon command what help we have + That to your wanting may be minister'd. + +ORLANDO Then but forbear your food a little while, + Whiles, like a doe, I go to find my fawn + And give it food. There is an old poor man, + Who after me hath many a weary step + Limp'd in pure love: till he be first sufficed, + Oppress'd with two weak evils, age and hunger, + I will not touch a bit. + +DUKE SENIOR Go find him out, + And we will nothing waste till you return. + +ORLANDO I thank ye; and be blest for your good comfort! + + [Exit] + +DUKE SENIOR Thou seest we are not all alone unhappy: + This wide and universal theatre + Presents more woeful pageants than the scene + Wherein we play in. + +JAQUES All the world's a stage, + And all the men and women merely players: + They have their exits and their entrances; + And one man in his time plays many parts, + His acts being seven ages. At first the infant, + Mewling and puking in the nurse's arms. + And then the whining school-boy, with his satchel + And shining morning face, creeping like snail + Unwillingly to school. And then the lover, + Sighing like furnace, with a woeful ballad + Made to his mistress' eyebrow. Then a soldier, + Full of strange oaths and bearded like the pard, + Jealous in honour, sudden and quick in quarrel, + Seeking the bubble reputation + Even in the cannon's mouth. And then the justice, + In fair round belly with good capon lined, + With eyes severe and beard of formal cut, + Full of wise saws and modern instances; + And so he plays his part. The sixth age shifts + Into the lean and slipper'd pantaloon, + With spectacles on nose and pouch on side, + His youthful hose, well saved, a world too wide + For his shrunk shank; and his big manly voice, + Turning again toward childish treble, pipes + And whistles in his sound. Last scene of all, + That ends this strange eventful history, + Is second childishness and mere oblivion, + Sans teeth, sans eyes, sans taste, sans everything. + + [Re-enter ORLANDO, with ADAM] + +DUKE SENIOR Welcome. Set down your venerable burthen, + And let him feed. + +ORLANDO I thank you most for him. + +ADAM So had you need: + I scarce can speak to thank you for myself. + +DUKE SENIOR Welcome; fall to: I will not trouble you + As yet, to question you about your fortunes. + Give us some music; and, good cousin, sing. + + SONG. +AMIENS Blow, blow, thou winter wind. + Thou art not so unkind + As man's ingratitude; + Thy tooth is not so keen, + Because thou art not seen, + Although thy breath be rude. + Heigh-ho! sing, heigh-ho! unto the green holly: + Most friendship is feigning, most loving mere folly: + Then, heigh-ho, the holly! + This life is most jolly. + Freeze, freeze, thou bitter sky, + That dost not bite so nigh + As benefits forgot: + Though thou the waters warp, + Thy sting is not so sharp + As friend remember'd not. + Heigh-ho! sing, &c. + +DUKE SENIOR If that you were the good Sir Rowland's son, + As you have whisper'd faithfully you were, + And as mine eye doth his effigies witness + Most truly limn'd and living in your face, + Be truly welcome hither: I am the duke + That loved your father: the residue of your fortune, + Go to my cave and tell me. Good old man, + Thou art right welcome as thy master is. + Support him by the arm. Give me your hand, + And let me all your fortunes understand. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT III + + + +SCENE I A room in the palace. + + + [Enter DUKE FREDERICK, Lords, and OLIVER] + +DUKE FREDERICK Not see him since? Sir, sir, that cannot be: + But were I not the better part made mercy, + I should not seek an absent argument + Of my revenge, thou present. But look to it: + Find out thy brother, wheresoe'er he is; + Seek him with candle; bring him dead or living + Within this twelvemonth, or turn thou no more + To seek a living in our territory. + Thy lands and all things that thou dost call thine + Worth seizure do we seize into our hands, + Till thou canst quit thee by thy brothers mouth + Of what we think against thee. + +OLIVER O that your highness knew my heart in this! + I never loved my brother in my life. + +DUKE FREDERICK More villain thou. Well, push him out of doors; + And let my officers of such a nature + Make an extent upon his house and lands: + Do this expediently and turn him going. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT III + + + +SCENE II The forest. + + + [Enter ORLANDO, with a paper] + +ORLANDO Hang there, my verse, in witness of my love: + And thou, thrice-crowned queen of night, survey + With thy chaste eye, from thy pale sphere above, + Thy huntress' name that my full life doth sway. + O Rosalind! these trees shall be my books + And in their barks my thoughts I'll character; + That every eye which in this forest looks + Shall see thy virtue witness'd every where. + Run, run, Orlando; carve on every tree + The fair, the chaste and unexpressive she. + + [Exit] + + [Enter CORIN and TOUCHSTONE] + +CORIN And how like you this shepherd's life, Master Touchstone? + +TOUCHSTONE Truly, shepherd, in respect of itself, it is a good + life, but in respect that it is a shepherd's life, + it is naught. In respect that it is solitary, I + like it very well; but in respect that it is + private, it is a very vile life. Now, in respect it + is in the fields, it pleaseth me well; but in + respect it is not in the court, it is tedious. As + is it a spare life, look you, it fits my humour well; + but as there is no more plenty in it, it goes much + against my stomach. Hast any philosophy in thee, shepherd? + +CORIN No more but that I know the more one sickens the + worse at ease he is; and that he that wants money, + means and content is without three good friends; + that the property of rain is to wet and fire to + burn; that good pasture makes fat sheep, and that a + great cause of the night is lack of the sun; that + he that hath learned no wit by nature nor art may + complain of good breeding or comes of a very dull kindred. + +TOUCHSTONE Such a one is a natural philosopher. Wast ever in + court, shepherd? + +CORIN No, truly. + +TOUCHSTONE Then thou art damned. + +CORIN Nay, I hope. + +TOUCHSTONE Truly, thou art damned like an ill-roasted egg, all + on one side. + +CORIN For not being at court? Your reason. + +TOUCHSTONE Why, if thou never wast at court, thou never sawest + good manners; if thou never sawest good manners, + then thy manners must be wicked; and wickedness is + sin, and sin is damnation. Thou art in a parlous + state, shepherd. + +CORIN Not a whit, Touchstone: those that are good manners + at the court are as ridiculous in the country as the + behavior of the country is most mockable at the + court. You told me you salute not at the court, but + you kiss your hands: that courtesy would be + uncleanly, if courtiers were shepherds. + +TOUCHSTONE Instance, briefly; come, instance. + +CORIN Why, we are still handling our ewes, and their + fells, you know, are greasy. + +TOUCHSTONE Why, do not your courtier's hands sweat? and is not + the grease of a mutton as wholesome as the sweat of + a man? Shallow, shallow. A better instance, I say; come. + +CORIN Besides, our hands are hard. + +TOUCHSTONE Your lips will feel them the sooner. Shallow again. + A more sounder instance, come. + +CORIN And they are often tarred over with the surgery of + our sheep: and would you have us kiss tar? The + courtier's hands are perfumed with civet. + +TOUCHSTONE Most shallow man! thou worms-meat, in respect of a + good piece of flesh indeed! Learn of the wise, and + perpend: civet is of a baser birth than tar, the + very uncleanly flux of a cat. Mend the instance, shepherd. + +CORIN You have too courtly a wit for me: I'll rest. + +TOUCHSTONE Wilt thou rest damned? God help thee, shallow man! + God make incision in thee! thou art raw. + +CORIN Sir, I am a true labourer: I earn that I eat, get + that I wear, owe no man hate, envy no man's + happiness, glad of other men's good, content with my + harm, and the greatest of my pride is to see my ewes + graze and my lambs suck. + +TOUCHSTONE That is another simple sin in you, to bring the ewes + and the rams together and to offer to get your + living by the copulation of cattle; to be bawd to a + bell-wether, and to betray a she-lamb of a + twelvemonth to a crooked-pated, old, cuckoldly ram, + out of all reasonable match. If thou beest not + damned for this, the devil himself will have no + shepherds; I cannot see else how thou shouldst + 'scape. + +CORIN Here comes young Master Ganymede, my new mistress's brother. + + [Enter ROSALIND, with a paper, reading] + +ROSALIND From the east to western Ind, + No jewel is like Rosalind. + Her worth, being mounted on the wind, + Through all the world bears Rosalind. + All the pictures fairest lined + Are but black to Rosalind. + Let no fair be kept in mind + But the fair of Rosalind. + +TOUCHSTONE I'll rhyme you so eight years together, dinners and + suppers and sleeping-hours excepted: it is the + right butter-women's rank to market. + +ROSALIND Out, fool! + +TOUCHSTONE For a taste: + If a hart do lack a hind, + Let him seek out Rosalind. + If the cat will after kind, + So be sure will Rosalind. + Winter garments must be lined, + So must slender Rosalind. + They that reap must sheaf and bind; + Then to cart with Rosalind. + Sweetest nut hath sourest rind, + Such a nut is Rosalind. + He that sweetest rose will find + Must find love's prick and Rosalind. + This is the very false gallop of verses: why do you + infect yourself with them? + +ROSALIND Peace, you dull fool! I found them on a tree. + +TOUCHSTONE Truly, the tree yields bad fruit. + +ROSALIND I'll graff it with you, and then I shall graff it + with a medlar: then it will be the earliest fruit + i' the country; for you'll be rotten ere you be half + ripe, and that's the right virtue of the medlar. + +TOUCHSTONE You have said; but whether wisely or no, let the + forest judge. + + [Enter CELIA, with a writing] + +ROSALIND Peace! Here comes my sister, reading: stand aside. + +CELIA [Reads] + + Why should this a desert be? + For it is unpeopled? No: + Tongues I'll hang on every tree, + That shall civil sayings show: + Some, how brief the life of man + Runs his erring pilgrimage, + That the stretching of a span + Buckles in his sum of age; + Some, of violated vows + 'Twixt the souls of friend and friend: + But upon the fairest boughs, + Or at every sentence end, + Will I Rosalinda write, + Teaching all that read to know + The quintessence of every sprite + Heaven would in little show. + Therefore Heaven Nature charged + That one body should be fill'd + With all graces wide-enlarged: + Nature presently distill'd + Helen's cheek, but not her heart, + Cleopatra's majesty, + Atalanta's better part, + Sad Lucretia's modesty. + Thus Rosalind of many parts + By heavenly synod was devised, + Of many faces, eyes and hearts, + To have the touches dearest prized. + Heaven would that she these gifts should have, + And I to live and die her slave. + +ROSALIND O most gentle pulpiter! what tedious homily of love + have you wearied your parishioners withal, and never + cried 'Have patience, good people!' + +CELIA How now! back, friends! Shepherd, go off a little. + Go with him, sirrah. + +TOUCHSTONE Come, shepherd, let us make an honourable retreat; + though not with bag and baggage, yet with scrip and scrippage. + + [Exeunt CORIN and TOUCHSTONE] + +CELIA Didst thou hear these verses? + +ROSALIND O, yes, I heard them all, and more too; for some of + them had in them more feet than the verses would bear. + +CELIA That's no matter: the feet might bear the verses. + +ROSALIND Ay, but the feet were lame and could not bear + themselves without the verse and therefore stood + lamely in the verse. + +CELIA But didst thou hear without wondering how thy name + should be hanged and carved upon these trees? + +ROSALIND I was seven of the nine days out of the wonder + before you came; for look here what I found on a + palm-tree. I was never so be-rhymed since + Pythagoras' time, that I was an Irish rat, which I + can hardly remember. + +CELIA Trow you who hath done this? + +ROSALIND Is it a man? + +CELIA And a chain, that you once wore, about his neck. + Change you colour? + +ROSALIND I prithee, who? + +CELIA O Lord, Lord! it is a hard matter for friends to + meet; but mountains may be removed with earthquakes + and so encounter. + +ROSALIND Nay, but who is it? + +CELIA Is it possible? + +ROSALIND Nay, I prithee now with most petitionary vehemence, + tell me who it is. + +CELIA O wonderful, wonderful, and most wonderful + wonderful! and yet again wonderful, and after that, + out of all hooping! + +ROSALIND Good my complexion! dost thou think, though I am + caparisoned like a man, I have a doublet and hose in + my disposition? One inch of delay more is a + South-sea of discovery; I prithee, tell me who is it + quickly, and speak apace. I would thou couldst + stammer, that thou mightst pour this concealed man + out of thy mouth, as wine comes out of a narrow- + mouthed bottle, either too much at once, or none at + all. I prithee, take the cork out of thy mouth that + may drink thy tidings. + +CELIA So you may put a man in your belly. + +ROSALIND Is he of God's making? What manner of man? Is his + head worth a hat, or his chin worth a beard? + +CELIA Nay, he hath but a little beard. + +ROSALIND Why, God will send more, if the man will be + thankful: let me stay the growth of his beard, if + thou delay me not the knowledge of his chin. + +CELIA It is young Orlando, that tripped up the wrestler's + heels and your heart both in an instant. + +ROSALIND Nay, but the devil take mocking: speak, sad brow and + true maid. + +CELIA I' faith, coz, 'tis he. + +ROSALIND Orlando? + +CELIA Orlando. + +ROSALIND Alas the day! what shall I do with my doublet and + hose? What did he when thou sawest him? What said + he? How looked he? Wherein went he? What makes + him here? Did he ask for me? Where remains he? + How parted he with thee? and when shalt thou see + him again? Answer me in one word. + +CELIA You must borrow me Gargantua's mouth first: 'tis a + word too great for any mouth of this age's size. To + say ay and no to these particulars is more than to + answer in a catechism. + +ROSALIND But doth he know that I am in this forest and in + man's apparel? Looks he as freshly as he did the + day he wrestled? + +CELIA It is as easy to count atomies as to resolve the + propositions of a lover; but take a taste of my + finding him, and relish it with good observance. + I found him under a tree, like a dropped acorn. + +ROSALIND It may well be called Jove's tree, when it drops + forth such fruit. + +CELIA Give me audience, good madam. + +ROSALIND Proceed. + +CELIA There lay he, stretched along, like a wounded knight. + +ROSALIND Though it be pity to see such a sight, it well + becomes the ground. + +CELIA Cry 'holla' to thy tongue, I prithee; it curvets + unseasonably. He was furnished like a hunter. + +ROSALIND O, ominous! he comes to kill my heart. + +CELIA I would sing my song without a burden: thou bringest + me out of tune. + +ROSALIND Do you not know I am a woman? when I think, I must + speak. Sweet, say on. + +CELIA You bring me out. Soft! comes he not here? + + [Enter ORLANDO and JAQUES] + +ROSALIND 'Tis he: slink by, and note him. + +JAQUES I thank you for your company; but, good faith, I had + as lief have been myself alone. + +ORLANDO And so had I; but yet, for fashion sake, I thank you + too for your society. + +JAQUES God be wi' you: let's meet as little as we can. + +ORLANDO I do desire we may be better strangers. + +JAQUES I pray you, mar no more trees with writing + love-songs in their barks. + +ORLANDO I pray you, mar no more of my verses with reading + them ill-favouredly. + +JAQUES Rosalind is your love's name? + +ORLANDO Yes, just. + +JAQUES I do not like her name. + +ORLANDO There was no thought of pleasing you when she was + christened. + +JAQUES What stature is she of? + +ORLANDO Just as high as my heart. + +JAQUES You are full of pretty answers. Have you not been + acquainted with goldsmiths' wives, and conned them + out of rings? + +ORLANDO Not so; but I answer you right painted cloth, from + whence you have studied your questions. + +JAQUES You have a nimble wit: I think 'twas made of + Atalanta's heels. Will you sit down with me? and + we two will rail against our mistress the world and + all our misery. + +ORLANDO I will chide no breather in the world but myself, + against whom I know most faults. + +JAQUES The worst fault you have is to be in love. + +ORLANDO 'Tis a fault I will not change for your best virtue. + I am weary of you. + +JAQUES By my troth, I was seeking for a fool when I found + you. + +ORLANDO He is drowned in the brook: look but in, and you + shall see him. + +JAQUES There I shall see mine own figure. + +ORLANDO Which I take to be either a fool or a cipher. + +JAQUES I'll tarry no longer with you: farewell, good + Signior Love. + +ORLANDO I am glad of your departure: adieu, good Monsieur + Melancholy. + + [Exit JAQUES] + +ROSALIND [Aside to CELIA] I will speak to him, like a saucy + lackey and under that habit play the knave with him. + Do you hear, forester? + +ORLANDO Very well: what would you? + +ROSALIND I pray you, what is't o'clock? + +ORLANDO You should ask me what time o' day: there's no clock + in the forest. + +ROSALIND Then there is no true lover in the forest; else + sighing every minute and groaning every hour would + detect the lazy foot of Time as well as a clock. + +ORLANDO And why not the swift foot of Time? had not that + been as proper? + +ROSALIND By no means, sir: Time travels in divers paces with + divers persons. I'll tell you who Time ambles + withal, who Time trots withal, who Time gallops + withal and who he stands still withal. + +ORLANDO I prithee, who doth he trot withal? + +ROSALIND Marry, he trots hard with a young maid between the + contract of her marriage and the day it is + solemnized: if the interim be but a se'nnight, + Time's pace is so hard that it seems the length of + seven year. + +ORLANDO Who ambles Time withal? + +ROSALIND With a priest that lacks Latin and a rich man that + hath not the gout, for the one sleeps easily because + he cannot study, and the other lives merrily because + he feels no pain, the one lacking the burden of lean + and wasteful learning, the other knowing no burden + of heavy tedious penury; these Time ambles withal. + +ORLANDO Who doth he gallop withal? + +ROSALIND With a thief to the gallows, for though he go as + softly as foot can fall, he thinks himself too soon there. + +ORLANDO Who stays it still withal? + +ROSALIND With lawyers in the vacation, for they sleep between + term and term and then they perceive not how Time moves. + +ORLANDO Where dwell you, pretty youth? + +ROSALIND With this shepherdess, my sister; here in the + skirts of the forest, like fringe upon a petticoat. + +ORLANDO Are you native of this place? + +ROSALIND As the cony that you see dwell where she is kindled. + +ORLANDO Your accent is something finer than you could + purchase in so removed a dwelling. + +ROSALIND I have been told so of many: but indeed an old + religious uncle of mine taught me to speak, who was + in his youth an inland man; one that knew courtship + too well, for there he fell in love. I have heard + him read many lectures against it, and I thank God + I am not a woman, to be touched with so many + giddy offences as he hath generally taxed their + whole sex withal. + +ORLANDO Can you remember any of the principal evils that he + laid to the charge of women? + +ROSALIND There were none principal; they were all like one + another as half-pence are, every one fault seeming + monstrous till his fellow fault came to match it. + +ORLANDO I prithee, recount some of them. + +ROSALIND No, I will not cast away my physic but on those that + are sick. There is a man haunts the forest, that + abuses our young plants with carving 'Rosalind' on + their barks; hangs odes upon hawthorns and elegies + on brambles, all, forsooth, deifying the name of + Rosalind: if I could meet that fancy-monger I would + give him some good counsel, for he seems to have the + quotidian of love upon him. + +ORLANDO I am he that is so love-shaked: I pray you tell me + your remedy. + +ROSALIND There is none of my uncle's marks upon you: he + taught me how to know a man in love; in which cage + of rushes I am sure you are not prisoner. + +ORLANDO What were his marks? + +ROSALIND A lean cheek, which you have not, a blue eye and + sunken, which you have not, an unquestionable + spirit, which you have not, a beard neglected, + which you have not; but I pardon you for that, for + simply your having in beard is a younger brother's + revenue: then your hose should be ungartered, your + bonnet unbanded, your sleeve unbuttoned, your shoe + untied and every thing about you demonstrating a + careless desolation; but you are no such man; you + are rather point-device in your accoutrements as + loving yourself than seeming the lover of any other. + +ORLANDO Fair youth, I would I could make thee believe I love. + +ROSALIND Me believe it! you may as soon make her that you + love believe it; which, I warrant, she is apter to + do than to confess she does: that is one of the + points in the which women still give the lie to + their consciences. But, in good sooth, are you he + that hangs the verses on the trees, wherein Rosalind + is so admired? + +ORLANDO I swear to thee, youth, by the white hand of + Rosalind, I am that he, that unfortunate he. + +ROSALIND But are you so much in love as your rhymes speak? + +ORLANDO Neither rhyme nor reason can express how much. + +ROSALIND Love is merely a madness, and, I tell you, deserves + as well a dark house and a whip as madmen do: and + the reason why they are not so punished and cured + is, that the lunacy is so ordinary that the whippers + are in love too. Yet I profess curing it by counsel. + +ORLANDO Did you ever cure any so? + +ROSALIND Yes, one, and in this manner. He was to imagine me + his love, his mistress; and I set him every day to + woo me: at which time would I, being but a moonish + youth, grieve, be effeminate, changeable, longing + and liking, proud, fantastical, apish, shallow, + inconstant, full of tears, full of smiles, for every + passion something and for no passion truly any + thing, as boys and women are for the most part + cattle of this colour; would now like him, now loathe + him; then entertain him, then forswear him; now weep + for him, then spit at him; that I drave my suitor + from his mad humour of love to a living humour of + madness; which was, to forswear the full stream of + the world, and to live in a nook merely monastic. + And thus I cured him; and this way will I take upon + me to wash your liver as clean as a sound sheep's + heart, that there shall not be one spot of love in't. + +ORLANDO I would not be cured, youth. + +ROSALIND I would cure you, if you would but call me Rosalind + and come every day to my cote and woo me. + +ORLANDO Now, by the faith of my love, I will: tell me + where it is. + +ROSALIND Go with me to it and I'll show it you and by the way + you shall tell me where in the forest you live. + Will you go? + +ORLANDO With all my heart, good youth. + +ROSALIND Nay you must call me Rosalind. Come, sister, will you go? + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT III + + + +SCENE III The forest. + + + [Enter TOUCHSTONE and AUDREY; JAQUES behind] + +TOUCHSTONE Come apace, good Audrey: I will fetch up your + goats, Audrey. And how, Audrey? am I the man yet? + doth my simple feature content you? + +AUDREY Your features! Lord warrant us! what features! + +TOUCHSTONE I am here with thee and thy goats, as the most + capricious poet, honest Ovid, was among the Goths. + +JAQUES [Aside] O knowledge ill-inhabited, worse than Jove + in a thatched house! + +TOUCHSTONE When a man's verses cannot be understood, nor a + man's good wit seconded with the forward child + Understanding, it strikes a man more dead than a + great reckoning in a little room. Truly, I would + the gods had made thee poetical. + +AUDREY I do not know what 'poetical' is: is it honest in + deed and word? is it a true thing? + +TOUCHSTONE No, truly; for the truest poetry is the most + feigning; and lovers are given to poetry, and what + they swear in poetry may be said as lovers they do feign. + +AUDREY Do you wish then that the gods had made me poetical? + +TOUCHSTONE I do, truly; for thou swearest to me thou art + honest: now, if thou wert a poet, I might have some + hope thou didst feign. + +AUDREY Would you not have me honest? + +TOUCHSTONE No, truly, unless thou wert hard-favoured; for + honesty coupled to beauty is to have honey a sauce to sugar. + +JAQUES [Aside] A material fool! + +AUDREY Well, I am not fair; and therefore I pray the gods + make me honest. + +TOUCHSTONE Truly, and to cast away honesty upon a foul slut + were to put good meat into an unclean dish. + +AUDREY I am not a slut, though I thank the gods I am foul. + +TOUCHSTONE Well, praised be the gods for thy foulness! + sluttishness may come hereafter. But be it as it may + be, I will marry thee, and to that end I have been + with Sir Oliver Martext, the vicar of the next + village, who hath promised to meet me in this place + of the forest and to couple us. + +JAQUES [Aside] I would fain see this meeting. + +AUDREY Well, the gods give us joy! + +TOUCHSTONE Amen. A man may, if he were of a fearful heart, + stagger in this attempt; for here we have no temple + but the wood, no assembly but horn-beasts. But what + though? Courage! As horns are odious, they are + necessary. It is said, 'many a man knows no end of + his goods:' right; many a man has good horns, and + knows no end of them. Well, that is the dowry of + his wife; 'tis none of his own getting. Horns? + Even so. Poor men alone? No, no; the noblest deer + hath them as huge as the rascal. Is the single man + therefore blessed? No: as a walled town is more + worthier than a village, so is the forehead of a + married man more honourable than the bare brow of a + bachelor; and by how much defence is better than no + skill, by so much is a horn more precious than to + want. Here comes Sir Oliver. + + [Enter SIR OLIVER MARTEXT] + + Sir Oliver Martext, you are well met: will you + dispatch us here under this tree, or shall we go + with you to your chapel? + +SIR OLIVER MARTEXT Is there none here to give the woman? + +TOUCHSTONE I will not take her on gift of any man. + +SIR OLIVER MARTEXT Truly, she must be given, or the marriage is not lawful. + +JAQUES [Advancing] + + Proceed, proceed I'll give her. + +TOUCHSTONE Good even, good Master What-ye-call't: how do you, + sir? You are very well met: God 'ild you for your + last company: I am very glad to see you: even a + toy in hand here, sir: nay, pray be covered. + +JAQUES Will you be married, motley? + +TOUCHSTONE As the ox hath his bow, sir, the horse his curb and + the falcon her bells, so man hath his desires; and + as pigeons bill, so wedlock would be nibbling. + +JAQUES And will you, being a man of your breeding, be + married under a bush like a beggar? Get you to + church, and have a good priest that can tell you + what marriage is: this fellow will but join you + together as they join wainscot; then one of you will + prove a shrunk panel and, like green timber, warp, warp. + +TOUCHSTONE [Aside] I am not in the mind but I were better to be + married of him than of another: for he is not like + to marry me well; and not being well married, it + will be a good excuse for me hereafter to leave my wife. + +JAQUES Go thou with me, and let me counsel thee. + +TOUCHSTONE 'Come, sweet Audrey: + We must be married, or we must live in bawdry. + Farewell, good Master Oliver: not,-- + O sweet Oliver, + O brave Oliver, + Leave me not behind thee: but,-- + Wind away, + Begone, I say, + I will not to wedding with thee. + + [Exeunt JAQUES, TOUCHSTONE and AUDREY] + +SIR OLIVER MARTEXT 'Tis no matter: ne'er a fantastical knave of them + all shall flout me out of my calling. + + [Exit] + + + + + AS YOU LIKE IT + + +ACT III + + + +SCENE IV The forest. + + + [Enter ROSALIND and CELIA] + +ROSALIND Never talk to me; I will weep. + +CELIA Do, I prithee; but yet have the grace to consider + that tears do not become a man. + +ROSALIND But have I not cause to weep? + +CELIA As good cause as one would desire; therefore weep. + +ROSALIND His very hair is of the dissembling colour. + +CELIA Something browner than Judas's marry, his kisses are + Judas's own children. + +ROSALIND I' faith, his hair is of a good colour. + +CELIA An excellent colour: your chestnut was ever the only colour. + +ROSALIND And his kissing is as full of sanctity as the touch + of holy bread. + +CELIA He hath bought a pair of cast lips of Diana: a nun + of winter's sisterhood kisses not more religiously; + the very ice of chastity is in them. + +ROSALIND But why did he swear he would come this morning, and + comes not? + +CELIA Nay, certainly, there is no truth in him. + +ROSALIND Do you think so? + +CELIA Yes; I think he is not a pick-purse nor a + horse-stealer, but for his verity in love, I do + think him as concave as a covered goblet or a + worm-eaten nut. + +ROSALIND Not true in love? + +CELIA Yes, when he is in; but I think he is not in. + +ROSALIND You have heard him swear downright he was. + +CELIA 'Was' is not 'is:' besides, the oath of a lover is + no stronger than the word of a tapster; they are + both the confirmer of false reckonings. He attends + here in the forest on the duke your father. + +ROSALIND I met the duke yesterday and had much question with + him: he asked me of what parentage I was; I told + him, of as good as he; so he laughed and let me go. + But what talk we of fathers, when there is such a + man as Orlando? + +CELIA O, that's a brave man! he writes brave verses, + speaks brave words, swears brave oaths and breaks + them bravely, quite traverse, athwart the heart of + his lover; as a puisny tilter, that spurs his horse + but on one side, breaks his staff like a noble + goose: but all's brave that youth mounts and folly + guides. Who comes here? + + [Enter CORIN] + +CORIN Mistress and master, you have oft inquired + After the shepherd that complain'd of love, + Who you saw sitting by me on the turf, + Praising the proud disdainful shepherdess + That was his mistress. + +CELIA Well, and what of him? + +CORIN If you will see a pageant truly play'd, + Between the pale complexion of true love + And the red glow of scorn and proud disdain, + Go hence a little and I shall conduct you, + If you will mark it. + +ROSALIND O, come, let us remove: + The sight of lovers feedeth those in love. + Bring us to this sight, and you shall say + I'll prove a busy actor in their play. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT III + + + +SCENE V Another part of the forest. + + + [Enter SILVIUS and PHEBE] + +SILVIUS Sweet Phebe, do not scorn me; do not, Phebe; + Say that you love me not, but say not so + In bitterness. The common executioner, + Whose heart the accustom'd sight of death makes hard, + Falls not the axe upon the humbled neck + But first begs pardon: will you sterner be + Than he that dies and lives by bloody drops? + + [Enter ROSALIND, CELIA, and CORIN, behind] + +PHEBE I would not be thy executioner: + I fly thee, for I would not injure thee. + Thou tell'st me there is murder in mine eye: + 'Tis pretty, sure, and very probable, + That eyes, that are the frail'st and softest things, + Who shut their coward gates on atomies, + Should be call'd tyrants, butchers, murderers! + Now I do frown on thee with all my heart; + And if mine eyes can wound, now let them kill thee: + Now counterfeit to swoon; why now fall down; + Or if thou canst not, O, for shame, for shame, + Lie not, to say mine eyes are murderers! + Now show the wound mine eye hath made in thee: + Scratch thee but with a pin, and there remains + Some scar of it; lean but upon a rush, + The cicatrice and capable impressure + Thy palm some moment keeps; but now mine eyes, + Which I have darted at thee, hurt thee not, + Nor, I am sure, there is no force in eyes + That can do hurt. + +SILVIUS O dear Phebe, + If ever,--as that ever may be near,-- + You meet in some fresh cheek the power of fancy, + Then shall you know the wounds invisible + That love's keen arrows make. + +PHEBE But till that time + Come not thou near me: and when that time comes, + Afflict me with thy mocks, pity me not; + As till that time I shall not pity thee. + +ROSALIND And why, I pray you? Who might be your mother, + That you insult, exult, and all at once, + Over the wretched? What though you have no beauty,-- + As, by my faith, I see no more in you + Than without candle may go dark to bed-- + Must you be therefore proud and pitiless? + Why, what means this? Why do you look on me? + I see no more in you than in the ordinary + Of nature's sale-work. 'Od's my little life, + I think she means to tangle my eyes too! + No, faith, proud mistress, hope not after it: + 'Tis not your inky brows, your black silk hair, + Your bugle eyeballs, nor your cheek of cream, + That can entame my spirits to your worship. + You foolish shepherd, wherefore do you follow her, + Like foggy south puffing with wind and rain? + You are a thousand times a properer man + Than she a woman: 'tis such fools as you + That makes the world full of ill-favour'd children: + 'Tis not her glass, but you, that flatters her; + And out of you she sees herself more proper + Than any of her lineaments can show her. + But, mistress, know yourself: down on your knees, + And thank heaven, fasting, for a good man's love: + For I must tell you friendly in your ear, + Sell when you can: you are not for all markets: + Cry the man mercy; love him; take his offer: + Foul is most foul, being foul to be a scoffer. + So take her to thee, shepherd: fare you well. + +PHEBE Sweet youth, I pray you, chide a year together: + I had rather hear you chide than this man woo. + +ROSALIND He's fallen in love with your foulness and she'll + fall in love with my anger. If it be so, as fast as + she answers thee with frowning looks, I'll sauce her + with bitter words. Why look you so upon me? + +PHEBE For no ill will I bear you. + +ROSALIND I pray you, do not fall in love with me, + For I am falser than vows made in wine: + Besides, I like you not. If you will know my house, + 'Tis at the tuft of olives here hard by. + Will you go, sister? Shepherd, ply her hard. + Come, sister. Shepherdess, look on him better, + And be not proud: though all the world could see, + None could be so abused in sight as he. + Come, to our flock. + + [Exeunt ROSALIND, CELIA and CORIN] + +PHEBE Dead Shepherd, now I find thy saw of might, + 'Who ever loved that loved not at first sight?' + +SILVIUS Sweet Phebe,-- + +PHEBE Ha, what say'st thou, Silvius? + +SILVIUS Sweet Phebe, pity me. + +PHEBE Why, I am sorry for thee, gentle Silvius. + +SILVIUS Wherever sorrow is, relief would be: + If you do sorrow at my grief in love, + By giving love your sorrow and my grief + Were both extermined. + +PHEBE Thou hast my love: is not that neighbourly? + +SILVIUS I would have you. + +PHEBE Why, that were covetousness. + Silvius, the time was that I hated thee, + And yet it is not that I bear thee love; + But since that thou canst talk of love so well, + Thy company, which erst was irksome to me, + I will endure, and I'll employ thee too: + But do not look for further recompense + Than thine own gladness that thou art employ'd. + +SILVIUS So holy and so perfect is my love, + And I in such a poverty of grace, + That I shall think it a most plenteous crop + To glean the broken ears after the man + That the main harvest reaps: loose now and then + A scatter'd smile, and that I'll live upon. + +PHEBE Know'st now the youth that spoke to me erewhile? + +SILVIUS Not very well, but I have met him oft; + And he hath bought the cottage and the bounds + That the old carlot once was master of. + +PHEBE Think not I love him, though I ask for him: + 'Tis but a peevish boy; yet he talks well; + But what care I for words? yet words do well + When he that speaks them pleases those that hear. + It is a pretty youth: not very pretty: + But, sure, he's proud, and yet his pride becomes him: + He'll make a proper man: the best thing in him + Is his complexion; and faster than his tongue + Did make offence his eye did heal it up. + He is not very tall; yet for his years he's tall: + His leg is but so so; and yet 'tis well: + There was a pretty redness in his lip, + A little riper and more lusty red + Than that mix'd in his cheek; 'twas just the difference + Between the constant red and mingled damask. + There be some women, Silvius, had they mark'd him + In parcels as I did, would have gone near + To fall in love with him; but, for my part, + I love him not nor hate him not; and yet + I have more cause to hate him than to love him: + For what had he to do to chide at me? + He said mine eyes were black and my hair black: + And, now I am remember'd, scorn'd at me: + I marvel why I answer'd not again: + But that's all one; omittance is no quittance. + I'll write to him a very taunting letter, + And thou shalt bear it: wilt thou, Silvius? + +SILVIUS Phebe, with all my heart. + +PHEBE I'll write it straight; + The matter's in my head and in my heart: + I will be bitter with him and passing short. + Go with me, Silvius. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT IV + + + +SCENE I The forest. + + + [Enter ROSALIND, CELIA, and JAQUES] + +JAQUES I prithee, pretty youth, let me be better acquainted + with thee. + +ROSALIND They say you are a melancholy fellow. + +JAQUES I am so; I do love it better than laughing. + +ROSALIND Those that are in extremity of either are abominable + fellows and betray themselves to every modern + censure worse than drunkards. + +JAQUES Why, 'tis good to be sad and say nothing. + +ROSALIND Why then, 'tis good to be a post. + +JAQUES I have neither the scholar's melancholy, which is + emulation, nor the musician's, which is fantastical, + nor the courtier's, which is proud, nor the + soldier's, which is ambitious, nor the lawyer's, + which is politic, nor the lady's, which is nice, nor + the lover's, which is all these: but it is a + melancholy of mine own, compounded of many simples, + extracted from many objects, and indeed the sundry's + contemplation of my travels, in which my often + rumination wraps me m a most humorous sadness. + +ROSALIND A traveller! By my faith, you have great reason to + be sad: I fear you have sold your own lands to see + other men's; then, to have seen much and to have + nothing, is to have rich eyes and poor hands. + +JAQUES Yes, I have gained my experience. + +ROSALIND And your experience makes you sad: I had rather have + a fool to make me merry than experience to make me + sad; and to travel for it too! + + [Enter ORLANDO] + +ORLANDO Good day and happiness, dear Rosalind! + +JAQUES Nay, then, God be wi' you, an you talk in blank verse. + + [Exit] + +ROSALIND Farewell, Monsieur Traveller: look you lisp and + wear strange suits, disable all the benefits of your + own country, be out of love with your nativity and + almost chide God for making you that countenance you + are, or I will scarce think you have swam in a + gondola. Why, how now, Orlando! where have you been + all this while? You a lover! An you serve me such + another trick, never come in my sight more. + +ORLANDO My fair Rosalind, I come within an hour of my promise. + +ROSALIND Break an hour's promise in love! He that will + divide a minute into a thousand parts and break but + a part of the thousandth part of a minute in the + affairs of love, it may be said of him that Cupid + hath clapped him o' the shoulder, but I'll warrant + him heart-whole. + +ORLANDO Pardon me, dear Rosalind. + +ROSALIND Nay, an you be so tardy, come no more in my sight: I + had as lief be wooed of a snail. + +ORLANDO Of a snail? + +ROSALIND Ay, of a snail; for though he comes slowly, he + carries his house on his head; a better jointure, + I think, than you make a woman: besides he brings + his destiny with him. + +ORLANDO What's that? + +ROSALIND Why, horns, which such as you are fain to be + beholding to your wives for: but he comes armed in + his fortune and prevents the slander of his wife. + +ORLANDO Virtue is no horn-maker; and my Rosalind is virtuous. + +ROSALIND And I am your Rosalind. + +CELIA It pleases him to call you so; but he hath a + Rosalind of a better leer than you. + +ROSALIND Come, woo me, woo me, for now I am in a holiday + humour and like enough to consent. What would you + say to me now, an I were your very very Rosalind? + +ORLANDO I would kiss before I spoke. + +ROSALIND Nay, you were better speak first, and when you were + gravelled for lack of matter, you might take + occasion to kiss. Very good orators, when they are + out, they will spit; and for lovers lacking--God + warn us!--matter, the cleanliest shift is to kiss. + +ORLANDO How if the kiss be denied? + +ROSALIND Then she puts you to entreaty, and there begins new matter. + +ORLANDO Who could be out, being before his beloved mistress? + +ROSALIND Marry, that should you, if I were your mistress, or + I should think my honesty ranker than my wit. + +ORLANDO What, of my suit? + +ROSALIND Not out of your apparel, and yet out of your suit. + Am not I your Rosalind? + +ORLANDO I take some joy to say you are, because I would be + talking of her. + +ROSALIND Well in her person I say I will not have you. + +ORLANDO Then in mine own person I die. + +ROSALIND No, faith, die by attorney. The poor world is + almost six thousand years old, and in all this time + there was not any man died in his own person, + videlicit, in a love-cause. Troilus had his brains + dashed out with a Grecian club; yet he did what he + could to die before, and he is one of the patterns + of love. Leander, he would have lived many a fair + year, though Hero had turned nun, if it had not been + for a hot midsummer night; for, good youth, he went + but forth to wash him in the Hellespont and being + taken with the cramp was drowned and the foolish + coroners of that age found it was 'Hero of Sestos.' + But these are all lies: men have died from time to + time and worms have eaten them, but not for love. + +ORLANDO I would not have my right Rosalind of this mind, + for, I protest, her frown might kill me. + +ROSALIND By this hand, it will not kill a fly. But come, now + I will be your Rosalind in a more coming-on + disposition, and ask me what you will. I will grant + it. + +ORLANDO Then love me, Rosalind. + +ROSALIND Yes, faith, will I, Fridays and Saturdays and all. + +ORLANDO And wilt thou have me? + +ROSALIND Ay, and twenty such. + +ORLANDO What sayest thou? + +ROSALIND Are you not good? + +ORLANDO I hope so. + +ROSALIND Why then, can one desire too much of a good thing? + Come, sister, you shall be the priest and marry us. + Give me your hand, Orlando. What do you say, sister? + +ORLANDO Pray thee, marry us. + +CELIA I cannot say the words. + +ROSALIND You must begin, 'Will you, Orlando--' + +CELIA Go to. Will you, Orlando, have to wife this Rosalind? + +ORLANDO I will. + +ROSALIND Ay, but when? + +ORLANDO Why now; as fast as she can marry us. + +ROSALIND Then you must say 'I take thee, Rosalind, for wife.' + +ORLANDO I take thee, Rosalind, for wife. + +ROSALIND I might ask you for your commission; but I do take + thee, Orlando, for my husband: there's a girl goes + before the priest; and certainly a woman's thought + runs before her actions. + +ORLANDO So do all thoughts; they are winged. + +ROSALIND Now tell me how long you would have her after you + have possessed her. + +ORLANDO For ever and a day. + +ROSALIND Say 'a day,' without the 'ever.' No, no, Orlando; + men are April when they woo, December when they wed: + maids are May when they are maids, but the sky + changes when they are wives. I will be more jealous + of thee than a Barbary cock-pigeon over his hen, + more clamorous than a parrot against rain, more + new-fangled than an ape, more giddy in my desires + than a monkey: I will weep for nothing, like Diana + in the fountain, and I will do that when you are + disposed to be merry; I will laugh like a hyen, and + that when thou art inclined to sleep. + +ORLANDO But will my Rosalind do so? + +ROSALIND By my life, she will do as I do. + +ORLANDO O, but she is wise. + +ROSALIND Or else she could not have the wit to do this: the + wiser, the waywarder: make the doors upon a woman's + wit and it will out at the casement; shut that and + 'twill out at the key-hole; stop that, 'twill fly + with the smoke out at the chimney. + +ORLANDO A man that had a wife with such a wit, he might say + 'Wit, whither wilt?' + +ROSALIND Nay, you might keep that cheque for it till you met + your wife's wit going to your neighbour's bed. + +ORLANDO And what wit could wit have to excuse that? + +ROSALIND Marry, to say she came to seek you there. You shall + never take her without her answer, unless you take + her without her tongue. O, that woman that cannot + make her fault her husband's occasion, let her + never nurse her child herself, for she will breed + it like a fool! + +ORLANDO For these two hours, Rosalind, I will leave thee. + +ROSALIND Alas! dear love, I cannot lack thee two hours. + +ORLANDO I must attend the duke at dinner: by two o'clock I + will be with thee again. + +ROSALIND Ay, go your ways, go your ways; I knew what you + would prove: my friends told me as much, and I + thought no less: that flattering tongue of yours + won me: 'tis but one cast away, and so, come, + death! Two o'clock is your hour? + +ORLANDO Ay, sweet Rosalind. + +ROSALIND By my troth, and in good earnest, and so God mend + me, and by all pretty oaths that are not dangerous, + if you break one jot of your promise or come one + minute behind your hour, I will think you the most + pathetical break-promise and the most hollow lover + and the most unworthy of her you call Rosalind that + may be chosen out of the gross band of the + unfaithful: therefore beware my censure and keep + your promise. + +ORLANDO With no less religion than if thou wert indeed my + Rosalind: so adieu. + +ROSALIND Well, Time is the old justice that examines all such + offenders, and let Time try: adieu. + + [Exit ORLANDO] + +CELIA You have simply misused our sex in your love-prate: + we must have your doublet and hose plucked over your + head, and show the world what the bird hath done to + her own nest. + +ROSALIND O coz, coz, coz, my pretty little coz, that thou + didst know how many fathom deep I am in love! But + it cannot be sounded: my affection hath an unknown + bottom, like the bay of Portugal. + +CELIA Or rather, bottomless, that as fast as you pour + affection in, it runs out. + +ROSALIND No, that same wicked bastard of Venus that was begot + of thought, conceived of spleen and born of madness, + that blind rascally boy that abuses every one's eyes + because his own are out, let him be judge how deep I + am in love. I'll tell thee, Aliena, I cannot be out + of the sight of Orlando: I'll go find a shadow and + sigh till he come. + +CELIA And I'll sleep. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT IV + + + +SCENE II The forest. + + + [Enter JAQUES, Lords, and Foresters] + +JAQUES Which is he that killed the deer? + +A Lord Sir, it was I. + +JAQUES Let's present him to the duke, like a Roman + conqueror; and it would do well to set the deer's + horns upon his head, for a branch of victory. Have + you no song, forester, for this purpose? + +Forester Yes, sir. + +JAQUES Sing it: 'tis no matter how it be in tune, so it + make noise enough. + + SONG. +Forester What shall he have that kill'd the deer? + His leather skin and horns to wear. + Then sing him home; + + [The rest shall bear this burden] + + Take thou no scorn to wear the horn; + It was a crest ere thou wast born: + Thy father's father wore it, + And thy father bore it: + The horn, the horn, the lusty horn + Is not a thing to laugh to scorn. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT IV + + + +SCENE III The forest. + + + [Enter ROSALIND and CELIA] + +ROSALIND How say you now? Is it not past two o'clock? and + here much Orlando! + +CELIA I warrant you, with pure love and troubled brain, he + hath ta'en his bow and arrows and is gone forth to + sleep. Look, who comes here. + + [Enter SILVIUS] + +SILVIUS My errand is to you, fair youth; + My gentle Phebe bid me give you this: + I know not the contents; but, as I guess + By the stern brow and waspish action + Which she did use as she was writing of it, + It bears an angry tenor: pardon me: + I am but as a guiltless messenger. + +ROSALIND Patience herself would startle at this letter + And play the swaggerer; bear this, bear all: + She says I am not fair, that I lack manners; + She calls me proud, and that she could not love me, + Were man as rare as phoenix. 'Od's my will! + Her love is not the hare that I do hunt: + Why writes she so to me? Well, shepherd, well, + This is a letter of your own device. + +SILVIUS No, I protest, I know not the contents: + Phebe did write it. + +ROSALIND Come, come, you are a fool + And turn'd into the extremity of love. + I saw her hand: she has a leathern hand. + A freestone-colour'd hand; I verily did think + That her old gloves were on, but 'twas her hands: + She has a huswife's hand; but that's no matter: + I say she never did invent this letter; + This is a man's invention and his hand. + +SILVIUS Sure, it is hers. + +ROSALIND Why, 'tis a boisterous and a cruel style. + A style for-challengers; why, she defies me, + Like Turk to Christian: women's gentle brain + Could not drop forth such giant-rude invention + Such Ethiope words, blacker in their effect + Than in their countenance. Will you hear the letter? + +SILVIUS So please you, for I never heard it yet; + Yet heard too much of Phebe's cruelty. + +ROSALIND She Phebes me: mark how the tyrant writes. + + [Reads] + + Art thou god to shepherd turn'd, + That a maiden's heart hath burn'd? + Can a woman rail thus? + +SILVIUS Call you this railing? + +ROSALIND [Reads] + + Why, thy godhead laid apart, + Warr'st thou with a woman's heart? + Did you ever hear such railing? + Whiles the eye of man did woo me, + That could do no vengeance to me. + Meaning me a beast. + If the scorn of your bright eyne + Have power to raise such love in mine, + Alack, in me what strange effect + Would they work in mild aspect! + Whiles you chid me, I did love; + How then might your prayers move! + He that brings this love to thee + Little knows this love in me: + And by him seal up thy mind; + Whether that thy youth and kind + Will the faithful offer take + Of me and all that I can make; + Or else by him my love deny, + And then I'll study how to die. + +SILVIUS Call you this chiding? + +CELIA Alas, poor shepherd! + +ROSALIND Do you pity him? no, he deserves no pity. Wilt + thou love such a woman? What, to make thee an + instrument and play false strains upon thee! not to + be endured! Well, go your way to her, for I see + love hath made thee a tame snake, and say this to + her: that if she love me, I charge her to love + thee; if she will not, I will never have her unless + thou entreat for her. If you be a true lover, + hence, and not a word; for here comes more company. + + [Exit SILVIUS] + + [Enter OLIVER] + +OLIVER Good morrow, fair ones: pray you, if you know, + Where in the purlieus of this forest stands + A sheep-cote fenced about with olive trees? + +CELIA West of this place, down in the neighbour bottom: + The rank of osiers by the murmuring stream + Left on your right hand brings you to the place. + But at this hour the house doth keep itself; + There's none within. + +OLIVER If that an eye may profit by a tongue, + Then should I know you by description; + Such garments and such years: 'The boy is fair, + Of female favour, and bestows himself + Like a ripe sister: the woman low + And browner than her brother.' Are not you + The owner of the house I did inquire for? + +CELIA It is no boast, being ask'd, to say we are. + +OLIVER Orlando doth commend him to you both, + And to that youth he calls his Rosalind + He sends this bloody napkin. Are you he? + +ROSALIND I am: what must we understand by this? + +OLIVER Some of my shame; if you will know of me + What man I am, and how, and why, and where + This handkercher was stain'd. + +CELIA I pray you, tell it. + +OLIVER When last the young Orlando parted from you + He left a promise to return again + Within an hour, and pacing through the forest, + Chewing the food of sweet and bitter fancy, + Lo, what befell! he threw his eye aside, + And mark what object did present itself: + Under an oak, whose boughs were moss'd with age + And high top bald with dry antiquity, + A wretched ragged man, o'ergrown with hair, + Lay sleeping on his back: about his neck + A green and gilded snake had wreathed itself, + Who with her head nimble in threats approach'd + The opening of his mouth; but suddenly, + Seeing Orlando, it unlink'd itself, + And with indented glides did slip away + Into a bush: under which bush's shade + A lioness, with udders all drawn dry, + Lay couching, head on ground, with catlike watch, + When that the sleeping man should stir; for 'tis + The royal disposition of that beast + To prey on nothing that doth seem as dead: + This seen, Orlando did approach the man + And found it was his brother, his elder brother. + +CELIA O, I have heard him speak of that same brother; + And he did render him the most unnatural + That lived amongst men. + +OLIVER And well he might so do, + For well I know he was unnatural. + +ROSALIND But, to Orlando: did he leave him there, + Food to the suck'd and hungry lioness? + +OLIVER Twice did he turn his back and purposed so; + But kindness, nobler ever than revenge, + And nature, stronger than his just occasion, + Made him give battle to the lioness, + Who quickly fell before him: in which hurtling + From miserable slumber I awaked. + +CELIA Are you his brother? + +ROSALIND Wast you he rescued? + +CELIA Was't you that did so oft contrive to kill him? + +OLIVER 'Twas I; but 'tis not I I do not shame + To tell you what I was, since my conversion + So sweetly tastes, being the thing I am. + +ROSALIND But, for the bloody napkin? + +OLIVER By and by. + When from the first to last betwixt us two + Tears our recountments had most kindly bathed, + As how I came into that desert place:-- + In brief, he led me to the gentle duke, + Who gave me fresh array and entertainment, + Committing me unto my brother's love; + Who led me instantly unto his cave, + There stripp'd himself, and here upon his arm + The lioness had torn some flesh away, + Which all this while had bled; and now he fainted + And cried, in fainting, upon Rosalind. + Brief, I recover'd him, bound up his wound; + And, after some small space, being strong at heart, + He sent me hither, stranger as I am, + To tell this story, that you might excuse + His broken promise, and to give this napkin + Dyed in his blood unto the shepherd youth + That he in sport doth call his Rosalind. + + [ROSALIND swoons] + +CELIA Why, how now, Ganymede! sweet Ganymede! + +OLIVER Many will swoon when they do look on blood. + +CELIA There is more in it. Cousin Ganymede! + +OLIVER Look, he recovers. + +ROSALIND I would I were at home. + +CELIA We'll lead you thither. + I pray you, will you take him by the arm? + +OLIVER Be of good cheer, youth: you a man! you lack a + man's heart. + +ROSALIND I do so, I confess it. Ah, sirrah, a body would + think this was well counterfeited! I pray you, tell + your brother how well I counterfeited. Heigh-ho! + +OLIVER This was not counterfeit: there is too great + testimony in your complexion that it was a passion + of earnest. + +ROSALIND Counterfeit, I assure you. + +OLIVER Well then, take a good heart and counterfeit to be a man. + +ROSALIND So I do: but, i' faith, I should have been a woman by right. + +CELIA Come, you look paler and paler: pray you, draw + homewards. Good sir, go with us. + +OLIVER That will I, for I must bear answer back + How you excuse my brother, Rosalind. + +ROSALIND I shall devise something: but, I pray you, commend + my counterfeiting to him. Will you go? + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT V + + + +SCENE I The forest. + + + [Enter TOUCHSTONE and AUDREY] + +TOUCHSTONE We shall find a time, Audrey; patience, gentle Audrey. + +AUDREY Faith, the priest was good enough, for all the old + gentleman's saying. + +TOUCHSTONE A most wicked Sir Oliver, Audrey, a most vile + Martext. But, Audrey, there is a youth here in the + forest lays claim to you. + +AUDREY Ay, I know who 'tis; he hath no interest in me in + the world: here comes the man you mean. + +TOUCHSTONE It is meat and drink to me to see a clown: by my + troth, we that have good wits have much to answer + for; we shall be flouting; we cannot hold. + + [Enter WILLIAM] + +WILLIAM Good even, Audrey. + +AUDREY God ye good even, William. + +WILLIAM And good even to you, sir. + +TOUCHSTONE Good even, gentle friend. Cover thy head, cover thy + head; nay, prithee, be covered. How old are you, friend? + +WILLIAM Five and twenty, sir. + +TOUCHSTONE A ripe age. Is thy name William? + +WILLIAM William, sir. + +TOUCHSTONE A fair name. Wast born i' the forest here? + +WILLIAM Ay, sir, I thank God. + +TOUCHSTONE 'Thank God;' a good answer. Art rich? + +WILLIAM Faith, sir, so so. + +TOUCHSTONE 'So so' is good, very good, very excellent good; and + yet it is not; it is but so so. Art thou wise? + +WILLIAM Ay, sir, I have a pretty wit. + +TOUCHSTONE Why, thou sayest well. I do now remember a saying, + 'The fool doth think he is wise, but the wise man + knows himself to be a fool.' The heathen + philosopher, when he had a desire to eat a grape, + would open his lips when he put it into his mouth; + meaning thereby that grapes were made to eat and + lips to open. You do love this maid? + +WILLIAM I do, sir. + +TOUCHSTONE Give me your hand. Art thou learned? + +WILLIAM No, sir. + +TOUCHSTONE Then learn this of me: to have, is to have; for it + is a figure in rhetoric that drink, being poured out + of a cup into a glass, by filling the one doth empty + the other; for all your writers do consent that ipse + is he: now, you are not ipse, for I am he. + +WILLIAM Which he, sir? + +TOUCHSTONE He, sir, that must marry this woman. Therefore, you + clown, abandon,--which is in the vulgar leave,--the + society,--which in the boorish is company,--of this + female,--which in the common is woman; which + together is, abandon the society of this female, or, + clown, thou perishest; or, to thy better + understanding, diest; or, to wit I kill thee, make + thee away, translate thy life into death, thy + liberty into bondage: I will deal in poison with + thee, or in bastinado, or in steel; I will bandy + with thee in faction; I will o'errun thee with + policy; I will kill thee a hundred and fifty ways: + therefore tremble and depart. + +AUDREY Do, good William. + +WILLIAM God rest you merry, sir. + + [Exit] + + [Enter CORIN] + +CORIN Our master and mistress seeks you; come, away, away! + +TOUCHSTONE Trip, Audrey! trip, Audrey! I attend, I attend. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT V + + + +SCENE II The forest. + + + [Enter ORLANDO and OLIVER] + +ORLANDO Is't possible that on so little acquaintance you + should like her? that but seeing you should love + her? and loving woo? and, wooing, she should + grant? and will you persever to enjoy her? + +OLIVER Neither call the giddiness of it in question, the + poverty of her, the small acquaintance, my sudden + wooing, nor her sudden consenting; but say with me, + I love Aliena; say with her that she loves me; + consent with both that we may enjoy each other: it + shall be to your good; for my father's house and all + the revenue that was old Sir Rowland's will I + estate upon you, and here live and die a shepherd. + +ORLANDO You have my consent. Let your wedding be to-morrow: + thither will I invite the duke and all's contented + followers. Go you and prepare Aliena; for look + you, here comes my Rosalind. + + [Enter ROSALIND] + +ROSALIND God save you, brother. + +OLIVER And you, fair sister. + + [Exit] + +ROSALIND O, my dear Orlando, how it grieves me to see thee + wear thy heart in a scarf! + +ORLANDO It is my arm. + +ROSALIND I thought thy heart had been wounded with the claws + of a lion. + +ORLANDO Wounded it is, but with the eyes of a lady. + +ROSALIND Did your brother tell you how I counterfeited to + swoon when he showed me your handkerchief? + +ORLANDO Ay, and greater wonders than that. + +ROSALIND O, I know where you are: nay, 'tis true: there was + never any thing so sudden but the fight of two rams + and Caesar's thrasonical brag of 'I came, saw, and + overcame:' for your brother and my sister no sooner + met but they looked, no sooner looked but they + loved, no sooner loved but they sighed, no sooner + sighed but they asked one another the reason, no + sooner knew the reason but they sought the remedy; + and in these degrees have they made a pair of stairs + to marriage which they will climb incontinent, or + else be incontinent before marriage: they are in + the very wrath of love and they will together; clubs + cannot part them. + +ORLANDO They shall be married to-morrow, and I will bid the + duke to the nuptial. But, O, how bitter a thing it + is to look into happiness through another man's + eyes! By so much the more shall I to-morrow be at + the height of heart-heaviness, by how much I shall + think my brother happy in having what he wishes for. + +ROSALIND Why then, to-morrow I cannot serve your turn for Rosalind? + +ORLANDO I can live no longer by thinking. + +ROSALIND I will weary you then no longer with idle talking. + Know of me then, for now I speak to some purpose, + that I know you are a gentleman of good conceit: I + speak not this that you should bear a good opinion + of my knowledge, insomuch I say I know you are; + neither do I labour for a greater esteem than may in + some little measure draw a belief from you, to do + yourself good and not to grace me. Believe then, if + you please, that I can do strange things: I have, + since I was three year old, conversed with a + magician, most profound in his art and yet not + damnable. If you do love Rosalind so near the heart + as your gesture cries it out, when your brother + marries Aliena, shall you marry her: I know into + what straits of fortune she is driven; and it is + not impossible to me, if it appear not inconvenient + to you, to set her before your eyes tomorrow human + as she is and without any danger. + +ORLANDO Speakest thou in sober meanings? + +ROSALIND By my life, I do; which I tender dearly, though I + say I am a magician. Therefore, put you in your + best array: bid your friends; for if you will be + married to-morrow, you shall, and to Rosalind, if you will. + + [Enter SILVIUS and PHEBE] + + Look, here comes a lover of mine and a lover of hers. + +PHEBE Youth, you have done me much ungentleness, + To show the letter that I writ to you. + +ROSALIND I care not if I have: it is my study + To seem despiteful and ungentle to you: + You are there followed by a faithful shepherd; + Look upon him, love him; he worships you. + +PHEBE Good shepherd, tell this youth what 'tis to love. + +SILVIUS It is to be all made of sighs and tears; + And so am I for Phebe. + +PHEBE And I for Ganymede. + +ORLANDO And I for Rosalind. + +ROSALIND And I for no woman. + +SILVIUS It is to be all made of faith and service; + And so am I for Phebe. + +PHEBE And I for Ganymede. + +ORLANDO And I for Rosalind. + +ROSALIND And I for no woman. + +SILVIUS It is to be all made of fantasy, + All made of passion and all made of wishes, + All adoration, duty, and observance, + All humbleness, all patience and impatience, + All purity, all trial, all observance; + And so am I for Phebe. + +PHEBE And so am I for Ganymede. + +ORLANDO And so am I for Rosalind. + +ROSALIND And so am I for no woman. + +PHEBE If this be so, why blame you me to love you? + +SILVIUS If this be so, why blame you me to love you? + +ORLANDO If this be so, why blame you me to love you? + +ROSALIND Who do you speak to, 'Why blame you me to love you?' + +ORLANDO To her that is not here, nor doth not hear. + +ROSALIND Pray you, no more of this; 'tis like the howling + of Irish wolves against the moon. + + [To SILVIUS] + + I will help you, if I can: + + [To PHEBE] + + I would love you, if I could. To-morrow meet me all together. + + [To PHEBE] + + I will marry you, if ever I marry woman, and I'll be + married to-morrow: + + [To ORLANDO] + + I will satisfy you, if ever I satisfied man, and you + shall be married to-morrow: + + [To SILVIUS] + + I will content you, if what pleases you contents + you, and you shall be married to-morrow. + + [To ORLANDO] + + As you love Rosalind, meet: + + [To SILVIUS] + + as you love Phebe, meet: and as I love no woman, + I'll meet. So fare you well: I have left you commands. + +SILVIUS I'll not fail, if I live. + +PHEBE Nor I. + +ORLANDO Nor I. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT V + + + +SCENE III The forest. + + + [Enter TOUCHSTONE and AUDREY] + +TOUCHSTONE To-morrow is the joyful day, Audrey; to-morrow will + we be married. + +AUDREY I do desire it with all my heart; and I hope it is + no dishonest desire to desire to be a woman of the + world. Here comes two of the banished duke's pages. + + [Enter two Pages] + +First Page Well met, honest gentleman. + +TOUCHSTONE By my troth, well met. Come, sit, sit, and a song. + +Second Page We are for you: sit i' the middle. + +First Page Shall we clap into't roundly, without hawking or + spitting or saying we are hoarse, which are the only + prologues to a bad voice? + +Second Page I'faith, i'faith; and both in a tune, like two + gipsies on a horse. + + SONG. + It was a lover and his lass, + With a hey, and a ho, and a hey nonino, + That o'er the green corn-field did pass + In the spring time, the only pretty ring time, + When birds do sing, hey ding a ding, ding: + Sweet lovers love the spring. + + Between the acres of the rye, + With a hey, and a ho, and a hey nonino + These pretty country folks would lie, + In spring time, &c. + + This carol they began that hour, + With a hey, and a ho, and a hey nonino, + How that a life was but a flower + In spring time, &c. + + And therefore take the present time, + With a hey, and a ho, and a hey nonino; + For love is crowned with the prime + In spring time, &c. + +TOUCHSTONE Truly, young gentlemen, though there was no great + matter in the ditty, yet the note was very + untuneable. + +First Page You are deceived, sir: we kept time, we lost not our time. + +TOUCHSTONE By my troth, yes; I count it but time lost to hear + such a foolish song. God be wi' you; and God mend + your voices! Come, Audrey. + + [Exeunt] + + + + + AS YOU LIKE IT + + +ACT V + + + +SCENE IV The forest. + + + [Enter DUKE SENIOR, AMIENS, JAQUES, ORLANDO, OLIVER, + and CELIA] + +DUKE SENIOR Dost thou believe, Orlando, that the boy + Can do all this that he hath promised? + +ORLANDO I sometimes do believe, and sometimes do not; + As those that fear they hope, and know they fear. + + [Enter ROSALIND, SILVIUS, and PHEBE] + +ROSALIND Patience once more, whiles our compact is urged: + You say, if I bring in your Rosalind, + You will bestow her on Orlando here? + +DUKE SENIOR That would I, had I kingdoms to give with her. + +ROSALIND And you say, you will have her, when I bring her? + +ORLANDO That would I, were I of all kingdoms king. + +ROSALIND You say, you'll marry me, if I be willing? + +PHEBE That will I, should I die the hour after. + +ROSALIND But if you do refuse to marry me, + You'll give yourself to this most faithful shepherd? + +PHEBE So is the bargain. + +ROSALIND You say, that you'll have Phebe, if she will? + +SILVIUS Though to have her and death were both one thing. + +ROSALIND I have promised to make all this matter even. + Keep you your word, O duke, to give your daughter; + You yours, Orlando, to receive his daughter: + Keep your word, Phebe, that you'll marry me, + Or else refusing me, to wed this shepherd: + Keep your word, Silvius, that you'll marry her. + If she refuse me: and from hence I go, + To make these doubts all even. + + [Exeunt ROSALIND and CELIA] + +DUKE SENIOR I do remember in this shepherd boy + Some lively touches of my daughter's favour. + +ORLANDO My lord, the first time that I ever saw him + Methought he was a brother to your daughter: + But, my good lord, this boy is forest-born, + And hath been tutor'd in the rudiments + Of many desperate studies by his uncle, + Whom he reports to be a great magician, + Obscured in the circle of this forest. + + [Enter TOUCHSTONE and AUDREY] + +JAQUES There is, sure, another flood toward, and these + couples are coming to the ark. Here comes a pair of + very strange beasts, which in all tongues are called fools. + +TOUCHSTONE Salutation and greeting to you all! + +JAQUES Good my lord, bid him welcome: this is the + motley-minded gentleman that I have so often met in + the forest: he hath been a courtier, he swears. + +TOUCHSTONE If any man doubt that, let him put me to my + purgation. I have trod a measure; I have flattered + a lady; I have been politic with my friend, smooth + with mine enemy; I have undone three tailors; I have + had four quarrels, and like to have fought one. + +JAQUES And how was that ta'en up? + +TOUCHSTONE Faith, we met, and found the quarrel was upon the + seventh cause. + +JAQUES How seventh cause? Good my lord, like this fellow. + +DUKE SENIOR I like him very well. + +TOUCHSTONE God 'ild you, sir; I desire you of the like. I + press in here, sir, amongst the rest of the country + copulatives, to swear and to forswear: according as + marriage binds and blood breaks: a poor virgin, + sir, an ill-favoured thing, sir, but mine own; a poor + humour of mine, sir, to take that that no man else + will: rich honesty dwells like a miser, sir, in a + poor house; as your pearl in your foul oyster. + +DUKE SENIOR By my faith, he is very swift and sententious. + +TOUCHSTONE According to the fool's bolt, sir, and such dulcet diseases. + +JAQUES But, for the seventh cause; how did you find the + quarrel on the seventh cause? + +TOUCHSTONE Upon a lie seven times removed:--bear your body more + seeming, Audrey:--as thus, sir. I did dislike the + cut of a certain courtier's beard: he sent me word, + if I said his beard was not cut well, he was in the + mind it was: this is called the Retort Courteous. + If I sent him word again 'it was not well cut,' he + would send me word, he cut it to please himself: + this is called the Quip Modest. If again 'it was + not well cut,' he disabled my judgment: this is + called the Reply Churlish. If again 'it was not + well cut,' he would answer, I spake not true: this + is called the Reproof Valiant. If again 'it was not + well cut,' he would say I lied: this is called the + Counter-cheque Quarrelsome: and so to the Lie + Circumstantial and the Lie Direct. + +JAQUES And how oft did you say his beard was not well cut? + +TOUCHSTONE I durst go no further than the Lie Circumstantial, + nor he durst not give me the Lie Direct; and so we + measured swords and parted. + +JAQUES Can you nominate in order now the degrees of the lie? + +TOUCHSTONE O sir, we quarrel in print, by the book; as you have + books for good manners: I will name you the degrees. + The first, the Retort Courteous; the second, the + Quip Modest; the third, the Reply Churlish; the + fourth, the Reproof Valiant; the fifth, the + Countercheque Quarrelsome; the sixth, the Lie with + Circumstance; the seventh, the Lie Direct. All + these you may avoid but the Lie Direct; and you may + avoid that too, with an If. I knew when seven + justices could not take up a quarrel, but when the + parties were met themselves, one of them thought but + of an If, as, 'If you said so, then I said so;' and + they shook hands and swore brothers. Your If is the + only peacemaker; much virtue in If. + +JAQUES Is not this a rare fellow, my lord? he's as good at + any thing and yet a fool. + +DUKE SENIOR He uses his folly like a stalking-horse and under + the presentation of that he shoots his wit. + + [Enter HYMEN, ROSALIND, and CELIA] + + [Still Music] + +HYMEN Then is there mirth in heaven, + When earthly things made even + Atone together. + Good duke, receive thy daughter + Hymen from heaven brought her, + Yea, brought her hither, + That thou mightst join her hand with his + Whose heart within his bosom is. + +ROSALIND [To DUKE SENIOR] To you I give myself, for I am yours. + + [To ORLANDO] + + To you I give myself, for I am yours. + +DUKE SENIOR If there be truth in sight, you are my daughter. + +ORLANDO If there be truth in sight, you are my Rosalind. + +PHEBE If sight and shape be true, + Why then, my love adieu! + +ROSALIND I'll have no father, if you be not he: + I'll have no husband, if you be not he: + Nor ne'er wed woman, if you be not she. + +HYMEN Peace, ho! I bar confusion: + 'Tis I must make conclusion + Of these most strange events: + Here's eight that must take hands + To join in Hymen's bands, + If truth holds true contents. + You and you no cross shall part: + You and you are heart in heart + You to his love must accord, + Or have a woman to your lord: + You and you are sure together, + As the winter to foul weather. + Whiles a wedlock-hymn we sing, + Feed yourselves with questioning; + That reason wonder may diminish, + How thus we met, and these things finish. + + SONG. + Wedding is great Juno's crown: + O blessed bond of board and bed! + 'Tis Hymen peoples every town; + High wedlock then be honoured: + Honour, high honour and renown, + To Hymen, god of every town! + +DUKE SENIOR O my dear niece, welcome thou art to me! + Even daughter, welcome, in no less degree. + +PHEBE I will not eat my word, now thou art mine; + Thy faith my fancy to thee doth combine. + + [Enter JAQUES DE BOYS] + +JAQUES DE BOYS Let me have audience for a word or two: + I am the second son of old Sir Rowland, + That bring these tidings to this fair assembly. + Duke Frederick, hearing how that every day + Men of great worth resorted to this forest, + Address'd a mighty power; which were on foot, + In his own conduct, purposely to take + His brother here and put him to the sword: + And to the skirts of this wild wood he came; + Where meeting with an old religious man, + After some question with him, was converted + Both from his enterprise and from the world, + His crown bequeathing to his banish'd brother, + And all their lands restored to them again + That were with him exiled. This to be true, + I do engage my life. + +DUKE SENIOR Welcome, young man; + Thou offer'st fairly to thy brothers' wedding: + To one his lands withheld, and to the other + A land itself at large, a potent dukedom. + First, in this forest, let us do those ends + That here were well begun and well begot: + And after, every of this happy number + That have endured shrewd days and nights with us + Shall share the good of our returned fortune, + According to the measure of their states. + Meantime, forget this new-fall'n dignity + And fall into our rustic revelry. + Play, music! And you, brides and bridegrooms all, + With measure heap'd in joy, to the measures fall. + +JAQUES Sir, by your patience. If I heard you rightly, + The duke hath put on a religious life + And thrown into neglect the pompous court? + +JAQUES DE BOYS He hath. + +JAQUES To him will I : out of these convertites + There is much matter to be heard and learn'd. + + [To DUKE SENIOR] + + You to your former honour I bequeath; + Your patience and your virtue well deserves it: + + [To ORLANDO] + + You to a love that your true faith doth merit: + + [To OLIVER] + + You to your land and love and great allies: + + [To SILVIUS] + + You to a long and well-deserved bed: + + [To TOUCHSTONE] + + And you to wrangling; for thy loving voyage + Is but for two months victuall'd. So, to your pleasures: + I am for other than for dancing measures. + +DUKE SENIOR Stay, Jaques, stay. + +JAQUES To see no pastime I what you would have + I'll stay to know at your abandon'd cave. + + [Exit] + +DUKE SENIOR Proceed, proceed: we will begin these rites, + As we do trust they'll end, in true delights. + + [A dance] + + + + + AS YOU LIKE IT + + EPILOGUE + + +ROSALIND It is not the fashion to see the lady the epilogue; + but it is no more unhandsome than to see the lord + the prologue. If it be true that good wine needs + no bush, 'tis true that a good play needs no + epilogue; yet to good wine they do use good bushes, + and good plays prove the better by the help of good + epilogues. What a case am I in then, that am + neither a good epilogue nor cannot insinuate with + you in the behalf of a good play! I am not + furnished like a beggar, therefore to beg will not + become me: my way is to conjure you; and I'll begin + with the women. I charge you, O women, for the love + you bear to men, to like as much of this play as + please you: and I charge you, O men, for the love + you bear to women--as I perceive by your simpering, + none of you hates them--that between you and the + women the play may please. If I were a woman I + would kiss as many of you as had beards that pleased + me, complexions that liked me and breaths that I + defied not: and, I am sure, as many as have good + beards or good faces or sweet breaths will, for my + kind offer, when I make curtsy, bid me farewell. + + [Exeunt] diff --git a/vendor/snap/data/baddata1.snappy b/vendor/snap/data/baddata1.snappy new file mode 100644 index 0000000000..99d970fb4b Binary files /dev/null and b/vendor/snap/data/baddata1.snappy differ diff --git a/vendor/snap/data/baddata2.snappy b/vendor/snap/data/baddata2.snappy new file mode 100644 index 0000000000..8f5cb13ee2 Binary files /dev/null and b/vendor/snap/data/baddata2.snappy differ diff --git a/vendor/snap/data/baddata3.snappy b/vendor/snap/data/baddata3.snappy new file mode 100644 index 0000000000..774aead4dc Binary files /dev/null and b/vendor/snap/data/baddata3.snappy differ diff --git a/vendor/snap/data/fireworks.jpeg b/vendor/snap/data/fireworks.jpeg new file mode 100644 index 0000000000..078cf1755d Binary files /dev/null and b/vendor/snap/data/fireworks.jpeg differ diff --git a/vendor/snap/data/geo.protodata b/vendor/snap/data/geo.protodata new file mode 100644 index 0000000000..c4e3e0d8ae Binary files /dev/null and b/vendor/snap/data/geo.protodata differ diff --git a/vendor/snap/data/html b/vendor/snap/data/html new file mode 100644 index 0000000000..ef768ccde9 --- /dev/null +++ b/vendor/snap/data/html @@ -0,0 +1 @@ + content: @ 1099872000000000: 'HTTP/1.1 200 OK\r\nX-Google-Crawl-Date: Mon, 08 Nov 2004 17:22:09 GMT\r\nContent-Type: text/html\r\nConnection: close\r\nX-Powered-By: PHP/4.3.8\r\nServer: Apache/1.3.31 (Unix) mod_gzip/1.3.19.1a PHP/4.3.8\r\nDate: Mon, 08 Nov 2004 17:19:07 GMT\r\n\r\n \r\n\r\n\r\n\r\n\r\n\nMicro Achat : Ordinateurs, PDA - Toute l\'informatique avec 01Informatique, L\'Ordinateur Individuel, Micro Hebdo, D\351cision Informatique et 01R\351seaux\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    Derni\350re mise \340 jour de cette page : lundi 8 novembre 2004  |  16:45
    \r\n \r\n\r\n\r\n\r\n\t\r\n\r\n\t\t\r\n\r\n\t\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n\t\t\r\n\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t

    \r\n\r\n\r\n\r\n


    \r\n\r\n\r\n\r\n
    \n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
    \"\"
    Imagerie 
    \"\"\n\t\t\t\t\t\t\t\tLG L1720B\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    332.89 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tAcer Veriton 7600G\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    705 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tShuttle SN95G5\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    375 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tAsus A7N8X-E Deluxe\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    91.99 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tThermalright SP-94\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    49 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
    \"\"
    1 \">\"PC Look
    2 \">\"Atelier Informatique
    3 \">\"Zanax Multim\351dia
    4 \">\"MISTEROOPS
    5 \">\"168 Golden Avenue
    6 \">\"microchoix
    7 \">\"e-Soph
    8 \">\"PC Price Club
    9 \">\"PC 77
    10 \">\"Web In Informatique
    \n\t\t\t\t
    \n\t\t\t\t
    \r\n \r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t
    \n\n\n\n\n\n\n\n\n\n\n\n\n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \r\n\r\n\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n

    \r\n\t\t\t

    \r\n\t\t\t

    \r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\r\n \r\n \r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    CD et DVD bient\364t insensibles aux rayures
    OpenOffice gagne son service
    La messagerie en cinq minutes selon Ipswitch
    > toutes les news


    \r\n\t\t
    \r\n \r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Recevez chaque jour l\'actualit\351 des produits et des promos
    \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n\r\n\r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Entreprise
    \r\n\t\t\t\tQuand le billet papier s\'envole vers la d\351mat\351rialisation


    Trucs et astuces
    \r\n\t\t\t\tD\351pannez Windows XP


    Conso
    \r\n\t\t\t\tVos photos sur papier imprimante ou labo ?


    Produits & Tests
    \r\n\t\t\t\t5 programmes d\222encodage vid\351o gratuits


    \r\n\t\t
    \r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t

    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\r\n\r\n\r\n\t\t\t\r\n\r\n\r\n\r\n\t\t\t\t\r\n
    \r\n
    \r\nPortable
    \r\nUn nouvel ultra portable r\351alis\351 par Nec
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nLe Versa S940 a un format r\351duit, mais ses performances sont \340 la hauteur.
    \r\n\340 partir de 1663 \200\r\n
    \r\n
    \r\nPortable
    \r\nAsus pr\351sente trois petits nouveaux dans la gamme A3N
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nCes trois portables Centrino int\350grent, entre autres, une webcam et un contr\364leur Wi-Fi.
    \r\n\340 partir de 1346 \200\r\n
    \r\n
    \r\n\t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t
    \r\n\t\r\n\r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    BON PLAN
    \r\n
    \r\n
    \r\nLes derni\350res technologies INTEL dans un nouveau design pour ce shuttle haut de gamme, pour un prix abordable.
    \r\n

    \r\n
    \r\n\340 partir de
    \r\n
    415 \200
    \r\n
    \r\n
    \r\n
    publicit\351
    \r\n
    \r\n\t\r\n\r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    \r\n\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\tDesktops
    \r\n\t\t\t\tPortables
    \r\n\t\t\t\tMini-PC
    \r\n\t\t\t\tPda / Tablets-PC
    \r\n\t\t\t\tApple
    \r\n\t\t\t\tGPS
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n

    \r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\tPortable Toshiba consacre deux gammes de machines au multim\351dia
    \r\n\tEquipement haut de gamme et Windows Media Center sont au menu de ces portables \340 vocation multim\351dia.

    \r\n\tOrdinateur Arriv\351e d\'un Power Mac G5 d\'entr\351e de gamme
    \r\n\tLa firme \340 la pomme propose une station de travail \351volutive et relativement abordable.

    \r\n\tPC Alienware propose deux machines au look \351trange
    \r\n\tAurora et Area 51 sont deux gammes d\'ordinateurs enti\350rement configurables.

    \r\n\tPortable Trois nouveaux iBook G4 chez Apple
    \r\n\tChez Apple, les portables gagnent en vitesse et communiquent sans fil en standard.

    \r\n\t\t\t\t> toutes les news\r\n\t\t\t
    \r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n

    \r\n\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tAsus A3N15-C Pro
    \r\n Voici un portable autonome et puissant gr\342ce \340 la technologie Intel Centrino.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1170 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tSoltek EQ3702A Miroir
    \r\n Ce mini PC est une solution int\351ressante pour les utilisateurs poss\351dant d\351j\340 un \351cran.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t559 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tIBM ThinkPad R51
    \r\n Voici un portable complet et pourtant relativement l\351ger.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1299 \200
    \r\n
    \r\n\t\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t> toutes les promos\r\n\t\t
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n\t\r\n\r\n
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\n
    \r\n
    \r\nLes graveurs de DVD
    \r\nQuel graveur choisir ? Quel type de format ? Quelle vitesse ? Double couche ou simple couche ? Voici tout ce qu\'il faut savoir pour faire le bon choix.
    \r\n\t\t\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n \t\r\n
    \r\n\t\t
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t\t\t\t

    \r\n\t\t\t\tChoisir une r\351gion
    \r\n\r\n
    Un d\351partement
    \r\n\r\n
    \r\n
    Un arrondissement
    \r\n\r\n
    \r\n
    \r\n\t\t\t\tRecherche directe
    \r\n\t\t\t\trechercher une ville
    et/ou une boutique
    \r\n\t\t\t\t

    \r\n\t\t\t\t \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
    Recherche avanc\351e
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    Bureautique
    \r\n\t\t\t\tTraducteur, organiseur...

    \r\n\t\t\t\t

    Multim\351dia
    \r\n\t\t\t\tPhoto, audio, vid\351o...

    \r\n\t\t\t\t

    Utilitaires
    \r\n\t\t\t\tAntivirus, pilotes, gravure...

    \r\n\t\t\t\t

    Personnaliser son PC
    \r\n\t\t\t\tEcrans de veille, th\350mes...

    \r\n\t\t\t\t

    D\351veloppement
    \r\n\t\t\t\tCr\351ation de logiciels, BDD...

    \r\n\t\t\t\t

    Jeux
    \r\n\t\t\t\tAction, simulation...

    \r\n\t\t\t\t

    Internet
    \r\n\t\t\t\tUtilitaires, email, FTP...

    \r\n\t\t\t\t

    Loisirs
    \r\n\t\t\t\tHumour, culture...

    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\t\t

    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\nMicro Achat : Ordinateurs, PDA - Toute l\'informatique avec 01Informatique, L\'Ordinateur Individuel, Micro Hebdo, D\351cision Informatique et 01R\351seaux\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    Derni\350re mise \340 jour de cette page : lundi 8 novembre 2004  |  16:45
    \r\n \r\n\r\n\r\n\r\n\t\r\n\r\n\t\t\r\n\r\n\t\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n\t\t\r\n\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t

    \r\n\r\n\r\n\r\n


    \r\n\r\n\r\n\r\n
    \n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
    \"\"
    Imagerie 
    \"\"\n\t\t\t\t\t\t\t\tLG L1720B\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    332.89 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tAcer Veriton 7600G\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    705 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tShuttle SN95G5\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    375 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tAsus A7N8X-E Deluxe\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    91.99 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tThermalright SP-94\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    49 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
    \"\"
    1 \">\"PC Look
    2 \">\"Atelier Informatique
    3 \">\"Zanax Multim\351dia
    4 \">\"MISTEROOPS
    5 \">\"168 Golden Avenue
    6 \">\"microchoix
    7 \">\"e-Soph
    8 \">\"PC Price Club
    9 \">\"PC 77
    10 \">\"Web In Informatique
    \n\t\t\t\t
    \n\t\t\t\t
    \r\n \r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t
    \n\n\n\n\n\n\n\n\n\n\n\n\n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \r\n\r\n\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n

    \r\n\t\t\t

    \r\n\t\t\t

    \r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\r\n \r\n \r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    CD et DVD bient\364t insensibles aux rayures
    OpenOffice gagne son service
    La messagerie en cinq minutes selon Ipswitch
    > toutes les news


    \r\n\t\t
    \r\n \r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Recevez chaque jour l\'actualit\351 des produits et des promos
    \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n\r\n\r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Entreprise
    \r\n\t\t\t\tQuand le billet papier s\'envole vers la d\351mat\351rialisation


    Trucs et astuces
    \r\n\t\t\t\tD\351pannez Windows XP


    Conso
    \r\n\t\t\t\tVos photos sur papier imprimante ou labo ?


    Produits & Tests
    \r\n\t\t\t\t5 programmes d\222encodage vid\351o gratuits


    \r\n\t\t
    \r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t

    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\r\n\r\n\r\n\t\t\t\r\n\r\n\r\n\r\n\t\t\t\t\r\n
    \r\n
    \r\nPortable
    \r\nUn nouvel ultra portable r\351alis\351 par Nec
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nLe Versa S940 a un format r\351duit, mais ses performances sont \340 la hauteur.
    \r\n\340 partir de 1663 \200\r\n
    \r\n
    \r\nPortable
    \r\nAsus pr\351sente trois petits nouveaux dans la gamme A3N
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nCes trois portables Centrino int\350grent, entre autres, une webcam et un contr\364leur Wi-Fi.
    \r\n\340 partir de 1346 \200\r\n
    \r\n
    \r\n\t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t
    \r\n\t\r\n\r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    BON PLAN
    \r\n
    \r\n
    \r\nLes derni\350res technologies INTEL dans un nouveau design pour ce shuttle haut de gamme, pour un prix abordable.
    \r\n

    \r\n
    \r\n\340 partir de
    \r\n
    415 \200
    \r\n
    \r\n
    \r\n
    publicit\351
    \r\n
    \r\n\t\r\n\r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    \r\n\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\tDesktops
    \r\n\t\t\t\tPortables
    \r\n\t\t\t\tMini-PC
    \r\n\t\t\t\tPda / Tablets-PC
    \r\n\t\t\t\tApple
    \r\n\t\t\t\tGPS
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n

    \r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\tPortable Toshiba consacre deux gammes de machines au multim\351dia
    \r\n\tEquipement haut de gamme et Windows Media Center sont au menu de ces portables \340 vocation multim\351dia.

    \r\n\tOrdinateur Arriv\351e d\'un Power Mac G5 d\'entr\351e de gamme
    \r\n\tLa firme \340 la pomme propose une station de travail \351volutive et relativement abordable.

    \r\n\tPC Alienware propose deux machines au look \351trange
    \r\n\tAurora et Area 51 sont deux gammes d\'ordinateurs enti\350rement configurables.

    \r\n\tPortable Trois nouveaux iBook G4 chez Apple
    \r\n\tChez Apple, les portables gagnent en vitesse et communiquent sans fil en standard.

    \r\n\t\t\t\t> toutes les news\r\n\t\t\t
    \r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n

    \r\n\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tAsus A3N15-C Pro
    \r\n Voici un portable autonome et puissant gr\342ce \340 la technologie Intel Centrino.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1170 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tSoltek EQ3702A Miroir
    \r\n Ce mini PC est une solution int\351ressante pour les utilisateurs poss\351dant d\351j\340 un \351cran.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t559 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tIBM ThinkPad R51
    \r\n Voici un portable complet et pourtant relativement l\351ger.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1299 \200
    \r\n
    \r\n\t\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t> toutes les promos\r\n\t\t
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n\t\r\n\r\n
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\n
    \r\n
    \r\nLes graveurs de DVD
    \r\nQuel graveur choisir ? Quel type de format ? Quelle vitesse ? Double couche ou simple couche ? Voici tout ce qu\'il faut savoir pour faire le bon choix.
    \r\n\t\t\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n \t\r\n
    \r\n\t\t
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t\t\t\t

    \r\n\t\t\t\tChoisir une r\351gion
    \r\n\r\n
    Un d\351partement
    \r\n\r\n
    \r\n
    Un arrondissement
    \r\n\r\n
    \r\n
    \r\n\t\t\t\tRecherche directe
    \r\n\t\t\t\trechercher une ville
    et/ou une boutique
    \r\n\t\t\t\t

    \r\n\t\t\t\t \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
    Recherche avanc\351e
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    Bureautique
    \r\n\t\t\t\tTraducteur, organiseur...

    \r\n\t\t\t\t

    Multim\351dia
    \r\n\t\t\t\tPhoto, audio, vid\351o...

    \r\n\t\t\t\t

    Utilitaires
    \r\n\t\t\t\tAntivirus, pilotes, gravure...

    \r\n\t\t\t\t

    Personnaliser son PC
    \r\n\t\t\t\tEcrans de veille, th\350mes...

    \r\n\t\t\t\t

    D\351veloppement
    \r\n\t\t\t\tCr\351ation de logiciels, BDD...

    \r\n\t\t\t\t

    Jeux
    \r\n\t\t\t\tAction, simulation...

    \r\n\t\t\t\t

    Internet
    \r\n\t\t\t\tUtilitaires, email, FTP...

    \r\n\t\t\t\t

    Loisirs
    \r\n\t\t\t\tHumour, culture...

    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\t\t

    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\nMicro Achat : Ordinateurs, PDA - Toute l\'informatique avec 01Informatique, L\'Ordinateur Individuel, Micro Hebdo, D\351cision Informatique et 01R\351seaux\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    Derni\350re mise \340 jour de cette page : lundi 8 novembre 2004  |  16:45
    \r\n \r\n\r\n\r\n\r\n\t\r\n\r\n\t\t\r\n\r\n\t\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n\t\t\r\n\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t

    \r\n\r\n\r\n\r\n


    \r\n\r\n\r\n\r\n
    \n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
    \"\"
    Imagerie 
    \"\"\n\t\t\t\t\t\t\t\tLG L1720B\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    332.89 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tAcer Veriton 7600G\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    705 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tShuttle SN95G5\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    375 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tAsus A7N8X-E Deluxe\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    91.99 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tThermalright SP-94\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    49 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
    \"\"
    1 \">\"PC Look
    2 \">\"Atelier Informatique
    3 \">\"Zanax Multim\351dia
    4 \">\"MISTEROOPS
    5 \">\"168 Golden Avenue
    6 \">\"microchoix
    7 \">\"e-Soph
    8 \">\"PC Price Club
    9 \">\"PC 77
    10 \">\"Web In Informatique
    \n\t\t\t\t
    \n\t\t\t\t
    \r\n \r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t
    \n\n\n\n\n\n\n\n\n\n\n\n\n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \r\n\r\n\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n

    \r\n\t\t\t

    \r\n\t\t\t

    \r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\r\n \r\n \r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    CD et DVD bient\364t insensibles aux rayures
    OpenOffice gagne son service
    La messagerie en cinq minutes selon Ipswitch
    > toutes les news


    \r\n\t\t
    \r\n \r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Recevez chaque jour l\'actualit\351 des produits et des promos
    \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n\r\n\r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Entreprise
    \r\n\t\t\t\tQuand le billet papier s\'envole vers la d\351mat\351rialisation


    Trucs et astuces
    \r\n\t\t\t\tD\351pannez Windows XP


    Conso
    \r\n\t\t\t\tVos photos sur papier imprimante ou labo ?


    Produits & Tests
    \r\n\t\t\t\t5 programmes d\222encodage vid\351o gratuits


    \r\n\t\t
    \r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t

    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\r\n\r\n\r\n\t\t\t\r\n\r\n\r\n\r\n\t\t\t\t\r\n
    \r\n
    \r\nPortable
    \r\nUn nouvel ultra portable r\351alis\351 par Nec
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nLe Versa S940 a un format r\351duit, mais ses performances sont \340 la hauteur.
    \r\n\340 partir de 1663 \200\r\n
    \r\n
    \r\nPortable
    \r\nAsus pr\351sente trois petits nouveaux dans la gamme A3N
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nCes trois portables Centrino int\350grent, entre autres, une webcam et un contr\364leur Wi-Fi.
    \r\n\340 partir de 1346 \200\r\n
    \r\n
    \r\n\t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t
    \r\n\t\r\n\r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    BON PLAN
    \r\n
    \r\n
    \r\nLes derni\350res technologies INTEL dans un nouveau design pour ce shuttle haut de gamme, pour un prix abordable.
    \r\n

    \r\n
    \r\n\340 partir de
    \r\n
    415 \200
    \r\n
    \r\n
    \r\n
    publicit\351
    \r\n
    \r\n\t\r\n\r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    \r\n\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\tDesktops
    \r\n\t\t\t\tPortables
    \r\n\t\t\t\tMini-PC
    \r\n\t\t\t\tPda / Tablets-PC
    \r\n\t\t\t\tApple
    \r\n\t\t\t\tGPS
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n

    \r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\tPortable Toshiba consacre deux gammes de machines au multim\351dia
    \r\n\tEquipement haut de gamme et Windows Media Center sont au menu de ces portables \340 vocation multim\351dia.

    \r\n\tOrdinateur Arriv\351e d\'un Power Mac G5 d\'entr\351e de gamme
    \r\n\tLa firme \340 la pomme propose une station de travail \351volutive et relativement abordable.

    \r\n\tPC Alienware propose deux machines au look \351trange
    \r\n\tAurora et Area 51 sont deux gammes d\'ordinateurs enti\350rement configurables.

    \r\n\tPortable Trois nouveaux iBook G4 chez Apple
    \r\n\tChez Apple, les portables gagnent en vitesse et communiquent sans fil en standard.

    \r\n\t\t\t\t> toutes les news\r\n\t\t\t
    \r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n

    \r\n\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tAsus A3N15-C Pro
    \r\n Voici un portable autonome et puissant gr\342ce \340 la technologie Intel Centrino.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1170 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tSoltek EQ3702A Miroir
    \r\n Ce mini PC est une solution int\351ressante pour les utilisateurs poss\351dant d\351j\340 un \351cran.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t559 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tIBM ThinkPad R51
    \r\n Voici un portable complet et pourtant relativement l\351ger.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1299 \200
    \r\n
    \r\n\t\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t> toutes les promos\r\n\t\t
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n\t\r\n\r\n
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\n
    \r\n
    \r\nLes graveurs de DVD
    \r\nQuel graveur choisir ? Quel type de format ? Quelle vitesse ? Double couche ou simple couche ? Voici tout ce qu\'il faut savoir pour faire le bon choix.
    \r\n\t\t\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n \t\r\n
    \r\n\t\t
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t\t\t\t

    \r\n\t\t\t\tChoisir une r\351gion
    \r\n\r\n
    Un d\351partement
    \r\n\r\n
    \r\n
    Un arrondissement
    \r\n\r\n
    \r\n
    \r\n\t\t\t\tRecherche directe
    \r\n\t\t\t\trechercher une ville
    et/ou une boutique
    \r\n\t\t\t\t

    \r\n\t\t\t\t \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
    Recherche avanc\351e
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    Bureautique
    \r\n\t\t\t\tTraducteur, organiseur...

    \r\n\t\t\t\t

    Multim\351dia
    \r\n\t\t\t\tPhoto, audio, vid\351o...

    \r\n\t\t\t\t

    Utilitaires
    \r\n\t\t\t\tAntivirus, pilotes, gravure...

    \r\n\t\t\t\t

    Personnaliser son PC
    \r\n\t\t\t\tEcrans de veille, th\350mes...

    \r\n\t\t\t\t

    D\351veloppement
    \r\n\t\t\t\tCr\351ation de logiciels, BDD...

    \r\n\t\t\t\t

    Jeux
    \r\n\t\t\t\tAction, simulation...

    \r\n\t\t\t\t

    Internet
    \r\n\t\t\t\tUtilitaires, email, FTP...

    \r\n\t\t\t\t

    Loisirs
    \r\n\t\t\t\tHumour, culture...

    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\t\t

    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\nMicro Achat : Ordinateurs, PDA - Toute l\'informatique avec 01Informatique, L\'Ordinateur Individuel, Micro Hebdo, D\351cision Informatique et 01R\351seaux\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    Derni\350re mise \340 jour de cette page : lundi 8 novembre 2004  |  16:45
    \r\n \r\n\r\n\r\n\r\n\t\r\n\r\n\t\t\r\n\r\n\t\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n\t\t\r\n\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t

    \r\n\r\n\r\n\r\n


    \r\n\r\n\r\n\r\n
    \n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
    \"\"
    Imagerie 
    \"\"\n\t\t\t\t\t\t\t\tLG L1720B\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    332.89 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tAcer Veriton 7600G\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    705 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tShuttle SN95G5\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    375 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tAsus A7N8X-E Deluxe\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    91.99 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tThermalright SP-94\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    49 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
    \"\"
    1 \">\"PC Look
    2 \">\"Atelier Informatique
    3 \">\"Zanax Multim\351dia
    4 \">\"MISTEROOPS
    5 \">\"168 Golden Avenue
    6 \">\"microchoix
    7 \">\"e-Soph
    8 \">\"PC Price Club
    9 \">\"PC 77
    10 \">\"Web In Informatique
    \n\t\t\t\t
    \n\t\t\t\t
    \r\n \r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t
    \n\n\n\n\n\n\n\n\n\n\n\n\n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \r\n\r\n\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n

    \r\n\t\t\t

    \r\n\t\t\t

    \r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\r\n \r\n \r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    CD et DVD bient\364t insensibles aux rayures
    OpenOffice gagne son service
    La messagerie en cinq minutes selon Ipswitch
    > toutes les news


    \r\n\t\t
    \r\n \r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Recevez chaque jour l\'actualit\351 des produits et des promos
    \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n\r\n\r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Entreprise
    \r\n\t\t\t\tQuand le billet papier s\'envole vers la d\351mat\351rialisation


    Trucs et astuces
    \r\n\t\t\t\tD\351pannez Windows XP


    Conso
    \r\n\t\t\t\tVos photos sur papier imprimante ou labo ?


    Produits & Tests
    \r\n\t\t\t\t5 programmes d\222encodage vid\351o gratuits


    \r\n\t\t
    \r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t

    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\r\n\r\n\r\n\t\t\t\r\n\r\n\r\n\r\n\t\t\t\t\r\n
    \r\n
    \r\nPortable
    \r\nUn nouvel ultra portable r\351alis\351 par Nec
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nLe Versa S940 a un format r\351duit, mais ses performances sont \340 la hauteur.
    \r\n\340 partir de 1663 \200\r\n
    \r\n
    \r\nPortable
    \r\nAsus pr\351sente trois petits nouveaux dans la gamme A3N
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nCes trois portables Centrino int\350grent, entre autres, une webcam et un contr\364leur Wi-Fi.
    \r\n\340 partir de 1346 \200\r\n
    \r\n
    \r\n\t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t
    \r\n\t\r\n\r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    BON PLAN
    \r\n
    \r\n
    \r\nLes derni\350res technologies INTEL dans un nouveau design pour ce shuttle haut de gamme, pour un prix abordable.
    \r\n

    \r\n
    \r\n\340 partir de
    \r\n
    415 \200
    \r\n
    \r\n
    \r\n
    publicit\351
    \r\n
    \r\n\t\r\n\r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    \r\n\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\tDesktops
    \r\n\t\t\t\tPortables
    \r\n\t\t\t\tMini-PC
    \r\n\t\t\t\tPda / Tablets-PC
    \r\n\t\t\t\tApple
    \r\n\t\t\t\tGPS
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n

    \r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\tPortable Toshiba consacre deux gammes de machines au multim\351dia
    \r\n\tEquipement haut de gamme et Windows Media Center sont au menu de ces portables \340 vocation multim\351dia.

    \r\n\tOrdinateur Arriv\351e d\'un Power Mac G5 d\'entr\351e de gamme
    \r\n\tLa firme \340 la pomme propose une station de travail \351volutive et relativement abordable.

    \r\n\tPC Alienware propose deux machines au look \351trange
    \r\n\tAurora et Area 51 sont deux gammes d\'ordinateurs enti\350rement configurables.

    \r\n\tPortable Trois nouveaux iBook G4 chez Apple
    \r\n\tChez Apple, les portables gagnent en vitesse et communiquent sans fil en standard.

    \r\n\t\t\t\t> toutes les news\r\n\t\t\t
    \r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n

    \r\n\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tAsus A3N15-C Pro
    \r\n Voici un portable autonome et puissant gr\342ce \340 la technologie Intel Centrino.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1170 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tSoltek EQ3702A Miroir
    \r\n Ce mini PC est une solution int\351ressante pour les utilisateurs poss\351dant d\351j\340 un \351cran.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t559 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tIBM ThinkPad R51
    \r\n Voici un portable complet et pourtant relativement l\351ger.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1299 \200
    \r\n
    \r\n\t\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t> toutes les promos\r\n\t\t
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n\t\r\n\r\n
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\n
    \r\n
    \r\nLes graveurs de DVD
    \r\nQuel graveur choisir ? Quel type de format ? Quelle vitesse ? Double couche ou simple couche ? Voici tout ce qu\'il faut savoir pour faire le bon choix.
    \r\n\t\t\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n \t\r\n
    \r\n\t\t
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t\t\t\t

    \r\n\t\t\t\tChoisir une r\351gion
    \r\n\r\n
    Un d\351partement
    \r\n\r\n
    \r\n
    Un arrondissement
    \r\n\r\n
    \r\n
    \r\n\t\t\t\tRecherche directe
    \r\n\t\t\t\trechercher une ville
    et/ou une boutique
    \r\n\t\t\t\t

    \r\n\t\t\t\t \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
    Recherche avanc\351e
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    Bureautique
    \r\n\t\t\t\tTraducteur, organiseur...

    \r\n\t\t\t\t

    Multim\351dia
    \r\n\t\t\t\tPhoto, audio, vid\351o...

    \r\n\t\t\t\t

    Utilitaires
    \r\n\t\t\t\tAntivirus, pilotes, gravure...

    \r\n\t\t\t\t

    Personnaliser son PC
    \r\n\t\t\t\tEcrans de veille, th\350mes...

    \r\n\t\t\t\t

    D\351veloppement
    \r\n\t\t\t\tCr\351ation de logiciels, BDD...

    \r\n\t\t\t\t

    Jeux
    \r\n\t\t\t\tAction, simulation...

    \r\n\t\t\t\t

    Internet
    \r\n\t\t\t\tUtilitaires, email, FTP...

    \r\n\t\t\t\t

    Loisirs
    \r\n\t\t\t\tHumour, culture...

    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\t\t

    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\nMicro Achat : Ordinateurs, PDA - Toute l\'informatique avec 01Informatique, L\'Ordinateur Individuel, Micro Hebdo, D\351cision Informatique et 01R\351seaux\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    Derni\350re mise \340 jour de cette page : lundi 8 novembre 2004  |  16:45
    \r\n \r\n\r\n\r\n\r\n\t\r\n\r\n\t\t\r\n\r\n\t\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n\t\t\r\n\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t

    \r\n\r\n\r\n\r\n


    \r\n\r\n\r\n\r\n
    \n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t\t\n\t\t\t\t\t\t
    \"\"
    Imagerie 
    \"\"\n\t\t\t\t\t\t\t\tLG L1720B\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    332.89 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tAcer Veriton 7600G\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    705 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Ordinateurs 
    \"\"\n\t\t\t\t\t\t\t\tShuttle SN95G5\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    375 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tAsus A7N8X-E Deluxe\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    91.99 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    Composants 
    \"\"\n\t\t\t\t\t\t\t\tThermalright SP-94\n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t\t\t\340 partir de\n\t\t\t\t\t\t\t\t\t
    49 €
    \n\t\t\t\t\t\t\t\t
    \n\t\t\t\t\t\t\t
    \n\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t\t\n\t\t\t\t
    \"\"
    1 \">\"PC Look
    2 \">\"Atelier Informatique
    3 \">\"Zanax Multim\351dia
    4 \">\"MISTEROOPS
    5 \">\"168 Golden Avenue
    6 \">\"microchoix
    7 \">\"e-Soph
    8 \">\"PC Price Club
    9 \">\"PC 77
    10 \">\"Web In Informatique
    \n\t\t\t\t
    \n\t\t\t\t
    \r\n \r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t
    \n\n\n\n\n\n\n\n\n\n\n\n\n
    \n\n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \n
    \r\n\r\n\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n

    \r\n\t\t\t

    \r\n\t\t\t

    \r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\r\n \r\n \r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    CD et DVD bient\364t insensibles aux rayures
    OpenOffice gagne son service
    La messagerie en cinq minutes selon Ipswitch
    > toutes les news


    \r\n\t\t
    \r\n \r\n\r\n\r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Recevez chaque jour l\'actualit\351 des produits et des promos
    \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n\r\n\r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t \r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    Entreprise
    \r\n\t\t\t\tQuand le billet papier s\'envole vers la d\351mat\351rialisation


    Trucs et astuces
    \r\n\t\t\t\tD\351pannez Windows XP


    Conso
    \r\n\t\t\t\tVos photos sur papier imprimante ou labo ?


    Produits & Tests
    \r\n\t\t\t\t5 programmes d\222encodage vid\351o gratuits


    \r\n\t\t
    \r\n\r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t

    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\r\n\r\n\r\n\t\t\t\r\n\r\n\r\n\r\n\t\t\t\t\r\n
    \r\n
    \r\nPortable
    \r\nUn nouvel ultra portable r\351alis\351 par Nec
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nLe Versa S940 a un format r\351duit, mais ses performances sont \340 la hauteur.
    \r\n\340 partir de 1663 \200\r\n
    \r\n
    \r\nPortable
    \r\nAsus pr\351sente trois petits nouveaux dans la gamme A3N
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\nCes trois portables Centrino int\350grent, entre autres, une webcam et un contr\364leur Wi-Fi.
    \r\n\340 partir de 1346 \200\r\n
    \r\n
    \r\n\t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t\r\n \t\r\n\t\r\n\t
    \r\n\t\r\n\r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    BON PLAN
    \r\n
    \r\n
    \r\nLes derni\350res technologies INTEL dans un nouveau design pour ce shuttle haut de gamme, pour un prix abordable.
    \r\n

    \r\n
    \r\n\340 partir de
    \r\n
    415 \200
    \r\n
    \r\n
    \r\n
    publicit\351
    \r\n
    \r\n\t\r\n\r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t

    \r\n\t\t\t\t\t\t\t\t\t\t\t\t
    \r\n\t\t\t\tDesktops
    \r\n\t\t\t\tPortables
    \r\n\t\t\t\tMini-PC
    \r\n\t\t\t\tPda / Tablets-PC
    \r\n\t\t\t\tApple
    \r\n\t\t\t\tGPS
    \r\n\t\t\t\t
    \r\n\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t


    \r\n\t\t\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n

    \r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\r\n\t\r\n\t\r\n\t\t\t\t\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\tPortable Toshiba consacre deux gammes de machines au multim\351dia
    \r\n\tEquipement haut de gamme et Windows Media Center sont au menu de ces portables \340 vocation multim\351dia.

    \r\n\tOrdinateur Arriv\351e d\'un Power Mac G5 d\'entr\351e de gamme
    \r\n\tLa firme \340 la pomme propose une station de travail \351volutive et relativement abordable.

    \r\n\tPC Alienware propose deux machines au look \351trange
    \r\n\tAurora et Area 51 sont deux gammes d\'ordinateurs enti\350rement configurables.

    \r\n\tPortable Trois nouveaux iBook G4 chez Apple
    \r\n\tChez Apple, les portables gagnent en vitesse et communiquent sans fil en standard.

    \r\n\t\t\t\t> toutes les news\r\n\t\t\t
    \r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n\r\n

    \r\n\r\n\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tAsus A3N15-C Pro
    \r\n Voici un portable autonome et puissant gr\342ce \340 la technologie Intel Centrino.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1170 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tSoltek EQ3702A Miroir
    \r\n Ce mini PC est une solution int\351ressante pour les utilisateurs poss\351dant d\351j\340 un \351cran.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t559 \200
    \r\n
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \tIBM ThinkPad R51
    \r\n Voici un portable complet et pourtant relativement l\351ger.
    \r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t\r\n\t
    \r\n\t1299 \200
    \r\n
    \r\n\t\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n\t\t\t\t> toutes les promos\r\n\t\t
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n

    \r\n
    \r\n\t\t\r\n\t\t\r\n\t\t\t\r\n\t\t\r\n\t\t\r\n\t\t
    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t
    \r\n\t\t\t\r\n\t\t\t\t\r\n\r\n\r\n\r\n \r\n\r\n\r\n \r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n\t\r\n\r\n
    \r\n\r\n\t\t\t\t\t \t \t\t\t\t\t\t\t\t\t\t\t\t\t\r\n\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t\t \t \t\r\n
    \r\n
    \r\nLes graveurs de DVD
    \r\nQuel graveur choisir ? Quel type de format ? Quelle vitesse ? Double couche ou simple couche ? Voici tout ce qu\'il faut savoir pour faire le bon choix.
    \r\n\t\t\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t
    \r\n
    \r\n\r\n\r\n\t\r\n\t\t\r\n\r\n\r\n \t\r\n
    \r\n\t\t
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    \r\n\t\t\t\t

    \r\n\t\t\t\tChoisir une r\351gion
    \r\n\r\n
    Un d\351partement
    \r\n\r\n
    \r\n
    Un arrondissement
    \r\n\r\n
    \r\n
    \r\n\t\t\t\tRecherche directe
    \r\n\t\t\t\trechercher une ville
    et/ou une boutique
    \r\n\t\t\t\t

    \r\n\t\t\t\t \r\n\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t\t\t\r\n\t\t\t\t\t\r\n\t\t\t\t
    Recherche avanc\351e
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n\t\r\n\t\t\r\n\t\r\n
    \r\n\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t\t\r\n\t\t\t\t\r\n\t\t\t\r\n\t\t
    Bureautique
    \r\n\t\t\t\tTraducteur, organiseur...

    \r\n\t\t\t\t

    Multim\351dia
    \r\n\t\t\t\tPhoto, audio, vid\351o...

    \r\n\t\t\t\t

    Utilitaires
    \r\n\t\t\t\tAntivirus, pilotes, gravure...

    \r\n\t\t\t\t

    Personnaliser son PC
    \r\n\t\t\t\tEcrans de veille, th\350mes...

    \r\n\t\t\t\t

    D\351veloppement
    \r\n\t\t\t\tCr\351ation de logiciels, BDD...

    \r\n\t\t\t\t

    Jeux
    \r\n\t\t\t\tAction, simulation...

    \r\n\t\t\t\t

    Internet
    \r\n\t\t\t\tUtilitaires, email, FTP...

    \r\n\t\t\t\t

    Loisirs
    \r\n\t\t\t\tHumour, culture...

    \r\n\t\t\t\t
    \r\n\t\t
    \r\n
    \r\n
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\r\n\t\t
    \r\n\t\t
    \r\n\t\t\r\n\t\t\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\r\n\t\t\t\t\r\n\t\t\t
    \r\n\t\t\t
    \r\n\r\n\t\t

    \r\n\t\t\t\r\n\r\n\r\n\r\n\r\n\r\n
    \r\n
    \r\n
    \r\n\r\n\r\n\r\n + + C=10 M=100 Y=50 K=0 + CMYK + PROCESS + 10.000002 + 100.000000 + 50.000000 + 0.000000 + + + C=0 M=95 Y=20 K=0 + CMYK + PROCESS + 0.000000 + 94.999999 + 19.999999 + 0.000000 + + + C=25 M=25 Y=40 K=0 + CMYK + PROCESS + 25.000000 + 25.000000 + 39.999998 + 0.000000 + + + C=40 M=45 Y=50 K=5 + CMYK + PROCESS + 39.999998 + 44.999999 + 50.000000 + 5.000001 + + + C=50 M=50 Y=60 K=25 + CMYK + PROCESS + 50.000000 + 50.000000 + 60.000002 + 25.000000 + + + C=55 M=60 Y=65 K=40 + CMYK + PROCESS + 55.000001 + 60.000002 + 64.999998 + 39.999998 + + + C=25 M=40 Y=65 K=0 + CMYK + PROCESS + 25.000000 + 39.999998 + 64.999998 + 0.000000 + + + C=30 M=50 Y=75 K=10 + CMYK + PROCESS + 30.000001 + 50.000000 + 75.000000 + 10.000002 + + + C=35 M=60 Y=80 K=25 + CMYK + PROCESS + 35.000002 + 60.000002 + 80.000001 + 25.000000 + + + C=40 M=65 Y=90 K=35 + CMYK + PROCESS + 39.999998 + 64.999998 + 90.000004 + 35.000002 + + + C=40 M=70 Y=100 K=50 + CMYK + PROCESS + 39.999998 + 69.999999 + 100.000000 + 50.000000 + + + C=50 M=70 Y=80 K=70 + CMYK + PROCESS + 50.000000 + 69.999999 + 80.000001 + 69.999999 + + + + + + Grays + 1 + + + + C=0 M=0 Y=0 K=100 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 100.000000 + + + C=0 M=0 Y=0 K=90 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 89.999402 + + + C=0 M=0 Y=0 K=80 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 79.998797 + + + C=0 M=0 Y=0 K=70 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 69.999701 + + + C=0 M=0 Y=0 K=60 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 59.999102 + + + C=0 M=0 Y=0 K=50 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 50.000000 + + + C=0 M=0 Y=0 K=40 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 39.999402 + + + C=0 M=0 Y=0 K=30 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 29.998803 + + + C=0 M=0 Y=0 K=20 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 19.999701 + + + C=0 M=0 Y=0 K=10 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 9.999102 + + + C=0 M=0 Y=0 K=5 + CMYK + PROCESS + 0.000000 + 0.000000 + 0.000000 + 4.998803 + + + + + + Brights + 1 + + + + C=0 M=100 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 100.000000 + 100.000000 + 0.000000 + + + C=0 M=75 Y=100 K=0 + CMYK + PROCESS + 0.000000 + 75.000000 + 100.000000 + 0.000000 + + + C=0 M=10 Y=95 K=0 + CMYK + PROCESS + 0.000000 + 10.000002 + 94.999999 + 0.000000 + + + C=85 M=10 Y=100 K=0 + CMYK + PROCESS + 84.999996 + 10.000002 + 100.000000 + 0.000000 + + + C=100 M=90 Y=0 K=0 + CMYK + PROCESS + 100.000000 + 90.000004 + 0.000000 + 0.000000 + + + C=60 M=90 Y=0 K=0 + CMYK + PROCESS + 60.000002 + 90.000004 + 0.003099 + 0.003099 + + + + + + + + + Adobe PDF library 9.00 + + + + + + + + + + + + + + + + + + + + + + + + + +endstream endobj 145 0 obj<> endobj 1 0 obj<> endobj 2 0 obj<>/Font<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 3 0 obj<>stream +hޔ[MsFWnmU(se{kjw`7ƨhhҜ_e&rl(BG2ˏ_oͷ|H.>޽)Vs"Wq\Xإob5{|)^xylD]E~g*vM_YAڨjqݷ?b*]PWrUm?04]\}\ʲNVId=ɼup6wN~reߎU;6c5652cvu gS3>_D04Qw#*ׇ}L%m_9f0^YצYN9npse)9&|O"~lms=2yTǾZ?'=VW;`L)T0XA4&q'IGJdשŷC7bb1QtrJ1E\ESñR!"dwǝ +?Gq pۢ_⧑}}؉+.DAɤ$& +*vo:UTi͑ks?y'V^4m]O߽A$xI;#4.|ýoQwvK,ă2kd6X,4#.C͛ ]=F6wQD1{~۴(}EK_w*hZ@CtEAg/)rjJчvS\a #xhGFؓ}lcYh)(ǍTNSb[,ʔW%ʣMswW/S2XGO5r>, b`'%E,B>|$G0,1%@T/2;,BQC)e]MRض~Rm[Q +P c ] QkONFJ_ɇz{θCn5yٜh׏Ұq P$ +Yp%b#X5|b^Q*B;NJ:3R*ě9"axpNA + +Sb' Up~t܅6C׏s$tWheޢ+hq, GFIH[W5Sa<DXSq-͘1+"G[!&f,ݭpg |v0EQ͝`ҎIYZ)+S wM@]G\ѵcv[C?0!8C1R<*`yqY!K5_q7|M QS:Y0YuIaf>]"B]<-W{0ps涹f^HGѸdV`)0YohjVB訅aRpv)PO%̹ W-%~ח >-@e\: +pXIRt/'* O.XIMh=N`Bepxc_ ~d~R'%W( &o׷+,NyL'$Rxa9KBYXW2Ө/0,sJ1yX>(f$W(J +쇋ÏD~1RQg#pp2:}RHX0 = #1p:]cQ3&sd̤joF?8V&ӒSnޝ#:tb02.žzD-;+,=߃`p!jΰLD]asɠFcT \0>I/LPafrF HKؙe(O/e;ex~ZY P3cd|V4dOЇ)Z~F$֕K$tI@[Au0\dFdZsj?K~oX&=x6U8~.PTZ;@WaNCnuP(Ψ-&fMȲ!<4lmC 5c^A֍Y1xU_2gtiMc%='0>ⷢړuWHh*ZCw3HVwAкa H*^IؽSĮl֫p*>Q!:M֥Mlղ"r91LADm]X؆I)W'SzS4CBlĉ&6qjȂ: SH+z G?_KtɌb~> 4=tU *8g2ajD&_ߩB{ + gB$EijMt|G +Ǩ>#!8JM:>3wy.#3:0QI.8k"tNZ}G%@i"ܷL5)w?/>+$.&N3ꔈ{[-R 韹n>u eP 4~zZ](i~|M 6A8*;:Mh!GͰ#;BjPDahS~ȗwjyǡQ|EQ'ࢳX +|J1c@"A'ceI3ȊZG#s>]MEn,R\FuNT':njDJXIgcqm7̰5zڎDyF AN;etS?Lم1gBB@3V̶uD|onhAJF*gyhLVVBbehה|0*n7AHRiDH§*H,puɢ)?e ;55ܬ_83SYMوtm4BXIގA<.}"!.d>?3Aq̋xH㗊t} lh*QLP3C{A+ͥ[ٲz'w/KisoE$( +{gi0s +I848'eŪLL"\Fx _BO!'o=`$j ̵4ݩ#,$Y۵RG,|{`WlЌ/pa՚%/[$GR"/Ai;F6䔒+um`P,k닀^TtfT'){.\Ur!|O +Sv* + Ő!XwrF,Xѕvvh0z +'wJ)s² ]hzo/1#A-+/6=nfݘ`7t刏/-(e>Ίeh"AO'ym(K@ 6~J2U# +<↲rJq[ $o0-xf>fAQ'nC*9̤OVJ|v؂?2*( Xd\0)IPsfO.7'N +8ltG֚,̜KdGdOH^e1gp5%Ƌ$$A/9hoZK`_Z%SBPV[ZP7/wVS6pOQul6 ה Fak׊'dyvyi*m4,>ѠG] 9D7"*霨WAh8D\1qu51cuYyתǩݱ+ezuݡ80T,J*y+”L^5F斵zV1ܛgeu׭L[yz#䷐cAmGDL-d>{[sGɕ,5yi5,iKv7eW +ĺi[vx~e@UpRDOUhVF;uCǾ4&!ּ3,3xe(CHϵ,{ˢj AsJ6ǯB O+}ɯp9)e;)gerbZÑ7N}ǣ4)[V~暋V@P?e_~ +%_ -wQ[ lE6b٤jc{޷뫾sL2=Z%ˑH0i4>v:26 +#Diy +m8#uKhK#ziT\=e̽ݲ%>'o?ި'{H4y'L=އxNjj1|}c^itB}[~V;-9lNï[p#[rٖsn!OEtp`|v+bERyoXT`zUw(#E Rm3O+-BoU`{mUj0vU0{4A#x/kqC8&(/^sYg2"@gr66L99.oKMPWtu)="kRfHkoQΤļB[Hi}?qsSgxOh S )Ca)ԺY:k=ƱYї".Sar/{DҦLt: hMlڲKLbxDA/'V#_lwŨ{-P3a09p,Ɯ,sՏ;+W!E _EhԭD6v$txd&wcmy82+pFO)W%_6AgY:p|+<t}8,!e4@R\s!{>%!e +0Zw?O~c=L"R'mSQhkY9 +t >}T-wS0kͻG KV6Ugl"cOGQetd=yy<*J-Vީoq z[X@4Va`) ?-aoN`,i*́v6jidS4D :Q>ZlQ]gY"b}$ P#qciGY^;;aEv0qಙޕ -^Jd49[aAr]vFMTQҨ8vǾ=2I>Vl;Vy g;](f7#6v7[M ?o} 2 +Cf ` sthCBV.]XA+YDZmG'̇ Li7ӂFÿ[ФE.eQu?姛wp9b˿I)p6:A(?c𳫮Ǚ +tZzy]:jZMiXe=ar?`KhŇa &ˤk%u&e/O. +endstream endobj 4 0 obj<> endobj 5 0 obj<>/ProcSet[/PDF/Text]/ExtGState<>>> endobj 6 0 obj<>stream +h[ےq}W#0.u%)YT][K>`z03M=a8^9YKO/IeK.2Oԯ]a7M'rxҖϋI3r~=!p20~S$U C^?OuY廦o*ߔI^e&0W"5Inɓn_K뷻.ox8*5~x*'v1ˤ﮾};YMɼ|.; ^˓Vfh}rg,-O2aer5ȜVF.9zhL"ZIL˱܋y]C#Ś蚚Z̷H,= +=-.!nmrj|T&Ub!|SU26S2ɮMxuVeˢš3V@nwAnLR ܃Ɉ.GQv hy +l{JfU[̢HIJϭl3Qj^Q7*ϏfÃ(~^z ΖWN>4?x{Lzan2pX3^)BbjaVUϹI,6~S(T"#\ˈ'N.rgX7NFbX`RĴ Ѽط'L-ŎT^u>1lyOFaK*!KpEqUcaA[ƹ>o,{d~EzO;$ڎ!5zД;H[6yygn:(Bfr˄ S3]%SC8;7͜sUlZeT ~VX\|Q|9Yu$/I Q&]->7kB.k3Mn~7qcGh .]~jukW3'6- S +0F(=8G;qKkola7ۗx~|( e vнv'U N J;%fC=Y._m?1Y ?fQ JLrOA͕`hzXEoȲp"NFK ˁ3ojEw~HT)&zlE^P9(NVEnQGP7Ë /.ҘI$AɇlgM"$!),T%> = lW._BXy߃A9DqGl9n[°g%6yQjڝ"@@H ~N)56OI?1'lt"k}BwChh}Qx.z@{\e,+be £P˜ A˜a^2v([|a +[QvG!&JrGsHy!ɭRm/< +P?Lu$'<ܾTf.`rBH&FhR3ڀNpzs \:d`j{18c1;YL1Üڧ&f3ybFmx '#3ѽ Y'*#ySq9t G(zhݵtܑqL#Fd,p&5BQXrb^c,כ +p­4NdᎩ*nK[6]1HI|.\dE!;% AtڔoySuiֳ"N2Ro>#-Ϭ?'͕7^d}8=hhe*k$W{3EMY2<{Jfﻱݽ@P 9ayHf*EКMC zHu&j~DmlM*C7k\ȃ~xuAn:*~R>LE,JehGl1$*iocW,=*EvasBc>GY|72AN* ]7"Fzar +` ZhB\&_@W,䫵GyZF׫́ +e %ԙȕ:_q&Ҡ\ SHڵ6>,%]NRY YKbfw[:^I[L[`~)CY2=+$TK^>1fVh3 > +`e'keZD.)S-+P*ڱ,bsf&[0QbGDž3f"Tz?.-gE,ÿq6:ҼD`=<6lXܶ-c+\6C,` 6},R/C6ECV>mN1`-dnC LOê?-?]CY."n"5, )8)e7[ %7 +%s5lQrYxZ,"p ?9~9!`R9r@:M4~@K`^!Al)OmwL8h@/okē*B6W 8ag*Y̸9A,gaaNчK y +c1ٛG6f )J'^Na@=- +[wI `3&"BSݨSiHܗh#ScɦږŶ> mahq%qUHnoK5%&b'l1}`)4ʘ Hݮ{-?Z>(ﳼi, Ʊ%fH1̾)d4lcKgYxaOtuK{WƄm}uBOI/jg/$Y2ΗShP1ev'FM،ڜ z` r~plT=1G43"etPA׍V`wKeV} +W!X)CKf0`#R&4RB.l71 j*xބxW{6ݮ|'\D⍦{U1$]|phGL3-knuPoT)ցk91p) t,Vr[*6.ck*?Q`Y\X^yЏh\ش&#pXVz=*š~ /؜C"](ɿFZ,_ +9ZgV4}g\5(oP;6I)zDHYr_) +;QZ63E ֆ)krACl"S" +l,fۄ2oi5qkUtSل[2F޶cuϚ|3֟ + #S7cHG[i.M2>u8Lt}TcӏS:kyhyQNa¯֒lb`zd \/vZ1C|sl+'!u",XeN2`8P-YwRU/hᴿՂ,TڶԎA>FSe(x E6o׭s}_!N@5F@їbw)y'xsv~DdaBW"V-fI՛zUyҟerY`L\2Ưsjlu̢F*8;pٽ ^."('ƙվA]Y5iT `^ +٤}u,v\bߡ㑜r_# +jaYK5y?2_BL>0ȝв2Tڴ,S]*Z7WM2MJy9y.$3Ǽ4A32xKhx6t3|#!XPq-c_[ +R)?GT ;1Q[=;mts9C9xqy$¢ 4rwfc[q=Pm"cOGי +JXdZЎ mGF墕PhN^O;j,lnfwtc#Q*F<-쵊kAro0{l2'FB'`,[ +Mb 7,!tM*LiW^jatQ8ZDG-;FtZ?ޕZ T>.pV1̔*aҶ2:0:lh*%ԺA[r`а5I{ Tmd9 +mQFLusW b4%> ceSD 8iHcC"]:mL1ehC3v, :/XdI-6|15kG}1c>iwGS&Z{mr vln\CqGyWY, * V +?'#>ȣh>ۼ纽g빢9ɣR{yj,_ g#4'7$v뱜G>׭2rJk!Y,3!јU?tVQ%Tyb7gς,m '.L> '8TrBS6*wmv6/2xdRfYVk-J}C\аeg>;dy0U >a!fT9+K M +VB џN7y xUcsɆG$J/3"> +Dv˅<4јΛ|؀`ܾyl\[> kkGSi%MB!MBk __ȕr ]d>͙0 ^Ƌ*_Mngx rCH4piL͍͊[[(û쬆:{5ІNysu4Y^Eڦ'x\'MQG438ŀnwڳcAX%_ NeMɴM?W)ݻ +endstream endobj 7 0 obj<> endobj 8 0 obj<>/XObject<>/ProcSet[/PDF/Text/ImageC]/ExtGState<>>> endobj 9 0 obj<>stream +hޜZrF+tpFQP7Ҷ 7(ZɗY-M8& deB_V]oƫwW_|_O<7O3gܵ*4>^e$M7CgsUZ&z:u6urIǻo`edR{{ _RԹLW.H. TXf҅W_^.\^V!:-nۺ 7*R|lC_&ɭ}}?]4zR}!-n ۦ*RI-i6W#Odz&<z", j[P>oT#sw:Q-'1ETt4Jo3C5 +zj1qtW)뺚H5c_6ۦ$z?V9n+XWFu2,4ݲ݇ ҟx5/^.A5Leu֏u _͋T-=D:ಏ<6ݷSX M5=fb'j?N"-9NtN56ÝƉWA'?⧧"Jz&͏oɀUbulf,njDF4?ҥ0bS-,%(QepB)nsRE U5qd3gA1>~F>1 T2~{#b#IN O"wNMGJ*6IrΝF1R:m%dƾբų|?G̮epړ my`:$E!Mt.\e0(8s@HĠ?PF]Ydnpz6pq$V6Ayte\Δ9L#෥߄T蠄v05U %s3h c 6[7'.S&j V7<ԝXa{, %ZBss. ,)^rZc9~HH)97Np،]Oc-XW `F|=骘 +Zi%Ќ2 tZ3.`sD0C5,%E +سKh> +-bJjcS*XjAG#lS ݛt8#8Bጢ arzO#XSk +g.,{eܒ4ȏ3 /oV4$i!UaOƙ +Třa9,9T@@l=DTn˛;z +! "%ߝ18אr-m6SHl8JpxP-=F?:HO>1S`"@Qx=3" D@%V$ʲYhz,]-*`ch!@8غq4#:B [$j/>EN7⛶tXRnWa\bH'&uTU`Msx"44Ka!2܄0B)NI7,Jv({+88G;)^ 6 Ib=8= )%$9fu + ;ܢ <4X=R, 4B^2:lP(3t"'TE_;#tZ| u$`2`P jv+beDwwW]YhjNPTm%U\kr{7[uIi"1sJo^R[,Z-Wu*nt|ARcX$W$5ZuL疣 ?P#5+UA)8Y2P^r`Y6q91\*rslR`[.b)qqU^D<Ž.T[*/ĉDI +rѵ(6B\E2acy1胰X)5[w72vtRMbiˠU#eڨ$ޣdh3XXyѝ3i[_ad—v0(g)+w²}Ԓ[k. +bd|ΰ +*Ӈ$Mg(ϣO!a27fX6f*_ +lc^60P]ñd .O(4U` +lml TualS0PGmOT +rswFb`D^Oܸ)l(䈊ћRli!8$Shp^ox^#VvWIA]c8Ey},%T +!X{C{LL +x?Wgi{,iwDsh, +g=4I)=,AiSAvtVH8' +.{fg@ 3%1t͕_}vq2>lBM>d(.~)E%Ӣ8;xTaWbrRڜl eʪvEikqwF!mH|aˢ~[P%TE6̝FD(Ŀj!s48مM ֱSFYlWDำp|<ʝ1b&`DThco +im*HT%#2|;!s{)).Xl3Z%~Fp@֤U*& ~^$ +ENn2G is+ŕ q7t|,XE۾d[崴‡)6F[B]OS)WޔϹt<G\|s$e߭ܰV|ٟVHB.Y,o+MdJFDP֚>|!Gwy$| &ft[L&β]q֭BqMV^=KgW#64δ9C^^&&?.ʑ"R䞹;f QJ|cڄ.T򾮆gJ1k.> endobj 11 0 obj<>stream +hTPn0 Stmt4x]hW@M <+)N >stream +hbd`ad`dd vL) 0q6q5gy+y@HꀀIHﳾmXrj.+r@tE⼼⼼+V,^B 'c +endstream endobj 13 0 obj<> endobj 14 0 obj<>stream +hO+'lf+:Aٽ zg6Yi !ۃ?p Z_ot6 ޅ!p `4' pvWӿsԭ硸#uZUݭ_U?>p6Et} o-z'K˳vF<"]J.'d~=Fy~n0뵆py=繆>%+,4\(ۭ8~2l:j+\FV7)ϟN.7Z KB/K02My~xv65H. - p标%kn$2٬=ozy7]_vfN 0\My~0,dt:Zgv2ԩa<9KSGujX:WRb̔8QY ~_[t:V R Q;7L.燚<C$*%521v|- t:?DXly~ӽg} 株ZZ45+ϲqZig>&5M_.`pNz/yс<ϵ64252@$@Oj:]bs6ipah*}y>L~Ml̻R^.)57 ZK12m l6 +Xjjf\ ypWnOBpk<7l6'V*n`(,­W,K׿g|)λkW5cuիW_Ǵ(gÃ6xf{p4y~(9p|x&Zcd>ϲйc4G#"P_k6A__|A$K @>\? ޼~MF#th ) ի}q,g١O>p!᠋3!_9H? ~ěׯ'CWOGWîa,kIU>|CSG>8\>t7#4>}u_]=`zչ4y~LӝOn:B\EP/_jgqzwZӟ4&珕2-G08rBG?VN #yX9!B|#+'dZ`pc @  <݋lP~ 5xrBn~6ifszt~n+ϲ,vyBOcK,Vi&y>N?V|Vm`liejn>WVm޿_ +rYY> (pD=_7L&ş2fYX>?+ѱpˊuY8N]uc>%yZ* <:IڻfZ~bh<#Jܬ*>߽xDg~~hyB܅Qm\O,3<͊k,k̟Fݮxix|><ÊŴBX MGoek/E{f,E!9BGj>`4珕<YivjXcT%nrU zebzܲd29: +:gҙOU8Ot֑K'yXU$db4EnMgqǘ˜|>RTUlJ""c:4? M/!-Fq+=\)c7~z8g؂'+y>/pǺMq wF8:܇6Y +n-pya-MV <$Vi2YvgaY9l9@itih;ߧ*J4p:?aSSLMc%K-3$Ml6+f/yoSD,ϻ묭m6 )y~LMet1\~b?Pci9*-g4p8CؼMYGHgߧfx珗<`p.7MW.2ߤbQGvbH$|PtqڇBY+ #1ݽMcOO;:w%w-HyݕU:#[[)AG4reM+c%i] fEiQjf wiLSD1[p;y釡PF)QlI=xi9+~?7}Rbc7|Oz# GKNڶHyAH.3J Py fg>X`cbj~6*?| څmIPIjW-Q,Z6MO PIhOlAV IQIOe'E˔`gj9b/wellVy<Х|p^JW=|c%MQs6ĪZ~[Ӡ4?_jBcP{iB-2yXy~er\וhgL,zKy~vJU(5*|Φ m:}jzQ'~J[~Oz{*oȈE/4ml6]O6 +GKڦ~V銇yro˯3mz>QJ=Z +ځXq 7ϏcC%^ ?|ISڹqJ(jI?V|9ol4>Yi6{=f;ԶRK'ҡӡJ^h5Vfy~ƷlCg߹y D|"NkxLO2Wy+R9*zVW [9۔ϫ*_*~V: ӕq񋧃#ci(|E+#ݴGZʗ*7B?V|9o_mqrZu1iͲ6$iƼEdnbq~\V3rO?i|Y0%oTߙuzЙy-M;<n\#8xmTp/֊Ԟ#\|PMbqmq3ՔeGTEt-1Oo i|=ʚojsle:?Ӧt{s+5<ͫADei|~J)QIĻVJ>YL؞W>=I`Ӟг:t\p)\o|,LX+:,Babb_1n j - +*1> +_omiqGگ(dR۶bg)?+8Gn<s<22?[ $|Pm Lz4I̵K疧-YހJk1KGj*i!_ތʷM?̿Zھl^v]<Jv'4 珕2+=MgA +ni7M ]ytr}=y~gg7U7Cafܞ.7Rye(J6~Ay~?ږ4_Q߾,+ʗ/_>{ +={-|+By>"+y>+Oo6v\.{ɤi~Ţg_PnXK:O_[8#MAP ahOM|,q>y7F'|ngo8|9W?:gYWNbv3ۯ<PkfY֙)HDXf%z*Ӡ~S7e*>8*#POM|@?D|n<sO.7#aPgZCqZ*}v!OM|@?DNn}SJ&\NkυNѰ@S^o:lj:Cm\.+ V +>.#i_ xPVmOMMaQ`C$vJ08'i',pDߔ̥?"?.|<&jj +ֹ=#tZyt',pC$vJ08t|4 UU- H¦N>L&tKRi:}܆{<,& +-]Z""!aKG4Tgw|B4N$χ!" '>V|YwGͦbmH +UVlJwjj^ϲ2[IrٔZ/'҇%G78aMV쾴JZ*ڡڡw ߥO˄eBqdjtf{*lC ptCj@ew +g隸9/9a`C$vJvϚݞ%'0n<${X,b˗Mk믛 +o5մJ(a3ݼsrV; S誶o?y(ġc%AAeri^^)-qS*E|)͖cxi:0[e=ؿ׿)9rͥ<.Yʍ/_|aUf\?:MjZm+<_(t^nQtE>T(|EQE/8E1yEQyAM1{uib'6jZ˗/+ o6v۴q7"=P(ݝ+$''~r݋()y>\v&ob_HR|Yl6ye6{}B<_I~,սV2y>IJ0(M OiOdM L0( ~/(@49(/?5kۥo&^\a~QkCo15v?hJˬVE gKɲthEnӷjwEv?L?:%?iIh^krJ Y'&׌J nd)ZQhLH,>GYx׈f~"G,a~Q{M +=3JY.v;),};!?&_,1r~6zlf!PK4,7( sO }a?y3Z.O&߸<)*p;V7ۆ皜.'n6_ +/v; #n6{ߗHuSϑ]hr~Q6܎ +pv[reYhۅefY\,}`O)-l$<,3;fg{#^ g!m&t~w &y~_g -}U0V|Xb}gJgEIVMTtja~Y'2<:fcڧž+pZ}C$3EhγNe_BȲZ/GRsOIuL&ߴM9i?`wG-w_;Y}~lڎe/ĎqNURӉ3Y:EsXLgγKi|XzKqHa봝Dg "ÃF@Ч|t = +o^WK  0._-`YSq-z |IwRE=FhTs隺H%aY=d&Z4QKH;:9oJ:ADKA^ ۍGwQ{|t) l r}1K/8O?M8G?W~'?Qל>}̙3O=C]I]IƓO>{IATĄb@>_jڙ,jļAb)K4]dAէO)' < (ɬ} 999j++ .|uS #_?|+8*K5a\)%; gj^5Hs,GöGH9Nuv[,GjK w7ؒu&7wA]%"-b&E;a1__=f~<">ڝGK{6'؂t1 VC]666++c>I, ;<[U"竸4kFjc(! gxU#3i8;4H#9x$;\!b|5 *hL[i7eU >q버6zv`LksJG*xʥ3U6Qa LbyӶ AD@:Kl> |/C|dvqXL' 12L\̀MՕ%+&R%5l{J5!4Vf +ժ7eem{g)U:ti@OfgJ" ^c<q~ﰸ߻(c}_=ޜt}k -t{*!?cFupzR)i2C9HnWwKZm}jRʽHGf8J@ f6{tV=.UODOWF A7 _|Qߞ> >܍dx 5A:yz>8a{ 24)KawWT@qGxMv +T}#v8}2-A!_i|:$3bx'H_uwuG#&??? TZ|8Yϗrzufmj B+3jE ?_|] +ÙJs2{̾?{ h c۶tw@VbC|&BV'}YE 6c#Ф% +Q9jsp<j캷Vt9[s(Ѷ; TLdA,Y +I>x!x>/ۜ= v@>F,+RwQZ RT PVVZԼM%xZo*nA%zHߏ)8;HޣqwTAD9ҚNܖoeU#Ͽ{GoOߚ9>>j++ AKQ!`}?Oqy<4XEsF 4ib#Uv7FΠg:#WMJtL)VIbzHR^ܗ&Fհ>"̐. ^mCum0>)E " xYҪ6V>s2C|{mi7o24RgE( l[ya"5D>QQg2uA`99GЏ6ƆJW€̶m>G|(UoӤ?,ՕL>|#aBK0;0UōI/24a/`S4Y妹at׀ #mkۣfpXFvE +4i8L]]{nJlzra[y]E׽[ww5Y輡@O !TG2[q pE  ekR7ԡ\EE+X7f,yr`̈JXMDFiSmgݣYz>|Ẋo\e`01^ + >?}~MF)Ȼ +ivVJ?l/Ryld)u6xEÓN7Tx{Ӫ1a"Hg1XaYʙx6g|~L=GL}&pFSA϶Lpc 7G w^?J}|3^?@>bQY pTQ,QE6d9*> +(RE+VϷ,KZY>#Vb(isX?pѮyQ}|Ir +ÐJQYw#YZth9!yruuO qJSڔݶ,GMH5߫8zi1G<#61kllld˵#Q/*TbQ(+g=}4b O?o<<+8<ʁ>qKW^ɺp8A?qS +d \N`,*d^_b]+ +S|kn}k*I/?-k9s&Vb~>XM+j0$c7,**JMiQsu&rbgZ|n{≷ULJ)Vpu-kn} +ڕo3w>_q(ҜW JUjخUϼ٠YYق4׋CWTҽڍ aPŏ(;A +a)lW"Rْ p**3gdYXQpEkSܐ!W,|a Ρ\(|^=eYHQ| q'5? +7}YH=R+Q0jlmixRJ~+mrJ*Y;J~\_4~ /=t KUkR8;bUѮ>_'ފ])#MOiPظ Fj:q|Oh[ܚYd~*s)7q` +w gy7o]{kYvߏkQOظ:7?TYxl14ojm_,]ݧs<tnHB D|>^z!y,hUM59KY'> ìB]q0<>Rf [UxI۟7F5mP0kP +?au|6˸I:Jͥ/˭kH,0T +gy76`;T /;JΩxܝ}yVF&~Q9i_ᵔw>amۣGA8pkŏޟiHMRw +(˪{4I3jo}k7G +K/ݮRW0*ԫW[z0xmn_+4T>\so|tBs0 &~zktj7ĉ+XTq?'TӼ}ٛA +bS_sBUJVEo6;MԤe|>YP3\SK|~+}<WV<|T|ϣlb؋²R:yJ`<,57{o~CHփu"M/T=5x@k8lw(J26+Iz}nWضGMU .N |-0uokb/#"͆Y:7)]޵A=dYɥ{'󇷧sDm[ܦ4RҰ(RnD1 ŊY{>jP}wK)~#_^T|>7C*<&Dlڄ; `F㵢Un&ͣ # ¬sxԈa{іrNRapxwXb@Ŋj?-|)5 h ʽ5𮆍)v˖rG.K5(}i"zgm+#]5\E R>s2c~g|>wwwaMgYjSPwsCbYJ1O^KŔb3GJ9kG@+7Q4 G*rXYYjNR4 /Jc[0t0RBpk MfжMvtyy0A|;'ÏFHd_ÛGSOinERefYJ4$80l/5IS `%d|֕I}Mx||#'>$7RS}~~ tT79PlVW*P_ض)܅&k/-@M@جYY.ws֤H9} !G9[.M|k#ڸޱ G҇sr.=*3fʾ4a*sԆa>LwË3ifŭC* .Gnk(ku#Ymc J'hKludviyp݈{꾆Jss_or|&cGݔ&MgordBW2s "ώ0Ĝd>?91ϟVM,vcc#+l&CHe |hLidue~@i,/UWOKmd+ޠP0#>Њg2ԟaA}#}*sKX7U=ҿ uZAp|߇Rx?,+Z m^kGϼ +xS?^#D"0a(rkfXBn|YHԿ:Tw+|YhvcLbpg0,^Ų:,UNPq)8T0I0as# +tb"Euўu u\Ødz6BDFj'RDC@ZYR]dl7mpQnV<"VZ %6fBUjwK\YHKKV,MZmwDLsEg PH3K^1mrFt}`'ߚ/$GQCRǂAgDQM+:/_<3n0&XPʊ'|H,;0 K?w +^o>_ Y]OkC:"n బ8V*aU+E&+Nz/,S y^RuϠ % 拭xr2IßڡTY->o&P}(}/TІpLN$F)ϣW!|ߏ4q\)_~ƕSggٽ15Z$E \֓/59 +J?uӲHWiO[ZOx6 T7pFͣχlw +D٥:y&XPٲ}/ޟL_| xDY]jDQ]܄>Jr"lgJvB|4o?)|~#4=opxKRE}TT$ g0l{$iF/%l/ԯzu#JƤ'̩R4*#k"5 +J'0oTR|TqrL~?">s~<5.7b> ӧ>Uuc)]abia(0|n?||,]C?ȨP}*^b>JRlA A dyOo/ΟZ\,Do}~qJm4tP%ߏ[czM!M7fXaRZ qh.Բ ψeA^^u<<;"(Ϧ?>Rרx] +Y5 Q8JpE|> 2 4ȳdbO?df˺VNY CJ[@_*iR ]i'Uޮpt5(IЖV)Pe`9{KXhpwͮWt)#WWo%'ߞ>wLfsUfR| (nH81?r\J TB"t&T.XiqA| Ɗm:a{e&[ZO';`p&.Ļ'wtz``~/[unsm]E}hw)9_eA(hۣNݶ&nUfYV7 gЃ*Oo|@P>A>v1|>v؏#DEw+CeVns489&ދY} |7*<"#[V~&&6>&7[$Rr>_޵\.ͿLTxF[LG*RuoUwi<64V%Њ0 UW@|pc JI% }i_yZ˲bRχ^IgwX#M8_/;^1XRkᰠR+9@a!>#Ɖ`"_)@ K|+J?`Bwee h&7.]v/9!qIqAk=!ͩJꞪ vwCADx6FAq/?oO~]ߜh`}}}{{{>ږ``۶ .>S(!% CvZ'0㢨1 nDpWYF/S$.N ~8(aoTXzW0Wd k!u^&T[^0:*eV =W>KEUy=5 Ԫ"O^j MmWFV'Y|<|VgK#_=*B7BDo*TwPŅpHV@=wG> ^!戦ʱT7ee͕/ϿvD^X1VC]I]It+^" p?|EL>-THøR6D~TֵV戢ToL*A0n(xtc _ 2zޘ'ABLdeɇP2m۶ ߗ(ߞ>@|Α]pMf3OPWvmǍ JJѮgn^jf|_%!W@_():%m$.1g:9 1 RKwT/(4jCG*_F6ܪ؍=AKEmۧ4͠),ҶIvJJ{]麮eY{jTBE>![%&epxuIe)n'sZ;w*t-e9ur/GߪhuAR053M1e C$E5AQ.|`iBu>_*rj:h(*kw>9!M3.i,]|?-4(rdM)aP |6uycPȏ " CǁWT0bKx]}K/χR/Ab=_ [42 Fk_V$~ ڽN#cuu|p 45',vf58%Ҹ[%AoO >萚 (er( +1VSK5Wsi24׫b#<ַ񲫐n]iYf씵Ls\V遰AQe|OAD(bIڞa(ԩ:'wG/,A|~7/dluuH?@B{KSa 66a\Y*(epp߷HqmkEm BDatߞ>& b0qJu]u^gEyE>_C*rAhZ PSi0V2| iGѼ + XFR"Ʀ7ar>_`E3 h#m#A0uV0TƧ .ۙov+r !ˆez %mq[~&3f\eZ! ϽnH7І; : +l]\=^?Ȳ+p6AH2 /rF«GYOyא|~Le3^jûDf_}Wo9R!LHi":4mr,W„' Ͽ<~mIѿ=}>5 21 ۮh8AЙ; +pmmmk nuݕ7* ; VE2 tnRh?gʗ'N+א|Bggl{/[ AiVȗz'3 .`꺷1R&AhΔeҕ 8 >9Aʥ{#bJloo?p8}hHQi5H^ue~ 7\H謓@ HńJ8}/~fU2ՉZ@"e  (*A*g%l^@2y(|mWF|m]]~eW:"bYs¥=ip,s ʤ'b*2&<l[8=1A677n@^w>0 i9AAߥTo/*z-766>OB!&E\Ȳ,& CQ1lmA2!3 +" $_Z{[~9qQ1 |Qz*^$P!-D ETiҢTd>M(  COı 7) nt㺮&>K]3۱E5>?Uk]RSB2URX`<YZF=Y$HAaSK)}ʽ߶mq`x7IȮFՀ|~u*FS>_ YY٢Btil82JH#9\-BDQ𖵁OE/-  Svr)PO}~ogn2/ +/~R L*z*#H-gy268 CTÏNdhNgֱ|?"F +ϯ|xWysGJN`\:#M8` ̇ՌAD |kwNriBH?5.(r}>a A L>N0dmy^O|޹x;>._ͮEQeYxilG@W<Aʼn\| R^zUwՁ|~u>WQfLH>nYVW*j+=('Obmet< Èa||8%_緅:}J}L[?獥'So=DM;\4sM}+Ӎd>AQ'[fQvdzr2(: G+r}~Eq +aͲ,nR%8amqN>Nzu1\󼤤3F, iT e~1x| +"r!EɀWf$Q{?#q/#Ri0ޥ$bRL޶g czM%*az7*!AD͔/cG#Ĵ0ϝ? ),0 Y> TLӤ\|M5|ճ֙eZ;( -x +zR. +"$$kIQAZUq"IBY,zfL=5VQ +*E20_HARϿytqs2Cdc8! |R&Of0՗qp=mYu\X5~|Saxhil$7|NflĂJ4(J1˲* o")ڍ%\{8>^zU۹A>-ûA`8K%'+亷vCpd>A-|܍os~kߟ" |OfMo:+Z?qYw82.C|>ONfG/LȧRn,ZR. ƸP=Xem}$ ܨ#>k%@.|>H+ ҩIlcHzHcj,hs'=gJ ?k>lG3^G̏7X(緃}q^>#OT4%cۣTL J.D2 h|> jyv&gܣ?޵^Gֻ]M-ȍu !$$ zbMKVKX'*jmFfLDaA,rad~Ϝl7333s2+3%c&j! H|~$fSޘ7 }Tx!q*#Ԑt y7[@k:Yb*Wt#NZ+FiAӠwf$Ɯvī_d-]! =ޅ.dRr˾6,Ӆ$꣨fB+%NII3Աnwm OEXnR>_x%r9Ůhdᾔ]N2q>Nk Bx>?ɦŐtr{+tl4624U+r؄GH24fM;qbxŸ`>9gQ豄j5ӅTIB=D0))iZ,;8`v)]RV>ᣧ6L\n|x_񈇹\.zN~5|/I2Fq(Aw&pa.X= xJll@ WPC4̮e盵!kZen(Z@Iw> USȞSrsٱr"mORcf(V #DӲz/1_Zh[ #|wL[ګOaVJs|v3 _ |〽bK Km#p4U*wӫ>_lقh>qhbh0< ;Rr}q(ٳupyN]Aa1,`ޟ3bX٘3;'G)OۗJlz|з_лU7nUi3|~0L|~l \U|{|撒&|]b]:+6Ͽ0|>/?W?[lGPhP==\~:|jdύ7M +M _hG+B,^K]]cuu5 |A/po +6 k 3+x$OF؎8q;cf(LmX"mOϏM\Uq %0̬^8|-/;;;beLI|(WH|>?I wED5Ci](nGKϏ3`_8GAGq|@d|>9E.og e>A+Sjܾr&WWhV^vO(VoU^HӅa_bZ0PpFƧ|~[OX"^J)|q>###Xv"âVO),J&tQKLJ%(,~D3 BtuloX$7DgYTc_ TDNxi|~0l}>gfV+Jc C.|p]z*MZD9E^}v\r*RHo @ܬֈt|>j4 xufgY ^篟|%,|~uVҬ`|>p>!3ҙg!*UJɱ}Z- >S85ĉ$4ݵ_`C7kxE5*cHDdZfS_|ݍl|EQ؋fffj~I#YU!C#Vs>?S4\kgY|go??/d.xÉn0oqgx|Z';Rxr5P"̀O x!!|+5YigpnGCj 54bvlQAgriDu㒭6DycX{ .(݇}1v-?og2v~s[. J뽀nāw?i<~n|^KB⻆TttZ:{d~bCA\ f87ކg޽^/~~D/7eMp!둋qj0A&{(p)Vu!{ +|~Pg81hooG@Ҁw?~q_Ǜ.ѯ'$fXf%wthqhFF1-Vva-0N-3mR^fffJDm@ HwIP(?Ov#tXѱ%tI1;ԟv+\Яzs/ ]|[eJB|2J].WjL36.-aw}L(XoJJ}~(M>|.接^9xUa}t̙g閆+Ip8ىeP677 Bl|9.AՃ[?'Z'i3|>`;]>?"ƨ)ocI*nf -boRdU~4 |?mBh 'ft},rT|Ci:BִH ׃g[v555L7D?C(JFFȫ`~7GPjV%!c[>?G}>u ݎyG!/h`qkX4O}iQHT 30 W+zsuuuXV@ 0Ji(,X@z1ӚVZMMM~!aw#OY)gO%Bj}> -1րχt>ߡ^)=H$L[O῞l< +,}V( +w$!ۍps/[)緛DH>?.F;ԟ6 ;M$B vmXAQ``p\Q(+1# KdUٳ 3}~Lzs].u| . i;ԟN&Xm_/vJLYm;sT8߂ Y;ȇJ߯>vH\.&dDχ |Ciϯiᾥ'LNH @_1`d)c.?w=sڊy%H +}>P? +G(x<'@P}\4t\W;$Z g[ٯt0:B8Hd>o nw;l8ARGH~?|Il;|C>(m5˙%Zٯ϶bvg] Kno~ŮMz+>Q57BpSza>^B ,>8Ck}@ #/04D]o p_C^3I?H 5m=LQ-FEAġT#n# |>ZSoJ. +HxFFF_$wc-`)(U>7aRÊI@ =G"ȋ} +`g4B9E"g.vc_LAzU>k?Cn(7צfҘl\h?sP(Da]fn [v܊n.K9WpO=ȋԟr]#eM|| G H#$M$rds;}0(ٳ8.W;u(2qCGǬ5,33 @ 9Wȅmv&Zyk&h.q1PA No6|atl_۝[^ [['ۅg-c˕mjj}>dۣRF&BW=ؿG d]9s|[.8󉸥>.ģ ++X?:LjV>?nQ7N2ɺvF,iј),)јI(nōAYLw],Gc(kcqM,2cS5~B#5q +{ha!հlќε3VHAfg!<]KJ7{c,nQ,MMROVY=?k՟bL4e&9M2ۭfX*җQD4\do:dIƼd$I>G4mpXL1?b^\37s(&X̊XPdQ\+]g0y1Tf :]Bi&iM淫&fp#>np_2J3 oX~,JIK9"\j zVStH2Ip(Ŗnf\E*afS7 H_% PjZL2Co%ۜB?$|}5[M{s̿+vZsv.~kgA·{9Vw[}h{Ez[<6>7|Gx#l8O{'kt3=tz͑ӫ;3ʪV=ꕳ+_=?Ks+:w-?j +O,/S~ӟ/յK.]rvuKjB7/>>y WC^?Q|Em[ r/5F1[_F+Xa5Q/j"b_i5r>,kXWFhA_݂Z5X}5};Fu7~sVoNoߜ 87Q,N. Ɖ/}Ow_RmQo]Eo.fޕ?]y#jw<ʫy9h,y=/BcGˇ_>Ƴ/?j<ٟ4Ow! 5~ǗD%]KY𒮇t=˷K.=K[,oWe;e-k-k|pم +C>\?x|ph}rKkJ׾Pu;_GCO <7P?}+X/(|eWvsɫ;3՝^ݙ[kA.knymͯYƞ7Li3XPb果DˬF3̼hbbf_cI厥;Un_oo_vcū}RP5 m>mmEnnQ{t㽢yo;Nl{b]'6t/%6&Q8MShmJV7W3[elߦ(9(ٌ.5Qb)ObYZ",i?#hMJy'%5/]yO&y鐐ΏYj6;v`ve Jٿk%ejf_i8g]q+]qZࣞSz>yA>Vxl{GWۿ[UUonu'VĚ??u5^WxɵOFWYU]Ԁo3X4:ԟ?<#[WSٽTRݱlvn{n]BfGv1y^l˄̖f6vkvk6/fbC`d_^!Q45m=ɼzzN`g^_+}2CKPK4LXIC9כv{}>\C1Ρ"H2qP2V>s]3!oq)4q}>?ےL`ݮsjfh%>_3Vy*$YL('wS5hoS^oqx"ybχχχχχχχχχQK}~M[Dєw$;;;Gs N?X/J PH0ZQ6; M &!%q-mq)y]42+ yC3VR-aq(Rϸ*((9>T`$w$w#24VEy ?7`z(ruIǻnI#飙?Is`Y;t7; Mʹ1hMY^eS"|[6?^ť|쪡 7&1l*RϷHkɝbwy>T>?4D `g >|>|>|>|>|>|>|>|>|>|>`dC_kc +}?/N}>q|D\Š {}~DgϧuT!n[#]Wf322,j ԇwm7<(>D NX"f3mx!,%"5{^ !R;ɧnIJq>1c~0vļY"|s|6ii&C$RZo41z^2hXvȋKt3O6wIDK!`ҰZR|K/33$xW1a=byi5<-4l&|}񩕠r5>oʈ~F}v~g8_<).<6qUvOHkB&f^3"~loF LVE$%NS}"Z`r/V?N7\0%0;r:$} WP;^ /6|8K>LXASox66PmJO!_J@.~٢.`W~E+ˆp;X)y"GkQGJ$ Ҝ/iJ[+S8 +LQ |O<*5m=d@8T22ZnjA J:(5KT>_s* | 3Ev)=z}[$SnZ+^m($#io NcvZcװ֗]G7)=:@|jLZ5/V|Skw܄jGF +ו}Nܕ2O0lkp6-<.'Dm||||||||||1f^VDOI3aEq#N_/v>VV\}EcDל;=.2ſM XZzEQd~X]甴,m_7:yin\e: q/y| yYAFjχ&Xۈ_E|y;gd}sy}eq |T|>k8p|kFnχχχχχχχχχx!zA\.]E~r|mT4vү˲]~8L#B Q^,:|nVC_?~RnJ|Rr=H:|Ԫ1k6+A7|[x]mqG#:W}&Ki>4 +4hEC hb0i >>>>:붙qJ!.$zs +{Ek|[1pC &J/ C^k`Ϗ}H|EQߊt~:fPK&|\6(Efv}HML\{<Coh5%;ܱ'Ekq)]1XC62U3 `;wVI7ʞ'.ҸO~xJd6:71yĖχχχχχχχχχlIcz0{@r|XWj%҆ds +---_]}K^ϗ ׉W }~DX,ZJzGcPvv=1.!>%U> [_L_y..øج}BBy OujRI|\ }|]x^r/_=WsCۯe|q&;nQf||||||||||($R/q 5$Er$ ++66+sUUU}JA1M~enj|}žsS٥P݆otl07-4OGt#}>eQj4i|>oϲ'7A?UB/`~\ʋ֭||VAtl fFlӻ6F"TRx,\2<=o Kt.Maج;pG +|ޏX"@pC)'>_#5za{Ni oxP(&YYf6ljjnyU֗_`DV |:.4"ޅ ˼`EYMa.h󲝴h!|>|>|>|>|>|>|>|>|>|>`4`)qGrSnN6w1϶_7]kZ}M|J̺ 7:#BMV_2\z9vl᧢.oVbyPKΨ&[m A3WJn +m?w4χχχχχχχχχχχVq#-%|~*_etLy}G9_s>?G^z^U)(-iͩZ5}} gf#),xEa0[ ➯Og,%zF'j,V+1C6-沫%wMOJ;8044v -~y}U3e:so*3hΤmsΞ=;kwVw֬♳gݞ3_[vܺ#g;)f횱x׌%잾teb4ϞXgۦmۦl}ۧl={[zG6;wfߙά{vڵ7kެ=wMɷ5&ywOIwGc"EQc_{K&W2 ?cqτ{n_hŽX//ō{cO{nFwRܥ^5jܮmj7EcM>j+ĶXU-8yBlRcb^uj~5jUBTj,WPeXP$j,X,ouޤ_Med_M?Ϻ7?kg,ɺ[^;7.Fa+nŴ+Y1}'Xg+g,_9Pef,폜U9KVYFުEr9 (ܺ&ǽ&53oX;sԘv֜uf5Kf嬧M1cfO0{S60;k7Ιčs&l{ƹ7n{æ>4oy6Ƶ[]%X5mb&Eso, pEd5D۟y1; rg,rќh:fyDqhjrDzӂ9jXD?SΒWjʚN)by⚶rԕBZ`IhS#[HeEwd {g90MLn,Ĵ&4x*K\Le,'<iEt(y#Ԥt`IJ&%!/&楕&5jSSx@v$_>Gݟߟ)1SQܥނ;ո vٷ-jZsKlWxo,QT8bk-jl.bTsr `!$l@>-Zmx6eLxNi }S][<@8($>_/}[$;wn 2G|T>|bFF3@r_dh5+VD{ 弙 7<*~oy<I;_.Z*c|[CyoϠD|W C8^ !b{K[oIr;͡j[NdwC/Cn~h@1" 7v]3ڷ#|:з1b_ OK1 Lhx  +7AǷ_1ph#&>_\bQR$s>?"d`Clx6c7,ؖGq ( +b@">ȫ?7ks_q_{(u%k6Ȭco?,Û7Ft#5\~CUdwQ.}Lп^ G}>ނ|6 EJ0[83f +q $t̏ 3|>v%$ϧ)MgaC[5lyBԍb'7VtŮO=~^PrP>tsdAfe ob°h'>U|@Tn@IսX,jH2}>>ū+}sl+S~=| ?P$KZ 1ض@|2&O瑱jxwDYi{rP%19W|aID'a-$ { E /8~ѷ1b [gP)hԗ_*DH}^~oz:>f,I6.()i[Lg(rxB%79+{s糇;4~H|~|sfF!)Ǜ.I4殈Zfwv|)U@`L<18SR7;ߕ=Ure̘ɹ| ij|>'0Tf^0dgR/vJLm# q\))i& PH|Yz;.p_՜kIOmYH" +|>vzjDy|4rONHdNwϡmmm Ø iJGX> eUUVxq~E*.M`0xN?c[hο]a2Ԩ~E}ɖ D|ЗtJXCzCd8̩iqsT:;;1ҚQ;gcUZe>k76{O 3hfT-5}5KHn)R!oJH"@J LE0o //oLCˊ':9J+k]I|cɫ՞9p8웍g}-L {Ge6\:iIOOϏԲ RSt]$>saXohڽ +|@ >HZ"sZv9d29PmSNj 鬁jǞW +;3D]ŋglYw21}݁#W#Yq)^ `JO{n8 t'|~:+lNߦSamDSu]UH$"Y˝s0esSMb t}-S6?Eͽ̷v1ebt0{/x<Λ2p{O?/GQ4c|> O4321 bJN%9wkay,^QI)gFb.|>+\=;¢WUMӜ:imqX̷5KJx:lӜO)]_Oӏ=O(S33ҟ'F>M:6Fhc Rȡ/|>7<1?pj&_>Ww4{r7qW?ڛ<36DDOjhGG鏎&_MvOgsJ|um5v$=LHstg͸4_Ζ1IJϖ4GldT(bpҌH?2,eF͖ǂ{%ܠ{FGqo>*Q:O +`*W R>pH+5<.oڮOW컻b7^G"c:ݩCMfD߮G e|ATt<1*;4N~?"Ȭ2$ ECNL_2ҟlJʻo~g?921U#/HMKC!gssJ~9g|GAU7uw}^\MqKfp<Ms&)؛AMӸ?aIk>gPgV21AI~M}>kj퉩xSCv0dS**eq+ރ@δ39FCjЉ4se?4!йWQ۸|U4iEMW-4ExJL.yxGV^ʥF.ۼ+囯\ʕ[jУ˯~t5.c~ز뚗]߼W|ōW*ry8r-_nۺۖ۶mKXrK~?<-y_nWخZ\>fBv{"t>;~[{n,}>;VoU BFW8%vA,2OOX&K:/6k/×n#!?'/ϹFr+s+]Z(mk]4[)Ӷ[#YK,yuk.ǚ+bknY-+b7|k7z_[};o׿կ޸i7Mk޼7o׽o߹z熻y{׽}^{]?x쩎|g}WQ襞U{|{+>O|`فeZ2_ / _RS1_5v$2rh&,-ɠB|O\:>#ғG~EeHč|0,F]!sL9eM!oi7}Kg#i򊑗4c/]6y BO,Ccd򬑝3<#i#;.v!Oi1'l3Ui>cF5Ef#yel2ҴlQCFjA!߈:<g/\Z"|S-!B엏>dbJդwZC?<~ovP>4hQ s*i=>HC loVw{?nk2骆mA|άzΰ +\8XJɁχχχG ~ c亾`} dz6MR8 4e-5Çє$POe1E̫2,Ԕc޻HSϼ5}p +}>kzǤ|J)g:p89G4 e7qgƦ;zž5-tvZ4Ben}`` N@5DSyV ")>1_Hzk}Lž>( + 􋃕W +tq|>|>|>|>%8ľ}zDͽSE}}}L7AS ===hJ`2̷6cn~/n׋~/ jh%7}# lF3֫w}>9b`bI9 4vД5C"ơp2Ӕj(_^$:ܶ$G"RCqχχχG r_VuhW}bߚփˑ)8e|b}ם;$|ϵQn%u|WχχχG&ž#fՋ>Hd&NKT7p +]m`0hs|^UхkRN~vK*=i7f-K||||>>>>>FM>]/ +cNKRb{F&xI?PN{8]׃MO \^rxQIubփ>b|j2oӒ{f#0+LMwdXi U, "43lse> C;hRҽ?`pu.ϹmN#E@8u~cL#SҟeԎGq#Pgnw Gr_y kN[^r縤{_䐻GEO '^ХKJBh?<|>|>|>|>|>0o;!q>@P>8~ H*K-8bڔ4Rt`}! oILK:vʩ *]:>όP+{O*0/>>>>χχχχ4o=(Kfhc#ShA@Cݸ;6Kiܴr릏*DFb_[}O_4)oڮ|]&]<.|Q:ޮ}OgKn>>>>>_G6B@ +Z4VnE4^>7O/_@Qاn_>z-II~ v+›f3Y)&EUUv}He8#nBᰵ($iiN u O >/ik_ +匐ϷG%:Sz'=r0+i`%zgn>>>>χχχχA;7}>ܫKO2-Dg`` z4e=7eWW$TUnہF̧wā5Ϸ[Z>!WnrBGEOXt++vX4'fP!)+ރ@δ39FCjЉ4se?4!йWQ۸|U4iEMW-4ExJL.yxGV^ʥF.ۼ+囯\ʕ[jУ˯~t5.c~ز뚗]߼W|ōW*ry8r-_nۺۖ۶mKXrK~?<-y_nWخɧ|s3-l|6IH򐑿yF6s%DW=F|<<B`=Y2r;X.|ߑ5>,+<.===]T +gBUDSbċ ++ےeXSO>͵ I~Iɺxns 8X/gK$}> Sc R{`n|(HY Ocd0?AS Ԏ===hX,f՘@k þR G֔ AT2M7|>v?'G6J k4emf)u]F>~:K-˧M[]+v/ !ko|[$>ɝ>_.Zɍ=\)W8d?T0QvM y:I1;jMTUeώPrfD xE";2_$t ݒ iZnw|qփ|>oPs(U>AA|@A7 RZ ^G6¿zu=Km +sgQEQu5+:ي竹^q竪*;R*V@gd1Сp>^󓙬7h>@R 25 5Jٽ]z %= c'2{Qw[EϊɢѨNbgfud&ԝP;FzܫKDP:;T)&߮(:9D$5Šq{ׁ|nk|-g۵˜-27%|>k>}X~6#id&KAH$Bo(r${n&=Jp\ժޛ'o-oȬ+}T0%A[nKfIfKkZ>Ū~uz|?vdbʎ߲7|'=.|]$YlR|>p(9tvT~/qAj(TK@@B(9ACe'?{<]H;e~>PPH< `4{+ճB;ks9O?%:hdb*uwdqjh4(oX,nz\FdbJ4ؤb1kgmlI:\9=lxb +=7rŸwڃ>hN06_L:;TۡCW;hʚnkU֌x0wPo;Ғ4lxq~ݮ^BϺG.G YL)tEQ|8RMzpI`Z&ɚޙ!fH$Ԕ8/ҧ;p8\~5> *6:G]lGWowN[w߫^῏LLy\H;6}>?20O|M%R@@h4`7}~_2=O2_Z ;MUPa8KG"P($~Lh(uٺiY4ДZ||)>UspW:+𫎆 y=h,^85#O1Ò>"x秳\tI/.m(5;"x'Nꬳ]UUV# B&?g<#w~RZ &mgZG&ԎQ{_$pdb`jyP#.g5]Ƙ-IJf9KU?N3@ňD"{Yٝ[ԭp8,~< Ҿy[XOw[{mkBiN|~.?$E4#ah &kSlV;Ǹo>*QCO;Yf`ΙnYW ~? +[1:C\O]}.yqht$y=i72&9G<|> +SLRIy|h4Zx狌LLI|~scڟ^8TN]t%u]BΚ`0H[,jfz moO}F\c0VϧvSiw6Hy@%*BӴ2ߛaoMS{v@ >^R)f1jǨDJ~ USκwG9s/nξR~%&xK;,:vΐP(FD9>q|"L|bn J ;`Y^E>D 0ZRN ˄ +t]WF2 ~a>曶 fksE|B;&:8PEԆϧoA &bZxE}~_2#DM w*L4 ևаO]*oڮ aqG"]EQMs=uawk +9_h^so/U'ԎQ&?#r`0zz8gן=IGpMQW\>xC+oBgGji #yltO?tgi+NH>+ouxw>ۆRMD-imDg`` ߧAS)F<sj<% I:oq̳E.f:] K#9ޘ\=:x &D^@J]GFu)&jN.T*Дhj!ڴZ&`uUb56XpHER/| lvpWDv@}>zcV4]A<5Ju|;!Q#SW588a&?QU{zz)yj;HiSU:JZ_e7󘤋^a}>{lӁ@L;ЉfO8%|@b[qvj6w$ݖB!*mC),T*\)kl6[MIJbaGi4*vg矵o.Ew[E;bow n !{tKJ>'=dsu^{+9|nc]seB\Z #;Pu>dbJ"wT]יh uq'v4-!^on*Χ𾤋>cmD}>~rz r3 UP<]Ľ<>P{P/>gP#Z_vN2`0(esO4u'$/"m@E?[-RpԙW8S8}Q"?6u'ԎQۆRSzp^i1kA]1`hA7ng<KKқ- 1+TU5$s|>`$`K|@ C-wPGm{0e.%ݡ˿>}(@ͽ:"c0R(S/]ldJ8Rjm?D@'_۪ԥ{֖-H;DXiN: +H%8ut+ + m,KCy$EͽD2~)ja"ڗjX]V`vQDr-:;nm2|Ĕ7uW,7=qISt}]-~HM +.nK_\(Wt.ٽ:4AGYzphO2Lf"kU?H0CۗԵyjij#d 22co7Wnx߾g[w|~% :L2@uEQ_0ɍi}>yA>l%ʨ/V@1C.yXȚMh[?RQZ|?.P.M'/2b_{7vR|:j 夛bB.@9:dLL>'~I (wD6MRvДh2F]>EJcZ|oN[Ǽ듁2 OiϞ~.|>&kx`RR$AZ."H8nhll"M>7v>k%]ȱ%˹DSw頶חd%HMgEo]@A:M,Q4v#wV13xGQqutݱSq5^˧>.=v.'@ ]pZKmC)f^~_0GҢgU"}}}AS ===4% 8S_J$)!Yo2g'Hs;_3ohء d>emfϧ!mNEw 4xG8.8G#pw Y$Jn}~_2åP2w{kZ焪~Rdlll```hh'd5p7Mid-'LCs_ 'Ť% #&Me>edb˧>3tV; 6gtrF)ojvI74pBBwwPqP`9(4dP>Rh z)[v愪~J¾̧h葯\/ FUs->}7>$8ge}nk[ Mv+,F9@\ Cjq pdPH(M>׍ +{ dI +o>T'ǏqO?P>PFuQwp|M~Fu ~c$t|LV⑚{uZH~oNO +u*uȴ||wU}`pOF6Kd>i~&廻xcsG#T/N6lҊ}mU{gwhG5b=7UMn@j9`%ih)%dPӒZߠ令>[Nx廻݂]Dze|i֧f6? r/ޖs_Зeeaw+VXhd%lvtt4JɷE bp%W'y$^aUXVUEтunWE#8KN(R\F_>ߋxmk4zX՛/e tZm02};wҧayw橇EE22Z9Cڰ?)RZfC.t:]lT*Ŗ^Db+{UaUXV$O\dZs;ֽ0_|@/s\ ҟ쬊jU[n7ϮA/> S]y@z[AK\$*C=Ԛvuu HVtqtt-SU/$Bɭª*U[gyIV:v'v% ;{7Ԫb/u*C/ƴguU/>ӄa=jʑ)+;||GA/A7/>exC:k֬$H IfDӪv}]+ +ªZ՞={N9f~CuہVF-.X@RNˋd`r nUk$%u_ܫ9|j޽|:QEaCW5s@4BU#@}JƪS:NYǜh+_`xƋ ؈b≎cr_0ۮqM@<\B$\,Ű!:=v07>KOtSv~yy~͎lmV |>@ ~q|>?J6 ۚuφ\Rၼߊb.\J\J':g(zu w^E1hM\:hqK]{>ʊϰ%QRWO賟qvvvx + '|_ F|yL_>M2aҔ ˦OlˮtI^7믾t W7^%t(]%~*.Kn9vKnUo 7Ɏ탟}uDtϋnK4ĴetS™FlS&P\9eS3MD:m"Oh\9Doq[|[7ZҚTV\^W/1-Rz\9ɢ}qh +DgL;_1u8W+1"1itLDxtL92x8bnpk1::v61{8D6ѰH&idF!7LILOjtq=+Pgzcu-i GG{ϙ%3}fI]|d#u{63KUBevoH>כL2:6VGGG{*p)q)9|:.ź;=;6% #]R:fEe~Lvɽs|AFe }>u-]>?w֩_z +F7Ȃ_^Z+|ں╟,ZT[__{>|uW?x7^Z ȋ0::WWu^>{~ssgc w&8YҾht~at_@GHIGo^ׯ,hk_?^n󒷛ݬ-}eo,^ oݷ5ݼjk5co|t\6wW-W-yE=ydacs;s;nFǭ#1[rf;ILHbM#q#57쑸>^7:[Jmxu)_(ib{Č1st\S(?::|q}&E?6v47 o?2;;6;_d8Z FsﭾێEdcHܫXZ64>;VV=mʑxpBAH<:>l#no,Of"dmy#)Ўg6x+~\[WvкŷV}}/u;6u?Y7ozs-˚OٯŎ7[eoA)qit[?km;6߻-x{?$_};^_}=;6Cifش?_[LY^[L e]v6+>c=P޻L ӼoI韼3g"?}4+/d|&(b 쉩QIppd&ʿ9ߞL)ȜgPym`}lC&8DEMa$57,Fc_>KҵHה.;n̒K2H/S$CԁWSAƗ]*iZ{C+##TdDs墕N JOO3dRn],-'B>@gUHZtkS&kpxK:O-^.e+Rք|>SwɅCRKw;?io>>>>>>>>>>wxak_$]6r>~E+D" p)A**R:<zKA2Ti"@qLSlsW1^AX.i:YD7$^Oa*mf/P ЯI6.o +57Y5N^o&;h[0|3.Z p.Ei +Eѻ/,_Ԕ֘C7֦o4GcY~hq~4zmKcϯ#!UUiShЏ " +||||||||||@0p}I{d^u40%H|z0>n<sJC#\䤮e./X29#s-ȴ|$Ѩu(aW<]}QOSCϺeI5%܉p~]f,χχχχχχχχχ˲t{e:hG_|Ivx)l}k(ugt<q(JgdY.$ OZ"ʬ8WŖȃT|_/{˃7侓9W A7aӑ7]= \N>j4ou}}A4+wU)\/yŌV|kyYW|֢2_F/Lӻy,~RCvM^ +=EutӚ%pUQ1ihB%;%2R{I;y> h&4>R3JKb2x|iuSG+Ms<j Ho  KĆ?EQXG (I19+H>,kPY8M4wZYiMkI6iK' +Z^[X=/2S,5qeE Ô(E])YRٿ:T>>>>>>>>>>|݉;o%Ibeo*֤媪:ՐN1;bvK:̪˲JzJ@||©%IS?pB!;W(mz͝k|s,cFF4_5Wj"p $Iޫ,VR>籄SǓrY*{(n))R X#(ʇN-|_Mk"%I_'K*gP}D}>#aÄ~DA_{#A~o8ɱEQ,㻼"O"r+%͝_'SiG%>3N T*ׇKK^VT4 PEQK œ OG7Q{QO!-0z鏶%ߙ'5*1zX' !||||||||||( +t;v]8zE}>@iG~;Hp+K{{n u)z} |>|>|>|>|>|>|>|>|>|>ᯊ38V+x\cii:?:gwtuu1 Kw:::r/3cV˲$I.i⠯4Z {)~̖\YI2=-רl@_ HI>ύAy, >ɉ3 %Edj(u`@cǎ)N,Kyq4MQ$|/RbZA\ +)+R>a()ttu^AXϖ\9^4ںY_R>& yIi|Ol;k.io z0>w1C( E—$iM0 +픿>>>>>>>>>ЀНo79t$I.ՆZ}a\pUv>>?xE71w}l=ǀPţ/IS+9C(iwIHE׵S*ey_̺1ڔ>UMqc_j7'NwNM^- u/Kb˯/nY/%3sw.wY8m]V,rTe<2/NswN~kO>{OxI߿-?m3q3,nGxAۤ}~}A>6w )Љ?ΈSk-]8m{E3-Aq.δ̤&q57,%\{k5s3^;uٵSfuŤ:'_W8뿑/!Yfoek{rcטPJL,%./_+uo_}#t|}xT'nb#9b#f,=3kf8Ŭ׍%O;=7č#q=,2Ʉ7G2͋g2sFe[e6;n;s$1/3xP6veȤ;Y~؎{2A&dbڽvP\zWfvX~.2SWA;V uyP~h^&VYz=m{y߱ 6 ج];f PS5'A3#G>6<粳#Y#ۄOdŨcё)a(Yr=K>x,I}Ol~M]̴8MT ~^8CwNiZQ9opTQI }>s1Ndj(u`|XW<@)ʐK4M3Kמ.f;Ş"0zee~$_(~iVKjTjY7Rf~ N^#4Ѷo}@;%*@ Ñj5+Ro;<"bPļtNIqy.d>*K_(x̎fJ/ +4g퀇>mfԆ(o |>@ ~n r/\?QF9$R2?\wN͝VN AыW/IlGӴ,_[ydv1,x{葑uװ%3sֺ=*(P`^ӮȅG hL4Mb=BM~X>O0C,Rm\w);W뼸!oO)Iҽ| _:1B쩁 ״\>܂뺠> 򃄽Tu.?r}Sk_ڻCT$JFWqN|w4c}uEקu_A"0['(_=#+ݬU|AsgTd4>[A e\YQ>|2"(kEӌbKy2?;=yh̳/42KRr`?)J }>]ta;xB 竈6 |>Pw7R p5]PCO>œ)|DepPUIId>=| +QlSyvK6*_LS͖KFg!RCOЯk;2?[Ͻ(Y#j ||~#)MeQeU&>}?vtttwwR&RR:_ 'Eeee>\pw{agT3l%i Gem}gL(9:u~n\5 +3FS*筮(tKȗA i n]񤋀`&H`\:G4e{KI(_HZ7͸(xYUyv?g.tIO{{~8Q ||~#) 0 \Yuf7&Aݟ1Nd=0sKYoII ݔvwwup^J2?[iZ{!!oޣɧ5iuɬ{)뜚|v K.P( |PCp:o0@R:뎏/,˹0VrtAdg4A>DFy={IRKI[[HG~-Σ:}C?)(=B/>4;W ||>!Pw7R Hni-pmf#7]|~ivKǮxA5wZ>TMJxZXr|U߀2?G}w,On;bK"z0߰ ||~#) 9=k97ϭ7M?҂R%et(ug4P6ykiaCUw4MhA(u#(ޢ:ڧS9YP>(k0 ZΩ/g@>(\;L` +|˲rCV( +.|giiZn:#Y (ʆgcf)ÔTއd~kY J$_] h9G".ِ3?Au|P~΀ L`AG.S"x>?=")vKǮxE@5wZH+c@P6 bV=G,ˢQBe*E4GZWw`DJ)~ +A.::/o0@R: 15$B [^\O;-7} +F/ +v˲r7(dYRe,Ȫ7^AX\^(%:`r)٨{ |/WP > +0B嚒$uݹܲ,ܶդd*0ycoc  +'TUU-#Eiw&rꎄ>-,(U㜖U/Y O)?Iwu|'ݳB>(\;LlB \=qC+8Ŏ,eHO8]}zύփgGZ +48KuWsK3ʋWm}HK6en]kZwI[KP,m6ESP{@t`J` wi˲?ED"(5ZtZo;]=[^b::@MŀJJ!).*S +G +CMb°Y0 --(8Wxs +gx.uʟR@>(\;Lx4MiUU-DQlF w*YZvxEF + T/H)ʆRof뺳(2}%廬 )i.'/#/Fo(ڹ_ߘ͝KOg=S @t`JF,UU%IRŹ>ڡp8L7xǓ)%]񤋌v?+/tww •InY RD4h.ozjFޭwo+-TZea\-|K/6ߘQxp) +@}JR8å_xw ?JlɽƍO*1|4/ |>42i*ePgTvT>~> +M}}ίl;ԏ#9D˲ѨǧCKcprNEf׍/_P赬" I +Dtް̧&ݺK+7[MM%.ie 2ߍJ|P)>ǀ2jpD1QG 9>%>+Tm<'SlɶC.n;?oرchh4,ˢ(z80˲'UQE7N +(M_ZOgğVu&b.Ϟӟ/\wInZVλX,F>"C_@r\68kO Ai4?%UNG(B&? +E^O!MW*cGΙ| + MK75;0<_nUAχ2>> 3 ɔx '7@cfQ+.IRlO(bG9'oͼ(U*#] +飺c٠)r0'pv=ZJ={^T5vʖ`;[72=l'_yS㤎=Z:HH@h(O4w*ԏAh8+zi,g[f]_eS+&󉘑.)g ##p]RedWI>2ȪwEP8_@xQU  @s8*=tT;%0@m1 CUUMJ >xSœ)2Pm,ˢGNJu_iHQ軾{x1-\+ʇEId>Aס) ݞ{Fv: #PG n1M3ZYHD4;_ieYܞ wKeH䮸iuu~ |JAd>'-!5W +ҳvKPG wh{=/a n {Nփq&Pmr58%%EQ(Ru]3h#Y$/-MM?-w +_U?ris{uqS9PG _XE\>|>sUCS;hTDa$ɲiVJltZS/2Xɩpx H +X0ZvIkbMMiQ XTA PU݀k+iD"Fnm\φ0E,NRU eY!+iIΗ$IMR +w0oKe|VB;Ιhto'^nmTV|T J*gebP ј>+tVcLvD"Q8] ~oLʢmKM>mmm%.3cVO_Trwb O\r#/:O$d̻Y[ m% Qi1KJ;9$I^ڧ hRoɒ%YֹiVUFS^)@6e|u_Kb|M9* zqQ{iys1>u%A:MՄO# {N̐'^18\]}>w?1@@; +2:r^eY/bً,즼\_Z'n/\.J6z0Ζ]ʋ {Te/㦼eS +Ee>ituA]v4t>hP.HZbƷS^̷Ñ|bmX֒ݖNO7^(#||~PAB;*jYu.q7UvI>?t -yW:1x& ~u}n>t ʨGjc|sp>_?ݤSd~pɇo:|Y|>e}*Ha%գB>ߣ5]_1OFdY.d5~HZ°u?#ԩeYQ||ROҒYWu>ܤ:(#||~PABS,ˊD"E+TC`P>P97(ӴNs>n;ԏjE >AIU$MӠK:';U:e];̗$f+'ӎ|ʇ>~%iuV#dB|T˲4M_pXQ|'8wKX,ZiTPV@)0 \Oω]eQ hq(|HK \ No newline at end of file diff --git a/vendor/snap/data/plrabn12.txt b/vendor/snap/data/plrabn12.txt new file mode 100644 index 0000000000..34088b82cd --- /dev/null +++ b/vendor/snap/data/plrabn12.txt @@ -0,0 +1,10699 @@ + +This is the February 1992 Project Gutenberg release of: + +Paradise Lost by John Milton + +The oldest etext known to Project Gutenberg (ca. 1964-1965) +(If you know of any older ones, please let us know.) + + +Introduction (one page) + +This etext was originally created in 1964-1965 according to Dr. +Joseph Raben of Queens College, NY, to whom it is attributed by +Project Gutenberg. We had heard of this etext for years but it +was not until 1991 that we actually managed to track it down to +a specific location, and then it took months to convince people +to let us have a copy, then more months for them actually to do +the copying and get it to us. Then another month to convert to +something we could massage with our favorite 486 in DOS. After +that is was only a matter of days to get it into this shape you +will see below. The original was, of course, in CAPS only, and +so were all the other etexts of the 60's and early 70's. Don't +let anyone fool you into thinking any etext with both upper and +lower case is an original; all those original Project Gutenberg +etexts were also in upper case and were translated or rewritten +many times to get them into their current condition. They have +been worked on by many people throughout the world. + +In the course of our searches for Professor Raben and his etext +we were never able to determine where copies were or which of a +variety of editions he may have used as a source. We did get a +little information here and there, but even after we received a +copy of the etext we were unwilling to release it without first +determining that it was in fact Public Domain and finding Raben +to verify this and get his permission. Interested enough, in a +totally unrelated action to our searches for him, the professor +subscribed to the Project Gutenberg listserver and we happened, +by accident, to notice his name. (We don't really look at every +subscription request as the computers usually handle them.) The +etext was then properly identified, copyright analyzed, and the +current edition prepared. + +To give you an estimation of the difference in the original and +what we have today: the original was probably entered on cards +commonly known at the time as "IBM cards" (Do Not Fold, Spindle +or Mutilate) and probably took in excess of 100,000 of them. A +single card could hold 80 characters (hence 80 characters is an +accepted standard for so many computer margins), and the entire +original edition we received in all caps was over 800,000 chars +in length, including line enumeration, symbols for caps and the +punctuation marks, etc., since they were not available keyboard +characters at the time (probably the keyboards operated at baud +rates of around 113, meaning the typists had to type slowly for +the keyboard to keep up). + +This is the second version of Paradise Lost released by Project +Gutenberg. The first was released as our October, 1991 etext. + + + + + +Paradise Lost + + + + +Book I + + +Of Man's first disobedience, and the fruit +Of that forbidden tree whose mortal taste +Brought death into the World, and all our woe, +With loss of Eden, till one greater Man +Restore us, and regain the blissful seat, +Sing, Heavenly Muse, that, on the secret top +Of Oreb, or of Sinai, didst inspire +That shepherd who first taught the chosen seed +In the beginning how the heavens and earth +Rose out of Chaos: or, if Sion hill +Delight thee more, and Siloa's brook that flowed +Fast by the oracle of God, I thence +Invoke thy aid to my adventurous song, +That with no middle flight intends to soar +Above th' Aonian mount, while it pursues +Things unattempted yet in prose or rhyme. +And chiefly thou, O Spirit, that dost prefer +Before all temples th' upright heart and pure, +Instruct me, for thou know'st; thou from the first +Wast present, and, with mighty wings outspread, +Dove-like sat'st brooding on the vast Abyss, +And mad'st it pregnant: what in me is dark +Illumine, what is low raise and support; +That, to the height of this great argument, +I may assert Eternal Providence, +And justify the ways of God to men. + Say first--for Heaven hides nothing from thy view, +Nor the deep tract of Hell--say first what cause +Moved our grand parents, in that happy state, +Favoured of Heaven so highly, to fall off +From their Creator, and transgress his will +For one restraint, lords of the World besides. +Who first seduced them to that foul revolt? + Th' infernal Serpent; he it was whose guile, +Stirred up with envy and revenge, deceived +The mother of mankind, what time his pride +Had cast him out from Heaven, with all his host +Of rebel Angels, by whose aid, aspiring +To set himself in glory above his peers, +He trusted to have equalled the Most High, +If he opposed, and with ambitious aim +Against the throne and monarchy of God, +Raised impious war in Heaven and battle proud, +With vain attempt. Him the Almighty Power +Hurled headlong flaming from th' ethereal sky, +With hideous ruin and combustion, down +To bottomless perdition, there to dwell +In adamantine chains and penal fire, +Who durst defy th' Omnipotent to arms. + Nine times the space that measures day and night +To mortal men, he, with his horrid crew, +Lay vanquished, rolling in the fiery gulf, +Confounded, though immortal. But his doom +Reserved him to more wrath; for now the thought +Both of lost happiness and lasting pain +Torments him: round he throws his baleful eyes, +That witnessed huge affliction and dismay, +Mixed with obdurate pride and steadfast hate. +At once, as far as Angels ken, he views +The dismal situation waste and wild. +A dungeon horrible, on all sides round, +As one great furnace flamed; yet from those flames +No light; but rather darkness visible +Served only to discover sights of woe, +Regions of sorrow, doleful shades, where peace +And rest can never dwell, hope never comes +That comes to all, but torture without end +Still urges, and a fiery deluge, fed +With ever-burning sulphur unconsumed. +Such place Eternal Justice has prepared +For those rebellious; here their prison ordained +In utter darkness, and their portion set, +As far removed from God and light of Heaven +As from the centre thrice to th' utmost pole. +Oh how unlike the place from whence they fell! +There the companions of his fall, o'erwhelmed +With floods and whirlwinds of tempestuous fire, +He soon discerns; and, weltering by his side, +One next himself in power, and next in crime, +Long after known in Palestine, and named +Beelzebub. To whom th' Arch-Enemy, +And thence in Heaven called Satan, with bold words +Breaking the horrid silence, thus began:-- + "If thou beest he--but O how fallen! how changed +From him who, in the happy realms of light +Clothed with transcendent brightness, didst outshine +Myriads, though bright!--if he whom mutual league, +United thoughts and counsels, equal hope +And hazard in the glorious enterprise +Joined with me once, now misery hath joined +In equal ruin; into what pit thou seest +From what height fallen: so much the stronger proved +He with his thunder; and till then who knew +The force of those dire arms? Yet not for those, +Nor what the potent Victor in his rage +Can else inflict, do I repent, or change, +Though changed in outward lustre, that fixed mind, +And high disdain from sense of injured merit, +That with the Mightiest raised me to contend, +And to the fierce contentions brought along +Innumerable force of Spirits armed, +That durst dislike his reign, and, me preferring, +His utmost power with adverse power opposed +In dubious battle on the plains of Heaven, +And shook his throne. What though the field be lost? +All is not lost--the unconquerable will, +And study of revenge, immortal hate, +And courage never to submit or yield: +And what is else not to be overcome? +That glory never shall his wrath or might +Extort from me. To bow and sue for grace +With suppliant knee, and deify his power +Who, from the terror of this arm, so late +Doubted his empire--that were low indeed; +That were an ignominy and shame beneath +This downfall; since, by fate, the strength of Gods, +And this empyreal sybstance, cannot fail; +Since, through experience of this great event, +In arms not worse, in foresight much advanced, +We may with more successful hope resolve +To wage by force or guile eternal war, +Irreconcilable to our grand Foe, +Who now triumphs, and in th' excess of joy +Sole reigning holds the tyranny of Heaven." + So spake th' apostate Angel, though in pain, +Vaunting aloud, but racked with deep despair; +And him thus answered soon his bold compeer:-- + "O Prince, O Chief of many throned Powers +That led th' embattled Seraphim to war +Under thy conduct, and, in dreadful deeds +Fearless, endangered Heaven's perpetual King, +And put to proof his high supremacy, +Whether upheld by strength, or chance, or fate, +Too well I see and rue the dire event +That, with sad overthrow and foul defeat, +Hath lost us Heaven, and all this mighty host +In horrible destruction laid thus low, +As far as Gods and heavenly Essences +Can perish: for the mind and spirit remains +Invincible, and vigour soon returns, +Though all our glory extinct, and happy state +Here swallowed up in endless misery. +But what if he our Conqueror (whom I now +Of force believe almighty, since no less +Than such could have o'erpowered such force as ours) +Have left us this our spirit and strength entire, +Strongly to suffer and support our pains, +That we may so suffice his vengeful ire, +Or do him mightier service as his thralls +By right of war, whate'er his business be, +Here in the heart of Hell to work in fire, +Or do his errands in the gloomy Deep? +What can it the avail though yet we feel +Strength undiminished, or eternal being +To undergo eternal punishment?" + Whereto with speedy words th' Arch-Fiend replied:-- +"Fallen Cherub, to be weak is miserable, +Doing or suffering: but of this be sure-- +To do aught good never will be our task, +But ever to do ill our sole delight, +As being the contrary to his high will +Whom we resist. If then his providence +Out of our evil seek to bring forth good, +Our labour must be to pervert that end, +And out of good still to find means of evil; +Which ofttimes may succeed so as perhaps +Shall grieve him, if I fail not, and disturb +His inmost counsels from their destined aim. +But see! the angry Victor hath recalled +His ministers of vengeance and pursuit +Back to the gates of Heaven: the sulphurous hail, +Shot after us in storm, o'erblown hath laid +The fiery surge that from the precipice +Of Heaven received us falling; and the thunder, +Winged with red lightning and impetuous rage, +Perhaps hath spent his shafts, and ceases now +To bellow through the vast and boundless Deep. +Let us not slip th' occasion, whether scorn +Or satiate fury yield it from our Foe. +Seest thou yon dreary plain, forlorn and wild, +The seat of desolation, void of light, +Save what the glimmering of these livid flames +Casts pale and dreadful? Thither let us tend +From off the tossing of these fiery waves; +There rest, if any rest can harbour there; +And, re-assembling our afflicted powers, +Consult how we may henceforth most offend +Our enemy, our own loss how repair, +How overcome this dire calamity, +What reinforcement we may gain from hope, +If not, what resolution from despair." + Thus Satan, talking to his nearest mate, +With head uplift above the wave, and eyes +That sparkling blazed; his other parts besides +Prone on the flood, extended long and large, +Lay floating many a rood, in bulk as huge +As whom the fables name of monstrous size, +Titanian or Earth-born, that warred on Jove, +Briareos or Typhon, whom the den +By ancient Tarsus held, or that sea-beast +Leviathan, which God of all his works +Created hugest that swim th' ocean-stream. +Him, haply slumbering on the Norway foam, +The pilot of some small night-foundered skiff, +Deeming some island, oft, as seamen tell, +With fixed anchor in his scaly rind, +Moors by his side under the lee, while night +Invests the sea, and wished morn delays. +So stretched out huge in length the Arch-fiend lay, +Chained on the burning lake; nor ever thence +Had risen, or heaved his head, but that the will +And high permission of all-ruling Heaven +Left him at large to his own dark designs, +That with reiterated crimes he might +Heap on himself damnation, while he sought +Evil to others, and enraged might see +How all his malice served but to bring forth +Infinite goodness, grace, and mercy, shewn +On Man by him seduced, but on himself +Treble confusion, wrath, and vengeance poured. + Forthwith upright he rears from off the pool +His mighty stature; on each hand the flames +Driven backward slope their pointing spires, and,rolled +In billows, leave i' th' midst a horrid vale. +Then with expanded wings he steers his flight +Aloft, incumbent on the dusky air, +That felt unusual weight; till on dry land +He lights--if it were land that ever burned +With solid, as the lake with liquid fire, +And such appeared in hue as when the force +Of subterranean wind transprots a hill +Torn from Pelorus, or the shattered side +Of thundering Etna, whose combustible +And fuelled entrails, thence conceiving fire, +Sublimed with mineral fury, aid the winds, +And leave a singed bottom all involved +With stench and smoke. Such resting found the sole +Of unblest feet. Him followed his next mate; +Both glorying to have scaped the Stygian flood +As gods, and by their own recovered strength, +Not by the sufferance of supernal Power. + "Is this the region, this the soil, the clime," +Said then the lost Archangel, "this the seat +That we must change for Heaven?--this mournful gloom +For that celestial light? Be it so, since he +Who now is sovereign can dispose and bid +What shall be right: farthest from him is best +Whom reason hath equalled, force hath made supreme +Above his equals. Farewell, happy fields, +Where joy for ever dwells! Hail, horrors! hail, +Infernal world! and thou, profoundest Hell, +Receive thy new possessor--one who brings +A mind not to be changed by place or time. +The mind is its own place, and in itself +Can make a Heaven of Hell, a Hell of Heaven. +What matter where, if I be still the same, +And what I should be, all but less than he +Whom thunder hath made greater? Here at least +We shall be free; th' Almighty hath not built +Here for his envy, will not drive us hence: +Here we may reigh secure; and, in my choice, +To reign is worth ambition, though in Hell: +Better to reign in Hell than serve in Heaven. +But wherefore let we then our faithful friends, +Th' associates and co-partners of our loss, +Lie thus astonished on th' oblivious pool, +And call them not to share with us their part +In this unhappy mansion, or once more +With rallied arms to try what may be yet +Regained in Heaven, or what more lost in Hell?" + So Satan spake; and him Beelzebub +Thus answered:--"Leader of those armies bright +Which, but th' Omnipotent, none could have foiled! +If once they hear that voice, their liveliest pledge +Of hope in fears and dangers--heard so oft +In worst extremes, and on the perilous edge +Of battle, when it raged, in all assaults +Their surest signal--they will soon resume +New courage and revive, though now they lie +Grovelling and prostrate on yon lake of fire, +As we erewhile, astounded and amazed; +No wonder, fallen such a pernicious height!" + He scare had ceased when the superior Fiend +Was moving toward the shore; his ponderous shield, +Ethereal temper, massy, large, and round, +Behind him cast. The broad circumference +Hung on his shoulders like the moon, whose orb +Through optic glass the Tuscan artist views +At evening, from the top of Fesole, +Or in Valdarno, to descry new lands, +Rivers, or mountains, in her spotty globe. +His spear--to equal which the tallest pine +Hewn on Norwegian hills, to be the mast +Of some great ammiral, were but a wand-- +He walked with, to support uneasy steps +Over the burning marl, not like those steps +On Heaven's azure; and the torrid clime +Smote on him sore besides, vaulted with fire. +Nathless he so endured, till on the beach +Of that inflamed sea he stood, and called +His legions--Angel Forms, who lay entranced +Thick as autumnal leaves that strow the brooks +In Vallombrosa, where th' Etrurian shades +High over-arched embower; or scattered sedge +Afloat, when with fierce winds Orion armed +Hath vexed the Red-Sea coast, whose waves o'erthrew +Busiris and his Memphian chivalry, +While with perfidious hatred they pursued +The sojourners of Goshen, who beheld +From the safe shore their floating carcases +And broken chariot-wheels. So thick bestrown, +Abject and lost, lay these, covering the flood, +Under amazement of their hideous change. +He called so loud that all the hollow deep +Of Hell resounded:--"Princes, Potentates, +Warriors, the Flower of Heaven--once yours; now lost, +If such astonishment as this can seize +Eternal Spirits! Or have ye chosen this place +After the toil of battle to repose +Your wearied virtue, for the ease you find +To slumber here, as in the vales of Heaven? +Or in this abject posture have ye sworn +To adore the Conqueror, who now beholds +Cherub and Seraph rolling in the flood +With scattered arms and ensigns, till anon +His swift pursuers from Heaven-gates discern +Th' advantage, and, descending, tread us down +Thus drooping, or with linked thunderbolts +Transfix us to the bottom of this gulf? +Awake, arise, or be for ever fallen!" + They heard, and were abashed, and up they sprung +Upon the wing, as when men wont to watch +On duty, sleeping found by whom they dread, +Rouse and bestir themselves ere well awake. +Nor did they not perceive the evil plight +In which they were, or the fierce pains not feel; +Yet to their General's voice they soon obeyed +Innumerable. As when the potent rod +Of Amram's son, in Egypt's evil day, +Waved round the coast, up-called a pitchy cloud +Of locusts, warping on the eastern wind, +That o'er the realm of impious Pharaoh hung +Like Night, and darkened all the land of Nile; +So numberless were those bad Angels seen +Hovering on wing under the cope of Hell, +'Twixt upper, nether, and surrounding fires; +Till, as a signal given, th' uplifted spear +Of their great Sultan waving to direct +Their course, in even balance down they light +On the firm brimstone, and fill all the plain: +A multitude like which the populous North +Poured never from her frozen loins to pass +Rhene or the Danaw, when her barbarous sons +Came like a deluge on the South, and spread +Beneath Gibraltar to the Libyan sands. +Forthwith, form every squadron and each band, +The heads and leaders thither haste where stood +Their great Commander--godlike Shapes, and Forms +Excelling human; princely Dignities; +And Powers that erst in Heaven sat on thrones, +Though on their names in Heavenly records now +Be no memorial, blotted out and rased +By their rebellion from the Books of Life. +Nor had they yet among the sons of Eve +Got them new names, till, wandering o'er the earth, +Through God's high sufferance for the trial of man, +By falsities and lies the greatest part +Of mankind they corrupted to forsake +God their Creator, and th' invisible +Glory of him that made them to transform +Oft to the image of a brute, adorned +With gay religions full of pomp and gold, +And devils to adore for deities: +Then were they known to men by various names, +And various idols through the heathen world. + Say, Muse, their names then known, who first, who last, +Roused from the slumber on that fiery couch, +At their great Emperor's call, as next in worth +Came singly where he stood on the bare strand, +While the promiscuous crowd stood yet aloof? + The chief were those who, from the pit of Hell +Roaming to seek their prey on Earth, durst fix +Their seats, long after, next the seat of God, +Their altars by his altar, gods adored +Among the nations round, and durst abide +Jehovah thundering out of Sion, throned +Between the Cherubim; yea, often placed +Within his sanctuary itself their shrines, +Abominations; and with cursed things +His holy rites and solemn feasts profaned, +And with their darkness durst affront his light. +First, Moloch, horrid king, besmeared with blood +Of human sacrifice, and parents' tears; +Though, for the noise of drums and timbrels loud, +Their children's cries unheard that passed through fire +To his grim idol. Him the Ammonite +Worshiped in Rabba and her watery plain, +In Argob and in Basan, to the stream +Of utmost Arnon. Nor content with such +Audacious neighbourhood, the wisest heart +Of Solomon he led by fraoud to build +His temple right against the temple of God +On that opprobrious hill, and made his grove +The pleasant valley of Hinnom, Tophet thence +And black Gehenna called, the type of Hell. +Next Chemos, th' obscene dread of Moab's sons, +From Aroar to Nebo and the wild +Of southmost Abarim; in Hesebon +And Horonaim, Seon's real, beyond +The flowery dale of Sibma clad with vines, +And Eleale to th' Asphaltic Pool: +Peor his other name, when he enticed +Israel in Sittim, on their march from Nile, +To do him wanton rites, which cost them woe. +Yet thence his lustful orgies he enlarged +Even to that hill of scandal, by the grove +Of Moloch homicide, lust hard by hate, +Till good Josiah drove them thence to Hell. +With these came they who, from the bordering flood +Of old Euphrates to the brook that parts +Egypt from Syrian ground, had general names +Of Baalim and Ashtaroth--those male, +These feminine. For Spirits, when they please, +Can either sex assume, or both; so soft +And uncompounded is their essence pure, +Not tried or manacled with joint or limb, +Nor founded on the brittle strength of bones, +Like cumbrous flesh; but, in what shape they choose, +Dilated or condensed, bright or obscure, +Can execute their airy purposes, +And works of love or enmity fulfil. +For those the race of Israel oft forsook +Their Living Strength, and unfrequented left +His righteous altar, bowing lowly down +To bestial gods; for which their heads as low +Bowed down in battle, sunk before the spear +Of despicable foes. With these in troop +Came Astoreth, whom the Phoenicians called +Astarte, queen of heaven, with crescent horns; +To whose bright image nigntly by the moon +Sidonian virgins paid their vows and songs; +In Sion also not unsung, where stood +Her temple on th' offensive mountain, built +By that uxorious king whose heart, though large, +Beguiled by fair idolatresses, fell +To idols foul. Thammuz came next behind, +Whose annual wound in Lebanon allured +The Syrian damsels to lament his fate +In amorous ditties all a summer's day, +While smooth Adonis from his native rock +Ran purple to the sea, supposed with blood +Of Thammuz yearly wounded: the love-tale +Infected Sion's daughters with like heat, +Whose wanton passions in the sacred proch +Ezekiel saw, when, by the vision led, +His eye surveyed the dark idolatries +Of alienated Judah. Next came one +Who mourned in earnest, when the captive ark +Maimed his brute image, head and hands lopt off, +In his own temple, on the grunsel-edge, +Where he fell flat and shamed his worshippers: +Dagon his name, sea-monster,upward man +And downward fish; yet had his temple high +Reared in Azotus, dreaded through the coast +Of Palestine, in Gath and Ascalon, +And Accaron and Gaza's frontier bounds. +Him followed Rimmon, whose delightful seat +Was fair Damascus, on the fertile banks +Of Abbana and Pharphar, lucid streams. +He also against the house of God was bold: +A leper once he lost, and gained a king-- +Ahaz, his sottish conqueror, whom he drew +God's altar to disparage and displace +For one of Syrian mode, whereon to burn +His odious offerings, and adore the gods +Whom he had vanquished. After these appeared +A crew who, under names of old renown-- +Osiris, Isis, Orus, and their train-- +With monstrous shapes and sorceries abused +Fanatic Egypt and her priests to seek +Their wandering gods disguised in brutish forms +Rather than human. Nor did Israel scape +Th' infection, when their borrowed gold composed +The calf in Oreb; and the rebel king +Doubled that sin in Bethel and in Dan, +Likening his Maker to the grazed ox-- +Jehovah, who, in one night, when he passed +From Egypt marching, equalled with one stroke +Both her first-born and all her bleating gods. +Belial came last; than whom a Spirit more lewd +Fell not from Heaven, or more gross to love +Vice for itself. To him no temple stood +Or altar smoked; yet who more oft than he +In temples and at altars, when the priest +Turns atheist, as did Eli's sons, who filled +With lust and violence the house of God? +In courts and palaces he also reigns, +And in luxurious cities, where the noise +Of riot ascends above their loftiest towers, +And injury and outrage; and, when night +Darkens the streets, then wander forth the sons +Of Belial, flown with insolence and wine. +Witness the streets of Sodom, and that night +In Gibeah, when the hospitable door +Exposed a matron, to avoid worse rape. + These were the prime in order and in might: +The rest were long to tell; though far renowned +Th' Ionian gods--of Javan's issue held +Gods, yet confessed later than Heaven and Earth, +Their boasted parents;--Titan, Heaven's first-born, +With his enormous brood, and birthright seized +By younger Saturn: he from mightier Jove, +His own and Rhea's son, like measure found; +So Jove usurping reigned. These, first in Crete +And Ida known, thence on the snowy top +Of cold Olympus ruled the middle air, +Their highest heaven; or on the Delphian cliff, +Or in Dodona, and through all the bounds +Of Doric land; or who with Saturn old +Fled over Adria to th' Hesperian fields, +And o'er the Celtic roamed the utmost Isles. + All these and more came flocking; but with looks +Downcast and damp; yet such wherein appeared +Obscure some glimpse of joy to have found their Chief +Not in despair, to have found themselves not lost +In loss itself; which on his countenance cast +Like doubtful hue. But he, his wonted pride +Soon recollecting, with high words, that bore +Semblance of worth, not substance, gently raised +Their fainting courage, and dispelled their fears. +Then straight commands that, at the warlike sound +Of trumpets loud and clarions, be upreared +His mighty standard. That proud honour claimed +Azazel as his right, a Cherub tall: +Who forthwith from the glittering staff unfurled +Th' imperial ensign; which, full high advanced, +Shone like a meteor streaming to the wind, +With gems and golden lustre rich emblazed, +Seraphic arms and trophies; all the while +Sonorous metal blowing martial sounds: +At which the universal host up-sent +A shout that tore Hell's concave, and beyond +Frighted the reign of Chaos and old Night. +All in a moment through the gloom were seen +Ten thousand banners rise into the air, +With orient colours waving: with them rose +A forest huge of spears; and thronging helms +Appeared, and serried shields in thick array +Of depth immeasurable. Anon they move +In perfect phalanx to the Dorian mood +Of flutes and soft recorders--such as raised +To height of noblest temper heroes old +Arming to battle, and instead of rage +Deliberate valour breathed, firm, and unmoved +With dread of death to flight or foul retreat; +Nor wanting power to mitigate and swage +With solemn touches troubled thoughts, and chase +Anguish and doubt and fear and sorrow and pain +From mortal or immortal minds. Thus they, +Breathing united force with fixed thought, +Moved on in silence to soft pipes that charmed +Their painful steps o'er the burnt soil. And now +Advanced in view they stand--a horrid front +Of dreadful length and dazzling arms, in guise +Of warriors old, with ordered spear and shield, +Awaiting what command their mighty Chief +Had to impose. He through the armed files +Darts his experienced eye, and soon traverse +The whole battalion views--their order due, +Their visages and stature as of gods; +Their number last he sums. And now his heart +Distends with pride, and, hardening in his strength, +Glories: for never, since created Man, +Met such embodied force as, named with these, +Could merit more than that small infantry +Warred on by cranes--though all the giant brood +Of Phlegra with th' heroic race were joined +That fought at Thebes and Ilium, on each side +Mixed with auxiliar gods; and what resounds +In fable or romance of Uther's son, +Begirt with British and Armoric knights; +And all who since, baptized or infidel, +Jousted in Aspramont, or Montalban, +Damasco, or Marocco, or Trebisond, +Or whom Biserta sent from Afric shore +When Charlemain with all his peerage fell +By Fontarabbia. Thus far these beyond +Compare of mortal prowess, yet observed +Their dread Commander. He, above the rest +In shape and gesture proudly eminent, +Stood like a tower. His form had yet not lost +All her original brightness, nor appeared +Less than Archangel ruined, and th' excess +Of glory obscured: as when the sun new-risen +Looks through the horizontal misty air +Shorn of his beams, or, from behind the moon, +In dim eclipse, disastrous twilight sheds +On half the nations, and with fear of change +Perplexes monarchs. Darkened so, yet shone +Above them all th' Archangel: but his face +Deep scars of thunder had intrenched, and care +Sat on his faded cheek, but under brows +Of dauntless courage, and considerate pride +Waiting revenge. Cruel his eye, but cast +Signs of remorse and passion, to behold +The fellows of his crime, the followers rather +(Far other once beheld in bliss), condemned +For ever now to have their lot in pain-- +Millions of Spirits for his fault amerced +Of Heaven, and from eteranl splendours flung +For his revolt--yet faithful how they stood, +Their glory withered; as, when heaven's fire +Hath scathed the forest oaks or mountain pines, +With singed top their stately growth, though bare, +Stands on the blasted heath. He now prepared +To speak; whereat their doubled ranks they bend +From wing to wing, and half enclose him round +With all his peers: attention held them mute. +Thrice he assayed, and thrice, in spite of scorn, +Tears, such as Angels weep, burst forth: at last +Words interwove with sighs found out their way:-- + "O myriads of immortal Spirits! O Powers +Matchless, but with th' Almighth!--and that strife +Was not inglorious, though th' event was dire, +As this place testifies, and this dire change, +Hateful to utter. But what power of mind, +Forseeing or presaging, from the depth +Of knowledge past or present, could have feared +How such united force of gods, how such +As stood like these, could ever know repulse? +For who can yet believe, though after loss, +That all these puissant legions, whose exile +Hath emptied Heaven, shall fail to re-ascend, +Self-raised, and repossess their native seat? +For me, be witness all the host of Heaven, +If counsels different, or danger shunned +By me, have lost our hopes. But he who reigns +Monarch in Heaven till then as one secure +Sat on his throne, upheld by old repute, +Consent or custom, and his regal state +Put forth at full, but still his strength concealed-- +Which tempted our attempt, and wrought our fall. +Henceforth his might we know, and know our own, +So as not either to provoke, or dread +New war provoked: our better part remains +To work in close design, by fraud or guile, +What force effected not; that he no less +At length from us may find, who overcomes +By force hath overcome but half his foe. +Space may produce new Worlds; whereof so rife +There went a fame in Heaven that he ere long +Intended to create, and therein plant +A generation whom his choice regard +Should favour equal to the Sons of Heaven. +Thither, if but to pry, shall be perhaps +Our first eruption--thither, or elsewhere; +For this infernal pit shall never hold +Celestial Spirits in bondage, nor th' Abyss +Long under darkness cover. But these thoughts +Full counsel must mature. Peace is despaired; +For who can think submission? War, then, war +Open or understood, must be resolved." + He spake; and, to confirm his words, outflew +Millions of flaming swords, drawn from the thighs +Of mighty Cherubim; the sudden blaze +Far round illumined Hell. Highly they raged +Against the Highest, and fierce with grasped arms +Clashed on their sounding shields the din of war, +Hurling defiance toward the vault of Heaven. + There stood a hill not far, whose grisly top +Belched fire and rolling smoke; the rest entire +Shone with a glossy scurf--undoubted sign +That in his womb was hid metallic ore, +The work of sulphur. Thither, winged with speed, +A numerous brigade hastened: as when bands +Of pioneers, with spade and pickaxe armed, +Forerun the royal camp, to trench a field, +Or cast a rampart. Mammon led them on-- +Mammon, the least erected Spirit that fell +From Heaven; for even in Heaven his looks and thoughts +Were always downward bent, admiring more +The riches of heaven's pavement, trodden gold, +Than aught divine or holy else enjoyed +In vision beatific. By him first +Men also, and by his suggestion taught, +Ransacked the centre, and with impious hands +Rifled the bowels of their mother Earth +For treasures better hid. Soon had his crew +Opened into the hill a spacious wound, +And digged out ribs of gold. Let none admire +That riches grow in Hell; that soil may best +Deserve the precious bane. And here let those +Who boast in mortal things, and wondering tell +Of Babel, and the works of Memphian kings, +Learn how their greatest monuments of fame +And strength, and art, are easily outdone +By Spirits reprobate, and in an hour +What in an age they, with incessant toil +And hands innumerable, scarce perform. +Nigh on the plain, in many cells prepared, +That underneath had veins of liquid fire +Sluiced from the lake, a second multitude +With wondrous art founded the massy ore, +Severing each kind, and scummed the bullion-dross. +A third as soon had formed within the ground +A various mould, and from the boiling cells +By strange conveyance filled each hollow nook; +As in an organ, from one blast of wind, +To many a row of pipes the sound-board breathes. +Anon out of the earth a fabric huge +Rose like an exhalation, with the sound +Of dulcet symphonies and voices sweet-- +Built like a temple, where pilasters round +Were set, and Doric pillars overlaid +With golden architrave; nor did there want +Cornice or frieze, with bossy sculptures graven; +The roof was fretted gold. Not Babylon +Nor great Alcairo such magnificence +Equalled in all their glories, to enshrine +Belus or Serapis their gods, or seat +Their kings, when Egypt with Assyria strove +In wealth and luxury. Th' ascending pile +Stood fixed her stately height, and straight the doors, +Opening their brazen folds, discover, wide +Within, her ample spaces o'er the smooth +And level pavement: from the arched roof, +Pendent by subtle magic, many a row +Of starry lamps and blazing cressets, fed +With naptha and asphaltus, yielded light +As from a sky. The hasty multitude +Admiring entered; and the work some praise, +And some the architect. His hand was known +In Heaven by many a towered structure high, +Where sceptred Angels held their residence, +And sat as Princes, whom the supreme King +Exalted to such power, and gave to rule, +Each in his Hierarchy, the Orders bright. +Nor was his name unheard or unadored +In ancient Greece; and in Ausonian land +Men called him Mulciber; and how he fell +From Heaven they fabled, thrown by angry Jove +Sheer o'er the crystal battlements: from morn +To noon he fell, from noon to dewy eve, +A summer's day, and with the setting sun +Dropt from the zenith, like a falling star, +On Lemnos, th' Aegaean isle. Thus they relate, +Erring; for he with this rebellious rout +Fell long before; nor aught aviled him now +To have built in Heaven high towers; nor did he scape +By all his engines, but was headlong sent, +With his industrious crew, to build in Hell. + Meanwhile the winged Heralds, by command +Of sovereign power, with awful ceremony +And trumpet's sound, throughout the host proclaim +A solemn council forthwith to be held +At Pandemonium, the high capital +Of Satan and his peers. Their summons called +From every band and squared regiment +By place or choice the worthiest: they anon +With hundreds and with thousands trooping came +Attended. All access was thronged; the gates +And porches wide, but chief the spacious hall +(Though like a covered field, where champions bold +Wont ride in armed, and at the Soldan's chair +Defied the best of Paynim chivalry +To mortal combat, or career with lance), +Thick swarmed, both on the ground and in the air, +Brushed with the hiss of rustling wings. As bees +In spring-time, when the Sun with Taurus rides. +Pour forth their populous youth about the hive +In clusters; they among fresh dews and flowers +Fly to and fro, or on the smoothed plank, +The suburb of their straw-built citadel, +New rubbed with balm, expatiate, and confer +Their state-affairs: so thick the airy crowd +Swarmed and were straitened; till, the signal given, +Behold a wonder! They but now who seemed +In bigness to surpass Earth's giant sons, +Now less than smallest dwarfs, in narrow room +Throng numberless--like that pygmean race +Beyond the Indian mount; or faery elves, +Whose midnight revels, by a forest-side +Or fountain, some belated peasant sees, +Or dreams he sees, while overhead the Moon +Sits arbitress, and nearer to the Earth +Wheels her pale course: they, on their mirth and dance +Intent, with jocund music charm his ear; +At once with joy and fear his heart rebounds. +Thus incorporeal Spirits to smallest forms +Reduced their shapes immense, and were at large, +Though without number still, amidst the hall +Of that infernal court. But far within, +And in their own dimensions like themselves, +The great Seraphic Lords and Cherubim +In close recess and secret conclave sat, +A thousand demi-gods on golden seats, +Frequent and full. After short silence then, +And summons read, the great consult began. + + + +Book II + + +High on a throne of royal state, which far +Outshone the wealth or Ormus and of Ind, +Or where the gorgeous East with richest hand +Showers on her kings barbaric pearl and gold, +Satan exalted sat, by merit raised +To that bad eminence; and, from despair +Thus high uplifted beyond hope, aspires +Beyond thus high, insatiate to pursue +Vain war with Heaven; and, by success untaught, +His proud imaginations thus displayed:-- + "Powers and Dominions, Deities of Heaven!-- +For, since no deep within her gulf can hold +Immortal vigour, though oppressed and fallen, +I give not Heaven for lost: from this descent +Celestial Virtues rising will appear +More glorious and more dread than from no fall, +And trust themselves to fear no second fate!-- +Me though just right, and the fixed laws of Heaven, +Did first create your leader--next, free choice +With what besides in council or in fight +Hath been achieved of merit--yet this loss, +Thus far at least recovered, hath much more +Established in a safe, unenvied throne, +Yielded with full consent. The happier state +In Heaven, which follows dignity, might draw +Envy from each inferior; but who here +Will envy whom the highest place exposes +Foremost to stand against the Thunderer's aim +Your bulwark, and condemns to greatest share +Of endless pain? Where there is, then, no good +For which to strive, no strife can grow up there +From faction: for none sure will claim in Hell +Precedence; none whose portion is so small +Of present pain that with ambitious mind +Will covet more! With this advantage, then, +To union, and firm faith, and firm accord, +More than can be in Heaven, we now return +To claim our just inheritance of old, +Surer to prosper than prosperity +Could have assured us; and by what best way, +Whether of open war or covert guile, +We now debate. Who can advise may speak." + He ceased; and next him Moloch, sceptred king, +Stood up--the strongest and the fiercest Spirit +That fought in Heaven, now fiercer by despair. +His trust was with th' Eternal to be deemed +Equal in strength, and rather than be less +Cared not to be at all; with that care lost +Went all his fear: of God, or Hell, or worse, +He recked not, and these words thereafter spake:-- + "My sentence is for open war. Of wiles, +More unexpert, I boast not: them let those +Contrive who need, or when they need; not now. +For, while they sit contriving, shall the rest-- +Millions that stand in arms, and longing wait +The signal to ascend--sit lingering here, +Heaven's fugitives, and for their dwelling-place +Accept this dark opprobrious den of shame, +The prison of his ryranny who reigns +By our delay? No! let us rather choose, +Armed with Hell-flames and fury, all at once +O'er Heaven's high towers to force resistless way, +Turning our tortures into horrid arms +Against the Torturer; when, to meet the noise +Of his almighty engine, he shall hear +Infernal thunder, and, for lightning, see +Black fire and horror shot with equal rage +Among his Angels, and his throne itself +Mixed with Tartarean sulphur and strange fire, +His own invented torments. But perhaps +The way seems difficult, and steep to scale +With upright wing against a higher foe! +Let such bethink them, if the sleepy drench +Of that forgetful lake benumb not still, +That in our porper motion we ascend +Up to our native seat; descent and fall +To us is adverse. Who but felt of late, +When the fierce foe hung on our broken rear +Insulting, and pursued us through the Deep, +With what compulsion and laborious flight +We sunk thus low? Th' ascent is easy, then; +Th' event is feared! Should we again provoke +Our stronger, some worse way his wrath may find +To our destruction, if there be in Hell +Fear to be worse destroyed! What can be worse +Than to dwell here, driven out from bliss, condemned +In this abhorred deep to utter woe! +Where pain of unextinguishable fire +Must exercise us without hope of end +The vassals of his anger, when the scourge +Inexorably, and the torturing hour, +Calls us to penance? More destroyed than thus, +We should be quite abolished, and expire. +What fear we then? what doubt we to incense +His utmost ire? which, to the height enraged, +Will either quite consume us, and reduce +To nothing this essential--happier far +Than miserable to have eternal being!-- +Or, if our substance be indeed divine, +And cannot cease to be, we are at worst +On this side nothing; and by proof we feel +Our power sufficient to disturb his Heaven, +And with perpetual inroads to alarm, +Though inaccessible, his fatal throne: +Which, if not victory, is yet revenge." + He ended frowning, and his look denounced +Desperate revenge, and battle dangerous +To less than gods. On th' other side up rose +Belial, in act more graceful and humane. +A fairer person lost not Heaven; he seemed +For dignity composed, and high exploit. +But all was false and hollow; though his tongue +Dropped manna, and could make the worse appear +The better reason, to perplex and dash +Maturest counsels: for his thoughts were low-- + To vice industrious, but to nobler deeds +Timorous and slothful. Yet he pleased the ear, +And with persuasive accent thus began:-- + "I should be much for open war, O Peers, +As not behind in hate, if what was urged +Main reason to persuade immediate war +Did not dissuade me most, and seem to cast +Ominous conjecture on the whole success; +When he who most excels in fact of arms, +In what he counsels and in what excels +Mistrustful, grounds his courage on despair +And utter dissolution, as the scope +Of all his aim, after some dire revenge. +First, what revenge? The towers of Heaven are filled +With armed watch, that render all access +Impregnable: oft on the bodering Deep +Encamp their legions, or with obscure wing +Scout far and wide into the realm of Night, +Scorning surprise. Or, could we break our way +By force, and at our heels all Hell should rise +With blackest insurrection to confound +Heaven's purest light, yet our great Enemy, +All incorruptible, would on his throne +Sit unpolluted, and th' ethereal mould, +Incapable of stain, would soon expel +Her mischief, and purge off the baser fire, +Victorious. Thus repulsed, our final hope +Is flat despair: we must exasperate +Th' Almighty Victor to spend all his rage; +And that must end us; that must be our cure-- +To be no more. Sad cure! for who would lose, +Though full of pain, this intellectual being, +Those thoughts that wander through eternity, +To perish rather, swallowed up and lost +In the wide womb of uncreated Night, +Devoid of sense and motion? And who knows, +Let this be good, whether our angry Foe +Can give it, or will ever? How he can +Is doubtful; that he never will is sure. +Will he, so wise, let loose at once his ire, +Belike through impotence or unaware, +To give his enemies their wish, and end +Them in his anger whom his anger saves +To punish endless? 'Wherefore cease we, then?' +Say they who counsel war; 'we are decreed, +Reserved, and destined to eternal woe; +Whatever doing, what can we suffer more, +What can we suffer worse?' Is this, then, worst-- +Thus sitting, thus consulting, thus in arms? +What when we fled amain, pursued and struck +With Heaven's afflicting thunder, and besought +The Deep to shelter us? This Hell then seemed +A refuge from those wounds. Or when we lay +Chained on the burning lake? That sure was worse. +What if the breath that kindled those grim fires, +Awaked, should blow them into sevenfold rage, +And plunge us in the flames; or from above +Should intermitted vengeance arm again +His red right hand to plague us? What if all +Her stores were opened, and this firmament +Of Hell should spout her cataracts of fire, +Impendent horrors, threatening hideous fall +One day upon our heads; while we perhaps, +Designing or exhorting glorious war, +Caught in a fiery tempest, shall be hurled, +Each on his rock transfixed, the sport and prey +Or racking whirlwinds, or for ever sunk +Under yon boiling ocean, wrapt in chains, +There to converse with everlasting groans, +Unrespited, unpitied, unreprieved, +Ages of hopeless end? This would be worse. +War, therefore, open or concealed, alike +My voice dissuades; for what can force or guile +With him, or who deceive his mind, whose eye +Views all things at one view? He from Heaven's height +All these our motions vain sees and derides, +Not more almighty to resist our might +Than wise to frustrate all our plots and wiles. +Shall we, then, live thus vile--the race of Heaven +Thus trampled, thus expelled, to suffer here +Chains and these torments? Better these than worse, +By my advice; since fate inevitable +Subdues us, and omnipotent decree, +The Victor's will. To suffer, as to do, +Our strength is equal; nor the law unjust +That so ordains. This was at first resolved, +If we were wise, against so great a foe +Contending, and so doubtful what might fall. +I laugh when those who at the spear are bold +And venturous, if that fail them, shrink, and fear +What yet they know must follow--to endure +Exile, or igominy, or bonds, or pain, +The sentence of their Conqueror. This is now +Our doom; which if we can sustain and bear, +Our Supreme Foe in time may much remit +His anger, and perhaps, thus far removed, +Not mind us not offending, satisfied +With what is punished; whence these raging fires +Will slacken, if his breath stir not their flames. +Our purer essence then will overcome +Their noxious vapour; or, inured, not feel; +Or, changed at length, and to the place conformed +In temper and in nature, will receive +Familiar the fierce heat; and, void of pain, +This horror will grow mild, this darkness light; +Besides what hope the never-ending flight +Of future days may bring, what chance, what change +Worth waiting--since our present lot appears +For happy though but ill, for ill not worst, +If we procure not to ourselves more woe." + Thus Belial, with words clothed in reason's garb, +Counselled ignoble ease and peaceful sloth, +Not peace; and after him thus Mammon spake:-- + "Either to disenthrone the King of Heaven +We war, if war be best, or to regain +Our own right lost. Him to unthrone we then +May hope, when everlasting Fate shall yield +To fickle Chance, and Chaos judge the strife. +The former, vain to hope, argues as vain +The latter; for what place can be for us +Within Heaven's bound, unless Heaven's Lord supreme +We overpower? Suppose he should relent +And publish grace to all, on promise made +Of new subjection; with what eyes could we +Stand in his presence humble, and receive +Strict laws imposed, to celebrate his throne +With warbled hyms, and to his Godhead sing +Forced hallelujahs, while he lordly sits +Our envied sovereign, and his altar breathes +Ambrosial odours and ambrosial flowers, +Our servile offerings? This must be our task +In Heaven, this our delight. How wearisome +Eternity so spent in worship paid +To whom we hate! Let us not then pursue, +By force impossible, by leave obtained +Unacceptable, though in Heaven, our state +Of splendid vassalage; but rather seek +Our own good from ourselves, and from our own +Live to ourselves, though in this vast recess, +Free and to none accountable, preferring +Hard liberty before the easy yoke +Of servile pomp. Our greatness will appear +Then most conspicuous when great things of small, +Useful of hurtful, prosperous of adverse, +We can create, and in what place soe'er +Thrive under evil, and work ease out of pain +Through labour and endurance. This deep world +Of darkness do we dread? How oft amidst +Thick clouds and dark doth Heaven's all-ruling Sire +Choose to reside, his glory unobscured, +And with the majesty of darkness round +Covers his throne, from whence deep thunders roar. +Mustering their rage, and Heaven resembles Hell! +As he our darkness, cannot we his light +Imitate when we please? This desert soil +Wants not her hidden lustre, gems and gold; +Nor want we skill or art from whence to raise +Magnificence; and what can Heaven show more? +Our torments also may, in length of time, +Become our elements, these piercing fires +As soft as now severe, our temper changed +Into their temper; which must needs remove +The sensible of pain. All things invite +To peaceful counsels, and the settled state +Of order, how in safety best we may +Compose our present evils, with regard +Of what we are and where, dismissing quite +All thoughts of war. Ye have what I advise." + He scarce had finished, when such murmur filled +Th' assembly as when hollow rocks retain +The sound of blustering winds, which all night long +Had roused the sea, now with hoarse cadence lull +Seafaring men o'erwatched, whose bark by chance +Or pinnace, anchors in a craggy bay +After the tempest. Such applause was heard +As Mammon ended, and his sentence pleased, +Advising peace: for such another field +They dreaded worse than Hell; so much the fear +Of thunder and the sword of Michael +Wrought still within them; and no less desire +To found this nether empire, which might rise, +By policy and long process of time, +In emulation opposite to Heaven. +Which when Beelzebub perceived--than whom, +Satan except, none higher sat--with grave +Aspect he rose, and in his rising seemed +A pillar of state. Deep on his front engraven +Deliberation sat, and public care; +And princely counsel in his face yet shone, +Majestic, though in ruin. Sage he stood +With Atlantean shoulders, fit to bear +The weight of mightiest monarchies; his look +Drew audience and attention still as night +Or summer's noontide air, while thus he spake:-- + "Thrones and Imperial Powers, Offspring of Heaven, +Ethereal Virtues! or these titles now +Must we renounce, and, changing style, be called +Princes of Hell? for so the popular vote +Inclines--here to continue, and build up here +A growing empire; doubtless! while we dream, +And know not that the King of Heaven hath doomed +This place our dungeon, not our safe retreat +Beyond his potent arm, to live exempt +From Heaven's high jurisdiction, in new league +Banded against his throne, but to remain +In strictest bondage, though thus far removed, +Under th' inevitable curb, reserved +His captive multitude. For he, to be sure, +In height or depth, still first and last will reign +Sole king, and of his kingdom lose no part +By our revolt, but over Hell extend +His empire, and with iron sceptre rule +Us here, as with his golden those in Heaven. +What sit we then projecting peace and war? +War hath determined us and foiled with loss +Irreparable; terms of peace yet none +Vouchsafed or sought; for what peace will be given +To us enslaved, but custody severe, +And stripes and arbitrary punishment +Inflicted? and what peace can we return, +But, to our power, hostility and hate, +Untamed reluctance, and revenge, though slow, +Yet ever plotting how the Conqueror least +May reap his conquest, and may least rejoice +In doing what we most in suffering feel? +Nor will occasion want, nor shall we need +With dangerous expedition to invade +Heaven, whose high walls fear no assault or siege, +Or ambush from the Deep. What if we find +Some easier enterprise? There is a place +(If ancient and prophetic fame in Heaven +Err not)--another World, the happy seat +Of some new race, called Man, about this time +To be created like to us, though less +In power and excellence, but favoured more +Of him who rules above; so was his will +Pronounced among the Gods, and by an oath +That shook Heaven's whole circumference confirmed. +Thither let us bend all our thoughts, to learn +What creatures there inhabit, of what mould +Or substance, how endued, and what their power +And where their weakness: how attempted best, +By force of subtlety. Though Heaven be shut, +And Heaven's high Arbitrator sit secure +In his own strength, this place may lie exposed, +The utmost border of his kingdom, left +To their defence who hold it: here, perhaps, +Some advantageous act may be achieved +By sudden onset--either with Hell-fire +To waste his whole creation, or possess +All as our own, and drive, as we were driven, +The puny habitants; or, if not drive, +Seduce them to our party, that their God +May prove their foe, and with repenting hand +Abolish his own works. This would surpass +Common revenge, and interrupt his joy +In our confusion, and our joy upraise +In his disturbance; when his darling sons, +Hurled headlong to partake with us, shall curse +Their frail original, and faded bliss-- +Faded so soon! Advise if this be worth +Attempting, or to sit in darkness here +Hatching vain empires." Thus beelzebub +Pleaded his devilish counsel--first devised +By Satan, and in part proposed: for whence, +But from the author of all ill, could spring +So deep a malice, to confound the race +Of mankind in one root, and Earth with Hell +To mingle and involve, done all to spite +The great Creator? But their spite still serves +His glory to augment. The bold design +Pleased highly those infernal States, and joy +Sparkled in all their eyes: with full assent +They vote: whereat his speech he thus renews:-- +"Well have ye judged, well ended long debate, +Synod of Gods, and, like to what ye are, +Great things resolved, which from the lowest deep +Will once more lift us up, in spite of fate, +Nearer our ancient seat--perhaps in view +Of those bright confines, whence, with neighbouring arms, +And opportune excursion, we may chance +Re-enter Heaven; or else in some mild zone +Dwell, not unvisited of Heaven's fair light, +Secure, and at the brightening orient beam +Purge off this gloom: the soft delicious air, +To heal the scar of these corrosive fires, +Shall breathe her balm. But, first, whom shall we send +In search of this new World? whom shall we find +Sufficient? who shall tempt with wandering feet +The dark, unbottomed, infinite Abyss, +And through the palpable obscure find out +His uncouth way, or spread his airy flight, +Upborne with indefatigable wings +Over the vast abrupt, ere he arrive +The happy Isle? What strength, what art, can then +Suffice, or what evasion bear him safe, +Through the strict senteries and stations thick +Of Angels watching round? Here he had need +All circumspection: and we now no less +Choice in our suffrage; for on whom we send +The weight of all, and our last hope, relies." + This said, he sat; and expectation held +His look suspense, awaiting who appeared +To second, or oppose, or undertake +The perilous attempt. But all sat mute, +Pondering the danger with deep thoughts; and each +In other's countenance read his own dismay, +Astonished. None among the choice and prime +Of those Heaven-warring champions could be found +So hardy as to proffer or accept, +Alone, the dreadful voyage; till, at last, +Satan, whom now transcendent glory raised +Above his fellows, with monarchal pride +Conscious of highest worth, unmoved thus spake:-- + "O Progeny of Heaven! Empyreal Thrones! +With reason hath deep silence and demur +Seized us, though undismayed. Long is the way +And hard, that out of Hell leads up to light. +Our prison strong, this huge convex of fire, +Outrageous to devour, immures us round +Ninefold; and gates of burning adamant, +Barred over us, prohibit all egress. +These passed, if any pass, the void profound +Of unessential Night receives him next, +Wide-gaping, and with utter loss of being +Threatens him, plunged in that abortive gulf. +If thence he scape, into whatever world, +Or unknown region, what remains him less +Than unknown dangers, and as hard escape? +But I should ill become this throne, O Peers, +And this imperial sovereignty, adorned +With splendour, armed with power, if aught proposed +And judged of public moment in the shape +Of difficulty or danger, could deter +Me from attempting. Wherefore do I assume +These royalties, and not refuse to reign, +Refusing to accept as great a share +Of hazard as of honour, due alike +To him who reigns, and so much to him due +Of hazard more as he above the rest +High honoured sits? Go, therefore, mighty Powers, +Terror of Heaven, though fallen; intend at home, +While here shall be our home, what best may ease +The present misery, and render Hell +More tolerable; if there be cure or charm +To respite, or deceive, or slack the pain +Of this ill mansion: intermit no watch +Against a wakeful foe, while I abroad +Through all the coasts of dark destruction seek +Deliverance for us all. This enterprise +None shall partake with me." Thus saying, rose +The Monarch, and prevented all reply; +Prudent lest, from his resolution raised, +Others among the chief might offer now, +Certain to be refused, what erst they feared, +And, so refused, might in opinion stand +His rivals, winning cheap the high repute +Which he through hazard huge must earn. But they +Dreaded not more th' adventure than his voice +Forbidding; and at once with him they rose. +Their rising all at once was as the sound +Of thunder heard remote. Towards him they bend +With awful reverence prone, and as a God +Extol him equal to the Highest in Heaven. +Nor failed they to express how much they praised +That for the general safety he despised +His own: for neither do the Spirits damned +Lose all their virtue; lest bad men should boast +Their specious deeds on earth, which glory excites, +Or close ambition varnished o'er with zeal. + Thus they their doubtful consultations dark +Ended, rejoicing in their matchless Chief: +As, when from mountain-tops the dusky clouds +Ascending, while the north wind sleeps, o'erspread +Heaven's cheerful face, the louring element +Scowls o'er the darkened landscape snow or shower, +If chance the radiant sun, with farewell sweet, +Extend his evening beam, the fields revive, +The birds their notes renew, and bleating herds +Attest their joy, that hill and valley rings. +O shame to men! Devil with devil damned +Firm concord holds; men only disagree +Of creatures rational, though under hope +Of heavenly grace, and, God proclaiming peace, +Yet live in hatred, enmity, and strife +Among themselves, and levy cruel wars +Wasting the earth, each other to destroy: +As if (which might induce us to accord) +Man had not hellish foes enow besides, +That day and night for his destruction wait! + The Stygian council thus dissolved; and forth +In order came the grand infernal Peers: +Midst came their mighty Paramount, and seemed +Alone th' antagonist of Heaven, nor less +Than Hell's dread Emperor, with pomp supreme, +And god-like imitated state: him round +A globe of fiery Seraphim enclosed +With bright emblazonry, and horrent arms. +Then of their session ended they bid cry +With trumpet's regal sound the great result: +Toward the four winds four speedy Cherubim +Put to their mouths the sounding alchemy, +By herald's voice explained; the hollow Abyss +Heard far adn wide, and all the host of Hell +With deafening shout returned them loud acclaim. +Thence more at ease their minds, and somewhat raised +By false presumptuous hope, the ranged Powers +Disband; and, wandering, each his several way +Pursues, as inclination or sad choice +Leads him perplexed, where he may likeliest find +Truce to his restless thoughts, and entertain +The irksome hours, till his great Chief return. +Part on the plain, or in the air sublime, +Upon the wing or in swift race contend, +As at th' Olympian games or Pythian fields; +Part curb their fiery steeds, or shun the goal +With rapid wheels, or fronted brigades form: +As when, to warn proud cities, war appears +Waged in the troubled sky, and armies rush +To battle in the clouds; before each van +Prick forth the airy knights, and couch their spears, +Till thickest legions close; with feats of arms +From either end of heaven the welkin burns. +Others, with vast Typhoean rage, more fell, +Rend up both rocks and hills, and ride the air +In whirlwind; Hell scarce holds the wild uproar:-- +As when Alcides, from Oechalia crowned +With conquest, felt th' envenomed robe, and tore +Through pain up by the roots Thessalian pines, +And Lichas from the top of Oeta threw +Into th' Euboic sea. Others, more mild, +Retreated in a silent valley, sing +With notes angelical to many a harp +Their own heroic deeds, and hapless fall +By doom of battle, and complain that Fate +Free Virtue should enthrall to Force or Chance. +Their song was partial; but the harmony +(What could it less when Spirits immortal sing?) +Suspended Hell, and took with ravishment +The thronging audience. In discourse more sweet +(For Eloquence the Soul, Song charms the Sense) +Others apart sat on a hill retired, +In thoughts more elevate, and reasoned high +Of Providence, Foreknowledge, Will, and Fate-- +Fixed fate, free will, foreknowledge absolute, +And found no end, in wandering mazes lost. +Of good and evil much they argued then, +Of happiness and final misery, +Passion and apathy, and glory and shame: +Vain wisdom all, and false philosophy!-- +Yet, with a pleasing sorcery, could charm +Pain for a while or anguish, and excite +Fallacious hope, or arm th' obdured breast +With stubborn patience as with triple steel. +Another part, in squadrons and gross bands, +On bold adventure to discover wide +That dismal world, if any clime perhaps +Might yield them easier habitation, bend +Four ways their flying march, along the banks +Of four infernal rivers, that disgorge +Into the burning lake their baleful streams-- +Abhorred Styx, the flood of deadly hate; +Sad Acheron of sorrow, black and deep; +Cocytus, named of lamentation loud +Heard on the rueful stream; fierce Phlegeton, +Whose waves of torrent fire inflame with rage. +Far off from these, a slow and silent stream, +Lethe, the river of oblivion, rolls +Her watery labyrinth, whereof who drinks +Forthwith his former state and being forgets-- +Forgets both joy and grief, pleasure and pain. +Beyond this flood a frozen continent +Lies dark and wild, beat with perpetual storms +Of whirlwind and dire hail, which on firm land +Thaws not, but gathers heap, and ruin seems +Of ancient pile; all else deep snow and ice, +A gulf profound as that Serbonian bog +Betwixt Damiata and Mount Casius old, +Where armies whole have sunk: the parching air +Burns frore, and cold performs th' effect of fire. +Thither, by harpy-footed Furies haled, +At certain revolutions all the damned +Are brought; and feel by turns the bitter change +Of fierce extremes, extremes by change more fierce, +From beds of raging fire to starve in ice +Their soft ethereal warmth, and there to pine +Immovable, infixed, and frozen round +Periods of time,--thence hurried back to fire. +They ferry over this Lethean sound +Both to and fro, their sorrow to augment, +And wish and struggle, as they pass, to reach +The tempting stream, with one small drop to lose +In sweet forgetfulness all pain and woe, +All in one moment, and so near the brink; +But Fate withstands, and, to oppose th' attempt, +Medusa with Gorgonian terror guards +The ford, and of itself the water flies +All taste of living wight, as once it fled +The lip of Tantalus. Thus roving on +In confused march forlorn, th' adventurous bands, +With shuddering horror pale, and eyes aghast, +Viewed first their lamentable lot, and found +No rest. Through many a dark and dreary vale +They passed, and many a region dolorous, +O'er many a frozen, many a fiery alp, +Rocks, caves, lakes, fens, bogs, dens, and shades of death-- +A universe of death, which God by curse +Created evil, for evil only good; +Where all life dies, death lives, and Nature breeds, +Perverse, all monstrous, all prodigious things, +Obominable, inutterable, and worse +Than fables yet have feigned or fear conceived, +Gorgons, and Hydras, and Chimeras dire. + Meanwhile the Adversary of God and Man, +Satan, with thoughts inflamed of highest design, +Puts on swift wings, and toward the gates of Hell +Explores his solitary flight: sometimes +He scours the right hand coast, sometimes the left; +Now shaves with level wing the deep, then soars +Up to the fiery concave towering high. +As when far off at sea a fleet descried +Hangs in the clouds, by equinoctial winds +Close sailing from Bengala, or the isles +Of Ternate and Tidore, whence merchants bring +Their spicy drugs; they on the trading flood, +Through the wide Ethiopian to the Cape, +Ply stemming nightly toward the pole: so seemed +Far off the flying Fiend. At last appear +Hell-bounds, high reaching to the horrid roof, +And thrice threefold the gates; three folds were brass, +Three iron, three of adamantine rock, +Impenetrable, impaled with circling fire, +Yet unconsumed. Before the gates there sat +On either side a formidable Shape. +The one seemed woman to the waist, and fair, +But ended foul in many a scaly fold, +Voluminous and vast--a serpent armed +With mortal sting. About her middle round +A cry of Hell-hounds never-ceasing barked +With wide Cerberean mouths full loud, and rung +A hideous peal; yet, when they list, would creep, +If aught disturbed their noise, into her womb, +And kennel there; yet there still barked and howled +Within unseen. Far less abhorred than these +Vexed Scylla, bathing in the sea that parts +Calabria from the hoarse Trinacrian shore; +Nor uglier follow the night-hag, when, called +In secret, riding through the air she comes, +Lured with the smell of infant blood, to dance +With Lapland witches, while the labouring moon +Eclipses at their charms. The other Shape-- +If shape it might be called that shape had none +Distinguishable in member, joint, or limb; +Or substance might be called that shadow seemed, +For each seemed either--black it stood as Night, +Fierce as ten Furies, terrible as Hell, +And shook a dreadful dart: what seemed his head +The likeness of a kingly crown had on. +Satan was now at hand, and from his seat +The monster moving onward came as fast +With horrid strides; Hell trembled as he strode. +Th' undaunted Fiend what this might be admired-- +Admired, not feared (God and his Son except, +Created thing naught valued he nor shunned), +And with disdainful look thus first began:-- + "Whence and what art thou, execrable Shape, +That dar'st, though grim and terrible, advance +Thy miscreated front athwart my way +To yonder gates? Through them I mean to pass, +That be assured, without leave asked of thee. +Retire; or taste thy folly, and learn by proof, +Hell-born, not to contend with Spirits of Heaven." + To whom the Goblin, full of wrath, replied:-- +"Art thou that traitor Angel? art thou he, +Who first broke peace in Heaven and faith, till then +Unbroken, and in proud rebellious arms +Drew after him the third part of Heaven's sons, +Conjured against the Highest--for which both thou +And they, outcast from God, are here condemned +To waste eternal days in woe and pain? +And reckon'st thou thyself with Spirits of Heaven +Hell-doomed, and breath'st defiance here and scorn, +Where I reign king, and, to enrage thee more, +Thy king and lord? Back to thy punishment, +False fugitive; and to thy speed add wings, +Lest with a whip of scorpions I pursue +Thy lingering, or with one stroke of this dart +Strange horror seize thee, and pangs unfelt before." + So spake the grisly Terror, and in shape, +So speaking and so threatening, grew tenfold, +More dreadful and deform. On th' other side, +Incensed with indignation, Satan stood +Unterrified, and like a comet burned, +That fires the length of Ophiuchus huge +In th' arctic sky, and from his horrid hair +Shakes pestilence and war. Each at the head +Levelled his deadly aim; their fatal hands +No second stroke intend; and such a frown +Each cast at th' other as when two black clouds, +With heaven's artillery fraught, came rattling on +Over the Caspian,--then stand front to front +Hovering a space, till winds the signal blow +To join their dark encounter in mid-air. +So frowned the mighty combatants that Hell +Grew darker at their frown; so matched they stood; +For never but once more was wither like +To meet so great a foe. And now great deeds +Had been achieved, whereof all Hell had rung, +Had not the snaky Sorceress, that sat +Fast by Hell-gate and kept the fatal key, +Risen, and with hideous outcry rushed between. + "O father, what intends thy hand," she cried, +"Against thy only son? What fury, O son, +Possesses thee to bend that mortal dart +Against thy father's head? And know'st for whom? +For him who sits above, and laughs the while +At thee, ordained his drudge to execute +Whate'er his wrath, which he calls justice, bids-- +His wrath, which one day will destroy ye both!" + She spake, and at her words the hellish Pest +Forbore: then these to her Satan returned:-- + "So strange thy outcry, and thy words so strange +Thou interposest, that my sudden hand, +Prevented, spares to tell thee yet by deeds +What it intends, till first I know of thee +What thing thou art, thus double-formed, and why, +In this infernal vale first met, thou call'st +Me father, and that phantasm call'st my son. +I know thee not, nor ever saw till now +Sight more detestable than him and thee." + T' whom thus the Portress of Hell-gate replied:-- +"Hast thou forgot me, then; and do I seem +Now in thine eye so foul?--once deemed so fair +In Heaven, when at th' assembly, and in sight +Of all the Seraphim with thee combined +In bold conspiracy against Heaven's King, +All on a sudden miserable pain +Surprised thee, dim thine eyes and dizzy swum +In darkness, while thy head flames thick and fast +Threw forth, till on the left side opening wide, +Likest to thee in shape and countenance bright, +Then shining heavenly fair, a goddess armed, +Out of thy head I sprung. Amazement seized +All th' host of Heaven; back they recoiled afraid +At first, and called me Sin, and for a sign +Portentous held me; but, familiar grown, +I pleased, and with attractive graces won +The most averse--thee chiefly, who, full oft +Thyself in me thy perfect image viewing, +Becam'st enamoured; and such joy thou took'st +With me in secret that my womb conceived +A growing burden. Meanwhile war arose, +And fields were fought in Heaven: wherein remained +(For what could else?) to our Almighty Foe +Clear victory; to our part loss and rout +Through all the Empyrean. Down they fell, +Driven headlong from the pitch of Heaven, down +Into this Deep; and in the general fall +I also: at which time this powerful key +Into my hands was given, with charge to keep +These gates for ever shut, which none can pass +Without my opening. Pensive here I sat +Alone; but long I sat not, till my womb, +Pregnant by thee, and now excessive grown, +Prodigious motion felt and rueful throes. +At last this odious offspring whom thou seest, +Thine own begotten, breaking violent way, +Tore through my entrails, that, with fear and pain +Distorted, all my nether shape thus grew +Transformed: but he my inbred enemy +Forth issued, brandishing his fatal dart, +Made to destroy. I fled, and cried out Death! +Hell trembled at the hideous name, and sighed +From all her caves, and back resounded Death! +I fled; but he pursued (though more, it seems, +Inflamed with lust than rage), and, swifter far, +Me overtook, his mother, all dismayed, +And, in embraces forcible and foul +Engendering with me, of that rape begot +These yelling monsters, that with ceaseless cry +Surround me, as thou saw'st--hourly conceived +And hourly born, with sorrow infinite +To me; for, when they list, into the womb +That bred them they return, and howl, and gnaw +My bowels, their repast; then, bursting forth +Afresh, with conscious terrors vex me round, +That rest or intermission none I find. +Before mine eyes in opposition sits +Grim Death, my son and foe, who set them on, +And me, his parent, would full soon devour +For want of other prey, but that he knows +His end with mine involved, and knows that I +Should prove a bitter morsel, and his bane, +Whenever that shall be: so Fate pronounced. +But thou, O father, I forewarn thee, shun +His deadly arrow; neither vainly hope +To be invulnerable in those bright arms, +Through tempered heavenly; for that mortal dint, +Save he who reigns above, none can resist." + She finished; and the subtle Fiend his lore +Soon learned, now milder, and thus answered smooth:-- + "Dear daughter--since thou claim'st me for thy sire, +And my fair son here show'st me, the dear pledge +Of dalliance had with thee in Heaven, and joys +Then sweet, now sad to mention, through dire change +Befallen us unforeseen, unthought-of--know, +I come no enemy, but to set free +From out this dark and dismal house of pain +Both him and thee, and all the heavenly host +Of Spirits that, in our just pretences armed, +Fell with us from on high. From them I go +This uncouth errand sole, and one for all +Myself expose, with lonely steps to tread +Th' unfounded Deep, and through the void immense +To search, with wandering quest, a place foretold +Should be--and, by concurring signs, ere now +Created vast and round--a place of bliss +In the purlieus of Heaven; and therein placed +A race of upstart creatures, to supply +Perhaps our vacant room, though more removed, +Lest Heaven, surcharged with potent multitude, +Might hap to move new broils. Be this, or aught +Than this more secret, now designed, I haste +To know; and, this once known, shall soon return, +And bring ye to the place where thou and Death +Shall dwell at ease, and up and down unseen +Wing silently the buxom air, embalmed +With odours. There ye shall be fed and filled +Immeasurably; all things shall be your prey." + He ceased; for both seemed highly pleased, and Death +Grinned horrible a ghastly smile, to hear +His famine should be filled, and blessed his maw +Destined to that good hour. No less rejoiced +His mother bad, and thus bespake her sire:-- + "The key of this infernal Pit, by due +And by command of Heaven's all-powerful King, +I keep, by him forbidden to unlock +These adamantine gates; against all force +Death ready stands to interpose his dart, +Fearless to be o'ermatched by living might. +But what owe I to his commands above, +Who hates me, and hath hither thrust me down +Into this gloom of Tartarus profound, +To sit in hateful office here confined, +Inhabitant of Heaven and heavenly born-- +Here in perpetual agony and pain, +With terrors and with clamours compassed round +Of mine own brood, that on my bowels feed? +Thou art my father, thou my author, thou +My being gav'st me; whom should I obey +But thee? whom follow? Thou wilt bring me soon +To that new world of light and bliss, among +The gods who live at ease, where I shall reign +At thy right hand voluptuous, as beseems +Thy daughter and thy darling, without end." + Thus saying, from her side the fatal key, +Sad instrument of all our woe, she took; +And, towards the gate rolling her bestial train, +Forthwith the huge portcullis high up-drew, +Which, but herself, not all the Stygian Powers +Could once have moved; then in the key-hole turns +Th' intricate wards, and every bolt and bar +Of massy iron or solid rock with ease +Unfastens. On a sudden open fly, +With impetuous recoil and jarring sound, +Th' infernal doors, and on their hinges grate +Harsh thunder, that the lowest bottom shook +Of Erebus. She opened; but to shut +Excelled her power: the gates wide open stood, +That with extended wings a bannered host, +Under spread ensigns marching, mibht pass through +With horse and chariots ranked in loose array; +So wide they stood, and like a furnace-mouth +Cast forth redounding smoke and ruddy flame. +Before their eyes in sudden view appear +The secrets of the hoary Deep--a dark +Illimitable ocean, without bound, +Without dimension; where length, breadth, and height, +And time, and place, are lost; where eldest Night +And Chaos, ancestors of Nature, hold +Eternal anarchy, amidst the noise +Of endless wars, and by confusion stand. +For Hot, Cold, Moist, and Dry, four champions fierce, +Strive here for mastery, and to battle bring +Their embryon atoms: they around the flag +Of each his faction, in their several clans, +Light-armed or heavy, sharp, smooth, swift, or slow, +Swarm populous, unnumbered as the sands +Of Barca or Cyrene's torrid soil, +Levied to side with warring winds, and poise +Their lighter wings. To whom these most adhere +He rules a moment: Chaos umpire sits, +And by decision more embroils the fray +By which he reigns: next him, high arbiter, +Chance governs all. Into this wild Abyss, +The womb of Nature, and perhaps her grave, +Of neither sea, nor shore, nor air, nor fire, +But all these in their pregnant causes mixed +Confusedly, and which thus must ever fight, +Unless th' Almighty Maker them ordain +His dark materials to create more worlds-- +Into this wild Abyss the wary Fiend +Stood on the brink of Hell and looked a while, +Pondering his voyage; for no narrow frith +He had to cross. Nor was his ear less pealed +With noises loud and ruinous (to compare +Great things with small) than when Bellona storms +With all her battering engines, bent to rase +Some capital city; or less than if this frame +Of Heaven were falling, and these elements +In mutiny had from her axle torn +The steadfast Earth. At last his sail-broad vans +He spread for flight, and, in the surging smoke +Uplifted, spurns the ground; thence many a league, +As in a cloudy chair, ascending rides +Audacious; but, that seat soon failing, meets +A vast vacuity. All unawares, +Fluttering his pennons vain, plumb-down he drops +Ten thousand fathom deep, and to this hour +Down had been falling, had not, by ill chance, +The strong rebuff of some tumultuous cloud, +Instinct with fire and nitre, hurried him +As many miles aloft. That fury stayed-- +Quenched in a boggy Syrtis, neither sea, +Nor good dry land--nigh foundered, on he fares, +Treading the crude consistence, half on foot, +Half flying; behoves him now both oar and sail. +As when a gryphon through the wilderness +With winged course, o'er hill or moory dale, +Pursues the Arimaspian, who by stealth +Had from his wakeful custody purloined +The guarded gold; so eagerly the Fiend +O'er bog or steep, through strait, rough, dense, or rare, +With head, hands, wings, or feet, pursues his way, +And swims, or sinks, or wades, or creeps, or flies. +At length a universal hubbub wild +Of stunning sounds, and voices all confused, +Borne through the hollow dark, assaults his ear +With loudest vehemence. Thither he plies +Undaunted, to meet there whatever Power +Or Spirit of the nethermost Abyss +Might in that noise reside, of whom to ask +Which way the nearest coast of darkness lies +Bordering on light; when straight behold the throne +Of Chaos, and his dark pavilion spread +Wide on the wasteful Deep! With him enthroned +Sat sable-vested Night, eldest of things, +The consort of his reign; and by them stood +Orcus and Ades, and the dreaded name +Of Demogorgon; Rumour next, and Chance, +And Tumult, and Confusion, all embroiled, +And Discord with a thousand various mouths. + T' whom Satan, turning boldly, thus:--"Ye Powers +And Spirtis of this nethermost Abyss, +Chaos and ancient Night, I come no spy +With purpose to explore or to disturb +The secrets of your realm; but, by constraint +Wandering this darksome desert, as my way +Lies through your spacious empire up to light, +Alone and without guide, half lost, I seek, +What readiest path leads where your gloomy bounds +Confine with Heaven; or, if some other place, +From your dominion won, th' Ethereal King +Possesses lately, thither to arrive +I travel this profound. Direct my course: +Directed, no mean recompense it brings +To your behoof, if I that region lost, +All usurpation thence expelled, reduce +To her original darkness and your sway +(Which is my present journey), and once more +Erect the standard there of ancient Night. +Yours be th' advantage all, mine the revenge!" + Thus Satan; and him thus the Anarch old, +With faltering speech and visage incomposed, +Answered: "I know thee, stranger, who thou art-- *** +That mighty leading Angel, who of late +Made head against Heaven's King, though overthrown. +I saw and heard; for such a numerous host +Fled not in silence through the frighted Deep, +With ruin upon ruin, rout on rout, +Confusion worse confounded; and Heaven-gates +Poured out by millions her victorious bands, +Pursuing. I upon my frontiers here +Keep residence; if all I can will serve +That little which is left so to defend, +Encroached on still through our intestine broils +Weakening the sceptre of old Night: first, Hell, +Your dungeon, stretching far and wide beneath; +Now lately Heaven and Earth, another world +Hung o'er my realm, linked in a golden chain +To that side Heaven from whence your legions fell! +If that way be your walk, you have not far; +So much the nearer danger. Go, and speed; +Havoc, and spoil, and ruin, are my gain." + He ceased; and Satan stayed not to reply, +But, glad that now his sea should find a shore, +With fresh alacrity and force renewed +Springs upward, like a pyramid of fire, +Into the wild expanse, and through the shock +Of fighting elements, on all sides round +Environed, wins his way; harder beset +And more endangered than when Argo passed +Through Bosporus betwixt the justling rocks, +Or when Ulysses on the larboard shunned +Charybdis, and by th' other whirlpool steered. +So he with difficulty and labour hard +Moved on, with difficulty and labour he; +But, he once passed, soon after, when Man fell, +Strange alteration! Sin and Death amain, +Following his track (such was the will of Heaven) +Paved after him a broad and beaten way +Over the dark Abyss, whose boiling gulf +Tamely endured a bridge of wondrous length, +From Hell continued, reaching th' utmost orb +Of this frail World; by which the Spirits perverse +With easy intercourse pass to and fro +To tempt or punish mortals, except whom +God and good Angels guard by special grace. + But now at last the sacred influence +Of light appears, and from the walls of Heaven +Shoots far into the bosom of dim Night +A glimmering dawn. Here Nature first begins +Her farthest verge, and Chaos to retire, +As from her outmost works, a broken foe, +With tumult less and with less hostile din; +That Satan with less toil, and now with ease, +Wafts on the calmer wave by dubious light, +And, like a weather-beaten vessel, holds +Gladly the port, though shrouds and tackle torn; +Or in the emptier waste, resembling air, +Weighs his spread wings, at leisure to behold +Far off th' empyreal Heaven, extended wide +In circuit, undetermined square or round, +With opal towers and battlements adorned +Of living sapphire, once his native seat; +And, fast by, hanging in a golden chain, +This pendent World, in bigness as a star +Of smallest magnitude close by the moon. +Thither, full fraught with mischievous revenge, +Accursed, and in a cursed hour, he hies. + + + +Book III + + +Hail, holy Light, offspring of Heaven firstborn, +Or of the Eternal coeternal beam +May I express thee unblam'd? since God is light, +And never but in unapproached light +Dwelt from eternity, dwelt then in thee +Bright effluence of bright essence increate. +Or hear"st thou rather pure ethereal stream, +Whose fountain who shall tell? before the sun, +Before the Heavens thou wert, and at the voice +Of God, as with a mantle, didst invest *** +The rising world of waters dark and deep, +Won from the void and formless infinite. +Thee I re-visit now with bolder wing, +Escap'd the Stygian pool, though long detain'd +In that obscure sojourn, while in my flight +Through utter and through middle darkness borne, +With other notes than to the Orphean lyre +I sung of Chaos and eternal Night; +Taught by the heavenly Muse to venture down +The dark descent, and up to re-ascend, +Though hard and rare: Thee I revisit safe, +And feel thy sovran vital lamp; but thou +Revisit'st not these eyes, that roll in vain +To find thy piercing ray, and find no dawn; +So thick a drop serene hath quench'd their orbs, +Or dim suffusion veil'd. Yet not the more +Cease I to wander, where the Muses haunt, +Clear spring, or shady grove, or sunny hill, +Smit with the love of sacred song; but chief +Thee, Sion, and the flowery brooks beneath, +That wash thy hallow'd feet, and warbling flow, +Nightly I visit: nor sometimes forget +So were I equall'd with them in renown, +Thy sovran command, that Man should find grace; +Blind Thamyris, and blind Maeonides, +And Tiresias, and Phineus, prophets old: +Then feed on thoughts, that voluntary move +Harmonious numbers; as the wakeful bird +Sings darkling, and in shadiest covert hid +Tunes her nocturnal note. Thus with the year +Seasons return; but not to me returns +Day, or the sweet approach of even or morn, +Or sight of vernal bloom, or summer's rose, +Or flocks, or herds, or human face divine; +But cloud instead, and ever-during dark +Surrounds me, from the cheerful ways of men +Cut off, and for the book of knowledge fair +Presented with a universal blank +Of nature's works to me expung'd and ras'd, +And wisdom at one entrance quite shut out. +So much the rather thou, celestial Light, +Shine inward, and the mind through all her powers +Irradiate; there plant eyes, all mist from thence +Purge and disperse, that I may see and tell +Of things invisible to mortal sight. +Now had the Almighty Father from above, +From the pure empyrean where he sits +High thron'd above all highth, bent down his eye +His own works and their works at once to view: +About him all the Sanctities of Heaven +Stood thick as stars, and from his sight receiv'd +Beatitude past utterance; on his right +The radiant image of his glory sat, +His only son; on earth he first beheld +Our two first parents, yet the only two +Of mankind in the happy garden plac'd +Reaping immortal fruits of joy and love, +Uninterrupted joy, unrivall'd love, +In blissful solitude; he then survey'd +Hell and the gulf between, and Satan there +Coasting the wall of Heaven on this side Night +In the dun air sublime, and ready now +To stoop with wearied wings, and willing feet, +On the bare outside of this world, that seem'd +Firm land imbosom'd, without firmament, +Uncertain which, in ocean or in air. +Him God beholding from his prospect high, +Wherein past, present, future, he beholds, +Thus to his only Son foreseeing spake. +Only begotten Son, seest thou what rage +Transports our Adversary? whom no bounds +Prescrib'd no bars of Hell, nor all the chains +Heap'd on him there, nor yet the main abyss +Wide interrupt, can hold; so bent he seems +On desperate revenge, that shall redound +Upon his own rebellious head. And now, +Through all restraint broke loose, he wings his way +Not far off Heaven, in the precincts of light, +Directly towards the new created world, +And man there plac'd, with purpose to assay +If him by force he can destroy, or, worse, +By some false guile pervert; and shall pervert; +For man will hearken to his glozing lies, +And easily transgress the sole command, +Sole pledge of his obedience: So will fall +He and his faithless progeny: Whose fault? +Whose but his own? ingrate, he had of me +All he could have; I made him just and right, +Sufficient to have stood, though free to fall. +Such I created all the ethereal Powers +And Spirits, both them who stood, and them who fail'd; +Freely they stood who stood, and fell who fell. +Not free, what proof could they have given sincere +Of true allegiance, constant faith or love, +Where only what they needs must do appear'd, +Not what they would? what praise could they receive? +What pleasure I from such obedience paid, +When will and reason (reason also is choice) +Useless and vain, of freedom both despoil'd, +Made passive both, had serv'd necessity, +Not me? they therefore, as to right belong$ 'd, +So were created, nor can justly accuse +Their Maker, or their making, or their fate, +As if predestination over-rul'd +Their will dispos'd by absolute decree +Or high foreknowledge they themselves decreed +Their own revolt, not I; if I foreknew, +Foreknowledge had no influence on their fault, +Which had no less proved certain unforeknown. +So without least impulse or shadow of fate, +Or aught by me immutably foreseen, +They trespass, authors to themselves in all +Both what they judge, and what they choose; for so +I form'd them free: and free they must remain, +Till they enthrall themselves; I else must change +Their nature, and revoke the high decree +Unchangeable, eternal, which ordain'd +$THeir freedom: they themselves ordain'd their fall. +The first sort by their own suggestion fell, +Self-tempted, self-deprav'd: Man falls, deceiv'd +By the other first: Man therefore shall find grace, +The other none: In mercy and justice both, +Through Heaven and Earth, so shall my glory excel; +But Mercy, first and last, shall brightest shine. +Thus while God spake, ambrosial fragrance fill'd +All Heaven, and in the blessed Spirits elect +Sense of new joy ineffable diffus'd. +Beyond compare the Son of God was seen +Most glorious; in him all his Father shone +Substantially express'd; and in his face +Divine compassion visibly appear'd, +Love without end, and without measure grace, +Which uttering, thus he to his Father spake. +O Father, gracious was that word which clos'd +Thy sovran command, that Man should find grace; +, that Man should find grace; +For which both Heaven and earth shall high extol +Thy praises, with the innumerable sound +Of hymns and sacred songs, wherewith thy throne +Encompass'd shall resound thee ever blest. +For should Man finally be lost, should Man, +Thy creature late so lov'd, thy youngest son, +Fall circumvented thus by fraud, though join'd +With his own folly? that be from thee far, +That far be from thee, Father, who art judge +Of all things made, and judgest only right. +Or shall the Adversary thus obtain +His end, and frustrate thine? shall he fulfill +His malice, and thy goodness bring to nought, +Or proud return, though to his heavier doom, +Yet with revenge accomplish'd, and to Hell +Draw after him the whole race of mankind, +By him corrupted? or wilt thou thyself +Abolish thy creation, and unmake +For him, what for thy glory thou hast made? +So should thy goodness and thy greatness both +Be question'd and blasphem'd without defence. +To whom the great Creator thus replied. +O son, in whom my soul hath chief delight, +Son of my bosom, Son who art alone. +My word, my wisdom, and effectual might, +All hast thou spoken as my thoughts are, all +As my eternal purpose hath decreed; +Man shall not quite be lost, but sav'd who will; +Yet not of will in him, but grace in me +Freely vouchsaf'd; once more I will renew +His lapsed powers, though forfeit; and enthrall'd +By sin to foul exorbitant desires; +Upheld by me, yet once more he shall stand +On even ground against his mortal foe; +By me upheld, that he may know how frail +His fallen condition is, and to me owe +All his deliverance, and to none but me. +Some I have chosen of peculiar grace, +Elect above the rest; so is my will: +The rest shall hear me call, and oft be warn'd +Their sinful state, and to appease betimes +The incensed Deity, while offer'd grace +Invites; for I will clear their senses dark, +What may suffice, and soften stony hearts +To pray, repent, and bring obedience due. +To prayer, repentance, and obedience due, +Though but endeavour'd with sincere intent, +Mine ear shall not be slow, mine eye not shut. +And I will place within them as a guide, +My umpire Conscience; whom if they will hear, +Light after light, well us'd, they shall attain, +And to the end, persisting, safe arrive. +This my long sufferance, and my day of grace, +They who neglect and scorn, shall never taste; +But hard be harden'd, blind be blinded more, +That they may stumble on, and deeper fall; +And none but such from mercy I exclude. +But yet all is not done; Man disobeying, +Disloyal, breaks his fealty, and sins +Against the high supremacy of Heaven, +Affecting God-head, and, so losing all, +To expiate his treason hath nought left, +But to destruction sacred and devote, +He, with his whole posterity, must die, +Die he or justice must; unless for him +Some other able, and as willing, pay +The rigid satisfaction, death for death. +Say, heavenly Powers, where shall we find such love? +Which of you will be mortal, to redeem +Man's mortal crime, and just the unjust to save? +Dwells in all Heaven charity so dear? +And silence was in Heaven: $ on Man's behalf +He ask'd, but all the heavenly quire stood mute, +Patron or intercessour none appear'd, +Much less that durst upon his own head draw +The deadly forfeiture, and ransom set. +And now without redemption all mankind +Must have been lost, adjudg'd to Death and Hell +By doom severe, had not the Son of God, +In whom the fulness dwells of love divine, +His dearest mediation thus renew'd. +Father, thy word is past, Man shall find grace; +And shall grace not find means, that finds her way, +The speediest of thy winged messengers, +To visit all thy creatures, and to all +Comes unprevented, unimplor'd, unsought? +Happy for Man, so coming; he her aid +Can never seek, once dead in sins, and lost; +Atonement for himself, or offering meet, +Indebted and undone, hath none to bring; +Behold me then: me for him, life for life +I offer: on me let thine anger fall; +Account me Man; I for his sake will leave + Thy bosom, and this glory next to thee + Freely put off, and for him lastly die + Well pleased; on me let Death wreak all his rage. + Under his gloomy power I shall not long + Lie vanquished. Thou hast given me to possess + Life in myself for ever; by thee I live; + Though now to Death I yield, and am his due, + All that of me can die, yet, that debt paid, + $ thou wilt not leave me in the loathsome grave + His prey, nor suffer my unspotted soul + For ever with corruption there to dwell; + But I shall rise victorious, and subdue + My vanquisher, spoiled of his vaunted spoil. + Death his death's wound shall then receive, and stoop + Inglorious, of his mortal sting disarmed; + I through the ample air in triumph high + Shall lead Hell captive maugre Hell, and show +The powers of darkness bound. Thou, at the sight + Pleased, out of Heaven shalt look down and smile, + While, by thee raised, I ruin all my foes; + Death last, and with his carcase glut the grave; + Then, with the multitude of my redeemed, + Shall enter Heaven, long absent, and return, + Father, to see thy face, wherein no cloud + Of anger shall remain, but peace assured + And reconcilement: wrath shall be no more + Thenceforth, but in thy presence joy entire. + His words here ended; but his meek aspect + Silent yet spake, and breathed immortal love + To mortal men, above which only shone + Filial obedience: as a sacrifice + Glad to be offered, he attends the will + Of his great Father. Admiration seized + All Heaven, what this might mean, and whither tend, + Wondering; but soon th' Almighty thus replied. + O thou in Heaven and Earth the only peace + Found out for mankind under wrath, O thou + My sole complacence! Well thou know'st how dear + To me are all my works; nor Man the least, + Though last created, that for him I spare + Thee from my bosom and right hand, to save, + By losing thee a while, the whole race lost. + + 00021053 + Thou, therefore, whom thou only canst redeem, + Their nature also to thy nature join; + And be thyself Man among men on Earth, + Made flesh, when time shall be, of virgin seed, + By wondrous birth; be thou in Adam's room +The head of all mankind, though Adam's son. +As in him perish all men, so in thee, +As from a second root, shall be restored +As many as are restored, without thee none. +His crime makes guilty all his sons; thy merit, +Imputed, shall absolve them who renounce +Their own both righteous and unrighteous deeds, +And live in thee transplanted, and from thee +Receive new life. So Man, as is most just, +Shall satisfy for Man, be judged and die, +And dying rise, and rising with him raise +His brethren, ransomed with his own dear life. +So heavenly love shall outdo hellish hate, +Giving to death, and dying to redeem, +So dearly to redeem what hellish hate +So easily destroyed, and still destroys +In those who, when they may, accept not grace. +Nor shalt thou, by descending to assume +Man's nature, lessen or degrade thine own. +Because thou hast, though throned in highest bliss +Equal to God, and equally enjoying +God-like fruition, quitted all, to save +A world from utter loss, and hast been found +By merit more than birthright Son of God, +Found worthiest to be so by being good, +Far more than great or high; because in thee +Love hath abounded more than glory abounds; +Therefore thy humiliation shall exalt +With thee thy manhood also to this throne: +Here shalt thou sit incarnate, here shalt reign +Both God and Man, Son both of God and Man, +Anointed universal King; all power +I give thee; reign for ever, and assume +Thy merits; under thee, as head supreme, +Thrones, Princedoms, Powers, Dominions, I reduce: +All knees to thee shall bow, of them that bide +In Heaven, or Earth, or under Earth in Hell. +When thou, attended gloriously from Heaven, +Shalt in the sky appear, and from thee send +The summoning Arch-Angels to proclaim +Thy dread tribunal; forthwith from all winds, +The living, and forthwith the cited dead +Of all past ages, to the general doom +Shall hasten; such a peal shall rouse their sleep. +Then, all thy saints assembled, thou shalt judge +Bad Men and Angels; they, arraigned, shall sink +Beneath thy sentence; Hell, her numbers full, +Thenceforth shall be for ever shut. Mean while +The world shall burn, and from her ashes spring +New Heaven and Earth, wherein the just shall dwell, +And, after all their tribulations long, +See golden days, fruitful of golden deeds, +With joy and peace triumphing, and fair truth. +Then thou thy regal scepter shalt lay by, +For regal scepter then no more shall need, +God shall be all in all. But, all ye Gods, +Adore him, who to compass all this dies; +Adore the Son, and honour him as me. +No sooner had the Almighty ceased, but all +The multitude of Angels, with a shout +Loud as from numbers without number, sweet +As from blest voices, uttering joy, Heaven rung +With jubilee, and loud Hosannas filled +The eternal regions: Lowly reverent +Towards either throne they bow, and to the ground +With solemn adoration down they cast +Their crowns inwove with amarant and gold; +Immortal amarant, a flower which once +In Paradise, fast by the tree of life, +Began to bloom; but soon for man's offence +To Heaven removed, where first it grew, there grows, +And flowers aloft shading the fount of life, +And where the river of bliss through midst of Heaven +Rolls o'er Elysian flowers her amber stream; +With these that never fade the Spirits elect +Bind their resplendent locks inwreathed with beams; +Now in loose garlands thick thrown off, the bright +Pavement, that like a sea of jasper shone, +Impurpled with celestial roses smiled. +Then, crowned again, their golden harps they took, +Harps ever tuned, that glittering by their side +Like quivers hung, and with preamble sweet +Of charming symphony they introduce +Their sacred song, and waken raptures high; +No voice exempt, no voice but well could join +Melodious part, such concord is in Heaven. +Thee, Father, first they sung Omnipotent, +Immutable, Immortal, Infinite, +Eternal King; the Author of all being, +Fonntain of light, thyself invisible +Amidst the glorious brightness where thou sit'st +Throned inaccessible, but when thou shadest +The full blaze of thy beams, and, through a cloud +Drawn round about thee like a radiant shrine, +Dark with excessive bright thy skirts appear, +Yet dazzle Heaven, that brightest Seraphim +Approach not, but with both wings veil their eyes. +Thee next they sang of all creation first, +Begotten Son, Divine Similitude, +In whose conspicuous countenance, without cloud +Made visible, the Almighty Father shines, +Whom else no creature can behold; on thee +Impressed the effulgence of his glory abides, +Transfused on thee his ample Spirit rests. +He Heaven of Heavens and all the Powers therein +By thee created; and by thee threw down +The aspiring Dominations: Thou that day +Thy Father's dreadful thunder didst not spare, +Nor stop thy flaming chariot-wheels, that shook +Heaven's everlasting frame, while o'er the necks +Thou drovest of warring Angels disarrayed. +Back from pursuit thy Powers with loud acclaim +Thee only extolled, Son of thy Father's might, +To execute fierce vengeance on his foes, +Not so on Man: Him through their malice fallen, +Father of mercy and grace, thou didst not doom +So strictly, but much more to pity incline: +No sooner did thy dear and only Son +Perceive thee purposed not to doom frail Man +So strictly, but much more to pity inclined, +He to appease thy wrath, and end the strife +Of mercy and justice in thy face discerned, +Regardless of the bliss wherein he sat +Second to thee, offered himself to die +For Man's offence. O unexampled love, +Love no where to be found less than Divine! +Hail, Son of God, Saviour of Men! Thy name +Shall be the copious matter of my song +Henceforth, and never shall my heart thy praise +Forget, nor from thy Father's praise disjoin. +Thus they in Heaven, above the starry sphere, +Their happy hours in joy and hymning spent. +Mean while upon the firm opacous globe +Of this round world, whose first convex divides +The luminous inferiour orbs, enclosed +From Chaos, and the inroad of Darkness old, +Satan alighted walks: A globe far off +It seemed, now seems a boundless continent +Dark, waste, and wild, under the frown of Night +Starless exposed, and ever-threatening storms +Of Chaos blustering round, inclement sky; +Save on that side which from the wall of Heaven, +Though distant far, some small reflection gains +Of glimmering air less vexed with tempest loud: +Here walked the Fiend at large in spacious field. +As when a vultur on Imaus bred, +Whose snowy ridge the roving Tartar bounds, +Dislodging from a region scarce of prey +To gorge the flesh of lambs or yeanling kids, +On hills where flocks are fed, flies toward the springs +Of Ganges or Hydaspes, Indian streams; +But in his way lights on the barren plains +Of Sericana, where Chineses drive +With sails and wind their cany waggons light: +So, on this windy sea of land, the Fiend +Walked up and down alone, bent on his prey; +Alone, for other creature in this place, +Living or lifeless, to be found was none; +None yet, but store hereafter from the earth +Up hither like aereal vapours flew +Of all things transitory and vain, when sin +With vanity had filled the works of men: +Both all things vain, and all who in vain things +Built their fond hopes of glory or lasting fame, +Or happiness in this or the other life; +All who have their reward on earth, the fruits +Of painful superstition and blind zeal, +Nought seeking but the praise of men, here find +Fit retribution, empty as their deeds; +All the unaccomplished works of Nature's hand, +Abortive, monstrous, or unkindly mixed, +Dissolved on earth, fleet hither, and in vain, +Till final dissolution, wander here; +Not in the neighbouring moon as some have dreamed; +Those argent fields more likely habitants, +Translated Saints, or middle Spirits hold +Betwixt the angelical and human kind. +Hither of ill-joined sons and daughters born +First from the ancient world those giants came +With many a vain exploit, though then renowned: +The builders next of Babel on the plain +Of Sennaar, and still with vain design, +New Babels, had they wherewithal, would build: +Others came single; he, who, to be deemed +A God, leaped fondly into Aetna flames, +Empedocles; and he, who, to enjoy +Plato's Elysium, leaped into the sea, +Cleombrotus; and many more too long, +Embryos, and idiots, eremites, and friars +White, black, and gray, with all their trumpery. +Here pilgrims roam, that strayed so far to seek +In Golgotha him dead, who lives in Heaven; +And they, who to be sure of Paradise, +Dying, put on the weeds of Dominick, +Or in Franciscan think to pass disguised; +They pass the planets seven, and pass the fixed, +And that crystalling sphere whose balance weighs +The trepidation talked, and that first moved; +And now Saint Peter at Heaven's wicket seems +To wait them with his keys, and now at foot +Of Heaven's ascent they lift their feet, when lo +A violent cross wind from either coast +Blows them transverse, ten thousand leagues awry +Into the devious air: Then might ye see +Cowls, hoods, and habits, with their wearers, tost +And fluttered into rags; then reliques, beads, +Indulgences, dispenses, pardons, bulls, +The sport of winds: All these, upwhirled aloft, +Fly o'er the backside of the world far off +Into a Limbo large and broad, since called +The Paradise of Fools, to few unknown +Long after; now unpeopled, and untrod. +All this dark globe the Fiend found as he passed, +And long he wandered, till at last a gleam +Of dawning light turned thither-ward in haste +His travelled steps: far distant he descries +Ascending by degrees magnificent +Up to the wall of Heaven a structure high; +At top whereof, but far more rich, appeared +The work as of a kingly palace-gate, +With frontispiece of diamond and gold +Embellished; thick with sparkling orient gems +The portal shone, inimitable on earth +By model, or by shading pencil, drawn. +These stairs were such as whereon Jacob saw +Angels ascending and descending, bands +Of guardians bright, when he from Esau fled +To Padan-Aram, in the field of Luz +Dreaming by night under the open sky +And waking cried, This is the gate of Heaven. +Each stair mysteriously was meant, nor stood +There always, but drawn up to Heaven sometimes +Viewless; and underneath a bright sea flowed +Of jasper, or of liquid pearl, whereon +Who after came from earth, failing arrived +Wafted by Angels, or flew o'er the lake +Rapt in a chariot drawn by fiery steeds. +The stairs were then let down, whether to dare +The Fiend by easy ascent, or aggravate +His sad exclusion from the doors of bliss: +Direct against which opened from beneath, +Just o'er the blissful seat of Paradise, +A passage down to the Earth, a passage wide, +Wider by far than that of after-times +Over mount Sion, and, though that were large, +Over the Promised Land to God so dear; +By which, to visit oft those happy tribes, +On high behests his angels to and fro +Passed frequent, and his eye with choice regard +From Paneas, the fount of Jordan's flood, +To Beersaba, where the Holy Land +Borders on Egypt and the Arabian shore; +So wide the opening seemed, where bounds were set +To darkness, such as bound the ocean wave. +Satan from hence, now on the lower stair, +That scaled by steps of gold to Heaven-gate, +Looks down with wonder at the sudden view +Of all this world at once. As when a scout, +Through dark?;nd desart ways with?oeril gone +All?might,?;t?kast by break of cheerful dawn +Obtains the brow of some high-climbing hill, +Which to his eye discovers unaware +The goodly prospect of some foreign land +First seen, or some renowned metropolis +With glistering spires and pinnacles adorned, +Which now the rising sun gilds with his beams: +Such wonder seised, though after Heaven seen, +The Spirit malign, but much more envy seised, +At sight of all this world beheld so fair. +Round he surveys (and well might, where he stood +So high above the circling canopy +Of night's extended shade,) from eastern point +Of Libra to the fleecy star that bears +Andromeda far off Atlantick seas +Beyond the horizon; then from pole to pole +He views in breadth, and without longer pause +Down right into the world's first region throws +His flight precipitant, and winds with ease +Through the pure marble air his oblique way +Amongst innumerable stars, that shone +Stars distant, but nigh hand seemed other worlds; +Or other worlds they seemed, or happy isles, +Like those Hesperian gardens famed of old, +Fortunate fields, and groves, and flowery vales, +Thrice happy isles; but who dwelt happy there +He staid not to inquire: Above them all +The golden sun, in splendour likest Heaven, +Allured his eye; thither his course he bends +Through the calm firmament, (but up or down, +By center, or eccentrick, hard to tell, +Or longitude,) where the great luminary +Aloof the vulgar constellations thick, +That from his lordly eye keep distance due, +Dispenses light from far; they, as they move +Their starry dance in numbers that compute +Days, months, and years, towards his all-cheering lamp +Turn swift their various motions, or are turned +By his magnetick beam, that gently warms +The universe, and to each inward part +With gentle penetration, though unseen, +Shoots invisible virtue even to the deep; +So wonderously was set his station bright. +There lands the Fiend, a spot like which perhaps +Astronomer in the sun's lucent orb +Through his glazed optick tube yet never saw. +The place he found beyond expression bright, +Compared with aught on earth, metal or stone; +Not all parts like, but all alike informed +With radiant light, as glowing iron with fire; +If metal, part seemed gold, part silver clear; +If stone, carbuncle most or chrysolite, +Ruby or topaz, to the twelve that shone +In Aaron's breast-plate, and a stone besides +Imagined rather oft than elsewhere seen, +That stone, or like to that which here below +Philosophers in vain so long have sought, +In vain, though by their powerful art they bind +Volatile Hermes, and call up unbound +In various shapes old Proteus from the sea, +Drained through a limbeck to his native form. +What wonder then if fields and regions here +Breathe forth Elixir pure, and rivers run +Potable gold, when with one virtuous touch +The arch-chemick sun, so far from us remote, +Produces, with terrestrial humour mixed, +Here in the dark so many precious things +Of colour glorious, and effect so rare? +Here matter new to gaze the Devil met +Undazzled; far and wide his eye commands; +For sight no obstacle found here, nor shade, +But all sun-shine, as when his beams at noon +Culminate from the equator, as they now +Shot upward still direct, whence no way round +Shadow from body opaque can fall; and the air, +No where so clear, sharpened his visual ray +To objects distant far, whereby he soon +Saw within ken a glorious Angel stand, +The same whom John saw also in the sun: +His back was turned, but not his brightness hid; +Of beaming sunny rays a golden tiar +Circled his head, nor less his locks behind +Illustrious on his shoulders fledge with wings +Lay waving round; on some great charge employed +He seemed, or fixed in cogitation deep. +Glad was the Spirit impure, as now in hope +To find who might direct his wandering flight +To Paradise, the happy seat of Man, +His journey's end and our beginning woe. +But first he casts to change his proper shape, +Which else might work him danger or delay: +And now a stripling Cherub he appears, +Not of the prime, yet such as in his face +Youth smiled celestial, and to every limb +Suitable grace diffused, so well he feigned: +Under a coronet his flowing hair +In curls on either cheek played; wings he wore +Of many a coloured plume, sprinkled with gold; +His habit fit for speed succinct, and held +Before his decent steps a silver wand. +He drew not nigh unheard; the Angel bright, +Ere he drew nigh, his radiant visage turned, +Admonished by his ear, and straight was known +The Arch-Angel Uriel, one of the seven +Who in God's presence, nearest to his throne, +Stand ready at command, and are his eyes +That run through all the Heavens, or down to the Earth +Bear his swift errands over moist and dry, +O'er sea and land: him Satan thus accosts. +Uriel, for thou of those seven Spirits that stand +In sight of God's high throne, gloriously bright, +The first art wont his great authentick will +Interpreter through highest Heaven to bring, +Where all his sons thy embassy attend; +And here art likeliest by supreme decree +Like honour to obtain, and as his eye +To visit oft this new creation round; +Unspeakable desire to see, and know +All these his wonderous works, but chiefly Man, +His chief delight and favour, him for whom +All these his works so wonderous he ordained, +Hath brought me from the quires of Cherubim +Alone thus wandering. Brightest Seraph, tell +In which of all these shining orbs hath Man +His fixed seat, or fixed seat hath none, +But all these shining orbs his choice to dwell; +That I may find him, and with secret gaze +Or open admiration him behold, +On whom the great Creator hath bestowed +Worlds, and on whom hath all these graces poured; +That both in him and all things, as is meet, +The universal Maker we may praise; +Who justly hath driven out his rebel foes +To deepest Hell, and, to repair that loss, +Created this new happy race of Men +To serve him better: Wise are all his ways. +So spake the false dissembler unperceived; +For neither Man nor Angel can discern +Hypocrisy, the only evil that walks +Invisible, except to God alone, +By his permissive will, through Heaven and Earth: +And oft, though wisdom wake, suspicion sleeps +At wisdom's gate, and to simplicity +Resigns her charge, while goodness thinks no ill +Where no ill seems: Which now for once beguiled +Uriel, though regent of the sun, and held +The sharpest-sighted Spirit of all in Heaven; +Who to the fraudulent impostor foul, +In his uprightness, answer thus returned. +Fair Angel, thy desire, which tends to know +The works of God, thereby to glorify +The great Work-master, leads to no excess +That reaches blame, but rather merits praise +The more it seems excess, that led thee hither +From thy empyreal mansion thus alone, +To witness with thine eyes what some perhaps, +Contented with report, hear only in Heaven: +For wonderful indeed are all his works, +Pleasant to know, and worthiest to be all +Had in remembrance always with delight; +But what created mind can comprehend +Their number, or the wisdom infinite +That brought them forth, but hid their causes deep? +I saw when at his word the formless mass, +This world's material mould, came to a heap: +Confusion heard his voice, and wild uproar +Stood ruled, stood vast infinitude confined; +Till at his second bidding Darkness fled, +Light shone, and order from disorder sprung: +Swift to their several quarters hasted then +The cumbrous elements, earth, flood, air, fire; +And this ethereal quintessence of Heaven +Flew upward, spirited with various forms, +That rolled orbicular, and turned to stars +Numberless, as thou seest, and how they move; +Each had his place appointed, each his course; +The rest in circuit walls this universe. +Look downward on that globe, whose hither side +With light from hence, though but reflected, shines; +That place is Earth, the seat of Man; that light +His day, which else, as the other hemisphere, +Night would invade; but there the neighbouring moon +So call that opposite fair star) her aid +Timely interposes, and her monthly round +Still ending, still renewing, through mid Heaven, +With borrowed light her countenance triform +Hence fills and empties to enlighten the Earth, +And in her pale dominion checks the night. +That spot, to which I point, is Paradise, +Adam's abode; those lofty shades, his bower. +Thy way thou canst not miss, me mine requires. +Thus said, he turned; and Satan, bowing low, +As to superiour Spirits is wont in Heaven, +Where honour due and reverence none neglects, +Took leave, and toward the coast of earth beneath, +Down from the ecliptick, sped with hoped success, +Throws his steep flight in many an aery wheel; +Nor staid, till on Niphates' top he lights. + + + +Book IV + + +O, for that warning voice, which he, who saw +The Apocalypse, heard cry in Heaven aloud, +Then when the Dragon, put to second rout, +Came furious down to be revenged on men, +Woe to the inhabitants on earth! that now, +While time was, our first parents had been warned +The coming of their secret foe, and 'scaped, +Haply so 'scaped his mortal snare: For now +Satan, now first inflamed with rage, came down, +The tempter ere the accuser of mankind, +To wreak on innocent frail Man his loss +Of that first battle, and his flight to Hell: +Yet, not rejoicing in his speed, though bold +Far off and fearless, nor with cause to boast, +Begins his dire attempt; which nigh the birth +Now rolling boils in his tumultuous breast, +And like a devilish engine back recoils +Upon himself; horrour and doubt distract +His troubled thoughts, and from the bottom stir +The Hell within him; for within him Hell +He brings, and round about him, nor from Hell +One step, no more than from himself, can fly +By change of place: Now conscience wakes despair, +That slumbered; wakes the bitter memory +Of what he was, what is, and what must be +Worse; of worse deeds worse sufferings must ensue. +Sometimes towards Eden, which now in his view +Lay pleasant, his grieved look he fixes sad; +Sometimes towards Heaven, and the full-blazing sun, +Which now sat high in his meridian tower: +Then, much revolving, thus in sighs began. +O thou, that, with surpassing glory crowned, +Lookest from thy sole dominion like the God +Of this new world; at whose sight all the stars +Hide their diminished heads; to thee I call, +But with no friendly voice, and add thy name, +Of Sun! to tell thee how I hate thy beams, +That bring to my remembrance from what state +I fell, how glorious once above thy sphere; +Till pride and worse ambition threw me down +Warring in Heaven against Heaven's matchless King: +Ah, wherefore! he deserved no such return +From me, whom he created what I was +In that bright eminence, and with his good +Upbraided none; nor was his service hard. +What could be less than to afford him praise, +The easiest recompence, and pay him thanks, +How due! yet all his good proved ill in me, +And wrought but malice; lifted up so high +I sdeined subjection, and thought one step higher +Would set me highest, and in a moment quit +The debt immense of endless gratitude, +So burdensome still paying, still to owe, +Forgetful what from him I still received, +And understood not that a grateful mind +By owing owes not, but still pays, at once +Indebted and discharged; what burden then +O, had his powerful destiny ordained +Me some inferiour Angel, I had stood +Then happy; no unbounded hope had raised +Ambition! Yet why not some other Power +As great might have aspired, and me, though mean, +Drawn to his part; but other Powers as great +Fell not, but stand unshaken, from within +Or from without, to all temptations armed. +Hadst thou the same free will and power to stand? +Thou hadst: whom hast thou then or what to accuse, +But Heaven's free love dealt equally to all? +Be then his love accursed, since love or hate, +To me alike, it deals eternal woe. +Nay, cursed be thou; since against his thy will +Chose freely what it now so justly rues. +Me miserable! which way shall I fly +Infinite wrath, and infinite despair? +Which way I fly is Hell; myself am Hell; +And, in the lowest deep, a lower deep +Still threatening to devour me opens wide, +To which the Hell I suffer seems a Heaven. +O, then, at last relent: Is there no place +Left for repentance, none for pardon left? +None left but by submission; and that word +Disdain forbids me, and my dread of shame +Among the Spirits beneath, whom I seduced +With other promises and other vaunts +Than to submit, boasting I could subdue +The Omnipotent. Ay me! they little know +How dearly I abide that boast so vain, +Under what torments inwardly I groan, +While they adore me on the throne of Hell. +With diadem and scepter high advanced, +The lower still I fall, only supreme +In misery: Such joy ambition finds. +But say I could repent, and could obtain, +By act of grace, my former state; how soon +Would highth recall high thoughts, how soon unsay +What feigned submission swore? Ease would recant +Vows made in pain, as violent and void. +For never can true reconcilement grow, +Where wounds of deadly hate have pierced so deep: +Which would but lead me to a worse relapse +And heavier fall: so should I purchase dear +Short intermission bought with double smart. +This knows my Punisher; therefore as far +From granting he, as I from begging, peace; +All hope excluded thus, behold, in stead +Mankind created, and for him this world. +So farewell, hope; and with hope farewell, fear; +Farewell, remorse! all good to me is lost; +Evil, be thou my good; by thee at least +Divided empire with Heaven's King I hold, +By thee, and more than half perhaps will reign; +As Man ere long, and this new world, shall know. +Thus while he spake, each passion dimmed his face +Thrice changed with pale, ire, envy, and despair; +Which marred his borrowed visage, and betrayed +Him counterfeit, if any eye beheld. +For heavenly minds from such distempers foul +Are ever clear. Whereof he soon aware, +Each perturbation smoothed with outward calm, +Artificer of fraud; and was the first +That practised falsehood under saintly show, +Deep malice to conceal, couched with revenge: +Yet not enough had practised to deceive +Uriel once warned; whose eye pursued him down + The way he went, and on the Assyrian mount + Saw him disfigured, more than could befall + Spirit of happy sort; his gestures fierce + He marked and mad demeanour, then alone, + As he supposed, all unobserved, unseen. + So on he fares, and to the border comes + Of Eden, where delicious Paradise, + Now nearer, crowns with her enclosure green, + As with a rural mound, the champaign head + Of a steep wilderness, whose hairy sides +Access denied; and overhead upgrew + Insuperable height of loftiest shade, + Cedar, and pine, and fir, and branching palm, + A sylvan scene, and, as the ranks ascend, + Shade above shade, a woody theatre + Of stateliest view. Yet higher than their tops + The verdurous wall of Paradise upsprung; + + 00081429 +Which to our general sire gave prospect large +Into his nether empire neighbouring round. +And higher than that wall a circling row +Of goodliest trees, loaden with fairest fruit, +Blossoms and fruits at once of golden hue, +Appeared, with gay enamelled colours mixed: +On which the sun more glad impressed his beams +Than in fair evening cloud, or humid bow, +When God hath showered the earth; so lovely seemed +That landskip: And of pure now purer air +Meets his approach, and to the heart inspires +Vernal delight and joy, able to drive +All sadness but despair: Now gentle gales, +Fanning their odoriferous wings, dispense +Native perfumes, and whisper whence they stole +Those balmy spoils. As when to them who fail +Beyond the Cape of Hope, and now are past +Mozambick, off at sea north-east winds blow +Sabean odours from the spicy shore +Of Araby the blest; with such delay +Well pleased they slack their course, and many a league +Cheered with the grateful smell old Ocean smiles: +So entertained those odorous sweets the Fiend, +Who came their bane; though with them better pleased +Than Asmodeus with the fishy fume +That drove him, though enamoured, from the spouse +Of Tobit's son, and with a vengeance sent +From Media post to Egypt, there fast bound. +Now to the ascent of that steep savage hill +Satan had journeyed on, pensive and slow; +But further way found none, so thick entwined, +As one continued brake, the undergrowth +Of shrubs and tangling bushes had perplexed +All path of man or beast that passed that way. +One gate there only was, and that looked east +On the other side: which when the arch-felon saw, +Due entrance he disdained; and, in contempt, +At one flight bound high over-leaped all bound +Of hill or highest wall, and sheer within +Lights on his feet. As when a prowling wolf, +Whom hunger drives to seek new haunt for prey, +Watching where shepherds pen their flocks at eve +In hurdled cotes amid the field secure, +Leaps o'er the fence with ease into the fold: +Or as a thief, bent to unhoard the cash +Of some rich burgher, whose substantial doors, +Cross-barred and bolted fast, fear no assault, +In at the window climbs, or o'er the tiles: +So clomb this first grand thief into God's fold; +So since into his church lewd hirelings climb. +Thence up he flew, and on the tree of life, +The middle tree and highest there that grew, +Sat like a cormorant; yet not true life +Thereby regained, but sat devising death +To them who lived; nor on the virtue thought +Of that life-giving plant, but only used +For prospect, what well used had been the pledge +Of immortality. So little knows +Any, but God alone, to value right +The good before him, but perverts best things +To worst abuse, or to their meanest use. +Beneath him with new wonder now he views, +To all delight of human sense exposed, +In narrow room, Nature's whole wealth, yea more, +A Heaven on Earth: For blissful Paradise +Of God the garden was, by him in the east +Of Eden planted; Eden stretched her line +From Auran eastward to the royal towers +Of great Seleucia, built by Grecian kings, +Of where the sons of Eden long before +Dwelt in Telassar: In this pleasant soil +His far more pleasant garden God ordained; +Out of the fertile ground he caused to grow +All trees of noblest kind for sight, smell, taste; +And all amid them stood the tree of life, +High eminent, blooming ambrosial fruit +Of vegetable gold; and next to life, +Our death, the tree of knowledge, grew fast by, +Knowledge of good bought dear by knowing ill. +Southward through Eden went a river large, +Nor changed his course, but through the shaggy hill +Passed underneath ingulfed; for God had thrown +That mountain as his garden-mould high raised +Upon the rapid current, which, through veins +Of porous earth with kindly thirst up-drawn, +Rose a fresh fountain, and with many a rill +Watered the garden; thence united fell +Down the steep glade, and met the nether flood, +Which from his darksome passage now appears, +And now, divided into four main streams, +Runs diverse, wandering many a famous realm +And country, whereof here needs no account; +But rather to tell how, if Art could tell, +How from that sapphire fount the crisped brooks, +Rolling on orient pearl and sands of gold, +With mazy errour under pendant shades +Ran nectar, visiting each plant, and fed +Flowers worthy of Paradise, which not nice Art +In beds and curious knots, but Nature boon +Poured forth profuse on hill, and dale, and plain, +Both where the morning sun first warmly smote +The open field, and where the unpierced shade +Imbrowned the noontide bowers: Thus was this place +A happy rural seat of various view; +Groves whose rich trees wept odorous gums and balm, +Others whose fruit, burnished with golden rind, +Hung amiable, Hesperian fables true, +If true, here only, and of delicious taste: +Betwixt them lawns, or level downs, and flocks +Grazing the tender herb, were interposed, +Or palmy hillock; or the flowery lap +Of some irriguous valley spread her store, +Flowers of all hue, and without thorn the rose: +Another side, umbrageous grots and caves +Of cool recess, o'er which the mantling vine +Lays forth her purple grape, and gently creeps +Luxuriant; mean while murmuring waters fall +Down the slope hills, dispersed, or in a lake, +That to the fringed bank with myrtle crowned +Her crystal mirrour holds, unite their streams. +The birds their quire apply; airs, vernal airs, +Breathing the smell of field and grove, attune +The trembling leaves, while universal Pan, +Knit with the Graces and the Hours in dance, +Led on the eternal Spring. Not that fair field +Of Enna, where Proserpine gathering flowers, +Herself a fairer flower by gloomy Dis +Was gathered, which cost Ceres all that pain +To seek her through the world; nor that sweet grove +Of Daphne by Orontes, and the inspired +Castalian spring, might with this Paradise +Of Eden strive; nor that Nyseian isle +Girt with the river Triton, where old Cham, +Whom Gentiles Ammon call and Libyan Jove, +Hid Amalthea, and her florid son +Young Bacchus, from his stepdame Rhea's eye; +Nor where Abassin kings their issue guard, +Mount Amara, though this by some supposed +True Paradise under the Ethiop line +By Nilus' head, enclosed with shining rock, +A whole day's journey high, but wide remote +From this Assyrian garden, where the Fiend +Saw, undelighted, all delight, all kind +Of living creatures, new to sight, and strange +Two of far nobler shape, erect and tall, +Godlike erect, with native honour clad +In naked majesty seemed lords of all: +And worthy seemed; for in their looks divine +The image of their glorious Maker shone, +Truth, wisdom, sanctitude severe and pure, +(Severe, but in true filial freedom placed,) +Whence true authority in men; though both +Not equal, as their sex not equal seemed; +For contemplation he and valour formed; +For softness she and sweet attractive grace; +He for God only, she for God in him: +His fair large front and eye sublime declared +Absolute rule; and hyacinthine locks +Round from his parted forelock manly hung +Clustering, but not beneath his shoulders broad: +She, as a veil, down to the slender waist +Her unadorned golden tresses wore +Dishevelled, but in wanton ringlets waved +As the vine curls her tendrils, which implied +Subjection, but required with gentle sway, +And by her yielded, by him best received, +Yielded with coy submission, modest pride, +And sweet, reluctant, amorous delay. +Nor those mysterious parts were then concealed; +Then was not guilty shame, dishonest shame +Of nature's works, honour dishonourable, +Sin-bred, how have ye troubled all mankind +With shows instead, mere shows of seeming pure, +And banished from man's life his happiest life, +Simplicity and spotless innocence! +So passed they naked on, nor shunned the sight +Of God or Angel; for they thought no ill: +So hand in hand they passed, the loveliest pair, +That ever since in love's embraces met; +Adam the goodliest man of men since born +His sons, the fairest of her daughters Eve. +Under a tuft of shade that on a green +Stood whispering soft, by a fresh fountain side +They sat them down; and, after no more toil +Of their sweet gardening labour than sufficed +To recommend cool Zephyr, and made ease +More easy, wholesome thirst and appetite +More grateful, to their supper-fruits they fell, +Nectarine fruits which the compliant boughs +Yielded them, side-long as they sat recline +On the soft downy bank damasked with flowers: +The savoury pulp they chew, and in the rind, +Still as they thirsted, scoop the brimming stream; +Nor gentle purpose, nor endearing smiles +Wanted, nor youthful dalliance, as beseems +Fair couple, linked in happy nuptial league, +Alone as they. About them frisking played +All beasts of the earth, since wild, and of all chase +In wood or wilderness, forest or den; +Sporting the lion ramped, and in his paw +Dandled the kid; bears, tigers, ounces, pards, +Gambolled before them; the unwieldy elephant, +To make them mirth, used all his might, and wreathed +His?kithetmroboscis; close the serpent sly, +Insinuating, wove with Gordian twine +His braided train, and of his fatal guile +Gave proof unheeded; others on the grass +Couched, and now filled with pasture gazing sat, +Or bedward ruminating; for the sun, +Declined, was hasting now with prone career +To the ocean isles, and in the ascending scale +Of Heaven the stars that usher evening rose: +When Satan still in gaze, as first he stood, +Scarce thus at length failed speech recovered sad. +O Hell! what do mine eyes with grief behold! +Into our room of bliss thus high advanced +Creatures of other mould, earth-born perhaps, +Not Spirits, yet to heavenly Spirits bright +Little inferiour; whom my thoughts pursue +With wonder, and could love, so lively shines +In them divine resemblance, and such grace +The hand that formed them on their shape hath poured. +Ah! gentle pair, ye little think how nigh +Your change approaches, when all these delights +Will vanish, and deliver ye to woe; +More woe, the more your taste is now of joy; +Happy, but for so happy ill secured +Long to continue, and this high seat your Heaven +Ill fenced for Heaven to keep out such a foe +As now is entered; yet no purposed foe +To you, whom I could pity thus forlorn, +Though I unpitied: League with you I seek, +And mutual amity, so strait, so close, +That I with you must dwell, or you with me +Henceforth; my dwelling haply may not please, +Like this fair Paradise, your sense; yet such +Accept your Maker's work; he gave it me, +Which I as freely give: Hell shall unfold, +To entertain you two, her widest gates, +And send forth all her kings; there will be room, +Not like these narrow limits, to receive +Your numerous offspring; if no better place, +Thank him who puts me loth to this revenge +On you who wrong me not for him who wronged. +And should I at your harmless innocence +Melt, as I do, yet publick reason just, +Honour and empire with revenge enlarged, +By conquering this new world, compels me now +To do what else, though damned, I should abhor. +So spake the Fiend, and with necessity, +The tyrant's plea, excused his devilish deeds. +Then from his lofty stand on that high tree +Down he alights among the sportful herd +Of those four-footed kinds, himself now one, +Now other, as their shape served best his end +Nearer to view his prey, and, unespied, +To mark what of their state he more might learn, +By word or action marked. About them round +A lion now he stalks with fiery glare; +Then as a tiger, who by chance hath spied +In some purlieu two gentle fawns at play, +Straight couches close, then, rising, changes oft +His couchant watch, as one who chose his ground, +Whence rushing, he might surest seize them both, +Griped in each paw: when, Adam first of men +To first of women Eve thus moving speech, +Turned him, all ear to hear new utterance flow. +Sole partner, and sole part, of all these joys, +Dearer thyself than all; needs must the Power +That made us, and for us this ample world, +Be infinitely good, and of his good +As liberal and free as infinite; +That raised us from the dust, and placed us here +In all this happiness, who at his hand +Have nothing merited, nor can perform +Aught whereof he hath need; he who requires +From us no other service than to keep +This one, this easy charge, of all the trees +In Paradise that bear delicious fruit +So various, not to taste that only tree +Of knowledge, planted by the tree of life; +So near grows death to life, whate'er death is, +Some dreadful thing no doubt; for well thou knowest +God hath pronounced it death to taste that tree, +The only sign of our obedience left, +Among so many signs of power and rule +Conferred upon us, and dominion given +Over all other creatures that possess +Earth, air, and sea. Then let us not think hard +One easy prohibition, who enjoy +Free leave so large to all things else, and choice +Unlimited of manifold delights: +But let us ever praise him, and extol +His bounty, following our delightful task, +To prune these growing plants, and tend these flowers, +Which were it toilsome, yet with thee were sweet. +To whom thus Eve replied. O thou for whom +And from whom I was formed, flesh of thy flesh, +And without whom am to no end, my guide +And head! what thou hast said is just and right. +For we to him indeed all praises owe, +And daily thanks; I chiefly, who enjoy +So far the happier lot, enjoying thee +Pre-eminent by so much odds, while thou +Like consort to thyself canst no where find. +That day I oft remember, when from sleep +I first awaked, and found myself reposed +Under a shade on flowers, much wondering where +And what I was, whence thither brought, and how. +Not distant far from thence a murmuring sound +Of waters issued from a cave, and spread +Into a liquid plain, then stood unmoved +Pure as the expanse of Heaven; I thither went +With unexperienced thought, and laid me down +On the green bank, to look into the clear +Smooth lake, that to me seemed another sky. +As I bent down to look, just opposite +A shape within the watery gleam appeared, +Bending to look on me: I started back, +It started back; but pleased I soon returned, +Pleased it returned as soon with answering looks +Of sympathy and love: There I had fixed +Mine eyes till now, and pined with vain desire, +Had not a voice thus warned me; 'What thou seest, +'What there thou seest, fair Creature, is thyself; +'With thee it came and goes: but follow me, +'And I will bring thee where no shadow stays +'Thy coming, and thy soft embraces, he +'Whose image thou art; him thou shalt enjoy +'Inseparably thine, to him shalt bear +'Multitudes like thyself, and thence be called +'Mother of human race.' What could I do, +But follow straight, invisibly thus led? +Till I espied thee, fair indeed and tall, +Under a platane; yet methought less fair, +Less winning soft, less amiably mild, +Than that smooth watery image: Back I turned; +Thou following cryedst aloud, 'Return, fair Eve; +'Whom flyest thou? whom thou flyest, of him thou art, +'His flesh, his bone; to give thee being I lent +'Out of my side to thee, nearest my heart, +'Substantial life, to have thee by my side +'Henceforth an individual solace dear; +'Part of my soul I seek thee, and thee claim +'My other half:' With that thy gentle hand +Seised mine: I yielded;and from that time see +How beauty is excelled by manly grace, +And wisdom, which alone is truly fair. +So spake our general mother, and with eyes +Of conjugal attraction unreproved, +And meek surrender, half-embracing leaned +On our first father; half her swelling breast +Naked met his, under the flowing gold +Of her loose tresses hid: he in delight +Both of her beauty, and submissive charms, +Smiled with superiour love, as Jupiter +On Juno smiles, when he impregns the clouds +That shed Mayflowers; and pressed her matron lip +With kisses pure: Aside the Devil turned +For envy; yet with jealous leer malign +Eyed them askance, and to himself thus plained. +Sight hateful, sight tormenting! thus these two, +Imparadised in one another's arms, +The happier Eden, shall enjoy their fill +Of bliss on bliss; while I to Hell am thrust, +Where neither joy nor love, but fierce desire, +Among our other torments not the least, +Still unfulfilled with pain of longing pines. +Yet let me not forget what I have gained +From their own mouths: All is not theirs, it seems; +One fatal tree there stands, of knowledge called, +Forbidden them to taste: Knowledge forbidden +Suspicious, reasonless. Why should their Lord +Envy them that? Can it be sin to know? +Can it be death? And do they only stand +By ignorance? Is that their happy state, +The proof of their obedience and their faith? +O fair foundation laid whereon to build +Their ruin! hence I will excite their minds +With more desire to know, and to reject +Envious commands, invented with design +To keep them low, whom knowledge might exalt +Equal with Gods: aspiring to be such, +They taste and die: What likelier can ensue +But first with narrow search I must walk round +This garden, and no corner leave unspied; +A chance but chance may lead where I may meet +Some wandering Spirit of Heaven by fountain side, +Or in thick shade retired, from him to draw +What further would be learned. Live while ye may, +Yet happy pair; enjoy, till I return, +Short pleasures, for long woes are to succeed! +So saying, his proud step he scornful turned, +But with sly circumspection, and began +Through wood, through waste, o'er hill, o'er dale, his roam +Mean while in utmost longitude, where Heaven +With earth and ocean meets, the setting sun +Slowly descended, and with right aspect +Against the eastern gate of Paradise +Levelled his evening rays: It was a rock +Of alabaster, piled up to the clouds, +Conspicuous far, winding with one ascent +Accessible from earth, one entrance high; +The rest was craggy cliff, that overhung +Still as it rose, impossible to climb. +Betwixt these rocky pillars Gabriel sat, +Chief of the angelick guards, awaiting night; +About him exercised heroick games +The unarmed youth of Heaven, but nigh at hand +Celestial armoury, shields, helms, and spears, +Hung high with diamond flaming, and with gold. +Thither came Uriel, gliding through the even +On a sun-beam, swift as a shooting star +In autumn thwarts the night, when vapours fired +Impress the air, and shows the mariner +From what point of his compass to beware +Impetuous winds: He thus began in haste. +Gabriel, to thee thy course by lot hath given +Charge and strict watch, that to this happy place +No evil thing approach or enter in. +This day at highth of noon came to my sphere +A Spirit, zealous, as he seemed, to know +More of the Almighty's works, and chiefly Man, +God's latest image: I described his way +Bent all on speed, and marked his aery gait; +But in the mount that lies from Eden north, +Where he first lighted, soon discerned his looks +Alien from Heaven, with passions foul obscured: +Mine eye pursued him still, but under shade +Lost sight of him: One of the banished crew, +I fear, hath ventured from the deep, to raise +New troubles; him thy care must be to find. +To whom the winged warriour thus returned. +Uriel, no wonder if thy perfect sight, +Amid the sun's bright circle where thou sitst, +See far and wide: In at this gate none pass +The vigilance here placed, but such as come +Well known from Heaven; and since meridian hour +No creature thence: If Spirit of other sort, +So minded, have o'er-leaped these earthly bounds +On purpose, hard thou knowest it to exclude +Spiritual substance with corporeal bar. +But if within the circuit of these walks, +In whatsoever shape he lurk, of whom +Thou tellest, by morrow dawning I shall know. +So promised he; and Uriel to his charge +Returned on that bright beam, whose point now raised +Bore him slope downward to the sun now fallen +Beneath the Azores; whether the prime orb, +Incredible how swift, had thither rolled +Diurnal, or this less volubil earth, +By shorter flight to the east, had left him there +Arraying with reflected purple and gold +The clouds that on his western throne attend. +Now came still Evening on, and Twilight gray +Had in her sober livery all things clad; +Silence accompanied; for beast and bird, +They to their grassy couch, these to their nests +Were slunk, all but the wakeful nightingale; +She all night long her amorous descant sung; +Silence was pleased: Now glowed the firmament +With living sapphires: Hesperus, that led +The starry host, rode brightest, till the moon, +Rising in clouded majesty, at length +Apparent queen unveiled her peerless light, +And o'er the dark her silver mantle threw. +When Adam thus to Eve. Fair Consort, the hour +Of night, and all things now retired to rest, +Mind us of like repose; since God hath set +Labour and rest, as day and night, to men +Successive; and the timely dew of sleep, +Now falling with soft slumbrous weight, inclines +Our eye-lids: Other creatures all day long +Rove idle, unemployed, and less need rest; +Man hath his daily work of body or mind +Appointed, which declares his dignity, +And the regard of Heaven on all his ways; +While other animals unactive range, +And of their doings God takes no account. +To-morrow, ere fresh morning streak the east +With first approach of light, we must be risen, +And at our pleasant labour, to reform +Yon flowery arbours, yonder alleys green, +Our walk at noon, with branches overgrown, +That mock our scant manuring, and require +More hands than ours to lop their wanton growth: +Those blossoms also, and those dropping gums, +That lie bestrown, unsightly and unsmooth, +Ask riddance, if we mean to tread with ease; +Mean while, as Nature wills, night bids us rest. +To whom thus Eve, with perfect beauty adorned +My Author and Disposer, what thou bidst +Unargued I obey: So God ordains; +God is thy law, thou mine: To know no more +Is woman's happiest knowledge, and her praise. +With thee conversing I forget all time; +All seasons, and their change, all please alike. +Sweet is the breath of Morn, her rising sweet, +With charm of earliest birds: pleasant the sun, +When first on this delightful land he spreads +His orient beams, on herb, tree, fruit, and flower, +Glistering with dew; fragrant the fertile earth +After soft showers; and sweet the coming on +Of grateful Evening mild; then silent Night, +With this her solemn bird, and this fair moon, +And these the gems of Heaven, her starry train: +But neither breath of Morn, when she ascends +With charm of earliest birds; nor rising sun +On this delightful land; nor herb, fruit, flower, +Glistering with dew; nor fragrance after showers; +Nor grateful Evening mild; nor silent Night, +With this her solemn bird, nor walk by moon, +Or glittering star-light, without thee is sweet. +But wherefore all night long shine these? for whom +This glorious sight, when sleep hath shut all eyes? +To whom our general ancestor replied. +Daughter of God and Man, accomplished Eve, +These have their course to finish round the earth, +By morrow evening, and from land to land +In order, though to nations yet unborn, +Ministring light prepared, they set and rise; +Lest total Darkness should by night regain +Her old possession, and extinguish life +In Nature and all things; which these soft fires +Not only enlighten, but with kindly heat +Of various influence foment and warm, +Temper or nourish, or in part shed down +Their stellar virtue on all kinds that grow +On earth, made hereby apter to receive +Perfection from the sun's more potent ray. +These then, though unbeheld in deep of night, +Shine not in vain; nor think, though men were none, +That Heaven would want spectators, God want praise: +Millions of spiritual creatures walk the earth +Unseen, both when we wake, and when we sleep: +All these with ceaseless praise his works behold +Both day and night: How often from the steep +Of echoing hill or thicket have we heard +Celestial voices to the midnight air, +Sole, or responsive each to others note, +Singing their great Creator? oft in bands +While they keep watch, or nightly rounding walk, +With heavenly touch of instrumental sounds +In full harmonick number joined, their songs +Divide the night, and lift our thoughts to Heaven. +Thus talking, hand in hand alone they passed +On to their blissful bower: it was a place +Chosen by the sovran Planter, when he framed +All things to Man's delightful use; the roof +Of thickest covert was inwoven shade +Laurel and myrtle, and what higher grew +Of firm and fragrant leaf; on either side +Acanthus, and each odorous bushy shrub, +Fenced up the verdant wall; each beauteous flower, +Iris all hues, roses, and jessamin, +Reared high their flourished heads between, and wrought +Mosaick; underfoot the violet, +Crocus, and hyacinth, with rich inlay +Broidered the ground, more coloured than with stone +Of costliest emblem: Other creature here, +Bird, beast, insect, or worm, durst enter none, +Such was their awe of Man. In shadier bower +More sacred and sequestered, though but feigned, +Pan or Sylvanus never slept, nor Nymph +Nor Faunus haunted. Here, in close recess, +With flowers, garlands, and sweet-smelling herbs, +Espoused Eve decked first her nuptial bed; +And heavenly quires the hymenaean sung, +What day the genial Angel to our sire +Brought her in naked beauty more adorned, +More lovely, than Pandora, whom the Gods +Endowed with all their gifts, and O! too like +In sad event, when to the unwiser son +Of Japhet brought by Hermes, she ensnared +Mankind with her fair looks, to be avenged +On him who had stole Jove's authentick fire. +Thus, at their shady lodge arrived, both stood, +Both turned, and under open sky adored +The God that made both sky, air, earth, and heaven, +Which they beheld, the moon's resplendent globe, +And starry pole: Thou also madest the night, +Maker Omnipotent, and thou the day, +Which we, in our appointed work employed, +Have finished, happy in our mutual help +And mutual love, the crown of all our bliss +Ordained by thee; and this delicious place +For us too large, where thy abundance wants +Partakers, and uncropt falls to the ground. +But thou hast promised from us two a race +To fill the earth, who shall with us extol +Thy goodness infinite, both when we wake, +And when we seek, as now, thy gift of sleep. +This said unanimous, and other rites +Observing none, but adoration pure +Which God likes best, into their inmost bower +Handed they went; and, eased the putting off +These troublesome disguises which we wear, +Straight side by side were laid; nor turned, I ween, +Adam from his fair spouse, nor Eve the rites +Mysterious of connubial love refused: +Whatever hypocrites austerely talk +Of purity, and place, and innocence, +Defaming as impure what God declares +Pure, and commands to some, leaves free to all. +Our Maker bids encrease; who bids abstain +But our Destroyer, foe to God and Man? +Hail, wedded Love, mysterious law, true source +Of human offspring, sole propriety +In Paradise of all things common else! +By thee adulterous Lust was driven from men +Among the bestial herds to range; by thee +Founded in reason, loyal, just, and pure, +Relations dear, and all the charities +Of father, son, and brother, first were known. +Far be it, that I should write thee sin or blame, +Or think thee unbefitting holiest place, +Perpetual fountain of domestick sweets, +Whose bed is undefiled and chaste pronounced, +Present, or past, as saints and patriarchs used. +Here Love his golden shafts employs, here lights +His constant lamp, and waves his purple wings, +Reigns here and revels; not in the bought smile +Of harlots, loveless, joyless, unendeared, +Casual fruition; nor in court-amours, +Mixed dance, or wanton mask, or midnight ball, +Or serenate, which the starved lover sings +To his proud fair, best quitted with disdain. +These, lulled by nightingales, embracing slept, +And on their naked limbs the flowery roof +Showered roses, which the morn repaired. Sleep on, +Blest pair; and O!yet happiest, if ye seek +No happier state, and know to know no more. +Now had night measured with her shadowy cone +Half way up hill this vast sublunar vault, +And from their ivory port the Cherubim, +Forth issuing at the accustomed hour, stood armed +To their night watches in warlike parade; +When Gabriel to his next in power thus spake. +Uzziel, half these draw off, and coast the south +With strictest watch; these other wheel the north; +Our circuit meets full west. As flame they part, +Half wheeling to the shield, half to the spear. +From these, two strong and subtle Spirits he called +That near him stood, and gave them thus in charge. +Ithuriel and Zephon, with winged speed +Search through this garden, leave unsearched no nook; +But chiefly where those two fair creatures lodge, +Now laid perhaps asleep, secure of harm. +This evening from the sun's decline arrived, +Who tells of some infernal Spirit seen +Hitherward bent (who could have thought?) escaped +The bars of Hell, on errand bad no doubt: +Such, where ye find, seise fast, and hither bring. +So saying, on he led his radiant files, +Dazzling the moon; these to the bower direct +In search of whom they sought: Him there they found +Squat like a toad, close at the ear of Eve, +Assaying by his devilish art to reach +The organs of her fancy, and with them forge +Illusions, as he list, phantasms and dreams; +Or if, inspiring venom, he might taint +The animal spirits, that from pure blood arise +Like gentle breaths from rivers pure, thence raise +At least distempered, discontented thoughts, +Vain hopes, vain aims, inordinate desires, +Blown up with high conceits ingendering pride. +Him thus intent Ithuriel with his spear +Touched lightly; for no falshood can endure +Touch of celestial temper, but returns +Of force to its own likeness: Up he starts +Discovered and surprised. As when a spark +Lights on a heap of nitrous powder, laid +Fit for the tun some magazine to store +Against a rumoured war, the smutty grain, +With sudden blaze diffused, inflames the air; +So started up in his own shape the Fiend. +Back stept those two fair Angels, half amazed +So sudden to behold the grisly king; +Yet thus, unmoved with fear, accost him soon. +Which of those rebel Spirits adjudged to Hell +Comest thou, escaped thy prison? and, transformed, +Why sat'st thou like an enemy in wait, +Here watching at the head of these that sleep? +Know ye not then said Satan, filled with scorn, +Know ye not me? ye knew me once no mate +For you, there sitting where ye durst not soar: +Not to know me argues yourselves unknown, +The lowest of your throng; or, if ye know, +Why ask ye, and superfluous begin +Your message, like to end as much in vain? +To whom thus Zephon, answering scorn with scorn. +Think not, revolted Spirit, thy shape the same, +Or undiminished brightness to be known, +As when thou stoodest in Heaven upright and pure; +That glory then, when thou no more wast good, +Departed from thee; and thou resemblest now +Thy sin and place of doom obscure and foul. +But come, for thou, be sure, shalt give account +To him who sent us, whose charge is to keep +This place inviolable, and these from harm. +So spake the Cherub; and his grave rebuke, +Severe in youthful beauty, added grace +Invincible: Abashed the Devil stood, +And felt how awful goodness is, and saw +Virtue in her shape how lovely; saw, and pined +His loss; but chiefly to find here observed +His lustre visibly impaired; yet seemed +Undaunted. If I must contend, said he, +Best with the best, the sender, not the sent, +Or all at once; more glory will be won, +Or less be lost. Thy fear, said Zephon bold, +Will save us trial what the least can do +Single against thee wicked, and thence weak. +The Fiend replied not, overcome with rage; +But, like a proud steed reined, went haughty on, +Champing his iron curb: To strive or fly +He held it vain; awe from above had quelled +His heart, not else dismayed. Now drew they nigh +The western point, where those half-rounding guards +Just met, and closing stood in squadron joined, +A waiting next command. To whom their Chief, +Gabriel, from the front thus called aloud. +O friends! I hear the tread of nimble feet +Hasting this way, and now by glimpse discern +Ithuriel and Zephon through the shade; +And with them comes a third of regal port, +But faded splendour wan; who by his gait +And fierce demeanour seems the Prince of Hell, +Not likely to part hence without contest; +Stand firm, for in his look defiance lours. +He scarce had ended, when those two approached, +And brief related whom they brought, where found, +How busied, in what form and posture couched. +To whom with stern regard thus Gabriel spake. +Why hast thou, Satan, broke the bounds prescribed +To thy transgressions, and disturbed the charge +Of others, who approve not to transgress +By thy example, but have power and right +To question thy bold entrance on this place; +Employed, it seems, to violate sleep, and those +Whose dwelling God hath planted here in bliss! +To whom thus Satan with contemptuous brow. +Gabriel? thou hadst in Heaven the esteem of wise, +And such I held thee; but this question asked +Puts me in doubt. Lives there who loves his pain! +Who would not, finding way, break loose from Hell, +Though thither doomed! Thou wouldst thyself, no doubt +And boldly venture to whatever place +Farthest from pain, where thou mightst hope to change +Torment with ease, and soonest recompense +Dole with delight, which in this place I sought; +To thee no reason, who knowest only good, +But evil hast not tried: and wilt object +His will who bounds us! Let him surer bar +His iron gates, if he intends our stay +In that dark durance: Thus much what was asked. +The rest is true, they found me where they say; +But that implies not violence or harm. +Thus he in scorn. The warlike Angel moved, +Disdainfully half smiling, thus replied. +O loss of one in Heaven to judge of wise +Since Satan fell, whom folly overthrew, +And now returns him from his prison 'scaped, +Gravely in doubt whether to hold them wise +Or not, who ask what boldness brought him hither +Unlicensed from his bounds in Hell prescribed; +So wise he judges it to fly from pain +However, and to 'scape his punishment! +So judge thou still, presumptuous! till the wrath, +Which thou incurrest by flying, meet thy flight +Sevenfold, and scourge that wisdom back to Hell, +Which taught thee yet no better, that no pain +Can equal anger infinite provoked. +But wherefore thou alone? wherefore with thee +Came not all hell broke loose? or thou than they +Less hardy to endure? Courageous Chief! +The first in flight from pain! hadst thou alleged +To thy deserted host this cause of flight, +Thou surely hadst not come sole fugitive. +To which the Fiend thus answered, frowning stern. +Not that I less endure, or shrink from pain, +Insulting Angel! well thou knowest I stood +Thy fiercest, when in battle to thy aid +The blasting vollied thunder made all speed, +And seconded thy else not dreaded spear. +But still thy words at random, as before, +Argue thy inexperience what behoves +From hard assays and ill successes past +A faithful leader, not to hazard all +Through ways of danger by himself untried: +I, therefore, I alone first undertook +To wing the desolate abyss, and spy +This new created world, whereof in Hell +Fame is not silent, here in hope to find +Better abode, and my afflicted Powers +To settle here on earth, or in mid air; +Though for possession put to try once more +What thou and thy gay legions dare against; +Whose easier business were to serve their Lord +High up in Heaven, with songs to hymn his throne, +And practised distances to cringe, not fight, +To whom the warriour Angel soon replied. +To say and straight unsay, pretending first +Wise to fly pain, professing next the spy, +Argues no leader but a liear traced, +Satan, and couldst thou faithful add? O name, +O sacred name of faithfulness profaned! +Faithful to whom? to thy rebellious crew? +Army of Fiends, fit body to fit head. +Was this your discipline and faith engaged, +Your military obedience, to dissolve +Allegiance to the acknowledged Power supreme? +And thou, sly hypocrite, who now wouldst seem +Patron of liberty, who more than thou +Once fawned, and cringed, and servily adored +Heaven's awful Monarch? wherefore, but in hope +To dispossess him, and thyself to reign? +But mark what I arreed thee now, Avant; +Fly neither whence thou fledst! If from this hour +Within these hallowed limits thou appear, +Back to the infernal pit I drag thee chained, +And seal thee so, as henceforth not to scorn +The facile gates of Hell too slightly barred. +So threatened he; but Satan to no threats +Gave heed, but waxing more in rage replied. +Then when I am thy captive talk of chains, +Proud limitary Cherub! but ere then +Far heavier load thyself expect to feel +From my prevailing arm, though Heaven's King +Ride on thy wings, and thou with thy compeers, +Us'd to the yoke, drawest his triumphant wheels +In progress through the road of Heaven star-paved. +While thus he spake, the angelick squadron bright +Turned fiery red, sharpening in mooned horns +Their phalanx, and began to hem him round +With ported spears, as thick as when a field +Of Ceres ripe for harvest waving bends +Her bearded grove of ears, which way the wind +Sways them; the careful plowman doubting stands, +Left on the threshing floor his hopeless sheaves +Prove chaff. On the other side, Satan, alarmed, +Collecting all his might, dilated stood, +Like Teneriff or Atlas, unremoved: +His stature reached the sky, and on his crest +Sat Horrour plumed; nor wanted in his grasp +What seemed both spear and shield: Now dreadful deeds +Might have ensued, nor only Paradise +In this commotion, but the starry cope +Of Heaven perhaps, or all the elements +At least had gone to wrack, disturbed and torn +With violence of this conflict, had not soon +The Eternal, to prevent such horrid fray, +Hung forth in Heaven his golden scales, yet seen +Betwixt Astrea and the Scorpion sign, +Wherein all things created first he weighed, +The pendulous round earth with balanced air +In counterpoise, now ponders all events, +Battles and realms: In these he put two weights, +The sequel each of parting and of fight: +The latter quick up flew, and kicked the beam, +Which Gabriel spying, thus bespake the Fiend. +Satan, I know thy strength, and thou knowest mine; +Neither our own, but given: What folly then +To boast what arms can do? since thine no more +Than Heaven permits, nor mine, though doubled now +To trample thee as mire: For proof look up, +And read thy lot in yon celestial sign; +Where thou art weighed, and shown how light, how weak, +If thou resist. The Fiend looked up, and knew +His mounted scale aloft: Nor more;but fled +Murmuring, and with him fled the shades of night. + + + +Book V + + +Now Morn, her rosy steps in the eastern clime +Advancing, sowed the earth with orient pearl, +When Adam waked, so customed; for his sleep +Was aery-light, from pure digestion bred, +And temperate vapours bland, which the only sound +Of leaves and fuming rills, Aurora's fan, +Lightly dispersed, and the shrill matin song +Of birds on every bough; so much the more +His wonder was to find unwakened Eve +With tresses discomposed, and glowing cheek, +As through unquiet rest: He, on his side +Leaning half raised, with looks of cordial love +Hung over her enamoured, and beheld +Beauty, which, whether waking or asleep, +Shot forth peculiar graces; then with voice +Mild, as when Zephyrus on Flora breathes, +Her hand soft touching, whispered thus. Awake, +My fairest, my espoused, my latest found, +Heaven's last best gift, my ever new delight! +Awake: The morning shines, and the fresh field +Calls us; we lose the prime, to mark how spring +Our tender plants, how blows the citron grove, +What drops the myrrh, and what the balmy reed, +How nature paints her colours, how the bee +Sits on the bloom extracting liquid sweet. +Such whispering waked her, but with startled eye +On Adam, whom embracing, thus she spake. +O sole in whom my thoughts find all repose, +My glory, my perfection! glad I see +Thy face, and morn returned; for I this night +(Such night till this I never passed) have dreamed, +If dreamed, not, as I oft am wont, of thee, +Works of day past, or morrow's next design, +But of offence and trouble, which my mind +Knew never till this irksome night: Methought, +Close at mine ear one called me forth to walk +With gentle voice; I thought it thine: It said, +'Why sleepest thou, Eve? now is the pleasant time, +'The cool, the silent, save where silence yields +'To the night-warbling bird, that now awake +'Tunes sweetest his love-laboured song; now reigns +'Full-orbed the moon, and with more pleasing light +'Shadowy sets off the face of things; in vain, +'If none regard; Heaven wakes with all his eyes, +'Whom to behold but thee, Nature's desire? +'In whose sight all things joy, with ravishment +'Attracted by thy beauty still to gaze.' +I rose as at thy call, but found thee not; +To find thee I directed then my walk; +And on, methought, alone I passed through ways +That brought me on a sudden to the tree +Of interdicted knowledge: fair it seemed, +Much fairer to my fancy than by day: +And, as I wondering looked, beside it stood +One shaped and winged like one of those from Heaven +By us oft seen; his dewy locks distilled +Ambrosia; on that tree he also gazed; +And 'O fair plant,' said he, 'with fruit surcharged, +'Deigns none to ease thy load, and taste thy sweet, +'Nor God, nor Man? Is knowledge so despised? +'Or envy, or what reserve forbids to taste? +'Forbid who will, none shall from me withhold +'Longer thy offered good; why else set here? +This said, he paused not, but with venturous arm +He plucked, he tasted; me damp horrour chilled +At such bold words vouched with a deed so bold: +But he thus, overjoyed; 'O fruit divine, +'Sweet of thyself, but much more sweet thus cropt, +'Forbidden here, it seems, as only fit +'For Gods, yet able to make Gods of Men: +'And why not Gods of Men; since good, the more +'Communicated, more abundant grows, +'The author not impaired, but honoured more? +'Here, happy creature, fair angelick Eve! +'Partake thou also; happy though thou art, +'Happier thou mayest be, worthier canst not be: +'Taste this, and be henceforth among the Gods +'Thyself a Goddess, not to earth confined, +'But sometimes in the air, as we, sometimes +'Ascend to Heaven, by merit thine, and see +'What life the Gods live there, and such live thou!' +So saying, he drew nigh, and to me held, +Even to my mouth of that same fruit held part +Which he had plucked; the pleasant savoury smell +So quickened appetite, that I, methought, +Could not but taste. Forthwith up to the clouds +With him I flew, and underneath beheld +The earth outstretched immense, a prospect wide +And various: Wondering at my flight and change +To this high exaltation; suddenly +My guide was gone, and I, methought, sunk down, +And fell asleep; but O, how glad I waked +To find this but a dream! Thus Eve her night +Related, and thus Adam answered sad. +Best image of myself, and dearer half, +The trouble of thy thoughts this night in sleep +Affects me equally; nor can I like +This uncouth dream, of evil sprung, I fear; +Yet evil whence? in thee can harbour none, +Created pure. But know that in the soul +Are many lesser faculties, that serve +Reason as chief; among these Fancy next +Her office holds; of all external things +Which the five watchful senses represent, +She forms imaginations, aery shapes, +Which Reason, joining or disjoining, frames +All what we affirm or what deny, and call +Our knowledge or opinion; then retires +Into her private cell, when nature rests. +Oft in her absence mimick Fancy wakes +To imitate her; but, misjoining shapes, +Wild work produces oft, and most in dreams; +Ill matching words and deeds long past or late. +Some such resemblances, methinks, I find +Of our last evening's talk, in this thy dream, +But with addition strange; yet be not sad. +Evil into the mind of God or Man +May come and go, so unreproved, and leave +No spot or blame behind: Which gives me hope +That what in sleep thou didst abhor to dream, +Waking thou never will consent to do. +Be not disheartened then, nor cloud those looks, +That wont to be more cheerful and serene, +Than when fair morning first smiles on the world; +And let us to our fresh employments rise +Among the groves, the fountains, and the flowers +That open now their choisest bosomed smells, +Reserved from night, and kept for thee in store. +So cheered he his fair spouse, and she was cheered; +But silently a gentle tear let fall +From either eye, and wiped them with her hair; +Two other precious drops that ready stood, +Each in their crystal sluice, he ere they fell +Kissed, as the gracious signs of sweet remorse +And pious awe, that feared to have offended. +So all was cleared, and to the field they haste. +But first, from under shady arborous roof +Soon as they forth were come to open sight +Of day-spring, and the sun, who, scarce up-risen, +With wheels yet hovering o'er the ocean-brim, +Shot parallel to the earth his dewy ray, +Discovering in wide landskip all the east +Of Paradise and Eden's happy plains, +Lowly they bowed adoring, and began +Their orisons, each morning duly paid +In various style; for neither various style +Nor holy rapture wanted they to praise +Their Maker, in fit strains pronounced, or sung +Unmeditated; such prompt eloquence +Flowed from their lips, in prose or numerous verse, +More tuneable than needed lute or harp +To add more sweetness; and they thus began. +These are thy glorious works, Parent of good, +Almighty! Thine this universal frame, +Thus wonderous fair; Thyself how wonderous then! +Unspeakable, who sitst above these heavens +To us invisible, or dimly seen +In these thy lowest works; yet these declare +Thy goodness beyond thought, and power divine. +Speak, ye who best can tell, ye sons of light, +Angels; for ye behold him, and with songs +And choral symphonies, day without night, +Circle his throne rejoicing; ye in Heaven +On Earth join all ye Creatures to extol +Him first, him last, him midst, and without end. +Fairest of stars, last in the train of night, +If better thou belong not to the dawn, +Sure pledge of day, that crownest the smiling morn +With thy bright circlet, praise him in thy sphere, +While day arises, that sweet hour of prime. +Thou Sun, of this great world both eye and soul, +Acknowledge him thy greater; sound his praise +In thy eternal course, both when thou climbest, +And when high noon hast gained, and when thou fallest. +Moon, that now meetest the orient sun, now flyest, +With the fixed Stars, fixed in their orb that flies; +And ye five other wandering Fires, that move +In mystick dance not without song, resound +His praise, who out of darkness called up light. +Air, and ye Elements, the eldest birth +Of Nature's womb, that in quaternion run +Perpetual circle, multiform; and mix +And nourish all things; let your ceaseless change +Vary to our great Maker still new praise. +Ye Mists and Exhalations, that now rise +From hill or steaming lake, dusky or gray, +Till the sun paint your fleecy skirts with gold, +In honour to the world's great Author rise; +Whether to deck with clouds the uncoloured sky, +Or wet the thirsty earth with falling showers, +Rising or falling still advance his praise. +His praise, ye Winds, that from four quarters blow, +Breathe soft or loud; and, wave your tops, ye Pines, +With every plant, in sign of worship wave. +Fountains, and ye that warble, as ye flow, +Melodious murmurs, warbling tune his praise. +Join voices, all ye living Souls: Ye Birds, +That singing up to Heaven-gate ascend, +Bear on your wings and in your notes his praise. +Ye that in waters glide, and ye that walk +The earth, and stately tread, or lowly creep; +Witness if I be silent, morn or even, +To hill, or valley, fountain, or fresh shade, +Made vocal by my song, and taught his praise. +Hail, universal Lord, be bounteous still +To give us only good; and if the night +Have gathered aught of evil, or concealed, +Disperse it, as now light dispels the dark! +So prayed they innocent, and to their thoughts +Firm peace recovered soon, and wonted calm. +On to their morning's rural work they haste, +Among sweet dews and flowers; where any row +Of fruit-trees over-woody reached too far +Their pampered boughs, and needed hands to check +Fruitless embraces: or they led the vine +To wed her elm; she, spoused, about him twines +Her marriageable arms, and with him brings +Her dower, the adopted clusters, to adorn +His barren leaves. Them thus employed beheld +With pity Heaven's high King, and to him called +Raphael, the sociable Spirit, that deigned +To travel with Tobias, and secured +His marriage with the seventimes-wedded maid. +Raphael, said he, thou hearest what stir on Earth +Satan, from Hell 'scaped through the darksome gulf, +Hath raised in Paradise; and how disturbed +This night the human pair; how he designs +In them at once to ruin all mankind. +Go therefore, half this day as friend with friend +Converse with Adam, in what bower or shade +Thou findest him from the heat of noon retired, +To respite his day-labour with repast, +Or with repose; and such discourse bring on, +As may advise him of his happy state, +Happiness in his power left free to will, +Left to his own free will, his will though free, +Yet mutable; whence warn him to beware +He swerve not, too secure: Tell him withal +His danger, and from whom; what enemy, +Late fallen himself from Heaven, is plotting now +The fall of others from like state of bliss; +By violence? no, for that shall be withstood; +But by deceit and lies: This let him know, +Lest, wilfully transgressing, he pretend +Surprisal, unadmonished, unforewarned. +So spake the Eternal Father, and fulfilled +All justice: Nor delayed the winged Saint +After his charge received; but from among +Thousand celestial Ardours, where he stood +Veiled with his gorgeous wings, up springing light, +Flew through the midst of Heaven; the angelick quires, +On each hand parting, to his speed gave way +Through all the empyreal road; till, at the gate +Of Heaven arrived, the gate self-opened wide +On golden hinges turning, as by work +Divine the sovran Architect had framed. +From hence no cloud, or, to obstruct his sight, +Star interposed, however small he sees, +Not unconformed to other shining globes, +Earth, and the garden of God, with cedars crowned +Above all hills. As when by night the glass +Of Galileo, less assured, observes +Imagined lands and regions in the moon: +Or pilot, from amidst the Cyclades +Delos or Samos first appearing, kens +A cloudy spot. Down thither prone in flight +He speeds, and through the vast ethereal sky +Sails between worlds and worlds, with steady wing +Now on the polar winds, then with quick fan +Winnows the buxom air; till, within soar +Of towering eagles, to all the fowls he seems +A phoenix, gazed by all as that sole bird, +When, to enshrine his reliques in the Sun's +Bright temple, to Egyptian Thebes he flies. +At once on the eastern cliff of Paradise +He lights, and to his proper shape returns +A Seraph winged: Six wings he wore, to shade +His lineaments divine; the pair that clad +Each shoulder broad, came mantling o'er his breast +With regal ornament; the middle pair +Girt like a starry zone his waist, and round +Skirted his loins and thighs with downy gold +And colours dipt in Heaven; the third his feet +Shadowed from either heel with feathered mail, +Sky-tinctured grain. Like Maia's son he stood, +And shook his plumes, that heavenly fragrance filled +The circuit wide. Straight knew him all the bands +Of Angels under watch; and to his state, +And to his message high, in honour rise; +For on some message high they guessed him bound. +Their glittering tents he passed, and now is come +Into the blissful field, through groves of myrrh, +And flowering odours, cassia, nard, and balm; +A wilderness of sweets; for Nature here +Wantoned as in her prime, and played at will +Her virgin fancies pouring forth more sweet, +Wild above rule or art, enormous bliss. +Him through the spicy forest onward come +Adam discerned, as in the door he sat +Of his cool bower, while now the mounted sun +Shot down direct his fervid rays to warm +Earth's inmost womb, more warmth than Adam needs: +And Eve within, due at her hour prepared +For dinner savoury fruits, of taste to please +True appetite, and not disrelish thirst +Of nectarous draughts between, from milky stream, +Berry or grape: To whom thus Adam called. +Haste hither, Eve, and worth thy sight behold +Eastward among those trees, what glorious shape +Comes this way moving; seems another morn +Risen on mid-noon; some great behest from Heaven +To us perhaps he brings, and will vouchsafe +This day to be our guest. But go with speed, +And, what thy stores contain, bring forth, and pour +Abundance, fit to honour and receive +Our heavenly stranger: Well we may afford +Our givers their own gifts, and large bestow +From large bestowed, where Nature multiplies +Her fertile growth, and by disburthening grows +More fruitful, which instructs us not to spare. +To whom thus Eve. Adam, earth's hallowed mould, +Of God inspired! small store will serve, where store, +All seasons, ripe for use hangs on the stalk; +Save what by frugal storing firmness gains +To nourish, and superfluous moist consumes: +But I will haste, and from each bough and brake, +Each plant and juciest gourd, will pluck such choice +To entertain our Angel-guest, as he +Beholding shall confess, that here on Earth +God hath dispensed his bounties as in Heaven. +So saying, with dispatchful looks in haste +She turns, on hospitable thoughts intent +What choice to choose for delicacy best, +What order, so contrived as not to mix +Tastes, not well joined, inelegant, but bring +Taste after taste upheld with kindliest change; +Bestirs her then, and from each tender stalk +Whatever Earth, all-bearing mother, yields +In India East or West, or middle shore +In Pontus or the Punick coast, or where +Alcinous reigned, fruit of all kinds, in coat +Rough, or smooth rind, or bearded husk, or shell, +She gathers, tribute large, and on the board +Heaps with unsparing hand; for drink the grape +She crushes, inoffensive must, and meaths +From many a berry, and from sweet kernels pressed +She tempers dulcet creams; nor these to hold +Wants her fit vessels pure; then strows the ground +With rose and odours from the shrub unfumed. +Mean while our primitive great sire, to meet +His God-like guest, walks forth, without more train +Accompanied than with his own complete +Perfections; in himself was all his state, +More solemn than the tedious pomp that waits +On princes, when their rich retinue long +Of horses led, and grooms besmeared with gold, +Dazzles the croud, and sets them all agape. +Nearer his presence Adam, though not awed, +Yet with submiss approach and reverence meek, +As to a superiour nature bowing low, +Thus said. Native of Heaven, for other place +None can than Heaven such glorious shape contain; +Since, by descending from the thrones above, +Those happy places thou hast deigned a while +To want, and honour these, vouchsafe with us +Two only, who yet by sovran gift possess +This spacious ground, in yonder shady bower +To rest; and what the garden choicest bears +To sit and taste, till this meridian heat +Be over, and the sun more cool decline. +Whom thus the angelick Virtue answered mild. +Adam, I therefore came; nor art thou such +Created, or such place hast here to dwell, +As may not oft invite, though Spirits of Heaven, +To visit thee; lead on then where thy bower +O'ershades; for these mid-hours, till evening rise, +I have at will. So to the sylvan lodge +They came, that like Pomona's arbour smiled, +With flowerets decked, and fragrant smells; but Eve, +Undecked save with herself, more lovely fair +Than Wood-Nymph, or the fairest Goddess feigned +Of three that in mount Ida naked strove, +Stood to entertain her guest from Heaven; no veil +She needed, virtue-proof; no thought infirm +Altered her cheek. On whom the Angel Hail +Bestowed, the holy salutation used +Long after to blest Mary, second Eve. +Hail, Mother of Mankind, whose fruitful womb +Shall fill the world more numerous with thy sons, +Than with these various fruits the trees of God +Have heaped this table!--Raised of grassy turf +Their table was, and mossy seats had round, +And on her ample square from side to side +All autumn piled, though spring and autumn here +Danced hand in hand. A while discourse they hold; +No fear lest dinner cool; when thus began +Our author. Heavenly stranger, please to taste +These bounties, which our Nourisher, from whom +All perfect good, unmeasured out, descends, +To us for food and for delight hath caused +The earth to yield; unsavoury food perhaps +To spiritual natures; only this I know, +That one celestial Father gives to all. +To whom the Angel. Therefore what he gives +(Whose praise be ever sung) to Man in part +Spiritual, may of purest Spirits be found +No ingrateful food: And food alike those pure +Intelligential substances require, +As doth your rational; and both contain +Within them every lower faculty +Of sense, whereby they hear, see, smell, touch, taste, +Tasting concoct, digest, assimilate, +And corporeal to incorporeal turn. +For know, whatever was created, needs +To be sustained and fed: Of elements +The grosser feeds the purer, earth the sea, +Earth and the sea feed air, the air those fires +Ethereal, and as lowest first the moon; +Whence in her visage round those spots, unpurged +Vapours not yet into her substance turned. +Nor doth the moon no nourishment exhale +From her moist continent to higher orbs. +The sun that light imparts to all, receives +From all his alimental recompence +In humid exhalations, and at even +Sups with the ocean. Though in Heaven the trees +Of life ambrosial fruitage bear, and vines +Yield nectar; though from off the boughs each morn +We brush mellifluous dews, and find the ground +Covered with pearly grain: Yet God hath here +Varied his bounty so with new delights, +As may compare with Heaven; and to taste +Think not I shall be nice. So down they sat, +And to their viands fell; nor seemingly +The Angel, nor in mist, the common gloss +Of Theologians; but with keen dispatch +Of real hunger, and concoctive heat +To transubstantiate: What redounds, transpires +Through Spirits with ease; nor wonder;if by fire +Of sooty coal the empirick alchemist +Can turn, or holds it possible to turn, +Metals of drossiest ore to perfect gold, +As from the mine. Mean while at table Eve +Ministered naked, and their flowing cups +With pleasant liquours crowned: O innocence +Deserving Paradise! if ever, then, +Then had the sons of God excuse to have been +Enamoured at that sight; but in those hearts +Love unlibidinous reigned, nor jealousy +Was understood, the injured lover's hell. +Thus when with meats and drinks they had sufficed, +Not burdened nature, sudden mind arose +In Adam, not to let the occasion pass +Given him by this great conference to know +Of things above his world, and of their being +Who dwell in Heaven, whose excellence he saw +Transcend his own so far; whose radiant forms, +Divine effulgence, whose high power, so far +Exceeded human; and his wary speech +Thus to the empyreal minister he framed. +Inhabitant with God, now know I well +Thy favour, in this honour done to Man; +Under whose lowly roof thou hast vouchsafed +To enter, and these earthly fruits to taste, +Food not of Angels, yet accepted so, +As that more willingly thou couldst not seem +At Heaven's high feasts to have fed: yet what compare +To whom the winged Hierarch replied. +O Adam, One Almighty is, from whom +All things proceed, and up to him return, +If not depraved from good, created all +Such to perfection, one first matter all, +Endued with various forms, various degrees +Of substance, and, in things that live, of life; +But more refined, more spiritous, and pure, +As nearer to him placed, or nearer tending +Each in their several active spheres assigned, +Till body up to spirit work, in bounds +Proportioned to each kind. So from the root +Springs lighter the green stalk, from thence the leaves +More aery, last the bright consummate flower +Spirits odorous breathes: flowers and their fruit, +Man's nourishment, by gradual scale sublimed, +To vital spirits aspire, to animal, +To intellectual; give both life and sense, +Fancy and understanding; whence the soul +Reason receives, and reason is her being, +Discursive, or intuitive; discourse +Is oftest yours, the latter most is ours, +Differing but in degree, of kind the same. +Wonder not then, what God for you saw good +If I refuse not, but convert, as you +To proper substance. Time may come, when Men +With Angels may participate, and find +No inconvenient diet, nor too light fare; +And from these corporal nutriments perhaps +Your bodies may at last turn all to spirit, +Improved by tract of time, and, winged, ascend +Ethereal, as we; or may, at choice, +Here or in heavenly Paradises dwell; +If ye be found obedient, and retain +Unalterably firm his love entire, +Whose progeny you are. Mean while enjoy +Your fill what happiness this happy state +Can comprehend, incapable of more. +To whom the patriarch of mankind replied. +O favourable Spirit, propitious guest, +Well hast thou taught the way that might direct +Our knowledge, and the scale of nature set +From center to circumference; whereon, +In contemplation of created things, +By steps we may ascend to God. But say, +What meant that caution joined, If ye be found +Obedient? Can we want obedience then +To him, or possibly his love desert, +Who formed us from the dust and placed us here +Full to the utmost measure of what bliss +Human desires can seek or apprehend? +To whom the Angel. Son of Heaven and Earth, +Attend! That thou art happy, owe to God; +That thou continuest such, owe to thyself, +That is, to thy obedience; therein stand. +This was that caution given thee; be advised. +God made thee perfect, not immutable; +And good he made thee, but to persevere +He left it in thy power; ordained thy will +By nature free, not over-ruled by fate +Inextricable, or strict necessity: +Our voluntary service he requires, +Not our necessitated; such with him +Finds no acceptance, nor can find; for how +Can hearts, not free, be tried whether they serve +Willing or no, who will but what they must +By destiny, and can no other choose? +Myself, and all the angelick host, that stand +In sight of God, enthroned, our happy state +Hold, as you yours, while our obedience holds; +On other surety none: Freely we serve, +Because we freely love, as in our will +To love or not; in this we stand or fall: +And some are fallen, to disobedience fallen, +And so from Heaven to deepest Hell; O fall +From what high state of bliss, into what woe! +To whom our great progenitor. Thy words +Attentive, and with more delighted ear, +Divine instructer, I have heard, than when +Cherubick songs by night from neighbouring hills +Aereal musick send: Nor knew I not +To be both will and deed created free; +Yet that we never shall forget to love +Our Maker, and obey him whose command +Single is yet so just, my constant thoughts +Assured me, and still assure: Though what thou tellest +Hath passed in Heaven, some doubt within me move, +But more desire to hear, if thou consent, +The full relation, which must needs be strange, +Worthy of sacred silence to be heard; +And we have yet large day, for scarce the sun +Hath finished half his journey, and scarce begins +His other half in the great zone of Heaven. +Thus Adam made request; and Raphael, +After short pause assenting, thus began. +High matter thou enjoinest me, O prime of men, +Sad task and hard: For how shall I relate +To human sense the invisible exploits +Of warring Spirits? how, without remorse, +The ruin of so many glorious once +And perfect while they stood? how last unfold +The secrets of another world, perhaps +Not lawful to reveal? yet for thy good +This is dispensed; and what surmounts the reach +Of human sense, I shall delineate so, +By likening spiritual to corporal forms, +As may express them best; though what if Earth +Be but a shadow of Heaven, and things therein +Each to other like, more than on earth is thought? +As yet this world was not, and Chaos wild +Reigned where these Heavens now roll, where Earth now rests +Upon her center poised; when on a day +(For time, though in eternity, applied +To motion, measures all things durable +By present, past, and future,) on such day +As Heaven's great year brings forth, the empyreal host +Of Angels by imperial summons called, +Innumerable before the Almighty's throne +Forthwith, from all the ends of Heaven, appeared +Under their Hierarchs in orders bright: +Ten thousand thousand ensigns high advanced, +Standards and gonfalons 'twixt van and rear +Stream in the air, and for distinction serve +Of hierarchies, of orders, and degrees; +Or in their glittering tissues bear imblazed +Holy memorials, acts of zeal and love +Recorded eminent. Thus when in orbs +Of circuit inexpressible they stood, +Orb within orb, the Father Infinite, +By whom in bliss imbosomed sat the Son, +Amidst as from a flaming mount, whose top +Brightness had made invisible, thus spake. +Hear, all ye Angels, progeny of light, +Thrones, Dominations, Princedoms, Virtues, Powers; +Hear my decree, which unrevoked shall stand. +This day I have begot whom I declare +My only Son, and on this holy hill +Him have anointed, whom ye now behold +At my right hand; your head I him appoint; +And by myself have sworn, to him shall bow +All knees in Heaven, and shall confess him Lord: +Under his great vice-gerent reign abide +United, as one individual soul, +For ever happy: Him who disobeys, +Me disobeys, breaks union, and that day, +Cast out from God and blessed vision, falls +Into utter darkness, deep ingulfed, his place +Ordained without redemption, without end. +So spake the Omnipotent, and with his words +All seemed well pleased; all seemed, but were not all. +That day, as other solemn days, they spent +In song and dance about the sacred hill; +Mystical dance, which yonder starry sphere +Of planets, and of fixed, in all her wheels +Resembles nearest, mazes intricate, +Eccentrick, intervolved, yet regular +Then most, when most irregular they seem; +And in their motions harmony divine +So smooths her charming tones, that God's own ear +Listens delighted. Evening now approached, +(For we have also our evening and our morn, +We ours for change delectable, not need;) +Forthwith from dance to sweet repast they turn +Desirous; all in circles as they stood, +Tables are set, and on a sudden piled +With Angels food, and rubied nectar flows +In pearl, in diamond, and massy gold, +Fruit of delicious vines, the growth of Heaven. +On flowers reposed, and with fresh flowerets crowned, +They eat, they drink, and in communion sweet +Quaff immortality and joy, secure +Of surfeit, where full measure only bounds +Excess, before the all-bounteous King, who showered +With copious hand, rejoicing in their joy. +Now when ambrosial night with clouds exhaled +From that high mount of God, whence light and shade +Spring both, the face of brightest Heaven had changed +To grateful twilight, (for night comes not there +In darker veil,) and roseat dews disposed +All but the unsleeping eyes of God to rest; +Wide over all the plain, and wider far +Than all this globous earth in plain outspread, +(Such are the courts of God) the angelick throng, +Dispersed in bands and files, their camp extend +By living streams among the trees of life, +Pavilions numberless, and sudden reared, +Celestial tabernacles, where they slept +Fanned with cool winds; save those, who, in their course, +Melodious hymns about the sovran throne +Alternate all night long: but not so waked +Satan; so call him now, his former name +Is heard no more in Heaven; he of the first, +If not the first Arch-Angel, great in power, +In favour and pre-eminence, yet fraught +With envy against the Son of God, that day +Honoured by his great Father, and proclaimed +Messiah King anointed, could not bear +Through pride that sight, and thought himself impaired. +Deep malice thence conceiving and disdain, +Soon as midnight brought on the dusky hour +Friendliest to sleep and silence, he resolved +With all his legions to dislodge, and leave +Unworshipt, unobeyed, the throne supreme, +Contemptuous; and his next subordinate +Awakening, thus to him in secret spake. +Sleepest thou, Companion dear? What sleep can close +Thy eye-lids? and rememberest what decree +Of yesterday, so late hath passed the lips +Of Heaven's Almighty. Thou to me thy thoughts +Wast wont, I mine to thee was wont to impart; +Both waking we were one; how then can now +Thy sleep dissent? New laws thou seest imposed; +New laws from him who reigns, new minds may raise +In us who serve, new counsels to debate +What doubtful may ensue: More in this place +To utter is not safe. Assemble thou +Of all those myriads which we lead the chief; +Tell them, that by command, ere yet dim night +Her shadowy cloud withdraws, I am to haste, +And all who under me their banners wave, +Homeward, with flying march, where we possess +The quarters of the north; there to prepare +Fit entertainment to receive our King, +The great Messiah, and his new commands, +Who speedily through all the hierarchies +Intends to pass triumphant, and give laws. +So spake the false Arch-Angel, and infused +Bad influence into the unwary breast +Of his associate: He together calls, +Or several one by one, the regent Powers, +Under him Regent; tells, as he was taught, +That the Most High commanding, now ere night, +Now ere dim night had disincumbered Heaven, +The great hierarchal standard was to move; +Tells the suggested cause, and casts between +Ambiguous words and jealousies, to sound +Or taint integrity: But all obeyed +The wonted signal, and superiour voice +Of their great Potentate; for great indeed +His name, and high was his degree in Heaven; +His countenance, as the morning-star that guides +The starry flock, allured them, and with lies +Drew after him the third part of Heaven's host. +Mean while the Eternal eye, whose sight discerns +Abstrusest thoughts, from forth his holy mount, +And from within the golden lamps that burn +Nightly before him, saw without their light +Rebellion rising; saw in whom, how spread +Among the sons of morn, what multitudes +Were banded to oppose his high decree; +And, smiling, to his only Son thus said. +Son, thou in whom my glory I behold +In full resplendence, Heir of all my might, +Nearly it now concerns us to be sure +Of our Omnipotence, and with what arms +We mean to hold what anciently we claim +Of deity or empire: Such a foe +Is rising, who intends to erect his throne +Equal to ours, throughout the spacious north; +Nor so content, hath in his thought to try +In battle, what our power is, or our right. +Let us advise, and to this hazard draw +With speed what force is left, and all employ +In our defence; lest unawares we lose +This our high place, our sanctuary, our hill. +To whom the Son with calm aspect and clear, +Lightning divine, ineffable, serene, +Made answer. Mighty Father, thou thy foes +Justly hast in derision, and, secure, +Laughest at their vain designs and tumults vain, +Matter to me of glory, whom their hate +Illustrates, when they see all regal power +Given me to quell their pride, and in event +Know whether I be dextrous to subdue +Thy rebels, or be found the worst in Heaven. +So spake the Son; but Satan, with his Powers, +Far was advanced on winged speed; an host +Innumerable as the stars of night, +Or stars of morning, dew-drops, which the sun +Impearls on every leaf and every flower. +Regions they passed, the mighty regencies +Of Seraphim, and Potentates, and Thrones, +In their triple degrees; regions to which +All thy dominion, Adam, is no more +Than what this garden is to all the earth, +And all the sea, from one entire globose +Stretched into longitude; which having passed, +At length into the limits of the north +They came; and Satan to his royal seat +High on a hill, far blazing, as a mount +Raised on a mount, with pyramids and towers +From diamond quarries hewn, and rocks of gold; +The palace of great Lucifer, (so call +That structure in the dialect of men +Interpreted,) which not long after, he +Affecting all equality with God, +In imitation of that mount whereon +Messiah was declared in sight of Heaven, +The Mountain of the Congregation called; +For thither he assembled all his train, +Pretending so commanded to consult +About the great reception of their King, +Thither to come, and with calumnious art +Of counterfeited truth thus held their ears. +Thrones, Dominations, Princedoms, Virtues, Powers; +If these magnifick titles yet remain +Not merely titular, since by decree +Another now hath to himself engrossed +All power, and us eclipsed under the name +Of King anointed, for whom all this haste +Of midnight-march, and hurried meeting here, +This only to consult how we may best, +With what may be devised of honours new, +Receive him coming to receive from us +Knee-tribute yet unpaid, prostration vile! +Too much to one! but double how endured, +To one, and to his image now proclaimed? +But what if better counsels might erect +Our minds, and teach us to cast off this yoke? +Will ye submit your necks, and choose to bend +The supple knee? Ye will not, if I trust +To know ye right, or if ye know yourselves +Natives and sons of Heaven possessed before +By none; and if not equal all, yet free, +Equally free; for orders and degrees +Jar not with liberty, but well consist. +Who can in reason then, or right, assume +Monarchy over such as live by right +His equals, if in power and splendour less, +In freedom equal? or can introduce +Law and edict on us, who without law +Err not? much less for this to be our Lord, +And look for adoration, to the abuse +Of those imperial titles, which assert +Our being ordained to govern, not to serve. +Thus far his bold discourse without controul +Had audience; when among the Seraphim +Abdiel, than whom none with more zeal adored +The Deity, and divine commands obeyed, +Stood up, and in a flame of zeal severe +The current of his fury thus opposed. +O argument blasphemous, false, and proud! +Words which no ear ever to hear in Heaven +Expected, least of all from thee, Ingrate, +In place thyself so high above thy peers. +Canst thou with impious obloquy condemn +The just decree of God, pronounced and sworn, +That to his only Son, by right endued +With regal scepter, every soul in Heaven +Shall bend the knee, and in that honour due +Confess him rightful King? unjust, thou sayest, +Flatly unjust, to bind with laws the free, +And equal over equals to let reign, +One over all with unsucceeded power. +Shalt thou give law to God? shalt thou dispute +With him the points of liberty, who made +Thee what thou art, and formed the Powers of Heaven +Such as he pleased, and circumscribed their being? +Yet, by experience taught, we know how good, +And of our good and of our dignity +How provident he is; how far from thought +To make us less, bent rather to exalt +Our happy state, under one head more near +United. But to grant it thee unjust, +That equal over equals monarch reign: +Thyself, though great and glorious, dost thou count, +Or all angelick nature joined in one, +Equal to him begotten Son? by whom, +As by his Word, the Mighty Father made +All things, even thee; and all the Spirits of Heaven +By him created in their bright degrees, +Crowned them with glory, and to their glory named +Thrones, Dominations, Princedoms, Virtues, Powers, +Essential Powers; nor by his reign obscured, +But more illustrious made; since he the head +One of our number thus reduced becomes; +His laws our laws; all honour to him done +Returns our own. Cease then this impious rage, +And tempt not these; but hasten to appease +The incensed Father, and the incensed Son, +While pardon may be found in time besought. +So spake the fervent Angel; but his zeal +None seconded, as out of season judged, +Or singular and rash: Whereat rejoiced +The Apostate, and, more haughty, thus replied. +That we were formed then sayest thou? and the work +Of secondary hands, by task transferred +From Father to his Son? strange point and new! +Doctrine which we would know whence learned: who saw +When this creation was? rememberest thou +Thy making, while the Maker gave thee being? +We know no time when we were not as now; +Know none before us, self-begot, self-raised +By our own quickening power, when fatal course +Had circled his full orb, the birth mature +Of this our native Heaven, ethereal sons. +Our puissance is our own; our own right hand +Shall teach us highest deeds, by proof to try +Who is our equal: Then thou shalt behold +Whether by supplication we intend +Address, and to begirt the almighty throne +Beseeching or besieging. This report, +These tidings carry to the anointed King; +And fly, ere evil intercept thy flight. +He said; and, as the sound of waters deep, +Hoarse murmur echoed to his words applause +Through the infinite host; nor less for that +The flaming Seraph fearless, though alone +Encompassed round with foes, thus answered bold. +O alienate from God, O Spirit accursed, +Forsaken of all good! I see thy fall +Determined, and thy hapless crew involved +In this perfidious fraud, contagion spread +Both of thy crime and punishment: Henceforth +No more be troubled how to quit the yoke +Of God's Messiah; those indulgent laws +Will not be now vouchsafed; other decrees +Against thee are gone forth without recall; +That golden scepter, which thou didst reject, +Is now an iron rod to bruise and break +Thy disobedience. Well thou didst advise; +Yet not for thy advice or threats I fly +These wicked tents devoted, lest the wrath +Impendent, raging into sudden flame, +Distinguish not: For soon expect to feel +His thunder on thy head, devouring fire. +Then who created thee lamenting learn, +When who can uncreate thee thou shalt know. +So spake the Seraph Abdiel, faithful found +Among the faithless, faithful only he; +Among innumerable false, unmoved, +Unshaken, unseduced, unterrified, +His loyalty he kept, his love, his zeal; +Nor number, nor example, with him wrought +To swerve from truth, or change his constant mind, +Though single. From amidst them forth he passed, +Long way through hostile scorn, which he sustained +Superiour, nor of violence feared aught; +And, with retorted scorn, his back he turned +On those proud towers to swift destruction doomed. + + + +Book VI + + +All night the dreadless Angel, unpursued, +Through Heaven's wide champain held his way; till Morn, +Waked by the circling Hours, with rosy hand +Unbarred the gates of light. There is a cave +Within the mount of God, fast by his throne, +Where light and darkness in perpetual round +Lodge and dislodge by turns, which makes through Heaven +Grateful vicissitude, like day and night; +Light issues forth, and at the other door +Obsequious darkness enters, till her hour +To veil the Heaven, though darkness there might well +Seem twilight here: And now went forth the Morn +Such as in highest Heaven arrayed in gold +Empyreal; from before her vanished Night, +Shot through with orient beams; when all the plain +Covered with thick embattled squadrons bright, +Chariots, and flaming arms, and fiery steeds, +Reflecting blaze on blaze, first met his view: +War he perceived, war in procinct; and found +Already known what he for news had thought +To have reported: Gladly then he mixed +Among those friendly Powers, who him received +With joy and acclamations loud, that one, +That of so many myriads fallen, yet one +Returned not lost. On to the sacred hill +They led him high applauded, and present +Before the seat supreme; from whence a voice, +From midst a golden cloud, thus mild was heard. +Servant of God. Well done; well hast thou fought +The better fight, who single hast maintained +Against revolted multitudes the cause +Of truth, in word mightier than they in arms; +And for the testimony of truth hast borne +Universal reproach, far worse to bear +Than violence; for this was all thy care +To stand approved in sight of God, though worlds +Judged thee perverse: The easier conquest now +Remains thee, aided by this host of friends, +Back on thy foes more glorious to return, +Than scorned thou didst depart; and to subdue +By force, who reason for their law refuse, +Right reason for their law, and for their King +Messiah, who by right of merit reigns. +Go, Michael, of celestial armies prince, +And thou, in military prowess next, +Gabriel, lead forth to battle these my sons +Invincible; lead forth my armed Saints, +By thousands and by millions, ranged for fight, +Equal in number to that Godless crew +Rebellious: Them with fire and hostile arms +Fearless assault; and, to the brow of Heaven +Pursuing, drive them out from God and bliss, +Into their place of punishment, the gulf +Of Tartarus, which ready opens wide +His fiery Chaos to receive their fall. +So spake the Sovran Voice, and clouds began +To darken all the hill, and smoke to roll +In dusky wreaths, reluctant flames, the sign +Of wrath awaked; nor with less dread the loud +Ethereal trumpet from on high 'gan blow: +At which command the Powers militant, +That stood for Heaven, in mighty quadrate joined +Of union irresistible, moved on +In silence their bright legions, to the sound +Of instrumental harmony, that breathed +Heroick ardour to adventurous deeds +Under their God-like leaders, in the cause +Of God and his Messiah. On they move +Indissolubly firm; nor obvious hill, +Nor straitening vale, nor wood, nor stream, divides +Their perfect ranks; for high above the ground +Their march was, and the passive air upbore +Their nimble tread; as when the total kind +Of birds, in orderly array on wing, +Came summoned over Eden to receive +Their names of thee; so over many a tract +Of Heaven they marched, and many a province wide, +Tenfold the length of this terrene: At last, +Far in the horizon to the north appeared +From skirt to skirt a fiery region, stretched +In battailous aspect, and nearer view +Bristled with upright beams innumerable +Of rigid spears, and helmets thronged, and shields +Various, with boastful argument portrayed, +The banded Powers of Satan hasting on +With furious expedition; for they weened +That self-same day, by fight or by surprise, +To win the mount of God, and on his throne +To set the Envier of his state, the proud +Aspirer; but their thoughts proved fond and vain +In the mid way: Though strange to us it seemed +At first, that Angel should with Angel war, +And in fierce hosting meet, who wont to meet +So oft in festivals of joy and love +Unanimous, as sons of one great Sire, +Hymning the Eternal Father: But the shout +Of battle now began, and rushing sound +Of onset ended soon each milder thought. +High in the midst, exalted as a God, +The Apostate in his sun-bright chariot sat, +Idol of majesty divine, enclosed +With flaming Cherubim, and golden shields; +Then lighted from his gorgeous throne, for now +"twixt host and host but narrow space was left, +A dreadful interval, and front to front +Presented stood in terrible array +Of hideous length: Before the cloudy van, +On the rough edge of battle ere it joined, +Satan, with vast and haughty strides advanced, +Came towering, armed in adamant and gold; +Abdiel that sight endured not, where he stood +Among the mightiest, bent on highest deeds, +And thus his own undaunted heart explores. +O Heaven! that such resemblance of the Highest +Should yet remain, where faith and realty +Remain not: Wherefore should not strength and might +There fail where virtue fails, or weakest prove +Where boldest, though to fight unconquerable? +His puissance, trusting in the Almighty's aid, +I mean to try, whose reason I have tried +Unsound and false; nor is it aught but just, +That he, who in debate of truth hath won, +Should win in arms, in both disputes alike +Victor; though brutish that contest and foul, +When reason hath to deal with force, yet so +Most reason is that reason overcome. +So pondering, and from his armed peers +Forth stepping opposite, half-way he met +His daring foe, at this prevention more +Incensed, and thus securely him defied. +Proud, art thou met? thy hope was to have reached +The highth of thy aspiring unopposed, +The throne of God unguarded, and his side +Abandoned, at the terrour of thy power +Or potent tongue: Fool!not to think how vain +Against the Omnipotent to rise in arms; +Who out of smallest things could, without end, +Have raised incessant armies to defeat +Thy folly; or with solitary hand +Reaching beyond all limit, at one blow, +Unaided, could have finished thee, and whelmed +Thy legions under darkness: But thou seest +All are not of thy train; there be, who faith +Prefer, and piety to God, though then +To thee not visible, when I alone +Seemed in thy world erroneous to dissent +From all: My sect thou seest;now learn too late +How few sometimes may know, when thousands err. +Whom the grand foe, with scornful eye askance, +Thus answered. Ill for thee, but in wished hour +Of my revenge, first sought for, thou returnest +From flight, seditious Angel! to receive +Thy merited reward, the first assay +Of this right hand provoked, since first that tongue, +Inspired with contradiction, durst oppose +A third part of the Gods, in synod met +Their deities to assert; who, while they feel +Vigour divine within them, can allow +Omnipotence to none. But well thou comest +Before thy fellows, ambitious to win +From me some plume, that thy success may show +Destruction to the rest: This pause between, +(Unanswered lest thou boast) to let thee know, +At first I thought that Liberty and Heaven +To heavenly souls had been all one; but now +I see that most through sloth had rather serve, +Ministring Spirits, trained up in feast and song! +Such hast thou armed, the minstrelsy of Heaven, +Servility with freedom to contend, +As both their deeds compared this day shall prove. +To whom in brief thus Abdiel stern replied. +Apostate! still thou errest, nor end wilt find +Of erring, from the path of truth remote: +Unjustly thou depravest it with the name +Of servitude, to serve whom God ordains, +Or Nature: God and Nature bid the same, +When he who rules is worthiest, and excels +Them whom he governs. This is servitude, +To serve the unwise, or him who hath rebelled +Against his worthier, as thine now serve thee, +Thyself not free, but to thyself enthralled; +Yet lewdly darest our ministring upbraid. +Reign thou in Hell, thy kingdom; let me serve +In Heaven God ever blest, and his divine +Behests obey, worthiest to be obeyed; +Yet chains in Hell, not realms, expect: Mean while +From me returned, as erst thou saidst, from flight, +This greeting on thy impious crest receive. +So saying, a noble stroke he lifted high, +Which hung not, but so swift with tempest fell +On the proud crest of Satan, that no sight, +Nor motion of swift thought, less could his shield, +Such ruin intercept: Ten paces huge +He back recoiled; the tenth on bended knee +His massy spear upstaid; as if on earth +Winds under ground, or waters forcing way, +Sidelong had pushed a mountain from his seat, +Half sunk with all his pines. Amazement seised +The rebel Thrones, but greater rage, to see +Thus foiled their mightiest; ours joy filled, and shout, +Presage of victory, and fierce desire +Of battle: Whereat Michael bid sound +The Arch-Angel trumpet; through the vast of Heaven +It sounded, and the faithful armies rung +Hosanna to the Highest: Nor stood at gaze +The adverse legions, nor less hideous joined +The horrid shock. Now storming fury rose, +And clamour such as heard in Heaven till now +Was never; arms on armour clashing brayed +Horrible discord, and the madding wheels +Of brazen chariots raged; dire was the noise +Of conflict; over head the dismal hiss +Of fiery darts in flaming vollies flew, +And flying vaulted either host with fire. +So under fiery cope together rushed +Both battles main, with ruinous assault +And inextinguishable rage. All Heaven +Resounded; and had Earth been then, all Earth +Had to her center shook. What wonder? when +Millions of fierce encountering Angels fought +On either side, the least of whom could wield +These elements, and arm him with the force +Of all their regions: How much more of power +Army against army numberless to raise +Dreadful combustion warring, and disturb, +Though not destroy, their happy native seat; +Had not the Eternal King Omnipotent, +From his strong hold of Heaven, high over-ruled +And limited their might; though numbered such +As each divided legion might have seemed +A numerous host; in strength each armed hand +A legion; led in fight, yet leader seemed +Each warriour single as in chief, expert +When to advance, or stand, or turn the sway +Of battle, open when, and when to close +The ridges of grim war: No thought of flight, +None of retreat, no unbecoming deed +That argued fear; each on himself relied, +As only in his arm the moment lay +Of victory: Deeds of eternal fame +Were done, but infinite; for wide was spread +That war and various; sometimes on firm ground +A standing fight, then, soaring on main wing, +Tormented all the air; all air seemed then +Conflicting fire. Long time in even scale +The battle hung; till Satan, who that day +Prodigious power had shown, and met in arms +No equal, ranging through the dire attack +Of fighting Seraphim confused, at length +Saw where the sword of Michael smote, and felled +Squadrons at once; with huge two-handed sway +Brandished aloft, the horrid edge came down +Wide-wasting; such destruction to withstand +He hasted, and opposed the rocky orb +Of tenfold adamant, his ample shield, +A vast circumference. At his approach +The great Arch-Angel from his warlike toil +Surceased, and glad, as hoping here to end +Intestine war in Heaven, the arch-foe subdued +Or captive dragged in chains, with hostile frown +And visage all inflamed first thus began. +Author of evil, unknown till thy revolt, +Unnamed in Heaven, now plenteous as thou seest +These acts of hateful strife, hateful to all, +Though heaviest by just measure on thyself, +And thy adherents: How hast thou disturbed +Heaven's blessed peace, and into nature brought +Misery, uncreated till the crime +Of thy rebellion! how hast thou instilled +Thy malice into thousands, once upright +And faithful, now proved false! But think not here +To trouble holy rest; Heaven casts thee out +From all her confines. Heaven, the seat of bliss, +Brooks not the works of violence and war. +Hence then, and evil go with thee along, +Thy offspring, to the place of evil, Hell; +Thou and thy wicked crew! there mingle broils, +Ere this avenging sword begin thy doom, +Or some more sudden vengeance, winged from God, +Precipitate thee with augmented pain. +So spake the Prince of Angels; to whom thus +The Adversary. Nor think thou with wind +Of aery threats to awe whom yet with deeds +Thou canst not. Hast thou turned the least of these +To flight, or if to fall, but that they rise +Unvanquished, easier to transact with me +That thou shouldst hope, imperious, and with threats +To chase me hence? err not, that so shall end +The strife which thou callest evil, but we style +The strife of glory; which we mean to win, +Or turn this Heaven itself into the Hell +Thou fablest; here however to dwell free, +If not to reign: Mean while thy utmost force, +And join him named Almighty to thy aid, +I fly not, but have sought thee far and nigh. +They ended parle, and both addressed for fight +Unspeakable; for who, though with the tongue +Of Angels, can relate, or to what things +Liken on earth conspicuous, that may lift +Human imagination to such highth +Of Godlike power? for likest Gods they seemed, +Stood they or moved, in stature, motion, arms, +Fit to decide the empire of great Heaven. +Now waved their fiery swords, and in the air +Made horrid circles; two broad suns their shields +Blazed opposite, while Expectation stood +In horrour: From each hand with speed retired, +Where erst was thickest fight, the angelick throng, +And left large field, unsafe within the wind +Of such commotion; such as, to set forth +Great things by small, if, nature's concord broke, +Among the constellations war were sprung, +Two planets, rushing from aspect malign +Of fiercest opposition, in mid sky +Should combat, and their jarring spheres confound. +Together both with next to almighty arm +Up-lifted imminent, one stroke they aimed +That might determine, and not need repeat, +As not of power at once; nor odds appeared +In might or swift prevention: But the sword +Of Michael from the armoury of God +Was given him tempered so, that neither keen +Nor solid might resist that edge: it met +The sword of Satan, with steep force to smite +Descending, and in half cut sheer; nor staid, +But with swift wheel reverse, deep entering, shared +All his right side: Then Satan first knew pain, +And writhed him to and fro convolved; so sore +The griding sword with discontinuous wound +Passed through him: But the ethereal substance closed, +Not long divisible; and from the gash +A stream of necturous humour issuing flowed +Sanguine, such as celestial Spirits may bleed, +And all his armour stained, ere while so bright. +Forthwith on all sides to his aid was run +By Angels many and strong, who interposed +Defence, while others bore him on their shields +Back to his chariot, where it stood retired +From off the files of war: There they him laid +Gnashing for anguish, and despite, and shame, +To find himself not matchless, and his pride +Humbled by such rebuke, so far beneath +His confidence to equal God in power. +Yet soon he healed; for Spirits that live throughout +Vital in every part, not as frail man +In entrails, heart of head, liver or reins, +Cannot but by annihilating die; +Nor in their liquid texture mortal wound +Receive, no more than can the fluid air: +All heart they live, all head, all eye, all ear, +All intellect, all sense; and, as they please, +They limb themselves, and colour, shape, or size +Assume, as?kikes them best, condense or rare. +Mean while in other parts like deeds deserved +Memorial, where the might of Gabriel fought, +And with fierce ensigns pierced the deep array +Of Moloch, furious king; who him defied, +And at his chariot-wheels to drag him bound +Threatened, nor from the Holy One of Heaven +Refrained his tongue blasphemous; but anon +Down cloven to the waist, with shattered arms +And uncouth pain fled bellowing. On each wing +Uriel, and Raphael, his vaunting foe, +Though huge, and in a rock of diamond armed, +Vanquished Adramelech, and Asmadai, +Two potent Thrones, that to be less than Gods +Disdained, but meaner thoughts learned in their flight, +Mangled with ghastly wounds through plate and mail. +Nor stood unmindful Abdiel to annoy +The atheist crew, but with redoubled blow +Ariel, and Arioch, and the violence +Of Ramiel scorched and blasted, overthrew. +I might relate of thousands, and their names +Eternize here on earth; but those elect +Angels, contented with their fame in Heaven, +Seek not the praise of men: The other sort, +In might though wonderous and in acts of war, +Nor of renown less eager, yet by doom +Cancelled from Heaven and sacred memory, +Nameless in dark oblivion let them dwell. +For strength from truth divided, and from just, +Illaudable, nought merits but dispraise +And ignominy; yet to glory aspires +Vain-glorious, and through infamy seeks fame: +Therefore eternal silence be their doom. +And now, their mightiest quelled, the battle swerved, +With many an inroad gored; deformed rout +Entered, and foul disorder; all the ground +With shivered armour strown, and on a heap +Chariot and charioteer lay overturned, +And fiery-foaming steeds; what stood, recoiled +O'er-wearied, through the faint Satanick host +Defensive scarce, or with pale fear surprised, +Then first with fear surprised, and sense of pain, +Fled ignominious, to such evil brought +By sin of disobedience; till that hour +Not liable to fear, or flight, or pain. +Far otherwise the inviolable Saints, +In cubick phalanx firm, advanced entire, +Invulnerable, impenetrably armed; +Such high advantages their innocence +Gave them above their foes; not to have sinned, +Not to have disobeyed; in fight they stood +Unwearied, unobnoxious to be pained +By wound, though from their place by violence moved, +Now Night her course began, and, over Heaven +Inducing darkness, grateful truce imposed, +And silence on the odious din of war: +Under her cloudy covert both retired, +Victor and vanquished: On the foughten field +Michael and his Angels prevalent +Encamping, placed in guard their watches round, +Cherubick waving fires: On the other part, +Satan with his rebellious disappeared, +Far in the dark dislodged; and, void of rest, +His potentates to council called by night; +And in the midst thus undismayed began. +O now in danger tried, now known in arms +Not to be overpowered, Companions dear, +Found worthy not of liberty alone, +Too mean pretence! but what we more affect, +Honour, dominion, glory, and renown; +Who have sustained one day in doubtful fight, +(And if one day, why not eternal days?) +What Heaven's Lord had powerfullest to send +Against us from about his throne, and judged +Sufficient to subdue us to his will, +But proves not so: Then fallible, it seems, +Of future we may deem him, though till now +Omniscient thought. True is, less firmly armed, +Some disadvantage we endured and pain, +Till now not known, but, known, as soon contemned; +Since now we find this our empyreal form +Incapable of mortal injury, +Imperishable, and, though pierced with wound, +Soon closing, and by native vigour healed. +Of evil then so small as easy think +The remedy; perhaps more valid arms, +Weapons more violent, when next we meet, +May serve to better us, and worse our foes, +Or equal what between us made the odds, +In nature none: If other hidden cause +Left them superiour, while we can preserve +Unhurt our minds, and understanding sound, +Due search and consultation will disclose. +He sat; and in the assembly next upstood +Nisroch, of Principalities the prime; +As one he stood escaped from cruel fight, +Sore toiled, his riven arms to havock hewn, +And cloudy in aspect thus answering spake. +Deliverer from new Lords, leader to free +Enjoyment of our right as Gods; yet hard +For Gods, and too unequal work we find, +Against unequal arms to fight in pain, +Against unpained, impassive; from which evil +Ruin must needs ensue; for what avails +Valour or strength, though matchless, quelled with pain +Which all subdues, and makes remiss the hands +Of mightiest? Sense of pleasure we may well +Spare out of life perhaps, and not repine, +But live content, which is the calmest life: +But pain is perfect misery, the worst +Of evils, and, excessive, overturns +All patience. He, who therefore can invent +With what more forcible we may offend +Our yet unwounded enemies, or arm +Ourselves with like defence, to me deserves +No less than for deliverance what we owe. +Whereto with look composed Satan replied. +Not uninvented that, which thou aright +Believest so main to our success, I bring. +Which of us who beholds the bright surface +Of this ethereous mould whereon we stand, +This continent of spacious Heaven, adorned +With plant, fruit, flower ambrosial, gems, and gold; +Whose eye so superficially surveys +These things, as not to mind from whence they grow +Deep under ground, materials dark and crude, +Of spiritous and fiery spume, till touched +With Heaven's ray, and tempered, they shoot forth +So beauteous, opening to the ambient light? +These in their dark nativity the deep +Shall yield us, pregnant with infernal flame; +Which, into hollow engines, long and round, +Thick rammed, at the other bore with touch of fire +Dilated and infuriate, shall send forth +From far, with thundering noise, among our foes +Such implements of mischief, as shall dash +To pieces, and o'erwhelm whatever stands +Adverse, that they shall fear we have disarmed +The Thunderer of his only dreaded bolt. +Nor long shall be our labour; yet ere dawn, +Effect shall end our wish. Mean while revive; +Abandon fear; to strength and counsel joined +Think nothing hard, much less to be despaired. +He ended, and his words their drooping cheer +Enlightened, and their languished hope revived. +The invention all admired, and each, how he +To be the inventer missed; so easy it seemed +Once found, which yet unfound most would have thought +Impossible: Yet, haply, of thy race +In future days, if malice should abound, +Some one intent on mischief, or inspired +With devilish machination, might devise +Like instrument to plague the sons of men +For sin, on war and mutual slaughter bent. +Forthwith from council to the work they flew; +None arguing stood; innumerable hands +Were ready; in a moment up they turned +Wide the celestial soil, and saw beneath +The originals of nature in their crude +Conception; sulphurous and nitrous foam +They found, they mingled, and, with subtle art, +Concocted and adusted they reduced +To blackest grain, and into store conveyed: +Part hidden veins digged up (nor hath this earth +Entrails unlike) of mineral and stone, +Whereof to found their engines and their balls +Of missive ruin; part incentive reed +Provide, pernicious with one touch to fire. +So all ere day-spring, under conscious night, +Secret they finished, and in order set, +With silent circumspection, unespied. +Now when fair morn orient in Heaven appeared, +Up rose the victor-Angels, and to arms +The matin trumpet sung: In arms they stood +Of golden panoply, refulgent host, +Soon banded; others from the dawning hills +Look round, and scouts each coast light-armed scour, +Each quarter to descry the distant foe, +Where lodged, or whither fled, or if for fight, +In motion or in halt: Him soon they met +Under spread ensigns moving nigh, in slow +But firm battalion; back with speediest sail +Zophiel, of Cherubim the swiftest wing, +Came flying, and in mid air aloud thus cried. +Arm, Warriours, arm for fight; the foe at hand, +Whom fled we thought, will save us long pursuit +This day; fear not his flight;so thick a cloud +He comes, and settled in his face I see +Sad resolution, and secure: Let each +His adamantine coat gird well, and each +Fit well his helm, gripe fast his orbed shield, +Borne even or high; for this day will pour down, +If I conjecture aught, no drizzling shower, +But rattling storm of arrows barbed with fire. +So warned he them, aware themselves, and soon +In order, quit of all impediment; +Instant without disturb they took alarm, +And onward moved embattled: When behold! +Not distant far with heavy pace the foe +Approaching gross and huge, in hollow cube +Training his devilish enginery, impaled +On every side with shadowing squadrons deep, +To hide the fraud. At interview both stood +A while; but suddenly at head appeared +Satan, and thus was heard commanding loud. +Vanguard, to right and left the front unfold; +That all may see who hate us, how we seek +Peace and composure, and with open breast +Stand ready to receive them, if they like +Our overture; and turn not back perverse: +But that I doubt; however witness, Heaven! +Heaven, witness thou anon! while we discharge +Freely our part: ye, who appointed stand +Do as you have in charge, and briefly touch +What we propound, and loud that all may hear! +So scoffing in ambiguous words, he scarce +Had ended; when to right and left the front +Divided, and to either flank retired: +Which to our eyes discovered, new and strange, +A triple mounted row of pillars laid +On wheels (for like to pillars most they seemed, +Or hollowed bodies made of oak or fir, +With branches lopt, in wood or mountain felled,) +Brass, iron, stony mould, had not their mouths +With hideous orifice gaped on us wide, +Portending hollow truce: At each behind +A Seraph stood, and in his hand a reed +Stood waving tipt with fire; while we, suspense, +Collected stood within our thoughts amused, +Not long; for sudden all at once their reeds +Put forth, and to a narrow vent applied +With nicest touch. Immediate in a flame, +But soon obscured with smoke, all Heaven appeared, +From those deep-throated engines belched, whose roar +Embowelled with outrageous noise the air, +And all her entrails tore, disgorging foul +Their devilish glut, chained thunderbolts and hail +Of iron globes; which, on the victor host +Levelled, with such impetuous fury smote, +That, whom they hit, none on their feet might stand, +Though standing else as rocks, but down they fell +By thousands, Angel on Arch-Angel rolled; +The sooner for their arms; unarmed, they might +Have easily, as Spirits, evaded swift +By quick contraction or remove; but now +Foul dissipation followed, and forced rout; +Nor served it to relax their serried files. +What should they do? if on they rushed, repulse +Repeated, and indecent overthrow +Doubled, would render them yet more despised, +And to their foes a laughter; for in view +Stood ranked of Seraphim another row, +In posture to displode their second tire +Of thunder: Back defeated to return +They worse abhorred. Satan beheld their plight, +And to his mates thus in derision called. +O Friends! why come not on these victors proud +Ere while they fierce were coming; and when we, +To entertain them fair with open front +And breast, (what could we more?) propounded terms +Of composition, straight they changed their minds, +Flew off, and into strange vagaries fell, +As they would dance; yet for a dance they seemed +Somewhat extravagant and wild; perhaps +For joy of offered peace: But I suppose, +If our proposals once again were heard, +We should compel them to a quick result. +To whom thus Belial, in like gamesome mood. +Leader! the terms we sent were terms of weight, +Of hard contents, and full of force urged home; +Such as we might perceive amused them all, +And stumbled many: Who receives them right, +Had need from head to foot well understand; +Not understood, this gift they have besides, +They show us when our foes walk not upright. +So they among themselves in pleasant vein +Stood scoffing, hightened in their thoughts beyond +All doubt of victory: Eternal Might +To match with their inventions they presumed +So easy, and of his thunder made a scorn, +And all his host derided, while they stood +A while in trouble: But they stood not long; +Rage prompted them at length, and found them arms +Against such hellish mischief fit to oppose. +Forthwith (behold the excellence, the power, +Which God hath in his mighty Angels placed!) +Their arms away they threw, and to the hills +(For Earth hath this variety from Heaven +Of pleasure situate in hill and dale,) +Light as the lightning glimpse they ran, they flew; +From their foundations loosening to and fro, +They plucked the seated hills, with all their load, +Rocks, waters, woods, and by the shaggy tops +Up-lifting bore them in their hands: Amaze, +Be sure, and terrour, seized the rebel host, +When coming towards them so dread they saw +The bottom of the mountains upward turned; +Till on those cursed engines' triple-row +They saw them whelmed, and all their confidence +Under the weight of mountains buried deep; +Themselves invaded next, and on their heads +Main promontories flung, which in the air +Came shadowing, and oppressed whole legions armed; +Their armour helped their harm, crushed in and bruised +Into their substance pent, which wrought them pain +Implacable, and many a dolorous groan; +Long struggling underneath, ere they could wind +Out of such prison, though Spirits of purest light, +Purest at first, now gross by sinning grown. +The rest, in imitation, to like arms +Betook them, and the neighbouring hills uptore: +So hills amid the air encountered hills, +Hurled to and fro with jaculation dire; +That under ground they fought in dismal shade; +Infernal noise! war seemed a civil game +To this uproar; horrid confusion heaped +Upon confusion rose: And now all Heaven +Had gone to wrack, with ruin overspread; +Had not the Almighty Father, where he sits +Shrined in his sanctuary of Heaven secure, +Consulting on the sum of things, foreseen +This tumult, and permitted all, advised: +That his great purpose he might so fulfil, +To honour his anointed Son avenged +Upon his enemies, and to declare +All power on him transferred: Whence to his Son, +The Assessour of his throne, he thus began. +Effulgence of my glory, Son beloved, +Son, in whose face invisible is beheld +Visibly, what by Deity I am; +And in whose hand what by decree I do, +Second Omnipotence! two days are past, +Two days, as we compute the days of Heaven, +Since Michael and his Powers went forth to tame +These disobedient: Sore hath been their fight, +As likeliest was, when two such foes met armed; +For to themselves I left them; and thou knowest, +Equal in their creation they were formed, +Save what sin hath impaired; which yet hath wrought +Insensibly, for I suspend their doom; +Whence in perpetual fight they needs must last +Endless, and no solution will be found: +War wearied hath performed what war can do, +And to disordered rage let loose the reins +With mountains, as with weapons, armed; which makes +Wild work in Heaven, and dangerous to the main. +Two days are therefore past, the third is thine; +For thee I have ordained it; and thus far +Have suffered, that the glory may be thine +Of ending this great war, since none but Thou +Can end it. Into thee such virtue and grace +Immense I have transfused, that all may know +In Heaven and Hell thy power above compare; +And, this perverse commotion governed thus, +To manifest thee worthiest to be Heir +Of all things; to be Heir, and to be King +By sacred unction, thy deserved right. +Go then, Thou Mightiest, in thy Father's might; +Ascend my chariot, guide the rapid wheels +That shake Heaven's basis, bring forth all my war, +My bow and thunder, my almighty arms +Gird on, and sword upon thy puissant thigh; +Pursue these sons of darkness, drive them out +From all Heaven's bounds into the utter deep: +There let them learn, as likes them, to despise +God, and Messiah his anointed King. +He said, and on his Son with rays direct +Shone full; he all his Father full expressed +Ineffably into his face received; +And thus the Filial Godhead answering spake. +O Father, O Supreme of heavenly Thrones, +First, Highest, Holiest, Best; thou always seek'st +To glorify thy Son, I always thee, +As is most just: This I my glory account, +My exaltation, and my whole delight, +That thou, in me well pleased, declarest thy will +Fulfilled, which to fulfil is all my bliss. +Scepter and power, thy giving, I assume, +And gladlier shall resign, when in the end +Thou shalt be all in all, and I in thee +For ever; and in me all whom thou lovest: +But whom thou hatest, I hate, and can put on +Thy terrours, as I put thy mildness on, +Image of thee in all things; and shall soon, +Armed with thy might, rid Heaven of these rebelled; +To their prepared ill mansion driven down, +To chains of darkness, and the undying worm; +That from thy just obedience could revolt, +Whom to obey is happiness entire. +Then shall thy Saints unmixed, and from the impure +Far separate, circling thy holy mount, +Unfeigned Halleluiahs to thee sing, +Hymns of high praise, and I among them Chief. +So said, he, o'er his scepter bowing, rose +From the right hand of Glory where he sat; +And the third sacred morn began to shine, +Dawning through Heaven. Forth rushed with whirlwind sound +The chariot of Paternal Deity, +Flashing thick flames, wheel within wheel undrawn, +Itself instinct with Spirit, but convoyed +By four Cherubick shapes; four faces each +Had wonderous; as with stars, their bodies all +And wings were set with eyes; with eyes the wheels +Of beryl, and careering fires between; +Over their heads a crystal firmament, +Whereon a sapphire throne, inlaid with pure +Amber, and colours of the showery arch. +He, in celestial panoply all armed +Of radiant Urim, work divinely wrought, +Ascended; at his right hand Victory +Sat eagle-winged; beside him hung his bow +And quiver with three-bolted thunder stored; +And from about him fierce effusion rolled +Of smoke, and bickering flame, and sparkles dire: +Attended with ten thousand thousand Saints, +He onward came; far off his coming shone; +And twenty thousand (I their number heard) +Chariots of God, half on each hand, were seen; +He on the wings of Cherub rode sublime +On the crystalline sky, in sapphire throned, +Illustrious far and wide; but by his own +First seen: Them unexpected joy surprised, +When the great ensign of Messiah blazed +Aloft by Angels borne, his sign in Heaven; +Under whose conduct Michael soon reduced +His army, circumfused on either wing, +Under their Head imbodied all in one. +Before him Power Divine his way prepared; +At his command the uprooted hills retired +Each to his place; they heard his voice, and went +Obsequious; Heaven his wonted face renewed, +And with fresh flowerets hill and valley smiled. +This saw his hapless foes, but stood obdured, +And to rebellious fight rallied their Powers, +Insensate, hope conceiving from despair. +In heavenly Spirits could such perverseness dwell? +But to convince the proud what signs avail, +Or wonders move the obdurate to relent? +They, hardened more by what might most reclaim, +Grieving to see his glory, at the sight +Took envy; and, aspiring to his highth, +Stood re-embattled fierce, by force or fraud +Weening to prosper, and at length prevail +Against God and Messiah, or to fall +In universal ruin last; and now +To final battle drew, disdaining flight, +Or faint retreat; when the great Son of God +To all his host on either hand thus spake. +Stand still in bright array, ye Saints; here stand, +Ye Angels armed; this day from battle rest: +Faithful hath been your warfare, and of God +Accepted, fearless in his righteous cause; +And as ye have received, so have ye done, +Invincibly: But of this cursed crew +The punishment to other hand belongs; +Vengeance is his, or whose he sole appoints: +Number to this day's work is not ordained, +Nor multitude; stand only, and behold +God's indignation on these godless poured +By me; not you, but me, they have despised, +Yet envied; against me is all their rage, +Because the Father, to whom in Heaven s'preme +Kingdom, and power, and glory appertains, +Hath honoured me, according to his will. +Therefore to me their doom he hath assigned; +That they may have their wish, to try with me +In battle which the stronger proves; they all, +Or I alone against them; since by strength +They measure all, of other excellence +Not emulous, nor care who them excels; +Nor other strife with them do I vouchsafe. +So spake the Son, and into terrour changed +His countenance too severe to be beheld, +And full of wrath bent on his enemies. +At once the Four spread out their starry wings +With dreadful shade contiguous, and the orbs +Of his fierce chariot rolled, as with the sound +Of torrent floods, or of a numerous host. +He on his impious foes right onward drove, +Gloomy as night; under his burning wheels +The stedfast empyrean shook throughout, +All but the throne itself of God. Full soon +Among them he arrived; in his right hand +Grasping ten thousand thunders, which he sent +Before him, such as in their souls infixed +Plagues: They, astonished, all resistance lost, +All courage; down their idle weapons dropt: +O'er shields, and helms, and helmed heads he rode +Of Thrones and mighty Seraphim prostrate, +That wished the mountains now might be again +Thrown on them, as a shelter from his ire. +Nor less on either side tempestuous fell +His arrows, from the fourfold-visaged Four +Distinct with eyes, and from the living wheels +Distinct alike with multitude of eyes; +One Spirit in them ruled; and every eye +Glared lightning, and shot forth pernicious fire +Among the accursed, that withered all their strength, +And of their wonted vigour left them drained, +Exhausted, spiritless, afflicted, fallen. +Yet half his strength he put not forth, but checked +His thunder in mid volley; for he meant +Not to destroy, but root them out of Heaven: +The overthrown he raised, and as a herd +Of goats or timorous flock together thronged +Drove them before him thunder-struck, pursued +With terrours, and with furies, to the bounds +And crystal wall of Heaven; which, opening wide, +Rolled inward, and a spacious gap disclosed +Into the wasteful deep: The monstrous sight +Struck them with horrour backward, but far worse +Urged them behind: Headlong themselves they threw +Down from the verge of Heaven; eternal wrath +Burnt after them to the bottomless pit. +Hell heard the unsufferable noise, Hell saw +Heaven ruining from Heaven, and would have fled +Affrighted; but strict Fate had cast too deep +Her dark foundations, and too fast had bound. +Nine days they fell: Confounded Chaos roared, +And felt tenfold confusion in their fall +Through his wild anarchy, so huge a rout +Incumbered him with ruin: Hell at last +Yawning received them whole, and on them closed; +Hell, their fit habitation, fraught with fire +Unquenchable, the house of woe and pain. +Disburdened Heaven rejoiced, and soon repaired +Her mural breach, returning whence it rolled. +Sole victor, from the expulsion of his foes, +Messiah his triumphal chariot turned: +To meet him all his Saints, who silent stood +Eye-witnesses of his almighty acts, +With jubilee advanced; and, as they went, +Shaded with branching palm, each Order bright, +Sung triumph, and him sung victorious King, +Son, Heir, and Lord, to him dominion given, +Worthiest to reign: He, celebrated, rode +Triumphant through mid Heaven, into the courts +And temple of his Mighty Father throned +On high; who into glory him received, +Where now he sits at the right hand of bliss. +Thus, measuring things in Heaven by things on Earth, +At thy request, and that thou mayest beware +By what is past, to thee I have revealed +What might have else to human race been hid; +The discord which befel, and war in Heaven +Among the angelick Powers, and the deep fall +Of those too high aspiring, who rebelled +With Satan; he who envies now thy state, +Who now is plotting how he may seduce +Thee also from obedience, that, with him +Bereaved of happiness, thou mayest partake +His punishment, eternal misery; +Which would be all his solace and revenge, +As a despite done against the Most High, +Thee once to gain companion of his woe. +But listen not to his temptations, warn +Thy weaker; let it profit thee to have heard, +By terrible example, the reward +Of disobedience; firm they might have stood, +Yet fell; remember, and fear to transgress. + + + +Book VII + + +Descend from Heaven, Urania, by that name +If rightly thou art called, whose voice divine +Following, above the Olympian hill I soar, +Above the flight of Pegasean wing! +The meaning, not the name, I call: for thou +Nor of the Muses nine, nor on the top +Of old Olympus dwellest; but, heavenly-born, +Before the hills appeared, or fountain flowed, +Thou with eternal Wisdom didst converse, +Wisdom thy sister, and with her didst play +In presence of the Almighty Father, pleased +With thy celestial song. Up led by thee +Into the Heaven of Heavens I have presumed, +An earthly guest, and drawn empyreal air, +Thy tempering: with like safety guided down +Return me to my native element: +Lest from this flying steed unreined, (as once +Bellerophon, though from a lower clime,) +Dismounted, on the Aleian field I fall, +Erroneous there to wander, and forlorn. +Half yet remains unsung, but narrower bound +Within the visible diurnal sphere; +Standing on earth, not rapt above the pole, +More safe I sing with mortal voice, unchanged +To hoarse or mute, though fallen on evil days, +On evil days though fallen, and evil tongues; +In darkness, and with dangers compassed round, +And solitude; yet not alone, while thou +Visitest my slumbers nightly, or when morn +Purples the east: still govern thou my song, +Urania, and fit audience find, though few. +But drive far off the barbarous dissonance +Of Bacchus and his revellers, the race +Of that wild rout that tore the Thracian bard +In Rhodope, where woods and rocks had ears +To rapture, till the savage clamour drowned +Both harp and voice; nor could the Muse defend +Her son. So fail not thou, who thee implores: +For thou art heavenly, she an empty dream. +Say, Goddess, what ensued when Raphael, +The affable Arch-Angel, had forewarned +Adam, by dire example, to beware +Apostasy, by what befel in Heaven +To those apostates; lest the like befall +In Paradise to Adam or his race, +Charged not to touch the interdicted tree, +If they transgress, and slight that sole command, +So easily obeyed amid the choice +Of all tastes else to please their appetite, +Though wandering. He, with his consorted Eve, +The story heard attentive, and was filled +With admiration and deep muse, to hear +Of things so high and strange; things, to their thought +So unimaginable, as hate in Heaven, +And war so near the peace of God in bliss, +With such confusion: but the evil, soon +Driven back, redounded as a flood on those +From whom it sprung; impossible to mix +With blessedness. Whence Adam soon repealed +The doubts that in his heart arose: and now +Led on, yet sinless, with desire to know +What nearer might concern him, how this world +Of Heaven and Earth conspicuous first began; +When, and whereof created; for what cause; +What within Eden, or without, was done +Before his memory; as one whose drouth +Yet scarce allayed still eyes the current stream, +Whose liquid murmur heard new thirst excites, +Proceeded thus to ask his heavenly guest. +Great things, and full of wonder in our ears, +Far differing from this world, thou hast revealed, +Divine interpreter! by favour sent +Down from the empyrean, to forewarn +Us timely of what might else have been our loss, +Unknown, which human knowledge could not reach; +For which to the infinitely Good we owe +Immortal thanks, and his admonishment +Receive, with solemn purpose to observe +Immutably his sovran will, the end +Of what we are. But since thou hast vouchsafed +Gently, for our instruction, to impart +Things above earthly thought, which yet concerned +Our knowing, as to highest wisdom seemed, +Deign to descend now lower, and relate +What may no less perhaps avail us known, +How first began this Heaven which we behold +Distant so high, with moving fires adorned +Innumerable; and this which yields or fills +All space, the ambient air wide interfused +Embracing round this floried Earth; what cause +Moved the Creator, in his holy rest +Through all eternity, so late to build +In Chaos; and the work begun, how soon +Absolved; if unforbid thou mayest unfold +What we, not to explore the secrets ask +Of his eternal empire, but the more +To magnify his works, the more we know. +And the great light of day yet wants to run +Much of his race though steep; suspense in Heaven, +Held by thy voice, thy potent voice, he hears, +And longer will delay to hear thee tell +His generation, and the rising birth +Of Nature from the unapparent Deep: +Or if the star of evening and the moon +Haste to thy audience, Night with her will bring, +Silence; and Sleep, listening to thee, will watch; +Or we can bid his absence, till thy song +End, and dismiss thee ere the morning shine. +Thus Adam his illustrious guest besought: +And thus the Godlike Angel answered mild. +This also thy request, with caution asked, +Obtain; though to recount almighty works +What words or tongue of Seraph can suffice, +Or heart of man suffice to comprehend? +Yet what thou canst attain, which best may serve +To glorify the Maker, and infer +Thee also happier, shall not be withheld +Thy hearing; such commission from above +I have received, to answer thy desire +Of knowledge within bounds; beyond, abstain +To ask; nor let thine own inventions hope +Things not revealed, which the invisible King, +Only Omniscient, hath suppressed in night; +To none communicable in Earth or Heaven: +Enough is left besides to search and know. +But knowledge is as food, and needs no less +Her temperance over appetite, to know +In measure what the mind may well contain; +Oppresses else with surfeit, and soon turns +Wisdom to folly, as nourishment to wind. +Know then, that, after Lucifer from Heaven +(So call him, brighter once amidst the host +Of Angels, than that star the stars among,) +Fell with his flaming legions through the deep +Into his place, and the great Son returned +Victorious with his Saints, the Omnipotent +Eternal Father from his throne beheld +Their multitude, and to his Son thus spake. +At least our envious Foe hath failed, who thought +All like himself rebellious, by whose aid +This inaccessible high strength, the seat +Of Deity supreme, us dispossessed, +He trusted to have seised, and into fraud +Drew many, whom their place knows here no more: +Yet far the greater part have kept, I see, +Their station; Heaven, yet populous, retains +Number sufficient to possess her realms +Though wide, and this high temple to frequent +With ministeries due, and solemn rites: +But, lest his heart exalt him in the harm +Already done, to have dispeopled Heaven, +My damage fondly deemed, I can repair +That detriment, if such it be to lose +Self-lost; and in a moment will create +Another world, out of one man a race +Of men innumerable, there to dwell, +Not here; till, by degrees of merit raised, +They open to themselves at length the way +Up hither, under long obedience tried; +And Earth be changed to Heaven, and Heaven to Earth, +One kingdom, joy and union without end. +Mean while inhabit lax, ye Powers of Heaven; +And thou my Word, begotten Son, by thee +This I perform; speak thou, and be it done! +My overshadowing Spirit and Might with thee +I send along; ride forth, and bid the Deep +Within appointed bounds be Heaven and Earth; +Boundless the Deep, because I Am who fill +Infinitude, nor vacuous the space. +Though I, uncircumscribed myself, retire, +And put not forth my goodness, which is free +To act or not, Necessity and Chance +Approach not me, and what I will is Fate. +So spake the Almighty, and to what he spake +His Word, the Filial Godhead, gave effect. +Immediate are the acts of God, more swift +Than time or motion, but to human ears +Cannot without process of speech be told, +So told as earthly notion can receive. +Great triumph and rejoicing was in Heaven, +When such was heard declared the Almighty's will; +Glory they sung to the Most High, good will +To future men, and in their dwellings peace; +Glory to Him, whose just avenging ire +Had driven out the ungodly from his sight +And the habitations of the just; to Him +Glory and praise, whose wisdom had ordained +Good out of evil to create; instead +Of Spirits malign, a better race to bring +Into their vacant room, and thence diffuse +His good to worlds and ages infinite. +So sang the Hierarchies: Mean while the Son +On his great expedition now appeared, +Girt with Omnipotence, with radiance crowned +Of Majesty Divine; sapience and love +Immense, and all his Father in him shone. +About his chariot numberless were poured +Cherub, and Seraph, Potentates, and Thrones, +And Virtues, winged Spirits, and chariots winged +From the armoury of God; where stand of old +Myriads, between two brazen mountains lodged +Against a solemn day, harnessed at hand, +Celestial equipage; and now came forth +Spontaneous, for within them Spirit lived, +Attendant on their Lord: Heaven opened wide +Her ever-during gates, harmonious sound +On golden hinges moving, to let forth +The King of Glory, in his powerful Word +And Spirit, coming to create new worlds. +On heavenly ground they stood; and from the shore +They viewed the vast immeasurable abyss +Outrageous as a sea, dark, wasteful, wild, +Up from the bottom turned by furious winds +And surging waves, as mountains, to assault +Heaven's highth, and with the center mix the pole. +Silence, ye troubled Waves, and thou Deep, peace, +Said then the Omnifick Word; your discord end! +Nor staid; but, on the wings of Cherubim +Uplifted, in paternal glory rode +Far into Chaos, and the world unborn; +For Chaos heard his voice: Him all his train +Followed in bright procession, to behold +Creation, and the wonders of his might. +Then staid the fervid wheels, and in his hand +He took the golden compasses, prepared +In God's eternal store, to circumscribe +This universe, and all created things: +One foot he centered, and the other turned +Round through the vast profundity obscure; +And said, Thus far extend, thus far thy bounds, +This be thy just circumference, O World! +Thus God the Heaven created, thus the Earth, +Matter unformed and void: Darkness profound +Covered the abyss: but on the watery calm +His brooding wings the Spirit of God outspread, +And vital virtue infused, and vital warmth +Throughout the fluid mass; but downward purged +The black tartareous cold infernal dregs, +Adverse to life: then founded, then conglobed +Like things to like; the rest to several place +Disparted, and between spun out the air; +And Earth self-balanced on her center hung. +Let there be light, said God; and forthwith Light +Ethereal, first of things, quintessence pure, +Sprung from the deep; and from her native east +To journey through the aery gloom began, +Sphered in a radiant cloud, for yet the sun +Was not; she in a cloudy tabernacle +Sojourned the while. God saw the light was good; +And light from darkness by the hemisphere +Divided: light the Day, and darkness Night, +He named. Thus was the first day even and morn: +Nor past uncelebrated, nor unsung +By the celestial quires, when orient light +Exhaling first from darkness they beheld; +Birth-day of Heaven and Earth; with joy and shout +The hollow universal orb they filled, +And touched their golden harps, and hymning praised +God and his works; Creator him they sung, +Both when first evening was, and when first morn. +Again, God said, Let there be firmament +Amid the waters, and let it divide +The waters from the waters; and God made +The firmament, expanse of liquid, pure, +Transparent, elemental air, diffused +In circuit to the uttermost convex +Of this great round; partition firm and sure, +The waters underneath from those above +Dividing: for as earth, so he the world +Built on circumfluous waters calm, in wide +Crystalline ocean, and the loud misrule +Of Chaos far removed; lest fierce extremes +Contiguous might distemper the whole frame: +And Heaven he named the Firmament: So even +And morning chorus sung the second day. +The Earth was formed, but in the womb as yet +Of waters, embryon immature involved, +Appeared not: over all the face of Earth +Main ocean flowed, not idle; but, with warm +Prolifick humour softening all her globe, +Fermented the great mother to conceive, +Satiate with genial moisture; when God said, +Be gathered now ye waters under Heaven +Into one place, and let dry land appear. +Immediately the mountains huge appear +Emergent, and their broad bare backs upheave +Into the clouds; their tops ascend the sky: +So high as heaved the tumid hills, so low +Down sunk a hollow bottom broad and deep, +Capacious bed of waters: Thither they +Hasted with glad precipitance, uprolled, +As drops on dust conglobing from the dry: +Part rise in crystal wall, or ridge direct, +For haste; such flight the great command impressed +On the swift floods: As armies at the call +Of trumpet (for of armies thou hast heard) +Troop to their standard; so the watery throng, +Wave rolling after wave, where way they found, +If steep, with torrent rapture, if through plain, +Soft-ebbing; nor withstood them rock or hill; +But they, or under ground, or circuit wide +With serpent errour wandering, found their way, +And on the washy oose deep channels wore; +Easy, ere God had bid the ground be dry, +All but within those banks, where rivers now +Stream, and perpetual draw their humid train. +The dry land, Earth; and the great receptacle +Of congregated waters, he called Seas: +And saw that it was good; and said, Let the Earth +Put forth the verdant grass, herb yielding seed, +And fruit-tree yielding fruit after her kind, +Whose seed is in herself upon the Earth. +He scarce had said, when the bare Earth, till then +Desart and bare, unsightly, unadorned, +Brought forth the tender grass, whose verdure clad +Her universal face with pleasant green; +Then herbs of every leaf, that sudden flowered +Opening their various colours, and made gay +Her bosom, smelling sweet: and, these scarce blown, +Forth flourished thick the clustering vine, forth crept +The swelling gourd, up stood the corny reed +Embattled in her field, and the humble shrub, +And bush with frizzled hair implicit: Last +Rose, as in dance, the stately trees, and spread +Their branches hung with copious fruit, or gemmed +Their blossoms: With high woods the hills were crowned; +With tufts the valleys, and each fountain side; +With borders long the rivers: that Earth now +Seemed like to Heaven, a seat where Gods might dwell, +Or wander with delight, and love to haunt +Her sacred shades: though God had yet not rained +Upon the Earth, and man to till the ground +None was; but from the Earth a dewy mist +Went up, and watered all the ground, and each +Plant of the field; which, ere it was in the Earth, +God made, and every herb, before it grew +On the green stem: God saw that it was good: +So even and morn recorded the third day. +Again the Almighty spake, Let there be lights +High in the expanse of Heaven, to divide +The day from night; and let them be for signs, +For seasons, and for days, and circling years; +And let them be for lights, as I ordain +Their office in the firmament of Heaven, +To give light on the Earth; and it was so. +And God made two great lights, great for their use +To Man, the greater to have rule by day, +The less by night, altern; and made the stars, +And set them in the firmament of Heaven +To illuminate the Earth, and rule the day +In their vicissitude, and rule the night, +And light from darkness to divide. God saw, +Surveying his great work, that it was good: +For of celestial bodies first the sun +A mighty sphere he framed, unlightsome first, +Though of ethereal mould: then formed the moon +Globose, and every magnitude of stars, +And sowed with stars the Heaven, thick as a field: +Of light by far the greater part he took, +Transplanted from her cloudy shrine, and placed +In the sun's orb, made porous to receive +And drink the liquid light; firm to retain +Her gathered beams, great palace now of light. +Hither, as to their fountain, other stars +Repairing, in their golden urns draw light, +And hence the morning-planet gilds her horns; +By tincture or reflection they augment +Their small peculiar, though from human sight +So far remote, with diminution seen, +First in his east the glorious lamp was seen, +Regent of day, and all the horizon round +Invested with bright rays, jocund to run +His longitude through Heaven's high road; the gray +Dawn, and the Pleiades, before him danced, +Shedding sweet influence: Less bright the moon, +But opposite in levelled west was set, +His mirrour, with full face borrowing her light +From him; for other light she needed none +In that aspect, and still that distance keeps +Till night; then in the east her turn she shines, +Revolved on Heaven's great axle, and her reign +With thousand lesser lights dividual holds, +With thousand thousand stars, that then appeared +Spangling the hemisphere: Then first adorned +With their bright luminaries that set and rose, +Glad evening and glad morn crowned the fourth day. +And God said, Let the waters generate +Reptile with spawn abundant, living soul: +And let fowl fly above the Earth, with wings +Displayed on the open firmament of Heaven. +And God created the great whales, and each +Soul living, each that crept, which plenteously +The waters generated by their kinds; +And every bird of wing after his kind; +And saw that it was good, and blessed them, saying. +Be fruitful, multiply, and in the seas, +And lakes, and running streams, the waters fill; +And let the fowl be multiplied, on the Earth. +Forthwith the sounds and seas, each creek and bay, +With fry innumerable swarm, and shoals +Of fish that with their fins, and shining scales, +Glide under the green wave, in sculls that oft +Bank the mid sea: part single, or with mate, +Graze the sea-weed their pasture, and through groves +Of coral stray; or, sporting with quick glance, +Show to the sun their waved coats dropt with gold; +Or, in their pearly shells at ease, attend +Moist nutriment; or under rocks their food +In jointed armour watch: on smooth the seal +And bended dolphins play: part huge of bulk +Wallowing unwieldy, enormous in their gait, +Tempest the ocean: there leviathan, +Hugest of living creatures, on the deep +Stretched like a promontory sleeps or swims, +And seems a moving land; and at his gills +Draws in, and at his trunk spouts out, a sea. +Mean while the tepid caves, and fens, and shores, +Their brood as numerous hatch, from the egg that soon +Bursting with kindly rupture forth disclosed +Their callow young; but feathered soon and fledge +They summed their pens; and, soaring the air sublime, +With clang despised the ground, under a cloud +In prospect; there the eagle and the stork +On cliffs and cedar tops their eyries build: +Part loosely wing the region, part more wise +In common, ranged in figure, wedge their way, +Intelligent of seasons, and set forth +Their aery caravan, high over seas +Flying, and over lands, with mutual wing +Easing their flight; so steers the prudent crane +Her annual voyage, borne on winds; the air +Floats as they pass, fanned with unnumbered plumes: +From branch to branch the smaller birds with song +Solaced the woods, and spread their painted wings +Till even; nor then the solemn nightingale +Ceased warbling, but all night tun'd her soft lays: +Others, on silver lakes and rivers, bathed +Their downy breast; the swan with arched neck, +Between her white wings mantling proudly, rows +Her state with oary feet; yet oft they quit +The dank, and, rising on stiff pennons, tower +The mid aereal sky: Others on ground +Walked firm; the crested cock whose clarion sounds +The silent hours, and the other whose gay train +Adorns him, coloured with the florid hue +Of rainbows and starry eyes. The waters thus +With fish replenished, and the air with fowl, +Evening and morn solemnized the fifth day. +The sixth, and of creation last, arose +With evening harps and matin; when God said, +Let the Earth bring forth soul living in her kind, +Cattle, and creeping things, and beast of the Earth, +Each in their kind. The Earth obeyed, and straight +Opening her fertile womb teemed at a birth +Innumerous living creatures, perfect forms, +Limbed and full grown: Out of the ground up rose, +As from his lair, the wild beast where he wons +In forest wild, in thicket, brake, or den; +Among the trees in pairs they rose, they walked: +The cattle in the fields and meadows green: +Those rare and solitary, these in flocks +Pasturing at once, and in broad herds upsprung. +The grassy clods now calved; now half appeared +The tawny lion, pawing to get free +His hinder parts, then springs as broke from bonds, +And rampant shakes his brinded mane; the ounce, +The libbard, and the tiger, as the mole +Rising, the crumbled earth above them threw +In hillocks: The swift stag from under ground +Bore up his branching head: Scarce from his mould +Behemoth biggest born of earth upheaved +His vastness: Fleeced the flocks and bleating rose, +As plants: Ambiguous between sea and land +The river-horse, and scaly crocodile. +At once came forth whatever creeps the ground, +Insect or worm: those waved their limber fans +For wings, and smallest lineaments exact +In all the liveries decked of summer's pride +With spots of gold and purple, azure and green: +These, as a line, their long dimension drew, +Streaking the ground with sinuous trace; not all +Minims of nature; some of serpent-kind, +Wonderous in length and corpulence, involved +Their snaky folds, and added wings. First crept +The parsimonious emmet, provident +Of future; in small room large heart enclosed; +Pattern of just equality perhaps +Hereafter, joined in her popular tribes +Of commonalty: Swarming next appeared +The female bee, that feeds her husband drone +Deliciously, and builds her waxen cells +With honey stored: The rest are numberless, +And thou their natures knowest, and gavest them names, +Needless to thee repeated; nor unknown +The serpent, subtlest beast of all the field, +Of huge extent sometimes, with brazen eyes +And hairy mane terrifick, though to thee +Not noxious, but obedient at thy call. +Now Heaven in all her glory shone, and rolled +Her motions, as the great first Mover's hand +First wheeled their course: Earth in her rich attire +Consummate lovely smiled; air, water, earth, +By fowl, fish, beast, was flown, was swum, was walked, +Frequent; and of the sixth day yet remained: +There wanted yet the master-work, the end +Of all yet done; a creature, who, not prone +And brute as other creatures, but endued +With sanctity of reason, might erect +His stature, and upright with front serene +Govern the rest, self-knowing; and from thence +Magnanimous to correspond with Heaven, +But grateful to acknowledge whence his good +Descends, thither with heart, and voice, and eyes +Directed in devotion, to adore +And worship God Supreme, who made him chief +Of all his works: therefore the Omnipotent +Eternal Father (for where is not he +Present?) thus to his Son audibly spake. +Let us make now Man in our image, Man +In our similitude, and let them rule +Over the fish and fowl of sea and air, +Beast of the field, and over all the Earth, +And every creeping thing that creeps the ground. +This said, he formed thee, Adam, thee, O Man, +Dust of the ground, and in thy nostrils breathed +The breath of life; in his own image he +Created thee, in the image of God +Express; and thou becamest a living soul. +Male he created thee; but thy consort +Female, for race; then blessed mankind, and said, +Be fruitful, multiply, and fill the Earth; +Subdue it, and throughout dominion hold +Over fish of the sea, and fowl of the air, +And every living thing that moves on the Earth. +Wherever thus created, for no place +Is yet distinct by name, thence, as thou knowest, +He brought thee into this delicious grove, +This garden, planted with the trees of God, +Delectable both to behold and taste; +And freely all their pleasant fruit for food +Gave thee; all sorts are here that all the Earth yields, +Variety without end; but of the tree, +Which, tasted, works knowledge of good and evil, +Thou mayest not; in the day thou eatest, thou diest; +Death is the penalty imposed; beware, +And govern well thy appetite; lest Sin +Surprise thee, and her black attendant Death. +Here finished he, and all that he had made +Viewed, and behold all was entirely good; +So even and morn accomplished the sixth day: +Yet not till the Creator from his work +Desisting, though unwearied, up returned, +Up to the Heaven of Heavens, his high abode; +Thence to behold this new created world, +The addition of his empire, how it showed +In prospect from his throne, how good, how fair, +Answering his great idea. Up he rode +Followed with acclamation, and the sound +Symphonious of ten thousand harps, that tuned +Angelick harmonies: The earth, the air +Resounded, (thou rememberest, for thou heardst,) +The heavens and all the constellations rung, +The planets in their station listening stood, +While the bright pomp ascended jubilant. +Open, ye everlasting gates! they sung, +Open, ye Heavens! your living doors;let in +The great Creator from his work returned +Magnificent, his six days work, a World; +Open, and henceforth oft; for God will deign +To visit oft the dwellings of just men, +Delighted; and with frequent intercourse +Thither will send his winged messengers +On errands of supernal grace. So sung +The glorious train ascending: He through Heaven, +That opened wide her blazing portals, led +To God's eternal house direct the way; +A broad and ample road, whose dust is gold +And pavement stars, as stars to thee appear, +Seen in the galaxy, that milky way, +Which nightly, as a circling zone, thou seest +Powdered with stars. And now on Earth the seventh +Evening arose in Eden, for the sun +Was set, and twilight from the east came on, +Forerunning night; when at the holy mount +Of Heaven's high-seated top, the imperial throne +Of Godhead, fixed for ever firm and sure, +The Filial Power arrived, and sat him down +With his great Father; for he also went +Invisible, yet staid, (such privilege +Hath Omnipresence) and the work ordained, +Author and End of all things; and, from work +Now resting, blessed and hallowed the seventh day, +As resting on that day from all his work, +But not in silence holy kept: the harp +Had work and rested not; the solemn pipe, +And dulcimer, all organs of sweet stop, +All sounds on fret by string or golden wire, +Tempered soft tunings, intermixed with voice +Choral or unison: of incense clouds, +Fuming from golden censers, hid the mount. +Creation and the six days acts they sung: +Great are thy works, Jehovah! infinite +Thy power! what thought can measure thee, or tongue +Relate thee! Greater now in thy return +Than from the giant Angels: Thee that day +Thy thunders magnified; but to create +Is greater than created to destroy. +Who can impair thee, Mighty King, or bound +Thy empire! Easily the proud attempt +Of Spirits apostate, and their counsels vain, +Thou hast repelled; while impiously they thought +Thee to diminish, and from thee withdraw +The number of thy worshippers. Who seeks +To lessen thee, against his purpose serves +To manifest the more thy might: his evil +Thou usest, and from thence createst more good. +Witness this new-made world, another Heaven +From Heaven-gate not far, founded in view +On the clear hyaline, the glassy sea; +Of amplitude almost immense, with stars +Numerous, and every star perhaps a world +Of destined habitation; but thou knowest +Their seasons: among these the seat of Men, +Earth, with her nether ocean circumfused, +Their pleasant dwelling-place. Thrice happy Men, +And sons of Men, whom God hath thus advanced! +Created in his image, there to dwell +And worship him; and in reward to rule +Over his works, on earth, in sea, or air, +And multiply a race of worshippers +Holy and just: Thrice happy, if they know +Their happiness, and persevere upright! +So sung they, and the empyrean rung +With halleluiahs: Thus was sabbath kept. +And thy request think now fulfilled, that asked +How first this world and face of things began, +And what before thy memory was done +From the beginning; that posterity, +Informed by thee, might know: If else thou seekest +Aught, not surpassing human measure, say. + + + +Book VIII + + +The Angel ended, and in Adam's ear +So charming left his voice, that he a while +Thought him still speaking, still stood fixed to hear; +Then, as new waked, thus gratefully replied. +What thanks sufficient, or what recompence +Equal, have I to render thee, divine +Historian, who thus largely hast allayed +The thirst I had of knowledge, and vouchsafed +This friendly condescension to relate +Things, else by me unsearchable; now heard +With wonder, but delight, and, as is due, +With glory attributed to the high +Creator! Something yet of doubt remains, +Which only thy solution can resolve. +When I behold this goodly frame, this world, +Of Heaven and Earth consisting; and compute +Their magnitudes; this Earth, a spot, a grain, +An atom, with the firmament compared +And all her numbered stars, that seem to roll +Spaces incomprehensible, (for such +Their distance argues, and their swift return +Diurnal,) merely to officiate light +Round this opacous Earth, this punctual spot, +One day and night; in all her vast survey +Useless besides; reasoning I oft admire, +How Nature wise and frugal could commit +Such disproportions, with superfluous hand +So many nobler bodies to create, +Greater so manifold, to this one use, +For aught appears, and on their orbs impose +Such restless revolution day by day +Repeated; while the sedentary Earth, +That better might with far less compass move, +Served by more noble than herself, attains +Her end without least motion, and receives, +As tribute, such a sumless journey brought +Of incorporeal speed, her warmth and light; +Speed, to describe whose swiftness number fails. +So spake our sire, and by his countenance seemed +Entering on studious thoughts abstruse; which Eve +Perceiving, where she sat retired in sight, +With lowliness majestick from her seat, +And grace that won who saw to wish her stay, +Rose, and went forth among her fruits and flowers, +To visit how they prospered, bud and bloom, +Her nursery; they at her coming sprung, +And, touched by her fair tendance, gladlier grew. +Yet went she not, as not with such discourse +Delighted, or not capable her ear +Of what was high: such pleasure she reserved, +Adam relating, she sole auditress; +Her husband the relater she preferred +Before the Angel, and of him to ask +Chose rather; he, she knew, would intermix +Grateful digressions, and solve high dispute +With conjugal caresses: from his lip +Not words alone pleased her. O! when meet now +Such pairs, in love and mutual honour joined? +With Goddess-like demeanour forth she went, +Not unattended; for on her, as Queen, +A pomp of winning Graces waited still, +And from about her shot darts of desire +Into all eyes, to wish her still in sight. +And Raphael now, to Adam's doubt proposed, +Benevolent and facile thus replied. +To ask or search, I blame thee not; for Heaven +Is as the book of God before thee set, +Wherein to read his wonderous works, and learn +His seasons, hours, or days, or months, or years: +This to attain, whether Heaven move or Earth, +Imports not, if thou reckon right; the rest +From Man or Angel the great Architect +Did wisely to conceal, and not divulge +His secrets to be scanned by them who ought +Rather admire; or, if they list to try +Conjecture, he his fabrick of the Heavens +Hath left to their disputes, perhaps to move +His laughter at their quaint opinions wide +Hereafter; when they come to model Heaven +And calculate the stars, how they will wield +The mighty frame; how build, unbuild, contrive +To save appearances; how gird the sphere +With centrick and eccentrick scribbled o'er, +Cycle and epicycle, orb in orb: +Already by thy reasoning this I guess, +Who art to lead thy offspring, and supposest +That bodies bright and greater should not serve +The less not bright, nor Heaven such journeys run, +Earth sitting still, when she alone receives +The benefit: Consider first, that great +Or bright infers not excellence: the Earth +Though, in comparison of Heaven, so small, +Nor glistering, may of solid good contain +More plenty than the sun that barren shines; +Whose virtue on itself works no effect, +But in the fruitful Earth; there first received, +His beams, unactive else, their vigour find. +Yet not to Earth are those bright luminaries +Officious; but to thee, Earth's habitant. +And for the Heaven's wide circuit, let it speak +The Maker's high magnificence, who built +So spacious, and his line stretched out so far; +That Man may know he dwells not in his own; +An edifice too large for him to fill, +Lodged in a small partition; and the rest +Ordained for uses to his Lord best known. +The swiftness of those circles attribute, +Though numberless, to his Omnipotence, +That to corporeal substances could add +Speed almost spiritual: Me thou thinkest not slow, +Who since the morning-hour set out from Heaven +Where God resides, and ere mid-day arrived +In Eden; distance inexpressible +By numbers that have name. But this I urge, +Admitting motion in the Heavens, to show +Invalid that which thee to doubt it moved; +Not that I so affirm, though so it seem +To thee who hast thy dwelling here on Earth. +God, to remove his ways from human sense, +Placed Heaven from Earth so far, that earthly sight, +If it presume, might err in things too high, +And no advantage gain. What if the sun +Be center to the world; and other stars, +By his attractive virtue and their own +Incited, dance about him various rounds? +Their wandering course now high, now low, then hid, +Progressive, retrograde, or standing still, +In six thou seest; and what if seventh to these +The planet earth, so stedfast though she seem, +Insensibly three different motions move? +Which else to several spheres thou must ascribe, +Moved contrary with thwart obliquities; +Or save the sun his labour, and that swift +Nocturnal and diurnal rhomb supposed, +Invisible else above all stars, the wheel +Of day and night; which needs not thy belief, +If earth, industrious of herself, fetch day +Travelling east, and with her part averse +From the sun's beam meet night, her other part +Still luminous by his ray. What if that light, +Sent from her through the wide transpicuous air, +To the terrestrial moon be as a star, +Enlightening her by day, as she by night +This earth? reciprocal, if land be there, +Fields and inhabitants: Her spots thou seest +As clouds, and clouds may rain, and rain produce +Fruits in her softened soil for some to eat +Allotted there; and other suns perhaps, +With their attendant moons, thou wilt descry, +Communicating male and female light; +Which two great sexes animate the world, +Stored in each orb perhaps with some that live. +For such vast room in Nature unpossessed +By living soul, desart and desolate, +Only to shine, yet scarce to contribute +Each orb a glimpse of light, conveyed so far +Down to this habitable, which returns +Light back to them, is obvious to dispute. +But whether thus these things, or whether not; +But whether the sun, predominant in Heaven, +Rise on the earth; or earth rise on the sun; +He from the east his flaming road begin; +Or she from west her silent course advance, +With inoffensive pace that spinning sleeps +On her soft axle, while she paces even, +And bears thee soft with the smooth hair along; +Sollicit not thy thoughts with matters hid; +Leave them to God above; him serve, and fear! +Of other creatures, as him pleases best, +Wherever placed, let him dispose; joy thou +In what he gives to thee, this Paradise +And thy fair Eve; Heaven is for thee too high +To know what passes there; be lowly wise: +Think only what concerns thee, and thy being; +Dream not of other worlds, what creatures there +Live, in what state, condition, or degree; +Contented that thus far hath been revealed +Not of Earth only, but of highest Heaven. +To whom thus Adam, cleared of doubt, replied. +How fully hast thou satisfied me, pure +Intelligence of Heaven, Angel serene! +And, freed from intricacies, taught to live +The easiest way; nor with perplexing thoughts +To interrupt the sweet of life, from which +God hath bid dwell far off all anxious cares, +And not molest us; unless we ourselves +Seek them with wandering thoughts, and notions vain. +But apt the mind or fancy is to rove +Unchecked, and of her roving is no end; +Till warned, or by experience taught, she learn, +That, not to know at large of things remote +From use, obscure and subtle; but, to know +That which before us lies in daily life, +Is the prime wisdom: What is more, is fume, +Or emptiness, or fond impertinence: +And renders us, in things that most concern, +Unpractised, unprepared, and still to seek. +Therefore from this high pitch let us descend +A lower flight, and speak of things at hand +Useful; whence, haply, mention may arise +Of something not unseasonable to ask, +By sufferance, and thy wonted favour, deigned. +Thee I have heard relating what was done +Ere my remembrance: now, hear me relate +My story, which perhaps thou hast not heard; +And day is not yet spent; till then thou seest +How subtly to detain thee I devise; +Inviting thee to hear while I relate; +Fond! were it not in hope of thy reply: +For, while I sit with thee, I seem in Heaven; +And sweeter thy discourse is to my ear +Than fruits of palm-tree pleasantest to thirst +And hunger both, from labour, at the hour +Of sweet repast; they satiate, and soon fill, +Though pleasant; but thy words, with grace divine +Imbued, bring to their sweetness no satiety. +To whom thus Raphael answered heavenly meek. +Nor are thy lips ungraceful, Sire of men, +Nor tongue ineloquent; for God on thee +Abundantly his gifts hath also poured +Inward and outward both, his image fair: +Speaking, or mute, all comeliness and grace +Attends thee; and each word, each motion, forms; +Nor less think we in Heaven of thee on Earth +Than of our fellow-servant, and inquire +Gladly into the ways of God with Man: +For God, we see, hath honoured thee, and set +On Man his equal love: Say therefore on; +For I that day was absent, as befel, +Bound on a voyage uncouth and obscure, +Far on excursion toward the gates of Hell; +Squared in full legion (such command we had) +To see that none thence issued forth a spy, +Or enemy, while God was in his work; +Lest he, incensed at such eruption bold, +Destruction with creation might have mixed. +Not that they durst without his leave attempt; +But us he sends upon his high behests +For state, as Sovran King; and to inure +Our prompt obedience. Fast we found, fast shut, +The dismal gates, and barricadoed strong; +But long ere our approaching heard within +Noise, other than the sound of dance or song, +Torment, and loud lament, and furious rage. +Glad we returned up to the coasts of light +Ere sabbath-evening: so we had in charge. +But thy relation now; for I attend, +Pleased with thy words no less than thou with mine. +So spake the Godlike Power, and thus our Sire. +For Man to tell how human life began +Is hard; for who himself beginning knew +Desire with thee still longer to converse +Induced me. As new waked from soundest sleep, +Soft on the flowery herb I found me laid, +In balmy sweat; which with his beams the sun +Soon dried, and on the reeking moisture fed. +Straight toward Heaven my wondering eyes I turned, +And gazed a while the ample sky; till, raised +By quick instinctive motion, up I sprung, +As thitherward endeavouring, and upright +Stood on my feet: about me round I saw +Hill, dale, and shady woods, and sunny plains, +And liquid lapse of murmuring streams; by these, +Creatures that lived and moved, and walked, or flew; +Birds on the branches warbling; all things smiled; +With fragrance and with joy my heart o'erflowed. +Myself I then perused, and limb by limb +Surveyed, and sometimes went, and sometimes ran +With supple joints, as lively vigour led: +But who I was, or where, or from what cause, +Knew not; to speak I tried, and forthwith spake; +My tongue obeyed, and readily could name +Whate'er I saw. Thou Sun, said I, fair light, +And thou enlightened Earth, so fresh and gay, +Ye Hills, and Dales, ye Rivers, Woods, and Plains, +And ye that live and move, fair Creatures, tell, +Tell, if ye saw, how I came thus, how here?-- +Not of myself;--by some great Maker then, +In goodness and in power pre-eminent: +Tell me, how may I know him, how adore, +From whom I have that thus I move and live, +And feel that I am happier than I know.-- +While thus I called, and strayed I knew not whither, +From where I first drew air, and first beheld +This happy light; when, answer none returned, +On a green shady bank, profuse of flowers, +Pensive I sat me down: There gentle sleep +First found me, and with soft oppression seised +My droused sense, untroubled, though I thought +I then was passing to my former state +Insensible, and forthwith to dissolve: +When suddenly stood at my head a dream, +Whose inward apparition gently moved +My fancy to believe I yet had being, +And lived: One came, methought, of shape divine, +And said, 'Thy mansion wants thee, Adam; rise, +'First Man, of men innumerable ordained +'First Father! called by thee, I come thy guide +'To the garden of bliss, thy seat prepared.' +So saying, by the hand he took me raised, +And over fields and waters, as in air +Smooth-sliding without step, last led me up +A woody mountain; whose high top was plain, +A circuit wide, enclosed, with goodliest trees +Planted, with walks, and bowers; that what I saw +Of Earth before scarce pleasant seemed. Each tree, +Loaden with fairest fruit that hung to the eye +Tempting, stirred in me sudden appetite +To pluck and eat; whereat I waked, and found +Before mine eyes all real, as the dream +Had lively shadowed: Here had new begun +My wandering, had not he, who was my guide +Up hither, from among the trees appeared, +Presence Divine. Rejoicing, but with awe, +In adoration at his feet I fell +Submiss: He reared me, and 'Whom thou soughtest I am,' +Said mildly, 'Author of all this thou seest +'Above, or round about thee, or beneath. +'This Paradise I give thee, count it thine +'To till and keep, and of the fruit to eat: +'Of every tree that in the garden grows +'Eat freely with glad heart; fear here no dearth: +'But of the tree whose operation brings +'Knowledge of good and ill, which I have set +'The pledge of thy obedience and thy faith, +'Amid the garden by the tree of life, +'Remember what I warn thee, shun to taste, +'And shun the bitter consequence: for know, +'The day thou eatest thereof, my sole command +'Transgressed, inevitably thou shalt die, +'From that day mortal; and this happy state +'Shalt lose, expelled from hence into a world +'Of woe and sorrow.' Sternly he pronounced +The rigid interdiction, which resounds +Yet dreadful in mine ear, though in my choice +Not to incur; but soon his clear aspect +Returned, and gracious purpose thus renewed. +'Not only these fair bounds, but all the Earth +'To thee and to thy race I give; as lords +'Possess it, and all things that therein live, +'Or live in sea, or air; beast, fish, and fowl. +'In sign whereof, each bird and beast behold +'After their kinds; I bring them to receive +'From thee their names, and pay thee fealty +'With low subjection; understand the same +'Of fish within their watery residence, +'Not hither summoned, since they cannot change +'Their element, to draw the thinner air.' +As thus he spake, each bird and beast behold +Approaching two and two; these cowering low +With blandishment; each bird stooped on his wing. +I named them, as they passed, and understood +Their nature, with such knowledge God endued +My sudden apprehension: But in these +I found not what methought I wanted still; +And to the heavenly Vision thus presumed. +O, by what name, for thou above all these, +Above mankind, or aught than mankind higher, +Surpassest far my naming; how may I +Adore thee, Author of this universe, +And all this good to man? for whose well being +So amply, and with hands so liberal, +Thou hast provided all things: But with me +I see not who partakes. In solitude +What happiness, who can enjoy alone, +Or, all enjoying, what contentment find? +Thus I presumptuous; and the Vision bright, +As with a smile more brightened, thus replied. +What callest thou solitude? Is not the Earth +With various living creatures, and the air +Replenished, and all these at thy command +To come and play before thee? Knowest thou not +Their language and their ways? They also know, +And reason not contemptibly: With these +Find pastime, and bear rule; thy realm is large. +So spake the Universal Lord, and seemed +So ordering: I, with leave of speech implored, +And humble deprecation, thus replied. +Let not my words offend thee, Heavenly Power; +My Maker, be propitious while I speak. +Hast thou not made me here thy substitute, +And these inferiour far beneath me set? +Among unequals what society +Can sort, what harmony, or true delight? +Which must be mutual, in proportion due +Given and received; but, in disparity +The one intense, the other still remiss, +Cannot well suit with either, but soon prove +Tedious alike: Of fellowship I speak +Such as I seek, fit to participate +All rational delight: wherein the brute +Cannot be human consort: They rejoice +Each with their kind, lion with lioness; +So fitly them in pairs thou hast combined: +Much less can bird with beast, or fish with fowl +So well converse, nor with the ox the ape; +Worse then can man with beast, and least of all. +Whereto the Almighty answered, not displeased. +A nice and subtle happiness, I see, +Thou to thyself proposest, in the choice +Of thy associates, Adam! and wilt taste +No pleasure, though in pleasure, solitary. +What thinkest thou then of me, and this my state? +Seem I to thee sufficiently possessed +Of happiness, or not? who am alone +From all eternity; for none I know +Second to me or like, equal much less. +How have I then with whom to hold converse, +Save with the creatures which I made, and those +To me inferiour, infinite descents +Beneath what other creatures are to thee? +He ceased; I lowly answered. To attain +The highth and depth of thy eternal ways +All human thoughts come short, Supreme of things! +Thou in thyself art perfect, and in thee +Is no deficience found: Not so is Man, +But in degree; the cause of his desire +By conversation with his like to help +Or solace his defects. No need that thou +Shouldst propagate, already Infinite; +And through all numbers absolute, though One: +But Man by number is to manifest +His single imperfection, and beget +Like of his like, his image multiplied, +In unity defective; which requires +Collateral love, and dearest amity. +Thou in thy secresy although alone, +Best with thyself accompanied, seekest not +Social communication; yet, so pleased, +Canst raise thy creature to what highth thou wilt +Of union or communion, deified: +I, by conversing, cannot these erect +From prone; nor in their ways complacence find. +Thus I emboldened spake, and freedom used +Permissive, and acceptance found; which gained +This answer from the gracious Voice Divine. +Thus far to try thee, Adam, I was pleased; +And find thee knowing, not of beasts alone, +Which thou hast rightly named, but of thyself; +Expressing well the spirit within thee free, +My image, not imparted to the brute; +Whose fellowship therefore unmeet for thee +Good reason was thou freely shouldst dislike; +And be so minded still: I, ere thou spakest, +Knew it not good for Man to be alone; +And no such company as then thou sawest +Intended thee; for trial only brought, +To see how thou couldest judge of fit and meet: +What next I bring shall please thee, be assured, +Thy likeness, thy fit help, thy other self, +Thy wish exactly to thy heart's desire. +He ended, or I heard no more; for now +My earthly by his heavenly overpowered, +Which it had long stood under, strained to the highth +In that celestial colloquy sublime, +As with an object that excels the sense +Dazzled and spent, sunk down; and sought repair +Of sleep, which instantly fell on me, called +By Nature as in aid, and closed mine eyes. +Mine eyes he closed, but open left the cell +Of fancy, my internal sight; by which, +Abstract as in a trance, methought I saw, +Though sleeping, where I lay, and saw the shape +Still glorious before whom awake I stood: +Who stooping opened my left side, and took +From thence a rib, with cordial spirits warm, +And life-blood streaming fresh; wide was the wound, +But suddenly with flesh filled up and healed: +The rib he formed and fashioned with his hands; +Under his forming hands a creature grew, +Man-like, but different sex; so lovely fair, +That what seemed fair in all the world, seemed now +Mean, or in her summed up, in her contained +And in her looks; which from that time infused +Sweetness into my heart, unfelt before, +And into all things from her air inspired +The spirit of love and amorous delight. +She disappeared, and left me dark; I waked +To find her, or for ever to deplore +Her loss, and other pleasures all abjure: +When out of hope, behold her, not far off, +Such as I saw her in my dream, adorned +With what all Earth or Heaven could bestow +To make her amiable: On she came, +Led by her heavenly Maker, though unseen, +And guided by his voice; nor uninformed +Of nuptial sanctity, and marriage rites: +Grace was in all her steps, Heaven in her eye, +In every gesture dignity and love. +I, overjoyed, could not forbear aloud. +This turn hath made amends; thou hast fulfilled +Thy words, Creator bounteous and benign, +Giver of all things fair! but fairest this +Of all thy gifts! nor enviest. I now see +Bone of my bone, flesh of my flesh, myself +Before me: Woman is her name;of Man +Extracted: for this cause he shall forego +Father and mother, and to his wife adhere; +And they shall be one flesh, one heart, one soul. +She heard me thus; and though divinely brought, +Yet innocence, and virgin modesty, +Her virtue, and the conscience of her worth, +That would be wooed, and not unsought be won, +Not obvious, not obtrusive, but, retired, +The more desirable; or, to say all, +Nature herself, though pure of sinful thought, +Wrought in her so, that, seeing me, she turned: +I followed her; she what was honour knew, +And with obsequious majesty approved +My pleaded reason. To the nuptial bower +I led her blushing like the morn: All Heaven, +And happy constellations, on that hour +Shed their selectest influence; the Earth +Gave sign of gratulation, and each hill; +Joyous the birds; fresh gales and gentle airs +Whispered it to the woods, and from their wings +Flung rose, flung odours from the spicy shrub, +Disporting, till the amorous bird of night +Sung spousal, and bid haste the evening-star +On his hill top, to light the bridal lamp. +Thus have I told thee all my state, and brought +My story to the sum of earthly bliss, +Which I enjoy; and must confess to find +In all things else delight indeed, but such +As, used or not, works in the mind no change, +Nor vehement desire; these delicacies +I mean of taste, sight, smell, herbs, fruits, and flowers, +Walks, and the melody of birds: but here +Far otherwise, transported I behold, +Transported touch; here passion first I felt, +Commotion strange! in all enjoyments else +Superiour and unmoved; here only weak +Against the charm of Beauty's powerful glance. +Or Nature failed in me, and left some part +Not proof enough such object to sustain; +Or, from my side subducting, took perhaps +More than enough; at least on her bestowed +Too much of ornament, in outward show +Elaborate, of inward less exact. +For well I understand in the prime end +Of Nature her the inferiour, in the mind +And inward faculties, which most excel; +In outward also her resembling less +His image who made both, and less expressing +The character of that dominion given +O'er other creatures: Yet when I approach +Her loveliness, so absolute she seems +And in herself complete, so well to know +Her own, that what she wills to do or say, +Seems wisest, virtuousest, discreetest, best: +All higher knowledge in her presence falls +Degraded; Wisdom in discourse with her +Loses discountenanced, and like Folly shows; +Authority and Reason on her wait, +As one intended first, not after made +Occasionally; and, to consummate all, +Greatness of mind and Nobleness their seat +Build in her loveliest, and create an awe +About her, as a guard angelick placed. +To whom the Angel with contracted brow. +Accuse not Nature, she hath done her part; +Do thou but thine; and be not diffident +Of Wisdom; she deserts thee not, if thou +Dismiss not her, when most thou needest her nigh, +By attributing overmuch to things +Less excellent, as thou thyself perceivest. +For, what admirest thou, what transports thee so, +An outside? fair, no doubt, and worthy well +Thy cherishing, thy honouring, and thy love; +Not thy subjection: Weigh with her thyself; +Then value: Oft-times nothing profits more +Than self-esteem, grounded on just and right +Well managed; of that skill the more thou knowest, +The more she will acknowledge thee her head, +And to realities yield all her shows: +Made so adorn for thy delight the more, +So awful, that with honour thou mayest love +Thy mate, who sees when thou art seen least wise. +But if the sense of touch, whereby mankind +Is propagated, seem such dear delight +Beyond all other; think the same vouchsafed +To cattle and each beast; which would not be +To them made common and divulged, if aught +Therein enjoyed were worthy to subdue +The soul of man, or passion in him move. +What higher in her society thou findest +Attractive, human, rational, love still; +In loving thou dost well, in passion not, +Wherein true love consists not: Love refines +The thoughts, and heart enlarges; hath his seat +In reason, and is judicious; is the scale +By which to heavenly love thou mayest ascend, +Not sunk in carnal pleasure; for which cause, +Among the beasts no mate for thee was found. +To whom thus, half abashed, Adam replied. +Neither her outside formed so fair, nor aught +In procreation common to all kinds, +(Though higher of the genial bed by far, +And with mysterious reverence I deem,) +So much delights me, as those graceful acts, +Those thousand decencies, that daily flow +From all her words and actions mixed with love +And sweet compliance, which declare unfeigned +Union of mind, or in us both one soul; +Harmony to behold in wedded pair +More grateful than harmonious sound to the ear. +Yet these subject not; I to thee disclose +What inward thence I feel, not therefore foiled, +Who meet with various objects, from the sense +Variously representing; yet, still free, +Approve the best, and follow what I approve. +To love, thou blamest me not; for Love, thou sayest, +Leads up to Heaven, is both the way and guide; +Bear with me then, if lawful what I ask: +Love not the heavenly Spirits, and how their love +Express they? by looks only? or do they mix +Irradiance, virtual or immediate touch? +To whom the Angel, with a smile that glowed +Celestial rosy red, Love's proper hue, +Answered. Let it suffice thee that thou knowest +Us happy, and without love no happiness. +Whatever pure thou in the body enjoyest, +(And pure thou wert created) we enjoy +In eminence; and obstacle find none +Of membrane, joint, or limb, exclusive bars; +Easier than air with air, if Spirits embrace, +Total they mix, union of pure with pure +Desiring, nor restrained conveyance need, +As flesh to mix with flesh, or soul with soul. +But I can now no more; the parting sun +Beyond the Earth's green Cape and verdant Isles +Hesperian sets, my signal to depart. +Be strong, live happy, and love! But, first of all, +Him, whom to love is to obey, and keep +His great command; take heed lest passion sway +Thy judgement to do aught, which else free will +Would not admit: thine, and of all thy sons, +The weal or woe in thee is placed; beware! +I in thy persevering shall rejoice, +And all the Blest: Stand fast;to stand or fall +Free in thine own arbitrement it lies. +Perfect within, no outward aid require; +And all temptation to transgress repel. +So saying, he arose; whom Adam thus +Followed with benediction. Since to part, +Go, heavenly guest, ethereal Messenger, +Sent from whose sovran goodness I adore! +Gentle to me and affable hath been +Thy condescension, and shall be honoured ever +With grateful memory: Thou to mankind +Be good and friendly still, and oft return! +So parted they; the Angel up to Heaven +From the thick shade, and Adam to his bower. + + + +Book IX + + +No more of talk where God or Angel guest +With Man, as with his friend, familiar us'd, +To sit indulgent, and with him partake +Rural repast; permitting him the while +Venial discourse unblam'd. I now must change +Those notes to tragick; foul distrust, and breach +Disloyal on the part of Man, revolt, +And disobedience: on the part of Heaven +Now alienated, distance and distaste, +Anger and just rebuke, and judgement given, +That brought into this world a world of woe, +Sin and her shadow Death, and Misery +Death's harbinger: Sad talk!yet argument +Not less but more heroick than the wrath +Of stern Achilles on his foe pursued +Thrice fugitive about Troy wall; or rage +Of Turnus for Lavinia disespous'd; +Or Neptune's ire, or Juno's, that so long +Perplexed the Greek, and Cytherea's son: + + 00482129 +If answerable style I can obtain +Of my celestial patroness, who deigns +Her nightly visitation unimplor'd, +And dictates to me slumbering; or inspires +Easy my unpremeditated verse: +Since first this subject for heroick song +Pleas'd me long choosing, and beginning late; +Not sedulous by nature to indite +Wars, hitherto the only argument +Heroick deem'd chief mastery to dissect +With long and tedious havock fabled knights +In battles feign'd; the better fortitude +Of patience and heroick martyrdom +Unsung; or to describe races and games, +Or tilting furniture, imblazon'd shields, +Impresses quaint, caparisons and steeds, +Bases and tinsel trappings, gorgeous knights +At joust and tournament; then marshall'd feast +Serv'd up in hall with sewers and seneshals; +The skill of artifice or office mean, +Not that which justly gives heroick name +To person, or to poem. Me, of these +Nor skill'd nor studious, higher argument +Remains; sufficient of itself to raise +That name, unless an age too late, or cold +Climate, or years, damp my intended wing +Depress'd; and much they may, if all be mine, +Not hers, who brings it nightly to my ear. +The sun was sunk, and after him the star +Of Hesperus, whose office is to bring +Twilight upon the earth, short arbiter +"twixt day and night, and now from end to end +Night's hemisphere had veil'd the horizon round: +When satan, who late fled before the threats +Of Gabriel out of Eden, now improv'd +In meditated fraud and malice, bent +On Man's destruction, maugre what might hap +Of heavier on himself, fearless returned +From compassing the earth; cautious of day, +Since Uriel, regent of the sun, descried +His entrance, and foreworned the Cherubim +That kept their watch; thence full of anguish driven, +The space of seven continued nights he rode +With darkness; thrice the equinoctial line +He circled; four times crossed the car of night +From pole to pole, traversing each colure; +On the eighth returned; and, on the coast averse +From entrance or Cherubick watch, by stealth +Found unsuspected way. There was a place, +Now not, though sin, not time, first wrought the change, +Where Tigris, at the foot of Paradise, +Into a gulf shot under ground, till part +Rose up a fountain by the tree of life: +In with the river sunk, and with it rose +Satan, involved in rising mist; then sought +Where to lie hid; sea he had searched, and land, +From Eden over Pontus and the pool +Maeotis, up beyond the river Ob; +Downward as far antarctick; and in length, +West from Orontes to the ocean barred +At Darien ; thence to the land where flows +Ganges and Indus: Thus the orb he roamed +With narrow search; and with inspection deep +Considered every creature, which of all +Most opportune might serve his wiles; and found +The Serpent subtlest beast of all the field. +Him after long debate, irresolute +Of thoughts revolved, his final sentence chose +Fit vessel, fittest imp of fraud, in whom +To enter, and his dark suggestions hide +From sharpest sight: for, in the wily snake +Whatever sleights, none would suspicious mark, +As from his wit and native subtlety +Proceeding; which, in other beasts observed, +Doubt might beget of diabolick power +Active within, beyond the sense of brute. +Thus he resolved, but first from inward grief +His bursting passion into plaints thus poured. +More justly, seat worthier of Gods, as built +With second thoughts, reforming what was old! +O Earth, how like to Heaven, if not preferred +For what God, after better, worse would build? +Terrestrial Heaven, danced round by other Heavens +That shine, yet bear their bright officious lamps, +Light above light, for thee alone, as seems, +In thee concentring all their precious beams +Of sacred influence! As God in Heaven +Is center, yet extends to all; so thou, +Centring, receivest from all those orbs: in thee, +Not in themselves, all their known virtue appears +Productive in herb, plant, and nobler birth +Of creatures animate with gradual life +Of growth, sense, reason, all summed up in Man. +With what delight could I have walked thee round, +If I could joy in aught, sweet interchange +Of hill, and valley, rivers, woods, and plains, +Now land, now sea and shores with forest crowned, +Rocks, dens, and caves! But I in none of these +Find place or refuge; and the more I see +Pleasures about me, so much more I feel +Torment within me, as from the hateful siege +Of contraries: all good to me becomes +Bane, and in Heaven much worse would be my state. +But neither here seek I, no nor in Heaven +To dwell, unless by mastering Heaven's Supreme; +Nor hope to be myself less miserable +By what I seek, but others to make such +As I, though thereby worse to me redound: +For only in destroying I find ease +To my relentless thoughts; and, him destroyed, +Or won to what may work his utter loss, +For whom all this was made, all this will soon +Follow, as to him linked in weal or woe; +In woe then; that destruction wide may range: +To me shall be the glory sole among +The infernal Powers, in one day to have marred +What he, Almighty styled, six nights and days +Continued making; and who knows how long +Before had been contriving? though perhaps +Not longer than since I, in one night, freed +From servitude inglorious well nigh half +The angelick name, and thinner left the throng +Of his adorers: He, to be avenged, +And to repair his numbers thus impaired, +Whether such virtue spent of old now failed +More Angels to create, if they at least +Are his created, or, to spite us more, +Determined to advance into our room +A creature formed of earth, and him endow, +Exalted from so base original, +With heavenly spoils, our spoils: What he decreed, +He effected; Man he made, and for him built +Magnificent this world, and earth his seat, +Him lord pronounced; and, O indignity! +Subjected to his service angel-wings, +And flaming ministers to watch and tend +Their earthly charge: Of these the vigilance +I dread; and, to elude, thus wrapt in mist +Of midnight vapour glide obscure, and pry +In every bush and brake, where hap may find +The serpent sleeping; in whose mazy folds +To hide me, and the dark intent I bring. +O foul descent! that I, who erst contended +With Gods to sit the highest, am now constrained +Into a beast; and, mixed with bestial slime, +This essence to incarnate and imbrute, +That to the highth of Deity aspired! +But what will not ambition and revenge +Descend to? Who aspires, must down as low +As high he soared; obnoxious, first or last, +To basest things. Revenge, at first though sweet, +Bitter ere long, back on itself recoils: +Let it; I reck not, so it light well aimed, +Since higher I fall short, on him who next +Provokes my envy, this new favourite +Of Heaven, this man of clay, son of despite, +Whom, us the more to spite, his Maker raised +From dust: Spite then with spite is best repaid. +So saying, through each thicket dank or dry, +Like a black mist low-creeping, he held on +His midnight-search, where soonest he might find +The serpent; him fast-sleeping soon he found +In labyrinth of many a round self-rolled, +His head the midst, well stored with subtile wiles: +Not yet in horrid shade or dismal den, +Nor nocent yet; but, on the grassy herb, +Fearless unfeared he slept: in at his mouth +The Devil entered; and his brutal sense, +In heart or head, possessing, soon inspired +With act intelligential; but his sleep +Disturbed not, waiting close the approach of morn. +Now, when as sacred light began to dawn +In Eden on the humid flowers, that breathed +Their morning incense, when all things, that breathe, +From the Earth's great altar send up silent praise +To the Creator, and his nostrils fill +With grateful smell, forth came the human pair, +And joined their vocal worship to the quire +Of creatures wanting voice; that done, partake +The season prime for sweetest scents and airs: +Then commune, how that day they best may ply +Their growing work: for much their work out-grew +The hands' dispatch of two gardening so wide, +And Eve first to her husband thus began. +Adam, well may we labour still to dress +This garden, still to tend plant, herb, and flower, +Our pleasant task enjoined; but, till more hands +Aid us, the work under our labour grows, +Luxurious by restraint; what we by day +Lop overgrown, or prune, or prop, or bind, +One night or two with wanton growth derides +Tending to wild. Thou therefore now advise, +Or bear what to my mind first thoughts present: +Let us divide our labours; thou, where choice +Leads thee, or where most needs, whether to wind +The woodbine round this arbour, or direct +The clasping ivy where to climb; while I, +In yonder spring of roses intermixed +With myrtle, find what to redress till noon: +For, while so near each other thus all day +Our task we choose, what wonder if so near +Looks intervene and smiles, or object new +Casual discourse draw on; which intermits +Our day's work, brought to little, though begun +Early, and the hour of supper comes unearned? +To whom mild answer Adam thus returned. +Sole Eve, associate sole, to me beyond +Compare above all living creatures dear! +Well hast thou motioned, well thy thoughts employed, +How we might best fulfil the work which here +God hath assigned us; nor of me shalt pass +Unpraised: for nothing lovelier can be found +In woman, than to study houshold good, +And good works in her husband to promote. +Yet not so strictly hath our Lord imposed +Labour, as to debar us when we need +Refreshment, whether food, or talk between, +Food of the mind, or this sweet intercourse +Of looks and smiles; for smiles from reason flow, +To brute denied, and are of love the food; +Love, not the lowest end of human life. +For not to irksome toil, but to delight, +He made us, and delight to reason joined. +These paths and bowers doubt not but our joint hands +Will keep from wilderness with ease, as wide +As we need walk, till younger hands ere long +Assist us; But, if much converse perhaps +Thee satiate, to short absence I could yield: +For solitude sometimes is best society, +And short retirement urges sweet return. +But other doubt possesses me, lest harm +Befall thee severed from me; for thou knowest +What hath been warned us, what malicious foe +Envying our happiness, and of his own +Despairing, seeks to work us woe and shame +By sly assault; and somewhere nigh at hand +Watches, no doubt, with greedy hope to find +His wish and best advantage, us asunder; +Hopeless to circumvent us joined, where each +To other speedy aid might lend at need: +Whether his first design be to withdraw +Our fealty from God, or to disturb +Conjugal love, than which perhaps no bliss +Enjoyed by us excites his envy more; +Or this, or worse, leave not the faithful side +That gave thee being, still shades thee, and protects. +The wife, where danger or dishonour lurks, +Safest and seemliest by her husband stays, +Who guards her, or with her the worst endures. +To whom the virgin majesty of Eve, +As one who loves, and some unkindness meets, +With sweet austere composure thus replied. +Offspring of Heaven and Earth, and all Earth's Lord! +That such an enemy we have, who seeks +Our ruin, both by thee informed I learn, +And from the parting Angel over-heard, +As in a shady nook I stood behind, +Just then returned at shut of evening flowers. +But, that thou shouldst my firmness therefore doubt +To God or thee, because we have a foe +May tempt it, I expected not to hear. +His violence thou fearest not, being such +As we, not capable of death or pain, +Can either not receive, or can repel. +His fraud is then thy fear; which plain infers +Thy equal fear, that my firm faith and love +Can by his fraud be shaken or seduced; +Thoughts, which how found they harbour in thy breast, +Adam, mis-thought of her to thee so dear? +To whom with healing words Adam replied. +Daughter of God and Man, immortal Eve! +For such thou art; from sin and blame entire: +Not diffident of thee do I dissuade +Thy absence from my sight, but to avoid +The attempt itself, intended by our foe. +For he who tempts, though in vain, at least asperses +The tempted with dishonour foul; supposed +Not incorruptible of faith, not proof +Against temptation: Thou thyself with scorn +And anger wouldst resent the offered wrong, +Though ineffectual found: misdeem not then, +If such affront I labour to avert +From thee alone, which on us both at once +The enemy, though bold, will hardly dare; +Or daring, first on me the assault shall light. +Nor thou his malice and false guile contemn; +Subtle he needs must be, who could seduce +Angels; nor think superfluous other's aid. +I, from the influence of thy looks, receive +Access in every virtue; in thy sight +More wise, more watchful, stronger, if need were +Of outward strength; while shame, thou looking on, +Shame to be overcome or over-reached, +Would utmost vigour raise, and raised unite. +Why shouldst not thou like sense within thee feel +When I am present, and thy trial choose +With me, best witness of thy virtue tried? +So spake domestick Adam in his care +And matrimonial love; but Eve, who thought +Less attributed to her faith sincere, +Thus her reply with accent sweet renewed. +If this be our condition, thus to dwell +In narrow circuit straitened by a foe, +Subtle or violent, we not endued +Single with like defence, wherever met; +How are we happy, still in fear of harm? +But harm precedes not sin: only our foe, +Tempting, affronts us with his foul esteem +Of our integrity: his foul esteem +Sticks no dishonour on our front, but turns +Foul on himself; then wherefore shunned or feared +By us? who rather double honour gain +From his surmise proved false; find peace within, +Favour from Heaven, our witness, from the event. +And what is faith, love, virtue, unassayed +Alone, without exteriour help sustained? +Let us not then suspect our happy state +Left so imperfect by the Maker wise, +As not secure to single or combined. +Frail is our happiness, if this be so, +And Eden were no Eden, thus exposed. +To whom thus Adam fervently replied. +O Woman, best are all things as the will +Of God ordained them: His creating hand +Nothing imperfect or deficient left +Of all that he created, much less Man, +Or aught that might his happy state secure, +Secure from outward force; within himself +The danger lies, yet lies within his power: +Against his will he can receive no harm. +But God left free the will; for what obeys +Reason, is free; and Reason he made right, +But bid her well be ware, and still erect; +Lest, by some fair-appearing good surprised, +She dictate false; and mis-inform the will +To do what God expressly hath forbid. +Not then mistrust, but tender love, enjoins, +That I should mind thee oft; and mind thou me. +Firm we subsist, yet possible to swerve; +Since Reason not impossibly may meet +Some specious object by the foe suborned, +And fall into deception unaware, +Not keeping strictest watch, as she was warned. +Seek not temptation then, which to avoid +Were better, and most likely if from me +Thou sever not: Trial will come unsought. +Wouldst thou approve thy constancy, approve +First thy obedience; the other who can know, +Not seeing thee attempted, who attest? +But, if thou think, trial unsought may find +Us both securer than thus warned thou seemest, +Go; for thy stay, not free, absents thee more; +Go in thy native innocence, rely +On what thou hast of virtue; summon all! +For God towards thee hath done his part, do thine. +So spake the patriarch of mankind; but Eve +Persisted; yet submiss, though last, replied. +With thy permission then, and thus forewarned +Chiefly by what thy own last reasoning words +Touched only; that our trial, when least sought, +May find us both perhaps far less prepared, +The willinger I go, nor much expect +A foe so proud will first the weaker seek; +So bent, the more shall shame him his repulse. +Thus saying, from her husband's hand her hand +Soft she withdrew; and, like a Wood-Nymph light, +Oread or Dryad, or of Delia's train, +Betook her to the groves; but Delia's self +In gait surpassed, and Goddess-like deport, +Though not as she with bow and quiver armed, +But with such gardening tools as Art yet rude, +Guiltless of fire, had formed, or Angels brought. +To Pales, or Pomona, thus adorned, +Likest she seemed, Pomona when she fled +Vertumnus, or to Ceres in her prime, +Yet virgin of Proserpina from Jove. +Her long with ardent look his eye pursued +Delighted, but desiring more her stay. +Oft he to her his charge of quick return +Repeated; she to him as oft engaged +To be returned by noon amid the bower, +And all things in best order to invite +Noontide repast, or afternoon's repose. +O much deceived, much failing, hapless Eve, +Of thy presumed return! event perverse! +Thou never from that hour in Paradise +Foundst either sweet repast, or sound repose; +Such ambush, hid among sweet flowers and shades, +Waited with hellish rancour imminent +To intercept thy way, or send thee back +Despoiled of innocence, of faith, of bliss! +For now, and since first break of dawn, the Fiend, +Mere serpent in appearance, forth was come; +And on his quest, where likeliest he might find +The only two of mankind, but in them +The whole included race, his purposed prey. +In bower and field he sought, where any tuft +Of grove or garden-plot more pleasant lay, +Their tendance, or plantation for delight; +By fountain or by shady rivulet +He sought them both, but wished his hap might find +Eve separate; he wished, but not with hope +Of what so seldom chanced; when to his wish, +Beyond his hope, Eve separate he spies, +Veiled in a cloud of fragrance, where she stood, +Half spied, so thick the roses blushing round +About her glowed, oft stooping to support +Each flower of slender stalk, whose head, though gay +Carnation, purple, azure, or specked with gold, +Hung drooping unsustained; them she upstays +Gently with myrtle band, mindless the while +Herself, though fairest unsupported flower, +From her best prop so far, and storm so nigh. +Nearer he drew, and many a walk traversed +Of stateliest covert, cedar, pine, or palm; +Then voluble and bold, now hid, now seen, +Among thick-woven arborets, and flowers +Imbordered on each bank, the hand of Eve: +Spot more delicious than those gardens feigned +Or of revived Adonis, or renowned +Alcinous, host of old Laertes' son; +Or that, not mystick, where the sapient king +Held dalliance with his fair Egyptian spouse. +Much he the place admired, the person more. +As one who long in populous city pent, +Where houses thick and sewers annoy the air, +Forth issuing on a summer's morn, to breathe +Among the pleasant villages and farms +Adjoined, from each thing met conceives delight; +The smell of grain, or tedded grass, or kine, +Or dairy, each rural sight, each rural sound; +If chance, with nymph-like step, fair virgin pass, +What pleasing seemed, for her now pleases more; +She most, and in her look sums all delight: +Such pleasure took the Serpent to behold +This flowery plat, the sweet recess of Eve +Thus early, thus alone: Her heavenly form +Angelick, but more soft, and feminine, +Her graceful innocence, her every air +Of gesture, or least action, overawed +His malice, and with rapine sweet bereaved +His fierceness of the fierce intent it brought: +That space the Evil-one abstracted stood +From his own evil, and for the time remained +Stupidly good; of enmity disarmed, +Of guile, of hate, of envy, of revenge: +But the hot Hell that always in him burns, +Though in mid Heaven, soon ended his delight, +And tortures him now more, the more he sees +Of pleasure, not for him ordained: then soon +Fierce hate he recollects, and all his thoughts +Of mischief, gratulating, thus excites. +Thoughts, whither have ye led me! with what sweet +Compulsion thus transported, to forget +What hither brought us! hate, not love;nor hope +Of Paradise for Hell, hope here to taste +Of pleasure; but all pleasure to destroy, +Save what is in destroying; other joy +To me is lost. Then, let me not let pass +Occasion which now smiles; behold alone +The woman, opportune to all attempts, +Her husband, for I view far round, not nigh, +Whose higher intellectual more I shun, +And strength, of courage haughty, and of limb +Heroick built, though of terrestrial mould; +Foe not informidable! exempt from wound, +I not; so much hath Hell debased, and pain +Enfeebled me, to what I was in Heaven. +She fair, divinely fair, fit love for Gods! +Not terrible, though terrour be in love +And beauty, not approached by stronger hate, +Hate stronger, under show of love well feigned; +The way which to her ruin now I tend. +So spake the enemy of mankind, enclosed +In serpent, inmate bad! and toward Eve +Addressed his way: not with indented wave, +Prone on the ground, as since; but on his rear, +Circular base of rising folds, that towered +Fold above fold, a surging maze! his head +Crested aloft, and carbuncle his eyes; +With burnished neck of verdant gold, erect +Amidst his circling spires, that on the grass +Floated redundant: pleasing was his shape +And lovely; never since of serpent-kind +Lovelier, not those that in Illyria changed, +Hermione and Cadmus, or the god +In Epidaurus; nor to which transformed +Ammonian Jove, or Capitoline, was seen; +He with Olympias; this with her who bore +Scipio, the highth of Rome. With tract oblique +At first, as one who sought access, but feared +To interrupt, side-long he works his way. +As when a ship, by skilful steersmen wrought +Nigh river's mouth or foreland, where the wind +Veers oft, as oft so steers, and shifts her sail: +So varied he, and of his tortuous train +Curled many a wanton wreath in sight of Eve, +To lure her eye; she, busied, heard the sound +Of rusling leaves, but minded not, as used +To such disport before her through the field, +From every beast; more duteous at her call, +Than at Circean call the herd disguised. +He, bolder now, uncalled before her stood, +But as in gaze admiring: oft he bowed +His turret crest, and sleek enamelled neck, +Fawning; and licked the ground whereon she trod. +His gentle dumb expression turned at length +The eye of Eve to mark his play; he, glad +Of her attention gained, with serpent-tongue +Organick, or impulse of vocal air, +His fraudulent temptation thus began. +Wonder not, sovran Mistress, if perhaps +Thou canst, who art sole wonder! much less arm +Thy looks, the Heaven of mildness, with disdain, +Displeased that I approach thee thus, and gaze +Insatiate; I thus single;nor have feared +Thy awful brow, more awful thus retired. +Fairest resemblance of thy Maker fair, +Thee all things living gaze on, all things thine +By gift, and thy celestial beauty adore +With ravishment beheld! there best beheld, +Where universally admired; but here +In this enclosure wild, these beasts among, +Beholders rude, and shallow to discern +Half what in thee is fair, one man except, +Who sees thee? and what is one? who should be seen +A Goddess among Gods, adored and served +By Angels numberless, thy daily train. +So glozed the Tempter, and his proem tuned: +Into the heart of Eve his words made way, +Though at the voice much marvelling; at length, +Not unamazed, she thus in answer spake. +What may this mean? language of man pronounced +By tongue of brute, and human sense expressed? +The first, at least, of these I thought denied +To beasts; whom God, on their creation-day, +Created mute to all articulate sound: +The latter I demur; for in their looks +Much reason, and in their actions, oft appears. +Thee, Serpent, subtlest beast of all the field +I knew, but not with human voice endued; +Redouble then this miracle, and say, +How camest thou speakable of mute, and how +To me so friendly grown above the rest +Of brutal kind, that daily are in sight? +Say, for such wonder claims attention due. +To whom the guileful Tempter thus replied. +Empress of this fair world, resplendent Eve! +Easy to me it is to tell thee all +What thou commandest; and right thou shouldst be obeyed: +I was at first as other beasts that graze +The trodden herb, of abject thoughts and low, +As was my food; nor aught but food discerned +Or sex, and apprehended nothing high: +Till, on a day roving the field, I chanced +A goodly tree far distant to behold +Loaden with fruit of fairest colours mixed, +Ruddy and gold: I nearer drew to gaze; +When from the boughs a savoury odour blown, +Grateful to appetite, more pleased my sense +Than smell of sweetest fennel, or the teats +Of ewe or goat dropping with milk at even, +Unsucked of lamb or kid, that tend their play. +To satisfy the sharp desire I had +Of tasting those fair apples, I resolved +Not to defer; hunger and thirst at once, +Powerful persuaders, quickened at the scent +Of that alluring fruit, urged me so keen. +About the mossy trunk I wound me soon; +For, high from ground, the branches would require +Thy utmost reach or Adam's: Round the tree +All other beasts that saw, with like desire +Longing and envying stood, but could not reach. +Amid the tree now got, where plenty hung +Tempting so nigh, to pluck and eat my fill +I spared not; for, such pleasure till that hour, +At feed or fountain, never had I found. +Sated at length, ere long I might perceive +Strange alteration in me, to degree +Of reason in my inward powers; and speech +Wanted not long; though to this shape retained. +Thenceforth to speculations high or deep +I turned my thoughts, and with capacious mind +Considered all things visible in Heaven, +Or Earth, or Middle; all things fair and good: +But all that fair and good in thy divine +Semblance, and in thy beauty's heavenly ray, +United I beheld; no fair to thine +Equivalent or second! which compelled +Me thus, though importune perhaps, to come +And gaze, and worship thee of right declared +Sovran of creatures, universal Dame! +So talked the spirited sly Snake; and Eve, +Yet more amazed, unwary thus replied. +Serpent, thy overpraising leaves in doubt +The virtue of that fruit, in thee first proved: +But say, where grows the tree? from hence how far? +For many are the trees of God that grow +In Paradise, and various, yet unknown +To us; in such abundance lies our choice, +As leaves a greater store of fruit untouched, +Still hanging incorruptible, till men +Grow up to their provision, and more hands +Help to disburden Nature of her birth. +To whom the wily Adder, blithe and glad. +Empress, the way is ready, and not long; +Beyond a row of myrtles, on a flat, +Fast by a fountain, one small thicket past +Of blowing myrrh and balm: if thou accept +My conduct, I can bring thee thither soon +Lead then, said Eve. He, leading, swiftly rolled +In tangles, and made intricate seem straight, +To mischief swift. Hope elevates, and joy +Brightens his crest; as when a wandering fire, +Compact of unctuous vapour, which the night +Condenses, and the cold environs round, +Kindled through agitation to a flame, +Which oft, they say, some evil Spirit attends, +Hovering and blazing with delusive light, +Misleads the amazed night-wanderer from his way +To bogs and mires, and oft through pond or pool; +There swallowed up and lost, from succour far. +So glistered the dire Snake, and into fraud +Led Eve, our credulous mother, to the tree +Of prohibition, root of all our woe; +Which when she saw, thus to her guide she spake. +Serpent, we might have spared our coming hither, +Fruitless to me, though fruit be here to excess, +The credit of whose virtue rest with thee; +Wonderous indeed, if cause of such effects. +But of this tree we may not taste nor touch; +God so commanded, and left that command +Sole daughter of his voice; the rest, we live +Law to ourselves; our reason is our law. +To whom the Tempter guilefully replied. +Indeed! hath God then said that of the fruit +Of all these garden-trees ye shall not eat, +Yet Lords declared of all in earth or air$? +To whom thus Eve, yet sinless. Of the fruit +Of each tree in the garden we may eat; +But of the fruit of this fair tree amidst +The garden, God hath said, Ye shall not eat +Thereof, nor shall ye touch it, lest ye die. +She scarce had said, though brief, when now more bold +The Tempter, but with show of zeal and love +To Man, and indignation at his wrong, +New part puts on; and, as to passion moved, +Fluctuates disturbed, yet comely and in act +Raised, as of some great matter to begin. +As when of old some orator renowned, +In Athens or free Rome, where eloquence +Flourished, since mute! to some great cause addressed, +Stood in himself collected; while each part, +Motion, each act, won audience ere the tongue; +Sometimes in highth began, as no delay +Of preface brooking, through his zeal of right: +So standing, moving, or to highth up grown, +The Tempter, all impassioned, thus began. +O sacred, wise, and wisdom-giving Plant, +Mother of science! now I feel thy power +Within me clear; not only to discern +Things in their causes, but to trace the ways +Of highest agents, deemed however wise. +Queen of this universe! do not believe +Those rigid threats of death: ye shall not die: +How should you? by the fruit? it gives you life +To knowledge; by the threatener? look on me, +Me, who have touched and tasted; yet both live, +And life more perfect have attained than Fate +Meant me, by venturing higher than my lot. +Shall that be shut to Man, which to the Beast +Is open? or will God incense his ire +For such a petty trespass? and not praise +Rather your dauntless virtue, whom the pain +Of death denounced, whatever thing death be, +Deterred not from achieving what might lead +To happier life, knowledge of good and evil; +Of good, how just? of evil, if what is evil +Be real, why not known, since easier shunned? +God therefore cannot hurt ye, and be just; +Not just, not God; not feared then, nor obeyed: +Your fear itself of death removes the fear. +Why then was this forbid? Why, but to awe; +Why, but to keep ye low and ignorant, +His worshippers? He knows that in the day +Ye eat thereof, your eyes that seem so clear, +Yet are but dim, shall perfectly be then +Opened and cleared, and ye shall be as Gods, +Knowing both good and evil, as they know. +That ye shall be as Gods, since I as Man, +Internal Man, is but proportion meet; +I, of brute, human; ye, of human, Gods. +So ye shall die perhaps, by putting off +Human, to put on Gods; death to be wished, +Though threatened, which no worse than this can bring. +And what are Gods, that Man may not become +As they, participating God-like food? +The Gods are first, and that advantage use +On our belief, that all from them proceeds: +I question it; for this fair earth I see, +Warmed by the sun, producing every kind; +Them, nothing: if they all things, who enclosed +Knowledge of good and evil in this tree, +That whoso eats thereof, forthwith attains +Wisdom without their leave? and wherein lies +The offence, that Man should thus attain to know? +What can your knowledge hurt him, or this tree +Impart against his will, if all be his? +Or is it envy? and can envy dwell +In heavenly breasts? These, these, and many more +Causes import your need of this fair fruit. +Goddess humane, reach then, and freely taste! +He ended; and his words, replete with guile, +Into her heart too easy entrance won: +Fixed on the fruit she gazed, which to behold +Might tempt alone; and in her ears the sound +Yet rung of his persuasive words, impregned +With reason, to her seeming, and with truth: +Mean while the hour of noon drew on, and waked +An eager appetite, raised by the smell +So savoury of that fruit, which with desire, +Inclinable now grown to touch or taste, +Solicited her longing eye; yet first +Pausing a while, thus to herself she mused. +Great are thy virtues, doubtless, best of fruits, +Though kept from man, and worthy to be admired; +Whose taste, too long forborn, at first assay +Gave elocution to the mute, and taught +The tongue not made for speech to speak thy praise: +Thy praise he also, who forbids thy use, +Conceals not from us, naming thee the tree +Of knowledge, knowledge both of good and evil; +Forbids us then to taste! but his forbidding +Commends thee more, while it infers the good +By thee communicated, and our want: +For good unknown sure is not had; or, had +And yet unknown, is as not had at all. +In plain then, what forbids he but to know, +Forbids us good, forbids us to be wise? +Such prohibitions bind not. But, if death +Bind us with after-bands, what profits then +Our inward freedom? In the day we eat +Of this fair fruit, our doom is, we shall die! +How dies the Serpent? he hath eaten and lives, +And knows, and speaks, and reasons, and discerns, +Irrational till then. For us alone +Was death invented? or to us denied +This intellectual food, for beasts reserved? +For beasts it seems: yet that one beast which first +Hath tasted envies not, but brings with joy +The good befallen him, author unsuspect, +Friendly to man, far from deceit or guile. +What fear I then? rather, what know to fear +Under this ignorance of good and evil, +Of God or death, of law or penalty? +Here grows the cure of all, this fruit divine, +Fair to the eye, inviting to the taste, +Of virtue to make wise: What hinders then +To reach, and feed at once both body and mind? +So saying, her rash hand in evil hour +Forth reaching to the fruit, she plucked, she eat! +Earth felt the wound; and Nature from her seat, +Sighing through all her works, gave signs of woe, +That all was lost. Back to the thicket slunk +The guilty Serpent; and well might;for Eve, +Intent now wholly on her taste, nought else +Regarded; such delight till then, as seemed, +In fruit she never tasted, whether true +Or fancied so, through expectation high +Of knowledge; not was Godhead from her thought. +Greedily she ingorged without restraint, +And knew not eating death: Satiate at length, +And hightened as with wine, jocund and boon, +Thus to herself she pleasingly began. +O sovran, virtuous, precious of all trees +In Paradise! of operation blest +To sapience, hitherto obscured, infamed. +And thy fair fruit let hang, as to no end +Created; but henceforth my early care, +Not without song, each morning, and due praise, +Shall tend thee, and the fertile burden ease +Of thy full branches offered free to all; +Till, dieted by thee, I grow mature +In knowledge, as the Gods, who all things know; +Though others envy what they cannot give: +For, had the gift been theirs, it had not here +Thus grown. Experience, next, to thee I owe, +Best guide; not following thee, I had remained +In ignorance; thou openest wisdom's way, +And givest access, though secret she retire. +And I perhaps am secret: Heaven is high, +High, and remote to see from thence distinct +Each thing on Earth; and other care perhaps +May have diverted from continual watch +Our great Forbidder, safe with all his spies +About him. But to Adam in what sort +Shall I appear? shall I to him make known +As yet my change, and give him to partake +Full happiness with me, or rather not, +But keeps the odds of knowledge in my power +Without copartner? so to add what wants +In female sex, the more to draw his love, +And render me more equal; and perhaps, +A thing not undesirable, sometime +Superiour; for, inferiour, who is free +This may be well: But what if God have seen, +And death ensue? then I shall be no more! +And Adam, wedded to another Eve, +Shall live with her enjoying, I extinct; +A death to think! Confirmed then I resolve, +Adam shall share with me in bliss or woe: +So dear I love him, that with him all deaths +I could endure, without him live no life. +So saying, from the tree her step she turned; +But first low reverence done, as to the Power +That dwelt within, whose presence had infused +Into the plant sciential sap, derived +From nectar, drink of Gods. Adam the while, +Waiting desirous her return, had wove +Of choicest flowers a garland, to adorn +Her tresses, and her rural labours crown; +As reapers oft are wont their harvest-queen. +Great joy he promised to his thoughts, and new +Solace in her return, so long delayed: +Yet oft his heart, divine of something ill, +Misgave him; he the faltering measure felt; +And forth to meet her went, the way she took +That morn when first they parted: by the tree +Of knowledge he must pass; there he her met, +Scarce from the tree returning; in her hand +A bough of fairest fruit, that downy smiled, +New gathered, and ambrosial smell diffused. +To him she hasted; in her face excuse +Came prologue, and apology too prompt; +Which, with bland words at will, she thus addressed. +Hast thou not wondered, Adam, at my stay? +Thee I have missed, and thought it long, deprived +Thy presence; agony of love till now +Not felt, nor shall be twice; for never more +Mean I to try, what rash untried I sought, +The pain of absence from thy sight. But strange +Hath been the cause, and wonderful to hear: +This tree is not, as we are told, a tree +Of danger tasted, nor to evil unknown +Opening the way, but of divine effect +To open eyes, and make them Gods who taste; +And hath been tasted such: The serpent wise, +Or not restrained as we, or not obeying, +Hath eaten of the fruit; and is become, +Not dead, as we are threatened, but thenceforth +Endued with human voice and human sense, +Reasoning to admiration; and with me +Persuasively hath so prevailed, that I +Have also tasted, and have also found +The effects to correspond; opener mine eyes, +Dim erst, dilated spirits, ampler heart, +And growing up to Godhead; which for thee +Chiefly I sought, without thee can despise. +For bliss, as thou hast part, to me is bliss; +Tedious, unshared with thee, and odious soon. +Thou therefore also taste, that equal lot +May join us, equal joy, as equal love; +Lest, thou not tasting, different degree +Disjoin us, and I then too late renounce +Deity for thee, when Fate will not permit. +Thus Eve with countenance blithe her story told; +But in her cheek distemper flushing glowed. +On the other side Adam, soon as he heard +The fatal trespass done by Eve, amazed, +Astonied stood and blank, while horrour chill +Ran through his veins, and all his joints relaxed; +From his slack hand the garland wreathed for Eve +Down dropt, and all the faded roses shed: +Speechless he stood and pale, till thus at length +First to himself he inward silence broke. +O fairest of Creation, last and best +Of all God's works, Creature in whom excelled +Whatever can to sight or thought be formed, +Holy, divine, good, amiable, or sweet! +How art thou lost! how on a sudden lost, +Defaced, deflowered, and now to death devote! +Rather, how hast thou yielded to transgress +The strict forbiddance, how to violate +The sacred fruit forbidden! Some cursed fraud +Of enemy hath beguiled thee, yet unknown, +And me with thee hath ruined; for with thee +Certain my resolution is to die: +How can I live without thee! how forego +Thy sweet converse, and love so dearly joined, +To live again in these wild woods forlorn! +Should God create another Eve, and I +Another rib afford, yet loss of thee +Would never from my heart: no, no!I feel +The link of Nature draw me: flesh of flesh, +Bone of my bone thou art, and from thy state +Mine never shall be parted, bliss or woe. +So having said, as one from sad dismay +Recomforted, and after thoughts disturbed +Submitting to what seemed remediless, +Thus in calm mood his words to Eve he turned. +Bold deed thou hast presumed, adventurous Eve, +And peril great provoked, who thus hast dared, +Had it been only coveting to eye +That sacred fruit, sacred to abstinence, +Much more to taste it under ban to touch. +But past who can recall, or done undo? +Not God Omnipotent, nor Fate; yet so +Perhaps thou shalt not die, perhaps the fact +Is not so heinous now, foretasted fruit, +Profaned first by the serpent, by him first +Made common, and unhallowed, ere our taste; +Nor yet on him found deadly; yet he lives; +Lives, as thou saidst, and gains to live, as Man, +Higher degree of life; inducement strong +To us, as likely tasting to attain +Proportional ascent; which cannot be +But to be Gods, or Angels, demi-Gods. +Nor can I think that God, Creator wise, +Though threatening, will in earnest so destroy +Us his prime creatures, dignified so high, +Set over all his works; which in our fall, +For us created, needs with us must fail, +Dependant made; so God shall uncreate, +Be frustrate, do, undo, and labour lose; +Not well conceived of God, who, though his power +Creation could repeat, yet would be loth +Us to abolish, lest the Adversary +Triumph, and say; "Fickle their state whom God +"Most favours; who can please him long? Me first +"He ruined, now Mankind; whom will he next?" +Matter of scorn, not to be given the Foe. +However I with thee have fixed my lot, +Certain to undergo like doom: If death +Consort with thee, death is to me as life; +So forcible within my heart I feel +The bond of Nature draw me to my own; +My own in thee, for what thou art is mine; +Our state cannot be severed; we are one, +One flesh; to lose thee were to lose myself. +So Adam; and thus Eve to him replied. +O glorious trial of exceeding love, +Illustrious evidence, example high! +Engaging me to emulate; but, short +Of thy perfection, how shall I attain, +Adam, from whose dear side I boast me sprung, +And gladly of our union hear thee speak, +One heart, one soul in both; whereof good proof +This day affords, declaring thee resolved, +Rather than death, or aught than death more dread, +Shall separate us, linked in love so dear, +To undergo with me one guilt, one crime, +If any be, of tasting this fair fruit; +Whose virtue for of good still good proceeds, +Direct, or by occasion, hath presented +This happy trial of thy love, which else +So eminently never had been known? +Were it I thought death menaced would ensue +This my attempt, I would sustain alone +The worst, and not persuade thee, rather die +Deserted, than oblige thee with a fact +Pernicious to thy peace; chiefly assured +Remarkably so late of thy so true, +So faithful, love unequalled: but I feel +Far otherwise the event; not death, but life +Augmented, opened eyes, new hopes, new joys, +Taste so divine, that what of sweet before +Hath touched my sense, flat seems to this, and harsh. +On my experience, Adam, freely taste, +And fear of death deliver to the winds. +So saying, she embraced him, and for joy +Tenderly wept; much won, that he his love +Had so ennobled, as of choice to incur +Divine displeasure for her sake, or death. +In recompence for such compliance bad +Such recompence best merits from the bough +She gave him of that fair enticing fruit +With liberal hand: he scrupled not to eat, +Against his better knowledge; not deceived, +But fondly overcome with female charm. +Earth trembled from her entrails, as again +In pangs; and Nature gave a second groan; +Sky loured; and, muttering thunder, some sad drops +Wept at completing of the mortal sin +Original: while Adam took no thought, +Eating his fill; nor Eve to iterate +Her former trespass feared, the more to sooth +Him with her loved society; that now, +As with new wine intoxicated both, +They swim in mirth, and fancy that they feel +Divinity within them breeding wings, +Wherewith to scorn the earth: But that false fruit +Far other operation first displayed, +Carnal desire inflaming; he on Eve +Began to cast lascivious eyes; she him +As wantonly repaid; in lust they burn: +Till Adam thus 'gan Eve to dalliance move. +Eve, now I see thou art exact of taste, +And elegant, of sapience no small part; +Since to each meaning savour we apply, +And palate call judicious; I the praise +Yield thee, so well this day thou hast purveyed. +Much pleasure we have lost, while we abstained +From this delightful fruit, nor known till now +True relish, tasting; if such pleasure be +In things to us forbidden, it might be wished, +For this one tree had been forbidden ten. +But come, so well refreshed, now let us play, +As meet is, after such delicious fare; +For never did thy beauty, since the day +I saw thee first and wedded thee, adorned +With all perfections, so inflame my sense +With ardour to enjoy thee, fairer now +Than ever; bounty of this virtuous tree! +So said he, and forbore not glance or toy +Of amorous intent; well understood +Of Eve, whose eye darted contagious fire. +Her hand he seised; and to a shady bank, +Thick over-head with verdant roof imbowered, +He led her nothing loth; flowers were the couch, +Pansies, and violets, and asphodel, +And hyacinth; Earth's freshest softest lap. +There they their fill of love and love's disport +Took largely, of their mutual guilt the seal, +The solace of their sin; till dewy sleep +Oppressed them, wearied with their amorous play, +Soon as the force of that fallacious fruit, +That with exhilarating vapour bland +About their spirits had played, and inmost powers +Made err, was now exhaled; and grosser sleep, +Bred of unkindly fumes, with conscious dreams +Incumbered, now had left them; up they rose +As from unrest; and, each the other viewing, +Soon found their eyes how opened, and their minds +How darkened; innocence, that as a veil +Had shadowed them from knowing ill, was gone; +Just confidence, and native righteousness, +And honour, from about them, naked left +To guilty Shame; he covered, but his robe +Uncovered more. So rose the Danite strong, +Herculean Samson, from the harlot-lap +Of Philistean Dalilah, and waked +Shorn of his strength. They destitute and bare +Of all their virtue: Silent, and in face +Confounded, long they sat, as strucken mute: +Till Adam, though not less than Eve abashed, +At length gave utterance to these words constrained. +O Eve, in evil hour thou didst give ear +To that false worm, of whomsoever taught +To counterfeit Man's voice; true in our fall, +False in our promised rising; since our eyes +Opened we find indeed, and find we know +Both good and evil; good lost, and evil got; +Bad fruit of knowledge, if this be to know; +Which leaves us naked thus, of honour void, +Of innocence, of faith, of purity, +Our wonted ornaments now soiled and stained, +And in our faces evident the signs +Of foul concupiscence; whence evil store; +Even shame, the last of evils; of the first +Be sure then.--How shall I behold the face +Henceforth of God or Angel, erst with joy +And rapture so oft beheld? Those heavenly shapes +Will dazzle now this earthly with their blaze +Insufferably bright. O! might I here +In solitude live savage; in some glade +Obscured, where highest woods, impenetrable +To star or sun-light, spread their umbrage broad +And brown as evening: Cover me, ye Pines! +Ye Cedars, with innumerable boughs +Hide me, where I may never see them more!-- +But let us now, as in bad plight, devise +What best may for the present serve to hide +The parts of each from other, that seem most +To shame obnoxious, and unseemliest seen; +Some tree, whose broad smooth leaves together sewed, +And girded on our loins, may cover round +Those middle parts; that this new comer, Shame, +There sit not, and reproach us as unclean. +So counselled he, and both together went +Into the thickest wood; there soon they chose +The fig-tree; not that kind for fruit renowned, +But such as at this day, to Indians known, +In Malabar or Decan spreads her arms +Branching so broad and long, that in the ground +The bended twigs take root, and daughters grow +About the mother tree, a pillared shade +High over-arched, and echoing walks between: +There oft the Indian herdsman, shunning heat, +Shelters in cool, and tends his pasturing herds +At loop-holes cut through thickest shade: Those leaves +They gathered, broad as Amazonian targe; +And, with what skill they had, together sewed, +To gird their waist; vain covering, if to hide +Their guilt and dreaded shame! O, how unlike +To that first naked glory! Such of late +Columbus found the American, so girt +With feathered cincture; naked else, and wild +Among the trees on isles and woody shores. +Thus fenced, and, as they thought, their shame in part +Covered, but not at rest or ease of mind, +They sat them down to weep; nor only tears +Rained at their eyes, but high winds worse within +Began to rise, high passions, anger, hate, +Mistrust, suspicion, discord; and shook sore +Their inward state of mind, calm region once +And full of peace, now tost and turbulent: +For Understanding ruled not, and the Will +Heard not her lore; both in subjection now +To sensual Appetite, who from beneath +Usurping over sovran Reason claimed +Superiour sway: From thus distempered breast, +Adam, estranged in look and altered style, +Speech intermitted thus to Eve renewed. +Would thou hadst hearkened to my words, and staid +With me, as I besought thee, when that strange +Desire of wandering, this unhappy morn, +I know not whence possessed thee; we had then +Remained still happy; not, as now, despoiled +Of all our good; shamed, naked, miserable! +Let none henceforth seek needless cause to approve +The faith they owe; when earnestly they seek +Such proof, conclude, they then begin to fail. +To whom, soon moved with touch of blame, thus Eve. +What words have passed thy lips, Adam severe! +Imputest thou that to my default, or will +Of wandering, as thou callest it, which who knows +But might as ill have happened thou being by, +Or to thyself perhaps? Hadst thou been there, +Or here the attempt, thou couldst not have discerned +Fraud in the Serpent, speaking as he spake; +No ground of enmity between us known, +Why he should mean me ill, or seek to harm. +Was I to have never parted from thy side? +As good have grown there still a lifeless rib. +Being as I am, why didst not thou, the head, +Command me absolutely not to go, +Going into such danger, as thou saidst? +Too facile then, thou didst not much gainsay; +Nay, didst permit, approve, and fair dismiss. +Hadst thou been firm and fixed in thy dissent, +Neither had I transgressed, nor thou with me. +To whom, then first incensed, Adam replied. +Is this the love, is this the recompence +Of mine to thee, ingrateful Eve! expressed +Immutable, when thou wert lost, not I; +Who might have lived, and joyed immortal bliss, +Yet willingly chose rather death with thee? +And am I now upbraided as the cause +Of thy transgressing? Not enough severe, +It seems, in thy restraint: What could I more +I warned thee, I admonished thee, foretold +The danger, and the lurking enemy +That lay in wait; beyond this, had been force; +And force upon free will hath here no place. +But confidence then bore thee on; secure +Either to meet no danger, or to find +Matter of glorious trial; and perhaps +I also erred, in overmuch admiring +What seemed in thee so perfect, that I thought +No evil durst attempt thee; but I rue +The errour now, which is become my crime, +And thou the accuser. Thus it shall befall +Him, who, to worth in women overtrusting, +Lets her will rule: restraint she will not brook; +And, left to herself, if evil thence ensue, +She first his weak indulgence will accuse. +Thus they in mutual accusation spent +The fruitless hours, but neither self-condemning; +And of their vain contest appeared no end. + + + +Book X + + +Mean while the heinous and despiteful act +Of Satan, done in Paradise; and how +He, in the serpent, had perverted Eve, +Her husband she, to taste the fatal fruit, +Was known in Heaven; for what can 'scape the eye +Of God all-seeing, or deceive his heart +Omniscient? who, in all things wise and just, +Hindered not Satan to attempt the mind +Of Man, with strength entire and free will armed, +Complete to have discovered and repulsed +Whatever wiles of foe or seeming friend. +For still they knew, and ought to have still remembered, +The high injunction, not to taste that fruit, +Whoever tempted; which they not obeying, +(Incurred what could they less?) the penalty; +And, manifold in sin, deserved to fall. +Up into Heaven from Paradise in haste +The angelick guards ascended, mute, and sad, +For Man; for of his state by this they knew, +Much wondering how the subtle Fiend had stolen +Entrance unseen. Soon as the unwelcome news +From Earth arrived at Heaven-gate, displeased +All were who heard; dim sadness did not spare +That time celestial visages, yet, mixed +With pity, violated not their bliss. +About the new-arrived, in multitudes +The ethereal people ran, to hear and know +How all befel: They towards the throne supreme, +Accountable, made haste, to make appear, +With righteous plea, their utmost vigilance +And easily approved; when the Most High +Eternal Father, from his secret cloud, +Amidst in thunder uttered thus his voice. +Assembled Angels, and ye Powers returned +From unsuccessful charge; be not dismayed, +Nor troubled at these tidings from the earth, +Which your sincerest care could not prevent; +Foretold so lately what would come to pass, +When first this tempter crossed the gulf from Hell. +I told ye then he should prevail, and speed +On his bad errand; Man should be seduced, +And flattered out of all, believing lies +Against his Maker; no decree of mine +Concurring to necessitate his fall, +Or touch with lightest moment of impulse +His free will, to her own inclining left +In even scale. But fallen he is; and now +What rests, but that the mortal sentence pass +On his transgression,--death denounced that day? +Which he presumes already vain and void, +Because not yet inflicted, as he feared, +By some immediate stroke; but soon shall find +Forbearance no acquittance, ere day end. +Justice shall not return as bounty scorned. +But whom send I to judge them? whom but thee, +Vicegerent Son? To thee I have transferred +All judgement, whether in Heaven, or Earth, or Hell. +Easy it may be seen that I intend +Mercy colleague with justice, sending thee +Man's friend, his Mediator, his designed +Both ransom and Redeemer voluntary, +And destined Man himself to judge Man fallen. +So spake the Father; and, unfolding bright +Toward the right hand his glory, on the Son +Blazed forth unclouded Deity: He full +Resplendent all his Father manifest +Expressed, and thus divinely answered mild. +Father Eternal, thine is to decree; +Mine, both in Heaven and Earth, to do thy will +Supreme; that thou in me, thy Son beloved, +Mayest ever rest well pleased. I go to judge +On earth these thy transgressours; but thou knowest, +Whoever judged, the worst on me must light, +When time shall be; for so I undertook +Before thee; and, not repenting, this obtain +Of right, that I may mitigate their doom +On me derived; yet I shall temper so +Justice with mercy, as may illustrate most +Them fully satisfied, and thee appease. +Attendance none shall need, nor train, where none +Are to behold the judgement, but the judged, +Those two; the third best absent is condemned, +Convict by flight, and rebel to all law: +Conviction to the serpent none belongs. +Thus saying, from his radiant seat he rose +Of high collateral glory: Him Thrones, and Powers, +Princedoms, and Dominations ministrant, +Accompanied to Heaven-gate; from whence +Eden, and all the coast, in prospect lay. +Down he descended straight; the speed of Gods +Time counts not, though with swiftest minutes winged. +Now was the sun in western cadence low +From noon, and gentle airs, due at their hour, +To fan the earth now waked, and usher in +The evening cool; when he, from wrath more cool, +Came the mild Judge, and Intercessour both, +To sentence Man: The voice of God they heard +Now walking in the garden, by soft winds +Brought to their ears, while day declined; they heard, +And from his presence hid themselves among +The thickest trees, both man and wife; till God, +Approaching, thus to Adam called aloud. +Where art thou, Adam, wont with joy to meet +My coming seen far off? I miss thee here, +Not pleased, thus entertained with solitude, +Where obvious duty ere while appeared unsought: +Or come I less conspicuous, or what change +Absents thee, or what chance detains?--Come forth! +He came; and with him Eve, more loth, though first +To offend; discountenanced both, and discomposed; +Love was not in their looks, either to God, +Or to each other; but apparent guilt, +And shame, and perturbation, and despair, +Anger, and obstinacy, and hate, and guile. +Whence Adam, faltering long, thus answered brief. +I heard thee in the garden, and of thy voice +Afraid, being naked, hid myself. To whom +The gracious Judge without revile replied. +My voice thou oft hast heard, and hast not feared, +But still rejoiced; how is it now become +So dreadful to thee? That thou art naked, who +Hath told thee? Hast thou eaten of the tree, +Whereof I gave thee charge thou shouldst not eat? +To whom thus Adam sore beset replied. +O Heaven! in evil strait this day I stand +Before my Judge; either to undergo +Myself the total crime, or to accuse +My other self, the partner of my life; +Whose failing, while her faith to me remains, +I should conceal, and not expose to blame +By my complaint: but strict necessity +Subdues me, and calamitous constraint; +Lest on my head both sin and punishment, +However insupportable, be all +Devolved; though should I hold my peace, yet thou +Wouldst easily detect what I conceal.-- +This Woman, whom thou madest to be my help, +And gavest me as thy perfect gift, so good, +So fit, so acceptable, so divine, +That from her hand I could suspect no ill, +And what she did, whatever in itself, +Her doing seemed to justify the deed; +She gave me of the tree, and I did eat. +To whom the Sovran Presence thus replied. +Was she thy God, that her thou didst obey +Before his voice? or was she made thy guide, +Superiour, or but equal, that to her +Thou didst resign thy manhood, and the place +Wherein God set thee above her made of thee, +And for thee, whose perfection far excelled +Hers in all real dignity? Adorned +She was indeed, and lovely, to attract +Thy love, not thy subjection; and her gifts +Were such, as under government well seemed; +Unseemly to bear rule; which was thy part +And person, hadst thou known thyself aright. +So having said, he thus to Eve in few. +Say, Woman, what is this which thou hast done? +To whom sad Eve, with shame nigh overwhelmed, +Confessing soon, yet not before her Judge +Bold or loquacious, thus abashed replied. +The Serpent me beguiled, and I did eat. +Which when the Lord God heard, without delay +To judgement he proceeded on the accused +Serpent, though brute; unable to transfer +The guilt on him, who made him instrument +Of mischief, and polluted from the end +Of his creation; justly then accursed, +As vitiated in nature: More to know +Concerned not Man, (since he no further knew) +Nor altered his offence; yet God at last +To Satan first in sin his doom applied, +Though in mysterious terms, judged as then best: +And on the Serpent thus his curse let fall. +Because thou hast done this, thou art accursed +Above all cattle, each beast of the field; +Upon thy belly groveling thou shalt go, +And dust shalt eat all the days of thy life. +Between thee and the woman I will put +Enmity, and between thine and her seed; +Her seed shall bruise thy head, thou bruise his heel. +So spake this oracle, then verified +When Jesus, Son of Mary, second Eve, +Saw Satan fall, like lightning, down from Heaven, +Prince of the air; then, rising from his grave +Spoiled Principalities and Powers, triumphed +In open show; and, with ascension bright, +Captivity led captive through the air, +The realm itself of Satan, long usurped; +Whom he shall tread at last under our feet; +Even he, who now foretold his fatal bruise; +And to the Woman thus his sentence turned. +Thy sorrow I will greatly multiply +By thy conception; children thou shalt bring +In sorrow forth; and to thy husband's will +Thine shall submit; he over thee shall rule. +On Adam last thus judgement he pronounced. +Because thou hast hearkened to the voice of thy wife, +And eaten of the tree, concerning which +I charged thee, saying, Thou shalt not eat thereof: +Cursed is the ground for thy sake; thou in sorrow +Shalt eat thereof, all the days of thy life; +Thorns also and thistles it shall bring thee forth +Unbid; and thou shalt eat the herb of the field; +In the sweat of thy face shalt thou eat bread, +Till thou return unto the ground; for thou +Out of the ground wast taken, know thy birth, +For dust thou art, and shalt to dust return. +So judged he Man, both Judge and Saviour sent; +And the instant stroke of death, denounced that day, +Removed far off; then, pitying how they stood +Before him naked to the air, that now +Must suffer change, disdained not to begin +Thenceforth the form of servant to assume; +As when he washed his servants feet; so now, +As father of his family, he clad +Their nakedness with skins of beasts, or slain, +Or as the snake with youthful coat repaid; +And thought not much to clothe his enemies; +Nor he their outward only with the skins +Of beasts, but inward nakedness, much more. +Opprobrious, with his robe of righteousness, +Arraying, covered from his Father's sight. +To him with swift ascent he up returned, +Into his blissful bosom reassumed +In glory, as of old; to him appeased +All, though all-knowing, what had passed with Man +Recounted, mixing intercession sweet. +Mean while, ere thus was sinned and judged on Earth, +Within the gates of Hell sat Sin and Death, +In counterview within the gates, that now +Stood open wide, belching outrageous flame +Far into Chaos, since the Fiend passed through, +Sin opening; who thus now to Death began. +O Son, why sit we here each other viewing +Idly, while Satan, our great author, thrives +In other worlds, and happier seat provides +For us, his offspring dear? It cannot be +But that success attends him; if mishap, +Ere this he had returned, with fury driven +By his avengers; since no place like this +Can fit his punishment, or their revenge. +Methinks I feel new strength within me rise, +Wings growing, and dominion given me large +Beyond this deep; whatever draws me on, +Or sympathy, or some connatural force, +Powerful at greatest distance to unite, +With secret amity, things of like kind, +By secretest conveyance. Thou, my shade +Inseparable, must with me along; +For Death from Sin no power can separate. +But, lest the difficulty of passing back +Stay his return perhaps over this gulf +Impassable, impervious; let us try +Adventurous work, yet to thy power and mine +Not unagreeable, to found a path +Over this main from Hell to that new world, +Where Satan now prevails; a monument +Of merit high to all the infernal host, +Easing their passage hence, for intercourse, +Or transmigration, as their lot shall lead. +Nor can I miss the way, so strongly drawn +By this new-felt attraction and instinct. +Whom thus the meager Shadow answered soon. +Go, whither Fate, and inclination strong, +Leads thee; I shall not lag behind, nor err +The way, thou leading; such a scent I draw +Of carnage, prey innumerable, and taste +The savour of death from all things there that live: +Nor shall I to the work thou enterprisest +Be wanting, but afford thee equal aid. +So saying, with delight he snuffed the smell +Of mortal change on earth. As when a flock +Of ravenous fowl, though many a league remote, +Against the day of battle, to a field, +Where armies lie encamped, come flying, lured +With scent of living carcasses designed +For death, the following day, in bloody fight: +So scented the grim Feature, and upturned +His nostril wide into the murky air; +Sagacious of his quarry from so far. +Then both from out Hell-gates, into the waste +Wide anarchy of Chaos, damp and dark, +Flew diverse; and with power (their power was great) +Hovering upon the waters, what they met +Solid or slimy, as in raging sea +Tost up and down, together crouded drove, +From each side shoaling towards the mouth of Hell; +As when two polar winds, blowing adverse +Upon the Cronian sea, together drive +Mountains of ice, that stop the imagined way +Beyond Petsora eastward, to the rich +Cathaian coast. The aggregated soil +Death with his mace petrifick, cold and dry, +As with a trident, smote; and fixed as firm +As Delos, floating once; the rest his look +Bound with Gorgonian rigour not to move; +And with Asphaltick slime, broad as the gate, +Deep to the roots of Hell the gathered beach +They fastened, and the mole immense wrought on +Over the foaming deep high-arched, a bridge +Of length prodigious, joining to the wall +Immoveable of this now fenceless world, +Forfeit to Death; from hence a passage broad, +Smooth, easy, inoffensive, down to Hell. +So, if great things to small may be compared, +Xerxes, the liberty of Greece to yoke, +From Susa, his Memnonian palace high, +Came to the sea: and, over Hellespont +Bridging his way, Europe with Asia joined, +And scourged with many a stroke the indignant waves. +Now had they brought the work by wonderous art +Pontifical, a ridge of pendant rock, +Over the vexed abyss, following the track +Of Satan to the self-same place where he +First lighted from his wing, and landed safe +From out of Chaos, to the outside bare +Of this round world: With pins of adamant +And chains they made all fast, too fast they made +And durable! And now in little space +The confines met of empyrean Heaven, +And of this World; and, on the left hand, Hell +With long reach interposed; three several ways +In sight, to each of these three places led. +And now their way to Earth they had descried, +To Paradise first tending; when, behold! +Satan, in likeness of an Angel bright, +Betwixt the Centaur and the Scorpion steering +His zenith, while the sun in Aries rose: +Disguised he came; but those his children dear +Their parent soon discerned, though in disguise. +He, after Eve seduced, unminded slunk +Into the wood fast by; and, changing shape, +To observe the sequel, saw his guileful act +By Eve, though all unweeting, seconded +Upon her husband; saw their shame that sought +Vain covertures; but when he saw descend +The Son of God to judge them, terrified +He fled; not hoping to escape, but shun +The present; fearing, guilty, what his wrath +Might suddenly inflict; that past, returned +By night, and listening where the hapless pair +Sat in their sad discourse, and various plaint, +Thence gathered his own doom; which understood +Not instant, but of future time, with joy +And tidings fraught, to Hell he now returned; +And at the brink of Chaos, near the foot +Of this new wonderous pontifice, unhoped +Met, who to meet him came, his offspring dear. +Great joy was at their meeting, and at sight +Of that stupendious bridge his joy encreased. +Long he admiring stood, till Sin, his fair +Enchanting daughter, thus the silence broke. +O Parent, these are thy magnifick deeds, +Thy trophies! which thou viewest as not thine own; +Thou art their author, and prime architect: +For I no sooner in my heart divined, +My heart, which by a secret harmony +Still moves with thine, joined in connexion sweet, +That thou on earth hadst prospered, which thy looks +Now also evidence, but straight I felt, +Though distant from thee worlds between, yet felt, +That I must after thee, with this thy son; +Such fatal consequence unites us three! +Hell could no longer hold us in our bounds, +Nor this unvoyageable gulf obscure +Detain from following thy illustrious track. +Thou hast achieved our liberty, confined +Within Hell-gates till now; thou us impowered +To fortify thus far, and overlay, +With this portentous bridge, the dark abyss. +Thine now is all this world; thy virtue hath won +What thy hands builded not; thy wisdom gained +With odds what war hath lost, and fully avenged +Our foil in Heaven; here thou shalt monarch reign, +There didst not; there let him still victor sway, +As battle hath adjudged; from this new world +Retiring, by his own doom alienated; +And henceforth monarchy with thee divide +Of all things, parted by the empyreal bounds, +His quadrature, from thy orbicular world; +Or try thee now more dangerous to his throne. +Whom thus the Prince of darkness answered glad. +Fair Daughter, and thou Son and Grandchild both; +High proof ye now have given to be the race +Of Satan (for I glory in the name, +Antagonist of Heaven's Almighty King,) +Amply have merited of me, of all +The infernal empire, that so near Heaven's door +Triumphal with triumphal act have met, +Mine, with this glorious work; and made one realm, +Hell and this world, one realm, one continent +Of easy thorough-fare. Therefore, while I +Descend through darkness, on your road with ease, +To my associate Powers, them to acquaint +With these successes, and with them rejoice; +You two this way, among these numerous orbs, +All yours, right down to Paradise descend; +There dwell, and reign in bliss; thence on the earth +Dominion exercise and in the air, +Chiefly on Man, sole lord of all declared; +Him first make sure your thrall, and lastly kill. +My substitutes I send ye, and create +Plenipotent on earth, of matchless might +Issuing from me: on your joint vigour now +My hold of this new kingdom all depends, +Through Sin to Death exposed by my exploit. +If your joint power prevail, the affairs of Hell +No detriment need fear; go, and be strong! +So saying he dismissed them; they with speed +Their course through thickest constellations held, +Spreading their bane; the blasted stars looked wan, +And planets, planet-struck, real eclipse +Then suffered. The other way Satan went down +The causey to Hell-gate: On either side +Disparted Chaos overbuilt exclaimed, +And with rebounding surge the bars assailed, +That scorned his indignation: Through the gate, +Wide open and unguarded, Satan passed, +And all about found desolate; for those, +Appointed to sit there, had left their charge, +Flown to the upper world; the rest were all +Far to the inland retired, about the walls +Of Pandemonium; city and proud seat +Of Lucifer, so by allusion called +Of that bright star to Satan paragoned; +There kept their watch the legions, while the Grand +In council sat, solicitous what chance +Might intercept their emperour sent; so he +Departing gave command, and they observed. +As when the Tartar from his Russian foe, +By Astracan, over the snowy plains, +Retires; or Bactrin Sophi, from the horns +Of Turkish crescent, leaves all waste beyond +The realm of Aladule, in his retreat +To Tauris or Casbeen: So these, the late +Heaven-banished host, left desart utmost Hell +Many a dark league, reduced in careful watch +Round their metropolis; and now expecting +Each hour their great adventurer, from the search +Of foreign worlds: He through the midst unmarked, +In show plebeian Angel militant +Of lowest order, passed; and from the door +Of that Plutonian hall, invisible +Ascended his high throne; which, under state +Of richest texture spread, at the upper end +Was placed in regal lustre. Down a while +He sat, and round about him saw unseen: +At last, as from a cloud, his fulgent head +And shape star-bright appeared, or brighter; clad +With what permissive glory since his fall +Was left him, or false glitter: All amazed +At that so sudden blaze the Stygian throng +Bent their aspect, and whom they wished beheld, +Their mighty Chief returned: loud was the acclaim: +Forth rushed in haste the great consulting peers, +Raised from their dark Divan, and with like joy +Congratulant approached him; who with hand +Silence, and with these words attention, won. +Thrones, Dominations, Princedoms, Virtues, Powers; +For in possession such, not only of right, +I call ye, and declare ye now; returned +Successful beyond hope, to lead ye forth +Triumphant out of this infernal pit +Abominable, accursed, the house of woe, +And dungeon of our tyrant: Now possess, +As Lords, a spacious world, to our native Heaven +Little inferiour, by my adventure hard +With peril great achieved. Long were to tell +What I have done; what suffered;with what pain +Voyaged th' unreal, vast, unbounded deep +Of horrible confusion; over which +By Sin and Death a broad way now is paved, +To expedite your glorious march; but I +Toiled out my uncouth passage, forced to ride +The untractable abyss, plunged in the womb +Of unoriginal Night and Chaos wild; +That, jealous of their secrets, fiercely opposed +My journey strange, with clamorous uproar +Protesting Fate supreme; thence how I found +The new created world, which fame in Heaven +Long had foretold, a fabrick wonderful +Of absolute perfection! therein Man +Placed in a Paradise, by our exile +Made happy: Him by fraud I have seduced +From his Creator; and, the more to encrease +Your wonder, with an apple; he, thereat +Offended, worth your laughter! hath given up +Both his beloved Man, and all his world, +To Sin and Death a prey, and so to us, +Without our hazard, labour, or alarm; +To range in, and to dwell, and over Man +To rule, as over all he should have ruled. +True is, me also he hath judged, or rather +Me not, but the brute serpent in whose shape +Man I deceived: that which to me belongs, +Is enmity which he will put between +Me and mankind; I am to bruise his heel; +His seed, when is not set, shall bruise my head: +A world who would not purchase with a bruise, +Or much more grievous pain?--Ye have the account +Of my performance: What remains, ye Gods, +But up, and enter now into full bliss? +So having said, a while he stood, expecting +Their universal shout, and high applause, +To fill his ear; when, contrary, he hears +On all sides, from innumerable tongues, +A dismal universal hiss, the sound +Of publick scorn; he wondered, but not long +Had leisure, wondering at himself now more, +His visage drawn he felt to sharp and spare; +His arms clung to his ribs; his legs entwining +Each other, till supplanted down he fell +A monstrous serpent on his belly prone, +Reluctant, but in vain; a greater power +Now ruled him, punished in the shape he sinned, +According to his doom: he would have spoke, +But hiss for hiss returned with forked tongue +To forked tongue; for now were all transformed +Alike, to serpents all, as accessories +To his bold riot: Dreadful was the din +Of hissing through the hall, thick swarming now +With complicated monsters head and tail, +Scorpion, and Asp, and Amphisbaena dire, +Cerastes horned, Hydrus, and Elops drear, +And Dipsas; (not so thick swarmed once the soil +Bedropt with blood of Gorgon, or the isle +Ophiusa,) but still greatest he the midst, +Now Dragon grown, larger than whom the sun +Ingendered in the Pythian vale or slime, +Huge Python, and his power no less he seemed +Above the rest still to retain; they all +Him followed, issuing forth to the open field, +Where all yet left of that revolted rout, +Heaven-fallen, in station stood or just array; +Sublime with expectation when to see +In triumph issuing forth their glorious Chief; +They saw, but other sight instead! a croud +Of ugly serpents; horrour on them fell, +And horrid sympathy; for, what they saw, +They felt themselves, now changing; down their arms, +Down fell both spear and shield; down they as fast; +And the dire hiss renewed, and the dire form +Catched, by contagion; like in punishment, +As in their crime. Thus was the applause they meant, +Turned to exploding hiss, triumph to shame +Cast on themselves from their own mouths. There stood +A grove hard by, sprung up with this their change, +His will who reigns above, to aggravate +Their penance, laden with fair fruit, like that +Which grew in Paradise, the bait of Eve +Used by the Tempter: on that prospect strange +Their earnest eyes they fixed, imagining +For one forbidden tree a multitude +Now risen, to work them further woe or shame; +Yet, parched with scalding thirst and hunger fierce, +Though to delude them sent, could not abstain; +But on they rolled in heaps, and, up the trees +Climbing, sat thicker than the snaky locks +That curled Megaera: greedily they plucked +The fruitage fair to sight, like that which grew +Near that bituminous lake where Sodom flamed; +This more delusive, not the touch, but taste +Deceived; they, fondly thinking to allay +Their appetite with gust, instead of fruit +Chewed bitter ashes, which the offended taste +With spattering noise rejected: oft they assayed, +Hunger and thirst constraining; drugged as oft, +With hatefullest disrelish writhed their jaws, +With soot and cinders filled; so oft they fell +Into the same illusion, not as Man +Whom they triumphed once lapsed. Thus were they plagued +And worn with famine, long and ceaseless hiss, +Till their lost shape, permitted, they resumed; +Yearly enjoined, some say, to undergo, +This annual humbling certain numbered days, +To dash their pride, and joy, for Man seduced. +However, some tradition they dispersed +Among the Heathen, of their purchase got, +And fabled how the Serpent, whom they called +Ophion, with Eurynome, the wide-- +Encroaching Eve perhaps, had first the rule +Of high Olympus; thence by Saturn driven +And Ops, ere yet Dictaean Jove was born. +Mean while in Paradise the hellish pair +Too soon arrived; Sin, there in power before, +Once actual; now in body, and to dwell +Habitual habitant; behind her Death, +Close following pace for pace, not mounted yet +On his pale horse: to whom Sin thus began. +Second of Satan sprung, all-conquering Death! +What thinkest thou of our empire now, though earned +With travel difficult, not better far +Than still at Hell's dark threshold to have sat watch, +Unnamed, undreaded, and thyself half starved? +Whom thus the Sin-born monster answered soon. +To me, who with eternal famine pine, +Alike is Hell, or Paradise, or Heaven; +There best, where most with ravine I may meet; +Which here, though plenteous, all too little seems +To stuff this maw, this vast unhide-bound corps. +To whom the incestuous mother thus replied. +Thou therefore on these herbs, and fruits, and flowers, +Feed first; on each beast next, and fish, and fowl; +No homely morsels! and, whatever thing +The sithe of Time mows down, devour unspared; +Till I, in Man residing, through the race, +His thoughts, his looks, words, actions, all infect; +And season him thy last and sweetest prey. +This said, they both betook them several ways, +Both to destroy, or unimmortal make +All kinds, and for destruction to mature +Sooner or later; which the Almighty seeing, +From his transcendent seat the Saints among, +To those bright Orders uttered thus his voice. +See, with what heat these dogs of Hell advance +To waste and havock yonder world, which I +So fair and good created; and had still +Kept in that state, had not the folly of Man +Let in these wasteful furies, who impute +Folly to me; so doth the Prince of Hell +And his adherents, that with so much ease +I suffer them to enter and possess +A place so heavenly; and, conniving, seem +To gratify my scornful enemies, +That laugh, as if, transported with some fit +Of passion, I to them had quitted all, +At random yielded up to their misrule; +And know not that I called, and drew them thither, +My Hell-hounds, to lick up the draff and filth +Which Man's polluting sin with taint hath shed +On what was pure; til, crammed and gorged, nigh burst +With sucked and glutted offal, at one sling +Of thy victorious arm, well-pleasing Son, +Both Sin, and Death, and yawning Grave, at last, +Through Chaos hurled, obstruct the mouth of Hell +For ever, and seal up his ravenous jaws. +Then Heaven and Earth renewed shall be made pure +To sanctity, that shall receive no stain: +Till then, the curse pronounced on both precedes. +He ended, and the heavenly audience loud +Sung Halleluiah, as the sound of seas, +Through multitude that sung: Just are thy ways, +Righteous are thy decrees on all thy works; +Who can extenuate thee? Next, to the Son, +Destined Restorer of mankind, by whom +New Heaven and Earth shall to the ages rise, +Or down from Heaven descend.--Such was their song; +While the Creator, calling forth by name +His mighty Angels, gave them several charge, +As sorted best with present things. The sun +Had first his precept so to move, so shine, +As might affect the earth with cold and heat +Scarce tolerable; and from the north to call +Decrepit winter; from the south to bring +Solstitial summer's heat. To the blanc moon +Her office they prescribed; to the other five +Their planetary motions, and aspects, +In sextile, square, and trine, and opposite, +Of noxious efficacy, and when to join +In synod unbenign; and taught the fixed +Their influence malignant when to shower, +Which of them rising with the sun, or falling, +Should prove tempestuous: To the winds they set +Their corners, when with bluster to confound +Sea, air, and shore; the thunder when to roll +With terrour through the dark aereal hall. +Some say, he bid his Angels turn ascanse +The poles of earth, twice ten degrees and more, +From the sun's axle; they with labour pushed +Oblique the centrick globe: Some say, the sun +Was bid turn reins from the equinoctial road +Like distant breadth to Taurus with the seven +Atlantick Sisters, and the Spartan Twins, +Up to the Tropick Crab: thence down amain +By Leo, and the Virgin, and the Scales, +As deep as Capricorn; to bring in change +Of seasons to each clime; else had the spring +Perpetual smiled on earth with vernant flowers, +Equal in days and nights, except to those +Beyond the polar circles; to them day +Had unbenighted shone, while the low sun, +To recompense his distance, in their sight +Had rounded still the horizon, and not known +Or east or west; which had forbid the snow +From cold Estotiland, and south as far +Beneath Magellan. At that tasted fruit +The sun, as from Thyestean banquet, turned +His course intended; else, how had the world +Inhabited, though sinless, more than now, +Avoided pinching cold and scorching heat? +These changes in the Heavens, though slow, produced +Like change on sea and land; sideral blast, +Vapour, and mist, and exhalation hot, +Corrupt and pestilent: Now from the north +Of Norumbega, and the Samoed shore, +Bursting their brazen dungeon, armed with ice, +And snow, and hail, and stormy gust and flaw, +Boreas, and Caecias, and Argestes loud, +And Thrascias, rend the woods, and seas upturn; +With adverse blast upturns them from the south +Notus, and Afer black with thunderous clouds +From Serraliona; thwart of these, as fierce, +Forth rush the Levant and the Ponent winds, +Eurus and Zephyr, with their lateral noise, +Sirocco and Libecchio. Thus began +Outrage from lifeless things; but Discord first, +Daughter of Sin, among the irrational +Death introduced, through fierce antipathy: +Beast now with beast 'gan war, and fowl with fowl, +And fish with fish; to graze the herb all leaving, +Devoured each other; nor stood much in awe +Of Man, but fled him; or, with countenance grim, +Glared on him passing. These were from without +The growing miseries, which Adam saw +Already in part, though hid in gloomiest shade, +To sorrow abandoned, but worse felt within; +And, in a troubled sea of passion tost, +Thus to disburden sought with sad complaint. +O miserable of happy! Is this the end +Of this new glorious world, and me so late +The glory of that glory, who now become +Accursed, of blessed? hide me from the face +Of God, whom to behold was then my highth +Of happiness!--Yet well, if here would end +The misery; I deserved it, and would bear +My own deservings; but this will not serve: +All that I eat or drink, or shall beget, +Is propagated curse. O voice, once heard +Delightfully, Encrease and multiply; +Now death to hear! for what can I encrease, +Or multiply, but curses on my head? +Who of all ages to succeed, but, feeling +The evil on him brought by me, will curse +My head? Ill fare our ancestor impure, +For this we may thank Adam! but his thanks +Shall be the execration: so, besides +Mine own that bide upon me, all from me +Shall with a fierce reflux on me rebound; +On me, as on their natural center, light +Heavy, though in their place. O fleeting joys +Of Paradise, dear bought with lasting woes! +Did I request thee, Maker, from my clay +To mould me Man? did I solicit thee +From darkness to promote me, or here place +In this delicious garden? As my will +Concurred not to my being, it were but right +And equal to reduce me to my dust; +Desirous to resign and render back +All I received; unable to perform +Thy terms too hard, by which I was to hold +The good I sought not. To the loss of that, +Sufficient penalty, why hast thou added +The sense of endless woes? Inexplicable +Why am I mocked with death, and lengthened out +To deathless pain? How gladly would I meet +Mortality my sentence, and be earth +Insensible! How glad would lay me down +As in my mother's lap! There I should rest, +And sleep secure; his dreadful voice no more +Would thunder in my ears; no fear of worse +To me, and to my offspring, would torment me +With cruel expectation. Yet one doubt +Pursues me still, lest all I cannot die; +Lest that pure breath of life, the spirit of Man +Which God inspired, cannot together perish +With this corporeal clod; then, in the grave, +Or in some other dismal place, who knows +But I shall die a living death? O thought +Horrid, if true! Yet why? It was but breath +Of life that sinned; what dies but what had life +And sin? The body properly had neither, +All of me then shall die: let this appease +The doubt, since human reach no further knows. +For though the Lord of all be infinite, +Is his wrath also? Be it, Man is not so, +But mortal doomed. How can he exercise +Wrath without end on Man, whom death must end? +Can he make deathless death? That were to make +Strange contradiction, which to God himself +Impossible is held; as argument +Of weakness, not of power. Will he draw out, +For anger's sake, finite to infinite, +In punished Man, to satisfy his rigour, +Satisfied never? That were to extend +His sentence beyond dust and Nature's law; +By which all causes else, according still +To the reception of their matter, act; +Not to the extent of their own sphere. But say +That death be not one stroke, as I supposed, +Bereaving sense, but endless misery +From this day onward; which I feel begun +Both in me, and without me; and so last +To perpetuity;--Ay me!that fear +Comes thundering back with dreadful revolution +On my defenceless head; both Death and I +Am found eternal, and incorporate both; +Nor I on my part single; in me all +Posterity stands cursed: Fair patrimony +That I must leave ye, Sons! O, were I able +To waste it all myself, and leave ye none! +So disinherited, how would you bless +Me, now your curse! Ah, why should all mankind, +For one man's fault, thus guiltless be condemned, +It guiltless? But from me what can proceed, +But all corrupt; both mind and will depraved +Not to do only, but to will the same +With me? How can they then acquitted stand +In sight of God? Him, after all disputes, +Forced I absolve: all my evasions vain, +And reasonings, though through mazes, lead me still +But to my own conviction: first and last +On me, me only, as the source and spring +Of all corruption, all the blame lights due; +So might the wrath! Fond wish!couldst thou support +That burden, heavier than the earth to bear; +Than all the world much heavier, though divided +With that bad Woman? Thus, what thou desirest, +And what thou fearest, alike destroys all hope +Of refuge, and concludes thee miserable +Beyond all past example and future; +To Satan only like both crime and doom. +O Conscience! into what abyss of fears +And horrours hast thou driven me; out of which +I find no way, from deep to deeper plunged! +Thus Adam to himself lamented loud, +Through the still night; not now, as ere Man fell, +Wholesome, and cool, and mild, but with black air +Accompanied; with damps, and dreadful gloom; +Which to his evil conscience represented +All things with double terrour: On the ground +Outstretched he lay, on the cold ground; and oft +Cursed his creation; Death as oft accused +Of tardy execution, since denounced +The day of his offence. Why comes not Death, +Said he, with one thrice-acceptable stroke +To end me? Shall Truth fail to keep her word, +Justice Divine not hasten to be just? +But Death comes not at call; Justice Divine +Mends not her slowest pace for prayers or cries, +O woods, O fountains, hillocks, dales, and bowers! +With other echo late I taught your shades +To answer, and resound far other song.-- +Whom thus afflicted when sad Eve beheld, +Desolate where she sat, approaching nigh, +Soft words to his fierce passion she assayed: +But her with stern regard he thus repelled. +Out of my sight, thou Serpent! That name best +Befits thee with him leagued, thyself as false +And hateful; nothing wants, but that thy shape, +Like his, and colour serpentine, may show +Thy inward fraud; to warn all creatures from thee +Henceforth; lest that too heavenly form, pretended +To hellish falshood, snare them! But for thee +I had persisted happy; had not thy pride +And wandering vanity, when least was safe, +Rejected my forewarning, and disdained +Not to be trusted; longing to be seen, +Though by the Devil himself; him overweening +To over-reach; but, with the serpent meeting, +Fooled and beguiled; by him thou, I by thee +To trust thee from my side; imagined wise, +Constant, mature, proof against all assaults; +And understood not all was but a show, +Rather than solid virtue; all but a rib +Crooked by nature, bent, as now appears, +More to the part sinister, from me drawn; +Well if thrown out, as supernumerary +To my just number found. O! why did God, +Creator wise, that peopled highest Heaven +With Spirits masculine, create at last +This novelty on earth, this fair defect +Of nature, and not fill the world at once +With Men, as Angels, without feminine; +Or find some other way to generate +Mankind? This mischief had not been befallen, +And more that shall befall; innumerable +Disturbances on earth through female snares, +And strait conjunction with this sex: for either +He never shall find out fit mate, but such +As some misfortune brings him, or mistake; +Or whom he wishes most shall seldom gain +Through her perverseness, but shall see her gained +By a far worse; or, if she love, withheld +By parents; or his happiest choice too late +Shall meet, already linked and wedlock-bound +To a fell adversary, his hate or shame: +Which infinite calamity shall cause +To human life, and houshold peace confound. +He added not, and from her turned; but Eve, +Not so repulsed, with tears that ceased not flowing +And tresses all disordered, at his feet +Fell humble; and, embracing them, besought +His peace, and thus proceeded in her plaint. +Forsake me not thus, Adam! witness Heaven +What love sincere, and reverence in my heart +I bear thee, and unweeting have offended, +Unhappily deceived! Thy suppliant +I beg, and clasp thy knees; bereave me not, +Whereon I live, thy gentle looks, thy aid, +Thy counsel, in this uttermost distress, +My only strength and stay: Forlorn of thee, +Whither shall I betake me, where subsist? +While yet we live, scarce one short hour perhaps, +Between us two let there be peace; both joining, +As joined in injuries, one enmity +Against a foe by doom express assigned us, +That cruel Serpent: On me exercise not +Thy hatred for this misery befallen; +On me already lost, me than thyself +More miserable! Both have sinned;but thou +Against God only; I against God and thee; +And to the place of judgement will return, +There with my cries importune Heaven; that all +The sentence, from thy head removed, may light +On me, sole cause to thee of all this woe; +Me, me only, just object of his ire! +She ended weeping; and her lowly plight, +Immoveable, till peace obtained from fault +Acknowledged and deplored, in Adam wrought +Commiseration: Soon his heart relented +Towards her, his life so late, and sole delight, +Now at his feet submissive in distress; +Creature so fair his reconcilement seeking, +His counsel, whom she had displeased, his aid: +As one disarmed, his anger all he lost, +And thus with peaceful words upraised her soon. +Unwary, and too desirous, as before, +So now of what thou knowest not, who desirest +The punishment all on thyself; alas! +Bear thine own first, ill able to sustain +His full wrath, whose thou feelest as yet least part, +And my displeasure bearest so ill. If prayers +Could alter high decrees, I to that place +Would speed before thee, and be louder heard, +That on my head all might be visited; +Thy frailty and infirmer sex forgiven, +To me committed, and by me exposed. +But rise;--let us no more contend, nor blame +Each other, blamed enough elsewhere; but strive +In offices of love, how we may lighten +Each other's burden, in our share of woe; +Since this day's death denounced, if aught I see, +Will prove no sudden, but a slow-paced evil; +A long day's dying, to augment our pain; +And to our seed (O hapless seed!) derived. +To whom thus Eve, recovering heart, replied. +Adam, by sad experiment I know +How little weight my words with thee can find, +Found so erroneous; thence by just event +Found so unfortunate: Nevertheless, +Restored by thee, vile as I am, to place +Of new acceptance, hopeful to regain +Thy love, the sole contentment of my heart +Living or dying, from thee I will not hide +What thoughts in my unquiet breast are risen, +Tending to some relief of our extremes, +Or end; though sharp and sad, yet tolerable, +As in our evils, and of easier choice. +If care of our descent perplex us most, +Which must be born to certain woe, devoured +By Death at last; and miserable it is +To be to others cause of misery, +Our own begotten, and of our loins to bring +Into this cursed world a woeful race, +That after wretched life must be at last +Food for so foul a monster; in thy power +It lies, yet ere conception to prevent +The race unblest, to being yet unbegot. +Childless thou art, childless remain: so Death +Shall be deceived his glut, and with us two +Be forced to satisfy his ravenous maw. +But if thou judge it hard and difficult, +Conversing, looking, loving, to abstain +From love's due rights, nuptial embraces sweet; +And with desire to languish without hope, +Before the present object languishing +With like desire; which would be misery +And torment less than none of what we dread; +Then, both ourselves and seed at once to free +From what we fear for both, let us make short, -- +Let us seek Death; -- or, he not found, supply +With our own hands his office on ourselves: +Why stand we longer shivering under fears, +That show no end but death, and have the power, +Of many ways to die the shortest choosing, +Destruction with destruction to destroy? -- +She ended here, or vehement despair +Broke off the rest: so much of death her thoughts +Had entertained, as dyed her cheeks with pale. +But Adam, with such counsel nothing swayed, +To better hopes his more attentive mind +Labouring had raised; and thus to Eve replied. +Eve, thy contempt of life and pleasure seems +To argue in thee something more sublime +And excellent, than what thy mind contemns; +But self-destruction therefore sought, refutes +That excellence thought in thee; and implies, +Not thy contempt, but anguish and regret +For loss of life and pleasure overloved. +Or if thou covet death, as utmost end +Of misery, so thinking to evade +The penalty pronounced; doubt not but God +Hath wiselier armed his vengeful ire, than so +To be forestalled; much more I fear lest death, +So snatched, will not exempt us from the pain +We are by doom to pay; rather, such acts +Of contumacy will provoke the Highest +To make death in us live: Then let us seek +Some safer resolution, which methinks +I have in view, calling to mind with heed +Part of our sentence, that thy seed shall bruise +The Serpent's head; piteous amends! unless +Be meant, whom I conjecture, our grand foe, +Satan; who, in the serpent, hath contrived +Against us this deceit: To crush his head +Would be revenge indeed! which will be lost +By death brought on ourselves, or childless days +Resolved, as thou proposest; so our foe +Shal 'scape his punishment ordained, and we +Instead shall double ours upon our heads. +No more be mentioned then of violence +Against ourselves; and wilful barrenness, +That cuts us off from hope; and savours only +Rancour and pride, impatience and despite, +Reluctance against God and his just yoke +Laid on our necks. Remember with what mild +And gracious temper he both heard, and judged, +Without wrath or reviling; we expected +Immediate dissolution, which we thought +Was meant by death that day; when lo!to thee +Pains only in child-bearing were foretold, +And bringing forth; soon recompensed with joy, +Fruit of thy womb: On me the curse aslope +Glanced on the ground; with labour I must earn +My bread; what harm? Idleness had been worse; +My labour will sustain me; and, lest cold +Or heat should injure us, his timely care +Hath, unbesought, provided; and his hands +Clothed us unworthy, pitying while he judged; +How much more, if we pray him, will his ear +Be open, and his heart to pity incline, +And teach us further by what means to shun +The inclement seasons, rain, ice, hail, and snow! +Which now the sky, with various face, begins +To show us in this mountain; while the winds +Blow moist and keen, shattering the graceful locks +Of these fair spreading trees; which bids us seek +Some better shroud, some better warmth to cherish +Our limbs benummed, ere this diurnal star +Leave cold the night, how we his gathered beams +Reflected may with matter sere foment; +Or, by collision of two bodies, grind +The air attrite to fire; as late the clouds +Justling, or pushed with winds, rude in their shock, +Tine the slant lightning; whose thwart flame, driven down +Kindles the gummy bark of fir or pine; +And sends a comfortable heat from far, +Which might supply the sun: Such fire to use, +And what may else be remedy or cure +To evils which our own misdeeds have wrought, +He will instruct us praying, and of grace +Beseeching him; so as we need not fear +To pass commodiously this life, sustained +By him with many comforts, till we end +In dust, our final rest and native home. +What better can we do, than, to the place +Repairing where he judged us, prostrate fall +Before him reverent; and there confess +Humbly our faults, and pardon beg; with tears +Watering the ground, and with our sighs the air +Frequenting, sent from hearts contrite, in sign +Of sorrow unfeigned, and humiliation meek + + + +Book XI + + +Undoubtedly he will relent, and turn +From his displeasure; in whose look serene, +When angry most he seemed and most severe, +What else but favour, grace, and mercy, shone? +So spake our father penitent; nor Eve +Felt less remorse: they, forthwith to the place +Repairing where he judged them, prostrate fell +Before him reverent; and both confessed +Humbly their faults, and pardon begged; with tears +Watering the ground, and with their sighs the air +Frequenting, sent from hearts contrite, in sign +Of sorrow unfeigned, and humiliation meek. +Thus they, in lowliest plight, repentant stood +Praying; for from the mercy-seat above +Prevenient grace descending had removed +The stony from their hearts, and made new flesh +Regenerate grow instead; that sighs now breathed +Unutterable; which the Spirit of prayer +Inspired, and winged for Heaven with speedier flight +Than loudest oratory: Yet their port +Not of mean suitors; nor important less +Seemed their petition, than when the ancient pair +In fables old, less ancient yet than these, +Deucalion and chaste Pyrrha, to restore +The race of mankind drowned, before the shrine +Of Themis stood devout. To Heaven their prayers +Flew up, nor missed the way, by envious winds +Blown vagabond or frustrate: in they passed +Dimensionless through heavenly doors; then clad +With incense, where the golden altar fumed, +By their great intercessour, came in sight +Before the Father's throne: them the glad Son +Presenting, thus to intercede began. +See$ Father, what first-fruits on earth are sprung +From thy implanted grace in Man; these sighs +And prayers, which in this golden censer mixed +With incense, I thy priest before thee bring; +Fruits of more pleasing savour, from thy seed +Sown with contrition in his heart, than those +Which, his own hand manuring, all the trees +Of Paradise could have produced, ere fallen +From innocence. Now therefore, bend thine ear +To supplication; hear his sighs, though mute; +Unskilful with what words to pray, let me +Interpret for him; me, his advocate +And propitiation; all his works on me, +Good, or not good, ingraft; my merit those +Shall perfect, and for these my death shall pay. +Accept me; and, in me, from these receive +The smell of peace toward mankind: let him live +Before thee reconciled, at least his days +Numbered, though sad; till death, his doom, (which I +To mitigate thus plead, not to reverse,) +To better life shall yield him: where with me +All my redeemed may dwell in joy and bliss; +Made one with me, as I with thee am one. +To whom the Father, without cloud, serene. +All thy request for Man, accepted Son, +Obtain; all thy request was my decree: +But, longer in that Paradise to dwell, +The law I gave to Nature him forbids: +Those pure immortal elements, that know, +No gross, no unharmonious mixture foul, +Eject him, tainted now; and purge him off, +As a distemper, gross, to air as gross, +And mortal food; as may dispose him best +For dissolution wrought by sin, that first +Distempered all things, and of incorrupt +Corrupted. I, at first, with two fair gifts +Created him endowed; with happiness, +And immortality: that fondly lost, +This other served but to eternize woe; +Till I provided death: so death becomes +His final remedy; and, after life, +Tried in sharp tribulation, and refined +By faith and faithful works, to second life, +Waked in the renovation of the just, +Resigns him up with Heaven and Earth renewed. +But let us call to synod all the Blest, +Through Heaven's wide bounds: from them I will not hide +My judgements; how with mankind I proceed, +As how with peccant Angels late they saw, +And in their state, though firm, stood more confirmed. +He ended, and the Son gave signal high +To the bright minister that watched; he blew +His trumpet, heard in Oreb since perhaps +When God descended, and perhaps once more +To sound at general doom. The angelick blast +Filled all the regions: from their blisful bowers +Of amarantine shade, fountain or spring, +By the waters of life, where'er they sat +In fellowships of joy, the sons of light +Hasted, resorting to the summons high; +And took their seats; till from his throne supreme +The Almighty thus pronounced his sovran will. +O Sons, like one of us Man is become +To know both good and evil, since his taste +Of that defended fruit; but let him boast +His knowledge of good lost, and evil got; +Happier! had it sufficed him to have known +Good by itself, and evil not at all. +He sorrows now, repents, and prays contrite, +My motions in him; longer than they move, +His heart I know, how variable and vain, +Self-left. Lest therefore his now bolder hand +Reach also of the tree of life, and eat, +And live for ever, dream at least to live +For ever, to remove him I decree, +And send him from the garden forth to till +The ground whence he was taken, fitter soil. +Michael, this my behest have thou in charge; +Take to thee from among the Cherubim +Thy choice of flaming warriours, lest the Fiend, +Or in behalf of Man, or to invade +Vacant possession, some new trouble raise: +Haste thee, and from the Paradise of God +Without remorse drive out the sinful pair; +From hallowed ground the unholy; and denounce +To them, and to their progeny, from thence +Perpetual banishment. Yet, lest they faint +At the sad sentence rigorously urged, +(For I behold them softened, and with tears +Bewailing their excess,) all terrour hide. +If patiently thy bidding they obey, +Dismiss them not disconsolate; reveal +To Adam what shall come in future days, +As I shall thee enlighten; intermix +My covenant in the Woman's seed renewed; +So send them forth, though sorrowing, yet in peace: +And on the east side of the garden place, +Where entrance up from Eden easiest climbs, +Cherubick watch; and of a sword the flame +Wide-waving; all approach far off to fright, +And guard all passage to the tree of life: +Lest Paradise a receptacle prove +To Spirits foul, and all my trees their prey; +With whose stolen fruit Man once more to delude. +He ceased; and the arch-angelick Power prepared +For swift descent; with him the cohort bright +Of watchful Cherubim: four faces each +Had, like a double Janus; all their shape +Spangled with eyes more numerous than those +Of Argus, and more wakeful than to drouse, +Charmed with Arcadian pipe, the pastoral reed +Of Hermes, or his opiate rod. Mean while, +To re-salute the world with sacred light, +Leucothea waked; and with fresh dews imbalmed +The earth; when Adam and first matron Eve +Had ended now their orisons, and found +Strength added from above; new hope to spring +Out of despair; joy, but with fear yet linked; +Which thus to Eve his welcome words renewed. +Eve, easily my faith admit, that all +The good which we enjoy from Heaven descends; +But, that from us aught should ascend to Heaven +So prevalent as to concern the mind +Of God high-blest, or to incline his will, +Hard to belief may seem; yet this will prayer +Or one short sigh of human breath, upborne +Even to the seat of God. For since I sought +By prayer the offended Deity to appease; +Kneeled, and before him humbled all my heart; +Methought I saw him placable and mild, +Bending his ear; persuasion in me grew +That I was heard with favour; peace returned +Home to my breast, and to my memory +His promise, that thy seed shall bruise our foe; +Which, then not minded in dismay, yet now +Assures me that the bitterness of death +Is past, and we shall live. Whence hail to thee, +Eve rightly called, mother of all mankind, +Mother of all things living, since by thee +Man is to live; and all things live for Man. +To whom thus Eve with sad demeanour meek. +Ill-worthy I such title should belong +To me transgressour; who, for thee ordained +A help, became thy snare; to me reproach +Rather belongs, distrust, and all dispraise: +But infinite in pardon was my Judge, +That I, who first brought death on all, am graced +The source of life; next favourable thou, +Who highly thus to entitle me vouchsaf'st, +Far other name deserving. But the field +To labour calls us, now with sweat imposed, +Though after sleepless night; for see!the morn, +All unconcerned with our unrest, begins +Her rosy progress smiling: let us forth; +I never from thy side henceforth to stray, +Where'er our day's work lies, though now enjoined +Laborious, till day droop; while here we dwell, +What can be toilsome in these pleasant walks? +Here let us live, though in fallen state, content. +So spake, so wished much humbled Eve; but Fate +Subscribed not: Nature first gave signs, impressed +On bird, beast, air; air suddenly eclipsed, +After short blush of morn; nigh in her sight +The bird of Jove, stooped from his aery tour, +Two birds of gayest plume before him drove; +Down from a hill the beast that reigns in woods, +First hunter then, pursued a gentle brace, +Goodliest of all the forest, hart and hind; +Direct to the eastern gate was bent their flight. +Adam observed, and with his eye the chase +Pursuing, not unmoved, to Eve thus spake. +O Eve, some further change awaits us nigh, +Which Heaven, by these mute signs in Nature, shows +Forerunners of his purpose; or to warn +Us, haply too secure, of our discharge +From penalty, because from death released +Some days: how long, and what till then our life, +Who knows? or more than this, that we are dust, +And thither must return, and be no more? +Why else this double object in our sight +Of flight pursued in the air, and o'er the ground, +One way the self-same hour? why in the east +Darkness ere day's mid-course, and morning-light +More orient in yon western cloud, that draws +O'er the blue firmament a radiant white, +And slow descends with something heavenly fraught? +He erred not; for by this the heavenly bands +Down from a sky of jasper lighted now +In Paradise, and on a hill made halt; +A glorious apparition, had not doubt +And carnal fear that day dimmed Adam's eye. +Not that more glorious, when the Angels met +Jacob in Mahanaim, where he saw +The field pavilioned with his guardians bright; +Nor that, which on the flaming mount appeared +In Dothan, covered with a camp of fire, +Against the Syrian king, who to surprise +One man, assassin-like, had levied war, +War unproclaimed. The princely Hierarch +In their bright stand there left his Powers, to seise +Possession of the garden; he alone, +To find where Adam sheltered, took his way, +Not unperceived of Adam; who to Eve, +While the great visitant approached, thus spake. +Eve$ now expect great tidings, which perhaps +Of us will soon determine, or impose +New laws to be observed; for I descry, +From yonder blazing cloud that veils the hill, +One of the heavenly host; and, by his gait, +None of the meanest; some great Potentate +Or of the Thrones above; such majesty +Invests him coming! yet not terrible, +That I should fear; nor sociably mild, +As Raphael, that I should much confide; +But solemn and sublime; whom not to offend, +With reverence I must meet, and thou retire. +He ended: and the Arch-Angel soon drew nigh, +Not in his shape celestial, but as man +Clad to meet man; over his lucid arms +A military vest of purple flowed, +Livelier than Meliboean, or the grain +Of Sarra, worn by kings and heroes old +In time of truce; Iris had dipt the woof; +His starry helm unbuckled showed him prime +In manhood where youth ended; by his side, +As in a glistering zodiack, hung the sword, +Satan's dire dread; and in his hand the spear. +Adam bowed low; he, kingly, from his state +Inclined not, but his coming thus declared. +Adam, Heaven's high behest no preface needs: +Sufficient that thy prayers are heard; and Death, +Then due by sentence when thou didst transgress, +Defeated of his seisure many days +Given thee of grace; wherein thou mayest repent, +And one bad act with many deeds well done +Mayest cover: Well may then thy Lord, appeased, +Redeem thee quite from Death's rapacious claim; +But longer in this Paradise to dwell +Permits not: to remove thee I am come, +And send thee from the garden forth to till +The ground whence thou wast taken, fitter soil. +He added not; for Adam at the news +Heart-struck with chilling gripe of sorrow stood, +That all his senses bound; Eve, who unseen +Yet all had heard, with audible lament +Discovered soon the place of her retire. +O unexpected stroke, worse than of Death! +Must I thus leave thee$ Paradise? thus leave +Thee, native soil! these happy walks and shades, +Fit haunt of Gods? where I had hope to spend, +Quiet though sad, the respite of that day +That must be mortal to us both. O flowers, +That never will in other climate grow, +My early visitation, and my last + ;t even, which I bred up with tender hand +From the first opening bud, and gave ye names! +Who now shall rear ye to the sun, or rank +Your tribes, and water from the ambrosial fount? +Thee lastly, nuptial bower! by me adorned +With what to sight or smell was sweet! from thee +How shall I part, and whither wander down +Into a lower world; to this obscure +And wild? how shall we breathe in other air +Less pure, accustomed to immortal fruits? +Whom thus the Angel interrupted mild. +Lament not, Eve, but patiently resign +What justly thou hast lost, nor set thy heart, +Thus over-fond, on that which is not thine: +Thy going is not lonely; with thee goes +Thy husband; whom to follow thou art bound; +Where he abides, think there thy native soil. +Adam, by this from the cold sudden damp +Recovering, and his scattered spirits returned, +To Michael thus his humble words addressed. +Celestial, whether among the Thrones, or named +Of them the highest; for such of shape may seem +Prince above princes! gently hast thou told +Thy message, which might else in telling wound, +And in performing end us; what besides +Of sorrow, and dejection, and despair, +Our frailty can sustain, thy tidings bring, +Departure from this happy place, our sweet +Recess, and only consolation left +Familiar to our eyes! all places else +Inhospitable appear, and desolate; +Nor knowing us, nor known: And, if by prayer +Incessant I could hope to change the will +Of Him who all things can, I would not cease +To weary him with my assiduous cries: +But prayer against his absolute decree +No more avails than breath against the wind, +Blown stifling back on him that breathes it forth: +Therefore to his great bidding I submit. +This most afflicts me, that, departing hence, +As from his face I shall be hid, deprived +His blessed countenance: Here I could frequent +With worship place by place where he vouchsafed +Presence Divine; and to my sons relate, +'On this mount he appeared; under this tree +'Stood visible; among these pines his voice +'I heard; here with him at this fountain talked: +So many grateful altars I would rear +Of grassy turf, and pile up every stone +Of lustre from the brook, in memory, +Or monument to ages; and theron +Offer sweet-smelling gums, and fruits, and flowers: +In yonder nether world where shall I seek +His bright appearances, or foot-step trace? +For though I fled him angry, yet recalled +To life prolonged and promised race, I now +Gladly behold though but his utmost skirts +Of glory; and far off his steps adore. +To whom thus Michael with regard benign. +Adam, thou knowest Heaven his, and all the Earth; +Not this rock only; his Omnipresence fills +Land, sea, and air, and every kind that lives, +Fomented by his virtual power and warmed: +All the earth he gave thee to possess and rule, +No despicable gift; surmise not then +His presence to these narrow bounds confined +Of Paradise, or Eden: this had been +Perhaps thy capital seat, from whence had spread +All generations; and had hither come +From all the ends of the earth, to celebrate +And reverence thee, their great progenitor. +But this pre-eminence thou hast lost, brought down +To dwell on even ground now with thy sons: +Yet doubt not but in valley, and in plain, +God is, as here; and will be found alike +Present; and of his presence many a sign +Still following thee, still compassing thee round +With goodness and paternal love, his face +Express, and of his steps the track divine. +Which that thou mayest believe, and be confirmed +Ere thou from hence depart; know, I am sent +To show thee what shall come in future days +To thee, and to thy offspring: good with bad +Expect to hear; supernal grace contending +With sinfulness of men; thereby to learn +True patience, and to temper joy with fear +And pious sorrow; equally inured +By moderation either state to bear, +Prosperous or adverse: so shalt thou lead +Safest thy life, and best prepared endure +Thy mortal passage when it comes.--Ascend +This hill; let Eve (for I have drenched her eyes) +Here sleep below; while thou to foresight wakest; +As once thou sleptst, while she to life was formed. +To whom thus Adam gratefully replied. +Ascend, I follow thee, safe Guide, the path +Thou leadest me; and to the hand of Heaven submit, +However chastening; to the evil turn +My obvious breast; arming to overcome +By suffering, and earn rest from labour won, +If so I may attain. -- So both ascend +In the visions of God. It was a hill, +Of Paradise the highest; from whose top +The hemisphere of earth, in clearest ken, +Stretched out to the amplest reach of prospect lay. +Not higher that hill, nor wider looking round, +Whereon, for different cause, the Tempter set +Our second Adam, in the wilderness; +To show him all Earth's kingdoms, and their glory. +His eye might there command wherever stood +City of old or modern fame, the seat +Of mightiest empire, from the destined walls +Of Cambalu, seat of Cathaian Can, +And Samarchand by Oxus, Temir's throne, +To Paquin of Sinaean kings; and thence +To Agra and Lahor of great Mogul, +Down to the golden Chersonese; or where +The Persian in Ecbatan sat, or since +In Hispahan; or where the Russian Ksar +In Mosco; or the Sultan in Bizance, +Turchestan-born; nor could his eye not ken +The empire of Negus to his utmost port +Ercoco, and the less maritim kings +Mombaza, and Quiloa, and Melind, +And Sofala, thought Ophir, to the realm +Of Congo, and Angola farthest south; +Or thence from Niger flood to Atlas mount +The kingdoms of Almansor, Fez and Sus, +Morocco, and Algiers, and Tremisen; +On Europe thence, and where Rome was to sway +The world: in spirit perhaps he also saw +Rich Mexico, the seat of Montezume, +And Cusco in Peru, the richer seat +Of Atabalipa; and yet unspoiled +Guiana, whose great city Geryon's sons +Call El Dorado. But to nobler sights +Michael from Adam's eyes the film removed, +Which that false fruit that promised clearer sight +Had bred; then purged with euphrasy and rue +The visual nerve, for he had much to see; +And from the well of life three drops instilled. +So deep the power of these ingredients pierced, +Even to the inmost seat of mental sight, +That Adam, now enforced to close his eyes, +Sunk down, and all his spirits became entranced; +But him the gentle Angel by the hand +Soon raised, and his attention thus recalled. +Adam, now ope thine eyes; and first behold +The effects, which thy original crime hath wrought +In some to spring from thee; who never touched +The excepted tree; nor with the snake conspired; +Nor sinned thy sin; yet from that sin derive +Corruption, to bring forth more violent deeds. +His eyes he opened, and beheld a field, +Part arable and tilth, whereon were sheaves +New reaped; the other part sheep-walks and folds; +I' the midst an altar as the land-mark stood, +Rustick, of grassy sord; thither anon +A sweaty reaper from his tillage brought +First fruits, the green ear, and the yellow sheaf, +Unculled, as came to hand; a shepherd next, +More meek, came with the firstlings of his flock, +Choicest and best; then, sacrificing, laid +The inwards and their fat, with incense strowed, +On the cleft wood, and all due rights performed: +His offering soon propitious fire from Heaven +Consumed with nimble glance, and grateful steam; +The other's not, for his was not sincere; +Whereat he inly raged, and, as they talked, +Smote him into the midriff with a stone +That beat out life; he fell;and, deadly pale, +Groaned out his soul with gushing blood effused. +Much at that sight was Adam in his heart +Dismayed, and thus in haste to the Angel cried. +O Teacher, some great mischief hath befallen +To that meek man, who well had sacrificed; +Is piety thus and pure devotion paid? +To whom Michael thus, he also moved, replied. +These two are brethren, Adam, and to come +Out of thy loins; the unjust the just hath slain, +For envy that his brother's offering found +From Heaven acceptance; but the bloody fact +Will be avenged; and the other's faith, approved, +Lose no reward; though here thou see him die, +Rolling in dust and gore. To which our sire. +Alas! both for the deed, and for the cause! +But have I now seen Death? Is this the way +I must return to native dust? O sight +Of terrour, foul and ugly to behold, +Horrid to think, how horrible to feel! +To whom thus Michael. Death thou hast seen +In his first shape on Man; but many shapes +Of Death, and many are the ways that lead +To his grim cave, all dismal; yet to sense +More terrible at the entrance, than within. +Some, as thou sawest, by violent stroke shall die; +By fire, flood, famine, by intemperance more +In meats and drinks, which on the earth shall bring +Diseases dire, of which a monstrous crew +Before thee shall appear; that thou mayest know +What misery the inabstinence of Eve +Shall bring on Men. Immediately a place +Before his eyes appeared, sad, noisome, dark; +A lazar-house it seemed; wherein were laid +Numbers of all diseased; all maladies +Of ghastly spasm, or racking torture, qualms +Of heart-sick agony, all feverous kinds, +Convulsions, epilepsies, fierce catarrhs, +Intestine stone and ulcer, colick-pangs, +Demoniack phrenzy, moaping melancholy, +And moon-struck madness, pining atrophy, +Marasmus, and wide-wasting pestilence, +Dropsies, and asthmas, and joint-racking rheums. +Dire was the tossing, deep the groans; Despair +Tended the sick busiest from couch to couch; +And over them triumphant Death his dart +Shook, but delayed to strike, though oft invoked +With vows, as their chief good, and final hope. +Sight so deform what heart of rock could long +Dry-eyed behold? Adam could not, but wept, +Though not of woman born; compassion quelled +His best of man, and gave him up to tears +A space, till firmer thoughts restrained excess; +And, scarce recovering words, his plaint renewed. +O miserable mankind, to what fall +Degraded, to what wretched state reserved! +Better end here unborn. Why is life given +To be thus wrested from us? rather, why +Obtruded on us thus? who, if we knew +What we receive, would either no accept +Life offered, or soon beg to lay it down; +Glad to be so dismissed in peace. Can thus +The image of God in Man, created once +So goodly and erect, though faulty since, +To such unsightly sufferings be debased +Under inhuman pains? Why should not Man, +Retaining still divine similitude +In part, from such deformities be free, +And, for his Maker's image sake, exempt? +Their Maker's image, answered Michael, then +Forsook them, when themselves they vilified +To serve ungoverned Appetite; and took +His image whom they served, a brutish vice, +Inductive mainly to the sin of Eve. +Therefore so abject is their punishment, +Disfiguring not God's likeness, but their own; +Or if his likeness, by themselves defaced; +While they pervert pure Nature's healthful rules +To loathsome sickness; worthily, since they +God's image did not reverence in themselves. +I yield it just, said Adam, and submit. +But is there yet no other way, besides +These painful passages, how we may come +To death, and mix with our connatural dust? +There is, said Michael, if thou well observe +The rule of Not too much; by temperance taught, +In what thou eatest and drinkest; seeking from thence +Due nourishment, not gluttonous delight, +Till many years over thy head return: +So mayest thou live; till, like ripe fruit, thou drop +Into thy mother's lap; or be with ease +Gathered, nor harshly plucked; for death mature: +This is Old Age; but then, thou must outlive +Thy youth, thy strength, thy beauty; which will change +To withered, weak, and gray; thy senses then, +Obtuse, all taste of pleasure must forego, +To what thou hast; and, for the air of youth, +Hopeful and cheerful, in thy blood will reign +A melancholy damp of cold and dry +To weigh thy spirits down, and last consume +The balm of life. To whom our ancestor. +Henceforth I fly not death, nor would prolong +Life much; bent rather, how I may be quit, +Fairest and easiest, of this cumbrous charge; +Which I must keep till my appointed day +Of rendering up, and patiently attend +My dissolution. Michael replied. +Nor love thy life, nor hate; but what thou livest +Live well; how long, or short, permit to Heaven: +And now prepare thee for another sight. +He looked, and saw a spacious plain, whereon +Were tents of various hue; by some, were herds +Of cattle grazing; others, whence the sound +Of instruments, that made melodious chime, +Was heard, of harp and organ; and, who moved +Their stops and chords, was seen; his volant touch, +Instinct through all proportions, low and high, +Fled and pursued transverse the resonant fugue. +In other part stood one who, at the forge +Labouring, two massy clods of iron and brass +Had melted, (whether found where casual fire +Had wasted woods on mountain or in vale, +Down to the veins of earth; thence gliding hot +To some cave's mouth; or whether washed by stream +From underground;) the liquid ore he drained +Into fit moulds prepared; from which he formed +First his own tools; then, what might else be wrought +Fusil or graven in metal. After these, +But on the hither side, a different sort +From the high neighbouring hills, which was their seat, +Down to the plain descended; by their guise +Just men they seemed, and all their study bent +To worship God aright, and know his works +Not hid; nor those things last, which might preserve +Freedom and peace to Men; they on the plain +Long had not walked, when from the tents, behold! +A bevy of fair women, richly gay +In gems and wanton dress; to the harp they sung +Soft amorous ditties, and in dance came on: +The men, though grave, eyed them; and let their eyes +Rove without rein; till, in the amorous net +Fast caught, they liked; and each his liking chose; +And now of love they treat, till the evening-star, +Love's harbinger, appeared; then, all in heat +They light the nuptial torch, and bid invoke +Hymen, then first to marriage rites invoked: +With feast and musick all the tents resound. +Such happy interview, and fair event +Of love and youth not lost, songs, garlands, flowers, +And charming symphonies, attached the heart +Of Adam, soon inclined to admit delight, +The bent of nature; which he thus expressed. +True opener of mine eyes, prime Angel blest; +Much better seems this vision, and more hope +Of peaceful days portends, than those two past; +Those were of hate and death, or pain much worse; +Here Nature seems fulfilled in all her ends. +To whom thus Michael. Judge not what is best +By pleasure, though to nature seeming meet; +Created, as thou art, to nobler end +Holy and pure, conformity divine. +Those tents thou sawest so pleasant, were the tents +Of wickedness, wherein shall dwell his race +Who slew his brother; studious they appear +Of arts that polish life, inventers rare; +Unmindful of their Maker, though his Spirit +Taught them; but they his gifts acknowledged none. +Yet they a beauteous offspring shall beget; +For that fair female troop thou sawest, that seemed +Of Goddesses, so blithe, so smooth, so gay, +Yet empty of all good wherein consists +Woman's domestick honour and chief praise; +Bred only and completed to the taste +Of lustful appetence, to sing, to dance, +To dress, and troll the tongue, and roll the eye: +To these that sober race of men, whose lives +Religious titled them the sons of God, +Shall yield up all their virtue, all their fame +Ignobly, to the trains and to the smiles +Of these fair atheists; and now swim in joy, +Erelong to swim at large; and laugh, for which +The world erelong a world of tears must weep. +To whom thus Adam, of short joy bereft. +O pity and shame, that they, who to live well +Entered so fair, should turn aside to tread +Paths indirect, or in the mid way faint! +But still I see the tenour of Man's woe +Holds on the same, from Woman to begin. +From Man's effeminate slackness it begins, +Said the Angel, who should better hold his place +By wisdom, and superiour gifts received. +But now prepare thee for another scene. +He looked, and saw wide territory spread +Before him, towns, and rural works between; +Cities of men with lofty gates and towers, +Concourse in arms, fierce faces threatening war, +Giants of mighty bone and bold emprise; +Part wield their arms, part curb the foaming steed, +Single or in array of battle ranged +Both horse and foot, nor idly mustering stood; +One way a band select from forage drives +A herd of beeves, fair oxen and fair kine, +From a fat meadow ground; or fleecy flock, +Ewes and their bleating lambs over the plain, +Their booty; scarce with life the shepherds fly, +But call in aid, which makes a bloody fray; +With cruel tournament the squadrons join; +Where cattle pastured late, now scattered lies +With carcasses and arms the ensanguined field, +Deserted: Others to a city strong +Lay siege, encamped; by battery, scale, and mine, +Assaulting; others from the wall defend +With dart and javelin, stones, and sulphurous fire; +On each hand slaughter, and gigantick deeds. +In other part the sceptered heralds call +To council, in the city-gates; anon +Gray-headed men and grave, with warriours mixed, +Assemble, and harangues are heard; but soon, +In factious opposition; till at last, +Of middle age one rising, eminent +In wise deport, spake much of right and wrong, +Of justice, or religion, truth, and peace, +And judgement from above: him old and young +Exploded, and had seized with violent hands, +Had not a cloud descending snatched him thence +Unseen amid the throng: so violence +Proceeded, and oppression, and sword-law, +Through all the plain, and refuge none was found. +Adam was all in tears, and to his guide +Lamenting turned full sad; O!what are these, +Death's ministers, not men? who thus deal death +Inhumanly to men, and multiply +Ten thousandfold the sin of him who slew +His brother: for of whom such massacre +Make they, but of their brethren; men of men +But who was that just man, whom had not Heaven +Rescued, had in his righteousness been lost? +To whom thus Michael. These are the product +Of those ill-mated marriages thou sawest; +Where good with bad were matched, who of themselves +Abhor to join; and, by imprudence mixed, +Produce prodigious births of body or mind. +Such were these giants, men of high renown; +For in those days might only shall be admired, +And valour and heroick virtue called; +To overcome in battle, and subdue +Nations, and bring home spoils with infinite +Man-slaughter, shall be held the highest pitch +Of human glory; and for glory done +Of triumph, to be styled great conquerours +Patrons of mankind, Gods, and sons of Gods; +Destroyers rightlier called, and plagues of men. +Thus fame shall be achieved, renown on earth; +And what most merits fame, in silence hid. +But he, the seventh from thee, whom thou beheldst +The only righteous in a world preverse, +And therefore hated, therefore so beset +With foes, for daring single to be just, +And utter odious truth, that God would come +To judge them with his Saints; him the Most High +Rapt in a balmy cloud with winged steeds +Did, as thou sawest, receive, to walk with God +High in salvation and the climes of bliss, +Exempt from death; to show thee what reward +Awaits the good; the rest what punishment; +Which now direct thine eyes and soon behold. +He looked, and saw the face of things quite changed; +The brazen throat of war had ceased to roar; +All now was turned to jollity and game, +To luxury and riot, feast and dance; +Marrying or prostituting, as befel, +Rape or adultery, where passing fair +Allured them; thence from cups to civil broils. +At length a reverend sire among them came, +And of their doings great dislike declared, +And testified against their ways; he oft +Frequented their assemblies, whereso met, +Triumphs or festivals; and to them preached +Conversion and repentance, as to souls +In prison, under judgements imminent: +But all in vain: which when he saw, he ceased +Contending, and removed his tents far off; +Then, from the mountain hewing timber tall, +Began to build a vessel of huge bulk; +Measured by cubit, length, and breadth, and highth; +Smeared round with pitch; and in the side a door +Contrived; and of provisions laid in large, +For man and beast: when lo, a wonder strange! +Of every beast, and bird, and insect small, +Came sevens, and pairs; and entered in as taught +Their order: last the sire and his three sons, +With their four wives; and God made fast the door. +Mean while the south-wind rose, and, with black wings +Wide-hovering, all the clouds together drove +From under Heaven; the hills to their supply +Vapour, and exhalation dusk and moist, +Sent up amain; and now the thickened sky +Like a dark cieling stood; down rushed the rain +Impetuous; and continued, till the earth +No more was seen: the floating vessel swum +Uplifted, and secure with beaked prow +Rode tilting o'er the waves; all dwellings else +Flood overwhelmed, and them with all their pomp +Deep under water rolled; sea covered sea, +Sea without shore; and in their palaces, +Where luxury late reigned, sea-monsters whelped +And stabled; of mankind, so numerous late, +All left, in one small bottom swum imbarked. +How didst thou grieve then, Adam, to behold +The end of all thy offspring, end so sad, +Depopulation! Thee another flood, +Of tears and sorrow a flood, thee also drowned, +And sunk thee as thy sons; till, gently reared +By the Angel, on thy feet thou stoodest at last, +Though comfortless; as when a father mourns +His children, all in view destroyed at once; +And scarce to the Angel utter'dst thus thy plaint. +O visions ill foreseen! Better had I +Lived ignorant of future! so had borne +My part of evil only, each day's lot +Enough to bear; those now, that were dispensed +The burden of many ages, on me light +At once, by my foreknowledge gaining birth +Abortive, to torment me ere their being, +With thought that they must be. Let no man seek +Henceforth to be foretold, what shall befall +Him or his children; evil he may be sure, +Which neither his foreknowing can prevent; +And he the future evil shall no less +In apprehension than in substance feel, +Grievous to bear: but that care now is past, +Man is not whom to warn: those few escaped +Famine and anguish will at last consume, +Wandering that watery desart: I had hope, +When violence was ceased, and war on earth, +All would have then gone well; peace would have crowned +With length of happy days the race of Man; +But I was far deceived; for now I see +Peace to corrupt no less than war to waste. +How comes it thus? unfold, celestial Guide, +And whether here the race of Man will end. +To whom thus Michael. Those, whom last thou sawest +In triumph and luxurious wealth, are they +First seen in acts of prowess eminent +And great exploits, but of true virtue void; +Who, having spilt much blood, and done much wast +Subduing nations, and achieved thereby +Fame in the world, high titles, and rich prey; +Shall change their course to pleasure, ease, and sloth, +Surfeit, and lust; till wantonness and pride +Raise out of friendship hostile deeds in peace. +The conquered also, and enslaved by war, +Shall, with their freedom lost, all virtue lose +And fear of God; from whom their piety feigned +In sharp contest of battle found no aid +Against invaders; therefore, cooled in zeal, +Thenceforth shall practice how to live secure, +Worldly or dissolute, on what their lords +Shall leave them to enjoy; for the earth shall bear +More than enough, that temperance may be tried: +So all shall turn degenerate, all depraved; +Justice and temperance, truth and faith, forgot; +One man except, the only son of light +In a dark age, against example good, +Against allurement, custom, and a world +Offended: fearless of reproach and scorn, +The grand-child, with twelve sons encreased, departs +From Canaan, to a land hereafter called +Egypt, divided by the river Nile; +See where it flows, disgorging at seven mouths +Into the sea: To sojourn in that land +He comes, invited by a younger son +In time of dearth; a son, whose worthy deeds +Raise him to be the second in that realm +Of Pharaoh: There he dies, and leaves his race +Growing into a nation, and now grown +Suspected to a sequent king, who seeks +To stop their overgrowth, as inmate guests +Or violence, he of their wicked ways +Shall them admonish; and before them set +The paths of righteousness, how much more safe +And full of peace; denouncing wrath to come +On their impenitence; and shall return +Of them derided, but of God observed +The one just man alive; by his command +Shall build a wonderous ark, as thou beheldst, +To save himself, and houshold, from amidst +A world devote to universal wrack. +No sooner he, with them of man and beast +Select for life, shall in the ark be lodged, +And sheltered round; but all the cataracts +Of Heaven set open on the Earth shall pour +Rain, day and night; all fountains of the deep, +Broke up, shall heave the ocean to usurp +Beyond all bounds; till inundation rise +Above the highest hills: Then shall this mount +Of Paradise by might of waves be moved +Out of his place, pushed by the horned flood, +With all his verdure spoiled, and trees adrift, +Down the great river to the opening gulf, +And there take root an island salt and bare, +The haunt of seals, and orcs, and sea-mews' clang: +To teach thee that God attributes to place +No sanctity, if none be thither brought +By men who there frequent, or therein dwell. +And now, what further shall ensue, behold. +He looked, and saw the ark hull on the flood, +Which now abated; for the clouds were fled, +Driven by a keen north-wind, that, blowing dry, +Wrinkled the face of deluge, as decayed; +And the clear sun on his wide watery glass +Gazed hot, and of the fresh wave largely drew, +As after thirst; which made their flowing shrink +From standing lake to tripping ebb, that stole +With soft foot towards the deep; who now had stopt +His sluces, as the Heaven his windows shut. +The ark no more now floats, but seems on ground, +Fast on the top of some high mountain fixed. +And now the tops of hills, as rocks, appear; +With clamour thence the rapid currents drive, +Towards the retreating sea, their furious tide. +Forthwith from out the ark a raven flies, +And after him, the surer messenger, +A dove sent forth once and again to spy +Green tree or ground, whereon his foot may light: +The second time returning, in his bill +An olive-leaf he brings, pacifick sign: +Anon dry ground appears, and from his ark +The ancient sire descends, with all his train; +Then with uplifted hands, and eyes devout, +Grateful to Heaven, over his head beholds +A dewy cloud, and in the cloud a bow +Conspicuous with three lifted colours gay, +Betokening peace from God, and covenant new. +Whereat the heart of Adam, erst so sad, +Greatly rejoiced; and thus his joy broke forth. +O thou, who future things canst represent +As present, heavenly Instructer! I revive +At this last sight; assured that Man shall live, +With all the creatures, and their seed preserve. +Far less I now lament for one whole world +Of wicked sons destroyed, than I rejoice +For one man found so perfect, and so just, +That God vouchsafes to raise another world +From him, and all his anger to forget. +But say, what mean those coloured streaks in Heaven +Distended, as the brow of God appeased? +Or serve they, as a flowery verge, to bind +The fluid skirts of that same watery cloud, +Lest it again dissolve, and shower the earth? +To whom the Arch-Angel. Dextrously thou aimest; +So willingly doth God remit his ire, +Though late repenting him of Man depraved; +Grieved at his heart, when looking down he saw +The whole earth filled with violence, and all flesh +Corrupting each their way; yet, those removed, +Such grace shall one just man find in his sight, +That he relents, not to blot out mankind; +And makes a covenant never to destroy +The earth again by flood; nor let the sea +Surpass his bounds; nor rain to drown the world, +With man therein or beast; but, when he brings +Over the earth a cloud, will therein set +His triple-coloured bow, whereon to look, +And call to mind his covenant: Day and night, +Seed-time and harvest, heat and hoary frost, +Shall hold their course; till fire purge all things new, +Both Heaven and Earth, wherein the just shall dwell. + + + +Book XII + + +As one who in his journey bates at noon, +Though bent on speed; so here the Arch-Angel paused +Betwixt the world destroyed and world restored, +If Adam aught perhaps might interpose; +Then, with transition sweet, new speech resumes. +Thus thou hast seen one world begin, and end; +And Man, as from a second stock, proceed. +Much thou hast yet to see; but I perceive +Thy mortal sight to fail; objects divine +Must needs impair and weary human sense: +Henceforth what is to come I will relate; +Thou therefore give due audience, and attend. +This second source of Men, while yet but few, +And while the dread of judgement past remains +Fresh in their minds, fearing the Deity, +With some regard to what is just and right +Shall lead their lives, and multiply apace; +Labouring the soil, and reaping plenteous crop, +Corn, wine, and oil; and, from the herd or flock, +Oft sacrificing bullock, lamb, or kid, +With large wine-offerings poured, and sacred feast, +Shall spend their days in joy unblamed; and dwell +Long time in peace, by families and tribes, +Under paternal rule: till one shall rise +Of proud ambitious heart; who, not content +With fair equality, fraternal state, +Will arrogate dominion undeserved +Over his brethren, and quite dispossess +Concord and law of nature from the earth; +Hunting (and men not beasts shall be his game) +With war, and hostile snare, such as refuse +Subjection to his empire tyrannous: +A mighty hunter thence he shall be styled +Before the Lord; as in despite of Heaven, +Or from Heaven, claiming second sovranty; +And from rebellion shall derive his name, +Though of rebellion others he accuse. +He with a crew, whom like ambition joins +With him or under him to tyrannize, +Marching from Eden towards the west, shall find +The plain, wherein a black bituminous gurge +Boils out from under ground, the mouth of Hell: +Of brick, and of that stuff, they cast to build +A city and tower, whose top may reach to Heaven; +And get themselves a name; lest, far dispersed +In foreign lands, their memory be lost; +Regardless whether good or evil fame. +But God, who oft descends to visit men +Unseen, and through their habitations walks +To mark their doings, them beholding soon, +Comes down to see their city, ere the tower +Obstruct Heaven-towers, and in derision sets +Upon their tongues a various spirit, to rase +Quite out their native language; and, instead, +To sow a jangling noise of words unknown: +Forthwith a hideous gabble rises loud, +Among the builders; each to other calls +Not understood; till hoarse, and all in rage, +As mocked they storm: great laughter was in Heaven, +And looking down, to see the hubbub strange, +And hear the din: Thus was the building left +Ridiculous, and the work Confusion named. +Whereto thus Adam, fatherly displeased. +O execrable son! so to aspire +Above his brethren; to himself assuming +Authority usurped, from God not given: +He gave us only over beast, fish, fowl, +Dominion absolute; that right we hold +By his donation; but man over men +He made not lord; such title to himself +Reserving, human left from human free. +But this usurper his encroachment proud +Stays not on Man; to God his tower intends +Siege and defiance: Wretched man!what food +Will he convey up thither, to sustain +Himself and his rash army; where thin air +Above the clouds will pine his entrails gross, +And famish him of breath, if not of bread? +To whom thus Michael. Justly thou abhorrest +That son, who on the quiet state of men +Such trouble brought, affecting to subdue +Rational liberty; yet know withal, +Since thy original lapse, true liberty +Is lost, which always with right reason dwells +Twinned, and from her hath no dividual being: +Reason in man obscured, or not obeyed, +Immediately inordinate desires, +And upstart passions, catch the government +From reason; and to servitude reduce +Man, till then free. Therefore, since he permits +Within himself unworthy powers to reign +Over free reason, God, in judgement just, +Subjects him from without to violent lords; +Who oft as undeservedly enthrall +His outward freedom: Tyranny must be; +Though to the tyrant thereby no excuse. +Yet sometimes nations will decline so low +From virtue, which is reason, that no wrong, +But justice, and some fatal curse annexed, +Deprives them of their outward liberty; +Their inward lost: Witness the irreverent son +Of him who built the ark; who, for the shame +Done to his father, heard this heavy curse, +Servant of servants, on his vicious race. +Thus will this latter, as the former world, +Still tend from bad to worse; till God at last, +Wearied with their iniquities, withdraw +His presence from among them, and avert +His holy eyes; resolving from thenceforth +To leave them to their own polluted ways; +And one peculiar nation to select +From all the rest, of whom to be invoked, +A nation from one faithful man to spring: +Him on this side Euphrates yet residing, +Bred up in idol-worship: O, that men +(Canst thou believe?) should be so stupid grown, +While yet the patriarch lived, who 'scaped the flood, +As to forsake the living God, and fall +To worship their own work in wood and stone +For Gods! Yet him God the Most High vouchsafes +To call by vision, from his father's house, +His kindred, and false Gods, into a land +Which he will show him; and from him will raise +A mighty nation; and upon him shower +His benediction so, that in his seed +All nations shall be blest: he straight obeys; +Not knowing to what land, yet firm believes: +I see him, but thou canst not, with what faith +He leaves his Gods, his friends, and native soil, +Ur of Chaldaea, passing now the ford +To Haran; after him a cumbrous train +Of herds and flocks, and numerous servitude; +Not wandering poor, but trusting all his wealth +With God, who called him, in a land unknown. +Canaan he now attains; I see his tents +Pitched about Sechem, and the neighbouring plain +Of Moreh; there by promise he receives +Gift to his progeny of all that land, +From Hameth northward to the Desart south; +(Things by their names I call, though yet unnamed;) +From Hermon east to the great western Sea; +Mount Hermon, yonder sea; each place behold +In prospect, as I point them; on the shore +Mount Carmel; here, the double-founted stream, +Jordan, true limit eastward; but his sons +Shall dwell to Senir, that long ridge of hills. +This ponder, that all nations of the earth +Shall in his seed be blessed: By that seed +Is meant thy great Deliverer, who shall bruise +The Serpent's head; whereof to thee anon +Plainlier shall be revealed. This patriarch blest, +Whom faithful Abraham due time shall call, +A son, and of his son a grand-child, leaves; +Like him in faith, in wisdom, and renown: +The grandchild, with twelve sons increased, departs +From Canaan to a land hereafter called +Egypt, divided by the river Nile +See where it flows, disgorging at seven mouths +Into the sea. To sojourn in that land +He comes, invited by a younger son +In time of dearth, a son whose worthy deeds +Raise him to be the second in that realm +Of Pharaoh. There he dies, and leaves his race +Growing into a nation, and now grown +Suspected to a sequent king, who seeks +To stop their overgrowth, as inmate guests +Too numerous; whence of guests he makes them slaves +Inhospitably, and kills their infant males: +Till by two brethren (these two brethren call +Moses and Aaron) sent from God to claim +His people from enthralment, they return, +With glory and spoil, back to their promised land. +But first, the lawless tyrant, who denies +To know their God, or message to regard, +Must be compelled by signs and judgements dire; +To blood unshed the rivers must be turned; +Frogs, lice, and flies, must all his palace fill +With loathed intrusion, and fill all the land; +His cattle must of rot and murren die; +Botches and blains must all his flesh emboss, +And all his people; thunder mixed with hail, +Hail mixed with fire, must rend the Egyptians sky, +And wheel on the earth, devouring where it rolls; +What it devours not, herb, or fruit, or grain, +A darksome cloud of locusts swarming down +Must eat, and on the ground leave nothing green; +Darkness must overshadow all his bounds, +Palpable darkness, and blot out three days; +Last, with one midnight stroke, all the first-born +Of Egypt must lie dead. Thus with ten wounds +The river-dragon tamed at length submits +To let his sojourners depart, and oft +Humbles his stubborn heart; but still, as ice +More hardened after thaw; till, in his rage +Pursuing whom he late dismissed, the sea +Swallows him with his host; but them lets pass, +As on dry land, between two crystal walls; +Awed by the rod of Moses so to stand +Divided, till his rescued gain their shore: +Such wondrous power God to his saint will lend, +Though present in his Angel; who shall go +Before them in a cloud, and pillar of fire; +By day a cloud, by night a pillar of fire; +To guide them in their journey, and remove +Behind them, while the obdurate king pursues: +All night he will pursue; but his approach +Darkness defends between till morning watch; +Then through the fiery pillar, and the cloud, +God looking forth will trouble all his host, +And craze their chariot-wheels: when by command +Moses once more his potent rod extends +Over the sea; the sea his rod obeys; +On their embattled ranks the waves return, +And overwhelm their war: The race elect +Safe toward Canaan from the shore advance +Through the wild Desart, not the readiest way; +Lest, entering on the Canaanite alarmed, +War terrify them inexpert, and fear +Return them back to Egypt, choosing rather +Inglorious life with servitude; for life +To noble and ignoble is more sweet +Untrained in arms, where rashness leads not on. +This also shall they gain by their delay +In the wide wilderness; there they shall found +Their government, and their great senate choose +Through the twelve tribes, to rule by laws ordained: +God from the mount of Sinai, whose gray top +Shall tremble, he descending, will himself +In thunder, lightning, and loud trumpets' sound, +Ordain them laws; part, such as appertain +To civil justice; part, religious rites +Of sacrifice; informing them, by types +And shadows, of that destined Seed to bruise +The Serpent, by what means he shall achieve +Mankind's deliverance. But the voice of God +To mortal ear is dreadful: They beseech +That Moses might report to them his will, +And terrour cease; he grants what they besought, +Instructed that to God is no access +Without Mediator, whose high office now +Moses in figure bears; to introduce +One greater, of whose day he shall foretel, +And all the Prophets in their age the times +Of great Messiah shall sing. Thus, laws and rites +Established, such delight hath God in Men +Obedient to his will, that he vouchsafes +Among them to set up his tabernacle; +The Holy One with mortal Men to dwell: +By his prescript a sanctuary is framed +Of cedar, overlaid with gold; therein +An ark, and in the ark his testimony, +The records of his covenant; over these +A mercy-seat of gold, between the wings +Of two bright Cherubim; before him burn +Seven lamps as in a zodiack representing +The heavenly fires; over the tent a cloud +Shall rest by day, a fiery gleam by night; +Save when they journey, and at length they come, +Conducted by his Angel, to the land +Promised to Abraham and his seed:--The rest +Were long to tell; how many battles fought +How many kings destroyed; and kingdoms won; +Or how the sun shall in mid Heaven stand still +A day entire, and night's due course adjourn, +Man's voice commanding, 'Sun, in Gibeon stand, +'And thou moon in the vale of Aialon, +'Till Israel overcome! so call the third +From Abraham, son of Isaac; and from him +His whole descent, who thus shall Canaan win. +Here Adam interposed. O sent from Heaven, +Enlightener of my darkness, gracious things +Thou hast revealed; those chiefly, which concern +Just Abraham and his seed: now first I find +Mine eyes true-opening, and my heart much eased; +Erewhile perplexed with thoughts, what would become +Of me and all mankind: But now I see +His day, in whom all nations shall be blest; +Favour unmerited by me, who sought +Forbidden knowledge by forbidden means. +This yet I apprehend not, why to those +Among whom God will deign to dwell on earth +So many and so various laws are given; +So many laws argue so many sins +Among them; how can God with such reside? +To whom thus Michael. Doubt not but that sin +Will reign among them, as of thee begot; +And therefore was law given them, to evince +Their natural pravity, by stirring up +Sin against law to fight: that when they see +Law can discover sin, but not remove, +Save by those shadowy expiations weak, +The blood of bulls and goats, they may conclude +Some blood more precious must be paid for Man; +Just for unjust; that, in such righteousness +To them by faith imputed, they may find +Justification towards God, and peace +Of conscience; which the law by ceremonies +Cannot appease; nor Man the mortal part +Perform; and, not performing, cannot live. +So law appears imperfect; and but given +With purpose to resign them, in full time, +Up to a better covenant; disciplined +From shadowy types to truth; from flesh to spirit; +From imposition of strict laws to free +Acceptance of large grace; from servile fear +To filial; works of law to works of faith. +And therefore shall not Moses, though of God +Highly beloved, being but the minister +Of law, his people into Canaan lead; +But Joshua, whom the Gentiles Jesus call, +His name and office bearing, who shall quell +The adversary-Serpent, and bring back +Through the world's wilderness long-wandered Man +Safe to eternal Paradise of rest. +Mean while they, in their earthly Canaan placed, +Long time shall dwell and prosper, but when sins +National interrupt their publick peace, +Provoking God to raise them enemies; +From whom as oft he saves them penitent +By Judges first, then under Kings; of whom +The second, both for piety renowned +And puissant deeds, a promise shall receive +Irrevocable, that his regal throne +For ever shall endure; the like shall sing +All Prophecy, that of the royal stock +Of David (so I name this king) shall rise +A Son, the Woman's seed to thee foretold, +Foretold to Abraham, as in whom shall trust +All nations; and to kings foretold, of kings +The last; for of his reign shall be no end. +But first, a long succession must ensue; +And his next son, for wealth and wisdom famed, +The clouded ark of God, till then in tents +Wandering, shall in a glorious temple enshrine. +Such follow him, as shall be registered +Part good, part bad; of bad the longer scroll; +Whose foul idolatries, and other faults +Heaped to the popular sum, will so incense +God, as to leave them, and expose their land, +Their city, his temple, and his holy ark, +With all his sacred things, a scorn and prey +To that proud city, whose high walls thou sawest +Left in confusion; Babylon thence called. +There in captivity he lets them dwell +The space of seventy years; then brings them back, +Remembering mercy, and his covenant sworn +To David, stablished as the days of Heaven. +Returned from Babylon by leave of kings +Their lords, whom God disposed, the house of God +They first re-edify; and for a while +In mean estate live moderate; till, grown +In wealth and multitude, factious they grow; +But first among the priests dissention springs, +Men who attend the altar, and should most +Endeavour peace: their strife pollution brings +Upon the temple itself: at last they seise +The scepter, and regard not David's sons; +Then lose it to a stranger, that the true +Anointed King Messiah might be born +Barred of his right; yet at his birth a star, +Unseen before in Heaven, proclaims him come; +And guides the eastern sages, who inquire +His place, to offer incense, myrrh, and gold: +His place of birth a solemn Angel tells +To simple shepherds, keeping watch by night; +They gladly thither haste, and by a quire +Of squadroned Angels hear his carol sung. +A virgin is his mother, but his sire +The power of the Most High: He shall ascend +The throne hereditary, and bound his reign +With Earth's wide bounds, his glory with the Heavens. +He ceased, discerning Adam with such joy +Surcharged, as had like grief been dewed in tears, +Without the vent of words; which these he breathed. +O prophet of glad tidings, finisher +Of utmost hope! now clear I understand +What oft my steadiest thoughts have searched in vain; +Why our great Expectation should be called +The seed of Woman: Virgin Mother, hail, +High in the love of Heaven; yet from my loins +Thou shalt proceed, and from thy womb the Son +Of God Most High: so God with Man unites! +Needs must the Serpent now his capital bruise +Expect with mortal pain: Say where and when +Their fight, what stroke shall bruise the victor's heel. +To whom thus Michael. Dream not of their fight, +As of a duel, or the local wounds +Of head or heel: Not therefore joins the Son +Manhood to Godhead, with more strength to foil +Thy enemy; nor so is overcome +Satan, whose fall from Heaven, a deadlier bruise, +Disabled, not to give thee thy death's wound: +Which he, who comes thy Saviour, shall recure, +Not by destroying Satan, but his works +In thee, and in thy seed: Nor can this be, +But by fulfilling that which thou didst want, +Obedience to the law of God, imposed +On penalty of death, and suffering death; +The penalty to thy transgression due, +And due to theirs which out of thine will grow: +So only can high Justice rest appaid. +The law of God exact he shall fulfil +Both by obedience and by love, though love +Alone fulfil the law; thy punishment +He shall endure, by coming in the flesh +To a reproachful life, and cursed death; +Proclaiming life to all who shall believe +In his redemption; and that his obedience, +Imputed, becomes theirs by faith; his merits +To save them, not their own, though legal, works. +For this he shall live hated, be blasphemed, +Seised on by force, judged, and to death condemned +A shameful and accursed, nailed to the cross +By his own nation; slain for bringing life: +But to the cross he nails thy enemies, +The law that is against thee, and the sins +Of all mankind, with him there crucified, +Never to hurt them more who rightly trust +In this his satisfaction; so he dies, +But soon revives; Death over him no power +Shall long usurp; ere the third dawning light +Return, the stars of morn shall see him rise +Out of his grave, fresh as the dawning light, +Thy ransom paid, which Man from death redeems, +His death for Man, as many as offered life +Neglect not, and the benefit embrace +By faith not void of works: This God-like act +Annuls thy doom, the death thou shouldest have died, +In sin for ever lost from life; this act +Shall bruise the head of Satan, crush his strength, +Defeating Sin and Death, his two main arms; +And fix far deeper in his head their stings +Than temporal death shall bruise the victor's heel, +Or theirs whom he redeems; a death, like sleep, +A gentle wafting to immortal life. +Nor after resurrection shall he stay +Longer on earth, than certain times to appear +To his disciples, men who in his life +Still followed him; to them shall leave in charge +To teach all nations what of him they learned +And his salvation; them who shall believe +Baptizing in the profluent stream, the sign +Of washing them from guilt of sin to life +Pure, and in mind prepared, if so befall, +For death, like that which the Redeemer died. +All nations they shall teach; for, from that day, +Not only to the sons of Abraham's loins +Salvation shall be preached, but to the sons +Of Abraham's faith wherever through the world; +So in his seed all nations shall be blest. +Then to the Heaven of Heavens he shall ascend +With victory, triumphing through the air +Over his foes and thine; there shall surprise +The Serpent, prince of air, and drag in chains +Through all his realm, and there confounded leave; +Then enter into glory, and resume +His seat at God's right hand, exalted high +Above all names in Heaven; and thence shall come, +When this world's dissolution shall be ripe, +With glory and power to judge both quick and dead; +To judge the unfaithful dead, but to reward +His faithful, and receive them into bliss, +Whether in Heaven or Earth; for then the Earth +Shall all be Paradise, far happier place +Than this of Eden, and far happier days. +So spake the Arch-Angel Michael; then paused, +As at the world's great period; and our sire, +Replete with joy and wonder, thus replied. +O Goodness infinite, Goodness immense! +That all this good of evil shall produce, +And evil turn to good; more wonderful +Than that which by creation first brought forth +Light out of darkness! Full of doubt I stand, +Whether I should repent me now of sin +By me done, and occasioned; or rejoice +Much more, that much more good thereof shall spring; +To God more glory, more good-will to Men +From God, and over wrath grace shall abound. +But say, if our Deliverer up to Heaven +Must re-ascend, what will betide the few +His faithful, left among the unfaithful herd, +The enemies of truth? Who then shall guide +His people, who defend? Will they not deal +Worse with his followers than with him they dealt? +Be sure they will, said the Angel; but from Heaven +He to his own a Comforter will send, +The promise of the Father, who shall dwell +His Spirit within them; and the law of faith, +Working through love, upon their hearts shall write, +To guide them in all truth; and also arm +With spiritual armour, able to resist +Satan's assaults, and quench his fiery darts; +What man can do against them, not afraid, +Though to the death; against such cruelties +With inward consolations recompensed, +And oft supported so as shall amaze +Their proudest persecutors: For the Spirit, +Poured first on his Apostles, whom he sends +To evangelize the nations, then on all +Baptized, shall them with wonderous gifts endue +To speak all tongues, and do all miracles, +As did their Lord before them. Thus they win +Great numbers of each nation to receive +With joy the tidings brought from Heaven: At length +Their ministry performed, and race well run, +Their doctrine and their story written left, +They die; but in their room, as they forewarn, +Wolves shall succeed for teachers, grievous wolves, +Who all the sacred mysteries of Heaven +To their own vile advantages shall turn +Of lucre and ambition; and the truth +With superstitions and traditions taint, +Left only in those written records pure, +Though not but by the Spirit understood. +Then shall they seek to avail themselves of names, +Places, and titles, and with these to join +Secular power; though feigning still to act +By spiritual, to themselves appropriating +The Spirit of God, promised alike and given +To all believers; and, from that pretence, +Spiritual laws by carnal power shall force +On every conscience; laws which none shall find +Left them inrolled, or what the Spirit within +Shall on the heart engrave. What will they then +But force the Spirit of Grace itself, and bind +His consort Liberty? what, but unbuild +His living temples, built by faith to stand, +Their own faith, not another's? for, on earth, +Who against faith and conscience can be heard +Infallible? yet many will presume: +Whence heavy persecution shall arise +On all, who in the worship persevere +Of spirit and truth; the rest, far greater part, +Will deem in outward rites and specious forms +Religion satisfied; Truth shall retire +Bestuck with slanderous darts, and works of faith +Rarely be found: So shall the world go on, +To good malignant, to bad men benign; +Under her own weight groaning; till the day +Appear of respiration to the just, +And vengeance to the wicked, at return +Of him so lately promised to thy aid, +The Woman's Seed; obscurely then foretold, +Now ampler known thy Saviour and thy Lord; +Last, in the clouds, from Heaven to be revealed +In glory of the Father, to dissolve +Satan with his perverted world; then raise +From the conflagrant mass, purged and refined, +New Heavens, new Earth, ages of endless date, +Founded in righteousness, and peace, and love; +To bring forth fruits, joy and eternal bliss. +He ended; and thus Adam last replied. +How soon hath thy prediction, Seer blest, +Measured this transient world, the race of time, +Till time stand fixed! Beyond is all abyss, +Eternity, whose end no eye can reach. +Greatly-instructed I shall hence depart; +Greatly in peace of thought; and have my fill +Of knowledge, what this vessel can contain; +Beyond which was my folly to aspire. +Henceforth I learn, that to obey is best, +And love with fear the only God; to walk +As in his presence; ever to observe +His providence; and on him sole depend, +Merciful over all his works, with good +Still overcoming evil, and by small +Accomplishing great things, by things deemed weak +Subverting worldly strong, and worldly wise +By simply meek: that suffering for truth's sake +Is fortitude to highest victory, +And, to the faithful, death the gate of life; +Taught this by his example, whom I now +Acknowledge my Redeemer ever blest. +To whom thus also the Angel last replied. +This having learned, thou hast attained the sum +Of wisdom; hope no higher, though all the stars +Thou knewest by name, and all the ethereal powers, +All secrets of the deep, all Nature's works, +Or works of God in Heaven, air, earth, or sea, +And all the riches of this world enjoyedst, +And all the rule, one empire; only add +Deeds to thy knowledge answerable; add faith, +Add virtue, patience, temperance; add love, +By name to come called charity, the soul +Of all the rest: then wilt thou not be loth +To leave this Paradise, but shalt possess +A Paradise within thee, happier far.-- +Let us descend now therefore from this top +Of speculation; for the hour precise +Exacts our parting hence; and see!the guards, +By me encamped on yonder hill, expect +Their motion; at whose front a flaming sword, +In signal of remove, waves fiercely round: +We may no longer stay: go, waken Eve; +Her also I with gentle dreams have calmed +Portending good, and all her spirits composed +To meek submission: thou, at season fit, +Let her with thee partake what thou hast heard; +Chiefly what may concern her faith to know, +The great deliverance by her seed to come +(For by the Woman's seed) on all mankind: +That ye may live, which will be many days, +Both in one faith unanimous, though sad, +With cause, for evils past; yet much more cheered +With meditation on the happy end. +He ended, and they both descend the hill; +Descended, Adam to the bower, where Eve +Lay sleeping, ran before; but found her waked; +And thus with words not sad she him received. +Whence thou returnest, and whither wentest, I know; +For God is also in sleep; and dreams advise, +Which he hath sent propitious, some great good +Presaging, since with sorrow and heart's distress +Wearied I fell asleep: But now lead on; +In me is no delay; with thee to go, +Is to stay here; without thee here to stay, +Is to go hence unwilling; thou to me +Art all things under $Heaven, all places thou, +Who for my wilful crime art banished hence. +This further consolation yet secure +I carry hence; though all by me is lost, +Such favour I unworthy am vouchsafed, +By me the Promised Seed shall all restore. +So spake our mother Eve; and Adam heard +Well pleased, but answered not: For now, too nigh +The Arch-Angel stood; and, from the other hill +To their fixed station, all in bright array +The Cherubim descended; on the ground +Gliding meteorous, as evening-mist +Risen from a river o'er the marish glides, +And gathers ground fast at the labourer's heel +Homeward returning. High in front advanced, +The brandished sword of God before them blazed, +Fierce as a comet; which with torrid heat, +And vapour as the Libyan air adust, +Began to parch that temperate clime; whereat +In either hand the hastening Angel caught +Our lingering parents, and to the eastern gate +Led them direct, and down the cliff as fast +To the subjected plain; then disappeared. +They, looking back, all the eastern side beheld +Of Paradise, so late their happy seat, +Waved over by that flaming brand; the gate +With dreadful faces thronged, and fiery arms: +Some natural tears they dropt, but wiped them soon; +The world was all before them, where to choose +Their place of rest, and Providence their guide: +They, hand in hand, with wandering steps and slow, +Through Eden took their solitary way. + +[The End] diff --git a/vendor/snap/data/urls.10K b/vendor/snap/data/urls.10K new file mode 100644 index 0000000000..eaf0633766 --- /dev/null +++ b/vendor/snap/data/urls.10K @@ -0,0 +1,10000 @@ +http://ftp.sektornet.dk/tucows/herdwin0904.html +http://209.143.244.16/directory/us/nd/fargo/insurance/automotive.html +http://bellona.itworld.com:8080/cwi/reprint/0,1926,NAV63-128-1357-1367_STO46538,00.html +http://www.legis.state.ia.us/usr/ns-home/docs/GA/76GA/Session.2/SJournal/01600/01644.html +http://www.centc251.org/forums/aca-1/dispatch.cgi/isowg4/showFolder/100001/1211898 +http://www.burstnet.com/ads/ad7826a-map.cgi/271412263 +http://topcu.tucows.com/winme/adnload/137036_30095.html +http://topcu.tucows.com/winme/adnload/145034_49120.html +http://link.fastpartner.com/do/session/600342/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/bitconomy.php +http://www.retrobytes.org/classiccmp/9911/msg01245.html +http://www.localbusiness.com/Story/Print/0,1197,DFW_196102,00.html +http://bbs.kh.edu.tw/treasure/childhood/M.962620586.A/M.966031025.A/M.966031098.A.html +http://www.hig.se/(accessed,clientname,return)/~jackson/roxen/testform.html +http://www.ipclub.ru:8102/cgi-bin/linkmaker/linklist-view.cgi?owner=elvis&Sector=434 +http://www.dulux.co.uk/UKRETAIL:229853034:DFinity.1QJiP4jMofi7bof +http://www.dominionpost.com/cgi-bin/redirect.exe/85288 +http://br.egroups.com/message/anedotas/3988 +http://www.ing.iac.es/~cfg/group_notes/texinfo/spec/file$_must$_exist_$28appendfile$29.html +http://hurweb01.hurriyetim.com.tr/hur/turk/99/06/22/yasam/14yas.htm +http://www3.plala.or.jp/shinchi/niltuki/mai0416.htm +http://www3.plala.or.jp/shinchi/niltuki/mai0420.htm +http://213.36.119.69/do/session/152968/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www3.travelprice.com/voyages/recherche.phtml +http://www.meristation.es/Trucos/s/starcraft_brood.htm +http://www.meristation.es/Trucos/trainer/train_star_war.htm +http://www.askme.com/cat/ShowCategory_3104_an_9.htm +http://mozilla.org/newlayout/testcases/css/sec542cm.htm +http://ampec.ampec.it/ted/box04/page36.htm +http://ampec.ampec.it/ted/box04/page39.htm +http://ampec.ampec.it/ted/box04/page42.htm +http://ampec.ampec.it/ted/box04/page58.htm +http://ampec.ampec.it/ted/box04/page62.htm +http://www.businesswire.com/webbox/bw.080300/202160192.htm +http://www.businesswire.com/webbox/bw.062700/201790580.htm +http://www.businesswire.com/webbox/bw.040300/200940796.htm +http://retailer.gocollect.com/do/session/1912606/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/top_ten.asp?pagenum=1 +http://retailer.gocollect.com/do/session/1912606/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://genforum.genealogy.com/cgi-bin/print.cgi?ivy::116.html +http://www.spiral.at/Katalog/Artikel/6150331/ +http://www.spiral.at/Katalog/Artikel/6150390/ +http://www.spiral.at/Katalog/Artikel/6150411/ +http://bbs.msquare.or.kr/list.bbs/writer/Soohah/8.html +http://www.eskimo.com/~wesn/waflyfishers/msg03537.html +http://denniscares.mp2.homes.com/content/glossary.html?Letter=A +http://library.bangor.ac.uk/search/aChandler,+Peter,+1936-/achandler+peter+1936/-5,-1,0,B/bibandlinks&F=achandler+raymond+1888+1959&5,,6 +http://www.kimkihong.pe.kr/ +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/199/1998/6/0/1323673/ +http://musictz.com/user/fernman.html +http://tucows.concepts.nl/winnt/adnload/1381_28803.html +http://www.mirror.kiev.ua:8083/paper/2000/03/1251/text/03-06-6.htm +http://ring.crl.go.jp/pub/linux/debian/debian-jp/dists/stable/non-free/binary-arm/x11/?N=D +http://news.novgorod.ru/news/2000/4/23/2/9 +http://www.egroups.com/dir/World/Deutsch/Gesellschaft/Bildung/Schule?st=167 +http://www.egroups.com/group/abitur98 +http://genforum.genealogy.com/cgi-genforum/forums/casey.cgi?1477 +http://www.tvstore.com/browse/TV/BOXERSHO/s.UtRroVXF +http://www.tvstore.com/browse/TV/COLLECTI/s.UtRroVXF +http://www.tvstore.com/browse/TV/EARRINGS/s.UtRroVXF +http://polygraph.ircache.net:8181/text/m90/http_-2ewp.aliant.com/attivita.htm +http://rosebay.1000pages.com/ceclgt12.htm +http://www02.u-page.so-net.ne.jp/sb3/mizo/home/sub1/link2/?M=A +http://community.webshots.com/photo/5827455/5827535oqdRLPNiek +http://troy.lib.sfu.ca/search/dbiology+periodicals/dbiology+periodicals/19,-1,0,B/frameset&F=dbiology+religious+aspects&1,1 +http://213.36.119.69/do/session/152973/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/special/alitalia.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/programs/simple/linux/math/computers/tunes.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/programs/simple/linux/math/lit/hasard.html +http://www.elop.de/l0-1011-xx-3006-top.html +http://britanica.com/bcom/eb/article/idxref/0/0,5716,364643,00.html +http://britanica.com/bcom/eb/article/7/0,5716,28557+1+28108,00.html +http://www.geocrawler.com/archives/3/3174/2000/5/50/3724502/ +http://www.geocrawler.com/archives/3/3174/2000/5/50/3699557/ +http://www.geocrawler.com/archives/3/3174/2000/5/50/3689003/ +http://ftp.sunet.se/pub/FreeBSD/ports/ports-stable/net/slirp/files/ +http://www.duluxvalentine.com/FRANCE:219793321:DFinity.1QJiP4jmPgUaedp +http://mundo.ole.es/ocio/articulo/html/oci4270.htm +http://www.maasvlakte-cam.nl/webcams/43/etna__italy/1999/08/29/01:28:02.html +http://www.chinabyte.com/staticpages/builder/builder_course_next/HIPR/builder_course_next_219_HIPR.html +http://www.prospects2.csu.ac.uk/servlet/postgrad.TcAssess?pgid=9634 +http://ftp.sunet.se/pub/lang/perl/CPAN/authors/id/SPP/?N=D +http://www.egroups.com/message/WDT/7751 +http://pub8.ezboard.com/fapricotyarn.unsubscribeUnregisteredToTopic?topicID=4.topic +http://support.tandy.com/support_audio/doc9/9679.htm +http://megalink.tucows.com/winme/preview/74862.html +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/199/1996/2/0/2460450/ +http://www.monaco.gouv.mc/dataweb/gouvmc.nsf/(NewsActu)/d28eaee29b3287d4c1256905004e1ef1!OpenDocument&ExpandSection=10.3,10.4,7,9,4,6 +http://www.fao.org/montes/foda/wforcong/PUBLI/V2/T8S/1-3.HTM +http://library.cuhk.edu.hk/search*chi/a蔡淙霖,+1965-/a%7B215572%7D%7B214758%7D%7B215f60%7D+1965/-5,-1,0,B/browse +http://www.nrk.no/finnmark/x31_12_97/nyh6.htm +http://www.dailyrush.dk/stories/129/comments/pages/1 +http://home.wanadoo.nl/pieter.heres/nedbaskteam/nbt/Web%20Album%20nbt%20spelers/page3.htm +http://members.tripod.co.jp/masa_selfish/?M=A +http://bsd.sinica.edu.tw/cgi-bin/cvsweb.cgi/ports/misc/lile/patches/Attic/?sortby=date +http://www.chaos.dk/sexriddle/z/l/x/y/m/ +http://www.chaos.dk/sexriddle/z/l/x/y/p/ +http://users.sexyboards.com/amandaslut/messages/17.html +http://pub11.ezboard.com/fusscroatiastartrekanimators.showAddTopicScreenFromWeb +http://retailer.gocollect.com/do/session/1912610/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/help/site_tour/index.asp +http://ftp.sunet.se/pub/FreeBSD/ports/ports-current/misc/boxes/pkg-comment +http://www.ce-europe2.philips.com/do/session/80299/vsid/1034/tid/1034/cid/28533/mid/1020/rid/1021/chid/1024/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkZHbjbHrolLmbkKmefLifmLpkZHljlKmoaLl0/url/http://www.eu.microsoft.com/windows/ie_intl/es/ +http://www.peopledaily.co.jp/199904/26/newfiles/col_990426001084_tyxw.html +http://www.peopledaily.co.jp/199904/26/newfiles/col_990426001087_tyxw.html +http://iraustralia.com/listco/hk/swire/profile.htm +http://jefferson.village.virginia.edu/wax/slow/english/3pix/BRight2/1/1a5a15a1.html +http://infoserv2.ita.doc.gov/efm/efm.nsf/Sources!OpenView&Start=35.16&Count=30&Expand=37 +http://www.affiliate.hpstore.hp.co.uk/do/session/380772/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/entry1.asp +http://www.trax.nilex.co.uk/trax.cgi/A1S/B1U/B1R/A3S/A4R/C2U/ +http://www.trax.nilex.co.uk/trax.cgi/A1S/B1U/B1R/A3S/A4R/C2S/ +http://www.quia.com/email.cgi?7106&fc +http://www.mirror.edu.cn/res/sunsite/pub/academic/agriculture/sustainable_agriculture/news+mail-archives/6/ +http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/Beholder/CVSROOT/config?only_with_tag=MAIN +http://collection.nlc-bnc.ca/100/201/300/info_tabac/html/1998/bull21/poumon.html +http://www.erotism.com/sweetlostcherry/g3.htm +http://adex3.flycast.com/server/socket/127.0.0.1:2800/click/SharewareMusicMachine/MusicSoftware1/96457 +http://members.tripod.com/~tonarcos/paginas/Nancy1.html +http://www.gbnf.com/genealog2/stout/html/d0024/I2144.HTM +http://ftp.du.se/disk4/FreeBSD/branches/4.0-stable/ports/deskutils/cbb/ +http://www.hri.org/docs//statedep/95-09-13.std.html +http://ftp.univie.ac.at/packages/tex/macros/latex//contrib/supported/eurofont/adobeuro/readme.txt +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/showNextUnseen/fol/100001/1513138 +http://tucows.ipv.pt/winnt/adnload/1891_28712.html +http://www.tucsonweekly.com/tw/02-09-95/danehy.htm +http://message/artefactphil/87?expand=1 +http://www.kiarchive.ru:8091/pub/FreeBSD/FreeBSD-current/src/gnu/Makefile/ +http://retailer.gocollect.com/do/session/1912644/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/index.asp +http://retailer.gocollect.com/do/session/1912644/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/about.asp +http://park.org:8888/Cdrom/TheNot/Mail/NotPark/msg00070.html +http://citeseer.nj.nec.com/cachedpage/67611/1 +http://citeseer.nj.nec.com/cidcontext/1053642 +http://www.3w-buecher.de/GiacamanGeorge/GiacamanGeorge0745312381.htm +http://au.yahoo.com/Regional/U_S__States/Colorado/Cities/Littleton/Real_Estate/Agencies/ +http://www.power2lead.com/Global/English.nsf/pgWWLocations!OpenPage&ExpandSection=21,28,29,32,22 +http://hem.fyristorg.com/bfo/gagarin/WWW.SAMIRADIO.ORG/svenska/sport-sv.html +http://www.chaos.dk/sexriddle/e/n/q/v/m/ +http://www.hig.se/(formoutput,remove_cookie,sort,sql,sqlquery)/~jackson/roxen/ +http://129.142.8.149/ds/it/isodocs/122400/12240011/12240000117900/ +http://129.142.8.149/ds/it/isodocs/122400/12240011/12240000116400/ +http://129.142.8.149/ds/it/isodocs/122400/12240011/12240000116200/ +http://129.142.8.149/ds/it/isodocs/122400/12240011/12240000113100/ +http://129.142.8.149/ds/it/isodocs/122400/12240011/12240000110800/ +http://koi.www.citycat.ru/funny/fido/2000_10/07.html +http://koi.www.citycat.ru/funny/fido/2000_10/09.html +http://www.hig.se/(countdown,debug,header,if,return)/~jackson/roxen/ +http://www.findtravel.to/search_engine_directory/north_america_usa_canada/united_states/michigan/_travel_guides/ +http://mediate.magicbutton.net/do/session/625534/vsid/3255/tid/3255/cid/87978/mid/2008/rid/2157/chid/2581/url/http://www1.getmapping.com/competition/index.cfm +http://mediate.magicbutton.net/do/session/625534/vsid/3255/tid/3255/cid/87978/mid/2008/rid/2157/chid/2581/url/http://www1.getmapping.com/aboutus/partners2.cfm +http://www.petropages.com/products/p9827.htm +http://www.egroups.com/login.cgi?login_target=%2Fmessage%2Fspynews%2F54 +http://health.sx.zj.cn/Treatment/SuperGuide/2000-3-8/4716.htm +http://www.nease.net/~qin/chardware.htm +http://www.argos.asso.fr/bourges/pratiq/emploi/texte/anpesud.htm +http://ftp.sunet.se/pub/FreeBSD/ports/ports-current/www/p5-Apache-Session/?S=A +http://www.eveclub.com/cgi-bin/eveclub.front/972959425847/Catalog/1000046 +http://retailer.gocollect.com/do/session/1912628/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/top_ten.asp?pagenum=1 +http://yp.gates96.com/1/10/21/73.html +http://yp.gates96.com/1/10/21/95.html +http://yp.gates96.com/1/10/22/21.html +http://yp.gates96.com/1/10/22/31.html +http://yp.gates96.com/1/10/22/52.html +http://yp.gates96.com/1/10/22/76.html +http://yp.gates96.com/1/10/22/79.html +http://yp.gates96.com/1/10/23/57.html +http://yp.gates96.com/1/10/23/73.html +http://yp.gates96.com/1/10/25/20.html +http://yp.gates96.com/1/10/25/46.html +http://yp.gates96.com/1/10/25/87.html +http://yp.gates96.com/1/10/26/76.html +http://yp.gates96.com/1/10/26/84.html +http://yp.gates96.com/1/10/27/67.html +http://yp.gates96.com/1/10/28/70.html +http://yp.gates96.com/1/10/28/91.html +http://live.excite.com/lifestyle/politics_and_society/countries/asia/uzbekistan/guides_and_reference/ +http://biblioteca.upv.es/bib/doc/doc_fisbd/367/114176//C/1825519/0////25/S/MLTPAI +http://mai.flora.org/forum/5322 +http://mai.flora.org/forum/5318 +http://www.brickshelf.com/scans/0000/0715/0715-03.html +http://www.brickshelf.com/scans/0000/0715/0715-12.html +http://www.brickshelf.com/scans/0000/0715/0715-21.html +http://www.msb.malmo.se/search*swe/dManikyr/dmanikyr/-5,-1,0,B/frameset&F=dmani&1,1 +http://message/cinematik/2441?expand=1 +http://message/cinematik/2447?expand=1 +http://www.jamba.de/KNet/_KNet-Rco8j1-WDd-137sh/showInfo-special1.de/node.0/cde7f1uou +http://www.jamba.de/KNet/_KNet-Rco8j1-WDd-137ss/showInfo-hilfe.de/node.0/cde7f1uou +http://acmepet.petsmart.com/canine/breeds/labrador/bboard/messages/5245.html +http://acmepet.petsmart.com/canine/breeds/labrador/bboard/messages/5226.html +http://config.tucows.com/winnt/adnload/67680_29009.html +http://config.tucows.com/winnt/adnload/55386_29005.html +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kdeutils/knotes/Attic/renamedlg.cpp?r1=1.7&only_with_tag=MAIN +http://www.imagestation.com/member/?name=Twiggy5&c=1 +http://cometweb01.comet.co.uk/do!tid=20&rtid=3&vsid=700&session=131981&mid=1000&rid=1060&cid=37030&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHljbLqleHqjiLlel5jblKqlmLkeq5j1 +http://community.webshots.com/photo/1921549/2334169DWEIWPyCoH +http://www.fogdog.com/cedroID/ssd3040183158605/nav/stores/skateboarding/ +http://www.fogdog.com/cedroID/ssd3040183158605/content/fan/subway_series/ +http://www.fogdog.com/cedroID/ssd3040183158605/boutique/ashworth/ +http://www.fogdog.com/cedroID/ssd3040183158605/customer_service/our_partners.html +http://www.jacksonhewitt.com/ctg/cgi-bin/JacksonHewitt/media_center/AAAksrACwAAACCOAAl +http://www.jacksonhewitt.com/ctg/cgi-bin/JacksonHewitt/talktous/AAAksrACwAAACCOAAl +http://arabia.com/jordan/article/print/1,5130,3048|Life,00.html +http://198.3.99.101/reference/politics_and_govt/humor/games/ +http://www.pocketbible.co.kr/old/Leviticus/Leviticus24/Leviticus24-14.htm +http://www.ozon.ru/detail.cfm/ent=5&id=12&txt=1 +http://www.ozon.ru/detail.cfm/ent=2&id=2141 +http://www.chaos.dk/sexriddle/m/t/i/t/j/ +http://www.outpersonals.com/cgi-bin/w3com/pws/out/5VhIq3rCy0eiHAzs1LOyTswNBIR33Wxc8NtFBCnYVNlrV5p9laRchaQrPWdU7-F739tsfX-p5-IA-j1rTm1YLCRAwn1FAriW9Ps21GP6CvyIL7YFYjLtOcez03i6Q9Xw3LRDtJY2CIzGQuZp-sH_-s_D66j9 +http://www.outpersonals.com/cgi-bin/w3com/pws/out/lKhIoWbn-weE729M1n0JT8Ina4qOfm_FI2ROg8RdrrVu5kq_AK_urPMHafLCMwWCiOLuc8OIIHCFnJaCfz2LSrURBHFjDJP1fBO0X58Y28opSv0qVXWAKYtub7NbCIIWMbE_ldcypBmh +http://www.outpersonals.com/cgi-bin/w3com/pws/out/PbhIoduIKw3faQWbBTWSK5aq7Y-nGqcvK3flLaTRo02t7k7GMY8rPlupJIheD8869wCXUAer4VimzyYa25qUx7ef2l2VdMR9i_p-pJ5gg2S6ZcP-G6RuPfdDS3TEsJNXGVsOTs1rA605 +http://www.linux.com/networking/network/development/web_server/performance/?printable=yes +http://www.linux.com/networking/network/development/web_server/performance/IBM/ +http://sunsite.icm.edu.pl/Linux/Documentation/HOWTO/mini/IP-Subnetworking-3.html +http://dreamcity.gaiax.com/www/dreamcity/m/s/musou/frame.html +http://guardian.co.uk/Widgets/Read_It_Later/TR/1,4694,4043922,00.html +http://www.gpul.org/ftp/os/infinite/?M=A +http://www.gpul.org/ftp/os/infinite/infinite_OS.txt +http://retailer.gocollect.com/do/session/1912666/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/exclusives.asp +http://yp.gates96.com/13/77/10/66.html +http://yp.gates96.com/13/77/10/91.html +http://yp.gates96.com/13/77/11/82.html +http://yp.gates96.com/13/77/12/17.html +http://yp.gates96.com/13/77/13/68.html +http://yp.gates96.com/13/77/13/80.html +http://yp.gates96.com/13/77/16/3.html +http://yp.gates96.com/13/77/16/17.html +http://yp.gates96.com/13/77/16/49.html +http://yp.gates96.com/13/77/17/8.html +http://yp.gates96.com/13/77/18/4.html +http://yp.gates96.com/13/77/18/61.html +http://yp.gates96.com/13/77/18/71.html +http://yp.gates96.com/13/77/19/3.html +http://yp.gates96.com/13/77/19/24.html +http://yp.gates96.com/13/77/19/48.html +http://yp.gates96.com/13/77/19/98.html +http://yp.gates96.com/13/77/19/99.html +http://scsinternet.tucows.com/winnt/mail95.html +http://tolm.terrashare.com/45.htm +http://news.dreamwiz.com/news/08/20001030/kukmin/200010301903081903261.html +http://www.tccomputers.com/cgi-bin/bp/1463655603/services/info/tci.htm +http://www.tccomputers.com/cgi-bin/bp/1463655603/services/csc/csc.htm +http://www.2pl.com/b/pl/to/1/01/04/v2/1010400016-6-2r.htm +http://www.2pl.com/b/pl/to/1/01/04/v2/1010400016-3-2r.htm +http://www.2pl.com/b/pl/to/1/01/04/v2/1010400016-18-2r.htm +http://www.2pl.com/b/pl/to/1/01/04/v2/1010400016-1r.htm +http://www.123bestphonerates.com/q/001p/vn/vR85aEOIaY.htm +http://www.thisislancashire.co.uk/lancashire/archive/1997/07/17/SPORTST5VQ.html +http://www.thisislancashire.co.uk/lancashire/archive/1997/07/17/SPORTST7VQ.html +http://www.thisislancashire.co.uk/lancashire/archive/1997/07/17/SPORTST11VQ.html +http://www.elsur.cl/archivo/marzo2000/13marzo2000/elsur/deportes/ind3.php3 +http://home.no.net/fristart/kvasir816/ +http://www.fun7.de/party/cafe_europa/_vti_cnf/?D=A +http://www.users.yun.co.jp/cgi-bin/moriq/pigeon/pigeon.cgi/%C5%E7%BA%AC%B8%A9.%C2%E7%B8%B6%B7%B4%C2%E7%C5%EC%C4%AE?c=e +http://polygraph.ircache.net:8181/http_-2www.whowhere.com/http_-2www.expired.com/html/service.html +http://home.t-online.de/home/mtc.hannover/head1655833.htm +http://moneycentral.msn.com/investor/invsub/insider/Details.asp?Pval=1&Symbol=MKSI +http://www.sohu.com/Regional/hunan/City_County/Yiyang/Firms/Food_Beverage/ +http://www.kulturkreis-rhein-lahn.de/lauer/fax.htm +http://ustlib.ust.hk/search*chi/aporter+bill+1943/aporter+bill+1943/7,-1,0,B/browse +http://www.brio.de/BRIO.catalog/39fe2f3708fb3c8e2740d472aa7806d5/UserTemplate/2 +http://www.brio.de/BRIO.catalog/39fe2f3708fb3c8e2740d472aa7806d5/UserTemplate/6 +http://rcsl.auto.inha.ac.kr/~treeman/Documents/HOWTO/Keyboard-and-Console-HOWTO-19.html +http://www.etoys.com/cat/toy/category/construction/brio_builder_system/1 +http://www.kxmd.com/now/story/0,1597,194790-295,00.shtml +http://www.ferien-immobilien.de/DominikanischeRep/verkauf/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/Gemeinsam/Gemeinsam/versicherungen/gebaeude/IIM-Teil/Startseite/froben.htm +http://hiv.medscape.com/LWW/SMD/1999/v21.n03/smd2103.01.html +http://www.egroups.com/message/dk-jaws/530 +http://no.egroups.com/message/daemon-news-announce/12 +http://ring.toyama-ix.net/archives/text/elisp/jaist/yamaoka/apel/00_THIS_DIRECTORY_WILL_NOT_BE_UPDATED_UNTIL_2000-10-26 +http://pub12.ezboard.com/ftibesataxg1637tibes.subscribeUnregisteredToTopic?topicID=7.topic +http://ustlib.ust.hk/search*chi/ali+huan+1827+1891/ali+huan+1827+1891/-5,-1,0,E/frameset&F=ali+huan&4,,0 +http://ustlib.ust.hk/search*chi/ali+huan+1827+1891/ali+huan+1827+1891/-5,-1,0,E/frameset&F=ali+huang+1895&1,,0 +http://www.digitalcity.com/cincinnati/sports/log.dci?league=NCF&team=NNF +http://ftp.nacamar.de/pub/debian/dists/potato/main/disks-m68k/2.2.16-2000-07-14/mac/images-1.44/?D=A +http://www.academyfloral.com/state/arboo/flowers/thanksabunchbouquet2.html +http://dante.bdp.it/cgi-bin/poseidon_v2.0/reflect/poseidon/disc/peacelink-scuola/2015003604/view/8 +http://ring.omp.ad.jp/pub/NetBSD/NetBSD-current/pkgsrc/lang/smalltalk/files/?S=A +http://ring.omp.ad.jp/pub/NetBSD/NetBSD-current/pkgsrc/lang/smalltalk/files/patch-sum +http://carriage.de/Schoner/Sammlungen/literature/collections/literature/modelle/ +http://www.buybuddy.com/sleuth/27/1/11001/1692/ +http://193.120.14.241/pub/languages/perl/CPAN/src/5.0/devel/ +http://lastminutetravel.bedandbreakfast.com/bbc/p208900.asp +http://chat.sportsline.com/u/wire/stories/0,1169,2957692_59,00.html +http://acad.uis.edu/sas/qc/q-index.htm +http://acad.uis.edu/sas/qc/s-index.htm +http://library.cuhk.edu.hk/search*chi/aPan,+Zhuonan./apan+zhuonan/-5,1,1,B/frameset&F=apan+zhichang+1956&1,1, +http://www.linux.com/networking/network/install/tools/updates/new/ +http://www.linux.com/networking/network/install/tools/updates/Standards/ +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=13,31,5,11,26 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=23,31,5,11,26 +http://www.mfa.no/fin/norsk/publ/stprp/006005-991562/index-hov017-b-n-a.html +http://ftp.sunet.se/pub/lang/perl/CPAN/authors/id/DBEAZLEY/?N=D +http://fi.egroups.com/messages/infoespo/6?expand=1 +http://ibc.cn.net/2000/0718/it-1message.html +http://www.shaggysguide.com/conhtml/adnload/51647_1809.html +http://www.shaggysguide.com/conhtml/adnload/51657_5567.html +http://www.shaggysguide.com/conhtml/adnload/74370_17872.html +http://www.shaggysguide.com/conhtml/adnload/78469_19520.html +http://www.shaggysguide.com/conhtml/adnload/78940_19788.html +http://www.backflip.com/members/jhferrara/5171381/page=1/sort=1/linkspp=10 +http://www.amcity.com/philadelphia/stories/1998/08/24/newscolumn3.html?t=printable +http://www.rge.com/pub/tex/biblio/bibtex/ms-dos/demel/?N=D +http://www.v2music.com/Scripts/WebObjects-ISAPI.dll/V2_New_Publisher.woa/67841000005885200000309700000064451/Giveaways.wo/257820000054451/2.0.0.6.0/3/Webobjects1 +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www-gds.desy.de:8080/zeitpl/zpl.htm +http://click-to.tell-a-friend.boardhost.com/tell-a-friend-confirm.cgi?chudtvlogic&msg=1596 +http://retailer.gocollect.com/do/session/1912639/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://www.jpc-music.com/5590216.htm +http://huntingfishing.tripod.com/sturgeonmain.htm +http://polygraph.ircache.net:8181/wwwboard/prodev/seminar/fast/http_-2www.centennialcc.org/bps.html +http://www.chaos.dk/sexriddle/s/t/c/x/l/ +http://www.chaos.dk/sexriddle/s/t/c/x/z/ +http://es.egroups.com/messages/plato-meno/1285 +http://tonggu-gch.ed.seoul.kr/home/2grade/2-10/981001/hang.htm +http://sjsulib1.sjsu.edu:81/search/dreligion/-5,-1,0,E/exact&dreligion+libraries&1,3 +http://www.generation-formation.fr/chiffrec.htm---o21zAo0UPwo0Ol9A074fo6Td4ezyr6feZJPAPfVbNyqHSezTHkekydMfeZJPdspt6dsSAtdsNhJdspt6dsrvrdjlhkfbd.htm +http://www.generation-formation.fr/dicoguid/diclogin.htm---o21zAo0UPwo0Ol9A074fo6Td4ezyr6feZJPAPfVbNyqureds5cezwhlezMpDeH7vGebI1yoKkfMd4vmMAxaAooKkfMd4u5xdfb7rmdfbT.htm +http://www.hollywoodonline.com/asplocal/mgvideoad.asp?rushhour-video-holdon-mov +http://www.ifg.uni-kiel.de/doc-clients/kdelibs-doc/html/kdeui/full-list-KRestrictedLine.html +http://www.3w-sciencefiction.de/ShapiroLarry/ShapiroLarry0760306729.htm +http://202.96.140.98/js/wenge/ +http://www.great-cyber-mall.com/SelectCompany.asp?CityID=230&CatID=19 +http://www.great-cyber-mall.com/SelectCompany.asp?CityID=230&CatID=34 +http://www.amazon.com.hk/exec/obidos/tg/stores/browse/-/books/13361/ +http://www.hole.kommune.no/hole/journweb.nsf/weboffjournal!OpenView&Start=99&Count=50&Collapse=116 +http://www.pbase.com/image/35702/small +http://www.infoscape.com.cn:8171/nf/0010/21/nfzy2104.htm +http://dell.excite.com/photo/topic/weather/national/19 +http://www.linux.com/networking/network/network/firewall/microsoft/government/ +http://www.gasex.com/gay.photo/gay.penis.pics.html +http://hausarbeiten.de/cgi-bin/superDBinters.pl/archiv/geschichte/gesch-stedinger.shtml +http://polygraph.ircache.net:8181/http_-2www.microsoft.com/frontpage/http_-2www.exploreuw.com/cards/ssoenews.html +http://www.fogdog.com/cedroID/ssd3040183137325/cgi-bin/MyFogdog +http://www.fogdog.com/cedroID/ssd3040183137325/cgi-bin/CedroCommerce?func=EditBasket +http://www.fogdog.com/cedroID/ssd3040183137325/nav/stores/cycling/ +http://www.fogdog.com/cedroID/ssd3040183137325/nav/stores/snowboarding/ +http://tucows.wanadoo.nl/win2k/organ2k_license.html +http://tucows.wanadoo.nl/win2k/preview/59164.html +http://windows.tucows.com/preview/001-009-005-005C.html +http://anekdotwall.boom.ru/car/html/75.htm +http://tucows.concepts.nl/win2k/clipb2k_size.html +http://tucows.concepts.nl/win2k/adnload/37291_29917.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=cricrila&l=pt +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=cricrilava&l=pt +http://www.trax.nilex.co.uk/trax.cgi/A1C/1AR/A2S/A3S/A3D/D1S/ +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_ngqyjt_ngqyjt.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_rtnucb_tyciyrg.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_kiektgt_fpwif.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_rjdbc_rjdbc.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_xsygo_xsygo.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_bovqcy_mkaqta.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_lgbrnl_psnjjt.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_lgbrnl_ybvfp.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_vermn_xmxmm.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/12_keojvu_faoex.html +http://info-china.hypermart.net/enterprise/company/messages/25.html +http://ring.yamanashi.ac.jp/pub/linux/debian/debian-jp/dists/potato/non-US/contrib/binary-m68k/Release +http://www.amigos.com/cgi-bin/w3com/pws/ffe/R7RIRASjZ5ATyRjNyXQBbwzK4LLK-rhgzZEBqJsLaR1cdnaeB7LT1xORWRg6aQmLxO7QWLEpsdjuf2ZqAnUO1IKpfrRctaIMYIzMNy1DSb7dp8_5z39WdF7oxbKUAByA +http://indigotrem1.chemie.uni-mainz.de/~manng001/Filme/S/SexLuegenundVideo.html +http://se.egroups.com/message/hur/387 +http://www.ilmessaggero.it/hermes/19990111/07_MARCHE/MARCHE_REGIONE/DUE.htm +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/lit/quizz/misc/colorart/lit/pushkin.html +http://www.amzn.com/exec/obidos/ts/artist-glance/201040/ref=pm_dp_ln_m_6/ +http://tucows.netpower.no/winme/adnload/138674_29970.html +http://www.chaos.dk/sexriddle/z/d/q/p/c/ +http://www.chaos.dk/sexriddle/z/d/q/p/u/ +http://sv.pachinkovillage.co.jp/catalog/DinoVaderB/3.html +http://ww2.comune.fe.it/cgi-win/hiweb.exe/a2/B1,a,1f,6,6,3a,3a,,5,,1f,5, +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=deflazioneranno&l=it +http://polygraph.ircache.net:8181/company/html/http_-2www.io.com/~kinnaman/pchealth/f-agents.html +http://polygraph.ircache.net:8181/company/html/http_-2www.io.com/~kinnaman/pchealth/f-leisureworld.html +http://ftp.univie.ac.at/packages/perl/modules/by-module/Tie/ILYAZ/cperl-mode/rms-emacs-20.2-patch-narrow-buffer+dirfiles +http://www.expressindia.com/ie/daily/19991126/ige26097p.html +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/ELINKEINO-+JA+YRITYSTOIMINTA/yritt%E4jyys/lukio/oppimateriaali/itseopiskelu/ +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=36,23,11,33,18 +http://www.trib.com/scjournal/ARC/1996/MAR/3_24_96/marines.html +http://www.slac.stanford.edu/BFROOT/www/Computing/Programming/QA/QaBetaTools/6.7.5a/SunOS5/?S=D +http://pokemonplant.tripod.com/150yellow.html +http://ftp.debian.org/dists/potato/contrib/binary-all/devel/?N=D +http://sunsite.org.uk/packages/tcl/Collections/ftp.neosoft.com/sorted/packages-8.0/print/frink/1.2p35/ +http://library.bangor.ac.uk/search/m304.6+LIN/m304.6+lin/-5,-1,0,B/frameset&F=m304.6+jos&1,1 +http://members.tripod.lycos.nl/janninksweg145/huis.htm +http://www.uib.no/People/mihtr/PS01/PS01_219.htm +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus141561/eus174865/eus327367/eus327602/eus329879/ +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus141561/eus174865/eus327367/eus327602/eus327608/ +http://sound-dist.secured.co.uk/cgi-bin/psShop.cgi/add|39P02|972959512|Communications|user|0|1,0,0,1 +http://www.bluefreds.f9.co.uk/vote2.html +http://www.hri.org/docs//statedep/1999/99-05-07.std.html +http://polygraph.ircache.net:8181/http_-2www.hblinfo.com/f_snowbuddies.html +http://mediate.magicbutton.net/do/session/625565/vsid/3342/tid/3342/cid/88020/mid/2008/rid/2313/chid/2648/url/http://www1.getmapping.com/products.cfm +http://cometweb01.comet.co.uk/do!tid=20&rtid=2&vsid=692&session=131975&mid=1000&rid=1060&cid=37051&chid=1702&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG5ubLZDXLZolLl3l5jbqLlci5XqVLkXsLkao4tloHbmlLoq5 +http://digilander.iol.it/net4free/spedia.htm +http://totalsports.aol.com/stats/bbo/mlb/20000425/col.at.mon.prvw.html +http://210.178.135.1/netbbs/Bbs.cgi/nhic32042/qry/pno/0/zka/B2-kB2Zk/qqatt/^ +http://cikkek.lezlisoft.com/kikelet/spiritualitas/spirit3v9.shtml +http://www.wingateinns.com/ctg/cgi-bin/Wingate/aarp/AAAksrACwAAACCPAAl +http://sunsite.berkeley.edu/PhiloBiblon/BITAGAP/BIB/BIB1848.html +http://sunsite.uakom.sk/tucows/adnload/69390_28371.html +http://sunsite.uakom.sk/tucows/preview/77630.html +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=(22,0+9,0-~0,3 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=(22,0+9,0-~9,6 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=(22,0+9,0-~21,0 +http://sirac.inrialpes.fr/Infos/Personnes/Christophe.Rippert/ressources/jdk1.2.2/docs/api/java/security/ +http://polygraph.ircache.net:8181/getting_started/http_-2www.microsoft.com/powered/radio/email_pal/email_pal.htm +http://mirror.nucba.ac.jp/mirror/FreeBSD/branches/2.2-stable/ports/net/tund/?M=A +http://mirror.nucba.ac.jp/mirror/FreeBSD/branches/2.2-stable/ports/net/tund/?D=A +http://library.bangor.ac.uk/search/tNursing+times+clinical+monographs+&%2359%3B+no.+51/tnursing+times+clinical+monographs+no+++51/-17,-1,0,B/browse +http://library.bangor.ac.uk/search/tNursing+times+clinical+monographs+&%2359%3B+no.+51/tnursing+times+clinical+monographs+no+++51/-5,-1,0,B/frameset&F=tnursing+times+complementary+therapy&1,1 +http://ftp.chg.ru/pub/FreeBSD/doc/en_US.ISO_8859-1/articles/programming-tools/ +http://polygraph.ircache.net:8181/getting_started/http_-2www.microsoft.com/powered/bomb/bomb.htm +http://linux.tucows.inwind.it/conhtml/adnload/8523_5414.html +http://www.magicvillage.de/magicvillage/KonferenzPlaza/fbs/%2328835852?NextInThread +http://www.shopworks.com/samplers/index.cfm/action/cart/userid/0009CECE-2EE1-19FE-9038010B0A0ADCF2 +http://dailynews.sina.com/newsCenter/taiwan/udn/2000/1021/2051701_b5.html +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kdeutils/khexedit/pics/Attic/?hideattic=1&sortby=date +http://moviestore.zap2it.com/browse/MOVIES/BOWL/s.zchC6lsi +http://moviestore.zap2it.com/browse/MOVIES/MUSIC/s.zchC6lsi +http://ww2.comune.fe.it/cgi-win/hiweb.exe/a2/d13/b12,c,1f,18,18,,13,,1f,13,17,,1f,17, +http://ww2.comune.fe.it/cgi-win/hiweb.exe/a2/d14/b12,c,1f,18,18,,13,,1f,13,17,,1f,17, +http://209.50.251.176/~bb/ +http://tucows.energy.it/winnt/adnload/59163_30035.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=circundara&l=pt +http://vishvesha.tripod.com/4/068d.htm +http://www.hot.ee/timbsy/kass_files/pildikogu.html +http://www3.newstimes.com/archive99/jan2599/rga.htm +http://pub11.ezboard.com/fmarjoriesdmboardpostyourdmpedigreeshere.showMessage?topicID=21.topic +http://www.geocities.com/Heartland/Plains/4825/bennyn.html +http://citeseer.nj.nec.com/site/115145 +http://www.techsupplies.com/sleuth/17/1/40406/254200/ +http://ccmnet.xj.cei.gov.cn/10/b10/b1007/99-05-02/a5-02.asp +http://206.251.18.85/FEATURES/home_improvement/1999/10/01/fall_lawncare3.html +http://www.dulux.co.uk/UKRETAIL:1355333640:DFinity.1QJiP4jmPgimjKlA +http://cometweb01.comet.co.uk/do!tid=20&rtid=2&vsid=700&session=131985&mid=1000&rid=1060&cid=37030&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG5ubLZDXLZolLl3l5jbqLlci5XqVLkXsLkao4tloHbmlLoq5 +http://cometweb01.comet.co.uk/do!tid=20&rtid=1&vsid=700&session=131985&mid=1000&rid=1060&cid=37030&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplGGolLarZLq4fLpmiLXv-KmooLckYLoznGmpq0qsc0mojLbkYLozvGotc0ZdoLckYLozvGsmv0qmc0jXfLkVZLdocLkYoLzcj1XfkLVZXLqkXLjbzKcob5qroLkVrLoizKlZd5fjYHfklKkZlLjjbLoZbLpl51ubZLDXZLollK3ljLbqlKjXfLkkaHotl4obmLloqL +http://www.berliner-morgenpost.de/bm/inhalt/990928/berlin/story14.html +http://gb.toget.com.tw/article/printer_tool/19990825_3210_p1.html +http://sbtr42.sbsusa.com/ncsamples/base1.htm +http://halflife02.opasia.dk/cs3stats/players/_AMNeSIA_.html +http://mediate.magicbutton.net/do/session/625570/vsid/3342/tid/3342/cid/88020/mid/2008/rid/2313/chid/2648/url/http://www1.getmapping.com/basket.cfm +http://mediate.magicbutton.net/do/session/625570/vsid/3342/tid/3342/cid/88020/mid/2008/rid/2313/chid/2648/url/http://www1.getmapping.com/viewer.cfm +http://www.citythek.de/erfurt/rheinhyp/fsinhalt.htm +http://my.egroups.com/group/mall-komputer +http://www-bd.cricket.org/link_to_database/ARCHIVE/1997-98/PAK_IN_RSA/PAK_IN_RSA_JAN-APR1998_PAK-SQUAD.html +http://www-bd.cricket.org/link_to_database/GROUNDS/RSA/ST-GEORGE_PARK_PT-ELIZ/ +http://www-bd.cricket.org/link_to_database/ARCHIVE/1997-98/PAK_IN_RSA/PAK_RSA_T3_06-10MAR1998_ET_MR.html +http://www.bemi-immobilien.de/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/versicherungen/unfall/Gemeinsam/erreichenPartner/Gemeinsam/MarketingStrategie/Gemeinsam/versicherungen/gebaeude/Gemeinsam/Top-Darlehens-Konditionen/anforderungsformular.htm +http://www.online.kokusai.co.jp/Qa/V0043459/wrd/G800/qa/ +http://iland.tucows.com/win2k/adnload/59229_29990.html +http://iland.tucows.com/win2k/preview/144411.html +http://iland.tucows.com/win2k/adnload/38173_29963.html +http://www.arm.com/sitearchitek/armtech.ns4/8ab0ea422fba51238025691f00399e13/9cb09cb360a967848025691f004e28b2!OpenDocument&ExpandSection=6,13,12,-1 +http://ftp.uni-mannheim.de/languages/perl/CPAN/modules/by-authors/id/JMURPHY/?N=D +http://proam.golfonline.com/tours/2000/hooters/silversprings/scores2.html +http://ftp.du.se/pub/FreeBSD/branches/4.0-stable/src/games/grdc/ +http://ftp.du.se/pub/FreeBSD/branches/4.0-stable/src/games/pom/ +http://ftp.du.se/pub/FreeBSD/branches/4.0-stable/src/games/Makefile +http://www.artex.firenze.it/_qualitart/articoli/zoom/03651.htm +http://www.chaos.dk/sexriddle/m/k/v/b/p/ +http://www.chaos.dk/sexriddle/m/k/v/b/s/ +http://www.chaos.dk/sexriddle/t/j/d/n/n/ +http://www.daysinn.com/ctg/cgi-bin/DaysInn/media_center/AAAksrACwAAACCQAAM +http://tukela.heha.net/ys/ll/boyuan.htm +http://tukela.heha.net/ys/ll/jinciming.htm +http://genforum.genealogy.com/ai/messages/4299.html +http://genforum.genealogy.com/ai/messages/4221.html +http://genforum.genealogy.com/ai/messages/4225.html +http://www.linkclub.or.jp/~sticky/index1/diary/1999/199906.html +http://ww.egroups.com/subscribe/lexingtonkystrapon +http://chita.fi.upm.es/docs/info/en_US/a_doc_lib/motif/motifsg/About.htm +http://chita.fi.upm.es/docs/info/en_US/a_doc_lib/motif/motifsg/motifsg41.htm +http://chita.fi.upm.es/docs/info/en_US/a_doc_lib/motif/motifsg/motifsg43.htm +http://hakuba-net.gr.jp/guide/rest/spa_each/spa_2.html +http://yp.gates96.com/6/16/40/22.html +http://yp.gates96.com/6/16/40/44.html +http://yp.gates96.com/6/16/40/50.html +http://yp.gates96.com/6/16/40/69.html +http://yp.gates96.com/6/16/40/83.html +http://yp.gates96.com/6/16/41/49.html +http://yp.gates96.com/6/16/41/50.html +http://yp.gates96.com/6/16/41/67.html +http://yp.gates96.com/6/16/42/15.html +http://yp.gates96.com/6/16/42/51.html +http://yp.gates96.com/6/16/42/56.html +http://yp.gates96.com/6/16/43/8.html +http://yp.gates96.com/6/16/43/69.html +http://yp.gates96.com/6/16/43/71.html +http://yp.gates96.com/6/16/44/11.html +http://yp.gates96.com/6/16/44/51.html +http://yp.gates96.com/6/16/45/20.html +http://yp.gates96.com/6/16/45/43.html +http://yp.gates96.com/6/16/46/12.html +http://yp.gates96.com/6/16/46/25.html +http://yp.gates96.com/6/16/46/64.html +http://yp.gates96.com/6/16/47/42.html +http://yp.gates96.com/6/16/47/80.html +http://yp.gates96.com/6/16/48/54.html +http://yp.gates96.com/6/16/48/85.html +http://yp.gates96.com/6/16/49/51.html +http://yp.gates96.com/6/16/49/62.html +http://assgay.com/main.html?fuck.cock.gaysex +http://ring.yamanashi.ac.jp/pub/linux/linuxppc/contrib/software/System_Environment/Libraries/?S=A +http://computalynx.tucows.com/winme/adnload/138681_29976.html +http://computalynx.tucows.com/winme/adnload/138706_29992.html +http://computalynx.tucows.com/winme/adnload/138690_29990.html +http://computalynx.tucows.com/winme/adnload/138694_29981.html +http://iceberg.adhomeworld.com/cgi-win/redirect.exe/851857198 +http://link.fastpartner.com/do/session/600337/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/mondosoft.php +http://link.fastpartner.com/do/session/600337/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/nordicliving.php +http://link.fastpartner.com/do/session/600337/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/create/learn.htm +http://www.linux.com/networking/network/applications/hardware/device/development/ +http://www.linux.com/networking/network/applications/hardware/device/Corel/ +http://www.linux.com/networking/network/applications/hardware/device/?kw_offset=50 +http://ftp.gigabell.net/debian/dists/unstable/main/binary-m68k/sound/?M=A +http://no.egroups.com/message/slfxpzur/36 +http://no.egroups.com/message/slfxpzur/38 +http://nuance.dhs.org/lbo-talk/0004/2286.html +http://www.jamba.de/KNet/_KNet-XEk8j1-ADd-136sq/showInfo-datenschutz.de/node.0/cde7f1uou +http://yp.gates96.com/2/37/60/0.html +http://yp.gates96.com/2/37/60/13.html +http://yp.gates96.com/2/37/61/24.html +http://yp.gates96.com/2/37/61/66.html +http://yp.gates96.com/2/37/62/5.html +http://yp.gates96.com/2/37/62/31.html +http://yp.gates96.com/2/37/63/31.html +http://yp.gates96.com/2/37/63/43.html +http://yp.gates96.com/2/37/63/48.html +http://yp.gates96.com/2/37/63/60.html +http://yp.gates96.com/2/37/63/88.html +http://yp.gates96.com/2/37/64/62.html +http://yp.gates96.com/2/37/64/74.html +http://yp.gates96.com/2/37/65/0.html +http://yp.gates96.com/2/37/66/20.html +http://yp.gates96.com/2/37/67/41.html +http://yp.gates96.com/2/37/68/2.html +http://yp.gates96.com/2/37/68/50.html +http://yp.gates96.com/2/37/69/15.html +http://yp.gates96.com/2/37/69/41.html +http://yp.gates96.com/2/37/69/47.html +http://yp.gates96.com/2/37/69/60.html +http://yp.gates96.com/2/37/69/75.html +http://yp.gates96.com/2/37/69/76.html +http://gettosdownloads.subportal.com/sn/Palm_Pilot/Games/12428.html +http://news.novgorod.ru/read/65/2000/10/27/10/49 +http://www.schwan.de/links-biografie.html +http://www.fogdog.com/cedroID/ssd3040183124617/cgi-bin/MyFogdog +http://www.nrk.no/finnmark/x27_6_97/nyh9.htm +http://www.aelita.net/products/news/services/sitemap/~archive/Download_redirect/company/Copyright.htm +http://www.staroriental.net/nav/soeg_c/ihf,aol,n15,149,TVB香港小姐2000.html +http://members.xoom.com/agent187/politics.htm +http://sunsite.org.uk/public/packages/perl/collections/cis.ufl/comp.lang.perl.announce/1998-03/724 +http://www.thestateofcolorado.com/gcecommercialsales.html +http://ftp.du.se/pub/redhat/rawhide/sparc/RedHat/RPMS/?M=A +http://www.linux.com/networking/network/community/trade_show/magazine/open_source/ +http://www.linux.com/networking/network/community/trade_show/magazine/Slashdot/ +http://www.linux.com/networking/network/community/trade_show/magazine/investors/ +http://scifi.emerchandise.com/browse/TV/PIN/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/DILBERT/_/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/DR.KATZ/_/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/FRIENDS/_/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/FUTURAMA/_/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/LOIS-CLARK/_/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/SPEEDRACER/_/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/THUNDERCATS/_/b.TV/s.KkOtzPMn +http://scifi.emerchandise.com/browse/WCW/_/b.TV/s.KkOtzPMn +http://www.railion.de/home/db_reise_touristik/region/bremen/db_rt_firmenreisedienst_reisezentrum_hb.shtml +http://pegasus.infor.kanazawa-it.ac.jp/~hara/bsd4.1-release/D/N_GETFLAG_NET.html +http://yp.gates96.com/5/54/20/19.html +http://yp.gates96.com/5/54/21/5.html +http://yp.gates96.com/5/54/21/42.html +http://yp.gates96.com/5/54/21/60.html +http://yp.gates96.com/5/54/21/69.html +http://yp.gates96.com/5/54/21/81.html +http://yp.gates96.com/5/54/21/96.html +http://yp.gates96.com/5/54/22/6.html +http://yp.gates96.com/5/54/22/29.html +http://yp.gates96.com/5/54/22/33.html +http://yp.gates96.com/5/54/22/64.html +http://yp.gates96.com/5/54/22/83.html +http://yp.gates96.com/5/54/22/94.html +http://yp.gates96.com/5/54/22/98.html +http://yp.gates96.com/5/54/23/17.html +http://yp.gates96.com/5/54/23/41.html +http://yp.gates96.com/5/54/24/2.html +http://yp.gates96.com/5/54/24/5.html +http://yp.gates96.com/5/54/24/9.html +http://yp.gates96.com/5/54/24/90.html +http://yp.gates96.com/5/54/25/89.html +http://yp.gates96.com/5/54/26/41.html +http://yp.gates96.com/5/54/27/83.html +http://yp.gates96.com/6/59/21/52.html +http://yp.gates96.com/6/59/22/63.html +http://yp.gates96.com/6/59/23/37.html +http://yp.gates96.com/6/59/23/95.html +http://yp.gates96.com/6/59/24/3.html +http://yp.gates96.com/6/59/24/9.html +http://yp.gates96.com/6/59/25/26.html +http://yp.gates96.com/6/59/25/55.html +http://yp.gates96.com/6/59/25/84.html +http://yp.gates96.com/6/59/25/94.html +http://yp.gates96.com/6/59/26/53.html +http://yp.gates96.com/6/59/26/73.html +http://yp.gates96.com/6/59/27/15.html +http://yp.gates96.com/6/59/27/29.html +http://yp.gates96.com/6/59/27/49.html +http://yp.gates96.com/6/59/27/97.html +http://yp.gates96.com/6/59/28/31.html +http://yp.gates96.com/6/59/28/32.html +http://yp.gates96.com/6/59/28/39.html +http://yp.gates96.com/6/59/28/98.html +http://yp.gates96.com/6/59/29/22.html +http://yp.gates96.com/6/59/29/83.html +http://www.gbnf.com/genealogy/royal92/html/d0016/I1249.HTM +http://www.gbnf.com/genealogy/royal92/html/d0018/I734.HTM +http://hifichoice.co.uk/archive/perl/193_printreview.htm +http://hifichoice.co.uk/archive/perl/313_printreview.htm +http://www.highwired.net/Paper/UniversalNav/Redirect/0,5314,2623-7802,00.html +http://www.mrlinux.notrix.de/ +http://www.ucalgary.ca/UofC/faculties/medicine/CHS/nhrdb/area/anat/fr.htm +http://home.pchome.com.tw/tv/pili0614/xing-sh/capric/capric47.htm +http://home.pchome.com.tw/tv/pili0614/xing-sh/capric/capric21.htm +http://home.pchome.com.tw/tv/pili0614/xing-sh/capric/caf26.htm +http://user.chollian.net/~pleiad7s/josun/3-37.htm +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=233&discrim=81,3,15 +http://mediate.magicbutton.net/do/session/625571/vsid/3342/tid/3342/cid/88020/mid/2008/rid/2313/chid/2648/url/http://www1.getmapping.com/aboutus/index.cfm +http://www.telecombrokers.com/q/001p/atn8/2aS9DLAZRXc.htm +http://www.telecomrefunds.com/q/001p/atn8/4SeFiiXvs2A.htm +http://soho.nascom.nasa.gov/solarsoft/soho/lasco/lasco/data_anal/data/9701/?M=A +http://members.xoom.com/mindnare +http://people.freenet.de/TheChamp/nachhilfe.htm +http://people.freenet.de/TheChamp/cheats.htm +http://www.zinezone.com/movies/1,4003,1040-23080,00.html +http://kulichki-win.rambler.ru/moshkow/TURIZM/kutsajo6.txt_with-icons.html +http://www.linux.com/networking/network/release/availability/hardware/?printable=yes +http://www.linux.com/networking/network/release/availability/hardware/applications/ +http://www.shopworks.com/flmp/index.cfm/action/cart/userid/000D1850-2F00-19FE-9038010B0A0ADCF2 +http://shrike.depaul.edu/~afranz/multimedia/?S=A +http://totalsports.net/news/20001014/bbo/mlb/sea/001014.0024.html +http://totalsports.net/news/20001009/bbo/mlb/sea/001009.0039.html +http://totalsports.net/news/20001006/bbo/mlb/sea/001006.0354.html +http://cometweb01.comet.co.uk/do!session=131986&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkkHbqpLZXmLbkZHljlKaltLkilLXalKfkaLbukKeqjLi1 +http://html.tucows.ciaoweb.it/adnload/berglincondlbind.html +http://www.tiscover.com/1Root/Interessante_Region/127151/sportfreizeit/m_sportfreizeit.wm_sport_freibad..1.html +http://f24.parsimony.net/forum54080/messages/97.htm +http://f24.parsimony.net/forum54080/messages/68.htm +http://www.amulation.com/md-l-archive/199702/msg00210.html +http://netpower.tucows.com/winnt/adnload/2821_29573.html +http://kutschen.de/Schoner/Info-d/literature/collections/collections/Geschichte/ +http://webtools.myschoolonline.com/page/0,1871,0-353-38-44534,00.html +http://www.linux.com/networking/network/help/hardware/open_source/GNOME/ +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=12,25,26,17,24 +http://retailer.gocollect.com/do/session/1912664/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/exclusives.asp +http://retailer.gocollect.com/do/session/1912665/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/news/index.asp +http://ring.nihon-u.ac.jp/pub/doc/jpnic/members/WORLDNET/members.txt +http://www.123webagent.com/q/001p/atn8/zImXxARDSm.htm +http://www.tu-chemnitz.de/~jflo/DOSDemos/cost_b.txt +http://yp.gates96.com/5/54/27/97.html +http://yp.gates96.com/5/54/28/23.html +http://yp.gates96.com/5/54/29/33.html +http://yp.gates96.com/5/54/29/64.html +http://rex.skyline.net/html/Medical_Equipment.html?224,software,equipment,agriculture,science +http://adex3.flycast.com/server/socket/127.0.0.1:2800/click/OnlineCitiesSM/OnlineCitiesInteractiveCityGuides/bd434602591 +http://www.dispatch.co.za/1998/05/29/business/BA.HTM +http://www.dispatch.co.za/1998/05/29/business/JSE.HTM +http://retailer.gocollect.com/do/session/1912663/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/help/site_tour/index.asp +http://retailer.gocollect.com/do/session/1912663/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/about.asp +http://retailer.gocollect.com/do/session/1912663/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/contact.asp +http://www.hblb.org.uk/hblbweb.nsf/$Pages/NewsArchive1!OpenDocument&ExpandSection=8,9,3,6,1,11,13 +http://retailer.gocollect.com/do/session/1912620/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/gifts/gift_floor.asp +http://genforum.genealogy.com/ga/messages/4583.html +http://genforum.genealogy.com/ga/messages/4582.html +http://genforum.genealogy.com/ga/messages/4570.html +http://genforum.genealogy.com/ga/messages/4561.html +http://genforum.genealogy.com/ga/messages/5575.html +http://ftp.gnu.org/software/sather/ICSI_Sather/whoswho.html +http://dk.egroups.com/group/GHSBasketball +http://dk.egroups.com/group/lovebasket +http://biblioteca.upv.es/bib/doc/doc_fisbd/10/131276//V/1820145/0////25/S/MLTPAID +http://www.qth.net/archive/packfr/200009/20000921.html +http://213.36.119.69/do/session/152975/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/preparer/sante.htm +http://ftp.lip6.fr/pub8/FreeBSD/FreeBSD-current/ports/emulators/mtools/ +http://ftp.lip6.fr/pub8/FreeBSD/FreeBSD-current/ports/emulators/sim6811/ +http://fyi.cnn.com/ASIANOW/asiaweek/97/0328/aa7.html +http://pub21.ezboard.com/fbeauxbatonfrm32.showMessage?topicID=6.topic +http://www.tente.de/us/produkte/produkteigenschaften/aa000001609.htm +http://www.tente.de/us/produkte/produkteigenschaften/aa000001630.htm +http://ftp.sunet.se/pub/FreeBSD/ports/ports-stable/net/rboot/?N=D +http://www.geocities.co.jp/Technopolis-Mars/3952/link.html +http://saleonall.com/cat/software/reference/5112/969434/advanced-search.html +http://www.jazzbude.de/EddieLockjawDavis/B000026F24.htm +http://www6.freeweb.ne.jp/art/iftaka/art/ +http://www.canit.se/(ftp,irc,k15,www)/support/kontakt.html +http://www.mirror.edu.cn/res/sunsite/pub/academic/chemistry/iupac/Download/publications/pac/special/0199/ +http://cinemabilia.de/details/katnr/234764/ +http://polygraph.ircache.net:8181/services/design/http_-2www.infolane.com/dallas.htm +http://ftp.sunet.se/pub/FreeBSD/ports/ports-stable/games/crafty-open-medium/pkg-comment +http://uk.dir.yahoo.com/Education/Primary_and_Secondary/Schools/Middle_Schools/By_Region/U_S__States/Virginia/Complete_List/ +http://yp.gates96.com/6/2/10/13.html +http://yp.gates96.com/6/2/10/41.html +http://yp.gates96.com/6/2/10/83.html +http://yp.gates96.com/6/2/11/51.html +http://yp.gates96.com/6/2/11/89.html +http://yp.gates96.com/6/2/12/22.html +http://yp.gates96.com/6/2/12/58.html +http://yp.gates96.com/6/2/12/62.html +http://yp.gates96.com/6/2/12/79.html +http://yp.gates96.com/6/2/13/19.html +http://yp.gates96.com/6/2/13/51.html +http://yp.gates96.com/6/2/13/64.html +http://yp.gates96.com/6/2/14/75.html +http://yp.gates96.com/6/2/15/91.html +http://yp.gates96.com/6/2/16/83.html +http://yp.gates96.com/6/2/18/15.html +http://yp.gates96.com/6/2/18/54.html +http://yp.gates96.com/6/2/19/35.html +http://yp.gates96.com/6/2/19/68.html +http://yp.gates96.com/6/2/19/75.html +http://yp.gates96.com/6/2/19/82.html +http://yp.gates96.com/6/2/19/87.html +http://www.chaos.dk/sexriddle/z/w/c/b/v/ +http://itcareers.careercast.com/texis/it/itjs/+bwwBmeg5986wwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewhTwdGpdGwBna5dhBiwGnawppcoqwBodD5amnVncdpMnDBaiw5roDtBdDamwBwaoDqc1moDtamn5otDanLpnGonDqnawDwcO5o5aMFqhTfR20Dzme8hwwwpBmeMWD86etmwww5rmeHdwwwBrmeZpwww/jobpage.html +http://itcareers.careercast.com/texis/it/itjs/+3wwBmeV6D86euhwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewhTwdGpdGwBna5dhBiwGnawppcoqwBodD5amnVncdpMnDBaiw5roDtBdDamwBwaoDqc1moDtamn5otDanLpnGonDqnawDwcO5o5aMFqhTfR20Dzme8hwwwpBmeMWD86etmwww5rmeidwwwBrmeZpwww/jobpage.html +http://itcareers.careercast.com/texis/it/itjs/+iwwBmeiWD86zwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewhTwdGpdGwBna5dhBiwGnawppcoqwBodD5amnVncdpMnDBaiw5roDtBdDamwBwaoDqc1moDtamn5otDanLpnGonDqnawDwcO5o5aMFqhTfR20Dzme8hwwwpBmeMWD86etmwww5rme3dwwwBrmeZpwww/jobpage.html +http://sanming.ebigchina.com/ +http://www.bestinfo.net.cn/bsti_kjxn/gn/guoneifagui/17hebei3.htm +http://www.detroitfreepress.com/photos/umgallery/g8/g8.1.htm +http://www.detroitfreepress.com/photos/umgallery/g8/g8.3.htm +http://xgll.soyou.edu.cn/item/2000-04-07/43733.html43733.html +http://se.egroups.com/message/bunyan/903 +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/KIRJASTO-+JA+TIETOPALVELUT/p%E4ij%E4t-h%E4meen+koulutuskonserni/tietokannat/kirjastot/viitetietokannat/ +http://channel.nytimes.com/2000/05/19/technology/ +http://www.ycwb.com.cn/gb/2000/04/15/jrzk/jrms/5.html +http://no.egroups.com/message/healthdigest/97 +http://no.egroups.com/message/healthdigest/119 +http://www.securitiestimes.com.cn/199909/10/ssgs_19990910007_xw.html +http://javatest.a-net.nl/servlet/pedit.Main/http://www.dohistory.org/interests/i_teaching.html +http://www.buybuddy.com/sleuth/27/1/11009/518452/ +http://www.buybuddy.com/sleuth/27/1/11001/518452/ +http://www.buybuddy.com/sleuth/27/1/11004/518452/ +http://ring.omp.ad.jp/archives/text/CTAN/fonts/metrics/tools/?D=A +http://www.jamba.de/KNet/_KNet-CIq8j1-hEd-138qo/showInfo-special1.de/node.0/cde7f1uou +http://cafe4.daum.net/Cafe-bin/Bbs.cgi/sdfamilypds/qry/zka/B2-kBI7p/qqatt/^ +http://www.insurequotes.com/oh3/1AB2.html +http://www.egroups.com/login.cgi?login_target=%2Fmessage%2FWHKPNews%2F190 +http://www.linux.com/networking/network/performance/reliability/linux/?printable=yes +http://preview.egroups.com/message/tattoos88/32 +http://ring.shibaura-it.ac.jp/archives/NetBSD/packages/1.5/cobalt/math/ +http://ring.shibaura-it.ac.jp/archives/NetBSD/packages/1.5/cobalt/sysutils/ +http://in.us.biz.yahoo.com/z/a/p/prgx/prgx_f0149933.html +http://www.backflip.org/members/robeeena/6484057 +http://www.accesslasvegas.com/shared/health/adam/ency/article/003481res.html +http://library.cuhk.edu.hk/search*chi/dAir+--+Pollution+--+China+--+Hong+Kong./dair+pollution+china+hong+kong/-17,1,1,B/frameset&F=dair+pilots+united+states+biography&7,,7 +http://innopac.lib.tsinghua.edu.cn:2082/search*chi/cTM-62+C288/ctm-62+c288/-5,-1,,B/browse +http://www.nd.edu/~rarebook/coins/bnl-mg/BNL-index-B/BNL-index-BU/BNL-index-bursley.html +http://home.kimo.com.tw/lcl566/布告欄.htm +http://www.northampton.ac.uk/cgi-bin/liberation/betsie/betsie.pl/1005/www.northampton.ac.uk/stu/commdev/chap.htm +http://www.peopledaily.co.jp/199905/11/newfiles/col_990511001040_zyxw.html +http://missuniverse.studiostore.com/browse/PAGEANTS/CAP/s.pJicQfVY +http://ftp.up.pt/Linux/Linus/kernel/v2.1/patch-html/patch-2.2.0-pre6/linux_drivers_misc_parport_procfs.c.html +http://ftp.up.pt/Linux/Linus/kernel/v2.1/patch-html/patch-2.2.0-pre6/linux_drivers_sound_es1370.c.html +http://ftp.up.pt/Linux/Linus/kernel/v2.1/patch-html/patch-2.2.0-pre6/linux_include_asm-arm_arch-vnc_system.h.html +http://ftp.up.pt/Linux/Linus/kernel/v2.1/patch-html/patch-2.2.0-pre6/linux_include_asm-arm_dec21285.h.html +http://www.gbnf.com/genealog2/dezarn/html/d0004/I1071.HTM +http://dogbert.wu-wien.ac.at/UniverCD/cc/td/doc/product/access/acs_mod/cis4000/4000/c4000him/22693/ +http://www.uralweb.ru:8081/stats/who +http://www.rrz.uni-hamburg.de/biologie/b_online/kegg/kegg/db/ligand/cpdhtm/C04881.html +http://www.la.digitalcity.com/fortwaynein/health/conditions.dci?condition=badbreath +http://ibelong.digitalcity.com/uticaarea/guygirlmidwest/main.dci?page=guyssept2000 +http://moviestore.zap2it.com/browse/MOVIES/JACKET/s.jNIqMaLO +http://www.doc.ic.ac.uk/~ace97/whoknows/whoknows.cgi?topic=applescript +http://www.doc.ic.ac.uk/~ace97/whoknows/whoknows.cgi?topic=prolog +http://www.doc.ic.ac.uk/~ace97/whoknows/whoknows.cgi?topic=samba +http://209.52.189.2/discussions.cfm/3031/1757-1776 +http://209.52.189.2/discussions.cfm/3031/757-776 +http://209.52.189.2/discussions.cfm/3031/57-76 +http://itcareers.careercast.com/texis/it/itjs/+DwwBmeOWD86OwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewVtqDhdGMwBodDanDtoDnnGaoDBntGwBodDaMwDwtnMnDBanDBnGpGo5na5nGVnG5anLpnGonDqnaDnBidGAa5O5BnMawppcoqwBodDaMFqhTfR20DzmeitwwwpBme2WD86e1xwww5rmenDwwwBrmeZpwww/morelike.html +http://volunteersolutions.org/austin/volunteer/opp/one_100634_printer_detailed.html +http://www.changeyourhome.net/PropertiesToLet/WithamLet/LOO606/pages/DCP_0421_JPG.htm +http://www.users.qwest.net/~eagletac/ +http://www.motorradversand.de/cgi-bin/bekleidung/integralhelm/NG94G933/beurteilung.htm +http://stol.list.ru/catalog/25440.html +http://stol.list.ru/catalog/25301.html +http://www.eveclub.com/cgi-bin/eveclub.front/972959436300/Club/start/1000000 +http://www.gohamptonroads.com/sportsticker/events/06-12/0447.CWS.FSUTEXCURRENT.html +http://genforum.genealogy.com/merriman/messages/228.html +http://genforum.genealogy.com/merriman/messages/223.html +http://genforum.genealogy.com/merriman/messages/163.html +http://genforum.genealogy.com/merriman/messages/495.html +http://genforum.genealogy.com/merriman/messages/232.html +http://genforum.genealogy.com/merriman/messages/351.html +http://genforum.genealogy.com/merriman/messages/324.html +http://genforum.genealogy.com/merriman/messages/510.html +http://genforum.genealogy.com/merriman/messages/57.html +http://genforum.genealogy.com/merriman/messages/12.html +http://genforum.genealogy.com/merriman/messages/263.html +http://genforum.genealogy.com/merriman/messages/15.html +http://retailer.gocollect.com/do/session/1912656/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus53832/eus53833/eus328722/eus129553/eus129564/ +http://cma.arabia.com:8008/jordan/article/print/arabic/0,5195,3750,00.html +http://webhome.ai-lab.fh-furtwangen.de/for_local_use_only/CD-TMFUMV/daten/mathema/01121m/?N=D +http://store1.europe.yahoo.com/brink2/2000000141305.html +http://www.contractorresource.com/Vermont/Westford/Architects.shtml +http://www.bemi-immobilien.de/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/3d-service/Top-Darlehens-Konditionen/Startseite/Gemeinsam/versicherungen/gebaeude/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Top-Darlehens-Konditionen/anforderungsformular.htm +http://free.polbox.pl/p/pphromar/OFERTA.htm +http://www.burstnet.com/ads/ad5788a-map.cgi/tr00010005_12 +http://www.private-immobilien-boerse.de/ungarn/verkauf/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/Gemeinsam/Immolink/3d-service/IIM-Teil/Startseite/froben.htm +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/KIRJASTO-+JA+TIETOPALVELUT/ammattikorkeakoulukirjastot/lahti/toisen+asteen+koulutus/ammattikorkeakoulut/ +http://www.geomag.com/pirates/html/4books.html +http://www.lithoquoter.com/Scripts/WebObjects.exe/Printers.woa/559420000049560000009753100000548302/main.wo/7016200000448302/0/-/prime +http://www.adventurecentre.com/Framesets/intrside/csh.htm +http://mitglied.tripod.de/vox0/negrostodos/de_sexo_dobles.html +http://www.sasinstitute.com/offices/asiapacific/taiwan/whatsnew/art1999/art091601.html +http://oss.sgi.com/cgi-bin/cvsweb.cgi/gdb/sim/ppc/Attic/ppc-opcode-complex?only_with_tag=HEAD +http://www.yorosiku.net:8080/-_-http://www.suntory.co.jp/eco/what.html +http://www.yorosiku.net:8080/-_-http://www.suntory.co.jp/culture/birds/welcome.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/linux/music/misc/unitest/lit/pushkin.html +http://sunsite.uakom.sk/tucows/adnload/69291_28346.html +http://members.tripod.com/yamabito2/gardening_000416_0502_n22.htm +http://www.affiliate.hpstore.hp.co.uk/do/session/380775/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/REGISTRATION/entry.asp +http://www.onsemi.com.cn/pub/prod/0,1193,products1_Disty_order=MC100H642FNR2,00.html +http://perso.wanadoo.fr/michel.brunel/Infographie/content/contacts.htm +http://mindit.netmind.com/proxy/http://www.film.com/RGI/FC.(/watch/broadband.jhtml).def...RGI//reviews/features/mow/blairwitch2.jhtml +http://www.doc.ic.ac.uk/lab/labsrc_area/firstyear/submissions/1997-98/jmc1/labs/Ex09/gv197/?N=D +http://www-d0.fnal.gov/d0dist/dist/releases/test/l3fmuo_unpack/rcp/?N=D +http://students.lsu.edu/students/main.nsf/c81d2bf8cb0b80ff862566fb00105ab2/44dc495cc7534894862566fe00127751!OpenDocument&ExpandSection=7,10,4,9 +http://www.zdnet.com/gamespot/filters/printerfriendly/0,10855,2531809-95,00.html +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/asiasanahaku/el%25C3%2583%25C2%25A4kelaitokset/vakuutuslaitokset/rahoitus/el%E4kerahastot/ +http://coe.ier.hit-u.ac.jp/BibEc/data/Papers/fthteavfo2-96.html +http://polygraph.ircache.net:8181/http_-2ESPN.SportsZone.com/nfl/mall/http_-2www.excite.com/http_-2www.exploreuw.com/cards/ +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=cosido&l=pt +http://fazmali.bigsmart.com/mall/allinone/comparison_chart_new.html +http://sunsite.ualberta.ca/pub/Mirror/gnu/etc/ORDERS +http://www.bumppo.net/lists/realbasic-dr/1998/12/msg00347.html +http://www.bumppo.net/lists/realbasic-dr/1998/12/msg00363.html +http://www.bumppo.net/lists/realbasic-dr/1998/12/msg00482.html +http://www.bumppo.net/lists/realbasic-dr/1998/12/msg00483.html +http://www.bumppo.net/lists/realbasic-dr/1998/12/msg00499.html +http://www.bumppo.net/lists/realbasic-dr/1998/12/msg00508.html +http://www.bumppo.net/lists/realbasic-dr/1998/12/msg00518.html +http://it.sports.yahoo.com/000911/90/of8m.html +http://ftp.support.compaq.com/public/dunix/v3.2g/TruCluster_V1.0/?M=A +http://ftp.support.compaq.com/public/dunix/v3.2g/TruCluster_V1.0/ReleaseNotes.pdf +http://www.quzhou.gov.cn/flfg.nsf/0a043ae26eb50247002564640039f21d/e3cb86464a9f805a002564ac0039422d!OpenDocument&ExpandSection=5,1,9 +http://www.quzhou.gov.cn/flfg.nsf/0a043ae26eb50247002564640039f21d/e3cb86464a9f805a002564ac0039422d!OpenDocument&ExpandSection=6,1,9 +http://polygraph.ircache.net:8181/Keyboards/http_-2www.sky.net/~robertf/http_-2domino.findyn.com/fdi.nsf/http_-2home.netscape.com/ +http://www.nv.cc.va.us/home/jakim +http://itcareers.careercast.com/texis/it/itjs/+nwwBmJe0B-deVmwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewXhmoBGnaqdGpdGwBodDaDnBidGAoDta5O5BnM5amo5BGox1BnmanDtoDnnGaMw55wqr15nBB5a51ppdGBamnVncdpaBn5BaMFqhTfR20DzmeQtwwwpBme-WD86eyxwww5rmesdwwwBrmeZpwww/morelike.html +http://itcareers.careercast.com/texis/it/itjs/+MwwBme7WD86JwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewXhmoBGnaqdGpdGwBodDaDnBidGAoDta5O5BnM5amo5BGox1BnmanDtoDnnGaMw55wqr15nBB5a51ppdGBamnVncdpaBn5BaMFqhTfR20DzmeQtwwwpBme-WD86eyxwww5rme4dwwwBrmeZpwww/jobpage.html +http://my.dreamwiz.com/hideyu/couple/couplemain.htm +http://www.noras.bizland.com/top_pages/top_gen_1.htm +http://www.nomade.fr/catm6/entreprises_economi/electricite_electro/electricite/composants_fournitu/index5.shtml +http://www.staroriental.net/nav/soeg_c/ihf,aeb,s0,363,黎明.html +http://online.excite.de/lifestyle/katalog/27990 +http://www.linux.com/networking/network/performance/install/news/Linux/ +http://www.linux.com/networking/network/performance/install/news/kernel/ +http://tw.yahoo.com/Regional/Countries_and_Regions/China/Provinces__Regions_and_Municipalities/Shandong/Cities_and_Towns/He_Zhe/Government/ +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/ReadAdverData/2000-10-29/12/972792271154.txt +http://independent-sun-01.whoc.theplanet.co.uk/news/Sport/Football/Bradford/ipswich221000.shtml +http://www.emis.de/journals/EJDE/Monographs/Volumes/Monographs/1996/05-Hetzer/Hetzer-tex +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux-2.3-4/linux/arch/arm/def-configs/assabet?only_with_tag=LINUX-2_4_0-test1 +http://www.nrk.no/finnmark/x22_8_96/arkivet/ +http://pelit.saunalahti.fi/.9/telenation/valveworld/games/Half-Life/?S=A +http://pelit.saunalahti.fi/.9/telenation/valveworld/games/Half-Life/_Dedicated.txt +http://pelit.saunalahti.fi/.9/telenation/valveworld/games/Half-Life/_Mods.txt +http://ftp.sunet.se/pub/FreeBSD/ports/ports-stable/games/bugsx/?N=D +http://ring.yamanashi.ac.jp/archives/NetBSD/packages/1.4.1/sparc/databases/ +http://citeseer.nj.nec.com/cidcontext/260967 +http://members.tripod.co.jp/jojo6251/sasamineHP.htm +http://www.segodnya.ru/w3s.nsf/Archive/2000_96_life_vrez_noname2.html +http://www.citybrasil.com.br/rs/ivora/cidadefala.htm +http://web62.com/engl/fashion/pompoes/nav.htm +http://www.jufo.com/netcenter/house/item/bglz/477_lmt.html +http://gatekeeper.dec.com/pub/BSD/FreeBSD/FreeBSD-current/src/gnu/libexec/uucp/uupick/ +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/lelandsystems.stanford.edu/announce/pubsw/ +http://www.schleuse.de/maschine/World/Deutsch/Kultur/Literatur/Autoren_und_Autorinnen/D/Dominik,_Hans/ +http://www.elsur.cl/archivo/mayo2000/8mayo2000/elsur/espectaculos/ind2.php3 +http://www.jpc-neuheiten.de/2881737.htm +http://www.digitaldrucke.de/(aktuell,arbeitsvermittlung,computer,creaccess,gaestebuch,hilfe,hilfeallgemein,individualverkehr,kultur,onlineservice,schnellübersicht,sense,veranstaltungen,verkehr,von)/_fort/html/themen/computer/soft/links/softquad.htm +http://bbs.syu.ac.kr/NetBBS/Bbs.dll/groupbbs031/rcm/zka/B2-kB23m/qqo/004A/qqatt/^ +http://www.city-map.de/city/print/nl/Niedersachsen/Osterholz/actueel_&_nieuw/onroerendgoed_&_woningen/k012700681.html +http://members.tripod.com/sultana_2/thiskindalife.htm +http://members.tripod.com/sultana_2/thisthing.htm +http://members.tripod.com/sultana_2/believeinthis.html +http://tulips.ntu.edu.tw/search*chi/m586.47+4412/m586.47+4412/-5,-1,0,B/frameset&F=m586.48+0146&1,1 +http://btp1da.phy.uni-bayreuth.de/ftp/pub/FreeBSD/ports/www/linbot/?S=A +http://pub6.ezboard.com/fbiblediscussionandsharingparableorversesharing.subscribeUnregisteredToTopic?topicID=113.topic +http://www.cs.rit.edu/usr/local/pub/atk/course_descr/481.dir/?M=A +http://neptune.guestworld.com/gear/gateway.cfm?action=manage&owner=Nickdays +http://retailer.gocollect.com/do/session/1912673/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/shipping_policy.asp +http://tucows.minorisa.es/adnload/001-006-009-001.html +http://www.cwi.nl/~jack/spunk/texts/pubs/sekhmet/8/sp001225.txt +http://homepage.yesky.com/33554432/36700160/103524.htm +http://cvs.php.net/viewcvs.cgi/php3/functions/gd.c?annotate=1.65&sortby=log +http://www.genexchange.com/deathreg.cfm?state=nc&county=pasquotank +http://www.genexchange.com/schoolreg.cfm?state=nc&county=pasquotank +http://www.tagnet.org/uva/Eventos/Emergencia99/Fotos/FotosOccidente01.htm +http://itcareers.careercast.com/texis/it/itjs/+CwwBmue0B-dswwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew6nmoBGnaqdGpdGwBodDa5oBnaoDqc1mnanLqnca15naGn31oGnma5Aocc5awqqd1DBoDtamn5oGwxcnaMFqhTfR20Dzme9twwwpBme+6D865www5rmesDwwwBrmeRdwww/jobpage.html +http://retailer.gocollect.com/do/session/1912638/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://kulichki-win.rambler.ru/inkwell/bio/zitinsk.htm +http://www.thestateofcolorado.com/e1tatpiercing.html +http://www.pc-schulmusik.purespace.de/seminar/START.HTM +http://www.feeler.nl/rubrieken/index.xml/818004059 +http://ftp.dartmouth.edu/~mcb/faculty/fiering.html +http://ustlib.ust.hk/search*chi/cHD30.28+.C56+1995/chd+++30.28+c56+1995/-17,-1,0,E/2browse +http://herndon1.sdrdc.com/cgi-bin/com_detail/C00325258/ +http://www.linux.com/networking/network/industry/press_release/linuxworld/Linux/ +http://mindit.netmind.com/proxy/http://www.abc.net.au/children/bananas/dreamtime/page1.htm +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959860700/Catalog/1000188 +http://207.87.5.36/pc/news/saa7108/ +http://musicalproducts.asiaep.com/muspro5a.htm +http://www.trax.nilex.co.uk/trax.cgi/A1S/A1U/1AL/A1S/A2S/C1L/ +http://www.cjga.com/JamMoviesCanadianO/obsessed.html +http://www.symantec.se/region/jp/support/mac/utiliti/num352/num352up.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=catapultaras&l=pt +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=catapultai&l=pt +http://no.egroups.com/group/Chenzhou-families +http://www.teenplatinum.com/barelylegal/anal-sexass/young-adultbest-friends/hardaction/slutsnude/red-toenail-polishfoot-fetish/toenail-polish.html +http://beatles.sonicnet.com/allmusic/ai_links.jhtml?ai_id=1000 +http://www.luecos.de/wow/art/fu_satir_30142.html +http://nw1.newsweek.com/nw-srv/inetguide/iguide_4505343.html +http://www.si.uniovi.es/mirror/squid/mail-archive/squid-users/200002/0637.html +http://sunsite.compapp.dcu.ie/pub/perl/modules/by-category/08_User_Interfaces/Tk/NI-S/Tk402.004.readme +http://www.amzn.com/exec/obidos/tg/feature/-/44435/ +http://www.amzn.com/exec/obidos/tg/feature/-/2869/ +http://www.hanter21.co.kr/NetBBS/Bbs.dll/dhliter02/lst/qqeq/1/zka/B2-kBINo/qqo/PRMY +http://www.linux.com/networking/network/help/email/web/security/ +http://www.linux.com/networking/network/help/email/web/Slackware/ +http://www.linux.com/networking/network/help/email/web/e-commerce/ +http://www.linux.com/networking/network/help/email/web/release/ +http://debian.tod.net/debian/dists/stable/contrib/binary-all/web/?S=A +http://ftp.sunet.se/pub/FreeBSD/ports/ports-current/devel/fastcrc/pkg-descr +http://www.trax.nilex.co.uk/trax.cgi/A1C/A2S/B1S/B3S/B1S/C1U/ +http://www.trax.nilex.co.uk/trax.cgi/A1C/A2S/B1S/B3S/B1S/C1D/ +http://rex.skyline.net/html/Metalurgy.html?266,supplies,hobbies,painting,arts +http://infoseek.wunderground.com/geo/BigtempBannerPromo/US/CO/Cortez.html +http://www.kaernten.at/1Root/Kontinent/6/Staat/7/Bundesland/17/Ort/820/Pension/304806/Homepage/h_homepage...1.html +http://dellnet.excite.de/nachrichten/katalog/6663 +http://www.users.skynet.be/eloymarc/infomobil2/sobeen13.htm +http://www.outpersonals.com/cgi-bin/w3com/pws/out/hXRIA9gT9KNJakAdbkyW2SaEFRyXAJCa2tpUDiYF1BHxbpYG0_go-roWL4XPWFopknXRvCQG4gmCQLNceomD4GJpJ4hvR4eYeQbgN2CFeSPhxakPczINPvttFOQK3IDjjmYz66jR +http://www.outpersonals.com/cgi-bin/w3com/pws/out/_cRIZWRepq55uG8fC8ijlWOJrkBzrY7AXdlxz7fhosBeDRNPqhpYFY3uMBgWodvLAPXL2sPRQ7GqKF66xzHYxHZISDRz4dfZjEKnEShXdRFhDxBcOPx4ufr7uXHA0sNvRvMq6Z1j +http://polygraph.ircache.net:8181/health/http_-2cyril.com/http_-2www.americanexpress.com/corp/consumerinfo/privacy/privacystatement.shtml +http://polygraph.ircache.net:8181/health/http_-2cyril.com/arch.html +http://www.villager.com/ctg/cgi-bin/Villager/home/AAAksrACwAAACCOAAI +http://www.medoc-ias.u-psud.fr:81/synoptic/gif/950829/?D=A +http://members.tripod.lycos.nl/unlimited_pagez/pld2.html +http://www.thisislancashire.co.uk/lancashire/archive/1996/01/25/FEATURES0VQ.html +http://members.tripod.com/rebelstrange/buxoms.html +http://fi.egroups.com/message/TEZKo/3 +http://www.yamato.jp.ibm.com/servers/eserver/xseries/about/availa.html +http://polygraph.ircache.net:8181/NetworkInfo/http_-2www.thepetsupply.com/3d/web.html +http://polygraph.ircache.net:8181/NetworkInfo/http_-2www.thepetsupply.com/3d/http_-2www.sccsi.com/welcome.html +http://www.luf.org/wiki/edit/GIG/GenericCodingTerm +http://208.178.109.85/msgshow.cfm/msgboard=822531545582878&msg=50215618980084&page=1&idDispSub=-1 +http://mercury.spaceports.com/~xenical/diet-food.html +http://de.news.yahoo.com/991202/3/echc.html +http://web.tiscalinet.it/ipsiang/uviafede/tertulli.html +http://www.brio.de/BRIO.catalog/39fdb8820423a4d82740d472aa780733/Customer/Register +http://rainforest.parentsplace.com/dialog/thread.pl/bradley2/16/2.html?dir=prevResponse +http://www.centc251.org/forums/aca-1/dispatch.cgi/isowg4/folderFrame/100012/0/def/1208103 +http://www.bemi-immobilien.de/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/versicherungen/gebaeude/Gemeinsam/Inserieren/Gemeinsam/MarketingStrategie/Gemeinsam/erreichenPartner/Gemeinsam/versicherungen/unfall/Top-Darlehens-Konditionen/anforderungsformular.htm +http://www.planetit.com/techcenters/docs/internet_&_intranet/news/PIT20000630S0024/threads?comment_status=on +http://ftp.eq.uc.pt/software/unix/Linux/redhat/redhat-6.2/doc/HOWTOS/localization/Hellenic-HOWTO-html/Hellenic-HOWTO-8.html +http://help.sap.com/saphelp_45b/helpdata/de/20/7be8341545ab06e10000009b38f83b/applet.htm +http://www.imagestation.com/member/?name=RonnyClas6&c=1 +http://www.egroups.com/messages/cmass-syd-talk/1170 +http://bellsouth-cl.tucows.com/winnt/xwinservernt_size.html +http://ftp.surfnet.nl/os/FreeBSD/cdrom/development/FreeBSD-CVS/ports/mail/youbin/patches/home.html +http://chat.bigchurch.com/cgi-bin/w3com/pws/bc/PDhIf1s64yA1us4SS1FzmCsroIgpwrmcmdaKEhvT295b5JjMxs9ttaP_gpBzDbn5VR9hkgTaiz3efTGjRK64ORbhJMs0Q8ONiYshBhnFHdkQjl3uSSwZim5B5Layd_SDwYDTVgHM659c +http://www.starshop.co.uk/Masson-Andre/Masson-Andre-Soleil-3200802.html +http://www.21hk.com/book/wx1/wx/zpj/h/huanzhulouzhu/shushan/4/ +http://www.dietrich-computer.de/creativegrafik.htm +http://forum.kf.kommorg.no/forum/agenda21/dispatch.cgi/disk_1/showFolder/100005/9206559 +http://mindit.netmind.com/proxy/http://abc.net.au/rn/schedule/wed.htm +http://www.fogdog.com/cedroID/ssd3040183156802/nav/stores/adventure_travel/ +http://www.fogdog.com/cedroID/ssd3040183156802/nav/stores/tennis/ +http://link.fastpartner.com/do/session/600349/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/nordicliving.php +http://members2.clubphoto.com/luisf216501/TAMARINDO/icons.phtml +http://www.affiliate.hpstore.hp.co.uk/do/session/380795/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/SMARTTIPS/brocdesign.asp +http://www.hblb.org.uk/hblbweb.nsf/$Pages/NewsArchive1!OpenDocument&ExpandSection=3,7,14,5,13,4,12 +http://www.chaos.dk/sexriddle/d/l/t/i/a/ +http://www.crutchfield.com/S-s7BJxKzNmKr/shop/ +http://www.crutchfield.com/cgi-bin/S-s7BJxKzNmKr/email.asp?sid=S-s7BJxKzNmKr +http://tucows.interbaun.com/winme/adnload/137104_47064.html +http://iland.tucows.com/win2k/adnload/73990_29810.html +http://ftp.uk.debian.org/debian/dists/woody/contrib/binary-alpha/text/?M=A +http://sound-dist.secured.co.uk/cgi-bin/psShop.cgi/add|10P02|972959526|Warm===and===Dry|user|0|1,0,0,1 +http://pub14.ezboard.com/fjavagateforum69255multibasicboard +http://www.xrefer.com/entry/317621 +http://library.cuhk.edu.hk/search*chi/aChen,+Jih-peng./achen+jih+peng/-5,-1,0,B/frameset&F=achen+jie+qi&1,1 +http://library.cuhk.edu.hk/search*chi/aChen,+Jih-peng./achen+jih+peng/-5,-1,0,B/exact&F=achen+jih+hsin&1,2 +http://yp.gates96.com/5/50/60/53.html +http://yp.gates96.com/5/50/60/98.html +http://yp.gates96.com/5/50/61/14.html +http://yp.gates96.com/5/50/61/60.html +http://yp.gates96.com/5/50/62/0.html +http://yp.gates96.com/5/50/63/12.html +http://yp.gates96.com/5/50/63/14.html +http://yp.gates96.com/5/50/63/51.html +http://yp.gates96.com/5/50/63/52.html +http://yp.gates96.com/5/50/64/2.html +http://yp.gates96.com/5/50/64/31.html +http://yp.gates96.com/5/50/65/36.html +http://yp.gates96.com/5/50/65/44.html +http://yp.gates96.com/5/50/65/58.html +http://yp.gates96.com/5/50/65/78.html +http://yp.gates96.com/5/50/66/33.html +http://yp.gates96.com/5/50/66/38.html +http://yp.gates96.com/5/50/67/3.html +http://yp.gates96.com/5/50/67/83.html +http://yp.gates96.com/5/50/68/40.html +http://yp.gates96.com/5/50/69/2.html +http://yp.gates96.com/5/50/69/36.html +http://yp.gates96.com/5/50/69/49.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=cochichastes&l=pt +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=cochicharam&l=pt +http://www.affiliate.hpstore.hp.co.uk/do/session/380791/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp.com/cposupport/fr/?CTRYcod=FR +http://www.affiliate.hpstore.hp.co.uk/do/session/380791/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/FR/REGISTRATION/entry.asp +http://pub22.ezboard.com/fworldofmugenfrm2.showMessage?topicID=131.topic&index=1 +http://pub23.ezboard.com/fmugenshowdownfrm8.showMessage?topicID=36.topic&index=1 +http://www.questlink.com/QL/CDA/Research/ProductBrief/1,1768,0_11203_135680_85724,00.html +http://www.jamba.de/KNet/_KNet-KBq8j1-gEd-138pd/showInfo-special1.de/node.0/cde7f1uou +http://www.leg.wa.gov/pub/rcw%20-%20text/title_41/chapter_050/rcw_41_50_650.txt +http://www.tiscover.ch/1Root/Kontinent/6/Staat/30/Bundesland/31/Ort/234/Ferienpaket/20120/Homepage/buchen...1.html +http://family.go.com/Categories/Features/family_2000_02/kidv/kidv0200resourceiii/ +http://www.online.kokusai.co.jp/Service/V0043469/wrd/G200/service/service.html +http://www.linux.com/networking/network/help/hardware/website/ISP/ +http://store1.europe.yahoo.com/I/freemans_1592_58696403 +http://202.99.23.195/BIG5/channel5/745/20000427/51173.html +http://www-usa10.cricket.org/link_to_database/GROUNDS/WI/ALBION/ALBION_SPORTS_COMPLEX_00772/ +http://www16.freeweb.ne.jp/computer/taka34/ +http://books.hyperlink.co.uk/bookinfo/Caught_in_a_Tornado/Ross/James_R./155553192X +http://ftp.uni-stuttgart.de/pub/security/unix/SSLapps/doc/?S=A +http://www.moviestarpages.com/rebecca_romijn-stamos/picture05.htm +http://html.tucows.ciaoweb.it/adnload/001-009-008-022.html +http://html.tucows.ciaoweb.it/adnload/001-009-008-019.html +http://www.brio.de/BRIO.catalog/39fe2f4306cb75f4273fd472aa780708/UserTemplate/2 +http://www.hole.kommune.no/hole/journweb.nsf/weboffjournal!OpenView&Start=92&Count=50&Expand=170 +http://polygraph.ircache.net:8181/docs/Win95/MSdialer/http_-2www.fastcounter.com/http_-2home.netscape.com/home/http_-2www.bildhome.com/plantationhomes/bale1500.htm +http://polygraph.ircache.net:8181/docs/Win95/MSdialer/http_-2www.fastcounter.com/http_-2home.netscape.com/home/http_-2www.bildhome.com/plantationhomes/bale8000.htm +http://writer.heha.net/poetics/90_poetics.htm +http://yp.gates96.com/5/55/20/98.html +http://yp.gates96.com/5/55/21/17.html +http://yp.gates96.com/5/55/21/75.html +http://yp.gates96.com/5/55/22/2.html +http://yp.gates96.com/5/55/22/22.html +http://yp.gates96.com/5/55/22/92.html +http://yp.gates96.com/5/55/23/11.html +http://yp.gates96.com/5/55/23/46.html +http://yp.gates96.com/5/55/23/66.html +http://yp.gates96.com/5/55/23/90.html +http://yp.gates96.com/5/55/24/2.html +http://yp.gates96.com/5/55/24/83.html +http://yp.gates96.com/5/55/24/85.html +http://yp.gates96.com/5/55/25/62.html +http://yp.gates96.com/5/55/26/38.html +http://yp.gates96.com/5/55/26/48.html +http://yp.gates96.com/5/55/28/5.html +http://yp.gates96.com/5/55/28/77.html +http://yp.gates96.com/5/55/29/14.html +http://yp.gates96.com/6/50/40/47.html +http://yp.gates96.com/6/50/40/60.html +http://yp.gates96.com/6/50/40/62.html +http://yp.gates96.com/6/50/41/81.html +http://yp.gates96.com/6/50/41/83.html +http://yp.gates96.com/6/50/42/58.html +http://yp.gates96.com/6/50/42/90.html +http://yp.gates96.com/6/50/42/93.html +http://yp.gates96.com/6/50/43/29.html +http://yp.gates96.com/6/50/43/79.html +http://yp.gates96.com/6/50/43/85.html +http://yp.gates96.com/6/50/44/40.html +http://yp.gates96.com/6/50/44/76.html +http://yp.gates96.com/6/50/44/81.html +http://yp.gates96.com/6/50/45/15.html +http://yp.gates96.com/6/50/45/52.html +http://yp.gates96.com/6/50/46/15.html +http://yp.gates96.com/6/50/46/19.html +http://yp.gates96.com/6/50/46/92.html +http://yp.gates96.com/6/50/47/2.html +http://yp.gates96.com/6/50/47/7.html +http://yp.gates96.com/6/50/47/33.html +http://yp.gates96.com/6/50/49/29.html +http://yp.gates96.com/6/50/49/36.html +http://www.outpersonals.com/cgi-bin/w3com/pws/out/wRtIx3JBCL5wVzA1pIKradbm9z4Oo2BbPRx_FVh-j4UyLzjojbipsV0nsuM2iF9RxJ1jG2C4LUy3YP5pJl7qDqPdnqV765l2x5hJ0fIUUJuWLaccxO0svbclJ4-alyBQj6Y5dO8YdURyhf9q05q8mJ25FlvF62sm +http://213.36.119.69/do/session/152980/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www3.travelprice.com/voyages/recherche.phtml +http://yp.gates96.com/6/2/20/11.html +http://yp.gates96.com/6/2/21/12.html +http://yp.gates96.com/6/2/21/51.html +http://yp.gates96.com/6/2/21/56.html +http://yp.gates96.com/6/2/22/8.html +http://yp.gates96.com/6/2/22/38.html +http://yp.gates96.com/6/2/22/65.html +http://yp.gates96.com/6/2/23/14.html +http://yp.gates96.com/6/2/23/50.html +http://yp.gates96.com/6/2/23/57.html +http://yp.gates96.com/6/2/23/75.html +http://yp.gates96.com/6/2/24/15.html +http://yp.gates96.com/6/2/24/31.html +http://yp.gates96.com/6/2/24/43.html +http://yp.gates96.com/6/2/24/70.html +http://yp.gates96.com/6/2/24/87.html +http://yp.gates96.com/6/2/25/22.html +http://yp.gates96.com/6/2/25/53.html +http://yp.gates96.com/6/2/25/90.html +http://yp.gates96.com/6/2/26/25.html +http://yp.gates96.com/6/2/26/26.html +http://yp.gates96.com/6/2/26/45.html +http://yp.gates96.com/6/2/26/76.html +http://yp.gates96.com/6/2/27/34.html +http://yp.gates96.com/6/2/28/1.html +http://yp.gates96.com/6/2/28/25.html +http://yp.gates96.com/6/2/29/2.html +http://yp.gates96.com/6/2/29/31.html +http://yp.gates96.com/6/2/29/57.html +http://yp.gates96.com/6/2/29/74.html +http://archive.bitcon.no/tucows//winme/preview/136862.html +http://archive.bitcon.no/tucows//winme/preview/138371.html +http://archive.bitcon.no/tucows//winme/preview/137011.html +http://archive.bitcon.no/tucows//winme/preview/137897.html +http://archive.bitcon.no/tucows//winme/preview/138157.html +http://www.ngmag.com/books/reference/0792275667.html +http://socrates.berkeley.edu:4231/pth.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/music/midi/lit/quizz/lit/multiple.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/music/midi/lit/quizz/lit/god.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/music/midi/lit/quizz/misc/colorart/ +http://retailer.gocollect.com/do/session/1912687/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/postcards/index.asp +http://www.affiliate.hpstore.hp.co.uk/do/session/380807/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/creative/entry.asp +http://home.swipnet.se/~w-29806/Tab/Guitar/Svenska/h/Jakob%20Hellman/VACKERT_.TXT +http://jupiter.u-3mrs.fr/~msc41www/releves/16860204.HTM +http://citeseer.nj.nec.com/cidcontext/1003669 +http://citeseer.nj.nec.com/cidcontext/1003675 +http://citeseer.nj.nec.com/cidcontext/1003676 +http://www.escribe.com/religion/nondualitysalon/m10801.html +http://www.escribe.com/religion/nondualitysalon/m10824.html +http://www.tvstore.com/browse/TV/PATCH/s.bCooTxTe +http://digilander.iol.it/lorciao/computer.htm +http://yosemite.epa.gov/r9/sfund/overview.nsf/ef81e03b0f6bcdb28825650f005dc4c1/1d8f2e36da9dc1de8825660b007ee696?OpenDocument&ExpandSection=-1,-8,-4 +http://cn.egroups.com/post/ukr_liga?act=reply&messageNum=40 +http://www.lithoquoter.com/Scripts/WebObjects.exe/Printers.woa/048720000079262000002260000000798302/Session_Expired_Page.wo/6144200000698302/0/-/prime +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=coadjuvaram&l=pt +http://www.craft-supplies.co.uk/cgi-bin/psProdDet.cgi/LW132|972959517|Liming_&_Patinating|user|0|0,0,1,1 +http://www.angelfire.com/va/boogiescamp +http://www.kyotei.or.jp/JLC/VS/19/991209/0212.htm +http://www.affiliate.hpstore.hp.co.uk/do/session/380800/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/assistance/entry.asp +http://www.city-map.nl/city/map/en/Niedersachsen/Landkreis_Cuxhaven/customers/Dr.rer.nat._Büro_für_Erdwiss.Untersuchungen_Udo_Lade/contact.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=consternais&l=pt +http://muenchen.bda.de/freizeitparks/gastbuch/gaestebuch003.html +http://www.linux.com/networking/network/industry/growth/editing/SAP/ +http://www.linux.com/networking/network/industry/growth/editing/mobile/ +http://lists.omnipotent.net/qmail/199909/msg00892.html +http://lists.omnipotent.net/qmail/199909/msg00952.html +http://lists.omnipotent.net/qmail/199909/msg00964.html +http://ftp.cc.chuo-u.ac.jp/home/pub/lang/perl/CPAN/ports/msdos/old/?N=D +http://www3.buch-per-sms.de/faq.jsp$ID=To7697mC5277111659640048At0.5320036065114109 +http://www3.buch-per-sms.de/wir_ueber_uns.jsp$ID=To7697mC5277111659640048At0.5337056452821441 +http://tradersdirectory.com/channel/jobs/insurance/insurance_policy_clerk/b.2166.g.2360.html +http://www.mapion.co.jp/custom/nikkei/admi/13/13119/takashimadaira/7chome/27/ +http://www.dispatch.co.za/1998/02/19/easterncape/MARCHANC.HTM +http://www.techsupplies.com/sleuth/33/1/10703/523434/ +http://fi.egroups.com/message/911dispatchers/171 +http://polygraph.ircache.net:8181/services/define/toast/congress2000/http_-2www.sportfish.net/fish.htm +http://polygraph.ircache.net:8181/services/define/toast/congress2000/MS.htm +http://polygraph.ircache.net:8181/services/define/toast/congress2000/http_-2leader.linkexchange.com/1/X171400/clicklogo +http://polygraph.ircache.net:8181/services/define/toast/congress2000/cfiref.htm +http://www.digitaldrucke.de/(aktuell,arbeitsvermittlung,computer,daham,hilfe,individualverkehr,kultur,literatur,veranstaltungen,verkehr)/_fort/html/themen/aktuell/events/events.htm#regional +http://dellnet.excite.de/computer/katalog/7054 +http://read.cnread.net/cnread1/ztxs/b/baitian/lmss/006.htm +http://www-d0.fnal.gov/d0dist/dist/releases/psim01.02.00/l2utils/GNUmakefile +http://www.allgemeine-immobilien-boerse.de/Frankreich/Verkauf/Private-IB/Startseite/Gemeinsam/erreichenPartner/Gemeinsam/Inserieren/Allgemeine-IB/ +http://wish.themes.tucows.com/adnload/14495.html +http://wish.themes.tucows.com/preview/14494.html +http://wish.themes.tucows.com/preview/78220.html +http://www.uwm.edu/IMT/Computing/sasdoc8/sashtml/af/z0230835.htm +http://www.bdnet.com/Taiga/H/Fulu/fiche_serie.htm +http://se.egroups.com/message/clippingts/14?source=1 +http://adelaida.net/music/texts/trex_s1.html +http://archive.bitcon.no/pub/cica/handheld/desktop/ +http://www.jacksonhewitt.com/ctg/cgi-bin/JacksonHewitt/disclaimers/AAAksrACwAAACCMAAC +http://ftp.cc.chuo-u.ac.jp/home/pub/TeX/CTAN/language/ethiopia/ethtex/lj_fonts/?N=D +http://sirac.inrialpes.fr/Infos/Personnes/Christophe.Rippert/ressources/jdk1.3/docs/guide/jdbc/spec/jdbc-spec.frame16.html +http://www.linux.com/networking/network/release/press_release/competition/web/ +http://www.linux.com/networking/network/release/press_release/competition/internet/ +http://www.linux.com/networking/network/release/press_release/competition/HTTP/ +http://hughes.tucows.com/win2k/share2k_size.html +http://icq.planetout.com/popcornq/movienews/98/10/23/money/careers +http://go3.163.com/_NTES/~cntop07/files/k20808/zengby-k201/zengby-k201-09.html +http://uunetnl.pda.tucows.com/palm/pqa_news_license.html +http://uunetnl.pda.tucows.com/palm/preview/54359.html +http://uunetnl.pda.tucows.com/palm/preview/58637.html +http://uunetnl.pda.tucows.com/palm/adnload/72726_21807.html +http://uunetnl.pda.tucows.com/palm/adnload/62079_21796.html +http://uunetnl.pda.tucows.com/palm/preview/33674.html +http://uunetnl.pda.tucows.com/palm/preview/33501.html +http://uunetnl.pda.tucows.com/palm/adnload/52518_21780.html +http://ftp.dei.uc.pt/pub/net/ip/trace/traffic/?N=D +http://dreamgallery.simplenet.com/lobby/yrestless/sets/26/yrz19.htm +http://sanqin.net/wenyuan/gudian/fengshen/a/fengshen24.html +http://windows.tucows.com/preview/001-010-005-007C.html +http://windows.tucows.com/preview/001-010-005-004C.html +http://proshikanet.tucows.com/win2k/preview/37883.html +http://www5.cplaza.ne.jp/auth/kingdom/bbs/rescue/no70/182.html +http://www5.cplaza.ne.jp/auth/kingdom/bbs/rescue/no70/84.html +http://www5.cplaza.ne.jp/auth/kingdom/bbs/rescue/no70/82.html +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=7,19,34,20,29 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=36,19,34,20,29 +http://www.ne.jp/asahi/kume-kume/kume/photogellery/zoo/nihon_saru/html/nihon_saru04.html +http://www.ne.jp/asahi/kume-kume/kume/photogellery/zoo/nihon_saru/html/nihon_saru05.html +http://www.iabusnet.org:90/forums/aca-1/dispatch.exe/survey/showNextUnseen/fol/100001/2443194 +http://www.chaos.dk/sexriddle/t/r/p/c/p/ +http://www.ld.com/cbd/archive/1999/09(September)/13-Sep-1999/16sol007.htm +http://www.ld.com/cbd/archive/1999/09(September)/13-Sep-1999/16sol024.htm +http://www.ld.com/cbd/archive/1999/09(September)/13-Sep-1999/16sol025.htm +http://www.ld.com/cbd/archive/1999/09(September)/13-Sep-1999/16sol030.htm +http://debian.linux.org.tw/debian/dists/Debian2.1r4/non-free/binary-alpha/oldlibs/?N=D +http://www.tamil.net/list/2000-04/nav00304.html +http://www.2pl.com/b/se/to/1/01/05/v2/1010500263-7.htm +http://www.2pl.com/b/se/to/1/01/05/v2/1010500263-8.htm +http://www.mirror.ac.uk/sites/ftp.microsoft.com/deskapps/powerpt/KB/Q129/5/ +http://www.gbnf.com/genealogy/royal92/html/d0028/I307.HTM +http://www-linux.gsi.de/linux-doc/libqt2/examples/qfd/?M=A +http://www.arm.com/sitearchitek/support.ns4/html/sdt_debug!OpenDocument&ExpandSection=24,6,37,7 +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kdeutils/kab/kab_kab1importer.h?sortby=log&only_with_tag=KDE_2_0_RELEASE +http://www.allgemeine-immobilien-boerse.de/nordrhein-Westfalen/bielefeld/Verkauf/Allgemeine-IB/Gemeinsam/versicherungen/gebaeude/Private-IB/Gemeinsam/erreichenPartner/email3d.htm +http://www.allgemeine-immobilien-boerse.de/nordrhein-Westfalen/bielefeld/Verkauf/Allgemeine-IB/Gemeinsam/versicherungen/gebaeude/Private-IB/3d-service/info.htm +http://satlink.tucows.com/winme/htmleditme_rating.html +http://satlink.tucows.com/winme/adnload/137630_29066.html +http://satlink.tucows.com/winme/adnload/137653_29087.html +http://yp.gates96.com/5/55/40/63.html +http://yp.gates96.com/5/55/40/93.html +http://yp.gates96.com/5/55/41/8.html +http://yp.gates96.com/5/55/41/27.html +http://yp.gates96.com/5/55/41/93.html +http://yp.gates96.com/5/55/42/1.html +http://yp.gates96.com/5/55/42/65.html +http://yp.gates96.com/5/55/43/15.html +http://yp.gates96.com/5/55/43/26.html +http://yp.gates96.com/5/55/43/94.html +http://yp.gates96.com/5/55/44/70.html +http://yp.gates96.com/5/55/44/83.html +http://yp.gates96.com/5/55/45/17.html +http://yp.gates96.com/5/55/46/3.html +http://yp.gates96.com/5/55/46/39.html +http://yp.gates96.com/5/55/46/43.html +http://yp.gates96.com/5/55/47/18.html +http://yp.gates96.com/5/55/48/23.html +http://yp.gates96.com/5/55/48/40.html +http://yp.gates96.com/5/55/48/72.html +http://yp.gates96.com/5/55/48/93.html +http://yp.gates96.com/5/55/49/7.html +http://yp.gates96.com/5/55/49/8.html +http://yp.gates96.com/5/55/49/20.html +http://yp.gates96.com/5/55/49/37.html +http://yp.gates96.com/5/55/49/49.html +http://yp.gates96.com/5/55/49/60.html +http://yp.gates96.com/5/55/49/69.html +http://www.ramtron.com/pages/visiters.htm +http://genforum.genealogy.com/cgi-genforum/forums/oh/wayne.cgi?56 +http://freebsd.ntu.edu.tw/perl/modules/by-module/DB_File/STAS/?N=D +http://sunsite.org.uk/public/usenet/news-faqs/alt.answers/us-visa-faq/?D=A +http://circumstance.co.kr/www.globalvillage.com/support/software.html +http://mediate.magicbutton.net/do/session/625589/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-top50.html +http://itcareers.careercast.com/texis/it/itjs/+9wwBmev6D86wwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewGPndhBiwGna5O5BnManDtoDnnGamnVncdpoDtaBn5Baw1BdMwBodDaGn31oGnma5Aocc5anLpnGonDqnaGnwcaMFqhTfR20DzmeTtwwwpBm3eP0-dmwww5rmehDwwwBrmeZpwww/morelike.html +http://library.bangor.ac.uk/search/dProtestant+churches+--+New+York+(State)+--+History+--+19th+century/dprotestant+churches+new+york+state+history+++19th+century/-17,-1,0,B/frameset&F=dprotestant+churches+england+history+++16th+century&2,,3 +http://augustachronicle.com/stories/021299/fea_223-4914.000.shtml +http://dreamcity.gaiax.com/www/dreamcity/k/n/kint/menu.html +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceMallCategories-BBC709D6_97E3_3D628A3FC67830F4FB7BD0E0AC833504 +http://www.mirror.kiev.ua:8082/paper/2000/07/1251/text/07-09-1.htm +http://www.burstnet.com/ads/ad7826a-map.cgi/1025131450 +http://link.fastpartner.com/do/session/600341/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/se/ +http://topcu.tucows.com/winme/adnload/137966_29370.html +http://topcu.tucows.com/winme/adnload/137990_29378.html +http://itcareers.careercast.com/texis/it/itjs/+9wwBmeS+D86swwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew6hwAwMwoaBnqrDoqwcaqdD51cBoDta5wcn5aqdD51cBwDB5aBnqrDdcdton5apGd5pnqBoVnaq15BdMnG5apGdm1qBaBnwMaMFqtwAwMwoDzmehxwwwpBmeV+D86eqxwww5rmedDwwwBrmeZpwww/jobpage.html +http://itcareers.careercast.com/texis/it/itjs/+DwwBmeoWD86eDqwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew6hwAwMwoaBnqrDoqwcaqdD51cBoDta5wcn5aqdD51cBwDB5aBnqrDdcdton5apGd5pnqBoVnaq15BdMnG5apGdm1qBaBnwMaMFqtwAwMwoDzmehxwwwpBmeV+D86eqxwww5rmeqDwwwBrmeZpwww/morelike.html +http://itcareers.careercast.com/texis/it/itjs/+QwwBme4+D86qxwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew6hwAwMwoaBnqrDoqwcaqdD51cBoDta5wcn5aqdD51cBwDB5aBnqrDdcdton5apGd5pnqBoVnaq15BdMnG5apGdm1qBaBnwMaMFqtwAwMwoDzmehxwwwpBmeV+D86eqxwww5rm+mwwBrmeZpwww/jobpage.html +http://wwwbackup.trinler.net/anleitungen/manual/mod/mod_dll.html +http://wwwbackup.trinler.net/anleitungen/manual/mod/mod_log_agent.html +http://as400bks.rochester.ibm.com/pubs/html/as400/v4r5/ic2962/info/RZAIENETDOTDATA.HTM +http://www.gov.ie/educ/000928.htm +http://www.gov.ie/educ/speech/000928.htm +http://pub3.ezboard.com/utaela.showPublicProfile?language=EN +http://genforum.genealogy.com/cody/messages/700.html +http://genforum.genealogy.com/cody/messages/525.html +http://genforum.genealogy.com/cody/messages/494.html +http://genforum.genealogy.com/cody/messages/447.html +http://ftp.surfnet.nl/os/FreeBSD/cdrom/development/FreeBSD-CVS/ports/editors/psgml-emacs/files/home.html +http://www.mic.hr/PGBURZA:135556 +http://pub8.ezboard.com/fthecompanionswebboardfrm19 +http://pub8.ezboard.com/fthecompanionswebboardarchive +http://gallery2.simplenet.com/lobby/main/videocaps/ghoffman/precious/ghsp36.htm +http://www.symantec.ru/avcenter/venc/data/unashamed.html +http://www.symantec.ru/avcenter/cgi-bin/virauto.cgi?vid=7000 +http://www.symantec.ru/avcenter/cgi-bin/virauto.cgi?vid=1685 +http://www.symantec.ru/avcenter/cgi-bin/virauto.cgi?vid=5358 +http://rex.skyline.net/navigate.cgi?reading,retail,hobbies,painting,arts +http://rex.skyline.net/navigate.cgi?forsale,retail,hobbies,painting,arts +http://pds.nchu.edu.tw/cpatch/ftp/cuteftp/?S=A +http://www.tel.de/s/M/MCFIT.htm +http://zeus.uni-trier.de/~ley/db/indices/a-tree/s/Stevenson:Allan.html +http://www.alsapresse.com/jdj/00/07/14/SA/article_16.html +http://link.fastpartner.com/do/session/600359/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/jobpilot.php +http://link.fastpartner.com/do/session/600359/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/index.php +http://news.dreamwiz.com/news_lg/04/20001025/joins/200010251653041653193.html +http://news.dreamwiz.com/news_lg/04/20001025/joins/200010250820040820583.html +http://windows.tucows.com/winnt/adnload/71593_30161.html +http://213.36.119.69/do/session/152979/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/reserver/encheres/ +http://213.36.119.69/do/session/152979/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/IT_IT/ +http://www.centc251.org/forums/aca-1/dispatch.cgi/isowg4/showNextUnseen/fol/100012/1220541 +http://bigpanda.net/46/alphabetical.html +http://bigpanda.net/46/io.html +http://fi.egroups.com/message/puzzles/547 +http://theaceshow.com/drawinglinda.html +http://theaceshow.com/drawingsketch.html +http://ftp.jp.debian.org/debian/dists/woody/main/binary-all/news/?D=A +http://www.trax.nilex.co.uk/trax.cgi/A1S/A2L/1AS/B3U/B4L/C2S/ +http://www.trax.nilex.co.uk/trax.cgi/A1S/A2L/1AS/B3U/B4L/C4D/ +http://in.egroups.com/message/islaam/3 +http://in.egroups.com/message/islaam/29 +http://ustlib.ust.hk/search*chi/a%7B233e68%7D%7B215976%7D%7B213e2e%7D/a%7B233e68%7D%7B215976%7D%7B213e2e%7D/-5,-1,0,B/browse +http://yp.gates96.com/13/8/20/68.html +http://yp.gates96.com/13/8/21/25.html +http://yp.gates96.com/13/8/21/32.html +http://yp.gates96.com/13/8/21/49.html +http://yp.gates96.com/13/8/21/63.html +http://yp.gates96.com/13/8/21/88.html +http://yp.gates96.com/13/8/22/2.html +http://yp.gates96.com/13/8/22/10.html +http://yp.gates96.com/13/8/22/67.html +http://yp.gates96.com/13/8/22/79.html +http://yp.gates96.com/13/8/23/19.html +http://yp.gates96.com/13/8/23/31.html +http://yp.gates96.com/13/8/25/64.html +http://yp.gates96.com/13/8/25/68.html +http://yp.gates96.com/13/8/25/73.html +http://yp.gates96.com/13/8/26/6.html +http://yp.gates96.com/13/8/26/11.html +http://yp.gates96.com/13/8/26/12.html +http://yp.gates96.com/13/8/26/39.html +http://yp.gates96.com/13/8/26/54.html +http://yp.gates96.com/13/8/26/55.html +http://yp.gates96.com/13/8/26/82.html +http://yp.gates96.com/13/8/27/89.html +http://yp.gates96.com/13/8/28/22.html +http://yp.gates96.com/13/8/28/61.html +http://yp.gates96.com/13/8/29/13.html +http://yp.gates96.com/13/8/29/33.html +http://yp.gates96.com/13/8/29/83.html +http://www.private-immobilien-boerse.de/baden-wuertemberg/ostalb-kreis/Verkauf/Versteigerungen-IB/Startseite/Gemeinsam/erreichenPartner/IIM-Teil/Startseite/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/indexbeginn.htm +http://www2.so-net.ne.jp/mc/columns/nakama/1112/ +http://ring.shibaura-it.ac.jp/archives/pack/x68/personal/tokei/00_index.txt +http://yp.gates96.com/5/32/0/0.html +http://yp.gates96.com/5/32/0/99.html +http://yp.gates96.com/5/32/1/92.html +http://yp.gates96.com/5/32/1/93.html +http://yp.gates96.com/5/32/3/68.html +http://yp.gates96.com/5/32/4/21.html +http://yp.gates96.com/5/32/4/72.html +http://yp.gates96.com/5/32/5/87.html +http://yp.gates96.com/5/32/6/64.html +http://yp.gates96.com/5/32/7/25.html +http://yp.gates96.com/5/32/7/32.html +http://yp.gates96.com/5/32/7/44.html +http://yp.gates96.com/5/32/7/68.html +http://yp.gates96.com/5/32/7/78.html +http://yp.gates96.com/5/32/8/40.html +http://yp.gates96.com/5/32/8/59.html +http://yp.gates96.com/5/32/8/90.html +http://yp.gates96.com/5/32/8/95.html +http://yp.gates96.com/5/32/9/3.html +http://yp.gates96.com/5/32/9/54.html +http://yp.gates96.com/5/32/9/62.html +http://yp.gates96.com/5/32/9/77.html +http://tucows.soneraplaza.nl/winme/preview/138260.html +http://www.cnnews.com/maya/finance/cjsy/gncj/item/2000_07/206341.shtml +http://212.31.0.37/hur/turk/98/09/23/dunya/02dun.htm +http://212.31.0.37/hur/turk/98/09/12/dunya/01dun.htm +http://ftp.cwi.nl/ftp/mdr/LOCKED/ +http://ftp.cwi.nl/ftp/mdr/PICH/ +http://www.ncte.org/lists/ncte-talk/jan2000/msg02008.html +http://www.russ.ru/forums/prav-dir/conf2/695_r.htm +http://www.doc.ic.ac.uk/lab/labsrc_area/firstyear/submissions/1997-98/jmc1/labs/Ex05/mjp97/?D=A +http://www.affiliate.hpstore.hp.co.uk/do/session/380786/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/search.asp +http://www.flapjack.de/main/2ndHP/jangl43637.htm +http://195.166.55.201/vfg-uk/HTML/P145232.HTM +http://www.greenleaves.com/bookcat/gb_0689826788.html +http://webraft.its.unimelb.edu.au/730452/students/sgm/pub/ +http://ring.omp.ad.jp/pub/NetBSD/packages/pkgsrc/print/teTeX-share/files/ +http://ww.egroups.com/subscribe/wtcjk_purnawirawan +http://167.8.29.14/life/travel/ski/skinj.htm +http://www.nrk.no/finnmark/x26_5_97/fastesid/abonn.htm +http://www.brio.de/BRIO.catalog/39fe2f41050aa9b82741d472aa7806dd/UserTemplate/6 +http://207.25.71.143/golf/news/2000/04/18/heintz/ +http://weekends.worldres.com/script/gen_review.asp?hotel_id=4291&n=1231 +http://www.netitor.com/photos/schools/bc/sport/m-footbl/auto_pdf/weekly-release-082800.pdf +http://www.3w-sciencefiction.de/SmytheRH/SmytheRH0785808744.htm +http://www.zdnet.com/gamespot/stories/screens/0,10865,2617426-32,00.html +http://ftp.lip6.fr/pub2/sgml-tools/website/HOWTO/Root-RAID-HOWTO/t1450.html +http://webusers.siba.fi/doc/texmf/latex/ms/?M=A +http://www.trax.nilex.co.uk/trax.cgi/A1S/1AL/A3L/A1U/A3S/1AS/ +http://www.trax.nilex.co.uk/trax.cgi/A1S/1AL/A3L/A1U/A3S/D1U/ +http://www.trax.nilex.co.uk/trax.cgi/A1S/1AL/A3L/A1U/A3S/D3S/ +http://thaigate.rd.nacsis.ac.jp/ftp/thaisoft/nectec/linux.tle/6.01/Mandrake/?S=D +http://www-ind5.cricket.org/link_to_database/ARCHIVE/2000-01/AUS_LOCAL/GRADE/NSW/SCA/WOMEN/SCA-WOMEN_2000-01_FIXTURES.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=abbratend&l=de +http://www.webvillage.org/mBEDJPsite/html/downloadplugins.html +http://www.gov.karelia.ru:8081/gov/Karelia/658/8.html +http://www.private-immobilien-boerse.de/bayern/ingolstadt/Verkauf/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/Gemeinsam/Inserieren/Gemeinsam/erreichenPartner/Ferien-IB/Startseite/ +http://pillsonline.00go.com/lowfatdiet/lifetime_fitness.htm +http://tecfa2.unige.ch/guides/java/examples/JavaClassLibExamples/io/FileReader/Main.class +http://www.burstnet.com/ads/ad7826a-map.cgi/1933336291 +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/asiasanahaku/Hong%2520Kong/aasia/talous/pika-+ja+perustilastoja/ +http://home.tiscalinet.be/oaseidstad/vonk/optop2000.html +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=19,36,22,32,23 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=29,36,22,32,23 +http://cn.egroups.com/messages/virtualaccess/194 +http://jerken.grida.no/nor/soeno97/ozone/frames/pressure.htm +http://online.excite.de/erotik/katalog/6213 +http://online.excite.de/erotik/katalog/6187 +http://online.excite.de/erotik/katalog/6221 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=28,7,35,25,13 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=31,7,35,25,13 +http://genforum.genealogy.com/cgi-genforum/forums/loughlin.cgi?11 +http://freesoftware.missouri.edu/pub/CPAN/authors/id/J/JS/JSWARTZ/?D=A +http://link.fastpartner.com/do/session/600360/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/fastpartner.php +http://www.jobvillage.com/channel/jobs/sciences/life_sciences/soil_plant_scientist/b.1041.g.251.html +http://ftp.debian.org/dists/Debian2.2r0/non-free/binary-sparc/mail/?D=A +http://generalstore.everdream.com/kore/catalog/Office_Supplies/General_Office_Supplies/Tape_Flags/Arrow/GRP-US6663/product.html +http://www.hig.se/(date,if,set,tablify,user)/~jackson/roxen/ +http://www.hig.se/(date,if,language,set,tablify)/~jackson/roxen/ +http://www.cyber-pages.com/0prog/classifieds_display.cgi?oakland=WEMP=0 +http://202.84.17.6/csnews/articles/141_18691.htm +http://202.84.17.6/csnews/articles/142_18526.htm +http://ftp.dti.ad.jp/pub/FreeBSD/FreeBSD-current/www/es/releases/1.1.5/ +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=9&discrim=247,207,129 +http://ftp.up.pt/Linux/debian/dists/unstable/main/disks-i386/?M=A +http://www.unterhaltungs-cd.de/HillJonny/B000025087.htm +http://filebox.vt.edu/users/aneal/excess/_fpclass/ +http://www.jamba.de/KNet/_KNet-JOt8j1-OEd-139q0/showInfo-presse.de/node.0/cde7f1uou +http://www.tercera.cl/diario/1997/12/05/win.html +http://yp.gates96.com/14/88/20/8.html +http://yp.gates96.com/14/88/20/13.html +http://yp.gates96.com/14/88/22/30.html +http://yp.gates96.com/14/88/25/28.html +http://yp.gates96.com/14/88/25/65.html +http://yp.gates96.com/14/88/26/3.html +http://bsdweb.pasta.cs.uit.no/bsdweb.cgi/~checkout~/pkgsrc/math/grace/pkg/ +http://ftp.tokyonet.ad.jp/pub/Linux/debian-jp/dists/unstable-jp/contrib/binary-m68k/math/?S=A +http://my.dreamwiz.com/piramos/lan.htm +http://pub8.ezboard.com/fselfreliantlivingfrm16.showMessage?topicID=11.topic +http://pub8.ezboard.com/fselfreliantlivingfrm16.showMessage?topicID=4.topic +http://www.affiliate.hpstore.hp.co.uk/do/session/380798/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/SMARTTIPS/vacationcards.asp +http://systemlogic.neoseeker.com/Companies/productportfolios/NEC_Interchannel/?sortby=sections +http://www.houses-apartment-rentals.com/Virginia/city_search_criteria.asp?state=VA&City=DALHART +http://www.wcbcourses.com/wcb2/schools/MERCED/merced/dhauser/2/forums/forum2/messages/17.html +http://www.wcbcourses.com/wcb2/schools/MERCED/merced/dhauser/2/forums/forum2/messages/10.html +http://beautifulsavers.subportal.com/sn/Shell_and_Desktop/Quick_Shutdown_Tools/2702.html +http://polygraph.ircache.net:8181/getting_started/http_-2www.lucent.com/micro/K56flex/http_-2home.netscape.com/comprod/mirror/http_-2www.wtcsf.org/mall/http_-2www.cdnow.com/http_-2www.microsoft.com/msoffice/publicaffairs.html +http://polygraph.ircache.net:8181/getting_started/http_-2www.lucent.com/micro/K56flex/http_-2home.netscape.com/comprod/mirror/http_-2www.wtcsf.org/mall/http_-2www.cdnow.com/http_-2www.microsoft.com/msoffice/videobroadcast/ +http://www.yagoo.co.kr/stats/pitching.asp?Mlbmanid=JESPEN7599 +http://www.4hotfantasy.com/acommon/guests/python4.html +http://boerseninfos.ksk-tut.de/dynamic/ak/adhoc/news/519000-20000316-150811.html +http://boerseninfos.ksk-tut.de/dynamic/ak/adhoc/news/519000-19991025-082814.html +http://cn.yahoo.com/Regional/Countries_and_Regions/China/Provinces__Regions_and_Municipalities/Zhejiang/Cities_and_Towns/Li_Hsua/Business/Companies/Books/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380810/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/FR/REGISTRATION/entry.asp +http://kuyper.calvin.edu/fathers2/NPNF1-01/npnf1-01-12.htm +http://library.bangor.ac.uk/search/dModernism+(Literature)/dmodernism+literature/-5,-1,0,E/2browse +http://aleph.tau.ac.il:4500/ALEPH/ENG/ATA/AAS/AAS/SHORT/410519/1/ +http://pub1.ezboard.com/fflashboard1flashjunkiestalk.showAddReplyScreenFromWeb?topicID=190.topic&index=2 +http://www.inforiese.de/db_cargo/typ_b_files/db_cargo_cargo_ansprechpartner.shtml +http://www.gbnf.com/genealogy/dehart/html/d0005/I985.HTM +http://btclickfam.excite.co.uk/directory/categories/670199 +http://www.worldmedicus.com/servlet/Controller/$7008040516620000.sj_viewc/ +http://www.worldmedicus.com/servlet/Controller/$7008040528250000.sj/ +http://207.25.71.143/features/galleries/then_and_now/belinsky/belinsky01_lg_01.html +http://wiem.onet.pl/wiem/002c66.html +http://www.peopledaily.com.cn/GB/paper40/544/58242.html +http://www.uihealthcare.com////PatientsVisitors/MedMuseum/CenturyOfCaring/UniversityHospitals/05Quarantine.html +http://se.egroups.com/login.cgi?login_target=%2Fmessages%2Fwotccglist%2F333 +http://se.egroups.com/message/wotccglist/334 +http://se.egroups.com/message/wotccglist/350 +http://se.egroups.com/message/wotccglist/358 +http://www.msn.expedia.co.uk/wg/North_America/United_States/P30131.asp +http://www.uol.com.br/cinemaonline/starwars +http://www.perotech.ch/d/securedb/html/listtopic.php?7396 +http://moviestore.zap2it.com/browse/X-FILES/POSTCARD/s.goFzN1Lb +http://zeus.uni-trier.de/~ley/db/indices/a-tree/m/Morgoev:Vladimir_K=.html +http://www.3w-buecher.de/GilliesRobertJ/GilliesRobertJ0122839803.htm +http://www.buybuddy.com/sleuth/27/1/11002/6637/ +http://ftp.uk.debian.org/debian/dists/unstable/contrib/binary-powerpc/oldlibs/?D=A +http://no.egroups.com/login.cgi?login_target=%2Fgroup%2Fwww.members.xoom.com%2FLibertyFlame +http://www.aelita.net/products/support/sitemap/Reg/QuoteRegister/news/company/Copyright.htm +http://www.aelita.net/products/support/sitemap/Reg/QuoteRegister/news/services/default.htm +http://www.amateurplatinum.com/spankingfantasy/fertiletrophy-wife/hot-hardcore-fuckinglongest/red-toenail-polishfeet-fucking-/vietnamesewomen/chinesechi/womenpetite.html +http://www.amateurplatinum.com/spankingfantasy/fertiletrophy-wife/hot-hardcore-fuckinglongest/red-toenail-polishfeet-fucking-/vietnamesewomen/fuckinghard/actionsmacking.html +http://genforum.genealogy.com/cgi-bin/print.cgi?fikes::26.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/programs/unlambda/lit/quizz/music/midi/ +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/programs/unlambda/lit/quizz/computers/callcc.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/programs/unlambda/lit/quizz/misc/colorart/ +http://www.musiciansfriend.com/ex/ds/live/001030182726064208037002434823 +http://www.musiciansfriend.com/ex/ds/home/funzone/001030182726064208037002434823?doc=doc,postcard.html +http://www.musiciansfriend.com/ex/ds/home/platinum/001030182726064208037002434823?g,home.platinum.html +http://www.musiciansfriend.com/ex/ds/home/articles/001030182726064208037002434823?dbase=gw,gwmain.html +http://www.musiciansfriend.com/ex/ds/home/articles/001030182726064208037002434823?dbase=info,privacy.html +http://preview.egroups.com/dir/Business/Training_and_Schools/Management_Training/Consultants?st=4 +http://hammer.prohosting.com/~nieting/html1216/lmtf015.htm +http://planetfreebies.subportal.com/sn/Information_Management/Misc__Information_Databases/12835.html +http://dada.linuxberg.com/kdehtml/adnload/61589_33448.html +http://www.wlu.ca/~wwwregi/95-96/cal/ucourses/GM/GM151.html +http://walkabout.tucows.com/win2k/adnload/61015_28629.html +http://www.1001e.net/02/qbt/09.htm +http://se.egroups.com/post/webfaaa?act=reply&messageNum=3 +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/keats.admin.virginia.edu/asbestos/home.html +http://www.hotelboulevard.com/fr/riviera/standard/htmlf752567459c6d803842381c50e94fd9f/sessionLang/ANG/gettingstarted.html +http://ring.omp.ad.jp/pub/NetBSD/packages/pkgsrc/print/transfig/?N=D +http://citeseer.nj.nec.com/cidcontext/2339336 +http://www.uk.multimap.com/p/browse.cgi?pc=LS287DR +http://topcu.linux.tucows.com/x11html/adnload/46019_3809.html +http://www.mon.de/nr/stuemges +http://www.tamil.net/list/1998-10/msg00212.html +http://retailer.gocollect.com/do/session/1912682/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/terms_and_conditions.asp +http://pl.php.net/manual/nl/function.pfpro-version.php +http://members.tripod.co.jp/millenium/top.html +http://community.webshots.com/photo/4331085/4331572GooaFzYUAJ +http://community.webshots.com/photo/4331085/4331589oKrBmsJbga +http://community.webshots.com/photo/4331085/4331620zgfyMLoSjs +http://www.utdallas.edu/~chansen/text/qabbala9.html +http://www.jobvillage.com/channel/jobs/installation_repair/safety_equipment/fire_alarm/b.2283.g.3516.html +http://www.geocities.com/Area51/Chamber/8750/DoesKitEverTalkAboutTheSubjectOnHand.html +http://www.geocities.com/Area51/Chamber/8750/TheMotherofAllMissleBoats.html +http://www.geocities.com/Area51/Chamber/8750/Tomahawk2.html +http://www.thecitizennews.com/main/archive-000628/thecitizennews/citizen.html +http://links2go.publiweb.com/expert/topic/Mp3_Hardware +http://webhelp.promovacances.net/S02/BL/BEGYP/SAI00512024/cal.htm?d=1013 +http://205.161.150.96/cgi-bin/c2k/title_talent.html&id=143786&title_star=DOMINICK +http://dennou-q.geo.kyushu-u.ac.jp/library/Linux/debian-jp/dists/stable/non-free-jp/binary-all/net/?S=A +http://wow-online.vhm.de/Wirtschaft/Unternehmen/Versicherungen/Versicherungsgesellschaften/Signal_Versicherung.html +http://www.linux.com/networking/network/firewall/web/communications/?kw_offset=50 +http://www.leg.wa.gov/pub/rcw%20-%20text/title_28b/chapter_056/rcw_28b_56_090.txt +http://pub12.ezboard.com/flalaland96545listeningbooth.showMessage?topicID=74.topic +http://www.fogdog.com/cedroID/ssd3040183156032/crs/pw__/wld/fogdog_sports/lee_sport/fan_memorabilia/apparel/new_york_yanke_2000_ameri_leagu_champ_tee_shi.html +http://www.fogdog.com/cedroID/ssd3040183156032/nav/stores/adventure_travel/ +http://www.hoovers.com/travel/cityguide/detailed/0,3368,46_119158,00.html +http://user.chollian.net/~mlsc/ +http://www.158china.com/data/stock/fundowner/default.asp?stck_cd=0548 +http://www.affiliate.hpstore.hp.co.uk/do/session/380803/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/SMARTTIPS/createbroch.asp +http://rcsl.auto.inha.ac.kr/~treeman/Documents/HOWTO/Consultants-HOWTO-3.html +http://www.diogenes.ch/4DACTION/web_rd_aut_prview/a_id=7056427&area=&ID=483330 +http://polygraph.ircache.net:8181/http_-2www.horizonfinance.com/http_-2www.netscape.com/download/http_-2www.microsoft.com/ie/http_-2207.91.150.20/links.html +http://www.multicosm.com/facade/www.adobe.com/support/techguides/printpublishing/scanning/psscanning01b.html +http://yp.gates96.com/0/50/10/62.html +http://yp.gates96.com/0/50/10/95.html +http://yp.gates96.com/0/50/11/1.html +http://yp.gates96.com/0/50/11/18.html +http://yp.gates96.com/0/50/11/49.html +http://yp.gates96.com/0/50/12/55.html +http://yp.gates96.com/0/50/13/48.html +http://yp.gates96.com/0/50/13/96.html +http://yp.gates96.com/0/50/14/15.html +http://yp.gates96.com/0/50/14/73.html +http://yp.gates96.com/0/50/15/50.html +http://yp.gates96.com/0/50/15/80.html +http://yp.gates96.com/0/50/16/1.html +http://yp.gates96.com/0/50/16/8.html +http://yp.gates96.com/0/50/17/50.html +http://yp.gates96.com/0/50/17/71.html +http://yp.gates96.com/0/50/18/25.html +http://yp.gates96.com/0/50/18/73.html +http://yp.gates96.com/0/50/18/82.html +http://yp.gates96.com/0/50/18/84.html +http://yp.gates96.com/0/50/18/90.html +http://cisne.sim.ucm.es/search*spi/dBallets+--+Gran+Bretaña+--+Discos+compactos/dballets+gran+bretan~aa+discos+compactos/-29,-1,0,B/browse +http://opac.lib.ntnu.edu.tw/search*chi/++ftlist/bp20005025/-17,-1,0,B/browse +http://www.trax.nilex.co.uk/trax.cgi/A1S/1AL/A3L/A4R/B1D/A3S/ +http://php.nic.fi/manual/html/function.cpdf-open.html +http://php.nic.fi/manual/html/function.cpdf-fill.html +http://php.nic.fi/manual/html/function.cpdf-setrgbcolor-fill.html +http://www.classiccmp.org/mail-archive/classiccmp/1998-04/1426.html +http://text.csn.ul.ie/~danny/tabs/p/proclaimers/?N=D +http://mirror.nucba.ac.jp/mirror/FreeBSD/branches/3.0-stable/ports/japanese/zangband/?N=D +http://augustachronicle.com/stories/100197/spo_fishing.html +http://www.symatrixinc.com/website/website.nsf/0/3e40df86fb357cd5882568720079613f!OpenDocument&ExpandSection=10,8,9,5 +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/linux/music/quizz/pics.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/linux/music/quizz/lit/ldvelh.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/linux/music/quizz/misc/unitest/ +http://mirror.nucba.ac.jp/mirror/FreeBSD/branches/3.0-stable/ports/japanese/ptex-pkfonts360/?N=D +http://www.2pl.com/b/ru/fi/1/24/06/b1/1240601249-11023.htm +http://galaxy.einet.net/galaxy/Community/United-States/States/Minnesota/Cities-and-Regions/Winona/Education/K--12/Middle/Public.html +http://www.hotelboulevard.com/fr/paris/standard/htmlc866e5cecf73322551f00b0108eb84bc/sessionLang/ANG/prov/browse/cp/75001/resultatSearch.html +http://btp1da.phy.uni-bayreuth.de/ftp/pub/FreeBSD/ports/japanese/dvipsk-vflib/pkg-descr +http://32548news.subportal.com/sn/Utilities/Misc__Encryption_Utilities/ +http://www.hongen.com/proedu/hext/zxks/dxyw/html/dxy62804.htm +http://www.users.globalnet.co.uk/~roy/InternetTree/WC01/WC01_226.htm +http://www2.msstate.edu/~eaddy/famtread/html/nti07339.htm +http://www.trackinfo.com/trakdocs/hound/ca/RESULTS/ARCHIVE/1996/0996/GRCA19S.HTM +http://www.idg.net/crd_essential_110984.html +http://www.zdnet.de//news/artikel/2000/09/06015-wc.html +http://www.secinfo.com/d114Cu.52.htm +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus141561/eus174865/eus327367/eus327527/eus331435/ +http://enjoy100.com.cn/200005/23/ +http://link.fastpartner.com/do/session/600348/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/mediatransfer.php +http://www.chaos.dk/sexriddle/t/z/p/b/b/ +http://www.brio.de/BRIO.catalog/39fe2f4106ca8ce0273fd472aa7806ff/UserTemplate/6 +http://link.fastpartner.com/do/session/600352/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/robinhus.php +http://link.fastpartner.com/do/session/600352/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/create/index.php +http://www.underground-online.com/companyfinder/filters/products/0,9996,1793-101,00.html +http://mediate.magicbutton.net/do/session/625588/vsid/3342/tid/3342/cid/88020/mid/2008/rid/2313/chid/2648/url/http://www1.getmapping.com/viewer.cfm +http://aol.digitalcity.com/houston/recreation/event.dci?eid=6452 +http://www.linux.com.hk/mirror/ldp/LDP/LG/issue10/lg_bytes10.html +http://www.linux.com.hk/mirror/ldp/LDP/LG/issue10/issue10.txt +http://www.beauty.net.cn/main/japanese/mie.htm +http://www.allgemeine-immobilien-boerse.de/kanada/verkauf/Gemeinsam/Inserieren/Allgemeine-IB/Ferien-IB/Startseite/Private-IB/Startseite/Default.htm +http://www.kodak.co.uk/US/en/corp/store/catalog/Product.jhtml?PRODID=2113&CATID=2234 +http://opac.lib.ntnu.edu.tw/search*chi/f373+017/f373+017/-5,-1,,B/browse +http://ftp.du.se/disk3/mandrake/7.1/Mandrake/mdkinst/etc/pcmcia/?M=A +http://www.teenplatinum.com/barelylegal/anal-sexass/taismall/almond-skinned/{gaylink} +http://194.128.65.4/pa/cm199697/cmhansrd/vo970318/debtext/70318-11.htm +http://netlondon.hotelbook.com/live/photos/19368 +http://www.centc251.org/forums/aca-1/dispatch.cgi/hsi/folderFrame/100205/0/author/1243894 +http://www.teacherformation.org/html/od/facilitators.cfm/task1,login/discussion_id,2/xid,5474/yid,3022999 +http://polygraph.ircache.net:8181/environment_energy/heritage/http_-2www.apache.org/ +http://plat.debian.or.jp/debian/dists/unstable/main/binary-alpha/math/?D=A +http://home.hiwaay.net/~bjacobs/genealogy/laster/html/d0054/g0000038.html +http://www.northampton.ac.uk/cgi-bin/liberation/betsie/betsie.pl/1005/www.northampton.ac.uk/cgi-bin/liberation/betsie/betsie.pl/1037/www.northampton.ac.uk/lrs/Information/refword.html +http://ustlib.ust.hk/search*chi/cPL1275+.F426+1991/cpl+1275+f426+1991/-5,1,1,E/frameset&F=cpl+1273+y36+1982&1,1, +http://stormix.com/en/resources/packages/tex/devel/debmake +http://stormix.com/en/resources/packages/tex/devel/doc++ +http://stormix.com/en/resources/packages/tex/devel/ftnchek +http://stormix.com/en/resources/packages/tex/devel/libnet0-dev +http://stormix.com/en/resources/packages/tex/devel/libobgtk-dev +http://stormix.com/en/resources/packages/tex/devel/netatalk-dev +http://stormix.com/en/resources/packages/tex/devel/pact-base +http://stormix.com/en/resources/packages/tex/devel/scalapack1-mpich +http://members.tripod.co.jp/sugisaka/?M=A +http://www.szinfo.com/book/wai/no/fa/h/hongyuhei/011.htm +http://www.szinfo.com/book/wai/no/fa/h/hongyuhei/054.htm +http://www.centc251.org/forums/aca-1/dispatch.cgi/hsi/listUnseen/fol/100205/20,0/1230074 +http://www.crutchfield.com/cgi-bin/S-p5rPnwuC0SA/Auto.asp +http://www.abb.co.uk/global/seapr/SEAPR035.NSF/viewUNID/f79b6db19a951ce0c125697300319a41!OpenDocument&ExpandSection=6,4,8,5 +http://freebsd.ntu.edu.tw/perl/authors/id/A/AO/AOCINAR/?S=A +http://www.gaymencam.com/elke.html +http://www.linux.com/networking/network/industry/new/web_server/website/ +http://www.tccomputers.com/cgi-bin/bp/1899758621/products/removeabledrives/removeabledrives.htm +http://www.tccomputers.com/cgi-bin/bp/1899758621/store/showcart.html +http://www.highwired.net/Guidance/Section/0,1860,1779-27626,00.html +http://gd.cnread.net/cnread1/net/zpj/r/repinsky/005.htm +http://www.amateurplatinum.com/tubal-ligationmilk/pregnanttubal-ligation/off-the-ragnipples/jizz-dribbling-cumshotscumming/{amateurlink} +http://home.dqt.com.cn/~why/wenzhang/ckpajq/.htm +http://ftp.fi.debian.org/debian/dists/woody/non-free/binary-all/doc/?D=A +http://www.linux.com/networking/network/website/hardware/howto/Linuxcare/ +http://www.linux.com/networking/network/website/hardware/howto/sales/ +http://shn.webmd.com/printing/asset/adam_imagepage_8626 +http://www.geocities.co.jp/Outdoors/2127/bangai_makuyama.html +http://www2.to/souhey +http://www.hotelboulevard.com/fr/paris/standard/html73b90b9d262d517e98c9d779b3b09b7a/sessionLang/ANG/prov/browse/cp/75017/resultatSearch.html +http://perso.wanadoo.fr/olivier.leieber/page22.html +http://www.computer-networking.de/studenten/dv_labor/onlinebuecher/apache/sections.html +http://saejong.pufs.ac.kr/~cilim/homepage/link.html +http://cafe3.daum.net/Cafe-bin/Bbs.cgi/hopepds/qry/zka/B2-kCYFp/qqatt/^ +http://www3.newstimes.com/archive99/jun1899/lch.htm +http://www.7thlevel.com/python/cwot/demo/ +http://www.paidmania.com/getpaid/signup/100/4632 +http://yp.gates96.com/12/14/0/31.html +http://yp.gates96.com/12/14/0/43.html +http://yp.gates96.com/12/14/0/60.html +http://yp.gates96.com/12/14/1/18.html +http://yp.gates96.com/12/14/1/44.html +http://yp.gates96.com/12/14/1/64.html +http://yp.gates96.com/12/14/1/82.html +http://yp.gates96.com/12/14/2/84.html +http://yp.gates96.com/12/14/3/61.html +http://yp.gates96.com/12/14/4/65.html +http://yp.gates96.com/12/14/5/24.html +http://yp.gates96.com/12/14/5/49.html +http://yp.gates96.com/12/14/5/60.html +http://yp.gates96.com/12/14/5/62.html +http://yp.gates96.com/12/14/6/20.html +http://yp.gates96.com/12/14/6/51.html +http://yp.gates96.com/12/14/7/28.html +http://yp.gates96.com/12/14/7/85.html +http://yp.gates96.com/12/14/7/93.html +http://planet.gaiax.com/home/kito/main +http://www.svt.se/falun/packat/program/603/images/1rep/?D=A +http://volunteersolutions.org/swt/volunteer/opp/one_151124_printer_detailed.html +http://fyi.cnn.com/ASIANOW/asiaweek/97/1003/nat1.html +http://www.farhi.org/ps09/ps09_233.htm +http://yp.gates96.com/6/8/30/27.html +http://biz.yahoo.com/apf/000929/tire_death_7.html +http://www.studentadvantage.gamers.com/game/135583 +http://www.studentadvantage.gamers.com/game/45759 +http://yp.gates96.com/6/8/30/44.html +http://yp.gates96.com/6/8/30/50.html +http://yp.gates96.com/6/8/30/72.html +http://yp.gates96.com/6/8/30/86.html +http://yp.gates96.com/6/8/30/89.html +http://yp.gates96.com/6/8/31/78.html +http://yp.gates96.com/6/8/31/88.html +http://yp.gates96.com/6/8/32/3.html +http://yp.gates96.com/6/8/32/24.html +http://yp.gates96.com/6/8/32/34.html +http://yp.gates96.com/6/8/33/14.html +http://yp.gates96.com/6/8/33/42.html +http://yp.gates96.com/6/8/33/75.html +http://yp.gates96.com/6/8/34/32.html +http://yp.gates96.com/6/8/34/97.html +http://yp.gates96.com/6/8/35/53.html +http://yp.gates96.com/6/8/35/98.html +http://yp.gates96.com/6/8/36/74.html +http://yp.gates96.com/6/8/36/99.html +http://yp.gates96.com/6/8/38/92.html +http://yp.gates96.com/6/8/38/97.html +http://yp.gates96.com/6/8/39/45.html +http://yp.gates96.com/6/8/39/69.html +http://tour.stanford.edu/tour/29.0/gMlPb +http://idl.tucows.com/winme/adnload/138396_30343.html +http://idl.tucows.com/winme/adnload/138395_29743.html +http://web.singnet.com.sg/~tay7012i/family.htm +http://www.chaos.dk/sexriddle/p/f/g/j/o/ +http://lcweb2.loc.gov/ll/llnt/070/?S=A +http://lcweb2.loc.gov/ll/llnt/070/0100/ +http://www.crosswinds.net/~lucifern/ +http://pub14.ezboard.com/fblazinofdablazinestdabattledome.subscribeUnregisteredToTopic?topicID=190.topic +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/computers/lit/quizz/programs/unlambda/misc/peanuts.html +http://members.se.tripod.de/svdata/inglis/sida2.htm +http://www.fogdog.com/cedroID/ssd3040183217284/crs/hp/nav/stores/golf/ +http://198.103.152.100/search*frc/tOperations+guide+to+ZIM/toperations+guide+to+zim/-17,-1,0,E/2browse +http://herndon1.sdrdc.com/cgi-bin/com_detail/C00186353 +http://www.j2ee.com/products/javamail/javadocs/javax/mail/Flags.html +http://www.j2ee.com/products/javamail/javadocs/javax/mail/Header.html +http://www.intellicast.com/Sail/World/UnitedStates/FourCorners/Arizona/LakeMeadCanyon/LocalWinds/d1_18/ +http://genforum.genealogy.com/cgi-bin/print.cgi?guill::871.html +http://in.egroups.com/message/ucc-medicine/9 +http://in.egroups.com/message/ucc-medicine/14 +http://www-uk3.cricket.org/link_to_database/PLAYERS/WOMEN/AUS/WILSON_B_02011221/index.NSW-WOMEN.html +http://ftp.du.se/disk4/FreeBSD/FreeBSD-current/www/ja/releases/?M=A +http://www.citythek.de/koeln/eduscho/fsinhalt.htm +http://198.103.152.100/search*frc/cCA1+MPY30+97C31/cca1+mpy30+97c31/-5,-1,,E/browse +http://ftp.nsysu.edu.tw/Linux/RedHat/doc/en/HOWTOS/localization/Serbian/?N=D +http://mk158.tripod.co.jp/old/praga1/do/bio.html +http://oneplace.adbureau.net/accipiter/adclick/site=ONEPLACE/area=INDEX/POSITION=FOOTER/AAMSZ=468x60/ACC_RANDOM=449975866078 +http://members.tripod.co.jp/Primrose/honeydcolumn3.html +http://911codes.com/games/platform/n64/sect/div/cont/list_cheat/spray/y/id/0000009564/gid/0000003291/_cheats/_walkthroughs/_codes/_pc/_n64/_psx/_gameboy/_playstation/ +http://iqseek.shop.goto.com/compperiph/monfol/mon/search/detail.jhtml?MANUF=ViewSonic&MODEL=E790 +http://iqseek.shop.goto.com/compperiph/monfol/mon/search/detail.jhtml?MANUF=ViewSonic&MODEL=GA655 +http://plat.debian.or.jp/debian/dists/stable/main/binary-powerpc/shells/?M=A +http://retailer.gocollect.com/do/session/1912686/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/shipping_policy.asp +http://vvv.geocities.co.jp/Playtown-Yoyo/5287/ +http://vvv.geocities.co.jp/Playtown-Yoyo/5714/ +http://vvv.geocities.co.jp/Playtown-Yoyo/5750/ +http://genforum.genealogy.com/cgi-genforum/forums/charpia.cgi?3 +http://www.amateurplatinum.com/tubal-ligationmilk/plus-sizecoushin-for-the-pushin/best-friendsjail-bait/vietnamese/ac/dclubrication/bisexualelbow-grease.html +http://library.bangor.ac.uk/search/tContemporary+psychology+series/tcontemporary+psychology+series/-17,-1,0,B/2exact&F=tcontemporary+problems+in+geography&1,4 +http://www-d0.fnal.gov/cgi-bin/cvsweb.cgi/calreco/VERSION?only_with_tag=p05-br +http://www.158china.com/news/2000/08/21/52747.htm +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx031009.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx031106.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx031208.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx031507.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx032406.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx032902.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx041501.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx041611.txt +http://www.ln.cei.gov.cn/dh/hgjj/wscf/hx/hx1.txt +http://wuarchive.wustl.edu/edu/math/software/multi-platform/SLATEC/G/G2/G2H/G2H2/sbols/ +http://www.loststars.net/story4/ab200-2.html +http://www.indian-express.com/ie/daily/19981219/35350564.html +http://www.indian-express.com/ie/daily/19981219/35351234.html +http://www.homestead.com/jennyb/pets.html +http://www.allgemeine-immobilien-boerse.de/kanada/verkauf/Gemeinsam/Inserieren/Allgemeine-IB/Versteigerungen-IB/Startseite/Gemeinsam/suche.htm +http://www.sankei.co.jp/databox/paper/9808/06/paper/today/sports/soccer/06soc002.htm +http://rex.skyline.net/navigate.cgi?history,collectibles,recreation,sculpture,arts +http://tjohoo.se/sport/snowboard/2.php3 +http://www.du-et.net/prof/n/nkaworu.html +http://www.iwon.com/home/movies/movies_summary_page/0,13160,383543,00.html +http://www.iwon.com/home/movies/movies_summary_page/0,13160,481885,00.html +http://www.iwon.com/home/movies/movies_summary_page/0,13160,372508,00.html +http://pub13.ezboard.com/fvisualbasicexplorergettingstarted.emailToFriend?topicID=861.topic +http://www.fogdog.com/cedroID/ssd3040183158417/customer_service/ +http://www.fogdog.com/cedroID/ssd3040183158417/cgi-bin/CedroCommerce?func=EditBasket +http://www.fogdog.com/cedroID/ssd3040183158417/nav/products/cycling/1y/software/ +http://www.niwl.se/wais/new/28/28189.htm +http://retailer.gocollect.com/do/session/1912674/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://www.trax.nilex.co.uk/trax.cgi/A1C/A2R/A2U/B3R/A1U/Resign/ +http://www.sofitware.com/books/sci05/0471969664.html +http://www.genome.wustl.edu:8021/gsc1/est/zebrafish_reports/old_rank_reports/zebrafish.rank.990322 +http://www.genome.wustl.edu:8021/gsc1/est/zebrafish_reports/old_rank_reports/zebrafish.rank.991004 +http://www.farhi.org/ps01/ps01_015.htm +http://www-usa10.cricket.org/link_to_database/ARCHIVE/WORLD_CUPS/WC99/STATS/BY_TEAM/SL/WC99_BOWL_BEST_INNS_SR_SL.html +http://www.online.kokusai.co.jp/Stock_corner/V0043480/wrd/G500/stock_corner/stock_corner.html +http://www.online.kokusai.co.jp/Mmf_corner/V0043480/mmf_corner/mmf_corner/url +http://mediate.magicbutton.net/do/session/625604/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-cust.html +http://www.malaysia.net/lists/sangkancil/1999-05/frm00449.html +http://www.bigstar.com/contest/index.cfm/4ae093fg371d8ddg3?fa=contest +http://www.bigstar.com/tv/index.cfm/4ae093fg371d8ddg3 +http://linux.tucows.dia.dk/gnomehtml/adnload/49933_5879.html +http://dc.web.aol.com/roanoke/health/directories.dci?type=professionals +http://dc.web.aol.com/roanoke/health/categories.dci?category=fitnessdiet +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux/drivers/isdn/icn/Makefile?only_with_tag=davem-cvs-merge +http://dennou-h.gfd-dennou.org/arch/cc-env.old/db/?M=A +http://www.envy.nu/wildcats/gare.html +http://www.envy.nu/wildcats/horst.html +http://www.linux.com/networking/network/release/performance/updates/Netscape/ +http://ftpsearch.belnet.be/pub/os/linux/Linux-sunsite.unc/distributions/ultra/Users-Guide/?S=A +http://www.chaos.dk/sexriddle/n/f/p/g/a/ +http://pub24.ezboard.com/fphilosophersstonefrm7.showAddTopicScreenFromWeb +http://pub24.ezboard.com/fphilosophersstonefrm7.showMessage?topicID=10.topic +http://www.yorosiku.net:8080/-_-http://www2.biglobe.ne.jp/~animenet/jan222/note/bbs2.html +http://www.web-chart.com/Detail.htm?s=2568&c=229 +http://www.brio.de/BRIO.catalog/39fe2f5009021d362740d472aa780645/UserTemplate/8 +http://www.service911.com/egghead/step/0,2743,10+55+157+24348+17295_2,00.html +http://home.pchome.com.tw/computer/judy7777/fast-7.htm +http://big5.peopledaily.com.cn/zdxw/11/20000126/200001261111.html +http://www.nhic.or.kr/netbbs/Bbs.cgi/nhic31792/lst/qqo/012D +http://sunsite.org.uk/public/usenet/news-faqs/alt.answers/paranormal/faq +http://newsone.net/nnr/listl/alt.bbs.elebbs/1 +http://ourworld.compuserve.com/homepages/hallg/mg_vor.htm +http://www.world001.com/forum/yue/1573.html +http://www.greenleaves.com/bookcat/gb_1567112730.html +http://quotidiano.monrif.net/chan/motori:1119539:/2000/10/30: +http://quotidiano.monrif.net/chan/motori:926303:/2000/10/30: +http://quotidiano.monrif.net/chan/motori:944719:/2000/10/30: +http://home.online.tj.cn/~madgoe/subtitle/nt/nt363.htm +http://home.online.tj.cn/~madgoe/subtitle/nt/nt352.htm +http://home.online.tj.cn/~madgoe/subtitle/nt/nt343.htm +http://home.online.tj.cn/~madgoe/subtitle/nt/nt327.htm +http://home.online.tj.cn/~madgoe/subtitle/nt/nt320.htm +http://www.collectingnation.com/cgi-bin/bn/request_email.mod?EHANDLE=Vincze +http://www.beanienation.com/cgi-bin/bn/view_feedback.mod?HANDLE=ving +http://www.collectingnation.com/cgi-bin/bn/request_email.mod?EHANDLE=Vinrye +http://www.collectingnation.com/cgi-bin/bn/request_email.mod?EHANDLE=Vinzy +http://www.beanienation.com/cgi-bin/bn/view_feedback.mod?HANDLE=violinist +http://www.beanienation.com/cgi-bin/bn/view_feedback.mod?HANDLE=Violin +http://www.collectingnation.com/cgi-bin/bn/request_email.mod?EHANDLE=vione +http://www.beanienation.com/cgi-bin/bn/view_feedback.mod?HANDLE=viper0669 +http://www.missouri.edu/HyperNews/get/writery/poetry/1.html?embed=-1 +http://www.missouri.edu/HyperNews/get/writery/poetry/6.html?outline=1&embed=1 +http://www.missouri.edu/HyperNews/get/writery/poetry/9.html?outline=-1&embed=1 +http://www.missouri.edu/HyperNews/get/writery/poetry/20.html?outline=3&embed=1 +http://www.missouri.edu/HyperNews/get/writery/poetry/21.html?outline=-1&embed=1 +http://www.missouri.edu/HyperNews/get/writery/poetry/23.html?outline=1&embed=1 +http://www.missouri.edu/HyperNews/get/writery/poetry/38.html?outline=1&embed=1 +http://fi.egroups.com/messages/Avon3DayBoston/5 +http://www.online.kokusai.co.jp/Demo/V0043481/wrd/G400/demo/ +http://www.jamba.de/KNet/_KNet-TQt8j1-PEd-139qr/showInfo-werbung.de/node.0/cde7f1uou +http://computalynx.tucows.com/winnt/adnload/73435_29524.html +http://www.intellicast.com/Golf/World/UnitedStates/Northwest/Oregon/OregonDunes/THUNDERcast/d2_06/ +http://202.105.55.146/h0/news/200009/20/jty7.htm +http://pda.tucows.edisontel.com/newton/newtsfiction_size.html +http://pda.tucows.edisontel.com/newton/adnload/33238_19961.html +http://hem.fyristorg.com/lottaleman/LLfar/1_2942.htm +http://www.norrblom.com/..\hund\1996\s2665496.htm +http://www.ferien-immobilien.de/niedersachsen/weserbergland/Verkauf/Gemeinsam/MarketingStrategie/Allgemeine-IB/Gemeinsam/Super-Zins-Konditionen/Private-IB/Startseite/Default.htm +http://nathanael.upi.jussieu.fr/tele6.nsf/autres+centres+de+formations!OpenPage&ExpandSection=14,18,11,9,15,8 +http://dennou-h.gfd-dennou.org/arch/cc-env.old/xtop/TEBIKI.top.rs590 +http://www.amzn.com/exec/obidos/search-handle-url/index=vhs&field-director=Jim%20Stenstrum/ +http://www.amzn.com/exec/obidos/tg/browse/-/169237/ +http://www.flora.org/flora.oclug/old-6088 +http://www.msn.expedia.co.uk/wg/Images/P24601.htm +http://www.asahi-net.or.jp/~ei2h-kdu/photos/rail/sanin/amarube3.html +http://au.yahoo.com/Business_and_Economy/Shopping_and_Services/Health/Providers/By_Region/U_S__States/Montana/Complete_List/ +http://www.staroriental.net/nav/soeg/ihf,aai,n2,118,Electric+Wave+Girl+1998.html +http://www.hig.se/(accessed,formoutput,referrer,smallcaps,sqlquery)/~jackson/roxen/ +http://carefinder.digitalcity.com/fargond/sports/team.dci?league=NF2&team=VAC +http://carefinder.digitalcity.com/fargond/sports/team.dci?league=NF2&team=GAA +http://carefinder.digitalcity.com/fargond/sports/team.dci?league=NF2&team=AAB +http://carefinder.digitalcity.com/fargond/sports/team.dci?league=NF2&team=AAF +http://newnova.tucows.com/preview/60922.html +http://www-d0.fnal.gov/d0dist/dist/releases/test/l3fsmtcluster/rcp/?S=A +http://www.cs.rit.edu/~ats/inferno/man/html/proto8.htm +http://dandini.cranfield.ac.uk/vl=-39835473/cl=140/nw=1/rpsv/cw/web/nw1/browse.htm +http://homepage.mac.com/nanameneko/job/architecture-oriented/OHP/Why/why_05.html +http://ftp.sunet.se/pub/FreeBSD/FreeBSD-current/ports/games/CaribbeanStud/?M=A +http://ftp.sunet.se/pub/FreeBSD/FreeBSD-current/ports/games/CaribbeanStud/distinfo +http://ads3.zdnet.com/c/g=r734&c=a53975&idx=2000.10.30.21.30.24/www.zdnet.com/downloads/stories/info/0,,000FDG,.html +http://yp.gates96.com/6/57/80/89.html +http://yp.gates96.com/6/57/81/42.html +http://yp.gates96.com/6/57/81/66.html +http://yp.gates96.com/6/57/82/16.html +http://yp.gates96.com/6/57/82/61.html +http://yp.gates96.com/6/57/83/37.html +http://yp.gates96.com/6/57/83/54.html +http://yp.gates96.com/6/57/84/14.html +http://yp.gates96.com/6/57/85/7.html +http://yp.gates96.com/6/57/85/24.html +http://yp.gates96.com/6/57/85/35.html +http://yp.gates96.com/6/57/85/64.html +http://yp.gates96.com/6/57/86/80.html +http://yp.gates96.com/6/57/86/96.html +http://yp.gates96.com/6/57/87/15.html +http://yp.gates96.com/6/57/89/2.html +http://yp.gates96.com/6/57/89/95.html +http://www.oncology.com/v2_MainFrame/1,1614,_12|00332|00_21|002|00_04|0039|00_38|00188,00.html +http://library.bangor.ac.uk/search/aEllis,+Gail/aellis+gail/-5,-1,0,B/exact&F=aellis+griffith+1844+1913&1,9 +http://www.rezel.enst.fr/ftp/linux/distributions/debian/CD-2/debian/dists/unstable/contrib/source/mail/?S=A +http://itcareers.careercast.com/texis/it/itjs/+SwwBmeYKD86e8hwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewhPndhBiwGna5O5BnManDtoDnnGamn5otDamnVncdpaGnwcaBoMnaoDhdGMwBodDaDnBidGAanLpnGonDqnaMFqhTfR20Dzme4twwwpBmex_D86ejxwww5rme6dwwwBrmeZpwww/morelike.html +http://esatnet.tucows.com/winnt/adnload/31316_29136.html +http://home.c2i.net/w-225961/steinare/brosjyre.htm +http://aleph.tau.ac.il:4500/ALEPH/ENG/ATA/AAS/AAS/FIND-ACC/0860271 +http://www.chaos.dk/sexriddle/v/c/w/d/r/ +http://www9.hmv.co.uk:5555/do/session/1347760/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d135_sd0_pt0.html +http://tagesanzeiger.ch/archiv/99november/991122/79295.HTM +http://www.pacifictech.com.cn/pcsoftware/sj/jq/00803.htm +http://www.pacifictech.com.cn/pcsoftware/sj/jq/00430b.htm +http://www.pacifictech.com.cn/pcsoftware/zl/syjq/dmtgj/old/tuxing/3d/20000131.html +http://www.building.com/communities/texis/db/go/+DexVFdeKmYnwrmwxerJOwrmwx3exmww/profile.html +http://my.egroups.com/message/mathies/43?source=1 +http://www.brio.de/BRIO.catalog/39fe2f5706df064c273fd472aa78067c/UserTemplate/6 +http://www.brio.de/BRIO.catalog/39fe2f5706df064c273fd472aa78067c/UserTemplate/9 +http://www.egroups.com/messages/GollyBeenz/44 +http://www.buybuddy.com/sleuth/15/1/1020507/495848/ +http://www.brio.de/BRIO.catalog/39fe2f41010c308a2742d472aa7806a7/UserTemplate/5 +http://www.ferien-immobilien.de/hessen/bad-hersfeld/Verkauf/IIM-Teil/Startseite/Private-IB/Allgemeine-IB/Gemeinsam/versicherungen/gebaeude/deckungsumfang.htm +http://www.ferien-immobilien.de/hessen/bad-hersfeld/Verkauf/IIM-Teil/Startseite/Private-IB/Allgemeine-IB/Gemeinsam/impressum.htm +http://beetle.marion.ohio-state.edu/Bratt2000/D0029/I10769.html +http://members.tripod.lycos.co.kr/RAINBOR/?D=A +http://www.eos.ncsu.edu/eos/info/bae/bae324_info/ +http://www.chez.com/mousis/vg/aqui/pages/0006.htm +http://search.chollian.net/cgi-bin/filter.cgi?cid=2052&p=1 +http://channel.nytimes.com/1998/03/15/technology/cybertimes/eurobytes/ +http://www4.nas.edu/ohr.nsf/All+Documents/Major+Units?OpenDocument&ExpandSection=13,4,2,7,11 +http://uk.dir.yahoo.com/Regional/Countries/Mexico/States/Baja_California/Cities/Ensenada/Travel_and_Transportation/Accommodation/Caravan_Parks_and_Campgrounds/ +http://ring.toyama-ix.net/archives/mac/info-mac/inet/_Mail/_Eudora/ +http://sport.voila.fr/it/calcio/euro2000/teams/por/squad/nunogomes.html +http://idefix-41.cs.kuleuven.ac.be/~henk/DPS/ +http://library.bangor.ac.uk/search/dLaw+--+Study+and+teaching+--+Great+Britain/dlaw+study+and+teaching+great+britain/-5,-1,0,B/buttonframe&F=dlaw+study+and+teaching+great+britain&7,,7 +http://www.eveclub.com/cgi-bin/eveclub.front/972959440822/Catalog/1000002 +http://www.eveclub.com/cgi-bin/eveclub.front/972959440822/Catalog/1000062 +http://ring.shibaura-it.ac.jp/archives/FreeBSD-PC98/dists/4.0-RELEASE/XF86336/PC98-Servers/?N=D +http://www.uq.edu.au/site-index/index.phtml?site_tree_data=1,91,95,203,338,344,2,6,182,148 +http://www.uq.edu.au/site-index/index.phtml?site_tree_data=1,91,95,203,338,344,2,6,182,163 +http://www.xmission.com/(apocalypse,art,caffiene,geek,misc,music,music,caffiene,art,toys,dots,edge,misc,shopping,ftp,places,privacy,geek,cuseeme,apocalypse,people,stuffiuse,people,places,shopping,stuffiuse,toys)/~bill/links.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=confinarias&l=pt +http://www.xmission.com/(apocalypse,art,caffiene,cuseeme,geek,misc,music,music,caffiene,art,toys,dots,edge,misc,shopping,ftp,places,privacy,geek,cuseeme,apocalypse,people,stuffiuse,places,privacy,stuffiuse,toys)/~bill/links.html +http://www.gigclub.co.jp/tanigawa/tanigawa/980915/menu.html +http://www.3w-sciencefiction.de/SmithWilliamK/SmithWilliamK0126528756.htm +http://w3c1.inria.fr/Mobile/posdep/Presentations/Mogid/sld014.htm +http://members.tripod.co.jp/view_i/p.html +http://202.99.23.245/zdxw/11/20000317/200003171117.html +http://www.jpc-music.com/7334085.htm +http://library.bangor.ac.uk/search/aLibrary+Association/alibrary+association/-5,-1,0,B/buttonframe&F=alibrary+association&2,,64 +http://www.sf.digitalcity.com/puntagordafl/sports/team.dci?league=FSL&team=CHA +http://www.sf.digitalcity.com/puntagordafl/sports/team.dci?league=FSL&team=LAK +http://brain.brent.gov.uk/__802564ff0045d739.nsf/vWebAllPagesByLocsSrvd!OpenView&Start=33&Count=60&Collapse=45 +http://www.nypost.com/news/933.htm +http://www.nypost.com/business/979.htm +http://www.nypost.com/living/951.htm +http://www.computer-networking.de/studenten/cn_intern/bauer/jobst/k07-graphik-gui/controls/swing/ +http://194.55.30.33/albanian/tema_gjermane/67823.html +http://194.55.30.33/albanian/tema_gjermane/65962.html +http://yp.gates96.com/14/85/10/12.html +http://yp.gates96.com/14/85/11/98.html +http://yp.gates96.com/14/85/12/24.html +http://yp.gates96.com/14/85/13/57.html +http://yp.gates96.com/14/85/14/92.html +http://yp.gates96.com/14/85/16/37.html +http://yp.gates96.com/14/85/16/51.html +http://yp.gates96.com/14/85/16/78.html +http://yp.gates96.com/14/85/17/38.html +http://yp.gates96.com/14/85/17/48.html +http://yp.gates96.com/14/85/17/91.html +http://yp.gates96.com/14/85/19/35.html +http://yp.gates96.com/14/85/19/88.html +http://genforum.genealogy.com/cgi-genforum/forums/deppen.cgi?3 +http://www.ferien-immobilien.de/nordrhein-Westfalen/Muehlheim-ruhr/Verkauf/Private-IB/Startseite/Gemeinsam/Inserieren/Versteigerungen-IB/Startseite/Ferien-IB/Startseite/ +http://www.redrocksports.com/sports/webSession/shopper/RR972959668-31057/store/dept-5/department/dept-5/item/51800 +http://www.redrocksports.com/sports/webSession/shopper/RR972959668-31057/store/dept-5/department/dept-5/item/53510 +http://www.redrocksports.com/sports/webSession/shopper/RR972959668-31057/store/dept-5/department/dept-5/item/52600 +http://www.redrocksports.com/sports/webSession/shopper/RR972959668-31057/store/dept-5/department/dept-5/item/50510 +http://www.redrocksports.com/sports/webSession/shopper/RR972959668-31057/store/dept-5/department/dept-5/item/50400 +http://polygraph.ircache.net:8181/http_-2www.horizonfinance.com/http_-2www.netscape.com/download/http_-2www.microsoft.com/ie/http_-2207.91.150.20/http_-2www.updowntowner.org/julyjamm/headliners.html +http://www.ccurrents.com/magazine/national/1702/nets31702.html +http://adept.subportal.com/sn/Themes/Vehicle_Themes/5090.html +http://www.fogdog.com/cedroID/ssd3040183211390/nav/products/outlet/1a/fishing/ +http://www.linux.com/networking/network/communications/article/unix/sales/ +http://fyi.cnn.com/content/US/9902/25/germans.death.penalty.ap/ +http://fyi.cnn.com/US/9902/09/monk.execute.ap.02/ +http://fyi.cnn.com/WORLD/asiapcf/9902/06/PM-Philippines-DeathPena.ap/ +http://pub11.ezboard.com/ucivik.showPublicProfile +http://playboy.software.net/PKIN005896/prod.htm +http://www.linux.com/networking/network/help/free/performance/install/ +http://www.linux.com/networking/network/help/free/performance/X/ +http://se.egroups.com/message/ghost_tales/1490 +http://niteowl.userfriendly.net/linux/RPM/rawhide/1.0/i386/usr_src_linux-2.4.0_include_Tree.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=coexistissem&l=pt +http://promed.univ-rennes1.fr/cerf/ico_an/IDRE/21_HADM.HTM +http://promed.univ-rennes1.fr/cerf/ico_an/IDRE/25_HADM.HTM +http://promed.univ-rennes1.fr/cerf/ico_an/IDRE/86_HADM.HTM +http://promed.univ-rennes1.fr/cerf/ico_an/IDRE/88_HADM.HTM +http://promed.univ-rennes1.fr/cerf/ico_an/IDRE/90_HADM.HTM +http://promed.univ-rennes1.fr/cerf/ico_an/IDRE/HADM6.HTM +http://www.estrelladigital.es/000814/articulos/economia/correos.htm +http://itcareers.careercast.com/texis/it/itjs/+awwBme4CD86LxwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewPPnBwpcnaqdGpdGwBnaoDhdGMwBodDahoDma5BdGnaq15BdMnGa5nGVoqnaqdDBwqBamo5BGox1BodDaMwDwtnMnDBaMFqrIRE7P0IDzme_xwwwpBmHe0B-deaqwww5rmsmwwBrme7Dwww/morelike.html +http://yp.gates96.com/3/79/50/30.html +http://yp.gates96.com/3/79/50/54.html +http://yp.gates96.com/3/79/51/1.html +http://yp.gates96.com/3/79/51/11.html +http://yp.gates96.com/3/79/51/80.html +http://yp.gates96.com/3/79/52/27.html +http://yp.gates96.com/3/79/52/81.html +http://yp.gates96.com/3/79/53/81.html +http://yp.gates96.com/3/79/54/0.html +http://yp.gates96.com/3/79/54/31.html +http://yp.gates96.com/3/79/55/74.html +http://yp.gates96.com/3/79/55/78.html +http://yp.gates96.com/3/79/56/72.html +http://yp.gates96.com/3/79/57/0.html +http://yp.gates96.com/3/79/58/27.html +http://yp.gates96.com/3/79/58/31.html +http://yp.gates96.com/3/79/58/48.html +http://yp.gates96.com/3/79/58/76.html +http://yp.gates96.com/3/79/58/99.html +http://yp.gates96.com/3/79/59/27.html +http://yp.gates96.com/3/79/59/32.html +http://yp.gates96.com/3/79/59/49.html +http://yp.gates96.com/3/79/59/81.html +http://yp.gates96.com/3/79/59/83.html +http://startribune.atevo.com/misc/print_article/0,3869,4504302,00.html +http://browse.carnaby.com/home/showcase/6/381/2078/A0638120780000EA01.html +http://www.checkout.com/music/earmail/form/1,7650,325272-1761567,00.html +http://ring.shibaura-it.ac.jp/archives/doc/jpnic/minutes/committee/200007/shiryou-4-1.txt +http://www.secinfo.com/d1ZMQs.51h.htm +http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/AtlantisPBEM/CVSROOT/modules?only_with_tag=MAIN +http://cvs.sourceforge.net/cgi-bin/cvsweb.cgi/AtlantisPBEM/CVSROOT/modules?only_with_tag=HEAD +http://ftp.bitcon.no/tucows/adnload/4961_28325.html +http://yp.gates96.com/3/37/0/21.html +http://yp.gates96.com/3/37/0/29.html +http://yp.gates96.com/3/37/0/80.html +http://yp.gates96.com/3/37/0/87.html +http://yp.gates96.com/3/37/1/9.html +http://yp.gates96.com/3/37/2/83.html +http://yp.gates96.com/3/37/2/92.html +http://yp.gates96.com/3/37/3/26.html +http://yp.gates96.com/3/37/4/9.html +http://yp.gates96.com/3/37/4/29.html +http://yp.gates96.com/3/37/5/31.html +http://yp.gates96.com/3/37/5/49.html +http://yp.gates96.com/3/37/5/51.html +http://yp.gates96.com/3/37/5/63.html +http://yp.gates96.com/3/37/5/95.html +http://yp.gates96.com/3/37/6/0.html +http://yp.gates96.com/3/37/6/4.html +http://yp.gates96.com/3/37/7/22.html +http://yp.gates96.com/3/37/8/10.html +http://yp.gates96.com/3/37/8/50.html +http://yp.gates96.com/3/37/8/92.html +http://yp.gates96.com/3/37/9/46.html +http://ftp.digex.net/debian/dists/woody/contrib/binary-sh/libs/?N=D +http://students.lsu.edu/students/main.nsf/c81d2bf8cb0b80ff862566fb00105ab2/7f3436ae9cb1268886256773006f9288!OpenDocument&ExpandSection=4,15,12,16 +http://in.egroups.com/group/bbw-uk +http://home.swipnet.se/~w-20817/ +http://shop.puretec.de/kunden/19867293/detailansicht_Aku1025B.html +http://www.rezeptkoch.de/Rezepte/Heimisches_/Gemuse/Sommerliche_Gemusegerichte/sommerliche_gemusegerichte_2.html +http://www.rezeptkoch.de/Rezepte/Heimisches_/Gemuse/Kohl/kohl_4.html +http://www.rezeptkoch.de/Rezepte/Heimisches_/Gemuse/Kohl/kohl_11.html +http://www.chinainvest.com.cn/C/Showdetail/20359.html +http://tucows.sp-plus.nl/winme/preview/141310.html +http://www.al-hujjat.grid9.net/gnomehtml/ent_enhance_rating.html +http://www.warmbloods.net/breeding/_vti_bin/shtml.dll/disc123_post.htm?1260 +http://ftp.sunet.se/pub/FreeBSD/FreeBSD-current/ports/net/ruby-snmp/Makefile +http://basil.cs.uwp.edu/Documentation/java/jdk/docs/guide/sound/prog_guide/chapter3.fm.html +http://tucows.1web.it/winme/preview/75525.html +http://uk-wire.ukinvest.com/articles/200009180701200586R.html +http://www.ozon.ru/detail.cfm/ent=33&id=953&add2navigator=1&txt=1 +http://cometweb01.comet.co.uk/do!session=131984&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkkHbqpLZXmLbkZHljlKaltLkilLXalKfkaLbukKeqjLi1 +http://community.webshots.com/photo/3922869/3923445TSuTSQIWpD +http://www.eveclub.com/cgi-bin/eveclub.front/972959447434/Catalog/1000040 +http://www.tvstore.com/browse/TV/NIGHTSHI/s.nXZNPRgQ +http://www.tvstore.com/browse/TV/COMIC/s.nXZNPRgQ +http://www.xmwb.sh.cn/xmwb/19981016/GB/13389^8101623.htm +http://helios.nlib.ee/search*est/tThe+threshold+series/tthreshold+series/-5,-1,0,B/frameset&F=tthrillers&1,1 +http://www4.nas.edu/ohr.nsf/All+Documents/Major+Units?OpenDocument&ExpandSection=23,9,7,18 +http://ftp.bitcon.no/pub/windowsce/epoc/desktop5.htm +http://ftp.lip6.fr/pub2/sgml-tools/website/HOWTO/Multicast-HOWTO/t1595.html +http://ftp.rge.com/pub/X/XFree86/3.3.3.1/untarred/xc/programs/Xserver/ +http://ftp.rge.com/pub/X/XFree86/3.3.3.1/untarred/xc/programs/xwud/ +http://syix.tucows.com/win2k/adnload/73370_29328.html +http://yp.gates96.com/0/54/80/40.html +http://yp.gates96.com/0/54/80/56.html +http://yp.gates96.com/0/54/80/61.html +http://yp.gates96.com/0/54/80/79.html +http://yp.gates96.com/0/54/81/11.html +http://yp.gates96.com/0/54/81/25.html +http://yp.gates96.com/0/54/81/58.html +http://yp.gates96.com/0/54/82/48.html +http://yp.gates96.com/0/54/82/75.html +http://yp.gates96.com/0/54/83/0.html +http://yp.gates96.com/0/54/84/12.html +http://yp.gates96.com/0/54/84/67.html +http://yp.gates96.com/0/54/85/47.html +http://yp.gates96.com/0/54/85/59.html +http://yp.gates96.com/0/54/86/52.html +http://yp.gates96.com/0/54/86/55.html +http://yp.gates96.com/0/54/86/79.html +http://yp.gates96.com/0/54/86/87.html +http://yp.gates96.com/0/54/87/12.html +http://yp.gates96.com/0/54/87/81.html +http://yp.gates96.com/0/54/88/97.html +http://yp.gates96.com/0/54/89/90.html +http://www.yorosiku.net:8080/-_-http://liinwww.ira.uka.de/bibliography/Distributed/SIGCOMM.94.html +http://news.pchome.com.tw/ftv/health/20000915/ +http://www.emis.de/journals/EJDE/Volumes/Volumes/Monographs/1998/05/?N=D +http://travelocity-dest.excite.com/DestGuides/0,1840,TRAVELOCITY|5706|3|1|159040|photo_id|4022,00.html +http://travelocity-dest.excite.com/DestGuides/0,1840,TRAVELOCITY|5706|3|1|159040|photo_id|4020,00.html +http://lhcbsoft.web.cern.ch/LHCbSoft/simmuon/v1/mgr/CVS/Root +http://tucows.soneraplaza.nl/winme/adnload/137454_28942.html +http://www.borland.nl/techpubs/jbuilder/jbuilder3/ui/wclass.html +http://fi.egroups.com/links/dssf +http://www.homestead.com/jcv2000/MBoard.html +http://careershop.resumeshotgun.com/directory/italy/sardegna/o.10.p.4408.html +http://www.hantsnet.co.uk/istcclr/cch32751.html +http://www.hantsnet.co.uk/istcclr/cch16729.html +http://www.hantsnet.co.uk/istcclr/cch03788.html +http://www.hantsnet.co.uk/istcclr/cch05491.html +http://www.hantsnet.co.uk/istcclr/cchr0418.html +http://www.hantsnet.co.uk/istcclr/cchh2289.html +http://www.hantsnet.co.uk/istcclr/cchh2074.html +http://www.hantsnet.co.uk/istcclr/cch30426.html +http://www.hantsnet.co.uk/istcclr/cch11726.html +http://www.hantsnet.co.uk/istcclr/cch03858.html +http://www.hantsnet.co.uk/istcclr/cche0920.html +http://www.hantsnet.co.uk/istcclr/cch34768.html +http://www.hantsnet.co.uk/istcclr/cchc2067.html +http://www.hantsnet.co.uk/istcclr/cche1085.html +http://www.v2music.com/Scripts/WebObjects-ISAPI.dll/V2_New_Publisher.woa/53771000000443000000339400000065451/v2tvindex.wo/614720000055451/1.14/3/Webobjects1 +http://www.sternonline.de/magazin/fotogalerie/hinz/index5.html +http://www.envy.nu/Sing.html +http://employment.subportal.com/sn/Themes/ +http://www.diogenes.ch/4DACTION/web_rd_aut_prview/a_id=7002120&area=&ID=483332 +http://wlink.tucows.com/winme/adnload/137847_29260.html +http://tucows.computalynx.net/winnt/adnload/71633_28766.html +http://ftp.up.pt/Linux/debian/dists/stable/main/disks-m68k/?M=A +http://lcweb2.loc.gov/ll/llnt/009/0000/ +http://www.magma.ca/~denisd/africa/day02.html +http://www.magma.ca/~denisd/africa/day16.html +http://content.health.msn.com/message_board_author/802072 +http://ep.com/js/about/c0/189455 +http://ep.com/js/about/c0/154005 +http://www.realbig.com/miata/miata/1999-12/2340.html +http://www.multimap.com/wi/33738.htm +http://www.multimap.com/wi/148724.htm +http://www.bemi-immobilien.de/Landhaus-Bordeaux/Gemeinsam/3d-service/Gemeinsam/versicherungen/lebensversicherung/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/versicherungen/lebensversicherung/Gemeinsam/MarketingStrategie/Strategie.htm +http://link.fastpartner.com/do/session/600347/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/create/learn.htm +http://pub16.ezboard.com/fisnforumsfrm16.subscribeUnregisteredToTopic?topicID=731.topic +http://freesoftware.subportal.com/sn/Business/Application_Add-ins/726.html +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/ports/deskutils/genius/files/?sortby=date +http://www.madein.nnov.ru/stat/index.phtml?cid=418&t=3 +http://citeseer.nj.nec.com/correct/294145 +http://www.phillips.semiconductors.com/pip/PCF5001H +http://www.tvstore.com/browse/TV/BANK/s.Vaphccqs +http://www.tvstore.com/browse/TV/SCRIPT/s.Vaphccqs +http://www.tvstore.com/aboutus/s.Vaphccqs +http://www.fogdog.com/cedroID/ssd3040183205929/nav/products/featured_brands/3b/arm_warmers/ +http://orders.mkn.co.uk/bear/steiff/classic/order/now.en$NOK?what-e=1 +http://www.crutchfield.com/S-jtpRS1P7vRY/help/ +http://www06.u-page.so-net.ne.jp/tb3/y-miyu/azure/kodatour.htm +http://ftp.sunet.se/pub/FreeBSD/ports/ports-stable/japanese/escpf/distinfo +http://no.egroups.com/subscribe/Theater_plays +http://www.equipe.fr/Football/FootballFicheJoueur8954_0.html +http://www.equipe.fr/Football/FootballFicheJoueur6039_0.html +http://www.pmdc.org.uk/dogsdb/p00/P00133.HTM +http://ip.tosp.co.jp/i.asp?i=nononatti3 +http://tucows.wlink.com.np/adnload/144221_48889.html +http://store.yahoo.co.jp/I/naturum_1590_147867488 +http://providenet.office.tucows.com/adnload/77414_41755.html +http://providenet.office.tucows.com/adnload/73011_41097.html +http://www.goldersgreen.londonengland.co.uk/medicalequipmentrentalandleasing.htm +http://www.online.kokusai.co.jp/Mmf_corner/V0043462/mmf_corner/mmf_corner/url +http://www.qth.net/archive/packrats/200008/20000804.html +http://www.expage.com/buffykat11nelly +http://dk.egroups.com/login.cgi?login_target=%2Fmessages%2Fbbs_people +http://dk.egroups.com/message/bbs_people/23 +http://www.linux.com/networking/network/technology/free/development/learning/ +http://www.chaos.dk/sexriddle/r/x/z/t/l/ +http://www.opensecrets.org/lobbyists/98profiles/5918.htm +http://www.cbs.sportsline.com/u/football/nfl/kids/players/3418.htm +http://www.cbs.sportsline.com/u/football/nfl/kids/players/3868.htm +http://www.cbs.sportsline.com/u/football/nfl/kids/players/133268.htm +http://www.hig.se/(apre,clientname,countdown,language,set_cookie)/~jackson/roxen/ +http://www.platogmbh.de/plato/home.nsf/c81870434660ba41c125652a0029a47a/fb7566ed772f8580c12566f00036ac59!OpenDocument&ExpandSection=4,8,11,12 +http://www.fogdog.com/cedroID/ssd3040183211315/nav/products/featured_brands/2m/kick_sprint_boards/ +http://www.iabusnet.org:90/forums/aca-1/dispatch.exe/survey/folderFrame/100001/0/alpha/2458960 +http://www.jamba.de/KNet/_KNet-ONt8j1-NEd-139p9/showInfo-jobs.de/node.0/cde7f1uou +http://www.jamba.de/KNet/_KNet-ONt8j1-NEd-139pf/browse.de/node.0/cdzqggtyb +http://iland.tucows.com/win2k/adnload/38318_29882.html +http://builder.hw.net/frmRestDir/0,1112,'1~21~325~1~S~020060~04880',00.html +http://builder.hw.net/frmRestDir/0,1112,'1~21~325~1~S~020060~35840',00.html +http://builder.hw.net/frmRestDir/0,1112,'1~21~325~1~S~020060~90237',00.html +http://sunsite.org.uk/public/usenet/news.answers/alt.answers/self-impr-faq/part1 +http://ftp.bitcon.no/pub/simtelnet/win95/fileutl/?S=A +http://totalsports.aol.com/stats/bbo/mlb/20000517/bal.at.ana.game.html +http://au.yahoo.com/Regional/U_S__States/Virginia/Counties_and_Regions/Henrico_County/Business_and_Shopping/Shopping_and_Services/Travel/ +http://ftp.up.pt/Linux/debian/dists/unstable/main/binary-all/math/ +http://students.lsu.edu/students/main.nsf/c81d2bf8cb0b80ff862566fb00105ab2/7f3436ae9cb1268886256773006f9288!OpenDocument&ExpandSection=10,17,13,14 +http://ftp.sunet.se/pub/FreeBSD/ports/ports-stable/japanese/vfghostscript/Makefile +http://polygraph.ircache.net:8181/yp/User_Contribs/http_-2home.netscape.com/comprod/mirror/ +http://www.emis.de/journals/EJDE/Volumes/Monographs/Volumes/1998/26/?S=A +http://www.smartshop.com/cgi-bin/main.cgi?c=314&a=contactus +http://213.36.119.69/do/session/152986/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/BE_NL/ +http://www.outdoorwire.com/lists/dirt/200009/msg01273.html +http://chicagocow.com/top/1,1419,M-Metromix-Home-Carryout!InputReview-9757--0,00.html +http://www.lithoquoter.com/Scripts/WebObjects.exe/Printers.woa/659920000022582000008720100000129302/main.wo/9193100000029302/4/-/prime +http://groups.haas.berkeley.edu/hcs/Docs/SASv8/sasdoc/sashtml/proc/z0292493.htm +http://groups.haas.berkeley.edu/hcs/Docs/SASv8/sasdoc/sashtml/proc/z0292495.htm +http://groups.haas.berkeley.edu/hcs/Docs/SASv8/sasdoc/sashtml/proc/z0292496.htm +http://www.outpersonals.com/cgi-bin/w3com/pws/out/jlhIVflnBPgWmpC4eFAjXlk3QXcFhcK-b9D_cbZyHLtTP5aigpMrgot7TKiIhNzg8y23_mmQAn7GVTQsvALIGIvJI8RFNXRZDuyGCzJ8JFs6ysbZfjgM3ik0nyIt5yhT_ujQhRI-42lzAOeb666j +http://www.nissan.co.jp/RENAULT-DEALERS/PASSPORT/view.cgi/admission/972959588-- +http://www.intellicast.com/Golf/World/UnitedStates/MidAtlantic/Virginia/RoyalNewKentGC/LocalWinds/d1_12/ +http://gbchinese.yahoo.com/headlines/001028/sports/ycwb/ycba28c003txttyxw00102800.html +http://gbchinese.yahoo.com/headlines/001028/sports/ycwb/ycba28c004txttyxw00102800.html +http://mx.php.net/manual/hu/language.references.unset.php +http://www.cbtravelguide.com/north_america/united_states/info_2.htm?sortby=city +http://www.intellicast.com/Sail/World/UnitedStates/Northwest/Idaho/Targhee/LocalWinds/d1_03/ +http://ftp.sunet.se/pub/FreeBSD/ports/ports-current/devel/libgii/distinfo +http://biblioteca.upv.es/bib/doc/doc_fisbd/816/149599//C/1826373/0////25/S/MLTPAI +http://willsmith.sonicnet.com/events/jay_z/index_sonicnet.jhtml +http://tucows.soneraplaza.nl/winme/tucowsme_license.html +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/src/usr.sbin/fdcontrol/Makefile?only_with_tag=MAIN +http://www.kurit.com/ip/a5iu/dungeon/showsw1.html +http://www.mapion.co.jp/custom/AOL/admi/13/13118/minamisenju/3chome/index-30.html +http://yp.gates96.com/3/2/10/4.html +http://yp.gates96.com/3/2/10/19.html +http://yp.gates96.com/3/2/10/48.html +http://yp.gates96.com/3/2/10/52.html +http://yp.gates96.com/3/2/10/82.html +http://yp.gates96.com/3/2/11/10.html +http://yp.gates96.com/3/2/11/13.html +http://yp.gates96.com/3/2/13/31.html +http://yp.gates96.com/3/2/13/41.html +http://yp.gates96.com/3/2/13/43.html +http://yp.gates96.com/3/2/14/3.html +http://yp.gates96.com/3/2/14/19.html +http://yp.gates96.com/3/2/15/54.html +http://yp.gates96.com/3/2/15/72.html +http://yp.gates96.com/3/2/16/84.html +http://yp.gates96.com/3/2/17/22.html +http://yp.gates96.com/3/2/17/61.html +http://yp.gates96.com/3/2/18/1.html +http://yp.gates96.com/3/2/18/41.html +http://yp.gates96.com/3/2/18/58.html +http://yp.gates96.com/3/2/19/56.html +http://yp.gates96.com/3/2/19/79.html +http://www.stas.net/lonlywtrsoul/minesweeper/ms.html +http://ksu.freeyellow.com/ +http://www.genome.wustl.edu:8021/gsc10/est/yt/yt69/ +http://www.genome.wustl.edu:8021/gsc10/est/yt/yt82/ +http://www.winsite.com/info/pc/win95/miscutil/cutty10.exe/downltop.html +http://habenix.uni-muenster.de/Rektorat/Forschungsberichte-1997-1998/fo05bbe03.htm +http://www.jobvillage.com/channel/jobs/installation_repair/bicycle/g.3370.html +http://www.mordkommission.de/ratgeber/praxis/service/broschueren/40504/ +http://www.aelita.net/products/news/solutions/sitemap/company/library/default.htm +http://www.beanienation.com/cgi-bin/bn/view_feedback.mod?HANDLE=acejet +http://cgi1.washingtonpost.com/wp-dyn/metro/va/alexandria/ +http://www.linux.com/networking/network/applications/interface/linux/distro/ +http://www2.brent.gov.uk/bv1nsf.nsf/031d5c68638196618025664000760871/963fe55ca97ccaa5802568f900503269!OpenDocument&Start=57.3&Count=60&Expand=69 +http://www2.brent.gov.uk/bv1nsf.nsf/031d5c68638196618025664000760871/963fe55ca97ccaa5802568f900503269!OpenDocument&Start=57.3&Count=60&Expand=72 +http://www2.brent.gov.uk/bv1nsf.nsf/031d5c68638196618025664000760871/963fe55ca97ccaa5802568f900503269!OpenDocument&Start=57.3&Count=60&Expand=87 +http://genforum.genealogy.com/cgi-genforum/forums/youngs.cgi?26 +http://www.tvstore.com/browse/TV/CAP/s.IRspZRIy +http://210.178.135.1/netbbs/Bbs.cgi/nhic30592/qry/zka/B2-kB2-p/pno/0/qqo/012A/qqatt/^ +http://home.sol.no/~leskjerv/aner/12063.htm +http://pub6.ezboard.com/fwatckkeepersgeneralwatchkeeperdiscussion?page=5 +http://www.centc251.org/forums/aca-1/dispatch.cgi/hsi/folderFrame/100217/0/def/1210456 +http://ftp.sunet.se/pub/FreeBSD/ports/ports-stable/games/xosmulti/?S=A +http://opac.lib.rpi.edu/search/ddata+processing+english+language+style/7,-1,0,B/browse +http://yp.gates96.com/7/40/0/5.html +http://yp.gates96.com/7/40/0/33.html +http://yp.gates96.com/7/40/1/27.html +http://yp.gates96.com/7/40/3/25.html +http://yp.gates96.com/7/40/3/36.html +http://yp.gates96.com/7/40/4/67.html +http://yp.gates96.com/7/40/4/77.html +http://yp.gates96.com/7/40/6/28.html +http://yp.gates96.com/7/40/6/49.html +http://yp.gates96.com/7/40/6/89.html +http://yp.gates96.com/7/40/7/21.html +http://yp.gates96.com/7/40/9/24.html +http://indonesian.wunderground.com/geo/GizmoTempBigPromo/global/stations/07434.html +http://www.teenplatinum.com/barelylegal/anal-sexass/legsred-toenail-polish/swallowspit/submissiondiscipline/maledomspanking/hardcorebondage.html +http://cgi.cnnsi.com/basketball/college/women/scoreboards/aeast/2000/10/18/ +http://cgi.cnnsi.com/basketball/college/women/scoreboards/aeast/2000/10/16/ +http://bellona.itworld.com:8080/cwi/Printer_Friendly_Version/frame/0,1212,NAV63-128-1357-1367_STO48482-,00.html +http://cdrwww.who.int/fsf/ehec.pdf +http://tw.yahoo.com/Regional/Countries_and_Regions/China/Provinces__Regions_and_Municipalities/Jiangxi/Cities_and_Towns/Nanchang/Real_Estate/ +http://tw.yahoo.com/Regional/Countries_and_Regions/China/Provinces__Regions_and_Municipalities/Jiangxi/Cities_and_Towns/Nanchang/Society_and_Culture/ +http://www.camden-industrial.com/supply/webSession/shopper/CI972959657-31048/store/dept-8 +http://www.msb.malmo.se/search*swe/mQdfm/mqdfm/-5,-1,0,E/2browse +http://tagesanzeiger.ch/archiv/96september/960903/213235.htm +http://yp.gates96.com/3/7/20/3.html +http://yp.gates96.com/3/7/20/28.html +http://yp.gates96.com/3/7/20/42.html +http://yp.gates96.com/3/7/21/5.html +http://yp.gates96.com/3/7/21/61.html +http://yp.gates96.com/3/7/22/18.html +http://yp.gates96.com/3/7/22/20.html +http://yp.gates96.com/3/7/22/24.html +http://yp.gates96.com/3/7/23/33.html +http://yp.gates96.com/3/7/23/49.html +http://yp.gates96.com/3/7/23/57.html +http://yp.gates96.com/3/7/24/22.html +http://yp.gates96.com/3/7/24/23.html +http://yp.gates96.com/3/7/24/27.html +http://yp.gates96.com/3/7/24/36.html +http://yp.gates96.com/3/7/24/45.html +http://yp.gates96.com/3/7/25/98.html +http://yp.gates96.com/3/7/26/56.html +http://yp.gates96.com/3/7/26/77.html +http://yp.gates96.com/3/7/26/94.html +http://yp.gates96.com/3/7/27/10.html +http://yp.gates96.com/3/7/27/17.html +http://yp.gates96.com/3/7/27/61.html +http://yp.gates96.com/3/7/27/73.html +http://yp.gates96.com/3/7/27/81.html +http://yp.gates96.com/3/7/27/82.html +http://yp.gates96.com/3/7/27/87.html +http://yp.gates96.com/3/7/28/48.html +http://yp.gates96.com/3/7/29/1.html +http://yp.gates96.com/3/7/29/8.html +http://yp.gates96.com/3/7/29/32.html +http://www.crit.org/http://www-mel.nrlmry.navy.mil/%ff:words:(MEL-is-a-sponsored-distributed-environmental-data-access-system-which-allows-users-to-search-for-browse-and-retrieve-environmental-data-from-distributed-sources) +http://www.crit.org/http://crit.org/pub/radiks.net/jwoods/%ff:words:jwoods-radiks-net-(A-More-Graceful-Transition)-An-expanded-definition +http://shn.webmd.com/roundtable_reply/802056 +http://shn.webmd.com/roundtable_author/802056 +http://bbs.bianca.com/mforums/e/expounder/posts/2000_Jan_09/3067/3073.html +http://www.spaindustry.com/ita/geosearch/navarra/navarra/ESLAVA.html +http://www.backflip.org/members/rj2nagle/4643211 +http://www.backflip.org/members/rj2nagle/7211888 +http://www.backflip.org/members/rj2nagle/5066953 +http://www.backflip.org/members/rj2nagle/5346740 +http://www.backflip.org/members/rj2nagle/5382951 +http://www.linux.com/networking/network/performance/help/va_linux_systems/server/ +http://www.secinfo.com/d178s.ad.htm +http://www.secinfo.com/d178s.9d.htm +http://www.secinfo.com/d178s.8b.htm +http://www.secinfo.com/d178s.8y.htm +http://iceberg.adhomeworld.com/cgi-win/redirect.exe/1153874888 +http://tmxy.363.net/refer-e.htm +http://www.narodnaobroda.sk/20000210/10_007.html +http://retailer.gocollect.com/do/session/1912712/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/index.asp +http://retailer.gocollect.com/do/session/1912712/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/halloween/halloween.asp +http://www.larevista.elmundo.es/documentos/secciones/ciencia.html +http://ftpsearch.belnet.be/mirrors/ftp.isc.org/pub/usenet/control/brightnet/?M=A +http://www.5a8.com/book/zt/zpj/k/kelisidi/wanshenjie/006.htm +http://www.5a8.com/book/zt/zpj/k/kelisidi/wanshenjie/019.htm +http://www.northwoods.bigsmart.com/mall/cat_automotive.cfm?drop_menu=yes +http://www.leg.wa.gov/pub/rcw%20-%20text/title_41/chapter_004/rcw_41_04_220.txt +http://www.leg.wa.gov/pub/rcw%20-%20text/title_41/chapter_004/rcw_41_04_364.txt +http://www.leg.wa.gov/pub/rcw%20-%20text/title_41/chapter_004/rcw_41_04_400.txt +http://www.leg.wa.gov/pub/rcw%20-%20text/title_41/chapter_004/rcw_41_04_630.txt +http://bsd.tucows.mol.com/x11html/adnload/69206_8129.html +http://ldp.teihal.gr/LDP/LG/issue22/notes-mode.html +http://ldp.teihal.gr/LDP/LG/issue22/haters.html +http://members.nbci.com/design_res/software_ftp.htm +http://www.nativeamerican-jewelry.com/necklace53.htm +http://members.theglobe.com/pamile/Pamela0004.html +http://webtools.familyeducation.com/whatworks/item/front/0,2551,22-9696-7350-1099-49655,00.html +http://wwws.br-online.de/geld/boerse/970909/072001.html +http://212.31.0.37/fix98/75yil/1938.htm +http://212.31.0.37/fix98/75yil/1950.htm +http://212.31.0.37/fix98/75yil/26ekl.htm +http://212.31.0.37/fix98/75yil/28ekl.htm +http://212.31.0.37/fix98/75yil/38ekl.htm +http://212.31.0.37/fix98/75yil/67ekl.htm +http://212.31.0.37/fix98/75yil/92ekl.htm +http://212.31.0.37/fix98/75yil/15ekl.htm +http://www.insurequotes.com/wa2/71J2.html +http://cn.egroups.com/message/csreye/112 +http://ring.crl.go.jp/archives/lang/perl/CPAN/authors/id/J/JA/JARIAALTO/?D=A +http://ds.dial.pipex.com/town/drive/kch36/select/s31/ch027.html +http://ds.dial.pipex.com/town/drive/kch36/select/s31/ch056.html +http://ds.dial.pipex.com/town/drive/kch36/select/s31/ch043.html +http://202.99.23.245/huadong/199905/25/no_4.html +http://www.linux.com/networking/network/industry/training/services/business/ +http://www.writtenbyme.com/articles/849308468.shtml +http://members.tripod.com/TroupeLynx/index_m.htm +http://polygraph.ircache.net:8181/http_-2www.horizonfinance.com/https_-2www.truste.org/validate/http_-2www.ziplink.net/~ralphb/newsroom/http_-2www.travelsc.com/industry/home.html +http://ftp.bitcon.no/pub/tucows/preview/1095.html +http://ftp.bitcon.no/pub/tucows/preview/870.html +http://ftp.bitcon.no/pub/tucows/preview/144675.html +http://ftp.bitcon.no/pub/tucows/preview/144869.html +http://ftp.bitcon.no/pub/tucows/preview/31162.html +http://ftp.bitcon.no/pub/tucows/preview/7724.html +http://ftp.bitcon.no/pub/tucows/preview/2691.html +http://ftp.bitcon.no/pub/tucows/preview/72841.html +http://ftp.bitcon.no/pub/tucows/preview/72185.html +http://www.jacksonhewitt.com/ctg/cgi-bin/JacksonHewitt/company_profile/AAAksrACwAAABtvAAX +http://search.excaliburfilms.com/moviepgs/goodbadanddirty.htm?currency=NOK&stock=8377V1 +http://search.excaliburfilms.com/moviepgs/goodbadanddirty.htm?currency=FRF&stock=8377V1 +http://genforum.genealogy.com/cgi-bin/print.cgi?torian::44.html +http://retailer.gocollect.com/do/session/1912702/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/newintros.asp +http://www.retrobytes.org/classiccmp/9911/msg00941.html +http://ftp.support.compaq.com/public/dunix/v3.2d-1/dce/?S=A +http://www.collectingnation.com/cgi-bin/bn/request_email.mod?EHANDLE=CoyoteChief +http://www.collectingnation.com/cgi-bin/bn/request_email.mod?EHANDLE=cpatch +http://www.beanienation.com/cgi-bin/bn/view_feedback.mod?HANDLE=cpegasus +http://www.quzhou.gov.cn/flfg.nsf/0a043ae26eb50247002564640039f21d/483ed12afec2b31d002564ac0039427a!OpenDocument&ExpandSection=7,6,5 +http://www.luecos.de/wow/art/mu_newsc_12080.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/quizz/misc/lit/programs/simple/pages_new.html +http://library.cuhk.edu.hk/search*chi/aChen,+Hui-fen./achen+hui+fen/31,-1,0,E/frameset&F=achen+hung&4,,0 +http://www.vedomosti.spb.ru/2000/arts/spbved-82-art-2.html +http://www.vedomosti.spb.ru/2000/arts/spbved-82-art-21.html +http://www.vedomosti.spb.ru/2000/arts/spbved-82-art-45.html +http://caller-times.com/1999/june/26/today/national/2447.html +http://cafe5.daum.net/Cafe-bin/Bbs.cgi/vision20pds/lst/qqeq/1/zka/B2-kB2Np +http://www.crutchfield.com/S-q8jdM6hvouc/sales.html +http://www.crutchfield.com/S-q8jdM6hvouc/cgi-bin/Catalog.asp?sid=S-q8jdM6hvouc +http://www.crutchfield.com/S-q8jdM6hvouc/copyright.html +http://deliveryc.aftonbladet.se/puls/stockholmsguiden/presentation/0,1714,2000023149,00.html +http://deliveryc.aftonbladet.se/puls/stockholmsguiden/presentation/0,1714,2000023162,00.html +http://deliveryc.aftonbladet.se/puls/stockholmsguiden/presentation/0,1714,2000023220,00.html +http://www.tnonline.com/archives/news/2000weeklies/09.20/pocono/pocono/police.html +http://retailer.gocollect.com/do/session/1912688/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/sports/index.asp +http://ftp.fas.org/irp/world/iraq/hadi/ +http://rusf.ru/kb/stories/kogda_chapaev_ne_utonul/text.htm +http://ring.yamanashi.ac.jp/pub/FreeBSD-PC98/dists/4.1-RELEASE/packages/chinese/?M=A +http://www3.buch-per-sms.de/anmeldung0.jsp$ID=To7737mC4935289641883087At0.9095524774481786 +http://www3.buch-per-sms.de/impressum.jsp$ID=To7737mC4935289641883087At0.9104482951702283 +http://ftp.uni-bremen.de/pub/linux/dist/suse/6.4/i386.de/suse/contents/ +http://ftp.uni-bremen.de/pub/linux/dist/suse/6.4/i386.de/suse/pay3/ +http://ftp.uni-bremen.de/pub/linux/dist/suse/6.4/i386.de/suse/xdev2/ +http://www.mlbworldseries.com/u/baseball/mlb/players/moreplayer_7649.htm +http://www.rismedia.com/consumer/27/5192/ +http://www.rismedia.com/consumer/27/18760/ +http://library.cuhk.edu.hk/search*chi/aZhang,+Wei-Yuan./azhang+wei+yuan/-5,-1,0,B/browse +http://itcareers.careercast.com/texis/it/itjs/+XwwBmeSFy86xwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew8awn5otDanDtoDnnGaxdo5na5BwBnazdxanLpnGonDqnamnVncdpaBnwMahoGMiwGna31wcohoqwBodDaMFqpl0bP0RRe2PftgQE2yDzmesxwwwpBmeAFy86Kwww5rmepdwwwBrmeZpwww/morelike.html +http://itcareers.careercast.com/texis/it/itjs/+zwwBmerEy86e+xwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew8awn5otDanDtoDnnGaxdo5na5BwBnazdxanLpnGonDqnamnVncdpaBnwMahoGMiwGna31wcohoqwBodDaMFqpl0bP0RRe2PftgQE2yDzmesxwwwpBmeAFy86Kwww5rmeADwwwBrmeZpwww/jobpage.html +http://itcareers.careercast.com/texis/it/itjs/++wwBmex8286xwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew8awn5otDanDtoDnnGaxdo5na5BwBnazdxanLpnGonDqnamnVncdpaBnwMahoGMiwGna31wcohoqwBodDaMFqpl0bP0RRe2PftgQE2yDzmesxwwwpBmeAFy86Kwww5rm6mwwBrmeZpwww/jobpage.html +http://archive.soccerage.com/s/de/09/b2445.html +http://archive.soccerage.com/s/de/09/b2408.html +http://archive.soccerage.com/s/de/09/b2272.html +http://archive.soccerage.com/s/de/09/b2256.html +http://archive.soccerage.com/s/de/09/b2249.html +http://archive.soccerage.com/s/de/09/b2245.html +http://archive.soccerage.com/s/de/09/b2246.html +http://archive.soccerage.com/s/de/09/b2237.html +http://archive.soccerage.com/s/de/09/b2207.html +http://genforum.genealogy.com/cgi-genforum/forums/wickham.cgi?296 +http://ftpsearch.belnet.be/packages/CPAN/authors/id/N/NE/NEDKONZ/?S=A +http://www.cheatscape.com/amiga/a/game53cindex_1.htm +http://www.best.com/~radko/lounge/messages/3572.html +http://www.best.com/~radko/lounge/messages/3542.html +http://www.best.com/~radko/lounge/messages/3563.html +http://www.best.com/~radko/lounge/messages/3502.html +http://www.best.com/~radko/lounge/messages/3431.html +http://user.tninet.se/~lrg243i/leo2.htm +http://www.pocketbible.co.kr/new/hebrews/hebrews07/hebrews7-5.htm +http://www.pocketbible.co.kr/new/hebrews/hebrews07/hebrews7-10.htm +http://members.tripod.co.jp/sugart/?D=A +http://www.linux.com/networking/network/industry/growth/new/server/ +http://kdecvs.stud.fh-heilbronn.de/cvsweb/kdegames/kspaceduel/sprites/?hideattic=0&sortby=log +http://karate.list.ru/catalog/10621.html +http://www.digitaldrucke.de/(aktuell,arbeitsvermittlung,computer,hilfe,individualverkehr,kultur,mix,nuernberg,sense,software,verkehr)/_fort/html/themen/aktuell/verkehr.htm +http://www.digitaldrucke.de/(aktuell,arbeitsvermittlung,computer,hilfe,individualverkehr,kultur,mix,nuernberg,sense,software,verkehr)/_fort/html/themen/aktuell/fahrzeug/fahrzeug.htm +http://www.digitaldrucke.de/(aktuell,arbeitsvermittlung,computer,creaccess,hilfe,individualverkehr,kultur,mix,nuernberg,schnellübersicht,sense,software,verkehr,von)/_fort/html/themen/hilfe/getall.htm +http://polygraph.ircache.net:8181/http_-2www.infolane.com/http_-2www.neosoft.com/~nitemoon/technical/http_-2www2.davidweekleyhomes.com/advancedproj.html +http://wow-online.vhm.de/Regional/Sri_Lanka/Nachrichten.html +http://www.bell.bellnet.com/suchen/sport/rodeo.html +http://netway.pda.tucows.com/palm/adnload/67796_21902.html +http://netway.pda.tucows.com/palm/preview/48544.html +http://netway.pda.tucows.com/palm/adnload/139037_47478.html +http://netway.pda.tucows.com/palm/adnload/73256_21914.html +http://netway.pda.tucows.com/palm/adnload/71930_21910.html +http://netway.pda.tucows.com/palm/adnload/136499_47294.html +http://netway.pda.tucows.com/palm/adnload/77938_21926.html +http://wap.jamba.de/KNet/_KNet-g_v8j1-4Fd-13aaq/browse.de/node.0/cde7f2elw +http://www.oreilly.com/medical/autism/news/research.html +http://www.geocities.co.jp/HeartLand-Namiki/5523/kopen.html +http://br-online.de/wissenschaft/wimfs/tm/tm9611/tt9611ol.htm +http://retailer.gocollect.com/do/session/1912709/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/preorder.asp +http://rac.co.kr/www.avm.de/ +http://rac.co.kr/www.aztech.com.sg/ +http://rac.co.kr/www.simple.com.au/drivers.htm +http://www.egroups.com/messages/Wrestlings2ndComing/263 +http://mediate.magicbutton.net/do/session/625584/vsid/3342/tid/3342/cid/88020/mid/2008/rid/2313/chid/2648/url/http://www1.getmapping.com/index.cfm +http://ben.aspads.net/ex/c/643/874990125 +http://www.hri.org/docs//statedep/1998/98-05-26.std.html +http://member1.shangdu.net/home2/longing/byzs/036.htm +http://web.tiscalinet.it/informacitta/n2Maggio2000/n2Maggio2000/Pagine/P16.htm +http://www.eveclub.com/cgi-bin/eveclub.front/972959455723/Catalog/11000155 +http://www.eveclub.com/cgi-bin/eveclub.front/972959455723/Basket/View/1000038 +http://student.monterey.edu/sz/troxellphillipju/campus/ +http://readers.thevines.com/leaf/AA0000401329/45///&act=24-1-11&bref=1601 +http://caller-times.com/1999/september/30/today/business/750.html +http://www.online.kokusai.co.jp/Mmf_corner/V0043482/mmf_corner/mmf_corner/url +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=27,33,21,19,32 +http://jupiter.u-3mrs.fr/~msc41www/GRATXT/PD6483.HTM +http://webtools.familyeducation.com/whatworks/item/front/0,2551,1-9696-7765-539-51377,00.html +http://parallel.fh-bielefeld.de/ti/vorlesung/sp/jdk_doc/java/text/class-use/FieldPosition.html +http://cinemabilia.de/details/katnr/239509/ +http://ftp.sunet.se/pub/FreeBSD/FreeBSD-current/ports/games/xgolgo/pkg-comment +http://yp.gates96.com/13/2/50/12.html +http://yp.gates96.com/13/2/50/68.html +http://yp.gates96.com/13/2/52/56.html +http://yp.gates96.com/13/2/53/71.html +http://yp.gates96.com/13/2/54/13.html +http://yp.gates96.com/13/2/54/21.html +http://yp.gates96.com/13/2/54/43.html +http://yp.gates96.com/13/2/54/52.html +http://yp.gates96.com/13/2/54/94.html +http://yp.gates96.com/13/2/55/25.html +http://yp.gates96.com/13/2/55/57.html +http://yp.gates96.com/13/2/56/95.html +http://yp.gates96.com/13/2/57/24.html +http://yp.gates96.com/13/2/57/34.html +http://yp.gates96.com/13/2/57/35.html +http://yp.gates96.com/13/2/57/64.html +http://yp.gates96.com/13/2/58/92.html +http://yp.gates96.com/13/2/59/2.html +http://yp.gates96.com/13/2/59/31.html +http://www.outpersonals.com/cgi-bin/w3com/pws/out/RLhI7rcI1D4JxQFT7-3mEP5SJK8AVzq_FCHTmPD4oB4tzM54LVISOGr6gaW80TieiLj3vEEhfqMBuYuDKIQXk3pROAhdckz6dDnbPsi72aC9ZSsK2o3j3J8YlLpw-uOtcBIEsA4ZZATUNj1D6atp66I4 +http://www.dulux.co.uk/UKRETAIL:1938649915:DFinity.1QJiP4jRabmkmb +http://www.dulux.co.uk/UKRETAIL:1938649915:DFinity.1QJiP4jMomdoclfieh +http://www.egroups.com/messages/raite-dvd/1442 +http://www3.newstimes.com/archive2000/jun28/bzd.htm +http://yp.gates96.com/2/75/20/35.html +http://yp.gates96.com/2/75/20/42.html +http://yp.gates96.com/2/75/20/48.html +http://yp.gates96.com/2/75/21/28.html +http://yp.gates96.com/2/75/21/88.html +http://yp.gates96.com/2/75/21/91.html +http://yp.gates96.com/2/75/21/93.html +http://yp.gates96.com/2/75/21/96.html +http://yp.gates96.com/2/75/22/23.html +http://yp.gates96.com/2/75/23/50.html +http://yp.gates96.com/2/75/24/13.html +http://yp.gates96.com/2/75/24/47.html +http://yp.gates96.com/2/75/24/90.html +http://yp.gates96.com/2/75/25/33.html +http://yp.gates96.com/2/75/25/46.html +http://yp.gates96.com/2/75/25/84.html +http://yp.gates96.com/2/75/26/37.html +http://yp.gates96.com/2/75/26/40.html +http://yp.gates96.com/2/75/27/30.html +http://yp.gates96.com/2/75/27/66.html +http://yp.gates96.com/2/75/27/81.html +http://yp.gates96.com/2/75/28/34.html +http://yp.gates96.com/2/75/28/55.html +http://yp.gates96.com/2/75/29/12.html +http://yp.gates96.com/2/75/29/19.html +http://yp.gates96.com/2/75/29/45.html +http://yp.gates96.com/2/75/29/56.html +http://yp.gates96.com/2/75/29/86.html +http://yp.gates96.com/2/75/29/99.html +http://cn.egroups.com/message/agribusiness1/31 +http://biblio.cesga.es:81/search*gag/jLugo+(Provincia).+Mapas+topográficos.+[1890%3F]/jlugo+provincia+mapas+topograficos+1890/31,-1,0,B/browse +http://bbs.lineone.net/news/uknews/msg01030.html +http://bbs.lineone.net/news/uknews/msg01047.html +http://bbs.lineone.net/news/uknews/msg01026.html +http://bbs.lineone.net/news/uknews/msg00976.html +http://bbs.lineone.net/news/uknews/msg00960.html +http://bbs.lineone.net/news/uknews/msg00952.html +http://idl.tucows.com/winnt/adnload/1380_28802.html +http://retailer.gocollect.com/do/session/1912681/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/christmas/holiday_shoppe.asp +http://www1.zdnet.co.uk/software/fstore/A/9/000BA9.html +http://polygraph.ircache.net:8181/home/http_-2www.tauchbali.com/SERV.HTM +http://channel.nytimes.com/1998/05/01/technology/cybertimes/artsatlarge/ +http://ftp.sunet.se/pub/FreeBSD/ports/ports/japanese/linux-netscape47-communicator/?D=A +http://www9.hmv.co.uk:5555/do/session/1347757/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/hiddenframe.html +http://www9.hmv.co.uk:5555/do/session/1347757/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/logoframe.html +http://www-usa9.cricket.org/link_to_database/ARCHIVE/1999-2000/WI_IN_NZ/ARTICLES/ +http://www-usa9.cricket.org/link_to_database/ARCHIVE/1999-2000/WI_IN_NZ/SCORECARDS/ +http://a228.g.akamai.net/7/228/289/55d96730f1ea56/news.indiainfo.com/2000/08/13/floods.html +http://caller-times.com/1999/august/08/today/texas_me/4241.html +http://ftp.uni-bremen.de/pub/doc/news.answers/movies/winona-ryder-faq/part3 +http://www.globalsources.com/gsol/owa/website.gold/GP3/8801728414/HOME.HTM +http://eds.kse.or.kr/jaemoo/jipyo_e/k_grp/E01683.htm +http://eds.kse.or.kr/jaemoo/jipyo_e/i_grp/E01116.htm +http://eds.kse.or.kr/jaemoo/jipyo_e/i_grp/E01126.htm +http://eds.kse.or.kr/jaemoo/jipyo_e/d_grp/E00366.htm +http://eds.kse.or.kr/jaemoo/jipyo_e/h_grp/E00929.htm +http://www.jobvillage.com/channel/jobs/cleaning/pruner/g.1276.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380817/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/assistance/entry.asp +http://gamingplace.zeelandnet.nl/poker_rating.html +http://no.egroups.com/message/DVD-Info/111 +http://www.relax.ch/static/it/lazurigo/mercatodellavoro/oben.html +http://internet.exit.de/mees-online/left_geld.html +http://www.redrocksports.com/sports/webSession/shopper/RR972959658-31049/store/dept-5/department/dept-5/item/footwear +http://www.redrocksports.com/sports/webSession/shopper/RR972959658-31049/store/dept-5/department/dept-5/item/52550 +http://www11.cplaza.ne.jp/babyweb/bbs/bdnmp01/no16/61N.html +http://www.daimi.au.dk/dIntProg/java/jdk1.2.2/docs/api/javax/swing/plaf/basic/BasicScrollBarUI.ArrowButtonListener.html +http://www.daimi.au.dk/dIntProg/java/jdk1.2.2/docs/api/javax/swing/plaf/basic/BasicScrollBarUI.ModelListener.html +http://www.angelfire.com/nc/Percosolation/POSDerisions.html +http://yp.gates96.com/3/4/40/80.html +http://yp.gates96.com/3/4/41/23.html +http://yp.gates96.com/3/4/41/24.html +http://yp.gates96.com/3/4/41/37.html +http://yp.gates96.com/3/4/41/90.html +http://yp.gates96.com/3/4/42/26.html +http://yp.gates96.com/3/4/42/71.html +http://yp.gates96.com/3/4/42/90.html +http://yp.gates96.com/3/4/44/44.html +http://yp.gates96.com/3/4/45/52.html +http://yp.gates96.com/3/4/45/75.html +http://yp.gates96.com/3/4/45/77.html +http://yp.gates96.com/3/4/46/0.html +http://yp.gates96.com/3/4/46/85.html +http://yp.gates96.com/3/4/47/19.html +http://yp.gates96.com/3/4/47/20.html +http://yp.gates96.com/3/4/47/23.html +http://yp.gates96.com/3/4/47/72.html +http://yp.gates96.com/3/4/48/4.html +http://yp.gates96.com/3/4/48/16.html +http://yp.gates96.com/3/4/48/45.html +http://yp.gates96.com/3/4/48/51.html +http://yp.gates96.com/3/4/49/16.html +http://ftpsearch.belnet.be/pub/mirror/sunsite.cnlab-switch.ch/mirror/harvest/contrib/Example-Customizations/?S=A +http://pub9.ezboard.com/fgaprforeignrelationdepartment.showAddTopicScreenFromWeb +http://pub9.ezboard.com/fgaprforeignrelationdepartment.showMessage?topicID=4.topic +http://www.asstr.org/nifty/gay/authoritarian/adonis-brotherhood/adonis-brotherhood-3 +http://www.brio.de/BRIO.catalog/39fe2f4c06d41844273fd472aa7806a9/UserTemplate/8 +http://itcareers.careercast.com/texis/it/itjs/+HwwBmeH_D86aqwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew6nxqdDdMoqax15oDn55a5BwhhawDwcO5o5aqd5Ban5BoMwBoDtaGo5Aa5nGVoqnaADdicnmtnaBddc5aMFqhTfR20DzmenxwwwpBmeWWD86exhwww5rmeWcwwwBrmeZpwww/jobpage.html +http://polygraph.ircache.net:8181/http_-2www.whowhere.com/http_-2www.updowntowner.org/julyjamm/frmain.htm +http://213.36.119.69/do/session/152987/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/reserver/spectacles/ +http://www.jobvillage.com/channel/jobs/health_care/physician/anesthesiologist/b.9467.g.1575.html +http://www.private-immobilien-boerse.de/friesland/verkauf/IIM-Teil/Startseite/Gemeinsam/Super-Zins-Konditionen/Gemeinsam/Inserieren/Gemeinsam/MarketingStrategie/inhalt.htm +http://se.egroups.com/message/yemdiscussion/38 +http://se.egroups.com/message/yemdiscussion/45 +http://home.bip.net/kerstin.hjelm/Stamtavla%20Z-kullen.html +http://mediate.magicbutton.net/do/session/625616/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-abou.html +http://members.tripod.lycos.co.kr/KWEN3607/?S=A +http://cpan.clix.pt/authors/id/B/BP/BPOWERS/String-StringLib-1.02.readme +http://www.gbnf.com/genealogy/bookout/html/d0001/I3283.HTM +http://m4.findmail.com/group/Opera2Developers +http://m4.findmail.com/group/acctworks +http://retailer.gocollect.com/do/session/1912690/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/top_ten.asp?pagenum=1 +http://retailer.gocollect.com/do/session/1912690/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/postcards/index.asp +http://platsbanken.amv.se/kap/text/47/001023,170030,140912,11,1276051947.shtml +http://www.gamespot.com/features/dunesg/dune6a.html +http://tucows.iquest.net/winme/preview/138053.html +http://tucows.iquest.net/winme/preview/137529.html +http://tucows.iquest.net/winme/preview/138641.html +http://archive.soccerage.com/s/pt/09/03721.html +http://archive.soccerage.com/s/pt/09/07102.html +http://www10.nytimes.com/library/national/science/health/021500hth-women-diabetes.html +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www.phy.bnl.gov/e949/e949_update.txt +http://www.mapion.co.jp/custom/AOL/admi/13/13105/otsuka/3chome/index-7.html +http://go18.163.com/_NTES/~starseeker/gin/saga/gin01/gin0100.htm +http://village.infoweb.ne.jp/~fvgg8450/t91.html +http://clickahouse.mp2.homes.com/content/articles/locks.html +http://findmail.com/messages/studentdoctor/354 +http://ldp.mirror.nettuno.it/Linux/LDP/LDP/lkmpg/node3.html +http://ldp.mirror.nettuno.it/Linux/LDP/LDP/lkmpg/node13.html +http://fi.egroups.com/group/sandycove +http://www.fogdog.com/cedroID/ssd3040183219992/boutique/nike/ +http://www.fogdog.com/cedroID/ssd3040183219992/boutique/harbinger/ +http://www.fogdog.com/cedroID/ssd3040183219992/customer_service/employment.html +http://www.genoma.de/shop/736a8b4b4c331e80f780899842a4b0b4/99/b +http://sjsulib1.sjsu.edu:81/search/tbraille+transcription+project+of+santa+clara+county+inc/-5,-1,1,B/frameset&tbook+reviews+in+the+humanities&1,1, +http://students.washington.edu/emgall/eng481/final/ +http://www.vc-graz.ac.at/ilct/ffe_349_99.htm +http://www.vc-graz.ac.at/ilct/ffe_372_00.htm +http://www.vc-graz.ac.at/ilct/ffe_375_00.htm +http://www.escribe.com/computing/virtcom/m452.html +http://members.tripod.com/~TreasureIsland/welcom/e.htm +http://augustachronicle.com/stories/022699/obi_038-5494.001.shtml +http://augustachronicle.com/stories/022699/obi_038-5477.001.shtml +http://ring.edogawa-u.ac.jp/archives/X/opengroup/R6.5.1/xc/lib/Imakefile +http://www.elop.de/d0-1015-2044-3001-top.html +http://www.ibiblio.org/pub/languages/java/blackdown.org/JDK-1.1.7/i386/glibc/v1a/?S=D +http://www.linux.com/networking/network/enterprise/integration/management/Linux/ +http://www.mapion.co.jp/custom/AOL/admi/13/13221/matsuyama/2chome/index-7.html +http://www.mapion.co.jp/custom/AOL/admi/13/13221/matsuyama/2chome/index-12.html +http://ftp.sunet.se/pub/FreeBSD/ports/ports/japanese/tcl76/Makefile +http://ftp.lip6.fr/pub2/sgml-tools/website/HOWTO/Consultants-HOWTO/t19977.html +http://www.irishnews.com/archive2000/06072000/sportuk1.html +http://allmacintosh.ii.net/adnload/71893.html +http://allmacintosh.ii.net/adnload/70339.html +http://www.museumshops.co.uk/Bonnefoit-Alain/Bonnefoit-Alain-Die-Schoene-mit-dem-Pelz-3000062.html +http://www.timesoc.com/editions/orange/20001030/t000103758.html +http://www.musiciansfriend.com/ex/ds/bv/001030182803064208037039434033 +http://www.beneteau-owners.com/library.nsf/Library+By+System!OpenView&Start=41.4&Count=45&Expand=49 +http://www.musiciansfriend.com/ex/search/guitar/001030182759064208037059215342?FIND=BABX&q=c +http://www.musiciansfriend.com/ex/search/guitar/001030182759064208037059215342?FIND=ASAX&q=c +http://www.iabusnet.org:90/forums/aca-1/dispatch.exe/survey/showNextUnseen/fol/100001/2467632 +http://tucows.wish.net/winme/adnload/137243_28721.html +http://yp.gates96.com/3/71/10/71.html +http://yp.gates96.com/3/71/11/12.html +http://yp.gates96.com/3/71/11/27.html +http://yp.gates96.com/3/71/11/34.html +http://yp.gates96.com/3/71/11/40.html +http://yp.gates96.com/3/71/11/62.html +http://yp.gates96.com/3/71/11/78.html +http://yp.gates96.com/3/71/12/70.html +http://yp.gates96.com/3/71/13/34.html +http://yp.gates96.com/3/71/13/38.html +http://yp.gates96.com/3/71/13/82.html +http://yp.gates96.com/3/71/14/94.html +http://yp.gates96.com/3/71/15/0.html +http://yp.gates96.com/3/71/15/88.html +http://yp.gates96.com/3/71/17/28.html +http://yp.gates96.com/3/71/17/85.html +http://yp.gates96.com/3/71/18/37.html +http://yp.gates96.com/3/71/18/69.html +http://yp.gates96.com/3/71/19/55.html +http://www.kodak.ca/US/en/corp/jobs/samplingMechanicalProds.shtml +http://ring.crl.go.jp/archives/lang/perl/CPAN/authors/id/G/GR/GRICHTER/HTML-Embperl-1.3b4.readme +http://www7.freeweb.ne.jp/photo/lystra/a/n_aikawa.html +http://www.imagesofengland.org.uk/31/73/317339.htm +http://webraft.its.unimelb.edu.au/110080/students/ojb/pub/?D=A +http://pub.chinaccm.com/13/news/200010/31/155751.asp +http://pub.chinaccm.com/13/news/200010/21/162140.asp +http://go18.163.com/_NTES/~chen0580/y25.htm +http://pub17.ezboard.com/fcometalkfreetalk.showMessage?topicID=15.topic +http://pub17.ezboard.com/fcometalkfreetalk.showMessage?topicID=6.topic +http://mediate.magicbutton.net/do/session/625593/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-tips.html +http://213.36.119.69/do/session/152982/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/wap/lancement.html +http://wap.jamba.de/KNet/_KNet-Drs8j1-yEd-1395x/showInfo-presse.de/node.0/cde7f1uou +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=choramingar&l=pt +http://www.amcity.com/philadelphia/stories/1998/11/09/story5.html?t=email_story +http://www.mic.hr/PGMARKET:553666 +http://cn.egroups.com/messages/KristinChenoweth/2280 +http://quest7.proteome.com/databases/YPD/PombePD/SPAC343.03.html +http://www.engines.org.uk/white/fld19/ +http://www.engines.org.uk/white/fld27/ +http://se.egroups.com/subscribe/plusgothswap +http://www.headlight.com/invoice_process/1,1074,adpa-4049-2423-69-718,00.html +http://www.findarticles.com/cf_0/m4PRN/1999_Nov_3/57153314/p1/article.jhtml +http://www.iabusnet.org:90/forums/aca-1/dispatch.exe/survey/folderFrame/100001/0/alpha/2480022 +http://archive.soccerage.com/s/it/06/10903.html +http://innopac.lib.tsinghua.edu.cn/search*chi/dProduction+engineering/dproduction+engineering/-5,-1,0,B/browse +http://www.consource.com/communities/profile_categories/1759/1510 +http://column.daum.net/Column-bin/Bbs.cgi/thinkaboutrbs/new/zka/B2-kB2Np +http://wwws.br-online.de/geld/boerse/960301/0730.html +http://www.2pl.com/asp/tools/fili1.asp?sp=ro&fi=pppp0003zi +http://www.proviser.co.uk/regional/towns/alford/property_prices/compare_current_prices/terraced.html +http://cometweb01.comet.co.uk/do!session=131998&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG3XqLbdlLov4LfpmLiXvL-Zd5jbkLYozKvot0cZd5ockLYozKvsm0utt0cZX5qkXLjbzKMfaLblpLbom0bos0bom04M4Lbom0miXLvboLp1 +http://cometweb01.comet.co.uk/do!session=131998&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG3XqLbdlLov4LfpmLiXvL-Zd5jbkLYozKvot0cZd5ockLYozKvsm0uqo0cZX5qkXLjbzKG3pLibo0miX5mqlLmpbKomb0osb0oml1odXLkfpLbopL +http://www.geocities.co.jp/Milano/8578/profile.html +http://ftp.dti.ad.jp/pub/XFree86/3.3.3/binaries/NetBSD-1.2/Servers/?N=D +http://ftp.dti.ad.jp/pub/XFree86/3.3.3/binaries/NetBSD-1.2/Servers/?D=A +http://www.best.com/~radko/lounge/messages/3742.html +http://www.best.com/~radko/lounge/messages/3711.html +http://www.best.com/~radko/lounge/messages/3619.html +http://www.linux.com/networking/network/help/email/business/RuleSpace/ +http://www.financialexpress.com/fe/daily/20000918/fco17026.html +http://209.67.27.70/comics/dilbert/scott/dawn/pg19.html +http://209.67.27.70/comics/dilbert/scott/dawn/pg22.html +http://flamingo.promote.ru/href.pl?fct_051 +http://pda.saa.net/palm/adnload/34404_22152.html +http://www.outpersonals.com/cgi-bin/w3com/pws/out/q6tIzhLNlKeaaMXYVAPJiOq7V33Ul08VcQoPAomjWMQzOxA0cR6_kRLx42D4nA_uumPVc2DRZtv6CVpWQCyNUgVZQ2P9F7bqqvcf_5WqCdUM7UIRKBdjb9lTbrCrrl5_jZ6cQsstJDqry3XrFI0toILqSCSm66j2 +http://www.home.ch/~spaw9012/ps11/ps11_003.htm +http://help.sap.com/saphelp_45b/helpdata/de/1c/e464b20437d1118b3f0060b03ca329/frameset.htm +http://abc.ru/cgi-bin/get_firminfo.pl?firm=comsys +http://www.pressa.spb.ru/newspapers/nevrem/arts/nevrem-1749-art-28.html +http://www.pressa.spb.ru/newspapers/nevrem/arts/nevrem-1749-art-32.html +http://admin.afiliando.com/do/session/189435/vsid/1507/tid/1507/cid/23455/mid/1025/rid/1168/chid/1205/parser/yes/imref/eqqLmwlGltt5tkpHrYjLXofLklkKZljLkju5lZa5l0/url/http://www.submarino.com.mx/pesquisa/jutherC.asp?id_categoria=57&id_tipo=C +http://admin.afiliando.com/do/session/189435/vsid/1507/tid/1507/cid/23455/mid/1025/rid/1168/chid/1205/parser/yes/imref/eqqLmwlGltt5tkpHrYjLXofLklkKZljLkju5lZa5l0/url/http://www.submarino.com.mx/extra/talk_to_sub.asp +http://cometweb01.comet.co.uk/do!session=131998&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG3XqLbdlLov4LfpmLiXvL-Zd5jbkLYozKvot0cZd5ockLYozKvsn0mvm0cZX5qkXLjbzKGelLkbpL +http://yp.gates96.com/3/39/30/1.html +http://yp.gates96.com/3/39/30/53.html +http://yp.gates96.com/3/39/31/22.html +http://yp.gates96.com/3/39/32/0.html +http://yp.gates96.com/3/39/32/39.html +http://yp.gates96.com/3/39/32/41.html +http://yp.gates96.com/3/39/32/45.html +http://yp.gates96.com/3/39/32/97.html +http://yp.gates96.com/3/39/34/39.html +http://yp.gates96.com/3/39/34/50.html +http://yp.gates96.com/3/39/34/68.html +http://yp.gates96.com/3/39/34/72.html +http://yp.gates96.com/3/39/35/14.html +http://yp.gates96.com/3/39/35/84.html +http://yp.gates96.com/3/39/36/3.html +http://yp.gates96.com/3/39/36/19.html +http://yp.gates96.com/3/39/36/20.html +http://yp.gates96.com/3/39/36/84.html +http://yp.gates96.com/3/39/36/88.html +http://yp.gates96.com/3/39/37/37.html +http://yp.gates96.com/3/39/38/60.html +http://yp.gates96.com/3/39/38/63.html +http://yp.gates96.com/3/39/39/52.html +http://yp.gates96.com/3/39/39/56.html +http://yp.gates96.com/3/39/39/58.html +http://yp.gates96.com/3/39/39/63.html +http://yp.gates96.com/13/9/80/14.html +http://yp.gates96.com/13/9/80/92.html +http://yp.gates96.com/13/9/81/23.html +http://yp.gates96.com/13/9/81/47.html +http://yp.gates96.com/13/9/82/45.html +http://yp.gates96.com/13/9/82/59.html +http://yp.gates96.com/13/9/82/65.html +http://yp.gates96.com/13/9/82/71.html +http://yp.gates96.com/13/9/82/77.html +http://yp.gates96.com/13/9/83/86.html +http://yp.gates96.com/13/9/83/88.html +http://yp.gates96.com/13/9/84/4.html +http://yp.gates96.com/13/9/84/28.html +http://yp.gates96.com/13/9/84/77.html +http://yp.gates96.com/13/9/85/34.html +http://yp.gates96.com/13/9/85/59.html +http://yp.gates96.com/13/9/86/22.html +http://yp.gates96.com/13/9/86/28.html +http://yp.gates96.com/13/9/86/30.html +http://yp.gates96.com/13/9/86/37.html +http://yp.gates96.com/13/9/86/85.html +http://yp.gates96.com/13/9/87/1.html +http://yp.gates96.com/13/9/87/2.html +http://yp.gates96.com/13/9/88/58.html +http://yp.gates96.com/13/9/89/17.html +http://yp.gates96.com/13/9/89/49.html +http://yp.gates96.com/13/9/89/51.html +http://yp.gates96.com/13/9/89/64.html +http://yp.gates96.com/13/9/89/69.html +http://yp.gates96.com/13/9/89/79.html +http://www.diogenes.ch/4DACTION/web_rd_aut_frlist_az/ID=483337&chr=D +http://ngi.tucows.com/win2k/adnload/37473_28857.html +http://www4.nas.edu/ohr.nsf/All+Documents/Major+Units?OpenDocument&ExpandSection=1,4,21,7,17 +http://www4.nas.edu/ohr.nsf/All+Documents/Major+Units?OpenDocument&ExpandSection=2,4,21,7,17 +http://www4.nas.edu/ohr.nsf/All+Documents/Major+Units?OpenDocument&ExpandSection=15,4,21,7,17 +http://www4.nas.edu/ohr.nsf/All+Documents/Major+Units?OpenDocument&ExpandSection=16,4,21,7,17 +http://www.susi.de/cgi-bin/order/segelzentrum-kagerer/c134-5021905270003,de +http://www.egroups.com/messages/iraq-l/9973 +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=29,24,30,11 +http://www.etoys.com/prod/book/51604361 +http://link.fastpartner.com/do/session/600358/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/itjobbank.php +http://link.fastpartner.com/do/session/600358/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/shopnett.php +http://mirror.nucba.ac.jp/mirror/FreeBSD/branches/2.2-stable/ports/devel/mips64orion-rtems-objc/?S=A +http://www-uk5.cricket.org/link_to_database/NATIONAL/ENG/FC_TEAMS/SOMERSET/STATS/CAREER/SOMERSET_CAREER_J.html +http://www.linux.com/networking/network/performance/install/distro/industry/ +http://www.linux.com/networking/network/performance/install/distro/tools/ +http://www.linux.com/networking/network/performance/install/distro/enterprise/ +http://mx.php.net/manual/de/language.basic-syntax.php +http://mx.php.net/manual/fr/language.basic-syntax.php +http://moviestore.zap2it.com/browse/MOVIES/SCRIPT/s.UxBwM3db +http://www.armouries.org.uk/bjarni/introduction.htm +http://mirror.cc.utsunomiya-u.ac.jp/mirror/CPAN/authors/id/C/CT/CTWETEN/?D=A +http://atlanta.webmd.com/related_results/1/25/article/1738.50204 +http://www.ccnet.com/tzimmer/?M=A +http://go2.163.com/~xinhua/ +http://www.ualberta.ca/FTP/OpenBSD/src/regress/lib/libc/_setjmp/CVS/Root +http://www.dqt.com.cn/wymb/military/jinyong/金庸全集.htm +http://www.hole.kommune.no/hole/journweb.nsf/7e180336094ef23a412568cd004a5093/2fd09f96f20814cac12568e300443d50!Navigate&To=Next +http://classifieds.alberta.com/js/mi/c16000/b16000/n15/858640.html +http://classifieds.alberta.com/js/mi/c16000/b16000/n15/861013.html +http://homepages.go.com/homepages/b/n/g/bngholo/ +http://www.aelita.net/products/news/library/support/Reg/Subscribe/library/default.htm +http://www.chaos.dk/sexriddle/j/a/b/s/e/ +http://www.chaos.dk/sexriddle/j/a/b/s/t/ +http://213.36.119.69/do/session/152985/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/contact/info-publicite.html +http://www.indian-express.com/fe/daily/19990807/corporate.html +http://web.cln.com/archives/atlanta/newsstand/atl100795/1316.htm +http://web.cln.com/archives/atlanta/newsstand/atl100795/1317.htm +http://plaza.gaiax.com/www/plaza/k/n/kenta/friends.html +http://polygraph.ircache.net:8181/docs/eudora/http_-2www.kentuckylake.com/rates/http_-2www.hubbell-wiring.com/NEMA/admin/additional.html +http://gd.cnread.net/cnread1/wxxs/d/dongfangying/pljc/015.htm +http://www.bemi-immobilien.de/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Startseite/Gemeinsam/versicherungen/gebaeude/Gemeinsam/versicherungen/unfall/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/versicherungen/lebensversicherung/Gemeinsam/versicherungen/gebaeude/anforderungsformular.htm +http://www.linux.com/networking/network/help/free/red_hat/competition/ +http://www.linux.com/networking/network/help/free/red_hat/development/ +http://www.linux.com/networking/network/help/free/red_hat/SuSE/ +http://search.chollian.net/d/%b1%e2%be%f7,%c8%b8%bb%e7/%b0%e1%c8%a5/%c5%e4%c5%bb%bf%fe%b5%f9%bc%ad%ba%f1%bd%ba/16.html +http://no.egroups.com/message/plowshares/840 +http://www.pressa.spb.ru/newspapers/nevrem/arts/nevrem-1872-art-13.html +http://www.bemi-immobilien.de/Startseite/www.allgemeine-immobilien-boerse.de/allgemeine-ib/landkreiszwickau/Verkauf/29109700708107kirchbergvillamü/Gemeinsam/erreichenPartner/Startseite/Gemeinsam/versicherungen/lebensversicherung/Top-Darlehens-Konditionen/Gemeinsam/versicherungen/unfall/anforderungsformular.htm +http://www.affiliate.hpstore.hp.co.uk/do/session/380819/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.france.hp.com/main/respect/ +http://www-rn.informatik.uni-bremen.de/home/ftp/pub/linux/redhat/updates/6.2EE/i586/ +http://archive.soccerage.com/s/es/09/12718.html +http://www.intel.es/kr/hangul/pressroom/archive/releases/dp990218.htm +http://www.intel.es/kr/hangul/pressroom/archive/releases/dp990105.htm +http://sunsite.informatik.rwth-aachen.de/cgi-bin/ftp/ftpshow/pub/Linux/sunsite.unc.edu/distributions/caldera/eServer/updates/2.3/021/RPMS/ +http://library.bangor.ac.uk/search/aMatis,+James+H/amatis+james+h/-5,-1,0,B/browse +http://polygraph.ircache.net:8181/http_-2www.microsoft.com/frontpage/html/http_-2www.sharkyextreme.com/hardware/hercules_tnt/ +http://ring.nihon-u.ac.jp/archives/pack/win95/net/fee/?N=D +http://dbc.copystar.com.tw/bcbchat/199804/msg03730.htm +http://dbc.copystar.com.tw/bcbchat/199804/msg03761.htm +http://dbc.copystar.com.tw/bcbchat/199804/msg03787.htm +http://www.private-immobilien-boerse.de/nordrhein-Westfalen/grevenbroich/Verkauf/Gemeinsam/Super-Zins-Konditionen/Exklusiv-IB/Startseite/IIM-Teil/Startseite/Gemeinsam/IIMMitglieder.htm +http://www.private-immobilien-boerse.de/nordrhein-Westfalen/grevenbroich/Verkauf/Gemeinsam/Super-Zins-Konditionen/Exklusiv-IB/Startseite/IIM-Teil/Startseite/Gemeinsam/vertriebspartner.htm +http://pd.shiseido.co.jp/s9604tub/html_00/win00051.htm +http://solaris.license.virginia.edu/os_product_patches/patches/5.7/107094-04/SUNWdtbas/pkgmap +http://www.eveclub.com/cgi-bin/eveclub.front/972959470432/Catalog/11000034 +http://www.sportinggreen.com/news/20001007/fbo/fbc/aar/001007.0607.html +http://www-x500-1.uni-giessen.de:8890/Lcn%3dBelloch%20Belloch%5c,%20Juana%20Maria,ou%3dFacultad%20de%20Medicina%20y%20Odontologia,o%3dUniversidad%20de%20Valencia,c%3dES +http://retailer.gocollect.com/do/session/1912723/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/limited_editions.asp +http://www.jufo.com/netcenter/chemistry/item/000904/16888.htm +http://ww2.comune.fe.it/cgi-win/hiweb.exe/a2/d29/b14,8,1f,1d,1d,,19,,1f,19, +http://www.2pl.com/b/ru/to/1/24/16/v2/1241600107-8.htm +http://ring.htcn.ne.jp/pub/text/CTAN/fonts/metrics/polish/plpsfont/?D=A +http://config.tucows.com/winme/adnload/26398_28890.html +http://ocean.ntou.edu.tw/search*chi/aRadojcic,+Riko,+jt.+auth./aradojcic+riko/-5,-1,0,B/frameset&F=aradomsky+nellie+a&1,1 +http://www.intellicast.com/Sail/World/UnitedStates/Northwest/Montana/Beaverhead/LocalWinds/d1_09/ +http://www.bild.de/service/archiv/2000/mar/31/sport/coulthard/coulthard.html +http://ustlib.ust.hk/search*chi/a%7B215a36%7D%7B213246%7D%7B215e42%7D+1926/a{215a36}{213246}{215e42}+1926/-5,-1,0,B/frameset&F=a{215a36}{213230}{214e70}&1,1 +http://mediate.magicbutton.net/do/session/625620/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-top50.html +http://mediate.magicbutton.net/do/session/625620/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-corp.html +http://www.amateurplatinum.com/mouthlicking/eunuchhershey-highway/bad-girlsubmission/petitebeauties/actionno-boundaries/fellatiogoing-down-on/give-headcock-suckers.html +http://www.brd.net/brd-cgi/brd_dkameras/filmscanner_fotodrucker/FZ00F0EF/beurteilung/ci=972751646.htm +http://www.niwl.se/WAIS/31607/31607073.htm +http://www.magicvillage.de/Login/magicvillage/magiclife/Lucullus/%2328706045/Reply +http://polygraph.ircache.net:8181/consumer/rel_meet_main.html +http://sunsite.informatik.rwth-aachen.de/cgi-bin/ftp/ftpshow/pub/Linux/sunsite.unc.edu/distributions/debian/dists/potato/non-free/binary-i386/x11/ +http://www.great-cyber-mall.com/SelectCompany.asp?CityID=67&CatID=5 +http://www.great-cyber-mall.com/SelectCompany.asp?CityID=67&CatID=50 +http://rainforest.parentsplace.com/dialog/get/bradley2/39/1/1.html?embed=2 +http://www.users.yun.co.jp/cgi-bin/moriq/pigeon/pigeon.cgi/DataSet.after_post?c=e +http://www.chaos.dk/sexriddle/n/f/p/x/x/ +http://www.amcity.com/dayton/stories/2000/03/20/smallb1.html?t=email_story +http://www.linux.com/networking/network/industry/web_server/windows_nt/Red_Hat/ +http://www.du-et.net/cgi/mail.cgi?NickName=naiki +http://gameboyz.com/g/demos_p1_c41_lV_w2.html +http://intelinfo.subportal.com/sn/Games/Strategy_Games/9289.html +http://home.kimo.com.tw/maso-kid/index2.html +http://citeseer.nj.nec.com/nrelated/1377121/289677 +http://citeseer.nj.nec.com/nrelated/0/289677 +http://ccar.ust.hk/~dataop/rs_ocean_cd/WVS/wvsplus/wvs003m/bat/q/h/lf/ +http://home.baoding.cn.net/~tjhlove/dzrwy/l11.htm +http://home.baoding.cn.net/~tjhlove/dzrwy/l23.htm +http://208.178.109.85/msgshow.cfm/msgboard=129014524422386&msg=3558983275052&page=1&idDispSub=-1 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=4,9,33,27,35 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=29,9,33,27,35 +http://config.tucows.com/win2k/adnload/76944_30007.html +http://www1.zdnet.com/zdnn/stories/news/0,4586,1021147,00.html +http://www.fogdog.com/cedroID/ssd3040183236187/nav/stores/snowboarding/ +http://www.fogdog.com/cedroID/ssd3040183236187/nav/stores/institutional/ +http://debian.linux.org.tw/debian/dists/sid/main/disks-powerpc/current/source/?M=A +http://satftp.soest.hawaii.edu/dlr/slides/ql21176.html +http://www.linux.com/networking/network/industry/new/help/internet/ +http://www.linux.com/networking/network/industry/new/help/growth/ +http://flint.freethemes.com/skins/winamp/preview/46994.html +http://flint.freethemes.com/skins/winamp/preview/24628.html +http://flint.freethemes.com/skins/winamp/preview/25113.html +http://flint.freethemes.com/skins/winamp/preview/24645.html +http://flint.freethemes.com/skins/winamp/preview/25319.html +http://flint.freethemes.com/skins/winamp/preview/25017.html +http://flint.freethemes.com/skins/winamp/preview/26154.html +http://flint.freethemes.com/skins/winamp/preview/24669.html +http://flint.freethemes.com/skins/winamp/preview/24674.html +http://flint.freethemes.com/skins/winamp/preview/69522.html +http://flint.freethemes.com/skins/winamp/preview/58805.html +http://flint.freethemes.com/skins/winamp/preview/71909.html +http://flint.freethemes.com/skins/winamp/preview/24389.html +http://flint.freethemes.com/skins/winamp/preview/25052.html +http://flint.freethemes.com/skins/winamp/preview/77185.html +http://flint.freethemes.com/skins/winamp/preview/56733.html +http://flint.freethemes.com/skins/winamp/preview/24736.html +http://flint.freethemes.com/skins/winamp/preview/24408.html +http://flint.freethemes.com/skins/winamp/preview/24744.html +http://flint.freethemes.com/skins/winamp/preview/24424.html +http://flint.freethemes.com/skins/winamp/preview/25075.html +http://flint.freethemes.com/skins/winamp/preview/71807.html +http://nomade.fr/cat/informatique_tele/informatique/progiciels_logiciel/utilitaires/communication +http://pub9.ezboard.com/umetalman5566.showPublicProfile?language=EN +http://archiv.leo.org/pub/comp/usenet/comp.binaries.atari.st/texinfo31/texif31b.zoo/ +http://www.maas.ccr.it/cgi-win/hiweb.exe/a18/d13/b261,4,d,,be,d, +http://citeseer.nj.nec.com/cidcontext/608466 +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/asiasanahaku/strategia/kansainv%E4listyminen/ulkomaankauppa/kansainv%E4linen+kauppa/ +http://cms.letsmusic.com/directory/search/albuminfo/1,1125,af0127818000000,00.asp +http://www.musiciansfriend.com/ex/ds/other/001030182805064208037054818832 +http://www.musiciansfriend.com/ex/search/other/001030182805064208037054818832?FIND=IBAX&q=c +http://www.mapion.co.jp/custom/tv/admi/13/13106/kuramae/3chome/19/ +http://dblab.comeng.chungnam.ac.kr/~dolphin//db/journals/ac/ac11.html +http://archive.soccerage.com/s/de/09/c4816.html +http://archive.soccerage.com/s/de/09/c4698.html +http://archive.soccerage.com/s/de/09/c4664.html +http://archive.soccerage.com/s/de/09/c4463.html +http://archive.soccerage.com/s/de/09/c4423.html +http://archive.soccerage.com/s/de/09/c4422.html +http://workingfamilies.digitalcity.com/tampabay/penpals/browse.dci?cat=teens&sort=f +http://www.bemi-immobilien.de/Startseite/www.allgemeine-immobilien-boerse.de/allgemeine-ib/landkreiszwickau/Verkauf/29109700708107kirchbergvillamü/Gemeinsam/Inserieren/Startseite/Gemeinsam/immolink/Top-Darlehens-Konditionen/Gemeinsam/versicherungen/unfall/anforderungsformular.htm +http://www.samba.org/cgi-bin/cvsweb/gnokii/xgnokii/docs/help/en_US/windows/main/?sortby=log +http://www.accesslasvegas.com/shared/health/adam/ency/article/002669sym.html +http://www.egroups.com/message/gaywrestle/33 +http://lfs.cyf-kr.edu.pl:8888/3Lcn%3dDirectory%20Manager,%20o%3dSPRITEL,%20c%3dES +http://www.acfas.ca/congres/congres66/S10.htm +http://hansard.www.act.gov.au/2000/week02/423.htm +http://207.25.71.142/cycling/2000/tour_de_france/stages/4/ +http://207.25.71.142/cycling/2000/tour_de_france/news/2000/07/20/pantani_reflects +http://207.25.71.142/cycling/2000/tour_de_france/news/2000/07/19/driver_charged/ +http://207.25.71.142/POLL/results/1142011.html +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=6,14,27,22 +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=29,14,27,22 +http://www.affiliate.hpstore.hp.co.uk/do/session/380816/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.france.hp.com/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380816/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/products/entry.asp +http://ads.carltononline.com/accipiter/adclick/site=purejamba/area=jamba.home_page/AAMSZ=POPUP/ACC_RANDOM=972959547609 +http://retailer.gocollect.com/do/session/1912714/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/contact.asp +http://208.178.101.41/news/1998/12/10newsd.html +http://208.178.101.41/news/1998/03/05news.html +http://208.178.101.41/news/1998/03/03news.html +http://208.178.101.41/news/1998/01/09news.html +http://hff.shunde.net/mobile/radio2000.163.net/radio2000.163.html +http://hff.shunde.net/mobile/www.tohome.net/www.tohome.html +http://www.egroups.com/login.cgi?login_target=%2Fmessages%2FShayrs%2F31 +http://moviestore.zap2it.com/browse/MOVIES/BANK/s.bsk4qCBs +http://moviestore.zap2it.com/browse/MOVIES/STATION/s.bsk4qCBs +http://moviestore.zap2it.com/browse/MOVIES/VIDEO/s.bsk4qCBs +http://ftp.fi.debian.org/debian/dists/unstable/contrib/source/x11/?N=D +http://link.fastpartner.com/do/session/600364/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/company/jobs.htm +http://pub16.ezboard.com/uprieni.showPublicProfile +http://ftp.du.se/disk4/FreeBSD/branches/4.0-stable/ports/x11-servers/XFree86-4-FontServer/ +http://ftp.du.se/disk4/FreeBSD/branches/4.0-stable/ports/x11-servers/XttXF98srv-NKVNEC/ +http://www.generation-formation.fr/services/adrutils/GUIDES/CCI.HTM---o21zAo0UaWo0Ol9A074fo65iyfmKlze8SUeecTAseLvI5ehw7se7NeCfeZJPAPfVbNyqgBecVktePbBxehwwlezc9fAb0vyApuRtAhGqGdisSLdspt6dsSAtdsNhJdspt6dsrvrdjlhkfbu.htm +http://www.generation-formation.fr/services/adrutils/GUIDES/DRIRE.HTM---o21zAo0UaWo0Ol9A074fo65iyfmKlze8SUeecTAseLvI5ehw7se7NeCfeZJPAPfVbNyqgBecVktePbBxehwwlezc9fAb0vyApuRudNnJpo1XCjdRsR3djaPfdNjfcdRsR3djakUApvGdhcmdfbv.htm +http://198.103.152.100/search*frc/aMayer,+Anita/amayer+anita/-5,-1,0,B/frameset&F=amaybank+j+e&1,1 +http://198.103.152.100/search*frc/aMayer,+Anita/amayer+anita/-5,-1,0,B/2exact&F=amaycunich+ann&1,3 +http://kobenhavn.icepage.se/hilfe/XFree86/3.9.18/DECtga2.html +http://itcareers.careercast.com/texis/it/itjs/+YwwBmeJf5C6wwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewyhw1Bdmn5AanLnq1BoVnawmMoDo5BGwBoVnazdxamnpwGBMnDBaGnpdGB5a5BdGnaqddGmoDwBnanMwoca5Aocc5aMFqoEuRZy0IQDzmeJqwwwpBmeBFZ86mwww5rmehpwwwBrmeZpwww/morelike.html +http://itcareers.careercast.com/texis/it/itjs/+cwwBmetKD86eMmwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewyhw1Bdmn5AanLnq1BoVnawmMoDo5BGwBoVnazdxamnpwGBMnDBaGnpdGB5a5BdGnaqddGmoDwBnanMwoca5Aocc5aMFqoEuRZy0IQDzmeJqwwwpBmeBFZ86mwww5rmeODwwwBrmeZpwww/morelike.html +http://bbs.syu.ac.kr/NetBBS/Bbs.dll/scbbs008/rcm/zka/B2-kB27p/qqo/005A/qqatt/^ +http://musicmabey.subportal.com/sn/Themes/Misc__Themes/ +http://www.intel.it/eBusiness/pdf/prod/ia64/SAS_IA-64_Paper.pdf +http://elflife.bigpanda.net/2866/io.html +http://www.excelsior.com.mx/9609/960911/nac11.html +http://www.allgemeine-immobilien-boerse.de/ungarn/verkauf/Private-IB/Ferien-IB/Startseite/Allgemeine-IB/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/indexbeginn.htm +http://www.allgemeine-immobilien-boerse.de/ungarn/verkauf/Private-IB/Ferien-IB/Startseite/Allgemeine-IB/Gemeinsam/geschaeftsbedingungen.htm +http://www.wingateinns.com/ctg/cgi-bin/Wingate/look_over/AAAksrACwAAACCPAAT +http://my.netian.com/~rakyun/?N=D +http://www.bemi-immobilien.de/Landhaus-Bordeaux/Gemeinsam/versicherungen/gebaeude/Gemeinsam/immolink/Top-Darlehens-Konditionen/Gemeinsam/Inserieren/Gemeinsam/suche.htm +http://www.mirror.kiev.ua:8083/paper/2000/04/1251/text/04-07-5.htm +http://ring.toyama-u.ac.jp/archives/NetBSD/packages/1.4.2/sun3/?N=D +http://ring.toyama-u.ac.jp/archives/NetBSD/packages/1.4.2/sun3/lang/ +http://www.vstore.com/vstorecomputers/8store/ +http://indiadirectory.indiatimes.com/webdirectory/1514pg1.htm +http://indiadirectory.indiatimes.com/webdirectory/1513pg1.htm +http://www.online.kokusai.co.jp/Map/V0002508/wrd/G400/demo/ +http://www.gamespot.com.au/features/everquest_gg/creatures1.html +http://www.jxi.gov.cn/yw-ty001.nsf/view!OpenView&Start=38.11&Count=30&Expand=40 +http://www.jxi.gov.cn/yw-ty001.nsf/view!OpenView&Start=38.11&Count=30&Expand=42 +http://yp.gates96.com/6/0/40/22.html +http://yp.gates96.com/6/0/40/85.html +http://yp.gates96.com/6/0/41/26.html +http://yp.gates96.com/6/0/41/94.html +http://yp.gates96.com/6/0/42/50.html +http://yp.gates96.com/6/0/43/30.html +http://yp.gates96.com/6/0/43/76.html +http://yp.gates96.com/6/0/44/43.html +http://yp.gates96.com/6/0/44/61.html +http://yp.gates96.com/6/0/44/99.html +http://yp.gates96.com/6/0/45/37.html +http://yp.gates96.com/6/0/45/84.html +http://yp.gates96.com/6/0/47/33.html +http://yp.gates96.com/6/0/47/43.html +http://yp.gates96.com/6/0/47/54.html +http://yp.gates96.com/6/0/48/30.html +http://yp.gates96.com/6/0/48/47.html +http://yp.gates96.com/6/0/49/5.html +http://hammer.prohosting.com/~kobeweb/cgi-bin/nagaya/nagaya.cgi?room=036&action=mente +http://www.petropages.com/kproduct/k4267p.htm +http://webraft.its.unimelb.edu.au/536029/students/plam/pub/?M=A +http://www.ld.com/cbd/archive/1999/09(September)/13-Sep-1999/Fawd001.htm +http://www.caijing.yesky.com/33554432/36700160/122010.htm +http://yp.gates96.com/14/85/0/7.html +http://yp.gates96.com/14/85/2/86.html +http://yp.gates96.com/14/85/3/90.html +http://yp.gates96.com/14/85/6/37.html +http://yp.gates96.com/14/85/8/82.html +http://yp.gates96.com/14/85/8/88.html +http://cn.egroups.com/messages/Toledo_Storm/228 +http://mediate.magicbutton.net/do/session/625598/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-cart.html +http://rainforest.parentsplace.com/dialog/thread.pl/bradley2/10/2.html?dir=prevResponse +http://tvstore.zap2it.com/browse/TV/JACKET/s.CmMildAx +http://tvstore.zap2it.com/browse/TV/CLOCK/s.CmMildAx +http://findmail.com/post/studentdoctor?act=forward&messageNum=2315 +http://www.chaos.dk/sexriddle/d/j/l/a/y/ +http://gandalf.neark.org/pub/distributions/OpenBSD/src/gnu/egcs/libstdc++/testsuite/libstdc++.tests/?D=A +http://gd.cnread.net/cnread1/net/zpj/s/shenfang/004.htm +http://www.imagesignworks.com/vinylmasksforacidetching/index.nhtml +http://209.249.170.32/stores/dir/bycat/Holiday_and_Seasonal/Christmas.shtml +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959867726/Catalog/1000107 +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959867726/Catalog/1000108 +http://www.linux.com/networking/network/applications/interface/microsoft/IBM/ +http://www.linux.com/networking/network/applications/interface/microsoft/Corel/ +http://www.linux.com/networking/network/applications/interface/microsoft/?kw_offset=50 +http://www.tiefbau-suhl.de/Leistung/Stuetzmauern/stuetzmauern2.htm +http://providenet.tucows.com/win2k/adnload/38394_29124.html +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/index.opentext.net/weather/detail.cgi?us-dc +http://iceberg.adhomeworld.com/cgi-win/redirect.exe/2133549064 +http://www.dc.digitalcity.com/charlestonwvarea/announce/main.dci?page=letusknow +http://members.tripod.co.jp/yoshihiro_2/yotete.html +http://www.bemi-immobilien.de/Startseite/www.allgemeine-immobilien-boerse.de/allgemeine-ib/landkreiszwickau/Verkauf/29109700708107kirchbergvillamü/Gemeinsam/immolink/Startseite/Gemeinsam/versicherungen/lebensversicherung/Gemeinsam/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/ +http://ftp.debian.org/dists/Debian2.2r0/non-free/binary-arm/web/?N=D +http://www.complete-skier.co.uk/resorts/survey/submit.asp?ResortID=1755 +http://members.tripod.com/~BHS_CC/boys_times_1997.html +http://fi.egroups.com/post/mens-health?act=forward&messageNum=11 +http://nomade.fr/cat/famille_sante/sante/medecine_pratique/medecine_generale/ +http://home.att.net/~mlbvault/mac8.htm +http://mirror.nucba.ac.jp/mirror/Perl/authors/id/ROSCH/String-ShellQuote-1.00.readme +http://www.nrk.no/finnmark/x12_9_96/nyh6.htm +http://ftp.debian.org/dists/Debian2.2r0/non-free/binary-m68k/editors/?N=D +http://134.84.160.1/infoserv/lists/nih-image/archives/nih-image-9702/0141.html +http://www.philly.digitalcity.com/saintjosephmo/penpals/browse.dci?cat=seniors&sort=m +http://www.idg.net/crd_percent_19960.html +http://204.202.130.51/playerfile/profile/mark_karcher.html +http://www.redrocksports.com/sports/webSession/shopper/RR972959692-31077/store/dept-5/department/dept-5/item/52800 +http://www.redrocksports.com/sports/webSession/shopper/RR972959692-31077/store/dept-5/department/dept-5/item/52900 +http://www.online.kokusai.co.jp/Service/V0043510/wrd/G200/service/service.html +http://www.service911.com/mvu/step/0,2632,1+13+139+23899+17191_4,00.html +http://216.34.146.180/141000afp/14worl21.htm +http://www.chaos.dk/sexriddle/t/p/v/r/i/ +http://www.chaos.dk/sexriddle/t/p/v/r/x/ +http://www.ualberta.ca/FTP/Mirror/debian/dists/potato-proposed-updates/eruby_0.0.9-1potato1_arm.changes +http://www.hbdaily.com.cn/scznb/20000622/BIG5/scznb^1104^16^Zn16014.htm +http://www.linux.com/networking/network/administrator/internet/ftp/install/ +http://bsdweb.pasta.cs.uit.no/bsdweb.cgi/xsrc/xc/lib/Xt/PassivGrab.c?sortby=author +http://bsdweb.pasta.cs.uit.no/bsdweb.cgi/xsrc/xc/lib/Xt/ConstrainP.h?sortby=author +http://www.jamba.de/KNet/_KNet-EAA8j1-vFd-13b95/browse.de/node.0/cdel3j591 +http://vvv.geocities.co.jp/SiliconValley-SanJose/5688/sn-3.html +http://vvv.geocities.co.jp/SiliconValley-SanJose/5688/n.html +http://www.amel.net/english/computer/games/b/X0006_Backstab__.html +http://www.amel.net/english/computer/games/b/X0059_Bumper_Ships_1.1.html +http://retailer.gocollect.com/do/session/1912693/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/sports/index.asp +http://www.hig.se/(apre,formoutput,modified,set,set_cookie)/~jackson/roxen/ +http://yp.gates96.com/3/73/80/18.html +http://yp.gates96.com/3/73/81/27.html +http://yp.gates96.com/3/73/81/48.html +http://yp.gates96.com/3/73/81/58.html +http://yp.gates96.com/3/73/82/38.html +http://yp.gates96.com/3/73/83/30.html +http://yp.gates96.com/3/73/83/43.html +http://yp.gates96.com/3/73/83/49.html +http://yp.gates96.com/3/73/83/52.html +http://yp.gates96.com/3/73/84/33.html +http://yp.gates96.com/3/73/84/75.html +http://yp.gates96.com/3/73/85/2.html +http://yp.gates96.com/3/73/85/44.html +http://yp.gates96.com/3/73/85/70.html +http://yp.gates96.com/3/73/86/37.html +http://yp.gates96.com/3/73/86/59.html +http://yp.gates96.com/3/73/87/97.html +http://yp.gates96.com/3/73/87/99.html +http://yp.gates96.com/3/73/88/58.html +http://yp.gates96.com/3/73/88/63.html +http://yp.gates96.com/3/73/88/97.html +http://yp.gates96.com/3/73/89/31.html +http://yp.gates96.com/3/73/89/40.html +http://deseretbook.com/products/4108132/stock-38.html +http://workingfamilies.digitalcity.com/madison/search/ +http://debian.linux.org.tw/debian/dists/Debian2.2r0/main/disks-sparc/current/?D=A +http://debian.linux.org.tw/debian/dists/Debian2.2r0/main/disks-sparc/current/base-contents.txt +http://www.wizardsoftheweb.com/news/183.shtml +http://mathematics.fiz-karlsruhe.de/stn/whyonline/why_0367.html +http://www.nrk.no/finnmark/x27_11_98/nyh3.htm +http://rex.skyline.net/navigate.cgi?computers,agriculture,nature,agriculture,computers +http://www.secinfo.com/d1ZG7r.78.htm +http://www.secinfo.com/d1ZG7r.74.htm +http://www.freesoftware.com.cn/python.org.cn/doc/essays/ppt/hp-training/tsld051.htm +http://www.nrk.no/finnmark/x28_5_96/nyh1.htm +http://www.areteoutdoors.com/channel/snow/downhilling/b.354.g.2944.html +http://www.areteoutdoors.com/channel/snow/downhilling/b.357.g.2944.html +http://www.mywebmd.net/roundtable_message/662348 +http://lovers-lane.porncity.net/216/ +http://myhome.thrunet.com/~estefe/seng/sen18.htm +http://myhome.thrunet.com/~estefe/seng/sen42.htm +http://myhome.thrunet.com/~estefe/seng/sen52.htm +http://myhome.thrunet.com/~estefe/seng/sen73.htm +http://no.egroups.com/login.cgi?login_target=%2Fmessages%2Fenglish-zone +http://www.uzp.gov.pl/biulety/1998/100/100_1327.html +http://www.uzp.gov.pl/biulety/1998/100/100_1341.html +http://www.uzp.gov.pl/biulety/1998/100/100_1372.html +http://www.uzp.gov.pl/biulety/1998/100/100_1377.html +http://www.uzp.gov.pl/biulety/1998/100/100_1428.html +http://www.hotelboulevard.com/fr/riviera/standard/html40f8403856d2fa84c9080a860b7608ba/sessionLang/ANG/prov/browse/lstLieu[0]/Saint-Tropez/resultatSearch.html +http://polygraph.ircache.net:8181/http_-2www.microsoft.com/frontpage/speeches/Pages/funds/portfolio.html +http://www9.hmv.co.uk:5555/do/session/1347778/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d40_sd0_pt0.html +http://edc.uni-augsburg.de/doc/susehilf/pak/paket_doinst_insure.html +http://www.schlagerplatten.de/NewmanJimmyC/B000009PXU.htm +http://cn.egroups.com/message/pro92/604 +http://wwws.br-online.de/geld/boerse/980107/190001.html +http://faqs.bilkent.edu.tr/faqs/sgi/faq/performer/section-3.html +http://faqs.bilkent.edu.tr/faqs/sgi/faq/performer/section-46.html +http://faqs.bilkent.edu.tr/faqs/sgi/faq/performer/section-105.html +http://faqs.bilkent.edu.tr/faqs/sgi/faq/performer/section-111.html +http://newsone.net/nnr/prep/maus.soziales.recht +http://www.mapion.co.jp/custom/tv/admi/14/14131/yako/3chome/1/ +http://info.verwaltung.uni-freiburg.de/doc/packages/qt/html/qpicture-members.html +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959870915/ContentView/1000091/1/1200207 +http://tour.stanford.edu/cgi/locate2.prl/135.5/jltA +http://mapquest.digitalcity.com/daytonarea/salaries/main.dci?page=admin +http://linuxberg.zeelandnet.nl/x11html/adnload/9146_6809.html +http://medwebplus.com/subject/Alternative%20and%20Complementary%20Medicine/Population/Lists%20of%20Internet%20Resources?^ftc=240&^cc=ftc +http://ftp.du.se/disk0/slackware/slackware-current/contrib/ham/login/package_descriptions +http://yp.gates96.com/12/56/70/0.html +http://yp.gates96.com/12/56/70/14.html +http://yp.gates96.com/12/56/70/62.html +http://yp.gates96.com/12/56/71/19.html +http://yp.gates96.com/12/56/71/38.html +http://yp.gates96.com/12/56/71/46.html +http://yp.gates96.com/12/56/72/49.html +http://yp.gates96.com/12/56/72/78.html +http://yp.gates96.com/12/56/72/91.html +http://yp.gates96.com/12/56/73/18.html +http://yp.gates96.com/12/56/73/52.html +http://yp.gates96.com/12/56/74/15.html +http://yp.gates96.com/12/56/74/54.html +http://yp.gates96.com/12/56/74/79.html +http://yp.gates96.com/12/56/75/28.html +http://yp.gates96.com/12/56/75/68.html +http://yp.gates96.com/12/56/75/71.html +http://yp.gates96.com/12/56/75/76.html +http://yp.gates96.com/12/56/75/88.html +http://yp.gates96.com/12/56/75/94.html +http://yp.gates96.com/12/56/76/27.html +http://yp.gates96.com/12/56/76/57.html +http://yp.gates96.com/12/56/76/73.html +http://yp.gates96.com/12/56/77/60.html +http://yp.gates96.com/12/56/78/3.html +http://yp.gates96.com/12/56/78/45.html +http://yp.gates96.com/12/56/78/64.html +http://yp.gates96.com/12/56/78/86.html +http://yp.gates96.com/12/56/78/91.html +http://yp.gates96.com/12/56/78/95.html +http://yp.gates96.com/12/56/79/39.html +http://yp.gates96.com/12/56/79/75.html +http://www.alldata.com/TSB/19/831915CS.html +http://polygraph.ircache.net:8181/iisadmin/libraries/http_-2www.travelsc.com/welcome_v3/form1.html +http://majordomo.cgu.edu/cgi-bin/lwgate/NEMAI/archives/nemai.archive.0003/Date/article-9.html +http://home.tiscalinet.be/fysinet/studententips/tipsVanStudentenNicolas/sld007.htm +http://www4.netease.com/~abac/writting/zpnr/xw.htm +http://64.209.212.162/learnlots/step/0,2891,47+75+26299+10981_5,00.html +http://www.adcentral.com/cgi-bin/w3com/pws/adsites/KLhIZjY9X9xD5moK2JGI9yyxCV4tsONpzxjYyzP1Uq5ZFTlQAg3Wd-d9dlZbdFK8g3p8_O5GT8q_tKPHmrHXekF-PEpGmxPO69EhQYYR0fwhi_k2GqJa7eAy8n4PQUv0fLw2IIBwNP_qQkQpWEvx666v +http://www.nrc.nl/W2/Nieuws/1998/08/01/ +http://online.excite.de/unterhaltung/katalog/38320 +http://202.167.121.158/ebooks/jetro/tra1-1-1.html +http://ftp.uni-paderborn.de/aminet/aminet/demo/tp94/Blur.readme +http://www.symatrixinc.com/website/website.nsf/0/3e40df86fb357cd5882568720079613f!OpenDocument&ExpandSection=11,14,12,26 +http://www.intellicast.com/Ski/World/UnitedStates/Northeast/NewYork/WingedFootGCWest/WindChill/d1_12/ +http://yp.gates96.com/10/17/80/25.html +http://yp.gates96.com/10/17/80/66.html +http://yp.gates96.com/10/17/80/92.html +http://yp.gates96.com/10/17/82/56.html +http://yp.gates96.com/10/17/82/80.html +http://yp.gates96.com/10/17/83/48.html +http://yp.gates96.com/10/17/83/71.html +http://yp.gates96.com/10/17/83/85.html +http://yp.gates96.com/10/17/84/9.html +http://yp.gates96.com/10/17/84/20.html +http://yp.gates96.com/10/17/84/56.html +http://yp.gates96.com/10/17/84/63.html +http://yp.gates96.com/10/17/85/88.html +http://yp.gates96.com/10/17/86/4.html +http://yp.gates96.com/10/17/86/43.html +http://yp.gates96.com/10/17/86/45.html +http://yp.gates96.com/10/17/86/89.html +http://yp.gates96.com/10/17/86/97.html +http://yp.gates96.com/10/17/87/2.html +http://yp.gates96.com/10/17/87/46.html +http://yp.gates96.com/10/17/88/0.html +http://yp.gates96.com/10/17/89/21.html +http://yp.gates96.com/10/17/89/83.html +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www.w3.org/International/O-URL-and-ident +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=(9,6)+21,0+3,0 +http://polygraph.ircache.net:8181/http_-2www.hystuff.com/nrc.htm +http://jproxy.uol.es/jproxy/http://www.ocregister.com/beaches/capistrano +http://www1.zdnet.com/companyfinder/filters/products/0,9996,38071-58,00.html +http://www.ftp.uni-erlangen.de/pub/mirrors/_other/afterstep.foo.net/AfterStep/binaries/?M=A +http://www.genome.wustl.edu:8021/gsc10/mouse/up/?D=A +http://www.genome.wustl.edu:8021/gsc10/mouse/up/up24/ +http://rotten-tomatoes.com/movies/browse/1074473/reviews.php?view=reviews.source +http://www.virtual-impact-mktg.com/fx110001.htm +http://genforum.genealogy.com/hagen/messages/164.html +http://genforum.genealogy.com/hagen/messages/111.html +http://genforum.genealogy.com/hagen/messages/7.html +http://genforum.genealogy.com/hagen/messages/271.html +http://genforum.genealogy.com/hagen/messages/40.html +http://nt.mortgage101.com/partner-scripts/1024.asp?p=cashsolutions +http://nt.mortgage101.com/partner-scripts/1026.asp?p=cashsolutions +http://library.cuhk.edu.hk/search*chi/t龍情三地+%26%2359%3B+[3]/t%7B21632b%7D%7B213e5b%7D%7B213024%7D%7B213779%7D++++3/-5,-1,0,B/browse +http://ftp.net.uni-c.dk/pub/linux/redhat/redhat-6.2/sparc/misc/src/anaconda/isys/?S=A +http://ftp.net.uni-c.dk/pub/linux/redhat/redhat-6.2/sparc/misc/src/anaconda/isys/modutils/ +http://cobrand.altrec.com/shop/detail/8273/30 +http://pegasus.infor.kanazawa-it.ac.jp/~hatlab/kaga/docs/jdk1.3-beta_api/jdk1.3/docs/api/java/lang/class-use/ClassFormatError.html +http://bci.tucows.com/winnt/adnload/58788_28761.html +http://www.buybuddy.com/sleuth/33/1/1020503/300/ +http://203.116.23.91/computer/pages2/it120800e.html +http://203.116.23.91/special/newspapers/2000/pages4/computer030700.html +http://203.116.23.91/computer/pages1/software131197.html +http://dic.empas.com/show.tsp/?q=anarchically&f=B +http://noodle.tigris.org/source/browse/subversion/subversion/libsvn_vcdiff/tests/target0.txt +http://www.dbservicestore.de/home/db_reise_touristik/angebote/db_rt_gat_muenster.shtml +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=2&discrim=16,237,275 +http://www.narodnaobroda.sk/20000926/06_006.html +http://mandijin.chinamarket.com.cn/C/Showdetail_company/22591.html +http://202.167.121.158/ebooks/jetro/t6.html +http://a228.g.akamai.net/7/228/289/dd50406be5fc91/news.indiainfo.com/2000/08/17/world-index.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=disaminerei&l=it +http://polygraph.ircache.net:8181/http_-2www.eastnebr.net/html/conversions.htm +http://www.secinfo.com/d2wVq.7ar.htm +http://www.secinfo.com/d2wVq.7B5.htm +http://www.secinfo.com/d2wVq.6cd.htm +http://www.secinfo.com/d2wVq.59x.htm +http://www.jamba.de/KNet/_KNet-xdz8j1-mFd-13b2b/browse.de/node.0/cenv0b09a +http://213.36.119.69/do/session/152991/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/jeux/jeux_himalaya.html +http://www.dailyexcelsior.com/99sep30/edit.htm +http://www.dailyexcelsior.com/99sep30/sports.htm +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/misc/misc/music/lit/quizz/computers/netwars.html +http://cometweb01.comet.co.uk/do!session=132020&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkjHfZoLlplLcqkKZljLlfb5lal5tkiLlXaLl0 +http://www.affiliate.hpstore.hp.co.uk/do/session/380832/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/search.asp +http://208.216.182.15/exec/obidos/ASIN/0516206443/qid=972959559/sr=1-22/ +http://fi.egroups.com/messages/alau/2350 +http://ads.puntopartenza.com/cgi-bin/redirect.cgi/31033631 +http://pds.nchu.edu.tw/cpatch/ftp/ftpctrl/?N=D +http://www.brio.de/BRIO.catalog/39fe2f5606def942273fd472aa7806e2/UserTemplate/5 +http://ep.com/js/mi/c7246/b0/832275.html +http://ep.com/js/mi/c7246/b0/837505.html +http://ep.com/js/mi/c7246/b0/764046.html +http://www.fogdog.com/cedroID/ssd3040183223072/nav/products/nhl/pittsburgh_penguins/fan/gender/autographed_pucks/ +http://netway.pda.tucows.com/palm/preview/33567.html +http://netway.pda.tucows.com/palm/preview/34007.html +http://cometweb01.comet.co.uk/do!session=132006&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkjHfZoLlplLcqkKZljLlfb5lal5tkiLlXaLl0 +http://www.udn.com.tw/ARCHIVE/2000/08/04/DOMESTIC/YUNLIN/587058.htm +http://www.linux.com/networking/network/support/web/news/services/ +http://www.linux.com/networking/network/support/web/news/website/ +http://www.linux.com/networking/network/support/web/news/business/ +http://ads.carltononline.com/accipiter/adclick/site=purejamba/area=jamba.home_page/AAMSZ=IAB_FULL_BANNER//ACC_RANDOM=972959548213 +http://www-x500-1.uni-giessen.de:8890/Lcn%3dConsuelo%20Alvarez,ou%3dDpto.%20Fisiologia%20y%20Biologia%20Animal,o%3dUniversidad%20de%20Sevilla,c%3dES +http://www.chaos.dk/sexriddle/b/q/v/y/n/ +http://www.cs.kuleuven.ac.be/~java/docs/tutorial/uiswing/converting/example-1dot1/ListDemo.html +http://golfonline.comfluent.net/cgi.pan$player&lpga82&Debbie_Raso&lpga?golfstats +http://acetoys.com/cgi-bin/exec/modify_cart_button=1&cart_id=1999923.7130.303&page=/tystore/htmlfiles/eden/dw.html +http://www.bigchurch.com/cgi-bin/w3com/pws/bc/y1hIyNzn0Bl2XX5GzG9wVnUEhWD8GTd-XbpDm6aNI4ZMGTnV_YsP2OjB0RrwLpDbJub1pKlzEMrInSQi9hRM-Rz4WNq8C1vKJ9STiU9leUD_a3PBVh-7OMZDzJtyEBAXTehiRqme6jBR +http://www.bigchurch.com/cgi-bin/w3com/pws/bc/mChIR_iy1798J8x9InaTkzOfisuwH2hv2KUj0e64IQ9CeS327muTnTo70bT5YC4YznUddEOY5WdX70keIPRlsQibJtG6uzZtaaPmL58O5zJ0z_2PkJNxmBS5dj5-gWoeBgE0zaSvCbi66Grq +http://wap.jamba.de/KNet/_KNet-8qB8j1-FFd-13blo/browse.de/node.0/cde7f2elw +http://collection.nlc-bnc.ca/100/201/300/info_tabac/html/1997/bull7/fdacarol.html +http://pub17.ezboard.com/fzhaostempleofenlightenmentzhaosforum.showMessage?topicID=116.topic +http://www.home.ch/~spaw4360/HOWTO_fr/Ethernet-HOWTO-5.html +http://www.chaos.dk/sexriddle/s/g/n/y/j/ +http://polygraph.ircache.net:8181/http_-2www.horizonfinance.com/https_-2www.truste.org/validate/page3.html +http://marketbiz.subportal.com/sn/Themes/Sports_Themes/288.html +http://www.chinaccm.com/04/news/200004/20/120305.asp +http://www.american.webtourist.net/travel/northamerica/usa/lagunabeach/bwlagunareefinn.htm +http://elib.zib.de/pub/visual/avs/mirror/imperial/new/?S=A +http://www.burstnet.com/ads/ad7826a-map.cgi/969206790 +http://yp.gates96.com/14/82/10/81.html +http://yp.gates96.com/14/82/12/82.html +http://yp.gates96.com/14/82/13/55.html +http://yp.gates96.com/14/82/14/27.html +http://yp.gates96.com/14/82/14/31.html +http://yp.gates96.com/14/82/15/52.html +http://yp.gates96.com/14/82/17/16.html +http://yp.gates96.com/14/82/17/93.html +http://www.outpersonals.com/cgi-bin/w3com/pws/out/P2hI5ODQEZ1-vIl-agOzeOeNg4wShDlZrsCbdT5YZ3TrprEU4rb4NnnDXiGmf5cX3dh8ltMer04TMDd3q-cE5Mne85eH57ltxsi4ZQfER6vkktoaaYlS9JFTzylmCJZ2_PAT9uu2oWvIjgMzt9toyeuV +http://www.mirror.ac.uk/sites/ftp.microsoft.com/deskapps/powerpt/KB/Q226/7/ +http://mirror.nucba.ac.jp/mirror/Perl/authors/id/MIKEKING/?M=A +http://lists.insecure.org/linux-kernel/2000/Jun/4357.html +http://www.nlc-bnc.ca/indexmus-bin/resultsum/m=0/e=0/h=25/p=1/f=AU/t=Siroir,+Maryse+Angrignon +http://genforum.genealogy.com/cgi-bin/print.cgi?leavy::19.html +http://www.egroups.com/message/malaysiakini/219 +http://wuarchive.wustl.edu/graphics/mirrors/ftp.povray.org/.3/netlib/ode/rksuite/?S=A +http://www.earthsystems.org/list/greenyes/jan2000/1999-2/0858.html +http://pp3.shef.ac.uk:4040/search=browse/dn=countryName%3DGB%40organizationName%3DUniversity+of+Sheffield%40organizationalUnitName%3DAutomatic+Control+and+Systems+Engineering%40commonName%3DI+D+Durkacz +http://cobrand.altrec.com/shop/detail/6133/15/sizing +http://cobrand.altrec.com/shop/detail/5624/17/write +http://members.theglobe.com/inwardpath/history.htm +http://findmail.com/post/studentdoctor?act=reply&messageNum=5168 +http://www.service911.com/everythingtele/step/0,2675,3+26057+24201+16394_0,00.html +http://www.linux.com/networking/network/free/release/development/mysql/ +http://www.nbip.com.cn/books/xdwx/Hongyan/hongyan14.html +http://ftp.jp.debian.org/debian-non-US/dists/sid/non-US/non-free/binary-hurd-i386/?N=D +http://homepage.swissonline.ch/chico_logo/www.Link008 +http://homepage.swissonline.ch/chico_logo/www.Link009 +http://citeseer.nj.nec.com/cidcontext/3719857 +http://itcareers.careercast.com/texis/it/itjs/+CwwBme3AT+6e-xwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewXnmoBGnamwBwxw5naBnqrDdcdtOaOnwGaMdDBramwOaqmwBwamn5otDamnVncdpoDtanDtoDnnGoDtaMFqhTfR20DzmebmwwwpBme3AT+6ekxwww5rmeXdwwwBrmeZpwww/jobpage.html +http://www.amazon.com.hk/exec/obidos/tg/stores/detail/-/pro-tools/B0000224UB/customer-reviews/ref=th_hp_rs_2_6/ +http://www.ard-buffet.de/buffet/teledoktor/1998/02/16/ +http://pub19.ezboard.com/fmissionimplausiblewhatpeoplearesaying.emailToFriend?topicID=41.topic +http://no.egroups.com/message/NikonCoolPix/211 +http://www.gasex.com/free.gay.sex/gay.men.dick.dicks.html +http://www.centc251.org/forums/aca-1/dispatch.cgi/hsi/showFolder/100001/1255931 +http://www.uni-duesseldorf.de/ftp/ftp/pf/s/yagirc-0.65.6/?N=D +http://www.outpersonals.com/cgi-bin/w3com/pws/out/uIhI1DhpdvAdxVFONIJuaNcvtSTejSMmZIBgOwsZamHFS4JpS3i6VWNOSb8LsLcmqmG0gp2hs1YjuScHwXmociV5L_3_fCYngafHC4CIYDuKoI-rOZldw1RU5K3jOfh5d3PxatRmmHqB662F +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/elax176954/eus53832/eus155852/eus53907/eus62316/ +http://www.magictraders.com/cgi-bin/ubb/ubbmisc.cgi?action=getbio&UserName=Ammo187 +http://fi.egroups.com/login.cgi?login_target=%2Fgroup%2Fweirdchicks +http://www.accesslasvegas.com/shared/health/adam/ency/article/000589.images.html +http://pp3.shef.ac.uk:4040/search=browse/dn=countryName%3DGB%40organizationName%3DAberdeen+University%40organizationalUnitName%3DGeneral+Practice%40commonName%3DMorrison+S +http://worldres.lycos.com/script/gen_amen.asp?hotel_id=2252&n=2089 +http://tulips.ntu.edu.tw/search*chi/dSymbolism+in+fairy+tales/dsymbolism+in+fairy+tales/-5,-1,0,B/browse +http://ftp.du.se/disk4/FreeBSD/branches/4.0-stable/ports/x11-clocks/pclock/ +http://ftp.du.se/disk4/FreeBSD/branches/4.0-stable/ports/x11-clocks/xtimer/ +http://polygraph.ircache.net:8181/cgi-win/lincoln/$cgi4wpro.exe/http_-2www.k56.com/http_-2www.webexplorer.net/c/SHLFFREZ.HTM +http://www.ecs.soton.ac.uk/~seg7/private/contact.html +http://wiem.onet.pl/wiem/00de68-s.html +http://lcweb2.loc.gov/ll/llnt/008/?M=A +http://www.alladvantage.com/pressroom.asp?refid=CBI-463 +http://herndon1.sdrdc.com/cgi-bin/ind_detail/FERRELL|PORTER|FORT+WORTH|TX|76107|SINGLE+SERVER+COMMUNICATIONS/ +http://herndon1.sdrdc.com/cgi-bin/ind_detail/HARRIS|WILLIAM|FAIRFAX|VA|22031|HARRIS+AND+ASSOCIATES/ +http://herndon1.sdrdc.com/cgi-bin/ind_detail/HUTCHER|LARRY|NEW+YORK|NY|10023|DAVIDOFF+AND+MALITO/ +http://herndon1.sdrdc.com/cgi-bin/ind_detail/ISIKOFF|NATHAN+R|WASHINGTON|DC|20007|CAREY-WINSTON+CO/ +http://www.linux.com/networking/network/communications/security/wireless/protocol/ +http://www.linux.com/networking/network/communications/security/wireless/technology/ +http://retailer.gocollect.com/do/session/1912719/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/about.asp +http://retailer.gocollect.com/do/session/1912719/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/limited_editions.asp +http://retailer.gocollect.com/do/session/1912719/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://www9.hmv.co.uk:5555/do/session/1347779/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/hiddenframe.html +http://pub9.ezboard.com/fwestlifedublinmessageboardwestlifemessageboard.showMessage?topicID=8.topic +http://no.egroups.com/subscribe/hardzero +http://link.fastpartner.com/do/session/600378/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/index.php +http://link.fastpartner.com/do/session/600378/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/gosafe.php +http://link.fastpartner.com/do/session/600378/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/bitconomy.php +http://www.hello.co.jp/~daichi2/ +http://bbs.nsysu.edu.tw/txtVersion/treasure/ChiaYi/M.937783175.A/M.959916136.M.html +http://chat.hani.co.kr/NetBBS/Bbs.dll/chosun21/lst/qqeq/1/zka/B2-kB2Bp/qqo/PRMY +http://www.gartenfachmarkt.de/haus/schleifen/so.htm +http://links2go.publiweb.com/topic/US_Department_of_Agriculture +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=14,15,6,36,22 +http://www.linux.com/networking/network/new/hardware/open_source/operating_system/ +http://www.linux.com/networking/network/new/hardware/open_source/availability/ +http://tokyo.cool.ne.jp/pure0101/Oblivion_dust.html +http://www.digitaldrucke.de/(aktuell,computer,gaestebuch,hilfe,hilfeallgemein,individualverkehr,kultur,onlineservice,peripherie,sense,veranstaltungen,verkehr)/_fort/html/themen/computer/hard/links/mitsu.htm +http://www.gbnf.com/genealogy/jenkins/html/d0097/I4129.HTM +http://www.geocities.co.jp/Outdoors-River/1625/hakuba0502.htm +http://ftp.fi.debian.org/OpenBSD/src/regress/share/man/ +http://www3.buch-per-sms.de/angemeldet.jsp$ID=To7767mC050667397857644736At0.8818825373175998 +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=15,25,16,27 +http://debian.tod.net/debian/dists/sid/main/binary-sparc/electronics/?D=A +http://hs1.takeoff.ne.jp/~hatuse/ +http://polygraph.ircache.net:8181/Keyboards/http_-2www.sky.net/~robertf/handson/engine.html +http://www.gbnf.com/genealogy/jenkins/html/d0005/I3818.HTM +http://sepwww.stanford.edu/oldreports/sep67/old_src/jon/extend/junk.listing +http://www.kol.net/~calldj/cyberstar/map/dw25a.htm +http://citeseer.nj.nec.com/cidcontext/1297195 +http://citeseer.nj.nec.com/cidcontext/1297207 +http://books.hyperlink.co.uk/xt2/Peace_Verses_War/Cole/Derek/0722329539 +http://www.spousehouse.com/ +http://futures.homeway.com.cn/lbi-html/news/special/zhzt/jdht/twparty/zhengfu94652.shtml +http://www.yorosiku.net:8080/-_-http://www.zdnet.co.jp/zdii/interviews/interviews.html +http://library.cwu.edu/search/aIdaho+State+University/aidaho+state+university/-5,-1,0,E/frameset&F=aidaho+state+university&2,,0 +http://pelit.saunalahti.fi/.1/tucows/preview/68721.html +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=34,20,30,36,32 +http://pike-community.org/(base=/forums/show.html,forum=7,show=146,t=972959487953431)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=185,t=972959487953431)/forums/show.html +http://pike-community.org/(base=/forums/show.html,explode=763,forum=7,t=972959487953431)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=870,t=972959487953431)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=890,t=972959487953431)/forums/show.html +http://ww2.comune.fe.it/cgi-win/hiweb.exe/a2/d3/b34,8,1,,1f,1,65,,1f,65, +http://www.telematik.informatik.uni-karlsruhe.de/osf/sw/v4.0x/lp2/bst320/kit/ +http://cafe3.daum.net/Cafe-bin/Bbs.cgi/harukypds/rnw/zka/B2-kB2Zq +http://www.digitaldrucke.de/(computer,hilfe)/_fort/html/themen/computer/hard/links/escom.htm +http://www2.ipc.pku.edu.cn/scop/pdb.cgi?sid=d6stdb_ +http://www2.ipc.pku.edu.cn/scop/pdb.cgi?sid=d4stdc_ +http://www.shopworks.com/index.cfm/action/specials/userid/00029735-2E1C-19FE-AF65010C0A0A8CF2 +http://www.shopworks.com/index.cfm/action/search/userid/00029735-2E1C-19FE-AF65010C0A0A8CF2 +http://www.helpnow.net.cn/helpnow/hardware/bbs/cpu/?D=A +http://books.hyperlink.co.uk/xt1/Light_My_Fire/Manzarek/Ray/0099280655 +http://bsd.sinica.edu.tw/cgi-bin/cvsweb.cgi/src/crypto/heimdal/appl/ftp/ftp/?sortby=author +http://tucows.interbaun.com/winme/adnload/5147_28523.html +http://tucows.interbaun.com/winme/adnload/137019_28530.html +http://moviestore.zap2it.com/browse/MOVIES/COLLECTI/s.NedNjpDf +http://moviestore.zap2it.com/browse/MOVIES/STRAW/s.NedNjpDf +http://www.online.kokusai.co.jp/Words/V0043505/wrd/G700/words/kana_main.html +http://www.mirror.edu.cn/res/sunsite/pub/X11/contrib/window_managers/gwm/patches/gwm_patch_1.8a_001 +http://www.musicblvd.com/cgi-bin/tw/270242907922133_20_hip +http://www.cowo.de/archiv/1991/21/9121c045.html +http://www.russ.ru:8080/netcult/nevod/19990827-pr.html +http://usol.linux.tucows.com/x11html/preview/26680.html +http://usol.linux.tucows.com/x11html/preview/10385.html +http://yp.gates96.com/7/22/20/54.html +http://yp.gates96.com/7/22/20/67.html +http://yp.gates96.com/7/22/20/71.html +http://yp.gates96.com/7/22/22/26.html +http://yp.gates96.com/7/22/22/55.html +http://yp.gates96.com/7/22/22/74.html +http://yp.gates96.com/7/22/22/94.html +http://yp.gates96.com/7/22/23/38.html +http://yp.gates96.com/7/22/23/59.html +http://yp.gates96.com/7/22/24/43.html +http://yp.gates96.com/7/22/24/60.html +http://yp.gates96.com/7/22/24/64.html +http://yp.gates96.com/7/22/24/66.html +http://yp.gates96.com/7/22/24/72.html +http://yp.gates96.com/7/22/24/85.html +http://yp.gates96.com/7/22/26/11.html +http://yp.gates96.com/7/22/26/69.html +http://yp.gates96.com/7/22/27/3.html +http://yp.gates96.com/7/22/27/11.html +http://yp.gates96.com/7/22/27/22.html +http://yp.gates96.com/7/22/27/48.html +http://yp.gates96.com/7/22/27/69.html +http://yp.gates96.com/7/22/28/13.html +http://yp.gates96.com/7/22/28/30.html +http://yp.gates96.com/7/22/29/39.html +http://yp.gates96.com/7/22/29/58.html +http://www.allgemeine-immobilien-boerse.de/frankfurt/verkauf/Gemeinsam/Super-Zins-Konditionen/Private-IB/Startseite/IIM-Teil/Startseite/Gemeinsam/Super-Zins-Konditionen/anforderungsformular.htm +http://cobrand.altrec.com/shop/detail/8470/9/description +http://oa-nett.no/0/73/90/2.html +http://www.nordi.no/~steinsk/ +http://www02.geocities.co.jp/Stylish/6692/ +http://no.egroups.com/login.cgi?login_target=%2Fmessages%2Fsan-diego-tango +http://no.egroups.com/message/san-diego-tango/390 +http://www.jamba.de/KNet/_KNet-m_C8j1-PFd-13bt7/showInfo-special1.de/node.0/cenv0b09a +http://www.bemi-immobilien.de/Ferien-IB/Startseite/Gemeinsam/immolink/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Startseite/Gemeinsam/versicherungen/gebaeude/Startseite/froben.htm +http://it.egroups.com/post/pimnews-homeworker?act=reply&messageNum=661 +http://members.es.tripod.de/remoto/t2/p3b.htm +http://no.egroups.com/post/Translat2000?act=reply&messageNum=530 +http://www.opengroup.com/pabooks/081/0816631352.shtml +http://www6.freeweb.ne.jp/feminine/ki18/portrait10/p21.htm +http://genforum.genealogy.com/cgi-genforum/forums/cantrell.cgi?2117 +http://www9.hmv.co.uk:5555/do/session/1347769/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d30_sd0_pt0.html +http://polygraph.ircache.net:8181/docs/Win95/MSdialer/http_-2www.fastcounter.com/http_-2www.perrypip.com/http_-2www.scruz.net/~dvb/cam.html +http://polygraph.ircache.net:8181/docs/Win95/MSdialer/http_-2www.fastcounter.com/http_-2www.perrypip.com/~logan/ +http://polygraph.ircache.net:8181/docs/Win95/MSdialer/http_-2www.fastcounter.com/http_-2www.perrypip.com/http_-2hits.omino.com/ +http://javatest.a-net.nl/servlet/pedit.Main/http://epidem13.plantsci.cam.ac.uk/~js/glossary/course-glossary.html +http://www.hellefors.se/ulf/akno/alla/p0349c5e1e.html +http://home.no.net/islamnor/had.sira.html +http://www.gutenberg2000.de/immerman/muenchim/muen1171.htm +http://www.gutenberg2000.de/immerman/muenchim/muen3091.htm +http://www.gutenberg2000.de/immerman/muenchim/muen7011.htm +http://www.sikhnet.com/sikhnet/music.nsf/by%20Shabad!OpenView&Start=30&Count=20&Expand=2 +http://www.proteome.com/databases/PombePD/reports/SPCC613.01.html +http://www.midwestvanlines.com/oh/indexC.html +http://ring.tains.tohoku.ac.jp/pub/linux/debian/debian-jp/dists/stable/contrib/binary-arm/electronics/?S=A +http://members.tripod.com/~infolog/Genhouses/Chap12.htm +http://www.4positiveimages.com/4positiveimages/1998693855/UserTemplate/2 +http://www.greenleaves.com/bookcat/gb_096855900X.html +http://www-rn.informatik.uni-bremen.de/home/X11R6/xc/doc/hardcopy/test/?M=A +http://rex.skyline.net/html/Shipping_of_Goods.html?48,airplanes,transportation,collectibles,transportation +http://rex.skyline.net/html/Automobile_Classified_Listings.html?59,airplanes,transportation,collectibles,transportation +http://www.admin.co.martin.fl.us/GOVT/depts/cas/corresp/2000/cas00l.133.html +http://www.admin.co.martin.fl.us/GOVT/depts/cas/corresp/2000/cas00l.126.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380834/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hpstore.hewlett-packard.fr/gp +http://link.fastpartner.com/do/session/600367/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/no/ +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www-library.lbl.gov/photo/gallery/ +http://dogbert.wu-wien.ac.at/UniverCD/cc/td/doc/product/core/cis12012/bfrcfig/4334acps/?M=A +http://ftp.uni-stuttgart.de/pub/tex/nonfree/support/latexdraw/doc/ltdmanual.html.g/node10.html +http://se.egroups.com/message/911dispatchers/718 +http://ftp.eecs.umich.edu/.1/people/jfr/Pinata_Book/?D=A +http://community.bigchalk.com/servlet/schools_ProcServ/DBPAGE=cge&GID=66001000660906746080215398&PG=66001000660906746080492039 +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=16,27,29,4 +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=22,27,29,4 +http://pds.nchu.edu.tw/cpatch/ftp/dap/cdap_4002.txt +http://pds.nchu.edu.tw/cpatch/ftp/dap/source/ +http://kuyper.calvin.edu/fathers2/ANF-03/anf03-22.htm +http://kuyper.calvin.edu/fathers2/ANF-03/anf03-27.htm +http://blisty.internet.cz/1250/9908/19990813a.html +http://ring.shibaura-it.ac.jp/archives/doc/jpnic/minutes/committee/200008/shiryou-2-8-2.txt +http://194.128.65.4/pa/cm199697/cmhansrd/vo970306/text/70306w14.htm +http://www.mortgagemag.com/guide/c096/c096573.htm +http://link.fastpartner.com/do/session/600369/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/mondosoft.php +http://link.fastpartner.com/do/session/600369/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/gosafe.php +http://cometweb01.comet.co.uk/do!session=132008&vsid=692&tid=20&cid=37051&mid=1000&rid=1060&chid=1702&url=eqqLmwlGltt5tkjHfZoLlplLcqkKZljLlfb5lal5tkiLlXaLl0 +http://www.vh.org///////Patients/IHB/FamilyPractice/AFP/November1994/HormoneReplacement.html +http://ftp.sunet.se/pub/unix/OpenBSD/distfiles/md5/74892a6ae002937d011d3e1102269b7f/?M=A +http://www.pcdads.com/pressroom/archive/releases/cn112999.htm +http://www.pcdads.com/pressroom/archive/releases/Fe90199a.htm +http://www.pcdads.com/pressroom/archive/releases/Cn042199.htm +http://www.cheap-cds.com/surf/order/017172 +http://www.hani.co.kr/ECONOMY/data/9909/day09/print/p00909060.html +http://www.bemi-immobilien.de/Startseite/www.allgemeine-immobilien-boerse.de/allgemeine-ib/landkreiszwickau/Verkauf/29109700708107kirchbergvillamü/Gemeinsam/MarketingStrategie/Startseite/Gemeinsam/Inserieren/Gemeinsam/Gemeinsam/versicherungen/unfall/anforderungsformular.htm +http://www.sj-rmall.com/Mall/Catalog/Product/ASP/product-id/57419/store-id/1000400121.html +http://www.travelodge.com/ctg/cgi-bin/Travelodge/home/AAAksrACwAAABvTAAd +http://ctc.org.cn/ctc2/news/internet/develop/news0322-6.htm +http://www.schlagertempel.de/FallbachTrio/B000025MBP.htm +http://www.fogdog.com/cedroID/ssd3040183238127/nav/products/nike/1b/all/10.html +http://www.fogdog.com/cedroID/ssd3040183238127/customer_service/security_policy.html +http://in.egroups.com/login.cgi?login_target=%2Fgroup%2Fradiotutorium +http://yp.gates96.com/7/87/70/43.html +http://yp.gates96.com/7/87/70/61.html +http://yp.gates96.com/7/87/71/85.html +http://yp.gates96.com/7/87/72/75.html +http://yp.gates96.com/7/87/73/1.html +http://yp.gates96.com/7/87/73/5.html +http://yp.gates96.com/7/87/73/60.html +http://yp.gates96.com/7/87/74/34.html +http://yp.gates96.com/7/87/75/9.html +http://yp.gates96.com/7/87/75/50.html +http://yp.gates96.com/7/87/75/92.html +http://yp.gates96.com/7/87/76/2.html +http://yp.gates96.com/7/87/76/59.html +http://yp.gates96.com/7/87/76/92.html +http://yp.gates96.com/7/87/78/30.html +http://yp.gates96.com/7/87/78/32.html +http://yp.gates96.com/7/87/78/75.html +http://yp.gates96.com/7/87/78/85.html +http://yp.gates96.com/7/87/78/93.html +http://yp.gates96.com/7/87/79/30.html +http://yp.gates96.com/7/87/79/50.html +http://yp.gates96.com/7/87/79/71.html +http://yp.gates96.com/7/87/79/85.html +http://interhotel.com/luxembourg/es/hoteles/45691.html +http://interhotel.com/luxembourg/es/hoteles/73094.html +http://bart.kullen.rwth-aachen.de/~quake3/Html_log/471_chat.html +http://search.yam.com.tw/en/search/rec/travel/domest/resorts/miaolir/ +http://www.narodnaobroda.sk/19991009/23_006.html +http://news.china.com/zh_cn/social/1007/20001027/7624.html +http://www.fila.com.br/ +http://www.jobvillage.com/channel/jobs/health_care/female_health/b.3122.g.2360.html +http://online.excite.de/bildung/katalog/35461 +http://deportes.ole.com/ocio/articulo/articulo.cfm?ID=OCI8055 +http://yp.gates96.com/3/36/90/2.html +http://yp.gates96.com/3/36/90/37.html +http://yp.gates96.com/3/36/90/55.html +http://yp.gates96.com/3/36/90/79.html +http://yp.gates96.com/3/36/91/7.html +http://yp.gates96.com/3/36/92/59.html +http://yp.gates96.com/3/36/92/95.html +http://yp.gates96.com/3/36/93/76.html +http://yp.gates96.com/3/36/93/88.html +http://yp.gates96.com/3/36/94/41.html +http://yp.gates96.com/3/36/94/64.html +http://yp.gates96.com/3/36/95/16.html +http://yp.gates96.com/3/36/95/33.html +http://yp.gates96.com/3/36/95/39.html +http://yp.gates96.com/3/36/96/36.html +http://yp.gates96.com/3/36/96/53.html +http://yp.gates96.com/3/36/99/30.html +http://yp.gates96.com/3/36/99/73.html +http://download.sourceforge.net/mirrors/turbolinux/turbolinux-cn/pub/turbolinux/updates/TLC3.0.2/?S=D +http://www.jobvillage.com/channel/jobs/administrative/mrd/courier/b.4728.g.3366.html +http://www.jobvillage.com/channel/jobs/administrative/mrd/shipping_clerk/b.4713.g.3366.html +http://quote.fool.com/simple.asp?symbols=NS +http://itcareers.careercast.com/texis/it/itjs/+NwwBmeIXD86dxwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewXhmoBGnaqdGpdGwBodDaqdMp1BnGadpnGwBodD5aMw55wqr15nBB5aqdGpdGwBnahoDwDqowcaMwocaBn5BoDtapGdxcnMaMFqhTfR20DzmetmwwwpBme_9D86eYmwww5rme1DwwwBrmeZpwww/jobpage.html +http://www.shopworks.com/index.cfm/action/info/userid/00066256-1160-19FE-A703010D0A0A8CF2 +http://isbn.nu/0716723212/fatbrain +http://isbn.nu/0716723212/amazon.ceo.html +http://ftp.nacamar.de/pub/NetBSD/NetBSD-current/pkgsrc/www/p5-URI/?N=D +http://213.36.119.69/do/session/152993/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/preparer/sante.htm +http://213.36.119.69/do/session/152993/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/jeux/jeux_himalaya.html +http://213.36.119.69/do/session/152993/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/DE_DE/ +http://www.linux.com/networking/network/support/open_source/investors/consulting/ +http://www.linux.com/networking/network/support/open_source/investors/research/ +http://sunsite.uakom.sk/doc/FAQ/alt-sex/fetish-fashion/?S=A +http://sunsite.uakom.sk/doc/FAQ/alt-sex/fetish-fashion/?D=A +http://phnet.tucows.com/winme/preview/75994.html +http://www.fivedoves.com/letters/june99/trish67.htm +http://www.teacherformation.org/html/od/facilitators.cfm/task1,about/discussion_id,2/xid,8571/yid,4064381 +http://pub24.ezboard.com/fnightmagicfrm1.showMessage?topicID=3.topic +http://infoserv2.ita.doc.gov/efm/efm.nsf/Sources!OpenView&Start=53.28&Count=30&Expand=54 +http://www.linux.com/networking/network/communications/management/windows_nt/website/ +http://www.linux.com/networking/network/communications/management/windows_nt/?kw_offset=50 +http://www.epinions.com/cmd-review-593A-C9BAC2B-3987B6DC-prod1 +http://www.bande-dessinee.org/bd/bd02.nsf/InterDescenaristes!OpenView&Start=1&Count=50&Collapse=51 +http://www.business-partner.ch/static/fr/pourlesfirmes/lesgrandesentreprises/whateveryouwant/solutionsspecifiquesalabranche/transport/main.html +http://ads.carltononline.com/accipiter/adclick/site=purejamba/area=JAMBA.HOME_PAGE/AAMSZ=KSJAMBA//ACC_RANDOM=972959547161 +http://expert.cc.purdue.edu/~yoko/simpsons/front.html +http://dailynews.sina.com.cn/society/2000-06-14/97332.html +http://ftp.dti.ad.jp/pub/Linux/debian-jp/dists/potato/main/binary-all/editors/?M=A +http://www.babyheirlooms.com/catalog/htmlos.cat/041124.1.5608817466 +http://www9.hmv.co.uk:5555/do/session/1347791/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d100_sd0_pt0.html +http://www.jobvillage.com/channel/jobs/health_care/pharmaceutical/pharmacist/b.3231.g.1267.html +http://yp.gates96.com/11/24/80/12.html +http://yp.gates96.com/11/24/80/18.html +http://yp.gates96.com/11/24/80/84.html +http://yp.gates96.com/11/24/80/90.html +http://yp.gates96.com/11/24/81/6.html +http://yp.gates96.com/11/24/81/9.html +http://yp.gates96.com/11/24/81/54.html +http://yp.gates96.com/11/24/81/74.html +http://yp.gates96.com/11/24/81/98.html +http://yp.gates96.com/11/24/82/17.html +http://yp.gates96.com/11/24/82/96.html +http://yp.gates96.com/11/24/83/54.html +http://yp.gates96.com/11/24/83/58.html +http://yp.gates96.com/11/24/84/44.html +http://yp.gates96.com/11/24/84/52.html +http://yp.gates96.com/11/24/84/63.html +http://yp.gates96.com/11/24/85/35.html +http://yp.gates96.com/11/24/85/77.html +http://yp.gates96.com/11/24/85/78.html +http://yp.gates96.com/11/24/87/15.html +http://yp.gates96.com/11/24/87/77.html +http://yp.gates96.com/11/24/88/0.html +http://yp.gates96.com/11/24/88/63.html +http://yp.gates96.com/11/24/89/93.html +http://www.iabusnet.org:90/forums/aca-1/dispatch.exe/survey/listUnseen/fol/100001/20,0/2498053 +http://www.zeenzone.com/movies/1,4003,1040-21565,00.html +http://www.zeenzone.com/movies/1,4003,1040-99354,00.html +http://www.zeenzone.com/movies/1,4003,1040-109493,00.html +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/folderFrame/100001/0/author/627181 +http://moshkow.rsl.ru/alt/MORUA/letters.txt +http://members.tripod.co.jp/muttley2000/?M=A +http://www.shopworks.com/index.cfm/action/specials/userid/000A8C31-2EFD-19FE-9038010B0A0ADCF2 +http://www.bookhome.net/xiandangdai/other1/chunjiang/006.html +http://www.bookhome.net/xiandangdai/other1/chunjiang/013.html +http://www.dailyrush.dk/clans/145 +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/auto/0210/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/brandenburg/0011/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/lokales/0077/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/lokales/0009/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/lokales/0111/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/lokales/0117/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/lokales/0014/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/sport/0018/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/sport/0158/ +http://www.berlinonline.de/wissen/berliner_kurier/archiv/2000/0429/tv/0209/ +http://www.multicosm.com/facade/www.contigo.com/ +http://www.boston.digitalcity.com/cincinnati/health/conditions.dci?condition=sids +http://www.onlineathens.com/1998/041498/0414.a2zbriefs.html +http://ist.linux.tucows.com/conhtml/adnload/52224_1782.html +http://www.outpersonals.com/cgi-bin/w3com/pws/out/-2hIv4VApV7948YHO6tPdd62dgSdHSwg0xTrLhYidK4__IjhefvQTQrwpTMkkPdR5C5XRGbdA57_pJIxtMRvHJmrtjKdnzn_di6Er9p9vwIk1rLYwssqdvQbgeNAvSgd2M1a7O5NWleCth4ETxMfqPQS +http://www.outpersonals.com/cgi-bin/w3com/pws/out/VwhIXbmwUfG9PK362Tf07_xy8BQY7YBwNspFlCmPD_syQhuUcYEAU2eNoW3Liccn5fOj3JHbx2nCG9Tkl-PZwI9bR0uW5_3bO8O3kRwFm2Sp0E8MBNqJ9FvuLKt4pS_X3qzA8sbHcygn7lFrBe9ZZqi565Rs +http://www.crutchfield.com/cgi-bin/S-5ILchLS19Z9/auto.asp +http://www.quzhou.gov.cn/flfg.nsf/0a043ae26eb50247002564640039f21d/7cdda9dbc7e2b2bb002564ac00393b48!OpenDocument&ExpandSection=1,7,6 +http://opac.lib.ntnu.edu.tw/search*chi/m92+R627/m92+r627/-5,-1,0,B/buttonframe&F=m92+r449m&1,1 +http://www03.u-page.so-net.ne.jp/fc4/kazumasa/tdl/side2/side2.html +http://launchbase.com/Home/Personal_Organization/communication/information/Bank_Rates_&_Info.htm +http://launchbase.com/Home/Personal_Organization/communication/entertainment/Sports.htm +http://launchbase.com/Home/Personal_Organization/communication/shopping/Flowers.htm +http://launchbase.com/Home/Personal_Organization/communication/shopping/Pro-Audio.htm +http://www.nissan.co.jp/RENAULT-DEALERS/PASSPORT/view.cgi/admission/972959587-- +http://channel.nytimes.com/1998/10/15/technology/ +http://www.la.gunma-u.ac.jp/S97/thtml/m/kiso/41808.html +http://www1.ocn.ne.jp/~yaiba/_private/kobanasi/tyouhen/haraguroido/noroi.htm +http://www.duluxvalentine.com/FRANCE:1161209847:DFinity.1QJiP4jmPgipihoa +http://fi.egroups.com/messages/mediamalle-letter/6 +http://personal.wol.com.cn/lxz20a/gp13.htm +http://eclat.gaiax.com/www/eclat/y/k/yoko_mama/main.html +http://eclat.gaiax.com/www/eclat/y/k/yoko_mama/bbs.html +http://findmail.com/login.cgi?login_target=%2Fgroup%2Fohsama-iroiro +http://www.fogdog.com/cedroID/ssd3040183248487/crs/po__/wld/fogdog_sports/superfeet/outdoor/footwear/green_hi-profile.html +http://www.fogdog.com/cedroID/ssd3040183248487/nav/stores/baseball/ +http://www.fogdog.com/cedroID/ssd3040183248487/nav/stores/winter_sports/ +http://www.consource.com/members/signup/signup_temp_user.html?tAccountID=561 +http://213.36.119.69/do/session/152994/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/reserver/voit.htm +http://213.36.119.69/do/session/152994/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/BE_NL/ +http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdevelop/Attic/configure.in?r1=1.62&sortby=rev +http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdevelop/Attic/configure.in?annotate=1.53&sortby=rev +http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdevelop/Attic/configure.in?r1=1.46&sortby=rev +http://www.aelita.net/products/solutions/sitemap/Reg/QuoteRegister/solutions/products/default.htm +http://sunsite.org.uk/public/public/packages/pine/docs/?S=A +http://sunsite.org.uk/public/public/packages/pine/docs/QandA.txt +http://www.sfc.keio.ac.jp/~s98008na/miniproject/0.html +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959867760/Catalog/1000023 +http://www.msn.expedia.co.uk/wg/Africa/Mauritius/P39048.asp +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/asiasanahaku/rakennesuunnittelu/talonrakennus/rakennukset/ohjeet/ +http://www.ericsson.cl/education/centers/dtmexic.shtml +http://ftp.gigabell.net/debian/dists/Debian2.2r0/main/binary-powerpc/web/?S=A +http://dirs.educationamerica.net/Colorado/Localities/C/Colorado_Springs/News_and_Media/Television/ +http://polygraph.ircache.net:8181/services/define/jeff/http_-2web01.hq.cyberserv.com/ryanhomes/http_-2www.travelsc.com/cgi-bin/news/NewsList.cfm?ID=1 +http://salinas2000.com/index.cfm/r/960/a/95.htm +http://213.36.119.69/do/session/152988/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www3.travelprice.com/voyages/recherche.phtml +http://213.36.119.69/do/session/152988/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/connaitre/questions-reponses.htm +http://ftp.cpan.org/src/5.0/sperl-2000-08-05/?D=A +http://virtualpubliclibrary.com/hallofanima/moresports/JOELOUIS.ORG//hallofanima/music/ +http://x500.rz.uni-karlsruhe.de:8000/Lcn%3dMonika%20Vogel,%20ou%3dPersonalabteilung,%20ou%3dUniversitaetsleitung%20und%20-verwaltung,%20o%3dUniversitaet%20Konstanz,%20c%3dDE +http://bsd.sinica.edu.tw/cgi-bin/cvsweb.cgi/ports/korean/pine/files/patch-ai?only_with_tag=RELEASE_2_2_2 +http://ftp.ring.gr.jp/archives/XFree86/4.0.1/binaries/Linux-ix86-glibc21/RELNOTES +http://homepage1.nifty.com/SAKURAISANS/itoshi.html +http://www.expage.com/savetucker +http://ring.edogawa-u.ac.jp/archives/pack/os2/prog/rexx/?N=D +http://www.saarreisen.de/rueckel-reisen/fluege-buchen/barbados/reise-ibiza.htm +http://debian.linux.org.tw/debian/dists/sid/contrib/binary-powerpc/interpreters/?S=A +http://ricoh.co.jp/rtoss/School/other/other/lotus_syo/pg7.html +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus52213/eus52841/eus236353/eus591199/eus937052/ +http://www.mapion.co.jp/custom/AOL/admi/23/23101/higashiyamatori/4chome/index-17.html +http://stocks.tradingcharts.com/stocks/charts/swti-bb/w/javachart +http://ftp.univ-lyon1.fr/gnu/Manuals/diffutils-2.7/html_chapter/diff_15.html +http://www.elfoco.com/EL_Foco/CDA/PrintPage/1,2171,2_53_28444,00.html +http://www.debian.org.cn/Bugs/db/61/61000.html +http://www.debian.org.cn/Bugs/db/66/66591.html +http://www.debian.org.cn/Bugs/db/57/57112.html +http://www.gxrb.com.cn/26/tbzl.htm +http://opac.lib.rpi.edu/search/dyosemite+national+park+water+resources+development+research+california/-5,-1,0,E/2browse +http://ring.omp.ad.jp/pub/NetBSD/NetBSD-current/src/usr.sbin/dhcp/client/scripts/openbsd +http://attach1.egroups.com/attach/1087162/28/gs-108=71=1087162/10-1-10-160/application=octet-stream/IntOrganist.htm +http://www.brainerddispatch.com/stories/071299/obi_0712990015.shtml +http://webusers.siba.fi/doc/HOWTO/en-html/Multi-Disk-HOWTO-27.html +http://www.pressa.spb.ru/newspapers/nevrem/arts/nevrem-1667-art-30.html +http://www4.ocn.ne.jp/~l-tommy/C1024.html +http://pub13.ezboard.com/fsequelossavannasoftwaredevelopment.showMessage?topicID=74.topic +http://pub13.ezboard.com/fsequelossavannasoftwaredevelopment.showMessage?topicID=109.topic +http://www.z-plus.de/freizeit/kino/galerie/unhold/kritikdpa.html +http://www.tiscover.com/1Root/Kontinent/6/Staat/7/Bundesland/16/Ort/515/Privatvermieter/326225/Homepage/m_homepage...2.html +http://wap.jamba.de/KNet/_KNet-NKE8j1-2Gd-13c6l/showInfo-wir.de/node.0/cde7f1uou +http://www.refdag.nl/kl/990706kl02.html +http://www.ferien-immobilien.de/nordrhein-Westfalen/soest/Verkauf/Versteigerungen-IB/Startseite/Gemeinsam/versicherungen/gebaeude/Versteigerungen-IB/Startseite/Gemeinsam/Super-Zins-Konditionen/anforderungsformular.htm +http://caller-times.com/1999/september/18/today/local_sp/78.html +http://link.fastpartner.com/do/session/600350/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/mondosoft.php +http://providenet.tukids.tucows.com/mac/9-12/adnload/11899_25711.html +http://providenet.tukids.tucows.com/mac/9-12/adnload/51475_24795.html +http://fivestar.subportal.com/sn/Network_and_Internet/Dial-up_Networking_Dialers/11735.html +http://www.kenley.londonengland.co.uk/newspaperandmagazinepublishers.htm +http://builder.hw.net/frmRestDir/0,1112,'1~21~325~1~C~013800~07790',00.html +http://builder.hw.net/frmRestDir/0,1112,'1~21~325~1~C~013800~54357',00.html +http://ftp1.support.compaq.com/public/vms/vax/v6.0/sls/2.6/?M=A +http://cpan.clix.pt/authors/id/I/IL/ILYAM/Mail-CheckUser-0.15.readme +http://www.maasvlakte-cam.nl/webcams/23/stavanger__norway/2000/10/12/?D=A +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/music/midi/computers/quizz/lit/arnheim.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/music/midi/computers/quizz/misc/colorart/ +http://www.taftp.com/A555D3/WebDir.nsf/MBC!OpenView&Start=89.2&Count=30&Expand=106 +http://jundavid.subportal.com/sn/Shell_and_Desktop/Animal_Cursors/11879.html +http://www.netitor.com/photos/schools/ucla/sports/m-wpolo/98-99action/?M=A +http://cpan.nitco.com/modules/by-module/Devel/MSCHWERN/Class-DBI-0.03.readme +http://cpan.nitco.com/modules/by-module/Devel/MSCHWERN/Text-Metaphone-0.02.readme +http://www.digitaldrucke.de/(aktuell,computer,gaestebuch,kino,literatur,nuernberg,rundfunk,sense,veranstaltungen,zeitschriften)/_fort/html/themen/kultur/literat/links/bin.htm +http://194.128.65.4/pa/cm199899/cmhansrd/vo990727/text/90727w01.htm +http://194.128.65.4/pa/cm199899/cmhansrd/vo990727/text/90727w15.htm +http://213.36.119.69/do/session/152989/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/jeux/jeux_himalaya.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/misc/quizz/lit/misc/cv.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/misc/quizz/lit/misc/lit/larme.html +http://www.hblb.org.uk/hblbweb.nsf/$Pages/NewsArchive1!OpenDocument&ExpandSection=6,7,3,5,1,8,11 +http://www.identer.co.kr/삶의여유/데이트정보/데이트정보/ +http://allmacintosh.arrakis.es/adnload/54801.html +http://link.fastpartner.com/do/session/600380/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/brleksaker.php +http://link.fastpartner.com/do/session/600380/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/local/redirect.php +http://icm.html.tucows.com/adnload/001-009-003-014.html +http://www.rakuten.co.jp/coffee/forum/forum-w.cgi?p=131&url=coffee +http://jxi.gov.cn/yw-cj001.nsf/6770fc9e7685796c482568c70008a30a!OpenView&Start=69&Count=30&Expand=70 +http://jxi.gov.cn/yw-cj001.nsf/6770fc9e7685796c482568c70008a30a!OpenView&Start=69&Count=30&Expand=72 +http://freehomepage.taconet.com.tw/This/is/taconet/top_hosts//tsyang/test9g.htm +http://www11.cplaza.ne.jp/babyweb/bbs/bdnm01/no33/130N.html +http://library.cuhk.edu.hk/search*chi/a憪���/a{213972}{213230}/-5,-1,0,B/frameset&F=a{213972}{213233}{215b34}&1,1 +http://library.cuhk.edu.hk/search*chi/a憪���/a{213972}{213230}/-5,-1,0,B/frameset&F=a{213972}{21323e}{213165}+1947&1,1 +http://library.cuhk.edu.hk/search*chi/a撱嗅ˊ,+904-975./a{213d32}{213877}++904++975/-5,-1,0,B/frameset&F=a{213d32}{213a67}{213779}{213455}+china+{215f7a}{213579}{213966}{21363e}{21435a}+{214241}{213c37}&1,1 +http://www.online.kokusai.co.jp/Service/V0043539/wrd/G200/service/service.html +http://quote.morningstar.com/Quote.html?ticker=GASFX +http://uoi.linux.tucows.com/x11html/adnload/9826_7194.html +http://dk.egroups.com/post/batoco?act=forward&messageNum=2017 +http://www.chaos.dk/sexriddle/b/h/l/o/h/ +http://www.picktips.com/category-1031-1174_1171_1170-4_3_2 +http://www.schmunzelecke.de/pic18.htm +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chhand20.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chhand25.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chhand30.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chimag16.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chimag26.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chlight3.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chspec34.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chspec35.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chview15.html +http://sun1.rrzn-user.uni-hannover.de/zzzzgart/matlab/help/techdoc/umg/chvolvi5.html +http://www.t-onlien.de/dtag/mail/kontaktseite/1,3606,160,00.html +http://yumemi.ne.jp/bbs/hiroba/ky/view/h/hiroba3/8_wdsmcn_wdsmcn.html +http://yumemi.ne.jp/bbs/hiroba/ky/view/h/hiroba3/8_mrlinl_tcincn.html +http://yumemi.ne.jp/bbs/hiroba/ky/view/h/hiroba3/8_caouny_hixlcy.html +http://students.lsu.edu/students/main.nsf/c81d2bf8cb0b80ff862566fb00105ab2/7f3436ae9cb1268886256773006f9288!OpenDocument&ExpandSection=20,9,13,16 +http://www.crn.com/sections/BreakingNews/breakingnews.asp?ArticleID=5760 +http://dennou-h.ees.hokudai.ac.jp/library/Linux/debian-jp/dists/hamm/main-jp/binary-all/tex/?M=A +http://www.cmyk21.com/photo1-3.htm +http://www.cs.ruu.nl/mirror/CPAN/modules/by-category/14_Security_and_Encryption/User/ILYAZ/images/?N=D +http://www.egroups.com/login.cgi?login_target=%2Fmessage%2FFloodsystems%2F45 +http://www.mirnet.org/ccsi/nisorgs/ukraine/kyiv/renaisnc.htm +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=231&discrim=2,125,10 +http://ring.omp.ad.jp/archives/lang/perl/CPAN/authors/id/BRADAPP/PodParser-1.17.readme +http://www.amzn.com.ref.digital-price.com/redir/amzn.com/prods/0553373730 +http://library.cwu.edu/search/dGermany+--+Politics+and+government+--+1918-1933/dgermany+politics+and+government+1918+1933/-5,-1,0,B/marc&F=dgermany+politics+and+government+1918+1933+bibliography&1,1, +http://www.multicosm.com/facade/www.unisys.com/partners/default.asp?cn=su +http://enjoy100.com.cn/200006/08/sssh/sssh_ssjp.html +http://enjoy100.com.cn/200006/08/yskj/b_s_big3_f.jpg.html +http://www.hoops.ne.jp/~zuikaku/photo2000/0811/rie11.html +http://pub23.ezboard.com/fiolaniy2kmessageboardfrm1.showMessage?topicID=66.topic +http://ring.htcn.ne.jp/archives/lang/perl/CPAN/modules/by-module/CGI/ULPFR/Wais-2.301.readme +http://www3.newstimes.com/archive99/mar1199/spg.htm +http://ftp1.support.compaq.com/public/vms/axp/v6.2-1h2/dsnlink/2.2/dsnlinkd022.CVRLET_TXT +http://ftp.nacamar.de/pub/redhat/cpan/6.2/CPAN-archive/doc/manual/html/pod/perldsc.html +http://ftp.nacamar.de/pub/redhat/cpan/6.2/CPAN-archive/doc/manual/html/pod/perlfaq5.html +http://info.cs.unitn.it/sdb/de/html/keylist.SOFTWARE.html +http://www.online.kokusai.co.jp/Mmf_corner/V0043545/mmf_corner/mmf_corner/url +http://www.office.com/global/0,2724,66-15915,FF.html +http://polygraph.ircache.net:8181/home/ISO9001.htm +http://www.allgemeine-immobilien-boerse.de/niedersachsen/emsland/Verkauf/Versteigerungen-IB/Startseite/Allgemeine-IB/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/Gemeinsam/hilfe.htm +http://launchbase.com/Health/Home_Health/communication/information/Science.htm +http://library.cwu.edu/search/aLockyer,+Norman,+Sir,+1836-1920/alockyer+norman+sir+1836+1920/-17,-1,0,B/frameset&F=alockwood+victoria+s+1953&1,1 +http://bbs.kcm.co.kr/NetBBS/Bbs.dll/chbod05/lst/qqa/r/qqo/004D/zka/B2-kCYFl +http://www.egroups.com/post/bhagavad_gita?act=forward&messageNum=101 +http://carriage.de/Schoner/Literatur/info-e/Geschichte/modelle/ +http://carriage.de/Schoner/Literatur/info-e/Geschichte/history/ +http://carriage.de/Schoner/Literatur/info-e/Geschichte/literature/ +http://wwwftp.ciril.fr/pub/linux/kernel///people/andrea/kernels +http://www.inctechnology.com/guide/item/0,7462,AGD6_GDE79,00.html +http://live.sportsline.com/u/basketball/college/teams/injuries/VATECH.htm +http://www-1.cisco.com/univercd/cc/td/doc/product/lan/28201900/1928v67x/28icg67x/28icpref.pdf +http://www.hitlist.com/music/presult/003948.php3 +http://ip.tosp.co.jp/Eki/TosiE000.asp?I=Jerryfish +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=(20,0)-16,0-9,2 +http://www.bigchurch.com/cgi-bin/w3com/pws/bc/RLhIotYxW-B0bt7seq4d876RzKIuJDYbydJP1qooxhzSKDVca77BUHQv6tsO2JdNpkx837SBl7FHRIEy00rmcLBk9Y1kQEmni0_YSk5mrym8WALtovIPQU_vlEtiMcNswNyh9z6CjU-2oS2uurrk666t +http://www.secinfo.com/d2wVq.7hv.htm +http://www.secinfo.com/d2wVq.6yd.htm +http://www.secinfo.com/d2wVq.6Y5.htm +http://www.secinfo.com/d2wVq.5gf.htm +http://www.secinfo.com/d2wVq.5hp.htm +http://www.secinfo.com/d2wVq.5y4.htm +http://ring.htcn.ne.jp/pub/text/CTAN/graphics/psfig/unsupported/macdemo/macfigs/?N=D +http://ring.htcn.ne.jp/pub/text/CTAN/graphics/psfig/unsupported/macdemo/macfigs/?M=A +http://books.hyperlink.co.uk/xt2/Drakelow_Unearthed/Stokes/Paul/0904015408 +http://www.homestead.com/rebeccah/files/ +http://sunsite.compapp.dcu.ie/pub/linux/redhat/redhat-6.1/alpha/usr/share/locale/ga_IE/LC_TIME +http://www.gbnf.com/genealogy/rockwel4/html/d0037/I2684.HTM +http://www.yorosiku.net:8080/-_-http://www.dd.iij4u.or.jp/~oni9/skebe/aindex18.html +http://www.yorosiku.net:8080/-_-http://www.dd.iij4u.or.jp/~oni9/skebe/aindex12.html +http://www.yorosiku.net:8080/-_-http://www.dd.iij4u.or.jp/~oni9/skebe/atg05.html +http://shn.webmd.net/content/article/1700.50808 +http://home.clara.net/cornell/woodcraft/spring2000/contents.htm +http://dic.empas.com/show.tsp/EDACITY +http://www.sanxia.net/beauty/Eriimai/417.htm +http://www.judds-resort.com/judds/Lake-Winni-pike-lodge/97menu/fallphoto/playground/boat/photo/12.html +http://www.judds-resort.com/judds/Lake-Winni-pike-lodge/97menu/fallphoto/playground/boat/fallphoto/2.html +http://imageserver2.tibetart.com:8087/fif=fpxbuddhistreverse/56.fpx&init=0.0,0.0,1.0,1.0&rect=0.0,0.25,0.5,0.75&wid=1443&hei=400&lng=en_US&enablePastMaxZoom=OFF&page=image.html&obj=uv,1.0&cmd=W +http://www.jamba.nl/KNet/_KNet-krE8j1-KC4-pv5y/showInfo-hilfe.nl/node.0/ce6u2jadf +http://www.babyheirlooms.com/catalog/htmlos.cat/011639.1.3372173854 +http://community.webshots.com/photo/441160/441363 +http://www.kaos.dk/sexriddle/x/n/d/x/b/ +http://isbn.nu/088730866X/chapters +http://login.hq.cricinfo.org/link_to_database/ARCHIVE/1992-93/AUS_LOCAL/MMC/WA_NSW_MMC_11OCT1992.html +http://login.hq.cricinfo.org/link_to_database/ARCHIVE/1991-92/AUS_LOCAL/FAI/WA_TAS_FAI_11OCT1991.html +http://login.hq.cricinfo.org/link_to_database/ARCHIVE/1991-92/AUS_LOCAL/FAI/WA_QLD_FAI-SEMI_19OCT1991.html +http://login.hq.cricinfo.org/link_to_database/ARCHIVE/1980S/1987-88/AUS_LOCAL/MDC/WA_SOA_MDC_06MAR1988.html +http://login.hq.cricinfo.org/link_to_database/ARCHIVE/1980S/1981-82/AUS_LOCAL/MDC/QLD_WA_MDC_08NOV1981.html +http://www.chaos.dk/sexriddle/x/k/l/y/h/ +http://tucows.teihal.gr/winnt/preview/6004.html +http://tucows.teihal.gr/winnt/preview/5986.html +http://tucows.teihal.gr/winnt/preview/71328.html +http://tucows.teihal.gr/winnt/preview/2757.html +http://www.medoc-ias.u-psud.fr:81/synoptic/gif/950724/?N=D +http://www4.nas.edu/ohr.nsf/All+Documents/Major+Units?OpenDocument&ExpandSection=18,7,21,20,4 +http://members.xoom.fr/logart/Anciens/Liste25/Selection_Navlist25.html +http://polygraph.ircache.net:8181/http_-2www.arthritis.org/http_-2pathfinder.com/si/swimsuit/swim97/terms2.html +http://polygraph.ircache.net:8181/http_-2www.arthritis.org/http_-2pathfinder.com/si/swimsuit/swim97/products2.html +http://debian.linux.org.tw/debian/dists/Debian2.2r0/main/disks-m68k/current/doc/ +http://findmail.com/dir/Arts/Writing/Fan_Fiction?st=1943 +http://www.telecombroker.com/q/001p/tgcb/4izQYz7mc.htm +http://www.free-phone.com/q/001p/tgcb/ItMd2D3jdEM.htm +http://www.123bestlongdistance.com/q/001p/tgcb/msN54jfl4mE.htm +http://www.netitor.com/photos/schools/nw/sport/w-baskbl/97action/?S=A +http://excite.de/katalog/katalog/33823 +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/programs/simple/music/midi/lit/misc/unitest/programs/ +http://yp.gates96.com/14/43/40/9.html +http://yp.gates96.com/14/43/40/43.html +http://yp.gates96.com/14/43/40/82.html +http://yp.gates96.com/14/43/40/85.html +http://yp.gates96.com/14/43/41/6.html +http://yp.gates96.com/14/43/41/18.html +http://yp.gates96.com/14/43/41/44.html +http://yp.gates96.com/14/43/41/96.html +http://yp.gates96.com/14/43/42/12.html +http://yp.gates96.com/14/43/46/38.html +http://yp.gates96.com/14/43/46/66.html +http://yp.gates96.com/14/43/46/68.html +http://yp.gates96.com/14/43/47/4.html +http://yp.gates96.com/14/43/47/37.html +http://yp.gates96.com/14/43/47/64.html +http://yp.gates96.com/14/43/47/68.html +http://yp.gates96.com/14/43/47/70.html +http://yp.gates96.com/14/43/48/68.html +http://yp.gates96.com/14/43/48/69.html +http://yp.gates96.com/14/43/49/7.html +http://yp.gates96.com/14/43/49/36.html +http://yp.gates96.com/14/43/49/37.html +http://yp.gates96.com/14/43/49/52.html +http://sound-dist.secured.co.uk/cgi-bin/psProdDet.cgi/5P005|972959562|Accessories|user|0|1,0,0,1 +http://school.educities.org/card/judy180.html +http://207.138.41.133/message/the-voice1/123 +http://207.138.41.133/message/the-voice1/124 +http://www-d0.fnal.gov/d0dist/dist/releases/p05.00.00/muo_analyze/?S=A +http://sjsulib1.sjsu.edu:81/search/cernest+haberkern+director/-5,-1,0,B/frameset&cgeorge+miller+director&1,1 +http://ring.nii.ac.jp/pub/pack/x68/net/00_index.txt +http://pub24.ezboard.com/fdoyoustillneedtoventfrm43.showMessage?topicID=19.topic +http://pub24.ezboard.com/fdoyoustillneedtoventfrm43.showMessage?topicID=15.topic +http://ukinvest.ukwire.com/articles/200007200700261473O.html +http://www.brd.net/brd-cgi/brd_multimedia/lautsprecher/LZ7460LK/ci=972822952.htm +http://my.netian.com/~haeng14/tatler_july6.htm +http://genforum.genealogy.com/cgi-genforum/forums/anderton.cgi?122 +http://www.excelsior.com.mx/0001/000125/for03.html +http://www.jobvillage.com/channel/jobs/sciences/b.9070.g.1675.html +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/www/contact.html?annotate=1.19&sortby=author +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/www/contact.html?r1=1.12&sortby=author +http://www.doc.ic.ac.uk/lab/labsrc_area/firstyear/submissions/1998-99/jmc1/labs/Ex06/skw98/?N=D +http://www.jamba.de/KNet/_KNet-fNw8j1-6Fd-13acp/browse.de/node.0/cde7f1uou +http://www.jamba.de/KNet/_KNet-fNw8j1-6Fd-13act/browse.de/node.0/cdel3j591 +http://www.nedstat.nl/cgi-bin/viewstat?name=mrbertmat +http://no.egroups.com/message/acessibilidade/1092 +http://no.egroups.com/message/acessibilidade/1099 +http://sound-dist.secured.co.uk/cgi-bin/psShop.cgi/add|38P08A|972959552|Communications|user|0|1,0,0,1 +http://213.36.119.69/do/session/152990/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/reserver/spectacles/ +http://213.36.119.69/do/session/152990/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/CA_EN/ +http://wiki2.parsimony.net/wiki2954/ +http://www.f2.parsimony.net/forum2954/messages/214.htm +http://www.f2.parsimony.net/forum2954/messages/181.htm +http://www.f2.parsimony.net/forum2954/messages/292.htm +http://www.f2.parsimony.net/forum2954/messages/115.htm +http://www.f2.parsimony.net/forum2954/messages/290.htm +http://www.f2.parsimony.net/forum2954/messages/54.htm +http://home.pchome.com.tw/cool/162203/wunew15.htm +http://hem.fyristorg.com/lottaleman/LLfar/1_6721.htm +http://www.babyheirlooms.com/catalog/htmlos.cat/011628.1.4596216338 +http://www.affiliate.hpstore.hp.co.uk/do/session/380833/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/search.asp +http://www.outdoorwire.com/content/lists/dirt/200007/msg00127.html?{LoadingFrameset} +http://adept.subportal.com/sn/Programming/ActiveX/11674.html +http://www.staroriental.net/nav/soeg/ihf,aog,s0,10,Lam+Hei-Lui.html +http://www-d0.fnal.gov/d0dist/dist/releases/p05.00.01/man/?N=D +http://members.tripod.com/bluti/PSX/V/VACUUM.HTM +http://connexus.tucows.com/winme/adnload/138384_29728.html +http://wwwtios.cs.utwente.nl/archive/wilyfans/msg00265.html +http://custom.clubnet.zeelandnet.nl/eckhardt/myself.htm +http://ftp.tokyonet.ad.jp/pub/Linux/debian/dists/potato/contrib/binary-arm/otherosfs/?D=A +http://www.amcity.com/charlotte/stories/1997/07/07/daily4.html?t=email_story +http://www.generation-formation.fr/chiffrec.htm---o21zAo0UbDo0Ol9A074fo6Td4ezyr6feZJPAPfVbNyqHSezTHkekydMfeZJPdspt6dsSAtdsNhJdspt6dsrvrdjlhkfbi.htm +http://tv.thevines.com/leaf/AA0000369140/2 +http://kuyper.calvin.edu/fathers2/NPNF2-02/Npnf2-02-06.htm +http://www.intellicast.com/Ski/World/UnitedStates/Southeast/Florida/FortWaltonBeach/TEMPcast/d0_12/ +http://stevebarnes.studiostore.com/aboutus/b.EMERCH/s.P01EBK2I +http://student.monterey.edu/Students_N-R/richterheidil/private/ +http://ds.dial.pipex.com/town/drive/kch36/select/s30/ch052.html +http://ds.dial.pipex.com/town/drive/kch36/select/s30/ch027.html +http://ds.dial.pipex.com/town/drive/kch36/select/s30/ch077.html +http://ds.dial.pipex.com/town/drive/kch36/select/s30/ch092.html +http://soneraplaza.tucows.com/winme/adnload/137026_28536.html +http://www.egroups.com/post/realtyindia +http://www.kita.or.kr/untpdc/incubator/zwe/tphar/ZIMB0037.htm +http://citeseer.nj.nec.com/nrelated/126165/187254 +http://citeseer.nj.nec.com/cachedpage/187254/1 +http://citeseer.nj.nec.com/cidcontext/2417551 +http://yp.gates96.com/13/6/1/36.html +http://yp.gates96.com/13/6/1/61.html +http://yp.gates96.com/13/6/1/83.html +http://yp.gates96.com/13/6/1/91.html +http://yp.gates96.com/13/6/3/39.html +http://yp.gates96.com/13/6/3/45.html +http://yp.gates96.com/13/6/3/65.html +http://yp.gates96.com/13/6/4/46.html +http://yp.gates96.com/13/6/4/57.html +http://yp.gates96.com/13/6/5/44.html +http://yp.gates96.com/13/6/6/21.html +http://yp.gates96.com/13/6/6/42.html +http://yp.gates96.com/13/6/7/0.html +http://yp.gates96.com/13/6/7/30.html +http://yp.gates96.com/13/6/7/69.html +http://yp.gates96.com/13/6/7/82.html +http://yp.gates96.com/13/6/8/5.html +http://yp.gates96.com/13/6/8/98.html +http://yp.gates96.com/13/6/9/45.html +http://home.wanadoo.nl/hockeyclub.nieuwegein/Teams/Dames/Dames_IV/body_dames_iv.html +http://pub3.ezboard.com/fthe4thdimensiongeneralinsanity.subscribeUnregisteredToTopic?topicID=38.topic +http://pub3.ezboard.com/fthe4thdimensiongeneralinsanity.unsubscribeUnregisteredToTopic?topicID=38.topic +http://moviestore.zap2it.com/help_shipping/s.hXCLyc56 +http://www.geocities.co.jp/Outdoors/2363/typoon1.html +http://ua.php.net/manual/it/function.pg-numrows.php +http://kidneyfailure.shn.net/roundtable_reply/727640 +http://itcareers.careercast.com/texis/it/itjs/+HwwBmje0B-deZqwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewyPxGwproqamn5otDnGaoDm15BGowcamn5otDapGdm1qBamnVncdpa5dhBiwGna5BGwBnton5ah1DqBodDanD51GnaMFqnFZI0DzmzwwwpBmje0B-deZqwww5rmeZpwwwBrmeZpwww/morelike.html +http://itcareers.careercast.com/texis/it/itjs/+lwwBmex6D86egqwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewyPxGwproqamn5otDnGaoDm15BGowcamn5otDapGdm1qBamnVncdpa5dhBiwGna5BGwBnton5ah1DqBodDanD51GnaMFqnFZI0DzmzwwwpBmje0B-deZqwww5rmeacwwwBrmeZpwww/morelike.html +http://pub23.ezboard.com/fhardoverclockfrm1.showAddReplyScreenFromWeb?topicID=43.topic&index=3 +http://www.adquest3d.com/content.cfm?BRD=1578&PAG=63 +http://pelit.saunalahti.fi/.1/tucows/adnload/51_28438.html +http://pelit.saunalahti.fi/.1/tucows/preview/70307.html +http://www.maillist.com.tw/maillist/publicboard_newform.pl?maillist_id=softuse +http://dennou-t.ms.u-tokyo.ac.jp/arch/cc-env/Linux/debian-jp/dists/woody/non-free-jp/binary-alpha/news/?M=A +http://ustlib.ust.hk/search*chi/amarcot+bruce+g/amarcot+bruce+g/-5,-1,0,B/frameset&F=amarcotty+michael+1931&1,1 +http://wine.cc.chuo-u.ac.jp/home/pub/TeX/CTAN/support/rtf2tex/?M=A +http://netchief.tucows.com/winme/preview/75911.html +http://yp.gates96.com/4/57/60/83.html +http://yp.gates96.com/4/57/60/99.html +http://yp.gates96.com/4/57/62/17.html +http://yp.gates96.com/4/57/62/88.html +http://yp.gates96.com/4/57/63/9.html +http://yp.gates96.com/4/57/63/39.html +http://yp.gates96.com/4/57/63/64.html +http://yp.gates96.com/4/57/64/33.html +http://yp.gates96.com/4/57/65/41.html +http://yp.gates96.com/4/57/65/70.html +http://yp.gates96.com/4/57/66/18.html +http://yp.gates96.com/4/57/66/56.html +http://yp.gates96.com/4/57/66/61.html +http://yp.gates96.com/4/57/66/94.html +http://yp.gates96.com/4/57/67/0.html +http://yp.gates96.com/4/57/67/63.html +http://yp.gates96.com/4/57/67/85.html +http://yp.gates96.com/4/57/69/1.html +http://yp.gates96.com/4/57/69/56.html +http://citeseer.nj.nec.com/cs?q=dbnum%3D1,DID%3D9262,qtype%3Dsamesite: +http://citeseer.nj.nec.com/cidcontext/163444 +http://www.amazon.com.au/exec/obidos/change-style/tg/stores/detail/-/books/0873995562/e-mail-friend/ +http://www.sdinfonet.com.cn/411/24/411249999.htm +http://pub14.ezboard.com/fallpodsgotoroswellsayhello.threadControl?topicID=17.topic +http://in.egroups.com/message/sexualidades-noticias/14 +http://in.egroups.com/message/sexualidades-noticias/37 +http://library.cuhk.edu.hk/search*chi/dChinese+literature+--+20th+century+--+Periodicals/dchinese+literature+++20th+century+periodicals/-5,-1,0,B/frameset&F=dchinese+literature+++20th+century+periodicals&26,,188 +http://www.3w-zeitschriften.de/EyreLinda/EyreLinda1582380570.htm +http://cometweb01.comet.co.uk/do!session=132027&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkjHfZoLlplLcqkKZljLlfb5lal5tkiLlXaLl0 +http://retailer.gocollect.com/do/session/1912774/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/contact.asp +http://providenet.games.tucows.com/adnload/71993_40744.html +http://www.geocities.co.jp/playtown-Toys/6366/bbsp.html +http://www.hnby.com.cn/docroot/jzrb/200001/19/km01/19031711.htm +http://213.36.119.69/do/session/152997/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/IT_IT/ +http://www.jamba.de/KNet/_KNet-p7t8j1-FEd-139gj/showInfo-datenschutz.de/node.0/cde7f1uou +http://www.jamba.de/KNet/_KNet-p7t8j1-FEd-139gn/browse.de/node.0/cdzqggtyb +http://www.paidmania.com/getpaid/signup/42/2518 +http://www.pressa.spb.ru/newspapers/nevrem/arts/nevrem-1679-art-13.html +http://jproxy.uol.es/jproxy/http://jama.ama-assn.org/issues/current/related/joc00479.html +http://www.mirror.kiev.ua:8082/paper/2000/11/1251/text/11-08-2.htm +http://my.netian.com/~eco71/wzmain.html +http://www.craft-supplies.co.uk/cgi-bin/psProdDet.cgi/HT206|972959540|Deluxe_Dividers|user|0|0,0,1,1 +http://www.trax.nilex.co.uk/trax.cgi/A1S/1AR/A3R/B3D/A4R/A4S/ +http://www.linux.com/networking/network/network/development/project/growth/ +http://www.linux.com/networking/network/development/project/growth/sales/ +http://www.icopyright.com/1.1653.134616 +http://retailer.gocollect.com/do/session/1912718/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/about.asp +http://www.dw-tv.de/indonesia/sari_pers/19793.html +http://freethemes.netc.pt/skins/icq/preview/44470.html +http://freethemes.netc.pt/skins/icq/adnload/26145.html +http://freethemes.netc.pt/skins/icq/preview/52524.html +http://freethemes.netc.pt/skins/icq/adnload/52040.html +http://students.lsu.edu/students/main.nsf/c81d2bf8cb0b80ff862566fb00105ab2/7f3436ae9cb1268886256773006f9288!OpenDocument&ExpandSection=7,18,9,16 +http://golfonline.comfluent.net/cgi.pan$player&pga93&John_Morse&pga?golfstats +http://wai.camera.it/_presidenti/003.htm +http://www.pcmagazine.de/produkte/artikel/komp/200003/mainboards01_00-wc.html +http://www.pcmagazine.de/produkte/artikel/komp/199908/asus_00-wc.html +http://se.sslug.dk/emailarkiv/locale/2000_09/msg00053.html +http://se.sslug.dk/emailarkiv/locale/2000_09/msg00057.html +http://se.sslug.dk/emailarkiv/locale/2000_09/msg00115.html +http://www.brio.de/BRIO.catalog/39fe2f7406fad828273fd472aa7806ff/UserTemplate/8 +http://link.fastpartner.com/do/session/600389/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/jobpilot.php +http://www.shopworks.com/grizzlygulch/index.cfm/action/search/userid/000B40E3-1177-19FE-A703010D0A0A8CF2 +http://www.shopworks.com/grizzlygulch/index.cfm/action/product/prodid/0001AF94-3FC3-19E7-A703010D0A0A8CF2/userid/000B40E3-1177-19FE-A703010D0A0A8CF2 +http://spiritwolf52.subportal.com/sn/Web_Authoring/Misc__Programming_Tools/2670.html +http://www.chaos.dk/sexriddle/o/g/j/h/t/ +http://link.fastpartner.com/do/session/600394/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/learn/ +http://opac.lib.rpi.edu/search/dpolitical+corruption+united+states/-5,-1,0,B/frameset&dpolitical+corruption+united+states&7,,22 +http://cnnsi.com/baseball/mlb/news/2000/01/28/ +http://amrr.com/agents/contact.html?Agents_id=3707 +http://www.dulux.co.uk/UKRETAIL:1489107816:DFinity.1QJiP4jMomdkbEc +http://www.geocities.com/SiliconValley/Screen/9059/ +http://www.nrk.no/finnmark/x17_4_96/nyh4.htm +http://in.egroups.com/message/islaam/288 +http://www.incestpornstories.com/knocked-upepisiotomy/fertileoff-the-rag/one-night-standlubrication/japaneseslanted-eyes/{storieslink} +http://kuyper.calvin.edu/fathers2/ANF-04/anf04-30.htm +http://wuarchive.wustl.edu/systems/unix/NetBSD/NetBSD-release/src/sys/arch/sun3/stand/bootxx/ +http://polygraph.ircache.net:8181/services/define/noframes/http_-2www.microsoft.com/ie/download/http_-2www.microsoft.com/infoserv/about.html +http://pub23.ezboard.com/fferion80369frm4.showMessage?topicID=192.topic +http://pub23.ezboard.com/fferion80369frm4.showMessage?topicID=182.topic +http://www.cs.ruu.nl/mirror/CPAN/authors/id/N/NO/?S=A +http://yp.gates96.com/1/40/30/16.html +http://yp.gates96.com/1/40/30/72.html +http://yp.gates96.com/1/40/30/99.html +http://yp.gates96.com/1/40/31/25.html +http://yp.gates96.com/1/40/31/42.html +http://yp.gates96.com/1/40/31/54.html +http://yp.gates96.com/1/40/31/61.html +http://yp.gates96.com/1/40/31/95.html +http://yp.gates96.com/1/40/32/39.html +http://yp.gates96.com/1/40/32/88.html +http://yp.gates96.com/1/40/32/92.html +http://yp.gates96.com/1/40/33/33.html +http://yp.gates96.com/1/40/34/24.html +http://yp.gates96.com/1/40/34/51.html +http://yp.gates96.com/1/40/34/62.html +http://yp.gates96.com/1/40/34/72.html +http://yp.gates96.com/1/40/35/38.html +http://yp.gates96.com/1/40/36/80.html +http://yp.gates96.com/1/40/36/98.html +http://yp.gates96.com/1/40/37/35.html +http://yp.gates96.com/1/40/37/89.html +http://yp.gates96.com/1/40/38/13.html +http://yp.gates96.com/1/40/38/67.html +http://yp.gates96.com/1/40/39/8.html +http://yp.gates96.com/1/40/39/11.html +http://yp.gates96.com/1/40/39/42.html +http://netway.pda.tucows.com/palm/preview/33466.html +http://netway.pda.tucows.com/palm/preview/70276.html +http://netway.pda.tucows.com/palm/adnload/76963_22012.html +http://netway.pda.tucows.com/palm/preview/33676.html +http://www.private-immobilien-boerse.de/berlin-immobilien/verkauf/Private-IB/Startseite/Gemeinsam/versicherungen/gebaeude/Gemeinsam/Immolink/Gemeinsam/Super-Zins-Konditionen/anforderungsformular.htm +http://www.ne.jp/asahi/matinami/gallery/mati/hokkaido/hakodate/ph_l011.html +http://www.findarticles.com/cf_0/m0EKF/14_46/61415465/p1/article.jhtml +http://www.trax.nilex.co.uk/trax.cgi/A1C/A2S/B1S/B1L/B4S/A1S/ +http://students.lsu.edu/students/main.nsf/c81d2bf8cb0b80ff862566fb00105ab2/7f3436ae9cb1268886256773006f9288!OpenDocument&ExpandSection=1,21,16,5 +http://students.lsu.edu/students/main.nsf/c81d2bf8cb0b80ff862566fb00105ab2/7f3436ae9cb1268886256773006f9288!OpenDocument&ExpandSection=18,21,16,5 +http://ddb.libnet.kulib.kyoto-u.ac.jp/exhibit/fl3/image/fl3lhf/fl3lh0344.html +http://www.trnonline.com/archives/2000archives/04072000/sports/26732.shtml +http://www.linux.com/networking/network/new/press_release/management/editor/ +http://www.linux.com/networking/network/new/press_release/management/experiences/ +http://jundavid.subportal.com/sn/Business/Misc__Phone_Tools/index3.html +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=27,9,23,14,19 +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/music/misc/thoughts/lit/music/midi/mirroring.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/music/misc/thoughts/lit/music/midi/legendes/ +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/music/misc/thoughts/lit/music/midi/lit/laurent.txt +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/music/misc/thoughts/lit/music/midi/misc/colorart/ +http://www.lz.gs.cninfo.net/news/shenghuo/messages/361.html +http://www.egroups.com/messages/skarmflyg/683 +http://www.egroups.com/message/skarmflyg/675 +http://www.egroups.com/message/skarmflyg/681 +http://www.genoma.de/shop/0d79e8c12cc42ea8242eafc8a0c5586a/99/b +http://travelocity-dest.excite.com/Vacations/Reviews/Cruise/Submit/1,2586,0_228__,00.html +http://www02.geocities.co.jp/HeartLand-Sakura/1068/history.html +http://www.streetprices.com/Electronics/Computer_Software_PC/Programming/MAKE+DIGITAL/sortproductbyhighprice/SP275945.html +http://www.streetprices.com/Electronics/Computer_Software_PC/Programming/MAKE+DIGITAL/sortproductbyhighprice/SP246217.html +http://www.emerchandise.com/help_privacy/b.TV%20SATNIGHTLIVE/s.BOkfj8Vk +http://ftp.ccu.edu.tw/pub/documents/faq/mail/setup/?S=A +http://iceberg.adhomeworld.com/cgi-win/redirect.exe/304063772 +http://pdacentral.zeelandnet.nl/rim/email_license.htm +http://pdacentral.zeelandnet.nl/rim/adnload/139471_47673.html +http://www.loisirs.ch/tfhglx/17/ltxeld.html +http://au.yahoo.com/Business_and_Economy/Shopping_and_Services/Health/Providers/By_Region/U_S__States/Mississippi/Cities/ +http://sound-dist.secured.co.uk/cgi-bin/psProdDet.cgi/15P02A|972959527|Helmet|user|0|1,0,0,0 +http://news.dreamwiz.com/news_lg/04/20001030/yonhap/200010301014041007292.html +http://news.dreamwiz.com/news_lg/04/20001028/yonhap/ +http://pds.nchu.edu.tw/cpatch/ftp/ftpnav/?D=A +http://members.tripod.lycos.co.kr/BONGBAE/?N=D +http://www9.hmv.co.uk:5555/do/session/1347758/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d50_sd0_pt0.html +http://itcareers.careercast.com/texis/it/itjs/+xwwBmeHWD86YwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewDhmoBGnaqdGpdGwBodDarGo5awDwcO5Baiw5roDtBdDaGn31n5BaGn31oGnmamnVncdpar1MwDaGn5d1Gqn5aMFqhTfR20DzmehrwwwpBmefWD86mwww5rmeddwwwBrmeZpwww/morelike.html +http://www.3w-buecher.de/GibbonsRob/GibbonsRob1572152214.htm +http://sennka.hoops.livedoor.com/%91%90%8a%a0%93%fa%98a%81%f4.htm +http://www.uni-duesseldorf.de/ftp/ftp/pf/s/netscape-v451/?S=A +http://www.outpersonals.com/cgi-bin/w3com/pws/out/0nhIQeA1Kelaujy0pUaBOo2AAoNruJ7MPpvxwl5qu-YeCeEn6SDc5vURHb5rk8dZP84c_4bSWkIDaPe8dCV5mfxj4LA69UDbXc_J2Z-eZg7dURZLZinceqCXYFUYC4pqT29R1BQKpdPvHP0APgIYRhQG +http://208.178.109.85/msgshow.cfm/msgboard=4779506785434&msg=80064825094809&page=1&idDispSub=-1 +http://interbox.tucows.com/preview/61367.html +http://www.crutchfield.com/cgi-bin/S-CI62JsDkHYX/viewcart.asp +http://www.hig.se/(aconf,formoutput,if,modified,set_cookie)/~jackson/roxen/ +http://www.trax.nilex.co.uk/trax.cgi/A1C/1AS/B1D/A3L/A1S/1AR/ +http://www.trax.nilex.co.uk/trax.cgi/A1C/1AS/B1D/A3L/A1S/C1R/ +http://www.trax.nilex.co.uk/trax.cgi/A1C/1AS/B1D/A3L/A1S/B4L/ +http://www.haikou.hi.cn/pandect/nj/n96ei3.htm +http://se.egroups.com/message/dailydreamers/36 +http://sunsite.org.uk/Mirrors/ftp.cdrom.com/pub/linux/slackware/contrib/contrib-sources/gcc-2.7.2.3/ +http://hp-partner.whowhere.lycos.com/hp/excite/Online_Communities/Angelfire/wi/index9.html +http://www.cse.unsw.edu.au/archives/linux/redhat/beta/?M=A +http://www.webcrawler.com/entertainment/music/artists_and_genres/folk_and_acoustic/artists_s/simon_and_garfunkel/garfunkel_art/interviews/ +http://www.russ.ru:8081/journal/media/98-05-21/telen0.htm +http://www.chaos.dk/sexriddle/x/r/k/o/w/ +http://www.jt.com.br/noticias/98/06/22/sd2.htm +http://retailer.gocollect.com/do/session/1912734/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/gifts/gift_floor.asp +http://www.ualberta.ca/CNS/RESEARCH/Software/SAS/gis/z0782606.htm +http://www.sentientnet.com/univercd/cc/td/doc/product/rtrmgmt/bluelist/cwblue21/cwbwsug/features.htm +http://pub5.ezboard.com/fthekojiroestrogenbrigadeconsolegaming.threadControl?topicID=16.topic +http://www.zjrs.zei.gov.cn/economy/text/policy/LHB/LHBA0909.TXT +http://seascape.tucows.com/winnt/adnload/2060_29646.html +http://seascape.tucows.com/winnt/adnload/2063_29648.html +http://seascape.tucows.com/winnt/adnload/2066_29651.html +http://ben.aspads.net/ex/c/641/517693268 +http://yp.gates96.com/7/63/80/20.html +http://yp.gates96.com/7/63/80/22.html +http://yp.gates96.com/7/63/80/80.html +http://yp.gates96.com/7/63/80/87.html +http://yp.gates96.com/7/63/81/50.html +http://yp.gates96.com/7/63/81/77.html +http://yp.gates96.com/7/63/81/79.html +http://yp.gates96.com/7/63/81/91.html +http://yp.gates96.com/7/63/82/36.html +http://yp.gates96.com/7/63/82/73.html +http://yp.gates96.com/7/63/84/6.html +http://yp.gates96.com/7/63/84/91.html +http://yp.gates96.com/7/63/85/30.html +http://yp.gates96.com/7/63/85/57.html +http://yp.gates96.com/7/63/85/98.html +http://yp.gates96.com/7/63/89/13.html +http://yp.gates96.com/7/63/89/20.html +http://yp.gates96.com/7/63/89/32.html +http://yp.gates96.com/7/63/89/65.html +http://www.rarf.riken.go.jp/archives/tex-archive/macros/latex//contrib/supported/linguex/?M=A +http://members.tripod.com/shelly34/shellyphotos/page12.html +http://ftp.nsysu.edu.tw/Unix/Perl/modules/by-category/23_Miscellaneous_Modules/Bundle/PlRPC-0.2003.readme +http://www.affiliate.hpstore.hp.co.uk/do/session/380827/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/SMARTTIPS/vacationcards.asp +http://www.marktplatz-hs.de/cgi-bin/ChioEditionShop.s/39fe2ee3005fd9642740d47540f806e1/IconBar +http://home.sprynet.com/~keithco/london.htm +http://earth.collectingnation.com/cgi-bin/bn/post.mod/aupn?B=cna&R=48 +http://earth.collectingnation.com/cgi-bin/bn/post.mod/aupn?B=cna&R=38 +http://www.realize.com/am747b81.htm,qt=e784fe2f=2a38a234-e-1adebfb-80000000-0-0-3-- +http://www.opengroup.com/dfbooks/009/0091856140.shtml +http://www.egroups.org/message/fotografya/216 +http://www.cn.informatik.fh-furtwangen.de/studenten/dv_labor/onlinebuecher/php/function.yaz-errno.html +http://www.cn.informatik.fh-furtwangen.de/studenten/dv_labor/onlinebuecher/php/function.yaz-hits.html +http://www.cn.informatik.fh-furtwangen.de/studenten/dv_labor/onlinebuecher/php/function.yaz-wait.html +http://www.catholicstore.com/search/index.cfm/FuseAction/detailSearch/SKU/17311/category/Bo/subCategory/G/subject/1 +http://www.cc.ntut.edu.tw/~584ce040/anne-1.htm +http://www.intervoz.com.ar/2000/09/23/sociedad_n11.htm +http://pub22.ezboard.com/frecipegoldminesharearecipe.showAddReplyScreenFromWeb?topicID=4.topic +http://opencity.kulichki.ru/moshkow/PROZA/LIPSKEROV/okno.txt +http://www.tccomputers.com/cgi-bin/bp/1021890426/products/modems/modems.htm +http://www.tccomputers.com/cgi-bin/bp/1021890426/services/sitemap.htm +http://library.bangor.ac.uk/search/dCrystallography+--+Periodicals/dcrystallography+periodicals/-5,-1,0,B/frameset&F=dcrystallography+mathematical&8,,9 +http://music.excite.ca/artist/-264813 +http://www.gameboyz.com/g/review_465_p4_n3.html +http://library.cwu.edu/search/aCarande,+Robert/acarande+robert/-5,-1,0,B/2exact&F=acarande+robert&1,2 +http://www.townstuff.com/search.cfm?directory=1040&town=285 +http://bsd.sinica.edu.tw/cgi-bin/cvsweb.cgi/ports/graphics/png/files/patch-aa?only_with_tag=RELEASE_2_2_7 +http://www.amcity.com/columbus/stories/1997/07/07/focus6.html?t=email_story +http://retailer.gocollect.com/do/session/1912716/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/checkout/shopping_cart.asp +http://ds.dial.pipex.com/town/drive/kch36/select/s12/ch034.html +http://ds.dial.pipex.com/town/drive/kch36/select/s12/ch118.html +http://www.dbring.de/160/16005-09.html +http://198.103.152.100/search*frc/lHQ+769+E3614/lhq++769+e3614/7,-1,0,B/frameset&F=lhq++777.4+d47&1,1 +http://yp.gates96.com/7/27/70/14.html +http://yp.gates96.com/7/27/70/27.html +http://yp.gates96.com/7/27/70/35.html +http://yp.gates96.com/7/27/70/37.html +http://yp.gates96.com/7/27/70/62.html +http://yp.gates96.com/7/27/71/38.html +http://yp.gates96.com/7/27/71/80.html +http://yp.gates96.com/7/27/72/62.html +http://yp.gates96.com/7/27/72/80.html +http://yp.gates96.com/7/27/73/10.html +http://yp.gates96.com/7/27/73/61.html +http://yp.gates96.com/7/27/73/78.html +http://yp.gates96.com/7/27/74/7.html +http://yp.gates96.com/7/27/74/16.html +http://yp.gates96.com/7/27/75/62.html +http://yp.gates96.com/7/27/76/90.html +http://yp.gates96.com/7/27/77/7.html +http://yp.gates96.com/7/27/77/92.html +http://yp.gates96.com/7/27/78/21.html +http://yp.gates96.com/7/27/79/21.html +http://yp.gates96.com/7/27/79/57.html +http://yp.gates96.com/7/27/79/96.html +http://moviestore.zap2it.com/help/b.STARWARSSAGA%20STARWARS-ROJ/s.nrF6V2sr +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=8,27,13,5 +http://newspaper.swww.com.cn/1999/cdwb/199912/26/html/1003.html +http://newspaper.swww.com.cn/1999/cdwb/199912/26/html/1008.html +http://iworld.freethemes.com/adnload/77752.html +http://iworld.freethemes.com/adnload/15251.html +http://iworld.freethemes.com/adnload/54697.html +http://iworld.freethemes.com/adnload/15232.html +http://www.fogdog.com/cedroID/ssd3040183238457/nav/products/ice_hockey/1d/gear_accessories/ +http://www.ftp.uni-erlangen.de/pub/Linux/DEBIAN/dists/Debian2.2r0/main/binary-m68k/doc/ +http://www.ftp.uni-erlangen.de/pub/Linux/DEBIAN/dists/Debian2.2r0/main/binary-m68k/sound/ +http://library.cwu.edu/search/aThimbleby,+Harold/athimbleby+harold/-5,-1,0,B/exact&F=athilde+jean&1,2 +http://www5.pconline.com.cn/pcedu/soft/doc/001024/2.htm +http://member.nifty.ne.jp/kaito-mist/nifty5.htm +http://www.cc.yamaguchi-u.ac.jp/~archive/doc/jdk1.2.2/docs/api/java/awt/image/BandedSampleModel.html +http://www.sandiego.digitalcity.com/honolulu/arts/occurrence.dci?ecid=75 +http://ubahn.exit.de/ffm/pic/pp/?S=A +http://www.visiobroker.com/opcvm/details/4/43591.html +http://www.visiobroker.com/opcvm/details/9/9765.html +http://ring.toyama-ix.net/archives/linux/debian/debian-jp/dists/woody-towns/?M=A +http://www.asahi-net.or.jp/~ZI3H-KWRZ/lawylegalaid.html +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/195/1999/7/0/ +http://www.buybuddy.com/sleuth/27/1/1060103/490578/ +http://java.javasoft.com/products/jdk/1.2/ja/docs/ja/api/java/awt/image/BandedSampleModel.html +http://mitglied.tripod.de/~HTTC/mannschaften/3LigaGr1_0001.htm +http://opac.lib.rpi.edu/search/anightingale+peggy+1942/-5,-1,0,B/browse +http://ftp.unina.it/pub/Amiga/NetBSD/NetBSD-current/pkgsrc/editors/ssam/files/ +http://kikakusvr3.city.yokohama.jp/y/j/e25/ktt/ktt.html +http://members.spree.com/entertainment/juskickit/http//members.spree.com/sports/comicus1 +http://www.butuanon.tsx.org/ +http://archive.soccerage.com/s/de/07/05375.html +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/151/1995/10/0/859255/ +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/151/1995/10/50 +http://polygraph.ircache.net:8181/http_-2www.soniajekums.com/docs/Http_-2ua.battle-zone.com/html/html/on_line.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380855/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-creativeworld.com/creativeworld.asp?lang=f +http://mirror.cc.utsunomiya-u.ac.jp/mirror/CPAN/authors/id/T/TO/TOSTI/vstadaf-0.01.readme +http://www.xmission.com/~dkenison/cgi/lwgate.cgi/KLR650/archives/v02.n1633/Subject/article-16.html +http://www.realize.com/p25581.htm,qt=e784fe2f=2a38a234-7-da710e-0-0-0-1-- +http://www.realize.com/am947681.htm,qt=e784fe2f=2a38a234-7-da6e1d-80000000-0-0-3-- +http://www.realize.com/am2c3a81.htm,qt=e784fe2f=2a38a234-7-da6e1d-80000000-0-0-3-- +http://www.realize.com/amd15381.htm,qt=e784fe2f=2a38a234-7-da6e1d-1-84-0-3-- +http://link.fastpartner.com/do/session/600403/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/speednames.php +http://home.freeuk.net/lyne/work.htm +http://www.gotocity.com/local/2/us/AZ/p/85643/people/ +http://www.service911.com/egghead/step/0,2743,6+33+121+25440+18092_4,00.html +http://www.jamba.de/KNet/_KNet-irv8j1-WEd-139z7/showInfo-werbung.de/node.0/cenv0b09a +http://ustlib.ust.hk/search*chi/dbeijing+mandarin+dialects+china+slang/dbeijing+mandarin+dialects+china+slang/-5,1,1,B/frameset&F=dbeijing+mayors+china+fiction&1,1, +http://www.linux.org.tw/~chester/xlib/GC/convenience-functions/XSetGraphicsExposures.html +http://www.linux.org.tw/~chester/xlib/graphics/font-metrics/XUnloadFont.html +http://www.chaos.dk/sexriddle/c/f/j/u/c/ +http://www.chaos.dk/sexriddle/c/f/j/u/q/ +http://www.bornloser.com/comics/committed/archive/committed-20001027.html +http://tulips.ntu.edu.tw/search*chi/dDeath+lc/ddeath+lc/-17,-1,0,E/frameset&F=ddeath+in+adolescence+abstracts&1,,0 +http://hem.fyristorg.com/lottaleman/LLfar/1_6955.htm +http://preview.egroups.com/post/scoresheet-talk?act=reply&messageNum=7013 +http://209.52.189.2/profile.cfm/TimmyJ +http://archive.soccerage.com/s/pt/37/04816.html +http://pub16.ezboard.com/fleftbehindmessageboardfellowshiphall.showMessage?topicID=456.topic&index=16 +http://www.2pl.com/asp/tools/fili1.asp?sp=se&fi=pppp0005s8 +http://link.fastpartner.com/do/session/600382/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/company/jobs.htm +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kdenetwork/kppp/Rules/Poland/?only_with_tag=MAIN +http://genforum.genealogy.com/cgi-genforum/forums/flippin.cgi?30 +http://pub.chinaccm.com/23/news/200010/28/114339.asp +http://pub.chinaccm.com/23/news/200010/27/134259.asp +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=21,9,14,35,15 +http://gamesearcher.com/games/pc/returnofphantom-cheatsfaqs.html +http://ua.php.net/manual/es/function.pg-errormessage.php +http://findmail.com/group/prairydog +http://www.loria.fr/projets/dilib/DILIB_ROOT/SYSTEMS/Linux/Dilib/Data/NLM/MedLine/ +http://www.daysinn.com/ctg/cgi-bin/DaysInn/programs/AAAksrACwAAACEaAAQ +http://www.leo.org/leoclick/35dd60550f1ba90ed5bb7952eebae0d3+L+1__ +http://members.fortunecity.com/abbalink/songs/lyrics/wg.htm +http://chat.sportsline.com/u/football/nfl/xword/answers/091500.htm +http://210.173.172.13/entertainments/sports/sydney/kanrenkiji/0924/0925m096-500.html +http://210.173.172.13/entertainments/sports/sydney/kanrenkiji/0924/0925m094-500.html +http://www.private-immobilien-boerse.de/nordrhein-Westfalen/Muehlheim-ruhr/Verkauf/3d-service/Gemeinsam/Inserieren/3d-service/Gemeinsam/versicherungen/gebaeude/deckungsumfang.htm +http://www.private-immobilien-boerse.de/nordrhein-Westfalen/Muehlheim-ruhr/Verkauf/3d-service/Gemeinsam/Inserieren/3d-service/Gemeinsam/IIMMitglieder.htm +http://www.realize.com/amcf7781.htm,qt=e784fe2f=2a38a234-4-7cf2ef-80000000-0-0-3-- +http://family.go.com/Categories/Features/family_1998_12/penn/penn128urban/ +http://www.loria.fr/projets/dilib/DILIB_ROOT/ApplicationsTest/Dilib/newBD/Prog/?N=D +http://www.loisirs.ch/xfeoav/7/kqbmsh.html +http://tucows.tu-graz.ac.at/herdwin0807.html +http://www-d0.fnal.gov/cgi-bin/cvsweb.cgi/gtr_htf/dat/?sortby=log +http://www.buybuddy.com/sleuth/17/1/2006/32619/ +http://www.aelita.net/products/Reg/QuoteRegister/products/library/products/company/Privacy.htm +http://www.refdag.nl/bui/990803bui08.html +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+9,6-14,0+0,2 +http://www.aelita.net/products/services/support/sitemap/news/solutions/default.htm +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=26,5,30,16,12 +http://www.ericsson.cl/gsmpro/contact.shtml +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/maheuitu/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mangoo333/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/maomizhijia/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/masaki_hamada/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/maxiaofei/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/maz0503/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/menghuanboy/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/michealshen/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mike717/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mikeshang_2/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mingyueyaze/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mm3/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mnbv89/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/morsia/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/move/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mslug/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/msshi/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/muwei/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/my1799/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mychat2000/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/myesky/ +http://members.tripodasia.com.cn/maolin_photo/maolin_suzuki/maolin_suzuki/mzlzq/ +http://www.ring.gr.jp/pub/linux/Vine/VineSeed/alpha/mnt/source/sbin/loader +http://www.nrk.no/finnmark/x8_5_96/nyh7.htm +http://202.99.23.245/rmrb/200001/27/no_txb_6.html +http://www-d0.fnal.gov/d0dist/dist/releases/test/smt_hit/test/?N=D +http://www-d0.fnal.gov/d0dist/dist/releases/test/smt_hit/test/LIBRARIES +http://jupiter.u-3mrs.fr/~msc41www/releves/13440405.HTM +http://ftp.univie.ac.at/packages/perl/modules/by-category/15_World_Wide_Web_HTML_HTTP_CGI/CGI/ANDK/Apache-correct_headers.readme.html +http://www.linux.com/networking/network/networking/free/windows_nt/distro/ +http://www.linux.com/networking/network/networking/free/windows_nt/tip/ +http://australia-holiday-guide.com/Englisch/Queensland_1/QLD_Furher_North_1/qld_further_north_1.html +http://australia-holiday-guide.com/Englisch/Queensland_1/QLD_Great_Barrier_Reef_1/qld_great_barrier_reef_1.html +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/Ayrton.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/Deadline_1.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/DiamondPPC.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/Gravity2_inv.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/HJB-BCFix.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/ImpPos.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/Nat-AutF.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/PSB-Desperado2.readme +http://ftp.uni-paderborn.de/aminet/aminet/demo/aga/PSB-PUK_final.readme +http://genforum.genealogy.com/cgi-genforum/forums/kilroy.cgi?34 +http://genforum.genealogy.com/cgi-bin/print.cgi?kilroy::34.html +http://content.health.msn.com/ef/message/803324/content.health.msn.com%2fmessage_board_message%2f803324/803324 +http://de.excite.de/gesundheit/katalog/6107 +http://de.excite.de/gesundheit/katalog/4909 +http://de.excite.de/gesundheit/katalog/5941 +http://de.excite.de/gesundheit/katalog/4924 +http://de.excite.de/gesundheit/katalog/5898 +http://de.excite.de/gesundheit/katalog/4949 +http://de.excite.de/gesundheit/katalog/5987 +http://de.excite.de/gesundheit/katalog/5855 +http://de.excite.de/gesundheit/katalog/39862 +http://de.excite.de/gesundheit/katalog/5852 +http://de.excite.de/gesundheit/katalog/5645 +http://de.excite.de/gesundheit/katalog/6078 +http://de.excite.de/gesundheit/katalog/5834 +http://yp.gates96.com/11/26/80/31.html +http://yp.gates96.com/11/26/80/47.html +http://yp.gates96.com/11/26/80/91.html +http://yp.gates96.com/11/26/81/61.html +http://yp.gates96.com/11/26/81/86.html +http://yp.gates96.com/11/26/82/37.html +http://yp.gates96.com/11/26/82/49.html +http://yp.gates96.com/11/26/83/38.html +http://yp.gates96.com/11/26/83/52.html +http://yp.gates96.com/11/26/83/58.html +http://yp.gates96.com/11/26/83/84.html +http://yp.gates96.com/11/26/84/0.html +http://yp.gates96.com/11/26/84/59.html +http://yp.gates96.com/11/26/84/75.html +http://yp.gates96.com/11/26/84/99.html +http://yp.gates96.com/11/26/85/37.html +http://yp.gates96.com/11/26/85/63.html +http://yp.gates96.com/11/26/85/78.html +http://yp.gates96.com/11/26/86/36.html +http://yp.gates96.com/11/26/86/40.html +http://yp.gates96.com/11/26/87/66.html +http://yp.gates96.com/11/26/87/87.html +http://yp.gates96.com/11/26/89/7.html +http://yp.gates96.com/11/26/89/21.html +http://yp.gates96.com/11/26/89/38.html +http://providenet.tukids.tucows.com/mac/9-12/macspell912_license.html +http://providenet.tukids.tucows.com/mac/9-12/adnload/25805_25780.html +http://www04.u-page.so-net.ne.jp/zb3/eiji-m/dog6.htm +http://school.educities.org/card/jou0731.html +http://school.educities.org/card/ke234.html +http://school.educities.org/card/aaaaaqqqqqqq.html +http://school.educities.org/card/cso.html +http://school.educities.org/card/g40203.html +http://school.educities.org/card/h123915388.html +http://school.educities.org/card/k1084211.html +http://www.cigar-pipe.de/SP/dhuc3112.htm +http://www.newquestcity.com/cities/MA///news/3675.htm +http://caowei_814.home.chinaren.com//wenxue/wenxue-mood/love147.htm +http://www.amulation.com/md-l-archive/199805/msg00065.html +http://in.egroups.com/messages/conventions/51?viscount=-30 +http://yp.gates96.com/11/63/20/4.html +http://yp.gates96.com/11/63/20/21.html +http://yp.gates96.com/11/63/20/51.html +http://yp.gates96.com/11/63/21/29.html +http://yp.gates96.com/11/63/21/41.html +http://yp.gates96.com/11/63/21/74.html +http://yp.gates96.com/11/63/22/4.html +http://yp.gates96.com/11/63/22/29.html +http://yp.gates96.com/11/63/22/80.html +http://yp.gates96.com/11/63/22/86.html +http://yp.gates96.com/11/63/23/7.html +http://yp.gates96.com/11/63/23/24.html +http://yp.gates96.com/11/63/23/39.html +http://yp.gates96.com/11/63/24/1.html +http://yp.gates96.com/11/63/25/35.html +http://yp.gates96.com/11/63/25/78.html +http://yp.gates96.com/11/63/25/83.html +http://yp.gates96.com/11/63/26/37.html +http://yp.gates96.com/11/63/27/3.html +http://yp.gates96.com/11/63/27/9.html +http://yp.gates96.com/11/63/27/14.html +http://yp.gates96.com/11/63/28/16.html +http://yp.gates96.com/11/63/28/26.html +http://yp.gates96.com/11/63/28/54.html +http://yp.gates96.com/11/63/28/55.html +http://yp.gates96.com/11/63/29/13.html +http://yp.gates96.com/11/63/29/64.html +http://yp.gates96.com/11/63/29/69.html +http://spaceports.tucows.com/winnt/httpservernt_license.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380848/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/FR/REGISTRATION/entry.asp +http://incrediblegolfsavings.subportal.com/sn/Games/Simulation_Games/11310.html +http://incrediblegolfsavings.subportal.com/sn/Games/Simulation_Games/12064.html +http://www.linux.com/networking/linux/industry/gnu/operating_system/Corel/ +http://www.linux.com/networking/linux/industry/gnu/operating_system/Updates/ +http://www.fogdog.com/cedroID/ssd3040183307418/womens/ +http://www.fogdog.com/cedroID/ssd3040183307418/nav/products/featured_brands/1o/casual_sunglasses/ +http://www.fogdog.com/cedroID/ssd3040183307418/nav/products/featured_brands/1o/hockey_skates/ +http://www.fogdog.com/cedroID/ssd3040183307418/nav/products/featured_brands/1o/sweatshirts_fleece/ +http://www.fogdog.com/cedroID/ssd3040183307418/crs/nvCZ/wld/fogdog_sports/nike/football/equipment/500r_series_football.html +http://www.seoul.co.kr/dmaeil/199908/0820j015.htm +http://www-trn.bards.ru/Lobanovskiy/part13.htm +http://www-trn.bards.ru/Vahnuk/part27.htm +http://www-trn.bards.ru/Vetrova_Svetlana/part9.htm +http://www-trn.bards.ru/Tretiyakov/part22.htm +http://www-trn.bards.ru/Okoudjava/part202.htm +http://www-trn.bards.ru/Panyushkin/part100.htm +http://www-trn.bards.ru/Gorodnicky/part287.htm +http://yumemi.ne.jp/bbs/ky/view/f/forum9/1_jpbshj_vvvzil.html +http://yumemi.ne.jp/bbs/ky/view/f/forum9/1_xxosis_czhmrb.html +http://yumemi.ne.jp/bbs/ky/view/f/forum9/1_yikriy_qjvins.html +http://www.peopledaily.co.jp/shch/199907/28/newfiles/D103.html +http://legalminds.lp.findlaw.com/list/newlawbooks-l/frm00336.html +http://tucows.sp-plus.nl/winme/phoneme.html +http://ustlib.ust.hk/search*chi/dalcoholic+beverages+china/dalcoholic+beverages+china/7,-1,0,E/2browse +http://ustlib.ust.hk/search*chi/dalcoholic+beverages+china/dalcoholic+beverages+china/-5,-1,0,E/frameset&F=dalcoholic+beverages+great+britain&1,,0 +http://www.canit.se/(k10,k13,k16,k6)/support/faq/faq.html +http://aecjobbank.com/texis/script/jobbank/+Owwrmwxeri2wBV6evNVpwwwF6eWYqkwwwn6eXmcOwwwn6ekmyjwwwn6eULpOwwqn6eUCBZwwwn6e22QuwwwefPY9GepmwwmeiP46eczdwwmeOTB6eXhzwwwnmBVve89AHwwxeY44Ie-pxwww+vejWRhwwxealYTeXjzwwwhvep9q9wwwxveoA6kwwqe0PYieqFzwwwv6eFRFrwwwt6eSGxDwwwetNY1e8drwwqeT53Amwww0h7mwww1tzmwwweb-3qmwwww/jobdirectory.html +http://www9.hmv.co.uk:5555/do/session/1347780/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/newmenu.html +http://www9.hmv.co.uk:5555/do/session/1347780/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d30_sd0_pt0.html +http://www9.hmv.co.uk:5555/do/session/1347780/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d70_sd0_pt0.html +http://www9.hmv.co.uk:5555/do/session/1347780/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d90_sd0_pt0.html +http://www9.hmv.co.uk:5555/do/session/1347780/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d120_sd0_pt0.html +http://www.hbdaily.com.cn/hbrb/20000622/BIG5/hbrb^18323^12^0622h016.htm +http://excite.de/immobilien/katalog/6877 +http://excite.de/immobilien/katalog/7012 +http://www.globalmart.com/housewares/appliances/household/irons/blackanddecker/S680.htm +http://mediate.magicbutton.net/do/session/625631/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-artc.html +http://ddb.libnet.kulib.kyoto-u.ac.jp/exhibit/mt3/image/mt3shf/mt3sh0192.html +http://us.parsimony.net/forum26166/messages/410.htm +http://linux.tnc.edu.tw/CPAN/authors/id/A/AZ/AZEMGI/?M=A +http://linux.tnc.edu.tw/CPAN/authors/id/A/AZ/AZEMGI/CHECKSUMS +http://launchbase.com/Shopping/Visual_Arts/communication/entertainment/Pictures_&_Images.htm +http://launchbase.com/Shopping/Visual_Arts/communication/shopping/Gifts.htm +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/programs/simple/music/midi/lit/lit/quizz/quizz1.html +http://home02.wxs.nl/~nash0002/amber-94.htm +http://www.redrocksports.com/sports/webSession/shopper/RR972959711-31098/store/dept-5/department/dept-5/item/52400 +http://www.redrocksports.com/sports/webSession/shopper/RR972959711-31098/store/dept-5/department/dept-5/item/52550 +http://www.redrocksports.com/sports/webSession/shopper/RR972959711-31098/store/dept-5/department/dept-5/item/50900 +http://gnu.archive.sunet.se/software/sather/ICSI_Sather/Documentation/Compiler/CompilerBrowser/shortflat-FLIST{_}.html +http://mailman.real-time.com/rte-crossfire/1992/Dec/mail1.html +http://de.nedstat.net/viewstat.asp?name=larsen +http://ftp.ring.gr.jp/archives/pc/gnu-win32/latest/man/?S=A +http://src.openresources.com/debian/src/graphics/HTML/D/S_ISSOCK.html +http://www.perotech.ch/d/securedb/html/listtopic.php?4277 +http://web.health.aol.thriveonline.oxygen.com/medical/library/article/003558res.html +http://cn.egroups.com/message/Website_Warez/346 +http://adex3.flycast.com/server/socket/127.0.0.1:2800/click/OnlineCitiesSM/OnlineCitiesInteractiveCityGuides/bd510213891 +http://ring.nii.ac.jp/pub/pack/x68/personal/calendar/ +http://www.zeal.com/Government/U_S__Government/State___Local_Governments/South_Carolina/Politics/Elections/State_wide/ +http://ftp.unina.it/pub/TeX/macros/latex209/contrib/manual/?S=A +http://www.perotech.ch/d/securedb/html/listtopic.php?5376 +http://polygraph.ircache.net:8181/lci/https_-2ssl.galaxy-net.net/jazzee/http_-2www.microsoft.com/truetype/fontpack/win.htm +http://python.konbib.nl/dutchess.ned/83/00/info-1592.html +http://www.excite.com/lifestyle/cultures_and_groups/world_cultures/regions/north_america/ethnic_communities/african_american/history/military_history/ +http://www.bluemonutain.com/engy/david/CHI1-educk.html +http://www.bluemonutain.com/engy/susie/CHI1-edaddog.html +http://cn.egroups.com/messages/childhoodepilepsy/3349 +http://cn.egroups.com/messages/childhoodepilepsy/648 +http://cn.egroups.com/messages/childhoodepilepsy/1189 +http://polygraph.ircache.net:8181/services/design/http_-2www.swnebr.net/~cambridg/http_-2www.bikininet.com/climate.htm +http://www.annuairefrancais.com/54/France/I/INTERNET/Fournisseurs-d'acces/Fournisseurs-d +http://polygraph.ircache.net:8181/http_-2www.monarchcom.net/http_-2www.netscape.com/comprod/mirror/http_-2bible.gospelcom.net/http_-2www.rehablinks.com/ptlinks.htm +http://findmail.com/message/studentdoctor/4312?source=1 +http://mediate.magicbutton.net/do/session/625624/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-cart.html +http://ring.htcn.ne.jp/archives/lang/perl/CPAN/authors/id/P/PG/?M=A +http://www.buybuddy.com/sleuth/33/1/10601/526343/ +http://www1.zdnet.com/products/stories/reviews/0,4161,2470142,00.html +http://www1.zdnet.com/companyfinder/filters/products/0,9996,2256-82,00.html +http://webcvs.kde.org/cgi-bin/cvsweb.cgi/kdeutils/ark/doc/en/Attic/index-2.html?only_with_tag=MAIN +http://tv.thevines.com/leaf/AA0000364048/45///&act=24-1-11&bref=1601 +http://link.fastpartner.com/do/session/600384/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/local/redirect.php +http://www.excite.com/lifestyle/politics_and_society/community_and_cultures/world_cultures/diaspora/jewish/judaism/congregations/humanistic_judaism/ +http://biblio.cesga.es:81/search*gag/aXove,+Xosé/axove+xose/7,-1,0,B/frameset&F=axuntanza&1,,3 +http://biblio.cesga.es:81/search*gag/aXove,+Xosé/axove+xose/7,-1,0,B/frameset&F=axuntanza&3,,3 +http://db.zaq.ne.jp/asp/bbs/jttk_baasc506_1/article/36 +http://db.zaq.ne.jp/asp/bbs/jttk_baasc506_1/article/37 +http://db.zaq.ne.jp/asp/bbs/jttk_baasc506_1/article/35 +http://db.zaq.ne.jp/asp/bbs/jttk_baasc506_1/article/21 +http://www.tiroler-adler.com/1Root/Kontinent/6/Staat/7/Bundesland/16/Ort/691/Homepage/f_homepage...1.html +http://yp.gates96.com/4/52/90/87.html +http://yp.gates96.com/4/52/90/95.html +http://yp.gates96.com/4/52/91/4.html +http://yp.gates96.com/4/52/91/39.html +http://yp.gates96.com/4/52/91/42.html +http://yp.gates96.com/4/52/92/33.html +http://yp.gates96.com/4/52/92/93.html +http://yp.gates96.com/4/52/93/6.html +http://yp.gates96.com/4/52/93/98.html +http://yp.gates96.com/4/52/94/8.html +http://yp.gates96.com/4/52/94/14.html +http://yp.gates96.com/4/52/95/92.html +http://yp.gates96.com/4/52/96/16.html +http://yp.gates96.com/4/52/96/32.html +http://yp.gates96.com/4/52/96/72.html +http://yp.gates96.com/4/52/96/90.html +http://yp.gates96.com/4/52/97/1.html +http://yp.gates96.com/4/52/97/53.html +http://yp.gates96.com/4/52/98/34.html +http://yp.gates96.com/4/52/98/84.html +http://yp.gates96.com/4/52/98/97.html +http://yp.gates96.com/4/52/99/55.html +http://yp.gates96.com/4/52/99/68.html +http://yp.gates96.com/14/40/10/3.html +http://yp.gates96.com/14/40/10/86.html +http://yp.gates96.com/14/40/11/53.html +http://yp.gates96.com/14/40/12/74.html +http://yp.gates96.com/14/40/13/11.html +http://yp.gates96.com/14/40/13/34.html +http://yp.gates96.com/14/40/13/45.html +http://yp.gates96.com/14/40/13/79.html +http://yp.gates96.com/14/40/14/3.html +http://yp.gates96.com/14/40/14/6.html +http://yp.gates96.com/14/40/14/25.html +http://yp.gates96.com/14/40/14/84.html +http://yp.gates96.com/14/40/14/88.html +http://yp.gates96.com/14/40/15/39.html +http://yp.gates96.com/14/40/15/40.html +http://yp.gates96.com/14/40/16/64.html +http://yp.gates96.com/14/40/16/92.html +http://yp.gates96.com/14/40/17/69.html +http://yp.gates96.com/14/40/18/42.html +http://yp.gates96.com/14/40/18/82.html +http://yp.gates96.com/14/40/19/36.html +http://www.4positiveimages.com/4positiveimages/727410225/IconBar +http://www.teacherformation.org/html/od/facilitators.cfm/task1,login/discussion_id,2/xid,6559/yid,6157439 +http://www.secinfo.com/dSU5m.74.htm +http://www.secinfo.com/dSU5m.7v.htm +http://www.secinfo.com/dSU5m.6y.htm +http://www.secinfo.com/dSU5m.5c.htm +http://linux.softhouse.com.cn/linux/knowledge/tech/qs/linux5.htm +http://linux.softhouse.com.cn/linux/knowledge/tech/qs/linux10.htm +http://freesoftware.subportal.com/sn/Programming/Visual_Basic_Components_H-P/993.html +http://dk.egroups.com/message/NGHILUAN/2881 +http://dk.egroups.com/message/NGHILUAN/2889 +http://www.cga.state.ct.us/ps98/cbs/H/hj-0084.htm +http://apple.excite.com/entertainment/music/artists_and_genres/jazz/new_world_jazz/afro_cuban/ +http://www.euronet.nl/users/hiroshi/ksweb/interest.htm +http://library.bangor.ac.uk/search/aMollica,+Anthony/amollica+anthony/-5,-1,0,B/browse +http://www.fogdog.com/cedroID/ssd3040183308040/nav/products/featured_brands/14t/all/ +http://www.brio.de/BRIO.catalog/39fe2f8d0912d4962740d472aa780701/UserTemplate/9 +http://www.hig.se/(accessed,autoformat,referrer,sqloutput,tablify)/~jackson/roxen/ +http://www.newstimescybermall.com/Mall/Catalog/Product/ASP/product-id/206059/store-id/1000010991.html +http://www6.163.com/news/p-item/0,1587,economy_1916,00.html +http://ftp.uni-stuttgart.de/pub/systems/sgi/graphics/lib/?D=A +http://preview.egroups.com/message/abdou3/152 +http://ch.php.net/manual/it/function.pg-loimport.php +http://yp.gates96.com/1/94/30/39.html +http://yp.gates96.com/1/94/30/78.html +http://yp.gates96.com/1/94/31/11.html +http://yp.gates96.com/1/94/31/72.html +http://yp.gates96.com/1/94/31/85.html +http://yp.gates96.com/1/94/32/25.html +http://yp.gates96.com/1/94/32/45.html +http://yp.gates96.com/1/94/32/74.html +http://yp.gates96.com/1/94/33/20.html +http://yp.gates96.com/1/94/33/68.html +http://yp.gates96.com/1/94/34/92.html +http://yp.gates96.com/1/94/35/1.html +http://yp.gates96.com/1/94/35/50.html +http://yp.gates96.com/1/94/35/60.html +http://yp.gates96.com/1/94/37/0.html +http://yp.gates96.com/1/94/37/46.html +http://yp.gates96.com/1/94/37/47.html +http://yp.gates96.com/1/94/37/61.html +http://yp.gates96.com/1/94/38/19.html +http://yp.gates96.com/1/94/39/49.html +http://yp.gates96.com/1/94/39/57.html +http://www.gartenfachmarkt.de/beratung_garten/duengen_und_kompostieren/anlage_und_vorarbeiten/fertig.htm +http://support.dell.com/docs/storage/4955r/en/Hw/setup.htm +http://www.hig.se/(clientname,header,sort,sqlquery,sqltable)/~jackson/roxen/ +http://www.mic.hr/PGBURZA:423870 +http://www.mic.hr/PGNEWS:423870 +http://members.tripod.com/Tess_Tom/my_photoalbum/page12.html +http://legalminds.lp.findlaw.com/list/courtinterp-spanish/nav05815.html +http://www.fogdog.com/cedroID/ssd3040183239698/crs/pn__/wld/fogdog_sports/pearl_izumi/road_cycling/apparel/classic_vest.html +http://www.fogdog.com/cedroID/ssd3040183239698/nav/stores/wakeboarding/ +http://troy.lib.sfu.ca/search/slogos/slogos/-5,-1,0,E/frameset&F=slogistics+and+transportation+review&1,,0 +http://themes.tucows.dia.dk/skins/icq/preview/54718.html +http://php.nic.fi/manual/html/function.shm_open.html +http://ftp.fi.debian.org/debian/dists/woody/non-free/binary-m68k/misc/?S=A +http://www.csupomona.edu/reference/java/jdk1.2/docs/api/org/omg/CORBA/class-use/CompletionStatus.html +http://www.trax.nilex.co.uk/trax.cgi/A1C/B1U/A1D/C1R/A1D/B1R/ +http://www.uni-duesseldorf.de/ftp/ftp/software/opt/cpio-2.4.2/?M=A +http://ep.com/js/about/c9079/b0/250918.html +http://polygraph.ircache.net:8181/busi/html/http_-2www.dirtsports.com/index.html-ssi +http://www.chabadlibrary.org/ecatalog/EC06/EC06232.HTM +http://chat.hani.co.kr/NetBBS/Bbs.dll/brief/lst/qqa/f/qqo/PRMY/zka/B23qB2Bm +http://209.207.239.212/bkindex/c1047/f1128.html +http://tv.thevines.com/leaf/AA0000364429/4/1 +http://tv.thevines.com/leaf/AA0000364429/4//&order_by=WORST +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=12,17,20,5,16 +http://yp.gates96.com/4/4/40/22.html +http://yp.gates96.com/4/4/40/29.html +http://yp.gates96.com/4/4/41/11.html +http://yp.gates96.com/4/4/42/0.html +http://yp.gates96.com/4/4/42/27.html +http://yp.gates96.com/4/4/42/89.html +http://yp.gates96.com/4/4/42/99.html +http://yp.gates96.com/4/4/43/40.html +http://yp.gates96.com/4/4/43/69.html +http://yp.gates96.com/4/4/43/85.html +http://yp.gates96.com/4/4/44/27.html +http://yp.gates96.com/4/4/44/28.html +http://yp.gates96.com/4/4/44/36.html +http://yp.gates96.com/4/4/44/86.html +http://yp.gates96.com/4/4/45/76.html +http://yp.gates96.com/4/4/45/82.html +http://yp.gates96.com/4/4/45/86.html +http://yp.gates96.com/4/4/46/61.html +http://yp.gates96.com/4/4/47/1.html +http://yp.gates96.com/4/4/47/41.html +http://yp.gates96.com/4/4/47/42.html +http://yp.gates96.com/4/4/48/66.html +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/ports/misc/geekcode/pkg-descr?only_with_tag=RELEASE_3_4_0 +http://perso.wanadoo.fr/genealogie.aubert.jm/geweb/ff100.htm +http://www.securitiestimes.com.cn/199904/29/data/newfiles/0060080.htm +http://autos.yahoo.co.jp/ucar/m1015/k10152012199906/g21/a101520120210248821003520208199906.html +http://dg.galaxy.com/galaxy/Community/United-States/States/Connecticut/Cities-and-Regions/Guilford/Education/K--12/Middle.html +http://carriage.de/Schoner/info-e/literature/collections/models/ +http://www.amcity.com/orlando/stories/1998/06/29/weekinbiz.html?t=email_story +http://www.icopyright.com/1.1655.94549 +http://biblio.cesga.es:81/search*gag/dMicrosoft+Visual+BASIC+(Archivo+de+ordenador)/dmicrosoft+visual+basic+archivo+de+ordenador/-5,1,1,B/frameset&F=dmicrosoft+project+archivo+de+ordenador&1,1, +http://www.jamba.de/KNet/_KNet-AzI8j1-tGd-13d56/browse.de/node.0/cde7f1uou +http://www.jamba.de/KNet/_KNet-AzI8j1-tGd-13d5e/browse.de/node.0/cde7f1uou +http://www.ioppublishing.com/PEL/help/article/ja30010l2/refs/?topic=refs +http://members.tripod.lycos.co.kr/uuujsh/?N=D +http://www.wlu.ca/~wwwregi/95-96/cal/ucourses/CP/CP417.html +http://books.hyperlink.co.uk/bookinfo/Essential_Papers_on_Messianic_Movements_and_Personalities_in_Jewish_History/0814779433 +http://generalstore.everdream.com/kore/catalog/Office_Supplies/Furniture_&_Accessories/File_Cabinets/Vertical/GRP-US747/product.html +http://satlink.tucows.com/winnt/adnload/54136_29678.html +http://dc.web.aol.com/myrtlebeacharea/penpals/browse.dci?cat=twenties&sort=m +http://itcareers.careercast.com/texis/it/itjs/+nwwBme4WD86e4rwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewDthDo5O5apGdtGwMaBGnDBdDaqd1DBGon5aoDqc1moDtax15oDn55amnVncdpoDta5dc1BodD5adppdGB1DoBon5aqdMpnBoBoVnaMFqtuNfIjIDzmYqwwpBme68D86eihwww5rmerdwwwBrmeZpwww/jobpage.html +http://ring.yamanashi.ac.jp/pub/linux/debian/debian-jp/dists/hamm-jp/hamm/disks-i386/current/base14-3.bin.2.0.11.2-i386 +http://www.ibm.co.jp/pc/thinkpad/pt110/look110.html +http://retailer.gocollect.com/do/session/1912720/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/postcards/index.asp +http://www-rn.informatik.uni-bremen.de/home/X11R6/xc/doc/hardcopy/XProtocol/?N=D +http://cafe3.daum.net/Cafe-bin/bbsList?bbsgrp=SIXTEEN&bbscode=SIXTEENbbs +http://allmacintosh.arrakis.es/adnload/12140.html +http://allmacintosh.arrakis.es/adnload/2476.html +http://www.msb.malmo.se/search*swe/dSkönlitteratur/dskz~cnlitteratur/-5,-1,0,B/2exact&F=dskz~cnliteratur&1,2 +http://tucows.syix.com/winme/preview/137803.html +http://pages.prodigy.net/patotoole/musicman/page6.htm +http://yp.gates96.com/14/43/0/39.html +http://yp.gates96.com/14/43/0/78.html +http://yp.gates96.com/14/43/0/79.html +http://yp.gates96.com/14/43/0/99.html +http://yp.gates96.com/14/43/1/3.html +http://yp.gates96.com/14/43/1/57.html +http://yp.gates96.com/14/43/1/86.html +http://yp.gates96.com/14/43/2/74.html +http://yp.gates96.com/14/43/2/80.html +http://yp.gates96.com/14/43/3/2.html +http://yp.gates96.com/14/43/3/97.html +http://yp.gates96.com/14/43/3/99.html +http://yp.gates96.com/14/43/4/37.html +http://yp.gates96.com/14/43/4/51.html +http://yp.gates96.com/14/43/4/72.html +http://yp.gates96.com/14/43/6/4.html +http://yp.gates96.com/14/43/7/20.html +http://yp.gates96.com/14/43/7/39.html +http://yp.gates96.com/14/43/7/45.html +http://yp.gates96.com/14/43/9/41.html +http://yp.gates96.com/14/43/9/58.html +http://yp.gates96.com/14/43/9/60.html +http://ftp.support.compaq.com/public/dunix/v3.2g/ASE_V1.3/ReleaseNotes.htm +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/mchI1k9vDw6DGJ19bljzJPwhHhJYxAcnAIKgudPEJtzjiTWMWT4U-YMr4m-AccPn7sEIqMzfFTZnQEQBZNx-lh8DEr_c1F3DXpcc4PzhALzHJ76GytRWNCSauwtfVocYmy_RKsP-H9T-UhQgoc9_uexBhD4a +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/IqtI3V1hdRxfYW_4AHOzeXZkuTzyKfveVl4qdYM_2WFldvLDKFgK8SvYa0mSlrWDVodDERGv2jvb2dEN1-mRmY3TBKURFCsqneanb8BNMBeBfqmSnBYuou5RMCmHxXCedHy3TQnL51n3TYbg5exYBWl9FJTcQEIJt2wyyrfB66jP +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/Hk1ILVbQbFwze5TrhlBima0MylJ0gTqcnVeTbMTcn7Gy5GkelYKhUQ7m8P8_K3IkOWfIWbpGOJEuHqJLX5jY_7ygFevbtkNXPvb1yztdy9qzCTsCJvS5uaHN3cZd0LtuoMX3lX7d_-L_PrwRXSfTE3TNvWl-RHiY4Xmxk1fXhD_uwwjDvC7DDsxz66j6 +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/T41IiB449vZ7nrOl2Z_klJHCHQZhigz52e9YVMztVI-K01klBYQrw4VmiKN8JDs9xaeMSWopQs1euSbr6BAiyuqpbSFiiVWObVmWHv031jtdQ1y93wnHhx8PkbrA4hkNhjTPs2mUhBF9wIAJSPCYLkf6W7mCB8ObikqLTuIwBfRtSgMK4Hz9e7Bp +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/CI1IlJNaoNrBcwJYSEcjLyxBnpQHK3wpRPeCR_0u07GznNXQ3Ug57ciOqlfXKlYM1HbRfcvrF5s214yaEHiIizneyWrbSEW_xal49NjQDbWj6R2nEZvDQdDMQEMoTuQlSetyUwMidLBmJJ5v5w9m066en6Yxuzt3RkGIyoHKaVmXgVIYD2Fc40eA +http://www.secinfo.com/dSm4r.997.htm +http://www.secinfo.com/dSm4r.68c.htm +http://www.secinfo.com/dSm4r.69c.htm +http://mirror.cc.utsunomiya-u.ac.jp/mirror/CPAN/modules/by-module/MD5/GAAS/HTML-Parser-3.04.readme +http://polygraph.ircache.net:8181/Game+Controllers/http_-2www.real-e-video.com/price-abuse.html +http://ecomonly.shop.goto.com/z/netadp/search/matches.jhtml?MANUF=Linksys +http://ecomonly.shop.goto.com/z/netadp/search/matches.jhtml?MANUF=Madge +http://freesoftware.subportal.com/sn/Web_Authoring/Misc__Programming_Tools/3100.html +http://www.sam.hi-ho.ne.jp/m-saka/stepwgn/himeji/6scene/ +http://ftp.unina.it/pub/Unix/linux/SuSE/ftp.suse.com/projects/3d/kernel/?N=D +http://www.ld.com/cbd/archive/1999/08(August)/10-Aug-1999/61awd001.htm +http://www.ld.com/cbd/archive/1999/08(August)/10-Aug-1999/61awd004.htm +http://statweb.byu.edu/sasdoc/sashtml/stat/chap2/sect5.htm +http://www.diogenes.de/4DACTION/web_rd_aut_show_authorlist/ID=483367&chr=F +http://web1.localbusiness.com/Story/Email/1,1198,RDU_461041,00.html +http://www.clientwire.com/A55697/tmr.nsf/vwApprovedResumesbyDate!OpenView&Start=55&Count=50&Collapse=48 +http://cpan.nitco.com/modules/by-module/Mail/JWIED/SNMP-Monitor-0.1011.readme +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=237&discrim=178,16,10 +http://www6.compaq.com/products/quickspecs/10135_na/10135_na.PDF +http://www.suk2.com/user/777/20001012.html +http://www.jamba.de/KNet/_KNet-vAy8j1-iFd-13az6/browse.de/node.0/cde7f2elw +http://www.imagesofengland.org.uk/41/69/416915.htm +http://ocean.ntou.edu.tw/search*chi/aLaplante,+Phillip+A./alaplante+phillip+a/7,-1,0,B/frameset&F=alappe+frances+moore&1,,2 +http://ocean.ntou.edu.tw/search*chi/aLaplante,+Phillip+A./alaplante+phillip+a/7,-1,0,B/frameset&F=alappe+frances+moore&2,,2 +http://wap.jamba.de/KNet/_KNet-6Fz8j1-oFd-13b3x/admLogin.de/node.0/cde7f1uou +http://yp.gates96.com/14/49/20/26.html +http://yp.gates96.com/14/49/20/37.html +http://yp.gates96.com/14/49/20/39.html +http://yp.gates96.com/14/49/20/86.html +http://yp.gates96.com/14/49/20/94.html +http://yp.gates96.com/14/49/20/97.html +http://yp.gates96.com/14/49/21/19.html +http://yp.gates96.com/14/49/21/43.html +http://yp.gates96.com/14/49/21/68.html +http://yp.gates96.com/14/49/21/78.html +http://yp.gates96.com/14/49/24/6.html +http://yp.gates96.com/14/49/24/62.html +http://yp.gates96.com/14/49/24/77.html +http://yp.gates96.com/14/49/24/83.html +http://yp.gates96.com/14/49/25/30.html +http://yp.gates96.com/14/49/25/41.html +http://yp.gates96.com/14/49/26/17.html +http://yp.gates96.com/14/49/26/53.html +http://yp.gates96.com/14/49/27/21.html +http://yp.gates96.com/14/49/27/27.html +http://yp.gates96.com/14/49/27/45.html +http://yp.gates96.com/14/49/27/65.html +http://yp.gates96.com/14/49/28/71.html +http://www.boston.digitalcity.com/orangecounty/entertainment/article.dci?aid=1293&start=10 +http://tucows.allnet.it/winme/adnload/143-006-005-021.html +http://tucows.allnet.it/winme/adnload/143-006-005-030.html +http://www.trax.nilex.co.uk/trax.cgi/A1C/B1U/A1D/C1R/A2D/A1U/ +http://www.crosswinds.net/~klinnia/DragonsDomain/Nest/nest.htm +http://mirrors.valueclick.com/backup.pause/modules/by-category/99_Not_In_Modulelist/Memoize/?S=A +http://www.tgw.com/EJr.5ajd/customer/category/product.html?SUBCATEGORY_ID=557 +http://www.sohu.com/business_economy/Company/Computer_Internet/Network_System/Network/ +http://china-water.51.net/oicq/oicq_down.htm +http://ftp.lip6.fr/pub/FreeBSD/development/FreeBSD-CVS/ports/math/plplot/patches/Attic/patch-ac,v +http://library.cuhk.edu.hk/search*chi/cHC427.92.C59/chc++427.92+c59/-5,-1,,E/browse +http://yp.gates96.com/4/8/60/2.html +http://yp.gates96.com/4/8/60/19.html +http://yp.gates96.com/4/8/62/9.html +http://yp.gates96.com/4/8/62/23.html +http://yp.gates96.com/4/8/62/59.html +http://yp.gates96.com/4/8/63/26.html +http://yp.gates96.com/4/8/63/41.html +http://yp.gates96.com/4/8/64/48.html +http://yp.gates96.com/4/8/65/0.html +http://yp.gates96.com/4/8/65/42.html +http://yp.gates96.com/4/8/66/13.html +http://yp.gates96.com/4/8/66/88.html +http://yp.gates96.com/4/8/67/23.html +http://yp.gates96.com/4/8/67/51.html +http://yp.gates96.com/4/8/68/11.html +http://yp.gates96.com/4/8/68/16.html +http://yp.gates96.com/4/8/68/78.html +http://www.outpersonals.com/cgi-bin/w3com/pws/out/CehIaxpSN7cGOeOUjXx_FtrylkakPWisW0DYq0MYmHwGxLBo7shB2XGSeXyvbnsBzHMJTZtmYOUK-XaaAW0Yh88wTY-Mms-hxw67Xaw8WMk3-vUJ4sXm4U7yIGdiN9XoPOqfnODrkqXYztjU6Var +http://www.brd.net/brd-cgi/brd_netzwerk?mailto&router&BZ85G0IL +http://power.luneng.com/power/library/jxgcs/jxgc99/jxgc9912/991204.htm +http://www.egroups.com/messages/Creative_Teaching/72?viscount=-30 +http://www.egroups.com/message/Creative_Teaching/85 +http://ftp.eecs.umich.edu/.1/people/elta/cusm-Javajae-elta/?D=A +http://polygraph.ircache.net:8181/cagliari/WHOWOULD.HTM +http://www.tiscover.ch/1Root/Kontinent/6/Staat/30/Bundesland/33/Ort/1564/Homepage/h_homepage...2.html +http://t-online.de/computer/haupt/intcoh87.htm +http://prodigy-sports.excite.com/ncaab/news/025uwire1 +http://wwwold.ifi.uni-klu.ac.at/Manuals/jdk1.1b3/docs/guide/awt/designspec/graphics/imagescale.html +http://www.taconet.com.tw/a6983/ +http://www.mapion.co.jp/custom/AOL/admi/13/13107/higashimukojima/3chome/index-3.html +http://www.mapion.co.jp/custom/AOL/admi/13/13107/higashimukojima/3chome/index-13.html +http://caller-times.com/autoconv/kickoff98/kickoff30.html +http://www.incestpornstories.com/bisexualbisexual/big-bonedmen/beautiesslanted-eyes/plus-sizeoverweight/{teenlink} +http://qcardsccg.safeshopper.com/8/359.htm?923 +http://qcardsccg.safeshopper.com/8/429.htm?923 +http://qcardsccg.safeshopper.com/8/433.htm?923 +http://lib1.nippon-foundation.or.jp/1997/0486/contents/011.htm +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceOrderStatusOverview-BBC709F1_97EF_F357031944376B6D965FDC23BED4C6F4 +http://in.egroups.com/subscribe/muovimallit +http://multichat.de/fp/talk/cb-funk/4.htm +http://multichat.de/fp/talk/cb-funk/5.htm +http://www.jamba.de/KNet/_KNet-zfB8j1-EFd-13bkr/browse.de/node.0/cde7f2elw +http://www.jamba.de/KNet/_KNet-zfB8j1-EFd-13bl7/showInfo-jobs.de/node.0/cenv0b09a +http://152.80.49.210/PUBLIC/WXMAP/GLOBAL/AVN/2000103000/avn.prp.00-36.swasia.htm +http://retailer.gocollect.com/do/session/1912741/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/help/site_tour/index.asp +http://retailer.gocollect.com/do/session/1912741/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/top_ten.asp?pagenum=2 +http://www.fogdog.com/cedroID/ssd3040183248168/nav/products/winter_sports/1b/shell_jackets/ +http://www.fogdog.com/cedroID/ssd3040183248168/nav/products/featured_brands/3c/all/ +http://kutschen.de/Schoner/literature/Sammlungen/modelle/collections/ +http://el-mundo.es/1999/06/04/television/04N0121.html +http://bitwise.tucows.com/win2k/htmlval2k_license.html +http://bbs.ee.ntu.edu.tw/boards/Saturn/3/7/12/5.html +http://ustlib.ust.hk/search*chi/deconomic+conditions+cameroon+to+1960/deconomic+conditions+cameroon+to+1960/-5,-1,0,B/browse +http://excite.de/kunst/katalog/865 +http://www2.hindustantimes.com/ht/nonfram/280498/detFRO07.htm +http://yp.gates96.com/11/69/0/60.html +http://yp.gates96.com/11/69/1/60.html +http://yp.gates96.com/11/69/1/72.html +http://yp.gates96.com/11/69/2/80.html +http://yp.gates96.com/11/69/3/7.html +http://yp.gates96.com/11/69/3/54.html +http://yp.gates96.com/11/69/3/66.html +http://yp.gates96.com/11/69/3/90.html +http://yp.gates96.com/11/69/3/91.html +http://yp.gates96.com/11/69/4/13.html +http://yp.gates96.com/11/69/4/18.html +http://yp.gates96.com/11/69/4/26.html +http://yp.gates96.com/11/69/4/70.html +http://yp.gates96.com/11/69/5/45.html +http://yp.gates96.com/11/69/5/77.html +http://yp.gates96.com/11/69/6/10.html +http://yp.gates96.com/11/69/6/80.html +http://yp.gates96.com/11/69/7/43.html +http://yp.gates96.com/11/69/7/76.html +http://yp.gates96.com/11/69/8/17.html +http://yp.gates96.com/11/69/8/33.html +http://yp.gates96.com/11/69/8/98.html +http://yp.gates96.com/11/69/9/3.html +http://yp.gates96.com/11/69/9/41.html +http://yp.gates96.com/11/69/9/92.html +http://store.peoplestour.com/kore/catalog/Music/R&B/G_by_artist/104757/product.html +http://free.prohosting.com/~seikyo/speak2.htm +http://pub.chinaccm.com/12/news/200009/16/160724.asp +http://pub.chinaccm.com/12/news/200008/11/155448.asp +http://www.fogdog.com/cedroID/ssd3040183305379/nav/products/featured_brands/12r/spa_products/ +http://itcareers.careercast.com/texis/it/itjs/+EwwBmev6D86ebtwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewGtmoBGnaqdGpdGwBodDacnwmaADdicnmtnaMwDwtnMnDBanDtoDnnGaMw55wqr15nBB5aqwpB1GnaoDhdGMwBodDaBnqrDdcdton5aMFqhTfR20DzmewrwwwpBmGeP0-dmwww5rmeNDwwwBrmeZpwww/jobpage.html +http://www.outdoorwire.com/content/lists/dirt/200004/msg00354.html?{LoadingFrameset} +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=5&discrim=186,22,8 +http://www.teleparc.com/sports/funski/02/03.htm +http://cn.egroups.com/post/safrica_bridge?act=reply&messageNum=43 +http://www.dfae.diplomatie.gouv.fr/culture/france/cinema/documentaires/recherche/francais/ethique.html +http://ring.toyama-ix.net/archives/mac/info-mac/_Communication/ctb/?D=A +http://www.eveclub.com/cgi-bin/eveclub.front/972959528284/Catalog/11000155 +http://www.eveclub.com/cgi-bin/eveclub.front/972959528284/Catalog/2000019 +http://cometweb01.comet.co.uk/do!session=132005&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG5ubLZDXLZolLl3l5jbqLljX5fkkKaotHlob5mloLq1 +http://cometweb01.comet.co.uk/do!session=132005&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG3XqLbdlLov4LfpmLiXvL-Zd5jbkLYozKvot0cZd5ockLYozKvsm0uts0cZX5qkXLjbzKKbiLbsfLpflLkp5 +http://www.ualberta.ca/CNS/RESEARCH/Software/SAS/cms/zfor-hex.htm +http://www.ualberta.ca/CNS/RESEARCH/Software/SAS/os390/zlibname.htm +http://genforum.genealogy.com/cgi-bin/print.cgi?hanrahan::175.html +http://library.bangor.ac.uk/search/dAIDS+(Disease)+--+Risk+factors+--+Psychological+aspects+--+Periodicals/daids+disease+risk+factors+psychological+aspects+periodicals/-5,1,1,B/frameset&F=daids+disease+research&1,1, +http://www.rismedia.com/consumer/27/12194/ +http://www.hole.kommune.no/hole/journweb.nsf/weboffjournal!OpenView&Start=39&Count=50&Expand=38 +http://www.etoys.com/prod/toy/53097261 +http://www.outpersonals.com/cgi-bin/w3com/pws/out/J6tI5danl1CaEvxOmyBVl8pzyaGqhs1RWIGq0aJ2_fwvzv4y9T7bHlxQKPzsrhMRN5HEI_Y9ZKrSvboCZvKhdwPPYK2klPp0EqNMO7Mb8fDTcz6xykQv8YQCQ2dy_iLZjbXwrknXqcH32HVSXAq7iUr4yIVG66IK +http://www.amcity.com/jacksonville/stories/1999/11/22/daily16.html?t=printable +http://moviestore.zap2it.com/browse/MOVIES/BOXERSHO/s.F0FWmEHm +http://moviestore.zap2it.com/browse/MOVIES/SHIRT/s.F0FWmEHm +http://moviestore.zap2it.com/browse/MOVIES/TIE/s.F0FWmEHm +http://moviestore.zap2it.com/browse/MOVIES/WATCH/s.F0FWmEHm +http://yp.gates96.com/11/25/30/0.html +http://yp.gates96.com/11/25/30/47.html +http://yp.gates96.com/11/25/31/87.html +http://yp.gates96.com/11/25/32/3.html +http://yp.gates96.com/11/25/32/61.html +http://yp.gates96.com/11/25/32/97.html +http://yp.gates96.com/11/25/33/6.html +http://yp.gates96.com/11/25/33/81.html +http://yp.gates96.com/11/25/33/83.html +http://yp.gates96.com/11/25/34/10.html +http://yp.gates96.com/11/25/34/35.html +http://yp.gates96.com/11/25/34/88.html +http://yp.gates96.com/11/25/34/90.html +http://yp.gates96.com/11/25/35/95.html +http://yp.gates96.com/11/25/36/19.html +http://yp.gates96.com/11/25/36/98.html +http://yp.gates96.com/11/25/37/61.html +http://yp.gates96.com/11/25/37/74.html +http://yp.gates96.com/11/25/38/2.html +http://yp.gates96.com/11/25/38/62.html +http://yp.gates96.com/11/25/39/1.html +http://yp.gates96.com/11/25/39/25.html +http://yp.gates96.com/11/25/39/85.html +http://yp.gates96.com/11/25/39/95.html +http://www.linux.com/networking/network/industry/server/community/Red_Hat/ +http://www.linux.com/networking/network/industry/server/community/Slashdot/ +http://www.linux.com/networking/network/industry/server/community/growth/ +http://mirror.cc.utsunomiya-u.ac.jp/mirror/CPAN/modules/by-category/16_Server_and_Daemon_Utilities/Server/DRUOSO/Server-FastPL-1.0.0.readme +http://ftp.nacamar.de/pub/NetBSD/NetBSD-current/pkgsrc/parallel/clusterit/pkg/DESCR +http://dk.egroups.com/login.cgi?login_target=%2Fgroup%2FGravesrus +http://www.maxfunds.com/MF1000.nsf/FUNDanalysisPrint/FGOAX +http://www.gbnf.com/genealog2/brothers/html/d0065/I12666.HTM +http://office.net/benelux/nld/downloadcatalog/dldpowerpoint.asp +http://yam.com/en/rand/ent/music/minfo/ +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/Collect_DB_Advers2/2000-09-28/23/?N=D +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=22,11,35 +http://dk.egroups.com/messages/lafz/6 +http://www.online.kokusai.co.jp/Words/V0043555/wrd/G700/words/kana_main.html +http://adelaida.net/music/texts/pink75.html +http://support.tandy.com/support_audio/doc40/40914.htm +http://www.nutritionblvd.com/426162.html +http://www.nutritionblvd.com/426121.html +http://www.nutritionblvd.com/426117.html +http://www.fogdog.com/cedroID/ssd3040183301450/boutique/aaron_chang/ +http://www.fogdog.com/cedroID/ssd3040183301450/boutique/moving_comfort/ +http://www.fogdog.com/cedroID/ssd3040183301450/fly/ +http://in.egroups.com/login.cgi?login_target=%2Fmessage%2Finfogiappone%2F81 +http://in.egroups.com/post/infogiappone?act=reply&messageNum=81 +http://cn.egroups.com/message/1800list/5416 +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www.slac.stanford.edu/grp/arb/tn/arbvol1/ARDB011.pdf +http://crrstv.tucows.com/winnt/adnload/135146_46908.html +http://syix.tucows.com/win2k/adnload/61785_28334.html +http://ftp.ccu.edu.tw/pub/language/tcl/sorted/packages-7.6/sound/xmpeg_0.5/ +http://www.eos.ncsu.edu/linux/LDP/LDP/khg/HyperNews/get/fs/fs/3.html +http://polygraph.ircache.net:8181/http_-2www.tvguide.com/sports/football/http_-2home.netscape.com/http_-2www.premaonline.com/http_-2www.ionet.net/~burndragon/form1.html +http://se.egroups.com/group/MyLuminaGoezBoom +http://www.diogenes.ch/4DACTION/web_rd_aut_show_author/a_id=7056553&tmpl=AUT_00&ID=483371 +http://www3.newstimes.com/archive97/apr0497/tvg.htm +http://dic.empas.com/show.tsp/?q=edger&f=B +http://www.brio.de/BRIO.catalog/39fe2f570905fb6a2740d472aa7806aa/UserTemplate/2 +http://itcareers.careercast.com/texis/it/itjs/+uwwBme7WD86eYtwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewGtmoBGnaqdGpdGwBodDaoDhdGMwBodDa5nq1GoBOanDtoDnnGaiw5roDtBdDanDBnGpGo5naGn31oGnmawGqroBnqB1Gna5O5BnM5aMFqhTfR20DzmehrwwwpBmeZWD86Nwww5rmekdwwwBrmeZpwww/jobpage.html +http://itcareers.careercast.com/texis/it/itjs/+pwwBmet5986twwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewGtmoBGnaqdGpdGwBodDaoDhdGMwBodDa5nq1GoBOanDtoDnnGaiw5roDtBdDanDBnGpGo5naGn31oGnmawGqroBnqB1Gna5O5BnM5aMFqhTfR20DzmehrwwwpBmeZWD86Nwww5rmekdwwwBrmeZpwww/morelike.html +http://biblioteca.upv.es/bib/doc/doc_fisbd/180/132317//C/1825784/0////25/S/MLTPAI +http://www.stanford.edu/~sevls/files/?M=D +http://library.bangor.ac.uk/search/dSystem+analysis+--+Periodicals/dsystem+analysis+periodicals/-17,-1,0,B/browse +http://mirror.ox.ac.uk/Mirrors/ftp.redhat.com/roughcuts/m68k/misc/src/install/pci-probing/CVS/ +http://yp.gates96.com/0/13/10/17.html +http://yp.gates96.com/0/13/11/26.html +http://yp.gates96.com/0/13/12/20.html +http://yp.gates96.com/0/13/12/24.html +http://yp.gates96.com/0/13/12/49.html +http://yp.gates96.com/0/13/13/22.html +http://yp.gates96.com/0/13/13/80.html +http://yp.gates96.com/0/13/15/8.html +http://yp.gates96.com/0/13/16/4.html +http://yp.gates96.com/0/13/16/18.html +http://yp.gates96.com/0/13/16/64.html +http://yp.gates96.com/0/13/17/15.html +http://yp.gates96.com/0/13/18/11.html +http://yp.gates96.com/0/13/18/18.html +http://yp.gates96.com/0/13/19/5.html +http://yp.gates96.com/0/13/19/22.html +http://yp.gates96.com/0/13/19/60.html +http://library.cuhk.edu.hk/search*chi/aYen-shou,+Shih,+904-975./ayen+shou+shih++904++975/-5,-1,0,E/2browse +http://china.sydney2000.com/StaticNews/2000-07-29/News372a86.htm +http://www.fujian-window.com/Fujian_w/news/mzrb1/20000724/3_1.html +http://www.fujian-window.com/Fujian_w/news/mzrb1/20000724/3_2.html +http://legalminds.lp.findlaw.com/list/law-lib/nav07807.html +http://ftp.fi.debian.org/debian/dists/woody/contrib/binary-sparc/tex/?N=D +http://community.webshots.com/photo/3635718/3636284GcTotmmONR +http://www.power2lead.com/Global/English.nsf/pgWWLocations!OpenPage&ExpandSection=23,24,25,17,10 +http://spaindustry.com/por/exp/911.html +http://niagara.tucows.com/winme/preview/10464.html +http://niagara.tucows.com/winme/adnload/138750_30032.html +http://niagara.tucows.com/winme/adnload/138743_30025.html +http://niagara.tucows.com/winme/adnload/138740_30023.html +http://retailer.gocollect.com/do/session/1912780/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/advanced_search.asp +http://preview.egroups.com/messages/UKMatrix +http://fi.egroups.com/login.cgi?login_target=%2Fmessage%2Fhecates_news%2F21 +http://pub.chinaccm.com/02/news/200005/31/133146.asp +http://pub.chinaccm.com/02/news/200005/31/133212.asp +http://localhost/test, +http://kuyper.calvin.edu/fathers2/ANF-02/anf02-25.htm +http://kuyper.calvin.edu/fathers2/ANF-02/anf02-56.htm +http://totalsports.aol.com/stats/bbo/mlb/mlb/990910.cle.AT.cws.box.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/990915.nym.AT.col.box.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/990919.cws.AT.tor.box.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/990926.hou.AT.mil.box.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/991003.nyy.AT.tam.box.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/991006.bos.AT.cle.box.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/ALscores.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/CAT.ROS.pit.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/NYY.CLE.pit.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/mlb.ARI.recap.html +http://totalsports.aol.com/stats/bbo/mlb/mlb/mlb.atl.vs.hou.stat.html +http://www.jpc-music.com/2241771.htm +http://sunsite.org.uk/packages/TeX/uk-tex/macros/latex/contrib/supported/europs/?M=A +http://mitglied.tripod.de/blueblood/forum.html +http://kuyper.calvin.edu/fathers2/NPNF1-06/npnf1-06-92.htm +http://garbage.sonicnet.com/classical/features/Thomas,_Tilson/060500/index04.jhtml +http://dk.egroups.com/post/danish?act=forward&messageNum=6 +http://www.bornloser.com/comics/peanuts/f_profiles/html/f4b1.html +http://www.online.kokusai.co.jp/Home/V0043517/wrd/G100/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380823/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.france.hp.com/Main/acheterhp/ +http://www.bemi-immobilien.de/Landhaus-Bordeaux/Gemeinsam/versicherungen/lebensversicherung/Gemeinsam/Startseite/Top-Darlehens-Konditionen/Gemeinsam/erreichenPartner/email3d.htm +http://sunsite.org.uk/public/pub/Mirrors/ftp.hpc.uh.edu/pub/?D=A +http://genforum.genealogy.com/cgi-bin/print.cgi?tillery::418.html +http://ring.omp.ad.jp/archives/lang/perl/CPAN/authors/id/MSCHWARTZ/?M=A +http://montxsuz.all-hotels.com/usa/massachusetts/plymouth_e1.htm +http://montxsuz.all-hotels.com/usa/massachusetts/brewster_e1.htm +http://montxsuz.all-hotels.com/usa/massachusetts/edgartown_e1.htm +http://montxsuz.all-hotels.com/usa/massachusetts/north_dartmouth_e1.htm +http://montxsuz.all-hotels.com/usa/massachusetts/washington_e1.htm +http://romeo.univ-savoie.fr/winnt/adnload/51179_28892.html +http://www.dispatch.co.za/1998/12/02/sport/FALDO.HTM +http://www.dispatch.co.za/1998/12/02/sport/RACE2.HTM +http://store1.europe.yahoo.com/brink2/2000074707407.html +http://www34.yahoo.co.jp/horse/1999/tokyo/0530/result_08.html +http://members.tripod.co.jp/suiha_izumi/gallery-taikoubou-.htm +http://linuxberg.vol.at/gnomehtml/adnload/020-008-002-004_6145.html +http://books.hyperlink.com/bookdetails/Nuclear_Power_Plants_Worldwide/0810388804 +http://www.hudecek.de/gen/gen57.htm +http://www.hudecek.de/gen/gen61.htm +http://unofficial.capital.edu/students/kralph/ +http://web6.peopledaily.com.cn/gjjrb/200004/home.htm +http://www.gov.hk/hkma/eng/public/sccr/toc.htm +http://www4.50megs.com/johnphil29/86week3injury.htm +http://www4.50megs.com/johnphil29/86week3loupitlog.htm +http://naver22.juniornaver.co.kr/Entertainment_and_Arts/Performing_Arts/Theater/Musical/ +http://198.103.152.100/search*frc/dInfrastructure+(Economics)+--+Canada/dinfrastructure+economics+canada/-5,-1,0,B/frameset&F=dinfrastructure+economics&3,,0 +http://198.103.152.100/search*frc/dInfrastructure+(Economics)+--+Canada/dinfrastructure+economics+canada/-5,-1,0,B/frameset&F=dinfrastructure+economics&5,,0 +http://www.playgirl.dk/oncampus/feature/collegemovies/06.html +http://www.linux.com/networking/support/red_hat/internet/consumer/growth/ +http://www.linux.com/networking/support/red_hat/internet/consumer/mainstream/ +http://no.egroups.com/message/tengu-l/224 +http://no.egroups.com/message/tengu-l/229 +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux-2.3-4/linux/Documentation/filesystems/romfs.txt?only_with_tag=LINUX-2_3_24 +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux-2.3-4/linux/Documentation/filesystems/romfs.txt?only_with_tag=LINUX-2_3_22 +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux-2.3-4/linux/Documentation/filesystems/romfs.txt?only_with_tag=LINUX-2_3_16 +http://sunsite.informatik.rwth-aachen.de/LinuxArchives/slackware/slackware/source/a/e2fsprog/?M=A +http://bbs.syu.ac.kr/NetBBS/Bbs.dll/ipspds018/lst/qqa/f/qqo/008A/zka/B2-kB2-p +http://stulchik.list.ru/catalog/13346.html +http://katalog.wp.pl/www/Biznes_i_Ekonomia/Firmy_Podzial_wg_Branz/Elektrotechnika_i_Energetyka/index25.html +http://www.fogdog.com/cedroID/ssd3040183313356/nav/stores/tennis/ +http://www.fogdog.com/cedroID/ssd3040183313356/customer_service/shop_by_catalog.html +http://193.207.57.3/cgi-win/hiweb.exe/a2/d13/b4,4,1f,4,4,, +http://ring.omp.ad.jp/archives/lang/perl/CPAN/modules/by-authors/id/JPRIT/Envy-2.45.readme +http://193.207.57.3/cgi-win/hiweb.exe/a2/d1342/b4,4,1f,e,e,, +http://library.wuhee.edu.cn/dzsy/military/china/army/002.htm +http://library.wuhee.edu.cn/dzsy/military/china/army/006.htm +http://library.wuhee.edu.cn/dzsy/military/china/army/059.htm +http://library.wuhee.edu.cn/dzsy/military/china/army/095.htm +http://polygraph.ircache.net:8181/http_-2www.geocities.com/TimesSquare/Maze/2075/http_-2www.yahoo.com/Science/Engineering/Mechanical_Engineering/corporate.htm +http://198.103.152.100/search*frc/aGundavaram,+Shishir/agundavaram+shishir/-17,-1,0,B/frameset&F=aguirdham+maureen&1,1 +http://findmail.com/message/geewhiz/21 +http://sound-dist.secured.co.uk/cgi-bin/psProdDet.cgi/19P02|972959597|Luggage|user|0|1,0,0,1 +http://sound-dist.secured.co.uk/cgi-bin/psShop.cgi/add|19P03|972959597|Luggage|user|0|1,0,0,1 +http://nme.com/AST/Discussion_Groups/CDA/Message_Search/1,1105,37_92-0-0-7,00.html +http://namviet.subportal.com/sn/Programming/Visual_Basic_Components_H-P/5638.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4963.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4810.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4735.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/3294.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/3329.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4689.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4646.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4582.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4587.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4154.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4607.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4600.html +http://www2.so-net.ne.jp/cinet/board/log/200001/messages/4571.html +http://www.gotocity.com/local/2/us/KS/g/67455/shopping/ +http://www.mapion.co.jp/custom/AOL/admi/13/13115/ogikubo/1chome/index-1.html +http://www.mapion.co.jp/custom/AOL/admi/13/13115/ogikubo/1chome/index-21.html +http://neuro-www.mgh.harvard.edu/forum_2/ChronicPainF/Capornottocapthatisthe.html +http://www.yagoo.co.kr/stats/pitching.asp?Mlbmanid=MIGDEL7299 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=50&discrim=165,233,7 +http://www.mirror.edu.cn/res/sunsite/pub/academic/literature/book-reviews/1994/8-August/?N=D +http://www.ferien-immobilien.de/ungarn/verkauf/Versteigerungen-IB/Startseite/Allgemeine-IB/Gemeinsam/versicherungen/gebaeude/Gemeinsam/vertriebspartner.htm +http://www.ferien-immobilien.de/ungarn/verkauf/Versteigerungen-IB/Startseite/Allgemeine-IB/Gemeinsam/versicherungen/gebaeude/Gemeinsam/feedback.html +http://www.bjd.com.cn/BJWB/20000401/GB/BJWB^10199^1^01W136.htm +http://pluto.beseen.com/boardroom/u/49766/ +http://amadeus.siba.fi/doc/bitchx/documentation/color.txt +http://www.ealingcommon.londonengland.co.uk/pensions.htm +http://pub8.ezboard.com/fthecriticalpoetsmessageboartheartofcritiquing.showMessage?topicID=11.topic&index=13 +http://pub8.ezboard.com/fthecriticalpoetsmessageboareverythingelse.showMessage?topicID=223.topic&index=10 +http://www.endocrine.ru/Meln_09_10_00/_vti_bin/shtml.exe/meln_post.htm?79 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,0+9,3-12,0+18,0 +http://www.jobvillage.com/channel/jobs/media_communication/b.9255.g.1733.html +http://www.teenplatinum.com/barelylegal/no-boundarieshardcore/flashingbarely-legal/sweatingendurance/cuntamateur/chinesepetite/bootygay-bar/lubricationfellatio.html +http://www.babyheirlooms.com/catalog/htmlos.cat/001222.1.5246799112 +http://src.openresources.com/debian/src/utils/HTML/R/change_cur_jutil.html +http://genforum.genealogy.com/caudill/messages/389.html +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959928076/Catalog/1000003 +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959928076/ContentView/1000188/1/1201981 +http://www.marketingtool.com/contribute/webfirm/b.435.r.2416.html +http://dell.excite.co.jp/member_encounters/mailing_list/ml_for_women +http://www.angeredsgymn.se/doc/sdb/en/html/keylist.SIGNSET.html +http://map.ipc.co.jp/asp/onmap/r/new/g-27/f-525628/ +http://www.jpc-music.com/2549026.htm +http://www.egroups.com/message/nandscarolina/324?source=1 +http://www.jpc-music.com/2226499.htm +http://www.jpc-music.com/2226480.htm +http://tucows.bigskysoft.com/winnt/miscaudiont_rating.html +http://tucows.bigskysoft.com/winnt/adnload/69355_28370.html +http://www.hole.kommune.no/hole/journweb.nsf/weboffjournal!OpenView&Start=115.23&Count=50&Expand=130 +http://personal.atl.bellsouth.net/mia/a/j/ajcubas/ +http://yp.gates96.com/7/49/21/96.html +http://yp.gates96.com/7/49/22/39.html +http://yp.gates96.com/7/49/22/60.html +http://yp.gates96.com/7/49/22/70.html +http://yp.gates96.com/7/49/22/75.html +http://yp.gates96.com/7/49/23/8.html +http://yp.gates96.com/7/49/23/30.html +http://yp.gates96.com/7/49/23/43.html +http://yp.gates96.com/7/49/24/7.html +http://yp.gates96.com/7/49/24/8.html +http://yp.gates96.com/7/49/24/27.html +http://yp.gates96.com/7/49/24/49.html +http://yp.gates96.com/7/49/25/92.html +http://yp.gates96.com/7/49/26/56.html +http://yp.gates96.com/7/49/26/77.html +http://yp.gates96.com/7/49/28/23.html +http://yp.gates96.com/7/49/28/34.html +http://yp.gates96.com/7/49/29/56.html +http://yp.gates96.com/7/49/29/60.html +http://sound-dist.secured.co.uk/cgi-bin/psShop.cgi/add|38P08B|972959501|Communications|user|0|1,0,0,1 +http://193.207.57.3/cgi-win/hiweb.exe/a2/d170/b9,4,1f,1c,1c,, +http://wuarchive.wustl.edu/systems/linux/replay/debian/dists/unstable/non-US/binary-hurd-i386/?M=D +http://www.private-immobilien-boerse.de/friesland/verkauf/Ferien-IB/Startseite/Gemeinsam/MarketingStrategie/Allgemeine-IB/Startseite/Exklusiv-IB/Startseite/ +http://citeseer.nj.nec.com/update/269184 +http://citeseer.nj.nec.com/cidcontext/3266491 +http://citeseer.nj.nec.com/cidcontext/3266502 +http://genforum.genealogy.com/cgi-genforum/forums/hinkle.cgi?786 +http://eagle.synet.edu.cn/mirror/www.wisc.edu/grad/catalog/cals/biometry.html +http://cisne.sim.ucm.es/search*spi/cCDR7(035)TRA/ccdr7(035)tra/-5,-1,0,B/frameset&F=ccdr7(058)may&1,1 +http://www.wfg-rhein-lahn.de/goldenes-fass/schrott2.htm +http://www.jamba.nl/KNet/_KNet-6Aw8j1-pC4-ptt0/browse.nl/node.0/cdn40t70v +http://www.dcc.ufmg.br/Entnet/estrem/tsld018.htm +http://sites.uol.com.br/knaumann/DorstnerDrahtwerke.html +http://64.209.212.162/learnlots/step/0,2891,9+47+95+23413+12412_0,00.html +http://www.on-semiconductor.com/pub/prod/0,1824,productsm_ProductSummary_BasePartNumber=LM337A,00.html +http://jxi.gov.cn/yw-gn001.nsf/view!OpenView&Start=39.19&Count=30&Expand=53 +http://systemlogic.neoseeker.com/Games/Products/PC/dropship/dropship_reviews.html +http://link.fastpartner.com/do/session/600373/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/smartguy.php +http://www.bsv.ch/ch/d/sr/0_211_222_1/a10.html +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/contact.netscape.com/contact +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/entertainment.netscape.com/entertainment/ +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/games.netscape.com/computing/games/features/ +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/home.netscape.com/finance/taxes/ +http://link.fastpartner.com/do/session/600379/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/brleksaker.php +http://itcareers.careercast.com/texis/it/itjs/+TwwBmeOWD86eDhwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewPXwotoBwcaqconDBahoDwDqnaqddGmoDwBdGaqdMpwDon5aBnwMax1mtnBoDtaMwoDBnDwDqnapGdqn55n5aGn51MnaMFqryfHfREIDzmUwwwpBme+9D86Exww5rme7dwwwBrmeZpwww/jobpage.html +http://fi.egroups.com/message/handebol_aaagm/5?source=1 +http://www.crutchfield.com/cgi-bin/S-SHC3792E7De/viewcart.asp +http://www.links2go.org/more/www.asle.umn.edu/ +http://yp.gates96.com/7/69/10/58.html +http://yp.gates96.com/7/69/10/64.html +http://yp.gates96.com/7/69/10/76.html +http://yp.gates96.com/7/69/10/91.html +http://yp.gates96.com/7/69/11/31.html +http://yp.gates96.com/7/69/11/67.html +http://yp.gates96.com/7/69/11/70.html +http://yp.gates96.com/7/69/11/88.html +http://yp.gates96.com/7/69/11/96.html +http://yp.gates96.com/7/69/12/25.html +http://yp.gates96.com/7/69/12/29.html +http://yp.gates96.com/7/69/12/61.html +http://yp.gates96.com/7/69/12/65.html +http://yp.gates96.com/7/69/12/73.html +http://yp.gates96.com/7/69/13/30.html +http://yp.gates96.com/7/69/13/36.html +http://yp.gates96.com/7/69/14/8.html +http://yp.gates96.com/7/69/14/32.html +http://yp.gates96.com/7/69/14/54.html +http://yp.gates96.com/7/69/14/62.html +http://yp.gates96.com/7/69/14/83.html +http://yp.gates96.com/7/69/15/34.html +http://yp.gates96.com/7/69/15/87.html +http://yp.gates96.com/7/69/16/18.html +http://yp.gates96.com/7/69/17/5.html +http://yp.gates96.com/7/69/17/22.html +http://yp.gates96.com/7/69/17/44.html +http://yp.gates96.com/7/69/17/86.html +http://yp.gates96.com/7/69/17/88.html +http://yp.gates96.com/7/69/18/16.html +http://yp.gates96.com/7/69/18/83.html +http://yp.gates96.com/7/69/18/88.html +http://yp.gates96.com/7/69/19/0.html +http://yp.gates96.com/7/69/19/1.html +http://yp.gates96.com/7/69/19/97.html +http://213.36.119.69/do/session/152995/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/jeux/jeux_himalaya.html +http://www.egroups.com/post/sikhstudent?act=forward&messageNum=77 +http://ca.yahoo.com/Regional/U_S__States/Wisconsin/Metropolitan_Areas/Milwaukee_Metro/Business_and_Shopping/Shopping_and_Services/Food_and_Drink/Beverages/ +http://www.aelita.net/products/services/library/~archive/Download_redirect/company/news/default.htm +http://mindex.tucows.com/winme/preview/430.html +http://coda.nctu.edu.tw/vendors/DBMaker/DBMaker/driver/PHP/?S=A +http://www.streetprices.com/Electronics/Computer_Hardware_PC/Switches/Monitor/MAKE+BELKIN+COMPONENTS/sortproductbydesc/SP151043.html +http://wynnsystems.com/y9I_5aVd/careerlink.html +http://www.volny.cz/alik/akordy/zizen.htm +http://www.houses-apartment-listings.com/Michigan/city_search_criteria.asp?state=MI&City=CHAMPION +http://pub9.ezboard.com/fpyro1394pyro1394.showAddReplyScreenFromWeb?topicID=345.topic +http://www.maastrek.de/maas/01851471b455eff5cd01/1/0/1 +http://beta.mkn.co.uk/wine/order/champ2?what-mnw9=1 +http://beta.mkn.co.uk/wine/order/champ2?what-mnw14=1 +http://sunsite.org.uk/public/pub/packages/andrew/auis-6.3/overhead/ +http://www.ferien-immobilien.de/Spanien/Verkauf/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/Gemeinsam/Exklusiv-IB/Startseite/Gemeinsam/geschaeftsbedingungen.htm +http://www.trax.nilex.co.uk/trax.cgi/A1S/A2S/A3S/1AL/A2D/A1S/ +http://www.trax.nilex.co.uk/trax.cgi/A1S/A2S/A3S/1AL/A2D/C2S/ +http://tv.thevines.com/leaf/AA0000369148/3/1 +http://tv.thevines.com/leaf/AA0000369148/37/0/&favorite[join]=yes +http://www.centc251.org/forums/aca-1/dispatch.cgi/isowg4/showFolder/100001/1304571 +http://freebsd.ntu.edu.tw/perl/modules/by-module/FileCache/ILYAZ/?D=A +http://www.highwired.net/Sport/Player/0,2291,2037-46698,00.html +http://www.nl.sco.com/unixware/adminguide/qs-11-32.html +http://www.online.kokusai.co.jp/Service/V0043502/wrd/G200/service/service.html +http://www.realize.com/ambe7581.htm,qt=e784fe2f=2a38a234-14-26557ed-80000000-0-0-3-- +http://www.realize.com/am9a7d81.htm,qt=e784fe2f=2a38a234-14-26557ed-80000000-0-0-3-- +http://www.geocities.co.jp/Colosseum/7952/dragon3.html +http://uk.dir.clubs.yahoo.com/Entertainment___Arts/Magic/~other/~White_Pages/2.html +http://yp.gates96.com/13/9/60/95.html +http://yp.gates96.com/13/9/60/97.html +http://yp.gates96.com/13/9/61/12.html +http://yp.gates96.com/13/9/61/42.html +http://yp.gates96.com/13/9/61/52.html +http://yp.gates96.com/13/9/62/13.html +http://yp.gates96.com/13/9/62/19.html +http://yp.gates96.com/13/9/62/32.html +http://yp.gates96.com/13/9/62/44.html +http://yp.gates96.com/13/9/62/75.html +http://yp.gates96.com/13/9/63/71.html +http://yp.gates96.com/13/9/63/89.html +http://yp.gates96.com/13/9/64/16.html +http://yp.gates96.com/13/9/64/64.html +http://yp.gates96.com/13/9/64/83.html +http://yp.gates96.com/13/9/65/15.html +http://yp.gates96.com/13/9/65/39.html +http://yp.gates96.com/13/9/65/81.html +http://yp.gates96.com/13/9/66/19.html +http://yp.gates96.com/13/9/66/51.html +http://yp.gates96.com/13/9/67/72.html +http://yp.gates96.com/13/9/67/75.html +http://yp.gates96.com/13/9/67/93.html +http://yp.gates96.com/13/9/67/94.html +http://yp.gates96.com/13/9/68/9.html +http://yp.gates96.com/13/9/68/14.html +http://yp.gates96.com/13/9/68/23.html +http://yp.gates96.com/13/9/68/39.html +http://yp.gates96.com/13/9/68/68.html +http://yp.gates96.com/13/9/69/22.html +http://yp.gates96.com/13/9/69/62.html +http://shop.intouch.de/cgi-bin/Eternit-Shop/1678827467/IconBar +http://www.jango.com/home_and_garden/outdoor_and_garden/gardening/outdoor_furniture/miscellaneous/?num=1&prod=7 +http://ring.omp.ad.jp/archives/lang/perl/CPAN/authors/id/SHERWOOD/CHECKSUMS +http://www.acad.polyu.edu.hk/spkg/sas8/sasdoc/hrddoc/indfiles/57263.htm +http://ftp.te.fcu.edu.tw/cpatch/system/mbm/source/?D=A +http://web1.localbusiness.com/Story/0,1118,SAN_11751,00.html +http://www.amulation.com/md-l-archive/199902/msg00357.html +http://ads3.zdnet.com/c/g=r1517&c=a53585&camp=c13878&idx=2000.10.30.21.32.11/www.sega.com/seganet +http://pub.chinaccm.com/23/news/200009/30/111206.asp +http://www.online.kokusai.co.jp/Service/V0043534/wrd/G200/service/service.html +http://www.buybuddy.com/sleuth/27/1/1060204/2992/ +http://www.friend4life.com/foreign-affair/infopage/info12655.htm +http://www.friend4life.com/women/info7867.htm +http://www.friend4life.com/women/info11637.htm +http://www.chabadlibrary.org/ecatalog/EC07/EC07328.HTM +http://tulips.ntu.edu.tw/search*chi/cJC311+S275+1992/cjc++311+s275+1992/7,-1,0,E/2browse +http://stationradio.subportal.com/sn/Network_and_Internet/Misc__Networking_Tools/866.html +http://www.canlii.org/ca/regu/sor88-278/sec2.html +http://www.rottentomato.com/movies/titles/traffic/click.php?review=1 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=4,26,16,35,15 +http://www.staroriental.net/nav/soeg/ihf,aai,n2,169,Electric+Wave+Girl+1998.html +http://www.staroriental.net/nav/soeg/ihf,aai,n2,176,Electric+Wave+Girl+1998.html +http://www.teenplatinum.com/barelylegal/bellyovary/parkingjail-bait/oral-sexoral-sex/big-bonedmen/sex/main.html +http://troy.lib.sfu.ca/search/snewsinc/snewsinc/-5,1,1,B/frameset&F=snewsbrief&1,,2 +http://biblio.cesga.es:81/search*gag/dLó%3Bpez+de+Medina,+Juan/dlopez+de+medina+juan/-5,-1,0,B/frameset&F=dlopez+de+ayala+pedro+critica+e+interpretacion&1,,2 +http://proxy.rmcnet.fr/udsp68/commissions.htm +http://proxy.rmcnet.fr/udsp68/csp_colmar.htm +http://yp.gates96.com/4/0/70/88.html +http://yp.gates96.com/4/0/71/51.html +http://yp.gates96.com/4/0/71/57.html +http://yp.gates96.com/4/0/71/84.html +http://yp.gates96.com/4/0/71/85.html +http://yp.gates96.com/4/0/72/84.html +http://yp.gates96.com/4/0/72/94.html +http://yp.gates96.com/4/0/73/15.html +http://yp.gates96.com/4/0/73/92.html +http://yp.gates96.com/4/0/74/96.html +http://yp.gates96.com/4/0/75/23.html +http://yp.gates96.com/4/0/75/94.html +http://yp.gates96.com/4/0/76/41.html +http://yp.gates96.com/4/0/76/82.html +http://yp.gates96.com/4/0/77/64.html +http://yp.gates96.com/4/0/78/93.html +http://yp.gates96.com/4/0/79/72.html +http://yp.gates96.com/4/0/79/82.html +http://fi.egroups.com/message/morehealth/13?source=1 +http://cn.egroups.com/message/Multicultural/489 +http://cn.egroups.com/message/Multicultural/495 +http://cn.egroups.com/message/Multicultural/497 +http://yp.gates96.com/4/1/60/54.html +http://yp.gates96.com/4/1/60/69.html +http://yp.gates96.com/4/1/61/83.html +http://yp.gates96.com/4/1/62/68.html +http://yp.gates96.com/4/1/63/13.html +http://yp.gates96.com/4/1/63/42.html +http://yp.gates96.com/4/1/63/61.html +http://yp.gates96.com/4/1/63/73.html +http://yp.gates96.com/4/1/64/15.html +http://yp.gates96.com/4/1/64/49.html +http://yp.gates96.com/4/1/64/54.html +http://yp.gates96.com/4/1/65/19.html +http://yp.gates96.com/4/1/65/26.html +http://yp.gates96.com/4/1/65/69.html +http://yp.gates96.com/4/1/65/98.html +http://yp.gates96.com/4/1/66/57.html +http://yp.gates96.com/4/1/66/62.html +http://yp.gates96.com/4/1/66/79.html +http://yp.gates96.com/4/1/66/86.html +http://yp.gates96.com/4/1/66/88.html +http://yp.gates96.com/4/1/67/6.html +http://yp.gates96.com/4/1/67/49.html +http://yp.gates96.com/4/1/67/76.html +http://yp.gates96.com/4/1/67/78.html +http://yp.gates96.com/4/1/68/57.html +http://yp.gates96.com/4/1/69/10.html +http://yp.gates96.com/4/1/69/47.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=blich&l=de +http://www.secinfo.com/d17xw.53m.htm +http://www.cs.unm.edu/sheppard-bin/igmdesc.cgi/n=shep/I1475 +http://home.pchome.com.tw/computer/54915491/data/data2.htm +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/folderFrame/100001/0/author/3910318 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=215&discrim=164,80,165 +http://library.bangor.ac.uk/search/cHN582+.R45+1991/chn++582+r45+1991/-5,-1,0,B/bibandlinks&F=chn++573+h313&1,1 +http://mai.flora.org/forum/new-2110 +http://www.tucows.telia.no/winnt/adnload/68747_30295.html +http://www.tucows.telia.no/winnt/adnload/135780_47081.html +http://www.annotate.net/html/Annotate_Directory/Top/Regional/North_America/United_States/Louisiana/Localities/C/Coushatta +http://wine.cc.chuo-u.ac.jp/home/pub/TeX/CTAN/support/mctex/?D=A +http://pub21.ezboard.com/ujaletheadmin.showPublicProfile?language=EN +http://ftp.lip6.fr/pub11/NetBSD/NetBSD-current/src/usr.sbin/quot/Makefile +http://www.hrdc.gc.ca/socpol/cfs/bulletins/jan97/man_f.shtml +http://www.loveme.com/infopage/info23899.htm +http://polygraph.ircache.net:8181/http_-2www.fsa.org/MutareMap.asp +http://www.sdrt.com.cn/tiyuzhichuang/wangqiu/mingxingdangan/4/gelafu.htm +http://home.netvigator.com/~raympoon/digital7.htm +http://www.bemi-immobilien.de/Startseite/www.allgemeine-immobilien-boerse.de/allgemeine-ib/landkreiszwickau/Verkauf/29109700708107kirchbergvillamü/Gemeinsam/3d-service/Top-Darlehens-Konditionen/Startseite/Gemeinsam/immolink/Startseite/froben.htm +http://www.hum.auc.dk/~magnus/MHonArc/NTSEC/frm00999.html +http://www.hum.auc.dk/~magnus/MHonArc/NTSEC/frm09255.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380849/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/entry.asp +http://genforum.genealogy.com/cgi-genforum/forums/skeen.cgi?265 +http://wiem.onet.pl/wiem/00f59f.html +http://www2.ipc.pku.edu.cn/scop/data/scop.1.007.033.001.002.000.html +http://splitrock.themes.tucows.com/cursors/adnload/15789.html +http://splitrock.themes.tucows.com/cursors/adnload/15884.html +http://www.cpami.gov.tw/ymsnp/animal/insect/34654text.htm +http://lateline.muzi.net/ll/fanti/89027.shtml +http://www.hig.se/(accessed,comment,date,header,quote)/~jackson/roxen/ +http://ftpsearch.belnet.be/ftp/packages/Linux-RedHat/up2date/rhl-6.0/alpha/README +http://ftpsearch.belnet.be/ftp/packages/Linux-RedHat/up2date/rhl-6.0/alpha/etc/ +http://ftpsearch.belnet.be/ftp/packages/Linux-RedHat/up2date/rhl-6.0/alpha/lib/ +http://polygraph.ircache.net:8181/services/define/http_-2www.microsoft.com/http_-2www.microsoft.com/ntserver/http_-2www.netscape.com/comprod/mirror/http_-2gateway.olympcfunding.com/products.html +http://polygraph.ircache.net:8181/services/define/http_-2www.microsoft.com/http_-2www.microsoft.com/ntserver/http_-2www.netscape.com/comprod/mirror/http_-2gateway.olympcfunding.com/products/ +http://f7.parsimony.net/forum9177/messages/638.htm +http://f7.parsimony.net/forum9177/messages/594.htm +http://japan.medscape.com/medscape/HIV/journal/1998/v04.n03/expert1098/expert1098.html +http://golfonline.comfluent.net/cgi.pan$advsts&Dicky_Pride&102&lwfth&pga?golfstats +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=93&discrim=5,200,183 +http://girls.4gee.com/japan/azumi_kawashima/big_page/0023.htm +http://www.jobvillage.com/channel/jobs/travel/travel_guide/b.4899.g.37.html +http://www.chaos.dk/sexriddle/b/o/q/p/ +http://www.osiris.978.org/~brianr/mirrors/olga/cowpie/m/mellencamp_john/?N=D +http://www.jpc-music.com/1695294.htm +http://sunsite.org.uk/packages/TeX/uk-tex/macros/latex/contrib/supported/t-angles/?D=A +http://www.shopworks.com/index.cfm/action/info/userid/000B34B5-2F17-19FE-9038010B0A0ADCF2 +http://www.bemi-immobilien.de/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Top-Darlehens-Konditionen/Gemeinsam/Startseite/Gemeinsam/Gemeinsam/versicherungen/gebaeude/Gemeinsam/Inserieren/onlineInserieren.htm +http://www.idgnet.com/crd_playstation_254384.html +http://www.3wbooks.de/BauerGunter/BauerGunter3406402798.htm +http://library.cwu.edu/search/dSports+--+Washington+(State)+--+Periodicals/dsports+washington+state+periodicals/-5,-1,0,B/request&F=dsports+university+of+michigan&1,,2 +http://www.aelita.net/products/library/sitemap/Reg/Subscribe/sitemap/Reg/QuoteRegister/Default.htm +http://topcu.tucows.com/winme/preview/76604.html +http://tonet.com.cn/zhuanyejihua/kaoshijihua/ligonglei/dianzizhuanyezhuanke.htm +http://tonet.com.cn/zhuanyejihua/kaoshijihua/falv2001.htm +http://tonet.com.cn/zhuanyejihua/kaoshijihua/caijinglei/gongshangqiyeguanlibenke.htm +http://ftp.univ-lyon1.fr/faq/by-name/cats-faq/breeds/american-curl +http://www.videos-erotism.com/xhuge/1/hardMid3.html +http://www.zope.org/Wikis/DevSite/Projects/CoreSessionTracking/WikiWikiWeb/map +http://www.v2music.com/Scripts/WebObjects-ISAPI.dll/V2_New_Publisher.woa/74461000003304200000112720000087451/Labels.wo/603110000077451/2.0.0.5.0/3/Webobjects1 +http://books.hyperlink.co.uk/bookinfo/Willa_Cathers_Transforming_Vision/Brienzo/Gary_W./0945636660 +http://ftp.darenet.dk/tucows/winme/adnload/137112_28604.html +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/TEKNIIKKA/korkeakoulukirjastot/yliopisto-+ja+korkeakoulukirjastot/insin%F6%F6rit/kirjastot/ +http://www.pokers.com/asp/sp-asp/_/SZ--2/PD--10017288/posters.htm +http://itcareers.careercast.com/texis/it/itjs/+RwwBmelXD86elmwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewhXwotoBwcaMnmowamoGnqBdGaDntdBowBodD5aqconDBaMwGAnBoDtapd5oBodDaMwDwtnainxawqqd1DBaMFqryfHfREIDzmbwwwpBmezWD86Wwww5rme9cwwwBrmeZpwww/jobpage.html +http://berlin-charlottenburg.de/deutsch/politik/ma/062.htm +http://www.ericsson.cl/cables/protection/index.shtml +http://209.207.239.212/bkindex/c1007/f1401.html +http://209.207.239.212/bkindex/c1007/f1418.html +http://www.neoseeker.com/forums/index.php?function=edit_message&messageid=1037 +http://www.neoseeker.com/forums/index.php?function=edit_message&messageid=1199 +http://www.geocities.co.jp/SweetHome-Green/3692/PROFILE.HTML +http://www.geocities.co.jp/SweetHome-Green/3692/MELINDEX.HTML +http://myhome.naver.com/bora1234/photo.html +http://www.magicvillage.de/magicvillage/computercenter/Grafik%20%26%20Layout/Software/Macintosh/Hotline/PowerBooks/ +http://student.monterey.edu/nr/panditharatnesha/world/ +http://in.egroups.com/message/Michelles__Miracles/657 +http://www.babyheirlooms.com/catalog/htmlos.cat/001248.1.5492769465 +http://republika.pl/raduczulu/counter.html +http://adex3.flycast.com/server/socket/127.0.0.1:2800/click/OnlineCitiesSM/OnlineCitiesInteractiveCityGuides/bd378258019 +http://www.8848.net/fjnews/200007/0728/2000072811393979.htm +http://www.chaos.dk/sexriddle/m/n/x/t/ +http://www.maastrek.de/maas/01eea86f59dac641c053/1/0/4 +http://yp.gates96.com/14/79/82/8.html +http://yp.gates96.com/14/79/82/95.html +http://yp.gates96.com/14/79/82/98.html +http://yp.gates96.com/14/79/83/10.html +http://yp.gates96.com/14/79/83/16.html +http://yp.gates96.com/14/79/83/48.html +http://yp.gates96.com/14/79/84/4.html +http://yp.gates96.com/14/79/84/96.html +http://yp.gates96.com/14/79/85/34.html +http://yp.gates96.com/14/79/85/96.html +http://yp.gates96.com/14/79/86/9.html +http://yp.gates96.com/14/79/86/11.html +http://yp.gates96.com/14/79/86/28.html +http://yp.gates96.com/14/79/86/32.html +http://yp.gates96.com/14/79/86/86.html +http://yp.gates96.com/14/79/86/96.html +http://yp.gates96.com/14/79/87/96.html +http://yp.gates96.com/14/79/88/38.html +http://yp.gates96.com/14/79/88/74.html +http://yp.gates96.com/14/79/88/95.html +http://yp.gates96.com/14/79/89/57.html +http://autos.yahoo.co.jp/ucar/m1010/k10102006199904/g24/a101020060240158710008510205199904_4.html +http://www02.geocities.co.jp/HeartLand-Keyaki/7483/ +http://online.excite.de/wirtschaft/katalog/32476 +http://www9.hmv.co.uk:5555/do/session/1347777/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/Top_Navigation_Bar/top_navbar.html +http://www9.hmv.co.uk:5555/do/session/1347777/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d90_sd0_pt0.html +http://infoserv2.ita.doc.gov/efm/efm.nsf/Sources!OpenView&Start=5&Count=30&Collapse=54 +http://users.ai-lab.fh-furtwangen.de/for_local_use_only/CD-TMFUMV/daten/beisp/05321/?D=A +http://www.babyheirlooms.com/catalog/htmlos.cat/011629.1.0871727476 +http://www.fogdog.com/cedroID/ssd3040183241146/cgi-bin/MyFogdog +http://www.3w-geschichte.de/OReillyJamesT/OReillyJamesT0471287237.htm +http://www.annotate.net/html/Annotate_Directory/Top/Arts/Movies/Titles/W/World_According_to_Garp,The/ +http://dandini.cranfield.ac.uk/vl=-39536559/cl=151/nw=1/rpsv/cw/web/nw1/bargen.htm +http://cgi.superonline.com/cgi-bin/sworld43/thread.pl/forums/sworld43/oss2000/45.html?dir=nextResponse +http://cgi.superonline.com/cgi-bin/sworld43/get/forums/sworld43/oss2000/45.html?admin +http://dogbert.bizit.net/debian/dists/unstable/non-US/non-free/binary-sparc/?M=A +http://ftp.eecs.umich.edu/debian/dists/potato/main/binary-i386/misc/?D=A +http://fi.egroups.com/message/girlscouting/3383 +http://dk.egroups.com/group/scaleauto +http://members.tripod.lycos.co.kr/SM4/paper.htm +http://www.jamba.nl/KNet/_KNet-BqE8j1-JC4-pv4w/browse.nl/node.0/cde7f2elw +http://yp.gates96.com/4/6/10/47.html +http://yp.gates96.com/4/6/10/52.html +http://yp.gates96.com/4/6/10/96.html +http://yp.gates96.com/4/6/11/25.html +http://yp.gates96.com/4/6/11/61.html +http://yp.gates96.com/4/6/11/67.html +http://yp.gates96.com/4/6/11/93.html +http://yp.gates96.com/4/6/12/11.html +http://yp.gates96.com/4/6/12/28.html +http://yp.gates96.com/4/6/12/66.html +http://yp.gates96.com/4/6/12/81.html +http://yp.gates96.com/4/6/12/93.html +http://yp.gates96.com/4/6/13/86.html +http://yp.gates96.com/4/6/13/94.html +http://yp.gates96.com/4/6/14/17.html +http://yp.gates96.com/4/6/14/76.html +http://yp.gates96.com/4/6/15/61.html +http://yp.gates96.com/4/6/16/47.html +http://yp.gates96.com/4/6/16/71.html +http://yp.gates96.com/4/6/17/62.html +http://yp.gates96.com/4/6/18/1.html +http://yp.gates96.com/4/6/18/24.html +http://yp.gates96.com/4/6/18/28.html +http://158.169.50.70/eur-lex/it/lif/dat/1994/it_294D1217_09.html +http://158.169.50.70/eur-lex/it/lif/dat/1995/it_295D0928_02.html +http://158.169.50.70/eur-lex/it/lif/dat/1997/it_297D0904_03.html +http://www.irishnews.com/k_archive/181299/local4.html +http://www.irishnews.com/k_archive/181299/local14.html +http://www.irishnews.com/k_archive/181299/local16.html +http://uk.dir.yahoo.com/Regional/U_S__States/North_Carolina/Cities/Charlotte/Business_and_Shopping/Business_to_Business/Manufacturing/Casting__Moulding__and_Machining/ +http://www.uwec.edu/Academic/English/Projects/VonHaden/ +http://www.playease.com/et/beauty/img/jijinglian/jjl054.htm +http://www.digitaldrucke.de/(aktuell,für,marktplatz,metamorphose,raum,sense)/_fort/html/themen/kultur/digital/digital.htm +http://pub6.ezboard.com/fzfreesubmissiondirectoryplacestosubmitforfree.showMessage?topicID=35.topic +http://pub6.ezboard.com/fzfreesubmissiondirectoryplacestosubmitforfree.showMessage?topicID=12.topic +http://www.emerchandise.com/browse/DISNEY/TOY/b.FAVORITES%20COMICS%20CARTOONS%20DISNEY/s.CgJlPxcV +http://www.centc251.org/forums/aca-1/dispatch.cgi/hsi/showNextUnseen/fol/100001/1302769 +http://911codes.com/games/platform/gameboy/sect/div/cont/list_cheat/spray/y/id/0000010187/gid/0000003974/_cheats/_walkthroughs/_codes/_pc/_n64/_psx/_gameboy/_playstation/ +http://library.bangor.ac.uk/search/dPolice+regulations+--+Great+Britain/dpolice+regulations+great+britain/7,-1,0,E/frameset&F=dpolice+social+work+great+britain+congresses&1,1 +http://www02.u-page.so-net.ne.jp/ta2/grosh/Training/Training9.html +http://ring.shibaura-it.ac.jp/archives/linux/RedHat/redhat/code/i18n/trans/?D=A +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=15,35,22,28,26 +http://ftp.nacamar.de/pub/NetBSD/NetBSD-current/pkgsrc/graphics/ruby-gl/?S=A +http://www.academyfloral.com/state/aliro/flowers/birthdaybouquet1.html +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/KIRJASTO-+JA+TIETOPALVELUT/ammattikorkeakoulukirjastot/ammattikorkeakoulut/p%E4ij%E4t-h%E4meen+koulutuskonserni/kirjastot/ +http://www.jpc-music.com/1409509.htm +http://chat.sportsline.com/u/ce/feature/0,1518,2565545_56,00.html +http://chat.sportsline.com/u/ce/feature/0,1518,1675610_56,00.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380831/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hpstore.hewlett-packard.fr/gp +http://209.207.239.212/bkindex/c1016/f1419.html +http://209.207.239.212/bkindex/c1016/f1424.html +http://www.sports.aol.fr/Jo/Perec_2.html +http://www.citybrazil.com.br/go/smiguelaraguaia/transporte.htm +http://www.fileamerica.com/states/texas/local/cameron/ptax.html +http://www.angelfire.com/nv/bellea +http://school.educities.org/card/a4711862.html +http://school.educities.org/card/a60902.html +http://school.educities.org/card/amy60630.html +http://school.educities.org/card/aney1.html +http://school.educities.org/card/christinelee.html +http://school.educities.org/card/grace3721.html +http://school.educities.org/card/jj1245j.html +http://school.educities.org/card/jyik.html +http://school.educities.org/card/k3813813.html +http://school.educities.org/card/k78780606.html +http://school.educities.org/card/kitty1snoopy.html +http://school.educities.org/card/landy1.html +http://school.educities.org/card/m0522.html +http://school.educities.org/card/mark747.html +http://school.educities.org/card/okdh.html +http://school.educities.org/card/poppybaby.html +http://school.educities.org/card/ry21.html +http://www.secinfo.com/dvtBm.7a.htm +http://www.craft-supplies.co.uk/cgi-bin/psProdDet.cgi/HT206|972959537|Deluxe_Dividers|user|0|0,0,1,1 +http://in.egroups.com/post/book-readers?act=forward&messageNum=3829 +http://www.nacion.co.cr/ln_ee/2000/enero/31/mundo10.html +http://www.bigstar.com/news/sb/index.cfm/4ae0978g371d907g1?fa=today +http://www.bigstar.com/cs/index.cfm/4ae0978g371d907g1?fa=privacy +http://v2.bdnet.com/I/Cailleaux/I/Cannabissimo/fiche_serie.htm +http://ftp.darenet.dk/tucows/winnt/adnload/12475_29978.html +http://ftp.darenet.dk/tucows/winnt/adnload/1879_29966.html +http://www.canit.se/(h1,k15,mail,unix,www)/support/ +http://byron17.home.chinaren.com/lit/novle/maio.htm +http://www.emerchandise.com/browse/PAGEANTS/MUG/b.FAVORITES%20PAGEANTS/s.Q8q0znEj +http://stulchik.list.ru/catalog/10310.html +http://stulchik.list.ru/catalog/10967.2.html +http://dada.tucows.com/adnload/70717_30131.html +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/folderFrame/100001/0/alpha/7677890 +http://webraft.its.unimelb.edu.au/196024/students/cabong/pub/?M=A +http://www.crutchfield.com/S-fFFHlZKyKNq/shop/ +http://www.earthsystems.org/gopher/seacnet/announce97-08-03-14/1994/aug94/94-08-25-18:%20Violence%20in%20Indian%20Country%20Over%20Waste +http://www.brio.de/BRIO.catalog/39fdb65f08c44c28273fd472aa7806e3/UserTemplate/10 +http://www.qsl.net/hj3ufa +http://www-jl.jl.cninfo.net/jlweb/book/wxtd/gu_long/chuliuxiang/bat/009.htm +http://www.intel.fr/support/netport/pro/21402.htm +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957423999/957522544/Catalog/1375/001 +http://www01.u-page.so-net.ne.jp/qc4/sam-ft/gallerycraftspace.html +http://rpmfind.net/linux/RPM/mandrake/usr_src_linux-2.2.16_pcmcia-cs-3.1.14_doc_Tree.html +http://www.chrisgraef.de/chg/webdesigner_medien.html +http://www.opengroup.com/trbooks/186/1864501634.shtml +http://moviestore.zap2it.com/shopcart/s.1GUFVsoF +http://moviestore.zap2it.com/browse/MOVIES/ACTIONFI/s.1GUFVsoF +http://moviestore.zap2it.com/browse/MOVIES/PUPPET/s.1GUFVsoF +http://ocean.ntou.edu.tw/search*chi/m387.224+M178t/m387.224+m178+t/-5,-1,0,E/buttonframe&F=m387.224+m178+m&1,,0 +http://www.egroups.com/message/BalletBuds/25 +http://link.fastpartner.com/do/session/600375/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/create/learn.htm +http://www.vedomosti.spb.ru/2000/arts/spbved-2180-art-27.html +http://www.vedomosti.spb.ru/2000/arts/spbved-2180-art-42.html +http://www.vedomosti.spb.ru/2000/arts/spbved-2180-art-45.html +http://www.vedomosti.spb.ru/2000/arts/spbved-2180-art-46.html +http://www2.ipc.pku.edu.cn/scop/rsgen.cgi?pd=3nla +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959900763/Catalog/1000006 +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959900763/Catalog/1000031 +http://fi.egroups.com/message/gailporter/199 +http://fi.egroups.com/message/gailporter/222 +http://www.egroups.com/messages/X-Air_Ultralight_Aircraft/359 +http://dia.tucows.com/winme/adnload/136838_28375.html +http://dia.tucows.com/winme/adnload/136846_28383.html +http://www.letsmusic.co.kr/directory/weblink/weblink_list/1,1011,100000000186810,00.html +http://www.smcworld.com/smcworld/bp/large/0744_2_1611_2_1611b.html +http://news.pchome.com.tw/ettoday/entertainment/20001028/index-20001028155543020439.html +http://www2.stas.net/lostlane/J.html +http://allmacintosh.arrakis.es/utilsmac_rating.html +http://novel.hichinese.net/zt/zpj/k/kelisidi/kill/008.htm +http://194.174.50.23/cgi-bin/FisRun/InsertExhibitorIntoNotebook/1/interpack99/d/2891 +http://www.loisirs.ch/jifmuf/14/roedrz.html +http://www.linux.com/networking/server/business/operating_system/learning/consumer/ +http://dandini.cranfield.ac.uk/vl=-39685335/cl=158/nw=1/rpsv/cw/www/faqs.htm +http://blisty.internet.cz/1250/9901/19990108a.html +http://www.staroriental.net/nav/soeg/ihf,aai,n2,247,Electric+Wave+Girl+1998.html +http://www.multimania.com/excave/vicking.html +http://students.lsu.edu/students/main.nsf/Pages/CSISAJ1!OpenDocument&ExpandSection=5,14,21,12 +http://www.secinfo.com/dWXc8.bz.htm +http://www.secinfo.com/dWXc8.9d.htm +http://bbs.ee.ntu.edu.tw/boards/RomanceNovel/11/2/9/2/ +http://ftp.nacamar.de/pub/NetBSD/packages/1.4/amiga/emulators/?M=A +http://no.egroups.com/subscribe/windows98 +http://ftp.dei.uc.pt/pub/netscape/communicator/english/4.76/unix/unsupported/linux20_libc5/?D=A +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www.gsb.stanford.edu/sloan/sloan_fellows.html +http://apple.excite.com/entertainment/music/artists_and_genres/alternative_rock/grunge/stone_temple_pilots/merchandise/ +http://home.sprynet.com/~tales/asw2.html +http://fi.egroups.com/post/audiovision?act=reply&messageNum=145 +http://www.zema.ru/post/forum/komi_respublika/usinsk/messages/712 +http://opac.lib.rpi.edu/search/ddesert+ecology/-5,-1,0,B/browse +http://www.arm.com/sitearchitek/support.ns4/html/sdt_debug!OpenDocument&ExpandSection=6,32,7,5 +http://www.linux.com/networking/network/technology/security/community/open_source/ +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=9,33,15,36,22 +http://isbn.nu/0505523892/borders +http://www.informika.ru/text/database/geom/Draw/ris/ris34_1.htm +http://caselaw.lp.findlaw.com/casecode/uscodes/42/chapters/77/subchapters/iii/parts/h/sections/section_6374_notes.html +http://www.cyd.com.cn/zqb/19991104/GB/9672^Q805.htm +http://providenet.tukids.tucows.com/win95nt/9-12/adnload/132963_46167.html +http://www.chaos.dk/sexriddle/e/o/g/k/i/ +http://www2.brent.gov.uk/planning.nsf/013459d30f2ad00680256623005fcc0a/8af30b42469a1215802568720046524a!OpenDocument&ExpandSection=16,13,11,9,15 +http://jje.subportal.com/sn/Multimedia_and_Graphics/MPEG_Audio_Players_and_Editors/9126.html +http://www.ropnet.ru/HyperNews/edit-response.pl/case/2856.html +http://www.eveclub.com/cgi-bin/eveclub.front/972959508447/Catalog/1000045 +http://itcareers.careercast.com/texis/it/itjs/+rwwBmeO9D86MwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewDXnnqrDoqwcaiGoBnapd5oBodDaxw5nmamdq1MnDBwBodDawppcoqwBodD5a15naM15BapGdm1qBodDawxcnaMFqtPfRRZNDzme8xwwwpBme7WD86eLrwww5rm-mwwBrmeZpwww/jobpage.html +http://www.iucr.ac.uk/iucr-top/journalsonline/iucr-top/cif/software/hiccup/prods/?M=A +http://lists.omnipotent.net/mysql/199707/msg00381.html +http://www.yescall.co.kr/kyungheein/ +http://minyos.its.rmit.edu.au/~s9763278/sparks/sparks.html +http://www.movieguide.com/pressroom/events/nbcpresstour/festival_nbcpresstour9.html +http://www.gamers.net/game/190940/reviews +http://www.staroriental.net/nav/soeg/ihf,aai,n2,198,Electric+Wave+Girl+1998.html +http://marysz.freeservers.com/cgi-bin/c/736/64/dXNlcmJhbm5lcg==/gn/6616/ +http://subversion.tigris.org/source/browse/subversion/subversion/libsvn_delta/delta.h?annotate=1.34&sortby=rev +http://subversion.tigris.org/source/browse/subversion/subversion/libsvn_delta/delta.h?annotate=1.28&sortby=rev +http://sunsite.org.uk/public/public/packages/WWW/spinner/?D=A +http://sunsite.org.uk/public/public/packages/WWW/spinner/untared/ +http://www.realbig.com/miata/miata/1998-01/1635.html +http://cky.8k.com/cgi-bin/framed/1359/info/jess.html +http://cky.8k.com/cgi-bin/framed/1359/info/bran.html +http://www.loisirs.ch/jifmuf/10/bhcqud.html +http://naver22.jrnaver.co.kr/Entertainment_and_Arts/Design_Arts/Architecture/Organizations/ +http://www.zing.com/member/?name=birchpole&c=1 +http://student.monterey.edu/nr/porrasjohnny/campus/ +http://ftp.lip6.fr/pub/FreeBSD/development/FreeBSD-CVS/ports/misc/peq/files/patch-ab,v +http://www.multimania.com/lesoir2/news/sept99/quake4.htm +http://www.multimania.com/lesoir2/news/sept99/2309-12.txt +http://www.multimania.com/lesoir2/news/sept99/0609-06.txt +http://www.multimania.com/lesoir2/news/sept99/1309-13.txt +http://homepage1.nifty.com/shiraishi/school/school2.htm +http://ring.htcn.ne.jp/pub/NetBSD/NetBSD-current/pkgsrc/mbone/sdr/pkg/PLIST +http://www.chaos.dk/sexriddle/m/c/z/b/ +http://www.chaos.dk/sexriddle/m/c/z/p/ +http://map.ipc.co.jp/asp/onmap/r/new/g-26/f-523824/ +http://www.nissan.co.jp/RENAULT-DEALERS/PASSPORT/view.cgi/admission/972959650-- +http://novel.hichinese.net/xd/gt/zpj/l/liangfengyi/jingrong/010.htm +http://www.tvstore.com/browse/TV/MAGNET/s.l03qOWiP +http://www.tvstore.com/browse/TV/KEYCHAIN/s.l03qOWiP +http://www.gbnf.com/genealog2/burt/html/d0002/I1199.HTM +http://www.gbnf.com/genealog2/burt/html/d0006/I1187.HTM +http://www.gbnf.com/genealog2/burt/html/d0004/I1521.HTM +http://src.openresources.com/debian/src/graphics/HTML/R/HVcreate.html +http://yomama.tgm.ac.at/doc/susehilf/gnu/vip/Changing.html +http://www.science.uva.nl/pub/NetBSD/NetBSD-current/pkgsrc/sysutils/gmc/pkg/ +http://news.fm365.com/zonghe/20001009/156610.htm +http://homepage1.nifty.com/tojo/shin13.htm +http://www.sf.digitalcity.com/naplesfl/personals/browse.dci?cat=wsw&sort=t +http://plat.debian.or.jp/debian/dists/woody/non-free/binary-hppa/otherosfs/?M=A +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/ports/databases/gdbm/distinfo?only_with_tag=RELEASE_4_1_0 +http://bbs.csie.ntu.edu.tw/txt/Emprisenovel/ebooks/mystery/alisanderla/wsyz/013.txt +http://www.legis.state.ia.us/GA/78GA/Legislation/SCR/00000/SCR00018/?M=D +http://www.mapion.co.jp/custom/AOL/admi/23/23104/kaminagoya/2chome/index-2.html +http://ciscom.cnet.com/hardware/member/entry/0,10285,0-1069-419-1544825,00.html +http://wow-online.vhm.de/Regional/Grossbritannien/Kunst.html +http://www.cs.rit.edu/~hpb/Man/_Man_Openwin_html/html2/sigaction.2.html +http://in.egroups.com/message/talksigncreate/287 +http://rainforest.parentsplace.com/dialog/thread.pl/newclubfoot8/19.html?dir=nextThread +http://ftp.jp.debian.org/debian-non-US/dists/potato/non-US/main/binary-arm/?N=D +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=baumelte&l=de +http://www.chaos.dk/sexriddle/i/f/p/k/h/ +http://unionsoft.narod.ru/3d/anatomy/pages/head1.htm +http://src.openresources.com/debian/src/electronics/acs_021.orig/acs-021.orig/ +http://www.mapion.co.jp/custom/AOL/admi/23/23111/takagicho/2chome/index-45.html +http://dennou-q.geo.kyushu-u.ac.jp/library/Linux/debian-jp/dists/unstable/contrib-jp/binary-m68k/tex/?N=D +http://rapidus.tucows.com/winnt/adnload/54123_28460.html +http://193.207.119.193/MV/gazzette_ufficiali/303-99/8.htm +http://www.emerchandise.com/help_security/b.TV%20FRASIER/s.LoO0xS99 +http://gpul.org/ftp/os/linux/cd-images/other/ISO/suse/?M=A +http://opac.lib.rpi.edu/search/arush+sean+c/-17,-1,0,E/frameset&arush+homer+f&1,,0 +http://genforum.genealogy.com/cgi-genforum/forums/griffin.cgi?3823 +http://www.leo.org/leoclick/dce2b1c893db6a8193428ecad9ecd878+L+1__ +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=55&discrim=178,230,174 +http://www.msb.malmo.se/search*swe/aKling,+Rolf/akling+rolf/7,-1,0,B/browse +http://retailer.gocollect.com/do/session/1912785/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/checkout/shopping_cart.asp +http://st3.yahoo.co.jp/nihondo/k4932828003023.html +http://webtools.familyeducation.com/whatworks/review/front/0,2562,1-10641-2316_-7233-3,00.html +http://www.bretagne-online.com/telegram/htdocs/archive/1997/19970618/sommaire/stpoldeleon.htm +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=234&discrim=235,230,183 +http://www.yagoo.co.kr/stats/batting.asp?Mlbmanid=HAMPAT7709 +http://www.linux.com/networking/network/new/website/suse/SAP/ +http://www.linux.com/networking/network/new/website/suse/security/ +http://javatest.a-net.nl/servlet/pedit.Main/http://www.cdc.gov/ncidod/dpd/parasiticpathways/drinkingwater.htm +http://www.across.or.jp/shizuoka/nbbs.cgi/seibu:n52/post +http://www.across.or.jp/shizuoka/nbbs.cgi/seibu:n52/450 +http://www.across.or.jp/shizuoka/nbbs.cgi/seibu:n52/607 +http://dangerous.co.kr/www.sony.co.jp/ProductsPark/Consumer/Peripheral/MDData/page6.html +http://www2.sega.co.jp/bbs/article/s/sports/47/xvwixh/jlvcgk.html +http://troy.lib.sfu.ca/search/alondon+mathematical+society/alondon+mathematical+society/-5,-1,0,B/frameset&F=alondon+m+c+s&2,,3 +http://pub14.ezboard.com/fbrlproductionsfrm10.showAddTopicScreenFromWeb +http://rex.skyline.net/html/Computers_-_Monitors.html?16,computers,radio,electronics,communication +http://rex.skyline.net/html/Software_-_Developers.html?20,computers,radio,electronics,communication +http://ftp.cwi.nl/static/publications/reports/abs/MAS-R9815.html +http://www.jt.com.br/noticias/98/09/28/sd2.htm +http://www.kentuckyconnect.com/heraldleader/news/080899/sportsdocs/08chuck.htm +http://pix.egroups.com/post/ipe?act=forward&messageNum=5302 +http://tulips.ntu.edu.tw/search*chi/cHT392+Un3/cht++392+un3/-5,-1,,B/browse +http://magazines.sina.com/gourmet/contents/199912/199912-006_3_gb.html +http://collection.nlc-bnc.ca/100/201/300/january/2000/00-06-05/sanctuary.html +http://collection.nlc-bnc.ca/100/201/300/january/2000/00-06-05/blue1.html +http://www.vorlesungen.uni-osnabrueck.de/informatik/pt/code/DiagramPalettes/Components.dpalette2/Image45 +http://www.vorlesungen.uni-osnabrueck.de/informatik/pt/code/DiagramPalettes/Components.dpalette2/Image5 +http://playsite.top263.net/software/hh-13.htm +http://www.dispatch.co.za/1998/12/21/sport/MISS.HTM +http://www.allhealth.com/parentsplace/send/0,3288,14-844-1-fertility-INFERTILITY,00.html +http://www.tucows.telia.no/win2k/preview/37705.html +http://www.peopledaily.co.jp/9803/09/current/newfiles/j1020.html +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957424007/957522556/Catalog/1320/001 +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957424007/957522556/Catalog/1321/001 +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957424007/957522556/Catalog/1328/001 +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957424007/957522556/Catalog/1350/001 +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957424007/957522556/Catalog/1359/001 +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957424007/957522556/ProductView/26897 +http://www.uftree.com/UFT/WebPages/Don_MacFarlane/FEB99/d1/i0001285.htm +http://wap.jamba.de/KNet/_KNet-n4B8j1-DFd-13bgt/showInfo-jambabanner.de/node.0/cde7f1uou +http://launchbase.com/Shopping/Visual_Arts/entertainment/information/Politics.htm +http://launchbase.com/Shopping/Visual_Arts/entertainment/shopping/Electronics.htm +http://www.aoyun.sina.com.cn/news/sports/table/2000-09-15/1/4622.shtml +http://www.eggerwirt.at/1Root/Kontinent/6/Staat/7/Bundesland/21/Ort/129509/Homepage/m_homepage...1.html +http://198.103.152.100/search*frc/dSociologie+rurale+--+Ontario/dsociologie+rurale+ontario/-5,-1,0,B/frameset&F=dsociologie+religieuse+islam&1,,0 +http://msn.excite.co.jp/travel/the_country/kinki/wakayama/hot_spring_of_accommodations/inn_tourist_home_in_wakayama?summary=false +http://search.ibm.co.jp/as400/year2000/v3r2.html +http://www.allgemeine-immobilien-boerse.de/nordrhein-Westfalen/Muehlheim-ruhr/Verkauf/Allgemeine-IB/Startseite/3d-service/Private-IB/Startseite/Gemeinsam/Super-Zins-Konditionen/anforderungsformular.htm +http://spaceports.tucows.com/winnt/adnload/78908_28797.html +http://www.trax.nilex.co.uk/trax.cgi/A1S/A2R/A3R/B1S/A1D/A1S/ +http://www.babyheirlooms.com/catalog/htmlos.cat/041130.1.3206884924 +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/music/misc/thoughts/lit/misc/colorart/misc/freespeech.html +http://www.cs.rit.edu/~hpb/Lectures/2000/JRMS_590/all-2.7.html +http://www.cs.rit.edu/~hpb/Lectures/2000/JRMS_590/all-4.11.html +http://www.refdag.nl/kl/990615klfo01.html +http://pub20.ezboard.com/ftheimperiumknightsfrm11.showMessage?topicID=9.topic +http://retailer.gocollect.com/do/session/1912767/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/advanced_search.asp +http://www.thestateofcolorado.com/saudealersnew.html +http://awelymor.weblogs.co.uk/sdb/en/html/ftp://ftp.suse.com/pub/suse/i386/6.2/suse/n1/ +http://www.mirror.kiev.ua:8083/paper/2000/21/1251/text/21-13-3.htm +http://www.recipezaar.com/browse/0110FC1070110A301109901109E00F06D +http://www.linux.com/networking/network/vpn/server/Unix/ +http://www.gasex.com/main.html?m4m.gallery.twinks +http://www.xtdnet.nl/listarch/linux-router/1998-05-01/nav00046.html +http://www.fogdog.com/cedroID/ssd3040183325831/cgi-bin/CedroCommerce?func=EditBasket +http://www.totalmarketing.com/an/basket.pl/cancel/xwxm6773.94076 +http://ciaoweb.tucows.com/winnt/adnload/56695_29112.html +http://www.brio.de/BRIO.catalog/39fe2f6006e4fc48273fd472aa7806e0/UserTemplate/1 +http://retailer.gocollect.com/do/session/1912715/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/top_ten.asp?pagenum=2 +http://retailer.gocollect.com/do/session/1912715/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/dealer_lookup.asp +http://www.streetprices.com/Electronics/Computer_Hardware_PC/Motherboards/ATX/Slot1/Via_Pro133/sortproductbymake/sortcategorybylowprice/ +http://www.streetprices.com/Electronics/Computer_Hardware_PC/Projectors/MAKE+CTX/sortdetailbystock/sortproductbyhighprice/sortcategorybycount/SP318392.html +http://www.multimania.com/egypt95/img0017.htm +http://dic.empas.com/show.tsp/?q=fourteenthly&f=B +http://linux2.ipc.pku.edu.cn/scop/pdb.cgi?sid=d1repc2 +http://www.schlagertempel.de/RobertPayer/B00000B8D2.htm +http://www.cricinfo.com/link_to_database/INTERACTIVE/MAGAZINE/1996-97/SL_IN_NZ/SL_IN_NZ_FEEDBACK_1.html +http://mediate.magicbutton.net/do/session/625637/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-top50.html +http://www.clickm.dk/Clickmusic_Web_Guide/Bands_and_Artists/B/Better_Than_Ezra/ +http://www.clickm.dk/Clickmusic_Web_Guide/Bands_and_Artists/B/Breeders,_The/ +http://www.maastrek.de/maas/71eb3baf4c78ed98ef94/1/0/4 +http://www.trnonline.com/archives/1999archives/07221999/obits/24620.shtml +http://www.recipezaar.com/browse/0110FC1070110A100F06D0110A00110A3 +http://www.areaguide.net/addlisting.asp?book=box&CatID=516 +http://webraft.its.unimelb.edu.au/196023/students/lucym/ +http://sunsite.org.uk/public/0-Most-Packages/quake/utils/frontends/qshel15b.txt +http://pub14.ezboard.com/flfiaglarafabianisagoddess.emailToFriend?topicID=858.topic +http://www.realize.com/am4d0481.htm,qt=e784fe2f=2a38a234-4-7cf2ef-1-1-0-3-- +http://www.realize.com/am7bcd81.htm,qt=e784fe2f=2a38a234-4-7cf2ef-1-10-0-3-- +http://mailman.real-time.com/rte-crossfire/1993/Dec/msg00022.html +http://mailman.real-time.com/rte-crossfire/1993/Dec/msg00000.html +http://mailman.real-time.com/rte-crossfire/1993/Dec/msg00009.html +http://www.eallinfo.com/A55782/sameeron.nsf/homeFood!OpenPage&ExpandSection=8,4,3,6 +http://www.ami.dk/udgivelser/emne/36.html +http://www-x500-1.uni-giessen.de:8890/Lcn%3dKai%20Cheong%20HO,ou%3dEstates%20Management%20Office,o%3dHong%20Kong%20University%20of%20Science%20and%20Technology,c%3dHK +http://ftp.telepac.pt/pub/cpan/modules/by-module/DBD/DMOW/?D=A +http://members.se.tripod.de/aah/jochumsen/per02614.htm +http://www.academyfloral.com/state/cacat/flowers/funeralofferingshare.html +http://www.hotelboulevard.com/fr/paris/standard/htmlb877e62937802c0678f4638130be1ef0/sessionLang/ANG/prov/browse/cp/75013/resultatSearch.html +http://www.alsapresse.com/jdj/00/03/24/AK/article_4.html +http://www.mairie-montreuil93.fr/ville_pratique/environ/democrat/printemps/_vti_cnf/interstice.htm +http://variety.studiostore.com/help/b.FAVORITES%20COMICS%20CARTOONS%20POWERPUFF/s.UAREyMtL +http://ftp.sektornet.dk/tucows/winme/adnload/137341_28799.html +http://www.eveclub.com/cgi-bin/eveclub.front/972959532302/Catalog/1000046 +http://www.eveclub.com/cgi-bin/eveclub.front/972959532302/ClubBoard/list/1000022 +http://findmail.com/post/geewhiz?act=reply&messageNum=2039 +http://orders.mkn.co.uk/toy/rattles/order/now.en$NOK?what-bells=1 +http://www.buybuddy.com.au/sleuth/26/1/502/10134/ +http://spokesmanreview.sportshuddle.com/sports/baseball/playbetter/ask-expert/vincent3.asp +http://ant.i.hosei.ac.jp/Ant.WWW/PCD0420/HTMLE/29.html +http://ant.i.hosei.ac.jp/Ant.WWW/PCD0420/HTMLE/34.html +http://builder.hw.net/frmRestDir/0,1112,'1~21~325~1~S~074800~90270',00.html +http://builder.hw.net/frmRestDir/0,1112,'1~21~325~1~S~074800~09890',00.html +http://dennou-h.ees.hokudai.ac.jp/library/Linux/debian-jp/dists/hamm-jp/non-free/binary-i386/games/?M=A +http://www.peopledaily.com.cn/GB/paper68/1469/236625.html +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/koffice/kformula/BracketElement.cc?hideattic=1&sortby=rev +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/koffice/kformula/FractionElement.cc?hideattic=1&sortby=rev +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/koffice/kformula/MIMETYPE-Format?hideattic=1&sortby=rev +http://linuxberg.ii.net/conhtml/preview/7963.html +http://213.36.119.69/do/session/152992/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/reserver/hotels.html +http://213.36.119.69/do/session/152992/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.spycamera.com/webcam/ +http://ftp.netc.pt/pub/idgames/levels/doom/d-f/deathme.txt +http://ftp.netc.pt/pub/idgames/levels/doom/d-f/dork.txt +http://ustlib.ust.hk/search*chi/dsea+stories/dsea+stories/-5,-1,0,B/browse +http://members.fortunecity.com/skinweaver/nf/nfpin01.htm +http://se.egroups.com/group/French_ +http://www.gencat.es/cgi-bin/bc/drawer.cgi/LD/0074/L00465?101 +http://oss.sgi.com/cgi-bin/cvsweb.cgi/projects/ogl-sample/main/gfx/lib/glut/glut_shapes.c?sortby=author +http://www.teacherformation.org/html/od/facilitators.cfm/task1,about/discussion_id,2/xid,9456/yid,7276398 +http://genforum.genealogy.com/cgi-genforum/forums/getchell.cgi?230 +http://www9.hmv.co.uk:5555/do/session/1347795/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d100_sd0_pt0.html +http://www.brd.net/brd-cgi/brd_multimedia/bildbearbeitung/WZ01K0DJ/beurteilung/ci=972850465.htm +http://retailer.gocollect.com/do/session/1912745/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/affiliate_network.asp +http://www.fao.org/icatalog/orders/basket.asp?prev2=yes&aries_id=1310 +http://www.realestate-mls.com/list.cgi/VACANT_LAND|WATERFRONT|Edenville!Midland!MI +http://www.geocities.co.jp/SilkRoad-Desert/1661/profile/profile.html +http://hp-partner.whowhere.lycos.com/hp/chick/com/nj/ +http://hp-partner.whowhere.lycos.com/hp/chick/com/next/ +http://hp-partner.whowhere.lycos.com/hp/chick/com/nightflight/ +http://www.emerchandise.com/browse/FRIENDS/TSHIRT/20/10/b.TV%20FRIENDS/s.kGIgjr5i +http://dk.egroups.com/group/anarchymcgill +http://bbs.gznet.edu.cn/cgi-bin/getannounce//groups/GROUP_3/WinNT_Win2k/smthbbs/Dir002 +http://de.excite.de/computer/katalog/12947 +http://www.bizline.co.kr/library/data/002/001/007/008/020/002/000017.html +http://www.bizline.co.kr/library/data/002/001/007/008/020/002/000046.html +http://saleonall.com/cat/OPTOMA/6492/video/projectors/145336/oneprod.html +http://sun1.rrzn-user.uni-hannover.de/jgaertner/matlab/help/techdoc/newfeat/ch213.html +http://sun1.rrzn-user.uni-hannover.de/jgaertner/matlab/help/techdoc/newfeat/newfeat.html +http://excite.de/wirtschaft/katalog/37737 +http://www.digitaldrucke.de/(aktuell,kino,kultur,werbung)/_fort/html/themen/aktuell/events/events.htm +http://www.digitaldrucke.de/(aktuell,kino,kultur,kunst)/suche/uebersicht.html +http://www.online.kokusai.co.jp/Stock_corner/V0043566/wrd/G500/stock_corner/stock_corner.html +http://yp.gates96.com/4/37/0/92.html +http://yp.gates96.com/4/37/1/3.html +http://yp.gates96.com/4/37/1/38.html +http://yp.gates96.com/4/37/1/58.html +http://yp.gates96.com/4/37/2/21.html +http://yp.gates96.com/4/37/3/56.html +http://yp.gates96.com/4/37/3/68.html +http://yp.gates96.com/4/37/3/79.html +http://yp.gates96.com/4/37/4/1.html +http://yp.gates96.com/4/37/4/48.html +http://yp.gates96.com/4/37/4/99.html +http://yp.gates96.com/4/37/5/27.html +http://yp.gates96.com/4/37/6/1.html +http://yp.gates96.com/4/37/6/7.html +http://yp.gates96.com/4/37/6/80.html +http://yp.gates96.com/4/37/7/0.html +http://yp.gates96.com/4/37/7/5.html +http://yp.gates96.com/4/37/7/9.html +http://yp.gates96.com/4/37/7/12.html +http://yp.gates96.com/4/37/7/49.html +http://yp.gates96.com/4/37/7/97.html +http://yp.gates96.com/4/37/8/15.html +http://yp.gates96.com/4/37/8/32.html +http://yp.gates96.com/4/37/8/62.html +http://yp.gates96.com/4/37/8/76.html +http://yp.gates96.com/4/37/8/96.html +http://yp.gates96.com/4/37/9/12.html +http://yp.gates96.com/4/37/9/14.html +http://yp.gates96.com/4/37/9/23.html +http://yp.gates96.com/4/37/9/78.html +http://yp.gates96.com/4/37/9/80.html +http://cgi.cnn.com/US/9601/state_union_poll/state_union_speech/pm/ +http://freethemes.netc.pt/cursors/adnload/16904.html +http://freethemes.netc.pt/cursors/preview/16926.html +http://freethemes.netc.pt/cursors/adnload/16953.html +http://library.bangor.ac.uk/search/dTelevision+broadcasting+of+news+--+Wales/dtelevision+broadcasting+of+news+wales/-17,-1,0,B/frameset&F=dtelevision+broadcasting+moral+and+ethical+aspects&1,1 +http://home.baoding.cn.net/~snowcxm/photoshop/newpage6tp.htm +http://home.baoding.cn.net/~snowcxm/photoshop/newpage6xq2.htm +http://dennou-q.geo.kyushu-u.ac.jp/library/Linux/debian-jp/dists/woody/non-free-jp/binary-sparc/otherosfs/?D=A +http://www.tucows.ch/winnt/toolnt_size.html +http://www.sdinfonet.com.cn/379/26/379269983.htm +http://www.sdinfonet.com.cn/379/26/379269980.htm +http://www.egroups.com/message/wdf/3368 +http://de.excite.de/bildung/katalog/35821 +http://kidneyfailure.shn.net/content/article/1677.57596 +http://kidneyfailure.shn.net/content/article/1677.57625 +http://kidneyfailure.shn.net/content/article/1677.57517 +http://kidneyfailure.shn.net/content/article/1677.57456 +http://kidneyfailure.shn.net/content/article/1677.57562 +http://dia.tucows.com/winme/adnload/138490_29803.html +http://www.nhic.or.kr/netbbs/Bbs.cgi/nhic31062/lst/qqo/004A +http://www.nhic.or.kr/netbbs/Bbs.cgi/nhic31062/qry/zka/B2-kB23p/pno/0/qqatt/^ +http://www.nhic.or.kr/netbbs/Bbs.cgi/nhic31062/qry/zka/B2-kB2-n/pno/0/qqatt/^ +http://www.nhic.or.kr/netbbs/Bbs.cgi/nhic31062/qry/zka/B2-kB2-o/pno/0/qqatt/^ +http://dk.egroups.com/message/tw2002/3626 +http://dk.egroups.com/message/tw2002/3644 +http://www.spiral.at/Katalog/Artikel/8908435/ +http://www.spiral.at/Katalog/Artikel/8908842/ +http://168.160.224.62/insurance/200006/10/114941.asp +http://168.160.224.62/insurance/200006/10/114219.asp +http://tucows.soneraplaza.nl/termnt_license.html +http://pub13.ezboard.com/ubelegruin.showPublicProfile?language=EN +http://troy.lib.sfu.ca/search/tbiometrics/tbiometrics/-5,-1,0,B/exact&F=tbiometrical+genetics+the+study+of+continuous+variation&1,2/limit +http://futures.homeway.com.cn/lbi-html/news/content/20001013/172026.shtml +http://jproxy.uol.es/jproxy/http://www.channel6000.com/sh/sports/columnist/stories/columnists-20001030-154321.html +http://www.linux.com/networking/network/free/release/community/development/ +http://pub17.ezboard.com/fskysurfingskysurfersubb.showAddReplyScreenFromWeb?topicID=4.topic +http://ring.tains.tohoku.ac.jp/pub/linux/debian/debian-jp/dists/woody/contrib-jp/binary-m68k/oldlibs/?D=A +http://10000downloads.subportal.com/sn/Network_and_Internet/Misc__Communications_Tools/12507.html +http://www.hbdaily.com.cn/ctdsb/19991101/GB/ctdsb^1042^06^Ct06b08.htm +http://cytobase.cnusc.fr:8101/textes/PURDmail/1998-12/nav00129.html +http://www.brio.de/BRIO.catalog/39fe2f73050d53aa2741d472aa7806d2/UserTemplate/9 +http://www.anekdot.ru:8084/an/an0007/t000731.html +http://statweb.byu.edu/sasdoc/sashtml/gref/z0265802.htm +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux/drivers/char/ftape/Makefile?only_with_tag=davem-cvs-merge +http://www.intellicast.com/Golf/World/UnitedStates/Southeast/NorthCarolina/Hawksnest/WINDcast/d1_00/bannerAd.shtml +http://dailynews.sina.com.hk/sinaNews/wiser/hkStock/2000/0720/1418727.html +http://ftp.dti.ad.jp/pub/lang/CPAN/authors/id/A/AG/AGUL/?S=A +http://link.fastpartner.com/do/session/600392/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/jobpilot.php +http://link.fastpartner.com/do/session/600392/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/smartguy.php +http://citeseer.nj.nec.com/cidcontext/1024594 +http://www.burstnet.com/ads/ad4820b-map.cgi/1395444997 +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kdeutils/kpm/proc.h?r1=1.6&only_with_tag=HEAD +http://www.uftree.com/UFT/WebPages/JenHawkins/ALL/d0/i0001501.htm +http://www.uftree.com/UFT/WebPages/JenHawkins/ALL/d0/i0000641.htm +http://www.uftree.com/UFT/WebPages/JenHawkins/ALL/d1/i0000932.htm +http://www.uftree.com/UFT/WebPages/JenHawkins/ALL/d1/i0000762.htm +http://www.uftree.com/UFT/WebPages/JenHawkins/ALL/d1/i0000997.htm +http://www.uftree.com/UFT/WebPages/JenHawkins/ALL/d1/i0001325.htm +http://www.uftree.com/UFT/WebPages/JenHawkins/ALL/nindex.htm +http://www.primenet.com/~g-lady/Farewell/_borders/ +http://imasy.or.jp/~iwao/hokkaido/kushiro.html +http://citeseer.nj.nec.com/nrelated/0/208436 +http://www.zeal.com/Arts___Entertainment/Literature/Authors/Lovecraft__H_P_/Books/Cthulhu_Campus_Crusade_for_Cthulhu/ +http://ftp1.se.debian.org/debian/dists/woody/contrib/binary-mipsel/mail/?M=A +http://ftp1.se.debian.org/debian/dists/woody/contrib/binary-mipsel/mail/?S=A +http://webtools.familyeducation.com/whatworks/item/front/0,2551,1-10698-1981-,00.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380859/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/REGISTRATION/entry.asp +http://www.collectingnation.com/cgi-bin/bn/view_feedback.mod/pn?HANDLE=pokeweed +http://www.egroups.com/messages/Future-History-L/213 +http://www.egroups.com/message/Future-History-L/192 +http://www.burstnet.com/ads/cb7826a-map.cgi/1384588733 +http://www.cs.com.cn/csnews/articles/142_23823.htm +http://search.yam.com.tw/en/new/edu/hs/voca/tpc_vs/ +http://ftp.univie.ac.at/packages/tex/macros/latex2e/contrib/supported/vmargin/?D=A +http://citeseer.nj.nec.com/cidcontext/3145269 +http://yp.gates96.com/11/72/80/34.html +http://yp.gates96.com/11/72/80/36.html +http://yp.gates96.com/11/72/80/76.html +http://yp.gates96.com/11/72/81/26.html +http://yp.gates96.com/11/72/81/67.html +http://yp.gates96.com/11/72/83/68.html +http://yp.gates96.com/11/72/84/29.html +http://yp.gates96.com/11/72/84/39.html +http://yp.gates96.com/11/72/85/56.html +http://yp.gates96.com/11/72/85/63.html +http://yp.gates96.com/11/72/85/96.html +http://yp.gates96.com/11/72/86/3.html +http://yp.gates96.com/11/72/86/28.html +http://yp.gates96.com/11/72/86/59.html +http://yp.gates96.com/11/72/86/63.html +http://yp.gates96.com/11/72/88/43.html +http://yp.gates96.com/11/72/89/8.html +http://yp.gates96.com/11/72/89/13.html +http://yp.gates96.com/11/72/89/20.html +http://cometweb01.comet.co.uk/do!session=132039&vsid=700&tid=20&cid=37030&mid=1000&rid=1060&chid=1713&url=eqqLmwlGltt5tkkHbqpLZXmLbkZHljlKaltLkilLXalKfkaLbukKeqjLi1 +http://iworld.freethemes.com/savers/adnload/77213.html +http://iworld.freethemes.com/savers/adnload/35420.html +http://www.questlink.com/QL/CDA/Research/ProductBrief/1,1768,0_11201_353170_43264,00.html +http://www.questlink.com/QL/CDA/Research/ProductBrief/1,1768,0_11201_353170_43305,00.html +http://www2.eunet.lv/library/iso/HISTORY/RUSSIA/Mirrors +http://nathanael.upi.jussieu.fr/tele6.nsf/autres+centres+de+formations!OpenPage&ExpandSection=10,3,5,16,14,6 +http://nathanael.upi.jussieu.fr/tele6.nsf/autres+centres+de+formations!OpenPage&ExpandSection=17,3,5,16,14,6 +http://opac.lib.rpi.edu/search/dnatural+history+united+states+historiography+dictionaries/-17,-1,0,B/browse +http://opac.lib.rpi.edu/search/dnatural+history+united+states+historiography+dictionaries/7,-1,0,B/browse +http://www.sportinggreen.com/news/20001014/fbo/fbc/abb/001014.0391.html +http://yp.gates96.com/0/14/10/63.html +http://yp.gates96.com/0/14/10/80.html +http://yp.gates96.com/0/14/11/32.html +http://yp.gates96.com/0/14/11/37.html +http://yp.gates96.com/0/14/11/80.html +http://yp.gates96.com/0/14/13/21.html +http://yp.gates96.com/0/14/13/23.html +http://yp.gates96.com/0/14/13/38.html +http://yp.gates96.com/0/14/13/49.html +http://yp.gates96.com/0/14/13/90.html +http://yp.gates96.com/0/14/14/53.html +http://yp.gates96.com/0/14/14/63.html +http://yp.gates96.com/0/14/14/77.html +http://yp.gates96.com/0/14/15/12.html +http://yp.gates96.com/0/14/15/88.html +http://yp.gates96.com/0/14/15/96.html +http://yp.gates96.com/0/14/16/27.html +http://yp.gates96.com/0/14/16/62.html +http://yp.gates96.com/0/14/16/67.html +http://yp.gates96.com/0/14/16/86.html +http://yp.gates96.com/0/14/16/92.html +http://yp.gates96.com/0/14/17/15.html +http://yp.gates96.com/0/14/17/22.html +http://yp.gates96.com/0/14/17/44.html +http://yp.gates96.com/0/14/18/27.html +http://yp.gates96.com/0/14/18/29.html +http://yp.gates96.com/0/14/18/83.html +http://yp.gates96.com/0/14/19/35.html +http://yp.gates96.com/0/14/19/58.html +http://www.123bestphonerates.com/q/001p/vn/ZWUdEJwdxM.htm +http://www.trax.nilex.co.uk/trax.cgi/A1C/B1U/A2S/B3L/A4S/B1L/ +http://www.trax.nilex.co.uk/trax.cgi/A1C/B1U/A2S/B3L/A4S/C2D/ +http://southwind.themes.tucows.com/skins/icq/preview/68532.html +http://southwind.themes.tucows.com/skins/icq/adnload/77797.html +http://southwind.themes.tucows.com/skins/icq/preview/55623.html +http://southwind.themes.tucows.com/skins/icq/adnload/51324.html +http://southwind.themes.tucows.com/skins/icq/adnload/26609.html +http://southwind.themes.tucows.com/skins/icq/adnload/48629.html +http://southwind.themes.tucows.com/skins/icq/adnload/48628.html +http://www.webcom.com.mx/cronica/1999/mar/09/neg01.html +http://jproxy.uol.es/jproxy/http://mars.jpl.nasa.gov/msp98/news/mpl000207.html +http://jproxy.uol.es/jproxy/http://mars.jpl.nasa.gov/msp98/news/news61.html +http://jproxy.uol.es/jproxy/http://mars.jpl.nasa.gov/msp98/ds2/fact.html +http://jproxy.uol.es/jproxy/http://mars.jpl.nasa.gov/mgs/sci/mola/98lander.html +http://jproxy.uol.es/jproxy/http://mars.jpl.nasa.gov/msp98/news/status990123.html +http://ustlib.ust.hk/search*chi/dmarriage/dmarriage/-5,-1,0,B/exact&F=dmarriage+china&1,4/limit +http://mediate.magicbutton.net/do/session/625641/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-artc.html +http://www.scifi.com/cgi-bin/rbox/articles.pl?1&6&1721&20 +http://www.areteoutdoors.com/contribute/earth/b.97.r.54.g.1706.html +http://members.tripod.lycos.co.kr/ifoo6981/?M=A +http://link.fastpartner.com/do/session/600395/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/bol.php +http://link.fastpartner.com/do/session/600395/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/mediatransfer.php +http://link.fastpartner.com/do/session/600395/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/smartguy.php +http://www.safrex.com/catalog/elite08/elite084c.html +http://www.911codes.com/games/platform/psx/sect/div/cont/list_cheat/spray/y/id/0000005511/gid/0000003893/_cheats/_walkthroughs/_codes/_pc/_n64/_psx/_gameboy/_playstation/ +http://yp.gates96.com/7/44/10/4.html +http://yp.gates96.com/7/44/10/15.html +http://yp.gates96.com/7/44/10/30.html +http://yp.gates96.com/7/44/10/32.html +http://yp.gates96.com/7/44/10/36.html +http://yp.gates96.com/7/44/11/1.html +http://yp.gates96.com/7/44/11/41.html +http://yp.gates96.com/7/44/11/44.html +http://yp.gates96.com/7/44/12/29.html +http://yp.gates96.com/7/44/12/76.html +http://yp.gates96.com/7/44/12/81.html +http://yp.gates96.com/7/44/13/56.html +http://yp.gates96.com/7/44/14/19.html +http://yp.gates96.com/7/44/15/14.html +http://yp.gates96.com/7/44/15/52.html +http://yp.gates96.com/7/44/15/62.html +http://yp.gates96.com/7/44/15/72.html +http://yp.gates96.com/7/44/15/78.html +http://yp.gates96.com/7/44/15/81.html +http://yp.gates96.com/7/44/15/82.html +http://yp.gates96.com/7/44/16/78.html +http://yp.gates96.com/7/44/16/93.html +http://yp.gates96.com/7/44/17/51.html +http://yp.gates96.com/7/44/17/75.html +http://yp.gates96.com/7/44/18/43.html +http://yp.gates96.com/7/44/18/92.html +http://yp.gates96.com/7/44/19/26.html +http://www3.newstimes.com/archive2000/oct17/bze.htm +http://member.aol.co%20m/askmo/ +http://home.excite.co.uk/directory/categories/528195 +http://www.scifi.com/bboard/browse.cgi/1/5/545/11566?pnum=1 +http://member.shangdu.net/home1/havdone/game/gonglue/ljcq.htm +http://member.shangdu.net/home1/havdone/game/gonglue/lishou.htm +http://archiv.leo.org/cgi-bin/leo-md5.pl/pub/comp/usenet/comp.sources.misc/dostrace/ +http://yp.gates96.com/8/70/91/12.html +http://yp.gates96.com/8/70/91/20.html +http://yp.gates96.com/8/70/91/45.html +http://yp.gates96.com/8/70/92/29.html +http://yp.gates96.com/8/70/92/40.html +http://yp.gates96.com/8/70/92/74.html +http://yp.gates96.com/8/70/93/9.html +http://yp.gates96.com/8/70/93/11.html +http://yp.gates96.com/8/70/94/10.html +http://yp.gates96.com/8/70/94/90.html +http://yp.gates96.com/8/70/95/4.html +http://yp.gates96.com/8/70/95/13.html +http://yp.gates96.com/8/70/95/58.html +http://yp.gates96.com/8/70/95/74.html +http://yp.gates96.com/8/70/95/80.html +http://yp.gates96.com/8/70/96/34.html +http://yp.gates96.com/8/70/96/65.html +http://yp.gates96.com/8/70/97/0.html +http://yp.gates96.com/8/70/97/16.html +http://yp.gates96.com/8/70/97/75.html +http://yp.gates96.com/8/70/98/27.html +http://yp.gates96.com/8/70/98/60.html +http://www.icopyright.com/1.1638.306154 +http://www.zeal.com/category/be_zealous.jhtml?cid=828 +http://lib1.nippon-foundation.or.jp/1996/0621/contents/004.htm +http://www.haikou.hainan.gov.cn/pandect/nj/n96jada.htm +http://www.chaos.dk/sexriddle/s/e/x/p/b/m/s/ +http://www.symantec.ca/region/uk/resources/mobile/nav.html +http://retailer.gocollect.com/do/session/1912798/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/products/product_lines.asp +http://polygraph.ircache.net:8181/services/define/http_-2www.microsoft.com/ie/Tabitha/http_-2www.adultlinks.net/gallery.shtml +http://f22.parsimony.net/forum42460/messages/1.htm +http://www.greenleaves.com/bookcat/gb_0722530986.html +http://www.classiccmp.org/mail-archive/classiccmp/1998-06/0638.html +http://www1.onelist.com/dir/Society/Paranormal/UFOs/Biblical_Perspectives +http://home.hiwaay.net/~bjacobs/genealogy/laster/html/d0055/g0000045.html +http://link.fastpartner.com/do/session/600374/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/netmaling.php +http://big5.peopledaily.com.cn/haiwai/200003/03/newfiles/A104.html +http://ustlib.ust.hk/search*chi/achang+chieh+mei/achang+chieh+mei/-5,-1,0,B/frameset&F=achang+chieh+fu&1,,2 +http://teleline.terra.es/personal/mgsair/chtml/ejemplos/marcos1.html +http://myhome.naver.com/toktok01/bbs.php3?p_work=admin&p_page=1 +http://netway.pda.tucows.com/palm/adnload/34443_22051.html +http://netway.pda.tucows.com/palm/adnload/34930_22057.html +http://netway.pda.tucows.com/palm/adnload/34435_22044.html +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kmusic/brahms/qtWaveTrack.h?sortby=rev&only_with_tag=HEAD +http://sinr.net/book/content/39/8411.html +http://www.egroups.com/post/gvocsa?act=reply&messageNum=145 +http://www.diogenes.ch/4DACTION/web_rd_aut_prview/a_id=7056669&area=&ID=483352 +http://www.brio.de/BRIO.catalog/39fe2f7d06fe4a08273fd472aa7806a9/UserTemplate/1 +http://www3.newstimes.com/archive2000/sep01/rgd.htm +http://community.webshots.com/photo/5886633/5886821zAagKCgZhs +http://community.webshots.com/photo/5886633/5917061PxBHHqElgV +http://www.dnai.com/~mbaum/anita/html/eng/art/images/image38.html +http://www.houses-apartment-listings.com/Michigan/city_search_criteria.asp?state=MI&City=CLINTON +http://www.brio.de/BRIO.catalog/39fdb87c09896af6273fd472aa78076c/UserTemplate/10 +http://www.expressindia.com/ie/daily/19990129/02950495p.html +http://www.linux.com/networking/web/unix/internet/project/security/ +http://www.linux.com/networking/web/unix/internet/project/Red_Hat/ +http://www.linux.com/networking/web/unix/internet/project/freshmeat/ +http://www.linux.com/networking/web/unix/internet/project/?kw_offset=50 +http://ring.yamanashi.ac.jp/pub/linux/debian/debian/dists/Debian2.2r0/non-free/binary-i386/science/?N=D +http://ftp.task.gda.pl/pub/games/idgames/utils/level_edit/acaddoom.txt +http://www.affiliate.hpstore.hp.co.uk/do/session/380864/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/FR/REGISTRATION/entry.asp +http://fi.egroups.com/post/allianc?act=reply&messageNum=2305 +http://polygraph.ircache.net:8181/services/design/company/http_-2burn.ucsd.edu/~abcf +http://polygraph.ircache.net:8181/services/design/company/miami.htm +http://www.utexas.edu/ftp/admin/AI_ATTIC/ATW/Mosaic.instruct/?D=A +http://ftp.du.se/disk3/redhat/updates/powertools/current/alpha/ +http://www.multicosm.com/facade/demo.multicosm.com/facade/www.informationweek.com/mediakit/00/default.html +http://www.multicosm.com/facade/demo.multicosm.com/facade/www.informationweek.com/mediakit/00/about_overview.html +http://www7.tok2.com/home/maki67/menu.htm +http://www.mapion.co.jp/custom/AOL/admi/23/23103/tsujicho/2chome/index-24.html +http://sunsite.org.uk/public/computing/networks/internet/ietf/printmib/printmib-attendees-97apr.txt +http://ftp.univie.ac.at/packages/tex/macros/latex2e/contrib/supported/nomencl/?N=D +http://spaceports.tucows.com/winme/adnload/137993_30287.html +http://habenix.uni-muenster.de/Rektorat/Forschungsberichte-1997-1998/fo05acd01.htm +http://www.power2lead.com/Global/English.nsf/pgWWLocations!OpenPage&ExpandSection=2,25,7,32,18 +http://www.teacherformation.org/html/od/facilitators.cfm/task1,help/discussion_id,2/xid,6155/yid,3651726 +http://itcareers.careercast.com/texis/it/itjs/+IwwBmeS9D867xwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew7hmwGAnBoDtapGdtGwMamnVncdpa51ppdGBaqconDBaqdMM1DoqwBodDaoDVn5BMnDBapGdm1qBaMwDwtnaqGnwBoVnaMFqhgfHNEDzm7wwwpBmeg9D86exqwww5rmeqDwwwBrmeZpwww/morelike.html +http://itcareers.careercast.com/texis/it/itjs/+XwwBmie0B-deaqwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew7hmwGAnBoDtapGdtGwMamnVncdpa51ppdGBaqconDBaqdMM1DoqwBodDaoDVn5BMnDBapGdm1qBaMwDwtnaqGnwBoVnaMFqhgfHNEDzm7wwwpBmeg9D86exqwww5rm-mwwBrmeZpwww/morelike.html +http://members.iinet.net.au/~scott3/legacy/matt.html +http://cn.egroups.com/post/bastardimage?act=forward&messageNum=11 +http://ftp.nodomainname.net/pub/mirrors/.2/gnu/tasks/?N=D +http://ftp.nodomainname.net/pub/mirrors/.2/gnu/tasks/standards.text +http://10000downloads.subportal.com/sn/Utilities/Misc__Utilities/11320.html +http://mindit.netmind.com/proxy/http://www.altera.com/html/tools/swupdates.html +http://www.next.com.hk/mag/419/news/an06.htm +http://www.areteoutdoors.com/channel/air/b.283.g.3871.html +http://troop485.tripod.com/documents/johnwayne.htm +http://troop485.tripod.com/documents/bp-churchhill.htm +http://sound-dist.secured.co.uk/cgi-bin/psProdDet.cgi/22P03|972959558|Security|user|0|1,0,0,1 +http://www9.hmv.co.uk:5555/do/session/1347794/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d120_sd0_pt0.html +http://ftp.du.se/debian/dists/Debian2.2r0/main/disks-m68k/2.2.16-2000-07-14/mac/images-1.44/?S=A +http://opac.lib.ntnu.edu.tw/search*chi/++ftlist/bp20043193/-5,-1,0,B/buttonframe&F=bp20043190&1,1 +http://www.parlament.ch/internet98/Poly/Suchen_amtl_Bulletin/ce98/ete/275.HTM +http://in.egroups.com/messages/svpvril/5195?viscount=-30 +http://in.egroups.com/messages/svpvril/?expand=1 +http://retailer.gocollect.com/do/session/1912744/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/checkout/shopping_cart.asp +http://retailer.gocollect.com/do/session/1912744/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://www18.freeweb.ne.jp/sports/imamako/ +http://www.cs.ucc.ie/javadocs/jdk1.2.2/docs/api/java/awt/geom/class-use/QuadCurve2D.Double.html +http://click-to.tell-a-friend.boardhost.com/tell-a-friend-confirm.cgi?stigmaonline&msg=172 +http://www.emerchandise.com/aboutus/b.TV%20ANGEL/s.2YYjVOgH +http://www.leyou.com/product/ShowResult.php?LY_Category=0531&page=3 +http://cafe6.daum.net/Cafe-bin/Bbs.cgi/rest114pds/qry/zka/B2-kB23o/qqatt/^ +http://sunsite.informatik.rwth-aachen.de/LinuxArchives/sunsite.unc.edu/distributions/linux-router/dists/2.9.6/base/?N=D +http://www-uk5.cricket.org/link_to_database/ARCHIVE/1999-2000/PAK_IN_SL/FANTASY/ +http://findmail.com/message/sangersreview/99 +http://phase.etl.go.jp/mirrors/netlib/utk/people/JackDongarra/SLIDES/osu-498/sld011.htm +http://tucows.datasync.com/winme/preview/75261.html +http://secure.danysoft.com/asp/dany.tienda/1266636789/Catalog +http://www.birding.about.com/hobbies/birding/cs/placesecuador/index_2.htm +http://www.cpami.gov.tw/ymsnp/animal/fauna/nospc385text.htm +http://www.fh-telekom-leipzig.de/hilfe/pak_e/paket_inhalt_jade_dsl.html +http://home.vicnet.net.au/~nunayl/feedback.html +http://www.expage.com/nibina +http://www.expage.com/virtuaalisiittolantallivihko +http://www.expage.com/muittentallijenkisoja +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=9,39,33 +http://retailer.gocollect.com/do/session/1912707/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/top_ten.asp?pagenum=2 +http://www.streetprices.com/Electronics/Other/MAKE+SYMANTEC/sortdetailbystock/SP322647.html +http://www.peopledaily.co.jp/haiwai/199810/09/no_981009003024_6.html +http://mediate.magicbutton.net/do/session/625622/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-artc.html +http://mediate.magicbutton.net/do/session/625622/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-top50.html +http://www.nada.kth.se/systemgruppen/docs/javadoc/jdk-1.3/docs/api/javax/swing/plaf/basic/class-use/BasicSliderUI.ChangeHandler.html +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/Collect_DB_Advers2/2000-09-10/08/?N=D +http://yp.gates96.com/12/57/30/53.html +http://yp.gates96.com/12/57/32/14.html +http://yp.gates96.com/12/57/32/97.html +http://yp.gates96.com/12/57/33/1.html +http://yp.gates96.com/12/57/33/37.html +http://yp.gates96.com/12/57/37/91.html +http://yp.gates96.com/12/57/37/98.html +http://yp.gates96.com/12/57/38/23.html +http://yp.gates96.com/12/57/38/34.html +http://yp.gates96.com/12/57/38/51.html +http://yp.gates96.com/12/57/38/53.html +http://yp.gates96.com/12/57/39/43.html +http://yp.gates96.com/12/57/39/56.html +http://yp.gates96.com/12/57/39/68.html +http://yp.gates96.com/12/57/39/70.html +http://www3.sympatico.ca/jacques.m.boisvert/Data_Distribution.html +http://www.garekiya.com/female/female02-25.html +http://www.brio.de/BRIO.catalog/39fe2f6c06f4cd8e273fd472aa780734/UserTemplate/5 +http://202.99.23.195/GB/channel1/13/20001030/291723.html +http://db.bbc.co.uk/education/gcsebitesize/maths/shape_and_space_i_h/loci_rev.shtml +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceStoreCategories-BBC709F9_97F3_1F2D7EFC4CA45617D914720977E88400 +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceShoppingCartPage-BBC709F9_97F3_1F2D7EFC4CA45617D914720977E88400 +http://polygraph.ircache.net:8181/http_-2www.microsoft.com/frontpage/http_-2www.hercules.com/history.htm +http://www.jbc.org/cgi/content/short/275/36/27501 +http://brazil.mit.edu/sdb/de/html/keylist.NNTP.html +http://ads3.zdnet.com/c/g=r771&c=a53605&idx=2000.10.30.21.30.57/www.micronpc.com/zd/max1299 +http://webtools.familyeducation.com/whatworks/item/front/0,2551,22-9696-6689-473-46499,00.html +http://www.dispatch.co.za/2000/04/08/business/HIGHLOW.HTM +http://generalstore.everdream.com/kore/catalog/Office_Supplies/Forms,_Record_Keeping_&_Reference/Human_Resources/Motivational/brand.html?sort=price&count=0 +http://www.laria.u-picardie.fr/docs/www.linux-france.org/article/securite/intro.html +http://ftp.uni-stuttgart.de/pub/netscape/communicator/slovenian/4.51/windows/windows95_or_nt/ +http://cafe4.daum.net/Cafe-bin/Bbs.cgi/monjatingpds/lst/qqeq/1/zka/B2-kBnNt +http://myhome.shinbiro.com/~funky27/novel18.htm +http://www.apcmag.com/apcweb/reviewsdisc.nsf/aac7d56ca8fd884b852563be00610639/25858e2d9c878e294a2567060015364d!EditDocument +http://www.private-immobilien-boerse.de/nordrhein-Westfalen/luedinghausen/Verkauf/3d-service/Gemeinsam/Immolink/Gemeinsam/erreichenPartner/Private-IB/ +http://www.eos.dk/archive/swing/msg00405.html +http://www.jobvillage.com/channel/jobs/human_resources/benefits_analysis/b.2807.g.1757.html +http://www.hanaga.com.cn/gbjc/tc/jq.htm +http://www.multimap.com/wi/33747.htm +http://www.multimap.com/wi/143959.htm +http://home.freeuk.net/jdl/Left_Navigate.htm +http://www.crit.org/nph-edit.cgi/http://crit.org/pub/ifi.unizh.ch/wagner/just-testing.html +http://www.interessengemeinschaft-musik.de/catalog%20data/body_22.html +http://aleph.tau.ac.il:4500/ALEPH/ENG/ATA/AAS/AAS/FIND-ACC/0333501 +http://www.mojahedin.org/Pages/Mojahed/Mojahed451/rp/rp09.html +http://genforum.genealogy.com/cgi-genforum/forums/lenhart.cgi?158 +http://carriage.de/Schoner/collections/Geschichte/Sammlungen/info-e/ +http://cafe4.daum.net/Cafe-bin/Bbs.cgi/pflhs11pds/rnw/zka/B2-kB2-s +http://ftp.lip6.fr/pub11/NetBSD/arch/hpcmips/pkgstat/20001008.0536/textproc/xerces-j-current/ +http://dk.egroups.com/message/scotdisinfo/306 +http://groups.haas.berkeley.edu/hcs/Docs/SASv8/sasdoc/sashtml/proc/z0360708.htm +http://www.legend-net.com/news/tiyu/messages/474.html +http://www.legend-net.com/news/tiyu/messages/466.html +http://tv.thevines.com/leaf/AA0000373887/3/0/0/&hmode=on +http://vorg1.subportal.com/sn/Business/Enhanced_Calculators/5511.html +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=7,28,31,24,35 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=24,5,17,30,11 +http://ftp.gwdg.de/pub/eff/Global/USA/Legislation/gtda_export.regulations +http://www.dein-schicksal.de/Fotoanzeigen/April_2000/7/17/27/body_57.html +http://www.fujian-window.com/Fujian_w/news/mzrb1/20000630/2_14.html +http://www.webswap.com/shelf/2/17559/sell.html +http://search.leg.wa.gov/wslrcw/RCW%20%2036%20%20TITLE/RCW%20%2036%20.100%20%20CHAPTER/RCW%20%2036%20.100%20.060.htm +http://www.doc.ic.ac.uk/lab/labsrc_area/firstyear/submissions/1997-98/jmc1/labs/Ex02/icc97/?M=A +http://school.educities.org/card/abc0609.html +http://school.educities.org/card/huangmei.html +http://school.educities.org/card/a126457822.html +http://school.educities.org/card/a8911.html +http://school.educities.org/card/aa5117.html +http://school.educities.org/card/b3575610.html +http://school.educities.org/card/c5625.html +http://school.educities.org/card/h1230997.html +http://school.educities.org/card/h224153937.html +http://school.educities.org/card/julie9.html +http://school.educities.org/card/lefe135.html +http://school.educities.org/card/nl123.html +http://school.educities.org/card/s5802.html +http://school.educities.org/card/s58120.html +http://school.educities.org/card/s5931.html +http://school.educities.org/card/s6197.html +http://school.educities.org/card/vov.html +http://school.educities.org/card/xx5331.html +http://darkwing.uoregon.edu/~cblanksh/GeneratedItems/?M=A +http://ciscom.gamecenter.com/Tipcheat/PC/Item/0,128,0-202,00.html +http://rotten-tomatoes.com/movies/browse/1010942/video.php +http://rotten-tomatoes.com/movies/browse/1076825/reviews.php +http://archive.soccerage.com/s/fr/09/98335.html +http://www.ferien-immobilien.de/nordrhein-Westfalen/aachen/Verkauf/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/3d-service/Gemeinsam/erreichenPartner/Gemeinsam/impressum.htm +http://www.ebigchina.com/tool_tellfriend.phtml?code=msg&mid=3174 +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/src/libexec/rpc.rwalld/Makefile?only_with_tag=RELENG_3 +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/src/libexec/rpc.rwalld/Makefile?only_with_tag=MAIN +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/src/libexec/rpc.rwalld/Makefile?only_with_tag=RELENG_3_BP +http://ring.jec.ad.jp/pub/linux/debian/debian/dists/unstable/contrib/binary-sh/admin/?M=A +http://www2.eunet.lv/library/alt/URIKOVA/FORTUNE_D/Mirrors +http://www.hermes.dk/departments/om/publica.shtml +http://208.194.150.10/Ski/Articles/DrDewpoint/001/bannerAd.shtml +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/quanta/quanta/widgets/?sortby=log&only_with_tag=start +http://biblio.cesga.es:81/search*gag/aSempere+Navarro,+Antonio-Vicente/asempere+navarro+antonio+vicente/-5,-1,0,E/frameset&F=asempere+y+guarinos+juan+trad&1,1 +http://www.fractal.com.ru/Component/Toshiba/74Cxx/TC74HC74DS.pdf +http://www.staroriental.net/nav/soeg/ihf,aai,n3,7,Electric+Wave+Girl+1998.html +http://excite.de/auto/katalog/11803 +http://gatekeeper.dec.com/pub/BSD/NetBSD/NetBSD-current/pkgsrc/sysutils/amanda-client/pkg/ +http://www.smcworld.com/smcworld/bp_e/large/0524_2301_002x2301_003x2301_004x2301_005x2301_006x2301_007_2301_005b.html +http://www.kaos.dk/sexriddle/x/j/t/z/d/ +http://www.kaos.dk/sexriddle/x/j/t/z/e/ +http://spartanburg2.edgate.com/blgspringes/school_athletics/parent/ +http://www-personal.engin.umich.edu/~mhaanpaa/?S=D +http://www.amcity.com/jacksonville/stories/2000/05/15/story8.html?t=email_story +http://yp.gates96.com/7/47/40/13.html +http://yp.gates96.com/7/47/42/7.html +http://yp.gates96.com/7/47/43/2.html +http://yp.gates96.com/7/47/43/22.html +http://yp.gates96.com/7/47/43/54.html +http://yp.gates96.com/7/47/44/0.html +http://yp.gates96.com/7/47/45/3.html +http://yp.gates96.com/7/47/45/30.html +http://yp.gates96.com/7/47/45/78.html +http://yp.gates96.com/7/47/45/89.html +http://yp.gates96.com/7/47/46/41.html +http://yp.gates96.com/7/47/46/71.html +http://yp.gates96.com/7/47/48/1.html +http://yp.gates96.com/7/47/48/68.html +http://yp.gates96.com/7/47/48/92.html +http://yp.gates96.com/7/47/49/6.html +http://yp.gates96.com/7/47/49/43.html +http://yp.gates96.com/7/47/49/86.html +http://yp.gates96.com/7/47/49/97.html +http://de.excite.de/bildung/katalog/24692 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=90&discrim=226,20,231 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=90&discrim=226,20,4 +http://www.affiliate.hpstore.hp.co.uk/do/session/380862/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/search.asp +http://www1.zdnet.co.uk/news/news1/ns-1511.html +http://bellona.itworld.com:8080/cwi/reprint/0,1926,NAV63-128-1357-1367_STO48730,00.html +http://wwwhome.cs.utwente.nl/~zwiers/projects/docs/jdk/api/java/util/class-use/SortedMap.html +http://cgi.cnnsi.com/football/nfl/players/Ed.McCaffrey/ +http://fi.egroups.com/messages/philmusic/12006 +http://fi.egroups.com/messages/philmusic/12123 +http://fi.egroups.com/messages/philmusic/213 +http://fi.egroups.com/messages/philmusic/1826 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=22,0+20,0-9,2-~ +http://my.egroups.com/message/gps4gis/164 +http://www.bemi-immobilien.de/Startseite/www.allgemeine-immobilien-boerse.de/allgemeine-ib/landkreiszwickau/Verkauf/29109700708107kirchbergvillamü/Gemeinsam/MarketingStrategie/Gemeinsam/Inserieren/Startseite/Startseite/Gemeinsam/versicherungen/gebaeude/anforderungsformular.htm +http://apple.excite.com/entertainment/fine_arts/classical_music/composers/baroque_composers/albinoni_tomaso/works/ +http://www.lithoquoter.com/Scripts/WebObjects.exe/Printers.woa/609420000046582000001552000000949302/main.wo/7834100000849302/4/-/prime +http://yp.gates96.com/11/75/40/25.html +http://yp.gates96.com/11/75/40/38.html +http://yp.gates96.com/11/75/40/88.html +http://yp.gates96.com/11/75/40/91.html +http://yp.gates96.com/11/75/42/1.html +http://yp.gates96.com/11/75/42/74.html +http://yp.gates96.com/11/75/42/81.html +http://yp.gates96.com/11/75/43/45.html +http://yp.gates96.com/11/75/43/51.html +http://yp.gates96.com/11/75/46/25.html +http://yp.gates96.com/11/75/46/72.html +http://yp.gates96.com/11/75/46/89.html +http://yp.gates96.com/11/75/46/91.html +http://yp.gates96.com/11/75/47/5.html +http://yp.gates96.com/11/75/48/67.html +http://yp.gates96.com/11/75/49/89.html +http://users.telerama.com/~mross/jenny/forsale.html +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=14&discrim=212,57 +http://ring.htcn.ne.jp/archives/NetBSD/NetBSD-1.4.2/atari/binary/security/?N=D +http://library.bangor.ac.uk/search/dCanada+--+Agricultural+resources+--+19th+century/dcanada+agricultural+resources+++19th+century/-5,-1,0,B/exact&F=dcanaanites&1,3 +http://www.brio.de/BRIO.catalog/39fe2f6406e8eec4273fd472aa780738/UserTemplate/5 +http://kuyper.calvin.edu/fathers2/NPNF1-05/npnf1-05-04.htm +http://kuyper.calvin.edu/fathers2/NPNF1-05/npnf1-05-08.htm +http://kuyper.calvin.edu/fathers2/NPNF1-05/npnf1-05-20.htm +http://polygraph.ircache.net:8181/http_-2www.sgi.net/http_-2www.itools.com/research-it/http_-2www.aardvarkclay.com/Themes/http_-2www.snapsite.com/guests/sk8ctrl/public/html/sitemap/sitemap.htm +http://www.genexchange.com/cemlist.cfm?state=mo&county=webster +http://newsone.net/nnr/showart/alt.current-events.haiti/911 +http://212.11.11.62/voyages_degriffes/MEXIQUE/PARIS+-+MEXICO+A%2FR/SAI00511790/ +http://bitwise.linux.tucows.com/x11html/adnload/131942_45932.html +http://www.brio.de/BRIO.catalog/39fe2f740910301a2740d472aa7806aa/UserTemplate/1 +http://singles-ads.theshoppe.com/cgi-bin/c/736/64/dXNlcmJhbm5lcg==/gn/3585/ +http://www.chaos.dk/sexriddle/j/l/v/y/t/ +http://www.interlog.com/~prandall/relations/d0003/g0000795.html +http://ftp.jp.debian.org/debian/dists/woody/non-free/binary-arm/oldlibs/?M=A +http://biblioteca.upv.es/bib/doc/doc_fisbd/129/97268//V/1828099/6////25/N/MLTPAID +http://biblioteca.upv.es/bib/doc/doc_fisbd/129/147168//V/1828099/11////25/N/MLTPAID +http://biblioteca.upv.es/bib/doc/doc_fisbd/129/124846//V/1828099/24////25/N/MLTPAID +http://mirrortucows.technet.it/winme/htmlbeginnerme_size.html +http://www.bcbsal.org/Provider_Dir/pharmacy/state/Georgia/HAWKINSVILLE/index_10201.html +http://www.incestpornstories.com/tinkerbellbeard/ac/plus-sizehealthy/petitevietnamese/slanted-eyes/cuntschoolgirls/high-schoolteenager/cherryunderage.html +http://www.0563.net/imode2/hazu/play/outdoor/nature/nature1.htm +http://www.launch.com/music/songpage/pvn_content/0,5259,1074221,00.html +http://ftp.jp.debian.org/debian/dists/unstable/main/binary-alpha/tex/?S=A +http://iceberg.adhomeworld.com/cgi-win/redirect.exe/896425026 +http://www.nrc-handelsblad.nl/W2/Lab/Baan/000726-a.html +http://www.nrc-handelsblad.nl/W2/Lab/Baan/000718-a.html +http://members.tripod.co.jp/muzyaki/?M=A +http://alfa.nic.in/lsdeb/ls12/ses4/0413039930.htm +http://excite.de/immobilien/katalog/26640 +http://excite.de/immobilien/katalog/27591 +http://excite.de/immobilien/katalog/28370 +http://excite.de/immobilien/katalog/28376 +http://excite.de/immobilien/katalog/26426 +http://excite.de/immobilien/katalog/28458 +http://www.emerchandise.com/aboutus/b.TV%20THE60S/s.qxmvd5Gr +http://www.computerworld.com.cn/99/week/9920/9920c13.asp +http://www.stud.ntnu.no/~oystena/oystena/cache/dvx70a.html +http://nealet.subportal.com/sn/Shell_and_Desktop/Holiday_Screen_Savers/ +http://dk.egroups.com/message/ugm/40?source=1 +http://www1.bdaserver.de/bda/nat/pzt/formel1/gp/mon.html +http://www17.freeweb.ne.jp/diary/t-soken/love-love.htm +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/SaveCounter/2000-10-12/14/971332013437.txt +http://pub3.ezboard.com/f80sxchangegeneraldiscussion.showMessage?topicID=60.topic +http://www.northampton.ac.uk/cgi-bin/liberation/betsie/betsie.pl/0005/www.nene.ac.uk/ncr/enrol/sectn4/pdf/4-5.pdf +http://www.xmission.com/~dkenison/cgi/lwgate.cgi/LDS-BOOKSHELF/archives/v01.n676/Date/article-15.html +http://www.eos.dk/archive/swing/nav08574.html +http://nathanael.upi.jussieu.fr/tele6.nsf/autres+centres+de+formations!OpenPage&ExpandSection=1,4,11,18,5,17 +http://nathanael.upi.jussieu.fr/tele6.nsf/autres+centres+de+formations!OpenPage&ExpandSection=6,4,11,18,5,17 +http://cn.egroups.com/message/highlanderswaps/3351 +http://cn.egroups.com/message/highlanderswaps/3356 +http://www.mobygames.com/user/sheet/view/havelist/so,game_title(game_id)+DESC,game_havelist_id+DESC/userHaveListId,18/userSheetId,832/offset,15/ +http://www.mobygames.com/user/sheet/view/havelist/so,game_title(game_id)+DESC,game_havelist_id+DESC/userHaveListId,18/userSheetId,832/offset,60/ +http://gettosdownloads.subportal.com/sn/Palm_Pilot/Home_and_Hobby/12385.html +http://biblio.cesga.es:81/search*gag/aOurense+(Di%26oacute%3Bcesis).+Obispado+de+Ourense,+ed./aourense+diocesis+obispado+de+ourense+ed/-5,-1,0,B/browse +http://www.beneteau-owners.com/beneteau.nsf/userlistbyboat!OpenView&Start=21.24&Count=45&Expand=39 +http://www.geocities.com/Yosemite/8908/ +http://www.geocities.com/Yosemite/3295/ +http://lists.insecure.org/linux-kernel/2000/Apr/4105.html +http://www.telematik.informatik.uni-karlsruhe.de/osf/sw/v5.0x/lp2/dna500/ +http://atlas.web.cern.ch/Atlas/GROUPS/SOFTWARE/OO/dist/0.0.28/graphics/TreeBuilder/TreeMaker/CVS/?M=A +http://www.21hk.com/book/zt/zt/zpj/c/chichuancilang/txmoxj/012.htm +http://chat.hani.co.kr/NetBBS/Bbs.dll/brief/rcm/zka/B23lBn-t/qqatt/^ +http://www3.buch-per-sms.de/impressum.jsp$ID=To7770mC6889218603037781At0.41865389376542195 +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/151/1997/7/0/904457/ +http://www.mets.com/gameinfo/990504-recap.htm +http://www.mets.com/Video/990709-PiazzaHR_lr.asp +http://www.people.zeelandnet.nl/cn.atlas/compatlasw1.html +http://www.digitaldrucke.de/(aktuell,bekanntschaften,hilfe,marktplatz,nuernberg)/_fort/html/themen/markt/bekannt/bekannt.htm +http://www.staroriental.net/nav/soeg/ihf,acf,s0,359,Gigi+Leung+Wing-Kay.html +http://rapidus.tucows.com/winme/adnload/137435_28887.html +http://library.bangor.ac.uk/search/aBerthoff,+Ann+E/aberthoff+ann+e/-5,-1,0,B/frameset&F=aberthier+rene&1,1 +http://www.teenplatinum.com/barelylegal/underagevirgin/abductionbondage/amateurco-ed/chijapanese/{gaylink} +http://www.paisvirtual.com/informatica/freeware/cltorres/contra.htm +http://library.cuhk.edu.hk/search*chi/aInstitution+of+Civil+Engineers+(Great+Britain)/ainstitution+of+civil+engineers+great+britain/-5,-1,0,B/browse +http://www.digitaldrucke.de/(aktuell,computer,hersteller,hilfe)/_fort/html/themen/computer/hard/links/dell.htm +http://www.angelfire.com/ar/jimbowles/weekofoct3.html +http://www.dtic.mil/envirodod/derpreport95/vol_2/b2_1991.html +http://www.dtic.mil/envirodod/derpreport95/vol_2/b2_2010.html +http://kobe.cool.ne.jp/heartisland/y_top0004.html +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=146&discrim=10,97,3 +http://www.channel7000.com/partners/tv/consumer/partners-tv-consumer-20000207-231308.html +http://www.channel7000.com/partners/tv/consumer/partners-tv-consumer-19991206-195152.html +http://www.channel7000.com/partners/tv/consumer/partners-tv-consumer-990920-105620.html +http://www.channel7000.com/partners/tv/consumer/partners-tv-consumer-990810-082554.html +http://gallery2.simplenet.com/lobby/main/videocaps/lalbrght/conair/laca26.htm +http://www.ld.com/cbd/archive/1999/09(September)/30-Sep-1999/Bawd007.htm +http://www.ld.com/cbd/archive/1999/09(September)/30-Sep-1999/Bawd013.htm +http://chunma.yeungnam.ac.kr/~j4390071/ +http://www.chaos.dk/sexriddle/h/y/z/m/ +http://www.maas.ccr.it/cgi-win/hiweb.exe/a18/d262/b190,8,be,29,29,,b,,be,b, +http://pub17.ezboard.com/fanimesandrpgslinkstositesandotherforums.showMessage?topicID=2.topic +http://www.hotelboulevard.com/fr/riviera/standard/htmled1e03872682f66e105b3c38b4506d50/sessionLang/ANG/search.html +http://bbs.msquare.or.kr/list.bbs/course/old/DiscMath95/9.html +http://www.rezel.enst.fr/ftp/linux/distributions/debian/CD-1/dists/unstable/main/binary-all/mail/?N=D +http://www.ee/epbe/pangandus/9910/0.2.txt +http://shitty.10pics.com/buttfucking/rear/ +http://www.thestateofcolorado.com/hsiwindowdoorlettering.html +http://www.generation-formation.fr/brevesc.htm---o21zAo0UtDo0Ol9A074fo6Td4ezyr6feZJPAPfVbNyqruePl9neNHhIeOkatAhcgNA074wNV8XzAhcgNAPfVbdsNhJI.htm +http://netscape.digitalcity.com/boston/sports/standings.dci?league=NBA&team=BOS +http://netscape.digitalcity.com/boston/sports/attcompare.dci?league=NBA&team=BOS +http://retailer.gocollect.com/do/session/1912752/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://mindit.netmind.com/proxy/http://www.skepdic.com/sympathetic.html +http://mindit.netmind.com/proxy/http://faculty.washington.edu/chudler/moon.html +http://itcareers.careercast.com/texis/it/itjs/++wwBmeE_D86esmwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqew8Qwo5qda5dc1BodDawGnwaGn31oGnmaoDmnpBraADdicnmtnapGdm1qBaBnqrDoqwcatGd1pamnVncdpaMFqoET02fgENDzmezxwwwpBmeC_D86Qwww5rmkmwwBrmeyDwww/morelike.html +http://retailer.gocollect.com/do/session/1912762/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/terms_and_conditions.asp +http://retailer.gocollect.com/do/session/1912762/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://www.writtenbyme.com/cgi-bin/rw_readarticle.cgi/141339880.shtml +http://www.writtenbyme.com/cgi-bin/rw_readarticle.cgi/410769654.shtml +http://www.writtenbyme.com/cgi-bin/rw_readarticle.cgi/190045923.shtml +http://tucows.megalink.com/winme/preview/76155.html +http://www.buybuddy.com/sleuth/17/1/2006/32184/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380853/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/FR/REGISTRATION/entry.asp +http://pchome.net:81/ch/Hw/CAMERA/canoneosd30/canoneosd30.htm +http://pchome.net:81/ch/Hw/CAMERA/kodaknew.htm +http://pchome.net:81/ch/Hw/MODEM/twluc562w2k.htm +http://pchome.net:81/ch/Hw/MONITOR/mag796fd.htm +http://pchome.net:81/ch/Hw/cool/anquanshuileng/anquanshuileng.htm +http://pchome.net:81/ch/Hw/DISPLAY/3dbenchmarks/3dbenchmarks.htm +http://pchome.net:81/ch/Hw/CAMERA/Microdrive.htm +http://pchome.net:81/ch/Hw/harddisk/niyaomaishime.htm +http://www.civila.com/guitar/desenredada/chat/logos/index.html-ssi +http://members.xoom.it/scialpinismo/gitaappenparm/PreviewPages/PreviewPage7.htm +http://cpan.nitco.com/modules/by-module/Mail/ASPIERS/URI-Bookmarks-0.92.readme +http://polygraph.ircache.net:8181/services/design/http_-2www.swnebr.net/~cambridg/http_-2www.cauce.org/Malcolm/ +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_aswkit_aswkit.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_nbilwv_rbpobu.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_jkawvi_messod.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_jkawvi_otdbms.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_jkawvi_hoktlo.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_uhfkhdn_ilaeh.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_xyhsj_pfepjoa.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_alkqaay_mogsts.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_ighrg_ighrg.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_cbfjod_parbe.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_dqnlq_jfspcj.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_phcro_bwlah.html +http://www.asahi-net.or.jp/~yd7k-itu/sbbsindex/old/16_phcro_xoxchqb.html +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/IkhI2h2UISFGhSJ4dK-jGu69npNFUTS7n0SO4q6b8rSzWq_RIDBJOsj9QRxPcb3IZgZlQ5jvjGikzJWNeK-85DucH1Ag5dhhL0czi-GMxyHC1dmfKc0hW5TzqJpnm938SIT3xNrWgjZN66P6 +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/oo1IpLu33emgRiskeudWkzY7LxFY35wz6EqyQ42lguNadi_4qnt4FhGUPOob_C5Wt99hQSEKEuRTRevsau9UYJ9lySivV-u51_OF4aSEhYXTt98QpjnIOFYPV6acMb20In922uOHMyYdC8HXvwhIP-8o8oM4wLBMdll6aW8xe922WllgXE1F5qlvFqyA +http://msdn.microsoft.com/library/devprods/vs6/visualj/vjref/java.sql.DatabaseMetaData136.html +http://msdn.microsoft.com/library/devprods/vs6/visualj/vjref/java.sql.DatabaseMetaData090.html +http://romulus.ehs.uiuc.edu/cgi-bin/lwgate/RADSAFE/archives/radsafe9902/Date/article-572.html +http://spaceports.tucows.com/winme/preview/76400.html +http://www.telecombroker.com/q/001p/ppc3/qG4gs1ewhU.htm +http://ftp.nodomainname.net/pub/mirrors/.2/gnu/graphics/?N=D +http://retailer.gocollect.com/do/session/1912813/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/help/site_tour/index.asp +http://retailer.gocollect.com/do/session/1912813/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/news/index.asp +http://retailer.gocollect.com/do/session/1912813/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/privacy_policy.asp +http://202.101.106.19/dir/100/10a/zzgk/bszn/111.htm +http://www.eveclub.com/cgi-bin/eveclub.front/972959538910/Catalog/1000084 +http://www.eveclub.com/cgi-bin/eveclub.front/972959538910/Club/start/1000000 +http://www.slis.ua.edu/cgi-bin/clickthrough.cgi/CT=http_3a_2f_2fwww_2edermis_2enet_2fbilddb_2fdiagnose_2fenglisch_2fi697015_2ehtm +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/folderFrame/100001/0/rnumber/8467604 +http://www-personal.engin.umich.edu/~vernage/teamweb/team.building/effective.meetings/effective.meetings.facilitation.htm +http://www4.law.cornell.edu/uscode/42/ch87subchIV.head.html +http://yp.gates96.com/7/27/90/10.html +http://yp.gates96.com/7/27/90/11.html +http://yp.gates96.com/7/27/90/30.html +http://yp.gates96.com/7/27/91/72.html +http://yp.gates96.com/7/27/91/76.html +http://yp.gates96.com/7/27/91/85.html +http://yp.gates96.com/7/27/91/92.html +http://yp.gates96.com/7/27/92/61.html +http://yp.gates96.com/7/27/92/72.html +http://yp.gates96.com/7/27/93/10.html +http://yp.gates96.com/7/27/93/17.html +http://yp.gates96.com/7/27/93/30.html +http://yp.gates96.com/7/27/93/65.html +http://yp.gates96.com/7/27/93/76.html +http://yp.gates96.com/7/27/93/99.html +http://yp.gates96.com/7/27/94/37.html +http://yp.gates96.com/7/27/94/85.html +http://yp.gates96.com/7/27/95/5.html +http://yp.gates96.com/7/27/95/14.html +http://yp.gates96.com/7/27/95/55.html +http://yp.gates96.com/7/27/95/57.html +http://yp.gates96.com/7/27/96/21.html +http://yp.gates96.com/7/27/96/49.html +http://yp.gates96.com/7/27/96/50.html +http://yp.gates96.com/7/27/96/55.html +http://yp.gates96.com/7/27/96/92.html +http://yp.gates96.com/7/27/97/24.html +http://yp.gates96.com/7/27/97/73.html +http://yp.gates96.com/7/27/97/98.html +http://yp.gates96.com/7/27/98/26.html +http://yp.gates96.com/7/27/98/62.html +http://yp.gates96.com/7/27/99/15.html +http://yp.gates96.com/7/27/99/52.html +http://www.nrk.no/finnmark/x2_9_98/nyh11.htm +http://www.excelsior.com.mx/9701/970105/nac18.html +http://www.symantec.co.kr/sabu/igear/igear_educ/stories.html +http://www.smcworld.com/smcworld/bp/pre/0204_1_1070.html +http://www.cpami.gov.tw/ymsnp/animal/fauna/nospc708choice.htm +http://pub9.ezboard.com/fdawsonscreek50374helpwanted +http://pub9.ezboard.com/fdawsonscreek50374frm17 +http://www.happychannel.it/turismo/europa/top_news/schede/scheda_991209110434.shtml +http://www.happychannel.it/turismo/europa/top_news/schede/scheda_991111111106.shtml +http://dirs.educationamerica.net/New_York/Localities/N/New_York_City/Manhattan/Business_and_Economy/ +http://dirs.educationamerica.net/New_York/Localities/N/New_York_City/Manhattan/Government/ +http://china-water.51.net/life/life_20.htm +http://china-water.51.net/life/life_22.htm +http://www.egroups.com/message/ramtalk/17801 +http://www.usahardware.com/inet/webSession/shopper/US972959720-31113/store/dept-1 +http://www.usahardware.com/inet/webSession/shopper/US972959720-31113/store/specials +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=97&discrim=2,68,201 +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/quizz/legendes/misc/music/lit/hasard.html +http://findmail.com/group/ken2061 +http://www.affiliate.hpstore.hp.co.uk/do/session/380852/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-photoworld.com/photoworld.asp?lang=f +http://www.affiliate.hpstore.hp.co.uk/do/session/380852/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/SMARTTIPS/traveljournal.asp +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www-med.stanford.edu/school/banner.html +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www-med.stanford.edu/school/neurosurgery.html +http://hotop.on.net.cn/diguo/club/disp.asp?owner=A201&ID=894 +http://hotop.on.net.cn/diguo/club/disp.asp?owner=A201&ID=846 +http://interbaun.tucows.com/winme/preview/577.html +http://www.ferien-immobilien.de/ungarn/verkauf/Gemeinsam/Immolink/Exklusiv-IB/Startseite/3d-service/Private-IB/Startseite/Default.htm +http://www.eos.dk/archive/swing/msg10936.html +http://www.egroups.com/message/ICSIA-PublicForum/138 +http://www.online.kokusai.co.jp/Service/V0043601/wrd/G200/service/service.html +http://debian.tod.net/debian/dists/unstable/main/source/libs/?N=D +http://www.maas.ccr.it/cgi-win/hiweb.exe/a17/d79/b77,e,4d,51,51,819,819,,2,,51,2,4e,,4d,4e, +http://www.redhat.com/mirrors/LDP/LDP/khg/HyperNews/get/fs/fs/9/?N=D +http://ftp.oleane.net/pub/CTAN/systems/knuth/local/man1/?D=A +http://www.jamba.de/KNet/_KNet-_UA8j1-xFd-13bat/browse.de/node.0/cde7f1uou +http://www.jamba.de/KNet/_KNet-_UA8j1-xFd-13bbg/showInfo-jambabanner.de/node.0/cenv0b09a +http://www.tente.de/us/produkte/artikel/af000000736.htm +http://dwp.bigplanet.com/bloomingprairie/look/sitemap.nhtml +http://www.kfh-mainz.de/Organisationen/Ketteler/pf/ws0001.html +http://extreme-dm.com/tracking/reports/dj/nph-reloads.cgi?tag=agmusik +http://www.chaos.dk/sexriddle/c/v/m/v/y/ +http://ring.jec.ad.jp/pub/linux/debian/debian/dists/woody/non-free/binary-i386/electronics/?D=A +http://tongbang-gh.ed.taejon.kr/1998대전시/math/olym/function/m103_003/html/m103_003h01.html +http://www.company-product.com/23063/ +http://members.tripod.lycos.co.kr/re22/CPUCOOL5195/uni2k15/?N=D +http://209.52.189.2/print_message.cfm/stepparents/8279/173602 +http://216.33.87.17/sports/baseball/sba/sba04r.htm +http://www.mc99.co.jp/mvp/member/new/honda/16kr3fj2/search.cgi?_file=038 +http://www.emerchandise.com/browse/EMERCH/COASTERS/s.cU6lmV05 +http://www.emerchandise.com/browse/CHARMED/s.cU6lmV05 +http://www.across.or.jp/nbbs/nbbs.cgi/talk:n18/replyto/462 +http://www.vins-siffert-scea.fr/lycee-seijo/guide/staff/yoshida.htm +http://www.egroups.com/messages/grebel-list/2305 +http://polygraph.ircache.net:8181/services/design/http_-2www.abcjewelry.com/http_-2www.1045fm.com/http_-2www.4sitedesign.com/stp/nbm.html +http://bsd.sinica.edu.tw/cgi-bin/cvsweb.cgi/ports/astro/wmmoonclock/pkg/Attic/DESCR?only_with_tag=RELEASE_4_0_0 +http://biblio.cesga.es:81/search*gag/tMariposas+negras.+1:08,50+min/tmariposas+negras++++1+++08+++50+min/-5,-1,0,B/frameset&F=tmariposa+y+la+hormiga&1,1 +http://polygraph.ircache.net:8181/Cameras/order/rr962.htm +http://polygraph.ircache.net:8181/Cameras/order/dfwmap.htm +http://support.tandy.com/support_audio/doc45/45827.htm +http://image.tulips.tsukuba.ac.jp:70/fif=picture/ECWP/001.fpx&init=-0.23170732,0.0,1.2317073,1.0&rect=0.5,0.25,0.6829269,0.375&wid=600&hei=600&lng=ja&enablePastMaxZoom=OFF&page=uv1-en.html&obj=uv,1.0&cmd=NW +http://pub23.ezboard.com/fcaribbeanvoiceforumsfrm3.showAddTopicScreenFromWeb +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,1+0,0-19,0+9,4 +http://vipnet.tucows.com/win2k/adnload/51108_28465.html +http://vipnet.tucows.com/win2k/adnload/38782_28482.html +http://www4.50megs.com/tstazer/edhtms/edbeats.htm +http://www.unterhaltungs-cd.de/ObervellacherBuam/B000025KMT.htm +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=bocarderont&l=fr +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=146&discrim=10,3,211 +http://variety.studiostore.com/help_security/b.TV%20HERCULES/s.cD15jQkr +http://variety.studiostore.com/help_shipping/b.TV%20HERCULES/s.cD15jQkr +http://variety.studiostore.com/product/TSHER0001/b.TV%20HERCULES/s.cD15jQkr +http://variety.studiostore.com/aboutus/b.TV%20HERCULES/s.cD15jQkr +http://www.redrocksports.com/sports/webSession/shopper/RR972959753-31163/store/dept-5/department/dept-5/item/51530 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=135&discrim=165,71,194 +http://www.kagtech.com/SpitfrireKennels +http://www.expage.com/page/thekatshow +http://www.jobvillage.com/channel/jobs/cleaning/gardener/b.4255.g.3878.html +http://www.xmwb.sh.cn/xmwb/20000704/BIG5/14016^6070408.htm +http://www.xmwb.sh.cn/xmwb/20000704/BIG5/14016^7070414.htm +http://dennou-t.ms.u-tokyo.ac.jp/arch/cc-env/Linux/debian-jp/dists/woody-jp/contrib/binary-all/tex/?S=A +http://genforum.genealogy.com/ny/monroe/messages/350.html +http://genforum.genealogy.com/ny/monroe/messages/296.html +http://genforum.genealogy.com/ny/monroe/messages/306.html +http://genforum.genealogy.com/ny/monroe/messages/213.html +http://otenet.themes.tucows.com/fonts/preview/18792.html +http://otenet.themes.tucows.com/fonts/adnload/18828.html +http://otenet.themes.tucows.com/fonts/adnload/18876.html +http://otenet.themes.tucows.com/fonts/preview/18877.html +http://otenet.themes.tucows.com/fonts/adnload/18894.html +http://otenet.themes.tucows.com/fonts/adnload/18910.html +http://otenet.themes.tucows.com/fonts/adnload/18941.html +http://otenet.themes.tucows.com/fonts/adnload/18949.html +http://otenet.themes.tucows.com/fonts/adnload/25945.html +http://ww.egroups.com/message/schoolnet_sadc/96 +http://ww.egroups.com/message/schoolnet_sadc/98 +http://www6.pasta.cs.uit.no/ietf/ietf45/proceedings/I-D/webdav-dublin-core-01.txt +http://www-uk9.cricket.org/link_to_database/INTERACTIVE/SURVEYS/POLLS_DEC1998.html +http://www.ucp.org/ucp_generaldsc.cfm/151/8/35/ucp_disctpc/292/263 +http://www.ucp.org/ucp_generaldsc.cfm/151/8/35/ucp_disctpc/79/79 +http://se.egroups.com/message/DBA/1700 +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/138/2000/6/0/ +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/138/2000/7/0/ +http://www.inf.fu-berlin.de/lehre/WS00/SWT/material/rosebeispiele/interaccess/logicalview/cat32862112022a/cat36e7162c0192/msg343269780227.htm +http://www.private-immobilien-boerse.de/leipzig/verkauf/Gemeinsam/erreichenPartner/IIM-Teil/Startseite/Gemeinsam/versicherungen/gebaeude/Allgemeine-IB/Startseite/ +http://www.private-immobilien-boerse.de/leipzig/verkauf/Gemeinsam/erreichenPartner/IIM-Teil/Startseite/Gemeinsam/versicherungen/gebaeude/Gemeinsam/Immolink/link.htm +http://freetravel.bedandbreakfast.com/Canada/Prince%20Edward%20Island/Little%20Sands.asp +http://freetravel.bedandbreakfast.com/Canada/Prince%20Edward%20Island/Miscouche.asp +http://freetravel.bedandbreakfast.com/Canada/Prince%20Edward%20Island/O'Leary.asp +http://www.buybuddy.com/sleuth/15/1/1070306/519432/ +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/KIRJASTO-+JA+TIETOPALVELUT/ammattikorkeakoulukirjastot/ammattikorkeakoulut/lahti/p%E4ij%E4t-h%E4me/ +http://www.3w-buecher.de/GravesRobert/GravesRobert0140171991.htm +http://www.3w-buecher.de/GravesRobert/GravesRobert1559948345.htm +http://www.3w-buecher.de/GravesRobert/GravesRobert1850897506.htm +http://members.theglobe.com/heliox2/pokepages/ninepic.htm +http://taiwan.vh.org//////Providers/Textbooks/MuscleInjuries/Fig2.html +http://www.globalgarden.com/Tomato/Archives/vol.1/1147.html +http://www.mojahedin.org/Pages/Mojahed/Mojahed442/articles/articlesftx03.html +http://216.34.146.180/161000reu/16hlth6.htm +http://moshkow.sstu.samara.ru/win/BESTER/Encoding_koi +http://in.egroups.com/message/Girl-Scout-Swaps/9 +http://in.egroups.com/message/Girl-Scout-Swaps/31 +http://members.tripod.com/floydechoes/more.htm +http://nanjingnews.jlonline.com/nanjingnews/njrb/20000222/08dushi.htm +http://www.egroups.com/messages/archery/38?expand=1 +http://retailer.gocollect.com/do/session/1912759/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/index.asp +http://home.dqt.com.cn/~ying_jia/wangwen/new/111.htm +http://canoe.com/MLB97FLASF/sep30_fla_sf.html +http://pub2.ezboard.com/fespguitarsmessageboardltdguitarandbassreviews.subscribeUnregisteredToTopic?topicID=8.topic +http://www.catholicstore.com/search/index.cfm/FuseAction/largeImage/SKU/2558/category/Bo/subCategory/AE/subject/17 +http://www.allgemeine-immobilien-boerse.de/bayern/augsburg/Verkauf/Private-IB/Startseite/Gemeinsam/Inserieren/Private-IB/IIM-Teil/Startseite/froben.htm +http://www.infoscape.com.cn:8171/nf/0004/18/nfga1801.htm +http://www.infoscape.com.cn:8171/nf/0004/18/nfga1809.htm +http://www.linux.com/networking/network/kernel/apache/applications/HTTP/ +http://www.linux.com/networking/network/kernel/apache/applications/Linuxcare/ +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=exacerbate&l=en +http://dopey.rediris.es/ftp/mirror/CPAN/modules/by-module/overload/GSAR/Archive-Tar-0.071.readme +http://dopey.rediris.es/ftp/mirror/CPAN/modules/by-module/overload/GSAR/Tie-IxHash-1.21.readme +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=207&discrim=3,201,226 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=207&discrim=3,201,85 +http://www.gsnet.com/bdltg/es/1_136243.html?num=2 +http://www.pinoycentral.com/img/UBB.nsf/e39d540ca6a9104b4825694d006ed185/6668efca7b60518648256966000fd202?Navigate&To=Prev +http://www.academyfloral.com/state/cabel/flowers/harmony.html +http://trading.rakuten.co.jp/items001/4c/0d/10138895/bidlist.html +http://www.cs.uwa.edu.au/programming/jdk1.2.2/api/javax/swing/event/class-use/TableColumnModelListener.html +http://secure.danysoft.com/asp/dany.tienda/803039052/IconBar +http://ftp-stud.fht-esslingen.de/pub/Mirrors/CPAN/modules/by-authors/id/L/LH/LHS/?S=A +http://genforum.genealogy.com/ga/messages/6297.html +http://genforum.genealogy.com/ga/messages/7843.html +http://genforum.genealogy.com/ga/messages/7281.html +http://www.jsinc.com/dd/destnat/sep00/fromcol10090800.asp +http://www.secinfo.com/$/SEC/Filing.asp?T=nDA3.7c_9i4 +http://www.secinfo.com/$/SEC/Filing.asp?T=nDA3.7c_b19 +http://www.sd.digitalcity.com/maconga/penpals/browse.dci?cat=teens +http://www.sd.digitalcity.com/maconga/penpals/browse.dci?cat=seniors&sort=f +http://www.picktips.com/category-1031-1172_1170_1174-4_1_3 +http://www-us6.semiconductors.com/acrobat/datasheets/CR6627_1.pdf +http://ftp.netc.pt/pub/idgames/levels/doom2/deathmatch/p-r/pimp.txt +http://ftp.netc.pt/pub/idgames/levels/doom2/deathmatch/p-r/radiated.txt +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceMallCategories-BBC709FC_97F7_9E91E7C8C7066684B664C77C8575B940 +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceOrderStatusOverview-BBC709FC_97F7_9E91E7C8C7066684B664C77C8575B940 +http://ads.puntopartenza.com/cgi-bin/redirect.cgi/31033638 +http://mediate.magicbutton.net/do/session/625642/vsid/4385/tid/4385/cid/88138/mid/1702/rid/2114/chid/3393/url/http://www.worldgallery.co.uk/frameset-top50.html +http://link.fastpartner.com/do/session/600388/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/netmaling.php +http://www.egroups.com/message/RecipeCollectors2/3785 +http://plat.debian.or.jp/debian/dists/woody/contrib/binary-alpha/admin/?S=A +http://198.103.152.100/search*frc/aFILIPPELLI,+R.L/afilippelli+r+l/-5,-1,0,B/frameset&F=afilion+louis+jacques&1,,0 +http://de.excite.de/wetter/katalog/4206 +http://www.burstnet.com/ads/ad8386a-map.cgi/973225252.925077 +http://www.branchenfuehreronline.de/A/hauptteil_a.html +http://www.linux.com/networking/support/red_hat/internet/test/simple/ +http://www.shopworks.com/ccfarm/index.cfm/action/search/userid/00061450-2F40-19FE-9038010B0A0ADCF2 +http://www.shopworks.com/index.cfm/userid/00061450-2F40-19FE-9038010B0A0ADCF2 +http://pelit.saunalahti.fi/.1/tucows/preview/144491.html +http://pelit.saunalahti.fi/.1/tucows/preview/52377.html +http://www.teacherformation.org/html/od/facilitators.cfm/xid,7238/yid,4053212 +http://tw.yahoo.com/Regional/Countries_and_Regions/China/Provinces__Regions_and_Municipalities/Tianjin/Business/Companies/Utilities/ +http://brain.brent.gov.uk/WebPages.nsf/vWebAllPagesByKey!OpenView&Start=174&Count=60&Expand=194 +http://brain.brent.gov.uk/WebPages.nsf/vWebAllPagesByKey!OpenView&Start=174&Count=60&Expand=227 +http://www.bemi-immobilien.de/Landhaus-Bordeaux/Gemeinsam/versicherungen/unfall/Gemeinsam/erreichenPartner/Startseite/Gemeinsam/MarketingStrategie/Startseite/froben.htm +http://www.bemi-immobilien.de/Landhaus-Bordeaux/Gemeinsam/versicherungen/unfall/Gemeinsam/erreichenPartner/Startseite/Gemeinsam/MarketingStrategie/Gemeinsam/versicherungen/gebaeude/deckungsumfang.htm +http://www.3wposter.com/hake/hkg1701.htm +http://www.citybrazil.com.br/go/mossamedes/utilpub.htm +http://oss.software.ibm.com/developerworks/opensource/cvs/icu4j/icu4j/src/com/ibm/demo/translit/Attic/?sortby=date +http://www.linux.com/networking/network/management/operating_system/enterprise/research/ +http://www.angelfire.com/pq/Prophetess/Prophetess.page3.html +http://www.3w-nostalgie.de/ZeigerMimi/ZeigerMimi007072833X.htm +http://www.excelsior.com.mx/9801/980128/for01.html +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=11&discrim=49,235,5 +http://retailer.gocollect.com/do/session/1912802/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/contact.asp +http://citeseer.nj.nec.com/track/64292/4220924 +http://citeseer.nj.nec.com/correct/318910 +http://citeseer.nj.nec.com/correct/249393 +http://www.chaos.dk/sexriddle/h/y/r/k/ +http://www.hig.se/(aconf,date,doc,insert,return)/~jackson/roxen/ +http://www.hig.se/(aconf,date,doc,gtext,insert)/~jackson/roxen/ +http://mediate.magicbutton.net/do/session/625608/vsid/4573/tid/4573/cid/88043/mid/2247/rid/2383/chid/3527/url/http://www.winesmart.com/expert.asp +http://magazines.sina.com/education/renbun/93/13.html +http://www6.freeweb.ne.jp/art/cilter/kamijo02.htm +http://yp.gates96.com/11/25/50/28.html +http://yp.gates96.com/11/25/50/41.html +http://yp.gates96.com/11/25/50/65.html +http://yp.gates96.com/11/25/50/74.html +http://yp.gates96.com/11/25/50/91.html +http://yp.gates96.com/11/25/50/93.html +http://yp.gates96.com/11/25/50/94.html +http://yp.gates96.com/11/25/51/59.html +http://yp.gates96.com/11/25/51/93.html +http://yp.gates96.com/11/25/52/66.html +http://yp.gates96.com/11/25/54/46.html +http://yp.gates96.com/11/25/54/68.html +http://yp.gates96.com/11/25/54/83.html +http://yp.gates96.com/11/25/54/95.html +http://yp.gates96.com/11/25/54/98.html +http://yp.gates96.com/11/25/55/1.html +http://yp.gates96.com/11/25/55/6.html +http://yp.gates96.com/11/25/55/96.html +http://yp.gates96.com/11/25/56/83.html +http://yp.gates96.com/11/25/56/89.html +http://yp.gates96.com/11/25/57/30.html +http://yp.gates96.com/11/25/57/68.html +http://yp.gates96.com/11/25/58/56.html +http://yp.gates96.com/11/25/58/67.html +http://yp.gates96.com/11/25/59/7.html +http://yp.gates96.com/11/25/59/40.html +http://yp.gates96.com/11/25/59/58.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/misc/legendes/lit/misc/quizz/quizz2.html +http://excite.de/kleinanzeigen/katalog/7100 +http://www.egroups.org/messages/stepup/97 +http://sunsite.org.uk/pub/packages/proftpd/misc/?S=A +http://ring.htcn.ne.jp/archives/lang/perl/CPAN/modules/by-module/CGI/DOUGM/?M=A +http://ring.htcn.ne.jp/archives/lang/perl/CPAN/modules/by-module/CGI/DOUGM/Apache-Scoreboard-0.10.readme +http://ring.htcn.ne.jp/archives/lang/perl/CPAN/modules/by-module/CGI/DOUGM/B-Size-0.04.readme +http://herndon1.sdrdc.com/cgi-bin/can_ind/S8NY00082/1/Y/ +http://in.egroups.com/message/msu-foi/20?source=1 +http://www.worldstocks.de/htm/boersen/asien/indonesien_boerse.htm +http://members.xoom.com/pvmnieuws/movies/movies.html +http://gb.toget.com.tw/article/screensaver/index_a_2.html +http://www.emis.de/journals/EJDE/Volumes/Monographs/Volumes/2000/64/?N=D +http://bsd.wj.o3.net/8/1/18/4.html +http://www.ftp.uni-erlangen.de/pub/mirrors/_other/afterstep.foo.net/apps/asprint/?S=A +http://citeseer.nj.nec.com/cidcontext/3597768 +http://m4.findmail.com/dir/Sports/Soccer/Academic_Study_of_Soccer/History +http://genforum.genealogy.com/cgi-bin/print.cgi?westerman::121.html +http://www-koi.bards.ru/Egorov/part84.htm +http://www-koi.bards.ru/Egorov/part29.htm +http://www-koi.bards.ru/Egorov/part127.htm +http://www-koi.bards.ru/Egorov/part68.htm +http://www.loisirs.ch/emjius/10/brglll.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/quizz/music/computers/legendes/lit/hellequin.html +http://www.redrival.com/dejanss/muzika/exploited/themassacre.html +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/SaveCounter/2000-08-31/13/967698323786.txt +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/SaveCounter/2000-08-31/13/967699453627.txt +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/SaveCounter/2000-08-31/13/967699813970.txt +http://www.chaos.dk/sexriddle/c/v/w/l/o/ +http://www.chaos.dk/sexriddle/c/v/w/l/x/ +http://www.allgemeine-immobilien-boerse.de/Oesterreich/verkauf/IIM-Teil/Startseite/Allgemeine-IB/Gemeinsam/3d-service/info.htm +http://www.marktplatz-hs.de/cgi-bin/ChioEditionShop.s/39fe2eeb0239a4a4273fd47540f806ea/IconBar +http://www.jamba.nl/KNet/_KNet-sDD8j1-GC4-puzu/browse.nl/node.0/cde7f1uou +http://www.icopyright.com/1.1635.66362 +http://www.ld.com/cbd/archive/1999/05(May)/07-May-1999/Vsol004.htm +http://www.infoscape.com.cn:8171/nf/0007/05/nfgz0517.htm +http://209.207.239.212/bkindex/c1034/f1392.html +http://www.gbnf.com/genealogy/rockwel4/html/d0007/I1584.HTM +http://www.gbnf.com/genealogy/rockwel4/html/d0023/I3700.HTM +http://www.hornchurch.londonengland.co.uk/designersgraphic.htm +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/computers/lit/misc/colorart/lit/quizz/ +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/computers/lit/misc/colorart/lit/misc/orders_mag.html +http://www.multimap.com/wi/141313.htm +http://www.multimap.com/wi/141326.htm +http://www.thestateofcolorado.com/aconplumbing.html +http://www.thestateofcolorado.com/aconstairs.html +http://ftp.netc.pt/pub/idgames/levels/doom2/0-9/10level.txt +http://members.tripod.com.br/Magoo13/musicas.htm +http://tucows.bigskysoft.com/winme/adnload/137256_30133.html +http://www.houses-apartment-rentals.com/Texas/city_search_criteria.asp?state=TX&City=CHICOTA +http://se.egroups.com/message/trabalhoseguro/186 +http://www.daysinn.com/ctg/cgi-bin/DaysInn/financial_support/AAAksrACwAAABvyAAQ +http://www.long-life.de/lt040.htm +http://smartnet.tucows.com/winme/meditme_rating.html +http://smartnet.tucows.com/winme/meditme_size.html +http://www.kmoviefc-jp.com/db/prod/pd/k1000003.htm +http://ftp.rge.com/pub/usenet/readers/mac/Mews/?S=A +http://fi.egroups.com/messages/lasermail/298 +http://fi.egroups.com/message/lasermail/295 +http://www.voter.com/home/message/post/1,1559,24-60_2976_2473-,00.html +http://se.egroups.com/message/rv8list/1122 +http://www.ferien-immobilien.de/Rhein-Sieg-kreis/verkauf/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/3d-service/Gemeinsam/Inserieren/Private-IB/Startseite/Default.htm +http://library.bangor.ac.uk/search/aUnited+Kingdom+Reading+Association/aunited+kingdom+reading+association/-17,-1,0,B/exact&F=aunited+kingdom+environmental+law+association&1,2/limit +http://webcenter.travelocity-leisure.netscape.com/DestGuides/0,1840,TRAVELOCITY|1987|5|2,00.html +http://yokohama.cool.ne.jp/michirur/dragon/maria/m2.htm +http://ring.omp.ad.jp/archives/NetBSD/packages/pkgsrc/graphics/Ngraph/patches/?D=A +http://mitglied.tripod.de/argewesterwald/jr/jrfo3.htm +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=3,16,10 +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=28,16,10 +http://avdistrict.edgate.com/hhs/pa_rc_gre.html +http://pub26.ezboard.com/fdysfuctionalrealityfrm2.showAddReplyScreenFromWeb?topicID=32.topic&index=1 +http://www.geocities.co.jp/Playtown-Domino/5245/guti.html +http://www.haikou.hi.cn/Pandect/hknj98/nj98d1.html +http://retailer.gocollect.com/do/session/1912800/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/help/site_tour/index.asp +http://ftp.unina.it/pub/Pcibm/pcdemos/ftp.hornet.org/graphics/images/1998/b/?M=A +http://variety.studiostore.com/browse/ABUGSLIFE/FIGURINE/s.qjEoNLlG +http://yp.gates96.com/11/76/10/13.html +http://yp.gates96.com/11/76/10/18.html +http://yp.gates96.com/11/76/11/63.html +http://yp.gates96.com/11/76/14/45.html +http://yp.gates96.com/11/76/14/65.html +http://yp.gates96.com/11/76/14/77.html +http://yp.gates96.com/11/76/15/1.html +http://yp.gates96.com/11/76/15/68.html +http://yp.gates96.com/11/76/15/97.html +http://yp.gates96.com/11/76/16/2.html +http://yp.gates96.com/11/76/16/59.html +http://yp.gates96.com/11/76/16/64.html +http://yp.gates96.com/11/76/16/79.html +http://yp.gates96.com/11/76/17/10.html +http://yp.gates96.com/11/76/17/52.html +http://yp.gates96.com/11/76/19/9.html +http://yp.gates96.com/11/76/19/11.html +http://yp.gates96.com/11/76/19/17.html +http://yp.gates96.com/11/76/19/19.html +http://www.debian.org.cn/Bugs/db/67/67207-b.html +http://www.bemi-immobilien.de/Exklusiv-IB/Startseite/Gemeinsam/immolink/Gemeinsam/Inserieren/Startseite/Gemeinsam/versicherungen/unfall/Gemeinsam/3d-service/info.htm +http://www.private-immobilien-boerse.de/baden-wuertemberg/calw/Verkauf/Gemeinsam/versicherungen/gebaeude/Gemeinsam/erreichenPartner/Private-IB/IIM-Teil/Startseite/frinfo.htm +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=21,0-(14,0)+9,5 +http://www.thesite.msnbc.com/tlkbck/comment/2100652/0,7436,80913-291181,00.html +http://202.109.72.57:8077/article/19991130/1741.htm +http://www.mit.edu/afs/athena.mit.edu/astaff/project/eolcdev/arch/sgi_62/ +http://www.metromix.com/top/1,1419,M-Metromix-Home-reviews!PlaceDetail-13623,00.html +http://ring.jec.ad.jp/pub/linux/debian/debian/dists/woody/non-free/binary-powerpc/news/?M=A +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceStoreCategories-BBC70A07_97FC_42E663949129E2030ACC2E97E71CD8B3 +http://grwy.online.ha.cn/paoe/about/aoe2.htm +http://www.2pl.com/b/ar/to/1/01/01/v1/1010178470-3.htm +http://www.digitaldrucke.de/(aktuell,marktplatz,nuernberg,sense,werbung)/suche/uebersicht.html +http://ustlib.ust.hk/search*chi/aswiss+radio+symphony+orchestra/aswiss+radio+symphony+orchestra/-5,-1,0,B/frameset&F=aswiss+society+for+soil+and+rock+mechanics&1,1 +http://www.ecatsbridge.com/BiB/static/sims/bbljuly99/00000101843221172F1.htm +http://www.videogames.com/psx/sports/freestyle99/screen.html?page=19 +http://www.mojahedin.org/Pages/Mojahed/Mojahed474/sci/sci02.html +http://www.shopworks.com/bigmountain/index.cfm/action/cart/userid/000E50D6-1185-19FE-A703010D0A0A8CF2 +http://polygraph.ircache.net:8181/http_-2www.horizonfinance.com/~xionthia/as/ +http://yp.gates96.com/14/76/30/16.html +http://yp.gates96.com/14/76/30/81.html +http://yp.gates96.com/14/76/31/12.html +http://yp.gates96.com/14/76/31/37.html +http://yp.gates96.com/14/76/31/68.html +http://yp.gates96.com/14/76/32/11.html +http://yp.gates96.com/14/76/32/50.html +http://yp.gates96.com/14/76/32/68.html +http://yp.gates96.com/14/76/33/26.html +http://yp.gates96.com/14/76/33/53.html +http://yp.gates96.com/14/76/35/11.html +http://yp.gates96.com/14/76/35/26.html +http://yp.gates96.com/14/76/35/47.html +http://yp.gates96.com/14/76/35/74.html +http://yp.gates96.com/14/76/36/16.html +http://yp.gates96.com/14/76/37/23.html +http://yp.gates96.com/14/76/37/56.html +http://yp.gates96.com/14/76/37/82.html +http://yp.gates96.com/14/76/38/76.html +http://yp.gates96.com/14/76/39/20.html +http://yp.gates96.com/14/76/39/25.html +http://yp.gates96.com/14/76/39/28.html +http://yp.gates96.com/14/76/39/33.html +http://yp.gates96.com/14/76/39/61.html +http://yp.gates96.com/14/76/39/69.html +http://yp.gates96.com/14/76/39/91.html +http://www-usa8.cricket.org/link_to_database/ARCHIVE/ARTICLES/JAN-JUN_1996/PRESS_REACTIONS_AUS_18MAR1996 +http://www-usa8.cricket.org/link_to_database/ARCHIVE/ARTICLES/JAN-JUN_1996/LOSS_WI_CRICKET_11MAR1996.html +http://www-usa8.cricket.org/link_to_database/ARCHIVE/ARTICLES/JAN-JUN_1996/SPINNERS_TALES_11JAN1996 +http://hurweb01.hurriyetim.com.tr/hur/turk/98/11/19/gundem/31gun.htm +http://library.cuhk.edu.hk/search*chi/aKuan,+Jui-hsuan./akuan+jui+hsuan/-5,-1,0,E/exact&F=akuan+jui+hsuan&1,22 +http://library.cuhk.edu.hk/search*chi/aKuan,+Jui-hsuan./akuan+jui+hsuan/-5,-1,0,E/frameset&F=akuan+jung&1,,0 +http://ring.toyama-ix.net/archives/pc/winsock-l/Windows95/Finger/fing32l.txt +http://cometweb01.comet.co.uk/do!tid=20&rtid=1&vsid=700&session=132044&mid=1000&rid=1060&cid=37030&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplGGolLarZLq4fLpmiLXv-KmooLckYLoznGmpq0qsc0mojLbkYLozvGotc0ZdoLckYLozvGsmv0qmc0jXfLkVZLdocLkYoLzcj1XfkLVZXLqkXLjbzKcob5qroLkVrLoizKlZd5fjYHfklKkZlLjjbLoZbLpl51ubZLDXZLollK3ljLbqlKjXfLkkaHotl4obmLloqL +http://student.monterey.edu/nr/riveradebranepom/campus/ +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/listUnseen/fol/100001/20,0/5170254 +http://www.ibiblio.org/pub/Linux/distributions/debian/contrib/binary-all/otherosfs/?D=D +http://www.ilmessaggero.it/hermes/19980909/01_NAZIONALE/SPETTACOLI/E.htm +http://ayasii.virtualspace.net/html/1207/12071611_himemiya02.htm +http://retailer.gocollect.com/do/session/1912732/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/about.asp +http://retailer.gocollect.com/do/session/1912732/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/newintros.asp +http://retailer.gocollect.com/do/session/1912732/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/dealer_lookup.asp +http://se.egroups.com/subscribe/pretty_of_five +http://home.neo.rr.com/keeter/pics.html +http://www.peopledaily.co.jp/haiwai/199910/12/newfiles/E108.html +http://www.telematik.informatik.uni-karlsruhe.de/osf/sw/v4.0x/lp2/snt100/?M=A +http://www.alyon.org/perso/1001-sciences/sciences_citoyens/agronomie/agronomie/intervenants.htm +http://www.2pl.com/b/no/fi/3/02/24/b1/3022400016-11131.htm +http://channel.nytimes.com/indexes/2000/07/21/sports/hockey/ +http://space.tin.it/io/fivird/REM/eng/albums/lyrics/documentfr.html +http://www.kurit.com/girls/galleryf.cgi?mp_code=7332&service=girls +http://store.efunctional.com/nokia.html +http://dk.egroups.com/login.cgi?login_target=%2Fmessage%2Fbonsai-cz%2F274 +http://bbs.kcm.co.kr/NetBBS/Bbs.dll/boliviabbs/opn/zka/B2-kB2Fq/qqo/007D/qqatt/^ +http://www.loisirs.ch/cvljnq/10/yrespd.html +http://www.primenet.com/~trakker/events/abcforum.htm +http://www.primenet.com/~trakker/events/frame_abcforum.htm +http://www.fogdog.com/cedroID/ssd3040183253760/nav/products/featured_brands/12r/gift_packs/ +http://www.fogdog.com/cedroID/ssd3040183253760/nav/products/featured_brands/12r/windshirts/ +http://www.oreilly.com/homepages/dtdparse/docbook/3.0/dtdent/simmod02.htm +http://dk.egroups.com/group/SCMHCSC +http://www.ycwb.com.cn/gb/2000/01/11/ycwb/dsxw/9.html +http://dk.egroups.com/message/teenhealth/1620 +http://nbzhuhq1.top263.net/htm/y/y14-5.htm +http://adserver.latimes.com/editions/orange/20001030/t000103739.html +http://adserver.latimes.com/editions/orange/20001030/t000103751.html +http://library.bangor.ac.uk/search/cWS+200+G4655+1999/cws++200+g4655+1999/-17,-1,0,B/frameset&F=cws++141+j74+h+1989&2,,2 +http://ftpsearch.belnet.be/pub/os/linux/SuSE-Linux/i386/6.4/disks/rescue +http://www.rarf.riken.go.jp/archives/tex-archive/macros/latex//contrib/supported/elsevier/model-harv.pdf +http://www.diogenes.ch/4DACTION/web_glob_showhtml/path=leser/verlag/index.html&ID=483373 +http://crn.com/Components/emailArticle.asp?ArticleID=2114 +http://link.fastpartner.com/do/session/600410/vsid/1970/tid/1970/cid/135878/mid/1060/rid/1488/chid/1970/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/speednames.php +http://link.fastpartner.com/do/session/600410/vsid/1970/tid/1970/cid/135878/mid/1060/rid/1488/chid/1970/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/nordicliving.php +http://ftp.gigabell.net/pub/FreeBSD/FreeBSD-stable/packages/emulators/ +http://ftp.gigabell.net/pub/FreeBSD/FreeBSD-stable/packages/print/ +http://emplois.fr.net/archive062000/2348.html +http://variety.studiostore.com/browse/ANASTASIA/_/b.FAVORITES%20COMICS%20ANIMFEAT/s.eKoxAPfo +http://www.geocities.co.jp/HeartLand-Gaien/3163/choko.htm +http://members.tripod.com/~moviemaniac1/moviesR/Rocketman.html +http://wiem.onet.pl/wiem/0006ac-sp1.html +http://msdn.microsoft.com/library/devprods/vs6/visualj/vjref/java.net.UnknownHostException001.html +http://www.tiscover.ch/1Root/Kontinent/6/Staat/30/Bundesland/31/Ort/1732/Homepage/m_homepage...2.html +http://power.luneng.com/power/library/jzjs/jzjs99/jzjs9903/990311.htm +http://citeseer.nj.nec.com/cidcontext/1976718 +http://in.egroups.com/messages/srcg/2 +http://sunsite.informatik.rwth-aachen.de/cgi-bin/ftp/ftpshow/pub/comp/Linux/debian/dists/potato/main/disks-sparc +http://pd.shiseido.co.jp/s9701unt/html/unt00025.htm +http://www.kame.tadaima.com/9721036/taro1.html +http://www.kame.tadaima.com/9721036/taro8.html +http://www.unc.edu/courses/chem41/classnotes/41s6/sld008.htm +http://a1sexpics.com/butts/buttfucking/ +http://moundoflove.com/buttfucking/butts/asslickinganal.html +http://www.digitaldrucke.de/(arbeitsvermittlung,hilfe,nuernberg)/_fort/html/themen/hilfe/hilfe.htm +http://freethemes.netc.pt/preview/15221.html +http://freethemes.netc.pt/preview/51972.html +http://freethemes.netc.pt/preview/74442.html +http://cn.tech.yahoo.com/000913/23/1dpl.html +http://cn.tech.yahoo.com/000913/23/1dp2.html +http://wap.jamba.de/KNet/_KNet-JgK8j1-FGd-13di8/browse.de/node.0/cde7f1uou +http://imageserver2.tibetart.com:8087/fif=fpxbuddhist/43.fpx&init=0.0,0.0,1.0,1.0&rect=-0.25,0.25,0.25,0.75&wid=280&hei=400&lng=en_US&enablePastMaxZoom=OFF&page=image.html&obj=uv,1.0&cmd=S +http://www.ozemail.com.au/~pballard/gnt_hidden123/mar12.htm +http://www.ozemail.com.au/~pballard/gnt_hidden123/act9.htm +http://www.ozemail.com.au/~pballard/gnt_hidden123/rom7.htm +http://www.ozemail.com.au/~pballard/gnt_hidden123/2co13.htm +http://www.ozemail.com.au/~pballard/gnt_hidden123/heb12.htm +http://www.ozemail.com.au/~pballard/gnt_hidden123/jam4.htm +http://ftp.darenet.dk/tucows/winnt/adnload/1449_29554.html +http://www.chaos.dk/sexriddle/w/j/u/o/ +http://www.chaos.dk/sexriddle/w/j/u/v/ +http://opac.lib.rpi.edu/search/tmcgraw+hill+series+in+advanced+chemistry/-5,-1,0,B/frameset&tmcgraw+hill+series+in+advanced+chemistry&9,,42 +http://www.zcu.cz/ftp/mirrors/pgp/6.5/6.5.1/win/ +http://webpolitik.subportal.com/sn/Multimedia_and_Graphics/Misc__Graphics_Tools/12852.html +http://ftp.lip6.fr/pub2/perl/CPAN/doc/manual/html/lib/SysV/SysV.html +http://bbs.gznet.edu.cn/cgi-bin/getannounce//groups/GROUP_9/Telecom/friend/fbf/ewqtr +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-10.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-88.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-92.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-177.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-178.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-229.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-288.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9709/date/article-293.html +http://www.usq.edu.au/unit-1997/fullspec/54081s2x.htm +http://sound-dist.secured.co.uk/cgi-bin/psProdDet.cgi/15P04|972959617|Helmet|user|0|1,0,0,0 +http://www.buybuddy.com.au/sleuth/8/1/5010204/40843/ +http://www.maxpages.com/vote.cgi?site=pokemonyellow1&pg=Home +http://rex.skyline.net/html/Automobiles_-_Dealers_-_Used.html?64,outdoor,transportation,collectibles,transportation +http://www.linux.com/networking/network/communications/management/updates/Windows_NT/ +http://retailer.gocollect.com/do/session/1912735/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/top_ten.asp?pagenum=1 +http://amarilloglobenews.com/stories/031000/ +http://www.egroups.com/post/swish?act=reply&messageNum=275 +http://www.apcmag.com/apcweb/reviewsdisc.nsf/aac7d56ca8fd884b852563be00610639/af5bb64432e7f9444a2565240026bbbf!Navigate&To=PrevMain +http://best.netease.com/guestbook/personal/zhuirinew3.html +http://best.netease.com/cgi-bin/view/viewbasic.cgi?japanboy4 +http://www.ftp.uni-erlangen.de/cgi-bin/view/pub/mirrors/redhat/current/i386/doc/gsg/ch-basics.htm +http://www.ftp.uni-erlangen.de/cgi-bin/view/pub/mirrors/redhat/current/i386/doc/gsg/p5202.htm +http://splitrock.themes.tucows.com/preview/77000.html +http://splitrock.themes.tucows.com/preview/25855.html +http://splitrock.themes.tucows.com/preview/134493.html +http://splitrock.themes.tucows.com/preview/14722.html +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=13,0-22,0+15,0-0,2 +http://www.icopyright.com/1.1634.64625 +http://mvweb.de/olympia/nachrichten/sportarten/ergebnisse/bdt-190900-438-dpa_153140.html +http://www.rge.com/pub/tex/fonts/armtex/v2.0/examples/plain/ +http://www.club-internet.fr/cgi-bin/h?Antibes +http://www.caprili.it/santantimo.htm +http://dic.empas.com/show.tsp/?q=%C3%EB%C8%EF%20%F6%AD%FD%E9&f=B +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=98&discrim=2,38 +http://www.artex.firenze.it/_qualitart/articoli/zoom/02235.htm +http://home.powertech.no/huftis/w3c/TR/WAI-WEBCONTENT-NO-NYN/checkpoint-list.txt +http://mtlab.biol.tsukuba.ac.jp/WWW/PDB2/PCD0467/htmls/07.html +http://library.cuhk.edu.hk/search*chi/aShu,+Tien-min./ashu+tien+min/-5,-1,0,B/exact&F=ashu+tsung+chiao&1,6 +http://www.trnonline.com/archives/2000archives/05242000/how_now_joe_brown/23506.shtml +http://www.bemi-immobilien.de/Exklusiv-IB/Startseite/Gemeinsam/versicherungen/gebaeude/Gemeinsam/MarketingStrategie/Gemeinsam/erreichenPartner/Gemeinsam/versicherungen/lebensversicherung/Startseite/frinfo.htm +http://santabarbarashops.com/Mall/Stores/StoreInfo/asp/store-id/1000007121.html +http://www.angelfire.com/ok/americassweetheart/UNique.html +http://ukinvest.ukwire.com/articles/199909070731000375A.html +http://www.streetprices.com/Electronics/Consumer/Camcorders/Digital/sortproductbylowprice/SP374033.html +http://www.streetprices.com/Electronics/Consumer/Camcorders/Digital/sortproductbylowprice/SP363722.html +http://www.streetprices.com/Electronics/Consumer/Camcorders/Digital/sortproductbylowprice/SP288187.html +http://www.streetprices.com/Electronics/Consumer/Camcorders/Digital/sortproductbylowprice/SP288192.html +http://www.bemi-immobilien.de/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/Gemeinsam/versicherungen/gebaeude/Startseite/Gemeinsam/Gemeinsam/immolink/Top-Darlehens-Konditionen/anforderungsformular.htm +http://celes.subportal.com/sn/Business/Standard_Calculators/index1.html +http://www.linux.com/networking/network/networking/it/future/firewall/ +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=198&discrim=87,19,3 +http://www.hig.se/(append,define,language,quote,tablify)/~jackson/roxen/ +http://www.guba.com/114/236/12fE/index-3.phtml +http://genforum.genealogy.com/tn/messages/7906.html +http://207.138.41.133/message/BienestarCalifornia/16 +http://207.138.41.133/message/BienestarCalifornia/26 +http://chasnaz.freeyellow.com/email.html +http://genforum.genealogy.com/cgi-bin/print.cgi?mcevoy::217.html +http://www.civila.com/brasil/fov/ +http://www.emerchandise.com/associates/b.FAVORITES%20PAGEANTS/s.oAq5vp1w +http://www.emerchandise.com/help_security/b.FAVORITES%20PAGEANTS/s.oAq5vp1w +http://www.z-plus.de/freizeit/kino/galerie/roula/kritikwelt.html +http://www.angelfire.com/mo2/MrMime2000/wewon.html +http://www.gazeta.com/Iso/Regiony/Lodz/Raporty/Jedzenie/Jedz/020jed.html +http://www.sportas.de/ddsup00.htm +http://muc-zvs-web1.goethe.de/an/mel/wabhorst/dtourism.htm +http://www.cardina.net/~erps +http://www.polbox.com/p/paruwa/spec.html +http://ww2.comune.fe.it/cgi-win/hiweb.exe/a2/d72/b31,e,1f,b,b,50,50,,3,,1f,3,9,,1f,9, +http://www.ld.com/cbd/archive/1999/03(March)/29-Mar-1999/15awd002.htm +http://dk.egroups.com/post/cbradio?act=reply&messageNum=823 +http://aecjobbank.com/texis/script/newjobs/+lww7mwww0xBV6e52iHwwwesPBB2eZmwwwt6erV0Vwwwh6er6Gswwwt6er6bgwwwt6etDL-www+6ethrCwwxeRT43eR4mwwwt6etrvuwwwn6KeU-wwwmcmrmwxerjmx7mwww1hzmww-eHxww/jobdirectory.html +http://www.envy.nu/summerslip/past.html +http://www.envy.nu/summerslip/leave.html +http://home.pacific.net.sg/~kinnkinn/ +http://www.bluesapphires.net/ladies/lv0444.shtml +http://www.freerepublic.com/forum/a4148bd.htm +http://www.sdinfonet.com.cn/024/32/024329969.htm +http://www.sdinfonet.com.cn/024/32/024329953.htm +http://www.jpc-music.com/8754347.htm +http://www.jpc-music.com/5183511.htm +http://www.jamba.nl/KNet/_KNet-ytO8j1-7D4-pwef/browse.nl/node.0/cde7f38ny +http://dk.egroups.com/message/noholdsbarred/210 +http://uoi.tucows.com/winme/preview/75912.html +http://207.197.132.133/lobbyists/98profiles/556.htm +http://www.jobvillage.com/channel/jobs/protective_services/private_investigator/g.4.html +http://www.jobvillage.com/channel/jobs/protective_services/private_investigator/b.8946.g.4179.html +http://aleph.tau.ac.il:4500/ALEPH/eng/ATA/AAS/AAS/SET-MAIL/381462/11/ +http://www-rn.informatik.uni-bremen.de/home/X11R6/xc/lib/font/Speedo/?D=A +http://www.brio.de/BRIO.catalog/39fe2f7006f69fb6273fd472aa78073d/UserTemplate/6 +http://cardiology.medscape.com/IMNG/ClinPsychNews/1998/v26.n07/cpn2607.34.01.html +http://www.incestpornstories.com/hot-hardcore-fuckingbanging/plus-sizewhale/slutspretty/slutsbest-friends/erectionfellatio/bisexualtinkerbell.html +http://yp.gates96.com/7/65/10/40.html +http://yp.gates96.com/7/65/11/15.html +http://yp.gates96.com/7/65/11/34.html +http://yp.gates96.com/7/65/11/69.html +http://yp.gates96.com/7/65/11/88.html +http://yp.gates96.com/7/65/12/95.html +http://yp.gates96.com/7/65/13/82.html +http://yp.gates96.com/7/65/13/91.html +http://yp.gates96.com/7/65/13/93.html +http://yp.gates96.com/7/65/14/2.html +http://yp.gates96.com/7/65/14/8.html +http://yp.gates96.com/7/65/15/31.html +http://yp.gates96.com/7/65/15/38.html +http://yp.gates96.com/7/65/15/51.html +http://yp.gates96.com/7/65/15/95.html +http://yp.gates96.com/7/65/15/96.html +http://yp.gates96.com/7/65/16/4.html +http://yp.gates96.com/7/65/16/20.html +http://yp.gates96.com/7/65/16/58.html +http://yp.gates96.com/7/65/17/22.html +http://yp.gates96.com/7/65/17/66.html +http://yp.gates96.com/7/65/18/37.html +http://yp.gates96.com/7/65/18/69.html +http://yp.gates96.com/7/65/18/97.html +http://yp.gates96.com/7/65/19/0.html +http://yp.gates96.com/7/65/19/12.html +http://yp.gates96.com/7/65/19/16.html +http://yp.gates96.com/7/65/19/28.html +http://yp.gates96.com/7/65/19/37.html +http://yp.gates96.com/7/65/19/44.html +http://dyade.inrialpes.fr/aaa/public/java/jdk1.3/docs/api/javax/swing/plaf/basic/class-use/BasicSplitPaneUI.KeyboardUpLeftHandler.html +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/asiasanahaku/kalatalous/ty%F6voimapolitiikka/pienet+ja+keskisuuret+yritykset/maatilatalous/ +http://www.ferien-immobilien.de/ungarn/verkauf/Gemeinsam/MarketingStrategie/Allgemeine-IB/Private-IB/Private-IB/Startseite/Default.htm +http://ftp.du.se/disk2/CPAN/modules/by-category/15_World_Wide_Web_HTML_HTTP_CGI/WWW/libwww-perl-5.43.readme +http://ftp.du.se/disk2/CPAN/modules/by-category/15_World_Wide_Web_HTML_HTTP_CGI/WWW/libwww-perl-5.46.readme +http://ftp.du.se/disk2/CPAN/modules/by-category/15_World_Wide_Web_HTML_HTTP_CGI/WWW/webchat-0.05.readme +http://209.0.220.240/biz/541519/541-389-1493.htm +http://www.shsu.edu/wcb/schools/SHSU/sed/rmzoubi/12/forums/forum54/wwwboard.html +http://retailer.gocollect.com/do/session/1912768/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/news/index.asp +http://romulus.ehs.uiuc.edu/cgi-bin/lwgate/RADSAFE/archives/radsafe9610/Date/article-33.html +http://romulus.ehs.uiuc.edu/cgi-bin/lwgate/RADSAFE/archives/radsafe9610/Date/article-31.html +http://www.acfas.ca/congres/congres67/S408.htm +http://pub1.ezboard.com/fthehawkeyehotspotfrm16.showMessage?topicID=178.topic +http://archives.marshall.edu/~mccomas/cd315-spring00-list/1549.html +http://www.asiastockwatch.com/AsiaStockWatch_-_Cached/Articles/asw_recommend_friend_con/1,1145,617_1_1:3,00.html +http://wiem.onet.pl/wiem/014a7e.html +http://linux99.inrialpes.fr/linux/RPM/kondara/1.2/errata/bugfixes/i586/System_Environment_Daemons.html +http://linux99.inrialpes.fr/linux/RPM/kondara/1.2/errata/bugfixes/i586/User_Interface_X.html +http://cn.egroups.com/login.cgi?login_target=%2Fmessage%2FWeb_Holidays%2F35 +http://library.bangor.ac.uk/search/aEuropean+Academy+of+Allergology+and+Clinical+Immunology/aeuropean+academy+of+allergology+and+clinical+immunology/7,-1,0,B/bibandlinks&F=aeuropean+association+for+animal+production+commission+on+animal+management&1,1 +http://www4.freeweb.ne.jp/art/fujiso/gehp/pge222.html +http://pnews.jcc.co.jp/scoop/9905/990506kk2-3ss.html +http://ring.nii.ac.jp/archives/linux/Vine/Vine-1.1/kernel-2.2.x-kit/RPMS/ +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=81&discrim=8,230,214 +http://www.emerchandise.com/browse/BUFFYTHEVAMP/KEYCHAIN/b.TV%20BUFFYTHEVAMP/s.DfgPpLQw +http://www.emerchandise.com/browse/BUFFYTHEVAMP/MAGNET/s.DfgPpLQw +http://www.koms.de/I-Data/Upgrades/HostCom/Cx/isp/?S=A +http://www.back2roots.org/Aminet/Forums/Util--Wb--Amero36/ +http://www.hig.se/(autoformat,define,en,modified,referrer)/~jackson/roxen/ +http://216.35.79.131/sites/gunits/052302u.html +http://216.35.79.131/sites/gunits/052303u.html +http://216.35.79.131/sites/gunits/032883u.html +http://itcareers.careercast.com/texis/it/itjs/+4wwBmecXD86ExwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewShwAwMwoacnwmamnpcdOMnDBaMwoDBnDwDqnanDtoDnnGaDnBidGAaoDqc1mna5BGdDtaADdicnmtnaGn31oGnmaMFqtwAwMwoDzmeZxwwwpBmIe0B-decrwww5rmeAdwwwBrmeZpwww/morelike.html +http://troy.lib.sfu.ca/search/tadvocate+vanc/tadvocate+vanc/7,-1,0,B/browse +http://210.159.30.200:8080/-_-http://www2s.biglobe.ne.jp/~proton/kokuritu/ +http://210.159.30.200:8080/-_-http://www2s.biglobe.ne.jp/~proton/mituzawa/mitusta.html +http://config.tucows.com/win2k/monitor2k_size.html +http://config.tucows.com/win2k/adnload/136674_47327.html +http://www.thisisyork.com/york/news/YORK_NEWS_CAMPAIGNS_POSTOFFICE5.html +http://yp.gates96.com/5/78/0/35.html +http://yp.gates96.com/5/78/0/41.html +http://yp.gates96.com/5/78/0/65.html +http://yp.gates96.com/5/78/0/79.html +http://yp.gates96.com/5/78/0/81.html +http://yp.gates96.com/5/78/1/33.html +http://yp.gates96.com/5/78/1/76.html +http://yp.gates96.com/5/78/2/0.html +http://yp.gates96.com/5/78/2/65.html +http://yp.gates96.com/5/78/3/37.html +http://yp.gates96.com/5/78/4/31.html +http://yp.gates96.com/5/78/4/60.html +http://yp.gates96.com/5/78/4/73.html +http://yp.gates96.com/5/78/5/28.html +http://yp.gates96.com/5/78/5/65.html +http://yp.gates96.com/5/78/6/12.html +http://yp.gates96.com/5/78/6/38.html +http://yp.gates96.com/5/78/6/99.html +http://yp.gates96.com/5/78/7/48.html +http://yp.gates96.com/5/78/8/49.html +http://yp.gates96.com/5/78/8/55.html +http://yp.gates96.com/5/78/8/71.html +http://yp.gates96.com/5/78/9/19.html +http://yp.gates96.com/5/78/9/94.html +http://link.fastpartner.com/do/session/600420/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/fastpartner.php +http://www.highwired.net/Guidance/UniversalNav/Redirect/0,5314,15089-15089-728,00.html +http://ring.tains.tohoku.ac.jp/archives/lang/perl/CPAN/modules/by-module/Math/ILYAZ/os2/?S=A +http://www.outpersonals.com/cgi-bin/w3com/pws/out/DzRIZER-v0LffJEf3raIMcG3_vXLUQncNB0JHLK7Xt_XcNu5W9Xwg3bnK7e0BWrbchX2jMSNnK6eY6UuDPq6GFLMrzB0DcydY5VgMGVRUFbdksWiDCuTI0LBo3psuJxBJjEd +http://www.outpersonals.com/cgi-bin/w3com/pws/out/vihIvBk0g-CdjheZ4MILAcJAB--YtsE3nzjAldQSrSojV9JzVQJV-1yVbCi9rsPamZBGc9GfXE6dq1sCz-CnrfwDCHqr_nfUtl2qUN5oWAHphPSuuQXCc2fjfBv3EI-W4XBgp-ANhxEJS0536665 +http://www.outpersonals.com/cgi-bin/w3com/pws/out/VihIDgZ6TF6W8zfPesIFMiw-CNzcKPLyYr5OXnsaqepOa1j4Wz2V-pVOhRfX5lUkxRpYs_BkTdpvjf7zUAk3RdhEaXDfmzm4RA2CLjQ84zSbEZ_Vil1cFFmY0FFZr5oIErljk11AnTlYM6y066jO +http://www.outpersonals.com/cgi-bin/w3com/pws/out/dRhIQJ3pEIfD5uG_JFeaP3_7Bke37Z5pJi0A-hZ_-kxEK4Z1jl3HNb6d3hgJ7UZ34jMQGSNzhYuMNxB-oyBon62h9GWx3Xt1Zk_o4kS3s9ybikCpzetMwprVGDCC-YzllwvEWxmP66jF +http://www.v2music.com/Scripts/WebObjects-ISAPI.dll/V2_New_Publisher.woa/24161000003783000000741030000081551/v2tvindex.wo/810000000071551/1.0.4/3/Webobjects1 +http://www.maas.ccr.it/cgi-win/hiweb.exe/a17/d3345/b77,c,4d,469,469,46e,46e,168e,168e,,51,,4d,51, +http://findmail.com/messages/themcse/102 +http://netcon.tucows.com/winme/adnload/136907_28427.html +http://netcon.tucows.com/winme/adnload/136906_30076.html +http://www.jyu.fi/~heili/tietoverkot/?S=A +http://www1.onelist.com/dir/1/16/483/32773?st=10 +http://www1.onelist.com/messages/animadores +http://seussville.com/teachers/authors/ayre.html +http://seussville.com/teachers/authors/corm.html +http://www.tente.de/sw/produkte/rubriksuche/aa000001461.htm +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=57&discrim=165,57,164 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=57&discrim=165,57,207 +http://jars.developer.com//classes/jresout.cgi?resource=2897 +http://members.tripod.co.jp/spirits/?S=A +http://homepages.go.com/homepages/i/u/g/iuguy22/ +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=21,5,24 +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=31,5,24 +http://troy.lib.sfu.ca/search/delectrolytes+periodicals/delectrolytes+periodicals/-5,-1,0,B/exact&F=delectrolytes+congresses&1,3 +http://www.rdg.ac.uk/ITS/Topic/Stats/StGSAS8_01/SAS8/af/z0254912.htm +http://www.rdg.ac.uk/ITS/Topic/Stats/StGSAS8_01/SAS8/af/z0254924.htm +http://ring.jec.ad.jp/local/mirror/FreeBSD-current/snapshots/i386/5.0-20000902-CURRENT/compat20/ +http://ring.jec.ad.jp/local/mirror/FreeBSD-current/snapshots/i386/5.0-20000902-CURRENT/dict/ +http://ring.jec.ad.jp/local/mirror/FreeBSD-current/snapshots/i386/5.0-20000902-CURRENT/manpages/ +http://www.xmission.com/~dkenison/cgi/lwgate.cgi/KLR650/archives/v02.n1682/date/article-7.html +http://ring.toyama-ix.net/pub/linux/Vine/Vine-2.0/ppc/?S=A +http://romulus.ehs.uiuc.edu/cgi-bin/lwgate/RADSAFE/archives/radsafe9907/Date/article-80.html +http://www.officeqmart.com/cgi-bin/qmart.front/972959552267/Catalog/3000033 +http://www.checkout.com/member/movies/title/member_reviews_form/1,7722,882122,00.html +http://mindit.netmind.com/proxy/http://www.siennasoft.com/english/order/orders_retail.shtml +http://pelit.saunalahti.fi/.1/tucows/adnload/267_29529.html +http://pelit.saunalahti.fi/.1/tucows/adnload/7574_29534.html +http://zenha.myrice.com/2/23.htm +http://zenha.myrice.com/2/20.htm +http://citeseer.nj.nec.com/cachedpage/62677/1 +http://citeseer.nj.nec.com/check/248055 +http://www.3wbooks.de/BrackRuth/BrackRuth3258053200.htm +http://preview.egroups.com/group/u_exactus +http://preview.egroups.com/group/ticovista +http://www.linux.com/networking/linux/support/va_linux_systems/price/sales/ +http://kulichki-mac.rambler.ru/moshkow/akm/zercalo/kosmix/03.html +http://innopac.lib.tsinghua.edu.cn:2080/search*chi/tStructure+and+bonding+&%2359%3B+70/tstructure+and+bonding+++70/19,-1,0,B/browse +http://www.science.uva.nl/pub/NetBSD/NetBSD-current/pkgsrc/archivers/gcpio/files/ +http://www-d0.fnal.gov/d0dist/dist/releases/pmc04.00.00/calibration_management/?S=A +http://mvweb.de/olympia/nachrichten/sportarten/news/bdt-290900-158-dpa_173282.html +http://www.scifi.com/bboard/browse.cgi/3/1/69/57?pnum=2 +http://www.diogenes.ch/4DACTION/web_rd_aut_prview/a_id=7056459&area=&ID=483365 +http://mirror.cc.utsunomiya-u.ac.jp/mirror/CPAN/authors/id/L/LA/LAXEN/?D=A +http://www.affiliate.hpstore.hp.co.uk/do/session/380856/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.france.hp.com/Main/acheterhp/ +http://library.cuhk.edu.hk/search*chi/aLu,+Li,+1914-/alu+li+1914/-5,-1,0,B/frameset&F=alu+li+chun&1,1 +http://www-usa4.cricket.org/link_to_database/ARCHIVE/2000-01/IND_LOCAL/WOMEN/OTHERS/KLCA-SL/SQUADS/ +http://www.babyheirlooms.com/catalog/htmlos.cat/041141.1.4425650346 +http://193.207.57.3/cgi-win/hiweb.exe/a2/d9/b1305,4,5,,1f,5, +http://www.icopyright.com/1.1664.228033 +http://www.trax.nilex.co.uk/trax.cgi/A1C/B1S/1AR/A2S/A1S/D1L/ +http://www.trax.nilex.co.uk/trax.cgi/A1C/B1S/1AR/A2S/A1S/A2S/ +http://www.ferien-immobilien.de/baden-wuertemberg/calw/Verkauf/Gemeinsam/Inserieren/Private-IB/Gemeinsam/Super-Zins-Konditionen/3d-service/info.htm +http://sunsite.informatik.rwth-aachen.de/LinuxArchives/redhat/releases/guinness/i386/en/dosutils/fips15c/restorrb/ +http://213.36.119.69/do/session/153002/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/connaitre/revue-presse_titres.html +http://pub19.ezboard.com/uvinylangel.showPublicProfile?language=EN +http://boeing_dude.tripod.com/id125_m.htm +http://members.fortunecity.com/greatway1/gallery-pageother-0.htm +http://www.searchtraffic.com/wsignup.php3?owor12 +http://www.staroriental.net/nav/soeg_c/ihf,acv,s0,194,陳慧琳.html +http://www.jpc-music.com/5864555.htm +http://oaziz.narod.ru/kuhn/uzb/sal_f1.html +http://preview.egroups.com/message/4aromatherapy/1112 +http://www.luecos.de/webguides/reisen/travelpictures/europe +http://www.maas.ccr.it/cgi-win/hiweb.exe/a18/d47/b47,8,be,29,29,,38,,be,38, +http://www.chaos.dk/sexriddle/k/u/u/a/ +http://www.chaos.dk/sexriddle/k/u/u/d/ +http://student.monterey.edu/nr/nielsenadamp/campus/ +http://excite.de/gesundheit/katalog/3727 +http://www.ozemail.com.au/~jcai/page19.html +http://www.ozemail.com.au/~jcai/page24.html +http://www.hantsnet.co.uk/scrmxn/c23173.html +http://www.fogdog.com/cedroID/ssd3040183334784/content/fan/subway_series/ +http://www.fogdog.com/cedroID/ssd3040183334784/boutique/arnette/ +http://www.fogdog.com/cedroID/ssd3040183334784/boutique/hi-tec/ +http://www.fogdog.com/cedroID/ssd3040183334784/boutique/marmot/ +http://ftpsearch.belnet.be/packages/CPAN/modules/by-module/Stat/ENNO/ +http://go1.163.com/_NTES/~yejingsong/03/y18/506.htm +http://sinr.net/book/content/343/26710.html +http://www.ramada.com/ctg/cgi-bin/Ramada/progpack/AAAksrACwAAABtrAAV +http://library.bangor.ac.uk/search/aBoer,+J.+H.+de+(Jan+Hendrik),+1899-/aboer+j+h+de+jan+hendrik+1899/-5,-1,0,B/buttonframe&F=aboer+dirk+jan+den&1,1 +http://library.cuhk.edu.hk/search*chi/a三省堂(千代田區,+Tokyo,+Japan)/a%7B213024%7D%7B214d49%7D%7B213840%7D+%7B213458%7D%7B213073%7D%7B214c24%7D%7B213455%7D+tokyo+japan/-5,-1,0,B/browse +http://ibm1.cicrp.jussieu.fr/ibmc/classref/ref/ISetCanvas--Style_DSC.htm +http://amateur-alley.porncity.net/169/ +http://www.teacherformation.org/html/od/facilitators.cfm/task1,about/discussion_id,2/xid,1989/yid,5768630 +http://www.shopworks.com/index.cfm/action/mallcat/mallcatlevel/2/parentmallcat/6/userid/000056F0-2E26-19FE-AF65010C0A0A8CF2 +http://retailer.gocollect.com/do/session/1912760/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/shipping_policy.asp +http://news.novgorod.ru/news/2001/4/1/8/-1 +http://news.novgorod.ru/news/2001/4/3/8/-1 +http://sp201.unige.ch:49213/cxxdoc/classref/ref/ITimingTestStopwatch_DSC.htm +http://netscape.digitalcity.com/boston/localexperts/profile.dci?screenName=PSYWU +http://netscape.digitalcity.com/boston/localexperts/profile.dci?screenName=Mende67 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=17,2,26,33,23 +http://www.multicosm.com/facade/www.isinet.com/isilinks/isilinks.html +http://kutschen.de/Schoner/Info-d/history/history/literature/ +http://troy.lib.sfu.ca/search/dengineering+research+periodicals/dengineering+research+periodicals/-5,-1,0,B/frameset&F=dengineering+research+grants+canada&3,,4 +http://member.nifty.ne.jp/y-shibata/pc/pch2.htm +http://stocks.tradingcharts.com/stocks/charts/iops-bb/m +http://www.kaos.dk/sexriddle/x/j/c/s/z/ +http://www.bioimages.org.uk/HTML/R138925.HTM +http://pub22.ezboard.com/fawolpaintballfrm1.threadControl?topicID=82.topic +http://www.incestpornstories.com/hot-hardcore-fuckingbanging/plus-sizewhale/body-shotstounge/fuckinghardcore/barely-legalbackseat/{gaylink} +http://www.buybuddy.com/sleuth/27/1/1060904/5811/ +http://www.loisirs.ch/gtfmjv/9/nkrlua.html +http://vorg1.subportal.com/sn/Utilities/File_Maintenance_and_Repair_Utilities/6387.html +http://smartnet.tucows.com/winme/adnload/138584_30392.html +http://ftpsearch.belnet.be/mirrors/src.doc.ic.ac.uk/usenet/usenet-by-hierarchy/comp/emacs/?D=A +http://genforum.genealogy.com/cgi-genforum/forums/green.cgi?7578 +http://cio.cisco.com/warp/public/789/33.html +http://www7.freeweb.ne.jp/diary/bru_dog/tk/ +http://www.chinabyte.com/staticpages/software/software_download/GRBA/software_download_23274_GRBA.html +http://www.chinabyte.com/staticpages/software/software_download/GRBA/software_download_9599_GRBA.html +http://www.seekon.com/L/US/IL/Abingdon +http://freethemes.arrakis.es/skins/winamp/adnload/25359.html +http://www.hig.se/(accessed,modified,remove_cookie,smallcaps,sqlquery)/~jackson/roxen/ +http://cn.egroups.com/message/SF-users/218 +http://cn.egroups.com/message/SF-users/235 +http://www.chaos.dk/sexriddle/r/f/y/c/ +http://www.chaos.dk/sexriddle/r/f/y/e/ +http://www.chaos.dk/sexriddle/r/f/y/g/ +http://yp.gates96.com/13/50/10/33.html +http://yp.gates96.com/13/50/10/49.html +http://yp.gates96.com/13/50/10/55.html +http://yp.gates96.com/13/50/10/98.html +http://yp.gates96.com/13/50/11/35.html +http://yp.gates96.com/13/50/11/73.html +http://yp.gates96.com/13/50/11/94.html +http://yp.gates96.com/13/50/12/39.html +http://yp.gates96.com/13/50/13/8.html +http://yp.gates96.com/13/50/13/67.html +http://yp.gates96.com/13/50/14/8.html +http://yp.gates96.com/13/50/14/11.html +http://yp.gates96.com/13/50/14/47.html +http://yp.gates96.com/13/50/16/18.html +http://yp.gates96.com/13/50/16/58.html +http://yp.gates96.com/13/50/17/33.html +http://yp.gates96.com/13/50/18/13.html +http://yp.gates96.com/13/50/18/49.html +http://yp.gates96.com/13/50/18/54.html +http://yp.gates96.com/13/50/19/0.html +http://cn.egroups.com/post/romtrade?act=reply&messageNum=3851 +http://members.fortunecity.com/toleransi/sorbonne.html +http://ring.htcn.ne.jp/pub/lang/perl/CPAN/modules/by-module/PPM/MURRAY/?S=A +http://sunsite.berkeley.edu/PhiloBiblon/BITAGAP/BIB/BIB5648.html +http://sunsite.berkeley.edu/PhiloBiblon/BITAGAP/BIB/BIB7392.html +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus53940/eus53960/eus54753/eus543189/eus550516/ +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus53940/eus53960/eus54753/eus543189/eus550528/ +http://shn.webmd.com/roundtable_printing/774674 +http://www.zi.unizh.ch/software/unix/statmath/sas/sasdoc/lgref/z0205140.htm +http://www.hblb.org.uk/hblbweb.nsf/$Pages/NewsArchive1!OpenDocument&ExpandSection=16,12,3,13,5,6,9 +http://www.uni-duesseldorf.de/ftp/ftp/pf/share/fvwm-2.0.45/?S=A +http://members.tripod.com/~PhyrePhox/mcse/70-088.htm +http://extreme-dm.com/tracking/reports/dj/nph-ref1.cgi?tag=nimrood +http://opac.lib.ntnu.edu.tw/search*chi/++ftlist/bp20040397/-5,-1,0,B/frameset&F=bp20040402&1,1 +http://209.0.220.240/spec/txve.htm +http://209.0.220.240/spec/tyai.htm +http://ftp.up.pt/Linux/Linus/net-source/www/clients/netscape/?M=A +http://ftp.up.pt/Linux/Linus/net-source/www/clients/netscape/?D=A +http://www.jobvillage.com/channel/jobs/health_care/nursing/licensed_practical_nurse/b.9505.g.1766.html +http://www.zope.org/Members/stevea/CoadObjectModels/BackLinks/backlinks +http://www.mairie-montreuil93.fr/ville_pratique/environ/energie/mve/media/?D=A +http://member.shangdu.net/home2/chr/jishang/hongkong/inxg-6.html +http://www.wild-dog.com/activity/touring/idx/page_18_1.html +http://members.tripod.co.jp/susu/?M=A +http://www.dulux.co.uk/UKRETAIL:623356687:DFinity.1QJiP4jMLco +http://www.kordic.re.kr/~trend/Content326/agriculture04.html +http://www.kordic.re.kr/~trend/Content326/agriculture09.html +http://ftp.lip6.fr/pub12/OpenBSD/src/gnu/egcs/config/mh-aix43 +http://ftp.lip6.fr/pub12/OpenBSD/src/gnu/egcs/config/mh-elfalphapic +http://ftp.lip6.fr/pub12/OpenBSD/src/gnu/egcs/config/mt-x86pic +http://www.ecatsbridge.com/BiB/static/sims/bbljuly99/00000101758612773F1.htm +http://pub20.ezboard.com/faustralianslotcarreviewhoracing.showMessage?topicID=2.topic&index=47 +http://ring.omp.ad.jp/archives/NetBSD/packages/pkgsrc/games/exchess/pkg/DESCR +http://homepage.renren.com/sandybay/help.htm +http://no.egroups.com/post/oslosynth?act=reply&messageNum=634 +http://www.brio.de/BRIO.catalog/39fe2f940703266c273fd472aa7806a8/UserTemplate/2 +http://www.50megs.com/prettysenshi/captures/ep3/SMep3.html +http://www.thisislancashire.co.uk/lancashire/archive/1999/11/05/CHORNEWS5VQ.html +http://au.yahoo.com/Regional/U_S__States/California/Metropolitan_Areas/San_Francisco_Bay_Area/Entertainment_and_Arts/Restaurants/Coffee_and_Tea_Houses/ +http://www.niwl.se/WAIS/30002/30002360.htm +http://www.infoscape.com.cn:8178/gb/content/2000-08/16/content_6082.htm +http://link.fastpartner.com/do/session/600419/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/mondosoft.php +http://www.canit.se/(c1,f3,ftp,generellt,irc,mail)/support/ +http://citeseer.nj.nec.com/cidcontext/3787443 +http://www.affiliate.hpstore.hp.co.uk/do/session/380878/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/entry.asp +http://www.usq.edu.au/unit-1997/fullspec/51129s3x.htm +http://worldres.lycos.com/script/gen_mr.asp?hotel_id=6354&n=1518 +http://www.members.aon.at/~kleindlp/neue_seite_4.htm +http://210.169.76.95/html/tai_0043/bat_1180.html +http://oneplace.adbureau.net/accipiter/adclick/site=ONEPLACE/area=INDEX/POSITION=FOOTER/AAMSZ=468x60/ACC_RANDOM=262411779164 +http://www.service911.com/mvu/step/0,2632,6+34+90+23506+13880_4,00.html +http://ftp.lip6.fr/pub11/NetBSD/NetBSD-current/src/usr.sbin/kvm_mkdb/Makefile +http://www.bemi-immobilien.de/Private-IB/Startseite/Startseite/Gemeinsam/versicherungen/unfall/Gemeinsam/immolink/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/versicherungen/gebaeude/anforderungsformular.htm +http://wap.jamba.de/KNet/_KNet-BOC8j1-LFd-13bpy/showInfo-hilfe.de/node.0/cenv0b09a +http://wap.jamba.de/KNet/_KNet-BOC8j1-LFd-13bq0/browse.de/node.0/cde7f1uou +http://cnnews.sina.com/kwongzhou/china/2000/1026/2083022_2.html +http://www.msb.malmo.se/search*swe/dFlygplanskonstruktion/dflygplanskonstruktion/-5,-1,0,B/frameset&F=dflygolyckor&4,,6 +http://home.hanmir.com/~100sun/joo4.htm +http://www.szed.com/szsb/19990629/GB/default.htm +http://www.szed.com/szsb/19990629/GB/4-NPCLASS.HTM +http://www.szed.com/szsb/19990629/GB/7-NPCLASS.HTM +http://www2.kbank.no/Web/nlpublish.nsf/Published/ord_og_uttrykk!OpenDocument&ExpandSection=15,24,26,25 +http://movies.exit.de/lichtsammler/images/tunnel/gross/sw_kb/?D=A +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=5,34,38 +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=21,34,38 +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=31,34,38 +http://fi.egroups.com/login.cgi?login_target=%2Fmessage%2Fgamp%2F1734 +http://de.excite.de/katalog/katalog/9231 +http://www-win.rusf.ru/esli/rubr/books/es0500di.htm +http://www.jamba.de/KNet/_KNet-yjF8j1-8Gd-13cj6/browse.de/node.0/cde7f1uou +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/misc/lit/programs/misc/math/lit/athalie.html +http://ftp.fi.debian.org/debian/dists/Debian2.2r0/contrib/binary-powerpc/interpreters/?S=A +http://jupiter.u-3mrs.fr/~msc41www/releves/04350110.HTM +http://ocean.ntou.edu.tw/search*chi/dDigital+modulation/ddigital+modulation/7,-1,0,E/frameset&F=ddigital+techniques+signal+processing&4,,0 +http://pub20.ezboard.com/fcharmingtailsresourcetradeyoursportscardshere.unsubscribeUnregisteredToTopic?topicID=43.topic +http://www.kaos.dk/sexriddle/x/w/k/u/q/ +http://www.kaos.dk/sexriddle/x/w/k/u/t/ +http://216.205.158.3/smm/programs/CDG_Player/wwwboard/messages/27.html +http://216.205.158.3/smm/programs/CDG_Player/wwwboard/messages/60.html +http://fen.com/whatworks/review/edit/1,2560,1-9696-5539-0-45394,00.html +http://yp.gates96.com/8/74/30/30.html +http://yp.gates96.com/8/74/31/1.html +http://yp.gates96.com/8/74/32/12.html +http://yp.gates96.com/8/74/32/60.html +http://yp.gates96.com/8/74/32/92.html +http://yp.gates96.com/8/74/33/41.html +http://yp.gates96.com/8/74/33/55.html +http://yp.gates96.com/8/74/33/57.html +http://yp.gates96.com/8/74/33/95.html +http://yp.gates96.com/8/74/34/21.html +http://yp.gates96.com/8/74/34/23.html +http://yp.gates96.com/8/74/34/79.html +http://yp.gates96.com/8/74/35/3.html +http://yp.gates96.com/8/74/35/22.html +http://yp.gates96.com/8/74/35/79.html +http://yp.gates96.com/8/74/36/31.html +http://yp.gates96.com/8/74/36/84.html +http://yp.gates96.com/8/74/37/58.html +http://yp.gates96.com/8/74/37/77.html +http://yp.gates96.com/8/74/37/89.html +http://yp.gates96.com/8/74/37/97.html +http://yp.gates96.com/8/74/39/43.html +http://yp.gates96.com/8/74/39/63.html +http://yp.gates96.com/8/74/39/88.html +http://www9.hmv.co.uk:5555/do/session/1347828/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/newmenu.html +http://www9.hmv.co.uk:5555/do/session/1347828/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/departments/d80_sd0_pt0.html +http://gladstone.uoregon.edu/~sme28057/arch181-202/assign2/?M=A +http://cco.cisco.com/univercd/cc/td/doc/product/core/7206/7206ig/trble6ug.pdf +http://210.32.1.18/goldbook/humor/mh/c/changgu/1/028.htm +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=17,28,24,31,11 +http://www.spiral.at/Katalog/Artikel/7561032/ +http://www.crutchfield.com/cgi-bin/S-Ql7dbZlSZa2/viewcart.asp +http://www.fogdog.com/cedroID/ssd3040183327788/nav/products/winter_sports/1b/shell_pants/ +http://www.fogdog.com/cedroID/ssd3040183327788/nav/products/winter_sports/1j/oakley/ +http://www.fogdog.com/cedroID/ssd3040183327788/nav/products/winter_sports/1l/day_packs/ +http://www.thestateofcolorado.com/pglblock.html +http://www.staroriental.net/nav/soeg/ihf,adj,s0,259,Kristy+Yeung+Gung-Yu.html +http://pcmcia.sourceforge.org/cgi-bin/HyperNews/get/pcmcia/toshiba/38.html +http://sunsite.org.uk/public/public/packages/Dr-Fun/df9412/?N=D +http://nt.mortgage101.com/partner-scripts/1144.asp?p=mig&pw=600 +http://biblioteca.upv.es/bib/doc/doc_fisbd/17/87050//C/1828104/3////25/N/MLTPAI +http://130.80.29.3/content/houston/k-12/hanc/ +http://javatest.a-net.nl/exhibits/default.htm +http://javatest.a-net.nl/museum_info/job_opportunities.asp +http://books.hyperlink.co.uk/booklist/Alphabet_Workbook/Cheney/Martha/1565658396 +http://kobe.cool.ne.jp/orera/guestbook.html +http://ftp.eecs.umich.edu/pub/NetBSD/packages/1.4.1/vax/audio/ +http://ftp.eecs.umich.edu/pub/NetBSD/packages/1.4.1/vax/editors/ +http://ftp.eecs.umich.edu/pub/NetBSD/packages/1.4.1/vax/tk80/ +http://www.zdnet.de//news/artikel/1999/03/09001-wc.html +http://neptune.guestworld.com/gear/gateway.cfm?action=private&owner=sitonga7 +http://www.de.lycos.de/dir/Reisen_und_Regionen/L%E4nder_und_St%E4dte/Deutschland/Schleswig-Holstein/St%E4dte_und_Orte/St%E4dte_und_Orte_P_bis_S/ +http://www.mirror.edu.cn/res/sunsite/pub/academic/music/album-reviews/1995/9-September/?M=A +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=213&discrim=176,11,57 +http://europa.eu.int/abc/doc/off/bull/el/9705/x085.htm +http://europa.eu.int/abc/doc/off/bull/el/9705/x209.htm +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=15,0+17,0-3,0-9,0 +http://www.ferien-immobilien.de/baden-wuertemberg/stuttgart/Verkauf/Gemeinsam/MarketingStrategie/Ferien-IB/Startseite/Gemeinsam/Super-Zins-Konditionen/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/indexbeginn.htm +http://www.ferien-immobilien.de/baden-wuertemberg/stuttgart/Verkauf/Gemeinsam/MarketingStrategie/Ferien-IB/Startseite/Gemeinsam/Super-Zins-Konditionen/Gemeinsam/impressum.htm +http://www.chaos.dk/sexriddle/s/e/x/v/i/a/w/ +http://pub4.ezboard.com/fscarletstreethorroritalianstyle.showAddReplyScreenFromWeb?topicID=15.topic +http://ftp.dti.ad.jp/pub/lang/CPAN/authors/id/P/PJ/PJF/ +http://www.highwired.net/Paper/EmailToFriend/1,2102,302-183023,00.html +http://ftpsearch.belnet.be/mirror3/ftp.kde.org/pub/kde/Incoming/Attic/old/1.1.2/apps/ide/?D=A +http://www.affiliate.hpstore.hp.co.uk/do/session/380877/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-creativeworld.com/creativeworld.asp?lang=f +http://expert.cc.purdue.edu/~steinfoc/assignment3/assig3.html +http://www.wyborcza.com/Ascii/Raporty/Filmowa/277rap.html +http://www.redhat.com/mirrors/LDP/LDP/LG/issue50/misc/pollman/?D=A +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=148&discrim=142,11,200 +http://www.marktplatz-hs.de/cgi-bin/ChioEditionShop.s/39fe2ee602379b7e273fd47540f806e1/Catalog +http://www.affiliate.hpstore.hp.co.uk/do/session/380836/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/SMARTTIPS/createbroch.asp +http://joy1.alpha-g.ne.jp/tree/user/a/amuro/2_index.shtml +http://time.188.net/movie/star/taiwan/2/pic/image36.htm +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=25,1,36,31,11 +http://bsd.sinica.edu.tw/cgi-bin/cvsweb.cgi/ports/audio/kdemultimedia11-i18n/Attic/pkg-comment?only_with_tag=RELEASE_2_2_7 +http://www.landfield.com/ftp/usenet/news.answers/bicycles-faq/?S=A +http://wap.jamba.de/KNet/_KNet-puF8j1-aGd-13clg/browse.de/node.0/cenv0b09a +http://www.empas.com/search/all.html?q=%C0%CC%B7%D3%B4%D9 +http://www.linux.com/networking/server/install/howto/website/developers/ +http://aecjobbank.com/texis/script/newjobs/+NwxBm6ev7I1wwwhmrmwxetiAw/jobdirectory.html +http://www.egroups.com/message/ijtihadmk/5 +http://www.egroups.com/message/ijtihadmk/11 +http://www.realize.com/am67bd81.htm,qt=e784fe2f=2a38a234-7-da6e2d-0-0-0-3-- +http://www.realize.com/p643c81.htm,qt=e784fe2f=2a38a234-7-da6e80-0-0-0-3-- +http://moneysaver.net/netcall/?almktng +http://www.agria.hu/bikersmeeting/archivum/talalkozo/foto/taj.cgi?15n +http://link.fastpartner.com/do/session/600401/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/company/ +http://198.103.152.100/search*frc/aDidsbury,+Howard+F.,+1924-/adidsbury+howard+f+1924/-5,-1,0,B/frameset&F=adidier+marcel&1,,0 +http://198.103.152.100/search*frc/aDidsbury,+Howard+F.,+1924-/adidsbury+howard+f+1924/-5,-1,0,B/frameset&F=adidier+michel&1,,0 +http://www.medoc-ias.u-psud.fr:81/synoptic/gif/001020/?D=A +http://shop.goto.com/compperiph/periph/cdrom/search/sidexside.jhtml?s=1&sort_up=LOW_PRICE +http://excite.de/wirtschaft/katalog/1356 +http://excite.de/wirtschaft/katalog/2631 +http://www.areteoutdoors.com/channel/earth/caving/b.89.g.473.html +http://www.areteoutdoors.com/channel/earth/caving/b.91.g.473.html +http://bo.ole.com/actualidad/articulo/html/act13873.htm +http://www.dulux.co.uk/UKRETAIL:446033260:DFinity.1QJiP4jMomdoclfieh +http://www.linux.com/networking/network/release/sap/hardware/firewall/ +http://genforum.genealogy.com/cgi-genforum/forums/hendrix.cgi?430 +http://www.chaos.dk/sexriddle/s/p/w/c/ +http://198.103.152.100/search*frc/tCanada+in+the+21st+century.+II,+Resources+and+technology/tcanada+in+the+21st+century+ii+resources+and+technology/-5,-1,0,B/frameset&F=tcanada+in+the+21st+century+no+01&1,1 +http://books.hyperlink.co.uk/bookinfo/Sunk_Costs_and_Market_Structure/Sutton/John/0262193051 +http://members.tripod.com/theshavedbeaver/site2/s2laststand.html +http://members.tripod.com/theshavedbeaver/site2/s2s1ep21.html +http://www.ytmag.com/cgi-bin/redirect.cgi/602479760 +http://www18.freeweb.ne.jp/school/syodou/you005.htm +http://www.fogdog.com/cedroID/ssd3040183334500/nav/products/featured_brands/2h/replica_jerseys/ +http://www.fogdog.com/cedroID/ssd3040183334500/nav/products/featured_brands/2h/replica_jerseys/4.html +http://www.fogdog.com/cedroID/ssd3040183334500/crs/nvCZ/wld/fogdog_sports/champion/fan_memorabilia/apparel/vlade_divac_replica_jersey.html +http://www.jobvillage.com/channel/jobs/travel/travel_guide/b.4897.g.5299.html +http://www.bcbsal.org/Provider_Dir/pharmacy/state/Oregon/HILLSBORO/index_29061.html +http://www.maas.ccr.it/cgi-win/hiweb.exe/a17/d2066/b77,c,4d,469,469,1b65,1b65,,51,811,4d,51,811,, +http://www.loisirs.ch/bbewxu/2/wofyff.html +http://mitglied.tripod.de/Jag3/jag3b.htm +http://linuxberg.starhub.net.sg/x11html/preview/9016.html +http://linuxberg.starhub.net.sg/x11html/preview/9062.html +http://linuxberg.starhub.net.sg/x11html/preview/9103.html +http://linuxberg.starhub.net.sg/x11html/preview/9820.html +http://linuxberg.starhub.net.sg/x11html/preview/10370.html +http://linuxberg.starhub.net.sg/x11html/preview/9965.html +http://linuxberg.starhub.net.sg/x11html/preview/10117.html +http://linuxberg.starhub.net.sg/x11html/preview/10129.html +http://linuxberg.starhub.net.sg/x11html/preview/10152.html +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=150&discrim=251,11,3 +http://totalsports.aol.com/stats/bbo/int/20000624/tol.at.swb.game.html +http://excite.de/gesundheit/katalog/41575 +http://bbs.csie.ntu.edu.tw/txt/Emprisenovel/ebooks/other/hsiao_yi/jqhy/007.txt +http://www.memorialcup99.com/HockeyStLouisArchive/nov17_stl.html +http://www.letsmusic.com/directory/theme/genre_each/1,1137,Z-ㄴ-124-2-2,00.asp +http://rainforest.parentsplace.com/dialog/get/bedwetting/29/2.html?outline=-1 +http://www.volny.cz/j_medkova/p05.html +http://www.maas.ccr.it/cgi-win/hiweb.exe/a17/d2072/b77,c,4d,51,51,815,815,818,7d9,,51,7d9,818,, +http://collection.nlc-bnc.ca/100/200/301/ccmd-ccg/ccmd_report-e/rpt1e.pdf +http://cn.egroups.com/post/export-import-indonesia?act=forward&messageNum=595 +http://www.secinfo.com/$/SEC/Filing.asp?T=1zBgb.6t_9yc +http://www.realize.com/am81.htm,qt=4619dc8c=279e650e-c-16fba7d-1-0-0-0-- +http://amadeus.siba.fi/doc/php3-ldap/html/features.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.ada-fetchrow.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.array-pop.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.current.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.ftp-size.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.getmyinode.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.gmdate.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.hw-getusername.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.icap-list-alarms.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.ifx-free-char.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.imap-reopen.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.is-link.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.is-string.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.mcal-event-set-recur-monthly-wday.html +http://amadeus.siba.fi/doc/php3-ldap/html/function.mhash-get-block-size.html +http://wwws.br-online.de/geld/boerse/980420/110001.html +http://family.go.com/Categories/reviews/Features/family_2000_01/dony/dony0100craftapple/ +http://family.go.com/Categories/reviews/Features/family_2000_01/dony/dony0100craftcactus/ +http://family.go.com/Categories/reviews/Features/family_2000_01/dony/dony0100petvetticks/ +http://www.maastrek.de/maas/d49da6854db9e797f212/1/0/1 +http://astro1.chungnam.ac.kr/NetBBS/Bbs.dll/astromov/lst/qqadm/1/zka/B2-kB2Bl/qqo/004D +http://channel.cnnsi.com/basketball/college/2000/ncaa_tourney/west/news/2000/03/25/keady_ap/lg_keady_ap.html +http://incmagazine.com/articles/details/0,3532,AGD5_ART13806_CNT56_GDE30,00.html +http://incmagazine.com/research/details/0,3470,AGD5_CNT49_GDE30_RSC16754,00.html +http://gatekeeper.dec.com/pub/linux/lorax/i386/misc/src/anaconda/balkan/CVS/ +http://adex3.flycast.com/server/socket/127.0.0.1:2800/click/OnlineCitiesSM/OnlineCitiesInteractiveCityGuides/bd720350329 +http://www.proviser.co.uk/regional/towns/alford/street_maps/alpha_b.html +http://www.fogdog.com/cedroID/ssd3040183255203/ +http://www.columbia.edu/~wl158/OCD.htm +http://www.irishnews.com/Archive2000/29052000/international.html +http://www.irishnews.com/Archive2000/29052000/sportinter.html +http://38scbshop.freeyellow.com/download.html +http://news.dinf.ne.jp/news/fj/rec/animation/msg01441.html +http://datastore.tucows.com/winnt/adnload/5372_28388.html +http://pages.infinit.net/limal/visage/chap17.htm +http://www.hotelboulevard.com/fr/paris/standard/htmlc258073cfbe254c1722c86e0aec5f5da/sessionLang/ANG/search.html +http://www.icopyright.com/1.1642.213678 +http://wiem.onet.pl/wiem/012aa2.html +http://www.secinfo.com/dRRsz.9e.htm +http://lily.nju.edu.cn/literature/cangshu/wx/wra/ysz/16.htm +http://home.swipnet.se/~w-15978/ +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www.stanford.edu/dept/EIS/moral_responsibility.htm +http://smb.slac.stanford.edu/cgi-bin/nph-proxy.cgi/000/http/www.stanford.edu/dept/EIS/hardin_review.htm +http://www.uni-duesseldorf.de/ftp/pf/share/flex-2.5.2/man/man1/?S=A +http://mindit.netmind.com/proxy/http://www.ninds.nih.gov/health_and_medical/pubs/chronic_pain_htr.htm +http://mindit.netmind.com/proxy/http://www.smalltime.com/notvictims/cutting.html +http://www.peopledaily.co.jp/zdxw/7/19991231/19991231001085.html +http://pokemonothin.8m.com/cgi-bin/c/736/64/dXNlcmJhbm5lcg==/gn/4638/ +http://www.chaos.dk/sexriddle/s/e/x/u/y/n/d/ +http://www.bestinfo.net.cn/bsti_kjhy/kyys/bjkyys/arim/technical.html +http://www.leicos.de/webguides/fun_lifestyle/unterhaltung/43101.html +http://209.207.239.212/bkindex/c1047/f1423.html +http://cylis.lib.cycu.edu.tw/search*chi/tEncyclopaedia+of+mathematical+sciences+&%2359%3B+v.+65/tencyclopaedia+of+mathematical+sciences+v+++65/-17,-1,0,B/frameset&F=tencyclopaedia+of+mathematical+sciences+v+++48&1,1 +http://www.sanxia.net/beauty/Nanako/313.htm +http://www.sanxia.net/beauty/Nanako/323.htm +http://mirrortucows.technet.it/winme/adnload/138469_29790.html +http://www.fogdog.com/cedroID/ssd3040183321970/nav/stores/walking/ +http://www.fogdog.com/cedroID/ssd3040183321970/customer_service/employment.html +http://mirror.pku.edu.cn/www.berkeley.edu/ls.berkeley.edu/lscr/services/backups/UCBackup.html +http://retailer.gocollect.com/do/session/1912804/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/postcards/index.asp +http://www.uni-duesseldorf.de/ftp/pf/share/ddd-1.4d/man/man1/?M=A +http://www.uni-duesseldorf.de/ftp/pf/share/ddd-1.4d/man/man1/?S=A +http://javatest.a-net.nl/servlet/pedit.Main/http://www.zdnet.com/special/stories/wireless/0,10676,2557092-8,00.html +http://ftp.sunet.se/pub/os/FreeBSD/development/FreeBSD-CVS/ports/archivers/makeself/ +http://www.jamba.nl/KNet/_KNet-QYL8j1-2D4-pw4k/browse.nl/node.0/cde7f1uou +http://www.discoveromaha.com/shared/health/adam/ency/imagepage/1090.000233.html +http://home.dqt.com.cn/cgi-bin/push/setluntan?luntan=64 +http://sjsulib1.sjsu.edu:81/search/dbusiness+periodicals/-5,-1,1,B/frameset&dbusiness+vocational+guidance&2,,3 +http://www-d0.fnal.gov/d0dist/dist/releases/psim01.01.00/cft_tuple/VERSION +http://pub3.ezboard.com/fmcdonaldscollectorsclubauctions.subscribeUnregisteredToTopic?topicID=136.topic +http://shopping.lycos.co.kr/cgi-bin/LCWB.cgi/957424027/957522583/Catalog/1301/001 +http://www.cs.kuleuven.ac.be/~java/docs/jdk1.3/docs/api/java/sql/class-use/DriverPropertyInfo.html +http://www.buybuddy.com/sleuth/27/1/1060701/505427/ +http://web4.sportsline.com/u/football/nfl/players/splits/4451_split.htm +http://mirror.cc.utsunomiya-u.ac.jp/mirror/FreeBSD/ports/alpha/packages-5-current/japanese/?M=A +http://no.egroups.com/login.cgi?login_target=%2Fgroup%2Ftkd-full +http://www.bemi-immobilien.de/Ferien-IB/Startseite/Gemeinsam/MarketingStrategie/Gemeinsam/immolink/Gemeinsam/3d-service/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/MarketingStrategie/Strategie.htm +http://www.bemi-immobilien.de/Ferien-IB/Startseite/Gemeinsam/MarketingStrategie/Gemeinsam/immolink/Gemeinsam/3d-service/Startseite/www.ferien-immobilien.de/ferien-ib/startseite/Gemeinsam/versicherungen/gebaeude/deckungsumfang.htm +http://www.3wposter.com/czaja/czj2002.htm +http://pub19.ezboard.com/fallamericanbaseballleagueplayersneeded.showMessage?topicID=6.topic +http://ftp.uni-mannheim.de/info/OReilly/nutshell/practcpp/disk/doit/?N=D +http://www02.geocities.co.jp/HeartLand-Kaede/4970/index2.htm +http://www.selbstmachen.de/shops/pop/infotext/8008.htm +http://dennou-t.ms.u-tokyo.ac.jp/arch/cc-env/Linux/debian-jp/dists/unstable/contrib-jp/binary-alpha/doc/?D=A +http://genforum.genealogy.com/cgi-genforum/forums/flynn.cgi?1004 +http://www.iwon.com/home/movies/movies_filmography_page/0,13178,Marguerite+Hickey,00.html +http://cometweb01.comet.co.uk/do!tid=20&rtid=2&vsid=700&session=132028&mid=1000&rid=1060&cid=37030&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG5ubLZDXLZolLl3l5jbqLlci5XqVLkXsLkao4tloHbmlLoq5 +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus65300/eus65303/eus77824/eus541028/eus168664/ +http://user.chollian.net/~iipuni/pds1/?M=A +http://tucows.ciaoweb.it/winnt/adnload/73935_29937.html +http://home2.keyciti.com/x2001/ +http://www.amateurplatinum.com/teenagerclique/fagbodyshots/elbow-greaseac/plus-sizemen/butt-fuckpartner/actionextreme/hitting-itendurance.html +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux-2.3-4/linux/Documentation/filesystems/vfs.txt?only_with_tag=LINUX-2_3_99_pre4 +http://oss.sgi.com/cgi-bin/cvsweb.cgi/linux-2.3-4/linux/Documentation/filesystems/vfs.txt?only_with_tag=LINUX-2_3_17 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+18,0-0,0-3,0 +http://www.skaninforma.no/nord-troendelag/leksvik-h.htm +http://194.128.65.4/pa/cm199798/cmwib/wb971115/nil.htm +http://www.on.fuchu.or.jp/~oimatudo/englishmisomanzyu.htm +http://map.ipc.co.jp/asp/onmap/connect/g-2/a-719/ +http://cherokee1.edgate.com/goucheres/ed_current.html +http://www.online.kokusai.co.jp/Service/V0043594/wrd/G200/service/service.html +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=21,16,7 +http://binary.tucows.com/winnt/adnload/70807_30160.html +http://binary.tucows.com/winnt/adnload/1422_28846.html +http://genforum.genealogy.com/cgi-genforum/forums/theroux.cgi?69 +http://rex.skyline.net/navigate.cgi?news,ice,women,resources,living +http://umweb2.unitedmedia.com/creators/rugrats/archive/rugrats-20001015.html +http://retailer.gocollect.com/do/session/1912824/vsid/2089/tid/2089/cid/621609/mid/1540/rid/1520/chid/2083/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLlmo5larLZqVLafpLmiXLvlmHolaLrZqLpl4/url/http://www.gocollect.com/product_display/products/product_lines.asp +http://retailer.gocollect.com/do/session/1912824/vsid/2089/tid/2089/cid/621609/mid/1540/rid/1520/chid/2083/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLlmo5larLZqVLafpLmiXLvlmHolaLrZqLpl4/url/http://www.gocollect.com/clubhouse/suggestions.asp +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=146&discrim=146,7,19 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=146&discrim=146,7,231 +http://login.hq.cricinfo.org/link_to_database/ARCHIVE/1996-97/OD_TOURNEYS/SINWS/SINWS-MATCHES/SL_ZIM_SINWS_ODI5_03SEP1996_DAILY_MR.html +http://preview.egroups.com/group/God_Calling +http://www.fogdog.com/cedroID/ssd3040183340945/nav/products/outlet/1b/sunglasses_optics/ +http://www.fogdog.com/cedroID/ssd3040183340945/nav/products/outlet/1c/dc/ +http://www.fogdog.com/cedroID/ssd3040183340945/customer_service/contact_us.html +http://link.fastpartner.com/do/session/600424/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/itjobbank.php +http://link.fastpartner.com/do/session/600424/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/index.php +http://pub2.ezboard.com/fteamnexgenforumhelpnexgennexencodestudio.unsubscribeUnregisteredToTopic?topicID=29.topic +http://www02.geocities.co.jp/SiliconValley-PaloAlto/1763/event/ni2k/ni2k.htm +http://yp.gates96.com/7/89/60/35.html +http://yp.gates96.com/7/89/61/4.html +http://yp.gates96.com/7/89/61/38.html +http://yp.gates96.com/7/89/62/80.html +http://yp.gates96.com/7/89/63/8.html +http://yp.gates96.com/7/89/63/16.html +http://yp.gates96.com/7/89/65/10.html +http://yp.gates96.com/7/89/65/42.html +http://yp.gates96.com/7/89/65/54.html +http://yp.gates96.com/7/89/65/88.html +http://yp.gates96.com/7/89/65/98.html +http://yp.gates96.com/7/89/66/26.html +http://yp.gates96.com/7/89/66/55.html +http://yp.gates96.com/7/89/67/28.html +http://yp.gates96.com/7/89/68/67.html +http://yp.gates96.com/7/89/69/63.html +http://yp.gates96.com/7/89/69/73.html +http://www.mediko.de/news/alt.support.eating-disord/19944.html +http://www.mediko.de/news/alt.support.eating-disord/19975.html +http://www13.cplaza.ne.jp/musicnavi/i-mode/id/KICS113.html +http://home.beseen.com/community/alienpilot/AbductionTheory.html +http://www.hausbau-finder.de/festpreis/anbieter/A11/A11_05_eg.htm +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=237&discrim=10,15,200 +http://ftp.eecs.umich.edu/pub/NetBSD/packages/1.3.3/mac68k/kde/ +http://www.leg.wa.gov/pub/rcw%20-%20text/title_49/chapter_028/rcw_49_28_065.txt +http://fi.egroups.com/login.cgi?login_target=%2Fmessages%2Fdfbl%2F77 +http://ring.omp.ad.jp/pub/NetBSD/NetBSD-current/src/sys/arch/sgimips/dev/?D=A +http://retailer.gocollect.com/do/session/1912781/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/postcards/index.asp +http://providenet.tucows.com/win2k/adnload/136128_47180.html +http://providenet.tucows.com/win2k/adnload/38527_29571.html +http://no.egroups.com/dir/1/16/476/32069/32291/104313/293356 +http://www.playease.com/et/beauty/img/lingmuyamei/lmam043.htm +http://202.99.23.201/gb/special/node_484.htm +http://202.99.23.201/gb/special/node_518.htm +http://202.99.23.201/gb/special/node_531.htm +http://ring.jec.ad.jp/archives/NetBSD/NetBSD-current/pkgsrc/fonts/acroread-chsfont/README.html +http://www.gaiax.com/~dengeki/lineb.html?haru_da_pump +http://cafe2.daum.net/Cafe-bin/Bbs.cgi/naturalproductspds/qry/zka/B2-kB27p/qqatt/^ +http://cafe2.daum.net/Cafe-bin/Bbs.cgi/naturalproductspds/qry/zka/B2-kB23t/qqatt/^ +http://cafe2.daum.net/Cafe-bin/Bbs.cgi/naturalproductspds/qry/zka/B2-kB23r/qqatt/^ +http://my.egroups.com/group/uk-mac-dev +http://www.f20.parsimony.net/forum35990/archiv.htm +http://findmail.com/group/Costumers +http://variety.studiostore.com/browse/PEOPLE/b.FAVORITES%20PEOPLE/s.ZaC1r6Q6 +http://www.chinawolf.com/~warson/japan/chichuan/cat/jiangzuo/020.htm +http://www.branchen-vermittler.de/Branchen/Mecklenburg/Mecklenburg_Region_3/Neustrelitz/kopf_neustrelitz.html +http://www.xmission.com/(art,ftp,geek,music,music,caffiene,art,toys,dots,edge,misc,shopping,ftp,places,privacy,geek,cuseeme,apocalypse,people,stuffiuse,places,privacy,stuffiuse)/~bill/links.html +http://www.cs.helsinki.fi/linux/linux-kernel/Year-1999/1999-49/1283.html +http://www.ecotec.co.jp/view/arc/f/free/33/umcotk/zxlqox.html +http://www.ecotec.co.jp/view/arc/f/free/33/tgiotk/uftfwm.html +http://www.ecotec.co.jp/view/arc/f/free/33/purotk/qxxotk.html +http://www.ecotec.co.jp/view/arc/f/free/33/purotk/sewotk.html +http://www.ecotec.co.jp/view/arc/f/free/33/purotk/sjkfwm.html +http://www.ecotec.co.jp/view/arc/f/free/33/hazfwm/llhetk.html +http://www.ecotec.co.jp/view/arc/f/free/33/bvtctk/eptrik.html +http://www.ecotec.co.jp/view/arc/f/free/33/rvkptk/syurzz.html +http://library.cuhk.edu.hk/search*chi/a��頦��哨蕭嚙賢��鞈�嚙踝���+1934-/a{214b33}{213021}{214451}+1934/-5,-1,0,B/frameset&F=a{214b33}{213021}{213c63}&6,,7 +http://mitglied.tripod.de/~haubentaucher/bilder.htm +http://amc.hollywood.com/maltin/v/valleyofthekings-1954.htm +http://amc.hollywood.com/maltin/v/vannuysblvd-1979.htm +http://amc.hollywood.com/maltin/v/venicevenice-1992.htm +http://amc.hollywood.com/maltin/v/vicesquad-1931.htm +http://amc.hollywood.com/maltin/v/violette-1978.htm +http://amc.hollywood.com/maltin/v/voiceofthewhistler-1945.htm +http://amc.hollywood.com/maltin/v/vulturethe-1967.htm +http://members.tripod.co.jp/hatahata/hikoki/?D=A +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/SaveCounter/2000-10-23/07/972255822718.txt +http://www.mapion.co.jp/custom/AOL/admi/23/23105/matsubaracho/5chome/index-43.html +http://search.chollian.net/cgi-bin/filter.cgi?cid=1109&g=11 +http://search.chollian.net/cgi-bin/filter.cgi?cid=1109&p=5 +http://www.linux.com/networking/network/new/website/applications/business/ +http://www.fogdog.com/cedroID/ssd3040183313598/nav/products/w_golf/1s/ball_retrievers/ +http://www.fogdog.com/cedroID/ssd3040183313598/nav/products/w_golf/1t/biographical_books/ +http://rammstein.sonicnet.com/artists/news/1090.jhtml +http://rammstein.sonicnet.com/allmusic/ai_bio.jhtml?ai_id=1090 +http://www.ycwb.com.cn/gb/2000/08/18/ycwb/gnxw/7.html +http://www.vorlesungen.uni-osnabrueck.de/informatik/c98/code/19/?D=A +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/SaveCounter/2000-10-23/11/972270515716.txt +http://www.affiliate.hpstore.hp.co.uk/do/session/380869/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/entry1.asp +http://uk.biz.yahoo.com/mutual_funds/micropal/lf/fund/008776/properf.html +http://troy.lib.sfu.ca/search/aasociacion+argentina+de+ciencias+naturales/aasociacion+argentina+de+ciencias+naturales/-5,-1,0,E/frameset&F=aasociacion+argentina+de+ciencias+naturales&1,,0 +http://uk.dir.yahoo.com/Regional/U_S__States/Virginia/Metropolitan_Areas/Charlottesville_Metro/Travel_and_Transportation/Accommodation/Caravan_Parks_and_Camp_Sites/ +http://uk.dir.yahoo.com/Regional/U_S__States/Virginia/Metropolitan_Areas/Charlottesville_Metro/Travel_and_Transportation/Accommodation/Hotels/ +http://library.cwu.edu/search/cQA76.73.A35+T75/cqa+++76.73+a35+t75/-5,-1,0,B/marc&F=cqa+++76.73+a8+j33+1985&1,1, +http://www.tages-anzeiger.ch/sport/nagano/0902/olymp_art4.htm +http://finance.sina.com.cn/globe/globe/2000-03-16/23725.html +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,3-9,0+0,1-0,3 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,3-9,0+0,1-9,3 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,3-9,0+0,1-19,0 +http://temps-libre.promovacances.net/D02/BH/BDANE/voyagealacarte.htm +http://sunsite.org.uk/public/computing/networks/internet/ietf/98aug/imapext-attendees-98aug.txt +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=124&discrim=221,178 +http://cpan.nettuno.it/authors/Ilya_Zakharevich/modules/FreezeThaw-0.41.readme +http://cpan.nettuno.it/authors/Ilya_Zakharevich/modules/Math-Pari-2.001700.readme +http://ricoh.co.jp/SHOGI/emate/tanigawa/tume0069a.html +http://troy.lib.sfu.ca/search/dlatin+america+periodicals/dlatin+america+periodicals/-5,-1,0,B/marc&F=dlatin+america+pest+control+industry&1,1, +http://moviestore.zap2it.com/browse/MOVIES/COLLECTI/s.w2bwHPkr +http://moviestore.zap2it.com/browse/MOVIES/BUNDLE/s.w2bwHPkr +http://moviestore.zap2it.com/browse/MOVIES/BOWL/s.w2bwHPkr +http://moviestore.zap2it.com/browse/MOVIES/JEWELRY/s.w2bwHPkr +http://moviestore.zap2it.com/browse/MOVIES/COMIC/s.w2bwHPkr +http://www9.hmv.co.uk:5555/do/session/1347801/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/Top_Navigation_Bar/top_banner.html +http://www3.adobe.com/type/browser/F/P_103/F_FRAK-70005000.html +http://ftp.netc.pt/pub/idgames/levels/doom2/deathmatch/j-l/kewl.txt +http://ftp.netc.pt/pub/idgames/levels/doom2/deathmatch/j-l/ledges-z.txt +http://park.org:8888/Japan/CSK/hyakki/zukan/turezure/ue/c_tirizuka.html +http://pub4.ezboard.com/fscarletstreetfilmmusic.unsubscribeUnregisteredToTopic?topicID=54.topic +http://tucows.niagara.com/win2k/adnload/37364_29149.html +http://wap.jamba.de/KNet/_KNet-JGG8j1-eGd-13cre/showInfo-special1.de/node.0/cde7f1uou +http://www.personalmd.com/news/n0706062122.shtml +http://ds.dial.pipex.com/tmc/ConfPresentations/s2000/NetworkingJ/msconfig.htm +http://calcul.si.uji.es/Programes/SAS/proc/z0325264.htm +http://www.kaos.dk/sexriddle/x/m/k/i/i/ +http://ring.toyama-ix.net/archives/lang/perl/CPAN/clpa/1998-08/?N=D +http://ring.toyama-ix.net/archives/lang/perl/CPAN/clpa/1998-08/?S=A +http://www.spiral.at/Katalog/Artikel/0879070/ +http://homepage1.nifty.com/nao~nao/pages/profile.html +http://www.ferien-immobilien.de/friesland/verkauf/Gemeinsam/Inserieren/Allgemeine-IB/3d-service/Allgemeine-IB/Startseite/ +http://www.ferien-immobilien.de/friesland/verkauf/Gemeinsam/Inserieren/Allgemeine-IB/3d-service/Gemeinsam/erreichenPartner/email3d.htm +http://www.thestateofcolorado.com/m1jerepair.html +http://www.legis.state.pa.us/WU01/LI/BI/TI/1989/0/MNTENNIS.HTM +http://www.legis.state.pa.us/WU01/LI/BI/TI/1989/0/MNTRASH.HTM +http://www.shop4magazines.com/pg004752.htm +http://www.shop4magazines.com/pg005070.htm +http://www.shop4magazines.com/pg005084.htm +http://fi.egroups.com/login.cgi?login_target=%2Fmessage%2Fsocalscan%2F5293 +http://www.incestpornstories.com/hot-hardcore-fuckingbanging/bootsfeet-/hitting-itsmacking/{hardcorelink} +http://www.columbia.edu/~mkn12/Nominees.html +http://www.generation-formation.fr/pdetail.htm---o21zAo06Rxo0Ol9A074fo6s0Md6jIHeNHhIeOkn2ApvFFo6s5dfexiWo2W81N3OsPeaR2VeuzlEdRsR3djaPfdNjfco41qrfP6sWd6wuCoz4ZteOgKHekLVSePl8vNhiWhAhcgNAPfVbdsNhJl.htm +http://tiscover.at/1Root/Kontinent/6/Staat/7/Bundesland/20/Ort/212/Sonstige_Sportstaette/276591/Bericht/berw...1.html +http://fi.egroups.com/message/meterreader/207?source=1 +http://polygraph.ircache.net:8181/services/design/http_-2www.arthritis.org/http_-2www.alameda-vcf.org/http_-2www.microsoft.com/ie/ie.htm +http://www.fortunecity.com/lavender/deathrace/251/billy.html +http://ftpsearch.belnet.be/packages/CPAN/modules/by-module/AppleII/?N=D +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=7,34,29,16,25 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=21,34,29,16,25 +http://www.ftp.uni-erlangen.de/pub/unix/BSD/FreeBSD/FreeBSD-current/ports/irc/tirc/ +http://retailer.gocollect.com/do/session/1912840/vsid/1696/tid/1696/cid/604361/mid/1540/rid/1420/chid/1725/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLlmo5larLZqVLafpLmiXLvlmHolaLrZqLpl4/url/http://www.gocollect.com/company_info/about.asp +http://retailer.gocollect.com/do/session/1912840/vsid/1696/tid/1696/cid/604361/mid/1540/rid/1420/chid/1725/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLlmo5larLZqVLafpLmiXLvlmHolaLrZqLpl4/url/http://www.gocollect.com/company_info/terms_and_conditions.asp +http://businessrecorder.com/story/S0024/S2401/S2401113.htm +http://arabia.com/article/0,1690,Sports|20732,00.html +http://www.worldmedicus.com/servlet/Controller/$7006041629a50000.sj_viewa/ +http://myhome.naver.com/chocobini/company.html +http://builder.hw.net/frmMessageFront/1,1079,'1~21~0~8~1~2348~9590',00.html +http://pub1.ezboard.com/fcrossstitchcorner504212000shepherdsbushretreat.showAddReplyScreenFromWeb?topicID=48.topic&index=5 +http://www.parisnights.de/fanfiction/archive/authors/andrews/stories/bright.htm +http://198.103.152.100/search*frc/cCA1+MPR+NS51+98Y25/cca1+mpr+ns51+98y25/7,-1,0,E/2browse +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus51605/eus147927/eus269761/eus269920/eus918452/ +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus51605/eus147927/eus269761/eus269920/eus918493/ +http://www.computing.net/cgi-bin/report.pl/windows95/wwwboard/forum/3119.html|21 +http://www.kiarchive.ru:8093/pub/misc/books/Camelot/Vasilyev/Forgotten_Road/ +http://yp.gates96.com/4/9/50/30.html +http://yp.gates96.com/4/9/51/1.html +http://yp.gates96.com/4/9/51/88.html +http://yp.gates96.com/4/9/51/92.html +http://yp.gates96.com/4/9/52/3.html +http://yp.gates96.com/4/9/52/53.html +http://yp.gates96.com/4/9/52/67.html +http://yp.gates96.com/4/9/53/25.html +http://yp.gates96.com/4/9/53/50.html +http://yp.gates96.com/4/9/53/96.html +http://yp.gates96.com/4/9/54/40.html +http://yp.gates96.com/4/9/54/57.html +http://yp.gates96.com/4/9/54/77.html +http://yp.gates96.com/4/9/55/57.html +http://yp.gates96.com/4/9/55/71.html +http://yp.gates96.com/4/9/56/1.html +http://yp.gates96.com/4/9/56/98.html +http://yp.gates96.com/4/9/57/6.html +http://yp.gates96.com/4/9/57/90.html +http://yp.gates96.com/4/9/58/91.html +http://yp.gates96.com/4/9/58/96.html +http://yp.gates96.com/4/9/59/29.html +http://yp.gates96.com/4/9/59/33.html +http://yp.gates96.com/4/9/59/84.html +http://yp.gates96.com/4/9/59/97.html +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/151/1997/5/0/900308/ +http://www2.odn.ne.jp/~cao20970/affair/oh/ha-342 +http://www2.odn.ne.jp/~cao20970/affair/oh/ha-346 +http://wap.jamba.de/KNet/_KNet-lvH8j1-nGd-13d1j/browse.de/node.0/cdzqggtyb +http://www.danielwebster.org//hallofusa/thestampact/HENDRICKFISHER.COM//thestampact/ +http://news.cn.tom.com/maya/cnnav/01/item/2000_09/309490.shtml +http://polygraph.ircache.net:8181/services/design/http_-2www.paducahrotary.org/pbcmap.htm +http://polygraph.ircache.net:8181/services/design/http_-2www.paducahrotary.org/mainpage.htm +http://www.debian.org.cn/Bugs/db/23/23547.html +http://www.debian.org.cn/Bugs/db/54/54172.html +http://www.adetti.iscte.pt/ADETTI/Security/HowTo/Java/jdk1.2.1/docs/guide/beans/spec/beancontext.fm7.html +http://www.users.qwest.net/~campputz/page413.htm +http://flybird.soyou.edu.cn/item/2000-07-31/164671.html +http://www.cognigen.net/corporate/trainers.cgi?full-timer +http://www.babyheirlooms.com/catalog/htmlos.cat/041143.1.1156359481 +http://ramdam.com/art/k/katerine.htm +http://ramdam.com/art/k/krapulax.htm +http://aleph.tau.ac.il:4501/ALEPH/eng/ATA/AAM/AAM/SET-MAIL///1249009 +http://online.linux.tucows.com/conhtml/adnload/8973_2294.html +http://www.arrakis.es/~lady_cel/frcontenf.htm +http://online.linux.tucows.com/conhtml/adnload/39034_1349.html +http://online.linux.tucows.com/conhtml/adnload/51651_2248.html +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=23,0+14,0-13,0-13,0 +http://www.ferien-immobilien.de/Westerwald/verkauf/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/Gemeinsam/Inserieren/Private-IB/Gemeinsam/suche.htm +http://www.linux.com/networking/network/it/alternative/developers/Apple/ +http://www.sanxia.net/beauty/Nanako/418.htm +http://www-usa8.cricket.org/link_to_database/ARCHIVE/1999-2000/OTHERS+ICC/NORTHANTS_IN_WI/ARTICLES/ +http://gds.cc.va.us:8888/Mcn%3dMELISSA%20BACK,%20ou%3dSV.CC.VA.US,%20ou%3dFaculty%20%26%20Staff,%20o%3dvccs,%20c%3dUS +http://www.allgemeine-immobilien-boerse.de/nordrhein-Westfalen/luedinghausen/Verkauf/Ferien-IB/Startseite/Gemeinsam/erreichenPartner/Versteigerungen-IB/Startseite/IIM-Teil/Startseite/froben.htm +http://198.103.152.100/search*frc/dIndustrial+relations+--+Germany+(West)+--+History/dindustrial+relations+germany+west+history/-5,-1,0,B/frameset&F=dindustrial+relations+germany+dictionaries&1,,0 +http://secure.danysoft.com/asp/dany.tienda/892496425/Catalog +http://yp.gates96.com/13/57/90/23.html +http://yp.gates96.com/13/57/90/91.html +http://yp.gates96.com/13/57/91/68.html +http://yp.gates96.com/13/57/92/22.html +http://yp.gates96.com/13/57/92/49.html +http://yp.gates96.com/13/57/92/73.html +http://yp.gates96.com/13/57/93/75.html +http://yp.gates96.com/13/57/94/16.html +http://yp.gates96.com/13/57/94/62.html +http://yp.gates96.com/13/57/94/99.html +http://yp.gates96.com/13/57/95/19.html +http://yp.gates96.com/13/57/95/34.html +http://yp.gates96.com/13/57/95/84.html +http://yp.gates96.com/13/57/96/22.html +http://yp.gates96.com/13/57/96/24.html +http://yp.gates96.com/13/57/96/52.html +http://yp.gates96.com/13/57/96/70.html +http://yp.gates96.com/13/57/97/39.html +http://yp.gates96.com/13/57/97/55.html +http://yp.gates96.com/13/57/98/4.html +http://yp.gates96.com/13/57/98/41.html +http://yp.gates96.com/13/57/98/58.html +http://yp.gates96.com/13/57/98/98.html +http://yp.gates96.com/13/57/98/99.html +http://yp.gates96.com/13/57/99/79.html +http://carriage.de/Schoner/Info-d/history/literature/literature/ +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/lit/computers/misc/unitest/misc/computers/programs/simple/simple.html +http://kwic.tucows.com/partners/flyswat/get_acx.html +http://sp201.unige.ch:49213/cxxdoc/ioc/concepts/c2g2rcsm.htm +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=0,2-0,1-21,0+9,1 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=237&discrim=10,2,183 +http://firstweb.tucows.com/win2k/adnload/58783_28760.html +http://www.boerseninfos.de/dynamic/ak/mk/news/719350-20000830-104827.html +http://baseball.mainichi.co.jp/life/family/syuppan/wakaru/wakaru-j/10/01/01.html +http://helios.nlib.ee/search*est/dsÃĩjalised+blokid/dsw~ajalised+blokid/-5,-1,0,B/exact&F=dsw~ajalised+konfliktid&1,58/limit +http://helios.nlib.ee/search*est/dsÃĩjalised+blokid/dsw~ajalised+blokid/-5,-1,0,B/frameset&F=dsw~ajalised+konfliktid&11,,58 +http://lexicon.linux.tucows.com/conhtml/adnload/8642_2088.html +http://ua.php.net/manual/es/function.pg-fieldisnull.php +http://www.babyheirlooms.com/catalog/htmlos.cat/041132.1.4352706945 +http://www.civila.com/guitar/chat/desenredada/juegos/ +http://sunsite.org.uk/public/pub/packages/info-mac/pilot/?N=D +http://www.aelita.net/products/products/support/news/Reg/Subscribe/company/contact/default.htm +http://cn.egroups.com/message/newsclips/295 +http://www.jornada.unam.mx/2000/sep00/000922/oriente-y.htm +http://members.tripod.co.jp/mosokke/dubair01ghe.html +http://202.99.23.245/zdxw/21/20000217/200002172112.html +http://link.fastpartner.com/do/session/600412/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/speednames.php +http://link.fastpartner.com/do/session/600412/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/nordicliving.php +http://link.fastpartner.com/do/session/600412/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/local/redirect.php +http://iant.subportal.com/sn/Utilities/System_Maintenance_and_Repair_Utilities/2128.html +http://polygraph.ircache.net:8181/client/http_-2www.scubaring.com/http_-2www.aaainvestments.com/http_-2www.primenet.com/~stmmoon/stmbik.html +http://itcareers.careercast.com/texis/it/itjs/+wwwBme89D86qxwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewGtmoBGnaqdGpdGwBodDanDtoDnnGaMw55wqr15nBB5aoDhdGMwBodDa5nq1GoBOaDnBidGAapGdBdqdc5aGn31oGnmanLpnGonDqnaMFqhTfR20DzmehrwwwpBme26D86eSqwww5rmePdwwwBrmeZpwww/morelike.html +http://itcareers.careercast.com/texis/it/itjs/+awwBme3AT+6ezqwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewGtmoBGnaqdGpdGwBodDanDtoDnnGaMw55wqr15nBB5aoDhdGMwBodDa5nq1GoBOaDnBidGAapGdBdqdc5aGn31oGnmanLpnGonDqnaMFqhTfR20DzmehrwwwpBme26D86eSqwww5rmeEdwwwBrmeZpwww/jobpage.html +http://itcareers.careercast.com/texis/it/itjs/+vwwBme26D86eSqwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewGtmoBGnaqdGpdGwBodDanDtoDnnGaMw55wqr15nBB5aoDhdGMwBodDa5nq1GoBOaDnBidGAapGdBdqdc5aGn31oGnmanLpnGonDqnaMFqhTfR20DzmehrwwwpBme26D86eSqwwwGzmwwww5rmeEdwwwBrmeZpwww/morelike.html +http://www.starcities.com/usa/ca/carlsbad/ +http://www.3w-geschichten.de/PlumptreGeorge/PlumptreGeorge1857938461.htm +http://residence.educities.edu.tw/goyen/ +http://polygraph.ircache.net:8181/http_-2www.whowhere.com/http_-2www.primenet.com/~mmfact/http_-2www.microsoft.com/ie/download/ +http://polygraph.ircache.net:8181/http_-2www.whowhere.com/http_-2www.primenet.com/~mmfact/http_-2www.infohwy.com/odframes.html +http://www.linux.com/networking/network/management/industry/internet/services/ +http://cn.egroups.com/message/ruosulista/1176 +http://ftp.jp.debian.org/debian/dists/unstable/main/binary-i386/tex/?M=A +http://de.excite.de/bildung/katalog/17722 +http://de.excite.de/bildung/katalog/17893 +http://de.excite.de/bildung/katalog/17879 +http://www.emerchandise.com/browse/BUFFYTHEVAMP/PIN/b.TV%20BUFFYTHEVAMP/s.Xpiu5LCZ +http://variety.studiostore.com/browse/VARIETY/CAMERA/s.dmZspziz +http://carriage.de/Schoner/Sammlungen/models/info-e/Info-d/ +http://www.gazeta.com/Iso/Plus/Kraj/Prezyden/Ak/700kwa.html +http://www.linux.com/networking/network/networking/developers/operating_system/Debian/ +http://online.linux.tucows.com/conhtml/adnload/8808_32695.html +http://149.221.91.10/news/lokales/wermelskirchen/ +http://opac.lib.rpi.edu/search/avirgin+vision+limited/7,-1,0,B/frameset&avirginia+cooperative+fisheries+research+unit&1,1 +http://www.emerchandise.com/browse/DISNEY-FAM/ACTIONFI/b.FAVORITES%20KIDSSTUFF%20DISNEY-FAM/s.erm2bF5K +http://polit.kulichki.net/moshkow/PXESY/GORIN/ +http://polit.kulichki.net/moshkow/COPYRIGHT/stolyarov.txt +http://www.science.uva.nl/pub/NetBSD/NetBSD-current/pkgsrc/textproc/rman/pkg/DESCR +http://cgi.www.4tourism.com/uk/wareham65426.html +http://cgi.www.4tourism.com/uk/wareham22477.html +http://www.ccnet.com/affif/_themes/sumipntg/_vti_cnf/?M=A +http://web.tin.it/regionesardegna/ital/lavpubb/bandi_contratti/schema5_1q.htm +http://ring.htcn.ne.jp/archives/text/CTAN/macros/latex/contrib/other/apa/ +http://ftpsearch.belnet.be/packages/CPAN/modules/by-module/Callback/Callback-1.02.readme +http://iant.subportal.com/sn/Utilities/Misc__Utilities/12800.html +http://yp.gates96.com/2/51/0/86.html +http://yp.gates96.com/2/51/1/72.html +http://yp.gates96.com/2/51/2/10.html +http://yp.gates96.com/2/51/3/7.html +http://yp.gates96.com/2/51/3/50.html +http://yp.gates96.com/2/51/4/90.html +http://yp.gates96.com/2/51/5/6.html +http://yp.gates96.com/2/51/5/42.html +http://yp.gates96.com/2/51/5/50.html +http://yp.gates96.com/2/51/6/49.html +http://yp.gates96.com/2/51/8/12.html +http://yp.gates96.com/2/51/8/50.html +http://yp.gates96.com/2/51/9/82.html +http://yp.gates96.com/2/51/9/94.html +http://archive.soccerage.com/s/fr/09/37602.html +http://archive.soccerage.com/s/fr/09/39203.html +http://ftp.ring.gr.jp/archives/NetBSD/NetBSD-1.4.1/pmax/binary/security/ +http://www.yorosiku.net:8080/-_-http://www.us-japan.org/otr/ +http://support.dell.com/docs/storage/dlt1/ug/sp/jumpers.htm +http://moviestore.zap2it.com/browse/MOVIES/MOUSEPAD/s.uiIfdEiW +http://moviestore.zap2it.com/browse/MOVIES/STANDUP/s.uiIfdEiW +http://focusin.ads.targetnet.com/ad/id=animeart&opt=cin&cv=210&uid=972942857 +http://www.emerchandise.com/browse/SATNIGHTLIVE/SWEATSHI/s.pJ2FFfba +http://www.realize.com/p5dee81.htm,qt=e784fe2f=2a38a234-e-1ade986-0-0-0-3-- +http://support.tandy.com/support_audio/doc30/30780.htm +http://sun1.rrzn-user.uni-hannover.de/jgaertner/matlab/help/techdoc/umg/chlabel2.html +http://sun1.rrzn-user.uni-hannover.de/jgaertner/matlab/help/techdoc/umg/chprin12.html +http://www.es.co.nz/~rotary.home.html +http://www.excelsior.com.mx/9802/980217/nac18.html +http://dante.bdp.it/cgi-bin/poseidon_v2.0/reflect/poseidon/disc/biblioteca1/1316779952/prevarticle +http://dennou-t.ms.u-tokyo.ac.jp/arch/cc-env/Linux/debian-jp/dists/stable/non-free-jp/binary-alpha/net/?D=A +http://guest/forestpatholog/diseases/annosus.html +http://guest/forestpatholog/diseases/rot.html +http://no.egroups.com/message/readbygrade3/2029 +http://www.cybercd.de/artist/Fabri,+Stafke.htm +http://www.jamba.de/KNet/_KNet-zQG8j1-hGd-13cwi/admLogin.de/node.0/cenv0b09a +http://www.digitaldrucke.de/(aktuell,computer,marktplatz,sense,tausch)/_fort/html/themen/computer/computer.htm +http://ring.tains.tohoku.ac.jp/pub/linux/debian/debian-jp/dists/potato/contrib-jp/source/news/?S=A +http://strategis.ic.gc.ca/sc_indps/recboats/frndoc/3g.html +http://ftp.eq.uc.pt/software/unix/Linux/redhat/redhat-6.2/i386/doc/gsg/figs/rpmlite/?M=A +http://www.judds-resort.com/judds/Lake-Winni-pike-lodge/upload/upload/photo/fallphoto/boat/12.html +http://ftp.eecs.umich.edu/.7/NetBSD/NetBSD-current/src/usr.sbin/cnwctl/ +http://ftp.eecs.umich.edu/.7/NetBSD/NetBSD-current/src/usr.sbin/mailwrapper/ +http://ftp.eecs.umich.edu/.7/NetBSD/NetBSD-current/src/usr.sbin/traceroute6/ +http://ftp.eecs.umich.edu/.7/NetBSD/NetBSD-current/src/usr.sbin/yppoll/ +http://pelit.saunalahti.fi/.3/linuxberg/conhtml/preview/8785.html +http://www.asahi-net.or.jp/~rz3n-snd/kitakan/kamiyosida.html +http://www.chaos.dk/sexriddle/s/e/x/q/x/k/l/ +http://www.chaos.dk/sexriddle/s/e/x/q/x/k/y/ +http://ring.jec.ad.jp/archives/text/CTAN/dviware/umddvi/libcompat/?S=A +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/OCtIhwK0_lecIJU9yN87J4DTFWqXdztVO8nfP1zxdwq79fkod_IhHN3-iHbCrlaXZ5ATMMc_Gb5Zt_RdtVOloKJ1Z7DGqz2vE9vOjESyOqryETO-lNa0NWtCoTJH_QGCfq7ss5VGa1MO3iLryKZ2gIVI_Lonfx_bC9m7 +http://seniorfriendfinder.com/cgi-bin/w3com/pws/ffsenior/D-tI2p4N__5TTgffRqVzdrKNYFZc3jj2Oatw29gt_YiNBPXUlYZaTA2ndP2CrwlrdiMS8YzPKxDR7Vp4ZBqD3d5o3MwYrYIxk31YsVtP3yFS2bLdZcBGLKdyNUc9yYgvGsGMXAMcEAUJPjtRqUVzDpuhHzS6V_U76I6G +http://my.egroups.com/subscribe/enemapix +http://yp.gates96.com/0/23/40/60.html +http://yp.gates96.com/0/23/40/82.html +http://yp.gates96.com/0/23/41/67.html +http://yp.gates96.com/0/23/43/71.html +http://yp.gates96.com/0/23/43/75.html +http://yp.gates96.com/0/23/44/64.html +http://yp.gates96.com/0/23/44/73.html +http://yp.gates96.com/0/23/44/84.html +http://yp.gates96.com/0/23/45/19.html +http://yp.gates96.com/0/23/46/9.html +http://yp.gates96.com/0/23/46/26.html +http://yp.gates96.com/0/23/46/37.html +http://yp.gates96.com/0/23/46/92.html +http://yp.gates96.com/0/23/47/39.html +http://yp.gates96.com/0/23/47/52.html +http://yp.gates96.com/0/23/48/52.html +http://yp.gates96.com/0/23/49/12.html +http://yp.gates96.com/0/23/49/90.html +http://retailer.gocollect.com/do/session/1912812/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/help/index.asp +http://retailer.gocollect.com/do/session/1912812/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/sports/index.asp +http://203.93.50.148:2222/*0110http://www.snweb.com/gb/people_daily/2000/10/20/i1020004.htm +http://cn.egroups.com/messages/romtrade/5024 +http://members.tripod.co.jp/medo/_private/ +http://dbc.copystar.com.tw/DelphiChat/200001/msg0325.htm +http://tucows.pi.be/winnt/diskcnt_license.html +http://millennium.fortunecity.com/ruthven/144/5041.htm +http://news.pchome.com.tw/ttv/finance/20000616/ +http://library.bangor.ac.uk/search/dEcology+--+Poland+--+Periodicals/decology+poland+periodicals/-17,-1,0,B/frameset&F=decology+north+america+congresses&1,1 +http://www.could.be/travel/north_america/united_states/lodge_2.htm +http://genforum.genealogy.com/cgi-bin/print.cgi?huntington::195.html +http://www.bemi-immobilien.de/Ferien-IB/Startseite/Gemeinsam/immolink/Gemeinsam/MarketingStrategie/Gemeinsam/erreichenPartner/Gemeinsam/3d-service/Top-Darlehens-Konditionen/anforderungsformular.htm +http://members.tripod.co.jp/snowmen/?D=A +http://ftp.unicamp.br/pub/FAQ/sf/alt_history/part6 +http://www.affiliate.hpstore.hp.co.uk/do/session/380884/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/REGISTRATION/entry.asp +http://grid9.linux.tucows.com/x11html/adnload/9444_3744.html +http://www.linux.com/networking/network/communications/tools/web/support/ +http://www.linux.com/networking/network/communications/tools/web/alternative/ +http://cometweb01.comet.co.uk/do!tid=20&rtid=1&vsid=700&session=132030&mid=1000&rid=1060&cid=37030&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplGGolLarZLq4fLpmiLXv-KmooLckYLoznGmpq0qsc0mojLbkYLozvGotc0ZdoLckYLozvGsmv0qmc0jXfLkVZLdocLkYoLzcj1XfkLVZXLqkXLjbzKcob5qroLkVrLoizKlZd5fjYHfklKkZlLjjbLoZbLpl51ubZLDXZLollK3ljLbqlKjXfLkkaHotl4obmLloqL +http://yp.gates96.com/14/77/20/1.html +http://yp.gates96.com/14/77/20/3.html +http://yp.gates96.com/14/77/20/32.html +http://yp.gates96.com/14/77/20/55.html +http://yp.gates96.com/14/77/21/7.html +http://yp.gates96.com/14/77/22/20.html +http://yp.gates96.com/14/77/22/26.html +http://yp.gates96.com/14/77/22/50.html +http://yp.gates96.com/14/77/23/63.html +http://yp.gates96.com/14/77/23/96.html +http://yp.gates96.com/14/77/25/53.html +http://yp.gates96.com/14/77/26/8.html +http://yp.gates96.com/14/77/26/32.html +http://yp.gates96.com/14/77/27/0.html +http://yp.gates96.com/14/77/27/55.html +http://yp.gates96.com/14/77/27/78.html +http://yp.gates96.com/14/77/28/8.html +http://yp.gates96.com/14/77/28/53.html +http://yp.gates96.com/14/77/28/57.html +http://yp.gates96.com/14/77/28/99.html +http://yp.gates96.com/14/77/29/96.html +http://mirror.nucba.ac.jp/mirror/FreeBSD/FreeBSD-stable/ports/cad/xcircuit/files/?D=A +http://pub3.ezboard.com/BBSForum.showForumSearch?boardName=jenxforum&forumName=jenxforumfrm0 +http://genforum.genealogy.com/cgi-genforum/forums/hi.cgi?415 +http://elib.zib.de/pub/opt-net/msc/msc-90-xx/90c15/v93w20n4 +http://biblio.cesga.es:81/search*gag/aDittrich,+Stefan/adittrich+stefan/-5,-1,0,E/frameset&F=adittman+richard+h+coaut&1,,0 +http://biblio.cesga.es:81/search*gag/aDittrich,+Stefan/adittrich+stefan/-5,-1,0,E/frameset&F=adittmar+jorge&1,1 +http://biblio.cesga.es:81/search*gag/aDittrich,+Stefan/adittrich+stefan/-5,-1,0,E/exact&F=adivis+jan&1,4 +http://www.doc.ic.ac.uk/~gwsb98/bucket/Wine-20001026/etc/?D=A +http://news.fm365.com/xinwen/guoji/20000531/72641.htm +http://www.newquestcity.com/templates/eventout.cfm?nqc=TN0730 +http://www.rhena.de/kempinsk1.htm +http://www.jamba.de/KNet/_KNet-tkL8j1-PGd-13dss/showInfo-wir.de/node.0/cenvd8eze +http://www.jamba.de/KNet/_KNet-tkL8j1-PGd-13dsv/browse.de/node.0/ceo0fdeye +http://cpan.nitco.com/modules/by-module/String/BLCKSMTH/?N=D +http://www.digitaldrucke.de/(hilfe,nuernberg)/_fort/html/themen/computer/soft/links/intuit.htm +http://www.jeunesdocteurs.com/fplr/56/08.html +http://simf1.tripod.com/Rio.htm +http://www.mirror.kiev.ua:8083/paper/1998/17/1251/people.htm +http://web2.sportsline.com/u/baseball/mlb/2000PO_stats/tpSTLw.htm +http://www15.freeweb.ne.jp/art/charukun/yusuke.htm +http://map.ipc.co.jp/asp/onmap/r/new/g-24/f-905972/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380882/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/REGISTRATION/entry.asp +http://www.webcrawler.com/education/arts_and_humanities/visual_arts/art_history/c19th/arts_and_crafts/mackintosh_cr/structures/ +http://polygraph.ircache.net:8181/wwwboard/http_-2www.microsoft.com/msoffice/frontpage/http_-2www.linkstar.com/home/partners/marketlink-international-inc +http://polygraph.ircache.net:8181/wwwboard/http_-2www.microsoft.com/msoffice/frontpage/ECA2.htm +http://polygraph.ircache.net:8181/wwwboard/http_-2www.microsoft.com/msoffice/frontpage/http_-2www.intac.com/~dversch/catalog.html +http://excite.de.netscape.com/kunst/katalog/24315 +http://www.outpersonals.com/cgi-bin/w3com/pws/out/KhhIzVYqtXJlJzGPqrqzbJbUw7ERB8P7PSm9mTaj3BkJF6tLfllGlz2yKgLweoM1LPKLdHjjKv8zfb9tb2yojpTmzt6264ZE3V9vWzxY1mZnhDOG1vlwPrnwH5OCJM6C98fbjgZX66II +http://mirror.nucba.ac.jp/mirror/Netscape/netscape6/french/6_PR2/windows/win32/?S=A +http://www.linux.com/networking/server/install/howto/red_hat/package/ +http://www.nissan.co.jp/RENAULT-DEALERS/PASSPORT/view.cgi/proof/972959618-- +http://brain.brent.gov.uk/WebPages.nsf/vWebAllPagesByKey!OpenView&Start=97&Count=60&Expand=152 +http://i-mode.kakiko.com/deaitomo/mag/magurox/1405b.html +http://www.ring.gr.jp/pub/NetBSD/arch/amiga/snapshot/20000115-1.4P/binary/security/ +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=18,0+20,0-17,0-0,0 +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/www/anoncvs.html?annotate=1.2&sortby=rev +http://ftp.jp.debian.org/debian/dists/woody/non-free/binary-sh/hamradio/?M=A +http://netscape.complete-skier.com/resorts/survey/submit.asp?ResortID=772 +http://nathanael.upi.jussieu.fr/tele6.nsf/autres+centres+de+formations!OpenPage&ExpandSection=9,17,2,16,5,14 +http://www.egroups.com/messages/zingiber/238 +http://www.umr.edu/~rhall/class/sap/sap8/demo.html +http://209.207.239.212/bkindex/c1043/f1202.html +http://se.egroups.com/message/ackmud/104 +http://school.educities.org/card/cug55.html +http://school.educities.org/card/wgl.html +http://school.educities.org/card/a77125.html +http://school.educities.org/card/apple6128.html +http://school.educities.org/card/c369852.html +http://school.educities.org/card/cges4216.html +http://school.educities.org/card/cges6307.html +http://school.educities.org/card/eaa.html +http://school.educities.org/card/f129235832.html +http://school.educities.org/card/g1546.html +http://school.educities.org/card/h223422022.html +http://school.educities.org/card/lemon6112.html +http://school.educities.org/card/st6408.html +http://www.dulux.co.uk/UKRETAIL:1243142410:DFinity.1QJiP4jRACol +http://www.iagora.com/pages/bbaddpost/::bb_id=148:mid=43302:thread_id=8185:parent_id=43302::lang=de +http://www.iagora.com/pages/bbaddpost/::bb_id=148:mid=43431:thread_id=8185:parent_id=43431::lang=de +http://www.egroups.com/message/intelligent_humor/875 +http://club.telepolis.com/klvinbc/fotosb.htm +http://plat.debian.or.jp/debian/dists/woody/non-free/binary-mips/editors/?D=A +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=207&discrim=3,12,63 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=207&discrim=3,12,237 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=207&discrim=3,12,120 +http://www.jamba.de/KNet/_KNet-_tJ8j1-AGd-13ddq/browse.de/node.0/cdel3j591 +http://immihelpdownloads.subportal.com/sn/Utilities/System_Analysis_Utilities/2980.html +http://dwp.bigplanet.com/crestinginc/discussion/edit.nhtml +http://dwp.bigplanet.com/crestinginc/discussion/list.nhtml?profile=discussion +http://194.128.65.4/pa/cm199900/cmwib/wb991127/ahead.htm +http://61.128.218.34/book/hhsh/wu/wolongsheng/jiangxue/055.htm +http://gd.cnread.net/cnread1/wgwx/t/tuwen/kxj/035.htm +http://gd.cnread.net/cnread1/wgwx/t/tuwen/kxj/041.htm +http://www.redrocksports.com/sports/webSession/shopper/RR972959743-31143/store/dept-5/department/dept-5/item/50110 +http://www.redrocksports.com/sports/webSession/shopper/RR972959743-31143/store/dept-5/department/dept-5/item/51530 +http://www.redrocksports.com/sports/webSession/shopper/RR972959743-31143/store/dept-5/department/dept-5/item/51510 +http://www.yorku.ca/org/yusa/who99/wh02.html +http://www1.onelist.com/message/ar8200/3350 +http://www.kodak.se/US/en/corp/features/kern/jodi/index.shtml +http://cafe3.daum.net/Cafe-bin/Bbs.cgi/semtle15pds/rnw/zka/B2-kB27k +http://my.egroups.com/messages/dcfwriters/187?expand=1 +http://link.fastpartner.com/do/session/600414/vsid/1970/tid/1970/cid/135878/mid/1060/rid/1488/chid/1970/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/gosafe.php +http://www.tiscover.com/1Root/Kontinent/6/Staat/7/Bundesland/20/Ort/108147/Bauernhof/315126/Homepage/f_homepage...2.html +http://ring.omp.ad.jp/archives/NetBSD/packages/pkgsrc/net/gnut/patches/?D=A +http://www.mtranslations.cz/40/cs/dictionary/dictionary_index.html +http://pub10.ezboard.com/BBSSystem.handleLoginCheck?action=forgotPassword&boardName=alakazamslair +http://tour.stanford.edu/cgi/locate3.prl/139.6/jMtlo +http://www.shopworks.com/index.cfm/action/search/userid/00042DDE-2F63-19FE-9038010B0A0ADCF2 +http://thestar.com/back_issues/ED20001004/life/20000820LFE01_AH-BATH.html +http://thestar.com/back_issues/ED20001004/life/20000818LFE01_LI-DEPRESS.html +http://thestar.com/back_issues/ED20001004/life/20000806LFE01_AH-DAHLIAS.html +http://www.hole.kommune.no/hole/journweb.nsf/7e180336094ef23a412568cd004a5093/466e7592a4c6c7ccc12568e3004402e8!Navigate&To=Prev +http://mailthat.subportal.com/sn/Multimedia_and_Graphics/Graphics_Editors/3752.html +http://www.gbnf.com/genealogy/rockwel4/html/d0014/I6348.HTM +http://www.lookforforestry.com/catalog/FORSALE/FORKLIFT/JCB/930RTFL/ +http://www.espl.org/mearscol/pagendxs/stockley/d1828.htm +http://in.egroups.com/messages/eyecandy/1290 +http://in.egroups.com/message/eyecandy/1264 +http://in.egroups.com/message/eyecandy/1271 +http://www.ferien-immobilien.de/bayern/deggendorf/Verkauf/Exklusiv-IB/Startseite/3d-service/Gemeinsam/Immolink/Gemeinsam/vertriebspartner.htm +http://linux99.inrialpes.fr/linux/RPM/redhat/6.2/i386/Distribs.html +http://students.lsu.edu/students/main.nsf/Pages/CSISAJ1!OpenDocument&ExpandSection=4,13,11,10 +http://www.doc.ic.ac.uk/lab/labsrc_area/firstyear/submissions/1997-98/jmc1/labs/Ex04/jwb97/?S=A +http://www.iabusnet.org:90/forums/aca-1/dispatch.exe/survey/folderFrame/100001/0/alpha/2509069 +http://www.scifi.com/bboard/browse.cgi/1/5/545?lnum=4223 +http://www.fogdog.com/cedroID/ssd3040183304719/customer_service/ +http://www.fogdog.com/cedroID/ssd3040183304719/nav/products/winter_sports/1b/suits/ +http://www.gpul.org/ftp/lang/java/JDK/jdk1.1.6-docs/api/java.lang.Math.html +http://www.gpul.org/ftp/lang/java/JDK/jdk1.1.6-docs/api/java.lang.IncompatibleClassChangeError.html +http://www.staroriental.net/nav/soeg/ihf,aai,n2,418,Electric+Wave+Girl+1998.html +http://www.parentsplace.com/expert/lactation/basics/qa/0,3459,5757,00.html +http://www.francetrade.fr/opcvm/details/4/44200.html +http://www.francetrade.fr/opcvm/details/4/42876.html +http://genforum.genealogy.com/cgi-bin/print.cgi?phillippines::319.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380860/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-photoworld.com/photoworld.asp?lang=f +http://ftp.eq.uc.pt/software/unix/Linux/docs/HOWTO/translations/italian/distributions/?M=A +http://store1.europe.yahoo.com/brink2/2000074017704.html +http://store1.europe.yahoo.com/brink2/2000073276003.html +http://www.cbe21.com.cn/xueke/dili/jiaoxuezs/ziliaojn/tupianhc/i0733.htm +http://www.networkpatternmatching.com/inventory/L/Limoges-American/Limoges-American-Tea-Rose-(Green).html +http://www.networkpatternmatching.com/inventory/L/Limoges-American/Limoges-American-Toledo-Delight-(Sand).html +http://ftp.debian.org/dists/sid/non-free/binary-hppa/games/?M=A +http://www.angelfire.com/vt/kAoZzZ +http://yp.gates96.com/14/28/60/15.html +http://yp.gates96.com/14/28/60/17.html +http://yp.gates96.com/14/28/60/41.html +http://yp.gates96.com/14/28/60/75.html +http://yp.gates96.com/14/28/60/83.html +http://yp.gates96.com/14/28/60/87.html +http://yp.gates96.com/14/28/61/96.html +http://yp.gates96.com/14/28/62/12.html +http://yp.gates96.com/14/28/62/28.html +http://yp.gates96.com/14/28/62/45.html +http://yp.gates96.com/14/28/62/74.html +http://yp.gates96.com/14/28/63/24.html +http://yp.gates96.com/14/28/63/45.html +http://yp.gates96.com/14/28/64/33.html +http://yp.gates96.com/14/28/65/84.html +http://yp.gates96.com/14/28/66/28.html +http://yp.gates96.com/14/28/66/49.html +http://yp.gates96.com/14/28/67/15.html +http://yp.gates96.com/14/28/67/17.html +http://yp.gates96.com/14/28/67/92.html +http://yp.gates96.com/14/28/67/95.html +http://yp.gates96.com/14/28/68/10.html +http://yp.gates96.com/14/28/69/20.html +http://yp.gates96.com/14/28/69/64.html +http://yp.gates96.com/14/28/69/74.html +http://www.cs.kuleuven.ac.be/documentation/Sun/WorkShop/html_docs/c-plusplus/stdlibcr/deq_4164.htm +http://no.egroups.com/message/Holiday-Best/571?source=1 +http://www.outpersonals.com/cgi-bin/w3com/pws/out/G1hIPcWIQWr-i3fHpjDuaPPPdDR9n25II-MFpjX9vR_df0A3ukwPXLd19bYe7oxRH5Zr5z3G_wJnwM6gAVSOlRUN-p5MKYEBVJa1T-GaZS44Z98yjSST2LfXzEdc9Xqp8W0jRiNL6iAX +http://msn.expedia.co.uk/wg/Asia/China/P31642.asp +http://www.angelfire.com/fl2/gulfcoastsoftball/images/?N=D +http://www.greenleaves.com/bookcat/gb_0879513802.html +http://cn.egroups.com/post/Digitrends_Daily?act=reply&messageNum=210 +http://www.bookhome.net/wuxia/hzlz/li/031.html +http://gb.toget.com.tw/intro/game_action/game_action_click/19990804_3190_dl.html +http://www.mbnet.mb.ca/gray/cgrcc.html +http://www.civila.com/noticias/chat/logos/juegos/esgratis/logos/index.html-ssi +http://www.ytmag.com/cgi-bin/redirect.cgi/1197948180 +http://debian.tod.net/debian/dists/sid/contrib/binary-arm/admin/?M=A +http://haste.co.kr/www.amaquest.com.tw/support.htm +http://www.diogenes.ch/4DACTION/web_rd_aut_frlist_az/ID=483376&chr=A +http://ads.neoseeker.com/remoteclick/GB972959289/ +http://urawa.cool.ne.jp/whoinside/cg/cgframe2.htm +http://excite.de/bildung/katalog/33148 +http://plat.debian.or.jp/debian-archive/dists/Debian-2.0/hamm/binary-m68k/news/ +http://wwwpriv.uni-koblenz.de:81/~admin/Doku/HtmlTutor/tcdkc.htm +http://platsbanken.amv.se/kap/text/62/000907,150090,120901,40,1427050362.shtml +http://216.35.79.131/sites/gunits/022140u.html +http://www.hotelboulevard.com/fr/paris/standard/htmle55cd396d0d1450ad1eddadf65bd6574/sessionLang/ANG/prov/browse/cp/75011/resultatSearch.html +http://www.ftp.uni-erlangen.de/cgi-bin/view/pub/unix/Linux/MIRROR.KDE/unstable/apps/README +http://www.ftp.uni-erlangen.de/pub/unix/Linux/MIRROR.KDE/unstable/apps/network/ +http://www.ycwb.com.cn/gb/2000/04/28/dnzk/itkx/3.html +http://polygraph.ircache.net:8181/http_-2www.microsoft.com/guestbook/http_-2www.nmpinc.com/cfiguest.htm +http://www.our-home.org/giulianovallemani/success.htm +http://retailer.gocollect.com/do/session/1912838/vsid/2312/tid/2312/cid/573127/mid/1020/rid/2147/chid/2210/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLlZe5ofpLqjXLpl4/url/http://www.gocollect.com/product_display/products/product_lines.asp +http://binary.tucows.com/win2k/adnload/60913_29719.html +http://www.allhealth.com/kickbutt/qa/0,4801,6565_168263-1,00.html +http://library.cuhk.edu.hk/search*chi/tChinese+history+series.+[Motion+picture]/tchinese+history+series/-5,1,1,B/frameset&F=tchinese+history+index+to+learned+articles+1902+1962&1,1, +http://cafe4.daum.net/Cafe-bin/Bbs.cgi/culturalistpds/lst/qqeq/1/zka/B2-kB27p +http://lib1.nippon-foundation.or.jp/1997/0012/contents/086.htm +http://members.tripod.com/~theernest/lit/long.html +http://de.excite.de/auto/katalog/13030 +http://www.szinfo.com/book/ke/fam/nk1/wlsf/001.htm +http://www.backflip.com/members/cquinn/466730/sort=1/ +http://130.158.208.53/WWW/PDB2/PCD4711/htmls/49.html +http://astronomysite.com/mapug1/15/msg15752.htm +http://astronomysite.com/mapug1/15/msg15922.htm +http://astronomysite.com/mapug1/15/msg15970.htm +http://astronomysite.com/mapug1/12/msg12909.htm +http://astronomysite.com/mapug1/9/msg9909.htm +http://astronomysite.com/mapug1/7/msg7248.htm +http://astronomysite.com/mapug1/7/msg7288.htm +http://astronomysite.com/mapug1/7/msg7300.htm +http://astronomysite.com/mapug1/7/msg7277.htm +http://astronomysite.com/mapug1/3/msg3386.htm +http://astronomysite.com/mapug1/0/msg898.htm +http://astronomysite.com/mapug1/2/msg2146.htm +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/ports/x11-fm/systemg/pkg/Attic/DESCR +http://www.posterwelt.de/byers/bye2506.htm +http://www.5a8.com/book/wg/zpj/f/fajieyefu/huimie/003.htm +http://www.5a8.com/book/wg/zpj/f/fajieyefu/huimie/015.htm +http://businessrecorder.com/story/S0015/S1510/top +http://sunsite.org.uk/Mirrors/ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/nt351/hotfixes-postsp5/sec-fix/?S=A +http://sunsite.org.uk/Mirrors/ftp.microsoft.com/bussys/winnt/winnt-public/fixes/usa/nt351/hotfixes-postsp5/sec-fix/readme.txt +http://www.angelfire.com/ky/dodone/HistJ.html +http://www.cricinfo.com/link_to_database/ARCHIVE/1997-98/WI_IN_PAK/WI_IN_PAK_NOV-DEC1997_WI-SQUAD.html +http://www.egroups.com/message/-Girlhelp-/3251 +http://www.egroups.com/message/-Girlhelp-/3268 +http://202.130.244.3/wuliwangye/help/help.htm +http://ftp.gwdg.de/pub/EMIS/EMS/journals/SLC/divers/mirror.html +http://ftp.gwdg.de/pub/EMIS/EMS/journals/SLC/divers/s20ghinelli.html +http://ftp.gwdg.de/pub/EMIS/EMS/journals/SLC/divers/s25dress.html +http://ftp.gwdg.de/pub/EMIS/EMS/journals/SLC/divers/s30wen.html +http://ftp.gwdg.de/pub/EMIS/EMS/journals/SLC/divers/slc41email.html +http://guardian.co.uk/Print/0,3858,3889048,00.html +http://genforum.genealogy.com/mccallum/messages/187.html +http://genforum.genealogy.com/mccallum/messages/192.html +http://genforum.genealogy.com/mccallum/messages/133.html +http://genforum.genealogy.com/mccallum/messages/95.html +http://genforum.genealogy.com/mccallum/messages/82.html +http://genforum.genealogy.com/mccallum/messages/30.html +http://dekooi.tucows.com/win2k/adnload/37333_29427.html +http://dekooi.tucows.com/win2k/adnload/37624_29418.html +http://dekooi.tucows.com/win2k/preview/139483.html +http://www.zurich-schweiz.ch/static/it/peraziende/grandiimprese/riskmanagement/procedere_con_metodo/gestione_del_rischio/ +http://cn.egroups.com/login.cgi?login_target=%2Fmessage%2Fcertdev%2F373 +http://www.angelfire.com/pa2/DreamAvs/ +http://www.madisonmag.com/sh/entertainment/stories/entertainment-20000713-013454.html +http://variety.studiostore.com/browse/WHATSNEW/SHIRT/b.FAVORITES%20WHATSNEW/s.GqXR0UHu +http://variety.studiostore.com/browse/WHATSNEW/MUG/b.FAVORITES%20WHATSNEW/s.GqXR0UHu +http://www.ecs.soton.ac.uk/~ecc/teaching/java/ExampleCode/Chapter10/s03/ +http://ftp.nacamar.de/pub/NetBSD/packages/1.4/alpha/cross/?M=A +http://www.he.ctc.org.cn/ctc2/news/internet/develop/news0413-7.htm +http://www.he.ctc.org.cn/ctc2/news/internet/invest/news0523-4.htm +http://www.he.ctc.org.cn/ctc2/news/internet/invest/news0514-1.htm +http://www.he.ctc.org.cn/ctc2/news/internet/politics/news0518-1.htm +http://www.linux.com/networking/network/applications/industry/trade_show/internet/ +http://www.linux.com/networking/network/applications/industry/trade_show/Motorola/ +http://www.linux.com/networking/network/applications/industry/trade_show/distro/ +http://iinet.tukids.tucows.com/mac/5-8/macmulti58_license.html +http://www.leg.wa.gov/pub/rcw%20-%20text/title_48/chapter_098/rcw_48_98_005.txt +http://universal.eud.com/1999/02/28/28304AA.shtml +http://www.firstview.com/WRTWfall97/MAX_MARA/P033.html +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/SOSIAALI-+JA+TERVEYSALA/tietoverkot/suositukset/tietotekniikka/sanat/getdoc.akM?document_id=479 +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/SOSIAALI-+JA+TERVEYSALA/tietoverkot/suositukset/tietotekniikka/sanat/www/ +http://ns.studenti.to.it/~s86852/applets/tetris.htm +http://www.egroups.com/message/grebel-list/1014 +http://emedici.net/www.homesbyavi.com/canadian_site/communities/evergreen/evergreen.html +http://ring.toyama-ix.net/pub/net/wu-ftpd/wu-ftpd/binaries/?N=D +http://ring.nii.ac.jp/archives/text/CTAN/support/vmspell/?N=D +http://ftpsearch.belnet.be/packages/CPAN/modules/by-authors/John_Macdonald/CHECKSUMS +http://students.depaul.edu/~eephrem/piazza123 +http://students.depaul.edu/~eephrem/maqdoomi.html +http://ftp.unina.it/pub/Unix/KDE/stable/2.0/distribution/deb/?D=A +http://www.dulux.co.uk/UKRETAIL:1433075516:DFinity.1QJiP4jMofi7bof +http://yp.gates96.com/14/20/10/26.html +http://yp.gates96.com/14/20/10/34.html +http://yp.gates96.com/14/20/10/63.html +http://yp.gates96.com/14/20/11/36.html +http://yp.gates96.com/14/20/11/73.html +http://yp.gates96.com/14/20/12/93.html +http://yp.gates96.com/14/20/13/42.html +http://yp.gates96.com/14/20/13/44.html +http://yp.gates96.com/14/20/14/9.html +http://yp.gates96.com/14/20/15/62.html +http://yp.gates96.com/14/20/15/77.html +http://yp.gates96.com/14/20/16/52.html +http://yp.gates96.com/14/20/16/70.html +http://yp.gates96.com/14/20/16/83.html +http://yp.gates96.com/14/20/17/91.html +http://yp.gates96.com/14/20/17/98.html +http://yp.gates96.com/14/20/18/8.html +http://yp.gates96.com/14/20/18/73.html +http://yp.gates96.com/14/20/19/38.html +http://yp.gates96.com/14/20/19/42.html +http://yp.gates96.com/14/20/19/56.html +http://www.wco.com/~havok/wellington.html +http://opac.lib.ntnu.edu.tw/search*chi/++ftlist/bbm0019678/7,-1,0,E/frameset&F=bbm0019685&1,1 +http://cdrom.zeelandnet.nl/elfsound/archief.htm +http://businessrecorder.com/story/S0055/S5527/top +http://www.private-immobilien-boerse.de/DominikanischeRep/verkauf/Versteigerungen-IB/Startseite/Gemeinsam/GmbH-Kauf-Verkauf-Insolvenz-konkurs/Startseite/IIM-Teil/Startseite/froben.htm +http://ring.nii.ac.jp/archives/lang/perl/CPAN/doc/manual/html/pod/perlfunc/utime.html +http://yp.gates96.com/14/21/10/71.html +http://yp.gates96.com/14/21/11/15.html +http://yp.gates96.com/14/21/12/55.html +http://yp.gates96.com/14/21/12/58.html +http://yp.gates96.com/14/21/13/94.html +http://yp.gates96.com/14/21/14/7.html +http://yp.gates96.com/14/21/14/12.html +http://yp.gates96.com/14/21/14/32.html +http://yp.gates96.com/14/21/14/96.html +http://yp.gates96.com/14/21/15/3.html +http://yp.gates96.com/14/21/15/51.html +http://yp.gates96.com/14/21/16/32.html +http://yp.gates96.com/14/21/16/87.html +http://yp.gates96.com/14/21/17/19.html +http://yp.gates96.com/14/21/17/31.html +http://yp.gates96.com/14/21/18/15.html +http://yp.gates96.com/14/21/18/68.html +http://yp.gates96.com/14/21/19/56.html +http://cafe2.daum.net/Cafe-bin/Bbs.cgi/kjbugopds/lst/qqa/f/zka/B2-kB2Rt +http://legalminds.lp.findlaw.com/list/courtinterp-spanish/frm04580.html +http://legalminds.lp.findlaw.com/list/courtinterp-spanish/frm04611.html +http://genforum.genealogy.com/cgi-genforum/forums/sweden.cgi?5207 +http://variety.studiostore.com/main/b.FAVORITES%20NOSTALGI%20CLASTV%20ILOVELUCY/s.VfgR3aEr +http://variety.studiostore.com/help/b.FAVORITES%20NOSTALGI%20CLASTV%20ILOVELUCY/s.VfgR3aEr +http://bsd.sinica.edu.tw/cgi-bin/cvsweb.cgi/ports/x11-clocks/xalarm/patches/Attic/patch-aa?only_with_tag=RELEASE_2_2_8 +http://gd.cnread.net/cnread1/ztxs/h/henggouzhengshi/eld/013.htm +http://gd.cnread.net/cnread1/ztxs/h/henggouzhengshi/eld/022.htm +http://gd.cnread.net/cnread1/ztxs/h/henggouzhengshi/eld/024.htm +http://ftp.unina.it/pub/Amiga/NetBSD/NetBSD-current/xsrc/xc/lib/xkbfile/?N=D +http://202.99.23.245/zdxw/17/20000217/200002171734.html +http://sunsite.org.uk/packages/netbsd/NetBSD-current/pkgsrc/net/batchftp/files/ +http://www.highwired.net/Activity/PrintArticle/0,1640,1326-186648,00.html +http://phpbuilder.net/forum/archives/1/2000/10/1/104426?&print_mode=1 +http://www.cognos.co.uk/de/vertriebspartner/vertriebspartner_plz.html +http://citeseer.nj.nec.com/cidcontext/3974259 +http://fi.egroups.com/message/free-classifieds/4556?source=1 +http://genforum.genealogy.com/cgi-genforum/forums/epler.cgi?2 +http://no.egroups.com/post/relations_iVillage?act=reply&messageNum=5 +http://198.103.152.100/search*frc/lHD69+P75H84/lhd+++69+p75+h84/-5,-1,0,E/frameset&F=lhd+++69+p75+k47+1984&1,1 +http://www.4positiveimages.com/4positiveimages/921456486/UserTemplate/2 +http://haha.3322.net/donghua/agui/adi/6.htm +http://mediate.magicbutton.net/do/session/625591/vsid/4573/tid/4573/cid/88043/mid/2247/rid/2383/chid/3527/url/http://www.winesmart.com/CaseDetails.asp?idCase=66 +http://www.lettera.de/tp/deutsch/inhalt/lis/8676/1.html +http://www.citybrazil.com.br/sc/regioes/joinville/expressoes.htm +http://webcvs.kde.org/cgi-bin/cvsweb.cgi/www/food/worse_is_better.html?sortby=date +http://yp.gates96.com/7/45/60/13.html +http://yp.gates96.com/7/45/61/3.html +http://yp.gates96.com/7/45/61/60.html +http://yp.gates96.com/7/45/62/37.html +http://yp.gates96.com/7/45/62/48.html +http://yp.gates96.com/7/45/62/70.html +http://yp.gates96.com/7/45/64/9.html +http://yp.gates96.com/7/45/64/33.html +http://yp.gates96.com/7/45/64/43.html +http://yp.gates96.com/7/45/64/55.html +http://yp.gates96.com/7/45/65/14.html +http://yp.gates96.com/7/45/65/48.html +http://yp.gates96.com/7/45/65/57.html +http://yp.gates96.com/7/45/66/27.html +http://yp.gates96.com/7/45/67/51.html +http://yp.gates96.com/7/45/68/12.html +http://yp.gates96.com/7/45/68/78.html +http://yp.gates96.com/7/45/69/25.html +http://www.msb.malmo.se/search*swe/aHarley,+Robert/aharley+robert/-5,-1,0,B/browse +http://www.superdownloads.com.br/linkinvalido.cfm?ID=748 +http://linuz.sns.it/doc/howto/en/html/AI-Alife-HOWTO-6.html +http://www.linux.com/networking/network/market/tools/applications/ +http://www.linux.com/networking/network/market/tools/frame_relay/ +http://www.linux.com/networking/network/market/tools/e-commerce/ +http://opac.lib.ntnu.edu.tw/search*chi/aUnited+Nations.+Dept.+of+Economic+and+Social+Affairs/aunited+nations+dept+of+economic+and+social+affairs/7,-1,0,B/frameset&F=aunited+nations+economic+and+social+commission+for+asia+and+the+pacific&6,,7 +http://www.affiliate.hpstore.hp.co.uk/do/session/380863/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/assistance/entry.asp +http://www.affiliate.hpstore.hp.co.uk/do/session/380863/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/entry.asp +http://www.shmoo.com/mail/ids/oct99/msg00288.html +http://bsd.sinica.edu.tw/ftp_pub/NetBSD/packages/1.3/hp300/?M=A +http://bsd.sinica.edu.tw/ftp_pub/NetBSD/packages/1.3/hp300/archivers/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380868/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/REGISTRATION/entry.asp +http://www.insideneworleans.com/shared/health/adam/ency/imagepage/1562.000872.html +http://ring.omp.ad.jp/archives/NetBSD/packages/pkgsrc/devel/xxgdb/patches/patch-ac +http://genforum.genealogy.com/casey/messages/327.html +http://genforum.genealogy.com/casey/messages/164.html +http://genforum.genealogy.com/casey/messages/337.html +http://genforum.genealogy.com/casey/messages/73.html +http://genforum.genealogy.com/casey/messages/57.html +http://genforum.genealogy.com/casey/messages/50.html +http://genforum.genealogy.com/casey/messages/23.html +http://genforum.genealogy.com/casey/messages/116.html +http://www.msb.malmo.se/search*swe/aNorman,+Karin,+1947-/anorman+karin+1947/-5,-1,0,B/frameset&F=anorman+leslie&1,1 +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/folderFrame/100001/0/rnumber/9096335 +http://www.mindspring.com/~arachnid/?S=D +http://www6.freeweb.ne.jp/business/n-bns/hre/ +http://news.swww.com.cn/wccdaily/review/200005/29/html/0908.htm +http://tucows.hom.net/croomnt_rating.html +http://www.trax.nilex.co.uk/trax.cgi/A1C/A2S/1AS/A4L/A4D/B1R/ +http://www.trax.nilex.co.uk/trax.cgi/A1C/A2S/1AS/A4L/A4D/A5L/ +http://www.5a8.com/book/kh/zg/zpj/h/heju/001.htm +http://www.5a8.com/book/kh/zg/zpj/h/heju/002.htm +http://www.luckyman.de/computer/hpaccess/java_cgi/java_applet/linien/applet_linien_nav1.htm +http://www.secure-me.net/information/kb/POP +http://in.egroups.com/message/BodybuildingContests/2804 +http://in.egroups.com/message/BodybuildingContests/2820 +http://in.egroups.com/message/BodybuildingContests/2822 +http://theconnection.vnunet.com/Analysis/Stfriend/70206 +http://www.yorosiku.net:8080/-_-http://www.nrcse.washington.edu/newsletter/newsletter.pdf +http://www.britishairways.nl/regional/barbados/docs/spec_world_offer.shtml +http://www.xmwb.sh.cn/xmwb/19981117/BIG5/13421^4111719.htm +http://www.z-plus.de/TEXTE/HOMEPAGE/HILFE/HILFE_SURFTIPS201099/text5.html +http://uzgamez.subportal.com/games/previews/0900/westwood/russian_general.html +http://bsd.sinica.edu.tw/ftp_pub/NetBSD/packages/1.3/sun3/?D=A +http://my.egroups.com/messages/dcfwriters/132?expand=1 +http://my.egroups.com/message/dcfwriters/147 +http://my.egroups.com/message/dcfwriters/149 +http://oss.sgi.com/cgi-bin/cvsweb.cgi/projects/failsafe/FailSafe/failsafe/scripts/?only_with_tag=MAIN +http://sound-dist.secured.co.uk/cgi-bin/psShop.cgi/add|8P007|972959615|Warm===and===Dry|user|0|1,0,0,1 +http://www.alsapresse.com/jdj/00/01/13/MA/photo_6.html +http://www.highwired.net/ESchoolDrive/Frameset/0,5592,13577-52,00.html +http://uk.sports.yahoo.com/000922/59/ak705.html +http://universal.eud.com/1999/02/26/26204DD.shtml +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/ports/audio/gkrellmvolume/pkg-descr?only_with_tag=MAIN +http://www3.skolverket.se/kursinfo/99_00/skolform/21/alt_nav/S_52S_10S_36VAV_SVSTEK_1715.HTML +http://www3.skolverket.se/kursinfo/99_00/skolform/21/alt_nav/S_52S_10S_36VAV_SVSTEK_1719.HTML +http://www.wsrn.com/apps/research/history.xpl?s=CMDCD&f=HISTORY +http://www.wsrn.com/apps/charts/?s=CMDCD&data=Z10 +http://pub3.ezboard.com/utherealcharron.showPublicProfile?language=EN +http://ring.shibaura-it.ac.jp/archives/graphics/gimp/gtk/binary/DEBIAN/stable/?S=A +http://209.52.189.2/discussion.cfm/autism/29762/198522 +http://www.affiliate.hpstore.hp.co.uk/do/session/380851/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/assistance/entry.asp +http://www01.sankei.co.jp/advertising/furusato/tokuhain/9810/1018sindou.html +http://kulichki-mac.rambler.ru/abiturient/ak.htm +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+9,1-20,0+9,0 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+9,1-20,0+18,0 +http://ballesta.inrialpes.fr/Infos/Personnes/Christophe.Rippert/ressources/tutorial/security1.2/summary/glossary.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380872/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.france.hp.com/main/respect/ +http://www11.cplaza.ne.jp/babyweb/bbs/bdnmp01/no24/99N.html +http://www.homeway.com.cn/lbi-html/news/zhxw/gatxw/20000922/165807.shtml +http://gd.cnread.net/cnread1/yqxs/d/dingqianrou/ssqj/009.htm +http://library.bangor.ac.uk/search/tBiol.+philos/tbiol+philos/-17,-1,0,B/frameset&F=tbioindicators+and+environmental+management&1,1 +http://dante.bdp.it/cgi-bin/poseidon_v2.0/reflect/poseidon/disc/peacelink-scuola/70630505/view/1 +http://www.indian-express.com/ie/daily/19980626/17750374.html +http://www.indian-express.com/ie/daily/19980626/17751044.html +http://www.indian-express.com/ie/daily/19980626/17751334.html +http://www.indian-express.com/ie/daily/19980626/17751494.html +http://polygraph.ircache.net:8181/services/define/http_-2www.disney.com/links.html +http://pub10.ezboard.com/fsavings4yousavings4you.subscribeUnregisteredToTopic?topicID=56.topic +http://www8.freeweb.ne.jp/shopping/arthome/arthome/menu.html +http://rainforest.parentsplace.com/dialog/get/medinfo/4/1.html?outline=3 +http://www.emerchandise.com/aboutus/b.TV%20SATNIGHTLIVE/s.afJ7iGE2 +http://ring.omp.ad.jp/archives/NetBSD/packages/pkgsrc/net/arpwatch/pkg/?S=A +http://ring.omp.ad.jp/archives/NetBSD/packages/pkgsrc/net/arpwatch/pkg/DESCR +http://210.178.135.1/netbbs/Bbs.cgi/nhic30872/qry/zka/B2-kBI-o/pno/0/qqo/004A/qqatt/^ +http://yp.gates96.com/8/48/0/54.html +http://yp.gates96.com/8/48/1/98.html +http://yp.gates96.com/8/48/2/23.html +http://yp.gates96.com/8/48/3/13.html +http://yp.gates96.com/8/48/3/14.html +http://yp.gates96.com/8/48/3/23.html +http://yp.gates96.com/8/48/3/84.html +http://yp.gates96.com/8/48/4/5.html +http://yp.gates96.com/8/48/4/72.html +http://yp.gates96.com/8/48/5/4.html +http://yp.gates96.com/8/48/5/49.html +http://yp.gates96.com/8/48/6/38.html +http://yp.gates96.com/8/48/6/89.html +http://yp.gates96.com/8/48/8/10.html +http://yp.gates96.com/8/48/8/41.html +http://yp.gates96.com/8/48/8/87.html +http://news.medscape.com/adis/CDI/2000/v19.n02/cdi1902.02.biel/cdi1902.02.biel-01.html +http://www.parsonstech.com/genealogy/trees/PKINGMAN/d2438.htm +http://www.parsonstech.com/genealogy/trees/PKINGMAN/d2502.htm +http://www.chaos.dk/sexriddle/j/c/b/o/ +http://www.outpersonals.com/cgi-bin/w3com/pws/out/FahI8ikSPIvk79ErK106-87Jy3U1_XgCksR4DWkUOldKaD_pciJBXOOmI2Sr4jXlDCT9Mkz59aBZhyyi3xxBeYROt0IpVObKZD4YcwBAhl9afrfb6y3nWI3SwdRE_Vp3d80RzmrDkPVZYQkJyvOgorzS +http://opac.lib.rpi.edu/search/dchemicals+dictionaries/-5,-1,0,E/frameset&dchemicals+catalogs&3,,0 +http://opac.lib.rpi.edu/search/dchemicals+dictionaries/-5,-1,0,E/frameset&dchemicals+catalogs+periodicals&1,1 +http://opac.lib.rpi.edu/search/dchemicals+dictionaries/-5,-1,0,E/frameset&dchemicals+dictionaries&3,,0 +http://opac.lib.rpi.edu/search/dchemicals+dictionaries/-5,-1,0,E/frameset&dchemicals+economic+aspects+united+states&1,,0 +http://www.jsonline.com/news/state/oct00/lambeau31103000a.asp +http://polygraph.ircache.net:8181/used/http_-2www.scubaring.com/http_-2www.alpinehotel.com/chinese/chine.htm +http://www.kaos.dk/sex-riddle/k/a/k/i/p/g/g/e/ +http://haikou.hainan.gov.cn/ghgl/ghsc/hkfg3020.html +http://variety.studiostore.com/main/VARIETY/s.Fz90iGDh +http://library.cuhk.edu.hk/search*chi/cPN595.C6I18+1993/cpn++595+c6+i18+1993/-5,1,1,E/frameset&F=cpn++595+c6+k6+1997&1,1, +http://library.cuhk.edu.hk/search*chi/cPN595.C6I18+1993/cpn++595+c6+i18+1993/-5,1,1,E/frameset&F=cpn++595+c6+l515&1,1, +http://link.fastpartner.com/do/session/600425/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/learn.htm +http://www.nanyang.com.my/20001020/articles/15-10-2000k16.htm +http://202.99.23.245/rmrb/199912/11/newfiles/col_19991211001063_zhxw.html +http://help.sap.com/saphelp_45b/helpdata/en/a7/2872510a6c11d28a220000e829fbbd/frameset.htm +http://www.s10.sexshare.com/~pornking/hardcore/43.html +http://www.gbnf.com/genealogy/Lawler99/html/d0102/I1772.HTM +http://ring.edogawa-u.ac.jp/pub/linux/RedHat/aic/OLD/aic7xxx-5.0.x/boot_disks/5.0.11/SuSE/?D=A +http://www.t-online.de/sport/inhalte/adispi51.htm +http://ftp.lip6.fr/pub11/FreeBSD/development/FreeBSD-CVS/src/kerberos5/usr.sbin/k5stash/ +http://education.legend-net.com/xinwen/gaokao/zl5/zhsh/3/zhshyk.html +http://www.contractorresource.com/Wyoming/Cody/ +http://213.36.119.69/do/session/152998/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/boutique/ +http://213.36.119.69/do/session/153000/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/reserver/hotels.html +http://213.36.119.69/do/session/153000/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www3.travelprice.com/voyages/recherche.phtml +http://ftp.unina.it/pub/TeX/macros/latex/contrib/supported/combine/?D=A +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=237&discrim=178,2,11 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=237&discrim=178,2,233 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=237&discrim=178,2,5 +http://www12.freeweb.ne.jp/novel/urufu24/linkz/ug1.html +http://www12.freeweb.ne.jp/novel/urufu24/linkz/pv.html +http://computers.kharkov.ua/win/43/ +http://www.1001e.net/nk4/022.htm +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=4&discrim=93,164,176 +http://dic.empas.com/show.tsp/?q=revisable&f=B +http://yp.gates96.com/0/28/30/45.html +http://yp.gates96.com/0/28/30/46.html +http://yp.gates96.com/0/28/31/24.html +http://yp.gates96.com/0/28/32/64.html +http://yp.gates96.com/0/28/33/28.html +http://yp.gates96.com/0/28/33/85.html +http://yp.gates96.com/0/28/33/87.html +http://yp.gates96.com/0/28/33/96.html +http://yp.gates96.com/0/28/34/52.html +http://yp.gates96.com/0/28/35/7.html +http://yp.gates96.com/0/28/36/23.html +http://yp.gates96.com/0/28/36/52.html +http://yp.gates96.com/0/28/37/50.html +http://yp.gates96.com/0/28/38/85.html +http://yp.gates96.com/0/28/39/16.html +http://www.fan590.com/JamMoviesReviewsE/earth_king.html +http://www.sportbuecher.de/shop/3-88034-750-6.html +http://www.msb.malmo.se/search*swe/aWhitaker,+Galvin,+Utgivare/awhitaker+galvin/-5,-1,0,B/exact&F=awhitburn+joel&1,2 +http://ftp.sunet.se/pub/security/vendor/microsoft/winnt/frn/nt40/?M=A +http://www.intervoz.com.ar/2000/03/02/op_n04.htm +http://www.ntut.edu.tw/~s7370840/8-19.htm +http://www.back2roots.org/Music/Files/Wondergirl%20-%20You%26Me/ +http://www.private-immobilien-boerse.de/nordrhein-Westfalen/Muehlheim-ruhr/Verkauf/3d-service/IIM-Teil/Startseite/Gemeinsam/Inserieren/IIM-Teil/Startseite/frinfo.htm +http://web.singnet.com.sg/~spirit5/letters/oct2000/frankm1025-3.htm +http://web.singnet.com.sg/~spirit5/letters/oct2000/davidp1025.htm +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=decuplicavamo&l=it +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=decuplichiate&l=it +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=decuplichereste&l=it +http://members.tripod.com/~OZEMU/cgi-bin/ +http://ring.tains.tohoku.ac.jp/archives/pack/dos/hardware/midi/?D=A +http://kutschen.de/Schoner/info-e/info-e/collections/literature/ +http://www.jamba.de/KNet/_KNet-MJJ8j1-DGd-13dgc/showInfo-special1.de/node.0/cde7f1uou +http://www.jamba.de/KNet/_KNet-MJJ8j1-DGd-13dgy/browse.de/node.0/cenv0b09a +http://in.egroups.com/message/sfconsim-l/6415 +http://genforum.genealogy.com/cgi-genforum/forums/vt.cgi?4123 +http://www.linux.com/networking/network/sap/article/price/VA_Linux_Systems/ +http://www.linux.com/networking/network/sap/article/price/regulation/ +http://slacvx.slac.stanford.edu/sldmcwww/mc/MC74BB_98R16B_WIN_ALL.HTML +http://www.xmission.com/~dkenison/cgi/lwgate.cgi/KLR650/archives/v02.n1611/date/article-15.html +http://www.iwon.com/home/movies/movies_filmography_page/0,13178,Macon+McCalman,00.html +http://excite.de/spiele/katalog/26997 +http://www.trax.nilex.co.uk/trax.cgi/A1C/B1S/B2R/A2U/B3S/B1R/ +http://www.power2lead.com/Global/English.nsf/pgWWLocations!OpenPage&ExpandSection=2,6,27,9,26 +http://itcareers.careercast.com/texis/it/itjs/+owwBm1eP0-dzwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewDPwdGpdGwBodDa5dhBiwGna5O5BnManDtoDnnGa5nDodGa5BwhhaidGAanLpnGonDqnaqdMp1BnGamnVncdpaMFqhTfR20Dzme8twwwpBmer+D86e9qwww5rmeZpwwwBrmeZpwww/morelike.html +http://pub4.ezboard.com/fnationoferidinegeneral.showAddReplyScreenFromWeb?topicID=615.topic&index=2 +http://www.chaos.dk/sexriddle/m/i/s/x/ +http://kiasuplanet.subportal.com/sn/Games/Tetris_Clone_Games/5532.html +http://kiasuplanet.subportal.com/sn/Games/Tetris_Clone_Games/11418.html +http://kiasuplanet.subportal.com/sn/Games/Tetris_Clone_Games/676.html +http://www.rge.com/pub/networking/ldap/umich/max500/beta/?M=A +http://my.egroups.com/dir/Health/Fitness/Exercise_Equipment +http://my.egroups.com/messages/prevention +http://pub4.ezboard.com/factiveprodiscussioncommunityactivitiesquestions.showMessage?topicID=12.topic +http://www.look4cranes.com/catalog/AUCTIONRESULT/AGGREGATE+-+CONVEYOR+%2F+FEEDER+%2F+STACKER/POWERSCREEN/ +http://www.fogdog.com/cedroID/ssd3040183344300/cgi-bin/MyFogdog +http://www.fogdog.com/cedroID/ssd3040183344300/nav/products/featured_brands/3b/gloves_mittens/ +http://www.houses-apartment-listings.com/Washington/city_search_criteria.asp?state=WA&City=CONCONULLY +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/c23417.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x12810.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x14250.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x14507.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x15988.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x17214.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x18550.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x19113.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x1949.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x21473.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x31101.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x3585.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x44035.html +http://www.brunel.ac.uk/~ccusjpe/linux/howto/Consultants-HOWTO/x4711.html +http://www.online.kokusai.co.jp/Home/V0043638/wrd/G100/ +http://ftp.lip6.fr/pub5/FreeBSD/branches/-current/ports/print/ghostscript5/ +http://ftp.lip6.fr/pub5/FreeBSD/branches/-current/ports/print/texinfo/ +http://ftpsearch.belnet.be/mirrors/ftp.isc.org/pub/usenet/control/ats/?N=D +http://garbo.uwasa.fi/pub/linux/distributions/SuSE/7.0/dosutils/exceed/USER/HOSTEX/SCHEME/?D=A +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/showNextUnseen/fol/100001/922702 +http://link.fastpartner.com/do/session/600391/vsid/1314/tid/1314/cid/134340/mid/1060/rid/1180/chid/1314/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/local/redirect.php +http://www.jamba.de/KNet/_KNet-wEF8j1-bGd-13cma/showInfo-datenschutz.de/node.0/cenvptf1i +http://www.jamba.de/KNet/_KNet-wEF8j1-bGd-13cmd/browse.de/node.0/cenv0b09a +http://www-usa6.cricket.org/link_to_database/PLAYERS/RSA/T/THOMPSON_DS_03003252/ +http://sunsite.org.uk/public/public/packages/WWW/emacs-w3/?S=A +http://www.excelsior.com.mx/9811/981129/buh25.html +http://www.anixter.nl/SBJEVE/170699-2155-01.html +http://innopac.lib.tsinghua.edu.cn:2082/search*chi/aBrooks,+Jane+B./abrooks+jane+b/-5,-1,0,B/browse +http://tour.stanford.edu/cgi/options.prl/95.70/gMcto +http://www.cksd.edgate.com/emeraldheightses/elections/students/the_parties/ +http://novel.hichinese.net/comment/comment.php?page=2091&action=write +http://205.161.150.96/cgi-bin/c2k/additem.html&item=204578 +http://www.nhic.or.kr/netbbs/Bbs.cgi/nhic31282/qry/zka/B2-kB2-m/pno/0/qqo/004A/qqatt/^ +http://scripts.infoart.ru/magazine/znamia/n4-20/shpakov.htm +http://excite.de/bildung/katalog/19909 +http://911codes.com/games/platform/n64/sect/div/cont/list_cheat/spray/y/id/0000009557/gid/0000003573/_cheats/_walkthroughs/_codes/_pc/_n64/_psx/_gameboy/_playstation/ +http://ftp.jp.debian.org/debian/dists/stable/main/source/web/?M=A +http://www.fogdog.com/cedroID/ssd3040183335913/nav/products/featured_brands/3c/all/ +http://his.luky.org/ML/linux-users.3/msg08073.html +http://yomiuri-1422.excite.co.jp/entertainment/animated_cartoon_comic/each_work_title/ha_line/ha +http://yomiuri-1422.excite.co.jp/entertainment/animated_cartoon_comic/each_work_title/ha_line/hu_he/berserk +http://library.cwu.edu/search/dWorld+War,+1914-1918+--+Diplomatic+history/dworld+war+1914+1918+diplomatic+history/-5,-1,0,B/exact&F=dworld+war+1914+1918+diplomatic+history&1,49 +http://www.utdallas.edu/dept/sci_ed/Caribbean/images/Jennifer%20Jordan/Antigua%20Mangrove/?N=D +http://www.baustoffhandel.de/service/faqs/faq-tapezieren.htm +http://muc-zvs-web1.goethe.de/ms/bud/film/un_f2.htm +http://www.online.kokusai.co.jp/Map/V0043636/wrd/G1000/map/sitemap.html +http://win.www.citycat.ru/funny/fido/2000_05/25.html +http://nathanael.upi.jussieu.fr/tele6.nsf/autres+centres+de+formations!OpenPage&ExpandSection=9,1,7,13,15,6 +http://yp.gates96.com/11/79/50/1.html +http://yp.gates96.com/11/79/50/92.html +http://yp.gates96.com/11/79/52/64.html +http://yp.gates96.com/11/79/54/79.html +http://yp.gates96.com/11/79/54/81.html +http://yp.gates96.com/11/79/56/28.html +http://yp.gates96.com/11/79/56/30.html +http://yp.gates96.com/11/79/56/46.html +http://yp.gates96.com/11/79/56/83.html +http://yp.gates96.com/11/79/57/10.html +http://yp.gates96.com/11/79/57/33.html +http://yp.gates96.com/11/79/58/1.html +http://yp.gates96.com/11/79/58/48.html +http://yp.gates96.com/11/79/58/82.html +http://yp.gates96.com/11/79/59/62.html +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/ELINKEINO-+JA+YRITYSTOIMINTA/Matkailu+-+maantiede/matkailu/linja-autoliikenne/joukkoliikenne/aikataulut/ +http://cn.egroups.com/message/romtrade/3823 +http://www.idgnet.com/idgns/1999/07/16/SmallFrenchBusinessesMoveSlowlyTo.shtml +http://www-d0.fnal.gov/d0dist/dist/releases/psim01.01.00/Exceptions/?M=A +http://www.4positiveimages.com/4positiveimages/781560892/Catalog +http://dellnet.excite.fr/yellow_pages/annuaire/823 +http://ftp.chg.ru/pub/math/grace/MIRRORS +http://ftp.chg.ru/pub/math/grace/aux/ +http://legalminds.lp.findlaw.com/list/lawlibref-l/mail8.html +http://carriage.de/Schoner/modelle/models/Info-d/Sammlungen/ +http://chunma.yeungnam.ac.kr/~j4390214/경기상승.htm +http://members.tripod.co.jp/stpp/?M=A +http://map.ipc.co.jp/asp/onmap/connect/f-525598/g-28/ +http://www.fortunecity.com/business/lerner/101/form.html +http://www.sportskorea.net/BBS/Bbs/db/L019/act/new/bnum/000060/zka/6/o/6/drc/f +http://ftp.jp.debian.org/debian/dists/Debian2.2r0/main/binary-all/hamradio/?M=A +http://admin.afiliando.com/do/session/189476/vsid/1507/tid/1507/cid/23455/mid/1025/rid/1168/chid/1205/parser/yes/imref/eqqLmwlGltt5tkpHrYjLXofLklkKZljLkju5lZa5l0/url/http://www.submarino.com.mx/toy/home.asp +http://www.gasex.com/gay.male.erotica/penis.gay.twink.men.html +http://ftpsearch.belnet.be/mirrors/ftp.isc.org/pub/usenet/control/ak/?S=A +http://gb.toget.com.tw/intro/desktop_wallpaper/desktop_wallpaper_idol/20000417_7747_dl.html +http://yp.gates96.com/13/50/50/27.html +http://yp.gates96.com/13/50/52/20.html +http://yp.gates96.com/13/50/52/31.html +http://yp.gates96.com/13/50/52/44.html +http://yp.gates96.com/13/50/53/33.html +http://yp.gates96.com/13/50/53/45.html +http://yp.gates96.com/13/50/53/72.html +http://yp.gates96.com/13/50/54/34.html +http://yp.gates96.com/13/50/54/62.html +http://yp.gates96.com/13/50/54/83.html +http://yp.gates96.com/13/50/54/84.html +http://yp.gates96.com/13/50/55/5.html +http://yp.gates96.com/13/50/55/61.html +http://yp.gates96.com/13/50/55/75.html +http://yp.gates96.com/13/50/56/0.html +http://yp.gates96.com/13/50/56/15.html +http://yp.gates96.com/13/50/56/21.html +http://yp.gates96.com/13/50/56/29.html +http://yp.gates96.com/13/50/57/2.html +http://yp.gates96.com/13/50/57/54.html +http://yp.gates96.com/13/50/58/9.html +http://yp.gates96.com/13/50/58/34.html +http://yp.gates96.com/13/50/59/64.html +http://yp.gates96.com/13/50/59/70.html +http://yp.gates96.com/13/50/59/75.html +http://yp.gates96.com/13/50/59/85.html +http://www.ilmessaggero.it/hermes/19990419/07_MARCHE/40/AGRI.htm +http://www.ilmessaggero.it/hermes/19990419/07_MARCHE/40/NERA.htm +http://amigos.com/cgi-bin/w3com/pws/ffe/IURImAxosglBgN4t3Iz538S9DOsFp6mHl6tpYJehgGibFrnWNcTM3WIsDckFomPqZ-JB8f_Qj8Aua4sE4AFvcFyidtj2iI6k1zPchuFbLwWMCo3hr8eXPNuxbHPQdRvo8J246667 +http://amigos.com/cgi-bin/w3com/pws/ffe/F3hIBiydr9mPRNSqk-dll3MTqIZCaRN3wRH0-H7o4qF0vlfPBXUV-Vhn028iva56e-GCSyYZKBQxuCJO8Y2JF25fVTkPHzFtrNMoOVhEp2n7Y11PhN9pvFNyqgssdZW8Eay0XJsP0vuD4oCbmJVx +http://home.digitalcity.com/boston/sportsguy/main.dci?page=curse2 +http://ftpsearch.belnet.be/mirror/ftp.funet.fi/pub/Linux/doc/logos/.cap/?S=A +http://ftpsearch.belnet.be/mirror/ftp.funet.fi/pub/Linux/doc/logos/.cap/?D=A +http://my.netian.com/~52tour/kyung1.html +http://aol.weather.com/weather/radar/single_site/us_ny_allegany.html +http://www-usa16.cricket.org/link_to_database/GROUNDS/RSA/CENTURION/ +http://polygraph.ircache.net:8181/prodev/career/http_-2www.getstats.com/http_-2www.shindex.com/in_dex/in_dex.html +http://polygraph.ircache.net:8181/prodev/career/http_-2www.getstats.com/http_-2www.microsoft.com/msoffice +http://www.5a8.com/book/wg/cp/p/puge/zhizhunv/005.htm +http://tukids.raha.com/crafts/preview/52044.html +http://tukids.raha.com/crafts/preview/52401.html +http://buc.co.kr/www.ecs.com.tw/ +http://wap.jamba.de/KNet/_KNet-EDS8j1-KHd-13gbq/showInfo-werbung.de/node.0/cde7f1uou +http://www.launch.com/music/songpage/1,4425,322514,00.html +http://www.emerchandise.com/browse/BUFFYTHEVAMP/CAP/b.TV%20BUFFYTHEVAMP/s.NGdTZGLC +http://www.emerchandise.com/browse/BUFFYTHEVAMP/STICKER/b.TV%20BUFFYTHEVAMP/s.NGdTZGLC +http://www.emerchandise.com/help_security/b.TV%20BUFFYTHEVAMP/s.NGdTZGLC +http://yp.gates96.com/14/70/50/9.html +http://yp.gates96.com/14/70/50/23.html +http://yp.gates96.com/14/70/50/24.html +http://yp.gates96.com/14/70/50/40.html +http://yp.gates96.com/14/70/50/47.html +http://yp.gates96.com/14/70/50/79.html +http://yp.gates96.com/14/70/50/89.html +http://yp.gates96.com/14/70/51/83.html +http://yp.gates96.com/14/70/52/98.html +http://yp.gates96.com/14/70/53/46.html +http://yp.gates96.com/14/70/54/4.html +http://yp.gates96.com/14/70/54/24.html +http://yp.gates96.com/14/70/54/97.html +http://yp.gates96.com/14/70/55/51.html +http://yp.gates96.com/14/70/57/51.html +http://yp.gates96.com/14/70/58/3.html +http://yp.gates96.com/14/70/58/84.html +http://yp.gates96.com/14/70/59/0.html +http://opac.lib.ntnu.edu.tw/search*chi/++ftlist/bp20046027/-5,-1,0,B/frameset&F=bp20046031&1,1 +http://www.free-phone.com/q/001p/ppc2/KtIYye9a8Pw.htm +http://www.1stemlm.com/q/001p/ppc2/7kwUxQYfGMk.htm +http://sports.excite.com/ten/grand_german +http://www.omniseek.com/dir/Arts+%26+Humanities/Fine+Arts/Ceramics/Organizations/Australia/ +http://ftp1.service.digital.com/patches/public/vms/axp/v7.1-2/dec-axpvms-vms712_usb-v0100--4.pcsi-dcx_axpexe +http://ftp1.service.digital.com/patches/public/vms/axp/v7.1-2/vms712_acrtl-v0100.README +http://ftp1.service.digital.com/patches/public/vms/axp/v7.1-2/vms712_acrtl-v0100.html +http://ftp1.service.digital.com/patches/public/vms/axp/v7.1-2/vms712_dqconfig-v0200.README +http://ftp1.service.digital.com/patches/public/vms/axp/v7.1-2/vms712_ds20e-v0100.html +http://ftp1.service.digital.com/patches/public/vms/axp/v7.1-2/vms712_shadowing-v0300.CVRLET_TXT +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=barrissait&l=fr +http://dk.egroups.com/message/M-1911/4394 +http://www.netsh.com.cn/wwwboardm/526/messages/2116.html +http://www.netsh.com.cn/wwwboardm/526/messages/2270.html +http://www.netsh.com.cn/wwwboardm/526/messages/773.html +http://www.netsh.com.cn/wwwboardm/526/messages/2058.html +http://www.netsh.com.cn/wwwboardm/526/messages/2329.html +http://www.netsh.com.cn/wwwboardm/526/messages/1813.html +http://linux.softhouse.com.cn/linux/knowledge/tech/HOWTO/Java-CGI-HOWTO-7.html +http://news.novgorod.ru/news/2000/9/22/2/12 +http://news.novgorod.ru/news/2000/9/24/2/12 +http://homepage1.nifty.com/sigenyan/nikki9.htm +http://perso.club-internet.fr/guige/ncpc78.htm +http://www.vr-homes.com/usa/California/Cities/Victorville/Travel/Maps_Images/ +http://www.incestpornstories.com/cum-sex-pics/underagecoed/spankingsweating/hardendurance.html +http://www.freeforums.com/forums/Hardball/000008-000007.asp +http://www.freeforums.com/forums/Hardball/000005-000001.asp +http://www.freeforums.com/forums/Hardball/000004-000001.asp +http://rex.skyline.net/html/Internet_Chat_Sites.html?315,computers,video,internet,computers +http://rex.skyline.net/html/Computers_-_Hardware.html?14,computers,video,internet,computers +http://194.128.65.4/pa/cm199899/cmhansrd/vo990216/text/90216w20.htm +http://pub14.ezboard.com/fyamguyskoflastblade.showMessage?topicID=3.topic +http://plant.reedexpo.ca/www.partnership.ca/?S=A +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=168&discrim=109,5,168 +http://www.aelita.net/products/~archive/Download_redirect/solutions/solutions/services/products/default.htm +http://www.jpc-music.com/7041801.htm +http://home.c2i.net/entreprenor/java/ra.html +http://gxschool.beelink.com.cn/mid_edu/midschool/geography3/t4cd7z/4d7z3.3_1.htm +http://ricoh.co.jp/SHOGI/emate/basic/mate3003a.html +http://www.diogenes.ch/4DACTION/web_rd_aut_frlist_az/ID=483385&chr=K +http://www.ebigchina.com/msg_post.phtml?cu=1003 +http://www.bemi-immobilien.de/allgemeine-ib/startseite/Gemeinsam/erreichenPartner/Gemeinsam/versicherungen/lebensversicherung/Gemeinsam/immolink/Gemeinsam/MarketingStrategie/Gemeinsam/Inserieren/onlineInserieren.htm +http://ftp.tku.edu.tw/OS/Linux/distributions/RedHat/rawhide/i386/doc/rhinst/stylesheet-images/?S=A +http://www.egroups.com/message/kicken/284 +http://www.guangmingdaily.com.cn/0_gm/1999/12/19991222/big5/gm^18278^2^GM2-2216.htm +http://brightnet.pda.tucows.com/www.psionsite.rcsed.ac.uk/ +http://www.symatrixinc.com/website/website.nsf/0/3e40df86fb357cd5882568720079613f!OpenDocument&ExpandSection=9,22,1,11 +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=durereste&l=it +http://click-to.tell-a-friend.boardhost.com/tell-a-friend-confirm.cgi?ylihilseen&msg=25 +http://www.gbgm-umc.org/EllisvilleMO/10-04-00.pdf +http://www.marketingtool.com/contribute/webfirm/b.435.r.2626.g.4134.html +http://www.chaos.dk/sexriddle/h/a/w/l/ +http://www.chaos.dk/sexriddle/h/a/w/t/ +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+9,5-0,3+( +http://www.guba.net/101/136/125E/index-4.phtml +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+9,5-0,3+21,0 +http://www.guba.net/101/136/125E/index-7.phtml +http://www.guba.net/101/136/125E/index-15.phtml +http://ftpsearch.belnet.be/ftp/mirror2/ftp.cert.dfn.de/pub/vendor/sun/security-alert/security-alert-108.txt +http://ftpsearch.belnet.be/ftp/mirror2/ftp.cert.dfn.de/pub/vendor/sun/security-alert/security-alert-170.txt +http://www.tente.de/us/produkte/rubriksuche/ad000000699.htm +http://www.angelfire.com/ky/kysweetpea/ +http://yp.gates96.com/7/69/60/1.html +http://www.amulation.com/md-l-archive/199908/frm00208.html +http://yp.gates96.com/7/69/60/4.html +http://yp.gates96.com/7/69/60/33.html +http://yp.gates96.com/7/69/60/49.html +http://yp.gates96.com/7/69/60/71.html +http://nanjingnews.jlonline.com/nanjingnews/njrb/20000226/04tiyu.htm +http://yp.gates96.com/7/69/61/44.html +http://yp.gates96.com/7/69/61/69.html +http://yp.gates96.com/7/69/61/82.html +http://yp.gates96.com/7/69/61/85.html +http://yp.gates96.com/7/69/62/4.html +http://yp.gates96.com/7/69/63/34.html +http://yp.gates96.com/7/69/63/48.html +http://yp.gates96.com/7/69/63/66.html +http://yp.gates96.com/7/69/64/22.html +http://www.bemi-immobilien.de/IIM-Teil/Startseite/Gemeinsam/MarketingStrategie/Gemeinsam/Inserieren/Startseite/Gemeinsam/versicherungen/unfall/Gemeinsam/3d-service/info.htm +http://yp.gates96.com/7/69/64/26.html +http://yp.gates96.com/7/69/65/89.html +http://yp.gates96.com/7/69/67/11.html +http://yp.gates96.com/7/69/67/28.html +http://yp.gates96.com/7/69/67/33.html +http://yp.gates96.com/7/69/67/70.html +http://yp.gates96.com/7/69/68/22.html +http://yp.gates96.com/7/69/68/72.html +http://yp.gates96.com/7/69/68/92.html +http://members.tripod.com/~katenleo/fading21.html +http://yp.gates96.com/7/69/69/6.html +http://members.tripod.com/~katenleo/fading26.html +http://yp.gates96.com/7/69/69/36.html +http://yp.gates96.com/7/69/69/91.html +http://yp.gates96.com/7/69/69/98.html +http://www.tribuneindia.com/98oct11/head1.htm +http://fi.egroups.com/message/internet-sig-announce/3 +http://info.verwaltung.uni-freiburg.de/doc/susehilf/pak/paket_inhalt_libxml.html +http://www.planetweb.com/cgi-bin/listmanager.pl/NETLINK-CUST/archives/1998Mar30-Apr05.archive/Date/article-23.html +http://www.maasvlakte-cam.nl/webcams/11/katowice__poland/2000/06/13/ +http://www.eveclub.com/cgi-bin/eveclub.front/972959521459/Home +http://totalsports.aol.com/stats/bbo/int/20000413/nor.at.lou.box.html +http://totalsports.aol.com/stats/bbo/int/20000413/ott.at.buf.game.html +http://fi.egroups.com/message/stccg-badlands/67 +http://www.fogdog.com/cedroID/ssd3040183315704/nav/stores/books_videos/ +http://xf-bbs.hb.cninfo.net/~socrates/sportold/images/football/_vti_cnf/ +http://cisc.tu-graz.ac.at/igi/lehre/semD_ss99/gruppe3/node10.html +http://in.egroups.com/message/sfconsim-l/8643 +http://ftp.cc.chuo-u.ac.jp/home/pub/lang/perl/CPAN/modules/by-authors/Karl_Glazebrook/ExtUtils-F77-1.13.readme +http://ftp.cc.chuo-u.ac.jp/home/pub/lang/perl/CPAN/modules/by-authors/Karl_Glazebrook/PGPLOT-2.17.readme +http://coe.ier.hit-u.ac.jp/BibEc/data/Papers/wopwobaiu2243.html +http://coe.ier.hit-u.ac.jp/BibEc/data/Papers/wopwobaiu2386.html +http://books.hyperlink.co.uk/bookinfo/Travel_Journal/0864427972 +http://dbc.copystar.com.tw/DelphiChat/200001/msg0650.htm +http://dbc.copystar.com.tw/DelphiChat/200001/msg0655.htm +http://dbc.copystar.com.tw/DelphiChat/200001/msg0666.htm +http://dbc.copystar.com.tw/DelphiChat/200001/msg0673.htm +http://dbc.copystar.com.tw/DelphiChat/200001/msg0681.htm +http://dbc.copystar.com.tw/DelphiChat/200001/msg0692.htm +http://www.expage.com/page/cavypigsponser +http://kernel2.adver.com.tw/Counter/log/kernel2.adver.com.tw/SaveCounter/2000-10-05/13/?S=A +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=210&discrim=214,253 +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=2&discrim=247,212,237 +http://wwwtios.cs.utwente.nl/archive/wilyfans/frm01740.html +http://z-06.land-sbg.gv.at/pressebuero/lpb/unserland/apr00/3.htm +http://z-06.land-sbg.gv.at/pressebuero/lpb/unserland/apr00/52.htm +http://gladstone.uoregon.edu/~sola/Stories/ +http://adetti.iscte.pt/RSI/HowTo/Java/jdk1.2.1/docs/guide/2d/api-jpeg/serialized-form.html +http://ocean.ntou.edu.tw/search*chi/aSloan,+Richard+P.,+jt.+ed./asloan+richard+p/-5,-1,0,E/frameset&F=asloan+irving+j&2,,0 +http://ttzcomputers.subportal.com/sn/Programming/C_and_C___Tools_and_Components/13286.html +http://ttzcomputers.subportal.com/sn/Programming/C_and_C___Tools_and_Components/1551.html +http://ftp.uni-stuttgart.de/pub/unix/tools/system/top/m/?N=D +http://no.egroups.com/message/romtrade/5216 +http://dk.egroups.com/message/Gunsmithing/80 +http://www.msb.malmo.se/search*swe/dMichelsen,+Hans/dmichelsen+hans/-5,-1,0,B/frameset&F=dmichels+robert&1,1 +http://solar.rtd.utk.edu/friends/news/omri/1998/05/980506I.html(opt,mozilla,pc,russian,koi8,default) +http://www.geocities.co.jp/HeartLand/6163/link8.htm +http://tucows.austria.com/sync95_size.html +http://tucows.austria.com/adnload/1082_30337.html +http://www.hotelboulevard.com/fr/paris/standard/html7752b1d358fd6459ebca66776e896614/sessionLang/ANG/prov/browse/cp/75015/resultatSearch.html +http://210.178.135.1/netbbs/Bbs.cgi/nhic30872/qry/zka/B2-kB2-o/pno/0/qqo/000A/qqatt/^ +http://210.178.135.1/netbbs/Bbs.cgi/nhic30872/new/pno/0/pno/0/qqo/000A +http://cometweb01.comet.co.uk/do!tid=20&rtid=2&vsid=700&session=132041&mid=1000&rid=1060&cid=37030&chid=1713&url=eqqLmwlGltt5tkZHljbLqkZHlkrHhlZHdfjKYfkLlkZ5ljjLboZLbplG5ubLZDXLZolLl3l5jbqLlci5XqVLkXsLkao4tloHbmlLoq5 +http://polygraph.ircache.net:8181/http_-2www.webtechs.com/html-val-svc/f-agents.html +http://www.linux.com/networking/network/development/communications/server/distro/ +http://www.linux.com/networking/network/development/communications/server/competition/ +http://www.linux.com/networking/network/development/communications/server/certification/ +http://www.linux.com/networking/network/development/communications/server/future/ +http://www.linux.com/networking/network/development/communications/server/Updates/ +http://people.freebsd.org/~knu/cgi-bin/cvsweb.cgi/ports/net/epic4/pkg/Attic/ +http://polygraph.ircache.net:8181/mo/mo_links/http_-2www.whowhere.com/tax_cuts.html +http://www.gov.ie/iveagh/angloirish/bloodysunday/summary4.htm +http://polygraph.ircache.net:8181/http_-2www.real-e-video.com/ftp_-2ftp.mpgn.com/Gaming/ADND/Worlds/BirthRight/MailingListArchive/Contents.htm +http://www.centc251.org/forums/aca-1/dispatch.cgi/isowg4/showNextUnseen/fol/100001/1323398 +http://www.centc251.org/forums/aca-1/dispatch.cgi/isowg4/folderFrame/100008/0/def/1323639 +http://user.alpha.co.kr/~selly/profile/main2.htm +http://polygraph.ircache.net:8181/company/http_-2www.aaainvestments.com/http_-2triad.cyberserv.com/http_-2207.90.134.3/miami/ +http://ring.htcn.ne.jp/pub/FreeBSD/FreeBSD-current/ports/archivers/zip/ +http://www.medoc-ias.u-psud.fr:81/synoptic/gif/950902/?S=A +http://in.egroups.com/message/GQRP/975 +http://idgnow.uol.com.br/idgnow/pcnews/2000/07/0046 +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kdebase/po/Attic/kdmconfig.pot?only_with_tag=beta1-0_2 +http://us.mandrakesoft.com/cgi-bin/cvsweb.cgi/kdebase/po/Attic/kwm.pot?only_with_tag=beta1-0_2 +http://lists.omnipotent.net/mysql/199912/msg02189.html +http://kyoto.cool.ne.jp/ryou_1125/lmax/list2.html +http://www.infodog.com/RESULTS/1998092302/1998092302800.HTM +http://www.infodog.com/RESULTS/1998092302/1998092302575.HTM +http://bedandbreakfast.com/bbc/p618230.asp +http://solaris.license.virginia.edu/os_product_patches/patches/5.5.1/103640-28/SUNWscpu/ +http://www.secinfo.com/d1Z36p.5n.htm +http://cn.egroups.com/messages/conscious_creation/2087 +http://www.brio.de/BRIO.catalog/39fdb4fb08541c02273fd472aa7806a2/UserTemplate/13 +http://www.chaos.dk/sexriddle/o/m/e/z/ +http://cgi.tbs.co.jp/cdtv/songdb/song1897-j.html +http://www.niwl.se/wais/new/12/12116.htm +http://bsdweb.pasta.cs.uit.no/bsdweb.cgi/~checkout~/pkgsrc/editors/vim-xaw/pkg/?sortby=log +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=boguerait&l=fr +http://www.medbulletin.com/scripts/medscape/jobsbystate.pl/diima00001/ND +http://ttz.soyou.edu.cn/tgyd/item/2000-05-31/3214.html +http://ttz.soyou.edu.cn/tgyd/item/2000-05-25/2973.html +http://ttz.soyou.edu.cn/tgyd/item/2000-05-23/2825.html +http://javatest.a-net.nl/servlet/pedit.Main/http://salon.com/tech/feature/2000/02/25/chatscan/ +http://javatest.a-net.nl/servlet/pedit.Main/http://www.wired.com/news/news/technology/story/20734.html +http://www.jps.net/fehlberg/diem9.html +http://chellobe.linux.tucows.com/x11html/adnload/9798_3876.html +http://chellobe.linux.tucows.com/x11html/preview/58190.html +http://internet.exit.de/akpolitik/Extern.htm +http://www.launch.com/music/albumpage/pvn_content/0,5258,163242_track,00.html +http://merumo.ne.jp/backno/i/00005163/20001001060103_024859.html +http://ftpsearch.belnet.be/mirrors/ftp.isc.org/pub/usenet/control/bc/?N=D +http://www-lehre.inf.uos.de/manuals/jdk1.2/docs/api/javax/swing/text/html/parser/class-use/Element.html +http://ftp.tku.edu.tw/OS/FreeBSD/ports/biology/deft/distinfo +http://javatest.a-net.nl/servlet/pedit.Main/http://www.cavejunction.com/phones/gower1.html +http://javatest.a-net.nl/servlet/pedit.Main/http://www.cavejunction.com/phones/contel1.html +http://www.allkorea.co.jp/cgi-bin/allkorea.front/972959966349/Catalog/1000002 +http://yp.gates96.com/5/82/41/1.html +http://yp.gates96.com/5/82/41/52.html +http://yp.gates96.com/5/82/41/59.html +http://yp.gates96.com/5/82/42/40.html +http://yp.gates96.com/5/82/42/73.html +http://yp.gates96.com/5/82/43/4.html +http://yp.gates96.com/5/82/43/20.html +http://yp.gates96.com/5/82/44/60.html +http://yp.gates96.com/5/82/44/95.html +http://yp.gates96.com/5/82/45/36.html +http://yp.gates96.com/5/82/45/43.html +http://yp.gates96.com/5/82/45/90.html +http://yp.gates96.com/5/82/46/37.html +http://yp.gates96.com/5/82/46/83.html +http://yp.gates96.com/5/82/47/22.html +http://yp.gates96.com/5/82/47/53.html +http://yp.gates96.com/5/82/48/8.html +http://yp.gates96.com/5/82/48/23.html +http://yp.gates96.com/5/82/48/41.html +http://yp.gates96.com/5/82/48/76.html +http://yp.gates96.com/5/82/49/5.html +http://yp.gates96.com/5/82/49/22.html +http://yp.gates96.com/5/82/49/37.html +http://yp.gates96.com/5/82/49/39.html +http://yp.gates96.com/5/82/49/65.html +http://yp.gates96.com/5/82/49/90.html +http://www.mirror.kiev.ua:8084/paper/1998/35/1251/power.htm +http://www.science.uva.nl/pub/NetBSD/NetBSD-current/pkgsrc/textproc/html/Makefile +http://www.fiss.at/1Root/Kontinent/6/Staat/7/Bundesland/16/Ort/708/Infrastruktur/7435/Homepage/homepage...1.html +http://linux.tnc.edu.tw/CPAN/authors/id/C/CH/CHOGAN/Apache-SetWWWTheme-1.02.readme +http://linux.tnc.edu.tw/CPAN/authors/id/C/CH/CHOGAN/Apache-SetWWWTheme-1.04.readme +http://linux.tnc.edu.tw/CPAN/authors/id/C/CH/CHOGAN/Apache-SetWWWTheme-1.05.readme +http://wufs.wustl.edu/vlander/vl_0002/browse/html/B0XX/22b090b4.htm +http://www.dnet.org/My_Locality/View_Statement.dnet/OH/43230-1863&SubjectItemID=6406&IssueID=47541&ElectionActivityID=4443&SubjectHolder=3462&type=Office&debate=yes +http://members.tripod.co.jp/suguruE/_private/ +http://members.tripod.lycos.nl/Kreeklaan/id19_cf.htm +http://forums.multimania.fr/general/login/login.phtml?_login=%2Flire%2Fjeuxvideospro%2Findex.phtml%3Fcollapse%3D1 +http://excite.de.netscape.com/jobs/katalog/30434 +http://excite.de.netscape.com/jobs/katalog/27370 +http://excite.de.netscape.com/jobs/katalog/127 +http://yp.gates96.com/2/54/20/79.html +http://yp.gates96.com/2/54/21/27.html +http://yp.gates96.com/2/54/22/14.html +http://yp.gates96.com/2/54/22/48.html +http://yp.gates96.com/2/54/22/78.html +http://yp.gates96.com/2/54/23/20.html +http://yp.gates96.com/2/54/23/62.html +http://yp.gates96.com/2/54/23/69.html +http://yp.gates96.com/2/54/24/1.html +http://yp.gates96.com/2/54/24/61.html +http://yp.gates96.com/2/54/24/95.html +http://yp.gates96.com/2/54/25/2.html +http://yp.gates96.com/2/54/25/16.html +http://yp.gates96.com/2/54/25/53.html +http://yp.gates96.com/2/54/25/67.html +http://yp.gates96.com/2/54/25/94.html +http://yp.gates96.com/2/54/26/3.html +http://yp.gates96.com/2/54/26/30.html +http://yp.gates96.com/2/54/26/65.html +http://yp.gates96.com/2/54/27/31.html +http://yp.gates96.com/2/54/27/41.html +http://yp.gates96.com/2/54/27/53.html +http://yp.gates96.com/2/54/27/71.html +http://yp.gates96.com/2/54/27/79.html +http://yp.gates96.com/2/54/27/80.html +http://yp.gates96.com/2/54/28/13.html +http://yp.gates96.com/2/54/28/14.html +http://yp.gates96.com/2/54/28/24.html +http://yp.gates96.com/2/54/28/34.html +http://yp.gates96.com/2/54/28/96.html +http://yp.gates96.com/2/54/29/49.html +http://ftp.sunet.se/pub/NT/mirror-microsoft/KB/Q134/3/40.TXT +http://members.tripod.com/joellogan/_cranedisc/000001d9.htm +http://members.tripod.com/joellogan/_cranedisc/000001cd.htm +http://www.ualberta.ca/CNS/RESEARCH/Software/SAS/vms/z-inf-zd.htm +http://www1.galaxy.com/galaxy/Leisure-and-Recreation/Games/Computer-Games/Titles/Virtual-Reality/Golf.html +http://www1.galaxy.com/galaxy/Leisure-and-Recreation/Games/Computer-Games/Titles/Virtual-Reality/Red-Planet.html +http://www.uni-duesseldorf.de/ftp/ftp/software/opt/zlib-1.1.2/?N=D +http://acbanks.know-where.com/acbanks/cgi/selection?place=Cavecreek&state=AZ +http://yp.gates96.com/10/26/70/49.html +http://yp.gates96.com/10/26/70/83.html +http://yp.gates96.com/10/26/72/40.html +http://yp.gates96.com/10/26/74/89.html +http://yp.gates96.com/10/26/75/15.html +http://yp.gates96.com/10/26/75/19.html +http://yp.gates96.com/10/26/76/87.html +http://yp.gates96.com/10/26/78/18.html +http://yp.gates96.com/10/26/78/76.html +http://yp.gates96.com/10/26/78/78.html +http://yp.gates96.com/10/26/78/81.html +http://cpan.nitco.com/modules/by-module/Devel/ADESC/Pod-DocBook-0.03.readme +http://www2.el-mundo.es/nuevaeconomia/2000/NE047/NE047-03b.html +http://www.familyeducation.com/whatworks/inappr_material/entry/1,2549,1-10119-1948-3469,00.html +http://ftp.nodomainname.net/pub/linux/daemons/raid/beta/ +http://192.80.57.161/corp/press/vannet.html +http://digilander.iol.it/mirkodeli/Stagioni/CI6_index.html +http://www.world-of-webs.de/magdeburg-in-bildern/_inhalt/_statnif/rechts/035.htm +http://ftpsearch.belnet.be/mirrors/src.doc.ic.ac.uk/usenet/usenet-by-hierarchy/rec/travel/?D=A +http://mirrortucows.technet.it/winme/netmiscme_rating.html +http://my.egroups.com/message/imperiumlarp/3148 +http://ep.com/js/about/c7857/b0/34551.html +http://webcrawler-sports.excite.com/ncaab/matchup/pafmax/ +http://www2.dbusiness.com/Quotes/1,1125,MSP_CORE,00.html?Ticker=CORE +http://tucows.wlink.com.np/regist95_size.html +http://www.babyheirlooms.com/catalog/htmlos.cat/041162.1.5960744054 +http://www.v2music.com/Scripts/WebObjects-ISAPI.dll/V2_New_Publisher.woa/71113000008423000000947720000021551/Labels.wo/168310000011551/1.0.1/3/Webobjects1 +http://www.v2music.com/Scripts/WebObjects-ISAPI.dll/V2_New_Publisher.woa/71113000008423000000947720000021551/Labels.wo/168310000011551/1.1.3.0.0/3/Webobjects1 +http://www.adcentral.com/cgi-bin/w3com/pws/adsites/vNhIXgVh_sji0rjcKc_GbuSlgBaEnCmKXU4ARmeefaqktCE3zwLsoXKDK_dlzoBzk2Ygr2cAuqN51PKOA0JxjzLEpPe-kic9TtvUJMbXG9Dlw8SggmHugQpwzjo-NiuofbUz4obq +http://ring.omp.ad.jp/archives/NetBSD/NetBSD-current/src/distrib/i386/floppies/ramdisk-big/Makefile +http://unofficial.capital.edu/students/alittle/ +http://213.36.119.69/do/session/153005/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/reserver/promotions/promo9.html +http://213.36.119.69/do/session/153005/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/GB_EN/ +http://www.riello-hamburg.de/mSerieRSBLU_130_465kw.htm +http://tucows.knoware.nl/winnt/filesplitnt_license.html +http://www.kaos.dk/sex-riddle/k/a/k/i/n/h/b/b/ +http://www.kaos.dk/sex-riddle/k/a/k/i/n/h/b/c/ +http://caller-times.com/1999/july/13/today/national/3143.html +http://news.fm365.com/jiaoyu/20000804/113896.htm +http://variety.studiostore.com/browse/ILOVELUCY/CAP/b.FAVORITES%20NOSTALGI%20CLASTV%20ILOVELUCY/s.qyPsT2fz +http://www.ferien-immobilien.de/bayern/ingolstadt/Verkauf/Gemeinsam/Immolink/3d-service/Private-IB/Startseite/Gemeinsam/vertriebspartner.htm +http://jefferson.village.virginia.edu/wax/japanese/0front/cd/1/1a2a9a2.html +http://space.tin.it/scuola/ermenegh/thewall/il2.htm +http://www.maasvlakte-cam.nl/webcams/17/kremlin__moscou__russia/2000/02/29/?D=A +http://pub17.ezboard.com/fecilordsoflightgeneral.showMessage?topicID=211.topic +http://pub17.ezboard.com/fecilordsoflightgeneral.showMessage?topicID=214.topic +http://pub17.ezboard.com/fecilordsoflightgeneral.showMessage?topicID=210.topic +http://www.kaos.dk/sexriddle/x/u/e/s/p/ +http://www.kaos.dk/sexriddle/x/u/e/s/q/ +http://amc.hollywood.com/maltin/k/kellysheroes-1970.htm +http://amc.hollywood.com/maltin/k/kidsarealrightthe-1979.htm +http://amc.hollywood.com/maltin/k/killingofsistergeorgethe-1968.htm +http://amc.hollywood.com/maltin/k/kingandcountry-1964.htm +http://amc.hollywood.com/maltin/k/kinglear-1987.htm +http://amc.hollywood.com/maltin/k/kingofthezombies-1941.htm +http://amc.hollywood.com/maltin/k/kingqueenknave-1972.htm +http://amc.hollywood.com/maltin/k/kissthe-1988.htm +http://www.egroups.com/login.cgi?login_target=%2Fgroup%2Ft-ida +http://polygraph.ircache.net:8181/faculty/http_-2www.stopwaste.org/freecontent.html +http://kutschen.de/Schoner/literature/Literatur/models/collections/ +http://www.incestpornstories.com/cum-sex-pics/anal-sexone-night-stand/big-bonedpleasantly-plump/smallwomen/{hardcorelink} +http://www.nytimes.com/library/financial/102897market-turmoil.html +http://polygraph.ircache.net:8181/services/define/http_-2www.microsoft.com/ie/http_-2www.ci.alameda.ca.us/main_left.html +http://polygraph.ircache.net:8181/services/define/http_-2www.microsoft.com/ie/http_-2www.ci.alameda.ca.us/dream.htm +http://www.chiayi.gob.tw/ +http://www.maas.ccr.it/cgi-win/hiweb.exe/a17/d77/b77,c,4d,51,51,df1,df1,,4e,2b62,4d,4e,2b62,, +http://citeseer.nj.nec.com/cidcontext/6361 +http://citeseer.nj.nec.com/cidcontext/6456 +http://utenti.tripod.it/Psychozine/Grunge/Creed_MyOwnPrison.htm +http://tucows.multiweb.net/winme/adnload/138210_30315.html +http://tucows.multiweb.net/winme/adnload/138190_29551.html +http://tucows.multiweb.net/winme/adnload/138218_29576.html +http://tucows.multiweb.net/winme/preview/138219.html +http://playsky.home.chinaren.com/star_region/11.htm +http://tucows.phnet.fi/winme/adnload/137614_29054.html +http://www.fortunecity.com/millennium/blyton/118/www.bih.net.ba/~sda +http://www11.informatik.tu-muenchen.de/lehre/lectures/ws2000-01/hypermedia/extension/html-kurz/hm2.2.4.2-navigation.html +http://ads.puntopartenza.com/cgi-bin/redirect.cgi/31033737 +http://www.eud.com/1997/03/20/20324A.shtml +http://ftp.net.uni-c.dk/pub/linux/mandrake/i586/Mandrake/mdkinst/usr/share/locale/gl/?N=D +http://no.sport.yahoo.com/s/snowboard-1.html +http://www.egroups.com/login.cgi?login_target=%2Fmessages%2Fshamanism%2F1311 +http://yp.gates96.com/5/82/70/13.html +http://yp.gates96.com/5/82/70/74.html +http://yp.gates96.com/5/82/71/30.html +http://yp.gates96.com/5/82/71/44.html +http://yp.gates96.com/5/82/72/22.html +http://yp.gates96.com/5/82/72/72.html +http://yp.gates96.com/5/82/72/88.html +http://yp.gates96.com/5/82/73/60.html +http://yp.gates96.com/5/82/73/79.html +http://yp.gates96.com/5/82/74/21.html +http://yp.gates96.com/5/82/74/59.html +http://yp.gates96.com/5/82/74/62.html +http://yp.gates96.com/5/82/74/75.html +http://yp.gates96.com/5/82/74/78.html +http://yp.gates96.com/5/82/75/30.html +http://yp.gates96.com/5/82/75/32.html +http://yp.gates96.com/5/82/75/82.html +http://yp.gates96.com/5/82/76/16.html +http://yp.gates96.com/5/82/76/43.html +http://yp.gates96.com/5/82/76/72.html +http://yp.gates96.com/5/82/77/48.html +http://yp.gates96.com/5/82/77/99.html +http://yp.gates96.com/5/82/78/73.html +http://yp.gates96.com/5/82/79/28.html +http://yp.gates96.com/5/82/79/70.html +http://yp.gates96.com/5/82/79/83.html +http://polygraph.ircache.net:8181/http_-2www.microsoft.com/ie/http_-2www.petrophysics.com/http_-2www.uio.no/~thomas/lists/info.html +http://www.munster-express.ie/000623/sports1.htm +http://cisne.sim.ucm.es/search*spi/aThiollier,+François-Joël,+int./athiollier+francois+joel+int/-5,-1,0,B/marc&F=athion+soriano+molla+dolores&2,,2 +http://www.zjdaily.com.cn/gb/2000/10/05/zjrb0625/guoji/6.htm +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceStoreCategories-BBC70A38_9815_E7A26CDF19A4AB167DD4B69EFB5B17FC +http://commerce.was-inc.com/cgi-bin/abtwsam.dll/LbkWebCommerceUserProfile-BBC70A38_9815_E7A26CDF19A4AB167DD4B69EFB5B17FC +http://www.shopworks.com/tools/index.cfm/action/search/userid/0003875B-2E5B-19FE-AF65010C0A0A8CF2 +http://www.doofpot.nl/~lists/bugtraq/October-99/frm00087.html +http://shop.citde.net/b79923.htm +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=divinizzarono&l=it +http://pub8.ezboard.com/fwrestlecarwwf.showAddReplyScreenFromWeb?topicID=38.topic +http://amrr.com/agents/contact.html?Agents_id=4046 +http://www.intellicast.com/LocalWeather/World/UnitedStates/Southeast/NorthCarolina/CarolinaBeach/RAINcast/d1_12/bannerAd.shtml +http://www.ferien-immobilien.de/schleswig-holstein/nordfriesland/Verkauf/Gemeinsam/versicherungen/gebaeude/Allgemeine-IB/IIM-Teil/Startseite/Gemeinsam/Inserieren/inserieren.htm +http://www.ferien-immobilien.de/schleswig-holstein/nordfriesland/Verkauf/Gemeinsam/versicherungen/gebaeude/Allgemeine-IB/IIM-Teil/Startseite/Gemeinsam/feedback.html +http://de.excite.com/jobs/katalog/10349 +http://pub16.ezboard.com/frealitycheck95307youadoreus.showAddReplyScreenFromWeb?topicID=33.topic +http://www.maas.ccr.it/cgi-win/hiweb.exe/a17/d2424/b77,e,4d,51,51,df1,df1,,978,,51,978,815,,51,815, +http://dk.egroups.com/message/noholdsbarred/2138 +http://kr.news.yahoo.com/headlines/so/20001029/hankook/2000102919513187338.html +http://www.buybuddy.com/sleuth/27/1/11002/508910/ +http://yp.gates96.com/13/95/50/10.html +http://yp.gates96.com/13/95/50/47.html +http://yp.gates96.com/13/95/51/16.html +http://yp.gates96.com/13/95/51/17.html +http://yp.gates96.com/13/95/51/21.html +http://yp.gates96.com/13/95/51/76.html +http://yp.gates96.com/13/95/53/5.html +http://yp.gates96.com/13/95/54/17.html +http://yp.gates96.com/13/95/54/44.html +http://yp.gates96.com/13/95/54/67.html +http://yp.gates96.com/13/95/54/80.html +http://yp.gates96.com/13/95/55/67.html +http://yp.gates96.com/13/95/56/15.html +http://yp.gates96.com/13/95/56/91.html +http://yp.gates96.com/13/95/57/9.html +http://yp.gates96.com/13/95/57/12.html +http://yp.gates96.com/13/95/57/24.html +http://yp.gates96.com/13/95/57/30.html +http://yp.gates96.com/13/95/57/46.html +http://yp.gates96.com/13/95/58/38.html +http://yp.gates96.com/13/95/58/52.html +http://yp.gates96.com/13/95/58/80.html +http://yp.gates96.com/13/95/59/40.html +http://yp.gates96.com/13/95/59/78.html +http://ftp.net.uni-c.dk/pub/linux/mandrake/i586/Mandrake/mdkinst/usr/share/locale/gv/?S=A +http://home.swipnet.se/~w-10458/sksida.htm +http://www.irishnews.com/k_archive/260799/nnews14.html +http://dennou-q.geo.kyushu-u.ac.jp/library/Linux/debian-jp/dists/potato-jp/contrib/binary-all/admin/?M=A +http://ayasii.virtualspace.net/html/1104/11041141_syuuei_yosimi008.htm +http://ayasii.virtualspace.net/html/1104/11041104_nakamura_yuma_2_027.htm +http://kikakusvr3.city.yokohama.jp/yhspot/ysc/prelaunch.html +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=0,1-20,0-9,1-9,2 +http://209.52.189.2/discussion.cfm/disco_music/7738/79749 +http://www.du-et.net/cgi/mail.cgi?NickName=coota +http://ustlib.ust.hk/search*chi/a%7B214c7d%7D%7B213837%7D%7B213c44%7D%7B213779%7D%7B214267%7D%7B21586d%7D%7B21515b%7D%7B21517c%7D%7B213966%7D/a{214c7d}{213837}{213c44}{213779}{214267}{21586d}{21515b}{21517c}{213966}/7,-1,0,B/browse +http://user.alpha.co.kr/~backspin/CGI-BIN/upload/files/ +http://194.174.50.23/cgi-bin/FisRun/InsertExhibitorIntoNotebook/1/interpack99/e/1217 +http://www.paxcapital.com/news/datacenter/200010/27/20001027180508_01.shtml +http://www.paxcapital.com/news/datacenter/200010/27/20001027175828_07.shtml +http://www.paxcapital.com/news/datacenter/200010/27/20001027173309_53.shtml +http://www.paxcapital.com/news/datacenter/200010/27/20001027165004_52.shtml +http://genforum.genealogy.com/cgi-bin/print.cgi?lantz::325.html +http://mirror.cc.utsunomiya-u.ac.jp/mirror/FreeBSD/ports/alpha/packages-current/x11-toolkits/?D=A +http://hotop.on.net.cn/diguo/club/disp.asp?owner=A205&ID=914 +http://www.babyheirlooms.com/catalog/htmlos.cat/041137.1.3501106310 +http://debian.linux.org.tw/debian/dists/frozen/non-free/binary-m68k/mail/?N=D +http://cafe5.daum.net/Cafe-bin/Cafe.cgi/member?cafe=LOTTEcleaning +http://www-d0.fnal.gov/cgi-bin/cvsweb.cgi/root_gui/data/?sortby=date +http://www.concentric.net/~Psaros/DbzUncensored/editorial/edit06-07-98.html +http://www.jobvillage.com/channel/jobs/travel/travel_guide/b.4897.g.5093.html +http://www.jobvillage.com/channel/jobs/travel/travel_guide/b.4897.g.5070.html +http://www.cricket.org/link_to_database/ARCHIVE/1999/OTHERS+ICC/NL_LOCAL/EERSTEKL/VCC_ASIAN-SHAH_EERSTEKL_16MAY1999.html +http://health.phinfo.sc.cn/navigator/illness_treatment/diseases_conditions/bone_diseases/spinal_column_injury/default.htm +http://cn.egroups.com/message/dfwscan/1412 +http://www.babyheirlooms.com/catalog/htmlos.cat/001255.1.1999922108 +http://ibm1.cicrp.jussieu.fr/ibmc/classref/ref/UFullStopNumber_DSC.htm +http://pda.tucows.fi/palm/adnload/33651_21862.html +http://www.fogdog.com/cedroID/ssd3040183330232/nav/products/nhl/chicago_blackhawks/fan/gender/fashion_polo_shirts/ +http://www.fogdog.com/cedroID/ssd3040183330232/nav/products/nhl/chicago_blackhawks/fan/gender/nylon_jackets/ +http://www.5a8.com/book/wg/zpj/d/delaisai/mgbj/004.htm +http://www.5a8.com/book/wg/zpj/d/delaisai/mgbj/050.htm +http://jars.developer.com//classes/jresout.cgi?resource=1133 +http://dwp.bigplanet.com/billbritton/files/edit.nhtml +http://members.tripod.co.jp/snow4/?D=A +http://www.lanoticia.com.ni/cronologico/2000/julio/15sabado/capital/capital5.html +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/151/1996/4/0/870960/ +http://mayu.sourceforge.net/cgi-bin/nph-ml.cgi/000/http/www.geocrawler.com/archives/3/151/1996/4/0/870950/ +http://ftp.ccu.edu.tw/pub/packages/dns/bind/src/8.1.1/ +http://www.chez.com/photographies/photos/paysage/page8.htm +http://www.ayto-malaga.es/Organismos/Urbanismo/PGMOM/Hojas/calificacion/3/47/34734.htm +http://www.symatrixinc.com/website/website.nsf/0/3e40df86fb357cd5882568720079613f!OpenDocument&ExpandSection=3,24,5,18 +http://www.symatrixinc.com/website/website.nsf/0/3e40df86fb357cd5882568720079613f!OpenDocument&ExpandSection=9,24,5,18 +http://variety.studiostore.com/browse/STARWARSTRIL/PHOTO/b.MOVIES%20STARWARSSAGA%20STARWARSTRIL/s.5FhZToe4 +http://www.stud.ntnu.no/~kjonigse/pod/ +http://eastday.com/epublish/gb/paper10/20001025/class001000011/hwz225792.htm +http://eastday.com/epublish/gb/paper10/20001025/class001000011/hwz225253.htm +http://www.jamba.de/KNet/_KNet-KdS8j1-IHd-13g8y/browse.de/node.0/cergpnwyt +http://www.la-verdad.com/pg000828/suscr/primera.htm +http://www.centc251.org/forums/aca-1/dispatch.cgi/hsi/listUnseen/fol/100020/20,0/1338881 +http://ftp.du.se/disk4/FreeBSD/ports/ports/japanese/libicq/pkg-comment +http://www.geocities.com/SunsetStrip/Towers/2395/ +http://www.geocities.com/joanna_luo +http://www.geocities.com/eric_wang_tafe +http://www.geocities.com/shsugiharto +http://wynnsystems.com/79I_5ase/seek/modifyUser.html +http://www.uk.cricket.org/link_to_database/INTERACTIVE/REVIEWS/BOOKS/barry14.html +http://perso.wanadoo.fr/alain.falgas/poesie1.htm +http://www.linux.com/networking/network/windows_nt/support/tools/SAP/ +http://www.rdnet.nl/provstaten1999/491ps.html +http://www.thisislancashire.co.uk/lancashire/archive/1998/03/19/FEATURES3VQ.html +http://myhome.naver.com/myclass46 +http://www.bride.ru/htcgi/ladies/in-26-30/index3.html +http://www.internet-verzeichnis.de/branchen/schuhreparaturen/nordrhein-westfalen/ +http://dk.egroups.com/post/SonyMavica?act=reply&messageNum=3370 +http://www.sneezy.org/Databases/Composers/Instrumentation/008889.html +http://www.sneezy.org/Databases/Composers/Instrumentation/009161.html +http://fatema2.math.nat.tu-bs.de/doc/sdb/de/html/keylist.LARGEEBDA.html +http://ssb.no/kommuner/hoyre_side.cgi?region=1931 +http://www.egroups.com/subscribe/mentemalata +http://www.debian.org.cn/Bugs/db/67/67056-b.html +http://dk.egroups.com/message/ssrdistribution/775?source=1 +http://link.fastpartner.com/do/session/600429/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/shopnett.php +http://ftp.uk.debian.org/debian/dists/stable/main/binary-arm/text/?D=A +http://www.bemi-immobilien.de/IIM-Teil/Startseite/Top-Darlehens-Konditionen/Gemeinsam/3d-service/Startseite/Gemeinsam/erreichenPartner/Top-Darlehens-Konditionen/anforderungsformular.htm +http://www.fujian-window.com/Fujian_w/news/mdrb/000816t/1_4.html +http://scholar.lib.vt.edu/VA-news/WDBJ-7/script_archives/98/0798/070498/?D=A +http://polygraph.ircache.net:8181/services/define/html/President.asp +http://old-maps.co.uk/10lancs191/HTML/nav_19034001g.htm +http://www.hanter21.co.kr/NetBBS/Bbs.dll/prdata/lst/qqa/f/qqo/000D/zka/B2-kB2-r +http://w3.webtourist.net/travel/europe/italy/milan/quarkallsuites.htm +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,5+0,0-9,6-0,1 +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=brillantant&l=fr +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=brillantais&l=fr +http://www.mathquest.com/~sarah/HTMLthreads/geopre.descriptions.html +http://www.retrobytes.org/classiccmp/9706/msg00827.html +http://www.retrobytes.org/classiccmp/9706/msg01408.html +http://www.rdnet.nl/provstaten1999/552ps.html +http://retailer.gocollect.com/do/session/1912828/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/checkout/shopping_cart.asp +http://retailer.gocollect.com/do/session/1912828/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/exclusives/limited_editions.asp +http://retailer.gocollect.com/do/session/1912828/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/company_info/privacy_policy.asp +http://de.news.yahoo.com/000322/36/nfqj.html +http://www.kl.gz.cn/~cco/FUNA022K.htm +http://www.launch.com/music/artistpage/pvn_content/0,5219,1013738_videos,00.html +http://www14.freeweb.ne.jp/play/kiryuus/keith-burn1-end.htm +http://variety.studiostore.com/help/b.MOVIES%20STARWARSSAGA%20STARWARSTRIL/s.BmesFhV7 +http://biblioteca.upv.es/bib/doc/doc_siglibros/1828105/26/25/////MLTPAID/Materia%20Lengua%20inglesa%20técnica:%20254/V +http://www.outpersonals.com/cgi-bin/w3com/pws/out/_AhIPkFr0_eq7P6TUMbkQGJgpHJOXqtNLZQ55qFmeZARJaJUKHP9RBX3tPWaLEWVLZ_-PAErnbukTTJzs-x0hew4G_r3S85M8fDFaJcIVi3EA4TxNjTbbGIaSLhr8VdNICuBwhPmgZEt662B +http://www.outpersonals.com/cgi-bin/w3com/pws/out/IxhI6dPotFAZDugwPbV2pjvsgvIvAP-oFtIZfMptEKMo48cUO8RmvG3Akuk2tktzM_RYBY3yIQE6nl7I2moLEV_nScO7wTfWpFfPR7LHZ3ntJxKS8-a_IukWT4q_o6mjhGw8SSwm +http://www.rge.com/pub/languages/perl/clpa/1995-11/171 +http://www.rge.com/pub/languages/perl/clpa/1995-11/186 +http://www.newmgm.com/cgi-bin/c2k/title_talent.html&id=146091&title_star=FOURFEAT +http://www.koreaweekly.co.kr/entertain/book/200009/en20000922185938E701133.htm +http://www.koreaweekly.co.kr/entertain/book/200008/en20000824183337E701112.htm +http://www.genome.wustl.edu:8021/pub/gsc10/nci/wl/wl72/?N=D +http://yp.gates96.com/13/50/70/33.html +http://yp.gates96.com/13/50/70/36.html +http://yp.gates96.com/13/50/70/53.html +http://yp.gates96.com/13/50/71/74.html +http://yp.gates96.com/13/50/72/13.html +http://yp.gates96.com/13/50/72/17.html +http://yp.gates96.com/13/50/72/83.html +http://yp.gates96.com/13/50/73/48.html +http://yp.gates96.com/13/50/73/79.html +http://yp.gates96.com/13/50/73/96.html +http://yp.gates96.com/13/50/74/14.html +http://yp.gates96.com/13/50/74/57.html +http://yp.gates96.com/13/50/75/13.html +http://yp.gates96.com/13/50/75/19.html +http://yp.gates96.com/13/50/75/30.html +http://yp.gates96.com/13/50/75/42.html +http://yp.gates96.com/13/50/75/53.html +http://yp.gates96.com/13/50/75/90.html +http://yp.gates96.com/13/50/77/45.html +http://yp.gates96.com/13/50/77/51.html +http://yp.gates96.com/13/50/77/79.html +http://yp.gates96.com/13/50/78/12.html +http://yp.gates96.com/13/50/78/47.html +http://yp.gates96.com/13/50/78/69.html +http://yp.gates96.com/13/50/78/96.html +http://www.tel.de/s/M/MSS.htm +http://linux.usu.edu/LDP/LDP/LG/issue23/shoham/node4.html +http://www.monaco.gouv.mc/dataweb/gouvmc.nsf/(NewsActu)/d28eaee29b3287d4c1256905004e1ef1!OpenDocument&ExpandSection=9,3,10.1,7,10.4,10.2,5,8,4 +http://fi.egroups.com/post/romtrade?act=reply&messageNum=5198 +http://www.outpersonals.com/cgi-bin/w3com/pws/out/erhIHCd-6X--WwWIQBR9tYYraJWo8ugur0GyAl8pg21sE-lotAURKodv9HAYnRuTT4ZM0aCKsA5ZVLlq8sgiFNqA4DyAY_GVTyPIEARrzArj8JrWabVCSpg03afQ_Xg3DaCQA17080y7T4EZ +http://oneplace.adbureau.net/accipiter/adclick/site=ONEPLACE/area=INDEX/POSITION=BLOCK_1/AAMSZ=120x90/ACC_RANDOM=619055616855 +http://cafe6.daum.net/Cafe-bin/Bbs.cgi/MyLoveNYpds/qry/zka/B2-kB23m/qqatt/^ +http://cafe6.daum.net/Cafe-bin/Bbs.cgi/MyLoveNYpds/qry/zka/B2-kB2-s/qqatt/^ +http://sas.uoregon.edu/sashtml/proc/z0292518.htm +http://www02.geocities.co.jp/PowderRoom-Rose/1346/flower02image.html +http://www02.geocities.co.jp/PowderRoom-Rose/1346/sozaiheart2.html +http://www.jamba.de/KNet/_KNet-sXN8j1-9Hd-13ej3/admLogin.de/node.0/cdn3r3qy3 +http://iccardreader.co.kr/ +http://online.linux.tucows.com/conhtml/ser_irc_size.html +http://www.fogdog.com/cedroID/ssd3040183339940/nav/products/winter_sports/1b/bibs/ +http://www.fogdog.com/cedroID/ssd3040183339940/nav/products/winter_sports/1c/jackets/ +http://www.fogdog.com/cedroID/ssd3040183339940/nav/products/winter_sports/1d/heavyweight_tops/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380883/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/assistance/entry.asp +http://www.kaos.dk/sex-riddle/k/a/k/i/l/y/t/c/ +http://www.kaos.dk/sex-riddle/k/a/k/i/l/y/t/o/ +http://ftp1.se.debian.org/debian/dists/stable/main/disks-alpha/2.2.8-2000-03-08/jensen/ +http://213.36.119.69/do/session/153006/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/FR/contact/recrute.htm +http://www10.freeweb.ne.jp/photo/myukun2/cosplay/000130/0130_40.htm +http://l-infonet.phkk.fi/fi/TIETOPALVELUT/JULKINEN+HALLINTO/tiedonhaku/artikkelit/hakupalvelut/l%E4%E4ketiede/tietokannat/ +http://202.109.72.57/article/20000903/67099.htm +http://www.outpersonals.com/cgi-bin/w3com/pws/out/5xhIsrJ5LBhn_gBogN2-VgQ1DA6WvBlLMjSoxYeQAJ1ig69sK1i1DhQ5hA3iOw7y6Wb_HDA2rkG5aJy9DrUMZxD31cyUqEqg7LeZ3pssb70DsyPc1sGCTVIRFBz1Nb_1ikEcJ3ds +http://ftp.gwdg.de/pub/misc/standards/infomagic/nist/oiw/agreemnt/read_me.txt +http://linuxberg.arrakis.es/conhtml/adnload/8894_17109.html +http://ring.toyama-ix.net/archives/pc/winsock-l/WWW-Browsers/Plug-In/ppp16124.txt +http://opac.lib.ntnu.edu.tw/search*chi/++ftlist/bp20040288/-5,-1,0,B/frameset&F=bp20040286&1,1 +http://ftp.darenet.dk/tucows/winme/adnload/137475_28966.html +http://ftp.darenet.dk/tucows/winme/adnload/137525_29009.html +http://elib.zib.de/pub/UserHome/Mueller/Course/Tutorial/Postscript/US/?M=A +http://greenpeace.lu/Admin/usage/weekly/1999/01/03/ +http://greenpeace.lu/Admin/usage/weekly/1998/04/26/ +http://greenpeace.lu/Admin/usage/weekly/1998/08/16/ +http://greenpeace.lu/Admin/usage/weekly/1997/10/12/ +http://retailer.gocollect.com/do/session/1912819/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/clubhouse/index.asp +http://www.kusastro.kyoto-u.ac.jp/LCs/index/AURAU.html +http://www.linux.com/networking/network/windows_nt/support/microsoft/Red_Hat/ +http://www.linux.com/networking/network/windows_nt/support/microsoft/operating_system/ +http://www.linux.com/networking/network/windows_nt/support/microsoft/SAP/ +http://www.linux.com/networking/network/windows_nt/support/microsoft/Unix/ +http://www.linux.com/networking/network/windows_nt/support/microsoft/pop-3/ +http://www.cs.rit.edu/photo_album/smr3632.html +http://www.cpan.dk/CPAN/modules/by-authors/id/C/CH/CHRMASTO/?D=A +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/lit/misc/unitest/lit/music/midi/ego.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/lit/misc/unitest/lit/music/midi/lit/multiple.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/lit/misc/unitest/lit/music/midi/misc/dissert.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/computers/lit/misc/unitest/lit/music/midi/misc/peanuts.html +http://www.eastsidejournal.com/sited/retr_story.pl/25409 +http://yp.gates96.com/8/46/50/23.html +http://yp.gates96.com/8/46/52/6.html +http://yp.gates96.com/8/46/52/10.html +http://yp.gates96.com/8/46/52/18.html +http://yp.gates96.com/8/46/52/25.html +http://yp.gates96.com/8/46/53/78.html +http://yp.gates96.com/8/46/53/95.html +http://yp.gates96.com/8/46/54/26.html +http://yp.gates96.com/8/46/54/41.html +http://yp.gates96.com/8/46/54/64.html +http://yp.gates96.com/8/46/54/76.html +http://yp.gates96.com/8/46/54/92.html +http://yp.gates96.com/8/46/55/62.html +http://yp.gates96.com/8/46/55/94.html +http://yp.gates96.com/8/46/55/98.html +http://yp.gates96.com/8/46/56/19.html +http://yp.gates96.com/8/46/56/42.html +http://yp.gates96.com/8/46/56/86.html +http://yp.gates96.com/8/46/58/53.html +http://yp.gates96.com/8/46/58/57.html +http://yp.gates96.com/8/46/59/41.html +http://yp.gates96.com/8/46/59/44.html +http://yp.gates96.com/8/46/59/84.html +http://yp.gates96.com/8/46/59/99.html +http://www.158.com.cn/news/2000/09/03/58946.htm +http://www.pobladores.com/territorios/juegos/Shanodin/pagina/2 +http://www.otemachi.ibm.co.jp/pc/vlp/ca20/32l9068/price.html +http://www.gutenberg2000.de/lessing/sinnged/sinna10.htm +http://www.gutenberg2000.de/lessing/sinnged/sinn138.htm +http://www.gutenberg2000.de/lessing/sinnged/sinnc27.htm +http://www.gutenberg2000.de/lessing/sinnged/sinnc06.htm +http://calcul.si.uji.es/Programes/SAS/stat/chap4/sect5.htm +http://calcul.si.uji.es/Programes/SAS/stat/chap4/sect6.htm +http://link.fastpartner.com/do/session/600436/vsid/3194/tid/3194/cid/137201/mid/1060/rid/2105/chid/3194/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/learn.htm +http://www.linux.com/networking/network/red_hat/performance/workstations/business/ +http://ftp.dei.uc.pt/pub/faqs/backrubs/faq/?D=A +http://www2.el-mundo.es/nuevaeconomia/2000/NE022/NE022-16b.html +http://ring.toyama-ix.net/pub/linux/linuxppc-jp/2.0/UsersGuide/?N=D +http://www.egroups.com/message/swchicks-rpg/763 +http://webraft.its.unimelb.edu.au/705195/students/caitlinb/pub/?N=D +http://cn.egroups.com/message/indexinvesting/17 +http://networkdesigner.subportal.com/sn/Programming/Setup_Utilities/11753.html +http://www.imagestation.com/member/?name=Mermaid34v&c=1 +http://crn.com/Components/TalkBack/tb-read.asp?ArticleId=8463 +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/misc/lit/computers/music/linux/misc/thoughts/turingtest.html +http://www.egroups.com/message/house_caliburnus/1479 +http://pub14.ezboard.com/BBSForum.showForumSearch?boardName=bleemtest +http://spaceports.tucows.com/winme/adnload/136943_28461.html +http://www.cerent.com/warp/public/767/spcl/vaccess/req-lab.html +http://www.ualberta.ca/icons/icons/numbers/Big-orange-thin/ +http://www.gencat.es/cgi-bin/bc/drawer.cgi/LD/0004/A00027?98 +http://interhotel.com/romania/en/hoteles/49235.html +http://www.infoscape.com.cn:8171/nf/0001/19/nfzx1908.htm +http://www.hurriyetim.com/akdeniz/turk/00/05/25/akdhab/62akd.htm +http://www.hurriyetim.com/akdeniz/turk/00/05/25/akdhab/38akd.htm +http://dennou-t.ms.u-tokyo.ac.jp/arch/cc-env/Linux/debian-jp/dists/woody-jp/contrib/binary-ia64/misc/?M=A +http://www.angelfire.com/vt/Mystical2 +http://www.indonesiansources.com/HELP/COOKIES.HTM +http://members.nbci.com/cmeadows/gvi/45regt/45gvibat.html +http://members.nbci.com/cmeadows/gvi/45regt/45gvicob.html +http://landview.census.gov/hhes/www/housing/soma/char96/ch96tab5.html +http://www.legis.state.pa.us/WU01/LI/BI/TI/1985/0/MNPENNSYLVANIAdENERGYdASSISTANCEdANDdCONSERVATIONdACT.HTM +http://www.legis.state.pa.us/WU01/LI/BI/TI/1985/0/MNPENNSYLVANIAdSEWAGEdFACILITIESdACT.HTM +http://www.legis.state.pa.us/WU01/LI/BI/TI/1985/0/MNPODIATRYdPRACTICEdACT.HTM +http://www.legis.state.pa.us/WU01/LI/BI/TI/1985/0/MNPRESIDENT.HTM +http://www.legis.state.pa.us/WU01/LI/BI/TI/1985/0/MNPRIVATEdMORTGAGEdINSURANCEdACT.HTM +http://www.legis.state.pa.us/WU01/LI/BI/TI/1985/0/MNPROJECTd500.HTM +http://www.legis.state.pa.us/WU01/LI/BI/TI/1985/0/MNPUBLICdWORKSdCONTRACTdREGULATIONdLAW.HTM +http://oss.sgi.com/cgi-bin/cvsweb.cgi/inventor/apps/samples/4view/Attic/Imakefile?only_with_tag=MAIN +http://oss.sgi.com/cgi-bin/cvsweb.cgi/inventor/apps/samples/4view/Attic/Imakefile?only_with_tag=HEAD +http://www4.50megs.com/justiceinn/charpages/leaves/707.html +http://www4.50megs.com/justiceinn/charpages/leaves/859.html +http://www4.50megs.com/justiceinn/charpages/leaves/171.html +http://www4.50megs.com/justiceinn/charpages/leaves/114.html +http://megalink.tucows.com/win2k/adnload/38582_28844.html +http://members.tripod.lycos.nl/monthlysports/hello_and_welkom_at_the_new.htm +http://coe.ier.hit-u.ac.jp/BibEc/data/Papers/nbrnberwo4558.html +http://coe.ier.hit-u.ac.jp/BibEc/data/Papers/nbrnberwo4462.html +http://coe.ier.hit-u.ac.jp/BibEc/data/Papers/nbrnberwo4813.html +http://pub4.ezboard.com/factiveprodiscussioncommunityhottopicsresidentsandalcohol.showMessage?topicID=3.topic +http://207.138.41.133/subscribe/IndoVStudio +http://www.biuemountain.com/eng3/karen/EArejoice.html +http://polygraph.ircache.net:8181/wwwboard/capabilities/http_-2www.westnebr.net/http_-2www.excite.com/grservic.htm +http://pub7.ezboard.com/fturonneuemissionennebenwerteundsonstigewerte.showAddReplyScreenFromWeb?topicID=58.topic +http://dk.egroups.com/post/badbart-showdown?act=forward&messageNum=679 +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus62920/eus62921/eus64894/eus170276/eus163832/ +http://www.algonet.se/~d88628/engelsk/various.htm +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=220&discrim=220,215,11 +http://www.z-plus.de/TEXTE/INETCO/AUSG20000524/text7.html +http://www.gbnf.com/genealog2/varner/html/d0059/I11636.HTM +http://www.musiciansfriend.com/ex/ds/live/001030183152064208037007463633 +http://www.musiciansfriend.com/ex/ds/home/001030183152064208037007463633?dbase=info,order_info.html +http://www.musiciansfriend.com/ex/ds/guitar/amps/001030183152064208037007463633?dbase=info,contact.html +http://pix.egroups.com/message/ipe/1642?source=1 +http://213.36.119.69/do/session/153008/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://resa.travelprice.com/CallCenter/InitCommunicationAgence +http://213.36.119.69/do/session/153008/vsid/1113/tid/1113/cid/28507/mid/1020/rid/1041/chid/1103/parser/yes/imref/eqqLmwlGltt5tkqHoXsLbimLofZLbkZHljlK6IlK/url/http://www.travelprice.com/DE_DE/ +http://www.egroups.com/message/peninsulaserv/567 +http://www.scifi.com/bboard/browse.cgi/1/5/545/12425?pnum=3 +http://no.egroups.com/post/icc-info?act=reply&messageNum=759 +http://www.chaos.dk/sexriddle/s/e/x/e/c/s/l/ +http://www.chaos.dk/sexriddle/s/e/x/e/c/s/t/ +http://www.nissan.co.jp/RENAULT-DEALERS/PASSPORT/view.cgi/search/972959630-- +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=6,29,20,36,32 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=7,29,20,36,32 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=27,29,20,36,32 +http://dada.linuxberg.com/gnomehtml/adnload/31471_2540.html +http://augustasports.com/football99/college/box_50347.shtml +http://augustasports.com/football99/college/box_50365.shtml +http://augustasports.com/football99/college/box_50423.shtml +http://www.linux.com/networking/network/enterprise/e-commerce/management/open_source/ +http://usol.pdacentral.com/winnt/preview/1946.html +http://usol.pdacentral.com/winnt/preview/78287.html +http://usol.pdacentral.com/winnt/preview/1338.html +http://usol.pdacentral.com/winnt/preview/12860.html +http://usol.pdacentral.com/winnt/preview/6920.html +http://usol.pdacentral.com/winnt/preview/51381.html +http://ring.htcn.ne.jp/pub/lang/perl/CPAN/authors/id/W/WO/?N=D +http://grybrd.subportal.com/sn/Network_and_Internet/Text_Chat_Clients/index1.html +http://www.gurlpages.com/lacej/part13.html +http://ring.shibaura-it.ac.jp/archives/mac/info-mac/game/com/wolf/?D=A +http://cgi.cnnsi.com/baseball/mlb/nl/gamelog/2000/10/07/mets_giants/ +http://my.egroups.com/messages/not_honyaku/236 +http://members.tripod.com/agran_gassendi/Countdown.htm +http://www.tccomputers.com/cgi-bin/bp/1878637479/showcase/showcase.htm +http://207.138.41.133/message/AikensTrivia/264 +http://207.138.41.133/message/AikensTrivia/276 +http://www.shumway.org/thetree/ped13583.htm +http://link.fastpartner.com/do/session/600421/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/dk/ +http://link.fastpartner.com/do/session/600421/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/politiken.php +http://link.fastpartner.com/do/session/600421/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/company/jobs.htm +http://in.egroups.com/message/canada/856 +http://in.egroups.com/message/canada/883 +http://debian.tod.net/OpenBSD/src/lib/libssl/README.OPENBSD +http://www.emerchandise.com/main/EMERCH/s.1M38gYrZ +http://www.emerchandise.com/browse/TOYSTORY2/FIGURINE/b.FAVORITES%20COMICS%20ANIMFEAT%20TOYSTORY2/s.1M38gYrZ +http://quotidiano.monrif.net/chan/cronaca_nazionale:410879.1:/1999/12/24 +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=baignes&l=fr +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=baignas&l=fr +http://www.egroups.com/message/swchicks-rpg/93 +http://usuarios.tripod.es/jlgolis/id142_l.htm +http://www9.freeweb.ne.jp/shopping/nossy/baby/200-59.html +http://www9.freeweb.ne.jp/shopping/nossy/baby/305-36.html +http://ftp.tku.edu.tw/OS/NetBSD/NetBSD-1.3.2/alpha/binary/kernel/?D=A +http://www-1.cisco.com/univercd/cc/td/doc/product/wanbu/82/access/fpmpmm12/fpmmappe.pdf +http://pub17.ezboard.com/fartofnorrathfavoritepaintings.threadControl?topicID=56.topic +http://itcareers.careercast.com/texis/it/itjs/+pwwBmew_D86eGrwwwqFqygdMpwDOeWXqqBcneWkjnwBneWkxqBOeWRlmmOtFqewyXwotoBwcaMwDwtnanmowcdt1naqconDBaGncwBodD5ropa5BGwBnton5amnVncdpaMwGAnBoDtanMwocaGn51MnaMFqryfHfREIDzmbwwwpBmFe-B-dehxwww5rmXmwwBrmeZpwww/morelike.html +http://www.thestateofcolorado.com/aoubicycling.html +http://www.freespeech.org/DISjak/disnews/maillist.html +http://www.freespeech.org/DISjak/sport/schwimm/bestlist.html +http://www.amigos.com/cgi-bin/w3com/pws/ffe/_MhIXE2wgPJZ1X047wqRwM-olUgaV3vI6fBPmDsoD0c26y7TrHjLUhhhTSIZ2PRmqLmBVyInWJLkLGkKScrdFyX1uyXCZhvaWFvbnSFioewAURJcXQC-hJE5KczVcMUiq3ncgKjQh7nynQEu662C +http://m.home.cern.ch/m/mrashid/www/cuisine/cuisin13.htm +http://m.home.cern.ch/m/mrashid/www/cuisine/cuisin28.htm +http://www.dayoo.com/channel/stock/news/cjzh/09/0921/06.htm +http://webcvs.kde.org/cgi-bin/cvsweb.cgi/KodeKnight/lib/Makefile.am?r1=1.3&sortby=rev +http://www.fogdog.com/cedroID/ssd3040183315779/nav/products/featured_brands/12p/all/ +http://www.fogdog.com/cedroID/ssd3040183315779/nav/stores/baseball/ +http://www.fogdog.com/cedroID/ssd3040183315779/nav/stores/squash/ +http://www9.hmv.co.uk:5555/do/session/1347832/vsid/199/tid/199/cid/1061396/mid/1020/rid/1052/chid/1029/parser/yes/imref/eqqLmwlGltt5tkeHjskKZlkKrhlK/url/http://www.hmv.co.uk/hmv/newmenu.html +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=9,36,8 +http://www.arm.com/sitearchitek/support.ns4/html/cores_faq!OpenDocument&ExpandSection=24,36,8 +http://www.hig.se/(append,countdown,set,sqloutput,sqltable)/~jackson/roxen/ +http://ring.jec.ad.jp/archives/linux/kernel.org/kernel/people/mingo/raid-patches/raid-2.2.17-A0 +http://www.wsrn.com/apps/links/?s=BKIRF +http://www.auto.ru/wwwboards/mercedes/0163/ +http://www.auto.ru/wwwboards/mercedes/0142/ +http://www.auto.ru/wwwboards/mercedes/0132/ +http://www.auto.ru/wwwboards/mercedes/0002/ +http://www.auto.ru/wwwboard/mercedes/0014/ +http://www.presa.spb.ru/newspapers/dp/arts/dp-178-art-12.html +http://pub8.ezboard.com/fnirlcomcenterracetalk.showMessage?topicID=8.topic +http://www.allhealth.com/pregnancy/labor/qa/0,3105,599,00.html +http://www3.newstimes.com/archive99/sep0499/lce.htm +http://jupiter.u-3mrs.fr/~msc41www/PSHTM/PS4330.HTM +http://www.gpul.org/ftp/os/linux/cd-images/other/suse/dosutils/pfdisktc/ +http://platsbanken.amv.se/kap/text/88/001025,010050,240907,10,0107051488.shtml +http://www.angel-bastel-zoo.de/detail/detail_811_3.htm +http://members.nbci.com/cmeadows/gvi/3battn/3bgvicob.html +http://www.chaos.dk/sexriddle/s/e/x/x/p/o/r/ +http://www.asiastockwatch.com/sg/Forum/ForumDetails/0,1819,561_1_2:15,00.html +http://mysanantonio.sportshuddle.com/sports/football/health/advisors/workouts/huff12.asp +http://mysanantonio.sportshuddle.com/sports/football/health/advisors/workouts/huff1.asp +http://ring.data-hotel.net/pub/linux/debian/debian-jp/dists/unstable/contrib/source/math/ +http://www.tel.de/s/I/IFG.htm +http://www.tel.de/s/I/IFHV.htm +http://chat.hr-online.de/fs/buecherbuecher/buch/kerr.html +http://mirror.cc.utsunomiya-u.ac.jp/mirror/FreeBSD/branches/2.2-stable/src/sys/dev/ +http://mirror.cc.utsunomiya-u.ac.jp/mirror/FreeBSD/branches/2.2-stable/src/sys/nfs/ +http://www.malaysia.net/lists/sangkancil/1998-12/msg01044.html +http://biblio.cesga.es:81/search*gag/aFerreiro,+Martín/aferreiro+martin/-5,1,1,E/frameset&F=aferreiro+manuel&4,,4 +http://www.ferien-immobilien.de/DominikanischeRep/verkauf/Exklusiv-IB/Startseite/Gemeinsam/MarketingStrategie/Exklusiv-IB/Startseite/Gemeinsam/erreichenPartner/email3d.htm +http://www.ferien-immobilien.de/DominikanischeRep/verkauf/Exklusiv-IB/Startseite/Gemeinsam/MarketingStrategie/Exklusiv-IB/Startseite/Gemeinsam/IIMMitglieder.htm +http://chunma.yeungnam.ac.kr/~home/home13/msgboard/msgboard.cgi?cmd=list&stat=start +http://link.fastpartner.com/do/session/600413/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/local/redirect.php +http://www.eyeball.symantec.co.uk/region/se/sepress/20000418111220.htm +http://www.rezel.enst.fr/ftp/linux/distributions/debian/CD-1/dists/frozen/main/binary-all/news/?D=A +http://www.latimes.com/editions/orange/20001028/p000103070_ome0014.html +http://www.chaos.dk/sexriddle/j/c/u/t/ +http://cometweb01.comet.co.uk/do!session=132050&vsid=694&tid=20&cid=37044&mid=1000&rid=1060&chid=1711&url=eqqLmwlGltt5tkkHbqpLZXmLbkZHljlKaltLkilLXalKfkaLbukKeqjLi1 +http://perso.wanadoo.fr/jm.michaud/electronique_index.htm +http://dk.egroups.com/messages/Gunsmithing/1446?viscount=-30 +http://www-d0.fnal.gov/d0dist/dist/releases/psim01.02.00/pmcs_met/VERSION +http://mirror.cc.utsunomiya-u.ac.jp/mirror/CPAN/authors/id/P/PM/?N=D +http://www.movieguide.com/pressroom/events/amcinema96/award_amcinema965.html +http://www.sda.t-online.de/reise/index/aktrex201.htm +http://dic.empas.com/show.tsp/SMASHER +http://www.3w-posters.com/tomlinson.htm +http://www.3w-posters.com/tuttle.htm +http://www.xmission.com/(art,dots,ftp,geek,misc,music,caffiene,art,toys,dots,edge,misc,shopping,ftp,places,privacy,geek,cuseeme,apocalypse,people,stuffiuse,places,stuffiuse)/~bill/links.html +http://www.osiris.978.org/~brianr/mirrors/olga/main/g/gangi_mike/?N=D +http://www.best.com/~workpage/g/57/300g.htm +http://www.cyd.com.cn/zqb/19991109/GB/9677^Q212.htm +http://edu.news.chinaren.com/161/10112157.shtml +http://users.info.unicaen.fr/~jjousset/perso/html/entrainperso/page.html +http://www.wordtheque.com/owa-wt/wordtheque_dba.w.t?w=destituiscono&l=it +http://www.uk.multimap.com/p/browse.cgi?pc=B771AA&cat=loc +http://www.auxerre.culture.gouv.fr/culture/actualites/conferen/bonneuil-duffour.htm +http://www.auxerre.culture.gouv.fr/culture/actualites/communiq/mediaBonneuil-Duffour.htm +http://www.ancientsites.com/~Ftagn_Sithathor +http://biblioteca.upv.es/bib/doc/doc_fisbd/86/127697//C/1820009/0////25/N/MLTPAI +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus53930/eus169714/eus169722/eus542057/eus542410/ +http://www.kfi640.com/shared/mod_perl/looksmart/looksmart/eus1/eus53930/eus169714/eus169722/eus542057/eus542106/ +http://pub26.ezboard.com/fathanasiafrm1.showMessage?topicID=113.topic +http://www.sourceforge.net/softwaremap/trove_list.php?form_cat=186&discrim=186,226,251 +http://www.linux.com/networking/network/community/future/news/services/ +http://www.linux.com/networking/network/community/future/news/operating_system/ +http://www.linux.com/networking/network/community/future/news/?kw_offset=50 +http://www.linux.com/networking/network/development/unix/open_source/commercial/ +http://ring.shibaura-it.ac.jp/pub/misc/ham/funet/packet/00Index +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+20,0+17,0-( +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=3,0+20,0+17,0-9,1 +http://www.vorlesungen.uni-osnabrueck.de/informatik/c98/aufgaben/code/aufg50/ProcessInfo/ProcessInfo.bundle/Resources/?D=A +http://wap.jamba.de/KNet/_KNet-xOQ8j1-xHd-13fk7/showInfo-special1.de/node.0/cde7f1uou +http://nx5.salon.com/books/col/keil/2000/05/02/too_old/index2.html +http://pcmagazin.de/news/artikel/1999/04/29016-wf.htm +http://www.redrival.com/rgrascher/ +http://208.184.36.144/cwi/subscriptions/privacy_policy/0,1323,NAV47-68-85-98_STO52856,00.html +http://www.staroriental.net/nav/soeg_c/ihf,aol,n12,1,TVB香港小姐2000.html +http://www.staroriental.net/nav/soeg_c/ihf,aol,n12,6,TVB香港小姐2000.html +http://166.111.104.242/uscode/30/541b.head.html +http://stocks.tradingcharts.com/stocks/charts/fwrx/dchart.php?S=fwrx&T=d +http://genforum.genealogy.com/cgi-bin/print.cgi?plemmons::57.html +http://www.geocities.co.jp/Hollywood-Studio/3572/geodiary.html +http://www.luf.org/~jwills/LufWiki/view.cgi/Tech/ +http://www.doc.ic.ac.uk/lab/labsrc_area/firstyear/submissions/cs1/labs/Ex01/arr00/?M=A +http://citeseer.nj.nec.com/ps/332798 +http://citeseer.nj.nec.com/addcomment/332798 +http://citeseer.nj.nec.com/cidcontext/4075337 +http://ftp.te.fcu.edu.tw/cpatch/helputil/answerworks/?M=A +http://ftp.te.fcu.edu.tw/cpatch/helputil/answerworks/d2hpro4ethanks.htm +http://link.fastpartner.com/do/session/600423/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/join/programmes/mondosoft.php +http://link.fastpartner.com/do/session/600423/vsid/2870/tid/2870/cid/136966/mid/1060/rid/1926/chid/2870/parser/yes/imref/eqqLmwlGltt5tkcHXpqLmXoLqkbLokZHljlK/url/http://www.fastpartner.com/company/ +http://library.cuhk.edu.hk/search*chi/dEnglish+language+--+Clauses./denglish+language+clauses/7,-1,0,B/browse +http://www04.u-page.so-net.ne.jp/yd5/yuma/top/home.html +http://www.smartshop.com/cgi-bin/main.cgi?c=1905&ssa=26 +http://www.smartshop.com/cgi-bin/main.cgi?c=1943&ssa=26 +http://se.egroups.com/dir/Business/Management/Project_and_Program_Management/Training?st=10 +http://www.hpl.online.sh.cn/WENXUE/tongsuo/wuxia/gulong/xueying/_vti_cnf/hs~001.htm +http://news.medscape.com/adis/PEON/public/archive/1999/toc-0221.html +http://news.medscape.com/adis/PEON/public/archive/1999/toc-0197.html +http://tucows.hongkong.com/winnt/adnload/4256_29575.html +http://www.etang.com/local/shenzhen/shopping/shop/0318mans02.htm +http://www.etang.com/local/shenzhen/shopping/shop/0319foll.htm +http://www.etang.com/local/shenzhen/shopping/shop/0319jialjs.htm +http://www.staffan.addr.com/cgi-bin/woda/icq.cgi/Edit?_id=2a5e +http://www.linux.com/networking/network/operating_system/kernel/distro/?printable=yes +http://www.linux.com/networking/network/operating_system/kernel/distro/commercial/ +http://www.linux.com/networking/network/operating_system/kernel/distro/white_dwarf/ +http://dir.dig.co.kr/parents/textbook/20301030101.html +http://www.affiliate.hpstore.hp.co.uk/do/session/380895/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/fr/CASHBACK/entry.asp +http://ccuftp.ccu.edu.tw/pub1/chinese/linux/clinux/c1/?N=D +http://cgi.cnnsi.com/basketball/college/women/boxscores/2000/03/07/cbp_rak +http://www.adcentral.com/cgi-bin/w3com/pws/adsites/5BRIztXQWHs_H_kyq8hmyrHpmCLb5RfQ09-DcKP1B6mZibAiJTLy1w3iiFS15WkFiCHMuMtjNK5FtHPDtZ7rxwckgoj0GaicnAZxhJLQ3zWaLoNUq8eTpG7wCxe3TWAb66jt +http://www.varsity.cam.ac.uk/varsity/live/2000/listings.nsf/44bbd1c2a6305036802567fb0081c76b!OpenView&Grid=1&Date=1999-04-06 +http://students.lsu.edu/students/main.nsf/Pages/CSISAJ1!OpenDocument&ExpandSection=15,21,5,4 +http://students.lsu.edu/students/main.nsf/Pages/CSISAJ1!OpenDocument&ExpandSection=18,21,5,4 +http://www.getplus.co.jp/category/catinet.homepagew2.asp +http://www.motorradversand.de/cgi-bin/antrieb/kettensatz_komplett_suzuki/RK82K872/beurteilung.htm +http://202.99.23.245/zdxw/13/20000328/200003281335.html +http://proxy.tiscover.com/1Root/Kontinent/6/Staat/7/Bundesland/22/Ort/120/Infrastruktur/299270/Homepage/homepage...1.html +http://www.jamba.de/KNet/_KNet-RcO8j1-cHd-13eq4/browse.de/node.0/cdel3j591 +http://www.jamba.de/KNet/_KNet-RcO8j1-cHd-13eqf/showInfo-wir.de/node.0/cde7f1uou +http://pub6.ezboard.com/fcrazyassmb47001generalshiznit.threadControl?topicID=685.topic +http://perso.infonie.fr/imagestld/photojyg5/images/alive5/?D=A +http://members.spree.com/sip1/take5planet/videos.htm +http://ae.boston.com/haiku/vote?haiku_id=4484 +http://adex3.flycast.com/server/socket/127.0.0.1:2800/click/OnlineCitiesSM/OnlineCitiesInteractiveCityGuides/bd129601192 +http://www.digitaldrucke.de/(aktuell,computer,marktplatz,shopping,verkehr)/suche/uebersicht.html +http://www.digitaldrucke.de/(aktuell,computer,hersteller,marktplatz,verkehr)/_fort/html/themen/computer/hard/herstell.htm +http://bbs.kcm.co.kr/NetBBS/Bbs.dll/kcmmission/lst/qqeq/1/zka/B2-kD2-l/qqo/004A +http://bbs.kcm.co.kr/NetBBS/Bbs.dll/kcmmission/rcm/zka/B2-kD2-l/qqo/004A/qqatt/^ +http://ftp.eq.uc.pt/software/lang/tcl/ftp.scriptics.com/nightly-cvs/tk/library/?S=A +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-141.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-165.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-241.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-239.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-150.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-44.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-12.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-4.html +http://www.infomedia.it/cgi-bin/lwgate/JAVA-IT/archives/java-it.log.9704/Subject/article-27.html +http://yp.gates96.com/5/88/50/47.html +http://yp.gates96.com/5/88/50/94.html +http://yp.gates96.com/5/88/51/20.html +http://yp.gates96.com/5/88/52/11.html +http://yp.gates96.com/5/88/52/26.html +http://yp.gates96.com/5/88/53/86.html +http://yp.gates96.com/5/88/53/99.html +http://yp.gates96.com/5/88/54/48.html +http://yp.gates96.com/5/88/55/29.html +http://yp.gates96.com/5/88/55/31.html +http://yp.gates96.com/5/88/55/41.html +http://yp.gates96.com/5/88/55/62.html +http://yp.gates96.com/5/88/55/77.html +http://yp.gates96.com/5/88/56/62.html +http://yp.gates96.com/5/88/56/93.html +http://yp.gates96.com/5/88/59/61.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/2090.918081010.176207534.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/1123.920140263.921690399.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/19089.918231855.610311830.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/16059.919279797.801472096.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/24001.919906575.275033199.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/14848.918256026.548154577.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/10783.918253985.660158806.html +http://ceu.fi.udc.es:8000/mc/maillist/99-02/27581.918670666.1055622954.html +http://www.activedayton.com/sportsticker/stnd/current/BBH.STAT.FSLKISLTRT.html +http://www.teenplatinum.com/barelylegal/japanesewomen/boots/petitesmall/explodingblowjob/eunuchbodyshots/homosexualass.html +http://books.hyperlink.co.uk/xt1/Methodology_for_the_Harmonization_of_European_Occupational_Accident_Statistics/9282641007 +http://www.jpc-music.com/2563637.htm +http://www.jpc-music.com/8168850.htm +http://www.expage.com/sugarshackstablesapryl +http://www.egroups.com/messages/svlug/31105 +http://www.chinawolf.com/~warson/japan/chichuan/bride/mldxn/009.htm +http://www.chinawolf.com/~warson/japan/chichuan/bride/mldxn/011.htm +http://yp.gates96.com/11/78/70/19.html +http://yp.gates96.com/11/78/70/95.html +http://yp.gates96.com/11/78/71/64.html +http://yp.gates96.com/11/78/71/65.html +http://yp.gates96.com/11/78/72/30.html +http://yp.gates96.com/11/78/73/35.html +http://yp.gates96.com/11/78/74/0.html +http://yp.gates96.com/11/78/75/58.html +http://yp.gates96.com/11/78/76/75.html +http://yp.gates96.com/11/78/77/36.html +http://yp.gates96.com/11/78/77/64.html +http://yp.gates96.com/11/78/78/20.html +http://yp.gates96.com/11/78/78/33.html +http://yp.gates96.com/11/78/78/70.html +http://yp.gates96.com/11/78/78/93.html +http://yp.gates96.com/11/78/79/3.html +http://yp.gates96.com/11/78/79/50.html +http://ben.aspads.net/ex/c/190/649604396 +http://www.lifl.fr/PRIVATE/Manuals/java/jdk1.2/docs/api/java/applet/class-use/AudioClip.html +http://dic.empas.com/show.tsp/?q=cea&f=B +http://beautifulthemes.subportal.com/sn/Utilities/Disk_Maintenance_and_Repair_Utilities/5294.html +http://ustlib.ust.hk/search*chi/anational+bureau+of+economic+research/anational+bureau+of+economic+research/-5,-1,0,E/frameset&F=anational+bureau+of+asian+and+soviet+research+u+s&1,,0 +http://www.canlii.org/ca/regl/dors99-120/art5.html +http://www.canlii.org/ca/regl/dors99-120/partie144284.html +http://www.incestpornstories.com/freshmanteen/eggbirth-canal/loverdrag-queen/birth-canalfull-term/stomachvagina.html +http://www.fashion-j.com/bs/013/013/19.html +http://www.fjtcm.edu.cn/Fujian_w/news/fjgsb/990311t/1-3.htm +http://www.kaos.dk/sex-riddle/k/a/k/i/s/z/r/d/ +http://www.kaos.dk/sex-riddle/k/a/k/i/s/z/r/f/ +http://www.tccomputers.com/cgi-bin/bp/41291345/products/specials/mbbundle.htm +http://www.tccomputers.com/cgi-bin/bp/41291345/services/insight.htm +http://www.tccomputers.com/cgi-bin/bp/41291345/products/batterybackups/batterybackups.htm +http://cartografia.comune.modena.it/Ril_Whip/menuogg/001-100/ME0068c.htm +http://library.bangor.ac.uk/search/cWS+5+V196a+2000/cws++++5+v196+a+2000/7,-1,0,B/frameset&F=cws+++21+e84+1989&5,,12 +http://mindit.netmind.com/proxy/http://www.exposure.aust.com/~promote1/auspalaeo/tectonix/tect1.htm +http://ftp.fi.debian.org/debian/dists/unstable/non-free/binary-i386/shells/?S=A +http://excite.de.netscape.com/unterhaltung/katalog/19344 +http://www.symatrixinc.com/website/website.nsf/0/3e40df86fb357cd5882568720079613f!OpenDocument&ExpandSection=25,20,21,29 +http://www.burstnet.com/ads/ad7826a-map.cgi/1708189811 +http://dic.empas.com/show.tsp/?s=b&q=CONSIDERABLE +http://www.kaos.dk/sex-riddle/k/a/k/i/p/g/t/c/ +http://www.kaos.dk/sex-riddle/k/a/k/i/p/g/t/h/ +http://www.kaos.dk/sex-riddle/k/a/k/i/p/g/t/n/ +http://www.kaos.dk/sex-riddle/k/a/k/i/p/g/t/x/ +http://www.cbe21.com.cn/xueke/dili/jiaoxuezs/ziliaojn/tupianhc/i0602.htm +http://babycenter.netscape.com/bbs/3788/thread530/message9.html +http://polygraph.ircache.net:8181/http_-2www.harborbay.com/home/webstuff/companyprofile.htm +http://dante.bdp.it/cgi-bin/poseidon_v2.0/reflect/poseidon/disc/bibl-uno/512098188/threadconfig +http://dante.bdp.it/cgi-bin/poseidon_v2.0/reflect/poseidon/disc/bibl-uno/512098188/newconfig +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=5,1,16,25,13 +http://www2.hgo.se/Kurskatalogen.nsf/a49e2126c83c4922412566f60052f831/f24cc45affc890eec12565d80055e0b9!OpenDocument&ExpandSection=28,1,16,25,13 +http://ftp.sunet.se/pub/lang/perl/CPAN/authors/id/R/RH/?D=A +http://www.geocities.co.jp/SilkRoad/1618/nixxki/010799.html +http://genforum.genealogy.com/cgi-genforum/forums/americanrev.cgi?4444 +http://in.egroups.com/message/djgppgames/358 +http://freehost.crazyhost.com/teengallery/apbh/panty.html +http://buffy.acmecity.com/xander/366/EDpt2.htm +http://www.tccomputers.com/cgi-bin/bp/505218695/promotional/deals.htm +http://www.tccomputers.com/cgi-bin/bp/505218695/products/cooling/cooling.htm +http://www.tccomputers.com/cgi-bin/bp/505218695/products/dvds/dvds.htm +http://www.tccomputers.com/cgi-bin/bp/505218695/products/mice/mice.htm +http://www.tccomputers.com/cgi-bin/bp/505218695/services/register.htm +http://www.foxsports.com/nba/scores/2000/000129_playbyplay_clewas.sml +http://pub1.ezboard.com/fcellofuncellistsbynightsemiprooramateur.showAddReplyScreenFromWeb?topicID=513.topic&index=9 +http://yp.gates96.com/0/22/30/81.html +http://yp.gates96.com/0/22/31/89.html +http://yp.gates96.com/0/22/32/1.html +http://yp.gates96.com/0/22/32/12.html +http://yp.gates96.com/0/22/32/48.html +http://yp.gates96.com/0/22/32/78.html +http://yp.gates96.com/0/22/34/48.html +http://yp.gates96.com/0/22/34/75.html +http://yp.gates96.com/0/22/34/85.html +http://yp.gates96.com/0/22/35/38.html +http://yp.gates96.com/0/22/35/73.html +http://yp.gates96.com/0/22/36/40.html +http://yp.gates96.com/0/22/36/92.html +http://yp.gates96.com/0/22/37/0.html +http://yp.gates96.com/0/22/37/61.html +http://yp.gates96.com/0/22/37/96.html +http://yp.gates96.com/0/22/39/13.html +http://yp.gates96.com/0/22/39/94.html +http://www.incestpornstories.com/underageflashing/plus-sizereal-size/beautiesasian/purpleanal-sex/maledomfantasy/high-schoolpretty/cherrybest-friends.html +http://variety.studiostore.com/browse/ELMOINGROU/TOY/s.2vzELAA2 +http://members.tripod.lycos.nl/BOGAERT/off2.htm +http://www.eveclub.com/cgi-bin/eveclub.front/972959555004/Catalog/2000019 +http://genforum.genealogy.com/cgi-genforum/forums/noel.cgi?662 +http://www.affiliate.hpstore.hp.co.uk/do/session/380888/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-expo.com/FR/REGISTRATION/entry.asp +http://yp.gates96.com/5/88/10/35.html +http://yp.gates96.com/5/88/10/44.html +http://yp.gates96.com/5/88/11/36.html +http://yp.gates96.com/5/88/13/1.html +http://yp.gates96.com/5/88/13/23.html +http://yp.gates96.com/5/88/13/77.html +http://yp.gates96.com/5/88/13/86.html +http://yp.gates96.com/5/88/14/47.html +http://yp.gates96.com/5/88/14/83.html +http://yp.gates96.com/5/88/15/11.html +http://yp.gates96.com/5/88/16/43.html +http://yp.gates96.com/5/88/16/86.html +http://yp.gates96.com/5/88/17/6.html +http://yp.gates96.com/5/88/17/12.html +http://yp.gates96.com/5/88/17/73.html +http://yp.gates96.com/5/88/18/1.html +http://yp.gates96.com/5/88/18/38.html +http://yp.gates96.com/5/88/18/47.html +http://yp.gates96.com/5/88/18/79.html +http://newnova.tucows.com/winme/adnload/138430_29763.html +http://yp.gates96.com/8/43/60/48.html +http://yp.gates96.com/8/43/60/55.html +http://yp.gates96.com/8/43/61/22.html +http://yp.gates96.com/8/43/62/40.html +http://yp.gates96.com/8/43/62/52.html +http://yp.gates96.com/8/43/62/94.html +http://yp.gates96.com/8/43/63/79.html +http://yp.gates96.com/8/43/64/73.html +http://yp.gates96.com/8/43/64/80.html +http://yp.gates96.com/8/43/66/26.html +http://yp.gates96.com/8/43/66/70.html +http://yp.gates96.com/8/43/67/16.html +http://yp.gates96.com/8/43/68/11.html +http://yp.gates96.com/8/43/69/74.html +http://www.fogdog.com/cedroID/ssd3040183354487/nav/products/winter_sports/1d/mid-weight_bottoms/ +http://www.fogdog.com/cedroID/ssd3040183354487/nav/products/winter_sports/1r/avalanche_safety/ +http://www.fogdog.com/cedroID/ssd3040183354487/boutique/marmot/ +http://www.affiliate.hpstore.hp.co.uk/do/session/380898/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.france.hp.com/Main/acheterhp/ +http://www.nd.edu/~dtl/cheg258/unix/unixhelp1.2/Pages/tasks_rm1.1.1.html +http://se.egroups.com/post/cyclesi?act=reply&messageNum=137 +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=22,0+18,0+22,0+9,4 +http://cidade.subportal.com/sn/Games/Action_Games/8120.html +http://wiem.onet.pl/wiem/0115d9-rp1.html +http://www.ferien-immobilien.de/detmold/Verkauf/Gemeinsam/Inserieren/Allgemeine-IB/Startseite/Gemeinsam/MarketingStrategie/Gemeinsam/erreichen.htm +http://retailer.gocollect.com/do/session/1912826/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/product_display/products/product_lines.asp +http://retailer.gocollect.com/do/session/1912826/vsid/2092/tid/2092/cid/569192/mid/1540/rid/1980/chid/2085/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLl0/url/http://www.gocollect.com/halloween/halloween.asp +http://www.iabusnet.org:90/forums/aca-1/dispatch.exe/survey/listUnseen/fol/100001/20,0/2542788 +http://www.dispatch.co.za/1998/06/25/easterncape/BISHO.HTM +http://pub24.ezboard.com/fsosatanfrm1.showMessage?topicID=48.topic +http://ftpsearch.belnet.be/ftp/packages/Linux-docs/howto/other-formats/INDEX +http://www.crosswinds.net/~mluotto/noframe/feedback/form2.htm +http://www.schoolweb.nl/studentensteden/Rotterdam/SVRGaudium/info.cfm +http://www.shopworks.com/index.cfm/action/directory/userid/0000BD9A-2F67-19FE-9038010B0A0ADCF2 +http://findmail.com/messages/masterhuen/802 +http://www.t-dialin.net/navkopf/service/websvkaa.htm +http://gallery2.simplenet.com/lobby/main/videocaps/ebaral/bigvalley/ebbva19.htm +http://gallery2.simplenet.com/lobby/main/videocaps/ebaral/bigvalley/ebbva31.htm +http://www.outpersonals.com/cgi-bin/w3com/pws/out/44hIVEhY5ZrKWoMKb0FtjCXhqcpntVLId5WTaJdeZmonn200jiiswYnK2vORJkjpm-x643ZCeLyy6kJnIAKa5rNx_42I13Ud9N03G9xPob7Hoci92HJhOlbEv4WsB85Au-cLXFlIHPd866jS +http://ftp.debian.org/debian/dists/Debian2.2r0/main/binary-all/editors/?D=A +http://ftp1.support.compaq.com/patches/public/Digital_UNIX/v3.2g/mailworks/2.0/?S=A +http://www.digitalhearth.com/Recipes/World_Cuisines/South_Asian/Indian/index5.html +http://ftp.gigabell.net/pub/Stormix/dists/rain/main/?M=A +http://www.stas.net/1/theparamanor/apartment.htm +http://www.netcom.com/~gfenzil/free.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/misc/misc/thoughts/math/legendes/pages_new.html +http://www.eleves.ens.fr:8080/home/madore/index.shtml.fr/lit/misc/misc/thoughts/math/legendes/misc/orders_mag.html +http://dandini.cranfield.ac.uk/vl=-39658948/cl=171/nw=1/rpsv/catchword/routledg/13606719/contp1-1.htm +http://genforum.genealogy.com/cgi-genforum/forums/pugsley.cgi?81 +http://www.users.globalnet.co.uk/~mmayes/pages/cross.htm +http://dic.empas.com/show.tsp/?s=d&q=%C4%A7%BD%C7 +http://www.jamba.de/KNet/_KNet-rHP8j1-lHd-13f16/browse.de/node.0/cde7f1uou +http://library.bangor.ac.uk/search/aHolmgren,+Nils+Fritiof,+1877-1954/aholmgren+nils+fritiof+1877+1954/7,1,1,B/marc&F=aholmlund+chris&1,1, +http://www.spiral.at/Katalog/Artikel/0181030/ +http://www.spiral.at/Katalog/Artikel/0181242/ +http://www.generation-formation.fr/navig.htm---o21zAo06L2o0Ol9A074fo6VJGezMkEeIgI8eOkn2ApvFFo6Td4ezyr6feZJPdspt6dsSAtdsNhJdspt6dsrvrdjlhkfbz.htm +http://www.nextmedia.com.hk/netgirl/sport/images/chelsea/ch-30.htm +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,5-9,0-15,0-17,0 +http://www.realize.com/i82.htm,qt=35665aa9=645a273f-1a-31fa805-1-0-0-0-- +http://www.eud.com/1998/06/21/21121AA.shtml +http://www.eud.com/1998/06/21/21414AA.shtml +http://www.eud.com/1998/06/21/21434AA.shtml +http://chemtech.chinamarket.com.cn/E/Showdetail_company/5569.html +http://chemtech.chinamarket.com.cn/E/Showdetail_company/1095.html +http://www.ferien-immobilien.de/baden-wuertemberg/konstanz/Verkauf/Private-IB/Allgemeine-IB/Startseite/Gemeinsam/Immolink/Gemeinsam/MarketingStrategie/inhalt.htm +http://www.ferien-immobilien.de/baden-wuertemberg/konstanz/Verkauf/Private-IB/Allgemeine-IB/Startseite/Gemeinsam/Immolink/Gemeinsam/versicherungen/gebaeude/deckungsumfang.htm +http://retailer.gocollect.com/do/session/1912886/vsid/2312/tid/2312/cid/573127/mid/1020/rid/2147/chid/2210/parser/yes/imtarget/ImMainFrame/imref/eqqLmwlGltt5tkdHlZlLiibLZqkKZljLlZe5ofpLqjXLpl4/url/http://www.gocollect.com/company_info/terms_and_conditions.asp +http://eagle.synet.edu.cn/mirror/www.tuc.org.uk/ +http://eagle.synet.edu.cn/mirror/dcarolco.lanminds.com/home/ +http://www.chez.com/carabanon/Pagecabanon.htm +http://poetry.lezlisoft.com/kikelet/spiritualitas/lelekszinpad.shtml +http://lateline.muzi.net/ll/fanti/81373.shtml +http://www.egroups.com/message/vacuum/1140 +http://www.egroups.com/message/vacuum/1153 +http://www.egroups.com/message/vacuum/1157 +http://no.egroups.com/message/-1friendsliste/401 +http://no.egroups.com/message/-1friendsliste/411 +http://pike-community.org/(base=/forums/show.html,explode=146,forum=7,t=972959520359311)/forums/show.html +http://pike-community.org/(base=/forums/show.html,explode=512,forum=7,t=972959520359311)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=413,t=972959520359311)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=423,t=972959520359311)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=761,t=972959520359311)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=777,t=972959520359311)/forums/show.html +http://pike-community.org/(base=/forums/show.html,forum=7,show=831,t=972959520359311)/forums/show.html +http://astro1.cnu.ac.kr/NetBBS/Bbs.dll/bulletin/qry/zka/B2-kC2Jo/qqa/r +http://www.gbnf.com/genealog2/brothers/html/d0049/I1011.HTM +http://www.intellicast.com/Golf/World/UnitedStates/Midwest/Ohio/Zanesville/CurrentWinds/ +http://www.nada.kth.se/systemgruppen/docs/javadoc/jdk-1.3/docs/api/javax/swing/text/class-use/TabSet.html +http://www.my-cat.de/hunde/zucht/file24.htm +http://194.128.65.4/pa/cm199899/cmwib/wb981128/edms.htm +http://www.gutenberg2000.de/sagen/austria/tirol/adasbub.htm +http://www1.onelist.com/message/osaki/22 +http://www.highwired.net/ESchoolDrive/JumpPage/1,5565,25179-46,00.html +http://pcmagazin.de/download/library/deADW-wc.htm +http://www.affiliate.hpstore.hp.co.uk/do/session/380873/vsid/1148/tid/1148/cid/74115/mid/1001/rid/1003/chid/1050/parser/yes/imref/eqqLmwlGltt5tkeHmjbHumlLkZl5jlcHol4/url/http://www.hp-creativeworld.com/creativeworld.asp?lang=f +http://cscns.csc.gifu.gifu.jp/pushcorn-kit/tanigumi/paged/0300214020000147.html +http://cscns.csc.gifu.gifu.jp/pushcorn-kit/tanigumi/paged/0300214020002363.html +http://cscns.csc.gifu.gifu.jp/pushcorn-kit/tanigumi/paged/0300214020001617.html +http://cpan.nitco.com/modules/by-module/String/MLEHMANN/?N=D +http://www.rge.com/pub/tex/language/ethiopia/ethtex/lqh_fonts/ +http://130.158.208.53/WWW/PDB2/PCD4711/htmls/41.html +http://www.thisislancashire.co.uk/lancashire/archive/1997/05/15/LEIGH0VQ.html +http://www.thisislancashire.co.uk/lancashire/archive/1997/05/15/LEIGH10VQ.html +http://southwind.tukids.tucows.com/mac/parents/adnload/72310_26093.html +http://ftp1.support.compaq.com/public/vms/vax/v7.2/dsnlink/2.2/dsnlinke022.a-dcx_vaxexe +http://wynnsystems.com/i.I_5aGd/search/listCompanies.html +http://www.pobladores.com/territorios/juegos/Zhief_Fantasy_World/info +http://www.pobladores.com/territorios/juegos/Zhief_Fantasy_World/pagina/9 +http://www.aebius.com/rpm2html/contrib/libc5/i386/usr_sbin_Tree.html +http://info.rutgers.edu/cgi-bin/RUInfo/TallyStats/name=WebRequest&exec=buildlimit&limit=9,0-22,0-0,0-9,4 +http://polygraph.ircache.net:8181/services/define/http_-2www.fastcounter.com/noframes/specials.htm +http://polygraph.ircache.net:8181/services/define/http_-2www.fastcounter.com/noframes/sitebuilder.htm +http://www.jamba.nl/KNet/_KNet-7YT8j1-nD4-pxan/browse.nl/node.0/cdmvcam7k +http://www.outdoorwire.com/content/lists/jeepoffroad/200010/msg00234.html?{LoadingFrameset} +http://www-uk8.cricket.org/link_to_database/ARCHIVE/2000-01/ENG_IN_PAK/ENG_IN_PAK_OCT-DEC2000_ENG-SQUAD.html +http://www-uk8.cricket.org/link_to_database/ARCHIVE/CRICKET_NEWS/2000/OCT/057670_CI_25OCT2000.html +http://www.chaos.dk/sexriddle/c/c/e/k/ +http://ben.aspads.net/ex/c/190/608504034 +http://forum.rai.it/aca-finestre/dispatch.cgi/FORUM/folderFrame/100001/0/alpha/2040958 +http://www.teacherformation.org/html/od/facilitators.cfm/task1,help/discussion_id,2/xid,5237/yid,3113916 +http://www.mirror.edu.cn/res/www.isoc.org/inet98/proceedings/7d/ +http://www.sumthin.nu/archives/bugtraq/Nov_1998/msg00058.html +http://proxy.tiscover.com/1Root/Kontinent/6/Staat/7/Bundesland/20/Regionen/regionen_az...2.html +http://www.streetprices.com/products/sortdetailbylowprice/SP142252.html +http://www.streetprices.com/products/sortdetailby1day/SP142252.html +http://pp3.shef.ac.uk:4040/form/path=1,+%3A%22countryName%3DGB%40organizationName%3DUniversity+of+Sheffield%40organizationalUnitName%3DFinance%40commonName%3DS+Green%22 +http://travelocity-dest.excite.com/DestGuides/0,1840,TRAVELOCITY|2662|3|1|239114,00.html +http://www.maastrek.de/maas/4a73999ddfd2d79be20a/1/0/5 +http://aol.weather.com/weather/cities/us_pa_fairview.html +http://aol.weather.com/weather/cities/us_pa_fort_loudon.html +http://javatest.a-net.nl/servlet/pedit.Main/http://www.tigerden.com/junkmail/compladdr.html +http://ftp.dti.ad.jp/pub/windows/forest/file/backup/press1/?M=A +http://www.contest.edu.tw/85/endshow/5/baseball/news/97feb/0225t_1c.html +http://www.contest.edu.tw/85/endshow/5/baseball/news/97feb/0225c_3c.html +http://www.contest.edu.tw/85/endshow/5/baseball/news/97feb/0217c_2c.html +http://www.contest.edu.tw/85/endshow/5/baseball/news/97feb/0216c_play.html +http://www.contest.edu.tw/85/endshow/5/baseball/news/97feb/0214co_1c.html +http://preview.egroups.com/messages/decoratingplusnews/6 +http://astro1.chungnam.ac.kr/NetBBS/Bbs.dll/bulletin/rcm/zka/B2-kC23n/qqatt/^ \ No newline at end of file diff --git a/vendor/snap/examples/compress-escaped.rs b/vendor/snap/examples/compress-escaped.rs new file mode 100644 index 0000000000..6fc97e9ac3 --- /dev/null +++ b/vendor/snap/examples/compress-escaped.rs @@ -0,0 +1,39 @@ +use std::env; +use std::io::{self, Write}; +use std::process; + +fn main() { + let bytes = match env::args().nth(1) { + None => { + writeln!(&mut io::stderr(), "Usage: compress-escaped string") + .unwrap(); + process::exit(1); + } + Some(arg) => arg.into_bytes(), + }; + let compressed = frame_press(&bytes); + println!("{}", escape(&compressed)); + println!("{}", escape(&frame_depress(&compressed))); +} + +fn frame_press(bytes: &[u8]) -> Vec { + use snap::write; + + let mut wtr = write::FrameEncoder::new(vec![]); + wtr.write_all(bytes).unwrap(); + wtr.into_inner().unwrap() +} + +fn frame_depress(bytes: &[u8]) -> Vec { + use snap::read; + use std::io::Read; + + let mut buf = vec![]; + read::FrameDecoder::new(bytes).read_to_end(&mut buf).unwrap(); + buf +} + +fn escape(bytes: &[u8]) -> String { + use std::ascii::escape_default; + bytes.iter().flat_map(|&b| escape_default(b)).map(|b| b as char).collect() +} diff --git a/vendor/snap/examples/compress.rs b/vendor/snap/examples/compress.rs new file mode 100644 index 0000000000..31d302c610 --- /dev/null +++ b/vendor/snap/examples/compress.rs @@ -0,0 +1,13 @@ +use snap; + +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + let mut rdr = stdin.lock(); + // Wrap the stdout writer in a Snappy writer. + let mut wtr = snap::write::FrameEncoder::new(stdout.lock()); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} diff --git a/vendor/snap/examples/decompress.rs b/vendor/snap/examples/decompress.rs new file mode 100644 index 0000000000..7548f2f03d --- /dev/null +++ b/vendor/snap/examples/decompress.rs @@ -0,0 +1,13 @@ +use snap; + +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + // Wrap the stdin reader in a Snappy reader. + let mut rdr = snap::read::FrameDecoder::new(stdin.lock()); + let mut wtr = stdout.lock(); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} diff --git a/vendor/snap/rustfmt.toml b/vendor/snap/rustfmt.toml new file mode 100644 index 0000000000..aa37a218b9 --- /dev/null +++ b/vendor/snap/rustfmt.toml @@ -0,0 +1,2 @@ +max_width = 79 +use_small_heuristics = "max" diff --git a/vendor/snap/src/bytes.rs b/vendor/snap/src/bytes.rs new file mode 100644 index 0000000000..4f198c6680 --- /dev/null +++ b/vendor/snap/src/bytes.rs @@ -0,0 +1,118 @@ +use std::convert::TryInto; +use std::io; + +/// Read a u16 in little endian format from the beginning of the given slice. +/// This panics if the slice has length less than 2. +pub fn read_u16_le(slice: &[u8]) -> u16 { + u16::from_le_bytes(slice[..2].try_into().unwrap()) +} + +/// Read a u24 (returned as a u32 with the most significant 8 bits always set +/// to 0) in little endian format from the beginning of the given slice. This +/// panics if the slice has length less than 3. +pub fn read_u24_le(slice: &[u8]) -> u32 { + slice[0] as u32 | (slice[1] as u32) << 8 | (slice[2] as u32) << 16 +} + +/// Read a u32 in little endian format from the beginning of the given slice. +/// This panics if the slice has length less than 4. +pub fn read_u32_le(slice: &[u8]) -> u32 { + u32::from_le_bytes(slice[..4].try_into().unwrap()) +} + +/// Like read_u32_le, but from an io::Read implementation. If io::Read does +/// not yield at least 4 bytes, then this returns an unexpected EOF error. +pub fn io_read_u32_le(mut rdr: R) -> io::Result { + let mut buf = [0; 4]; + rdr.read_exact(&mut buf)?; + Ok(u32::from_le_bytes(buf)) +} + +/// Write a u16 in little endian format to the beginning of the given slice. +/// This panics if the slice has length less than 2. +pub fn write_u16_le(n: u16, slice: &mut [u8]) { + assert!(slice.len() >= 2); + let bytes = n.to_le_bytes(); + slice[0] = bytes[0]; + slice[1] = bytes[1]; +} + +/// Write a u24 (given as a u32 where the most significant 8 bits are ignored) +/// in little endian format to the beginning of the given slice. This panics +/// if the slice has length less than 3. +pub fn write_u24_le(n: u32, slice: &mut [u8]) { + slice[0] = n as u8; + slice[1] = (n >> 8) as u8; + slice[2] = (n >> 16) as u8; +} + +/// Write a u32 in little endian format to the beginning of the given slice. +/// This panics if the slice has length less than 4. +pub fn write_u32_le(n: u32, slice: &mut [u8]) { + assert!(slice.len() >= 4); + let bytes = n.to_le_bytes(); + slice[0] = bytes[0]; + slice[1] = bytes[1]; + slice[2] = bytes[2]; + slice[3] = bytes[3]; +} + +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +pub fn write_varu64(data: &mut [u8], mut n: u64) -> usize { + let mut i = 0; + while n >= 0b1000_0000 { + data[i] = (n as u8) | 0b1000_0000; + n >>= 7; + i += 1; + } + data[i] = n as u8; + i + 1 +} + +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +pub fn read_varu64(data: &[u8]) -> (u64, usize) { + let mut n: u64 = 0; + let mut shift: u32 = 0; + for (i, &b) in data.iter().enumerate() { + if b < 0b1000_0000 { + return match (b as u64).checked_shl(shift) { + None => (0, 0), + Some(b) => (n | b, i + 1), + }; + } + match ((b as u64) & 0b0111_1111).checked_shl(shift) { + None => return (0, 0), + Some(b) => n |= b, + } + shift += 7; + } + (0, 0) +} + +/// Does an unaligned load of a little endian encoded u32. +/// +/// This is unsafe because `data` must point to some memory of size at least 4. +pub unsafe fn loadu_u32_le(data: *const u8) -> u32 { + loadu_u32_ne(data).to_le() +} + +/// Does an unaligned load of a native endian encoded u32. +/// +/// This is unsafe because `data` must point to some memory of size at least 4. +pub unsafe fn loadu_u32_ne(data: *const u8) -> u32 { + (data as *const u32).read_unaligned() +} + +/// Does an unaligned load of a little endian encoded u64. +/// +/// This is unsafe because `data` must point to some memory of size at least 8. +pub unsafe fn loadu_u64_le(data: *const u8) -> u64 { + loadu_u64_ne(data).to_le() +} + +/// Does an unaligned load of a native endian encoded u64. +/// +/// This is unsafe because `data` must point to some memory of size at least 8. +pub unsafe fn loadu_u64_ne(data: *const u8) -> u64 { + (data as *const u64).read_unaligned() +} diff --git a/vendor/snap/src/compress.rs b/vendor/snap/src/compress.rs new file mode 100644 index 0000000000..1a6638df4f --- /dev/null +++ b/vendor/snap/src/compress.rs @@ -0,0 +1,539 @@ +use std::fmt; +use std::ops::{Deref, DerefMut}; +use std::ptr; + +use crate::bytes; +use crate::error::{Error, Result}; +use crate::{MAX_BLOCK_SIZE, MAX_INPUT_SIZE}; + +/// The total number of slots we permit for our hash table of 4 byte repeat +/// sequences. +const MAX_TABLE_SIZE: usize = 1 << 14; + +/// The size of a small hash table. This is useful for reducing overhead when +/// compressing very small blocks of bytes. +const SMALL_TABLE_SIZE: usize = 1 << 10; + +/// The total number of bytes that we always leave uncompressed at the end +/// of the buffer. This in particular affords us some wiggle room during +/// compression such that faster copy operations can be used. +const INPUT_MARGIN: usize = 16 - 1; + +/// The minimum block size that we're willing to consider for compression. +/// Anything smaller than this gets emitted as a literal. +const MIN_NON_LITERAL_BLOCK_SIZE: usize = 1 + 1 + INPUT_MARGIN; + +/// Nice names for the various Snappy tags. +enum Tag { + Literal = 0b00, + Copy1 = 0b01, + Copy2 = 0b10, + // Compression never actually emits a Copy4 operation and decompression + // uses tricks so that we never explicitly do case analysis on the copy + // operation type, therefore leading to the fact that we never use Copy4. + #[allow(dead_code)] + Copy4 = 0b11, +} + +/// Returns the maximum compressed size given the uncompressed size. +/// +/// If the uncompressed size exceeds the maximum allowable size then this +/// returns 0. +pub fn max_compress_len(input_len: usize) -> usize { + let input_len = input_len as u64; + if input_len > MAX_INPUT_SIZE { + return 0; + } + let max = 32 + input_len + (input_len / 6); + if max > MAX_INPUT_SIZE { + 0 + } else { + max as usize + } +} + +/// Encoder is a raw encoder for compressing bytes in the Snappy format. +/// +/// Thie encoder does not use the Snappy frame format and simply compresses the +/// given bytes in one big Snappy block (that is, it has a single header). +/// +/// Unless you explicitly need the low-level control, you should use +/// [`read::FrameEncoder`](../read/struct.FrameEncoder.html) +/// or +/// [`write::FrameEncoder`](../write/struct.FrameEncoder.html) +/// instead, which compresses to the Snappy frame format. +/// +/// It is beneficial to reuse an Encoder when possible. +pub struct Encoder { + small: [u16; SMALL_TABLE_SIZE], + big: Vec, +} + +impl fmt::Debug for Encoder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "Encoder(...)") + } +} + +impl Encoder { + /// Return a new encoder that can be used for compressing bytes. + pub fn new() -> Encoder { + Encoder { small: [0; SMALL_TABLE_SIZE], big: vec![] } + } + + /// Compresses all bytes in `input` into `output`. + /// + /// `input` can be any arbitrary sequence of bytes. + /// + /// `output` must be large enough to hold the maximum possible compressed + /// size of `input`, which can be computed using `max_compress_len`. + /// + /// On success, this returns the number of bytes written to `output`. + /// + /// # Errors + /// + /// This method returns an error in the following circumstances: + /// + /// * The total number of bytes to compress exceeds `2^32 - 1`. + /// * `output` has length less than `max_compress_len(input.len())`. + pub fn compress( + &mut self, + mut input: &[u8], + output: &mut [u8], + ) -> Result { + match max_compress_len(input.len()) { + 0 => { + return Err(Error::TooBig { + given: input.len() as u64, + max: MAX_INPUT_SIZE, + }); + } + min if output.len() < min => { + return Err(Error::BufferTooSmall { + given: output.len() as u64, + min: min as u64, + }); + } + _ => {} + } + // Handle an edge case specially. + if input.is_empty() { + // Encodes a varint of 0, denoting the total size of uncompressed + // bytes. + output[0] = 0; + return Ok(1); + } + // Write the Snappy header, which is just the total number of + // uncompressed bytes. + let mut d = bytes::write_varu64(output, input.len() as u64); + while !input.is_empty() { + // Find the next block. + let mut src = input; + if src.len() > MAX_BLOCK_SIZE { + src = &src[..MAX_BLOCK_SIZE as usize]; + } + input = &input[src.len()..]; + + // If the block is smallish, then don't waste time on it and just + // emit a literal. + let mut block = Block::new(src, output, d); + if block.src.len() < MIN_NON_LITERAL_BLOCK_SIZE { + let lit_end = block.src.len(); + unsafe { + // SAFETY: next_emit is zero (in bounds) and the end is + // the length of the block (in bounds). + block.emit_literal(lit_end); + } + } else { + let table = self.block_table(block.src.len()); + block.compress(table); + } + d = block.d; + } + Ok(d) + } + + /// Compresses all bytes in `input` into a freshly allocated `Vec`. + /// + /// This is just like the `compress` method, except it allocates a `Vec` + /// with the right size for you. (This is intended to be a convenience + /// method.) + /// + /// This method returns an error under the same circumstances that + /// `compress` does. + pub fn compress_vec(&mut self, input: &[u8]) -> Result> { + let mut buf = vec![0; max_compress_len(input.len())]; + let n = self.compress(input, &mut buf)?; + buf.truncate(n); + Ok(buf) + } +} + +struct Block<'s, 'd> { + src: &'s [u8], + s: usize, + s_limit: usize, + dst: &'d mut [u8], + d: usize, + next_emit: usize, +} + +impl<'s, 'd> Block<'s, 'd> { + #[inline(always)] + fn new(src: &'s [u8], dst: &'d mut [u8], d: usize) -> Block<'s, 'd> { + Block { + src: src, + s: 0, + s_limit: src.len(), + dst: dst, + d: d, + next_emit: 0, + } + } + + #[inline(always)] + fn compress(&mut self, mut table: BlockTable<'_>) { + debug_assert!(!table.is_empty()); + debug_assert!(self.src.len() >= MIN_NON_LITERAL_BLOCK_SIZE); + + self.s += 1; + self.s_limit -= INPUT_MARGIN; + let mut next_hash = + table.hash(bytes::read_u32_le(&self.src[self.s..])); + loop { + let mut skip = 32; + let mut candidate; + let mut s_next = self.s; + loop { + self.s = s_next; + let bytes_between_hash_lookups = skip >> 5; + s_next = self.s + bytes_between_hash_lookups; + skip += bytes_between_hash_lookups; + if s_next > self.s_limit { + return self.done(); + } + unsafe { + // SAFETY: next_hash is always computed by table.hash + // which is guaranteed to be in bounds. + candidate = *table.get_unchecked(next_hash) as usize; + *table.get_unchecked_mut(next_hash) = self.s as u16; + + let srcp = self.src.as_ptr(); + // SAFETY: s_next is guaranteed to be less than s_limit by + // the conditional above, which implies s_next is in + // bounds. + let x = bytes::loadu_u32_le(srcp.add(s_next)); + next_hash = table.hash(x); + // SAFETY: self.s is always less than s_next, so it is also + // in bounds by the argument above. + // + // candidate is extracted from table, which is only ever + // set to valid positions in the block and is therefore + // also in bounds. + // + // We only need to compare y/z for equality, so we don't + // need to both with endianness. cur corresponds to the + // bytes at the current position and cand corresponds to + // a potential match. If they're equal, we declare victory + // and move below to try and extend the match. + let cur = bytes::loadu_u32_ne(srcp.add(self.s)); + let cand = bytes::loadu_u32_ne(srcp.add(candidate)); + if cur == cand { + break; + } + } + } + // While the above found a candidate for compression, before we + // emit a copy operation for it, we need to make sure that we emit + // any bytes between the last copy operation and this one as a + // literal. + let lit_end = self.s; + unsafe { + // SAFETY: next_emit is set to a previous value of self.s, + // which is guaranteed to be less than s_limit (in bounds). + // lit_end is set to the current value of self.s, also + // guaranteed to be less than s_limit (in bounds). + self.emit_literal(lit_end); + } + loop { + // Look for more matching bytes starting at the position of + // the candidate and the current src position. We increment + // self.s and candidate by 4 since we already know the first 4 + // bytes match. + let base = self.s; + self.s += 4; + unsafe { + // SAFETY: candidate is always set to a value from our + // hash table, which only contains positions in self.src + // that have been seen for this block that occurred before + // self.s. + self.extend_match(candidate + 4); + } + let (offset, len) = (base - candidate, self.s - base); + self.emit_copy(offset, len); + self.next_emit = self.s; + if self.s >= self.s_limit { + return self.done(); + } + // Update the hash table with the byte sequences + // self.src[self.s - 1..self.s + 3] and + // self.src[self.s..self.s + 4]. Instead of reading 4 bytes + // twice, we read 8 bytes once. + // + // If we happen to get a hit on self.src[self.s..self.s + 4], + // then continue this loop and extend the match. + unsafe { + let srcp = self.src.as_ptr(); + // SAFETY: self.s can never exceed s_limit given by the + // conditional above and self.s is guaranteed to be + // non-zero and is therefore in bounds. + let x = bytes::loadu_u64_le(srcp.add(self.s - 1)); + // The lower 4 bytes of x correspond to + // self.src[self.s - 1..self.s + 3]. + let prev_hash = table.hash(x as u32); + // SAFETY: Hash values are guaranteed to be in bounds. + *table.get_unchecked_mut(prev_hash) = (self.s - 1) as u16; + // The lower 4 bytes of x>>8 correspond to + // self.src[self.s..self.s + 4]. + let cur_hash = table.hash((x >> 8) as u32); + // SAFETY: Hash values are guaranteed to be in bounds. + candidate = *table.get_unchecked(cur_hash) as usize; + *table.get_unchecked_mut(cur_hash) = self.s as u16; + + // SAFETY: candidate is set from table, which always + // contains valid positions in the current block. + let y = bytes::loadu_u32_le(srcp.add(candidate)); + if (x >> 8) as u32 != y { + // If we didn't get a hit, update the next hash + // and move on. Our initial 8 byte read continues to + // pay off. + next_hash = table.hash((x >> 16) as u32); + self.s += 1; + break; + } + } + } + } + } + + /// Emits one or more copy operations with the given offset and length. + /// offset must be in the range [1, 65535] and len must be in the range + /// [4, 65535]. + #[inline(always)] + fn emit_copy(&mut self, offset: usize, mut len: usize) { + debug_assert!(1 <= offset && offset <= 65535); + // Copy operations only allow lengths up to 64, but we'll allow bigger + // lengths and emit as many operations as we need. + // + // N.B. Since our block size is 64KB, we never actually emit a copy 4 + // operation. + debug_assert!(4 <= len && len <= 65535); + + // Emit copy 2 operations until we don't have to. + // We check on 68 here and emit a shorter copy than 64 below because + // it is cheaper to, e.g., encode a length 67 copy as a length 60 + // copy 2 followed by a length 7 copy 1 than to encode it as a length + // 64 copy 2 followed by a length 3 copy 2. They key here is that a + // copy 1 operation requires at least length 4 which forces a length 3 + // copy to use a copy 2 operation. + while len >= 68 { + self.emit_copy2(offset, 64); + len -= 64; + } + if len > 64 { + self.emit_copy2(offset, 60); + len -= 60; + } + // If we can squeeze the last copy into a copy 1 operation, do it. + if len <= 11 && offset <= 2047 { + self.dst[self.d] = (((offset >> 8) as u8) << 5) + | (((len - 4) as u8) << 2) + | (Tag::Copy1 as u8); + self.dst[self.d + 1] = offset as u8; + self.d += 2; + } else { + self.emit_copy2(offset, len); + } + } + + /// Emits a "copy 2" operation with the given offset and length. The + /// offset and length must be valid for a copy 2 operation. i.e., offset + /// must be in the range [1, 65535] and len must be in the range [1, 64]. + #[inline(always)] + fn emit_copy2(&mut self, offset: usize, len: usize) { + debug_assert!(1 <= offset && offset <= 65535); + debug_assert!(1 <= len && len <= 64); + self.dst[self.d] = (((len - 1) as u8) << 2) | (Tag::Copy2 as u8); + bytes::write_u16_le(offset as u16, &mut self.dst[self.d + 1..]); + self.d += 3; + } + + /// Attempts to extend a match from the current position in self.src with + /// the candidate position given. + /// + /// This method uses unaligned loads and elides bounds checks, so the + /// caller must guarantee that cand points to a valid location in self.src + /// and is less than the current position in src. + #[inline(always)] + unsafe fn extend_match(&mut self, mut cand: usize) { + debug_assert!(cand < self.s); + while self.s + 8 <= self.src.len() { + let srcp = self.src.as_ptr(); + // SAFETY: The loop invariant guarantees that there is at least + // 8 bytes to read at self.src + self.s. Since cand must be + // guaranteed by the caller to be valid and less than self.s, it + // also has enough room to read 8 bytes. + // + // TODO(ag): Despite my best efforts, I couldn't get this to + // autovectorize with 128-bit loads. The logic after the loads + // appears to be a little too clever... + let x = bytes::loadu_u64_ne(srcp.add(self.s)); + let y = bytes::loadu_u64_ne(srcp.add(cand)); + if x == y { + // If all 8 bytes are equal, move on... + self.s += 8; + cand += 8; + } else { + // Otherwise, find the last byte that was equal. We can do + // this efficiently by interpreted x/y as little endian + // numbers, which lets us use the number of trailing zeroes + // as a proxy for the number of equivalent bits (after an XOR). + let z = x.to_le() ^ y.to_le(); + self.s += z.trailing_zeros() as usize / 8; + return; + } + } + // When we have fewer than 8 bytes left in the block, fall back to the + // slow loop. + while self.s < self.src.len() && self.src[self.s] == self.src[cand] { + self.s += 1; + cand += 1; + } + } + + /// Executes any cleanup when the current block has finished compressing. + /// In particular, it emits any leftover bytes as a literal. + #[inline(always)] + fn done(&mut self) { + if self.next_emit < self.src.len() { + let lit_end = self.src.len(); + unsafe { + // SAFETY: Both next_emit and lit_end are trivially in bounds + // given the conditional and definition above. + self.emit_literal(lit_end); + } + } + } + + /// Emits a literal from self.src[self.next_emit..lit_end]. + /// + /// This uses unaligned loads and elides bounds checks, so the caller must + /// guarantee that self.src[self.next_emit..lit_end] is valid. + #[inline(always)] + unsafe fn emit_literal(&mut self, lit_end: usize) { + let lit_start = self.next_emit; + let len = lit_end - lit_start; + let n = len.checked_sub(1).unwrap(); + if n <= 59 { + self.dst[self.d] = ((n as u8) << 2) | (Tag::Literal as u8); + self.d += 1; + if len <= 16 && lit_start + 16 <= self.src.len() { + // SAFETY: lit_start is equivalent to self.next_emit, which is + // only set to self.s immediately following a copy emit. The + // conditional above also ensures that there is at least 16 + // bytes of room in both src and dst. + // + // dst is big enough because the buffer is guaranteed to + // be big enough to hold biggest possible compressed size plus + // an extra 32 bytes, which exceeds the 16 byte copy here. + let srcp = self.src.as_ptr().add(lit_start); + let dstp = self.dst.as_mut_ptr().add(self.d); + ptr::copy_nonoverlapping(srcp, dstp, 16); + self.d += len; + return; + } + } else if n < 256 { + self.dst[self.d] = (60 << 2) | (Tag::Literal as u8); + self.dst[self.d + 1] = n as u8; + self.d += 2; + } else { + self.dst[self.d] = (61 << 2) | (Tag::Literal as u8); + bytes::write_u16_le(n as u16, &mut self.dst[self.d + 1..]); + self.d += 3; + } + // SAFETY: lit_start is equivalent to self.next_emit, which is only set + // to self.s immediately following a copy, which implies that it always + // points to valid bytes in self.src. + // + // We can't guarantee that there are at least len bytes though, which + // must be guaranteed by the caller and is why this method is unsafe. + let srcp = self.src.as_ptr().add(lit_start); + let dstp = self.dst.as_mut_ptr().add(self.d); + ptr::copy_nonoverlapping(srcp, dstp, len); + self.d += len; + } +} + +/// `BlockTable` is a map from 4 byte sequences to positions of their most +/// recent occurrence in a block. In particular, this table lets us quickly +/// find candidates for compression. +/// +/// We expose the `hash` method so that callers can be fastidious about the +/// number of times a hash is computed. +struct BlockTable<'a> { + table: &'a mut [u16], + /// The number of bits required to shift the hash such that the result + /// is less than table.len(). + shift: u32, +} + +impl Encoder { + fn block_table(&mut self, block_size: usize) -> BlockTable<'_> { + let mut shift: u32 = 32 - 8; + let mut table_size = 256; + while table_size < MAX_TABLE_SIZE && table_size < block_size { + shift -= 1; + table_size *= 2; + } + // If our block size is small, then use a small stack allocated table + // instead of putting a bigger one on the heap. This particular + // optimization is important if the caller is using Snappy to compress + // many small blocks. (The memset savings alone is considerable.) + let table: &mut [u16] = if table_size <= SMALL_TABLE_SIZE { + &mut self.small[0..table_size] + } else { + if self.big.is_empty() { + // Interestingly, using `self.big.resize` here led to some + // very weird code getting generated that led to a large + // slow down. Forcing the issue with a new vec seems to + // fix it. ---AG + self.big = vec![0; MAX_TABLE_SIZE]; + } + &mut self.big[0..table_size] + }; + for x in &mut *table { + *x = 0; + } + BlockTable { table: table, shift: shift } + } +} + +impl<'a> BlockTable<'a> { + #[inline(always)] + fn hash(&self, x: u32) -> usize { + (x.wrapping_mul(0x1E35A7BD) >> self.shift) as usize + } +} + +impl<'a> Deref for BlockTable<'a> { + type Target = [u16]; + fn deref(&self) -> &[u16] { + self.table + } +} + +impl<'a> DerefMut for BlockTable<'a> { + fn deref_mut(&mut self) -> &mut [u16] { + self.table + } +} diff --git a/vendor/snap/src/crc32.rs b/vendor/snap/src/crc32.rs new file mode 100644 index 0000000000..1298ef04ac --- /dev/null +++ b/vendor/snap/src/crc32.rs @@ -0,0 +1,111 @@ +use crate::bytes; +use crate::crc32_table::{TABLE, TABLE16}; + +/// Provides a simple API to generate "masked" CRC32C checksums specifically +/// for use in Snappy. When available, this will make use of SSE 4.2 to compute +/// checksums. Otherwise, it falls back to only-marginally-slower "slicing by +/// 16" technique. +/// +/// The main purpose of this type is to cache the CPU feature check and expose +/// a safe API. +#[derive(Clone, Copy, Debug)] +pub struct CheckSummer { + sse42: bool, +} + +impl CheckSummer { + /// Create a new checksummer that can compute CRC32C checksums on arbitrary + /// bytes. + #[cfg(not(target_arch = "x86_64"))] + pub fn new() -> CheckSummer { + CheckSummer { sse42: false } + } + + /// Create a new checksummer that can compute CRC32C checksums on arbitrary + /// bytes. + #[cfg(target_arch = "x86_64")] + pub fn new() -> CheckSummer { + CheckSummer { sse42: is_x86_feature_detected!("sse4.2") } + } + + /// Returns the "masked" CRC32 checksum of `buf` using the Castagnoli + /// polynomial. This "masked" checksum is defined by the Snappy frame + /// format. Masking is supposed to make the checksum robust with respect to + /// the data that contains the checksum itself. + pub fn crc32c_masked(&self, buf: &[u8]) -> u32 { + let sum = self.crc32c(buf); + (sum.wrapping_shr(15) | sum.wrapping_shl(17)).wrapping_add(0xA282EAD8) + } + + /// Returns the CRC32 checksum of `buf` using the Castagnoli polynomial. + #[cfg(not(target_arch = "x86_64"))] + fn crc32c(&self, buf: &[u8]) -> u32 { + crc32c_slice16(buf) + } + + /// Returns the CRC32 checksum of `buf` using the Castagnoli polynomial. + #[cfg(target_arch = "x86_64")] + fn crc32c(&self, buf: &[u8]) -> u32 { + if self.sse42 { + // SAFETY: When sse42 is true, we are guaranteed to be running on + // a CPU that supports SSE 4.2. + unsafe { crc32c_sse(buf) } + } else { + crc32c_slice16(buf) + } + } +} + +#[cfg(target_arch = "x86_64")] +#[target_feature(enable = "sse4.2")] +unsafe fn crc32c_sse(buf: &[u8]) -> u32 { + use std::arch::x86_64::*; + + let mut crc = !0u32; + // SAFETY: This is safe since alignment is handled by align_to (oh how I + // love you) and since 8 adjacent u8's are guaranteed to have the same + // in-memory representation as u64 for all possible values. + let (prefix, u64s, suffix) = buf.align_to::(); + for &b in prefix { + // SAFETY: Safe since we have sse4.2 enabled. + crc = _mm_crc32_u8(crc, b); + } + for &n in u64s { + // SAFETY: Safe since we have sse4.2 enabled. + crc = _mm_crc32_u64(crc as u64, n) as u32; + } + for &b in suffix { + // SAFETY: Safe since we have sse4.2 enabled. + crc = _mm_crc32_u8(crc, b); + } + !crc +} + +/// Returns the CRC32 checksum of `buf` using the Castagnoli polynomial. +fn crc32c_slice16(mut buf: &[u8]) -> u32 { + let mut crc: u32 = !0; + while buf.len() >= 16 { + crc ^= bytes::read_u32_le(buf); + crc = TABLE16[0][buf[15] as usize] + ^ TABLE16[1][buf[14] as usize] + ^ TABLE16[2][buf[13] as usize] + ^ TABLE16[3][buf[12] as usize] + ^ TABLE16[4][buf[11] as usize] + ^ TABLE16[5][buf[10] as usize] + ^ TABLE16[6][buf[9] as usize] + ^ TABLE16[7][buf[8] as usize] + ^ TABLE16[8][buf[7] as usize] + ^ TABLE16[9][buf[6] as usize] + ^ TABLE16[10][buf[5] as usize] + ^ TABLE16[11][buf[4] as usize] + ^ TABLE16[12][(crc >> 24) as u8 as usize] + ^ TABLE16[13][(crc >> 16) as u8 as usize] + ^ TABLE16[14][(crc >> 8) as u8 as usize] + ^ TABLE16[15][(crc) as u8 as usize]; + buf = &buf[16..]; + } + for &b in buf { + crc = TABLE[((crc as u8) ^ b) as usize] ^ (crc >> 8); + } + !crc +} diff --git a/vendor/snap/src/crc32_table.rs b/vendor/snap/src/crc32_table.rs new file mode 100644 index 0000000000..7821b5d86e --- /dev/null +++ b/vendor/snap/src/crc32_table.rs @@ -0,0 +1,2 @@ +// Generated by build.rs. +include!(concat!(env!("OUT_DIR"), "/crc32_table.rs")); diff --git a/vendor/snap/src/decompress.rs b/vendor/snap/src/decompress.rs new file mode 100644 index 0000000000..07ab16b4c1 --- /dev/null +++ b/vendor/snap/src/decompress.rs @@ -0,0 +1,470 @@ +use std::ptr; + +use crate::bytes; +use crate::error::{Error, Result}; +use crate::tag; +use crate::MAX_INPUT_SIZE; + +/// A lookup table for quickly computing the various attributes derived from a +/// tag byte. +const TAG_LOOKUP_TABLE: TagLookupTable = TagLookupTable(tag::TAG_LOOKUP_TABLE); + +/// `WORD_MASK` is a map from the size of an integer in bytes to its +/// corresponding on a 32 bit integer. This is used when we need to read an +/// integer and we know there are at least 4 bytes to read from a buffer. In +/// this case, we can read a 32 bit little endian integer and mask out only the +/// bits we need. This in particular saves a branch. +const WORD_MASK: [usize; 5] = [0, 0xFF, 0xFFFF, 0xFFFFFF, 0xFFFFFFFF]; + +/// Returns the decompressed size (in bytes) of the compressed bytes given. +/// +/// `input` must be a sequence of bytes returned by a conforming Snappy +/// compressor. +/// +/// # Errors +/// +/// This function returns an error in the following circumstances: +/// +/// * An invalid Snappy header was seen. +/// * The total space required for decompression exceeds `2^32 - 1`. +pub fn decompress_len(input: &[u8]) -> Result { + if input.is_empty() { + return Ok(0); + } + Ok(Header::read(input)?.decompress_len) +} + +/// Decoder is a raw decoder for decompressing bytes in the Snappy format. +/// +/// This decoder does not use the Snappy frame format and simply decompresses +/// the given bytes as if it were returned from `Encoder`. +/// +/// Unless you explicitly need the low-level control, you should use +/// [`read::FrameDecoder`](../read/struct.FrameDecoder.html) +/// instead, which decompresses the Snappy frame format. +#[derive(Clone, Debug, Default)] +pub struct Decoder { + // Place holder for potential future fields. + _dummy: (), +} + +impl Decoder { + /// Return a new decoder that can be used for decompressing bytes. + pub fn new() -> Decoder { + Decoder { _dummy: () } + } + + /// Decompresses all bytes in `input` into `output`. + /// + /// `input` must be a sequence of bytes returned by a conforming Snappy + /// compressor. + /// + /// The size of `output` must be large enough to hold all decompressed + /// bytes from the `input`. The size required can be queried with the + /// `decompress_len` function. + /// + /// On success, this returns the number of bytes written to `output`. + /// + /// # Errors + /// + /// This method returns an error in the following circumstances: + /// + /// * Invalid compressed Snappy data was seen. + /// * The total space required for decompression exceeds `2^32 - 1`. + /// * `output` has length less than `decompress_len(input)`. + pub fn decompress( + &mut self, + input: &[u8], + output: &mut [u8], + ) -> Result { + if input.is_empty() { + return Err(Error::Empty); + } + let hdr = Header::read(input)?; + if hdr.decompress_len > output.len() { + return Err(Error::BufferTooSmall { + given: output.len() as u64, + min: hdr.decompress_len as u64, + }); + } + let dst = &mut output[..hdr.decompress_len]; + let mut dec = + Decompress { src: &input[hdr.len..], s: 0, dst: dst, d: 0 }; + dec.decompress()?; + Ok(dec.dst.len()) + } + + /// Decompresses all bytes in `input` into a freshly allocated `Vec`. + /// + /// This is just like the `decompress` method, except it allocates a `Vec` + /// with the right size for you. (This is intended to be a convenience + /// method.) + /// + /// This method returns an error under the same circumstances that + /// `decompress` does. + pub fn decompress_vec(&mut self, input: &[u8]) -> Result> { + let mut buf = vec![0; decompress_len(input)?]; + let n = self.decompress(input, &mut buf)?; + buf.truncate(n); + Ok(buf) + } +} + +/// Decompress is the state of the Snappy compressor. +struct Decompress<'s, 'd> { + /// The original compressed bytes not including the header. + src: &'s [u8], + /// The current position in the compressed bytes. + s: usize, + /// The output buffer to write the decompressed bytes. + dst: &'d mut [u8], + /// The current position in the decompressed buffer. + d: usize, +} + +impl<'s, 'd> Decompress<'s, 'd> { + /// Decompresses snappy compressed bytes in `src` to `dst`. + /// + /// This assumes that the header has already been read and that `dst` is + /// big enough to store all decompressed bytes. + fn decompress(&mut self) -> Result<()> { + while self.s < self.src.len() { + let byte = self.src[self.s]; + self.s += 1; + if byte & 0b000000_11 == 0 { + let len = (byte >> 2) as usize + 1; + self.read_literal(len)?; + } else { + self.read_copy(byte)?; + } + } + if self.d != self.dst.len() { + return Err(Error::HeaderMismatch { + expected_len: self.dst.len() as u64, + got_len: self.d as u64, + }); + } + Ok(()) + } + + /// Decompresses a literal from `src` starting at `s` to `dst` starting at + /// `d` and returns the updated values of `s` and `d`. `s` should point to + /// the byte immediately proceding the literal tag byte. + /// + /// `len` is the length of the literal if it's <=60. Otherwise, it's the + /// length tag, indicating the number of bytes needed to read a little + /// endian integer at `src[s..]`. i.e., `61 => 1 byte`, `62 => 2 bytes`, + /// `63 => 3 bytes` and `64 => 4 bytes`. + /// + /// `len` must be <=64. + #[inline(always)] + fn read_literal(&mut self, len: usize) -> Result<()> { + debug_assert!(len <= 64); + let mut len = len as u64; + // As an optimization for the common case, if the literal length is + // <=16 and we have enough room in both `src` and `dst`, copy the + // literal using unaligned loads and stores. + // + // We pick 16 bytes with the hope that it optimizes down to a 128 bit + // load/store. + if len <= 16 + && self.s + 16 <= self.src.len() + && self.d + 16 <= self.dst.len() + { + unsafe { + // SAFETY: We know both src and dst have at least 16 bytes of + // wiggle room after s/d, even if `len` is <16, so the copy is + // safe. + let srcp = self.src.as_ptr().add(self.s); + let dstp = self.dst.as_mut_ptr().add(self.d); + // Hopefully uses SIMD registers for 128 bit load/store. + ptr::copy_nonoverlapping(srcp, dstp, 16); + } + self.d += len as usize; + self.s += len as usize; + return Ok(()); + } + // When the length is bigger than 60, it indicates that we need to read + // an additional 1-4 bytes to get the real length of the literal. + if len >= 61 { + // If there aren't at least 4 bytes left to read then we know this + // is corrupt because the literal must have length >=61. + if self.s as u64 + 4 > self.src.len() as u64 { + return Err(Error::Literal { + len: 4, + src_len: (self.src.len() - self.s) as u64, + dst_len: (self.dst.len() - self.d) as u64, + }); + } + // Since we know there are 4 bytes left to read, read a 32 bit LE + // integer and mask away the bits we don't need. + let byte_count = len as usize - 60; + len = bytes::read_u32_le(&self.src[self.s..]) as u64; + len = (len & (WORD_MASK[byte_count] as u64)) + 1; + self.s += byte_count; + } + // If there's not enough buffer left to load or store this literal, + // then the input is corrupt. + // if self.s + len > self.src.len() || self.d + len > self.dst.len() { + if ((self.src.len() - self.s) as u64) < len + || ((self.dst.len() - self.d) as u64) < len + { + return Err(Error::Literal { + len: len, + src_len: (self.src.len() - self.s) as u64, + dst_len: (self.dst.len() - self.d) as u64, + }); + } + unsafe { + // SAFETY: We've already checked the bounds, so we know this copy + // is correct. + let srcp = self.src.as_ptr().add(self.s); + let dstp = self.dst.as_mut_ptr().add(self.d); + ptr::copy_nonoverlapping(srcp, dstp, len as usize); + } + self.s += len as usize; + self.d += len as usize; + Ok(()) + } + + /// Reads a copy from `src` and writes the decompressed bytes to `dst`. `s` + /// should point to the byte immediately proceding the copy tag byte. + #[inline(always)] + fn read_copy(&mut self, tag_byte: u8) -> Result<()> { + // Find the copy offset and len, then advance the input past the copy. + // The rest of this function deals with reading/writing to output only. + let entry = TAG_LOOKUP_TABLE.entry(tag_byte); + let offset = entry.offset(self.src, self.s)?; + let len = entry.len(); + self.s += entry.num_tag_bytes(); + + // What we really care about here is whether `d == 0` or `d < offset`. + // To save an extra branch, use `d < offset - 1` instead. If `d` is + // `0`, then `offset.wrapping_sub(1)` will be usize::MAX which is also + // the max value of `d`. + if self.d <= offset.wrapping_sub(1) { + return Err(Error::Offset { + offset: offset as u64, + dst_pos: self.d as u64, + }); + } + // When all is said and done, dst is advanced to end. + let end = self.d + len; + // When the copy is small and the offset is at least 8 bytes away from + // `d`, then we can decompress the copy with two 64 bit unaligned + // loads/stores. + if offset >= 8 && len <= 16 && self.d + 16 <= self.dst.len() { + unsafe { + // SAFETY: We know dstp points to at least 16 bytes of memory + // from the condition above, and we also know that dstp is + // preceded by at least `offset` bytes from the `d <= offset` + // check above. + // + // We also know that dstp and dstp-8 do not overlap from the + // check above, justifying the use of copy_nonoverlapping. + let dstp = self.dst.as_mut_ptr().add(self.d); + let srcp = dstp.sub(offset); + // We can't do a single 16 byte load/store because src/dst may + // overlap with each other. Namely, the second copy here may + // copy bytes written in the first copy! + ptr::copy_nonoverlapping(srcp, dstp, 8); + ptr::copy_nonoverlapping(srcp.add(8), dstp.add(8), 8); + } + // If we have some wiggle room, try to decompress the copy 16 bytes + // at a time with 128 bit unaligned loads/stores. Remember, we can't + // just do a memcpy because decompressing copies may require copying + // overlapping memory. + // + // We need the extra wiggle room to make effective use of 128 bit + // loads/stores. Even if the store ends up copying more data than we + // need, we're careful to advance `d` by the correct amount at the end. + } else if end + 24 <= self.dst.len() { + unsafe { + // SAFETY: We know that dstp is preceded by at least `offset` + // bytes from the `d <= offset` check above. + // + // We don't know whether dstp overlaps with srcp, so we start + // by copying from srcp to dstp until they no longer overlap. + // The worst case is when dstp-src = 3 and copy length = 1. The + // first loop will issue these copy operations before stopping: + // + // [-1, 14] -> [0, 15] + // [-1, 14] -> [3, 18] + // [-1, 14] -> [9, 24] + // + // But the copy had length 1, so it was only supposed to write + // to [0, 0]. But the last copy wrote to [9, 24], which is 24 + // extra bytes in dst *beyond* the end of the copy, which is + // guaranteed by the conditional above. + let mut dstp = self.dst.as_mut_ptr().add(self.d); + let mut srcp = dstp.sub(offset); + loop { + debug_assert!(dstp >= srcp); + let diff = (dstp as usize) - (srcp as usize); + if diff >= 16 { + break; + } + // srcp and dstp can overlap, so use ptr::copy. + debug_assert!(self.d + 16 <= self.dst.len()); + ptr::copy(srcp, dstp, 16); + self.d += diff as usize; + dstp = dstp.add(diff); + } + while self.d < end { + ptr::copy_nonoverlapping(srcp, dstp, 16); + srcp = srcp.add(16); + dstp = dstp.add(16); + self.d += 16; + } + // At this point, `d` is likely wrong. We correct it before + // returning. It's correct value is `end`. + } + } else { + if end > self.dst.len() { + return Err(Error::CopyWrite { + len: len as u64, + dst_len: (self.dst.len() - self.d) as u64, + }); + } + // Finally, the slow byte-by-byte case, which should only be used + // for the last few bytes of decompression. + while self.d != end { + self.dst[self.d] = self.dst[self.d - offset]; + self.d += 1; + } + } + self.d = end; + Ok(()) + } +} + +/// Header represents the single varint that starts every Snappy compressed +/// block. +#[derive(Debug)] +struct Header { + /// The length of the header in bytes (i.e., the varint). + len: usize, + /// The length of the original decompressed input in bytes. + decompress_len: usize, +} + +impl Header { + /// Reads the varint header from the given input. + /// + /// If there was a problem reading the header then an error is returned. + /// If a header is returned then it is guaranteed to be valid. + #[inline(always)] + fn read(input: &[u8]) -> Result
    { + let (decompress_len, header_len) = bytes::read_varu64(input); + if header_len == 0 { + return Err(Error::Header); + } + if decompress_len > MAX_INPUT_SIZE { + return Err(Error::TooBig { + given: decompress_len as u64, + max: MAX_INPUT_SIZE, + }); + } + Ok(Header { len: header_len, decompress_len: decompress_len as usize }) + } +} + +/// A lookup table for quickly computing the various attributes derived from +/// a tag byte. The attributes are most useful for the three "copy" tags +/// and include the length of the copy, part of the offset (for copy 1-byte +/// only) and the total number of bytes proceding the tag byte that encode +/// the other part of the offset (1 for copy 1, 2 for copy 2 and 4 for copy 4). +/// +/// More specifically, the keys of the table are u8s and the values are u16s. +/// The bits of the values are laid out as follows: +/// +/// xxaa abbb xxcc cccc +/// +/// Where `a` is the number of bytes, `b` are the three bits of the offset +/// for copy 1 (the other 8 bits are in the byte proceding the tag byte; for +/// copy 2 and copy 4, `b = 0`), and `c` is the length of the copy (max of 64). +/// +/// We could pack this in fewer bits, but the position of the three `b` bits +/// lines up with the most significant three bits in the total offset for copy +/// 1, which avoids an extra shift instruction. +/// +/// In sum, this table is useful because it reduces branches and various +/// arithmetic operations. +struct TagLookupTable([u16; 256]); + +impl TagLookupTable { + /// Look up the tag entry given the tag `byte`. + #[inline(always)] + fn entry(&self, byte: u8) -> TagEntry { + TagEntry(self.0[byte as usize] as usize) + } +} + +/// Represents a single entry in the tag lookup table. +/// +/// See the documentation in `TagLookupTable` for the bit layout. +/// +/// The type is a `usize` for convenience. +struct TagEntry(usize); + +impl TagEntry { + /// Return the total number of bytes proceding this tag byte required to + /// encode the offset. + fn num_tag_bytes(&self) -> usize { + self.0 >> 11 + } + + /// Return the total copy length, capped at 255. + fn len(&self) -> usize { + self.0 & 0xFF + } + + /// Return the copy offset corresponding to this copy operation. `s` should + /// point to the position just after the tag byte that this entry was read + /// from. + /// + /// This requires reading from the compressed input since the offset is + /// encoded in bytes proceding the tag byte. + fn offset(&self, src: &[u8], s: usize) -> Result { + let num_tag_bytes = self.num_tag_bytes(); + let trailer = + // It is critical for this case to come first, since it is the + // fast path. We really hope that this case gets branch + // predicted. + if s + 4 <= src.len() { + unsafe { + // SAFETY: The conditional above guarantees that + // src[s..s+4] is valid to read from. + let p = src.as_ptr().add(s); + // We use WORD_MASK here to mask out the bits we don't + // need. While we're guaranteed to read 4 valid bytes, + // not all of those bytes are necessarily part of the + // offset. This is the key optimization: we don't need to + // branch on num_tag_bytes. + bytes::loadu_u32_le(p) as usize & WORD_MASK[num_tag_bytes] + } + } else if num_tag_bytes == 1 { + if s >= src.len() { + return Err(Error::CopyRead { + len: 1, + src_len: (src.len() - s) as u64, + }); + } + src[s] as usize + } else if num_tag_bytes == 2 { + if s + 1 >= src.len() { + return Err(Error::CopyRead { + len: 2, + src_len: (src.len() - s) as u64, + }); + } + bytes::read_u16_le(&src[s..]) as usize + } else { + return Err(Error::CopyRead { + len: num_tag_bytes as u64, + src_len: (src.len() - s) as u64, + }); + }; + Ok((self.0 & 0b0000_0111_0000_0000) | trailer) + } +} diff --git a/vendor/snap/src/error.rs b/vendor/snap/src/error.rs new file mode 100644 index 0000000000..be23d795b8 --- /dev/null +++ b/vendor/snap/src/error.rs @@ -0,0 +1,333 @@ +use std::fmt; +use std::io; +use std::result; + +/// A convenient type alias for `Result`. +pub type Result = result::Result; + +/// `IntoInnerError` occurs when consuming an encoder fails. +/// +/// Consuming the encoder causes a flush to happen. If the flush fails, then +/// this error is returned, which contains both the original encoder and the +/// error that occurred. +/// +/// The type parameter `W` is the unconsumed writer. +pub struct IntoInnerError { + wtr: W, + err: io::Error, +} + +impl IntoInnerError { + pub(crate) fn new(wtr: W, err: io::Error) -> IntoInnerError { + IntoInnerError { wtr, err } + } + + /// Returns the error which caused the call to `into_inner` to fail. + /// + /// This error was returned when attempting to flush the internal buffer. + pub fn error(&self) -> &io::Error { + &self.err + } + + /// Returns the underlying writer which generated the error. + /// + /// The returned value can be used for error recovery, such as + /// re-inspecting the buffer. + pub fn into_inner(self) -> W { + self.wtr + } +} + +impl std::error::Error for IntoInnerError {} + +impl fmt::Display for IntoInnerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.err.fmt(f) + } +} + +impl fmt::Debug for IntoInnerError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + self.err.fmt(f) + } +} + +/// Error describes all the possible errors that may occur during Snappy +/// compression or decompression. +/// +/// Note that it's unlikely that you'll need to care about the specific error +/// reported since all of them indicate a corrupt Snappy data or a limitation +/// that cannot be worked around. Therefore, +/// `From for std::io::Error` is provided so that any Snappy +/// errors will be converted to a `std::io::Error` automatically when using +/// `try!`. +#[derive(Debug)] +pub enum Error { + /// This error occurs when the given input is too big. This can happen + /// during compression or decompression. + TooBig { + /// The size of the given input. + given: u64, + /// The maximum allowed size of an input buffer. + max: u64, + }, + /// This error occurs when the given buffer is too small to contain the + /// maximum possible compressed bytes or the total number of decompressed + /// bytes. + BufferTooSmall { + /// The size of the given output buffer. + given: u64, + /// The minimum size of the output buffer. + min: u64, + }, + /// This error occurs when trying to decompress a zero length buffer. + Empty, + /// This error occurs when an invalid header is found during decompression. + Header, + /// This error occurs when there is a mismatch between the number of + /// decompressed bytes reported in the header and the number of + /// actual decompressed bytes. In this error case, the number of actual + /// decompressed bytes is always less than the number reported in the + /// header. + HeaderMismatch { + /// The total number of decompressed bytes expected (i.e., the header + /// value). + expected_len: u64, + /// The total number of actual decompressed bytes. + got_len: u64, + }, + /// This error occurs during decompression when there was a problem + /// reading a literal. + Literal { + /// The expected length of the literal. + len: u64, + /// The number of remaining bytes in the compressed bytes. + src_len: u64, + /// The number of remaining slots in the decompression buffer. + dst_len: u64, + }, + /// This error occurs during decompression when there was a problem + /// reading a copy. + CopyRead { + /// The expected length of the copy (as encoded in the compressed + /// bytes). + len: u64, + /// The number of remaining bytes in the compressed bytes. + src_len: u64, + }, + /// This error occurs during decompression when there was a problem + /// writing a copy to the decompression buffer. + CopyWrite { + /// The length of the copy (i.e., the total number of bytes to be + /// produced by this copy in the decompression buffer). + len: u64, + /// The number of remaining bytes in the decompression buffer. + dst_len: u64, + }, + /// This error occurs during decompression when an invalid copy offset + /// is found. An offset is invalid if it is zero or if it is out of bounds. + Offset { + /// The offset that was read. + offset: u64, + /// The current position in the decompression buffer. If the offset is + /// non-zero, then the offset must be greater than this position. + dst_pos: u64, + }, + /// This error occurs when a stream header chunk type was expected but got + /// a different chunk type. + /// This error only occurs when reading a Snappy frame formatted stream. + StreamHeader { + /// The chunk type byte that was read. + byte: u8, + }, + /// This error occurs when the magic stream headers bytes do not match + /// what is expected. + /// This error only occurs when reading a Snappy frame formatted stream. + StreamHeaderMismatch { + /// The bytes that were read. + bytes: Vec, + }, + /// This error occurs when an unsupported chunk type is seen. + /// This error only occurs when reading a Snappy frame formatted stream. + UnsupportedChunkType { + /// The chunk type byte that was read. + byte: u8, + }, + /// This error occurs when trying to read a chunk with an unexpected or + /// incorrect length when reading a Snappy frame formatted stream. + /// This error only occurs when reading a Snappy frame formatted stream. + UnsupportedChunkLength { + /// The length of the chunk encountered. + len: u64, + /// True when this error occured while reading the stream header. + header: bool, + }, + /// This error occurs when a checksum validity check fails. + /// This error only occurs when reading a Snappy frame formatted stream. + Checksum { + /// The expected checksum read from the stream. + expected: u32, + /// The computed checksum. + got: u32, + }, +} + +impl From for io::Error { + fn from(err: Error) -> io::Error { + io::Error::new(io::ErrorKind::Other, err) + } +} + +impl Eq for Error {} + +impl PartialEq for Error { + fn eq(&self, other: &Error) -> bool { + use self::Error::*; + match (self, other) { + ( + &TooBig { given: given1, max: max1 }, + &TooBig { given: given2, max: max2 }, + ) => (given1, max1) == (given2, max2), + ( + &BufferTooSmall { given: given1, min: min1 }, + &BufferTooSmall { given: given2, min: min2 }, + ) => (given1, min1) == (given2, min2), + (&Empty, &Empty) | (&Header, &Header) => true, + ( + &HeaderMismatch { expected_len: elen1, got_len: glen1 }, + &HeaderMismatch { expected_len: elen2, got_len: glen2 }, + ) => (elen1, glen1) == (elen2, glen2), + ( + &Literal { len: len1, src_len: src_len1, dst_len: dst_len1 }, + &Literal { len: len2, src_len: src_len2, dst_len: dst_len2 }, + ) => (len1, src_len1, dst_len1) == (len2, src_len2, dst_len2), + ( + &CopyRead { len: len1, src_len: src_len1 }, + &CopyRead { len: len2, src_len: src_len2 }, + ) => (len1, src_len1) == (len2, src_len2), + ( + &CopyWrite { len: len1, dst_len: dst_len1 }, + &CopyWrite { len: len2, dst_len: dst_len2 }, + ) => (len1, dst_len1) == (len2, dst_len2), + ( + &Offset { offset: offset1, dst_pos: dst_pos1 }, + &Offset { offset: offset2, dst_pos: dst_pos2 }, + ) => (offset1, dst_pos1) == (offset2, dst_pos2), + (&StreamHeader { byte: byte1 }, &StreamHeader { byte: byte2 }) => { + byte1 == byte2 + } + ( + &StreamHeaderMismatch { bytes: ref bytes1 }, + &StreamHeaderMismatch { bytes: ref bytes2 }, + ) => bytes1 == bytes2, + ( + &UnsupportedChunkType { byte: byte1 }, + &UnsupportedChunkType { byte: byte2 }, + ) => byte1 == byte2, + ( + &UnsupportedChunkLength { len: len1, header: header1 }, + &UnsupportedChunkLength { len: len2, header: header2 }, + ) => (len1, header1) == (len2, header2), + ( + &Checksum { expected: e1, got: g1 }, + &Checksum { expected: e2, got: g2 }, + ) => (e1, g1) == (e2, g2), + _ => false, + } + } +} + +impl std::error::Error for Error {} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + Error::TooBig { given, max } => write!( + f, + "snappy: input buffer (size = {}) is larger than \ + allowed (size = {})", + given, max + ), + Error::BufferTooSmall { given, min } => write!( + f, + "snappy: output buffer (size = {}) is smaller than \ + required (size = {})", + given, min + ), + Error::Empty => write!(f, "snappy: corrupt input (empty)"), + Error::Header => { + write!(f, "snappy: corrupt input (invalid header)") + } + Error::HeaderMismatch { expected_len, got_len } => write!( + f, + "snappy: corrupt input (header mismatch; expected \ + {} decompressed bytes but got {})", + expected_len, got_len + ), + Error::Literal { len, src_len, dst_len } => write!( + f, + "snappy: corrupt input (expected literal read of \ + length {}; remaining src: {}; remaining dst: {})", + len, src_len, dst_len + ), + Error::CopyRead { len, src_len } => write!( + f, + "snappy: corrupt input (expected copy read of \ + length {}; remaining src: {})", + len, src_len + ), + Error::CopyWrite { len, dst_len } => write!( + f, + "snappy: corrupt input (expected copy write of \ + length {}; remaining dst: {})", + len, dst_len + ), + Error::Offset { offset, dst_pos } => write!( + f, + "snappy: corrupt input (expected valid offset but \ + got offset {}; dst position: {})", + offset, dst_pos + ), + Error::StreamHeader { byte } => write!( + f, + "snappy: corrupt input (expected stream header but \ + got unexpected chunk type byte {})", + byte + ), + Error::StreamHeaderMismatch { ref bytes } => write!( + f, + "snappy: corrupt input (expected sNaPpY stream \ + header but got {})", + escape(&**bytes) + ), + Error::UnsupportedChunkType { byte } => write!( + f, + "snappy: corrupt input (unsupported chunk type: {})", + byte + ), + Error::UnsupportedChunkLength { len, header: false } => write!( + f, + "snappy: corrupt input \ + (unsupported chunk length: {})", + len + ), + Error::UnsupportedChunkLength { len, header: true } => write!( + f, + "snappy: corrupt input \ + (invalid stream header length: {})", + len + ), + Error::Checksum { expected, got } => write!( + f, + "snappy: corrupt input (bad checksum; \ + expected: {}, got: {})", + expected, got + ), + } + } +} + +fn escape(bytes: &[u8]) -> String { + use std::ascii::escape_default; + bytes.iter().flat_map(|&b| escape_default(b)).map(|b| b as char).collect() +} diff --git a/vendor/snap/src/frame.rs b/vendor/snap/src/frame.rs new file mode 100644 index 0000000000..3c56f9a881 --- /dev/null +++ b/vendor/snap/src/frame.rs @@ -0,0 +1,104 @@ +use crate::bytes; +use crate::compress::{max_compress_len, Encoder}; +use crate::crc32::CheckSummer; +use crate::error::Error; +use crate::MAX_BLOCK_SIZE; + +/// The maximum chunk of compressed bytes that can be processed at one time. +/// +/// This is computed via `max_compress_len(MAX_BLOCK_SIZE)`. +/// +/// TODO(ag): Replace with const fn once they support nominal branching. +pub const MAX_COMPRESS_BLOCK_SIZE: usize = 76490; + +/// The special magic string that starts any stream. +/// +/// This may appear more than once in a stream in order to support easy +/// concatenation of files compressed in the Snappy frame format. +pub const STREAM_IDENTIFIER: &'static [u8] = b"\xFF\x06\x00\x00sNaPpY"; + +/// The body of the special stream identifier. +pub const STREAM_BODY: &'static [u8] = b"sNaPpY"; + +/// The length of a snappy chunk type (1 byte), packet length (3 bytes) +/// and CRC field (4 bytes). This is technically the chunk header _plus_ +/// the CRC present in most chunks. +pub const CHUNK_HEADER_AND_CRC_SIZE: usize = 8; + +/// An enumeration describing each of the 4 main chunk types. +#[derive(Copy, Clone, Debug, Eq, PartialEq)] +pub enum ChunkType { + Stream = 0xFF, + Compressed = 0x00, + Uncompressed = 0x01, + Padding = 0xFE, +} + +impl ChunkType { + /// Converts a byte to one of the four defined chunk types represented by + /// a single byte. If the chunk type is reserved, then it is returned as + /// an Err. + pub fn from_u8(b: u8) -> Result { + match b { + 0xFF => Ok(ChunkType::Stream), + 0x00 => Ok(ChunkType::Compressed), + 0x01 => Ok(ChunkType::Uncompressed), + 0xFE => Ok(ChunkType::Padding), + b => Err(b), + } + } +} + +/// Compress a single frame (or decide to pass it through uncompressed). This +/// will output a frame header in `dst_chunk_header`, and it will return a slice +/// pointing to the data to use in the frame. The `dst_chunk_header` array must +/// always have a size of 8 bytes. +/// +/// If `always_use_dst` is set to false, the return value may point into either +/// `src` (for data we couldn't compress) or into `dst` (for data we could +/// compress). If `always_use_dst` is true, the data will always be in `dst`. +/// This is a bit weird, but because of Rust's ownership rules, it's easiest +/// for a single function to always be in charge of writing to `dst`. +pub fn compress_frame<'a>( + enc: &mut Encoder, + checksummer: CheckSummer, + src: &'a [u8], + dst_chunk_header: &mut [u8], + dst: &'a mut [u8], + always_use_dst: bool, +) -> Result<&'a [u8], Error> { + // This is a purely internal function, with a bunch of preconditions. + assert!(src.len() <= MAX_BLOCK_SIZE); + assert!(dst.len() >= max_compress_len(MAX_BLOCK_SIZE)); + assert_eq!(dst_chunk_header.len(), CHUNK_HEADER_AND_CRC_SIZE); + + // Build a checksum of our _uncompressed_ data. + let checksum = checksummer.crc32c_masked(src); + + // Compress the buffer. If compression sucked, throw it out and + // write uncompressed bytes instead. Since our buffer is at most + // MAX_BLOCK_SIZE and our dst buffer has size + // max_compress_len(MAX_BLOCK_SIZE), we have enough space. + let compress_len = enc.compress(src, dst)?; + let (chunk_type, chunk_len) = + // We add 4 to the chunk_len because of the checksum. + if compress_len >= src.len() - (src.len() / 8) { + (ChunkType::Uncompressed, 4 + src.len()) + } else { + (ChunkType::Compressed, 4 + compress_len) + }; + + dst_chunk_header[0] = chunk_type as u8; + bytes::write_u24_le(chunk_len as u32, &mut dst_chunk_header[1..]); + bytes::write_u32_le(checksum, &mut dst_chunk_header[4..]); + + // Return the data to put in our frame. + if chunk_type == ChunkType::Compressed { + Ok(&dst[0..compress_len]) + } else if always_use_dst { + dst[..src.len()].copy_from_slice(src); + Ok(&dst[..src.len()]) + } else { + Ok(src) + } +} diff --git a/vendor/snap/src/lib.rs b/vendor/snap/src/lib.rs new file mode 100644 index 0000000000..06fbfeda75 --- /dev/null +++ b/vendor/snap/src/lib.rs @@ -0,0 +1,109 @@ +/*! +This crate provides an implementation of the +[Snappy compression format](https://github.com/google/snappy/blob/master/format_description.txt), +as well as the +[framing format](https://github.com/google/snappy/blob/master/framing_format.txt). +The goal of Snappy is to provide reasonable compression at high speed. On a +modern CPU, Snappy can compress data at about 300 MB/sec or more and can +decompress data at about 800 MB/sec or more. + +# Install + +To use this crate with +[Cargo](http://doc.crates.io/index.html), +simply add it as a dependency to your `Cargo.toml`: + +```ignore +[dependencies] +snap = "1" +``` + +# Overview + +This crate provides two ways to use Snappy. The first way is through the +[`read::FrameDecoder`](read/struct.FrameDecoder.html) +and +[`write::FrameEncoder`](write/struct.FrameEncoder.html) +types, which implement the `std::io::Read` and `std::io::Write` traits with the +Snappy frame format. Unless you have a specific reason to the contrary, you +should only use the Snappy frame format. Specifically, the Snappy frame format +permits streaming compression or decompression. + +The second way is through the +[`raw::Decoder`](raw/struct.Decoder.html) +and +[`raw::Encoder`](raw/struct.Encoder.html) +types. These types provide lower level control to the raw Snappy format, and +don't support a streaming interface directly. You should only use these types +if you know you specifically need the Snappy raw format. + +Finally, the `Error` type in this crate provides an exhaustive list of error +conditions that are probably useless in most circumstances. Therefore, +`From for io::Error` is implemented in this crate, which will let +you automatically convert a Snappy error to an `std::io::Error` (when using +`?`) with an appropriate error message to display to an end user. + +# Example: compress data on `stdin` + +This program reads data from `stdin`, compresses it and emits it to `stdout`. +This example can be found in `examples/compress.rs`: + +```no_run +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + let mut rdr = stdin.lock(); + // Wrap the stdout writer in a Snappy writer. + let mut wtr = snap::write::FrameEncoder::new(stdout.lock()); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} +``` + +# Example: decompress data on `stdin` + +This program reads data from `stdin`, decompresses it and emits it to `stdout`. +This example can be found in `examples/decompress.rs`: + +```no_run +use std::io; + +fn main() { + let stdin = io::stdin(); + let stdout = io::stdout(); + + // Wrap the stdin reader in a Snappy reader. + let mut rdr = snap::read::FrameDecoder::new(stdin.lock()); + let mut wtr = stdout.lock(); + io::copy(&mut rdr, &mut wtr).expect("I/O operation failed"); +} +``` +*/ + +#![deny(missing_docs)] + +#[cfg(test)] +doc_comment::doctest!("../README.md"); + +pub use crate::error::{Error, Result}; + +/// We don't permit compressing a block bigger than what can fit in a u32. +const MAX_INPUT_SIZE: u64 = std::u32::MAX as u64; + +/// The maximum number of bytes that we process at once. A block is the unit +/// at which we scan for candidates for compression. +const MAX_BLOCK_SIZE: usize = 1 << 16; + +mod bytes; +mod compress; +mod crc32; +mod crc32_table; +mod decompress; +mod error; +mod frame; +pub mod raw; +pub mod read; +mod tag; +pub mod write; diff --git a/vendor/snap/src/raw.rs b/vendor/snap/src/raw.rs new file mode 100644 index 0000000000..8b0eed2632 --- /dev/null +++ b/vendor/snap/src/raw.rs @@ -0,0 +1,14 @@ +/*! +This module provides a raw Snappy encoder and decoder. + +A raw Snappy encoder/decoder can only compress/decompress a fixed amount of +data at a time. For this reason, this module is lower level and more difficult +to use than the higher level streaming readers and writers exposed as part of +the [`read`](../read/index.html) and [`write`](../write/index.html) modules. + +Generally, one only needs to use the raw format if some other source is +generating raw Snappy compressed data and you have no choice but to do the +same. Otherwise, the Snappy frame format should probably always be preferred. +*/ +pub use crate::compress::{max_compress_len, Encoder}; +pub use crate::decompress::{decompress_len, Decoder}; diff --git a/vendor/snap/src/read.rs b/vendor/snap/src/read.rs new file mode 100644 index 0000000000..362c2d7ba0 --- /dev/null +++ b/vendor/snap/src/read.rs @@ -0,0 +1,444 @@ +/*! +This module provides two `std::io::Read` implementations: + +* [`read::FrameDecoder`](struct.FrameDecoder.html) + wraps another `std::io::Read` implemenation, and decompresses data encoded + using the Snappy frame format. Use this if you have a compressed data source + and wish to read it as uncompressed data. +* [`read::FrameEncoder`](struct.FrameEncoder.html) + wraps another `std::io::Read` implemenation, and compresses data encoded + using the Snappy frame format. Use this if you have uncompressed data source + and wish to read it as compressed data. + +Typically, `read::FrameDecoder` is the version that you'll want. +*/ + +use std::cmp; +use std::fmt; +use std::io; + +use crate::bytes; +use crate::compress::Encoder; +use crate::crc32::CheckSummer; +use crate::decompress::{decompress_len, Decoder}; +use crate::error::Error; +use crate::frame::{ + compress_frame, ChunkType, CHUNK_HEADER_AND_CRC_SIZE, + MAX_COMPRESS_BLOCK_SIZE, STREAM_BODY, STREAM_IDENTIFIER, +}; +use crate::MAX_BLOCK_SIZE; + +/// The maximum size of a compressed block, including the header and stream +/// identifier, that can be emitted by FrameEncoder. +const MAX_READ_FRAME_ENCODER_BLOCK_SIZE: usize = STREAM_IDENTIFIER.len() + + CHUNK_HEADER_AND_CRC_SIZE + + MAX_COMPRESS_BLOCK_SIZE; + +/// A reader for decompressing a Snappy stream. +/// +/// This `FrameDecoder` wraps any other reader that implements `std::io::Read`. +/// Bytes read from this reader are decompressed using the +/// [Snappy frame format](https://github.com/google/snappy/blob/master/framing_format.txt) +/// (file extension `sz`, MIME type `application/x-snappy-framed`). +/// +/// This reader can potentially make many small reads from the underlying +/// stream depending on its format, therefore, passing in a buffered reader +/// may be beneficial. +pub struct FrameDecoder { + /// The underlying reader. + r: R, + /// A Snappy decoder that we reuse that does the actual block based + /// decompression. + dec: Decoder, + /// A CRC32 checksummer that is configured to either use the portable + /// fallback version or the SSE4.2 accelerated version when the right CPU + /// features are available. + checksummer: CheckSummer, + /// The compressed bytes buffer, taken from the underlying reader. + src: Vec, + /// The decompressed bytes buffer. Bytes are decompressed from src to dst + /// before being passed back to the caller. + dst: Vec, + /// Index into dst: starting point of bytes not yet given back to caller. + dsts: usize, + /// Index into dst: ending point of bytes not yet given back to caller. + dste: usize, + /// Whether we've read the special stream header or not. + read_stream_ident: bool, +} + +impl FrameDecoder { + /// Create a new reader for streaming Snappy decompression. + pub fn new(rdr: R) -> FrameDecoder { + FrameDecoder { + r: rdr, + dec: Decoder::new(), + checksummer: CheckSummer::new(), + src: vec![0; MAX_COMPRESS_BLOCK_SIZE], + dst: vec![0; MAX_BLOCK_SIZE], + dsts: 0, + dste: 0, + read_stream_ident: false, + } + } + + /// Gets a reference to the underlying reader in this decoder. + pub fn get_ref(&self) -> &R { + &self.r + } + + /// Gets a mutable reference to the underlying reader in this decoder. + /// + /// Note that mutation of the stream may result in surprising results if + /// this decoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.r + } +} + +impl io::Read for FrameDecoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + macro_rules! fail { + ($err:expr) => { + return Err(io::Error::from($err)); + }; + } + loop { + if self.dsts < self.dste { + let len = cmp::min(self.dste - self.dsts, buf.len()); + let dste = self.dsts.checked_add(len).unwrap(); + buf[0..len].copy_from_slice(&self.dst[self.dsts..dste]); + self.dsts = dste; + return Ok(len); + } + if !read_exact_eof(&mut self.r, &mut self.src[0..4])? { + return Ok(0); + } + let ty = ChunkType::from_u8(self.src[0]); + if !self.read_stream_ident { + if ty != Ok(ChunkType::Stream) { + fail!(Error::StreamHeader { byte: self.src[0] }); + } + self.read_stream_ident = true; + } + let len64 = bytes::read_u24_le(&self.src[1..]) as u64; + if len64 > self.src.len() as u64 { + fail!(Error::UnsupportedChunkLength { + len: len64, + header: false, + }); + } + let len = len64 as usize; + match ty { + Err(b) if 0x02 <= b && b <= 0x7F => { + // Spec says that chunk types 0x02-0x7F are reserved and + // conformant decoders must return an error. + fail!(Error::UnsupportedChunkType { byte: b }); + } + Err(b) if 0x80 <= b && b <= 0xFD => { + // Spec says that chunk types 0x80-0xFD are reserved but + // skippable. + self.r.read_exact(&mut self.src[0..len])?; + } + Err(b) => { + // Can never happen. 0x02-0x7F and 0x80-0xFD are handled + // above in the error case. That leaves 0x00, 0x01, 0xFE + // and 0xFF, each of which correspond to one of the four + // defined chunk types. + unreachable!("BUG: unhandled chunk type: {}", b); + } + Ok(ChunkType::Padding) => { + // Just read and move on. + self.r.read_exact(&mut self.src[0..len])?; + } + Ok(ChunkType::Stream) => { + if len != STREAM_BODY.len() { + fail!(Error::UnsupportedChunkLength { + len: len64, + header: true, + }) + } + self.r.read_exact(&mut self.src[0..len])?; + if &self.src[0..len] != STREAM_BODY { + fail!(Error::StreamHeaderMismatch { + bytes: self.src[0..len].to_vec(), + }); + } + } + Ok(ChunkType::Uncompressed) => { + if len < 4 { + fail!(Error::UnsupportedChunkLength { + len: len as u64, + header: false, + }); + } + let expected_sum = bytes::io_read_u32_le(&mut self.r)?; + let n = len - 4; + if n > self.dst.len() { + fail!(Error::UnsupportedChunkLength { + len: n as u64, + header: false, + }); + } + self.r.read_exact(&mut self.dst[0..n])?; + let got_sum = + self.checksummer.crc32c_masked(&self.dst[0..n]); + if expected_sum != got_sum { + fail!(Error::Checksum { + expected: expected_sum, + got: got_sum, + }); + } + self.dsts = 0; + self.dste = n; + } + Ok(ChunkType::Compressed) => { + if len < 4 { + fail!(Error::UnsupportedChunkLength { + len: len as u64, + header: false, + }); + } + let expected_sum = bytes::io_read_u32_le(&mut self.r)?; + let sn = len - 4; + if sn > self.src.len() { + fail!(Error::UnsupportedChunkLength { + len: len64, + header: false, + }); + } + self.r.read_exact(&mut self.src[0..sn])?; + let dn = decompress_len(&self.src)?; + if dn > self.dst.len() { + fail!(Error::UnsupportedChunkLength { + len: dn as u64, + header: false, + }); + } + self.dec + .decompress(&self.src[0..sn], &mut self.dst[0..dn])?; + let got_sum = + self.checksummer.crc32c_masked(&self.dst[0..dn]); + if expected_sum != got_sum { + fail!(Error::Checksum { + expected: expected_sum, + got: got_sum, + }); + } + self.dsts = 0; + self.dste = dn; + } + } + } + } +} + +impl fmt::Debug for FrameDecoder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FrameDecoder") + .field("r", &self.r) + .field("dec", &self.dec) + .field("checksummer", &self.checksummer) + .field("src", &"[...]") + .field("dst", &"[...]") + .field("dsts", &self.dsts) + .field("dste", &self.dste) + .field("read_stream_ident", &self.read_stream_ident) + .finish() + } +} + +/// A reader for compressing data using snappy as it is read. +/// +/// This `FrameEncoder` wraps any other reader that implements `std::io::Read`. +/// Bytes read from this reader are compressed using the +/// [Snappy frame format](https://github.com/google/snappy/blob/master/framing_format.txt) +/// (file extension `sz`, MIME type `application/x-snappy-framed`). +/// +/// Usually you'll want +/// [`read::FrameDecoder`](struct.FrameDecoder.html) +/// (for decompressing while reading) or +/// [`write::FrameEncoder`](../write/struct.FrameEncoder.html) +/// (for compressing while writing) instead. +/// +/// Unlike `FrameDecoder`, this will attempt to make large reads roughly +/// equivalent to the size of a single Snappy block. Therefore, callers may not +/// benefit from using a buffered reader. +pub struct FrameEncoder { + /// Internally, we split `FrameEncoder` in two to keep the borrow checker + /// happy. The `inner` member contains everything that `read_frame` needs + /// to fetch a frame's worth of data and compress it. + inner: Inner, + /// Data that we've encoded and are ready to return to our caller. + dst: Vec, + /// Starting point of bytes in `dst` not yet given back to the caller. + dsts: usize, + /// Ending point of bytes in `dst` that we want to give to our caller. + dste: usize, +} + +struct Inner { + /// The underlying data source. + r: R, + /// An encoder that we reuse that does the actual block based compression. + enc: Encoder, + /// A CRC32 checksummer that is configured to either use the portable + /// fallback version or the SSE4.2 accelerated version when the right CPU + /// features are available. + checksummer: CheckSummer, + /// Data taken from the underlying `r`, and not yet compressed. + src: Vec, + /// Have we written the standard snappy header to `dst` yet? + wrote_stream_ident: bool, +} + +impl FrameEncoder { + /// Create a new reader for streaming Snappy compression. + pub fn new(rdr: R) -> FrameEncoder { + FrameEncoder { + inner: Inner { + r: rdr, + enc: Encoder::new(), + checksummer: CheckSummer::new(), + src: vec![0; MAX_BLOCK_SIZE], + wrote_stream_ident: false, + }, + dst: vec![0; MAX_READ_FRAME_ENCODER_BLOCK_SIZE], + dsts: 0, + dste: 0, + } + } + + /// Gets a reference to the underlying reader in this decoder. + pub fn get_ref(&self) -> &R { + &self.inner.r + } + + /// Gets a mutable reference to the underlying reader in this decoder. + /// + /// Note that mutation of the stream may result in surprising results if + /// this encoder is continued to be used. + pub fn get_mut(&mut self) -> &mut R { + &mut self.inner.r + } + + /// Read previously compressed data from `self.dst`, returning the number of + /// bytes read. If `self.dst` is empty, returns 0. + fn read_from_dst(&mut self, buf: &mut [u8]) -> usize { + let available_bytes = self.dste - self.dsts; + let count = cmp::min(available_bytes, buf.len()); + buf[..count].copy_from_slice(&self.dst[self.dsts..self.dsts + count]); + self.dsts += count; + count + } +} + +impl io::Read for FrameEncoder { + fn read(&mut self, buf: &mut [u8]) -> io::Result { + // Try reading previously compressed bytes from our `dst` buffer, if + // any. + let count = self.read_from_dst(buf); + + if count > 0 { + // We had some bytes in our `dst` buffer that we used. + Ok(count) + } else if buf.len() >= MAX_READ_FRAME_ENCODER_BLOCK_SIZE { + // Our output `buf` is big enough that we can directly write into + // it, so bypass `dst` entirely. + self.inner.read_frame(buf) + } else { + // We need to refill `self.dst`, and then return some bytes from + // that. + let count = self.inner.read_frame(&mut self.dst)?; + self.dsts = 0; + self.dste = count; + Ok(self.read_from_dst(buf)) + } + } +} + +impl Inner { + /// Read from `self.r`, and create a new frame, writing it to `dst`, which + /// must be at least `MAX_READ_FRAME_ENCODER_BLOCK_SIZE` bytes in size. + fn read_frame(&mut self, dst: &mut [u8]) -> io::Result { + debug_assert!(dst.len() >= MAX_READ_FRAME_ENCODER_BLOCK_SIZE); + + // We make one read to the underlying reader. If the underlying reader + // doesn't fill the buffer but there are still bytes to be read, then + // compression won't be optimal. The alternative would be to block + // until our buffer is maximally full (or we see EOF), but this seems + // more surprising. In general, io::Read implementations should try to + // fill the caller's buffer as much as they can, so this seems like the + // better choice. + let nread = self.r.read(&mut self.src)?; + if nread == 0 { + return Ok(0); + } + + // If we haven't yet written the stream header to `dst`, write it. + let mut dst_write_start = 0; + if !self.wrote_stream_ident { + dst[0..STREAM_IDENTIFIER.len()].copy_from_slice(STREAM_IDENTIFIER); + dst_write_start += STREAM_IDENTIFIER.len(); + self.wrote_stream_ident = true; + } + + // Reserve space for our chunk header. We need to use `split_at_mut` so + // that we can get two mutable slices pointing at non-overlapping parts + // of `dst`. + let (chunk_header, remaining_dst) = + dst[dst_write_start..].split_at_mut(CHUNK_HEADER_AND_CRC_SIZE); + dst_write_start += CHUNK_HEADER_AND_CRC_SIZE; + + // Compress our frame if possible, telling `compress_frame` to always + // put the output in `dst`. + let frame_data = compress_frame( + &mut self.enc, + self.checksummer, + &self.src[..nread], + chunk_header, + remaining_dst, + true, + )?; + Ok(dst_write_start + frame_data.len()) + } +} + +impl fmt::Debug for FrameEncoder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FrameEncoder") + .field("inner", &self.inner) + .field("dst", &"[...]") + .field("dsts", &self.dsts) + .field("dste", &self.dste) + .finish() + } +} + +impl fmt::Debug for Inner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Inner") + .field("r", &self.r) + .field("enc", &self.enc) + .field("checksummer", &self.checksummer) + .field("src", &"[...]") + .field("wrote_stream_ident", &self.wrote_stream_ident) + .finish() + } +} + +// read_exact_eof is like Read::read_exact, except it converts an UnexpectedEof +// error to a bool of false. +// +// If no error occurred, then this returns true. +fn read_exact_eof( + rdr: &mut R, + buf: &mut [u8], +) -> io::Result { + use std::io::ErrorKind::UnexpectedEof; + match rdr.read_exact(buf) { + Ok(()) => Ok(true), + Err(ref err) if err.kind() == UnexpectedEof => Ok(false), + Err(err) => Err(err), + } +} diff --git a/vendor/snap/src/tag.rs b/vendor/snap/src/tag.rs new file mode 100644 index 0000000000..6344a13fce --- /dev/null +++ b/vendor/snap/src/tag.rs @@ -0,0 +1,2 @@ +// Generated by build.rs. +include!(concat!(env!("OUT_DIR"), "/tag.rs")); diff --git a/vendor/snap/src/varint.rs b/vendor/snap/src/varint.rs new file mode 100644 index 0000000000..d4a11384f5 --- /dev/null +++ b/vendor/snap/src/varint.rs @@ -0,0 +1,31 @@ +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +pub fn write_varu64(data: &mut [u8], mut n: u64) -> usize { + let mut i = 0; + while n >= 0b1000_0000 { + data[i] = (n as u8) | 0b1000_0000; + n >>= 7; + i += 1; + } + data[i] = n as u8; + i + 1 +} + +/// https://developers.google.com/protocol-buffers/docs/encoding#varints +pub fn read_varu64(data: &[u8]) -> (u64, usize) { + let mut n: u64 = 0; + let mut shift: u32 = 0; + for (i, &b) in data.iter().enumerate() { + if b < 0b1000_0000 { + return match (b as u64).checked_shl(shift) { + None => (0, 0), + Some(b) => (n | b, i + 1), + }; + } + match ((b as u64) & 0b0111_1111).checked_shl(shift) { + None => return (0, 0), + Some(b) => n |= b, + } + shift += 7; + } + (0, 0) +} diff --git a/vendor/snap/src/write.rs b/vendor/snap/src/write.rs new file mode 100644 index 0000000000..7975bd18e3 --- /dev/null +++ b/vendor/snap/src/write.rs @@ -0,0 +1,215 @@ +/*! +This module provides a `std::io::Write` implementation: + +- `write::FrameEncoder` wraps another `std::io::Write` implemenation, and + compresses data encoded using the Snappy frame format. Use this if you have + uncompressed data source and wish to write it as compressed data. + +It would also be possible to provide a `write::FrameDecoder`, which decompresses +data as it writes it, but it hasn't been implemented yet. +*/ + +use std::fmt; +use std::io::{self, Write}; + +use crate::compress::Encoder; +use crate::crc32::CheckSummer; +pub use crate::error::IntoInnerError; +use crate::frame::{ + compress_frame, CHUNK_HEADER_AND_CRC_SIZE, MAX_COMPRESS_BLOCK_SIZE, + STREAM_IDENTIFIER, +}; +use crate::MAX_BLOCK_SIZE; + +/// A writer for compressing a Snappy stream. +/// +/// This `FrameEncoder` wraps any other writer that implements `io::Write`. +/// Bytes written to this writer are compressed using the [Snappy frame +/// format](https://github.com/google/snappy/blob/master/framing_format.txt) +/// (file extension `sz`, MIME type `application/x-snappy-framed`). +/// +/// Writes are buffered automatically, so there's no need to wrap the given +/// writer in a `std::io::BufWriter`. +/// +/// The writer will be flushed automatically when it is dropped. If an error +/// occurs, it is ignored. +pub struct FrameEncoder { + /// Our main internal state, split out for borrowck reasons (happily paid). + /// + /// Also, it's an `Option` so we can move out of it even though + /// `FrameEncoder` impls `Drop`. + inner: Option>, + /// Our buffer of uncompressed bytes. This isn't part of `inner` because + /// we may write bytes directly from the caller if the given buffer was + /// big enough. As a result, the main `write` implementation needs to + /// accept either the internal buffer or the caller's bytes directly. Since + /// `write` requires a mutable borrow, we satisfy the borrow checker by + /// separating `src` from the rest of the state. + src: Vec, +} + +struct Inner { + /// The underlying writer. + w: W, + /// An encoder that we reuse that does the actual block based compression. + enc: Encoder, + /// A CRC32 checksummer that is configured to either use the portable + /// fallback version or the SSE4.2 accelerated version when the right CPU + /// features are available. + checksummer: CheckSummer, + /// The compressed bytes buffer. Bytes are compressed from src (usually) + /// to dst before being written to w. + dst: Vec, + /// When false, the stream identifier (with magic bytes) must precede the + /// next write. + wrote_stream_ident: bool, + /// Space for writing the header of a chunk before writing it to the + /// underlying writer. + chunk_header: [u8; 8], +} + +impl FrameEncoder { + /// Create a new writer for streaming Snappy compression. + pub fn new(wtr: W) -> FrameEncoder { + FrameEncoder { + inner: Some(Inner { + w: wtr, + enc: Encoder::new(), + checksummer: CheckSummer::new(), + dst: vec![0; MAX_COMPRESS_BLOCK_SIZE], + wrote_stream_ident: false, + chunk_header: [0; CHUNK_HEADER_AND_CRC_SIZE], + }), + src: Vec::with_capacity(MAX_BLOCK_SIZE), + } + } + + /// Returns the underlying stream, consuming and flushing this writer. + /// + /// If flushing the writer caused an error, then an `IntoInnerError` is + /// returned, which contains both the writer and the original writer. + pub fn into_inner(mut self) -> Result>> { + match self.flush() { + Ok(()) => Ok(self.inner.take().unwrap().w), + Err(err) => Err(IntoInnerError::new(self, err)), + } + } + + /// Gets a reference to the underlying writer in this encoder. + pub fn get_ref(&self) -> &W { + &self.inner.as_ref().unwrap().w + } + + /// Gets a reference to the underlying writer in this encoder. + /// + /// Note that mutating the output/input state of the stream may corrupt + /// this encoder, so care must be taken when using this method. + pub fn get_mut(&mut self) -> &mut W { + &mut self.inner.as_mut().unwrap().w + } +} + +impl Drop for FrameEncoder { + fn drop(&mut self) { + if self.inner.is_some() { + // Ignore errors because we can't conceivably return an error and + // panicing in a dtor is bad juju. + let _ = self.flush(); + } + } +} + +impl io::Write for FrameEncoder { + fn write(&mut self, mut buf: &[u8]) -> io::Result { + let mut total = 0; + // If there isn't enough room to add buf to src, then add only a piece + // of it, flush it and mush on. + loop { + let free = self.src.capacity() - self.src.len(); + // n is the number of bytes extracted from buf. + let n = if buf.len() <= free { + break; + } else if self.src.is_empty() { + // If buf is bigger than our entire buffer then avoid + // the indirection and write the buffer directly. + self.inner.as_mut().unwrap().write(buf)? + } else { + self.src.extend_from_slice(&buf[0..free]); + self.flush()?; + free + }; + buf = &buf[n..]; + total += n; + } + // We're only here if buf.len() will fit within the available space of + // self.src. + debug_assert!(buf.len() <= (self.src.capacity() - self.src.len())); + self.src.extend_from_slice(buf); + total += buf.len(); + // We should never expand or contract self.src. + debug_assert!(self.src.capacity() == MAX_BLOCK_SIZE); + Ok(total) + } + + fn flush(&mut self) -> io::Result<()> { + if self.src.is_empty() { + return Ok(()); + } + self.inner.as_mut().unwrap().write(&self.src)?; + self.src.truncate(0); + Ok(()) + } +} + +impl Inner { + fn write(&mut self, mut buf: &[u8]) -> io::Result { + let mut total = 0; + if !self.wrote_stream_ident { + self.wrote_stream_ident = true; + self.w.write_all(STREAM_IDENTIFIER)?; + } + while !buf.is_empty() { + // Advance buf and get our block. + let mut src = buf; + if src.len() > MAX_BLOCK_SIZE { + src = &src[0..MAX_BLOCK_SIZE]; + } + buf = &buf[src.len()..]; + + let frame_data = compress_frame( + &mut self.enc, + self.checksummer, + src, + &mut self.chunk_header, + &mut self.dst, + false, + )?; + self.w.write_all(&self.chunk_header)?; + self.w.write_all(frame_data)?; + total += src.len(); + } + Ok(total) + } +} + +impl fmt::Debug for FrameEncoder { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("FrameEncoder") + .field("inner", &self.inner) + .field("src", &"[...]") + .finish() + } +} + +impl fmt::Debug for Inner { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + f.debug_struct("Inner") + .field("w", &self.w) + .field("enc", &self.enc) + .field("checksummer", &self.checksummer) + .field("dst", &"[...]") + .field("wrote_stream_ident", &self.wrote_stream_ident) + .field("chunk_header", &self.chunk_header) + .finish() + } +} diff --git a/vendor/stacker/.cargo-checksum.json b/vendor/stacker/.cargo-checksum.json index 113fbd2a7f..1291eb5fae 100644 --- a/vendor/stacker/.cargo-checksum.json +++ b/vendor/stacker/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"c4f854fdc0b79eddc1481a50a028cdfca71ab4ed1362a83990927392ab10950d","Cross.toml":"b5f300c31f4522caba733582f4957f693a4017f4728a69805390b63ad69eff67","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e938c263b76ff66671013f0f77755aa289e807d91b7d39471ba92dea6782929e","build.rs":"8a9274309128a737566386f2534a93c69d2991da19a4543113790bc819448a53","src/arch/asm.h":"4c4db945e854e4ce3f0b7ba8da3755613c0e4513a7aab0604bd6a67c0ff2192d","src/arch/windows.c":"e98e08f6b5102480b8fa4dfa7ee13441845202f5ba81c60b13da2800e0a8630c","src/lib.rs":"37ef9666d048191eeca23d8f7d99cf912b953cc489bf860107aec306b95b2d99","tests/simple.rs":"18fbb3e891ab486c58aa011698f755945818db8799c564f2fa8cfe5ac8d8f0dc","tests/smoke.rs":"db4fd5b210123d9643aefd703be324d626d4b0f9398d7cae7f30871fba71f65b"},"package":"a92bc346006ae78c539d6ab2cf1a1532bc657b8339c464877a990ec82073c66f"} \ No newline at end of file +{"files":{"Cargo.toml":"a86150d141236e033cf1202ad117c0aa235f04e48b8ee278c1010e175a4536d0","Cross.toml":"b5f300c31f4522caba733582f4957f693a4017f4728a69805390b63ad69eff67","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"e938c263b76ff66671013f0f77755aa289e807d91b7d39471ba92dea6782929e","build.rs":"8a9274309128a737566386f2534a93c69d2991da19a4543113790bc819448a53","src/arch/asm.h":"4c4db945e854e4ce3f0b7ba8da3755613c0e4513a7aab0604bd6a67c0ff2192d","src/arch/windows.c":"e98e08f6b5102480b8fa4dfa7ee13441845202f5ba81c60b13da2800e0a8630c","src/lib.rs":"cee329550bad2ed1182abb71db9c24558a91b12e1eab8d9a48e23b997bb8f04e","tests/simple.rs":"18fbb3e891ab486c58aa011698f755945818db8799c564f2fa8cfe5ac8d8f0dc","tests/smoke.rs":"db4fd5b210123d9643aefd703be324d626d4b0f9398d7cae7f30871fba71f65b"},"package":"21ccb4c06ec57bc82d0f610f1a2963d7648700e43a6f513e564b9c89f7991786"} \ No newline at end of file diff --git a/vendor/stacker/Cargo.toml b/vendor/stacker/Cargo.toml index b72ec90f18..c86ffaa385 100644 --- a/vendor/stacker/Cargo.toml +++ b/vendor/stacker/Cargo.toml @@ -12,12 +12,12 @@ [package] name = "stacker" -version = "0.1.11" +version = "0.1.12" authors = ["Alex Crichton ", "Simonas Kazlauskas "] build = "build.rs" description = "A stack growth library useful when implementing deeply recursive algorithms that\nmay accidentally blow the stack.\n" homepage = "https://github.com/rust-lang/stacker" -documentation = "https://docs.rs/stacker/0.1.10" +documentation = "https://docs.rs/stacker/0.1.12" readme = "README.md" license = "MIT/Apache-2.0" repository = "https://github.com/rust-lang/stacker" diff --git a/vendor/stacker/src/lib.rs b/vendor/stacker/src/lib.rs index 8d9689ed86..3c1d8891ed 100644 --- a/vendor/stacker/src/lib.rs +++ b/vendor/stacker/src/lib.rs @@ -47,7 +47,10 @@ use std::cell::Cell; pub fn maybe_grow R>(red_zone: usize, stack_size: usize, callback: F) -> R { // if we can't guess the remaining stack (unsupported on some platforms) we immediately grow // the stack and then cache the new stack size (which we do know now because we allocated it. - let enough_space = remaining_stack().map_or(false, |remaining| remaining >= red_zone); + let enough_space = match remaining_stack() { + Some(remaining) => remaining >= red_zone, + None => false, + }; if enough_space { callback() } else { @@ -59,11 +62,24 @@ pub fn maybe_grow R>(red_zone: usize, stack_size: usize, callb /// The closure will still be on the same thread as the caller of `grow`. /// This will allocate a new stack with at least `stack_size` bytes. pub fn grow R>(stack_size: usize, callback: F) -> R { + // To avoid monomorphizing `_grow()` and everything it calls, + // we convert the generic callback to a dynamic one. + let mut opt_callback = Some(callback); let mut ret = None; let ret_ref = &mut ret; - _grow(stack_size, move || { - *ret_ref = Some(callback()); - }); + + // This wrapper around `callback` achieves two things: + // * It converts the `impl FnOnce` to a `dyn FnMut`. + // `dyn` because we want it to not be generic, and + // `FnMut` because we can't pass a `dyn FnOnce` around without boxing it. + // * It eliminates the generic return value, by writing it to the stack of this function. + // Otherwise the closure would have to return an unsized value, which isn't possible. + let dyn_callback: &mut dyn FnMut() = &mut || { + let taken_callback = opt_callback.take().unwrap(); + *ret_ref = Some(taken_callback()); + }; + + _grow(stack_size, dyn_callback); ret.unwrap() } @@ -201,7 +217,7 @@ psm_stack_manipulation! { } } - fn _grow(stack_size: usize, callback: F) { + fn _grow(stack_size: usize, callback: &mut dyn FnMut()) { // Calculate a number of pages we want to allocate for the new stack. // For maximum portability we want to produce a stack that is aligned to a page and has // a size that’s a multiple of page size. Furthermore we want to allocate two extras pages @@ -249,7 +265,7 @@ psm_stack_manipulation! { no { #[cfg(not(windows))] - fn _grow(stack_size: usize, callback: F) { + fn _grow(stack_size: usize, callback: &mut dyn FnMut()) { drop(stack_size); callback(); } @@ -298,7 +314,7 @@ cfg_if! { return; } - fn _grow(stack_size: usize, callback: F) { + fn _grow(stack_size: usize, callback: &mut dyn FnMut()) { // Fibers (or stackful coroutines) is the only official way to create new stacks on the // same thread on Windows. So in order to extend the stack we create fiber and switch // to it so we can use it's stack. After running `callback` within our fiber, we switch @@ -329,8 +345,8 @@ cfg_if! { let fiber = CreateFiber( stack_size as SIZE_T, - Some(fiber_proc::), - &mut data as *mut FiberInfo as *mut _, + Some(fiber_proc::<&mut dyn FnMut()>), + &mut data as *mut FiberInfo<&mut dyn FnMut()> as *mut _, ); if fiber.is_null() { panic!("unable to allocate fiber: {}", io::Error::last_os_error()); diff --git a/vendor/syn/.cargo-checksum.json b/vendor/syn/.cargo-checksum.json index ede531a917..b325093667 100644 --- a/vendor/syn/.cargo-checksum.json +++ b/vendor/syn/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"acbdca6e2da57a8ed034f951ca16579be5ecdebaad46e7aecfeb49e9227c319f","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"03f3b53cf858536a0883aa5b5882ee61dcd0f1e71c0930c9106fcfa1d6aad2df","benches/file.rs":"b4724fc7c0f48b8f488e2632a1064f6c0bf16ded3969680fc3f4a2369536269b","benches/rust.rs":"46ace9fcd127eb7cacab10c1f3269bff0a2701cc10b80b24c7146743130c3910","build.rs":"aeca2312f05aec658eaa66980a0ef3d578837db107a55702b39419ea0422eb4a","src/attr.rs":"ecbd693423707b1f4b5d744ed6f158272c95977f3b4984f990d98e24e02f9487","src/await.rs":"18f0b2ecb319991f891e300011424985e3cf33d166ea9f29f22d575fc8c83a76","src/bigint.rs":"efc7f64959980653d73fe4f8bc2a3a2904dc05f45b02c6dc15cd316fa3d7c338","src/buffer.rs":"2779fd1057c0293cea9032d182d955537f1575a78394260356ccb5e166debe27","src/custom_keyword.rs":"9627467063e41776315a6a14b2aaea3875592d8e0ebd2dc6df1fc2f12c06f146","src/custom_punctuation.rs":"b00e7bee96eb473507527e39db65e74e71592dc06421d2cfe45ed899c17d4847","src/data.rs":"7aec9a745cd53ec95688afa353f6efb9576e7fc0143757b51d28bc3d900b1d2a","src/derive.rs":"fa71866df6e383673dd3329f455a9f953585b83f9739050be3bf1f8c6d526b96","src/discouraged.rs":"a1f3d85e20dedf50b1b7b4571d970a3a6e9b2de4afde7dd0c986fe240df2ba46","src/error.rs":"cb9b94d8aa5cab54e157e8ea38296461f07e88f80dd5a5473273feb2e1be0669","src/export.rs":"dcae67456278c0339acfbcbb4737b8d37cfba5a150ae789f31f4be79abf7e726","src/expr.rs":"03c0666e32531ce296da7be93b7bcdf48398d7f7a189703f17e42826e6fec0cc","src/ext.rs":"c99f0959fb5d5384e304d539db148a43a9401fc55cd7984280fc19e86837ee08","src/file.rs":"75167ebc77e7870122078eabde1b872c337142d4b0962c20cedffcaaa2a5b7c6","src/gen/fold.rs":"5b50e7a2ddde2f31eb5048bf3e552845e2e66edfcb6cf7f76d664d6699b6e80a","src/gen/visit.rs":"23008c170d4dd3975232876a0a654921d9b6af57372cb9fcc133ca740588d666","src/gen/visit_mut.rs":"42886c3ee02ded72d9c3eec006e20431eaee0c6b90ddefc1a36ec7bf50c6a24a","src/gen_helper.rs":"ea6c66388365971db6a2fc86cbb208f7eacde77e245bc8623f27a3642a3d7741","src/generics.rs":"8c01b433ef8fbff6de763119657f28d0dad2495196dfb9bf5d6b315950e75a9c","src/group.rs":"119b62d8481b4b1c327639bed40e114bf1969765250b68186628247fd4144b3b","src/ident.rs":"503156ce51a7ef0420892e8dbf2ecf8fe51f42a84d52cc2c05654e1a83020cbf","src/item.rs":"52ffa258a0e706ba059bc81fe8c4d717f05b36680a3e61c37ca2fe12871b3d57","src/lib.rs":"83bee7548d3a0d408bbb00294631da16e761f2c1eab4b75d7bbf5813517747a9","src/lifetime.rs":"001ecb56cb05b0f9c8a9e52f2dccd16091eb3696f1aba4c774df23a2ddea45df","src/lit.rs":"d76e60be1f3a983c209b1f97de8d682305b99357d8070f9bb73c672e068443d0","src/lookahead.rs":"5cce8b4cb345a85c24a452ea6d78eadb76f01ca0a789cbf5ce35108334904173","src/mac.rs":"465cb7e9f408d05a9a56456bdfef630d3063049ea997423a32de8605b1d62f7b","src/macros.rs":"3927364fdcf46bfebef97cf29f4b1a0c862484980707e714c4a572c5f7261065","src/op.rs":"8ff07703b14e40d64e27a06be0063c730699937959ea1cdf89eb74c33d9fffd6","src/parse.rs":"9e1cffac2806f807ab162306b694bf1f6ad5a4c4783d9bf86b9eb3ba7a560d9a","src/parse_macro_input.rs":"653a020f023cac0eccbc1fcc34aa7bf80567b43e5475deab4ad3e487a5363201","src/parse_quote.rs":"642f21e5fa54df4b7c373fb158289ee1005d49e1a49b1d194df5438faee71c46","src/pat.rs":"9f0c36e116c0e98f91becb3c39cd523c00cf02ea5797519121db40baf87eb435","src/path.rs":"f119f0c2af12fabd360eac9a2312e0f6e6c28c633c9671bde6ef0bece7c5ba3c","src/print.rs":"da6529c1d9d21aaf6c835f66b4e67eacb7cf91a10eb5e9a2143b49bf99b3b5e1","src/punctuated.rs":"9f0c0496dcf6a797668c36a9a78ccb99164e324ebd884cf91f1b103160610b0b","src/sealed.rs":"896a495a5340eec898527f18bd4ddca408ea03ea0ee3af30074ff48deace778d","src/span.rs":"748c51c6feb223c26d3b1701f5bb98aee823666c775c98106cfa24fe29d8cec1","src/spanned.rs":"7d77714d585e6f42397091ffb3a799fd7b20c05c5442c737683c429ea7d409a5","src/stmt.rs":"3917fbc897f80efe838267833c55650ff8d636cb49a6d1084e28eff65d0e3ccd","src/thread.rs":"815eca6bd64f4eef7c447f0809e84108f5428ff50225224b373efd8fbb696874","src/token.rs":"8d557fd95fe91353f64de0c2259cfbf161667b19e277daad72d0c20181ba5be5","src/tt.rs":"1cc9e200624288322f800f32e3d6e2e53da946467bb312dd40a52c02cdcc4730","src/ty.rs":"a37e458b0af3e7408634c2cd0b53dde3f8f7aaec771257cb0e5fd4fa15a96ea6","src/verbatim.rs":"802a97df997432f18cac6e6200ff6ea29fb2474986005e0fcdbc2b65197f87f7","src/whitespace.rs":"e63dd0aa3d34029f17766a8b09c1a6e4479e36c552c8b7023d710a399333aace","tests/.gitignore":"22e782449a3c216db3f7215d5fb8882e316768e40beeec3833aae419ad8941db","tests/common/eq.rs":"ad74121d35877602fdc624c5352435d9a526884487428eea72e2c4fdb3d6d810","tests/common/mod.rs":"25ef6d7daa09bad3198a0e9e91b2812425f92db7c585c1e34a03a84d7362ccd8","tests/common/parse.rs":"8b7ba32f4988c30758c108536c4877dc5a039a237bf9b0687220ef2295797bbd","tests/debug/gen.rs":"d6e2abf2a7bb58a7895a60c2f094a98a4f85c9189d02011d0dcef6ef053f26e3","tests/debug/mod.rs":"868763d0ef1609a3ad5e05e9f1bfa0f813e91e7e9a36653414a188bb2fdaa425","tests/macros/mod.rs":"c0eafa4e3845fc08f6efe6021bac37822c0ac325eb7b51194a5f35236f648d92","tests/repo/mod.rs":"4520f18d634eaee871881f1cc956a2a2efa7a08bcc1708d217ad7cf975434d8a","tests/repo/progress.rs":"c08d0314a7f3ecf760d471f27da3cd2a500aeb9f1c8331bffb2aa648f9fabf3f","tests/test_asyncness.rs":"cff01db49d28ab23b0b258bc6c0a5cc4071be4fe7248eef344a5d79d2fb649b7","tests/test_attribute.rs":"0ffd99384e1a52ae17d9fed5c4053e411e8f9018decef07ffa621d1faa7329d8","tests/test_derive_input.rs":"b1fce660c8f6244b83ed3aa04ef93edec26ab5db8d6d4ccf215a080933d0759b","tests/test_expr.rs":"0ee83f6f6de950018c043efcc3e85776b4227dae3068309998a8d9709f2fc66c","tests/test_generics.rs":"11cfddd46f55a4e0ab378872498b2ba1631f2b99beb39c53362d2105f677a569","tests/test_grouping.rs":"60504efdb75d681b4c38b7004e7754c22329653eb814013560c8046d06902a2f","tests/test_ident.rs":"9eb53d1e21edf23e7c9e14dc74dcc2b2538e9221e19dbcc0a44e3acc2e90f3f6","tests/test_item.rs":"461ed0c8648afffcea3217f52c9a88298182b4d39d73a11803b1281d99c98c25","tests/test_iterators.rs":"53ed6078d37550bd6765d2411e3660be401aef8a31a407350cc064a7d08c7c33","tests/test_lit.rs":"cbef9738f0a510389d5e9f3f08d24065408445793e8fb2165a06a328709ec8e2","tests/test_meta.rs":"1fc98af3279cadc3d8db3c7e8d4d7f9e9dbd4d17548cf6a2f6f4536ed65367f6","tests/test_parse_buffer.rs":"8bbe2d24ca8a3788f72c6908fc96c26d546f11c69687bf8d72727f851d5e2d27","tests/test_parse_stream.rs":"2f449a2c41a3dee6fd14bee24e1666a453cb808eda17332fd91afd127fcdd2a6","tests/test_pat.rs":"2cb331fe404496d51e7cc7e283ae13c519a2265ca82e1c88e113296f860c2cba","tests/test_path.rs":"fcd5591e639fc787acc9763d828a811c8114525c9341282eefda8f331e082a51","tests/test_precedence.rs":"65cb6e8559361ad83cac8a20d58900ceeb72b34f9a1a06a37ee4bd52c2bc6f41","tests/test_receiver.rs":"084eca59984b9a18651da52f2c4407355da3de1335916a12477652999e2d01cc","tests/test_round_trip.rs":"01940ccd645df4e31cc221320cbcae036e2200d2c8f412e161eea0c4f2432dd0","tests/test_shebang.rs":"404c3505569efd2195615367076f0ff5c4003c2da0ed9fbf1eb0f66c71e879c5","tests/test_should_parse.rs":"1d3535698a446e2755bfc360676bdb161841a1f454cdef6e7556c6d06a95c89d","tests/test_size.rs":"5fae772bab66809d6708232f35cfb4a287882486763b0f763feec2ad79fbb68b","tests/test_stmt.rs":"17e4355843ee2982b51faba2721a18966f8c2b9422e16b052a123b8ee8b80752","tests/test_token_trees.rs":"429ed8bdd04aa8d3baa55b61c04755b95565e23f94478b6f9c7595b93e017e0b","tests/test_ty.rs":"5b7c0bfc4963d41920dd0b39fdea419e34f00409ba86ad4211d6c3c7e8bbe1c0","tests/test_visibility.rs":"3f958e2b3b5908005e756a80eea326a91eac97cc4ab60599bebde8d4b942d65c","tests/zzz_stable.rs":"2a862e59cb446235ed99aec0e6ada8e16d3ecc30229b29d825b7c0bbc2602989"},"package":"e69abc24912995b3038597a7a593be5053eb0fb44f3cc5beec0deb421790c1f4"} \ No newline at end of file +{"files":{"Cargo.toml":"28ddb678a5ccac4423435384c8b7116f804e896eabc5aae9d5c2bc666aaebbb4","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","README.md":"03f3b53cf858536a0883aa5b5882ee61dcd0f1e71c0930c9106fcfa1d6aad2df","benches/file.rs":"b4724fc7c0f48b8f488e2632a1064f6c0bf16ded3969680fc3f4a2369536269b","benches/rust.rs":"ea6291ef2d2a83d94a3312fe179d48259f8ec0b04c961993ddd181d0a4ab740e","build.rs":"aeca2312f05aec658eaa66980a0ef3d578837db107a55702b39419ea0422eb4a","src/attr.rs":"7d79482634d6544eb4a4825405407b53660d0f5f8b929f7e1671e005b9d92038","src/await.rs":"18f0b2ecb319991f891e300011424985e3cf33d166ea9f29f22d575fc8c83a76","src/bigint.rs":"efc7f64959980653d73fe4f8bc2a3a2904dc05f45b02c6dc15cd316fa3d7c338","src/buffer.rs":"cf2a4b3bdc247b80c85ff5625a1dfb7a5f517fd835f6e1518a7b924990e4c293","src/custom_keyword.rs":"9627467063e41776315a6a14b2aaea3875592d8e0ebd2dc6df1fc2f12c06f146","src/custom_punctuation.rs":"b00e7bee96eb473507527e39db65e74e71592dc06421d2cfe45ed899c17d4847","src/data.rs":"7aec9a745cd53ec95688afa353f6efb9576e7fc0143757b51d28bc3d900b1d2a","src/derive.rs":"fa71866df6e383673dd3329f455a9f953585b83f9739050be3bf1f8c6d526b96","src/discouraged.rs":"a1f3d85e20dedf50b1b7b4571d970a3a6e9b2de4afde7dd0c986fe240df2ba46","src/error.rs":"c3005b50e3132026250c5356d0d391bf96db8087f0f5f744de98e360d8a20a3e","src/export.rs":"dcae67456278c0339acfbcbb4737b8d37cfba5a150ae789f31f4be79abf7e726","src/expr.rs":"54455fd20041996653ca5379b03cdf3c2fc1b3dd2e1149b5bc6b1dd492545d55","src/ext.rs":"870086d9021e6a6fcefa2f00cd91b55c4b74dcee8f0f6a07e76d96fb44707d61","src/file.rs":"75167ebc77e7870122078eabde1b872c337142d4b0962c20cedffcaaa2a5b7c6","src/gen/clone.rs":"0845c1bf8624c3f235cd247b4eb748e7e16b4c240097cb0ff16751f688c079ae","src/gen/debug.rs":"d24fe37f4ce1dd74f2dc54136e893782d3c4d0908323c036c97599551a56960c","src/gen/eq.rs":"1e6ef09b17ca7f36861ef23ce2a6991b231ed5f087f046469b5f23da40f5b419","src/gen/fold.rs":"3f59e59ed8ad2ab5dd347bfbe41bbc785c2aabd8ae902087a584a6daed597182","src/gen/hash.rs":"e5b2a52587173076777233a9e57e2b3c8e0dd6d6f41d16fa7c9fde68b05c2bfc","src/gen/visit.rs":"23008c170d4dd3975232876a0a654921d9b6af57372cb9fcc133ca740588d666","src/gen/visit_mut.rs":"42886c3ee02ded72d9c3eec006e20431eaee0c6b90ddefc1a36ec7bf50c6a24a","src/gen_helper.rs":"ea6c66388365971db6a2fc86cbb208f7eacde77e245bc8623f27a3642a3d7741","src/generics.rs":"d1c175284ca21e777ef0414c28383929b170ccb00aaf7a929eb18d3b05e18da8","src/group.rs":"119b62d8481b4b1c327639bed40e114bf1969765250b68186628247fd4144b3b","src/ident.rs":"503156ce51a7ef0420892e8dbf2ecf8fe51f42a84d52cc2c05654e1a83020cbf","src/item.rs":"c9ad9881e8cda8ee3f157f0c7602fc53d08a7e3288b9afc388c393689eac5aea","src/lib.rs":"558ad13779233b27bebc4b2fc8025eb1c7e57b32130dc1dd911391e27b427500","src/lifetime.rs":"f390fe06692fc51fbf3eb490bb9f795da70e4452f51c5b0df3bbaa899084ddf1","src/lit.rs":"9fab84e38756b092fbb055dcdf01e31d42d916c49e3eaae8c9019043b0ee4301","src/lookahead.rs":"5cce8b4cb345a85c24a452ea6d78eadb76f01ca0a789cbf5ce35108334904173","src/mac.rs":"e5cecea397fd01a44958162781d8d94343fe2a1b9b9754a5666c3d2ab4d7ef64","src/macros.rs":"2ce05b553f14da4ee550bb681cb0733b7186ad94719cd36f96d53e15fd02cf2b","src/op.rs":"449514e146deab0ab020bc6f764544c294dbc780941c9802bf60cf1b2839d550","src/parse.rs":"bde888c98ee259f2a73489a693515ed4875432b0d79486ac83aea19f441992a3","src/parse_macro_input.rs":"653a020f023cac0eccbc1fcc34aa7bf80567b43e5475deab4ad3e487a5363201","src/parse_quote.rs":"642f21e5fa54df4b7c373fb158289ee1005d49e1a49b1d194df5438faee71c46","src/pat.rs":"1473b258162cc822f1ee0c0869f521053ed345a140c39ed83b9b4dfb6f9f2aca","src/path.rs":"f119f0c2af12fabd360eac9a2312e0f6e6c28c633c9671bde6ef0bece7c5ba3c","src/print.rs":"da6529c1d9d21aaf6c835f66b4e67eacb7cf91a10eb5e9a2143b49bf99b3b5e1","src/punctuated.rs":"212f5a601d6c2eb8b8fa679be1167b455b595bee964d2775b0101ebb16c3eaa5","src/reserved.rs":"3625eb2a64589a4992ab79a1674e9679f465bea613ab139a671df5337e88cee6","src/sealed.rs":"896a495a5340eec898527f18bd4ddca408ea03ea0ee3af30074ff48deace778d","src/span.rs":"748c51c6feb223c26d3b1701f5bb98aee823666c775c98106cfa24fe29d8cec1","src/spanned.rs":"7d77714d585e6f42397091ffb3a799fd7b20c05c5442c737683c429ea7d409a5","src/stmt.rs":"3917fbc897f80efe838267833c55650ff8d636cb49a6d1084e28eff65d0e3ccd","src/thread.rs":"815eca6bd64f4eef7c447f0809e84108f5428ff50225224b373efd8fbb696874","src/token.rs":"a1ca6298bf6592cb80cbab1db4eac2fa4e3fa56729bb807bfb0f08ab0f229ca5","src/tt.rs":"1cc9e200624288322f800f32e3d6e2e53da946467bb312dd40a52c02cdcc4730","src/ty.rs":"cb167cbb16240c59a31b44adec175172caaf75ffef9a0bb168584b51bf105795","src/verbatim.rs":"802a97df997432f18cac6e6200ff6ea29fb2474986005e0fcdbc2b65197f87f7","src/whitespace.rs":"e63dd0aa3d34029f17766a8b09c1a6e4479e36c552c8b7023d710a399333aace","tests/.gitignore":"22e782449a3c216db3f7215d5fb8882e316768e40beeec3833aae419ad8941db","tests/common/eq.rs":"4b190a3833bdfd20a4cb1e3dff25a698751dec71d6f30249cf09426e061a4fb1","tests/common/mod.rs":"25ef6d7daa09bad3198a0e9e91b2812425f92db7c585c1e34a03a84d7362ccd8","tests/common/parse.rs":"8b7ba32f4988c30758c108536c4877dc5a039a237bf9b0687220ef2295797bbd","tests/debug/gen.rs":"d6e2abf2a7bb58a7895a60c2f094a98a4f85c9189d02011d0dcef6ef053f26e3","tests/debug/mod.rs":"868763d0ef1609a3ad5e05e9f1bfa0f813e91e7e9a36653414a188bb2fdaa425","tests/macros/mod.rs":"c0eafa4e3845fc08f6efe6021bac37822c0ac325eb7b51194a5f35236f648d92","tests/repo/mod.rs":"9e316b88d57ae213e81950c35e45443078ec90e702798353bc3528cb8a2810b6","tests/repo/progress.rs":"c08d0314a7f3ecf760d471f27da3cd2a500aeb9f1c8331bffb2aa648f9fabf3f","tests/test_asyncness.rs":"cff01db49d28ab23b0b258bc6c0a5cc4071be4fe7248eef344a5d79d2fb649b7","tests/test_attribute.rs":"0ffd99384e1a52ae17d9fed5c4053e411e8f9018decef07ffa621d1faa7329d8","tests/test_derive_input.rs":"610444351e3bf99366976bbf1da109c334a70ac9500caef366bcf9b68819829f","tests/test_expr.rs":"0ee83f6f6de950018c043efcc3e85776b4227dae3068309998a8d9709f2fc66c","tests/test_generics.rs":"9d713f90a79d6145efc89fb6f946029ca03486c632219950889da39940152ba0","tests/test_grouping.rs":"46c27baec4daaaf1e891892f0b0515ea8a44619071c7d0cc9192580916f1569f","tests/test_ident.rs":"9eb53d1e21edf23e7c9e14dc74dcc2b2538e9221e19dbcc0a44e3acc2e90f3f6","tests/test_item.rs":"461ed0c8648afffcea3217f52c9a88298182b4d39d73a11803b1281d99c98c25","tests/test_iterators.rs":"53ed6078d37550bd6765d2411e3660be401aef8a31a407350cc064a7d08c7c33","tests/test_lit.rs":"2a46c5f2f2ad1dcbb7e9b0cd11b55861c5ff818c2c4c51351d07e2daa7c74674","tests/test_meta.rs":"1fc98af3279cadc3d8db3c7e8d4d7f9e9dbd4d17548cf6a2f6f4536ed65367f6","tests/test_parse_buffer.rs":"8bbe2d24ca8a3788f72c6908fc96c26d546f11c69687bf8d72727f851d5e2d27","tests/test_parse_stream.rs":"2f449a2c41a3dee6fd14bee24e1666a453cb808eda17332fd91afd127fcdd2a6","tests/test_pat.rs":"2cb331fe404496d51e7cc7e283ae13c519a2265ca82e1c88e113296f860c2cba","tests/test_path.rs":"fcd5591e639fc787acc9763d828a811c8114525c9341282eefda8f331e082a51","tests/test_precedence.rs":"8d03656741b01e577d7501ce24332d1a4febec3e31a043e47c61062b8c527ed2","tests/test_receiver.rs":"084eca59984b9a18651da52f2c4407355da3de1335916a12477652999e2d01cc","tests/test_round_trip.rs":"ba01bf4ec04cd2d6f9e4800c343563925ae960c5f16752dc0797fda4451b6cc2","tests/test_shebang.rs":"f5772cadad5b56e3112cb16308b779f92bce1c3a48091fc9933deb2276a69331","tests/test_should_parse.rs":"1d3535698a446e2755bfc360676bdb161841a1f454cdef6e7556c6d06a95c89d","tests/test_size.rs":"5fae772bab66809d6708232f35cfb4a287882486763b0f763feec2ad79fbb68b","tests/test_stmt.rs":"17e4355843ee2982b51faba2721a18966f8c2b9422e16b052a123b8ee8b80752","tests/test_token_trees.rs":"43e56a701817e3c3bfd0cae54a457dd7a38ccb3ca19da41e2b995fdf20e6ed18","tests/test_ty.rs":"5b7c0bfc4963d41920dd0b39fdea419e34f00409ba86ad4211d6c3c7e8bbe1c0","tests/test_visibility.rs":"3f958e2b3b5908005e756a80eea326a91eac97cc4ab60599bebde8d4b942d65c","tests/zzz_stable.rs":"2a862e59cb446235ed99aec0e6ada8e16d3ecc30229b29d825b7c0bbc2602989"},"package":"963f7d3cc59b59b9325165add223142bbf1df27655d07789f109896d353d8350"} \ No newline at end of file diff --git a/vendor/syn/Cargo.toml b/vendor/syn/Cargo.toml index 8dce27e9ff..20277fc461 100644 --- a/vendor/syn/Cargo.toml +++ b/vendor/syn/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "syn" -version = "1.0.38" +version = "1.0.40" authors = ["David Tolnay "] include = ["/benches/**", "/build.rs", "/Cargo.toml", "/LICENSE-APACHE", "/LICENSE-MIT", "/README.md", "/src/**", "/tests/**"] description = "Parser for Rust source code" diff --git a/vendor/syn/benches/rust.rs b/vendor/syn/benches/rust.rs index ba9a3d4cd3..50e1a7f601 100644 --- a/vendor/syn/benches/rust.rs +++ b/vendor/syn/benches/rust.rs @@ -36,7 +36,6 @@ mod syn_parse { #[cfg(not(syn_only))] mod librustc_parse { - extern crate rustc_ast; extern crate rustc_data_structures; extern crate rustc_errors; extern crate rustc_parse; @@ -59,7 +58,7 @@ mod librustc_parse { } } - rustc_ast::with_session_globals(Edition::Edition2018, || { + rustc_span::with_session_globals(Edition::Edition2018, || { let cm = Lrc::new(SourceMap::new(FilePathMapping::empty())); let emitter = Box::new(SilentEmitter); let handler = Handler::with_emitter(false, None, emitter); diff --git a/vendor/syn/src/attr.rs b/vendor/syn/src/attr.rs index 2a4bced105..fa4f1cb2a3 100644 --- a/vendor/syn/src/attr.rs +++ b/vendor/syn/src/attr.rs @@ -9,10 +9,6 @@ use proc_macro2::TokenStream; use crate::parse::{Parse, ParseBuffer, ParseStream, Parser, Result}; #[cfg(feature = "parsing")] use crate::punctuated::Pair; -#[cfg(feature = "extra-traits")] -use crate::tt::TokenStreamHelper; -#[cfg(feature = "extra-traits")] -use std::hash::{Hash, Hasher}; ast_struct! { /// An attribute like `#[repr(transparent)]`. @@ -139,8 +135,10 @@ ast_struct! { /// let attr: ItemMod = parse_quote! { /// #[doc = r" Single line doc comments"] /// #[doc = r" We write so many!"] - /// #[doc = r" Multi-line comments... - /// May span many lines"] + /// #[doc = r" + /// * Multi-line comments... + /// * May span many lines + /// "] /// mod example { /// #![doc = r" Of course, they can be inner too"] /// #![doc = r" And fit in a single line "] @@ -148,7 +146,7 @@ ast_struct! { /// }; /// assert_eq!(doc, attr); /// ``` - pub struct Attribute #manual_extra_traits { + pub struct Attribute { pub pound_token: Token![#], pub style: AttrStyle, pub bracket_token: token::Bracket, @@ -157,34 +155,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for Attribute {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for Attribute { - fn eq(&self, other: &Self) -> bool { - self.style == other.style - && self.pound_token == other.pound_token - && self.bracket_token == other.bracket_token - && self.path == other.path - && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens) - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for Attribute { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - self.style.hash(state); - self.pound_token.hash(state); - self.bracket_token.hash(state); - self.path.hash(state); - TokenStreamHelper(&self.tokens).hash(state); - } -} - impl Attribute { /// Parses the content of the attribute, consisting of the path and tokens, /// as a [`Meta`] if possible. @@ -353,7 +323,6 @@ ast_enum! { /// - `#![feature(proc_macro)]` /// - `//! # Example` /// - `/*! Please file an issue */` - #[cfg_attr(feature = "clone-impls", derive(Copy))] pub enum AttrStyle { Outer, Inner(Token![!]), diff --git a/vendor/syn/src/buffer.rs b/vendor/syn/src/buffer.rs index 00aaa7dec5..a461cc49ea 100644 --- a/vendor/syn/src/buffer.rs +++ b/vendor/syn/src/buffer.rs @@ -134,7 +134,6 @@ impl TokenBuffer { /// stream, and have the same scope. /// /// *This type is available only if Syn is built with the `"parsing"` feature.* -#[derive(Copy, Clone, Eq, PartialEq)] pub struct Cursor<'a> { // The current entry which the `Cursor` is pointing at. ptr: *const Entry, @@ -365,6 +364,24 @@ impl<'a> Cursor<'a> { } } +impl<'a> Copy for Cursor<'a> {} + +impl<'a> Clone for Cursor<'a> { + fn clone(&self) -> Self { + *self + } +} + +impl<'a> Eq for Cursor<'a> {} + +impl<'a> PartialEq for Cursor<'a> { + fn eq(&self, other: &Self) -> bool { + let Cursor { ptr, scope, marker } = self; + let _ = marker; + *ptr == other.ptr && *scope == other.scope + } +} + pub(crate) fn same_scope(a: Cursor, b: Cursor) -> bool { a.scope == b.scope } diff --git a/vendor/syn/src/error.rs b/vendor/syn/src/error.rs index d155f98473..dba34f9254 100644 --- a/vendor/syn/src/error.rs +++ b/vendor/syn/src/error.rs @@ -81,7 +81,6 @@ pub type Result = std::result::Result; /// # } /// # } /// ``` -#[derive(Clone)] pub struct Error { messages: Vec, } @@ -288,6 +287,14 @@ impl Display for Error { } } +impl Clone for Error { + fn clone(&self) -> Self { + Error { + messages: self.messages.clone(), + } + } +} + impl Clone for ErrorMessage { fn clone(&self) -> Self { let start = self diff --git a/vendor/syn/src/expr.rs b/vendor/syn/src/expr.rs index 55a49058b0..2fe0e0b5d8 100644 --- a/vendor/syn/src/expr.rs +++ b/vendor/syn/src/expr.rs @@ -1,7 +1,7 @@ use super::*; use crate::punctuated::Punctuated; -#[cfg(feature = "extra-traits")] -use crate::tt::TokenStreamHelper; +#[cfg(feature = "full")] +use crate::reserved::Reserved; use proc_macro2::{Span, TokenStream}; #[cfg(feature = "printing")] use quote::IdentFragment; @@ -86,7 +86,7 @@ ast_enum_of_structs! { /// A sign that you may not be choosing the right variable names is if you /// see names getting repeated in your code, like accessing /// `receiver.receiver` or `pat.pat` or `cond.cond`. - pub enum Expr #manual_extra_traits { + pub enum Expr { /// A slice literal expression: `[a, b, c, d]`. Array(ExprArray), @@ -720,232 +720,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for Expr {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for Expr { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Expr::Array(this), Expr::Array(other)) => this == other, - (Expr::Assign(this), Expr::Assign(other)) => this == other, - (Expr::AssignOp(this), Expr::AssignOp(other)) => this == other, - (Expr::Async(this), Expr::Async(other)) => this == other, - (Expr::Await(this), Expr::Await(other)) => this == other, - (Expr::Binary(this), Expr::Binary(other)) => this == other, - (Expr::Block(this), Expr::Block(other)) => this == other, - (Expr::Box(this), Expr::Box(other)) => this == other, - (Expr::Break(this), Expr::Break(other)) => this == other, - (Expr::Call(this), Expr::Call(other)) => this == other, - (Expr::Cast(this), Expr::Cast(other)) => this == other, - (Expr::Closure(this), Expr::Closure(other)) => this == other, - (Expr::Continue(this), Expr::Continue(other)) => this == other, - (Expr::Field(this), Expr::Field(other)) => this == other, - (Expr::ForLoop(this), Expr::ForLoop(other)) => this == other, - (Expr::Group(this), Expr::Group(other)) => this == other, - (Expr::If(this), Expr::If(other)) => this == other, - (Expr::Index(this), Expr::Index(other)) => this == other, - (Expr::Let(this), Expr::Let(other)) => this == other, - (Expr::Lit(this), Expr::Lit(other)) => this == other, - (Expr::Loop(this), Expr::Loop(other)) => this == other, - (Expr::Macro(this), Expr::Macro(other)) => this == other, - (Expr::Match(this), Expr::Match(other)) => this == other, - (Expr::MethodCall(this), Expr::MethodCall(other)) => this == other, - (Expr::Paren(this), Expr::Paren(other)) => this == other, - (Expr::Path(this), Expr::Path(other)) => this == other, - (Expr::Range(this), Expr::Range(other)) => this == other, - (Expr::Reference(this), Expr::Reference(other)) => this == other, - (Expr::Repeat(this), Expr::Repeat(other)) => this == other, - (Expr::Return(this), Expr::Return(other)) => this == other, - (Expr::Struct(this), Expr::Struct(other)) => this == other, - (Expr::Try(this), Expr::Try(other)) => this == other, - (Expr::TryBlock(this), Expr::TryBlock(other)) => this == other, - (Expr::Tuple(this), Expr::Tuple(other)) => this == other, - (Expr::Type(this), Expr::Type(other)) => this == other, - (Expr::Unary(this), Expr::Unary(other)) => this == other, - (Expr::Unsafe(this), Expr::Unsafe(other)) => this == other, - (Expr::Verbatim(this), Expr::Verbatim(other)) => { - TokenStreamHelper(this) == TokenStreamHelper(other) - } - (Expr::While(this), Expr::While(other)) => this == other, - (Expr::Yield(this), Expr::Yield(other)) => this == other, - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for Expr { - fn hash(&self, hash: &mut H) - where - H: Hasher, - { - match self { - Expr::Array(expr) => { - hash.write_u8(0); - expr.hash(hash); - } - Expr::Assign(expr) => { - hash.write_u8(1); - expr.hash(hash); - } - Expr::AssignOp(expr) => { - hash.write_u8(2); - expr.hash(hash); - } - Expr::Async(expr) => { - hash.write_u8(3); - expr.hash(hash); - } - Expr::Await(expr) => { - hash.write_u8(4); - expr.hash(hash); - } - Expr::Binary(expr) => { - hash.write_u8(5); - expr.hash(hash); - } - Expr::Block(expr) => { - hash.write_u8(6); - expr.hash(hash); - } - Expr::Box(expr) => { - hash.write_u8(7); - expr.hash(hash); - } - Expr::Break(expr) => { - hash.write_u8(8); - expr.hash(hash); - } - Expr::Call(expr) => { - hash.write_u8(9); - expr.hash(hash); - } - Expr::Cast(expr) => { - hash.write_u8(10); - expr.hash(hash); - } - Expr::Closure(expr) => { - hash.write_u8(11); - expr.hash(hash); - } - Expr::Continue(expr) => { - hash.write_u8(12); - expr.hash(hash); - } - Expr::Field(expr) => { - hash.write_u8(13); - expr.hash(hash); - } - Expr::ForLoop(expr) => { - hash.write_u8(14); - expr.hash(hash); - } - Expr::Group(expr) => { - hash.write_u8(15); - expr.hash(hash); - } - Expr::If(expr) => { - hash.write_u8(16); - expr.hash(hash); - } - Expr::Index(expr) => { - hash.write_u8(17); - expr.hash(hash); - } - Expr::Let(expr) => { - hash.write_u8(18); - expr.hash(hash); - } - Expr::Lit(expr) => { - hash.write_u8(19); - expr.hash(hash); - } - Expr::Loop(expr) => { - hash.write_u8(20); - expr.hash(hash); - } - Expr::Macro(expr) => { - hash.write_u8(21); - expr.hash(hash); - } - Expr::Match(expr) => { - hash.write_u8(22); - expr.hash(hash); - } - Expr::MethodCall(expr) => { - hash.write_u8(23); - expr.hash(hash); - } - Expr::Paren(expr) => { - hash.write_u8(24); - expr.hash(hash); - } - Expr::Path(expr) => { - hash.write_u8(25); - expr.hash(hash); - } - Expr::Range(expr) => { - hash.write_u8(26); - expr.hash(hash); - } - Expr::Reference(expr) => { - hash.write_u8(27); - expr.hash(hash); - } - Expr::Repeat(expr) => { - hash.write_u8(28); - expr.hash(hash); - } - Expr::Return(expr) => { - hash.write_u8(29); - expr.hash(hash); - } - Expr::Struct(expr) => { - hash.write_u8(30); - expr.hash(hash); - } - Expr::Try(expr) => { - hash.write_u8(31); - expr.hash(hash); - } - Expr::TryBlock(expr) => { - hash.write_u8(32); - expr.hash(hash); - } - Expr::Tuple(expr) => { - hash.write_u8(33); - expr.hash(hash); - } - Expr::Type(expr) => { - hash.write_u8(34); - expr.hash(hash); - } - Expr::Unary(expr) => { - hash.write_u8(35); - expr.hash(hash); - } - Expr::Unsafe(expr) => { - hash.write_u8(36); - expr.hash(hash); - } - Expr::Verbatim(expr) => { - hash.write_u8(37); - TokenStreamHelper(expr).hash(hash); - } - Expr::While(expr) => { - hash.write_u8(38); - expr.hash(hash); - } - Expr::Yield(expr) => { - hash.write_u8(39); - expr.hash(hash); - } - Expr::__Nonexhaustive => unreachable!(), - } - } -} - impl Expr { #[cfg(all(feature = "parsing", feature = "full"))] pub(crate) fn replace_attrs(&mut self, new: Vec) -> Vec { @@ -1001,8 +775,7 @@ ast_enum! { /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - #[derive(Eq, PartialEq, Hash)] - pub enum Member #manual_extra_traits { + pub enum Member { /// A named field like `self.x`. Named(Ident), /// An unnamed field like `self.0`. @@ -1010,6 +783,27 @@ ast_enum! { } } +impl Eq for Member {} + +impl PartialEq for Member { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Member::Named(this), Member::Named(other)) => this == other, + (Member::Unnamed(this), Member::Unnamed(other)) => this == other, + _ => false, + } + } +} + +impl Hash for Member { + fn hash(&self, state: &mut H) { + match self { + Member::Named(m) => m.hash(state), + Member::Unnamed(m) => m.hash(state), + } + } +} + #[cfg(feature = "printing")] impl IdentFragment for Member { fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { @@ -1032,7 +826,7 @@ ast_struct! { /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - pub struct Index #manual_extra_traits { + pub struct Index { pub index: u32, pub span: Span, } @@ -1073,14 +867,6 @@ impl IdentFragment for Index { } } -#[cfg(feature = "full")] -ast_struct! { - #[derive(Default)] - pub struct Reserved { - _private: (), - } -} - #[cfg(feature = "full")] ast_struct! { /// The `::<>` explicit type parameters passed to a method call: @@ -1179,7 +965,6 @@ ast_enum! { /// Limit types of a range, inclusive or exclusive. /// /// *This type is available only if Syn is built with the `"full"` feature.* - #[cfg_attr(feature = "clone-impls", derive(Copy))] pub enum RangeLimits { /// Inclusive at the beginning, exclusive at the end. HalfOpen(Token![..]), @@ -1212,6 +997,7 @@ pub(crate) mod parsing { use crate::parse::{Parse, ParseStream, Result}; use crate::path; + use std::cmp::Ordering; crate::custom_keyword!(raw); @@ -1220,10 +1006,8 @@ pub(crate) mod parsing { // // Struct literals are ambiguous in certain positions // https://github.com/rust-lang/rfcs/pull/92 - #[derive(Copy, Clone)] pub struct AllowStruct(bool); - #[derive(Copy, Clone, PartialEq, PartialOrd)] enum Precedence { Any, Assign, @@ -1364,6 +1148,36 @@ pub(crate) mod parsing { } } + impl Copy for AllowStruct {} + + impl Clone for AllowStruct { + fn clone(&self) -> Self { + *self + } + } + + impl Copy for Precedence {} + + impl Clone for Precedence { + fn clone(&self) -> Self { + *self + } + } + + impl PartialEq for Precedence { + fn eq(&self, other: &Self) -> bool { + *self as u8 == *other as u8 + } + } + + impl PartialOrd for Precedence { + fn partial_cmp(&self, other: &Self) -> Option { + let this = *self as u8; + let other = *other as u8; + Some(this.cmp(&other)) + } + } + #[cfg(feature = "full")] fn parse_expr( input: ParseStream, diff --git a/vendor/syn/src/ext.rs b/vendor/syn/src/ext.rs index b58baaafc3..4f9bc145d9 100644 --- a/vendor/syn/src/ext.rs +++ b/vendor/syn/src/ext.rs @@ -129,7 +129,13 @@ mod private { impl Sealed for Ident {} - #[derive(Copy, Clone)] pub struct PeekFn; pub struct IdentAny; + + impl Copy for PeekFn {} + impl Clone for PeekFn { + fn clone(&self) -> Self { + *self + } + } } diff --git a/vendor/syn/src/gen/clone.rs b/vendor/syn/src/gen/clone.rs new file mode 100644 index 0000000000..bea3887013 --- /dev/null +++ b/vendor/syn/src/gen/clone.rs @@ -0,0 +1,2051 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +#![allow(clippy::clone_on_copy, clippy::expl_impl_clone_on_copy)] +use crate::*; +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Abi { + fn clone(&self) -> Self { + Abi { + extern_token: self.extern_token.clone(), + name: self.name.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for AngleBracketedGenericArguments { + fn clone(&self) -> Self { + AngleBracketedGenericArguments { + colon2_token: self.colon2_token.clone(), + lt_token: self.lt_token.clone(), + args: self.args.clone(), + gt_token: self.gt_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for Arm { + fn clone(&self) -> Self { + Arm { + attrs: self.attrs.clone(), + pat: self.pat.clone(), + guard: self.guard.clone(), + fat_arrow_token: self.fat_arrow_token.clone(), + body: self.body.clone(), + comma: self.comma.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Copy for AttrStyle {} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for AttrStyle { + fn clone(&self) -> Self { + *self + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Attribute { + fn clone(&self) -> Self { + Attribute { + pound_token: self.pound_token.clone(), + style: self.style.clone(), + bracket_token: self.bracket_token.clone(), + path: self.path.clone(), + tokens: self.tokens.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for BareFnArg { + fn clone(&self) -> Self { + BareFnArg { + attrs: self.attrs.clone(), + name: self.name.clone(), + ty: self.ty.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Copy for BinOp {} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for BinOp { + fn clone(&self) -> Self { + *self + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Binding { + fn clone(&self) -> Self { + Binding { + ident: self.ident.clone(), + eq_token: self.eq_token.clone(), + ty: self.ty.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for Block { + fn clone(&self) -> Self { + Block { + brace_token: self.brace_token.clone(), + stmts: self.stmts.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for BoundLifetimes { + fn clone(&self) -> Self { + BoundLifetimes { + for_token: self.for_token.clone(), + lt_token: self.lt_token.clone(), + lifetimes: self.lifetimes.clone(), + gt_token: self.gt_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ConstParam { + fn clone(&self) -> Self { + ConstParam { + attrs: self.attrs.clone(), + const_token: self.const_token.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + eq_token: self.eq_token.clone(), + default: self.default.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Constraint { + fn clone(&self) -> Self { + Constraint { + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + bounds: self.bounds.clone(), + } + } +} +#[cfg(feature = "derive")] +impl Clone for Data { + fn clone(&self) -> Self { + match self { + Data::Struct(v0) => Data::Struct(v0.clone()), + Data::Enum(v0) => Data::Enum(v0.clone()), + Data::Union(v0) => Data::Union(v0.clone()), + } + } +} +#[cfg(feature = "derive")] +impl Clone for DataEnum { + fn clone(&self) -> Self { + DataEnum { + enum_token: self.enum_token.clone(), + brace_token: self.brace_token.clone(), + variants: self.variants.clone(), + } + } +} +#[cfg(feature = "derive")] +impl Clone for DataStruct { + fn clone(&self) -> Self { + DataStruct { + struct_token: self.struct_token.clone(), + fields: self.fields.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "derive")] +impl Clone for DataUnion { + fn clone(&self) -> Self { + DataUnion { + union_token: self.union_token.clone(), + fields: self.fields.clone(), + } + } +} +#[cfg(feature = "derive")] +impl Clone for DeriveInput { + fn clone(&self) -> Self { + DeriveInput { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + data: self.data.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Expr { + fn clone(&self) -> Self { + match self { + #[cfg(feature = "full")] + Expr::Array(v0) => Expr::Array(v0.clone()), + #[cfg(feature = "full")] + Expr::Assign(v0) => Expr::Assign(v0.clone()), + #[cfg(feature = "full")] + Expr::AssignOp(v0) => Expr::AssignOp(v0.clone()), + #[cfg(feature = "full")] + Expr::Async(v0) => Expr::Async(v0.clone()), + #[cfg(feature = "full")] + Expr::Await(v0) => Expr::Await(v0.clone()), + Expr::Binary(v0) => Expr::Binary(v0.clone()), + #[cfg(feature = "full")] + Expr::Block(v0) => Expr::Block(v0.clone()), + #[cfg(feature = "full")] + Expr::Box(v0) => Expr::Box(v0.clone()), + #[cfg(feature = "full")] + Expr::Break(v0) => Expr::Break(v0.clone()), + Expr::Call(v0) => Expr::Call(v0.clone()), + Expr::Cast(v0) => Expr::Cast(v0.clone()), + #[cfg(feature = "full")] + Expr::Closure(v0) => Expr::Closure(v0.clone()), + #[cfg(feature = "full")] + Expr::Continue(v0) => Expr::Continue(v0.clone()), + Expr::Field(v0) => Expr::Field(v0.clone()), + #[cfg(feature = "full")] + Expr::ForLoop(v0) => Expr::ForLoop(v0.clone()), + #[cfg(feature = "full")] + Expr::Group(v0) => Expr::Group(v0.clone()), + #[cfg(feature = "full")] + Expr::If(v0) => Expr::If(v0.clone()), + Expr::Index(v0) => Expr::Index(v0.clone()), + #[cfg(feature = "full")] + Expr::Let(v0) => Expr::Let(v0.clone()), + Expr::Lit(v0) => Expr::Lit(v0.clone()), + #[cfg(feature = "full")] + Expr::Loop(v0) => Expr::Loop(v0.clone()), + #[cfg(feature = "full")] + Expr::Macro(v0) => Expr::Macro(v0.clone()), + #[cfg(feature = "full")] + Expr::Match(v0) => Expr::Match(v0.clone()), + #[cfg(feature = "full")] + Expr::MethodCall(v0) => Expr::MethodCall(v0.clone()), + Expr::Paren(v0) => Expr::Paren(v0.clone()), + Expr::Path(v0) => Expr::Path(v0.clone()), + #[cfg(feature = "full")] + Expr::Range(v0) => Expr::Range(v0.clone()), + #[cfg(feature = "full")] + Expr::Reference(v0) => Expr::Reference(v0.clone()), + #[cfg(feature = "full")] + Expr::Repeat(v0) => Expr::Repeat(v0.clone()), + #[cfg(feature = "full")] + Expr::Return(v0) => Expr::Return(v0.clone()), + #[cfg(feature = "full")] + Expr::Struct(v0) => Expr::Struct(v0.clone()), + #[cfg(feature = "full")] + Expr::Try(v0) => Expr::Try(v0.clone()), + #[cfg(feature = "full")] + Expr::TryBlock(v0) => Expr::TryBlock(v0.clone()), + #[cfg(feature = "full")] + Expr::Tuple(v0) => Expr::Tuple(v0.clone()), + #[cfg(feature = "full")] + Expr::Type(v0) => Expr::Type(v0.clone()), + Expr::Unary(v0) => Expr::Unary(v0.clone()), + #[cfg(feature = "full")] + Expr::Unsafe(v0) => Expr::Unsafe(v0.clone()), + Expr::Verbatim(v0) => Expr::Verbatim(v0.clone()), + #[cfg(feature = "full")] + Expr::While(v0) => Expr::While(v0.clone()), + #[cfg(feature = "full")] + Expr::Yield(v0) => Expr::Yield(v0.clone()), + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprArray { + fn clone(&self) -> Self { + ExprArray { + attrs: self.attrs.clone(), + bracket_token: self.bracket_token.clone(), + elems: self.elems.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprAssign { + fn clone(&self) -> Self { + ExprAssign { + attrs: self.attrs.clone(), + left: self.left.clone(), + eq_token: self.eq_token.clone(), + right: self.right.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprAssignOp { + fn clone(&self) -> Self { + ExprAssignOp { + attrs: self.attrs.clone(), + left: self.left.clone(), + op: self.op.clone(), + right: self.right.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprAsync { + fn clone(&self) -> Self { + ExprAsync { + attrs: self.attrs.clone(), + async_token: self.async_token.clone(), + capture: self.capture.clone(), + block: self.block.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprAwait { + fn clone(&self) -> Self { + ExprAwait { + attrs: self.attrs.clone(), + base: self.base.clone(), + dot_token: self.dot_token.clone(), + await_token: self.await_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprBinary { + fn clone(&self) -> Self { + ExprBinary { + attrs: self.attrs.clone(), + left: self.left.clone(), + op: self.op.clone(), + right: self.right.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprBlock { + fn clone(&self) -> Self { + ExprBlock { + attrs: self.attrs.clone(), + label: self.label.clone(), + block: self.block.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprBox { + fn clone(&self) -> Self { + ExprBox { + attrs: self.attrs.clone(), + box_token: self.box_token.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprBreak { + fn clone(&self) -> Self { + ExprBreak { + attrs: self.attrs.clone(), + break_token: self.break_token.clone(), + label: self.label.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprCall { + fn clone(&self) -> Self { + ExprCall { + attrs: self.attrs.clone(), + func: self.func.clone(), + paren_token: self.paren_token.clone(), + args: self.args.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprCast { + fn clone(&self) -> Self { + ExprCast { + attrs: self.attrs.clone(), + expr: self.expr.clone(), + as_token: self.as_token.clone(), + ty: self.ty.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprClosure { + fn clone(&self) -> Self { + ExprClosure { + attrs: self.attrs.clone(), + asyncness: self.asyncness.clone(), + movability: self.movability.clone(), + capture: self.capture.clone(), + or1_token: self.or1_token.clone(), + inputs: self.inputs.clone(), + or2_token: self.or2_token.clone(), + output: self.output.clone(), + body: self.body.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprContinue { + fn clone(&self) -> Self { + ExprContinue { + attrs: self.attrs.clone(), + continue_token: self.continue_token.clone(), + label: self.label.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprField { + fn clone(&self) -> Self { + ExprField { + attrs: self.attrs.clone(), + base: self.base.clone(), + dot_token: self.dot_token.clone(), + member: self.member.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprForLoop { + fn clone(&self) -> Self { + ExprForLoop { + attrs: self.attrs.clone(), + label: self.label.clone(), + for_token: self.for_token.clone(), + pat: self.pat.clone(), + in_token: self.in_token.clone(), + expr: self.expr.clone(), + body: self.body.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprGroup { + fn clone(&self) -> Self { + ExprGroup { + attrs: self.attrs.clone(), + group_token: self.group_token.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprIf { + fn clone(&self) -> Self { + ExprIf { + attrs: self.attrs.clone(), + if_token: self.if_token.clone(), + cond: self.cond.clone(), + then_branch: self.then_branch.clone(), + else_branch: self.else_branch.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprIndex { + fn clone(&self) -> Self { + ExprIndex { + attrs: self.attrs.clone(), + expr: self.expr.clone(), + bracket_token: self.bracket_token.clone(), + index: self.index.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprLet { + fn clone(&self) -> Self { + ExprLet { + attrs: self.attrs.clone(), + let_token: self.let_token.clone(), + pat: self.pat.clone(), + eq_token: self.eq_token.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprLit { + fn clone(&self) -> Self { + ExprLit { + attrs: self.attrs.clone(), + lit: self.lit.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprLoop { + fn clone(&self) -> Self { + ExprLoop { + attrs: self.attrs.clone(), + label: self.label.clone(), + loop_token: self.loop_token.clone(), + body: self.body.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprMacro { + fn clone(&self) -> Self { + ExprMacro { + attrs: self.attrs.clone(), + mac: self.mac.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprMatch { + fn clone(&self) -> Self { + ExprMatch { + attrs: self.attrs.clone(), + match_token: self.match_token.clone(), + expr: self.expr.clone(), + brace_token: self.brace_token.clone(), + arms: self.arms.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprMethodCall { + fn clone(&self) -> Self { + ExprMethodCall { + attrs: self.attrs.clone(), + receiver: self.receiver.clone(), + dot_token: self.dot_token.clone(), + method: self.method.clone(), + turbofish: self.turbofish.clone(), + paren_token: self.paren_token.clone(), + args: self.args.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprParen { + fn clone(&self) -> Self { + ExprParen { + attrs: self.attrs.clone(), + paren_token: self.paren_token.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprPath { + fn clone(&self) -> Self { + ExprPath { + attrs: self.attrs.clone(), + qself: self.qself.clone(), + path: self.path.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprRange { + fn clone(&self) -> Self { + ExprRange { + attrs: self.attrs.clone(), + from: self.from.clone(), + limits: self.limits.clone(), + to: self.to.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprReference { + fn clone(&self) -> Self { + ExprReference { + attrs: self.attrs.clone(), + and_token: self.and_token.clone(), + raw: self.raw.clone(), + mutability: self.mutability.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprRepeat { + fn clone(&self) -> Self { + ExprRepeat { + attrs: self.attrs.clone(), + bracket_token: self.bracket_token.clone(), + expr: self.expr.clone(), + semi_token: self.semi_token.clone(), + len: self.len.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprReturn { + fn clone(&self) -> Self { + ExprReturn { + attrs: self.attrs.clone(), + return_token: self.return_token.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprStruct { + fn clone(&self) -> Self { + ExprStruct { + attrs: self.attrs.clone(), + path: self.path.clone(), + brace_token: self.brace_token.clone(), + fields: self.fields.clone(), + dot2_token: self.dot2_token.clone(), + rest: self.rest.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprTry { + fn clone(&self) -> Self { + ExprTry { + attrs: self.attrs.clone(), + expr: self.expr.clone(), + question_token: self.question_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprTryBlock { + fn clone(&self) -> Self { + ExprTryBlock { + attrs: self.attrs.clone(), + try_token: self.try_token.clone(), + block: self.block.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprTuple { + fn clone(&self) -> Self { + ExprTuple { + attrs: self.attrs.clone(), + paren_token: self.paren_token.clone(), + elems: self.elems.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprType { + fn clone(&self) -> Self { + ExprType { + attrs: self.attrs.clone(), + expr: self.expr.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ExprUnary { + fn clone(&self) -> Self { + ExprUnary { + attrs: self.attrs.clone(), + op: self.op.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprUnsafe { + fn clone(&self) -> Self { + ExprUnsafe { + attrs: self.attrs.clone(), + unsafe_token: self.unsafe_token.clone(), + block: self.block.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprWhile { + fn clone(&self) -> Self { + ExprWhile { + attrs: self.attrs.clone(), + label: self.label.clone(), + while_token: self.while_token.clone(), + cond: self.cond.clone(), + body: self.body.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ExprYield { + fn clone(&self) -> Self { + ExprYield { + attrs: self.attrs.clone(), + yield_token: self.yield_token.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Field { + fn clone(&self) -> Self { + Field { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for FieldPat { + fn clone(&self) -> Self { + FieldPat { + attrs: self.attrs.clone(), + member: self.member.clone(), + colon_token: self.colon_token.clone(), + pat: self.pat.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for FieldValue { + fn clone(&self) -> Self { + FieldValue { + attrs: self.attrs.clone(), + member: self.member.clone(), + colon_token: self.colon_token.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Fields { + fn clone(&self) -> Self { + match self { + Fields::Named(v0) => Fields::Named(v0.clone()), + Fields::Unnamed(v0) => Fields::Unnamed(v0.clone()), + Fields::Unit => Fields::Unit, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for FieldsNamed { + fn clone(&self) -> Self { + FieldsNamed { + brace_token: self.brace_token.clone(), + named: self.named.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for FieldsUnnamed { + fn clone(&self) -> Self { + FieldsUnnamed { + paren_token: self.paren_token.clone(), + unnamed: self.unnamed.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for File { + fn clone(&self) -> Self { + File { + shebang: self.shebang.clone(), + attrs: self.attrs.clone(), + items: self.items.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for FnArg { + fn clone(&self) -> Self { + match self { + FnArg::Receiver(v0) => FnArg::Receiver(v0.clone()), + FnArg::Typed(v0) => FnArg::Typed(v0.clone()), + } + } +} +#[cfg(feature = "full")] +impl Clone for ForeignItem { + fn clone(&self) -> Self { + match self { + ForeignItem::Fn(v0) => ForeignItem::Fn(v0.clone()), + ForeignItem::Static(v0) => ForeignItem::Static(v0.clone()), + ForeignItem::Type(v0) => ForeignItem::Type(v0.clone()), + ForeignItem::Macro(v0) => ForeignItem::Macro(v0.clone()), + ForeignItem::Verbatim(v0) => ForeignItem::Verbatim(v0.clone()), + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ForeignItemFn { + fn clone(&self) -> Self { + ForeignItemFn { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + sig: self.sig.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ForeignItemMacro { + fn clone(&self) -> Self { + ForeignItemMacro { + attrs: self.attrs.clone(), + mac: self.mac.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ForeignItemStatic { + fn clone(&self) -> Self { + ForeignItemStatic { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + static_token: self.static_token.clone(), + mutability: self.mutability.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ForeignItemType { + fn clone(&self) -> Self { + ForeignItemType { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + type_token: self.type_token.clone(), + ident: self.ident.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for GenericArgument { + fn clone(&self) -> Self { + match self { + GenericArgument::Lifetime(v0) => GenericArgument::Lifetime(v0.clone()), + GenericArgument::Type(v0) => GenericArgument::Type(v0.clone()), + GenericArgument::Binding(v0) => GenericArgument::Binding(v0.clone()), + GenericArgument::Constraint(v0) => GenericArgument::Constraint(v0.clone()), + GenericArgument::Const(v0) => GenericArgument::Const(v0.clone()), + } + } +} +#[cfg(feature = "full")] +impl Clone for GenericMethodArgument { + fn clone(&self) -> Self { + match self { + GenericMethodArgument::Type(v0) => GenericMethodArgument::Type(v0.clone()), + GenericMethodArgument::Const(v0) => GenericMethodArgument::Const(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for GenericParam { + fn clone(&self) -> Self { + match self { + GenericParam::Type(v0) => GenericParam::Type(v0.clone()), + GenericParam::Lifetime(v0) => GenericParam::Lifetime(v0.clone()), + GenericParam::Const(v0) => GenericParam::Const(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Generics { + fn clone(&self) -> Self { + Generics { + lt_token: self.lt_token.clone(), + params: self.params.clone(), + gt_token: self.gt_token.clone(), + where_clause: self.where_clause.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ImplItem { + fn clone(&self) -> Self { + match self { + ImplItem::Const(v0) => ImplItem::Const(v0.clone()), + ImplItem::Method(v0) => ImplItem::Method(v0.clone()), + ImplItem::Type(v0) => ImplItem::Type(v0.clone()), + ImplItem::Macro(v0) => ImplItem::Macro(v0.clone()), + ImplItem::Verbatim(v0) => ImplItem::Verbatim(v0.clone()), + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ImplItemConst { + fn clone(&self) -> Self { + ImplItemConst { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + defaultness: self.defaultness.clone(), + const_token: self.const_token.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + eq_token: self.eq_token.clone(), + expr: self.expr.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ImplItemMacro { + fn clone(&self) -> Self { + ImplItemMacro { + attrs: self.attrs.clone(), + mac: self.mac.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ImplItemMethod { + fn clone(&self) -> Self { + ImplItemMethod { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + defaultness: self.defaultness.clone(), + sig: self.sig.clone(), + block: self.block.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ImplItemType { + fn clone(&self) -> Self { + ImplItemType { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + defaultness: self.defaultness.clone(), + type_token: self.type_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + eq_token: self.eq_token.clone(), + ty: self.ty.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Index { + fn clone(&self) -> Self { + Index { + index: self.index.clone(), + span: self.span.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for Item { + fn clone(&self) -> Self { + match self { + Item::Const(v0) => Item::Const(v0.clone()), + Item::Enum(v0) => Item::Enum(v0.clone()), + Item::ExternCrate(v0) => Item::ExternCrate(v0.clone()), + Item::Fn(v0) => Item::Fn(v0.clone()), + Item::ForeignMod(v0) => Item::ForeignMod(v0.clone()), + Item::Impl(v0) => Item::Impl(v0.clone()), + Item::Macro(v0) => Item::Macro(v0.clone()), + Item::Macro2(v0) => Item::Macro2(v0.clone()), + Item::Mod(v0) => Item::Mod(v0.clone()), + Item::Static(v0) => Item::Static(v0.clone()), + Item::Struct(v0) => Item::Struct(v0.clone()), + Item::Trait(v0) => Item::Trait(v0.clone()), + Item::TraitAlias(v0) => Item::TraitAlias(v0.clone()), + Item::Type(v0) => Item::Type(v0.clone()), + Item::Union(v0) => Item::Union(v0.clone()), + Item::Use(v0) => Item::Use(v0.clone()), + Item::Verbatim(v0) => Item::Verbatim(v0.clone()), + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemConst { + fn clone(&self) -> Self { + ItemConst { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + const_token: self.const_token.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + eq_token: self.eq_token.clone(), + expr: self.expr.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemEnum { + fn clone(&self) -> Self { + ItemEnum { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + enum_token: self.enum_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + brace_token: self.brace_token.clone(), + variants: self.variants.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemExternCrate { + fn clone(&self) -> Self { + ItemExternCrate { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + extern_token: self.extern_token.clone(), + crate_token: self.crate_token.clone(), + ident: self.ident.clone(), + rename: self.rename.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemFn { + fn clone(&self) -> Self { + ItemFn { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + sig: self.sig.clone(), + block: self.block.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemForeignMod { + fn clone(&self) -> Self { + ItemForeignMod { + attrs: self.attrs.clone(), + abi: self.abi.clone(), + brace_token: self.brace_token.clone(), + items: self.items.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemImpl { + fn clone(&self) -> Self { + ItemImpl { + attrs: self.attrs.clone(), + defaultness: self.defaultness.clone(), + unsafety: self.unsafety.clone(), + impl_token: self.impl_token.clone(), + generics: self.generics.clone(), + trait_: self.trait_.clone(), + self_ty: self.self_ty.clone(), + brace_token: self.brace_token.clone(), + items: self.items.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemMacro { + fn clone(&self) -> Self { + ItemMacro { + attrs: self.attrs.clone(), + ident: self.ident.clone(), + mac: self.mac.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemMacro2 { + fn clone(&self) -> Self { + ItemMacro2 { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + macro_token: self.macro_token.clone(), + ident: self.ident.clone(), + rules: self.rules.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemMod { + fn clone(&self) -> Self { + ItemMod { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + mod_token: self.mod_token.clone(), + ident: self.ident.clone(), + content: self.content.clone(), + semi: self.semi.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemStatic { + fn clone(&self) -> Self { + ItemStatic { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + static_token: self.static_token.clone(), + mutability: self.mutability.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + eq_token: self.eq_token.clone(), + expr: self.expr.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemStruct { + fn clone(&self) -> Self { + ItemStruct { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + struct_token: self.struct_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + fields: self.fields.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemTrait { + fn clone(&self) -> Self { + ItemTrait { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + unsafety: self.unsafety.clone(), + auto_token: self.auto_token.clone(), + trait_token: self.trait_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + colon_token: self.colon_token.clone(), + supertraits: self.supertraits.clone(), + brace_token: self.brace_token.clone(), + items: self.items.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemTraitAlias { + fn clone(&self) -> Self { + ItemTraitAlias { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + trait_token: self.trait_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + eq_token: self.eq_token.clone(), + bounds: self.bounds.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemType { + fn clone(&self) -> Self { + ItemType { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + type_token: self.type_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + eq_token: self.eq_token.clone(), + ty: self.ty.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemUnion { + fn clone(&self) -> Self { + ItemUnion { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + union_token: self.union_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + fields: self.fields.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for ItemUse { + fn clone(&self) -> Self { + ItemUse { + attrs: self.attrs.clone(), + vis: self.vis.clone(), + use_token: self.use_token.clone(), + leading_colon: self.leading_colon.clone(), + tree: self.tree.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for Label { + fn clone(&self) -> Self { + Label { + name: self.name.clone(), + colon_token: self.colon_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for LifetimeDef { + fn clone(&self) -> Self { + LifetimeDef { + attrs: self.attrs.clone(), + lifetime: self.lifetime.clone(), + colon_token: self.colon_token.clone(), + bounds: self.bounds.clone(), + } + } +} +impl Clone for Lit { + fn clone(&self) -> Self { + match self { + Lit::Str(v0) => Lit::Str(v0.clone()), + Lit::ByteStr(v0) => Lit::ByteStr(v0.clone()), + Lit::Byte(v0) => Lit::Byte(v0.clone()), + Lit::Char(v0) => Lit::Char(v0.clone()), + Lit::Int(v0) => Lit::Int(v0.clone()), + Lit::Float(v0) => Lit::Float(v0.clone()), + Lit::Bool(v0) => Lit::Bool(v0.clone()), + Lit::Verbatim(v0) => Lit::Verbatim(v0.clone()), + } + } +} +impl Clone for LitBool { + fn clone(&self) -> Self { + LitBool { + value: self.value.clone(), + span: self.span.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for Local { + fn clone(&self) -> Self { + Local { + attrs: self.attrs.clone(), + let_token: self.let_token.clone(), + pat: self.pat.clone(), + init: self.init.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Macro { + fn clone(&self) -> Self { + Macro { + path: self.path.clone(), + bang_token: self.bang_token.clone(), + delimiter: self.delimiter.clone(), + tokens: self.tokens.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for MacroDelimiter { + fn clone(&self) -> Self { + match self { + MacroDelimiter::Paren(v0) => MacroDelimiter::Paren(v0.clone()), + MacroDelimiter::Brace(v0) => MacroDelimiter::Brace(v0.clone()), + MacroDelimiter::Bracket(v0) => MacroDelimiter::Bracket(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Member { + fn clone(&self) -> Self { + match self { + Member::Named(v0) => Member::Named(v0.clone()), + Member::Unnamed(v0) => Member::Unnamed(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Meta { + fn clone(&self) -> Self { + match self { + Meta::Path(v0) => Meta::Path(v0.clone()), + Meta::List(v0) => Meta::List(v0.clone()), + Meta::NameValue(v0) => Meta::NameValue(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for MetaList { + fn clone(&self) -> Self { + MetaList { + path: self.path.clone(), + paren_token: self.paren_token.clone(), + nested: self.nested.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for MetaNameValue { + fn clone(&self) -> Self { + MetaNameValue { + path: self.path.clone(), + eq_token: self.eq_token.clone(), + lit: self.lit.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for MethodTurbofish { + fn clone(&self) -> Self { + MethodTurbofish { + colon2_token: self.colon2_token.clone(), + lt_token: self.lt_token.clone(), + args: self.args.clone(), + gt_token: self.gt_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for NestedMeta { + fn clone(&self) -> Self { + match self { + NestedMeta::Meta(v0) => NestedMeta::Meta(v0.clone()), + NestedMeta::Lit(v0) => NestedMeta::Lit(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ParenthesizedGenericArguments { + fn clone(&self) -> Self { + ParenthesizedGenericArguments { + paren_token: self.paren_token.clone(), + inputs: self.inputs.clone(), + output: self.output.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for Pat { + fn clone(&self) -> Self { + match self { + Pat::Box(v0) => Pat::Box(v0.clone()), + Pat::Ident(v0) => Pat::Ident(v0.clone()), + Pat::Lit(v0) => Pat::Lit(v0.clone()), + Pat::Macro(v0) => Pat::Macro(v0.clone()), + Pat::Or(v0) => Pat::Or(v0.clone()), + Pat::Path(v0) => Pat::Path(v0.clone()), + Pat::Range(v0) => Pat::Range(v0.clone()), + Pat::Reference(v0) => Pat::Reference(v0.clone()), + Pat::Rest(v0) => Pat::Rest(v0.clone()), + Pat::Slice(v0) => Pat::Slice(v0.clone()), + Pat::Struct(v0) => Pat::Struct(v0.clone()), + Pat::Tuple(v0) => Pat::Tuple(v0.clone()), + Pat::TupleStruct(v0) => Pat::TupleStruct(v0.clone()), + Pat::Type(v0) => Pat::Type(v0.clone()), + Pat::Verbatim(v0) => Pat::Verbatim(v0.clone()), + Pat::Wild(v0) => Pat::Wild(v0.clone()), + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatBox { + fn clone(&self) -> Self { + PatBox { + attrs: self.attrs.clone(), + box_token: self.box_token.clone(), + pat: self.pat.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatIdent { + fn clone(&self) -> Self { + PatIdent { + attrs: self.attrs.clone(), + by_ref: self.by_ref.clone(), + mutability: self.mutability.clone(), + ident: self.ident.clone(), + subpat: self.subpat.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatLit { + fn clone(&self) -> Self { + PatLit { + attrs: self.attrs.clone(), + expr: self.expr.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatMacro { + fn clone(&self) -> Self { + PatMacro { + attrs: self.attrs.clone(), + mac: self.mac.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatOr { + fn clone(&self) -> Self { + PatOr { + attrs: self.attrs.clone(), + leading_vert: self.leading_vert.clone(), + cases: self.cases.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatPath { + fn clone(&self) -> Self { + PatPath { + attrs: self.attrs.clone(), + qself: self.qself.clone(), + path: self.path.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatRange { + fn clone(&self) -> Self { + PatRange { + attrs: self.attrs.clone(), + lo: self.lo.clone(), + limits: self.limits.clone(), + hi: self.hi.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatReference { + fn clone(&self) -> Self { + PatReference { + attrs: self.attrs.clone(), + and_token: self.and_token.clone(), + mutability: self.mutability.clone(), + pat: self.pat.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatRest { + fn clone(&self) -> Self { + PatRest { + attrs: self.attrs.clone(), + dot2_token: self.dot2_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatSlice { + fn clone(&self) -> Self { + PatSlice { + attrs: self.attrs.clone(), + bracket_token: self.bracket_token.clone(), + elems: self.elems.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatStruct { + fn clone(&self) -> Self { + PatStruct { + attrs: self.attrs.clone(), + path: self.path.clone(), + brace_token: self.brace_token.clone(), + fields: self.fields.clone(), + dot2_token: self.dot2_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatTuple { + fn clone(&self) -> Self { + PatTuple { + attrs: self.attrs.clone(), + paren_token: self.paren_token.clone(), + elems: self.elems.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatTupleStruct { + fn clone(&self) -> Self { + PatTupleStruct { + attrs: self.attrs.clone(), + path: self.path.clone(), + pat: self.pat.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatType { + fn clone(&self) -> Self { + PatType { + attrs: self.attrs.clone(), + pat: self.pat.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for PatWild { + fn clone(&self) -> Self { + PatWild { + attrs: self.attrs.clone(), + underscore_token: self.underscore_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Path { + fn clone(&self) -> Self { + Path { + leading_colon: self.leading_colon.clone(), + segments: self.segments.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for PathArguments { + fn clone(&self) -> Self { + match self { + PathArguments::None => PathArguments::None, + PathArguments::AngleBracketed(v0) => PathArguments::AngleBracketed(v0.clone()), + PathArguments::Parenthesized(v0) => PathArguments::Parenthesized(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for PathSegment { + fn clone(&self) -> Self { + PathSegment { + ident: self.ident.clone(), + arguments: self.arguments.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for PredicateEq { + fn clone(&self) -> Self { + PredicateEq { + lhs_ty: self.lhs_ty.clone(), + eq_token: self.eq_token.clone(), + rhs_ty: self.rhs_ty.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for PredicateLifetime { + fn clone(&self) -> Self { + PredicateLifetime { + lifetime: self.lifetime.clone(), + colon_token: self.colon_token.clone(), + bounds: self.bounds.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for PredicateType { + fn clone(&self) -> Self { + PredicateType { + lifetimes: self.lifetimes.clone(), + bounded_ty: self.bounded_ty.clone(), + colon_token: self.colon_token.clone(), + bounds: self.bounds.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for QSelf { + fn clone(&self) -> Self { + QSelf { + lt_token: self.lt_token.clone(), + ty: self.ty.clone(), + position: self.position.clone(), + as_token: self.as_token.clone(), + gt_token: self.gt_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Copy for RangeLimits {} +#[cfg(feature = "full")] +impl Clone for RangeLimits { + fn clone(&self) -> Self { + *self + } +} +#[cfg(feature = "full")] +impl Clone for Receiver { + fn clone(&self) -> Self { + Receiver { + attrs: self.attrs.clone(), + reference: self.reference.clone(), + mutability: self.mutability.clone(), + self_token: self.self_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for ReturnType { + fn clone(&self) -> Self { + match self { + ReturnType::Default => ReturnType::Default, + ReturnType::Type(v0, v1) => ReturnType::Type(v0.clone(), v1.clone()), + } + } +} +#[cfg(feature = "full")] +impl Clone for Signature { + fn clone(&self) -> Self { + Signature { + constness: self.constness.clone(), + asyncness: self.asyncness.clone(), + unsafety: self.unsafety.clone(), + abi: self.abi.clone(), + fn_token: self.fn_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + paren_token: self.paren_token.clone(), + inputs: self.inputs.clone(), + variadic: self.variadic.clone(), + output: self.output.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for Stmt { + fn clone(&self) -> Self { + match self { + Stmt::Local(v0) => Stmt::Local(v0.clone()), + Stmt::Item(v0) => Stmt::Item(v0.clone()), + Stmt::Expr(v0) => Stmt::Expr(v0.clone()), + Stmt::Semi(v0, v1) => Stmt::Semi(v0.clone(), v1.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TraitBound { + fn clone(&self) -> Self { + TraitBound { + paren_token: self.paren_token.clone(), + modifier: self.modifier.clone(), + lifetimes: self.lifetimes.clone(), + path: self.path.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Copy for TraitBoundModifier {} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TraitBoundModifier { + fn clone(&self) -> Self { + *self + } +} +#[cfg(feature = "full")] +impl Clone for TraitItem { + fn clone(&self) -> Self { + match self { + TraitItem::Const(v0) => TraitItem::Const(v0.clone()), + TraitItem::Method(v0) => TraitItem::Method(v0.clone()), + TraitItem::Type(v0) => TraitItem::Type(v0.clone()), + TraitItem::Macro(v0) => TraitItem::Macro(v0.clone()), + TraitItem::Verbatim(v0) => TraitItem::Verbatim(v0.clone()), + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Clone for TraitItemConst { + fn clone(&self) -> Self { + TraitItemConst { + attrs: self.attrs.clone(), + const_token: self.const_token.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + ty: self.ty.clone(), + default: self.default.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for TraitItemMacro { + fn clone(&self) -> Self { + TraitItemMacro { + attrs: self.attrs.clone(), + mac: self.mac.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for TraitItemMethod { + fn clone(&self) -> Self { + TraitItemMethod { + attrs: self.attrs.clone(), + sig: self.sig.clone(), + default: self.default.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for TraitItemType { + fn clone(&self) -> Self { + TraitItemType { + attrs: self.attrs.clone(), + type_token: self.type_token.clone(), + ident: self.ident.clone(), + generics: self.generics.clone(), + colon_token: self.colon_token.clone(), + bounds: self.bounds.clone(), + default: self.default.clone(), + semi_token: self.semi_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Type { + fn clone(&self) -> Self { + match self { + Type::Array(v0) => Type::Array(v0.clone()), + Type::BareFn(v0) => Type::BareFn(v0.clone()), + Type::Group(v0) => Type::Group(v0.clone()), + Type::ImplTrait(v0) => Type::ImplTrait(v0.clone()), + Type::Infer(v0) => Type::Infer(v0.clone()), + Type::Macro(v0) => Type::Macro(v0.clone()), + Type::Never(v0) => Type::Never(v0.clone()), + Type::Paren(v0) => Type::Paren(v0.clone()), + Type::Path(v0) => Type::Path(v0.clone()), + Type::Ptr(v0) => Type::Ptr(v0.clone()), + Type::Reference(v0) => Type::Reference(v0.clone()), + Type::Slice(v0) => Type::Slice(v0.clone()), + Type::TraitObject(v0) => Type::TraitObject(v0.clone()), + Type::Tuple(v0) => Type::Tuple(v0.clone()), + Type::Verbatim(v0) => Type::Verbatim(v0.clone()), + _ => unreachable!(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeArray { + fn clone(&self) -> Self { + TypeArray { + bracket_token: self.bracket_token.clone(), + elem: self.elem.clone(), + semi_token: self.semi_token.clone(), + len: self.len.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeBareFn { + fn clone(&self) -> Self { + TypeBareFn { + lifetimes: self.lifetimes.clone(), + unsafety: self.unsafety.clone(), + abi: self.abi.clone(), + fn_token: self.fn_token.clone(), + paren_token: self.paren_token.clone(), + inputs: self.inputs.clone(), + variadic: self.variadic.clone(), + output: self.output.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeGroup { + fn clone(&self) -> Self { + TypeGroup { + group_token: self.group_token.clone(), + elem: self.elem.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeImplTrait { + fn clone(&self) -> Self { + TypeImplTrait { + impl_token: self.impl_token.clone(), + bounds: self.bounds.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeInfer { + fn clone(&self) -> Self { + TypeInfer { + underscore_token: self.underscore_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeMacro { + fn clone(&self) -> Self { + TypeMacro { + mac: self.mac.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeNever { + fn clone(&self) -> Self { + TypeNever { + bang_token: self.bang_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeParam { + fn clone(&self) -> Self { + TypeParam { + attrs: self.attrs.clone(), + ident: self.ident.clone(), + colon_token: self.colon_token.clone(), + bounds: self.bounds.clone(), + eq_token: self.eq_token.clone(), + default: self.default.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeParamBound { + fn clone(&self) -> Self { + match self { + TypeParamBound::Trait(v0) => TypeParamBound::Trait(v0.clone()), + TypeParamBound::Lifetime(v0) => TypeParamBound::Lifetime(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeParen { + fn clone(&self) -> Self { + TypeParen { + paren_token: self.paren_token.clone(), + elem: self.elem.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypePath { + fn clone(&self) -> Self { + TypePath { + qself: self.qself.clone(), + path: self.path.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypePtr { + fn clone(&self) -> Self { + TypePtr { + star_token: self.star_token.clone(), + const_token: self.const_token.clone(), + mutability: self.mutability.clone(), + elem: self.elem.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeReference { + fn clone(&self) -> Self { + TypeReference { + and_token: self.and_token.clone(), + lifetime: self.lifetime.clone(), + mutability: self.mutability.clone(), + elem: self.elem.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeSlice { + fn clone(&self) -> Self { + TypeSlice { + bracket_token: self.bracket_token.clone(), + elem: self.elem.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeTraitObject { + fn clone(&self) -> Self { + TypeTraitObject { + dyn_token: self.dyn_token.clone(), + bounds: self.bounds.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for TypeTuple { + fn clone(&self) -> Self { + TypeTuple { + paren_token: self.paren_token.clone(), + elems: self.elems.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Copy for UnOp {} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for UnOp { + fn clone(&self) -> Self { + *self + } +} +#[cfg(feature = "full")] +impl Clone for UseGlob { + fn clone(&self) -> Self { + UseGlob { + star_token: self.star_token.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for UseGroup { + fn clone(&self) -> Self { + UseGroup { + brace_token: self.brace_token.clone(), + items: self.items.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for UseName { + fn clone(&self) -> Self { + UseName { + ident: self.ident.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for UsePath { + fn clone(&self) -> Self { + UsePath { + ident: self.ident.clone(), + colon2_token: self.colon2_token.clone(), + tree: self.tree.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for UseRename { + fn clone(&self) -> Self { + UseRename { + ident: self.ident.clone(), + as_token: self.as_token.clone(), + rename: self.rename.clone(), + } + } +} +#[cfg(feature = "full")] +impl Clone for UseTree { + fn clone(&self) -> Self { + match self { + UseTree::Path(v0) => UseTree::Path(v0.clone()), + UseTree::Name(v0) => UseTree::Name(v0.clone()), + UseTree::Rename(v0) => UseTree::Rename(v0.clone()), + UseTree::Glob(v0) => UseTree::Glob(v0.clone()), + UseTree::Group(v0) => UseTree::Group(v0.clone()), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Variadic { + fn clone(&self) -> Self { + Variadic { + attrs: self.attrs.clone(), + dots: self.dots.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Variant { + fn clone(&self) -> Self { + Variant { + attrs: self.attrs.clone(), + ident: self.ident.clone(), + fields: self.fields.clone(), + discriminant: self.discriminant.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for VisCrate { + fn clone(&self) -> Self { + VisCrate { + crate_token: self.crate_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for VisPublic { + fn clone(&self) -> Self { + VisPublic { + pub_token: self.pub_token.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for VisRestricted { + fn clone(&self) -> Self { + VisRestricted { + pub_token: self.pub_token.clone(), + paren_token: self.paren_token.clone(), + in_token: self.in_token.clone(), + path: self.path.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for Visibility { + fn clone(&self) -> Self { + match self { + Visibility::Public(v0) => Visibility::Public(v0.clone()), + Visibility::Crate(v0) => Visibility::Crate(v0.clone()), + Visibility::Restricted(v0) => Visibility::Restricted(v0.clone()), + Visibility::Inherited => Visibility::Inherited, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for WhereClause { + fn clone(&self) -> Self { + WhereClause { + where_token: self.where_token.clone(), + predicates: self.predicates.clone(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Clone for WherePredicate { + fn clone(&self) -> Self { + match self { + WherePredicate::Type(v0) => WherePredicate::Type(v0.clone()), + WherePredicate::Lifetime(v0) => WherePredicate::Lifetime(v0.clone()), + WherePredicate::Eq(v0) => WherePredicate::Eq(v0.clone()), + } + } +} diff --git a/vendor/syn/src/gen/debug.rs b/vendor/syn/src/gen/debug.rs new file mode 100644 index 0000000000..72baab05f4 --- /dev/null +++ b/vendor/syn/src/gen/debug.rs @@ -0,0 +1,2857 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +use crate::*; +use std::fmt::{self, Debug}; +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Abi { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Abi"); + formatter.field("extern_token", &self.extern_token); + formatter.field("name", &self.name); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for AngleBracketedGenericArguments { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("AngleBracketedGenericArguments"); + formatter.field("colon2_token", &self.colon2_token); + formatter.field("lt_token", &self.lt_token); + formatter.field("args", &self.args); + formatter.field("gt_token", &self.gt_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for Arm { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Arm"); + formatter.field("attrs", &self.attrs); + formatter.field("pat", &self.pat); + formatter.field("guard", &self.guard); + formatter.field("fat_arrow_token", &self.fat_arrow_token); + formatter.field("body", &self.body); + formatter.field("comma", &self.comma); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for AttrStyle { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + AttrStyle::Outer => formatter.write_str("Outer"), + AttrStyle::Inner(v0) => { + let mut formatter = formatter.debug_tuple("Inner"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Attribute { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Attribute"); + formatter.field("pound_token", &self.pound_token); + formatter.field("style", &self.style); + formatter.field("bracket_token", &self.bracket_token); + formatter.field("path", &self.path); + formatter.field("tokens", &self.tokens); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for BareFnArg { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("BareFnArg"); + formatter.field("attrs", &self.attrs); + formatter.field("name", &self.name); + formatter.field("ty", &self.ty); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for BinOp { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + BinOp::Add(v0) => { + let mut formatter = formatter.debug_tuple("Add"); + formatter.field(v0); + formatter.finish() + } + BinOp::Sub(v0) => { + let mut formatter = formatter.debug_tuple("Sub"); + formatter.field(v0); + formatter.finish() + } + BinOp::Mul(v0) => { + let mut formatter = formatter.debug_tuple("Mul"); + formatter.field(v0); + formatter.finish() + } + BinOp::Div(v0) => { + let mut formatter = formatter.debug_tuple("Div"); + formatter.field(v0); + formatter.finish() + } + BinOp::Rem(v0) => { + let mut formatter = formatter.debug_tuple("Rem"); + formatter.field(v0); + formatter.finish() + } + BinOp::And(v0) => { + let mut formatter = formatter.debug_tuple("And"); + formatter.field(v0); + formatter.finish() + } + BinOp::Or(v0) => { + let mut formatter = formatter.debug_tuple("Or"); + formatter.field(v0); + formatter.finish() + } + BinOp::BitXor(v0) => { + let mut formatter = formatter.debug_tuple("BitXor"); + formatter.field(v0); + formatter.finish() + } + BinOp::BitAnd(v0) => { + let mut formatter = formatter.debug_tuple("BitAnd"); + formatter.field(v0); + formatter.finish() + } + BinOp::BitOr(v0) => { + let mut formatter = formatter.debug_tuple("BitOr"); + formatter.field(v0); + formatter.finish() + } + BinOp::Shl(v0) => { + let mut formatter = formatter.debug_tuple("Shl"); + formatter.field(v0); + formatter.finish() + } + BinOp::Shr(v0) => { + let mut formatter = formatter.debug_tuple("Shr"); + formatter.field(v0); + formatter.finish() + } + BinOp::Eq(v0) => { + let mut formatter = formatter.debug_tuple("Eq"); + formatter.field(v0); + formatter.finish() + } + BinOp::Lt(v0) => { + let mut formatter = formatter.debug_tuple("Lt"); + formatter.field(v0); + formatter.finish() + } + BinOp::Le(v0) => { + let mut formatter = formatter.debug_tuple("Le"); + formatter.field(v0); + formatter.finish() + } + BinOp::Ne(v0) => { + let mut formatter = formatter.debug_tuple("Ne"); + formatter.field(v0); + formatter.finish() + } + BinOp::Ge(v0) => { + let mut formatter = formatter.debug_tuple("Ge"); + formatter.field(v0); + formatter.finish() + } + BinOp::Gt(v0) => { + let mut formatter = formatter.debug_tuple("Gt"); + formatter.field(v0); + formatter.finish() + } + BinOp::AddEq(v0) => { + let mut formatter = formatter.debug_tuple("AddEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::SubEq(v0) => { + let mut formatter = formatter.debug_tuple("SubEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::MulEq(v0) => { + let mut formatter = formatter.debug_tuple("MulEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::DivEq(v0) => { + let mut formatter = formatter.debug_tuple("DivEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::RemEq(v0) => { + let mut formatter = formatter.debug_tuple("RemEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::BitXorEq(v0) => { + let mut formatter = formatter.debug_tuple("BitXorEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::BitAndEq(v0) => { + let mut formatter = formatter.debug_tuple("BitAndEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::BitOrEq(v0) => { + let mut formatter = formatter.debug_tuple("BitOrEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::ShlEq(v0) => { + let mut formatter = formatter.debug_tuple("ShlEq"); + formatter.field(v0); + formatter.finish() + } + BinOp::ShrEq(v0) => { + let mut formatter = formatter.debug_tuple("ShrEq"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Binding { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Binding"); + formatter.field("ident", &self.ident); + formatter.field("eq_token", &self.eq_token); + formatter.field("ty", &self.ty); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for Block { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Block"); + formatter.field("brace_token", &self.brace_token); + formatter.field("stmts", &self.stmts); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for BoundLifetimes { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("BoundLifetimes"); + formatter.field("for_token", &self.for_token); + formatter.field("lt_token", &self.lt_token); + formatter.field("lifetimes", &self.lifetimes); + formatter.field("gt_token", &self.gt_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ConstParam { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ConstParam"); + formatter.field("attrs", &self.attrs); + formatter.field("const_token", &self.const_token); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.field("eq_token", &self.eq_token); + formatter.field("default", &self.default); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Constraint { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Constraint"); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("bounds", &self.bounds); + formatter.finish() + } +} +#[cfg(feature = "derive")] +impl Debug for Data { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Data::Struct(v0) => { + let mut formatter = formatter.debug_tuple("Struct"); + formatter.field(v0); + formatter.finish() + } + Data::Enum(v0) => { + let mut formatter = formatter.debug_tuple("Enum"); + formatter.field(v0); + formatter.finish() + } + Data::Union(v0) => { + let mut formatter = formatter.debug_tuple("Union"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(feature = "derive")] +impl Debug for DataEnum { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("DataEnum"); + formatter.field("enum_token", &self.enum_token); + formatter.field("brace_token", &self.brace_token); + formatter.field("variants", &self.variants); + formatter.finish() + } +} +#[cfg(feature = "derive")] +impl Debug for DataStruct { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("DataStruct"); + formatter.field("struct_token", &self.struct_token); + formatter.field("fields", &self.fields); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "derive")] +impl Debug for DataUnion { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("DataUnion"); + formatter.field("union_token", &self.union_token); + formatter.field("fields", &self.fields); + formatter.finish() + } +} +#[cfg(feature = "derive")] +impl Debug for DeriveInput { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("DeriveInput"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("data", &self.data); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Expr { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + #[cfg(feature = "full")] + Expr::Array(v0) => { + let mut formatter = formatter.debug_tuple("Array"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Assign(v0) => { + let mut formatter = formatter.debug_tuple("Assign"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::AssignOp(v0) => { + let mut formatter = formatter.debug_tuple("AssignOp"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Async(v0) => { + let mut formatter = formatter.debug_tuple("Async"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Await(v0) => { + let mut formatter = formatter.debug_tuple("Await"); + formatter.field(v0); + formatter.finish() + } + Expr::Binary(v0) => { + let mut formatter = formatter.debug_tuple("Binary"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Block(v0) => { + let mut formatter = formatter.debug_tuple("Block"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Box(v0) => { + let mut formatter = formatter.debug_tuple("Box"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Break(v0) => { + let mut formatter = formatter.debug_tuple("Break"); + formatter.field(v0); + formatter.finish() + } + Expr::Call(v0) => { + let mut formatter = formatter.debug_tuple("Call"); + formatter.field(v0); + formatter.finish() + } + Expr::Cast(v0) => { + let mut formatter = formatter.debug_tuple("Cast"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Closure(v0) => { + let mut formatter = formatter.debug_tuple("Closure"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Continue(v0) => { + let mut formatter = formatter.debug_tuple("Continue"); + formatter.field(v0); + formatter.finish() + } + Expr::Field(v0) => { + let mut formatter = formatter.debug_tuple("Field"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::ForLoop(v0) => { + let mut formatter = formatter.debug_tuple("ForLoop"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Group(v0) => { + let mut formatter = formatter.debug_tuple("Group"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::If(v0) => { + let mut formatter = formatter.debug_tuple("If"); + formatter.field(v0); + formatter.finish() + } + Expr::Index(v0) => { + let mut formatter = formatter.debug_tuple("Index"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Let(v0) => { + let mut formatter = formatter.debug_tuple("Let"); + formatter.field(v0); + formatter.finish() + } + Expr::Lit(v0) => { + let mut formatter = formatter.debug_tuple("Lit"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Loop(v0) => { + let mut formatter = formatter.debug_tuple("Loop"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Macro(v0) => { + let mut formatter = formatter.debug_tuple("Macro"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Match(v0) => { + let mut formatter = formatter.debug_tuple("Match"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::MethodCall(v0) => { + let mut formatter = formatter.debug_tuple("MethodCall"); + formatter.field(v0); + formatter.finish() + } + Expr::Paren(v0) => { + let mut formatter = formatter.debug_tuple("Paren"); + formatter.field(v0); + formatter.finish() + } + Expr::Path(v0) => { + let mut formatter = formatter.debug_tuple("Path"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Range(v0) => { + let mut formatter = formatter.debug_tuple("Range"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Reference(v0) => { + let mut formatter = formatter.debug_tuple("Reference"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Repeat(v0) => { + let mut formatter = formatter.debug_tuple("Repeat"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Return(v0) => { + let mut formatter = formatter.debug_tuple("Return"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Struct(v0) => { + let mut formatter = formatter.debug_tuple("Struct"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Try(v0) => { + let mut formatter = formatter.debug_tuple("Try"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::TryBlock(v0) => { + let mut formatter = formatter.debug_tuple("TryBlock"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Tuple(v0) => { + let mut formatter = formatter.debug_tuple("Tuple"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + Expr::Unary(v0) => { + let mut formatter = formatter.debug_tuple("Unary"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Unsafe(v0) => { + let mut formatter = formatter.debug_tuple("Unsafe"); + formatter.field(v0); + formatter.finish() + } + Expr::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::While(v0) => { + let mut formatter = formatter.debug_tuple("While"); + formatter.field(v0); + formatter.finish() + } + #[cfg(feature = "full")] + Expr::Yield(v0) => { + let mut formatter = formatter.debug_tuple("Yield"); + formatter.field(v0); + formatter.finish() + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Debug for ExprArray { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprArray"); + formatter.field("attrs", &self.attrs); + formatter.field("bracket_token", &self.bracket_token); + formatter.field("elems", &self.elems); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprAssign { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprAssign"); + formatter.field("attrs", &self.attrs); + formatter.field("left", &self.left); + formatter.field("eq_token", &self.eq_token); + formatter.field("right", &self.right); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprAssignOp { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprAssignOp"); + formatter.field("attrs", &self.attrs); + formatter.field("left", &self.left); + formatter.field("op", &self.op); + formatter.field("right", &self.right); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprAsync { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprAsync"); + formatter.field("attrs", &self.attrs); + formatter.field("async_token", &self.async_token); + formatter.field("capture", &self.capture); + formatter.field("block", &self.block); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprAwait { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprAwait"); + formatter.field("attrs", &self.attrs); + formatter.field("base", &self.base); + formatter.field("dot_token", &self.dot_token); + formatter.field("await_token", &self.await_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprBinary { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprBinary"); + formatter.field("attrs", &self.attrs); + formatter.field("left", &self.left); + formatter.field("op", &self.op); + formatter.field("right", &self.right); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprBlock { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprBlock"); + formatter.field("attrs", &self.attrs); + formatter.field("label", &self.label); + formatter.field("block", &self.block); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprBox { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprBox"); + formatter.field("attrs", &self.attrs); + formatter.field("box_token", &self.box_token); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprBreak { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprBreak"); + formatter.field("attrs", &self.attrs); + formatter.field("break_token", &self.break_token); + formatter.field("label", &self.label); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprCall { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprCall"); + formatter.field("attrs", &self.attrs); + formatter.field("func", &self.func); + formatter.field("paren_token", &self.paren_token); + formatter.field("args", &self.args); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprCast { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprCast"); + formatter.field("attrs", &self.attrs); + formatter.field("expr", &self.expr); + formatter.field("as_token", &self.as_token); + formatter.field("ty", &self.ty); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprClosure { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprClosure"); + formatter.field("attrs", &self.attrs); + formatter.field("asyncness", &self.asyncness); + formatter.field("movability", &self.movability); + formatter.field("capture", &self.capture); + formatter.field("or1_token", &self.or1_token); + formatter.field("inputs", &self.inputs); + formatter.field("or2_token", &self.or2_token); + formatter.field("output", &self.output); + formatter.field("body", &self.body); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprContinue { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprContinue"); + formatter.field("attrs", &self.attrs); + formatter.field("continue_token", &self.continue_token); + formatter.field("label", &self.label); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprField { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprField"); + formatter.field("attrs", &self.attrs); + formatter.field("base", &self.base); + formatter.field("dot_token", &self.dot_token); + formatter.field("member", &self.member); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprForLoop { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprForLoop"); + formatter.field("attrs", &self.attrs); + formatter.field("label", &self.label); + formatter.field("for_token", &self.for_token); + formatter.field("pat", &self.pat); + formatter.field("in_token", &self.in_token); + formatter.field("expr", &self.expr); + formatter.field("body", &self.body); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprGroup { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprGroup"); + formatter.field("attrs", &self.attrs); + formatter.field("group_token", &self.group_token); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprIf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprIf"); + formatter.field("attrs", &self.attrs); + formatter.field("if_token", &self.if_token); + formatter.field("cond", &self.cond); + formatter.field("then_branch", &self.then_branch); + formatter.field("else_branch", &self.else_branch); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprIndex { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprIndex"); + formatter.field("attrs", &self.attrs); + formatter.field("expr", &self.expr); + formatter.field("bracket_token", &self.bracket_token); + formatter.field("index", &self.index); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprLet { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprLet"); + formatter.field("attrs", &self.attrs); + formatter.field("let_token", &self.let_token); + formatter.field("pat", &self.pat); + formatter.field("eq_token", &self.eq_token); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprLit { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprLit"); + formatter.field("attrs", &self.attrs); + formatter.field("lit", &self.lit); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprLoop { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprLoop"); + formatter.field("attrs", &self.attrs); + formatter.field("label", &self.label); + formatter.field("loop_token", &self.loop_token); + formatter.field("body", &self.body); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprMacro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprMacro"); + formatter.field("attrs", &self.attrs); + formatter.field("mac", &self.mac); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprMatch { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprMatch"); + formatter.field("attrs", &self.attrs); + formatter.field("match_token", &self.match_token); + formatter.field("expr", &self.expr); + formatter.field("brace_token", &self.brace_token); + formatter.field("arms", &self.arms); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprMethodCall { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprMethodCall"); + formatter.field("attrs", &self.attrs); + formatter.field("receiver", &self.receiver); + formatter.field("dot_token", &self.dot_token); + formatter.field("method", &self.method); + formatter.field("turbofish", &self.turbofish); + formatter.field("paren_token", &self.paren_token); + formatter.field("args", &self.args); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprParen { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprParen"); + formatter.field("attrs", &self.attrs); + formatter.field("paren_token", &self.paren_token); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprPath { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprPath"); + formatter.field("attrs", &self.attrs); + formatter.field("qself", &self.qself); + formatter.field("path", &self.path); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprRange { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprRange"); + formatter.field("attrs", &self.attrs); + formatter.field("from", &self.from); + formatter.field("limits", &self.limits); + formatter.field("to", &self.to); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprReference { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprReference"); + formatter.field("attrs", &self.attrs); + formatter.field("and_token", &self.and_token); + formatter.field("raw", &self.raw); + formatter.field("mutability", &self.mutability); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprRepeat { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprRepeat"); + formatter.field("attrs", &self.attrs); + formatter.field("bracket_token", &self.bracket_token); + formatter.field("expr", &self.expr); + formatter.field("semi_token", &self.semi_token); + formatter.field("len", &self.len); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprReturn { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprReturn"); + formatter.field("attrs", &self.attrs); + formatter.field("return_token", &self.return_token); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprStruct { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprStruct"); + formatter.field("attrs", &self.attrs); + formatter.field("path", &self.path); + formatter.field("brace_token", &self.brace_token); + formatter.field("fields", &self.fields); + formatter.field("dot2_token", &self.dot2_token); + formatter.field("rest", &self.rest); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprTry { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprTry"); + formatter.field("attrs", &self.attrs); + formatter.field("expr", &self.expr); + formatter.field("question_token", &self.question_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprTryBlock { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprTryBlock"); + formatter.field("attrs", &self.attrs); + formatter.field("try_token", &self.try_token); + formatter.field("block", &self.block); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprTuple { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprTuple"); + formatter.field("attrs", &self.attrs); + formatter.field("paren_token", &self.paren_token); + formatter.field("elems", &self.elems); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprType"); + formatter.field("attrs", &self.attrs); + formatter.field("expr", &self.expr); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ExprUnary { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprUnary"); + formatter.field("attrs", &self.attrs); + formatter.field("op", &self.op); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprUnsafe { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprUnsafe"); + formatter.field("attrs", &self.attrs); + formatter.field("unsafe_token", &self.unsafe_token); + formatter.field("block", &self.block); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprWhile { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprWhile"); + formatter.field("attrs", &self.attrs); + formatter.field("label", &self.label); + formatter.field("while_token", &self.while_token); + formatter.field("cond", &self.cond); + formatter.field("body", &self.body); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ExprYield { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ExprYield"); + formatter.field("attrs", &self.attrs); + formatter.field("yield_token", &self.yield_token); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Field { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Field"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for FieldPat { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("FieldPat"); + formatter.field("attrs", &self.attrs); + formatter.field("member", &self.member); + formatter.field("colon_token", &self.colon_token); + formatter.field("pat", &self.pat); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for FieldValue { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("FieldValue"); + formatter.field("attrs", &self.attrs); + formatter.field("member", &self.member); + formatter.field("colon_token", &self.colon_token); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Fields { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Fields::Named(v0) => { + let mut formatter = formatter.debug_tuple("Named"); + formatter.field(v0); + formatter.finish() + } + Fields::Unnamed(v0) => { + let mut formatter = formatter.debug_tuple("Unnamed"); + formatter.field(v0); + formatter.finish() + } + Fields::Unit => formatter.write_str("Unit"), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for FieldsNamed { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("FieldsNamed"); + formatter.field("brace_token", &self.brace_token); + formatter.field("named", &self.named); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for FieldsUnnamed { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("FieldsUnnamed"); + formatter.field("paren_token", &self.paren_token); + formatter.field("unnamed", &self.unnamed); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for File { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("File"); + formatter.field("shebang", &self.shebang); + formatter.field("attrs", &self.attrs); + formatter.field("items", &self.items); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for FnArg { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + FnArg::Receiver(v0) => { + let mut formatter = formatter.debug_tuple("Receiver"); + formatter.field(v0); + formatter.finish() + } + FnArg::Typed(v0) => { + let mut formatter = formatter.debug_tuple("Typed"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(feature = "full")] +impl Debug for ForeignItem { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + ForeignItem::Fn(v0) => { + let mut formatter = formatter.debug_tuple("Fn"); + formatter.field(v0); + formatter.finish() + } + ForeignItem::Static(v0) => { + let mut formatter = formatter.debug_tuple("Static"); + formatter.field(v0); + formatter.finish() + } + ForeignItem::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + ForeignItem::Macro(v0) => { + let mut formatter = formatter.debug_tuple("Macro"); + formatter.field(v0); + formatter.finish() + } + ForeignItem::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Debug for ForeignItemFn { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ForeignItemFn"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("sig", &self.sig); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ForeignItemMacro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ForeignItemMacro"); + formatter.field("attrs", &self.attrs); + formatter.field("mac", &self.mac); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ForeignItemStatic { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ForeignItemStatic"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("static_token", &self.static_token); + formatter.field("mutability", &self.mutability); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ForeignItemType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ForeignItemType"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("type_token", &self.type_token); + formatter.field("ident", &self.ident); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for GenericArgument { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + GenericArgument::Lifetime(v0) => { + let mut formatter = formatter.debug_tuple("Lifetime"); + formatter.field(v0); + formatter.finish() + } + GenericArgument::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + GenericArgument::Binding(v0) => { + let mut formatter = formatter.debug_tuple("Binding"); + formatter.field(v0); + formatter.finish() + } + GenericArgument::Constraint(v0) => { + let mut formatter = formatter.debug_tuple("Constraint"); + formatter.field(v0); + formatter.finish() + } + GenericArgument::Const(v0) => { + let mut formatter = formatter.debug_tuple("Const"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(feature = "full")] +impl Debug for GenericMethodArgument { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + GenericMethodArgument::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + GenericMethodArgument::Const(v0) => { + let mut formatter = formatter.debug_tuple("Const"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for GenericParam { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + GenericParam::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + GenericParam::Lifetime(v0) => { + let mut formatter = formatter.debug_tuple("Lifetime"); + formatter.field(v0); + formatter.finish() + } + GenericParam::Const(v0) => { + let mut formatter = formatter.debug_tuple("Const"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Generics { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Generics"); + formatter.field("lt_token", &self.lt_token); + formatter.field("params", &self.params); + formatter.field("gt_token", &self.gt_token); + formatter.field("where_clause", &self.where_clause); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ImplItem { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + ImplItem::Const(v0) => { + let mut formatter = formatter.debug_tuple("Const"); + formatter.field(v0); + formatter.finish() + } + ImplItem::Method(v0) => { + let mut formatter = formatter.debug_tuple("Method"); + formatter.field(v0); + formatter.finish() + } + ImplItem::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + ImplItem::Macro(v0) => { + let mut formatter = formatter.debug_tuple("Macro"); + formatter.field(v0); + formatter.finish() + } + ImplItem::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Debug for ImplItemConst { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ImplItemConst"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("defaultness", &self.defaultness); + formatter.field("const_token", &self.const_token); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.field("eq_token", &self.eq_token); + formatter.field("expr", &self.expr); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ImplItemMacro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ImplItemMacro"); + formatter.field("attrs", &self.attrs); + formatter.field("mac", &self.mac); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ImplItemMethod { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ImplItemMethod"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("defaultness", &self.defaultness); + formatter.field("sig", &self.sig); + formatter.field("block", &self.block); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ImplItemType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ImplItemType"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("defaultness", &self.defaultness); + formatter.field("type_token", &self.type_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("eq_token", &self.eq_token); + formatter.field("ty", &self.ty); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Index { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Index"); + formatter.field("index", &self.index); + formatter.field("span", &self.span); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for Item { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Item::Const(v0) => { + let mut formatter = formatter.debug_tuple("Const"); + formatter.field(v0); + formatter.finish() + } + Item::Enum(v0) => { + let mut formatter = formatter.debug_tuple("Enum"); + formatter.field(v0); + formatter.finish() + } + Item::ExternCrate(v0) => { + let mut formatter = formatter.debug_tuple("ExternCrate"); + formatter.field(v0); + formatter.finish() + } + Item::Fn(v0) => { + let mut formatter = formatter.debug_tuple("Fn"); + formatter.field(v0); + formatter.finish() + } + Item::ForeignMod(v0) => { + let mut formatter = formatter.debug_tuple("ForeignMod"); + formatter.field(v0); + formatter.finish() + } + Item::Impl(v0) => { + let mut formatter = formatter.debug_tuple("Impl"); + formatter.field(v0); + formatter.finish() + } + Item::Macro(v0) => { + let mut formatter = formatter.debug_tuple("Macro"); + formatter.field(v0); + formatter.finish() + } + Item::Macro2(v0) => { + let mut formatter = formatter.debug_tuple("Macro2"); + formatter.field(v0); + formatter.finish() + } + Item::Mod(v0) => { + let mut formatter = formatter.debug_tuple("Mod"); + formatter.field(v0); + formatter.finish() + } + Item::Static(v0) => { + let mut formatter = formatter.debug_tuple("Static"); + formatter.field(v0); + formatter.finish() + } + Item::Struct(v0) => { + let mut formatter = formatter.debug_tuple("Struct"); + formatter.field(v0); + formatter.finish() + } + Item::Trait(v0) => { + let mut formatter = formatter.debug_tuple("Trait"); + formatter.field(v0); + formatter.finish() + } + Item::TraitAlias(v0) => { + let mut formatter = formatter.debug_tuple("TraitAlias"); + formatter.field(v0); + formatter.finish() + } + Item::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + Item::Union(v0) => { + let mut formatter = formatter.debug_tuple("Union"); + formatter.field(v0); + formatter.finish() + } + Item::Use(v0) => { + let mut formatter = formatter.debug_tuple("Use"); + formatter.field(v0); + formatter.finish() + } + Item::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Debug for ItemConst { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemConst"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("const_token", &self.const_token); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.field("eq_token", &self.eq_token); + formatter.field("expr", &self.expr); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemEnum { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemEnum"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("enum_token", &self.enum_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("brace_token", &self.brace_token); + formatter.field("variants", &self.variants); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemExternCrate { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemExternCrate"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("extern_token", &self.extern_token); + formatter.field("crate_token", &self.crate_token); + formatter.field("ident", &self.ident); + formatter.field("rename", &self.rename); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemFn { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemFn"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("sig", &self.sig); + formatter.field("block", &self.block); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemForeignMod { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemForeignMod"); + formatter.field("attrs", &self.attrs); + formatter.field("abi", &self.abi); + formatter.field("brace_token", &self.brace_token); + formatter.field("items", &self.items); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemImpl { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemImpl"); + formatter.field("attrs", &self.attrs); + formatter.field("defaultness", &self.defaultness); + formatter.field("unsafety", &self.unsafety); + formatter.field("impl_token", &self.impl_token); + formatter.field("generics", &self.generics); + formatter.field("trait_", &self.trait_); + formatter.field("self_ty", &self.self_ty); + formatter.field("brace_token", &self.brace_token); + formatter.field("items", &self.items); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemMacro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemMacro"); + formatter.field("attrs", &self.attrs); + formatter.field("ident", &self.ident); + formatter.field("mac", &self.mac); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemMacro2 { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemMacro2"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("macro_token", &self.macro_token); + formatter.field("ident", &self.ident); + formatter.field("rules", &self.rules); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemMod { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemMod"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("mod_token", &self.mod_token); + formatter.field("ident", &self.ident); + formatter.field("content", &self.content); + formatter.field("semi", &self.semi); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemStatic { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemStatic"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("static_token", &self.static_token); + formatter.field("mutability", &self.mutability); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.field("eq_token", &self.eq_token); + formatter.field("expr", &self.expr); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemStruct { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemStruct"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("struct_token", &self.struct_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("fields", &self.fields); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemTrait { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemTrait"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("unsafety", &self.unsafety); + formatter.field("auto_token", &self.auto_token); + formatter.field("trait_token", &self.trait_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("colon_token", &self.colon_token); + formatter.field("supertraits", &self.supertraits); + formatter.field("brace_token", &self.brace_token); + formatter.field("items", &self.items); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemTraitAlias { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemTraitAlias"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("trait_token", &self.trait_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("eq_token", &self.eq_token); + formatter.field("bounds", &self.bounds); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemType"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("type_token", &self.type_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("eq_token", &self.eq_token); + formatter.field("ty", &self.ty); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemUnion { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemUnion"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("union_token", &self.union_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("fields", &self.fields); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for ItemUse { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ItemUse"); + formatter.field("attrs", &self.attrs); + formatter.field("vis", &self.vis); + formatter.field("use_token", &self.use_token); + formatter.field("leading_colon", &self.leading_colon); + formatter.field("tree", &self.tree); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for Label { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Label"); + formatter.field("name", &self.name); + formatter.field("colon_token", &self.colon_token); + formatter.finish() + } +} +impl Debug for Lifetime { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Lifetime"); + formatter.field("apostrophe", &self.apostrophe); + formatter.field("ident", &self.ident); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for LifetimeDef { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("LifetimeDef"); + formatter.field("attrs", &self.attrs); + formatter.field("lifetime", &self.lifetime); + formatter.field("colon_token", &self.colon_token); + formatter.field("bounds", &self.bounds); + formatter.finish() + } +} +impl Debug for Lit { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Lit::Str(v0) => { + let mut formatter = formatter.debug_tuple("Str"); + formatter.field(v0); + formatter.finish() + } + Lit::ByteStr(v0) => { + let mut formatter = formatter.debug_tuple("ByteStr"); + formatter.field(v0); + formatter.finish() + } + Lit::Byte(v0) => { + let mut formatter = formatter.debug_tuple("Byte"); + formatter.field(v0); + formatter.finish() + } + Lit::Char(v0) => { + let mut formatter = formatter.debug_tuple("Char"); + formatter.field(v0); + formatter.finish() + } + Lit::Int(v0) => { + let mut formatter = formatter.debug_tuple("Int"); + formatter.field(v0); + formatter.finish() + } + Lit::Float(v0) => { + let mut formatter = formatter.debug_tuple("Float"); + formatter.field(v0); + formatter.finish() + } + Lit::Bool(v0) => { + let mut formatter = formatter.debug_tuple("Bool"); + formatter.field(v0); + formatter.finish() + } + Lit::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(feature = "full")] +impl Debug for Local { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Local"); + formatter.field("attrs", &self.attrs); + formatter.field("let_token", &self.let_token); + formatter.field("pat", &self.pat); + formatter.field("init", &self.init); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Macro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Macro"); + formatter.field("path", &self.path); + formatter.field("bang_token", &self.bang_token); + formatter.field("delimiter", &self.delimiter); + formatter.field("tokens", &self.tokens); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for MacroDelimiter { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + MacroDelimiter::Paren(v0) => { + let mut formatter = formatter.debug_tuple("Paren"); + formatter.field(v0); + formatter.finish() + } + MacroDelimiter::Brace(v0) => { + let mut formatter = formatter.debug_tuple("Brace"); + formatter.field(v0); + formatter.finish() + } + MacroDelimiter::Bracket(v0) => { + let mut formatter = formatter.debug_tuple("Bracket"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Member { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Member::Named(v0) => { + let mut formatter = formatter.debug_tuple("Named"); + formatter.field(v0); + formatter.finish() + } + Member::Unnamed(v0) => { + let mut formatter = formatter.debug_tuple("Unnamed"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Meta { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Meta::Path(v0) => { + let mut formatter = formatter.debug_tuple("Path"); + formatter.field(v0); + formatter.finish() + } + Meta::List(v0) => { + let mut formatter = formatter.debug_tuple("List"); + formatter.field(v0); + formatter.finish() + } + Meta::NameValue(v0) => { + let mut formatter = formatter.debug_tuple("NameValue"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for MetaList { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("MetaList"); + formatter.field("path", &self.path); + formatter.field("paren_token", &self.paren_token); + formatter.field("nested", &self.nested); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for MetaNameValue { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("MetaNameValue"); + formatter.field("path", &self.path); + formatter.field("eq_token", &self.eq_token); + formatter.field("lit", &self.lit); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for MethodTurbofish { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("MethodTurbofish"); + formatter.field("colon2_token", &self.colon2_token); + formatter.field("lt_token", &self.lt_token); + formatter.field("args", &self.args); + formatter.field("gt_token", &self.gt_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for NestedMeta { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + NestedMeta::Meta(v0) => { + let mut formatter = formatter.debug_tuple("Meta"); + formatter.field(v0); + formatter.finish() + } + NestedMeta::Lit(v0) => { + let mut formatter = formatter.debug_tuple("Lit"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ParenthesizedGenericArguments { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("ParenthesizedGenericArguments"); + formatter.field("paren_token", &self.paren_token); + formatter.field("inputs", &self.inputs); + formatter.field("output", &self.output); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for Pat { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Pat::Box(v0) => { + let mut formatter = formatter.debug_tuple("Box"); + formatter.field(v0); + formatter.finish() + } + Pat::Ident(v0) => { + let mut formatter = formatter.debug_tuple("Ident"); + formatter.field(v0); + formatter.finish() + } + Pat::Lit(v0) => { + let mut formatter = formatter.debug_tuple("Lit"); + formatter.field(v0); + formatter.finish() + } + Pat::Macro(v0) => { + let mut formatter = formatter.debug_tuple("Macro"); + formatter.field(v0); + formatter.finish() + } + Pat::Or(v0) => { + let mut formatter = formatter.debug_tuple("Or"); + formatter.field(v0); + formatter.finish() + } + Pat::Path(v0) => { + let mut formatter = formatter.debug_tuple("Path"); + formatter.field(v0); + formatter.finish() + } + Pat::Range(v0) => { + let mut formatter = formatter.debug_tuple("Range"); + formatter.field(v0); + formatter.finish() + } + Pat::Reference(v0) => { + let mut formatter = formatter.debug_tuple("Reference"); + formatter.field(v0); + formatter.finish() + } + Pat::Rest(v0) => { + let mut formatter = formatter.debug_tuple("Rest"); + formatter.field(v0); + formatter.finish() + } + Pat::Slice(v0) => { + let mut formatter = formatter.debug_tuple("Slice"); + formatter.field(v0); + formatter.finish() + } + Pat::Struct(v0) => { + let mut formatter = formatter.debug_tuple("Struct"); + formatter.field(v0); + formatter.finish() + } + Pat::Tuple(v0) => { + let mut formatter = formatter.debug_tuple("Tuple"); + formatter.field(v0); + formatter.finish() + } + Pat::TupleStruct(v0) => { + let mut formatter = formatter.debug_tuple("TupleStruct"); + formatter.field(v0); + formatter.finish() + } + Pat::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + Pat::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + Pat::Wild(v0) => { + let mut formatter = formatter.debug_tuple("Wild"); + formatter.field(v0); + formatter.finish() + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Debug for PatBox { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatBox"); + formatter.field("attrs", &self.attrs); + formatter.field("box_token", &self.box_token); + formatter.field("pat", &self.pat); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatIdent { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatIdent"); + formatter.field("attrs", &self.attrs); + formatter.field("by_ref", &self.by_ref); + formatter.field("mutability", &self.mutability); + formatter.field("ident", &self.ident); + formatter.field("subpat", &self.subpat); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatLit { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatLit"); + formatter.field("attrs", &self.attrs); + formatter.field("expr", &self.expr); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatMacro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatMacro"); + formatter.field("attrs", &self.attrs); + formatter.field("mac", &self.mac); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatOr { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatOr"); + formatter.field("attrs", &self.attrs); + formatter.field("leading_vert", &self.leading_vert); + formatter.field("cases", &self.cases); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatPath { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatPath"); + formatter.field("attrs", &self.attrs); + formatter.field("qself", &self.qself); + formatter.field("path", &self.path); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatRange { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatRange"); + formatter.field("attrs", &self.attrs); + formatter.field("lo", &self.lo); + formatter.field("limits", &self.limits); + formatter.field("hi", &self.hi); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatReference { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatReference"); + formatter.field("attrs", &self.attrs); + formatter.field("and_token", &self.and_token); + formatter.field("mutability", &self.mutability); + formatter.field("pat", &self.pat); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatRest { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatRest"); + formatter.field("attrs", &self.attrs); + formatter.field("dot2_token", &self.dot2_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatSlice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatSlice"); + formatter.field("attrs", &self.attrs); + formatter.field("bracket_token", &self.bracket_token); + formatter.field("elems", &self.elems); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatStruct { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatStruct"); + formatter.field("attrs", &self.attrs); + formatter.field("path", &self.path); + formatter.field("brace_token", &self.brace_token); + formatter.field("fields", &self.fields); + formatter.field("dot2_token", &self.dot2_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatTuple { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatTuple"); + formatter.field("attrs", &self.attrs); + formatter.field("paren_token", &self.paren_token); + formatter.field("elems", &self.elems); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatTupleStruct { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatTupleStruct"); + formatter.field("attrs", &self.attrs); + formatter.field("path", &self.path); + formatter.field("pat", &self.pat); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatType"); + formatter.field("attrs", &self.attrs); + formatter.field("pat", &self.pat); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for PatWild { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PatWild"); + formatter.field("attrs", &self.attrs); + formatter.field("underscore_token", &self.underscore_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Path { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Path"); + formatter.field("leading_colon", &self.leading_colon); + formatter.field("segments", &self.segments); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for PathArguments { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + PathArguments::None => formatter.write_str("None"), + PathArguments::AngleBracketed(v0) => { + let mut formatter = formatter.debug_tuple("AngleBracketed"); + formatter.field(v0); + formatter.finish() + } + PathArguments::Parenthesized(v0) => { + let mut formatter = formatter.debug_tuple("Parenthesized"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for PathSegment { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PathSegment"); + formatter.field("ident", &self.ident); + formatter.field("arguments", &self.arguments); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for PredicateEq { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PredicateEq"); + formatter.field("lhs_ty", &self.lhs_ty); + formatter.field("eq_token", &self.eq_token); + formatter.field("rhs_ty", &self.rhs_ty); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for PredicateLifetime { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PredicateLifetime"); + formatter.field("lifetime", &self.lifetime); + formatter.field("colon_token", &self.colon_token); + formatter.field("bounds", &self.bounds); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for PredicateType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("PredicateType"); + formatter.field("lifetimes", &self.lifetimes); + formatter.field("bounded_ty", &self.bounded_ty); + formatter.field("colon_token", &self.colon_token); + formatter.field("bounds", &self.bounds); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for QSelf { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("QSelf"); + formatter.field("lt_token", &self.lt_token); + formatter.field("ty", &self.ty); + formatter.field("position", &self.position); + formatter.field("as_token", &self.as_token); + formatter.field("gt_token", &self.gt_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for RangeLimits { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + RangeLimits::HalfOpen(v0) => { + let mut formatter = formatter.debug_tuple("HalfOpen"); + formatter.field(v0); + formatter.finish() + } + RangeLimits::Closed(v0) => { + let mut formatter = formatter.debug_tuple("Closed"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(feature = "full")] +impl Debug for Receiver { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Receiver"); + formatter.field("attrs", &self.attrs); + formatter.field("reference", &self.reference); + formatter.field("mutability", &self.mutability); + formatter.field("self_token", &self.self_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for ReturnType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + ReturnType::Default => formatter.write_str("Default"), + ReturnType::Type(v0, v1) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.field(v1); + formatter.finish() + } + } + } +} +#[cfg(feature = "full")] +impl Debug for Signature { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Signature"); + formatter.field("constness", &self.constness); + formatter.field("asyncness", &self.asyncness); + formatter.field("unsafety", &self.unsafety); + formatter.field("abi", &self.abi); + formatter.field("fn_token", &self.fn_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("paren_token", &self.paren_token); + formatter.field("inputs", &self.inputs); + formatter.field("variadic", &self.variadic); + formatter.field("output", &self.output); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for Stmt { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Stmt::Local(v0) => { + let mut formatter = formatter.debug_tuple("Local"); + formatter.field(v0); + formatter.finish() + } + Stmt::Item(v0) => { + let mut formatter = formatter.debug_tuple("Item"); + formatter.field(v0); + formatter.finish() + } + Stmt::Expr(v0) => { + let mut formatter = formatter.debug_tuple("Expr"); + formatter.field(v0); + formatter.finish() + } + Stmt::Semi(v0, v1) => { + let mut formatter = formatter.debug_tuple("Semi"); + formatter.field(v0); + formatter.field(v1); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TraitBound { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TraitBound"); + formatter.field("paren_token", &self.paren_token); + formatter.field("modifier", &self.modifier); + formatter.field("lifetimes", &self.lifetimes); + formatter.field("path", &self.path); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TraitBoundModifier { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + TraitBoundModifier::None => formatter.write_str("None"), + TraitBoundModifier::Maybe(v0) => { + let mut formatter = formatter.debug_tuple("Maybe"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(feature = "full")] +impl Debug for TraitItem { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + TraitItem::Const(v0) => { + let mut formatter = formatter.debug_tuple("Const"); + formatter.field(v0); + formatter.finish() + } + TraitItem::Method(v0) => { + let mut formatter = formatter.debug_tuple("Method"); + formatter.field(v0); + formatter.finish() + } + TraitItem::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + TraitItem::Macro(v0) => { + let mut formatter = formatter.debug_tuple("Macro"); + formatter.field(v0); + formatter.finish() + } + TraitItem::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Debug for TraitItemConst { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TraitItemConst"); + formatter.field("attrs", &self.attrs); + formatter.field("const_token", &self.const_token); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("ty", &self.ty); + formatter.field("default", &self.default); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for TraitItemMacro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TraitItemMacro"); + formatter.field("attrs", &self.attrs); + formatter.field("mac", &self.mac); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for TraitItemMethod { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TraitItemMethod"); + formatter.field("attrs", &self.attrs); + formatter.field("sig", &self.sig); + formatter.field("default", &self.default); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for TraitItemType { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TraitItemType"); + formatter.field("attrs", &self.attrs); + formatter.field("type_token", &self.type_token); + formatter.field("ident", &self.ident); + formatter.field("generics", &self.generics); + formatter.field("colon_token", &self.colon_token); + formatter.field("bounds", &self.bounds); + formatter.field("default", &self.default); + formatter.field("semi_token", &self.semi_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Type { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Type::Array(v0) => { + let mut formatter = formatter.debug_tuple("Array"); + formatter.field(v0); + formatter.finish() + } + Type::BareFn(v0) => { + let mut formatter = formatter.debug_tuple("BareFn"); + formatter.field(v0); + formatter.finish() + } + Type::Group(v0) => { + let mut formatter = formatter.debug_tuple("Group"); + formatter.field(v0); + formatter.finish() + } + Type::ImplTrait(v0) => { + let mut formatter = formatter.debug_tuple("ImplTrait"); + formatter.field(v0); + formatter.finish() + } + Type::Infer(v0) => { + let mut formatter = formatter.debug_tuple("Infer"); + formatter.field(v0); + formatter.finish() + } + Type::Macro(v0) => { + let mut formatter = formatter.debug_tuple("Macro"); + formatter.field(v0); + formatter.finish() + } + Type::Never(v0) => { + let mut formatter = formatter.debug_tuple("Never"); + formatter.field(v0); + formatter.finish() + } + Type::Paren(v0) => { + let mut formatter = formatter.debug_tuple("Paren"); + formatter.field(v0); + formatter.finish() + } + Type::Path(v0) => { + let mut formatter = formatter.debug_tuple("Path"); + formatter.field(v0); + formatter.finish() + } + Type::Ptr(v0) => { + let mut formatter = formatter.debug_tuple("Ptr"); + formatter.field(v0); + formatter.finish() + } + Type::Reference(v0) => { + let mut formatter = formatter.debug_tuple("Reference"); + formatter.field(v0); + formatter.finish() + } + Type::Slice(v0) => { + let mut formatter = formatter.debug_tuple("Slice"); + formatter.field(v0); + formatter.finish() + } + Type::TraitObject(v0) => { + let mut formatter = formatter.debug_tuple("TraitObject"); + formatter.field(v0); + formatter.finish() + } + Type::Tuple(v0) => { + let mut formatter = formatter.debug_tuple("Tuple"); + formatter.field(v0); + formatter.finish() + } + Type::Verbatim(v0) => { + let mut formatter = formatter.debug_tuple("Verbatim"); + formatter.field(v0); + formatter.finish() + } + _ => unreachable!(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeArray { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeArray"); + formatter.field("bracket_token", &self.bracket_token); + formatter.field("elem", &self.elem); + formatter.field("semi_token", &self.semi_token); + formatter.field("len", &self.len); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeBareFn { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeBareFn"); + formatter.field("lifetimes", &self.lifetimes); + formatter.field("unsafety", &self.unsafety); + formatter.field("abi", &self.abi); + formatter.field("fn_token", &self.fn_token); + formatter.field("paren_token", &self.paren_token); + formatter.field("inputs", &self.inputs); + formatter.field("variadic", &self.variadic); + formatter.field("output", &self.output); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeGroup { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeGroup"); + formatter.field("group_token", &self.group_token); + formatter.field("elem", &self.elem); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeImplTrait { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeImplTrait"); + formatter.field("impl_token", &self.impl_token); + formatter.field("bounds", &self.bounds); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeInfer { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeInfer"); + formatter.field("underscore_token", &self.underscore_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeMacro { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeMacro"); + formatter.field("mac", &self.mac); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeNever { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeNever"); + formatter.field("bang_token", &self.bang_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeParam { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeParam"); + formatter.field("attrs", &self.attrs); + formatter.field("ident", &self.ident); + formatter.field("colon_token", &self.colon_token); + formatter.field("bounds", &self.bounds); + formatter.field("eq_token", &self.eq_token); + formatter.field("default", &self.default); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeParamBound { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + TypeParamBound::Trait(v0) => { + let mut formatter = formatter.debug_tuple("Trait"); + formatter.field(v0); + formatter.finish() + } + TypeParamBound::Lifetime(v0) => { + let mut formatter = formatter.debug_tuple("Lifetime"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeParen { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeParen"); + formatter.field("paren_token", &self.paren_token); + formatter.field("elem", &self.elem); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypePath { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypePath"); + formatter.field("qself", &self.qself); + formatter.field("path", &self.path); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypePtr { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypePtr"); + formatter.field("star_token", &self.star_token); + formatter.field("const_token", &self.const_token); + formatter.field("mutability", &self.mutability); + formatter.field("elem", &self.elem); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeReference { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeReference"); + formatter.field("and_token", &self.and_token); + formatter.field("lifetime", &self.lifetime); + formatter.field("mutability", &self.mutability); + formatter.field("elem", &self.elem); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeSlice { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeSlice"); + formatter.field("bracket_token", &self.bracket_token); + formatter.field("elem", &self.elem); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeTraitObject { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeTraitObject"); + formatter.field("dyn_token", &self.dyn_token); + formatter.field("bounds", &self.bounds); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for TypeTuple { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("TypeTuple"); + formatter.field("paren_token", &self.paren_token); + formatter.field("elems", &self.elems); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for UnOp { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + UnOp::Deref(v0) => { + let mut formatter = formatter.debug_tuple("Deref"); + formatter.field(v0); + formatter.finish() + } + UnOp::Not(v0) => { + let mut formatter = formatter.debug_tuple("Not"); + formatter.field(v0); + formatter.finish() + } + UnOp::Neg(v0) => { + let mut formatter = formatter.debug_tuple("Neg"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(feature = "full")] +impl Debug for UseGlob { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("UseGlob"); + formatter.field("star_token", &self.star_token); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for UseGroup { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("UseGroup"); + formatter.field("brace_token", &self.brace_token); + formatter.field("items", &self.items); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for UseName { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("UseName"); + formatter.field("ident", &self.ident); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for UsePath { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("UsePath"); + formatter.field("ident", &self.ident); + formatter.field("colon2_token", &self.colon2_token); + formatter.field("tree", &self.tree); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for UseRename { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("UseRename"); + formatter.field("ident", &self.ident); + formatter.field("as_token", &self.as_token); + formatter.field("rename", &self.rename); + formatter.finish() + } +} +#[cfg(feature = "full")] +impl Debug for UseTree { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + UseTree::Path(v0) => { + let mut formatter = formatter.debug_tuple("Path"); + formatter.field(v0); + formatter.finish() + } + UseTree::Name(v0) => { + let mut formatter = formatter.debug_tuple("Name"); + formatter.field(v0); + formatter.finish() + } + UseTree::Rename(v0) => { + let mut formatter = formatter.debug_tuple("Rename"); + formatter.field(v0); + formatter.finish() + } + UseTree::Glob(v0) => { + let mut formatter = formatter.debug_tuple("Glob"); + formatter.field(v0); + formatter.finish() + } + UseTree::Group(v0) => { + let mut formatter = formatter.debug_tuple("Group"); + formatter.field(v0); + formatter.finish() + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Variadic { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Variadic"); + formatter.field("attrs", &self.attrs); + formatter.field("dots", &self.dots); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Variant { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("Variant"); + formatter.field("attrs", &self.attrs); + formatter.field("ident", &self.ident); + formatter.field("fields", &self.fields); + formatter.field("discriminant", &self.discriminant); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for VisCrate { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("VisCrate"); + formatter.field("crate_token", &self.crate_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for VisPublic { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("VisPublic"); + formatter.field("pub_token", &self.pub_token); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for VisRestricted { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("VisRestricted"); + formatter.field("pub_token", &self.pub_token); + formatter.field("paren_token", &self.paren_token); + formatter.field("in_token", &self.in_token); + formatter.field("path", &self.path); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for Visibility { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + Visibility::Public(v0) => { + let mut formatter = formatter.debug_tuple("Public"); + formatter.field(v0); + formatter.finish() + } + Visibility::Crate(v0) => { + let mut formatter = formatter.debug_tuple("Crate"); + formatter.field(v0); + formatter.finish() + } + Visibility::Restricted(v0) => { + let mut formatter = formatter.debug_tuple("Restricted"); + formatter.field(v0); + formatter.finish() + } + Visibility::Inherited => formatter.write_str("Inherited"), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for WhereClause { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + let mut formatter = formatter.debug_struct("WhereClause"); + formatter.field("where_token", &self.where_token); + formatter.field("predicates", &self.predicates); + formatter.finish() + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Debug for WherePredicate { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + match self { + WherePredicate::Type(v0) => { + let mut formatter = formatter.debug_tuple("Type"); + formatter.field(v0); + formatter.finish() + } + WherePredicate::Lifetime(v0) => { + let mut formatter = formatter.debug_tuple("Lifetime"); + formatter.field(v0); + formatter.finish() + } + WherePredicate::Eq(v0) => { + let mut formatter = formatter.debug_tuple("Eq"); + formatter.field(v0); + formatter.finish() + } + } + } +} diff --git a/vendor/syn/src/gen/eq.rs b/vendor/syn/src/gen/eq.rs new file mode 100644 index 0000000000..15b2bcbbde --- /dev/null +++ b/vendor/syn/src/gen/eq.rs @@ -0,0 +1,1930 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +#[cfg(any(feature = "derive", feature = "full"))] +use crate::tt::TokenStreamHelper; +use crate::*; +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Abi {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Abi { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for AngleBracketedGenericArguments {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for AngleBracketedGenericArguments { + fn eq(&self, other: &Self) -> bool { + self.colon2_token == other.colon2_token && self.args == other.args + } +} +#[cfg(feature = "full")] +impl Eq for Arm {} +#[cfg(feature = "full")] +impl PartialEq for Arm { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.pat == other.pat + && self.guard == other.guard + && self.body == other.body + && self.comma == other.comma + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for AttrStyle {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for AttrStyle { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (AttrStyle::Outer, AttrStyle::Outer) => true, + (AttrStyle::Inner(_), AttrStyle::Inner(_)) => true, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Attribute {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Attribute { + fn eq(&self, other: &Self) -> bool { + self.style == other.style + && self.path == other.path + && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for BareFnArg {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for BareFnArg { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.name == other.name && self.ty == other.ty + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for BinOp {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for BinOp { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (BinOp::Add(_), BinOp::Add(_)) => true, + (BinOp::Sub(_), BinOp::Sub(_)) => true, + (BinOp::Mul(_), BinOp::Mul(_)) => true, + (BinOp::Div(_), BinOp::Div(_)) => true, + (BinOp::Rem(_), BinOp::Rem(_)) => true, + (BinOp::And(_), BinOp::And(_)) => true, + (BinOp::Or(_), BinOp::Or(_)) => true, + (BinOp::BitXor(_), BinOp::BitXor(_)) => true, + (BinOp::BitAnd(_), BinOp::BitAnd(_)) => true, + (BinOp::BitOr(_), BinOp::BitOr(_)) => true, + (BinOp::Shl(_), BinOp::Shl(_)) => true, + (BinOp::Shr(_), BinOp::Shr(_)) => true, + (BinOp::Eq(_), BinOp::Eq(_)) => true, + (BinOp::Lt(_), BinOp::Lt(_)) => true, + (BinOp::Le(_), BinOp::Le(_)) => true, + (BinOp::Ne(_), BinOp::Ne(_)) => true, + (BinOp::Ge(_), BinOp::Ge(_)) => true, + (BinOp::Gt(_), BinOp::Gt(_)) => true, + (BinOp::AddEq(_), BinOp::AddEq(_)) => true, + (BinOp::SubEq(_), BinOp::SubEq(_)) => true, + (BinOp::MulEq(_), BinOp::MulEq(_)) => true, + (BinOp::DivEq(_), BinOp::DivEq(_)) => true, + (BinOp::RemEq(_), BinOp::RemEq(_)) => true, + (BinOp::BitXorEq(_), BinOp::BitXorEq(_)) => true, + (BinOp::BitAndEq(_), BinOp::BitAndEq(_)) => true, + (BinOp::BitOrEq(_), BinOp::BitOrEq(_)) => true, + (BinOp::ShlEq(_), BinOp::ShlEq(_)) => true, + (BinOp::ShrEq(_), BinOp::ShrEq(_)) => true, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Binding {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Binding { + fn eq(&self, other: &Self) -> bool { + self.ident == other.ident && self.ty == other.ty + } +} +#[cfg(feature = "full")] +impl Eq for Block {} +#[cfg(feature = "full")] +impl PartialEq for Block { + fn eq(&self, other: &Self) -> bool { + self.stmts == other.stmts + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for BoundLifetimes {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for BoundLifetimes { + fn eq(&self, other: &Self) -> bool { + self.lifetimes == other.lifetimes + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ConstParam {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ConstParam { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.ident == other.ident + && self.ty == other.ty + && self.eq_token == other.eq_token + && self.default == other.default + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Constraint {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Constraint { + fn eq(&self, other: &Self) -> bool { + self.ident == other.ident && self.bounds == other.bounds + } +} +#[cfg(feature = "derive")] +impl Eq for Data {} +#[cfg(feature = "derive")] +impl PartialEq for Data { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Data::Struct(self0), Data::Struct(other0)) => self0 == other0, + (Data::Enum(self0), Data::Enum(other0)) => self0 == other0, + (Data::Union(self0), Data::Union(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(feature = "derive")] +impl Eq for DataEnum {} +#[cfg(feature = "derive")] +impl PartialEq for DataEnum { + fn eq(&self, other: &Self) -> bool { + self.variants == other.variants + } +} +#[cfg(feature = "derive")] +impl Eq for DataStruct {} +#[cfg(feature = "derive")] +impl PartialEq for DataStruct { + fn eq(&self, other: &Self) -> bool { + self.fields == other.fields && self.semi_token == other.semi_token + } +} +#[cfg(feature = "derive")] +impl Eq for DataUnion {} +#[cfg(feature = "derive")] +impl PartialEq for DataUnion { + fn eq(&self, other: &Self) -> bool { + self.fields == other.fields + } +} +#[cfg(feature = "derive")] +impl Eq for DeriveInput {} +#[cfg(feature = "derive")] +impl PartialEq for DeriveInput { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.generics == other.generics + && self.data == other.data + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Expr {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Expr { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + #[cfg(feature = "full")] + (Expr::Array(self0), Expr::Array(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Assign(self0), Expr::Assign(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::AssignOp(self0), Expr::AssignOp(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Async(self0), Expr::Async(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Await(self0), Expr::Await(other0)) => self0 == other0, + (Expr::Binary(self0), Expr::Binary(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Block(self0), Expr::Block(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Box(self0), Expr::Box(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Break(self0), Expr::Break(other0)) => self0 == other0, + (Expr::Call(self0), Expr::Call(other0)) => self0 == other0, + (Expr::Cast(self0), Expr::Cast(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Closure(self0), Expr::Closure(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Continue(self0), Expr::Continue(other0)) => self0 == other0, + (Expr::Field(self0), Expr::Field(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::ForLoop(self0), Expr::ForLoop(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Group(self0), Expr::Group(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::If(self0), Expr::If(other0)) => self0 == other0, + (Expr::Index(self0), Expr::Index(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Let(self0), Expr::Let(other0)) => self0 == other0, + (Expr::Lit(self0), Expr::Lit(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Loop(self0), Expr::Loop(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Macro(self0), Expr::Macro(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Match(self0), Expr::Match(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::MethodCall(self0), Expr::MethodCall(other0)) => self0 == other0, + (Expr::Paren(self0), Expr::Paren(other0)) => self0 == other0, + (Expr::Path(self0), Expr::Path(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Range(self0), Expr::Range(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Reference(self0), Expr::Reference(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Repeat(self0), Expr::Repeat(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Return(self0), Expr::Return(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Struct(self0), Expr::Struct(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Try(self0), Expr::Try(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::TryBlock(self0), Expr::TryBlock(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Tuple(self0), Expr::Tuple(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Type(self0), Expr::Type(other0)) => self0 == other0, + (Expr::Unary(self0), Expr::Unary(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Unsafe(self0), Expr::Unsafe(other0)) => self0 == other0, + (Expr::Verbatim(self0), Expr::Verbatim(other0)) => { + TokenStreamHelper(self0) == TokenStreamHelper(other0) + } + #[cfg(feature = "full")] + (Expr::While(self0), Expr::While(other0)) => self0 == other0, + #[cfg(feature = "full")] + (Expr::Yield(self0), Expr::Yield(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for ExprArray {} +#[cfg(feature = "full")] +impl PartialEq for ExprArray { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.elems == other.elems + } +} +#[cfg(feature = "full")] +impl Eq for ExprAssign {} +#[cfg(feature = "full")] +impl PartialEq for ExprAssign { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.left == other.left && self.right == other.right + } +} +#[cfg(feature = "full")] +impl Eq for ExprAssignOp {} +#[cfg(feature = "full")] +impl PartialEq for ExprAssignOp { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.left == other.left + && self.op == other.op + && self.right == other.right + } +} +#[cfg(feature = "full")] +impl Eq for ExprAsync {} +#[cfg(feature = "full")] +impl PartialEq for ExprAsync { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.capture == other.capture && self.block == other.block + } +} +#[cfg(feature = "full")] +impl Eq for ExprAwait {} +#[cfg(feature = "full")] +impl PartialEq for ExprAwait { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.base == other.base + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprBinary {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprBinary { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.left == other.left + && self.op == other.op + && self.right == other.right + } +} +#[cfg(feature = "full")] +impl Eq for ExprBlock {} +#[cfg(feature = "full")] +impl PartialEq for ExprBlock { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.label == other.label && self.block == other.block + } +} +#[cfg(feature = "full")] +impl Eq for ExprBox {} +#[cfg(feature = "full")] +impl PartialEq for ExprBox { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ExprBreak {} +#[cfg(feature = "full")] +impl PartialEq for ExprBreak { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.label == other.label && self.expr == other.expr + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprCall {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprCall { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.func == other.func && self.args == other.args + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprCast {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprCast { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr && self.ty == other.ty + } +} +#[cfg(feature = "full")] +impl Eq for ExprClosure {} +#[cfg(feature = "full")] +impl PartialEq for ExprClosure { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.asyncness == other.asyncness + && self.movability == other.movability + && self.capture == other.capture + && self.inputs == other.inputs + && self.output == other.output + && self.body == other.body + } +} +#[cfg(feature = "full")] +impl Eq for ExprContinue {} +#[cfg(feature = "full")] +impl PartialEq for ExprContinue { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.label == other.label + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprField {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprField { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.base == other.base && self.member == other.member + } +} +#[cfg(feature = "full")] +impl Eq for ExprForLoop {} +#[cfg(feature = "full")] +impl PartialEq for ExprForLoop { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.label == other.label + && self.pat == other.pat + && self.expr == other.expr + && self.body == other.body + } +} +#[cfg(feature = "full")] +impl Eq for ExprGroup {} +#[cfg(feature = "full")] +impl PartialEq for ExprGroup { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ExprIf {} +#[cfg(feature = "full")] +impl PartialEq for ExprIf { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.cond == other.cond + && self.then_branch == other.then_branch + && self.else_branch == other.else_branch + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprIndex {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprIndex { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr && self.index == other.index + } +} +#[cfg(feature = "full")] +impl Eq for ExprLet {} +#[cfg(feature = "full")] +impl PartialEq for ExprLet { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.pat == other.pat && self.expr == other.expr + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprLit {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprLit { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.lit == other.lit + } +} +#[cfg(feature = "full")] +impl Eq for ExprLoop {} +#[cfg(feature = "full")] +impl PartialEq for ExprLoop { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.label == other.label && self.body == other.body + } +} +#[cfg(feature = "full")] +impl Eq for ExprMacro {} +#[cfg(feature = "full")] +impl PartialEq for ExprMacro { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.mac == other.mac + } +} +#[cfg(feature = "full")] +impl Eq for ExprMatch {} +#[cfg(feature = "full")] +impl PartialEq for ExprMatch { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr && self.arms == other.arms + } +} +#[cfg(feature = "full")] +impl Eq for ExprMethodCall {} +#[cfg(feature = "full")] +impl PartialEq for ExprMethodCall { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.receiver == other.receiver + && self.method == other.method + && self.turbofish == other.turbofish + && self.args == other.args + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprParen {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprParen { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprPath {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprPath { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.qself == other.qself && self.path == other.path + } +} +#[cfg(feature = "full")] +impl Eq for ExprRange {} +#[cfg(feature = "full")] +impl PartialEq for ExprRange { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.from == other.from + && self.limits == other.limits + && self.to == other.to + } +} +#[cfg(feature = "full")] +impl Eq for ExprReference {} +#[cfg(feature = "full")] +impl PartialEq for ExprReference { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.mutability == other.mutability && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ExprRepeat {} +#[cfg(feature = "full")] +impl PartialEq for ExprRepeat { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr && self.len == other.len + } +} +#[cfg(feature = "full")] +impl Eq for ExprReturn {} +#[cfg(feature = "full")] +impl PartialEq for ExprReturn { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ExprStruct {} +#[cfg(feature = "full")] +impl PartialEq for ExprStruct { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.path == other.path + && self.fields == other.fields + && self.dot2_token == other.dot2_token + && self.rest == other.rest + } +} +#[cfg(feature = "full")] +impl Eq for ExprTry {} +#[cfg(feature = "full")] +impl PartialEq for ExprTry { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ExprTryBlock {} +#[cfg(feature = "full")] +impl PartialEq for ExprTryBlock { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.block == other.block + } +} +#[cfg(feature = "full")] +impl Eq for ExprTuple {} +#[cfg(feature = "full")] +impl PartialEq for ExprTuple { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.elems == other.elems + } +} +#[cfg(feature = "full")] +impl Eq for ExprType {} +#[cfg(feature = "full")] +impl PartialEq for ExprType { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr && self.ty == other.ty + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ExprUnary {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ExprUnary { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.op == other.op && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ExprUnsafe {} +#[cfg(feature = "full")] +impl PartialEq for ExprUnsafe { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.block == other.block + } +} +#[cfg(feature = "full")] +impl Eq for ExprWhile {} +#[cfg(feature = "full")] +impl PartialEq for ExprWhile { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.label == other.label + && self.cond == other.cond + && self.body == other.body + } +} +#[cfg(feature = "full")] +impl Eq for ExprYield {} +#[cfg(feature = "full")] +impl PartialEq for ExprYield { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Field {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Field { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.colon_token == other.colon_token + && self.ty == other.ty + } +} +#[cfg(feature = "full")] +impl Eq for FieldPat {} +#[cfg(feature = "full")] +impl PartialEq for FieldPat { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.member == other.member + && self.colon_token == other.colon_token + && self.pat == other.pat + } +} +#[cfg(feature = "full")] +impl Eq for FieldValue {} +#[cfg(feature = "full")] +impl PartialEq for FieldValue { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.member == other.member + && self.colon_token == other.colon_token + && self.expr == other.expr + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Fields {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Fields { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Fields::Named(self0), Fields::Named(other0)) => self0 == other0, + (Fields::Unnamed(self0), Fields::Unnamed(other0)) => self0 == other0, + (Fields::Unit, Fields::Unit) => true, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for FieldsNamed {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for FieldsNamed { + fn eq(&self, other: &Self) -> bool { + self.named == other.named + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for FieldsUnnamed {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for FieldsUnnamed { + fn eq(&self, other: &Self) -> bool { + self.unnamed == other.unnamed + } +} +#[cfg(feature = "full")] +impl Eq for File {} +#[cfg(feature = "full")] +impl PartialEq for File { + fn eq(&self, other: &Self) -> bool { + self.shebang == other.shebang && self.attrs == other.attrs && self.items == other.items + } +} +#[cfg(feature = "full")] +impl Eq for FnArg {} +#[cfg(feature = "full")] +impl PartialEq for FnArg { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (FnArg::Receiver(self0), FnArg::Receiver(other0)) => self0 == other0, + (FnArg::Typed(self0), FnArg::Typed(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for ForeignItem {} +#[cfg(feature = "full")] +impl PartialEq for ForeignItem { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (ForeignItem::Fn(self0), ForeignItem::Fn(other0)) => self0 == other0, + (ForeignItem::Static(self0), ForeignItem::Static(other0)) => self0 == other0, + (ForeignItem::Type(self0), ForeignItem::Type(other0)) => self0 == other0, + (ForeignItem::Macro(self0), ForeignItem::Macro(other0)) => self0 == other0, + (ForeignItem::Verbatim(self0), ForeignItem::Verbatim(other0)) => { + TokenStreamHelper(self0) == TokenStreamHelper(other0) + } + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for ForeignItemFn {} +#[cfg(feature = "full")] +impl PartialEq for ForeignItemFn { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.vis == other.vis && self.sig == other.sig + } +} +#[cfg(feature = "full")] +impl Eq for ForeignItemMacro {} +#[cfg(feature = "full")] +impl PartialEq for ForeignItemMacro { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.mac == other.mac && self.semi_token == other.semi_token + } +} +#[cfg(feature = "full")] +impl Eq for ForeignItemStatic {} +#[cfg(feature = "full")] +impl PartialEq for ForeignItemStatic { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.mutability == other.mutability + && self.ident == other.ident + && self.ty == other.ty + } +} +#[cfg(feature = "full")] +impl Eq for ForeignItemType {} +#[cfg(feature = "full")] +impl PartialEq for ForeignItemType { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.vis == other.vis && self.ident == other.ident + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for GenericArgument {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for GenericArgument { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (GenericArgument::Lifetime(self0), GenericArgument::Lifetime(other0)) => { + self0 == other0 + } + (GenericArgument::Type(self0), GenericArgument::Type(other0)) => self0 == other0, + (GenericArgument::Binding(self0), GenericArgument::Binding(other0)) => self0 == other0, + (GenericArgument::Constraint(self0), GenericArgument::Constraint(other0)) => { + self0 == other0 + } + (GenericArgument::Const(self0), GenericArgument::Const(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for GenericMethodArgument {} +#[cfg(feature = "full")] +impl PartialEq for GenericMethodArgument { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (GenericMethodArgument::Type(self0), GenericMethodArgument::Type(other0)) => { + self0 == other0 + } + (GenericMethodArgument::Const(self0), GenericMethodArgument::Const(other0)) => { + self0 == other0 + } + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for GenericParam {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for GenericParam { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (GenericParam::Type(self0), GenericParam::Type(other0)) => self0 == other0, + (GenericParam::Lifetime(self0), GenericParam::Lifetime(other0)) => self0 == other0, + (GenericParam::Const(self0), GenericParam::Const(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Generics {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Generics { + fn eq(&self, other: &Self) -> bool { + self.lt_token == other.lt_token + && self.params == other.params + && self.gt_token == other.gt_token + && self.where_clause == other.where_clause + } +} +#[cfg(feature = "full")] +impl Eq for ImplItem {} +#[cfg(feature = "full")] +impl PartialEq for ImplItem { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (ImplItem::Const(self0), ImplItem::Const(other0)) => self0 == other0, + (ImplItem::Method(self0), ImplItem::Method(other0)) => self0 == other0, + (ImplItem::Type(self0), ImplItem::Type(other0)) => self0 == other0, + (ImplItem::Macro(self0), ImplItem::Macro(other0)) => self0 == other0, + (ImplItem::Verbatim(self0), ImplItem::Verbatim(other0)) => { + TokenStreamHelper(self0) == TokenStreamHelper(other0) + } + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for ImplItemConst {} +#[cfg(feature = "full")] +impl PartialEq for ImplItemConst { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.defaultness == other.defaultness + && self.ident == other.ident + && self.ty == other.ty + && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ImplItemMacro {} +#[cfg(feature = "full")] +impl PartialEq for ImplItemMacro { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.mac == other.mac && self.semi_token == other.semi_token + } +} +#[cfg(feature = "full")] +impl Eq for ImplItemMethod {} +#[cfg(feature = "full")] +impl PartialEq for ImplItemMethod { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.defaultness == other.defaultness + && self.sig == other.sig + && self.block == other.block + } +} +#[cfg(feature = "full")] +impl Eq for ImplItemType {} +#[cfg(feature = "full")] +impl PartialEq for ImplItemType { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.defaultness == other.defaultness + && self.ident == other.ident + && self.generics == other.generics + && self.ty == other.ty + } +} +#[cfg(feature = "full")] +impl Eq for Item {} +#[cfg(feature = "full")] +impl PartialEq for Item { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Item::Const(self0), Item::Const(other0)) => self0 == other0, + (Item::Enum(self0), Item::Enum(other0)) => self0 == other0, + (Item::ExternCrate(self0), Item::ExternCrate(other0)) => self0 == other0, + (Item::Fn(self0), Item::Fn(other0)) => self0 == other0, + (Item::ForeignMod(self0), Item::ForeignMod(other0)) => self0 == other0, + (Item::Impl(self0), Item::Impl(other0)) => self0 == other0, + (Item::Macro(self0), Item::Macro(other0)) => self0 == other0, + (Item::Macro2(self0), Item::Macro2(other0)) => self0 == other0, + (Item::Mod(self0), Item::Mod(other0)) => self0 == other0, + (Item::Static(self0), Item::Static(other0)) => self0 == other0, + (Item::Struct(self0), Item::Struct(other0)) => self0 == other0, + (Item::Trait(self0), Item::Trait(other0)) => self0 == other0, + (Item::TraitAlias(self0), Item::TraitAlias(other0)) => self0 == other0, + (Item::Type(self0), Item::Type(other0)) => self0 == other0, + (Item::Union(self0), Item::Union(other0)) => self0 == other0, + (Item::Use(self0), Item::Use(other0)) => self0 == other0, + (Item::Verbatim(self0), Item::Verbatim(other0)) => { + TokenStreamHelper(self0) == TokenStreamHelper(other0) + } + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for ItemConst {} +#[cfg(feature = "full")] +impl PartialEq for ItemConst { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.ty == other.ty + && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ItemEnum {} +#[cfg(feature = "full")] +impl PartialEq for ItemEnum { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.generics == other.generics + && self.variants == other.variants + } +} +#[cfg(feature = "full")] +impl Eq for ItemExternCrate {} +#[cfg(feature = "full")] +impl PartialEq for ItemExternCrate { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.rename == other.rename + } +} +#[cfg(feature = "full")] +impl Eq for ItemFn {} +#[cfg(feature = "full")] +impl PartialEq for ItemFn { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.sig == other.sig + && self.block == other.block + } +} +#[cfg(feature = "full")] +impl Eq for ItemForeignMod {} +#[cfg(feature = "full")] +impl PartialEq for ItemForeignMod { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.abi == other.abi && self.items == other.items + } +} +#[cfg(feature = "full")] +impl Eq for ItemImpl {} +#[cfg(feature = "full")] +impl PartialEq for ItemImpl { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.defaultness == other.defaultness + && self.unsafety == other.unsafety + && self.generics == other.generics + && self.trait_ == other.trait_ + && self.self_ty == other.self_ty + && self.items == other.items + } +} +#[cfg(feature = "full")] +impl Eq for ItemMacro {} +#[cfg(feature = "full")] +impl PartialEq for ItemMacro { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.ident == other.ident + && self.mac == other.mac + && self.semi_token == other.semi_token + } +} +#[cfg(feature = "full")] +impl Eq for ItemMacro2 {} +#[cfg(feature = "full")] +impl PartialEq for ItemMacro2 { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && TokenStreamHelper(&self.rules) == TokenStreamHelper(&other.rules) + } +} +#[cfg(feature = "full")] +impl Eq for ItemMod {} +#[cfg(feature = "full")] +impl PartialEq for ItemMod { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.content == other.content + && self.semi == other.semi + } +} +#[cfg(feature = "full")] +impl Eq for ItemStatic {} +#[cfg(feature = "full")] +impl PartialEq for ItemStatic { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.mutability == other.mutability + && self.ident == other.ident + && self.ty == other.ty + && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for ItemStruct {} +#[cfg(feature = "full")] +impl PartialEq for ItemStruct { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.generics == other.generics + && self.fields == other.fields + && self.semi_token == other.semi_token + } +} +#[cfg(feature = "full")] +impl Eq for ItemTrait {} +#[cfg(feature = "full")] +impl PartialEq for ItemTrait { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.unsafety == other.unsafety + && self.auto_token == other.auto_token + && self.ident == other.ident + && self.generics == other.generics + && self.colon_token == other.colon_token + && self.supertraits == other.supertraits + && self.items == other.items + } +} +#[cfg(feature = "full")] +impl Eq for ItemTraitAlias {} +#[cfg(feature = "full")] +impl PartialEq for ItemTraitAlias { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.generics == other.generics + && self.bounds == other.bounds + } +} +#[cfg(feature = "full")] +impl Eq for ItemType {} +#[cfg(feature = "full")] +impl PartialEq for ItemType { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.generics == other.generics + && self.ty == other.ty + } +} +#[cfg(feature = "full")] +impl Eq for ItemUnion {} +#[cfg(feature = "full")] +impl PartialEq for ItemUnion { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.ident == other.ident + && self.generics == other.generics + && self.fields == other.fields + } +} +#[cfg(feature = "full")] +impl Eq for ItemUse {} +#[cfg(feature = "full")] +impl PartialEq for ItemUse { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.vis == other.vis + && self.leading_colon == other.leading_colon + && self.tree == other.tree + } +} +#[cfg(feature = "full")] +impl Eq for Label {} +#[cfg(feature = "full")] +impl PartialEq for Label { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for LifetimeDef {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for LifetimeDef { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.lifetime == other.lifetime + && self.colon_token == other.colon_token + && self.bounds == other.bounds + } +} +impl Eq for Lit {} +impl PartialEq for Lit { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Lit::Str(self0), Lit::Str(other0)) => self0 == other0, + (Lit::ByteStr(self0), Lit::ByteStr(other0)) => self0 == other0, + (Lit::Byte(self0), Lit::Byte(other0)) => self0 == other0, + (Lit::Char(self0), Lit::Char(other0)) => self0 == other0, + (Lit::Int(self0), Lit::Int(other0)) => self0 == other0, + (Lit::Float(self0), Lit::Float(other0)) => self0 == other0, + (Lit::Bool(self0), Lit::Bool(other0)) => self0 == other0, + (Lit::Verbatim(self0), Lit::Verbatim(other0)) => { + self0.to_string() == other0.to_string() + } + _ => false, + } + } +} +impl Eq for LitBool {} +impl PartialEq for LitBool { + fn eq(&self, other: &Self) -> bool { + self.value == other.value + } +} +impl Eq for LitByte {} +impl Eq for LitByteStr {} +impl Eq for LitChar {} +impl Eq for LitFloat {} +impl Eq for LitInt {} +impl Eq for LitStr {} +#[cfg(feature = "full")] +impl Eq for Local {} +#[cfg(feature = "full")] +impl PartialEq for Local { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.pat == other.pat && self.init == other.init + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Macro {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Macro { + fn eq(&self, other: &Self) -> bool { + self.path == other.path + && self.delimiter == other.delimiter + && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens) + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for MacroDelimiter {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for MacroDelimiter { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (MacroDelimiter::Paren(_), MacroDelimiter::Paren(_)) => true, + (MacroDelimiter::Brace(_), MacroDelimiter::Brace(_)) => true, + (MacroDelimiter::Bracket(_), MacroDelimiter::Bracket(_)) => true, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Meta {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Meta { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Meta::Path(self0), Meta::Path(other0)) => self0 == other0, + (Meta::List(self0), Meta::List(other0)) => self0 == other0, + (Meta::NameValue(self0), Meta::NameValue(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for MetaList {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for MetaList { + fn eq(&self, other: &Self) -> bool { + self.path == other.path && self.nested == other.nested + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for MetaNameValue {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for MetaNameValue { + fn eq(&self, other: &Self) -> bool { + self.path == other.path && self.lit == other.lit + } +} +#[cfg(feature = "full")] +impl Eq for MethodTurbofish {} +#[cfg(feature = "full")] +impl PartialEq for MethodTurbofish { + fn eq(&self, other: &Self) -> bool { + self.args == other.args + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for NestedMeta {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for NestedMeta { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (NestedMeta::Meta(self0), NestedMeta::Meta(other0)) => self0 == other0, + (NestedMeta::Lit(self0), NestedMeta::Lit(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ParenthesizedGenericArguments {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ParenthesizedGenericArguments { + fn eq(&self, other: &Self) -> bool { + self.inputs == other.inputs && self.output == other.output + } +} +#[cfg(feature = "full")] +impl Eq for Pat {} +#[cfg(feature = "full")] +impl PartialEq for Pat { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Pat::Box(self0), Pat::Box(other0)) => self0 == other0, + (Pat::Ident(self0), Pat::Ident(other0)) => self0 == other0, + (Pat::Lit(self0), Pat::Lit(other0)) => self0 == other0, + (Pat::Macro(self0), Pat::Macro(other0)) => self0 == other0, + (Pat::Or(self0), Pat::Or(other0)) => self0 == other0, + (Pat::Path(self0), Pat::Path(other0)) => self0 == other0, + (Pat::Range(self0), Pat::Range(other0)) => self0 == other0, + (Pat::Reference(self0), Pat::Reference(other0)) => self0 == other0, + (Pat::Rest(self0), Pat::Rest(other0)) => self0 == other0, + (Pat::Slice(self0), Pat::Slice(other0)) => self0 == other0, + (Pat::Struct(self0), Pat::Struct(other0)) => self0 == other0, + (Pat::Tuple(self0), Pat::Tuple(other0)) => self0 == other0, + (Pat::TupleStruct(self0), Pat::TupleStruct(other0)) => self0 == other0, + (Pat::Type(self0), Pat::Type(other0)) => self0 == other0, + (Pat::Verbatim(self0), Pat::Verbatim(other0)) => { + TokenStreamHelper(self0) == TokenStreamHelper(other0) + } + (Pat::Wild(self0), Pat::Wild(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for PatBox {} +#[cfg(feature = "full")] +impl PartialEq for PatBox { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.pat == other.pat + } +} +#[cfg(feature = "full")] +impl Eq for PatIdent {} +#[cfg(feature = "full")] +impl PartialEq for PatIdent { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.by_ref == other.by_ref + && self.mutability == other.mutability + && self.ident == other.ident + && self.subpat == other.subpat + } +} +#[cfg(feature = "full")] +impl Eq for PatLit {} +#[cfg(feature = "full")] +impl PartialEq for PatLit { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.expr == other.expr + } +} +#[cfg(feature = "full")] +impl Eq for PatMacro {} +#[cfg(feature = "full")] +impl PartialEq for PatMacro { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.mac == other.mac + } +} +#[cfg(feature = "full")] +impl Eq for PatOr {} +#[cfg(feature = "full")] +impl PartialEq for PatOr { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.leading_vert == other.leading_vert + && self.cases == other.cases + } +} +#[cfg(feature = "full")] +impl Eq for PatPath {} +#[cfg(feature = "full")] +impl PartialEq for PatPath { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.qself == other.qself && self.path == other.path + } +} +#[cfg(feature = "full")] +impl Eq for PatRange {} +#[cfg(feature = "full")] +impl PartialEq for PatRange { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.lo == other.lo + && self.limits == other.limits + && self.hi == other.hi + } +} +#[cfg(feature = "full")] +impl Eq for PatReference {} +#[cfg(feature = "full")] +impl PartialEq for PatReference { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.mutability == other.mutability && self.pat == other.pat + } +} +#[cfg(feature = "full")] +impl Eq for PatRest {} +#[cfg(feature = "full")] +impl PartialEq for PatRest { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + } +} +#[cfg(feature = "full")] +impl Eq for PatSlice {} +#[cfg(feature = "full")] +impl PartialEq for PatSlice { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.elems == other.elems + } +} +#[cfg(feature = "full")] +impl Eq for PatStruct {} +#[cfg(feature = "full")] +impl PartialEq for PatStruct { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.path == other.path + && self.fields == other.fields + && self.dot2_token == other.dot2_token + } +} +#[cfg(feature = "full")] +impl Eq for PatTuple {} +#[cfg(feature = "full")] +impl PartialEq for PatTuple { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.elems == other.elems + } +} +#[cfg(feature = "full")] +impl Eq for PatTupleStruct {} +#[cfg(feature = "full")] +impl PartialEq for PatTupleStruct { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.path == other.path && self.pat == other.pat + } +} +#[cfg(feature = "full")] +impl Eq for PatType {} +#[cfg(feature = "full")] +impl PartialEq for PatType { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.pat == other.pat && self.ty == other.ty + } +} +#[cfg(feature = "full")] +impl Eq for PatWild {} +#[cfg(feature = "full")] +impl PartialEq for PatWild { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Path {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Path { + fn eq(&self, other: &Self) -> bool { + self.leading_colon == other.leading_colon && self.segments == other.segments + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for PathArguments {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for PathArguments { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (PathArguments::None, PathArguments::None) => true, + (PathArguments::AngleBracketed(self0), PathArguments::AngleBracketed(other0)) => { + self0 == other0 + } + (PathArguments::Parenthesized(self0), PathArguments::Parenthesized(other0)) => { + self0 == other0 + } + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for PathSegment {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for PathSegment { + fn eq(&self, other: &Self) -> bool { + self.ident == other.ident && self.arguments == other.arguments + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for PredicateEq {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for PredicateEq { + fn eq(&self, other: &Self) -> bool { + self.lhs_ty == other.lhs_ty && self.rhs_ty == other.rhs_ty + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for PredicateLifetime {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for PredicateLifetime { + fn eq(&self, other: &Self) -> bool { + self.lifetime == other.lifetime && self.bounds == other.bounds + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for PredicateType {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for PredicateType { + fn eq(&self, other: &Self) -> bool { + self.lifetimes == other.lifetimes + && self.bounded_ty == other.bounded_ty + && self.bounds == other.bounds + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for QSelf {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for QSelf { + fn eq(&self, other: &Self) -> bool { + self.ty == other.ty && self.position == other.position && self.as_token == other.as_token + } +} +#[cfg(feature = "full")] +impl Eq for RangeLimits {} +#[cfg(feature = "full")] +impl PartialEq for RangeLimits { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (RangeLimits::HalfOpen(_), RangeLimits::HalfOpen(_)) => true, + (RangeLimits::Closed(_), RangeLimits::Closed(_)) => true, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for Receiver {} +#[cfg(feature = "full")] +impl PartialEq for Receiver { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.reference == other.reference + && self.mutability == other.mutability + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for ReturnType {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for ReturnType { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (ReturnType::Default, ReturnType::Default) => true, + (ReturnType::Type(_, self1), ReturnType::Type(_, other1)) => self1 == other1, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for Signature {} +#[cfg(feature = "full")] +impl PartialEq for Signature { + fn eq(&self, other: &Self) -> bool { + self.constness == other.constness + && self.asyncness == other.asyncness + && self.unsafety == other.unsafety + && self.abi == other.abi + && self.ident == other.ident + && self.generics == other.generics + && self.inputs == other.inputs + && self.variadic == other.variadic + && self.output == other.output + } +} +#[cfg(feature = "full")] +impl Eq for Stmt {} +#[cfg(feature = "full")] +impl PartialEq for Stmt { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Stmt::Local(self0), Stmt::Local(other0)) => self0 == other0, + (Stmt::Item(self0), Stmt::Item(other0)) => self0 == other0, + (Stmt::Expr(self0), Stmt::Expr(other0)) => self0 == other0, + (Stmt::Semi(self0, _), Stmt::Semi(other0, _)) => self0 == other0, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TraitBound {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TraitBound { + fn eq(&self, other: &Self) -> bool { + self.paren_token == other.paren_token + && self.modifier == other.modifier + && self.lifetimes == other.lifetimes + && self.path == other.path + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TraitBoundModifier {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TraitBoundModifier { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (TraitBoundModifier::None, TraitBoundModifier::None) => true, + (TraitBoundModifier::Maybe(_), TraitBoundModifier::Maybe(_)) => true, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for TraitItem {} +#[cfg(feature = "full")] +impl PartialEq for TraitItem { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (TraitItem::Const(self0), TraitItem::Const(other0)) => self0 == other0, + (TraitItem::Method(self0), TraitItem::Method(other0)) => self0 == other0, + (TraitItem::Type(self0), TraitItem::Type(other0)) => self0 == other0, + (TraitItem::Macro(self0), TraitItem::Macro(other0)) => self0 == other0, + (TraitItem::Verbatim(self0), TraitItem::Verbatim(other0)) => { + TokenStreamHelper(self0) == TokenStreamHelper(other0) + } + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for TraitItemConst {} +#[cfg(feature = "full")] +impl PartialEq for TraitItemConst { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.ident == other.ident + && self.ty == other.ty + && self.default == other.default + } +} +#[cfg(feature = "full")] +impl Eq for TraitItemMacro {} +#[cfg(feature = "full")] +impl PartialEq for TraitItemMacro { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs && self.mac == other.mac && self.semi_token == other.semi_token + } +} +#[cfg(feature = "full")] +impl Eq for TraitItemMethod {} +#[cfg(feature = "full")] +impl PartialEq for TraitItemMethod { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.sig == other.sig + && self.default == other.default + && self.semi_token == other.semi_token + } +} +#[cfg(feature = "full")] +impl Eq for TraitItemType {} +#[cfg(feature = "full")] +impl PartialEq for TraitItemType { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.ident == other.ident + && self.generics == other.generics + && self.colon_token == other.colon_token + && self.bounds == other.bounds + && self.default == other.default + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Type {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Type { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Type::Array(self0), Type::Array(other0)) => self0 == other0, + (Type::BareFn(self0), Type::BareFn(other0)) => self0 == other0, + (Type::Group(self0), Type::Group(other0)) => self0 == other0, + (Type::ImplTrait(self0), Type::ImplTrait(other0)) => self0 == other0, + (Type::Infer(self0), Type::Infer(other0)) => self0 == other0, + (Type::Macro(self0), Type::Macro(other0)) => self0 == other0, + (Type::Never(self0), Type::Never(other0)) => self0 == other0, + (Type::Paren(self0), Type::Paren(other0)) => self0 == other0, + (Type::Path(self0), Type::Path(other0)) => self0 == other0, + (Type::Ptr(self0), Type::Ptr(other0)) => self0 == other0, + (Type::Reference(self0), Type::Reference(other0)) => self0 == other0, + (Type::Slice(self0), Type::Slice(other0)) => self0 == other0, + (Type::TraitObject(self0), Type::TraitObject(other0)) => self0 == other0, + (Type::Tuple(self0), Type::Tuple(other0)) => self0 == other0, + (Type::Verbatim(self0), Type::Verbatim(other0)) => { + TokenStreamHelper(self0) == TokenStreamHelper(other0) + } + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeArray {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeArray { + fn eq(&self, other: &Self) -> bool { + self.elem == other.elem && self.len == other.len + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeBareFn {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeBareFn { + fn eq(&self, other: &Self) -> bool { + self.lifetimes == other.lifetimes + && self.unsafety == other.unsafety + && self.abi == other.abi + && self.inputs == other.inputs + && self.variadic == other.variadic + && self.output == other.output + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeGroup {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeGroup { + fn eq(&self, other: &Self) -> bool { + self.elem == other.elem + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeImplTrait {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeImplTrait { + fn eq(&self, other: &Self) -> bool { + self.bounds == other.bounds + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeInfer {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeInfer { + fn eq(&self, _other: &Self) -> bool { + true + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeMacro {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeMacro { + fn eq(&self, other: &Self) -> bool { + self.mac == other.mac + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeNever {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeNever { + fn eq(&self, _other: &Self) -> bool { + true + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeParam {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeParam { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.ident == other.ident + && self.colon_token == other.colon_token + && self.bounds == other.bounds + && self.eq_token == other.eq_token + && self.default == other.default + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeParamBound {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeParamBound { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (TypeParamBound::Trait(self0), TypeParamBound::Trait(other0)) => self0 == other0, + (TypeParamBound::Lifetime(self0), TypeParamBound::Lifetime(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeParen {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeParen { + fn eq(&self, other: &Self) -> bool { + self.elem == other.elem + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypePath {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypePath { + fn eq(&self, other: &Self) -> bool { + self.qself == other.qself && self.path == other.path + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypePtr {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypePtr { + fn eq(&self, other: &Self) -> bool { + self.const_token == other.const_token + && self.mutability == other.mutability + && self.elem == other.elem + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeReference {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeReference { + fn eq(&self, other: &Self) -> bool { + self.lifetime == other.lifetime + && self.mutability == other.mutability + && self.elem == other.elem + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeSlice {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeSlice { + fn eq(&self, other: &Self) -> bool { + self.elem == other.elem + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeTraitObject {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeTraitObject { + fn eq(&self, other: &Self) -> bool { + self.dyn_token == other.dyn_token && self.bounds == other.bounds + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for TypeTuple {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for TypeTuple { + fn eq(&self, other: &Self) -> bool { + self.elems == other.elems + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for UnOp {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for UnOp { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (UnOp::Deref(_), UnOp::Deref(_)) => true, + (UnOp::Not(_), UnOp::Not(_)) => true, + (UnOp::Neg(_), UnOp::Neg(_)) => true, + _ => false, + } + } +} +#[cfg(feature = "full")] +impl Eq for UseGlob {} +#[cfg(feature = "full")] +impl PartialEq for UseGlob { + fn eq(&self, _other: &Self) -> bool { + true + } +} +#[cfg(feature = "full")] +impl Eq for UseGroup {} +#[cfg(feature = "full")] +impl PartialEq for UseGroup { + fn eq(&self, other: &Self) -> bool { + self.items == other.items + } +} +#[cfg(feature = "full")] +impl Eq for UseName {} +#[cfg(feature = "full")] +impl PartialEq for UseName { + fn eq(&self, other: &Self) -> bool { + self.ident == other.ident + } +} +#[cfg(feature = "full")] +impl Eq for UsePath {} +#[cfg(feature = "full")] +impl PartialEq for UsePath { + fn eq(&self, other: &Self) -> bool { + self.ident == other.ident && self.tree == other.tree + } +} +#[cfg(feature = "full")] +impl Eq for UseRename {} +#[cfg(feature = "full")] +impl PartialEq for UseRename { + fn eq(&self, other: &Self) -> bool { + self.ident == other.ident && self.rename == other.rename + } +} +#[cfg(feature = "full")] +impl Eq for UseTree {} +#[cfg(feature = "full")] +impl PartialEq for UseTree { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (UseTree::Path(self0), UseTree::Path(other0)) => self0 == other0, + (UseTree::Name(self0), UseTree::Name(other0)) => self0 == other0, + (UseTree::Rename(self0), UseTree::Rename(other0)) => self0 == other0, + (UseTree::Glob(self0), UseTree::Glob(other0)) => self0 == other0, + (UseTree::Group(self0), UseTree::Group(other0)) => self0 == other0, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Variadic {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Variadic { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Variant {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Variant { + fn eq(&self, other: &Self) -> bool { + self.attrs == other.attrs + && self.ident == other.ident + && self.fields == other.fields + && self.discriminant == other.discriminant + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for VisCrate {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for VisCrate { + fn eq(&self, _other: &Self) -> bool { + true + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for VisPublic {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for VisPublic { + fn eq(&self, _other: &Self) -> bool { + true + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for VisRestricted {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for VisRestricted { + fn eq(&self, other: &Self) -> bool { + self.in_token == other.in_token && self.path == other.path + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for Visibility {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for Visibility { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (Visibility::Public(self0), Visibility::Public(other0)) => self0 == other0, + (Visibility::Crate(self0), Visibility::Crate(other0)) => self0 == other0, + (Visibility::Restricted(self0), Visibility::Restricted(other0)) => self0 == other0, + (Visibility::Inherited, Visibility::Inherited) => true, + _ => false, + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for WhereClause {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for WhereClause { + fn eq(&self, other: &Self) -> bool { + self.predicates == other.predicates + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Eq for WherePredicate {} +#[cfg(any(feature = "derive", feature = "full"))] +impl PartialEq for WherePredicate { + fn eq(&self, other: &Self) -> bool { + match (self, other) { + (WherePredicate::Type(self0), WherePredicate::Type(other0)) => self0 == other0, + (WherePredicate::Lifetime(self0), WherePredicate::Lifetime(other0)) => self0 == other0, + (WherePredicate::Eq(self0), WherePredicate::Eq(other0)) => self0 == other0, + _ => false, + } + } +} diff --git a/vendor/syn/src/gen/fold.rs b/vendor/syn/src/gen/fold.rs index ec1bcfda15..d9dd32a420 100644 --- a/vendor/syn/src/gen/fold.rs +++ b/vendor/syn/src/gen/fold.rs @@ -792,10 +792,10 @@ where F: Fold + ?Sized, { AngleBracketedGenericArguments { - colon2_token: (node.colon2_token).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))), - lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + colon2_token: (node.colon2_token).map(|it| Token ! [::](tokens_helper(f, &it.spans))), + lt_token: Token ! [<](tokens_helper(f, &node.lt_token.spans)), args: FoldHelper::lift(node.args, |it| f.fold_generic_argument(it)), - gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + gt_token: Token ! [>](tokens_helper(f, &node.gt_token.spans)), } } #[cfg(feature = "full")] @@ -812,9 +812,9 @@ where Box::new(f.fold_expr(*(it).1)), ) }), - fat_arrow_token: Token ! [ => ](tokens_helper(f, &node.fat_arrow_token.spans)), + fat_arrow_token: Token ! [=>](tokens_helper(f, &node.fat_arrow_token.spans)), body: Box::new(f.fold_expr(*node.body)), - comma: (node.comma).map(|it| Token ! [ , ](tokens_helper(f, &it.spans))), + comma: (node.comma).map(|it| Token ! [,](tokens_helper(f, &it.spans))), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -835,7 +835,7 @@ where F: Fold + ?Sized, { Attribute { - pound_token: Token ! [ # ](tokens_helper(f, &node.pound_token.spans)), + pound_token: Token ! [#](tokens_helper(f, &node.pound_token.spans)), style: f.fold_attr_style(node.style), bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), path: f.fold_path(node.path), @@ -852,7 +852,7 @@ where name: (node.name).map(|it| { ( f.fold_ident((it).0), - Token ! [ : ](tokens_helper(f, &(it).1.spans)), + Token ! [:](tokens_helper(f, &(it).1.spans)), ) }), ty: f.fold_type(node.ty), @@ -864,59 +864,47 @@ where F: Fold + ?Sized, { match node { - BinOp::Add(_binding_0) => BinOp::Add(Token ! [ + ](tokens_helper(f, &_binding_0.spans))), - BinOp::Sub(_binding_0) => BinOp::Sub(Token ! [ - ](tokens_helper(f, &_binding_0.spans))), - BinOp::Mul(_binding_0) => BinOp::Mul(Token ! [ * ](tokens_helper(f, &_binding_0.spans))), - BinOp::Div(_binding_0) => BinOp::Div(Token ! [ / ](tokens_helper(f, &_binding_0.spans))), - BinOp::Rem(_binding_0) => BinOp::Rem(Token ! [ % ](tokens_helper(f, &_binding_0.spans))), - BinOp::And(_binding_0) => BinOp::And(Token ! [ && ](tokens_helper(f, &_binding_0.spans))), - BinOp::Or(_binding_0) => BinOp::Or(Token ! [ || ](tokens_helper(f, &_binding_0.spans))), + BinOp::Add(_binding_0) => BinOp::Add(Token ! [+](tokens_helper(f, &_binding_0.spans))), + BinOp::Sub(_binding_0) => BinOp::Sub(Token ! [-](tokens_helper(f, &_binding_0.spans))), + BinOp::Mul(_binding_0) => BinOp::Mul(Token ! [*](tokens_helper(f, &_binding_0.spans))), + BinOp::Div(_binding_0) => BinOp::Div(Token ! [/](tokens_helper(f, &_binding_0.spans))), + BinOp::Rem(_binding_0) => BinOp::Rem(Token ! [%](tokens_helper(f, &_binding_0.spans))), + BinOp::And(_binding_0) => BinOp::And(Token ! [&&](tokens_helper(f, &_binding_0.spans))), + BinOp::Or(_binding_0) => BinOp::Or(Token ! [||](tokens_helper(f, &_binding_0.spans))), BinOp::BitXor(_binding_0) => { - BinOp::BitXor(Token ! [ ^ ](tokens_helper(f, &_binding_0.spans))) + BinOp::BitXor(Token ! [^](tokens_helper(f, &_binding_0.spans))) } BinOp::BitAnd(_binding_0) => { - BinOp::BitAnd(Token ! [ & ](tokens_helper(f, &_binding_0.spans))) - } - BinOp::BitOr(_binding_0) => { - BinOp::BitOr(Token ! [ | ](tokens_helper(f, &_binding_0.spans))) - } - BinOp::Shl(_binding_0) => BinOp::Shl(Token ! [ << ](tokens_helper(f, &_binding_0.spans))), - BinOp::Shr(_binding_0) => BinOp::Shr(Token ! [ >> ](tokens_helper(f, &_binding_0.spans))), - BinOp::Eq(_binding_0) => BinOp::Eq(Token ! [ == ](tokens_helper(f, &_binding_0.spans))), - BinOp::Lt(_binding_0) => BinOp::Lt(Token ! [ < ](tokens_helper(f, &_binding_0.spans))), - BinOp::Le(_binding_0) => BinOp::Le(Token ! [ <= ](tokens_helper(f, &_binding_0.spans))), - BinOp::Ne(_binding_0) => BinOp::Ne(Token ! [ != ](tokens_helper(f, &_binding_0.spans))), - BinOp::Ge(_binding_0) => BinOp::Ge(Token ! [ >= ](tokens_helper(f, &_binding_0.spans))), - BinOp::Gt(_binding_0) => BinOp::Gt(Token ! [ > ](tokens_helper(f, &_binding_0.spans))), - BinOp::AddEq(_binding_0) => { - BinOp::AddEq(Token ! [ += ](tokens_helper(f, &_binding_0.spans))) - } - BinOp::SubEq(_binding_0) => { - BinOp::SubEq(Token ! [ -= ](tokens_helper(f, &_binding_0.spans))) - } - BinOp::MulEq(_binding_0) => { - BinOp::MulEq(Token ! [ *= ](tokens_helper(f, &_binding_0.spans))) - } - BinOp::DivEq(_binding_0) => { - BinOp::DivEq(Token ! [ /= ](tokens_helper(f, &_binding_0.spans))) - } - BinOp::RemEq(_binding_0) => { - BinOp::RemEq(Token ! [ %= ](tokens_helper(f, &_binding_0.spans))) + BinOp::BitAnd(Token ! [&](tokens_helper(f, &_binding_0.spans))) } + BinOp::BitOr(_binding_0) => BinOp::BitOr(Token ! [|](tokens_helper(f, &_binding_0.spans))), + BinOp::Shl(_binding_0) => BinOp::Shl(Token ! [<<](tokens_helper(f, &_binding_0.spans))), + BinOp::Shr(_binding_0) => BinOp::Shr(Token ! [>>](tokens_helper(f, &_binding_0.spans))), + BinOp::Eq(_binding_0) => BinOp::Eq(Token ! [==](tokens_helper(f, &_binding_0.spans))), + BinOp::Lt(_binding_0) => BinOp::Lt(Token ! [<](tokens_helper(f, &_binding_0.spans))), + BinOp::Le(_binding_0) => BinOp::Le(Token ! [<=](tokens_helper(f, &_binding_0.spans))), + BinOp::Ne(_binding_0) => BinOp::Ne(Token ! [!=](tokens_helper(f, &_binding_0.spans))), + BinOp::Ge(_binding_0) => BinOp::Ge(Token ! [>=](tokens_helper(f, &_binding_0.spans))), + BinOp::Gt(_binding_0) => BinOp::Gt(Token ! [>](tokens_helper(f, &_binding_0.spans))), + BinOp::AddEq(_binding_0) => BinOp::AddEq(Token ! [+=](tokens_helper(f, &_binding_0.spans))), + BinOp::SubEq(_binding_0) => BinOp::SubEq(Token ! [-=](tokens_helper(f, &_binding_0.spans))), + BinOp::MulEq(_binding_0) => BinOp::MulEq(Token ! [*=](tokens_helper(f, &_binding_0.spans))), + BinOp::DivEq(_binding_0) => BinOp::DivEq(Token ! [/=](tokens_helper(f, &_binding_0.spans))), + BinOp::RemEq(_binding_0) => BinOp::RemEq(Token ! [%=](tokens_helper(f, &_binding_0.spans))), BinOp::BitXorEq(_binding_0) => { - BinOp::BitXorEq(Token ! [ ^= ](tokens_helper(f, &_binding_0.spans))) + BinOp::BitXorEq(Token ! [^=](tokens_helper(f, &_binding_0.spans))) } BinOp::BitAndEq(_binding_0) => { - BinOp::BitAndEq(Token ! [ &= ](tokens_helper(f, &_binding_0.spans))) + BinOp::BitAndEq(Token ! [&=](tokens_helper(f, &_binding_0.spans))) } BinOp::BitOrEq(_binding_0) => { - BinOp::BitOrEq(Token ! [ |= ](tokens_helper(f, &_binding_0.spans))) + BinOp::BitOrEq(Token ! [|=](tokens_helper(f, &_binding_0.spans))) } BinOp::ShlEq(_binding_0) => { - BinOp::ShlEq(Token ! [ <<= ](tokens_helper(f, &_binding_0.spans))) + BinOp::ShlEq(Token ! [<<=](tokens_helper(f, &_binding_0.spans))) } BinOp::ShrEq(_binding_0) => { - BinOp::ShrEq(Token ! [ >>= ](tokens_helper(f, &_binding_0.spans))) + BinOp::ShrEq(Token ! [>>=](tokens_helper(f, &_binding_0.spans))) } } } @@ -927,7 +915,7 @@ where { Binding { ident: f.fold_ident(node.ident), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), ty: f.fold_type(node.ty), } } @@ -948,9 +936,9 @@ where { BoundLifetimes { for_token: Token![for](tokens_helper(f, &node.for_token.span)), - lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + lt_token: Token ! [<](tokens_helper(f, &node.lt_token.spans)), lifetimes: FoldHelper::lift(node.lifetimes, |it| f.fold_lifetime_def(it)), - gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + gt_token: Token ! [>](tokens_helper(f, &node.gt_token.spans)), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -962,9 +950,9 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), const_token: Token![const](tokens_helper(f, &node.const_token.span)), ident: f.fold_ident(node.ident), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: f.fold_type(node.ty), - eq_token: (node.eq_token).map(|it| Token ! [ = ](tokens_helper(f, &it.spans))), + eq_token: (node.eq_token).map(|it| Token ! [=](tokens_helper(f, &it.spans))), default: (node.default).map(|it| f.fold_expr(it)), } } @@ -975,7 +963,7 @@ where { Constraint { ident: f.fold_ident(node.ident), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), } } @@ -1009,7 +997,7 @@ where DataStruct { struct_token: Token![struct](tokens_helper(f, &node.struct_token.span)), fields: f.fold_fields(node.fields), - semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi_token: (node.semi_token).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "derive")] @@ -1105,7 +1093,7 @@ where ExprAssign { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), left: Box::new(f.fold_expr(*node.left)), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), right: Box::new(f.fold_expr(*node.right)), } } @@ -1141,7 +1129,7 @@ where ExprAwait { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), base: Box::new(f.fold_expr(*node.base)), - dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)), + dot_token: Token ! [.](tokens_helper(f, &node.dot_token.spans)), await_token: crate::token::Await(tokens_helper(f, &node.await_token.span)), } } @@ -1225,9 +1213,9 @@ where asyncness: (node.asyncness).map(|it| Token![async](tokens_helper(f, &it.span))), movability: (node.movability).map(|it| Token![static](tokens_helper(f, &it.span))), capture: (node.capture).map(|it| Token![move](tokens_helper(f, &it.span))), - or1_token: Token ! [ | ](tokens_helper(f, &node.or1_token.spans)), + or1_token: Token ! [|](tokens_helper(f, &node.or1_token.spans)), inputs: FoldHelper::lift(node.inputs, |it| f.fold_pat(it)), - or2_token: Token ! [ | ](tokens_helper(f, &node.or2_token.spans)), + or2_token: Token ! [|](tokens_helper(f, &node.or2_token.spans)), output: f.fold_return_type(node.output), body: Box::new(f.fold_expr(*node.body)), } @@ -1251,7 +1239,7 @@ where ExprField { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), base: Box::new(f.fold_expr(*node.base)), - dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)), + dot_token: Token ! [.](tokens_helper(f, &node.dot_token.spans)), member: f.fold_member(node.member), } } @@ -1320,7 +1308,7 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), let_token: Token![let](tokens_helper(f, &node.let_token.span)), pat: f.fold_pat(node.pat), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), expr: Box::new(f.fold_expr(*node.expr)), } } @@ -1377,7 +1365,7 @@ where ExprMethodCall { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), receiver: Box::new(f.fold_expr(*node.receiver)), - dot_token: Token ! [ . ](tokens_helper(f, &node.dot_token.spans)), + dot_token: Token ! [.](tokens_helper(f, &node.dot_token.spans)), method: f.fold_ident(node.method), turbofish: (node.turbofish).map(|it| f.fold_method_turbofish(it)), paren_token: Paren(tokens_helper(f, &node.paren_token.span)), @@ -1425,7 +1413,7 @@ where { ExprReference { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), - and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)), + and_token: Token ! [&](tokens_helper(f, &node.and_token.spans)), raw: node.raw, mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), expr: Box::new(f.fold_expr(*node.expr)), @@ -1440,7 +1428,7 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), expr: Box::new(f.fold_expr(*node.expr)), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), len: Box::new(f.fold_expr(*node.len)), } } @@ -1477,7 +1465,7 @@ where ExprTry { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), expr: Box::new(f.fold_expr(*node.expr)), - question_token: Token ! [ ? ](tokens_helper(f, &node.question_token.spans)), + question_token: Token ! [?](tokens_helper(f, &node.question_token.spans)), } } #[cfg(feature = "full")] @@ -1510,7 +1498,7 @@ where ExprType { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), expr: Box::new(f.fold_expr(*node.expr)), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: Box::new(f.fold_type(*node.ty)), } } @@ -1569,7 +1557,7 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), vis: f.fold_visibility(node.vis), ident: (node.ident).map(|it| f.fold_ident(it)), - colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + colon_token: (node.colon_token).map(|it| Token ! [:](tokens_helper(f, &it.spans))), ty: f.fold_type(node.ty), } } @@ -1581,7 +1569,7 @@ where FieldPat { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), member: f.fold_member(node.member), - colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + colon_token: (node.colon_token).map(|it| Token ! [:](tokens_helper(f, &it.spans))), pat: Box::new(f.fold_pat(*node.pat)), } } @@ -1593,7 +1581,7 @@ where FieldValue { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), member: f.fold_member(node.member), - colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + colon_token: (node.colon_token).map(|it| Token ! [:](tokens_helper(f, &it.spans))), expr: f.fold_expr(node.expr), } } @@ -1674,7 +1662,7 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), vis: f.fold_visibility(node.vis), sig: f.fold_signature(node.sig), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -1685,7 +1673,7 @@ where ForeignItemMacro { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), mac: f.fold_macro(node.mac), - semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi_token: (node.semi_token).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "full")] @@ -1699,9 +1687,9 @@ where static_token: Token![static](tokens_helper(f, &node.static_token.span)), mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), ident: f.fold_ident(node.ident), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: Box::new(f.fold_type(*node.ty)), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -1714,7 +1702,7 @@ where vis: f.fold_visibility(node.vis), type_token: Token![type](tokens_helper(f, &node.type_token.span)), ident: f.fold_ident(node.ident), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -1772,9 +1760,9 @@ where F: Fold + ?Sized, { Generics { - lt_token: (node.lt_token).map(|it| Token ! [ < ](tokens_helper(f, &it.spans))), + lt_token: (node.lt_token).map(|it| Token ! [<](tokens_helper(f, &it.spans))), params: FoldHelper::lift(node.params, |it| f.fold_generic_param(it)), - gt_token: (node.gt_token).map(|it| Token ! [ > ](tokens_helper(f, &it.spans))), + gt_token: (node.gt_token).map(|it| Token ! [>](tokens_helper(f, &it.spans))), where_clause: (node.where_clause).map(|it| f.fold_where_clause(it)), } } @@ -1812,11 +1800,11 @@ where defaultness: (node.defaultness).map(|it| Token![default](tokens_helper(f, &it.span))), const_token: Token![const](tokens_helper(f, &node.const_token.span)), ident: f.fold_ident(node.ident), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: f.fold_type(node.ty), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), expr: f.fold_expr(node.expr), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -1827,7 +1815,7 @@ where ImplItemMacro { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), mac: f.fold_macro(node.mac), - semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi_token: (node.semi_token).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "full")] @@ -1855,9 +1843,9 @@ where type_token: Token![type](tokens_helper(f, &node.type_token.span)), ident: f.fold_ident(node.ident), generics: f.fold_generics(node.generics), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), ty: f.fold_type(node.ty), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -1906,11 +1894,11 @@ where vis: f.fold_visibility(node.vis), const_token: Token![const](tokens_helper(f, &node.const_token.span)), ident: f.fold_ident(node.ident), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: Box::new(f.fold_type(*node.ty)), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), expr: Box::new(f.fold_expr(*node.expr)), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -1945,7 +1933,7 @@ where f.fold_ident((it).1), ) }), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -2004,7 +1992,7 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), ident: (node.ident).map(|it| f.fold_ident(it)), mac: f.fold_macro(node.mac), - semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi_token: (node.semi_token).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "full")] @@ -2036,7 +2024,7 @@ where FoldHelper::lift((it).1, |it| f.fold_item(it)), ) }), - semi: (node.semi).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi: (node.semi).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "full")] @@ -2050,11 +2038,11 @@ where static_token: Token![static](tokens_helper(f, &node.static_token.span)), mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), ident: f.fold_ident(node.ident), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: Box::new(f.fold_type(*node.ty)), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), expr: Box::new(f.fold_expr(*node.expr)), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -2069,7 +2057,7 @@ where ident: f.fold_ident(node.ident), generics: f.fold_generics(node.generics), fields: f.fold_fields(node.fields), - semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi_token: (node.semi_token).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "full")] @@ -2085,7 +2073,7 @@ where trait_token: Token![trait](tokens_helper(f, &node.trait_token.span)), ident: f.fold_ident(node.ident), generics: f.fold_generics(node.generics), - colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + colon_token: (node.colon_token).map(|it| Token ! [:](tokens_helper(f, &it.spans))), supertraits: FoldHelper::lift(node.supertraits, |it| f.fold_type_param_bound(it)), brace_token: Brace(tokens_helper(f, &node.brace_token.span)), items: FoldHelper::lift(node.items, |it| f.fold_trait_item(it)), @@ -2102,9 +2090,9 @@ where trait_token: Token![trait](tokens_helper(f, &node.trait_token.span)), ident: f.fold_ident(node.ident), generics: f.fold_generics(node.generics), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -2118,9 +2106,9 @@ where type_token: Token![type](tokens_helper(f, &node.type_token.span)), ident: f.fold_ident(node.ident), generics: f.fold_generics(node.generics), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), ty: Box::new(f.fold_type(*node.ty)), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -2146,9 +2134,9 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), vis: f.fold_visibility(node.vis), use_token: Token![use](tokens_helper(f, &node.use_token.span)), - leading_colon: (node.leading_colon).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))), + leading_colon: (node.leading_colon).map(|it| Token ! [::](tokens_helper(f, &it.spans))), tree: f.fold_use_tree(node.tree), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -2158,7 +2146,7 @@ where { Label { name: f.fold_lifetime(node.name), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), } } pub fn fold_lifetime(f: &mut F, node: Lifetime) -> Lifetime @@ -2178,7 +2166,7 @@ where LifetimeDef { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), lifetime: f.fold_lifetime(node.lifetime), - colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + colon_token: (node.colon_token).map(|it| Token ! [:](tokens_helper(f, &it.spans))), bounds: FoldHelper::lift(node.bounds, |it| f.fold_lifetime(it)), } } @@ -2271,11 +2259,11 @@ where pat: f.fold_pat(node.pat), init: (node.init).map(|it| { ( - Token ! [ = ](tokens_helper(f, &(it).0.spans)), + Token ! [=](tokens_helper(f, &(it).0.spans)), Box::new(f.fold_expr(*(it).1)), ) }), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -2346,7 +2334,7 @@ where { MetaNameValue { path: f.fold_path(node.path), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), lit: f.fold_lit(node.lit), } } @@ -2356,10 +2344,10 @@ where F: Fold + ?Sized, { MethodTurbofish { - colon2_token: Token ! [ :: ](tokens_helper(f, &node.colon2_token.spans)), - lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + colon2_token: Token ! [::](tokens_helper(f, &node.colon2_token.spans)), + lt_token: Token ! [<](tokens_helper(f, &node.lt_token.spans)), args: FoldHelper::lift(node.args, |it| f.fold_generic_method_argument(it)), - gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + gt_token: Token ! [>](tokens_helper(f, &node.gt_token.spans)), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -2434,7 +2422,7 @@ where ident: f.fold_ident(node.ident), subpat: (node.subpat).map(|it| { ( - Token ! [ @ ](tokens_helper(f, &(it).0.spans)), + Token ! [@](tokens_helper(f, &(it).0.spans)), Box::new(f.fold_pat(*(it).1)), ) }), @@ -2467,7 +2455,7 @@ where { PatOr { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), - leading_vert: (node.leading_vert).map(|it| Token ! [ | ](tokens_helper(f, &it.spans))), + leading_vert: (node.leading_vert).map(|it| Token ! [|](tokens_helper(f, &it.spans))), cases: FoldHelper::lift(node.cases, |it| f.fold_pat(it)), } } @@ -2501,7 +2489,7 @@ where { PatReference { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), - and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)), + and_token: Token ! [&](tokens_helper(f, &node.and_token.spans)), mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), pat: Box::new(f.fold_pat(*node.pat)), } @@ -2570,7 +2558,7 @@ where PatType { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), pat: Box::new(f.fold_pat(*node.pat)), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: Box::new(f.fold_type(*node.ty)), } } @@ -2590,7 +2578,7 @@ where F: Fold + ?Sized, { Path { - leading_colon: (node.leading_colon).map(|it| Token ! [ :: ](tokens_helper(f, &it.spans))), + leading_colon: (node.leading_colon).map(|it| Token ! [::](tokens_helper(f, &it.spans))), segments: FoldHelper::lift(node.segments, |it| f.fold_path_segment(it)), } } @@ -2626,7 +2614,7 @@ where { PredicateEq { lhs_ty: f.fold_type(node.lhs_ty), - eq_token: Token ! [ = ](tokens_helper(f, &node.eq_token.spans)), + eq_token: Token ! [=](tokens_helper(f, &node.eq_token.spans)), rhs_ty: f.fold_type(node.rhs_ty), } } @@ -2637,7 +2625,7 @@ where { PredicateLifetime { lifetime: f.fold_lifetime(node.lifetime), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), bounds: FoldHelper::lift(node.bounds, |it| f.fold_lifetime(it)), } } @@ -2649,7 +2637,7 @@ where PredicateType { lifetimes: (node.lifetimes).map(|it| f.fold_bound_lifetimes(it)), bounded_ty: f.fold_type(node.bounded_ty), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), } } @@ -2659,11 +2647,11 @@ where F: Fold + ?Sized, { QSelf { - lt_token: Token ! [ < ](tokens_helper(f, &node.lt_token.spans)), + lt_token: Token ! [<](tokens_helper(f, &node.lt_token.spans)), ty: Box::new(f.fold_type(*node.ty)), position: node.position, as_token: (node.as_token).map(|it| Token![as](tokens_helper(f, &it.span))), - gt_token: Token ! [ > ](tokens_helper(f, &node.gt_token.spans)), + gt_token: Token ! [>](tokens_helper(f, &node.gt_token.spans)), } } #[cfg(feature = "full")] @@ -2676,7 +2664,7 @@ where RangeLimits::HalfOpen(Token![..](tokens_helper(f, &_binding_0.spans))) } RangeLimits::Closed(_binding_0) => { - RangeLimits::Closed(Token ! [ ..= ](tokens_helper(f, &_binding_0.spans))) + RangeLimits::Closed(Token ! [..=](tokens_helper(f, &_binding_0.spans))) } } } @@ -2689,7 +2677,7 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), reference: (node.reference).map(|it| { ( - Token ! [ & ](tokens_helper(f, &(it).0.spans)), + Token ! [&](tokens_helper(f, &(it).0.spans)), ((it).1).map(|it| f.fold_lifetime(it)), ) }), @@ -2705,7 +2693,7 @@ where match node { ReturnType::Default => ReturnType::Default, ReturnType::Type(_binding_0, _binding_1) => ReturnType::Type( - Token ! [ -> ](tokens_helper(f, &_binding_0.spans)), + Token ! [->](tokens_helper(f, &_binding_0.spans)), Box::new(f.fold_type(*_binding_1)), ), } @@ -2746,7 +2734,7 @@ where Stmt::Expr(_binding_0) => Stmt::Expr(f.fold_expr(_binding_0)), Stmt::Semi(_binding_0, _binding_1) => Stmt::Semi( f.fold_expr(_binding_0), - Token ! [ ; ](tokens_helper(f, &_binding_1.spans)), + Token ! [;](tokens_helper(f, &_binding_1.spans)), ), } } @@ -2770,7 +2758,7 @@ where match node { TraitBoundModifier::None => TraitBoundModifier::None, TraitBoundModifier::Maybe(_binding_0) => { - TraitBoundModifier::Maybe(Token ! [ ? ](tokens_helper(f, &_binding_0.spans))) + TraitBoundModifier::Maybe(Token ! [?](tokens_helper(f, &_binding_0.spans))) } } } @@ -2797,15 +2785,15 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), const_token: Token![const](tokens_helper(f, &node.const_token.span)), ident: f.fold_ident(node.ident), - colon_token: Token ! [ : ](tokens_helper(f, &node.colon_token.spans)), + colon_token: Token ! [:](tokens_helper(f, &node.colon_token.spans)), ty: f.fold_type(node.ty), default: (node.default).map(|it| { ( - Token ! [ = ](tokens_helper(f, &(it).0.spans)), + Token ! [=](tokens_helper(f, &(it).0.spans)), f.fold_expr((it).1), ) }), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(feature = "full")] @@ -2816,7 +2804,7 @@ where TraitItemMacro { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), mac: f.fold_macro(node.mac), - semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi_token: (node.semi_token).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "full")] @@ -2828,7 +2816,7 @@ where attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), sig: f.fold_signature(node.sig), default: (node.default).map(|it| f.fold_block(it)), - semi_token: (node.semi_token).map(|it| Token ! [ ; ](tokens_helper(f, &it.spans))), + semi_token: (node.semi_token).map(|it| Token ! [;](tokens_helper(f, &it.spans))), } } #[cfg(feature = "full")] @@ -2841,15 +2829,15 @@ where type_token: Token![type](tokens_helper(f, &node.type_token.span)), ident: f.fold_ident(node.ident), generics: f.fold_generics(node.generics), - colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + colon_token: (node.colon_token).map(|it| Token ! [:](tokens_helper(f, &it.spans))), bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), default: (node.default).map(|it| { ( - Token ! [ = ](tokens_helper(f, &(it).0.spans)), + Token ! [=](tokens_helper(f, &(it).0.spans)), f.fold_type((it).1), ) }), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -2884,7 +2872,7 @@ where TypeArray { bracket_token: Bracket(tokens_helper(f, &node.bracket_token.span)), elem: Box::new(f.fold_type(*node.elem)), - semi_token: Token ! [ ; ](tokens_helper(f, &node.semi_token.spans)), + semi_token: Token ! [;](tokens_helper(f, &node.semi_token.spans)), len: f.fold_expr(node.len), } } @@ -2959,9 +2947,9 @@ where TypeParam { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), ident: f.fold_ident(node.ident), - colon_token: (node.colon_token).map(|it| Token ! [ : ](tokens_helper(f, &it.spans))), + colon_token: (node.colon_token).map(|it| Token ! [:](tokens_helper(f, &it.spans))), bounds: FoldHelper::lift(node.bounds, |it| f.fold_type_param_bound(it)), - eq_token: (node.eq_token).map(|it| Token ! [ = ](tokens_helper(f, &it.spans))), + eq_token: (node.eq_token).map(|it| Token ! [=](tokens_helper(f, &it.spans))), default: (node.default).map(|it| f.fold_type(it)), } } @@ -3003,7 +2991,7 @@ where F: Fold + ?Sized, { TypePtr { - star_token: Token ! [ * ](tokens_helper(f, &node.star_token.spans)), + star_token: Token ! [*](tokens_helper(f, &node.star_token.spans)), const_token: (node.const_token).map(|it| Token![const](tokens_helper(f, &it.span))), mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), elem: Box::new(f.fold_type(*node.elem)), @@ -3015,7 +3003,7 @@ where F: Fold + ?Sized, { TypeReference { - and_token: Token ! [ & ](tokens_helper(f, &node.and_token.spans)), + and_token: Token ! [&](tokens_helper(f, &node.and_token.spans)), lifetime: (node.lifetime).map(|it| f.fold_lifetime(it)), mutability: (node.mutability).map(|it| Token![mut](tokens_helper(f, &it.span))), elem: Box::new(f.fold_type(*node.elem)), @@ -3057,9 +3045,9 @@ where F: Fold + ?Sized, { match node { - UnOp::Deref(_binding_0) => UnOp::Deref(Token ! [ * ](tokens_helper(f, &_binding_0.spans))), + UnOp::Deref(_binding_0) => UnOp::Deref(Token ! [*](tokens_helper(f, &_binding_0.spans))), UnOp::Not(_binding_0) => UnOp::Not(Token![!](tokens_helper(f, &_binding_0.spans))), - UnOp::Neg(_binding_0) => UnOp::Neg(Token ! [ - ](tokens_helper(f, &_binding_0.spans))), + UnOp::Neg(_binding_0) => UnOp::Neg(Token ! [-](tokens_helper(f, &_binding_0.spans))), } } #[cfg(feature = "full")] @@ -3068,7 +3056,7 @@ where F: Fold + ?Sized, { UseGlob { - star_token: Token ! [ * ](tokens_helper(f, &node.star_token.spans)), + star_token: Token ! [*](tokens_helper(f, &node.star_token.spans)), } } #[cfg(feature = "full")] @@ -3097,7 +3085,7 @@ where { UsePath { ident: f.fold_ident(node.ident), - colon2_token: Token ! [ :: ](tokens_helper(f, &node.colon2_token.spans)), + colon2_token: Token ! [::](tokens_helper(f, &node.colon2_token.spans)), tree: Box::new(f.fold_use_tree(*node.tree)), } } @@ -3132,7 +3120,7 @@ where { Variadic { attrs: FoldHelper::lift(node.attrs, |it| f.fold_attribute(it)), - dots: Token ! [ ... ](tokens_helper(f, &node.dots.spans)), + dots: Token ! [...](tokens_helper(f, &node.dots.spans)), } } #[cfg(any(feature = "derive", feature = "full"))] @@ -3146,7 +3134,7 @@ where fields: f.fold_fields(node.fields), discriminant: (node.discriminant).map(|it| { ( - Token ! [ = ](tokens_helper(f, &(it).0.spans)), + Token ! [=](tokens_helper(f, &(it).0.spans)), f.fold_expr((it).1), ) }), diff --git a/vendor/syn/src/gen/hash.rs b/vendor/syn/src/gen/hash.rs new file mode 100644 index 0000000000..9e9e84a7af --- /dev/null +++ b/vendor/syn/src/gen/hash.rs @@ -0,0 +1,2691 @@ +// This file is @generated by syn-internal-codegen. +// It is not intended for manual editing. + +#[cfg(any(feature = "derive", feature = "full"))] +use crate::tt::TokenStreamHelper; +use crate::*; +use std::hash::{Hash, Hasher}; +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Abi { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.name.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for AngleBracketedGenericArguments { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.colon2_token.hash(state); + self.args.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for Arm { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.pat.hash(state); + self.guard.hash(state); + self.body.hash(state); + self.comma.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for AttrStyle { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + AttrStyle::Outer => { + state.write_u8(0u8); + } + AttrStyle::Inner(_) => { + state.write_u8(1u8); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Attribute { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.style.hash(state); + self.path.hash(state); + TokenStreamHelper(&self.tokens).hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for BareFnArg { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.name.hash(state); + self.ty.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for BinOp { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + BinOp::Add(_) => { + state.write_u8(0u8); + } + BinOp::Sub(_) => { + state.write_u8(1u8); + } + BinOp::Mul(_) => { + state.write_u8(2u8); + } + BinOp::Div(_) => { + state.write_u8(3u8); + } + BinOp::Rem(_) => { + state.write_u8(4u8); + } + BinOp::And(_) => { + state.write_u8(5u8); + } + BinOp::Or(_) => { + state.write_u8(6u8); + } + BinOp::BitXor(_) => { + state.write_u8(7u8); + } + BinOp::BitAnd(_) => { + state.write_u8(8u8); + } + BinOp::BitOr(_) => { + state.write_u8(9u8); + } + BinOp::Shl(_) => { + state.write_u8(10u8); + } + BinOp::Shr(_) => { + state.write_u8(11u8); + } + BinOp::Eq(_) => { + state.write_u8(12u8); + } + BinOp::Lt(_) => { + state.write_u8(13u8); + } + BinOp::Le(_) => { + state.write_u8(14u8); + } + BinOp::Ne(_) => { + state.write_u8(15u8); + } + BinOp::Ge(_) => { + state.write_u8(16u8); + } + BinOp::Gt(_) => { + state.write_u8(17u8); + } + BinOp::AddEq(_) => { + state.write_u8(18u8); + } + BinOp::SubEq(_) => { + state.write_u8(19u8); + } + BinOp::MulEq(_) => { + state.write_u8(20u8); + } + BinOp::DivEq(_) => { + state.write_u8(21u8); + } + BinOp::RemEq(_) => { + state.write_u8(22u8); + } + BinOp::BitXorEq(_) => { + state.write_u8(23u8); + } + BinOp::BitAndEq(_) => { + state.write_u8(24u8); + } + BinOp::BitOrEq(_) => { + state.write_u8(25u8); + } + BinOp::ShlEq(_) => { + state.write_u8(26u8); + } + BinOp::ShrEq(_) => { + state.write_u8(27u8); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Binding { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.ident.hash(state); + self.ty.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for Block { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.stmts.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for BoundLifetimes { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.lifetimes.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ConstParam { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.ident.hash(state); + self.ty.hash(state); + self.eq_token.hash(state); + self.default.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Constraint { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.ident.hash(state); + self.bounds.hash(state); + } +} +#[cfg(feature = "derive")] +impl Hash for Data { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Data::Struct(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Data::Enum(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Data::Union(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + } + } +} +#[cfg(feature = "derive")] +impl Hash for DataEnum { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.variants.hash(state); + } +} +#[cfg(feature = "derive")] +impl Hash for DataStruct { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.fields.hash(state); + self.semi_token.hash(state); + } +} +#[cfg(feature = "derive")] +impl Hash for DataUnion { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.fields.hash(state); + } +} +#[cfg(feature = "derive")] +impl Hash for DeriveInput { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.data.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Expr { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + #[cfg(feature = "full")] + Expr::Array(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Assign(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::AssignOp(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Async(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Await(v0) => { + state.write_u8(4u8); + v0.hash(state); + } + Expr::Binary(v0) => { + state.write_u8(5u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Block(v0) => { + state.write_u8(6u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Box(v0) => { + state.write_u8(7u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Break(v0) => { + state.write_u8(8u8); + v0.hash(state); + } + Expr::Call(v0) => { + state.write_u8(9u8); + v0.hash(state); + } + Expr::Cast(v0) => { + state.write_u8(10u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Closure(v0) => { + state.write_u8(11u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Continue(v0) => { + state.write_u8(12u8); + v0.hash(state); + } + Expr::Field(v0) => { + state.write_u8(13u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::ForLoop(v0) => { + state.write_u8(14u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Group(v0) => { + state.write_u8(15u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::If(v0) => { + state.write_u8(16u8); + v0.hash(state); + } + Expr::Index(v0) => { + state.write_u8(17u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Let(v0) => { + state.write_u8(18u8); + v0.hash(state); + } + Expr::Lit(v0) => { + state.write_u8(19u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Loop(v0) => { + state.write_u8(20u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Macro(v0) => { + state.write_u8(21u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Match(v0) => { + state.write_u8(22u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::MethodCall(v0) => { + state.write_u8(23u8); + v0.hash(state); + } + Expr::Paren(v0) => { + state.write_u8(24u8); + v0.hash(state); + } + Expr::Path(v0) => { + state.write_u8(25u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Range(v0) => { + state.write_u8(26u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Reference(v0) => { + state.write_u8(27u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Repeat(v0) => { + state.write_u8(28u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Return(v0) => { + state.write_u8(29u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Struct(v0) => { + state.write_u8(30u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Try(v0) => { + state.write_u8(31u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::TryBlock(v0) => { + state.write_u8(32u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Tuple(v0) => { + state.write_u8(33u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Type(v0) => { + state.write_u8(34u8); + v0.hash(state); + } + Expr::Unary(v0) => { + state.write_u8(35u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Unsafe(v0) => { + state.write_u8(36u8); + v0.hash(state); + } + Expr::Verbatim(v0) => { + state.write_u8(37u8); + TokenStreamHelper(v0).hash(state); + } + #[cfg(feature = "full")] + Expr::While(v0) => { + state.write_u8(38u8); + v0.hash(state); + } + #[cfg(feature = "full")] + Expr::Yield(v0) => { + state.write_u8(39u8); + v0.hash(state); + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Hash for ExprArray { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.elems.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprAssign { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.left.hash(state); + self.right.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprAssignOp { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.left.hash(state); + self.op.hash(state); + self.right.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprAsync { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.capture.hash(state); + self.block.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprAwait { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.base.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprBinary { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.left.hash(state); + self.op.hash(state); + self.right.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprBlock { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.label.hash(state); + self.block.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprBox { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprBreak { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.label.hash(state); + self.expr.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprCall { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.func.hash(state); + self.args.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprCast { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + self.ty.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprClosure { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.asyncness.hash(state); + self.movability.hash(state); + self.capture.hash(state); + self.inputs.hash(state); + self.output.hash(state); + self.body.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprContinue { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.label.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprField { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.base.hash(state); + self.member.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprForLoop { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.label.hash(state); + self.pat.hash(state); + self.expr.hash(state); + self.body.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprGroup { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprIf { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.cond.hash(state); + self.then_branch.hash(state); + self.else_branch.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprIndex { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + self.index.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprLet { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.pat.hash(state); + self.expr.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprLit { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.lit.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprLoop { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.label.hash(state); + self.body.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprMacro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.mac.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprMatch { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + self.arms.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprMethodCall { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.receiver.hash(state); + self.method.hash(state); + self.turbofish.hash(state); + self.args.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprParen { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprPath { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.qself.hash(state); + self.path.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprRange { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.from.hash(state); + self.limits.hash(state); + self.to.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprReference { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.mutability.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprRepeat { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + self.len.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprReturn { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprStruct { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.path.hash(state); + self.fields.hash(state); + self.dot2_token.hash(state); + self.rest.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprTry { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprTryBlock { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.block.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprTuple { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.elems.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + self.ty.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ExprUnary { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.op.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprUnsafe { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.block.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprWhile { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.label.hash(state); + self.cond.hash(state); + self.body.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ExprYield { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Field { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.colon_token.hash(state); + self.ty.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for FieldPat { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.member.hash(state); + self.colon_token.hash(state); + self.pat.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for FieldValue { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.member.hash(state); + self.colon_token.hash(state); + self.expr.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Fields { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Fields::Named(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Fields::Unnamed(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Fields::Unit => { + state.write_u8(2u8); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for FieldsNamed { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.named.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for FieldsUnnamed { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.unnamed.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for File { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.shebang.hash(state); + self.attrs.hash(state); + self.items.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for FnArg { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + FnArg::Receiver(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + FnArg::Typed(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + } + } +} +#[cfg(feature = "full")] +impl Hash for ForeignItem { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + ForeignItem::Fn(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + ForeignItem::Static(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + ForeignItem::Type(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + ForeignItem::Macro(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + ForeignItem::Verbatim(v0) => { + state.write_u8(4u8); + TokenStreamHelper(v0).hash(state); + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Hash for ForeignItemFn { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.sig.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ForeignItemMacro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.mac.hash(state); + self.semi_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ForeignItemStatic { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.mutability.hash(state); + self.ident.hash(state); + self.ty.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ForeignItemType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for GenericArgument { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + GenericArgument::Lifetime(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + GenericArgument::Type(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + GenericArgument::Binding(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + GenericArgument::Constraint(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + GenericArgument::Const(v0) => { + state.write_u8(4u8); + v0.hash(state); + } + } + } +} +#[cfg(feature = "full")] +impl Hash for GenericMethodArgument { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + GenericMethodArgument::Type(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + GenericMethodArgument::Const(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for GenericParam { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + GenericParam::Type(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + GenericParam::Lifetime(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + GenericParam::Const(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Generics { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.lt_token.hash(state); + self.params.hash(state); + self.gt_token.hash(state); + self.where_clause.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ImplItem { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + ImplItem::Const(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + ImplItem::Method(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + ImplItem::Type(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + ImplItem::Macro(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + ImplItem::Verbatim(v0) => { + state.write_u8(4u8); + TokenStreamHelper(v0).hash(state); + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Hash for ImplItemConst { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.defaultness.hash(state); + self.ident.hash(state); + self.ty.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ImplItemMacro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.mac.hash(state); + self.semi_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ImplItemMethod { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.defaultness.hash(state); + self.sig.hash(state); + self.block.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ImplItemType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.defaultness.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.ty.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for Item { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Item::Const(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Item::Enum(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Item::ExternCrate(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + Item::Fn(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + Item::ForeignMod(v0) => { + state.write_u8(4u8); + v0.hash(state); + } + Item::Impl(v0) => { + state.write_u8(5u8); + v0.hash(state); + } + Item::Macro(v0) => { + state.write_u8(6u8); + v0.hash(state); + } + Item::Macro2(v0) => { + state.write_u8(7u8); + v0.hash(state); + } + Item::Mod(v0) => { + state.write_u8(8u8); + v0.hash(state); + } + Item::Static(v0) => { + state.write_u8(9u8); + v0.hash(state); + } + Item::Struct(v0) => { + state.write_u8(10u8); + v0.hash(state); + } + Item::Trait(v0) => { + state.write_u8(11u8); + v0.hash(state); + } + Item::TraitAlias(v0) => { + state.write_u8(12u8); + v0.hash(state); + } + Item::Type(v0) => { + state.write_u8(13u8); + v0.hash(state); + } + Item::Union(v0) => { + state.write_u8(14u8); + v0.hash(state); + } + Item::Use(v0) => { + state.write_u8(15u8); + v0.hash(state); + } + Item::Verbatim(v0) => { + state.write_u8(16u8); + TokenStreamHelper(v0).hash(state); + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Hash for ItemConst { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.ty.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemEnum { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.variants.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemExternCrate { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.rename.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemFn { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.sig.hash(state); + self.block.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemForeignMod { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.abi.hash(state); + self.items.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemImpl { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.defaultness.hash(state); + self.unsafety.hash(state); + self.generics.hash(state); + self.trait_.hash(state); + self.self_ty.hash(state); + self.items.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemMacro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.ident.hash(state); + self.mac.hash(state); + self.semi_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemMacro2 { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + TokenStreamHelper(&self.rules).hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemMod { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.content.hash(state); + self.semi.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemStatic { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.mutability.hash(state); + self.ident.hash(state); + self.ty.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemStruct { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.fields.hash(state); + self.semi_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemTrait { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.unsafety.hash(state); + self.auto_token.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.colon_token.hash(state); + self.supertraits.hash(state); + self.items.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemTraitAlias { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.bounds.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.ty.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemUnion { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.fields.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for ItemUse { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.vis.hash(state); + self.leading_colon.hash(state); + self.tree.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for Label { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.name.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for LifetimeDef { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.lifetime.hash(state); + self.colon_token.hash(state); + self.bounds.hash(state); + } +} +impl Hash for Lit { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Lit::Str(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Lit::ByteStr(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Lit::Byte(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + Lit::Char(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + Lit::Int(v0) => { + state.write_u8(4u8); + v0.hash(state); + } + Lit::Float(v0) => { + state.write_u8(5u8); + v0.hash(state); + } + Lit::Bool(v0) => { + state.write_u8(6u8); + v0.hash(state); + } + Lit::Verbatim(v0) => { + state.write_u8(7u8); + v0.to_string().hash(state); + } + } + } +} +impl Hash for LitBool { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.value.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for Local { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.pat.hash(state); + self.init.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Macro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.path.hash(state); + self.delimiter.hash(state); + TokenStreamHelper(&self.tokens).hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for MacroDelimiter { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + MacroDelimiter::Paren(_) => { + state.write_u8(0u8); + } + MacroDelimiter::Brace(_) => { + state.write_u8(1u8); + } + MacroDelimiter::Bracket(_) => { + state.write_u8(2u8); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Meta { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Meta::Path(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Meta::List(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Meta::NameValue(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for MetaList { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.path.hash(state); + self.nested.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for MetaNameValue { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.path.hash(state); + self.lit.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for MethodTurbofish { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.args.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for NestedMeta { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + NestedMeta::Meta(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + NestedMeta::Lit(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ParenthesizedGenericArguments { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.inputs.hash(state); + self.output.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for Pat { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Pat::Box(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Pat::Ident(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Pat::Lit(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + Pat::Macro(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + Pat::Or(v0) => { + state.write_u8(4u8); + v0.hash(state); + } + Pat::Path(v0) => { + state.write_u8(5u8); + v0.hash(state); + } + Pat::Range(v0) => { + state.write_u8(6u8); + v0.hash(state); + } + Pat::Reference(v0) => { + state.write_u8(7u8); + v0.hash(state); + } + Pat::Rest(v0) => { + state.write_u8(8u8); + v0.hash(state); + } + Pat::Slice(v0) => { + state.write_u8(9u8); + v0.hash(state); + } + Pat::Struct(v0) => { + state.write_u8(10u8); + v0.hash(state); + } + Pat::Tuple(v0) => { + state.write_u8(11u8); + v0.hash(state); + } + Pat::TupleStruct(v0) => { + state.write_u8(12u8); + v0.hash(state); + } + Pat::Type(v0) => { + state.write_u8(13u8); + v0.hash(state); + } + Pat::Verbatim(v0) => { + state.write_u8(14u8); + TokenStreamHelper(v0).hash(state); + } + Pat::Wild(v0) => { + state.write_u8(15u8); + v0.hash(state); + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Hash for PatBox { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.pat.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatIdent { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.by_ref.hash(state); + self.mutability.hash(state); + self.ident.hash(state); + self.subpat.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatLit { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.expr.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatMacro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.mac.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatOr { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.leading_vert.hash(state); + self.cases.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatPath { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.qself.hash(state); + self.path.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatRange { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.lo.hash(state); + self.limits.hash(state); + self.hi.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatReference { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.mutability.hash(state); + self.pat.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatRest { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatSlice { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.elems.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatStruct { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.path.hash(state); + self.fields.hash(state); + self.dot2_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatTuple { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.elems.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatTupleStruct { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.path.hash(state); + self.pat.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.pat.hash(state); + self.ty.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for PatWild { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Path { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.leading_colon.hash(state); + self.segments.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for PathArguments { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + PathArguments::None => { + state.write_u8(0u8); + } + PathArguments::AngleBracketed(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + PathArguments::Parenthesized(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for PathSegment { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.ident.hash(state); + self.arguments.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for PredicateEq { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.lhs_ty.hash(state); + self.rhs_ty.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for PredicateLifetime { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.lifetime.hash(state); + self.bounds.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for PredicateType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.lifetimes.hash(state); + self.bounded_ty.hash(state); + self.bounds.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for QSelf { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.ty.hash(state); + self.position.hash(state); + self.as_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for RangeLimits { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + RangeLimits::HalfOpen(_) => { + state.write_u8(0u8); + } + RangeLimits::Closed(_) => { + state.write_u8(1u8); + } + } + } +} +#[cfg(feature = "full")] +impl Hash for Receiver { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.reference.hash(state); + self.mutability.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for ReturnType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + ReturnType::Default => { + state.write_u8(0u8); + } + ReturnType::Type(_, v1) => { + state.write_u8(1u8); + v1.hash(state); + } + } + } +} +#[cfg(feature = "full")] +impl Hash for Signature { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.constness.hash(state); + self.asyncness.hash(state); + self.unsafety.hash(state); + self.abi.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.inputs.hash(state); + self.variadic.hash(state); + self.output.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for Stmt { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Stmt::Local(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Stmt::Item(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Stmt::Expr(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + Stmt::Semi(v0, _) => { + state.write_u8(3u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TraitBound { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.paren_token.hash(state); + self.modifier.hash(state); + self.lifetimes.hash(state); + self.path.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TraitBoundModifier { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + TraitBoundModifier::None => { + state.write_u8(0u8); + } + TraitBoundModifier::Maybe(_) => { + state.write_u8(1u8); + } + } + } +} +#[cfg(feature = "full")] +impl Hash for TraitItem { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + TraitItem::Const(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + TraitItem::Method(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + TraitItem::Type(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + TraitItem::Macro(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + TraitItem::Verbatim(v0) => { + state.write_u8(4u8); + TokenStreamHelper(v0).hash(state); + } + _ => unreachable!(), + } + } +} +#[cfg(feature = "full")] +impl Hash for TraitItemConst { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.ident.hash(state); + self.ty.hash(state); + self.default.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for TraitItemMacro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.mac.hash(state); + self.semi_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for TraitItemMethod { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.sig.hash(state); + self.default.hash(state); + self.semi_token.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for TraitItemType { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.ident.hash(state); + self.generics.hash(state); + self.colon_token.hash(state); + self.bounds.hash(state); + self.default.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Type { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Type::Array(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Type::BareFn(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Type::Group(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + Type::ImplTrait(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + Type::Infer(v0) => { + state.write_u8(4u8); + v0.hash(state); + } + Type::Macro(v0) => { + state.write_u8(5u8); + v0.hash(state); + } + Type::Never(v0) => { + state.write_u8(6u8); + v0.hash(state); + } + Type::Paren(v0) => { + state.write_u8(7u8); + v0.hash(state); + } + Type::Path(v0) => { + state.write_u8(8u8); + v0.hash(state); + } + Type::Ptr(v0) => { + state.write_u8(9u8); + v0.hash(state); + } + Type::Reference(v0) => { + state.write_u8(10u8); + v0.hash(state); + } + Type::Slice(v0) => { + state.write_u8(11u8); + v0.hash(state); + } + Type::TraitObject(v0) => { + state.write_u8(12u8); + v0.hash(state); + } + Type::Tuple(v0) => { + state.write_u8(13u8); + v0.hash(state); + } + Type::Verbatim(v0) => { + state.write_u8(14u8); + TokenStreamHelper(v0).hash(state); + } + _ => unreachable!(), + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeArray { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.elem.hash(state); + self.len.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeBareFn { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.lifetimes.hash(state); + self.unsafety.hash(state); + self.abi.hash(state); + self.inputs.hash(state); + self.variadic.hash(state); + self.output.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeGroup { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.elem.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeImplTrait { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.bounds.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeInfer { + fn hash(&self, _state: &mut H) + where + H: Hasher, + { + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeMacro { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.mac.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeNever { + fn hash(&self, _state: &mut H) + where + H: Hasher, + { + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeParam { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.ident.hash(state); + self.colon_token.hash(state); + self.bounds.hash(state); + self.eq_token.hash(state); + self.default.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeParamBound { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + TypeParamBound::Trait(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + TypeParamBound::Lifetime(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeParen { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.elem.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypePath { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.qself.hash(state); + self.path.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypePtr { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.const_token.hash(state); + self.mutability.hash(state); + self.elem.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeReference { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.lifetime.hash(state); + self.mutability.hash(state); + self.elem.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeSlice { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.elem.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeTraitObject { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.dyn_token.hash(state); + self.bounds.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for TypeTuple { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.elems.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for UnOp { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + UnOp::Deref(_) => { + state.write_u8(0u8); + } + UnOp::Not(_) => { + state.write_u8(1u8); + } + UnOp::Neg(_) => { + state.write_u8(2u8); + } + } + } +} +#[cfg(feature = "full")] +impl Hash for UseGlob { + fn hash(&self, _state: &mut H) + where + H: Hasher, + { + } +} +#[cfg(feature = "full")] +impl Hash for UseGroup { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.items.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for UseName { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.ident.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for UsePath { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.ident.hash(state); + self.tree.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for UseRename { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.ident.hash(state); + self.rename.hash(state); + } +} +#[cfg(feature = "full")] +impl Hash for UseTree { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + UseTree::Path(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + UseTree::Name(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + UseTree::Rename(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + UseTree::Glob(v0) => { + state.write_u8(3u8); + v0.hash(state); + } + UseTree::Group(v0) => { + state.write_u8(4u8); + v0.hash(state); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Variadic { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Variant { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.attrs.hash(state); + self.ident.hash(state); + self.fields.hash(state); + self.discriminant.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for VisCrate { + fn hash(&self, _state: &mut H) + where + H: Hasher, + { + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for VisPublic { + fn hash(&self, _state: &mut H) + where + H: Hasher, + { + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for VisRestricted { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.in_token.hash(state); + self.path.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for Visibility { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + Visibility::Public(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + Visibility::Crate(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + Visibility::Restricted(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + Visibility::Inherited => { + state.write_u8(3u8); + } + } + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for WhereClause { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + self.predicates.hash(state); + } +} +#[cfg(any(feature = "derive", feature = "full"))] +impl Hash for WherePredicate { + fn hash(&self, state: &mut H) + where + H: Hasher, + { + match self { + WherePredicate::Type(v0) => { + state.write_u8(0u8); + v0.hash(state); + } + WherePredicate::Lifetime(v0) => { + state.write_u8(1u8); + v0.hash(state); + } + WherePredicate::Eq(v0) => { + state.write_u8(2u8); + v0.hash(state); + } + } + } +} diff --git a/vendor/syn/src/generics.rs b/vendor/syn/src/generics.rs index d0015dbcba..05e8ef5cdf 100644 --- a/vendor/syn/src/generics.rs +++ b/vendor/syn/src/generics.rs @@ -1,5 +1,9 @@ use super::*; use crate::punctuated::{Iter, IterMut, Punctuated}; +#[cfg(all(feature = "printing", feature = "extra-traits"))] +use std::fmt::{self, Debug}; +#[cfg(all(feature = "printing", feature = "extra-traits"))] +use std::hash::{Hash, Hasher}; ast_struct! { /// Lifetimes and type parameters attached to a declaration of a function, @@ -7,7 +11,6 @@ ast_struct! { /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - #[derive(Default)] pub struct Generics { pub lt_token: Option, pub params: Punctuated, @@ -84,6 +87,17 @@ ast_struct! { } } +impl Default for Generics { + fn default() -> Self { + Generics { + lt_token: None, + params: Punctuated::new(), + gt_token: None, + where_clause: None, + } + } +} + impl Generics { /// Returns an /// Iterator for ConstParamsMut<'a> { /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature and the `"printing"` feature.* #[cfg(feature = "printing")] -#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] -#[cfg_attr(feature = "clone-impls", derive(Clone))] pub struct ImplGenerics<'a>(&'a Generics); /// Returned by `Generics::split_for_impl`. @@ -289,8 +301,6 @@ pub struct ImplGenerics<'a>(&'a Generics); /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature and the `"printing"` feature.* #[cfg(feature = "printing")] -#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] -#[cfg_attr(feature = "clone-impls", derive(Clone))] pub struct TypeGenerics<'a>(&'a Generics); /// Returned by `TypeGenerics::as_turbofish`. @@ -298,8 +308,6 @@ pub struct TypeGenerics<'a>(&'a Generics); /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature and the `"printing"` feature.* #[cfg(feature = "printing")] -#[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] -#[cfg_attr(feature = "clone-impls", derive(Clone))] pub struct Turbofish<'a>(&'a Generics); #[cfg(feature = "printing")] @@ -334,6 +342,52 @@ impl Generics { } } +#[cfg(feature = "printing")] +macro_rules! generics_wrapper_impls { + ($ty:ident) => { + #[cfg(feature = "clone-impls")] + impl<'a> Clone for $ty<'a> { + fn clone(&self) -> Self { + $ty(self.0) + } + } + + #[cfg(feature = "extra-traits")] + impl<'a> Debug for $ty<'a> { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter + .debug_tuple(stringify!($ty)) + .field(self.0) + .finish() + } + } + + #[cfg(feature = "extra-traits")] + impl<'a> Eq for $ty<'a> {} + + #[cfg(feature = "extra-traits")] + impl<'a> PartialEq for $ty<'a> { + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } + } + + #[cfg(feature = "extra-traits")] + impl<'a> Hash for $ty<'a> { + fn hash(&self, state: &mut H) { + self.0.hash(state); + } + } + }; +} + +#[cfg(feature = "printing")] +generics_wrapper_impls!(ImplGenerics); +#[cfg(feature = "printing")] +generics_wrapper_impls!(TypeGenerics); +#[cfg(feature = "printing")] +generics_wrapper_impls!(Turbofish); + #[cfg(feature = "printing")] impl<'a> TypeGenerics<'a> { /// Turn a type's generics like `` into a turbofish like `::`. @@ -350,7 +404,6 @@ ast_struct! { /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - #[derive(Default)] pub struct BoundLifetimes { pub for_token: Token![for], pub lt_token: Token![<], @@ -359,6 +412,17 @@ ast_struct! { } } +impl Default for BoundLifetimes { + fn default() -> Self { + BoundLifetimes { + for_token: Default::default(), + lt_token: Default::default(), + lifetimes: Punctuated::new(), + gt_token: Default::default(), + } + } +} + impl LifetimeDef { pub fn new(lifetime: Lifetime) -> Self { LifetimeDef { @@ -415,7 +479,6 @@ ast_enum! { /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - #[cfg_attr(feature = "clone-impls", derive(Copy))] pub enum TraitBoundModifier { None, Maybe(Token![?]), @@ -513,7 +576,6 @@ pub mod parsing { let mut params = Punctuated::new(); let mut allow_lifetime_param = true; - let mut allow_type_param = true; loop { if input.peek(Token![>]) { break; @@ -526,7 +588,7 @@ pub mod parsing { attrs, ..input.parse()? })); - } else if allow_type_param && lookahead.peek(Ident) { + } else if lookahead.peek(Ident) { allow_lifetime_param = false; params.push_value(GenericParam::Type(TypeParam { attrs, @@ -534,7 +596,6 @@ pub mod parsing { })); } else if lookahead.peek(Token![const]) { allow_lifetime_param = false; - allow_type_param = false; params.push_value(GenericParam::Const(ConstParam { attrs, ..input.parse()? @@ -1123,9 +1184,9 @@ mod printing { self.ident.to_tokens(tokens); self.colon_token.to_tokens(tokens); self.ty.to_tokens(tokens); - if self.default.is_some() { + if let Some(default) = &self.default { TokensOrDefault(&self.eq_token).to_tokens(tokens); - self.default.to_tokens(tokens); + default.to_tokens(tokens); } } } diff --git a/vendor/syn/src/item.rs b/vendor/syn/src/item.rs index 45e05a3da9..0d8f7d3ddc 100644 --- a/vendor/syn/src/item.rs +++ b/vendor/syn/src/item.rs @@ -3,10 +3,6 @@ use crate::derive::{Data, DataEnum, DataStruct, DataUnion, DeriveInput}; use crate::punctuated::Punctuated; use proc_macro2::TokenStream; -#[cfg(feature = "extra-traits")] -use crate::tt::TokenStreamHelper; -#[cfg(feature = "extra-traits")] -use std::hash::{Hash, Hasher}; #[cfg(feature = "parsing")] use std::mem; @@ -23,7 +19,7 @@ ast_enum_of_structs! { // // TODO: change syntax-tree-enum link to an intra rustdoc link, currently // blocked on https://github.com/rust-lang/rust/issues/62833 - pub enum Item #manual_extra_traits { + pub enum Item { /// A constant item: `const MAX: u16 = 65535`. Const(ItemConst), @@ -191,7 +187,7 @@ ast_struct! { /// A 2.0-style declarative macro introduced by the `macro` keyword. /// /// *This type is available only if Syn is built with the `"full"` feature.* - pub struct ItemMacro2 #manual_extra_traits { + pub struct ItemMacro2 { pub attrs: Vec, pub vis: Visibility, pub macro_token: Token![macro], @@ -326,117 +322,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for Item {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for Item { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Item::Const(this), Item::Const(other)) => this == other, - (Item::Enum(this), Item::Enum(other)) => this == other, - (Item::ExternCrate(this), Item::ExternCrate(other)) => this == other, - (Item::Fn(this), Item::Fn(other)) => this == other, - (Item::ForeignMod(this), Item::ForeignMod(other)) => this == other, - (Item::Impl(this), Item::Impl(other)) => this == other, - (Item::Macro(this), Item::Macro(other)) => this == other, - (Item::Macro2(this), Item::Macro2(other)) => this == other, - (Item::Mod(this), Item::Mod(other)) => this == other, - (Item::Static(this), Item::Static(other)) => this == other, - (Item::Struct(this), Item::Struct(other)) => this == other, - (Item::Trait(this), Item::Trait(other)) => this == other, - (Item::TraitAlias(this), Item::TraitAlias(other)) => this == other, - (Item::Type(this), Item::Type(other)) => this == other, - (Item::Union(this), Item::Union(other)) => this == other, - (Item::Use(this), Item::Use(other)) => this == other, - (Item::Verbatim(this), Item::Verbatim(other)) => { - TokenStreamHelper(this) == TokenStreamHelper(other) - } - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for Item { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - match self { - Item::Const(item) => { - state.write_u8(0); - item.hash(state); - } - Item::Enum(item) => { - state.write_u8(1); - item.hash(state); - } - Item::ExternCrate(item) => { - state.write_u8(2); - item.hash(state); - } - Item::Fn(item) => { - state.write_u8(3); - item.hash(state); - } - Item::ForeignMod(item) => { - state.write_u8(4); - item.hash(state); - } - Item::Impl(item) => { - state.write_u8(5); - item.hash(state); - } - Item::Macro(item) => { - state.write_u8(6); - item.hash(state); - } - Item::Macro2(item) => { - state.write_u8(7); - item.hash(state); - } - Item::Mod(item) => { - state.write_u8(8); - item.hash(state); - } - Item::Static(item) => { - state.write_u8(9); - item.hash(state); - } - Item::Struct(item) => { - state.write_u8(10); - item.hash(state); - } - Item::Trait(item) => { - state.write_u8(11); - item.hash(state); - } - Item::TraitAlias(item) => { - state.write_u8(12); - item.hash(state); - } - Item::Type(item) => { - state.write_u8(13); - item.hash(state); - } - Item::Union(item) => { - state.write_u8(14); - item.hash(state); - } - Item::Use(item) => { - state.write_u8(15); - item.hash(state); - } - Item::Verbatim(item) => { - state.write_u8(16); - TokenStreamHelper(item).hash(state); - } - Item::__Nonexhaustive => unreachable!(), - } - } -} - impl Item { #[cfg(feature = "parsing")] pub(crate) fn replace_attrs(&mut self, new: Vec) -> Vec { @@ -463,34 +348,6 @@ impl Item { } } -#[cfg(feature = "extra-traits")] -impl Eq for ItemMacro2 {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for ItemMacro2 { - fn eq(&self, other: &Self) -> bool { - self.attrs == other.attrs - && self.vis == other.vis - && self.macro_token == other.macro_token - && self.ident == other.ident - && TokenStreamHelper(&self.rules) == TokenStreamHelper(&other.rules) - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for ItemMacro2 { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - self.attrs.hash(state); - self.vis.hash(state); - self.macro_token.hash(state); - self.ident.hash(state); - TokenStreamHelper(&self.rules).hash(state); - } -} - impl From for Item { fn from(input: DeriveInput) -> Item { match input.data { @@ -665,7 +522,7 @@ ast_enum_of_structs! { // // TODO: change syntax-tree-enum link to an intra rustdoc link, currently // blocked on https://github.com/rust-lang/rust/issues/62833 - pub enum ForeignItem #manual_extra_traits { + pub enum ForeignItem { /// A foreign function in an `extern` block. Fn(ForeignItemFn), @@ -738,57 +595,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for ForeignItem {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for ForeignItem { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (ForeignItem::Fn(this), ForeignItem::Fn(other)) => this == other, - (ForeignItem::Static(this), ForeignItem::Static(other)) => this == other, - (ForeignItem::Type(this), ForeignItem::Type(other)) => this == other, - (ForeignItem::Macro(this), ForeignItem::Macro(other)) => this == other, - (ForeignItem::Verbatim(this), ForeignItem::Verbatim(other)) => { - TokenStreamHelper(this) == TokenStreamHelper(other) - } - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for ForeignItem { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - match self { - ForeignItem::Fn(item) => { - state.write_u8(0); - item.hash(state); - } - ForeignItem::Static(item) => { - state.write_u8(1); - item.hash(state); - } - ForeignItem::Type(item) => { - state.write_u8(2); - item.hash(state); - } - ForeignItem::Macro(item) => { - state.write_u8(3); - item.hash(state); - } - ForeignItem::Verbatim(item) => { - state.write_u8(4); - TokenStreamHelper(item).hash(state); - } - ForeignItem::__Nonexhaustive => unreachable!(), - } - } -} - ast_enum_of_structs! { /// An item declaration within the definition of a trait. /// @@ -802,7 +608,7 @@ ast_enum_of_structs! { // // TODO: change syntax-tree-enum link to an intra rustdoc link, currently // blocked on https://github.com/rust-lang/rust/issues/62833 - pub enum TraitItem #manual_extra_traits { + pub enum TraitItem { /// An associated constant within the definition of a trait. Const(TraitItemConst), @@ -877,57 +683,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for TraitItem {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for TraitItem { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (TraitItem::Const(this), TraitItem::Const(other)) => this == other, - (TraitItem::Method(this), TraitItem::Method(other)) => this == other, - (TraitItem::Type(this), TraitItem::Type(other)) => this == other, - (TraitItem::Macro(this), TraitItem::Macro(other)) => this == other, - (TraitItem::Verbatim(this), TraitItem::Verbatim(other)) => { - TokenStreamHelper(this) == TokenStreamHelper(other) - } - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for TraitItem { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - match self { - TraitItem::Const(item) => { - state.write_u8(0); - item.hash(state); - } - TraitItem::Method(item) => { - state.write_u8(1); - item.hash(state); - } - TraitItem::Type(item) => { - state.write_u8(2); - item.hash(state); - } - TraitItem::Macro(item) => { - state.write_u8(3); - item.hash(state); - } - TraitItem::Verbatim(item) => { - state.write_u8(4); - TokenStreamHelper(item).hash(state); - } - TraitItem::__Nonexhaustive => unreachable!(), - } - } -} - ast_enum_of_structs! { /// An item within an impl block. /// @@ -941,7 +696,7 @@ ast_enum_of_structs! { // // TODO: change syntax-tree-enum link to an intra rustdoc link, currently // blocked on https://github.com/rust-lang/rust/issues/62833 - pub enum ImplItem #manual_extra_traits { + pub enum ImplItem { /// An associated constant within an impl block. Const(ImplItemConst), @@ -1021,57 +776,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for ImplItem {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for ImplItem { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (ImplItem::Const(this), ImplItem::Const(other)) => this == other, - (ImplItem::Method(this), ImplItem::Method(other)) => this == other, - (ImplItem::Type(this), ImplItem::Type(other)) => this == other, - (ImplItem::Macro(this), ImplItem::Macro(other)) => this == other, - (ImplItem::Verbatim(this), ImplItem::Verbatim(other)) => { - TokenStreamHelper(this) == TokenStreamHelper(other) - } - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for ImplItem { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - match self { - ImplItem::Const(item) => { - state.write_u8(0); - item.hash(state); - } - ImplItem::Method(item) => { - state.write_u8(1); - item.hash(state); - } - ImplItem::Type(item) => { - state.write_u8(2); - item.hash(state); - } - ImplItem::Macro(item) => { - state.write_u8(3); - item.hash(state); - } - ImplItem::Verbatim(item) => { - state.write_u8(4); - TokenStreamHelper(item).hash(state); - } - ImplItem::__Nonexhaustive => unreachable!(), - } - } -} - ast_struct! { /// A function signature in a trait or implementation: `unsafe fn /// initialize(&self)`. diff --git a/vendor/syn/src/lib.rs b/vendor/syn/src/lib.rs index f715c7f69e..3da506731e 100644 --- a/vendor/syn/src/lib.rs +++ b/vendor/syn/src/lib.rs @@ -250,7 +250,7 @@ //! dynamic library libproc_macro from rustc toolchain. // Syn types in rustdoc of other crates get linked to here. -#![doc(html_root_url = "https://docs.rs/syn/1.0.38")] +#![doc(html_root_url = "https://docs.rs/syn/1.0.40")] #![deny(clippy::all, clippy::pedantic)] // Ignored clippy lints. #![allow( @@ -274,7 +274,9 @@ // Ignored clippy_pedantic lints. #![allow( clippy::cast_possible_truncation, + clippy::default_trait_access, clippy::empty_enum, + clippy::expl_impl_clone_on_copy, clippy::if_not_else, clippy::items_after_statements, clippy::match_same_arms, @@ -762,6 +764,22 @@ mod gen { #[rustfmt::skip] pub mod fold; + #[cfg(feature = "clone-impls")] + #[rustfmt::skip] + mod clone; + + #[cfg(feature = "extra-traits")] + #[rustfmt::skip] + mod eq; + + #[cfg(feature = "extra-traits")] + #[rustfmt::skip] + mod hash; + + #[cfg(feature = "extra-traits")] + #[rustfmt::skip] + mod debug; + #[cfg(any(feature = "full", feature = "derive"))] #[path = "../gen_helper.rs"] mod helper; @@ -784,6 +802,9 @@ mod lookahead; #[cfg(feature = "parsing")] pub mod parse; +#[cfg(feature = "full")] +mod reserved; + #[cfg(all(any(feature = "full", feature = "derive"), feature = "parsing"))] mod verbatim; diff --git a/vendor/syn/src/lifetime.rs b/vendor/syn/src/lifetime.rs index d34df34b81..959cc5f9c6 100644 --- a/vendor/syn/src/lifetime.rs +++ b/vendor/syn/src/lifetime.rs @@ -20,8 +20,6 @@ use crate::lookahead; /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* -#[cfg_attr(feature = "extra-traits", derive(Debug))] -#[derive(Clone)] pub struct Lifetime { pub apostrophe: Span, pub ident: Ident, @@ -72,6 +70,15 @@ impl Display for Lifetime { } } +impl Clone for Lifetime { + fn clone(&self) -> Self { + Lifetime { + apostrophe: self.apostrophe, + ident: self.ident.clone(), + } + } +} + impl PartialEq for Lifetime { fn eq(&self, other: &Lifetime) -> bool { self.ident.eq(&other.ident) diff --git a/vendor/syn/src/lit.rs b/vendor/syn/src/lit.rs index 692391d9b3..ee77e75bec 100644 --- a/vendor/syn/src/lit.rs +++ b/vendor/syn/src/lit.rs @@ -30,7 +30,7 @@ ast_enum_of_structs! { // // TODO: change syntax-tree-enum link to an intra rustdoc link, currently // blocked on https://github.com/rust-lang/rust/issues/62833 - pub enum Lit #manual_extra_traits { + pub enum Lit { /// A UTF-8 string literal: `"foo"`. Str(LitStr), @@ -61,33 +61,32 @@ ast_enum_of_structs! { ast_struct! { /// A UTF-8 string literal: `"foo"`. - pub struct LitStr #manual_extra_traits_debug { + pub struct LitStr { repr: Box, } } ast_struct! { /// A byte string literal: `b"foo"`. - pub struct LitByteStr #manual_extra_traits_debug { + pub struct LitByteStr { repr: Box, } } ast_struct! { /// A byte literal: `b'f'`. - pub struct LitByte #manual_extra_traits_debug { + pub struct LitByte { repr: Box, } } ast_struct! { /// A character literal: `'a'`. - pub struct LitChar #manual_extra_traits_debug { + pub struct LitChar { repr: Box, } } -#[cfg_attr(feature = "clone-impls", derive(Clone))] struct LitRepr { token: Literal, suffix: Box, @@ -95,12 +94,11 @@ struct LitRepr { ast_struct! { /// An integer literal: `1` or `1u16`. - pub struct LitInt #manual_extra_traits_debug { + pub struct LitInt { repr: Box, } } -#[cfg_attr(feature = "clone-impls", derive(Clone))] struct LitIntRepr { token: Literal, digits: Box, @@ -111,12 +109,11 @@ ast_struct! { /// A floating point literal: `1f64` or `1.0e10f64`. /// /// Must be finite. May not be infinte or NaN. - pub struct LitFloat #manual_extra_traits_debug { + pub struct LitFloat { repr: Box, } } -#[cfg_attr(feature = "clone-impls", derive(Clone))] struct LitFloatRepr { token: Literal, digits: Box, @@ -125,75 +122,12 @@ struct LitFloatRepr { ast_struct! { /// A boolean literal: `true` or `false`. - pub struct LitBool #manual_extra_traits_debug { + pub struct LitBool { pub value: bool, pub span: Span, } } -#[cfg(feature = "extra-traits")] -impl Eq for Lit {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for Lit { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Lit::Str(this), Lit::Str(other)) => this == other, - (Lit::ByteStr(this), Lit::ByteStr(other)) => this == other, - (Lit::Byte(this), Lit::Byte(other)) => this == other, - (Lit::Char(this), Lit::Char(other)) => this == other, - (Lit::Int(this), Lit::Int(other)) => this == other, - (Lit::Float(this), Lit::Float(other)) => this == other, - (Lit::Bool(this), Lit::Bool(other)) => this == other, - (Lit::Verbatim(this), Lit::Verbatim(other)) => this.to_string() == other.to_string(), - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for Lit { - fn hash(&self, hash: &mut H) - where - H: Hasher, - { - match self { - Lit::Str(lit) => { - hash.write_u8(0); - lit.hash(hash); - } - Lit::ByteStr(lit) => { - hash.write_u8(1); - lit.hash(hash); - } - Lit::Byte(lit) => { - hash.write_u8(2); - lit.hash(hash); - } - Lit::Char(lit) => { - hash.write_u8(3); - lit.hash(hash); - } - Lit::Int(lit) => { - hash.write_u8(4); - lit.hash(hash); - } - Lit::Float(lit) => { - hash.write_u8(5); - lit.hash(hash); - } - Lit::Bool(lit) => { - hash.write_u8(6); - lit.hash(hash); - } - Lit::Verbatim(lit) => { - hash.write_u8(7); - lit.to_string().hash(hash); - } - } - } -} - impl LitStr { pub fn new(value: &str, span: Span) -> Self { let mut token = Literal::string(value); @@ -646,15 +580,53 @@ mod debug_impls { } } +#[cfg(feature = "clone-impls")] +impl Clone for LitRepr { + fn clone(&self) -> Self { + LitRepr { + token: self.token.clone(), + suffix: self.suffix.clone(), + } + } +} + +#[cfg(feature = "clone-impls")] +impl Clone for LitIntRepr { + fn clone(&self) -> Self { + LitIntRepr { + token: self.token.clone(), + digits: self.digits.clone(), + suffix: self.suffix.clone(), + } + } +} + +#[cfg(feature = "clone-impls")] +impl Clone for LitFloatRepr { + fn clone(&self) -> Self { + LitFloatRepr { + token: self.token.clone(), + digits: self.digits.clone(), + suffix: self.suffix.clone(), + } + } +} + macro_rules! lit_extra_traits { - ($ty:ident, $($field:ident).+) => { - #[cfg(feature = "extra-traits")] - impl Eq for $ty {} + ($ty:ident) => { + #[cfg(feature = "clone-impls")] + impl Clone for $ty { + fn clone(&self) -> Self { + $ty { + repr: self.repr.clone(), + } + } + } #[cfg(feature = "extra-traits")] impl PartialEq for $ty { fn eq(&self, other: &Self) -> bool { - self.$($field).+.to_string() == other.$($field).+.to_string() + self.repr.token.to_string() == other.repr.token.to_string() } } @@ -664,7 +636,7 @@ macro_rules! lit_extra_traits { where H: Hasher, { - self.$($field).+.to_string().hash(state); + self.repr.token.to_string().hash(state); } } @@ -677,13 +649,19 @@ macro_rules! lit_extra_traits { }; } -lit_extra_traits!(LitStr, repr.token); -lit_extra_traits!(LitByteStr, repr.token); -lit_extra_traits!(LitByte, repr.token); -lit_extra_traits!(LitChar, repr.token); -lit_extra_traits!(LitInt, repr.token); -lit_extra_traits!(LitFloat, repr.token); -lit_extra_traits!(LitBool, value); +lit_extra_traits!(LitStr); +lit_extra_traits!(LitByteStr); +lit_extra_traits!(LitByte); +lit_extra_traits!(LitChar); +lit_extra_traits!(LitInt); +lit_extra_traits!(LitFloat); + +#[cfg(feature = "parsing")] +#[doc(hidden)] +#[allow(non_snake_case)] +pub fn LitBool(marker: lookahead::TokenMarker) -> LitBool { + match marker {} +} ast_enum! { /// The style of a string literal, either plain quoted or a raw string like @@ -1453,7 +1431,11 @@ mod value { } b'e' | b'E' => { if has_e { - return None; + if has_exponent { + break; + } else { + return None; + } } has_e = true; bytes[write] = b'e'; diff --git a/vendor/syn/src/mac.rs b/vendor/syn/src/mac.rs index 2d94c95181..de288a34e1 100644 --- a/vendor/syn/src/mac.rs +++ b/vendor/syn/src/mac.rs @@ -6,17 +6,13 @@ use proc_macro2::{Delimiter, Group, Span, TokenTree}; #[cfg(feature = "parsing")] use crate::parse::{Parse, ParseStream, Parser, Result}; -#[cfg(feature = "extra-traits")] -use crate::tt::TokenStreamHelper; -#[cfg(feature = "extra-traits")] -use std::hash::{Hash, Hasher}; ast_struct! { /// A macro invocation: `println!("{}", mac)`. /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - pub struct Macro #manual_extra_traits { + pub struct Macro { pub path: Path, pub bang_token: Token![!], pub delimiter: MacroDelimiter, @@ -36,32 +32,6 @@ ast_enum! { } } -#[cfg(feature = "extra-traits")] -impl Eq for Macro {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for Macro { - fn eq(&self, other: &Self) -> bool { - self.path == other.path - && self.bang_token == other.bang_token - && self.delimiter == other.delimiter - && TokenStreamHelper(&self.tokens) == TokenStreamHelper(&other.tokens) - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for Macro { - fn hash(&self, state: &mut H) - where - H: Hasher, - { - self.path.hash(state); - self.bang_token.hash(state); - self.delimiter.hash(state); - TokenStreamHelper(&self.tokens).hash(state); - } -} - #[cfg(feature = "parsing")] fn delimiter_span_close(macro_delimiter: &MacroDelimiter) -> Span { let delimiter = match macro_delimiter { diff --git a/vendor/syn/src/macros.rs b/vendor/syn/src/macros.rs index 57091c09f8..8060224381 100644 --- a/vendor/syn/src/macros.rs +++ b/vendor/syn/src/macros.rs @@ -4,15 +4,11 @@ macro_rules! ast_struct { struct $name:ident #full $($rest:tt)* ) => { #[cfg(feature = "full")] - #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] - #[cfg_attr(feature = "clone-impls", derive(Clone))] $($attrs_pub)* struct $name $($rest)* #[cfg(not(feature = "full"))] - #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] - #[cfg_attr(feature = "clone-impls", derive(Clone))] $($attrs_pub)* struct $name { - _noconstruct: (), + _noconstruct: ::std::marker::PhantomData<::proc_macro2::Span>, } #[cfg(all(not(feature = "full"), feature = "printing"))] @@ -23,29 +19,10 @@ macro_rules! ast_struct { } }; - ( - [$($attrs_pub:tt)*] - struct $name:ident #manual_extra_traits $($rest:tt)* - ) => { - #[cfg_attr(feature = "extra-traits", derive(Debug))] - #[cfg_attr(feature = "clone-impls", derive(Clone))] - $($attrs_pub)* struct $name $($rest)* - }; - - ( - [$($attrs_pub:tt)*] - struct $name:ident #manual_extra_traits_debug $($rest:tt)* - ) => { - #[cfg_attr(feature = "clone-impls", derive(Clone))] - $($attrs_pub)* struct $name $($rest)* - }; - ( [$($attrs_pub:tt)*] struct $name:ident $($rest:tt)* ) => { - #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] - #[cfg_attr(feature = "clone-impls", derive(Clone))] $($attrs_pub)* struct $name $($rest)* }; @@ -63,21 +40,10 @@ macro_rules! ast_enum { ast_enum!([$($attrs_pub)*] enum $name $($rest)*); ); - ( - [$($attrs_pub:tt)*] - enum $name:ident #manual_extra_traits $($rest:tt)* - ) => ( - #[cfg_attr(feature = "extra-traits", derive(Debug))] - #[cfg_attr(feature = "clone-impls", derive(Clone))] - $($attrs_pub)* enum $name $($rest)* - ); - ( [$($attrs_pub:tt)*] enum $name:ident $($rest:tt)* ) => ( - #[cfg_attr(feature = "extra-traits", derive(Debug, Eq, PartialEq, Hash))] - #[cfg_attr(feature = "clone-impls", derive(Clone))] $($attrs_pub)* enum $name $($rest)* ); diff --git a/vendor/syn/src/op.rs b/vendor/syn/src/op.rs index e0e7809f69..d254673b40 100644 --- a/vendor/syn/src/op.rs +++ b/vendor/syn/src/op.rs @@ -3,7 +3,6 @@ ast_enum! { /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - #[cfg_attr(feature = "clone-impls", derive(Copy))] pub enum BinOp { /// The `+` operator (addition) Add(Token![+]), @@ -69,7 +68,6 @@ ast_enum! { /// /// *This type is available only if Syn is built with the `"derive"` or `"full"` /// feature.* - #[cfg_attr(feature = "clone-impls", derive(Copy))] pub enum UnOp { /// The `*` operator for dereferencing Deref(Token![*]), diff --git a/vendor/syn/src/parse.rs b/vendor/syn/src/parse.rs index dffc2ad307..abb4c4c14f 100644 --- a/vendor/syn/src/parse.rs +++ b/vendor/syn/src/parse.rs @@ -336,7 +336,6 @@ impl<'a> Debug for ParseBuffer<'a> { /// # .unwrap(); /// # assert_eq!(remainder.to_string(), "b c"); /// ``` -#[derive(Copy, Clone)] pub struct StepCursor<'c, 'a> { scope: Span, // This field is covariant in 'c. @@ -360,6 +359,14 @@ impl<'c, 'a> Deref for StepCursor<'c, 'a> { } } +impl<'c, 'a> Copy for StepCursor<'c, 'a> {} + +impl<'c, 'a> Clone for StepCursor<'c, 'a> { + fn clone(&self) -> Self { + *self + } +} + impl<'c, 'a> StepCursor<'c, 'a> { /// Triggers an error at the current position of the parse stream. /// @@ -393,7 +400,6 @@ pub(crate) fn new_parse_buffer( } } -#[derive(Clone)] pub(crate) enum Unexpected { None, Some(Span), @@ -406,6 +412,16 @@ impl Default for Unexpected { } } +impl Clone for Unexpected { + fn clone(&self) -> Self { + match self { + Unexpected::None => Unexpected::None, + Unexpected::Some(span) => Unexpected::Some(*span), + Unexpected::Chain(next) => Unexpected::Chain(next.clone()), + } + } +} + // We call this on Cell and Cell> where temporarily // swapping in a None is cheap. fn cell_clone(cell: &Cell) -> T { diff --git a/vendor/syn/src/pat.rs b/vendor/syn/src/pat.rs index 68d58dc55b..e9576a2361 100644 --- a/vendor/syn/src/pat.rs +++ b/vendor/syn/src/pat.rs @@ -1,10 +1,6 @@ use super::*; use crate::punctuated::Punctuated; -#[cfg(feature = "extra-traits")] -use crate::tt::TokenStreamHelper; use proc_macro2::TokenStream; -#[cfg(feature = "extra-traits")] -use std::hash::{Hash, Hasher}; ast_enum_of_structs! { /// A pattern in a local binding, function signature, match expression, or @@ -20,7 +16,7 @@ ast_enum_of_structs! { // // TODO: change syntax-tree-enum link to an intra rustdoc link, currently // blocked on https://github.com/rust-lang/rust/issues/62833 - pub enum Pat #manual_extra_traits { + pub enum Pat { /// A box pattern: `box v`. Box(PatBox), @@ -278,112 +274,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for Pat {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for Pat { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Pat::Box(this), Pat::Box(other)) => this == other, - (Pat::Ident(this), Pat::Ident(other)) => this == other, - (Pat::Lit(this), Pat::Lit(other)) => this == other, - (Pat::Macro(this), Pat::Macro(other)) => this == other, - (Pat::Or(this), Pat::Or(other)) => this == other, - (Pat::Path(this), Pat::Path(other)) => this == other, - (Pat::Range(this), Pat::Range(other)) => this == other, - (Pat::Reference(this), Pat::Reference(other)) => this == other, - (Pat::Rest(this), Pat::Rest(other)) => this == other, - (Pat::Slice(this), Pat::Slice(other)) => this == other, - (Pat::Struct(this), Pat::Struct(other)) => this == other, - (Pat::Tuple(this), Pat::Tuple(other)) => this == other, - (Pat::TupleStruct(this), Pat::TupleStruct(other)) => this == other, - (Pat::Type(this), Pat::Type(other)) => this == other, - (Pat::Verbatim(this), Pat::Verbatim(other)) => { - TokenStreamHelper(this) == TokenStreamHelper(other) - } - (Pat::Wild(this), Pat::Wild(other)) => this == other, - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for Pat { - fn hash(&self, hash: &mut H) - where - H: Hasher, - { - match self { - Pat::Box(pat) => { - hash.write_u8(0); - pat.hash(hash); - } - Pat::Ident(pat) => { - hash.write_u8(1); - pat.hash(hash); - } - Pat::Lit(pat) => { - hash.write_u8(2); - pat.hash(hash); - } - Pat::Macro(pat) => { - hash.write_u8(3); - pat.hash(hash); - } - Pat::Or(pat) => { - hash.write_u8(4); - pat.hash(hash); - } - Pat::Path(pat) => { - hash.write_u8(5); - pat.hash(hash); - } - Pat::Range(pat) => { - hash.write_u8(6); - pat.hash(hash); - } - Pat::Reference(pat) => { - hash.write_u8(7); - pat.hash(hash); - } - Pat::Rest(pat) => { - hash.write_u8(8); - pat.hash(hash); - } - Pat::Slice(pat) => { - hash.write_u8(9); - pat.hash(hash); - } - Pat::Struct(pat) => { - hash.write_u8(10); - pat.hash(hash); - } - Pat::Tuple(pat) => { - hash.write_u8(11); - pat.hash(hash); - } - Pat::TupleStruct(pat) => { - hash.write_u8(12); - pat.hash(hash); - } - Pat::Type(pat) => { - hash.write_u8(13); - pat.hash(hash); - } - Pat::Verbatim(pat) => { - hash.write_u8(14); - TokenStreamHelper(pat).hash(hash); - } - Pat::Wild(pat) => { - hash.write_u8(15); - pat.hash(hash); - } - Pat::__Nonexhaustive => unreachable!(), - } - } -} - #[cfg(feature = "parsing")] pub mod parsing { use super::*; diff --git a/vendor/syn/src/punctuated.rs b/vendor/syn/src/punctuated.rs index cdd25c06a7..46c82a65b1 100644 --- a/vendor/syn/src/punctuated.rs +++ b/vendor/syn/src/punctuated.rs @@ -22,6 +22,8 @@ #[cfg(feature = "extra-traits")] use std::fmt::{self, Debug}; +#[cfg(feature = "extra-traits")] +use std::hash::{Hash, Hasher}; #[cfg(any(feature = "full", feature = "derive"))] use std::iter; use std::iter::FromIterator; @@ -41,8 +43,6 @@ use crate::token::Token; /// Refer to the [module documentation] for details about punctuated sequences. /// /// [module documentation]: self -#[cfg_attr(feature = "extra-traits", derive(Eq, PartialEq, Hash))] -#[cfg_attr(feature = "clone-impls", derive(Clone))] pub struct Punctuated { inner: Vec<(T, P)>, last: Option>, @@ -341,6 +341,53 @@ impl Punctuated { } } +#[cfg(feature = "clone-impls")] +impl Clone for Punctuated +where + T: Clone, + P: Clone, +{ + fn clone(&self) -> Self { + Punctuated { + inner: self.inner.clone(), + last: self.last.clone(), + } + } +} + +#[cfg(feature = "extra-traits")] +impl Eq for Punctuated +where + T: Eq, + P: Eq, +{ +} + +#[cfg(feature = "extra-traits")] +impl PartialEq for Punctuated +where + T: PartialEq, + P: PartialEq, +{ + fn eq(&self, other: &Self) -> bool { + let Punctuated { inner, last } = self; + *inner == other.inner && *last == other.last + } +} + +#[cfg(feature = "extra-traits")] +impl Hash for Punctuated +where + T: Hash, + P: Hash, +{ + fn hash(&self, state: &mut H) { + let Punctuated { inner, last } = self; + inner.hash(state); + last.hash(state); + } +} + #[cfg(feature = "extra-traits")] impl Debug for Punctuated { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -539,7 +586,6 @@ impl<'a, T, P> ExactSizeIterator for PairsMut<'a, T, P> { /// Refer to the [module documentation] for details about punctuated sequences. /// /// [module documentation]: self -#[derive(Clone)] pub struct IntoPairs { inner: vec::IntoIter<(T, P)>, last: option::IntoIter, @@ -575,12 +621,24 @@ impl ExactSizeIterator for IntoPairs { } } +impl Clone for IntoPairs +where + T: Clone, + P: Clone, +{ + fn clone(&self) -> Self { + IntoPairs { + inner: self.inner.clone(), + last: self.last.clone(), + } + } +} + /// An iterator over owned values of type `T`. /// /// Refer to the [module documentation] for details about punctuated sequences. /// /// [module documentation]: self -#[derive(Clone)] pub struct IntoIter { inner: vec::IntoIter, } @@ -609,6 +667,17 @@ impl ExactSizeIterator for IntoIter { } } +impl Clone for IntoIter +where + T: Clone, +{ + fn clone(&self) -> Self { + IntoIter { + inner: self.inner.clone(), + } + } +} + /// An iterator over borrowed values of type `&T`. /// /// Refer to the [module documentation] for details about punctuated sequences. @@ -802,7 +871,6 @@ impl<'a, T: 'a, I: 'a> IterMutTrait<'a, T> for I where /// Refer to the [module documentation] for details about punctuated sequences. /// /// [module documentation]: self -#[cfg_attr(feature = "clone-impls", derive(Clone))] pub enum Pair { Punctuated(T, P), End(T), @@ -859,6 +927,20 @@ impl Pair { } } +#[cfg(feature = "clone-impls")] +impl Clone for Pair +where + T: Clone, + P: Clone, +{ + fn clone(&self) -> Self { + match self { + Pair::Punctuated(t, p) => Pair::Punctuated(t.clone(), p.clone()), + Pair::End(t) => Pair::End(t.clone()), + } + } +} + impl Index for Punctuated { type Output = T; diff --git a/vendor/syn/src/reserved.rs b/vendor/syn/src/reserved.rs new file mode 100644 index 0000000000..ccfb8b5ad0 --- /dev/null +++ b/vendor/syn/src/reserved.rs @@ -0,0 +1,42 @@ +// Type for a syntax tree node that is reserved for future use. +// +// For example ExprReference contains a field `raw` of type Reserved. If `&raw +// place` syntax becomes a thing as per https://github.com/rust-lang/rfcs/pull/2582, +// we can backward compatibly change `raw`'s type to Option without +// the possibility of breaking any code. + +use proc_macro2::Span; +use std::marker::PhantomData; + +#[cfg(feature = "extra-traits")] +use std::fmt::{self, Debug}; + +ast_struct! { + pub struct Reserved { + _private: PhantomData, + } +} + +impl Default for Reserved { + fn default() -> Self { + Reserved { + _private: PhantomData, + } + } +} + +#[cfg(feature = "clone-impls")] +impl Clone for Reserved { + fn clone(&self) -> Self { + Reserved { + _private: self._private, + } + } +} + +#[cfg(feature = "extra-traits")] +impl Debug for Reserved { + fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { + formatter.debug_struct("Reserved").finish() + } +} diff --git a/vendor/syn/src/token.rs b/vendor/syn/src/token.rs index d23f126b48..8539378c5e 100644 --- a/vendor/syn/src/token.rs +++ b/vendor/syn/src/token.rs @@ -243,7 +243,6 @@ impl Token for T { macro_rules! define_keywords { ($($token:tt pub struct $name:ident #[$doc:meta])*) => { $( - #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))] #[$doc] /// /// Don't try to remember the name of this type — use the @@ -270,6 +269,16 @@ macro_rules! define_keywords { } } + #[cfg(feature = "clone-impls")] + impl Copy for $name {} + + #[cfg(feature = "clone-impls")] + impl Clone for $name { + fn clone(&self) -> Self { + *self + } + } + #[cfg(feature = "extra-traits")] impl Debug for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -348,7 +357,6 @@ macro_rules! impl_deref_if_len_is_1 { macro_rules! define_punctuation_structs { ($($token:tt pub struct $name:ident/$len:tt #[$doc:meta])*) => { $( - #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))] #[repr(C)] #[$doc] /// @@ -376,6 +384,16 @@ macro_rules! define_punctuation_structs { } } + #[cfg(feature = "clone-impls")] + impl Copy for $name {} + + #[cfg(feature = "clone-impls")] + impl Clone for $name { + fn clone(&self) -> Self { + *self + } + } + #[cfg(feature = "extra-traits")] impl Debug for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -446,7 +464,6 @@ macro_rules! define_punctuation { macro_rules! define_delimiters { ($($token:tt pub struct $name:ident #[$doc:meta])*) => { $( - #[cfg_attr(feature = "clone-impls", derive(Copy, Clone))] #[$doc] pub struct $name { pub span: Span, @@ -468,6 +485,16 @@ macro_rules! define_delimiters { } } + #[cfg(feature = "clone-impls")] + impl Copy for $name {} + + #[cfg(feature = "clone-impls")] + impl Clone for $name { + fn clone(&self) -> Self { + *self + } + } + #[cfg(feature = "extra-traits")] impl Debug for $name { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/vendor/syn/src/ty.rs b/vendor/syn/src/ty.rs index ed263e6707..fd7c97eab7 100644 --- a/vendor/syn/src/ty.rs +++ b/vendor/syn/src/ty.rs @@ -1,10 +1,6 @@ use super::*; use crate::punctuated::Punctuated; -#[cfg(feature = "extra-traits")] -use crate::tt::TokenStreamHelper; use proc_macro2::TokenStream; -#[cfg(feature = "extra-traits")] -use std::hash::{Hash, Hasher}; ast_enum_of_structs! { /// The possible types that a Rust value could have. @@ -20,7 +16,7 @@ ast_enum_of_structs! { // // TODO: change syntax-tree-enum link to an intra rustdoc link, currently // blocked on https://github.com/rust-lang/rust/issues/62833 - pub enum Type #manual_extra_traits { + pub enum Type { /// A fixed size array type: `[T; n]`. Array(TypeArray), @@ -240,107 +236,6 @@ ast_struct! { } } -#[cfg(feature = "extra-traits")] -impl Eq for Type {} - -#[cfg(feature = "extra-traits")] -impl PartialEq for Type { - fn eq(&self, other: &Self) -> bool { - match (self, other) { - (Type::Array(this), Type::Array(other)) => this == other, - (Type::BareFn(this), Type::BareFn(other)) => this == other, - (Type::Group(this), Type::Group(other)) => this == other, - (Type::ImplTrait(this), Type::ImplTrait(other)) => this == other, - (Type::Infer(this), Type::Infer(other)) => this == other, - (Type::Macro(this), Type::Macro(other)) => this == other, - (Type::Never(this), Type::Never(other)) => this == other, - (Type::Paren(this), Type::Paren(other)) => this == other, - (Type::Path(this), Type::Path(other)) => this == other, - (Type::Ptr(this), Type::Ptr(other)) => this == other, - (Type::Reference(this), Type::Reference(other)) => this == other, - (Type::Slice(this), Type::Slice(other)) => this == other, - (Type::TraitObject(this), Type::TraitObject(other)) => this == other, - (Type::Tuple(this), Type::Tuple(other)) => this == other, - (Type::Verbatim(this), Type::Verbatim(other)) => { - TokenStreamHelper(this) == TokenStreamHelper(other) - } - _ => false, - } - } -} - -#[cfg(feature = "extra-traits")] -impl Hash for Type { - fn hash(&self, hash: &mut H) - where - H: Hasher, - { - match self { - Type::Array(ty) => { - hash.write_u8(0); - ty.hash(hash); - } - Type::BareFn(ty) => { - hash.write_u8(1); - ty.hash(hash); - } - Type::Group(ty) => { - hash.write_u8(2); - ty.hash(hash); - } - Type::ImplTrait(ty) => { - hash.write_u8(3); - ty.hash(hash); - } - Type::Infer(ty) => { - hash.write_u8(4); - ty.hash(hash); - } - Type::Macro(ty) => { - hash.write_u8(5); - ty.hash(hash); - } - Type::Never(ty) => { - hash.write_u8(6); - ty.hash(hash); - } - Type::Paren(ty) => { - hash.write_u8(7); - ty.hash(hash); - } - Type::Path(ty) => { - hash.write_u8(8); - ty.hash(hash); - } - Type::Ptr(ty) => { - hash.write_u8(9); - ty.hash(hash); - } - Type::Reference(ty) => { - hash.write_u8(10); - ty.hash(hash); - } - Type::Slice(ty) => { - hash.write_u8(11); - ty.hash(hash); - } - Type::TraitObject(ty) => { - hash.write_u8(12); - ty.hash(hash); - } - Type::Tuple(ty) => { - hash.write_u8(13); - ty.hash(hash); - } - Type::Verbatim(ty) => { - hash.write_u8(14); - TokenStreamHelper(ty).hash(hash); - } - Type::__Nonexhaustive => unreachable!(), - } - } -} - ast_struct! { /// The binary interface of a function: `extern "C"`. /// diff --git a/vendor/syn/tests/common/eq.rs b/vendor/syn/tests/common/eq.rs index 247a58b755..7589a07573 100644 --- a/vendor/syn/tests/common/eq.rs +++ b/vendor/syn/tests/common/eq.rs @@ -14,22 +14,22 @@ use rustc_ast::ast::{ GenericParam, GenericParamKind, Generics, GlobalAsm, ImplPolarity, InlineAsm, InlineAsmOperand, InlineAsmOptions, InlineAsmRegOrRegClass, InlineAsmTemplatePiece, IntTy, IsAuto, Item, ItemKind, Label, Lifetime, Lit, LitFloatType, LitIntType, LitKind, LlvmAsmDialect, - LlvmInlineAsm, LlvmInlineAsmOutput, Local, MacArgs, MacCall, MacDelimiter, MacStmtStyle, - MacroDef, Mod, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs, Pat, PatKind, - Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, StmtKind, - StrLit, StrStyle, StructField, TraitBoundModifier, TraitObjectSyntax, TraitRef, Ty, TyKind, - UintTy, UnOp, Unsafe, UnsafeSource, UseTree, UseTreeKind, Variant, VariantData, VisibilityKind, - WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate, WhereRegionPredicate, + LlvmInlineAsm, LlvmInlineAsmOutput, Local, MacArgs, MacCall, MacCallStmt, MacDelimiter, + MacStmtStyle, MacroDef, Mod, Movability, MutTy, Mutability, NodeId, Param, ParenthesizedArgs, + Pat, PatKind, Path, PathSegment, PolyTraitRef, QSelf, RangeEnd, RangeLimits, RangeSyntax, Stmt, + StmtKind, StrLit, StrStyle, StructField, TraitBoundModifier, TraitObjectSyntax, TraitRef, Ty, + TyKind, UintTy, UnOp, Unsafe, UnsafeSource, UseTree, UseTreeKind, Variant, VariantData, + VisibilityKind, WhereBoundPredicate, WhereClause, WhereEqPredicate, WherePredicate, + WhereRegionPredicate, }; use rustc_ast::ptr::P; -use rustc_ast::token::{self, DelimToken, Token, TokenKind}; +use rustc_ast::token::{self, CommentKind, DelimToken, Token, TokenKind}; use rustc_ast::tokenstream::{DelimSpan, TokenStream, TokenTree}; -use rustc_ast::util::comments; use rustc_data_structures::sync::Lrc; use rustc_data_structures::thin_vec::ThinVec; use rustc_span::source_map::Spanned; use rustc_span::symbol::Ident; -use rustc_span::{sym, Span, Symbol, SyntaxContext, DUMMY_SP}; +use rustc_span::{Span, Symbol, SyntaxContext}; pub trait SpanlessEq { fn eq(&self, other: &Self) -> bool; @@ -85,14 +85,6 @@ impl SpanlessEq for (A, B) { } } -impl SpanlessEq for (A, B, C) { - fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(&self.0, &other.0) - && SpanlessEq::eq(&self.1, &other.1) - && SpanlessEq::eq(&self.2, &other.2) - } -} - macro_rules! spanless_eq_true { ($name:ident) => { impl SpanlessEq for $name { @@ -127,6 +119,7 @@ spanless_eq_partial_eq!(usize); spanless_eq_partial_eq!(char); spanless_eq_partial_eq!(String); spanless_eq_partial_eq!(Symbol); +spanless_eq_partial_eq!(CommentKind); spanless_eq_partial_eq!(DelimToken); spanless_eq_partial_eq!(InlineAsmOptions); @@ -278,7 +271,7 @@ spanless_eq_struct!(Field; attrs id span ident expr is_shorthand is_placeholder) spanless_eq_struct!(FieldPat; ident pat is_shorthand attrs id span is_placeholder); spanless_eq_struct!(FnDecl; inputs output); spanless_eq_struct!(FnHeader; constness asyncness unsafety ext); -spanless_eq_struct!(FnSig; header decl); +spanless_eq_struct!(FnSig; header decl span); spanless_eq_struct!(ForeignMod; abi items); spanless_eq_struct!(GenericParam; id ident attrs bounds is_placeholder kind); spanless_eq_struct!(Generics; params where_clause span); @@ -292,12 +285,13 @@ spanless_eq_struct!(LlvmInlineAsm; asm asm_str_style outputs inputs clobbers vol spanless_eq_struct!(LlvmInlineAsmOutput; constraint expr is_rw is_indirect); spanless_eq_struct!(Local; pat ty init id span attrs); spanless_eq_struct!(MacCall; path args prior_type_ascription); +spanless_eq_struct!(MacCallStmt; mac style attrs); spanless_eq_struct!(MacroDef; body macro_rules); spanless_eq_struct!(Mod; inner items inline); spanless_eq_struct!(MutTy; ty mutbl); spanless_eq_struct!(Param; attrs ty pat id span is_placeholder); spanless_eq_struct!(ParenthesizedArgs; span inputs output); -spanless_eq_struct!(Pat; id kind span); +spanless_eq_struct!(Pat; id kind span tokens); spanless_eq_struct!(Path; span segments); spanless_eq_struct!(PathSegment; ident id args); spanless_eq_struct!(PolyTraitRef; bound_generic_params trait_ref span); @@ -318,7 +312,7 @@ spanless_eq_enum!(AngleBracketedArg; Arg(0) Constraint(0)); spanless_eq_enum!(AssocItemKind; Const(0 1 2) Fn(0 1 2 3) TyAlias(0 1 2 3) MacCall(0)); spanless_eq_enum!(AssocTyConstraintKind; Equality(ty) Bound(bounds)); spanless_eq_enum!(Async; Yes(span closure_id return_impl_trait_id) No); -spanless_eq_enum!(AttrKind; Normal(0) DocComment(0)); +spanless_eq_enum!(AttrKind; Normal(0) DocComment(0 1)); spanless_eq_enum!(AttrStyle; Outer Inner); spanless_eq_enum!(BinOpKind; Add Sub Mul Div Rem And Or BitXor BitAnd BitOr Shl Shr Eq Lt Le Ne Ge Gt); spanless_eq_enum!(BindingMode; ByRef(0) ByValue(0)); @@ -425,44 +419,20 @@ impl SpanlessEq for TokenKind { impl SpanlessEq for TokenStream { fn eq(&self, other: &Self) -> bool { - SpanlessEq::eq(&expand_tts(self), &expand_tts(other)) - } -} - -fn expand_tts(tts: &TokenStream) -> Vec { - let mut tokens = Vec::new(); - for tt in tts.clone().into_trees() { - let c = match tt { - TokenTree::Token(Token { - kind: TokenKind::DocComment(c), - .. - }) => c, - _ => { - tokens.push(tt); - continue; + let mut this = self.clone().into_trees(); + let mut other = other.clone().into_trees(); + loop { + let this = match this.next() { + None => return other.next().is_none(), + Some(val) => val, + }; + let other = match other.next() { + None => return false, + Some(val) => val, + }; + if !SpanlessEq::eq(&this, &other) { + return false; } - }; - let contents = comments::strip_doc_comment_decoration(c); - let style = comments::doc_comment_style(c); - tokens.push(TokenTree::token(TokenKind::Pound, DUMMY_SP)); - if style == AttrStyle::Inner { - tokens.push(TokenTree::token(TokenKind::Not, DUMMY_SP)); } - let lit = token::Lit { - kind: token::LitKind::Str, - symbol: Symbol::intern(&contents), - suffix: None, - }; - let tts = vec![ - TokenTree::token(TokenKind::Ident(sym::doc, false), DUMMY_SP), - TokenTree::token(TokenKind::Eq, DUMMY_SP), - TokenTree::token(TokenKind::Literal(lit), DUMMY_SP), - ]; - tokens.push(TokenTree::Delimited( - DelimSpan::dummy(), - DelimToken::Bracket, - tts.into_iter().collect::().into(), - )); } - tokens } diff --git a/vendor/syn/tests/repo/mod.rs b/vendor/syn/tests/repo/mod.rs index 20c5fdd3b0..1d3e1f0e74 100644 --- a/vendor/syn/tests/repo/mod.rs +++ b/vendor/syn/tests/repo/mod.rs @@ -8,17 +8,20 @@ use std::path::Path; use tar::Archive; use walkdir::DirEntry; -const REVISION: &str = "81e754c359c471f91263813c46c67955071716a7"; +const REVISION: &str = "792c645ca7d11a8d254df307d019c5bf01445c37"; #[rustfmt::skip] static EXCLUDE: &[&str] = &[ + // Compile-fail expr parameter in const generic position: f::<1 + 2>() + "test/ui/const-generics/const-expression-parameter.rs", + // Deprecated anonymous parameter syntax in traits "test/ui/issues/issue-13105.rs", "test/ui/issues/issue-13775.rs", "test/ui/issues/issue-34074.rs", "test/ui/proc-macro/trait-fn-args-2015.rs", - // not actually test cases + // Not actually test cases "test/rustdoc-ui/test-compile-fail2.rs", "test/rustdoc-ui/test-compile-fail3.rs", "test/ui/include-single-expr-helper.rs", diff --git a/vendor/syn/tests/test_derive_input.rs b/vendor/syn/tests/test_derive_input.rs index fd31fe6b5d..bf1ebdb67d 100644 --- a/vendor/syn/tests/test_derive_input.rs +++ b/vendor/syn/tests/test_derive_input.rs @@ -46,7 +46,7 @@ fn test_struct() { }, ], }, - tokens: TokenStream(`( Debug , Clone )`), + tokens: TokenStream(`(Debug , Clone)`), }, ], vis: Visibility::Public, @@ -378,7 +378,7 @@ fn test_attr_with_path() { }, ], }, - tokens: TokenStream(`fn main ( ) { assert_eq ! ( foo ( ) , "Hello, world!" ) ; }`), + tokens: TokenStream(`fn main () { assert_eq ! (foo () , "Hello, world!") ; }`), }, ], vis: Inherited, diff --git a/vendor/syn/tests/test_generics.rs b/vendor/syn/tests/test_generics.rs index adf1f55727..b29434a147 100644 --- a/vendor/syn/tests/test_generics.rs +++ b/vendor/syn/tests/test_generics.rs @@ -265,7 +265,7 @@ fn test_fn_precedence_in_where_clause() { assert_eq!(predicate.bounds.len(), 2, "{:#?}", predicate.bounds); let first_bound = &predicate.bounds[0]; - assert_eq!(quote!(#first_bound).to_string(), "FnOnce ( ) -> i32"); + assert_eq!(quote!(#first_bound).to_string(), "FnOnce () -> i32"); let second_bound = &predicate.bounds[1]; assert_eq!(quote!(#second_bound).to_string(), "Send"); diff --git a/vendor/syn/tests/test_grouping.rs b/vendor/syn/tests/test_grouping.rs index c53ab34623..a0fe716390 100644 --- a/vendor/syn/tests/test_grouping.rs +++ b/vendor/syn/tests/test_grouping.rs @@ -23,7 +23,7 @@ fn test_grouping() { TokenTree::Literal(Literal::i32_suffixed(4)), ]); - assert_eq!(tokens.to_string(), "1i32 + 2i32 + 3i32 * 4i32"); + assert_eq!(tokens.to_string(), "1i32 + 2i32 + 3i32 * 4i32"); snapshot!(tokens as Expr, @r###" Expr::Binary { diff --git a/vendor/syn/tests/test_lit.rs b/vendor/syn/tests/test_lit.rs index 0bd170c3b4..e995f2287f 100644 --- a/vendor/syn/tests/test_lit.rs +++ b/vendor/syn/tests/test_lit.rs @@ -191,6 +191,7 @@ fn floats() { test_float("5.5e12", 5.5e12, ""); test_float("1.0__3e-12", 1.03e-12, ""); test_float("1.03e+12", 1.03e12, ""); + test_float("9e99e99", 9e99, "e99"); } #[test] diff --git a/vendor/syn/tests/test_precedence.rs b/vendor/syn/tests/test_precedence.rs index dfdab3f4f8..a586b3fe48 100644 --- a/vendor/syn/tests/test_precedence.rs +++ b/vendor/syn/tests/test_precedence.rs @@ -156,7 +156,7 @@ fn test_expressions(edition: Edition, exprs: Vec) -> (usize, usize) { let mut passed = 0; let mut failed = 0; - rustc_ast::with_session_globals(edition, || { + rustc_span::with_session_globals(edition, || { for expr in exprs { let raw = quote!(#expr).to_string(); diff --git a/vendor/syn/tests/test_round_trip.rs b/vendor/syn/tests/test_round_trip.rs index 99268a7c1f..260dd0c3d9 100644 --- a/vendor/syn/tests/test_round_trip.rs +++ b/vendor/syn/tests/test_round_trip.rs @@ -79,7 +79,7 @@ fn test_round_trip() { let edition = repo::edition(path).parse().unwrap(); let equal = panic::catch_unwind(|| { - rustc_ast::with_session_globals(edition, || { + rustc_span::with_session_globals(edition, || { let sess = ParseSess::new(FilePathMapping::empty()); let before = match librustc_parse(content, &sess) { Ok(before) => before, diff --git a/vendor/syn/tests/test_shebang.rs b/vendor/syn/tests/test_shebang.rs index e76e1803da..dc26b9aab3 100644 --- a/vendor/syn/tests/test_shebang.rs +++ b/vendor/syn/tests/test_shebang.rs @@ -40,7 +40,7 @@ fn test_comment() { }, ], }, - tokens: TokenStream(`( dead_code )`), + tokens: TokenStream(`(dead_code)`), }, ], items: [ diff --git a/vendor/syn/tests/test_token_trees.rs b/vendor/syn/tests/test_token_trees.rs index 4256382dbe..5b00448af8 100644 --- a/vendor/syn/tests/test_token_trees.rs +++ b/vendor/syn/tests/test_token_trees.rs @@ -17,7 +17,7 @@ fn test_struct() { snapshot!(input as TokenStream, @r###" TokenStream( - `# [ derive ( Debug , Clone ) ] pub struct Item { pub ident : Ident , pub attrs : Vec < Attribute >, }`, + `# [derive (Debug , Clone)] pub struct Item { pub ident : Ident , pub attrs : Vec < Attribute >, }`, ) "###); } diff --git a/vendor/time/.cargo-checksum.json b/vendor/time/.cargo-checksum.json index f6085da3f1..901b364212 100644 --- a/vendor/time/.cargo-checksum.json +++ b/vendor/time/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"ddebccd9128093c3fdf84b4f6a131fe634c85e8fc2059afed9ea30e02fe22c58","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"35b591c7481ec3ae59210fa4f9b7cecb1b16e632bfd6193b032239e74f9bfdb8","src/display.rs":"52d16abaa37b3ab577747c7d9d2ed6ded1b126458e980dc3e1a571fa6e1f9fda","src/duration.rs":"c706d392bdb7f65b23fcc20189a9a77c50b765b9c548e247238424ed6fb56a46","src/lib.rs":"720e380829cda276466bce34d6a29a2f7aec1f750e4b4522b217c57930380545","src/parse.rs":"65bd9142d8c15eb54a8d4db6e2c48bf1adbcc875953141c17e07ba58f356a027","src/sys.rs":"851994516ff29dd9f5749fa19b1db13b7afe484e4bd1d279b420fda7ed8404ab"},"package":"ca8a50ef2360fbd1eeb0ecd46795a87a19024eb4b53c5dc916ca1fd95fe62438"} \ No newline at end of file +{"files":{"Cargo.toml":"37a749b23d43c8ad48eecfa03b7483b76dded90290150fab232c014a59350e00","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"6485b8ed310d3f0340bf1ad1f47645069ce4069dcc6bb46c7d5c6faf41de1fdb","README.md":"35b591c7481ec3ae59210fa4f9b7cecb1b16e632bfd6193b032239e74f9bfdb8","src/display.rs":"52d16abaa37b3ab577747c7d9d2ed6ded1b126458e980dc3e1a571fa6e1f9fda","src/duration.rs":"c706d392bdb7f65b23fcc20189a9a77c50b765b9c548e247238424ed6fb56a46","src/lib.rs":"fcd2f8739dab93a8e39aed1464b48f0f11d7bb0a3e2516b683af41dc8920d298","src/parse.rs":"65bd9142d8c15eb54a8d4db6e2c48bf1adbcc875953141c17e07ba58f356a027","src/sys.rs":"cb604129e4b83ad701234562e62a137cde2ba52c9eb1b1f17d4f308e182cabaa"},"package":"6db9e6914ab8b1ae1c260a4ae7a49b6c5611b40328a735b21862567685e73255"} \ No newline at end of file diff --git a/vendor/time/Cargo.toml b/vendor/time/Cargo.toml index 51e5ab1d10..02b0f6af96 100644 --- a/vendor/time/Cargo.toml +++ b/vendor/time/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "time" -version = "0.1.43" +version = "0.1.44" authors = ["The Rust Project Developers"] exclude = [".github", "benches"] description = "Utilities for working with time-related functions in Rust.\n" @@ -33,6 +33,8 @@ version = "0.4" [dev-dependencies.winapi] version = "0.3.0" features = ["std", "processthreadsapi", "winbase"] +[target."cfg(target_os = \"wasi\")".dependencies.wasi] +version = "=0.10.0" [target."cfg(windows)".dependencies.winapi] version = "0.3.0" features = ["std", "minwinbase", "minwindef", "ntdef", "profileapi", "sysinfoapi", "timezoneapi"] diff --git a/vendor/time/src/lib.rs b/vendor/time/src/lib.rs index 07c38e4066..2627cc1648 100644 --- a/vendor/time/src/lib.rs +++ b/vendor/time/src/lib.rs @@ -42,6 +42,8 @@ #[cfg(windows)] extern crate winapi; #[cfg(feature = "rustc-serialize")] extern crate rustc_serialize; +#[cfg(target_os = "wasi")] extern crate wasi; + #[cfg(test)] #[macro_use] extern crate log; use std::cmp::Ordering; diff --git a/vendor/time/src/sys.rs b/vendor/time/src/sys.rs index 80de8fa2c2..22b77e1079 100644 --- a/vendor/time/src/sys.rs +++ b/vendor/time/src/sys.rs @@ -69,7 +69,7 @@ mod common { } } -#[cfg(all(target_arch = "wasm32", not(target_os = "emscripten")))] +#[cfg(all(target_arch = "wasm32", not(any(target_os = "emscripten", target_os = "wasi"))))] mod inner { use std::ops::{Add, Sub}; use Tm; @@ -121,7 +121,7 @@ mod inner { impl Sub for SteadyTime { type Output = SteadyTime; fn sub(self, _other: Duration) -> SteadyTime { - unimplemented!() + unimplemented!() } } @@ -133,6 +133,84 @@ mod inner { } } +#[cfg(target_os = "wasi")] +mod inner { + use std::ops::{Add, Sub}; + use Tm; + use Duration; + use super::common::{time_to_tm, tm_to_time}; + use wasi::{clock_time_get, CLOCKID_MONOTONIC, CLOCKID_REALTIME}; + + #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)] + pub struct SteadyTime { + t: u64 + } + + pub fn time_to_utc_tm(sec: i64, tm: &mut Tm) { + time_to_tm(sec, tm); + } + + pub fn time_to_local_tm(sec: i64, tm: &mut Tm) { + // FIXME: Add timezone logic + time_to_tm(sec, tm); + } + + pub fn utc_tm_to_time(tm: &Tm) -> i64 { + tm_to_time(tm) + } + + pub fn local_tm_to_time(tm: &Tm) -> i64 { + // FIXME: Add timezone logic + tm_to_time(tm) + } + + pub fn get_time() -> (i64, i32) { + let ts = get_precise_ns(); + ( + ts as i64 / 1_000_000_000, + (ts as i64 % 1_000_000_000) as i32, + ) + } + + pub fn get_precise_ns() -> u64 { + unsafe { clock_time_get(CLOCKID_REALTIME, 1_000_000_000) } + .expect("Host doesn't implement a real-time clock") + } + + impl SteadyTime { + pub fn now() -> SteadyTime { + SteadyTime { + t: unsafe { clock_time_get(CLOCKID_MONOTONIC, 1_000_000_000) } + .expect("Host doesn't implement a monotonic clock"), + } + } + } + + impl Sub for SteadyTime { + type Output = Duration; + fn sub(self, other: SteadyTime) -> Duration { + Duration::nanoseconds(self.t as i64 - other.t as i64) + } + } + + impl Sub for SteadyTime { + type Output = SteadyTime; + fn sub(self, other: Duration) -> SteadyTime { + self + -other + } + } + + impl Add for SteadyTime { + type Output = SteadyTime; + fn add(self, other: Duration) -> SteadyTime { + let delta = other.num_nanoseconds().unwrap(); + SteadyTime { + t: (self.t as i64 + delta) as u64, + } + } + } +} + #[cfg(target_env = "sgx")] mod inner { use std::ops::{Add, Sub}; diff --git a/vendor/toml/.cargo-checksum.json b/vendor/toml/.cargo-checksum.json index 220592cc3b..7f27be3b24 100644 --- a/vendor/toml/.cargo-checksum.json +++ b/vendor/toml/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.lock":"c1a1c1cc39429fa1266c11ad7fbfe6cf7017678053a1fcfae76c1e9b63990982","Cargo.toml":"94455e80d272740f42a421fb43ee6a5a7c58cdc4cd34031063353e3f04fcadd9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"9f9fabc5623932ee1ac3d4c7d00c01ce78d43e1b916844249b1991df28a58be0","examples/decode.rs":"196b30175566306e70bd4e9d62622772783b53253156d312c90095a3eaf2c817","examples/enum_external.rs":"ee4e5a989fcc9a5fb29f39ecb8a46715253321e54e5604e7c956b43465696a70","examples/toml2json.rs":"b0256e8393f91633abaa5b5c1ce496b73efee14a81b51e4f242aae967eaf9548","src/datetime.rs":"3a3642112bb67a6556686a19459dc1768fe6fe46ae6ddc1ef1a876318c93765b","src/de.rs":"06ffd6068c1beedaf3f38c93da97837e854f79e1447809bfd4f351d268371c6a","src/lib.rs":"b5b503c16fb1227a5f67308e7423d85e2da83f6555e568775adec7cb4bef2664","src/macros.rs":"81a7e1b7884714cb23af28e9415f3fe35395820edad7a534c98593d5c940ec0c","src/map.rs":"b25282ab8935501587879c9b3703633f36c4114b9d0c68fa5619233fcf32cc90","src/ser.rs":"7772a5fc30c799c5713a149bbd436a7da24941e590884dbbf9e70ad640ecba4e","src/spanned.rs":"01b8776279c1ef3fe2e81188e3e8f672430220482c5765178b57dac78522b1b3","src/tokens.rs":"c7e375d63c17805e15ade15687908b4371ba26412c06ab400d699519bc3ba114","src/value.rs":"b2f2985a29c53e0126959a251244e822397ac584e37f8537a775bd356b7f77fa","tests/enum_external_deserialize.rs":"32515d5fa80e36efed6006da6514b5054c5c903960d9d884866d608ce9d23c35"},"package":"ffc92d160b1eef40665be3a05630d003936a3bc7da7421277846c2613e92c71a"} \ No newline at end of file +{"files":{"Cargo.lock":"939ae93cd62696867163f5fefb7058496721789aa0fcd8233447031ed02aee92","Cargo.toml":"2696f06c454d3434a15f5d14d30eeb2208f05c3f4f8afe6917e44f136870d83b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"378f5840b258e2779c39418f3f2d7b2ba96f1c7917dd6be0713f88305dbda397","README.md":"9f9fabc5623932ee1ac3d4c7d00c01ce78d43e1b916844249b1991df28a58be0","examples/decode.rs":"196b30175566306e70bd4e9d62622772783b53253156d312c90095a3eaf2c817","examples/enum_external.rs":"ee4e5a989fcc9a5fb29f39ecb8a46715253321e54e5604e7c956b43465696a70","examples/toml2json.rs":"b0256e8393f91633abaa5b5c1ce496b73efee14a81b51e4f242aae967eaf9548","src/datetime.rs":"3a3642112bb67a6556686a19459dc1768fe6fe46ae6ddc1ef1a876318c93765b","src/de.rs":"862f283727bccb9368f3518e59c0f940f5016ca310c9ca10c44dbcd5b24281b9","src/lib.rs":"31eb29cee1fb7efa5063c87ac9d13d2d44c1ca3d4c827ee733d6fd99f7853ef2","src/macros.rs":"81a7e1b7884714cb23af28e9415f3fe35395820edad7a534c98593d5c940ec0c","src/map.rs":"ffc5539c8884baea62ed0e2ea89b018797c5e2d285f778f1d0e124a69ec29ddc","src/ser.rs":"5bf5e270eb0960fed0559e982dd23805bcbc14e47b1aa0543c95e997afa60851","src/spanned.rs":"01b8776279c1ef3fe2e81188e3e8f672430220482c5765178b57dac78522b1b3","src/tokens.rs":"9c1b92dac2c2397270af20c07812661677595936940e26bfebc6963d4fbb6502","src/value.rs":"ea259335cadc89c8c5c5c05dba0ef3986c6fde3c10782ac7573506d20fa36c88","tests/enum_external_deserialize.rs":"32515d5fa80e36efed6006da6514b5054c5c903960d9d884866d608ce9d23c35"},"package":"75cf45bb0bef80604d001caaec0d09da99611b3c0fd39d3080468875cdb65645"} \ No newline at end of file diff --git a/vendor/toml/Cargo.lock b/vendor/toml/Cargo.lock index dd8ac0790a..b9ac09767f 100644 --- a/vendor/toml/Cargo.lock +++ b/vendor/toml/Cargo.lock @@ -2,102 +2,107 @@ # It is not intended for manual editing. [[package]] name = "autocfg" -version = "0.1.7" +version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + +[[package]] +name = "hashbrown" +version = "0.9.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d7afe4a420e3fe79967a00898cc1f4db7c8a49a9333a29f8a4bd76a253d5cd04" [[package]] name = "indexmap" -version = "1.3.0" +version = "1.6.0" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "55e2e4c765aa53a0424761bf9f41aa7a6ac1efa87238f59560640e27fca028f2" dependencies = [ - "autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)", + "autocfg", + "hashbrown", ] [[package]] name = "itoa" -version = "0.4.4" +version = "0.4.6" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6" [[package]] name = "proc-macro2" -version = "1.0.1" +version = "1.0.24" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1e0704ee1a7e00d7bb417d0770ea303c1bccbabf0ef1667dae92b5967f5f8a71" dependencies = [ - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "unicode-xid", ] [[package]] name = "quote" -version = "1.0.2" +version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "aa563d17ecb180e500da1cfd2b028310ac758de548efdd203e18f283af693f37" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", ] [[package]] name = "ryu" -version = "1.0.0" +version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "71d301d4193d031abdd79ff7e3dd721168a9572ef3fe51a1517aba235bd8f86e" [[package]] name = "serde" -version = "1.0.99" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "96fe57af81d28386a513cbc6858332abc6117cfdb5999647c6444b8f43a370a5" [[package]] name = "serde_derive" -version = "1.0.99" +version = "1.0.116" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f630a6370fd8e457873b4bd2ffdae75408bc291ba72be773772a4c2a065d9ae8" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "syn", ] [[package]] name = "serde_json" -version = "1.0.40" +version = "1.0.58" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a230ea9107ca2220eea9d46de97eddcb04cd00e92d13dda78e478dd33fa82bd4" dependencies = [ - "itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)", - "ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", + "itoa", + "ryu", + "serde", ] [[package]] name = "syn" -version = "1.0.5" +version = "1.0.44" source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e03e57e4fcbfe7749842d53e24ccb9aa12b7252dbe5e91d2acad31834c8b8fdd" dependencies = [ - "proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)", - "quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)", - "unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)", + "proc-macro2", + "quote", + "unicode-xid", ] [[package]] name = "toml" -version = "0.5.6" +version = "0.5.7" dependencies = [ - "indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", - "serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)", - "serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)", + "indexmap", + "serde", + "serde_derive", + "serde_json", ] [[package]] name = "unicode-xid" -version = "0.2.0" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" - -[metadata] -"checksum autocfg 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "1d49d90015b3c36167a20fe2810c5cd875ad504b39cff3d4eae7977e6b7c1cb2" -"checksum indexmap 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712d7b3ea5827fcb9d4fda14bf4da5f136f0db2ae9c8f4bd4e2d1c6fde4e6db2" -"checksum itoa 0.4.4 (registry+https://github.com/rust-lang/crates.io-index)" = "501266b7edd0174f8530248f87f99c88fbe60ca4ef3dd486835b8d8d53136f7f" -"checksum proc-macro2 1.0.1 (registry+https://github.com/rust-lang/crates.io-index)" = "4c5c2380ae88876faae57698be9e9775e3544decad214599c3a6266cca6ac802" -"checksum quote 1.0.2 (registry+https://github.com/rust-lang/crates.io-index)" = "053a8c8bcc71fcce321828dc897a98ab9760bef03a4fc36693c231e5b3216cfe" -"checksum ryu 1.0.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c92464b447c0ee8c4fb3824ecc8383b81717b9f1e74ba2e72540aef7b9f82997" -"checksum serde 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "fec2851eb56d010dc9a21b89ca53ee75e6528bab60c11e89d38390904982da9f" -"checksum serde_derive 1.0.99 (registry+https://github.com/rust-lang/crates.io-index)" = "cb4dc18c61206b08dc98216c98faa0232f4337e1e1b8574551d5bad29ea1b425" -"checksum serde_json 1.0.40 (registry+https://github.com/rust-lang/crates.io-index)" = "051c49229f282f7c6f3813f8286cc1e3323e8051823fce42c7ea80fe13521704" -"checksum syn 1.0.5 (registry+https://github.com/rust-lang/crates.io-index)" = "66850e97125af79138385e9b88339cbcd037e3f28ceab8c5ad98e64f0f1f80bf" -"checksum unicode-xid 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "826e7639553986605ec5979c7dd957c7895e93eabed50ab2ffa7f6128a75097c" +checksum = "f7fe0bb3479651439c9112f72b6c505038574c9fbb575ed1bf3b797fa39dd564" diff --git a/vendor/toml/Cargo.toml b/vendor/toml/Cargo.toml index 4594875d27..ecc56021b5 100644 --- a/vendor/toml/Cargo.toml +++ b/vendor/toml/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "toml" -version = "0.5.6" +version = "0.5.7" authors = ["Alex Crichton "] description = "A native Rust encoder and decoder of TOML-formatted files and streams. Provides\nimplementations of the standard Serialize/Deserialize traits for TOML data to\nfacilitate deserializing and serializing Rust structures.\n" homepage = "https://github.com/alexcrichton/toml-rs" diff --git a/vendor/toml/src/de.rs b/vendor/toml/src/de.rs index 98b3a60ac3..64112932a2 100644 --- a/vendor/toml/src/de.rs +++ b/vendor/toml/src/de.rs @@ -191,6 +191,9 @@ enum ErrorKind { available: &'static [&'static str], }, + /// Unquoted string was found when quoted one was expected + UnquotedString, + #[doc(hidden)] __Nonexhaustive, } @@ -333,7 +336,7 @@ fn build_table_indices<'de>(tables: &[Table<'de>]) -> HashMap> let mut res = HashMap::new(); for (i, table) in tables.iter().enumerate() { let header = table.header.iter().map(|v| v.1.clone()).collect::>(); - res.entry(header).or_insert(Vec::new()).push(i); + res.entry(header).or_insert_with(Vec::new).push(i); } res } @@ -359,7 +362,7 @@ fn build_table_pindices<'de>(tables: &[Table<'de>]) -> HashMap let header = table.header.iter().map(|v| v.1.clone()).collect::>(); for len in 0..=header.len() { res.entry(header[..len].to_owned()) - .or_insert(Vec::new()) + .or_insert_with(Vec::new) .push(i); } } @@ -680,7 +683,7 @@ impl<'de, 'b> de::Deserializer<'de> for MapVisitor<'de, 'b> { } let table = &mut self.tables[0]; let values = table.values.take().expect("table has no values?"); - if table.header.len() == 0 { + if table.header.is_empty() { return Err(self.de.error(self.cur, ErrorKind::EmptyTableKey)); } let name = table.header[table.header.len() - 1].1.to_owned(); @@ -1428,7 +1431,7 @@ impl<'a> Deserializer<'a> { start, end, }, - Some((span, Token::Keylike(key))) => self.number_or_date(span, key)?, + Some((span, Token::Keylike(key))) => self.parse_keylike(at, span, key)?, Some((span, Token::Plus)) => self.number_leading_plus(span)?, Some((Span { start, .. }, Token::LeftBrace)) => { self.inline_table().map(|(Span { end, .. }, table)| Value { @@ -1451,13 +1454,25 @@ impl<'a> Deserializer<'a> { expected: "a value", found: token.1.describe(), }, - )) + )); } None => return Err(self.eof()), }; Ok(value) } + fn parse_keylike(&mut self, at: usize, span: Span, key: &'a str) -> Result, Error> { + if key == "inf" || key == "nan" { + return self.number_or_date(span, key); + } + + let first_char = key.chars().next().expect("key should not be empty here"); + match first_char { + '-' | '0'..='9' => self.number_or_date(span, key), + _ => Err(self.error(at, ErrorKind::UnquotedString)), + } + } + fn number_or_date(&mut self, span: Span, s: &'a str) -> Result, Error> { if s.contains('T') || s.contains('t') @@ -1633,7 +1648,7 @@ impl<'a> Deserializer<'a> { if c == '0' && first { first_zero = true; - } else if c.to_digit(radix).is_some() { + } else if c.is_digit(radix) { if !first && first_zero && !allow_leading_zeros { return Err(self.error(at, ErrorKind::NumberInvalid)); } @@ -2076,7 +2091,7 @@ impl std::convert::From for std::io::Error { impl fmt::Display for Error { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match self.inner.kind { + match &self.inner.kind { ErrorKind::UnexpectedEof => "unexpected eof encountered".fmt(f)?, ErrorKind::InvalidCharInString(c) => write!( f, @@ -2131,6 +2146,10 @@ impl fmt::Display for Error { "unexpected keys in table: `{:?}`, available keys: `{:?}`", keys, available )?, + ErrorKind::UnquotedString => write!( + f, + "invalid TOML value, did you mean to use a quoted string?" + )?, ErrorKind::__Nonexhaustive => panic!(), } diff --git a/vendor/toml/src/lib.rs b/vendor/toml/src/lib.rs index 4a32d71d8e..6b02941c3d 100644 --- a/vendor/toml/src/lib.rs +++ b/vendor/toml/src/lib.rs @@ -21,7 +21,7 @@ //! //! ## TOML values //! -//! A value in TOML is represented with the `Value` enum in this crate: +//! A value in TOML is represented with the [`Value`] enum in this crate: //! //! ```rust,ignore //! pub enum Value { @@ -35,13 +35,13 @@ //! } //! ``` //! -//! TOML is similar to JSON with the notable addition of a `Datetime` +//! TOML is similar to JSON with the notable addition of a [`Datetime`] //! type. In general, TOML and JSON are interchangeable in terms of //! formats. //! //! ## Parsing TOML //! -//! The easiest way to parse a TOML document is via the `Value` type: +//! The easiest way to parse a TOML document is via the [`Value`] type: //! //! ```rust //! use toml::Value; @@ -51,9 +51,9 @@ //! assert_eq!(value["foo"].as_str(), Some("bar")); //! ``` //! -//! The `Value` type implements a number of convenience methods and -//! traits; the example above uses `FromStr` to parse a `str` into a -//! `Value`. +//! The [`Value`] type implements a number of convenience methods and +//! traits; the example above uses [`FromStr`] to parse a [`str`] into a +//! [`Value`]. //! //! ## Deserialization and Serialization //! @@ -70,8 +70,8 @@ //! * `Deserializer for Value` //! //! This means that you can use Serde to deserialize/serialize the -//! `Value` type as well as the `Datetime` type in this crate. You can also -//! use the `Deserializer`, `Serializer`, or `Value` type itself to act as +//! [`Value`] type as well as the [`Datetime`] type in this crate. You can also +//! use the [`Deserializer`], [`Serializer`], or [`Value`] type itself to act as //! a deserializer/serializer for arbitrary types. //! //! An example of deserializing with TOML is: @@ -171,4 +171,11 @@ mod tokens; pub mod macros; mod spanned; +#[doc(no_inline)] pub use crate::spanned::Spanned; + +// Just for rustdoc +#[allow(unused_imports)] +use crate::datetime::Datetime; +#[allow(unused_imports)] +use core::str::FromStr; diff --git a/vendor/toml/src/map.rs b/vendor/toml/src/map.rs index 2d472407a2..d130a1d540 100644 --- a/vendor/toml/src/map.rs +++ b/vendor/toml/src/map.rs @@ -28,7 +28,7 @@ use std::collections::{btree_map, BTreeMap}; #[cfg(feature = "preserve_order")] use indexmap::{self, IndexMap}; -/// Represents a JSON key/value type. +/// Represents a TOML key/value type. pub struct Map { map: MapImpl, } diff --git a/vendor/toml/src/ser.rs b/vendor/toml/src/ser.rs index b4737cc570..e115541751 100644 --- a/vendor/toml/src/ser.rs +++ b/vendor/toml/src/ser.rs @@ -502,7 +502,7 @@ impl<'a> Serializer<'a> { State::Array { type_, .. } => type_, _ => return Ok(()), }; - if let None = prev.get() { + if prev.get().is_none() { prev.set(Some(type_)); } Ok(()) @@ -569,8 +569,9 @@ impl<'a> Serializer<'a> { match ch { '\t' => {} '\n' => ty = Type::NewlineTripple, - // note that the following are invalid: \b \f \r - c if c < '\u{1f}' => can_be_pretty = false, // Invalid control character + // Escape codes are needed if any ascii control + // characters are present, including \b \f \r. + c if c <= '\u{1f}' || c == '\u{7f}' => can_be_pretty = false, _ => {} } out.push(ch); @@ -646,7 +647,7 @@ impl<'a> Serializer<'a> { '\u{d}' => self.dst.push_str("\\r"), '\u{22}' => self.dst.push_str("\\\""), '\u{5c}' => self.dst.push_str("\\\\"), - c if c < '\u{1f}' => { + c if c <= '\u{1f}' || c == '\u{7f}' => { write!(self.dst, "\\u{:04X}", ch as u32).map_err(ser::Error::custom)?; } ch => self.dst.push(ch), diff --git a/vendor/toml/src/tokens.rs b/vendor/toml/src/tokens.rs index 49265fb6ef..fd8b6b98da 100644 --- a/vendor/toml/src/tokens.rs +++ b/vendor/toml/src/tokens.rs @@ -334,7 +334,7 @@ impl<'a> Tokenizer<'a> { return Err(Error::NewlineInString(i)); } } - Some((i, ch)) if ch == delim => { + Some((mut i, ch)) if ch == delim => { if multiline { if !self.eatc(delim) { val.push(delim); @@ -345,6 +345,14 @@ impl<'a> Tokenizer<'a> { val.push(delim); continue 'outer; } + if self.eatc(delim) { + val.push(delim); + i += 1; + } + if self.eatc(delim) { + val.push(delim); + i += 1; + } } return Ok(String { src: &self.input[start..self.current()], diff --git a/vendor/toml/src/value.rs b/vendor/toml/src/value.rs index 38dfe1f687..e631efec01 100644 --- a/vendor/toml/src/value.rs +++ b/vendor/toml/src/value.rs @@ -13,6 +13,7 @@ use serde::de::IntoDeserializer; use serde::ser; use crate::datetime::{self, DatetimeFromString}; +#[doc(no_inline)] pub use crate::datetime::{Datetime, DatetimeParseError}; pub use crate::map::Map; diff --git a/vendor/tracing-core/.cargo-checksum.json b/vendor/tracing-core/.cargo-checksum.json index 3f2a48391e..4b61db6890 100644 --- a/vendor/tracing-core/.cargo-checksum.json +++ b/vendor/tracing-core/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CHANGELOG.md":"a11338fb7bb64db1ae2f9fe451767cf5a283fdb3dce27af1f7949391278198bf","Cargo.toml":"1dc983938a37bad681f2e955142b1d9e601cdbf5e146ee776f560a4b87f7d01a","LICENSE":"898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1","README.md":"fe564d339163fa06447c91f9c5b5c0ad7ad2cf1e4cd40ff12c7a6217e9a349b6","src/callsite.rs":"18de45d43092aeb7a0cda14c98045e12ae11647d059133ec1542a43983dc90b8","src/dispatcher.rs":"9d1bbc89f338785d4341930cbdfbc41040f2bff692827c248dffaa85ea828e3d","src/event.rs":"8b85188c6db6c49848260f050ec6b313ea10e13257597a3418dba100d35bcef2","src/field.rs":"560179f2399d52ed37bda79939ce1b29a60da03baa7068d5613a7ecac5814e50","src/lazy_static/LICENSE":"1e2391052f82d7b0111f512680dcbecf01b06842f5295833e7bd435be2b09a9b","src/lazy_static/core_lazy.rs":"b4c1aaec440177f0de3148fd7b5b60f052890267035966069e9d6a167a72af6a","src/lazy_static/mod.rs":"31abed65708c02b36ec4c72d0788b3fc18c684274ba943dc80fc9f2347f5fb2f","src/lib.rs":"619b99a3a1039ac5e2415f0ae11a0abb35c2c4169278fce1b17541f2942f1384","src/metadata.rs":"9bc8e4b38a220eee4887477b5e10a5e0194f5f60c2875005beebb36d3bd3183f","src/parent.rs":"5d5ad733343280a64a1feb6a008e186c39305ec554f14279012b8d7915821471","src/span.rs":"18d9000b35469ea91c56d3e0023e18a982ef625232c617c2827a417793b02c4a","src/spin/LICENSE":"58545fed1565e42d687aecec6897d35c6d37ccb71479a137c0deb2203e125c79","src/spin/mod.rs":"c458ce5e875acb7fbfb279f23254f4924d7c6d6fee419b740800d2e8087d1524","src/spin/mutex.rs":"eaf592b586a5ed73735d6442009b16b0350cb1f71013dafcc95a512c1a49f187","src/spin/once.rs":"c611328c4287adf5c63ae768e2923f34228cad6e019263c98dd33f96a3357edf","src/stdlib.rs":"491c9e37321798c86124c0690f7c5f29054bc444cc51406c36b6fdb106392303","src/subscriber.rs":"7de3f75d93399baa3a0617206291b4d9c770bea8e16844dfd834b1458d042142","tests/common/mod.rs":"0bbb217baa17df0f96cc1ff57dfa74ccc5a959e7f66b15bb7d25d5f43358a278","tests/dispatch.rs":"c99a9ee042b2a9185d090ffc1a042e1bced0626ce95608c610dd8f7867022f3d","tests/global_dispatch.rs":"cdc05d77e448ee8b50bfb930abafa3f19b4c6f922b7bebc7797fa1dbdaa1d398","tests/macros.rs":"b1603d888b349c8d103794deceec3b1ae4538b8d3eba805f3f561899e8ad0dd2"},"package":"db63662723c316b43ca36d833707cc93dff82a02ba3d7e354f342682cc8b3545"} \ No newline at end of file +{"files":{"CHANGELOG.md":"948ebe49a1a9d96e8dd6ab3a40b1c428bb5615985519deb40c3bff03d347664c","Cargo.toml":"85cd7733f3b0912e6c2e9a308a4024802cfa1cbc3f9a3513e8c50f40158b046c","LICENSE":"898b1ae9821e98daf8964c8d6c7f61641f5f5aa78ad500020771c0939ee0dea1","README.md":"5f7491cb6c4cd727f3c59fc3aff1d05bb643cc3a5666b38115a8c63c8fb87ae0","src/callsite.rs":"c8f5f2cb976f83c4904a6e70f5c6cf353c42943725a55a286fc4da7dc0b4ad53","src/dispatcher.rs":"386fb35ec3a2ebd37c96b50a52eca8232e8c55756681815963d8050ecbc3a417","src/event.rs":"8b85188c6db6c49848260f050ec6b313ea10e13257597a3418dba100d35bcef2","src/field.rs":"560179f2399d52ed37bda79939ce1b29a60da03baa7068d5613a7ecac5814e50","src/lazy_static/LICENSE":"1e2391052f82d7b0111f512680dcbecf01b06842f5295833e7bd435be2b09a9b","src/lazy_static/core_lazy.rs":"b4c1aaec440177f0de3148fd7b5b60f052890267035966069e9d6a167a72af6a","src/lazy_static/mod.rs":"31abed65708c02b36ec4c72d0788b3fc18c684274ba943dc80fc9f2347f5fb2f","src/lib.rs":"0e5b1d01256b5bd26306035ebda7e4ec0f510c8ac8be0498983bf227af4e332f","src/metadata.rs":"3f416d1e73de45e7827838cdb673caaca72b185514e69789b920a99c5c84018a","src/parent.rs":"5d5ad733343280a64a1feb6a008e186c39305ec554f14279012b8d7915821471","src/span.rs":"18d9000b35469ea91c56d3e0023e18a982ef625232c617c2827a417793b02c4a","src/spin/LICENSE":"58545fed1565e42d687aecec6897d35c6d37ccb71479a137c0deb2203e125c79","src/spin/mod.rs":"c458ce5e875acb7fbfb279f23254f4924d7c6d6fee419b740800d2e8087d1524","src/spin/mutex.rs":"eaf592b586a5ed73735d6442009b16b0350cb1f71013dafcc95a512c1a49f187","src/spin/once.rs":"c611328c4287adf5c63ae768e2923f34228cad6e019263c98dd33f96a3357edf","src/stdlib.rs":"491c9e37321798c86124c0690f7c5f29054bc444cc51406c36b6fdb106392303","src/subscriber.rs":"66edfcad19821e4d8d92c9ad44b4717c97a89ea5e5172a4c6d6301bdd5a76025","tests/common/mod.rs":"0bbb217baa17df0f96cc1ff57dfa74ccc5a959e7f66b15bb7d25d5f43358a278","tests/dispatch.rs":"c99a9ee042b2a9185d090ffc1a042e1bced0626ce95608c610dd8f7867022f3d","tests/global_dispatch.rs":"cdc05d77e448ee8b50bfb930abafa3f19b4c6f922b7bebc7797fa1dbdaa1d398","tests/macros.rs":"b1603d888b349c8d103794deceec3b1ae4538b8d3eba805f3f561899e8ad0dd2"},"package":"5bcf46c1f1f06aeea2d6b81f3c863d0930a596c86ad1920d4e5bad6dd1d7119a"} \ No newline at end of file diff --git a/vendor/tracing-core/CHANGELOG.md b/vendor/tracing-core/CHANGELOG.md index dea419a313..40e22a6442 100644 --- a/vendor/tracing-core/CHANGELOG.md +++ b/vendor/tracing-core/CHANGELOG.md @@ -1,3 +1,24 @@ +# 0.1.16 (September 8, 2020) + +### Fixed + +- Added a conversion from `Option` to `LevelFilter`. This resolves a + previously unreported regression where `Option` was no longer + a valid LevelFilter. ([#966](https://github.com/tokio-rs/tracing/pull/966)) + +# 0.1.15 (August 22, 2020) + +### Fixed + +- When combining `Interest` from multiple subscribers, if the interests differ, + the current subscriber is now always asked if a callsite should be enabled + (#927) + +## Added + +- Internal API changes to support optimizations in the `tracing` crate (#943) +- **docs**: Multiple fixes and improvements (#913, #941) + # 0.1.14 (August 10, 2020) ### Fixed diff --git a/vendor/tracing-core/Cargo.toml b/vendor/tracing-core/Cargo.toml index f0ab647db9..b6ec4c1f7c 100644 --- a/vendor/tracing-core/Cargo.toml +++ b/vendor/tracing-core/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "tracing-core" -version = "0.1.14" +version = "0.1.16" authors = ["Tokio Contributors "] description = "Core primitives for application-level tracing.\n" homepage = "https://tokio.rs" diff --git a/vendor/tracing-core/README.md b/vendor/tracing-core/README.md index c59ed86023..6b7714563c 100644 --- a/vendor/tracing-core/README.md +++ b/vendor/tracing-core/README.md @@ -1,4 +1,5 @@ ![Tracing — Structured, application-level diagnostics][splash] + [splash]: https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/splash.svg # tracing-core @@ -15,9 +16,9 @@ Core primitives for application-level tracing. [Documentation][docs-url] | [Chat][discord-url] [crates-badge]: https://img.shields.io/crates/v/tracing-core.svg -[crates-url]: https://crates.io/crates/tracing-core/0.1.14 +[crates-url]: https://crates.io/crates/tracing-core/0.1.16 [docs-badge]: https://docs.rs/tracing-core/badge.svg -[docs-url]: https://docs.rs/tracing-core/0.1.14 +[docs-url]: https://docs.rs/tracing-core/0.1.16 [docs-master-badge]: https://img.shields.io/badge/docs-master-blue [docs-master-url]: https://tracing-rs.netlify.com/tracing_core [mit-badge]: https://img.shields.io/badge/license-MIT-blue.svg @@ -52,8 +53,12 @@ The crate provides: In addition, it defines the global callsite registry and per-thread current dispatcher which other components of the tracing system rely on. -## Usage +*Compiler support: [requires `rustc` 1.40+][msrv]* +[msrv]: #supported-rust-versions + +## Usage + Application authors will typically not use this crate directly. Instead, they will use the [`tracing`] crate, which provides a much more fully-featured API. However, this crate's API will change very infrequently, so it may be used @@ -70,28 +75,40 @@ The following crate feature flags are available: * `std`: Depend on the Rust standard library (enabled by default). - `no_std` users may disable this feature with `default-features = false`: + `no_std` users may disable this feature with `default-features = false`: ```toml [dependencies] - tracing-core = { version = "0.1.14", default-features = false } + tracing-core = { version = "0.1.16", default-features = false } ``` - *Compiler support: requires rustc 1.39+* - **Note**:`tracing-core`'s `no_std` support requires `liballoc`. [`tracing`]: ../tracing -[`span::Id`]: https://docs.rs/tracing-core/0.1.14/tracing_core/span/struct.Id.html -[`Event`]: https://docs.rs/tracing-core/0.1.14/tracing_core/event/struct.Event.html -[`Subscriber`]: https://docs.rs/tracing-core/0.1.14/tracing_core/subscriber/trait.Subscriber.html -[`Metadata`]: https://docs.rs/tracing-core/0.1.14/tracing_core/metadata/struct.Metadata.html -[`Callsite`]: https://docs.rs/tracing-core/0.1.14/tracing_core/callsite/trait.Callsite.html -[`Field`]: https://docs.rs/tracing-core/0.1.14/tracing_core/field/struct.Field.html -[`FieldSet`]: https://docs.rs/tracing-core/0.1.14/tracing_core/field/struct.FieldSet.html -[`Value`]: https://docs.rs/tracing-core/0.1.14/tracing_core/field/trait.Value.html -[`ValueSet`]: https://docs.rs/tracing-core/0.1.14/tracing_core/field/struct.ValueSet.html -[`Dispatch`]: https://docs.rs/tracing-core/0.1.14/tracing_core/dispatcher/struct.Dispatch.html +[`span::Id`]: https://docs.rs/tracing-core/0.1.16/tracing_core/span/struct.Id.html +[`Event`]: https://docs.rs/tracing-core/0.1.16/tracing_core/event/struct.Event.html +[`Subscriber`]: https://docs.rs/tracing-core/0.1.16/tracing_core/subscriber/trait.Subscriber.html +[`Metadata`]: https://docs.rs/tracing-core/0.1.16/tracing_core/metadata/struct.Metadata.html +[`Callsite`]: https://docs.rs/tracing-core/0.1.16/tracing_core/callsite/trait.Callsite.html +[`Field`]: https://docs.rs/tracing-core/0.1.16/tracing_core/field/struct.Field.html +[`FieldSet`]: https://docs.rs/tracing-core/0.1.16/tracing_core/field/struct.FieldSet.html +[`Value`]: https://docs.rs/tracing-core/0.1.16/tracing_core/field/trait.Value.html +[`ValueSet`]: https://docs.rs/tracing-core/0.1.16/tracing_core/field/struct.ValueSet.html +[`Dispatch`]: https://docs.rs/tracing-core/0.1.16/tracing_core/dispatcher/struct.Dispatch.html + +## Supported Rust Versions + +Tracing is built against the latest stable release. The minimum supported +version is 1.40. The current Tracing version is not guaranteed to build on Rust +versions earlier than the minimum supported version. + +Tracing follows the same compiler support policies as the rest of the Tokio +project. The current stable Rust compiler and the three most recent minor +versions before it will always be supported. For example, if the current stable +compiler version is 1.45, the minimum supported version will not be increased +past 1.42, three minor versions prior. Increasing the minimum supported compiler +version is not considered a semver breaking change as long as doing so complies +with this policy. ## License diff --git a/vendor/tracing-core/src/callsite.rs b/vendor/tracing-core/src/callsite.rs index 9c6e6b31ad..f6904befda 100644 --- a/vendor/tracing-core/src/callsite.rs +++ b/vendor/tracing-core/src/callsite.rs @@ -28,13 +28,21 @@ impl Registry { fn rebuild_callsite_interest(&self, callsite: &'static dyn Callsite) { let meta = callsite.metadata(); - let mut interest = Interest::never(); + // Iterate over the subscribers in the registry, and — if they are + // active — register the callsite with them. + let mut interests = self + .dispatchers + .iter() + .filter_map(|registrar| registrar.try_register(meta)); - for registrar in &self.dispatchers { - if let Some(sub_interest) = registrar.try_register(meta) { - interest = interest.and(sub_interest); - } - } + // Use the first subscriber's `Interest` as the base value. + let interest = if let Some(interest) = interests.next() { + // Combine all remaining `Interest`s. + interests.fold(interest, Interest::and) + } else { + // If nobody was interested in this thing, just return `never`. + Interest::never() + }; callsite.set_interest(interest) } diff --git a/vendor/tracing-core/src/dispatcher.rs b/vendor/tracing-core/src/dispatcher.rs index 9a6048bc1b..658463584e 100644 --- a/vendor/tracing-core/src/dispatcher.rs +++ b/vendor/tracing-core/src/dispatcher.rs @@ -149,7 +149,7 @@ use crate::stdlib::{ #[cfg(feature = "std")] use crate::stdlib::{ - cell::{Cell, RefCell}, + cell::{Cell, RefCell, RefMut}, error, }; @@ -193,6 +193,12 @@ struct State { can_enter: Cell, } +/// While this guard is active, additional calls to subscriber functions on +/// the default dispatcher will not be able to access the dispatch context. +/// Dropping the guard will allow the dispatch context to be re-entered. +#[cfg(feature = "std")] +struct Entered<'a>(&'a State); + /// A guard that resets the current default dispatcher to the prior /// default dispatcher when dropped. #[cfg(feature = "std")] @@ -325,38 +331,46 @@ pub fn get_default(mut f: F) -> T where F: FnMut(&Dispatch) -> T, { - // While this guard is active, additional calls to subscriber functions on - // the default dispatcher will not be able to access the dispatch context. - // Dropping the guard will allow the dispatch context to be re-entered. - struct Entered<'a>(&'a Cell); - impl<'a> Drop for Entered<'a> { - #[inline] - fn drop(&mut self) { - self.0.set(true); - } - } - CURRENT_STATE .try_with(|state| { - if state.can_enter.replace(false) { - let _guard = Entered(&state.can_enter); - - let mut default = state.default.borrow_mut(); - - if default.is::() { - if let Some(global) = get_global() { - // don't redo this call on the next check - *default = global.clone(); - } - } - f(&*default) - } else { - f(&Dispatch::none()) + if let Some(entered) = state.enter() { + return f(&*entered.current()); } + + f(&Dispatch::none()) }) .unwrap_or_else(|_| f(&Dispatch::none())) } +/// Executes a closure with a reference to this thread's current [dispatcher]. +/// +/// Note that calls to `get_default` should not be nested; if this function is +/// called while inside of another `get_default`, that closure will be provided +/// with `Dispatch::none` rather than the previously set dispatcher. +/// +/// [dispatcher]: ../dispatcher/struct.Dispatch.html +#[cfg(feature = "std")] +#[doc(hidden)] +#[inline(never)] +pub fn get_current(f: impl FnOnce(&Dispatch) -> T) -> Option { + CURRENT_STATE + .try_with(|state| { + let entered = state.enter()?; + Some(f(&*entered.current())) + }) + .ok()? +} + +/// Executes a closure with a reference to the current [dispatcher]. +/// +/// [dispatcher]: ../dispatcher/struct.Dispatch.html +#[cfg(not(feature = "std"))] +#[doc(hidden)] +pub fn get_current(f: impl FnOnce(&Dispatch) -> T) -> Option { + let dispatch = get_global()?; + Some(f(&dispatch)) +} + /// Executes a closure with a reference to the current [dispatcher]. /// /// [dispatcher]: ../dispatcher/struct.Dispatch.html @@ -711,6 +725,42 @@ impl State { EXISTS.store(true, Ordering::Release); DefaultGuard(prior) } + + #[inline] + fn enter(&self) -> Option> { + if self.can_enter.replace(false) { + Some(Entered(&self)) + } else { + None + } + } +} + +// ===== impl Entered ===== + +#[cfg(feature = "std")] +impl<'a> Entered<'a> { + #[inline] + fn current(&self) -> RefMut<'a, Dispatch> { + let mut default = self.0.default.borrow_mut(); + + if default.is::() { + if let Some(global) = get_global() { + // don't redo this call on the next check + *default = global.clone(); + } + } + + default + } +} + +#[cfg(feature = "std")] +impl<'a> Drop for Entered<'a> { + #[inline] + fn drop(&mut self) { + self.0.can_enter.set(true); + } } // ===== impl DefaultGuard ===== diff --git a/vendor/tracing-core/src/lib.rs b/vendor/tracing-core/src/lib.rs index 8ca2157455..49ba35ea91 100644 --- a/vendor/tracing-core/src/lib.rs +++ b/vendor/tracing-core/src/lib.rs @@ -23,6 +23,10 @@ //! In addition, it defines the global callsite registry and per-thread current //! dispatcher which other components of the tracing system rely on. //! +//! *Compiler support: [requires `rustc` 1.40+][msrv]* +//! +//! [msrv]: #supported-rust-versions +//! //! ## Usage //! //! Application authors will typically not use this crate directly. Instead, @@ -49,13 +53,26 @@ //! //! ```toml //! [dependencies] -//! tracing-core = { version = "0.1.14", default-features = false } +//! tracing-core = { version = "0.1.16", default-features = false } //! ``` //! -//! *Compiler support: requires rustc 1.39+* -//! //! **Note**:`tracing-core`'s `no_std` support requires `liballoc`. //! +//! ## Supported Rust Versions +//! +//! Tracing is built against the latest stable release. The minimum supported +//! version is 1.40. The current Tracing version is not guaranteed to build on +//! Rust versions earlier than the minimum supported version. +//! +//! Tracing follows the same compiler support policies as the rest of the Tokio +//! project. The current stable Rust compiler and the three most recent minor +//! versions before it will always be supported. For example, if the current +//! stable compiler version is 1.45, the minimum supported version will not be +//! increased past 1.42, three minor versions prior. Increasing the minimum +//! supported compiler version is not considered a semver breaking change as +//! long as doing so complies with this policy. +//! +//! //! [`span::Id`]: span/struct.Id.html //! [`Event`]: event/struct.Event.html //! [`Subscriber`]: subscriber/trait.Subscriber.html @@ -68,9 +85,9 @@ //! [`Dispatch`]: dispatcher/struct.Dispatch.html //! [`tokio-rs/tracing`]: https://github.com/tokio-rs/tracing //! [`tracing`]: https://crates.io/crates/tracing -#![doc(html_root_url = "https://docs.rs/tracing-core/0.1.14")] +#![doc(html_root_url = "https://docs.rs/tracing-core/0.1.16")] #![doc( - html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo.svg", + html_logo_url = "https://raw.githubusercontent.com/tokio-rs/tracing/master/assets/logo-type.png", issue_tracker_base_url = "https://github.com/tokio-rs/tracing/issues/" )] #![cfg_attr(not(feature = "std"), no_std)] diff --git a/vendor/tracing-core/src/metadata.rs b/vendor/tracing-core/src/metadata.rs index c5c67912f2..c575a55b45 100644 --- a/vendor/tracing-core/src/metadata.rs +++ b/vendor/tracing-core/src/metadata.rs @@ -365,6 +365,13 @@ impl From for LevelFilter { } } +impl From> for LevelFilter { + #[inline] + fn from(level: Option) -> Self { + Self(level) + } +} + impl Into> for LevelFilter { #[inline] fn into(self) -> Option { @@ -819,8 +826,15 @@ mod tests { ]; for (filter, level) in mapping.iter() { assert_eq!(filter.clone().into_level(), *level); - if let Some(level) = level { - assert_eq!(LevelFilter::from_level(level.clone()), *filter); + match level { + Some(level) => { + let actual: LevelFilter = level.clone().into(); + assert_eq!(actual, *filter); + } + None => { + let actual: LevelFilter = None.into(); + assert_eq!(actual, *filter); + } } } } diff --git a/vendor/tracing-core/src/subscriber.rs b/vendor/tracing-core/src/subscriber.rs index 2c8911d90f..2b56f8d483 100644 --- a/vendor/tracing-core/src/subscriber.rs +++ b/vendor/tracing-core/src/subscriber.rs @@ -556,24 +556,15 @@ impl Interest { /// Returns the common interest between these two Interests. /// - /// The common interest is defined as the least restrictive, so if one - /// interest is `never` and the other is `always` the common interest is - /// `always`. + /// If both interests are the same, this propagates that interest. + /// Otherwise, if they differ, the result must always be + /// `Interest::sometimes` --- if the two subscribers differ in opinion, we + /// will have to ask the current subscriber what it thinks, no matter what. pub(crate) fn and(self, rhs: Interest) -> Self { - match rhs.0 { - // If the added interest is `never()`, don't change anything — - // either a different subscriber added a higher interest, which we - // want to preserve, or the interest is 0 anyway (as it's - // initialized to 0). - InterestKind::Never => self, - // If the interest is `sometimes()`, that overwrites a `never()` - // interest, but doesn't downgrade an `always()` interest. - InterestKind::Sometimes if self.0 == InterestKind::Never => rhs, - // If the interest is `always()`, we overwrite the current interest, - // as always() is the highest interest level and should take - // precedent. - InterestKind::Always => rhs, - _ => self, + if self.0 == rhs.0 { + self + } else { + Interest::sometimes() } } } diff --git a/vendor/ungrammar/.cargo-checksum.json b/vendor/ungrammar/.cargo-checksum.json index eea1dca5b0..adfaf84f18 100644 --- a/vendor/ungrammar/.cargo-checksum.json +++ b/vendor/ungrammar/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"76a565a05faae8d3c6563c3b33a4100b175e729bbed6a2e13e5fda92d67191c9","README.md":"80dabc09d0e9697eace40fb1793bc23f5710b6032eb2b2e5b9376ed2a2f0427b","rust.ungram":"1181155389caeba13fdba7263ba520ad0bae215a6c40886a820ab9f5b64d2ce2","src/error.rs":"b2afc5e3bceaa7c309ad053094030b8a1534ff51c23c2b10857656e6bc5e4c3a","src/lexer.rs":"09f6cd46bd9ee98bf2b4204dc5dc76bd25b70fbe88e734519efc4184e8c4d074","src/lib.rs":"8bc8edbc7f79f32c4d65b01a000f2c29bf7c89f63f851d63e88e5d47a0d3984e","src/parser.rs":"58eb5ad8d697db6f774b88dcf664a1c6e2880f64d93019fc14d774ebbb37e61b","ungrammar.ungram":"7db0838f2b02c9e093d321c38bb5c864ee4c799c336f966e10af2fb80109010b"},"package":"bab6142ac77be714b1ea78faca6efaed5478c50724786b0fe80d8528d10692b3"} \ No newline at end of file +{"files":{"Cargo.toml":"4eaf8a1b3ff51478146f65ecdb9e5ca14f43a57334395c060699fa8a1791cde7","README.md":"80dabc09d0e9697eace40fb1793bc23f5710b6032eb2b2e5b9376ed2a2f0427b","rust.ungram":"8a5cdf83dec786499f6e66b04a9e6b1d85b135bf302ad58f0214332060ec167f","src/error.rs":"b2afc5e3bceaa7c309ad053094030b8a1534ff51c23c2b10857656e6bc5e4c3a","src/lexer.rs":"09f6cd46bd9ee98bf2b4204dc5dc76bd25b70fbe88e734519efc4184e8c4d074","src/lib.rs":"8bc8edbc7f79f32c4d65b01a000f2c29bf7c89f63f851d63e88e5d47a0d3984e","src/parser.rs":"58eb5ad8d697db6f774b88dcf664a1c6e2880f64d93019fc14d774ebbb37e61b","ungrammar.ungram":"7db0838f2b02c9e093d321c38bb5c864ee4c799c336f966e10af2fb80109010b"},"package":"df0cd89993af555540e2436fc6adb8479b0dbe386339a136397952e9c89e17a9"} \ No newline at end of file diff --git a/vendor/ungrammar/Cargo.toml b/vendor/ungrammar/Cargo.toml index 105954620e..0100bdccf6 100644 --- a/vendor/ungrammar/Cargo.toml +++ b/vendor/ungrammar/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "ungrammar" -version = "1.1.2" +version = "1.1.4" authors = ["Aleksey Kladov "] exclude = ["/bors.toml", "/.github"] description = "A DSL for describing concrete syntax trees" diff --git a/vendor/ungrammar/rust.ungram b/vendor/ungrammar/rust.ungram index 1f3a70529b..6ecdb7bfb0 100644 --- a/vendor/ungrammar/rust.ungram +++ b/vendor/ungrammar/rust.ungram @@ -125,7 +125,7 @@ UseTreeList = Fn = Attr* Visibility? - 'default'? ('async' | 'const')? 'unsafe'? Abi? + 'default'? 'const'? 'async'? 'unsafe'? Abi? 'fn' Name GenericParamList? ParamList RetType? WhereClause? (body:BlockExpr | ';') @@ -250,6 +250,7 @@ ExternItem = Fn | MacroCall | Static +| TypeAlias GenericParamList = '<' (GenericParam (',' GenericParam)* ','?)? '>' diff --git a/vendor/version_check/.cargo-checksum.json b/vendor/version_check/.cargo-checksum.json index f4066d52f2..99887bda22 100644 --- a/vendor/version_check/.cargo-checksum.json +++ b/vendor/version_check/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"Cargo.toml":"8e79e76a669227ea5f61530ad74ea835434efb34b3143dd8afe7fbd327e1f8f9","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"b7e650f3fce5c53249d1cdc608b54df156a97edd636cf9d23498d0cfe7aec63e","README.md":"d45a7a97623a56bf9cb7766976c3807312f7d4ac0cfaf4563ff76bc4d6ad1835","src/channel.rs":"f916ece9beeb7f3d512b423ae6da05d45f284bf42ddf7c14f80b77398d52dac7","src/date.rs":"d31e158a2b49f81da512150c5c93194655dac4114825e285fe2f688c09b001a4","src/lib.rs":"a15eb43cec1acfb0db42e8f93bdf70246ebceb1684ac39496bd28184722e4480","src/version.rs":"7022a20252f8beee0833f5d4f67b863e2f10963a24010e1300cb6603bcb7d514"},"package":"078775d0255232fb988e6fccf26ddc9d1ac274299aaedcedce21c6f72cc533ce"} \ No newline at end of file +{"files":{"Cargo.toml":"d4b465b354ce74e417516ecc4d14e9551ff99fe116a2296db459dff725881801","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-MIT":"b7e650f3fce5c53249d1cdc608b54df156a97edd636cf9d23498d0cfe7aec63e","README.md":"d45a7a97623a56bf9cb7766976c3807312f7d4ac0cfaf4563ff76bc4d6ad1835","src/channel.rs":"f916ece9beeb7f3d512b423ae6da05d45f284bf42ddf7c14f80b77398d52dac7","src/date.rs":"d31e158a2b49f81da512150c5c93194655dac4114825e285fe2f688c09b001a4","src/lib.rs":"a15eb43cec1acfb0db42e8f93bdf70246ebceb1684ac39496bd28184722e4480","src/version.rs":"81503116d2d65968edeec37a0e9797a569ac5cafec13ca61bd631b11948ab7ac"},"package":"b5a972e5669d67ba988ce3dc826706fb0a8b01471c088cb0b6110b805cc36aed"} \ No newline at end of file diff --git a/vendor/version_check/Cargo.toml b/vendor/version_check/Cargo.toml index 6e01ed8c31..8c656fd104 100644 --- a/vendor/version_check/Cargo.toml +++ b/vendor/version_check/Cargo.toml @@ -12,7 +12,7 @@ [package] name = "version_check" -version = "0.9.1" +version = "0.9.2" authors = ["Sergio Benitez "] description = "Tiny crate to check the version of the installed/running rustc." documentation = "https://docs.rs/version_check/" diff --git a/vendor/version_check/src/version.rs b/vendor/version_check/src/version.rs index a0738d983a..a37d8d6d54 100644 --- a/vendor/version_check/src/version.rs +++ b/vendor/version_check/src/version.rs @@ -1,17 +1,10 @@ use std::fmt; /// Version number: `major.minor.patch`, ignoring release channel. -#[derive(Debug, PartialEq, Eq, Copy, Clone, PartialOrd, Ord)] +#[derive(PartialEq, Eq, Copy, Clone, PartialOrd, Ord)] pub struct Version(u64); impl Version { - fn to_mmp(&self) -> (u16, u16, u16) { - let major = self.0 >> 32; - let minor = (self.0 << 32) >> 48; - let patch = (self.0 << 48) >> 48; - (major as u16, minor as u16, patch as u16) - } - /// Reads the version of the running compiler. If it cannot be determined /// (see the [top-level documentation](crate)), returns `None`. /// @@ -55,25 +48,64 @@ impl Version { /// assert!(version.exactly("1.0.0")); /// /// assert!(Version::parse("one.two.three").is_none()); + /// assert!(Version::parse("1.65536.2").is_none()); + /// assert!(Version::parse("1. 2").is_none()); + /// assert!(Version::parse("").is_none()); + /// assert!(Version::parse("1.").is_none()); + /// assert!(Version::parse("1.2.3.4").is_none()); /// ``` pub fn parse(version: &str) -> Option { - let mut mmp: Vec = version.split('-') + let splits = version.split('-') .nth(0) .unwrap_or("") .split('.') - .filter_map(|s| s.parse::().ok()) - .collect(); + .map(|s| s.parse::().ok()); - if mmp.is_empty() { - return None + let mut mmp = [0u16; 3]; + for (i, split) in splits.enumerate() { + mmp[i] = match (i, split) { + (3, _) | (_, None) => return None, + (_, Some(v)) => v, + }; } - while mmp.len() < 3 { - mmp.push(0); - } + let (maj, min, patch) = (mmp[0], mmp[1], mmp[2]); + Some(Version::from_mmp(maj, min, patch)) + } - let (maj, min, patch) = (mmp[0] as u64, mmp[1] as u64, mmp[2] as u64); - Some(Version((maj << 32) | (min << 16) | patch)) + /// Creates a `Version` from `(major, minor, patch)` version components. + /// + /// # Example + /// + /// ```rust + /// use version_check::Version; + /// + /// assert!(Version::from_mmp(1, 35, 0).exactly("1.35.0")); + /// assert!(Version::from_mmp(1, 33, 0).exactly("1.33.0")); + /// assert!(Version::from_mmp(1, 35, 1).exactly("1.35.1")); + /// assert!(Version::from_mmp(1, 13, 2).exactly("1.13.2")); + /// ``` + pub fn from_mmp(major: u16, minor: u16, patch: u16) -> Version { + Version(((major as u64) << 32) | ((minor as u64) << 16) | patch as u64) + } + + /// Returns the `(major, minor, patch)` version components of `self`. + /// + /// # Example + /// + /// ```rust + /// use version_check::Version; + /// + /// assert_eq!(Version::parse("1.35.0").unwrap().to_mmp(), (1, 35, 0)); + /// assert_eq!(Version::parse("1.33.0").unwrap().to_mmp(), (1, 33, 0)); + /// assert_eq!(Version::parse("1.35.1").unwrap().to_mmp(), (1, 35, 1)); + /// assert_eq!(Version::parse("1.13.2").unwrap().to_mmp(), (1, 13, 2)); + /// ``` + pub fn to_mmp(&self) -> (u16, u16, u16) { + let major = self.0 >> 32; + let minor = (self.0 << 32) >> 48; + let patch = (self.0 << 48) >> 48; + (major as u16, minor as u16, patch as u16) } /// Returns `true` if `self` is greater than or equal to `version`. @@ -94,6 +126,11 @@ impl Version { /// /// assert!(!version.at_least("1.35.1")); /// assert!(!version.at_least("1.55.0")); + /// + /// let version = Version::parse("1.12.5").unwrap(); + /// + /// assert!(version.at_least("1.12.0")); + /// assert!(!version.at_least("1.35.0")); /// ``` pub fn at_least(&self, version: &str) -> bool { Version::parse(version) @@ -158,35 +195,76 @@ impl fmt::Display for Version { } } +impl fmt::Debug for Version { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + // We don't use `debug_*` because it's not available in `1.0.0`. + write!(f, "Version({:?}, {:?})", self.0, self.to_mmp()) + } +} + #[cfg(test)] mod tests { use super::Version; - macro_rules! check_mmp { - ($s:expr => ($x:expr, $y:expr, $z:expr)) => ( - if let Some(v) = Version::parse($s) { - if v.to_mmp() != ($x, $y, $z) { - panic!("{:?} ({}) didn't parse as {}.{}.{}.", $s, v, $x, $y, $z); - } - } else { - panic!("{:?} didn't parse for mmp testing.", $s); - } + macro_rules! assert_to_mmp { + // We don't use `.into::>` because it's not available in 1.0. + // We don't use the message part of `assert!` for the same reason. + ($s:expr, None) => ( + assert_eq!(Version::parse($s), None); + ); + ($s:expr, $mmp:expr) => ( + assert_eq!(Version::parse($s).map(|v| v.to_mmp()), Some($mmp)); ) } + macro_rules! assert_from_mmp { + (($x:expr, $y:expr, $z:expr) => $s:expr) => { + assert_eq!(Some(Version::from_mmp($x, $y, $z)), Version::parse($s)); + }; + } + #[test] fn test_str_to_mmp() { - check_mmp!("1.18.0" => (1, 18, 0)); - check_mmp!("3.19.0" => (3, 19, 0)); - check_mmp!("1.19.0-nightly" => (1, 19, 0)); - check_mmp!("1.12.2349" => (1, 12, 2349)); - check_mmp!("0.12" => (0, 12, 0)); - check_mmp!("1.12.5" => (1, 12, 5)); - check_mmp!("1.12" => (1, 12, 0)); - check_mmp!("1" => (1, 0, 0)); - check_mmp!("1.4.4-nightly (d84693b93 2017-07-09)" => (1, 4, 4)); - check_mmp!("1.58879.4478-dev" => (1, 58879, 4478)); - check_mmp!("1.58879.4478-dev (d84693b93 2017-07-09)" => (1, 58879, 4478)); + assert_to_mmp!("1", (1, 0, 0)); + assert_to_mmp!("1.2", (1, 2, 0)); + assert_to_mmp!("1.18.0", (1, 18, 0)); + assert_to_mmp!("3.19.0", (3, 19, 0)); + assert_to_mmp!("1.19.0-nightly", (1, 19, 0)); + assert_to_mmp!("1.12.2349", (1, 12, 2349)); + assert_to_mmp!("0.12", (0, 12, 0)); + assert_to_mmp!("1.12.5", (1, 12, 5)); + assert_to_mmp!("1.12", (1, 12, 0)); + assert_to_mmp!("1", (1, 0, 0)); + assert_to_mmp!("1.4.4-nightly (d84693b93 2017-07-09))", (1, 4, 4)); + assert_to_mmp!("1.58879.4478-dev", (1, 58879, 4478)); + assert_to_mmp!("1.58879.4478-dev (d84693b93 2017-07-09))", (1, 58879, 4478)); + } + + #[test] + fn test_malformed() { + assert_to_mmp!("1.65536.2", None); + assert_to_mmp!("-1.2.3", None); + assert_to_mmp!("1. 2", None); + assert_to_mmp!("", None); + assert_to_mmp!(" ", None); + assert_to_mmp!(".", None); + assert_to_mmp!("one", None); + assert_to_mmp!("1.", None); + assert_to_mmp!("1.2.3.4.5.6", None); + } + + #[test] + fn test_from_mmp() { + assert_from_mmp!((1, 18, 0) => "1.18.0"); + assert_from_mmp!((3, 19, 0) => "3.19.0"); + assert_from_mmp!((1, 19, 0) => "1.19.0"); + assert_from_mmp!((1, 12, 2349) => "1.12.2349"); + assert_from_mmp!((0, 12, 0) => "0.12"); + assert_from_mmp!((1, 12, 5) => "1.12.5"); + assert_from_mmp!((1, 12, 0) => "1.12"); + assert_from_mmp!((1, 0, 0) => "1"); + assert_from_mmp!((1, 4, 4) => "1.4.4"); + assert_from_mmp!((1, 58879, 4478) => "1.58879.4478"); } #[test] diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/.cargo-checksum.json b/vendor/wasi-0.9.0+wasi-snapshot-preview1/.cargo-checksum.json new file mode 100644 index 0000000000..05c3a22697 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/.cargo-checksum.json @@ -0,0 +1 @@ +{"files":{"CODE_OF_CONDUCT.md":"a13aaaf393818bd91207c618724d3fb74944ca5161201822a84af951bcf655ef","CONTRIBUTING.md":"2c908a3e263dc35dfed131c02ff907cd72fafb2c2096e4ba9b1e0cbb7a1b76df","Cargo.toml":"2ecba6e9e633226bc0a26ca5dd580c97c510be660fa348cea248125d90e85bf2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-Apache-2.0_WITH_LLVM-exception":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","ORG_CODE_OF_CONDUCT.md":"a62b69bf86e605ee1bcbb2f0a12ba79e4cebb6983a7b6491949750aecc4f2178","README.md":"9412b3834687f28f0fae01a6e45b1309733ac92dcf04ef3ef36a823e76a6fed2","SECURITY.md":"4d75afb09dd28eb5982e3a1f768ee398d90204669ceef3240a16b31dcf04148a","old-bitflags.patch":"6a35cdbe866fbb51608195b74f0e6c0d37201ed933e473588cc2ab6211916b40","src/error.rs":"96818880fab83125079842e35aacb49333ac66699e223f896699e4fdb88b99e8","src/lib.rs":"7bfc4ffb02d1abfe25f3682affa3a50ca1e7b9d67a478a3d0f2e7788aeaab2b4","src/lib_generated.rs":"7983898c5fc69db19047cf5c3da5ed615b68859094cad8de9a3bc63d1a28de15"},"package":"cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"} \ No newline at end of file diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/CODE_OF_CONDUCT.md b/vendor/wasi-0.9.0+wasi-snapshot-preview1/CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..5c5ebdd259 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/CODE_OF_CONDUCT.md @@ -0,0 +1,49 @@ +# Contributor Covenant Code of Conduct + +*Note*: this Code of Conduct pertains to individuals' behavior. Please also see the [Organizational Code of Conduct][OCoC]. + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as contributors and maintainers pledge to making participation in our project and our community a harassment-free experience for everyone, regardless of age, body size, disability, ethnicity, gender identity and expression, level of experience, nationality, personal appearance, race, religion, or sexual identity and orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable behavior and are expected to take appropriate and fair corrective action in response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or reject comments, commits, code, wiki edits, issues, and other contributions that are not aligned to this Code of Conduct, or to ban temporarily or permanently any contributor for other behaviors that they deem inappropriate, threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces when an individual is representing the project or its community. Examples of representing a project or community include using an official project e-mail address, posting via an official social media account, or acting as an appointed representative at an online or offline event. Representation of a project may be further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be reported by contacting the Bytecode Alliance CoC team at [report@bytecodealliance.org](mailto:report@bytecodealliance.org). The CoC team will review and investigate all complaints, and will respond in a way that it deems appropriate to the circumstances. The CoC team is obligated to maintain confidentiality with regard to the reporter of an incident. Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good faith may face temporary or permanent repercussions as determined by other members of the Bytecode Alliance's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, available at [http://contributor-covenant.org/version/1/4][version] + +[OCoC]: ORG_CODE_OF_CONDUCT.md +[homepage]: https://www.contributor-covenant.org +[version]: https://www.contributor-covenant.org/version/1/4/ diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/CONTRIBUTING.md b/vendor/wasi-0.9.0+wasi-snapshot-preview1/CONTRIBUTING.md new file mode 100644 index 0000000000..2db6d0ddf3 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/CONTRIBUTING.md @@ -0,0 +1,8 @@ +# Contributing to wasi-core + +wasi-core follows the same development style as Cranelift, so checkout +[Cranelift's CONTRIBUTING.md]. Of course, for wasi-core-specific issues, please +use the [wasi-core issue tracker]. + +[Cranelift's CONTRIBUTING.md]: https://github.com/CraneStation/cranelift/blob/master/CONTRIBUTING.md +[wasi-core issue tracker]: https://github.com/CraneStation/wasi-core/issues/new diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/Cargo.toml b/vendor/wasi-0.9.0+wasi-snapshot-preview1/Cargo.toml new file mode 100644 index 0000000000..cd0dfb5351 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/Cargo.toml @@ -0,0 +1,43 @@ +# THIS FILE IS AUTOMATICALLY GENERATED BY CARGO +# +# When uploading crates to the registry Cargo will automatically +# "normalize" Cargo.toml files for maximal compatibility +# with all versions of Cargo and also rewrite `path` dependencies +# to registry (e.g., crates.io) dependencies +# +# If you believe there's an error in this file please file an +# issue against the rust-lang/cargo repository. If you're +# editing this file be aware that the upstream Cargo.toml +# will likely look very different (and much more reasonable) + +[package] +edition = "2018" +name = "wasi" +version = "0.9.0+wasi-snapshot-preview1" +authors = ["The Cranelift Project Developers"] +description = "Experimental WASI API bindings for Rust" +documentation = "https://docs.rs/wasi" +readme = "README.md" +keywords = ["webassembly", "wasm"] +categories = ["no-std", "wasm"] +license = "Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT" +repository = "https://github.com/bytecodealliance/wasi" +[dependencies.compiler_builtins] +version = "0.1" +optional = true + +[dependencies.core] +version = "1.0" +optional = true +package = "rustc-std-workspace-core" + +[dependencies.rustc-std-workspace-alloc] +version = "1.0" +optional = true + +[features] +default = ["std"] +rustc-dep-of-std = ["compiler_builtins", "core", "rustc-std-workspace-alloc"] +std = [] +[badges.maintenance] +status = "experimental" diff --git a/vendor/parking_lot_core-0.7.2/LICENSE-APACHE b/vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-APACHE similarity index 100% rename from vendor/parking_lot_core-0.7.2/LICENSE-APACHE rename to vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-APACHE diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-Apache-2.0_WITH_LLVM-exception b/vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-Apache-2.0_WITH_LLVM-exception new file mode 100644 index 0000000000..f9d81955f4 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-Apache-2.0_WITH_LLVM-exception @@ -0,0 +1,220 @@ + + 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 + + APPENDIX: How to apply the Apache License to your work. + + To apply the Apache License to your work, attach the following + boilerplate notice, with the fields enclosed by brackets "[]" + replaced with your own identifying information. (Don't include + the brackets!) The text should be enclosed in the appropriate + comment syntax for the file format. We also recommend that a + file or class name and description of purpose be included on the + same "printed page" as the copyright notice for easier + identification within third-party archives. + + Copyright [yyyy] [name of copyright owner] + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + +--- LLVM Exceptions to the Apache 2.0 License ---- + +As an exception, if, as a result of your compiling your source code, portions +of this Software are embedded into an Object form of such source code, you +may redistribute such embedded portions in such Object form without complying +with the conditions of Sections 4(a), 4(b) and 4(d) of the License. + +In addition, if you combine or link compiled forms of this Software with +software that is licensed under the GPLv2 ("Combined Software") and if a +court of competent jurisdiction determines that the patent provision (Section +3), the indemnity provision (Section 9) or other Section of the License +conflicts with the conditions of the GPLv2, you may retroactively and +prospectively choose to deem waived or otherwise exclude such Section(s) of +the License, but only in their entirety and only with respect to the Combined +Software. + diff --git a/vendor/itertools-0.8.2/LICENSE-MIT b/vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-MIT similarity index 98% rename from vendor/itertools-0.8.2/LICENSE-MIT rename to vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-MIT index 9203baa055..31aa79387f 100644 --- a/vendor/itertools-0.8.2/LICENSE-MIT +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/LICENSE-MIT @@ -1,5 +1,3 @@ -Copyright (c) 2015 - 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 diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/ORG_CODE_OF_CONDUCT.md b/vendor/wasi-0.9.0+wasi-snapshot-preview1/ORG_CODE_OF_CONDUCT.md new file mode 100644 index 0000000000..6f4fb3f537 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/ORG_CODE_OF_CONDUCT.md @@ -0,0 +1,143 @@ +# Bytecode Alliance Organizational Code of Conduct (OCoC) + +*Note*: this Code of Conduct pertains to organizations' behavior. Please also see the [Individual Code of Conduct](CODE_OF_CONDUCT.md). + +## Preamble + +The Bytecode Alliance (BA) welcomes involvement from organizations, +including commercial organizations. This document is an +*organizational* code of conduct, intended particularly to provide +guidance to commercial organizations. It is distinct from the +[Individual Code of Conduct (ICoC)](CODE_OF_CONDUCT.md), and does not +replace the ICoC. This OCoC applies to any group of people acting in +concert as a BA member or as a participant in BA activities, whether +or not that group is formally incorporated in some jurisdiction. + +The code of conduct described below is not a set of rigid rules, and +we did not write it to encompass every conceivable scenario that might +arise. For example, it is theoretically possible there would be times +when asserting patents is in the best interest of the BA community as +a whole. In such instances, consult with the BA, strive for +consensus, and interpret these rules with an intent that is generous +to the community the BA serves. + +While we may revise these guidelines from time to time based on +real-world experience, overall they are based on a simple principle: + +*Bytecode Alliance members should observe the distinction between + public community functions and private functions — especially + commercial ones — and should ensure that the latter support, or at + least do not harm, the former.* + +## Guidelines + + * **Do not cause confusion about Wasm standards or interoperability.** + + Having an interoperable WebAssembly core is a high priority for + the BA, and members should strive to preserve that core. It is fine + to develop additional non-standard features or APIs, but they + should always be clearly distinguished from the core interoperable + Wasm. + + Treat the WebAssembly name and any BA-associated names with + respect, and follow BA trademark and branding guidelines. If you + distribute a customized version of software originally produced by + the BA, or if you build a product or service using BA-derived + software, use names that clearly distinguish your work from the + original. (You should still provide proper attribution to the + original, of course, wherever such attribution would normally be + given.) + + Further, do not use the WebAssembly name or BA-associated names in + other public namespaces in ways that could cause confusion, e.g., + in company names, names of commercial service offerings, domain + names, publicly-visible social media accounts or online service + accounts, etc. It may sometimes be reasonable, however, to + register such a name in a new namespace and then immediately donate + control of that account to the BA, because that would help the project + maintain its identity. + + For further guidance, see the BA Trademark and Branding Policy + [TODO: create policy, then insert link]. + + * **Do not restrict contributors.** If your company requires + employees or contractors to sign non-compete agreements, those + agreements must not prevent people from participating in the BA or + contributing to related projects. + + This does not mean that all non-compete agreements are incompatible + with this code of conduct. For example, a company may restrict an + employee's ability to solicit the company's customers. However, an + agreement must not block any form of technical or social + participation in BA activities, including but not limited to the + implementation of particular features. + + The accumulation of experience and expertise in individual persons, + who are ultimately free to direct their energy and attention as + they decide, is one of the most important drivers of progress in + open source projects. A company that limits this freedom may hinder + the success of the BA's efforts. + + * **Do not use patents as offensive weapons.** If any BA participant + prevents the adoption or development of BA technologies by + asserting its patents, that undermines the purpose of the + coalition. The collaboration fostered by the BA cannot include + members who act to undermine its work. + + * **Practice responsible disclosure** for security vulnerabilities. + Use designated, non-public reporting channels to disclose technical + vulnerabilities, and give the project a reasonable period to + respond, remediate, and patch. [TODO: optionally include the + security vulnerability reporting URL here.] + + Vulnerability reporters may patch their company's own offerings, as + long as that patching does not significantly delay the reporting of + the vulnerability. Vulnerability information should never be used + for unilateral commercial advantage. Vendors may legitimately + compete on the speed and reliability with which they deploy + security fixes, but withholding vulnerability information damages + everyone in the long run by risking harm to the BA project's + reputation and to the security of all users. + + * **Respect the letter and spirit of open source practice.** While + there is not space to list here all possible aspects of standard + open source practice, some examples will help show what we mean: + + * Abide by all applicable open source license terms. Do not engage + in copyright violation or misattribution of any kind. + + * Do not claim others' ideas or designs as your own. + + * When others engage in publicly visible work (e.g., an upcoming + demo that is coordinated in a public issue tracker), do not + unilaterally announce early releases or early demonstrations of + that work ahead of their schedule in order to secure private + advantage (such as marketplace advantage) for yourself. + + The BA reserves the right to determine what constitutes good open + source practices and to take action as it deems appropriate to + encourage, and if necessary enforce, such practices. + +## Enforcement + +Instances of organizational behavior in violation of the OCoC may +be reported by contacting the Bytecode Alliance CoC team at +[report@bytecodealliance.org](mailto:report@bytecodealliance.org). The +CoC team will review and investigate all complaints, and will respond +in a way that it deems appropriate to the circumstances. The CoC team +is obligated to maintain confidentiality with regard to the reporter of +an incident. Further details of specific enforcement policies may be +posted separately. + +When the BA deems an organization in violation of this OCoC, the BA +will, at its sole discretion, determine what action to take. The BA +will decide what type, degree, and duration of corrective action is +needed, if any, before a violating organization can be considered for +membership (if it was not already a member) or can have its membership +reinstated (if it was a member and the BA canceled its membership due +to the violation). + +In practice, the BA's first approach will be to start a conversation, +with punitive enforcement used only as a last resort. Violations +often turn out to be unintentional and swiftly correctable with all +parties acting in good faith. diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/README.md b/vendor/wasi-0.9.0+wasi-snapshot-preview1/README.md new file mode 100644 index 0000000000..e92f50e3f5 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/README.md @@ -0,0 +1,76 @@ + + +This crate contains API bindings for [WASI](https://github.com/WebAssembly/WASI) +system calls in Rust, and currently reflects the `wasi_snapshot_preview1` +module. This crate is quite low-level and provides conceptually a "system call" +interface. In most settings, it's better to use the Rust standard library, which +has WASI support. + +The `wasi` crate is also entirely procedurally generated from the `*.witx` files +describing the WASI apis. While some conveniences are provided the bindings here +are intentionally low-level! + +# Usage + +First you can depend on this crate via `Cargo.toml`: + +```toml +[dependencies] +wasi = "0.8.0" +``` + +Next you can use the APIs in the root of the module like so: + +```rust +fn main() { + let stdout = 1; + let message = "Hello, World!\n"; + let data = [wasi::Ciovec { + buf: message.as_ptr(), + buf_len: message.len(), + }]; + wasi::fd_write(stdout, &data).unwrap(); +} +``` + +Next you can use a tool like [`cargo +wasi`](https://github.com/bytecodealliance/cargo-wasi) to compile and run your +project: + +To compile Rust projects to wasm using WASI, use the `wasm32-wasi` target, +like this: + +``` +$ cargo wasi run + Compiling wasi v0.8.0+wasi-snapshot-preview1 + Compiling wut v0.1.0 (/code) + Finished dev [unoptimized + debuginfo] target(s) in 0.34s + Running `/.cargo/bin/cargo-wasi target/wasm32-wasi/debug/wut.wasm` + Running `target/wasm32-wasi/debug/wut.wasm` +Hello, World! +``` + +# License + +This project is licensed under the Apache 2.0 license with the LLVM exception. +See [LICENSE](LICENSE) for more details. + +### Contribution + +Unless you explicitly state otherwise, any contribution intentionally submitted +for inclusion in this project by you, as defined in the Apache-2.0 license, +shall be licensed as above, without any additional terms or conditions. diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/SECURITY.md b/vendor/wasi-0.9.0+wasi-snapshot-preview1/SECURITY.md new file mode 100644 index 0000000000..3513b9cb35 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/SECURITY.md @@ -0,0 +1,29 @@ +# Security Policy + +Building secure foundations for software development is at the core of what we do in the Bytecode Alliance. Contributions of external security researchers are a vital part of that. + +## Scope + +If you believe you've found a security issue in any website, service, or software owned or operated by the Bytecode Alliance, we encourage you to notify us. + +## How to Submit a Report + +To submit a vulnerability report to the Bytecode Alliance, please contact us at [security@bytecodealliance.org](mailto:security@bytecodealliance.org). Your submission will be reviewed and validated by a member of our security team. + +## Safe Harbor + +The Bytecode Alliance supports safe harbor for security researchers who: + +* Make a good faith effort to avoid privacy violations, destruction of data, and interruption or degradation of our services. +* Only interact with accounts you own or with explicit permission of the account holder. If you do encounter Personally Identifiable Information (PII) contact us immediately, do not proceed with access, and immediately purge any local information. +* Provide us with a reasonable amount of time to resolve vulnerabilities prior to any disclosure to the public or a third-party. + +We will consider activities conducted consistent with this policy to constitute "authorized" conduct and will not pursue civil action or initiate a complaint to law enforcement. We will help to the extent we can if legal action is initiated by a third party against you. + +Please submit a report to us before engaging in conduct that may be inconsistent with or unaddressed by this policy. + +## Preferences + +* Please provide detailed reports with reproducible steps and a clearly defined impact. +* Submit one vulnerability per report. +* Social engineering (e.g. phishing, vishing, smishing) is prohibited. diff --git a/vendor/wasi/old-bitflags.patch b/vendor/wasi-0.9.0+wasi-snapshot-preview1/old-bitflags.patch similarity index 100% rename from vendor/wasi/old-bitflags.patch rename to vendor/wasi-0.9.0+wasi-snapshot-preview1/old-bitflags.patch diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/error.rs b/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/error.rs new file mode 100644 index 0000000000..2f2aaf4b90 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/error.rs @@ -0,0 +1,51 @@ +use super::Errno; +use core::fmt; +use core::num::NonZeroU16; + +/// A raw error returned by wasi APIs, internally containing a 16-bit error +/// code. +#[derive(Copy, Clone, PartialEq, Eq, Ord, PartialOrd)] +pub struct Error { + code: NonZeroU16, +} + +impl Error { + /// Constructs a new error from a raw error code, returning `None` if the + /// error code is zero (which means success). + pub fn from_raw_error(error: Errno) -> Option { + Some(Error { + code: NonZeroU16::new(error)?, + }) + } + + /// Returns the raw error code that this error represents. + pub fn raw_error(&self) -> u16 { + self.code.get() + } +} + +impl fmt::Display for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} (error {})", + super::strerror(self.code.get()), + self.code + )?; + Ok(()) + } +} + +impl fmt::Debug for Error { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + f.debug_struct("Error") + .field("code", &self.code) + .field("message", &super::strerror(self.code.get())) + .finish() + } +} + +#[cfg(feature = "std")] +extern crate std; +#[cfg(feature = "std")] +impl std::error::Error for Error {} diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib.rs b/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib.rs new file mode 100644 index 0000000000..45c2469277 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib.rs @@ -0,0 +1,36 @@ +//! Raw API bindings to the WebAssembly System Interface (WASI) +//! +//! This crate provides Rust API bindings to WASI APIs. All WASI APIs are +//! exported from this crate and provided with the appropriate type signatures. +//! This crate is entirely procedurally generated from the `*.witx` files that +//! describe the WASI API. +//! +//! # WASI API Version +//! +//! The WASI API is evolving over time. It is both gaining new features as well +//! as tweaking the ABI of existing features. As a result it's important to +//! understand what version of this crate you're using and how it relates to +//! the WASI version of the spec. +//! +//! The WASI specification is organized into phases where there is a snapshot +//! at any one point in time describing the current state of the specification. +//! This crate implements a particular snapshot. You can find the snapshot +//! version implemented in this crate in the build metadata of the crate +//! version number. For example something like `0.9.0+wasi-snapshot-preview1` +//! means that this crate's own personal version is 0.9.0 and it implements the +//! `wasi-snapshot-preview1` snapshot. A major release of this crate (i.e. +//! bumping the "0.9.0") is expected whenever the generated code changes +//! or a new WASI snapshot is used. +//! +//! # Crate Features +//! +//! This crate supports one feature, `std`, which implements the standard +//! `Error` trait for the exported [`Error`] type in this crate. This is +//! enabled by default but can be disabled to make the library `no_std` +//! compatible. + +#![no_std] + +mod error; +mod lib_generated; +pub use lib_generated::*; diff --git a/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib_generated.rs b/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib_generated.rs new file mode 100644 index 0000000000..8adf466470 --- /dev/null +++ b/vendor/wasi-0.9.0+wasi-snapshot-preview1/src/lib_generated.rs @@ -0,0 +1,1853 @@ +// This file is automatically generated, DO NOT EDIT +// +// To regenerate this file run the `crates/generate-raw` command + +use core::mem::MaybeUninit; + +pub use crate::error::Error; +pub type Result = core::result::Result; +pub type Size = usize; +pub type Filesize = u64; +pub type Timestamp = u64; +pub type Clockid = u32; +/// The clock measuring real time. Time value zero corresponds with +/// 1970-01-01T00:00:00Z. +pub const CLOCKID_REALTIME: Clockid = 0; +/// The store-wide monotonic clock, which is defined as a clock measuring +/// real time, whose value cannot be adjusted and which cannot have negative +/// clock jumps. The epoch of this clock is undefined. The absolute time +/// value of this clock therefore has no meaning. +pub const CLOCKID_MONOTONIC: Clockid = 1; +/// The CPU-time clock associated with the current process. +pub const CLOCKID_PROCESS_CPUTIME_ID: Clockid = 2; +/// The CPU-time clock associated with the current thread. +pub const CLOCKID_THREAD_CPUTIME_ID: Clockid = 3; +pub type Errno = u16; +/// No error occurred. System call completed successfully. +pub const ERRNO_SUCCESS: Errno = 0; +/// Argument list too long. +pub const ERRNO_2BIG: Errno = 1; +/// Permission denied. +pub const ERRNO_ACCES: Errno = 2; +/// Address in use. +pub const ERRNO_ADDRINUSE: Errno = 3; +/// Address not available. +pub const ERRNO_ADDRNOTAVAIL: Errno = 4; +/// Address family not supported. +pub const ERRNO_AFNOSUPPORT: Errno = 5; +/// Resource unavailable, or operation would block. +pub const ERRNO_AGAIN: Errno = 6; +/// Connection already in progress. +pub const ERRNO_ALREADY: Errno = 7; +/// Bad file descriptor. +pub const ERRNO_BADF: Errno = 8; +/// Bad message. +pub const ERRNO_BADMSG: Errno = 9; +/// Device or resource busy. +pub const ERRNO_BUSY: Errno = 10; +/// Operation canceled. +pub const ERRNO_CANCELED: Errno = 11; +/// No child processes. +pub const ERRNO_CHILD: Errno = 12; +/// Connection aborted. +pub const ERRNO_CONNABORTED: Errno = 13; +/// Connection refused. +pub const ERRNO_CONNREFUSED: Errno = 14; +/// Connection reset. +pub const ERRNO_CONNRESET: Errno = 15; +/// Resource deadlock would occur. +pub const ERRNO_DEADLK: Errno = 16; +/// Destination address required. +pub const ERRNO_DESTADDRREQ: Errno = 17; +/// Mathematics argument out of domain of function. +pub const ERRNO_DOM: Errno = 18; +/// Reserved. +pub const ERRNO_DQUOT: Errno = 19; +/// File exists. +pub const ERRNO_EXIST: Errno = 20; +/// Bad address. +pub const ERRNO_FAULT: Errno = 21; +/// File too large. +pub const ERRNO_FBIG: Errno = 22; +/// Host is unreachable. +pub const ERRNO_HOSTUNREACH: Errno = 23; +/// Identifier removed. +pub const ERRNO_IDRM: Errno = 24; +/// Illegal byte sequence. +pub const ERRNO_ILSEQ: Errno = 25; +/// Operation in progress. +pub const ERRNO_INPROGRESS: Errno = 26; +/// Interrupted function. +pub const ERRNO_INTR: Errno = 27; +/// Invalid argument. +pub const ERRNO_INVAL: Errno = 28; +/// I/O error. +pub const ERRNO_IO: Errno = 29; +/// Socket is connected. +pub const ERRNO_ISCONN: Errno = 30; +/// Is a directory. +pub const ERRNO_ISDIR: Errno = 31; +/// Too many levels of symbolic links. +pub const ERRNO_LOOP: Errno = 32; +/// File descriptor value too large. +pub const ERRNO_MFILE: Errno = 33; +/// Too many links. +pub const ERRNO_MLINK: Errno = 34; +/// Message too large. +pub const ERRNO_MSGSIZE: Errno = 35; +/// Reserved. +pub const ERRNO_MULTIHOP: Errno = 36; +/// Filename too long. +pub const ERRNO_NAMETOOLONG: Errno = 37; +/// Network is down. +pub const ERRNO_NETDOWN: Errno = 38; +/// Connection aborted by network. +pub const ERRNO_NETRESET: Errno = 39; +/// Network unreachable. +pub const ERRNO_NETUNREACH: Errno = 40; +/// Too many files open in system. +pub const ERRNO_NFILE: Errno = 41; +/// No buffer space available. +pub const ERRNO_NOBUFS: Errno = 42; +/// No such device. +pub const ERRNO_NODEV: Errno = 43; +/// No such file or directory. +pub const ERRNO_NOENT: Errno = 44; +/// Executable file format error. +pub const ERRNO_NOEXEC: Errno = 45; +/// No locks available. +pub const ERRNO_NOLCK: Errno = 46; +/// Reserved. +pub const ERRNO_NOLINK: Errno = 47; +/// Not enough space. +pub const ERRNO_NOMEM: Errno = 48; +/// No message of the desired type. +pub const ERRNO_NOMSG: Errno = 49; +/// Protocol not available. +pub const ERRNO_NOPROTOOPT: Errno = 50; +/// No space left on device. +pub const ERRNO_NOSPC: Errno = 51; +/// Function not supported. +pub const ERRNO_NOSYS: Errno = 52; +/// The socket is not connected. +pub const ERRNO_NOTCONN: Errno = 53; +/// Not a directory or a symbolic link to a directory. +pub const ERRNO_NOTDIR: Errno = 54; +/// Directory not empty. +pub const ERRNO_NOTEMPTY: Errno = 55; +/// State not recoverable. +pub const ERRNO_NOTRECOVERABLE: Errno = 56; +/// Not a socket. +pub const ERRNO_NOTSOCK: Errno = 57; +/// Not supported, or operation not supported on socket. +pub const ERRNO_NOTSUP: Errno = 58; +/// Inappropriate I/O control operation. +pub const ERRNO_NOTTY: Errno = 59; +/// No such device or address. +pub const ERRNO_NXIO: Errno = 60; +/// Value too large to be stored in data type. +pub const ERRNO_OVERFLOW: Errno = 61; +/// Previous owner died. +pub const ERRNO_OWNERDEAD: Errno = 62; +/// Operation not permitted. +pub const ERRNO_PERM: Errno = 63; +/// Broken pipe. +pub const ERRNO_PIPE: Errno = 64; +/// Protocol error. +pub const ERRNO_PROTO: Errno = 65; +/// Protocol not supported. +pub const ERRNO_PROTONOSUPPORT: Errno = 66; +/// Protocol wrong type for socket. +pub const ERRNO_PROTOTYPE: Errno = 67; +/// Result too large. +pub const ERRNO_RANGE: Errno = 68; +/// Read-only file system. +pub const ERRNO_ROFS: Errno = 69; +/// Invalid seek. +pub const ERRNO_SPIPE: Errno = 70; +/// No such process. +pub const ERRNO_SRCH: Errno = 71; +/// Reserved. +pub const ERRNO_STALE: Errno = 72; +/// Connection timed out. +pub const ERRNO_TIMEDOUT: Errno = 73; +/// Text file busy. +pub const ERRNO_TXTBSY: Errno = 74; +/// Cross-device link. +pub const ERRNO_XDEV: Errno = 75; +/// Extension: Capabilities insufficient. +pub const ERRNO_NOTCAPABLE: Errno = 76; +pub(crate) fn strerror(code: u16) -> &'static str { + match code { + ERRNO_SUCCESS => "No error occurred. System call completed successfully.", + ERRNO_2BIG => "Argument list too long.", + ERRNO_ACCES => "Permission denied.", + ERRNO_ADDRINUSE => "Address in use.", + ERRNO_ADDRNOTAVAIL => "Address not available.", + ERRNO_AFNOSUPPORT => "Address family not supported.", + ERRNO_AGAIN => "Resource unavailable, or operation would block.", + ERRNO_ALREADY => "Connection already in progress.", + ERRNO_BADF => "Bad file descriptor.", + ERRNO_BADMSG => "Bad message.", + ERRNO_BUSY => "Device or resource busy.", + ERRNO_CANCELED => "Operation canceled.", + ERRNO_CHILD => "No child processes.", + ERRNO_CONNABORTED => "Connection aborted.", + ERRNO_CONNREFUSED => "Connection refused.", + ERRNO_CONNRESET => "Connection reset.", + ERRNO_DEADLK => "Resource deadlock would occur.", + ERRNO_DESTADDRREQ => "Destination address required.", + ERRNO_DOM => "Mathematics argument out of domain of function.", + ERRNO_DQUOT => "Reserved.", + ERRNO_EXIST => "File exists.", + ERRNO_FAULT => "Bad address.", + ERRNO_FBIG => "File too large.", + ERRNO_HOSTUNREACH => "Host is unreachable.", + ERRNO_IDRM => "Identifier removed.", + ERRNO_ILSEQ => "Illegal byte sequence.", + ERRNO_INPROGRESS => "Operation in progress.", + ERRNO_INTR => "Interrupted function.", + ERRNO_INVAL => "Invalid argument.", + ERRNO_IO => "I/O error.", + ERRNO_ISCONN => "Socket is connected.", + ERRNO_ISDIR => "Is a directory.", + ERRNO_LOOP => "Too many levels of symbolic links.", + ERRNO_MFILE => "File descriptor value too large.", + ERRNO_MLINK => "Too many links.", + ERRNO_MSGSIZE => "Message too large.", + ERRNO_MULTIHOP => "Reserved.", + ERRNO_NAMETOOLONG => "Filename too long.", + ERRNO_NETDOWN => "Network is down.", + ERRNO_NETRESET => "Connection aborted by network.", + ERRNO_NETUNREACH => "Network unreachable.", + ERRNO_NFILE => "Too many files open in system.", + ERRNO_NOBUFS => "No buffer space available.", + ERRNO_NODEV => "No such device.", + ERRNO_NOENT => "No such file or directory.", + ERRNO_NOEXEC => "Executable file format error.", + ERRNO_NOLCK => "No locks available.", + ERRNO_NOLINK => "Reserved.", + ERRNO_NOMEM => "Not enough space.", + ERRNO_NOMSG => "No message of the desired type.", + ERRNO_NOPROTOOPT => "Protocol not available.", + ERRNO_NOSPC => "No space left on device.", + ERRNO_NOSYS => "Function not supported.", + ERRNO_NOTCONN => "The socket is not connected.", + ERRNO_NOTDIR => "Not a directory or a symbolic link to a directory.", + ERRNO_NOTEMPTY => "Directory not empty.", + ERRNO_NOTRECOVERABLE => "State not recoverable.", + ERRNO_NOTSOCK => "Not a socket.", + ERRNO_NOTSUP => "Not supported, or operation not supported on socket.", + ERRNO_NOTTY => "Inappropriate I/O control operation.", + ERRNO_NXIO => "No such device or address.", + ERRNO_OVERFLOW => "Value too large to be stored in data type.", + ERRNO_OWNERDEAD => "Previous owner died.", + ERRNO_PERM => "Operation not permitted.", + ERRNO_PIPE => "Broken pipe.", + ERRNO_PROTO => "Protocol error.", + ERRNO_PROTONOSUPPORT => "Protocol not supported.", + ERRNO_PROTOTYPE => "Protocol wrong type for socket.", + ERRNO_RANGE => "Result too large.", + ERRNO_ROFS => "Read-only file system.", + ERRNO_SPIPE => "Invalid seek.", + ERRNO_SRCH => "No such process.", + ERRNO_STALE => "Reserved.", + ERRNO_TIMEDOUT => "Connection timed out.", + ERRNO_TXTBSY => "Text file busy.", + ERRNO_XDEV => "Cross-device link.", + ERRNO_NOTCAPABLE => "Extension: Capabilities insufficient.", + _ => "Unknown error.", + } +} +pub type Rights = u64; +/// The right to invoke `fd_datasync`. +/// If `path_open` is set, includes the right to invoke +/// `path_open` with `fdflag::dsync`. +pub const RIGHTS_FD_DATASYNC: Rights = 0x1; +/// The right to invoke `fd_read` and `sock_recv`. +/// If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. +pub const RIGHTS_FD_READ: Rights = 0x2; +/// The right to invoke `fd_seek`. This flag implies `rights::fd_tell`. +pub const RIGHTS_FD_SEEK: Rights = 0x4; +/// The right to invoke `fd_fdstat_set_flags`. +pub const RIGHTS_FD_FDSTAT_SET_FLAGS: Rights = 0x8; +/// The right to invoke `fd_sync`. +/// If `path_open` is set, includes the right to invoke +/// `path_open` with `fdflag::rsync` and `fdflag::dsync`. +pub const RIGHTS_FD_SYNC: Rights = 0x10; +/// The right to invoke `fd_seek` in such a way that the file offset +/// remains unaltered (i.e., `WHENCE_CUR` with offset zero), or to +/// invoke `fd_tell`. +pub const RIGHTS_FD_TELL: Rights = 0x20; +/// The right to invoke `fd_write` and `sock_send`. +/// If `rights::fd_seek` is set, includes the right to invoke `fd_pwrite`. +pub const RIGHTS_FD_WRITE: Rights = 0x40; +/// The right to invoke `fd_advise`. +pub const RIGHTS_FD_ADVISE: Rights = 0x80; +/// The right to invoke `fd_allocate`. +pub const RIGHTS_FD_ALLOCATE: Rights = 0x100; +/// The right to invoke `path_create_directory`. +pub const RIGHTS_PATH_CREATE_DIRECTORY: Rights = 0x200; +/// If `path_open` is set, the right to invoke `path_open` with `oflags::creat`. +pub const RIGHTS_PATH_CREATE_FILE: Rights = 0x400; +/// The right to invoke `path_link` with the file descriptor as the +/// source directory. +pub const RIGHTS_PATH_LINK_SOURCE: Rights = 0x800; +/// The right to invoke `path_link` with the file descriptor as the +/// target directory. +pub const RIGHTS_PATH_LINK_TARGET: Rights = 0x1000; +/// The right to invoke `path_open`. +pub const RIGHTS_PATH_OPEN: Rights = 0x2000; +/// The right to invoke `fd_readdir`. +pub const RIGHTS_FD_READDIR: Rights = 0x4000; +/// The right to invoke `path_readlink`. +pub const RIGHTS_PATH_READLINK: Rights = 0x8000; +/// The right to invoke `path_rename` with the file descriptor as the source directory. +pub const RIGHTS_PATH_RENAME_SOURCE: Rights = 0x10000; +/// The right to invoke `path_rename` with the file descriptor as the target directory. +pub const RIGHTS_PATH_RENAME_TARGET: Rights = 0x20000; +/// The right to invoke `path_filestat_get`. +pub const RIGHTS_PATH_FILESTAT_GET: Rights = 0x40000; +/// The right to change a file's size (there is no `path_filestat_set_size`). +/// If `path_open` is set, includes the right to invoke `path_open` with `oflags::trunc`. +pub const RIGHTS_PATH_FILESTAT_SET_SIZE: Rights = 0x80000; +/// The right to invoke `path_filestat_set_times`. +pub const RIGHTS_PATH_FILESTAT_SET_TIMES: Rights = 0x100000; +/// The right to invoke `fd_filestat_get`. +pub const RIGHTS_FD_FILESTAT_GET: Rights = 0x200000; +/// The right to invoke `fd_filestat_set_size`. +pub const RIGHTS_FD_FILESTAT_SET_SIZE: Rights = 0x400000; +/// The right to invoke `fd_filestat_set_times`. +pub const RIGHTS_FD_FILESTAT_SET_TIMES: Rights = 0x800000; +/// The right to invoke `path_symlink`. +pub const RIGHTS_PATH_SYMLINK: Rights = 0x1000000; +/// The right to invoke `path_remove_directory`. +pub const RIGHTS_PATH_REMOVE_DIRECTORY: Rights = 0x2000000; +/// The right to invoke `path_unlink_file`. +pub const RIGHTS_PATH_UNLINK_FILE: Rights = 0x4000000; +/// If `rights::fd_read` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_read`. +/// If `rights::fd_write` is set, includes the right to invoke `poll_oneoff` to subscribe to `eventtype::fd_write`. +pub const RIGHTS_POLL_FD_READWRITE: Rights = 0x8000000; +/// The right to invoke `sock_shutdown`. +pub const RIGHTS_SOCK_SHUTDOWN: Rights = 0x10000000; +pub type Fd = u32; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Iovec { + /// The address of the buffer to be filled. + pub buf: *mut u8, + /// The length of the buffer to be filled. + pub buf_len: Size, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Ciovec { + /// The address of the buffer to be written. + pub buf: *const u8, + /// The length of the buffer to be written. + pub buf_len: Size, +} +pub type IovecArray<'a> = &'a [Iovec]; +pub type CiovecArray<'a> = &'a [Ciovec]; +pub type Filedelta = i64; +pub type Whence = u8; +/// Seek relative to start-of-file. +pub const WHENCE_SET: Whence = 0; +/// Seek relative to current position. +pub const WHENCE_CUR: Whence = 1; +/// Seek relative to end-of-file. +pub const WHENCE_END: Whence = 2; +pub type Dircookie = u64; +pub type Dirnamlen = u32; +pub type Inode = u64; +pub type Filetype = u8; +/// The type of the file descriptor or file is unknown or is different from any of the other types specified. +pub const FILETYPE_UNKNOWN: Filetype = 0; +/// The file descriptor or file refers to a block device inode. +pub const FILETYPE_BLOCK_DEVICE: Filetype = 1; +/// The file descriptor or file refers to a character device inode. +pub const FILETYPE_CHARACTER_DEVICE: Filetype = 2; +/// The file descriptor or file refers to a directory inode. +pub const FILETYPE_DIRECTORY: Filetype = 3; +/// The file descriptor or file refers to a regular file inode. +pub const FILETYPE_REGULAR_FILE: Filetype = 4; +/// The file descriptor or file refers to a datagram socket. +pub const FILETYPE_SOCKET_DGRAM: Filetype = 5; +/// The file descriptor or file refers to a byte-stream socket. +pub const FILETYPE_SOCKET_STREAM: Filetype = 6; +/// The file refers to a symbolic link inode. +pub const FILETYPE_SYMBOLIC_LINK: Filetype = 7; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Dirent { + /// The offset of the next directory entry stored in this directory. + pub d_next: Dircookie, + /// The serial number of the file referred to by this directory entry. + pub d_ino: Inode, + /// The length of the name of the directory entry. + pub d_namlen: Dirnamlen, + /// The type of the file referred to by this directory entry. + pub d_type: Filetype, +} +pub type Advice = u8; +/// The application has no advice to give on its behavior with respect to the specified data. +pub const ADVICE_NORMAL: Advice = 0; +/// The application expects to access the specified data sequentially from lower offsets to higher offsets. +pub const ADVICE_SEQUENTIAL: Advice = 1; +/// The application expects to access the specified data in a random order. +pub const ADVICE_RANDOM: Advice = 2; +/// The application expects to access the specified data in the near future. +pub const ADVICE_WILLNEED: Advice = 3; +/// The application expects that it will not access the specified data in the near future. +pub const ADVICE_DONTNEED: Advice = 4; +/// The application expects to access the specified data once and then not reuse it thereafter. +pub const ADVICE_NOREUSE: Advice = 5; +pub type Fdflags = u16; +/// Append mode: Data written to the file is always appended to the file's end. +pub const FDFLAGS_APPEND: Fdflags = 0x1; +/// Write according to synchronized I/O data integrity completion. Only the data stored in the file is synchronized. +pub const FDFLAGS_DSYNC: Fdflags = 0x2; +/// Non-blocking mode. +pub const FDFLAGS_NONBLOCK: Fdflags = 0x4; +/// Synchronized read I/O operations. +pub const FDFLAGS_RSYNC: Fdflags = 0x8; +/// Write according to synchronized I/O file integrity completion. In +/// addition to synchronizing the data stored in the file, the implementation +/// may also synchronously update the file's metadata. +pub const FDFLAGS_SYNC: Fdflags = 0x10; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Fdstat { + /// File type. + pub fs_filetype: Filetype, + /// File descriptor flags. + pub fs_flags: Fdflags, + /// Rights that apply to this file descriptor. + pub fs_rights_base: Rights, + /// Maximum set of rights that may be installed on new file descriptors that + /// are created through this file descriptor, e.g., through `path_open`. + pub fs_rights_inheriting: Rights, +} +pub type Device = u64; +pub type Fstflags = u16; +/// Adjust the last data access timestamp to the value stored in `filestat::st_atim`. +pub const FSTFLAGS_ATIM: Fstflags = 0x1; +/// Adjust the last data access timestamp to the time of clock `clock::realtime`. +pub const FSTFLAGS_ATIM_NOW: Fstflags = 0x2; +/// Adjust the last data modification timestamp to the value stored in `filestat::st_mtim`. +pub const FSTFLAGS_MTIM: Fstflags = 0x4; +/// Adjust the last data modification timestamp to the time of clock `clock::realtime`. +pub const FSTFLAGS_MTIM_NOW: Fstflags = 0x8; +pub type Lookupflags = u32; +/// As long as the resolved path corresponds to a symbolic link, it is expanded. +pub const LOOKUPFLAGS_SYMLINK_FOLLOW: Lookupflags = 0x1; +pub type Oflags = u16; +/// Create file if it does not exist. +pub const OFLAGS_CREAT: Oflags = 0x1; +/// Fail if not a directory. +pub const OFLAGS_DIRECTORY: Oflags = 0x2; +/// Fail if file already exists. +pub const OFLAGS_EXCL: Oflags = 0x4; +/// Truncate file to size 0. +pub const OFLAGS_TRUNC: Oflags = 0x8; +pub type Linkcount = u64; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Filestat { + /// Device ID of device containing the file. + pub dev: Device, + /// File serial number. + pub ino: Inode, + /// File type. + pub filetype: Filetype, + /// Number of hard links to the file. + pub nlink: Linkcount, + /// For regular files, the file size in bytes. For symbolic links, the length in bytes of the pathname contained in the symbolic link. + pub size: Filesize, + /// Last data access timestamp. + pub atim: Timestamp, + /// Last data modification timestamp. + pub mtim: Timestamp, + /// Last file status change timestamp. + pub ctim: Timestamp, +} +pub type Userdata = u64; +pub type Eventtype = u8; +/// The time value of clock `subscription::u.clock.clock_id` has +/// reached timestamp `subscription::u.clock.timeout`. +pub const EVENTTYPE_CLOCK: Eventtype = 0; +/// File descriptor `subscription::u.fd_readwrite.fd` has data +/// available for reading. This event always triggers for regular files. +pub const EVENTTYPE_FD_READ: Eventtype = 1; +/// File descriptor `subscription::u.fd_readwrite.fd` has capacity +/// available for writing. This event always triggers for regular files. +pub const EVENTTYPE_FD_WRITE: Eventtype = 2; +pub type Eventrwflags = u16; +/// The peer of this socket has closed or disconnected. +pub const EVENTRWFLAGS_FD_READWRITE_HANGUP: Eventrwflags = 0x1; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct EventFdReadwrite { + /// The number of bytes available for reading or writing. + pub nbytes: Filesize, + /// The state of the file descriptor. + pub flags: Eventrwflags, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union EventU { + /// When type is `eventtype::fd_read` or `eventtype::fd_write`: + pub fd_readwrite: EventFdReadwrite, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Event { + /// User-provided value that got attached to `subscription::userdata`. + pub userdata: Userdata, + /// If non-zero, an error that occurred while processing the subscription request. + pub error: Errno, + /// The type of the event that occurred. + pub r#type: Eventtype, + /// The contents of the event. + pub u: EventU, +} +pub type Subclockflags = u16; +/// If set, treat the timestamp provided in +/// `subscription::u.clock.timeout` as an absolute timestamp of clock +/// `subscription::u.clock.clock_id.` If clear, treat the timestamp +/// provided in `subscription::u.clock.timeout` relative to the +/// current time value of clock `subscription::u.clock.clock_id.` +pub const SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME: Subclockflags = 0x1; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SubscriptionClock { + /// The clock against which to compare the timestamp. + pub id: Clockid, + /// The absolute or relative timestamp. + pub timeout: Timestamp, + /// The amount of time that the implementation may wait additionally + /// to coalesce with other events. + pub precision: Timestamp, + /// Flags specifying whether the timeout is absolute or relative + pub flags: Subclockflags, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SubscriptionFdReadwrite { + /// The file descriptor on which to wait for it to become ready for reading or writing. + pub file_descriptor: Fd, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union SubscriptionU { + /// When type is `eventtype::clock`: + pub clock: SubscriptionClock, + /// When type is `eventtype::fd_read` or `eventtype::fd_write`: + pub fd_readwrite: SubscriptionFdReadwrite, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Subscription { + /// User-provided value that is attached to the subscription in the + /// implementation and returned through `event::userdata`. + pub userdata: Userdata, + /// The type of the event to which to subscribe. + pub r#type: Eventtype, + /// The contents of the subscription. + pub u: SubscriptionU, +} +pub type Exitcode = u32; +pub type Signal = u8; +/// No signal. Note that POSIX has special semantics for `kill(pid, 0)`, +/// so this value is reserved. +pub const SIGNAL_NONE: Signal = 0; +/// Hangup. +/// Action: Terminates the process. +pub const SIGNAL_HUP: Signal = 1; +/// Terminate interrupt signal. +/// Action: Terminates the process. +pub const SIGNAL_INT: Signal = 2; +/// Terminal quit signal. +/// Action: Terminates the process. +pub const SIGNAL_QUIT: Signal = 3; +/// Illegal instruction. +/// Action: Terminates the process. +pub const SIGNAL_ILL: Signal = 4; +/// Trace/breakpoint trap. +/// Action: Terminates the process. +pub const SIGNAL_TRAP: Signal = 5; +/// Process abort signal. +/// Action: Terminates the process. +pub const SIGNAL_ABRT: Signal = 6; +/// Access to an undefined portion of a memory object. +/// Action: Terminates the process. +pub const SIGNAL_BUS: Signal = 7; +/// Erroneous arithmetic operation. +/// Action: Terminates the process. +pub const SIGNAL_FPE: Signal = 8; +/// Kill. +/// Action: Terminates the process. +pub const SIGNAL_KILL: Signal = 9; +/// User-defined signal 1. +/// Action: Terminates the process. +pub const SIGNAL_USR1: Signal = 10; +/// Invalid memory reference. +/// Action: Terminates the process. +pub const SIGNAL_SEGV: Signal = 11; +/// User-defined signal 2. +/// Action: Terminates the process. +pub const SIGNAL_USR2: Signal = 12; +/// Write on a pipe with no one to read it. +/// Action: Ignored. +pub const SIGNAL_PIPE: Signal = 13; +/// Alarm clock. +/// Action: Terminates the process. +pub const SIGNAL_ALRM: Signal = 14; +/// Termination signal. +/// Action: Terminates the process. +pub const SIGNAL_TERM: Signal = 15; +/// Child process terminated, stopped, or continued. +/// Action: Ignored. +pub const SIGNAL_CHLD: Signal = 16; +/// Continue executing, if stopped. +/// Action: Continues executing, if stopped. +pub const SIGNAL_CONT: Signal = 17; +/// Stop executing. +/// Action: Stops executing. +pub const SIGNAL_STOP: Signal = 18; +/// Terminal stop signal. +/// Action: Stops executing. +pub const SIGNAL_TSTP: Signal = 19; +/// Background process attempting read. +/// Action: Stops executing. +pub const SIGNAL_TTIN: Signal = 20; +/// Background process attempting write. +/// Action: Stops executing. +pub const SIGNAL_TTOU: Signal = 21; +/// High bandwidth data is available at a socket. +/// Action: Ignored. +pub const SIGNAL_URG: Signal = 22; +/// CPU time limit exceeded. +/// Action: Terminates the process. +pub const SIGNAL_XCPU: Signal = 23; +/// File size limit exceeded. +/// Action: Terminates the process. +pub const SIGNAL_XFSZ: Signal = 24; +/// Virtual timer expired. +/// Action: Terminates the process. +pub const SIGNAL_VTALRM: Signal = 25; +/// Profiling timer expired. +/// Action: Terminates the process. +pub const SIGNAL_PROF: Signal = 26; +/// Window changed. +/// Action: Ignored. +pub const SIGNAL_WINCH: Signal = 27; +/// I/O possible. +/// Action: Terminates the process. +pub const SIGNAL_POLL: Signal = 28; +/// Power failure. +/// Action: Terminates the process. +pub const SIGNAL_PWR: Signal = 29; +/// Bad system call. +/// Action: Terminates the process. +pub const SIGNAL_SYS: Signal = 30; +pub type Riflags = u16; +/// Returns the message without removing it from the socket's receive queue. +pub const RIFLAGS_RECV_PEEK: Riflags = 0x1; +/// On byte-stream sockets, block until the full amount of data can be returned. +pub const RIFLAGS_RECV_WAITALL: Riflags = 0x2; +pub type Roflags = u16; +/// Returned by `sock_recv`: Message data has been truncated. +pub const ROFLAGS_RECV_DATA_TRUNCATED: Roflags = 0x1; +pub type Siflags = u16; +pub type Sdflags = u8; +/// Disables further receive operations. +pub const SDFLAGS_RD: Sdflags = 0x1; +/// Disables further send operations. +pub const SDFLAGS_WR: Sdflags = 0x2; +pub type Preopentype = u8; +/// A pre-opened directory. +pub const PREOPENTYPE_DIR: Preopentype = 0; +#[repr(C)] +#[derive(Copy, Clone)] +pub struct PrestatDir { + /// The length of the directory name for use with `fd_prestat_dir_name`. + pub pr_name_len: Size, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub union PrestatU { + /// When type is `preopentype::dir`: + pub dir: PrestatDir, +} +#[repr(C)] +#[derive(Copy, Clone)] +pub struct Prestat { + /// The type of the pre-opened capability. + pub pr_type: Preopentype, + /// The contents of the information. + pub u: PrestatU, +} +/// Read command-line argument data. +/// The size of the array should match that returned by `wasi_args_sizes_get()` +pub unsafe fn args_get(argv: *mut *mut u8, argv_buf: *mut u8) -> Result<()> { + let rc = wasi_snapshot_preview1::args_get(argv, argv_buf); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Return command-line argument data sizes. +/// +/// ## Return +/// +/// * `argc` - The number of arguments. +/// * `argv_buf_size` - The size of the argument string data. +pub unsafe fn args_sizes_get() -> Result<(Size, Size)> { + let mut argc = MaybeUninit::uninit(); + let mut argv_buf_size = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::args_sizes_get(argc.as_mut_ptr(), argv_buf_size.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok((argc.assume_init(), argv_buf_size.assume_init())) + } +} + +/// Read environment variable data. +/// The sizes of the buffers should match that returned by `environ.sizes_get()`. +pub unsafe fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Result<()> { + let rc = wasi_snapshot_preview1::environ_get(environ, environ_buf); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Return command-line argument data sizes. +/// +/// ## Return +/// +/// * `argc` - The number of arguments. +/// * `argv_buf_size` - The size of the argument string data. +pub unsafe fn environ_sizes_get() -> Result<(Size, Size)> { + let mut argc = MaybeUninit::uninit(); + let mut argv_buf_size = MaybeUninit::uninit(); + let rc = + wasi_snapshot_preview1::environ_sizes_get(argc.as_mut_ptr(), argv_buf_size.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok((argc.assume_init(), argv_buf_size.assume_init())) + } +} + +/// Return the resolution of a clock. +/// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` +/// Note: This is similar to `clock_getres` in POSIX. +/// +/// ## Parameters +/// +/// * `id` - The clock for which to return the resolution. +/// +/// ## Return +/// +/// * `resolution` - The resolution of the clock. +pub unsafe fn clock_res_get(id: Clockid) -> Result { + let mut resolution = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::clock_res_get(id, resolution.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(resolution.assume_init()) + } +} + +/// Return the time value of a clock. +/// Note: This is similar to `clock_gettime` in POSIX. +/// +/// ## Parameters +/// +/// * `id` - The clock for which to return the time. +/// * `precision` - The maximum lag (exclusive) that the returned time value may have, compared to its actual value. +/// +/// ## Return +/// +/// * `time` - The time value of the clock. +pub unsafe fn clock_time_get(id: Clockid, precision: Timestamp) -> Result { + let mut time = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::clock_time_get(id, precision, time.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(time.assume_init()) + } +} + +/// Provide file advisory information on a file descriptor. +/// Note: This is similar to `posix_fadvise` in POSIX. +/// +/// ## Parameters +/// +/// * `offset` - The offset within the file to which the advisory applies. +/// * `len` - The length of the region to which the advisory applies. +/// * `advice` - The advice. +pub unsafe fn fd_advise(fd: Fd, offset: Filesize, len: Filesize, advice: Advice) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_advise(fd, offset, len, advice); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Force the allocation of space in a file. +/// Note: This is similar to `posix_fallocate` in POSIX. +/// +/// ## Parameters +/// +/// * `offset` - The offset at which to start the allocation. +/// * `len` - The length of the area that is allocated. +pub unsafe fn fd_allocate(fd: Fd, offset: Filesize, len: Filesize) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_allocate(fd, offset, len); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Close a file descriptor. +/// Note: This is similar to `close` in POSIX. +pub unsafe fn fd_close(fd: Fd) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_close(fd); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Synchronize the data of a file to disk. +/// Note: This is similar to `fdatasync` in POSIX. +pub unsafe fn fd_datasync(fd: Fd) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_datasync(fd); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Get the attributes of a file descriptor. +/// Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. +/// +/// ## Return +/// +/// * `stat` - The buffer where the file descriptor's attributes are stored. +pub unsafe fn fd_fdstat_get(fd: Fd) -> Result { + let mut stat = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_fdstat_get(fd, stat.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(stat.assume_init()) + } +} + +/// Adjust the flags associated with a file descriptor. +/// Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. +/// +/// ## Parameters +/// +/// * `flags` - The desired values of the file descriptor flags. +pub unsafe fn fd_fdstat_set_flags(fd: Fd, flags: Fdflags) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_fdstat_set_flags(fd, flags); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Adjust the rights associated with a file descriptor. +/// This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights +/// +/// ## Parameters +/// +/// * `fs_rights_base` - The desired rights of the file descriptor. +pub unsafe fn fd_fdstat_set_rights( + fd: Fd, + fs_rights_base: Rights, + fs_rights_inheriting: Rights, +) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_fdstat_set_rights(fd, fs_rights_base, fs_rights_inheriting); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Return the attributes of an open file. +/// +/// ## Return +/// +/// * `buf` - The buffer where the file's attributes are stored. +pub unsafe fn fd_filestat_get(fd: Fd) -> Result { + let mut buf = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_filestat_get(fd, buf.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(buf.assume_init()) + } +} + +/// Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. +/// Note: This is similar to `ftruncate` in POSIX. +/// +/// ## Parameters +/// +/// * `size` - The desired file size. +pub unsafe fn fd_filestat_set_size(fd: Fd, size: Filesize) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_filestat_set_size(fd, size); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Adjust the timestamps of an open file or directory. +/// Note: This is similar to `futimens` in POSIX. +/// +/// ## Parameters +/// +/// * `atim` - The desired values of the data access timestamp. +/// * `mtim` - The desired values of the data modification timestamp. +/// * `fst_flags` - A bitmask indicating which timestamps to adjust. +pub unsafe fn fd_filestat_set_times( + fd: Fd, + atim: Timestamp, + mtim: Timestamp, + fst_flags: Fstflags, +) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_filestat_set_times(fd, atim, mtim, fst_flags); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Read from a file descriptor, without using and updating the file descriptor's offset. +/// Note: This is similar to `preadv` in POSIX. +/// +/// ## Parameters +/// +/// * `iovs` - List of scatter/gather vectors in which to store data. +/// * `offset` - The offset within the file at which to read. +/// +/// ## Return +/// +/// * `nread` - The number of bytes read. +pub unsafe fn fd_pread(fd: Fd, iovs: IovecArray, offset: Filesize) -> Result { + let mut nread = MaybeUninit::uninit(); + let rc = + wasi_snapshot_preview1::fd_pread(fd, iovs.as_ptr(), iovs.len(), offset, nread.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(nread.assume_init()) + } +} + +/// Return a description of the given preopened file descriptor. +/// +/// ## Return +/// +/// * `buf` - The buffer where the description is stored. +pub unsafe fn fd_prestat_get(fd: Fd) -> Result { + let mut buf = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_prestat_get(fd, buf.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(buf.assume_init()) + } +} + +/// Return a description of the given preopened file descriptor. +/// +/// ## Parameters +/// +/// * `path` - A buffer into which to write the preopened directory name. +pub unsafe fn fd_prestat_dir_name(fd: Fd, path: *mut u8, path_len: Size) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_prestat_dir_name(fd, path, path_len); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Write to a file descriptor, without using and updating the file descriptor's offset. +/// Note: This is similar to `pwritev` in POSIX. +/// +/// ## Parameters +/// +/// * `iovs` - List of scatter/gather vectors from which to retrieve data. +/// * `offset` - The offset within the file at which to write. +/// +/// ## Return +/// +/// * `nwritten` - The number of bytes written. +pub unsafe fn fd_pwrite(fd: Fd, iovs: CiovecArray, offset: Filesize) -> Result { + let mut nwritten = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_pwrite( + fd, + iovs.as_ptr(), + iovs.len(), + offset, + nwritten.as_mut_ptr(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(nwritten.assume_init()) + } +} + +/// Read from a file descriptor. +/// Note: This is similar to `readv` in POSIX. +/// +/// ## Parameters +/// +/// * `iovs` - List of scatter/gather vectors to which to store data. +/// +/// ## Return +/// +/// * `nread` - The number of bytes read. +pub unsafe fn fd_read(fd: Fd, iovs: IovecArray) -> Result { + let mut nread = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_read(fd, iovs.as_ptr(), iovs.len(), nread.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(nread.assume_init()) + } +} + +/// Read directory entries from a directory. +/// When successful, the contents of the output buffer consist of a sequence of +/// directory entries. Each directory entry consists of a dirent_t object, +/// followed by dirent_t::d_namlen bytes holding the name of the directory +/// entry. +/// This function fills the output buffer as much as possible, potentially +/// truncating the last directory entry. This allows the caller to grow its +/// read buffer size in case it's too small to fit a single large directory +/// entry, or skip the oversized directory entry. +/// +/// ## Parameters +/// +/// * `buf` - The buffer where directory entries are stored +/// * `cookie` - The location within the directory to start reading +/// +/// ## Return +/// +/// * `bufused` - The number of bytes stored in the read buffer. If less than the size of the read buffer, the end of the directory has been reached. +pub unsafe fn fd_readdir(fd: Fd, buf: *mut u8, buf_len: Size, cookie: Dircookie) -> Result { + let mut bufused = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_readdir(fd, buf, buf_len, cookie, bufused.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(bufused.assume_init()) + } +} + +/// Atomically replace a file descriptor by renumbering another file descriptor. +/// Due to the strong focus on thread safety, this environment does not provide +/// a mechanism to duplicate or renumber a file descriptor to an arbitrary +/// number, like `dup2()`. This would be prone to race conditions, as an actual +/// file descriptor with the same number could be allocated by a different +/// thread at the same time. +/// This function provides a way to atomically renumber file descriptors, which +/// would disappear if `dup2()` were to be removed entirely. +/// +/// ## Parameters +/// +/// * `to` - The file descriptor to overwrite. +pub unsafe fn fd_renumber(fd: Fd, to: Fd) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_renumber(fd, to); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Move the offset of a file descriptor. +/// Note: This is similar to `lseek` in POSIX. +/// +/// ## Parameters +/// +/// * `offset` - The number of bytes to move. +/// * `whence` - The base from which the offset is relative. +/// +/// ## Return +/// +/// * `newoffset` - The new offset of the file descriptor, relative to the start of the file. +pub unsafe fn fd_seek(fd: Fd, offset: Filedelta, whence: Whence) -> Result { + let mut newoffset = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_seek(fd, offset, whence, newoffset.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(newoffset.assume_init()) + } +} + +/// Synchronize the data and metadata of a file to disk. +/// Note: This is similar to `fsync` in POSIX. +pub unsafe fn fd_sync(fd: Fd) -> Result<()> { + let rc = wasi_snapshot_preview1::fd_sync(fd); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Return the current offset of a file descriptor. +/// Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. +/// +/// ## Return +/// +/// * `offset` - The current offset of the file descriptor, relative to the start of the file. +pub unsafe fn fd_tell(fd: Fd) -> Result { + let mut offset = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_tell(fd, offset.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(offset.assume_init()) + } +} + +/// Write to a file descriptor. +/// Note: This is similar to `writev` in POSIX. +/// +/// ## Parameters +/// +/// * `iovs` - List of scatter/gather vectors from which to retrieve data. +/// +/// ## Return +/// +/// * `nwritten` - The number of bytes written. +pub unsafe fn fd_write(fd: Fd, iovs: CiovecArray) -> Result { + let mut nwritten = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::fd_write(fd, iovs.as_ptr(), iovs.len(), nwritten.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(nwritten.assume_init()) + } +} + +/// Create a directory. +/// Note: This is similar to `mkdirat` in POSIX. +/// +/// ## Parameters +/// +/// * `path` - The path at which to create the directory. +pub unsafe fn path_create_directory(fd: Fd, path: &str) -> Result<()> { + let rc = wasi_snapshot_preview1::path_create_directory(fd, path.as_ptr(), path.len()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Return the attributes of a file or directory. +/// Note: This is similar to `stat` in POSIX. +/// +/// ## Parameters +/// +/// * `flags` - Flags determining the method of how the path is resolved. +/// * `path` - The path of the file or directory to inspect. +/// +/// ## Return +/// +/// * `buf` - The buffer where the file's attributes are stored. +pub unsafe fn path_filestat_get(fd: Fd, flags: Lookupflags, path: &str) -> Result { + let mut buf = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::path_filestat_get( + fd, + flags, + path.as_ptr(), + path.len(), + buf.as_mut_ptr(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(buf.assume_init()) + } +} + +/// Adjust the timestamps of a file or directory. +/// Note: This is similar to `utimensat` in POSIX. +/// +/// ## Parameters +/// +/// * `flags` - Flags determining the method of how the path is resolved. +/// * `path` - The path of the file or directory to operate on. +/// * `atim` - The desired values of the data access timestamp. +/// * `mtim` - The desired values of the data modification timestamp. +/// * `fst_flags` - A bitmask indicating which timestamps to adjust. +pub unsafe fn path_filestat_set_times( + fd: Fd, + flags: Lookupflags, + path: &str, + atim: Timestamp, + mtim: Timestamp, + fst_flags: Fstflags, +) -> Result<()> { + let rc = wasi_snapshot_preview1::path_filestat_set_times( + fd, + flags, + path.as_ptr(), + path.len(), + atim, + mtim, + fst_flags, + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Create a hard link. +/// Note: This is similar to `linkat` in POSIX. +/// +/// ## Parameters +/// +/// * `old_flags` - Flags determining the method of how the path is resolved. +/// * `old_path` - The source path from which to link. +/// * `new_fd` - The working directory at which the resolution of the new path starts. +/// * `new_path` - The destination path at which to create the hard link. +pub unsafe fn path_link( + old_fd: Fd, + old_flags: Lookupflags, + old_path: &str, + new_fd: Fd, + new_path: &str, +) -> Result<()> { + let rc = wasi_snapshot_preview1::path_link( + old_fd, + old_flags, + old_path.as_ptr(), + old_path.len(), + new_fd, + new_path.as_ptr(), + new_path.len(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Open a file or directory. +/// The returned file descriptor is not guaranteed to be the lowest-numbered +/// file descriptor not currently open; it is randomized to prevent +/// applications from depending on making assumptions about indexes, since this +/// is error-prone in multi-threaded contexts. The returned file descriptor is +/// guaranteed to be less than 2**31. +/// Note: This is similar to `openat` in POSIX. +/// +/// ## Parameters +/// +/// * `dirflags` - Flags determining the method of how the path is resolved. +/// * `path` - The relative path of the file or directory to open, relative to the +/// `dirfd` directory. +/// * `oflags` - The method by which to open the file. +/// * `fs_rights_base` - The initial rights of the newly created file descriptor. The +/// implementation is allowed to return a file descriptor with fewer rights +/// than specified, if and only if those rights do not apply to the type of +/// file being opened. +/// The *base* rights are rights that will apply to operations using the file +/// descriptor itself, while the *inheriting* rights are rights that apply to +/// file descriptors derived from it. +/// +/// ## Return +/// +/// * `opened_fd` - The file descriptor of the file that has been opened. +pub unsafe fn path_open( + fd: Fd, + dirflags: Lookupflags, + path: &str, + oflags: Oflags, + fs_rights_base: Rights, + fs_rights_inherting: Rights, + fdflags: Fdflags, +) -> Result { + let mut opened_fd = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::path_open( + fd, + dirflags, + path.as_ptr(), + path.len(), + oflags, + fs_rights_base, + fs_rights_inherting, + fdflags, + opened_fd.as_mut_ptr(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(opened_fd.assume_init()) + } +} + +/// Read the contents of a symbolic link. +/// Note: This is similar to `readlinkat` in POSIX. +/// +/// ## Parameters +/// +/// * `path` - The path of the symbolic link from which to read. +/// * `buf` - The buffer to which to write the contents of the symbolic link. +/// +/// ## Return +/// +/// * `bufused` - The number of bytes placed in the buffer. +pub unsafe fn path_readlink(fd: Fd, path: &str, buf: *mut u8, buf_len: Size) -> Result { + let mut bufused = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::path_readlink( + fd, + path.as_ptr(), + path.len(), + buf, + buf_len, + bufused.as_mut_ptr(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(bufused.assume_init()) + } +} + +/// Remove a directory. +/// Return `ENOTEMPTY` if the directory is not empty. +/// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. +/// +/// ## Parameters +/// +/// * `path` - The path to a directory to remove. +pub unsafe fn path_remove_directory(fd: Fd, path: &str) -> Result<()> { + let rc = wasi_snapshot_preview1::path_remove_directory(fd, path.as_ptr(), path.len()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Rename a file or directory. +/// Note: This is similar to `renameat` in POSIX. +/// +/// ## Parameters +/// +/// * `old_path` - The source path of the file or directory to rename. +/// * `new_fd` - The working directory at which the resolution of the new path starts. +/// * `new_path` - The destination path to which to rename the file or directory. +pub unsafe fn path_rename(fd: Fd, old_path: &str, new_fd: Fd, new_path: &str) -> Result<()> { + let rc = wasi_snapshot_preview1::path_rename( + fd, + old_path.as_ptr(), + old_path.len(), + new_fd, + new_path.as_ptr(), + new_path.len(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Create a symbolic link. +/// Note: This is similar to `symlinkat` in POSIX. +/// +/// ## Parameters +/// +/// * `old_path` - The contents of the symbolic link. +/// * `new_path` - The destination path at which to create the symbolic link. +pub unsafe fn path_symlink(old_path: &str, fd: Fd, new_path: &str) -> Result<()> { + let rc = wasi_snapshot_preview1::path_symlink( + old_path.as_ptr(), + old_path.len(), + fd, + new_path.as_ptr(), + new_path.len(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Unlink a file. +/// Return `EISDIR` if the path refers to a directory. +/// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. +/// +/// ## Parameters +/// +/// * `path` - The path to a file to unlink. +pub unsafe fn path_unlink_file(fd: Fd, path: &str) -> Result<()> { + let rc = wasi_snapshot_preview1::path_unlink_file(fd, path.as_ptr(), path.len()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Concurrently poll for the occurrence of a set of events. +/// +/// ## Parameters +/// +/// * `r#in` - The events to which to subscribe. +/// * `out` - The events that have occurred. +/// * `nsubscriptions` - Both the number of subscriptions and events. +/// +/// ## Return +/// +/// * `nevents` - The number of events stored. +pub unsafe fn poll_oneoff( + r#in: *const Subscription, + out: *mut Event, + nsubscriptions: Size, +) -> Result { + let mut nevents = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::poll_oneoff(r#in, out, nsubscriptions, nevents.as_mut_ptr()); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(nevents.assume_init()) + } +} + +/// Terminate the process normally. An exit code of 0 indicates successful +/// termination of the program. The meanings of other values is dependent on +/// the environment. +/// +/// ## Parameters +/// +/// * `rval` - The exit code returned by the process. +pub unsafe fn proc_exit(rval: Exitcode) { + wasi_snapshot_preview1::proc_exit(rval); +} + +/// Send a signal to the process of the calling thread. +/// Note: This is similar to `raise` in POSIX. +/// +/// ## Parameters +/// +/// * `sig` - The signal condition to trigger. +pub unsafe fn proc_raise(sig: Signal) -> Result<()> { + let rc = wasi_snapshot_preview1::proc_raise(sig); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Temporarily yield execution of the calling thread. +/// Note: This is similar to `sched_yield` in POSIX. +pub unsafe fn sched_yield() -> Result<()> { + let rc = wasi_snapshot_preview1::sched_yield(); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Write high-quality random data into a buffer. +/// This function blocks when the implementation is unable to immediately +/// provide sufficient high-quality random data. +/// This function may execute slowly, so when large mounts of random data are +/// required, it's advisable to use this function to seed a pseudo-random +/// number generator, rather than to provide the random data directly. +/// +/// ## Parameters +/// +/// * `buf` - The buffer to fill with random data. +pub unsafe fn random_get(buf: *mut u8, buf_len: Size) -> Result<()> { + let rc = wasi_snapshot_preview1::random_get(buf, buf_len); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +/// Receive a message from a socket. +/// Note: This is similar to `recv` in POSIX, though it also supports reading +/// the data into multiple buffers in the manner of `readv`. +/// +/// ## Parameters +/// +/// * `ri_data` - List of scatter/gather vectors to which to store data. +/// * `ri_flags` - Message flags. +/// +/// ## Return +/// +/// * `ro_datalen` - Number of bytes stored in ri_data. +/// * `ro_flags` - Message flags. +pub unsafe fn sock_recv(fd: Fd, ri_data: IovecArray, ri_flags: Riflags) -> Result<(Size, Roflags)> { + let mut ro_datalen = MaybeUninit::uninit(); + let mut ro_flags = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::sock_recv( + fd, + ri_data.as_ptr(), + ri_data.len(), + ri_flags, + ro_datalen.as_mut_ptr(), + ro_flags.as_mut_ptr(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok((ro_datalen.assume_init(), ro_flags.assume_init())) + } +} + +/// Send a message on a socket. +/// Note: This is similar to `send` in POSIX, though it also supports writing +/// the data from multiple buffers in the manner of `writev`. +/// +/// ## Parameters +/// +/// * `si_data` - List of scatter/gather vectors to which to retrieve data +/// * `si_flags` - Message flags. +/// +/// ## Return +/// +/// * `so_datalen` - Number of bytes transmitted. +pub unsafe fn sock_send(fd: Fd, si_data: CiovecArray, si_flags: Siflags) -> Result { + let mut so_datalen = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::sock_send( + fd, + si_data.as_ptr(), + si_data.len(), + si_flags, + so_datalen.as_mut_ptr(), + ); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(so_datalen.assume_init()) + } +} + +/// Shut down socket send and receive channels. +/// Note: This is similar to `shutdown` in POSIX. +/// +/// ## Parameters +/// +/// * `how` - Which channels on the socket to shut down. +pub unsafe fn sock_shutdown(fd: Fd, how: Sdflags) -> Result<()> { + let rc = wasi_snapshot_preview1::sock_shutdown(fd, how); + if let Some(err) = Error::from_raw_error(rc) { + Err(err) + } else { + Ok(()) + } +} + +pub mod wasi_snapshot_preview1 { + use super::*; + #[link(wasm_import_module = "wasi_snapshot_preview1")] + extern "C" { + /// Read command-line argument data. + /// The size of the array should match that returned by `wasi_args_sizes_get()` + pub fn args_get(argv: *mut *mut u8, argv_buf: *mut u8) -> Errno; + /// Return command-line argument data sizes. + pub fn args_sizes_get(argc: *mut Size, argv_buf_size: *mut Size) -> Errno; + /// Read environment variable data. + /// The sizes of the buffers should match that returned by `environ.sizes_get()`. + pub fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Errno; + /// Return command-line argument data sizes. + pub fn environ_sizes_get(argc: *mut Size, argv_buf_size: *mut Size) -> Errno; + /// Return the resolution of a clock. + /// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` + /// Note: This is similar to `clock_getres` in POSIX. + pub fn clock_res_get(id: Clockid, resolution: *mut Timestamp) -> Errno; + /// Return the time value of a clock. + /// Note: This is similar to `clock_gettime` in POSIX. + pub fn clock_time_get(id: Clockid, precision: Timestamp, time: *mut Timestamp) -> Errno; + /// Provide file advisory information on a file descriptor. + /// Note: This is similar to `posix_fadvise` in POSIX. + pub fn fd_advise(fd: Fd, offset: Filesize, len: Filesize, advice: Advice) -> Errno; + /// Force the allocation of space in a file. + /// Note: This is similar to `posix_fallocate` in POSIX. + pub fn fd_allocate(fd: Fd, offset: Filesize, len: Filesize) -> Errno; + /// Close a file descriptor. + /// Note: This is similar to `close` in POSIX. + pub fn fd_close(fd: Fd) -> Errno; + /// Synchronize the data of a file to disk. + /// Note: This is similar to `fdatasync` in POSIX. + pub fn fd_datasync(fd: Fd) -> Errno; + /// Get the attributes of a file descriptor. + /// Note: This returns similar flags to `fsync(fd, F_GETFL)` in POSIX, as well as additional fields. + pub fn fd_fdstat_get(fd: Fd, stat: *mut Fdstat) -> Errno; + /// Adjust the flags associated with a file descriptor. + /// Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. + pub fn fd_fdstat_set_flags(fd: Fd, flags: Fdflags) -> Errno; + /// Adjust the rights associated with a file descriptor. + /// This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights + pub fn fd_fdstat_set_rights( + fd: Fd, + fs_rights_base: Rights, + fs_rights_inheriting: Rights, + ) -> Errno; + /// Return the attributes of an open file. + pub fn fd_filestat_get(fd: Fd, buf: *mut Filestat) -> Errno; + /// Adjust the size of an open file. If this increases the file's size, the extra bytes are filled with zeros. + /// Note: This is similar to `ftruncate` in POSIX. + pub fn fd_filestat_set_size(fd: Fd, size: Filesize) -> Errno; + /// Adjust the timestamps of an open file or directory. + /// Note: This is similar to `futimens` in POSIX. + pub fn fd_filestat_set_times( + fd: Fd, + atim: Timestamp, + mtim: Timestamp, + fst_flags: Fstflags, + ) -> Errno; + /// Read from a file descriptor, without using and updating the file descriptor's offset. + /// Note: This is similar to `preadv` in POSIX. + pub fn fd_pread( + fd: Fd, + iovs_ptr: *const Iovec, + iovs_len: usize, + offset: Filesize, + nread: *mut Size, + ) -> Errno; + /// Return a description of the given preopened file descriptor. + pub fn fd_prestat_get(fd: Fd, buf: *mut Prestat) -> Errno; + /// Return a description of the given preopened file descriptor. + pub fn fd_prestat_dir_name(fd: Fd, path: *mut u8, path_len: Size) -> Errno; + /// Write to a file descriptor, without using and updating the file descriptor's offset. + /// Note: This is similar to `pwritev` in POSIX. + pub fn fd_pwrite( + fd: Fd, + iovs_ptr: *const Ciovec, + iovs_len: usize, + offset: Filesize, + nwritten: *mut Size, + ) -> Errno; + /// Read from a file descriptor. + /// Note: This is similar to `readv` in POSIX. + pub fn fd_read(fd: Fd, iovs_ptr: *const Iovec, iovs_len: usize, nread: *mut Size) -> Errno; + /// Read directory entries from a directory. + /// When successful, the contents of the output buffer consist of a sequence of + /// directory entries. Each directory entry consists of a dirent_t object, + /// followed by dirent_t::d_namlen bytes holding the name of the directory + /// entry. + /// This function fills the output buffer as much as possible, potentially + /// truncating the last directory entry. This allows the caller to grow its + /// read buffer size in case it's too small to fit a single large directory + /// entry, or skip the oversized directory entry. + pub fn fd_readdir( + fd: Fd, + buf: *mut u8, + buf_len: Size, + cookie: Dircookie, + bufused: *mut Size, + ) -> Errno; + /// Atomically replace a file descriptor by renumbering another file descriptor. + /// Due to the strong focus on thread safety, this environment does not provide + /// a mechanism to duplicate or renumber a file descriptor to an arbitrary + /// number, like `dup2()`. This would be prone to race conditions, as an actual + /// file descriptor with the same number could be allocated by a different + /// thread at the same time. + /// This function provides a way to atomically renumber file descriptors, which + /// would disappear if `dup2()` were to be removed entirely. + pub fn fd_renumber(fd: Fd, to: Fd) -> Errno; + /// Move the offset of a file descriptor. + /// Note: This is similar to `lseek` in POSIX. + pub fn fd_seek( + fd: Fd, + offset: Filedelta, + whence: Whence, + newoffset: *mut Filesize, + ) -> Errno; + /// Synchronize the data and metadata of a file to disk. + /// Note: This is similar to `fsync` in POSIX. + pub fn fd_sync(fd: Fd) -> Errno; + /// Return the current offset of a file descriptor. + /// Note: This is similar to `lseek(fd, 0, SEEK_CUR)` in POSIX. + pub fn fd_tell(fd: Fd, offset: *mut Filesize) -> Errno; + /// Write to a file descriptor. + /// Note: This is similar to `writev` in POSIX. + pub fn fd_write( + fd: Fd, + iovs_ptr: *const Ciovec, + iovs_len: usize, + nwritten: *mut Size, + ) -> Errno; + /// Create a directory. + /// Note: This is similar to `mkdirat` in POSIX. + pub fn path_create_directory(fd: Fd, path_ptr: *const u8, path_len: usize) -> Errno; + /// Return the attributes of a file or directory. + /// Note: This is similar to `stat` in POSIX. + pub fn path_filestat_get( + fd: Fd, + flags: Lookupflags, + path_ptr: *const u8, + path_len: usize, + buf: *mut Filestat, + ) -> Errno; + /// Adjust the timestamps of a file or directory. + /// Note: This is similar to `utimensat` in POSIX. + pub fn path_filestat_set_times( + fd: Fd, + flags: Lookupflags, + path_ptr: *const u8, + path_len: usize, + atim: Timestamp, + mtim: Timestamp, + fst_flags: Fstflags, + ) -> Errno; + /// Create a hard link. + /// Note: This is similar to `linkat` in POSIX. + pub fn path_link( + old_fd: Fd, + old_flags: Lookupflags, + old_path_ptr: *const u8, + old_path_len: usize, + new_fd: Fd, + new_path_ptr: *const u8, + new_path_len: usize, + ) -> Errno; + /// Open a file or directory. + /// The returned file descriptor is not guaranteed to be the lowest-numbered + /// file descriptor not currently open; it is randomized to prevent + /// applications from depending on making assumptions about indexes, since this + /// is error-prone in multi-threaded contexts. The returned file descriptor is + /// guaranteed to be less than 2**31. + /// Note: This is similar to `openat` in POSIX. + pub fn path_open( + fd: Fd, + dirflags: Lookupflags, + path_ptr: *const u8, + path_len: usize, + oflags: Oflags, + fs_rights_base: Rights, + fs_rights_inherting: Rights, + fdflags: Fdflags, + opened_fd: *mut Fd, + ) -> Errno; + /// Read the contents of a symbolic link. + /// Note: This is similar to `readlinkat` in POSIX. + pub fn path_readlink( + fd: Fd, + path_ptr: *const u8, + path_len: usize, + buf: *mut u8, + buf_len: Size, + bufused: *mut Size, + ) -> Errno; + /// Remove a directory. + /// Return `ENOTEMPTY` if the directory is not empty. + /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. + pub fn path_remove_directory(fd: Fd, path_ptr: *const u8, path_len: usize) -> Errno; + /// Rename a file or directory. + /// Note: This is similar to `renameat` in POSIX. + pub fn path_rename( + fd: Fd, + old_path_ptr: *const u8, + old_path_len: usize, + new_fd: Fd, + new_path_ptr: *const u8, + new_path_len: usize, + ) -> Errno; + /// Create a symbolic link. + /// Note: This is similar to `symlinkat` in POSIX. + pub fn path_symlink( + old_path_ptr: *const u8, + old_path_len: usize, + fd: Fd, + new_path_ptr: *const u8, + new_path_len: usize, + ) -> Errno; + /// Unlink a file. + /// Return `EISDIR` if the path refers to a directory. + /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. + pub fn path_unlink_file(fd: Fd, path_ptr: *const u8, path_len: usize) -> Errno; + /// Concurrently poll for the occurrence of a set of events. + pub fn poll_oneoff( + r#in: *const Subscription, + out: *mut Event, + nsubscriptions: Size, + nevents: *mut Size, + ) -> Errno; + /// Terminate the process normally. An exit code of 0 indicates successful + /// termination of the program. The meanings of other values is dependent on + /// the environment. + pub fn proc_exit(rval: Exitcode) -> !; + /// Send a signal to the process of the calling thread. + /// Note: This is similar to `raise` in POSIX. + pub fn proc_raise(sig: Signal) -> Errno; + /// Temporarily yield execution of the calling thread. + /// Note: This is similar to `sched_yield` in POSIX. + pub fn sched_yield() -> Errno; + /// Write high-quality random data into a buffer. + /// This function blocks when the implementation is unable to immediately + /// provide sufficient high-quality random data. + /// This function may execute slowly, so when large mounts of random data are + /// required, it's advisable to use this function to seed a pseudo-random + /// number generator, rather than to provide the random data directly. + pub fn random_get(buf: *mut u8, buf_len: Size) -> Errno; + /// Receive a message from a socket. + /// Note: This is similar to `recv` in POSIX, though it also supports reading + /// the data into multiple buffers in the manner of `readv`. + pub fn sock_recv( + fd: Fd, + ri_data_ptr: *const Iovec, + ri_data_len: usize, + ri_flags: Riflags, + ro_datalen: *mut Size, + ro_flags: *mut Roflags, + ) -> Errno; + /// Send a message on a socket. + /// Note: This is similar to `send` in POSIX, though it also supports writing + /// the data from multiple buffers in the manner of `writev`. + pub fn sock_send( + fd: Fd, + si_data_ptr: *const Ciovec, + si_data_len: usize, + si_flags: Siflags, + so_datalen: *mut Size, + ) -> Errno; + /// Shut down socket send and receive channels. + /// Note: This is similar to `shutdown` in POSIX. + pub fn sock_shutdown(fd: Fd, how: Sdflags) -> Errno; + } +} diff --git a/vendor/wasi/.cargo-checksum.json b/vendor/wasi/.cargo-checksum.json index 05c3a22697..534dc6e205 100644 --- a/vendor/wasi/.cargo-checksum.json +++ b/vendor/wasi/.cargo-checksum.json @@ -1 +1 @@ -{"files":{"CODE_OF_CONDUCT.md":"a13aaaf393818bd91207c618724d3fb74944ca5161201822a84af951bcf655ef","CONTRIBUTING.md":"2c908a3e263dc35dfed131c02ff907cd72fafb2c2096e4ba9b1e0cbb7a1b76df","Cargo.toml":"2ecba6e9e633226bc0a26ca5dd580c97c510be660fa348cea248125d90e85bf2","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-Apache-2.0_WITH_LLVM-exception":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","ORG_CODE_OF_CONDUCT.md":"a62b69bf86e605ee1bcbb2f0a12ba79e4cebb6983a7b6491949750aecc4f2178","README.md":"9412b3834687f28f0fae01a6e45b1309733ac92dcf04ef3ef36a823e76a6fed2","SECURITY.md":"4d75afb09dd28eb5982e3a1f768ee398d90204669ceef3240a16b31dcf04148a","old-bitflags.patch":"6a35cdbe866fbb51608195b74f0e6c0d37201ed933e473588cc2ab6211916b40","src/error.rs":"96818880fab83125079842e35aacb49333ac66699e223f896699e4fdb88b99e8","src/lib.rs":"7bfc4ffb02d1abfe25f3682affa3a50ca1e7b9d67a478a3d0f2e7788aeaab2b4","src/lib_generated.rs":"7983898c5fc69db19047cf5c3da5ed615b68859094cad8de9a3bc63d1a28de15"},"package":"cccddf32554fecc6acb585f82a32a72e28b48f8c4c1883ddfeeeaa96f7d8e519"} \ No newline at end of file +{"files":{"CODE_OF_CONDUCT.md":"a13aaaf393818bd91207c618724d3fb74944ca5161201822a84af951bcf655ef","CONTRIBUTING.md":"2c908a3e263dc35dfed131c02ff907cd72fafb2c2096e4ba9b1e0cbb7a1b76df","Cargo.toml":"0507b220e56fe90becc31c95576b3c42f05b6453659af34e43eaab219274a14b","LICENSE-APACHE":"a60eea817514531668d7e00765731449fe14d059d3249e0bc93b36de45f759f2","LICENSE-Apache-2.0_WITH_LLVM-exception":"268872b9816f90fd8e85db5a28d33f8150ebb8dd016653fb39ef1f94f2686bc5","LICENSE-MIT":"23f18e03dc49df91622fe2a76176497404e46ced8a715d9d2b67a7446571cca3","ORG_CODE_OF_CONDUCT.md":"a62b69bf86e605ee1bcbb2f0a12ba79e4cebb6983a7b6491949750aecc4f2178","README.md":"9412b3834687f28f0fae01a6e45b1309733ac92dcf04ef3ef36a823e76a6fed2","SECURITY.md":"4d75afb09dd28eb5982e3a1f768ee398d90204669ceef3240a16b31dcf04148a","src/error.rs":"96818880fab83125079842e35aacb49333ac66699e223f896699e4fdb88b99e8","src/lib.rs":"ce2e7ee6a6e4d5900f3835568b168afc70870d601b2bb94f1a6b9ddd2f046c3a","src/lib_generated.rs":"352b56bdb0f87dc18592a2241b312710c8326a415c2b3e3e7af26a8e36c2d303"},"package":"1a143597ca7c7793eff794def352d41792a93c481eb1042423ff7ff72ba2c31f"} \ No newline at end of file diff --git a/vendor/wasi/Cargo.toml b/vendor/wasi/Cargo.toml index cd0dfb5351..00fe5b3cd4 100644 --- a/vendor/wasi/Cargo.toml +++ b/vendor/wasi/Cargo.toml @@ -13,7 +13,7 @@ [package] edition = "2018" name = "wasi" -version = "0.9.0+wasi-snapshot-preview1" +version = "0.10.0+wasi-snapshot-preview1" authors = ["The Cranelift Project Developers"] description = "Experimental WASI API bindings for Rust" documentation = "https://docs.rs/wasi" diff --git a/vendor/wasi/src/lib.rs b/vendor/wasi/src/lib.rs index 45c2469277..51f488907f 100644 --- a/vendor/wasi/src/lib.rs +++ b/vendor/wasi/src/lib.rs @@ -34,3 +34,15 @@ mod error; mod lib_generated; pub use lib_generated::*; + +/// Special `Dircookie` value indicating the start of a directory. +pub const DIRCOOKIE_START: Dircookie = 0; + +/// The "standard input" descriptor number. +pub const FD_STDIN: Fd = 0; + +/// The "standard output" descriptor number. +pub const FD_STDOUT: Fd = 1; + +/// The "standard error" descriptor number. +pub const FD_STDERR: Fd = 2; diff --git a/vendor/wasi/src/lib_generated.rs b/vendor/wasi/src/lib_generated.rs index 8adf466470..422794153d 100644 --- a/vendor/wasi/src/lib_generated.rs +++ b/vendor/wasi/src/lib_generated.rs @@ -262,7 +262,7 @@ pub(crate) fn strerror(code: u16) -> &'static str { pub type Rights = u64; /// The right to invoke `fd_datasync`. /// If `path_open` is set, includes the right to invoke -/// `path_open` with `fdflag::dsync`. +/// `path_open` with `fdflags::dsync`. pub const RIGHTS_FD_DATASYNC: Rights = 0x1; /// The right to invoke `fd_read` and `sock_recv`. /// If `rights::fd_seek` is set, includes the right to invoke `fd_pread`. @@ -273,10 +273,10 @@ pub const RIGHTS_FD_SEEK: Rights = 0x4; pub const RIGHTS_FD_FDSTAT_SET_FLAGS: Rights = 0x8; /// The right to invoke `fd_sync`. /// If `path_open` is set, includes the right to invoke -/// `path_open` with `fdflag::rsync` and `fdflag::dsync`. +/// `path_open` with `fdflags::rsync` and `fdflags::dsync`. pub const RIGHTS_FD_SYNC: Rights = 0x10; /// The right to invoke `fd_seek` in such a way that the file offset -/// remains unaltered (i.e., `WHENCE_CUR` with offset zero), or to +/// remains unaltered (i.e., `whence::cur` with offset zero), or to /// invoke `fd_tell`. pub const RIGHTS_FD_TELL: Rights = 0x20; /// The right to invoke `fd_write` and `sock_send`. @@ -332,7 +332,7 @@ pub const RIGHTS_POLL_FD_READWRITE: Rights = 0x8000000; pub const RIGHTS_SOCK_SHUTDOWN: Rights = 0x10000000; pub type Fd = u32; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Iovec { /// The address of the buffer to be filled. pub buf: *mut u8, @@ -340,7 +340,7 @@ pub struct Iovec { pub buf_len: Size, } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Ciovec { /// The address of the buffer to be written. pub buf: *const u8, @@ -378,7 +378,7 @@ pub const FILETYPE_SOCKET_STREAM: Filetype = 6; /// The file refers to a symbolic link inode. pub const FILETYPE_SYMBOLIC_LINK: Filetype = 7; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Dirent { /// The offset of the next directory entry stored in this directory. pub d_next: Dircookie, @@ -416,7 +416,7 @@ pub const FDFLAGS_RSYNC: Fdflags = 0x8; /// may also synchronously update the file's metadata. pub const FDFLAGS_SYNC: Fdflags = 0x10; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Fdstat { /// File type. pub fs_filetype: Filetype, @@ -430,13 +430,13 @@ pub struct Fdstat { } pub type Device = u64; pub type Fstflags = u16; -/// Adjust the last data access timestamp to the value stored in `filestat::st_atim`. +/// Adjust the last data access timestamp to the value stored in `filestat::atim`. pub const FSTFLAGS_ATIM: Fstflags = 0x1; -/// Adjust the last data access timestamp to the time of clock `clock::realtime`. +/// Adjust the last data access timestamp to the time of clock `clockid::realtime`. pub const FSTFLAGS_ATIM_NOW: Fstflags = 0x2; -/// Adjust the last data modification timestamp to the value stored in `filestat::st_mtim`. +/// Adjust the last data modification timestamp to the value stored in `filestat::mtim`. pub const FSTFLAGS_MTIM: Fstflags = 0x4; -/// Adjust the last data modification timestamp to the time of clock `clock::realtime`. +/// Adjust the last data modification timestamp to the time of clock `clockid::realtime`. pub const FSTFLAGS_MTIM_NOW: Fstflags = 0x8; pub type Lookupflags = u32; /// As long as the resolved path corresponds to a symbolic link, it is expanded. @@ -452,7 +452,7 @@ pub const OFLAGS_EXCL: Oflags = 0x4; pub const OFLAGS_TRUNC: Oflags = 0x8; pub type Linkcount = u64; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Filestat { /// Device ID of device containing the file. pub dev: Device, @@ -473,20 +473,20 @@ pub struct Filestat { } pub type Userdata = u64; pub type Eventtype = u8; -/// The time value of clock `subscription::u.clock.clock_id` has -/// reached timestamp `subscription::u.clock.timeout`. +/// The time value of clock `subscription_clock::id` has +/// reached timestamp `subscription_clock::timeout`. pub const EVENTTYPE_CLOCK: Eventtype = 0; -/// File descriptor `subscription::u.fd_readwrite.fd` has data +/// File descriptor `subscription_fd_readwrite::file_descriptor` has data /// available for reading. This event always triggers for regular files. pub const EVENTTYPE_FD_READ: Eventtype = 1; -/// File descriptor `subscription::u.fd_readwrite.fd` has capacity +/// File descriptor `subscription_fd_readwrite::file_descriptor` has capacity /// available for writing. This event always triggers for regular files. pub const EVENTTYPE_FD_WRITE: Eventtype = 2; pub type Eventrwflags = u16; /// The peer of this socket has closed or disconnected. pub const EVENTRWFLAGS_FD_READWRITE_HANGUP: Eventrwflags = 0x1; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct EventFdReadwrite { /// The number of bytes available for reading or writing. pub nbytes: Filesize, @@ -494,32 +494,27 @@ pub struct EventFdReadwrite { pub flags: Eventrwflags, } #[repr(C)] -#[derive(Copy, Clone)] -pub union EventU { - /// When type is `eventtype::fd_read` or `eventtype::fd_write`: - pub fd_readwrite: EventFdReadwrite, -} -#[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct Event { /// User-provided value that got attached to `subscription::userdata`. pub userdata: Userdata, /// If non-zero, an error that occurred while processing the subscription request. pub error: Errno, - /// The type of the event that occurred. + /// The type of event that occured pub r#type: Eventtype, - /// The contents of the event. - pub u: EventU, + /// The contents of the event, if it is an `eventtype::fd_read` or + /// `eventtype::fd_write`. `eventtype::clock` events ignore this field. + pub fd_readwrite: EventFdReadwrite, } pub type Subclockflags = u16; /// If set, treat the timestamp provided in -/// `subscription::u.clock.timeout` as an absolute timestamp of clock -/// `subscription::u.clock.clock_id.` If clear, treat the timestamp -/// provided in `subscription::u.clock.timeout` relative to the -/// current time value of clock `subscription::u.clock.clock_id.` +/// `subscription_clock::timeout` as an absolute timestamp of clock +/// `subscription_clock::id`. If clear, treat the timestamp +/// provided in `subscription_clock::timeout` relative to the +/// current time value of clock `subscription_clock::id`. pub const SUBCLOCKFLAGS_SUBSCRIPTION_CLOCK_ABSTIME: Subclockflags = 0x1; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct SubscriptionClock { /// The clock against which to compare the timestamp. pub id: Clockid, @@ -532,28 +527,32 @@ pub struct SubscriptionClock { pub flags: Subclockflags, } #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct SubscriptionFdReadwrite { /// The file descriptor on which to wait for it to become ready for reading or writing. pub file_descriptor: Fd, } #[repr(C)] #[derive(Copy, Clone)] -pub union SubscriptionU { - /// When type is `eventtype::clock`: +pub union SubscriptionUU { pub clock: SubscriptionClock, - /// When type is `eventtype::fd_read` or `eventtype::fd_write`: - pub fd_readwrite: SubscriptionFdReadwrite, + pub fd_read: SubscriptionFdReadwrite, + pub fd_write: SubscriptionFdReadwrite, } +#[repr(C)] +#[derive(Copy, Clone)] +pub struct SubscriptionU { + pub tag: Eventtype, + pub u: SubscriptionUU, +} + #[repr(C)] #[derive(Copy, Clone)] pub struct Subscription { /// User-provided value that is attached to the subscription in the /// implementation and returned through `event::userdata`. pub userdata: Userdata, - /// The type of the event to which to subscribe. - pub r#type: Eventtype, - /// The contents of the subscription. + /// The type of the event to which to subscribe, and its contents pub u: SubscriptionU, } pub type Exitcode = u32; @@ -669,7 +668,7 @@ pub type Preopentype = u8; /// A pre-opened directory. pub const PREOPENTYPE_DIR: Preopentype = 0; #[repr(C)] -#[derive(Copy, Clone)] +#[derive(Copy, Clone, Debug)] pub struct PrestatDir { /// The length of the directory name for use with `fd_prestat_dir_name`. pub pr_name_len: Size, @@ -677,19 +676,17 @@ pub struct PrestatDir { #[repr(C)] #[derive(Copy, Clone)] pub union PrestatU { - /// When type is `preopentype::dir`: pub dir: PrestatDir, } #[repr(C)] #[derive(Copy, Clone)] pub struct Prestat { - /// The type of the pre-opened capability. - pub pr_type: Preopentype, - /// The contents of the information. + pub tag: Preopentype, pub u: PrestatU, } + /// Read command-line argument data. -/// The size of the array should match that returned by `wasi_args_sizes_get()` +/// The size of the array should match that returned by `args_sizes_get` pub unsafe fn args_get(argv: *mut *mut u8, argv_buf: *mut u8) -> Result<()> { let rc = wasi_snapshot_preview1::args_get(argv, argv_buf); if let Some(err) = Error::from_raw_error(rc) { @@ -717,7 +714,7 @@ pub unsafe fn args_sizes_get() -> Result<(Size, Size)> { } /// Read environment variable data. -/// The sizes of the buffers should match that returned by `environ.sizes_get()`. +/// The sizes of the buffers should match that returned by `environ_sizes_get`. pub unsafe fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Result<()> { let rc = wasi_snapshot_preview1::environ_get(environ, environ_buf); if let Some(err) = Error::from_raw_error(rc) { @@ -727,26 +724,29 @@ pub unsafe fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Result } } -/// Return command-line argument data sizes. +/// Return environment variable data sizes. /// /// ## Return /// -/// * `argc` - The number of arguments. -/// * `argv_buf_size` - The size of the argument string data. +/// * `environc` - The number of environment variable arguments. +/// * `environ_buf_size` - The size of the environment variable data. pub unsafe fn environ_sizes_get() -> Result<(Size, Size)> { - let mut argc = MaybeUninit::uninit(); - let mut argv_buf_size = MaybeUninit::uninit(); - let rc = - wasi_snapshot_preview1::environ_sizes_get(argc.as_mut_ptr(), argv_buf_size.as_mut_ptr()); + let mut environc = MaybeUninit::uninit(); + let mut environ_buf_size = MaybeUninit::uninit(); + let rc = wasi_snapshot_preview1::environ_sizes_get( + environc.as_mut_ptr(), + environ_buf_size.as_mut_ptr(), + ); if let Some(err) = Error::from_raw_error(rc) { Err(err) } else { - Ok((argc.assume_init(), argv_buf_size.assume_init())) + Ok((environc.assume_init(), environ_buf_size.assume_init())) } } /// Return the resolution of a clock. -/// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` +/// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, +/// return `errno::inval`. /// Note: This is similar to `clock_getres` in POSIX. /// /// ## Parameters @@ -874,7 +874,7 @@ pub unsafe fn fd_fdstat_set_flags(fd: Fd, flags: Fdflags) -> Result<()> { } /// Adjust the rights associated with a file descriptor. -/// This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights +/// This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add rights /// /// ## Parameters /// @@ -1279,7 +1279,7 @@ pub unsafe fn path_link( /// /// * `dirflags` - Flags determining the method of how the path is resolved. /// * `path` - The relative path of the file or directory to open, relative to the -/// `dirfd` directory. +/// `path_open::fd` directory. /// * `oflags` - The method by which to open the file. /// * `fs_rights_base` - The initial rights of the newly created file descriptor. The /// implementation is allowed to return a file descriptor with fewer rights @@ -1349,7 +1349,7 @@ pub unsafe fn path_readlink(fd: Fd, path: &str, buf: *mut u8, buf_len: Size) -> } /// Remove a directory. -/// Return `ENOTEMPTY` if the directory is not empty. +/// Return `errno::notempty` if the directory is not empty. /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. /// /// ## Parameters @@ -1411,7 +1411,7 @@ pub unsafe fn path_symlink(old_path: &str, fd: Fd, new_path: &str) -> Result<()> } /// Unlink a file. -/// Return `EISDIR` if the path refers to a directory. +/// Return `errno::isdir` if the path refers to a directory. /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. /// /// ## Parameters @@ -1586,17 +1586,18 @@ pub mod wasi_snapshot_preview1 { #[link(wasm_import_module = "wasi_snapshot_preview1")] extern "C" { /// Read command-line argument data. - /// The size of the array should match that returned by `wasi_args_sizes_get()` + /// The size of the array should match that returned by `args_sizes_get` pub fn args_get(argv: *mut *mut u8, argv_buf: *mut u8) -> Errno; /// Return command-line argument data sizes. pub fn args_sizes_get(argc: *mut Size, argv_buf_size: *mut Size) -> Errno; /// Read environment variable data. - /// The sizes of the buffers should match that returned by `environ.sizes_get()`. + /// The sizes of the buffers should match that returned by `environ_sizes_get`. pub fn environ_get(environ: *mut *mut u8, environ_buf: *mut u8) -> Errno; - /// Return command-line argument data sizes. - pub fn environ_sizes_get(argc: *mut Size, argv_buf_size: *mut Size) -> Errno; + /// Return environment variable data sizes. + pub fn environ_sizes_get(environc: *mut Size, environ_buf_size: *mut Size) -> Errno; /// Return the resolution of a clock. - /// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, return `WASI_EINVAL` + /// Implementations are required to provide a non-zero value for supported clocks. For unsupported clocks, + /// return `errno::inval`. /// Note: This is similar to `clock_getres` in POSIX. pub fn clock_res_get(id: Clockid, resolution: *mut Timestamp) -> Errno; /// Return the time value of a clock. @@ -1621,7 +1622,7 @@ pub mod wasi_snapshot_preview1 { /// Note: This is similar to `fcntl(fd, F_SETFL, flags)` in POSIX. pub fn fd_fdstat_set_flags(fd: Fd, flags: Fdflags) -> Errno; /// Adjust the rights associated with a file descriptor. - /// This can only be used to remove rights, and returns `ENOTCAPABLE` if called in a way that would attempt to add rights + /// This can only be used to remove rights, and returns `errno::notcapable` if called in a way that would attempt to add rights pub fn fd_fdstat_set_rights( fd: Fd, fs_rights_base: Rights, @@ -1775,7 +1776,7 @@ pub mod wasi_snapshot_preview1 { bufused: *mut Size, ) -> Errno; /// Remove a directory. - /// Return `ENOTEMPTY` if the directory is not empty. + /// Return `errno::notempty` if the directory is not empty. /// Note: This is similar to `unlinkat(fd, path, AT_REMOVEDIR)` in POSIX. pub fn path_remove_directory(fd: Fd, path_ptr: *const u8, path_len: usize) -> Errno; /// Rename a file or directory. @@ -1798,7 +1799,7 @@ pub mod wasi_snapshot_preview1 { new_path_len: usize, ) -> Errno; /// Unlink a file. - /// Return `EISDIR` if the path refers to a directory. + /// Return `errno::isdir` if the path refers to a directory. /// Note: This is similar to `unlinkat(fd, path, 0)` in POSIX. pub fn path_unlink_file(fd: Fd, path_ptr: *const u8, path_len: usize) -> Errno; /// Concurrently poll for the occurrence of a set of events. diff --git a/version b/version index 9e3c9f7fcd..63fd5802ce 100644 --- a/version +++ b/version @@ -1 +1 @@ -1.47.0 (18bf6b4f0 2020-10-07) \ No newline at end of file +1.48.0-beta.8 (121901459 2020-11-08) \ No newline at end of file
    +

    wasi

    + +A
    Bytecode Alliance project + +

    + WASI API Bindings for Rust +

    + +

    + Crates.io version + Download + docs.rs docs +

    +
    +Expand for code + +This is so extensive to show how you can build up to processing totally arbitrary sequences, but for the most part these can be used on `GenericArray` instances without much added complexity. + +```rust +/// Super-simple fixed-length i32 `GenericArray`s +pub fn generic_array_plain_zip_sum(a: GenericArray, b: GenericArray) -> i32 { + a.zip(b, |l, r| l + r) + .map(|x| x + 1) + .fold(0, |a, x| x + a) +} + +pub fn generic_array_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 +where + N: ArrayLength, +{ + a.zip(b, |l, r| l + r) + .map(|x| x + 1) + .fold(0, |a, x| x + a) +} + +pub fn generic_array_same_type_variable_length_zip_sum(a: GenericArray, b: GenericArray) -> i32 +where + N: ArrayLength + ArrayLength<>::Output>, + T: Add, +{ + a.zip(b, |l, r| l + r) + .map(|x| x + 1) + .fold(0, |a, x| x + a) +} + +/// Complex example using fully generic `GenericArray`s with the same length. +/// +/// It's mostly just the repeated `Add` traits, which would be present in other systems anyway. +pub fn generic_array_zip_sum + ArrayLength>(a: GenericArray, b: GenericArray) -> i32 +where + A: Add, + N: ArrayLength<>::Output> + + ArrayLength<<>::Output as Add>::Output>, + >::Output: Add, + <>::Output as Add>::Output: Add, +{ + a.zip(b, |l, r| l + r) + .map(|x| x + 1) + .fold(0, |a, x| x + a) +} +``` +